Merge tag 'ti-v2020.07-rc3' of https://gitlab.denx.de/u-boot/custodians/u-boot-ti
[oweals/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 <linux/bitops.h>
21 #include <linux/kernel.h>
22 #include <asm/io.h>
23 #include <asm/arch/cpu.h>
24 #include <asm/arch/soc.h>
25
26 DECLARE_GLOBAL_DATA_PTR;
27
28 struct orion_wdt_priv {
29         void __iomem *reg;
30         int wdt_counter_offset;
31         void __iomem *rstout;
32         void __iomem *rstout_mask;
33         u32 timeout;
34         unsigned long clk_rate;
35         struct clk clk;
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
48 static int orion_wdt_reset(struct udevice *dev)
49 {
50         struct orion_wdt_priv *priv = dev_get_priv(dev);
51
52         /* Reload watchdog duration */
53         writel(priv->clk_rate * priv->timeout,
54                priv->reg + priv->wdt_counter_offset);
55
56         return 0;
57 }
58
59 static int orion_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
60 {
61         struct orion_wdt_priv *priv = dev_get_priv(dev);
62         u32 reg;
63
64         priv->timeout = DIV_ROUND_UP(timeout_ms, 1000);
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 */
72         writel(priv->clk_rate * priv->timeout,
73                priv->reg + priv->wdt_counter_offset);
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
97 static 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
119 static 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
125         addr = devfdt_get_addr_size_index(dev, index, &off);
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
136 static int orion_wdt_ofdata_to_platdata(struct udevice *dev)
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;
151 err:
152         debug("%s: Could not determine Orion wdt IO addresses\n", __func__);
153         return -ENXIO;
154 }
155
156 static int orion_wdt_probe(struct udevice *dev)
157 {
158         struct orion_wdt_priv *priv = dev_get_priv(dev);
159         int ret;
160
161         debug("%s: Probing wdt%u\n", __func__, dev->seq);
162         orion_wdt_stop(dev);
163
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
170         return 0;
171 }
172
173 static const struct wdt_ops orion_wdt_ops = {
174         .start = orion_wdt_start,
175         .reset = orion_wdt_reset,
176         .stop = orion_wdt_stop,
177 };
178
179 static const struct udevice_id orion_wdt_ids[] = {
180         { .compatible = "marvell,armada-380-wdt" },
181         {}
182 };
183
184 U_BOOT_DRIVER(orion_wdt) = {
185         .name = "orion_wdt",
186         .id = UCLASS_WDT,
187         .of_match = orion_wdt_ids,
188         .probe = orion_wdt_probe,
189         .priv_auto_alloc_size = sizeof(struct orion_wdt_priv),
190         .ofdata_to_platdata = orion_wdt_ofdata_to_platdata,
191         .ops = &orion_wdt_ops,
192 };