diff options
Diffstat (limited to 'target/linux/realtek/files/arch/rlx/bsp/irq.c')
-rw-r--r-- | target/linux/realtek/files/arch/rlx/bsp/irq.c | 265 |
1 files changed, 265 insertions, 0 deletions
diff --git a/target/linux/realtek/files/arch/rlx/bsp/irq.c b/target/linux/realtek/files/arch/rlx/bsp/irq.c new file mode 100644 index 000000000..80d5a3b71 --- /dev/null +++ b/target/linux/realtek/files/arch/rlx/bsp/irq.c @@ -0,0 +1,265 @@ +/* + * Realtek Semiconductor Corp. + * + * arch/rlx/rlxocp0/irq.c + * Interrupt and exception initialization for RLX OCP Platform + * + * Tony Wu (tonywu@realtek.com.tw) + * Nov. 7, 2006 + */ +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/kernel_stat.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/ioport.h> +#include <linux/timex.h> +#include <linux/slab.h> +#include <linux/random.h> +#include <linux/irq.h> + +#include <asm/bitops.h> +#include <asm/bootinfo.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/irq_cpu.h> +#include <asm/irq_vec.h> +#include <asm/system.h> + +#include <asm/rlxregs.h> +#include <asm/rlxbsp.h> +#include <net/rtl/rtl_types.h> +#include "bspchip.h" + +static struct irqaction irq_cascade = { + .handler = no_action, + .mask = CPU_MASK_NONE, + .name = "cascade", +}; + +static void bsp_ictl_irq_mask(unsigned int irq) +{ + REG32(BSP_GIMR) &= ~(1 << (irq - BSP_IRQ_ICTL_BASE)); +} + +static void bsp_ictl_irq_unmask(unsigned int irq) +{ + REG32(BSP_GIMR) |= (1 << (irq - BSP_IRQ_ICTL_BASE)); +} + +static struct irq_chip bsp_ictl_irq = { + .typename = "ICTL", + .ack = bsp_ictl_irq_mask, + .mask = bsp_ictl_irq_mask, + .mask_ack = bsp_ictl_irq_mask, + .unmask = bsp_ictl_irq_unmask, +}; + +static void bsp_ictl_irq_dispatch(void) +{ + volatile unsigned int pending; + + pending = REG32(BSP_GIMR) & REG32(BSP_GISR); + + if (pending & BSP_UART0_IP) + do_IRQ(BSP_UART0_IRQ); + else if (pending & BSP_TC1_IP) + do_IRQ(BSP_TC1_IRQ); + else if (pending & BSP_GPIO_ABCD_IP) + do_IRQ(BSP_GPIO_ABCD_IRQ); + else { + REG32(BSP_GIMR) &= (~pending); + REG32(BSP_GISR) = REG32(BSP_GISR); + printk("Unknown Interrupt0:%x\n", pending); + #if defined(CONFIG_RTK_VOIP) || defined(CONFIG_RTL_819X) + spurious_interrupt(SPURIOS_INT_CASCADE); + #else + spurious_interrupt(); + #endif + } +} + +void bsp_irq_dispatch(void) +{ + volatile unsigned int pending; + pending = read_c0_cause() & read_c0_status(); + + if (pending & CAUSEF_IP2) + bsp_ictl_irq_dispatch(); + else if (pending & CAUSEF_IP0) + do_IRQ(0); + else if (pending & CAUSEF_IP1) + do_IRQ(1); + else { +#if defined(CONFIG_RTK_VOIP) || defined(CONFIG_RTL_819X) + spurious_interrupt(SPURIOS_INT_CPU); +#else + spurious_interrupt(); +#endif + } +} + +static void __init bsp_ictl_irq_init(unsigned int irq_base) +{ + int i; + + for (i=0; i < BSP_IRQ_ICTL_NUM; i++) + set_irq_chip_and_handler(irq_base + i, &bsp_ictl_irq, handle_level_irq); + + setup_irq(BSP_ICTL_IRQ, &irq_cascade); +} + +void __init bsp_irq_init(void) +{ + //unsigned int status; + //volatile unsigned int status; + /* disable ict interrupt */ + REG32(BSP_GIMR) = 0; + + /* initialize IRQ action handlers */ + rlx_cpu_irq_init(BSP_IRQ_CPU_BASE); + rlx_vec_irq_init(BSP_IRQ_LOPI_BASE); + bsp_ictl_irq_init(BSP_IRQ_ICTL_BASE); + + /* Set IRR */ + REG32(BSP_IRR0) = BSP_IRR0_SETTING; + REG32(BSP_IRR1) = BSP_IRR1_SETTING; + REG32(BSP_IRR2) = BSP_IRR2_SETTING; + REG32(BSP_IRR3) = BSP_IRR3_SETTING; + + //status = read_c0_status(); + //status = (status&(~ST0_IM))|(CAUSEF_IP2|CAUSEF_IP3|CAUSEF_IP4|CAUSEF_IP5|CAUSEF_IP6); + //write_c0_status(status); +} + +#if defined(CONFIG_RTL_8196C) && defined(CONFIG_ARCH_SUSPEND_POSSIBLE)//michaelxxx + #define CONFIG_RTL819X_SUSPEND_CHECK_INTERRUPT + + #ifdef CONFIG_RTL819X_SUSPEND_CHECK_INTERRUPT + #include <linux/proc_fs.h> + #include <linux/kernel_stat.h> + #include <asm/uaccess.h> + //#define INT_HIGH_WATER_MARK 1850 //for window size = 1, based on LAN->WAN test result + //#define INT_LOW_WATER_MARK 1150 + //#define INT_HIGH_WATER_MARK 9190 //for window size = 5, based on LAN->WAN test result + //#define INT_LOW_WATER_MARK 5500 + #define INT_HIGH_WATER_MARK 3200 //for window size = 5, based on WLAN->WAN test result + #define INT_LOW_WATER_MARK 2200 + #define INT_WINDOW_SIZE_MAX 10 + static int suspend_check_enable = 1; + static int suspend_check_high_water_mark = INT_HIGH_WATER_MARK; + static int suspend_check_low_water_mark = INT_LOW_WATER_MARK; + static int suspend_check_win_size = 5; + static struct timer_list suspend_check_timer; + static int index=0; + static int eth_int_count[INT_WINDOW_SIZE_MAX]; + static int wlan_int_count[INT_WINDOW_SIZE_MAX]; + int cpu_can_suspend = 1; + int cpu_can_suspend_check_init = 0; + + static int read_proc_suspend_check(char *page, char **start, off_t off, + int count, int *eof, void *data) + { + int len; + + len = sprintf(page, "enable=%d, winsize=%d(%d), high=%d, low=%d, suspend=%d\n", + suspend_check_enable, suspend_check_win_size, INT_WINDOW_SIZE_MAX, + suspend_check_high_water_mark, suspend_check_low_water_mark, cpu_can_suspend); + + if (len <= off+count) + *eof = 1; + *start = page + off; + len -= off; + if (len > count) + len = count; + if (len < 0) + len = 0; + return len; + } + + static int write_proc_suspend_check(struct file *file, const char *buffer, + unsigned long count, void *data) + { + char tmp[128]; + + if (buffer && !copy_from_user(tmp, buffer, 128)) { + sscanf(tmp, "%d %d %d %d", + &suspend_check_enable, &suspend_check_win_size, + &suspend_check_high_water_mark, &suspend_check_low_water_mark); + if (suspend_check_win_size >= INT_WINDOW_SIZE_MAX) + suspend_check_win_size = INT_WINDOW_SIZE_MAX - 1; + if (suspend_check_enable) { + mod_timer(&suspend_check_timer, jiffies + 100); + } + else { + del_timer(&suspend_check_timer); + } + } + return count; + } + + static void suspend_check_timer_fn(unsigned long arg) + { + int count, j; + + index++; + if (INT_WINDOW_SIZE_MAX <= index) + index = 0; + eth_int_count[index] = kstat_irqs(BSP_SWCORE_IRQ); + wlan_int_count[index] = kstat_irqs(BSP_PCIE_IRQ); + j = index - suspend_check_win_size; + if (j < 0) + j += INT_WINDOW_SIZE_MAX; + count = (eth_int_count[index] - eth_int_count[j]) + + (wlan_int_count[index]- wlan_int_count[j]); //unit: number of interrupt occurred + + if (cpu_can_suspend) { + if (count > suspend_check_high_water_mark) { + cpu_can_suspend = 0; + //printk("\n<<<RTL8196C LEAVE SLEEP>>>\n"); /* for Debug Only*/ + } + } + else { + if (count < suspend_check_low_water_mark) { + cpu_can_suspend = 1; + //printk("\n<<<RTL8196C ENTER SLEEP>>>\n"); /* for Debug Only*/ + } + } + #if 0 /* for Debug Only*/ + printk("###index=%d, count=%d (%d+%d) suspend=%d###\n",index, count, + (eth_int_count[index] - eth_int_count[j]), + (wlan_int_count[index]- wlan_int_count[j]), + cpu_can_suspend); + #endif + mod_timer(&suspend_check_timer, jiffies + 100); + } + + void suspend_check_interrupt_init(void) + { + struct proc_dir_entry *res; + int i; + + res = create_proc_entry("suspend_check", 0, NULL); + if (res) { + res->read_proc = read_proc_suspend_check; + res->write_proc = write_proc_suspend_check; + } + else { + printk("unable to create /proc/suspend_check\n"); + } + + for (i=0; i<INT_WINDOW_SIZE_MAX; i++) { + wlan_int_count[i] = 0; + eth_int_count[i] = 0; + } + init_timer(&suspend_check_timer); + suspend_check_timer.data = 0; + suspend_check_timer.function = suspend_check_timer_fn; + suspend_check_timer.expires = jiffies + 100; /* in jiffies */ + add_timer(&suspend_check_timer); + } + #endif // CONFIG_RTL819X_SUSPEND_CHECK_INTERRUPT + #endif //CONFIG_RTL8196C + |