1/* 2 * Programmable Interrupt Controller functions for the Freescale MPC52xx 3 * embedded CPU. 4 * 5 * 6 * Maintainer : Sylvain Munaut <tnt@246tNt.com> 7 * 8 * Based on (well, mostly copied from) the code from the 2.4 kernel by 9 * Dale Farnsworth <dfarnsworth@mvista.com> and Kent Borg. 10 * 11 * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com> 12 * Copyright (C) 2003 Montavista Software, Inc 13 * 14 * This file is licensed under the terms of the GNU General Public License 15 * version 2. This program is licensed "as is" without any warranty of any 16 * kind, whether express or implied. 17 */ 18 19#include <linux/stddef.h> 20#include <linux/init.h> 21#include <linux/sched.h> 22#include <linux/signal.h> 23#include <linux/stddef.h> 24#include <linux/delay.h> 25#include <linux/irq.h> 26 27#include <asm/io.h> 28#include <asm/processor.h> 29#include <asm/system.h> 30#include <asm/irq.h> 31#include <asm/mpc52xx.h> 32 33 34static struct mpc52xx_intr __iomem *intr; 35static struct mpc52xx_sdma __iomem *sdma; 36 37static void 38mpc52xx_ic_disable(unsigned int irq) 39{ 40 u32 val; 41 42 if (irq == MPC52xx_IRQ0) { 43 val = in_be32(&intr->ctrl); 44 val &= ~(1 << 11); 45 out_be32(&intr->ctrl, val); 46 } 47 else if (irq < MPC52xx_IRQ1) { 48 BUG(); 49 } 50 else if (irq <= MPC52xx_IRQ3) { 51 val = in_be32(&intr->ctrl); 52 val &= ~(1 << (10 - (irq - MPC52xx_IRQ1))); 53 out_be32(&intr->ctrl, val); 54 } 55 else if (irq < MPC52xx_SDMA_IRQ_BASE) { 56 val = in_be32(&intr->main_mask); 57 val |= 1 << (16 - (irq - MPC52xx_MAIN_IRQ_BASE)); 58 out_be32(&intr->main_mask, val); 59 } 60 else if (irq < MPC52xx_PERP_IRQ_BASE) { 61 val = in_be32(&sdma->IntMask); 62 val |= 1 << (irq - MPC52xx_SDMA_IRQ_BASE); 63 out_be32(&sdma->IntMask, val); 64 } 65 else { 66 val = in_be32(&intr->per_mask); 67 val |= 1 << (31 - (irq - MPC52xx_PERP_IRQ_BASE)); 68 out_be32(&intr->per_mask, val); 69 } 70} 71 72static void 73mpc52xx_ic_enable(unsigned int irq) 74{ 75 u32 val; 76 77 if (irq == MPC52xx_IRQ0) { 78 val = in_be32(&intr->ctrl); 79 val |= 1 << 11; 80 out_be32(&intr->ctrl, val); 81 } 82 else if (irq < MPC52xx_IRQ1) { 83 BUG(); 84 } 85 else if (irq <= MPC52xx_IRQ3) { 86 val = in_be32(&intr->ctrl); 87 val |= 1 << (10 - (irq - MPC52xx_IRQ1)); 88 out_be32(&intr->ctrl, val); 89 } 90 else if (irq < MPC52xx_SDMA_IRQ_BASE) { 91 val = in_be32(&intr->main_mask); 92 val &= ~(1 << (16 - (irq - MPC52xx_MAIN_IRQ_BASE))); 93 out_be32(&intr->main_mask, val); 94 } 95 else if (irq < MPC52xx_PERP_IRQ_BASE) { 96 val = in_be32(&sdma->IntMask); 97 val &= ~(1 << (irq - MPC52xx_SDMA_IRQ_BASE)); 98 out_be32(&sdma->IntMask, val); 99 } 100 else { 101 val = in_be32(&intr->per_mask); 102 val &= ~(1 << (31 - (irq - MPC52xx_PERP_IRQ_BASE))); 103 out_be32(&intr->per_mask, val); 104 } 105} 106 107static void 108mpc52xx_ic_ack(unsigned int irq) 109{ 110 u32 val; 111 112 /* 113 * Only some irqs are reset here, others in interrupting hardware. 114 */ 115 116 switch (irq) { 117 case MPC52xx_IRQ0: 118 val = in_be32(&intr->ctrl); 119 val |= 0x08000000; 120 out_be32(&intr->ctrl, val); 121 break; 122 case MPC52xx_CCS_IRQ: 123 val = in_be32(&intr->enc_status); 124 val |= 0x00000400; 125 out_be32(&intr->enc_status, val); 126 break; 127 case MPC52xx_IRQ1: 128 val = in_be32(&intr->ctrl); 129 val |= 0x04000000; 130 out_be32(&intr->ctrl, val); 131 break; 132 case MPC52xx_IRQ2: 133 val = in_be32(&intr->ctrl); 134 val |= 0x02000000; 135 out_be32(&intr->ctrl, val); 136 break; 137 case MPC52xx_IRQ3: 138 val = in_be32(&intr->ctrl); 139 val |= 0x01000000; 140 out_be32(&intr->ctrl, val); 141 break; 142 default: 143 if (irq >= MPC52xx_SDMA_IRQ_BASE 144 && irq < (MPC52xx_SDMA_IRQ_BASE + MPC52xx_SDMA_IRQ_NUM)) { 145 out_be32(&sdma->IntPend, 146 1 << (irq - MPC52xx_SDMA_IRQ_BASE)); 147 } 148 break; 149 } 150} 151 152static void 153mpc52xx_ic_disable_and_ack(unsigned int irq) 154{ 155 mpc52xx_ic_disable(irq); 156 mpc52xx_ic_ack(irq); 157} 158 159static void 160mpc52xx_ic_end(unsigned int irq) 161{ 162 if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) 163 mpc52xx_ic_enable(irq); 164} 165 166static struct hw_interrupt_type mpc52xx_ic = { 167 .typename = " MPC52xx ", 168 .enable = mpc52xx_ic_enable, 169 .disable = mpc52xx_ic_disable, 170 .ack = mpc52xx_ic_disable_and_ack, 171 .end = mpc52xx_ic_end, 172}; 173 174void __init 175mpc52xx_init_irq(void) 176{ 177 int i; 178 u32 intr_ctrl; 179 180 /* Remap the necessary zones */ 181 intr = ioremap(MPC52xx_PA(MPC52xx_INTR_OFFSET), MPC52xx_INTR_SIZE); 182 sdma = ioremap(MPC52xx_PA(MPC52xx_SDMA_OFFSET), MPC52xx_SDMA_SIZE); 183 184 if ((intr==NULL) || (sdma==NULL)) 185 panic("Can't ioremap PIC/SDMA register for init_irq !"); 186 187 /* Disable all interrupt sources. */ 188 out_be32(&sdma->IntPend, 0xffffffff); /* 1 means clear pending */ 189 out_be32(&sdma->IntMask, 0xffffffff); /* 1 means disabled */ 190 out_be32(&intr->per_mask, 0x7ffffc00); /* 1 means disabled */ 191 out_be32(&intr->main_mask, 0x00010fff); /* 1 means disabled */ 192 intr_ctrl = in_be32(&intr->ctrl); 193 intr_ctrl &= 0x00ff0000; /* Keeps IRQ[0-3] config */ 194 intr_ctrl |= 0x0f000000 | /* clear IRQ 0-3 */ 195 0x00001000 | /* MEE master external enable */ 196 0x00000000 | /* 0 means disable IRQ 0-3 */ 197 0x00000001; /* CEb route critical normally */ 198 out_be32(&intr->ctrl, intr_ctrl); 199 200 /* Zero a bunch of the priority settings. */ 201 out_be32(&intr->per_pri1, 0); 202 out_be32(&intr->per_pri2, 0); 203 out_be32(&intr->per_pri3, 0); 204 out_be32(&intr->main_pri1, 0); 205 out_be32(&intr->main_pri2, 0); 206 207 /* Initialize irq_desc[i].chip's with mpc52xx_ic. */ 208 for (i = 0; i < NR_IRQS; i++) { 209 irq_desc[i].chip = &mpc52xx_ic; 210 irq_desc[i].status = IRQ_LEVEL; 211 } 212 213 #define IRQn_MODE(intr_ctrl,irq) (((intr_ctrl) >> (22-(i<<1))) & 0x03) 214 for (i=0 ; i<4 ; i++) { 215 int mode; 216 mode = IRQn_MODE(intr_ctrl,i); 217 if ((mode == 0x1) || (mode == 0x2)) 218 irq_desc[i?MPC52xx_IRQ1+i-1:MPC52xx_IRQ0].status = 0; 219 } 220} 221 222int 223mpc52xx_get_irq(void) 224{ 225 u32 status; 226 int irq = -1; 227 228 status = in_be32(&intr->enc_status); 229 230 if (status & 0x00000400) { /* critical */ 231 irq = (status >> 8) & 0x3; 232 if (irq == 2) /* high priority peripheral */ 233 goto peripheral; 234 irq += MPC52xx_CRIT_IRQ_BASE; 235 } 236 else if (status & 0x00200000) { /* main */ 237 irq = (status >> 16) & 0x1f; 238 if (irq == 4) /* low priority peripheral */ 239 goto peripheral; 240 irq += MPC52xx_MAIN_IRQ_BASE; 241 } 242 else if (status & 0x20000000) { /* peripheral */ 243peripheral: 244 irq = (status >> 24) & 0x1f; 245 if (irq == 0) { /* bestcomm */ 246 status = in_be32(&sdma->IntPend); 247 irq = ffs(status) + MPC52xx_SDMA_IRQ_BASE-1; 248 } 249 else 250 irq += MPC52xx_PERP_IRQ_BASE; 251 } 252 253 return irq; 254} 255