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
ast_wdt_start(struct udevice * dev,u64 timeout,ulong flags)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
ast_wdt_stop(struct udevice * dev)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_mask2);
121 } else
122 writel(WDT_RESET_DEFAULT, &priv->regs->reset_mask1);
123
124 return 0;
125 }
126
ast_wdt_reset(struct udevice * dev)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
ast_wdt_expire_now(struct udevice * dev,ulong flags)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
ast_wdt_ofdata_to_platdata(struct udevice * dev)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
ast_wdt_probe(struct udevice * dev)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