diff options
author | maxims@google.com <maxims@google.com> | 2017-04-17 12:00:22 -0700 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2017-05-08 11:57:31 -0400 |
commit | 1eb0a464b7434175800c98a175909588d38c1dae (patch) | |
tree | 32b328b44d53ac1af19901f94385c3a648bc8893 /drivers/watchdog | |
parent | 0753bc2d30d7ca4a0ea4ef7f97083961c3a9d0e0 (diff) | |
download | u-boot-1eb0a464b7434175800c98a175909588d38c1dae.tar.gz u-boot-1eb0a464b7434175800c98a175909588d38c1dae.tar.bz2 u-boot-1eb0a464b7434175800c98a175909588d38c1dae.zip |
aspeed: Watchdog Timer Driver
This driver supports ast2500 and ast2400 SoCs.
Only ast2500 supports reset_mask and thus the option of resettting
individual peripherals using WDT.
Signed-off-by: Maxim Sloyko <maxims@google.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
Diffstat (limited to 'drivers/watchdog')
-rw-r--r-- | drivers/watchdog/Kconfig | 11 | ||||
-rw-r--r-- | drivers/watchdog/Makefile | 1 | ||||
-rw-r--r-- | drivers/watchdog/ast_wdt.c | 125 |
3 files changed, 137 insertions, 0 deletions
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index e8d2dba835..2034e3c620 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -23,4 +23,15 @@ config WDT_SANDBOX can be probed and supports all of the methods of WDT, but does not really do anything. +config WDT_ASPEED + bool "Aspeed ast2400/ast2500 watchdog timer support" + depends on WDT + default y if ARCH_ASPEED + help + Select this to enable watchdog timer for Aspeed ast2500/ast2400 devices. + The watchdog timer is stopped when initialized. It performs reset, either + full SoC reset or CPU or just some peripherals, based on the flags. + It currently does not support Boot Flash Addressing Mode Detection or + Second Boot. + endmenu diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index e891d64849..dfc7fbda4a 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -17,3 +17,4 @@ obj-$(CONFIG_DESIGNWARE_WATCHDOG) += designware_wdt.o obj-$(CONFIG_ULP_WATCHDOG) += ulp_wdog.o obj-$(CONFIG_WDT) += wdt-uclass.o obj-$(CONFIG_WDT_SANDBOX) += sandbox_wdt.o +obj-$(CONFIG_WDT_ASPEED) += ast_wdt.o diff --git a/drivers/watchdog/ast_wdt.c b/drivers/watchdog/ast_wdt.c new file mode 100644 index 0000000000..b2bd912ad5 --- /dev/null +++ b/drivers/watchdog/ast_wdt.c @@ -0,0 +1,125 @@ +/* + * Copyright 2017 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <wdt.h> +#include <asm/io.h> +#include <asm/arch/wdt.h> + +#define WDT_AST2500 2500 +#define WDT_AST2400 2400 + +DECLARE_GLOBAL_DATA_PTR; + +struct ast_wdt_priv { + struct ast_wdt *regs; +}; + +static int ast_wdt_start(struct udevice *dev, u64 timeout, ulong flags) +{ + struct ast_wdt_priv *priv = dev_get_priv(dev); + ulong driver_data = dev_get_driver_data(dev); + u32 reset_mode = ast_reset_mode_from_flags(flags); + + clrsetbits_le32(&priv->regs->ctrl, + WDT_CTRL_RESET_MASK << WDT_CTRL_RESET_MODE_SHIFT, + reset_mode << WDT_CTRL_RESET_MODE_SHIFT); + + if (driver_data >= WDT_AST2500 && reset_mode == WDT_CTRL_RESET_SOC) + writel(ast_reset_mask_from_flags(flags), + &priv->regs->reset_mask); + + writel((u32) timeout, &priv->regs->counter_reload_val); + writel(WDT_COUNTER_RESTART_VAL, &priv->regs->counter_restart); + /* + * Setting CLK1MHZ bit is just for compatibility with ast2400 part. + * On ast2500 watchdog timer clock is fixed at 1MHz and the bit is + * read-only + */ + setbits_le32(&priv->regs->ctrl, + WDT_CTRL_EN | WDT_CTRL_RESET | WDT_CTRL_CLK1MHZ); + + return 0; +} + +static int ast_wdt_stop(struct udevice *dev) +{ + struct ast_wdt_priv *priv = dev_get_priv(dev); + + clrbits_le32(&priv->regs->ctrl, WDT_CTRL_EN); + + return 0; +} + +static int ast_wdt_reset(struct udevice *dev) +{ + struct ast_wdt_priv *priv = dev_get_priv(dev); + + writel(WDT_COUNTER_RESTART_VAL, &priv->regs->counter_restart); + + return 0; +} + +static int ast_wdt_expire_now(struct udevice *dev, ulong flags) +{ + struct ast_wdt_priv *priv = dev_get_priv(dev); + int ret; + + ret = ast_wdt_start(dev, 1, flags); + if (ret) + return ret; + + while (readl(&priv->regs->ctrl) & WDT_CTRL_EN) + ; + + return ast_wdt_stop(dev); +} + +static int ast_wdt_ofdata_to_platdata(struct udevice *dev) +{ + struct ast_wdt_priv *priv = dev_get_priv(dev); + + priv->regs = dev_get_addr_ptr(dev); + if (IS_ERR(priv->regs)) + return PTR_ERR(priv->regs); + + return 0; +} + +static const struct wdt_ops ast_wdt_ops = { + .start = ast_wdt_start, + .reset = ast_wdt_reset, + .stop = ast_wdt_stop, + .expire_now = ast_wdt_expire_now, +}; + +static const struct udevice_id ast_wdt_ids[] = { + { .compatible = "aspeed,wdt", .data = WDT_AST2500 }, + { .compatible = "aspeed,ast2500-wdt", .data = WDT_AST2500 }, + { .compatible = "aspeed,ast2400-wdt", .data = WDT_AST2400 }, + {} +}; + +static int ast_wdt_probe(struct udevice *dev) +{ + debug("%s() wdt%u\n", __func__, dev->seq); + ast_wdt_stop(dev); + + return 0; +} + +U_BOOT_DRIVER(ast_wdt) = { + .name = "ast_wdt", + .id = UCLASS_WDT, + .of_match = ast_wdt_ids, + .probe = ast_wdt_probe, + .priv_auto_alloc_size = sizeof(struct ast_wdt_priv), + .ofdata_to_platdata = ast_wdt_ofdata_to_platdata, + .ops = &ast_wdt_ops, + .flags = DM_FLAG_PRE_RELOC, +}; |