blob: 53a3e9f5c78e8a794c7098468973bafb78ec02f9 [file] [log] [blame]
Troy Kisky4b7c6022012-10-22 15:19:01 +00001/*
2 * watchdog.c - driver for i.mx on-chip watchdog
3 *
4 * Licensed under the GPL-2 or later.
5 */
6
7#include <common.h>
Marek Vasutf7fc5c12019-06-09 03:46:22 +02008#include <dm.h>
Troy Kisky4b7c6022012-10-22 15:19:01 +00009#include <asm/io.h>
Marek Vasutf7fc5c12019-06-09 03:46:22 +020010#include <wdt.h>
Troy Kisky4b7c6022012-10-22 15:19:01 +000011#include <watchdog.h>
12#include <asm/arch/imx-regs.h>
Xiaoliang Yanga6657ad2018-10-18 18:27:45 +080013#ifdef CONFIG_FSL_LSCH2
14#include <asm/arch/immap_lsch2.h>
15#endif
Fabio Estevamcd847ab2015-10-03 14:20:59 -030016#include <fsl_wdog.h>
Troy Kisky4b7c6022012-10-22 15:19:01 +000017
Marek Vasutf7fc5c12019-06-09 03:46:22 +020018static void imx_watchdog_expire_now(struct watchdog_regs *wdog)
Troy Kisky4b7c6022012-10-22 15:19:01 +000019{
Marek Vasutf7fc5c12019-06-09 03:46:22 +020020 clrsetbits_le16(&wdog->wcr, WCR_WT_MSK, WCR_WDE);
21
22 writew(0x5555, &wdog->wsr);
23 writew(0xaaaa, &wdog->wsr); /* load minimum 1/2 second timeout */
24 while (1) {
25 /*
26 * spin for .5 seconds before reset
27 */
28 }
29}
30
31#if !defined(CONFIG_IMX_WATCHDOG) || \
32 (defined(CONFIG_IMX_WATCHDOG) && !CONFIG_IS_ENABLED(WDT))
33void __attribute__((weak)) reset_cpu(ulong addr)
34{
Troy Kisky4b7c6022012-10-22 15:19:01 +000035 struct watchdog_regs *wdog = (struct watchdog_regs *)WDOG1_BASE_ADDR;
36
Marek Vasutf7fc5c12019-06-09 03:46:22 +020037 imx_watchdog_expire_now(wdog);
38}
39#endif
40
41#if defined(CONFIG_IMX_WATCHDOG)
42static void imx_watchdog_reset(struct watchdog_regs *wdog)
43{
44#ifndef CONFIG_WATCHDOG_RESET_DISABLE
Troy Kisky4b7c6022012-10-22 15:19:01 +000045 writew(0x5555, &wdog->wsr);
46 writew(0xaaaa, &wdog->wsr);
Xiaoliang Yang09e92132018-10-18 18:27:46 +080047#endif /* CONFIG_WATCHDOG_RESET_DISABLE*/
Troy Kisky4b7c6022012-10-22 15:19:01 +000048}
49
Marek Vasutf7fc5c12019-06-09 03:46:22 +020050static void imx_watchdog_init(struct watchdog_regs *wdog)
Troy Kisky4b7c6022012-10-22 15:19:01 +000051{
Troy Kisky4b7c6022012-10-22 15:19:01 +000052 u16 timeout;
53
54 /*
55 * The timer watchdog can be set between
56 * 0.5 and 128 Seconds. If not defined
57 * in configuration file, sets 128 Seconds
58 */
59#ifndef CONFIG_WATCHDOG_TIMEOUT_MSECS
60#define CONFIG_WATCHDOG_TIMEOUT_MSECS 128000
61#endif
62 timeout = (CONFIG_WATCHDOG_TIMEOUT_MSECS / 500) - 1;
Xiaoliang Yanga6657ad2018-10-18 18:27:45 +080063#ifdef CONFIG_FSL_LSCH2
64 writew((WCR_WDA | WCR_SRS | WCR_WDE) << 8 | timeout, &wdog->wcr);
65#else
Anatolij Gustschinca310002013-09-30 12:52:38 +020066 writew(WCR_WDZST | WCR_WDBG | WCR_WDE | WCR_WDT | WCR_SRS |
Ross Parkerfeaada12016-08-02 08:08:07 +000067 WCR_WDA | SET_WCR_WT(timeout), &wdog->wcr);
Xiaoliang Yanga6657ad2018-10-18 18:27:45 +080068#endif /* CONFIG_FSL_LSCH2*/
Marek Vasutf7fc5c12019-06-09 03:46:22 +020069 imx_watchdog_reset(wdog);
Troy Kisky4b7c6022012-10-22 15:19:01 +000070}
Troy Kisky4b7c6022012-10-22 15:19:01 +000071
Marek Vasutf7fc5c12019-06-09 03:46:22 +020072#if !CONFIG_IS_ENABLED(WDT)
73void hw_watchdog_reset(void)
Troy Kisky4b7c6022012-10-22 15:19:01 +000074{
75 struct watchdog_regs *wdog = (struct watchdog_regs *)WDOG1_BASE_ADDR;
76
Marek Vasutf7fc5c12019-06-09 03:46:22 +020077 imx_watchdog_reset(wdog);
78}
Peng Fan838cf7b2015-09-14 13:34:44 +080079
Marek Vasutf7fc5c12019-06-09 03:46:22 +020080void hw_watchdog_init(void)
81{
82 struct watchdog_regs *wdog = (struct watchdog_regs *)WDOG1_BASE_ADDR;
83
84 imx_watchdog_init(wdog);
85}
86#else
87struct imx_wdt_priv {
88 void __iomem *base;
89};
90
91static int imx_wdt_reset(struct udevice *dev)
92{
93 struct imx_wdt_priv *priv = dev_get_priv(dev);
94
95 imx_watchdog_reset(priv->base);
96
97 return 0;
98}
99
100static int imx_wdt_expire_now(struct udevice *dev, ulong flags)
101{
102 struct imx_wdt_priv *priv = dev_get_priv(dev);
103
104 imx_watchdog_expire_now(priv->base);
105 hang();
106
107 return 0;
108}
109
110static int imx_wdt_start(struct udevice *dev, u64 timeout, ulong flags)
111{
112 struct imx_wdt_priv *priv = dev_get_priv(dev);
113
114 imx_watchdog_init(priv->base);
115
116 return 0;
117}
118
119static int imx_wdt_probe(struct udevice *dev)
120{
121 struct imx_wdt_priv *priv = dev_get_priv(dev);
122
123 priv->base = dev_read_addr_ptr(dev);
124 if (!priv->base)
125 return -ENOENT;
126
127 return 0;
Troy Kisky4b7c6022012-10-22 15:19:01 +0000128}
Marek Vasutf7fc5c12019-06-09 03:46:22 +0200129
130static const struct wdt_ops imx_wdt_ops = {
131 .start = imx_wdt_start,
132 .reset = imx_wdt_reset,
133 .expire_now = imx_wdt_expire_now,
134};
135
136static const struct udevice_id imx_wdt_ids[] = {
137 { .compatible = "fsl,imx21-wdt" },
138 {}
139};
140
141U_BOOT_DRIVER(imx_wdt) = {
142 .name = "imx_wdt",
143 .id = UCLASS_WDT,
144 .of_match = imx_wdt_ids,
145 .probe = imx_wdt_probe,
146 .ops = &imx_wdt_ops,
147 .priv_auto_alloc_size = sizeof(struct imx_wdt_priv),
148 .flags = DM_FLAG_PRE_RELOC,
149};
150#endif
151#endif