2 * drivers/watchdog/orion_wdt.c
4 * Watchdog driver for Orion/Kirkwood processors
6 * Authors: Tomas Hlavacek <tmshlvck@gmail.com>
7 * Sylver Bruneau <sylver.bruneau@googlemail.com>
8 * Marek Behun <marek.behun@nic.cz>
10 * This file is licensed under the terms of the GNU General Public
11 * License version 2. This program is licensed "as is" without any
12 * warranty of any kind, whether express or implied.
19 #include <linux/kernel.h>
21 #include <asm/arch/cpu.h>
22 #include <asm/arch/soc.h>
24 DECLARE_GLOBAL_DATA_PTR;
26 struct orion_wdt_priv {
28 int wdt_counter_offset;
30 void __iomem *rstout_mask;
32 unsigned long clk_rate;
36 #define RSTOUT_ENABLE_BIT BIT(8)
37 #define RSTOUT_MASK_BIT BIT(10)
38 #define WDT_ENABLE_BIT BIT(8)
40 #define TIMER_CTRL 0x0000
41 #define TIMER_A370_STATUS 0x04
43 #define WDT_AXP_FIXED_ENABLE_BIT BIT(10)
44 #define WDT_A370_EXPIRED BIT(31)
46 static int orion_wdt_reset(struct udevice *dev)
48 struct orion_wdt_priv *priv = dev_get_priv(dev);
50 /* Reload watchdog duration */
51 writel(priv->clk_rate * priv->timeout,
52 priv->reg + priv->wdt_counter_offset);
57 static int orion_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
59 struct orion_wdt_priv *priv = dev_get_priv(dev);
62 priv->timeout = DIV_ROUND_UP(timeout_ms, 1000);
64 /* Enable the fixed watchdog clock input */
65 reg = readl(priv->reg + TIMER_CTRL);
66 reg |= WDT_AXP_FIXED_ENABLE_BIT;
67 writel(reg, priv->reg + TIMER_CTRL);
69 /* Set watchdog duration */
70 writel(priv->clk_rate * priv->timeout,
71 priv->reg + priv->wdt_counter_offset);
73 /* Clear the watchdog expiration bit */
74 reg = readl(priv->reg + TIMER_A370_STATUS);
75 reg &= ~WDT_A370_EXPIRED;
76 writel(reg, priv->reg + TIMER_A370_STATUS);
78 /* Enable watchdog timer */
79 reg = readl(priv->reg + TIMER_CTRL);
80 reg |= WDT_ENABLE_BIT;
81 writel(reg, priv->reg + TIMER_CTRL);
83 /* Enable reset on watchdog */
84 reg = readl(priv->rstout);
85 reg |= RSTOUT_ENABLE_BIT;
86 writel(reg, priv->rstout);
88 reg = readl(priv->rstout_mask);
89 reg &= ~RSTOUT_MASK_BIT;
90 writel(reg, priv->rstout_mask);
95 static int orion_wdt_stop(struct udevice *dev)
97 struct orion_wdt_priv *priv = dev_get_priv(dev);
100 /* Disable reset on watchdog */
101 reg = readl(priv->rstout_mask);
102 reg |= RSTOUT_MASK_BIT;
103 writel(reg, priv->rstout_mask);
105 reg = readl(priv->rstout);
106 reg &= ~RSTOUT_ENABLE_BIT;
107 writel(reg, priv->rstout);
109 /* Disable watchdog timer */
110 reg = readl(priv->reg + TIMER_CTRL);
111 reg &= ~WDT_ENABLE_BIT;
112 writel(reg, priv->reg + TIMER_CTRL);
117 static inline bool save_reg_from_ofdata(struct udevice *dev, int index,
118 void __iomem **reg, int *offset)
123 addr = devfdt_get_addr_size_index(dev, index, &off);
124 if (addr == FDT_ADDR_T_NONE)
127 *reg = (void __iomem *) addr;
134 static int orion_wdt_ofdata_to_platdata(struct udevice *dev)
136 struct orion_wdt_priv *priv = dev_get_priv(dev);
138 if (!save_reg_from_ofdata(dev, 0, &priv->reg,
139 &priv->wdt_counter_offset))
142 if (!save_reg_from_ofdata(dev, 1, &priv->rstout, NULL))
145 if (!save_reg_from_ofdata(dev, 2, &priv->rstout_mask, NULL))
150 debug("%s: Could not determine Orion wdt IO addresses\n", __func__);
154 static int orion_wdt_probe(struct udevice *dev)
156 struct orion_wdt_priv *priv = dev_get_priv(dev);
159 debug("%s: Probing wdt%u\n", __func__, dev->seq);
162 ret = clk_get_by_name(dev, "fixed", &priv->clk);
164 priv->clk_rate = clk_get_rate(&priv->clk);
166 priv->clk_rate = 25000000;
171 static const struct wdt_ops orion_wdt_ops = {
172 .start = orion_wdt_start,
173 .reset = orion_wdt_reset,
174 .stop = orion_wdt_stop,
177 static const struct udevice_id orion_wdt_ids[] = {
178 { .compatible = "marvell,armada-380-wdt" },
182 U_BOOT_DRIVER(orion_wdt) = {
185 .of_match = orion_wdt_ids,
186 .probe = orion_wdt_probe,
187 .priv_auto_alloc_size = sizeof(struct orion_wdt_priv),
188 .ofdata_to_platdata = orion_wdt_ofdata_to_platdata,
189 .ops = &orion_wdt_ops,