From nobody Sun May 5 10:23:05 2024 Delivered-To: importer2@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer2=patchew.org@nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1622093374; cv=none; d=zohomail.com; s=zohoarc; b=PGu14CUIX2x2s7KcX5XL/Rn9vEHAjZjCAoHG36ITRUenb27rX5/ywFKRC8fNY7ITakPy+1bzVxzhz5/QK+hGXto/hMCzVz8Qu7Ze/xTiUrCNI0w2V2kwFT1PkTEC3xnuK2wVi7jhVvLZE43eCVWZK1hrqhiSmcCI0+S29p+plIQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1622093374; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=PMWHXfLyO6+ZNjQnemXy41jmoTuBU5rUSHwaYOSUkYo=; b=E/H6MpVtbiH7bwM2bN6Gd6+Qtg3Rzr+zqmoZlaH6gaPz1tc57X7D4wTmZiydlTLI0515FDOJwtaVd7BU2dpq4zhtT/PWPK5/2i9vPnhZO0OxA0f8GMSlQy1/pjNZkQQYL35AKFshUGOTPyodNKOP5tW+8+inU/n3k6nLAcMEpAA= ARC-Authentication-Results: i=1; mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer2=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 1622093374571640.880689576215; Wed, 26 May 2021 22:29:34 -0700 (PDT) Received: from localhost ([::1]:55978 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lm8aL-0005bc-CC for importer2@patchew.org; Thu, 27 May 2021 01:29:33 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:56946) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lm8Sl-00008P-7z for qemu-devel@nongnu.org; Thu, 27 May 2021 01:21:44 -0400 Received: from mail01.asahi-net.or.jp ([202.224.55.13]:58615) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lm8Sc-00063x-2a for qemu-devel@nongnu.org; Thu, 27 May 2021 01:21:43 -0400 Received: from sakura.ysato.name (ik1-413-38519.vs.sakura.ne.jp [153.127.30.23]) (Authenticated sender: PQ4Y-STU) by mail01.asahi-net.or.jp (Postfix) with ESMTPA id E216811D38F; Thu, 27 May 2021 14:21:29 +0900 (JST) Received: from yo-satoh-debian.localdomain (y245018.dynamic.ppp.asahi-net.or.jp [118.243.245.18]) by sakura.ysato.name (Postfix) with ESMTPSA id 12EBF1C060B; Thu, 27 May 2021 14:21:28 +0900 (JST) From: Yoshinori Sato To: qemu-devel@nongnu.org Subject: [PATCH 01/11] hw/char: Renesas SCI module. Date: Thu, 27 May 2021 14:21:12 +0900 Message-Id: <20210527052122.97103-2-ysato@users.sourceforge.jp> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20210527052122.97103-1-ysato@users.sourceforge.jp> References: <20210527052122.97103-1-ysato@users.sourceforge.jp> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer2=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: softfail client-ip=202.224.55.13; envelope-from=ysato@users.sourceforge.jp; helo=mail01.asahi-net.or.jp X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_DNSWL_LOW=-0.7, SPF_HELO_NONE=0.001, SPF_SOFTFAIL=0.665 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Yoshinori Sato Errors-To: qemu-devel-bounces+importer2=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" This module supported SCI / SCIa / SCIF. Hardware manual. SCI / SCIF https://www.renesas.com/us/en/doc/products/mpumcu/001/r01uh0457ej0401_sh775= 1.pdf SCIa https://www.renesas.com/us/en/doc/products/mpumcu/doc/rx_family/r01uh0033ej= 0140_rx62n.pdf Signed-off-by: Yoshinori Sato --- include/hw/char/renesas_sci.h | 129 +++- hw/char/renesas_sci.c | 1039 +++++++++++++++++++++++++++------ 2 files changed, 966 insertions(+), 202 deletions(-) diff --git a/include/hw/char/renesas_sci.h b/include/hw/char/renesas_sci.h index a4764e3eee..ae9554db60 100644 --- a/include/hw/char/renesas_sci.h +++ b/include/hw/char/renesas_sci.h @@ -1,54 +1,137 @@ /* * Renesas Serial Communication Interface * - * Copyright (c) 2018 Yoshinori Sato + * Copyright (c) 2020 Yoshinori Sato + * + * This code is licensed under the GPL version 2 or later. * - * SPDX-License-Identifier: GPL-2.0-or-later */ =20 -#ifndef HW_CHAR_RENESAS_SCI_H -#define HW_CHAR_RENESAS_SCI_H - #include "chardev/char-fe.h" +#include "qemu/timer.h" +#include "qemu/fifo8.h" #include "hw/sysbus.h" #include "qom/object.h" =20 +#define TYPE_RENESAS_SCI_BASE "renesas-sci-base" +OBJECT_DECLARE_TYPE(RenesasSCIBaseState, RenesasSCIBaseClass, + RENESAS_SCI_BASE) #define TYPE_RENESAS_SCI "renesas-sci" -typedef struct RSCIState RSCIState; -DECLARE_INSTANCE_CHECKER(RSCIState, RSCI, - TYPE_RENESAS_SCI) +OBJECT_DECLARE_TYPE(RenesasSCIState, RenesasSCIClass, + RENESAS_SCI) +#define TYPE_RENESAS_SCIA "renesas-scia" +OBJECT_DECLARE_TYPE(RenesasSCIAState, RenesasSCIAClass, + RENESAS_SCIA) +#define TYPE_RENESAS_SCIF "renesas-scif" +OBJECT_DECLARE_TYPE(RenesasSCIFState, RenesasSCIFClass, + RENESAS_SCIF) =20 enum { ERI =3D 0, RXI =3D 1, TXI =3D 2, - TEI =3D 3, - SCI_NR_IRQ =3D 4 + BRI_TEI =3D 3, + SCI_NR_IRQ =3D 4, +}; + +enum { + RXTOUT, + RXNEXT, + TXEMPTY, + TXEND, + NR_SCI_EVENT, }; =20 -struct RSCIState { +enum { + SCI_REGSIZE_8 =3D 0, + SCI_REGSIZE_16 =3D 1, + SCI_REGSIZE_32 =3D 2, +}; + +typedef struct RenesasSCIBaseState { /*< private >*/ SysBusDevice parent_obj; - /*< public >*/ - MemoryRegion memory; - QEMUTimer timer; - CharBackend chr; - qemu_irq irq[SCI_NR_IRQ]; + MemoryRegion memory_p4; + MemoryRegion memory_a7; =20 + /* SCI register */ uint8_t smr; uint8_t brr; uint8_t scr; uint8_t tdr; - uint8_t ssr; - uint8_t rdr; - uint8_t scmr; - uint8_t semr; + uint16_t Xsr; =20 - uint8_t read_ssr; + /* internal use */ + uint16_t read_Xsr; + int64_t etu; int64_t trtime; - int64_t rx_next; + int64_t tx_start_time; + struct { + int64_t time; + int64_t (*handler)(struct RenesasSCIBaseState *sci); + } event[NR_SCI_EVENT]; + QEMUTimer *event_timer; + CharBackend chr; uint64_t input_freq; + qemu_irq irq[SCI_NR_IRQ]; + Fifo8 rxfifo; + int regshift; + uint32_t unit; + Clock *pck; +} RenesasSCIBaseState; + +struct RenesasSCIState { + RenesasSCIBaseState parent_obj; + + /* SCI specific register */ + uint8_t sptr; }; =20 -#endif +struct RenesasSCIAState { + RenesasSCIBaseState parent_obj; + + /* SCIa specific register */ + uint8_t scmr; + uint8_t semr; +}; + +struct RenesasSCIFState { + RenesasSCIBaseState parent_obj; + + /* SCIF specific register */ + uint16_t fcr; + uint16_t sptr; + uint16_t lsr; + + /* private */ + uint16_t read_lsr; + int tdcnt; +}; + +typedef struct RenesasSCIBaseClass { + SysBusDeviceClass parent; + + const struct MemoryRegionOps *ops; + void (*irq_fn)(struct RenesasSCIBaseState *sci, int request); + int (*divrate)(struct RenesasSCIBaseState *sci); +} RenesasSCIBaseClass; + +typedef struct RenesasSCIClass { + RenesasSCIBaseClass parent; + + void (*p_irq_fn)(struct RenesasSCIBaseState *sci, int request); +} RenesasSCIClass; + +typedef struct RenesasSCIAClass { + RenesasSCIBaseClass parent; + + void (*p_irq_fn)(struct RenesasSCIBaseState *sci, int request); + int (*p_divrate)(struct RenesasSCIBaseState *sci); +} RenesasSCIAClass; + +typedef struct RenesasSCIFClass { + RenesasSCIBaseClass parent; + + void (*p_irq_fn)(struct RenesasSCIBaseState *sci, int request); +} RenesasSCIFClass; diff --git a/hw/char/renesas_sci.c b/hw/char/renesas_sci.c index 1c63467290..f8ab00362a 100644 --- a/hw/char/renesas_sci.c +++ b/hw/char/renesas_sci.c @@ -1,10 +1,12 @@ /* - * Renesas Serial Communication Interface + * Renesas Serial Communication Interface (SCI / SCIa / SCIF) * * Datasheet: RX62N Group, RX621 Group User's Manual: Hardware * (Rev.1.40 R01UH0033EJ0140) + * And SH7751 Group, SH7751R Group User's Manual: Hardware + * (Rev.4.01 R01UH0457EJ0401) * - * Copyright (c) 2019 Yoshinori Sato + * Copyright (c) 2020 Yoshinori Sato * * SPDX-License-Identifier: GPL-2.0-or-later * @@ -23,15 +25,25 @@ =20 #include "qemu/osdep.h" #include "qemu/log.h" +#include "qapi/error.h" +#include "qemu-common.h" +#include "hw/hw.h" #include "hw/irq.h" +#include "hw/sysbus.h" #include "hw/registerfields.h" -#include "hw/qdev-properties.h" #include "hw/qdev-properties-system.h" +#include "hw/qdev-clock.h" #include "hw/char/renesas_sci.h" #include "migration/vmstate.h" +#include "qemu/error-report.h" =20 -/* SCI register map */ -REG8(SMR, 0) +/* + * SCI register map + * SCI(a) register size all 8bit. + * SCIF regsister size 8bit and 16bit. + * Allocate 16bit to match the larger one. + */ +REG32(SMR, 0) /* 8bit */ FIELD(SMR, CKS, 0, 2) FIELD(SMR, MP, 2, 1) FIELD(SMR, STOP, 3, 1) @@ -39,263 +51,840 @@ REG8(SMR, 0) FIELD(SMR, PE, 5, 1) FIELD(SMR, CHR, 6, 1) FIELD(SMR, CM, 7, 1) -REG8(BRR, 1) -REG8(SCR, 2) - FIELD(SCR, CKE, 0, 2) +REG32(BRR, 4) /* 8bit */ +REG32(SCR, 8) + FIELD(SCR, CKE, 0, 2) FIELD(SCR, TEIE, 2, 1) FIELD(SCR, MPIE, 3, 1) + FIELD(SCR, REIE, 3, 1) FIELD(SCR, RE, 4, 1) FIELD(SCR, TE, 5, 1) FIELD(SCR, RIE, 6, 1) FIELD(SCR, TIE, 7, 1) -REG8(TDR, 3) -REG8(SSR, 4) +REG32(TDR, 12) /* 8bit */ +REG32(SSR, 16) /* 8bit */ FIELD(SSR, MPBT, 0, 1) FIELD(SSR, MPB, 1, 1) FIELD(SSR, TEND, 2, 1) - FIELD(SSR, ERR, 3, 3) + FIELD(SSR, ERR, 3, 3) FIELD(SSR, PER, 3, 1) FIELD(SSR, FER, 4, 1) FIELD(SSR, ORER, 5, 1) FIELD(SSR, RDRF, 6, 1) FIELD(SSR, TDRE, 7, 1) -REG8(RDR, 5) -REG8(SCMR, 6) +REG32(FSR, 16) + FIELD(FSR, DR, 0, 1) + FIELD(FSR, RDF, 1, 1) + FIELD(FSR, RDF_DR, 0, 2) + FIELD(FSR, PER, 2, 1) + FIELD(FSR, FER, 3, 1) + FIELD(FSR, BRK, 4, 1) + FIELD(FSR, TDFE, 5, 1) + FIELD(FSR, TEND, 6, 1) + FIELD(FSR, ER, 7, 1) + FIELD(FSR, FERn, 8, 4) + FIELD(FSR, PERn, 12, 4) +REG32(RDR, 20) /* 8bit */ +REG32(SCMR, 24) /* 8bit */ FIELD(SCMR, SMIF, 0, 1) FIELD(SCMR, SINV, 2, 1) FIELD(SCMR, SDIR, 3, 1) FIELD(SCMR, BCP2, 7, 1) -REG8(SEMR, 7) +REG32(FCR, 24) + FIELD(FCR, LOOP, 0, 1) + FIELD(FCR, RFRST, 1, 1) + FIELD(FCR, TFRST, 2, 1) + FIELD(FCR, MCE, 3, 1) + FIELD(FCR, TTRG, 4, 2) + FIELD(FCR, RTRG, 6, 2) + FIELD(FCR, RSTRG, 8, 3) +REG32(SEMR, 28) /* 8bit */ FIELD(SEMR, ACS0, 0, 1) FIELD(SEMR, ABCS, 4, 1) +REG32(FDR, 28) + FIELD(FDR, Rn, 0, 4) + FIELD(FDR, Tn, 8, 4) +REG32(SPTR, 32) + FIELD(SPTR, SPB2DT, 0, 1) + FIELD(SPTR, SPB2IO, 1, 1) + FIELD(SPTR, SCKDT, 2, 1) + FIELD(SPTR, SCKIO, 3, 1) + FIELD(SPTR, CTSDT, 4, 1) + FIELD(SPTR, CTSIO, 5, 1) + FIELD(SPTR, RTSDT, 6, 1) + FIELD(SPTR, RTSIO, 7, 1) + FIELD(SPTR, EIO, 7, 1) +REG32(LSR, 36) + FIELD(LSR, ORER, 0, 1) + +#define SCIF_FIFO_DEPTH 16 =20 -static int can_receive(void *opaque) +static const int sci_rtrg[] =3D {1, 4, 8, 14}; + +static void update_event_time(RenesasSCIBaseState *sci, int evt, int64_t t) { - RSCIState *sci =3D RSCI(opaque); - if (sci->rx_next > qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)) { - return 0; + if (t > 0) { + t +=3D qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + sci->event[evt].time =3D t; + if (timer_expire_time_ns(sci->event_timer) > t) { + timer_mod(sci->event_timer, t); + } } else { - return FIELD_EX8(sci->scr, SCR, RE); + sci->event[evt].time =3D 0; + } +} + +static void sci_irq(RenesasSCIBaseState *sci_common, int req) +{ + int irq =3D 0; + int rie; + int tie; + RenesasSCIState *sci =3D RENESAS_SCI(sci_common); + + rie =3D FIELD_EX16(sci_common->scr, SCR, RIE); + tie =3D FIELD_EX16(sci_common->scr, SCR, TIE); + switch (req) { + case ERI: + irq =3D rie && (FIELD_EX16(sci_common->Xsr, SSR, ERR) !=3D 0); + break; + case RXI: + irq =3D FIELD_EX16(sci_common->Xsr, SSR, RDRF) && rie && + !FIELD_EX16(sci->sptr, SPTR, EIO); + break; + case TXI: + irq =3D FIELD_EX16(sci_common->Xsr, SSR, TDRE) && tie; + break; + case BRI_TEI: + irq =3D FIELD_EX16(sci_common->Xsr, SSR, TEND) && + FIELD_EX16(sci_common->scr, SCR, TEIE); + break; } + qemu_set_irq(sci_common->irq[req], irq); } =20 -static void receive(void *opaque, const uint8_t *buf, int size) +static void scia_irq(RenesasSCIBaseState *sci, int req) { - RSCIState *sci =3D RSCI(opaque); - sci->rx_next =3D qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + sci->trtime; - if (FIELD_EX8(sci->ssr, SSR, RDRF) || size > 1) { - sci->ssr =3D FIELD_DP8(sci->ssr, SSR, ORER, 1); - if (FIELD_EX8(sci->scr, SCR, RIE)) { - qemu_set_irq(sci->irq[ERI], 1); + int irq =3D 0; + int rie; + int tie; + + rie =3D FIELD_EX16(sci->scr, SCR, RIE); + tie =3D FIELD_EX16(sci->scr, SCR, TIE); + switch (req) { + case ERI: + irq =3D (FIELD_EX16(sci->Xsr, SSR, ERR) !=3D 0) && rie; + qemu_set_irq(sci->irq[req], irq); + break; + case RXI: + if (FIELD_EX16(sci->Xsr, SSR, RDRF) && rie) { + qemu_irq_pulse(sci->irq[req]); } - } else { - sci->rdr =3D buf[0]; - sci->ssr =3D FIELD_DP8(sci->ssr, SSR, RDRF, 1); - if (FIELD_EX8(sci->scr, SCR, RIE)) { - qemu_irq_pulse(sci->irq[RXI]); + break; + case TXI: + if (FIELD_EX16(sci->Xsr, SSR, TDRE) && tie) { + qemu_irq_pulse(sci->irq[req]); + } + break; + case BRI_TEI: + irq =3D FIELD_EX16(sci->Xsr, SSR, TEND) && + FIELD_EX16(sci->scr, SCR, TEIE); + qemu_set_irq(sci->irq[req], irq); + break; + } +} + +static void scif_irq(RenesasSCIBaseState *sci, int req) +{ + int irq =3D 0; + int rie; + int reie; + int tie; + + rie =3D FIELD_EX16(sci->scr, SCR, RIE); + reie =3D FIELD_EX16(sci->scr, SCR, REIE); + tie =3D FIELD_EX16(sci->scr, SCR, TIE); + switch (req) { + case ERI: + irq =3D (rie || reie) && FIELD_EX16(sci->Xsr, FSR, ER); + break; + case RXI: + irq =3D (FIELD_EX16(sci->Xsr, FSR, RDF_DR) !=3D 0) && rie; + break; + case TXI: + irq =3D FIELD_EX16(sci->Xsr, FSR, TDFE) & tie; + break; + case BRI_TEI: + irq =3D (rie || reie) && FIELD_EX16(sci->Xsr, FSR, BRK); + break; + } + qemu_set_irq(sci->irq[req], irq); +} + +static int sci_can_receive(void *opaque) +{ + RenesasSCIBaseState *sci =3D RENESAS_SCI_BASE(opaque); + int fifo_free =3D 0; + if (clock_is_enabled(sci->pck) && FIELD_EX16(sci->scr, SCR, RE)) { + /* Receiver enabled */ + fifo_free =3D fifo8_num_free(&sci->rxfifo); + } + return fifo_free; +} + +static void sci_receive(void *opaque, const uint8_t *buf, int size) +{ + RenesasSCIBaseState *sci =3D RENESAS_SCI_BASE(opaque); + RenesasSCIBaseClass *rc =3D RENESAS_SCI_BASE_GET_CLASS(sci); + fifo8_push_all(&sci->rxfifo, buf, size); + if (sci->event[RXNEXT].time =3D=3D 0) { + sci->Xsr =3D FIELD_DP16(sci->Xsr, SSR, RDRF, 1); + update_event_time(sci, RXNEXT, sci->trtime); + rc->irq_fn(sci, RXI); + } +} + +static int scif_can_receive(void *opaque) +{ + RenesasSCIFState *scif =3D RENESAS_SCIF(opaque); + RenesasSCIBaseState *sci =3D RENESAS_SCI_BASE(opaque); + int fifo_free =3D 0; + if (clock_is_enabled(sci->pck) && FIELD_EX16(sci->scr, SCR, RE)) { + /* Receiver enabled */ + fifo_free =3D fifo8_num_free(&sci->rxfifo); + if (fifo_free =3D=3D 0) { + /* FIFO overrun */ + scif->lsr =3D FIELD_DP16(scif->lsr, LSR, ORER, 1); + scif_irq(sci, ERI); + } + } + return fifo_free; +} + +static void scif_receive(void *opaque, const uint8_t *buf, int size) +{ + RenesasSCIFState *scif =3D RENESAS_SCIF(opaque); + RenesasSCIBaseState *sci =3D RENESAS_SCI_BASE(opaque); + int rtrg; + + fifo8_push_all(&sci->rxfifo, buf, size); + if (sci->event[RXNEXT].time =3D=3D 0) { + rtrg =3D sci_rtrg[FIELD_EX16(scif->fcr, FCR, RTRG)]; + if (fifo8_num_used(&sci->rxfifo) >=3D rtrg) { + sci->Xsr =3D FIELD_DP16(sci->Xsr, FSR, RDF, 1); + } else { + update_event_time(sci, RXTOUT, 15 * sci->etu); } + scif_irq(sci, RXI); } } =20 -static void send_byte(RSCIState *sci) +static void sci_send_byte(RenesasSCIBaseState *sci) { if (qemu_chr_fe_backend_connected(&sci->chr)) { qemu_chr_fe_write_all(&sci->chr, &sci->tdr, 1); } - timer_mod(&sci->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + sci->tr= time); - sci->ssr =3D FIELD_DP8(sci->ssr, SSR, TEND, 0); - sci->ssr =3D FIELD_DP8(sci->ssr, SSR, TDRE, 1); - qemu_set_irq(sci->irq[TEI], 0); - if (FIELD_EX8(sci->scr, SCR, TIE)) { - qemu_irq_pulse(sci->irq[TXI]); + sci->Xsr =3D FIELD_DP16(sci->Xsr, SSR, TEND, 0); + sci->Xsr =3D FIELD_DP16(sci->Xsr, SSR, TDRE, 1); +} + +static int transmit_byte(RenesasSCIFState *scif) +{ + RenesasSCIBaseState *sci =3D RENESAS_SCI_BASE(scif); + int64_t elapsed; + int byte =3D 0; + if (sci->tx_start_time > 0) { + elapsed =3D qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - sci->tx_start_= time; + byte =3D elapsed / sci->trtime; + if (byte > scif->tdcnt) { + byte =3D scif->tdcnt; + } } + return byte; } =20 -static void txend(void *opaque) +static int64_t scif_rx_timeout(RenesasSCIBaseState *sci) { - RSCIState *sci =3D RSCI(opaque); - if (!FIELD_EX8(sci->ssr, SSR, TDRE)) { - send_byte(sci); + sci->Xsr =3D FIELD_DP16(sci->Xsr, FSR, DR, 1); + scif_irq(sci, RXI); + return 0; +} + +static int64_t sci_rx_next(RenesasSCIBaseState *sci) +{ + int64_t next_event =3D 0; + RenesasSCIBaseClass *rc =3D RENESAS_SCI_BASE_GET_CLASS(sci); + if (FIELD_EX16(sci->Xsr, SSR, RDRF)) { + /* Receiver overrun */ + sci->Xsr =3D FIELD_DP16(sci->Xsr, SSR, ORER, 1); + rc->irq_fn(sci, ERI); } else { - sci->ssr =3D FIELD_DP8(sci->ssr, SSR, TEND, 1); - if (FIELD_EX8(sci->scr, SCR, TEIE)) { - qemu_set_irq(sci->irq[TEI], 1); + if (!fifo8_is_empty(&sci->rxfifo)) { + /* set next event */ + sci->Xsr =3D FIELD_DP16(sci->Xsr, SSR, RDRF, 1); + rc->irq_fn(sci, RXI); + next_event =3D sci->trtime; } } + return next_event; } =20 -static void update_trtime(RSCIState *sci) +static int64_t sci_tx_empty(RenesasSCIBaseState *sci) { - /* char per bits */ - sci->trtime =3D 8 - FIELD_EX8(sci->smr, SMR, CHR); - sci->trtime +=3D FIELD_EX8(sci->smr, SMR, PE); - sci->trtime +=3D FIELD_EX8(sci->smr, SMR, STOP) + 1; - /* x bit transmit time (32 * divrate * brr) / base freq */ - sci->trtime *=3D 32 * sci->brr; - sci->trtime *=3D 1 << (2 * FIELD_EX8(sci->smr, SMR, CKS)); - sci->trtime *=3D NANOSECONDS_PER_SECOND; - sci->trtime /=3D sci->input_freq; + int64_t ret =3D 0; + RenesasSCIBaseClass *rc =3D RENESAS_SCI_BASE_GET_CLASS(sci); + if (!FIELD_EX16(sci->Xsr, SSR, TDRE)) { + sci_send_byte(sci); + ret =3D sci->trtime; + rc->irq_fn(sci, TXI); + } else { + sci->Xsr =3D FIELD_DP16(sci->Xsr, SSR, TEND, 1); + rc->irq_fn(sci, BRI_TEI); + } + return ret; } =20 -static bool sci_is_tr_enabled(RSCIState *sci) +static int64_t scif_tx_empty(RenesasSCIBaseState *sci) { - return FIELD_EX8(sci->scr, SCR, TE) || FIELD_EX8(sci->scr, SCR, RE); + RenesasSCIFState *scif =3D RENESAS_SCIF(sci); + scif->tdcnt -=3D transmit_byte(scif); + sci->Xsr =3D FIELD_DP16(sci->Xsr, FSR, TDFE, 1); + scif_irq(sci, TXI); + return 0; } =20 -static void sci_write(void *opaque, hwaddr offset, uint64_t val, unsigned = size) +static int64_t scif_tx_end(RenesasSCIBaseState *sci) { - RSCIState *sci =3D RSCI(opaque); + RenesasSCIFState *scif =3D RENESAS_SCIF(sci); + scif->tdcnt =3D 0; + sci->Xsr =3D FIELD_DP16(sci->Xsr, FSR, TEND, 1); + return 0; +} =20 - switch (offset) { - case A_SMR: - if (!sci_is_tr_enabled(sci)) { - sci->smr =3D val; - update_trtime(sci); +static void sci_timer_event(void *opaque) +{ + RenesasSCIBaseState *sci =3D RENESAS_SCI_BASE(opaque); + int64_t now, next, t; + int i; + + now =3D qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + next =3D INT64_MAX; + for (i =3D 0; i < NR_SCI_EVENT; i++) { + if (sci->event[i].time > 0 && sci->event[i].time <=3D now) { + t =3D sci->event[i].handler(sci); + sci->event[i].time =3D (t > 0) ? now + t : 0; } - break; - case A_BRR: - if (!sci_is_tr_enabled(sci)) { - sci->brr =3D val; - update_trtime(sci); + if (sci->event[i].time > 0) { + next =3D MIN(next, sci->event[i].time); } - break; + } + if (next < INT64_MAX) { + timer_mod(sci->event_timer, next); + } else { + timer_del(sci->event_timer); + } +} + +static int static_divrate(RenesasSCIBaseState *sci) +{ + /* SCI / SCIF have static divide rate */ + return 32; +} + +static int scia_divrate(RenesasSCIBaseState *sci) +{ + /* + * SEMR.ABCS =3D 0 -> 32 + * SEMR.ABCS =3D 1 -> 16 + */ + RenesasSCIAState *scia =3D RENESAS_SCIA(sci); + return 16 * (2 - FIELD_EX8(scia->semr, SEMR, ABCS)); +} + +static void update_trtime(RenesasSCIBaseState *sci) +{ + RenesasSCIBaseClass *rc =3D RENESAS_SCI_BASE_GET_CLASS(sci); + int cks =3D 1 << (2 * FIELD_EX16(sci->smr, SMR, CKS)); + if (sci->input_freq > 0) { + /* x bit transmit time (divrate * brr) / base freq */ + sci->etu =3D rc->divrate(sci) * cks; + sci->etu *=3D sci->brr + 1; + sci->etu *=3D NANOSECONDS_PER_SECOND; + sci->etu /=3D sci->input_freq; + + /* char per bits */ + sci->trtime =3D 8 - FIELD_EX16(sci->smr, SMR, CHR); + sci->trtime +=3D FIELD_EX16(sci->smr, SMR, PE); + sci->trtime +=3D FIELD_EX16(sci->smr, SMR, STOP) + 1 + 1; + sci->trtime *=3D sci->etu; + } +} + +static void sci_pck_update(void *opaque, ClockEvent evt) +{ + RenesasSCIBaseState *sci =3D RENESAS_SCI_BASE(opaque); + + sci->input_freq =3D clock_get_hz(sci->pck); + update_trtime(sci); +} + +#define IS_TR_ENABLED(scr) \ + (FIELD_EX16(scr, SCR, TE) || FIELD_EX16(scr, SCR, RE)) + +static hwaddr map_address(RenesasSCIBaseState *sci, hwaddr addr) +{ + return addr << (2 - sci->regshift); +} + +static void sci_common_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + RenesasSCIBaseState *sci =3D RENESAS_SCI_BASE(opaque); + RenesasSCIBaseClass *rc =3D RENESAS_SCI_BASE_GET_CLASS(opaque); + switch (addr) { case A_SCR: sci->scr =3D val; - if (FIELD_EX8(sci->scr, SCR, TE)) { - sci->ssr =3D FIELD_DP8(sci->ssr, SSR, TDRE, 1); - sci->ssr =3D FIELD_DP8(sci->ssr, SSR, TEND, 1); - if (FIELD_EX8(sci->scr, SCR, TIE)) { - qemu_irq_pulse(sci->irq[TXI]); - } + if (FIELD_EX16(sci->scr, SCR, TE)) { + /* Transmitter enable */ + sci->Xsr =3D FIELD_DP16(sci->Xsr, SSR, TDRE, 1); + sci->Xsr =3D FIELD_DP16(sci->Xsr, SSR, TEND, 1); + rc->irq_fn(sci, TXI); + rc->irq_fn(sci, BRI_TEI); + } else { + /* Transmitter disable */ + update_event_time(sci, TXEND, 0); + update_event_time(sci, TXEMPTY, 0); + } + break; + case A_SMR: + sci->smr =3D val; + update_trtime(sci); + break; + case A_BRR: + sci->brr =3D val; + update_trtime(sci); + break; + default: + qemu_log_mask(LOG_UNIMP, "renesas_sci: Register 0x%" HWADDR_PRIX + " not implemented\n", addr); + } +} + +static void sci_write(void *opaque, hwaddr addr, uint64_t val, unsigned si= ze) +{ + RenesasSCIBaseState *sci =3D RENESAS_SCI_BASE(opaque); + RenesasSCIBaseClass *rc =3D RENESAS_SCI_BASE_GET_CLASS(sci); + bool tx_start; + + if (!clock_is_enabled(sci->pck)) { + qemu_log_mask(LOG_GUEST_ERROR, "renesas_sci: SCI %d is stopped.\n", + sci->unit); + return ; + } + addr =3D map_address(sci, addr); + switch (addr) { + case A_TDR: + sci->tdr =3D val; + break; + case A_SSR: + /* Mask for read only bits */ + sci->Xsr =3D FIELD_DP16(RENESAS_SCI_BASE(sci)->Xsr, SSR, MPBT, + FIELD_EX16(val, SSR, MPBT)); + sci->Xsr &=3D (val | 0x07); + /* Clear ERI */ + rc->irq_fn(sci, ERI); + tx_start =3D FIELD_EX16(sci->read_Xsr, SSR, TDRE) && + !FIELD_EX16(sci->Xsr, SSR, TDRE) && + (FIELD_EX16(sci->Xsr, SSR, ERR) =3D=3D 0); + if (tx_start) { + sci_send_byte(sci); + update_event_time(sci, TXEMPTY, sci->trtime); + rc->irq_fn(sci, TXI); } - if (!FIELD_EX8(sci->scr, SCR, TEIE)) { - qemu_set_irq(sci->irq[TEI], 0); + break; + case A_SPTR: + RENESAS_SCI(sci)->sptr =3D val; + break; + default: + sci_common_write(sci, addr, val, size); + } +} + +static void scia_write(void *opaque, hwaddr addr, uint64_t val, unsigned s= ize) +{ + RenesasSCIBaseState *sci =3D RENESAS_SCI_BASE(opaque); + RenesasSCIAState *scia =3D RENESAS_SCIA(opaque); + + if (!clock_is_enabled(sci->pck)) { + qemu_log_mask(LOG_GUEST_ERROR, "renesas_sci: SCIa %d is stopped.\n= ", + sci->unit); + return ; + } + addr =3D map_address(sci, addr); + switch (addr) { + case A_SMR: + if (IS_TR_ENABLED(sci->scr)) { + qemu_log_mask(LOG_GUEST_ERROR, + "reneas_sci: SMR write protected.\n"); + } else { + sci_common_write(sci, addr, val, size); } - if (!FIELD_EX8(sci->scr, SCR, RIE)) { - qemu_set_irq(sci->irq[ERI], 0); + break; + case A_BRR: + if (IS_TR_ENABLED(sci->scr)) { + qemu_log_mask(LOG_GUEST_ERROR, + "reneas_sci: BRR write protected.\n"); + break; + } else { + sci_common_write(sci, addr, val, size); } break; case A_TDR: sci->tdr =3D val; - if (FIELD_EX8(sci->ssr, SSR, TEND)) { - send_byte(sci); + if (FIELD_EX16(sci->Xsr, SSR, TEND)) { + update_event_time(sci, TXEMPTY, sci->trtime); + sci_send_byte(sci); } else { - sci->ssr =3D FIELD_DP8(sci->ssr, SSR, TDRE, 0); + sci->Xsr =3D FIELD_DP16(sci->Xsr, SSR, TDRE, 0); } + scia_irq(sci, TXI); + scia_irq(sci, BRI_TEI); break; case A_SSR: - sci->ssr =3D FIELD_DP8(sci->ssr, SSR, MPBT, - FIELD_EX8(val, SSR, MPBT)); - sci->ssr =3D FIELD_DP8(sci->ssr, SSR, ERR, - FIELD_EX8(val, SSR, ERR) & 0x07); - if (FIELD_EX8(sci->read_ssr, SSR, ERR) && - FIELD_EX8(sci->ssr, SSR, ERR) =3D=3D 0) { - qemu_set_irq(sci->irq[ERI], 0); - } - break; - case A_RDR: - qemu_log_mask(LOG_GUEST_ERROR, "reneas_sci: RDR is read only.\n"); + /* Mask for read only bits */ + sci->Xsr =3D FIELD_DP16(sci->Xsr, SSR, MPBT, + FIELD_EX16(val, SSR, MPBT)); + sci->Xsr &=3D (val | 0xc7); + /* Clear ERI */ + scia_irq(sci, ERI); break; case A_SCMR: - sci->scmr =3D val; break; - case A_SEMR: /* SEMR */ - sci->semr =3D val; break; + scia->scmr =3D val; + break; + case A_SEMR: + scia->semr =3D val; + break; default: - qemu_log_mask(LOG_UNIMP, "renesas_sci: Register 0x%" HWADDR_PRIX "= " - "not implemented\n", - offset); + sci_common_write(sci, addr, val, size); + break; } } =20 -static uint64_t sci_read(void *opaque, hwaddr offset, unsigned size) +static void scif_write(void *opaque, hwaddr addr, uint64_t val, unsigned s= ize) { - RSCIState *sci =3D RSCI(opaque); + RenesasSCIBaseState *sci =3D RENESAS_SCI_BASE(opaque); + RenesasSCIFState *scif =3D RENESAS_SCIF(opaque); + int txtrg; + int rxtrg; + uint16_t ssr_mask; + uint8_t txd; + + if (!clock_is_enabled(sci->pck)) { + qemu_log_mask(LOG_GUEST_ERROR, "renesas_sci: SCIF %d is stopped.\n= ", + sci->unit); + return ; + } + txtrg =3D 1 << (3 - FIELD_EX16(scif->fcr, FCR, TTRG)); + addr =3D map_address(sci, addr); + switch (addr) { + case A_SCR: + sci->scr =3D val; + if (FIELD_EX16(sci->scr, SCR, TE)) { + /* Transmitter enable */ + sci->Xsr =3D FIELD_DP16(sci->Xsr, FSR, TEND, 1); + sci->Xsr =3D FIELD_DP16(sci->Xsr, FSR, TDFE, 1); + sci->tx_start_time =3D 0; + scif_irq(sci, TXI); + } else { + /* Transmitter disable */ + update_event_time(sci, TXEND, 0); + update_event_time(sci, TXEMPTY, 0); + } + break; + case A_TDR: + if (sci->tx_start_time > 0) { + scif->tdcnt -=3D transmit_byte(scif); + } else { + sci->tx_start_time =3D qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + } + if (scif->tdcnt >=3D SCIF_FIFO_DEPTH) { + break; + } + txd =3D val; + if (qemu_chr_fe_backend_connected(&sci->chr)) { + qemu_chr_fe_write_all(&sci->chr, &txd, 1); + } + if (FIELD_EX16(scif->fcr, FCR, LOOP) && scif_can_receive(sci) > 0)= { + /* Loopback mode */ + scif_receive(sci, &txd, 1); + } + scif->tdcnt++; + sci->Xsr =3D FIELD_DP16(sci->Xsr, FSR, TEND, 0); + update_event_time(sci, TXEND, scif->tdcnt); + if (scif->tdcnt > txtrg) { + sci->Xsr =3D FIELD_DP16(sci->Xsr, FSR, TDFE, 0); + update_event_time(sci, TXEMPTY, scif->tdcnt - txtrg + 1); + scif_irq(sci, TXI); + } + break; + case A_FSR: + rxtrg =3D sci_rtrg[FIELD_EX16(scif->fcr, FCR, RTRG)]; + ssr_mask =3D ~(sci->read_Xsr & 0xf3); + scif->tdcnt -=3D transmit_byte(scif); + if (scif->tdcnt < txtrg) { + ssr_mask =3D FIELD_DP16(ssr_mask, FSR, TDFE, 1); + } + if (fifo8_num_used(&sci->rxfifo) >=3D rxtrg) { + ssr_mask =3D FIELD_DP16(ssr_mask, FSR, RDF, 1); + } + sci->Xsr &=3D (val | ssr_mask); + scif_irq(sci, ERI); + scif_irq(sci, RXI); + scif_irq(sci, TXI); + break; + case A_FCR: + scif->fcr =3D val; + if (FIELD_EX16(scif->fcr, FCR, RFRST)) { + fifo8_reset(&sci->rxfifo); + update_event_time(sci, RXTOUT, 0); + update_event_time(sci, RXNEXT, 0); + } + if (FIELD_EX16(scif->fcr, FCR, TFRST)) { + scif->tdcnt =3D 0; + } + break; + case A_FDR: + qemu_log_mask(LOG_GUEST_ERROR, "reneas_sci: FDR is read only.\n"); + break; + case A_SPTR: + scif->sptr =3D val; + break; + case A_LSR: + if (FIELD_EX16(scif->read_lsr, LSR, ORER) !=3D 1) { + val =3D FIELD_DP16(val, LSR, ORER, 1); + } + scif->lsr &=3D val; + scif_irq(sci, ERI); + break; + default: + sci_common_write(sci, addr, val, size); + break; + } +} =20 - switch (offset) { +static uint64_t sci_common_read(void *opaque, hwaddr addr, unsigned size) +{ + RenesasSCIBaseState *sci =3D RENESAS_SCI_BASE(opaque); + switch (addr) { case A_SMR: return sci->smr; case A_BRR: return sci->brr; case A_SCR: return sci->scr; - case A_TDR: - return sci->tdr; - case A_SSR: - sci->read_ssr =3D sci->ssr; - return sci->ssr; + case A_FSR: /* A_SSR */ + sci->read_Xsr =3D sci->Xsr; + return sci->Xsr; case A_RDR: - sci->ssr =3D FIELD_DP8(sci->ssr, SSR, RDRF, 0); - return sci->rdr; - case A_SCMR: - return sci->scmr; - case A_SEMR: - return sci->semr; + if (fifo8_num_used(&sci->rxfifo) > 0) { + return fifo8_pop(&sci->rxfifo); + } else { + return 0xff; + } default: qemu_log_mask(LOG_UNIMP, "renesas_sci: Register 0x%" HWADDR_PRIX - " not implemented.\n", offset); + " not implemented.\n", addr); } return UINT64_MAX; } =20 -static const MemoryRegionOps sci_ops =3D { - .write =3D sci_write, - .read =3D sci_read, - .endianness =3D DEVICE_NATIVE_ENDIAN, - .impl.max_access_size =3D 1, - .valid.max_access_size =3D 1, -}; +static uint64_t sci_read(void *opaque, hwaddr addr, unsigned size) +{ + RenesasSCIBaseState *sci =3D RENESAS_SCI_BASE(opaque); + addr =3D map_address(sci, addr); + + if (clock_is_enabled(sci->pck)) { + switch (addr) { + case A_TDR: + return sci->tdr; + case A_SPTR: + return RENESAS_SCI(sci)->sptr; + default: + return sci_common_read(sci, addr, size); + } + } else { + qemu_log_mask(LOG_GUEST_ERROR, "renesas_sci: SCI %d is stopped.\n", + sci->unit); + } + return UINT64_MAX; +} =20 -static void rsci_reset(DeviceState *dev) +static uint64_t scia_read(void *opaque, hwaddr addr, unsigned size) { - RSCIState *sci =3D RSCI(dev); - sci->smr =3D sci->scr =3D 0x00; - sci->brr =3D 0xff; - sci->tdr =3D 0xff; - sci->rdr =3D 0x00; - sci->ssr =3D 0x84; - sci->scmr =3D 0x00; - sci->semr =3D 0x00; - sci->rx_next =3D qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + RenesasSCIBaseState *sci =3D RENESAS_SCI_BASE(opaque); + RenesasSCIAState *scia =3D RENESAS_SCIA(opaque); + + if (clock_is_enabled(sci->pck)) { + addr =3D map_address(sci, addr); + switch (addr) { + case A_TDR: + return sci->tdr; + case A_RDR: + sci->Xsr =3D FIELD_DP16(sci->Xsr, SSR, RDRF, 0); + return fifo8_pop(&sci->rxfifo); + case A_SCMR: + return scia->scmr; + default: + return sci_common_read(sci, addr, size); + } + } else { + qemu_log_mask(LOG_GUEST_ERROR, "renesas_sci: SCIa %d is stopped.\n= ", + sci->unit); + } + return UINT64_MAX; +} + +static uint64_t scif_read(void *opaque, hwaddr addr, unsigned size) +{ + RenesasSCIFState *scif =3D RENESAS_SCIF(opaque); + RenesasSCIBaseState *sci =3D RENESAS_SCI_BASE(opaque); + uint64_t ret; + + if (clock_is_enabled(sci->pck)) { + addr =3D map_address(sci, addr); + switch (addr) { + case A_FCR: + return scif->fcr & 0x7ff; + case A_FDR: + ret =3D 0; + ret =3D FIELD_DP16(ret, FDR, Rn, fifo8_num_used(&sci->rxfifo)); + ret =3D FIELD_DP16(ret, FDR, Tn, scif->tdcnt - transmit_byte(s= cif)); + return ret; + case A_SPTR: + return scif->sptr; + case A_LSR: + scif->read_lsr =3D scif->lsr; + return scif->lsr; + default: + return sci_common_read(sci, addr, size); + } + } else { + qemu_log_mask(LOG_GUEST_ERROR, "renesas_sci: SCIF %d is stopped.\n= ", + sci->unit); + } + return UINT64_MAX; +} + +static void rsci_common_init(Object *obj) +{ + RenesasSCIBaseState *sci =3D RENESAS_SCI_BASE(obj); + SysBusDevice *d =3D SYS_BUS_DEVICE(obj); + int i; + + for (i =3D 0; i < SCI_NR_IRQ; i++) { + sysbus_init_irq(d, &sci->irq[i]); + } + fifo8_create(&sci->rxfifo, SCIF_FIFO_DEPTH); + sci->event_timer =3D timer_new_ns(QEMU_CLOCK_VIRTUAL, sci_timer_event,= sci); + sci->pck =3D qdev_init_clock_in(DEVICE(d), "pck", + sci_pck_update, sci, ClockUpdate); } =20 static void sci_event(void *opaque, QEMUChrEvent event) { - RSCIState *sci =3D RSCI(opaque); + RenesasSCIBaseState *sci =3D RENESAS_SCI_BASE(opaque); + RenesasSCIBaseClass *rc =3D RENESAS_SCI_BASE_GET_CLASS(sci); + if (clock_is_enabled(sci->pck) && event =3D=3D CHR_EVENT_BREAK) { + sci->Xsr =3D FIELD_DP16(sci->Xsr, SSR, FER, 1); + rc->irq_fn(sci, BRI_TEI); + } +} + +static void scif_event(void *opaque, QEMUChrEvent event) +{ + RenesasSCIBaseState *sci =3D RENESAS_SCI_BASE(opaque); if (event =3D=3D CHR_EVENT_BREAK) { - sci->ssr =3D FIELD_DP8(sci->ssr, SSR, FER, 1); - if (FIELD_EX8(sci->scr, SCR, RIE)) { - qemu_set_irq(sci->irq[ERI], 1); - } + sci->Xsr =3D FIELD_DP16(sci->Xsr, FSR, BRK, 1); + scif_irq(sci, BRI_TEI); } } =20 -static void rsci_realize(DeviceState *dev, Error **errp) +static void rsci_common_realize(DeviceState *dev, Error **errp) { - RSCIState *sci =3D RSCI(dev); + RenesasSCIBaseState *sci =3D RENESAS_SCI_BASE(dev); =20 - if (sci->input_freq =3D=3D 0) { + if (sci->regshift !=3D 8 && sci->regshift !=3D 16 && sci->regshift != =3D 32) { qemu_log_mask(LOG_GUEST_ERROR, - "renesas_sci: input-freq property must be set."); + "renesas_sci: Invalid register size."); return; } - qemu_chr_fe_set_handlers(&sci->chr, can_receive, receive, - sci_event, NULL, sci, NULL, true); + + sci->smr =3D sci->scr =3D 0x00; + sci->brr =3D 0xff; + sci->tdr =3D 0xff; + sci->Xsr =3D 0x84; + update_trtime(sci); + } =20 -static void rsci_init(Object *obj) +static void register_mmio(RenesasSCIBaseState *sci, int size) { - SysBusDevice *d =3D SYS_BUS_DEVICE(obj); - RSCIState *sci =3D RSCI(obj); - int i; + SysBusDevice *d =3D SYS_BUS_DEVICE(sci); + RenesasSCIBaseClass *rc =3D RENESAS_SCI_BASE_GET_CLASS(sci); =20 - memory_region_init_io(&sci->memory, OBJECT(sci), &sci_ops, - sci, "renesas-sci", 0x8); + memory_region_init_io(&sci->memory, OBJECT(sci), rc->ops, + sci, "renesas-sci", size); sysbus_init_mmio(d, &sci->memory); + memory_region_init_alias(&sci->memory_p4, NULL, "renesas-sci-p4", + &sci->memory, 0, size); + sysbus_init_mmio(d, &sci->memory_p4); + memory_region_init_alias(&sci->memory_a7, NULL, "renesas-sci-a7", + &sci->memory, 0, size); + sysbus_init_mmio(d, &sci->memory_a7); +} =20 - for (i =3D 0; i < SCI_NR_IRQ; i++) { - sysbus_init_irq(d, &sci->irq[i]); - } - timer_init_ns(&sci->timer, QEMU_CLOCK_VIRTUAL, txend, sci); +static void rsci_realize(DeviceState *dev, Error **errp) +{ + RenesasSCIState *sci =3D RENESAS_SCI(dev); + RenesasSCIBaseState *common =3D RENESAS_SCI_BASE(dev); + + rsci_common_realize(dev, errp); + + register_mmio(common, 8 * (1 << common->regshift)); + qemu_chr_fe_set_handlers(&common->chr, sci_can_receive, sci_receive, + sci_event, NULL, sci, NULL, true); + + sci->sptr =3D 0x00; +} + +static void rscia_realize(DeviceState *dev, Error **errp) +{ + RenesasSCIAState *sci =3D RENESAS_SCIA(dev); + RenesasSCIBaseState *common =3D RENESAS_SCI_BASE(dev); + + rsci_common_realize(dev, errp); + + register_mmio(common, 8 * (1 << common->regshift)); + qemu_chr_fe_set_handlers(&common->chr, sci_can_receive, sci_receive, + sci_event, NULL, sci, NULL, true); + + sci->scmr =3D 0x00; + sci->semr =3D 0x00; +} + +static void rscif_realize(DeviceState *dev, Error **errp) +{ + RenesasSCIFState *sci =3D RENESAS_SCIF(dev); + RenesasSCIBaseState *common =3D RENESAS_SCI_BASE(sci); + + rsci_common_realize(dev, errp); + + register_mmio(common, 10 * (1 << common->regshift)); + qemu_chr_fe_set_handlers(&common->chr, scif_can_receive, scif_receive, + scif_event, NULL, sci, NULL, true); + common->Xsr =3D 0x0060; + sci->fcr =3D 0x0000; + sci->sptr =3D 0x0000; + sci->lsr =3D 0x0000; } =20 static const VMStateDescription vmstate_rsci =3D { @@ -303,49 +892,141 @@ static const VMStateDescription vmstate_rsci =3D { .version_id =3D 1, .minimum_version_id =3D 1, .fields =3D (VMStateField[]) { - VMSTATE_INT64(trtime, RSCIState), - VMSTATE_INT64(rx_next, RSCIState), - VMSTATE_UINT8(smr, RSCIState), - VMSTATE_UINT8(brr, RSCIState), - VMSTATE_UINT8(scr, RSCIState), - VMSTATE_UINT8(tdr, RSCIState), - VMSTATE_UINT8(ssr, RSCIState), - VMSTATE_UINT8(rdr, RSCIState), - VMSTATE_UINT8(scmr, RSCIState), - VMSTATE_UINT8(semr, RSCIState), - VMSTATE_UINT8(read_ssr, RSCIState), - VMSTATE_TIMER(timer, RSCIState), VMSTATE_END_OF_LIST() } }; =20 static Property rsci_properties[] =3D { - DEFINE_PROP_UINT64("input-freq", RSCIState, input_freq, 0), - DEFINE_PROP_CHR("chardev", RSCIState, chr), + DEFINE_PROP_INT32("register-size", RenesasSCIBaseState, + regshift, SCI_REGSIZE_32), + DEFINE_PROP_UINT32("unit", RenesasSCIBaseState, unit, 0), + DEFINE_PROP_CHR("chardev", RenesasSCIBaseState, chr), DEFINE_PROP_END_OF_LIST(), }; =20 -static void rsci_class_init(ObjectClass *klass, void *data) +static void rsci_init(Object *obj) { + RenesasSCIBaseState *sci =3D RENESAS_SCI_BASE(obj); + sci->event[RXNEXT].handler =3D sci_rx_next; + sci->event[TXEMPTY].handler =3D sci_tx_empty; +} + +static void rscif_init(Object *obj) +{ + RenesasSCIBaseState *sci =3D RENESAS_SCI_BASE(obj); + sci->event[RXTOUT].handler =3D scif_rx_timeout; + sci->event[TXEMPTY].handler =3D scif_tx_empty; + sci->event[TXEND].handler =3D scif_tx_end; +} + +static void rsci_common_class_init(ObjectClass *klass, void *data) +{ + RenesasSCIBaseClass *rc =3D RENESAS_SCI_BASE_CLASS(klass); DeviceClass *dc =3D DEVICE_CLASS(klass); =20 - dc->realize =3D rsci_realize; dc->vmsd =3D &vmstate_rsci; - dc->reset =3D rsci_reset; device_class_set_props(dc, rsci_properties); + rc->divrate =3D static_divrate; } =20 -static const TypeInfo rsci_info =3D { - .name =3D TYPE_RENESAS_SCI, - .parent =3D TYPE_SYS_BUS_DEVICE, - .instance_size =3D sizeof(RSCIState), - .instance_init =3D rsci_init, - .class_init =3D rsci_class_init, +static const MemoryRegionOps sci_ops =3D { + .read =3D sci_read, + .write =3D sci_write, + .endianness =3D DEVICE_NATIVE_ENDIAN, + .valid =3D { + .min_access_size =3D 1, + .max_access_size =3D 4, + }, }; =20 -static void rsci_register_types(void) +static void rsci_class_init(ObjectClass *klass, void *data) { - type_register_static(&rsci_info); + RenesasSCIBaseClass *comm_rc =3D RENESAS_SCI_BASE_CLASS(klass); + DeviceClass *dc =3D DEVICE_CLASS(klass); + + comm_rc->ops =3D &sci_ops; + comm_rc->irq_fn =3D sci_irq; + dc->realize =3D rsci_realize; } =20 -type_init(rsci_register_types) +static const MemoryRegionOps scia_ops =3D { + .read =3D scia_read, + .write =3D scia_write, + .endianness =3D DEVICE_NATIVE_ENDIAN, + .valid =3D { + .min_access_size =3D 1, + .max_access_size =3D 4, + }, +}; + +static void rscia_class_init(ObjectClass *klass, void *data) +{ + RenesasSCIBaseClass *comm_rc =3D RENESAS_SCI_BASE_CLASS(klass); + DeviceClass *dc =3D DEVICE_CLASS(klass); + + comm_rc->ops =3D &scia_ops; + comm_rc->irq_fn =3D scia_irq; + comm_rc->divrate =3D scia_divrate; + + dc->realize =3D rscia_realize; +} + +static const MemoryRegionOps scif_ops =3D { + .read =3D scif_read, + .write =3D scif_write, + .endianness =3D DEVICE_NATIVE_ENDIAN, + .valid =3D { + .min_access_size =3D 1, + .max_access_size =3D 4, + }, +}; + +static void rscif_class_init(ObjectClass *klass, void *data) +{ + RenesasSCIBaseClass *comm_rc =3D RENESAS_SCI_BASE_CLASS(klass); + DeviceClass *dc =3D DEVICE_CLASS(klass); + + comm_rc->ops =3D &scif_ops; + comm_rc->irq_fn =3D scif_irq; + + dc->realize =3D rscif_realize; +} + +static const TypeInfo renesas_sci_info[] =3D { + { + .name =3D TYPE_RENESAS_SCI_BASE, + .parent =3D TYPE_SYS_BUS_DEVICE, + .instance_size =3D sizeof(RenesasSCIBaseState), + .instance_init =3D rsci_common_init, + .class_init =3D rsci_common_class_init, + .class_size =3D sizeof(RenesasSCIBaseClass), + .abstract =3D true, + }, + { + .name =3D TYPE_RENESAS_SCI, + .parent =3D TYPE_RENESAS_SCI_BASE, + .instance_size =3D sizeof(RenesasSCIState), + .instance_init =3D rsci_init, + .class_init =3D rsci_class_init, + .class_size =3D sizeof(RenesasSCIClass), + }, + { + .name =3D TYPE_RENESAS_SCIA, + .parent =3D TYPE_RENESAS_SCI_BASE, + .instance_size =3D sizeof(RenesasSCIAState), + /* Initializer same of SCI */ + .instance_init =3D rsci_init, + .class_init =3D rscia_class_init, + .class_size =3D sizeof(RenesasSCIAClass), + }, + { + .name =3D TYPE_RENESAS_SCIF, + .parent =3D TYPE_RENESAS_SCI_BASE, + .instance_size =3D sizeof(RenesasSCIFState), + .instance_init =3D rscif_init, + .class_init =3D rscif_class_init, + .class_size =3D sizeof(RenesasSCIFClass), + }, +}; + +DEFINE_TYPES(renesas_sci_info) --=20 2.20.1 From nobody Sun May 5 10:23:05 2024 Delivered-To: importer2@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer2=patchew.org@nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1622093048; cv=none; d=zohomail.com; s=zohoarc; b=gqoizgLMa7lZhBJgSsAflnDbO/qWviyUUG5WjO5EDMAO1kh2XZodexGgRSaowN3jUHl4H2ufBz9OH85gkEwGif81arsOD5fZtBA6AZBzSohcBZhZCCPPXLyUD/mWta1vfAHyMgQe0bSgC9L1gRaEcYYxBb+waBF4t27ndzEfCo0= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1622093048; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=R4hZga9IV9zIzA0fQhJcphsjmjRUX0VSwmNpU+MAdUE=; b=blpphrPMmRcFFCzxAA64WUqDixIsg0eLxf9MtiRgAcoNkuk7h+DcS2yphMQS4/dl3i/uAei78hA5m+c+/MhSviwVO0CBo6BupdeaiJ5ZtnnLKLFo4Za67znwBEI39CRkN3ItseedoiSz/lua96luSEH5niwF3isKx6i0/rrCvD4= ARC-Authentication-Results: i=1; mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer2=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 1622093048775234.37679597076692; Wed, 26 May 2021 22:24:08 -0700 (PDT) Received: from localhost ([::1]:39044 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lm8V5-0002hQ-Hc for importer2@patchew.org; Thu, 27 May 2021 01:24:07 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:56846) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lm8Sg-0008Ls-Sr for qemu-devel@nongnu.org; Thu, 27 May 2021 01:21:39 -0400 Received: from mail03.asahi-net.or.jp ([202.224.55.15]:32926) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lm8Sc-00063v-27 for qemu-devel@nongnu.org; Thu, 27 May 2021 01:21:38 -0400 Received: from sakura.ysato.name (ik1-413-38519.vs.sakura.ne.jp [153.127.30.23]) (Authenticated sender: PQ4Y-STU) by mail03.asahi-net.or.jp (Postfix) with ESMTPA id EEBFA385A6; Thu, 27 May 2021 14:21:29 +0900 (JST) Received: from yo-satoh-debian.localdomain (y245018.dynamic.ppp.asahi-net.or.jp [118.243.245.18]) by sakura.ysato.name (Postfix) with ESMTPSA id 77AA81C0643; Thu, 27 May 2021 14:21:29 +0900 (JST) From: Yoshinori Sato To: qemu-devel@nongnu.org Subject: [PATCH 02/11] hw/char: remove sh_serial. Date: Thu, 27 May 2021 14:21:13 +0900 Message-Id: <20210527052122.97103-3-ysato@users.sourceforge.jp> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20210527052122.97103-1-ysato@users.sourceforge.jp> References: <20210527052122.97103-1-ysato@users.sourceforge.jp> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer2=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: softfail client-ip=202.224.55.15; envelope-from=ysato@users.sourceforge.jp; helo=mail03.asahi-net.or.jp X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_DNSWL_LOW=-0.7, SPF_HELO_NONE=0.001, SPF_SOFTFAIL=0.665 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Yoshinori Sato Errors-To: qemu-devel-bounces+importer2=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" Migrate to renesas_sci. Signed-off-by: Yoshinori Sato --- hw/char/sh_serial.c | 431 -------------------------------------------- MAINTAINERS | 4 +- hw/char/Kconfig | 3 - hw/char/meson.build | 1 - 4 files changed, 2 insertions(+), 437 deletions(-) delete mode 100644 hw/char/sh_serial.c diff --git a/hw/char/sh_serial.c b/hw/char/sh_serial.c deleted file mode 100644 index 167f4d8cb9..0000000000 --- a/hw/char/sh_serial.c +++ /dev/null @@ -1,431 +0,0 @@ -/* - * QEMU SCI/SCIF serial port emulation - * - * Copyright (c) 2007 Magnus Damm - * - * Based on serial.c - QEMU 16450 UART emulation - * Copyright (c) 2003-2004 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a= copy - * of this software and associated documentation files (the "Software"), t= o deal - * in the Software without restriction, including without limitation the r= ights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or se= ll - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included= in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS= OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OT= HER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING= FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS = IN - * THE SOFTWARE. - */ - -#include "qemu/osdep.h" -#include "hw/irq.h" -#include "hw/sh4/sh.h" -#include "chardev/char-fe.h" -#include "qapi/error.h" -#include "qemu/timer.h" - -//#define DEBUG_SERIAL - -#define SH_SERIAL_FLAG_TEND (1 << 0) -#define SH_SERIAL_FLAG_TDE (1 << 1) -#define SH_SERIAL_FLAG_RDF (1 << 2) -#define SH_SERIAL_FLAG_BRK (1 << 3) -#define SH_SERIAL_FLAG_DR (1 << 4) - -#define SH_RX_FIFO_LENGTH (16) - -typedef struct { - MemoryRegion iomem; - MemoryRegion iomem_p4; - MemoryRegion iomem_a7; - uint8_t smr; - uint8_t brr; - uint8_t scr; - uint8_t dr; /* ftdr / tdr */ - uint8_t sr; /* fsr / ssr */ - uint16_t fcr; - uint8_t sptr; - - uint8_t rx_fifo[SH_RX_FIFO_LENGTH]; /* frdr / rdr */ - uint8_t rx_cnt; - uint8_t rx_tail; - uint8_t rx_head; - - int freq; - int feat; - int flags; - int rtrg; - - CharBackend chr; - QEMUTimer *fifo_timeout_timer; - uint64_t etu; /* Elementary Time Unit (ns) */ - - qemu_irq eri; - qemu_irq rxi; - qemu_irq txi; - qemu_irq tei; - qemu_irq bri; -} sh_serial_state; - -static void sh_serial_clear_fifo(sh_serial_state * s) -{ - memset(s->rx_fifo, 0, SH_RX_FIFO_LENGTH); - s->rx_cnt =3D 0; - s->rx_head =3D 0; - s->rx_tail =3D 0; -} - -static void sh_serial_write(void *opaque, hwaddr offs, - uint64_t val, unsigned size) -{ - sh_serial_state *s =3D opaque; - unsigned char ch; - -#ifdef DEBUG_SERIAL - printf("sh_serial: write offs=3D0x%02x val=3D0x%02x\n", - offs, val); -#endif - switch(offs) { - case 0x00: /* SMR */ - s->smr =3D val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0x7b : 0xff); - return; - case 0x04: /* BRR */ - s->brr =3D val; - return; - case 0x08: /* SCR */ - /* TODO : For SH7751, SCIF mask should be 0xfb. */ - s->scr =3D val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0xfa : 0xff); - if (!(val & (1 << 5))) - s->flags |=3D SH_SERIAL_FLAG_TEND; - if ((s->feat & SH_SERIAL_FEAT_SCIF) && s->txi) { - qemu_set_irq(s->txi, val & (1 << 7)); - } - if (!(val & (1 << 6))) { - qemu_set_irq(s->rxi, 0); - } - return; - case 0x0c: /* FTDR / TDR */ - if (qemu_chr_fe_backend_connected(&s->chr)) { - ch =3D val; - /* XXX this blocks entire thread. Rewrite to use - * qemu_chr_fe_write and background I/O callbacks */ - qemu_chr_fe_write_all(&s->chr, &ch, 1); - } - s->dr =3D val; - s->flags &=3D ~SH_SERIAL_FLAG_TDE; - return; -#if 0 - case 0x14: /* FRDR / RDR */ - ret =3D 0; - break; -#endif - } - if (s->feat & SH_SERIAL_FEAT_SCIF) { - switch(offs) { - case 0x10: /* FSR */ - if (!(val & (1 << 6))) - s->flags &=3D ~SH_SERIAL_FLAG_TEND; - if (!(val & (1 << 5))) - s->flags &=3D ~SH_SERIAL_FLAG_TDE; - if (!(val & (1 << 4))) - s->flags &=3D ~SH_SERIAL_FLAG_BRK; - if (!(val & (1 << 1))) - s->flags &=3D ~SH_SERIAL_FLAG_RDF; - if (!(val & (1 << 0))) - s->flags &=3D ~SH_SERIAL_FLAG_DR; - - if (!(val & (1 << 1)) || !(val & (1 << 0))) { - if (s->rxi) { - qemu_set_irq(s->rxi, 0); - } - } - return; - case 0x18: /* FCR */ - s->fcr =3D val; - switch ((val >> 6) & 3) { - case 0: - s->rtrg =3D 1; - break; - case 1: - s->rtrg =3D 4; - break; - case 2: - s->rtrg =3D 8; - break; - case 3: - s->rtrg =3D 14; - break; - } - if (val & (1 << 1)) { - sh_serial_clear_fifo(s); - s->sr &=3D ~(1 << 1); - } - - return; - case 0x20: /* SPTR */ - s->sptr =3D val & 0xf3; - return; - case 0x24: /* LSR */ - return; - } - } - else { - switch(offs) { -#if 0 - case 0x0c: - ret =3D s->dr; - break; - case 0x10: - ret =3D 0; - break; -#endif - case 0x1c: - s->sptr =3D val & 0x8f; - return; - } - } - - fprintf(stderr, "sh_serial: unsupported write to 0x%02" - HWADDR_PRIx "\n", offs); - abort(); -} - -static uint64_t sh_serial_read(void *opaque, hwaddr offs, - unsigned size) -{ - sh_serial_state *s =3D opaque; - uint32_t ret =3D ~0; - -#if 0 - switch(offs) { - case 0x00: - ret =3D s->smr; - break; - case 0x04: - ret =3D s->brr; - break; - case 0x08: - ret =3D s->scr; - break; - case 0x14: - ret =3D 0; - break; - } -#endif - if (s->feat & SH_SERIAL_FEAT_SCIF) { - switch(offs) { - case 0x00: /* SMR */ - ret =3D s->smr; - break; - case 0x08: /* SCR */ - ret =3D s->scr; - break; - case 0x10: /* FSR */ - ret =3D 0; - if (s->flags & SH_SERIAL_FLAG_TEND) - ret |=3D (1 << 6); - if (s->flags & SH_SERIAL_FLAG_TDE) - ret |=3D (1 << 5); - if (s->flags & SH_SERIAL_FLAG_BRK) - ret |=3D (1 << 4); - if (s->flags & SH_SERIAL_FLAG_RDF) - ret |=3D (1 << 1); - if (s->flags & SH_SERIAL_FLAG_DR) - ret |=3D (1 << 0); - - if (s->scr & (1 << 5)) - s->flags |=3D SH_SERIAL_FLAG_TDE | SH_SERIAL_FLAG_TEND; - - break; - case 0x14: - if (s->rx_cnt > 0) { - ret =3D s->rx_fifo[s->rx_tail++]; - s->rx_cnt--; - if (s->rx_tail =3D=3D SH_RX_FIFO_LENGTH) - s->rx_tail =3D 0; - if (s->rx_cnt < s->rtrg) - s->flags &=3D ~SH_SERIAL_FLAG_RDF; - } - break; - case 0x18: - ret =3D s->fcr; - break; - case 0x1c: - ret =3D s->rx_cnt; - break; - case 0x20: - ret =3D s->sptr; - break; - case 0x24: - ret =3D 0; - break; - } - } - else { - switch(offs) { -#if 0 - case 0x0c: - ret =3D s->dr; - break; - case 0x10: - ret =3D 0; - break; - case 0x14: - ret =3D s->rx_fifo[0]; - break; -#endif - case 0x1c: - ret =3D s->sptr; - break; - } - } -#ifdef DEBUG_SERIAL - printf("sh_serial: read offs=3D0x%02x val=3D0x%x\n", - offs, ret); -#endif - - if (ret & ~((1 << 16) - 1)) { - fprintf(stderr, "sh_serial: unsupported read from 0x%02" - HWADDR_PRIx "\n", offs); - abort(); - } - - return ret; -} - -static int sh_serial_can_receive(sh_serial_state *s) -{ - return s->scr & (1 << 4); -} - -static void sh_serial_receive_break(sh_serial_state *s) -{ - if (s->feat & SH_SERIAL_FEAT_SCIF) - s->sr |=3D (1 << 4); -} - -static int sh_serial_can_receive1(void *opaque) -{ - sh_serial_state *s =3D opaque; - return sh_serial_can_receive(s); -} - -static void sh_serial_timeout_int(void *opaque) -{ - sh_serial_state *s =3D opaque; - - s->flags |=3D SH_SERIAL_FLAG_RDF; - if (s->scr & (1 << 6) && s->rxi) { - qemu_set_irq(s->rxi, 1); - } -} - -static void sh_serial_receive1(void *opaque, const uint8_t *buf, int size) -{ - sh_serial_state *s =3D opaque; - - if (s->feat & SH_SERIAL_FEAT_SCIF) { - int i; - for (i =3D 0; i < size; i++) { - if (s->rx_cnt < SH_RX_FIFO_LENGTH) { - s->rx_fifo[s->rx_head++] =3D buf[i]; - if (s->rx_head =3D=3D SH_RX_FIFO_LENGTH) { - s->rx_head =3D 0; - } - s->rx_cnt++; - if (s->rx_cnt >=3D s->rtrg) { - s->flags |=3D SH_SERIAL_FLAG_RDF; - if (s->scr & (1 << 6) && s->rxi) { - timer_del(s->fifo_timeout_timer); - qemu_set_irq(s->rxi, 1); - } - } else { - timer_mod(s->fifo_timeout_timer, - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 15 * s->et= u); - } - } - } - } else { - s->rx_fifo[0] =3D buf[0]; - } -} - -static void sh_serial_event(void *opaque, QEMUChrEvent event) -{ - sh_serial_state *s =3D opaque; - if (event =3D=3D CHR_EVENT_BREAK) - sh_serial_receive_break(s); -} - -static const MemoryRegionOps sh_serial_ops =3D { - .read =3D sh_serial_read, - .write =3D sh_serial_write, - .endianness =3D DEVICE_NATIVE_ENDIAN, -}; - -void sh_serial_init(MemoryRegion *sysmem, - hwaddr base, int feat, - uint32_t freq, Chardev *chr, - qemu_irq eri_source, - qemu_irq rxi_source, - qemu_irq txi_source, - qemu_irq tei_source, - qemu_irq bri_source) -{ - sh_serial_state *s; - - s =3D g_malloc0(sizeof(sh_serial_state)); - - s->feat =3D feat; - s->flags =3D SH_SERIAL_FLAG_TEND | SH_SERIAL_FLAG_TDE; - s->rtrg =3D 1; - - s->smr =3D 0; - s->brr =3D 0xff; - s->scr =3D 1 << 5; /* pretend that TX is enabled so early printk works= */ - s->sptr =3D 0; - - if (feat & SH_SERIAL_FEAT_SCIF) { - s->fcr =3D 0; - } - else { - s->dr =3D 0xff; - } - - sh_serial_clear_fifo(s); - - memory_region_init_io(&s->iomem, NULL, &sh_serial_ops, s, - "serial", 0x100000000ULL); - - memory_region_init_alias(&s->iomem_p4, NULL, "serial-p4", &s->iomem, - 0, 0x28); - memory_region_add_subregion(sysmem, P4ADDR(base), &s->iomem_p4); - - memory_region_init_alias(&s->iomem_a7, NULL, "serial-a7", &s->iomem, - 0, 0x28); - memory_region_add_subregion(sysmem, A7ADDR(base), &s->iomem_a7); - - if (chr) { - qemu_chr_fe_init(&s->chr, chr, &error_abort); - qemu_chr_fe_set_handlers(&s->chr, sh_serial_can_receive1, - sh_serial_receive1, - sh_serial_event, NULL, s, NULL, true); - } - - s->fifo_timeout_timer =3D timer_new_ns(QEMU_CLOCK_VIRTUAL, - sh_serial_timeout_int, s); - s->etu =3D NANOSECONDS_PER_SECOND / 9600; - s->eri =3D eri_source; - s->rxi =3D rxi_source; - s->txi =3D txi_source; - s->tei =3D tei_source; - s->bri =3D bri_source; -} diff --git a/MAINTAINERS b/MAINTAINERS index a77f246569..ecfa97cefa 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1410,7 +1410,7 @@ R2D R: Yoshinori Sato R: Magnus Damm S: Odd Fixes -F: hw/char/sh_serial.c +F: hw/char/renesas_sci.c F: hw/sh4/r2d.c F: hw/intc/sh_intc.c F: hw/pci-host/sh_pci.c @@ -1422,7 +1422,7 @@ R: Yoshinori Sato R: Magnus Damm S: Odd Fixes F: hw/block/tc58128.c -F: hw/char/sh_serial.c +F: hw/char/reness_sci.c F: hw/sh4/shix.c F: hw/intc/sh_intc.c F: hw/timer/sh_timer.c diff --git a/hw/char/Kconfig b/hw/char/Kconfig index 4cf36ac637..a8bf0c6a77 100644 --- a/hw/char/Kconfig +++ b/hw/char/Kconfig @@ -50,9 +50,6 @@ config SCLPCONSOLE config TERMINAL3270 bool =20 -config SH_SCI - bool - config RENESAS_SCI bool =20 diff --git a/hw/char/meson.build b/hw/char/meson.build index 8361d0ab28..b9a88aa200 100644 --- a/hw/char/meson.build +++ b/hw/char/meson.build @@ -29,7 +29,6 @@ softmmu_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_= uart.c')) softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_aux.c')) softmmu_ss.add(when: 'CONFIG_RENESAS_SCI', if_true: files('renesas_sci.c')) softmmu_ss.add(when: 'CONFIG_SIFIVE_UART', if_true: files('sifive_uart.c')) -softmmu_ss.add(when: 'CONFIG_SH_SCI', if_true: files('sh_serial.c')) softmmu_ss.add(when: 'CONFIG_STM32F2XX_USART', if_true: files('stm32f2xx_u= sart.c')) softmmu_ss.add(when: 'CONFIG_MCHP_PFSOC_MMUART', if_true: files('mchp_pfso= c_mmuart.c')) =20 --=20 2.20.1 From nobody Sun May 5 10:23:05 2024 Delivered-To: importer2@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer2=patchew.org@nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1622093372; cv=none; d=zohomail.com; s=zohoarc; b=TF/zpExXNy1lUIqiTCr31HSTAgs2i+OVngh21zTtbb5u0rIwdmSkaCsxV4oTMtImVyN8uB+5vtQorNGyyNVmk9yVvUPIWQXl2vm+JL7AjoJJJl2SBBGlVnqjxfYxQU90FrHAr6Q5Rx9yL5f/O3fuI9Bw1JifkjWHe6gDlgHaWd4= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1622093372; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=ul1m3taDr73oHroGMzW3f9Bm6oY29EU2hykV7IXKW4w=; b=B38qqtTWctQnK/RAk9HzAbW1UArGmriVuSVWTlW8B/SBB4g31uH0Qy9JOf6y9dVcqgmssZYfhzISZ3zXpQOl+MUW36ufOz8jPST7O6LO1DwaR8ePBfrE0YA9MWwLeCEBM5PewGVrUHtXZUDbekC63AeHyYitX0Z/9gtQhuFSqbc= ARC-Authentication-Results: i=1; mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer2=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 1622093372370727.9959042166037; Wed, 26 May 2021 22:29:32 -0700 (PDT) Received: from localhost ([::1]:56064 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lm8aJ-0005ed-9u for importer2@patchew.org; Thu, 27 May 2021 01:29:31 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:56902) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lm8Sj-0008S0-0X for qemu-devel@nongnu.org; Thu, 27 May 2021 01:21:41 -0400 Received: from mail01.asahi-net.or.jp ([202.224.55.13]:58620) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lm8Sc-00064b-2X for qemu-devel@nongnu.org; Thu, 27 May 2021 01:21:40 -0400 Received: from sakura.ysato.name (ik1-413-38519.vs.sakura.ne.jp [153.127.30.23]) (Authenticated sender: PQ4Y-STU) by mail01.asahi-net.or.jp (Postfix) with ESMTPA id 7AB7D11D366; Thu, 27 May 2021 14:21:30 +0900 (JST) Received: from yo-satoh-debian.localdomain (y245018.dynamic.ppp.asahi-net.or.jp [118.243.245.18]) by sakura.ysato.name (Postfix) with ESMTPSA id E18F31C064D; Thu, 27 May 2021 14:21:29 +0900 (JST) From: Yoshinori Sato To: qemu-devel@nongnu.org Subject: [PATCH 03/11] hw/timer: Renesas TMU/CMT module. Date: Thu, 27 May 2021 14:21:14 +0900 Message-Id: <20210527052122.97103-4-ysato@users.sourceforge.jp> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20210527052122.97103-1-ysato@users.sourceforge.jp> References: <20210527052122.97103-1-ysato@users.sourceforge.jp> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer2=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: softfail client-ip=202.224.55.13; envelope-from=ysato@users.sourceforge.jp; helo=mail01.asahi-net.or.jp X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_DNSWL_LOW=-0.7, SPF_HELO_NONE=0.001, SPF_SOFTFAIL=0.665 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Yoshinori Sato Errors-To: qemu-devel-bounces+importer2=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" TMU - SH4 Timer module. CMT - Compare and match timer used by some Renesas MCUs. The two modules have similar interfaces and have been merged. Signed-off-by: Yoshinori Sato --- include/hw/timer/renesas_timer.h | 96 +++++ hw/timer/renesas_timer.c | 644 +++++++++++++++++++++++++++++++ hw/timer/Kconfig | 3 + hw/timer/meson.build | 1 + 4 files changed, 744 insertions(+) create mode 100644 include/hw/timer/renesas_timer.h create mode 100644 hw/timer/renesas_timer.c diff --git a/include/hw/timer/renesas_timer.h b/include/hw/timer/renesas_ti= mer.h new file mode 100644 index 0000000000..d71feec54e --- /dev/null +++ b/include/hw/timer/renesas_timer.h @@ -0,0 +1,96 @@ +/* + * Renesas Timer unit Object + * + * Copyright (c) 2020 Yoshinori Sato + * + * This code is licensed under the GPL version 2 or later. + * + */ + +#ifndef HW_RENESAS_TIMER_H +#define HW_RENESAS_TIMER_H + +#include "hw/sysbus.h" +#include "hw/qdev-clock.h" + +#define TYPE_RENESAS_TIMER_BASE "renesas-timer" +OBJECT_DECLARE_TYPE(RenesasTimerBaseState, RenesasTimerBaseClass, + RENESAS_TIMER_BASE) +#define TYPE_RENESAS_CMT "renesas-cmt" +OBJECT_DECLARE_TYPE(RenesasCMTState, RenesasCMTClass, + RENESAS_CMT) +#define TYPE_RENESAS_TMU "renesas-tmu" +OBJECT_DECLARE_TYPE(RenesasTMUState, RenesasTMUClass, + RENESAS_TMU) + +enum { + TIMER_CH_CMT =3D 2, + TIMER_CH_TMU =3D 3, +}; + +enum { + CMT_NR_IRQ =3D 1 * TIMER_CH_CMT, +}; + +struct RenesasTimerBaseState; + +enum dirction { + countup, countdown, +}; + +struct rtimer_ch { + uint32_t cnt; + uint32_t cor; + uint16_t ctrl; + qemu_irq irq; + int64_t base; + int64_t next; + uint64_t clk; + bool start; + QEMUTimer *timer; + struct RenesasTimerBaseState *tmrp; +}; + +typedef struct RenesasTimerBaseState { + SysBusDevice parent_obj; + + uint64_t input_freq; + MemoryRegion memory; + Clock *pck; + + struct rtimer_ch ch[TIMER_CH_TMU]; + int num_ch; + enum dirction direction; + int unit; +} RenesasTimerBaseState; + +typedef struct RenesasCMTState { + RenesasTimerBaseState parent_obj; +} RenesasCMTState; + +typedef struct RenesasTMUState { + RenesasTimerBaseState parent_obj; + uint8_t tocr; + MemoryRegion memory_p4; + MemoryRegion memory_a7; +} RenesasTMUState; + +typedef struct RenesasTimerBaseClass { + SysBusDeviceClass parent; + int (*divrate)(RenesasTimerBaseState *tmr, int ch); + void (*timer_event)(void *opaque); + int64_t (*delta_to_tcnt)(RenesasTimerBaseState *tmr, int ch, int64_t d= elta); + int64_t (*get_next)(RenesasTimerBaseState *tmr, int ch); + void (*update_clk)(RenesasTimerBaseState *tmr, int ch); +} RenesasTimerBaseClass; + +typedef struct RenesasCMTClass { + RenesasTimerBaseClass parent; +} RenesasCMTClass; + +typedef struct RenesasTMUClass { + RenesasTimerBaseClass parent; + void (*p_update_clk)(RenesasTimerBaseState *tmr, int ch); +} RenesasTMUClass; + +#endif diff --git a/hw/timer/renesas_timer.c b/hw/timer/renesas_timer.c new file mode 100644 index 0000000000..b1224e1e6b --- /dev/null +++ b/hw/timer/renesas_timer.c @@ -0,0 +1,644 @@ +/* + * Renesas 16bit/32bit Compare-match timer (CMT/TMU) + * + * Datasheet: RX62N Group, RX621 Group User's Manual: Hardware + * (Rev.1.40 R01UH0033EJ0140) + * And SH7751 Group, SH7751R Group User's Manual: Hardware + * (Rev.4.01 R01UH0457EJ0401) + * + * Copyright (c) 2021 Yoshinori Sato + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * 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/log.h" +#include "qapi/error.h" +#include "qemu/timer.h" +#include "hw/hw.h" +#include "hw/irq.h" +#include "hw/sysbus.h" +#include "hw/registerfields.h" +#include "hw/qdev-properties.h" +#include "hw/timer/renesas_timer.h" +#include "migration/vmstate.h" +#include "qemu/error-report.h" + +REG32(TOCR, 0) + FIELD(TOCR, TCOE, 0, 1) +REG32(CMSTR, 0) +REG32(TSTR, 4) +REG32(TCOR, 8) +REG32(TCNT, 12) +REG32(TCR, 16) + FIELD(TCR, TPSC, 0, 3) + FIELD(TCR, CKEG, 3, 2) + FIELD(TCR, UNIE, 5, 1) + FIELD(TCR, ICPE, 6, 2) + FIELD(TCR, UNF, 8, 1) + FIELD(TCR, ICPF, 9, 1) +REG32(CMCR, 16) + FIELD(CMCR, CKS, 0, 2) + FIELD(CMCR, CMIE, 6, 1) +REG32(TCPR, 20) + +static int cmt_div(RenesasTimerBaseState *tmr, int ch) +{ + return 8 << (2 * FIELD_EX16(tmr->ch[ch].ctrl, CMCR, CKS)); +} + +static int tmu_div(RenesasTimerBaseState *tmr, int ch) +{ + if (FIELD_EX16(tmr->ch[ch].ctrl, TCR, TPSC) <=3D 5) { + return 4 << (2 * FIELD_EX16(tmr->ch[ch].ctrl, TCR, TPSC)); + } else { + return 0; + } + +} + +static int64_t cmt_get_next(RenesasTimerBaseState *tmr, int ch) +{ + return tmr->ch[ch].cor - tmr->ch[ch].cnt; +} + +static int64_t tmu_get_next(RenesasTimerBaseState *tmr, int ch) +{ + return tmr->ch[ch].cnt; +} + +static void cmt_timer_event(void *opaque) +{ + struct rtimer_ch *ch =3D opaque; + ch->cnt =3D 0; + if (FIELD_EX16(ch->ctrl, CMCR, CMIE)) { + qemu_irq_pulse(ch->irq); + } + ch->base =3D ch->next; + ch->next +=3D (ch->cor - ch->cnt) * ch->clk; + timer_mod(ch->timer, ch->next); +} + +static void tmu_timer_event(void *opaque) +{ + struct rtimer_ch *ch =3D opaque; + ch->cnt =3D ch->cor; + if (!FIELD_EX16(ch->ctrl, TCR, UNF)) { + ch->ctrl =3D FIELD_DP16(ch->ctrl, TCR, UNF, 1); + qemu_set_irq(ch->irq, FIELD_EX16(ch->ctrl, TCR, UNIE)); + } + ch->base =3D ch->next; + ch->next +=3D ch->cnt * ch->clk; + timer_mod(ch->timer, ch->next); +} + +static int64_t cmt_delta_to_cnt(RenesasTimerBaseState *tmr, + int ch, int64_t delta) +{ + return tmr->ch[ch].cnt + delta; +} + +static int64_t tmu_delta_to_cnt(RenesasTimerBaseState *tmr, + int ch, int64_t delta) +{ + return tmr->ch[ch].cnt - delta; +} + +static int64_t read_tcnt(RenesasTimerBaseState *tmr, int ch) +{ + int64_t delta, now =3D qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + RenesasTimerBaseClass *tc =3D RENESAS_TIMER_BASE_GET_CLASS(tmr); + + if (tmr->ch[ch].clk > 0) { + delta =3D (now - tmr->ch[ch].base); + delta /=3D tmr->ch[ch].clk; + return tc->delta_to_tcnt(tmr, ch, delta); + } else { + return tmr->ch[ch].cnt; + } +} + +static void tmr_start_stop(RenesasTimerBaseState *tmr, int ch, int start) +{ + RenesasTimerBaseClass *tc =3D RENESAS_TIMER_BASE_GET_CLASS(tmr); + int64_t now; + if (tmr->ch[ch].start !=3D start) { + now =3D qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + if (start) { + if (!tmr->ch[ch].timer) { + tmr->ch[ch].timer =3D + timer_new_ns(QEMU_CLOCK_VIRTUAL, + tc->timer_event, &tmr->ch[ch]); + } + tmr->ch[ch].base =3D now; + tmr->ch[ch].next =3D now + tc->get_next(tmr, ch) * tmr->ch[ch]= .clk; + timer_mod(tmr->ch[ch].timer, tmr->ch[ch].next); + } else { + tmr->ch[ch].cnt =3D read_tcnt(tmr, ch); + tmr->ch[ch].next =3D 0; + if (tmr->ch[ch].timer) { + timer_del(tmr->ch[ch].timer); + } + } + tmr->ch[ch].start =3D start; + } +} + +static uint64_t read_tstr(RenesasTimerBaseState *tmr) +{ + uint64_t ret =3D 0; + int ch; + for (ch =3D 0; ch < tmr->num_ch; ch++) { + ret =3D deposit64(ret, ch, 1, tmr->ch[ch].start); + } + return ret; +} + +static void update_clk(RenesasTimerBaseState *tmr, int ch) +{ + RenesasTimerBaseClass *tc =3D RENESAS_TIMER_BASE_GET_CLASS(tmr); + int t; + t =3D tc->divrate(tmr, ch); + if (t > 0) { + t =3D tmr->input_freq / t; + tmr->ch[ch].clk =3D NANOSECONDS_PER_SECOND / t; + } else { + tmr->ch[ch].clk =3D 0; + } +} + +static void tmu_update_clk(RenesasTimerBaseState *tmr, int ch) +{ + /* Clock setting validation */ + int tpsc =3D FIELD_EX16(tmr->ch[ch].ctrl, TCR, TPSC); + switch (tpsc) { + case 5: + qemu_log_mask(LOG_GUEST_ERROR, + "renesas_timer: Invalid TPSC valule %d.\n", tpsc); + break; + case 6: + case 7: + qemu_log_mask(LOG_UNIMP, + "renesas_timer: External clock not implemented.\n"); + break; + } + /* Interrupt clear */ + if (FIELD_EX16(tmr->ch[ch].ctrl, TCR, UNF) =3D=3D 0) { + qemu_set_irq(tmr->ch[ch].irq, 0); + } + update_clk(tmr, ch); +} + +static uint64_t channel_read(RenesasTimerBaseState *tmr, int ch, int reg) +{ + switch (reg) { + case R_TCR: + return tmr->ch[ch].ctrl; + case R_TCNT: + if (tmr->ch[ch].start) { + return read_tcnt(tmr, ch); + } else { + return tmr->ch[ch].cnt; + } + case R_TCOR: + return tmr->ch[ch].cor; + } + return UINT64_MAX; +} + +static void tmr_pck_update(void *opaque, ClockEvent evt) +{ + RenesasTimerBaseState *tmr =3D RENESAS_TIMER_BASE(opaque); + int64_t now; + int i; + struct rtimer_ch *ch; + for (i =3D 0; i < TIMER_CH_CMT; i++) { + if (tmr->ch[i].start) { + tmr->ch[i].cnt =3D read_tcnt(tmr, i); + } + } + if (clock_is_enabled(tmr->pck)) { + tmr->input_freq =3D clock_get_hz(tmr->pck); + now =3D qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + for (i =3D 0; i < TIMER_CH_CMT; i++) { + update_clk(tmr, i); + ch =3D &tmr->ch[i]; + if (ch->start) { + ch->next =3D ch->base =3D now; + if (tmr->direction =3D=3D countup) { + ch->next +=3D (ch->cor - ch->cnt) * ch->clk; + } else { + ch->next +=3D ch->cnt * ch->clk; + } + timer_mod(ch->timer, ch->next); + } + } + } else { + for (i =3D 0; i < TIMER_CH_CMT; i++) { + if (tmr->ch[i].timer) { + timer_del(tmr->ch[i].timer); + } + } + } +} + +static uint64_t cmt_read(void *opaque, hwaddr addr, unsigned size) +{ + RenesasCMTState *cmt =3D RENESAS_CMT(opaque); + RenesasTimerBaseState *tmr =3D RENESAS_TIMER_BASE(cmt); + int ch, reg; + + /* +0 - CMSTR (TSTR) */ + /* +2 - CMCR0 (TCR) */ + /* +4 - CMCNT0 (TCNT) */ + /* +6 - CMCOR0 (TCOR) */ + /* +8 - CMCR1 (TCR) */ + /* +10 - CMCNT1 (TCNT) */ + /* +12 - CMCOR1 (TCOR) */ + if (!clock_is_enabled(tmr->pck)) { + qemu_log_mask(LOG_UNIMP, "renesas_timer: Unit %d stopped.\n", + tmr->unit); + return UINT64_MAX; + } + addr /=3D 2; + if (addr =3D=3D R_CMSTR) { + return read_tstr(RENESAS_TIMER_BASE(cmt)); + } else { + ch =3D addr / 4; + if (addr < 4) { + /* skip CMSTR */ + addr--; + } + reg =3D 2 - (addr % 4); + return channel_read(RENESAS_TIMER_BASE(cmt), ch, reg); + } +} + +static uint64_t tmu_read(void *opaque, hwaddr addr, unsigned size) +{ + RenesasTMUState *tmu =3D RENESAS_TMU(opaque); + RenesasTimerBaseState *tmr =3D RENESAS_TIMER_BASE(tmu); + int ch =3D -1, reg =3D -1; + + /* +0 - TCOR */ + /* +4 - TSTR */ + /* +8 - TCOR0 */ + /* +12 - TCNT0 */ + /* +16 - TCR0 */ + /* +20 - TCOR1 */ + /* +24 - TCNT1 */ + /* +28 - TCR1 */ + /* +32 - TCOR2 */ + /* +36 - TCNT2 */ + /* +40 - TCR2 */ + /* +44 - TCPR2 */ + + if (tmr->unit !=3D 0 && addr >=3D 32) { + /* UNIT1 channel2 is not exit */ + qemu_log_mask(LOG_UNIMP, "renesas_timer: Register 0x%" + HWADDR_PRIX " not implemented\n", addr); + return UINT64_MAX; + } + if (!clock_is_enabled(tmr->pck)) { + qemu_log_mask(LOG_UNIMP, "renesas_timer: Unit %d stopped.\n", + tmr->unit); + return UINT64_MAX; + } + addr /=3D 4; + switch (addr) { + case R_TOCR: + return tmu->tocr; + case R_TSTR: + return read_tstr(RENESAS_TIMER_BASE(tmu)); + case R_TCPR: + qemu_log_mask(LOG_UNIMP, + "renesas_timer: Input capture not implemented.\n"); + return UINT64_MAX; + default: + ch =3D (addr - 2) / 3; + reg =3D (addr - 2) % 3 + 2; + return channel_read(RENESAS_TIMER_BASE(tmu), ch, reg); + } +} + +static void write_tstr(RenesasTimerBaseState *tmr, uint16_t val) +{ + int ch; + for (ch =3D 0; ch < tmr->num_ch; ch++) { + tmr_start_stop(tmr, ch, extract16(val, ch, 1)); + } +} + +static void write_tcr(RenesasTimerBaseState *tmr, int ch, + uint16_t val, uint16_t mask) +{ + RenesasTimerBaseClass *tc =3D RENESAS_TIMER_BASE_GET_CLASS(tmr); + tmr->ch[ch].ctrl |=3D (mask & 0x00ff); + tmr->ch[ch].ctrl &=3D val & mask; + tc->update_clk(tmr, ch); +} + +static void channel_write(RenesasTimerBaseState *tmr, int ch, + int reg, uint64_t val) +{ + switch (reg) { + case R_TCNT: + tmr->ch[ch].cnt =3D val; + break; + case R_TCOR: + tmr->ch[ch].cor =3D val; + break; + } +} + +static void cmt_write(void *opaque, hwaddr addr, uint64_t val, unsigned si= ze) +{ + RenesasTimerBaseState *tmr =3D RENESAS_TIMER_BASE(opaque); + int ch, reg; + uint32_t next_timeout; + uint16_t cnt; + + if (!clock_is_enabled(tmr->pck)) { + qemu_log_mask(LOG_UNIMP, "renesas_timer: Unit %d stopped.\n", + tmr->unit); + return; + } + addr /=3D 2; + if (addr =3D=3D R_CMSTR) { + write_tstr(tmr, val); + } else { + ch =3D addr / 4; + if (addr < 4) { + /* skip CMSTR */ + addr--; + } + reg =3D (2 - (addr % 4)) + 2; + if (reg =3D=3D R_TCR) { + /* bit7 always 1 */ + val |=3D 0x0080; + write_tcr(RENESAS_TIMER_BASE(tmr), ch, val, 0x0043); + } else { + channel_write(RENESAS_TIMER_BASE(tmr), ch, reg, val); + if (tmr->ch[ch].start) { + if (reg =3D=3D R_TCNT) { + cnt =3D tmr->ch[ch].cnt; + } else { + cnt =3D read_tcnt(tmr, ch); + } + if (tmr->ch[ch].cor < cnt) { + next_timeout =3D 0x10000 + tmr->ch[ch].cor - cnt; + } else { + next_timeout =3D tmr->ch[ch].cor - cnt; + } + tmr->ch[ch].next =3D tmr->ch[ch].base + + next_timeout * tmr->ch[ch].clk; + timer_mod(tmr->ch[ch].timer, tmr->ch[ch].next); + } + } + } +} + +static void tmu_write(void *opaque, hwaddr addr, uint64_t val, unsigned si= ze) +{ + RenesasTMUState *tmu =3D RENESAS_TMU(opaque); + RenesasTimerBaseState *tmr =3D RENESAS_TIMER_BASE(tmu); + + int ch, reg; + uint16_t tcr_mask; + + if (tmr->unit !=3D 0 && addr >=3D 32) { + /* UNIT1 channel2 is not exit */ + qemu_log_mask(LOG_UNIMP, "renesas_timer: Register 0x%" + HWADDR_PRIX " not implemented\n", addr); + return; + } + if (!clock_is_enabled(tmr->pck)) { + qemu_log_mask(LOG_UNIMP, "renesas_timer: Unit %d stopped.\n", + tmr->unit); + return; + } + addr /=3D 4; + switch (addr) { + case R_TOCR: + tmu->tocr =3D FIELD_DP8(tmu->tocr, TOCR, TCOE, + FIELD_EX8(val, TOCR, TCOE)); + break; + case R_TSTR: + write_tstr(tmr, val); + break; + case R_TCPR: + qemu_log_mask(LOG_GUEST_ERROR, + "renesas_timer: TCPR is read only.\n"); + break; + default: + ch =3D (addr - 2) / 3; + reg =3D (addr - 2) % 3 + 2; + if (reg =3D=3D R_TCR) { + if (tmr->unit =3D=3D 0) { + tcr_mask =3D (ch < 2) ? 0x013f : 0x03ff; + } else { + tcr_mask =3D 0x0127; + } + write_tcr(tmr, ch, val, tcr_mask); + } else { + channel_write(tmr, ch, reg, val); + if (reg =3D=3D R_TCNT && tmr->ch[ch].start) { + tmr->ch[ch].next =3D tmr->ch[ch].base + + tmr->ch[ch].cnt * tmr->ch[ch].clk; + timer_mod(tmr->ch[ch].timer, tmr->ch[ch].next); + } + } + break; + } +} + +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 const MemoryRegionOps tmu_ops =3D { + .write =3D tmu_write, + .read =3D tmu_read, + .endianness =3D DEVICE_NATIVE_ENDIAN, + .impl =3D { + .min_access_size =3D 2, + .max_access_size =3D 4, + }, +}; + +static void timer_base_realize(RenesasTimerBaseState *tmr, int num_ch) +{ + tmr->num_ch =3D num_ch; +} + +static void cmt_realize(DeviceState *dev, Error **errp) +{ + RenesasCMTState *cmt =3D RENESAS_CMT(dev); + RenesasTimerBaseState *tmr =3D RENESAS_TIMER_BASE(cmt); + int i; + + timer_base_realize(tmr, TIMER_CH_CMT); + + for (i =3D 0; i < TIMER_CH_CMT; i++) { + tmr->ch[i].cor =3D 0xffff; + if (clock_is_enabled(tmr->pck)) { + update_clk(tmr, i); + } + } +} + +static void cmt_init(Object *obj) +{ + SysBusDevice *d =3D SYS_BUS_DEVICE(obj); + RenesasCMTState *cmt =3D RENESAS_CMT(obj); + RenesasTimerBaseState *tmr =3D RENESAS_TIMER_BASE(cmt); + int i; + + tmr->direction =3D countup; + memory_region_init_io(&tmr->memory, obj, &cmt_ops, + tmr, "renesas-cmt", 0x10); + sysbus_init_mmio(d, &tmr->memory); + + for (i =3D 0; i < TIMER_CH_CMT; i++) { + sysbus_init_irq(d, &tmr->ch[i].irq); + } + tmr->pck =3D qdev_init_clock_in(DEVICE(obj), "pck", + tmr_pck_update, tmr, ClockUpdate); +} + +static void tmu_realize(DeviceState *dev, Error **errp) +{ + SysBusDevice *d =3D SYS_BUS_DEVICE(dev); + RenesasTMUState *tmu =3D RENESAS_TMU(dev); + RenesasTimerBaseState *tmr =3D RENESAS_TIMER_BASE(tmu); + int i; + int num_ch; + + /* Unit0 have 3ch, Unit1 have 2ch */ + num_ch =3D TIMER_CH_TMU - tmr->unit; + timer_base_realize(tmr, num_ch); + for (i =3D 0; i < num_ch; i++) { + sysbus_init_irq(d, &tmr->ch[i].irq); + tmr->ch[i].cor =3D tmr->ch[i].cnt =3D 0xffffffff; + if (clock_is_enabled(tmr->pck)) { + update_clk(tmr, i); + } + } +} + +static void tmu_init(Object *obj) +{ + SysBusDevice *d =3D SYS_BUS_DEVICE(obj); + RenesasTimerBaseState *tmr =3D RENESAS_TIMER_BASE(obj); + RenesasTMUState *tmu =3D RENESAS_TMU(obj); + + tmr->direction =3D countdown; + memory_region_init_io(&tmr->memory, obj, &tmu_ops, + tmr, "renesas-tmu", 0x30); + sysbus_init_mmio(d, &tmr->memory); + memory_region_init_alias(&tmu->memory_p4, NULL, "renesas-tmu-p4", + &tmr->memory, 0, 0x30); + sysbus_init_mmio(d, &tmu->memory_p4); + memory_region_init_alias(&tmu->memory_a7, NULL, "renesas-tmu-a7", + &tmr->memory, 0, 0x30); + sysbus_init_mmio(d, &tmu->memory_a7); + tmr->pck =3D qdev_init_clock_in(DEVICE(obj), "pck", + tmr_pck_update, tmr, ClockUpdate); +} + +static const VMStateDescription vmstate_rtimer =3D { + .name =3D "rx-cmt", + .version_id =3D 1, + .minimum_version_id =3D 1, + .fields =3D (VMStateField[]) { + VMSTATE_END_OF_LIST() + } +}; + +static Property renesas_timer_properties[] =3D { + DEFINE_PROP_INT32("unit", RenesasTimerBaseState, unit, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void renesas_timer_base_class_init(ObjectClass *klass, void *data) +{ + RenesasTimerBaseClass *base =3D RENESAS_TIMER_BASE_CLASS(klass); + DeviceClass *dc =3D DEVICE_CLASS(klass); + + dc->vmsd =3D &vmstate_rtimer; + base->update_clk =3D update_clk; + device_class_set_props(dc, renesas_timer_properties); +} + +static void cmt_class_init(ObjectClass *klass, void *data) +{ + RenesasTimerBaseClass *base =3D RENESAS_TIMER_BASE_CLASS(klass); + DeviceClass *dc =3D DEVICE_CLASS(klass); + + base->divrate =3D cmt_div; + base->timer_event =3D cmt_timer_event; + base->delta_to_tcnt =3D cmt_delta_to_cnt; + base->get_next =3D cmt_get_next; + dc->realize =3D cmt_realize; +} + +static void tmu_class_init(ObjectClass *klass, void *data) +{ + RenesasTimerBaseClass *base =3D RENESAS_TIMER_BASE_CLASS(klass); + DeviceClass *dc =3D DEVICE_CLASS(klass); + + base->divrate =3D tmu_div; + base->timer_event =3D tmu_timer_event; + base->delta_to_tcnt =3D tmu_delta_to_cnt; + base->get_next =3D tmu_get_next; + base->update_clk =3D tmu_update_clk; + dc->realize =3D tmu_realize; +} + +static const TypeInfo renesas_timer_info[] =3D { + { + .name =3D TYPE_RENESAS_TIMER_BASE, + .parent =3D TYPE_SYS_BUS_DEVICE, + .instance_size =3D sizeof(RenesasTimerBaseState), + .class_init =3D renesas_timer_base_class_init, + .class_size =3D sizeof(RenesasTimerBaseClass), + .abstract =3D true, + }, + { + .name =3D TYPE_RENESAS_CMT, + .parent =3D TYPE_RENESAS_TIMER_BASE, + .instance_size =3D sizeof(RenesasCMTState), + .instance_init =3D cmt_init, + .class_init =3D cmt_class_init, + .class_size =3D sizeof(RenesasCMTClass), + }, + { + .name =3D TYPE_RENESAS_TMU, + .parent =3D TYPE_RENESAS_TIMER_BASE, + .instance_size =3D sizeof(RenesasTMUState), + .instance_init =3D tmu_init, + .class_init =3D tmu_class_init, + .class_size =3D sizeof(RenesasTMUClass), + }, +}; + +DEFINE_TYPES(renesas_timer_info) diff --git a/hw/timer/Kconfig b/hw/timer/Kconfig index bac2511715..347add12dd 100644 --- a/hw/timer/Kconfig +++ b/hw/timer/Kconfig @@ -54,3 +54,6 @@ config SSE_TIMER =20 config AVR_TIMER16 bool + +config RENESAS_TIMER + bool diff --git a/hw/timer/meson.build b/hw/timer/meson.build index 157f540ecd..9019dce993 100644 --- a/hw/timer/meson.build +++ b/hw/timer/meson.build @@ -33,5 +33,6 @@ softmmu_ss.add(when: 'CONFIG_SSE_COUNTER', if_true: files= ('sse-counter.c')) softmmu_ss.add(when: 'CONFIG_SSE_TIMER', if_true: files('sse-timer.c')) softmmu_ss.add(when: 'CONFIG_STM32F2XX_TIMER', if_true: files('stm32f2xx_t= imer.c')) softmmu_ss.add(when: 'CONFIG_XILINX', if_true: files('xilinx_timer.c')) +softmmu_ss.add(when: 'CONFIG_RENESAS_TIMER', if_true: files('renesas_timer= .c')) =20 specific_ss.add(when: 'CONFIG_AVR_TIMER16', if_true: files('avr_timer16.c'= )) --=20 2.20.1 From nobody Sun May 5 10:23:05 2024 Delivered-To: importer2@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer2=patchew.org@nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1622093204; cv=none; d=zohomail.com; s=zohoarc; b=Zb9fWZoFuEc5fxudRRMrN3XrjaW4enpFPLLQ4HtkFaV48wt1BIIlgJ0i16+Itt12/d3ghDxffgIgh+phTL7CqSBFLLfrbiKw4W48/y5NXnknmlRargXw5LhKg2hMEc+bKm8I8VkF+udczrXB91wPDLr/pKXNy+QPGX+vutECxIM= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1622093204; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=QKSqLwytyIcQzyVQUt1ME2syBNvM9qkrXYK+1DabLqY=; b=MxSCwvRMWdH6k1Et/vAAhfh9G3zNeF5keC3qCU9FZ0S34T8v3eXaBGVs2Khm7xSPfz24Wi5Z0HzER7UcQOVRm4DSR0M5gJfsbVUpRMPJcoeGzQ7cNuEIHyw3cZaTmSfFSzbbEimK3133FIEpuXyaX/5wXd9mE2D3yjok/nF3vos= ARC-Authentication-Results: i=1; mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer2=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 1622093204600464.1324793315598; Wed, 26 May 2021 22:26:44 -0700 (PDT) Received: from localhost ([::1]:47342 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lm8Xb-0008Bi-HH for importer2@patchew.org; Thu, 27 May 2021 01:26:43 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:56898) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lm8Si-0008R7-RU for qemu-devel@nongnu.org; Thu, 27 May 2021 01:21:40 -0400 Received: from mail01.asahi-net.or.jp ([202.224.55.13]:58621) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lm8Sc-00064s-2Z for qemu-devel@nongnu.org; Thu, 27 May 2021 01:21:40 -0400 Received: from sakura.ysato.name (ik1-413-38519.vs.sakura.ne.jp [153.127.30.23]) (Authenticated sender: PQ4Y-STU) by mail01.asahi-net.or.jp (Postfix) with ESMTPA id CAA1B11D396; Thu, 27 May 2021 14:21:30 +0900 (JST) Received: from yo-satoh-debian.localdomain (y245018.dynamic.ppp.asahi-net.or.jp [118.243.245.18]) by sakura.ysato.name (Postfix) with ESMTPSA id 692871C0077; Thu, 27 May 2021 14:21:30 +0900 (JST) From: Yoshinori Sato To: qemu-devel@nongnu.org Subject: [PATCH 04/11] hw/timer: Remove sh_timer. Date: Thu, 27 May 2021 14:21:15 +0900 Message-Id: <20210527052122.97103-5-ysato@users.sourceforge.jp> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20210527052122.97103-1-ysato@users.sourceforge.jp> References: <20210527052122.97103-1-ysato@users.sourceforge.jp> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer2=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: softfail client-ip=202.224.55.13; envelope-from=ysato@users.sourceforge.jp; helo=mail01.asahi-net.or.jp X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_DNSWL_LOW=-0.7, SPF_HELO_NONE=0.001, SPF_SOFTFAIL=0.665 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Yoshinori Sato Errors-To: qemu-devel-bounces+importer2=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" Migrate to renesas_timer. Signed-off-by: Yoshinori Sato --- include/hw/timer/tmu012.h | 23 --- hw/timer/sh_timer.c | 368 -------------------------------------- MAINTAINERS | 4 +- hw/timer/Kconfig | 4 - hw/timer/meson.build | 1 - 5 files changed, 2 insertions(+), 398 deletions(-) delete mode 100644 include/hw/timer/tmu012.h delete mode 100644 hw/timer/sh_timer.c diff --git a/include/hw/timer/tmu012.h b/include/hw/timer/tmu012.h deleted file mode 100644 index 808ed8de1d..0000000000 --- a/include/hw/timer/tmu012.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * SuperH Timer - * - * Copyright (c) 2007 Magnus Damm - * - * This code is licensed under the GPL. - */ - -#ifndef HW_TIMER_TMU012_H -#define HW_TIMER_TMU012_H - -#include "exec/hwaddr.h" - -#define TMU012_FEAT_TOCR (1 << 0) -#define TMU012_FEAT_3CHAN (1 << 1) -#define TMU012_FEAT_EXTCLK (1 << 2) - -void tmu012_init(MemoryRegion *sysmem, hwaddr base, - int feat, uint32_t freq, - qemu_irq ch0_irq, qemu_irq ch1_irq, - qemu_irq ch2_irq0, qemu_irq ch2_irq1); - -#endif diff --git a/hw/timer/sh_timer.c b/hw/timer/sh_timer.c deleted file mode 100644 index 58af1a1edb..0000000000 --- a/hw/timer/sh_timer.c +++ /dev/null @@ -1,368 +0,0 @@ -/* - * SuperH Timer modules. - * - * Copyright (c) 2007 Magnus Damm - * Based on arm_timer.c by Paul Brook - * Copyright (c) 2005-2006 CodeSourcery. - * - * This code is licensed under the GPL. - */ - -#include "qemu/osdep.h" -#include "exec/memory.h" -#include "hw/hw.h" -#include "hw/irq.h" -#include "hw/sh4/sh.h" -#include "hw/timer/tmu012.h" -#include "hw/ptimer.h" - -//#define DEBUG_TIMER - -#define TIMER_TCR_TPSC (7 << 0) -#define TIMER_TCR_CKEG (3 << 3) -#define TIMER_TCR_UNIE (1 << 5) -#define TIMER_TCR_ICPE (3 << 6) -#define TIMER_TCR_UNF (1 << 8) -#define TIMER_TCR_ICPF (1 << 9) -#define TIMER_TCR_RESERVED (0x3f << 10) - -#define TIMER_FEAT_CAPT (1 << 0) -#define TIMER_FEAT_EXTCLK (1 << 1) - -#define OFFSET_TCOR 0 -#define OFFSET_TCNT 1 -#define OFFSET_TCR 2 -#define OFFSET_TCPR 3 - -typedef struct { - ptimer_state *timer; - uint32_t tcnt; - uint32_t tcor; - uint32_t tcr; - uint32_t tcpr; - int freq; - int int_level; - int old_level; - int feat; - int enabled; - qemu_irq irq; -} sh_timer_state; - -/* Check all active timers, and schedule the next timer interrupt. */ - -static void sh_timer_update(sh_timer_state *s) -{ - int new_level =3D s->int_level && (s->tcr & TIMER_TCR_UNIE); - - if (new_level !=3D s->old_level) - qemu_set_irq (s->irq, new_level); - - s->old_level =3D s->int_level; - s->int_level =3D new_level; -} - -static uint32_t sh_timer_read(void *opaque, hwaddr offset) -{ - sh_timer_state *s =3D (sh_timer_state *)opaque; - - switch (offset >> 2) { - case OFFSET_TCOR: - return s->tcor; - case OFFSET_TCNT: - return ptimer_get_count(s->timer); - case OFFSET_TCR: - return s->tcr | (s->int_level ? TIMER_TCR_UNF : 0); - case OFFSET_TCPR: - if (s->feat & TIMER_FEAT_CAPT) - return s->tcpr; - /* fall through */ - default: - hw_error("sh_timer_read: Bad offset %x\n", (int)offset); - return 0; - } -} - -static void sh_timer_write(void *opaque, hwaddr offset, - uint32_t value) -{ - sh_timer_state *s =3D (sh_timer_state *)opaque; - int freq; - - switch (offset >> 2) { - case OFFSET_TCOR: - s->tcor =3D value; - ptimer_transaction_begin(s->timer); - ptimer_set_limit(s->timer, s->tcor, 0); - ptimer_transaction_commit(s->timer); - break; - case OFFSET_TCNT: - s->tcnt =3D value; - ptimer_transaction_begin(s->timer); - ptimer_set_count(s->timer, s->tcnt); - ptimer_transaction_commit(s->timer); - break; - case OFFSET_TCR: - ptimer_transaction_begin(s->timer); - if (s->enabled) { - /* Pause the timer if it is running. This may cause some - inaccuracy dure to rounding, but avoids a whole lot of other - messyness. */ - ptimer_stop(s->timer); - } - freq =3D s->freq; - /* ??? Need to recalculate expiry time after changing divisor. */ - switch (value & TIMER_TCR_TPSC) { - case 0: freq >>=3D 2; break; - case 1: freq >>=3D 4; break; - case 2: freq >>=3D 6; break; - case 3: freq >>=3D 8; break; - case 4: freq >>=3D 10; break; - case 6: - case 7: - if (s->feat & TIMER_FEAT_EXTCLK) { - break; - } - /* fallthrough */ - default: - hw_error("sh_timer_write: Reserved TPSC value\n"); - } - switch ((value & TIMER_TCR_CKEG) >> 3) { - case 0: - break; - case 1: - case 2: - case 3: - if (s->feat & TIMER_FEAT_EXTCLK) { - break; - } - /* fallthrough */ - default: - hw_error("sh_timer_write: Reserved CKEG value\n"); - } - switch ((value & TIMER_TCR_ICPE) >> 6) { - case 0: - break; - case 2: - case 3: - if (s->feat & TIMER_FEAT_CAPT) { - break; - } - /* fallthrough */ - default: - hw_error("sh_timer_write: Reserved ICPE value\n"); - } - if ((value & TIMER_TCR_UNF) =3D=3D 0) { - s->int_level =3D 0; - } - - value &=3D ~TIMER_TCR_UNF; - - if ((value & TIMER_TCR_ICPF) && (!(s->feat & TIMER_FEAT_CAPT))) { - hw_error("sh_timer_write: Reserved ICPF value\n"); - } - - value &=3D ~TIMER_TCR_ICPF; /* capture not supported */ - - if (value & TIMER_TCR_RESERVED) { - hw_error("sh_timer_write: Reserved TCR bits set\n"); - } - s->tcr =3D value; - ptimer_set_limit(s->timer, s->tcor, 0); - ptimer_set_freq(s->timer, freq); - if (s->enabled) { - /* Restart the timer if still enabled. */ - ptimer_run(s->timer, 0); - } - ptimer_transaction_commit(s->timer); - break; - case OFFSET_TCPR: - if (s->feat & TIMER_FEAT_CAPT) { - s->tcpr =3D value; - break; - } - /* fallthrough */ - default: - hw_error("sh_timer_write: Bad offset %x\n", (int)offset); - } - sh_timer_update(s); -} - -static void sh_timer_start_stop(void *opaque, int enable) -{ - sh_timer_state *s =3D (sh_timer_state *)opaque; - -#ifdef DEBUG_TIMER - printf("sh_timer_start_stop %d (%d)\n", enable, s->enabled); -#endif - - ptimer_transaction_begin(s->timer); - if (s->enabled && !enable) { - ptimer_stop(s->timer); - } - if (!s->enabled && enable) { - ptimer_run(s->timer, 0); - } - ptimer_transaction_commit(s->timer); - s->enabled =3D !!enable; - -#ifdef DEBUG_TIMER - printf("sh_timer_start_stop done %d\n", s->enabled); -#endif -} - -static void sh_timer_tick(void *opaque) -{ - sh_timer_state *s =3D (sh_timer_state *)opaque; - s->int_level =3D s->enabled; - sh_timer_update(s); -} - -static void *sh_timer_init(uint32_t freq, int feat, qemu_irq irq) -{ - sh_timer_state *s; - - s =3D (sh_timer_state *)g_malloc0(sizeof(sh_timer_state)); - s->freq =3D freq; - s->feat =3D feat; - s->tcor =3D 0xffffffff; - s->tcnt =3D 0xffffffff; - s->tcpr =3D 0xdeadbeef; - s->tcr =3D 0; - s->enabled =3D 0; - s->irq =3D irq; - - s->timer =3D ptimer_init(sh_timer_tick, s, PTIMER_POLICY_DEFAULT); - - sh_timer_write(s, OFFSET_TCOR >> 2, s->tcor); - sh_timer_write(s, OFFSET_TCNT >> 2, s->tcnt); - sh_timer_write(s, OFFSET_TCPR >> 2, s->tcpr); - sh_timer_write(s, OFFSET_TCR >> 2, s->tcpr); - /* ??? Save/restore. */ - return s; -} - -typedef struct { - MemoryRegion iomem; - MemoryRegion iomem_p4; - MemoryRegion iomem_a7; - void *timer[3]; - int level[3]; - uint32_t tocr; - uint32_t tstr; - int feat; -} tmu012_state; - -static uint64_t tmu012_read(void *opaque, hwaddr offset, - unsigned size) -{ - tmu012_state *s =3D (tmu012_state *)opaque; - -#ifdef DEBUG_TIMER - printf("tmu012_read 0x%lx\n", (unsigned long) offset); -#endif - - if (offset >=3D 0x20) { - if (!(s->feat & TMU012_FEAT_3CHAN)) { - hw_error("tmu012_write: Bad channel offset %x\n", (int)offset); - } - return sh_timer_read(s->timer[2], offset - 0x20); - } - - if (offset >=3D 0x14) - return sh_timer_read(s->timer[1], offset - 0x14); - - if (offset >=3D 0x08) - return sh_timer_read(s->timer[0], offset - 0x08); - - if (offset =3D=3D 4) - return s->tstr; - - if ((s->feat & TMU012_FEAT_TOCR) && offset =3D=3D 0) - return s->tocr; - - hw_error("tmu012_write: Bad offset %x\n", (int)offset); - return 0; -} - -static void tmu012_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - tmu012_state *s =3D (tmu012_state *)opaque; - -#ifdef DEBUG_TIMER - printf("tmu012_write 0x%lx 0x%08x\n", (unsigned long) offset, value); -#endif - - if (offset >=3D 0x20) { - if (!(s->feat & TMU012_FEAT_3CHAN)) { - hw_error("tmu012_write: Bad channel offset %x\n", (int)offset); - } - sh_timer_write(s->timer[2], offset - 0x20, value); - return; - } - - if (offset >=3D 0x14) { - sh_timer_write(s->timer[1], offset - 0x14, value); - return; - } - - if (offset >=3D 0x08) { - sh_timer_write(s->timer[0], offset - 0x08, value); - return; - } - - if (offset =3D=3D 4) { - sh_timer_start_stop(s->timer[0], value & (1 << 0)); - sh_timer_start_stop(s->timer[1], value & (1 << 1)); - if (s->feat & TMU012_FEAT_3CHAN) { - sh_timer_start_stop(s->timer[2], value & (1 << 2)); - } else { - if (value & (1 << 2)) { - hw_error("tmu012_write: Bad channel\n"); - } - } - - s->tstr =3D value; - return; - } - - if ((s->feat & TMU012_FEAT_TOCR) && offset =3D=3D 0) { - s->tocr =3D value & (1 << 0); - } -} - -static const MemoryRegionOps tmu012_ops =3D { - .read =3D tmu012_read, - .write =3D tmu012_write, - .endianness =3D DEVICE_NATIVE_ENDIAN, -}; - -void tmu012_init(MemoryRegion *sysmem, hwaddr base, - int feat, uint32_t freq, - qemu_irq ch0_irq, qemu_irq ch1_irq, - qemu_irq ch2_irq0, qemu_irq ch2_irq1) -{ - tmu012_state *s; - int timer_feat =3D (feat & TMU012_FEAT_EXTCLK) ? TIMER_FEAT_EXTCLK : 0; - - s =3D (tmu012_state *)g_malloc0(sizeof(tmu012_state)); - s->feat =3D feat; - s->timer[0] =3D sh_timer_init(freq, timer_feat, ch0_irq); - s->timer[1] =3D sh_timer_init(freq, timer_feat, ch1_irq); - if (feat & TMU012_FEAT_3CHAN) { - s->timer[2] =3D sh_timer_init(freq, timer_feat | TIMER_FEAT_CAPT, - ch2_irq0); /* ch2_irq1 not supported */ - } - - memory_region_init_io(&s->iomem, NULL, &tmu012_ops, s, - "timer", 0x100000000ULL); - - memory_region_init_alias(&s->iomem_p4, NULL, "timer-p4", - &s->iomem, 0, 0x1000); - memory_region_add_subregion(sysmem, P4ADDR(base), &s->iomem_p4); - - memory_region_init_alias(&s->iomem_a7, NULL, "timer-a7", - &s->iomem, 0, 0x1000); - memory_region_add_subregion(sysmem, A7ADDR(base), &s->iomem_a7); - /* ??? Save/restore. */ -} diff --git a/MAINTAINERS b/MAINTAINERS index ecfa97cefa..4e41c3ff91 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1414,7 +1414,7 @@ F: hw/char/renesas_sci.c F: hw/sh4/r2d.c F: hw/intc/sh_intc.c F: hw/pci-host/sh_pci.c -F: hw/timer/sh_timer.c +F: hw/timer/renesas_timer.c F: include/hw/sh4/sh_intc.h =20 Shix @@ -1425,7 +1425,7 @@ F: hw/block/tc58128.c F: hw/char/reness_sci.c F: hw/sh4/shix.c F: hw/intc/sh_intc.c -F: hw/timer/sh_timer.c +F: hw/timer/renesas_timer.c F: include/hw/sh4/sh_intc.h =20 SPARC Machines diff --git a/hw/timer/Kconfig b/hw/timer/Kconfig index 347add12dd..ec19708a4d 100644 --- a/hw/timer/Kconfig +++ b/hw/timer/Kconfig @@ -36,10 +36,6 @@ config CMSDK_APB_DUALTIMER bool select PTIMER =20 -config SH_TIMER - bool - select PTIMER - config RENESAS_TMR bool =20 diff --git a/hw/timer/meson.build b/hw/timer/meson.build index 9019dce993..ec70821c0b 100644 --- a/hw/timer/meson.build +++ b/hw/timer/meson.build @@ -27,7 +27,6 @@ softmmu_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_= gptimer.c')) softmmu_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_synctimer.c')) softmmu_ss.add(when: 'CONFIG_PXA2XX', if_true: files('pxa2xx_timer.c')) softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_systmr.c')) -softmmu_ss.add(when: 'CONFIG_SH_TIMER', if_true: files('sh_timer.c')) softmmu_ss.add(when: 'CONFIG_SLAVIO', if_true: files('slavio_timer.c')) softmmu_ss.add(when: 'CONFIG_SSE_COUNTER', if_true: files('sse-counter.c')) softmmu_ss.add(when: 'CONFIG_SSE_TIMER', if_true: files('sse-timer.c')) --=20 2.20.1 From nobody Sun May 5 10:23:05 2024 Delivered-To: importer2@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer2=patchew.org@nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1622093047; cv=none; d=zohomail.com; s=zohoarc; b=VqxdrPHaF9b8eqCLS9hcyTe67hQcI67jTyrSraK5YCIj9k2BTK2B5Jeg/29twjZ8V6sHv1C31gMQnu3TJ8wtQOG0di+tbzPIxCoNxg2QsRDIiYnYzgiHYiNNyOh8vE2AboDxWMprtTL4xZO3VT4YhCBUQL+Qo3thO42Q7ref+ZM= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1622093047; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=/smkPRhUmiex54A/+8owH1RKuUTNrSNO/pRviaO01k4=; b=YMJTrHtnApVZV68uhBZXlgMy0BbYW0NgFPccYcGMEQozK9r3fWK0InBczDNyaUSRFjE2Yl1dPdVpB3w33gicrHFQQ/b2ovEkpIuDdUCPbgDV5j2QhsvjcHCNYIgKQWyBHriEl2CUw6dtAavbIuFLcBE0sXLP8YuBBGgYq4+Gwro= ARC-Authentication-Results: i=1; mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer2=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 1622093047300186.3925271634606; Wed, 26 May 2021 22:24:07 -0700 (PDT) Received: from localhost ([::1]:38980 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lm8V4-0002fA-2k for importer2@patchew.org; Thu, 27 May 2021 01:24:06 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:56842) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lm8Sg-0008LU-I9 for qemu-devel@nongnu.org; Thu, 27 May 2021 01:21:38 -0400 Received: from mail01.asahi-net.or.jp ([202.224.55.13]:58622) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lm8Sc-00064v-2b for qemu-devel@nongnu.org; Thu, 27 May 2021 01:21:38 -0400 Received: from sakura.ysato.name (ik1-413-38519.vs.sakura.ne.jp [153.127.30.23]) (Authenticated sender: PQ4Y-STU) by mail01.asahi-net.or.jp (Postfix) with ESMTPA id 2FD3511D398; Thu, 27 May 2021 14:21:31 +0900 (JST) Received: from yo-satoh-debian.localdomain (y245018.dynamic.ppp.asahi-net.or.jp [118.243.245.18]) by sakura.ysato.name (Postfix) with ESMTPSA id C3DEE1C060B; Thu, 27 May 2021 14:21:30 +0900 (JST) From: Yoshinori Sato To: qemu-devel@nongnu.org Subject: [PATCH 05/11] hw/timer: Remove renesas_cmt. Date: Thu, 27 May 2021 14:21:16 +0900 Message-Id: <20210527052122.97103-6-ysato@users.sourceforge.jp> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20210527052122.97103-1-ysato@users.sourceforge.jp> References: <20210527052122.97103-1-ysato@users.sourceforge.jp> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer2=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: softfail client-ip=202.224.55.13; envelope-from=ysato@users.sourceforge.jp; helo=mail01.asahi-net.or.jp X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_DNSWL_LOW=-0.7, SPF_HELO_NONE=0.001, SPF_SOFTFAIL=0.665 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Yoshinori Sato Errors-To: qemu-devel-bounces+importer2=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" Migrate to renesas_timer. Signed-off-by: Yoshinori Sato --- include/hw/timer/renesas_cmt.h | 43 ----- hw/timer/renesas_cmt.c | 283 --------------------------------- hw/timer/meson.build | 1 - 3 files changed, 327 deletions(-) delete mode 100644 include/hw/timer/renesas_cmt.h delete mode 100644 hw/timer/renesas_cmt.c diff --git a/include/hw/timer/renesas_cmt.h b/include/hw/timer/renesas_cmt.h deleted file mode 100644 index 1c0b65c1d5..0000000000 --- a/include/hw/timer/renesas_cmt.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Renesas Compare-match timer Object - * - * Copyright (c) 2019 Yoshinori Sato - * - * SPDX-License-Identifier: GPL-2.0-or-later - */ - -#ifndef HW_TIMER_RENESAS_CMT_H -#define HW_TIMER_RENESAS_CMT_H - -#include "qemu/timer.h" -#include "hw/sysbus.h" -#include "qom/object.h" - -#define TYPE_RENESAS_CMT "renesas-cmt" -typedef struct RCMTState RCMTState; -DECLARE_INSTANCE_CHECKER(RCMTState, RCMT, - TYPE_RENESAS_CMT) - -enum { - CMT_CH =3D 2, - CMT_NR_IRQ =3D 1 * CMT_CH -}; - -struct RCMTState { - /*< private >*/ - SysBusDevice parent_obj; - /*< public >*/ - - uint64_t input_freq; - MemoryRegion memory; - - uint16_t cmstr; - uint16_t cmcr[CMT_CH]; - uint16_t cmcnt[CMT_CH]; - uint16_t cmcor[CMT_CH]; - int64_t tick[CMT_CH]; - qemu_irq cmi[CMT_CH]; - QEMUTimer timer[CMT_CH]; -}; - -#endif diff --git a/hw/timer/renesas_cmt.c b/hw/timer/renesas_cmt.c deleted file mode 100644 index 2e0fd21a36..0000000000 --- a/hw/timer/renesas_cmt.c +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Renesas 16bit Compare-match timer - * - * Datasheet: RX62N Group, RX621 Group User's Manual: Hardware - * (Rev.1.40 R01UH0033EJ0140) - * - * Copyright (c) 2019 Yoshinori Sato - * - * SPDX-License-Identifier: GPL-2.0-or-later - * - * 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/log.h" -#include "hw/irq.h" -#include "hw/registerfields.h" -#include "hw/qdev-properties.h" -#include "hw/timer/renesas_cmt.h" -#include "migration/vmstate.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 that. - */ -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 offset, unsigned size) -{ - 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 0x%" HWADDR_PRIX " " - "not implemented\n", - offset); - return UINT64_MAX; -} - -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 offset, uint64_t val, unsigned = size) -{ - 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 0x%" HWADDR_PR= IX " " - "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, - }, - .valid =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); -} - -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 < ARRAY_SIZE(cmt->cmi); i++) { - sysbus_init_irq(d, &cmt->cmi[i]); - } - timer_init_ns(&cmt->timer[0], QEMU_CLOCK_VIRTUAL, timer_event0, cmt); - timer_init_ns(&cmt->timer[1], 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_UINT16(cmstr, RCMTState), - VMSTATE_UINT16_ARRAY(cmcr, RCMTState, CMT_CH), - VMSTATE_UINT16_ARRAY(cmcnt, RCMTState, CMT_CH), - VMSTATE_UINT16_ARRAY(cmcor, RCMTState, CMT_CH), - VMSTATE_INT64_ARRAY(tick, RCMTState, CMT_CH), - VMSTATE_TIMER_ARRAY(timer, RCMTState, CMT_CH), - 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->vmsd =3D &vmstate_rcmt; - dc->reset =3D rcmt_reset; - device_class_set_props(dc, rcmt_properties); -} - -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/meson.build b/hw/timer/meson.build index ec70821c0b..03b40cfbee 100644 --- a/hw/timer/meson.build +++ b/hw/timer/meson.build @@ -9,7 +9,6 @@ softmmu_ss.add(when: 'CONFIG_CADENCE', if_true: files('cade= nce_ttc.c')) softmmu_ss.add(when: 'CONFIG_CMSDK_APB_DUALTIMER', if_true: files('cmsdk-a= pb-dualtimer.c')) softmmu_ss.add(when: 'CONFIG_CMSDK_APB_TIMER', if_true: files('cmsdk-apb-t= imer.c')) softmmu_ss.add(when: 'CONFIG_RENESAS_TMR', if_true: files('renesas_tmr.c')) -softmmu_ss.add(when: 'CONFIG_RENESAS_CMT', if_true: files('renesas_cmt.c')) softmmu_ss.add(when: 'CONFIG_DIGIC', if_true: files('digic-timer.c')) softmmu_ss.add(when: 'CONFIG_ETRAXFS', if_true: files('etraxfs_timer.c')) softmmu_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210_mct.c')) --=20 2.20.1 From nobody Sun May 5 10:23:05 2024 Delivered-To: importer2@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer2=patchew.org@nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1622093211; cv=none; d=zohomail.com; s=zohoarc; b=IZo0/lSs5kAj+DzTfYPbRzwdF+xBV7VoEe5jIXfxzS3iCX7R9uyPIrxovPEb5DhzVtLvtcvbyk84lU8HLfKNBLRxJKT4rC5dJTqINZeNNUowaILI60Z/WYnIFajr2oaErvXoj7t+QtKPPMKpvFi1tQEmEiP6qm/LnGANzrZ31a4= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1622093211; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=suIdlQlSjlUmZzQkcYqSVyoerRfD1QGmygWjMNgfIok=; b=Ufm3AiMOBhPq6ciNtQGJwgfQzQTY+P7QFQbuUt9TfvOBXjecIv1q/wrimuAs1nqTR9bf6+gmhiYJ3uveaWcA7wkaxIV/F6C7JBn29sFZPauOO/v8iTyg65psuLaXPwGDRPDO/tUtGEMooqCMOB+zOf8bJM9CFN0XS6pLHR9LaTg= ARC-Authentication-Results: i=1; mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer2=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 1622093211324646.4359342816443; Wed, 26 May 2021 22:26:51 -0700 (PDT) Received: from localhost ([::1]:47612 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lm8Xi-0008N7-7s for importer2@patchew.org; Thu, 27 May 2021 01:26:50 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:56856) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lm8Sh-0008MK-7q for qemu-devel@nongnu.org; Thu, 27 May 2021 01:21:39 -0400 Received: from mail02.asahi-net.or.jp ([202.224.55.14]:38758) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lm8Sc-00065U-2W for qemu-devel@nongnu.org; Thu, 27 May 2021 01:21:38 -0400 Received: from sakura.ysato.name (ik1-413-38519.vs.sakura.ne.jp [153.127.30.23]) (Authenticated sender: PQ4Y-STU) by mail02.asahi-net.or.jp (Postfix) with ESMTPA id 8A3423D256; Thu, 27 May 2021 14:21:31 +0900 (JST) Received: from yo-satoh-debian.localdomain (y245018.dynamic.ppp.asahi-net.or.jp [118.243.245.18]) by sakura.ysato.name (Postfix) with ESMTPSA id 258491C0077; Thu, 27 May 2021 14:21:31 +0900 (JST) From: Yoshinori Sato To: qemu-devel@nongnu.org Subject: [PATCH 06/11] hw/rx: Add RX62N Clock generator Date: Thu, 27 May 2021 14:21:17 +0900 Message-Id: <20210527052122.97103-7-ysato@users.sourceforge.jp> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20210527052122.97103-1-ysato@users.sourceforge.jp> References: <20210527052122.97103-1-ysato@users.sourceforge.jp> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer2=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: softfail client-ip=202.224.55.14; envelope-from=ysato@users.sourceforge.jp; helo=mail02.asahi-net.or.jp X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_DNSWL_LOW=-0.7, SPF_HELO_NONE=0.001, SPF_SOFTFAIL=0.665 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Yoshinori Sato Errors-To: qemu-devel-bounces+importer2=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" This module generated core and peripheral clock. Signed-off-by: Yoshinori Sato --- include/hw/rx/rx62n-cpg.h | 72 ++++++++ include/hw/rx/rx62n.h | 8 +- hw/rx/rx62n-cpg.c | 344 ++++++++++++++++++++++++++++++++++++++ hw/rx/rx62n.c | 39 +++-- hw/rx/meson.build | 2 +- 5 files changed, 449 insertions(+), 16 deletions(-) create mode 100644 include/hw/rx/rx62n-cpg.h create mode 100644 hw/rx/rx62n-cpg.c diff --git a/include/hw/rx/rx62n-cpg.h b/include/hw/rx/rx62n-cpg.h new file mode 100644 index 0000000000..d90a067313 --- /dev/null +++ b/include/hw/rx/rx62n-cpg.h @@ -0,0 +1,72 @@ +/* + * RX62N Clock generator circuit + * + * Datasheet: RX62N Group, RX621 Group User's Manual: Hardware + * (Rev.1.40 R01UH0033EJ0140) + * + * Copyright (c) 2020 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 . + */ + +#ifndef HW_RX_RX62N_CPG_H +#define HW_RX_RX62N_CPG_H + +#include "hw/sysbus.h" +#include "hw/qdev-clock.h" + +#define TYPE_RX62N_CPG "rx62n-cpg" +#define RX62NCPG(obj) OBJECT_CHECK(RX62NCPGState, (obj), TYPE_RX62N_CPG) + +enum { + CK_TMR8_1, + CK_TMR8_0, + CK_MTU_1, + CK_MTU_0, + CK_CMT_1, + CK_CMT_0, + CK_EDMAC, + CK_SCI6, + CK_SCI5, + CK_SCI3, + CK_SCI2, + CK_SCI1, + CK_SCI0, + NUM_SUBCLOCK, +}; + +typedef struct RX62NCPGState { + SysBusDevice parent_obj; + uint32_t mstpcr[3]; + uint32_t sckcr; + uint8_t bckcr; + uint8_t ostdcr; + + int ick; + Clock *clk_ick; + int bck; + Clock *clk_bck; + int pck; + Clock *clk_pck; + Clock *dev_clocks[NUM_SUBCLOCK]; + uint32_t xtal_freq_hz; + MemoryRegion memory; +} RX62NCPGState; + +typedef struct RX62NCPGClass { + SysBusDeviceClass parent; +} RX62NCPGClass; + +#define OSTDCR_KEY 0xac + +#endif diff --git a/include/hw/rx/rx62n.h b/include/hw/rx/rx62n.h index 3ed80dba0d..44f5fcc74d 100644 --- a/include/hw/rx/rx62n.h +++ b/include/hw/rx/rx62n.h @@ -29,6 +29,7 @@ #include "hw/timer/renesas_tmr.h" #include "hw/timer/renesas_cmt.h" #include "hw/char/renesas_sci.h" +#include "hw/rx/rx62n-cpg.h" #include "qemu/units.h" #include "qom/object.h" =20 @@ -58,9 +59,9 @@ struct RX62NState { RTMRState tmr[RX62N_NR_TMR]; RCMTState cmt[RX62N_NR_CMT]; RSCIState sci[RX62N_NR_SCI]; + RX62NCPGState cpg; =20 MemoryRegion *sysmem; - bool kernel; =20 MemoryRegion iram; MemoryRegion iomem1; @@ -72,8 +73,7 @@ struct RX62NState { =20 /* Input Clock (XTAL) frequency */ uint32_t xtal_freq_hz; - /* Peripheral Module Clock frequency */ - uint32_t pclk_freq_hz; -}; +} RX62NState; + =20 #endif diff --git a/hw/rx/rx62n-cpg.c b/hw/rx/rx62n-cpg.c new file mode 100644 index 0000000000..9d70004302 --- /dev/null +++ b/hw/rx/rx62n-cpg.c @@ -0,0 +1,344 @@ +/* + * RX62N Clock Generation Circuit + * + * Datasheet: RX62N Group, RX621 Group User's Manual: Hardware + * (Rev.1.40 R01UH0033EJ0140) + * + * Copyright (c) 2020 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 "qapi/error.h" +#include "qemu/log.h" +#include "hw/hw.h" +#include "hw/rx/rx62n-cpg.h" +#include "hw/sysbus.h" +#include "hw/qdev-properties.h" +#include "hw/registerfields.h" +#include "hw/qdev-properties.h" +#include "hw/clock.h" +#include "migration/vmstate.h" + +#define RX62N_XTAL_MIN_HZ (8 * 1000 * 1000) +#define RX62N_XTAL_MAX_HZ (14 * 1000 * 1000) + +REG32(MSTPCRA, 0) +REG32(MSTPCRB, 4) +REG32(MSTPCRC, 8) +REG32(SCKCR, 16) + FIELD(SCKCR, PCK, 8, 3) + FIELD(SCKCR, BCK, 16, 3) + FIELD(SCKCR, PSTOP, 22, 2) + FIELD(SCKCR, ICK, 24, 3) +REG8(BCKCR, 32) + FIELD(BCKCR, BCLKDIV, 0, 1) +REG16(OSTDCR, 48) + FIELD(OSTDCR, OSTDF, 6, 1) + FIELD(OSTDCR, OSTDE, 7, 1) + +static const int access_size[] =3D {4, 4, 1, 2}; + +typedef struct { + const char *name; + int devnum; + int reg; + int offset; + int parentck; +} dev_clock_t; + +enum { + parent_ick, parent_bck, parent_pck, +}; + +static const dev_clock_t dev_clock_list[] =3D { + { .name =3D "pck_tmr8-1", + .devnum =3D CK_TMR8_1, .reg =3D 0, .offset =3D 4, .parentck =3D pare= nt_pck, }, + { .name =3D "pck_tmr8-0", + .devnum =3D CK_TMR8_0, .reg =3D 0, .offset =3D 5, .parentck =3D pare= nt_pck, }, + { .name =3D "pck_mtu-1", + .devnum =3D CK_MTU_1, .reg =3D 0, .offset =3D 8, .parentck =3D paren= t_pck, }, + { .name =3D "pck_mtu-0", + .devnum =3D CK_MTU_0, .reg =3D 0, .offset =3D 9, .parentck =3D paren= t_pck, }, + { .name =3D "pck_cmt-1", + .devnum =3D CK_CMT_1, .reg =3D 0, .offset =3D 14, .parentck =3D pare= nt_pck, }, + { .name =3D "pck_cmt-0", + .devnum =3D CK_CMT_0, .reg =3D 0, .offset =3D 15, .parentck =3D pare= nt_pck, }, + { .name =3D "ick_edmac", + .devnum =3D CK_EDMAC, .reg =3D 1, .offset =3D 15, .parentck =3D pare= nt_ick, }, + { .name =3D "pck_sci-6", + .devnum =3D CK_SCI6, .reg =3D 1, .offset =3D 25, .parentck =3D paren= t_pck, }, + { .name =3D "pck_sci-5", + .devnum =3D CK_SCI5, .reg =3D 1, .offset =3D 26, .parentck =3D paren= t_pck, }, + { .name =3D "pck_sci-3", + .devnum =3D CK_SCI3, .reg =3D 1, .offset =3D 28, .parentck =3D paren= t_pck, }, + { .name =3D "pck_sci-2", + .devnum =3D CK_SCI2, .reg =3D 1, .offset =3D 29, .parentck =3D paren= t_pck, }, + { .name =3D "pck_sci-1", + .devnum =3D CK_SCI1, .reg =3D 1, .offset =3D 30, .parentck =3D paren= t_pck, }, + { .name =3D "pck_sci-0", + .devnum =3D CK_SCI0, .reg =3D 1, .offset =3D 31, .parentck =3D paren= t_pck, }, + { }, +}; + +static void set_clock_in(RX62NCPGState *cpg, const dev_clock_t *ck) +{ + Clock *out; + uint64_t period; + + out =3D qdev_get_clock_out(DEVICE(cpg), ck->name); + g_assert(out); + period =3D 0; + if (extract32(cpg->mstpcr[ck->reg], ck->offset, 1) =3D=3D 0) { + switch (ck->parentck) { + case parent_ick: + period =3D clock_get(cpg->clk_ick); + break; + case parent_pck: + period =3D clock_get(cpg->clk_pck); + break; + } + } + if (clock_get(out) !=3D period) { + clock_update(out, period); + } +} + +#define update_ck(ckname) \ + if (cpg->ckname !=3D ckname) { \ + cpg->ckname =3D ckname; \ + ckname =3D 8 / (1 << ckname); \ + clock_update_hz(cpg->clk_ ## ckname, \ + cpg->xtal_freq_hz * ckname); \ + } + +#define validate_setting(ckname) \ + if (ick > ckname) { \ + qemu_log_mask(LOG_GUEST_ERROR, \ + "rx62n-cpg: Invalid " #ckname " setting." \ + " (ick=3D%d " #ckname "=3D%d)\n", ick, ckname); \ + cpg->ckname =3D ckname =3D ick; \ + } + +static void update_divrate(RX62NCPGState *cpg) +{ + int ick =3D FIELD_EX32(cpg->sckcr, SCKCR, ICK); + int bck =3D FIELD_EX32(cpg->sckcr, SCKCR, BCK); + int pck =3D FIELD_EX32(cpg->sckcr, SCKCR, PCK); + const dev_clock_t *p =3D dev_clock_list; + validate_setting(pck); + validate_setting(bck); + update_ck(ick); + update_ck(bck); + update_ck(pck); + while (p->name) { + set_clock_in(cpg, p); + p++; + } +} + +static const dev_clock_t *find_clock_list(int crno, int bit) +{ + const dev_clock_t *ret =3D dev_clock_list; + while (ret->name) { + if (ret->reg =3D=3D crno && ret->offset =3D=3D bit) { + return ret; + } + ret++; + } + return NULL; +} + +static void update_mstpcr(RX62NCPGState *cpg, int crno, uint32_t diff) +{ + int bit =3D 0; + const dev_clock_t *p; + + while (diff) { + if (diff & 1) { + p =3D find_clock_list(crno, bit); + if (p) { + set_clock_in(cpg, p); + } else { + qemu_log_mask(LOG_UNIMP, "rx62n-cpg: MSTPCR%c " + " bit %d is not implement.\n", 'A' + crno, b= it); + } + } + bit++; + diff >>=3D 1; + } +} + +static uint64_t cpg_read(void *opaque, hwaddr addr, unsigned size) +{ + RX62NCPGState *cpg =3D RX62NCPG(opaque); + + if (access_size[addr >> 4] !=3D size) { + qemu_log_mask(LOG_GUEST_ERROR, "rx62n-cpg: Register 0x%" + HWADDR_PRIX " Invalid access size.\n", addr); + return UINT64_MAX; + } + switch (addr) { + case A_MSTPCRA: + return cpg->mstpcr[0] | 0x473530cf; + case A_MSTPCRB: + return cpg->mstpcr[1] | 0x09407ffe; + case A_MSTPCRC: + return (cpg->mstpcr[2] | 0xffff0000) & 0xffff0003; + case A_SCKCR: + return cpg->sckcr & 0x0fcf0f00; + case A_BCKCR: + return cpg->bckcr & 0x01; + case A_OSTDCR: + /* Main OSC always good */ + return cpg->ostdcr & 0x0080; + default: + qemu_log_mask(LOG_GUEST_ERROR, "rx62n-cpg: Register 0x%" + HWADDR_PRIX " Invalid address.\n", addr); + return UINT64_MAX; + } +} + +static void cpg_write(void *opaque, hwaddr addr, uint64_t val, unsigned si= ze) +{ + RX62NCPGState *cpg =3D RX62NCPG(opaque); + uint32_t old_mstpcr; + int cr_no; + if (access_size[addr >> 4] !=3D size) { + qemu_log_mask(LOG_GUEST_ERROR, "rx62n-cpg: Register 0x%" + HWADDR_PRIX " Invalid access size.\n", addr); + return; + } + switch (addr) { + case A_MSTPCRA: + case A_MSTPCRB: + case A_MSTPCRC: + cr_no =3D (addr & 0x0f) >> 2; + old_mstpcr =3D cpg->mstpcr[cr_no]; + old_mstpcr ^=3D val; + cpg->mstpcr[cr_no] =3D val; + update_mstpcr(cpg, cr_no, old_mstpcr); + break; + case A_SCKCR: + cpg->sckcr =3D val; + update_divrate(cpg); + break; + case A_BCKCR: + cpg->bckcr =3D val; + break; + case A_OSTDCR: + if (extract16(val, 8, 8) =3D=3D OSTDCR_KEY) { + cpg->ostdcr =3D val; + } else { + qemu_log_mask(LOG_GUEST_ERROR, "rx62n-cpg: Register 0x%" + HWADDR_PRIX " Invalid key value.\n", addr); + } + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, "rx62n-cpg: Register 0x%" + HWADDR_PRIX " Invalid address.\n", addr); + } +} + +static const MemoryRegionOps cpg_ops =3D { + .write =3D cpg_write, + .read =3D cpg_read, + .endianness =3D DEVICE_NATIVE_ENDIAN, + .impl =3D { + .min_access_size =3D 1, + .max_access_size =3D 4, + }, +}; + +static const ClockPortInitArray rx62n_cpg_clocks =3D { + QDEV_CLOCK_OUT(RX62NCPGState, clk_ick), + QDEV_CLOCK_OUT(RX62NCPGState, clk_bck), + QDEV_CLOCK_OUT(RX62NCPGState, clk_pck), + QDEV_CLOCK_END +}; + +static void cpg_realize(DeviceState *dev, Error **errp) +{ + RX62NCPGState *cpg =3D RX62NCPG(dev); + const dev_clock_t *p =3D dev_clock_list; + + if (cpg->xtal_freq_hz =3D=3D 0) { + error_setg(errp, "\"xtal-frequency-hz\" property must be provided.= "); + return; + } + /* XTAL range: 8-14 MHz */ + if (cpg->xtal_freq_hz < RX62N_XTAL_MIN_HZ || + cpg->xtal_freq_hz > RX62N_XTAL_MAX_HZ) { + error_setg(errp, "\"xtal-frequency-hz\" property in incorrect rang= e."); + return; + } + + cpg->sckcr =3D FIELD_DP32(cpg->sckcr, SCKCR, ICK, 2); + cpg->sckcr =3D FIELD_DP32(cpg->sckcr, SCKCR, BCK, 2); + cpg->sckcr =3D FIELD_DP32(cpg->sckcr, SCKCR, PCK, 2); + cpg->ostdcr =3D FIELD_DP8(cpg->ostdcr, OSTDCR, OSTDE, 1); + cpg->mstpcr[0] =3D 0x47ffffff; + cpg->mstpcr[1] =3D 0xffffffff; + cpg->mstpcr[2] =3D 0xffff0000; + + /* set initial state */ + while (p->name) { + set_clock_in(cpg, p); + p++; + } + update_divrate(cpg); +} + +static void rx62n_cpg_init(Object *obj) +{ + RX62NCPGState *cpg =3D RX62NCPG(obj); + const dev_clock_t *p =3D dev_clock_list; + qdev_init_clocks(DEVICE(obj), rx62n_cpg_clocks); + /* connect parent clock */ + while (p->name) { + cpg->dev_clocks[p->devnum] =3D qdev_init_clock_out(DEVICE(obj), + p->name); + p++; + } + + memory_region_init_io(&cpg->memory, OBJECT(cpg), &cpg_ops, + cpg, "rx62n-cpg", 0x40); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &cpg->memory); +} + +static Property rx62n_cpg_properties[] =3D { + DEFINE_PROP_UINT32("xtal-frequency-hz", RX62NCPGState, xtal_freq_hz, 0= ), + DEFINE_PROP_END_OF_LIST(), +}; + +static void rx62n_cpg_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(klass); + + dc->realize =3D cpg_realize; + device_class_set_props(dc, rx62n_cpg_properties); +} + +static const TypeInfo rx62n_cpg_info[] =3D { + { + .name =3D TYPE_RX62N_CPG, + .parent =3D TYPE_SYS_BUS_DEVICE, + .instance_size =3D sizeof(RX62NCPGState), + .instance_init =3D rx62n_cpg_init, + .class_init =3D rx62n_cpg_class_init, + .class_size =3D sizeof(RX62NCPGClass), + }, +}; + +DEFINE_TYPES(rx62n_cpg_info) diff --git a/hw/rx/rx62n.c b/hw/rx/rx62n.c index fa5add9f9d..cfd41930bf 100644 --- a/hw/rx/rx62n.c +++ b/hw/rx/rx62n.c @@ -45,6 +45,7 @@ #define RX62N_TMR_BASE 0x00088200 #define RX62N_CMT_BASE 0x00088000 #define RX62N_SCI_BASE 0x00088240 +#define RX62N_CPG_BASE 0x00080010 =20 /* * RX62N Peripheral IRQ @@ -56,7 +57,6 @@ =20 #define RX62N_XTAL_MIN_HZ (8 * 1000 * 1000) #define RX62N_XTAL_MAX_HZ (14 * 1000 * 1000) -#define RX62N_PCLK_MAX_HZ (50 * 1000 * 1000) =20 struct RX62NClass { /*< private >*/ @@ -161,36 +161,45 @@ static void register_tmr(RX62NState *s, int unit) { SysBusDevice *tmr; int i, irqbase; + char ckname[16]; =20 object_initialize_child(OBJECT(s), "tmr[*]", &s->tmr[unit], TYPE_RENESAS_TMR); tmr =3D SYS_BUS_DEVICE(&s->tmr[unit]); - qdev_prop_set_uint64(DEVICE(tmr), "input-freq", s->pclk_freq_hz); - sysbus_realize(tmr, &error_abort); =20 irqbase =3D RX62N_TMR_IRQ + TMR_NR_IRQ * unit; for (i =3D 0; i < TMR_NR_IRQ; i++) { sysbus_connect_irq(tmr, i, s->irq[irqbase + i]); } sysbus_mmio_map(tmr, 0, RX62N_TMR_BASE + unit * 0x10); + + qdev_prop_set_uint32(DEVICE(tmr), "unit", unit); + sysbus_realize(tmr, &error_abort); + snprintf(ckname, sizeof(ckname), "pck_tmr8-%d", unit); + qdev_connect_clock_in(DEVICE(tmr), "pck", + qdev_get_clock_out(DEVICE(&s->cpg), ckname)); } =20 static void register_cmt(RX62NState *s, int unit) { SysBusDevice *cmt; int i, irqbase; + char ckname[16]; =20 object_initialize_child(OBJECT(s), "cmt[*]", &s->cmt[unit], TYPE_RENESAS_CMT); cmt =3D SYS_BUS_DEVICE(&s->cmt[unit]); - qdev_prop_set_uint64(DEVICE(cmt), "input-freq", s->pclk_freq_hz); - sysbus_realize(cmt, &error_abort); + qdev_prop_set_uint32(DEVICE(cmt), "unit", unit); =20 irqbase =3D RX62N_CMT_IRQ + CMT_NR_IRQ * unit; for (i =3D 0; i < CMT_NR_IRQ; i++) { sysbus_connect_irq(cmt, i, s->irq[irqbase + i]); } sysbus_mmio_map(cmt, 0, RX62N_CMT_BASE + unit * 0x10); + sysbus_realize(cmt, &error_abort); + snprintf(ckname, sizeof(ckname), "pck_cmt-%d", unit); + qdev_connect_clock_in(DEVICE(cmt), "pck", + qdev_get_clock_out(DEVICE(&s->cpg), ckname)); } =20 static void register_sci(RX62NState *s, int unit) @@ -202,7 +211,6 @@ static void register_sci(RX62NState *s, int unit) &s->sci[unit], TYPE_RENESAS_SCI); sci =3D SYS_BUS_DEVICE(&s->sci[unit]); qdev_prop_set_chr(DEVICE(sci), "chardev", serial_hd(unit)); - qdev_prop_set_uint64(DEVICE(sci), "input-freq", s->pclk_freq_hz); sysbus_realize(sci, &error_abort); =20 irqbase =3D RX62N_SCI_IRQ + SCI_NR_IRQ * unit; @@ -212,6 +220,18 @@ static void register_sci(RX62NState *s, int unit) sysbus_mmio_map(sci, 0, RX62N_SCI_BASE + unit * 0x08); } =20 +static void register_cpg(RX62NState *s) +{ + SysBusDevice *cpg; + + object_initialize_child(OBJECT(s), "rx62n-cpg", &s->cpg, + TYPE_RX62N_CPG); + cpg =3D SYS_BUS_DEVICE(&s->cpg); + qdev_prop_set_uint64(DEVICE(cpg), "xtal-frequency-hz", s->xtal_freq_hz= ); + + sysbus_mmio_map(cpg, 0, RX62N_CPG_BASE); +} + static void rx62n_realize(DeviceState *dev, Error **errp) { RX62NState *s =3D RX62N_MCU(dev); @@ -227,11 +247,6 @@ static void rx62n_realize(DeviceState *dev, Error **er= rp) error_setg(errp, "\"xtal-frequency-hz\" property in incorrect rang= e."); return; } - /* Use a 4x fixed multiplier */ - s->pclk_freq_hz =3D 4 * s->xtal_freq_hz; - /* PCLK range: 8-50 MHz */ - assert(s->pclk_freq_hz <=3D RX62N_PCLK_MAX_HZ); - memory_region_init_ram(&s->iram, OBJECT(dev), "iram", rxc->ram_size, &error_abort); memory_region_add_subregion(s->sysmem, RX62N_IRAM_BASE, &s->iram); @@ -248,11 +263,13 @@ static void rx62n_realize(DeviceState *dev, Error **e= rrp) =20 register_icu(s); s->cpu.env.ack =3D qdev_get_gpio_in_named(DEVICE(&s->icu), "ack", 0); + register_cpg(s); register_tmr(s, 0); register_tmr(s, 1); register_cmt(s, 0); register_cmt(s, 1); register_sci(s, 0); + sysbus_realize(SYS_BUS_DEVICE(&s->cpg), &error_abort); } =20 static Property rx62n_properties[] =3D { diff --git a/hw/rx/meson.build b/hw/rx/meson.build index d223512a78..e1c5278b6f 100644 --- a/hw/rx/meson.build +++ b/hw/rx/meson.build @@ -1,5 +1,5 @@ rx_ss =3D ss.source_set() rx_ss.add(when: 'CONFIG_RX_GDBSIM', if_true: files('rx-gdbsim.c')) -rx_ss.add(when: 'CONFIG_RX62N_MCU', if_true: files('rx62n.c')) +rx_ss.add(when: 'CONFIG_RX62N_MCU', if_true: files('rx62n.c', 'rx62n-cpg.c= ')) =20 hw_arch +=3D {'rx': rx_ss} --=20 2.20.1 From nobody Sun May 5 10:23:05 2024 Delivered-To: importer2@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer2=patchew.org@nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1622093381; cv=none; d=zohomail.com; s=zohoarc; b=oKgVuFMs4mq/gvqWVTBUGcnKw9xVQcLxp9zrK00RwzmuzaqEAe/NuiYsE7N51hgHsiZhWugDVxqPtZahQPgr4XeTM/kO8Z02nmarr+88NxLxu9DlZNr9HzQcg+Lvw1n/fdDZQjK7xHCOchWZ7F5LkhfU0t0l+2spi9k0gj93NAQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1622093381; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=3GhjZrTIXFRinS+QyX69bhwmJMfvAqyetLv39WVvjok=; b=b0b4AxBiFD0xwLDrh1bD/p82tlP0HLlPJI4ZWAOs6n2wdB7F+Jzk27Rv1MgjjXh4rN1teBiQSP/s21uIWl9ynIWnDNHOMXfUAQP+tGHbdithShy57KUXxSV3ZipxyZy2Phnphx0wvNnFwK57dKHCAtoJ8+QQGMbNTi5VpJRZ0EA= ARC-Authentication-Results: i=1; mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer2=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 1622093381732497.16848664935196; Wed, 26 May 2021 22:29:41 -0700 (PDT) Received: from localhost ([::1]:56352 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lm8aR-0005qV-Oh for importer2@patchew.org; Thu, 27 May 2021 01:29:39 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:56878) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lm8Si-0008OW-3s for qemu-devel@nongnu.org; Thu, 27 May 2021 01:21:40 -0400 Received: from mail03.asahi-net.or.jp ([202.224.55.15]:32933) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lm8Sc-00065u-2L for qemu-devel@nongnu.org; Thu, 27 May 2021 01:21:39 -0400 Received: from sakura.ysato.name (ik1-413-38519.vs.sakura.ne.jp [153.127.30.23]) (Authenticated sender: PQ4Y-STU) by mail03.asahi-net.or.jp (Postfix) with ESMTPA id E568638574; Thu, 27 May 2021 14:21:31 +0900 (JST) Received: from yo-satoh-debian.localdomain (y245018.dynamic.ppp.asahi-net.or.jp [118.243.245.18]) by sakura.ysato.name (Postfix) with ESMTPSA id 7B8AB1C060B; Thu, 27 May 2021 14:21:31 +0900 (JST) From: Yoshinori Sato To: qemu-devel@nongnu.org Subject: [PATCH 07/11] hw/timer: Renesas 8bit timer. Date: Thu, 27 May 2021 14:21:18 +0900 Message-Id: <20210527052122.97103-8-ysato@users.sourceforge.jp> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20210527052122.97103-1-ysato@users.sourceforge.jp> References: <20210527052122.97103-1-ysato@users.sourceforge.jp> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer2=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: softfail client-ip=202.224.55.15; envelope-from=ysato@users.sourceforge.jp; helo=mail03.asahi-net.or.jp X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_DNSWL_LOW=-0.7, SPF_HELO_NONE=0.001, SPF_SOFTFAIL=0.665 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Yoshinori Sato Errors-To: qemu-devel-bounces+importer2=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" Rewrite timer api. Signed-off-by: Yoshinori Sato --- include/hw/timer/renesas_tmr.h | 58 ---- include/hw/timer/renesas_tmr8.h | 67 ++++ hw/timer/renesas_tmr.c | 493 ----------------------------- hw/timer/renesas_tmr8.c | 540 ++++++++++++++++++++++++++++++++ hw/timer/Kconfig | 5 +- hw/timer/meson.build | 2 +- 6 files changed, 609 insertions(+), 556 deletions(-) delete mode 100644 include/hw/timer/renesas_tmr.h create mode 100644 include/hw/timer/renesas_tmr8.h delete mode 100644 hw/timer/renesas_tmr.c create mode 100644 hw/timer/renesas_tmr8.c diff --git a/include/hw/timer/renesas_tmr.h b/include/hw/timer/renesas_tmr.h deleted file mode 100644 index caf7eec0dc..0000000000 --- a/include/hw/timer/renesas_tmr.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Renesas 8bit timer Object - * - * Copyright (c) 2018 Yoshinori Sato - * - * SPDX-License-Identifier: GPL-2.0-or-later - */ - -#ifndef HW_TIMER_RENESAS_TMR_H -#define HW_TIMER_RENESAS_TMR_H - -#include "qemu/timer.h" -#include "hw/sysbus.h" -#include "qom/object.h" - -#define TYPE_RENESAS_TMR "renesas-tmr" -typedef struct RTMRState RTMRState; -DECLARE_INSTANCE_CHECKER(RTMRState, RTMR, - TYPE_RENESAS_TMR) - -enum timer_event { - cmia =3D 0, - cmib =3D 1, - ovi =3D 2, - none =3D 3, - TMR_NR_EVENTS =3D 4 -}; - -enum { - TMR_CH =3D 2, - TMR_NR_IRQ =3D 3 * TMR_CH -}; - -struct RTMRState { - /*< private >*/ - SysBusDevice parent_obj; - /*< public >*/ - - uint64_t input_freq; - MemoryRegion memory; - - int64_t tick; - uint8_t tcnt[TMR_CH]; - uint8_t tcora[TMR_CH]; - uint8_t tcorb[TMR_CH]; - uint8_t tcr[TMR_CH]; - uint8_t tccr[TMR_CH]; - uint8_t tcor[TMR_CH]; - uint8_t tcsr[TMR_CH]; - int64_t div_round[TMR_CH]; - uint8_t next[TMR_CH]; - qemu_irq cmia[TMR_CH]; - qemu_irq cmib[TMR_CH]; - qemu_irq ovi[TMR_CH]; - QEMUTimer timer[TMR_CH]; -}; - -#endif diff --git a/include/hw/timer/renesas_tmr8.h b/include/hw/timer/renesas_tmr= 8.h new file mode 100644 index 0000000000..21e4337b0c --- /dev/null +++ b/include/hw/timer/renesas_tmr8.h @@ -0,0 +1,67 @@ +/* + * Renesas 8bit timer Object + * + * Copyright (c) 2018 Yoshinori Sato + * + * This code is licensed under the GPL version 2 or later. + * + */ + +#ifndef HW_RENESAS_TMR8_H +#define HW_RENESAS_TMR8_H + +#include "hw/sysbus.h" + +#define TYPE_RENESAS_TMR8 "renesas-tmr8" +OBJECT_DECLARE_TYPE(RenesasTMR8State, RenesasTMR8Class, + RENESAS_TMR8) + +enum { + TMR_CH =3D 2, +}; + +enum { + IRQ_CMIA, IRQ_CMIB, IRQ_OVI, + TMR_NR_IRQ, +}; + +enum timer_event { + EVT_NONE, EVT_CMIA, EVT_CMIB, EVT_OVI, EVT_WOVI, + TMR_NR_EVENTS, +}; + +enum cor { + REG_A, REG_B, NR_COR, +}; + +struct RenesasTMR8State; + +struct tmr8_ch { + uint16_t cnt; + uint16_t cor[NR_COR]; + uint8_t tcr; + uint8_t tccr; + uint8_t tcsr; + qemu_irq irq[TMR_NR_IRQ]; + QEMUTimer *timer; + int64_t base; + int64_t next; + int64_t clk; + enum timer_event event; + int id; + struct RenesasTMR8State *tmrp; + bool word; +}; + +typedef struct RenesasTMR8State { + SysBusDevice parent_obj; + + uint32_t unit; + Clock *pck; + uint64_t input_freq; + MemoryRegion memory; + + struct tmr8_ch ch[TMR_CH]; +} RenesasTMR8State; + +#endif diff --git a/hw/timer/renesas_tmr.c b/hw/timer/renesas_tmr.c deleted file mode 100644 index d96002e1ee..0000000000 --- a/hw/timer/renesas_tmr.c +++ /dev/null @@ -1,493 +0,0 @@ -/* - * Renesas 8bit timer - * - * Datasheet: RX62N Group, RX621 Group User's Manual: Hardware - * (Rev.1.40 R01UH0033EJ0140) - * - * Copyright (c) 2019 Yoshinori Sato - * - * SPDX-License-Identifier: GPL-2.0-or-later - * - * 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/log.h" -#include "hw/irq.h" -#include "hw/registerfields.h" -#include "hw/qdev-properties.h" -#include "hw/timer/renesas_tmr.h" -#include "migration/vmstate.h" - -REG8(TCR, 0) - FIELD(TCR, CCLR, 3, 2) - FIELD(TCR, OVIE, 5, 1) - FIELD(TCR, CMIEA, 6, 1) - FIELD(TCR, CMIEB, 7, 1) -REG8(TCSR, 2) - FIELD(TCSR, OSA, 0, 2) - FIELD(TCSR, OSB, 2, 2) - FIELD(TCSR, ADTE, 4, 2) -REG8(TCORA, 4) -REG8(TCORB, 6) -REG8(TCNT, 8) -REG8(TCCR, 10) - FIELD(TCCR, CKS, 0, 3) - FIELD(TCCR, CSS, 3, 2) - FIELD(TCCR, TMRIS, 7, 1) - -#define CSS_EXTERNAL 0x00 -#define CSS_INTERNAL 0x01 -#define CSS_INVALID 0x02 -#define CSS_CASCADING 0x03 -#define CCLR_A 0x01 -#define CCLR_B 0x02 - -static const int clkdiv[] =3D {0, 1, 2, 8, 32, 64, 1024, 8192}; - -static uint8_t concat_reg(uint8_t *reg) -{ - return (reg[0] << 8) | reg[1]; -} - -static void update_events(RTMRState *tmr, int ch) -{ - uint16_t diff[TMR_NR_EVENTS], min; - int64_t next_time; - int i, event; - - if (tmr->tccr[ch] =3D=3D 0) { - return ; - } - if (FIELD_EX8(tmr->tccr[ch], TCCR, CSS) =3D=3D 0) { - /* external clock mode */ - /* event not happened */ - return ; - } - if (FIELD_EX8(tmr->tccr[0], TCCR, CSS) =3D=3D CSS_CASCADING) { - /* cascading mode */ - if (ch =3D=3D 1) { - tmr->next[ch] =3D none; - return ; - } - diff[cmia] =3D concat_reg(tmr->tcora) - concat_reg(tmr->tcnt); - diff[cmib] =3D concat_reg(tmr->tcorb) - concat_reg(tmr->tcnt); - diff[ovi] =3D 0x10000 - concat_reg(tmr->tcnt); - } else { - /* separate mode */ - diff[cmia] =3D tmr->tcora[ch] - tmr->tcnt[ch]; - diff[cmib] =3D tmr->tcorb[ch] - tmr->tcnt[ch]; - diff[ovi] =3D 0x100 - tmr->tcnt[ch]; - } - /* Search for the most recently occurring event. */ - for (event =3D 0, min =3D diff[0], i =3D 1; i < none; i++) { - if (min > diff[i]) { - event =3D i; - min =3D diff[i]; - } - } - tmr->next[ch] =3D event; - next_time =3D diff[event]; - next_time *=3D clkdiv[FIELD_EX8(tmr->tccr[ch], TCCR, CKS)]; - next_time *=3D NANOSECONDS_PER_SECOND; - next_time /=3D tmr->input_freq; - next_time +=3D qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - timer_mod(&tmr->timer[ch], next_time); -} - -static int elapsed_time(RTMRState *tmr, int ch, int64_t delta) -{ - int divrate =3D clkdiv[FIELD_EX8(tmr->tccr[ch], TCCR, CKS)]; - int et; - - tmr->div_round[ch] +=3D delta; - if (divrate > 0) { - et =3D tmr->div_round[ch] / divrate; - tmr->div_round[ch] %=3D divrate; - } else { - /* disble clock. so no update */ - et =3D 0; - } - return et; -} - -static uint16_t read_tcnt(RTMRState *tmr, unsigned size, int ch) -{ - int64_t delta, now =3D qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - int elapsed, ovf =3D 0; - uint16_t tcnt[2]; - uint32_t ret; - - delta =3D (now - tmr->tick) * NANOSECONDS_PER_SECOND / tmr->input_freq; - if (delta > 0) { - tmr->tick =3D now; - - switch (FIELD_EX8(tmr->tccr[1], TCCR, CSS)) { - case CSS_INTERNAL: - /* timer1 count update */ - elapsed =3D elapsed_time(tmr, 1, delta); - if (elapsed >=3D 0x100) { - ovf =3D elapsed >> 8; - } - tcnt[1] =3D tmr->tcnt[1] + (elapsed & 0xff); - break; - case CSS_INVALID: /* guest error to have set this */ - case CSS_EXTERNAL: /* QEMU doesn't implement these */ - case CSS_CASCADING: - tcnt[1] =3D tmr->tcnt[1]; - break; - default: - g_assert_not_reached(); - } - switch (FIELD_EX8(tmr->tccr[0], TCCR, CSS)) { - case CSS_INTERNAL: - elapsed =3D elapsed_time(tmr, 0, delta); - tcnt[0] =3D tmr->tcnt[0] + elapsed; - break; - case CSS_CASCADING: - tcnt[0] =3D tmr->tcnt[0] + ovf; - break; - case CSS_INVALID: /* guest error to have set this */ - case CSS_EXTERNAL: /* QEMU doesn't implement this */ - tcnt[0] =3D tmr->tcnt[0]; - break; - default: - g_assert_not_reached(); - } - } else { - tcnt[0] =3D tmr->tcnt[0]; - tcnt[1] =3D tmr->tcnt[1]; - } - if (size =3D=3D 1) { - return tcnt[ch]; - } else { - ret =3D 0; - ret =3D deposit32(ret, 0, 8, tcnt[1]); - ret =3D deposit32(ret, 8, 8, tcnt[0]); - return ret; - } -} - -static uint8_t read_tccr(uint8_t r) -{ - uint8_t tccr =3D 0; - tccr =3D FIELD_DP8(tccr, TCCR, TMRIS, - FIELD_EX8(r, TCCR, TMRIS)); - tccr =3D FIELD_DP8(tccr, TCCR, CSS, - FIELD_EX8(r, TCCR, CSS)); - tccr =3D FIELD_DP8(tccr, TCCR, CKS, - FIELD_EX8(r, TCCR, CKS)); - return tccr; -} - -static uint64_t tmr_read(void *opaque, hwaddr addr, unsigned size) -{ - RTMRState *tmr =3D opaque; - int ch =3D addr & 1; - uint64_t ret; - - if (size =3D=3D 2 && (ch !=3D 0 || addr =3D=3D A_TCR || addr =3D=3D A_= TCSR)) { - qemu_log_mask(LOG_GUEST_ERROR, "renesas_tmr: Invalid read size 0x%" - HWADDR_PRIX "\n", - addr); - return UINT64_MAX; - } - switch (addr & 0x0e) { - case A_TCR: - ret =3D 0; - ret =3D FIELD_DP8(ret, TCR, CCLR, - FIELD_EX8(tmr->tcr[ch], TCR, CCLR)); - ret =3D FIELD_DP8(ret, TCR, OVIE, - FIELD_EX8(tmr->tcr[ch], TCR, OVIE)); - ret =3D FIELD_DP8(ret, TCR, CMIEA, - FIELD_EX8(tmr->tcr[ch], TCR, CMIEA)); - ret =3D FIELD_DP8(ret, TCR, CMIEB, - FIELD_EX8(tmr->tcr[ch], TCR, CMIEB)); - return ret; - case A_TCSR: - ret =3D 0; - ret =3D FIELD_DP8(ret, TCSR, OSA, - FIELD_EX8(tmr->tcsr[ch], TCSR, OSA)); - ret =3D FIELD_DP8(ret, TCSR, OSB, - FIELD_EX8(tmr->tcsr[ch], TCSR, OSB)); - switch (ch) { - case 0: - ret =3D FIELD_DP8(ret, TCSR, ADTE, - FIELD_EX8(tmr->tcsr[ch], TCSR, ADTE)); - break; - case 1: /* CH1 ADTE unimplement always 1 */ - ret =3D FIELD_DP8(ret, TCSR, ADTE, 1); - break; - } - return ret; - case A_TCORA: - if (size =3D=3D 1) { - return tmr->tcora[ch]; - } else if (ch =3D=3D 0) { - return concat_reg(tmr->tcora); - } - /* fall through */ - case A_TCORB: - if (size =3D=3D 1) { - return tmr->tcorb[ch]; - } else { - return concat_reg(tmr->tcorb); - } - case A_TCNT: - return read_tcnt(tmr, size, ch); - case A_TCCR: - if (size =3D=3D 1) { - return read_tccr(tmr->tccr[ch]); - } else { - return read_tccr(tmr->tccr[0]) << 8 | read_tccr(tmr->tccr[1]); - } - default: - qemu_log_mask(LOG_UNIMP, "renesas_tmr: Register 0x%" HWADDR_PRIX - " not implemented\n", - addr); - break; - } - return UINT64_MAX; -} - -static void tmr_write_count(RTMRState *tmr, int ch, unsigned size, - uint8_t *reg, uint64_t val) -{ - if (size =3D=3D 1) { - reg[ch] =3D val; - update_events(tmr, ch); - } else { - reg[0] =3D extract32(val, 8, 8); - reg[1] =3D extract32(val, 0, 8); - update_events(tmr, 0); - update_events(tmr, 1); - } -} - -static void tmr_write(void *opaque, hwaddr addr, uint64_t val, unsigned si= ze) -{ - RTMRState *tmr =3D opaque; - int ch =3D addr & 1; - - if (size =3D=3D 2 && (ch !=3D 0 || addr =3D=3D A_TCR || addr =3D=3D A_= TCSR)) { - qemu_log_mask(LOG_GUEST_ERROR, - "renesas_tmr: Invalid write size 0x%" HWADDR_PRIX "\= n", - addr); - return; - } - switch (addr & 0x0e) { - case A_TCR: - tmr->tcr[ch] =3D val; - break; - case A_TCSR: - tmr->tcsr[ch] =3D val; - break; - case A_TCORA: - tmr_write_count(tmr, ch, size, tmr->tcora, val); - break; - case A_TCORB: - tmr_write_count(tmr, ch, size, tmr->tcorb, val); - break; - case A_TCNT: - tmr_write_count(tmr, ch, size, tmr->tcnt, val); - break; - case A_TCCR: - tmr_write_count(tmr, ch, size, tmr->tccr, val); - break; - default: - qemu_log_mask(LOG_UNIMP, "renesas_tmr: Register 0x%" HWADDR_PRIX - " not implemented\n", - addr); - break; - } -} - -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, - }, - .valid =3D { - .min_access_size =3D 1, - .max_access_size =3D 2, - }, -}; - -static void timer_events(RTMRState *tmr, int ch); - -static uint16_t issue_event(RTMRState *tmr, int ch, int sz, - uint16_t tcnt, uint16_t tcora, uint16_t tcorb) -{ - uint16_t ret =3D tcnt; - - switch (tmr->next[ch]) { - case none: - break; - case cmia: - if (tcnt >=3D tcora) { - if (FIELD_EX8(tmr->tcr[ch], TCR, CCLR) =3D=3D CCLR_A) { - ret =3D tcnt - tcora; - } - if (FIELD_EX8(tmr->tcr[ch], TCR, CMIEA)) { - qemu_irq_pulse(tmr->cmia[ch]); - } - if (sz =3D=3D 8 && ch =3D=3D 0 && - FIELD_EX8(tmr->tccr[1], TCCR, CSS) =3D=3D CSS_CASCADING) { - tmr->tcnt[1]++; - timer_events(tmr, 1); - } - } - break; - case cmib: - if (tcnt >=3D tcorb) { - if (FIELD_EX8(tmr->tcr[ch], TCR, CCLR) =3D=3D CCLR_B) { - ret =3D tcnt - tcorb; - } - if (FIELD_EX8(tmr->tcr[ch], TCR, CMIEB)) { - qemu_irq_pulse(tmr->cmib[ch]); - } - } - break; - case ovi: - if ((tcnt >=3D (1 << sz)) && FIELD_EX8(tmr->tcr[ch], TCR, OVIE)) { - qemu_irq_pulse(tmr->ovi[ch]); - } - break; - default: - g_assert_not_reached(); - } - return ret; -} - -static void timer_events(RTMRState *tmr, int ch) -{ - uint16_t tcnt; - - tmr->tcnt[ch] =3D read_tcnt(tmr, 1, ch); - if (FIELD_EX8(tmr->tccr[0], TCCR, CSS) !=3D CSS_CASCADING) { - tmr->tcnt[ch] =3D issue_event(tmr, ch, 8, - tmr->tcnt[ch], - tmr->tcora[ch], - tmr->tcorb[ch]) & 0xff; - } else { - if (ch =3D=3D 1) { - return ; - } - tcnt =3D issue_event(tmr, ch, 16, - concat_reg(tmr->tcnt), - concat_reg(tmr->tcora), - concat_reg(tmr->tcorb)); - 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->tcr[0] =3D tmr->tcr[1] =3D 0x00; - tmr->tcsr[0] =3D 0x00; - tmr->tcsr[1] =3D 0x10; - tmr->tcnt[0] =3D tmr->tcnt[1] =3D 0x00; - tmr->tcora[0] =3D tmr->tcora[1] =3D 0xff; - tmr->tcorb[0] =3D tmr->tcorb[1] =3D 0xff; - tmr->tccr[0] =3D tmr->tccr[1] =3D 0x00; - tmr->next[0] =3D tmr->next[1] =3D none; - 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, "renesas-tmr", 0x10); - sysbus_init_mmio(d, &tmr->memory); - - for (i =3D 0; i < ARRAY_SIZE(tmr->ovi); i++) { - sysbus_init_irq(d, &tmr->cmia[i]); - sysbus_init_irq(d, &tmr->cmib[i]); - sysbus_init_irq(d, &tmr->ovi[i]); - } - timer_init_ns(&tmr->timer[0], QEMU_CLOCK_VIRTUAL, timer_event0, tmr); - timer_init_ns(&tmr->timer[1], QEMU_CLOCK_VIRTUAL, timer_event1, tmr); -} - -static const VMStateDescription vmstate_rtmr =3D { - .name =3D "rx-tmr", - .version_id =3D 1, - .minimum_version_id =3D 1, - .fields =3D (VMStateField[]) { - VMSTATE_INT64(tick, RTMRState), - VMSTATE_UINT8_ARRAY(tcnt, RTMRState, TMR_CH), - VMSTATE_UINT8_ARRAY(tcora, RTMRState, TMR_CH), - VMSTATE_UINT8_ARRAY(tcorb, RTMRState, TMR_CH), - VMSTATE_UINT8_ARRAY(tcr, RTMRState, TMR_CH), - VMSTATE_UINT8_ARRAY(tccr, RTMRState, TMR_CH), - VMSTATE_UINT8_ARRAY(tcor, RTMRState, TMR_CH), - VMSTATE_UINT8_ARRAY(tcsr, RTMRState, TMR_CH), - VMSTATE_INT64_ARRAY(div_round, RTMRState, TMR_CH), - VMSTATE_UINT8_ARRAY(next, RTMRState, TMR_CH), - VMSTATE_TIMER_ARRAY(timer, RTMRState, TMR_CH), - 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->vmsd =3D &vmstate_rtmr; - dc->reset =3D rtmr_reset; - device_class_set_props(dc, rtmr_properties); -} - -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/hw/timer/renesas_tmr8.c b/hw/timer/renesas_tmr8.c new file mode 100644 index 0000000000..ba1d2faa07 --- /dev/null +++ b/hw/timer/renesas_tmr8.c @@ -0,0 +1,540 @@ +/* + * Renesas 8bit timer + * + * Datasheet: RX62N Group, RX621 Group User's Manual: Hardware + * (Rev.1.40 R01UH0033EJ0140) + * + * Copyright (c) 2020 Yoshinori Sato + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * 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/log.h" +#include "qapi/error.h" +#include "qemu/timer.h" +#include "qemu/bitops.h" +#include "hw/hw.h" +#include "hw/irq.h" +#include "hw/sysbus.h" +#include "hw/registerfields.h" +#include "hw/qdev-properties.h" +#include "hw/qdev-clock.h" +#include "hw/timer/renesas_tmr8.h" +#include "migration/vmstate.h" +#include "qemu/error-report.h" + +REG8(TCR, 0) + FIELD(TCR, CCLR, 3, 2) + FIELD(TCR, OVIE, 5, 1) + FIELD(TCR, CMIEA, 6, 1) + FIELD(TCR, CMIEB, 7, 1) + FIELD(TCR, CMIE, 6, 2) + FIELD(TCR, ALLIE, 5, 3) +REG8(TCSR, 2) + FIELD(TCSR, OSA, 0, 2) + FIELD(TCSR, OSB, 2, 2) + FIELD(TCSR, ADTE, 4, 1) +REG8(TCORA, 4) +REG8(TCORB, 6) +REG8(TCNT, 8) +REG8(TCCR, 10) + FIELD(TCCR, CKS, 0, 3) + FIELD(TCCR, CSS, 3, 2) + FIELD(TCCR, TMRIS, 7, 1) + +#define CLK_EVT -1 + +enum CSS { + CSS_EXT =3D 0, /* extarnal clock */ + CSS_INT =3D 1, /* internal clock */ + CSS_UND =3D 2, /* undefined */ + CSS_EVT =3D 3, /* event count */ +}; + +static void update_clk(RenesasTMR8State *tmr, int ch) +{ + int64_t t; + static const int divlist[] =3D {1, 2, 8, 32, 64, 1024, 8192, 0}; + switch (FIELD_EX8(tmr->ch[ch].tccr, TCCR, CSS)) { + case CSS_EXT: + qemu_log_mask(LOG_UNIMP, + "renesas_tmr8: External clock not implemented.\n"); + tmr->ch[ch].clk =3D 0; + break; + case CSS_INT: + t =3D divlist[FIELD_EX8(tmr->ch[ch].tccr, TCCR, CKS)]; + if (t > 0 && clock_is_enabled(tmr->pck)) { + t =3D tmr->input_freq / t; + tmr->ch[ch].clk =3D NANOSECONDS_PER_SECOND / t; + } else { + tmr->ch[ch].clk =3D 0; + } + break; + case CSS_UND: + qemu_log_mask(LOG_UNIMP, + "renesas_8timer: CSS undefined."); + tmr->ch[ch].clk =3D 0; + break; + case CSS_EVT: + tmr->ch[ch].clk =3D CLK_EVT; + break; + } +} + +static uint16_t catreg(uint8_t hi, uint8_t lo) +{ + uint16_t ret =3D 0; + ret =3D deposit32(ret, 8, 8, hi); + ret =3D deposit32(ret, 0, 8, lo); + return ret; +} + +static bool is_clr_count(uint8_t tcr, enum timer_event event) +{ + switch (event) { + case EVT_CMIA: + case EVT_CMIB: + return FIELD_EX8(tcr, TCR, CCLR) =3D=3D event; + case EVT_OVI: + return true; + default: + g_assert_not_reached(); + } +} + +static bool is_irq_enabled(uint8_t tcr, enum timer_event event) +{ + switch (event) { + case EVT_CMIA: + return FIELD_EX8(tcr, TCR, CMIEA); + case EVT_CMIB: + return FIELD_EX8(tcr, TCR, CMIEB); + case EVT_OVI: + return FIELD_EX8(tcr, TCR, OVIE); + default: + g_assert_not_reached(); + } +} + +static bool event_enabled(uint8_t tcr, enum timer_event event) +{ + return is_clr_count(tcr, event) || is_irq_enabled(tcr, event); +} + +static int event_cor(struct tmr8_ch *ch, enum timer_event event) +{ + switch (event) { + case EVT_CMIA: + return ch->cor[REG_A]; + case EVT_CMIB: + return ch->cor[REG_B]; + default: + return 0xff; + } +} + +static bool is_word_mode(RenesasTMR8State *tmr) +{ + /* + * If the following conditions are met, it is treated as a 16-bit coun= ter. + * ch0 - free running and no compare match event + * ch1 - free running no event + */ + return tmr->ch[0].clk =3D=3D CLK_EVT && + tmr->ch[1].clk > 0 && + FIELD_EX8(tmr->ch[0].tcr, TCR, CCLR) =3D=3D 0 && + FIELD_EX8(tmr->ch[0].tcr, TCR, CMIE) =3D=3D 0 && + FIELD_EX8(tmr->ch[0].tccr, TCCR, CSS) =3D=3D CSS_EVT && + FIELD_EX8(tmr->ch[1].tcr, TCR, CCLR) =3D=3D 0 && + FIELD_EX8(tmr->ch[1].tcr, TCR, ALLIE) =3D=3D 0; +} + +static void set_next_event(RenesasTMR8State *tmr, int ch) +{ + int64_t next =3D 0; + enum timer_event evt; + int cor; + int min; + if (ch =3D=3D 1 && is_word_mode(tmr)) { + /* 16bit count mode */ + next =3D 0x10000 - catreg(tmr->ch[0].cnt, tmr->ch[1].cnt); + next *=3D tmr->ch[1].clk; + tmr->ch[0].event =3D tmr->ch[1].event =3D EVT_WOVI; + } else if (tmr->ch[ch].clk > 0) { + /* Find the next event. */ + min =3D 0x100 + 1; + for (evt =3D EVT_CMIA; evt < EVT_WOVI; evt++) { + cor =3D event_cor(&tmr->ch[ch], evt); + /* event happen in next count up */ + cor++; + if (tmr->ch[ch].cnt < cor && min > cor && + event_enabled(tmr->ch[ch].tcr, evt)) { + min =3D cor; + next =3D cor - tmr->ch[ch].cnt; + next *=3D tmr->ch[ch].clk; + tmr->ch[ch].event =3D evt; + } + } + } + if (next > 0) { + tmr->ch[ch].base =3D tmr->ch[ch].next; + tmr->ch[ch].next +=3D next; + printf("%s %ld\n", __func__, next); + timer_mod(tmr->ch[ch].timer, tmr->ch[ch].next); + } else { + timer_del(tmr->ch[ch].timer); + } +} + +static void sent_irq(struct tmr8_ch *ch, enum timer_event evt) +{ + if (is_irq_enabled(ch->tcr, evt)) { + qemu_irq_pulse(ch->irq[evt - 1]); + } +} + +static void event_countup(struct tmr8_ch *ch) +{ + enum timer_event evt; + int cor; + + ch->cnt++; + for (evt =3D EVT_CMIA; evt < EVT_WOVI; evt++) { + cor =3D event_cor(ch, evt) + 1; + if (ch->cnt =3D=3D cor) { + if (is_clr_count(ch->tcr, evt)) { + ch->cnt =3D 0; + } + sent_irq(ch, evt); + } + } +} + +static void timer_event(void *opaque) +{ + struct tmr8_ch *ch =3D opaque; + RenesasTMR8State *tmr =3D ch->tmrp; + + switch (ch->event) { + case EVT_CMIA: + if (ch->id =3D=3D 0 && tmr->ch[1].clk =3D=3D CLK_EVT) { + /* CH1 event count */ + event_countup(&tmr->ch[1]); + } + /* Falls through. */ + case EVT_CMIB: + if (FIELD_EX8(ch->tcr, TCR, CCLR) =3D=3D ch->event) { + ch->cnt =3D 0; + } else { + /* update current value */ + ch->cnt =3D ch->cor[ch->event] + 1; + } + sent_irq(ch, ch->event); + break; + case EVT_OVI: + ch->cnt =3D 0; + sent_irq(ch, EVT_OVI); + if (ch->id =3D=3D 1 && tmr->ch[0].clk =3D=3D CLK_EVT) { + /* CH0 event count */ + event_countup(&tmr->ch[0]); + } + break; + case EVT_WOVI: + tmr->ch[0].cnt =3D tmr->ch[1].cnt =3D 0; + sent_irq(ch, EVT_OVI); + break; + default: + g_assert_not_reached(); + } + set_next_event(tmr, ch->id); +} + +static uint16_t read_tcnt(RenesasTMR8State *tmr, unsigned int size, int ch) +{ + int64_t now =3D qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + int64_t delta; + uint8_t ret[2]; + int i; + + switch (size) { + case 1: + if (tmr->ch[ch].clk > 0) { + delta =3D now - tmr->ch[ch].base; + delta /=3D tmr->ch[ch].clk; + } else { + delta =3D 0; + } + return tmr->ch[ch].cnt + delta; + case 2: + if (is_word_mode(tmr)) { + /* 16bit count mode */ + delta =3D now - tmr->ch[1].base; + delta /=3D tmr->ch[1].clk; + return catreg(tmr->ch[0].cnt, tmr->ch[1].cnt) + delta; + } else { + for (i =3D 0; i < TMR_CH; i++) { + if (tmr->ch[i].clk > 0) { + delta =3D now - tmr->ch[i].base; + delta /=3D tmr->ch[i].clk; + } else { + delta =3D 0; + } + ret[i] =3D tmr->ch[i].cnt + delta; + } + return catreg(ret[0], ret[1]); + } + default: + g_assert_not_reached(); + } +} + +static void tmr_pck_update(void *opaque, ClockEvent evt) +{ + RenesasTMR8State *tmr =3D RENESAS_TMR8(opaque); + int i; + uint16_t tcnt =3D read_tcnt(tmr, 2, 0); + + tmr->ch[0].cnt =3D extract16(tcnt, 8, 8); + tmr->ch[1].cnt =3D extract16(tcnt, 0, 8); + + tmr->input_freq =3D clock_get_hz(tmr->pck); + for (i =3D 0; i < TMR_CH; i++) { + if (clock_is_enabled(tmr->pck)) { + update_clk(tmr, i); + set_next_event(tmr, i); + } else { + if (tmr->ch[i].timer) { + timer_del(tmr->ch[i].timer); + } + } + } +} + +static int validate_access(hwaddr addr, unsigned int size) +{ + /* Byte access always OK */ + if (size =3D=3D 1) { + return 1; + } + /* word access allowed TCNT / TCOR / TCCR */ + return ((addr & 1) =3D=3D 0 && addr >=3D A_TCORA); +} + +static uint64_t tmr8_read(void *opaque, hwaddr addr, unsigned int size) +{ + RenesasTMR8State *tmr =3D RENESAS_TMR8(opaque); + int ch =3D addr & 1; + int cor; + + if (!validate_access(addr, size)) { + qemu_log_mask(LOG_GUEST_ERROR, "renesas_tmr8: Invalid read size 0x= %" + HWADDR_PRIX "\n", addr); + return UINT64_MAX; + } + if (!clock_is_enabled(tmr->pck)) { + qemu_log_mask(LOG_GUEST_ERROR, "renesas_tmr8: Unit %d is stopped.\= n", + tmr->unit); + return UINT64_MAX; + } + switch (addr & ~1) { + case A_TCR: + return tmr->ch[ch].tcr; + case A_TCSR: + return tmr->ch[ch].tcsr; + case A_TCORA: + case A_TCORB: + cor =3D extract32(addr, 1, 1); + if (size =3D=3D 1) { + /* 8bit read - single register */ + return tmr->ch[ch].cor[cor]; + } else { + /* 16bit read - high byte ch0 reg, low byte ch1 reg */ + return catreg(tmr->ch[0].cor[cor], tmr->ch[1].cor[cor]); + } + case A_TCNT: + return read_tcnt(tmr, size, ch); + case A_TCCR: + if (size =3D=3D 1) { + return tmr->ch[ch].tccr; + } else { + return catreg(tmr->ch[0].tccr, tmr->ch[1].tccr); + } + default: + qemu_log_mask(LOG_UNIMP, "renesas_tmr8: Register 0x%" HWADDR_PRIX + " not implemented\n", addr); + break; + } + return UINT64_MAX; +} + +static void tmr8_write(void *opaque, hwaddr addr, uint64_t val, unsigned s= ize) +{ + RenesasTMR8State *tmr =3D RENESAS_TMR8(opaque); + int ch =3D addr & 1; + int cor; + int64_t now; + + if (!validate_access(addr, size)) { + qemu_log_mask(LOG_GUEST_ERROR, + "renesas_tmr: Invalid write size 0x%" HWADDR_PRIX + "\n", addr); + return; + } + if (!clock_is_enabled(tmr->pck)) { + qemu_log_mask(LOG_GUEST_ERROR, "renesas_tmr8: Unit %d is stopped.\= n", + tmr->unit); + return; + } + switch (addr & ~1) { + case A_TCR: + tmr->ch[ch].tcr =3D val; + break; + case A_TCSR: + if (ch =3D=3D 1) { + /* CH1 ADTR always 1 */ + val =3D FIELD_DP8(val, TCSR, ADTE, 1); + } + tmr->ch[ch].tcsr =3D val; + break; + case A_TCORA: + case A_TCORB: + cor =3D extract32(addr, 1, 1); + if (size =3D=3D 1) { + tmr->ch[ch].cor[cor] =3D val; + } else { + tmr->ch[0].cor[cor] =3D extract32(val, 0, 8); + tmr->ch[1].cor[cor] =3D extract32(val, 8, 8); + } + break; + case A_TCNT: + now =3D qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + if (size =3D=3D 1) { + tmr->ch[ch].base =3D now; + tmr->ch[ch].cnt =3D val; + } else { + tmr->ch[0].base =3D tmr->ch[1].base =3D now; + tmr->ch[0].cnt =3D extract32(val, 0, 8); + tmr->ch[1].cnt =3D extract32(val, 8, 8); + } + break; + case A_TCCR: + val &=3D ~0x6060; + if (size =3D=3D 1) { + tmr->ch[ch].tccr =3D val; + update_clk(tmr, ch); + } else { + tmr->ch[0].tccr =3D extract32(val, 0, 8); + tmr->ch[1].tccr =3D extract32(val, 8, 8); + update_clk(tmr, 0); + update_clk(tmr, 1); + } + break; + default: + qemu_log_mask(LOG_UNIMP, "renesas_tmr: Register 0x%" HWADDR_PRIX + " not implemented\n", addr); + return; + } + if (size =3D=3D 1) { + set_next_event(tmr, ch); + } else { + set_next_event(tmr, 0); + set_next_event(tmr, 1); + } +} + +static const MemoryRegionOps tmr_ops =3D { + .write =3D tmr8_write, + .read =3D tmr8_read, + .endianness =3D DEVICE_LITTLE_ENDIAN, + .impl =3D { + .min_access_size =3D 1, + .max_access_size =3D 2, + }, +}; + +static void tmr8_realize(DeviceState *dev, Error **errp) +{ + RenesasTMR8State *tmr =3D RENESAS_TMR8(dev); + int i; + + for (i =3D 0; i < TMR_CH; i++) { + tmr->ch[i].id =3D i; + tmr->ch[i].timer =3D timer_new_ns(QEMU_CLOCK_VIRTUAL, + timer_event, &tmr->ch[i]); + tmr->ch[i].tmrp =3D tmr; + tmr->ch[i].tcr =3D 0x00; + tmr->ch[i].tcsr =3D (i =3D=3D 0) ? 0x00 : 0x10; + tmr->ch[i].cnt =3D 0x00; + tmr->ch[i].cor[0] =3D 0xff; + tmr->ch[i].cor[1] =3D 0xff; + tmr->ch[i].tccr =3D 0x00; + } +} + +static void tmr8_init(Object *obj) +{ + RenesasTMR8State *tmr =3D RENESAS_TMR8(obj); + SysBusDevice *d =3D SYS_BUS_DEVICE(obj); + int i; + + memory_region_init_io(&tmr->memory, obj, &tmr_ops, + tmr, "renesas-tmr8", 0x10); + sysbus_init_mmio(d, &tmr->memory); + + for (i =3D 0; i < TMR_CH; i++) { + sysbus_init_irq(d, &tmr->ch[i].irq[IRQ_CMIA]); + sysbus_init_irq(d, &tmr->ch[i].irq[IRQ_CMIB]); + sysbus_init_irq(d, &tmr->ch[i].irq[IRQ_OVI]); + } + tmr->pck =3D qdev_init_clock_in(DEVICE(d), "pck", + tmr_pck_update, tmr, ClockUpdate); +} + +static const VMStateDescription vmstate_rtmr =3D { + .name =3D "renesas-8tmr", + .version_id =3D 1, + .minimum_version_id =3D 1, + .fields =3D (VMStateField[]) { + VMSTATE_END_OF_LIST() + } +}; + +static Property tmr8_properties[] =3D { + DEFINE_PROP_UINT32("unit", RenesasTMR8State, unit, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void tmr8_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(klass); + + dc->vmsd =3D &vmstate_rtmr; + dc->realize =3D tmr8_realize; + device_class_set_props(dc, tmr8_properties); +} + +static const TypeInfo tmr8_info[] =3D { + { + .name =3D TYPE_RENESAS_TMR8, + .parent =3D TYPE_SYS_BUS_DEVICE, + .instance_size =3D sizeof(RenesasTMR8State), + .instance_init =3D tmr8_init, + .class_init =3D tmr8_class_init, + } +}; + +DEFINE_TYPES(tmr8_info) diff --git a/hw/timer/Kconfig b/hw/timer/Kconfig index ec19708a4d..6aee6f8a13 100644 --- a/hw/timer/Kconfig +++ b/hw/timer/Kconfig @@ -36,10 +36,7 @@ config CMSDK_APB_DUALTIMER bool select PTIMER =20 -config RENESAS_TMR - bool - -config RENESAS_CMT +config RENESAS_TMR8 bool =20 config SSE_COUNTER diff --git a/hw/timer/meson.build b/hw/timer/meson.build index 03b40cfbee..0b4e8850ed 100644 --- a/hw/timer/meson.build +++ b/hw/timer/meson.build @@ -8,7 +8,7 @@ softmmu_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('a= speed_timer.c')) softmmu_ss.add(when: 'CONFIG_CADENCE', if_true: files('cadence_ttc.c')) softmmu_ss.add(when: 'CONFIG_CMSDK_APB_DUALTIMER', if_true: files('cmsdk-a= pb-dualtimer.c')) softmmu_ss.add(when: 'CONFIG_CMSDK_APB_TIMER', if_true: files('cmsdk-apb-t= imer.c')) -softmmu_ss.add(when: 'CONFIG_RENESAS_TMR', if_true: files('renesas_tmr.c')) +softmmu_ss.add(when: 'CONFIG_RENESAS_TMR8', if_true: files('renesas_tmr8.c= ')) softmmu_ss.add(when: 'CONFIG_DIGIC', if_true: files('digic-timer.c')) softmmu_ss.add(when: 'CONFIG_ETRAXFS', if_true: files('etraxfs_timer.c')) softmmu_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210_mct.c')) --=20 2.20.1 From nobody Sun May 5 10:23:05 2024 Delivered-To: importer2@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer2=patchew.org@nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1622093210; cv=none; d=zohomail.com; s=zohoarc; b=O9ykTCtHH7OrOQx/p4YFVp97VmgRxGvl/xTHhmM7HgjC6HhFGRRQt1uqbcTUHxl/uzYANYj3bhlVofzyCnWlO+caHBMKv9sxIWGDwybdNXH2IuXnxeY43LFH1Q3t0hQBOK6e3xZxcPgUa8t4dD0dXoHQ2/shuYYKMmSlb+7edbI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1622093210; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=j1Mir4Hr9Hv5wTgwOHetkWDylgxn7ZV3ES6pY5AXAYo=; b=N61XVBIcWwA4WR37q3nZDVDwMIt0m2wtZRxX2wm0fDM/n16kCxFg/BR9FbwQ6KOPT2iW9F664UCWULRSEytvqQHTpfhE48UpdzRBUv2r3XtKC8anuKm+Qb4hgJLdA81LPUOzoEujpCrrqNicfcqCGttELWtZq1eIjKCRwsS78n0= ARC-Authentication-Results: i=1; mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer2=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 1622093210818652.1385102715681; Wed, 26 May 2021 22:26:50 -0700 (PDT) Received: from localhost ([::1]:47640 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lm8Xh-0008Px-Pb for importer2@patchew.org; Thu, 27 May 2021 01:26:49 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:56888) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lm8Si-0008P3-83 for qemu-devel@nongnu.org; Thu, 27 May 2021 01:21:40 -0400 Received: from mail03.asahi-net.or.jp ([202.224.55.15]:32938) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lm8Sc-00066C-97 for qemu-devel@nongnu.org; Thu, 27 May 2021 01:21:39 -0400 Received: from sakura.ysato.name (ik1-413-38519.vs.sakura.ne.jp [153.127.30.23]) (Authenticated sender: PQ4Y-STU) by mail03.asahi-net.or.jp (Postfix) with ESMTPA id 41FEC385BB; Thu, 27 May 2021 14:21:32 +0900 (JST) Received: from yo-satoh-debian.localdomain (y245018.dynamic.ppp.asahi-net.or.jp [118.243.245.18]) by sakura.ysato.name (Postfix) with ESMTPSA id D82651C0077; Thu, 27 May 2021 14:21:31 +0900 (JST) From: Yoshinori Sato To: qemu-devel@nongnu.org Subject: [PATCH 08/11] hw/rx: rx62n use new hw modules. Date: Thu, 27 May 2021 14:21:19 +0900 Message-Id: <20210527052122.97103-9-ysato@users.sourceforge.jp> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20210527052122.97103-1-ysato@users.sourceforge.jp> References: <20210527052122.97103-1-ysato@users.sourceforge.jp> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer2=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: softfail client-ip=202.224.55.15; envelope-from=ysato@users.sourceforge.jp; helo=mail03.asahi-net.or.jp X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_DNSWL_LOW=-0.7, SPF_HELO_NONE=0.001, SPF_SOFTFAIL=0.665 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Yoshinori Sato Errors-To: qemu-devel-bounces+importer2=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" Signed-off-by: Yoshinori Sato --- include/hw/rx/rx62n.h | 10 +++++----- hw/rx/rx62n.c | 18 ++++++++++++------ hw/rx/Kconfig | 4 ++-- 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/include/hw/rx/rx62n.h b/include/hw/rx/rx62n.h index 44f5fcc74d..942ed0639f 100644 --- a/include/hw/rx/rx62n.h +++ b/include/hw/rx/rx62n.h @@ -26,8 +26,8 @@ =20 #include "target/rx/cpu.h" #include "hw/intc/rx_icu.h" -#include "hw/timer/renesas_tmr.h" -#include "hw/timer/renesas_cmt.h" +#include "hw/timer/renesas_tmr8.h" +#include "hw/timer/renesas_timer.h" #include "hw/char/renesas_sci.h" #include "hw/rx/rx62n-cpg.h" #include "qemu/units.h" @@ -56,9 +56,9 @@ struct RX62NState { =20 RXCPU cpu; RXICUState icu; - RTMRState tmr[RX62N_NR_TMR]; - RCMTState cmt[RX62N_NR_CMT]; - RSCIState sci[RX62N_NR_SCI]; + RenesasTMR8State tmr[RX62N_NR_TMR]; + RenesasCMTState cmt[RX62N_NR_CMT]; + RenesasSCIState sci[RX62N_NR_SCI]; RX62NCPGState cpg; =20 MemoryRegion *sysmem; diff --git a/hw/rx/rx62n.c b/hw/rx/rx62n.c index cfd41930bf..58eff0b4a3 100644 --- a/hw/rx/rx62n.c +++ b/hw/rx/rx62n.c @@ -164,7 +164,7 @@ static void register_tmr(RX62NState *s, int unit) char ckname[16]; =20 object_initialize_child(OBJECT(s), "tmr[*]", - &s->tmr[unit], TYPE_RENESAS_TMR); + &s->tmr[unit], TYPE_RENESAS_TMR8); tmr =3D SYS_BUS_DEVICE(&s->tmr[unit]); =20 irqbase =3D RX62N_TMR_IRQ + TMR_NR_IRQ * unit; @@ -174,10 +174,10 @@ static void register_tmr(RX62NState *s, int unit) sysbus_mmio_map(tmr, 0, RX62N_TMR_BASE + unit * 0x10); =20 qdev_prop_set_uint32(DEVICE(tmr), "unit", unit); - sysbus_realize(tmr, &error_abort); snprintf(ckname, sizeof(ckname), "pck_tmr8-%d", unit); qdev_connect_clock_in(DEVICE(tmr), "pck", qdev_get_clock_out(DEVICE(&s->cpg), ckname)); + sysbus_realize(tmr, &error_abort); } =20 static void register_cmt(RX62NState *s, int unit) @@ -190,6 +190,9 @@ static void register_cmt(RX62NState *s, int unit) &s->cmt[unit], TYPE_RENESAS_CMT); cmt =3D SYS_BUS_DEVICE(&s->cmt[unit]); qdev_prop_set_uint32(DEVICE(cmt), "unit", unit); + snprintf(ckname, sizeof(ckname), "pck_cmt-%d", unit); + qdev_connect_clock_in(DEVICE(cmt), "pck", + qdev_get_clock_out(DEVICE(&s->cpg), ckname)); =20 irqbase =3D RX62N_CMT_IRQ + CMT_NR_IRQ * unit; for (i =3D 0; i < CMT_NR_IRQ; i++) { @@ -197,20 +200,23 @@ static void register_cmt(RX62NState *s, int unit) } sysbus_mmio_map(cmt, 0, RX62N_CMT_BASE + unit * 0x10); sysbus_realize(cmt, &error_abort); - snprintf(ckname, sizeof(ckname), "pck_cmt-%d", unit); - qdev_connect_clock_in(DEVICE(cmt), "pck", - qdev_get_clock_out(DEVICE(&s->cpg), ckname)); } =20 static void register_sci(RX62NState *s, int unit) { SysBusDevice *sci; int i, irqbase; + char ckname[16]; =20 object_initialize_child(OBJECT(s), "sci[*]", - &s->sci[unit], TYPE_RENESAS_SCI); + &s->sci[unit], TYPE_RENESAS_SCIA); sci =3D SYS_BUS_DEVICE(&s->sci[unit]); qdev_prop_set_chr(DEVICE(sci), "chardev", serial_hd(unit)); + qdev_prop_set_uint32(DEVICE(sci), "unit", unit); + qdev_prop_set_uint32(DEVICE(sci), "register-size", SCI_REGSIZE_8); + snprintf(ckname, sizeof(ckname), "pck_sci-%d", unit); + qdev_connect_clock_in(DEVICE(sci), "pck", + qdev_get_clock_out(DEVICE(&s->cpg), ckname)); sysbus_realize(sci, &error_abort); =20 irqbase =3D RX62N_SCI_IRQ + SCI_NR_IRQ * unit; diff --git a/hw/rx/Kconfig b/hw/rx/Kconfig index 2b297c5a6a..9cd1082623 100644 --- a/hw/rx/Kconfig +++ b/hw/rx/Kconfig @@ -1,8 +1,8 @@ config RX62N_MCU bool select RX_ICU - select RENESAS_TMR - select RENESAS_CMT + select RENESAS_TMR8 + select RENESAS_TIMER select RENESAS_SCI =20 config RX_GDBSIM --=20 2.20.1 From nobody Sun May 5 10:23:05 2024 Delivered-To: importer2@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer2=patchew.org@nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1622093371; cv=none; d=zohomail.com; s=zohoarc; b=VdCxv8QuyOGjF11rhZ9DV4RsJH5/CgFznxZUL+0hkjaZGyNVVdWfRpPUY+n6YQAnrym24TAk2O8JySTqcYtCp6XWcirvVsKeQWhh98kweFsteCbiaGEUbwnCYM04wytjhaMbDCxykaHWz+As+A82Ayy3jj03PvfqG3oer5eiIu4= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1622093371; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=gXf1YGpJhGGgnA5d1dvKVfOMVT6cCURqhNnt1riiYec=; b=VFF+YoSBonLrKOXXT8/Efk+S2QV8tgGjLuxdIYMhlBcgTT2aHfUxMclKdwgjMB8+CZ6DUbOihzg31rRci/0bPpsPEbJxid2NIg24qY+AGCkaKXQtE1ZDM3weM82P99dFbfmgb/E9/evsNQi02nP7OGseYCbwZ8nT7uUj8j8zGXo= ARC-Authentication-Results: i=1; mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer2=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 1622093371776924.8427090640175; Wed, 26 May 2021 22:29:31 -0700 (PDT) Received: from localhost ([::1]:56084 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lm8aI-0005fM-N2 for importer2@patchew.org; Thu, 27 May 2021 01:29:30 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:56942) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lm8Sk-00007M-RP for qemu-devel@nongnu.org; Thu, 27 May 2021 01:21:42 -0400 Received: from mail03.asahi-net.or.jp ([202.224.55.15]:32945) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lm8Sc-00066X-8u for qemu-devel@nongnu.org; Thu, 27 May 2021 01:21:42 -0400 Received: from sakura.ysato.name (ik1-413-38519.vs.sakura.ne.jp [153.127.30.23]) (Authenticated sender: PQ4Y-STU) by mail03.asahi-net.or.jp (Postfix) with ESMTPA id 98F97385F8; Thu, 27 May 2021 14:21:32 +0900 (JST) Received: from yo-satoh-debian.localdomain (y245018.dynamic.ppp.asahi-net.or.jp [118.243.245.18]) by sakura.ysato.name (Postfix) with ESMTPSA id 3702B1C060B; Thu, 27 May 2021 14:21:32 +0900 (JST) From: Yoshinori Sato To: qemu-devel@nongnu.org Subject: [PATCH 09/11] hw/sh4: sh7750 Add CPG. Date: Thu, 27 May 2021 14:21:20 +0900 Message-Id: <20210527052122.97103-10-ysato@users.sourceforge.jp> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20210527052122.97103-1-ysato@users.sourceforge.jp> References: <20210527052122.97103-1-ysato@users.sourceforge.jp> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer2=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: softfail client-ip=202.224.55.15; envelope-from=ysato@users.sourceforge.jp; helo=mail03.asahi-net.or.jp X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_DNSWL_LOW=-0.7, SPF_HELO_NONE=0.001, SPF_SOFTFAIL=0.665 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Yoshinori Sato Errors-To: qemu-devel-bounces+importer2=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" CPG required new hw modules. Signed-off-by: Yoshinori Sato --- include/hw/sh4/sh7751-cpg.h | 94 ++++++++ hw/sh4/sh7750.c | 25 ++ hw/sh4/sh7751-cpg.c | 457 ++++++++++++++++++++++++++++++++++++ hw/sh4/meson.build | 1 + 4 files changed, 577 insertions(+) create mode 100644 include/hw/sh4/sh7751-cpg.h create mode 100644 hw/sh4/sh7751-cpg.c diff --git a/include/hw/sh4/sh7751-cpg.h b/include/hw/sh4/sh7751-cpg.h new file mode 100644 index 0000000000..79f9abe210 --- /dev/null +++ b/include/hw/sh4/sh7751-cpg.h @@ -0,0 +1,94 @@ +/* + * SH7751(R) Clock generator circuit + * + * Datasheet: SH7751 Group, SH7751R Group User's Manual: Hardware + * (Rev.4.01 R01UH0457EJ0401) + * + * Copyright (c) 2020 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 . + */ + +#ifndef HW_SH4_SH7751_CPG_H +#define HW_SH4_SH7751_CPG_H + +#include "hw/sysbus.h" +#include "hw/qdev-clock.h" + +#define TYPE_SH7751_CPG_BASE "sh7751-cpg-base" +#define SH7751CPGBase(obj) \ + OBJECT_CHECK(SH7751CPGBaseState, (obj), TYPE_SH7751_CPG_BASE) +#define TYPE_SH7751_CPG "sh7751-cpg" +#define SH7751CPG(obj) OBJECT_CHECK(SH7751CPGState, (obj), TYPE_SH7751_CPG) +#define TYPE_SH7751R_CPG "sh7751r-cpg" +#define SH7751RCPG(obj) OBJECT_CHECK(SH7751RCPGState, (obj), TYPE_SH7751R_= CPG) +#define SH7751CPG_GET_CLASS(obj) \ + OBJECT_GET_CLASS(SH7751CPGBaseClass, obj, TYPE_SH7751_CPG_BASE) +#define SH7751CPGBaseClass(klass) \ + OBJECT_CLASS_CHECK(SH7751CPGBaseClass, klass, TYPE_SH7751_CPG_BASE) + +enum { + CK_DMAC, + CK_SCIF, + CK_TMU_0, + CK_RTC, + CK_SCI, + CK_SQ, + CK_UBC, + CK_PCIC, + CK_TMU_1, + CK_INTC, + NUM_SUBCLOCK, +}; + +typedef struct SH7751CPGBaseState { + SysBusDevice parent_obj; + uint8_t stbcr[2]; + uint32_t clkstp00; + uint16_t freqcr; + + uint32_t clock_mode; + int ick; + Clock *clk_ick; + int bck; + Clock *clk_bck; + int pck; + Clock *clk_pck; + Clock *dev_clocks[NUM_SUBCLOCK]; + uint32_t xtal_freq_hz; + MemoryRegion memory[3 * 2]; +} SH7751CPGBaseState; + +typedef struct { + SH7751CPGBaseState parent_obj; +} SH7751CPGState; + +typedef struct { + SH7751CPGBaseState parent_obj; +} SH7751RCPGState; + +typedef struct { + SysBusDeviceClass parent; + int (*pll1mul)(int mode, uint16_t freqcr); + uint16_t *initfreqcr; +} SH7751CPGBaseClass; + +typedef struct { + SH7751CPGBaseClass parent; +} SH7751CPGClass; + +typedef struct { + SH7751CPGBaseClass parent; +} SH7751RCPGClass; + +#endif diff --git a/hw/sh4/sh7750.c b/hw/sh4/sh7750.c index d53a436d8c..2f6c382aa6 100644 --- a/hw/sh4/sh7750.c +++ b/hw/sh4/sh7750.c @@ -24,6 +24,7 @@ */ =20 #include "qemu/osdep.h" +#include "qapi/error.h" #include "hw/irq.h" #include "hw/sh4/sh.h" #include "sysemu/sysemu.h" @@ -32,6 +33,8 @@ #include "hw/sh4/sh_intc.h" #include "hw/timer/tmu012.h" #include "exec/exec-all.h" +#include "hw/sh4/sh7751-cpg.h" +#include "hw/qdev-properties.h" =20 #define NB_DEVICES 4 =20 @@ -752,9 +755,29 @@ static const MemoryRegionOps sh7750_mmct_ops =3D { .endianness =3D DEVICE_NATIVE_ENDIAN, }; =20 +static SH7751CPGBaseState *sh_cpg_init(MemoryRegion *sysmem, + int cputype) +{ + const char *cpgtype; + SH7751CPGBaseState *cpg; + if (cputype & (SH_CPU_SH7750R | SH_CPU_SH7751R)) { + cpgtype =3D TYPE_SH7751R_CPG; + } else { + cpgtype =3D TYPE_SH7751_CPG; + } + cpg =3D SH7751CPGBase(qdev_new(cpgtype)); + qdev_prop_set_uint32(DEVICE(cpg), "xtal-frequency-hz", 20 * 1000 * 100= 0); + qdev_prop_set_uint32(DEVICE(cpg), "clock-mode", 5); + sysbus_mmio_map(SYS_BUS_DEVICE(cpg), 0, 0x1fc00000); + sysbus_mmio_map(SYS_BUS_DEVICE(cpg), 1, P4ADDR(0x1fc00000)); + sysbus_mmio_map(SYS_BUS_DEVICE(cpg), 2, A7ADDR(0x1fc00000)); + return cpg; +} + SH7750State *sh7750_init(SuperHCPU *cpu, MemoryRegion *sysmem) { SH7750State *s; + SH7751CPGBaseState *cpg; =20 s =3D g_malloc0(sizeof(SH7750State)); s->cpu =3D cpu; @@ -800,6 +823,7 @@ SH7750State *sh7750_init(SuperHCPU *cpu, MemoryRegion *= sysmem) =20 cpu->env.intc_handle =3D &s->intc; =20 + cpg =3D sh_cpg_init(sysmem, cpu->env.id); sh_serial_init(sysmem, 0x1fe00000, 0, s->periph_freq, serial_hd(0), s->intc.irqs[SCI1_ERI], @@ -824,6 +848,7 @@ SH7750State *sh7750_init(SuperHCPU *cpu, MemoryRegion *= sysmem) s->intc.irqs[TMU2_TUNI], s->intc.irqs[TMU2_TICPI]); =20 + sysbus_realize(SYS_BUS_DEVICE(cpg), &error_abort); if (cpu->env.id & (SH_CPU_SH7750 | SH_CPU_SH7750S | SH_CPU_SH7751)) { sh_intc_register_sources(&s->intc, _INTC_ARRAY(vectors_dma4), diff --git a/hw/sh4/sh7751-cpg.c b/hw/sh4/sh7751-cpg.c new file mode 100644 index 0000000000..4e057908ff --- /dev/null +++ b/hw/sh4/sh7751-cpg.c @@ -0,0 +1,457 @@ +/* + * SH7750 / SH7751 Clock Generation Circuit + * + * Datasheet: SH7751 Group, SH7751R Group User's Manual: Hardware + * (Rev.4.01 R01UH0457EJ0401) + * + * Copyright (c) 2020 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 "qapi/error.h" +#include "qemu/log.h" +#include "hw/hw.h" +#include "hw/sh4/sh7751-cpg.h" +#include "hw/sysbus.h" +#include "hw/qdev-properties.h" +#include "hw/registerfields.h" +#include "hw/qdev-properties.h" +#include "hw/clock.h" +#include "migration/vmstate.h" + +#define SH7751_XTAL_MIN_HZ (1 * 1000 * 1000) +#define SH7751_XTAL_MAX_HZ (34 * 1000 * 1000) + +REG16(FREQCR, 0) + FIELD(FREQCR, PFC, 0, 3) + FIELD(FREQCR, BFC, 3, 3) + FIELD(FREQCR, IFC, 6, 3) + FIELD(FREQCR, PLL2EN, 9, 1) + FIELD(FREQCR, PLL1EN, 10, 1) + FIELD(FREQCR, CKOEN, 11, 1) +REG8(STBCR, 4) +REG8(STBCR2, 16) + +REG32(CLKSTP00, 0) +REG32(CLKSTPCLR00, 8) + +typedef struct { + const char *name; + int devnum; + int reg; + int offset; +} dev_clock_t; + +static const dev_clock_t dev_clock_list[] =3D { + { .name =3D "pck_sci", .devnum =3D CK_SCI, .reg =3D 0, .offset =3D 0}, + { .name =3D "pck_rtc", .devnum =3D CK_RTC, .reg =3D 0, .offset =3D 1}, + { .name =3D "pck_tmu-0", .devnum =3D CK_TMU_0, .reg =3D 0, .offset =3D= 2}, + { .name =3D "pck_scif", .devnum =3D CK_SCIF, .reg =3D 0, .offset =3D = 3}, + { .name =3D "pck_dmac", .devnum =3D CK_DMAC, .reg =3D 0, .offset =3D 4= }, + { .name =3D "pck_ubc", .devnum =3D CK_UBC, .reg =3D 1, .offset =3D 0}, + { .name =3D "pck_sq", .devnum =3D CK_SQ, .reg =3D 1, .offset =3D 1}, + { .name =3D "pck_intc", .devnum =3D CK_INTC, .reg =3D 2, .offset =3D 0= }, + { .name =3D "pck_tmu-1", .devnum =3D CK_TMU_1, .reg =3D 2, .offset =3D= 1}, + { .name =3D "pck_pcic", .devnum =3D CK_PCIC, .reg =3D 2, .offset =3D 2= }, + { }, +}; + +static void set_clock_in(SH7751CPGBaseState *cpg, const dev_clock_t *ck) +{ + Clock *out; + uint64_t period; + + out =3D qdev_get_clock_out(DEVICE(cpg), ck->name); + g_assert(out); + period =3D 0; + switch (ck->reg) { + case 0: + case 1: + if (extract8(cpg->stbcr[ck->reg], ck->offset, 1) =3D=3D 0) { + period =3D clock_get(cpg->clk_ick); + } + break; + case 2: + if (extract32(cpg->clkstp00, ck->offset, 1) =3D=3D 0) { + period =3D clock_get(cpg->clk_ick); + } + break; + } + if (clock_get(out) !=3D period) { + clock_update(out, period); + } +} + +static void update_divrate(SH7751CPGBaseState *cpg) +{ + SH7751CPGBaseClass *k =3D SH7751CPG_GET_CLASS(cpg); + int ick =3D FIELD_EX32(cpg->freqcr, FREQCR, IFC); + int bck =3D FIELD_EX32(cpg->freqcr, FREQCR, BFC); + int pck =3D FIELD_EX32(cpg->freqcr, FREQCR, PFC); + const dev_clock_t *p =3D dev_clock_list; + uint32_t divinput; + + divinput =3D cpg->xtal_freq_hz * k->pll1mul(cpg->clock_mode, cpg->freq= cr); + + ick =3D ick < 4 ? ick + 1 : (ick - 1) * 2; + clock_update_hz(cpg->clk_ick, divinput / ick); + bck =3D bck < 4 ? bck + 1 : (bck - 1) * 2; + clock_update_hz(cpg->clk_bck, divinput / bck); + pck =3D pck < 3 ? pck + 2 : pck * 2; + clock_update_hz(cpg->clk_pck, divinput / pck); + + while (p->name) { + set_clock_in(cpg, p); + p++; + } +} + +static const dev_clock_t *find_clock_list(int crno, int bit) +{ + const dev_clock_t *ret =3D dev_clock_list; + while (ret->name) { + if (ret->reg =3D=3D crno && ret->offset =3D=3D bit) { + return ret; + } + ret++; + } + return NULL; +} + +static void update_stbcr(SH7751CPGBaseState *cpg, int no, uint32_t diff) +{ + int bit =3D 0; + const dev_clock_t *p; + static const char *reg[] =3D {"STBCR", "STBCR2", "CLKSTP00"}; + + while (diff) { + if (diff & 1) { + p =3D find_clock_list(no, bit); + if (p) { + set_clock_in(cpg, p); + } else { + qemu_log_mask(LOG_UNIMP, "sh7751-cpg: %s " + " bit %d is not implement.\n", reg[no], bit); + } + } + bit++; + diff >>=3D 1; + } +} + +static uint64_t cpg_read(void *opaque, hwaddr addr, unsigned size) +{ + SH7751CPGBaseState *cpg =3D SH7751CPGBase(opaque); + int reg; + + switch (addr) { + case A_FREQCR: + if (size !=3D 2) { + qemu_log_mask(LOG_GUEST_ERROR, "sh7751-cpg: Register 0x%" + HWADDR_PRIX " Invalid access size.\n", addr); + return UINT64_MAX; + } + return cpg->freqcr; + case A_STBCR: + case A_STBCR2: + if (size !=3D 1) { + qemu_log_mask(LOG_GUEST_ERROR, "sh7751-cpg: Register 0x%" + HWADDR_PRIX " Invalid access size.\n", addr); + return UINT64_MAX; + } + reg =3D extract32(addr, 4, 1); /* STBCR -> 0x04 / STBCR2 -> 0x10 */ + return cpg->stbcr[reg]; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, "sh7751-cpg: Register 0x%" + HWADDR_PRIX " Invalid address.\n", addr); + return UINT64_MAX; + } + +} + +static void cpg_write(void *opaque, hwaddr addr, uint64_t val, unsigned si= ze) +{ + SH7751CPGBaseState *cpg =3D SH7751CPGBase(opaque); + uint32_t old_stbcr; + int reg; + + switch (addr) { + case A_FREQCR: + if (size !=3D 2) { + qemu_log_mask(LOG_GUEST_ERROR, "sh7751-cpg: Register 0x%" + HWADDR_PRIX " Invalid access size.\n", addr); + return; + } + if ((cpg->freqcr ^ val) & 0x0600) { + qemu_log_mask(LOG_UNIMP, + "sh7751-cpg: PLL operation not supported.\n"); + } + cpg->freqcr =3D val; + update_divrate(cpg); + break; + case A_STBCR: + case A_STBCR2: + if (size !=3D 1) { + qemu_log_mask(LOG_GUEST_ERROR, "sh7751-cpg: Register 0x%" + HWADDR_PRIX " Invalid access size.\n", addr); + return; + } + reg =3D extract32(addr, 4, 1); /* STBCR -> 0x04 / STBCR2 -> 0x10 */ + old_stbcr =3D cpg->stbcr[reg]; + old_stbcr ^=3D val; + cpg->stbcr[reg] =3D val; + update_stbcr(cpg, reg, old_stbcr); + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, "sh7751-cpg: Register 0x%" + HWADDR_PRIX " Invalid address.\n", addr); + } +} + +static uint64_t stp_read(void *opaque, hwaddr addr, unsigned size) +{ + SH7751CPGBaseState *cpg =3D SH7751CPGBase(opaque); + + switch (addr) { + case A_CLKSTP00: + return cpg->clkstp00; + case A_CLKSTPCLR00: + qemu_log_mask(LOG_GUEST_ERROR, + "sh7751-cpg: CLKSTPCLR00 is write only.\n"); + return UINT64_MAX; + default: + qemu_log_mask(LOG_GUEST_ERROR, "sh7751-cpg: Register 0x%" + HWADDR_PRIX " Invalid address.\n", addr); + return UINT64_MAX; + } +} + +static void stp_write(void *opaque, hwaddr addr, uint64_t val, unsigned si= ze) +{ + SH7751CPGBaseState *cpg =3D SH7751CPGBase(opaque); + + val &=3D 0x7; + switch (addr) { + case A_CLKSTP00: + cpg->clkstp00 |=3D val; + update_stbcr(cpg, 2, val); + break; + case A_CLKSTPCLR00: + cpg->clkstp00 &=3D ~val; + update_stbcr(cpg, 2, val); + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, "sh7751-cpg: Register 0x%" + HWADDR_PRIX " Invalid address.\n", addr); + } +} + +static int sh7751_pll1mul(int mode, uint16_t freqcr) +{ + int div1; + int pll1; + switch (mode) { + case 3: + case 5: + case 6: + div1 =3D 2; + break; + default: + div1 =3D 1; + } + if (FIELD_EX16(freqcr, FREQCR, PLL1EN)) { + pll1 =3D 6; + } else { + pll1 =3D 1; + } + return pll1 / div1; +} + +static int sh7751r_pll1mul(int mode, uint16_t freqcr) +{ + int pll1; + switch (mode) { + case 0: + case 1: + case 3: + case 5: + pll1 =3D 12; + break; + case 2: + case 4: + case 6: + pll1 =3D 6; + break; + default: + g_assert_not_reached(); + } + if (!FIELD_EX16(freqcr, FREQCR, PLL1EN)) { + pll1 =3D 1; + } + return pll1; +} + +static const MemoryRegionOps cpg_ops =3D { + .write =3D cpg_write, + .read =3D cpg_read, + .endianness =3D DEVICE_NATIVE_ENDIAN, + .impl =3D { + .min_access_size =3D 1, + .max_access_size =3D 4, + }, +}; + +static const MemoryRegionOps stp_ops =3D { + .write =3D stp_write, + .read =3D stp_read, + .endianness =3D DEVICE_NATIVE_ENDIAN, + .impl =3D { + .min_access_size =3D 4, + .max_access_size =3D 4, + }, +}; + +static const ClockPortInitArray sh7751_cpg_clocks =3D { + QDEV_CLOCK_OUT(SH7751CPGBaseState, clk_ick), + QDEV_CLOCK_OUT(SH7751CPGBaseState, clk_bck), + QDEV_CLOCK_OUT(SH7751CPGBaseState, clk_pck), + QDEV_CLOCK_END +}; + +static void sh7751cpg_realize(DeviceState *dev, Error **errp) +{ + SH7751CPGBaseState *cpg =3D SH7751CPGBase(dev); + SH7751CPGBaseClass *k =3D SH7751CPG_GET_CLASS(cpg); + + if (cpg->xtal_freq_hz =3D=3D 0) { + error_setg(errp, "\"xtal-frequency-hz\" property must be provided.= "); + return; + } + /* XTAL range: 1-34 MHz */ + if (cpg->xtal_freq_hz < SH7751_XTAL_MIN_HZ || + cpg->xtal_freq_hz > SH7751_XTAL_MAX_HZ) { + error_setg(errp, "\"xtal-frequency-hz\" property in incorrect rang= e."); + return; + } + /* Clock mode: 0 - 6 */ + if (cpg->clock_mode > 6) { + error_setg(errp, "\"clock-mode\" property in incorrect range."); + return; + } + + cpg->freqcr =3D k->initfreqcr[cpg->clock_mode]; + update_divrate(cpg); +} + +static void sh7751_cpg_init(Object *obj) +{ + SH7751CPGBaseState *cpg =3D SH7751CPGBase(obj); + const dev_clock_t *p =3D dev_clock_list; + qdev_init_clocks(DEVICE(obj), sh7751_cpg_clocks); + /* connect parent clock */ + while (p->name) { + cpg->dev_clocks[p->devnum] =3D qdev_init_clock_out(DEVICE(obj), + p->name); + p++; + } + + memory_region_init_io(&cpg->memory[0], OBJECT(cpg), &cpg_ops, + cpg, "sh7751-cpg", 0x14); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &cpg->memory[0]); + memory_region_init_alias(&cpg->memory[1], NULL, + "sh7751-cpg-a4", &cpg->memory[0], 0, 0x14); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &cpg->memory[1]); + memory_region_init_alias(&cpg->memory[2], NULL, + "sh7751-cpg-p7", &cpg->memory[0], 0, 0x14); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &cpg->memory[2]); + memory_region_init_io(&cpg->memory[3], OBJECT(cpg), &stp_ops, + cpg, "sh7751-stp", 0x10); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &cpg->memory[3]); + memory_region_init_alias(&cpg->memory[4], NULL, + "sh7751-stp-a4", &cpg->memory[3], 0, 0x10); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &cpg->memory[4]); + memory_region_init_alias(&cpg->memory[5], NULL, + "sh7751-stp-p7", &cpg->memory[3], 0, 0x10u); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &cpg->memory[5]); +} + +static Property sh7751_cpg_properties[] =3D { + DEFINE_PROP_UINT32("xtal-frequency-hz", + SH7751CPGBaseState, xtal_freq_hz, 0), + DEFINE_PROP_UINT32("clock-mode", + SH7751CPGBaseState, clock_mode, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void sh7751cpg_base_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(klass); + + device_class_set_props(dc, sh7751_cpg_properties); +} + +static void sh7751cpg_class_init(ObjectClass *klass, void *data) +{ + SH7751CPGBaseClass *base =3D SH7751CPGBaseClass(klass); + DeviceClass *dc =3D DEVICE_CLASS(klass); + static uint16_t initfreqcr[] =3D {0x0e1a, 0x0e23, 0x0e13, 0x0e13, + 0x0e0a, 0x0e0a, 0x0808}; + + base->pll1mul =3D sh7751_pll1mul; + base->initfreqcr =3D initfreqcr; + dc->realize =3D sh7751cpg_realize; +} + +static void sh7751rcpg_class_init(ObjectClass *klass, void *data) +{ + SH7751CPGBaseClass *base =3D SH7751CPGBaseClass(klass); + DeviceClass *dc =3D DEVICE_CLASS(klass); + static uint16_t initfreqcr[] =3D {0x0e1a, 0x0e2c, 0x0e13, 0x0e13, + 0x0e0a, 0x0e0a, 0x0808}; + + base->pll1mul =3D sh7751r_pll1mul; + base->initfreqcr =3D initfreqcr; + dc->realize =3D sh7751cpg_realize; +} + +static const TypeInfo sh7751cpg_info[] =3D { + { + .name =3D TYPE_SH7751_CPG_BASE, + .parent =3D TYPE_SYS_BUS_DEVICE, + .instance_size =3D sizeof(SH7751CPGBaseState), + .class_init =3D sh7751cpg_base_class_init, + .class_size =3D sizeof(SH7751CPGBaseClass), + .abstract =3D true, + }, + { + .name =3D TYPE_SH7751_CPG, + .parent =3D TYPE_SH7751_CPG_BASE, + .instance_size =3D sizeof(SH7751CPGState), + .instance_init =3D sh7751_cpg_init, + .class_init =3D sh7751cpg_class_init, + .class_size =3D sizeof(SH7751CPGClass), + }, + { + .name =3D TYPE_SH7751R_CPG, + .parent =3D TYPE_SH7751_CPG_BASE, + .instance_size =3D sizeof(SH7751RCPGState), + .instance_init =3D sh7751_cpg_init, + .class_init =3D sh7751rcpg_class_init, + .class_size =3D sizeof(SH7751RCPGClass), + }, +}; + +DEFINE_TYPES(sh7751cpg_info) diff --git a/hw/sh4/meson.build b/hw/sh4/meson.build index 424d5674de..7ed8246152 100644 --- a/hw/sh4/meson.build +++ b/hw/sh4/meson.build @@ -2,6 +2,7 @@ sh4_ss =3D ss.source_set() sh4_ss.add(files( 'sh7750.c', 'sh7750_regnames.c', + 'sh7751-cpg.c', )) sh4_ss.add(when: 'CONFIG_R2D', if_true: files('r2d.c')) sh4_ss.add(when: 'CONFIG_SHIX', if_true: files('shix.c')) --=20 2.20.1 From nobody Sun May 5 10:23:05 2024 Delivered-To: importer2@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer2=patchew.org@nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1622093204; cv=none; d=zohomail.com; s=zohoarc; b=KfV6jAac4x2sfOucgOcbsP7wXh/uu25VU+b0bOZLaD8QkvlQaOa+z02WEBSphU8XZnNQ7k1AMLQf8fOBA7Wc6wy4lUC9RnqGZV8wp6e9Z/aLCaAZ/h8RAcOhJxt5Ve+Dvna4enoqnYP6dgQkTcGNkz//3jtIiLlfngOfDCpjwhY= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1622093204; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=uJ+78MGrt30ZTCEJ+aGtOKKw6hMhEqnkfYKrEDNSCys=; b=TOWVXhdR/jYrqXd6pOSF0AyuVnUXnQA5oZkhYV9Kn5KSTim57RxhoVWvhtoX4j8LI8TBnFum7fhE1p4Ob1UliIOWi1s4S0kf685TskjEWbwc2YBnKZlQXekG6jAO9wNtiHBSV8LiTGZeRt8qaKZg1KO/XLtpfZCwTimFXV6L/Tk= ARC-Authentication-Results: i=1; mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer2=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 1622093204680777.3530892442865; Wed, 26 May 2021 22:26:44 -0700 (PDT) Received: from localhost ([::1]:47420 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lm8Xb-0008Ec-MZ for importer2@patchew.org; Thu, 27 May 2021 01:26:43 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:56836) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lm8Sg-0008Kr-3S for qemu-devel@nongnu.org; Thu, 27 May 2021 01:21:38 -0400 Received: from mail03.asahi-net.or.jp ([202.224.55.15]:32950) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lm8Sc-000675-2Z for qemu-devel@nongnu.org; Thu, 27 May 2021 01:21:37 -0400 Received: from sakura.ysato.name (ik1-413-38519.vs.sakura.ne.jp [153.127.30.23]) (Authenticated sender: PQ4Y-STU) by mail03.asahi-net.or.jp (Postfix) with ESMTPA id DADF23860B; Thu, 27 May 2021 14:21:32 +0900 (JST) Received: from yo-satoh-debian.localdomain (y245018.dynamic.ppp.asahi-net.or.jp [118.243.245.18]) by sakura.ysato.name (Postfix) with ESMTPSA id 86DCD1C0077; Thu, 27 May 2021 14:21:32 +0900 (JST) From: Yoshinori Sato To: qemu-devel@nongnu.org Subject: [PATCH 10/11] hw/sh4: sh7750 use new hw modules. Date: Thu, 27 May 2021 14:21:21 +0900 Message-Id: <20210527052122.97103-11-ysato@users.sourceforge.jp> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20210527052122.97103-1-ysato@users.sourceforge.jp> References: <20210527052122.97103-1-ysato@users.sourceforge.jp> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer2=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: softfail client-ip=202.224.55.15; envelope-from=ysato@users.sourceforge.jp; helo=mail03.asahi-net.or.jp X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_DNSWL_LOW=-0.7, SPF_HELO_NONE=0.001, SPF_SOFTFAIL=0.665 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Yoshinori Sato Errors-To: qemu-devel-bounces+importer2=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" Signed-off-by: Yoshinori Sato --- include/hw/sh4/sh.h | 8 ----- hw/sh4/sh7750.c | 87 +++++++++++++++++++++++++++++++++++++++------ hw/sh4/Kconfig | 4 +-- 3 files changed, 79 insertions(+), 20 deletions(-) diff --git a/include/hw/sh4/sh.h b/include/hw/sh4/sh.h index becb596979..74e1ba59a8 100644 --- a/include/hw/sh4/sh.h +++ b/include/hw/sh4/sh.h @@ -55,14 +55,6 @@ int sh7750_register_io_device(struct SH7750State *s, =20 /* sh_serial.c */ #define SH_SERIAL_FEAT_SCIF (1 << 0) -void sh_serial_init(MemoryRegion *sysmem, - hwaddr base, int feat, - uint32_t freq, Chardev *chr, - qemu_irq eri_source, - qemu_irq rxi_source, - qemu_irq txi_source, - qemu_irq tei_source, - qemu_irq bri_source); =20 /* sh7750.c */ qemu_irq sh7750_irl(struct SH7750State *s); diff --git a/hw/sh4/sh7750.c b/hw/sh4/sh7750.c index 2f6c382aa6..b2f6ebe936 100644 --- a/hw/sh4/sh7750.c +++ b/hw/sh4/sh7750.c @@ -31,9 +31,10 @@ #include "sh7750_regs.h" #include "sh7750_regnames.h" #include "hw/sh4/sh_intc.h" -#include "hw/timer/tmu012.h" +#include "hw/timer/renesas_timer.h" #include "exec/exec-all.h" #include "hw/sh4/sh7751-cpg.h" +#include "hw/char/renesas_sci.h" #include "hw/qdev-properties.h" =20 #define NB_DEVICES 4 @@ -774,6 +775,74 @@ static SH7751CPGBaseState *sh_cpg_init(MemoryRegion *s= ysmem, return cpg; } =20 +static void tmu012_init(MemoryRegion *sysmem, hwaddr base, + int unit, + qemu_irq ch0_irq, qemu_irq ch1_irq, + qemu_irq ch2_irq0, qemu_irq ch2_irq1, + SH7751CPGBaseState *cpg) +{ + RenesasTMUState *tmu; + char ckname[16]; + + tmu =3D RENESAS_TMU(qdev_new(TYPE_RENESAS_TMU)); + qdev_prop_set_uint32(DEVICE(tmu), "unit", unit); + snprintf(ckname, sizeof(ckname), "pck_tmu-%d", unit); + qdev_connect_clock_in(DEVICE(tmu), "pck", + qdev_get_clock_out(DEVICE(cpg), "pck_tmu-0")); + + sysbus_realize(SYS_BUS_DEVICE(tmu), &error_abort); + sysbus_connect_irq(SYS_BUS_DEVICE(tmu), 0, ch0_irq); + sysbus_connect_irq(SYS_BUS_DEVICE(tmu), 1, ch1_irq); + if (unit =3D=3D 0) { + sysbus_connect_irq(SYS_BUS_DEVICE(tmu), 2, ch2_irq0); + } + /* ch2_irq1 is not used. */ + + sysbus_mmio_map(SYS_BUS_DEVICE(tmu), 0, base); + sysbus_mmio_map(SYS_BUS_DEVICE(tmu), 1, P4ADDR(base)); + sysbus_mmio_map(SYS_BUS_DEVICE(tmu), 2, A7ADDR(base)); +} + +static void sh_serial_init(MemoryRegion *sysmem, + hwaddr base, int feat, + uint32_t freq, Chardev *chr, + qemu_irq eri_source, + qemu_irq rxi_source, + qemu_irq txi_source, + qemu_irq tei_source, + qemu_irq bri_source, + SH7751CPGBaseState *cpg) +{ + RenesasSCIBaseState *sci; + char ckname[16]; + + switch(feat) { + case 0: /* SCI */ + sci =3D RENESAS_SCI_BASE(qdev_new(TYPE_RENESAS_SCI)); + snprintf(ckname, sizeof(ckname), "pck_sci"); + break; + case SH_SERIAL_FEAT_SCIF: + sci =3D RENESAS_SCI_BASE(qdev_new(TYPE_RENESAS_SCIF)); + snprintf(ckname, sizeof(ckname), "pck_scif"); + break; + } + qdev_prop_set_chr(DEVICE(sci), "chardev", chr); + qdev_prop_set_uint32(DEVICE(sci), "register-size", SCI_REGSIZE_32); + qdev_connect_clock_in(DEVICE(sci), "pck", + qdev_get_clock_out(DEVICE(cpg), ckname)); + sysbus_connect_irq(SYS_BUS_DEVICE(sci), 0, eri_source); + sysbus_connect_irq(SYS_BUS_DEVICE(sci), 1, rxi_source); + sysbus_connect_irq(SYS_BUS_DEVICE(sci), 2, txi_source); + if (tei_source) + sysbus_connect_irq(SYS_BUS_DEVICE(sci), 3, tei_source); + if (bri_source) + sysbus_connect_irq(SYS_BUS_DEVICE(sci), 3, bri_source); + sysbus_realize(SYS_BUS_DEVICE(sci), &error_abort); + sysbus_mmio_map(SYS_BUS_DEVICE(sci), 0, base); + sysbus_mmio_map(SYS_BUS_DEVICE(sci), 1, P4ADDR(base)); + sysbus_mmio_map(SYS_BUS_DEVICE(sci), 2, A7ADDR(base)); +} + SH7750State *sh7750_init(SuperHCPU *cpu, MemoryRegion *sysmem) { SH7750State *s; @@ -830,7 +899,7 @@ SH7750State *sh7750_init(SuperHCPU *cpu, MemoryRegion *= sysmem) s->intc.irqs[SCI1_RXI], s->intc.irqs[SCI1_TXI], s->intc.irqs[SCI1_TEI], - NULL); + NULL, cpg); sh_serial_init(sysmem, 0x1fe80000, SH_SERIAL_FEAT_SCIF, s->periph_freq, serial_hd(1), @@ -838,17 +907,14 @@ SH7750State *sh7750_init(SuperHCPU *cpu, MemoryRegion= *sysmem) s->intc.irqs[SCIF_RXI], s->intc.irqs[SCIF_TXI], NULL, - s->intc.irqs[SCIF_BRI]); + s->intc.irqs[SCIF_BRI], cpg); =20 - tmu012_init(sysmem, 0x1fd80000, - TMU012_FEAT_TOCR | TMU012_FEAT_3CHAN | TMU012_FEAT_EXTCLK, - s->periph_freq, + tmu012_init(sysmem, 0x1fd80000, 0, s->intc.irqs[TMU0], s->intc.irqs[TMU1], s->intc.irqs[TMU2_TUNI], - s->intc.irqs[TMU2_TICPI]); + s->intc.irqs[TMU2_TICPI], cpg); =20 - sysbus_realize(SYS_BUS_DEVICE(cpg), &error_abort); if (cpu->env.id & (SH_CPU_SH7750 | SH_CPU_SH7750S | SH_CPU_SH7751)) { sh_intc_register_sources(&s->intc, _INTC_ARRAY(vectors_dma4), @@ -865,10 +931,10 @@ SH7750State *sh7750_init(SuperHCPU *cpu, MemoryRegion= *sysmem) sh_intc_register_sources(&s->intc, _INTC_ARRAY(vectors_tmu34), NULL, 0); - tmu012_init(sysmem, 0x1e100000, 0, s->periph_freq, + tmu012_init(sysmem, 0x1e100000, 1, s->intc.irqs[TMU3], s->intc.irqs[TMU4], - NULL, NULL); + NULL, NULL, cpg); } =20 if (cpu->env.id & (SH_CPU_SH7751_ALL)) { @@ -886,6 +952,7 @@ SH7750State *sh7750_init(SuperHCPU *cpu, MemoryRegion *= sysmem) sh_intc_register_sources(&s->intc, _INTC_ARRAY(vectors_irl), _INTC_ARRAY(groups_irl)); + sysbus_realize(SYS_BUS_DEVICE(cpg), &error_abort); return s; } =20 diff --git a/hw/sh4/Kconfig b/hw/sh4/Kconfig index ab733a3f76..b2da634d22 100644 --- a/hw/sh4/Kconfig +++ b/hw/sh4/Kconfig @@ -20,5 +20,5 @@ config SHIX config SH7750 bool select SH_INTC - select SH_SCI - select SH_TIMER + select RENESAS_TIMER + select RENESAS_SCI --=20 2.20.1 From nobody Sun May 5 10:23:05 2024 Delivered-To: importer2@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer2=patchew.org@nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1622093046; cv=none; d=zohomail.com; s=zohoarc; b=J14QgVMBabW3xshnJOV1YPjv/nhCijzRyUOD0B2vJbYtY+8acA8mWmB/llj2FYPvguV2fx8RLRcIS8F/AqKiev0Xpq+0GkmLIcbhX9RWwNfsKjE4zv4Z4+oZ6qLOsL3Z0QePPH4wvMsAlMREl5U1ZY4il05XdWWdY/PloeAgTz8= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1622093046; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=tZUn0AvzGwNXDWyHnYzSIdxxtVH0GQuSfRJ4Y+kDTIA=; b=jHHcUtOr3WM9xZJjsFtQMJ5Cm11kFBgHuFlWHCGCVKfM4o4+eyh+n0k+gT9bV0XU7OYGWOsWLKqDx2/mOQxXh5r9+EfOnb1MOJHgtyLwUwzbGj0YbjqpyVrhoPMm89U3erFQrcdeCYg7ilxqrhVKlK+xDWu/Z64AUN9m8On2E5A= ARC-Authentication-Results: i=1; mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer2=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 16220930464328.482577005185817; Wed, 26 May 2021 22:24:06 -0700 (PDT) Received: from localhost ([::1]:38848 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lm8V3-0002Zc-EC for importer2@patchew.org; Thu, 27 May 2021 01:24:05 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:56798) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lm8Se-0008KW-Ep for qemu-devel@nongnu.org; Thu, 27 May 2021 01:21:36 -0400 Received: from mail01.asahi-net.or.jp ([202.224.55.13]:58635) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lm8Sc-00067C-2a for qemu-devel@nongnu.org; Thu, 27 May 2021 01:21:36 -0400 Received: from sakura.ysato.name (ik1-413-38519.vs.sakura.ne.jp [153.127.30.23]) (Authenticated sender: PQ4Y-STU) by mail01.asahi-net.or.jp (Postfix) with ESMTPA id 1EE1C11D3D0; Thu, 27 May 2021 14:21:33 +0900 (JST) Received: from yo-satoh-debian.localdomain (y245018.dynamic.ppp.asahi-net.or.jp [118.243.245.18]) by sakura.ysato.name (Postfix) with ESMTPSA id C36801C060B; Thu, 27 May 2021 14:21:32 +0900 (JST) From: Yoshinori Sato To: qemu-devel@nongnu.org Subject: [PATCH 11/11] hw/rx: rx-gdbsim Add bootstrup for linux Date: Thu, 27 May 2021 14:21:22 +0900 Message-Id: <20210527052122.97103-12-ysato@users.sourceforge.jp> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20210527052122.97103-1-ysato@users.sourceforge.jp> References: <20210527052122.97103-1-ysato@users.sourceforge.jp> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer2=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: softfail client-ip=202.224.55.13; envelope-from=ysato@users.sourceforge.jp; helo=mail01.asahi-net.or.jp X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_DNSWL_LOW=-0.7, SPF_HELO_NONE=0.001, SPF_SOFTFAIL=0.665 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Yoshinori Sato Errors-To: qemu-devel-bounces+importer2=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" linux kernel require initializing some peripherals. Signed-off-by: Yoshinori Sato --- include/hw/rx/rx62n.h | 16 ++++---- hw/rx/rx-gdbsim.c | 89 +++++++++++++++++++++++++------------------ hw/rx/rx62n.c | 15 -------- 3 files changed, 59 insertions(+), 61 deletions(-) diff --git a/include/hw/rx/rx62n.h b/include/hw/rx/rx62n.h index 942ed0639f..3bbeb5da52 100644 --- a/include/hw/rx/rx62n.h +++ b/include/hw/rx/rx62n.h @@ -33,14 +33,6 @@ #include "qemu/units.h" #include "qom/object.h" =20 -#define TYPE_RX62N_MCU "rx62n-mcu" -typedef struct RX62NState RX62NState; -DECLARE_INSTANCE_CHECKER(RX62NState, RX62N_MCU, - TYPE_RX62N_MCU) - -#define TYPE_R5F562N7_MCU "r5f562n7-mcu" -#define TYPE_R5F562N8_MCU "r5f562n8-mcu" - #define EXT_CS_BASE 0x01000000 #define VECTOR_TABLE_BASE 0xffffff80 #define RX62N_CFLASH_BASE 0xfff80000 @@ -49,7 +41,7 @@ DECLARE_INSTANCE_CHECKER(RX62NState, RX62N_MCU, #define RX62N_NR_CMT 2 #define RX62N_NR_SCI 6 =20 -struct RX62NState { +typedef struct RX62NState { /*< private >*/ DeviceState parent_obj; /*< public >*/ @@ -75,5 +67,11 @@ struct RX62NState { uint32_t xtal_freq_hz; } RX62NState; =20 +#define TYPE_RX62N_MCU "rx62n-mcu" + +#define TYPE_R5F562N7_MCU "r5f562n7-mcu" +#define TYPE_R5F562N8_MCU "r5f562n8-mcu" +DECLARE_INSTANCE_CHECKER(RX62NState, RX62N_MCU, + TYPE_RX62N_MCU) =20 #endif diff --git a/hw/rx/rx-gdbsim.c b/hw/rx/rx-gdbsim.c index 75d1fec6ca..34705d953b 100644 --- a/hw/rx/rx-gdbsim.c +++ b/hw/rx/rx-gdbsim.c @@ -31,14 +31,16 @@ /* Same address of GDB integrated simulator */ #define SDRAM_BASE EXT_CS_BASE =20 +typedef struct RxGdbSimMachineClass RxGdbSimMachineClass; + struct RxGdbSimMachineClass { /*< private >*/ MachineClass parent_class; /*< public >*/ const char *mcu_name; uint32_t xtal_freq_hz; + size_t romsize; }; -typedef struct RxGdbSimMachineClass RxGdbSimMachineClass; =20 struct RxGdbSimMachineState { /*< private >*/ @@ -54,26 +56,50 @@ DECLARE_OBJ_CHECKERS(RxGdbSimMachineState, RxGdbSimMach= ineClass, RX_GDBSIM_MACHINE, TYPE_RX_GDBSIM_MACHINE) =20 =20 -static void rx_load_image(RXCPU *cpu, const char *filename, - uint32_t start, uint32_t size) +#define TINYBOOT_TOP (0xffffff00) + +static void set_bootstrap(hwaddr entry, hwaddr dtb) { - static uint32_t extable[32]; - long kernel_size; + /* Minimal hardware initialize for kernel requirement */ + /* linux kernel only works little-endian mode */ + static uint8_t tinyboot[256] =3D { + 0xfb, 0x2e, 0x20, 0x00, 0x08, /* mov.l #0x80020, r2 */ + 0xf8, 0x2e, 0x00, 0x01, 0x01, /* mov.l #0x00010100, [r2] */ + 0xfb, 0x2e, 0x10, 0x00, 0x08, /* mov.l #0x80010, r2 */ + 0xf8, 0x22, 0xdf, 0x7d, 0xff, 0xff, /* mov.l #0xffff7ddf, [r2] */ + 0x62, 0x42, /* add #4, r2 */ + 0xf8, 0x22, 0xff, 0x7f, 0xff, 0x7f, /* mov.l #0x7fff7fff, [r2] */ + 0xfb, 0x2e, 0x40, 0x82, 0x08, /* mov.l #0x88240, r2 */ + 0x3c, 0x22, 0x00, /* mov.b #0, 2[r2] */ + 0x3c, 0x21, 0x4e, /* mov.b #78, 1[r2] */ + 0xfb, 0x22, 0x70, 0xff, 0xff, 0xff, /* mov.l #0xffffff70, r2 */ + 0xec, 0x21, /* mov.l [r2], r1 */ + 0xfb, 0x22, 0x74, 0xff, 0xff, 0xff, /* mov.l #0xffffff74, r2 */ + 0xec, 0x22, /* mov.l [r2], r2 */ + 0x7f, 0x02, /* jmp r2 */ + }; int i; =20 + *((uint32_t *)&tinyboot[0x70]) =3D cpu_to_le32(dtb); + *((uint32_t *)&tinyboot[0x74]) =3D cpu_to_le32(entry); + + /* setup exception trap trampoline */ + for (i =3D 0; i < 31; i++) { + *((uint32_t *)&tinyboot[0x80 + i * 4]) =3D cpu_to_le32(0x10 + i * = 4); + } + *((uint32_t *)&tinyboot[0xfc]) =3D cpu_to_le32(TINYBOOT_TOP); + rom_add_blob_fixed("tinyboot", tinyboot, sizeof(tinyboot), TINYBOOT_TO= P); +} + +static void load_kernel(const char *filename, uint32_t start, uint32_t siz= e) +{ + long kernel_size; + kernel_size =3D load_image_targphys(filename, start, size); if (kernel_size < 0) { fprintf(stderr, "qemu: could not load kernel '%s'\n", filename); exit(1); } - cpu->env.pc =3D start; - - /* setup exception trap trampoline */ - /* linux kernel only works little-endian mode */ - for (i =3D 0; i < ARRAY_SIZE(extable); i++) { - extable[i] =3D cpu_to_le32(0x10 + i * 4); - } - rom_add_blob_fixed("extable", extable, sizeof(extable), VECTOR_TABLE_B= ASE); } =20 static void rx_gdbsim_init(MachineState *machine) @@ -101,33 +127,15 @@ static void rx_gdbsim_init(MachineState *machine) &error_abort); object_property_set_uint(OBJECT(&s->mcu), "xtal-frequency-hz", rxc->xtal_freq_hz, &error_abort); - object_property_set_bool(OBJECT(&s->mcu), "load-kernel", - kernel_filename !=3D NULL, &error_abort); - - if (!kernel_filename) { - if (machine->firmware) { - rom_add_file_fixed(machine->firmware, RX62N_CFLASH_BASE, 0); - } else if (!qtest_enabled()) { - error_report("No bios or kernel specified"); - exit(1); - } - } - - qdev_realize(DEVICE(&s->mcu), NULL, &error_abort); - /* Load kernel and dtb */ if (kernel_filename) { ram_addr_t kernel_offset; - - /* - * The kernel image is loaded into - * the latter half of the SDRAM space. - */ + ram_addr_t dtb_offset =3D 0; kernel_offset =3D machine->ram_size / 2; - rx_load_image(RX_CPU(first_cpu), kernel_filename, - SDRAM_BASE + kernel_offset, kernel_offset); + + load_kernel(machine->kernel_filename, + SDRAM_BASE + kernel_offset, kernel_offset); if (dtb_filename) { - ram_addr_t dtb_offset; int dtb_size; g_autofree void *dtb =3D load_device_tree(dtb_filename, &dtb_s= ize); =20 @@ -145,10 +153,17 @@ static void rx_gdbsim_init(MachineState *machine) dtb_offset =3D machine->ram_size - dtb_size; rom_add_blob_fixed("dtb", dtb, dtb_size, SDRAM_BASE + dtb_offset); - /* Set dtb address to R1 */ - RX_CPU(first_cpu)->env.regs[1] =3D SDRAM_BASE + dtb_offset; + } + set_bootstrap(SDRAM_BASE + kernel_offset, SDRAM_BASE + dtb_offset); + } else { + if (machine->firmware) { + rom_add_file_fixed(machine->firmware, RX62N_CFLASH_BASE, 0); + } else if (!qtest_enabled()) { + error_report("No bios or kernel specified"); + exit(1); } } + qdev_realize(DEVICE(&s->mcu), NULL, &error_abort); } =20 static void rx_gdbsim_class_init(ObjectClass *oc, void *data) diff --git a/hw/rx/rx62n.c b/hw/rx/rx62n.c index 58eff0b4a3..d84ffa148c 100644 --- a/hw/rx/rx62n.c +++ b/hw/rx/rx62n.c @@ -58,20 +58,6 @@ #define RX62N_XTAL_MIN_HZ (8 * 1000 * 1000) #define RX62N_XTAL_MAX_HZ (14 * 1000 * 1000) =20 -struct RX62NClass { - /*< private >*/ - DeviceClass parent_class; - /*< public >*/ - const char *name; - uint64_t ram_size; - uint64_t rom_flash_size; - uint64_t data_flash_size; -}; -typedef struct RX62NClass RX62NClass; - -DECLARE_CLASS_CHECKERS(RX62NClass, RX62N_MCU, - TYPE_RX62N_MCU) - /* * IRQ -> IPR mapping table * 0x00 - 0x91: IPR no (IPR00 to IPR91) @@ -281,7 +267,6 @@ static void rx62n_realize(DeviceState *dev, Error **err= p) static Property rx62n_properties[] =3D { DEFINE_PROP_LINK("main-bus", RX62NState, sysmem, TYPE_MEMORY_REGION, MemoryRegion *), - DEFINE_PROP_BOOL("load-kernel", RX62NState, kernel, false), DEFINE_PROP_UINT32("xtal-frequency-hz", RX62NState, xtal_freq_hz, 0), DEFINE_PROP_END_OF_LIST(), }; --=20 2.20.1