xref: /openbmc/u-boot/drivers/watchdog/ast_wdt.c (revision 817503916ad087ac1663a5fab686cd10aa61c6fd)
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