From: Martyn Welch Date: Mon, 12 Mar 2012 17:12:59 +0000 (+0000) Subject: powerpc: Move GE PIC drivers X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=44b24b74abc37e3c0f28c8288178056f10074863;p=GitHub%2Fmoto-9609%2Fandroid_kernel_motorola_exynos9610.git powerpc: Move GE PIC drivers Move the GE PIC drivers to allow these to be used by non-86xx boards. Signed-off-by: Martyn Welch Signed-off-by: Kumar Gala --- diff --git a/arch/powerpc/platforms/86xx/Kconfig b/arch/powerpc/platforms/86xx/Kconfig index abe2c4fff811..7a6279e38213 100644 --- a/arch/powerpc/platforms/86xx/Kconfig +++ b/arch/powerpc/platforms/86xx/Kconfig @@ -64,10 +64,6 @@ config GEF_SBC610 help This option enables support for the GE SBC610. -config GE_FPGA - bool - default n - endif config MPC8641 diff --git a/arch/powerpc/platforms/86xx/Makefile b/arch/powerpc/platforms/86xx/Makefile index 1ee6ca8e53f7..ede815d6489d 100644 --- a/arch/powerpc/platforms/86xx/Makefile +++ b/arch/powerpc/platforms/86xx/Makefile @@ -7,7 +7,6 @@ obj-$(CONFIG_SMP) += mpc86xx_smp.o obj-$(CONFIG_MPC8641_HPCN) += mpc86xx_hpcn.o obj-$(CONFIG_SBC8641D) += sbc8641d.o obj-$(CONFIG_MPC8610_HPCD) += mpc8610_hpcd.o -obj-$(CONFIG_GE_FPGA) += gef_pic.o obj-$(CONFIG_GEF_SBC610) += gef_sbc610.o obj-$(CONFIG_GEF_SBC310) += gef_sbc310.o obj-$(CONFIG_GEF_PPC9A) += gef_ppc9a.o diff --git a/arch/powerpc/platforms/86xx/gef_pic.c b/arch/powerpc/platforms/86xx/gef_pic.c deleted file mode 100644 index 94594e58594c..000000000000 --- a/arch/powerpc/platforms/86xx/gef_pic.c +++ /dev/null @@ -1,252 +0,0 @@ -/* - * Interrupt handling for GE FPGA based PIC - * - * Author: Martyn Welch - * - * 2008 (c) GE Intelligent Platforms Embedded Systems, Inc. - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "gef_pic.h" - -#define DEBUG -#undef DEBUG - -#ifdef DEBUG -#define DBG(fmt...) do { printk(KERN_DEBUG "gef_pic: " fmt); } while (0) -#else -#define DBG(fmt...) do { } while (0) -#endif - -#define GEF_PIC_NUM_IRQS 32 - -/* Interrupt Controller Interface Registers */ -#define GEF_PIC_INTR_STATUS 0x0000 - -#define GEF_PIC_INTR_MASK(cpu) (0x0010 + (0x4 * cpu)) -#define GEF_PIC_CPU0_INTR_MASK GEF_PIC_INTR_MASK(0) -#define GEF_PIC_CPU1_INTR_MASK GEF_PIC_INTR_MASK(1) - -#define GEF_PIC_MCP_MASK(cpu) (0x0018 + (0x4 * cpu)) -#define GEF_PIC_CPU0_MCP_MASK GEF_PIC_MCP_MASK(0) -#define GEF_PIC_CPU1_MCP_MASK GEF_PIC_MCP_MASK(1) - - -static DEFINE_RAW_SPINLOCK(gef_pic_lock); - -static void __iomem *gef_pic_irq_reg_base; -static struct irq_host *gef_pic_irq_host; -static int gef_pic_cascade_irq; - -/* - * Interrupt Controller Handling - * - * The interrupt controller handles interrupts for most on board interrupts, - * apart from PCI interrupts. For example on SBC610: - * - * 17:31 RO Reserved - * 16 RO PCI Express Doorbell 3 Status - * 15 RO PCI Express Doorbell 2 Status - * 14 RO PCI Express Doorbell 1 Status - * 13 RO PCI Express Doorbell 0 Status - * 12 RO Real Time Clock Interrupt Status - * 11 RO Temperature Interrupt Status - * 10 RO Temperature Critical Interrupt Status - * 9 RO Ethernet PHY1 Interrupt Status - * 8 RO Ethernet PHY3 Interrupt Status - * 7 RO PEX8548 Interrupt Status - * 6 RO Reserved - * 5 RO Watchdog 0 Interrupt Status - * 4 RO Watchdog 1 Interrupt Status - * 3 RO AXIS Message FIFO A Interrupt Status - * 2 RO AXIS Message FIFO B Interrupt Status - * 1 RO AXIS Message FIFO C Interrupt Status - * 0 RO AXIS Message FIFO D Interrupt Status - * - * Interrupts can be forwarded to one of two output lines. Nothing - * clever is done, so if the masks are incorrectly set, a single input - * interrupt could generate interrupts on both output lines! - * - * The dual lines are there to allow the chained interrupts to be easily - * passed into two different cores. We currently do not use this functionality - * in this driver. - * - * Controller can also be configured to generate Machine checks (MCP), again on - * two lines, to be attached to two different cores. It is suggested that these - * should be masked out. - */ - -void gef_pic_cascade(unsigned int irq, struct irq_desc *desc) -{ - struct irq_chip *chip = irq_desc_get_chip(desc); - unsigned int cascade_irq; - - /* - * See if we actually have an interrupt, call generic handling code if - * we do. - */ - cascade_irq = gef_pic_get_irq(); - - if (cascade_irq != NO_IRQ) - generic_handle_irq(cascade_irq); - - chip->irq_eoi(&desc->irq_data); -} - -static void gef_pic_mask(struct irq_data *d) -{ - unsigned long flags; - unsigned int hwirq = irqd_to_hwirq(d); - u32 mask; - - raw_spin_lock_irqsave(&gef_pic_lock, flags); - mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0)); - mask &= ~(1 << hwirq); - out_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0), mask); - raw_spin_unlock_irqrestore(&gef_pic_lock, flags); -} - -static void gef_pic_mask_ack(struct irq_data *d) -{ - /* Don't think we actually have to do anything to ack an interrupt, - * we just need to clear down the devices interrupt and it will go away - */ - gef_pic_mask(d); -} - -static void gef_pic_unmask(struct irq_data *d) -{ - unsigned long flags; - unsigned int hwirq = irqd_to_hwirq(d); - u32 mask; - - raw_spin_lock_irqsave(&gef_pic_lock, flags); - mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0)); - mask |= (1 << hwirq); - out_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0), mask); - raw_spin_unlock_irqrestore(&gef_pic_lock, flags); -} - -static struct irq_chip gef_pic_chip = { - .name = "gefp", - .irq_mask = gef_pic_mask, - .irq_mask_ack = gef_pic_mask_ack, - .irq_unmask = gef_pic_unmask, -}; - - -/* When an interrupt is being configured, this call allows some flexibilty - * in deciding which irq_chip structure is used - */ -static int gef_pic_host_map(struct irq_host *h, unsigned int virq, - irq_hw_number_t hwirq) -{ - /* All interrupts are LEVEL sensitive */ - irq_set_status_flags(virq, IRQ_LEVEL); - irq_set_chip_and_handler(virq, &gef_pic_chip, handle_level_irq); - - return 0; -} - -static int gef_pic_host_xlate(struct irq_host *h, struct device_node *ct, - const u32 *intspec, unsigned int intsize, - irq_hw_number_t *out_hwirq, unsigned int *out_flags) -{ - - *out_hwirq = intspec[0]; - if (intsize > 1) - *out_flags = intspec[1]; - else - *out_flags = IRQ_TYPE_LEVEL_HIGH; - - return 0; -} - -static struct irq_host_ops gef_pic_host_ops = { - .map = gef_pic_host_map, - .xlate = gef_pic_host_xlate, -}; - - -/* - * Initialisation of PIC, this should be called in BSP - */ -void __init gef_pic_init(struct device_node *np) -{ - unsigned long flags; - - /* Map the devices registers into memory */ - gef_pic_irq_reg_base = of_iomap(np, 0); - - raw_spin_lock_irqsave(&gef_pic_lock, flags); - - /* Initialise everything as masked. */ - out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU0_INTR_MASK, 0); - out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU1_INTR_MASK, 0); - - out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU0_MCP_MASK, 0); - out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU1_MCP_MASK, 0); - - raw_spin_unlock_irqrestore(&gef_pic_lock, flags); - - /* Map controller */ - gef_pic_cascade_irq = irq_of_parse_and_map(np, 0); - if (gef_pic_cascade_irq == NO_IRQ) { - printk(KERN_ERR "SBC610: failed to map cascade interrupt"); - return; - } - - /* Setup an irq_host structure */ - gef_pic_irq_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, - GEF_PIC_NUM_IRQS, - &gef_pic_host_ops, NO_IRQ); - if (gef_pic_irq_host == NULL) - return; - - /* Chain with parent controller */ - irq_set_chained_handler(gef_pic_cascade_irq, gef_pic_cascade); -} - -/* - * This is called when we receive an interrupt with apparently comes from this - * chip - check, returning the highest interrupt generated or return NO_IRQ - */ -unsigned int gef_pic_get_irq(void) -{ - u32 cause, mask, active; - unsigned int virq = NO_IRQ; - int hwirq; - - cause = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_STATUS); - - mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0)); - - active = cause & mask; - - if (active) { - for (hwirq = GEF_PIC_NUM_IRQS - 1; hwirq > -1; hwirq--) { - if (active & (0x1 << hwirq)) - break; - } - virq = irq_linear_revmap(gef_pic_irq_host, - (irq_hw_number_t)hwirq); - } - - return virq; -} - diff --git a/arch/powerpc/platforms/86xx/gef_pic.h b/arch/powerpc/platforms/86xx/gef_pic.h deleted file mode 100644 index 6149916da3f4..000000000000 --- a/arch/powerpc/platforms/86xx/gef_pic.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef __GEF_PIC_H__ -#define __GEF_PIC_H__ - -#include - -void gef_pic_cascade(unsigned int, struct irq_desc *); -unsigned int gef_pic_get_irq(void); -void gef_pic_init(struct device_node *); - -#endif /* __GEF_PIC_H__ */ - diff --git a/arch/powerpc/platforms/86xx/gef_ppc9a.c b/arch/powerpc/platforms/86xx/gef_ppc9a.c index 60ce07e39100..ed58b6cfd60c 100644 --- a/arch/powerpc/platforms/86xx/gef_ppc9a.c +++ b/arch/powerpc/platforms/86xx/gef_ppc9a.c @@ -37,9 +37,9 @@ #include #include +#include #include "mpc86xx.h" -#include "gef_pic.h" #undef DEBUG diff --git a/arch/powerpc/platforms/86xx/gef_sbc310.c b/arch/powerpc/platforms/86xx/gef_sbc310.c index 3ecee25bf3ed..710db69bd523 100644 --- a/arch/powerpc/platforms/86xx/gef_sbc310.c +++ b/arch/powerpc/platforms/86xx/gef_sbc310.c @@ -37,9 +37,9 @@ #include #include +#include #include "mpc86xx.h" -#include "gef_pic.h" #undef DEBUG diff --git a/arch/powerpc/platforms/86xx/gef_sbc610.c b/arch/powerpc/platforms/86xx/gef_sbc610.c index 5090d608d9ee..4a13d2f4ac20 100644 --- a/arch/powerpc/platforms/86xx/gef_sbc610.c +++ b/arch/powerpc/platforms/86xx/gef_sbc610.c @@ -37,9 +37,9 @@ #include #include +#include #include "mpc86xx.h" -#include "gef_pic.h" #undef DEBUG diff --git a/arch/powerpc/sysdev/Kconfig b/arch/powerpc/sysdev/Kconfig index 7b4df37ac381..a84fecf63c4d 100644 --- a/arch/powerpc/sysdev/Kconfig +++ b/arch/powerpc/sysdev/Kconfig @@ -29,3 +29,7 @@ config SCOM_DEBUGFS bool "Expose SCOM controllers via debugfs" depends on PPC_SCOM default n + +config GE_FPGA + bool + default n diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile index 5e37b4717864..f80ff9f5f441 100644 --- a/arch/powerpc/sysdev/Makefile +++ b/arch/powerpc/sysdev/Makefile @@ -65,3 +65,5 @@ obj-$(CONFIG_PPC_SCOM) += scom.o subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror obj-$(CONFIG_PPC_XICS) += xics/ + +obj-$(CONFIG_GE_FPGA) += ge/ diff --git a/arch/powerpc/sysdev/ge/Makefile b/arch/powerpc/sysdev/ge/Makefile new file mode 100644 index 000000000000..8731ffcb79b9 --- /dev/null +++ b/arch/powerpc/sysdev/ge/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_GE_FPGA) += ge_pic.o diff --git a/arch/powerpc/sysdev/ge/ge_pic.c b/arch/powerpc/sysdev/ge/ge_pic.c new file mode 100644 index 000000000000..002a56295e01 --- /dev/null +++ b/arch/powerpc/sysdev/ge/ge_pic.c @@ -0,0 +1,252 @@ +/* + * Interrupt handling for GE FPGA based PIC + * + * Author: Martyn Welch + * + * 2008 (c) GE Intelligent Platforms Embedded Systems, Inc. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "ge_pic.h" + +#define DEBUG +#undef DEBUG + +#ifdef DEBUG +#define DBG(fmt...) do { printk(KERN_DEBUG "gef_pic: " fmt); } while (0) +#else +#define DBG(fmt...) do { } while (0) +#endif + +#define GEF_PIC_NUM_IRQS 32 + +/* Interrupt Controller Interface Registers */ +#define GEF_PIC_INTR_STATUS 0x0000 + +#define GEF_PIC_INTR_MASK(cpu) (0x0010 + (0x4 * cpu)) +#define GEF_PIC_CPU0_INTR_MASK GEF_PIC_INTR_MASK(0) +#define GEF_PIC_CPU1_INTR_MASK GEF_PIC_INTR_MASK(1) + +#define GEF_PIC_MCP_MASK(cpu) (0x0018 + (0x4 * cpu)) +#define GEF_PIC_CPU0_MCP_MASK GEF_PIC_MCP_MASK(0) +#define GEF_PIC_CPU1_MCP_MASK GEF_PIC_MCP_MASK(1) + + +static DEFINE_RAW_SPINLOCK(gef_pic_lock); + +static void __iomem *gef_pic_irq_reg_base; +static struct irq_host *gef_pic_irq_host; +static int gef_pic_cascade_irq; + +/* + * Interrupt Controller Handling + * + * The interrupt controller handles interrupts for most on board interrupts, + * apart from PCI interrupts. For example on SBC610: + * + * 17:31 RO Reserved + * 16 RO PCI Express Doorbell 3 Status + * 15 RO PCI Express Doorbell 2 Status + * 14 RO PCI Express Doorbell 1 Status + * 13 RO PCI Express Doorbell 0 Status + * 12 RO Real Time Clock Interrupt Status + * 11 RO Temperature Interrupt Status + * 10 RO Temperature Critical Interrupt Status + * 9 RO Ethernet PHY1 Interrupt Status + * 8 RO Ethernet PHY3 Interrupt Status + * 7 RO PEX8548 Interrupt Status + * 6 RO Reserved + * 5 RO Watchdog 0 Interrupt Status + * 4 RO Watchdog 1 Interrupt Status + * 3 RO AXIS Message FIFO A Interrupt Status + * 2 RO AXIS Message FIFO B Interrupt Status + * 1 RO AXIS Message FIFO C Interrupt Status + * 0 RO AXIS Message FIFO D Interrupt Status + * + * Interrupts can be forwarded to one of two output lines. Nothing + * clever is done, so if the masks are incorrectly set, a single input + * interrupt could generate interrupts on both output lines! + * + * The dual lines are there to allow the chained interrupts to be easily + * passed into two different cores. We currently do not use this functionality + * in this driver. + * + * Controller can also be configured to generate Machine checks (MCP), again on + * two lines, to be attached to two different cores. It is suggested that these + * should be masked out. + */ + +void gef_pic_cascade(unsigned int irq, struct irq_desc *desc) +{ + struct irq_chip *chip = irq_desc_get_chip(desc); + unsigned int cascade_irq; + + /* + * See if we actually have an interrupt, call generic handling code if + * we do. + */ + cascade_irq = gef_pic_get_irq(); + + if (cascade_irq != NO_IRQ) + generic_handle_irq(cascade_irq); + + chip->irq_eoi(&desc->irq_data); +} + +static void gef_pic_mask(struct irq_data *d) +{ + unsigned long flags; + unsigned int hwirq = irqd_to_hwirq(d); + u32 mask; + + raw_spin_lock_irqsave(&gef_pic_lock, flags); + mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0)); + mask &= ~(1 << hwirq); + out_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0), mask); + raw_spin_unlock_irqrestore(&gef_pic_lock, flags); +} + +static void gef_pic_mask_ack(struct irq_data *d) +{ + /* Don't think we actually have to do anything to ack an interrupt, + * we just need to clear down the devices interrupt and it will go away + */ + gef_pic_mask(d); +} + +static void gef_pic_unmask(struct irq_data *d) +{ + unsigned long flags; + unsigned int hwirq = irqd_to_hwirq(d); + u32 mask; + + raw_spin_lock_irqsave(&gef_pic_lock, flags); + mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0)); + mask |= (1 << hwirq); + out_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0), mask); + raw_spin_unlock_irqrestore(&gef_pic_lock, flags); +} + +static struct irq_chip gef_pic_chip = { + .name = "gefp", + .irq_mask = gef_pic_mask, + .irq_mask_ack = gef_pic_mask_ack, + .irq_unmask = gef_pic_unmask, +}; + + +/* When an interrupt is being configured, this call allows some flexibilty + * in deciding which irq_chip structure is used + */ +static int gef_pic_host_map(struct irq_host *h, unsigned int virq, + irq_hw_number_t hwirq) +{ + /* All interrupts are LEVEL sensitive */ + irq_set_status_flags(virq, IRQ_LEVEL); + irq_set_chip_and_handler(virq, &gef_pic_chip, handle_level_irq); + + return 0; +} + +static int gef_pic_host_xlate(struct irq_host *h, struct device_node *ct, + const u32 *intspec, unsigned int intsize, + irq_hw_number_t *out_hwirq, unsigned int *out_flags) +{ + + *out_hwirq = intspec[0]; + if (intsize > 1) + *out_flags = intspec[1]; + else + *out_flags = IRQ_TYPE_LEVEL_HIGH; + + return 0; +} + +static struct irq_host_ops gef_pic_host_ops = { + .map = gef_pic_host_map, + .xlate = gef_pic_host_xlate, +}; + + +/* + * Initialisation of PIC, this should be called in BSP + */ +void __init gef_pic_init(struct device_node *np) +{ + unsigned long flags; + + /* Map the devices registers into memory */ + gef_pic_irq_reg_base = of_iomap(np, 0); + + raw_spin_lock_irqsave(&gef_pic_lock, flags); + + /* Initialise everything as masked. */ + out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU0_INTR_MASK, 0); + out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU1_INTR_MASK, 0); + + out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU0_MCP_MASK, 0); + out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU1_MCP_MASK, 0); + + raw_spin_unlock_irqrestore(&gef_pic_lock, flags); + + /* Map controller */ + gef_pic_cascade_irq = irq_of_parse_and_map(np, 0); + if (gef_pic_cascade_irq == NO_IRQ) { + printk(KERN_ERR "SBC610: failed to map cascade interrupt"); + return; + } + + /* Setup an irq_host structure */ + gef_pic_irq_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, + GEF_PIC_NUM_IRQS, + &gef_pic_host_ops, NO_IRQ); + if (gef_pic_irq_host == NULL) + return; + + /* Chain with parent controller */ + irq_set_chained_handler(gef_pic_cascade_irq, gef_pic_cascade); +} + +/* + * This is called when we receive an interrupt with apparently comes from this + * chip - check, returning the highest interrupt generated or return NO_IRQ + */ +unsigned int gef_pic_get_irq(void) +{ + u32 cause, mask, active; + unsigned int virq = NO_IRQ; + int hwirq; + + cause = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_STATUS); + + mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0)); + + active = cause & mask; + + if (active) { + for (hwirq = GEF_PIC_NUM_IRQS - 1; hwirq > -1; hwirq--) { + if (active & (0x1 << hwirq)) + break; + } + virq = irq_linear_revmap(gef_pic_irq_host, + (irq_hw_number_t)hwirq); + } + + return virq; +} + diff --git a/arch/powerpc/sysdev/ge/ge_pic.h b/arch/powerpc/sysdev/ge/ge_pic.h new file mode 100644 index 000000000000..6149916da3f4 --- /dev/null +++ b/arch/powerpc/sysdev/ge/ge_pic.h @@ -0,0 +1,11 @@ +#ifndef __GEF_PIC_H__ +#define __GEF_PIC_H__ + +#include + +void gef_pic_cascade(unsigned int, struct irq_desc *); +unsigned int gef_pic_get_irq(void); +void gef_pic_init(struct device_node *); + +#endif /* __GEF_PIC_H__ */ +