diff options
Diffstat (limited to 'roms/u-boot/drivers/watchdog')
31 files changed, 4380 insertions, 0 deletions
diff --git a/roms/u-boot/drivers/watchdog/Kconfig b/roms/u-boot/drivers/watchdog/Kconfig new file mode 100644 index 000000000..f0ff2612a --- /dev/null +++ b/roms/u-boot/drivers/watchdog/Kconfig @@ -0,0 +1,276 @@ +menu "Watchdog Timer Support" + +config WATCHDOG + bool "Enable U-Boot watchdog reset" + depends on !HW_WATCHDOG + help + This option enables U-Boot watchdog support where U-Boot is using + watchdog_reset function to service watchdog device in U-Boot. Enable + this option if you want to service enabled watchdog by U-Boot. Disable + this option if you want U-Boot to start watchdog but never service it. + +config WATCHDOG_AUTOSTART + bool "Automatically start watchdog timer" + depends on WDT + default y + help + Automatically start watchdog timer and start servicing it during + init phase. Enabled by default. Disable this option if you want + to compile U-Boot with CONFIG_WDT support but do not want to + activate watchdog, like when CONFIG_WDT option is disabled. You + would be able to start watchdog manually by 'wdt' command. Useful + when you want to have support for 'wdt' command but do not want + to have watchdog enabled by default. + +config WATCHDOG_TIMEOUT_MSECS + int "Watchdog timeout in msec" + default 128000 if ARCH_MX25 || ARCH_MX31 || ARCH_MX5 || ARCH_MX6 + default 128000 if ARCH_MX7 || ARCH_VF610 + default 30000 if ARCH_SOCFPGA + default 60000 + help + Watchdog timeout in msec + +config HW_WATCHDOG + bool + +config IMX_WATCHDOG + bool "Enable Watchdog Timer support for IMX and LSCH2 of NXP" + select HW_WATCHDOG if !WDT + help + Select this to enable the IMX and LSCH2 of Layerscape watchdog + driver. + +config WATCHDOG_RESET_DISABLE + bool "Disable reset watchdog" + depends on IMX_WATCHDOG + help + Disable reset watchdog, which can let WATCHDOG_RESET invalid, so + that the watchdog will not be fed in u-boot. + +config OMAP_WATCHDOG + bool "TI OMAP watchdog driver" + depends on ARCH_OMAP2PLUS + select HW_WATCHDOG + help + Say Y here to enable the OMAP3+ watchdog driver. + +config ULP_WATCHDOG + bool "i.MX7ULP watchdog" + help + Say Y here to enable i.MX7ULP watchdog driver. + +config DESIGNWARE_WATCHDOG + bool "Designware watchdog timer support" + select HW_WATCHDOG if !WDT + default y if WDT && ROCKCHIP_RK3399 + help + Enable this to support Designware Watchdog Timer IP, present e.g. + on Altera SoCFPGA SoCs. + +config WDT + bool "Enable driver model for watchdog timer drivers" + depends on DM + imply WATCHDOG + help + Enable driver model for watchdog timer. At the moment the API + is very simple and only supports four operations: + start, stop, reset and expire_now (expire immediately). + What exactly happens when the timer expires is up to a particular + device/driver. + +config WDT_ARMADA_37XX + bool "Marvell Armada 37xx watchdog timer support" + depends on WDT && ARMADA_3700 + help + Enable this to support Watchdog Timer on Marvell Armada 37xx SoC. + There are 4 possible clocks which can be used on these SoCs. This + driver uses the second clock (ID 1), assuming that so will also + Linux's driver. + +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. + +config WDT_AST2600 + bool "Aspeed AST2600 watchdog timer support" + depends on WDT + default y if ASPEED_AST2600 + 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. + +config WDT_AT91 + bool "AT91 watchdog timer support" + depends on WDT + help + Select this to enable Microchip watchdog timer, which can be found on + some AT91 devices. + +config WDT_BCM6345 + bool "BCM6345 watchdog timer support" + depends on WDT && (ARCH_BMIPS || ARCH_BCM68360 || \ + ARCH_BCM6858 || ARCH_BCM63158) + help + Select this to enable watchdog timer for BCM6345 SoCs. + The watchdog timer is stopped when initialized. + It performs full SoC reset. + +config WDT_BOOKE + bool "PowerPC Book-E watchdog driver" + depends on WDT && MPC85xx + help + Watchdog driver for PowerPC Book-E chips, such as the Freescale + MPC85xx SOCs and the IBM PowerPC 440. + +config WDT_CDNS + bool "Cadence watchdog timer support" + depends on WDT + imply WATCHDOG + help + Select this to enable Cadence watchdog timer, which can be found on some + Xilinx Microzed Platform. + +config WDT_CORTINA + bool "Cortina Access CAxxxx watchdog timer support" + depends on WDT + help + Cortina Access CAxxxx watchdog timer support. + This driver support all CPU ISAs supported by Cortina + Access CAxxxx SoCs. + +config WDT_MPC8xx + bool "MPC8xx watchdog timer support" + depends on WDT && MPC8xx + select HW_WATCHDOG + help + Select this to enable mpc8xx watchdog timer + +config WDT_MT7620 + bool "MediaTek MT7620 watchdog timer support" + depends on WDT && SOC_MT7620 + help + Select this to enable watchdog timer on MediaTek MT7620 and earlier + SoC chips. + +config WDT_MT7621 + bool "MediaTek MT7621 watchdog timer support" + depends on WDT && SOC_MT7628 + help + Select this to enable Ralink / Mediatek watchdog timer, + which can be found on some MediaTek chips. + +config WDT_MTK + bool "MediaTek watchdog timer support" + depends on WDT && ARCH_MEDIATEK + help + Select this to enable watchdog timer for MediaTek SoCs. + The watchdog timer is stopped when initialized. + It performs full SoC reset. + +config WDT_OCTEONTX + bool "OcteonTX core watchdog support" + depends on WDT && (ARCH_OCTEONTX || ARCH_OCTEONTX2) + default y + imply WATCHDOG + help + This enables OcteonTX watchdog driver, which can be + found on OcteonTX/TX2 chipsets and inline with driver model. + Only supports watchdog reset. + +config WDT_OMAP3 + bool "TI OMAP watchdog timer support" + depends on WDT && ARCH_OMAP2PLUS + default y if AM33XX + help + This enables OMAP3+ watchdog timer driver, which can be + found on some TI chipsets and inline with driver model. + +config WDT_ORION + bool "Orion watchdog timer support" + depends on WDT + select CLK + help + Select this to enable Orion watchdog timer, which can be found on some + Marvell Armada chips. + +config WDT_K3_RTI + bool "Texas Instruments K3 RTI watchdog" + depends on WDT && ARCH_K3 + help + Say Y here if you want to include support for the K3 watchdog + timer (RTI module) available in the K3 generation of processors. + +config WDT_SANDBOX + bool "Enable Watchdog Timer support for Sandbox" + depends on SANDBOX && WDT + help + Enable Watchdog Timer support in Sandbox. This is a dummy device that + can be probed and supports all of the methods of WDT, but does not + really do anything. + +config WDT_SBSA + bool "SBSA watchdog timer support" + depends on WDT + help + Select this to enable SBSA watchdog timer. + This driver can operate ARM SBSA Generic Watchdog as a single stage. + In the single stage mode, when the timeout is reached, your system + will be reset by WS1. The first signal (WS0) is ignored. + +config WDT_SP805 + bool "SP805 watchdog timer support" + depends on WDT + help + Select this to enable SP805 watchdog timer, which can be found on some + nxp layerscape chips. + +config WDT_STM32MP + bool "IWDG watchdog driver for STM32 MP's family" + depends on WDT + imply WATCHDOG + help + Enable the STM32 watchdog (IWDG) driver. Enable support to + configure STM32's on-SoC watchdog. + +config XILINX_TB_WATCHDOG + bool "Xilinx Axi watchdog timer support" + depends on WDT + imply WATCHDOG + help + Select this to enable Xilinx Axi watchdog timer, which can be found on some + Xilinx Microblaze Platforms. + +config WDT_XILINX + bool "Xilinx window watchdog timer support" + depends on WDT && ARCH_VERSAL + select REGMAP + imply WATCHDOG + help + Select this to enable Xilinx window watchdog timer, which can be found on + Xilinx Versal Platforms. + +config WDT_TANGIER + bool "Intel Tangier watchdog timer support" + depends on WDT && INTEL_MID + help + This enables support for watchdog controller available on + Intel Tangier SoC. If you're using a board with Intel Tangier + SoC, say Y here. + +config SPL_WDT + bool "Enable driver model for watchdog timer drivers in SPL" + depends on SPL_DM + help + Enable driver model for watchdog timer in SPL. + This is similar to CONFIG_WDT in U-Boot. + +endmenu diff --git a/roms/u-boot/drivers/watchdog/Makefile b/roms/u-boot/drivers/watchdog/Makefile new file mode 100644 index 000000000..5c7ef593f --- /dev/null +++ b/roms/u-boot/drivers/watchdog/Makefile @@ -0,0 +1,39 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# (C) Copyright 2008 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. + +obj-$(CONFIG_WDT_AT91) += at91sam9_wdt.o +obj-$(CONFIG_FTWDT010_WATCHDOG) += ftwdt010_wdt.o +ifneq (,$(filter $(SOC), mx25 mx31 mx35 mx5 mx6 mx7 vf610)) +obj-y += imx_watchdog.o +else +obj-$(CONFIG_IMX_WATCHDOG) += imx_watchdog.o +endif +obj-$(CONFIG_S5P) += s5p_wdt.o +obj-$(CONFIG_XILINX_TB_WATCHDOG) += xilinx_tb_wdt.o +obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o +obj-$(CONFIG_DESIGNWARE_WATCHDOG) += designware_wdt.o +obj-$(CONFIG_ULP_WATCHDOG) += ulp_wdog.o +obj-$(CONFIG_$(SPL_TPL_)WDT) += wdt-uclass.o +obj-$(CONFIG_WDT_SANDBOX) += sandbox_wdt.o +obj-$(CONFIG_WDT_ARMADA_37XX) += armada-37xx-wdt.o +obj-$(CONFIG_WDT_ASPEED) += ast_wdt.o +obj-$(CONFIG_WDT_AST2600) += ast2600_wdt.o +obj-$(CONFIG_WDT_BCM6345) += bcm6345_wdt.o +obj-$(CONFIG_WDT_BOOKE) += booke_wdt.o +obj-$(CONFIG_WDT_CORTINA) += cortina_wdt.o +obj-$(CONFIG_WDT_ORION) += orion_wdt.o +obj-$(CONFIG_WDT_CDNS) += cdns_wdt.o +obj-$(CONFIG_WDT_MPC8xx) += mpc8xx_wdt.o +obj-$(CONFIG_WDT_MT7620) += mt7620_wdt.o +obj-$(CONFIG_WDT_MT7621) += mt7621_wdt.o +obj-$(CONFIG_WDT_MTK) += mtk_wdt.o +obj-$(CONFIG_WDT_OCTEONTX) += octeontx_wdt.o +obj-$(CONFIG_WDT_OMAP3) += omap_wdt.o +obj-$(CONFIG_WDT_SBSA) += sbsa_gwdt.o +obj-$(CONFIG_WDT_K3_RTI) += rti_wdt.o +obj-$(CONFIG_WDT_SP805) += sp805_wdt.o +obj-$(CONFIG_WDT_STM32MP) += stm32mp_wdt.o +obj-$(CONFIG_WDT_TANGIER) += tangier_wdt.o +obj-$(CONFIG_WDT_XILINX) += xilinx_wwdt.o diff --git a/roms/u-boot/drivers/watchdog/armada-37xx-wdt.c b/roms/u-boot/drivers/watchdog/armada-37xx-wdt.c new file mode 100644 index 000000000..6b5e1ab6f --- /dev/null +++ b/roms/u-boot/drivers/watchdog/armada-37xx-wdt.c @@ -0,0 +1,202 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Marvell Armada 37xx SoC Watchdog Driver + * + * Marek Behun <marek.behun@nic.cz> + */ + +#include <common.h> +#include <dm.h> +#include <wdt.h> +#include <asm/global_data.h> +#include <asm/io.h> +#include <asm/arch/cpu.h> +#include <asm/arch/soc.h> +#include <dm/device_compat.h> + +DECLARE_GLOBAL_DATA_PTR; + +struct a37xx_wdt { + void __iomem *sel_reg; + void __iomem *reg; + ulong clk_rate; + u64 timeout; +}; + +/* + * We use Counter 1 as watchdog timer, and Counter 0 for re-triggering Counter 1 + */ + +#define CNTR_CTRL(id) ((id) * 0x10) +#define CNTR_CTRL_ENABLE 0x0001 +#define CNTR_CTRL_ACTIVE 0x0002 +#define CNTR_CTRL_MODE_MASK 0x000c +#define CNTR_CTRL_MODE_ONESHOT 0x0000 +#define CNTR_CTRL_MODE_HWSIG 0x000c +#define CNTR_CTRL_TRIG_SRC_MASK 0x00f0 +#define CNTR_CTRL_TRIG_SRC_PREV_CNTR 0x0050 +#define CNTR_CTRL_PRESCALE_MASK 0xff00 +#define CNTR_CTRL_PRESCALE_MIN 2 +#define CNTR_CTRL_PRESCALE_SHIFT 8 + +#define CNTR_COUNT_LOW(id) (CNTR_CTRL(id) + 0x4) +#define CNTR_COUNT_HIGH(id) (CNTR_CTRL(id) + 0x8) + +static void set_counter_value(struct a37xx_wdt *priv, int id, u64 val) +{ + writel(val & 0xffffffff, priv->reg + CNTR_COUNT_LOW(id)); + writel(val >> 32, priv->reg + CNTR_COUNT_HIGH(id)); +} + +static void counter_enable(struct a37xx_wdt *priv, int id) +{ + setbits_le32(priv->reg + CNTR_CTRL(id), CNTR_CTRL_ENABLE); +} + +static void counter_disable(struct a37xx_wdt *priv, int id) +{ + clrbits_le32(priv->reg + CNTR_CTRL(id), CNTR_CTRL_ENABLE); +} + +static int init_counter(struct a37xx_wdt *priv, int id, u32 mode, u32 trig_src) +{ + u32 reg; + + reg = readl(priv->reg + CNTR_CTRL(id)); + if (reg & CNTR_CTRL_ACTIVE) + return -EBUSY; + + reg &= ~(CNTR_CTRL_MODE_MASK | CNTR_CTRL_PRESCALE_MASK | + CNTR_CTRL_TRIG_SRC_MASK); + + /* set mode */ + reg |= mode; + + /* set prescaler to the min value */ + reg |= CNTR_CTRL_PRESCALE_MIN << CNTR_CTRL_PRESCALE_SHIFT; + + /* set trigger source */ + reg |= trig_src; + + writel(reg, priv->reg + CNTR_CTRL(id)); + + return 0; +} + +static int a37xx_wdt_reset(struct udevice *dev) +{ + struct a37xx_wdt *priv = dev_get_priv(dev); + + if (!priv->timeout) + return -EINVAL; + + /* counter 1 is retriggered by forcing end count on counter 0 */ + counter_disable(priv, 0); + counter_enable(priv, 0); + + return 0; +} + +static int a37xx_wdt_expire_now(struct udevice *dev, ulong flags) +{ + struct a37xx_wdt *priv = dev_get_priv(dev); + + /* first we set timeout to 0 */ + counter_disable(priv, 1); + set_counter_value(priv, 1, 0); + counter_enable(priv, 1); + + /* and then we start counter 1 by forcing end count on counter 0 */ + counter_disable(priv, 0); + counter_enable(priv, 0); + + return 0; +} + +static int a37xx_wdt_start(struct udevice *dev, u64 ms, ulong flags) +{ + struct a37xx_wdt *priv = dev_get_priv(dev); + int err; + + err = init_counter(priv, 0, CNTR_CTRL_MODE_ONESHOT, 0); + if (err < 0) + return err; + + err = init_counter(priv, 1, CNTR_CTRL_MODE_HWSIG, + CNTR_CTRL_TRIG_SRC_PREV_CNTR); + if (err < 0) + return err; + + priv->timeout = ms * priv->clk_rate / 1000 / CNTR_CTRL_PRESCALE_MIN; + + set_counter_value(priv, 0, 0); + set_counter_value(priv, 1, priv->timeout); + counter_enable(priv, 1); + + /* we have to force end count on counter 0 to start counter 1 */ + counter_enable(priv, 0); + + return 0; +} + +static int a37xx_wdt_stop(struct udevice *dev) +{ + struct a37xx_wdt *priv = dev_get_priv(dev); + + counter_disable(priv, 1); + counter_disable(priv, 0); + writel(0, priv->sel_reg); + + return 0; +} + +static int a37xx_wdt_probe(struct udevice *dev) +{ + struct a37xx_wdt *priv = dev_get_priv(dev); + fdt_addr_t addr; + + addr = dev_read_addr_index(dev, 0); + if (addr == FDT_ADDR_T_NONE) + goto err; + priv->sel_reg = (void __iomem *)addr; + + addr = dev_read_addr_index(dev, 1); + if (addr == FDT_ADDR_T_NONE) + goto err; + priv->reg = (void __iomem *)addr; + + priv->clk_rate = (ulong)get_ref_clk() * 1000000; + + /* + * We use counter 1 as watchdog timer, therefore we only set bit + * TIMER1_IS_WCHDOG_TIMER. Counter 0 is only used to force re-trigger on + * counter 1. + */ + writel(1 << 1, priv->sel_reg); + + return 0; +err: + dev_err(dev, "no io address\n"); + return -ENODEV; +} + +static const struct wdt_ops a37xx_wdt_ops = { + .start = a37xx_wdt_start, + .reset = a37xx_wdt_reset, + .stop = a37xx_wdt_stop, + .expire_now = a37xx_wdt_expire_now, +}; + +static const struct udevice_id a37xx_wdt_ids[] = { + { .compatible = "marvell,armada-3700-wdt" }, + {} +}; + +U_BOOT_DRIVER(a37xx_wdt) = { + .name = "armada_37xx_wdt", + .id = UCLASS_WDT, + .of_match = a37xx_wdt_ids, + .probe = a37xx_wdt_probe, + .priv_auto = sizeof(struct a37xx_wdt), + .ops = &a37xx_wdt_ops, +}; diff --git a/roms/u-boot/drivers/watchdog/ast2600_wdt.c b/roms/u-boot/drivers/watchdog/ast2600_wdt.c new file mode 100644 index 000000000..bc9842089 --- /dev/null +++ b/roms/u-boot/drivers/watchdog/ast2600_wdt.c @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2020 Aspeed Technology, Inc + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <log.h> +#include <wdt.h> +#include <asm/io.h> +#include <asm/arch/wdt_ast2600.h> +#include <linux/err.h> + +struct ast2600_wdt_priv { + struct ast2600_wdt *regs; +}; + +static int ast2600_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags) +{ + struct ast2600_wdt_priv *priv = dev_get_priv(dev); + struct ast2600_wdt *wdt = priv->regs; + + /* WDT counts in the 1MHz frequency, namely 1us */ + writel((u32)(timeout_ms * 1000), &wdt->counter_reload_val); + writel(WDT_COUNTER_RESTART_VAL, &wdt->counter_restart); + writel(WDT_CTRL_EN | WDT_CTRL_RESET, &wdt->ctrl); + + return 0; +} + +static int ast2600_wdt_stop(struct udevice *dev) +{ + struct ast2600_wdt_priv *priv = dev_get_priv(dev); + struct ast2600_wdt *wdt = priv->regs; + + clrbits_le32(&wdt->ctrl, WDT_CTRL_EN); + + writel(WDT_RESET_MASK1_DEFAULT, &wdt->reset_mask1); + writel(WDT_RESET_MASK2_DEFAULT, &wdt->reset_mask2); + + return 0; +} + +static int ast2600_wdt_reset(struct udevice *dev) +{ + struct ast2600_wdt_priv *priv = dev_get_priv(dev); + struct ast2600_wdt *wdt = priv->regs; + + writel(WDT_COUNTER_RESTART_VAL, &wdt->counter_restart); + + return 0; +} + +static int ast2600_wdt_expire_now(struct udevice *dev, ulong flags) +{ + int ret; + struct ast2600_wdt_priv *priv = dev_get_priv(dev); + struct ast2600_wdt *wdt = priv->regs; + + ret = ast2600_wdt_start(dev, 1, flags); + if (ret) + return ret; + + while (readl(&wdt->ctrl) & WDT_CTRL_EN) + ; + + return ast2600_wdt_stop(dev); +} + +static int ast2600_wdt_of_to_plat(struct udevice *dev) +{ + struct ast2600_wdt_priv *priv = dev_get_priv(dev); + + priv->regs = dev_read_addr_ptr(dev); + if (!priv->regs) + return -EINVAL; + + return 0; +} + +static const struct wdt_ops ast2600_wdt_ops = { + .start = ast2600_wdt_start, + .reset = ast2600_wdt_reset, + .stop = ast2600_wdt_stop, + .expire_now = ast2600_wdt_expire_now, +}; + +static const struct udevice_id ast2600_wdt_ids[] = { + { .compatible = "aspeed,ast2600-wdt" }, + { } +}; + +static int ast2600_wdt_probe(struct udevice *dev) +{ + debug("%s() wdt%u\n", __func__, dev_seq(dev)); + ast2600_wdt_stop(dev); + + return 0; +} + +U_BOOT_DRIVER(ast2600_wdt) = { + .name = "ast2600_wdt", + .id = UCLASS_WDT, + .of_match = ast2600_wdt_ids, + .probe = ast2600_wdt_probe, + .priv_auto = sizeof(struct ast2600_wdt_priv), + .of_to_plat = ast2600_wdt_of_to_plat, + .ops = &ast2600_wdt_ops, +}; diff --git a/roms/u-boot/drivers/watchdog/ast_wdt.c b/roms/u-boot/drivers/watchdog/ast_wdt.c new file mode 100644 index 000000000..f7b5a1adc --- /dev/null +++ b/roms/u-boot/drivers/watchdog/ast_wdt.c @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2017 Google, Inc + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <log.h> +#include <wdt.h> +#include <asm/io.h> +#include <asm/arch/wdt.h> +#include <linux/err.h> + +#define WDT_AST2500 2500 +#define WDT_AST2400 2400 + +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); + + /* 32 bits at 1MHz is 4294967ms */ + timeout = min_t(u64, timeout, 4294967); + + /* WDT counts in ticks of 1MHz clock. 1ms / 1e3 * 1e6 */ + timeout *= 1000; + + 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); + + writel(WDT_RESET_DEFAULT, &priv->regs->reset_mask); + 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_of_to_plat(struct udevice *dev) +{ + struct ast_wdt_priv *priv = dev_get_priv(dev); + + priv->regs = dev_read_addr_ptr(dev); + if (!priv->regs) + return -EINVAL; + + 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(dev)); + 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 = sizeof(struct ast_wdt_priv), + .of_to_plat = ast_wdt_of_to_plat, + .ops = &ast_wdt_ops, +}; diff --git a/roms/u-boot/drivers/watchdog/at91sam9_wdt.c b/roms/u-boot/drivers/watchdog/at91sam9_wdt.c new file mode 100644 index 000000000..647ae325e --- /dev/null +++ b/roms/u-boot/drivers/watchdog/at91sam9_wdt.c @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * [origin: Linux kernel drivers/watchdog/at91sam9_wdt.c] + * + * Watchdog driver for AT91SAM9x processors. + * + * Copyright (C) 2008 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> + * Copyright (C) 2008 Renaud CERRATO r.cerrato@til-technologies.fr + */ + +/* + * The Watchdog Timer Mode Register can be only written to once. If the + * timeout need to be set from U-Boot, be sure that the bootstrap doesn't + * write to this register. Inform Linux to it too + */ + +#include <log.h> +#include <asm/global_data.h> +#include <asm/io.h> +#include <asm/arch/at91_wdt.h> +#include <common.h> +#include <div64.h> +#include <dm.h> +#include <errno.h> +#include <wdt.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* + * AT91SAM9 watchdog runs a 12bit counter @ 256Hz, + * use this to convert a watchdog + * value from seconds. + */ +#define WDT_SEC2TICKS(s) (((s) << 8) - 1) + +/* + * Set the watchdog time interval in 1/256Hz (write-once) + * Counter is 12 bit. + */ +static int at91_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags) +{ + struct at91_wdt_priv *priv = dev_get_priv(dev); + u64 timeout; + u32 ticks; + + /* Calculate timeout in seconds and the resulting ticks */ + timeout = timeout_ms; + do_div(timeout, 1000); + timeout = min_t(u64, timeout, WDT_MAX_TIMEOUT); + ticks = WDT_SEC2TICKS(timeout); + + /* Check if disabled */ + if (readl(priv->regs + AT91_WDT_MR) & AT91_WDT_MR_WDDIS) { + printf("sorry, watchdog is disabled\n"); + return -1; + } + + /* + * All counting occurs at SLOW_CLOCK / 128 = 256 Hz + * + * Since WDV is a 12-bit counter, the maximum period is + * 4096 / 256 = 16 seconds. + */ + priv->regval = AT91_WDT_MR_WDRSTEN /* causes watchdog reset */ + | AT91_WDT_MR_WDDBGHLT /* disabled in debug mode */ + | AT91_WDT_MR_WDD(0xfff) /* restart at any time */ + | AT91_WDT_MR_WDV(ticks); /* timer value */ + writel(priv->regval, priv->regs + AT91_WDT_MR); + + return 0; +} + +static int at91_wdt_stop(struct udevice *dev) +{ + struct at91_wdt_priv *priv = dev_get_priv(dev); + + /* Disable Watchdog Timer */ + priv->regval |= AT91_WDT_MR_WDDIS; + writel(priv->regval, priv->regs + AT91_WDT_MR); + + return 0; +} + +static int at91_wdt_reset(struct udevice *dev) +{ + struct at91_wdt_priv *priv = dev_get_priv(dev); + + writel(AT91_WDT_CR_WDRSTT | AT91_WDT_CR_KEY, priv->regs + AT91_WDT_CR); + + return 0; +} + +static const struct wdt_ops at91_wdt_ops = { + .start = at91_wdt_start, + .stop = at91_wdt_stop, + .reset = at91_wdt_reset, +}; + +static const struct udevice_id at91_wdt_ids[] = { + { .compatible = "atmel,at91sam9260-wdt" }, + {} +}; + +static int at91_wdt_probe(struct udevice *dev) +{ + struct at91_wdt_priv *priv = dev_get_priv(dev); + + priv->regs = dev_remap_addr(dev); + if (!priv->regs) + return -EINVAL; + + debug("%s: Probing wdt%u\n", __func__, dev_seq(dev)); + + return 0; +} + +U_BOOT_DRIVER(atmel_at91sam9260_wdt) = { + .name = "atmel_at91sam9260_wdt", + .id = UCLASS_WDT, + .of_match = at91_wdt_ids, + .priv_auto = sizeof(struct at91_wdt_priv), + .ops = &at91_wdt_ops, + .probe = at91_wdt_probe, +}; diff --git a/roms/u-boot/drivers/watchdog/bcm6345_wdt.c b/roms/u-boot/drivers/watchdog/bcm6345_wdt.c new file mode 100644 index 000000000..677b1347c --- /dev/null +++ b/roms/u-boot/drivers/watchdog/bcm6345_wdt.c @@ -0,0 +1,117 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2017 Álvaro Fernández Rojas <noltari@gmail.com> + * + * Derived from linux/drivers/watchdog/bcm63xx_wdt.c: + * Copyright (C) 2007 Miguel Gaio <miguel.gaio@efixo.com> + * Copyright (C) 2008 Florian Fainelli <florian@openwrt.org> + */ + +#include <common.h> +#include <dm.h> +#include <log.h> +#include <wdt.h> +#include <clk.h> +#include <asm/io.h> + +/* WDT Value register */ +#define WDT_VAL_REG 0x0 +#define WDT_VAL_MIN 0x00000002 +#define WDT_VAL_MAX 0xfffffffe + +/* WDT Control register */ +#define WDT_CTL_REG 0x4 +#define WDT_CTL_START1_MASK 0x0000ff00 +#define WDT_CTL_START2_MASK 0x000000ff +#define WDT_CTL_STOP1_MASK 0x0000ee00 +#define WDT_CTL_STOP2_MASK 0x000000ee + +struct bcm6345_wdt_priv { + void __iomem *regs; + unsigned long clk_rate; +}; + +static int bcm6345_wdt_reset(struct udevice *dev) +{ + struct bcm6345_wdt_priv *priv = dev_get_priv(dev); + + writel(WDT_CTL_START1_MASK, priv->regs + WDT_CTL_REG); + writel(WDT_CTL_START2_MASK, priv->regs + WDT_CTL_REG); + + return 0; +} + +static int bcm6345_wdt_start(struct udevice *dev, u64 timeout, ulong flags) +{ + struct bcm6345_wdt_priv *priv = dev_get_priv(dev); + u32 val = priv->clk_rate / 1000 * timeout; + + if (val < WDT_VAL_MIN) { + debug("watchdog won't fire with less than 2 ticks\n"); + val = WDT_VAL_MIN; + } else if (val > WDT_VAL_MAX) { + debug("maximum watchdog timeout exceeded\n"); + val = WDT_VAL_MAX; + } + + writel(val, priv->regs + WDT_VAL_REG); + + return bcm6345_wdt_reset(dev); +} + +static int bcm6345_wdt_expire_now(struct udevice *dev, ulong flags) +{ + return bcm6345_wdt_start(dev, WDT_VAL_MIN, flags); +} + +static int bcm6345_wdt_stop(struct udevice *dev) +{ + struct bcm6345_wdt_priv *priv = dev_get_priv(dev); + + writel(WDT_CTL_STOP1_MASK, priv->regs + WDT_CTL_REG); + writel(WDT_CTL_STOP2_MASK, priv->regs + WDT_CTL_REG); + + return 0; +} + +static const struct wdt_ops bcm6345_wdt_ops = { + .expire_now = bcm6345_wdt_expire_now, + .reset = bcm6345_wdt_reset, + .start = bcm6345_wdt_start, + .stop = bcm6345_wdt_stop, +}; + +static const struct udevice_id bcm6345_wdt_ids[] = { + { .compatible = "brcm,bcm6345-wdt" }, + { /* sentinel */ } +}; + +static int bcm6345_wdt_probe(struct udevice *dev) +{ + struct bcm6345_wdt_priv *priv = dev_get_priv(dev); + struct clk clk; + int ret; + + priv->regs = dev_remap_addr(dev); + if (!priv->regs) + return -EINVAL; + + ret = clk_get_by_index(dev, 0, &clk); + if (!ret) + priv->clk_rate = clk_get_rate(&clk); + else + return -EINVAL; + + bcm6345_wdt_stop(dev); + + return 0; +} + +U_BOOT_DRIVER(wdt_bcm6345) = { + .name = "wdt_bcm6345", + .id = UCLASS_WDT, + .of_match = bcm6345_wdt_ids, + .ops = &bcm6345_wdt_ops, + .priv_auto = sizeof(struct bcm6345_wdt_priv), + .probe = bcm6345_wdt_probe, +}; diff --git a/roms/u-boot/drivers/watchdog/booke_wdt.c b/roms/u-boot/drivers/watchdog/booke_wdt.c new file mode 100644 index 000000000..50c091956 --- /dev/null +++ b/roms/u-boot/drivers/watchdog/booke_wdt.c @@ -0,0 +1,106 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Watchdog timer for PowerPC Book-E systems + */ + +#include <div64.h> +#include <dm.h> +#include <wdt.h> +#include <asm/processor.h> + +#define WDTP_MASK TCR_WP(0x3f) + +/* For the specified period, determine the number of seconds + * corresponding to the reset time. There will be a watchdog + * exception at approximately 3/5 of this time. + * + * The formula to calculate this is given by: + * 2.5 * (2^(63-period+1)) / timebase_freq + * + * In order to simplify things, we assume that period is + * at least 1. This will still result in a very long timeout. + */ +static unsigned long long period_to_sec(unsigned int period) +{ + unsigned long long tmp = 1ULL << (64 - period); + unsigned long tmp2 = get_tbclk(); + + /* tmp may be a very large number and we don't want to overflow, + * so divide the timebase freq instead of multiplying tmp + */ + tmp2 = tmp2 / 5 * 2; + + do_div(tmp, tmp2); + return tmp; +} + +/* + * This procedure will find the highest period which will give a timeout + * greater than the one required. e.g. for a bus speed of 66666666 and + * and a parameter of 2 secs, then this procedure will return a value of 38. + */ +static unsigned int sec_to_period(unsigned int secs) +{ + unsigned int period; + + for (period = 63; period > 0; period--) { + if (period_to_sec(period) >= secs) + return period; + } + return 0; +} + +static int booke_wdt_reset(struct udevice *dev) +{ + mtspr(SPRN_TSR, TSR_ENW | TSR_WIS); + + return 0; +} + +static int booke_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags) +{ + u32 val; + unsigned int timeout = DIV_ROUND_UP(timeout_ms, 1000); + + /* clear status before enabling watchdog */ + booke_wdt_reset(dev); + val = mfspr(SPRN_TCR); + val &= ~WDTP_MASK; + val |= (TCR_WIE | TCR_WRC(WRC_CHIP) | TCR_WP(sec_to_period(timeout))); + + mtspr(SPRN_TCR, val); + + return 0; +} + +static int booke_wdt_stop(struct udevice *dev) +{ + u32 val; + + val = mfspr(SPRN_TCR); + val &= ~(TCR_WIE | WDTP_MASK); + mtspr(SPRN_TCR, val); + + /* clear status to make sure nothing is pending */ + booke_wdt_reset(dev); + + return 0; +} + +static const struct wdt_ops booke_wdt_ops = { + .start = booke_wdt_start, + .stop = booke_wdt_stop, + .reset = booke_wdt_reset, +}; + +static const struct udevice_id booke_wdt_ids[] = { + { .compatible = "fsl,booke-wdt" }, + {} +}; + +U_BOOT_DRIVER(booke_wdt) = { + .name = "booke_wdt", + .id = UCLASS_WDT, + .of_match = booke_wdt_ids, + .ops = &booke_wdt_ops, +}; diff --git a/roms/u-boot/drivers/watchdog/cdns_wdt.c b/roms/u-boot/drivers/watchdog/cdns_wdt.c new file mode 100644 index 000000000..966d010e4 --- /dev/null +++ b/roms/u-boot/drivers/watchdog/cdns_wdt.c @@ -0,0 +1,266 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Cadence WDT driver - Used by Xilinx Zynq + * Reference: Linux kernel Cadence watchdog driver. + * + * Author(s): Shreenidhi Shedi <yesshedi@gmail.com> + */ + +#include <common.h> +#include <dm.h> +#include <log.h> +#include <wdt.h> +#include <clk.h> +#include <div64.h> +#include <dm/device_compat.h> +#include <linux/err.h> +#include <linux/io.h> + +struct cdns_regs { + u32 zmr; /* WD Zero mode register, offset - 0x0 */ + u32 ccr; /* Counter Control Register offset - 0x4 */ + u32 restart; /* Restart key register, offset - 0x8 */ + u32 status; /* Status Register, offset - 0xC */ +}; + +struct cdns_wdt_priv { + bool rst; + struct cdns_regs *regs; +}; + +#define CDNS_WDT_DEFAULT_TIMEOUT 10 + +/* Supports 1 - 516 sec */ +#define CDNS_WDT_MIN_TIMEOUT 1 +#define CDNS_WDT_MAX_TIMEOUT 516 + +/* Restart key */ +#define CDNS_WDT_RESTART_KEY 0x00001999 + +/* Counter register access key */ +#define CDNS_WDT_REGISTER_ACCESS_KEY 0x00920000 + +/* Counter value divisor */ +#define CDNS_WDT_COUNTER_VALUE_DIVISOR 0x1000 + +/* Clock prescaler value and selection */ +#define CDNS_WDT_PRESCALE_64 64 +#define CDNS_WDT_PRESCALE_512 512 +#define CDNS_WDT_PRESCALE_4096 4096 +#define CDNS_WDT_PRESCALE_SELECT_64 1 +#define CDNS_WDT_PRESCALE_SELECT_512 2 +#define CDNS_WDT_PRESCALE_SELECT_4096 3 + +/* Input clock frequency */ +#define CDNS_WDT_CLK_75MHZ 75000000 + +/* Counter maximum value */ +#define CDNS_WDT_COUNTER_MAX 0xFFF + +/********************* Register Map **********************************/ + +/* + * Zero Mode Register - This register controls how the time out is indicated + * and also contains the access code to allow writes to the register (0xABC). + */ +#define CDNS_WDT_ZMR_WDEN_MASK 0x00000001 /* Enable the WDT */ +#define CDNS_WDT_ZMR_RSTEN_MASK 0x00000002 /* Enable the reset output */ +#define CDNS_WDT_ZMR_IRQEN_MASK 0x00000004 /* Enable IRQ output */ +#define CDNS_WDT_ZMR_RSTLEN_16 0x00000030 /* Reset pulse of 16 pclk cycles */ +#define CDNS_WDT_ZMR_ZKEY_VAL 0x00ABC000 /* Access key, 0xABC << 12 */ + +/* + * Counter Control register - This register controls how fast the timer runs + * and the reset value and also contains the access code to allow writes to + * the register. + */ +#define CDNS_WDT_CCR_CRV_MASK 0x00003FFC /* Counter reset value */ + +/* Write access to Registers */ +static inline void cdns_wdt_writereg(u32 *addr, u32 val) +{ + writel(val, addr); +} + +/** + * cdns_wdt_reset - Reload the watchdog timer (i.e. pat the watchdog). + * + * @dev: Watchdog device + * + * Write the restart key value (0x00001999) to the restart register. + * + * Return: Always 0 + */ +static int cdns_wdt_reset(struct udevice *dev) +{ + struct cdns_wdt_priv *priv = dev_get_priv(dev); + + debug("%s\n", __func__); + + cdns_wdt_writereg(&priv->regs->restart, CDNS_WDT_RESTART_KEY); + + return 0; +} + +/** + * cdns_wdt_start - Enable and start the watchdog. + * + * @dev: Watchdog device + * @timeout: Timeout value + * @flags: Driver flags + * + * The counter value is calculated according to the formula: + * count = (timeout * clock) / prescaler + 1. + * + * The calculated count is divided by 0x1000 to obtain the field value + * to write to counter control register. + * + * Clears the contents of prescaler and counter reset value. Sets the + * prescaler to 4096 and the calculated count and access key + * to write to CCR Register. + * + * Sets the WDT (WDEN bit) and either the Reset signal(RSTEN bit) + * or Interrupt signal(IRQEN) with a specified cycles and the access + * key to write to ZMR Register. + * + * Return: Upon success 0, failure -1. + */ +static int cdns_wdt_start(struct udevice *dev, u64 timeout, ulong flags) +{ + ulong clk_f; + u32 count, prescaler, ctrl_clksel, data = 0; + struct clk clock; + struct cdns_wdt_priv *priv = dev_get_priv(dev); + + if (clk_get_by_index(dev, 0, &clock) < 0) { + dev_err(dev, "failed to get clock\n"); + return -1; + } + + clk_f = clk_get_rate(&clock); + if (IS_ERR_VALUE(clk_f)) { + dev_err(dev, "failed to get rate\n"); + return -1; + } + + /* Calculate timeout in seconds and restrict to min and max value */ + do_div(timeout, 1000); + timeout = max_t(u64, timeout, CDNS_WDT_MIN_TIMEOUT); + timeout = min_t(u64, timeout, CDNS_WDT_MAX_TIMEOUT); + + debug("%s: CLK_FREQ %ld, timeout %lld\n", __func__, clk_f, timeout); + + if (clk_f <= CDNS_WDT_CLK_75MHZ) { + prescaler = CDNS_WDT_PRESCALE_512; + ctrl_clksel = CDNS_WDT_PRESCALE_SELECT_512; + } else { + prescaler = CDNS_WDT_PRESCALE_4096; + ctrl_clksel = CDNS_WDT_PRESCALE_SELECT_4096; + } + + /* + * Counter value divisor to obtain the value of + * counter reset to be written to control register. + */ + count = (timeout * (clk_f / prescaler)) / + CDNS_WDT_COUNTER_VALUE_DIVISOR + 1; + + if (count > CDNS_WDT_COUNTER_MAX) + count = CDNS_WDT_COUNTER_MAX; + + cdns_wdt_writereg(&priv->regs->zmr, CDNS_WDT_ZMR_ZKEY_VAL); + + count = (count << 2) & CDNS_WDT_CCR_CRV_MASK; + + /* Write counter access key first to be able write to register */ + data = count | CDNS_WDT_REGISTER_ACCESS_KEY | ctrl_clksel; + cdns_wdt_writereg(&priv->regs->ccr, data); + + data = CDNS_WDT_ZMR_WDEN_MASK | CDNS_WDT_ZMR_RSTLEN_16 | + CDNS_WDT_ZMR_ZKEY_VAL; + + /* Reset on timeout if specified in device tree. */ + if (priv->rst) { + data |= CDNS_WDT_ZMR_RSTEN_MASK; + data &= ~CDNS_WDT_ZMR_IRQEN_MASK; + } else { + data &= ~CDNS_WDT_ZMR_RSTEN_MASK; + data |= CDNS_WDT_ZMR_IRQEN_MASK; + } + + cdns_wdt_writereg(&priv->regs->zmr, data); + cdns_wdt_writereg(&priv->regs->restart, CDNS_WDT_RESTART_KEY); + + return 0; +} + +/** + * cdns_wdt_stop - Stop the watchdog. + * + * @dev: Watchdog device + * + * Read the contents of the ZMR register, clear the WDEN bit in the register + * and set the access key for successful write. + * + * Return: Always 0 + */ +static int cdns_wdt_stop(struct udevice *dev) +{ + struct cdns_wdt_priv *priv = dev_get_priv(dev); + + cdns_wdt_writereg(&priv->regs->zmr, + CDNS_WDT_ZMR_ZKEY_VAL & (~CDNS_WDT_ZMR_WDEN_MASK)); + + return 0; +} + +/** + * cdns_wdt_probe - Probe call for the device. + * + * @dev: Handle to the udevice structure. + * + * Return: Always 0. + */ +static int cdns_wdt_probe(struct udevice *dev) +{ + debug("%s: Probing wdt%u\n", __func__, dev_seq(dev)); + + return 0; +} + +static int cdns_wdt_of_to_plat(struct udevice *dev) +{ + struct cdns_wdt_priv *priv = dev_get_priv(dev); + + priv->regs = (struct cdns_regs *)dev_read_addr(dev); + if (IS_ERR(priv->regs)) + return PTR_ERR(priv->regs); + + priv->rst = dev_read_bool(dev, "reset-on-timeout"); + + debug("%s: reset %d\n", __func__, priv->rst); + + return 0; +} + +static const struct wdt_ops cdns_wdt_ops = { + .start = cdns_wdt_start, + .reset = cdns_wdt_reset, + .stop = cdns_wdt_stop, + /* There is no bit/reg/support in IP for expire_now functionality */ +}; + +static const struct udevice_id cdns_wdt_ids[] = { + { .compatible = "cdns,wdt-r1p2" }, + {} +}; + +U_BOOT_DRIVER(cdns_wdt) = { + .name = "cdns_wdt", + .id = UCLASS_WDT, + .of_match = cdns_wdt_ids, + .probe = cdns_wdt_probe, + .priv_auto = sizeof(struct cdns_wdt_priv), + .of_to_plat = cdns_wdt_of_to_plat, + .ops = &cdns_wdt_ops, +}; diff --git a/roms/u-boot/drivers/watchdog/cortina_wdt.c b/roms/u-boot/drivers/watchdog/cortina_wdt.c new file mode 100644 index 000000000..7ab9d7b2d --- /dev/null +++ b/roms/u-boot/drivers/watchdog/cortina_wdt.c @@ -0,0 +1,139 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2020 Cortina-Access + * + */ + +#include <common.h> +#include <dm.h> +#include <hang.h> +#include <asm/io.h> +#include <wdt.h> +#include <linux/bitops.h> + +#define CA_WDT_CTRL 0x00 +#define CA_WDT_PS 0x04 +#define CA_WDT_DIV 0x08 +#define CA_WDT_LD 0x0C +#define CA_WDT_LOADE 0x10 +#define CA_WDT_CNT 0x14 +#define CA_WDT_IE 0x18 +#define CA_WDT_INT 0x1C +#define CA_WDT_STAT 0x20 + +/* CA_WDT_CTRL */ +#define CTL_WDT_EN BIT(0) +#define CTL_WDT_RSTEN BIT(1) +#define CTL_WDT_CLK_SEL BIT(2) +/* CA_WDT_LOADE */ +#define WDT_UPD BIT(0) +#define WDT_UPD_PS BIT(1) + +/* Global config */ +#define WDT_RESET_SUB BIT(4) +#define WDT_RESET_ALL_BLOCK BIT(6) +#define WDT_RESET_REMAP BIT(7) +#define WDT_EXT_RESET BIT(8) +#define WDT_RESET_DEFAULT (WDT_EXT_RESET | WDT_RESET_REMAP | \ + WDT_RESET_ALL_BLOCK | WDT_RESET_SUB) + +struct ca_wdt_priv { + void __iomem *base; + void __iomem *global_config; +}; + +static void cortina_wdt_set_timeout(struct udevice *dev, u64 timeout_ms) +{ + struct ca_wdt_priv *priv = dev_get_priv(dev); + + /* Prescale using millisecond unit */ + writel(CORTINA_PER_IO_FREQ / 1000, priv->base + CA_WDT_PS); + + /* Millisecond */ + writel(1, priv->base + CA_WDT_DIV); + + writel(timeout_ms, priv->base + CA_WDT_LD); + writel(WDT_UPD | WDT_UPD_PS, priv->base + CA_WDT_LOADE); +} + +static int cortina_wdt_start(struct udevice *dev, u64 timeout, ulong flags) +{ + struct ca_wdt_priv *priv = dev_get_priv(dev); + + cortina_wdt_set_timeout(dev, timeout); + + /* WDT Reset option */ + setbits_32(priv->global_config, WDT_RESET_DEFAULT); + + /* Enable WDT */ + setbits_32(priv->base, CTL_WDT_EN | CTL_WDT_RSTEN | CTL_WDT_CLK_SEL); + + return 0; +} + +static int cortina_wdt_stop(struct udevice *dev) +{ + struct ca_wdt_priv *priv = dev_get_priv(dev); + + /* Disable WDT */ + writel(0, priv->base); + + return 0; +} + +static int cortina_wdt_reset(struct udevice *dev) +{ + struct ca_wdt_priv *priv = dev_get_priv(dev); + + /* Reload WDT counter */ + writel(WDT_UPD, priv->base + CA_WDT_LOADE); + + return 0; +} + +static int cortina_wdt_expire_now(struct udevice *dev, ulong flags) +{ + /* Set 1ms timeout to reset system */ + cortina_wdt_set_timeout(dev, 1); + hang(); + + return 0; +} + +static int cortina_wdt_probe(struct udevice *dev) +{ + struct ca_wdt_priv *priv = dev_get_priv(dev); + + priv->base = dev_remap_addr_index(dev, 0); + if (!priv->base) + return -ENOENT; + + priv->global_config = dev_remap_addr_index(dev, 1); + if (!priv->global_config) + return -ENOENT; + + /* Stop WDT */ + cortina_wdt_stop(dev); + + return 0; +} + +static const struct wdt_ops cortina_wdt_ops = { + .start = cortina_wdt_start, + .reset = cortina_wdt_reset, + .stop = cortina_wdt_stop, + .expire_now = cortina_wdt_expire_now, +}; + +static const struct udevice_id cortina_wdt_ids[] = { + {.compatible = "cortina,ca-wdt"}, + {} +}; + +U_BOOT_DRIVER(cortina_wdt) = { + .name = "cortina_wdt", + .id = UCLASS_WDT, + .probe = cortina_wdt_probe, + .of_match = cortina_wdt_ids, + .ops = &cortina_wdt_ops, +}; diff --git a/roms/u-boot/drivers/watchdog/designware_wdt.c b/roms/u-boot/drivers/watchdog/designware_wdt.c new file mode 100644 index 000000000..9e5487168 --- /dev/null +++ b/roms/u-boot/drivers/watchdog/designware_wdt.c @@ -0,0 +1,187 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2013 Altera Corporation <www.altera.com> + */ + +#include <clk.h> +#include <common.h> +#include <dm.h> +#include <reset.h> +#include <wdt.h> +#include <asm/io.h> +#include <linux/bitops.h> + +#define DW_WDT_CR 0x00 +#define DW_WDT_TORR 0x04 +#define DW_WDT_CRR 0x0C + +#define DW_WDT_CR_EN_OFFSET 0x00 +#define DW_WDT_CR_RMOD_OFFSET 0x01 +#define DW_WDT_CRR_RESTART_VAL 0x76 + +struct designware_wdt_priv { + void __iomem *base; + unsigned int clk_khz; +}; + +/* + * Set the watchdog time interval. + * Counter is 32 bit. + */ +static int designware_wdt_settimeout(void __iomem *base, unsigned int clk_khz, + unsigned int timeout) +{ + signed int i; + + /* calculate the timeout range value */ + i = fls(timeout * clk_khz - 1) - 16; + i = clamp(i, 0, 15); + + writel(i | (i << 4), base + DW_WDT_TORR); + + return 0; +} + +static void designware_wdt_enable(void __iomem *base) +{ + writel(BIT(DW_WDT_CR_EN_OFFSET), base + DW_WDT_CR); +} + +static unsigned int designware_wdt_is_enabled(void __iomem *base) +{ + return readl(base + DW_WDT_CR) & BIT(0); +} + +static void designware_wdt_reset_common(void __iomem *base) +{ + if (designware_wdt_is_enabled(base)) + /* restart the watchdog counter */ + writel(DW_WDT_CRR_RESTART_VAL, base + DW_WDT_CRR); +} + +#if !CONFIG_IS_ENABLED(WDT) +void hw_watchdog_reset(void) +{ + designware_wdt_reset_common((void __iomem *)CONFIG_DW_WDT_BASE); +} + +void hw_watchdog_init(void) +{ + /* reset to disable the watchdog */ + hw_watchdog_reset(); + /* set timer in miliseconds */ + designware_wdt_settimeout((void __iomem *)CONFIG_DW_WDT_BASE, + CONFIG_DW_WDT_CLOCK_KHZ, + CONFIG_WATCHDOG_TIMEOUT_MSECS); + /* enable the watchdog */ + designware_wdt_enable((void __iomem *)CONFIG_DW_WDT_BASE); + /* reset the watchdog */ + hw_watchdog_reset(); +} +#else +static int designware_wdt_reset(struct udevice *dev) +{ + struct designware_wdt_priv *priv = dev_get_priv(dev); + + designware_wdt_reset_common(priv->base); + + return 0; +} + +static int designware_wdt_stop(struct udevice *dev) +{ + struct designware_wdt_priv *priv = dev_get_priv(dev); + + designware_wdt_reset(dev); + writel(0, priv->base + DW_WDT_CR); + + return 0; +} + +static int designware_wdt_start(struct udevice *dev, u64 timeout, ulong flags) +{ + struct designware_wdt_priv *priv = dev_get_priv(dev); + + designware_wdt_stop(dev); + + /* set timer in miliseconds */ + designware_wdt_settimeout(priv->base, priv->clk_khz, timeout); + + designware_wdt_enable(priv->base); + + /* reset the watchdog */ + return designware_wdt_reset(dev); +} + +static int designware_wdt_probe(struct udevice *dev) +{ + struct designware_wdt_priv *priv = dev_get_priv(dev); + __maybe_unused int ret; + + priv->base = dev_remap_addr(dev); + if (!priv->base) + return -EINVAL; + +#if CONFIG_IS_ENABLED(CLK) + struct clk clk; + + ret = clk_get_by_index(dev, 0, &clk); + if (ret) + return ret; + + ret = clk_enable(&clk); + if (ret) + goto err; + + priv->clk_khz = clk_get_rate(&clk) / 1000; + if (!priv->clk_khz) { + ret = -EINVAL; + goto err; + } +#else + priv->clk_khz = CONFIG_DW_WDT_CLOCK_KHZ; +#endif + + if (CONFIG_IS_ENABLED(DM_RESET)) { + struct reset_ctl_bulk resets; + + ret = reset_get_bulk(dev, &resets); + if (ret) + goto err; + + ret = reset_deassert_bulk(&resets); + if (ret) + goto err; + } + + /* reset to disable the watchdog */ + return designware_wdt_stop(dev); + +err: +#if CONFIG_IS_ENABLED(CLK) + clk_free(&clk); +#endif + return ret; +} + +static const struct wdt_ops designware_wdt_ops = { + .start = designware_wdt_start, + .reset = designware_wdt_reset, + .stop = designware_wdt_stop, +}; + +static const struct udevice_id designware_wdt_ids[] = { + { .compatible = "snps,dw-wdt"}, + {} +}; + +U_BOOT_DRIVER(designware_wdt) = { + .name = "designware_wdt", + .id = UCLASS_WDT, + .of_match = designware_wdt_ids, + .priv_auto = sizeof(struct designware_wdt_priv), + .probe = designware_wdt_probe, + .ops = &designware_wdt_ops, + .flags = DM_FLAG_PRE_RELOC, +}; +#endif diff --git a/roms/u-boot/drivers/watchdog/ftwdt010_wdt.c b/roms/u-boot/drivers/watchdog/ftwdt010_wdt.c new file mode 100644 index 000000000..6aed41642 --- /dev/null +++ b/roms/u-boot/drivers/watchdog/ftwdt010_wdt.c @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Watchdog driver for the FTWDT010 Watch Dog Driver + * + * (c) Copyright 2004 Faraday Technology Corp. (www.faraday-tech.com) + * Based on sa1100_wdt.c by Oleg Drokin <green@crimea.edu> + * Based on SoftDog driver by Alan Cox <alan@redhat.com> + * + * Copyright (C) 2011 Andes Technology Corporation + * Macpaul Lin, Andes Technology Corporation <macpaul@andestech.com> + * + * 27/11/2004 Initial release, Faraday. + * 12/01/2011 Port to u-boot, Macpaul Lin. + */ + +#include <common.h> +#include <log.h> +#include <watchdog.h> +#include <asm/io.h> +#include <faraday/ftwdt010_wdt.h> + +/* + * Set the watchdog time interval. + * Counter is 32 bit. + */ +int ftwdt010_wdt_settimeout(unsigned int timeout) +{ + unsigned int reg; + + struct ftwdt010_wdt *wd = (struct ftwdt010_wdt *)CONFIG_FTWDT010_BASE; + + debug("Activating WDT..\n"); + + /* Check if disabled */ + if (readl(&wd->wdcr) & ~FTWDT010_WDCR_ENABLE) { + printf("sorry, watchdog is disabled\n"); + return -1; + } + + /* + * In a 66MHz system, + * if you set WDLOAD as 0x03EF1480 (66000000) + * the reset timer is 1 second. + */ + reg = FTWDT010_WDLOAD(timeout * FTWDT010_TIMEOUT_FACTOR); + + writel(reg, &wd->wdload); + + return 0; +} + +void ftwdt010_wdt_reset(void) +{ + struct ftwdt010_wdt *wd = (struct ftwdt010_wdt *)CONFIG_FTWDT010_BASE; + + /* clear control register */ + writel(0, &wd->wdcr); + + /* Write Magic number */ + writel(FTWDT010_WDRESTART_MAGIC, &wd->wdrestart); + + /* Enable WDT */ + writel((FTWDT010_WDCR_RST | FTWDT010_WDCR_ENABLE), &wd->wdcr); +} + +void ftwdt010_wdt_disable(void) +{ + struct ftwdt010_wdt *wd = (struct ftwdt010_wdt *)CONFIG_FTWDT010_BASE; + + debug("Deactivating WDT..\n"); + + /* + * It was defined with CONFIG_WATCHDOG_NOWAYOUT in Linux + * + * Shut off the timer. + * Lock it in if it's a module and we defined ...NOWAYOUT + */ + writel(0, &wd->wdcr); +} + +#if defined(CONFIG_HW_WATCHDOG) +void hw_watchdog_reset(void) +{ + ftwdt010_wdt_reset(); +} + +void hw_watchdog_init(void) +{ + /* set timer in ms */ + ftwdt010_wdt_settimeout(CONFIG_FTWDT010_HW_TIMEOUT * 1000); +} +#endif diff --git a/roms/u-boot/drivers/watchdog/imx_watchdog.c b/roms/u-boot/drivers/watchdog/imx_watchdog.c new file mode 100644 index 000000000..3586246fb --- /dev/null +++ b/roms/u-boot/drivers/watchdog/imx_watchdog.c @@ -0,0 +1,176 @@ +/* + * watchdog.c - driver for i.mx on-chip watchdog + * + * Licensed under the GPL-2 or later. + */ + +#include <common.h> +#include <cpu_func.h> +#include <dm.h> +#include <hang.h> +#include <asm/io.h> +#include <wdt.h> +#include <watchdog.h> +#include <asm/arch/imx-regs.h> +#ifdef CONFIG_FSL_LSCH2 +#include <asm/arch/immap_lsch2.h> +#endif +#include <fsl_wdog.h> +#include <div64.h> + +#define TIMEOUT_MAX 128000 +#define TIMEOUT_MIN 500 + +static void imx_watchdog_expire_now(struct watchdog_regs *wdog, bool ext_reset) +{ + u16 wcr = WCR_WDE; + + if (ext_reset) + wcr |= WCR_SRS; /* do not assert internal reset */ + else + wcr |= WCR_WDA; /* do not assert external reset */ + + /* Write 3 times to ensure it works, due to IMX6Q errata ERR004346 */ + writew(wcr, &wdog->wcr); + writew(wcr, &wdog->wcr); + writew(wcr, &wdog->wcr); + + while (1) { + /* + * spin before reset + */ + } +} + +#if !defined(CONFIG_IMX_WATCHDOG) || \ + (defined(CONFIG_IMX_WATCHDOG) && !CONFIG_IS_ENABLED(WDT)) +void __attribute__((weak)) reset_cpu(void) +{ + struct watchdog_regs *wdog = (struct watchdog_regs *)WDOG1_BASE_ADDR; + + imx_watchdog_expire_now(wdog, true); +} +#endif + +#if defined(CONFIG_IMX_WATCHDOG) +static void imx_watchdog_reset(struct watchdog_regs *wdog) +{ +#ifndef CONFIG_WATCHDOG_RESET_DISABLE + writew(0x5555, &wdog->wsr); + writew(0xaaaa, &wdog->wsr); +#endif /* CONFIG_WATCHDOG_RESET_DISABLE*/ +} + +static void imx_watchdog_init(struct watchdog_regs *wdog, bool ext_reset, + u64 timeout) +{ + u16 wcr; + + /* + * The timer watchdog can be set between + * 0.5 and 128 Seconds. If not defined + * in configuration file, sets 128 Seconds + */ +#ifndef CONFIG_WATCHDOG_TIMEOUT_MSECS +#define CONFIG_WATCHDOG_TIMEOUT_MSECS 128000 +#endif + + timeout = max_t(u64, timeout, TIMEOUT_MIN); + timeout = min_t(u64, timeout, TIMEOUT_MAX); + timeout = lldiv(timeout, 500) - 1; + +#ifdef CONFIG_FSL_LSCH2 + wcr = (WCR_WDA | WCR_SRS | WCR_WDE) << 8 | timeout; +#else + wcr = WCR_WDZST | WCR_WDBG | WCR_WDE | WCR_SRS | + WCR_WDA | SET_WCR_WT(timeout); + if (ext_reset) + wcr |= WCR_WDT; +#endif /* CONFIG_FSL_LSCH2*/ + writew(wcr, &wdog->wcr); + imx_watchdog_reset(wdog); +} + +#if !CONFIG_IS_ENABLED(WDT) +void hw_watchdog_reset(void) +{ + struct watchdog_regs *wdog = (struct watchdog_regs *)WDOG1_BASE_ADDR; + + imx_watchdog_reset(wdog); +} + +void hw_watchdog_init(void) +{ + struct watchdog_regs *wdog = (struct watchdog_regs *)WDOG1_BASE_ADDR; + + imx_watchdog_init(wdog, true, CONFIG_WATCHDOG_TIMEOUT_MSECS); +} +#else +struct imx_wdt_priv { + void __iomem *base; + bool ext_reset; +}; + +static int imx_wdt_reset(struct udevice *dev) +{ + struct imx_wdt_priv *priv = dev_get_priv(dev); + + imx_watchdog_reset(priv->base); + + return 0; +} + +static int imx_wdt_expire_now(struct udevice *dev, ulong flags) +{ + struct imx_wdt_priv *priv = dev_get_priv(dev); + + imx_watchdog_expire_now(priv->base, priv->ext_reset); + hang(); + + return 0; +} + +static int imx_wdt_start(struct udevice *dev, u64 timeout, ulong flags) +{ + struct imx_wdt_priv *priv = dev_get_priv(dev); + + imx_watchdog_init(priv->base, priv->ext_reset, timeout); + + return 0; +} + +static int imx_wdt_probe(struct udevice *dev) +{ + struct imx_wdt_priv *priv = dev_get_priv(dev); + + priv->base = dev_read_addr_ptr(dev); + if (!priv->base) + return -ENOENT; + + priv->ext_reset = dev_read_bool(dev, "fsl,ext-reset-output"); + + return 0; +} + +static const struct wdt_ops imx_wdt_ops = { + .start = imx_wdt_start, + .reset = imx_wdt_reset, + .expire_now = imx_wdt_expire_now, +}; + +static const struct udevice_id imx_wdt_ids[] = { + { .compatible = "fsl,imx21-wdt" }, + {} +}; + +U_BOOT_DRIVER(imx_wdt) = { + .name = "imx_wdt", + .id = UCLASS_WDT, + .of_match = imx_wdt_ids, + .probe = imx_wdt_probe, + .ops = &imx_wdt_ops, + .priv_auto = sizeof(struct imx_wdt_priv), + .flags = DM_FLAG_PRE_RELOC, +}; +#endif +#endif diff --git a/roms/u-boot/drivers/watchdog/mpc8xx_wdt.c b/roms/u-boot/drivers/watchdog/mpc8xx_wdt.c new file mode 100644 index 000000000..c8b104d8f --- /dev/null +++ b/roms/u-boot/drivers/watchdog/mpc8xx_wdt.c @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2017 CS Systemes d'Information + */ + +#include <common.h> +#include <env.h> +#include <dm.h> +#include <wdt.h> +#include <mpc8xx.h> +#include <asm/cpm_8xx.h> +#include <asm/io.h> + +void hw_watchdog_reset(void) +{ + immap_t __iomem *immap = (immap_t __iomem *)CONFIG_SYS_IMMR; + + out_be16(&immap->im_siu_conf.sc_swsr, 0x556c); /* write magic1 */ + out_be16(&immap->im_siu_conf.sc_swsr, 0xaa39); /* write magic2 */ +} + +static int mpc8xx_wdt_start(struct udevice *dev, u64 timeout, ulong flags) +{ + immap_t __iomem *immap = (immap_t __iomem *)CONFIG_SYS_IMMR; + u32 val = CONFIG_SYS_SYPCR; + const char *mode = env_get("watchdog_mode"); + + if (strcmp(mode, "off") == 0) + val = val & ~(SYPCR_SWE | SYPCR_SWRI); + else if (strcmp(mode, "nmi") == 0) + val = (val & ~SYPCR_SWRI) | SYPCR_SWE; + + out_be32(&immap->im_siu_conf.sc_sypcr, val); + + if (!(in_be32(&immap->im_siu_conf.sc_sypcr) & SYPCR_SWE)) + return -EBUSY; + return 0; + +} + +static int mpc8xx_wdt_stop(struct udevice *dev) +{ + immap_t __iomem *immap = (immap_t __iomem *)CONFIG_SYS_IMMR; + + out_be32(&immap->im_siu_conf.sc_sypcr, CONFIG_SYS_SYPCR & ~SYPCR_SWE); + + if (in_be32(&immap->im_siu_conf.sc_sypcr) & SYPCR_SWE) + return -EBUSY; + return 0; +} + +static int mpc8xx_wdt_reset(struct udevice *dev) +{ + hw_watchdog_reset(); + + return 0; +} + +static const struct wdt_ops mpc8xx_wdt_ops = { + .start = mpc8xx_wdt_start, + .reset = mpc8xx_wdt_reset, + .stop = mpc8xx_wdt_stop, +}; + +static const struct udevice_id mpc8xx_wdt_ids[] = { + { .compatible = "fsl,pq1-wdt" }, + {} +}; + +U_BOOT_DRIVER(wdt_mpc8xx) = { + .name = "wdt_mpc8xx", + .id = UCLASS_WDT, + .of_match = mpc8xx_wdt_ids, + .ops = &mpc8xx_wdt_ops, +}; diff --git a/roms/u-boot/drivers/watchdog/mt7620_wdt.c b/roms/u-boot/drivers/watchdog/mt7620_wdt.c new file mode 100644 index 000000000..fe89721dd --- /dev/null +++ b/roms/u-boot/drivers/watchdog/mt7620_wdt.c @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020 MediaTek Inc. + * + * Author: Weijie Gao <weijie.gao@mediatek.com> + * + * Watchdog timer for MT7620 and earlier SoCs + */ + +#include <div64.h> +#include <dm.h> +#include <reset.h> +#include <wdt.h> +#include <linux/bitops.h> +#include <linux/io.h> + +struct mt7620_wdt { + void __iomem *regs; + u64 timeout; +}; + +#define TIMER_FREQ 40000000 +#define TIMER_MASK 0xffff +#define TIMER_PRESCALE 65536 + +#define TIMER_LOAD 0x00 +#define TIMER_CTL 0x08 + +#define TIMER_ENABLE BIT(7) +#define TIMER_MODE_SHIFT 4 +#define TIMER_MODE_WDT 3 +#define TIMER_PRESCALE_SHIFT 0 +#define TIMER_PRESCALE_65536 15 + +static void mt7620_wdt_ping(struct mt7620_wdt *priv) +{ + u64 val; + + val = (TIMER_FREQ / TIMER_PRESCALE) * priv->timeout; + do_div(val, 1000); + + if (val > TIMER_MASK) + val = TIMER_MASK; + + writel(val, priv->regs + TIMER_LOAD); +} + +static int mt7620_wdt_start(struct udevice *dev, u64 ms, ulong flags) +{ + struct mt7620_wdt *priv = dev_get_priv(dev); + + priv->timeout = ms; + mt7620_wdt_ping(priv); + + writel(TIMER_ENABLE | (TIMER_MODE_WDT << TIMER_MODE_SHIFT) | + (TIMER_PRESCALE_65536 << TIMER_PRESCALE_SHIFT), + priv->regs + TIMER_CTL); + + return 0; +} + +static int mt7620_wdt_stop(struct udevice *dev) +{ + struct mt7620_wdt *priv = dev_get_priv(dev); + + mt7620_wdt_ping(priv); + + clrbits_32(priv->regs + TIMER_CTL, TIMER_ENABLE); + + return 0; +} + +static int mt7620_wdt_reset(struct udevice *dev) +{ + struct mt7620_wdt *priv = dev_get_priv(dev); + + mt7620_wdt_ping(priv); + + return 0; +} + +static int mt7620_wdt_expire_now(struct udevice *dev, ulong flags) +{ + struct mt7620_wdt *priv = dev_get_priv(dev); + + mt7620_wdt_start(dev, 1, flags); + + /* + * 0 will disable the timer directly, a positive number must be used + * instead. Since the timer is a countdown timer, 1 (tick) is used. + * + * For a timer with input clock = 40MHz, 1 timer tick is short + * enough to trigger a timeout immediately. + * + * Restore prescale to 1, and load timer with 1 to trigger timeout. + */ + writel(TIMER_ENABLE | (TIMER_MODE_WDT << TIMER_MODE_SHIFT), + priv->regs + TIMER_CTL); + writel(1, priv->regs + TIMER_LOAD); + + return 0; +} + +static int mt7620_wdt_probe(struct udevice *dev) +{ + struct mt7620_wdt *priv = dev_get_priv(dev); + struct reset_ctl reset_wdt; + int ret; + + ret = reset_get_by_index(dev, 0, &reset_wdt); + if (!ret) + reset_deassert(&reset_wdt); + + priv->regs = dev_remap_addr(dev); + if (!priv->regs) + return -EINVAL; + + mt7620_wdt_stop(dev); + + return 0; +} + +static const struct wdt_ops mt7620_wdt_ops = { + .start = mt7620_wdt_start, + .reset = mt7620_wdt_reset, + .stop = mt7620_wdt_stop, + .expire_now = mt7620_wdt_expire_now, +}; + +static const struct udevice_id mt7620_wdt_ids[] = { + { .compatible = "mediatek,mt7620-wdt" }, + {} +}; + +U_BOOT_DRIVER(mt7620_wdt) = { + .name = "mt7620_wdt", + .id = UCLASS_WDT, + .of_match = mt7620_wdt_ids, + .probe = mt7620_wdt_probe, + .priv_auto = sizeof(struct mt7620_wdt), + .ops = &mt7620_wdt_ops, +}; diff --git a/roms/u-boot/drivers/watchdog/mt7621_wdt.c b/roms/u-boot/drivers/watchdog/mt7621_wdt.c new file mode 100644 index 000000000..f7d201b92 --- /dev/null +++ b/roms/u-boot/drivers/watchdog/mt7621_wdt.c @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Ralink / Mediatek RT288x/RT3xxx/MT76xx built-in hardware watchdog timer + * + * Copyright (C) 2018 Stefan Roese <sr@denx.de> + * + * Based on the Linux driver version which is: + * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org> + * Copyright (C) 2013 John Crispin <blogic@openwrt.org> + */ + +#include <common.h> +#include <dm.h> +#include <wdt.h> +#include <asm/global_data.h> +#include <linux/bitops.h> +#include <linux/io.h> + +DECLARE_GLOBAL_DATA_PTR; + +struct mt762x_wdt { + void __iomem *regs; +}; + +#define TIMER_REG_TMRSTAT 0x00 +#define TIMER_REG_TMR1CTL 0x20 +#define TIMER_REG_TMR1LOAD 0x24 + +#define TMR1CTL_ENABLE BIT(7) +#define TMR1CTL_RESTART BIT(9) +#define TMR1CTL_PRESCALE_SHIFT 16 + +static int mt762x_wdt_ping(struct mt762x_wdt *priv) +{ + writel(TMR1CTL_RESTART, priv->regs + TIMER_REG_TMRSTAT); + + return 0; +} + +static int mt762x_wdt_start(struct udevice *dev, u64 ms, ulong flags) +{ + struct mt762x_wdt *priv = dev_get_priv(dev); + + /* set the prescaler to 1ms == 1000us */ + writel(1000 << TMR1CTL_PRESCALE_SHIFT, priv->regs + TIMER_REG_TMR1CTL); + writel(ms, priv->regs + TIMER_REG_TMR1LOAD); + + setbits_le32(priv->regs + TIMER_REG_TMR1CTL, TMR1CTL_ENABLE); + + return 0; +} + +static int mt762x_wdt_stop(struct udevice *dev) +{ + struct mt762x_wdt *priv = dev_get_priv(dev); + + mt762x_wdt_ping(priv); + + clrbits_le32(priv->regs + TIMER_REG_TMR1CTL, TMR1CTL_ENABLE); + + return 0; +} + +static int mt762x_wdt_reset(struct udevice *dev) +{ + struct mt762x_wdt *priv = dev_get_priv(dev); + + mt762x_wdt_ping(priv); + + return 0; +} + +static int mt762x_wdt_probe(struct udevice *dev) +{ + struct mt762x_wdt *priv = dev_get_priv(dev); + + priv->regs = dev_remap_addr(dev); + if (!priv->regs) + return -EINVAL; + + mt762x_wdt_stop(dev); + + return 0; +} + +static const struct wdt_ops mt762x_wdt_ops = { + .start = mt762x_wdt_start, + .reset = mt762x_wdt_reset, + .stop = mt762x_wdt_stop, +}; + +static const struct udevice_id mt762x_wdt_ids[] = { + { .compatible = "mediatek,mt7621-wdt" }, + {} +}; + +U_BOOT_DRIVER(mt762x_wdt) = { + .name = "mt762x_wdt", + .id = UCLASS_WDT, + .of_match = mt762x_wdt_ids, + .probe = mt762x_wdt_probe, + .priv_auto = sizeof(struct mt762x_wdt), + .ops = &mt762x_wdt_ops, +}; diff --git a/roms/u-boot/drivers/watchdog/mtk_wdt.c b/roms/u-boot/drivers/watchdog/mtk_wdt.c new file mode 100644 index 000000000..b098b2e3c --- /dev/null +++ b/roms/u-boot/drivers/watchdog/mtk_wdt.c @@ -0,0 +1,159 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Watchdog driver for MediaTek SoCs + * + * Copyright (C) 2018 MediaTek Inc. + * Author: Ryder Lee <ryder.lee@mediatek.com> + */ + +#include <common.h> +#include <dm.h> +#include <hang.h> +#include <wdt.h> +#include <asm/io.h> +#include <linux/bitops.h> + +#define MTK_WDT_MODE 0x00 +#define MTK_WDT_LENGTH 0x04 +#define MTK_WDT_RESTART 0x08 +#define MTK_WDT_STATUS 0x0c +#define MTK_WDT_INTERVAL 0x10 +#define MTK_WDT_SWRST 0x14 +#define MTK_WDT_REQ_MODE 0x30 +#define MTK_WDT_DEBUG_CTL 0x40 + +#define WDT_MODE_KEY (0x22 << 24) +#define WDT_MODE_EN BIT(0) +#define WDT_MODE_EXTPOL BIT(1) +#define WDT_MODE_EXTEN BIT(2) +#define WDT_MODE_IRQ_EN BIT(3) +#define WDT_MODE_DUAL_EN BIT(6) + +#define WDT_LENGTH_KEY 0x8 +#define WDT_LENGTH_TIMEOUT(n) ((n) << 5) + +#define WDT_RESTART_KEY 0x1971 +#define WDT_SWRST_KEY 0x1209 + +struct mtk_wdt_priv { + void __iomem *base; +}; + +static int mtk_wdt_reset(struct udevice *dev) +{ + struct mtk_wdt_priv *priv = dev_get_priv(dev); + + /* Reload watchdog duration */ + writel(WDT_RESTART_KEY, priv->base + MTK_WDT_RESTART); + + return 0; +} + +static int mtk_wdt_stop(struct udevice *dev) +{ + struct mtk_wdt_priv *priv = dev_get_priv(dev); + + clrsetbits_le32(priv->base + MTK_WDT_MODE, WDT_MODE_EN, WDT_MODE_KEY); + + return 0; +} + +static int mtk_wdt_expire_now(struct udevice *dev, ulong flags) +{ + struct mtk_wdt_priv *priv = dev_get_priv(dev); + + /* Kick watchdog to prevent counter == 0 */ + writel(WDT_RESTART_KEY, priv->base + MTK_WDT_RESTART); + + /* Reset */ + writel(WDT_SWRST_KEY, priv->base + MTK_WDT_SWRST); + hang(); + + return 0; +} + +static void mtk_wdt_set_timeout(struct udevice *dev, u64 timeout_ms) +{ + struct mtk_wdt_priv *priv = dev_get_priv(dev); + u64 timeout_us; + u32 timeout_cc; + u32 length; + + /* + * One WDT_LENGTH count is 512 ticks of the wdt clock + * Clock runs at 32768 Hz + * e.g. 15.625 ms per count (nominal) + * We want the ceiling after dividing timeout_ms by 15.625 ms + * We add 15624 prior to the divide to implement the ceiling + * We prevent over-flow by clamping the timeout_ms value here + * as the maximum WDT_LENGTH counts is 1023 -> 15.984375 sec + * We also enforce a minimum of 1 count + * Many watchdog peripherals have a self-imposed count of 1 + * that is added to the register counts. + * The MediaTek docs lack details to know if this is the case here. + * So we enforce a minimum of 1 to guarantee operation. + */ + if (timeout_ms > 15984) + timeout_ms = 15984; + + timeout_us = timeout_ms * 1000; + timeout_cc = (15624 + timeout_us) / 15625; + if (timeout_cc == 0) + timeout_cc = 1; + + length = WDT_LENGTH_TIMEOUT(timeout_cc) | WDT_LENGTH_KEY; + writel(length, priv->base + MTK_WDT_LENGTH); +} + +static int mtk_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags) +{ + struct mtk_wdt_priv *priv = dev_get_priv(dev); + + mtk_wdt_set_timeout(dev, timeout_ms); + + mtk_wdt_reset(dev); + + /* Enable watchdog reset signal */ + setbits_le32(priv->base + MTK_WDT_MODE, + WDT_MODE_EN | WDT_MODE_KEY | WDT_MODE_EXTEN); + + return 0; +} + +static int mtk_wdt_probe(struct udevice *dev) +{ + struct mtk_wdt_priv *priv = dev_get_priv(dev); + + priv->base = dev_read_addr_ptr(dev); + if (!priv->base) + return -ENOENT; + + /* Clear status */ + clrsetbits_le32(priv->base + MTK_WDT_MODE, + WDT_MODE_IRQ_EN | WDT_MODE_EXTPOL, WDT_MODE_KEY); + + return mtk_wdt_stop(dev); +} + +static const struct wdt_ops mtk_wdt_ops = { + .start = mtk_wdt_start, + .reset = mtk_wdt_reset, + .stop = mtk_wdt_stop, + .expire_now = mtk_wdt_expire_now, +}; + +static const struct udevice_id mtk_wdt_ids[] = { + { .compatible = "mediatek,wdt"}, + { .compatible = "mediatek,mt6589-wdt"}, + {} +}; + +U_BOOT_DRIVER(mtk_wdt) = { + .name = "mtk_wdt", + .id = UCLASS_WDT, + .of_match = mtk_wdt_ids, + .priv_auto = sizeof(struct mtk_wdt_priv), + .probe = mtk_wdt_probe, + .ops = &mtk_wdt_ops, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/roms/u-boot/drivers/watchdog/octeontx_wdt.c b/roms/u-boot/drivers/watchdog/octeontx_wdt.c new file mode 100644 index 000000000..01b244db8 --- /dev/null +++ b/roms/u-boot/drivers/watchdog/octeontx_wdt.c @@ -0,0 +1,145 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2019 Marvell International Ltd. + * + * https://spdx.org/licenses + */ + +#include <clk.h> +#include <dm.h> +#include <errno.h> +#include <wdt.h> +#include <asm/global_data.h> +#include <asm/io.h> +#include <linux/bitfield.h> + +DECLARE_GLOBAL_DATA_PTR; + +#define CORE0_WDOG_OFFSET 0x40000 +#define CORE0_POKE_OFFSET 0x50000 +#define CORE0_POKE_OFFSET_MASK 0xfffffULL + +#define WDOG_MODE GENMASK_ULL(1, 0) +#define WDOG_LEN GENMASK_ULL(19, 4) +#define WDOG_CNT GENMASK_ULL(43, 20) + +struct octeontx_wdt { + void __iomem *reg; + struct clk clk; +}; + +static int octeontx_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags) +{ + struct octeontx_wdt *priv = dev_get_priv(dev); + u64 clk_rate, val; + u64 tout_wdog; + + clk_rate = clk_get_rate(&priv->clk); + if (IS_ERR_VALUE(clk_rate)) + return -EINVAL; + + /* Watchdog counts in 1024 cycle steps */ + tout_wdog = (clk_rate * timeout_ms / 1000) >> 10; + + /* + * We can only specify the upper 16 bits of a 24 bit value. + * Round up + */ + tout_wdog = (tout_wdog + 0xff) >> 8; + + /* If the timeout overflows the hardware limit, set max */ + if (tout_wdog >= 0x10000) + tout_wdog = 0xffff; + + val = FIELD_PREP(WDOG_MODE, 0x3) | + FIELD_PREP(WDOG_LEN, tout_wdog) | + FIELD_PREP(WDOG_CNT, tout_wdog << 8); + writeq(val, priv->reg + CORE0_WDOG_OFFSET); + + return 0; +} + +static int octeontx_wdt_stop(struct udevice *dev) +{ + struct octeontx_wdt *priv = dev_get_priv(dev); + + writeq(0, priv->reg + CORE0_WDOG_OFFSET); + + return 0; +} + +static int octeontx_wdt_expire_now(struct udevice *dev, ulong flags) +{ + octeontx_wdt_stop(dev); + + /* Start with 100ms timeout to expire immediately */ + octeontx_wdt_start(dev, 100, flags); + + return 0; +} + +static int octeontx_wdt_reset(struct udevice *dev) +{ + struct octeontx_wdt *priv = dev_get_priv(dev); + + writeq(~0ULL, priv->reg + CORE0_POKE_OFFSET); + + return 0; +} + +static int octeontx_wdt_remove(struct udevice *dev) +{ + octeontx_wdt_stop(dev); + + return 0; +} + +static int octeontx_wdt_probe(struct udevice *dev) +{ + struct octeontx_wdt *priv = dev_get_priv(dev); + int ret; + + priv->reg = dev_remap_addr(dev); + if (!priv->reg) + return -EINVAL; + + /* + * Save base register address in reg masking lower 20 bits + * as 0xa0000 appears when extracted from the DT + */ + priv->reg = (void __iomem *)(((u64)priv->reg & + ~CORE0_POKE_OFFSET_MASK)); + + ret = clk_get_by_index(dev, 0, &priv->clk); + if (ret < 0) + return ret; + + ret = clk_enable(&priv->clk); + if (ret) + return ret; + + return 0; +} + +static const struct wdt_ops octeontx_wdt_ops = { + .reset = octeontx_wdt_reset, + .start = octeontx_wdt_start, + .stop = octeontx_wdt_stop, + .expire_now = octeontx_wdt_expire_now, +}; + +static const struct udevice_id octeontx_wdt_ids[] = { + { .compatible = "arm,sbsa-gwdt" }, + {} +}; + +U_BOOT_DRIVER(wdt_octeontx) = { + .name = "wdt_octeontx", + .id = UCLASS_WDT, + .of_match = octeontx_wdt_ids, + .ops = &octeontx_wdt_ops, + .priv_auto = sizeof(struct octeontx_wdt), + .probe = octeontx_wdt_probe, + .remove = octeontx_wdt_remove, + .flags = DM_FLAG_OS_PREPARE, +}; diff --git a/roms/u-boot/drivers/watchdog/omap_wdt.c b/roms/u-boot/drivers/watchdog/omap_wdt.c new file mode 100644 index 000000000..ca2bc7cfb --- /dev/null +++ b/roms/u-boot/drivers/watchdog/omap_wdt.c @@ -0,0 +1,268 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * omap_wdt.c + * + * (C) Copyright 2013 + * Heiko Schocher, DENX Software Engineering, hs@denx.de. + * + * Based on: + * + * Watchdog driver for the TI OMAP 16xx & 24xx/34xx 32KHz (non-secure) watchdog + * + * commit 2d991a164a61858012651e13c59521975504e260 + * Author: Bill Pemberton <wfp5p@virginia.edu> + * Date: Mon Nov 19 13:21:41 2012 -0500 + * + * watchdog: remove use of __devinit + * + * CONFIG_HOTPLUG is going away as an option so __devinit is no longer + * needed. + * + * Author: MontaVista Software, Inc. + * <gdavis@mvista.com> or <source@mvista.com> + * + * History: + * + * 20030527: George G. Davis <gdavis@mvista.com> + * Initially based on linux-2.4.19-rmk7-pxa1/drivers/char/sa1100_wdt.c + * (c) Copyright 2000 Oleg Drokin <green@crimea.edu> + * Based on SoftDog driver by Alan Cox <alan@lxorguk.ukuu.org.uk> + * + * Copyright (c) 2004 Texas Instruments. + * 1. Modified to support OMAP1610 32-KHz watchdog timer + * 2. Ported to 2.6 kernel + * + * Copyright (c) 2005 David Brownell + * Use the driver model and standard identifiers; handle bigger timeouts. + */ + +#include <common.h> +#include <log.h> +#include <watchdog.h> +#include <asm/arch/hardware.h> +#include <asm/io.h> +#include <asm/processor.h> +#include <asm/arch/cpu.h> +#include <wdt.h> +#include <dm.h> +#include <errno.h> + +/* Hardware timeout in seconds */ +#define WDT_HW_TIMEOUT 60 + +#if !CONFIG_IS_ENABLED(WDT) +static unsigned int wdt_trgr_pattern = 0x1234; + +void hw_watchdog_reset(void) +{ + struct wd_timer *wdt = (struct wd_timer *)WDT_BASE; + + /* + * Somebody just triggered watchdog reset and write to WTGR register + * is in progress. It is resetting right now, no need to trigger it + * again + */ + if ((readl(&wdt->wdtwwps)) & WDT_WWPS_PEND_WTGR) + return; + + wdt_trgr_pattern = ~wdt_trgr_pattern; + writel(wdt_trgr_pattern, &wdt->wdtwtgr); + + /* + * Don't wait for posted write to complete, i.e. don't check + * WDT_WWPS_PEND_WTGR bit in WWPS register. There is no writes to + * WTGR register outside of this func, and if entering it + * we see WDT_WWPS_PEND_WTGR bit set, it means watchdog reset + * was just triggered. This prevents us from wasting time in busy + * polling of WDT_WWPS_PEND_WTGR bit. + */ +} + +static int omap_wdt_set_timeout(unsigned int timeout) +{ + struct wd_timer *wdt = (struct wd_timer *)WDT_BASE; + u32 pre_margin = GET_WLDR_VAL(timeout); + + /* just count up at 32 KHz */ + while (readl(&wdt->wdtwwps) & WDT_WWPS_PEND_WLDR) + ; + + writel(pre_margin, &wdt->wdtwldr); + while (readl(&wdt->wdtwwps) & WDT_WWPS_PEND_WLDR) + ; + + return 0; +} + +void hw_watchdog_disable(void) +{ + struct wd_timer *wdt = (struct wd_timer *)WDT_BASE; + + /* + * Disable watchdog + */ + writel(0xAAAA, &wdt->wdtwspr); + while (readl(&wdt->wdtwwps) != 0x0) + ; + writel(0x5555, &wdt->wdtwspr); + while (readl(&wdt->wdtwwps) != 0x0) + ; +} + +void hw_watchdog_init(void) +{ + struct wd_timer *wdt = (struct wd_timer *)WDT_BASE; + + /* + * Make sure the watchdog is disabled. This is unfortunately required + * because writing to various registers with the watchdog running has no + * effect. + */ + hw_watchdog_disable(); + + /* initialize prescaler */ + while (readl(&wdt->wdtwwps) & WDT_WWPS_PEND_WCLR) + ; + + writel(WDT_WCLR_PRE | (PTV << WDT_WCLR_PTV_OFF), &wdt->wdtwclr); + while (readl(&wdt->wdtwwps) & WDT_WWPS_PEND_WCLR) + ; + + omap_wdt_set_timeout(WDT_HW_TIMEOUT); + + /* Sequence to enable the watchdog */ + writel(0xBBBB, &wdt->wdtwspr); + while ((readl(&wdt->wdtwwps)) & WDT_WWPS_PEND_WSPR) + ; + + writel(0x4444, &wdt->wdtwspr); + while ((readl(&wdt->wdtwwps)) & WDT_WWPS_PEND_WSPR) + ; +} + +void watchdog_reset(void) +{ + hw_watchdog_reset(); +} + +#else + +static int omap3_wdt_reset(struct udevice *dev) +{ + struct omap3_wdt_priv *priv = dev_get_priv(dev); + + /* + * Somebody just triggered watchdog reset and write to WTGR register + * is in progress. It is resetting right now, no need to trigger it + * again + */ + if ((readl(&priv->regs->wdtwwps)) & WDT_WWPS_PEND_WTGR) + return 0; + + priv->wdt_trgr_pattern = ~(priv->wdt_trgr_pattern); + writel(priv->wdt_trgr_pattern, &priv->regs->wdtwtgr); + /* + * Don't wait for posted write to complete, i.e. don't check + * WDT_WWPS_PEND_WTGR bit in WWPS register. There is no writes to + * WTGR register outside of this func, and if entering it + * we see WDT_WWPS_PEND_WTGR bit set, it means watchdog reset + * was just triggered. This prevents us from wasting time in busy + * polling of WDT_WWPS_PEND_WTGR bit. + */ + return 0; +} + +static int omap3_wdt_stop(struct udevice *dev) +{ + struct omap3_wdt_priv *priv = dev_get_priv(dev); + + /* disable watchdog */ + writel(0xAAAA, &priv->regs->wdtwspr); + while (readl(&priv->regs->wdtwwps) != 0x0) + ; + writel(0x5555, &priv->regs->wdtwspr); + while (readl(&priv->regs->wdtwwps) != 0x0) + ; + return 0; +} + +static int omap3_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags) +{ + struct omap3_wdt_priv *priv = dev_get_priv(dev); + u32 pre_margin = GET_WLDR_VAL(timeout_ms / 1000); + /* + * Make sure the watchdog is disabled. This is unfortunately required + * because writing to various registers with the watchdog running has + * no effect. + */ + omap3_wdt_stop(dev); + + /* initialize prescaler */ + while (readl(&priv->regs->wdtwwps) & WDT_WWPS_PEND_WCLR) + ; + + writel(WDT_WCLR_PRE | (PTV << WDT_WCLR_PTV_OFF), &priv->regs->wdtwclr); + while (readl(&priv->regs->wdtwwps) & WDT_WWPS_PEND_WCLR) + ; + /* just count up at 32 KHz */ + while (readl(&priv->regs->wdtwwps) & WDT_WWPS_PEND_WLDR) + ; + + writel(pre_margin, &priv->regs->wdtwldr); + while (readl(&priv->regs->wdtwwps) & WDT_WWPS_PEND_WLDR) + ; + /* Sequence to enable the watchdog */ + writel(0xBBBB, &priv->regs->wdtwspr); + while ((readl(&priv->regs->wdtwwps)) & WDT_WWPS_PEND_WSPR) + ; + + writel(0x4444, &priv->regs->wdtwspr); + while ((readl(&priv->regs->wdtwwps)) & WDT_WWPS_PEND_WSPR) + ; + + /* Trigger the watchdog to actually reload the counter. */ + while ((readl(&priv->regs->wdtwwps)) & WDT_WWPS_PEND_WTGR) + ; + + priv->wdt_trgr_pattern = ~(priv->wdt_trgr_pattern); + writel(priv->wdt_trgr_pattern, &priv->regs->wdtwtgr); + + while ((readl(&priv->regs->wdtwwps)) & WDT_WWPS_PEND_WTGR) + ; + + return 0; +} + +static int omap3_wdt_probe(struct udevice *dev) +{ + struct omap3_wdt_priv *priv = dev_get_priv(dev); + + priv->regs = dev_read_addr_ptr(dev); + if (!priv->regs) + return -EINVAL; + + priv->wdt_trgr_pattern = 0x1234; + debug("%s: Probing wdt%u\n", __func__, dev_seq(dev)); + return 0; +} + +static const struct wdt_ops omap3_wdt_ops = { + .start = omap3_wdt_start, + .stop = omap3_wdt_stop, + .reset = omap3_wdt_reset, +}; + +static const struct udevice_id omap3_wdt_ids[] = { + { .compatible = "ti,omap3-wdt" }, + { } +}; + +U_BOOT_DRIVER(omap3_wdt) = { + .name = "omap3_wdt", + .id = UCLASS_WDT, + .of_match = omap3_wdt_ids, + .ops = &omap3_wdt_ops, + .probe = omap3_wdt_probe, + .priv_auto = sizeof(struct omap3_wdt_priv), +}; +#endif /* !CONFIG_IS_ENABLED(WDT) */ diff --git a/roms/u-boot/drivers/watchdog/orion_wdt.c b/roms/u-boot/drivers/watchdog/orion_wdt.c new file mode 100644 index 000000000..cebea426f --- /dev/null +++ b/roms/u-boot/drivers/watchdog/orion_wdt.c @@ -0,0 +1,193 @@ +/* + * drivers/watchdog/orion_wdt.c + * + * Watchdog driver for Orion/Kirkwood processors + * + * Authors: Tomas Hlavacek <tmshlvck@gmail.com> + * Sylver Bruneau <sylver.bruneau@googlemail.com> + * Marek Behun <marek.behun@nic.cz> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <common.h> +#include <dm.h> +#include <clk.h> +#include <log.h> +#include <wdt.h> +#include <asm/global_data.h> +#include <linux/bitops.h> +#include <linux/kernel.h> +#include <asm/io.h> +#include <asm/arch/cpu.h> +#include <asm/arch/soc.h> + +DECLARE_GLOBAL_DATA_PTR; + +struct orion_wdt_priv { + void __iomem *reg; + int wdt_counter_offset; + void __iomem *rstout; + void __iomem *rstout_mask; + u32 timeout; + unsigned long clk_rate; + struct clk clk; +}; + +#define RSTOUT_ENABLE_BIT BIT(8) +#define RSTOUT_MASK_BIT BIT(10) +#define WDT_ENABLE_BIT BIT(8) + +#define TIMER_CTRL 0x0000 +#define TIMER_A370_STATUS 0x04 + +#define WDT_AXP_FIXED_ENABLE_BIT BIT(10) +#define WDT_A370_EXPIRED BIT(31) + +static int orion_wdt_reset(struct udevice *dev) +{ + struct orion_wdt_priv *priv = dev_get_priv(dev); + + /* Reload watchdog duration */ + writel(priv->clk_rate * priv->timeout, + priv->reg + priv->wdt_counter_offset); + + return 0; +} + +static int orion_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags) +{ + struct orion_wdt_priv *priv = dev_get_priv(dev); + u32 reg; + + priv->timeout = DIV_ROUND_UP(timeout_ms, 1000); + + /* Enable the fixed watchdog clock input */ + reg = readl(priv->reg + TIMER_CTRL); + reg |= WDT_AXP_FIXED_ENABLE_BIT; + writel(reg, priv->reg + TIMER_CTRL); + + /* Set watchdog duration */ + writel(priv->clk_rate * priv->timeout, + priv->reg + priv->wdt_counter_offset); + + /* Clear the watchdog expiration bit */ + reg = readl(priv->reg + TIMER_A370_STATUS); + reg &= ~WDT_A370_EXPIRED; + writel(reg, priv->reg + TIMER_A370_STATUS); + + /* Enable watchdog timer */ + reg = readl(priv->reg + TIMER_CTRL); + reg |= WDT_ENABLE_BIT; + writel(reg, priv->reg + TIMER_CTRL); + + /* Enable reset on watchdog */ + reg = readl(priv->rstout); + reg |= RSTOUT_ENABLE_BIT; + writel(reg, priv->rstout); + + reg = readl(priv->rstout_mask); + reg &= ~RSTOUT_MASK_BIT; + writel(reg, priv->rstout_mask); + + return 0; +} + +static int orion_wdt_stop(struct udevice *dev) +{ + struct orion_wdt_priv *priv = dev_get_priv(dev); + u32 reg; + + /* Disable reset on watchdog */ + reg = readl(priv->rstout_mask); + reg |= RSTOUT_MASK_BIT; + writel(reg, priv->rstout_mask); + + reg = readl(priv->rstout); + reg &= ~RSTOUT_ENABLE_BIT; + writel(reg, priv->rstout); + + /* Disable watchdog timer */ + reg = readl(priv->reg + TIMER_CTRL); + reg &= ~WDT_ENABLE_BIT; + writel(reg, priv->reg + TIMER_CTRL); + + return 0; +} + +static inline bool save_reg_from_ofdata(struct udevice *dev, int index, + void __iomem **reg, int *offset) +{ + fdt_addr_t addr; + fdt_size_t off; + + addr = devfdt_get_addr_size_index(dev, index, &off); + if (addr == FDT_ADDR_T_NONE) + return false; + + *reg = (void __iomem *) addr; + if (offset) + *offset = off; + + return true; +} + +static int orion_wdt_of_to_plat(struct udevice *dev) +{ + struct orion_wdt_priv *priv = dev_get_priv(dev); + + if (!save_reg_from_ofdata(dev, 0, &priv->reg, + &priv->wdt_counter_offset)) + goto err; + + if (!save_reg_from_ofdata(dev, 1, &priv->rstout, NULL)) + goto err; + + if (!save_reg_from_ofdata(dev, 2, &priv->rstout_mask, NULL)) + goto err; + + return 0; +err: + debug("%s: Could not determine Orion wdt IO addresses\n", __func__); + return -ENXIO; +} + +static int orion_wdt_probe(struct udevice *dev) +{ + struct orion_wdt_priv *priv = dev_get_priv(dev); + int ret; + + debug("%s: Probing wdt%u\n", __func__, dev_seq(dev)); + orion_wdt_stop(dev); + + ret = clk_get_by_name(dev, "fixed", &priv->clk); + if (!ret) + priv->clk_rate = clk_get_rate(&priv->clk); + else + priv->clk_rate = 25000000; + + return 0; +} + +static const struct wdt_ops orion_wdt_ops = { + .start = orion_wdt_start, + .reset = orion_wdt_reset, + .stop = orion_wdt_stop, +}; + +static const struct udevice_id orion_wdt_ids[] = { + { .compatible = "marvell,armada-380-wdt" }, + {} +}; + +U_BOOT_DRIVER(orion_wdt) = { + .name = "orion_wdt", + .id = UCLASS_WDT, + .of_match = orion_wdt_ids, + .probe = orion_wdt_probe, + .priv_auto = sizeof(struct orion_wdt_priv), + .of_to_plat = orion_wdt_of_to_plat, + .ops = &orion_wdt_ops, +}; diff --git a/roms/u-boot/drivers/watchdog/rti_wdt.c b/roms/u-boot/drivers/watchdog/rti_wdt.c new file mode 100644 index 000000000..8335b20ae --- /dev/null +++ b/roms/u-boot/drivers/watchdog/rti_wdt.c @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) Siemens AG, 2020 + * + * Authors: + * Jan Kiszka <jan.kiszka@siemens.com> + * + * Derived from linux/drivers/watchdog/rti_wdt.c + */ + +#include <common.h> +#include <clk.h> +#include <dm.h> +#include <power-domain.h> +#include <wdt.h> +#include <asm/io.h> + +/* Timer register set definition */ +#define RTIDWDCTRL 0x90 +#define RTIDWDPRLD 0x94 +#define RTIWDSTATUS 0x98 +#define RTIWDKEY 0x9c +#define RTIDWDCNTR 0xa0 +#define RTIWWDRXCTRL 0xa4 +#define RTIWWDSIZECTRL 0xa8 + +#define RTIWWDRX_NMI 0xa + +#define RTIWWDSIZE_50P 0x50 + +#define WDENABLE_KEY 0xa98559da + +#define WDKEY_SEQ0 0xe51a +#define WDKEY_SEQ1 0xa35c + +#define WDT_PRELOAD_SHIFT 13 + +#define WDT_PRELOAD_MAX 0xfff + +struct rti_wdt_priv { + phys_addr_t regs; + unsigned int clk_khz; +}; + +static int rti_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags) +{ + struct rti_wdt_priv *priv = dev_get_priv(dev); + u32 timer_margin; + int ret; + + if (readl(priv->regs + RTIDWDCTRL) == WDENABLE_KEY) + return -EBUSY; + + timer_margin = timeout_ms * priv->clk_khz / 1000; + timer_margin >>= WDT_PRELOAD_SHIFT; + if (timer_margin > WDT_PRELOAD_MAX) + timer_margin = WDT_PRELOAD_MAX; + + writel(timer_margin, priv->regs + RTIDWDPRLD); + writel(RTIWWDRX_NMI, priv->regs + RTIWWDRXCTRL); + writel(RTIWWDSIZE_50P, priv->regs + RTIWWDSIZECTRL); + + readl(priv->regs + RTIWWDSIZECTRL); + + writel(WDENABLE_KEY, priv->regs + RTIDWDCTRL); + + return 0; +} + +static int rti_wdt_reset(struct udevice *dev) +{ + struct rti_wdt_priv *priv = dev_get_priv(dev); + u32 prld; + + /* Make sure we do not reset too early */ + prld = readl(priv->regs + RTIDWDPRLD) << WDT_PRELOAD_SHIFT; + if (readl(priv->regs + RTIDWDCNTR) >= prld / 2) + return -EPERM; + + writel(WDKEY_SEQ0, priv->regs + RTIWDKEY); + writel(WDKEY_SEQ1, priv->regs + RTIWDKEY); + + return 0; +} + +static int rti_wdt_probe(struct udevice *dev) +{ + struct rti_wdt_priv *priv = dev_get_priv(dev); + struct clk clk; + int ret; + + priv->regs = devfdt_get_addr(dev); + if (!priv->regs) + return -EINVAL; + + ret = clk_get_by_index(dev, 0, &clk); + if (ret) + return ret; + + priv->clk_khz = clk_get_rate(&clk); + + return 0; +} + +static const struct wdt_ops rti_wdt_ops = { + .start = rti_wdt_start, + .reset = rti_wdt_reset, +}; + +static const struct udevice_id rti_wdt_ids[] = { + { .compatible = "ti,j7-rti-wdt" }, + { } +}; + +U_BOOT_DRIVER(rti_wdt) = { + .name = "rti_wdt", + .id = UCLASS_WDT, + .of_match = rti_wdt_ids, + .ops = &rti_wdt_ops, + .probe = rti_wdt_probe, + .priv_auto = sizeof(struct rti_wdt_priv), + .flags = DM_FLAG_LEAVE_PD_ON, +}; diff --git a/roms/u-boot/drivers/watchdog/s5p_wdt.c b/roms/u-boot/drivers/watchdog/s5p_wdt.c new file mode 100644 index 000000000..5ad7d2609 --- /dev/null +++ b/roms/u-boot/drivers/watchdog/s5p_wdt.c @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2012 Samsung Electronics + * Minkyu Kang <mk7.kang@samsung.com> + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/watchdog.h> + +#define PRESCALER_VAL 255 + +void wdt_stop(void) +{ + struct s5p_watchdog *wdt = + (struct s5p_watchdog *)samsung_get_base_watchdog(); + unsigned int wtcon; + + wtcon = readl(&wdt->wtcon); + wtcon &= ~(WTCON_EN | WTCON_INT | WTCON_RESET); + + writel(wtcon, &wdt->wtcon); +} + +void wdt_start(unsigned int timeout) +{ + struct s5p_watchdog *wdt = + (struct s5p_watchdog *)samsung_get_base_watchdog(); + unsigned int wtcon; + + wdt_stop(); + + wtcon = readl(&wdt->wtcon); + wtcon |= (WTCON_EN | WTCON_CLK(WTCON_CLK_128)); + wtcon &= ~WTCON_INT; + wtcon |= WTCON_RESET; + wtcon |= WTCON_PRESCALER(PRESCALER_VAL); + + writel(timeout, &wdt->wtdat); + writel(timeout, &wdt->wtcnt); + writel(wtcon, &wdt->wtcon); +} diff --git a/roms/u-boot/drivers/watchdog/sandbox_wdt.c b/roms/u-boot/drivers/watchdog/sandbox_wdt.c new file mode 100644 index 000000000..e05d82789 --- /dev/null +++ b/roms/u-boot/drivers/watchdog/sandbox_wdt.c @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2017 Google, Inc + */ + +#include <common.h> +#include <dm.h> +#include <wdt.h> +#include <asm/state.h> + +static int sandbox_wdt_start(struct udevice *dev, u64 timeout, ulong flags) +{ + struct sandbox_state *state = state_get_current(); + + state->wdt.counter = timeout; + state->wdt.running = true; + + return 0; +} + +static int sandbox_wdt_stop(struct udevice *dev) +{ + struct sandbox_state *state = state_get_current(); + + state->wdt.running = false; + + return 0; +} + +static int sandbox_wdt_reset(struct udevice *dev) +{ + struct sandbox_state *state = state_get_current(); + + state->wdt.reset_count++; + + return 0; +} + +static int sandbox_wdt_expire_now(struct udevice *dev, ulong flags) +{ + sandbox_wdt_start(dev, 1, flags); + + return 0; +} + +static const struct wdt_ops sandbox_wdt_ops = { + .start = sandbox_wdt_start, + .reset = sandbox_wdt_reset, + .stop = sandbox_wdt_stop, + .expire_now = sandbox_wdt_expire_now, +}; + +static const struct udevice_id sandbox_wdt_ids[] = { + { .compatible = "sandbox,wdt" }, + {} +}; + +U_BOOT_DRIVER(wdt_sandbox) = { + .name = "wdt_sandbox", + .id = UCLASS_WDT, + .of_match = sandbox_wdt_ids, + .ops = &sandbox_wdt_ops, +}; diff --git a/roms/u-boot/drivers/watchdog/sbsa_gwdt.c b/roms/u-boot/drivers/watchdog/sbsa_gwdt.c new file mode 100644 index 000000000..f43cd3fd2 --- /dev/null +++ b/roms/u-boot/drivers/watchdog/sbsa_gwdt.c @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Watchdog driver for SBSA + * + * Copyright 2020 NXP + */ + +#include <asm/global_data.h> +#include <asm/io.h> +#include <common.h> +#include <dm/device.h> +#include <dm/fdtaddr.h> +#include <dm/read.h> +#include <linux/bitops.h> +#include <linux/err.h> +#include <watchdog.h> +#include <wdt.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* SBSA Generic Watchdog register definitions */ +/* refresh frame */ +#define SBSA_GWDT_WRR 0x000 + +/* control frame */ +#define SBSA_GWDT_WCS 0x000 +#define SBSA_GWDT_WOR 0x008 +#define SBSA_GWDT_WCV 0x010 + +/* refresh/control frame */ +#define SBSA_GWDT_W_IIDR 0xfcc +#define SBSA_GWDT_IDR 0xfd0 + +/* Watchdog Control and Status Register */ +#define SBSA_GWDT_WCS_EN BIT(0) +#define SBSA_GWDT_WCS_WS0 BIT(1) +#define SBSA_GWDT_WCS_WS1 BIT(2) + +struct sbsa_gwdt_priv { + void __iomem *reg_refresh; + void __iomem *reg_control; +}; + +static int sbsa_gwdt_reset(struct udevice *dev) +{ + struct sbsa_gwdt_priv *priv = dev_get_priv(dev); + + writel(0, priv->reg_refresh + SBSA_GWDT_WRR); + + return 0; +} + +static int sbsa_gwdt_start(struct udevice *dev, u64 timeout, ulong flags) +{ + struct sbsa_gwdt_priv *priv = dev_get_priv(dev); + u32 clk; + + /* + * it work in the single stage mode in u-boot, + * The first signal (WS0) is ignored, + * the timeout is (WOR * 2), so the WOR should be configured + * to half value of timeout. + */ + clk = get_tbclk(); + writel(clk / (2 * 1000) * timeout, + priv->reg_control + SBSA_GWDT_WOR); + + /* writing WCS will cause an explicit watchdog refresh */ + writel(SBSA_GWDT_WCS_EN, priv->reg_control + SBSA_GWDT_WCS); + + return 0; +} + +static int sbsa_gwdt_stop(struct udevice *dev) +{ + struct sbsa_gwdt_priv *priv = dev_get_priv(dev); + + writel(0, priv->reg_control + SBSA_GWDT_WCS); + + return 0; +} + +static int sbsa_gwdt_expire_now(struct udevice *dev, ulong flags) +{ + sbsa_gwdt_start(dev, 0, flags); + + return 0; +} + +static int sbsa_gwdt_probe(struct udevice *dev) +{ + debug("%s: Probing wdt%u (sbsa-gwdt)\n", __func__, dev_seq(dev)); + + return 0; +} + +static int sbsa_gwdt_of_to_plat(struct udevice *dev) +{ + struct sbsa_gwdt_priv *priv = dev_get_priv(dev); + + priv->reg_control = (void __iomem *)dev_read_addr_index(dev, 0); + if (IS_ERR(priv->reg_control)) + return PTR_ERR(priv->reg_control); + + priv->reg_refresh = (void __iomem *)dev_read_addr_index(dev, 1); + if (IS_ERR(priv->reg_refresh)) + return PTR_ERR(priv->reg_refresh); + + return 0; +} + +static const struct wdt_ops sbsa_gwdt_ops = { + .start = sbsa_gwdt_start, + .reset = sbsa_gwdt_reset, + .stop = sbsa_gwdt_stop, + .expire_now = sbsa_gwdt_expire_now, +}; + +static const struct udevice_id sbsa_gwdt_ids[] = { + { .compatible = "arm,sbsa-gwdt" }, + {} +}; + +U_BOOT_DRIVER(sbsa_gwdt) = { + .name = "sbsa_gwdt", + .id = UCLASS_WDT, + .of_match = sbsa_gwdt_ids, + .probe = sbsa_gwdt_probe, + .priv_auto = sizeof(struct sbsa_gwdt_priv), + .of_to_plat = sbsa_gwdt_of_to_plat, + .ops = &sbsa_gwdt_ops, +}; diff --git a/roms/u-boot/drivers/watchdog/sp805_wdt.c b/roms/u-boot/drivers/watchdog/sp805_wdt.c new file mode 100644 index 000000000..bec8827ce --- /dev/null +++ b/roms/u-boot/drivers/watchdog/sp805_wdt.c @@ -0,0 +1,149 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Watchdog driver for SP805 on some Layerscape SoC + * + * Copyright 2019 NXP + */ + +#include <log.h> +#include <asm/global_data.h> +#include <asm/io.h> +#include <common.h> +#include <clk.h> +#include <dm/device.h> +#include <dm/fdtaddr.h> +#include <dm/read.h> +#include <linux/bitops.h> +#include <watchdog.h> +#include <wdt.h> +#include <linux/err.h> + +#define WDTLOAD 0x000 +#define WDTCONTROL 0x008 +#define WDTINTCLR 0x00C +#define WDTLOCK 0xC00 + +#define TIME_OUT_MIN_MSECS 1 +#define TIME_OUT_MAX_MSECS 120000 +#define SYS_FSL_WDT_CLK_DIV 16 +#define INT_ENABLE BIT(0) +#define RESET_ENABLE BIT(1) +#define DISABLE 0 +#define UNLOCK 0x1ACCE551 +#define LOCK 0x00000001 +#define INT_MASK BIT(0) + +DECLARE_GLOBAL_DATA_PTR; + +struct sp805_wdt_priv { + void __iomem *reg; + unsigned long clk_rate; +}; + +static int sp805_wdt_reset(struct udevice *dev) +{ + struct sp805_wdt_priv *priv = dev_get_priv(dev); + + writel(UNLOCK, priv->reg + WDTLOCK); + writel(INT_MASK, priv->reg + WDTINTCLR); + writel(LOCK, priv->reg + WDTLOCK); + readl(priv->reg + WDTLOCK); + + return 0; +} + +static int sp805_wdt_start(struct udevice *dev, u64 timeout, ulong flags) +{ + u32 load_value; + u32 load_time; + struct sp805_wdt_priv *priv = dev_get_priv(dev); + + load_time = (u32)timeout; + if (timeout < TIME_OUT_MIN_MSECS) + load_time = TIME_OUT_MIN_MSECS; + else if (timeout > TIME_OUT_MAX_MSECS) + load_time = TIME_OUT_MAX_MSECS; + /* sp805 runs counter with given value twice, so when the max timeout is + * set 120s, the gd->bus_clk is less than 1145MHz, the load_value will + * not overflow. + */ + if (gd->bus_clk) { + load_value = (gd->bus_clk) / + (2 * 1000 * SYS_FSL_WDT_CLK_DIV) * load_time; + } else { + /* platform provide clk */ + load_value = (timeout / 2) * (priv->clk_rate / 1000); + } + + writel(UNLOCK, priv->reg + WDTLOCK); + writel(load_value, priv->reg + WDTLOAD); + writel(INT_MASK, priv->reg + WDTINTCLR); + writel(INT_ENABLE | RESET_ENABLE, priv->reg + WDTCONTROL); + writel(LOCK, priv->reg + WDTLOCK); + readl(priv->reg + WDTLOCK); + + return 0; +} + +static int sp805_wdt_stop(struct udevice *dev) +{ + struct sp805_wdt_priv *priv = dev_get_priv(dev); + + writel(UNLOCK, priv->reg + WDTLOCK); + writel(DISABLE, priv->reg + WDTCONTROL); + writel(LOCK, priv->reg + WDTLOCK); + readl(priv->reg + WDTLOCK); + + return 0; +} + +static int sp805_wdt_expire_now(struct udevice *dev, ulong flags) +{ + sp805_wdt_start(dev, 0, flags); + + return 0; +} + +static int sp805_wdt_probe(struct udevice *dev) +{ + debug("%s: Probing wdt%u (sp805-wdt)\n", __func__, dev_seq(dev)); + + return 0; +} + +static int sp805_wdt_of_to_plat(struct udevice *dev) +{ + struct sp805_wdt_priv *priv = dev_get_priv(dev); + struct clk clk; + + priv->reg = (void __iomem *)dev_read_addr(dev); + if (IS_ERR(priv->reg)) + return PTR_ERR(priv->reg); + + if (!clk_get_by_index(dev, 0, &clk)) + priv->clk_rate = clk_get_rate(&clk); + + return 0; +} + +static const struct wdt_ops sp805_wdt_ops = { + .start = sp805_wdt_start, + .reset = sp805_wdt_reset, + .stop = sp805_wdt_stop, + .expire_now = sp805_wdt_expire_now, +}; + +static const struct udevice_id sp805_wdt_ids[] = { + { .compatible = "arm,sp805-wdt" }, + {} +}; + +U_BOOT_DRIVER(sp805_wdt) = { + .name = "sp805_wdt", + .id = UCLASS_WDT, + .of_match = sp805_wdt_ids, + .probe = sp805_wdt_probe, + .priv_auto = sizeof(struct sp805_wdt_priv), + .of_to_plat = sp805_wdt_of_to_plat, + .ops = &sp805_wdt_ops, +}; diff --git a/roms/u-boot/drivers/watchdog/stm32mp_wdt.c b/roms/u-boot/drivers/watchdog/stm32mp_wdt.c new file mode 100644 index 000000000..4be616c1b --- /dev/null +++ b/roms/u-boot/drivers/watchdog/stm32mp_wdt.c @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * Copyright (C) 2019, STMicroelectronics - All Rights Reserved + */ + +#define LOG_CATEGORY UCLASS_WDT + +#include <common.h> +#include <clk.h> +#include <dm.h> +#include <log.h> +#include <syscon.h> +#include <wdt.h> +#include <asm/io.h> +#include <dm/device_compat.h> +#include <linux/bitops.h> +#include <linux/iopoll.h> + +/* IWDG registers */ +#define IWDG_KR 0x00 /* Key register */ +#define IWDG_PR 0x04 /* Prescaler Register */ +#define IWDG_RLR 0x08 /* ReLoad Register */ +#define IWDG_SR 0x0C /* Status Register */ + +/* IWDG_KR register bit mask */ +#define KR_KEY_RELOAD 0xAAAA /* Reload counter enable */ +#define KR_KEY_ENABLE 0xCCCC /* Peripheral enable */ +#define KR_KEY_EWA 0x5555 /* Write access enable */ + +/* IWDG_PR register bit values */ +#define PR_256 0x06 /* Prescaler set to 256 */ + +/* IWDG_RLR register values */ +#define RLR_MAX 0xFFF /* Max value supported by reload register */ + +/* IWDG_SR register bit values */ +#define SR_PVU BIT(0) /* Watchdog prescaler value update */ +#define SR_RVU BIT(1) /* Watchdog counter reload value update */ + +struct stm32mp_wdt_priv { + fdt_addr_t base; /* registers addr in physical memory */ + unsigned long wdt_clk_rate; /* Watchdog dedicated clock rate */ +}; + +static int stm32mp_wdt_reset(struct udevice *dev) +{ + struct stm32mp_wdt_priv *priv = dev_get_priv(dev); + + writel(KR_KEY_RELOAD, priv->base + IWDG_KR); + + return 0; +} + +static int stm32mp_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags) +{ + struct stm32mp_wdt_priv *priv = dev_get_priv(dev); + int reload; + u32 val; + int ret; + + /* Prescaler fixed to 256 */ + reload = timeout_ms * priv->wdt_clk_rate / 256; + if (reload > RLR_MAX + 1) + /* Force to max watchdog counter reload value */ + reload = RLR_MAX + 1; + else if (!reload) + /* Force to min watchdog counter reload value */ + reload = priv->wdt_clk_rate / 256; + + /* Set prescaler & reload registers */ + writel(KR_KEY_EWA, priv->base + IWDG_KR); + writel(PR_256, priv->base + IWDG_PR); + writel(reload - 1, priv->base + IWDG_RLR); + + /* Enable watchdog */ + writel(KR_KEY_ENABLE, priv->base + IWDG_KR); + + /* Wait for the registers to be updated */ + ret = readl_poll_timeout(priv->base + IWDG_SR, val, + val & (SR_PVU | SR_RVU), CONFIG_SYS_HZ); + + if (ret < 0) { + dev_err(dev, "Updating IWDG registers timeout"); + return -ETIMEDOUT; + } + + return 0; +} + +static int stm32mp_wdt_probe(struct udevice *dev) +{ + struct stm32mp_wdt_priv *priv = dev_get_priv(dev); + struct clk clk; + int ret; + + dev_dbg(dev, "IWDG init\n"); + + priv->base = dev_read_addr(dev); + if (priv->base == FDT_ADDR_T_NONE) + return -EINVAL; + + /* Enable clock */ + ret = clk_get_by_name(dev, "pclk", &clk); + if (ret) + return ret; + + ret = clk_enable(&clk); + if (ret) + return ret; + + /* Get LSI clock */ + ret = clk_get_by_name(dev, "lsi", &clk); + if (ret) + return ret; + + priv->wdt_clk_rate = clk_get_rate(&clk); + + dev_dbg(dev, "IWDG init done\n"); + + return 0; +} + +static const struct wdt_ops stm32mp_wdt_ops = { + .start = stm32mp_wdt_start, + .reset = stm32mp_wdt_reset, +}; + +static const struct udevice_id stm32mp_wdt_match[] = { + { .compatible = "st,stm32mp1-iwdg" }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(stm32mp_wdt) = { + .name = "stm32mp-wdt", + .id = UCLASS_WDT, + .of_match = stm32mp_wdt_match, + .priv_auto = sizeof(struct stm32mp_wdt_priv), + .probe = stm32mp_wdt_probe, + .ops = &stm32mp_wdt_ops, +}; diff --git a/roms/u-boot/drivers/watchdog/tangier_wdt.c b/roms/u-boot/drivers/watchdog/tangier_wdt.c new file mode 100644 index 000000000..bdc65597d --- /dev/null +++ b/roms/u-boot/drivers/watchdog/tangier_wdt.c @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2017 Intel Corporation + */ +#include <common.h> +#include <dm.h> +#include <log.h> +#include <wdt.h> +#include <div64.h> +#include <asm/scu.h> + +/* Hardware timeout in seconds */ +#define WDT_PRETIMEOUT 15 +#define WDT_TIMEOUT_MIN (1 + WDT_PRETIMEOUT) +#define WDT_TIMEOUT_MAX 170 + +/* + * Note, firmware chooses 90 seconds as a default timeout for watchdog on + * Intel Tangier SoC. It means that without handling it in the running code + * the reboot will happen. + */ + +enum { + SCU_WATCHDOG_START = 0, + SCU_WATCHDOG_STOP = 1, + SCU_WATCHDOG_KEEPALIVE = 2, + SCU_WATCHDOG_SET_ACTION_ON_TIMEOUT = 3, +}; + +static int tangier_wdt_reset(struct udevice *dev) +{ + scu_ipc_simple_command(IPCMSG_WATCHDOG_TIMER, SCU_WATCHDOG_KEEPALIVE); + return 0; +} + +static int tangier_wdt_stop(struct udevice *dev) +{ + return scu_ipc_simple_command(IPCMSG_WATCHDOG_TIMER, SCU_WATCHDOG_STOP); +} + +static int tangier_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags) +{ + u32 timeout_sec; + int in_size; + struct ipc_wd_start { + u32 pretimeout; + u32 timeout; + } ipc_wd_start; + + /* Calculate timeout in seconds and restrict to min and max value */ + do_div(timeout_ms, 1000); + timeout_sec = clamp_t(u32, timeout_ms, WDT_TIMEOUT_MIN, WDT_TIMEOUT_MAX); + + /* Update values in the IPC request */ + ipc_wd_start.pretimeout = timeout_sec - WDT_PRETIMEOUT; + ipc_wd_start.timeout = timeout_sec; + + /* + * SCU expects the input size for watchdog IPC + * to be based on 4 bytes + */ + in_size = DIV_ROUND_UP(sizeof(ipc_wd_start), 4); + + scu_ipc_command(IPCMSG_WATCHDOG_TIMER, SCU_WATCHDOG_START, + (u32 *)&ipc_wd_start, in_size, NULL, 0); + + return 0; +} + +static const struct wdt_ops tangier_wdt_ops = { + .reset = tangier_wdt_reset, + .start = tangier_wdt_start, + .stop = tangier_wdt_stop, +}; + +static const struct udevice_id tangier_wdt_ids[] = { + { .compatible = "intel,tangier-wdt" }, + { /* sentinel */ } +}; + +static int tangier_wdt_probe(struct udevice *dev) +{ + debug("%s: Probing wdt%u\n", __func__, dev_seq(dev)); + return 0; +} + +U_BOOT_DRIVER(wdt_tangier) = { + .name = "wdt_tangier", + .id = UCLASS_WDT, + .of_match = tangier_wdt_ids, + .ops = &tangier_wdt_ops, + .probe = tangier_wdt_probe, +}; diff --git a/roms/u-boot/drivers/watchdog/ulp_wdog.c b/roms/u-boot/drivers/watchdog/ulp_wdog.c new file mode 100644 index 000000000..6f63b11b9 --- /dev/null +++ b/roms/u-boot/drivers/watchdog/ulp_wdog.c @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. + */ + +#include <common.h> +#include <cpu_func.h> +#include <asm/io.h> +#include <asm/arch/imx-regs.h> + +/* + * MX7ULP WDOG Register Map + */ +struct wdog_regs { + u8 cs1; + u8 cs2; + u16 reserve0; + u32 cnt; + u32 toval; + u32 win; +}; + +#ifndef CONFIG_WATCHDOG_TIMEOUT_MSECS +#define CONFIG_WATCHDOG_TIMEOUT_MSECS 0x1500 +#endif + +#define REFRESH_WORD0 0xA602 /* 1st refresh word */ +#define REFRESH_WORD1 0xB480 /* 2nd refresh word */ + +#define UNLOCK_WORD0 0xC520 /* 1st unlock word */ +#define UNLOCK_WORD1 0xD928 /* 2nd unlock word */ + +#define WDGCS1_WDGE (1<<7) +#define WDGCS1_WDGUPDATE (1<<5) + +#define WDGCS2_FLG (1<<6) + +#define WDG_BUS_CLK (0x0) +#define WDG_LPO_CLK (0x1) +#define WDG_32KHZ_CLK (0x2) +#define WDG_EXT_CLK (0x3) + +void hw_watchdog_set_timeout(u16 val) +{ + /* setting timeout value */ + struct wdog_regs *wdog = (struct wdog_regs *)WDOG_BASE_ADDR; + + writel(val, &wdog->toval); +} + +void hw_watchdog_reset(void) +{ + struct wdog_regs *wdog = (struct wdog_regs *)WDOG_BASE_ADDR; + + writel(REFRESH_WORD0, &wdog->cnt); + writel(REFRESH_WORD1, &wdog->cnt); +} + +void hw_watchdog_init(void) +{ + u8 val; + struct wdog_regs *wdog = (struct wdog_regs *)WDOG_BASE_ADDR; + + writel(UNLOCK_WORD0, &wdog->cnt); + writel(UNLOCK_WORD1, &wdog->cnt); + + val = readb(&wdog->cs2); + val |= WDGCS2_FLG; + writeb(val, &wdog->cs2); + + hw_watchdog_set_timeout(CONFIG_WATCHDOG_TIMEOUT_MSECS); + writel(0, &wdog->win); + + writeb(WDG_LPO_CLK, &wdog->cs2);/* setting 1-kHz clock source */ + writeb((WDGCS1_WDGE | WDGCS1_WDGUPDATE), &wdog->cs1);/* enable counter running */ + + hw_watchdog_reset(); +} + +void reset_cpu(void) +{ + struct wdog_regs *wdog = (struct wdog_regs *)WDOG_BASE_ADDR; + + writel(UNLOCK_WORD0, &wdog->cnt); + writel(UNLOCK_WORD1, &wdog->cnt); + + hw_watchdog_set_timeout(5); /* 5ms timeout */ + writel(0, &wdog->win); + + writeb(WDG_LPO_CLK, &wdog->cs2);/* setting 1-kHz clock source */ + writeb(WDGCS1_WDGE, &wdog->cs1);/* enable counter running */ + + hw_watchdog_reset(); + + while (1); +} diff --git a/roms/u-boot/drivers/watchdog/wdt-uclass.c b/roms/u-boot/drivers/watchdog/wdt-uclass.c new file mode 100644 index 000000000..268713529 --- /dev/null +++ b/roms/u-boot/drivers/watchdog/wdt-uclass.c @@ -0,0 +1,185 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2017 Google, Inc + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <hang.h> +#include <log.h> +#include <time.h> +#include <wdt.h> +#include <asm/global_data.h> +#include <dm/device-internal.h> +#include <dm/lists.h> + +DECLARE_GLOBAL_DATA_PTR; + +#define WATCHDOG_TIMEOUT_SECS (CONFIG_WATCHDOG_TIMEOUT_MSECS / 1000) + +/* + * Reset every 1000ms, or however often is required as indicated by a + * hw_margin_ms property. + */ +static ulong reset_period = 1000; + +int initr_watchdog(void) +{ + u32 timeout = WATCHDOG_TIMEOUT_SECS; + int ret; + + /* + * Init watchdog: This will call the probe function of the + * watchdog driver, enabling the use of the device + */ + if (uclass_get_device_by_seq(UCLASS_WDT, 0, + (struct udevice **)&gd->watchdog_dev)) { + debug("WDT: Not found by seq!\n"); + if (uclass_get_device(UCLASS_WDT, 0, + (struct udevice **)&gd->watchdog_dev)) { + printf("WDT: Not found!\n"); + return 0; + } + } + + if (CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)) { + timeout = dev_read_u32_default(gd->watchdog_dev, "timeout-sec", + WATCHDOG_TIMEOUT_SECS); + reset_period = dev_read_u32_default(gd->watchdog_dev, + "hw_margin_ms", + 4 * reset_period) / 4; + } + + if (!CONFIG_IS_ENABLED(WATCHDOG_AUTOSTART)) { + printf("WDT: Not starting\n"); + return 0; + } + + ret = wdt_start(gd->watchdog_dev, timeout * 1000, 0); + if (ret != 0) { + printf("WDT: Failed to start\n"); + return 0; + } + + printf("WDT: Started with%s servicing (%ds timeout)\n", + IS_ENABLED(CONFIG_WATCHDOG) ? "" : "out", timeout); + + return 0; +} + +int wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags) +{ + const struct wdt_ops *ops = device_get_ops(dev); + int ret; + + if (!ops->start) + return -ENOSYS; + + ret = ops->start(dev, timeout_ms, flags); + if (ret == 0) + gd->flags |= GD_FLG_WDT_READY; + + return ret; +} + +int wdt_stop(struct udevice *dev) +{ + const struct wdt_ops *ops = device_get_ops(dev); + int ret; + + if (!ops->stop) + return -ENOSYS; + + ret = ops->stop(dev); + if (ret == 0) + gd->flags &= ~GD_FLG_WDT_READY; + + return ret; +} + +int wdt_reset(struct udevice *dev) +{ + const struct wdt_ops *ops = device_get_ops(dev); + + if (!ops->reset) + return -ENOSYS; + + return ops->reset(dev); +} + +int wdt_expire_now(struct udevice *dev, ulong flags) +{ + int ret = 0; + const struct wdt_ops *ops; + + debug("WDT Resetting: %lu\n", flags); + ops = device_get_ops(dev); + if (ops->expire_now) { + return ops->expire_now(dev, flags); + } else { + if (!ops->start) + return -ENOSYS; + + ret = ops->start(dev, 1, flags); + if (ret < 0) + return ret; + + hang(); + } + + return ret; +} + +#if defined(CONFIG_WATCHDOG) +/* + * Called by macro WATCHDOG_RESET. This function be called *very* early, + * so we need to make sure, that the watchdog driver is ready before using + * it in this function. + */ +void watchdog_reset(void) +{ + static ulong next_reset; + ulong now; + + /* Exit if GD is not ready or watchdog is not initialized yet */ + if (!gd || !(gd->flags & GD_FLG_WDT_READY)) + return; + + /* Do not reset the watchdog too often */ + now = get_timer(0); + if (time_after_eq(now, next_reset)) { + next_reset = now + reset_period; + wdt_reset(gd->watchdog_dev); + } +} +#endif + +static int wdt_post_bind(struct udevice *dev) +{ +#if defined(CONFIG_NEEDS_MANUAL_RELOC) + struct wdt_ops *ops = (struct wdt_ops *)device_get_ops(dev); + static int reloc_done; + + if (!reloc_done) { + if (ops->start) + ops->start += gd->reloc_off; + if (ops->stop) + ops->stop += gd->reloc_off; + if (ops->reset) + ops->reset += gd->reloc_off; + if (ops->expire_now) + ops->expire_now += gd->reloc_off; + + reloc_done++; + } +#endif + return 0; +} + +UCLASS_DRIVER(wdt) = { + .id = UCLASS_WDT, + .name = "watchdog", + .flags = DM_UC_FLAG_SEQ_ALIAS, + .post_bind = wdt_post_bind, +}; diff --git a/roms/u-boot/drivers/watchdog/xilinx_tb_wdt.c b/roms/u-boot/drivers/watchdog/xilinx_tb_wdt.c new file mode 100644 index 000000000..1687a4599 --- /dev/null +++ b/roms/u-boot/drivers/watchdog/xilinx_tb_wdt.c @@ -0,0 +1,129 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Xilinx AXI platforms watchdog timer driver. + * + * Author(s): Michal Simek <michal.simek@xilinx.com> + * Shreenidhi Shedi <yesshedi@gmail.com> + * + * Copyright (c) 2011-2018 Xilinx Inc. + */ + +#include <common.h> +#include <dm.h> +#include <log.h> +#include <wdt.h> +#include <linux/err.h> +#include <linux/io.h> + +#define XWT_CSR0_WRS_MASK 0x00000008 /* Reset status Mask */ +#define XWT_CSR0_WDS_MASK 0x00000004 /* Timer state Mask */ +#define XWT_CSR0_EWDT1_MASK 0x00000002 /* Enable bit 1 Mask*/ +#define XWT_CSRX_EWDT2_MASK 0x00000001 /* Enable bit 2 Mask */ + +struct watchdog_regs { + u32 twcsr0; /* 0x0 */ + u32 twcsr1; /* 0x4 */ + u32 tbr; /* 0x8 */ +}; + +struct xlnx_wdt_plat { + bool enable_once; + struct watchdog_regs *regs; +}; + +static int xlnx_wdt_reset(struct udevice *dev) +{ + u32 reg; + struct xlnx_wdt_plat *plat = dev_get_plat(dev); + + debug("%s ", __func__); + + /* Read the current contents of TCSR0 */ + reg = readl(&plat->regs->twcsr0); + + /* Clear the watchdog WDS bit */ + if (reg & (XWT_CSR0_EWDT1_MASK | XWT_CSRX_EWDT2_MASK)) + writel(reg | XWT_CSR0_WDS_MASK, &plat->regs->twcsr0); + + return 0; +} + +static int xlnx_wdt_stop(struct udevice *dev) +{ + u32 reg; + struct xlnx_wdt_plat *plat = dev_get_plat(dev); + + if (plat->enable_once) { + debug("Can't stop Xilinx watchdog.\n"); + return -EBUSY; + } + + /* Read the current contents of TCSR0 */ + reg = readl(&plat->regs->twcsr0); + + writel(reg & ~XWT_CSR0_EWDT1_MASK, &plat->regs->twcsr0); + writel(~XWT_CSRX_EWDT2_MASK, &plat->regs->twcsr1); + + debug("Watchdog disabled!\n"); + + return 0; +} + +static int xlnx_wdt_start(struct udevice *dev, u64 timeout, ulong flags) +{ + struct xlnx_wdt_plat *plat = dev_get_plat(dev); + + debug("%s:\n", __func__); + + writel((XWT_CSR0_WRS_MASK | XWT_CSR0_WDS_MASK | XWT_CSR0_EWDT1_MASK), + &plat->regs->twcsr0); + + writel(XWT_CSRX_EWDT2_MASK, &plat->regs->twcsr1); + + return 0; +} + +static int xlnx_wdt_probe(struct udevice *dev) +{ + debug("%s: Probing wdt%u\n", __func__, dev_seq(dev)); + + return 0; +} + +static int xlnx_wdt_of_to_plat(struct udevice *dev) +{ + struct xlnx_wdt_plat *plat = dev_get_plat(dev); + + plat->regs = (struct watchdog_regs *)dev_read_addr(dev); + if (IS_ERR(plat->regs)) + return PTR_ERR(plat->regs); + + plat->enable_once = dev_read_u32_default(dev, "xlnx,wdt-enable-once", + 0); + + debug("%s: wdt-enable-once %d\n", __func__, plat->enable_once); + + return 0; +} + +static const struct wdt_ops xlnx_wdt_ops = { + .start = xlnx_wdt_start, + .reset = xlnx_wdt_reset, + .stop = xlnx_wdt_stop, +}; + +static const struct udevice_id xlnx_wdt_ids[] = { + { .compatible = "xlnx,xps-timebase-wdt-1.00.a", }, + { .compatible = "xlnx,xps-timebase-wdt-1.01.a", }, + {}, +}; + +U_BOOT_DRIVER(xlnx_wdt) = { + .name = "xlnx_wdt", + .id = UCLASS_WDT, + .of_match = xlnx_wdt_ids, + .probe = xlnx_wdt_probe, + .plat_auto = sizeof(struct xlnx_wdt_plat), + .of_to_plat = xlnx_wdt_of_to_plat, + .ops = &xlnx_wdt_ops, +}; diff --git a/roms/u-boot/drivers/watchdog/xilinx_wwdt.c b/roms/u-boot/drivers/watchdog/xilinx_wwdt.c new file mode 100644 index 000000000..11b30ae85 --- /dev/null +++ b/roms/u-boot/drivers/watchdog/xilinx_wwdt.c @@ -0,0 +1,178 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Xilinx window watchdog timer driver. + * + * Author(s): Michal Simek <michal.simek@xilinx.com> + * Ashok Reddy Soma <ashokred@xilinx.com> + * + * Copyright (c) 2020, Xilinx Inc. + */ + +#include <clk.h> +#include <common.h> +#include <dm.h> +#include <regmap.h> +#include <wdt.h> +#include <linux/compat.h> +#include <linux/io.h> + +/* Refresh Register Masks */ +#define XWT_WWREF_GWRR_MASK BIT(0) /* Refresh and start new period */ + +/* Generic Control/Status Register Masks */ +#define XWT_WWCSR_GWEN_MASK BIT(0) /* Enable Bit */ + +/* Register offsets for the Wdt device */ +#define XWT_WWREF_OFFSET 0x1000 /* Refresh Register */ +#define XWT_WWCSR_OFFSET 0x2000 /* Control/Status Register */ +#define XWT_WWOFF_OFFSET 0x2008 /* Offset Register */ +#define XWT_WWCMP0_OFFSET 0x2010 /* Compare Value Register0 */ +#define XWT_WWCMP1_OFFSET 0x2014 /* Compare Value Register1 */ +#define XWT_WWWRST_OFFSET 0x2FD0 /* Warm Reset Register */ + +struct xlnx_wwdt_priv { + bool enable_once; + struct regmap *regs; + struct clk clk; +}; + +struct xlnx_wwdt_plat { + bool enable_once; +}; + +static int xlnx_wwdt_reset(struct udevice *dev) +{ + struct xlnx_wwdt_priv *wdt = dev_get_priv(dev); + + regmap_write(wdt->regs, XWT_WWREF_OFFSET, XWT_WWREF_GWRR_MASK); + + return 0; +} + +static int xlnx_wwdt_stop(struct udevice *dev) +{ + u32 csr; + struct xlnx_wwdt_priv *wdt = dev_get_priv(dev); + + if (wdt->enable_once) { + dev_warn(dev, "Can't stop Xilinx watchdog.\n"); + return -EBUSY; + } + + /* Disable the generic watchdog timer */ + regmap_read(wdt->regs, XWT_WWCSR_OFFSET, &csr); + csr &= ~(XWT_WWCSR_GWEN_MASK); + regmap_write(wdt->regs, XWT_WWCSR_OFFSET, csr); + + clk_disable(&wdt->clk); + + dev_dbg(dev, "Watchdog disabled!\n"); + + return 0; +} + +static int xlnx_wwdt_start(struct udevice *dev, u64 timeout, ulong flags) +{ + int ret; + u32 csr; + u64 count; + unsigned long clock_f; + struct xlnx_wwdt_priv *wdt = dev_get_priv(dev); + + clock_f = clk_get_rate(&wdt->clk); + if (IS_ERR_VALUE(clock_f)) { + dev_err(dev, "failed to get rate\n"); + return clock_f; + } + + dev_dbg(dev, "%s: CLK %ld\n", __func__, clock_f); + + /* Calculate timeout count */ + count = timeout * clock_f; + + ret = clk_enable(&wdt->clk); + if (ret) { + dev_err(dev, "failed to enable clock\n"); + return ret; + } + + /* + * Timeout count is half as there are two windows + * first window overflow is ignored (interrupt), + * reset is only generated at second window overflow + */ + count = count >> 1; + + /* Disable the generic watchdog timer */ + regmap_read(wdt->regs, XWT_WWCSR_OFFSET, &csr); + csr &= ~(XWT_WWCSR_GWEN_MASK); + regmap_write(wdt->regs, XWT_WWCSR_OFFSET, csr); + + /* Set compare and offset registers for generic watchdog timeout */ + regmap_write(wdt->regs, XWT_WWCMP0_OFFSET, (u32)count); + regmap_write(wdt->regs, XWT_WWCMP1_OFFSET, 0); + regmap_write(wdt->regs, XWT_WWOFF_OFFSET, (u32)count); + + /* Enable the generic watchdog timer */ + regmap_read(wdt->regs, XWT_WWCSR_OFFSET, &csr); + csr |= (XWT_WWCSR_GWEN_MASK); + regmap_write(wdt->regs, XWT_WWCSR_OFFSET, csr); + + return 0; +} + +static int xlnx_wwdt_probe(struct udevice *dev) +{ + int ret; + struct xlnx_wwdt_plat *plat = dev_get_plat(dev); + struct xlnx_wwdt_priv *wdt = dev_get_priv(dev); + + dev_dbg(dev, "%s: Probing wdt%u\n", __func__, dev_seq(dev)); + + ret = regmap_init_mem(dev_ofnode(dev), &wdt->regs); + if (ret) { + dev_dbg(dev, "failed to get regbase of wwdt\n"); + return ret; + } + + wdt->enable_once = plat->enable_once; + + ret = clk_get_by_index(dev, 0, &wdt->clk); + if (ret < 0) + dev_err(dev, "failed to get clock\n"); + + return ret; +} + +static int xlnx_wwdt_of_to_plat(struct udevice *dev) +{ + struct xlnx_wwdt_plat *plat = dev_get_plat(dev); + + plat->enable_once = dev_read_u32_default(dev, "xlnx,wdt-enable-once", + 0); + dev_dbg(dev, "wdt-enable-once %d\n", plat->enable_once); + + return 0; +} + +static const struct wdt_ops xlnx_wwdt_ops = { + .start = xlnx_wwdt_start, + .reset = xlnx_wwdt_reset, + .stop = xlnx_wwdt_stop, +}; + +static const struct udevice_id xlnx_wwdt_ids[] = { + { .compatible = "xlnx,versal-wwdt-1.0", }, + {}, +}; + +U_BOOT_DRIVER(xlnx_wwdt) = { + .name = "xlnx_wwdt", + .id = UCLASS_WDT, + .of_match = xlnx_wwdt_ids, + .probe = xlnx_wwdt_probe, + .priv_auto = sizeof(struct xlnx_wwdt_priv), + .plat_auto = sizeof(struct xlnx_wwdt_plat), + .of_to_plat = xlnx_wwdt_of_to_plat, + .ops = &xlnx_wwdt_ops, +}; |