blob: 05bbfe0005bfad8f4cac5307a5acaabcd9c8a2c9 [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
Robert Hancockd00a0b12019-08-06 11:05:29 -060050static void imx_watchdog_init(struct watchdog_regs *wdog, bool ext_reset)
Troy Kisky4b7c6022012-10-22 15:19:01 +000051{
Troy Kisky4b7c6022012-10-22 15:19:01 +000052 u16 timeout;
Robert Hancockd00a0b12019-08-06 11:05:29 -060053 u16 wcr;
Troy Kisky4b7c6022012-10-22 15:19:01 +000054
55 /*
56 * The timer watchdog can be set between
57 * 0.5 and 128 Seconds. If not defined
58 * in configuration file, sets 128 Seconds
59 */
60#ifndef CONFIG_WATCHDOG_TIMEOUT_MSECS
61#define CONFIG_WATCHDOG_TIMEOUT_MSECS 128000
62#endif
63 timeout = (CONFIG_WATCHDOG_TIMEOUT_MSECS / 500) - 1;
Xiaoliang Yanga6657ad2018-10-18 18:27:45 +080064#ifdef CONFIG_FSL_LSCH2
Robert Hancockd00a0b12019-08-06 11:05:29 -060065 wcr = (WCR_WDA | WCR_SRS | WCR_WDE) << 8 | timeout;
Xiaoliang Yanga6657ad2018-10-18 18:27:45 +080066#else
Robert Hancockd00a0b12019-08-06 11:05:29 -060067 wcr = WCR_WDZST | WCR_WDBG | WCR_WDE | WCR_SRS |
68 WCR_WDA | SET_WCR_WT(timeout);
69 if (ext_reset)
70 wcr |= WCR_WDT;
Xiaoliang Yanga6657ad2018-10-18 18:27:45 +080071#endif /* CONFIG_FSL_LSCH2*/
Robert Hancockd00a0b12019-08-06 11:05:29 -060072 writew(wcr, &wdog->wcr);
Marek Vasutf7fc5c12019-06-09 03:46:22 +020073 imx_watchdog_reset(wdog);
Troy Kisky4b7c6022012-10-22 15:19:01 +000074}
Troy Kisky4b7c6022012-10-22 15:19:01 +000075
Marek Vasutf7fc5c12019-06-09 03:46:22 +020076#if !CONFIG_IS_ENABLED(WDT)
77void hw_watchdog_reset(void)
Troy Kisky4b7c6022012-10-22 15:19:01 +000078{
79 struct watchdog_regs *wdog = (struct watchdog_regs *)WDOG1_BASE_ADDR;
80
Marek Vasutf7fc5c12019-06-09 03:46:22 +020081 imx_watchdog_reset(wdog);
82}
Peng Fan838cf7b2015-09-14 13:34:44 +080083
Marek Vasutf7fc5c12019-06-09 03:46:22 +020084void hw_watchdog_init(void)
85{
86 struct watchdog_regs *wdog = (struct watchdog_regs *)WDOG1_BASE_ADDR;
87
Robert Hancockd00a0b12019-08-06 11:05:29 -060088 imx_watchdog_init(wdog, true);
Marek Vasutf7fc5c12019-06-09 03:46:22 +020089}
90#else
91struct imx_wdt_priv {
92 void __iomem *base;
Robert Hancockd00a0b12019-08-06 11:05:29 -060093 bool ext_reset;
Marek Vasutf7fc5c12019-06-09 03:46:22 +020094};
95
96static int imx_wdt_reset(struct udevice *dev)
97{
98 struct imx_wdt_priv *priv = dev_get_priv(dev);
99
100 imx_watchdog_reset(priv->base);
101
102 return 0;
103}
104
105static int imx_wdt_expire_now(struct udevice *dev, ulong flags)
106{
107 struct imx_wdt_priv *priv = dev_get_priv(dev);
108
109 imx_watchdog_expire_now(priv->base);
110 hang();
111
112 return 0;
113}
114
115static int imx_wdt_start(struct udevice *dev, u64 timeout, ulong flags)
116{
117 struct imx_wdt_priv *priv = dev_get_priv(dev);
118
Robert Hancockd00a0b12019-08-06 11:05:29 -0600119 imx_watchdog_init(priv->base, priv->ext_reset);
Marek Vasutf7fc5c12019-06-09 03:46:22 +0200120
121 return 0;
122}
123
124static int imx_wdt_probe(struct udevice *dev)
125{
126 struct imx_wdt_priv *priv = dev_get_priv(dev);
127
128 priv->base = dev_read_addr_ptr(dev);
129 if (!priv->base)
130 return -ENOENT;
131
Robert Hancockd00a0b12019-08-06 11:05:29 -0600132 priv->ext_reset = dev_read_bool(dev, "fsl,ext-reset-output");
133
Marek Vasutf7fc5c12019-06-09 03:46:22 +0200134 return 0;
Troy Kisky4b7c6022012-10-22 15:19:01 +0000135}
Marek Vasutf7fc5c12019-06-09 03:46:22 +0200136
137static const struct wdt_ops imx_wdt_ops = {
138 .start = imx_wdt_start,
139 .reset = imx_wdt_reset,
140 .expire_now = imx_wdt_expire_now,
141};
142
143static const struct udevice_id imx_wdt_ids[] = {
144 { .compatible = "fsl,imx21-wdt" },
145 {}
146};
147
148U_BOOT_DRIVER(imx_wdt) = {
149 .name = "imx_wdt",
150 .id = UCLASS_WDT,
151 .of_match = imx_wdt_ids,
152 .probe = imx_wdt_probe,
153 .ops = &imx_wdt_ops,
154 .priv_auto_alloc_size = sizeof(struct imx_wdt_priv),
155 .flags = DM_FLAG_PRE_RELOC,
156};
157#endif
158#endif