blob: 83f19dc0e86b332b43b47bd39efaedbd0f05fe24 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Ye Li62862b62017-02-22 16:21:48 +08002/*
3 * Copyright (C) 2016 Freescale Semiconductor, Inc.
Ye Li62862b62017-02-22 16:21:48 +08004 */
5
Simon Glassafb02152019-12-28 10:45:01 -07006#include <cpu_func.h>
Ye Li62862b62017-02-22 16:21:48 +08007#include <asm/io.h>
8#include <asm/arch/imx-regs.h>
Alice Guoab63a6e2022-10-21 16:41:18 +08009#include <dm.h>
10#include <wdt.h>
Ye Li62862b62017-02-22 16:21:48 +080011
12/*
13 * MX7ULP WDOG Register Map
14 */
15struct wdog_regs {
Breno Lima4a686892021-06-29 10:32:35 +080016 u32 cs;
Ye Li62862b62017-02-22 16:21:48 +080017 u32 cnt;
18 u32 toval;
19 u32 win;
20};
21
Alice Guoab63a6e2022-10-21 16:41:18 +080022struct ulp_wdt_priv {
23 struct wdog_regs *wdog;
24 u32 clk_rate;
25};
26
Ye Li62862b62017-02-22 16:21:48 +080027#define REFRESH_WORD0 0xA602 /* 1st refresh word */
28#define REFRESH_WORD1 0xB480 /* 2nd refresh word */
29
30#define UNLOCK_WORD0 0xC520 /* 1st unlock word */
31#define UNLOCK_WORD1 0xD928 /* 2nd unlock word */
32
Ye Li67439162022-10-21 16:41:15 +080033#define UNLOCK_WORD 0xD928C520 /* unlock word */
34#define REFRESH_WORD 0xB480A602 /* refresh word */
35
Breno Lima4a686892021-06-29 10:32:35 +080036#define WDGCS_WDGE BIT(7)
37#define WDGCS_WDGUPDATE BIT(5)
Ye Li62862b62017-02-22 16:21:48 +080038
Breno Lima4a686892021-06-29 10:32:35 +080039#define WDGCS_RCS BIT(10)
40#define WDGCS_ULK BIT(11)
Alice Guodea73ea2022-10-21 16:41:16 +080041#define WDOG_CS_PRES BIT(12)
Ye Li67439162022-10-21 16:41:15 +080042#define WDGCS_CMD32EN BIT(13)
Breno Lima4a686892021-06-29 10:32:35 +080043#define WDGCS_FLG BIT(14)
Alice Guo71e0e6c2022-10-21 16:41:17 +080044#define WDGCS_INT BIT(6)
Ye Li62862b62017-02-22 16:21:48 +080045
46#define WDG_BUS_CLK (0x0)
47#define WDG_LPO_CLK (0x1)
48#define WDG_32KHZ_CLK (0x2)
49#define WDG_EXT_CLK (0x3)
50
Alice Guoab63a6e2022-10-21 16:41:18 +080051#define CLK_RATE_1KHZ 1000
52#define CLK_RATE_32KHZ 125
53
Ye Li62862b62017-02-22 16:21:48 +080054void hw_watchdog_set_timeout(u16 val)
55{
56 /* setting timeout value */
57 struct wdog_regs *wdog = (struct wdog_regs *)WDOG_BASE_ADDR;
58
59 writel(val, &wdog->toval);
60}
61
Alice Guoab63a6e2022-10-21 16:41:18 +080062void ulp_watchdog_reset(struct wdog_regs *wdog)
Ye Li62862b62017-02-22 16:21:48 +080063{
Ye Li67439162022-10-21 16:41:15 +080064 if (readl(&wdog->cs) & WDGCS_CMD32EN) {
65 writel(REFRESH_WORD, &wdog->cnt);
66 } else {
67 dmb();
68 __raw_writel(REFRESH_WORD0, &wdog->cnt);
69 __raw_writel(REFRESH_WORD1, &wdog->cnt);
70 dmb();
71 }
Ye Li62862b62017-02-22 16:21:48 +080072}
73
Alice Guoab63a6e2022-10-21 16:41:18 +080074void ulp_watchdog_init(struct wdog_regs *wdog, u16 timeout)
Ye Li62862b62017-02-22 16:21:48 +080075{
Ye Li67439162022-10-21 16:41:15 +080076 u32 cmd32 = 0;
Ye Li62862b62017-02-22 16:21:48 +080077
Ye Li67439162022-10-21 16:41:15 +080078 if (readl(&wdog->cs) & WDGCS_CMD32EN) {
79 writel(UNLOCK_WORD, &wdog->cnt);
80 cmd32 = WDGCS_CMD32EN;
81 } else {
82 dmb();
83 __raw_writel(UNLOCK_WORD0, &wdog->cnt);
84 __raw_writel(UNLOCK_WORD1, &wdog->cnt);
85 dmb();
86 }
Ye Li62862b62017-02-22 16:21:48 +080087
Breno Lima4a686892021-06-29 10:32:35 +080088 /* Wait WDOG Unlock */
89 while (!(readl(&wdog->cs) & WDGCS_ULK))
90 ;
Ye Li62862b62017-02-22 16:21:48 +080091
Alice Guoab63a6e2022-10-21 16:41:18 +080092 hw_watchdog_set_timeout(timeout);
Ye Li62862b62017-02-22 16:21:48 +080093 writel(0, &wdog->win);
94
Breno Lima4a686892021-06-29 10:32:35 +080095 /* setting 1-kHz clock source, enable counter running, and clear interrupt */
Alice Guodea73ea2022-10-21 16:41:16 +080096 if (IS_ENABLED(CONFIG_ARCH_IMX9))
97 writel((cmd32 | WDGCS_WDGE | WDGCS_WDGUPDATE | (WDG_LPO_CLK << 8) |
Alice Guo71e0e6c2022-10-21 16:41:17 +080098 WDGCS_FLG | WDOG_CS_PRES | WDGCS_INT), &wdog->cs);
Alice Guodea73ea2022-10-21 16:41:16 +080099 else
100 writel((cmd32 | WDGCS_WDGE | WDGCS_WDGUPDATE | (WDG_LPO_CLK << 8) |
101 WDGCS_FLG), &wdog->cs);
Breno Lima4a686892021-06-29 10:32:35 +0800102
103 /* Wait WDOG reconfiguration */
104 while (!(readl(&wdog->cs) & WDGCS_RCS))
105 ;
Ye Li62862b62017-02-22 16:21:48 +0800106
Alice Guoab63a6e2022-10-21 16:41:18 +0800107 ulp_watchdog_reset(wdog);
108}
109
110void hw_watchdog_reset(void)
111{
112 struct wdog_regs *wdog = (struct wdog_regs *)WDOG_BASE_ADDR;
113
114 ulp_watchdog_reset(wdog);
Ye Li62862b62017-02-22 16:21:48 +0800115}
116
Alice Guoab63a6e2022-10-21 16:41:18 +0800117void hw_watchdog_init(void)
118{
119 struct wdog_regs *wdog = (struct wdog_regs *)WDOG_BASE_ADDR;
120
121 ulp_watchdog_init(wdog, CONFIG_WATCHDOG_TIMEOUT_MSECS);
122}
123
Peng Fan8a26d342023-04-28 12:08:26 +0800124#if !CONFIG_IS_ENABLED(SYSRESET)
Harald Seiler6f14d5f2020-12-15 16:47:52 +0100125void reset_cpu(void)
Ye Li62862b62017-02-22 16:21:48 +0800126{
127 struct wdog_regs *wdog = (struct wdog_regs *)WDOG_BASE_ADDR;
Ye Li67439162022-10-21 16:41:15 +0800128 u32 cmd32 = 0;
Ye Li62862b62017-02-22 16:21:48 +0800129
Ye Li67439162022-10-21 16:41:15 +0800130 if (readl(&wdog->cs) & WDGCS_CMD32EN) {
131 writel(UNLOCK_WORD, &wdog->cnt);
132 cmd32 = WDGCS_CMD32EN;
133 } else {
134 dmb();
135 __raw_writel(UNLOCK_WORD0, &wdog->cnt);
136 __raw_writel(UNLOCK_WORD1, &wdog->cnt);
137 dmb();
138 }
Ye Li62862b62017-02-22 16:21:48 +0800139
Breno Lima4a686892021-06-29 10:32:35 +0800140 /* Wait WDOG Unlock */
141 while (!(readl(&wdog->cs) & WDGCS_ULK))
142 ;
143
Alice Guodea73ea2022-10-21 16:41:16 +0800144 hw_watchdog_set_timeout(5); /* 5ms timeout for general; 40ms timeout for imx93 */
Ye Li62862b62017-02-22 16:21:48 +0800145 writel(0, &wdog->win);
146
Breno Lima4a686892021-06-29 10:32:35 +0800147 /* enable counter running */
Alice Guodea73ea2022-10-21 16:41:16 +0800148 if (IS_ENABLED(CONFIG_ARCH_IMX9))
Alice Guo71e0e6c2022-10-21 16:41:17 +0800149 writel((cmd32 | WDGCS_WDGE | (WDG_LPO_CLK << 8) | WDOG_CS_PRES |
150 WDGCS_INT), &wdog->cs);
Alice Guodea73ea2022-10-21 16:41:16 +0800151 else
152 writel((cmd32 | WDGCS_WDGE | (WDG_LPO_CLK << 8)), &wdog->cs);
Breno Lima4a686892021-06-29 10:32:35 +0800153
154 /* Wait WDOG reconfiguration */
155 while (!(readl(&wdog->cs) & WDGCS_RCS))
156 ;
Ye Li62862b62017-02-22 16:21:48 +0800157
158 hw_watchdog_reset();
159
160 while (1);
161}
Peng Fan8a26d342023-04-28 12:08:26 +0800162#endif
Alice Guoab63a6e2022-10-21 16:41:18 +0800163
164static int ulp_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
165{
166 struct ulp_wdt_priv *priv = dev_get_priv(dev);
167 u64 timeout = 0;
168
169 timeout = (timeout_ms * priv->clk_rate) / 1000;
170 if (timeout > U16_MAX)
171 return -EINVAL;
172
173 ulp_watchdog_init(priv->wdog, (u16)timeout);
174
175 return 0;
176}
177
178static int ulp_wdt_reset(struct udevice *dev)
179{
180 struct ulp_wdt_priv *priv = dev_get_priv(dev);
181
182 ulp_watchdog_reset(priv->wdog);
183
184 return 0;
185}
186
187static int ulp_wdt_probe(struct udevice *dev)
188{
189 struct ulp_wdt_priv *priv = dev_get_priv(dev);
190
191 priv->wdog = dev_read_addr_ptr(dev);
192 if (!priv->wdog)
193 return -EINVAL;
194
195 priv->clk_rate = (u32)dev_get_driver_data(dev);
196 if (!priv->clk_rate)
197 return -EINVAL;
198
199 return 0;
200}
201
202static const struct wdt_ops ulp_wdt_ops = {
203 .start = ulp_wdt_start,
204 .reset = ulp_wdt_reset,
205};
206
207static const struct udevice_id ulp_wdt_ids[] = {
208 { .compatible = "fsl,imx7ulp-wdt", .data = CLK_RATE_1KHZ },
209 { .compatible = "fsl,imx8ulp-wdt", .data = CLK_RATE_1KHZ },
210 { .compatible = "fsl,imx93-wdt", .data = CLK_RATE_32KHZ },
211 {}
212};
213
214U_BOOT_DRIVER(ulp_wdt) = {
215 .name = "ulp_wdt",
216 .id = UCLASS_WDT,
217 .of_match = ulp_wdt_ids,
218 .priv_auto = sizeof(struct ulp_wdt_priv),
219 .probe = ulp_wdt_probe,
220 .ops = &ulp_wdt_ops,
221};