xref: /openbmc/u-boot/drivers/watchdog/ast_wdt.c (revision a0765678)
183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
21eb0a464Smaxims@google.com /*
31eb0a464Smaxims@google.com  * Copyright 2017 Google, Inc
41eb0a464Smaxims@google.com  */
51eb0a464Smaxims@google.com 
61eb0a464Smaxims@google.com #include <common.h>
71eb0a464Smaxims@google.com #include <dm.h>
81eb0a464Smaxims@google.com #include <errno.h>
91eb0a464Smaxims@google.com #include <wdt.h>
101eb0a464Smaxims@google.com #include <asm/io.h>
111ac11e4aSryan_chen 
121ac11e4aSryan_chen /*
131ac11e4aSryan_chen  * Special value that needs to be written to counter_restart register to
141ac11e4aSryan_chen  * (re)start the timer
151ac11e4aSryan_chen  */
161ac11e4aSryan_chen #define WDT_COUNTER_RESTART_VAL		0x4755
171ac11e4aSryan_chen 
181ac11e4aSryan_chen /* Control register */
191ac11e4aSryan_chen #define WDT_CTRL_RESET_MODE_SHIFT	5
201ac11e4aSryan_chen #define WDT_CTRL_RESET_MODE_MASK	3
211ac11e4aSryan_chen 
221ac11e4aSryan_chen #define WDT_CTRL_EN			(1 << 0)
231ac11e4aSryan_chen #define WDT_CTRL_RESET			(1 << 1)
241ac11e4aSryan_chen #define WDT_CTRL_CLK1MHZ		(1 << 4)
251ac11e4aSryan_chen #define WDT_CTRL_2ND_BOOT		(1 << 7)
261ac11e4aSryan_chen 
271ac11e4aSryan_chen /* Values for Reset Mode */
281ac11e4aSryan_chen #define WDT_CTRL_RESET_SOC		0
291ac11e4aSryan_chen #define WDT_CTRL_RESET_CHIP		1
301ac11e4aSryan_chen #define WDT_CTRL_RESET_CPU		2
311ac11e4aSryan_chen #define WDT_CTRL_RESET_MASK		3
321ac11e4aSryan_chen 
331ac11e4aSryan_chen /* Reset Mask register */
341ac11e4aSryan_chen #define WDT_RESET_ARM			(1 << 0)
351ac11e4aSryan_chen #define WDT_RESET_COPROC		(1 << 1)
361ac11e4aSryan_chen #define WDT_RESET_SDRAM			(1 << 2)
371ac11e4aSryan_chen #define WDT_RESET_AHB			(1 << 3)
381ac11e4aSryan_chen #define WDT_RESET_I2C			(1 << 4)
391ac11e4aSryan_chen #define WDT_RESET_MAC1			(1 << 5)
401ac11e4aSryan_chen #define WDT_RESET_MAC2			(1 << 6)
411ac11e4aSryan_chen #define WDT_RESET_GCRT			(1 << 7)
421ac11e4aSryan_chen #define WDT_RESET_USB20			(1 << 8)
431ac11e4aSryan_chen #define WDT_RESET_USB11_HOST		(1 << 9)
441ac11e4aSryan_chen #define WDT_RESET_USB11_EHCI2		(1 << 10)
451ac11e4aSryan_chen #define WDT_RESET_VIDEO			(1 << 11)
461ac11e4aSryan_chen #define WDT_RESET_HAC			(1 << 12)
471ac11e4aSryan_chen #define WDT_RESET_LPC			(1 << 13)
481ac11e4aSryan_chen #define WDT_RESET_SDSDIO		(1 << 14)
491ac11e4aSryan_chen #define WDT_RESET_MIC			(1 << 15)
501ac11e4aSryan_chen #define WDT_RESET_CRT2C			(1 << 16)
511ac11e4aSryan_chen #define WDT_RESET_PWM			(1 << 17)
521ac11e4aSryan_chen #define WDT_RESET_PECI			(1 << 18)
531ac11e4aSryan_chen #define WDT_RESET_JTAG			(1 << 19)
541ac11e4aSryan_chen #define WDT_RESET_ADC			(1 << 20)
551ac11e4aSryan_chen #define WDT_RESET_GPIO			(1 << 21)
561ac11e4aSryan_chen #define WDT_RESET_MCTP			(1 << 22)
571ac11e4aSryan_chen #define WDT_RESET_XDMA			(1 << 23)
581ac11e4aSryan_chen #define WDT_RESET_SPI			(1 << 24)
591ac11e4aSryan_chen #define WDT_RESET_MISC			(1 << 25)
601ac11e4aSryan_chen 
611ac11e4aSryan_chen #define WDT_RESET_DEFAULT						\
621ac11e4aSryan_chen 	(WDT_RESET_ARM | WDT_RESET_COPROC | WDT_RESET_I2C |		\
631ac11e4aSryan_chen 	 WDT_RESET_MAC1 | WDT_RESET_MAC2 | WDT_RESET_GCRT |		\
641ac11e4aSryan_chen 	 WDT_RESET_USB20 | WDT_RESET_USB11_HOST | WDT_RESET_USB11_EHCI2 | \
651ac11e4aSryan_chen 	 WDT_RESET_VIDEO | WDT_RESET_HAC | WDT_RESET_LPC |		\
661ac11e4aSryan_chen 	 WDT_RESET_SDSDIO | WDT_RESET_MIC | WDT_RESET_CRT2C |		\
671ac11e4aSryan_chen 	 WDT_RESET_PWM | WDT_RESET_PECI | WDT_RESET_JTAG |		\
681ac11e4aSryan_chen 	 WDT_RESET_ADC | WDT_RESET_GPIO | WDT_RESET_MISC)
691eb0a464Smaxims@google.com 
70612dc3e3Sryan_chen enum aspeed_wdt_model {
71612dc3e3Sryan_chen 	WDT_AST2400,
72612dc3e3Sryan_chen 	WDT_AST2500,
73612dc3e3Sryan_chen 	WDT_AST2600,
74612dc3e3Sryan_chen };
751eb0a464Smaxims@google.com 
761ac11e4aSryan_chen struct ast_wdt {
771ac11e4aSryan_chen 	u32 counter_status;
781ac11e4aSryan_chen 	u32 counter_reload_val;
791ac11e4aSryan_chen 	u32 counter_restart;
801ac11e4aSryan_chen 	u32 ctrl;
811ac11e4aSryan_chen 	u32 timeout_status;
821ac11e4aSryan_chen 	u32 clr_timeout_status;
831ac11e4aSryan_chen 	u32 reset_width;
841ac11e4aSryan_chen 	/* On pre-ast2500 SoCs this register is reserved. */
851ac11e4aSryan_chen 	u32 reset_mask1;
861ac11e4aSryan_chen 	u32 reset_mask2;	//ast2600 support
871ac11e4aSryan_chen 	u32 sw_ctrl;	//ast2600 support
881ac11e4aSryan_chen 	u32 sw_reset_mask1;	//ast2600 support
891ac11e4aSryan_chen 	u32 sw_reset_mask2;	//ast2600 support
901ac11e4aSryan_chen 	u32 sw_fun_disable;	//ast2600 support
911ac11e4aSryan_chen 
921ac11e4aSryan_chen };
931ac11e4aSryan_chen 
941eb0a464Smaxims@google.com struct ast_wdt_priv {
951eb0a464Smaxims@google.com 	struct ast_wdt *regs;
961eb0a464Smaxims@google.com };
971eb0a464Smaxims@google.com 
ast_wdt_start(struct udevice * dev,u64 timeout,ulong flags)981eb0a464Smaxims@google.com static int ast_wdt_start(struct udevice *dev, u64 timeout, ulong flags)
991eb0a464Smaxims@google.com {
1001eb0a464Smaxims@google.com 	struct ast_wdt_priv *priv = dev_get_priv(dev);
1011eb0a464Smaxims@google.com 
1021eb0a464Smaxims@google.com 	writel((u32) timeout, &priv->regs->counter_reload_val);
1031ac11e4aSryan_chen 
1041eb0a464Smaxims@google.com 	writel(WDT_COUNTER_RESTART_VAL, &priv->regs->counter_restart);
1051ac11e4aSryan_chen 
1061ac11e4aSryan_chen 	writel(WDT_CTRL_EN | WDT_CTRL_RESET, &priv->regs->ctrl);
1071eb0a464Smaxims@google.com 
1081eb0a464Smaxims@google.com 	return 0;
1091eb0a464Smaxims@google.com }
1101eb0a464Smaxims@google.com 
ast_wdt_stop(struct udevice * dev)1111eb0a464Smaxims@google.com static int ast_wdt_stop(struct udevice *dev)
1121eb0a464Smaxims@google.com {
1131eb0a464Smaxims@google.com 	struct ast_wdt_priv *priv = dev_get_priv(dev);
1141ac11e4aSryan_chen 	ulong driver_data = dev_get_driver_data(dev);
1151eb0a464Smaxims@google.com 
1161eb0a464Smaxims@google.com 	clrbits_le32(&priv->regs->ctrl, WDT_CTRL_EN);
1171eb0a464Smaxims@google.com 
1181ac11e4aSryan_chen 	if(driver_data == WDT_AST2600) {
1191ac11e4aSryan_chen 		writel(0x030f1ff1, &priv->regs->reset_mask1);
120*a0765678SChia-Wei, Wang 		writel(0x3fffff1, &priv->regs->reset_mask2);
1211ac11e4aSryan_chen 	} else
1221ac11e4aSryan_chen 		writel(WDT_RESET_DEFAULT, &priv->regs->reset_mask1);
1231ac11e4aSryan_chen 
1241eb0a464Smaxims@google.com 	return 0;
1251eb0a464Smaxims@google.com }
1261eb0a464Smaxims@google.com 
ast_wdt_reset(struct udevice * dev)1271eb0a464Smaxims@google.com static int ast_wdt_reset(struct udevice *dev)
1281eb0a464Smaxims@google.com {
1291eb0a464Smaxims@google.com 	struct ast_wdt_priv *priv = dev_get_priv(dev);
1301eb0a464Smaxims@google.com 
1311eb0a464Smaxims@google.com 	writel(WDT_COUNTER_RESTART_VAL, &priv->regs->counter_restart);
1321eb0a464Smaxims@google.com 
1331eb0a464Smaxims@google.com 	return 0;
1341eb0a464Smaxims@google.com }
1351eb0a464Smaxims@google.com 
ast_wdt_expire_now(struct udevice * dev,ulong flags)1361eb0a464Smaxims@google.com static int ast_wdt_expire_now(struct udevice *dev, ulong flags)
1371eb0a464Smaxims@google.com {
1381eb0a464Smaxims@google.com 	struct ast_wdt_priv *priv = dev_get_priv(dev);
1391eb0a464Smaxims@google.com 	int ret;
1401eb0a464Smaxims@google.com 
1411eb0a464Smaxims@google.com 	ret = ast_wdt_start(dev, 1, flags);
1421eb0a464Smaxims@google.com 	if (ret)
1431eb0a464Smaxims@google.com 		return ret;
1441eb0a464Smaxims@google.com 
1451ac11e4aSryan_chen 	while (readl(&priv->regs->ctrl) & WDT_CTRL_EN);
1461eb0a464Smaxims@google.com 
1471eb0a464Smaxims@google.com 	return ast_wdt_stop(dev);
1481eb0a464Smaxims@google.com }
1491eb0a464Smaxims@google.com 
ast_wdt_ofdata_to_platdata(struct udevice * dev)1501eb0a464Smaxims@google.com static int ast_wdt_ofdata_to_platdata(struct udevice *dev)
1511eb0a464Smaxims@google.com {
1521eb0a464Smaxims@google.com 	struct ast_wdt_priv *priv = dev_get_priv(dev);
1531eb0a464Smaxims@google.com 
154a821c4afSSimon Glass 	priv->regs = devfdt_get_addr_ptr(dev);
1551eb0a464Smaxims@google.com 	if (IS_ERR(priv->regs))
1561eb0a464Smaxims@google.com 		return PTR_ERR(priv->regs);
1571eb0a464Smaxims@google.com 
1581eb0a464Smaxims@google.com 	return 0;
1591eb0a464Smaxims@google.com }
1601eb0a464Smaxims@google.com 
1611eb0a464Smaxims@google.com static const struct wdt_ops ast_wdt_ops = {
1621eb0a464Smaxims@google.com 	.start = ast_wdt_start,
1631eb0a464Smaxims@google.com 	.reset = ast_wdt_reset,
1641eb0a464Smaxims@google.com 	.stop = ast_wdt_stop,
1651eb0a464Smaxims@google.com 	.expire_now = ast_wdt_expire_now,
1661eb0a464Smaxims@google.com };
1671eb0a464Smaxims@google.com 
ast_wdt_probe(struct udevice * dev)1681eb0a464Smaxims@google.com static int ast_wdt_probe(struct udevice *dev)
1691eb0a464Smaxims@google.com {
1701eb0a464Smaxims@google.com 	debug("%s() wdt%u\n", __func__, dev->seq);
1711eb0a464Smaxims@google.com 	ast_wdt_stop(dev);
1721eb0a464Smaxims@google.com 
1731eb0a464Smaxims@google.com 	return 0;
1741eb0a464Smaxims@google.com }
1751eb0a464Smaxims@google.com 
17610655ec9Sryan_chen static const struct udevice_id ast_wdt_ids[] = {
17710655ec9Sryan_chen 	{ .compatible = "aspeed,wdt", .data = WDT_AST2500 },
17810655ec9Sryan_chen 	{ .compatible = "aspeed,ast2600-wdt", .data = WDT_AST2600 },
17910655ec9Sryan_chen 	{ .compatible = "aspeed,ast2500-wdt", .data = WDT_AST2500 },
18010655ec9Sryan_chen 	{ .compatible = "aspeed,ast2400-wdt", .data = WDT_AST2400 },
18110655ec9Sryan_chen 	{}
18210655ec9Sryan_chen };
18310655ec9Sryan_chen 
1841eb0a464Smaxims@google.com U_BOOT_DRIVER(ast_wdt) = {
1851eb0a464Smaxims@google.com 	.name = "ast_wdt",
1861eb0a464Smaxims@google.com 	.id = UCLASS_WDT,
1871eb0a464Smaxims@google.com 	.of_match = ast_wdt_ids,
1881eb0a464Smaxims@google.com 	.probe = ast_wdt_probe,
1891eb0a464Smaxims@google.com 	.priv_auto_alloc_size = sizeof(struct ast_wdt_priv),
1901eb0a464Smaxims@google.com 	.ofdata_to_platdata = ast_wdt_ofdata_to_platdata,
1911eb0a464Smaxims@google.com 	.ops = &ast_wdt_ops,
1921eb0a464Smaxims@google.com };
193