GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)
This commit is contained in:
@@ -0,0 +1,186 @@
|
||||
menu "Watchdog Timer Support"
|
||||
|
||||
config WATCHDOG
|
||||
bool "Enable U-Boot watchdog reset"
|
||||
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_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 WATCHDOG_RESET_DISABLE
|
||||
bool "Disable reset watchdog"
|
||||
help
|
||||
Disable reset watchdog, which can let WATCHDOG_RESET invalid, so
|
||||
that the watchdog will not be fed in u-boot.
|
||||
|
||||
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 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 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_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_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_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_MPC8xx
|
||||
bool "MPC8xx watchdog timer support"
|
||||
depends on WDT && MPC8xx
|
||||
select CONFIG_MPC8xx_WATCHDOG
|
||||
help
|
||||
Select this to enable mpc8xx watchdog timer
|
||||
|
||||
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_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_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_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_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
|
||||
@@ -0,0 +1,31 @@
|
||||
# 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_BCM6345) += bcm6345_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_MT7621) += mt7621_wdt.o
|
||||
obj-$(CONFIG_WDT_MTK) += mtk_wdt.o
|
||||
obj-$(CONFIG_WDT_OMAP3) += omap_wdt.o
|
||||
obj-$(CONFIG_WDT_SP805) += sp805_wdt.o
|
||||
obj-$(CONFIG_WDT_STM32MP) += stm32mp_wdt.o
|
||||
obj-$(CONFIG_WDT_TANGIER) += tangier_wdt.o
|
||||
@@ -0,0 +1,200 @@
|
||||
// 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/io.h>
|
||||
#include <asm/arch/cpu.h>
|
||||
#include <asm/arch/soc.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_alloc_size = sizeof(struct a37xx_wdt),
|
||||
.ops = &a37xx_wdt_ops,
|
||||
};
|
||||
@@ -0,0 +1,128 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2017 Google, Inc
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <wdt.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/wdt.h>
|
||||
|
||||
#define WDT_AST2500 2500
|
||||
#define WDT_AST2400 2400
|
||||
|
||||
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_ofdata_to_platdata(struct udevice *dev)
|
||||
{
|
||||
struct ast_wdt_priv *priv = dev_get_priv(dev);
|
||||
|
||||
priv->regs = devfdt_get_addr_ptr(dev);
|
||||
if (IS_ERR(priv->regs))
|
||||
return PTR_ERR(priv->regs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct wdt_ops ast_wdt_ops = {
|
||||
.start = ast_wdt_start,
|
||||
.reset = ast_wdt_reset,
|
||||
.stop = ast_wdt_stop,
|
||||
.expire_now = ast_wdt_expire_now,
|
||||
};
|
||||
|
||||
static const struct udevice_id ast_wdt_ids[] = {
|
||||
{ .compatible = "aspeed,wdt", .data = WDT_AST2500 },
|
||||
{ .compatible = "aspeed,ast2500-wdt", .data = WDT_AST2500 },
|
||||
{ .compatible = "aspeed,ast2400-wdt", .data = WDT_AST2400 },
|
||||
{}
|
||||
};
|
||||
|
||||
static int ast_wdt_probe(struct udevice *dev)
|
||||
{
|
||||
debug("%s() wdt%u\n", __func__, dev->seq);
|
||||
ast_wdt_stop(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
U_BOOT_DRIVER(ast_wdt) = {
|
||||
.name = "ast_wdt",
|
||||
.id = UCLASS_WDT,
|
||||
.of_match = ast_wdt_ids,
|
||||
.probe = ast_wdt_probe,
|
||||
.priv_auto_alloc_size = sizeof(struct ast_wdt_priv),
|
||||
.ofdata_to_platdata = ast_wdt_ofdata_to_platdata,
|
||||
.ops = &ast_wdt_ops,
|
||||
};
|
||||
@@ -0,0 +1,122 @@
|
||||
// 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 <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);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
U_BOOT_DRIVER(at91_wdt) = {
|
||||
.name = "at91_wdt",
|
||||
.id = UCLASS_WDT,
|
||||
.of_match = at91_wdt_ids,
|
||||
.priv_auto_alloc_size = sizeof(struct at91_wdt_priv),
|
||||
.ops = &at91_wdt_ops,
|
||||
.probe = at91_wdt_probe,
|
||||
};
|
||||
@@ -0,0 +1,116 @@
|
||||
// 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 <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_alloc_size = sizeof(struct bcm6345_wdt_priv),
|
||||
.probe = bcm6345_wdt_probe,
|
||||
};
|
||||
@@ -0,0 +1,265 @@
|
||||
// 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 <wdt.h>
|
||||
#include <clk.h>
|
||||
#include <div64.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
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);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cdns_wdt_ofdata_to_platdata(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_alloc_size = sizeof(struct cdns_wdt_priv),
|
||||
.ofdata_to_platdata = cdns_wdt_ofdata_to_platdata,
|
||||
.ops = &cdns_wdt_ops,
|
||||
};
|
||||
@@ -0,0 +1,73 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2013 Altera Corporation <www.altera.com>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <watchdog.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/utils.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_CR_RMOD_VAL 0x00
|
||||
#define DW_WDT_CRR_RESTART_VAL 0x76
|
||||
|
||||
/*
|
||||
* Set the watchdog time interval.
|
||||
* Counter is 32 bit.
|
||||
*/
|
||||
static int designware_wdt_settimeout(unsigned int timeout)
|
||||
{
|
||||
signed int i;
|
||||
|
||||
/* calculate the timeout range value */
|
||||
i = (log_2_n_round_up(timeout * CONFIG_DW_WDT_CLOCK_KHZ)) - 16;
|
||||
if (i > 15)
|
||||
i = 15;
|
||||
if (i < 0)
|
||||
i = 0;
|
||||
|
||||
writel((i | (i << 4)), (CONFIG_DW_WDT_BASE + DW_WDT_TORR));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void designware_wdt_enable(void)
|
||||
{
|
||||
writel(((DW_WDT_CR_RMOD_VAL << DW_WDT_CR_RMOD_OFFSET) |
|
||||
(0x1 << DW_WDT_CR_EN_OFFSET)),
|
||||
(CONFIG_DW_WDT_BASE + DW_WDT_CR));
|
||||
}
|
||||
|
||||
static unsigned int designware_wdt_is_enabled(void)
|
||||
{
|
||||
unsigned long val;
|
||||
val = readl((CONFIG_DW_WDT_BASE + DW_WDT_CR));
|
||||
return val & 0x1;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_HW_WATCHDOG)
|
||||
void hw_watchdog_reset(void)
|
||||
{
|
||||
if (designware_wdt_is_enabled())
|
||||
/* restart the watchdog counter */
|
||||
writel(DW_WDT_CRR_RESTART_VAL,
|
||||
(CONFIG_DW_WDT_BASE + DW_WDT_CRR));
|
||||
}
|
||||
|
||||
void hw_watchdog_init(void)
|
||||
{
|
||||
/* reset to disable the watchdog */
|
||||
hw_watchdog_reset();
|
||||
/* set timer in miliseconds */
|
||||
designware_wdt_settimeout(CONFIG_WATCHDOG_TIMEOUT_MSECS);
|
||||
/* enable the watchdog */
|
||||
designware_wdt_enable();
|
||||
/* reset the watchdog */
|
||||
hw_watchdog_reset();
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,91 @@
|
||||
// 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 <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
|
||||
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* watchdog.c - driver for i.mx on-chip watchdog
|
||||
*
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.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>
|
||||
|
||||
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(ulong addr)
|
||||
{
|
||||
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)
|
||||
{
|
||||
u16 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 = (CONFIG_WATCHDOG_TIMEOUT_MSECS / 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);
|
||||
}
|
||||
#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);
|
||||
|
||||
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_alloc_size = sizeof(struct imx_wdt_priv),
|
||||
.flags = DM_FLAG_PRE_RELOC,
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,67 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2017 CS Systemes d'Information
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <wdt.h>
|
||||
#include <mpc8xx.h>
|
||||
#include <asm/cpm_8xx.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
static 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;
|
||||
|
||||
out_be32(&immap->im_siu_conf.sc_sypcr, CONFIG_SYS_SYPCR);
|
||||
|
||||
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,
|
||||
};
|
||||
@@ -0,0 +1,102 @@
|
||||
// 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 <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_alloc_size = sizeof(struct mt762x_wdt),
|
||||
.ops = &mt762x_wdt_ops,
|
||||
};
|
||||
@@ -0,0 +1,156 @@
|
||||
// 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 <wdt.h>
|
||||
#include <asm/io.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"},
|
||||
{}
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(mtk_wdt) = {
|
||||
.name = "mtk_wdt",
|
||||
.id = UCLASS_WDT,
|
||||
.of_match = mtk_wdt_ids,
|
||||
.priv_auto_alloc_size = sizeof(struct mtk_wdt_priv),
|
||||
.probe = mtk_wdt_probe,
|
||||
.ops = &mtk_wdt_ops,
|
||||
.flags = DM_FLAG_PRE_RELOC,
|
||||
};
|
||||
@@ -0,0 +1,257 @@
|
||||
// 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 <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);
|
||||
/*
|
||||
* 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)
|
||||
;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int omap3_wdt_probe(struct udevice *dev)
|
||||
{
|
||||
struct omap3_wdt_priv *priv = dev_get_priv(dev);
|
||||
|
||||
priv->regs = (struct wd_timer *)devfdt_get_addr(dev);
|
||||
if (!priv->regs)
|
||||
return -EINVAL;
|
||||
|
||||
priv->wdt_trgr_pattern = 0x1234;
|
||||
debug("%s: Probing wdt%u\n", __func__, dev->seq);
|
||||
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_alloc_size = sizeof(struct omap3_wdt_priv),
|
||||
};
|
||||
#endif /* !CONFIG_IS_ENABLED(WDT) */
|
||||
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
* 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 <wdt.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_ofdata_to_platdata(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);
|
||||
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_alloc_size = sizeof(struct orion_wdt_priv),
|
||||
.ofdata_to_platdata = orion_wdt_ofdata_to_platdata,
|
||||
.ops = &orion_wdt_ops,
|
||||
};
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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,
|
||||
};
|
||||
@@ -0,0 +1,156 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Watchdog driver for SP805 on some Layerscape SoC
|
||||
*
|
||||
* Copyright 2019 NXP
|
||||
*/
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <common.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/math64.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)
|
||||
#define WATCHDOG_BASE 0x12030000
|
||||
#define WDT_CLK_RATE 24000000
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
struct sp805_wdt_priv {
|
||||
unsigned long base;
|
||||
void __iomem *reg;
|
||||
};
|
||||
|
||||
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;
|
||||
unsigned long clk_rate;
|
||||
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) {
|
||||
clk_rate = WDT_CLK_RATE;
|
||||
load_value = div_u64(clk_rate, 2) * load_time / 1000 - 1;
|
||||
}
|
||||
else{
|
||||
load_value = (gd->bus_clk) /
|
||||
(2 * 1000 * SYS_FSL_WDT_CLK_DIV) * load_time;
|
||||
}
|
||||
|
||||
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);
|
||||
struct sp805_wdt_priv *priv = dev_get_priv(dev);
|
||||
|
||||
priv->base = WATCHDOG_BASE;
|
||||
if (!priv->reg) {
|
||||
priv->reg = (void __iomem *)priv->base;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sp805_wdt_ofdata_to_platdata(struct udevice *dev)
|
||||
{
|
||||
struct sp805_wdt_priv *priv = dev_get_priv(dev);
|
||||
|
||||
priv->reg = (void __iomem *)dev_read_addr(dev);
|
||||
if (IS_ERR(priv->reg))
|
||||
return PTR_ERR(priv->reg);
|
||||
|
||||
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_alloc_size = sizeof(struct sp805_wdt_priv),
|
||||
.ofdata_to_platdata = sp805_wdt_ofdata_to_platdata,
|
||||
.ops = &sp805_wdt_ops,
|
||||
};
|
||||
|
||||
U_BOOT_DEVICE(sp805_wdt) = {
|
||||
.name = "sp805_wdt",
|
||||
};
|
||||
@@ -0,0 +1,135 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright (C) 2019, STMicroelectronics - All Rights Reserved
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <clk.h>
|
||||
#include <dm.h>
|
||||
#include <syscon.h>
|
||||
#include <wdt.h>
|
||||
#include <asm/io.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) {
|
||||
pr_err("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;
|
||||
|
||||
debug("IWDG init\n");
|
||||
|
||||
priv->base = devfdt_get_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);
|
||||
|
||||
debug("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_alloc_size = sizeof(struct stm32mp_wdt_priv),
|
||||
.probe = stm32mp_wdt_probe,
|
||||
.ops = &stm32mp_wdt_ops,
|
||||
};
|
||||
@@ -0,0 +1,92 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (c) 2017 Intel Corporation
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <dm.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);
|
||||
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,
|
||||
};
|
||||
@@ -0,0 +1,95 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2016 Freescale Semiconductor, Inc.
|
||||
*/
|
||||
|
||||
#include <common.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(ulong addr)
|
||||
{
|
||||
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);
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2017 Google, Inc
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <wdt.h>
|
||||
#include <dm/device-internal.h>
|
||||
#include <dm/lists.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
int wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
|
||||
{
|
||||
const struct wdt_ops *ops = device_get_ops(dev);
|
||||
|
||||
if (!ops->start)
|
||||
return -ENOSYS;
|
||||
|
||||
return ops->start(dev, timeout_ms, flags);
|
||||
}
|
||||
|
||||
int wdt_stop(struct udevice *dev)
|
||||
{
|
||||
const struct wdt_ops *ops = device_get_ops(dev);
|
||||
|
||||
if (!ops->stop)
|
||||
return -ENOSYS;
|
||||
|
||||
return ops->stop(dev);
|
||||
}
|
||||
|
||||
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 (now > next_reset) {
|
||||
next_reset = now + 1000; /* reset every 1000ms */
|
||||
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,
|
||||
};
|
||||
@@ -0,0 +1,127 @@
|
||||
// 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 <wdt.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_platdata {
|
||||
bool enable_once;
|
||||
struct watchdog_regs *regs;
|
||||
};
|
||||
|
||||
static int xlnx_wdt_reset(struct udevice *dev)
|
||||
{
|
||||
u32 reg;
|
||||
struct xlnx_wdt_platdata *platdata = dev_get_platdata(dev);
|
||||
|
||||
debug("%s ", __func__);
|
||||
|
||||
/* Read the current contents of TCSR0 */
|
||||
reg = readl(&platdata->regs->twcsr0);
|
||||
|
||||
/* Clear the watchdog WDS bit */
|
||||
if (reg & (XWT_CSR0_EWDT1_MASK | XWT_CSRX_EWDT2_MASK))
|
||||
writel(reg | XWT_CSR0_WDS_MASK, &platdata->regs->twcsr0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xlnx_wdt_stop(struct udevice *dev)
|
||||
{
|
||||
u32 reg;
|
||||
struct xlnx_wdt_platdata *platdata = dev_get_platdata(dev);
|
||||
|
||||
if (platdata->enable_once) {
|
||||
debug("Can't stop Xilinx watchdog.\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* Read the current contents of TCSR0 */
|
||||
reg = readl(&platdata->regs->twcsr0);
|
||||
|
||||
writel(reg & ~XWT_CSR0_EWDT1_MASK, &platdata->regs->twcsr0);
|
||||
writel(~XWT_CSRX_EWDT2_MASK, &platdata->regs->twcsr1);
|
||||
|
||||
debug("Watchdog disabled!\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xlnx_wdt_start(struct udevice *dev, u64 timeout, ulong flags)
|
||||
{
|
||||
struct xlnx_wdt_platdata *platdata = dev_get_platdata(dev);
|
||||
|
||||
debug("%s:\n", __func__);
|
||||
|
||||
writel((XWT_CSR0_WRS_MASK | XWT_CSR0_WDS_MASK | XWT_CSR0_EWDT1_MASK),
|
||||
&platdata->regs->twcsr0);
|
||||
|
||||
writel(XWT_CSRX_EWDT2_MASK, &platdata->regs->twcsr1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xlnx_wdt_probe(struct udevice *dev)
|
||||
{
|
||||
debug("%s: Probing wdt%u\n", __func__, dev->seq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xlnx_wdt_ofdata_to_platdata(struct udevice *dev)
|
||||
{
|
||||
struct xlnx_wdt_platdata *platdata = dev_get_platdata(dev);
|
||||
|
||||
platdata->regs = (struct watchdog_regs *)dev_read_addr(dev);
|
||||
if (IS_ERR(platdata->regs))
|
||||
return PTR_ERR(platdata->regs);
|
||||
|
||||
platdata->enable_once = dev_read_u32_default(dev,
|
||||
"xlnx,wdt-enable-once", 0);
|
||||
|
||||
debug("%s: wdt-enable-once %d\n", __func__, platdata->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,
|
||||
.platdata_auto_alloc_size = sizeof(struct xlnx_wdt_platdata),
|
||||
.ofdata_to_platdata = xlnx_wdt_ofdata_to_platdata,
|
||||
.ops = &xlnx_wdt_ops,
|
||||
};
|
||||
Reference in New Issue
Block a user