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 g_assert_not_reached();
152 switch (FIELD_EX8(tmr
->tccr
[0], TCCR
, CSS
)) {
154 elapsed
= elapsed_time(tmr
, 0, delta
);
155 tcnt
[0] = tmr
->tcnt
[0] + elapsed
;
158 tcnt
[0] = tmr
->tcnt
[0] + ovf
;
160 case CSS_INVALID
: /* guest error to have set this */
161 case CSS_EXTERNAL
: /* QEMU doesn't implement this */
162 tcnt
[0] = tmr
->tcnt
[0];
165 g_assert_not_reached();
168 tcnt
[0] = tmr
->tcnt
[0];
169 tcnt
[1] = tmr
->tcnt
[1];
175 ret
= deposit32(ret
, 0, 8, tcnt
[1]);
176 ret
= deposit32(ret
, 8, 8, tcnt
[0]);
181 static uint8_t read_tccr(uint8_t r
)
184 tccr
= FIELD_DP8(tccr
, TCCR
, TMRIS
,
185 FIELD_EX8(r
, TCCR
, TMRIS
));
186 tccr
= FIELD_DP8(tccr
, TCCR
, CSS
,
187 FIELD_EX8(r
, TCCR
, CSS
));
188 tccr
= FIELD_DP8(tccr
, TCCR
, CKS
,
189 FIELD_EX8(r
, TCCR
, CKS
));
193 static uint64_t tmr_read(void *opaque
, hwaddr addr
, unsigned size
)
195 RTMRState
*tmr
= opaque
;
199 if (size
== 2 && (ch
!= 0 || addr
== A_TCR
|| addr
== A_TCSR
)) {
200 qemu_log_mask(LOG_GUEST_ERROR
, "renesas_tmr: Invalid read size 0x%"
205 switch (addr
& 0x0e) {
208 ret
= FIELD_DP8(ret
, TCR
, CCLR
,
209 FIELD_EX8(tmr
->tcr
[ch
], TCR
, CCLR
));
210 ret
= FIELD_DP8(ret
, TCR
, OVIE
,
211 FIELD_EX8(tmr
->tcr
[ch
], TCR
, OVIE
));
212 ret
= FIELD_DP8(ret
, TCR
, CMIEA
,
213 FIELD_EX8(tmr
->tcr
[ch
], TCR
, CMIEA
));
214 ret
= FIELD_DP8(ret
, TCR
, CMIEB
,
215 FIELD_EX8(tmr
->tcr
[ch
], TCR
, CMIEB
));
219 ret
= FIELD_DP8(ret
, TCSR
, OSA
,
220 FIELD_EX8(tmr
->tcsr
[ch
], TCSR
, OSA
));
221 ret
= FIELD_DP8(ret
, TCSR
, OSB
,
222 FIELD_EX8(tmr
->tcsr
[ch
], TCSR
, OSB
));
225 ret
= FIELD_DP8(ret
, TCSR
, ADTE
,
226 FIELD_EX8(tmr
->tcsr
[ch
], TCSR
, ADTE
));
228 case 1: /* CH1 ADTE unimplement always 1 */
229 ret
= FIELD_DP8(ret
, TCSR
, ADTE
, 1);
235 return tmr
->tcora
[ch
];
236 } else if (ch
== 0) {
237 return concat_reg(tmr
->tcora
);
242 return tmr
->tcorb
[ch
];
244 return concat_reg(tmr
->tcorb
);
247 return read_tcnt(tmr
, size
, ch
);
250 return read_tccr(tmr
->tccr
[ch
]);
252 return read_tccr(tmr
->tccr
[0]) << 8 | read_tccr(tmr
->tccr
[1]);
255 qemu_log_mask(LOG_UNIMP
, "renesas_tmr: Register 0x%" HWADDR_PRIX
256 " not implemented\n",
263 static void tmr_write_count(RTMRState
*tmr
, int ch
, unsigned size
,
264 uint8_t *reg
, uint64_t val
)
268 update_events(tmr
, ch
);
270 reg
[0] = extract32(val
, 8, 8);
271 reg
[1] = extract32(val
, 0, 8);
272 update_events(tmr
, 0);
273 update_events(tmr
, 1);
277 static void tmr_write(void *opaque
, hwaddr addr
, uint64_t val
, unsigned size
)
279 RTMRState
*tmr
= opaque
;
282 if (size
== 2 && (ch
!= 0 || addr
== A_TCR
|| addr
== A_TCSR
)) {
283 qemu_log_mask(LOG_GUEST_ERROR
,
284 "renesas_tmr: Invalid write size 0x%" HWADDR_PRIX
"\n",
288 switch (addr
& 0x0e) {
296 tmr_write_count(tmr
, ch
, size
, tmr
->tcora
, val
);
299 tmr_write_count(tmr
, ch
, size
, tmr
->tcorb
, val
);
302 tmr_write_count(tmr
, ch
, size
, tmr
->tcnt
, val
);
305 tmr_write_count(tmr
, ch
, size
, tmr
->tccr
, val
);
308 qemu_log_mask(LOG_UNIMP
, "renesas_tmr: Register 0x%" HWADDR_PRIX
309 " not implemented\n",
315 static const MemoryRegionOps tmr_ops
= {
318 .endianness
= DEVICE_LITTLE_ENDIAN
,
320 .min_access_size
= 1,
321 .max_access_size
= 2,
324 .min_access_size
= 1,
325 .max_access_size
= 2,
329 static void timer_events(RTMRState
*tmr
, int ch
);
331 static uint16_t issue_event(RTMRState
*tmr
, int ch
, int sz
,
332 uint16_t tcnt
, uint16_t tcora
, uint16_t tcorb
)
336 switch (tmr
->next
[ch
]) {
341 if (FIELD_EX8(tmr
->tcr
[ch
], TCR
, CCLR
) == CCLR_A
) {
344 if (FIELD_EX8(tmr
->tcr
[ch
], TCR
, CMIEA
)) {
345 qemu_irq_pulse(tmr
->cmia
[ch
]);
347 if (sz
== 8 && ch
== 0 &&
348 FIELD_EX8(tmr
->tccr
[1], TCCR
, CSS
) == CSS_CASCADING
) {
350 timer_events(tmr
, 1);
356 if (FIELD_EX8(tmr
->tcr
[ch
], TCR
, CCLR
) == CCLR_B
) {
359 if (FIELD_EX8(tmr
->tcr
[ch
], TCR
, CMIEB
)) {
360 qemu_irq_pulse(tmr
->cmib
[ch
]);
365 if ((tcnt
>= (1 << sz
)) && FIELD_EX8(tmr
->tcr
[ch
], TCR
, OVIE
)) {
366 qemu_irq_pulse(tmr
->ovi
[ch
]);
370 g_assert_not_reached();
375 static void timer_events(RTMRState
*tmr
, int ch
)
379 tmr
->tcnt
[ch
] = read_tcnt(tmr
, 1, ch
);
380 if (FIELD_EX8(tmr
->tccr
[0], TCCR
, CSS
) != CSS_CASCADING
) {
381 tmr
->tcnt
[ch
] = issue_event(tmr
, ch
, 8,
384 tmr
->tcorb
[ch
]) & 0xff;
389 tcnt
= issue_event(tmr
, ch
, 16,
390 concat_reg(tmr
->tcnt
),
391 concat_reg(tmr
->tcora
),
392 concat_reg(tmr
->tcorb
));
393 tmr
->tcnt
[0] = (tcnt
>> 8) & 0xff;
394 tmr
->tcnt
[1] = tcnt
& 0xff;
396 update_events(tmr
, ch
);
399 static void timer_event0(void *opaque
)
401 RTMRState
*tmr
= opaque
;
403 timer_events(tmr
, 0);
406 static void timer_event1(void *opaque
)
408 RTMRState
*tmr
= opaque
;
410 timer_events(tmr
, 1);
413 static void rtmr_reset(DeviceState
*dev
)
415 RTMRState
*tmr
= RTMR(dev
);
416 tmr
->tcr
[0] = tmr
->tcr
[1] = 0x00;
419 tmr
->tcnt
[0] = tmr
->tcnt
[1] = 0x00;
420 tmr
->tcora
[0] = tmr
->tcora
[1] = 0xff;
421 tmr
->tcorb
[0] = tmr
->tcorb
[1] = 0xff;
422 tmr
->tccr
[0] = tmr
->tccr
[1] = 0x00;
423 tmr
->next
[0] = tmr
->next
[1] = none
;
424 tmr
->tick
= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
);
427 static void rtmr_init(Object
*obj
)
429 SysBusDevice
*d
= SYS_BUS_DEVICE(obj
);
430 RTMRState
*tmr
= RTMR(obj
);
433 memory_region_init_io(&tmr
->memory
, OBJECT(tmr
), &tmr_ops
,
434 tmr
, "renesas-tmr", 0x10);
435 sysbus_init_mmio(d
, &tmr
->memory
);
437 for (i
= 0; i
< ARRAY_SIZE(tmr
->ovi
); i
++) {
438 sysbus_init_irq(d
, &tmr
->cmia
[i
]);
439 sysbus_init_irq(d
, &tmr
->cmib
[i
]);
440 sysbus_init_irq(d
, &tmr
->ovi
[i
]);
442 timer_init_ns(&tmr
->timer
[0], QEMU_CLOCK_VIRTUAL
, timer_event0
, tmr
);
443 timer_init_ns(&tmr
->timer
[1], QEMU_CLOCK_VIRTUAL
, timer_event1
, tmr
);
446 static const VMStateDescription vmstate_rtmr
= {
449 .minimum_version_id
= 1,
450 .fields
= (VMStateField
[]) {
451 VMSTATE_INT64(tick
, RTMRState
),
452 VMSTATE_UINT8_ARRAY(tcnt
, RTMRState
, TMR_CH
),
453 VMSTATE_UINT8_ARRAY(tcora
, RTMRState
, TMR_CH
),
454 VMSTATE_UINT8_ARRAY(tcorb
, RTMRState
, TMR_CH
),
455 VMSTATE_UINT8_ARRAY(tcr
, RTMRState
, TMR_CH
),
456 VMSTATE_UINT8_ARRAY(tccr
, RTMRState
, TMR_CH
),
457 VMSTATE_UINT8_ARRAY(tcor
, RTMRState
, TMR_CH
),
458 VMSTATE_UINT8_ARRAY(tcsr
, RTMRState
, TMR_CH
),
459 VMSTATE_INT64_ARRAY(div_round
, RTMRState
, TMR_CH
),
460 VMSTATE_UINT8_ARRAY(next
, RTMRState
, TMR_CH
),
461 VMSTATE_TIMER_ARRAY(timer
, RTMRState
, TMR_CH
),
462 VMSTATE_END_OF_LIST()
466 static Property rtmr_properties
[] = {
467 DEFINE_PROP_UINT64("input-freq", RTMRState
, input_freq
, 0),
468 DEFINE_PROP_END_OF_LIST(),
471 static void rtmr_class_init(ObjectClass
*klass
, void *data
)
473 DeviceClass
*dc
= DEVICE_CLASS(klass
);
475 dc
->vmsd
= &vmstate_rtmr
;
476 dc
->reset
= rtmr_reset
;
477 device_class_set_props(dc
, rtmr_properties
);
480 static const TypeInfo rtmr_info
= {
481 .name
= TYPE_RENESAS_TMR
,
482 .parent
= TYPE_SYS_BUS_DEVICE
,
483 .instance_size
= sizeof(RTMRState
),
484 .instance_init
= rtmr_init
,
485 .class_init
= rtmr_class_init
,
488 static void rtmr_register_types(void)
490 type_register_static(&rtmr_info
);
493 type_init(rtmr_register_types
)