]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
8f8a12d1 FB |
2 | /* |
3 | * Copyright (c) 2017 Intel Corporation | |
8f8a12d1 | 4 | */ |
d678a59d | 5 | #include <common.h> |
c974a3d1 | 6 | #include <dm.h> |
f7ae49fc | 7 | #include <log.h> |
c974a3d1 AS |
8 | #include <wdt.h> |
9 | #include <div64.h> | |
8f8a12d1 FB |
10 | #include <asm/scu.h> |
11 | ||
12 | /* Hardware timeout in seconds */ | |
13 | #define WDT_PRETIMEOUT 15 | |
14 | #define WDT_TIMEOUT_MIN (1 + WDT_PRETIMEOUT) | |
15 | #define WDT_TIMEOUT_MAX 170 | |
8b295a20 AS |
16 | |
17 | /* | |
18 | * Note, firmware chooses 90 seconds as a default timeout for watchdog on | |
19 | * Intel Tangier SoC. It means that without handling it in the running code | |
20 | * the reboot will happen. | |
21 | */ | |
8f8a12d1 | 22 | |
8f8a12d1 FB |
23 | enum { |
24 | SCU_WATCHDOG_START = 0, | |
25 | SCU_WATCHDOG_STOP = 1, | |
26 | SCU_WATCHDOG_KEEPALIVE = 2, | |
27 | SCU_WATCHDOG_SET_ACTION_ON_TIMEOUT = 3, | |
28 | }; | |
29 | ||
c974a3d1 | 30 | static int tangier_wdt_reset(struct udevice *dev) |
8f8a12d1 | 31 | { |
c974a3d1 AS |
32 | scu_ipc_simple_command(IPCMSG_WATCHDOG_TIMER, SCU_WATCHDOG_KEEPALIVE); |
33 | return 0; | |
8f8a12d1 FB |
34 | } |
35 | ||
c974a3d1 | 36 | static int tangier_wdt_stop(struct udevice *dev) |
8f8a12d1 FB |
37 | { |
38 | return scu_ipc_simple_command(IPCMSG_WATCHDOG_TIMER, SCU_WATCHDOG_STOP); | |
39 | } | |
40 | ||
c974a3d1 | 41 | static int tangier_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags) |
8f8a12d1 | 42 | { |
c974a3d1 | 43 | u32 timeout_sec; |
8f8a12d1 FB |
44 | int in_size; |
45 | struct ipc_wd_start { | |
46 | u32 pretimeout; | |
47 | u32 timeout; | |
c974a3d1 AS |
48 | } ipc_wd_start; |
49 | ||
50 | /* Calculate timeout in seconds and restrict to min and max value */ | |
51 | do_div(timeout_ms, 1000); | |
52 | timeout_sec = clamp_t(u32, timeout_ms, WDT_TIMEOUT_MIN, WDT_TIMEOUT_MAX); | |
53 | ||
54 | /* Update values in the IPC request */ | |
55 | ipc_wd_start.pretimeout = timeout_sec - WDT_PRETIMEOUT; | |
56 | ipc_wd_start.timeout = timeout_sec; | |
8f8a12d1 FB |
57 | |
58 | /* | |
59 | * SCU expects the input size for watchdog IPC | |
60 | * to be based on 4 bytes | |
61 | */ | |
62 | in_size = DIV_ROUND_UP(sizeof(ipc_wd_start), 4); | |
63 | ||
64 | scu_ipc_command(IPCMSG_WATCHDOG_TIMER, SCU_WATCHDOG_START, | |
65 | (u32 *)&ipc_wd_start, in_size, NULL, 0); | |
c974a3d1 AS |
66 | |
67 | return 0; | |
68 | } | |
69 | ||
70 | static const struct wdt_ops tangier_wdt_ops = { | |
71 | .reset = tangier_wdt_reset, | |
72 | .start = tangier_wdt_start, | |
73 | .stop = tangier_wdt_stop, | |
74 | }; | |
75 | ||
76 | static const struct udevice_id tangier_wdt_ids[] = { | |
77 | { .compatible = "intel,tangier-wdt" }, | |
78 | { /* sentinel */ } | |
79 | }; | |
80 | ||
81 | static int tangier_wdt_probe(struct udevice *dev) | |
82 | { | |
8b85dfc6 | 83 | debug("%s: Probing wdt%u\n", __func__, dev_seq(dev)); |
c974a3d1 | 84 | return 0; |
8f8a12d1 | 85 | } |
c974a3d1 AS |
86 | |
87 | U_BOOT_DRIVER(wdt_tangier) = { | |
88 | .name = "wdt_tangier", | |
89 | .id = UCLASS_WDT, | |
90 | .of_match = tangier_wdt_ids, | |
91 | .ops = &tangier_wdt_ops, | |
92 | .probe = tangier_wdt_probe, | |
93 | }; |