arm11mpcore.c 8.3 KB

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