blob: 62bf25e9cc04ff7c09f04e2b49c4871b50ee6abc [file] [log] [blame]
Troy Kiskyabbab702012-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>
Simon Glass9a3b4ce2019-12-28 10:45:01 -07008#include <cpu_func.h>
Marek Vasut4b969de2019-06-09 03:46:22 +02009#include <dm.h>
Troy Kiskyabbab702012-10-22 15:19:01 +000010#include <asm/io.h>
Marek Vasut4b969de2019-06-09 03:46:22 +020011#include <wdt.h>
Troy Kiskyabbab702012-10-22 15:19:01 +000012#include <watchdog.h>
13#include <asm/arch/imx-regs.h>
Xiaoliang Yang005c1cf2018-10-18 18:27:45 +080014#ifdef CONFIG_FSL_LSCH2
15#include <asm/arch/immap_lsch2.h>
16#endif
Fabio Estevamf5327272015-10-03 14:20:59 -030017#include <fsl_wdog.h>
Troy Kiskyabbab702012-10-22 15:19:01 +000018
Robert Hancockf2929d12019-08-06 11:05:30 -060019static void imx_watchdog_expire_now(struct watchdog_regs *wdog, bool ext_reset)
Troy Kiskyabbab702012-10-22 15:19:01 +000020{
Robert Hancockf2929d12019-08-06 11:05:30 -060021 u16 wcr = WCR_WDE;
Marek Vasut4b969de2019-06-09 03:46:22 +020022
Robert Hancockf2929d12019-08-06 11:05:30 -060023 if (ext_reset)
24 wcr |= WCR_SRS; /* do not assert internal reset */
25 else
26 wcr |= WCR_WDA; /* do not assert external reset */
27
28 /* Write 3 times to ensure it works, due to IMX6Q errata ERR004346 */
29 writew(wcr, &wdog->wcr);
30 writew(wcr, &wdog->wcr);
31 writew(wcr, &wdog->wcr);
32
Marek Vasut4b969de2019-06-09 03:46:22 +020033 while (1) {
34 /*
Robert Hancockf2929d12019-08-06 11:05:30 -060035 * spin before reset
Marek Vasut4b969de2019-06-09 03:46:22 +020036 */
37 }
38}
39
40#if !defined(CONFIG_IMX_WATCHDOG) || \
41 (defined(CONFIG_IMX_WATCHDOG) && !CONFIG_IS_ENABLED(WDT))
42void __attribute__((weak)) reset_cpu(ulong addr)
43{
Troy Kiskyabbab702012-10-22 15:19:01 +000044 struct watchdog_regs *wdog = (struct watchdog_regs *)WDOG1_BASE_ADDR;
45
Robert Hancockf2929d12019-08-06 11:05:30 -060046 imx_watchdog_expire_now(wdog, true);
Marek Vasut4b969de2019-06-09 03:46:22 +020047}
48#endif
49
50#if defined(CONFIG_IMX_WATCHDOG)
51static void imx_watchdog_reset(struct watchdog_regs *wdog)
52{
53#ifndef CONFIG_WATCHDOG_RESET_DISABLE
Troy Kiskyabbab702012-10-22 15:19:01 +000054 writew(0x5555, &wdog->wsr);
55 writew(0xaaaa, &wdog->wsr);
Xiaoliang Yangda4918a2018-10-18 18:27:46 +080056#endif /* CONFIG_WATCHDOG_RESET_DISABLE*/
Troy Kiskyabbab702012-10-22 15:19:01 +000057}
58
Robert Hancockceea0c12019-08-06 11:05:29 -060059static void imx_watchdog_init(struct watchdog_regs *wdog, bool ext_reset)
Troy Kiskyabbab702012-10-22 15:19:01 +000060{
Troy Kiskyabbab702012-10-22 15:19:01 +000061 u16 timeout;
Robert Hancockceea0c12019-08-06 11:05:29 -060062 u16 wcr;
Troy Kiskyabbab702012-10-22 15:19:01 +000063
64 /*
65 * The timer watchdog can be set between
66 * 0.5 and 128 Seconds. If not defined
67 * in configuration file, sets 128 Seconds
68 */
69#ifndef CONFIG_WATCHDOG_TIMEOUT_MSECS
70#define CONFIG_WATCHDOG_TIMEOUT_MSECS 128000
71#endif
72 timeout = (CONFIG_WATCHDOG_TIMEOUT_MSECS / 500) - 1;
Xiaoliang Yang005c1cf2018-10-18 18:27:45 +080073#ifdef CONFIG_FSL_LSCH2
Robert Hancockceea0c12019-08-06 11:05:29 -060074 wcr = (WCR_WDA | WCR_SRS | WCR_WDE) << 8 | timeout;
Xiaoliang Yang005c1cf2018-10-18 18:27:45 +080075#else
Robert Hancockceea0c12019-08-06 11:05:29 -060076 wcr = WCR_WDZST | WCR_WDBG | WCR_WDE | WCR_SRS |
77 WCR_WDA | SET_WCR_WT(timeout);
78 if (ext_reset)
79 wcr |= WCR_WDT;
Xiaoliang Yang005c1cf2018-10-18 18:27:45 +080080#endif /* CONFIG_FSL_LSCH2*/
Robert Hancockceea0c12019-08-06 11:05:29 -060081 writew(wcr, &wdog->wcr);
Marek Vasut4b969de2019-06-09 03:46:22 +020082 imx_watchdog_reset(wdog);
Troy Kiskyabbab702012-10-22 15:19:01 +000083}
Troy Kiskyabbab702012-10-22 15:19:01 +000084
Marek Vasut4b969de2019-06-09 03:46:22 +020085#if !CONFIG_IS_ENABLED(WDT)
86void hw_watchdog_reset(void)
Troy Kiskyabbab702012-10-22 15:19:01 +000087{
88 struct watchdog_regs *wdog = (struct watchdog_regs *)WDOG1_BASE_ADDR;
89
Marek Vasut4b969de2019-06-09 03:46:22 +020090 imx_watchdog_reset(wdog);
Troy Kiskyabbab702012-10-22 15:19:01 +000091}
Marek Vasut4b969de2019-06-09 03:46:22 +020092
93void hw_watchdog_init(void)
94{
95 struct watchdog_regs *wdog = (struct watchdog_regs *)WDOG1_BASE_ADDR;
96
Robert Hancockceea0c12019-08-06 11:05:29 -060097 imx_watchdog_init(wdog, true);
Marek Vasut4b969de2019-06-09 03:46:22 +020098}
99#else
100struct imx_wdt_priv {
101 void __iomem *base;
Robert Hancockceea0c12019-08-06 11:05:29 -0600102 bool ext_reset;
Marek Vasut4b969de2019-06-09 03:46:22 +0200103};
104
105static int imx_wdt_reset(struct udevice *dev)
106{
107 struct imx_wdt_priv *priv = dev_get_priv(dev);
108
109 imx_watchdog_reset(priv->base);
110
111 return 0;
112}
113
114static int imx_wdt_expire_now(struct udevice *dev, ulong flags)
115{
116 struct imx_wdt_priv *priv = dev_get_priv(dev);
117
Robert Hancockf2929d12019-08-06 11:05:30 -0600118 imx_watchdog_expire_now(priv->base, priv->ext_reset);
Marek Vasut4b969de2019-06-09 03:46:22 +0200119 hang();
120
121 return 0;
122}
123
124static int imx_wdt_start(struct udevice *dev, u64 timeout, ulong flags)
125{
126 struct imx_wdt_priv *priv = dev_get_priv(dev);
127
Robert Hancockceea0c12019-08-06 11:05:29 -0600128 imx_watchdog_init(priv->base, priv->ext_reset);
Marek Vasut4b969de2019-06-09 03:46:22 +0200129
130 return 0;
131}
132
133static int imx_wdt_probe(struct udevice *dev)
134{
135 struct imx_wdt_priv *priv = dev_get_priv(dev);
136
137 priv->base = dev_read_addr_ptr(dev);
138 if (!priv->base)
139 return -ENOENT;
140
Robert Hancockceea0c12019-08-06 11:05:29 -0600141 priv->ext_reset = dev_read_bool(dev, "fsl,ext-reset-output");
142
Marek Vasut4b969de2019-06-09 03:46:22 +0200143 return 0;
144}
145
146static const struct wdt_ops imx_wdt_ops = {
147 .start = imx_wdt_start,
148 .reset = imx_wdt_reset,
149 .expire_now = imx_wdt_expire_now,
150};
151
152static const struct udevice_id imx_wdt_ids[] = {
153 { .compatible = "fsl,imx21-wdt" },
154 {}
155};
156
157U_BOOT_DRIVER(imx_wdt) = {
158 .name = "imx_wdt",
159 .id = UCLASS_WDT,
160 .of_match = imx_wdt_ids,
161 .probe = imx_wdt_probe,
162 .ops = &imx_wdt_ops,
163 .priv_auto_alloc_size = sizeof(struct imx_wdt_priv),
164 .flags = DM_FLAG_PRE_RELOC,
165};
166#endif
167#endif