Merge tag 'u-boot-atmel-fixes-2020.04-a' of https://gitlab.denx.de/u-boot/custodians...
[oweals/u-boot.git] / drivers / watchdog / omap_wdt.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * omap_wdt.c
4  *
5  * (C) Copyright 2013
6  * Heiko Schocher, DENX Software Engineering, hs@denx.de.
7  *
8  * Based on:
9  *
10  * Watchdog driver for the TI OMAP 16xx & 24xx/34xx 32KHz (non-secure) watchdog
11  *
12  * commit 2d991a164a61858012651e13c59521975504e260
13  * Author: Bill Pemberton <wfp5p@virginia.edu>
14  * Date:   Mon Nov 19 13:21:41 2012 -0500
15  *
16  * watchdog: remove use of __devinit
17  *
18  * CONFIG_HOTPLUG is going away as an option so __devinit is no longer
19  * needed.
20  *
21  * Author: MontaVista Software, Inc.
22  *       <gdavis@mvista.com> or <source@mvista.com>
23  *
24  * History:
25  *
26  * 20030527: George G. Davis <gdavis@mvista.com>
27  *      Initially based on linux-2.4.19-rmk7-pxa1/drivers/char/sa1100_wdt.c
28  *      (c) Copyright 2000 Oleg Drokin <green@crimea.edu>
29  *      Based on SoftDog driver by Alan Cox <alan@lxorguk.ukuu.org.uk>
30  *
31  * Copyright (c) 2004 Texas Instruments.
32  *      1. Modified to support OMAP1610 32-KHz watchdog timer
33  *      2. Ported to 2.6 kernel
34  *
35  * Copyright (c) 2005 David Brownell
36  *      Use the driver model and standard identifiers; handle bigger timeouts.
37  */
38
39 #include <common.h>
40 #include <watchdog.h>
41 #include <asm/arch/hardware.h>
42 #include <asm/io.h>
43 #include <asm/processor.h>
44 #include <asm/arch/cpu.h>
45 #include <wdt.h>
46 #include <dm.h>
47 #include <errno.h>
48
49 /* Hardware timeout in seconds */
50 #define WDT_HW_TIMEOUT 60
51
52 #if !CONFIG_IS_ENABLED(WDT)
53 static unsigned int wdt_trgr_pattern = 0x1234;
54
55 void hw_watchdog_reset(void)
56 {
57         struct wd_timer *wdt = (struct wd_timer *)WDT_BASE;
58
59         /*
60          * Somebody just triggered watchdog reset and write to WTGR register
61          * is in progress. It is resetting right now, no need to trigger it
62          * again
63          */
64         if ((readl(&wdt->wdtwwps)) & WDT_WWPS_PEND_WTGR)
65                 return;
66
67         wdt_trgr_pattern = ~wdt_trgr_pattern;
68         writel(wdt_trgr_pattern, &wdt->wdtwtgr);
69
70         /*
71          * Don't wait for posted write to complete, i.e. don't check
72          * WDT_WWPS_PEND_WTGR bit in WWPS register. There is no writes to
73          * WTGR register outside of this func, and if entering it
74          * we see WDT_WWPS_PEND_WTGR bit set, it means watchdog reset
75          * was just triggered. This prevents us from wasting time in busy
76          * polling of WDT_WWPS_PEND_WTGR bit.
77          */
78 }
79
80 static int omap_wdt_set_timeout(unsigned int timeout)
81 {
82         struct wd_timer *wdt = (struct wd_timer *)WDT_BASE;
83         u32 pre_margin = GET_WLDR_VAL(timeout);
84
85         /* just count up at 32 KHz */
86         while (readl(&wdt->wdtwwps) & WDT_WWPS_PEND_WLDR)
87                 ;
88
89         writel(pre_margin, &wdt->wdtwldr);
90         while (readl(&wdt->wdtwwps) & WDT_WWPS_PEND_WLDR)
91                 ;
92
93         return 0;
94 }
95
96 void hw_watchdog_disable(void)
97 {
98         struct wd_timer *wdt = (struct wd_timer *)WDT_BASE;
99
100         /*
101          * Disable watchdog
102          */
103         writel(0xAAAA, &wdt->wdtwspr);
104         while (readl(&wdt->wdtwwps) != 0x0)
105                 ;
106         writel(0x5555, &wdt->wdtwspr);
107         while (readl(&wdt->wdtwwps) != 0x0)
108                 ;
109 }
110
111 void hw_watchdog_init(void)
112 {
113         struct wd_timer *wdt = (struct wd_timer *)WDT_BASE;
114
115         /*
116          * Make sure the watchdog is disabled. This is unfortunately required
117          * because writing to various registers with the watchdog running has no
118          * effect.
119          */
120         hw_watchdog_disable();
121
122         /* initialize prescaler */
123         while (readl(&wdt->wdtwwps) & WDT_WWPS_PEND_WCLR)
124                 ;
125
126         writel(WDT_WCLR_PRE | (PTV << WDT_WCLR_PTV_OFF), &wdt->wdtwclr);
127         while (readl(&wdt->wdtwwps) & WDT_WWPS_PEND_WCLR)
128                 ;
129
130         omap_wdt_set_timeout(WDT_HW_TIMEOUT);
131
132         /* Sequence to enable the watchdog */
133         writel(0xBBBB, &wdt->wdtwspr);
134         while ((readl(&wdt->wdtwwps)) & WDT_WWPS_PEND_WSPR)
135                 ;
136
137         writel(0x4444, &wdt->wdtwspr);
138         while ((readl(&wdt->wdtwwps)) & WDT_WWPS_PEND_WSPR)
139                 ;
140 }
141
142 void watchdog_reset(void)
143 {
144         hw_watchdog_reset();
145 }
146
147 #else
148
149 static int omap3_wdt_reset(struct udevice *dev)
150 {
151         struct omap3_wdt_priv *priv = dev_get_priv(dev);
152
153         /*
154          * Somebody just triggered watchdog reset and write to WTGR register
155          * is in progress. It is resetting right now, no need to trigger it
156          * again
157          */
158         if ((readl(&priv->regs->wdtwwps)) & WDT_WWPS_PEND_WTGR)
159                 return 0;
160
161         priv->wdt_trgr_pattern = ~(priv->wdt_trgr_pattern);
162         writel(priv->wdt_trgr_pattern, &priv->regs->wdtwtgr);
163         /*
164          * Don't wait for posted write to complete, i.e. don't check
165          * WDT_WWPS_PEND_WTGR bit in WWPS register. There is no writes to
166          * WTGR register outside of this func, and if entering it
167          * we see WDT_WWPS_PEND_WTGR bit set, it means watchdog reset
168          * was just triggered. This prevents us from wasting time in busy
169          * polling of WDT_WWPS_PEND_WTGR bit.
170          */
171         return 0;
172 }
173
174 static int omap3_wdt_stop(struct udevice *dev)
175 {
176         struct omap3_wdt_priv *priv = dev_get_priv(dev);
177
178         /* disable watchdog */
179         writel(0xAAAA, &priv->regs->wdtwspr);
180         while (readl(&priv->regs->wdtwwps) != 0x0)
181                 ;
182         writel(0x5555, &priv->regs->wdtwspr);
183         while (readl(&priv->regs->wdtwwps) != 0x0)
184                 ;
185         return 0;
186 }
187
188 static int omap3_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
189 {
190         struct omap3_wdt_priv *priv = dev_get_priv(dev);
191         u32 pre_margin = GET_WLDR_VAL(timeout_ms / 1000);
192         /*
193          * Make sure the watchdog is disabled. This is unfortunately required
194          * because writing to various registers with the watchdog running has
195          * no effect.
196          */
197         omap3_wdt_stop(dev);
198
199         /* initialize prescaler */
200         while (readl(&priv->regs->wdtwwps) & WDT_WWPS_PEND_WCLR)
201                 ;
202
203         writel(WDT_WCLR_PRE | (PTV << WDT_WCLR_PTV_OFF), &priv->regs->wdtwclr);
204         while (readl(&priv->regs->wdtwwps) & WDT_WWPS_PEND_WCLR)
205                 ;
206         /* just count up at 32 KHz */
207         while (readl(&priv->regs->wdtwwps) & WDT_WWPS_PEND_WLDR)
208                 ;
209
210         writel(pre_margin, &priv->regs->wdtwldr);
211         while (readl(&priv->regs->wdtwwps) & WDT_WWPS_PEND_WLDR)
212                 ;
213         /* Sequence to enable the watchdog */
214         writel(0xBBBB, &priv->regs->wdtwspr);
215         while ((readl(&priv->regs->wdtwwps)) & WDT_WWPS_PEND_WSPR)
216                 ;
217
218         writel(0x4444, &priv->regs->wdtwspr);
219         while ((readl(&priv->regs->wdtwwps)) & WDT_WWPS_PEND_WSPR)
220                 ;
221
222         /* Trigger the watchdog to actually reload the counter. */
223         while ((readl(&priv->regs->wdtwwps)) & WDT_WWPS_PEND_WTGR)
224                 ;
225
226         priv->wdt_trgr_pattern = ~(priv->wdt_trgr_pattern);
227         writel(priv->wdt_trgr_pattern, &priv->regs->wdtwtgr);
228
229         while ((readl(&priv->regs->wdtwwps)) & WDT_WWPS_PEND_WTGR)
230                 ;
231
232         return 0;
233 }
234
235 static int omap3_wdt_probe(struct udevice *dev)
236 {
237         struct omap3_wdt_priv *priv = dev_get_priv(dev);
238
239         priv->regs = (struct wd_timer *)devfdt_get_addr(dev);
240         if (!priv->regs)
241                 return -EINVAL;
242
243         priv->wdt_trgr_pattern = 0x1234;
244         debug("%s: Probing wdt%u\n", __func__, dev->seq);
245         return 0;
246 }
247
248 static const struct wdt_ops omap3_wdt_ops = {
249         .start = omap3_wdt_start,
250         .stop = omap3_wdt_stop,
251         .reset = omap3_wdt_reset,
252 };
253
254 static const struct udevice_id omap3_wdt_ids[] = {
255         { .compatible = "ti,omap3-wdt" },
256         { }
257 };
258
259 U_BOOT_DRIVER(omap3_wdt) = {
260         .name = "omap3_wdt",
261         .id = UCLASS_WDT,
262         .of_match = omap3_wdt_ids,
263         .ops = &omap3_wdt_ops,
264         .probe = omap3_wdt_probe,
265         .priv_auto_alloc_size = sizeof(struct omap3_wdt_priv),
266 };
267 #endif /* !CONFIG_IS_ENABLED(WDT) */