xlnx-zynqmp-rtc: Initial commit
[qemu/ar7.git] / hw / timer / xlnx-zynqmp-rtc.c
blob707f145027828342a6e2ce1afe3bf41f5d2ae4f5
1 /*
2 * QEMU model of the Xilinx ZynqMP Real Time Clock (RTC).
4 * Copyright (c) 2017 Xilinx Inc.
6 * Written-by: Alistair Francis <alistair.francis@xilinx.com>
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 * THE SOFTWARE.
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/timer/xlnx-zynqmp-rtc.h"
34 #ifndef XLNX_ZYNQMP_RTC_ERR_DEBUG
35 #define XLNX_ZYNQMP_RTC_ERR_DEBUG 0
36 #endif
38 static void rtc_int_update_irq(XlnxZynqMPRTC *s)
40 bool pending = s->regs[R_RTC_INT_STATUS] & ~s->regs[R_RTC_INT_MASK];
41 qemu_set_irq(s->irq_rtc_int, pending);
44 static void addr_error_int_update_irq(XlnxZynqMPRTC *s)
46 bool pending = s->regs[R_ADDR_ERROR] & ~s->regs[R_ADDR_ERROR_INT_MASK];
47 qemu_set_irq(s->irq_addr_error_int, pending);
50 static void rtc_int_status_postw(RegisterInfo *reg, uint64_t val64)
52 XlnxZynqMPRTC *s = XLNX_ZYNQMP_RTC(reg->opaque);
53 rtc_int_update_irq(s);
56 static uint64_t rtc_int_en_prew(RegisterInfo *reg, uint64_t val64)
58 XlnxZynqMPRTC *s = XLNX_ZYNQMP_RTC(reg->opaque);
60 s->regs[R_RTC_INT_MASK] &= (uint32_t) ~val64;
61 rtc_int_update_irq(s);
62 return 0;
65 static uint64_t rtc_int_dis_prew(RegisterInfo *reg, uint64_t val64)
67 XlnxZynqMPRTC *s = XLNX_ZYNQMP_RTC(reg->opaque);
69 s->regs[R_RTC_INT_MASK] |= (uint32_t) val64;
70 rtc_int_update_irq(s);
71 return 0;
74 static void addr_error_postw(RegisterInfo *reg, uint64_t val64)
76 XlnxZynqMPRTC *s = XLNX_ZYNQMP_RTC(reg->opaque);
77 addr_error_int_update_irq(s);
80 static uint64_t addr_error_int_en_prew(RegisterInfo *reg, uint64_t val64)
82 XlnxZynqMPRTC *s = XLNX_ZYNQMP_RTC(reg->opaque);
84 s->regs[R_ADDR_ERROR_INT_MASK] &= (uint32_t) ~val64;
85 addr_error_int_update_irq(s);
86 return 0;
89 static uint64_t addr_error_int_dis_prew(RegisterInfo *reg, uint64_t val64)
91 XlnxZynqMPRTC *s = XLNX_ZYNQMP_RTC(reg->opaque);
93 s->regs[R_ADDR_ERROR_INT_MASK] |= (uint32_t) val64;
94 addr_error_int_update_irq(s);
95 return 0;
98 static const RegisterAccessInfo rtc_regs_info[] = {
99 { .name = "SET_TIME_WRITE", .addr = A_SET_TIME_WRITE,
100 },{ .name = "SET_TIME_READ", .addr = A_SET_TIME_READ,
101 .ro = 0xffffffff,
102 },{ .name = "CALIB_WRITE", .addr = A_CALIB_WRITE,
103 },{ .name = "CALIB_READ", .addr = A_CALIB_READ,
104 .ro = 0x1fffff,
105 },{ .name = "CURRENT_TIME", .addr = A_CURRENT_TIME,
106 .ro = 0xffffffff,
107 },{ .name = "CURRENT_TICK", .addr = A_CURRENT_TICK,
108 .ro = 0xffff,
109 },{ .name = "ALARM", .addr = A_ALARM,
110 },{ .name = "RTC_INT_STATUS", .addr = A_RTC_INT_STATUS,
111 .w1c = 0x3,
112 .post_write = rtc_int_status_postw,
113 },{ .name = "RTC_INT_MASK", .addr = A_RTC_INT_MASK,
114 .reset = 0x3,
115 .ro = 0x3,
116 },{ .name = "RTC_INT_EN", .addr = A_RTC_INT_EN,
117 .pre_write = rtc_int_en_prew,
118 },{ .name = "RTC_INT_DIS", .addr = A_RTC_INT_DIS,
119 .pre_write = rtc_int_dis_prew,
120 },{ .name = "ADDR_ERROR", .addr = A_ADDR_ERROR,
121 .w1c = 0x1,
122 .post_write = addr_error_postw,
123 },{ .name = "ADDR_ERROR_INT_MASK", .addr = A_ADDR_ERROR_INT_MASK,
124 .reset = 0x1,
125 .ro = 0x1,
126 },{ .name = "ADDR_ERROR_INT_EN", .addr = A_ADDR_ERROR_INT_EN,
127 .pre_write = addr_error_int_en_prew,
128 },{ .name = "ADDR_ERROR_INT_DIS", .addr = A_ADDR_ERROR_INT_DIS,
129 .pre_write = addr_error_int_dis_prew,
130 },{ .name = "CONTROL", .addr = A_CONTROL,
131 .reset = 0x1000000,
132 .rsvd = 0x70fffffe,
133 },{ .name = "SAFETY_CHK", .addr = A_SAFETY_CHK,
137 static void rtc_reset(DeviceState *dev)
139 XlnxZynqMPRTC *s = XLNX_ZYNQMP_RTC(dev);
140 unsigned int i;
142 for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) {
143 register_reset(&s->regs_info[i]);
146 rtc_int_update_irq(s);
147 addr_error_int_update_irq(s);
150 static const MemoryRegionOps rtc_ops = {
151 .read = register_read_memory,
152 .write = register_write_memory,
153 .endianness = DEVICE_LITTLE_ENDIAN,
154 .valid = {
155 .min_access_size = 4,
156 .max_access_size = 4,
160 static void rtc_init(Object *obj)
162 XlnxZynqMPRTC *s = XLNX_ZYNQMP_RTC(obj);
163 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
164 RegisterInfoArray *reg_array;
166 memory_region_init(&s->iomem, obj, TYPE_XLNX_ZYNQMP_RTC,
167 XLNX_ZYNQMP_RTC_R_MAX * 4);
168 reg_array =
169 register_init_block32(DEVICE(obj), rtc_regs_info,
170 ARRAY_SIZE(rtc_regs_info),
171 s->regs_info, s->regs,
172 &rtc_ops,
173 XLNX_ZYNQMP_RTC_ERR_DEBUG,
174 XLNX_ZYNQMP_RTC_R_MAX * 4);
175 memory_region_add_subregion(&s->iomem,
176 0x0,
177 &reg_array->mem);
178 sysbus_init_mmio(sbd, &s->iomem);
179 sysbus_init_irq(sbd, &s->irq_rtc_int);
180 sysbus_init_irq(sbd, &s->irq_addr_error_int);
183 static const VMStateDescription vmstate_rtc = {
184 .name = TYPE_XLNX_ZYNQMP_RTC,
185 .version_id = 1,
186 .minimum_version_id = 1,
187 .fields = (VMStateField[]) {
188 VMSTATE_UINT32_ARRAY(regs, XlnxZynqMPRTC, XLNX_ZYNQMP_RTC_R_MAX),
189 VMSTATE_END_OF_LIST(),
193 static void rtc_class_init(ObjectClass *klass, void *data)
195 DeviceClass *dc = DEVICE_CLASS(klass);
197 dc->reset = rtc_reset;
198 dc->vmsd = &vmstate_rtc;
201 static const TypeInfo rtc_info = {
202 .name = TYPE_XLNX_ZYNQMP_RTC,
203 .parent = TYPE_SYS_BUS_DEVICE,
204 .instance_size = sizeof(XlnxZynqMPRTC),
205 .class_init = rtc_class_init,
206 .instance_init = rtc_init,
209 static void rtc_register_types(void)
211 type_register_static(&rtc_info);
214 type_init(rtc_register_types)