]> Git Repo - u-boot.git/blame - drivers/watchdog/orion_wdt.c
dm: Avoid accessing seq directly
[u-boot.git] / drivers / watchdog / orion_wdt.c
CommitLineData
2ab7704a
MB
1/*
2 * drivers/watchdog/orion_wdt.c
3 *
4 * Watchdog driver for Orion/Kirkwood processors
5 *
6 * Authors: Tomas Hlavacek <[email protected]>
7 * Sylver Bruneau <[email protected]>
8 * Marek Behun <[email protected]>
9 *
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.
13 */
14
15#include <common.h>
16#include <dm.h>
8e427ba3 17#include <clk.h>
f7ae49fc 18#include <log.h>
2ab7704a 19#include <wdt.h>
cd93d625 20#include <linux/bitops.h>
8e427ba3 21#include <linux/kernel.h>
2ab7704a
MB
22#include <asm/io.h>
23#include <asm/arch/cpu.h>
24#include <asm/arch/soc.h>
25
26DECLARE_GLOBAL_DATA_PTR;
27
28struct orion_wdt_priv {
29 void __iomem *reg;
30 int wdt_counter_offset;
31 void __iomem *rstout;
32 void __iomem *rstout_mask;
33 u32 timeout;
8e427ba3
CP
34 unsigned long clk_rate;
35 struct clk clk;
2ab7704a
MB
36};
37
38#define RSTOUT_ENABLE_BIT BIT(8)
39#define RSTOUT_MASK_BIT BIT(10)
40#define WDT_ENABLE_BIT BIT(8)
41
42#define TIMER_CTRL 0x0000
43#define TIMER_A370_STATUS 0x04
44
45#define WDT_AXP_FIXED_ENABLE_BIT BIT(10)
46#define WDT_A370_EXPIRED BIT(31)
47
48static int orion_wdt_reset(struct udevice *dev)
49{
50 struct orion_wdt_priv *priv = dev_get_priv(dev);
51
52 /* Reload watchdog duration */
8e427ba3
CP
53 writel(priv->clk_rate * priv->timeout,
54 priv->reg + priv->wdt_counter_offset);
2ab7704a
MB
55
56 return 0;
57}
58
8e427ba3 59static int orion_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
2ab7704a
MB
60{
61 struct orion_wdt_priv *priv = dev_get_priv(dev);
62 u32 reg;
63
8e427ba3 64 priv->timeout = DIV_ROUND_UP(timeout_ms, 1000);
2ab7704a
MB
65
66 /* Enable the fixed watchdog clock input */
67 reg = readl(priv->reg + TIMER_CTRL);
68 reg |= WDT_AXP_FIXED_ENABLE_BIT;
69 writel(reg, priv->reg + TIMER_CTRL);
70
71 /* Set watchdog duration */
8e427ba3
CP
72 writel(priv->clk_rate * priv->timeout,
73 priv->reg + priv->wdt_counter_offset);
2ab7704a
MB
74
75 /* Clear the watchdog expiration bit */
76 reg = readl(priv->reg + TIMER_A370_STATUS);
77 reg &= ~WDT_A370_EXPIRED;
78 writel(reg, priv->reg + TIMER_A370_STATUS);
79
80 /* Enable watchdog timer */
81 reg = readl(priv->reg + TIMER_CTRL);
82 reg |= WDT_ENABLE_BIT;
83 writel(reg, priv->reg + TIMER_CTRL);
84
85 /* Enable reset on watchdog */
86 reg = readl(priv->rstout);
87 reg |= RSTOUT_ENABLE_BIT;
88 writel(reg, priv->rstout);
89
90 reg = readl(priv->rstout_mask);
91 reg &= ~RSTOUT_MASK_BIT;
92 writel(reg, priv->rstout_mask);
93
94 return 0;
95}
96
97static int orion_wdt_stop(struct udevice *dev)
98{
99 struct orion_wdt_priv *priv = dev_get_priv(dev);
100 u32 reg;
101
102 /* Disable reset on watchdog */
103 reg = readl(priv->rstout_mask);
104 reg |= RSTOUT_MASK_BIT;
105 writel(reg, priv->rstout_mask);
106
107 reg = readl(priv->rstout);
108 reg &= ~RSTOUT_ENABLE_BIT;
109 writel(reg, priv->rstout);
110
111 /* Disable watchdog timer */
112 reg = readl(priv->reg + TIMER_CTRL);
113 reg &= ~WDT_ENABLE_BIT;
114 writel(reg, priv->reg + TIMER_CTRL);
115
116 return 0;
117}
118
119static inline bool save_reg_from_ofdata(struct udevice *dev, int index,
120 void __iomem **reg, int *offset)
121{
122 fdt_addr_t addr;
123 fdt_size_t off;
124
8562e414 125 addr = devfdt_get_addr_size_index(dev, index, &off);
2ab7704a
MB
126 if (addr == FDT_ADDR_T_NONE)
127 return false;
128
129 *reg = (void __iomem *) addr;
130 if (offset)
131 *offset = off;
132
133 return true;
134}
135
d1998a9f 136static int orion_wdt_of_to_plat(struct udevice *dev)
2ab7704a
MB
137{
138 struct orion_wdt_priv *priv = dev_get_priv(dev);
139
140 if (!save_reg_from_ofdata(dev, 0, &priv->reg,
141 &priv->wdt_counter_offset))
142 goto err;
143
144 if (!save_reg_from_ofdata(dev, 1, &priv->rstout, NULL))
145 goto err;
146
147 if (!save_reg_from_ofdata(dev, 2, &priv->rstout_mask, NULL))
148 goto err;
149
150 return 0;
151err:
152 debug("%s: Could not determine Orion wdt IO addresses\n", __func__);
153 return -ENXIO;
154}
155
156static int orion_wdt_probe(struct udevice *dev)
157{
8e427ba3
CP
158 struct orion_wdt_priv *priv = dev_get_priv(dev);
159 int ret;
160
8b85dfc6 161 debug("%s: Probing wdt%u\n", __func__, dev_seq(dev));
2ab7704a
MB
162 orion_wdt_stop(dev);
163
8e427ba3
CP
164 ret = clk_get_by_name(dev, "fixed", &priv->clk);
165 if (!ret)
166 priv->clk_rate = clk_get_rate(&priv->clk);
167 else
168 priv->clk_rate = 25000000;
169
2ab7704a
MB
170 return 0;
171}
172
173static const struct wdt_ops orion_wdt_ops = {
174 .start = orion_wdt_start,
175 .reset = orion_wdt_reset,
176 .stop = orion_wdt_stop,
177};
178
179static const struct udevice_id orion_wdt_ids[] = {
180 { .compatible = "marvell,armada-380-wdt" },
181 {}
182};
183
184U_BOOT_DRIVER(orion_wdt) = {
185 .name = "orion_wdt",
186 .id = UCLASS_WDT,
187 .of_match = orion_wdt_ids,
188 .probe = orion_wdt_probe,
41575d8e 189 .priv_auto = sizeof(struct orion_wdt_priv),
d1998a9f 190 .of_to_plat = orion_wdt_of_to_plat,
2ab7704a
MB
191 .ops = &orion_wdt_ops,
192};
This page took 0.164095 seconds and 4 git commands to generate.