ppc4xx_pic.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. /*
  2. * arch/ppc/syslib/ppc4xx_pic.c
  3. *
  4. * Interrupt controller driver for PowerPC 4xx-based processors.
  5. *
  6. * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
  7. * Copyright (c) 2004, 2005 Zultys Technologies
  8. *
  9. * Based on original code by
  10. * Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
  11. * Armin Custer <akuster@mvista.com>
  12. *
  13. * This program is free software; you can redistribute it and/or modify it
  14. * under the terms of the GNU General Public License as published by the
  15. * Free Software Foundation; either version 2 of the License, or (at your
  16. * option) any later version.
  17. */
  18. #include <linux/config.h>
  19. #include <linux/init.h>
  20. #include <linux/sched.h>
  21. #include <linux/signal.h>
  22. #include <linux/stddef.h>
  23. #include <asm/processor.h>
  24. #include <asm/system.h>
  25. #include <asm/irq.h>
  26. #include <asm/ppc4xx_pic.h>
  27. #include <asm/machdep.h>
  28. /* See comment in include/arch-ppc/ppc4xx_pic.h
  29. * for more info about these two variables
  30. */
  31. extern struct ppc4xx_uic_settings ppc4xx_core_uic_cfg[NR_UICS]
  32. __attribute__ ((weak));
  33. extern unsigned char ppc4xx_uic_ext_irq_cfg[] __attribute__ ((weak));
  34. #define IRQ_MASK_UIC0(irq) (1 << (31 - (irq)))
  35. #define IRQ_MASK_UICx(irq) (1 << (31 - ((irq) & 0x1f)))
  36. #define IRQ_MASK_UIC1(irq) IRQ_MASK_UICx(irq)
  37. #define IRQ_MASK_UIC2(irq) IRQ_MASK_UICx(irq)
  38. #define IRQ_MASK_UIC3(irq) IRQ_MASK_UICx(irq)
  39. #define UIC_HANDLERS(n) \
  40. static void ppc4xx_uic##n##_enable(unsigned int irq) \
  41. { \
  42. u32 mask = IRQ_MASK_UIC##n(irq); \
  43. if (irq_desc[irq].status & IRQ_LEVEL) \
  44. mtdcr(DCRN_UIC_SR(UIC##n), mask); \
  45. ppc_cached_irq_mask[n] |= mask; \
  46. mtdcr(DCRN_UIC_ER(UIC##n), ppc_cached_irq_mask[n]); \
  47. } \
  48. \
  49. static void ppc4xx_uic##n##_disable(unsigned int irq) \
  50. { \
  51. ppc_cached_irq_mask[n] &= ~IRQ_MASK_UIC##n(irq); \
  52. mtdcr(DCRN_UIC_ER(UIC##n), ppc_cached_irq_mask[n]); \
  53. ACK_UIC##n##_PARENT \
  54. } \
  55. \
  56. static void ppc4xx_uic##n##_ack(unsigned int irq) \
  57. { \
  58. u32 mask = IRQ_MASK_UIC##n(irq); \
  59. ppc_cached_irq_mask[n] &= ~mask; \
  60. mtdcr(DCRN_UIC_ER(UIC##n), ppc_cached_irq_mask[n]); \
  61. mtdcr(DCRN_UIC_SR(UIC##n), mask); \
  62. ACK_UIC##n##_PARENT \
  63. } \
  64. \
  65. static void ppc4xx_uic##n##_end(unsigned int irq) \
  66. { \
  67. unsigned int status = irq_desc[irq].status; \
  68. u32 mask = IRQ_MASK_UIC##n(irq); \
  69. if (status & IRQ_LEVEL) { \
  70. mtdcr(DCRN_UIC_SR(UIC##n), mask); \
  71. ACK_UIC##n##_PARENT \
  72. } \
  73. if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) { \
  74. ppc_cached_irq_mask[n] |= mask; \
  75. mtdcr(DCRN_UIC_ER(UIC##n), ppc_cached_irq_mask[n]); \
  76. } \
  77. }
  78. #define DECLARE_UIC(n) \
  79. { \
  80. .typename = "UIC"#n, \
  81. .enable = ppc4xx_uic##n##_enable, \
  82. .disable = ppc4xx_uic##n##_disable, \
  83. .ack = ppc4xx_uic##n##_ack, \
  84. .end = ppc4xx_uic##n##_end, \
  85. } \
  86. #if NR_UICS == 4
  87. #define ACK_UIC0_PARENT
  88. #define ACK_UIC1_PARENT mtdcr(DCRN_UIC_SR(UIC0), UIC0_UIC1NC);
  89. #define ACK_UIC2_PARENT mtdcr(DCRN_UIC_SR(UIC0), UIC0_UIC2NC);
  90. #define ACK_UIC3_PARENT mtdcr(DCRN_UIC_SR(UIC0), UIC0_UIC3NC);
  91. UIC_HANDLERS(0);
  92. UIC_HANDLERS(1);
  93. UIC_HANDLERS(2);
  94. UIC_HANDLERS(3);
  95. static int ppc4xx_pic_get_irq(struct pt_regs *regs)
  96. {
  97. u32 uic0 = mfdcr(DCRN_UIC_MSR(UIC0));
  98. if (uic0 & UIC0_UIC1NC)
  99. return 64 - ffs(mfdcr(DCRN_UIC_MSR(UIC1)));
  100. else if (uic0 & UIC0_UIC2NC)
  101. return 96 - ffs(mfdcr(DCRN_UIC_MSR(UIC2)));
  102. else if (uic0 & UIC0_UIC3NC)
  103. return 128 - ffs(mfdcr(DCRN_UIC_MSR(UIC3)));
  104. else
  105. return uic0 ? 32 - ffs(uic0) : -1;
  106. }
  107. static void __init ppc4xx_pic_impl_init(void)
  108. {
  109. /* Enable cascade interrupts in UIC0 */
  110. ppc_cached_irq_mask[0] |= UIC0_UIC1NC | UIC0_UIC2NC | UIC0_UIC3NC;
  111. mtdcr(DCRN_UIC_SR(UIC0), UIC0_UIC1NC | UIC0_UIC2NC | UIC0_UIC3NC);
  112. mtdcr(DCRN_UIC_ER(UIC0), ppc_cached_irq_mask[0]);
  113. }
  114. #elif NR_UICS == 3
  115. #define ACK_UIC0_PARENT mtdcr(DCRN_UIC_SR(UICB), UICB_UIC0NC);
  116. #define ACK_UIC1_PARENT mtdcr(DCRN_UIC_SR(UICB), UICB_UIC1NC);
  117. #define ACK_UIC2_PARENT mtdcr(DCRN_UIC_SR(UICB), UICB_UIC2NC);
  118. UIC_HANDLERS(0);
  119. UIC_HANDLERS(1);
  120. UIC_HANDLERS(2);
  121. static int ppc4xx_pic_get_irq(struct pt_regs *regs)
  122. {
  123. u32 uicb = mfdcr(DCRN_UIC_MSR(UICB));
  124. if (uicb & UICB_UIC0NC)
  125. return 32 - ffs(mfdcr(DCRN_UIC_MSR(UIC0)));
  126. else if (uicb & UICB_UIC1NC)
  127. return 64 - ffs(mfdcr(DCRN_UIC_MSR(UIC1)));
  128. else if (uicb & UICB_UIC2NC)
  129. return 96 - ffs(mfdcr(DCRN_UIC_MSR(UIC2)));
  130. else
  131. return -1;
  132. }
  133. static void __init ppc4xx_pic_impl_init(void)
  134. {
  135. #if defined(CONFIG_440GX)
  136. /* Disable 440GP compatibility mode if it was enabled in firmware */
  137. SDR_WRITE(DCRN_SDR_MFR, SDR_READ(DCRN_SDR_MFR) & ~DCRN_SDR_MFR_PCM);
  138. #endif
  139. /* Configure Base UIC */
  140. mtdcr(DCRN_UIC_CR(UICB), 0);
  141. mtdcr(DCRN_UIC_TR(UICB), 0);
  142. mtdcr(DCRN_UIC_PR(UICB), 0xffffffff);
  143. mtdcr(DCRN_UIC_SR(UICB), 0xffffffff);
  144. mtdcr(DCRN_UIC_ER(UICB), UICB_UIC0NC | UICB_UIC1NC | UICB_UIC2NC);
  145. }
  146. #elif NR_UICS == 2
  147. #define ACK_UIC0_PARENT
  148. #define ACK_UIC1_PARENT mtdcr(DCRN_UIC_SR(UIC0), UIC0_UIC1NC);
  149. UIC_HANDLERS(0);
  150. UIC_HANDLERS(1);
  151. static int ppc4xx_pic_get_irq(struct pt_regs *regs)
  152. {
  153. u32 uic0 = mfdcr(DCRN_UIC_MSR(UIC0));
  154. if (uic0 & UIC0_UIC1NC)
  155. return 64 - ffs(mfdcr(DCRN_UIC_MSR(UIC1)));
  156. else
  157. return uic0 ? 32 - ffs(uic0) : -1;
  158. }
  159. static void __init ppc4xx_pic_impl_init(void)
  160. {
  161. /* Enable cascade interrupt in UIC0 */
  162. ppc_cached_irq_mask[0] |= UIC0_UIC1NC;
  163. mtdcr(DCRN_UIC_SR(UIC0), UIC0_UIC1NC);
  164. mtdcr(DCRN_UIC_ER(UIC0), ppc_cached_irq_mask[0]);
  165. }
  166. #elif NR_UICS == 1
  167. #define ACK_UIC0_PARENT
  168. UIC_HANDLERS(0);
  169. static int ppc4xx_pic_get_irq(struct pt_regs *regs)
  170. {
  171. u32 uic0 = mfdcr(DCRN_UIC_MSR(UIC0));
  172. return uic0 ? 32 - ffs(uic0) : -1;
  173. }
  174. static inline void ppc4xx_pic_impl_init(void)
  175. {
  176. }
  177. #endif
  178. static struct ppc4xx_uic_impl {
  179. struct hw_interrupt_type decl;
  180. int base; /* Base DCR number */
  181. } __uic[] = {
  182. { .decl = DECLARE_UIC(0), .base = UIC0 },
  183. #if NR_UICS > 1
  184. { .decl = DECLARE_UIC(1), .base = UIC1 },
  185. #if NR_UICS > 2
  186. { .decl = DECLARE_UIC(2), .base = UIC2 },
  187. #if NR_UICS > 3
  188. { .decl = DECLARE_UIC(3), .base = UIC3 },
  189. #endif
  190. #endif
  191. #endif
  192. };
  193. static inline int is_level_sensitive(int irq)
  194. {
  195. u32 tr = mfdcr(DCRN_UIC_TR(__uic[irq >> 5].base));
  196. return (tr & IRQ_MASK_UICx(irq)) == 0;
  197. }
  198. void __init ppc4xx_pic_init(void)
  199. {
  200. int i;
  201. unsigned char *eirqs = ppc4xx_uic_ext_irq_cfg;
  202. for (i = 0; i < NR_UICS; ++i) {
  203. int base = __uic[i].base;
  204. /* Disable everything by default */
  205. ppc_cached_irq_mask[i] = 0;
  206. mtdcr(DCRN_UIC_ER(base), 0);
  207. /* We don't use critical interrupts */
  208. mtdcr(DCRN_UIC_CR(base), 0);
  209. /* Configure polarity and triggering */
  210. if (ppc4xx_core_uic_cfg) {
  211. struct ppc4xx_uic_settings *p = ppc4xx_core_uic_cfg + i;
  212. u32 mask = p->ext_irq_mask;
  213. u32 pr = mfdcr(DCRN_UIC_PR(base)) & mask;
  214. u32 tr = mfdcr(DCRN_UIC_TR(base)) & mask;
  215. /* "Fixed" interrupts (on-chip devices) */
  216. pr |= p->polarity & ~mask;
  217. tr |= p->triggering & ~mask;
  218. /* Merge external IRQs settings if board port
  219. * provided them
  220. */
  221. if (eirqs && mask) {
  222. pr &= ~mask;
  223. tr &= ~mask;
  224. while (mask) {
  225. /* Extract current external IRQ mask */
  226. u32 eirq_mask = 1 << __ilog2(mask);
  227. if (!(*eirqs & IRQ_SENSE_LEVEL))
  228. tr |= eirq_mask;
  229. if (*eirqs & IRQ_POLARITY_POSITIVE)
  230. pr |= eirq_mask;
  231. mask &= ~eirq_mask;
  232. ++eirqs;
  233. }
  234. }
  235. mtdcr(DCRN_UIC_PR(base), pr);
  236. mtdcr(DCRN_UIC_TR(base), tr);
  237. }
  238. /* ACK any pending interrupts to prevent false
  239. * triggering after first enable
  240. */
  241. mtdcr(DCRN_UIC_SR(base), 0xffffffff);
  242. }
  243. /* Perform optional implementation specific setup
  244. * (e.g. enable cascade interrupts for multi-UIC configurations)
  245. */
  246. ppc4xx_pic_impl_init();
  247. /* Attach low-level handlers */
  248. for (i = 0; i < (NR_UICS << 5); ++i) {
  249. irq_desc[i].handler = &__uic[i >> 5].decl;
  250. if (is_level_sensitive(i))
  251. irq_desc[i].status |= IRQ_LEVEL;
  252. }
  253. ppc_md.get_irq = ppc4xx_pic_get_irq;
  254. }