2
0

allwinner-rtc.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  1. /*
  2. * Allwinner Real Time Clock emulation
  3. *
  4. * Copyright (C) 2019 Niek Linnenbank <nieklinnenbank@gmail.com>
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include "qemu/osdep.h"
  20. #include "qemu/units.h"
  21. #include "hw/sysbus.h"
  22. #include "migration/vmstate.h"
  23. #include "qemu/log.h"
  24. #include "qemu/module.h"
  25. #include "hw/qdev-properties.h"
  26. #include "hw/rtc/allwinner-rtc.h"
  27. #include "sysemu/rtc.h"
  28. #include "trace.h"
  29. /* RTC registers */
  30. enum {
  31. REG_LOSC = 1, /* Low Oscillator Control */
  32. REG_YYMMDD, /* RTC Year-Month-Day */
  33. REG_HHMMSS, /* RTC Hour-Minute-Second */
  34. REG_ALARM1_WKHHMMSS, /* Alarm1 Week Hour-Minute-Second */
  35. REG_ALARM1_EN, /* Alarm1 Enable */
  36. REG_ALARM1_IRQ_EN, /* Alarm1 IRQ Enable */
  37. REG_ALARM1_IRQ_STA, /* Alarm1 IRQ Status */
  38. REG_GP0, /* General Purpose Register 0 */
  39. REG_GP1, /* General Purpose Register 1 */
  40. REG_GP2, /* General Purpose Register 2 */
  41. REG_GP3, /* General Purpose Register 3 */
  42. /* sun4i registers */
  43. REG_ALARM1_DDHHMMSS, /* Alarm1 Day Hour-Minute-Second */
  44. REG_CPUCFG, /* CPU Configuration Register */
  45. /* sun6i registers */
  46. REG_LOSC_AUTOSTA, /* LOSC Auto Switch Status */
  47. REG_INT_OSC_PRE, /* Internal OSC Clock Prescaler */
  48. REG_ALARM0_COUNTER, /* Alarm0 Counter */
  49. REG_ALARM0_CUR_VLU, /* Alarm0 Counter Current Value */
  50. REG_ALARM0_ENABLE, /* Alarm0 Enable */
  51. REG_ALARM0_IRQ_EN, /* Alarm0 IRQ Enable */
  52. REG_ALARM0_IRQ_STA, /* Alarm0 IRQ Status */
  53. REG_ALARM_CONFIG, /* Alarm Config */
  54. REG_LOSC_OUT_GATING, /* LOSC Output Gating Register */
  55. REG_GP4, /* General Purpose Register 4 */
  56. REG_GP5, /* General Purpose Register 5 */
  57. REG_GP6, /* General Purpose Register 6 */
  58. REG_GP7, /* General Purpose Register 7 */
  59. REG_RTC_DBG, /* RTC Debug Register */
  60. REG_GPL_HOLD_OUT, /* GPL Hold Output Register */
  61. REG_VDD_RTC, /* VDD RTC Regulate Register */
  62. REG_IC_CHARA, /* IC Characteristics Register */
  63. };
  64. /* RTC register flags */
  65. enum {
  66. REG_LOSC_YMD = (1 << 7),
  67. REG_LOSC_HMS = (1 << 8),
  68. };
  69. /* RTC sun4i register map (offset to name) */
  70. const uint8_t allwinner_rtc_sun4i_regmap[] = {
  71. [0x0000] = REG_LOSC,
  72. [0x0004] = REG_YYMMDD,
  73. [0x0008] = REG_HHMMSS,
  74. [0x000C] = REG_ALARM1_DDHHMMSS,
  75. [0x0010] = REG_ALARM1_WKHHMMSS,
  76. [0x0014] = REG_ALARM1_EN,
  77. [0x0018] = REG_ALARM1_IRQ_EN,
  78. [0x001C] = REG_ALARM1_IRQ_STA,
  79. [0x0020] = REG_GP0,
  80. [0x0024] = REG_GP1,
  81. [0x0028] = REG_GP2,
  82. [0x002C] = REG_GP3,
  83. [0x003C] = REG_CPUCFG,
  84. };
  85. /* RTC sun6i register map (offset to name) */
  86. const uint8_t allwinner_rtc_sun6i_regmap[] = {
  87. [0x0000] = REG_LOSC,
  88. [0x0004] = REG_LOSC_AUTOSTA,
  89. [0x0008] = REG_INT_OSC_PRE,
  90. [0x0010] = REG_YYMMDD,
  91. [0x0014] = REG_HHMMSS,
  92. [0x0020] = REG_ALARM0_COUNTER,
  93. [0x0024] = REG_ALARM0_CUR_VLU,
  94. [0x0028] = REG_ALARM0_ENABLE,
  95. [0x002C] = REG_ALARM0_IRQ_EN,
  96. [0x0030] = REG_ALARM0_IRQ_STA,
  97. [0x0040] = REG_ALARM1_WKHHMMSS,
  98. [0x0044] = REG_ALARM1_EN,
  99. [0x0048] = REG_ALARM1_IRQ_EN,
  100. [0x004C] = REG_ALARM1_IRQ_STA,
  101. [0x0050] = REG_ALARM_CONFIG,
  102. [0x0060] = REG_LOSC_OUT_GATING,
  103. [0x0100] = REG_GP0,
  104. [0x0104] = REG_GP1,
  105. [0x0108] = REG_GP2,
  106. [0x010C] = REG_GP3,
  107. [0x0110] = REG_GP4,
  108. [0x0114] = REG_GP5,
  109. [0x0118] = REG_GP6,
  110. [0x011C] = REG_GP7,
  111. [0x0170] = REG_RTC_DBG,
  112. [0x0180] = REG_GPL_HOLD_OUT,
  113. [0x0190] = REG_VDD_RTC,
  114. [0x01F0] = REG_IC_CHARA,
  115. };
  116. static bool allwinner_rtc_sun4i_read(AwRtcState *s, uint32_t offset)
  117. {
  118. /* no sun4i specific registers currently implemented */
  119. return false;
  120. }
  121. static bool allwinner_rtc_sun4i_write(AwRtcState *s, uint32_t offset,
  122. uint32_t data)
  123. {
  124. /* no sun4i specific registers currently implemented */
  125. return false;
  126. }
  127. static bool allwinner_rtc_sun6i_read(AwRtcState *s, uint32_t offset)
  128. {
  129. const AwRtcClass *c = AW_RTC_GET_CLASS(s);
  130. switch (c->regmap[offset]) {
  131. case REG_GP4: /* General Purpose Register 4 */
  132. case REG_GP5: /* General Purpose Register 5 */
  133. case REG_GP6: /* General Purpose Register 6 */
  134. case REG_GP7: /* General Purpose Register 7 */
  135. return true;
  136. default:
  137. break;
  138. }
  139. return false;
  140. }
  141. static bool allwinner_rtc_sun6i_write(AwRtcState *s, uint32_t offset,
  142. uint32_t data)
  143. {
  144. const AwRtcClass *c = AW_RTC_GET_CLASS(s);
  145. switch (c->regmap[offset]) {
  146. case REG_GP4: /* General Purpose Register 4 */
  147. case REG_GP5: /* General Purpose Register 5 */
  148. case REG_GP6: /* General Purpose Register 6 */
  149. case REG_GP7: /* General Purpose Register 7 */
  150. return true;
  151. default:
  152. break;
  153. }
  154. return false;
  155. }
  156. static uint64_t allwinner_rtc_read(void *opaque, hwaddr offset,
  157. unsigned size)
  158. {
  159. AwRtcState *s = AW_RTC(opaque);
  160. const AwRtcClass *c = AW_RTC_GET_CLASS(s);
  161. uint64_t val = 0;
  162. if (offset >= c->regmap_size) {
  163. qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset 0x%04x\n",
  164. __func__, (uint32_t)offset);
  165. return 0;
  166. }
  167. if (!c->regmap[offset]) {
  168. qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid register 0x%04x\n",
  169. __func__, (uint32_t)offset);
  170. return 0;
  171. }
  172. switch (c->regmap[offset]) {
  173. case REG_LOSC: /* Low Oscillator Control */
  174. val = s->regs[REG_LOSC];
  175. s->regs[REG_LOSC] &= ~(REG_LOSC_YMD | REG_LOSC_HMS);
  176. break;
  177. case REG_YYMMDD: /* RTC Year-Month-Day */
  178. case REG_HHMMSS: /* RTC Hour-Minute-Second */
  179. case REG_GP0: /* General Purpose Register 0 */
  180. case REG_GP1: /* General Purpose Register 1 */
  181. case REG_GP2: /* General Purpose Register 2 */
  182. case REG_GP3: /* General Purpose Register 3 */
  183. val = s->regs[c->regmap[offset]];
  184. break;
  185. default:
  186. if (!c->read(s, offset)) {
  187. qemu_log_mask(LOG_UNIMP, "%s: unimplemented register 0x%04x\n",
  188. __func__, (uint32_t)offset);
  189. }
  190. val = s->regs[c->regmap[offset]];
  191. break;
  192. }
  193. trace_allwinner_rtc_read(offset, val);
  194. return val;
  195. }
  196. static void allwinner_rtc_write(void *opaque, hwaddr offset,
  197. uint64_t val, unsigned size)
  198. {
  199. AwRtcState *s = AW_RTC(opaque);
  200. const AwRtcClass *c = AW_RTC_GET_CLASS(s);
  201. if (offset >= c->regmap_size) {
  202. qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset 0x%04x\n",
  203. __func__, (uint32_t)offset);
  204. return;
  205. }
  206. if (!c->regmap[offset]) {
  207. qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid register 0x%04x\n",
  208. __func__, (uint32_t)offset);
  209. return;
  210. }
  211. trace_allwinner_rtc_write(offset, val);
  212. switch (c->regmap[offset]) {
  213. case REG_YYMMDD: /* RTC Year-Month-Day */
  214. s->regs[REG_YYMMDD] = val;
  215. s->regs[REG_LOSC] |= REG_LOSC_YMD;
  216. break;
  217. case REG_HHMMSS: /* RTC Hour-Minute-Second */
  218. s->regs[REG_HHMMSS] = val;
  219. s->regs[REG_LOSC] |= REG_LOSC_HMS;
  220. break;
  221. case REG_GP0: /* General Purpose Register 0 */
  222. case REG_GP1: /* General Purpose Register 1 */
  223. case REG_GP2: /* General Purpose Register 2 */
  224. case REG_GP3: /* General Purpose Register 3 */
  225. s->regs[c->regmap[offset]] = val;
  226. break;
  227. default:
  228. if (!c->write(s, offset, val)) {
  229. qemu_log_mask(LOG_UNIMP, "%s: unimplemented register 0x%04x\n",
  230. __func__, (uint32_t)offset);
  231. }
  232. break;
  233. }
  234. }
  235. static const MemoryRegionOps allwinner_rtc_ops = {
  236. .read = allwinner_rtc_read,
  237. .write = allwinner_rtc_write,
  238. .endianness = DEVICE_NATIVE_ENDIAN,
  239. .valid = {
  240. .min_access_size = 4,
  241. .max_access_size = 4,
  242. },
  243. .impl.min_access_size = 4,
  244. };
  245. static void allwinner_rtc_reset(DeviceState *dev)
  246. {
  247. AwRtcState *s = AW_RTC(dev);
  248. struct tm now;
  249. /* Clear registers */
  250. memset(s->regs, 0, sizeof(s->regs));
  251. /* Get current datetime */
  252. qemu_get_timedate(&now, 0);
  253. /* Set RTC with current datetime */
  254. if (s->base_year > 1900) {
  255. s->regs[REG_YYMMDD] = ((now.tm_year + 1900 - s->base_year) << 16) |
  256. ((now.tm_mon + 1) << 8) |
  257. now.tm_mday;
  258. s->regs[REG_HHMMSS] = (((now.tm_wday + 6) % 7) << 29) |
  259. (now.tm_hour << 16) |
  260. (now.tm_min << 8) |
  261. now.tm_sec;
  262. }
  263. }
  264. static void allwinner_rtc_init(Object *obj)
  265. {
  266. SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
  267. AwRtcState *s = AW_RTC(obj);
  268. /* Memory mapping */
  269. memory_region_init_io(&s->iomem, OBJECT(s), &allwinner_rtc_ops, s,
  270. TYPE_AW_RTC, 1 * KiB);
  271. sysbus_init_mmio(sbd, &s->iomem);
  272. }
  273. static const VMStateDescription allwinner_rtc_vmstate = {
  274. .name = "allwinner-rtc",
  275. .version_id = 1,
  276. .minimum_version_id = 1,
  277. .fields = (VMStateField[]) {
  278. VMSTATE_UINT32_ARRAY(regs, AwRtcState, AW_RTC_REGS_NUM),
  279. VMSTATE_END_OF_LIST()
  280. }
  281. };
  282. static Property allwinner_rtc_properties[] = {
  283. DEFINE_PROP_INT32("base-year", AwRtcState, base_year, 0),
  284. DEFINE_PROP_END_OF_LIST(),
  285. };
  286. static void allwinner_rtc_class_init(ObjectClass *klass, void *data)
  287. {
  288. DeviceClass *dc = DEVICE_CLASS(klass);
  289. dc->reset = allwinner_rtc_reset;
  290. dc->vmsd = &allwinner_rtc_vmstate;
  291. device_class_set_props(dc, allwinner_rtc_properties);
  292. }
  293. static void allwinner_rtc_sun4i_init(Object *obj)
  294. {
  295. AwRtcState *s = AW_RTC(obj);
  296. s->base_year = 2010;
  297. }
  298. static void allwinner_rtc_sun4i_class_init(ObjectClass *klass, void *data)
  299. {
  300. AwRtcClass *arc = AW_RTC_CLASS(klass);
  301. arc->regmap = allwinner_rtc_sun4i_regmap;
  302. arc->regmap_size = sizeof(allwinner_rtc_sun4i_regmap);
  303. arc->read = allwinner_rtc_sun4i_read;
  304. arc->write = allwinner_rtc_sun4i_write;
  305. }
  306. static void allwinner_rtc_sun6i_init(Object *obj)
  307. {
  308. AwRtcState *s = AW_RTC(obj);
  309. s->base_year = 1970;
  310. }
  311. static void allwinner_rtc_sun6i_class_init(ObjectClass *klass, void *data)
  312. {
  313. AwRtcClass *arc = AW_RTC_CLASS(klass);
  314. arc->regmap = allwinner_rtc_sun6i_regmap;
  315. arc->regmap_size = sizeof(allwinner_rtc_sun6i_regmap);
  316. arc->read = allwinner_rtc_sun6i_read;
  317. arc->write = allwinner_rtc_sun6i_write;
  318. }
  319. static void allwinner_rtc_sun7i_init(Object *obj)
  320. {
  321. AwRtcState *s = AW_RTC(obj);
  322. s->base_year = 1970;
  323. }
  324. static void allwinner_rtc_sun7i_class_init(ObjectClass *klass, void *data)
  325. {
  326. AwRtcClass *arc = AW_RTC_CLASS(klass);
  327. allwinner_rtc_sun4i_class_init(klass, arc);
  328. }
  329. static const TypeInfo allwinner_rtc_info = {
  330. .name = TYPE_AW_RTC,
  331. .parent = TYPE_SYS_BUS_DEVICE,
  332. .instance_init = allwinner_rtc_init,
  333. .instance_size = sizeof(AwRtcState),
  334. .class_init = allwinner_rtc_class_init,
  335. .class_size = sizeof(AwRtcClass),
  336. .abstract = true,
  337. };
  338. static const TypeInfo allwinner_rtc_sun4i_info = {
  339. .name = TYPE_AW_RTC_SUN4I,
  340. .parent = TYPE_AW_RTC,
  341. .class_init = allwinner_rtc_sun4i_class_init,
  342. .instance_init = allwinner_rtc_sun4i_init,
  343. };
  344. static const TypeInfo allwinner_rtc_sun6i_info = {
  345. .name = TYPE_AW_RTC_SUN6I,
  346. .parent = TYPE_AW_RTC,
  347. .class_init = allwinner_rtc_sun6i_class_init,
  348. .instance_init = allwinner_rtc_sun6i_init,
  349. };
  350. static const TypeInfo allwinner_rtc_sun7i_info = {
  351. .name = TYPE_AW_RTC_SUN7I,
  352. .parent = TYPE_AW_RTC,
  353. .class_init = allwinner_rtc_sun7i_class_init,
  354. .instance_init = allwinner_rtc_sun7i_init,
  355. };
  356. static void allwinner_rtc_register(void)
  357. {
  358. type_register_static(&allwinner_rtc_info);
  359. type_register_static(&allwinner_rtc_sun4i_info);
  360. type_register_static(&allwinner_rtc_sun6i_info);
  361. type_register_static(&allwinner_rtc_sun7i_info);
  362. }
  363. type_init(allwinner_rtc_register)