xref: /openbmc/u-boot/drivers/watchdog/ast_wdt.c (revision a821c4af)
11eb0a464Smaxims@google.com /*
21eb0a464Smaxims@google.com  * Copyright 2017 Google, Inc
31eb0a464Smaxims@google.com  *
41eb0a464Smaxims@google.com  * SPDX-License-Identifier:	GPL-2.0+
51eb0a464Smaxims@google.com  */
61eb0a464Smaxims@google.com 
71eb0a464Smaxims@google.com #include <common.h>
81eb0a464Smaxims@google.com #include <dm.h>
91eb0a464Smaxims@google.com #include <errno.h>
101eb0a464Smaxims@google.com #include <wdt.h>
111eb0a464Smaxims@google.com #include <asm/io.h>
121eb0a464Smaxims@google.com #include <asm/arch/wdt.h>
131eb0a464Smaxims@google.com 
141eb0a464Smaxims@google.com #define WDT_AST2500	2500
151eb0a464Smaxims@google.com #define WDT_AST2400	2400
161eb0a464Smaxims@google.com 
171eb0a464Smaxims@google.com DECLARE_GLOBAL_DATA_PTR;
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);
281eb0a464Smaxims@google.com 
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 
561eb0a464Smaxims@google.com 	return 0;
571eb0a464Smaxims@google.com }
581eb0a464Smaxims@google.com 
591eb0a464Smaxims@google.com static int ast_wdt_reset(struct udevice *dev)
601eb0a464Smaxims@google.com {
611eb0a464Smaxims@google.com 	struct ast_wdt_priv *priv = dev_get_priv(dev);
621eb0a464Smaxims@google.com 
631eb0a464Smaxims@google.com 	writel(WDT_COUNTER_RESTART_VAL, &priv->regs->counter_restart);
641eb0a464Smaxims@google.com 
651eb0a464Smaxims@google.com 	return 0;
661eb0a464Smaxims@google.com }
671eb0a464Smaxims@google.com 
681eb0a464Smaxims@google.com static int ast_wdt_expire_now(struct udevice *dev, ulong flags)
691eb0a464Smaxims@google.com {
701eb0a464Smaxims@google.com 	struct ast_wdt_priv *priv = dev_get_priv(dev);
711eb0a464Smaxims@google.com 	int ret;
721eb0a464Smaxims@google.com 
731eb0a464Smaxims@google.com 	ret = ast_wdt_start(dev, 1, flags);
741eb0a464Smaxims@google.com 	if (ret)
751eb0a464Smaxims@google.com 		return ret;
761eb0a464Smaxims@google.com 
771eb0a464Smaxims@google.com 	while (readl(&priv->regs->ctrl) & WDT_CTRL_EN)
781eb0a464Smaxims@google.com 		;
791eb0a464Smaxims@google.com 
801eb0a464Smaxims@google.com 	return ast_wdt_stop(dev);
811eb0a464Smaxims@google.com }
821eb0a464Smaxims@google.com 
831eb0a464Smaxims@google.com static int ast_wdt_ofdata_to_platdata(struct udevice *dev)
841eb0a464Smaxims@google.com {
851eb0a464Smaxims@google.com 	struct ast_wdt_priv *priv = dev_get_priv(dev);
861eb0a464Smaxims@google.com 
87*a821c4afSSimon Glass 	priv->regs = devfdt_get_addr_ptr(dev);
881eb0a464Smaxims@google.com 	if (IS_ERR(priv->regs))
891eb0a464Smaxims@google.com 		return PTR_ERR(priv->regs);
901eb0a464Smaxims@google.com 
911eb0a464Smaxims@google.com 	return 0;
921eb0a464Smaxims@google.com }
931eb0a464Smaxims@google.com 
941eb0a464Smaxims@google.com static const struct wdt_ops ast_wdt_ops = {
951eb0a464Smaxims@google.com 	.start = ast_wdt_start,
961eb0a464Smaxims@google.com 	.reset = ast_wdt_reset,
971eb0a464Smaxims@google.com 	.stop = ast_wdt_stop,
981eb0a464Smaxims@google.com 	.expire_now = ast_wdt_expire_now,
991eb0a464Smaxims@google.com };
1001eb0a464Smaxims@google.com 
1011eb0a464Smaxims@google.com static const struct udevice_id ast_wdt_ids[] = {
1021eb0a464Smaxims@google.com 	{ .compatible = "aspeed,wdt", .data = WDT_AST2500 },
1031eb0a464Smaxims@google.com 	{ .compatible = "aspeed,ast2500-wdt", .data = WDT_AST2500 },
1041eb0a464Smaxims@google.com 	{ .compatible = "aspeed,ast2400-wdt", .data = WDT_AST2400 },
1051eb0a464Smaxims@google.com 	{}
1061eb0a464Smaxims@google.com };
1071eb0a464Smaxims@google.com 
1081eb0a464Smaxims@google.com static int ast_wdt_probe(struct udevice *dev)
1091eb0a464Smaxims@google.com {
1101eb0a464Smaxims@google.com 	debug("%s() wdt%u\n", __func__, dev->seq);
1111eb0a464Smaxims@google.com 	ast_wdt_stop(dev);
1121eb0a464Smaxims@google.com 
1131eb0a464Smaxims@google.com 	return 0;
1141eb0a464Smaxims@google.com }
1151eb0a464Smaxims@google.com 
1161eb0a464Smaxims@google.com U_BOOT_DRIVER(ast_wdt) = {
1171eb0a464Smaxims@google.com 	.name = "ast_wdt",
1181eb0a464Smaxims@google.com 	.id = UCLASS_WDT,
1191eb0a464Smaxims@google.com 	.of_match = ast_wdt_ids,
1201eb0a464Smaxims@google.com 	.probe = ast_wdt_probe,
1211eb0a464Smaxims@google.com 	.priv_auto_alloc_size = sizeof(struct ast_wdt_priv),
1221eb0a464Smaxims@google.com 	.ofdata_to_platdata = ast_wdt_ofdata_to_platdata,
1231eb0a464Smaxims@google.com 	.ops = &ast_wdt_ops,
1241eb0a464Smaxims@google.com 	.flags = DM_FLAG_PRE_RELOC,
1251eb0a464Smaxims@google.com };
126