2
0

a9mpcore.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. /*
  2. * Cortex-A9MPCore internal peripheral emulation.
  3. *
  4. * Copyright (c) 2009 CodeSourcery.
  5. * Copyright (c) 2011 Linaro Limited.
  6. * Written by Paul Brook, Peter Maydell.
  7. *
  8. * This code is licensed under the GPL.
  9. */
  10. #include "qemu/osdep.h"
  11. #include "qapi/error.h"
  12. #include "qemu/module.h"
  13. #include "hw/cpu/a9mpcore.h"
  14. #include "hw/irq.h"
  15. #include "hw/qdev-properties.h"
  16. #include "hw/core/cpu.h"
  17. static void a9mp_priv_set_irq(void *opaque, int irq, int level)
  18. {
  19. A9MPPrivState *s = (A9MPPrivState *)opaque;
  20. qemu_set_irq(qdev_get_gpio_in(DEVICE(&s->gic), irq), level);
  21. }
  22. static void a9mp_priv_initfn(Object *obj)
  23. {
  24. A9MPPrivState *s = A9MPCORE_PRIV(obj);
  25. memory_region_init(&s->container, obj, "a9mp-priv-container", 0x2000);
  26. sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->container);
  27. sysbus_init_child_obj(obj, "scu", &s->scu, sizeof(s->scu), TYPE_A9_SCU);
  28. sysbus_init_child_obj(obj, "gic", &s->gic, sizeof(s->gic), TYPE_ARM_GIC);
  29. sysbus_init_child_obj(obj, "gtimer", &s->gtimer, sizeof(s->gtimer),
  30. TYPE_A9_GTIMER);
  31. sysbus_init_child_obj(obj, "mptimer", &s->mptimer, sizeof(s->mptimer),
  32. TYPE_ARM_MPTIMER);
  33. sysbus_init_child_obj(obj, "wdt", &s->wdt, sizeof(s->wdt),
  34. TYPE_ARM_MPTIMER);
  35. }
  36. static void a9mp_priv_realize(DeviceState *dev, Error **errp)
  37. {
  38. SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
  39. A9MPPrivState *s = A9MPCORE_PRIV(dev);
  40. DeviceState *scudev, *gicdev, *gtimerdev, *mptimerdev, *wdtdev;
  41. SysBusDevice *scubusdev, *gicbusdev, *gtimerbusdev, *mptimerbusdev,
  42. *wdtbusdev;
  43. Error *err = NULL;
  44. int i;
  45. bool has_el3;
  46. Object *cpuobj;
  47. scudev = DEVICE(&s->scu);
  48. qdev_prop_set_uint32(scudev, "num-cpu", s->num_cpu);
  49. object_property_set_bool(OBJECT(&s->scu), true, "realized", &err);
  50. if (err != NULL) {
  51. error_propagate(errp, err);
  52. return;
  53. }
  54. scubusdev = SYS_BUS_DEVICE(&s->scu);
  55. gicdev = DEVICE(&s->gic);
  56. qdev_prop_set_uint32(gicdev, "num-cpu", s->num_cpu);
  57. qdev_prop_set_uint32(gicdev, "num-irq", s->num_irq);
  58. /* Make the GIC's TZ support match the CPUs. We assume that
  59. * either all the CPUs have TZ, or none do.
  60. */
  61. cpuobj = OBJECT(qemu_get_cpu(0));
  62. has_el3 = object_property_find(cpuobj, "has_el3", NULL) &&
  63. object_property_get_bool(cpuobj, "has_el3", &error_abort);
  64. qdev_prop_set_bit(gicdev, "has-security-extensions", has_el3);
  65. object_property_set_bool(OBJECT(&s->gic), true, "realized", &err);
  66. if (err != NULL) {
  67. error_propagate(errp, err);
  68. return;
  69. }
  70. gicbusdev = SYS_BUS_DEVICE(&s->gic);
  71. /* Pass through outbound IRQ lines from the GIC */
  72. sysbus_pass_irq(sbd, gicbusdev);
  73. /* Pass through inbound GPIO lines to the GIC */
  74. qdev_init_gpio_in(dev, a9mp_priv_set_irq, s->num_irq - 32);
  75. gtimerdev = DEVICE(&s->gtimer);
  76. qdev_prop_set_uint32(gtimerdev, "num-cpu", s->num_cpu);
  77. object_property_set_bool(OBJECT(&s->gtimer), true, "realized", &err);
  78. if (err != NULL) {
  79. error_propagate(errp, err);
  80. return;
  81. }
  82. gtimerbusdev = SYS_BUS_DEVICE(&s->gtimer);
  83. mptimerdev = DEVICE(&s->mptimer);
  84. qdev_prop_set_uint32(mptimerdev, "num-cpu", s->num_cpu);
  85. object_property_set_bool(OBJECT(&s->mptimer), true, "realized", &err);
  86. if (err != NULL) {
  87. error_propagate(errp, err);
  88. return;
  89. }
  90. mptimerbusdev = SYS_BUS_DEVICE(&s->mptimer);
  91. wdtdev = DEVICE(&s->wdt);
  92. qdev_prop_set_uint32(wdtdev, "num-cpu", s->num_cpu);
  93. object_property_set_bool(OBJECT(&s->wdt), true, "realized", &err);
  94. if (err != NULL) {
  95. error_propagate(errp, err);
  96. return;
  97. }
  98. wdtbusdev = SYS_BUS_DEVICE(&s->wdt);
  99. /* Memory map (addresses are offsets from PERIPHBASE):
  100. * 0x0000-0x00ff -- Snoop Control Unit
  101. * 0x0100-0x01ff -- GIC CPU interface
  102. * 0x0200-0x02ff -- Global Timer
  103. * 0x0300-0x05ff -- nothing
  104. * 0x0600-0x06ff -- private timers and watchdogs
  105. * 0x0700-0x0fff -- nothing
  106. * 0x1000-0x1fff -- GIC Distributor
  107. */
  108. memory_region_add_subregion(&s->container, 0,
  109. sysbus_mmio_get_region(scubusdev, 0));
  110. /* GIC CPU interface */
  111. memory_region_add_subregion(&s->container, 0x100,
  112. sysbus_mmio_get_region(gicbusdev, 1));
  113. memory_region_add_subregion(&s->container, 0x200,
  114. sysbus_mmio_get_region(gtimerbusdev, 0));
  115. /* Note that the A9 exposes only the "timer/watchdog for this core"
  116. * memory region, not the "timer/watchdog for core X" ones 11MPcore has.
  117. */
  118. memory_region_add_subregion(&s->container, 0x600,
  119. sysbus_mmio_get_region(mptimerbusdev, 0));
  120. memory_region_add_subregion(&s->container, 0x620,
  121. sysbus_mmio_get_region(wdtbusdev, 0));
  122. memory_region_add_subregion(&s->container, 0x1000,
  123. sysbus_mmio_get_region(gicbusdev, 0));
  124. /* Wire up the interrupt from each watchdog and timer.
  125. * For each core the global timer is PPI 27, the private
  126. * timer is PPI 29 and the watchdog PPI 30.
  127. */
  128. for (i = 0; i < s->num_cpu; i++) {
  129. int ppibase = (s->num_irq - 32) + i * 32;
  130. sysbus_connect_irq(gtimerbusdev, i,
  131. qdev_get_gpio_in(gicdev, ppibase + 27));
  132. sysbus_connect_irq(mptimerbusdev, i,
  133. qdev_get_gpio_in(gicdev, ppibase + 29));
  134. sysbus_connect_irq(wdtbusdev, i,
  135. qdev_get_gpio_in(gicdev, ppibase + 30));
  136. }
  137. }
  138. static Property a9mp_priv_properties[] = {
  139. DEFINE_PROP_UINT32("num-cpu", A9MPPrivState, num_cpu, 1),
  140. /* The Cortex-A9MP may have anything from 0 to 224 external interrupt
  141. * IRQ lines (with another 32 internal). We default to 64+32, which
  142. * is the number provided by the Cortex-A9MP test chip in the
  143. * Realview PBX-A9 and Versatile Express A9 development boards.
  144. * Other boards may differ and should set this property appropriately.
  145. */
  146. DEFINE_PROP_UINT32("num-irq", A9MPPrivState, num_irq, 96),
  147. DEFINE_PROP_END_OF_LIST(),
  148. };
  149. static void a9mp_priv_class_init(ObjectClass *klass, void *data)
  150. {
  151. DeviceClass *dc = DEVICE_CLASS(klass);
  152. dc->realize = a9mp_priv_realize;
  153. dc->props = a9mp_priv_properties;
  154. }
  155. static const TypeInfo a9mp_priv_info = {
  156. .name = TYPE_A9MPCORE_PRIV,
  157. .parent = TYPE_SYS_BUS_DEVICE,
  158. .instance_size = sizeof(A9MPPrivState),
  159. .instance_init = a9mp_priv_initfn,
  160. .class_init = a9mp_priv_class_init,
  161. };
  162. static void a9mp_register_types(void)
  163. {
  164. type_register_static(&a9mp_priv_info);
  165. }
  166. type_init(a9mp_register_types)