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