bcm2835_systmr.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  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_update_irq(BCM2835SystemTimerState *s)
  29. {
  30. bool enable = !!s->reg.status;
  31. trace_bcm2835_systmr_irq(enable);
  32. qemu_set_irq(s->irq, enable);
  33. }
  34. static void bcm2835_systmr_update_compare(BCM2835SystemTimerState *s,
  35. unsigned timer_index)
  36. {
  37. /* TODO fow now, since neither Linux nor U-boot use these timers. */
  38. qemu_log_mask(LOG_UNIMP, "COMPARE register %u not implemented\n",
  39. timer_index);
  40. }
  41. static uint64_t bcm2835_systmr_read(void *opaque, hwaddr offset,
  42. unsigned size)
  43. {
  44. BCM2835SystemTimerState *s = BCM2835_SYSTIMER(opaque);
  45. uint64_t r = 0;
  46. switch (offset) {
  47. case A_CTRL_STATUS:
  48. r = s->reg.status;
  49. break;
  50. case A_COMPARE0 ... A_COMPARE3:
  51. r = s->reg.compare[(offset - A_COMPARE0) >> 2];
  52. break;
  53. case A_COUNTER_LOW:
  54. case A_COUNTER_HIGH:
  55. /* Free running counter at 1MHz */
  56. r = qemu_clock_get_us(QEMU_CLOCK_VIRTUAL);
  57. r >>= 8 * (offset - A_COUNTER_LOW);
  58. r &= UINT32_MAX;
  59. break;
  60. default:
  61. qemu_log_mask(LOG_GUEST_ERROR, "%s: bad offset 0x%" HWADDR_PRIx "\n",
  62. __func__, offset);
  63. break;
  64. }
  65. trace_bcm2835_systmr_read(offset, r);
  66. return r;
  67. }
  68. static void bcm2835_systmr_write(void *opaque, hwaddr offset,
  69. uint64_t value, unsigned size)
  70. {
  71. BCM2835SystemTimerState *s = BCM2835_SYSTIMER(opaque);
  72. trace_bcm2835_systmr_write(offset, value);
  73. switch (offset) {
  74. case A_CTRL_STATUS:
  75. s->reg.status &= ~value; /* Ack */
  76. bcm2835_systmr_update_irq(s);
  77. break;
  78. case A_COMPARE0 ... A_COMPARE3:
  79. s->reg.compare[(offset - A_COMPARE0) >> 2] = value;
  80. bcm2835_systmr_update_compare(s, (offset - A_COMPARE0) >> 2);
  81. break;
  82. case A_COUNTER_LOW:
  83. case A_COUNTER_HIGH:
  84. qemu_log_mask(LOG_GUEST_ERROR, "%s: read-only ofs 0x%" HWADDR_PRIx "\n",
  85. __func__, offset);
  86. break;
  87. default:
  88. qemu_log_mask(LOG_GUEST_ERROR, "%s: bad offset 0x%" HWADDR_PRIx "\n",
  89. __func__, offset);
  90. break;
  91. }
  92. }
  93. static const MemoryRegionOps bcm2835_systmr_ops = {
  94. .read = bcm2835_systmr_read,
  95. .write = bcm2835_systmr_write,
  96. .endianness = DEVICE_LITTLE_ENDIAN,
  97. .impl = {
  98. .min_access_size = 4,
  99. .max_access_size = 4,
  100. },
  101. };
  102. static void bcm2835_systmr_reset(DeviceState *dev)
  103. {
  104. BCM2835SystemTimerState *s = BCM2835_SYSTIMER(dev);
  105. memset(&s->reg, 0, sizeof(s->reg));
  106. }
  107. static void bcm2835_systmr_realize(DeviceState *dev, Error **errp)
  108. {
  109. BCM2835SystemTimerState *s = BCM2835_SYSTIMER(dev);
  110. memory_region_init_io(&s->iomem, OBJECT(dev), &bcm2835_systmr_ops,
  111. s, "bcm2835-sys-timer", 0x20);
  112. sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
  113. sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq);
  114. }
  115. static const VMStateDescription bcm2835_systmr_vmstate = {
  116. .name = "bcm2835_sys_timer",
  117. .version_id = 1,
  118. .minimum_version_id = 1,
  119. .fields = (VMStateField[]) {
  120. VMSTATE_UINT32(reg.status, BCM2835SystemTimerState),
  121. VMSTATE_UINT32_ARRAY(reg.compare, BCM2835SystemTimerState, 4),
  122. VMSTATE_END_OF_LIST()
  123. }
  124. };
  125. static void bcm2835_systmr_class_init(ObjectClass *klass, void *data)
  126. {
  127. DeviceClass *dc = DEVICE_CLASS(klass);
  128. dc->realize = bcm2835_systmr_realize;
  129. dc->reset = bcm2835_systmr_reset;
  130. dc->vmsd = &bcm2835_systmr_vmstate;
  131. }
  132. static const TypeInfo bcm2835_systmr_info = {
  133. .name = TYPE_BCM2835_SYSTIMER,
  134. .parent = TYPE_SYS_BUS_DEVICE,
  135. .instance_size = sizeof(BCM2835SystemTimerState),
  136. .class_init = bcm2835_systmr_class_init,
  137. };
  138. static void bcm2835_systmr_register_types(void)
  139. {
  140. type_register_static(&bcm2835_systmr_info);
  141. }
  142. type_init(bcm2835_systmr_register_types);