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  + | 
