blob: ea770217e5907c42536137dec4795fceed5665df [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
Simon Glassafb02152019-12-28 10:45:01 -07007#include <cpu_func.h>
Marek Vasutf7fc5c12019-06-09 03:46:22 +02008#include <dm.h>
Simon Glassf11478f2019-12-28 10:45:07 -07009#include <hang.h>
Troy Kisky4b7c6022012-10-22 15:19:01 +000010#include <asm/io.h>
Marek Vasutf7fc5c12019-06-09 03:46:22 +020011#include <wdt.h>
Troy Kisky4b7c6022012-10-22 15:19:01 +000012#include <watchdog.h>
13#include <asm/arch/imx-regs.h>
Xiaoliang Yanga6657ad2018-10-18 18:27:45 +080014#ifdef CONFIG_FSL_LSCH2
15#include <asm/arch/immap_lsch2.h>
16#endif
Fabio Estevamcd847ab2015-10-03 14:20:59 -030017#include <fsl_wdog.h>
Mo, Yuezhangc65adaa2020-07-01 09:15:28 +000018#include <div64.h>
19
20#define TIMEOUT_MAX 128000
21#define TIMEOUT_MIN 500
Troy Kisky4b7c6022012-10-22 15:19:01 +000022
Robert Hancockedc1d152019-08-06 11:05:30 -060023static void imx_watchdog_expire_now(struct watchdog_regs *wdog, bool ext_reset)
Troy Kisky4b7c6022012-10-22 15:19:01 +000024{
Robert Hancockedc1d152019-08-06 11:05:30 -060025 u16 wcr = WCR_WDE;
Marek Vasutf7fc5c12019-06-09 03:46:22 +020026
Robert Hancockedc1d152019-08-06 11:05:30 -060027 if (ext_reset)
28 wcr |= WCR_SRS; /* do not assert internal reset */
29 else
30 wcr |= WCR_WDA; /* do not assert external reset */
31
32 /* Write 3 times to ensure it works, due to IMX6Q errata ERR004346 */
33 writew(wcr, &wdog->wcr);
34 writew(wcr, &wdog->wcr);
35 writew(wcr, &wdog->wcr);
36
Marek Vasutf7fc5c12019-06-09 03:46:22 +020037 while (1) {
38 /*
Robert Hancockedc1d152019-08-06 11:05:30 -060039 * spin before reset
Marek Vasutf7fc5c12019-06-09 03:46:22 +020040 */
41 }
42}
43
44#if !defined(CONFIG_IMX_WATCHDOG) || \
45 (defined(CONFIG_IMX_WATCHDOG) && !CONFIG_IS_ENABLED(WDT))
Harald Seiler6f14d5f2020-12-15 16:47:52 +010046void __attribute__((weak)) reset_cpu(void)
Marek Vasutf7fc5c12019-06-09 03:46:22 +020047{
Troy Kisky4b7c6022012-10-22 15:19:01 +000048 struct watchdog_regs *wdog = (struct watchdog_regs *)WDOG1_BASE_ADDR;
49
Robert Hancockedc1d152019-08-06 11:05:30 -060050 imx_watchdog_expire_now(wdog, true);
Marek Vasutf7fc5c12019-06-09 03:46:22 +020051}
52#endif
53
54#if defined(CONFIG_IMX_WATCHDOG)
55static void imx_watchdog_reset(struct watchdog_regs *wdog)
56{
57#ifndef CONFIG_WATCHDOG_RESET_DISABLE
Troy Kisky4b7c6022012-10-22 15:19:01 +000058 writew(0x5555, &wdog->wsr);
59 writew(0xaaaa, &wdog->wsr);
Xiaoliang Yang09e92132018-10-18 18:27:46 +080060#endif /* CONFIG_WATCHDOG_RESET_DISABLE*/
Troy Kisky4b7c6022012-10-22 15:19:01 +000061}
62
Mo, Yuezhangc65adaa2020-07-01 09:15:28 +000063static void imx_watchdog_init(struct watchdog_regs *wdog, bool ext_reset,
64 u64 timeout)
Troy Kisky4b7c6022012-10-22 15:19:01 +000065{
Robert Hancockd00a0b12019-08-06 11:05:29 -060066 u16 wcr;
Troy Kisky4b7c6022012-10-22 15:19:01 +000067
68 /*
69 * The timer watchdog can be set between
Tom Rini0ab49a12023-01-10 11:19:44 -050070 * 0.5 and 128 Seconds.
Troy Kisky4b7c6022012-10-22 15:19:01 +000071 */
Mo, Yuezhangc65adaa2020-07-01 09:15:28 +000072 timeout = max_t(u64, timeout, TIMEOUT_MIN);
73 timeout = min_t(u64, timeout, TIMEOUT_MAX);
74 timeout = lldiv(timeout, 500) - 1;
75
Xiaoliang Yanga6657ad2018-10-18 18:27:45 +080076#ifdef CONFIG_FSL_LSCH2
Robert Hancockd00a0b12019-08-06 11:05:29 -060077 wcr = (WCR_WDA | WCR_SRS | WCR_WDE) << 8 | timeout;
Xiaoliang Yanga6657ad2018-10-18 18:27:45 +080078#else
Robert Hancockd00a0b12019-08-06 11:05:29 -060079 wcr = WCR_WDZST | WCR_WDBG | WCR_WDE | WCR_SRS |
80 WCR_WDA | SET_WCR_WT(timeout);
81 if (ext_reset)
82 wcr |= WCR_WDT;
Xiaoliang Yanga6657ad2018-10-18 18:27:45 +080083#endif /* CONFIG_FSL_LSCH2*/
Robert Hancockd00a0b12019-08-06 11:05:29 -060084 writew(wcr, &wdog->wcr);
Marek Vasutf7fc5c12019-06-09 03:46:22 +020085 imx_watchdog_reset(wdog);
Troy Kisky4b7c6022012-10-22 15:19:01 +000086}
Troy Kisky4b7c6022012-10-22 15:19:01 +000087
Marek Vasutf7fc5c12019-06-09 03:46:22 +020088#if !CONFIG_IS_ENABLED(WDT)
89void hw_watchdog_reset(void)
Troy Kisky4b7c6022012-10-22 15:19:01 +000090{
91 struct watchdog_regs *wdog = (struct watchdog_regs *)WDOG1_BASE_ADDR;
92
Marek Vasutf7fc5c12019-06-09 03:46:22 +020093 imx_watchdog_reset(wdog);
94}
Peng Fan838cf7b2015-09-14 13:34:44 +080095
Marek Vasutf7fc5c12019-06-09 03:46:22 +020096void hw_watchdog_init(void)
97{
98 struct watchdog_regs *wdog = (struct watchdog_regs *)WDOG1_BASE_ADDR;
99
Mo, Yuezhangc65adaa2020-07-01 09:15:28 +0000100 imx_watchdog_init(wdog, true, CONFIG_WATCHDOG_TIMEOUT_MSECS);
Marek Vasutf7fc5c12019-06-09 03:46:22 +0200101}
102#else
103struct imx_wdt_priv {
104 void __iomem *base;
Robert Hancockd00a0b12019-08-06 11:05:29 -0600105 bool ext_reset;
Marek Vasutf7fc5c12019-06-09 03:46:22 +0200106};
107
108static int imx_wdt_reset(struct udevice *dev)
109{
110 struct imx_wdt_priv *priv = dev_get_priv(dev);
111
112 imx_watchdog_reset(priv->base);
113
114 return 0;
115}
116
117static int imx_wdt_expire_now(struct udevice *dev, ulong flags)
118{
119 struct imx_wdt_priv *priv = dev_get_priv(dev);
120
Robert Hancockedc1d152019-08-06 11:05:30 -0600121 imx_watchdog_expire_now(priv->base, priv->ext_reset);
Marek Vasutf7fc5c12019-06-09 03:46:22 +0200122 hang();
123
124 return 0;
125}
126
127static int imx_wdt_start(struct udevice *dev, u64 timeout, ulong flags)
128{
129 struct imx_wdt_priv *priv = dev_get_priv(dev);
130
Mo, Yuezhangc65adaa2020-07-01 09:15:28 +0000131 imx_watchdog_init(priv->base, priv->ext_reset, timeout);
Marek Vasutf7fc5c12019-06-09 03:46:22 +0200132
133 return 0;
134}
135
136static int imx_wdt_probe(struct udevice *dev)
137{
138 struct imx_wdt_priv *priv = dev_get_priv(dev);
139
140 priv->base = dev_read_addr_ptr(dev);
141 if (!priv->base)
142 return -ENOENT;
143
Robert Hancockd00a0b12019-08-06 11:05:29 -0600144 priv->ext_reset = dev_read_bool(dev, "fsl,ext-reset-output");
145
Marek Vasutf7fc5c12019-06-09 03:46:22 +0200146 return 0;
Troy Kisky4b7c6022012-10-22 15:19:01 +0000147}
Marek Vasutf7fc5c12019-06-09 03:46:22 +0200148
149static const struct wdt_ops imx_wdt_ops = {
150 .start = imx_wdt_start,
151 .reset = imx_wdt_reset,
152 .expire_now = imx_wdt_expire_now,
153};
154
155static const struct udevice_id imx_wdt_ids[] = {
156 { .compatible = "fsl,imx21-wdt" },
157 {}
158};
159
160U_BOOT_DRIVER(imx_wdt) = {
161 .name = "imx_wdt",
162 .id = UCLASS_WDT,
163 .of_match = imx_wdt_ids,
164 .probe = imx_wdt_probe,
165 .ops = &imx_wdt_ops,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700166 .priv_auto = sizeof(struct imx_wdt_priv),
Marek Vasutf7fc5c12019-06-09 03:46:22 +0200167 .flags = DM_FLAG_PRE_RELOC,
168};
169#endif
170#endif