From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([209.51.188.92]:53403) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1hNJfK-0003Jk-Cw for qemu-devel@nongnu.org; Sun, 05 May 2019 12:07:04 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hNJfI-0006MG-Gq for qemu-devel@nongnu.org; Sun, 05 May 2019 12:07:02 -0400 Received: from mail02.asahi-net.or.jp ([202.224.55.14]:52082) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1hNJfI-0006LV-8c for qemu-devel@nongnu.org; Sun, 05 May 2019 12:07:00 -0400 Date: Mon, 06 May 2019 01:06:58 +0900 Message-ID: <87sgts51i5.wl-ysato@users.sourceforge.jp> From: Yoshinori Sato In-Reply-To: <87pnoz4l9s.fsf@zen.linaroharston> References: <20190502143409.59600-1-ysato@users.sourceforge.jp> <20190502143409.59600-8-ysato@users.sourceforge.jp> <87pnoz4l9s.fsf@zen.linaroharston> MIME-Version: 1.0 (generated by SEMI-EPG 1.14.7 - "Harue") Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable Subject: Re: [Qemu-devel] [PATCH RFC v8 07/12] hw/timer: RX62N internal timer modules List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Alex =?ISO-8859-1?Q?Benn=E9e?= Cc: qemu-devel@nongnu.org, peter.maydell@linaro.org, richard.henderson@linaro.org On Sat, 04 May 2019 00:20:47 +0900, Alex Benn=E9e wrote: >=20 >=20 > Yoshinori Sato writes: >=20 > > 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/r01uh00= 33ej0140_rx62n.pdf > > > > Signed-off-by: Yoshinori Sato > > --- > > include/hw/timer/renesas_cmt.h | 33 +++ > > include/hw/timer/renesas_tmr.h | 46 +++++ > > hw/timer/renesas_cmt.c | 277 +++++++++++++++++++++++++ > > hw/timer/renesas_tmr.c | 458 +++++++++++++++++++++++++++++++++= ++++++++ > > hw/timer/Kconfig | 6 + > > hw/timer/Makefile.objs | 3 + > > 6 files changed, 823 insertions(+) > > create mode 100644 include/hw/timer/renesas_cmt.h > > create mode 100644 include/hw/timer/renesas_tmr.h > > create mode 100644 hw/timer/renesas_cmt.c > > create mode 100644 hw/timer/renesas_tmr.c > > > > diff --git a/include/hw/timer/renesas_cmt.h b/include/hw/timer/renesas_= cmt.h > > new file mode 100644 > > index 0000000000..7e393d7ad3 > > --- /dev/null > > +++ b/include/hw/timer/renesas_cmt.h > > @@ -0,0 +1,33 @@ > > +/* > > + * Renesas Compare-match timer Object > > + * > > + * Copyright (c) 2019 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..718d9dc4ff > > --- /dev/null > > +++ b/include/hw/timer/renesas_tmr.h > > @@ -0,0 +1,46 @@ > > +/* > > + * 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 {cmia =3D 0, > > + cmib =3D 1, > > + ovi =3D 2, > > + none =3D 3, > > + TMR_NR_EVENTS =3D 4}; > > +enum {CH =3D 2}; > > +typedef struct RTMRState { > > + SysBusDevice parent_obj; > > + > > + uint64_t input_freq; > > + MemoryRegion memory; > > + > > + uint8_t tcnt[CH]; > > + uint8_t tcora[CH]; > > + uint8_t tcorb[CH]; > > + uint8_t tcr[CH]; > > + uint8_t tccr[CH]; > > + uint8_t tcor[CH]; > > + uint8_t tcsr[CH]; > > + int64_t tick; > > + int64_t div_round[CH]; > > + enum timer_event next[CH]; > > + qemu_irq cmia[CH]; > > + qemu_irq cmib[CH]; > > + qemu_irq ovi[CH]; > > + QEMUTimer *timer[CH]; > > +} RTMRState; > > + > > +#endif > > diff --git a/hw/timer/renesas_cmt.c b/hw/timer/renesas_cmt.c > > new file mode 100644 > > index 0000000000..b82250dbc2 > > --- /dev/null > > +++ b/hw/timer/renesas_cmt.c > > @@ -0,0 +1,277 @@ > > +/* > > + * Renesas 16bit Compare-match timer > > + * > > + * Datasheet: RX62N Group, RX621 Group User's Manual: Hardware > > + * (Rev.1.40 R01UH0033EJ0140) > > + * > > + * Copyright (c) 2019 Yoshinori Sato > > + * > > + * This program is free software; you can redistribute it and/or modif= y 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 WITH= OUT > > + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY = or > > + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public Licen= se for > > + * more details. > > + * > > + * You should have received a copy of the GNU General Public License a= long with > > + * this program. If not, see . > > + */ > > + > > +#include "qemu/osdep.h" > > +#include "qemu-common.h" > > +#include "qemu/log.h" > > +#include "qapi/error.h" > > +#include "qemu/timer.h" > > +#include "cpu.h" > > +#include "hw/hw.h" > > +#include "hw/sysbus.h" > > +#include "hw/registerfields.h" > > +#include "hw/timer/renesas_cmt.h" > > +#include "qemu/error-report.h" > > + > > +/* > > + * +0 CMSTR - common control > > + * +2 CMCR - ch0 > > + * +4 CMCNT - ch0 > > + * +6 CMCOR - ch0 > > + * +8 CMCR - ch1 > > + * +10 CMCNT - ch1 > > + * +12 CMCOR - ch1 > > + * If we think that the address of CH 0 has an offset of +2, > > + * we can treat it with the same address as CH 1, so define it like th= at. > > + */ > > +REG16(CMSTR, 0) > > + FIELD(CMSTR, STR0, 0, 1) > > + FIELD(CMSTR, STR1, 1, 1) > > + FIELD(CMSTR, STR, 0, 2) > > +/* This addeess is channel offset */ > > +REG16(CMCR, 0) > > + FIELD(CMCR, CKS, 0, 2) > > + FIELD(CMCR, CMIE, 6, 1) > > +REG16(CMCNT, 2) > > +REG16(CMCOR, 4) > > + > > +static void update_events(RCMTState *cmt, int ch) > > +{ > > + int64_t next_time; > > + > > + if ((cmt->cmstr & (1 << ch)) =3D=3D 0) { > > + /* count disable, so not happened next event. */ > > + return ; > > + } > > + next_time =3D cmt->cmcor[ch] - cmt->cmcnt[ch]; > > + next_time *=3D NANOSECONDS_PER_SECOND; > > + next_time /=3D cmt->input_freq; > > + /* > > + * CKS -> div rate > > + * 0 -> 8 (1 << 3) > > + * 1 -> 32 (1 << 5) > > + * 2 -> 128 (1 << 7) > > + * 3 -> 512 (1 << 9) > > + */ > > + next_time *=3D 1 << (3 + FIELD_EX16(cmt->cmcr[ch], CMCR, CKS) * 2); > > + next_time +=3D qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); > > + timer_mod(cmt->timer[ch], next_time); > > +} > > + > > +static int64_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]); > > + delta /=3D NANOSECONDS_PER_SECOND; > > + delta /=3D cmt->input_freq; > > + delta /=3D 1 << (3 + FIELD_EX16(cmt->cmcr[ch], CMCR, CKS) * 2); > > + cmt->tick[ch] =3D now; > > + 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; > > + uint64_t ret; > > + > > + if (offset =3D=3D A_CMSTR) { > > + ret =3D 0; > > + ret =3D FIELD_DP16(ret, CMSTR, STR, > > + FIELD_EX16(cmt->cmstr, CMSTR, STR)); > > + return ret; > > + } else { > > + offset &=3D 0x07; > > + if (ch =3D=3D 0) { > > + offset -=3D 0x02; > > + } > > + switch (offset) { > > + case A_CMCR: > > + ret =3D 0; > > + ret =3D FIELD_DP16(ret, CMCR, CKS, > > + FIELD_EX16(cmt->cmstr, CMCR, CKS)); > > + ret =3D FIELD_DP16(ret, CMCR, CMIE, > > + FIELD_EX16(cmt->cmstr, CMCR, CMIE)); > > + return ret; > > + case A_CMCNT: > > + return read_cmcnt(cmt, ch); > > + case A_CMCOR: > > + return cmt->cmcor[ch]; > > + } > > + } > > + qemu_log_mask(LOG_UNIMP, > > + "renesas_cmt: Register %08lx not implemented\n", > > + offset); > > + 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, unsigne= d size) > > +{ > > + hwaddr offset =3D addr & 0x0f; > > + RCMTState *cmt =3D opaque; > > + int ch =3D offset / 0x08; > > + > > + if (offset =3D=3D A_CMSTR) { > > + cmt->cmstr =3D FIELD_EX16(val, CMSTR, STR); > > + start_stop(cmt, 0, FIELD_EX16(cmt->cmstr, CMSTR, STR0)); > > + start_stop(cmt, 1, FIELD_EX16(cmt->cmstr, CMSTR, STR1)); > > + } else { > > + offset &=3D 0x07; > > + if (ch =3D=3D 0) { > > + offset -=3D 0x02; > > + } > > + switch (offset) { > > + case A_CMCR: > > + cmt->cmcr[ch] =3D FIELD_DP16(cmt->cmcr[ch], CMCR, CKS, > > + FIELD_EX16(val, CMCR, CKS)); > > + cmt->cmcr[ch] =3D FIELD_DP16(cmt->cmcr[ch], CMCR, CMIE, > > + FIELD_EX16(val, CMCR, CMIE)); > > + break; > > + case 2: > > + cmt->cmcnt[ch] =3D val; > > + break; > > + case 4: > > + cmt->cmcor[ch] =3D val; > > + break; > > + default: > > + qemu_log_mask(LOG_UNIMP, > > + "renesas_cmt: Register %08lx not implemented= \n", > > + offset); > > + return; > > + } > > + if (FIELD_EX16(cmt->cmstr, CMSTR, STR) & (1 << ch)) { > > + update_events(cmt, ch); > > + } > > + } > > +} > > + > > +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 (FIELD_EX16(cmt->cmcr[ch], CMCR, CMIE)) { > > + 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); > > +} >=20 > I guess there is enough shared state RCMTState that you couldn't have an > array of channel structures and just pass that when you setup the > timers: >=20 > > +static void rcmt_init(Object *obj) > > +{ > > > + cmt->timer[0] =3D timer_new_ns(QEMU_CLOCK_VIRTUAL, timer_event0, c= mt); > > + cmt->timer[1] =3D timer_new_ns(QEMU_CLOCK_VIRTUAL, timer_event1, > > cmt); >=20 > here? Yes. The shared part is only access from the CPU, so I don't think there will be a conflict in the timer's event. If problems occur, fix it to manage with one timer. > Anyway: >=20 > Reviewed-by: Alex Benn=E9e >=20 > -- > Alex Benn=E9e >=20 --=20 Yosinori Sato From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY,SPF_PASS,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4EEFCC004C9 for ; Sun, 5 May 2019 16:08:40 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 0BED42082F for ; Sun, 5 May 2019 16:08:39 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 0BED42082F Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=users.sourceforge.jp Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([127.0.0.1]:43224 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1hNJgs-00045Z-W8 for qemu-devel@archiver.kernel.org; Sun, 05 May 2019 12:08:39 -0400 Received: from eggs.gnu.org ([209.51.188.92]:53403) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1hNJfK-0003Jk-Cw for qemu-devel@nongnu.org; Sun, 05 May 2019 12:07:04 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hNJfI-0006MG-Gq for qemu-devel@nongnu.org; Sun, 05 May 2019 12:07:02 -0400 Received: from mail02.asahi-net.or.jp ([202.224.55.14]:52082) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1hNJfI-0006LV-8c for qemu-devel@nongnu.org; Sun, 05 May 2019 12:07:00 -0400 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 mail02.asahi-net.or.jp (Postfix) with ESMTPA id EB0C73B913; Mon, 6 May 2019 01:06:58 +0900 (JST) Received: from yo-satoh-debian.ysato.ml (ZM005235.ppp.dion.ne.jp [222.8.5.235]) by h61-195-96-97.vps.ablenet.jp (Postfix) with ESMTPSA id AA5A7240085; Mon, 6 May 2019 01:06:58 +0900 (JST) Date: Mon, 06 May 2019 01:06:58 +0900 Message-ID: <87sgts51i5.wl-ysato@users.sourceforge.jp> From: Yoshinori Sato To: Alex =?ISO-8859-1?Q?Benn=E9e?= In-Reply-To: <87pnoz4l9s.fsf@zen.linaroharston> References: <20190502143409.59600-1-ysato@users.sourceforge.jp> <20190502143409.59600-8-ysato@users.sourceforge.jp> <87pnoz4l9s.fsf@zen.linaroharston> User-Agent: Wanderlust/2.15.9 (Almost Unreal) SEMI-EPG/1.14.7 (Harue) FLIM/1.14.9 (=?ISO-8859-4?Q?Goj=F2?=) APEL/10.8 EasyPG/1.0.0 Emacs/25.1 (x86_64-pc-linux-gnu) MULE/6.0 (HANACHIRUSATO) MIME-Version: 1.0 (generated by SEMI-EPG 1.14.7 - "Harue") Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 202.224.55.14 Subject: Re: [Qemu-devel] [PATCH RFC v8 07/12] hw/timer: 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, qemu-devel@nongnu.org Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" Message-ID: <20190505160658.H4o6VpcP6mSrCKxSZ9TkIYbjsZvAWaOLvZiSH08qLn0@z> On Sat, 04 May 2019 00:20:47 +0900, Alex Benn=E9e wrote: >=20 >=20 > Yoshinori Sato writes: >=20 > > 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/r01uh00= 33ej0140_rx62n.pdf > > > > Signed-off-by: Yoshinori Sato > > --- > > include/hw/timer/renesas_cmt.h | 33 +++ > > include/hw/timer/renesas_tmr.h | 46 +++++ > > hw/timer/renesas_cmt.c | 277 +++++++++++++++++++++++++ > > hw/timer/renesas_tmr.c | 458 +++++++++++++++++++++++++++++++++= ++++++++ > > hw/timer/Kconfig | 6 + > > hw/timer/Makefile.objs | 3 + > > 6 files changed, 823 insertions(+) > > create mode 100644 include/hw/timer/renesas_cmt.h > > create mode 100644 include/hw/timer/renesas_tmr.h > > create mode 100644 hw/timer/renesas_cmt.c > > create mode 100644 hw/timer/renesas_tmr.c > > > > diff --git a/include/hw/timer/renesas_cmt.h b/include/hw/timer/renesas_= cmt.h > > new file mode 100644 > > index 0000000000..7e393d7ad3 > > --- /dev/null > > +++ b/include/hw/timer/renesas_cmt.h > > @@ -0,0 +1,33 @@ > > +/* > > + * Renesas Compare-match timer Object > > + * > > + * Copyright (c) 2019 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..718d9dc4ff > > --- /dev/null > > +++ b/include/hw/timer/renesas_tmr.h > > @@ -0,0 +1,46 @@ > > +/* > > + * 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 {cmia =3D 0, > > + cmib =3D 1, > > + ovi =3D 2, > > + none =3D 3, > > + TMR_NR_EVENTS =3D 4}; > > +enum {CH =3D 2}; > > +typedef struct RTMRState { > > + SysBusDevice parent_obj; > > + > > + uint64_t input_freq; > > + MemoryRegion memory; > > + > > + uint8_t tcnt[CH]; > > + uint8_t tcora[CH]; > > + uint8_t tcorb[CH]; > > + uint8_t tcr[CH]; > > + uint8_t tccr[CH]; > > + uint8_t tcor[CH]; > > + uint8_t tcsr[CH]; > > + int64_t tick; > > + int64_t div_round[CH]; > > + enum timer_event next[CH]; > > + qemu_irq cmia[CH]; > > + qemu_irq cmib[CH]; > > + qemu_irq ovi[CH]; > > + QEMUTimer *timer[CH]; > > +} RTMRState; > > + > > +#endif > > diff --git a/hw/timer/renesas_cmt.c b/hw/timer/renesas_cmt.c > > new file mode 100644 > > index 0000000000..b82250dbc2 > > --- /dev/null > > +++ b/hw/timer/renesas_cmt.c > > @@ -0,0 +1,277 @@ > > +/* > > + * Renesas 16bit Compare-match timer > > + * > > + * Datasheet: RX62N Group, RX621 Group User's Manual: Hardware > > + * (Rev.1.40 R01UH0033EJ0140) > > + * > > + * Copyright (c) 2019 Yoshinori Sato > > + * > > + * This program is free software; you can redistribute it and/or modif= y 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 WITH= OUT > > + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY = or > > + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public Licen= se for > > + * more details. > > + * > > + * You should have received a copy of the GNU General Public License a= long with > > + * this program. If not, see . > > + */ > > + > > +#include "qemu/osdep.h" > > +#include "qemu-common.h" > > +#include "qemu/log.h" > > +#include "qapi/error.h" > > +#include "qemu/timer.h" > > +#include "cpu.h" > > +#include "hw/hw.h" > > +#include "hw/sysbus.h" > > +#include "hw/registerfields.h" > > +#include "hw/timer/renesas_cmt.h" > > +#include "qemu/error-report.h" > > + > > +/* > > + * +0 CMSTR - common control > > + * +2 CMCR - ch0 > > + * +4 CMCNT - ch0 > > + * +6 CMCOR - ch0 > > + * +8 CMCR - ch1 > > + * +10 CMCNT - ch1 > > + * +12 CMCOR - ch1 > > + * If we think that the address of CH 0 has an offset of +2, > > + * we can treat it with the same address as CH 1, so define it like th= at. > > + */ > > +REG16(CMSTR, 0) > > + FIELD(CMSTR, STR0, 0, 1) > > + FIELD(CMSTR, STR1, 1, 1) > > + FIELD(CMSTR, STR, 0, 2) > > +/* This addeess is channel offset */ > > +REG16(CMCR, 0) > > + FIELD(CMCR, CKS, 0, 2) > > + FIELD(CMCR, CMIE, 6, 1) > > +REG16(CMCNT, 2) > > +REG16(CMCOR, 4) > > + > > +static void update_events(RCMTState *cmt, int ch) > > +{ > > + int64_t next_time; > > + > > + if ((cmt->cmstr & (1 << ch)) =3D=3D 0) { > > + /* count disable, so not happened next event. */ > > + return ; > > + } > > + next_time =3D cmt->cmcor[ch] - cmt->cmcnt[ch]; > > + next_time *=3D NANOSECONDS_PER_SECOND; > > + next_time /=3D cmt->input_freq; > > + /* > > + * CKS -> div rate > > + * 0 -> 8 (1 << 3) > > + * 1 -> 32 (1 << 5) > > + * 2 -> 128 (1 << 7) > > + * 3 -> 512 (1 << 9) > > + */ > > + next_time *=3D 1 << (3 + FIELD_EX16(cmt->cmcr[ch], CMCR, CKS) * 2); > > + next_time +=3D qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); > > + timer_mod(cmt->timer[ch], next_time); > > +} > > + > > +static int64_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]); > > + delta /=3D NANOSECONDS_PER_SECOND; > > + delta /=3D cmt->input_freq; > > + delta /=3D 1 << (3 + FIELD_EX16(cmt->cmcr[ch], CMCR, CKS) * 2); > > + cmt->tick[ch] =3D now; > > + 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; > > + uint64_t ret; > > + > > + if (offset =3D=3D A_CMSTR) { > > + ret =3D 0; > > + ret =3D FIELD_DP16(ret, CMSTR, STR, > > + FIELD_EX16(cmt->cmstr, CMSTR, STR)); > > + return ret; > > + } else { > > + offset &=3D 0x07; > > + if (ch =3D=3D 0) { > > + offset -=3D 0x02; > > + } > > + switch (offset) { > > + case A_CMCR: > > + ret =3D 0; > > + ret =3D FIELD_DP16(ret, CMCR, CKS, > > + FIELD_EX16(cmt->cmstr, CMCR, CKS)); > > + ret =3D FIELD_DP16(ret, CMCR, CMIE, > > + FIELD_EX16(cmt->cmstr, CMCR, CMIE)); > > + return ret; > > + case A_CMCNT: > > + return read_cmcnt(cmt, ch); > > + case A_CMCOR: > > + return cmt->cmcor[ch]; > > + } > > + } > > + qemu_log_mask(LOG_UNIMP, > > + "renesas_cmt: Register %08lx not implemented\n", > > + offset); > > + 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, unsigne= d size) > > +{ > > + hwaddr offset =3D addr & 0x0f; > > + RCMTState *cmt =3D opaque; > > + int ch =3D offset / 0x08; > > + > > + if (offset =3D=3D A_CMSTR) { > > + cmt->cmstr =3D FIELD_EX16(val, CMSTR, STR); > > + start_stop(cmt, 0, FIELD_EX16(cmt->cmstr, CMSTR, STR0)); > > + start_stop(cmt, 1, FIELD_EX16(cmt->cmstr, CMSTR, STR1)); > > + } else { > > + offset &=3D 0x07; > > + if (ch =3D=3D 0) { > > + offset -=3D 0x02; > > + } > > + switch (offset) { > > + case A_CMCR: > > + cmt->cmcr[ch] =3D FIELD_DP16(cmt->cmcr[ch], CMCR, CKS, > > + FIELD_EX16(val, CMCR, CKS)); > > + cmt->cmcr[ch] =3D FIELD_DP16(cmt->cmcr[ch], CMCR, CMIE, > > + FIELD_EX16(val, CMCR, CMIE)); > > + break; > > + case 2: > > + cmt->cmcnt[ch] =3D val; > > + break; > > + case 4: > > + cmt->cmcor[ch] =3D val; > > + break; > > + default: > > + qemu_log_mask(LOG_UNIMP, > > + "renesas_cmt: Register %08lx not implemented= \n", > > + offset); > > + return; > > + } > > + if (FIELD_EX16(cmt->cmstr, CMSTR, STR) & (1 << ch)) { > > + update_events(cmt, ch); > > + } > > + } > > +} > > + > > +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 (FIELD_EX16(cmt->cmcr[ch], CMCR, CMIE)) { > > + 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); > > +} >=20 > I guess there is enough shared state RCMTState that you couldn't have an > array of channel structures and just pass that when you setup the > timers: >=20 > > +static void rcmt_init(Object *obj) > > +{ > > > + cmt->timer[0] =3D timer_new_ns(QEMU_CLOCK_VIRTUAL, timer_event0, c= mt); > > + cmt->timer[1] =3D timer_new_ns(QEMU_CLOCK_VIRTUAL, timer_event1, > > cmt); >=20 > here? Yes. The shared part is only access from the CPU, so I don't think there will be a conflict in the timer's event. If problems occur, fix it to manage with one timer. > Anyway: >=20 > Reviewed-by: Alex Benn=E9e >=20 > -- > Alex Benn=E9e >=20 --=20 Yosinori Sato