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_tmr.h"
30 #include "migration/vmstate.h"
33 FIELD(TCR
, CCLR
, 3, 2)
34 FIELD(TCR
, OVIE
, 5, 1)
35 FIELD(TCR
, CMIEA
, 6, 1)
36 FIELD(TCR
, CMIEB
, 7, 1)
38 FIELD(TCSR
, OSA
, 0, 2)
39 FIELD(TCSR
, OSB
, 2, 2)
40 FIELD(TCSR
, ADTE
, 4, 2)
45 FIELD(TCCR
, CKS
, 0, 3)
46 FIELD(TCCR
, CSS
, 3, 2)
47 FIELD(TCCR
, TMRIS
, 7, 1)
49 #define CSS_EXTERNAL 0x00
50 #define CSS_INTERNAL 0x01
51 #define CSS_INVALID 0x02
52 #define CSS_CASCADING 0x03
56 static const int clkdiv
[] = {0, 1, 2, 8, 32, 64, 1024, 8192};
58 static uint8_t concat_reg(uint8_t *reg
)
60 return (reg
[0] << 8) | reg
[1];
63 static void update_events(RTMRState
*tmr
, int ch
)
65 uint16_t diff
[TMR_NR_EVENTS
], min
;
69 if (tmr
->tccr
[ch
] == 0) {
72 if (FIELD_EX8(tmr
->tccr
[ch
], TCCR
, CSS
) == 0) {
73 /* external clock mode */
74 /* event not happened */
77 if (FIELD_EX8(tmr
->tccr
[0], TCCR
, CSS
) == CSS_CASCADING
) {
83 diff
[cmia
] = concat_reg(tmr
->tcora
) - concat_reg(tmr
->tcnt
);
84 diff
[cmib
] = concat_reg(tmr
->tcorb
) - concat_reg(tmr
->tcnt
);
85 diff
[ovi
] = 0x10000 - concat_reg(tmr
->tcnt
);
88 diff
[cmia
] = tmr
->tcora
[ch
] - tmr
->tcnt
[ch
];
89 diff
[cmib
] = tmr
->tcorb
[ch
] - tmr
->tcnt
[ch
];
90 diff
[ovi
] = 0x100 - tmr
->tcnt
[ch
];
92 /* Search for the most recently occurring event. */
93 for (event
= 0, min
= diff
[0], i
= 1; i
< none
; i
++) {
99 tmr
->next
[ch
] = event
;
100 next_time
= diff
[event
];
101 next_time
*= clkdiv
[FIELD_EX8(tmr
->tccr
[ch
], TCCR
, CKS
)];
102 next_time
*= NANOSECONDS_PER_SECOND
;
103 next_time
/= tmr
->input_freq
;
104 next_time
+= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
);
105 timer_mod(&tmr
->timer
[ch
], next_time
);
108 static int elapsed_time(RTMRState
*tmr
, int ch
, int64_t delta
)
110 int divrate
= clkdiv
[FIELD_EX8(tmr
->tccr
[ch
], TCCR
, CKS
)];
113 tmr
->div_round
[ch
] += delta
;
115 et
= tmr
->div_round
[ch
] / divrate
;
116 tmr
->div_round
[ch
] %= divrate
;
118 /* disble clock. so no update */
124 static uint16_t read_tcnt(RTMRState
*tmr
, unsigned size
, int ch
)
126 int64_t delta
, now
= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
);
127 int elapsed
, ovf
= 0;
131 delta
= (now
- tmr
->tick
) * NANOSECONDS_PER_SECOND
/ tmr
->input_freq
;
135 switch (FIELD_EX8(tmr
->tccr
[1], TCCR
, CSS
)) {
137 /* timer1 count update */
138 elapsed
= elapsed_time(tmr
, 1, delta
);
139 if (elapsed
>= 0x100) {
142 tcnt
[1] = tmr
->tcnt
[1] + (elapsed
& 0xff);
144 case CSS_INVALID
: /* guest error to have set this */
145 case CSS_EXTERNAL
: /* QEMU doesn't implement these */
147 tcnt
[1] = tmr
->tcnt
[1];
150 switch (FIELD_EX8(tmr
->tccr
[0], TCCR
, CSS
)) {
152 elapsed
= elapsed_time(tmr
, 0, delta
);
153 tcnt
[0] = tmr
->tcnt
[0] + elapsed
;
156 tcnt
[0] = tmr
->tcnt
[0] + ovf
;
158 case CSS_INVALID
: /* guest error to have set this */
159 case CSS_EXTERNAL
: /* QEMU doesn't implement this */
160 tcnt
[0] = tmr
->tcnt
[0];
164 tcnt
[0] = tmr
->tcnt
[0];
165 tcnt
[1] = tmr
->tcnt
[1];
171 ret
= deposit32(ret
, 0, 8, tcnt
[1]);
172 ret
= deposit32(ret
, 8, 8, tcnt
[0]);
177 static uint8_t read_tccr(uint8_t r
)
180 tccr
= FIELD_DP8(tccr
, TCCR
, TMRIS
,
181 FIELD_EX8(r
, TCCR
, TMRIS
));
182 tccr
= FIELD_DP8(tccr
, TCCR
, CSS
,
183 FIELD_EX8(r
, TCCR
, CSS
));
184 tccr
= FIELD_DP8(tccr
, TCCR
, CKS
,
185 FIELD_EX8(r
, TCCR
, CKS
));
189 static uint64_t tmr_read(void *opaque
, hwaddr addr
, unsigned size
)
191 RTMRState
*tmr
= opaque
;
195 if (size
== 2 && (ch
!= 0 || addr
== A_TCR
|| addr
== A_TCSR
)) {
196 qemu_log_mask(LOG_GUEST_ERROR
, "renesas_tmr: Invalid read size 0x%"
201 switch (addr
& 0x0e) {
204 ret
= FIELD_DP8(ret
, TCR
, CCLR
,
205 FIELD_EX8(tmr
->tcr
[ch
], TCR
, CCLR
));
206 ret
= FIELD_DP8(ret
, TCR
, OVIE
,
207 FIELD_EX8(tmr
->tcr
[ch
], TCR
, OVIE
));
208 ret
= FIELD_DP8(ret
, TCR
, CMIEA
,
209 FIELD_EX8(tmr
->tcr
[ch
], TCR
, CMIEA
));
210 ret
= FIELD_DP8(ret
, TCR
, CMIEB
,
211 FIELD_EX8(tmr
->tcr
[ch
], TCR
, CMIEB
));
215 ret
= FIELD_DP8(ret
, TCSR
, OSA
,
216 FIELD_EX8(tmr
->tcsr
[ch
], TCSR
, OSA
));
217 ret
= FIELD_DP8(ret
, TCSR
, OSB
,
218 FIELD_EX8(tmr
->tcsr
[ch
], TCSR
, OSB
));
221 ret
= FIELD_DP8(ret
, TCSR
, ADTE
,
222 FIELD_EX8(tmr
->tcsr
[ch
], TCSR
, ADTE
));
224 case 1: /* CH1 ADTE unimplement always 1 */
225 ret
= FIELD_DP8(ret
, TCSR
, ADTE
, 1);
231 return tmr
->tcora
[ch
];
232 } else if (ch
== 0) {
233 return concat_reg(tmr
->tcora
);
238 return tmr
->tcorb
[ch
];
240 return concat_reg(tmr
->tcorb
);
243 return read_tcnt(tmr
, size
, ch
);
246 return read_tccr(tmr
->tccr
[ch
]);
248 return read_tccr(tmr
->tccr
[0]) << 8 | read_tccr(tmr
->tccr
[1]);
251 qemu_log_mask(LOG_UNIMP
, "renesas_tmr: Register 0x%" HWADDR_PRIX
252 " not implemented\n",
259 static void tmr_write_count(RTMRState
*tmr
, int ch
, unsigned size
,
260 uint8_t *reg
, uint64_t val
)
264 update_events(tmr
, ch
);
266 reg
[0] = extract32(val
, 8, 8);
267 reg
[1] = extract32(val
, 0, 8);
268 update_events(tmr
, 0);
269 update_events(tmr
, 1);
273 static void tmr_write(void *opaque
, hwaddr addr
, uint64_t val
, unsigned size
)
275 RTMRState
*tmr
= opaque
;
278 if (size
== 2 && (ch
!= 0 || addr
== A_TCR
|| addr
== A_TCSR
)) {
279 qemu_log_mask(LOG_GUEST_ERROR
,
280 "renesas_tmr: Invalid write size 0x%" HWADDR_PRIX
"\n",
284 switch (addr
& 0x0e) {
292 tmr_write_count(tmr
, ch
, size
, tmr
->tcora
, val
);
295 tmr_write_count(tmr
, ch
, size
, tmr
->tcorb
, val
);
298 tmr_write_count(tmr
, ch
, size
, tmr
->tcnt
, val
);
301 tmr_write_count(tmr
, ch
, size
, tmr
->tccr
, val
);
304 qemu_log_mask(LOG_UNIMP
, "renesas_tmr: Register 0x%" HWADDR_PRIX
305 " not implemented\n",
311 static const MemoryRegionOps tmr_ops
= {
314 .endianness
= DEVICE_LITTLE_ENDIAN
,
316 .min_access_size
= 1,
317 .max_access_size
= 2,
320 .min_access_size
= 1,
321 .max_access_size
= 2,
325 static void timer_events(RTMRState
*tmr
, int ch
);
327 static uint16_t issue_event(RTMRState
*tmr
, int ch
, int sz
,
328 uint16_t tcnt
, uint16_t tcora
, uint16_t tcorb
)
332 switch (tmr
->next
[ch
]) {
337 if (FIELD_EX8(tmr
->tcr
[ch
], TCR
, CCLR
) == CCLR_A
) {
340 if (FIELD_EX8(tmr
->tcr
[ch
], TCR
, CMIEA
)) {
341 qemu_irq_pulse(tmr
->cmia
[ch
]);
343 if (sz
== 8 && ch
== 0 &&
344 FIELD_EX8(tmr
->tccr
[1], TCCR
, CSS
) == CSS_CASCADING
) {
346 timer_events(tmr
, 1);
352 if (FIELD_EX8(tmr
->tcr
[ch
], TCR
, CCLR
) == CCLR_B
) {
355 if (FIELD_EX8(tmr
->tcr
[ch
], TCR
, CMIEB
)) {
356 qemu_irq_pulse(tmr
->cmib
[ch
]);
361 if ((tcnt
>= (1 << sz
)) && FIELD_EX8(tmr
->tcr
[ch
], TCR
, OVIE
)) {
362 qemu_irq_pulse(tmr
->ovi
[ch
]);
366 g_assert_not_reached();
371 static void timer_events(RTMRState
*tmr
, int ch
)
375 tmr
->tcnt
[ch
] = read_tcnt(tmr
, 1, ch
);
376 if (FIELD_EX8(tmr
->tccr
[0], TCCR
, CSS
) != CSS_CASCADING
) {
377 tmr
->tcnt
[ch
] = issue_event(tmr
, ch
, 8,
380 tmr
->tcorb
[ch
]) & 0xff;
385 tcnt
= issue_event(tmr
, ch
, 16,
386 concat_reg(tmr
->tcnt
),
387 concat_reg(tmr
->tcora
),
388 concat_reg(tmr
->tcorb
));
389 tmr
->tcnt
[0] = (tcnt
>> 8) & 0xff;
390 tmr
->tcnt
[1] = tcnt
& 0xff;
392 update_events(tmr
, ch
);
395 static void timer_event0(void *opaque
)
397 RTMRState
*tmr
= opaque
;
399 timer_events(tmr
, 0);
402 static void timer_event1(void *opaque
)
404 RTMRState
*tmr
= opaque
;
406 timer_events(tmr
, 1);
409 static void rtmr_reset(DeviceState
*dev
)
411 RTMRState
*tmr
= RTMR(dev
);
412 tmr
->tcr
[0] = tmr
->tcr
[1] = 0x00;
415 tmr
->tcnt
[0] = tmr
->tcnt
[1] = 0x00;
416 tmr
->tcora
[0] = tmr
->tcora
[1] = 0xff;
417 tmr
->tcorb
[0] = tmr
->tcorb
[1] = 0xff;
418 tmr
->tccr
[0] = tmr
->tccr
[1] = 0x00;
419 tmr
->next
[0] = tmr
->next
[1] = none
;
420 tmr
->tick
= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
);
423 static void rtmr_init(Object
*obj
)
425 SysBusDevice
*d
= SYS_BUS_DEVICE(obj
);
426 RTMRState
*tmr
= RTMR(obj
);
429 memory_region_init_io(&tmr
->memory
, OBJECT(tmr
), &tmr_ops
,
430 tmr
, "renesas-tmr", 0x10);
431 sysbus_init_mmio(d
, &tmr
->memory
);
433 for (i
= 0; i
< ARRAY_SIZE(tmr
->ovi
); i
++) {
434 sysbus_init_irq(d
, &tmr
->cmia
[i
]);
435 sysbus_init_irq(d
, &tmr
->cmib
[i
]);
436 sysbus_init_irq(d
, &tmr
->ovi
[i
]);
438 timer_init_ns(&tmr
->timer
[0], QEMU_CLOCK_VIRTUAL
, timer_event0
, tmr
);
439 timer_init_ns(&tmr
->timer
[1], QEMU_CLOCK_VIRTUAL
, timer_event1
, tmr
);
442 static const VMStateDescription vmstate_rtmr
= {
445 .minimum_version_id
= 1,
446 .fields
= (VMStateField
[]) {
447 VMSTATE_INT64(tick
, RTMRState
),
448 VMSTATE_UINT8_ARRAY(tcnt
, RTMRState
, TMR_CH
),
449 VMSTATE_UINT8_ARRAY(tcora
, RTMRState
, TMR_CH
),
450 VMSTATE_UINT8_ARRAY(tcorb
, RTMRState
, TMR_CH
),
451 VMSTATE_UINT8_ARRAY(tcr
, RTMRState
, TMR_CH
),
452 VMSTATE_UINT8_ARRAY(tccr
, RTMRState
, TMR_CH
),
453 VMSTATE_UINT8_ARRAY(tcor
, RTMRState
, TMR_CH
),
454 VMSTATE_UINT8_ARRAY(tcsr
, RTMRState
, TMR_CH
),
455 VMSTATE_INT64_ARRAY(div_round
, RTMRState
, TMR_CH
),
456 VMSTATE_UINT8_ARRAY(next
, RTMRState
, TMR_CH
),
457 VMSTATE_TIMER_ARRAY(timer
, RTMRState
, TMR_CH
),
458 VMSTATE_END_OF_LIST()
462 static Property rtmr_properties
[] = {
463 DEFINE_PROP_UINT64("input-freq", RTMRState
, input_freq
, 0),
464 DEFINE_PROP_END_OF_LIST(),
467 static void rtmr_class_init(ObjectClass
*klass
, void *data
)
469 DeviceClass
*dc
= DEVICE_CLASS(klass
);
471 dc
->vmsd
= &vmstate_rtmr
;
472 dc
->reset
= rtmr_reset
;
473 device_class_set_props(dc
, rtmr_properties
);
476 static const TypeInfo rtmr_info
= {
477 .name
= TYPE_RENESAS_TMR
,
478 .parent
= TYPE_SYS_BUS_DEVICE
,
479 .instance_size
= sizeof(RTMRState
),
480 .instance_init
= rtmr_init
,
481 .class_init
= rtmr_class_init
,
484 static void rtmr_register_types(void)
486 type_register_static(&rtmr_info
);
489 type_init(rtmr_register_types
)