1/* 2 * Interrupt controller support for IBM Spruce 3 * 4 * Authors: Mark Greer, Matt Porter, and Johnnie Peters 5 * mgreer@mvista.com 6 * mporter@mvista.com 7 * jpeters@mvista.com 8 * 9 * 2001-2002 (c) MontaVista, Software, Inc. This file is licensed under 10 * the terms of the GNU General Public License version 2. This program 11 * is licensed "as is" without any warranty of any kind, whether express 12 * or implied. 13 */ 14 15#include <linux/stddef.h> 16#include <linux/init.h> 17#include <linux/sched.h> 18#include <linux/signal.h> 19#include <linux/irq.h> 20 21#include <asm/io.h> 22#include <asm/system.h> 23#include <asm/irq.h> 24 25#include "cpc700.h" 26 27static void 28cpc700_unmask_irq(unsigned int irq) 29{ 30 unsigned int tr_bits; 31 32 /* 33 * IRQ 31 is largest IRQ supported. 34 * IRQs 17-19 are reserved. 35 */ 36 if ((irq <= 31) && ((irq < 17) || (irq > 19))) { 37 tr_bits = CPC700_IN_32(CPC700_UIC_UICTR); 38 39 if ((tr_bits & (1 << (31 - irq))) == 0) { 40 /* level trigger interrupt, clear bit in status 41 * register */ 42 CPC700_OUT_32(CPC700_UIC_UICSR, 1 << (31 - irq)); 43 } 44 45 /* Know IRQ fits in entry 0 of ppc_cached_irq_mask[] */ 46 ppc_cached_irq_mask[0] |= CPC700_UIC_IRQ_BIT(irq); 47 48 CPC700_OUT_32(CPC700_UIC_UICER, ppc_cached_irq_mask[0]); 49 } 50 return; 51} 52 53static void 54cpc700_mask_irq(unsigned int irq) 55{ 56 /* 57 * IRQ 31 is largest IRQ supported. 58 * IRQs 17-19 are reserved. 59 */ 60 if ((irq <= 31) && ((irq < 17) || (irq > 19))) { 61 /* Know IRQ fits in entry 0 of ppc_cached_irq_mask[] */ 62 ppc_cached_irq_mask[0] &= 63 ~CPC700_UIC_IRQ_BIT(irq); 64 65 CPC700_OUT_32(CPC700_UIC_UICER, ppc_cached_irq_mask[0]); 66 } 67 return; 68} 69 70static void 71cpc700_mask_and_ack_irq(unsigned int irq) 72{ 73 u_int bit; 74 75 /* 76 * IRQ 31 is largest IRQ supported. 77 * IRQs 17-19 are reserved. 78 */ 79 if ((irq <= 31) && ((irq < 17) || (irq > 19))) { 80 /* Know IRQ fits in entry 0 of ppc_cached_irq_mask[] */ 81 bit = CPC700_UIC_IRQ_BIT(irq); 82 83 ppc_cached_irq_mask[0] &= ~bit; 84 CPC700_OUT_32(CPC700_UIC_UICER, ppc_cached_irq_mask[0]); 85 CPC700_OUT_32(CPC700_UIC_UICSR, bit); /* Write 1 clears IRQ */ 86 } 87 return; 88} 89 90static struct hw_interrupt_type cpc700_pic = { 91 .typename = "CPC700 PIC", 92 .enable = cpc700_unmask_irq, 93 .disable = cpc700_mask_irq, 94 .ack = cpc700_mask_and_ack_irq, 95}; 96 97__init static void 98cpc700_pic_init_irq(unsigned int irq) 99{ 100 unsigned int tmp; 101 102 /* Set interrupt sense */ 103 tmp = CPC700_IN_32(CPC700_UIC_UICTR); 104 if (cpc700_irq_assigns[irq][0] == 0) { 105 tmp &= ~CPC700_UIC_IRQ_BIT(irq); 106 } else { 107 tmp |= CPC700_UIC_IRQ_BIT(irq); 108 } 109 CPC700_OUT_32(CPC700_UIC_UICTR, tmp); 110 111 /* Set interrupt polarity */ 112 tmp = CPC700_IN_32(CPC700_UIC_UICPR); 113 if (cpc700_irq_assigns[irq][1]) { 114 tmp |= CPC700_UIC_IRQ_BIT(irq); 115 } else { 116 tmp &= ~CPC700_UIC_IRQ_BIT(irq); 117 } 118 CPC700_OUT_32(CPC700_UIC_UICPR, tmp); 119 120 /* Set interrupt critical */ 121 tmp = CPC700_IN_32(CPC700_UIC_UICCR); 122 tmp |= CPC700_UIC_IRQ_BIT(irq); 123 CPC700_OUT_32(CPC700_UIC_UICCR, tmp); 124 125 return; 126} 127 128__init void 129cpc700_init_IRQ(void) 130{ 131 int i; 132 133 ppc_cached_irq_mask[0] = 0; 134 CPC700_OUT_32(CPC700_UIC_UICER, 0x00000000); /* Disable all irq's */ 135 CPC700_OUT_32(CPC700_UIC_UICSR, 0xffffffff); /* Clear cur intrs */ 136 CPC700_OUT_32(CPC700_UIC_UICCR, 0xffffffff); /* Gen INT not MCP */ 137 CPC700_OUT_32(CPC700_UIC_UICPR, 0x00000000); /* Active low */ 138 CPC700_OUT_32(CPC700_UIC_UICTR, 0x00000000); /* Level Sensitive */ 139 CPC700_OUT_32(CPC700_UIC_UICVR, CPC700_UIC_UICVCR_0_HI); 140 /* IRQ 0 is highest */ 141 142 for (i = 0; i < 17; i++) { 143 irq_desc[i].chip = &cpc700_pic; 144 cpc700_pic_init_irq(i); 145 } 146 147 for (i = 20; i < 32; i++) { 148 irq_desc[i].chip = &cpc700_pic; 149 cpc700_pic_init_irq(i); 150 } 151 152 return; 153} 154 155 156 157/* 158 * Find the highest IRQ that generating an interrupt, if any. 159 */ 160int 161cpc700_get_irq(void) 162{ 163 int irq = 0; 164 u_int irq_status, irq_test = 1; 165 166 irq_status = CPC700_IN_32(CPC700_UIC_UICMSR); 167 168 do 169 { 170 if (irq_status & irq_test) 171 break; 172 irq++; 173 irq_test <<= 1; 174 } while (irq < NR_IRQS); 175 176 177 if (irq == NR_IRQS) 178 irq = 33; 179 180 return (31 - irq); 181} 182