diff --git a/debian/changelog b/debian/changelog index 5de0f2898..0d8eec14c 100644 --- a/debian/changelog +++ b/debian/changelog @@ -88,6 +88,7 @@ linux-2.6 (2.6.26-1~experimental.1) UNRELEASED; urgency=low - cache align destination pointer when copying memory for some processors - cache align memset and memzero - DMA engine driver for Marvell XOR engine + - Orion hardware watchdog support * [arm/orion5x] Enable NETCONSOLE. * [arm/orion5x] Disable more SCSI drivers. * [arm/ixp4xx] Disable most ATA and more SCSI and network drivers. diff --git a/debian/config/arm/config.orion5x b/debian/config/arm/config.orion5x index e952b46b2..32f8fee90 100644 --- a/debian/config/arm/config.orion5x +++ b/debian/config/arm/config.orion5x @@ -542,3 +542,6 @@ CONFIG_BT_HCIBPA10X=m CONFIG_BT_HCIBFUSB=m CONFIG_BT_HCIVHCI=m +CONFIG_WATCHDOG=y +CONFIG_ORION5X_WATCHDOG=m + diff --git a/debian/patches/features/arm/orion_watchdog.patch b/debian/patches/features/arm/orion_watchdog.patch new file mode 100644 index 000000000..f848b46fb --- /dev/null +++ b/debian/patches/features/arm/orion_watchdog.patch @@ -0,0 +1,300 @@ +From: Sylver Bruneau +Date: Fri, 23 May 2008 23:02:30 +0000 (+0200) +Subject: [WATCHDOG] Orion: add hardware watchdog support +X-Git-Url: http://git.marvell.com/?p=orion.git;a=commitdiff_plain;h=c64ce41834e774179b9769ae53eaede18e029943 + +[WATCHDOG] Orion: add hardware watchdog support + +This patch allows the use of the hardware watchdog in the +Marvell Orion series of ARM SoCs. + +Signed-off-by: Sylver Bruneau +Signed-off-by: Lennert Buytenhek +--- + +diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig +index ccb78f6..b0c3212 100644 +--- a/drivers/watchdog/Kconfig ++++ b/drivers/watchdog/Kconfig +@@ -217,6 +217,15 @@ config DAVINCI_WATCHDOG + NOTE: once enabled, this timer cannot be disabled. + Say N if you are unsure. + ++config ORION5X_WATCHDOG ++ tristate "Orion5x watchdog" ++ depends on ARCH_ORION5X ++ help ++ Say Y here if to include support for the watchdog timer ++ in the Orion5x ARM SoCs. ++ To compile this driver as a module, choose M here: the ++ module will be called orion5x_wdt. ++ + # ARM26 Architecture + + # AVR32 Architecture +diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile +index 25b352b..2af7324 100644 +--- a/drivers/watchdog/Makefile ++++ b/drivers/watchdog/Makefile +@@ -39,6 +39,7 @@ obj-$(CONFIG_EP93XX_WATCHDOG) += ep93xx_wdt.o + obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o + obj-$(CONFIG_IOP_WATCHDOG) += iop_wdt.o + obj-$(CONFIG_DAVINCI_WATCHDOG) += davinci_wdt.o ++obj-$(CONFIG_ORION5X_WATCHDOG) += orion5x_wdt.o + + # ARM26 Architecture + +diff --git a/drivers/watchdog/orion5x_wdt.c b/drivers/watchdog/orion5x_wdt.c +new file mode 100644 +index 0000000..5cc1953 +--- /dev/null ++++ b/drivers/watchdog/orion5x_wdt.c +@@ -0,0 +1,232 @@ ++/* ++ * drivers/watchdog/orion5x_wdt.c ++ * ++ * Watchdog driver for Orion5x processors ++ * ++ * Author: Sylver Bruneau ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++/* ++ * Watchdog timer block registers. ++ */ ++#define TIMER_CTRL (TIMER_VIRT_BASE + 0x0000) ++#define WDT_EN 0x0010 ++#define WDT_VAL (TIMER_VIRT_BASE + 0x0024) ++ ++#define WDT_MAX_DURATION (0xffffffff / ORION5X_TCLK) ++#define WDT_IN_USE 0 ++#define WDT_OK_TO_CLOSE 1 ++ ++static int nowayout = WATCHDOG_NOWAYOUT; ++static int heartbeat = WDT_MAX_DURATION; /* (seconds) */ ++static unsigned long wdt_status; ++ ++static void wdt_enable(void) ++{ ++ u32 reg; ++ ++ /* Set watchdog duration */ ++ writel(ORION5X_TCLK * heartbeat, WDT_VAL); ++ ++ /* Clear watchdog timer interrupt */ ++ reg = readl(BRIDGE_CAUSE); ++ reg &= ~WDT_INT_REQ; ++ writel(reg, BRIDGE_CAUSE); ++ ++ /* Enable watchdog timer */ ++ reg = readl(TIMER_CTRL); ++ reg |= WDT_EN; ++ writel(reg, TIMER_CTRL); ++ ++ /* Enable reset on watchdog */ ++ reg = readl(CPU_RESET_MASK); ++ reg |= WDT_RESET; ++ writel(reg, CPU_RESET_MASK); ++} ++ ++static void wdt_disable(void) ++{ ++ u32 reg; ++ ++ /* Disable reset on watchdog */ ++ reg = readl(CPU_RESET_MASK); ++ reg &= ~WDT_RESET; ++ writel(reg, CPU_RESET_MASK); ++ ++ /* Disable watchdog timer */ ++ reg = readl(TIMER_CTRL); ++ reg &= ~WDT_EN; ++ writel(reg, TIMER_CTRL); ++} ++ ++static int orion5x_wdt_open(struct inode *inode, struct file *file) ++{ ++ if (test_and_set_bit(WDT_IN_USE, &wdt_status)) ++ return -EBUSY; ++ clear_bit(WDT_OK_TO_CLOSE, &wdt_status); ++ wdt_enable(); ++ return nonseekable_open(inode, file); ++} ++ ++static int orion5x_wdt_get_timeleft(int *time_left) ++{ ++ *time_left = readl(WDT_VAL) / ORION5X_TCLK; ++ return 0; ++} ++ ++static ssize_t orion5x_wdt_write(struct file *file, const char *data, ++ size_t len, loff_t *ppos) ++{ ++ if (len) { ++ if (!nowayout) { ++ size_t i; ++ ++ clear_bit(WDT_OK_TO_CLOSE, &wdt_status); ++ for (i = 0; i != len; i++) { ++ char c; ++ ++ if (get_user(c, data + i)) ++ return -EFAULT; ++ if (c == 'V') ++ set_bit(WDT_OK_TO_CLOSE, &wdt_status); ++ } ++ } ++ wdt_enable(); ++ } ++ return len; ++} ++ ++static struct watchdog_info ident = { ++ .options = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT | ++ WDIOF_KEEPALIVEPING, ++ .identity = "Orion5x Watchdog", ++}; ++ ++ ++static int orion5x_wdt_ioctl(struct inode *inode, struct file *file, ++ unsigned int cmd, unsigned long arg) ++{ ++ int ret = -ENOTTY; ++ int time; ++ ++ switch (cmd) { ++ case WDIOC_GETSUPPORT: ++ ret = copy_to_user((struct watchdog_info *)arg, &ident, ++ sizeof(ident)) ? -EFAULT : 0; ++ break; ++ ++ case WDIOC_GETSTATUS: ++ ret = put_user(0, (int *)arg); ++ break; ++ ++ case WDIOC_SETTIMEOUT: ++ ret = get_user(time, (int *)arg); ++ if (ret) ++ break; ++ ++ if (time <= 0 || time > WDT_MAX_DURATION) { ++ ret = -EINVAL; ++ break; ++ } ++ heartbeat = time; ++ wdt_enable(); ++ /* Fall through */ ++ ++ case WDIOC_GETTIMEOUT: ++ ret = put_user(heartbeat, (int *)arg); ++ break; ++ ++ case WDIOC_KEEPALIVE: ++ wdt_enable(); ++ ret = 0; ++ break; ++ ++ case WDIOC_GETTIMELEFT: ++ if (orion5x_wdt_get_timeleft(&time)) { ++ ret = -EINVAL; ++ break; ++ } ++ ret = put_user(time, (int *)arg); ++ break; ++ } ++ return ret; ++} ++ ++static int orion5x_wdt_release(struct inode *inode, struct file *file) ++{ ++ if (test_bit(WDT_OK_TO_CLOSE, &wdt_status)) ++ wdt_disable(); ++ else ++ printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - " ++ "timer will not stop\n"); ++ clear_bit(WDT_IN_USE, &wdt_status); ++ clear_bit(WDT_OK_TO_CLOSE, &wdt_status); ++ ++ return 0; ++} ++ ++ ++static const struct file_operations orion5x_wdt_fops = { ++ .owner = THIS_MODULE, ++ .llseek = no_llseek, ++ .write = orion5x_wdt_write, ++ .ioctl = orion5x_wdt_ioctl, ++ .open = orion5x_wdt_open, ++ .release = orion5x_wdt_release, ++}; ++ ++static struct miscdevice orion5x_wdt_miscdev = { ++ .minor = WATCHDOG_MINOR, ++ .name = "watchdog", ++ .fops = &orion5x_wdt_fops, ++}; ++ ++static int __init orion5x_wdt_init(void) ++{ ++ int ret; ++ ++ ret = misc_register(&orion5x_wdt_miscdev); ++ if (ret == 0) ++ printk("Orion5x Watchdog Timer: heartbeat %d sec\n", ++ heartbeat); ++ ++ return ret; ++} ++ ++static void __exit orion5x_wdt_exit(void) ++{ ++ misc_deregister(&orion5x_wdt_miscdev); ++} ++ ++module_init(orion5x_wdt_init); ++module_exit(orion5x_wdt_exit); ++ ++MODULE_AUTHOR("Sylver Bruneau "); ++MODULE_DESCRIPTION("Orion5x Processor Watchdog"); ++ ++module_param(heartbeat, int, 0); ++MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds (default is " ++ __MODULE_STRING(WDT_MAX_DURATION) ")"); ++ ++module_param(nowayout, int, 0); ++MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started"); ++ ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); +diff --git a/include/asm-arm/arch-orion5x/orion5x.h b/include/asm-arm/arch-orion5x/orion5x.h +index 10257f5..375da2e 100644 +--- a/include/asm-arm/arch-orion5x/orion5x.h~ 2008-07-26 00:33:55.000000000 +0000 ++++ b/include/asm-arm/arch-orion5x/orion5x.h 2008-07-26 00:33:58.000000000 +0000 +@@ -151,9 +151,11 @@ + #define CPU_CONF ORION5X_BRIDGE_REG(0x100) + #define CPU_CTRL ORION5X_BRIDGE_REG(0x104) + #define CPU_RESET_MASK ORION5X_BRIDGE_REG(0x108) ++#define WDT_RESET 0x0002 + #define CPU_SOFT_RESET ORION5X_BRIDGE_REG(0x10c) + #define POWER_MNG_CTRL_REG ORION5X_BRIDGE_REG(0x11C) + #define BRIDGE_CAUSE ORION5X_BRIDGE_REG(0x110) ++#define WDT_INT_REQ 0x0008 + #define BRIDGE_MASK ORION5X_BRIDGE_REG(0x114) + #define BRIDGE_INT_TIMER0 0x0002 + #define BRIDGE_INT_TIMER1 0x0004 diff --git a/debian/patches/series/1~experimental.1 b/debian/patches/series/1~experimental.1 index ea3fedec0..81d0116f2 100644 --- a/debian/patches/series/1~experimental.1 +++ b/debian/patches/series/1~experimental.1 @@ -48,6 +48,7 @@ + features/arm/ixp4xx-4874-fsg-board-support.patch + features/arm/mv_dma_engine.patch + features/arm/orion_use_mv_xor.patch ++ features/arm/orion_watchdog.patch + features/mips/ip32_sound.patch + features/all/at76.patch + bugfix/fix-hifn_795X-divdi3.patch