1/* 2 * iop13xx IRQ handling / support functions 3 * Copyright (c) 2005-2006, Intel Corporation. 4 * 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms and conditions of the GNU General Public License, 7 * version 2, as published by the Free Software Foundation. 8 * 9 * This program is distributed in the hope it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12 * more details. 13 * 14 * You should have received a copy of the GNU General Public License along with 15 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple 16 * Place - Suite 330, Boston, MA 02111-1307 USA. 17 * 18 */ 19#include <linux/init.h> 20#include <linux/interrupt.h> 21#include <linux/list.h> 22#include <linux/sysctl.h> 23#include <asm/uaccess.h> 24#include <asm/mach/irq.h> 25#include <asm/irq.h> 26#include <mach/hardware.h> 27#include <mach/irqs.h> 28#include <mach/msi.h> 29 30/* INTCTL0 CP6 R0 Page 4 31 */ 32static u32 read_intctl_0(void) 33{ 34 u32 val; 35 asm volatile("mrc p6, 0, %0, c0, c4, 0":"=r" (val)); 36 return val; 37} 38static void write_intctl_0(u32 val) 39{ 40 asm volatile("mcr p6, 0, %0, c0, c4, 0"::"r" (val)); 41} 42 43/* INTCTL1 CP6 R1 Page 4 44 */ 45static u32 read_intctl_1(void) 46{ 47 u32 val; 48 asm volatile("mrc p6, 0, %0, c1, c4, 0":"=r" (val)); 49 return val; 50} 51static void write_intctl_1(u32 val) 52{ 53 asm volatile("mcr p6, 0, %0, c1, c4, 0"::"r" (val)); 54} 55 56/* INTCTL2 CP6 R2 Page 4 57 */ 58static u32 read_intctl_2(void) 59{ 60 u32 val; 61 asm volatile("mrc p6, 0, %0, c2, c4, 0":"=r" (val)); 62 return val; 63} 64static void write_intctl_2(u32 val) 65{ 66 asm volatile("mcr p6, 0, %0, c2, c4, 0"::"r" (val)); 67} 68 69/* INTCTL3 CP6 R3 Page 4 70 */ 71static u32 read_intctl_3(void) 72{ 73 u32 val; 74 asm volatile("mrc p6, 0, %0, c3, c4, 0":"=r" (val)); 75 return val; 76} 77static void write_intctl_3(u32 val) 78{ 79 asm volatile("mcr p6, 0, %0, c3, c4, 0"::"r" (val)); 80} 81 82/* INTSTR0 CP6 R0 Page 5 83 */ 84static void write_intstr_0(u32 val) 85{ 86 asm volatile("mcr p6, 0, %0, c0, c5, 0"::"r" (val)); 87} 88 89/* INTSTR1 CP6 R1 Page 5 90 */ 91static void write_intstr_1(u32 val) 92{ 93 asm volatile("mcr p6, 0, %0, c1, c5, 0"::"r" (val)); 94} 95 96/* INTSTR2 CP6 R2 Page 5 97 */ 98static void write_intstr_2(u32 val) 99{ 100 asm volatile("mcr p6, 0, %0, c2, c5, 0"::"r" (val)); 101} 102 103/* INTSTR3 CP6 R3 Page 5 104 */ 105static void write_intstr_3(u32 val) 106{ 107 asm volatile("mcr p6, 0, %0, c3, c5, 0"::"r" (val)); 108} 109 110/* INTBASE CP6 R0 Page 2 111 */ 112static void write_intbase(u32 val) 113{ 114 asm volatile("mcr p6, 0, %0, c0, c2, 0"::"r" (val)); 115} 116 117/* INTSIZE CP6 R2 Page 2 118 */ 119static void write_intsize(u32 val) 120{ 121 asm volatile("mcr p6, 0, %0, c2, c2, 0"::"r" (val)); 122} 123 124/* 0 = Interrupt Masked and 1 = Interrupt not masked */ 125static void 126iop13xx_irq_mask0 (struct irq_data *d) 127{ 128 write_intctl_0(read_intctl_0() & ~(1 << (d->irq - 0))); 129} 130 131static void 132iop13xx_irq_mask1 (struct irq_data *d) 133{ 134 write_intctl_1(read_intctl_1() & ~(1 << (d->irq - 32))); 135} 136 137static void 138iop13xx_irq_mask2 (struct irq_data *d) 139{ 140 write_intctl_2(read_intctl_2() & ~(1 << (d->irq - 64))); 141} 142 143static void 144iop13xx_irq_mask3 (struct irq_data *d) 145{ 146 write_intctl_3(read_intctl_3() & ~(1 << (d->irq - 96))); 147} 148 149static void 150iop13xx_irq_unmask0(struct irq_data *d) 151{ 152 write_intctl_0(read_intctl_0() | (1 << (d->irq - 0))); 153} 154 155static void 156iop13xx_irq_unmask1(struct irq_data *d) 157{ 158 write_intctl_1(read_intctl_1() | (1 << (d->irq - 32))); 159} 160 161static void 162iop13xx_irq_unmask2(struct irq_data *d) 163{ 164 write_intctl_2(read_intctl_2() | (1 << (d->irq - 64))); 165} 166 167static void 168iop13xx_irq_unmask3(struct irq_data *d) 169{ 170 write_intctl_3(read_intctl_3() | (1 << (d->irq - 96))); 171} 172 173static struct irq_chip iop13xx_irqchip1 = { 174 .name = "IOP13xx-1", 175 .irq_ack = iop13xx_irq_mask0, 176 .irq_mask = iop13xx_irq_mask0, 177 .irq_unmask = iop13xx_irq_unmask0, 178}; 179 180static struct irq_chip iop13xx_irqchip2 = { 181 .name = "IOP13xx-2", 182 .irq_ack = iop13xx_irq_mask1, 183 .irq_mask = iop13xx_irq_mask1, 184 .irq_unmask = iop13xx_irq_unmask1, 185}; 186 187static struct irq_chip iop13xx_irqchip3 = { 188 .name = "IOP13xx-3", 189 .irq_ack = iop13xx_irq_mask2, 190 .irq_mask = iop13xx_irq_mask2, 191 .irq_unmask = iop13xx_irq_unmask2, 192}; 193 194static struct irq_chip iop13xx_irqchip4 = { 195 .name = "IOP13xx-4", 196 .irq_ack = iop13xx_irq_mask3, 197 .irq_mask = iop13xx_irq_mask3, 198 .irq_unmask = iop13xx_irq_unmask3, 199}; 200 201extern void iop_init_cp6_handler(void); 202 203void __init iop13xx_init_irq(void) 204{ 205 unsigned int i; 206 207 iop_init_cp6_handler(); 208 209 /* disable all interrupts */ 210 write_intctl_0(0); 211 write_intctl_1(0); 212 write_intctl_2(0); 213 write_intctl_3(0); 214 215 /* treat all as IRQ */ 216 write_intstr_0(0); 217 write_intstr_1(0); 218 write_intstr_2(0); 219 write_intstr_3(0); 220 221 /* initialize the interrupt vector generator */ 222 write_intbase(INTBASE); 223 write_intsize(INTSIZE_4); 224 225 for(i = 0; i <= IRQ_IOP13XX_HPI; i++) { 226 if (i < 32) 227 irq_set_chip(i, &iop13xx_irqchip1); 228 else if (i < 64) 229 irq_set_chip(i, &iop13xx_irqchip2); 230 else if (i < 96) 231 irq_set_chip(i, &iop13xx_irqchip3); 232 else 233 irq_set_chip(i, &iop13xx_irqchip4); 234 235 irq_set_handler(i, handle_level_irq); 236 set_irq_flags(i, IRQF_VALID | IRQF_PROBE); 237 } 238 239 iop13xx_msi_init(); 240} 241