Merge tag 'for-upstream' of git://repo.or.cz/qemu/kevin into staging
[qemu/ar7.git] / hw / rtc / ls7a_rtc.c
blobfe6710310f61971eb9c26f3307cb69449f57af0e
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(uint64_t val, struct tm *tm)
153 tm->tm_sec = FIELD_EX32(val, TOY_MATCH, SEC);
154 tm->tm_min = FIELD_EX32(val, TOY_MATCH, MIN);
155 tm->tm_hour = FIELD_EX32(val, TOY_MATCH, HOUR);
156 tm->tm_mday = FIELD_EX32(val, TOY_MATCH, DAY);
157 tm->tm_mon = FIELD_EX32(val, TOY_MATCH, MON) - 1;
158 tm->tm_year += (FIELD_EX32(val, TOY_MATCH, YEAR) - (tm->tm_year & 0x3f));
161 static void toymatch_write(LS7ARtcState *s, struct tm *tm, uint64_t val, int num)
163 int64_t now, expire_time;
165 /* it do not support write when toy disabled */
166 if (toy_enabled(s)) {
167 s->toymatch[num] = val;
168 /* caculate expire time */
169 now = qemu_clock_get_ms(rtc_clock);
170 toymatch_val_to_time(val, tm);
171 expire_time = now + (qemu_timedate_diff(tm) - s->offset_toy) * 1000;
172 timer_mod(s->toy_timer[num], expire_time);
176 static void rtcmatch_write(LS7ARtcState *s, uint64_t val, int num)
178 uint64_t expire_ns;
180 /* it do not support write when toy disabled */
181 if (rtc_enabled(s)) {
182 s->rtcmatch[num] = val;
183 /* caculate expire time */
184 expire_ns = ticks_to_ns(val) - ticks_to_ns(s->offset_rtc);
185 timer_mod_ns(s->rtc_timer[num], expire_ns);
189 static void ls7a_toy_stop(LS7ARtcState *s)
191 int i;
192 struct tm tm;
194 * save time when disabled toy,
195 * because toy time not add counters.
197 qemu_get_timedate(&tm, s->offset_toy);
198 s->save_toy_mon = toy_time_to_val_mon(tm);
199 s->save_toy_year = toy_time_to_val_year(tm);
201 /* delete timers, and when re-enabled, recaculate expire time */
202 for (i = 0; i < TIMER_NUMS; i++) {
203 timer_del(s->toy_timer[i]);
207 static void ls7a_rtc_stop(LS7ARtcState *s)
209 int i;
210 uint64_t time;
212 /* save rtc time */
213 time = ls7a_rtc_ticks() + s->offset_rtc;
214 s->save_rtc = time;
216 /* delete timers, and when re-enabled, recaculate expire time */
217 for (i = 0; i < TIMER_NUMS; i++) {
218 timer_del(s->rtc_timer[i]);
222 static void ls7a_toy_start(LS7ARtcState *s)
224 int i;
225 uint64_t expire_time, now;
226 struct tm tm;
228 * need to recaculate toy offset
229 * and expire time when enable it.
231 toy_val_to_time_mon(s->save_toy_mon, &tm);
232 toy_val_to_time_year(s->save_toy_year, &tm);
234 s->offset_toy = qemu_timedate_diff(&tm);
235 now = qemu_clock_get_ms(rtc_clock);
237 /* recaculate expire time and enable timer */
238 for (i = 0; i < TIMER_NUMS; i++) {
239 toymatch_val_to_time(s->toymatch[i], &tm);
240 expire_time = now + (qemu_timedate_diff(&tm) - s->offset_toy) * 1000;
241 timer_mod(s->toy_timer[i], expire_time);
245 static void ls7a_rtc_start(LS7ARtcState *s)
247 int i;
248 uint64_t expire_time, now;
251 * need to recaculate rtc offset
252 * and expire time when enable it.
254 now = ls7a_rtc_ticks();
255 s->offset_rtc = s->save_rtc - now;
257 /* recaculate expire time and enable timer */
258 for (i = 0; i < TIMER_NUMS; i++) {
259 expire_time = ticks_to_ns(s->rtcmatch[i]) - ticks_to_ns(s->offset_rtc);
260 timer_mod_ns(s->rtc_timer[i], expire_time);
264 static uint64_t ls7a_rtc_read(void *opaque, hwaddr addr, unsigned size)
266 LS7ARtcState *s = LS7A_RTC(opaque);
267 struct tm tm;
268 int val = 0;
270 switch (addr) {
271 case SYS_TOYREAD0:
272 /* if toy disabled, read save toy time */
273 if (toy_enabled(s)) {
274 qemu_get_timedate(&tm, s->offset_toy);
275 val = toy_time_to_val_mon(tm);
276 } else {
277 /* read save mon val */
278 val = s->save_toy_mon;
280 break;
281 case SYS_TOYREAD1:
282 /* if toy disabled, read save toy time */
283 if (toy_enabled(s)) {
284 qemu_get_timedate(&tm, s->offset_toy);
285 val = tm.tm_year;
286 } else {
287 /* read save year val */
288 val = s->save_toy_year;
290 break;
291 case SYS_TOYMATCH0:
292 val = s->toymatch[0];
293 break;
294 case SYS_TOYMATCH1:
295 val = s->toymatch[1];
296 break;
297 case SYS_TOYMATCH2:
298 val = s->toymatch[2];
299 break;
300 case SYS_RTCCTRL:
301 val = s->cntrctl;
302 break;
303 case SYS_RTCREAD0:
304 /* if rtc disabled, read save rtc time */
305 if (rtc_enabled(s)) {
306 val = ls7a_rtc_ticks() + s->offset_rtc;
307 } else {
308 val = s->save_rtc;
310 break;
311 case SYS_RTCMATCH0:
312 val = s->rtcmatch[0];
313 break;
314 case SYS_RTCMATCH1:
315 val = s->rtcmatch[1];
316 break;
317 case SYS_RTCMATCH2:
318 val = s->rtcmatch[2];
319 break;
320 default:
321 val = 0;
322 break;
324 return val;
327 static void ls7a_rtc_write(void *opaque, hwaddr addr,
328 uint64_t val, unsigned size)
330 int old_toyen, old_rtcen, new_toyen, new_rtcen;
331 LS7ARtcState *s = LS7A_RTC(opaque);
332 struct tm tm;
334 switch (addr) {
335 case SYS_TOYWRITE0:
336 /* it do not support write when toy disabled */
337 if (toy_enabled(s)) {
338 qemu_get_timedate(&tm, s->offset_toy);
339 tm.tm_sec = FIELD_EX32(val, TOY, SEC);
340 tm.tm_min = FIELD_EX32(val, TOY, MIN);
341 tm.tm_hour = FIELD_EX32(val, TOY, HOUR);
342 tm.tm_mday = FIELD_EX32(val, TOY, DAY);
343 tm.tm_mon = FIELD_EX32(val, TOY, MON) - 1;
344 s->offset_toy = qemu_timedate_diff(&tm);
346 break;
347 case SYS_TOYWRITE1:
348 if (toy_enabled(s)) {
349 qemu_get_timedate(&tm, s->offset_toy);
350 tm.tm_year = val;
351 s->offset_toy = qemu_timedate_diff(&tm);
353 break;
354 case SYS_TOYMATCH0:
355 toymatch_write(s, &tm, val, 0);
356 break;
357 case SYS_TOYMATCH1:
358 toymatch_write(s, &tm, val, 1);
359 break;
360 case SYS_TOYMATCH2:
361 toymatch_write(s, &tm, val, 2);
362 break;
363 case SYS_RTCCTRL:
364 /* get old ctrl */
365 old_toyen = toy_enabled(s);
366 old_rtcen = rtc_enabled(s);
368 s->cntrctl = val;
369 /* get new ctrl */
370 new_toyen = toy_enabled(s);
371 new_rtcen = rtc_enabled(s);
374 * we do not consider if EO changed, as it always set at most time.
375 * toy or rtc enabled should start timer. otherwise, stop timer
377 if (old_toyen != new_toyen) {
378 if (new_toyen) {
379 ls7a_toy_start(s);
380 } else {
381 ls7a_toy_stop(s);
384 if (old_rtcen != new_rtcen) {
385 if (new_rtcen) {
386 ls7a_rtc_start(s);
387 } else {
388 ls7a_rtc_stop(s);
391 break;
392 case SYS_RTCWRTIE0:
393 if (rtc_enabled(s)) {
394 s->offset_rtc = val - ls7a_rtc_ticks();
396 break;
397 case SYS_RTCMATCH0:
398 rtcmatch_write(s, val, 0);
399 break;
400 case SYS_RTCMATCH1:
401 rtcmatch_write(s, val, 1);
402 break;
403 case SYS_RTCMATCH2:
404 rtcmatch_write(s, val, 2);
405 break;
406 default:
407 break;
411 static const MemoryRegionOps ls7a_rtc_ops = {
412 .read = ls7a_rtc_read,
413 .write = ls7a_rtc_write,
414 .endianness = DEVICE_LITTLE_ENDIAN,
415 .valid = {
416 .min_access_size = 4,
417 .max_access_size = 4,
421 static void toy_timer_cb(void *opaque)
423 LS7ARtcState *s = opaque;
425 if (toy_enabled(s)) {
426 qemu_irq_pulse(s->irq);
430 static void rtc_timer_cb(void *opaque)
432 LS7ARtcState *s = opaque;
434 if (rtc_enabled(s)) {
435 qemu_irq_pulse(s->irq);
439 static void ls7a_rtc_realize(DeviceState *dev, Error **errp)
441 int i;
442 SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
443 LS7ARtcState *d = LS7A_RTC(sbd);
444 memory_region_init_io(&d->iomem, NULL, &ls7a_rtc_ops,
445 (void *)d, "ls7a_rtc", 0x100);
447 sysbus_init_irq(sbd, &d->irq);
449 sysbus_init_mmio(sbd, &d->iomem);
450 for (i = 0; i < TIMER_NUMS; i++) {
451 d->toymatch[i] = 0;
452 d->rtcmatch[i] = 0;
453 d->toy_timer[i] = timer_new_ms(rtc_clock, toy_timer_cb, d);
454 d->rtc_timer[i] = timer_new_ms(rtc_clock, rtc_timer_cb, d);
456 d->offset_toy = 0;
457 d->offset_rtc = 0;
458 d->save_toy_mon = 0;
459 d->save_toy_year = 0;
460 d->save_rtc = 0;
462 create_unimplemented_device("mmio fallback 1", 0x10013ffc, 0x4);
465 static int ls7a_rtc_pre_save(void *opaque)
467 LS7ARtcState *s = LS7A_RTC(opaque);
469 ls7a_toy_stop(s);
470 ls7a_rtc_stop(s);
472 return 0;
475 static int ls7a_rtc_post_load(void *opaque, int version_id)
477 LS7ARtcState *s = LS7A_RTC(opaque);
478 if (toy_enabled(s)) {
479 ls7a_toy_start(s);
482 if (rtc_enabled(s)) {
483 ls7a_rtc_start(s);
486 return 0;
489 static const VMStateDescription vmstate_ls7a_rtc = {
490 .name = "ls7a_rtc",
491 .version_id = 1,
492 .minimum_version_id = 1,
493 .pre_save = ls7a_rtc_pre_save,
494 .post_load = ls7a_rtc_post_load,
495 .fields = (VMStateField[]) {
496 VMSTATE_INT64(offset_toy, LS7ARtcState),
497 VMSTATE_INT64(offset_rtc, LS7ARtcState),
498 VMSTATE_UINT64(save_toy_mon, LS7ARtcState),
499 VMSTATE_UINT64(save_toy_year, LS7ARtcState),
500 VMSTATE_UINT64(save_rtc, LS7ARtcState),
501 VMSTATE_UINT32_ARRAY(toymatch, LS7ARtcState, TIMER_NUMS),
502 VMSTATE_UINT32_ARRAY(rtcmatch, LS7ARtcState, TIMER_NUMS),
503 VMSTATE_UINT32(cntrctl, LS7ARtcState),
504 VMSTATE_END_OF_LIST()
508 static void ls7a_rtc_class_init(ObjectClass *klass, void *data)
510 DeviceClass *dc = DEVICE_CLASS(klass);
511 dc->vmsd = &vmstate_ls7a_rtc;
512 dc->realize = ls7a_rtc_realize;
513 dc->desc = "ls7a rtc";
516 static const TypeInfo ls7a_rtc_info = {
517 .name = TYPE_LS7A_RTC,
518 .parent = TYPE_SYS_BUS_DEVICE,
519 .instance_size = sizeof(LS7ARtcState),
520 .class_init = ls7a_rtc_class_init,
523 static void ls7a_rtc_register_types(void)
525 type_register_static(&ls7a_rtc_info);
528 type_init(ls7a_rtc_register_types)