/** * Copyright (C) 2010-2014 Ikanos Communications. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. * * Info : VX185 interrupt routines. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef CONFIG_SMP #include #endif #include #include /* #include */ #if defined (CONFIG_CPU_MIPSR2_IRQ_VI) #include #endif #undef DEBUG_IRQ #ifdef DEBUG_IRQ /* note: prints function name for you */ #define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args) #else #define DPRINTK(fmt, args...) #endif int gcmp_present = -1; extern unsigned int gic_present; unsigned long _gcmp_base; extern unsigned int getIntCtl_IPTI(void); //void __init gcmp_setregion(void); #if defined(CONFIG_MIPS_MT_SMP) static int gic_resched_int_base; static int gic_call_int_base; #define MIPSCPU_INT_IPI0 3 #define MIPSCPU_INT_IPI1 4 #define GIC_RESCHED_INT(cpu) (gic_resched_int_base+(cpu)) #define GIC_CALL_INT(cpu) (gic_call_int_base+(cpu)) #endif #define MIPS_GIC_IRQ_BASE 8 #if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_MIPS_CPS) static void fusiv_ipi_irqdispatch(void); static unsigned int ipi_map[NR_CPUS]; #endif #if defined (CONFIG_CPU_MIPSR2_IRQ_VI) extern void __init mips_cpu_irq_init(void); #endif /* Declare per interrupt bit map */ DECLARE_BITMAP(hw0_ints, GIC_NUM_INTRS); DECLARE_BITMAP(hw1_ints, GIC_NUM_INTRS); DECLARE_BITMAP(hw2_ints, GIC_NUM_INTRS); DECLARE_BITMAP(hw3_ints, GIC_NUM_INTRS); DECLARE_BITMAP(hw4_ints, GIC_NUM_INTRS); asmlinkage void plat_irq_dispatch(void) { unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM; printk("entered plat_irq_dispatch with pending as %d\r\n", pending); printk("spurious.....spurious.....spurious.......spurious\r\n"); } #define GIC_BASE_ADDR 0x19940000 #define GIC_ADDRSPACE_SZ (128 * 1024) int __init gcmp_probe(unsigned long addr, unsigned long size) { unsigned int mask_gic = 0x0001FFFF; unsigned int enable_gic = 0x1; volatile unsigned int *i; unsigned int j; _gcmp_base = (unsigned long)ioremap_nocache(addr, size); i = (volatile unsigned int *)(_gcmp_base + 0xd0); if (*i == enable_gic) { gic_present = 1; i = (volatile unsigned int *)(_gcmp_base + 0x80); j = *i; j = ((j & mask_gic) | GIC_BASE_ADDR | enable_gic); *i = j; } i = (volatile unsigned int *)(_gcmp_base + 0x08); gcmp_present = (GCMPGCB(GCMPB) & GCMP_GCB_GCMPB_GCMPBASE_MSK) == addr; if (gcmp_present) printk("GCMP Probe completed successfully\n"); return gcmp_present; } #if 0 /* TODO: This API is not used anywhere and it is empty -- VB */ void __init gcmp_setregion() { // GCMPGCBn(CMxBASE, region) = base; // GCMPGCBn(CMxMASK, region) = mask | type; } #endif #if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_MIPS_CPS) static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id) { scheduler_ipi(); return IRQ_HANDLED; } static irqreturn_t ipi_call_interrupt(int irq, void *dev_id) { smp_call_function_interrupt(); return IRQ_HANDLED; } static struct irqaction irq_resched = { .handler = ipi_resched_interrupt, .flags = IRQF_PERCPU, .name = "IPI_resched" }; static struct irqaction irq_call = { .handler = ipi_call_interrupt, .flags = IRQF_PERCPU, .name = "IPI_call" }; void __init arch_init_ipiirq(int irq, struct irqaction *action) { setup_irq(irq, action); irq_set_handler(irq, handle_percpu_irq); } #endif /* CONFIG_MIPS_MT_SMP */ #if defined (CONFIG_CPU_MIPSR2_IRQ_VI) void mipscpu_int_hw5_dispatch(void) { do_IRQ(MIPSCPU_INT_HW5); } void mipscpu_int_hw4_dispatch(void) { unsigned long irq; DECLARE_BITMAP(pending, GIC_NUM_INTRS); gic_get_int_mask(pending, hw4_ints); irq = find_first_bit(pending, GIC_NUM_INTRS); while (irq < GIC_NUM_INTRS) { do_IRQ(MIPS_GIC_IRQ_BASE + irq); irq = find_next_bit(pending, GIC_NUM_INTRS, irq + 1); } } void mipscpu_int_hw3_dispatch(void) { unsigned long irq; DECLARE_BITMAP(pending, GIC_NUM_INTRS); gic_get_int_mask(pending, hw3_ints); irq = find_first_bit(pending, GIC_NUM_INTRS); while (irq < GIC_NUM_INTRS) { do_IRQ(MIPS_GIC_IRQ_BASE + irq); irq = find_next_bit(pending, GIC_NUM_INTRS, irq + 1); } } void mipscpu_int_hw2_dispatch(void) { unsigned long irq; DECLARE_BITMAP(pending, GIC_NUM_INTRS); gic_get_int_mask(pending, hw2_ints); irq = find_first_bit(pending, GIC_NUM_INTRS); while (irq < GIC_NUM_INTRS) { do_IRQ(MIPS_GIC_IRQ_BASE + irq); irq = find_next_bit(pending, GIC_NUM_INTRS, irq + 1); } } void mipscpu_int_hw1_dispatch(void) { unsigned long irq; DECLARE_BITMAP(pending, GIC_NUM_INTRS); gic_get_int_mask(pending, hw1_ints); irq = find_first_bit(pending, GIC_NUM_INTRS); while (irq < GIC_NUM_INTRS) { do_IRQ(MIPS_GIC_IRQ_BASE + irq); irq = find_next_bit(pending, GIC_NUM_INTRS, irq + 1); } } void mipscpu_int_hw0_dispatch(void) { unsigned long irq; DECLARE_BITMAP(pending, GIC_NUM_INTRS); gic_get_int_mask(pending, hw0_ints); irq = find_first_bit(pending, GIC_NUM_INTRS); while (irq < GIC_NUM_INTRS) { do_IRQ(MIPS_GIC_IRQ_BASE + irq); irq = find_next_bit(pending, GIC_NUM_INTRS, irq + 1); } } void setup_vint_handlers(void) { //The despatch for h/w int 5 is defined in plat_time.c file set_vi_handler(MIPSCPU_INT_HW4, mipscpu_int_hw4_dispatch); set_vi_handler(MIPSCPU_INT_HW3, mipscpu_int_hw3_dispatch); set_vi_handler(MIPSCPU_INT_HW2, mipscpu_int_hw2_dispatch); set_vi_handler(MIPSCPU_INT_HW1, mipscpu_int_hw1_dispatch); set_vi_handler(MIPSCPU_INT_HW0, mipscpu_int_hw0_dispatch); } #endif //CONFIG_CPU_MIPSR2_IRQ_VI /* GIC_CPU_INT3 - IPI0 GIC_CPU_INT4 - IPI1 GIC_CPU_INT5 - Periodic Timer */ #define X GIC_UNUSED #ifdef CONFIG_MIPS_MT_SMP static struct gic_intr_map gic_intr_map[GIC_NUM_INTRS] = { {X, X, X, X, X}, /* 0 */ {X, X, X, X, X}, /* 1 */ {X, X, X, X, X}, /* 2 */ {X, X, X, X, X}, /* 3 */ {X, X, X, X, X}, /* 4 */ {X, X, X, X, X}, /* 5 */ {X, X, X, X, X}, /* 6 */ {X, X, X, X, X}, /* 7 */ {X, X, X, X, X}, /* 8 */ {X, X, X, X, X}, /* 9 */ {X, X, X, X, X}, /* 10 */ {X, X, X, X, X}, /* 11 */ {X, X, X, X, X}, /* 12 */ {X, X, X, X, X}, /* 13 */ {0, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_LEVEL, 0}, /* 14 */ {0, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_LEVEL, 0}, /* 15 */ {0, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_LEVEL, 0}, /* 16 */ {0, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_LEVEL, 0}, /* 17 */ {0, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_LEVEL, 0}, /* 18 */ {0, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_LEVEL, 0}, /* 19 */ {0, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_LEVEL, 0}, /* 20 */ {0, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_LEVEL, 0}, /* 21 */ {0, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_LEVEL, 0}, /* 22 */ {0, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_LEVEL, 0}, /* 23 */ {0, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_LEVEL, 0}, /* 24 */ {0, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_LEVEL, 0}, /* 25 */ /* UART CPU0 pin 2 */ {0, GIC_CPU_INT0, GIC_POL_POS, GIC_TRIG_LEVEL, 0}, /* 26 */ {X, X, X, X, X}, /* 27 */ {X, X, X, X, X}, /* 28 */ {X, X, X, X, X}, /* 29 */ {X, X, X, X, X}, /* 30 */ {X, X, X, X, X}, /* 31 */ {X, X, X, X, X}, /* 32 */ {X, X, X, X, X}, /* 33 */ {X, X, X, X, X}, /* 34 */ {X, X, X, X, X}, /* 35 */ {X, X, X, X, X}, /* 36 */ {X, X, X, X, X}, /* 37 */ {X, X, X, X, X}, /* 38 */ {X, X, X, X, X}, /* 39 */ {X, X, X, X, X}, /* 40 */ {X, X, X, X, X}, /* 41 */ {X, X, X, X, X}, /* 42 */ {X, X, X, X, X}, /* 43 */ {X, X, X, X, X}, /* 44 */ {X, X, X, X, X}, /* 45 */ /* SATA CPU3 pin 2 */ {0, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_LEVEL, 0}, /* 46 */ /* WLAN0 CPU2 pin 5 */ {2, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_LEVEL, 0}, /* 47 */ /* WLAN1 CPU3 pin 5 */ {3, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_LEVEL, 0}, /* 48 */ /* USB CPU1 pin 2 */ {1, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_LEVEL, 0}, /* 49 */ {X, X, X, X, X}, /* 50 */ {X, X, X, X, X}, /* 51 */ {X, X, X, X, X}, /* 52 */ {X, X, X, X, X}, /* 53 */ /* CL0 CPU0 pin 6 */ {0, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_LEVEL, 0}, /* 54 */ /* CL1 CPU 3 pin 6 */ {3, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_LEVEL, 0}, /* 55 */ /* BMU AP CPU 3 pin 2 */ {0, GIC_CPU_INT1, GIC_POL_POS, GIC_TRIG_LEVEL, 0}, /* 56 */ /* SPA CPU 2 pin 6*/ {2, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_LEVEL, 0}, /* 57 */ {X, X, X, X, X}, /* 58 */ {X, X, X, X, X}, /* 59 */ {X, X, X, X, X}, /* 60 */ {X, X, X, X, X}, /* 61 */ {X, X, X, X, X}, /* 62 */ {X, X, X, X, X}, /* 63 */ {X, X, X, X, X}, /* 64 */ {X, X, X, X, X}, /* 65 */ {X, X, X, X, X}, /* 66 */ {X, X, X, X, X}, /* 67 */ {X, X, X, X, X}, /* 68 */ {X, X, X, X, X}, /* 69 */ /* MailBox B2H CPU */ {0, GIC_CPU_INT1, GIC_POL_POS, GIC_TRIG_LEVEL, 0}, /* 70 */ /* MailBox H2B */ {X, X, X, X, X}, /* 71 */ {X, X, X, X, X}, /* 72 */ {X, X, X, X, X}, /* 73 */ {X, X, X, X, X}, /* 74 */ {X, X, X, X, X}, /* 75 */ /* CL3 CPU1 pin 1 */ {1, GIC_CPU_INT1, GIC_POL_POS, GIC_TRIG_LEVEL, 0}, /* 76 */ /* HOSTAP CPU 2 pin 2*/ { 2, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_LEVEL, 0 }, /* 77 */ {X, X, X, X, X}, /* 78 */ {X, X, X, X, X}, /* 79 */ {X, X, X, X, X}, /* 80 */ {X, X, X, X, X}, /* 81 */ {X, X, X, X, X}, /* 82 */ {X, X, X, X, X}, /* 83 */ {X, X, X, X, X}, /* 84 */ {X, X, X, X, X}, /* 85 */ {X, X, X, X, X}, /* 86 */ {X, X, X, X, X}, /* 87 */ {X, X, X, X, X}, /* 88 */ {X, X, X, X, X}, /* 89 */ {X, X, X, X, X}, /* 90 */ {X, X, X, X, X}, /* 91 */ {X, X, X, X, X}, /* 92 */ {X, X, X, X, X}, /* 93 */ {X, X, X, X, X}, /* 94 */ {X, X, X, X, X}, /* 95 */ {X, X, X, X, X}, /* 96 */ {X, X, X, X, X}, /* 97 */ {X, X, X, X, X}, /* 98 */ {X, X, X, X, X}, /* 99 */ {X, X, X, X, X}, /* 100 */ {X, X, X, X, X}, /* 101 */ {X, X, X, X, X}, /* 102 */ {X, X, X, X, X}, /* 103 */ {X, X, X, X, X}, /* 104 */ {X, X, X, X, X}, /* 105 */ {X, X, X, X, X}, /* 106 */ {X, X, X, X, X}, /* 107 */ {X, X, X, X, X}, /* 108 */ {X, X, X, X, X}, /* 109 */ {X, X, X, X, X}, /* 110 */ {X, X, X, X, X}, /* 111 */ {X, X, X, X, X}, /* 112 */ {X, X, X, X, X}, /* 113 */ {X, X, X, X, X}, /* 114 */ {X, X, X, X, X}, /* 115 */ {X, X, X, X, X}, /* 116 */ {X, X, X, X, X}, /* 117 */ {X, X, X, X, X}, /* 118 */ {X, X, X, X, X}, /* 119 */ /* The remainder of this table is initialised by fill_ipi_map */ }; #endif #undef X #if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_MIPS_CPS) static void __init fill_ipi_map1(int baseintr, int cpu, int cpupin) { int intr = baseintr + cpu; gic_intr_map[intr].cpunum = cpu; gic_intr_map[intr].pin = cpupin; gic_intr_map[intr].polarity = GIC_POL_POS; gic_intr_map[intr].trigtype = GIC_TRIG_EDGE; gic_intr_map[intr].flags = 0; ipi_map[cpu] |= (1 << (cpupin + 2)); } static void __init fill_ipi_map(void) { int cpu; for (cpu = 0; cpu < NR_CPUS; cpu++) { fill_ipi_map1(gic_resched_int_base, cpu, GIC_CPU_INT1); fill_ipi_map1(gic_call_int_base, cpu, GIC_CPU_INT2); } } #endif void __init fusiv_init_IRQ(void) { #if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_MIPS_CPS) int i; #endif int gic_num; unsigned long cp0_status; cp0_status = read_c0_status(); printk("The value of MVPControl register is %x\r\n", read_c0_mvpcontrol()); printk("The value of 16 select 0 register is %x\r\n", read_c0_config()); printk("Initializing IPC..\r\n"); #if defined (CONFIG_CPU_MIPSR2_IRQ_VI) /* Initialize IRQ descriptor for six MIPS interrupt lines (2-7) */ if (!cpu_has_veic && cpu_has_vint) { mips_cpu_irq_init(); if (gic_present) { #if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_MIPS_CPS) gic_call_int_base = GIC_NUM_INTRS - NR_CPUS; gic_resched_int_base = gic_call_int_base - NR_CPUS; fill_ipi_map(); #endif gic_init(GIC_BASE_ADDR, GIC_ADDRSPACE_SZ, gic_intr_map, ARRAY_SIZE(gic_intr_map), MIPS_GIC_IRQ_BASE); #if defined(CONFIG_MIPS_MT_SMP) bitmap_set(hw0_ints, 26, 1); /* Serial interrupt bit map set */ bitmap_set(hw1_ints, 56, 1); /* BMU Interrupts */ bitmap_set(hw1_ints, 70, 1); /* B2H Interrupts */ bitmap_set(hw1_ints, 76, 1); /* CL3 */ bitmap_set(hw2_ints, 14, 12); /* DSP and HSPORT interrupts bit map set */ bitmap_set(hw2_ints, 46, 4); /* SATA */ bitmap_set(hw2_ints, 54, 2); /* CL0,CL1 */ bitmap_set(hw2_ints,57,1); /* SPA */ bitmap_set(hw2_ints,77,1); /* HOSTAP */ #endif setup_vint_handlers(); // Currently handling all GIC interrupts as Level triggered // Timer requires edge triggered handling which needs to be done later #if defined(CONFIG_MIPS_MT_SMP) for (gic_num = 0; gic_num <= (GIC_NUM_INTRS - 2 * NR_CPUS); gic_num++) irq_set_handler((gic_num + MIPS_GIC_IRQ_BASE), handle_level_irq); #else for (gic_num = 0; gic_num <= GIC_NUM_INTRS; gic_num++) irq_set_handler((gic_num + MIPS_GIC_IRQ_BASE), handle_level_irq); #endif __asm__ __volatile("ehb"); #if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_MIPS_CPS) /* set up ipi interrupts */ if (cpu_has_vint) { set_vi_handler(MIPSCPU_INT_IPI0, fusiv_ipi_irqdispatch); set_vi_handler(MIPSCPU_INT_IPI1, fusiv_ipi_irqdispatch); } /* Argh.. this really needs sorting out.. */ printk("CPU%d: status register now %08x\n", smp_processor_id(), read_c0_status()); write_c0_status(0x11009c00); printk("CPU%d: status register frc %08x\n", smp_processor_id(), read_c0_status()); for (i = 0; i < NR_CPUS; i++) { arch_init_ipiirq(MIPS_GIC_IRQ_BASE + GIC_RESCHED_INT(i), &irq_resched); arch_init_ipiirq(MIPS_GIC_IRQ_BASE + GIC_CALL_INT(i), &irq_call); } #endif } #endif #ifdef CONFIG_KGDB /* If local serial I/O used for debug port, enter kgdb at once */ puts("Waiting for kgdb to connect..."); set_debug_traps(); breakpoint(); #endif } printk("Fusiv IPC INIT COMPLETe\n\r"); } void gic_enable_interrupt(int irq_vec) { GIC_SET_INTR_MASK(irq_vec); } void gic_disable_interrupt(int irq_vec) { GIC_CLR_INTR_MASK(irq_vec); } void gic_irq_ack(struct irq_data *d) { int irq = (d->irq - gic_irq_base); GIC_CLR_INTR_MASK(irq); if (gic_irq_flags[irq] & GIC_TRIG_EDGE) GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), irq); } void gic_finish_irq(struct irq_data *d) { int irq = (d->irq - gic_irq_base); GIC_SET_INTR_MASK(irq); } void __init gic_platform_init(int irqs, struct irq_chip *irq_controller) { int i; for (i = gic_irq_base; i < (gic_irq_base + irqs); i++) { irq_set_chip(i, irq_controller); } } #if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_MIPS_CPS) static void fusiv_ipi_irqdispatch(void) { unsigned int irq; irq = gic_get_int(); if ((irq < 0) || (irq >= GIC_NUM_INTRS)) return; /* interrupt has already been cleared */ do_IRQ(MIPS_GIC_IRQ_BASE + irq); } unsigned int plat_ipi_call_int_xlate(unsigned int cpu) { return GIC_CALL_INT(cpu); } unsigned int plat_ipi_resched_int_xlate(unsigned int cpu) { return GIC_RESCHED_INT(cpu); } #endif