blob: e0810543048533eda56fc24daa6b0a67727d69e8 [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
6#include <common.h>
Simon Glassafb02152019-12-28 10:45:01 -07007#include <cpu_func.h>
Ye Li62862b62017-02-22 16:21:48 +08008#include <asm/io.h>
9#include <asm/arch/imx-regs.h>
Alice Guoab63a6e2022-10-21 16:41:18 +080010#include <dm.h>
11#include <wdt.h>
Ye Li62862b62017-02-22 16:21:48 +080012
13/*
14 * MX7ULP WDOG Register Map
15 */
16struct wdog_regs {
Breno Lima4a686892021-06-29 10:32:35 +080017 u32 cs;
Ye Li62862b62017-02-22 16:21:48 +080018 u32 cnt;
19 u32 toval;
20 u32 win;
21};
22
Alice Guoab63a6e2022-10-21 16:41:18 +080023struct ulp_wdt_priv {
24 struct wdog_regs *wdog;
25 u32 clk_rate;
26};
27
Ye Li62862b62017-02-22 16:21:48 +080028#ifndef CONFIG_WATCHDOG_TIMEOUT_MSECS
29#define CONFIG_WATCHDOG_TIMEOUT_MSECS 0x1500
30#endif
31
32#define REFRESH_WORD0 0xA602 /* 1st refresh word */
33#define REFRESH_WORD1 0xB480 /* 2nd refresh word */
34
35#define UNLOCK_WORD0 0xC520 /* 1st unlock word */
36#define UNLOCK_WORD1 0xD928 /* 2nd unlock word */
37
Ye Li67439162022-10-21 16:41:15 +080038#define UNLOCK_WORD 0xD928C520 /* unlock word */
39#define REFRESH_WORD 0xB480A602 /* refresh word */
40
Breno Lima4a686892021-06-29 10:32:35 +080041#define WDGCS_WDGE BIT(7)
42#define WDGCS_WDGUPDATE BIT(5)
Ye Li62862b62017-02-22 16:21:48 +080043
Breno Lima4a686892021-06-29 10:32:35 +080044#define WDGCS_RCS BIT(10)
45#define WDGCS_ULK BIT(11)
Alice Guodea73ea2022-10-21 16:41:16 +080046#define WDOG_CS_PRES BIT(12)
Ye Li67439162022-10-21 16:41:15 +080047#define WDGCS_CMD32EN BIT(13)
Breno Lima4a686892021-06-29 10:32:35 +080048#define WDGCS_FLG BIT(14)
Alice Guo71e0e6c2022-10-21 16:41:17 +080049#define WDGCS_INT BIT(6)
Ye Li62862b62017-02-22 16:21:48 +080050
51#define WDG_BUS_CLK (0x0)
52#define WDG_LPO_CLK (0x1)
53#define WDG_32KHZ_CLK (0x2)
54#define WDG_EXT_CLK (0x3)
55
Alice Guoab63a6e2022-10-21 16:41:18 +080056#define CLK_RATE_1KHZ 1000
57#define CLK_RATE_32KHZ 125
58
Ye Li62862b62017-02-22 16:21:48 +080059void hw_watchdog_set_timeout(u16 val)
60{
61 /* setting timeout value */
62 struct wdog_regs *wdog = (struct wdog_regs *)WDOG_BASE_ADDR;
63
64 writel(val, &wdog->toval);
65}
66
Alice Guoab63a6e2022-10-21 16:41:18 +080067void ulp_watchdog_reset(struct wdog_regs *wdog)
Ye Li62862b62017-02-22 16:21:48 +080068{
Ye Li67439162022-10-21 16:41:15 +080069 if (readl(&wdog->cs) & WDGCS_CMD32EN) {
70 writel(REFRESH_WORD, &wdog->cnt);
71 } else {
72 dmb();
73 __raw_writel(REFRESH_WORD0, &wdog->cnt);
74 __raw_writel(REFRESH_WORD1, &wdog->cnt);
75 dmb();
76 }
Ye Li62862b62017-02-22 16:21:48 +080077}
78
Alice Guoab63a6e2022-10-21 16:41:18 +080079void ulp_watchdog_init(struct wdog_regs *wdog, u16 timeout)
Ye Li62862b62017-02-22 16:21:48 +080080{
Ye Li67439162022-10-21 16:41:15 +080081 u32 cmd32 = 0;
Ye Li62862b62017-02-22 16:21:48 +080082
Ye Li67439162022-10-21 16:41:15 +080083 if (readl(&wdog->cs) & WDGCS_CMD32EN) {
84 writel(UNLOCK_WORD, &wdog->cnt);
85 cmd32 = WDGCS_CMD32EN;
86 } else {
87 dmb();
88 __raw_writel(UNLOCK_WORD0, &wdog->cnt);
89 __raw_writel(UNLOCK_WORD1, &wdog->cnt);
90 dmb();
91 }
Ye Li62862b62017-02-22 16:21:48 +080092
Breno Lima4a686892021-06-29 10:32:35 +080093 /* Wait WDOG Unlock */
94 while (!(readl(&wdog->cs) & WDGCS_ULK))
95 ;
Ye Li62862b62017-02-22 16:21:48 +080096
Alice Guoab63a6e2022-10-21 16:41:18 +080097 hw_watchdog_set_timeout(timeout);
Ye Li62862b62017-02-22 16:21:48 +080098 writel(0, &wdog->win);
99
Breno Lima4a686892021-06-29 10:32:35 +0800100 /* setting 1-kHz clock source, enable counter running, and clear interrupt */
Alice Guodea73ea2022-10-21 16:41:16 +0800101 if (IS_ENABLED(CONFIG_ARCH_IMX9))
102 writel((cmd32 | WDGCS_WDGE | WDGCS_WDGUPDATE | (WDG_LPO_CLK << 8) |
Alice Guo71e0e6c2022-10-21 16:41:17 +0800103 WDGCS_FLG | WDOG_CS_PRES | WDGCS_INT), &wdog->cs);
Alice Guodea73ea2022-10-21 16:41:16 +0800104 else
105 writel((cmd32 | WDGCS_WDGE | WDGCS_WDGUPDATE | (WDG_LPO_CLK << 8) |
106 WDGCS_FLG), &wdog->cs);
Breno Lima4a686892021-06-29 10:32:35 +0800107
108 /* Wait WDOG reconfiguration */
109 while (!(readl(&wdog->cs) & WDGCS_RCS))
110 ;
Ye Li62862b62017-02-22 16:21:48 +0800111
Alice Guoab63a6e2022-10-21 16:41:18 +0800112 ulp_watchdog_reset(wdog);
113}
114
115void hw_watchdog_reset(void)
116{
117 struct wdog_regs *wdog = (struct wdog_regs *)WDOG_BASE_ADDR;
118
119 ulp_watchdog_reset(wdog);
Ye Li62862b62017-02-22 16:21:48 +0800120}
121
Alice Guoab63a6e2022-10-21 16:41:18 +0800122void hw_watchdog_init(void)
123{
124 struct wdog_regs *wdog = (struct wdog_regs *)WDOG_BASE_ADDR;
125
126 ulp_watchdog_init(wdog, CONFIG_WATCHDOG_TIMEOUT_MSECS);
127}
128
Harald Seiler6f14d5f2020-12-15 16:47:52 +0100129void reset_cpu(void)
Ye Li62862b62017-02-22 16:21:48 +0800130{
131 struct wdog_regs *wdog = (struct wdog_regs *)WDOG_BASE_ADDR;
Ye Li67439162022-10-21 16:41:15 +0800132 u32 cmd32 = 0;
Ye Li62862b62017-02-22 16:21:48 +0800133
Ye Li67439162022-10-21 16:41:15 +0800134 if (readl(&wdog->cs) & WDGCS_CMD32EN) {
135 writel(UNLOCK_WORD, &wdog->cnt);
136 cmd32 = WDGCS_CMD32EN;
137 } else {
138 dmb();
139 __raw_writel(UNLOCK_WORD0, &wdog->cnt);
140 __raw_writel(UNLOCK_WORD1, &wdog->cnt);
141 dmb();
142 }
Ye Li62862b62017-02-22 16:21:48 +0800143
Breno Lima4a686892021-06-29 10:32:35 +0800144 /* Wait WDOG Unlock */
145 while (!(readl(&wdog->cs) & WDGCS_ULK))
146 ;
147
Alice Guodea73ea2022-10-21 16:41:16 +0800148 hw_watchdog_set_timeout(5); /* 5ms timeout for general; 40ms timeout for imx93 */
Ye Li62862b62017-02-22 16:21:48 +0800149 writel(0, &wdog->win);
150
Breno Lima4a686892021-06-29 10:32:35 +0800151 /* enable counter running */
Alice Guodea73ea2022-10-21 16:41:16 +0800152 if (IS_ENABLED(CONFIG_ARCH_IMX9))
Alice Guo71e0e6c2022-10-21 16:41:17 +0800153 writel((cmd32 | WDGCS_WDGE | (WDG_LPO_CLK << 8) | WDOG_CS_PRES |
154 WDGCS_INT), &wdog->cs);
Alice Guodea73ea2022-10-21 16:41:16 +0800155 else
156 writel((cmd32 | WDGCS_WDGE | (WDG_LPO_CLK << 8)), &wdog->cs);
Breno Lima4a686892021-06-29 10:32:35 +0800157
158 /* Wait WDOG reconfiguration */
159 while (!(readl(&wdog->cs) & WDGCS_RCS))
160 ;
Ye Li62862b62017-02-22 16:21:48 +0800161
162 hw_watchdog_reset();
163
164 while (1);
165}
Alice Guoab63a6e2022-10-21 16:41:18 +0800166
167static int ulp_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
168{
169 struct ulp_wdt_priv *priv = dev_get_priv(dev);
170 u64 timeout = 0;
171
172 timeout = (timeout_ms * priv->clk_rate) / 1000;
173 if (timeout > U16_MAX)
174 return -EINVAL;
175
176 ulp_watchdog_init(priv->wdog, (u16)timeout);
177
178 return 0;
179}
180
181static int ulp_wdt_reset(struct udevice *dev)
182{
183 struct ulp_wdt_priv *priv = dev_get_priv(dev);
184
185 ulp_watchdog_reset(priv->wdog);
186
187 return 0;
188}
189
190static int ulp_wdt_probe(struct udevice *dev)
191{
192 struct ulp_wdt_priv *priv = dev_get_priv(dev);
193
194 priv->wdog = dev_read_addr_ptr(dev);
195 if (!priv->wdog)
196 return -EINVAL;
197
198 priv->clk_rate = (u32)dev_get_driver_data(dev);
199 if (!priv->clk_rate)
200 return -EINVAL;
201
202 return 0;
203}
204
205static const struct wdt_ops ulp_wdt_ops = {
206 .start = ulp_wdt_start,
207 .reset = ulp_wdt_reset,
208};
209
210static const struct udevice_id ulp_wdt_ids[] = {
211 { .compatible = "fsl,imx7ulp-wdt", .data = CLK_RATE_1KHZ },
212 { .compatible = "fsl,imx8ulp-wdt", .data = CLK_RATE_1KHZ },
213 { .compatible = "fsl,imx93-wdt", .data = CLK_RATE_32KHZ },
214 {}
215};
216
217U_BOOT_DRIVER(ulp_wdt) = {
218 .name = "ulp_wdt",
219 .id = UCLASS_WDT,
220 .of_match = ulp_wdt_ids,
221 .priv_auto = sizeof(struct ulp_wdt_priv),
222 .probe = ulp_wdt_probe,
223 .ops = &ulp_wdt_ops,
224};