diff options
Diffstat (limited to 'target/linux/ar7-2.4/patches/005-wdt_driver.patch')
-rw-r--r-- | target/linux/ar7-2.4/patches/005-wdt_driver.patch | 392 |
1 files changed, 392 insertions, 0 deletions
diff --git a/target/linux/ar7-2.4/patches/005-wdt_driver.patch b/target/linux/ar7-2.4/patches/005-wdt_driver.patch new file mode 100644 index 0000000000..9b01a353da --- /dev/null +++ b/target/linux/ar7-2.4/patches/005-wdt_driver.patch @@ -0,0 +1,392 @@ +diff -ruN linux-2.4.30-patch006/drivers/char/ar7_wdt.c linux-2.4.30-patch007/drivers/char/ar7_wdt.c +--- linux-2.4.30-patch006/drivers/char/ar7_wdt.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.30-patch007/drivers/char/ar7_wdt.c 2005-10-27 09:39:40.000000000 +0200 +@@ -0,0 +1,335 @@ ++/* linux/drivers/char/ar7_wdt.c ++ ++ TI AR7 watch dog timer support ++ ++ Copyright (c) 2005 Enrik Berkhan <Enrik.Berkhan@akk.org> ++ ++ Som code taken from: ++ National Semiconductor SCx200 Watchdog support ++ Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com> ++ ++ This program is free software; you can redistribute it and/or ++ modify it under the terms of the GNU General Public License as ++ published by the Free Software Foundation; either version 2 of the ++ License, or (at your option) any later version. ++ ++ The author(s) of this software shall not be held liable for damages ++ of any nature resulting due to the use of this software. This ++ software is provided AS-IS with no warranties. */ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/errno.h> ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/miscdevice.h> ++#include <linux/watchdog.h> ++#include <linux/notifier.h> ++#include <linux/reboot.h> ++#include <linux/ioport.h> ++ ++#include <asm/uaccess.h> ++ ++#include <asm/ar7/avalanche_misc.h> ++#include <asm/ar7/sangam.h> ++ ++#define NAME "ar7_wdt" ++#define LONGNAME "TI AR7 Watchdog Timer" ++ ++MODULE_AUTHOR("Enrik Berkhan <Enrik.Berkhan@akk.org>"); ++MODULE_DESCRIPTION(LONGNAME); ++MODULE_LICENSE("GPL"); ++ ++#ifndef CONFIG_WATCHDOG_NOWAYOUT ++#define CONFIG_WATCHDOG_NOWAYOUT 0 ++#endif ++ ++static int margin = 60; ++MODULE_PARM(margin, "i"); ++MODULE_PARM_DESC(margin, "Watchdog margin in seconds (1 - ~68)"); ++ ++static int nowayout = CONFIG_WATCHDOG_NOWAYOUT; ++MODULE_PARM(nowayout, "i"); ++MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close"); ++ ++typedef struct { ++ uint32_t kick_lock; ++ uint32_t kick; ++ uint32_t change_lock; ++ uint32_t change ; ++ uint32_t disable_lock; ++ uint32_t disable; ++ uint32_t prescale_lock; ++ uint32_t prescale; ++} ar7_wdt_t; ++ ++volatile ar7_wdt_t *ar7_wdt = (ar7_wdt_t *)AVALANCHE_WATCHDOG_TIMER_BASE; ++ ++static struct semaphore open_semaphore; ++static unsigned expect_close; ++ ++/* XXX correct? assumed to be sysfreq/2. get this dynamically ... */ ++#define vbus_freq 62500000 ++ ++/* XXX currently fixed, allows max margin ~68.72 secs */ ++#define prescale_value 0xFFFF ++ ++static void ar7_wdt_kick(uint32_t value) ++{ ++ ar7_wdt->kick_lock = 0x5555; ++ if ((ar7_wdt->kick_lock & 3) == 1) { ++ ar7_wdt->kick_lock = 0xAAAA; ++ if ((ar7_wdt->kick_lock & 3) == 3) { ++ ar7_wdt->kick = value; ++ return; ++ } ++ } ++ printk(KERN_ERR NAME "failed to unlock WDT kick reg\n"); ++} ++ ++static void ar7_wdt_prescale(uint32_t value) ++{ ++ ar7_wdt->prescale_lock = 0x5A5A; ++ if ((ar7_wdt->prescale_lock & 3) == 1) { ++ ar7_wdt->prescale_lock = 0xA5A5; ++ if ((ar7_wdt->prescale_lock & 3) == 3) { ++ ar7_wdt->prescale = value; ++ return; ++ } ++ } ++ printk(KERN_ERR NAME "failed to unlock WDT prescale reg\n"); ++} ++ ++static void ar7_wdt_change(uint32_t value) ++{ ++ ar7_wdt->change_lock = 0x6666; ++ if ((ar7_wdt->change_lock & 3) == 1) { ++ ar7_wdt->change_lock = 0xBBBB; ++ if ((ar7_wdt->change_lock & 3) == 3) { ++ ar7_wdt->change = value; ++ return; ++ } ++ } ++ printk(KERN_ERR NAME "failed to unlock WDT change reg\n"); ++} ++ ++static void ar7_wdt_disable(uint32_t value) ++{ ++ ar7_wdt->disable_lock = 0x7777; ++ if ((ar7_wdt->disable_lock & 3) == 1) { ++ ar7_wdt->disable_lock = 0xCCCC; ++ if ((ar7_wdt->disable_lock & 3) == 2) { ++ ar7_wdt->disable_lock = 0xDDDD; ++ if ((ar7_wdt->disable_lock & 3) == 3) { ++ ar7_wdt->disable = value; ++ return; ++ } ++ } ++ } ++ printk(KERN_ERR NAME "failed to unlock WDT disable reg\n"); ++ return; ++} ++ ++static void ar7_wdt_update_margin(int new_margin) ++{ ++ uint32_t change; ++ ++ change = new_margin * (vbus_freq / prescale_value); ++ if (change < 1) change = 1; ++ if (change > 0xFFFF) change = 0xFFFF; ++ ar7_wdt_change(change); ++ margin = change * prescale_value / vbus_freq; ++ printk(KERN_INFO NAME ++ ": timer margin %d seconds (prescale %d, change %d, freq %d)\n", ++ margin, prescale_value, change, vbus_freq); ++} ++ ++static void ar7_wdt_enable_wdt(void) ++{ ++ printk(KERN_DEBUG NAME ": enabling watchdog timer\n"); ++ ar7_wdt_disable(1); ++ ar7_wdt_kick(1); ++} ++ ++static void ar7_wdt_disable_wdt(void) ++{ ++ printk(KERN_DEBUG NAME ": disabling watchdog timer\n"); ++ ar7_wdt_disable(0); ++} ++ ++static int ar7_wdt_open(struct inode *inode, struct file *file) ++{ ++ /* only allow one at a time */ ++ if (down_trylock(&open_semaphore)) ++ return -EBUSY; ++ ar7_wdt_enable_wdt(); ++ expect_close = 0; ++ ++ return 0; ++} ++ ++static int ar7_wdt_release(struct inode *inode, struct file *file) ++{ ++ if (!expect_close) { ++ printk(KERN_WARNING NAME ": watchdog device closed unexpectedly, will not disable the watchdog timer\n"); ++ } else if (!nowayout) { ++ ar7_wdt_disable_wdt(); ++ } ++ up(&open_semaphore); ++ ++ return 0; ++} ++ ++static int ar7_wdt_notify_sys(struct notifier_block *this, ++ unsigned long code, void *unused) ++{ ++ if (code == SYS_HALT || code == SYS_POWER_OFF) ++ if (!nowayout) ++ ar7_wdt_disable_wdt(); ++ ++ return NOTIFY_DONE; ++} ++ ++static struct notifier_block ar7_wdt_notifier = ++{ ++ .notifier_call = ar7_wdt_notify_sys ++}; ++ ++static ssize_t ar7_wdt_write(struct file *file, const char *data, ++ size_t len, loff_t *ppos) ++{ ++ if (ppos != &file->f_pos) ++ return -ESPIPE; ++ ++ /* check for a magic close character */ ++ if (len) ++ { ++ size_t i; ++ ++ ar7_wdt_kick(1); ++ ++ expect_close = 0; ++ for (i = 0; i < len; ++i) { ++ char c; ++ if (get_user(c, data+i)) ++ return -EFAULT; ++ if (c == 'V') ++ expect_close = 1; ++ } ++ ++ } ++ return len; ++} ++ ++static int ar7_wdt_ioctl(struct inode *inode, struct file *file, ++ unsigned int cmd, unsigned long arg) ++{ ++ static struct watchdog_info ident = { ++ .identity = LONGNAME, ++ .firmware_version = 1, ++ .options = (WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING), ++ }; ++ int new_margin; ++ ++ switch (cmd) { ++ default: ++ return -ENOTTY; ++ case WDIOC_GETSUPPORT: ++ if(copy_to_user((struct watchdog_info *)arg, &ident, ++ sizeof(ident))) ++ return -EFAULT; ++ return 0; ++ case WDIOC_GETSTATUS: ++ case WDIOC_GETBOOTSTATUS: ++ if (put_user(0, (int *)arg)) ++ return -EFAULT; ++ return 0; ++ case WDIOC_KEEPALIVE: ++ ar7_wdt_kick(1); ++ return 0; ++ case WDIOC_SETTIMEOUT: ++ if (get_user(new_margin, (int *)arg)) ++ return -EFAULT; ++ if (new_margin < 1) ++ return -EINVAL; ++ ++ ar7_wdt_update_margin(new_margin); ++ ar7_wdt_kick(1); ++ ++ case WDIOC_GETTIMEOUT: ++ if (put_user(margin, (int *)arg)) ++ return -EFAULT; ++ return 0; ++ } ++} ++ ++static struct file_operations ar7_wdt_fops = { ++ .owner = THIS_MODULE, ++ .write = ar7_wdt_write, ++ .ioctl = ar7_wdt_ioctl, ++ .open = ar7_wdt_open, ++ .release = ar7_wdt_release, ++}; ++ ++static struct miscdevice ar7_wdt_miscdev = { ++ .minor = WATCHDOG_MINOR, ++ .name = "watchdog", ++ .fops = &ar7_wdt_fops, ++}; ++ ++static __initdata char *last_initiator[] = { ++ [HARDWARE_RESET] = "hardware reset", ++ [SOFTWARE_RESET0] = "SW0 software reset", ++ [SOFTWARE_RESET1] = "SW1 software reset", ++ [WATCHDOG_RESET] = "watchdog" ++}; ++ ++static int __init ar7_wdt_init(void) ++{ ++ int r; ++ ++ if (!request_mem_region(AVALANCHE_WATCHDOG_TIMER_BASE, ++ sizeof(ar7_wdt_t), LONGNAME)) { ++ printk(KERN_WARNING NAME ": watchdog I/O region busy\n"); ++ return -EBUSY; ++ } ++ ++ printk(KERN_INFO NAME ": last system reset initiated by %s\n", ++ last_initiator[avalanche_get_sys_last_reset_status()]); ++ ++ ++ ar7_wdt_disable_wdt(); ++ ar7_wdt_prescale(prescale_value); ++ ar7_wdt_update_margin(margin); ++ ++ sema_init(&open_semaphore, 1); ++ ++ r = misc_register(&ar7_wdt_miscdev); ++ if (r) { ++ printk(KERN_ERR NAME ": unable to register misc device\n"); ++ release_mem_region(AVALANCHE_WATCHDOG_TIMER_BASE, ++ sizeof(ar7_wdt_t)); ++ return r; ++ } ++ ++ r = register_reboot_notifier(&ar7_wdt_notifier); ++ if (r) { ++ printk(KERN_ERR NAME ": unable to register reboot notifier\n"); ++ misc_deregister(&ar7_wdt_miscdev); ++ release_mem_region(AVALANCHE_WATCHDOG_TIMER_BASE, ++ sizeof(ar7_wdt_t)); ++ return r; ++ } ++ ++ return 0; ++} ++ ++static void __exit ar7_wdt_cleanup(void) ++{ ++ unregister_reboot_notifier(&ar7_wdt_notifier); ++ misc_deregister(&ar7_wdt_miscdev); ++ release_mem_region(AVALANCHE_WATCHDOG_TIMER_BASE, sizeof(ar7_wdt_t)); ++} ++ ++module_init(ar7_wdt_init); ++module_exit(ar7_wdt_cleanup); +diff -ruN linux-2.4.30-patch006/drivers/char/Config.in linux-2.4.30-patch007/drivers/char/Config.in +--- linux-2.4.30-patch006/drivers/char/Config.in 2005-10-27 11:25:29.000000000 +0200 ++++ linux-2.4.30-patch007/drivers/char/Config.in 2005-10-27 11:17:32.000000000 +0200 +@@ -251,6 +251,9 @@ + bool 'Watchdog Timer Support' CONFIG_WATCHDOG + if [ "$CONFIG_WATCHDOG" != "n" ]; then + bool ' Disable watchdog shutdown on close' CONFIG_WATCHDOG_NOWAYOUT ++ if [ "$CONFIG_AR7" = "y" ] ; then ++ tristate ' TI AR7 Watchdog Timer' CONFIG_AR7_WDT ++ else + tristate ' Acquire SBC Watchdog Timer' CONFIG_ACQUIRE_WDT + tristate ' Advantech SBC Watchdog Timer' CONFIG_ADVANTECH_WDT + tristate ' ALi M7101 PMU on ALi 1535D+ Watchdog Timer' CONFIG_ALIM1535_WDT +@@ -271,7 +274,6 @@ + tristate ' SBC-60XX Watchdog Timer' CONFIG_60XX_WDT + dep_tristate ' SC1200 Watchdog Timer (EXPERIMENTAL)' CONFIG_SC1200_WDT $CONFIG_EXPERIMENTAL + tristate ' NatSemi SCx200 Watchdog' CONFIG_SCx200_WDT +- tristate ' Software Watchdog' CONFIG_SOFT_WATCHDOG + tristate ' W83877F (EMACS) Watchdog Timer' CONFIG_W83877F_WDT + tristate ' WDT Watchdog timer' CONFIG_WDT + tristate ' WDT PCI Watchdog timer' CONFIG_WDTPCI +@@ -282,6 +284,8 @@ + fi + fi + tristate ' ZF MachZ Watchdog' CONFIG_MACHZ_WDT ++ fi ++ tristate ' Software Watchdog' CONFIG_SOFT_WATCHDOG + if [ "$CONFIG_SGI_IP22" = "y" ]; then + dep_tristate ' Indy/I2 Hardware Watchdog' CONFIG_INDYDOG $CONFIG_SGI_IP22 + fi +diff -ruN linux-2.4.30-patch006/drivers/char/Makefile linux-2.4.30-patch007/drivers/char/Makefile +--- linux-2.4.30-patch006/drivers/char/Makefile 2005-10-27 11:19:38.000000000 +0200 ++++ linux-2.4.30-patch007/drivers/char/Makefile 2005-10-27 09:39:40.000000000 +0200 +@@ -342,6 +342,7 @@ + obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o + obj-$(CONFIG_INDYDOG) += indydog.o + obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o ++obj-$(CONFIG_AR7_WDT) += ar7_wdt.o + + subdir-$(CONFIG_MWAVE) += mwave + ifeq ($(CONFIG_MWAVE),y) +diff -ruN linux-2.4.30-patch006/include/asm-mips/ar7/sangam.h linux-2.4.30-patch007/include/asm-mips/ar7/sangam.h +--- linux-2.4.30-patch006/include/asm-mips/ar7/sangam.h 2005-10-27 11:25:51.000000000 +0200 ++++ linux-2.4.30-patch007/include/asm-mips/ar7/sangam.h 2005-10-27 11:13:37.000000000 +0200 +@@ -152,7 +152,7 @@ + #define AVALANCHE_EMIF_SDRAM_CFG (AVALANCHE_EMIF_CONTROL_BASE + 0x8) + #define AVALANCHE_RST_CTRL_PRCR (KSEG1ADDR(0x08611600)) + #define AVALANCHE_RST_CTRL_SWRCR (KSEG1ADDR(0x08611604)) +-#define AVALANCHE_RST_CTRL_RSR (KSEG1ADDR(0x08611600)) ++#define AVALANCHE_RST_CTRL_RSR (KSEG1ADDR(0x08611608)) + + #define AVALANCHE_POWER_CTRL_PDCR (KSEG1ADDR(0x08610A00)) + #define AVALANCHE_WAKEUP_CTRL_WKCR (KSEG1ADDR(0x08610A0C)) |