2
0

omap_intc.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598
  1. /*
  2. * TI OMAP interrupt controller emulation.
  3. *
  4. * Copyright (C) 2006-2008 Andrzej Zaborowski <balrog@zabor.org>
  5. * Copyright (C) 2007-2008 Nokia Corporation
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License as
  9. * published by the Free Software Foundation; either version 2 or
  10. * (at your option) version 3 of the License.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License along
  18. * with this program; if not, see <http://www.gnu.org/licenses/>.
  19. */
  20. #include "hw.h"
  21. #include "omap.h"
  22. /* Interrupt Handlers */
  23. struct omap_intr_handler_bank_s {
  24. uint32_t irqs;
  25. uint32_t inputs;
  26. uint32_t mask;
  27. uint32_t fiq;
  28. uint32_t sens_edge;
  29. uint32_t swi;
  30. unsigned char priority[32];
  31. };
  32. struct omap_intr_handler_s {
  33. qemu_irq *pins;
  34. qemu_irq parent_intr[2];
  35. unsigned char nbanks;
  36. int level_only;
  37. /* state */
  38. uint32_t new_agr[2];
  39. int sir_intr[2];
  40. int autoidle;
  41. uint32_t mask;
  42. struct omap_intr_handler_bank_s bank[];
  43. };
  44. inline qemu_irq omap_inth_get_pin(struct omap_intr_handler_s *s, int n)
  45. {
  46. return s->pins[n];
  47. }
  48. static void omap_inth_sir_update(struct omap_intr_handler_s *s, int is_fiq)
  49. {
  50. int i, j, sir_intr, p_intr, p, f;
  51. uint32_t level;
  52. sir_intr = 0;
  53. p_intr = 255;
  54. /* Find the interrupt line with the highest dynamic priority.
  55. * Note: 0 denotes the hightest priority.
  56. * If all interrupts have the same priority, the default order is IRQ_N,
  57. * IRQ_N-1,...,IRQ_0. */
  58. for (j = 0; j < s->nbanks; ++j) {
  59. level = s->bank[j].irqs & ~s->bank[j].mask &
  60. (is_fiq ? s->bank[j].fiq : ~s->bank[j].fiq);
  61. for (f = ffs(level), i = f - 1, level >>= f - 1; f; i += f,
  62. level >>= f) {
  63. p = s->bank[j].priority[i];
  64. if (p <= p_intr) {
  65. p_intr = p;
  66. sir_intr = 32 * j + i;
  67. }
  68. f = ffs(level >> 1);
  69. }
  70. }
  71. s->sir_intr[is_fiq] = sir_intr;
  72. }
  73. static inline void omap_inth_update(struct omap_intr_handler_s *s, int is_fiq)
  74. {
  75. int i;
  76. uint32_t has_intr = 0;
  77. for (i = 0; i < s->nbanks; ++i)
  78. has_intr |= s->bank[i].irqs & ~s->bank[i].mask &
  79. (is_fiq ? s->bank[i].fiq : ~s->bank[i].fiq);
  80. if (s->new_agr[is_fiq] & has_intr & s->mask) {
  81. s->new_agr[is_fiq] = 0;
  82. omap_inth_sir_update(s, is_fiq);
  83. qemu_set_irq(s->parent_intr[is_fiq], 1);
  84. }
  85. }
  86. #define INT_FALLING_EDGE 0
  87. #define INT_LOW_LEVEL 1
  88. static void omap_set_intr(void *opaque, int irq, int req)
  89. {
  90. struct omap_intr_handler_s *ih = (struct omap_intr_handler_s *) opaque;
  91. uint32_t rise;
  92. struct omap_intr_handler_bank_s *bank = &ih->bank[irq >> 5];
  93. int n = irq & 31;
  94. if (req) {
  95. rise = ~bank->irqs & (1 << n);
  96. if (~bank->sens_edge & (1 << n))
  97. rise &= ~bank->inputs;
  98. bank->inputs |= (1 << n);
  99. if (rise) {
  100. bank->irqs |= rise;
  101. omap_inth_update(ih, 0);
  102. omap_inth_update(ih, 1);
  103. }
  104. } else {
  105. rise = bank->sens_edge & bank->irqs & (1 << n);
  106. bank->irqs &= ~rise;
  107. bank->inputs &= ~(1 << n);
  108. }
  109. }
  110. /* Simplified version with no edge detection */
  111. static void omap_set_intr_noedge(void *opaque, int irq, int req)
  112. {
  113. struct omap_intr_handler_s *ih = (struct omap_intr_handler_s *) opaque;
  114. uint32_t rise;
  115. struct omap_intr_handler_bank_s *bank = &ih->bank[irq >> 5];
  116. int n = irq & 31;
  117. if (req) {
  118. rise = ~bank->inputs & (1 << n);
  119. if (rise) {
  120. bank->irqs |= bank->inputs |= rise;
  121. omap_inth_update(ih, 0);
  122. omap_inth_update(ih, 1);
  123. }
  124. } else
  125. bank->irqs = (bank->inputs &= ~(1 << n)) | bank->swi;
  126. }
  127. static uint32_t omap_inth_read(void *opaque, target_phys_addr_t addr)
  128. {
  129. struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
  130. int i, offset = addr;
  131. int bank_no = offset >> 8;
  132. int line_no;
  133. struct omap_intr_handler_bank_s *bank = &s->bank[bank_no];
  134. offset &= 0xff;
  135. switch (offset) {
  136. case 0x00: /* ITR */
  137. return bank->irqs;
  138. case 0x04: /* MIR */
  139. return bank->mask;
  140. case 0x10: /* SIR_IRQ_CODE */
  141. case 0x14: /* SIR_FIQ_CODE */
  142. if (bank_no != 0)
  143. break;
  144. line_no = s->sir_intr[(offset - 0x10) >> 2];
  145. bank = &s->bank[line_no >> 5];
  146. i = line_no & 31;
  147. if (((bank->sens_edge >> i) & 1) == INT_FALLING_EDGE)
  148. bank->irqs &= ~(1 << i);
  149. return line_no;
  150. case 0x18: /* CONTROL_REG */
  151. if (bank_no != 0)
  152. break;
  153. return 0;
  154. case 0x1c: /* ILR0 */
  155. case 0x20: /* ILR1 */
  156. case 0x24: /* ILR2 */
  157. case 0x28: /* ILR3 */
  158. case 0x2c: /* ILR4 */
  159. case 0x30: /* ILR5 */
  160. case 0x34: /* ILR6 */
  161. case 0x38: /* ILR7 */
  162. case 0x3c: /* ILR8 */
  163. case 0x40: /* ILR9 */
  164. case 0x44: /* ILR10 */
  165. case 0x48: /* ILR11 */
  166. case 0x4c: /* ILR12 */
  167. case 0x50: /* ILR13 */
  168. case 0x54: /* ILR14 */
  169. case 0x58: /* ILR15 */
  170. case 0x5c: /* ILR16 */
  171. case 0x60: /* ILR17 */
  172. case 0x64: /* ILR18 */
  173. case 0x68: /* ILR19 */
  174. case 0x6c: /* ILR20 */
  175. case 0x70: /* ILR21 */
  176. case 0x74: /* ILR22 */
  177. case 0x78: /* ILR23 */
  178. case 0x7c: /* ILR24 */
  179. case 0x80: /* ILR25 */
  180. case 0x84: /* ILR26 */
  181. case 0x88: /* ILR27 */
  182. case 0x8c: /* ILR28 */
  183. case 0x90: /* ILR29 */
  184. case 0x94: /* ILR30 */
  185. case 0x98: /* ILR31 */
  186. i = (offset - 0x1c) >> 2;
  187. return (bank->priority[i] << 2) |
  188. (((bank->sens_edge >> i) & 1) << 1) |
  189. ((bank->fiq >> i) & 1);
  190. case 0x9c: /* ISR */
  191. return 0x00000000;
  192. }
  193. OMAP_BAD_REG(addr);
  194. return 0;
  195. }
  196. static void omap_inth_write(void *opaque, target_phys_addr_t addr,
  197. uint32_t value)
  198. {
  199. struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
  200. int i, offset = addr;
  201. int bank_no = offset >> 8;
  202. struct omap_intr_handler_bank_s *bank = &s->bank[bank_no];
  203. offset &= 0xff;
  204. switch (offset) {
  205. case 0x00: /* ITR */
  206. /* Important: ignore the clearing if the IRQ is level-triggered and
  207. the input bit is 1 */
  208. bank->irqs &= value | (bank->inputs & bank->sens_edge);
  209. return;
  210. case 0x04: /* MIR */
  211. bank->mask = value;
  212. omap_inth_update(s, 0);
  213. omap_inth_update(s, 1);
  214. return;
  215. case 0x10: /* SIR_IRQ_CODE */
  216. case 0x14: /* SIR_FIQ_CODE */
  217. OMAP_RO_REG(addr);
  218. break;
  219. case 0x18: /* CONTROL_REG */
  220. if (bank_no != 0)
  221. break;
  222. if (value & 2) {
  223. qemu_set_irq(s->parent_intr[1], 0);
  224. s->new_agr[1] = ~0;
  225. omap_inth_update(s, 1);
  226. }
  227. if (value & 1) {
  228. qemu_set_irq(s->parent_intr[0], 0);
  229. s->new_agr[0] = ~0;
  230. omap_inth_update(s, 0);
  231. }
  232. return;
  233. case 0x1c: /* ILR0 */
  234. case 0x20: /* ILR1 */
  235. case 0x24: /* ILR2 */
  236. case 0x28: /* ILR3 */
  237. case 0x2c: /* ILR4 */
  238. case 0x30: /* ILR5 */
  239. case 0x34: /* ILR6 */
  240. case 0x38: /* ILR7 */
  241. case 0x3c: /* ILR8 */
  242. case 0x40: /* ILR9 */
  243. case 0x44: /* ILR10 */
  244. case 0x48: /* ILR11 */
  245. case 0x4c: /* ILR12 */
  246. case 0x50: /* ILR13 */
  247. case 0x54: /* ILR14 */
  248. case 0x58: /* ILR15 */
  249. case 0x5c: /* ILR16 */
  250. case 0x60: /* ILR17 */
  251. case 0x64: /* ILR18 */
  252. case 0x68: /* ILR19 */
  253. case 0x6c: /* ILR20 */
  254. case 0x70: /* ILR21 */
  255. case 0x74: /* ILR22 */
  256. case 0x78: /* ILR23 */
  257. case 0x7c: /* ILR24 */
  258. case 0x80: /* ILR25 */
  259. case 0x84: /* ILR26 */
  260. case 0x88: /* ILR27 */
  261. case 0x8c: /* ILR28 */
  262. case 0x90: /* ILR29 */
  263. case 0x94: /* ILR30 */
  264. case 0x98: /* ILR31 */
  265. i = (offset - 0x1c) >> 2;
  266. bank->priority[i] = (value >> 2) & 0x1f;
  267. bank->sens_edge &= ~(1 << i);
  268. bank->sens_edge |= ((value >> 1) & 1) << i;
  269. bank->fiq &= ~(1 << i);
  270. bank->fiq |= (value & 1) << i;
  271. return;
  272. case 0x9c: /* ISR */
  273. for (i = 0; i < 32; i ++)
  274. if (value & (1 << i)) {
  275. omap_set_intr(s, 32 * bank_no + i, 1);
  276. return;
  277. }
  278. return;
  279. }
  280. OMAP_BAD_REG(addr);
  281. }
  282. static CPUReadMemoryFunc * const omap_inth_readfn[] = {
  283. omap_badwidth_read32,
  284. omap_badwidth_read32,
  285. omap_inth_read,
  286. };
  287. static CPUWriteMemoryFunc * const omap_inth_writefn[] = {
  288. omap_inth_write,
  289. omap_inth_write,
  290. omap_inth_write,
  291. };
  292. void omap_inth_reset(struct omap_intr_handler_s *s)
  293. {
  294. int i;
  295. for (i = 0; i < s->nbanks; ++i){
  296. s->bank[i].irqs = 0x00000000;
  297. s->bank[i].mask = 0xffffffff;
  298. s->bank[i].sens_edge = 0x00000000;
  299. s->bank[i].fiq = 0x00000000;
  300. s->bank[i].inputs = 0x00000000;
  301. s->bank[i].swi = 0x00000000;
  302. memset(s->bank[i].priority, 0, sizeof(s->bank[i].priority));
  303. if (s->level_only)
  304. s->bank[i].sens_edge = 0xffffffff;
  305. }
  306. s->new_agr[0] = ~0;
  307. s->new_agr[1] = ~0;
  308. s->sir_intr[0] = 0;
  309. s->sir_intr[1] = 0;
  310. s->autoidle = 0;
  311. s->mask = ~0;
  312. qemu_set_irq(s->parent_intr[0], 0);
  313. qemu_set_irq(s->parent_intr[1], 0);
  314. }
  315. struct omap_intr_handler_s *omap_inth_init(target_phys_addr_t base,
  316. unsigned long size, unsigned char nbanks, qemu_irq **pins,
  317. qemu_irq parent_irq, qemu_irq parent_fiq, omap_clk clk)
  318. {
  319. int iomemtype;
  320. struct omap_intr_handler_s *s = (struct omap_intr_handler_s *)
  321. qemu_mallocz(sizeof(struct omap_intr_handler_s) +
  322. sizeof(struct omap_intr_handler_bank_s) * nbanks);
  323. s->parent_intr[0] = parent_irq;
  324. s->parent_intr[1] = parent_fiq;
  325. s->nbanks = nbanks;
  326. s->pins = qemu_allocate_irqs(omap_set_intr, s, nbanks * 32);
  327. if (pins)
  328. *pins = s->pins;
  329. omap_inth_reset(s);
  330. iomemtype = cpu_register_io_memory(omap_inth_readfn,
  331. omap_inth_writefn, s, DEVICE_NATIVE_ENDIAN);
  332. cpu_register_physical_memory(base, size, iomemtype);
  333. return s;
  334. }
  335. static uint32_t omap2_inth_read(void *opaque, target_phys_addr_t addr)
  336. {
  337. struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
  338. int offset = addr;
  339. int bank_no, line_no;
  340. struct omap_intr_handler_bank_s *bank = NULL;
  341. if ((offset & 0xf80) == 0x80) {
  342. bank_no = (offset & 0x60) >> 5;
  343. if (bank_no < s->nbanks) {
  344. offset &= ~0x60;
  345. bank = &s->bank[bank_no];
  346. }
  347. }
  348. switch (offset) {
  349. case 0x00: /* INTC_REVISION */
  350. return 0x21;
  351. case 0x10: /* INTC_SYSCONFIG */
  352. return (s->autoidle >> 2) & 1;
  353. case 0x14: /* INTC_SYSSTATUS */
  354. return 1; /* RESETDONE */
  355. case 0x40: /* INTC_SIR_IRQ */
  356. return s->sir_intr[0];
  357. case 0x44: /* INTC_SIR_FIQ */
  358. return s->sir_intr[1];
  359. case 0x48: /* INTC_CONTROL */
  360. return (!s->mask) << 2; /* GLOBALMASK */
  361. case 0x4c: /* INTC_PROTECTION */
  362. return 0;
  363. case 0x50: /* INTC_IDLE */
  364. return s->autoidle & 3;
  365. /* Per-bank registers */
  366. case 0x80: /* INTC_ITR */
  367. return bank->inputs;
  368. case 0x84: /* INTC_MIR */
  369. return bank->mask;
  370. case 0x88: /* INTC_MIR_CLEAR */
  371. case 0x8c: /* INTC_MIR_SET */
  372. return 0;
  373. case 0x90: /* INTC_ISR_SET */
  374. return bank->swi;
  375. case 0x94: /* INTC_ISR_CLEAR */
  376. return 0;
  377. case 0x98: /* INTC_PENDING_IRQ */
  378. return bank->irqs & ~bank->mask & ~bank->fiq;
  379. case 0x9c: /* INTC_PENDING_FIQ */
  380. return bank->irqs & ~bank->mask & bank->fiq;
  381. /* Per-line registers */
  382. case 0x100 ... 0x300: /* INTC_ILR */
  383. bank_no = (offset - 0x100) >> 7;
  384. if (bank_no > s->nbanks)
  385. break;
  386. bank = &s->bank[bank_no];
  387. line_no = (offset & 0x7f) >> 2;
  388. return (bank->priority[line_no] << 2) |
  389. ((bank->fiq >> line_no) & 1);
  390. }
  391. OMAP_BAD_REG(addr);
  392. return 0;
  393. }
  394. static void omap2_inth_write(void *opaque, target_phys_addr_t addr,
  395. uint32_t value)
  396. {
  397. struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
  398. int offset = addr;
  399. int bank_no, line_no;
  400. struct omap_intr_handler_bank_s *bank = NULL;
  401. if ((offset & 0xf80) == 0x80) {
  402. bank_no = (offset & 0x60) >> 5;
  403. if (bank_no < s->nbanks) {
  404. offset &= ~0x60;
  405. bank = &s->bank[bank_no];
  406. }
  407. }
  408. switch (offset) {
  409. case 0x10: /* INTC_SYSCONFIG */
  410. s->autoidle &= 4;
  411. s->autoidle |= (value & 1) << 2;
  412. if (value & 2) /* SOFTRESET */
  413. omap_inth_reset(s);
  414. return;
  415. case 0x48: /* INTC_CONTROL */
  416. s->mask = (value & 4) ? 0 : ~0; /* GLOBALMASK */
  417. if (value & 2) { /* NEWFIQAGR */
  418. qemu_set_irq(s->parent_intr[1], 0);
  419. s->new_agr[1] = ~0;
  420. omap_inth_update(s, 1);
  421. }
  422. if (value & 1) { /* NEWIRQAGR */
  423. qemu_set_irq(s->parent_intr[0], 0);
  424. s->new_agr[0] = ~0;
  425. omap_inth_update(s, 0);
  426. }
  427. return;
  428. case 0x4c: /* INTC_PROTECTION */
  429. /* TODO: Make a bitmap (or sizeof(char)map) of access privileges
  430. * for every register, see Chapter 3 and 4 for privileged mode. */
  431. if (value & 1)
  432. fprintf(stderr, "%s: protection mode enable attempt\n",
  433. __FUNCTION__);
  434. return;
  435. case 0x50: /* INTC_IDLE */
  436. s->autoidle &= ~3;
  437. s->autoidle |= value & 3;
  438. return;
  439. /* Per-bank registers */
  440. case 0x84: /* INTC_MIR */
  441. bank->mask = value;
  442. omap_inth_update(s, 0);
  443. omap_inth_update(s, 1);
  444. return;
  445. case 0x88: /* INTC_MIR_CLEAR */
  446. bank->mask &= ~value;
  447. omap_inth_update(s, 0);
  448. omap_inth_update(s, 1);
  449. return;
  450. case 0x8c: /* INTC_MIR_SET */
  451. bank->mask |= value;
  452. return;
  453. case 0x90: /* INTC_ISR_SET */
  454. bank->irqs |= bank->swi |= value;
  455. omap_inth_update(s, 0);
  456. omap_inth_update(s, 1);
  457. return;
  458. case 0x94: /* INTC_ISR_CLEAR */
  459. bank->swi &= ~value;
  460. bank->irqs = bank->swi & bank->inputs;
  461. return;
  462. /* Per-line registers */
  463. case 0x100 ... 0x300: /* INTC_ILR */
  464. bank_no = (offset - 0x100) >> 7;
  465. if (bank_no > s->nbanks)
  466. break;
  467. bank = &s->bank[bank_no];
  468. line_no = (offset & 0x7f) >> 2;
  469. bank->priority[line_no] = (value >> 2) & 0x3f;
  470. bank->fiq &= ~(1 << line_no);
  471. bank->fiq |= (value & 1) << line_no;
  472. return;
  473. case 0x00: /* INTC_REVISION */
  474. case 0x14: /* INTC_SYSSTATUS */
  475. case 0x40: /* INTC_SIR_IRQ */
  476. case 0x44: /* INTC_SIR_FIQ */
  477. case 0x80: /* INTC_ITR */
  478. case 0x98: /* INTC_PENDING_IRQ */
  479. case 0x9c: /* INTC_PENDING_FIQ */
  480. OMAP_RO_REG(addr);
  481. return;
  482. }
  483. OMAP_BAD_REG(addr);
  484. }
  485. static CPUReadMemoryFunc * const omap2_inth_readfn[] = {
  486. omap_badwidth_read32,
  487. omap_badwidth_read32,
  488. omap2_inth_read,
  489. };
  490. static CPUWriteMemoryFunc * const omap2_inth_writefn[] = {
  491. omap2_inth_write,
  492. omap2_inth_write,
  493. omap2_inth_write,
  494. };
  495. struct omap_intr_handler_s *omap2_inth_init(target_phys_addr_t base,
  496. int size, int nbanks, qemu_irq **pins,
  497. qemu_irq parent_irq, qemu_irq parent_fiq,
  498. omap_clk fclk, omap_clk iclk)
  499. {
  500. int iomemtype;
  501. struct omap_intr_handler_s *s = (struct omap_intr_handler_s *)
  502. qemu_mallocz(sizeof(struct omap_intr_handler_s) +
  503. sizeof(struct omap_intr_handler_bank_s) * nbanks);
  504. s->parent_intr[0] = parent_irq;
  505. s->parent_intr[1] = parent_fiq;
  506. s->nbanks = nbanks;
  507. s->level_only = 1;
  508. s->pins = qemu_allocate_irqs(omap_set_intr_noedge, s, nbanks * 32);
  509. if (pins)
  510. *pins = s->pins;
  511. omap_inth_reset(s);
  512. iomemtype = cpu_register_io_memory(omap2_inth_readfn,
  513. omap2_inth_writefn, s, DEVICE_NATIVE_ENDIAN);
  514. cpu_register_physical_memory(base, size, iomemtype);
  515. return s;
  516. }