icu.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:10k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * FILE NAME
  3.  * arch/mips/vr41xx/vr4122/common/icu.c
  4.  *
  5.  * BRIEF MODULE DESCRIPTION
  6.  * Interrupt Control Unit routines for the NEC VR4122 and VR4131.
  7.  *
  8.  * Author: Yoichi Yuasa
  9.  *         yyuasa@mvista.com or source@mvista.com
  10.  *
  11.  * Copyright 2001,2002 MontaVista Software Inc.
  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.  *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
  19.  *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  20.  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  21.  *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  22.  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  23.  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  24.  *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  25.  *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
  26.  *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
  27.  *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28.  *
  29.  *  You should have received a copy of the GNU General Public License along
  30.  *  with this program; if not, write to the Free Software Foundation, Inc.,
  31.  *  675 Mass Ave, Cambridge, MA 02139, USA.
  32.  */
  33. /*
  34.  * Changes:
  35.  *  MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
  36.  *  - Added support for NEC VR4111 and VR4121.
  37.  *
  38.  *  Paul Mundt <lethal@chaoticdreams.org>
  39.  *  - kgdb support.
  40.  *
  41.  *  MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
  42.  *  - New creation, NEC VR4122 and VR4131 are supported.
  43.  */
  44. #include <linux/errno.h>
  45. #include <linux/init.h>
  46. #include <linux/interrupt.h>
  47. #include <linux/irq.h>
  48. #include <linux/types.h>
  49. #include <asm/addrspace.h>
  50. #include <asm/cpu.h>
  51. #include <asm/gdb-stub.h>
  52. #include <asm/io.h>
  53. #include <asm/mipsregs.h>
  54. #include <asm/vr41xx/vr41xx.h>
  55. #define MIPS_CPU_IRQ_BASE 0
  56. #define SYSINT1_IRQ_BASE 8
  57. #define SYSINT1_IRQ_LAST 23
  58. #define SYSINT2_IRQ_BASE 24
  59. #define SYSINT2_IRQ_LAST 39
  60. #define GIUINT_IRQ_BASE GIU_IRQ(0)
  61. #define GIUINT_IRQ_LAST GIU_IRQ(31)
  62. #define ICU_CASCADE_IRQ (MIPS_CPU_IRQ_BASE + 2)
  63. extern asmlinkage void vr41xx_handle_interrupt(void);
  64. extern void __init init_generic_irq(void);
  65. extern void mips_cpu_irq_init(u32 irq_base);
  66. extern unsigned int do_IRQ(int irq, struct pt_regs *regs);
  67. extern void vr41xx_giuint_init(void);
  68. extern unsigned int giuint_do_IRQ(int pin, struct pt_regs *regs);
  69. static u32 vr41xx_icu1_base = 0;
  70. static u32 vr41xx_icu2_base = 0;
  71. #define VR4111_SYSINT1REG KSEG1ADDR(0x0b000080)
  72. #define VR4111_SYSINT2REG KSEG1ADDR(0x0b000200)
  73. #define VR4122_SYSINT1REG KSEG1ADDR(0x0f000080)
  74. #define VR4122_SYSINT2REG KSEG1ADDR(0x0f0000a0)
  75. #define SYSINT1REG 0x00
  76. #define GIUINTLREG 0x08
  77. #define MSYSINT1REG 0x0c
  78. #define MGIUINTLREG 0x14
  79. #define NMIREG 0x18
  80. #define SOFTREG 0x1a
  81. #define SYSINT2REG 0x00
  82. #define GIUINTHREG 0x02
  83. #define MSYSINT2REG 0x06
  84. #define MGIUINTHREG 0x08
  85. #define read_icu1(offset) readw(vr41xx_icu1_base + (offset))
  86. #define write_icu1(val, offset) writew((val), vr41xx_icu1_base + (offset))
  87. #define read_icu2(offset) readw(vr41xx_icu2_base + (offset))
  88. #define write_icu2(val, offset) writew((val), vr41xx_icu2_base + (offset))
  89. static inline u16 set_icu1(u16 offset, u16 set)
  90. {
  91. u16 res;
  92. res = read_icu1(offset);
  93. res |= set;
  94. write_icu1(res, offset);
  95. return res;
  96. }
  97. static inline u16 clear_icu1(u16 offset, u16 clear)
  98. {
  99. u16 res;
  100. res = read_icu1(offset);
  101. res &= ~clear;
  102. write_icu1(res, offset);
  103. return res;
  104. }
  105. static inline u16 set_icu2(u16 offset, u16 set)
  106. {
  107. u16 res;
  108. res = read_icu2(offset);
  109. res |= set;
  110. write_icu2(res, offset);
  111. return res;
  112. }
  113. static inline u16 clear_icu2(u16 offset, u16 clear)
  114. {
  115. u16 res;
  116. res = read_icu2(offset);
  117. res &= ~clear;
  118. write_icu2(res, offset);
  119. return res;
  120. }
  121. /*=======================================================================*/
  122. static void enable_sysint1_irq(unsigned int irq)
  123. {
  124. set_icu1(MSYSINT1REG, (u16)1 << (irq - SYSINT1_IRQ_BASE));
  125. }
  126. static void disable_sysint1_irq(unsigned int irq)
  127. {
  128. clear_icu1(MSYSINT1REG, (u16)1 << (irq - SYSINT1_IRQ_BASE));
  129. }
  130. static unsigned int startup_sysint1_irq(unsigned int irq)
  131. {
  132. set_icu1(MSYSINT1REG, (u16)1 << (irq - SYSINT1_IRQ_BASE));
  133. return 0; /* never anything pending */
  134. }
  135. #define shutdown_sysint1_irq disable_sysint1_irq
  136. #define ack_sysint1_irq disable_sysint1_irq
  137. static void end_sysint1_irq(unsigned int irq)
  138. {
  139. if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
  140. set_icu1(MSYSINT1REG, (u16)1 << (irq - SYSINT1_IRQ_BASE));
  141. }
  142. static struct hw_interrupt_type sysint1_irq_type = {
  143. "SYSINT1",
  144. startup_sysint1_irq,
  145. shutdown_sysint1_irq,
  146. enable_sysint1_irq,
  147. disable_sysint1_irq,
  148. ack_sysint1_irq,
  149. end_sysint1_irq,
  150. NULL
  151. };
  152. /*=======================================================================*/
  153. static void enable_sysint2_irq(unsigned int irq)
  154. {
  155. set_icu2(MSYSINT2REG, (u16)1 << (irq - SYSINT2_IRQ_BASE));
  156. }
  157. static void disable_sysint2_irq(unsigned int irq)
  158. {
  159. clear_icu2(MSYSINT2REG, (u16)1 << (irq - SYSINT2_IRQ_BASE));
  160. }
  161. static unsigned int startup_sysint2_irq(unsigned int irq)
  162. {
  163. set_icu2(MSYSINT2REG, (u16)1 << (irq - SYSINT2_IRQ_BASE));
  164. return 0; /* never anything pending */
  165. }
  166. #define shutdown_sysint2_irq disable_sysint2_irq
  167. #define ack_sysint2_irq disable_sysint2_irq
  168. static void end_sysint2_irq(unsigned int irq)
  169. {
  170. if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
  171. set_icu2(MSYSINT2REG, (u16)1 << (irq - SYSINT2_IRQ_BASE));
  172. }
  173. static struct hw_interrupt_type sysint2_irq_type = {
  174. "SYSINT2",
  175. startup_sysint2_irq,
  176. shutdown_sysint2_irq,
  177. enable_sysint2_irq,
  178. disable_sysint2_irq,
  179. ack_sysint2_irq,
  180. end_sysint2_irq,
  181. NULL
  182. };
  183. /*=======================================================================*/
  184. extern void vr41xx_enable_giuint(u8 pin);
  185. extern void vr41xx_disable_giuint(u8 pin);
  186. extern void vr41xx_clear_giuint(u8 pin);
  187. static void enable_giuint_irq(unsigned int irq)
  188. {
  189. u8 pin;
  190. pin = irq - GIUINT_IRQ_BASE;
  191. if (pin < 16)
  192. set_icu1(MGIUINTLREG, (u16)1 << pin);
  193. else
  194. set_icu2(MGIUINTHREG, (u16)1 << (pin - 16));
  195. vr41xx_enable_giuint(pin);
  196. }
  197. static void disable_giuint_irq(unsigned int irq)
  198. {
  199. u8 pin;
  200. pin = irq - GIUINT_IRQ_BASE;
  201. vr41xx_disable_giuint(pin);
  202. if (pin < 16)
  203. clear_icu1(MGIUINTLREG, (u16)1 << pin);
  204. else
  205. clear_icu2(MGIUINTHREG, (u16)1 << (pin - 16));
  206. }
  207. static unsigned int startup_giuint_irq(unsigned int irq)
  208. {
  209. vr41xx_clear_giuint(irq - GIUINT_IRQ_BASE);
  210. enable_giuint_irq(irq);
  211. return 0; /* never anything pending */
  212. }
  213. #define shutdown_giuint_irq disable_giuint_irq
  214. static void ack_giuint_irq(unsigned int irq)
  215. {
  216. disable_giuint_irq(irq);
  217. vr41xx_clear_giuint(irq - GIUINT_IRQ_BASE);
  218. }
  219. static void end_giuint_irq(unsigned int irq)
  220. {
  221. if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
  222. enable_giuint_irq(irq);
  223. }
  224. static struct hw_interrupt_type giuint_irq_type = {
  225. "GIUINT",
  226. startup_giuint_irq,
  227. shutdown_giuint_irq,
  228. enable_giuint_irq,
  229. disable_giuint_irq,
  230. ack_giuint_irq,
  231. end_giuint_irq,
  232. NULL
  233. };
  234. /*=======================================================================*/
  235. static struct irqaction icu_cascade = {no_action, 0, 0, "cascade", NULL, NULL};
  236. static void __init vr41xx_icu_init(void)
  237. {
  238. int i;
  239. switch (mips_cpu.cputype) {
  240. case CPU_VR4111:
  241. case CPU_VR4121:
  242. vr41xx_icu1_base = VR4111_SYSINT1REG;
  243. vr41xx_icu2_base = VR4111_SYSINT2REG;
  244. break;
  245. case CPU_VR4122:
  246. case CPU_VR4131:
  247. vr41xx_icu1_base = VR4122_SYSINT1REG;
  248. vr41xx_icu2_base = VR4122_SYSINT2REG;
  249. break;
  250. default:
  251. panic("Unexpected CPU of NEC VR4100 series");
  252. break;
  253. }
  254. write_icu1(0, MSYSINT1REG);
  255. write_icu1(0, MGIUINTLREG);
  256. write_icu2(0, MSYSINT2REG);
  257. write_icu2(0, MGIUINTHREG);
  258. for (i = SYSINT1_IRQ_BASE; i <= GIUINT_IRQ_LAST; i++) {
  259. if (i >= SYSINT1_IRQ_BASE && i <= SYSINT1_IRQ_LAST)
  260. irq_desc[i].handler = &sysint1_irq_type;
  261. else if (i >= SYSINT2_IRQ_BASE && i <= SYSINT2_IRQ_LAST)
  262. irq_desc[i].handler = &sysint2_irq_type;
  263. else if (i >= GIUINT_IRQ_BASE && i <= GIUINT_IRQ_LAST)
  264. irq_desc[i].handler = &giuint_irq_type;
  265. }
  266. setup_irq(ICU_CASCADE_IRQ, &icu_cascade);
  267. }
  268. void __init init_IRQ(void)
  269. {
  270. memset(irq_desc, 0, sizeof(irq_desc));
  271. init_generic_irq();
  272. mips_cpu_irq_init(MIPS_CPU_IRQ_BASE);
  273. vr41xx_icu_init();
  274. vr41xx_giuint_init();
  275. set_except_vector(0, vr41xx_handle_interrupt);
  276. #ifdef CONFIG_REMOTE_DEBUG
  277. printk("Setting debug traps - please connect the remote debugger.n");
  278. set_debug_traps();
  279. breakpoint();
  280. #endif
  281. }
  282. /*=======================================================================*/
  283. static inline void giuint_irqdispatch(u16 pendl, u16 pendh, struct pt_regs *regs)
  284. {
  285. int i;
  286. if (pendl) {
  287. for (i = 0; i < 16; i++) {
  288. if (pendl & (0x0001 << i)) {
  289. giuint_do_IRQ(i, regs);
  290. return;
  291. }
  292. }
  293. }
  294. else if (pendh) {
  295. for (i = 0; i < 16; i++) {
  296. if (pendh & (0x0001 << i)) {
  297. giuint_do_IRQ(i + 16, regs);
  298. return;
  299. }
  300. }
  301. }
  302. }
  303. asmlinkage void icu_irqdispatch(struct pt_regs *regs)
  304. {
  305. u16 pend1, pend2, pendl, pendh;
  306. u16 mask1, mask2, maskl, maskh;
  307. int i;
  308. pend1 = read_icu1(SYSINT1REG);
  309. mask1 = read_icu1(MSYSINT1REG);
  310. pend2 = read_icu2(SYSINT2REG);
  311. mask2 = read_icu2(MSYSINT2REG);
  312. pendl = read_icu1(GIUINTLREG);
  313. maskl = read_icu1(MGIUINTLREG);
  314. pendh = read_icu2(GIUINTHREG);
  315. maskh = read_icu2(MGIUINTHREG);
  316. pend1 &= mask1;
  317. pend2 &= mask2;
  318. pendl &= maskl;
  319. pendh &= maskh;
  320. if (pend1) {
  321. if ((pend1 & 0x01ff) == 0x0100) {
  322. giuint_irqdispatch(pendl, pendh, regs);
  323. }
  324. else {
  325. for (i = 0; i < 16; i++) {
  326. if (pend1 & (0x0001 << i)) {
  327. do_IRQ(SYSINT1_IRQ_BASE + i, regs);
  328. break;
  329. }
  330. }
  331. }
  332. return;
  333. }
  334. else if (pend2) {
  335. for (i = 0; i < 16; i++) {
  336. if (pend2 & (0x0001 << i)) {
  337. do_IRQ(SYSINT2_IRQ_BASE + i, regs);
  338. break;
  339. }
  340. }
  341. }
  342. }