hw/rtc/ls7a_rtc: Fix uninitialied bugs and toymatch writing function
[qemu/rayw.git] / hw / rtc / ls7a_rtc.c
blobb88a90de8b140dc7d052c85c1622bfb2607d8ac3
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /*
3 * Loongarch LS7A Real Time Clock emulation
5 * Copyright (C) 2021 Loongson Technology Corporation Limited
6 */
8 #include "qemu/osdep.h"
9 #include "hw/sysbus.h"
10 #include "hw/irq.h"
11 #include "include/hw/register.h"
12 #include "qemu/timer.h"
13 #include "sysemu/sysemu.h"
14 #include "qemu/cutils.h"
15 #include "qemu/log.h"
16 #include "migration/vmstate.h"
17 #include "hw/misc/unimp.h"
18 #include "sysemu/rtc.h"
19 #include "hw/registerfields.h"
21 #define SYS_TOYTRIM 0x20
22 #define SYS_TOYWRITE0 0x24
23 #define SYS_TOYWRITE1 0x28
24 #define SYS_TOYREAD0 0x2C
25 #define SYS_TOYREAD1 0x30
26 #define SYS_TOYMATCH0 0x34
27 #define SYS_TOYMATCH1 0x38
28 #define SYS_TOYMATCH2 0x3C
29 #define SYS_RTCCTRL 0x40
30 #define SYS_RTCTRIM 0x60
31 #define SYS_RTCWRTIE0 0x64
32 #define SYS_RTCREAD0 0x68
33 #define SYS_RTCMATCH0 0x6C
34 #define SYS_RTCMATCH1 0x70
35 #define SYS_RTCMATCH2 0x74
37 #define LS7A_RTC_FREQ 32768
38 #define TIMER_NUMS 3
40 * Shift bits and filed mask
43 FIELD(TOY, MON, 26, 6)
44 FIELD(TOY, DAY, 21, 5)
45 FIELD(TOY, HOUR, 16, 5)
46 FIELD(TOY, MIN, 10, 6)
47 FIELD(TOY, SEC, 4, 6)
48 FIELD(TOY, MSEC, 0, 4)
50 FIELD(TOY_MATCH, YEAR, 26, 6)
51 FIELD(TOY_MATCH, MON, 22, 4)
52 FIELD(TOY_MATCH, DAY, 17, 5)
53 FIELD(TOY_MATCH, HOUR, 12, 5)
54 FIELD(TOY_MATCH, MIN, 6, 6)
55 FIELD(TOY_MATCH, SEC, 0, 6)
57 FIELD(RTC_CTRL, RTCEN, 13, 1)
58 FIELD(RTC_CTRL, TOYEN, 11, 1)
59 FIELD(RTC_CTRL, EO, 8, 1)
61 #define TYPE_LS7A_RTC "ls7a_rtc"
62 OBJECT_DECLARE_SIMPLE_TYPE(LS7ARtcState, LS7A_RTC)
64 struct LS7ARtcState {
65 SysBusDevice parent_obj;
67 MemoryRegion iomem;
69 * Needed to preserve the tick_count across migration, even if the
70 * absolute value of the rtc_clock is different on the source and
71 * destination.
73 int64_t offset_toy;
74 int64_t offset_rtc;
75 uint64_t save_toy_mon;
76 uint64_t save_toy_year;
77 uint64_t save_rtc;
78 int64_t data;
79 int tidx;
80 uint32_t toymatch[3];
81 uint32_t toytrim;
82 uint32_t cntrctl;
83 uint32_t rtctrim;
84 uint32_t rtccount;
85 uint32_t rtcmatch[3];
86 QEMUTimer *toy_timer[TIMER_NUMS];
87 QEMUTimer *rtc_timer[TIMER_NUMS];
88 qemu_irq irq;
91 /* switch nanoseconds time to rtc ticks */
92 static inline uint64_t ls7a_rtc_ticks(void)
94 return qemu_clock_get_ns(rtc_clock) * LS7A_RTC_FREQ / NANOSECONDS_PER_SECOND;
97 /* switch rtc ticks to nanoseconds */
98 static inline uint64_t ticks_to_ns(uint64_t ticks)
100 return ticks * NANOSECONDS_PER_SECOND / LS7A_RTC_FREQ;
103 static inline bool toy_enabled(LS7ARtcState *s)
105 return FIELD_EX32(s->cntrctl, RTC_CTRL, TOYEN) &&
106 FIELD_EX32(s->cntrctl, RTC_CTRL, EO);
109 static inline bool rtc_enabled(LS7ARtcState *s)
111 return FIELD_EX32(s->cntrctl, RTC_CTRL, RTCEN) &&
112 FIELD_EX32(s->cntrctl, RTC_CTRL, EO);
115 /* parse toy value to struct tm */
116 static inline void toy_val_to_time_mon(uint64_t toy_val, struct tm *tm)
118 tm->tm_sec = FIELD_EX32(toy_val, TOY, SEC);
119 tm->tm_min = FIELD_EX32(toy_val, TOY, MIN);
120 tm->tm_hour = FIELD_EX32(toy_val, TOY, HOUR);
121 tm->tm_mday = FIELD_EX32(toy_val, TOY, DAY);
122 tm->tm_mon = FIELD_EX32(toy_val, TOY, MON) - 1;
125 static inline void toy_val_to_time_year(uint64_t toy_year, struct tm *tm)
127 tm->tm_year = toy_year;
130 /* parse struct tm to toy value */
131 static inline uint64_t toy_time_to_val_mon(struct tm tm)
133 uint64_t val = 0;
135 val = FIELD_DP32(val, TOY, MON, tm.tm_mon + 1);
136 val = FIELD_DP32(val, TOY, DAY, tm.tm_mday);
137 val = FIELD_DP32(val, TOY, HOUR, tm.tm_hour);
138 val = FIELD_DP32(val, TOY, MIN, tm.tm_min);
139 val = FIELD_DP32(val, TOY, SEC, tm.tm_sec);
140 return val;
143 static inline uint64_t toy_time_to_val_year(struct tm tm)
145 uint64_t year;
147 year = tm.tm_year;
148 return year;
151 static inline void toymatch_val_to_time(LS7ARtcState *s, uint64_t val, struct tm *tm)
153 qemu_get_timedate(tm, s->offset_toy);
154 tm->tm_sec = FIELD_EX32(val, TOY_MATCH, SEC);
155 tm->tm_min = FIELD_EX32(val, TOY_MATCH, MIN);
156 tm->tm_hour = FIELD_EX32(val, TOY_MATCH, HOUR);
157 tm->tm_mday = FIELD_EX32(val, TOY_MATCH, DAY);
158 tm->tm_mon = FIELD_EX32(val, TOY_MATCH, MON) - 1;
159 tm->tm_year += (FIELD_EX32(val, TOY_MATCH, YEAR) - (tm->tm_year & 0x3f));
162 static void toymatch_write(LS7ARtcState *s, uint64_t val, int num)
164 int64_t now, expire_time;
165 struct tm tm = {};
167 /* it do not support write when toy disabled */
168 if (toy_enabled(s)) {
169 s->toymatch[num] = val;
170 /* caculate expire time */
171 now = qemu_clock_get_ms(rtc_clock);
172 toymatch_val_to_time(s, val, &tm);
173 expire_time = now + (qemu_timedate_diff(&tm) - s->offset_toy) * 1000;
174 timer_mod(s->toy_timer[num], expire_time);
178 static void rtcmatch_write(LS7ARtcState *s, uint64_t val, int num)
180 uint64_t expire_ns;
182 /* it do not support write when toy disabled */
183 if (rtc_enabled(s)) {
184 s->rtcmatch[num] = val;
185 /* caculate expire time */
186 expire_ns = ticks_to_ns(val) - ticks_to_ns(s->offset_rtc);
187 timer_mod_ns(s->rtc_timer[num], expire_ns);
191 static void ls7a_toy_stop(LS7ARtcState *s)
193 int i;
194 struct tm tm;
196 * save time when disabled toy,
197 * because toy time not add counters.
199 qemu_get_timedate(&tm, s->offset_toy);
200 s->save_toy_mon = toy_time_to_val_mon(tm);
201 s->save_toy_year = toy_time_to_val_year(tm);
203 /* delete timers, and when re-enabled, recaculate expire time */
204 for (i = 0; i < TIMER_NUMS; i++) {
205 timer_del(s->toy_timer[i]);
209 static void ls7a_rtc_stop(LS7ARtcState *s)
211 int i;
212 uint64_t time;
214 /* save rtc time */
215 time = ls7a_rtc_ticks() + s->offset_rtc;
216 s->save_rtc = time;
218 /* delete timers, and when re-enabled, recaculate expire time */
219 for (i = 0; i < TIMER_NUMS; i++) {
220 timer_del(s->rtc_timer[i]);
224 static void ls7a_toy_start(LS7ARtcState *s)
226 int i;
227 uint64_t expire_time, now;
228 struct tm tm = {};
230 * need to recaculate toy offset
231 * and expire time when enable it.
233 toy_val_to_time_mon(s->save_toy_mon, &tm);
234 toy_val_to_time_year(s->save_toy_year, &tm);
236 s->offset_toy = qemu_timedate_diff(&tm);
237 now = qemu_clock_get_ms(rtc_clock);
239 /* recaculate expire time and enable timer */
240 for (i = 0; i < TIMER_NUMS; i++) {
241 toymatch_val_to_time(s, s->toymatch[i], &tm);
242 expire_time = now + (qemu_timedate_diff(&tm) - s->offset_toy) * 1000;
243 timer_mod(s->toy_timer[i], expire_time);
247 static void ls7a_rtc_start(LS7ARtcState *s)
249 int i;
250 uint64_t expire_time, now;
253 * need to recaculate rtc offset
254 * and expire time when enable it.
256 now = ls7a_rtc_ticks();
257 s->offset_rtc = s->save_rtc - now;
259 /* recaculate expire time and enable timer */
260 for (i = 0; i < TIMER_NUMS; i++) {
261 expire_time = ticks_to_ns(s->rtcmatch[i]) - ticks_to_ns(s->offset_rtc);
262 timer_mod_ns(s->rtc_timer[i], expire_time);
266 static uint64_t ls7a_rtc_read(void *opaque, hwaddr addr, unsigned size)
268 LS7ARtcState *s = LS7A_RTC(opaque);
269 struct tm tm;
270 int val = 0;
272 switch (addr) {
273 case SYS_TOYREAD0:
274 /* if toy disabled, read save toy time */
275 if (toy_enabled(s)) {
276 qemu_get_timedate(&tm, s->offset_toy);
277 val = toy_time_to_val_mon(tm);
278 } else {
279 /* read save mon val */
280 val = s->save_toy_mon;
282 break;
283 case SYS_TOYREAD1:
284 /* if toy disabled, read save toy time */
285 if (toy_enabled(s)) {
286 qemu_get_timedate(&tm, s->offset_toy);
287 val = tm.tm_year;
288 } else {
289 /* read save year val */
290 val = s->save_toy_year;
292 break;
293 case SYS_TOYMATCH0:
294 val = s->toymatch[0];
295 break;
296 case SYS_TOYMATCH1:
297 val = s->toymatch[1];
298 break;
299 case SYS_TOYMATCH2:
300 val = s->toymatch[2];
301 break;
302 case SYS_RTCCTRL:
303 val = s->cntrctl;
304 break;
305 case SYS_RTCREAD0:
306 /* if rtc disabled, read save rtc time */
307 if (rtc_enabled(s)) {
308 val = ls7a_rtc_ticks() + s->offset_rtc;
309 } else {
310 val = s->save_rtc;
312 break;
313 case SYS_RTCMATCH0:
314 val = s->rtcmatch[0];
315 break;
316 case SYS_RTCMATCH1:
317 val = s->rtcmatch[1];
318 break;
319 case SYS_RTCMATCH2:
320 val = s->rtcmatch[2];
321 break;
322 default:
323 val = 0;
324 break;
326 return val;
329 static void ls7a_rtc_write(void *opaque, hwaddr addr,
330 uint64_t val, unsigned size)
332 int old_toyen, old_rtcen, new_toyen, new_rtcen;
333 LS7ARtcState *s = LS7A_RTC(opaque);
334 struct tm tm;
336 switch (addr) {
337 case SYS_TOYWRITE0:
338 /* it do not support write when toy disabled */
339 if (toy_enabled(s)) {
340 qemu_get_timedate(&tm, s->offset_toy);
341 tm.tm_sec = FIELD_EX32(val, TOY, SEC);
342 tm.tm_min = FIELD_EX32(val, TOY, MIN);
343 tm.tm_hour = FIELD_EX32(val, TOY, HOUR);
344 tm.tm_mday = FIELD_EX32(val, TOY, DAY);
345 tm.tm_mon = FIELD_EX32(val, TOY, MON) - 1;
346 s->offset_toy = qemu_timedate_diff(&tm);
348 break;
349 case SYS_TOYWRITE1:
350 if (toy_enabled(s)) {
351 qemu_get_timedate(&tm, s->offset_toy);
352 tm.tm_year = val;
353 s->offset_toy = qemu_timedate_diff(&tm);
355 break;
356 case SYS_TOYMATCH0:
357 toymatch_write(s, val, 0);
358 break;
359 case SYS_TOYMATCH1:
360 toymatch_write(s, val, 1);
361 break;
362 case SYS_TOYMATCH2:
363 toymatch_write(s, val, 2);
364 break;
365 case SYS_RTCCTRL:
366 /* get old ctrl */
367 old_toyen = toy_enabled(s);
368 old_rtcen = rtc_enabled(s);
370 s->cntrctl = val;
371 /* get new ctrl */
372 new_toyen = toy_enabled(s);
373 new_rtcen = rtc_enabled(s);
376 * we do not consider if EO changed, as it always set at most time.
377 * toy or rtc enabled should start timer. otherwise, stop timer
379 if (old_toyen != new_toyen) {
380 if (new_toyen) {
381 ls7a_toy_start(s);
382 } else {
383 ls7a_toy_stop(s);
386 if (old_rtcen != new_rtcen) {
387 if (new_rtcen) {
388 ls7a_rtc_start(s);
389 } else {
390 ls7a_rtc_stop(s);
393 break;
394 case SYS_RTCWRTIE0:
395 if (rtc_enabled(s)) {
396 s->offset_rtc = val - ls7a_rtc_ticks();
398 break;
399 case SYS_RTCMATCH0:
400 rtcmatch_write(s, val, 0);
401 break;
402 case SYS_RTCMATCH1:
403 rtcmatch_write(s, val, 1);
404 break;
405 case SYS_RTCMATCH2:
406 rtcmatch_write(s, val, 2);
407 break;
408 default:
409 break;
413 static const MemoryRegionOps ls7a_rtc_ops = {
414 .read = ls7a_rtc_read,
415 .write = ls7a_rtc_write,
416 .endianness = DEVICE_LITTLE_ENDIAN,
417 .valid = {
418 .min_access_size = 4,
419 .max_access_size = 4,
423 static void toy_timer_cb(void *opaque)
425 LS7ARtcState *s = opaque;
427 if (toy_enabled(s)) {
428 qemu_irq_pulse(s->irq);
432 static void rtc_timer_cb(void *opaque)
434 LS7ARtcState *s = opaque;
436 if (rtc_enabled(s)) {
437 qemu_irq_pulse(s->irq);
441 static void ls7a_rtc_realize(DeviceState *dev, Error **errp)
443 int i;
444 SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
445 LS7ARtcState *d = LS7A_RTC(sbd);
446 memory_region_init_io(&d->iomem, NULL, &ls7a_rtc_ops,
447 (void *)d, "ls7a_rtc", 0x100);
449 sysbus_init_irq(sbd, &d->irq);
451 sysbus_init_mmio(sbd, &d->iomem);
452 for (i = 0; i < TIMER_NUMS; i++) {
453 d->toymatch[i] = 0;
454 d->rtcmatch[i] = 0;
455 d->toy_timer[i] = timer_new_ms(rtc_clock, toy_timer_cb, d);
456 d->rtc_timer[i] = timer_new_ms(rtc_clock, rtc_timer_cb, d);
458 d->offset_toy = 0;
459 d->offset_rtc = 0;
460 d->save_toy_mon = 0;
461 d->save_toy_year = 0;
462 d->save_rtc = 0;
464 create_unimplemented_device("mmio fallback 1", 0x10013ffc, 0x4);
467 static int ls7a_rtc_pre_save(void *opaque)
469 LS7ARtcState *s = LS7A_RTC(opaque);
471 ls7a_toy_stop(s);
472 ls7a_rtc_stop(s);
474 return 0;
477 static int ls7a_rtc_post_load(void *opaque, int version_id)
479 LS7ARtcState *s = LS7A_RTC(opaque);
480 if (toy_enabled(s)) {
481 ls7a_toy_start(s);
484 if (rtc_enabled(s)) {
485 ls7a_rtc_start(s);
488 return 0;
491 static const VMStateDescription vmstate_ls7a_rtc = {
492 .name = "ls7a_rtc",
493 .version_id = 1,
494 .minimum_version_id = 1,
495 .pre_save = ls7a_rtc_pre_save,
496 .post_load = ls7a_rtc_post_load,
497 .fields = (VMStateField[]) {
498 VMSTATE_INT64(offset_toy, LS7ARtcState),
499 VMSTATE_INT64(offset_rtc, LS7ARtcState),
500 VMSTATE_UINT64(save_toy_mon, LS7ARtcState),
501 VMSTATE_UINT64(save_toy_year, LS7ARtcState),
502 VMSTATE_UINT64(save_rtc, LS7ARtcState),
503 VMSTATE_UINT32_ARRAY(toymatch, LS7ARtcState, TIMER_NUMS),
504 VMSTATE_UINT32_ARRAY(rtcmatch, LS7ARtcState, TIMER_NUMS),
505 VMSTATE_UINT32(cntrctl, LS7ARtcState),
506 VMSTATE_END_OF_LIST()
510 static void ls7a_rtc_class_init(ObjectClass *klass, void *data)
512 DeviceClass *dc = DEVICE_CLASS(klass);
513 dc->vmsd = &vmstate_ls7a_rtc;
514 dc->realize = ls7a_rtc_realize;
515 dc->desc = "ls7a rtc";
518 static const TypeInfo ls7a_rtc_info = {
519 .name = TYPE_LS7A_RTC,
520 .parent = TYPE_SYS_BUS_DEVICE,
521 .instance_size = sizeof(LS7ARtcState),
522 .class_init = ls7a_rtc_class_init,
525 static void ls7a_rtc_register_types(void)
527 type_register_static(&ls7a_rtc_info);
530 type_init(ls7a_rtc_register_types)