xref: /rk3399_rockchip-uboot/drivers/watchdog/orion_wdt.c (revision e14b1169c0c5a1b362b41451006b492bd16f2fff)
1*2ab7704aSMarek Behún /*
2*2ab7704aSMarek Behún  * drivers/watchdog/orion_wdt.c
3*2ab7704aSMarek Behún  *
4*2ab7704aSMarek Behún  * Watchdog driver for Orion/Kirkwood processors
5*2ab7704aSMarek Behún  *
6*2ab7704aSMarek Behún  * Authors:	Tomas Hlavacek <tmshlvck@gmail.com>
7*2ab7704aSMarek Behún  * 		Sylver Bruneau <sylver.bruneau@googlemail.com>
8*2ab7704aSMarek Behún  * 		Marek Behun <marek.behun@nic.cz>
9*2ab7704aSMarek Behún  *
10*2ab7704aSMarek Behún  * This file is licensed under  the terms of the GNU General Public
11*2ab7704aSMarek Behún  * License version 2. This program is licensed "as is" without any
12*2ab7704aSMarek Behún  * warranty of any kind, whether express or implied.
13*2ab7704aSMarek Behún  */
14*2ab7704aSMarek Behún 
15*2ab7704aSMarek Behún #include <common.h>
16*2ab7704aSMarek Behún #include <dm.h>
17*2ab7704aSMarek Behún #include <wdt.h>
18*2ab7704aSMarek Behún #include <asm/io.h>
19*2ab7704aSMarek Behún #include <asm/arch/cpu.h>
20*2ab7704aSMarek Behún #include <asm/arch/soc.h>
21*2ab7704aSMarek Behún 
22*2ab7704aSMarek Behún DECLARE_GLOBAL_DATA_PTR;
23*2ab7704aSMarek Behún 
24*2ab7704aSMarek Behún struct orion_wdt_priv {
25*2ab7704aSMarek Behún 	void __iomem *reg;
26*2ab7704aSMarek Behún 	int wdt_counter_offset;
27*2ab7704aSMarek Behún 	void __iomem *rstout;
28*2ab7704aSMarek Behún 	void __iomem *rstout_mask;
29*2ab7704aSMarek Behún 	u32 timeout;
30*2ab7704aSMarek Behún };
31*2ab7704aSMarek Behún 
32*2ab7704aSMarek Behún #define RSTOUT_ENABLE_BIT		BIT(8)
33*2ab7704aSMarek Behún #define RSTOUT_MASK_BIT			BIT(10)
34*2ab7704aSMarek Behún #define WDT_ENABLE_BIT			BIT(8)
35*2ab7704aSMarek Behún 
36*2ab7704aSMarek Behún #define TIMER_CTRL			0x0000
37*2ab7704aSMarek Behún #define TIMER_A370_STATUS		0x04
38*2ab7704aSMarek Behún 
39*2ab7704aSMarek Behún #define WDT_AXP_FIXED_ENABLE_BIT	BIT(10)
40*2ab7704aSMarek Behún #define WDT_A370_EXPIRED		BIT(31)
41*2ab7704aSMarek Behún 
orion_wdt_reset(struct udevice * dev)42*2ab7704aSMarek Behún static int orion_wdt_reset(struct udevice *dev)
43*2ab7704aSMarek Behún {
44*2ab7704aSMarek Behún 	struct orion_wdt_priv *priv = dev_get_priv(dev);
45*2ab7704aSMarek Behún 
46*2ab7704aSMarek Behún 	/* Reload watchdog duration */
47*2ab7704aSMarek Behún 	writel(priv->timeout, priv->reg + priv->wdt_counter_offset);
48*2ab7704aSMarek Behún 
49*2ab7704aSMarek Behún 	return 0;
50*2ab7704aSMarek Behún }
51*2ab7704aSMarek Behún 
orion_wdt_start(struct udevice * dev,u64 timeout,ulong flags)52*2ab7704aSMarek Behún static int orion_wdt_start(struct udevice *dev, u64 timeout, ulong flags)
53*2ab7704aSMarek Behún {
54*2ab7704aSMarek Behún 	struct orion_wdt_priv *priv = dev_get_priv(dev);
55*2ab7704aSMarek Behún 	u32 reg;
56*2ab7704aSMarek Behún 
57*2ab7704aSMarek Behún 	priv->timeout = (u32) timeout;
58*2ab7704aSMarek Behún 
59*2ab7704aSMarek Behún 	/* Enable the fixed watchdog clock input */
60*2ab7704aSMarek Behún 	reg = readl(priv->reg + TIMER_CTRL);
61*2ab7704aSMarek Behún 	reg |= WDT_AXP_FIXED_ENABLE_BIT;
62*2ab7704aSMarek Behún 	writel(reg, priv->reg + TIMER_CTRL);
63*2ab7704aSMarek Behún 
64*2ab7704aSMarek Behún 	/* Set watchdog duration */
65*2ab7704aSMarek Behún 	writel(priv->timeout, priv->reg + priv->wdt_counter_offset);
66*2ab7704aSMarek Behún 
67*2ab7704aSMarek Behún 	/* Clear the watchdog expiration bit */
68*2ab7704aSMarek Behún 	reg = readl(priv->reg + TIMER_A370_STATUS);
69*2ab7704aSMarek Behún 	reg &= ~WDT_A370_EXPIRED;
70*2ab7704aSMarek Behún 	writel(reg, priv->reg + TIMER_A370_STATUS);
71*2ab7704aSMarek Behún 
72*2ab7704aSMarek Behún 	/* Enable watchdog timer */
73*2ab7704aSMarek Behún 	reg = readl(priv->reg + TIMER_CTRL);
74*2ab7704aSMarek Behún 	reg |= WDT_ENABLE_BIT;
75*2ab7704aSMarek Behún 	writel(reg, priv->reg + TIMER_CTRL);
76*2ab7704aSMarek Behún 
77*2ab7704aSMarek Behún 	/* Enable reset on watchdog */
78*2ab7704aSMarek Behún 	reg = readl(priv->rstout);
79*2ab7704aSMarek Behún 	reg |= RSTOUT_ENABLE_BIT;
80*2ab7704aSMarek Behún 	writel(reg, priv->rstout);
81*2ab7704aSMarek Behún 
82*2ab7704aSMarek Behún 	reg = readl(priv->rstout_mask);
83*2ab7704aSMarek Behún 	reg &= ~RSTOUT_MASK_BIT;
84*2ab7704aSMarek Behún 	writel(reg, priv->rstout_mask);
85*2ab7704aSMarek Behún 
86*2ab7704aSMarek Behún 	return 0;
87*2ab7704aSMarek Behún }
88*2ab7704aSMarek Behún 
orion_wdt_stop(struct udevice * dev)89*2ab7704aSMarek Behún static int orion_wdt_stop(struct udevice *dev)
90*2ab7704aSMarek Behún {
91*2ab7704aSMarek Behún 	struct orion_wdt_priv *priv = dev_get_priv(dev);
92*2ab7704aSMarek Behún 	u32 reg;
93*2ab7704aSMarek Behún 
94*2ab7704aSMarek Behún 	/* Disable reset on watchdog */
95*2ab7704aSMarek Behún 	reg = readl(priv->rstout_mask);
96*2ab7704aSMarek Behún 	reg |= RSTOUT_MASK_BIT;
97*2ab7704aSMarek Behún 	writel(reg, priv->rstout_mask);
98*2ab7704aSMarek Behún 
99*2ab7704aSMarek Behún 	reg = readl(priv->rstout);
100*2ab7704aSMarek Behún 	reg &= ~RSTOUT_ENABLE_BIT;
101*2ab7704aSMarek Behún 	writel(reg, priv->rstout);
102*2ab7704aSMarek Behún 
103*2ab7704aSMarek Behún 	/* Disable watchdog timer */
104*2ab7704aSMarek Behún 	reg = readl(priv->reg + TIMER_CTRL);
105*2ab7704aSMarek Behún 	reg &= ~WDT_ENABLE_BIT;
106*2ab7704aSMarek Behún 	writel(reg, priv->reg + TIMER_CTRL);
107*2ab7704aSMarek Behún 
108*2ab7704aSMarek Behún 	return 0;
109*2ab7704aSMarek Behún }
110*2ab7704aSMarek Behún 
save_reg_from_ofdata(struct udevice * dev,int index,void __iomem ** reg,int * offset)111*2ab7704aSMarek Behún static inline bool save_reg_from_ofdata(struct udevice *dev, int index,
112*2ab7704aSMarek Behún 					void __iomem **reg, int *offset)
113*2ab7704aSMarek Behún {
114*2ab7704aSMarek Behún 	fdt_addr_t addr;
115*2ab7704aSMarek Behún 	fdt_size_t off;
116*2ab7704aSMarek Behún 
117*2ab7704aSMarek Behún 	addr = fdtdec_get_addr_size_auto_noparent(
118*2ab7704aSMarek Behún 		gd->fdt_blob, dev_of_offset(dev), "reg", index, &off, true);
119*2ab7704aSMarek Behún 
120*2ab7704aSMarek Behún 	if (addr == FDT_ADDR_T_NONE)
121*2ab7704aSMarek Behún 		return false;
122*2ab7704aSMarek Behún 
123*2ab7704aSMarek Behún 	*reg = (void __iomem *) addr;
124*2ab7704aSMarek Behún 	if (offset)
125*2ab7704aSMarek Behún 		*offset = off;
126*2ab7704aSMarek Behún 
127*2ab7704aSMarek Behún 	return true;
128*2ab7704aSMarek Behún }
129*2ab7704aSMarek Behún 
orion_wdt_ofdata_to_platdata(struct udevice * dev)130*2ab7704aSMarek Behún static int orion_wdt_ofdata_to_platdata(struct udevice *dev)
131*2ab7704aSMarek Behún {
132*2ab7704aSMarek Behún 	struct orion_wdt_priv *priv = dev_get_priv(dev);
133*2ab7704aSMarek Behún 
134*2ab7704aSMarek Behún 	if (!save_reg_from_ofdata(dev, 0, &priv->reg,
135*2ab7704aSMarek Behún 				  &priv->wdt_counter_offset))
136*2ab7704aSMarek Behún 		goto err;
137*2ab7704aSMarek Behún 
138*2ab7704aSMarek Behún 	if (!save_reg_from_ofdata(dev, 1, &priv->rstout, NULL))
139*2ab7704aSMarek Behún 		goto err;
140*2ab7704aSMarek Behún 
141*2ab7704aSMarek Behún 	if (!save_reg_from_ofdata(dev, 2, &priv->rstout_mask, NULL))
142*2ab7704aSMarek Behún 		goto err;
143*2ab7704aSMarek Behún 
144*2ab7704aSMarek Behún 	return 0;
145*2ab7704aSMarek Behún err:
146*2ab7704aSMarek Behún 	debug("%s: Could not determine Orion wdt IO addresses\n", __func__);
147*2ab7704aSMarek Behún 	return -ENXIO;
148*2ab7704aSMarek Behún }
149*2ab7704aSMarek Behún 
orion_wdt_probe(struct udevice * dev)150*2ab7704aSMarek Behún static int orion_wdt_probe(struct udevice *dev)
151*2ab7704aSMarek Behún {
152*2ab7704aSMarek Behún 	debug("%s: Probing wdt%u\n", __func__, dev->seq);
153*2ab7704aSMarek Behún 	orion_wdt_stop(dev);
154*2ab7704aSMarek Behún 
155*2ab7704aSMarek Behún 	return 0;
156*2ab7704aSMarek Behún }
157*2ab7704aSMarek Behún 
158*2ab7704aSMarek Behún static const struct wdt_ops orion_wdt_ops = {
159*2ab7704aSMarek Behún 	.start = orion_wdt_start,
160*2ab7704aSMarek Behún 	.reset = orion_wdt_reset,
161*2ab7704aSMarek Behún 	.stop = orion_wdt_stop,
162*2ab7704aSMarek Behún };
163*2ab7704aSMarek Behún 
164*2ab7704aSMarek Behún static const struct udevice_id orion_wdt_ids[] = {
165*2ab7704aSMarek Behún 	{ .compatible = "marvell,armada-380-wdt" },
166*2ab7704aSMarek Behún 	{}
167*2ab7704aSMarek Behún };
168*2ab7704aSMarek Behún 
169*2ab7704aSMarek Behún U_BOOT_DRIVER(orion_wdt) = {
170*2ab7704aSMarek Behún 	.name = "orion_wdt",
171*2ab7704aSMarek Behún 	.id = UCLASS_WDT,
172*2ab7704aSMarek Behún 	.of_match = orion_wdt_ids,
173*2ab7704aSMarek Behún 	.probe = orion_wdt_probe,
174*2ab7704aSMarek Behún 	.priv_auto_alloc_size = sizeof(struct orion_wdt_priv),
175*2ab7704aSMarek Behún 	.ofdata_to_platdata = orion_wdt_ofdata_to_platdata,
176*2ab7704aSMarek Behún 	.ops = &orion_wdt_ops,
177*2ab7704aSMarek Behún };
178