xref: /openbmc/u-boot/drivers/watchdog/ast_wdt.c (revision 10655ec9)
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>
111eb0a464Smaxims@google.com #include <asm/arch/wdt.h>
121eb0a464Smaxims@google.com 
13612dc3e3Sryan_chen enum aspeed_wdt_model {
14612dc3e3Sryan_chen 	WDT_AST2400,
15612dc3e3Sryan_chen 	WDT_AST2500,
16612dc3e3Sryan_chen 	WDT_AST2600,
17612dc3e3Sryan_chen };
181eb0a464Smaxims@google.com 
191eb0a464Smaxims@google.com struct ast_wdt_priv {
201eb0a464Smaxims@google.com 	struct ast_wdt *regs;
211eb0a464Smaxims@google.com };
221eb0a464Smaxims@google.com 
231eb0a464Smaxims@google.com static int ast_wdt_start(struct udevice *dev, u64 timeout, ulong flags)
241eb0a464Smaxims@google.com {
251eb0a464Smaxims@google.com 	struct ast_wdt_priv *priv = dev_get_priv(dev);
261eb0a464Smaxims@google.com 	ulong driver_data = dev_get_driver_data(dev);
271eb0a464Smaxims@google.com 	u32 reset_mode = ast_reset_mode_from_flags(flags);
28*10655ec9Sryan_chen printf("ast_wdt_start to %ld \n", timeout);
291eb0a464Smaxims@google.com 	clrsetbits_le32(&priv->regs->ctrl,
301eb0a464Smaxims@google.com 			WDT_CTRL_RESET_MASK << WDT_CTRL_RESET_MODE_SHIFT,
311eb0a464Smaxims@google.com 			reset_mode << WDT_CTRL_RESET_MODE_SHIFT);
321eb0a464Smaxims@google.com 
331eb0a464Smaxims@google.com 	if (driver_data >= WDT_AST2500 && reset_mode == WDT_CTRL_RESET_SOC)
341eb0a464Smaxims@google.com 		writel(ast_reset_mask_from_flags(flags),
351eb0a464Smaxims@google.com 		       &priv->regs->reset_mask);
361eb0a464Smaxims@google.com 
371eb0a464Smaxims@google.com 	writel((u32) timeout, &priv->regs->counter_reload_val);
381eb0a464Smaxims@google.com 	writel(WDT_COUNTER_RESTART_VAL, &priv->regs->counter_restart);
391eb0a464Smaxims@google.com 	/*
401eb0a464Smaxims@google.com 	 * Setting CLK1MHZ bit is just for compatibility with ast2400 part.
411eb0a464Smaxims@google.com 	 * On ast2500 watchdog timer clock is fixed at 1MHz and the bit is
421eb0a464Smaxims@google.com 	 * read-only
431eb0a464Smaxims@google.com 	 */
441eb0a464Smaxims@google.com 	setbits_le32(&priv->regs->ctrl,
451eb0a464Smaxims@google.com 		     WDT_CTRL_EN | WDT_CTRL_RESET | WDT_CTRL_CLK1MHZ);
461eb0a464Smaxims@google.com 
471eb0a464Smaxims@google.com 	return 0;
481eb0a464Smaxims@google.com }
491eb0a464Smaxims@google.com 
501eb0a464Smaxims@google.com static int ast_wdt_stop(struct udevice *dev)
511eb0a464Smaxims@google.com {
521eb0a464Smaxims@google.com 	struct ast_wdt_priv *priv = dev_get_priv(dev);
531eb0a464Smaxims@google.com 
541eb0a464Smaxims@google.com 	clrbits_le32(&priv->regs->ctrl, WDT_CTRL_EN);
551eb0a464Smaxims@google.com 
56e1a8dfdeSCédric Le Goater 	writel(WDT_RESET_DEFAULT, &priv->regs->reset_mask);
571eb0a464Smaxims@google.com 	return 0;
581eb0a464Smaxims@google.com }
591eb0a464Smaxims@google.com 
601eb0a464Smaxims@google.com static int ast_wdt_reset(struct udevice *dev)
611eb0a464Smaxims@google.com {
621eb0a464Smaxims@google.com 	struct ast_wdt_priv *priv = dev_get_priv(dev);
631eb0a464Smaxims@google.com 
641eb0a464Smaxims@google.com 	writel(WDT_COUNTER_RESTART_VAL, &priv->regs->counter_restart);
651eb0a464Smaxims@google.com 
661eb0a464Smaxims@google.com 	return 0;
671eb0a464Smaxims@google.com }
681eb0a464Smaxims@google.com 
691eb0a464Smaxims@google.com static int ast_wdt_expire_now(struct udevice *dev, ulong flags)
701eb0a464Smaxims@google.com {
711eb0a464Smaxims@google.com 	struct ast_wdt_priv *priv = dev_get_priv(dev);
721eb0a464Smaxims@google.com 	int ret;
731eb0a464Smaxims@google.com 
741eb0a464Smaxims@google.com 	ret = ast_wdt_start(dev, 1, flags);
751eb0a464Smaxims@google.com 	if (ret)
761eb0a464Smaxims@google.com 		return ret;
771eb0a464Smaxims@google.com 
781eb0a464Smaxims@google.com 	while (readl(&priv->regs->ctrl) & WDT_CTRL_EN)
791eb0a464Smaxims@google.com 		;
801eb0a464Smaxims@google.com 
811eb0a464Smaxims@google.com 	return ast_wdt_stop(dev);
821eb0a464Smaxims@google.com }
831eb0a464Smaxims@google.com 
841eb0a464Smaxims@google.com static int ast_wdt_ofdata_to_platdata(struct udevice *dev)
851eb0a464Smaxims@google.com {
861eb0a464Smaxims@google.com 	struct ast_wdt_priv *priv = dev_get_priv(dev);
871eb0a464Smaxims@google.com 
88a821c4afSSimon Glass 	priv->regs = devfdt_get_addr_ptr(dev);
891eb0a464Smaxims@google.com 	if (IS_ERR(priv->regs))
901eb0a464Smaxims@google.com 		return PTR_ERR(priv->regs);
911eb0a464Smaxims@google.com 
921eb0a464Smaxims@google.com 	return 0;
931eb0a464Smaxims@google.com }
941eb0a464Smaxims@google.com 
951eb0a464Smaxims@google.com static const struct wdt_ops ast_wdt_ops = {
961eb0a464Smaxims@google.com 	.start = ast_wdt_start,
971eb0a464Smaxims@google.com 	.reset = ast_wdt_reset,
981eb0a464Smaxims@google.com 	.stop = ast_wdt_stop,
991eb0a464Smaxims@google.com 	.expire_now = ast_wdt_expire_now,
1001eb0a464Smaxims@google.com };
1011eb0a464Smaxims@google.com 
1021eb0a464Smaxims@google.com static int ast_wdt_probe(struct udevice *dev)
1031eb0a464Smaxims@google.com {
1041eb0a464Smaxims@google.com 	debug("%s() wdt%u\n", __func__, dev->seq);
1051eb0a464Smaxims@google.com 	ast_wdt_stop(dev);
1061eb0a464Smaxims@google.com 
1071eb0a464Smaxims@google.com 	return 0;
1081eb0a464Smaxims@google.com }
1091eb0a464Smaxims@google.com 
110*10655ec9Sryan_chen static const struct udevice_id ast_wdt_ids[] = {
111*10655ec9Sryan_chen 	{ .compatible = "aspeed,wdt", .data = WDT_AST2500 },
112*10655ec9Sryan_chen 	{ .compatible = "aspeed,ast2600-wdt", .data = WDT_AST2600 },
113*10655ec9Sryan_chen 	{ .compatible = "aspeed,ast2500-wdt", .data = WDT_AST2500 },
114*10655ec9Sryan_chen 	{ .compatible = "aspeed,ast2400-wdt", .data = WDT_AST2400 },
115*10655ec9Sryan_chen 	{}
116*10655ec9Sryan_chen };
117*10655ec9Sryan_chen 
1181eb0a464Smaxims@google.com U_BOOT_DRIVER(ast_wdt) = {
1191eb0a464Smaxims@google.com 	.name = "ast_wdt",
1201eb0a464Smaxims@google.com 	.id = UCLASS_WDT,
1211eb0a464Smaxims@google.com 	.of_match = ast_wdt_ids,
1221eb0a464Smaxims@google.com 	.probe = ast_wdt_probe,
1231eb0a464Smaxims@google.com 	.priv_auto_alloc_size = sizeof(struct ast_wdt_priv),
1241eb0a464Smaxims@google.com 	.ofdata_to_platdata = ast_wdt_ofdata_to_platdata,
1251eb0a464Smaxims@google.com 	.ops = &ast_wdt_ops,
1261eb0a464Smaxims@google.com };
127