1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2016 Freescale Semiconductor, Inc.
4  */
5 
6 #include <common.h>
7 #include <cpu_func.h>
8 #include <asm/io.h>
9 #include <asm/arch/imx-regs.h>
10 #include <dm.h>
11 #include <wdt.h>
12 
13 /*
14  * MX7ULP WDOG Register Map
15  */
16 struct wdog_regs {
17 	u32 cs;
18 	u32 cnt;
19 	u32 toval;
20 	u32 win;
21 };
22 
23 struct ulp_wdt_priv {
24 	struct wdog_regs *wdog;
25 	u32 clk_rate;
26 };
27 
28 #define REFRESH_WORD0 0xA602 /* 1st refresh word */
29 #define REFRESH_WORD1 0xB480 /* 2nd refresh word */
30 
31 #define UNLOCK_WORD0 0xC520 /* 1st unlock word */
32 #define UNLOCK_WORD1 0xD928 /* 2nd unlock word */
33 
34 #define UNLOCK_WORD 0xD928C520 /* unlock word */
35 #define REFRESH_WORD 0xB480A602 /* refresh word */
36 
37 #define WDGCS_WDGE                      BIT(7)
38 #define WDGCS_WDGUPDATE                 BIT(5)
39 
40 #define WDGCS_RCS                       BIT(10)
41 #define WDGCS_ULK                       BIT(11)
42 #define WDOG_CS_PRES                    BIT(12)
43 #define WDGCS_CMD32EN                   BIT(13)
44 #define WDGCS_FLG                       BIT(14)
45 #define WDGCS_INT			BIT(6)
46 
47 #define WDG_BUS_CLK                      (0x0)
48 #define WDG_LPO_CLK                      (0x1)
49 #define WDG_32KHZ_CLK                    (0x2)
50 #define WDG_EXT_CLK                      (0x3)
51 
52 #define CLK_RATE_1KHZ			1000
53 #define CLK_RATE_32KHZ			125
54 
hw_watchdog_set_timeout(u16 val)55 void hw_watchdog_set_timeout(u16 val)
56 {
57 	/* setting timeout value */
58 	struct wdog_regs *wdog = (struct wdog_regs *)WDOG_BASE_ADDR;
59 
60 	writel(val, &wdog->toval);
61 }
62 
ulp_watchdog_reset(struct wdog_regs * wdog)63 void ulp_watchdog_reset(struct wdog_regs *wdog)
64 {
65 	if (readl(&wdog->cs) & WDGCS_CMD32EN) {
66 		writel(REFRESH_WORD, &wdog->cnt);
67 	} else {
68 		dmb();
69 		__raw_writel(REFRESH_WORD0, &wdog->cnt);
70 		__raw_writel(REFRESH_WORD1, &wdog->cnt);
71 		dmb();
72 	}
73 }
74 
ulp_watchdog_init(struct wdog_regs * wdog,u16 timeout)75 void ulp_watchdog_init(struct wdog_regs *wdog, u16 timeout)
76 {
77 	u32 cmd32 = 0;
78 
79 	if (readl(&wdog->cs) & WDGCS_CMD32EN) {
80 		writel(UNLOCK_WORD, &wdog->cnt);
81 		cmd32 = WDGCS_CMD32EN;
82 	} else {
83 		dmb();
84 		__raw_writel(UNLOCK_WORD0, &wdog->cnt);
85 		__raw_writel(UNLOCK_WORD1, &wdog->cnt);
86 		dmb();
87 	}
88 
89 	/* Wait WDOG Unlock */
90 	while (!(readl(&wdog->cs) & WDGCS_ULK))
91 		;
92 
93 	hw_watchdog_set_timeout(timeout);
94 	writel(0, &wdog->win);
95 
96 	/* setting 1-kHz clock source, enable counter running, and clear interrupt */
97 	if (IS_ENABLED(CONFIG_ARCH_IMX9))
98 		writel((cmd32 | WDGCS_WDGE | WDGCS_WDGUPDATE | (WDG_LPO_CLK << 8) |
99 		       WDGCS_FLG | WDOG_CS_PRES | WDGCS_INT), &wdog->cs);
100 	else
101 		writel((cmd32 | WDGCS_WDGE | WDGCS_WDGUPDATE | (WDG_LPO_CLK << 8) |
102 		       WDGCS_FLG), &wdog->cs);
103 
104 	/* Wait WDOG reconfiguration */
105 	while (!(readl(&wdog->cs) & WDGCS_RCS))
106 		;
107 
108 	ulp_watchdog_reset(wdog);
109 }
110 
hw_watchdog_reset(void)111 void hw_watchdog_reset(void)
112 {
113 	struct wdog_regs *wdog = (struct wdog_regs *)WDOG_BASE_ADDR;
114 
115 	ulp_watchdog_reset(wdog);
116 }
117 
hw_watchdog_init(void)118 void hw_watchdog_init(void)
119 {
120 	struct wdog_regs *wdog = (struct wdog_regs *)WDOG_BASE_ADDR;
121 
122 	ulp_watchdog_init(wdog, CONFIG_WATCHDOG_TIMEOUT_MSECS);
123 }
124 
125 #if !CONFIG_IS_ENABLED(SYSRESET)
reset_cpu(void)126 void reset_cpu(void)
127 {
128 	struct wdog_regs *wdog = (struct wdog_regs *)WDOG_BASE_ADDR;
129 	u32 cmd32 = 0;
130 
131 	if (readl(&wdog->cs) & WDGCS_CMD32EN) {
132 		writel(UNLOCK_WORD, &wdog->cnt);
133 		cmd32 = WDGCS_CMD32EN;
134 	} else {
135 		dmb();
136 		__raw_writel(UNLOCK_WORD0, &wdog->cnt);
137 		__raw_writel(UNLOCK_WORD1, &wdog->cnt);
138 		dmb();
139 	}
140 
141 	/* Wait WDOG Unlock */
142 	while (!(readl(&wdog->cs) & WDGCS_ULK))
143 		;
144 
145 	hw_watchdog_set_timeout(5); /* 5ms timeout for general; 40ms timeout for imx93 */
146 	writel(0, &wdog->win);
147 
148 	/* enable counter running */
149 	if (IS_ENABLED(CONFIG_ARCH_IMX9))
150 		writel((cmd32 | WDGCS_WDGE | (WDG_LPO_CLK << 8) | WDOG_CS_PRES |
151 		       WDGCS_INT), &wdog->cs);
152 	else
153 		writel((cmd32 | WDGCS_WDGE | (WDG_LPO_CLK << 8)), &wdog->cs);
154 
155 	/* Wait WDOG reconfiguration */
156 	while (!(readl(&wdog->cs) & WDGCS_RCS))
157 		;
158 
159 	hw_watchdog_reset();
160 
161 	while (1);
162 }
163 #endif
164 
ulp_wdt_start(struct udevice * dev,u64 timeout_ms,ulong flags)165 static int ulp_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
166 {
167 	struct ulp_wdt_priv *priv = dev_get_priv(dev);
168 	u64 timeout = 0;
169 
170 	timeout = (timeout_ms * priv->clk_rate) / 1000;
171 	if (timeout > U16_MAX)
172 		return -EINVAL;
173 
174 	ulp_watchdog_init(priv->wdog, (u16)timeout);
175 
176 	return 0;
177 }
178 
ulp_wdt_reset(struct udevice * dev)179 static int ulp_wdt_reset(struct udevice *dev)
180 {
181 	struct ulp_wdt_priv *priv = dev_get_priv(dev);
182 
183 	ulp_watchdog_reset(priv->wdog);
184 
185 	return 0;
186 }
187 
ulp_wdt_probe(struct udevice * dev)188 static int ulp_wdt_probe(struct udevice *dev)
189 {
190 	struct ulp_wdt_priv *priv = dev_get_priv(dev);
191 
192 	priv->wdog = dev_read_addr_ptr(dev);
193 	if (!priv->wdog)
194 		return -EINVAL;
195 
196 	priv->clk_rate = (u32)dev_get_driver_data(dev);
197 	if (!priv->clk_rate)
198 		return -EINVAL;
199 
200 	return 0;
201 }
202 
203 static const struct wdt_ops ulp_wdt_ops = {
204 	.start = ulp_wdt_start,
205 	.reset = ulp_wdt_reset,
206 };
207 
208 static const struct udevice_id ulp_wdt_ids[] = {
209 	{ .compatible = "fsl,imx7ulp-wdt", .data = CLK_RATE_1KHZ },
210 	{ .compatible = "fsl,imx8ulp-wdt", .data = CLK_RATE_1KHZ },
211 	{ .compatible = "fsl,imx93-wdt", .data = CLK_RATE_32KHZ },
212 	{}
213 };
214 
215 U_BOOT_DRIVER(ulp_wdt) = {
216 	.name	= "ulp_wdt",
217 	.id	= UCLASS_WDT,
218 	.of_match	= ulp_wdt_ids,
219 	.priv_auto	= sizeof(struct ulp_wdt_priv),
220 	.probe		= ulp_wdt_probe,
221 	.ops	= &ulp_wdt_ops,
222 };
223