Subject: Axon MPIC support This patch is to add support for the MPIC inside the Axon South Bridge. Signed-off-by: Shaun Wetzstein Signed-off-by: Murali Iyer Signed-off-by: Arnd Bergmann Index: linux-2.6/arch/powerpc/Kconfig =================================================================== --- linux-2.6.orig/arch/powerpc/Kconfig +++ linux-2.6/arch/powerpc/Kconfig @@ -448,6 +448,8 @@ config PPC_CELL_NATIVE bool select PPC_CELL select PPC_DCR + select MPIC + select MPIC_WEIRD default n config PPC_IBM_CELL_BLADE Index: linux-2.6/arch/powerpc/platforms/cell/setup.c =================================================================== --- linux-2.6.orig/arch/powerpc/platforms/cell/setup.c +++ linux-2.6/arch/powerpc/platforms/cell/setup.c @@ -47,9 +47,11 @@ #include #include #include +#include #include #include #include +#include #include "interrupt.h" #include "iommu.h" @@ -63,6 +65,18 @@ #define DBG(fmt...) #endif +static void cell_irq_cascade(unsigned int irq, struct irq_desc *desc, + struct pt_regs *regs) +{ + struct mpic *mpic = desc->handler_data; + unsigned int virq; + + virq = mpic_get_one_irq(mpic, regs); + if (virq != NO_IRQ) + generic_handle_irq(virq, regs); + desc->chip->eoi(irq); +} + static void cell_show_cpuinfo(struct seq_file *m) { struct device_node *root; @@ -88,10 +102,70 @@ static void __init cell_pcibios_fixup(vo pci_read_irq_line(dev); } +static void __init mpic_init_IRQ(void) +{ + struct device_node *dn; + struct mpic *mpic; + unsigned int virq; + unsigned long mpic_addr = 0; + int chip = 0; + u32 *res; + + /* XXX node numbers are totally bogus. We _hope_ we get the device + * nodes in the right order here but that's definitely not guaranteed, + * we need to get the node from the device tree instead. + * There is currently no proper property for it (but our whole + * device-tree is bogus anyway) so all we can do is pray or maybe test + * the address and deduce the node-id + */ + for (dn = NULL; + (dn = of_find_node_by_name(dn, "interrupt-controller"));) { + if (!device_is_compatible(dn, "CBEA,platform-open-pic")) + continue; + + /* ... it could be a DCR based device */ + res = get_property(dn, "dcr-reg", NULL); + if (res != NULL) { + mpic_addr = of_translate_dcr_address(dn, res); + if (mpic_addr == OF_BAD_ADDR) { + printk(KERN_WARNING + "mpic: Failed to find resource.\n"); + continue; + } + } else { + res = get_property(dn, "reg", NULL); + if (res != NULL) { + mpic_addr = of_translate_address(dn, res); + if (mpic_addr == OF_BAD_ADDR) { + printk(KERN_WARNING + "mpic: Failed to find resource.\n"); + continue; + } + } + } + + mpic = mpic_alloc(dn, mpic_addr, MPIC_BIG_ENDIAN | MPIC_REGSET_AXON, + 0, 128+4, " MPIC "); + if (mpic == NULL) + continue; + mpic_init(mpic); + + virq = irq_of_parse_and_map(dn, 0); + if (virq == NO_IRQ) + continue; + + printk(KERN_INFO "%s : hooking up to %i\n", dn->full_name, virq); + set_irq_data(virq, mpic); + set_irq_chained_handler(virq, cell_irq_cascade); + chip++; + } +} + static void __init cell_init_irq(void) { iic_init_IRQ(); spider_init_IRQ(); + mpic_init_IRQ(); } static void __init cell_setup_arch(void) Index: linux-2.6/arch/powerpc/sysdev/mpic.c =================================================================== --- linux-2.6.orig/arch/powerpc/sysdev/mpic.c +++ linux-2.6/arch/powerpc/sysdev/mpic.c @@ -12,10 +12,11 @@ * for more details. */ -#undef DEBUG -#undef DEBUG_IPI -#undef DEBUG_IRQ -#undef DEBUG_LOW +#define DEBUG +#define DEBUG_IPI +#define DEBUG_IRQ +#define DEBUG_LOW +#undef DEBUG_REG #include #include @@ -37,7 +38,7 @@ #include #ifdef DEBUG -#define DBG(fmt...) printk(fmt) +#define DBG(fmt...) udbg_printf(fmt) #else #define DBG(fmt...) #endif @@ -132,6 +133,44 @@ static u32 mpic_infos[][MPIC_IDX_END] = TSI108_VECPRI_SENSE_MASK, TSI108_IRQ_DESTINATION }, + [2] = { /* Axon MPIC */ + MPIC_GREG_BASE << 4, + MPIC_GREG_FEATURE_0 << 4, + MPIC_GREG_GLOBAL_CONF_0 << 4, + MPIC_GREG_VENDOR_ID << 4, + MPIC_GREG_IPI_VECTOR_PRI_0 << 4, + MPIC_GREG_IPI_STRIDE << 4, + MPIC_GREG_SPURIOUS << 4, + MPIC_GREG_TIMER_FREQ << 4, + + MPIC_TIMER_BASE << 4, + MPIC_TIMER_STRIDE << 4, + MPIC_TIMER_CURRENT_CNT << 4, + MPIC_TIMER_BASE_CNT << 4, + MPIC_TIMER_VECTOR_PRI << 4, + MPIC_TIMER_DESTINATION << 4, + + MPIC_CPU_BASE << 4, + MPIC_CPU_STRIDE << 4, + MPIC_CPU_IPI_DISPATCH_0 << 4, + MPIC_CPU_IPI_DISPATCH_STRIDE << 4, + MPIC_CPU_CURRENT_TASK_PRI << 4, + MPIC_CPU_WHOAMI << 4, + MPIC_CPU_INTACK << 4, + MPIC_CPU_EOI << 4, + + MPIC_IRQ_BASE << 4, + MPIC_IRQ_STRIDE << 4, + MPIC_IRQ_VECTOR_PRI << 4, + MPIC_VECPRI_VECTOR_MASK, + MPIC_VECPRI_POLARITY_POSITIVE, + MPIC_VECPRI_POLARITY_NEGATIVE, + MPIC_VECPRI_SENSE_LEVEL, + MPIC_VECPRI_SENSE_EDGE, + MPIC_VECPRI_POLARITY_MASK, + MPIC_VECPRI_SENSE_MASK, + MPIC_IRQ_DESTINATION << 4 + }, }; #define MPIC_INFO(name) mpic->hw_set[MPIC_IDX_##name] @@ -150,6 +189,9 @@ static u32 mpic_infos[][MPIC_IDX_END] = static inline u32 _mpic_read(unsigned int be, volatile u32 __iomem *base, unsigned int reg) { +#ifdef DEBUG_REG + DBG("mpic: _mpic_read(0x%p + 0x%x)\n", base, reg); +#endif if (be) return in_be32(base + (reg >> 2)); else @@ -159,6 +201,9 @@ static inline u32 _mpic_read(unsigned in static inline void _mpic_write(unsigned int be, volatile u32 __iomem *base, unsigned int reg, u32 value) { +#ifdef DEBUG_REG + DBG("mpic: _mpic_write(0x%p + 0x%x, 0x%x)\n", base, reg, value); +#endif if (be) out_be32(base + (reg >> 2), value); else @@ -897,11 +942,16 @@ struct mpic * __init mpic_alloc(struct d mpic->hw_set = mpic_infos[MPIC_GET_REGSET(flags)]; #endif - /* Map the global registers */ - mpic->gregs = ioremap(phys_addr + MPIC_INFO(GREG_BASE), 0x1000); + /* Map the registers */ + DBG("mpic: Mapping from phys_addr = 0x%lx\n", phys_addr); + mpic->gregs = ioremap(phys_addr + MPIC_INFO(GREG_BASE), 0x10000); mpic->tmregs = mpic->gregs + ((MPIC_INFO(TIMER_BASE) - MPIC_INFO(GREG_BASE)) >> 2); BUG_ON(mpic->gregs == NULL); + DBG("mpic: gregs = 0x%lx -> 0x%p\n", + phys_addr + MPIC_INFO(GREG_BASE), mpic->gregs); + DBG("mpic: tmregs = 0x%lx -> 0x%p\n", + phys_addr + MPIC_INFO(TIMER_BASE), mpic->tmregs); /* Reset */ if (flags & MPIC_WANTS_RESET) { @@ -926,16 +976,19 @@ struct mpic * __init mpic_alloc(struct d /* Map the per-CPU registers */ for (i = 0; i < mpic->num_cpus; i++) { - mpic->cpuregs[i] = ioremap(phys_addr + MPIC_INFO(CPU_BASE) + - i * MPIC_INFO(CPU_STRIDE), 0x1000); + unsigned long p = phys_addr + MPIC_INFO(CPU_BASE) + + i * MPIC_INFO(CPU_STRIDE); + mpic->cpuregs[i] = ioremap(p, 0x1000); + DBG("mpic: cpu%dregs = 0x%lx -> 0x%p\n", i, p, mpic->cpuregs[i]); BUG_ON(mpic->cpuregs[i] == NULL); } /* Initialize main ISU if none provided */ if (mpic->isu_size == 0) { + unsigned long p = phys_addr + MPIC_INFO(IRQ_BASE); mpic->isu_size = mpic->num_sources; - mpic->isus[0] = ioremap(phys_addr + MPIC_INFO(IRQ_BASE), - MPIC_INFO(IRQ_STRIDE) * mpic->isu_size); + mpic->isus[0] = ioremap(p, MPIC_INFO(IRQ_STRIDE) * mpic->isu_size); + DBG("mpic: mainisu = 0x%lx -> 0x%p\n", p, mpic->isus[0]); BUG_ON(mpic->isus[0] == NULL); } mpic->isu_shift = 1 + __ilog2(mpic->isu_size - 1); @@ -1007,6 +1060,8 @@ void __init mpic_init(struct mpic *mpic) /* Set current processor priority to max */ mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0xf); + DBG("mpic: Initializing timers\n"); + /* Initialize timers: just disable them all */ for (i = 0; i < 4; i++) { mpic_write(mpic->tmregs, @@ -1019,6 +1074,8 @@ void __init mpic_init(struct mpic *mpic) (MPIC_VEC_TIMER_0 + i)); } + DBG("mpic: Initializing IPIs\n"); + /* Initialize IPIs to our reserved vectors and mark them disabled for now */ mpic_test_broken_ipi(mpic); for (i = 0; i < 4; i++) { @@ -1037,6 +1094,8 @@ void __init mpic_init(struct mpic *mpic) if ((mpic->flags & MPIC_BROKEN_U3) && (mpic->flags & MPIC_PRIMARY)) mpic_scan_ht_pics(mpic); + DBG("mpic: Initializing sources\n"); + for (i = 0; i < mpic->num_sources; i++) { /* start with vector = source number, and masked */ u32 vecpri = MPIC_VECPRI_MASK | i | @@ -1048,6 +1107,8 @@ void __init mpic_init(struct mpic *mpic) 1 << hard_smp_processor_id()); } + DBG("mpic: Initializing misc\n"); + /* Init spurrious vector */ mpic_write(mpic->gregs, MPIC_INFO(GREG_SPURIOUS), MPIC_VEC_SPURRIOUS); Index: linux-2.6/include/asm-powerpc/mpic.h =================================================================== --- linux-2.6.orig/include/asm-powerpc/mpic.h +++ linux-2.6/include/asm-powerpc/mpic.h @@ -313,6 +313,7 @@ struct mpic #define MPIC_REGSET_STANDARD MPIC_REGSET(0) /* Original MPIC */ #define MPIC_REGSET_TSI108 MPIC_REGSET(1) /* Tsi108/109 PIC */ +#define MPIC_REGSET_AXON MPIC_REGSET(2) /* Axon MPIC */ /* Allocate the controller structure and setup the linux irq descs * for the range if interrupts passed in. No HW initialization is Index: linux-2.6/arch/powerpc/configs/cell_defconfig =================================================================== --- linux-2.6.orig/arch/powerpc/configs/cell_defconfig +++ linux-2.6/arch/powerpc/configs/cell_defconfig @@ -152,7 +152,7 @@ CONFIG_CPU_FREQ_GOV_ONDEMAND=y CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y # CONFIG_CPU_FREQ_PMAC64 is not set # CONFIG_WANT_EARLY_SERIAL is not set -# CONFIG_MPIC is not set +CONFIG_MPIC=y # # Cell Broadband Engine options @@ -214,7 +214,7 @@ CONFIG_ISA_DMA_API=y # Bus options # CONFIG_GENERIC_ISA_DMA=y -# CONFIG_MPIC_WEIRD is not set +CONFIG_MPIC_WEIRD=y # CONFIG_PPC_I8259 is not set # CONFIG_PPC_INDIRECT_PCI is not set CONFIG_PCI=y