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