exynos4210_gic.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  1. /*
  2. * Samsung exynos4210 GIC implementation. Based on hw/arm_gic.c
  3. *
  4. * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
  5. * All rights reserved.
  6. *
  7. * Evgeny Voevodin <e.voevodin@samsung.com>
  8. *
  9. * This program is free software; you can redistribute it and/or modify it
  10. * under the terms of the GNU General Public License as published by the
  11. * Free Software Foundation; either version 2 of the License, or (at your
  12. * option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  17. * See the GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License along
  20. * with this program; if not, see <http://www.gnu.org/licenses/>.
  21. */
  22. #include "qemu/osdep.h"
  23. #include "hw/sysbus.h"
  24. #include "migration/vmstate.h"
  25. #include "qemu/module.h"
  26. #include "hw/irq.h"
  27. #include "hw/qdev-properties.h"
  28. #include "hw/arm/exynos4210.h"
  29. enum ExtGicId {
  30. EXT_GIC_ID_MDMA_LCD0 = 66,
  31. EXT_GIC_ID_PDMA0,
  32. EXT_GIC_ID_PDMA1,
  33. EXT_GIC_ID_TIMER0,
  34. EXT_GIC_ID_TIMER1,
  35. EXT_GIC_ID_TIMER2,
  36. EXT_GIC_ID_TIMER3,
  37. EXT_GIC_ID_TIMER4,
  38. EXT_GIC_ID_MCT_L0,
  39. EXT_GIC_ID_WDT,
  40. EXT_GIC_ID_RTC_ALARM,
  41. EXT_GIC_ID_RTC_TIC,
  42. EXT_GIC_ID_GPIO_XB,
  43. EXT_GIC_ID_GPIO_XA,
  44. EXT_GIC_ID_MCT_L1,
  45. EXT_GIC_ID_IEM_APC,
  46. EXT_GIC_ID_IEM_IEC,
  47. EXT_GIC_ID_NFC,
  48. EXT_GIC_ID_UART0,
  49. EXT_GIC_ID_UART1,
  50. EXT_GIC_ID_UART2,
  51. EXT_GIC_ID_UART3,
  52. EXT_GIC_ID_UART4,
  53. EXT_GIC_ID_MCT_G0,
  54. EXT_GIC_ID_I2C0,
  55. EXT_GIC_ID_I2C1,
  56. EXT_GIC_ID_I2C2,
  57. EXT_GIC_ID_I2C3,
  58. EXT_GIC_ID_I2C4,
  59. EXT_GIC_ID_I2C5,
  60. EXT_GIC_ID_I2C6,
  61. EXT_GIC_ID_I2C7,
  62. EXT_GIC_ID_SPI0,
  63. EXT_GIC_ID_SPI1,
  64. EXT_GIC_ID_SPI2,
  65. EXT_GIC_ID_MCT_G1,
  66. EXT_GIC_ID_USB_HOST,
  67. EXT_GIC_ID_USB_DEVICE,
  68. EXT_GIC_ID_MODEMIF,
  69. EXT_GIC_ID_HSMMC0,
  70. EXT_GIC_ID_HSMMC1,
  71. EXT_GIC_ID_HSMMC2,
  72. EXT_GIC_ID_HSMMC3,
  73. EXT_GIC_ID_SDMMC,
  74. EXT_GIC_ID_MIPI_CSI_4LANE,
  75. EXT_GIC_ID_MIPI_DSI_4LANE,
  76. EXT_GIC_ID_MIPI_CSI_2LANE,
  77. EXT_GIC_ID_MIPI_DSI_2LANE,
  78. EXT_GIC_ID_ONENAND_AUDI,
  79. EXT_GIC_ID_ROTATOR,
  80. EXT_GIC_ID_FIMC0,
  81. EXT_GIC_ID_FIMC1,
  82. EXT_GIC_ID_FIMC2,
  83. EXT_GIC_ID_FIMC3,
  84. EXT_GIC_ID_JPEG,
  85. EXT_GIC_ID_2D,
  86. EXT_GIC_ID_PCIe,
  87. EXT_GIC_ID_MIXER,
  88. EXT_GIC_ID_HDMI,
  89. EXT_GIC_ID_HDMI_I2C,
  90. EXT_GIC_ID_MFC,
  91. EXT_GIC_ID_TVENC,
  92. };
  93. enum ExtInt {
  94. EXT_GIC_ID_EXTINT0 = 48,
  95. EXT_GIC_ID_EXTINT1,
  96. EXT_GIC_ID_EXTINT2,
  97. EXT_GIC_ID_EXTINT3,
  98. EXT_GIC_ID_EXTINT4,
  99. EXT_GIC_ID_EXTINT5,
  100. EXT_GIC_ID_EXTINT6,
  101. EXT_GIC_ID_EXTINT7,
  102. EXT_GIC_ID_EXTINT8,
  103. EXT_GIC_ID_EXTINT9,
  104. EXT_GIC_ID_EXTINT10,
  105. EXT_GIC_ID_EXTINT11,
  106. EXT_GIC_ID_EXTINT12,
  107. EXT_GIC_ID_EXTINT13,
  108. EXT_GIC_ID_EXTINT14,
  109. EXT_GIC_ID_EXTINT15
  110. };
  111. /*
  112. * External GIC sources which are not from External Interrupt Combiner or
  113. * External Interrupts are starting from EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ,
  114. * which is INTG16 in Internal Interrupt Combiner.
  115. */
  116. static const uint32_t
  117. combiner_grp_to_gic_id[64-EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ][8] = {
  118. /* int combiner groups 16-19 */
  119. { }, { }, { }, { },
  120. /* int combiner group 20 */
  121. { 0, EXT_GIC_ID_MDMA_LCD0 },
  122. /* int combiner group 21 */
  123. { EXT_GIC_ID_PDMA0, EXT_GIC_ID_PDMA1 },
  124. /* int combiner group 22 */
  125. { EXT_GIC_ID_TIMER0, EXT_GIC_ID_TIMER1, EXT_GIC_ID_TIMER2,
  126. EXT_GIC_ID_TIMER3, EXT_GIC_ID_TIMER4 },
  127. /* int combiner group 23 */
  128. { EXT_GIC_ID_RTC_ALARM, EXT_GIC_ID_RTC_TIC },
  129. /* int combiner group 24 */
  130. { EXT_GIC_ID_GPIO_XB, EXT_GIC_ID_GPIO_XA },
  131. /* int combiner group 25 */
  132. { EXT_GIC_ID_IEM_APC, EXT_GIC_ID_IEM_IEC },
  133. /* int combiner group 26 */
  134. { EXT_GIC_ID_UART0, EXT_GIC_ID_UART1, EXT_GIC_ID_UART2, EXT_GIC_ID_UART3,
  135. EXT_GIC_ID_UART4 },
  136. /* int combiner group 27 */
  137. { EXT_GIC_ID_I2C0, EXT_GIC_ID_I2C1, EXT_GIC_ID_I2C2, EXT_GIC_ID_I2C3,
  138. EXT_GIC_ID_I2C4, EXT_GIC_ID_I2C5, EXT_GIC_ID_I2C6,
  139. EXT_GIC_ID_I2C7 },
  140. /* int combiner group 28 */
  141. { EXT_GIC_ID_SPI0, EXT_GIC_ID_SPI1, EXT_GIC_ID_SPI2 , EXT_GIC_ID_USB_HOST},
  142. /* int combiner group 29 */
  143. { EXT_GIC_ID_HSMMC0, EXT_GIC_ID_HSMMC1, EXT_GIC_ID_HSMMC2,
  144. EXT_GIC_ID_HSMMC3, EXT_GIC_ID_SDMMC },
  145. /* int combiner group 30 */
  146. { EXT_GIC_ID_MIPI_CSI_4LANE, EXT_GIC_ID_MIPI_CSI_2LANE },
  147. /* int combiner group 31 */
  148. { EXT_GIC_ID_MIPI_DSI_4LANE, EXT_GIC_ID_MIPI_DSI_2LANE },
  149. /* int combiner group 32 */
  150. { EXT_GIC_ID_FIMC0, EXT_GIC_ID_FIMC1 },
  151. /* int combiner group 33 */
  152. { EXT_GIC_ID_FIMC2, EXT_GIC_ID_FIMC3 },
  153. /* int combiner group 34 */
  154. { EXT_GIC_ID_ONENAND_AUDI, EXT_GIC_ID_NFC },
  155. /* int combiner group 35 */
  156. { 0, 0, 0, EXT_GIC_ID_MCT_L1, EXT_GIC_ID_MCT_G0, EXT_GIC_ID_MCT_G1 },
  157. /* int combiner group 36 */
  158. { EXT_GIC_ID_MIXER },
  159. /* int combiner group 37 */
  160. { EXT_GIC_ID_EXTINT4, EXT_GIC_ID_EXTINT5, EXT_GIC_ID_EXTINT6,
  161. EXT_GIC_ID_EXTINT7 },
  162. /* groups 38-50 */
  163. { }, { }, { }, { }, { }, { }, { }, { }, { }, { }, { }, { }, { },
  164. /* int combiner group 51 */
  165. { EXT_GIC_ID_MCT_L0, 0, 0, 0, EXT_GIC_ID_MCT_G0, EXT_GIC_ID_MCT_G1 },
  166. /* group 52 */
  167. { },
  168. /* int combiner group 53 */
  169. { EXT_GIC_ID_WDT, 0, 0, 0, EXT_GIC_ID_MCT_G0, EXT_GIC_ID_MCT_G1 },
  170. /* groups 54-63 */
  171. { }, { }, { }, { }, { }, { }, { }, { }, { }, { }
  172. };
  173. #define EXYNOS4210_GIC_NIRQ 160
  174. #define EXYNOS4210_EXT_GIC_CPU_REGION_SIZE 0x10000
  175. #define EXYNOS4210_EXT_GIC_DIST_REGION_SIZE 0x10000
  176. #define EXYNOS4210_EXT_GIC_PER_CPU_OFFSET 0x8000
  177. #define EXYNOS4210_EXT_GIC_CPU_GET_OFFSET(n) \
  178. ((n) * EXYNOS4210_EXT_GIC_PER_CPU_OFFSET)
  179. #define EXYNOS4210_EXT_GIC_DIST_GET_OFFSET(n) \
  180. ((n) * EXYNOS4210_EXT_GIC_PER_CPU_OFFSET)
  181. #define EXYNOS4210_GIC_CPU_REGION_SIZE 0x100
  182. #define EXYNOS4210_GIC_DIST_REGION_SIZE 0x1000
  183. static void exynos4210_irq_handler(void *opaque, int irq, int level)
  184. {
  185. Exynos4210Irq *s = (Exynos4210Irq *)opaque;
  186. /* Bypass */
  187. qemu_set_irq(s->board_irqs[irq], level);
  188. }
  189. /*
  190. * Initialize exynos4210 IRQ subsystem stub.
  191. */
  192. qemu_irq *exynos4210_init_irq(Exynos4210Irq *s)
  193. {
  194. return qemu_allocate_irqs(exynos4210_irq_handler, s,
  195. EXYNOS4210_MAX_INT_COMBINER_IN_IRQ);
  196. }
  197. /*
  198. * Initialize board IRQs.
  199. * These IRQs contain splitted Int/External Combiner and External Gic IRQs.
  200. */
  201. void exynos4210_init_board_irqs(Exynos4210Irq *s)
  202. {
  203. uint32_t grp, bit, irq_id, n;
  204. for (n = 0; n < EXYNOS4210_MAX_EXT_COMBINER_IN_IRQ; n++) {
  205. irq_id = 0;
  206. if (n == EXYNOS4210_COMBINER_GET_IRQ_NUM(1, 4) ||
  207. n == EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 4)) {
  208. /* MCT_G0 is passed to External GIC */
  209. irq_id = EXT_GIC_ID_MCT_G0;
  210. }
  211. if (n == EXYNOS4210_COMBINER_GET_IRQ_NUM(1, 5) ||
  212. n == EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 5)) {
  213. /* MCT_G1 is passed to External and GIC */
  214. irq_id = EXT_GIC_ID_MCT_G1;
  215. }
  216. if (irq_id) {
  217. s->board_irqs[n] = qemu_irq_split(s->int_combiner_irq[n],
  218. s->ext_gic_irq[irq_id-32]);
  219. } else {
  220. s->board_irqs[n] = qemu_irq_split(s->int_combiner_irq[n],
  221. s->ext_combiner_irq[n]);
  222. }
  223. }
  224. for (; n < EXYNOS4210_MAX_INT_COMBINER_IN_IRQ; n++) {
  225. /* these IDs are passed to Internal Combiner and External GIC */
  226. grp = EXYNOS4210_COMBINER_GET_GRP_NUM(n);
  227. bit = EXYNOS4210_COMBINER_GET_BIT_NUM(n);
  228. irq_id = combiner_grp_to_gic_id[grp -
  229. EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ][bit];
  230. if (irq_id) {
  231. s->board_irqs[n] = qemu_irq_split(s->int_combiner_irq[n],
  232. s->ext_gic_irq[irq_id-32]);
  233. }
  234. }
  235. }
  236. /*
  237. * Get IRQ number from exynos4210 IRQ subsystem stub.
  238. * To identify IRQ source use internal combiner group and bit number
  239. * grp - group number
  240. * bit - bit number inside group
  241. */
  242. uint32_t exynos4210_get_irq(uint32_t grp, uint32_t bit)
  243. {
  244. return EXYNOS4210_COMBINER_GET_IRQ_NUM(grp, bit);
  245. }
  246. /********* GIC part *********/
  247. #define TYPE_EXYNOS4210_GIC "exynos4210.gic"
  248. #define EXYNOS4210_GIC(obj) \
  249. OBJECT_CHECK(Exynos4210GicState, (obj), TYPE_EXYNOS4210_GIC)
  250. typedef struct {
  251. SysBusDevice parent_obj;
  252. MemoryRegion cpu_container;
  253. MemoryRegion dist_container;
  254. MemoryRegion cpu_alias[EXYNOS4210_NCPUS];
  255. MemoryRegion dist_alias[EXYNOS4210_NCPUS];
  256. uint32_t num_cpu;
  257. DeviceState *gic;
  258. } Exynos4210GicState;
  259. static void exynos4210_gic_set_irq(void *opaque, int irq, int level)
  260. {
  261. Exynos4210GicState *s = (Exynos4210GicState *)opaque;
  262. qemu_set_irq(qdev_get_gpio_in(s->gic, irq), level);
  263. }
  264. static void exynos4210_gic_realize(DeviceState *dev, Error **errp)
  265. {
  266. Object *obj = OBJECT(dev);
  267. Exynos4210GicState *s = EXYNOS4210_GIC(obj);
  268. SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
  269. const char cpu_prefix[] = "exynos4210-gic-alias_cpu";
  270. const char dist_prefix[] = "exynos4210-gic-alias_dist";
  271. char cpu_alias_name[sizeof(cpu_prefix) + 3];
  272. char dist_alias_name[sizeof(cpu_prefix) + 3];
  273. SysBusDevice *gicbusdev;
  274. uint32_t i;
  275. s->gic = qdev_create(NULL, "arm_gic");
  276. qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu);
  277. qdev_prop_set_uint32(s->gic, "num-irq", EXYNOS4210_GIC_NIRQ);
  278. qdev_init_nofail(s->gic);
  279. gicbusdev = SYS_BUS_DEVICE(s->gic);
  280. /* Pass through outbound IRQ lines from the GIC */
  281. sysbus_pass_irq(sbd, gicbusdev);
  282. /* Pass through inbound GPIO lines to the GIC */
  283. qdev_init_gpio_in(dev, exynos4210_gic_set_irq,
  284. EXYNOS4210_GIC_NIRQ - 32);
  285. memory_region_init(&s->cpu_container, obj, "exynos4210-cpu-container",
  286. EXYNOS4210_EXT_GIC_CPU_REGION_SIZE);
  287. memory_region_init(&s->dist_container, obj, "exynos4210-dist-container",
  288. EXYNOS4210_EXT_GIC_DIST_REGION_SIZE);
  289. for (i = 0; i < s->num_cpu; i++) {
  290. /* Map CPU interface per SMP Core */
  291. sprintf(cpu_alias_name, "%s%x", cpu_prefix, i);
  292. memory_region_init_alias(&s->cpu_alias[i], obj,
  293. cpu_alias_name,
  294. sysbus_mmio_get_region(gicbusdev, 1),
  295. 0,
  296. EXYNOS4210_GIC_CPU_REGION_SIZE);
  297. memory_region_add_subregion(&s->cpu_container,
  298. EXYNOS4210_EXT_GIC_CPU_GET_OFFSET(i), &s->cpu_alias[i]);
  299. /* Map Distributor per SMP Core */
  300. sprintf(dist_alias_name, "%s%x", dist_prefix, i);
  301. memory_region_init_alias(&s->dist_alias[i], obj,
  302. dist_alias_name,
  303. sysbus_mmio_get_region(gicbusdev, 0),
  304. 0,
  305. EXYNOS4210_GIC_DIST_REGION_SIZE);
  306. memory_region_add_subregion(&s->dist_container,
  307. EXYNOS4210_EXT_GIC_DIST_GET_OFFSET(i), &s->dist_alias[i]);
  308. }
  309. sysbus_init_mmio(sbd, &s->cpu_container);
  310. sysbus_init_mmio(sbd, &s->dist_container);
  311. }
  312. static Property exynos4210_gic_properties[] = {
  313. DEFINE_PROP_UINT32("num-cpu", Exynos4210GicState, num_cpu, 1),
  314. DEFINE_PROP_END_OF_LIST(),
  315. };
  316. static void exynos4210_gic_class_init(ObjectClass *klass, void *data)
  317. {
  318. DeviceClass *dc = DEVICE_CLASS(klass);
  319. dc->props = exynos4210_gic_properties;
  320. dc->realize = exynos4210_gic_realize;
  321. }
  322. static const TypeInfo exynos4210_gic_info = {
  323. .name = TYPE_EXYNOS4210_GIC,
  324. .parent = TYPE_SYS_BUS_DEVICE,
  325. .instance_size = sizeof(Exynos4210GicState),
  326. .class_init = exynos4210_gic_class_init,
  327. };
  328. static void exynos4210_gic_register_types(void)
  329. {
  330. type_register_static(&exynos4210_gic_info);
  331. }
  332. type_init(exynos4210_gic_register_types)
  333. /* IRQ OR Gate struct.
  334. *
  335. * This device models an OR gate. There are n_in input qdev gpio lines and one
  336. * output sysbus IRQ line. The output IRQ level is formed as OR between all
  337. * gpio inputs.
  338. */
  339. #define TYPE_EXYNOS4210_IRQ_GATE "exynos4210.irq_gate"
  340. #define EXYNOS4210_IRQ_GATE(obj) \
  341. OBJECT_CHECK(Exynos4210IRQGateState, (obj), TYPE_EXYNOS4210_IRQ_GATE)
  342. typedef struct Exynos4210IRQGateState {
  343. SysBusDevice parent_obj;
  344. uint32_t n_in; /* inputs amount */
  345. uint32_t *level; /* input levels */
  346. qemu_irq out; /* output IRQ */
  347. } Exynos4210IRQGateState;
  348. static Property exynos4210_irq_gate_properties[] = {
  349. DEFINE_PROP_UINT32("n_in", Exynos4210IRQGateState, n_in, 1),
  350. DEFINE_PROP_END_OF_LIST(),
  351. };
  352. static const VMStateDescription vmstate_exynos4210_irq_gate = {
  353. .name = "exynos4210.irq_gate",
  354. .version_id = 2,
  355. .minimum_version_id = 2,
  356. .fields = (VMStateField[]) {
  357. VMSTATE_VBUFFER_UINT32(level, Exynos4210IRQGateState, 1, NULL, n_in),
  358. VMSTATE_END_OF_LIST()
  359. }
  360. };
  361. /* Process a change in IRQ input. */
  362. static void exynos4210_irq_gate_handler(void *opaque, int irq, int level)
  363. {
  364. Exynos4210IRQGateState *s = (Exynos4210IRQGateState *)opaque;
  365. uint32_t i;
  366. assert(irq < s->n_in);
  367. s->level[irq] = level;
  368. for (i = 0; i < s->n_in; i++) {
  369. if (s->level[i] >= 1) {
  370. qemu_irq_raise(s->out);
  371. return;
  372. }
  373. }
  374. qemu_irq_lower(s->out);
  375. }
  376. static void exynos4210_irq_gate_reset(DeviceState *d)
  377. {
  378. Exynos4210IRQGateState *s = EXYNOS4210_IRQ_GATE(d);
  379. memset(s->level, 0, s->n_in * sizeof(*s->level));
  380. }
  381. /*
  382. * IRQ Gate initialization.
  383. */
  384. static void exynos4210_irq_gate_init(Object *obj)
  385. {
  386. Exynos4210IRQGateState *s = EXYNOS4210_IRQ_GATE(obj);
  387. SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
  388. sysbus_init_irq(sbd, &s->out);
  389. }
  390. static void exynos4210_irq_gate_realize(DeviceState *dev, Error **errp)
  391. {
  392. Exynos4210IRQGateState *s = EXYNOS4210_IRQ_GATE(dev);
  393. /* Allocate general purpose input signals and connect a handler to each of
  394. * them */
  395. qdev_init_gpio_in(dev, exynos4210_irq_gate_handler, s->n_in);
  396. s->level = g_malloc0(s->n_in * sizeof(*s->level));
  397. }
  398. static void exynos4210_irq_gate_class_init(ObjectClass *klass, void *data)
  399. {
  400. DeviceClass *dc = DEVICE_CLASS(klass);
  401. dc->reset = exynos4210_irq_gate_reset;
  402. dc->vmsd = &vmstate_exynos4210_irq_gate;
  403. dc->props = exynos4210_irq_gate_properties;
  404. dc->realize = exynos4210_irq_gate_realize;
  405. }
  406. static const TypeInfo exynos4210_irq_gate_info = {
  407. .name = TYPE_EXYNOS4210_IRQ_GATE,
  408. .parent = TYPE_SYS_BUS_DEVICE,
  409. .instance_size = sizeof(Exynos4210IRQGateState),
  410. .instance_init = exynos4210_irq_gate_init,
  411. .class_init = exynos4210_irq_gate_class_init,
  412. };
  413. static void exynos4210_irq_gate_register_types(void)
  414. {
  415. type_register_static(&exynos4210_irq_gate_info);
  416. }
  417. type_init(exynos4210_irq_gate_register_types)