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 + + Som code taken from: + National Semiconductor SCx200 Watchdog support + Copyright (c) 2001,2002 Christer Weinigel + + 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#define NAME "ar7_wdt" +#define LONGNAME "TI AR7 Watchdog Timer" + +MODULE_AUTHOR("Enrik Berkhan "); +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))