mpcore.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. /*
  2. * ARM MPCore internal peripheral emulation (common code).
  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. #define NCPU 4
  12. static inline int
  13. gic_get_current_cpu(void)
  14. {
  15. return cpu_single_env->cpu_index;
  16. }
  17. #include "arm_gic.c"
  18. /* MPCore private memory region. */
  19. typedef struct {
  20. uint32_t count;
  21. uint32_t load;
  22. uint32_t control;
  23. uint32_t status;
  24. uint32_t old_status;
  25. int64_t tick;
  26. QEMUTimer *timer;
  27. struct mpcore_priv_state *mpcore;
  28. int id; /* Encodes both timer/watchdog and CPU. */
  29. } mpcore_timer_state;
  30. typedef struct mpcore_priv_state {
  31. gic_state gic;
  32. uint32_t scu_control;
  33. int iomemtype;
  34. mpcore_timer_state timer[8];
  35. uint32_t num_cpu;
  36. MemoryRegion iomem;
  37. MemoryRegion container;
  38. } mpcore_priv_state;
  39. /* Per-CPU Timers. */
  40. static inline void mpcore_timer_update_irq(mpcore_timer_state *s)
  41. {
  42. if (s->status & ~s->old_status) {
  43. gic_set_pending_private(&s->mpcore->gic, s->id >> 1, 29 + (s->id & 1));
  44. }
  45. s->old_status = s->status;
  46. }
  47. /* Return conversion factor from mpcore timer ticks to qemu timer ticks. */
  48. static inline uint32_t mpcore_timer_scale(mpcore_timer_state *s)
  49. {
  50. return (((s->control >> 8) & 0xff) + 1) * 10;
  51. }
  52. static void mpcore_timer_reload(mpcore_timer_state *s, int restart)
  53. {
  54. if (s->count == 0)
  55. return;
  56. if (restart)
  57. s->tick = qemu_get_clock_ns(vm_clock);
  58. s->tick += (int64_t)s->count * mpcore_timer_scale(s);
  59. qemu_mod_timer(s->timer, s->tick);
  60. }
  61. static void mpcore_timer_tick(void *opaque)
  62. {
  63. mpcore_timer_state *s = (mpcore_timer_state *)opaque;
  64. s->status = 1;
  65. if (s->control & 2) {
  66. s->count = s->load;
  67. mpcore_timer_reload(s, 0);
  68. } else {
  69. s->count = 0;
  70. }
  71. mpcore_timer_update_irq(s);
  72. }
  73. static uint32_t mpcore_timer_read(mpcore_timer_state *s, int offset)
  74. {
  75. int64_t val;
  76. switch (offset) {
  77. case 0: /* Load */
  78. return s->load;
  79. /* Fall through. */
  80. case 4: /* Counter. */
  81. if (((s->control & 1) == 0) || (s->count == 0))
  82. return 0;
  83. /* Slow and ugly, but hopefully won't happen too often. */
  84. val = s->tick - qemu_get_clock_ns(vm_clock);
  85. val /= mpcore_timer_scale(s);
  86. if (val < 0)
  87. val = 0;
  88. return val;
  89. case 8: /* Control. */
  90. return s->control;
  91. case 12: /* Interrupt status. */
  92. return s->status;
  93. default:
  94. return 0;
  95. }
  96. }
  97. static void mpcore_timer_write(mpcore_timer_state *s, int offset,
  98. uint32_t value)
  99. {
  100. int64_t old;
  101. switch (offset) {
  102. case 0: /* Load */
  103. s->load = value;
  104. /* Fall through. */
  105. case 4: /* Counter. */
  106. if ((s->control & 1) && s->count) {
  107. /* Cancel the previous timer. */
  108. qemu_del_timer(s->timer);
  109. }
  110. s->count = value;
  111. if (s->control & 1) {
  112. mpcore_timer_reload(s, 1);
  113. }
  114. break;
  115. case 8: /* Control. */
  116. old = s->control;
  117. s->control = value;
  118. if (((old & 1) == 0) && (value & 1)) {
  119. if (s->count == 0 && (s->control & 2))
  120. s->count = s->load;
  121. mpcore_timer_reload(s, 1);
  122. }
  123. break;
  124. case 12: /* Interrupt status. */
  125. s->status &= ~value;
  126. mpcore_timer_update_irq(s);
  127. break;
  128. }
  129. }
  130. static void mpcore_timer_init(mpcore_priv_state *mpcore,
  131. mpcore_timer_state *s, int id)
  132. {
  133. s->id = id;
  134. s->mpcore = mpcore;
  135. s->timer = qemu_new_timer_ns(vm_clock, mpcore_timer_tick, s);
  136. }
  137. /* Per-CPU private memory mapped IO. */
  138. static uint64_t mpcore_priv_read(void *opaque, target_phys_addr_t offset,
  139. unsigned size)
  140. {
  141. mpcore_priv_state *s = (mpcore_priv_state *)opaque;
  142. int id;
  143. offset &= 0xfff;
  144. if (offset < 0x100) {
  145. /* SCU */
  146. switch (offset) {
  147. case 0x00: /* Control. */
  148. return s->scu_control;
  149. case 0x04: /* Configuration. */
  150. id = ((1 << s->num_cpu) - 1) << 4;
  151. return id | (s->num_cpu - 1);
  152. case 0x08: /* CPU status. */
  153. return 0;
  154. case 0x0c: /* Invalidate all. */
  155. return 0;
  156. default:
  157. goto bad_reg;
  158. }
  159. } else if (offset < 0x600) {
  160. /* Interrupt controller. */
  161. if (offset < 0x200) {
  162. id = gic_get_current_cpu();
  163. } else {
  164. id = (offset - 0x200) >> 8;
  165. if (id >= s->num_cpu) {
  166. return 0;
  167. }
  168. }
  169. return gic_cpu_read(&s->gic, id, offset & 0xff);
  170. } else if (offset < 0xb00) {
  171. /* Timers. */
  172. if (offset < 0x700) {
  173. id = gic_get_current_cpu();
  174. } else {
  175. id = (offset - 0x700) >> 8;
  176. if (id >= s->num_cpu) {
  177. return 0;
  178. }
  179. }
  180. id <<= 1;
  181. if (offset & 0x20)
  182. id++;
  183. return mpcore_timer_read(&s->timer[id], offset & 0xf);
  184. }
  185. bad_reg:
  186. hw_error("mpcore_priv_read: Bad offset %x\n", (int)offset);
  187. return 0;
  188. }
  189. static void mpcore_priv_write(void *opaque, target_phys_addr_t offset,
  190. uint64_t value, unsigned size)
  191. {
  192. mpcore_priv_state *s = (mpcore_priv_state *)opaque;
  193. int id;
  194. offset &= 0xfff;
  195. if (offset < 0x100) {
  196. /* SCU */
  197. switch (offset) {
  198. case 0: /* Control register. */
  199. s->scu_control = value & 1;
  200. break;
  201. case 0x0c: /* Invalidate all. */
  202. /* This is a no-op as cache is not emulated. */
  203. break;
  204. default:
  205. goto bad_reg;
  206. }
  207. } else if (offset < 0x600) {
  208. /* Interrupt controller. */
  209. if (offset < 0x200) {
  210. id = gic_get_current_cpu();
  211. } else {
  212. id = (offset - 0x200) >> 8;
  213. }
  214. if (id < s->num_cpu) {
  215. gic_cpu_write(&s->gic, id, offset & 0xff, value);
  216. }
  217. } else if (offset < 0xb00) {
  218. /* Timers. */
  219. if (offset < 0x700) {
  220. id = gic_get_current_cpu();
  221. } else {
  222. id = (offset - 0x700) >> 8;
  223. }
  224. if (id < s->num_cpu) {
  225. id <<= 1;
  226. if (offset & 0x20)
  227. id++;
  228. mpcore_timer_write(&s->timer[id], offset & 0xf, value);
  229. }
  230. return;
  231. }
  232. return;
  233. bad_reg:
  234. hw_error("mpcore_priv_read: Bad offset %x\n", (int)offset);
  235. }
  236. static const MemoryRegionOps mpcore_priv_ops = {
  237. .read = mpcore_priv_read,
  238. .write = mpcore_priv_write,
  239. .endianness = DEVICE_NATIVE_ENDIAN,
  240. };
  241. static void mpcore_priv_map_setup(mpcore_priv_state *s)
  242. {
  243. memory_region_init(&s->container, "mpcode-priv-container", 0x2000);
  244. memory_region_init_io(&s->iomem, &mpcore_priv_ops, s, "mpcode-priv",
  245. 0x1000);
  246. memory_region_add_subregion(&s->container, 0, &s->iomem);
  247. memory_region_add_subregion(&s->container, 0x1000, &s->gic.iomem);
  248. }
  249. static int mpcore_priv_init(SysBusDevice *dev)
  250. {
  251. mpcore_priv_state *s = FROM_SYSBUSGIC(mpcore_priv_state, dev);
  252. int i;
  253. gic_init(&s->gic, s->num_cpu);
  254. mpcore_priv_map_setup(s);
  255. sysbus_init_mmio_region(dev, &s->container);
  256. for (i = 0; i < s->num_cpu * 2; i++) {
  257. mpcore_timer_init(s, &s->timer[i], i);
  258. }
  259. return 0;
  260. }