1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27#include "qemu/osdep.h"
28#include <stdint.h>
29#include "qemu-common.h"
30#include "hw/sysbus.h"
31#include "hw/register.h"
32#include "qemu/bitops.h"
33#include "qemu/log.h"
34#include "qemu/module.h"
35#include "hw/irq.h"
36#include "qemu/cutils.h"
37#include "sysemu/sysemu.h"
38#include "trace.h"
39#include "hw/rtc/xlnx-zynqmp-rtc.h"
40#include "migration/vmstate.h"
41#include "hw/qdev-properties.h"
42#include "qemu/timer.h"
43
44#ifndef XLNX_ZYNQMP_RTC_ERR_DEBUG
45#define XLNX_ZYNQMP_RTC_ERR_DEBUG 0
46#endif
47
48#if XLNX_ZYNQMP_RTC_ERR_DEBUG
49 #define DPRINT(fmt, args...) do { \
50 if (XLNX_ZYNQMP_RTC_ERR_DEBUG) { \
51 qemu_log(fmt, ##args); \
52 } \
53 } while (0)
54
55 #define DPRINT_TM(fmt, args...) do { \
56 if (XLNX_ZYNQMP_RTC_ERR_DEBUG) { \
57 qemu_log("[%lld] -> " fmt,\
58 qemu_clock_get_ns(rtc_clock) / NANOSECONDS_PER_SECOND,\
59 ##args);\
60 } \
61 } while (0)
62#else
63 #define DPRINT(fmt, args...) do {} while (0)
64 #define DPRINT_TM(fmt, args...) do {} while (0)
65#endif
66
67enum version_id {
68 IP_VERSION_1_0_1 = 0,
69 IP_VERSION_2_0_0 = 1
70};
71
72struct version_item_lookup {
73 enum version_id id;
74 const char *str;
75};
76
77static struct version_item_lookup version_table_lookup[] = {
78 { IP_VERSION_1_0_1, "1.0.1" },
79 { IP_VERSION_2_0_0, "2.0.0" }
80};
81
82static Property xlnx_rtc_properties[] = {
83 DEFINE_PROP_STRING("version", XlnxZynqMPRTC, cfg.version),
84 DEFINE_PROP_END_OF_LIST(),
85};
86
87
88static uint32_t get_host_time_now(void)
89{
90 int64_t host_time_now = qemu_clock_get_ns(rtc_clock);
91 return host_time_now / NANOSECONDS_PER_SECOND;
92}
93
94
95static uint32_t get_qemu_time_now(XlnxZynqMPRTC *s)
96{
97 return get_host_time_now() - s->tick_offset;
98}
99
100
101static uint32_t get_guest_time_now(XlnxZynqMPRTC *s)
102{
103 return get_qemu_time_now(s) - s->guest_offset;
104}
105
106
107static uint32_t host_time_from_guest(XlnxZynqMPRTC *s, uint32_t guest_time)
108{
109 return s->tick_offset + s->guest_offset + guest_time;
110}
111
112static void rtc_int_update_irq(XlnxZynqMPRTC *s)
113{
114 uint32_t pending = s->regs[R_RTC_INT_STATUS] & ~s->regs[R_RTC_INT_MASK];
115 qemu_set_irq(s->irq_rtc_int[0],
116 !!(pending & R_RTC_INT_STATUS_ALARM_MASK));
117 qemu_set_irq(s->irq_rtc_int[1],
118 !!(pending & R_RTC_INT_STATUS_SECONDS_MASK));
119
120}
121
122static void addr_error_int_update_irq(XlnxZynqMPRTC *s)
123{
124 bool pending = s->regs[R_ADDR_ERROR] & ~s->regs[R_ADDR_ERROR_INT_MASK];
125 qemu_set_irq(s->irq_addr_error_int, pending);
126}
127
128static void update_alarm(XlnxZynqMPRTC *s)
129{
130 uint32_t alarm;
131 uint32_t host_time_now;
132
133 timer_del(s->alarm);
134
135
136
137
138
139 alarm = host_time_from_guest(s, s->regs[R_ALARM]);
140 host_time_now = get_host_time_now();
141
142
143
144
145
146
147
148
149 if (alarm > host_time_now) {
150 timer_mod(s->alarm, alarm * NANOSECONDS_PER_SECOND);
151 } else if (alarm == host_time_now) {
152 s->regs[R_RTC_INT_STATUS] = FIELD_DP32(s->regs[R_RTC_INT_STATUS],
153 RTC_INT_STATUS, ALARM, 1);
154
155 rtc_int_update_irq(s);
156 } else {
157 qemu_log_mask(LOG_GUEST_ERROR, "%06d : %s() attempting to arm the "
158 "alarm timer with a timestamp that is earlier than "
159 "the current time: \talarm=%u,\n\tguest time=%u,\n",
160 __LINE__, __func__, alarm, get_guest_time_now(s));
161 }
162}
163
164static void update_seconds(XlnxZynqMPRTC *s)
165{
166 uint32_t next_sec;
167
168 timer_del(s->sec_tick);
169
170 next_sec = get_host_time_now() + 1;
171 timer_mod(s->sec_tick, next_sec * NANOSECONDS_PER_SECOND);
172}
173
174static void rtc_set_time_write_postw(RegisterInfo *reg, uint64_t val64)
175{
176 XlnxZynqMPRTC *s = XLNX_ZYNQMP_RTC(reg->opaque);
177
178 s->regs[R_SET_TIME_WRITE] = val64;
179
180 s->regs[R_SET_TIME_READ] = val64;
181
182 s->guest_offset = get_qemu_time_now(s) - s->regs[R_SET_TIME_READ];
183 DPRINT_TM("%06d : %s()\n", __LINE__, __func__);
184 DPRINT_TM("Time Marks:\n\tQEMU Time = %u,\n \tHost Time = %u,\n"
185 " \ts->tick_offset = %u,\n",
186 get_qemu_time_now(s), get_host_time_now(), s->tick_offset);
187 DPRINT("\tguest_offset = %010u\n", s->guest_offset);
188}
189
190static void rtc_calib_write_postw(RegisterInfo *reg, uint64_t val64)
191{
192 XlnxZynqMPRTC *s = XLNX_ZYNQMP_RTC(reg->opaque);
193
194 s->regs[R_CALIB_READ] = val64;
195
196
197
198
199 s->regs[R_CURRENT_TICK] = FIELD_EX32(s->regs[R_CALIB_READ],
200 CALIB_WRITE, MAX_TICK);
201}
202
203static uint64_t current_time_postr(RegisterInfo *reg, uint64_t val64)
204{
205 XlnxZynqMPRTC *s = XLNX_ZYNQMP_RTC(reg->opaque);
206 uint32_t guest_time_now = get_guest_time_now(s);
207 return guest_time_now;
208}
209
210static void alarm_postw(RegisterInfo *reg, uint64_t val64)
211{
212 XlnxZynqMPRTC *s = XLNX_ZYNQMP_RTC(reg->opaque);
213
214 s->regs[R_ALARM] = val64;
215 update_alarm(s);
216}
217
218static uint64_t rtc_int_en_prew(RegisterInfo *reg, uint64_t val64)
219{
220 XlnxZynqMPRTC *s = XLNX_ZYNQMP_RTC(reg->opaque);
221
222 s->regs[R_RTC_INT_MASK] &= ~val64;
223 if (FIELD_EX32(s->regs[R_RTC_INT_MASK], RTC_INT_MASK, SECONDS) == 1) {
224 update_seconds(s);
225 }
226 rtc_int_update_irq(s);
227 return 0;
228}
229
230static uint64_t rtc_int_dis_prew(RegisterInfo *reg, uint64_t val64)
231{
232 XlnxZynqMPRTC *s = XLNX_ZYNQMP_RTC(reg->opaque);
233
234 s->regs[R_RTC_INT_MASK] |= val64;
235 rtc_int_update_irq(s);
236 return 0;
237}
238
239static void rtc_int_status_postw(RegisterInfo *reg, uint64_t val64)
240{
241 XlnxZynqMPRTC *s = XLNX_ZYNQMP_RTC(reg->opaque);
242
243 if (FIELD_EX32(s->regs[R_RTC_INT_STATUS], RTC_INT_STATUS, SECONDS) == 0) {
244 update_seconds(s);
245 }
246 rtc_int_update_irq(s);
247}
248
249static void addr_error_set_status(void *opaque)
250{
251 RegisterInfo *ri = *((RegisterInfo **)((RegisterInfoArray*)opaque)->r);
252 XlnxZynqMPRTC *s = (XlnxZynqMPRTC *)ri->opaque;
253
254 s->regs[R_ADDR_ERROR] = FIELD_DP32(s->regs[R_ADDR_ERROR],
255 ADDR_ERROR, STATUS, 1);
256 addr_error_int_update_irq(s);
257}
258
259static void addr_error_postw(RegisterInfo *reg, uint64_t val64)
260{
261 XlnxZynqMPRTC *s = XLNX_ZYNQMP_RTC(reg->opaque);
262 addr_error_int_update_irq(s);
263}
264
265static uint64_t addr_error_int_en_prew(RegisterInfo *reg, uint64_t val64)
266{
267 XlnxZynqMPRTC *s = XLNX_ZYNQMP_RTC(reg->opaque);
268
269 s->regs[R_ADDR_ERROR_INT_MASK] &= ~val64;
270 addr_error_int_update_irq(s);
271 return 0;
272}
273
274static uint64_t addr_error_int_dis_prew(RegisterInfo *reg, uint64_t val64)
275{
276 XlnxZynqMPRTC *s = XLNX_ZYNQMP_RTC(reg->opaque);
277
278 s->regs[R_ADDR_ERROR_INT_MASK] |= val64;;
279 addr_error_int_update_irq(s);
280 return 0;
281}
282
283static const RegisterAccessInfo rtc_regs_info[] = {
284 { .name = "SET_TIME_WRITE", .addr = A_SET_TIME_WRITE,
285 .post_write = rtc_set_time_write_postw,
286 },{ .name = "SET_TIME_READ", .addr = A_SET_TIME_READ,
287 .ro = 0xffffffff,
288 },{ .name = "CALIB_WRITE", .addr = A_CALIB_WRITE,
289 .post_write = rtc_calib_write_postw,
290 },{ .name = "CALIB_READ", .addr = A_CALIB_READ,
291 .ro = 0x1fffff,
292 },{ .name = "CURRENT_TIME", .addr = A_CURRENT_TIME,
293 .ro = 0xffffffff,
294 .post_read = current_time_postr,
295 },{ .name = "CURRENT_TICK", .addr = A_CURRENT_TICK,
296 .ro = 0xffff,
297 },{ .name = "ALARM", .addr = A_ALARM,
298 .post_write = alarm_postw,
299 .reset = 0x00000000,
300 },{ .name = "RTC_INT_STATUS", .addr = A_RTC_INT_STATUS,
301 .w1c = 0x3,
302 .post_write = rtc_int_status_postw,
303 },{ .name = "RTC_INT_MASK", .addr = A_RTC_INT_MASK,
304 .reset = 0x3,
305 .ro = 0x3,
306 },{ .name = "RTC_INT_EN", .addr = A_RTC_INT_EN,
307 .pre_write = rtc_int_en_prew,
308 },{ .name = "RTC_INT_DIS", .addr = A_RTC_INT_DIS,
309 .pre_write = rtc_int_dis_prew,
310 },{ .name = "ADDR_ERROR", .addr = A_ADDR_ERROR,
311 .w1c = 0x1,
312 .post_write = addr_error_postw,
313 },{ .name = "ADDR_ERROR_INT_MASK", .addr = A_ADDR_ERROR_INT_MASK,
314 .reset = 0x1,
315 .ro = 0x1,
316 },{ .name = "ADDR_ERROR_INT_EN", .addr = A_ADDR_ERROR_INT_EN,
317 .pre_write = addr_error_int_en_prew,
318 },{ .name = "ADDR_ERROR_INT_DIS", .addr = A_ADDR_ERROR_INT_DIS,
319 .pre_write = addr_error_int_dis_prew,
320 },{ .name = "CONTROL", .addr = A_CONTROL,
321 .reset = 0x1000000,
322 .rsvd = 0x70fffffe,
323 },{ .name = "SAFETY_CHK", .addr = A_SAFETY_CHK,
324 }
325};
326
327static const RegisterAccessInfo rtc_regs_control_v2_info = {
328 .name = "CONTROL", .addr = A_CONTROL,
329 .reset = 0x2000000, .rsvd = 0x70fffffe,
330};
331
332static enum version_id version_id_lookup(const char *str)
333{
334 uint32_t i;
335 enum version_id version;
336
337 version = IP_VERSION_1_0_1;
338
339 if (str) {
340 for (i = 0; i < ARRAY_SIZE(version_table_lookup); ++i) {
341 if (!strcmp(str, version_table_lookup[i].str)) {
342 version = version_table_lookup[i].id;
343 break;
344 }
345 }
346 }
347
348 return version;
349}
350
351static void clear_time(XlnxZynqMPRTC *s)
352{
353 time_t qemu_time;
354
355
356
357
358 uint32_t host_time = get_host_time_now();
359
360
361
362
363
364
365 struct tm qemu_tm = {0};
366 qemu_get_timedate(&qemu_tm, 0);
367 qemu_time = mktimegm(&qemu_tm);
368
369
370
371
372 s->tick_offset = host_time - qemu_time;
373
374
375
376
377
378
379
380 s->regs[R_SET_TIME_WRITE] = qemu_time;
381 s->regs[R_SET_TIME_READ] = qemu_time;
382 s->guest_offset = qemu_time - s->regs[R_SET_TIME_READ];
383
384 DPRINT_TM("%06d : %s()\n", __LINE__, __func__);
385 DPRINT_TM("Time Marks:\n\tQEMU Time = %lu,\n\tHost Time = %u,\n"
386 " \ts->tick_offset = %u,\n",
387 qemu_time, host_time, s->tick_offset);
388 DPRINT("\tguest_offset = %010u\n", s->guest_offset);
389 DPRINT("\t%04u-%02u-%02u-T%02u:%02u:%02u (yyyy-mm-ddThh:mm:ss ISO-8601)\n",
390 qemu_tm.tm_year + 1900, qemu_tm.tm_mon + 1, qemu_tm.tm_mday,
391 qemu_tm.tm_hour, qemu_tm.tm_min, qemu_tm.tm_sec);
392}
393
394static void rtc_reset(DeviceState *dev)
395{
396 XlnxZynqMPRTC *s = XLNX_ZYNQMP_RTC(dev);
397 unsigned int i;
398
399 for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) {
400 register_reset(&s->regs_info[i]);
401 }
402
403 if (version_id_lookup(s->cfg.version) == IP_VERSION_2_0_0) {
404 s->regs_info[R_CONTROL].access = &rtc_regs_control_v2_info;
405 register_reset(&s->regs_info[R_CONTROL]);
406 }
407
408 clear_time(s);
409}
410
411static void alarm_timeout_cb(void *opaque)
412{
413 XlnxZynqMPRTC *s = (XlnxZynqMPRTC *)opaque;
414
415 s->regs[R_RTC_INT_STATUS] = FIELD_DP32(s->regs[R_RTC_INT_STATUS],
416 RTC_INT_STATUS, ALARM, 1);
417
418 rtc_int_update_irq(s);
419}
420
421static void second_timeout_cb(void *opaque)
422{
423 XlnxZynqMPRTC *s = (XlnxZynqMPRTC *)opaque;
424
425 s->regs[R_RTC_INT_STATUS] = FIELD_DP32(s->regs[R_RTC_INT_STATUS],
426 RTC_INT_STATUS, SECONDS, 1);
427
428 rtc_int_update_irq(s);
429}
430
431static uint64_t rtc_register_read_memory(void *opaque, hwaddr addr,
432 unsigned size)
433{
434 if (addr >= (XLNX_ZYNQMP_RTC_R_MAX * 4)) {
435 DPRINT_TM("%06d : %s()\n", __LINE__, __func__);
436 DPRINT_TM("\tAttempting to Read from invalid RTC Memory"
437 " Space 0x%08lx\n", addr);
438 addr_error_set_status(opaque);
439 return (uint64_t)0;
440 }
441
442 return register_read_memory(opaque, addr, size);
443}
444
445static void rtc_register_write_memory(void *opaque, hwaddr addr, uint64_t value,
446 unsigned size)
447{
448 if (addr >= (XLNX_ZYNQMP_RTC_R_MAX * 4)) {
449 DPRINT_TM("%06d : %s()\n", __LINE__, __func__);
450 DPRINT_TM("\tAttempting to Write to invalid RTC Memory Space 0x%08lx\n",
451 addr);
452 addr_error_set_status(opaque);
453 return;
454 }
455
456 register_write_memory(opaque, addr, value, size);
457}
458
459static const MemoryRegionOps rtc_ops = {
460 .read = rtc_register_read_memory,
461 .write = rtc_register_write_memory,
462 .endianness = DEVICE_LITTLE_ENDIAN,
463 .valid = {
464 .min_access_size = 4,
465 .max_access_size = 4,
466 },
467};
468
469static void rtc_init(Object *obj)
470{
471 XlnxZynqMPRTC *s = XLNX_ZYNQMP_RTC(obj);
472 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
473 RegisterInfoArray *reg_array;
474
475 memory_region_init(&s->iomem, obj, TYPE_XLNX_ZYNQMP_RTC,
476 XLNX_ZYNQMP_RTC_IO_REGION_SZ);
477
478 reg_array =
479 register_init_block32(DEVICE(obj), rtc_regs_info,
480 ARRAY_SIZE(rtc_regs_info),
481 s->regs_info, s->regs,
482 &rtc_ops,
483 XLNX_ZYNQMP_RTC_ERR_DEBUG,
484 XLNX_ZYNQMP_RTC_IO_REGION_SZ);
485 memory_region_add_subregion(&s->iomem,
486 0x0,
487 ®_array->mem);
488 sysbus_init_mmio(sbd, &s->iomem);
489
490 sysbus_init_irq(sbd, &s->irq_addr_error_int);
491
492 sysbus_init_irq(sbd, &s->irq_rtc_int[0]);
493
494 sysbus_init_irq(sbd, &s->irq_rtc_int[1]);
495
496 DPRINT_TM("%06d : %s()\n", __LINE__, __func__);
497 clear_time(s);
498 s->alarm = timer_new_ns(rtc_clock, alarm_timeout_cb, s);
499 s->sec_tick = timer_new_ns(rtc_clock, second_timeout_cb, s);
500}
501
502static int rtc_pre_save(void *opaque)
503{
504 XlnxZynqMPRTC *s = opaque;
505 int64_t now = qemu_clock_get_ns(rtc_clock) / NANOSECONDS_PER_SECOND;
506
507
508 s->tick_offset = s->tick_offset + now;
509
510 return 0;
511}
512
513static int rtc_post_load(void *opaque, int version_id)
514{
515 XlnxZynqMPRTC *s = opaque;
516 int64_t now = qemu_clock_get_ns(rtc_clock) / NANOSECONDS_PER_SECOND;
517
518
519
520
521
522 s->tick_offset = s->tick_offset - now;
523
524 return 0;
525}
526
527static const VMStateDescription vmstate_rtc = {
528 .name = TYPE_XLNX_ZYNQMP_RTC,
529 .version_id = 1,
530 .minimum_version_id = 1,
531 .pre_save = rtc_pre_save,
532 .post_load = rtc_post_load,
533 .fields = (VMStateField[]) {
534 VMSTATE_UINT32_ARRAY(regs, XlnxZynqMPRTC, XLNX_ZYNQMP_RTC_R_MAX),
535 VMSTATE_UINT32(tick_offset, XlnxZynqMPRTC),
536 VMSTATE_END_OF_LIST(),
537 }
538};
539
540static void rtc_class_init(ObjectClass *klass, void *data)
541{
542 DeviceClass *dc = DEVICE_CLASS(klass);
543
544 dc->reset = rtc_reset;
545 dc->props = xlnx_rtc_properties;
546 dc->vmsd = &vmstate_rtc;
547}
548
549static const TypeInfo rtc_info = {
550 .name = TYPE_XLNX_ZYNQMP_RTC,
551 .parent = TYPE_SYS_BUS_DEVICE,
552 .instance_size = sizeof(XlnxZynqMPRTC),
553 .class_init = rtc_class_init,
554 .instance_init = rtc_init,
555};
556
557static const TypeInfo rtc_alias_info = {
558 .name = TYPE_XLNX_ZYNQMP_ALIAS_RTC,
559 .parent = TYPE_XLNX_ZYNQMP_RTC,
560};
561
562static void rtc_register_types(void)
563{
564 type_register_static(&rtc_info);
565 type_register_static(&rtc_alias_info);
566}
567
568type_init(rtc_register_types)
569