arm_mptimer.c 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. /*
  2. * Private peripheral timer/watchdog blocks for ARM 11MPCore and A9MP
  3. *
  4. * Copyright (c) 2006-2007 CodeSourcery.
  5. * Copyright (c) 2011 Linaro Limited
  6. * Written by Paul Brook, Peter Maydell
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License
  10. * as published by the Free Software Foundation; either version
  11. * 2 of the License, or (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License along
  19. * with this program; if not, see <http://www.gnu.org/licenses/>.
  20. */
  21. #include "sysbus.h"
  22. #include "qemu-timer.h"
  23. /* This device implements the per-cpu private timer and watchdog block
  24. * which is used in both the ARM11MPCore and Cortex-A9MP.
  25. */
  26. #define MAX_CPUS 4
  27. /* State of a single timer or watchdog block */
  28. typedef struct {
  29. uint32_t count;
  30. uint32_t load;
  31. uint32_t control;
  32. uint32_t status;
  33. int64_t tick;
  34. QEMUTimer *timer;
  35. qemu_irq irq;
  36. MemoryRegion iomem;
  37. } timerblock;
  38. typedef struct {
  39. SysBusDevice busdev;
  40. uint32_t num_cpu;
  41. timerblock timerblock[MAX_CPUS * 2];
  42. MemoryRegion iomem[2];
  43. } arm_mptimer_state;
  44. static inline int get_current_cpu(arm_mptimer_state *s)
  45. {
  46. if (cpu_single_env->cpu_index >= s->num_cpu) {
  47. hw_error("arm_mptimer: num-cpu %d but this cpu is %d!\n",
  48. s->num_cpu, cpu_single_env->cpu_index);
  49. }
  50. return cpu_single_env->cpu_index;
  51. }
  52. static inline void timerblock_update_irq(timerblock *tb)
  53. {
  54. qemu_set_irq(tb->irq, tb->status);
  55. }
  56. /* Return conversion factor from mpcore timer ticks to qemu timer ticks. */
  57. static inline uint32_t timerblock_scale(timerblock *tb)
  58. {
  59. return (((tb->control >> 8) & 0xff) + 1) * 10;
  60. }
  61. static void timerblock_reload(timerblock *tb, int restart)
  62. {
  63. if (tb->count == 0) {
  64. return;
  65. }
  66. if (restart) {
  67. tb->tick = qemu_get_clock_ns(vm_clock);
  68. }
  69. tb->tick += (int64_t)tb->count * timerblock_scale(tb);
  70. qemu_mod_timer(tb->timer, tb->tick);
  71. }
  72. static void timerblock_tick(void *opaque)
  73. {
  74. timerblock *tb = (timerblock *)opaque;
  75. tb->status = 1;
  76. if (tb->control & 2) {
  77. tb->count = tb->load;
  78. timerblock_reload(tb, 0);
  79. } else {
  80. tb->count = 0;
  81. }
  82. timerblock_update_irq(tb);
  83. }
  84. static uint64_t timerblock_read(void *opaque, target_phys_addr_t addr,
  85. unsigned size)
  86. {
  87. timerblock *tb = (timerblock *)opaque;
  88. int64_t val;
  89. switch (addr) {
  90. case 0: /* Load */
  91. return tb->load;
  92. case 4: /* Counter. */
  93. if (((tb->control & 1) == 0) || (tb->count == 0)) {
  94. return 0;
  95. }
  96. /* Slow and ugly, but hopefully won't happen too often. */
  97. val = tb->tick - qemu_get_clock_ns(vm_clock);
  98. val /= timerblock_scale(tb);
  99. if (val < 0) {
  100. val = 0;
  101. }
  102. return val;
  103. case 8: /* Control. */
  104. return tb->control;
  105. case 12: /* Interrupt status. */
  106. return tb->status;
  107. default:
  108. return 0;
  109. }
  110. }
  111. static void timerblock_write(void *opaque, target_phys_addr_t addr,
  112. uint64_t value, unsigned size)
  113. {
  114. timerblock *tb = (timerblock *)opaque;
  115. int64_t old;
  116. switch (addr) {
  117. case 0: /* Load */
  118. tb->load = value;
  119. /* Fall through. */
  120. case 4: /* Counter. */
  121. if ((tb->control & 1) && tb->count) {
  122. /* Cancel the previous timer. */
  123. qemu_del_timer(tb->timer);
  124. }
  125. tb->count = value;
  126. if (tb->control & 1) {
  127. timerblock_reload(tb, 1);
  128. }
  129. break;
  130. case 8: /* Control. */
  131. old = tb->control;
  132. tb->control = value;
  133. if (((old & 1) == 0) && (value & 1)) {
  134. if (tb->count == 0 && (tb->control & 2)) {
  135. tb->count = tb->load;
  136. }
  137. timerblock_reload(tb, 1);
  138. }
  139. break;
  140. case 12: /* Interrupt status. */
  141. tb->status &= ~value;
  142. timerblock_update_irq(tb);
  143. break;
  144. }
  145. }
  146. /* Wrapper functions to implement the "read timer/watchdog for
  147. * the current CPU" memory regions.
  148. */
  149. static uint64_t arm_thistimer_read(void *opaque, target_phys_addr_t addr,
  150. unsigned size)
  151. {
  152. arm_mptimer_state *s = (arm_mptimer_state *)opaque;
  153. int id = get_current_cpu(s);
  154. return timerblock_read(&s->timerblock[id * 2], addr, size);
  155. }
  156. static void arm_thistimer_write(void *opaque, target_phys_addr_t addr,
  157. uint64_t value, unsigned size)
  158. {
  159. arm_mptimer_state *s = (arm_mptimer_state *)opaque;
  160. int id = get_current_cpu(s);
  161. timerblock_write(&s->timerblock[id * 2], addr, value, size);
  162. }
  163. static uint64_t arm_thiswdog_read(void *opaque, target_phys_addr_t addr,
  164. unsigned size)
  165. {
  166. arm_mptimer_state *s = (arm_mptimer_state *)opaque;
  167. int id = get_current_cpu(s);
  168. return timerblock_read(&s->timerblock[id * 2 + 1], addr, size);
  169. }
  170. static void arm_thiswdog_write(void *opaque, target_phys_addr_t addr,
  171. uint64_t value, unsigned size)
  172. {
  173. arm_mptimer_state *s = (arm_mptimer_state *)opaque;
  174. int id = get_current_cpu(s);
  175. timerblock_write(&s->timerblock[id * 2 + 1], addr, value, size);
  176. }
  177. static const MemoryRegionOps arm_thistimer_ops = {
  178. .read = arm_thistimer_read,
  179. .write = arm_thistimer_write,
  180. .valid = {
  181. .min_access_size = 4,
  182. .max_access_size = 4,
  183. },
  184. .endianness = DEVICE_NATIVE_ENDIAN,
  185. };
  186. static const MemoryRegionOps arm_thiswdog_ops = {
  187. .read = arm_thiswdog_read,
  188. .write = arm_thiswdog_write,
  189. .valid = {
  190. .min_access_size = 4,
  191. .max_access_size = 4,
  192. },
  193. .endianness = DEVICE_NATIVE_ENDIAN,
  194. };
  195. static const MemoryRegionOps timerblock_ops = {
  196. .read = timerblock_read,
  197. .write = timerblock_write,
  198. .valid = {
  199. .min_access_size = 4,
  200. .max_access_size = 4,
  201. },
  202. .endianness = DEVICE_NATIVE_ENDIAN,
  203. };
  204. static void timerblock_reset(timerblock *tb)
  205. {
  206. tb->count = 0;
  207. tb->load = 0;
  208. tb->control = 0;
  209. tb->status = 0;
  210. tb->tick = 0;
  211. if (tb->timer) {
  212. qemu_del_timer(tb->timer);
  213. }
  214. }
  215. static void arm_mptimer_reset(DeviceState *dev)
  216. {
  217. arm_mptimer_state *s =
  218. FROM_SYSBUS(arm_mptimer_state, sysbus_from_qdev(dev));
  219. int i;
  220. /* We reset every timer in the array, not just the ones we're using,
  221. * because vmsave will look at every array element.
  222. */
  223. for (i = 0; i < ARRAY_SIZE(s->timerblock); i++) {
  224. timerblock_reset(&s->timerblock[i]);
  225. }
  226. }
  227. static int arm_mptimer_init(SysBusDevice *dev)
  228. {
  229. arm_mptimer_state *s = FROM_SYSBUS(arm_mptimer_state, dev);
  230. int i;
  231. if (s->num_cpu < 1 || s->num_cpu > MAX_CPUS) {
  232. hw_error("%s: num-cpu must be between 1 and %d\n", __func__, MAX_CPUS);
  233. }
  234. /* We implement one timer and one watchdog block per CPU, and
  235. * expose multiple MMIO regions:
  236. * * region 0 is "timer for this core"
  237. * * region 1 is "watchdog for this core"
  238. * * region 2 is "timer for core 0"
  239. * * region 3 is "watchdog for core 0"
  240. * * region 4 is "timer for core 1"
  241. * * region 5 is "watchdog for core 1"
  242. * and so on.
  243. * The outgoing interrupt lines are
  244. * * timer for core 0
  245. * * watchdog for core 0
  246. * * timer for core 1
  247. * * watchdog for core 1
  248. * and so on.
  249. */
  250. memory_region_init_io(&s->iomem[0], &arm_thistimer_ops, s,
  251. "arm_mptimer_timer", 0x20);
  252. sysbus_init_mmio(dev, &s->iomem[0]);
  253. memory_region_init_io(&s->iomem[1], &arm_thiswdog_ops, s,
  254. "arm_mptimer_wdog", 0x20);
  255. sysbus_init_mmio(dev, &s->iomem[1]);
  256. for (i = 0; i < (s->num_cpu * 2); i++) {
  257. timerblock *tb = &s->timerblock[i];
  258. tb->timer = qemu_new_timer_ns(vm_clock, timerblock_tick, tb);
  259. sysbus_init_irq(dev, &tb->irq);
  260. memory_region_init_io(&tb->iomem, &timerblock_ops, tb,
  261. "arm_mptimer_timerblock", 0x20);
  262. sysbus_init_mmio(dev, &tb->iomem);
  263. }
  264. return 0;
  265. }
  266. static const VMStateDescription vmstate_timerblock = {
  267. .name = "arm_mptimer_timerblock",
  268. .version_id = 1,
  269. .minimum_version_id = 1,
  270. .fields = (VMStateField[]) {
  271. VMSTATE_UINT32(count, timerblock),
  272. VMSTATE_UINT32(load, timerblock),
  273. VMSTATE_UINT32(control, timerblock),
  274. VMSTATE_UINT32(status, timerblock),
  275. VMSTATE_INT64(tick, timerblock),
  276. VMSTATE_END_OF_LIST()
  277. }
  278. };
  279. static const VMStateDescription vmstate_arm_mptimer = {
  280. .name = "arm_mptimer",
  281. .version_id = 1,
  282. .minimum_version_id = 1,
  283. .fields = (VMStateField[]) {
  284. VMSTATE_STRUCT_ARRAY(timerblock, arm_mptimer_state, (MAX_CPUS * 2),
  285. 1, vmstate_timerblock, timerblock),
  286. VMSTATE_END_OF_LIST()
  287. }
  288. };
  289. static Property arm_mptimer_properties[] = {
  290. DEFINE_PROP_UINT32("num-cpu", arm_mptimer_state, num_cpu, 0),
  291. DEFINE_PROP_END_OF_LIST()
  292. };
  293. static void arm_mptimer_class_init(ObjectClass *klass, void *data)
  294. {
  295. DeviceClass *dc = DEVICE_CLASS(klass);
  296. SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
  297. sbc->init = arm_mptimer_init;
  298. dc->vmsd = &vmstate_arm_mptimer;
  299. dc->reset = arm_mptimer_reset;
  300. dc->no_user = 1;
  301. dc->props = arm_mptimer_properties;
  302. }
  303. static TypeInfo arm_mptimer_info = {
  304. .name = "arm_mptimer",
  305. .parent = TYPE_SYS_BUS_DEVICE,
  306. .instance_size = sizeof(arm_mptimer_state),
  307. .class_init = arm_mptimer_class_init,
  308. };
  309. static void arm_mptimer_register_types(void)
  310. {
  311. type_register_static(&arm_mptimer_info);
  312. }
  313. type_init(arm_mptimer_register_types)