2
0

mips_gictimer.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. /*
  2. * This file is subject to the terms and conditions of the GNU General Public
  3. * License. See the file "COPYING" in the main directory of this archive
  4. * for more details.
  5. *
  6. * Copyright (C) 2016 Imagination Technologies
  7. */
  8. #include "qemu/osdep.h"
  9. #include "hw/sysbus.h"
  10. #include "qemu/timer.h"
  11. #include "hw/timer/mips_gictimer.h"
  12. #define TIMER_PERIOD 10 /* 10 ns period for 100 Mhz frequency */
  13. uint32_t mips_gictimer_get_freq(MIPSGICTimerState *gic)
  14. {
  15. return NANOSECONDS_PER_SECOND / TIMER_PERIOD;
  16. }
  17. static void gic_vptimer_update(MIPSGICTimerState *gictimer,
  18. uint32_t vp_index, uint64_t now)
  19. {
  20. uint64_t next;
  21. uint32_t wait;
  22. wait = gictimer->vptimers[vp_index].comparelo - gictimer->sh_counterlo -
  23. (uint32_t)(now / TIMER_PERIOD);
  24. next = now + (uint64_t)wait * TIMER_PERIOD;
  25. timer_mod(gictimer->vptimers[vp_index].qtimer, next);
  26. }
  27. static void gic_vptimer_expire(MIPSGICTimerState *gictimer, uint32_t vp_index,
  28. uint64_t now)
  29. {
  30. if (gictimer->countstop) {
  31. /* timer stopped */
  32. return;
  33. }
  34. gictimer->cb(gictimer->opaque, vp_index);
  35. gic_vptimer_update(gictimer, vp_index, now);
  36. }
  37. static void gic_vptimer_cb(void *opaque)
  38. {
  39. MIPSGICTimerVPState *vptimer = opaque;
  40. MIPSGICTimerState *gictimer = vptimer->gictimer;
  41. gic_vptimer_expire(gictimer, vptimer->vp_index,
  42. qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
  43. }
  44. uint32_t mips_gictimer_get_sh_count(MIPSGICTimerState *gictimer)
  45. {
  46. int i;
  47. if (gictimer->countstop) {
  48. return gictimer->sh_counterlo;
  49. } else {
  50. uint64_t now;
  51. now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
  52. for (i = 0; i < gictimer->num_vps; i++) {
  53. if (timer_pending(gictimer->vptimers[i].qtimer)
  54. && timer_expired(gictimer->vptimers[i].qtimer, now)) {
  55. /* The timer has already expired. */
  56. gic_vptimer_expire(gictimer, i, now);
  57. }
  58. }
  59. return gictimer->sh_counterlo + (uint32_t)(now / TIMER_PERIOD);
  60. }
  61. }
  62. void mips_gictimer_store_sh_count(MIPSGICTimerState *gictimer, uint64_t count)
  63. {
  64. int i;
  65. uint64_t now;
  66. if (gictimer->countstop || !gictimer->vptimers[0].qtimer) {
  67. gictimer->sh_counterlo = count;
  68. } else {
  69. /* Store new count register */
  70. now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
  71. gictimer->sh_counterlo = count - (uint32_t)(now / TIMER_PERIOD);
  72. /* Update timer timer */
  73. for (i = 0; i < gictimer->num_vps; i++) {
  74. gic_vptimer_update(gictimer, i, now);
  75. }
  76. }
  77. }
  78. uint32_t mips_gictimer_get_vp_compare(MIPSGICTimerState *gictimer,
  79. uint32_t vp_index)
  80. {
  81. return gictimer->vptimers[vp_index].comparelo;
  82. }
  83. void mips_gictimer_store_vp_compare(MIPSGICTimerState *gictimer,
  84. uint32_t vp_index, uint64_t compare)
  85. {
  86. gictimer->vptimers[vp_index].comparelo = (uint32_t) compare;
  87. gic_vptimer_update(gictimer, vp_index,
  88. qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
  89. }
  90. uint8_t mips_gictimer_get_countstop(MIPSGICTimerState *gictimer)
  91. {
  92. return gictimer->countstop;
  93. }
  94. void mips_gictimer_start_count(MIPSGICTimerState *gictimer)
  95. {
  96. gictimer->countstop = 0;
  97. mips_gictimer_store_sh_count(gictimer, gictimer->sh_counterlo);
  98. }
  99. void mips_gictimer_stop_count(MIPSGICTimerState *gictimer)
  100. {
  101. int i;
  102. gictimer->countstop = 1;
  103. /* Store the current value */
  104. gictimer->sh_counterlo +=
  105. (uint32_t)(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / TIMER_PERIOD);
  106. for (i = 0; i < gictimer->num_vps; i++) {
  107. timer_del(gictimer->vptimers[i].qtimer);
  108. }
  109. }
  110. MIPSGICTimerState *mips_gictimer_init(void *opaque, uint32_t nvps,
  111. MIPSGICTimerCB *cb)
  112. {
  113. int i;
  114. MIPSGICTimerState *gictimer = g_new(MIPSGICTimerState, 1);
  115. gictimer->vptimers = g_new(MIPSGICTimerVPState, nvps);
  116. gictimer->countstop = 1;
  117. gictimer->num_vps = nvps;
  118. gictimer->opaque = opaque;
  119. gictimer->cb = cb;
  120. for (i = 0; i < nvps; i++) {
  121. gictimer->vptimers[i].gictimer = gictimer;
  122. gictimer->vptimers[i].vp_index = i;
  123. gictimer->vptimers[i].qtimer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
  124. &gic_vptimer_cb,
  125. &gictimer->vptimers[i]);
  126. }
  127. return gictimer;
  128. }