X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fpowerpc%2Fsysdev%2Fipic.c;h=8f01e0f1d847404ceea8ce035f390c1fa2091f6c;hb=9464c7cf61b9433057924c36e6e02f303a00e768;hp=70e707785d4924eedcc8a27ce3c0e94e122f8983;hpb=41689045f6a3cbe0550e1d34e9cc20d2e8c432ba;p=linux-2.6.git diff --git a/arch/powerpc/sysdev/ipic.c b/arch/powerpc/sysdev/ipic.c index 70e707785..8f01e0f1d 100644 --- a/arch/powerpc/sysdev/ipic.c +++ b/arch/powerpc/sysdev/ipic.c @@ -19,18 +19,15 @@ #include #include #include -#include -#include -#include #include #include -#include #include +#include #include "ipic.h" +static struct ipic p_ipic; static struct ipic * primary_ipic; -static DEFINE_SPINLOCK(ipic_lock); static struct ipic_info ipic_info[] = { [9] = { @@ -376,220 +373,74 @@ static inline void ipic_write(volatile u32 __iomem *base, unsigned int reg, u32 out_be32(base + (reg >> 2), value); } -static inline struct ipic * ipic_from_irq(unsigned int virq) +static inline struct ipic * ipic_from_irq(unsigned int irq) { return primary_ipic; } -#define ipic_irq_to_hw(virq) ((unsigned int)irq_map[virq].hwirq) - -static void ipic_unmask_irq(unsigned int virq) +static void ipic_enable_irq(unsigned int irq) { - struct ipic *ipic = ipic_from_irq(virq); - unsigned int src = ipic_irq_to_hw(virq); - unsigned long flags; + struct ipic *ipic = ipic_from_irq(irq); + unsigned int src = irq - ipic->irq_offset; u32 temp; - spin_lock_irqsave(&ipic_lock, flags); - temp = ipic_read(ipic->regs, ipic_info[src].mask); temp |= (1 << (31 - ipic_info[src].bit)); ipic_write(ipic->regs, ipic_info[src].mask, temp); - - spin_unlock_irqrestore(&ipic_lock, flags); } -static void ipic_mask_irq(unsigned int virq) +static void ipic_disable_irq(unsigned int irq) { - struct ipic *ipic = ipic_from_irq(virq); - unsigned int src = ipic_irq_to_hw(virq); - unsigned long flags; + struct ipic *ipic = ipic_from_irq(irq); + unsigned int src = irq - ipic->irq_offset; u32 temp; - spin_lock_irqsave(&ipic_lock, flags); - temp = ipic_read(ipic->regs, ipic_info[src].mask); temp &= ~(1 << (31 - ipic_info[src].bit)); ipic_write(ipic->regs, ipic_info[src].mask, temp); - - spin_unlock_irqrestore(&ipic_lock, flags); } -static void ipic_ack_irq(unsigned int virq) +static void ipic_disable_irq_and_ack(unsigned int irq) { - struct ipic *ipic = ipic_from_irq(virq); - unsigned int src = ipic_irq_to_hw(virq); - unsigned long flags; + struct ipic *ipic = ipic_from_irq(irq); + unsigned int src = irq - ipic->irq_offset; u32 temp; - spin_lock_irqsave(&ipic_lock, flags); + ipic_disable_irq(irq); temp = ipic_read(ipic->regs, ipic_info[src].pend); temp |= (1 << (31 - ipic_info[src].bit)); ipic_write(ipic->regs, ipic_info[src].pend, temp); - - spin_unlock_irqrestore(&ipic_lock, flags); } -static void ipic_mask_irq_and_ack(unsigned int virq) +static void ipic_end_irq(unsigned int irq) { - struct ipic *ipic = ipic_from_irq(virq); - unsigned int src = ipic_irq_to_hw(virq); - unsigned long flags; - u32 temp; - - spin_lock_irqsave(&ipic_lock, flags); - - temp = ipic_read(ipic->regs, ipic_info[src].mask); - temp &= ~(1 << (31 - ipic_info[src].bit)); - ipic_write(ipic->regs, ipic_info[src].mask, temp); - - temp = ipic_read(ipic->regs, ipic_info[src].pend); - temp |= (1 << (31 - ipic_info[src].bit)); - ipic_write(ipic->regs, ipic_info[src].pend, temp); - - spin_unlock_irqrestore(&ipic_lock, flags); + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + ipic_enable_irq(irq); } -static int ipic_set_irq_type(unsigned int virq, unsigned int flow_type) -{ - struct ipic *ipic = ipic_from_irq(virq); - unsigned int src = ipic_irq_to_hw(virq); - struct irq_desc *desc = get_irq_desc(virq); - unsigned int vold, vnew, edibit; - - if (flow_type == IRQ_TYPE_NONE) - flow_type = IRQ_TYPE_LEVEL_LOW; - - /* ipic supports only low assertion and high-to-low change senses - */ - if (!(flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_EDGE_FALLING))) { - printk(KERN_ERR "ipic: sense type 0x%x not supported\n", - flow_type); - return -EINVAL; - } - - desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL); - desc->status |= flow_type & IRQ_TYPE_SENSE_MASK; - if (flow_type & IRQ_TYPE_LEVEL_LOW) { - desc->status |= IRQ_LEVEL; - set_irq_handler(virq, handle_level_irq); - } else { - set_irq_handler(virq, handle_edge_irq); - } - - /* only EXT IRQ senses are programmable on ipic - * internal IRQ senses are LEVEL_LOW - */ - if (src == IPIC_IRQ_EXT0) - edibit = 15; - else - if (src >= IPIC_IRQ_EXT1 && src <= IPIC_IRQ_EXT7) - edibit = (14 - (src - IPIC_IRQ_EXT1)); - else - return (flow_type & IRQ_TYPE_LEVEL_LOW) ? 0 : -EINVAL; - - vold = ipic_read(ipic->regs, IPIC_SECNR); - if ((flow_type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_FALLING) { - vnew = vold | (1 << edibit); - } else { - vnew = vold & ~(1 << edibit); - } - if (vold != vnew) - ipic_write(ipic->regs, IPIC_SECNR, vnew); - return 0; -} - -static struct irq_chip ipic_irq_chip = { - .typename = " IPIC ", - .unmask = ipic_unmask_irq, - .mask = ipic_mask_irq, - .mask_ack = ipic_mask_irq_and_ack, - .ack = ipic_ack_irq, - .set_type = ipic_set_irq_type, -}; - -static int ipic_host_match(struct irq_host *h, struct device_node *node) -{ - struct ipic *ipic = h->host_data; - - /* Exact match, unless ipic node is NULL */ - return ipic->of_node == NULL || ipic->of_node == node; -} - -static int ipic_host_map(struct irq_host *h, unsigned int virq, - irq_hw_number_t hw) -{ - struct ipic *ipic = h->host_data; - struct irq_chip *chip; - - /* Default chip */ - chip = &ipic->hc_irq; - - set_irq_chip_data(virq, ipic); - set_irq_chip_and_handler(virq, chip, handle_level_irq); - - /* Set default irq type */ - set_irq_type(virq, IRQ_TYPE_NONE); - - return 0; -} - -static int ipic_host_xlate(struct irq_host *h, struct device_node *ct, - u32 *intspec, unsigned int intsize, - irq_hw_number_t *out_hwirq, unsigned int *out_flags) - -{ - /* interrupt sense values coming from the device tree equal either - * LEVEL_LOW (low assertion) or EDGE_FALLING (high-to-low change) - */ - *out_hwirq = intspec[0]; - if (intsize > 1) - *out_flags = intspec[1]; - else - *out_flags = IRQ_TYPE_NONE; - return 0; -} - -static struct irq_host_ops ipic_host_ops = { - .match = ipic_host_match, - .map = ipic_host_map, - .xlate = ipic_host_xlate, +struct hw_interrupt_type ipic = { + .typename = " IPIC ", + .enable = ipic_enable_irq, + .disable = ipic_disable_irq, + .ack = ipic_disable_irq_and_ack, + .end = ipic_end_irq, }; -void __init ipic_init(struct device_node *node, - unsigned int flags) +void __init ipic_init(phys_addr_t phys_addr, + unsigned int flags, + unsigned int irq_offset, + unsigned char *senses, + unsigned int senses_count) { - struct ipic *ipic; - struct resource res; - u32 temp = 0, ret; - - ipic = alloc_bootmem(sizeof(struct ipic)); - if (ipic == NULL) - return; - - memset(ipic, 0, sizeof(struct ipic)); - ipic->of_node = node ? of_node_get(node) : NULL; - - ipic->irqhost = irq_alloc_host(IRQ_HOST_MAP_LINEAR, - NR_IPIC_INTS, - &ipic_host_ops, 0); - if (ipic->irqhost == NULL) { - of_node_put(node); - return; - } - - ret = of_address_to_resource(node, 0, &res); - if (ret) - return; + u32 i, temp = 0; - ipic->regs = ioremap(res.start, res.end - res.start + 1); + primary_ipic = &p_ipic; + primary_ipic->regs = ioremap(phys_addr, MPC83xx_IPIC_SIZE); - ipic->irqhost->host_data = ipic; - ipic->hc_irq = ipic_irq_chip; + primary_ipic->irq_offset = irq_offset; - /* init hw */ - ipic_write(ipic->regs, IPIC_SICNR, 0x0); + ipic_write(primary_ipic->regs, IPIC_SICNR, 0x0); /* default priority scheme is grouped. If spread mode is required * configure SICFR accordingly */ @@ -602,35 +453,49 @@ void __init ipic_init(struct device_node *node, if (flags & IPIC_SPREADMODE_MIX_B) temp |= SICFR_MPSB; - ipic_write(ipic->regs, IPIC_SICNR, temp); + ipic_write(primary_ipic->regs, IPIC_SICNR, temp); /* handle MCP route */ temp = 0; if (flags & IPIC_DISABLE_MCP_OUT) temp = SERCR_MCPR; - ipic_write(ipic->regs, IPIC_SERCR, temp); + ipic_write(primary_ipic->regs, IPIC_SERCR, temp); /* handle routing of IRQ0 to MCP */ - temp = ipic_read(ipic->regs, IPIC_SEMSR); + temp = ipic_read(primary_ipic->regs, IPIC_SEMSR); if (flags & IPIC_IRQ0_MCP) temp |= SEMSR_SIRQ0; else temp &= ~SEMSR_SIRQ0; - ipic_write(ipic->regs, IPIC_SEMSR, temp); + ipic_write(primary_ipic->regs, IPIC_SEMSR, temp); - primary_ipic = ipic; - irq_set_default_host(primary_ipic->irqhost); + for (i = 0 ; i < NR_IPIC_INTS ; i++) { + irq_desc[i+irq_offset].handler = &ipic; + irq_desc[i+irq_offset].status = IRQ_LEVEL; + } - printk ("IPIC (%d IRQ sources) at %p\n", NR_IPIC_INTS, - primary_ipic->regs); + temp = 0; + for (i = 0 ; i < senses_count ; i++) { + if ((senses[i] & IRQ_SENSE_MASK) == IRQ_SENSE_EDGE) { + temp |= 1 << (15 - i); + if (i != 0) + irq_desc[i + irq_offset + MPC83xx_IRQ_EXT1 - 1].status = 0; + else + irq_desc[irq_offset + MPC83xx_IRQ_EXT0].status = 0; + } + } + ipic_write(primary_ipic->regs, IPIC_SECNR, temp); + + printk ("IPIC (%d IRQ sources, %d External IRQs) at %p\n", NR_IPIC_INTS, + senses_count, primary_ipic->regs); } -int ipic_set_priority(unsigned int virq, unsigned int priority) +int ipic_set_priority(unsigned int irq, unsigned int priority) { - struct ipic *ipic = ipic_from_irq(virq); - unsigned int src = ipic_irq_to_hw(virq); + struct ipic *ipic = ipic_from_irq(irq); + unsigned int src = irq - ipic->irq_offset; u32 temp; if (priority > 7) @@ -655,10 +520,10 @@ int ipic_set_priority(unsigned int virq, unsigned int priority) return 0; } -void ipic_set_highest_priority(unsigned int virq) +void ipic_set_highest_priority(unsigned int irq) { - struct ipic *ipic = ipic_from_irq(virq); - unsigned int src = ipic_irq_to_hw(virq); + struct ipic *ipic = ipic_from_irq(irq); + unsigned int src = irq - ipic->irq_offset; u32 temp; temp = ipic_read(ipic->regs, IPIC_SICFR); @@ -672,10 +537,37 @@ void ipic_set_highest_priority(unsigned int virq) void ipic_set_default_priority(void) { - ipic_write(primary_ipic->regs, IPIC_SIPRR_A, IPIC_SIPRR_A_DEFAULT); - ipic_write(primary_ipic->regs, IPIC_SIPRR_D, IPIC_SIPRR_D_DEFAULT); - ipic_write(primary_ipic->regs, IPIC_SMPRR_A, IPIC_SMPRR_A_DEFAULT); - ipic_write(primary_ipic->regs, IPIC_SMPRR_B, IPIC_SMPRR_B_DEFAULT); + ipic_set_priority(MPC83xx_IRQ_TSEC1_TX, 0); + ipic_set_priority(MPC83xx_IRQ_TSEC1_RX, 1); + ipic_set_priority(MPC83xx_IRQ_TSEC1_ERROR, 2); + ipic_set_priority(MPC83xx_IRQ_TSEC2_TX, 3); + ipic_set_priority(MPC83xx_IRQ_TSEC2_RX, 4); + ipic_set_priority(MPC83xx_IRQ_TSEC2_ERROR, 5); + ipic_set_priority(MPC83xx_IRQ_USB2_DR, 6); + ipic_set_priority(MPC83xx_IRQ_USB2_MPH, 7); + + ipic_set_priority(MPC83xx_IRQ_UART1, 0); + ipic_set_priority(MPC83xx_IRQ_UART2, 1); + ipic_set_priority(MPC83xx_IRQ_SEC2, 2); + ipic_set_priority(MPC83xx_IRQ_IIC1, 5); + ipic_set_priority(MPC83xx_IRQ_IIC2, 6); + ipic_set_priority(MPC83xx_IRQ_SPI, 7); + ipic_set_priority(MPC83xx_IRQ_RTC_SEC, 0); + ipic_set_priority(MPC83xx_IRQ_PIT, 1); + ipic_set_priority(MPC83xx_IRQ_PCI1, 2); + ipic_set_priority(MPC83xx_IRQ_PCI2, 3); + ipic_set_priority(MPC83xx_IRQ_EXT0, 4); + ipic_set_priority(MPC83xx_IRQ_EXT1, 5); + ipic_set_priority(MPC83xx_IRQ_EXT2, 6); + ipic_set_priority(MPC83xx_IRQ_EXT3, 7); + ipic_set_priority(MPC83xx_IRQ_RTC_ALR, 0); + ipic_set_priority(MPC83xx_IRQ_MU, 1); + ipic_set_priority(MPC83xx_IRQ_SBA, 2); + ipic_set_priority(MPC83xx_IRQ_DMA, 3); + ipic_set_priority(MPC83xx_IRQ_EXT4, 4); + ipic_set_priority(MPC83xx_IRQ_EXT5, 5); + ipic_set_priority(MPC83xx_IRQ_EXT6, 6); + ipic_set_priority(MPC83xx_IRQ_EXT7, 7); } void ipic_enable_mcp(enum ipic_mcp_irq mcp_irq) @@ -708,20 +600,17 @@ void ipic_clear_mcp_status(u32 mask) ipic_write(primary_ipic->regs, IPIC_SERMR, mask); } -/* Return an interrupt vector or NO_IRQ if no interrupt is pending. */ -unsigned int ipic_get_irq(struct pt_regs *regs) +/* Return an interrupt vector or -1 if no interrupt is pending. */ +int ipic_get_irq(struct pt_regs *regs) { int irq; - BUG_ON(primary_ipic == NULL); - -#define IPIC_SIVCR_VECTOR_MASK 0x7f - irq = ipic_read(primary_ipic->regs, IPIC_SIVCR) & IPIC_SIVCR_VECTOR_MASK; + irq = ipic_read(primary_ipic->regs, IPIC_SIVCR) & 0x7f; if (irq == 0) /* 0 --> no irq is pending */ - return NO_IRQ; + irq = -1; - return irq_linear_revmap(primary_ipic->irqhost, irq); + return irq; } static struct sysdev_class ipic_sysclass = {