mpcore.c 7.4 KB

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