2
0

a9mpcore.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  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 "sysbus.h"
  11. /* A9MP private memory region. */
  12. typedef struct a9mp_priv_state {
  13. SysBusDevice busdev;
  14. uint32_t scu_control;
  15. uint32_t scu_status;
  16. uint32_t old_timer_status[8];
  17. uint32_t num_cpu;
  18. MemoryRegion scu_iomem;
  19. MemoryRegion container;
  20. DeviceState *mptimer;
  21. DeviceState *gic;
  22. uint32_t num_irq;
  23. } a9mp_priv_state;
  24. static uint64_t a9_scu_read(void *opaque, hwaddr offset,
  25. unsigned size)
  26. {
  27. a9mp_priv_state *s = (a9mp_priv_state *)opaque;
  28. switch (offset) {
  29. case 0x00: /* Control */
  30. return s->scu_control;
  31. case 0x04: /* Configuration */
  32. return (((1 << s->num_cpu) - 1) << 4) | (s->num_cpu - 1);
  33. case 0x08: /* CPU Power Status */
  34. return s->scu_status;
  35. case 0x09: /* CPU status. */
  36. return s->scu_status >> 8;
  37. case 0x0a: /* CPU status. */
  38. return s->scu_status >> 16;
  39. case 0x0b: /* CPU status. */
  40. return s->scu_status >> 24;
  41. case 0x0c: /* Invalidate All Registers In Secure State */
  42. return 0;
  43. case 0x40: /* Filtering Start Address Register */
  44. case 0x44: /* Filtering End Address Register */
  45. /* RAZ/WI, like an implementation with only one AXI master */
  46. return 0;
  47. case 0x50: /* SCU Access Control Register */
  48. case 0x54: /* SCU Non-secure Access Control Register */
  49. /* unimplemented, fall through */
  50. default:
  51. return 0;
  52. }
  53. }
  54. static void a9_scu_write(void *opaque, hwaddr offset,
  55. uint64_t value, unsigned size)
  56. {
  57. a9mp_priv_state *s = (a9mp_priv_state *)opaque;
  58. uint32_t mask;
  59. uint32_t shift;
  60. switch (size) {
  61. case 1:
  62. mask = 0xff;
  63. break;
  64. case 2:
  65. mask = 0xffff;
  66. break;
  67. case 4:
  68. mask = 0xffffffff;
  69. break;
  70. default:
  71. fprintf(stderr, "Invalid size %u in write to a9 scu register %x\n",
  72. size, (unsigned)offset);
  73. return;
  74. }
  75. switch (offset) {
  76. case 0x00: /* Control */
  77. s->scu_control = value & 1;
  78. break;
  79. case 0x4: /* Configuration: RO */
  80. break;
  81. case 0x08: case 0x09: case 0x0A: case 0x0B: /* Power Control */
  82. shift = (offset - 0x8) * 8;
  83. s->scu_status &= ~(mask << shift);
  84. s->scu_status |= ((value & mask) << shift);
  85. break;
  86. case 0x0c: /* Invalidate All Registers In Secure State */
  87. /* no-op as we do not implement caches */
  88. break;
  89. case 0x40: /* Filtering Start Address Register */
  90. case 0x44: /* Filtering End Address Register */
  91. /* RAZ/WI, like an implementation with only one AXI master */
  92. break;
  93. case 0x50: /* SCU Access Control Register */
  94. case 0x54: /* SCU Non-secure Access Control Register */
  95. /* unimplemented, fall through */
  96. default:
  97. break;
  98. }
  99. }
  100. static const MemoryRegionOps a9_scu_ops = {
  101. .read = a9_scu_read,
  102. .write = a9_scu_write,
  103. .endianness = DEVICE_NATIVE_ENDIAN,
  104. };
  105. static void a9mp_priv_reset(DeviceState *dev)
  106. {
  107. a9mp_priv_state *s = FROM_SYSBUS(a9mp_priv_state, SYS_BUS_DEVICE(dev));
  108. int i;
  109. s->scu_control = 0;
  110. for (i = 0; i < ARRAY_SIZE(s->old_timer_status); i++) {
  111. s->old_timer_status[i] = 0;
  112. }
  113. }
  114. static void a9mp_priv_set_irq(void *opaque, int irq, int level)
  115. {
  116. a9mp_priv_state *s = (a9mp_priv_state *)opaque;
  117. qemu_set_irq(qdev_get_gpio_in(s->gic, irq), level);
  118. }
  119. static int a9mp_priv_init(SysBusDevice *dev)
  120. {
  121. a9mp_priv_state *s = FROM_SYSBUS(a9mp_priv_state, dev);
  122. SysBusDevice *busdev, *gicbusdev;
  123. int i;
  124. s->gic = qdev_create(NULL, "arm_gic");
  125. qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu);
  126. qdev_prop_set_uint32(s->gic, "num-irq", s->num_irq);
  127. qdev_init_nofail(s->gic);
  128. gicbusdev = SYS_BUS_DEVICE(s->gic);
  129. /* Pass through outbound IRQ lines from the GIC */
  130. sysbus_pass_irq(dev, gicbusdev);
  131. /* Pass through inbound GPIO lines to the GIC */
  132. qdev_init_gpio_in(&s->busdev.qdev, a9mp_priv_set_irq, s->num_irq - 32);
  133. s->mptimer = qdev_create(NULL, "arm_mptimer");
  134. qdev_prop_set_uint32(s->mptimer, "num-cpu", s->num_cpu);
  135. qdev_init_nofail(s->mptimer);
  136. busdev = SYS_BUS_DEVICE(s->mptimer);
  137. /* Memory map (addresses are offsets from PERIPHBASE):
  138. * 0x0000-0x00ff -- Snoop Control Unit
  139. * 0x0100-0x01ff -- GIC CPU interface
  140. * 0x0200-0x02ff -- Global Timer
  141. * 0x0300-0x05ff -- nothing
  142. * 0x0600-0x06ff -- private timers and watchdogs
  143. * 0x0700-0x0fff -- nothing
  144. * 0x1000-0x1fff -- GIC Distributor
  145. *
  146. * We should implement the global timer but don't currently do so.
  147. */
  148. memory_region_init(&s->container, "a9mp-priv-container", 0x2000);
  149. memory_region_init_io(&s->scu_iomem, &a9_scu_ops, s, "a9mp-scu", 0x100);
  150. memory_region_add_subregion(&s->container, 0, &s->scu_iomem);
  151. /* GIC CPU interface */
  152. memory_region_add_subregion(&s->container, 0x100,
  153. sysbus_mmio_get_region(gicbusdev, 1));
  154. /* Note that the A9 exposes only the "timer/watchdog for this core"
  155. * memory region, not the "timer/watchdog for core X" ones 11MPcore has.
  156. */
  157. memory_region_add_subregion(&s->container, 0x600,
  158. sysbus_mmio_get_region(busdev, 0));
  159. memory_region_add_subregion(&s->container, 0x620,
  160. sysbus_mmio_get_region(busdev, 1));
  161. memory_region_add_subregion(&s->container, 0x1000,
  162. sysbus_mmio_get_region(gicbusdev, 0));
  163. sysbus_init_mmio(dev, &s->container);
  164. /* Wire up the interrupt from each watchdog and timer.
  165. * For each core the timer is PPI 29 and the watchdog PPI 30.
  166. */
  167. for (i = 0; i < s->num_cpu; i++) {
  168. int ppibase = (s->num_irq - 32) + i * 32;
  169. sysbus_connect_irq(busdev, i * 2,
  170. qdev_get_gpio_in(s->gic, ppibase + 29));
  171. sysbus_connect_irq(busdev, i * 2 + 1,
  172. qdev_get_gpio_in(s->gic, ppibase + 30));
  173. }
  174. return 0;
  175. }
  176. static const VMStateDescription vmstate_a9mp_priv = {
  177. .name = "a9mpcore_priv",
  178. .version_id = 2,
  179. .minimum_version_id = 1,
  180. .fields = (VMStateField[]) {
  181. VMSTATE_UINT32(scu_control, a9mp_priv_state),
  182. VMSTATE_UINT32_ARRAY(old_timer_status, a9mp_priv_state, 8),
  183. VMSTATE_UINT32_V(scu_status, a9mp_priv_state, 2),
  184. VMSTATE_END_OF_LIST()
  185. }
  186. };
  187. static Property a9mp_priv_properties[] = {
  188. DEFINE_PROP_UINT32("num-cpu", a9mp_priv_state, num_cpu, 1),
  189. /* The Cortex-A9MP may have anything from 0 to 224 external interrupt
  190. * IRQ lines (with another 32 internal). We default to 64+32, which
  191. * is the number provided by the Cortex-A9MP test chip in the
  192. * Realview PBX-A9 and Versatile Express A9 development boards.
  193. * Other boards may differ and should set this property appropriately.
  194. */
  195. DEFINE_PROP_UINT32("num-irq", a9mp_priv_state, num_irq, 96),
  196. DEFINE_PROP_END_OF_LIST(),
  197. };
  198. static void a9mp_priv_class_init(ObjectClass *klass, void *data)
  199. {
  200. DeviceClass *dc = DEVICE_CLASS(klass);
  201. SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
  202. k->init = a9mp_priv_init;
  203. dc->props = a9mp_priv_properties;
  204. dc->vmsd = &vmstate_a9mp_priv;
  205. dc->reset = a9mp_priv_reset;
  206. }
  207. static const TypeInfo a9mp_priv_info = {
  208. .name = "a9mpcore_priv",
  209. .parent = TYPE_SYS_BUS_DEVICE,
  210. .instance_size = sizeof(a9mp_priv_state),
  211. .class_init = a9mp_priv_class_init,
  212. };
  213. static void a9mp_register_types(void)
  214. {
  215. type_register_static(&a9mp_priv_info);
  216. }
  217. type_init(a9mp_register_types)