From nobody Sun Feb 8 12:19:40 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1551508131382250.33618096421014; Fri, 1 Mar 2019 22:28:51 -0800 (PST) Received: from localhost ([127.0.0.1]:49145 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gzy8c-0006OY-80 for importer@patchew.org; Sat, 02 Mar 2019 01:28:46 -0500 Received: from eggs.gnu.org ([209.51.188.92]:49488) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gzy4D-0002vM-6z for qemu-devel@nongnu.org; Sat, 02 Mar 2019 01:24:15 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gzy2B-00031F-1q for qemu-devel@nongnu.org; Sat, 02 Mar 2019 01:22:10 -0500 Received: from mail01.asahi-net.or.jp ([202.224.55.13]:48783) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gzy29-0002yF-8h for qemu-devel@nongnu.org; Sat, 02 Mar 2019 01:22:06 -0500 Received: from h61-195-96-97.vps.ablenet.jp (h61-195-96-97.vps.ablenet.jp [61.195.96.97]) (Authenticated sender: PQ4Y-STU) by mail01.asahi-net.or.jp (Postfix) with ESMTPA id A994410C404; Sat, 2 Mar 2019 15:21:50 +0900 (JST) Received: from ysato.dip.jp (ZM005235.ppp.dion.ne.jp [222.8.5.235]) by h61-195-96-97.vps.ablenet.jp (Postfix) with ESMTPSA id 68376240089; Sat, 2 Mar 2019 15:21:50 +0900 (JST) From: Yoshinori Sato To: qemu-devel@nongnu.org Date: Sat, 2 Mar 2019 15:21:34 +0900 Message-Id: <20190302062138.10713-8-ysato@users.sourceforge.jp> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20190302062138.10713-1-ysato@users.sourceforge.jp> References: <20190122121413.31437-1-ysato@users.sourceforge.jp> <20190302062138.10713-1-ysato@users.sourceforge.jp> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 202.224.55.13 Subject: [Qemu-devel] [PATCH RFC v3 07/11] RX62N internal timer modules X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: peter.maydell@linaro.org, richard.henderson@linaro.org, Yoshinori Sato Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" 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/r01uh0033ej= 0140_rx62n.pdf?key=3D086621e01bd70347c18ea7f794aa9cc3 Signed-off-by: Yoshinori Sato --- hw/timer/Makefile.objs | 2 + hw/timer/renesas_cmt.c | 235 +++++++++++++++++++++++ hw/timer/renesas_tmr.c | 412 +++++++++++++++++++++++++++++++++++++= ++++ include/hw/timer/renesas_cmt.h | 33 ++++ include/hw/timer/renesas_tmr.h | 42 +++++ 5 files changed, 724 insertions(+) create mode 100644 hw/timer/renesas_cmt.c create mode 100644 hw/timer/renesas_tmr.c create mode 100644 include/hw/timer/renesas_cmt.h create mode 100644 include/hw/timer/renesas_tmr.h diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs index 0e9a4530f8..e11aaf5bf5 100644 --- a/hw/timer/Makefile.objs +++ b/hw/timer/Makefile.objs @@ -40,6 +40,8 @@ obj-$(CONFIG_MC146818RTC) +=3D mc146818rtc.o =20 obj-$(CONFIG_ALLWINNER_A10_PIT) +=3D allwinner-a10-pit.o =20 +obj-$(CONFIG_RX) +=3D renesas_tmr.o renesas_cmt.o + common-obj-$(CONFIG_STM32F2XX_TIMER) +=3D stm32f2xx_timer.o common-obj-$(CONFIG_ASPEED_SOC) +=3D aspeed_timer.o =20 diff --git a/hw/timer/renesas_cmt.c b/hw/timer/renesas_cmt.c new file mode 100644 index 0000000000..3d4a7d6ca6 --- /dev/null +++ b/hw/timer/renesas_cmt.c @@ -0,0 +1,235 @@ +/* + * Renesas 16bit Compare-match timer + * + * Copyright (c) 2019 Yoshinori Sato + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License f= or + * more details. + * + * You should have received a copy of the GNU General Public License along= with + * this program. If not, see . + */ + +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "qemu/timer.h" +#include "cpu.h" +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/timer/renesas_cmt.h" +#include "qemu/error-report.h" + +#define freq_to_ns(freq) (1000000000LL / freq) +static const int clkdiv[] =3D {8, 32, 128, 512}; + +static void update_events(RCMTState *cmt, int ch) +{ + uint16_t diff; + + if ((cmt->cmstr & (1 << ch)) !=3D 0) { + diff =3D cmt->cmcor[ch] - cmt->cmcnt[ch]; + timer_mod(cmt->timer[ch], + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + + diff * freq_to_ns(cmt->input_freq) * + clkdiv[cmt->cmcr[ch] & 3]); + } +} + +static uint64_t read_cmcnt(RCMTState *cmt, int ch) +{ + int64_t delta, now =3D qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + + if (cmt->cmstr & (1 << ch)) { + delta =3D (now - cmt->tick[ch]) / freq_to_ns(cmt->input_freq); + delta /=3D clkdiv[cmt->cmcr[ch] & 0x03]; + return cmt->cmcnt[ch] + delta; + } else { + return cmt->cmcnt[ch]; + } +} + +static uint64_t cmt_read(void *opaque, hwaddr addr, unsigned size) +{ + hwaddr offset =3D addr & 0x0f; + RCMTState *cmt =3D opaque; + int ch =3D offset / 0x08; + int error =3D 1; + + if (offset =3D=3D 0) { + return cmt->cmstr; + error =3D 0; + } else { + offset &=3D 0x07; + if (ch =3D=3D 0) { + offset -=3D 0x02; + } + error =3D 0; + switch (offset) { + case 0: + return cmt->cmcr[ch]; + case 2: + return read_cmcnt(cmt, ch); + case 4: + return cmt->cmcor[ch]; + default: + error =3D 1; + } + } + if (error) { + error_report("rcmt: unsupported read request to %08lx", addr); + } + return 0xffffffffffffffffUL; +} + +static void start_stop(RCMTState *cmt, int ch, int st) +{ + if (st) { + update_events(cmt, ch); + } else { + timer_del(cmt->timer[ch]); + } +} + +static void cmt_write(void *opaque, hwaddr addr, uint64_t val, unsigned si= ze) +{ + hwaddr offset =3D addr & 0x0f; + RCMTState *cmt =3D opaque; + int ch =3D offset / 0x08; + int error =3D 1; + + if (offset =3D=3D 0) { + cmt->cmstr =3D val; + start_stop(cmt, 0, cmt->cmstr & 1); + start_stop(cmt, 1, (cmt->cmstr >> 1) & 1); + error =3D 0; + } else { + offset &=3D 0x07; + if (ch =3D=3D 0) { + offset -=3D 0x02; + } + error =3D 0; + switch (offset) { + case 0: + cmt->cmcr[ch] =3D val; + break; + case 2: + cmt->cmcnt[ch] =3D val; + break; + case 4: + cmt->cmcor[ch] =3D val; + break; + default: + error =3D 1; + } + if (error =3D=3D 0 && cmt->cmstr & (1 << ch)) { + update_events(cmt, ch); + } + } + if (error) { + error_report("rcmt: unsupported write request to %08lx", addr); + } +} + +static const MemoryRegionOps cmt_ops =3D { + .write =3D cmt_write, + .read =3D cmt_read, + .endianness =3D DEVICE_NATIVE_ENDIAN, + .impl =3D { + .min_access_size =3D 2, + .max_access_size =3D 2, + }, +}; + +static void timer_events(RCMTState *cmt, int ch) +{ + cmt->cmcnt[ch] =3D 0; + cmt->tick[ch] =3D qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + update_events(cmt, ch); + if (cmt->cmcr[ch] & 0x40) { + qemu_irq_pulse(cmt->cmi[ch]); + } +} + +static void timer_event0(void *opaque) +{ + RCMTState *cmt =3D opaque; + + timer_events(cmt, 0); +} + +static void timer_event1(void *opaque) +{ + RCMTState *cmt =3D opaque; + + timer_events(cmt, 1); +} + +static void rcmt_reset(DeviceState *dev) +{ + RCMTState *cmt =3D RCMT(dev); + cmt->cmstr =3D 0; + cmt->cmcr[0] =3D cmt->cmcr[1] =3D 0; + cmt->cmcnt[0] =3D cmt->cmcnt[1] =3D 0; + cmt->cmcor[0] =3D cmt->cmcor[1] =3D 0xffff; +} + +static void rcmt_init(Object *obj) +{ + SysBusDevice *d =3D SYS_BUS_DEVICE(obj); + RCMTState *cmt =3D RCMT(obj); + int i; + + memory_region_init_io(&cmt->memory, OBJECT(cmt), &cmt_ops, + cmt, "renesas-cmt", 0x10); + sysbus_init_mmio(d, &cmt->memory); + + for (i =3D 0; i < 2; i++) { + sysbus_init_irq(d, &cmt->cmi[i]); + } + cmt->timer[0] =3D timer_new_ns(QEMU_CLOCK_VIRTUAL, timer_event0, cmt); + cmt->timer[1] =3D timer_new_ns(QEMU_CLOCK_VIRTUAL, timer_event1, cmt); +} + +static const VMStateDescription vmstate_rcmt =3D { + .name =3D "rx-cmt", + .version_id =3D 1, + .minimum_version_id =3D 1, + .fields =3D (VMStateField[]) { + VMSTATE_END_OF_LIST() + } +}; + +static Property rcmt_properties[] =3D { + DEFINE_PROP_UINT64("input-freq", RCMTState, input_freq, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void rcmt_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(klass); + + dc->props =3D rcmt_properties; + dc->vmsd =3D &vmstate_rcmt; + dc->reset =3D rcmt_reset; +} + +static const TypeInfo rcmt_info =3D { + .name =3D TYPE_RENESAS_CMT, + .parent =3D TYPE_SYS_BUS_DEVICE, + .instance_size =3D sizeof(RCMTState), + .instance_init =3D rcmt_init, + .class_init =3D rcmt_class_init, +}; + +static void rcmt_register_types(void) +{ + type_register_static(&rcmt_info); +} + +type_init(rcmt_register_types) diff --git a/hw/timer/renesas_tmr.c b/hw/timer/renesas_tmr.c new file mode 100644 index 0000000000..f8d7c22fb4 --- /dev/null +++ b/hw/timer/renesas_tmr.c @@ -0,0 +1,412 @@ +/* + * Renesas 8bit timer + * + * Copyright (c) 2019 Yoshinori Sato + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License f= or + * more details. + * + * You should have received a copy of the GNU General Public License along= with + * this program. If not, see . + */ + +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "qemu/timer.h" +#include "cpu.h" +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/timer/renesas_tmr.h" +#include "qemu/error-report.h" + +#define freq_to_ns(freq) (1000000000LL / freq) +static const int clkdiv[] =3D {0, 1, 2, 8, 32, 64, 1024, 8192}; + +static void update_events(RTMRState *tmr, int ch) +{ + uint16_t diff[3]; + uint16_t tcnt, tcora, tcorb; + int i, min, event; + + if (tmr->tccr[ch] =3D=3D 0) { + return ; + } + if ((tmr->tccr[ch] & 0x08) =3D=3D 0) { + error_report("rtmr: unsupported count mode %02x", tmr->tccr[ch]); + return ; + } + if ((tmr->tccr[0] & 0x18) =3D=3D 0x18) { + if (ch =3D=3D 1) { + tmr->next[ch] =3D none; + return ; + } + tcnt =3D (tmr->tcnt[0] << 8) + tmr->tcnt[1]; + tcora =3D (tmr->tcora[0] << 8) | tmr->tcora[1]; + tcorb =3D (tmr->tcorb[0] << 8) | tmr->tcorb[1]; + diff[0] =3D tcora - tcnt; + diff[1] =3D tcorb - tcnt; + diff[2] =3D 0x10000 - tcnt; + } else { + diff[0] =3D tmr->tcora[ch] - tmr->tcnt[ch]; + diff[1] =3D tmr->tcorb[ch] - tmr->tcnt[ch]; + diff[2] =3D 0x100 - tmr->tcnt[ch]; + } + for (event =3D 0, min =3D diff[0], i =3D 1; i < 3; i++) { + if (min > diff[i]) { + event =3D i; + min =3D diff[i]; + } + } + tmr->next[ch] =3D event + 1; + timer_mod(tmr->timer[ch], + diff[event] * freq_to_ns(tmr->input_freq) * + clkdiv[tmr->tccr[ch] & 7]); +} + +#define UPDATE_TIME(tmr, ch, upd, delta) \ + do { \ + tmr->div_round[ch] +=3D delta; \ + if (clkdiv[tmr->tccr[ch] & 0x07] > 0) { \ + upd =3D tmr->div_round[ch] / clkdiv[tmr->tccr[ch] & 0x07]; \ + tmr->div_round[ch] %=3D clkdiv[tmr->tccr[ch] & 0x07]; \ + } else \ + upd =3D 0; \ + } while (0) + +static uint64_t read_tcnt(RTMRState *tmr, unsigned size, int ch) +{ + int64_t delta, now =3D qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + int upd, ovf =3D 0; + uint16_t tcnt[2]; + uint16_t cnt; + + delta =3D (now - tmr->tick) / freq_to_ns(tmr->input_freq); + if (delta > 0) { + tmr->tick =3D now; + + if ((tmr->tccr[1] & 0x18) =3D=3D 0x08) { + UPDATE_TIME(tmr, 1, upd, delta); + if (upd >=3D 0x100) { + ovf =3D upd >> 8; + upd -=3D ovf; + } + tcnt[1] =3D tmr->tcnt[1] + upd; + } + switch (tmr->tccr[0] & 0x18) { + case 0x08: + UPDATE_TIME(tmr, 0, upd, delta); + tcnt[0] =3D tmr->tcnt[0] + upd; + break; + case 0x18: + if (ovf > 0) { + tcnt[0] =3D tmr->tcnt[0] + ovf; + } + break; + } + } else { + tcnt[0] =3D tmr->tcnt[0]; + tcnt[1] =3D tmr->tcnt[1]; + } + if (size =3D=3D 1) { + return tcnt[ch]; + } else { + cnt =3D (tmr->tcnt[0] << 8) | (tmr->tcnt[1] & 0xff); + return cnt; + } +} + +static uint64_t tmr_read(void *opaque, hwaddr addr, unsigned size) +{ + hwaddr offset =3D addr & 0x1f; + RTMRState *tmr =3D opaque; + int ch =3D offset & 1; + int error =3D 0; + + if (size =3D=3D 1) { + switch (offset & 0x0e) { + case 0x00: + return tmr->tcr[ch] & 0xf8; + case 0x02: + return tmr->tcsr[ch] & 0xf8; + case 0x04: + return tmr->tcora[ch]; + case 0x06: + return tmr->tcorb[ch]; + case 0x08: + return read_tcnt(tmr, size, ch); + case 0x0a: + return tmr->tccr[ch]; + default: + error =3D 1; + } + } else if (ch =3D=3D 0) { + switch (offset & 0x0e) { + case 0x04: + return tmr->tcora[0] << 8 | tmr->tcora[1]; + case 0x06: + return tmr->tcorb[0] << 8 | tmr->tcorb[1];; + case 0x08: + return read_tcnt(tmr, size, 0) & 0xff; + case 0x0a: + return tmr->tccr[0] << 8 | tmr->tccr[1]; + default: + error =3D 1; + } + } else { + error =3D 1; + } + if (error) { + error_report("rtmr: unsupported read request to %08lx", addr); + } + return 0xffffffffffffffffULL; +} + +static void tmr_write(void *opaque, hwaddr addr, uint64_t val, unsigned si= ze) +{ + hwaddr offset =3D addr & 0x1f; + RTMRState *tmr =3D opaque; + int ch =3D offset & 1; + int error =3D 0; + + if (size =3D=3D 1) { + switch (offset & 0x0e) { + case 0x00: + tmr->tcr[ch] =3D val; + break; + case 0x02: + tmr->tcsr[ch] =3D val; + break; + case 0x04: + tmr->tcora[ch] =3D val; + update_events(tmr, ch); + break; + case 0x06: + tmr->tcora[ch] =3D val; + update_events(tmr, ch); + break; + case 0x08: + tmr->tcnt[ch] =3D val; + update_events(tmr, ch); + break; + case 0x0a: + tmr->tccr[ch] =3D val; + update_events(tmr, ch); + break; + default: + error =3D 1; + } + } else if (ch =3D=3D 0) { + switch (offset & 0x0e) { + case 0x04: + tmr->tcora[0] =3D (val >> 8) & 0xff; + tmr->tcora[1] =3D val & 0xff; + update_events(tmr, 0); + update_events(tmr, 1); + case 0x06: + tmr->tcorb[0] =3D (val >> 8) & 0xff; + tmr->tcorb[1] =3D val & 0xff; + update_events(tmr, 0); + update_events(tmr, 1); + break; + case 0x08: + tmr->tcnt[0] =3D (val >> 8) & 0xff; + tmr->tcnt[1] =3D val & 0xff; + update_events(tmr, 0); + update_events(tmr, 1); + break; + case 0x0a: + tmr->tccr[0] =3D (val >> 8) & 0xff; + tmr->tccr[1] =3D val & 0xff; + update_events(tmr, 0); + update_events(tmr, 1); + break; + default: + error =3D 1; + } + } else { + error =3D 1; + } + if (error) { + error_report("rtmr: unsupported write request to %08lx", addr); + } +} + +static const MemoryRegionOps tmr_ops =3D { + .write =3D tmr_write, + .read =3D tmr_read, + .endianness =3D DEVICE_LITTLE_ENDIAN, + .impl =3D { + .min_access_size =3D 1, + .max_access_size =3D 2, + }, +}; + +static void timer_events(RTMRState *tmr, int ch) +{ + tmr->tcnt[ch] =3D read_tcnt(tmr, 1, ch); + if ((tmr->tccr[0] & 0x18) !=3D 0x18) { + switch (tmr->next[ch]) { + case none: + break; + case cmia: + if (tmr->tcnt[ch] >=3D tmr->tcora[ch]) { + if ((tmr->tcr[ch] & 0x18) =3D=3D 0x08) { + tmr->tcnt[ch] =3D 0; + } + if ((tmr->tcr[ch] & 0x40)) { + qemu_irq_pulse(tmr->cmia[ch]); + } + if (ch =3D=3D 0 && (tmr->tccr[1] & 0x18) =3D=3D 0x18) { + tmr->tcnt[1]++; + timer_events(tmr, 1); + } + } + break; + case cmib: + if (tmr->tcnt[ch] >=3D tmr->tcorb[ch]) { + if ((tmr->tcr[ch] & 0x18) =3D=3D 0x10) { + tmr->tcnt[ch] =3D 0; + } + if ((tmr->tcr[ch] & 0x80)) { + qemu_irq_pulse(tmr->cmib[ch]); + } + } + break; + case ovi: + if ((tmr->tcnt[ch] >=3D 0x100) && + (tmr->tcr[ch] & 0x20)) { + qemu_irq_pulse(tmr->ovi[ch]); + } + break; + } + tmr->tcnt[ch] &=3D 0xff; + } else { + uint32_t tcnt, tcora, tcorb; + if (ch =3D=3D 1) { + return ; + } + tcnt =3D (tmr->tcnt[0] << 8) + tmr->tcnt[1]; + tcora =3D (tmr->tcora[0] << 8) | tmr->tcora[1]; + tcorb =3D (tmr->tcorb[0] << 8) | tmr->tcorb[1]; + switch (tmr->next[ch]) { + case none: + break; + case cmia: + if (tcnt >=3D tcora) { + if ((tmr->tcr[ch] & 0x18) =3D=3D 0x08) { + tcnt =3D 0; + } + if ((tmr->tcr[ch] & 0x40)) { + qemu_irq_pulse(tmr->cmia[ch]); + } + } + break; + case cmib: + if (tcnt >=3D tcorb) { + if ((tmr->tcr[ch] & 0x18) =3D=3D 0x10) { + tcnt =3D 0; + } + if ((tmr->tcr[ch] & 0x80)) { + qemu_irq_pulse(tmr->cmib[ch]); + } + } + break; + case ovi: + if ((tcnt >=3D 0x10000) && + (tmr->tcr[ch] & 0x20)) { + qemu_irq_pulse(tmr->ovi[ch]); + } + break; + } + tmr->tcnt[0] =3D (tcnt >> 8) & 0xff; + tmr->tcnt[1] =3D tcnt & 0xff; + } + update_events(tmr, ch); +} + +static void timer_event0(void *opaque) +{ + RTMRState *tmr =3D opaque; + + timer_events(tmr, 0); +} + +static void timer_event1(void *opaque) +{ + RTMRState *tmr =3D opaque; + + timer_events(tmr, 1); +} + +static void rtmr_reset(DeviceState *dev) +{ + RTMRState *tmr =3D RTMR(dev); + tmr->tcora[0] =3D tmr->tcora[1] =3D 0xff; + tmr->tcorb[0] =3D tmr->tcorb[1] =3D 0xff; + tmr->tcsr[0] =3D 0x00; + tmr->tcsr[1] =3D 0x10; + tmr->tick =3D qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); +} + +static void rtmr_init(Object *obj) +{ + SysBusDevice *d =3D SYS_BUS_DEVICE(obj); + RTMRState *tmr =3D RTMR(obj); + int i; + + memory_region_init_io(&tmr->memory, OBJECT(tmr), &tmr_ops, + tmr, "rx-tmr", 0x10); + sysbus_init_mmio(d, &tmr->memory); + + for (i =3D 0; i < 2; i++) { + sysbus_init_irq(d, &tmr->cmia[i]); + sysbus_init_irq(d, &tmr->cmib[i]); + sysbus_init_irq(d, &tmr->ovi[i]); + } + tmr->timer[0] =3D timer_new_ns(QEMU_CLOCK_VIRTUAL, timer_event0, tmr); + tmr->timer[1] =3D timer_new_ns(QEMU_CLOCK_VIRTUAL, timer_event1, tmr); +} + +static const VMStateDescription vmstate_rtmr =3D { + .name =3D "rx-cmt", + .version_id =3D 1, + .minimum_version_id =3D 1, + .fields =3D (VMStateField[]) { + VMSTATE_END_OF_LIST() + } +}; + +static Property rtmr_properties[] =3D { + DEFINE_PROP_UINT64("input-freq", RTMRState, input_freq, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void rtmr_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(klass); + + dc->props =3D rtmr_properties; + dc->vmsd =3D &vmstate_rtmr; + dc->reset =3D rtmr_reset; +} + +static const TypeInfo rtmr_info =3D { + .name =3D TYPE_RENESAS_TMR, + .parent =3D TYPE_SYS_BUS_DEVICE, + .instance_size =3D sizeof(RTMRState), + .instance_init =3D rtmr_init, + .class_init =3D rtmr_class_init, +}; + +static void rtmr_register_types(void) +{ + type_register_static(&rtmr_info); +} + +type_init(rtmr_register_types) diff --git a/include/hw/timer/renesas_cmt.h b/include/hw/timer/renesas_cmt.h new file mode 100644 index 0000000000..764759d4ad --- /dev/null +++ b/include/hw/timer/renesas_cmt.h @@ -0,0 +1,33 @@ +/* + * Renesas Compare-match timer Object + * + * Copyright (c) 2018 Yoshinori Sato + * + * This code is licensed under the GPL version 2 or later. + * + */ + +#ifndef HW_RENESAS_CMT_H +#define HW_RENESAS_CMT_H + +#include "hw/sysbus.h" + +#define TYPE_RENESAS_CMT "renesas-cmt" +#define RCMT(obj) OBJECT_CHECK(RCMTState, (obj), TYPE_RENESAS_CMT) + +typedef struct RCMTState { + SysBusDevice parent_obj; + + uint64_t input_freq; + MemoryRegion memory; + + uint16_t cmstr; + uint16_t cmcr[2]; + uint16_t cmcnt[2]; + uint16_t cmcor[2]; + int64_t tick[2]; + qemu_irq cmi[2]; + QEMUTimer *timer[2]; +} RCMTState; + +#endif diff --git a/include/hw/timer/renesas_tmr.h b/include/hw/timer/renesas_tmr.h new file mode 100644 index 0000000000..09333c86fc --- /dev/null +++ b/include/hw/timer/renesas_tmr.h @@ -0,0 +1,42 @@ +/* + * Renesas 8bit timer Object + * + * Copyright (c) 2018 Yoshinori Sato + * + * This code is licensed under the GPL version 2 or later. + * + */ + +#ifndef HW_RENESAS_TMR_H +#define HW_RENESAS_TMR_H + +#include "hw/sysbus.h" + +#define TYPE_RENESAS_TMR "renesas-tmr" +#define RTMR(obj) OBJECT_CHECK(RTMRState, (obj), TYPE_RENESAS_TMR) + +enum timer_event {none, cmia, cmib, ovi}; + +typedef struct RTMRState { + SysBusDevice parent_obj; + + uint64_t input_freq; + MemoryRegion memory; + + uint16_t tcnt[2]; + uint8_t tcora[2]; + uint8_t tcorb[2]; + uint8_t tcr[2]; + uint8_t tccr[2]; + uint8_t tcor[2]; + uint8_t tcsr[2]; + int64_t tick; + int64_t div_round[2]; + enum timer_event next[2]; + qemu_irq cmia[2]; + qemu_irq cmib[2]; + qemu_irq ovi[2]; + QEMUTimer *timer[2]; +} RTMRState; + +#endif --=20 2.11.0