arm11mpcore.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. /*
  2. * ARM11MPCore internal peripheral emulation.
  3. *
  4. * Copyright (c) 2006-2007 CodeSourcery.
  5. * Written by Paul Brook
  6. *
  7. * This code is licensed under the GPL.
  8. */
  9. #include "sysbus.h"
  10. #include "qemu/timer.h"
  11. /* MPCore private memory region. */
  12. typedef struct mpcore_priv_state {
  13. SysBusDevice busdev;
  14. uint32_t scu_control;
  15. int iomemtype;
  16. uint32_t old_timer_status[8];
  17. uint32_t num_cpu;
  18. MemoryRegion iomem;
  19. MemoryRegion container;
  20. DeviceState *mptimer;
  21. DeviceState *gic;
  22. uint32_t num_irq;
  23. } mpcore_priv_state;
  24. /* Per-CPU private memory mapped IO. */
  25. static uint64_t mpcore_scu_read(void *opaque, hwaddr offset,
  26. unsigned size)
  27. {
  28. mpcore_priv_state *s = (mpcore_priv_state *)opaque;
  29. int id;
  30. /* SCU */
  31. switch (offset) {
  32. case 0x00: /* Control. */
  33. return s->scu_control;
  34. case 0x04: /* Configuration. */
  35. id = ((1 << s->num_cpu) - 1) << 4;
  36. return id | (s->num_cpu - 1);
  37. case 0x08: /* CPU status. */
  38. return 0;
  39. case 0x0c: /* Invalidate all. */
  40. return 0;
  41. default:
  42. qemu_log_mask(LOG_GUEST_ERROR,
  43. "mpcore_priv_read: Bad offset %x\n", (int)offset);
  44. return 0;
  45. }
  46. }
  47. static void mpcore_scu_write(void *opaque, hwaddr offset,
  48. uint64_t value, unsigned size)
  49. {
  50. mpcore_priv_state *s = (mpcore_priv_state *)opaque;
  51. /* SCU */
  52. switch (offset) {
  53. case 0: /* Control register. */
  54. s->scu_control = value & 1;
  55. break;
  56. case 0x0c: /* Invalidate all. */
  57. /* This is a no-op as cache is not emulated. */
  58. break;
  59. default:
  60. qemu_log_mask(LOG_GUEST_ERROR,
  61. "mpcore_priv_read: Bad offset %x\n", (int)offset);
  62. }
  63. }
  64. static const MemoryRegionOps mpcore_scu_ops = {
  65. .read = mpcore_scu_read,
  66. .write = mpcore_scu_write,
  67. .endianness = DEVICE_NATIVE_ENDIAN,
  68. };
  69. static void mpcore_priv_set_irq(void *opaque, int irq, int level)
  70. {
  71. mpcore_priv_state *s = (mpcore_priv_state *)opaque;
  72. qemu_set_irq(qdev_get_gpio_in(s->gic, irq), level);
  73. }
  74. static void mpcore_priv_map_setup(mpcore_priv_state *s)
  75. {
  76. int i;
  77. SysBusDevice *gicbusdev = SYS_BUS_DEVICE(s->gic);
  78. SysBusDevice *busdev = SYS_BUS_DEVICE(s->mptimer);
  79. memory_region_init(&s->container, "mpcode-priv-container", 0x2000);
  80. memory_region_init_io(&s->iomem, &mpcore_scu_ops, s, "mpcore-scu", 0x100);
  81. memory_region_add_subregion(&s->container, 0, &s->iomem);
  82. /* GIC CPU interfaces: "current CPU" at 0x100, then specific CPUs
  83. * at 0x200, 0x300...
  84. */
  85. for (i = 0; i < (s->num_cpu + 1); i++) {
  86. hwaddr offset = 0x100 + (i * 0x100);
  87. memory_region_add_subregion(&s->container, offset,
  88. sysbus_mmio_get_region(gicbusdev, i + 1));
  89. }
  90. /* Add the regions for timer and watchdog for "current CPU" and
  91. * for each specific CPU.
  92. */
  93. for (i = 0; i < (s->num_cpu + 1) * 2; i++) {
  94. /* Timers at 0x600, 0x700, ...; watchdogs at 0x620, 0x720, ... */
  95. hwaddr offset = 0x600 + (i >> 1) * 0x100 + (i & 1) * 0x20;
  96. memory_region_add_subregion(&s->container, offset,
  97. sysbus_mmio_get_region(busdev, i));
  98. }
  99. memory_region_add_subregion(&s->container, 0x1000,
  100. sysbus_mmio_get_region(gicbusdev, 0));
  101. /* Wire up the interrupt from each watchdog and timer.
  102. * For each core the timer is PPI 29 and the watchdog PPI 30.
  103. */
  104. for (i = 0; i < s->num_cpu; i++) {
  105. int ppibase = (s->num_irq - 32) + i * 32;
  106. sysbus_connect_irq(busdev, i * 2,
  107. qdev_get_gpio_in(s->gic, ppibase + 29));
  108. sysbus_connect_irq(busdev, i * 2 + 1,
  109. qdev_get_gpio_in(s->gic, ppibase + 30));
  110. }
  111. }
  112. static int mpcore_priv_init(SysBusDevice *dev)
  113. {
  114. mpcore_priv_state *s = FROM_SYSBUS(mpcore_priv_state, dev);
  115. s->gic = qdev_create(NULL, "arm_gic");
  116. qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu);
  117. qdev_prop_set_uint32(s->gic, "num-irq", s->num_irq);
  118. /* Request the legacy 11MPCore GIC behaviour: */
  119. qdev_prop_set_uint32(s->gic, "revision", 0);
  120. qdev_init_nofail(s->gic);
  121. /* Pass through outbound IRQ lines from the GIC */
  122. sysbus_pass_irq(dev, SYS_BUS_DEVICE(s->gic));
  123. /* Pass through inbound GPIO lines to the GIC */
  124. qdev_init_gpio_in(&s->busdev.qdev, mpcore_priv_set_irq, s->num_irq - 32);
  125. s->mptimer = qdev_create(NULL, "arm_mptimer");
  126. qdev_prop_set_uint32(s->mptimer, "num-cpu", s->num_cpu);
  127. qdev_init_nofail(s->mptimer);
  128. mpcore_priv_map_setup(s);
  129. sysbus_init_mmio(dev, &s->container);
  130. return 0;
  131. }
  132. /* Dummy PIC to route IRQ lines. The baseboard has 4 independent IRQ
  133. controllers. The output of these, plus some of the raw input lines
  134. are fed into a single SMP-aware interrupt controller on the CPU. */
  135. typedef struct {
  136. SysBusDevice busdev;
  137. SysBusDevice *priv;
  138. qemu_irq cpuic[32];
  139. qemu_irq rvic[4][64];
  140. uint32_t num_cpu;
  141. } mpcore_rirq_state;
  142. /* Map baseboard IRQs onto CPU IRQ lines. */
  143. static const int mpcore_irq_map[32] = {
  144. -1, -1, -1, -1, 1, 2, -1, -1,
  145. -1, -1, 6, -1, 4, 5, -1, -1,
  146. -1, 14, 15, 0, 7, 8, -1, -1,
  147. -1, -1, -1, -1, 9, 3, -1, -1,
  148. };
  149. static void mpcore_rirq_set_irq(void *opaque, int irq, int level)
  150. {
  151. mpcore_rirq_state *s = (mpcore_rirq_state *)opaque;
  152. int i;
  153. for (i = 0; i < 4; i++) {
  154. qemu_set_irq(s->rvic[i][irq], level);
  155. }
  156. if (irq < 32) {
  157. irq = mpcore_irq_map[irq];
  158. if (irq >= 0) {
  159. qemu_set_irq(s->cpuic[irq], level);
  160. }
  161. }
  162. }
  163. static int realview_mpcore_init(SysBusDevice *dev)
  164. {
  165. mpcore_rirq_state *s = FROM_SYSBUS(mpcore_rirq_state, dev);
  166. DeviceState *gic;
  167. DeviceState *priv;
  168. int n;
  169. int i;
  170. priv = qdev_create(NULL, "arm11mpcore_priv");
  171. qdev_prop_set_uint32(priv, "num-cpu", s->num_cpu);
  172. qdev_init_nofail(priv);
  173. s->priv = SYS_BUS_DEVICE(priv);
  174. sysbus_pass_irq(dev, s->priv);
  175. for (i = 0; i < 32; i++) {
  176. s->cpuic[i] = qdev_get_gpio_in(priv, i);
  177. }
  178. /* ??? IRQ routing is hardcoded to "normal" mode. */
  179. for (n = 0; n < 4; n++) {
  180. gic = sysbus_create_simple("realview_gic", 0x10040000 + n * 0x10000,
  181. s->cpuic[10 + n]);
  182. for (i = 0; i < 64; i++) {
  183. s->rvic[n][i] = qdev_get_gpio_in(gic, i);
  184. }
  185. }
  186. qdev_init_gpio_in(&dev->qdev, mpcore_rirq_set_irq, 64);
  187. sysbus_init_mmio(dev, sysbus_mmio_get_region(s->priv, 0));
  188. return 0;
  189. }
  190. static Property mpcore_rirq_properties[] = {
  191. DEFINE_PROP_UINT32("num-cpu", mpcore_rirq_state, num_cpu, 1),
  192. DEFINE_PROP_END_OF_LIST(),
  193. };
  194. static void mpcore_rirq_class_init(ObjectClass *klass, void *data)
  195. {
  196. DeviceClass *dc = DEVICE_CLASS(klass);
  197. SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
  198. k->init = realview_mpcore_init;
  199. dc->props = mpcore_rirq_properties;
  200. }
  201. static const TypeInfo mpcore_rirq_info = {
  202. .name = "realview_mpcore",
  203. .parent = TYPE_SYS_BUS_DEVICE,
  204. .instance_size = sizeof(mpcore_rirq_state),
  205. .class_init = mpcore_rirq_class_init,
  206. };
  207. static Property mpcore_priv_properties[] = {
  208. DEFINE_PROP_UINT32("num-cpu", mpcore_priv_state, num_cpu, 1),
  209. /* The ARM11 MPCORE TRM says the on-chip controller may have
  210. * anything from 0 to 224 external interrupt IRQ lines (with another
  211. * 32 internal). We default to 32+32, which is the number provided by
  212. * the ARM11 MPCore test chip in the Realview Versatile Express
  213. * coretile. Other boards may differ and should set this property
  214. * appropriately. Some Linux kernels may not boot if the hardware
  215. * has more IRQ lines than the kernel expects.
  216. */
  217. DEFINE_PROP_UINT32("num-irq", mpcore_priv_state, num_irq, 64),
  218. DEFINE_PROP_END_OF_LIST(),
  219. };
  220. static void mpcore_priv_class_init(ObjectClass *klass, void *data)
  221. {
  222. DeviceClass *dc = DEVICE_CLASS(klass);
  223. SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
  224. k->init = mpcore_priv_init;
  225. dc->props = mpcore_priv_properties;
  226. }
  227. static const TypeInfo mpcore_priv_info = {
  228. .name = "arm11mpcore_priv",
  229. .parent = TYPE_SYS_BUS_DEVICE,
  230. .instance_size = sizeof(mpcore_priv_state),
  231. .class_init = mpcore_priv_class_init,
  232. };
  233. static void arm11mpcore_register_types(void)
  234. {
  235. type_register_static(&mpcore_rirq_info);
  236. type_register_static(&mpcore_priv_info);
  237. }
  238. type_init(arm11mpcore_register_types)