
This watchdog can be found on some Armada chips.
Signed-off-by: Marek Behun marek.behun@nic.cz --- drivers/watchdog/Kconfig | 7 +++ drivers/watchdog/Makefile | 1 + drivers/watchdog/orion_wdt.c | 128 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 136 insertions(+) create mode 100644 drivers/watchdog/orion_wdt.c
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index bdaf5d4..c2df88f 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -12,6 +12,13 @@ config BCM2835_WDT This provides basic infrastructure to support BCM2835/2836 watchdog hardware, with a max timeout of ~15secs.
+config ORION_WATCHDOG + bool "Enable " + select HW_WATCHDOG + help + Say Y here to enable the Orion watchdog, which can be found on some + Marvell Armada chips. + config ULP_WATCHDOG bool "i.MX7ULP watchdog" help diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 8378601..7df33f0 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -19,3 +19,4 @@ obj-$(CONFIG_WDT) += wdt-uclass.o obj-$(CONFIG_WDT_SANDBOX) += sandbox_wdt.o obj-$(CONFIG_WDT_ASPEED) += ast_wdt.o obj-$(CONFIG_BCM2835_WDT) += bcm2835_wdt.o +obj-$(CONFIG_ORION_WATCHDOG) += orion_wdt.o diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c new file mode 100644 index 0000000..35d129b --- /dev/null +++ b/drivers/watchdog/orion_wdt.c @@ -0,0 +1,128 @@ +/* + * drivers/watchdog/orion_wdt.c + * + * Watchdog driver for Orion/Kirkwood processors + * + * Authors: Tomas Hlavacek tmshlvck@gmail.com + * Sylver Bruneau sylver.bruneau@googlemail.com + * + * 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 <watchdog.h> +#include <asm/io.h> +#include <asm/arch/cpu.h> +#include <asm/arch/soc.h> + + +/* + * Watchdog timer block registers. + */ + +#define ORION_WDT_REG MVEBU_REGISTER(0x20300) +#define ORION_WDT_RSTOUTREG MVEBU_REGISTER(0x20704) +#define ORION_WDT_RSTOUTMASKREG MVEBU_REGISTER(0x18260) + +#define RSTOUT_ENABLE_BIT BIT(8) +#define RSTOUT_MASK_BIT BIT(10) +#define WDT_ENABLE_BIT BIT(8) + +#define ORION_WDT_COUNTER_OFFSET 0x34 + + +#define TIMER_CTRL 0x0000 +#define TIMER_A370_STATUS 0x04 + +#define WDT_MAX_CYCLE_COUNT 0xffffffff + +#define WDT_AXP_FIXED_ENABLE_BIT BIT(10) +#define WDT_A370_EXPIRED BIT(31) + +#define FIXED_CLKRATE 25000000 /* Hz */ +#ifndef ORION_WDT_TIMEOUT +#define ORION_WDT_TIMEOUT 120 /* sec */ +#endif + + +static int orion_wdt_ping(void) +{ + /* Reload watchdog duration */ + writel((u32)FIXED_CLKRATE * ORION_WDT_TIMEOUT, + ORION_WDT_REG + ORION_WDT_COUNTER_OFFSET); + return 0; +} + +static int orion_wdt_start(void) +{ + u32 reg; + + /* Enable the fixed watchdog clock input */ + reg = readl(ORION_WDT_REG + TIMER_CTRL); + reg |= WDT_AXP_FIXED_ENABLE_BIT; + writel(reg, ORION_WDT_REG + TIMER_CTRL); + + /* Set watchdog duration */ + writel((u32)FIXED_CLKRATE * ORION_WDT_TIMEOUT, + ORION_WDT_REG + ORION_WDT_COUNTER_OFFSET); + + /* Clear the watchdog expiration bit */ + reg = readl(ORION_WDT_REG + TIMER_A370_STATUS); + reg &= ~WDT_A370_EXPIRED; + writel(reg, ORION_WDT_REG + TIMER_A370_STATUS); + + /* Enable watchdog timer */ + reg = readl(ORION_WDT_REG + TIMER_CTRL); + reg |= WDT_ENABLE_BIT; + writel(reg, ORION_WDT_REG + TIMER_CTRL); + + /* Enable reset on watchdog */ + reg = readl(ORION_WDT_RSTOUTREG); + reg |= RSTOUT_ENABLE_BIT; + writel(reg, ORION_WDT_RSTOUTREG); + + reg = readl(ORION_WDT_RSTOUTMASKREG); + reg &= ~RSTOUT_MASK_BIT; + writel(reg, ORION_WDT_RSTOUTMASKREG); + + return 0; +} + +static int orion_wdt_stop(void) +{ + u32 reg; + + /* Disable reset on watchdog */ + reg = readl(ORION_WDT_RSTOUTMASKREG); + reg |= RSTOUT_MASK_BIT; + writel(reg, ORION_WDT_RSTOUTMASKREG); + + reg = readl(ORION_WDT_RSTOUTREG); + reg &= ~RSTOUT_ENABLE_BIT; + writel(reg, ORION_WDT_RSTOUTREG); + + /* Disable watchdog timer */ + reg = readl(ORION_WDT_REG + TIMER_CTRL); + reg &= ~WDT_ENABLE_BIT; + writel(reg, ORION_WDT_REG + TIMER_CTRL); + + return 0; +} + +void hw_watchdog_disable(void) +{ + orion_wdt_stop(); +} + +void hw_watchdog_reset(void) +{ + orion_wdt_ping(); +} + +void hw_watchdog_init(void) +{ + orion_wdt_start(); +} +