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
27 #include "qemu/osdep.h"
28 #include "hw/sysbus.h"
29 #include "hw/register.h"
30 #include "qemu/bitops.h"
32 #include "hw/timer/xlnx-zynqmp-rtc.h"
34 #ifndef XLNX_ZYNQMP_RTC_ERR_DEBUG
35 #define XLNX_ZYNQMP_RTC_ERR_DEBUG 0
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
);
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
);
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
);
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
);
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
,
102 },{ .name
= "CALIB_WRITE", .addr
= A_CALIB_WRITE
,
103 },{ .name
= "CALIB_READ", .addr
= A_CALIB_READ
,
105 },{ .name
= "CURRENT_TIME", .addr
= A_CURRENT_TIME
,
107 },{ .name
= "CURRENT_TICK", .addr
= A_CURRENT_TICK
,
109 },{ .name
= "ALARM", .addr
= A_ALARM
,
110 },{ .name
= "RTC_INT_STATUS", .addr
= A_RTC_INT_STATUS
,
112 .post_write
= rtc_int_status_postw
,
113 },{ .name
= "RTC_INT_MASK", .addr
= A_RTC_INT_MASK
,
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
,
122 .post_write
= addr_error_postw
,
123 },{ .name
= "ADDR_ERROR_INT_MASK", .addr
= A_ADDR_ERROR_INT_MASK
,
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
,
133 },{ .name
= "SAFETY_CHK", .addr
= A_SAFETY_CHK
,
137 static void rtc_reset(DeviceState
*dev
)
139 XlnxZynqMPRTC
*s
= XLNX_ZYNQMP_RTC(dev
);
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
,
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);
169 register_init_block32(DEVICE(obj
), rtc_regs_info
,
170 ARRAY_SIZE(rtc_regs_info
),
171 s
->regs_info
, s
->regs
,
173 XLNX_ZYNQMP_RTC_ERR_DEBUG
,
174 XLNX_ZYNQMP_RTC_R_MAX
* 4);
175 memory_region_add_subregion(&s
->iomem
,
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
,
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
)