|
|
1.1 ! root 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 <[email protected]> ! 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: ! 23: #include "sysbus.h" ! 24: #include "qemu-common.h" ! 25: #include "irq.h" ! 26: #include "exynos4210.h" ! 27: ! 28: enum ExtGicId { ! 29: EXT_GIC_ID_MDMA_LCD0 = 66, ! 30: EXT_GIC_ID_PDMA0, ! 31: EXT_GIC_ID_PDMA1, ! 32: EXT_GIC_ID_TIMER0, ! 33: EXT_GIC_ID_TIMER1, ! 34: EXT_GIC_ID_TIMER2, ! 35: EXT_GIC_ID_TIMER3, ! 36: EXT_GIC_ID_TIMER4, ! 37: EXT_GIC_ID_MCT_L0, ! 38: EXT_GIC_ID_WDT, ! 39: EXT_GIC_ID_RTC_ALARM, ! 40: EXT_GIC_ID_RTC_TIC, ! 41: EXT_GIC_ID_GPIO_XB, ! 42: EXT_GIC_ID_GPIO_XA, ! 43: EXT_GIC_ID_MCT_L1, ! 44: EXT_GIC_ID_IEM_APC, ! 45: EXT_GIC_ID_IEM_IEC, ! 46: EXT_GIC_ID_NFC, ! 47: EXT_GIC_ID_UART0, ! 48: EXT_GIC_ID_UART1, ! 49: EXT_GIC_ID_UART2, ! 50: EXT_GIC_ID_UART3, ! 51: EXT_GIC_ID_UART4, ! 52: EXT_GIC_ID_MCT_G0, ! 53: EXT_GIC_ID_I2C0, ! 54: EXT_GIC_ID_I2C1, ! 55: EXT_GIC_ID_I2C2, ! 56: EXT_GIC_ID_I2C3, ! 57: EXT_GIC_ID_I2C4, ! 58: EXT_GIC_ID_I2C5, ! 59: EXT_GIC_ID_I2C6, ! 60: EXT_GIC_ID_I2C7, ! 61: EXT_GIC_ID_SPI0, ! 62: EXT_GIC_ID_SPI1, ! 63: EXT_GIC_ID_SPI2, ! 64: EXT_GIC_ID_MCT_G1, ! 65: EXT_GIC_ID_USB_HOST, ! 66: EXT_GIC_ID_USB_DEVICE, ! 67: EXT_GIC_ID_MODEMIF, ! 68: EXT_GIC_ID_HSMMC0, ! 69: EXT_GIC_ID_HSMMC1, ! 70: EXT_GIC_ID_HSMMC2, ! 71: EXT_GIC_ID_HSMMC3, ! 72: EXT_GIC_ID_SDMMC, ! 73: EXT_GIC_ID_MIPI_CSI_4LANE, ! 74: EXT_GIC_ID_MIPI_DSI_4LANE, ! 75: EXT_GIC_ID_MIPI_CSI_2LANE, ! 76: EXT_GIC_ID_MIPI_DSI_2LANE, ! 77: EXT_GIC_ID_ONENAND_AUDI, ! 78: EXT_GIC_ID_ROTATOR, ! 79: EXT_GIC_ID_FIMC0, ! 80: EXT_GIC_ID_FIMC1, ! 81: EXT_GIC_ID_FIMC2, ! 82: EXT_GIC_ID_FIMC3, ! 83: EXT_GIC_ID_JPEG, ! 84: EXT_GIC_ID_2D, ! 85: EXT_GIC_ID_PCIe, ! 86: EXT_GIC_ID_MIXER, ! 87: EXT_GIC_ID_HDMI, ! 88: EXT_GIC_ID_HDMI_I2C, ! 89: EXT_GIC_ID_MFC, ! 90: EXT_GIC_ID_TVENC, ! 91: }; ! 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: /* ! 113: * External GIC sources which are not from External Interrupt Combiner or ! 114: * External Interrupts are starting from EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ, ! 115: * which is INTG16 in Internal Interrupt Combiner. ! 116: */ ! 117: ! 118: static uint32_t ! 119: combiner_grp_to_gic_id[64-EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ][8] = { ! 120: /* int combiner groups 16-19 */ ! 121: { }, { }, { }, { }, ! 122: /* int combiner group 20 */ ! 123: { 0, EXT_GIC_ID_MDMA_LCD0 }, ! 124: /* int combiner group 21 */ ! 125: { EXT_GIC_ID_PDMA0, EXT_GIC_ID_PDMA1 }, ! 126: /* int combiner group 22 */ ! 127: { EXT_GIC_ID_TIMER0, EXT_GIC_ID_TIMER1, EXT_GIC_ID_TIMER2, ! 128: EXT_GIC_ID_TIMER3, EXT_GIC_ID_TIMER4 }, ! 129: /* int combiner group 23 */ ! 130: { EXT_GIC_ID_RTC_ALARM, EXT_GIC_ID_RTC_TIC }, ! 131: /* int combiner group 24 */ ! 132: { EXT_GIC_ID_GPIO_XB, EXT_GIC_ID_GPIO_XA }, ! 133: /* int combiner group 25 */ ! 134: { EXT_GIC_ID_IEM_APC, EXT_GIC_ID_IEM_IEC }, ! 135: /* int combiner group 26 */ ! 136: { EXT_GIC_ID_UART0, EXT_GIC_ID_UART1, EXT_GIC_ID_UART2, EXT_GIC_ID_UART3, ! 137: EXT_GIC_ID_UART4 }, ! 138: /* int combiner group 27 */ ! 139: { EXT_GIC_ID_I2C0, EXT_GIC_ID_I2C1, EXT_GIC_ID_I2C2, EXT_GIC_ID_I2C3, ! 140: EXT_GIC_ID_I2C4, EXT_GIC_ID_I2C5, EXT_GIC_ID_I2C6, ! 141: EXT_GIC_ID_I2C7 }, ! 142: /* int combiner group 28 */ ! 143: { EXT_GIC_ID_SPI0, EXT_GIC_ID_SPI1, EXT_GIC_ID_SPI2 }, ! 144: /* int combiner group 29 */ ! 145: { EXT_GIC_ID_HSMMC0, EXT_GIC_ID_HSMMC1, EXT_GIC_ID_HSMMC2, ! 146: EXT_GIC_ID_HSMMC3, EXT_GIC_ID_SDMMC }, ! 147: /* int combiner group 30 */ ! 148: { EXT_GIC_ID_MIPI_CSI_4LANE, EXT_GIC_ID_MIPI_CSI_2LANE }, ! 149: /* int combiner group 31 */ ! 150: { EXT_GIC_ID_MIPI_DSI_4LANE, EXT_GIC_ID_MIPI_DSI_2LANE }, ! 151: /* int combiner group 32 */ ! 152: { EXT_GIC_ID_FIMC0, EXT_GIC_ID_FIMC1 }, ! 153: /* int combiner group 33 */ ! 154: { EXT_GIC_ID_FIMC2, EXT_GIC_ID_FIMC3 }, ! 155: /* int combiner group 34 */ ! 156: { EXT_GIC_ID_ONENAND_AUDI, EXT_GIC_ID_NFC }, ! 157: /* int combiner group 35 */ ! 158: { 0, 0, 0, EXT_GIC_ID_MCT_L1, EXT_GIC_ID_MCT_G0, EXT_GIC_ID_MCT_G1 }, ! 159: /* int combiner group 36 */ ! 160: { EXT_GIC_ID_MIXER }, ! 161: /* int combiner group 37 */ ! 162: { EXT_GIC_ID_EXTINT4, EXT_GIC_ID_EXTINT5, EXT_GIC_ID_EXTINT6, ! 163: EXT_GIC_ID_EXTINT7 }, ! 164: /* groups 38-50 */ ! 165: { }, { }, { }, { }, { }, { }, { }, { }, { }, { }, { }, { }, { }, ! 166: /* int combiner group 51 */ ! 167: { EXT_GIC_ID_MCT_L0, 0, 0, 0, EXT_GIC_ID_MCT_G0, EXT_GIC_ID_MCT_G1 }, ! 168: /* group 52 */ ! 169: { }, ! 170: /* int combiner group 53 */ ! 171: { EXT_GIC_ID_WDT, 0, 0, 0, EXT_GIC_ID_MCT_G0, EXT_GIC_ID_MCT_G1 }, ! 172: /* groups 54-63 */ ! 173: { }, { }, { }, { }, { }, { }, { }, { }, { }, { } ! 174: }; ! 175: ! 176: #define EXYNOS4210_GIC_NIRQ 160 ! 177: ! 178: #define EXYNOS4210_EXT_GIC_CPU_REGION_SIZE 0x10000 ! 179: #define EXYNOS4210_EXT_GIC_DIST_REGION_SIZE 0x10000 ! 180: ! 181: #define EXYNOS4210_EXT_GIC_PER_CPU_OFFSET 0x8000 ! 182: #define EXYNOS4210_EXT_GIC_CPU_GET_OFFSET(n) \ ! 183: ((n) * EXYNOS4210_EXT_GIC_PER_CPU_OFFSET) ! 184: #define EXYNOS4210_EXT_GIC_DIST_GET_OFFSET(n) \ ! 185: ((n) * EXYNOS4210_EXT_GIC_PER_CPU_OFFSET) ! 186: ! 187: #define EXYNOS4210_GIC_CPU_REGION_SIZE 0x100 ! 188: #define EXYNOS4210_GIC_DIST_REGION_SIZE 0x1000 ! 189: ! 190: static void exynos4210_irq_handler(void *opaque, int irq, int level) ! 191: { ! 192: Exynos4210Irq *s = (Exynos4210Irq *)opaque; ! 193: ! 194: /* Bypass */ ! 195: qemu_set_irq(s->board_irqs[irq], level); ! 196: ! 197: return; ! 198: } ! 199: ! 200: /* ! 201: * Initialize exynos4210 IRQ subsystem stub. ! 202: */ ! 203: qemu_irq *exynos4210_init_irq(Exynos4210Irq *s) ! 204: { ! 205: return qemu_allocate_irqs(exynos4210_irq_handler, s, ! 206: EXYNOS4210_MAX_INT_COMBINER_IN_IRQ); ! 207: } ! 208: ! 209: /* ! 210: * Initialize board IRQs. ! 211: * These IRQs contain splitted Int/External Combiner and External Gic IRQs. ! 212: */ ! 213: void exynos4210_init_board_irqs(Exynos4210Irq *s) ! 214: { ! 215: uint32_t grp, bit, irq_id, n; ! 216: ! 217: for (n = 0; n < EXYNOS4210_MAX_EXT_COMBINER_IN_IRQ; n++) { ! 218: s->board_irqs[n] = qemu_irq_split(s->int_combiner_irq[n], ! 219: s->ext_combiner_irq[n]); ! 220: ! 221: irq_id = 0; ! 222: if (n == EXYNOS4210_COMBINER_GET_IRQ_NUM(1, 4) || ! 223: n == EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 4)) { ! 224: /* MCT_G0 is passed to External GIC */ ! 225: irq_id = EXT_GIC_ID_MCT_G0; ! 226: } ! 227: if (n == EXYNOS4210_COMBINER_GET_IRQ_NUM(1, 5) || ! 228: n == EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 5)) { ! 229: /* MCT_G1 is passed to External and GIC */ ! 230: irq_id = EXT_GIC_ID_MCT_G1; ! 231: } ! 232: if (irq_id) { ! 233: s->board_irqs[n] = qemu_irq_split(s->int_combiner_irq[n], ! 234: s->ext_gic_irq[irq_id-32]); ! 235: } ! 236: ! 237: } ! 238: for (; n < EXYNOS4210_MAX_INT_COMBINER_IN_IRQ; n++) { ! 239: /* these IDs are passed to Internal Combiner and External GIC */ ! 240: grp = EXYNOS4210_COMBINER_GET_GRP_NUM(n); ! 241: bit = EXYNOS4210_COMBINER_GET_BIT_NUM(n); ! 242: irq_id = combiner_grp_to_gic_id[grp - ! 243: EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ][bit]; ! 244: ! 245: if (irq_id) { ! 246: s->board_irqs[n] = qemu_irq_split(s->int_combiner_irq[n], ! 247: s->ext_gic_irq[irq_id-32]); ! 248: } ! 249: } ! 250: } ! 251: ! 252: /* ! 253: * Get IRQ number from exynos4210 IRQ subsystem stub. ! 254: * To identify IRQ source use internal combiner group and bit number ! 255: * grp - group number ! 256: * bit - bit number inside group ! 257: */ ! 258: uint32_t exynos4210_get_irq(uint32_t grp, uint32_t bit) ! 259: { ! 260: return EXYNOS4210_COMBINER_GET_IRQ_NUM(grp, bit); ! 261: } ! 262: ! 263: /********* GIC part *********/ ! 264: ! 265: typedef struct { ! 266: SysBusDevice busdev; ! 267: MemoryRegion cpu_container; ! 268: MemoryRegion dist_container; ! 269: MemoryRegion cpu_alias[EXYNOS4210_NCPUS]; ! 270: MemoryRegion dist_alias[EXYNOS4210_NCPUS]; ! 271: uint32_t num_cpu; ! 272: DeviceState *gic; ! 273: } Exynos4210GicState; ! 274: ! 275: static void exynos4210_gic_set_irq(void *opaque, int irq, int level) ! 276: { ! 277: Exynos4210GicState *s = (Exynos4210GicState *)opaque; ! 278: qemu_set_irq(qdev_get_gpio_in(s->gic, irq), level); ! 279: } ! 280: ! 281: static int exynos4210_gic_init(SysBusDevice *dev) ! 282: { ! 283: Exynos4210GicState *s = FROM_SYSBUS(Exynos4210GicState, dev); ! 284: uint32_t i; ! 285: const char cpu_prefix[] = "exynos4210-gic-alias_cpu"; ! 286: const char dist_prefix[] = "exynos4210-gic-alias_dist"; ! 287: char cpu_alias_name[sizeof(cpu_prefix) + 3]; ! 288: char dist_alias_name[sizeof(cpu_prefix) + 3]; ! 289: SysBusDevice *busdev; ! 290: ! 291: s->gic = qdev_create(NULL, "arm_gic"); ! 292: qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu); ! 293: qdev_prop_set_uint32(s->gic, "num-irq", EXYNOS4210_GIC_NIRQ); ! 294: qdev_init_nofail(s->gic); ! 295: busdev = sysbus_from_qdev(s->gic); ! 296: ! 297: /* Pass through outbound IRQ lines from the GIC */ ! 298: sysbus_pass_irq(dev, busdev); ! 299: ! 300: /* Pass through inbound GPIO lines to the GIC */ ! 301: qdev_init_gpio_in(&s->busdev.qdev, exynos4210_gic_set_irq, ! 302: EXYNOS4210_GIC_NIRQ - 32); ! 303: ! 304: memory_region_init(&s->cpu_container, "exynos4210-cpu-container", ! 305: EXYNOS4210_EXT_GIC_CPU_REGION_SIZE); ! 306: memory_region_init(&s->dist_container, "exynos4210-dist-container", ! 307: EXYNOS4210_EXT_GIC_DIST_REGION_SIZE); ! 308: ! 309: for (i = 0; i < s->num_cpu; i++) { ! 310: /* Map CPU interface per SMP Core */ ! 311: sprintf(cpu_alias_name, "%s%x", cpu_prefix, i); ! 312: memory_region_init_alias(&s->cpu_alias[i], ! 313: cpu_alias_name, ! 314: sysbus_mmio_get_region(busdev, 1), ! 315: 0, ! 316: EXYNOS4210_GIC_CPU_REGION_SIZE); ! 317: memory_region_add_subregion(&s->cpu_container, ! 318: EXYNOS4210_EXT_GIC_CPU_GET_OFFSET(i), &s->cpu_alias[i]); ! 319: ! 320: /* Map Distributor per SMP Core */ ! 321: sprintf(dist_alias_name, "%s%x", dist_prefix, i); ! 322: memory_region_init_alias(&s->dist_alias[i], ! 323: dist_alias_name, ! 324: sysbus_mmio_get_region(busdev, 0), ! 325: 0, ! 326: EXYNOS4210_GIC_DIST_REGION_SIZE); ! 327: memory_region_add_subregion(&s->dist_container, ! 328: EXYNOS4210_EXT_GIC_DIST_GET_OFFSET(i), &s->dist_alias[i]); ! 329: } ! 330: ! 331: sysbus_init_mmio(dev, &s->cpu_container); ! 332: sysbus_init_mmio(dev, &s->dist_container); ! 333: ! 334: return 0; ! 335: } ! 336: ! 337: static Property exynos4210_gic_properties[] = { ! 338: DEFINE_PROP_UINT32("num-cpu", Exynos4210GicState, num_cpu, 1), ! 339: DEFINE_PROP_END_OF_LIST(), ! 340: }; ! 341: ! 342: static void exynos4210_gic_class_init(ObjectClass *klass, void *data) ! 343: { ! 344: DeviceClass *dc = DEVICE_CLASS(klass); ! 345: SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); ! 346: ! 347: k->init = exynos4210_gic_init; ! 348: dc->props = exynos4210_gic_properties; ! 349: } ! 350: ! 351: static TypeInfo exynos4210_gic_info = { ! 352: .name = "exynos4210.gic", ! 353: .parent = TYPE_SYS_BUS_DEVICE, ! 354: .instance_size = sizeof(Exynos4210GicState), ! 355: .class_init = exynos4210_gic_class_init, ! 356: }; ! 357: ! 358: static void exynos4210_gic_register_types(void) ! 359: { ! 360: type_register_static(&exynos4210_gic_info); ! 361: } ! 362: ! 363: type_init(exynos4210_gic_register_types) ! 364: ! 365: /* ! 366: * IRQGate struct. ! 367: * IRQ Gate represents OR gate between GICs to pass IRQ to PIC. ! 368: */ ! 369: typedef struct { ! 370: SysBusDevice busdev; ! 371: ! 372: qemu_irq pic_irq[EXYNOS4210_NCPUS]; /* output IRQs to PICs */ ! 373: uint32_t gpio_level[EXYNOS4210_IRQ_GATE_NINPUTS]; /* Input levels */ ! 374: } Exynos4210IRQGateState; ! 375: ! 376: static const VMStateDescription vmstate_exynos4210_irq_gate = { ! 377: .name = "exynos4210.irq_gate", ! 378: .version_id = 1, ! 379: .minimum_version_id = 1, ! 380: .minimum_version_id_old = 1, ! 381: .fields = (VMStateField[]) { ! 382: VMSTATE_UINT32_ARRAY(gpio_level, Exynos4210IRQGateState, ! 383: EXYNOS4210_IRQ_GATE_NINPUTS), ! 384: VMSTATE_END_OF_LIST() ! 385: } ! 386: }; ! 387: ! 388: /* Process a change in an external IRQ input. */ ! 389: static void exynos4210_irq_gate_handler(void *opaque, int irq, int level) ! 390: { ! 391: Exynos4210IRQGateState *s = ! 392: (Exynos4210IRQGateState *)opaque; ! 393: uint32_t odd, even; ! 394: ! 395: if (irq & 1) { ! 396: odd = irq; ! 397: even = irq & ~1; ! 398: } else { ! 399: even = irq; ! 400: odd = irq | 1; ! 401: } ! 402: ! 403: assert(irq < EXYNOS4210_IRQ_GATE_NINPUTS); ! 404: s->gpio_level[irq] = level; ! 405: ! 406: if (s->gpio_level[odd] >= 1 || s->gpio_level[even] >= 1) { ! 407: qemu_irq_raise(s->pic_irq[even >> 1]); ! 408: } else { ! 409: qemu_irq_lower(s->pic_irq[even >> 1]); ! 410: } ! 411: ! 412: return; ! 413: } ! 414: ! 415: static void exynos4210_irq_gate_reset(DeviceState *d) ! 416: { ! 417: Exynos4210IRQGateState *s = (Exynos4210IRQGateState *)d; ! 418: ! 419: memset(&s->gpio_level, 0, sizeof(s->gpio_level)); ! 420: } ! 421: ! 422: /* ! 423: * IRQ Gate initialization. ! 424: */ ! 425: static int exynos4210_irq_gate_init(SysBusDevice *dev) ! 426: { ! 427: unsigned int i; ! 428: Exynos4210IRQGateState *s = ! 429: FROM_SYSBUS(Exynos4210IRQGateState, dev); ! 430: ! 431: /* Allocate general purpose input signals and connect a handler to each of ! 432: * them */ ! 433: qdev_init_gpio_in(&s->busdev.qdev, exynos4210_irq_gate_handler, ! 434: EXYNOS4210_IRQ_GATE_NINPUTS); ! 435: ! 436: /* Connect SysBusDev irqs to device specific irqs */ ! 437: for (i = 0; i < EXYNOS4210_NCPUS; i++) { ! 438: sysbus_init_irq(dev, &s->pic_irq[i]); ! 439: } ! 440: ! 441: return 0; ! 442: } ! 443: ! 444: static void exynos4210_irq_gate_class_init(ObjectClass *klass, void *data) ! 445: { ! 446: DeviceClass *dc = DEVICE_CLASS(klass); ! 447: SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); ! 448: ! 449: k->init = exynos4210_irq_gate_init; ! 450: dc->reset = exynos4210_irq_gate_reset; ! 451: dc->vmsd = &vmstate_exynos4210_irq_gate; ! 452: } ! 453: ! 454: static TypeInfo exynos4210_irq_gate_info = { ! 455: .name = "exynos4210.irq_gate", ! 456: .parent = TYPE_SYS_BUS_DEVICE, ! 457: .instance_size = sizeof(Exynos4210IRQGateState), ! 458: .class_init = exynos4210_irq_gate_class_init, ! 459: }; ! 460: ! 461: static void exynos4210_irq_gate_register_types(void) ! 462: { ! 463: type_register_static(&exynos4210_irq_gate_info); ! 464: } ! 465: ! 466: type_init(exynos4210_irq_gate_register_types)
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.