1/* 2 * linux/arch/h8300/platform/h8s/ints.c 3 * 4 * Yoshinori Sato <ysato@users.sourceforge.jp> 5 * 6 * Based on linux/arch/$(ARCH)/platform/$(PLATFORM)/ints.c 7 * 8 * This file is subject to the terms and conditions of the GNU General Public 9 * License. See the file COPYING in the main directory of this archive 10 * for more details. 11 * 12 * Copyright 1996 Roman Zippel 13 * Copyright 1999 D. Jeff Dionne <jeff@rt-control.com> 14 */ 15 16#include <linux/module.h> 17#include <linux/types.h> 18#include <linux/kernel.h> 19#include <linux/sched.h> 20#include <linux/kernel_stat.h> 21#include <linux/seq_file.h> 22#include <linux/init.h> 23#include <linux/interrupt.h> 24#include <linux/bootmem.h> 25#include <linux/random.h> 26#include <linux/hardirq.h> 27 28#include <asm/system.h> 29#include <asm/irq.h> 30#include <asm/traps.h> 31#include <asm/io.h> 32#include <asm/setup.h> 33#include <asm/gpio.h> 34#include <asm/regs267x.h> 35#include <asm/errno.h> 36 37/* 38 * This structure has only 4 elements for speed reasons 39 */ 40typedef struct irq_handler { 41 irqreturn_t (*handler)(int, void *, struct pt_regs *); 42 int flags; 43 int count; 44 void *dev_id; 45 const char *devname; 46} irq_handler_t; 47 48static irq_handler_t *irq_list[NR_IRQS]; 49 50/* IRQ pin assignment */ 51struct irq_pins { 52 unsigned char port_no; 53 unsigned char bit_no; 54}; 55/* ISTR = 0 */ 56static const struct irq_pins irq_assign_table0[16]={ 57 {H8300_GPIO_P5,H8300_GPIO_B0},{H8300_GPIO_P5,H8300_GPIO_B1}, 58 {H8300_GPIO_P5,H8300_GPIO_B2},{H8300_GPIO_P5,H8300_GPIO_B3}, 59 {H8300_GPIO_P5,H8300_GPIO_B4},{H8300_GPIO_P5,H8300_GPIO_B5}, 60 {H8300_GPIO_P5,H8300_GPIO_B6},{H8300_GPIO_P5,H8300_GPIO_B7}, 61 {H8300_GPIO_P6,H8300_GPIO_B0},{H8300_GPIO_P6,H8300_GPIO_B1}, 62 {H8300_GPIO_P6,H8300_GPIO_B2},{H8300_GPIO_P6,H8300_GPIO_B3}, 63 {H8300_GPIO_P6,H8300_GPIO_B4},{H8300_GPIO_P6,H8300_GPIO_B5}, 64 {H8300_GPIO_PF,H8300_GPIO_B1},{H8300_GPIO_PF,H8300_GPIO_B2}, 65}; 66/* ISTR = 1 */ 67static const struct irq_pins irq_assign_table1[16]={ 68 {H8300_GPIO_P8,H8300_GPIO_B0},{H8300_GPIO_P8,H8300_GPIO_B1}, 69 {H8300_GPIO_P8,H8300_GPIO_B2},{H8300_GPIO_P8,H8300_GPIO_B3}, 70 {H8300_GPIO_P8,H8300_GPIO_B4},{H8300_GPIO_P8,H8300_GPIO_B5}, 71 {H8300_GPIO_PH,H8300_GPIO_B2},{H8300_GPIO_PH,H8300_GPIO_B3}, 72 {H8300_GPIO_P2,H8300_GPIO_B0},{H8300_GPIO_P2,H8300_GPIO_B1}, 73 {H8300_GPIO_P2,H8300_GPIO_B2},{H8300_GPIO_P2,H8300_GPIO_B3}, 74 {H8300_GPIO_P2,H8300_GPIO_B4},{H8300_GPIO_P2,H8300_GPIO_B5}, 75 {H8300_GPIO_P2,H8300_GPIO_B6},{H8300_GPIO_P2,H8300_GPIO_B7}, 76}; 77 78static short use_kmalloc = 0; 79 80extern unsigned long *interrupt_redirect_table; 81 82#define CPU_VECTOR ((unsigned long *)0x000000) 83#define ADDR_MASK (0xffffff) 84 85static inline unsigned long *get_vector_address(void) 86{ 87 volatile unsigned long *rom_vector = CPU_VECTOR; 88 unsigned long base,tmp; 89 int vec_no; 90 91 base = rom_vector[EXT_IRQ0] & ADDR_MASK; 92 93 /* check romvector format */ 94 for (vec_no = EXT_IRQ1; vec_no <= EXT_IRQ15; vec_no++) { 95 if ((base+(vec_no - EXT_IRQ0)*4) != (rom_vector[vec_no] & ADDR_MASK)) 96 return NULL; 97 } 98 99 /* ramvector base address */ 100 base -= EXT_IRQ0*4; 101 102 /* writerble check */ 103 tmp = ~(*(unsigned long *)base); 104 (*(unsigned long *)base) = tmp; 105 if ((*(unsigned long *)base) != tmp) 106 return NULL; 107 return (unsigned long *)base; 108} 109 110void __init init_IRQ(void) 111{ 112#if defined(CONFIG_RAMKERNEL) 113 int i; 114 unsigned long *ramvec,*ramvec_p; 115 unsigned long break_vec; 116 117 ramvec = get_vector_address(); 118 if (ramvec == NULL) 119 panic("interrupt vector serup failed."); 120 else 121 printk("virtual vector at 0x%08lx\n",(unsigned long)ramvec); 122 123#if defined(CONFIG_GDB_DEBUG) 124 /* save orignal break vector */ 125 break_vec = ramvec[TRAP3_VEC]; 126#else 127 break_vec = VECTOR(trace_break); 128#endif 129 130 /* create redirect table */ 131 for (ramvec_p = ramvec, i = 0; i < NR_IRQS; i++) 132 *ramvec_p++ = REDIRECT(interrupt_entry); 133 134 /* set special vector */ 135 ramvec[TRAP0_VEC] = VECTOR(system_call); 136 ramvec[TRAP3_VEC] = break_vec; 137 interrupt_redirect_table = ramvec; 138#ifdef DUMP_VECTOR 139 ramvec_p = ramvec; 140 for (i = 0; i < NR_IRQS; i++) { 141 if ((i % 8) == 0) 142 printk("\n%p: ",ramvec_p); 143 printk("%p ",*ramvec_p); 144 ramvec_p++; 145 } 146 printk("\n"); 147#endif 148#endif 149} 150 151int request_irq(unsigned int irq, 152 irqreturn_t (*handler)(int, void *, struct pt_regs *), 153 unsigned long flags, const char *devname, void *dev_id) 154{ 155 unsigned short ptn = 1 << (irq - EXT_IRQ0); 156 irq_handler_t *irq_handle; 157 if (irq < 0 || irq >= NR_IRQS) { 158 printk("Incorrect IRQ %d from %s\n", irq, devname); 159 return -EINVAL; 160 } 161 if (irq_list[irq]) 162 return -EBUSY; /* already used */ 163 if (irq >= EXT_IRQ0 && irq <= EXT_IRQ15) { 164 /* initialize IRQ pin */ 165 unsigned int port_no,bit_no; 166 if (*(volatile unsigned short *)ITSR & ptn) { 167 port_no = irq_assign_table1[irq - EXT_IRQ0].port_no; 168 bit_no = irq_assign_table1[irq - EXT_IRQ0].bit_no; 169 } else { 170 port_no = irq_assign_table0[irq - EXT_IRQ0].port_no; 171 bit_no = irq_assign_table0[irq - EXT_IRQ0].bit_no; 172 } 173 if (H8300_GPIO_RESERVE(port_no, bit_no) == 0) 174 return -EBUSY; /* pin already use */ 175 H8300_GPIO_DDR(port_no, bit_no, H8300_GPIO_INPUT); 176 *(volatile unsigned short *)ISR &= ~ptn; /* ISR clear */ 177 } 178 179 if (use_kmalloc) 180 irq_handle = kmalloc(sizeof(irq_handler_t), GFP_ATOMIC); 181 else { 182 /* use bootmem allocater */ 183 irq_handle = (irq_handler_t *)alloc_bootmem(sizeof(irq_handler_t)); 184 irq_handle = (irq_handler_t *)((unsigned long)irq_handle | 0x80000000); 185 } 186 187 if (irq_handle == NULL) 188 return -ENOMEM; 189 190 irq_handle->handler = handler; 191 irq_handle->flags = flags; 192 irq_handle->count = 0; 193 irq_handle->dev_id = dev_id; 194 irq_handle->devname = devname; 195 irq_list[irq] = irq_handle; 196 if (irq_handle->flags & IRQF_SAMPLE_RANDOM) 197 rand_initialize_irq(irq); 198 199 /* enable interrupt */ 200 /* compatible i386 */ 201 if (irq >= EXT_IRQ0 && irq <= EXT_IRQ15) 202 *(volatile unsigned short *)IER |= ptn; 203 return 0; 204} 205 206EXPORT_SYMBOL(request_irq); 207 208void free_irq(unsigned int irq, void *dev_id) 209{ 210 if (irq >= NR_IRQS) 211 return; 212 if (irq_list[irq]->dev_id != dev_id) 213 printk("%s: Removing probably wrong IRQ %d from %s\n", 214 __FUNCTION__, irq, irq_list[irq]->devname); 215 if (irq >= EXT_IRQ0 && irq <= EXT_IRQ15) { 216 /* disable interrupt & release IRQ pin */ 217 unsigned short port_no,bit_no; 218 *(volatile unsigned short *)ISR &= ~(1 << (irq - EXT_IRQ0)); 219 *(volatile unsigned short *)IER |= 1 << (irq - EXT_IRQ0); 220 if (*(volatile unsigned short *)ITSR & (1 << (irq - EXT_IRQ0))) { 221 port_no = irq_assign_table1[irq - EXT_IRQ0].port_no; 222 bit_no = irq_assign_table1[irq - EXT_IRQ0].bit_no; 223 } else { 224 port_no = irq_assign_table0[irq - EXT_IRQ0].port_no; 225 bit_no = irq_assign_table0[irq - EXT_IRQ0].bit_no; 226 } 227 H8300_GPIO_FREE(port_no, bit_no); 228 } 229 if (((unsigned long)irq_list[irq] & 0x80000000) == 0) { 230 kfree(irq_list[irq]); 231 irq_list[irq] = NULL; 232 } 233} 234 235EXPORT_SYMBOL(free_irq); 236 237unsigned long probe_irq_on (void) 238{ 239 return 0; 240} 241 242EXPORT_SYMBOL(probe_irq_on); 243 244int probe_irq_off (unsigned long irqs) 245{ 246 return 0; 247} 248 249EXPORT_SYMBOL(probe_irq_off); 250 251void enable_irq(unsigned int irq) 252{ 253 if (irq >= EXT_IRQ0 && irq <= EXT_IRQ15) 254 *(volatile unsigned short *)IER |= 1 << (irq - EXT_IRQ0); 255} 256 257void disable_irq(unsigned int irq) 258{ 259 if (irq >= EXT_IRQ0 && irq <= EXT_IRQ15) 260 *(volatile unsigned short *)IER &= ~(1 << (irq - EXT_IRQ0)); 261} 262 263asmlinkage void process_int(unsigned long vec, struct pt_regs *fp) 264{ 265 irq_enter(); 266 /* ISR clear */ 267 /* compatible i386 */ 268 if (vec >= EXT_IRQ0 && vec <= EXT_IRQ15) 269 *(volatile unsigned short *)ISR &= ~(1 << (vec - EXT_IRQ0)); 270 if (vec < NR_IRQS) { 271 if (irq_list[vec]) { 272 irq_list[vec]->handler(vec, irq_list[vec]->dev_id, fp); 273 irq_list[vec]->count++; 274 if (irq_list[vec]->flags & IRQF_SAMPLE_RANDOM) 275 add_interrupt_randomness(vec); 276 } 277 } else { 278 BUG(); 279 } 280 irq_exit(); 281} 282 283int show_interrupts(struct seq_file *p, void *v) 284{ 285 int i = *(loff_t *) v; 286 287 if ((i < NR_IRQS) && (irq_list[i] !=NULL)) { 288 seq_printf(p, "%3d: %10u ",i,irq_list[i]->count); 289 seq_printf(p, "%s\n", irq_list[i]->devname); 290 } 291 292 return 0; 293} 294 295void init_irq_proc(void) 296{ 297} 298 299static int __init enable_kmalloc(void) 300{ 301 use_kmalloc = 1; 302 return 0; 303} 304core_initcall(enable_kmalloc); 305