omap_intc.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684
  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 "qemu/osdep.h"
  21. #include "hw/hw.h"
  22. #include "hw/arm/omap.h"
  23. #include "hw/sysbus.h"
  24. #include "qemu/error-report.h"
  25. #include "qapi/error.h"
  26. /* Interrupt Handlers */
  27. struct omap_intr_handler_bank_s {
  28. uint32_t irqs;
  29. uint32_t inputs;
  30. uint32_t mask;
  31. uint32_t fiq;
  32. uint32_t sens_edge;
  33. uint32_t swi;
  34. unsigned char priority[32];
  35. };
  36. #define TYPE_OMAP_INTC "common-omap-intc"
  37. #define OMAP_INTC(obj) \
  38. OBJECT_CHECK(struct omap_intr_handler_s, (obj), TYPE_OMAP_INTC)
  39. struct omap_intr_handler_s {
  40. SysBusDevice parent_obj;
  41. qemu_irq *pins;
  42. qemu_irq parent_intr[2];
  43. MemoryRegion mmio;
  44. void *iclk;
  45. void *fclk;
  46. unsigned char nbanks;
  47. int level_only;
  48. uint32_t size;
  49. uint8_t revision;
  50. /* state */
  51. uint32_t new_agr[2];
  52. int sir_intr[2];
  53. int autoidle;
  54. uint32_t mask;
  55. struct omap_intr_handler_bank_s bank[3];
  56. };
  57. static void omap_inth_sir_update(struct omap_intr_handler_s *s, int is_fiq)
  58. {
  59. int i, j, sir_intr, p_intr, p;
  60. uint32_t level;
  61. sir_intr = 0;
  62. p_intr = 255;
  63. /* Find the interrupt line with the highest dynamic priority.
  64. * Note: 0 denotes the hightest priority.
  65. * If all interrupts have the same priority, the default order is IRQ_N,
  66. * IRQ_N-1,...,IRQ_0. */
  67. for (j = 0; j < s->nbanks; ++j) {
  68. level = s->bank[j].irqs & ~s->bank[j].mask &
  69. (is_fiq ? s->bank[j].fiq : ~s->bank[j].fiq);
  70. while (level != 0) {
  71. i = ctz32(level);
  72. p = s->bank[j].priority[i];
  73. if (p <= p_intr) {
  74. p_intr = p;
  75. sir_intr = 32 * j + i;
  76. }
  77. level &= level - 1;
  78. }
  79. }
  80. s->sir_intr[is_fiq] = sir_intr;
  81. }
  82. static inline void omap_inth_update(struct omap_intr_handler_s *s, int is_fiq)
  83. {
  84. int i;
  85. uint32_t has_intr = 0;
  86. for (i = 0; i < s->nbanks; ++i)
  87. has_intr |= s->bank[i].irqs & ~s->bank[i].mask &
  88. (is_fiq ? s->bank[i].fiq : ~s->bank[i].fiq);
  89. if (s->new_agr[is_fiq] & has_intr & s->mask) {
  90. s->new_agr[is_fiq] = 0;
  91. omap_inth_sir_update(s, is_fiq);
  92. qemu_set_irq(s->parent_intr[is_fiq], 1);
  93. }
  94. }
  95. #define INT_FALLING_EDGE 0
  96. #define INT_LOW_LEVEL 1
  97. static void omap_set_intr(void *opaque, int irq, int req)
  98. {
  99. struct omap_intr_handler_s *ih = (struct omap_intr_handler_s *) opaque;
  100. uint32_t rise;
  101. struct omap_intr_handler_bank_s *bank = &ih->bank[irq >> 5];
  102. int n = irq & 31;
  103. if (req) {
  104. rise = ~bank->irqs & (1 << n);
  105. if (~bank->sens_edge & (1 << n))
  106. rise &= ~bank->inputs;
  107. bank->inputs |= (1 << n);
  108. if (rise) {
  109. bank->irqs |= rise;
  110. omap_inth_update(ih, 0);
  111. omap_inth_update(ih, 1);
  112. }
  113. } else {
  114. rise = bank->sens_edge & bank->irqs & (1 << n);
  115. bank->irqs &= ~rise;
  116. bank->inputs &= ~(1 << n);
  117. }
  118. }
  119. /* Simplified version with no edge detection */
  120. static void omap_set_intr_noedge(void *opaque, int irq, int req)
  121. {
  122. struct omap_intr_handler_s *ih = (struct omap_intr_handler_s *) opaque;
  123. uint32_t rise;
  124. struct omap_intr_handler_bank_s *bank = &ih->bank[irq >> 5];
  125. int n = irq & 31;
  126. if (req) {
  127. rise = ~bank->inputs & (1 << n);
  128. if (rise) {
  129. bank->irqs |= bank->inputs |= rise;
  130. omap_inth_update(ih, 0);
  131. omap_inth_update(ih, 1);
  132. }
  133. } else
  134. bank->irqs = (bank->inputs &= ~(1 << n)) | bank->swi;
  135. }
  136. static uint64_t omap_inth_read(void *opaque, hwaddr addr,
  137. unsigned size)
  138. {
  139. struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
  140. int i, offset = addr;
  141. int bank_no = offset >> 8;
  142. int line_no;
  143. struct omap_intr_handler_bank_s *bank = &s->bank[bank_no];
  144. offset &= 0xff;
  145. switch (offset) {
  146. case 0x00: /* ITR */
  147. return bank->irqs;
  148. case 0x04: /* MIR */
  149. return bank->mask;
  150. case 0x10: /* SIR_IRQ_CODE */
  151. case 0x14: /* SIR_FIQ_CODE */
  152. if (bank_no != 0)
  153. break;
  154. line_no = s->sir_intr[(offset - 0x10) >> 2];
  155. bank = &s->bank[line_no >> 5];
  156. i = line_no & 31;
  157. if (((bank->sens_edge >> i) & 1) == INT_FALLING_EDGE)
  158. bank->irqs &= ~(1 << i);
  159. return line_no;
  160. case 0x18: /* CONTROL_REG */
  161. if (bank_no != 0)
  162. break;
  163. return 0;
  164. case 0x1c: /* ILR0 */
  165. case 0x20: /* ILR1 */
  166. case 0x24: /* ILR2 */
  167. case 0x28: /* ILR3 */
  168. case 0x2c: /* ILR4 */
  169. case 0x30: /* ILR5 */
  170. case 0x34: /* ILR6 */
  171. case 0x38: /* ILR7 */
  172. case 0x3c: /* ILR8 */
  173. case 0x40: /* ILR9 */
  174. case 0x44: /* ILR10 */
  175. case 0x48: /* ILR11 */
  176. case 0x4c: /* ILR12 */
  177. case 0x50: /* ILR13 */
  178. case 0x54: /* ILR14 */
  179. case 0x58: /* ILR15 */
  180. case 0x5c: /* ILR16 */
  181. case 0x60: /* ILR17 */
  182. case 0x64: /* ILR18 */
  183. case 0x68: /* ILR19 */
  184. case 0x6c: /* ILR20 */
  185. case 0x70: /* ILR21 */
  186. case 0x74: /* ILR22 */
  187. case 0x78: /* ILR23 */
  188. case 0x7c: /* ILR24 */
  189. case 0x80: /* ILR25 */
  190. case 0x84: /* ILR26 */
  191. case 0x88: /* ILR27 */
  192. case 0x8c: /* ILR28 */
  193. case 0x90: /* ILR29 */
  194. case 0x94: /* ILR30 */
  195. case 0x98: /* ILR31 */
  196. i = (offset - 0x1c) >> 2;
  197. return (bank->priority[i] << 2) |
  198. (((bank->sens_edge >> i) & 1) << 1) |
  199. ((bank->fiq >> i) & 1);
  200. case 0x9c: /* ISR */
  201. return 0x00000000;
  202. }
  203. OMAP_BAD_REG(addr);
  204. return 0;
  205. }
  206. static void omap_inth_write(void *opaque, hwaddr addr,
  207. uint64_t value, unsigned size)
  208. {
  209. struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
  210. int i, offset = addr;
  211. int bank_no = offset >> 8;
  212. struct omap_intr_handler_bank_s *bank = &s->bank[bank_no];
  213. offset &= 0xff;
  214. switch (offset) {
  215. case 0x00: /* ITR */
  216. /* Important: ignore the clearing if the IRQ is level-triggered and
  217. the input bit is 1 */
  218. bank->irqs &= value | (bank->inputs & bank->sens_edge);
  219. return;
  220. case 0x04: /* MIR */
  221. bank->mask = value;
  222. omap_inth_update(s, 0);
  223. omap_inth_update(s, 1);
  224. return;
  225. case 0x10: /* SIR_IRQ_CODE */
  226. case 0x14: /* SIR_FIQ_CODE */
  227. OMAP_RO_REG(addr);
  228. break;
  229. case 0x18: /* CONTROL_REG */
  230. if (bank_no != 0)
  231. break;
  232. if (value & 2) {
  233. qemu_set_irq(s->parent_intr[1], 0);
  234. s->new_agr[1] = ~0;
  235. omap_inth_update(s, 1);
  236. }
  237. if (value & 1) {
  238. qemu_set_irq(s->parent_intr[0], 0);
  239. s->new_agr[0] = ~0;
  240. omap_inth_update(s, 0);
  241. }
  242. return;
  243. case 0x1c: /* ILR0 */
  244. case 0x20: /* ILR1 */
  245. case 0x24: /* ILR2 */
  246. case 0x28: /* ILR3 */
  247. case 0x2c: /* ILR4 */
  248. case 0x30: /* ILR5 */
  249. case 0x34: /* ILR6 */
  250. case 0x38: /* ILR7 */
  251. case 0x3c: /* ILR8 */
  252. case 0x40: /* ILR9 */
  253. case 0x44: /* ILR10 */
  254. case 0x48: /* ILR11 */
  255. case 0x4c: /* ILR12 */
  256. case 0x50: /* ILR13 */
  257. case 0x54: /* ILR14 */
  258. case 0x58: /* ILR15 */
  259. case 0x5c: /* ILR16 */
  260. case 0x60: /* ILR17 */
  261. case 0x64: /* ILR18 */
  262. case 0x68: /* ILR19 */
  263. case 0x6c: /* ILR20 */
  264. case 0x70: /* ILR21 */
  265. case 0x74: /* ILR22 */
  266. case 0x78: /* ILR23 */
  267. case 0x7c: /* ILR24 */
  268. case 0x80: /* ILR25 */
  269. case 0x84: /* ILR26 */
  270. case 0x88: /* ILR27 */
  271. case 0x8c: /* ILR28 */
  272. case 0x90: /* ILR29 */
  273. case 0x94: /* ILR30 */
  274. case 0x98: /* ILR31 */
  275. i = (offset - 0x1c) >> 2;
  276. bank->priority[i] = (value >> 2) & 0x1f;
  277. bank->sens_edge &= ~(1 << i);
  278. bank->sens_edge |= ((value >> 1) & 1) << i;
  279. bank->fiq &= ~(1 << i);
  280. bank->fiq |= (value & 1) << i;
  281. return;
  282. case 0x9c: /* ISR */
  283. for (i = 0; i < 32; i ++)
  284. if (value & (1 << i)) {
  285. omap_set_intr(s, 32 * bank_no + i, 1);
  286. return;
  287. }
  288. return;
  289. }
  290. OMAP_BAD_REG(addr);
  291. }
  292. static const MemoryRegionOps omap_inth_mem_ops = {
  293. .read = omap_inth_read,
  294. .write = omap_inth_write,
  295. .endianness = DEVICE_NATIVE_ENDIAN,
  296. .valid = {
  297. .min_access_size = 4,
  298. .max_access_size = 4,
  299. },
  300. };
  301. static void omap_inth_reset(DeviceState *dev)
  302. {
  303. struct omap_intr_handler_s *s = OMAP_INTC(dev);
  304. int i;
  305. for (i = 0; i < s->nbanks; ++i){
  306. s->bank[i].irqs = 0x00000000;
  307. s->bank[i].mask = 0xffffffff;
  308. s->bank[i].sens_edge = 0x00000000;
  309. s->bank[i].fiq = 0x00000000;
  310. s->bank[i].inputs = 0x00000000;
  311. s->bank[i].swi = 0x00000000;
  312. memset(s->bank[i].priority, 0, sizeof(s->bank[i].priority));
  313. if (s->level_only)
  314. s->bank[i].sens_edge = 0xffffffff;
  315. }
  316. s->new_agr[0] = ~0;
  317. s->new_agr[1] = ~0;
  318. s->sir_intr[0] = 0;
  319. s->sir_intr[1] = 0;
  320. s->autoidle = 0;
  321. s->mask = ~0;
  322. qemu_set_irq(s->parent_intr[0], 0);
  323. qemu_set_irq(s->parent_intr[1], 0);
  324. }
  325. static void omap_intc_init(Object *obj)
  326. {
  327. DeviceState *dev = DEVICE(obj);
  328. struct omap_intr_handler_s *s = OMAP_INTC(obj);
  329. SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
  330. s->nbanks = 1;
  331. sysbus_init_irq(sbd, &s->parent_intr[0]);
  332. sysbus_init_irq(sbd, &s->parent_intr[1]);
  333. qdev_init_gpio_in(dev, omap_set_intr, s->nbanks * 32);
  334. memory_region_init_io(&s->mmio, obj, &omap_inth_mem_ops, s,
  335. "omap-intc", s->size);
  336. sysbus_init_mmio(sbd, &s->mmio);
  337. }
  338. static void omap_intc_realize(DeviceState *dev, Error **errp)
  339. {
  340. struct omap_intr_handler_s *s = OMAP_INTC(dev);
  341. if (!s->iclk) {
  342. error_setg(errp, "omap-intc: clk not connected");
  343. }
  344. }
  345. static Property omap_intc_properties[] = {
  346. DEFINE_PROP_UINT32("size", struct omap_intr_handler_s, size, 0x100),
  347. DEFINE_PROP_PTR("clk", struct omap_intr_handler_s, iclk),
  348. DEFINE_PROP_END_OF_LIST(),
  349. };
  350. static void omap_intc_class_init(ObjectClass *klass, void *data)
  351. {
  352. DeviceClass *dc = DEVICE_CLASS(klass);
  353. dc->reset = omap_inth_reset;
  354. dc->props = omap_intc_properties;
  355. /* Reason: pointer property "clk" */
  356. dc->user_creatable = false;
  357. dc->realize = omap_intc_realize;
  358. }
  359. static const TypeInfo omap_intc_info = {
  360. .name = "omap-intc",
  361. .parent = TYPE_OMAP_INTC,
  362. .instance_init = omap_intc_init,
  363. .class_init = omap_intc_class_init,
  364. };
  365. static uint64_t omap2_inth_read(void *opaque, hwaddr addr,
  366. unsigned size)
  367. {
  368. struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
  369. int offset = addr;
  370. int bank_no, line_no;
  371. struct omap_intr_handler_bank_s *bank = NULL;
  372. if ((offset & 0xf80) == 0x80) {
  373. bank_no = (offset & 0x60) >> 5;
  374. if (bank_no < s->nbanks) {
  375. offset &= ~0x60;
  376. bank = &s->bank[bank_no];
  377. } else {
  378. OMAP_BAD_REG(addr);
  379. return 0;
  380. }
  381. }
  382. switch (offset) {
  383. case 0x00: /* INTC_REVISION */
  384. return s->revision;
  385. case 0x10: /* INTC_SYSCONFIG */
  386. return (s->autoidle >> 2) & 1;
  387. case 0x14: /* INTC_SYSSTATUS */
  388. return 1; /* RESETDONE */
  389. case 0x40: /* INTC_SIR_IRQ */
  390. return s->sir_intr[0];
  391. case 0x44: /* INTC_SIR_FIQ */
  392. return s->sir_intr[1];
  393. case 0x48: /* INTC_CONTROL */
  394. return (!s->mask) << 2; /* GLOBALMASK */
  395. case 0x4c: /* INTC_PROTECTION */
  396. return 0;
  397. case 0x50: /* INTC_IDLE */
  398. return s->autoidle & 3;
  399. /* Per-bank registers */
  400. case 0x80: /* INTC_ITR */
  401. return bank->inputs;
  402. case 0x84: /* INTC_MIR */
  403. return bank->mask;
  404. case 0x88: /* INTC_MIR_CLEAR */
  405. case 0x8c: /* INTC_MIR_SET */
  406. return 0;
  407. case 0x90: /* INTC_ISR_SET */
  408. return bank->swi;
  409. case 0x94: /* INTC_ISR_CLEAR */
  410. return 0;
  411. case 0x98: /* INTC_PENDING_IRQ */
  412. return bank->irqs & ~bank->mask & ~bank->fiq;
  413. case 0x9c: /* INTC_PENDING_FIQ */
  414. return bank->irqs & ~bank->mask & bank->fiq;
  415. /* Per-line registers */
  416. case 0x100 ... 0x300: /* INTC_ILR */
  417. bank_no = (offset - 0x100) >> 7;
  418. if (bank_no > s->nbanks)
  419. break;
  420. bank = &s->bank[bank_no];
  421. line_no = (offset & 0x7f) >> 2;
  422. return (bank->priority[line_no] << 2) |
  423. ((bank->fiq >> line_no) & 1);
  424. }
  425. OMAP_BAD_REG(addr);
  426. return 0;
  427. }
  428. static void omap2_inth_write(void *opaque, hwaddr addr,
  429. uint64_t value, unsigned size)
  430. {
  431. struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
  432. int offset = addr;
  433. int bank_no, line_no;
  434. struct omap_intr_handler_bank_s *bank = NULL;
  435. if ((offset & 0xf80) == 0x80) {
  436. bank_no = (offset & 0x60) >> 5;
  437. if (bank_no < s->nbanks) {
  438. offset &= ~0x60;
  439. bank = &s->bank[bank_no];
  440. } else {
  441. OMAP_BAD_REG(addr);
  442. return;
  443. }
  444. }
  445. switch (offset) {
  446. case 0x10: /* INTC_SYSCONFIG */
  447. s->autoidle &= 4;
  448. s->autoidle |= (value & 1) << 2;
  449. if (value & 2) { /* SOFTRESET */
  450. omap_inth_reset(DEVICE(s));
  451. }
  452. return;
  453. case 0x48: /* INTC_CONTROL */
  454. s->mask = (value & 4) ? 0 : ~0; /* GLOBALMASK */
  455. if (value & 2) { /* NEWFIQAGR */
  456. qemu_set_irq(s->parent_intr[1], 0);
  457. s->new_agr[1] = ~0;
  458. omap_inth_update(s, 1);
  459. }
  460. if (value & 1) { /* NEWIRQAGR */
  461. qemu_set_irq(s->parent_intr[0], 0);
  462. s->new_agr[0] = ~0;
  463. omap_inth_update(s, 0);
  464. }
  465. return;
  466. case 0x4c: /* INTC_PROTECTION */
  467. /* TODO: Make a bitmap (or sizeof(char)map) of access privileges
  468. * for every register, see Chapter 3 and 4 for privileged mode. */
  469. if (value & 1)
  470. fprintf(stderr, "%s: protection mode enable attempt\n",
  471. __func__);
  472. return;
  473. case 0x50: /* INTC_IDLE */
  474. s->autoidle &= ~3;
  475. s->autoidle |= value & 3;
  476. return;
  477. /* Per-bank registers */
  478. case 0x84: /* INTC_MIR */
  479. bank->mask = value;
  480. omap_inth_update(s, 0);
  481. omap_inth_update(s, 1);
  482. return;
  483. case 0x88: /* INTC_MIR_CLEAR */
  484. bank->mask &= ~value;
  485. omap_inth_update(s, 0);
  486. omap_inth_update(s, 1);
  487. return;
  488. case 0x8c: /* INTC_MIR_SET */
  489. bank->mask |= value;
  490. return;
  491. case 0x90: /* INTC_ISR_SET */
  492. bank->irqs |= bank->swi |= value;
  493. omap_inth_update(s, 0);
  494. omap_inth_update(s, 1);
  495. return;
  496. case 0x94: /* INTC_ISR_CLEAR */
  497. bank->swi &= ~value;
  498. bank->irqs = bank->swi & bank->inputs;
  499. return;
  500. /* Per-line registers */
  501. case 0x100 ... 0x300: /* INTC_ILR */
  502. bank_no = (offset - 0x100) >> 7;
  503. if (bank_no > s->nbanks)
  504. break;
  505. bank = &s->bank[bank_no];
  506. line_no = (offset & 0x7f) >> 2;
  507. bank->priority[line_no] = (value >> 2) & 0x3f;
  508. bank->fiq &= ~(1 << line_no);
  509. bank->fiq |= (value & 1) << line_no;
  510. return;
  511. case 0x00: /* INTC_REVISION */
  512. case 0x14: /* INTC_SYSSTATUS */
  513. case 0x40: /* INTC_SIR_IRQ */
  514. case 0x44: /* INTC_SIR_FIQ */
  515. case 0x80: /* INTC_ITR */
  516. case 0x98: /* INTC_PENDING_IRQ */
  517. case 0x9c: /* INTC_PENDING_FIQ */
  518. OMAP_RO_REG(addr);
  519. return;
  520. }
  521. OMAP_BAD_REG(addr);
  522. }
  523. static const MemoryRegionOps omap2_inth_mem_ops = {
  524. .read = omap2_inth_read,
  525. .write = omap2_inth_write,
  526. .endianness = DEVICE_NATIVE_ENDIAN,
  527. .valid = {
  528. .min_access_size = 4,
  529. .max_access_size = 4,
  530. },
  531. };
  532. static void omap2_intc_init(Object *obj)
  533. {
  534. DeviceState *dev = DEVICE(obj);
  535. struct omap_intr_handler_s *s = OMAP_INTC(obj);
  536. SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
  537. s->level_only = 1;
  538. s->nbanks = 3;
  539. sysbus_init_irq(sbd, &s->parent_intr[0]);
  540. sysbus_init_irq(sbd, &s->parent_intr[1]);
  541. qdev_init_gpio_in(dev, omap_set_intr_noedge, s->nbanks * 32);
  542. memory_region_init_io(&s->mmio, obj, &omap2_inth_mem_ops, s,
  543. "omap2-intc", 0x1000);
  544. sysbus_init_mmio(sbd, &s->mmio);
  545. }
  546. static void omap2_intc_realize(DeviceState *dev, Error **errp)
  547. {
  548. struct omap_intr_handler_s *s = OMAP_INTC(dev);
  549. if (!s->iclk) {
  550. error_setg(errp, "omap2-intc: iclk not connected");
  551. return;
  552. }
  553. if (!s->fclk) {
  554. error_setg(errp, "omap2-intc: fclk not connected");
  555. return;
  556. }
  557. }
  558. static Property omap2_intc_properties[] = {
  559. DEFINE_PROP_UINT8("revision", struct omap_intr_handler_s,
  560. revision, 0x21),
  561. DEFINE_PROP_PTR("iclk", struct omap_intr_handler_s, iclk),
  562. DEFINE_PROP_PTR("fclk", struct omap_intr_handler_s, fclk),
  563. DEFINE_PROP_END_OF_LIST(),
  564. };
  565. static void omap2_intc_class_init(ObjectClass *klass, void *data)
  566. {
  567. DeviceClass *dc = DEVICE_CLASS(klass);
  568. dc->reset = omap_inth_reset;
  569. dc->props = omap2_intc_properties;
  570. /* Reason: pointer property "iclk", "fclk" */
  571. dc->user_creatable = false;
  572. dc->realize = omap2_intc_realize;
  573. }
  574. static const TypeInfo omap2_intc_info = {
  575. .name = "omap2-intc",
  576. .parent = TYPE_OMAP_INTC,
  577. .instance_init = omap2_intc_init,
  578. .class_init = omap2_intc_class_init,
  579. };
  580. static const TypeInfo omap_intc_type_info = {
  581. .name = TYPE_OMAP_INTC,
  582. .parent = TYPE_SYS_BUS_DEVICE,
  583. .instance_size = sizeof(struct omap_intr_handler_s),
  584. .abstract = true,
  585. };
  586. static void omap_intc_register_types(void)
  587. {
  588. type_register_static(&omap_intc_type_info);
  589. type_register_static(&omap_intc_info);
  590. type_register_static(&omap2_intc_info);
  591. }
  592. type_init(omap_intc_register_types)