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 
orion_wdt_reset(struct udevice * dev)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 
orion_wdt_start(struct udevice * dev,u64 timeout_ms,ulong flags)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 
orion_wdt_stop(struct udevice * dev)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 
save_reg_from_ofdata(struct udevice * dev,int index,void __iomem ** reg,int * offset)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 
orion_wdt_of_to_plat(struct udevice * dev)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 
orion_wdt_probe(struct udevice * dev)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 };
194