ints.c 7.9 KB

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