at v3.2-rc2 186 lines 4.2 kB view raw
1#include <linux/kernel.h> 2#include <linux/stddef.h> 3#include <linux/init.h> 4#include <linux/sched.h> 5#include <linux/signal.h> 6#include <linux/irq.h> 7#include <linux/dma-mapping.h> 8#include <asm/prom.h> 9#include <asm/irq.h> 10#include <asm/io.h> 11#include <asm/8xx_immap.h> 12 13#include "mpc8xx_pic.h" 14 15 16#define PIC_VEC_SPURRIOUS 15 17 18extern int cpm_get_irq(struct pt_regs *regs); 19 20static struct irq_host *mpc8xx_pic_host; 21#define NR_MASK_WORDS ((NR_IRQS + 31) / 32) 22static unsigned long ppc_cached_irq_mask[NR_MASK_WORDS]; 23static sysconf8xx_t __iomem *siu_reg; 24 25int cpm_get_irq(struct pt_regs *regs); 26 27static void mpc8xx_unmask_irq(struct irq_data *d) 28{ 29 int bit, word; 30 unsigned int irq_nr = (unsigned int)irqd_to_hwirq(d); 31 32 bit = irq_nr & 0x1f; 33 word = irq_nr >> 5; 34 35 ppc_cached_irq_mask[word] |= (1 << (31-bit)); 36 out_be32(&siu_reg->sc_simask, ppc_cached_irq_mask[word]); 37} 38 39static void mpc8xx_mask_irq(struct irq_data *d) 40{ 41 int bit, word; 42 unsigned int irq_nr = (unsigned int)irqd_to_hwirq(d); 43 44 bit = irq_nr & 0x1f; 45 word = irq_nr >> 5; 46 47 ppc_cached_irq_mask[word] &= ~(1 << (31-bit)); 48 out_be32(&siu_reg->sc_simask, ppc_cached_irq_mask[word]); 49} 50 51static void mpc8xx_ack(struct irq_data *d) 52{ 53 int bit; 54 unsigned int irq_nr = (unsigned int)irqd_to_hwirq(d); 55 56 bit = irq_nr & 0x1f; 57 out_be32(&siu_reg->sc_sipend, 1 << (31-bit)); 58} 59 60static void mpc8xx_end_irq(struct irq_data *d) 61{ 62 int bit, word; 63 unsigned int irq_nr = (unsigned int)irqd_to_hwirq(d); 64 65 bit = irq_nr & 0x1f; 66 word = irq_nr >> 5; 67 68 ppc_cached_irq_mask[word] |= (1 << (31-bit)); 69 out_be32(&siu_reg->sc_simask, ppc_cached_irq_mask[word]); 70} 71 72static int mpc8xx_set_irq_type(struct irq_data *d, unsigned int flow_type) 73{ 74 if (flow_type & IRQ_TYPE_EDGE_FALLING) { 75 irq_hw_number_t hw = (unsigned int)irqd_to_hwirq(d); 76 unsigned int siel = in_be32(&siu_reg->sc_siel); 77 78 /* only external IRQ senses are programmable */ 79 if ((hw & 1) == 0) { 80 siel |= (0x80000000 >> hw); 81 out_be32(&siu_reg->sc_siel, siel); 82 __irq_set_handler_locked(d->irq, handle_edge_irq); 83 } 84 } 85 return 0; 86} 87 88static struct irq_chip mpc8xx_pic = { 89 .name = "MPC8XX SIU", 90 .irq_unmask = mpc8xx_unmask_irq, 91 .irq_mask = mpc8xx_mask_irq, 92 .irq_ack = mpc8xx_ack, 93 .irq_eoi = mpc8xx_end_irq, 94 .irq_set_type = mpc8xx_set_irq_type, 95}; 96 97unsigned int mpc8xx_get_irq(void) 98{ 99 int irq; 100 101 /* For MPC8xx, read the SIVEC register and shift the bits down 102 * to get the irq number. 103 */ 104 irq = in_be32(&siu_reg->sc_sivec) >> 26; 105 106 if (irq == PIC_VEC_SPURRIOUS) 107 irq = NO_IRQ; 108 109 return irq_linear_revmap(mpc8xx_pic_host, irq); 110 111} 112 113static int mpc8xx_pic_host_map(struct irq_host *h, unsigned int virq, 114 irq_hw_number_t hw) 115{ 116 pr_debug("mpc8xx_pic_host_map(%d, 0x%lx)\n", virq, hw); 117 118 /* Set default irq handle */ 119 irq_set_chip_and_handler(virq, &mpc8xx_pic, handle_level_irq); 120 return 0; 121} 122 123 124static int mpc8xx_pic_host_xlate(struct irq_host *h, struct device_node *ct, 125 const u32 *intspec, unsigned int intsize, 126 irq_hw_number_t *out_hwirq, unsigned int *out_flags) 127{ 128 static unsigned char map_pic_senses[4] = { 129 IRQ_TYPE_EDGE_RISING, 130 IRQ_TYPE_LEVEL_LOW, 131 IRQ_TYPE_LEVEL_HIGH, 132 IRQ_TYPE_EDGE_FALLING, 133 }; 134 135 *out_hwirq = intspec[0]; 136 if (intsize > 1 && intspec[1] < 4) 137 *out_flags = map_pic_senses[intspec[1]]; 138 else 139 *out_flags = IRQ_TYPE_NONE; 140 141 return 0; 142} 143 144 145static struct irq_host_ops mpc8xx_pic_host_ops = { 146 .map = mpc8xx_pic_host_map, 147 .xlate = mpc8xx_pic_host_xlate, 148}; 149 150int mpc8xx_pic_init(void) 151{ 152 struct resource res; 153 struct device_node *np; 154 int ret; 155 156 np = of_find_compatible_node(NULL, NULL, "fsl,pq1-pic"); 157 if (np == NULL) 158 np = of_find_node_by_type(NULL, "mpc8xx-pic"); 159 if (np == NULL) { 160 printk(KERN_ERR "Could not find fsl,pq1-pic node\n"); 161 return -ENOMEM; 162 } 163 164 ret = of_address_to_resource(np, 0, &res); 165 if (ret) 166 goto out; 167 168 siu_reg = ioremap(res.start, resource_size(&res)); 169 if (siu_reg == NULL) { 170 ret = -EINVAL; 171 goto out; 172 } 173 174 mpc8xx_pic_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, 175 64, &mpc8xx_pic_host_ops, 64); 176 if (mpc8xx_pic_host == NULL) { 177 printk(KERN_ERR "MPC8xx PIC: failed to allocate irq host!\n"); 178 ret = -ENOMEM; 179 goto out; 180 } 181 return 0; 182 183out: 184 of_node_put(np); 185 return ret; 186}