tx4927_irq.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599
  1. /*
  2. * Common tx4927 irq handler
  3. *
  4. * Author: MontaVista Software, Inc.
  5. * source@mvista.com
  6. *
  7. * under the terms of the GNU General Public License as published by the
  8. * Free Software Foundation; either version 2 of the License, or (at your
  9. * option) any later version.
  10. *
  11. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
  12. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  13. * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  14. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  15. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  16. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  17. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  18. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
  19. * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
  20. * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  21. *
  22. * You should have received a copy of the GNU General Public License along
  23. * with this program; if not, write to the Free Software Foundation, Inc.,
  24. * 675 Mass Ave, Cambridge, MA 02139, USA.
  25. */
  26. #include <linux/errno.h>
  27. #include <linux/init.h>
  28. #include <linux/kernel_stat.h>
  29. #include <linux/module.h>
  30. #include <linux/signal.h>
  31. #include <linux/sched.h>
  32. #include <linux/types.h>
  33. #include <linux/interrupt.h>
  34. #include <linux/ioport.h>
  35. #include <linux/timex.h>
  36. #include <linux/slab.h>
  37. #include <linux/random.h>
  38. #include <linux/irq.h>
  39. #include <linux/bitops.h>
  40. #include <asm/bootinfo.h>
  41. #include <asm/io.h>
  42. #include <asm/irq.h>
  43. #include <asm/mipsregs.h>
  44. #include <asm/system.h>
  45. #include <asm/tx4927/tx4927.h>
  46. /*
  47. * DEBUG
  48. */
  49. #undef TX4927_IRQ_DEBUG
  50. #ifdef TX4927_IRQ_DEBUG
  51. #define TX4927_IRQ_NONE 0x00000000
  52. #define TX4927_IRQ_INFO ( 1 << 0 )
  53. #define TX4927_IRQ_WARN ( 1 << 1 )
  54. #define TX4927_IRQ_EROR ( 1 << 2 )
  55. #define TX4927_IRQ_INIT ( 1 << 5 )
  56. #define TX4927_IRQ_NEST1 ( 1 << 6 )
  57. #define TX4927_IRQ_NEST2 ( 1 << 7 )
  58. #define TX4927_IRQ_NEST3 ( 1 << 8 )
  59. #define TX4927_IRQ_NEST4 ( 1 << 9 )
  60. #define TX4927_IRQ_CP0_INIT ( 1 << 10 )
  61. #define TX4927_IRQ_CP0_STARTUP ( 1 << 11 )
  62. #define TX4927_IRQ_CP0_SHUTDOWN ( 1 << 12 )
  63. #define TX4927_IRQ_CP0_ENABLE ( 1 << 13 )
  64. #define TX4927_IRQ_CP0_DISABLE ( 1 << 14 )
  65. #define TX4927_IRQ_CP0_MASK ( 1 << 15 )
  66. #define TX4927_IRQ_CP0_ENDIRQ ( 1 << 16 )
  67. #define TX4927_IRQ_PIC_INIT ( 1 << 20 )
  68. #define TX4927_IRQ_PIC_STARTUP ( 1 << 21 )
  69. #define TX4927_IRQ_PIC_SHUTDOWN ( 1 << 22 )
  70. #define TX4927_IRQ_PIC_ENABLE ( 1 << 23 )
  71. #define TX4927_IRQ_PIC_DISABLE ( 1 << 24 )
  72. #define TX4927_IRQ_PIC_MASK ( 1 << 25 )
  73. #define TX4927_IRQ_PIC_ENDIRQ ( 1 << 26 )
  74. #define TX4927_IRQ_ALL 0xffffffff
  75. #endif
  76. #ifdef TX4927_IRQ_DEBUG
  77. static const u32 tx4927_irq_debug_flag = (TX4927_IRQ_NONE
  78. | TX4927_IRQ_INFO
  79. | TX4927_IRQ_WARN | TX4927_IRQ_EROR
  80. // | TX4927_IRQ_CP0_INIT
  81. // | TX4927_IRQ_CP0_STARTUP
  82. // | TX4927_IRQ_CP0_SHUTDOWN
  83. // | TX4927_IRQ_CP0_ENABLE
  84. // | TX4927_IRQ_CP0_DISABLE
  85. // | TX4927_IRQ_CP0_MASK
  86. // | TX4927_IRQ_CP0_ENDIRQ
  87. // | TX4927_IRQ_PIC_INIT
  88. // | TX4927_IRQ_PIC_STARTUP
  89. // | TX4927_IRQ_PIC_SHUTDOWN
  90. // | TX4927_IRQ_PIC_ENABLE
  91. // | TX4927_IRQ_PIC_DISABLE
  92. // | TX4927_IRQ_PIC_MASK
  93. // | TX4927_IRQ_PIC_ENDIRQ
  94. // | TX4927_IRQ_INIT
  95. // | TX4927_IRQ_NEST1
  96. // | TX4927_IRQ_NEST2
  97. // | TX4927_IRQ_NEST3
  98. // | TX4927_IRQ_NEST4
  99. );
  100. #endif
  101. #ifdef TX4927_IRQ_DEBUG
  102. #define TX4927_IRQ_DPRINTK(flag,str...) \
  103. if ( (tx4927_irq_debug_flag) & (flag) ) \
  104. { \
  105. char tmp[100]; \
  106. sprintf( tmp, str ); \
  107. printk( "%s(%s:%u)::%s", __FUNCTION__, __FILE__, __LINE__, tmp ); \
  108. }
  109. #else
  110. #define TX4927_IRQ_DPRINTK(flag,str...)
  111. #endif
  112. /*
  113. * Forwad definitions for all pic's
  114. */
  115. static unsigned int tx4927_irq_cp0_startup(unsigned int irq);
  116. static void tx4927_irq_cp0_shutdown(unsigned int irq);
  117. static void tx4927_irq_cp0_enable(unsigned int irq);
  118. static void tx4927_irq_cp0_disable(unsigned int irq);
  119. static void tx4927_irq_cp0_mask_and_ack(unsigned int irq);
  120. static void tx4927_irq_cp0_end(unsigned int irq);
  121. static unsigned int tx4927_irq_pic_startup(unsigned int irq);
  122. static void tx4927_irq_pic_shutdown(unsigned int irq);
  123. static void tx4927_irq_pic_enable(unsigned int irq);
  124. static void tx4927_irq_pic_disable(unsigned int irq);
  125. static void tx4927_irq_pic_mask_and_ack(unsigned int irq);
  126. static void tx4927_irq_pic_end(unsigned int irq);
  127. /*
  128. * Kernel structs for all pic's
  129. */
  130. static DEFINE_SPINLOCK(tx4927_cp0_lock);
  131. static DEFINE_SPINLOCK(tx4927_pic_lock);
  132. #define TX4927_CP0_NAME "TX4927-CP0"
  133. static struct irq_chip tx4927_irq_cp0_type = {
  134. .typename = TX4927_CP0_NAME,
  135. .startup = tx4927_irq_cp0_startup,
  136. .shutdown = tx4927_irq_cp0_shutdown,
  137. .enable = tx4927_irq_cp0_enable,
  138. .disable = tx4927_irq_cp0_disable,
  139. .ack = tx4927_irq_cp0_mask_and_ack,
  140. .end = tx4927_irq_cp0_end,
  141. .set_affinity = NULL
  142. };
  143. #define TX4927_PIC_NAME "TX4927-PIC"
  144. static struct irq_chip tx4927_irq_pic_type = {
  145. .typename = TX4927_PIC_NAME,
  146. .startup = tx4927_irq_pic_startup,
  147. .shutdown = tx4927_irq_pic_shutdown,
  148. .enable = tx4927_irq_pic_enable,
  149. .disable = tx4927_irq_pic_disable,
  150. .ack = tx4927_irq_pic_mask_and_ack,
  151. .end = tx4927_irq_pic_end,
  152. .set_affinity = NULL
  153. };
  154. #define TX4927_PIC_ACTION(s) { no_action, 0, CPU_MASK_NONE, s, NULL, NULL }
  155. static struct irqaction tx4927_irq_pic_action =
  156. TX4927_PIC_ACTION(TX4927_PIC_NAME);
  157. #define CCP0_STATUS 12
  158. #define CCP0_CAUSE 13
  159. /*
  160. * Functions for cp0
  161. */
  162. #define tx4927_irq_cp0_mask(irq) ( 1 << ( irq-TX4927_IRQ_CP0_BEG+8 ) )
  163. static void
  164. tx4927_irq_cp0_modify(unsigned cp0_reg, unsigned clr_bits, unsigned set_bits)
  165. {
  166. unsigned long val = 0;
  167. switch (cp0_reg) {
  168. case CCP0_STATUS:
  169. val = read_c0_status();
  170. break;
  171. case CCP0_CAUSE:
  172. val = read_c0_cause();
  173. break;
  174. }
  175. val &= (~clr_bits);
  176. val |= (set_bits);
  177. switch (cp0_reg) {
  178. case CCP0_STATUS:{
  179. write_c0_status(val);
  180. break;
  181. }
  182. case CCP0_CAUSE:{
  183. write_c0_cause(val);
  184. break;
  185. }
  186. }
  187. return;
  188. }
  189. static void __init tx4927_irq_cp0_init(void)
  190. {
  191. int i;
  192. TX4927_IRQ_DPRINTK(TX4927_IRQ_CP0_INIT, "beg=%d end=%d\n",
  193. TX4927_IRQ_CP0_BEG, TX4927_IRQ_CP0_END);
  194. for (i = TX4927_IRQ_CP0_BEG; i <= TX4927_IRQ_CP0_END; i++) {
  195. irq_desc[i].status = IRQ_DISABLED;
  196. irq_desc[i].action = 0;
  197. irq_desc[i].depth = 1;
  198. irq_desc[i].chip = &tx4927_irq_cp0_type;
  199. }
  200. return;
  201. }
  202. static unsigned int tx4927_irq_cp0_startup(unsigned int irq)
  203. {
  204. TX4927_IRQ_DPRINTK(TX4927_IRQ_CP0_STARTUP, "irq=%d \n", irq);
  205. tx4927_irq_cp0_enable(irq);
  206. return (0);
  207. }
  208. static void tx4927_irq_cp0_shutdown(unsigned int irq)
  209. {
  210. TX4927_IRQ_DPRINTK(TX4927_IRQ_CP0_SHUTDOWN, "irq=%d \n", irq);
  211. tx4927_irq_cp0_disable(irq);
  212. return;
  213. }
  214. static void tx4927_irq_cp0_enable(unsigned int irq)
  215. {
  216. unsigned long flags;
  217. TX4927_IRQ_DPRINTK(TX4927_IRQ_CP0_ENABLE, "irq=%d \n", irq);
  218. spin_lock_irqsave(&tx4927_cp0_lock, flags);
  219. tx4927_irq_cp0_modify(CCP0_STATUS, 0, tx4927_irq_cp0_mask(irq));
  220. spin_unlock_irqrestore(&tx4927_cp0_lock, flags);
  221. return;
  222. }
  223. static void tx4927_irq_cp0_disable(unsigned int irq)
  224. {
  225. unsigned long flags;
  226. TX4927_IRQ_DPRINTK(TX4927_IRQ_CP0_DISABLE, "irq=%d \n", irq);
  227. spin_lock_irqsave(&tx4927_cp0_lock, flags);
  228. tx4927_irq_cp0_modify(CCP0_STATUS, tx4927_irq_cp0_mask(irq), 0);
  229. spin_unlock_irqrestore(&tx4927_cp0_lock, flags);
  230. return;
  231. }
  232. static void tx4927_irq_cp0_mask_and_ack(unsigned int irq)
  233. {
  234. TX4927_IRQ_DPRINTK(TX4927_IRQ_CP0_MASK, "irq=%d \n", irq);
  235. tx4927_irq_cp0_disable(irq);
  236. return;
  237. }
  238. static void tx4927_irq_cp0_end(unsigned int irq)
  239. {
  240. TX4927_IRQ_DPRINTK(TX4927_IRQ_CP0_ENDIRQ, "irq=%d \n", irq);
  241. if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
  242. tx4927_irq_cp0_enable(irq);
  243. }
  244. return;
  245. }
  246. /*
  247. * Functions for pic
  248. */
  249. u32 tx4927_irq_pic_addr(int irq)
  250. {
  251. /* MVMCP -- need to formulize this */
  252. irq -= TX4927_IRQ_PIC_BEG;
  253. switch (irq) {
  254. case 17:
  255. case 16:
  256. case 1:
  257. case 0:
  258. return (0xff1ff610);
  259. case 19:
  260. case 18:
  261. case 3:
  262. case 2:
  263. return (0xff1ff614);
  264. case 21:
  265. case 20:
  266. case 5:
  267. case 4:
  268. return (0xff1ff618);
  269. case 23:
  270. case 22:
  271. case 7:
  272. case 6:
  273. return (0xff1ff61c);
  274. case 25:
  275. case 24:
  276. case 9:
  277. case 8:
  278. return (0xff1ff620);
  279. case 27:
  280. case 26:
  281. case 11:
  282. case 10:
  283. return (0xff1ff624);
  284. case 29:
  285. case 28:
  286. case 13:
  287. case 12:
  288. return (0xff1ff628);
  289. case 31:
  290. case 30:
  291. case 15:
  292. case 14:
  293. return (0xff1ff62c);
  294. }
  295. return (0);
  296. }
  297. u32 tx4927_irq_pic_mask(int irq)
  298. {
  299. /* MVMCP -- need to formulize this */
  300. irq -= TX4927_IRQ_PIC_BEG;
  301. switch (irq) {
  302. case 31:
  303. case 29:
  304. case 27:
  305. case 25:
  306. case 23:
  307. case 21:
  308. case 19:
  309. case 17:{
  310. return (0x07000000);
  311. }
  312. case 30:
  313. case 28:
  314. case 26:
  315. case 24:
  316. case 22:
  317. case 20:
  318. case 18:
  319. case 16:{
  320. return (0x00070000);
  321. }
  322. case 15:
  323. case 13:
  324. case 11:
  325. case 9:
  326. case 7:
  327. case 5:
  328. case 3:
  329. case 1:{
  330. return (0x00000700);
  331. }
  332. case 14:
  333. case 12:
  334. case 10:
  335. case 8:
  336. case 6:
  337. case 4:
  338. case 2:
  339. case 0:{
  340. return (0x00000007);
  341. }
  342. }
  343. return (0x00000000);
  344. }
  345. static void tx4927_irq_pic_modify(unsigned pic_reg, unsigned clr_bits,
  346. unsigned set_bits)
  347. {
  348. unsigned long val = 0;
  349. val = TX4927_RD(pic_reg);
  350. val &= (~clr_bits);
  351. val |= (set_bits);
  352. TX4927_WR(pic_reg, val);
  353. return;
  354. }
  355. static void __init tx4927_irq_pic_init(void)
  356. {
  357. unsigned long flags;
  358. int i;
  359. TX4927_IRQ_DPRINTK(TX4927_IRQ_PIC_INIT, "beg=%d end=%d\n",
  360. TX4927_IRQ_PIC_BEG, TX4927_IRQ_PIC_END);
  361. for (i = TX4927_IRQ_PIC_BEG; i <= TX4927_IRQ_PIC_END; i++) {
  362. irq_desc[i].status = IRQ_DISABLED;
  363. irq_desc[i].action = 0;
  364. irq_desc[i].depth = 2;
  365. irq_desc[i].chip = &tx4927_irq_pic_type;
  366. }
  367. setup_irq(TX4927_IRQ_NEST_PIC_ON_CP0, &tx4927_irq_pic_action);
  368. spin_lock_irqsave(&tx4927_pic_lock, flags);
  369. TX4927_WR(0xff1ff640, 0x6); /* irq level mask -- only accept hightest */
  370. TX4927_WR(0xff1ff600, TX4927_RD(0xff1ff600) | 0x1); /* irq enable */
  371. spin_unlock_irqrestore(&tx4927_pic_lock, flags);
  372. return;
  373. }
  374. static unsigned int tx4927_irq_pic_startup(unsigned int irq)
  375. {
  376. TX4927_IRQ_DPRINTK(TX4927_IRQ_PIC_STARTUP, "irq=%d\n", irq);
  377. tx4927_irq_pic_enable(irq);
  378. return (0);
  379. }
  380. static void tx4927_irq_pic_shutdown(unsigned int irq)
  381. {
  382. TX4927_IRQ_DPRINTK(TX4927_IRQ_PIC_SHUTDOWN, "irq=%d\n", irq);
  383. tx4927_irq_pic_disable(irq);
  384. return;
  385. }
  386. static void tx4927_irq_pic_enable(unsigned int irq)
  387. {
  388. unsigned long flags;
  389. TX4927_IRQ_DPRINTK(TX4927_IRQ_PIC_ENABLE, "irq=%d\n", irq);
  390. spin_lock_irqsave(&tx4927_pic_lock, flags);
  391. tx4927_irq_pic_modify(tx4927_irq_pic_addr(irq), 0,
  392. tx4927_irq_pic_mask(irq));
  393. spin_unlock_irqrestore(&tx4927_pic_lock, flags);
  394. return;
  395. }
  396. static void tx4927_irq_pic_disable(unsigned int irq)
  397. {
  398. unsigned long flags;
  399. TX4927_IRQ_DPRINTK(TX4927_IRQ_PIC_DISABLE, "irq=%d\n", irq);
  400. spin_lock_irqsave(&tx4927_pic_lock, flags);
  401. tx4927_irq_pic_modify(tx4927_irq_pic_addr(irq),
  402. tx4927_irq_pic_mask(irq), 0);
  403. spin_unlock_irqrestore(&tx4927_pic_lock, flags);
  404. return;
  405. }
  406. static void tx4927_irq_pic_mask_and_ack(unsigned int irq)
  407. {
  408. TX4927_IRQ_DPRINTK(TX4927_IRQ_PIC_MASK, "irq=%d\n", irq);
  409. tx4927_irq_pic_disable(irq);
  410. return;
  411. }
  412. static void tx4927_irq_pic_end(unsigned int irq)
  413. {
  414. TX4927_IRQ_DPRINTK(TX4927_IRQ_PIC_ENDIRQ, "irq=%d\n", irq);
  415. if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
  416. tx4927_irq_pic_enable(irq);
  417. }
  418. return;
  419. }
  420. /*
  421. * Main init functions
  422. */
  423. void __init tx4927_irq_init(void)
  424. {
  425. TX4927_IRQ_DPRINTK(TX4927_IRQ_INIT, "-\n");
  426. TX4927_IRQ_DPRINTK(TX4927_IRQ_INIT, "=Calling tx4927_irq_cp0_init()\n");
  427. tx4927_irq_cp0_init();
  428. TX4927_IRQ_DPRINTK(TX4927_IRQ_INIT, "=Calling tx4927_irq_pic_init()\n");
  429. tx4927_irq_pic_init();
  430. TX4927_IRQ_DPRINTK(TX4927_IRQ_INIT, "+\n");
  431. return;
  432. }
  433. static int tx4927_irq_nested(void)
  434. {
  435. int sw_irq = 0;
  436. u32 level2;
  437. TX4927_IRQ_DPRINTK(TX4927_IRQ_NEST1, "-\n");
  438. level2 = TX4927_RD(0xff1ff6a0);
  439. TX4927_IRQ_DPRINTK(TX4927_IRQ_NEST2, "=level2a=0x%x\n", level2);
  440. if ((level2 & 0x10000) == 0) {
  441. level2 &= 0x1f;
  442. TX4927_IRQ_DPRINTK(TX4927_IRQ_NEST3, "=level2b=0x%x\n", level2);
  443. sw_irq = TX4927_IRQ_PIC_BEG + level2;
  444. TX4927_IRQ_DPRINTK(TX4927_IRQ_NEST3, "=sw_irq=%d\n", sw_irq);
  445. if (sw_irq == 27) {
  446. TX4927_IRQ_DPRINTK(TX4927_IRQ_NEST4, "=irq-%d\n",
  447. sw_irq);
  448. #ifdef CONFIG_TOSHIBA_RBTX4927
  449. {
  450. sw_irq = toshiba_rbtx4927_irq_nested(sw_irq);
  451. }
  452. #endif
  453. TX4927_IRQ_DPRINTK(TX4927_IRQ_NEST4, "=irq+%d\n",
  454. sw_irq);
  455. }
  456. }
  457. TX4927_IRQ_DPRINTK(TX4927_IRQ_NEST2, "=sw_irq=%d\n", sw_irq);
  458. TX4927_IRQ_DPRINTK(TX4927_IRQ_NEST1, "+\n");
  459. return (sw_irq);
  460. }
  461. asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
  462. {
  463. unsigned int pending = read_c0_status() & read_c0_cause();
  464. if (pending & STATUSF_IP7) /* cpu timer */
  465. do_IRQ(TX4927_IRQ_CPU_TIMER, regs);
  466. else if (pending & STATUSF_IP2) { /* tx4927 pic */
  467. unsigned int irq = tx4927_irq_nested();
  468. if (unlikely(irq == 0)) {
  469. spurious_interrupt(regs);
  470. return;
  471. }
  472. do_IRQ(irq, regs);
  473. } else if (pending & STATUSF_IP0) /* user line 0 */
  474. do_IRQ(TX4927_IRQ_USER0, regs);
  475. else if (pending & STATUSF_IP1) /* user line 1 */
  476. do_IRQ(TX4927_IRQ_USER1, regs);
  477. else
  478. spurious_interrupt(regs);
  479. }