source: branches/buildroot-ng/openwrt/target/linux/aruba-2.6/patches/002-irq.patch @ 5057

Last change on this file since 5057 was 5057, checked in by mbm, 10 years ago

rewrite of platform irq handler

File size: 7.3 KB
  • arch/mips/aruba/irq.c

    diff -Nur linux-2.6.17/arch/mips/aruba/irq.c linux-2.6.17-openwrt/arch/mips/aruba/irq.c
    old new  
     1#include <linux/errno.h> 
     2#include <linux/init.h> 
     3#include <linux/kernel_stat.h> 
     4#include <linux/module.h> 
     5#include <linux/signal.h> 
     6#include <linux/sched.h> 
     7#include <linux/types.h> 
     8#include <linux/interrupt.h> 
     9#include <linux/ioport.h> 
     10#include <linux/timex.h> 
     11#include <linux/slab.h> 
     12#include <linux/random.h> 
     13#include <linux/delay.h> 
     14 
     15#include <asm/bitops.h> 
     16#include <asm/bootinfo.h> 
     17#include <asm/io.h> 
     18#include <asm/mipsregs.h> 
     19#include <asm/system.h> 
     20#include <asm/idt-boards/rc32434/rc32434.h> 
     21#include <asm/idt-boards/rc32434/rc32434_gpio.h> 
     22 
     23#include <asm/irq.h> 
     24 
     25extern void aruba_timer_interrupt(struct pt_regs *regs); 
     26 
     27typedef struct { 
     28        u32 mask; 
     29        volatile u32 *base_addr; 
     30} intr_group_t; 
     31 
     32static const intr_group_t intr_group_merlot[NUM_INTR_GROUPS] = { 
     33        {0x00000000, (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 0)}, 
     34}; 
     35 
     36#define READ_PEND_MERLOT(base) (*((volatile unsigned long *)(0xbc003010))) 
     37#define READ_MASK_MERLOT(base) (*((volatile unsigned long *)(0xbc003014))) 
     38#define WRITE_MASK_MERLOT(base, val) ((*((volatile unsigned long *)(0xbc003014))) = (val), READ_MASK_MERLOT()) 
     39 
     40static const intr_group_t intr_group_muscat[NUM_INTR_GROUPS] = { 
     41        {0x0000efff, (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 0 * IC_GROUP_OFFSET)}, 
     42        {0x00001fff, (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 1 * IC_GROUP_OFFSET)}, 
     43        {0x00000007, (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 2 * IC_GROUP_OFFSET)}, 
     44        {0x0003ffff, (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 3 * IC_GROUP_OFFSET)}, 
     45        {0xffffffff, (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 4 * IC_GROUP_OFFSET)} 
     46}; 
     47 
     48#define READ_PEND_MUSCAT(base) (*(base)) 
     49#define READ_MASK_MUSCAT(base) (*(base + 2)) 
     50#define WRITE_MASK_MUSCAT(base, val) (*(base + 2) = (val)) 
     51 
     52static inline int group_to_ip(unsigned int group) 
     53{ 
     54        switch (mips_machtype) { 
     55                case MACH_ARUBA_AP70: 
     56                        return group + 2; 
     57                case MACH_ARUBA_AP65: 
     58                case MACH_ARUBA_AP60: 
     59                default: 
     60                        return 6; 
     61        } 
     62} 
     63 
     64static inline void enable_local_irq(unsigned int irq) 
     65{ 
     66        clear_c0_cause(0x100 << irq); 
     67        set_c0_status(0x100 << irq); 
     68        irq_enable_hazard(); 
     69} 
     70 
     71static inline void disable_local_irq(unsigned int irq) 
     72{ 
     73        clear_c0_status(0x100 << irq); 
     74        clear_c0_cause(0x100 << irq); 
     75        irq_disable_hazard(); 
     76} 
     77 
     78static inline void aruba_irq_enable(unsigned int irq) 
     79{ 
     80        unsigned long flags; 
     81        unsigned int  group, intr_bit; 
     82        volatile unsigned int  *addr; 
     83 
     84        local_irq_save(flags); 
     85 
     86        if (irq < GROUP0_IRQ_BASE) { 
     87                enable_local_irq(irq); 
     88        } else { 
     89                int ip = irq - GROUP0_IRQ_BASE; 
     90                switch (mips_machtype) { 
     91                        case MACH_ARUBA_AP70: 
     92                                // irqs are in groups of 32 
     93                                // ip is set to the remainder 
     94                                group = ip >> 5; 
     95                                ip &= 0x1f; 
     96 
     97                                // bit -> 0 = unmask 
     98                                intr_bit = 1 << ip; 
     99                                addr = intr_group_muscat[group].base_addr; 
     100                                WRITE_MASK_MUSCAT(addr, READ_MASK_MUSCAT(addr) & ~intr_bit); 
     101                                break; 
     102 
     103                        case MACH_ARUBA_AP65: 
     104                        case MACH_ARUBA_AP60: 
     105                                group = 0; 
     106 
     107                                // bit -> 1 = unmasked 
     108                                intr_bit = 1 << ip; 
     109                                addr = intr_group_merlot[group].base_addr; 
     110                                WRITE_MASK_MERLOT(addr, READ_MASK_MERLOT(addr) | intr_bit); 
     111                                break; 
     112                } 
     113                enable_local_irq(group_to_ip(group)); 
     114        } 
     115 
     116        back_to_back_c0_hazard(); 
     117        local_irq_restore(flags); 
     118} 
     119 
     120static void aruba_irq_disable(unsigned int irq) 
     121{ 
     122        unsigned long flags; 
     123        unsigned int  group, intr_bit, mask; 
     124        volatile unsigned int  *addr; 
     125 
     126        local_irq_save(flags); 
     127 
     128        if (irq < GROUP0_IRQ_BASE) { 
     129                disable_local_irq(irq); 
     130        } else { 
     131                int ip = irq - GROUP0_IRQ_BASE; 
     132                switch (mips_machtype) { 
     133                        case MACH_ARUBA_AP70: 
     134                                idt_gpio->gpioistat &= ~(1 << ip); 
     135 
     136                                // irqs are in groups of 32 
     137                                // ip is set to the remainder 
     138                                group = ip >> 5; 
     139                                ip &= 0x1f; 
     140 
     141                                // bit -> 1 = mask 
     142                                intr_bit = 1 << ip; 
     143                                addr = intr_group_muscat[group].base_addr; 
     144 
     145                                mask = READ_MASK_MUSCAT(addr); 
     146                                mask |= intr_bit; 
     147                                WRITE_MASK_MUSCAT(addr, mask); 
     148 
     149                                if (mask == intr_group_muscat[group].mask) { 
     150                                        disable_local_irq(group_to_ip(group)); 
     151                                } 
     152                                break; 
     153 
     154                        case MACH_ARUBA_AP65: 
     155                        case MACH_ARUBA_AP60: 
     156                                group = 0; 
     157 
     158                                // bit -> 0 = masked 
     159                                intr_bit = 1 << ip; 
     160                                addr = intr_group_merlot[group].base_addr; 
     161 
     162                                mask = READ_MASK_MERLOT(addr); 
     163                                mask &= ~intr_bit; 
     164                                WRITE_MASK_MERLOT(addr, mask); 
     165 
     166                                if (mask == intr_group_merlot[group].mask) { 
     167                                        disable_local_irq(group_to_ip(group)); 
     168                                } 
     169                                break; 
     170                } 
     171        } 
     172 
     173        back_to_back_c0_hazard(); 
     174        local_irq_restore(flags); 
     175} 
     176 
     177static unsigned int aruba_irq_startup(unsigned int irq) 
     178{ 
     179        aruba_irq_enable(irq); 
     180        return 0; 
     181} 
     182 
     183#define aruba_irq_shutdown aruba_irq_disable 
     184 
     185static void aruba_irq_ack(unsigned int irq) 
     186{ 
     187        aruba_irq_disable(irq); 
     188} 
     189 
     190static void aruba_irq_end(unsigned int irq) 
     191{ 
     192        if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) 
     193                aruba_irq_enable(irq); 
     194} 
     195 
     196static struct hw_interrupt_type aruba_irq_type = { 
     197        .typename       = "ARUBA", 
     198        .startup        = aruba_irq_startup, 
     199        .shutdown       = aruba_irq_shutdown, 
     200        .enable         = aruba_irq_enable, 
     201        .disable        = aruba_irq_disable, 
     202        .ack            = aruba_irq_ack, 
     203        .end            = aruba_irq_end, 
     204}; 
     205 
     206void __init arch_init_irq(void) 
     207{ 
     208        int i; 
     209        printk("Initializing IRQ's: %d out of %d\n", RC32434_NR_IRQS, NR_IRQS); 
     210        memset(irq_desc, 0, sizeof(irq_desc)); 
     211 
     212        for (i = 0; i < RC32434_NR_IRQS; i++) { 
     213                irq_desc[i].status = IRQ_DISABLED; 
     214                irq_desc[i].action = NULL; 
     215                irq_desc[i].depth = 1; 
     216                irq_desc[i].handler = &aruba_irq_type; 
     217                spin_lock_init(&irq_desc[i].lock); 
     218        } 
     219} 
     220 
     221/* Main Interrupt dispatcher */ 
     222 
     223void plat_irq_dispatch(struct pt_regs *regs) 
     224{ 
     225        unsigned int pend, group, ip; 
     226        volatile unsigned int *addr; 
     227        unsigned long cp0_cause = read_c0_cause() & read_c0_status() & CAUSEF_IP; 
     228 
     229        if (cp0_cause & CAUSEF_IP7) 
     230                return aruba_timer_interrupt(regs); 
     231 
     232        if(cp0_cause == 0) { 
     233                printk("INTERRUPT(S) FIRED WHILE MASKED\n"); 
     234#ifdef ARUBA_DEBUG 
     235                // debuging use -- figure out which interrupt(s) fired 
     236                cp0_cause = read_c0_cause() & CAUSEF_IP; 
     237                while (cp0_cause) { 
     238                        unsigned long intr_bit; 
     239                        unsigned int irq_nr; 
     240                        intr_bit = (31 - rc32434_clz(cp0_cause)); 
     241                        irq_nr = intr_bit - GROUP0_IRQ_BASE; 
     242                        printk(" ---> MASKED IRQ %d\n",irq_nr); 
     243                        cp0_cause &= ~(1 << intr_bit); 
     244                } 
     245#endif 
     246                return; 
     247        } 
     248 
     249        switch (mips_machtype) { 
     250                case MACH_ARUBA_AP70: 
     251                        if ((ip = (cp0_cause & 0x7c00))) { 
     252                                group = 21 - rc32434_clz(ip); 
     253                 
     254                                addr = intr_group_muscat[group].base_addr; 
     255                 
     256                                pend = READ_PEND_MUSCAT(addr); 
     257                                pend &= ~READ_MASK_MUSCAT(addr); // only unmasked interrupts 
     258                                pend = 39 - rc32434_clz(pend); 
     259                                do_IRQ(pend + (group << 5), regs); 
     260                        } 
     261                        break; 
     262                case MACH_ARUBA_AP65: 
     263                case MACH_ARUBA_AP60: 
     264                default: 
     265                        if (cp0_cause & 0x4000) { // 1 << (8 +6) == irq 6 
     266                                // Misc Interrupt 
     267                                group = 0; 
     268 
     269                                addr = intr_group_merlot[group].base_addr; 
     270 
     271                                pend = READ_PEND_MERLOT(addr); 
     272                                pend &= READ_MASK_MERLOT(addr); // only unmasked interrupts 
     273                                pend = 31 - rc32434_clz(pend); 
     274                                do_IRQ(pend + GROUP0_IRQ_BASE, regs); 
     275                        } 
     276                        if ((ip = (cp0_cause & 0x3c00))) { // irq 2-5 
     277                                pend = 31 - rc32434_clz(ip); 
     278                                do_IRQ(pend - GROUP0_IRQ_BASE, regs); 
     279                        } 
     280                        break; 
     281        } 
     282} 
Note: See TracBrowser for help on using the repository browser.