• R/O
  • HTTP
  • SSH
  • HTTPS

Commit

Tags
No Tags

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

Commit MetaInfo

Revisãobb5b431237d02302ba762251214b384d9ee5b762 (tree)
Hora2020-02-23 15:25:57
AutorYoshinori Sato <ysato@user...>
CommiterYoshinori Sato

Mensagem de Log

hw/timer: RX62N internal timer modules

renesas_tmr: 8bit timer modules.
renesas_cmt: 16bit compare match timer modules.
This part use many renesas's CPU.
Hardware manual.
https://www.renesas.com/us/en/doc/products/mpumcu/doc/rx_family/r01uh0033ej0140_rx62n.pdf

Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Message-Id: <20190607091116.49044-7-ysato@users.sourceforge.jp>
Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

Mudança Sumário

Diff

--- a/hw/timer/Kconfig
+++ b/hw/timer/Kconfig
@@ -35,3 +35,9 @@ config CMSDK_APB_TIMER
3535 config CMSDK_APB_DUALTIMER
3636 bool
3737 select PTIMER
38+
39+config RENESAS_TMR8
40+ bool
41+
42+config RENESAS_CMT
43+ bool
--- a/hw/timer/Makefile.objs
+++ b/hw/timer/Makefile.objs
@@ -28,6 +28,9 @@ common-obj-$(CONFIG_MIPS_CPS) += mips_gictimer.o
2828
2929 common-obj-$(CONFIG_ALLWINNER_A10_PIT) += allwinner-a10-pit.o
3030
31+obj-$(CONFIG_RENESAS_TMR8) += renesas_tmr.o
32+obj-$(CONFIG_RENESAS_CMT) += renesas_cmt.o
33+
3134 common-obj-$(CONFIG_STM32F2XX_TIMER) += stm32f2xx_timer.o
3235 common-obj-$(CONFIG_ASPEED_SOC) += aspeed_timer.o
3336
--- /dev/null
+++ b/hw/timer/renesas_cmt.c
@@ -0,0 +1,278 @@
1+/*
2+ * Renesas 16bit Compare-match timer
3+ *
4+ * Datasheet: RX62N Group, RX621 Group User's Manual: Hardware
5+ * (Rev.1.40 R01UH0033EJ0140)
6+ *
7+ * Copyright (c) 2019 Yoshinori Sato
8+ *
9+ * This program is free software; you can redistribute it and/or modify it
10+ * under the terms and conditions of the GNU General Public License,
11+ * version 2 or later, as published by the Free Software Foundation.
12+ *
13+ * This program is distributed in the hope it will be useful, but WITHOUT
14+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16+ * more details.
17+ *
18+ * You should have received a copy of the GNU General Public License along with
19+ * this program. If not, see <http://www.gnu.org/licenses/>.
20+ */
21+
22+#include "qemu/osdep.h"
23+#include "qemu-common.h"
24+#include "qemu/log.h"
25+#include "qapi/error.h"
26+#include "qemu/timer.h"
27+#include "cpu.h"
28+#include "hw/hw.h"
29+#include "hw/irq.h"
30+#include "hw/sysbus.h"
31+#include "hw/registerfields.h"
32+#include "hw/qdev-properties.h"
33+#include "hw/timer/renesas_cmt.h"
34+#include "migration/vmstate.h"
35+#include "qemu/error-report.h"
36+
37+/*
38+ * +0 CMSTR - common control
39+ * +2 CMCR - ch0
40+ * +4 CMCNT - ch0
41+ * +6 CMCOR - ch0
42+ * +8 CMCR - ch1
43+ * +10 CMCNT - ch1
44+ * +12 CMCOR - ch1
45+ * If we think that the address of CH 0 has an offset of +2,
46+ * we can treat it with the same address as CH 1, so define it like that.
47+ */
48+REG16(CMSTR, 0)
49+ FIELD(CMSTR, STR0, 0, 1)
50+ FIELD(CMSTR, STR1, 1, 1)
51+ FIELD(CMSTR, STR, 0, 2)
52+/* This addeess is channel offset */
53+REG16(CMCR, 0)
54+ FIELD(CMCR, CKS, 0, 2)
55+ FIELD(CMCR, CMIE, 6, 1)
56+REG16(CMCNT, 2)
57+REG16(CMCOR, 4)
58+
59+static void update_events(RCMTState *cmt, int ch)
60+{
61+ int64_t next_time;
62+
63+ if ((cmt->cmstr & (1 << ch)) == 0) {
64+ /* count disable, so not happened next event. */
65+ return ;
66+ }
67+ next_time = cmt->cmcor[ch] - cmt->cmcnt[ch];
68+ next_time *= NANOSECONDS_PER_SECOND;
69+ next_time /= cmt->input_freq;
70+ /*
71+ * CKS -> div rate
72+ * 0 -> 8 (1 << 3)
73+ * 1 -> 32 (1 << 5)
74+ * 2 -> 128 (1 << 7)
75+ * 3 -> 512 (1 << 9)
76+ */
77+ next_time *= 1 << (3 + FIELD_EX16(cmt->cmcr[ch], CMCR, CKS) * 2);
78+ next_time += qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
79+ timer_mod(cmt->timer[ch], next_time);
80+}
81+
82+static int64_t read_cmcnt(RCMTState *cmt, int ch)
83+{
84+ int64_t delta, now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
85+
86+ if (cmt->cmstr & (1 << ch)) {
87+ delta = (now - cmt->tick[ch]);
88+ delta /= NANOSECONDS_PER_SECOND;
89+ delta /= cmt->input_freq;
90+ delta /= 1 << (3 + FIELD_EX16(cmt->cmcr[ch], CMCR, CKS) * 2);
91+ cmt->tick[ch] = now;
92+ return cmt->cmcnt[ch] + delta;
93+ } else {
94+ return cmt->cmcnt[ch];
95+ }
96+}
97+
98+static uint64_t cmt_read(void *opaque, hwaddr addr, unsigned size)
99+{
100+ hwaddr offset = addr & 0x0f;
101+ RCMTState *cmt = opaque;
102+ int ch = offset / 0x08;
103+ uint64_t ret;
104+
105+ if (offset == A_CMSTR) {
106+ ret = 0;
107+ ret = FIELD_DP16(ret, CMSTR, STR,
108+ FIELD_EX16(cmt->cmstr, CMSTR, STR));
109+ return ret;
110+ } else {
111+ offset &= 0x07;
112+ if (ch == 0) {
113+ offset -= 0x02;
114+ }
115+ switch (offset) {
116+ case A_CMCR:
117+ ret = 0;
118+ ret = FIELD_DP16(ret, CMCR, CKS,
119+ FIELD_EX16(cmt->cmstr, CMCR, CKS));
120+ ret = FIELD_DP16(ret, CMCR, CMIE,
121+ FIELD_EX16(cmt->cmstr, CMCR, CMIE));
122+ return ret;
123+ case A_CMCNT:
124+ return read_cmcnt(cmt, ch);
125+ case A_CMCOR:
126+ return cmt->cmcor[ch];
127+ }
128+ }
129+ qemu_log_mask(LOG_UNIMP, "renesas_cmt: Register 0x%"
130+ HWADDR_PRIX " not implemented\n", offset);
131+ return UINT64_MAX;
132+}
133+
134+static void start_stop(RCMTState *cmt, int ch, int st)
135+{
136+ if (st) {
137+ update_events(cmt, ch);
138+ } else {
139+ timer_del(cmt->timer[ch]);
140+ }
141+}
142+
143+static void cmt_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
144+{
145+ hwaddr offset = addr & 0x0f;
146+ RCMTState *cmt = opaque;
147+ int ch = offset / 0x08;
148+
149+ if (offset == A_CMSTR) {
150+ cmt->cmstr = FIELD_EX16(val, CMSTR, STR);
151+ start_stop(cmt, 0, FIELD_EX16(cmt->cmstr, CMSTR, STR0));
152+ start_stop(cmt, 1, FIELD_EX16(cmt->cmstr, CMSTR, STR1));
153+ } else {
154+ offset &= 0x07;
155+ if (ch == 0) {
156+ offset -= 0x02;
157+ }
158+ switch (offset) {
159+ case A_CMCR:
160+ cmt->cmcr[ch] = FIELD_DP16(cmt->cmcr[ch], CMCR, CKS,
161+ FIELD_EX16(val, CMCR, CKS));
162+ cmt->cmcr[ch] = FIELD_DP16(cmt->cmcr[ch], CMCR, CMIE,
163+ FIELD_EX16(val, CMCR, CMIE));
164+ break;
165+ case 2:
166+ cmt->cmcnt[ch] = val;
167+ break;
168+ case 4:
169+ cmt->cmcor[ch] = val;
170+ break;
171+ default:
172+ qemu_log_mask(LOG_UNIMP, "renesas_cmt: Register -0x%" HWADDR_PRIX
173+ " not implemented\n", offset);
174+ return;
175+ }
176+ if (FIELD_EX16(cmt->cmstr, CMSTR, STR) & (1 << ch)) {
177+ update_events(cmt, ch);
178+ }
179+ }
180+}
181+
182+static const MemoryRegionOps cmt_ops = {
183+ .write = cmt_write,
184+ .read = cmt_read,
185+ .endianness = DEVICE_NATIVE_ENDIAN,
186+ .impl = {
187+ .min_access_size = 2,
188+ .max_access_size = 2,
189+ },
190+};
191+
192+static void timer_events(RCMTState *cmt, int ch)
193+{
194+ cmt->cmcnt[ch] = 0;
195+ cmt->tick[ch] = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
196+ update_events(cmt, ch);
197+ if (FIELD_EX16(cmt->cmcr[ch], CMCR, CMIE)) {
198+ qemu_irq_pulse(cmt->cmi[ch]);
199+ }
200+}
201+
202+static void timer_event0(void *opaque)
203+{
204+ RCMTState *cmt = opaque;
205+
206+ timer_events(cmt, 0);
207+}
208+
209+static void timer_event1(void *opaque)
210+{
211+ RCMTState *cmt = opaque;
212+
213+ timer_events(cmt, 1);
214+}
215+
216+static void rcmt_reset(DeviceState *dev)
217+{
218+ RCMTState *cmt = RCMT(dev);
219+ cmt->cmstr = 0;
220+ cmt->cmcr[0] = cmt->cmcr[1] = 0;
221+ cmt->cmcnt[0] = cmt->cmcnt[1] = 0;
222+ cmt->cmcor[0] = cmt->cmcor[1] = 0xffff;
223+}
224+
225+static void rcmt_init(Object *obj)
226+{
227+ SysBusDevice *d = SYS_BUS_DEVICE(obj);
228+ RCMTState *cmt = RCMT(obj);
229+ int i;
230+
231+ memory_region_init_io(&cmt->memory, OBJECT(cmt), &cmt_ops,
232+ cmt, "renesas-cmt", 0x10);
233+ sysbus_init_mmio(d, &cmt->memory);
234+
235+ for (i = 0; i < ARRAY_SIZE(cmt->cmi); i++) {
236+ sysbus_init_irq(d, &cmt->cmi[i]);
237+ }
238+ cmt->timer[0] = timer_new_ns(QEMU_CLOCK_VIRTUAL, timer_event0, cmt);
239+ cmt->timer[1] = timer_new_ns(QEMU_CLOCK_VIRTUAL, timer_event1, cmt);
240+}
241+
242+static const VMStateDescription vmstate_rcmt = {
243+ .name = "rx-cmt",
244+ .version_id = 1,
245+ .minimum_version_id = 1,
246+ .fields = (VMStateField[]) {
247+ VMSTATE_END_OF_LIST()
248+ }
249+};
250+
251+static Property rcmt_properties[] = {
252+ DEFINE_PROP_UINT64("input-freq", RCMTState, input_freq, 0),
253+ DEFINE_PROP_END_OF_LIST(),
254+};
255+
256+static void rcmt_class_init(ObjectClass *klass, void *data)
257+{
258+ DeviceClass *dc = DEVICE_CLASS(klass);
259+
260+ dc->vmsd = &vmstate_rcmt;
261+ dc->reset = rcmt_reset;
262+ device_class_set_props(dc, rcmt_properties);
263+}
264+
265+static const TypeInfo rcmt_info = {
266+ .name = TYPE_RENESAS_CMT,
267+ .parent = TYPE_SYS_BUS_DEVICE,
268+ .instance_size = sizeof(RCMTState),
269+ .instance_init = rcmt_init,
270+ .class_init = rcmt_class_init,
271+};
272+
273+static void rcmt_register_types(void)
274+{
275+ type_register_static(&rcmt_info);
276+}
277+
278+type_init(rcmt_register_types)
--- /dev/null
+++ b/hw/timer/renesas_tmr.c
@@ -0,0 +1,458 @@
1+/*
2+ * Renesas 8bit timer
3+ *
4+ * Datasheet: RX62N Group, RX621 Group User's Manual: Hardware
5+ * (Rev.1.40 R01UH0033EJ0140)
6+ *
7+ * Copyright (c) 2019 Yoshinori Sato
8+ *
9+ * This program is free software; you can redistribute it and/or modify it
10+ * under the terms and conditions of the GNU General Public License,
11+ * version 2 or later, as published by the Free Software Foundation.
12+ *
13+ * This program is distributed in the hope it will be useful, but WITHOUT
14+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16+ * more details.
17+ *
18+ * You should have received a copy of the GNU General Public License along with
19+ * this program. If not, see <http://www.gnu.org/licenses/>.
20+ */
21+
22+#include "qemu/osdep.h"
23+#include "qemu-common.h"
24+#include "qemu/log.h"
25+#include "qapi/error.h"
26+#include "qemu/timer.h"
27+#include "qemu/bitops.h"
28+#include "cpu.h"
29+#include "hw/hw.h"
30+#include "hw/irq.h"
31+#include "hw/sysbus.h"
32+#include "hw/registerfields.h"
33+#include "hw/qdev-properties.h"
34+#include "hw/timer/renesas_tmr.h"
35+#include "migration/vmstate.h"
36+#include "qemu/error-report.h"
37+
38+REG8(TCR, 0)
39+ FIELD(TCR, CCLR, 3, 2)
40+ FIELD(TCR, OVIE, 5, 1)
41+ FIELD(TCR, CMIEA, 6, 1)
42+ FIELD(TCR, CMIEB, 7, 1)
43+REG8(TCSR, 2)
44+ FIELD(TCSR, OSA, 0, 2)
45+ FIELD(TCSR, OSB, 2, 2)
46+ FIELD(TCSR, ADTE, 4, 2)
47+REG8(TCORA, 4)
48+REG8(TCORB, 6)
49+REG8(TCNT, 8)
50+REG8(TCCR, 10)
51+ FIELD(TCCR, CKS, 0, 3)
52+ FIELD(TCCR, CSS, 3, 2)
53+ FIELD(TCCR, TMRIS, 7, 1)
54+
55+#define INTERNAL 0x01
56+#define CASCADING 0x03
57+#define CCLR_A 0x01
58+#define CCLR_B 0x02
59+
60+static const int clkdiv[] = {0, 1, 2, 8, 32, 64, 1024, 8192};
61+
62+#define concat_reg(reg) ((reg[0] << 8) | reg[1])
63+static void update_events(RTMRState *tmr, int ch)
64+{
65+ uint16_t diff[TMR_NR_EVENTS], min;
66+ int64_t next_time;
67+ int i, event;
68+
69+ if (tmr->tccr[ch] == 0) {
70+ return ;
71+ }
72+ if (FIELD_EX8(tmr->tccr[ch], TCCR, CSS) == 0) {
73+ /* external clock mode */
74+ /* event not happened */
75+ return ;
76+ }
77+ if (FIELD_EX8(tmr->tccr[0], TCCR, CSS) == CASCADING) {
78+ /* cascading mode */
79+ if (ch == 1) {
80+ tmr->next[ch] = none;
81+ return ;
82+ }
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);
86+ } else {
87+ /* separate mode */
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];
91+ }
92+ /* Search for the most recently occurring event. */
93+ for (event = 0, min = diff[0], i = 1; i < none; i++) {
94+ if (min > diff[i]) {
95+ event = i;
96+ min = diff[i];
97+ }
98+ }
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);
106+}
107+
108+
109+static inline int elapsed_time(RTMRState *tmr, int ch, int64_t delta)
110+{
111+ int divrate = clkdiv[FIELD_EX8(tmr->tccr[ch], TCCR, CKS)];
112+ int et;
113+
114+ tmr->div_round[ch] += delta;
115+ if (divrate > 0) {
116+ et = tmr->div_round[ch] / divrate;
117+ tmr->div_round[ch] %= divrate;
118+ } else {
119+ /* disble clock. so no update */
120+ et = 0;
121+ }
122+ return et;
123+}
124+static uint16_t read_tcnt(RTMRState *tmr, unsigned size, int ch)
125+{
126+ int64_t delta, now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
127+ int elapsed, ovf = 0;
128+ uint16_t tcnt[2];
129+ uint32_t ret;
130+
131+ delta = (now - tmr->tick) * NANOSECONDS_PER_SECOND / tmr->input_freq;
132+ if (delta > 0) {
133+ tmr->tick = now;
134+
135+ if (FIELD_EX8(tmr->tccr[1], TCCR, CSS) == INTERNAL) {
136+ /* timer1 count update */
137+ elapsed = elapsed_time(tmr, 1, delta);
138+ if (elapsed >= 0x100) {
139+ ovf = elapsed >> 8;
140+ }
141+ tcnt[1] = tmr->tcnt[1] + (elapsed & 0xff);
142+ }
143+ switch (FIELD_EX8(tmr->tccr[0], TCCR, CSS)) {
144+ case INTERNAL:
145+ elapsed = elapsed_time(tmr, 0, delta);
146+ tcnt[0] = tmr->tcnt[0] + elapsed;
147+ break;
148+ case CASCADING:
149+ if (ovf > 0) {
150+ tcnt[0] = tmr->tcnt[0] + ovf;
151+ }
152+ break;
153+ }
154+ } else {
155+ tcnt[0] = tmr->tcnt[0];
156+ tcnt[1] = tmr->tcnt[1];
157+ }
158+ if (size == 1) {
159+ return tcnt[ch];
160+ } else {
161+ ret = 0;
162+ ret = deposit32(ret, 0, 8, tcnt[1]);
163+ ret = deposit32(ret, 8, 8, tcnt[0]);
164+ return ret;
165+ }
166+}
167+
168+static inline uint8_t read_tccr(uint8_t r)
169+{
170+ uint8_t tccr = 0;
171+ tccr = FIELD_DP8(tccr, TCCR, TMRIS,
172+ FIELD_EX8(r, TCCR, TMRIS));
173+ tccr = FIELD_DP8(tccr, TCCR, CSS,
174+ FIELD_EX8(r, TCCR, CSS));
175+ tccr = FIELD_DP8(tccr, TCCR, CKS,
176+ FIELD_EX8(r, TCCR, CKS));
177+ return tccr;
178+}
179+
180+static uint64_t tmr_read(void *opaque, hwaddr addr, unsigned size)
181+{
182+ RTMRState *tmr = opaque;
183+ int ch = addr & 1;
184+ uint64_t ret;
185+
186+ if (size == 2 && (ch != 0 || addr == A_TCR || addr == A_TCSR)) {
187+ qemu_log_mask(LOG_GUEST_ERROR, "renesas_tmr: Invalid read size 0x%"
188+ HWADDR_PRIX "\n", addr);
189+ return UINT64_MAX;
190+ }
191+ switch (addr & 0x0e) {
192+ case A_TCR:
193+ ret = 0;
194+ ret = FIELD_DP8(ret, TCR, CCLR,
195+ FIELD_EX8(tmr->tcr[ch], TCR, CCLR));
196+ ret = FIELD_DP8(ret, TCR, OVIE,
197+ FIELD_EX8(tmr->tcr[ch], TCR, OVIE));
198+ ret = FIELD_DP8(ret, TCR, CMIEA,
199+ FIELD_EX8(tmr->tcr[ch], TCR, CMIEA));
200+ ret = FIELD_DP8(ret, TCR, CMIEB,
201+ FIELD_EX8(tmr->tcr[ch], TCR, CMIEB));
202+ return ret;
203+ case A_TCSR:
204+ ret = 0;
205+ ret = FIELD_DP8(ret, TCSR, OSA,
206+ FIELD_EX8(tmr->tcsr[ch], TCSR, OSA));
207+ ret = FIELD_DP8(ret, TCSR, OSB,
208+ FIELD_EX8(tmr->tcsr[ch], TCSR, OSB));
209+ switch (ch) {
210+ case 0:
211+ ret = FIELD_DP8(ret, TCSR, ADTE,
212+ FIELD_EX8(tmr->tcsr[ch], TCSR, ADTE));
213+ break;
214+ case 1: /* CH1 ADTE unimplement always 1 */
215+ ret = FIELD_DP8(ret, TCSR, ADTE, 1);
216+ break;
217+ }
218+ return ret;
219+ case A_TCORA:
220+ if (size == 1) {
221+ return tmr->tcora[ch];
222+ } else if (ch == 0) {
223+ return concat_reg(tmr->tcora);
224+ }
225+ case A_TCORB:
226+ if (size == 1) {
227+ return tmr->tcorb[ch];
228+ } else {
229+ return concat_reg(tmr->tcorb);
230+ }
231+ case A_TCNT:
232+ return read_tcnt(tmr, size, ch);
233+ case A_TCCR:
234+ if (size == 1) {
235+ return read_tccr(tmr->tccr[ch]);
236+ } else {
237+ return read_tccr(tmr->tccr[0]) << 8 | read_tccr(tmr->tccr[1]);
238+ }
239+ default:
240+ qemu_log_mask(LOG_UNIMP, "renesas_tmr: Register 0x%" HWADDR_PRIX
241+ " not implemented\n", addr);
242+ break;
243+ }
244+ return UINT64_MAX;
245+}
246+
247+#define COUNT_WRITE(reg, val) \
248+ do { \
249+ if (size == 1) { \
250+ tmr->reg[ch] = val; \
251+ update_events(tmr, ch); \
252+ } else { \
253+ tmr->reg[0] = extract32(val, 8, 8); \
254+ tmr->reg[1] = extract32(val, 0, 8); \
255+ update_events(tmr, 0); \
256+ update_events(tmr, 1); \
257+ } \
258+ } while (0)
259+
260+static void tmr_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
261+{
262+ RTMRState *tmr = opaque;
263+ int ch = addr & 1;
264+
265+ if (size == 2 && (ch != 0 || addr == A_TCR || addr == A_TCSR)) {
266+ qemu_log_mask(LOG_GUEST_ERROR,
267+ "renesas_tmr: Invalid write size 0x%" HWADDR_PRIX
268+ "\n", addr);
269+ return;
270+ }
271+ switch (addr & 0x0e) {
272+ case A_TCR:
273+ tmr->tcr[ch] = val;
274+ break;
275+ case A_TCSR:
276+ tmr->tcsr[ch] = val;
277+ break;
278+ case A_TCORA:
279+ COUNT_WRITE(tcora, val);
280+ break;
281+ case A_TCORB:
282+ COUNT_WRITE(tcorb, val);
283+ break;
284+ case A_TCNT:
285+ COUNT_WRITE(tcnt, val);
286+ break;
287+ case A_TCCR:
288+ COUNT_WRITE(tccr, val);
289+ break;
290+ default:
291+ qemu_log_mask(LOG_UNIMP, "renesas_tmr: Register 0x%" HWADDR_PRIX
292+ " not implemented\n", addr);
293+ break;
294+ }
295+}
296+
297+static const MemoryRegionOps tmr_ops = {
298+ .write = tmr_write,
299+ .read = tmr_read,
300+ .endianness = DEVICE_LITTLE_ENDIAN,
301+ .impl = {
302+ .min_access_size = 1,
303+ .max_access_size = 2,
304+ },
305+};
306+
307+static void timer_events(RTMRState *tmr, int ch);
308+
309+static uint16_t issue_event(RTMRState *tmr, int ch, int sz,
310+ uint16_t tcnt, uint16_t tcora, uint16_t tcorb)
311+{
312+ uint16_t ret = tcnt;
313+
314+ switch (tmr->next[ch]) {
315+ case none:
316+ break;
317+ case cmia:
318+ if (tcnt >= tcora) {
319+ if (FIELD_EX8(tmr->tcr[ch], TCR, CCLR) == CCLR_A) {
320+ ret = tcnt - tcora;
321+ }
322+ if (FIELD_EX8(tmr->tcr[ch], TCR, CMIEA)) {
323+ qemu_irq_pulse(tmr->cmia[ch]);
324+ }
325+ if (sz == 8 && ch == 0 &&
326+ FIELD_EX8(tmr->tccr[1], TCCR, CSS) == CASCADING) {
327+ tmr->tcnt[1]++;
328+ timer_events(tmr, 1);
329+ }
330+ }
331+ break;
332+ case cmib:
333+ if (tcnt >= tcorb) {
334+ if (FIELD_EX8(tmr->tcr[ch], TCR, CCLR) == CCLR_B) {
335+ ret = tcnt - tcorb;
336+ }
337+ if (FIELD_EX8(tmr->tcr[ch], TCR, CMIEB)) {
338+ qemu_irq_pulse(tmr->cmib[ch]);
339+ }
340+ }
341+ break;
342+ case ovi:
343+ if ((tcnt >= (1 << sz)) && FIELD_EX8(tmr->tcr[ch], TCR, OVIE)) {
344+ qemu_irq_pulse(tmr->ovi[ch]);
345+ }
346+ break;
347+ default:
348+ g_assert_not_reached();
349+ }
350+ return ret;
351+}
352+
353+static void timer_events(RTMRState *tmr, int ch)
354+{
355+ uint16_t tcnt;
356+ tmr->tcnt[ch] = read_tcnt(tmr, 1, ch);
357+ if (FIELD_EX8(tmr->tccr[0], TCCR, CSS) != CASCADING) {
358+ tmr->tcnt[ch] = issue_event(tmr, ch, 8,
359+ tmr->tcnt[ch],
360+ tmr->tcora[ch], tmr->tcorb[ch]) & 0xff;
361+ } else {
362+ if (ch == 1) {
363+ return ;
364+ }
365+ tcnt = issue_event(tmr, ch, 16,
366+ concat_reg(tmr->tcnt),
367+ concat_reg(tmr->tcora),
368+ concat_reg(tmr->tcorb));
369+ tmr->tcnt[0] = (tcnt >> 8) & 0xff;
370+ tmr->tcnt[1] = tcnt & 0xff;
371+ }
372+ update_events(tmr, ch);
373+}
374+
375+static void timer_event0(void *opaque)
376+{
377+ RTMRState *tmr = opaque;
378+
379+ timer_events(tmr, 0);
380+}
381+
382+static void timer_event1(void *opaque)
383+{
384+ RTMRState *tmr = opaque;
385+
386+ timer_events(tmr, 1);
387+}
388+
389+static void rtmr_reset(DeviceState *dev)
390+{
391+ RTMRState *tmr = RTMR(dev);
392+ tmr->tcr[0] = tmr->tcr[1] = 0x00;
393+ tmr->tcsr[0] = 0x00;
394+ tmr->tcsr[1] = 0x10;
395+ tmr->tcnt[0] = tmr->tcnt[1] = 0x00;
396+ tmr->tcora[0] = tmr->tcora[1] = 0xff;
397+ tmr->tcorb[0] = tmr->tcorb[1] = 0xff;
398+ tmr->tccr[0] = tmr->tccr[1] = 0x00;
399+ tmr->next[0] = tmr->next[1] = none;
400+ tmr->tick = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
401+}
402+
403+static void rtmr_init(Object *obj)
404+{
405+ SysBusDevice *d = SYS_BUS_DEVICE(obj);
406+ RTMRState *tmr = RTMR(obj);
407+ int i;
408+
409+ memory_region_init_io(&tmr->memory, OBJECT(tmr), &tmr_ops,
410+ tmr, "renesas-tmr", 0x10);
411+ sysbus_init_mmio(d, &tmr->memory);
412+
413+ for (i = 0; i < ARRAY_SIZE(tmr->ovi); i++) {
414+ sysbus_init_irq(d, &tmr->cmia[i]);
415+ sysbus_init_irq(d, &tmr->cmib[i]);
416+ sysbus_init_irq(d, &tmr->ovi[i]);
417+ }
418+ tmr->timer[0] = timer_new_ns(QEMU_CLOCK_VIRTUAL, timer_event0, tmr);
419+ tmr->timer[1] = timer_new_ns(QEMU_CLOCK_VIRTUAL, timer_event1, tmr);
420+}
421+
422+static const VMStateDescription vmstate_rtmr = {
423+ .name = "rx-tmr",
424+ .version_id = 1,
425+ .minimum_version_id = 1,
426+ .fields = (VMStateField[]) {
427+ VMSTATE_END_OF_LIST()
428+ }
429+};
430+
431+static Property rtmr_properties[] = {
432+ DEFINE_PROP_UINT64("input-freq", RTMRState, input_freq, 0),
433+ DEFINE_PROP_END_OF_LIST(),
434+};
435+
436+static void rtmr_class_init(ObjectClass *klass, void *data)
437+{
438+ DeviceClass *dc = DEVICE_CLASS(klass);
439+
440+ dc->vmsd = &vmstate_rtmr;
441+ dc->reset = rtmr_reset;
442+ device_class_set_props(dc, rtmr_properties);
443+}
444+
445+static const TypeInfo rtmr_info = {
446+ .name = TYPE_RENESAS_TMR,
447+ .parent = TYPE_SYS_BUS_DEVICE,
448+ .instance_size = sizeof(RTMRState),
449+ .instance_init = rtmr_init,
450+ .class_init = rtmr_class_init,
451+};
452+
453+static void rtmr_register_types(void)
454+{
455+ type_register_static(&rtmr_info);
456+}
457+
458+type_init(rtmr_register_types)
--- /dev/null
+++ b/include/hw/timer/renesas_cmt.h
@@ -0,0 +1,38 @@
1+/*
2+ * Renesas Compare-match timer Object
3+ *
4+ * Copyright (c) 2019 Yoshinori Sato
5+ *
6+ * This code is licensed under the GPL version 2 or later.
7+ *
8+ */
9+
10+#ifndef HW_RENESAS_CMT_H
11+#define HW_RENESAS_CMT_H
12+
13+#include "hw/sysbus.h"
14+
15+#define TYPE_RENESAS_CMT "renesas-cmt"
16+#define RCMT(obj) OBJECT_CHECK(RCMTState, (obj), TYPE_RENESAS_CMT)
17+
18+enum {
19+ CMT_CH = 2,
20+ CMT_NR_IRQ = 1 * CMT_CH,
21+};
22+
23+typedef struct RCMTState {
24+ SysBusDevice parent_obj;
25+
26+ uint64_t input_freq;
27+ MemoryRegion memory;
28+
29+ uint16_t cmstr;
30+ uint16_t cmcr[CMT_CH];
31+ uint16_t cmcnt[CMT_CH];
32+ uint16_t cmcor[CMT_CH];
33+ int64_t tick[CMT_CH];
34+ qemu_irq cmi[CMT_CH];
35+ QEMUTimer *timer[CMT_CH];
36+} RCMTState;
37+
38+#endif
--- /dev/null
+++ b/include/hw/timer/renesas_tmr.h
@@ -0,0 +1,53 @@
1+/*
2+ * Renesas 8bit timer Object
3+ *
4+ * Copyright (c) 2018 Yoshinori Sato
5+ *
6+ * This code is licensed under the GPL version 2 or later.
7+ *
8+ */
9+
10+#ifndef HW_RENESAS_TMR_H
11+#define HW_RENESAS_TMR_H
12+
13+#include "hw/sysbus.h"
14+
15+#define TYPE_RENESAS_TMR "renesas-tmr"
16+#define RTMR(obj) OBJECT_CHECK(RTMRState, (obj), TYPE_RENESAS_TMR)
17+
18+enum timer_event {
19+ cmia = 0,
20+ cmib = 1,
21+ ovi = 2,
22+ none = 3,
23+ TMR_NR_EVENTS = 4
24+};
25+
26+enum {
27+ TMR_CH = 2,
28+ TMR_NR_IRQ = 3 * TMR_CH,
29+};
30+
31+typedef struct RTMRState {
32+ SysBusDevice parent_obj;
33+
34+ uint64_t input_freq;
35+ MemoryRegion memory;
36+
37+ uint8_t tcnt[TMR_CH];
38+ uint8_t tcora[TMR_CH];
39+ uint8_t tcorb[TMR_CH];
40+ uint8_t tcr[TMR_CH];
41+ uint8_t tccr[TMR_CH];
42+ uint8_t tcor[TMR_CH];
43+ uint8_t tcsr[TMR_CH];
44+ int64_t tick;
45+ int64_t div_round[TMR_CH];
46+ enum timer_event next[TMR_CH];
47+ qemu_irq cmia[TMR_CH];
48+ qemu_irq cmib[TMR_CH];
49+ qemu_irq ovi[TMR_CH];
50+ QEMUTimer *timer[TMR_CH];
51+} RTMRState;
52+
53+#endif