| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136 |
- // SPDX-License-Identifier: GPL-2.0+
- /*
- * Copyright (c) 2022 BayLibre, SAS.
- */
- #include <clk.h>
- #include <dm.h>
- #include <dm/device_compat.h>
- #include <reset.h>
- #include <wdt.h>
- #include <asm/io.h>
- #include <linux/bitops.h>
- #define GXBB_WDT_CTRL_REG 0x0
- #define GXBB_WDT_TCNT_REG 0x8
- #define GXBB_WDT_RSET_REG 0xc
- #define GXBB_WDT_CTRL_SYS_RESET_NOW BIT(26)
- #define GXBB_WDT_CTRL_CLKDIV_EN BIT(25)
- #define GXBB_WDT_CTRL_CLK_EN BIT(24)
- #define GXBB_WDT_CTRL_EE_RESET BIT(21)
- #define GXBB_WDT_CTRL_EN BIT(18)
- #define GXBB_WDT_CTRL_DIV_MASK GENMASK(17, 0)
- #define GXBB_WDT_TCNT_SETUP_MASK GENMASK(15, 0)
- struct amlogic_wdt_priv {
- void __iomem *reg_base;
- };
- static int amlogic_wdt_set_timeout(struct udevice *dev, u64 timeout_ms)
- {
- struct amlogic_wdt_priv *data = dev_get_priv(dev);
- if (timeout_ms > GXBB_WDT_TCNT_SETUP_MASK) {
- dev_warn(dev, "%s: timeout_ms=%llu: maximum watchdog timeout exceeded\n",
- __func__, timeout_ms);
- timeout_ms = GXBB_WDT_TCNT_SETUP_MASK;
- }
- writel(timeout_ms, data->reg_base + GXBB_WDT_TCNT_REG);
- return 0;
- }
- static int amlogic_wdt_stop(struct udevice *dev)
- {
- struct amlogic_wdt_priv *data = dev_get_priv(dev);
- writel(readl(data->reg_base + GXBB_WDT_CTRL_REG) & ~GXBB_WDT_CTRL_EN,
- data->reg_base + GXBB_WDT_CTRL_REG);
- return 0;
- }
- static int amlogic_wdt_start(struct udevice *dev, u64 time_ms, ulong flags)
- {
- struct amlogic_wdt_priv *data = dev_get_priv(dev);
- writel(readl(data->reg_base + GXBB_WDT_CTRL_REG) | GXBB_WDT_CTRL_EN,
- data->reg_base + GXBB_WDT_CTRL_REG);
- return amlogic_wdt_set_timeout(dev, time_ms);
- }
- static int amlogic_wdt_reset(struct udevice *dev)
- {
- struct amlogic_wdt_priv *data = dev_get_priv(dev);
- writel(0, data->reg_base + GXBB_WDT_RSET_REG);
- return 0;
- }
- static int amlogic_wdt_expire_now(struct udevice *dev, ulong flags)
- {
- struct amlogic_wdt_priv *data = dev_get_priv(dev);
- writel(0, data->reg_base + GXBB_WDT_CTRL_SYS_RESET_NOW);
- return 0;
- }
- static int amlogic_wdt_probe(struct udevice *dev)
- {
- struct amlogic_wdt_priv *data = dev_get_priv(dev);
- int ret;
- data->reg_base = dev_remap_addr(dev);
- if (!data->reg_base)
- return -EINVAL;
- struct clk clk;
- ret = clk_get_by_index(dev, 0, &clk);
- if (ret)
- return ret;
- ret = clk_enable(&clk);
- if (ret) {
- clk_free(&clk);
- return ret;
- }
- /* Setup with 1ms timebase */
- writel(((clk_get_rate(&clk) / 1000) & GXBB_WDT_CTRL_DIV_MASK) |
- GXBB_WDT_CTRL_EE_RESET |
- GXBB_WDT_CTRL_CLK_EN |
- GXBB_WDT_CTRL_CLKDIV_EN,
- data->reg_base + GXBB_WDT_CTRL_REG);
- return 0;
- }
- static const struct wdt_ops amlogic_wdt_ops = {
- .start = amlogic_wdt_start,
- .reset = amlogic_wdt_reset,
- .stop = amlogic_wdt_stop,
- .expire_now = amlogic_wdt_expire_now,
- };
- static const struct udevice_id amlogic_wdt_ids[] = {
- { .compatible = "amlogic,meson-gxbb-wdt" },
- {}
- };
- U_BOOT_DRIVER(amlogic_wdt) = {
- .name = "amlogic_wdt",
- .id = UCLASS_WDT,
- .of_match = amlogic_wdt_ids,
- .priv_auto = sizeof(struct amlogic_wdt_priv),
- .probe = amlogic_wdt_probe,
- .ops = &amlogic_wdt_ops,
- .flags = DM_FLAG_PRE_RELOC,
- };
|