2 * Renesas 16bit Compare-match timer
4 * Datasheet: RX62N Group, RX621 Group User's Manual: Hardware
5 * (Rev.1.40 R01UH0033EJ0140)
7 * Copyright (c) 2019 Yoshinori Sato
9 * SPDX-License-Identifier: GPL-2.0-or-later
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms and conditions of the GNU General Public License,
13 * version 2 or later, as published by the Free Software Foundation.
15 * This program is distributed in the hope it will be useful, but WITHOUT
16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
20 * You should have received a copy of the GNU General Public License along with
21 * this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "qemu/osdep.h"
27 #include "hw/registerfields.h"
28 #include "hw/qdev-properties.h"
29 #include "hw/timer/renesas_cmt.h"
30 #include "migration/vmstate.h"
33 * +0 CMSTR - common control
40 * If we think that the address of CH 0 has an offset of +2,
41 * we can treat it with the same address as CH 1, so define it like that.
44 FIELD(CMSTR, STR0, 0, 1)
45 FIELD(CMSTR, STR1, 1, 1)
46 FIELD(CMSTR, STR, 0, 2)
47 /* This addeess is channel offset */
49 FIELD(CMCR, CKS, 0, 2)
50 FIELD(CMCR, CMIE, 6, 1)
54 static void update_events(RCMTState *cmt, int ch)
58 if ((cmt->cmstr & (1 << ch)) == 0) {
59 /* count disable, so not happened next event. */
62 next_time = cmt->cmcor[ch] - cmt->cmcnt[ch];
63 next_time *= NANOSECONDS_PER_SECOND;
64 next_time /= cmt->input_freq;
72 next_time *= 1 << (3 + FIELD_EX16(cmt->cmcr[ch], CMCR, CKS) * 2);
73 next_time += qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
74 timer_mod(&cmt->timer[ch], next_time);
77 static int64_t read_cmcnt(RCMTState *cmt, int ch)
79 int64_t delta, now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
81 if (cmt->cmstr & (1 << ch)) {
82 delta = (now - cmt->tick[ch]);
83 delta /= NANOSECONDS_PER_SECOND;
84 delta /= cmt->input_freq;
85 delta /= 1 << (3 + FIELD_EX16(cmt->cmcr[ch], CMCR, CKS) * 2);
87 return cmt->cmcnt[ch] + delta;
89 return cmt->cmcnt[ch];
93 static uint64_t cmt_read(void *opaque, hwaddr offset, unsigned size)
95 RCMTState *cmt = opaque;
96 int ch = offset / 0x08;
99 if (offset == A_CMSTR) {
101 ret = FIELD_DP16(ret, CMSTR, STR,
102 FIELD_EX16(cmt->cmstr, CMSTR, STR));
112 ret = FIELD_DP16(ret, CMCR, CKS,
113 FIELD_EX16(cmt->cmstr, CMCR, CKS));
114 ret = FIELD_DP16(ret, CMCR, CMIE,
115 FIELD_EX16(cmt->cmstr, CMCR, CMIE));
118 return read_cmcnt(cmt, ch);
120 return cmt->cmcor[ch];
123 qemu_log_mask(LOG_UNIMP, "renesas_cmt: Register 0x%" HWADDR_PRIX " "
129 static void start_stop(RCMTState *cmt, int ch, int st)
132 update_events(cmt, ch);
134 timer_del(&cmt->timer[ch]);
138 static void cmt_write(void *opaque, hwaddr offset, uint64_t val, unsigned size)
140 RCMTState *cmt = opaque;
141 int ch = offset / 0x08;
143 if (offset == A_CMSTR) {
144 cmt->cmstr = FIELD_EX16(val, CMSTR, STR);
145 start_stop(cmt, 0, FIELD_EX16(cmt->cmstr, CMSTR, STR0));
146 start_stop(cmt, 1, FIELD_EX16(cmt->cmstr, CMSTR, STR1));
154 cmt->cmcr[ch] = FIELD_DP16(cmt->cmcr[ch], CMCR, CKS,
155 FIELD_EX16(val, CMCR, CKS));
156 cmt->cmcr[ch] = FIELD_DP16(cmt->cmcr[ch], CMCR, CMIE,
157 FIELD_EX16(val, CMCR, CMIE));
160 cmt->cmcnt[ch] = val;
163 cmt->cmcor[ch] = val;
166 qemu_log_mask(LOG_UNIMP, "renesas_cmt: Register 0x%" HWADDR_PRIX " "
171 if (FIELD_EX16(cmt->cmstr, CMSTR, STR) & (1 << ch)) {
172 update_events(cmt, ch);
177 static const MemoryRegionOps cmt_ops = {
180 .endianness = DEVICE_NATIVE_ENDIAN,
182 .min_access_size = 2,
183 .max_access_size = 2,
186 .min_access_size = 2,
187 .max_access_size = 2,
191 static void timer_events(RCMTState *cmt, int ch)
194 cmt->tick[ch] = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
195 update_events(cmt, ch);
196 if (FIELD_EX16(cmt->cmcr[ch], CMCR, CMIE)) {
197 qemu_irq_pulse(cmt->cmi[ch]);
201 static void timer_event0(void *opaque)
203 RCMTState *cmt = opaque;
205 timer_events(cmt, 0);
208 static void timer_event1(void *opaque)
210 RCMTState *cmt = opaque;
212 timer_events(cmt, 1);
215 static void rcmt_reset(DeviceState *dev)
217 RCMTState *cmt = RCMT(dev);
219 cmt->cmcr[0] = cmt->cmcr[1] = 0;
220 cmt->cmcnt[0] = cmt->cmcnt[1] = 0;
221 cmt->cmcor[0] = cmt->cmcor[1] = 0xffff;
224 static void rcmt_init(Object *obj)
226 SysBusDevice *d = SYS_BUS_DEVICE(obj);
227 RCMTState *cmt = RCMT(obj);
230 memory_region_init_io(&cmt->memory, OBJECT(cmt), &cmt_ops,
231 cmt, "renesas-cmt", 0x10);
232 sysbus_init_mmio(d, &cmt->memory);
234 for (i = 0; i < ARRAY_SIZE(cmt->cmi); i++) {
235 sysbus_init_irq(d, &cmt->cmi[i]);
237 timer_init_ns(&cmt->timer[0], QEMU_CLOCK_VIRTUAL, timer_event0, cmt);
238 timer_init_ns(&cmt->timer[1], QEMU_CLOCK_VIRTUAL, timer_event1, cmt);
241 static const VMStateDescription vmstate_rcmt = {
244 .minimum_version_id = 1,
245 .fields = (VMStateField[]) {
246 VMSTATE_UINT16(cmstr, RCMTState),
247 VMSTATE_UINT16_ARRAY(cmcr, RCMTState, CMT_CH),
248 VMSTATE_UINT16_ARRAY(cmcnt, RCMTState, CMT_CH),
249 VMSTATE_UINT16_ARRAY(cmcor, RCMTState, CMT_CH),
250 VMSTATE_INT64_ARRAY(tick, RCMTState, CMT_CH),
251 VMSTATE_TIMER_ARRAY(timer, RCMTState, CMT_CH),
252 VMSTATE_END_OF_LIST()
256 static Property rcmt_properties[] = {
257 DEFINE_PROP_UINT64("input-freq", RCMTState, input_freq, 0),
258 DEFINE_PROP_END_OF_LIST(),
261 static void rcmt_class_init(ObjectClass *klass, void *data)
263 DeviceClass *dc = DEVICE_CLASS(klass);
265 dc->vmsd = &vmstate_rcmt;
266 dc->reset = rcmt_reset;
267 device_class_set_props(dc, rcmt_properties);
270 static const TypeInfo rcmt_info = {
271 .name = TYPE_RENESAS_CMT,
272 .parent = TYPE_SYS_BUS_DEVICE,
273 .instance_size = sizeof(RCMTState),
274 .instance_init = rcmt_init,
275 .class_init = rcmt_class_init,
278 static void rcmt_register_types(void)
280 type_register_static(&rcmt_info);
283 type_init(rcmt_register_types)