bcm2835_systmr.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. /*
  2. * BCM2835 SYS timer emulation
  3. *
  4. * Copyright (C) 2019 Philippe Mathieu-Daudé <f4bug@amsat.org>
  5. *
  6. * SPDX-License-Identifier: GPL-2.0-or-later
  7. *
  8. * Datasheet: BCM2835 ARM Peripherals (C6357-M-1398)
  9. * https://www.raspberrypi.org/app/uploads/2012/02/BCM2835-ARM-Peripherals.pdf
  10. *
  11. * Only the free running 64-bit counter is implemented.
  12. * The 4 COMPARE registers and the interruption are not implemented.
  13. */
  14. #include "qemu/osdep.h"
  15. #include "qemu/log.h"
  16. #include "qemu/timer.h"
  17. #include "hw/timer/bcm2835_systmr.h"
  18. #include "hw/registerfields.h"
  19. #include "migration/vmstate.h"
  20. #include "trace.h"
  21. REG32(CTRL_STATUS, 0x00)
  22. REG32(COUNTER_LOW, 0x04)
  23. REG32(COUNTER_HIGH, 0x08)
  24. REG32(COMPARE0, 0x0c)
  25. REG32(COMPARE1, 0x10)
  26. REG32(COMPARE2, 0x14)
  27. REG32(COMPARE3, 0x18)
  28. static void bcm2835_systmr_timer_expire(void *opaque)
  29. {
  30. BCM2835SystemTimerCompare *tmr = opaque;
  31. trace_bcm2835_systmr_timer_expired(tmr->id);
  32. tmr->state->reg.ctrl_status |= 1 << tmr->id;
  33. qemu_set_irq(tmr->irq, 1);
  34. }
  35. static uint64_t bcm2835_systmr_read(void *opaque, hwaddr offset,
  36. unsigned size)
  37. {
  38. BCM2835SystemTimerState *s = BCM2835_SYSTIMER(opaque);
  39. uint64_t r = 0;
  40. switch (offset) {
  41. case A_CTRL_STATUS:
  42. r = s->reg.ctrl_status;
  43. break;
  44. case A_COMPARE0 ... A_COMPARE3:
  45. r = s->reg.compare[(offset - A_COMPARE0) >> 2];
  46. break;
  47. case A_COUNTER_LOW:
  48. case A_COUNTER_HIGH:
  49. /* Free running counter at 1MHz */
  50. r = qemu_clock_get_us(QEMU_CLOCK_VIRTUAL);
  51. r >>= 8 * (offset - A_COUNTER_LOW);
  52. r &= UINT32_MAX;
  53. break;
  54. default:
  55. qemu_log_mask(LOG_GUEST_ERROR, "%s: bad offset 0x%" HWADDR_PRIx "\n",
  56. __func__, offset);
  57. break;
  58. }
  59. trace_bcm2835_systmr_read(offset, r);
  60. return r;
  61. }
  62. static void bcm2835_systmr_write(void *opaque, hwaddr offset,
  63. uint64_t value64, unsigned size)
  64. {
  65. BCM2835SystemTimerState *s = BCM2835_SYSTIMER(opaque);
  66. int index;
  67. uint32_t value = value64;
  68. uint32_t triggers_delay_us;
  69. uint64_t now;
  70. trace_bcm2835_systmr_write(offset, value);
  71. switch (offset) {
  72. case A_CTRL_STATUS:
  73. s->reg.ctrl_status &= ~value; /* Ack */
  74. for (index = 0; index < ARRAY_SIZE(s->tmr); index++) {
  75. if (extract32(value, index, 1)) {
  76. trace_bcm2835_systmr_irq_ack(index);
  77. qemu_set_irq(s->tmr[index].irq, 0);
  78. }
  79. }
  80. break;
  81. case A_COMPARE0 ... A_COMPARE3:
  82. index = (offset - A_COMPARE0) >> 2;
  83. s->reg.compare[index] = value;
  84. now = qemu_clock_get_us(QEMU_CLOCK_VIRTUAL);
  85. /* Compare lower 32-bits of the free-running counter. */
  86. triggers_delay_us = value - now;
  87. trace_bcm2835_systmr_run(index, triggers_delay_us);
  88. timer_mod(&s->tmr[index].timer, now + triggers_delay_us);
  89. break;
  90. case A_COUNTER_LOW:
  91. case A_COUNTER_HIGH:
  92. qemu_log_mask(LOG_GUEST_ERROR, "%s: read-only ofs 0x%" HWADDR_PRIx "\n",
  93. __func__, offset);
  94. break;
  95. default:
  96. qemu_log_mask(LOG_GUEST_ERROR, "%s: bad offset 0x%" HWADDR_PRIx "\n",
  97. __func__, offset);
  98. break;
  99. }
  100. }
  101. static const MemoryRegionOps bcm2835_systmr_ops = {
  102. .read = bcm2835_systmr_read,
  103. .write = bcm2835_systmr_write,
  104. .endianness = DEVICE_LITTLE_ENDIAN,
  105. .impl = {
  106. .min_access_size = 4,
  107. .max_access_size = 4,
  108. },
  109. };
  110. static void bcm2835_systmr_reset(DeviceState *dev)
  111. {
  112. BCM2835SystemTimerState *s = BCM2835_SYSTIMER(dev);
  113. memset(&s->reg, 0, sizeof(s->reg));
  114. }
  115. static void bcm2835_systmr_realize(DeviceState *dev, Error **errp)
  116. {
  117. BCM2835SystemTimerState *s = BCM2835_SYSTIMER(dev);
  118. memory_region_init_io(&s->iomem, OBJECT(dev), &bcm2835_systmr_ops,
  119. s, "bcm2835-sys-timer", 0x20);
  120. sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
  121. for (size_t i = 0; i < ARRAY_SIZE(s->tmr); i++) {
  122. s->tmr[i].id = i;
  123. s->tmr[i].state = s;
  124. sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->tmr[i].irq);
  125. timer_init_us(&s->tmr[i].timer, QEMU_CLOCK_VIRTUAL,
  126. bcm2835_systmr_timer_expire, &s->tmr[i]);
  127. }
  128. }
  129. static const VMStateDescription bcm2835_systmr_vmstate = {
  130. .name = "bcm2835_sys_timer",
  131. .version_id = 1,
  132. .minimum_version_id = 1,
  133. .fields = (VMStateField[]) {
  134. VMSTATE_UINT32(reg.ctrl_status, BCM2835SystemTimerState),
  135. VMSTATE_UINT32_ARRAY(reg.compare, BCM2835SystemTimerState,
  136. BCM2835_SYSTIMER_COUNT),
  137. VMSTATE_END_OF_LIST()
  138. }
  139. };
  140. static void bcm2835_systmr_class_init(ObjectClass *klass, void *data)
  141. {
  142. DeviceClass *dc = DEVICE_CLASS(klass);
  143. dc->realize = bcm2835_systmr_realize;
  144. dc->reset = bcm2835_systmr_reset;
  145. dc->vmsd = &bcm2835_systmr_vmstate;
  146. }
  147. static const TypeInfo bcm2835_systmr_info = {
  148. .name = TYPE_BCM2835_SYSTIMER,
  149. .parent = TYPE_SYS_BUS_DEVICE,
  150. .instance_size = sizeof(BCM2835SystemTimerState),
  151. .class_init = bcm2835_systmr_class_init,
  152. };
  153. static void bcm2835_systmr_register_types(void)
  154. {
  155. type_register_static(&bcm2835_systmr_info);
  156. }
  157. type_init(bcm2835_systmr_register_types);