arm_mptimer.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  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 "qemu/osdep.h"
  22. #include "hw/hw.h"
  23. #include "hw/irq.h"
  24. #include "hw/ptimer.h"
  25. #include "hw/qdev-properties.h"
  26. #include "hw/timer/arm_mptimer.h"
  27. #include "migration/vmstate.h"
  28. #include "qapi/error.h"
  29. #include "qemu/module.h"
  30. #include "hw/core/cpu.h"
  31. #define PTIMER_POLICY \
  32. (PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD | \
  33. PTIMER_POLICY_CONTINUOUS_TRIGGER | \
  34. PTIMER_POLICY_NO_IMMEDIATE_TRIGGER | \
  35. PTIMER_POLICY_NO_IMMEDIATE_RELOAD | \
  36. PTIMER_POLICY_NO_COUNTER_ROUND_DOWN)
  37. /* This device implements the per-cpu private timer and watchdog block
  38. * which is used in both the ARM11MPCore and Cortex-A9MP.
  39. */
  40. static inline int get_current_cpu(ARMMPTimerState *s)
  41. {
  42. int cpu_id = current_cpu ? current_cpu->cpu_index : 0;
  43. if (cpu_id >= s->num_cpu) {
  44. hw_error("arm_mptimer: num-cpu %d but this cpu is %d!\n",
  45. s->num_cpu, cpu_id);
  46. }
  47. return cpu_id;
  48. }
  49. static inline void timerblock_update_irq(TimerBlock *tb)
  50. {
  51. qemu_set_irq(tb->irq, tb->status && (tb->control & 4));
  52. }
  53. /* Return conversion factor from mpcore timer ticks to qemu timer ticks. */
  54. static inline uint32_t timerblock_scale(uint32_t control)
  55. {
  56. return (((control >> 8) & 0xff) + 1) * 10;
  57. }
  58. /* Must be called within a ptimer transaction block */
  59. static inline void timerblock_set_count(struct ptimer_state *timer,
  60. uint32_t control, uint64_t *count)
  61. {
  62. /* PTimer would trigger interrupt for periodic timer when counter set
  63. * to 0, MPtimer under certain condition only.
  64. */
  65. if ((control & 3) == 3 && (control & 0xff00) == 0 && *count == 0) {
  66. *count = ptimer_get_limit(timer);
  67. }
  68. ptimer_set_count(timer, *count);
  69. }
  70. /* Must be called within a ptimer transaction block */
  71. static inline void timerblock_run(struct ptimer_state *timer,
  72. uint32_t control, uint32_t load)
  73. {
  74. if ((control & 1) && ((control & 0xff00) || load != 0)) {
  75. ptimer_run(timer, !(control & 2));
  76. }
  77. }
  78. static void timerblock_tick(void *opaque)
  79. {
  80. TimerBlock *tb = (TimerBlock *)opaque;
  81. /* Periodic timer with load = 0 and prescaler != 0 would re-trigger
  82. * IRQ after one period, otherwise it either stops or wraps around.
  83. */
  84. if ((tb->control & 2) && (tb->control & 0xff00) == 0 &&
  85. ptimer_get_limit(tb->timer) == 0) {
  86. ptimer_stop(tb->timer);
  87. }
  88. tb->status = 1;
  89. timerblock_update_irq(tb);
  90. }
  91. static uint64_t timerblock_read(void *opaque, hwaddr addr,
  92. unsigned size)
  93. {
  94. TimerBlock *tb = (TimerBlock *)opaque;
  95. switch (addr) {
  96. case 0: /* Load */
  97. return ptimer_get_limit(tb->timer);
  98. case 4: /* Counter. */
  99. return ptimer_get_count(tb->timer);
  100. case 8: /* Control. */
  101. return tb->control;
  102. case 12: /* Interrupt status. */
  103. return tb->status;
  104. default:
  105. return 0;
  106. }
  107. }
  108. static void timerblock_write(void *opaque, hwaddr addr,
  109. uint64_t value, unsigned size)
  110. {
  111. TimerBlock *tb = (TimerBlock *)opaque;
  112. uint32_t control = tb->control;
  113. switch (addr) {
  114. case 0: /* Load */
  115. ptimer_transaction_begin(tb->timer);
  116. /* Setting load to 0 stops the timer without doing the tick if
  117. * prescaler = 0.
  118. */
  119. if ((control & 1) && (control & 0xff00) == 0 && value == 0) {
  120. ptimer_stop(tb->timer);
  121. }
  122. ptimer_set_limit(tb->timer, value, 1);
  123. timerblock_run(tb->timer, control, value);
  124. ptimer_transaction_commit(tb->timer);
  125. break;
  126. case 4: /* Counter. */
  127. ptimer_transaction_begin(tb->timer);
  128. /* Setting counter to 0 stops the one-shot timer, or periodic with
  129. * load = 0, without doing the tick if prescaler = 0.
  130. */
  131. if ((control & 1) && (control & 0xff00) == 0 && value == 0 &&
  132. (!(control & 2) || ptimer_get_limit(tb->timer) == 0)) {
  133. ptimer_stop(tb->timer);
  134. }
  135. timerblock_set_count(tb->timer, control, &value);
  136. timerblock_run(tb->timer, control, value);
  137. ptimer_transaction_commit(tb->timer);
  138. break;
  139. case 8: /* Control. */
  140. ptimer_transaction_begin(tb->timer);
  141. if ((control & 3) != (value & 3)) {
  142. ptimer_stop(tb->timer);
  143. }
  144. if ((control & 0xff00) != (value & 0xff00)) {
  145. ptimer_set_period(tb->timer, timerblock_scale(value));
  146. }
  147. if (value & 1) {
  148. uint64_t count = ptimer_get_count(tb->timer);
  149. /* Re-load periodic timer counter if needed. */
  150. if ((value & 2) && count == 0) {
  151. timerblock_set_count(tb->timer, value, &count);
  152. }
  153. timerblock_run(tb->timer, value, count);
  154. }
  155. tb->control = value;
  156. ptimer_transaction_commit(tb->timer);
  157. break;
  158. case 12: /* Interrupt status. */
  159. tb->status &= ~value;
  160. timerblock_update_irq(tb);
  161. break;
  162. }
  163. }
  164. /* Wrapper functions to implement the "read timer/watchdog for
  165. * the current CPU" memory regions.
  166. */
  167. static uint64_t arm_thistimer_read(void *opaque, hwaddr addr,
  168. unsigned size)
  169. {
  170. ARMMPTimerState *s = (ARMMPTimerState *)opaque;
  171. int id = get_current_cpu(s);
  172. return timerblock_read(&s->timerblock[id], addr, size);
  173. }
  174. static void arm_thistimer_write(void *opaque, hwaddr addr,
  175. uint64_t value, unsigned size)
  176. {
  177. ARMMPTimerState *s = (ARMMPTimerState *)opaque;
  178. int id = get_current_cpu(s);
  179. timerblock_write(&s->timerblock[id], addr, value, size);
  180. }
  181. static const MemoryRegionOps arm_thistimer_ops = {
  182. .read = arm_thistimer_read,
  183. .write = arm_thistimer_write,
  184. .valid = {
  185. .min_access_size = 4,
  186. .max_access_size = 4,
  187. },
  188. .endianness = DEVICE_NATIVE_ENDIAN,
  189. };
  190. static const MemoryRegionOps timerblock_ops = {
  191. .read = timerblock_read,
  192. .write = timerblock_write,
  193. .valid = {
  194. .min_access_size = 4,
  195. .max_access_size = 4,
  196. },
  197. .endianness = DEVICE_NATIVE_ENDIAN,
  198. };
  199. static void timerblock_reset(TimerBlock *tb)
  200. {
  201. tb->control = 0;
  202. tb->status = 0;
  203. if (tb->timer) {
  204. ptimer_transaction_begin(tb->timer);
  205. ptimer_stop(tb->timer);
  206. ptimer_set_limit(tb->timer, 0, 1);
  207. ptimer_set_period(tb->timer, timerblock_scale(0));
  208. ptimer_transaction_commit(tb->timer);
  209. }
  210. }
  211. static void arm_mptimer_reset(DeviceState *dev)
  212. {
  213. ARMMPTimerState *s = ARM_MPTIMER(dev);
  214. int i;
  215. for (i = 0; i < ARRAY_SIZE(s->timerblock); i++) {
  216. timerblock_reset(&s->timerblock[i]);
  217. }
  218. }
  219. static void arm_mptimer_init(Object *obj)
  220. {
  221. ARMMPTimerState *s = ARM_MPTIMER(obj);
  222. memory_region_init_io(&s->iomem, obj, &arm_thistimer_ops, s,
  223. "arm_mptimer_timer", 0x20);
  224. sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem);
  225. }
  226. static void arm_mptimer_realize(DeviceState *dev, Error **errp)
  227. {
  228. SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
  229. ARMMPTimerState *s = ARM_MPTIMER(dev);
  230. int i;
  231. if (s->num_cpu < 1 || s->num_cpu > ARM_MPTIMER_MAX_CPUS) {
  232. error_setg(errp, "num-cpu must be between 1 and %d",
  233. ARM_MPTIMER_MAX_CPUS);
  234. return;
  235. }
  236. /* We implement one timer block per CPU, and expose multiple MMIO regions:
  237. * * region 0 is "timer for this core"
  238. * * region 1 is "timer for core 0"
  239. * * region 2 is "timer for core 1"
  240. * and so on.
  241. * The outgoing interrupt lines are
  242. * * timer for core 0
  243. * * timer for core 1
  244. * and so on.
  245. */
  246. for (i = 0; i < s->num_cpu; i++) {
  247. TimerBlock *tb = &s->timerblock[i];
  248. tb->timer = ptimer_init(timerblock_tick, tb, PTIMER_POLICY);
  249. sysbus_init_irq(sbd, &tb->irq);
  250. memory_region_init_io(&tb->iomem, OBJECT(s), &timerblock_ops, tb,
  251. "arm_mptimer_timerblock", 0x20);
  252. sysbus_init_mmio(sbd, &tb->iomem);
  253. }
  254. }
  255. static const VMStateDescription vmstate_timerblock = {
  256. .name = "arm_mptimer_timerblock",
  257. .version_id = 3,
  258. .minimum_version_id = 3,
  259. .fields = (const VMStateField[]) {
  260. VMSTATE_UINT32(control, TimerBlock),
  261. VMSTATE_UINT32(status, TimerBlock),
  262. VMSTATE_PTIMER(timer, TimerBlock),
  263. VMSTATE_END_OF_LIST()
  264. }
  265. };
  266. static const VMStateDescription vmstate_arm_mptimer = {
  267. .name = "arm_mptimer",
  268. .version_id = 3,
  269. .minimum_version_id = 3,
  270. .fields = (const VMStateField[]) {
  271. VMSTATE_STRUCT_VARRAY_UINT32(timerblock, ARMMPTimerState, num_cpu,
  272. 3, vmstate_timerblock, TimerBlock),
  273. VMSTATE_END_OF_LIST()
  274. }
  275. };
  276. static const Property arm_mptimer_properties[] = {
  277. DEFINE_PROP_UINT32("num-cpu", ARMMPTimerState, num_cpu, 0),
  278. };
  279. static void arm_mptimer_class_init(ObjectClass *klass, void *data)
  280. {
  281. DeviceClass *dc = DEVICE_CLASS(klass);
  282. dc->realize = arm_mptimer_realize;
  283. dc->vmsd = &vmstate_arm_mptimer;
  284. device_class_set_legacy_reset(dc, arm_mptimer_reset);
  285. device_class_set_props(dc, arm_mptimer_properties);
  286. }
  287. static const TypeInfo arm_mptimer_info = {
  288. .name = TYPE_ARM_MPTIMER,
  289. .parent = TYPE_SYS_BUS_DEVICE,
  290. .instance_size = sizeof(ARMMPTimerState),
  291. .instance_init = arm_mptimer_init,
  292. .class_init = arm_mptimer_class_init,
  293. };
  294. static void arm_mptimer_register_types(void)
  295. {
  296. type_register_static(&arm_mptimer_info);
  297. }
  298. type_init(arm_mptimer_register_types)