blob: b0a3b4ed58636a945f7355d2ce0d33b791a7086c [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Jean-Christophe PLAGNIOL-VILLARD843a2652009-03-27 23:26:42 +01002/*
3 * [origin: Linux kernel drivers/watchdog/at91sam9_wdt.c]
4 *
Prasanthi Chellakumar1473f6a2018-10-09 11:46:40 -07005 * Watchdog driver for AT91SAM9x processors.
Jean-Christophe PLAGNIOL-VILLARD843a2652009-03-27 23:26:42 +01006 *
7 * Copyright (C) 2008 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
8 * Copyright (C) 2008 Renaud CERRATO r.cerrato@til-technologies.fr
Jean-Christophe PLAGNIOL-VILLARD843a2652009-03-27 23:26:42 +01009 */
10
11/*
12 * The Watchdog Timer Mode Register can be only written to once. If the
13 * timeout need to be set from U-Boot, be sure that the bootstrap doesn't
14 * write to this register. Inform Linux to it too
15 */
16
Reinhard Meyer7f6ed7f2011-02-04 20:17:33 +010017#include <asm/io.h>
Jean-Christophe PLAGNIOL-VILLARD843a2652009-03-27 23:26:42 +010018#include <asm/arch/at91_wdt.h>
Prasanthi Chellakumar1473f6a2018-10-09 11:46:40 -070019#include <common.h>
Stefan Roese6c04bd32019-04-02 10:57:19 +020020#include <div64.h>
Prasanthi Chellakumar1473f6a2018-10-09 11:46:40 -070021#include <dm.h>
22#include <errno.h>
23#include <wdt.h>
24
25DECLARE_GLOBAL_DATA_PTR;
Jean-Christophe PLAGNIOL-VILLARD843a2652009-03-27 23:26:42 +010026
27/*
28 * AT91SAM9 watchdog runs a 12bit counter @ 256Hz,
29 * use this to convert a watchdog
Prasanthi Chellakumar1473f6a2018-10-09 11:46:40 -070030 * value from seconds.
Jean-Christophe PLAGNIOL-VILLARD843a2652009-03-27 23:26:42 +010031 */
Prasanthi Chellakumar1473f6a2018-10-09 11:46:40 -070032#define WDT_SEC2TICKS(s) (((s) << 8) - 1)
Jean-Christophe PLAGNIOL-VILLARD843a2652009-03-27 23:26:42 +010033
34/* Hardware timeout in seconds */
Stefan Roese6c04bd32019-04-02 10:57:19 +020035#define WDT_MAX_TIMEOUT 16
36#define WDT_DEFAULT_TIMEOUT 2
Prasanthi Chellakumar1473f6a2018-10-09 11:46:40 -070037
38struct at91_wdt_priv {
39 void __iomem *regs;
Stefan Roese6c04bd32019-04-02 10:57:19 +020040 u32 regval;
41 u32 timeout;
Prasanthi Chellakumar1473f6a2018-10-09 11:46:40 -070042};
Jean-Christophe PLAGNIOL-VILLARD843a2652009-03-27 23:26:42 +010043
44/*
45 * Set the watchdog time interval in 1/256Hz (write-once)
46 * Counter is 12 bit.
47 */
Stefan Roese6c04bd32019-04-02 10:57:19 +020048static int at91_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
Jean-Christophe PLAGNIOL-VILLARD843a2652009-03-27 23:26:42 +010049{
Prasanthi Chellakumar1473f6a2018-10-09 11:46:40 -070050 struct at91_wdt_priv *priv = dev_get_priv(dev);
Stefan Roese6c04bd32019-04-02 10:57:19 +020051 u64 timeout;
52 u32 ticks;
Prasanthi Chellakumar1473f6a2018-10-09 11:46:40 -070053
Stefan Roese6c04bd32019-04-02 10:57:19 +020054 /* Calculate timeout in seconds and the resulting ticks */
55 timeout = timeout_ms;
56 do_div(timeout, 1000);
57 timeout = min_t(u64, timeout, WDT_MAX_TIMEOUT);
58 ticks = WDT_SEC2TICKS(timeout);
Jean-Christophe PLAGNIOL-VILLARD843a2652009-03-27 23:26:42 +010059
60 /* Check if disabled */
Prasanthi Chellakumar1473f6a2018-10-09 11:46:40 -070061 if (readl(priv->regs + AT91_WDT_MR) & AT91_WDT_MR_WDDIS) {
Jean-Christophe PLAGNIOL-VILLARD843a2652009-03-27 23:26:42 +010062 printf("sorry, watchdog is disabled\n");
63 return -1;
64 }
65
66 /*
67 * All counting occurs at SLOW_CLOCK / 128 = 256 Hz
68 *
69 * Since WDV is a 12-bit counter, the maximum period is
70 * 4096 / 256 = 16 seconds.
71 */
Prasanthi Chellakumar1473f6a2018-10-09 11:46:40 -070072 priv->regval = AT91_WDT_MR_WDRSTEN /* causes watchdog reset */
Achim Ehrlichf936aa02010-03-17 14:50:29 +010073 | AT91_WDT_MR_WDDBGHLT /* disabled in debug mode */
74 | AT91_WDT_MR_WDD(0xfff) /* restart at any time */
Stefan Roese6c04bd32019-04-02 10:57:19 +020075 | AT91_WDT_MR_WDV(ticks); /* timer value */
Prasanthi Chellakumar1473f6a2018-10-09 11:46:40 -070076 writel(priv->regval, priv->regs + AT91_WDT_MR);
Jean-Christophe PLAGNIOL-VILLARD843a2652009-03-27 23:26:42 +010077
78 return 0;
79}
80
Prasanthi Chellakumar1473f6a2018-10-09 11:46:40 -070081static int at91_wdt_stop(struct udevice *dev)
Jean-Christophe PLAGNIOL-VILLARD843a2652009-03-27 23:26:42 +010082{
Prasanthi Chellakumar1473f6a2018-10-09 11:46:40 -070083 struct at91_wdt_priv *priv = dev_get_priv(dev);
84
85 /* Disable Watchdog Timer */
86 priv->regval |= AT91_WDT_MR_WDDIS;
87 writel(priv->regval, priv->regs + AT91_WDT_MR);
88
89 return 0;
Jean-Christophe PLAGNIOL-VILLARD843a2652009-03-27 23:26:42 +010090}
91
Prasanthi Chellakumar1473f6a2018-10-09 11:46:40 -070092static int at91_wdt_reset(struct udevice *dev)
Jean-Christophe PLAGNIOL-VILLARD843a2652009-03-27 23:26:42 +010093{
Prasanthi Chellakumar1473f6a2018-10-09 11:46:40 -070094 struct at91_wdt_priv *priv = dev_get_priv(dev);
95
96 writel(AT91_WDT_CR_WDRSTT | AT91_WDT_CR_KEY, priv->regs + AT91_WDT_CR);
97
98 return 0;
Jean-Christophe PLAGNIOL-VILLARD843a2652009-03-27 23:26:42 +010099}
Prasanthi Chellakumar1473f6a2018-10-09 11:46:40 -0700100
101static const struct wdt_ops at91_wdt_ops = {
102 .start = at91_wdt_start,
103 .stop = at91_wdt_stop,
104 .reset = at91_wdt_reset,
105};
106
107static const struct udevice_id at91_wdt_ids[] = {
108 { .compatible = "atmel,at91sam9260-wdt" },
109 {}
110};
111
112static int at91_wdt_probe(struct udevice *dev)
113{
114 struct at91_wdt_priv *priv = dev_get_priv(dev);
115
116 priv->regs = dev_remap_addr(dev);
117 if (!priv->regs)
118 return -EINVAL;
119
120#ifdef CONFIG_AT91_HW_WDT_TIMEOUT
121 priv->timeout = dev_read_u32_default(dev, "timeout-sec",
122 WDT_DEFAULT_TIMEOUT);
123 debug("%s: timeout %d", __func__, priv->timeout);
124#endif
125
126 debug("%s: Probing wdt%u\n", __func__, dev->seq);
127
128 return 0;
129}
130
131U_BOOT_DRIVER(at91_wdt) = {
132 .name = "at91_wdt",
133 .id = UCLASS_WDT,
134 .of_match = at91_wdt_ids,
135 .priv_auto_alloc_size = sizeof(struct at91_wdt_priv),
136 .ops = &at91_wdt_ops,
137 .probe = at91_wdt_probe,
138};