Skip to content

Commit 4e7f1fa

Browse files
duynguyenxastephanosio
authored andcommitted
hw/timer/renesas_cmt: Update renesas_cmt timer
Correct CMCNT read value calculation Signed-off-by: Duy Nguyen <[email protected]> Signed-off-by: Phi Tran <[email protected]>
1 parent 37b8667 commit 4e7f1fa

File tree

2 files changed

+45
-53
lines changed

2 files changed

+45
-53
lines changed

hw/timer/renesas_cmt.c

Lines changed: 44 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -51,69 +51,52 @@ REG16(CMCR, 0)
5151
REG16(CMCNT, 2)
5252
REG16(CMCOR, 4)
5353

54-
static void update_events(RCMTState *cmt, int ch)
55-
{
56-
int64_t next_time;
54+
static uint16_t read_cmcnt(RCMTState *cmt, int ch) {
55+
if (!(cmt->cmstr & (1 << ch))) {
56+
return cmt->cmcnt[ch];
57+
}
58+
int64_t elapsed_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - cmt->tick[ch];
59+
uint64_t ticks = (elapsed_ns * cmt->cmt_freq[ch]) / (NANOSECONDS_PER_SECOND);
60+
uint32_t limit = cmt->cmcor[ch] + 1;
61+
return (cmt->cmcnt[ch] + ticks) % limit;
62+
}
5763

58-
if ((cmt->cmstr & (1 << ch)) == 0) {
59-
/* count disable, so not happened next event. */
64+
static void update_events(RCMTState *cmt, int ch) {
65+
if (!(cmt->cmstr & (1 << ch))) {
6066
return;
6167
}
62-
next_time = cmt->cmcor[ch] - cmt->cmcnt[ch];
63-
next_time *= NANOSECONDS_PER_SECOND;
64-
next_time /= cmt->input_freq;
65-
/*
66-
* CKS -> div rate
67-
* 0 -> 8 (1 << 3)
68-
* 1 -> 32 (1 << 5)
69-
* 2 -> 128 (1 << 7)
70-
* 3 -> 512 (1 << 9)
71-
*/
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);
75-
}
68+
uint16_t current = read_cmcnt(cmt, ch);
69+
uint32_t remain = (cmt->cmcor[ch] + 1) - current;
70+
if (remain == 0) {
71+
remain = cmt->cmcor[ch] + 1;
72+
}
73+
int64_t next_time = (int64_t)remain * NANOSECONDS_PER_SECOND / cmt->cmt_freq[ch];
7674

77-
static int64_t read_cmcnt(RCMTState *cmt, int ch)
78-
{
79-
int64_t delta, now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
75+
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
76+
int64_t fire_time = now + next_time;
8077

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);
86-
cmt->tick[ch] = now;
87-
return cmt->cmcnt[ch] + delta;
88-
} else {
89-
return cmt->cmcnt[ch];
78+
if (fire_time <= now) {
79+
fire_time = now + 1;
9080
}
81+
82+
timer_mod(&cmt->timer[ch], fire_time);
9183
}
9284

9385
static uint64_t cmt_read(void *opaque, hwaddr offset, unsigned size)
9486
{
9587
RCMTState *cmt = opaque;
9688
int ch = offset / 0x08;
97-
uint64_t ret;
9889

9990
if (offset == A_CMSTR) {
100-
ret = 0;
101-
ret = FIELD_DP16(ret, CMSTR, STR,
102-
FIELD_EX16(cmt->cmstr, CMSTR, STR));
103-
return ret;
91+
return FIELD_EX16(cmt->cmstr, CMSTR, STR);
10492
} else {
10593
offset &= 0x07;
10694
if (ch == 0) {
10795
offset -= 0x02;
10896
}
10997
switch (offset) {
11098
case A_CMCR:
111-
ret = 0;
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));
116-
return ret;
99+
return cmt->cmcr[ch];
117100
case A_CMCNT:
118101
return read_cmcnt(cmt, ch);
119102
case A_CMCOR:
@@ -123,12 +106,13 @@ static uint64_t cmt_read(void *opaque, hwaddr offset, unsigned size)
123106
qemu_log_mask(LOG_UNIMP, "renesas_cmt: Register 0x%" HWADDR_PRIX " "
124107
"not implemented\n",
125108
offset);
126-
return UINT64_MAX;
109+
return UINT16_MAX;
127110
}
128111

129-
static void start_stop(RCMTState *cmt, int ch, int st)
130-
{
131-
if (st) {
112+
static void start_stop(RCMTState *cmt, int ch, int enable) {
113+
if (enable) {
114+
cmt->cmcnt[ch] = 0;
115+
cmt->tick[ch] = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
132116
update_events(cmt, ch);
133117
} else {
134118
timer_del(&cmt->timer[ch]);
@@ -155,9 +139,13 @@ static void cmt_write(void *opaque, hwaddr offset, uint64_t val, unsigned size)
155139
FIELD_EX16(val, CMCR, CKS));
156140
cmt->cmcr[ch] = FIELD_DP16(cmt->cmcr[ch], CMCR, CMIE,
157141
FIELD_EX16(val, CMCR, CMIE));
142+
cmt->cmt_freq[ch] =
143+
cmt->input_freq / (8u << (2 * FIELD_EX16(cmt->cmcr[ch], CMCR, CKS)));
144+
update_events(cmt, ch);
158145
break;
159146
case 2:
160147
cmt->cmcnt[ch] = val;
148+
cmt->tick[ch] = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
161149
break;
162150
case 4:
163151
cmt->cmcor[ch] = val;
@@ -216,26 +204,29 @@ static void rcmt_reset(DeviceState *dev)
216204
{
217205
RCMTState *cmt = RCMT(dev);
218206
cmt->cmstr = 0;
219-
cmt->cmcr[0] = cmt->cmcr[1] = 0;
220-
cmt->cmcnt[0] = cmt->cmcnt[1] = 0;
221-
cmt->cmcor[0] = cmt->cmcor[1] = 0xffff;
207+
for (int i = 0; i < CMT_CH; i++) {
208+
cmt->cmcr[i] = 0;
209+
cmt->cmcnt[i] = 0;
210+
cmt->cmcor[i] = 0xFFFF;
211+
cmt->tick[i] = 0;
212+
}
222213
}
223214

224215
static void rcmt_init(Object *obj)
225216
{
226217
SysBusDevice *d = SYS_BUS_DEVICE(obj);
227218
RCMTState *cmt = RCMT(obj);
228-
int i;
229219

230220
memory_region_init_io(&cmt->memory, OBJECT(cmt), &cmt_ops,
231221
cmt, "renesas-cmt", 0x10);
232222
sysbus_init_mmio(d, &cmt->memory);
233223

234-
for (i = 0; i < ARRAY_SIZE(cmt->cmi); i++) {
224+
for (int i = 0; i < CMT_CH; i++) {
235225
sysbus_init_irq(d, &cmt->cmi[i]);
226+
cmt->cmt_freq[i] = cmt->input_freq >> 3;
227+
timer_init_ns(&cmt->timer[i], QEMU_CLOCK_VIRTUAL,
228+
(i == 0 ? timer_event0 : timer_event1), cmt);
236229
}
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);
239230
}
240231

241232
static const VMStateDescription vmstate_rcmt = {

include/hw/timer/renesas_cmt.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ struct RCMTState {
2929
/*< public >*/
3030

3131
uint64_t input_freq;
32+
uint64_t cmt_freq[CMT_CH];
3233
MemoryRegion memory;
3334

3435
uint16_t cmstr;

0 commit comments

Comments
 (0)