1b0c110b4SVitaly Bordug /* 2b0c110b4SVitaly Bordug * Platform information definitions. 3b0c110b4SVitaly Bordug * 4b0c110b4SVitaly Bordug * Copied from arch/ppc/syslib/cpm2_pic.c with minor subsequent updates 5b0c110b4SVitaly Bordug * to make in work in arch/powerpc/. Original (c) belongs to Dan Malek. 6b0c110b4SVitaly Bordug * 7b0c110b4SVitaly Bordug * Author: Vitaly Bordug <vbordug@ru.mvista.com> 8b0c110b4SVitaly Bordug * 9b0c110b4SVitaly Bordug * 1999-2001 (c) Dan Malek <dan@embeddedalley.com> 10b0c110b4SVitaly Bordug * 2006 (c) MontaVista Software, Inc. 11b0c110b4SVitaly Bordug * 12b0c110b4SVitaly Bordug * This file is licensed under the terms of the GNU General Public License 13b0c110b4SVitaly Bordug * version 2. This program is licensed "as is" without any warranty of any 14b0c110b4SVitaly Bordug * kind, whether express or implied. 15b0c110b4SVitaly Bordug */ 16b0c110b4SVitaly Bordug 17b0c110b4SVitaly Bordug /* The CPM2 internal interrupt controller. It is usually 18b0c110b4SVitaly Bordug * the only interrupt controller. 19b0c110b4SVitaly Bordug * There are two 32-bit registers (high/low) for up to 64 20b0c110b4SVitaly Bordug * possible interrupts. 21b0c110b4SVitaly Bordug * 22b0c110b4SVitaly Bordug * Now, the fun starts.....Interrupt Numbers DO NOT MAP 23b0c110b4SVitaly Bordug * in a simple arithmetic fashion to mask or pending registers. 24b0c110b4SVitaly Bordug * That is, interrupt 4 does not map to bit position 4. 25b0c110b4SVitaly Bordug * We create two tables, indexed by vector number, to indicate 26b0c110b4SVitaly Bordug * which register to use and which bit in the register to use. 27b0c110b4SVitaly Bordug */ 28b0c110b4SVitaly Bordug 29b0c110b4SVitaly Bordug #include <linux/stddef.h> 30b0c110b4SVitaly Bordug #include <linux/init.h> 31b0c110b4SVitaly Bordug #include <linux/sched.h> 32b0c110b4SVitaly Bordug #include <linux/signal.h> 33b0c110b4SVitaly Bordug #include <linux/irq.h> 34b0c110b4SVitaly Bordug 35b0c110b4SVitaly Bordug #include <asm/immap_cpm2.h> 36b0c110b4SVitaly Bordug #include <asm/mpc8260.h> 37b0c110b4SVitaly Bordug #include <asm/io.h> 38b0c110b4SVitaly Bordug #include <asm/prom.h> 3973844ecbSVitaly Bordug #include <asm/fs_pd.h> 40b0c110b4SVitaly Bordug 41b0c110b4SVitaly Bordug #include "cpm2_pic.h" 42b0c110b4SVitaly Bordug 4373844ecbSVitaly Bordug /* External IRQS */ 4473844ecbSVitaly Bordug #define CPM2_IRQ_EXT1 19 4573844ecbSVitaly Bordug #define CPM2_IRQ_EXT7 25 4673844ecbSVitaly Bordug 4773844ecbSVitaly Bordug /* Port C IRQS */ 4873844ecbSVitaly Bordug #define CPM2_IRQ_PORTC15 48 4973844ecbSVitaly Bordug #define CPM2_IRQ_PORTC0 63 5073844ecbSVitaly Bordug 5173844ecbSVitaly Bordug static intctl_cpm2_t *cpm2_intctl; 5273844ecbSVitaly Bordug 53b0c110b4SVitaly Bordug static struct irq_host *cpm2_pic_host; 54b0c110b4SVitaly Bordug #define NR_MASK_WORDS ((NR_IRQS + 31) / 32) 55b0c110b4SVitaly Bordug static unsigned long ppc_cached_irq_mask[NR_MASK_WORDS]; 56b0c110b4SVitaly Bordug 57b0c110b4SVitaly Bordug static const u_char irq_to_siureg[] = { 58b0c110b4SVitaly Bordug 1, 1, 1, 1, 1, 1, 1, 1, 59b0c110b4SVitaly Bordug 1, 1, 1, 1, 1, 1, 1, 1, 60b0c110b4SVitaly Bordug 0, 0, 0, 0, 0, 0, 0, 0, 61b0c110b4SVitaly Bordug 0, 0, 0, 0, 0, 0, 0, 0, 62b0c110b4SVitaly Bordug 1, 1, 1, 1, 1, 1, 1, 1, 63b0c110b4SVitaly Bordug 1, 1, 1, 1, 1, 1, 1, 1, 64b0c110b4SVitaly Bordug 0, 0, 0, 0, 0, 0, 0, 0, 65b0c110b4SVitaly Bordug 0, 0, 0, 0, 0, 0, 0, 0 66b0c110b4SVitaly Bordug }; 67b0c110b4SVitaly Bordug 68b0c110b4SVitaly Bordug /* bit numbers do not match the docs, these are precomputed so the bit for 69b0c110b4SVitaly Bordug * a given irq is (1 << irq_to_siubit[irq]) */ 70b0c110b4SVitaly Bordug static const u_char irq_to_siubit[] = { 71b0c110b4SVitaly Bordug 0, 15, 14, 13, 12, 11, 10, 9, 72b0c110b4SVitaly Bordug 8, 7, 6, 5, 4, 3, 2, 1, 73b0c110b4SVitaly Bordug 2, 1, 0, 14, 13, 12, 11, 10, 74b0c110b4SVitaly Bordug 9, 8, 7, 6, 5, 4, 3, 0, 75b0c110b4SVitaly Bordug 31, 30, 29, 28, 27, 26, 25, 24, 76b0c110b4SVitaly Bordug 23, 22, 21, 20, 19, 18, 17, 16, 77b0c110b4SVitaly Bordug 16, 17, 18, 19, 20, 21, 22, 23, 78b0c110b4SVitaly Bordug 24, 25, 26, 27, 28, 29, 30, 31, 79b0c110b4SVitaly Bordug }; 80b0c110b4SVitaly Bordug 8173844ecbSVitaly Bordug static void cpm2_mask_irq(unsigned int virq) 82b0c110b4SVitaly Bordug { 83b0c110b4SVitaly Bordug int bit, word; 8473844ecbSVitaly Bordug unsigned int irq_nr = virq_to_hw(virq); 85b0c110b4SVitaly Bordug 86b0c110b4SVitaly Bordug bit = irq_to_siubit[irq_nr]; 87b0c110b4SVitaly Bordug word = irq_to_siureg[irq_nr]; 88b0c110b4SVitaly Bordug 89b0c110b4SVitaly Bordug ppc_cached_irq_mask[word] &= ~(1 << bit); 9073844ecbSVitaly Bordug out_be32(&cpm2_intctl->ic_simrh + word, ppc_cached_irq_mask[word]); 91b0c110b4SVitaly Bordug } 92b0c110b4SVitaly Bordug 9373844ecbSVitaly Bordug static void cpm2_unmask_irq(unsigned int virq) 94b0c110b4SVitaly Bordug { 95b0c110b4SVitaly Bordug int bit, word; 9673844ecbSVitaly Bordug unsigned int irq_nr = virq_to_hw(virq); 97b0c110b4SVitaly Bordug 98b0c110b4SVitaly Bordug bit = irq_to_siubit[irq_nr]; 99b0c110b4SVitaly Bordug word = irq_to_siureg[irq_nr]; 100b0c110b4SVitaly Bordug 101b0c110b4SVitaly Bordug ppc_cached_irq_mask[word] |= 1 << bit; 10273844ecbSVitaly Bordug out_be32(&cpm2_intctl->ic_simrh + word, ppc_cached_irq_mask[word]); 103b0c110b4SVitaly Bordug } 104b0c110b4SVitaly Bordug 10573844ecbSVitaly Bordug static void cpm2_ack(unsigned int virq) 106b0c110b4SVitaly Bordug { 107b0c110b4SVitaly Bordug int bit, word; 10873844ecbSVitaly Bordug unsigned int irq_nr = virq_to_hw(virq); 109b0c110b4SVitaly Bordug 110b0c110b4SVitaly Bordug bit = irq_to_siubit[irq_nr]; 111b0c110b4SVitaly Bordug word = irq_to_siureg[irq_nr]; 112b0c110b4SVitaly Bordug 11373844ecbSVitaly Bordug out_be32(&cpm2_intctl->ic_sipnrh + word, 1 << bit); 114b0c110b4SVitaly Bordug } 115b0c110b4SVitaly Bordug 11673844ecbSVitaly Bordug static void cpm2_end_irq(unsigned int virq) 117b0c110b4SVitaly Bordug { 118b0c110b4SVitaly Bordug int bit, word; 11973844ecbSVitaly Bordug unsigned int irq_nr = virq_to_hw(virq); 120b0c110b4SVitaly Bordug 121b0c110b4SVitaly Bordug if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS)) 122b0c110b4SVitaly Bordug && irq_desc[irq_nr].action) { 123b0c110b4SVitaly Bordug 124b0c110b4SVitaly Bordug bit = irq_to_siubit[irq_nr]; 125b0c110b4SVitaly Bordug word = irq_to_siureg[irq_nr]; 126b0c110b4SVitaly Bordug 127b0c110b4SVitaly Bordug ppc_cached_irq_mask[word] |= 1 << bit; 12873844ecbSVitaly Bordug out_be32(&cpm2_intctl->ic_simrh + word, ppc_cached_irq_mask[word]); 12973844ecbSVitaly Bordug 130b0c110b4SVitaly Bordug /* 131b0c110b4SVitaly Bordug * Work around large numbers of spurious IRQs on PowerPC 82xx 132b0c110b4SVitaly Bordug * systems. 133b0c110b4SVitaly Bordug */ 134b0c110b4SVitaly Bordug mb(); 135b0c110b4SVitaly Bordug } 136b0c110b4SVitaly Bordug } 137b0c110b4SVitaly Bordug 13873844ecbSVitaly Bordug static int cpm2_set_irq_type(unsigned int virq, unsigned int flow_type) 13973844ecbSVitaly Bordug { 14073844ecbSVitaly Bordug unsigned int src = virq_to_hw(virq); 14173844ecbSVitaly Bordug struct irq_desc *desc = get_irq_desc(virq); 14273844ecbSVitaly Bordug unsigned int vold, vnew, edibit; 14373844ecbSVitaly Bordug 14473844ecbSVitaly Bordug if (flow_type == IRQ_TYPE_NONE) 14573844ecbSVitaly Bordug flow_type = IRQ_TYPE_LEVEL_LOW; 14673844ecbSVitaly Bordug 14773844ecbSVitaly Bordug if (flow_type & IRQ_TYPE_EDGE_RISING) { 14873844ecbSVitaly Bordug printk(KERN_ERR "CPM2 PIC: sense type 0x%x not supported\n", 14973844ecbSVitaly Bordug flow_type); 15073844ecbSVitaly Bordug return -EINVAL; 15173844ecbSVitaly Bordug } 15273844ecbSVitaly Bordug 15373844ecbSVitaly Bordug desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL); 15473844ecbSVitaly Bordug desc->status |= flow_type & IRQ_TYPE_SENSE_MASK; 15573844ecbSVitaly Bordug if (flow_type & IRQ_TYPE_LEVEL_LOW) { 15673844ecbSVitaly Bordug desc->status |= IRQ_LEVEL; 15773844ecbSVitaly Bordug desc->handle_irq = handle_level_irq; 15873844ecbSVitaly Bordug } else 15973844ecbSVitaly Bordug desc->handle_irq = handle_edge_irq; 16073844ecbSVitaly Bordug 16173844ecbSVitaly Bordug /* internal IRQ senses are LEVEL_LOW 16273844ecbSVitaly Bordug * EXT IRQ and Port C IRQ senses are programmable 16373844ecbSVitaly Bordug */ 16473844ecbSVitaly Bordug if (src >= CPM2_IRQ_EXT1 && src <= CPM2_IRQ_EXT7) 16573844ecbSVitaly Bordug edibit = (14 - (src - CPM2_IRQ_EXT1)); 16673844ecbSVitaly Bordug else 16773844ecbSVitaly Bordug if (src >= CPM2_IRQ_PORTC15 && src <= CPM2_IRQ_PORTC0) 16873844ecbSVitaly Bordug edibit = (31 - (src - CPM2_IRQ_PORTC15)); 16973844ecbSVitaly Bordug else 17073844ecbSVitaly Bordug return (flow_type & IRQ_TYPE_LEVEL_LOW) ? 0 : -EINVAL; 17173844ecbSVitaly Bordug 17273844ecbSVitaly Bordug vold = in_be32(&cpm2_intctl->ic_siexr); 17373844ecbSVitaly Bordug 17473844ecbSVitaly Bordug if ((flow_type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_FALLING) 17573844ecbSVitaly Bordug vnew = vold | (1 << edibit); 17673844ecbSVitaly Bordug else 17773844ecbSVitaly Bordug vnew = vold & ~(1 << edibit); 17873844ecbSVitaly Bordug 17973844ecbSVitaly Bordug if (vold != vnew) 18073844ecbSVitaly Bordug out_be32(&cpm2_intctl->ic_siexr, vnew); 18173844ecbSVitaly Bordug return 0; 18273844ecbSVitaly Bordug } 18373844ecbSVitaly Bordug 184b0c110b4SVitaly Bordug static struct irq_chip cpm2_pic = { 185b0c110b4SVitaly Bordug .typename = " CPM2 SIU ", 18673844ecbSVitaly Bordug .mask = cpm2_mask_irq, 187b0c110b4SVitaly Bordug .unmask = cpm2_unmask_irq, 18873844ecbSVitaly Bordug .ack = cpm2_ack, 18973844ecbSVitaly Bordug .eoi = cpm2_end_irq, 19073844ecbSVitaly Bordug .set_type = cpm2_set_irq_type, 191b0c110b4SVitaly Bordug }; 192b0c110b4SVitaly Bordug 19335a84c2fSOlaf Hering unsigned int cpm2_get_irq(void) 194b0c110b4SVitaly Bordug { 195b0c110b4SVitaly Bordug int irq; 196b0c110b4SVitaly Bordug unsigned long bits; 197b0c110b4SVitaly Bordug 198b0c110b4SVitaly Bordug /* For CPM2, read the SIVEC register and shift the bits down 199b0c110b4SVitaly Bordug * to get the irq number. */ 20073844ecbSVitaly Bordug bits = in_be32(&cpm2_intctl->ic_sivec); 201b0c110b4SVitaly Bordug irq = bits >> 26; 202b0c110b4SVitaly Bordug 203b0c110b4SVitaly Bordug if (irq == 0) 204b0c110b4SVitaly Bordug return(-1); 20573844ecbSVitaly Bordug return irq_linear_revmap(cpm2_pic_host, irq); 206b0c110b4SVitaly Bordug } 207b0c110b4SVitaly Bordug 208b0c110b4SVitaly Bordug static int cpm2_pic_host_match(struct irq_host *h, struct device_node *node) 209b0c110b4SVitaly Bordug { 21052964f87SMichael Ellerman return h->of_node == node; 211b0c110b4SVitaly Bordug } 212b0c110b4SVitaly Bordug 213b0c110b4SVitaly Bordug static int cpm2_pic_host_map(struct irq_host *h, unsigned int virq, 214b0c110b4SVitaly Bordug irq_hw_number_t hw) 215b0c110b4SVitaly Bordug { 216b0c110b4SVitaly Bordug pr_debug("cpm2_pic_host_map(%d, 0x%lx)\n", virq, hw); 217b0c110b4SVitaly Bordug 218b0c110b4SVitaly Bordug get_irq_desc(virq)->status |= IRQ_LEVEL; 219b0c110b4SVitaly Bordug set_irq_chip_and_handler(virq, &cpm2_pic, handle_level_irq); 220b0c110b4SVitaly Bordug return 0; 221b0c110b4SVitaly Bordug } 222b0c110b4SVitaly Bordug 223b0c110b4SVitaly Bordug static int cpm2_pic_host_xlate(struct irq_host *h, struct device_node *ct, 224b0c110b4SVitaly Bordug u32 *intspec, unsigned int intsize, 225b0c110b4SVitaly Bordug irq_hw_number_t *out_hwirq, unsigned int *out_flags) 226b0c110b4SVitaly Bordug { 227b0c110b4SVitaly Bordug *out_hwirq = intspec[0]; 22873844ecbSVitaly Bordug if (intsize > 1) 22973844ecbSVitaly Bordug *out_flags = intspec[1]; 230b0c110b4SVitaly Bordug else 231b0c110b4SVitaly Bordug *out_flags = IRQ_TYPE_NONE; 232b0c110b4SVitaly Bordug return 0; 233b0c110b4SVitaly Bordug } 234b0c110b4SVitaly Bordug 235b0c110b4SVitaly Bordug static struct irq_host_ops cpm2_pic_host_ops = { 236b0c110b4SVitaly Bordug .match = cpm2_pic_host_match, 237b0c110b4SVitaly Bordug .map = cpm2_pic_host_map, 238b0c110b4SVitaly Bordug .xlate = cpm2_pic_host_xlate, 239b0c110b4SVitaly Bordug }; 240b0c110b4SVitaly Bordug 241b0c110b4SVitaly Bordug void cpm2_pic_init(struct device_node *node) 242b0c110b4SVitaly Bordug { 243b0c110b4SVitaly Bordug int i; 244b0c110b4SVitaly Bordug 24573844ecbSVitaly Bordug cpm2_intctl = cpm2_map(im_intctl); 24673844ecbSVitaly Bordug 247b0c110b4SVitaly Bordug /* Clear the CPM IRQ controller, in case it has any bits set 248b0c110b4SVitaly Bordug * from the bootloader 249b0c110b4SVitaly Bordug */ 250b0c110b4SVitaly Bordug 251b0c110b4SVitaly Bordug /* Mask out everything */ 252b0c110b4SVitaly Bordug 25373844ecbSVitaly Bordug out_be32(&cpm2_intctl->ic_simrh, 0x00000000); 25473844ecbSVitaly Bordug out_be32(&cpm2_intctl->ic_simrl, 0x00000000); 255b0c110b4SVitaly Bordug 256b0c110b4SVitaly Bordug wmb(); 257b0c110b4SVitaly Bordug 258b0c110b4SVitaly Bordug /* Ack everything */ 25973844ecbSVitaly Bordug out_be32(&cpm2_intctl->ic_sipnrh, 0xffffffff); 26073844ecbSVitaly Bordug out_be32(&cpm2_intctl->ic_sipnrl, 0xffffffff); 261b0c110b4SVitaly Bordug wmb(); 262b0c110b4SVitaly Bordug 263b0c110b4SVitaly Bordug /* Dummy read of the vector */ 26473844ecbSVitaly Bordug i = in_be32(&cpm2_intctl->ic_sivec); 265b0c110b4SVitaly Bordug rmb(); 266b0c110b4SVitaly Bordug 267b0c110b4SVitaly Bordug /* Initialize the default interrupt mapping priorities, 268b0c110b4SVitaly Bordug * in case the boot rom changed something on us. 269b0c110b4SVitaly Bordug */ 27073844ecbSVitaly Bordug out_be16(&cpm2_intctl->ic_sicr, 0); 27173844ecbSVitaly Bordug out_be32(&cpm2_intctl->ic_scprrh, 0x05309770); 27273844ecbSVitaly Bordug out_be32(&cpm2_intctl->ic_scprrl, 0x05309770); 273b0c110b4SVitaly Bordug 274b0c110b4SVitaly Bordug /* create a legacy host */ 27552964f87SMichael Ellerman cpm2_pic_host = irq_alloc_host(of_node_get(node), IRQ_HOST_MAP_LINEAR, 27652964f87SMichael Ellerman 64, &cpm2_pic_host_ops, 64); 277b0c110b4SVitaly Bordug if (cpm2_pic_host == NULL) { 278b0c110b4SVitaly Bordug printk(KERN_ERR "CPM2 PIC: failed to allocate irq host!\n"); 279b0c110b4SVitaly Bordug return; 280b0c110b4SVitaly Bordug } 281b0c110b4SVitaly Bordug } 282