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 "hw/sysbus.h"
29#include "hw/register.h"
30#include "qemu/bitops.h"
31#include "qemu/log.h"
32#include "hw/ptimer.h"
33#include "qemu/cutils.h"
34#include "sysemu/sysemu.h"
35#include "trace.h"
36#include "hw/timer/xlnx-zynqmp-rtc.h"
37
38#ifndef XLNX_ZYNQMP_RTC_ERR_DEBUG
39#define XLNX_ZYNQMP_RTC_ERR_DEBUG 0
40#endif
41
42enum version_id {
43 IP_VERSION_1_0_1 = 0,
44 IP_VERSION_2_0_0 = 1
45};
46
47struct version_item_lookup {
48 enum version_id id;
49 const char *str;
50};
51
52static struct version_item_lookup version_table_lookup[] = {
53 { IP_VERSION_1_0_1, "1.0.1" },
54 { IP_VERSION_2_0_0, "2.0.0" }
55};
56
57static Property xlnx_rtc_properties[] = {
58 DEFINE_PROP_STRING("version", XlnxZynqMPRTC, cfg.version),
59 DEFINE_PROP_END_OF_LIST(),
60};
61
62static void rtc_int_update_irq(XlnxZynqMPRTC *s)
63{
64 bool pending = s->regs[R_RTC_INT_STATUS] & ~s->regs[R_RTC_INT_MASK];
65 qemu_set_irq(s->irq_rtc_int, pending);
66}
67
68static void addr_error_int_update_irq(XlnxZynqMPRTC *s)
69{
70 bool pending = s->regs[R_ADDR_ERROR] & ~s->regs[R_ADDR_ERROR_INT_MASK];
71 qemu_set_irq(s->irq_addr_error_int, pending);
72}
73
74static uint32_t rtc_get_count(XlnxZynqMPRTC *s)
75{
76 int64_t now = qemu_clock_get_ns(rtc_clock);
77 return s->tick_offset + now / NANOSECONDS_PER_SECOND;
78}
79
80static uint64_t current_time_postr(RegisterInfo *reg, uint64_t val64)
81{
82 XlnxZynqMPRTC *s = XLNX_ZYNQMP_RTC(reg->opaque);
83
84 return rtc_get_count(s);
85}
86
87static void rtc_int_status_postw(RegisterInfo *reg, uint64_t val64)
88{
89 XlnxZynqMPRTC *s = XLNX_ZYNQMP_RTC(reg->opaque);
90 rtc_int_update_irq(s);
91}
92
93static uint64_t rtc_int_en_prew(RegisterInfo *reg, uint64_t val64)
94{
95 XlnxZynqMPRTC *s = XLNX_ZYNQMP_RTC(reg->opaque);
96
97 s->regs[R_RTC_INT_MASK] &= (uint32_t) ~val64;
98 rtc_int_update_irq(s);
99 return 0;
100}
101
102static uint64_t rtc_int_dis_prew(RegisterInfo *reg, uint64_t val64)
103{
104 XlnxZynqMPRTC *s = XLNX_ZYNQMP_RTC(reg->opaque);
105
106 s->regs[R_RTC_INT_MASK] |= (uint32_t) val64;
107 rtc_int_update_irq(s);
108 return 0;
109}
110
111static void addr_error_postw(RegisterInfo *reg, uint64_t val64)
112{
113 XlnxZynqMPRTC *s = XLNX_ZYNQMP_RTC(reg->opaque);
114 addr_error_int_update_irq(s);
115}
116
117static uint64_t addr_error_int_en_prew(RegisterInfo *reg, uint64_t val64)
118{
119 XlnxZynqMPRTC *s = XLNX_ZYNQMP_RTC(reg->opaque);
120
121 s->regs[R_ADDR_ERROR_INT_MASK] &= (uint32_t) ~val64;
122 addr_error_int_update_irq(s);
123 return 0;
124}
125
126static uint64_t addr_error_int_dis_prew(RegisterInfo *reg, uint64_t val64)
127{
128 XlnxZynqMPRTC *s = XLNX_ZYNQMP_RTC(reg->opaque);
129
130 s->regs[R_ADDR_ERROR_INT_MASK] |= (uint32_t) val64;
131 addr_error_int_update_irq(s);
132 return 0;
133}
134
135static void rtc_set_timer_postw(RegisterInfo *reg, uint64_t val64)
136{
137 XlnxZynqMPRTC *s = XLNX_ZYNQMP_RTC(reg->opaque);
138 s->tick_offset = (uint32_t) val64;
139}
140
141static void rtc_calib_write_postw(RegisterInfo *reg, uint64_t val64)
142{
143 XlnxZynqMPRTC *s = XLNX_ZYNQMP_RTC(reg->opaque);
144 s->regs[R_CALIB_READ] = (uint32_t) val64;
145}
146
147static const RegisterAccessInfo rtc_regs_info[] = {
148 { .name = "SET_TIME_WRITE", .addr = A_SET_TIME_WRITE,
149 .post_write = rtc_set_timer_postw,
150 },{ .name = "SET_TIME_READ", .addr = A_SET_TIME_READ,
151 .ro = 0xffffffff,
152 .post_read = current_time_postr,
153 },{ .name = "CALIB_WRITE", .addr = A_CALIB_WRITE,
154 .post_write = rtc_calib_write_postw,
155 },{ .name = "CALIB_READ", .addr = A_CALIB_READ,
156 .ro = 0x1fffff,
157 },{ .name = "CURRENT_TIME", .addr = A_CURRENT_TIME,
158 .ro = 0xffffffff,
159 .post_read = current_time_postr,
160 },{ .name = "CURRENT_TICK", .addr = A_CURRENT_TICK,
161 .ro = 0xffff,
162 },{ .name = "ALARM", .addr = A_ALARM,
163 },{ .name = "RTC_INT_STATUS", .addr = A_RTC_INT_STATUS,
164 .w1c = 0x3,
165 .post_write = rtc_int_status_postw,
166 },{ .name = "RTC_INT_MASK", .addr = A_RTC_INT_MASK,
167 .reset = 0x3,
168 .ro = 0x3,
169 },{ .name = "RTC_INT_EN", .addr = A_RTC_INT_EN,
170 .pre_write = rtc_int_en_prew,
171 },{ .name = "RTC_INT_DIS", .addr = A_RTC_INT_DIS,
172 .pre_write = rtc_int_dis_prew,
173 },{ .name = "ADDR_ERROR", .addr = A_ADDR_ERROR,
174 .w1c = 0x1,
175 .post_write = addr_error_postw,
176 },{ .name = "ADDR_ERROR_INT_MASK", .addr = A_ADDR_ERROR_INT_MASK,
177 .reset = 0x1,
178 .ro = 0x1,
179 },{ .name = "ADDR_ERROR_INT_EN", .addr = A_ADDR_ERROR_INT_EN,
180 .pre_write = addr_error_int_en_prew,
181 },{ .name = "ADDR_ERROR_INT_DIS", .addr = A_ADDR_ERROR_INT_DIS,
182 .pre_write = addr_error_int_dis_prew,
183 },{ .name = "CONTROL", .addr = A_CONTROL,
184 .reset = 0x1000000,
185 .rsvd = 0x70fffffe,
186 },{ .name = "SAFETY_CHK", .addr = A_SAFETY_CHK,
187 }
188};
189
190static const RegisterAccessInfo rtc_regs_control_v2_info = {
191 .name = "CONTROL", .addr = A_CONTROL,
192 .reset = 0x2000000, .rsvd = 0x70fffffe,
193};
194
195static enum version_id version_id_lookup(const char *str)
196{
197 uint32_t i;
198 enum version_id version;
199
200 version = IP_VERSION_1_0_1;
201
202 if (str) {
203 for (i = 0; i < ARRAY_SIZE(version_table_lookup); ++i) {
204 if (!strcmp(str, version_table_lookup[i].str)) {
205 version = version_table_lookup[i].id;
206 break;
207 }
208 }
209 }
210
211 return version;
212}
213
214static void rtc_reset(DeviceState *dev)
215{
216 XlnxZynqMPRTC *s = XLNX_ZYNQMP_RTC(dev);
217 unsigned int i;
218
219 for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) {
220 register_reset(&s->regs_info[i]);
221 }
222
223 if (version_id_lookup(s->cfg.version) == IP_VERSION_2_0_0) {
224 s->regs_info[R_CONTROL].access = &rtc_regs_control_v2_info;
225 register_reset(&s->regs_info[R_CONTROL]);
226 }
227
228 trace_xlnx_zynqmp_rtc_gettime(s->current_tm.tm_year, s->current_tm.tm_mon,
229 s->current_tm.tm_mday, s->current_tm.tm_hour,
230 s->current_tm.tm_min, s->current_tm.tm_sec);
231
232 rtc_int_update_irq(s);
233 addr_error_int_update_irq(s);
234}
235
236static const MemoryRegionOps rtc_ops = {
237 .read = register_read_memory,
238 .write = register_write_memory,
239 .endianness = DEVICE_LITTLE_ENDIAN,
240 .valid = {
241 .min_access_size = 4,
242 .max_access_size = 4,
243 },
244};
245
246static void rtc_init(Object *obj)
247{
248 XlnxZynqMPRTC *s = XLNX_ZYNQMP_RTC(obj);
249 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
250 RegisterInfoArray *reg_array;
251
252 memory_region_init(&s->iomem, obj, TYPE_XLNX_ZYNQMP_RTC,
253 XLNX_ZYNQMP_RTC_R_MAX * 4);
254 reg_array =
255 register_init_block32(DEVICE(obj), rtc_regs_info,
256 ARRAY_SIZE(rtc_regs_info),
257 s->regs_info, s->regs,
258 &rtc_ops,
259 XLNX_ZYNQMP_RTC_ERR_DEBUG,
260 XLNX_ZYNQMP_RTC_R_MAX * 4);
261 memory_region_add_subregion(&s->iomem,
262 0x0,
263 ®_array->mem);
264 sysbus_init_mmio(sbd, &s->iomem);
265 sysbus_init_irq(sbd, &s->irq_rtc_int);
266 sysbus_init_irq(sbd, &s->irq_addr_error_int);
267
268 qemu_get_timedate(&s->current_tm, 0);
269 s->tick_offset = mktimegm(&s->current_tm) -
270 qemu_clock_get_ns(rtc_clock) / NANOSECONDS_PER_SECOND;
271}
272
273static int rtc_post_load(void *opaque, int version_id)
274{
275 XlnxZynqMPRTC *s = opaque;
276
277
278
279
280
281
282 s->tick_offset = mktimegm(&s->current_tm) -
283 qemu_clock_get_ns(rtc_clock) / NANOSECONDS_PER_SECOND;
284
285 return 0;
286}
287
288static const VMStateDescription vmstate_rtc = {
289 .name = TYPE_XLNX_ZYNQMP_RTC,
290 .version_id = 1,
291 .minimum_version_id = 1,
292 .post_load = rtc_post_load,
293 .fields = (VMStateField[]) {
294 VMSTATE_UINT32_ARRAY(regs, XlnxZynqMPRTC, XLNX_ZYNQMP_RTC_R_MAX),
295 VMSTATE_INT32(current_tm.tm_sec, XlnxZynqMPRTC),
296 VMSTATE_INT32(current_tm.tm_min, XlnxZynqMPRTC),
297 VMSTATE_INT32(current_tm.tm_hour, XlnxZynqMPRTC),
298 VMSTATE_INT32(current_tm.tm_wday, XlnxZynqMPRTC),
299 VMSTATE_INT32(current_tm.tm_mday, XlnxZynqMPRTC),
300 VMSTATE_INT32(current_tm.tm_mon, XlnxZynqMPRTC),
301 VMSTATE_INT32(current_tm.tm_year, XlnxZynqMPRTC),
302 VMSTATE_END_OF_LIST(),
303 }
304};
305
306static void rtc_class_init(ObjectClass *klass, void *data)
307{
308 DeviceClass *dc = DEVICE_CLASS(klass);
309
310 dc->reset = rtc_reset;
311 dc->props = xlnx_rtc_properties;
312 dc->vmsd = &vmstate_rtc;
313}
314
315static const TypeInfo rtc_info = {
316 .name = TYPE_XLNX_ZYNQMP_RTC,
317 .parent = TYPE_SYS_BUS_DEVICE,
318 .instance_size = sizeof(XlnxZynqMPRTC),
319 .class_init = rtc_class_init,
320 .instance_init = rtc_init,
321};
322
323static const TypeInfo rtc_alias_info = {
324 .name = TYPE_XLNX_ZYNQMP_ALIAS_RTC,
325 .parent = TYPE_XLNX_ZYNQMP_RTC,
326};
327
328static void rtc_register_types(void)
329{
330 type_register_static(&rtc_info);
331 type_register_static(&rtc_alias_info);
332}
333
334type_init(rtc_register_types)
335