irq_ipr.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:8k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /* $Id: irq_ipr.c,v 1.20 2001/07/15 23:26:56 gniibe Exp $
  2.  *
  3.  * linux/arch/sh/kernel/irq_ipr.c
  4.  *
  5.  * Copyright (C) 1999  Niibe Yutaka & Takeshi Yaegashi
  6.  * Copyright (C) 2000  Kazumoto Kojima
  7.  *
  8.  * Interrupt handling for IPR-based IRQ.
  9.  *
  10.  * Supported system:
  11.  * On-chip supporting modules (TMU, RTC, etc.).
  12.  * On-chip supporting modules for SH7709/SH7709A/SH7729.
  13.  * Hitachi SolutionEngine external I/O:
  14.  * MS7709SE01, MS7709ASE01, and MS7750SE01
  15.  *
  16.  */
  17. #include <linux/config.h>
  18. #include <linux/init.h>
  19. #include <linux/irq.h>
  20. #include <asm/system.h>
  21. #include <asm/io.h>
  22. #include <asm/machvec.h>
  23. struct ipr_data {
  24. unsigned int addr; /* Address of Interrupt Priority Register */
  25. int shift; /* Shifts of the 16-bit data */
  26. int priority; /* The priority */
  27. };
  28. static struct ipr_data ipr_data[NR_IRQS];
  29. static void enable_ipr_irq(unsigned int irq);
  30. static void disable_ipr_irq(unsigned int irq);
  31. /* shutdown is same as "disable" */
  32. #define shutdown_ipr_irq disable_ipr_irq
  33. static void mask_and_ack_ipr(unsigned int);
  34. static void end_ipr_irq(unsigned int irq);
  35. static unsigned int startup_ipr_irq(unsigned int irq)
  36. enable_ipr_irq(irq);
  37. return 0; /* never anything pending */
  38. }
  39. static struct hw_interrupt_type ipr_irq_type = {
  40. "IPR-IRQ",
  41. startup_ipr_irq,
  42. shutdown_ipr_irq,
  43. enable_ipr_irq,
  44. disable_ipr_irq,
  45. mask_and_ack_ipr,
  46. end_ipr_irq
  47. };
  48. static void disable_ipr_irq(unsigned int irq)
  49. {
  50. unsigned long val, flags;
  51. unsigned int addr = ipr_data[irq].addr;
  52. unsigned short mask = 0xffff ^ (0x0f << ipr_data[irq].shift);
  53. /* Set the priority in IPR to 0 */
  54. save_and_cli(flags);
  55. val = ctrl_inw(addr);
  56. val &= mask;
  57. ctrl_outw(val, addr);
  58. restore_flags(flags);
  59. }
  60. static void enable_ipr_irq(unsigned int irq)
  61. {
  62. unsigned long val, flags;
  63. unsigned int addr = ipr_data[irq].addr;
  64. int priority = ipr_data[irq].priority;
  65. unsigned short value = (priority << ipr_data[irq].shift);
  66. /* Set priority in IPR back to original value */
  67. save_and_cli(flags);
  68. val = ctrl_inw(addr);
  69. val |= value;
  70. ctrl_outw(val, addr);
  71. restore_flags(flags);
  72. }
  73. static void mask_and_ack_ipr(unsigned int irq)
  74. {
  75. disable_ipr_irq(irq);
  76. #if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709)
  77. /* This is needed when we use edge triggered setting */
  78. /* XXX: Is it really needed? */
  79. if (IRQ0_IRQ <= irq && irq <= IRQ5_IRQ) {
  80. /* Clear external interrupt request */
  81. int a = ctrl_inb(INTC_IRR0);
  82. a &= ~(1 << (irq - IRQ0_IRQ));
  83. ctrl_outb(a, INTC_IRR0);
  84. }
  85. #endif
  86. }
  87. static void end_ipr_irq(unsigned int irq)
  88. {
  89. if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
  90. enable_ipr_irq(irq);
  91. }
  92. void make_ipr_irq(unsigned int irq, unsigned int addr, int pos, int priority)
  93. {
  94. disable_irq_nosync(irq);
  95. ipr_data[irq].addr = addr;
  96. ipr_data[irq].shift = pos*4; /* POSition (0-3) x 4 means shift */
  97. ipr_data[irq].priority = priority;
  98. irq_desc[irq].handler = &ipr_irq_type;
  99. disable_ipr_irq(irq);
  100. }
  101. #if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709)
  102. static unsigned char pint_map[256];
  103. static unsigned long portcr_mask = 0;
  104. static void enable_pint_irq(unsigned int irq);
  105. static void disable_pint_irq(unsigned int irq);
  106. /* shutdown is same as "disable" */
  107. #define shutdown_pint_irq disable_pint_irq
  108. static void mask_and_ack_pint(unsigned int);
  109. static void end_pint_irq(unsigned int irq);
  110. static unsigned int startup_pint_irq(unsigned int irq)
  111. enable_pint_irq(irq);
  112. return 0; /* never anything pending */
  113. }
  114. static struct hw_interrupt_type pint_irq_type = {
  115. "PINT-IRQ",
  116. startup_pint_irq,
  117. shutdown_pint_irq,
  118. enable_pint_irq,
  119. disable_pint_irq,
  120. mask_and_ack_pint,
  121. end_pint_irq
  122. };
  123. static void disable_pint_irq(unsigned int irq)
  124. {
  125. unsigned long val, flags;
  126. save_and_cli(flags);
  127. val = ctrl_inw(INTC_INTER);
  128. val &= ~(1 << (irq - PINT_IRQ_BASE));
  129. ctrl_outw(val, INTC_INTER); /* disable PINTn */
  130. portcr_mask &= ~(3 << (irq - PINT_IRQ_BASE)*2);
  131. restore_flags(flags);
  132. }
  133. static void enable_pint_irq(unsigned int irq)
  134. {
  135. unsigned long val, flags;
  136. save_and_cli(flags);
  137. val = ctrl_inw(INTC_INTER);
  138. val |= 1 << (irq - PINT_IRQ_BASE);
  139. ctrl_outw(val, INTC_INTER); /* enable PINTn */
  140. portcr_mask |= 3 << (irq - PINT_IRQ_BASE)*2;
  141. restore_flags(flags);
  142. }
  143. static void mask_and_ack_pint(unsigned int irq)
  144. {
  145. disable_pint_irq(irq);
  146. }
  147. static void end_pint_irq(unsigned int irq)
  148. {
  149. if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
  150. enable_pint_irq(irq);
  151. }
  152. void make_pint_irq(unsigned int irq)
  153. {
  154. disable_irq_nosync(irq);
  155. irq_desc[irq].handler = &pint_irq_type;
  156. disable_pint_irq(irq);
  157. }
  158. #endif
  159. void __init init_IRQ(void)
  160. {
  161. #if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709)
  162. int i;
  163. #endif
  164. make_ipr_irq(TIMER_IRQ, TIMER_IPR_ADDR, TIMER_IPR_POS, TIMER_PRIORITY);
  165. make_ipr_irq(RTC_IRQ, RTC_IPR_ADDR, RTC_IPR_POS, RTC_PRIORITY);
  166. #ifdef SCI_ERI_IRQ
  167. make_ipr_irq(SCI_ERI_IRQ, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY);
  168. make_ipr_irq(SCI_RXI_IRQ, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY);
  169. make_ipr_irq(SCI_TXI_IRQ, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY);
  170. #endif
  171. #ifdef SCIF1_ERI_IRQ
  172. make_ipr_irq(SCIF1_ERI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY);
  173. make_ipr_irq(SCIF1_RXI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY);
  174. make_ipr_irq(SCIF1_BRI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY);
  175. make_ipr_irq(SCIF1_TXI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY);
  176. #endif
  177. #ifdef SCIF_ERI_IRQ
  178. make_ipr_irq(SCIF_ERI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY);
  179. make_ipr_irq(SCIF_RXI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY);
  180. make_ipr_irq(SCIF_BRI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY);
  181. make_ipr_irq(SCIF_TXI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY);
  182. #endif
  183. #ifdef IRDA_ERI_IRQ
  184. make_ipr_irq(IRDA_ERI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY);
  185. make_ipr_irq(IRDA_RXI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY);
  186. make_ipr_irq(IRDA_BRI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY);
  187. make_ipr_irq(IRDA_TXI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY);
  188. #endif
  189. #if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709)
  190. /*
  191.  * Initialize the Interrupt Controller (INTC)
  192.  * registers to their power on values
  193.  */ 
  194. /*
  195.  * Enable external irq (INTC IRQ mode).
  196.  * You should set corresponding bits of PFC to "00"
  197.  * to enable these interrupts.
  198.  */
  199. make_ipr_irq(IRQ0_IRQ, IRQ0_IPR_ADDR, IRQ0_IPR_POS, IRQ0_PRIORITY);
  200. make_ipr_irq(IRQ1_IRQ, IRQ1_IPR_ADDR, IRQ1_IPR_POS, IRQ1_PRIORITY);
  201. make_ipr_irq(IRQ2_IRQ, IRQ2_IPR_ADDR, IRQ2_IPR_POS, IRQ2_PRIORITY);
  202. make_ipr_irq(IRQ3_IRQ, IRQ3_IPR_ADDR, IRQ3_IPR_POS, IRQ3_PRIORITY);
  203. make_ipr_irq(IRQ4_IRQ, IRQ4_IPR_ADDR, IRQ4_IPR_POS, IRQ4_PRIORITY);
  204. make_ipr_irq(IRQ5_IRQ, IRQ5_IPR_ADDR, IRQ5_IPR_POS, IRQ5_PRIORITY);
  205. make_ipr_irq(PINT0_IRQ, PINT0_IPR_ADDR, PINT0_IPR_POS, PINT0_PRIORITY);
  206. make_ipr_irq(PINT8_IRQ, PINT8_IPR_ADDR, PINT8_IPR_POS, PINT8_PRIORITY);
  207. enable_ipr_irq(PINT0_IRQ);
  208. enable_ipr_irq(PINT8_IRQ);
  209. for(i = 0; i < 16; i++)
  210. make_pint_irq(PINT_IRQ_BASE + i);
  211. for(i = 0; i < 256; i++)
  212. {
  213. if(i & 1) pint_map[i] = 0;
  214. else if(i & 2) pint_map[i] = 1;
  215. else if(i & 4) pint_map[i] = 2;
  216. else if(i & 8) pint_map[i] = 3;
  217. else if(i & 0x10) pint_map[i] = 4;
  218. else if(i & 0x20) pint_map[i] = 5;
  219. else if(i & 0x40) pint_map[i] = 6;
  220. else if(i & 0x80) pint_map[i] = 7;
  221. }
  222. #endif /* CONFIG_CPU_SUBTYPE_SH7707 || CONFIG_CPU_SUBTYPE_SH7709 */
  223. /* Perform the machine specific initialisation */
  224. if (sh_mv.mv_init_irq != NULL) {
  225. sh_mv.mv_init_irq();
  226. }
  227. }
  228. #if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709)
  229. int ipr_irq_demux(int irq)
  230. {
  231. unsigned long creg, dreg, d, sav;
  232. if(irq == PINT0_IRQ)
  233. {
  234. #if defined(CONFIG_CPU_SUBTYPE_SH7707)
  235. creg = PORT_PACR;
  236. dreg = PORT_PADR;
  237. #else
  238. creg = PORT_PCCR;
  239. dreg = PORT_PCDR;
  240. #endif
  241. sav = ctrl_inw(creg);
  242. ctrl_outw(sav | portcr_mask, creg);
  243. d = (~ctrl_inb(dreg) ^ ctrl_inw(INTC_ICR2)) & ctrl_inw(INTC_INTER) & 0xff;
  244. ctrl_outw(sav, creg);
  245. if(d == 0) return irq;
  246. return PINT_IRQ_BASE + pint_map[d];
  247. }
  248. else if(irq == PINT8_IRQ)
  249. {
  250. #if defined(CONFIG_CPU_SUBTYPE_SH7707)
  251. creg = PORT_PBCR;
  252. dreg = PORT_PBDR;
  253. #else
  254. creg = PORT_PFCR;
  255. dreg = PORT_PFDR;
  256. #endif
  257. sav = ctrl_inw(creg);
  258. ctrl_outw(sav | (portcr_mask >> 16), creg);
  259. d = (~ctrl_inb(dreg) ^ (ctrl_inw(INTC_ICR2) >> 8)) & (ctrl_inw(INTC_INTER) >> 8) & 0xff;
  260. ctrl_outw(sav, creg);
  261. if(d == 0) return irq;
  262. return PINT_IRQ_BASE + 8 + pint_map[d];
  263. }
  264. return irq;
  265. }
  266. #endif