2
0

aspeed_rtc.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. /*
  2. * ASPEED Real Time Clock
  3. * Joel Stanley <joel@jms.id.au>
  4. *
  5. * Copyright 2019 IBM Corp
  6. * SPDX-License-Identifier: GPL-2.0-or-later
  7. */
  8. #include "qemu/osdep.h"
  9. #include "qemu-common.h"
  10. #include "hw/rtc/aspeed_rtc.h"
  11. #include "migration/vmstate.h"
  12. #include "qemu/log.h"
  13. #include "qemu/timer.h"
  14. #include "trace.h"
  15. #define COUNTER1 (0x00 / 4)
  16. #define COUNTER2 (0x04 / 4)
  17. #define ALARM (0x08 / 4)
  18. #define CONTROL (0x10 / 4)
  19. #define ALARM_STATUS (0x14 / 4)
  20. #define RTC_UNLOCKED BIT(1)
  21. #define RTC_ENABLED BIT(0)
  22. static void aspeed_rtc_calc_offset(AspeedRtcState *rtc)
  23. {
  24. struct tm tm;
  25. uint32_t year, cent;
  26. uint32_t reg1 = rtc->reg[COUNTER1];
  27. uint32_t reg2 = rtc->reg[COUNTER2];
  28. tm.tm_mday = (reg1 >> 24) & 0x1f;
  29. tm.tm_hour = (reg1 >> 16) & 0x1f;
  30. tm.tm_min = (reg1 >> 8) & 0x3f;
  31. tm.tm_sec = (reg1 >> 0) & 0x3f;
  32. cent = (reg2 >> 16) & 0x1f;
  33. year = (reg2 >> 8) & 0x7f;
  34. tm.tm_mon = ((reg2 >> 0) & 0x0f) - 1;
  35. tm.tm_year = year + (cent * 100) - 1900;
  36. rtc->offset = qemu_timedate_diff(&tm);
  37. }
  38. static uint32_t aspeed_rtc_get_counter(AspeedRtcState *rtc, int r)
  39. {
  40. uint32_t year, cent;
  41. struct tm now;
  42. qemu_get_timedate(&now, rtc->offset);
  43. switch (r) {
  44. case COUNTER1:
  45. return (now.tm_mday << 24) | (now.tm_hour << 16) |
  46. (now.tm_min << 8) | now.tm_sec;
  47. case COUNTER2:
  48. cent = (now.tm_year + 1900) / 100;
  49. year = now.tm_year % 100;
  50. return ((cent & 0x1f) << 16) | ((year & 0x7f) << 8) |
  51. ((now.tm_mon + 1) & 0xf);
  52. default:
  53. g_assert_not_reached();
  54. }
  55. }
  56. static uint64_t aspeed_rtc_read(void *opaque, hwaddr addr,
  57. unsigned size)
  58. {
  59. AspeedRtcState *rtc = opaque;
  60. uint64_t val;
  61. uint32_t r = addr >> 2;
  62. switch (r) {
  63. case COUNTER1:
  64. case COUNTER2:
  65. if (rtc->reg[CONTROL] & RTC_ENABLED) {
  66. rtc->reg[r] = aspeed_rtc_get_counter(rtc, r);
  67. }
  68. /* fall through */
  69. case CONTROL:
  70. val = rtc->reg[r];
  71. break;
  72. case ALARM:
  73. case ALARM_STATUS:
  74. default:
  75. qemu_log_mask(LOG_UNIMP, "%s: 0x%" HWADDR_PRIx "\n", __func__, addr);
  76. return 0;
  77. }
  78. trace_aspeed_rtc_read(addr, val);
  79. return val;
  80. }
  81. static void aspeed_rtc_write(void *opaque, hwaddr addr,
  82. uint64_t val, unsigned size)
  83. {
  84. AspeedRtcState *rtc = opaque;
  85. uint32_t r = addr >> 2;
  86. switch (r) {
  87. case COUNTER1:
  88. case COUNTER2:
  89. if (!(rtc->reg[CONTROL] & RTC_UNLOCKED)) {
  90. break;
  91. }
  92. /* fall through */
  93. case CONTROL:
  94. rtc->reg[r] = val;
  95. aspeed_rtc_calc_offset(rtc);
  96. break;
  97. case ALARM:
  98. case ALARM_STATUS:
  99. default:
  100. qemu_log_mask(LOG_UNIMP, "%s: 0x%" HWADDR_PRIx "\n", __func__, addr);
  101. break;
  102. }
  103. trace_aspeed_rtc_write(addr, val);
  104. }
  105. static void aspeed_rtc_reset(DeviceState *d)
  106. {
  107. AspeedRtcState *rtc = ASPEED_RTC(d);
  108. rtc->offset = 0;
  109. memset(rtc->reg, 0, sizeof(rtc->reg));
  110. }
  111. static const MemoryRegionOps aspeed_rtc_ops = {
  112. .read = aspeed_rtc_read,
  113. .write = aspeed_rtc_write,
  114. .endianness = DEVICE_NATIVE_ENDIAN,
  115. };
  116. static const VMStateDescription vmstate_aspeed_rtc = {
  117. .name = TYPE_ASPEED_RTC,
  118. .version_id = 1,
  119. .fields = (VMStateField[]) {
  120. VMSTATE_UINT32_ARRAY(reg, AspeedRtcState, 0x18),
  121. VMSTATE_INT32(offset, AspeedRtcState),
  122. VMSTATE_INT32(offset, AspeedRtcState),
  123. VMSTATE_END_OF_LIST()
  124. }
  125. };
  126. static void aspeed_rtc_realize(DeviceState *dev, Error **errp)
  127. {
  128. SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
  129. AspeedRtcState *s = ASPEED_RTC(dev);
  130. sysbus_init_irq(sbd, &s->irq);
  131. memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_rtc_ops, s,
  132. "aspeed-rtc", 0x18ULL);
  133. sysbus_init_mmio(sbd, &s->iomem);
  134. }
  135. static void aspeed_rtc_class_init(ObjectClass *klass, void *data)
  136. {
  137. DeviceClass *dc = DEVICE_CLASS(klass);
  138. dc->realize = aspeed_rtc_realize;
  139. dc->vmsd = &vmstate_aspeed_rtc;
  140. dc->reset = aspeed_rtc_reset;
  141. }
  142. static const TypeInfo aspeed_rtc_info = {
  143. .name = TYPE_ASPEED_RTC,
  144. .parent = TYPE_SYS_BUS_DEVICE,
  145. .instance_size = sizeof(AspeedRtcState),
  146. .class_init = aspeed_rtc_class_init,
  147. };
  148. static void aspeed_rtc_register_types(void)
  149. {
  150. type_register_static(&aspeed_rtc_info);
  151. }
  152. type_init(aspeed_rtc_register_types)