xref: /openbmc/u-boot/drivers/watchdog/ast_wdt.c (revision ea68d6ca)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright 2017 Google, Inc
4  */
5 
6 #include <common.h>
7 #include <dm.h>
8 #include <errno.h>
9 #include <wdt.h>
10 #include <asm/io.h>
11 
12 /*
13  * Special value that needs to be written to counter_restart register to
14  * (re)start the timer
15  */
16 #define WDT_COUNTER_RESTART_VAL		0x4755
17 
18 /* Control register */
19 #define WDT_CTRL_RESET_MODE_SHIFT	5
20 #define WDT_CTRL_RESET_MODE_MASK	3
21 
22 #define WDT_CTRL_EN			(1 << 0)
23 #define WDT_CTRL_RESET			(1 << 1)
24 #define WDT_CTRL_CLK1MHZ		(1 << 4)
25 #define WDT_CTRL_2ND_BOOT		(1 << 7)
26 
27 /* Values for Reset Mode */
28 #define WDT_CTRL_RESET_SOC		0
29 #define WDT_CTRL_RESET_CHIP		1
30 #define WDT_CTRL_RESET_CPU		2
31 #define WDT_CTRL_RESET_MASK		3
32 
33 /* Reset Mask register */
34 #define WDT_RESET_ARM			(1 << 0)
35 #define WDT_RESET_COPROC		(1 << 1)
36 #define WDT_RESET_SDRAM			(1 << 2)
37 #define WDT_RESET_AHB			(1 << 3)
38 #define WDT_RESET_I2C			(1 << 4)
39 #define WDT_RESET_MAC1			(1 << 5)
40 #define WDT_RESET_MAC2			(1 << 6)
41 #define WDT_RESET_GCRT			(1 << 7)
42 #define WDT_RESET_USB20			(1 << 8)
43 #define WDT_RESET_USB11_HOST		(1 << 9)
44 #define WDT_RESET_USB11_EHCI2		(1 << 10)
45 #define WDT_RESET_VIDEO			(1 << 11)
46 #define WDT_RESET_HAC			(1 << 12)
47 #define WDT_RESET_LPC			(1 << 13)
48 #define WDT_RESET_SDSDIO		(1 << 14)
49 #define WDT_RESET_MIC			(1 << 15)
50 #define WDT_RESET_CRT2C			(1 << 16)
51 #define WDT_RESET_PWM			(1 << 17)
52 #define WDT_RESET_PECI			(1 << 18)
53 #define WDT_RESET_JTAG			(1 << 19)
54 #define WDT_RESET_ADC			(1 << 20)
55 #define WDT_RESET_GPIO			(1 << 21)
56 #define WDT_RESET_MCTP			(1 << 22)
57 #define WDT_RESET_XDMA			(1 << 23)
58 #define WDT_RESET_SPI			(1 << 24)
59 #define WDT_RESET_MISC			(1 << 25)
60 
61 #define WDT_RESET_DEFAULT						\
62 	(WDT_RESET_ARM | WDT_RESET_COPROC | WDT_RESET_I2C |		\
63 	 WDT_RESET_MAC1 | WDT_RESET_MAC2 | WDT_RESET_GCRT |		\
64 	 WDT_RESET_USB20 | WDT_RESET_USB11_HOST | WDT_RESET_USB11_EHCI2 | \
65 	 WDT_RESET_VIDEO | WDT_RESET_HAC | WDT_RESET_LPC |		\
66 	 WDT_RESET_SDSDIO | WDT_RESET_MIC | WDT_RESET_CRT2C |		\
67 	 WDT_RESET_PWM | WDT_RESET_PECI | WDT_RESET_JTAG |		\
68 	 WDT_RESET_ADC | WDT_RESET_GPIO | WDT_RESET_MISC)
69 
70 enum aspeed_wdt_model {
71 	WDT_AST2400,
72 	WDT_AST2500,
73 	WDT_AST2600,
74 };
75 
76 struct ast_wdt {
77 	u32 counter_status;
78 	u32 counter_reload_val;
79 	u32 counter_restart;
80 	u32 ctrl;
81 	u32 timeout_status;
82 	u32 clr_timeout_status;
83 	u32 reset_width;
84 	/* On pre-ast2500 SoCs this register is reserved. */
85 	u32 reset_mask1;
86 	u32 reset_mask2;	//ast2600 support
87 	u32 sw_ctrl;	//ast2600 support
88 	u32 sw_reset_mask1;	//ast2600 support
89 	u32 sw_reset_mask2;	//ast2600 support
90 	u32 sw_fun_disable;	//ast2600 support
91 
92 };
93 
94 struct ast_wdt_priv {
95 	struct ast_wdt *regs;
96 };
97 
98 static int ast_wdt_start(struct udevice *dev, u64 timeout, ulong flags)
99 {
100 	struct ast_wdt_priv *priv = dev_get_priv(dev);
101 
102 	writel((u32) timeout, &priv->regs->counter_reload_val);
103 
104 	writel(WDT_COUNTER_RESTART_VAL, &priv->regs->counter_restart);
105 
106 	writel(WDT_CTRL_EN | WDT_CTRL_RESET, &priv->regs->ctrl);
107 
108 	return 0;
109 }
110 
111 static int ast_wdt_stop(struct udevice *dev)
112 {
113 	struct ast_wdt_priv *priv = dev_get_priv(dev);
114 	ulong driver_data = dev_get_driver_data(dev);
115 
116 	clrbits_le32(&priv->regs->ctrl, WDT_CTRL_EN);
117 
118 	if(driver_data == WDT_AST2600) {
119 		writel(0x030f1ff1, &priv->regs->reset_mask1);
120 		writel(0x3fffff1, &priv->regs->reset_mask1);
121 	} else
122 		writel(WDT_RESET_DEFAULT, &priv->regs->reset_mask1);
123 
124 	return 0;
125 }
126 
127 static int ast_wdt_reset(struct udevice *dev)
128 {
129 	struct ast_wdt_priv *priv = dev_get_priv(dev);
130 
131 	writel(WDT_COUNTER_RESTART_VAL, &priv->regs->counter_restart);
132 
133 	return 0;
134 }
135 
136 static int ast_wdt_expire_now(struct udevice *dev, ulong flags)
137 {
138 	struct ast_wdt_priv *priv = dev_get_priv(dev);
139 	int ret;
140 
141 	ret = ast_wdt_start(dev, 1, flags);
142 	if (ret)
143 		return ret;
144 
145 	while (readl(&priv->regs->ctrl) & WDT_CTRL_EN);
146 
147 	return ast_wdt_stop(dev);
148 }
149 
150 static int ast_wdt_ofdata_to_platdata(struct udevice *dev)
151 {
152 	struct ast_wdt_priv *priv = dev_get_priv(dev);
153 
154 	priv->regs = devfdt_get_addr_ptr(dev);
155 	if (IS_ERR(priv->regs))
156 		return PTR_ERR(priv->regs);
157 
158 	return 0;
159 }
160 
161 static const struct wdt_ops ast_wdt_ops = {
162 	.start = ast_wdt_start,
163 	.reset = ast_wdt_reset,
164 	.stop = ast_wdt_stop,
165 	.expire_now = ast_wdt_expire_now,
166 };
167 
168 static int ast_wdt_probe(struct udevice *dev)
169 {
170 	debug("%s() wdt%u\n", __func__, dev->seq);
171 	ast_wdt_stop(dev);
172 
173 	return 0;
174 }
175 
176 static const struct udevice_id ast_wdt_ids[] = {
177 	{ .compatible = "aspeed,wdt", .data = WDT_AST2500 },
178 	{ .compatible = "aspeed,ast2600-wdt", .data = WDT_AST2600 },
179 	{ .compatible = "aspeed,ast2500-wdt", .data = WDT_AST2500 },
180 	{ .compatible = "aspeed,ast2400-wdt", .data = WDT_AST2400 },
181 	{}
182 };
183 
184 U_BOOT_DRIVER(ast_wdt) = {
185 	.name = "ast_wdt",
186 	.id = UCLASS_WDT,
187 	.of_match = ast_wdt_ids,
188 	.probe = ast_wdt_probe,
189 	.priv_auto_alloc_size = sizeof(struct ast_wdt_priv),
190 	.ofdata_to_platdata = ast_wdt_ofdata_to_platdata,
191 	.ops = &ast_wdt_ops,
192 };
193