From cb6ae8cb76641181d435bdb4220119343892e3f5 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Wed, 30 Jan 2008 15:25:48 +0000 Subject: [adm5120] add preliminary support for 2.6.24 git-svn-id: svn://svn.openwrt.org/openwrt/trunk@10329 3c298f89-4303-0410-b956-a3cf2f4a3e73 --- .../linux/adm5120/files/arch/mips/adm5120/setup.c | 6 +- .../linux/adm5120/files/arch/mips/adm5120/time.c | 5 +- .../adm5120/files/drivers/watchdog/adm5120_wdt.c | 206 +++++++++++++++++++++ .../include/asm-mips/mach-adm5120/adm5120_info.h | 1 - .../include/asm-mips/mach-adm5120/adm5120_switch.h | 6 +- .../files/include/asm-mips/mach-adm5120/war.h | 25 +++ 6 files changed, 244 insertions(+), 5 deletions(-) create mode 100644 target/linux/adm5120/files/drivers/watchdog/adm5120_wdt.c create mode 100644 target/linux/adm5120/files/include/asm-mips/mach-adm5120/war.h (limited to 'target/linux/adm5120/files') diff --git a/target/linux/adm5120/files/arch/mips/adm5120/setup.c b/target/linux/adm5120/files/arch/mips/adm5120/setup.c index ca509859ba..9046057f9f 100644 --- a/target/linux/adm5120/files/arch/mips/adm5120/setup.c +++ b/target/linux/adm5120/files/arch/mips/adm5120/setup.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -59,7 +60,10 @@ void __init plat_mem_setup(void) adm5120_mem_init(); adm5120_report(); - board_time_init = adm5120_time_init; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) +extern void plat_time_init(void) __init; + board_time_init = plat_time_init; +#endif _machine_restart = adm5120_restart; _machine_halt = adm5120_halt; diff --git a/target/linux/adm5120/files/arch/mips/adm5120/time.c b/target/linux/adm5120/files/arch/mips/adm5120/time.c index b36cea647a..66eb1ce7df 100644 --- a/target/linux/adm5120/files/arch/mips/adm5120/time.c +++ b/target/linux/adm5120/files/arch/mips/adm5120/time.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -29,11 +30,12 @@ #include #include -void __init adm5120_time_init(void) +void __init plat_time_init(void) { mips_hpt_frequency = adm5120_speed / 2; } +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) void __init plat_timer_setup(struct irqaction *irq) { clear_c0_status(ST0_BEV); @@ -41,3 +43,4 @@ void __init plat_timer_setup(struct irqaction *irq) /* Install ISR for CPU Counter interrupt */ setup_irq(ADM5120_IRQ_COUNTER, irq); } +#endif diff --git a/target/linux/adm5120/files/drivers/watchdog/adm5120_wdt.c b/target/linux/adm5120/files/drivers/watchdog/adm5120_wdt.c new file mode 100644 index 0000000000..cddb1721cf --- /dev/null +++ b/target/linux/adm5120/files/drivers/watchdog/adm5120_wdt.c @@ -0,0 +1,206 @@ +/* + * ADM5120_WDT 0.01: Infineon ADM5120 SoC watchdog driver + * Copyright (c) Ondrej Zajicek , 2007 + * + * based on + * + * RC32434_WDT 0.01: IDT Interprise 79RC32434 watchdog driver + * + * 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. + * + */ + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + + +#define DEFAULT_TIMEOUT 15 /* (secs) Default is 15 seconds */ +#define MAX_TIMEOUT 327 +/* Max is 327 seconds, counter is 15-bit integer, step is 10 ms */ + +#define NAME "adm5120_wdt" +#define VERSION "0.1" + +static int expect_close = 0; +static int access = 0; +static unsigned int timeout = DEFAULT_TIMEOUT; + +static int nowayout = WATCHDOG_NOWAYOUT; +module_param(nowayout, int, 0); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); +MODULE_LICENSE("GPL"); + + +static inline void wdt_set_timeout(void) +{ + u32 val = (1 << 31) | (((timeout * 100) & 0x7FFF) << 16); + SW_WRITE_REG(SWITCH_REG_WDOG0, val); +} + +/* + It looks like WDOG0-register-write don't modify counter, + but WDOG0-register-read resets counter. +*/ + +static inline void wdt_reset_counter(void) +{ + SW_READ_REG(SWITCH_REG_WDOG0); +} + +static inline void wdt_disable(void) +{ + SW_WRITE_REG(SWITCH_REG_WDOG0, 0x7FFF0000); +} + + + +static int wdt_open(struct inode *inode, struct file *file) +{ + /* Allow only one person to hold it open */ + if (access) + return -EBUSY; + + if (nowayout) { + __module_get(THIS_MODULE); + } + + /* Activate timer */ + wdt_reset_counter(); + wdt_set_timeout(); + printk(KERN_INFO NAME ": enabling watchdog timer\n"); + access = 1; + return 0; +} + +static int wdt_release(struct inode *inode, struct file *file) +{ + /* + * Shut off the timer. + * Lock it in if it's a module and we set nowayout + */ + if (expect_close && (nowayout == 0)) { + wdt_disable(); + printk(KERN_INFO NAME ": disabling watchdog timer\n"); + module_put(THIS_MODULE); + } else { + printk(KERN_CRIT NAME ": device closed unexpectedly. WDT will not stop!\n"); + } + access = 0; + return 0; +} + +static ssize_t wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos) +{ + /* Refresh the timer. */ + if (len) { + if (!nowayout) { + size_t i; + + /* In case it was set long ago */ + 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; + } + } + wdt_reset_counter(); + return len; + } + return 0; +} + +static int wdt_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int new_timeout; + static struct watchdog_info ident = { + .options = WDIOF_SETTIMEOUT | + WDIOF_KEEPALIVEPING | + WDIOF_MAGICCLOSE, + .firmware_version = 0, + .identity = "ADM5120_WDT Watchdog", + }; + 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: + return put_user(0,(int *)arg); + case WDIOC_KEEPALIVE: + wdt_reset_counter(); + return 0; + case WDIOC_SETTIMEOUT: + if (get_user(new_timeout, (int *)arg)) + return -EFAULT; + if (new_timeout < 1) + return -EINVAL; + if (new_timeout > MAX_TIMEOUT) + return -EINVAL; + timeout = new_timeout; + wdt_set_timeout(); + /* Fall */ + case WDIOC_GETTIMEOUT: + return put_user(timeout, (int *)arg); + } +} + +static struct file_operations wdt_fops = { + owner: THIS_MODULE, + llseek: no_llseek, + write: wdt_write, + ioctl: wdt_ioctl, + open: wdt_open, + release: wdt_release, +}; + +static struct miscdevice wdt_miscdev = { + minor: WATCHDOG_MINOR, + name: "watchdog", + fops: &wdt_fops, +}; + +static char banner[] __initdata = KERN_INFO NAME ": Watchdog Timer version " VERSION "\n"; + +static int __init watchdog_init(void) +{ + int ret; + + ret = misc_register(&wdt_miscdev); + + if (ret) + return ret; + + wdt_disable(); + printk(banner); + + return 0; +} + +static void __exit watchdog_exit(void) +{ + misc_deregister(&wdt_miscdev); +} + +module_init(watchdog_init); +module_exit(watchdog_exit); diff --git a/target/linux/adm5120/files/include/asm-mips/mach-adm5120/adm5120_info.h b/target/linux/adm5120/files/include/asm-mips/mach-adm5120/adm5120_info.h index a2e8d48a7d..401000197f 100644 --- a/target/linux/adm5120/files/include/asm-mips/mach-adm5120/adm5120_info.h +++ b/target/linux/adm5120/files/include/asm-mips/mach-adm5120/adm5120_info.h @@ -50,7 +50,6 @@ extern unsigned char adm5120_eth_vlans[6]; extern void adm5120_soc_init(void) __init; extern void adm5120_mem_init(void) __init; -extern void adm5120_time_init(void) __init; extern void adm5120_ndelay(u32 ns); extern void adm5120_restart(char *command); diff --git a/target/linux/adm5120/files/include/asm-mips/mach-adm5120/adm5120_switch.h b/target/linux/adm5120/files/include/asm-mips/mach-adm5120/adm5120_switch.h index bc9b6f6625..2dbb097763 100644 --- a/target/linux/adm5120/files/include/asm-mips/mach-adm5120/adm5120_switch.h +++ b/target/linux/adm5120/files/include/asm-mips/mach-adm5120/adm5120_switch.h @@ -18,8 +18,10 @@ #ifndef _ADM5120_SWITCH_H_ #define _ADM5120_SWITCH_H_ -#define BIT(at) (1 << (at)) -#define BITMASK(len) ((1 << (len))-1) +#ifndef BIT +# define BIT(at) (1 << (at)) +#endif +#define BITMASK(len) (BIT(len)-1) #define SW_READ_REG(r) __raw_readl( \ (void __iomem *)KSEG1ADDR(ADM5120_SWITCH_BASE) + r) diff --git a/target/linux/adm5120/files/include/asm-mips/mach-adm5120/war.h b/target/linux/adm5120/files/include/asm-mips/mach-adm5120/war.h new file mode 100644 index 0000000000..87c35f375b --- /dev/null +++ b/target/linux/adm5120/files/include/asm-mips/mach-adm5120/war.h @@ -0,0 +1,25 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2002, 2004, 2007 by Ralf Baechle + */ +#ifndef __ASM_MIPS_MACH_ADM5120_WAR_H +#define __ASM_MIPS_MACH_ADM5120_WAR_H + +#define R4600_V1_INDEX_ICACHEOP_WAR 0 +#define R4600_V1_HIT_CACHEOP_WAR 0 +#define R4600_V2_HIT_CACHEOP_WAR 0 +#define R5432_CP0_INTERRUPT_WAR 0 +#define BCM1250_M3_WAR 0 +#define SIBYTE_1956_WAR 0 +#define MIPS4K_ICACHE_REFILL_WAR 0 +#define MIPS_CACHE_SYNC_WAR 0 +#define TX49XX_ICACHE_INDEX_INV_WAR 0 +#define RM9000_CDEX_SMP_WAR 0 +#define ICACHE_REFILLS_WORKAROUND_WAR 0 +#define R10000_LLSC_WAR 0 +#define MIPS34K_MISSED_ITLB_WAR 0 + +#endif /* __ASM_MIPS_MACH_ADM5120_WAR_H */ -- cgit v1.2.3