]> git.ipfire.org Git - thirdparty/u-boot.git/blame - drivers/watchdog/ulp_wdog.c
Revert "Merge patch series "arm: dts: am62-beagleplay: Fix Beagleplay Ethernet""
[thirdparty/u-boot.git] / drivers / watchdog / ulp_wdog.c
CommitLineData
83d290c5 1// SPDX-License-Identifier: GPL-2.0+
253531bb
YL
2/*
3 * Copyright (C) 2016 Freescale Semiconductor, Inc.
253531bb
YL
4 */
5
d678a59d 6#include <common.h>
9a3b4ceb 7#include <cpu_func.h>
253531bb
YL
8#include <asm/io.h>
9#include <asm/arch/imx-regs.h>
5e112c7c
AG
10#include <dm.h>
11#include <wdt.h>
253531bb
YL
12
13/*
14 * MX7ULP WDOG Register Map
15 */
16struct wdog_regs {
edf95bde 17 u32 cs;
253531bb
YL
18 u32 cnt;
19 u32 toval;
20 u32 win;
21};
22
5e112c7c
AG
23struct ulp_wdt_priv {
24 struct wdog_regs *wdog;
25 u32 clk_rate;
26};
27
253531bb
YL
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
a79f2007
YL
34#define UNLOCK_WORD 0xD928C520 /* unlock word */
35#define REFRESH_WORD 0xB480A602 /* refresh word */
36
edf95bde
BL
37#define WDGCS_WDGE BIT(7)
38#define WDGCS_WDGUPDATE BIT(5)
253531bb 39
edf95bde
BL
40#define WDGCS_RCS BIT(10)
41#define WDGCS_ULK BIT(11)
ef0ad9b0 42#define WDOG_CS_PRES BIT(12)
a79f2007 43#define WDGCS_CMD32EN BIT(13)
edf95bde 44#define WDGCS_FLG BIT(14)
a7fd6335 45#define WDGCS_INT BIT(6)
253531bb
YL
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
5e112c7c
AG
52#define CLK_RATE_1KHZ 1000
53#define CLK_RATE_32KHZ 125
54
253531bb
YL
55void 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
5e112c7c 63void ulp_watchdog_reset(struct wdog_regs *wdog)
253531bb 64{
a79f2007
YL
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 }
253531bb
YL
73}
74
5e112c7c 75void ulp_watchdog_init(struct wdog_regs *wdog, u16 timeout)
253531bb 76{
a79f2007
YL
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 }
253531bb 88
edf95bde
BL
89 /* Wait WDOG Unlock */
90 while (!(readl(&wdog->cs) & WDGCS_ULK))
91 ;
253531bb 92
5e112c7c 93 hw_watchdog_set_timeout(timeout);
253531bb
YL
94 writel(0, &wdog->win);
95
edf95bde 96 /* setting 1-kHz clock source, enable counter running, and clear interrupt */
ef0ad9b0
AG
97 if (IS_ENABLED(CONFIG_ARCH_IMX9))
98 writel((cmd32 | WDGCS_WDGE | WDGCS_WDGUPDATE | (WDG_LPO_CLK << 8) |
a7fd6335 99 WDGCS_FLG | WDOG_CS_PRES | WDGCS_INT), &wdog->cs);
ef0ad9b0
AG
100 else
101 writel((cmd32 | WDGCS_WDGE | WDGCS_WDGUPDATE | (WDG_LPO_CLK << 8) |
102 WDGCS_FLG), &wdog->cs);
edf95bde
BL
103
104 /* Wait WDOG reconfiguration */
105 while (!(readl(&wdog->cs) & WDGCS_RCS))
106 ;
253531bb 107
5e112c7c
AG
108 ulp_watchdog_reset(wdog);
109}
110
111void hw_watchdog_reset(void)
112{
113 struct wdog_regs *wdog = (struct wdog_regs *)WDOG_BASE_ADDR;
114
115 ulp_watchdog_reset(wdog);
116}
117
118void 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);
253531bb
YL
123}
124
fee8cf21 125#if !CONFIG_IS_ENABLED(SYSRESET)
35b65dd8 126void reset_cpu(void)
253531bb
YL
127{
128 struct wdog_regs *wdog = (struct wdog_regs *)WDOG_BASE_ADDR;
a79f2007
YL
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 }
253531bb 140
edf95bde
BL
141 /* Wait WDOG Unlock */
142 while (!(readl(&wdog->cs) & WDGCS_ULK))
143 ;
144
ef0ad9b0 145 hw_watchdog_set_timeout(5); /* 5ms timeout for general; 40ms timeout for imx93 */
253531bb
YL
146 writel(0, &wdog->win);
147
edf95bde 148 /* enable counter running */
ef0ad9b0 149 if (IS_ENABLED(CONFIG_ARCH_IMX9))
a7fd6335
AG
150 writel((cmd32 | WDGCS_WDGE | (WDG_LPO_CLK << 8) | WDOG_CS_PRES |
151 WDGCS_INT), &wdog->cs);
ef0ad9b0
AG
152 else
153 writel((cmd32 | WDGCS_WDGE | (WDG_LPO_CLK << 8)), &wdog->cs);
edf95bde
BL
154
155 /* Wait WDOG reconfiguration */
156 while (!(readl(&wdog->cs) & WDGCS_RCS))
157 ;
253531bb
YL
158
159 hw_watchdog_reset();
160
161 while (1);
162}
fee8cf21 163#endif
5e112c7c
AG
164
165static 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
179static 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
188static 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
203static const struct wdt_ops ulp_wdt_ops = {
204 .start = ulp_wdt_start,
205 .reset = ulp_wdt_reset,
206};
207
208static 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
215U_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};