From nobody Sun Nov 16 04:02:32 2025 Delivered-To: importer@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+importer=patchew.org@nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1598532012; cv=none; d=zohomail.com; s=zohoarc; b=ebna9JrPnckNXnJf9VVEBMZXFaF8iOh5a1FVgQjoyrvDcA+UwioQuthFeDgEXUjducAGNJaf2kn15uQZ4iIolFzk8RNzACGbsqBslvSAmqVYcabgJ0Ug+SaeRHLWRnKeiyyuNpNEb0hldYs1uc1Qu3W9l27Juu7t1VbmdaHw57k= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1598532012; 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=IQacQcqaP5YbZ8+c/JAGPkQYLXH3iM9mSKVsgTk84gs=; b=gYRP/a9Ui58HJus8DZMn/h1Vyv5CtSJyn6lU8yDdEwqij47Jy5Ct3sKO/BoDRUXKtEdutMMv7yKXkla/jUmrO4tNzOMRBaHuqnILkncGKR0UVsY8rjOdkla4CweXM7a3ju1NA1+HRmdB9SJHdM2BHh1q6nbf5DZF/dKfMKuteAU= 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+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1598532012285732.2964947511842; Thu, 27 Aug 2020 05:40:12 -0700 (PDT) Received: from localhost ([::1]:39184 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kBHCM-0001Kt-TV for importer@patchew.org; Thu, 27 Aug 2020 08:40:10 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:58938) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kBHBR-0007xe-IZ for qemu-devel@nongnu.org; Thu, 27 Aug 2020 08:39:13 -0400 Received: from mail02.asahi-net.or.jp ([202.224.55.14]:56301) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kBHBN-0005u5-SJ for qemu-devel@nongnu.org; Thu, 27 Aug 2020 08:39:13 -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 84A9B25525; Thu, 27 Aug 2020 21:39:05 +0900 (JST) Received: from yo-satoh-debian.localdomain (ZM005235.ppp.dion.ne.jp [222.8.5.235]) by sakura.ysato.name (Postfix) with ESMTPSA id 0BBA51C0792; Thu, 27 Aug 2020 21:39:05 +0900 (JST) From: Yoshinori Sato To: qemu-devel@nongnu.org Subject: [PATCH 01/20] loader.c: Add support Motrola S-record format. Date: Thu, 27 Aug 2020 21:38:40 +0900 Message-Id: <20200827123859.81793-2-ysato@users.sourceforge.jp> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200827123859.81793-1-ysato@users.sourceforge.jp> References: <20200827123859.81793-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+importer=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-detected-operating-system: by eggs.gnu.org: First seen = 2020/08/27 08:39:06 X-ACL-Warn: Detected OS = ??? 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+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" Signed-off-by: Yoshinori Sato --- include/hw/loader.h | 14 +++ hw/core/loader.c | 208 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 222 insertions(+) diff --git a/include/hw/loader.h b/include/hw/loader.h index a9eeea3952..6f1fb62ded 100644 --- a/include/hw/loader.h +++ b/include/hw/loader.h @@ -55,6 +55,20 @@ int load_image_targphys_as(const char *filename, */ int load_targphys_hex_as(const char *filename, hwaddr *entry, AddressSpace= *as); =20 +/* + * load_targphys_srec_as: + * @filename: Path to the .hex file + * @entry: Store the entry point given by the .hex file + * @as: The AddressSpace to load the .hex file to. The value of + * address_space_memory is used if nothing is supplied here. + * + * Load a fixed .srec file into memory. + * + * Returns the size of the loaded .hex file on success, -1 otherwise. + */ +int load_targphys_srec_as(const char *filename, + hwaddr *entry, AddressSpace *as); + /** load_image_targphys: * Same as load_image_targphys_as(), but doesn't allow the caller to speci= fy * an AddressSpace. diff --git a/hw/core/loader.c b/hw/core/loader.c index 8bbb1797a4..6964b04ec7 100644 --- a/hw/core/loader.c +++ b/hw/core/loader.c @@ -1618,3 +1618,211 @@ int load_targphys_hex_as(const char *filename, hwad= dr *entry, AddressSpace *as) g_free(hex_blob); return total_size; } + +typedef enum { + SREC_SOH, + SREC_TYPE, + SREC_LEN, + SREC_ADDR, + SREC_DATA, + SREC_SKIP, + SREC_SUM, +} srec_state; + +typedef struct { + srec_state state; + int nibble; + int total_size; + uint32_t address; + uint32_t topaddr; + uint32_t bufremain; + int length; + int addr_len; + int record_type; + uint8_t byte; + uint8_t data[DATA_FIELD_MAX_LEN]; + uint8_t *datap; + uint8_t *bufptr; + uint8_t sum; +} SrecLine; + +static bool parse_srec_line(SrecLine *line, char c) +{ + if (!g_ascii_isxdigit(c)) { + return false; + } + line->byte <<=3D 4; + line->byte |=3D g_ascii_xdigit_value(c); + line->nibble++; + if (line->nibble =3D=3D 2) { + line->nibble =3D 0; + line->length--; + line->sum +=3D line->byte; + switch (line->state) { + case SREC_SOH: + case SREC_TYPE: + /* first 2chars ignore parse */ + break; + case SREC_LEN: + line->sum =3D line->length =3D line->byte; + if (line->addr_len > 0) { + line->state =3D SREC_ADDR; + line->address =3D 0; + } else { + line->state =3D SREC_SKIP; + } + break; + case SREC_ADDR: + line->address <<=3D 8; + line->address |=3D line->byte; + if (--line->addr_len =3D=3D 0) { + if (line->length > 1) { + if (line->record_type !=3D 0) { + line->state =3D SREC_DATA; + } else { + line->state =3D SREC_SKIP; + } + line->datap =3D line->data; + } else { + line->state =3D SREC_SUM; + } + } + break; + case SREC_DATA: + *line->datap++ =3D line->byte; + /* fail through */ + case SREC_SKIP: + if (line->length =3D=3D 1) { + line->state =3D SREC_SUM; + } + break; + case SREC_SUM: + if ((line->sum & 0xff) !=3D 0xff) { + return false; + } + } + } + return true; +} + +#define SRECBUFSIZE 0x40000 + +/* return size or -1 if error */ +static int parse_srec_blob(const char *filename, hwaddr *addr, + uint8_t *hex_blob, size_t hex_blob_size, + AddressSpace *as) +{ + SrecLine line; + size_t len; + int total_len =3D 0; + uint8_t *end =3D hex_blob + hex_blob_size; + rom_transaction_begin(); + line.state =3D SREC_SOH; + line.bufptr =3D g_malloc(SRECBUFSIZE); + line.bufremain =3D SRECBUFSIZE; + line.topaddr =3D UINT32_MAX; + for (; hex_blob < end; ++hex_blob) { + switch (*hex_blob) { + case '\r': + case '\n': + if (line.state =3D=3D SREC_SUM) { + switch (line.record_type) { + case 1: + case 2: + case 3: + len =3D line.datap - line.data; + if (line.topaddr =3D=3D UINT32_MAX) { + line.topaddr =3D line.address; + } + if (line.bufremain < len || line.address < line.topadd= r) { + rom_add_blob_fixed_as(filename, line.bufptr, + SRECBUFSIZE - line.bufremain, + line.topaddr, as); + line.topaddr =3D line.address; + line.bufremain =3D SRECBUFSIZE; + } + memcpy(line.bufptr + (line.address - line.topaddr), + line.data, len); + line.bufremain -=3D len; + total_len +=3D len; + break; + case 7: + case 8: + case 9: + *addr =3D line.address; + break; + } + line.state =3D SREC_SOH; + } + break; + /* start of a new record. */ + case 'S': + if (line.state !=3D SREC_SOH) { + total_len =3D -1; + goto out; + } + line.state =3D SREC_TYPE; + break; + /* decoding lines */ + default: + if (line.state =3D=3D SREC_TYPE) { + if (g_ascii_isdigit(*hex_blob)) { + line.record_type =3D g_ascii_digit_value(*hex_blob); + switch (line.record_type) { + case 1: + case 2: + case 3: + line.addr_len =3D 1 + line.record_type; + break; + case 0: + case 5: + line.addr_len =3D 2; + break; + case 7: + case 8: + case 9: + line.addr_len =3D 11 - line.record_type; + break; + default: + line.addr_len =3D 0; + } + } + line.state =3D SREC_LEN; + line.nibble =3D 0; + } else { + if (!parse_srec_line(&line, *hex_blob)) { + total_len =3D -1; + goto out; + } + } + break; + } + } + if (line.bufremain < SRECBUFSIZE) { + rom_add_blob_fixed_as(filename, line.bufptr, + SRECBUFSIZE - line.bufremain, + line.topaddr, as); + } +out: + rom_transaction_end(total_len !=3D -1); + g_free(line.bufptr); + return total_len; +} + +/* return size or -1 if error */ +int load_targphys_srec_as(const char *filename, hwaddr *entry, AddressSpac= e *as) +{ + gsize hex_blob_size; + gchar *hex_blob; + int total_size =3D 0; + + if (!g_file_get_contents(filename, &hex_blob, &hex_blob_size, NULL)) { + return -1; + } + + total_size =3D parse_srec_blob(filename, entry, (uint8_t *)hex_blob, + hex_blob_size, as); + + g_free(hex_blob); + return total_size; +} --=20 2.20.1 From nobody Sun Nov 16 04:02:32 2025 Delivered-To: importer@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+importer=patchew.org@nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1598532004; cv=none; d=zohomail.com; s=zohoarc; b=n5CNqsjCh4o4vqlYzralOfrinszPOx2DuM7aJolr7p8JB15gMJaEOZSdBvk9bWYFI3B4P3MzlvWX8qRMQmhT6Hfp/1KfpWegE+55yygE1EEHjfetYg6WUM9D0dkT1YdzUsYbSWR3XyrN2Xelyofp32D40nhmhRKusWpka1zAhJg= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1598532004; 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=pl/yhDZegd9Oq5xFM+4XkSAzYI66ANgvA2qjgwXd9hI=; b=GSBF2F5qvRomWVsa0ySVQtQ3e3VWfeovM2TY4MC0UeWicy3XkENwjaIBU9Ma6vQY8zXK4tMvolAqM/h7MjGtiT3P83Tj6sLyU9nY2scYGKIZZEIP8QzCpLpvIKTNNp0r3RaxporeR9C+QhhXx2X3GHEKniN3L8LGzLFYoaEce8o= 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+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1598532004251617.4514198603986; Thu, 27 Aug 2020 05:40:04 -0700 (PDT) Received: from localhost ([::1]:38828 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kBHCE-0001CD-V3 for importer@patchew.org; Thu, 27 Aug 2020 08:40:03 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:58912) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kBHBQ-0007xI-LS for qemu-devel@nongnu.org; Thu, 27 Aug 2020 08:39:12 -0400 Received: from mail01.asahi-net.or.jp ([202.224.55.13]:47876) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kBHBN-0005u9-UT for qemu-devel@nongnu.org; Thu, 27 Aug 2020 08:39:12 -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 A3322108660; Thu, 27 Aug 2020 21:39:05 +0900 (JST) Received: from yo-satoh-debian.localdomain (ZM005235.ppp.dion.ne.jp [222.8.5.235]) by sakura.ysato.name (Postfix) with ESMTPSA id 43B4C1C07A8; Thu, 27 Aug 2020 21:39:05 +0900 (JST) From: Yoshinori Sato To: qemu-devel@nongnu.org Subject: [PATCH 02/20] include/elf.h: Add EM_RX. Date: Thu, 27 Aug 2020 21:38:41 +0900 Message-Id: <20200827123859.81793-3-ysato@users.sourceforge.jp> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200827123859.81793-1-ysato@users.sourceforge.jp> References: <20200827123859.81793-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+importer=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-detected-operating-system: by eggs.gnu.org: First seen = 2020/08/27 08:39:06 X-ACL-Warn: Detected OS = ??? 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+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" Signed-off-by: Yoshinori Sato --- include/elf.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/elf.h b/include/elf.h index c117a4d1ab..d9bf4a95d8 100644 --- a/include/elf.h +++ b/include/elf.h @@ -172,6 +172,8 @@ typedef struct mips_elf_abiflags_v0 { =20 #define EM_UNICORE32 110 /* UniCore32 */ =20 +#define EM_RX 173 /* Renesas RX family */ + #define EM_RISCV 243 /* RISC-V */ =20 #define EM_NANOMIPS 249 /* Wave Computing nanoMIPS */ --=20 2.20.1 From nobody Sun Nov 16 04:02:32 2025 Delivered-To: importer@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+importer=patchew.org@nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1598532003; cv=none; d=zohomail.com; s=zohoarc; b=Yss2R/sXXbz7k9vxR8OeBnXGIug2mr8kz2hEXC26MenybMFO9qi13hkqIh93x05D1KnjXFUcd+HNkWRuSpAxddbHfM3hfu2dSv3gY785INZCMzgJpKSti9LYnkwxAE5w8P/9v06rEePqBeglAxFRytOKUdz495L86P9JDvPDpog= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1598532003; 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=HDsHFtC7DfdxNrX6DNTLYtSHI5I+A9ONNjRkCoz7VEI=; b=P4Ss5g7MxLeDuIx/aOF9XgZ4lSnFnaEahyR/dlRLPkoczcc3M+lPimIbjLZd6y8ZC25bkaxGHX9VuS8vPk6jW5LpUq/WSNfto5ZTvE15MvYEZ3p9O7YO/tytoBXPDiaL9+FGAHOQH5HuT1bhAE1oHcCJOs5XSGzPlBv0qsPxyjU= 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+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 15985320030721009.9528799557985; Thu, 27 Aug 2020 05:40:03 -0700 (PDT) Received: from localhost ([::1]:38742 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kBHCD-0001AB-NJ for importer@patchew.org; Thu, 27 Aug 2020 08:40:01 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:58900) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kBHBQ-0007xC-6F for qemu-devel@nongnu.org; Thu, 27 Aug 2020 08:39:12 -0400 Received: from mail02.asahi-net.or.jp ([202.224.55.14]:56302) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kBHBN-0005u8-TJ for qemu-devel@nongnu.org; Thu, 27 Aug 2020 08:39:11 -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 CC51026329; Thu, 27 Aug 2020 21:39:05 +0900 (JST) Received: from yo-satoh-debian.localdomain (ZM005235.ppp.dion.ne.jp [222.8.5.235]) by sakura.ysato.name (Postfix) with ESMTPSA id 7C96C1C07B2; Thu, 27 Aug 2020 21:39:05 +0900 (JST) From: Yoshinori Sato To: qemu-devel@nongnu.org Subject: [PATCH 03/20] hw/rx: Firmware and kernel loader. Date: Thu, 27 Aug 2020 21:38:42 +0900 Message-Id: <20200827123859.81793-4-ysato@users.sourceforge.jp> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200827123859.81793-1-ysato@users.sourceforge.jp> References: <20200827123859.81793-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+importer=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-detected-operating-system: by eggs.gnu.org: First seen = 2020/08/27 08:39:06 X-ACL-Warn: Detected OS = ??? 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+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" Suppoerted format. ELF, HEX, SREC and Raw firmware. fit and Raw kernel image. Signed-off-by: Yoshinori Sato --- include/hw/rx/loader.h | 35 ++++++++ hw/rx/loader.c | 182 +++++++++++++++++++++++++++++++++++++++++ hw/rx/Kconfig | 1 + hw/rx/meson.build | 1 + 4 files changed, 219 insertions(+) create mode 100644 include/hw/rx/loader.h create mode 100644 hw/rx/loader.c diff --git a/include/hw/rx/loader.h b/include/hw/rx/loader.h new file mode 100644 index 0000000000..71f3bd2bb3 --- /dev/null +++ b/include/hw/rx/loader.h @@ -0,0 +1,35 @@ +/* + * RX QEMU frimware loader + * + * 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 "qapi/error.h" +#include "qemu/error-report.h" + +typedef struct { + hwaddr ram_start; + size_t ram_size; + hwaddr entry; + hwaddr kernel_entry; + hwaddr dtb_address; + const char *filename; + const char *dtbname; + const char *cmdline; +} rx_kernel_info_t; + +bool load_bios(const char *filename, int rom_size, Error **errp); + +bool load_kernel(rx_kernel_info_t *info); diff --git a/hw/rx/loader.c b/hw/rx/loader.c new file mode 100644 index 0000000000..c262f3ef86 --- /dev/null +++ b/hw/rx/loader.c @@ -0,0 +1,182 @@ +/* + * RX QEMU frimware loader + * + * 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 "elf.h" +#include "hw/loader.h" +#include "hw/loader-fit.h" +#include "hw/rx/loader.h" +#include "sysemu/device_tree.h" +#include "exec/cpu-defs.h" +#include + +#define RX_RESET_VEC 0xfffffffc +#define ADDRESS_TOP ((1LL << TARGET_PHYS_ADDR_SPACE_BITS) - 1) + +bool load_bios(const char *filename, int rom_size, Error **errp) +{ + int size; + uint64_t entry64 =3D UINT64_MAX; + uint32_t entry; + + size =3D load_elf(filename, NULL, NULL, NULL, &entry64, + NULL, NULL, NULL, 0, EM_RX, 0, 0); + if (size > 0) { + goto load_ok; + } + size =3D load_targphys_hex_as(filename, &entry64, NULL); + if (size > 0) { + goto load_ok; + } + size =3D load_targphys_srec_as(filename, &entry64, NULL); + if (size > 0) { + goto load_ok; + } + size =3D get_image_size(filename); + if (size < 0) { + error_setg(errp, "\"%s\" is open failed.", filename); + return false; + } + if (size > rom_size) { + error_setg(errp, "\"%s\" is too large for ROM area.", filename); + return false; + } + + /* + * The RX CPU reset vector is at the top of the ROM, + * so the raw binary is loaded there. + */ + rom_add_file_fixed(filename, -size, 0); + load_ok: + if (rom_ptr(RX_RESET_VEC, 4) =3D=3D NULL) { + if (entry64 <=3D ADDRESS_TOP) { + entry =3D cpu_to_le32(entry64); + rom_add_blob_fixed("entry", &entry, 4, RX_RESET_VEC); + } else { + error_setg(errp, "Reset vector is not set"); + return false; + } + } + return true; +} + +static hwaddr rx_addr_to_phys(void *opaque, uint64_t addr) +{ + /* No address translation */ + return addr; +} + +static bool setup_commandline(void *dtb, rx_kernel_info_t *info) +{ + if (info->cmdline && + qemu_fdt_setprop_string(dtb, "/chosen", "bootargs", + info->cmdline) < 0) { + return false; + } + return true; +} + + +static const void *rx_fdt_filter(void *opaque, const void *fdt_orig, + const void *match_data, hwaddr *load_addr) +{ + rx_kernel_info_t *info =3D opaque; + void *fdt; + size_t fdt_sz; + int err; + + fdt_sz =3D fdt_totalsize(fdt_orig) + 0x1000; + fdt =3D g_malloc0(fdt_sz); + + err =3D fdt_open_into(fdt_orig, fdt, fdt_sz); + if (err) { + error_report("couldn't open dtb"); + return NULL; + } + + if (!setup_commandline(fdt, info)) { + error_report("couldn't set /chosen/bootargs"); + return NULL; + } + fdt_sz =3D fdt_totalsize(fdt); + fdt =3D g_realloc(fdt, fdt_totalsize(fdt)); + info->dtb_address =3D info->ram_start + info->ram_size - fdt_sz; + *load_addr =3D info->dtb_address; + + return fdt; +} + +static const void *rx_kernel_filter(void *opaque, const void *kernel, + hwaddr *load_addr, hwaddr *entry_a= ddr) +{ + rx_kernel_info_t *info =3D opaque; + + info->kernel_entry =3D *entry_addr; + + return kernel; +} + +static const struct fit_loader rx_fit_loader =3D { + .addr_to_phys =3D rx_addr_to_phys, + .fdt_filter =3D rx_fdt_filter, + .kernel_filter =3D rx_kernel_filter, +}; + +bool load_kernel(rx_kernel_info_t *info) +{ + ram_addr_t kernel_offset; + size_t kernel_size; + + if (load_fit(&rx_fit_loader, info->filename, info) =3D=3D 0) { + return true; + } + + /* + * The kernel image is loaded into + * the latter half of the SDRAM space. + */ + kernel_offset =3D info->ram_size / 2; + + info->entry =3D info->ram_start + kernel_offset; + kernel_size =3D load_image_targphys(info->filename, + info->entry, info->ram_size / 2); + if (kernel_size =3D=3D -1) { + return false; + } + if (info->dtbname) { + ram_addr_t dtb_offset; + int dtb_size; + void *dtb; + + dtb =3D load_device_tree(info->dtbname, &dtb_size); + if (dtb =3D=3D NULL) { + error_report("Couldn't open dtb file %s", info->dtbname); + return false; + } + if (!setup_commandline(dtb, info)) { + error_report("Couldn't set /chosen/bootargs"); + return false; + } + /* DTB is located at the end of SDRAM space. */ + dtb_size =3D fdt_totalsize(dtb); + dtb_offset =3D info->ram_size - dtb_size; + info->dtb_address =3D info->ram_start + dtb_offset; + rom_add_blob_fixed("dtb", dtb, dtb_size, info->dtb_address); + } + return true; +} diff --git a/hw/rx/Kconfig b/hw/rx/Kconfig index 2b297c5a6a..a63e4a5520 100644 --- a/hw/rx/Kconfig +++ b/hw/rx/Kconfig @@ -8,3 +8,4 @@ config RX62N_MCU config RX_GDBSIM bool select RX62N_MCU + select FITLOADER diff --git a/hw/rx/meson.build b/hw/rx/meson.build index d223512a78..e73850f303 100644 --- a/hw/rx/meson.build +++ b/hw/rx/meson.build @@ -1,4 +1,5 @@ rx_ss =3D ss.source_set() +rx_ss.add(files('loader.c')) 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')) =20 --=20 2.20.1 From nobody Sun Nov 16 04:02:32 2025 Delivered-To: importer@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+importer=patchew.org@nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1598532084; cv=none; d=zohomail.com; s=zohoarc; b=cGju5gjuqeUefwRTsjsWMrx8KfvkMy7OnIeAL+L2JgBWIF6QLhz5K40Q2OzYSZsZSiHrOql8/A2xsWdAY+42I5cCK9L7E3RFNghkubrmLfirhi+vX0qO+QBK0YLnQzFa7Xw2QuzglhxBOowrxLNFvTaNUO7m3hLIYdZyGc48zaY= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1598532084; 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=j6RtC7e7UICBfn73UWPONf7rjXb7wHhAIN1T8ULvLWI=; b=NpSR29OWQWXUxieHCbj77pfJK88wwZLyBFVc88/ziz/TGIEYwDT5ADBOWtlgV5hUlGkIOvga2DX9nqO7I0CTVcwSe+OoQYmhqIrBvPxYWein6pRLC5Hekltjd+JvGctL5mu69+vinA6oR7NURdNib+VJL0SI8SZIrOjwowj6Vds= 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+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1598532084909170.84970499428516; Thu, 27 Aug 2020 05:41:24 -0700 (PDT) Received: from localhost ([::1]:47024 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kBHDX-0004Yd-Ic for importer@patchew.org; Thu, 27 Aug 2020 08:41:23 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:58958) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kBHBS-0007yC-83 for qemu-devel@nongnu.org; Thu, 27 Aug 2020 08:39:14 -0400 Received: from mail01.asahi-net.or.jp ([202.224.55.13]:47877) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kBHBN-0005uA-Tb for qemu-devel@nongnu.org; Thu, 27 Aug 2020 08:39:13 -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 045621080B5; Thu, 27 Aug 2020 21:39:06 +0900 (JST) Received: from yo-satoh-debian.localdomain (ZM005235.ppp.dion.ne.jp [222.8.5.235]) by sakura.ysato.name (Postfix) with ESMTPSA id B23DE1C0696; Thu, 27 Aug 2020 21:39:05 +0900 (JST) From: Yoshinori Sato To: qemu-devel@nongnu.org Subject: [PATCH 04/20] hw/rx: New firmware loader. Date: Thu, 27 Aug 2020 21:38:43 +0900 Message-Id: <20200827123859.81793-5-ysato@users.sourceforge.jp> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200827123859.81793-1-ysato@users.sourceforge.jp> References: <20200827123859.81793-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+importer=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-detected-operating-system: by eggs.gnu.org: First seen = 2020/08/27 08:39:06 X-ACL-Warn: Detected OS = ??? 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+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" Separate the loading of the firmware from the target definition as it is an obstacle to adding more targets. Signed-off-by: Yoshinori Sato --- include/hw/rx/rx62n.h | 15 +++++++ hw/rx/rx-gdbsim.c | 98 +++++++++++++++++++++---------------------- hw/rx/rx62n.c | 25 ----------- 3 files changed, 64 insertions(+), 74 deletions(-) diff --git a/include/hw/rx/rx62n.h b/include/hw/rx/rx62n.h index aa94758c27..32e460bbad 100644 --- a/include/hw/rx/rx62n.h +++ b/include/hw/rx/rx62n.h @@ -45,6 +45,21 @@ #define RX62N_NR_CMT 2 #define RX62N_NR_SCI 6 =20 +typedef struct RX62NClass { + /*< private >*/ + DeviceClass parent_class; + /*< public >*/ + const char *name; + uint64_t ram_size; + uint64_t rom_flash_size; + uint64_t data_flash_size; +} RX62NClass; + +#define RX62N_MCU_CLASS(klass) \ + OBJECT_CLASS_CHECK(RX62NClass, (klass), TYPE_RX62N_MCU) +#define RX62N_MCU_GET_CLASS(obj) \ + OBJECT_GET_CLASS(RX62NClass, (obj), TYPE_RX62N_MCU) + typedef struct RX62NState { /*< private >*/ DeviceState parent_obj; diff --git a/hw/rx/rx-gdbsim.c b/hw/rx/rx-gdbsim.c index 54992ebe57..02e03c797c 100644 --- a/hw/rx/rx-gdbsim.c +++ b/hw/rx/rx-gdbsim.c @@ -25,6 +25,7 @@ #include "hw/hw.h" #include "hw/sysbus.h" #include "hw/loader.h" +#include "hw/rx/loader.h" #include "hw/rx/rx62n.h" #include "sysemu/sysemu.h" #include "sysemu/qtest.h" @@ -40,6 +41,7 @@ typedef struct RxGdbSimMachineClass { /*< public >*/ const char *mcu_name; uint32_t xtal_freq_hz; + size_t romsize; } RxGdbSimMachineClass; =20 typedef struct RxGdbSimMachineState { @@ -59,26 +61,39 @@ typedef struct RxGdbSimMachineState { #define RX_GDBSIM_MACHINE_GET_CLASS(obj) \ OBJECT_GET_CLASS(RxGdbSimMachineClass, (obj), TYPE_RX_GDBSIM_MACHINE) =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 - 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; + *((uint32_t *)&tinyboot[0x70]) =3D cpu_to_le32(dtb); + *((uint32_t *)&tinyboot[0x74]) =3D cpu_to_le32(entry); =20 /* 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); + for (i =3D 0; i < 31; i++) { + *((uint32_t *)&tinyboot[0x40 + i * 4]) =3D cpu_to_le32(0x10 + i * = 4); } - rom_add_blob_fixed("extable", extable, sizeof(extable), VECTOR_TABLE_B= ASE); + *((uint32_t *)&tinyboot[0xfc - 0x40]) =3D cpu_to_le32(TINYBOOT_TOP); + rom_add_blob_fixed("tinyboot", tinyboot, sizeof(tinyboot), TINYBOOT_TO= P); } =20 static void rx_gdbsim_init(MachineState *machine) @@ -86,10 +101,11 @@ static void rx_gdbsim_init(MachineState *machine) MachineClass *mc =3D MACHINE_GET_CLASS(machine); RxGdbSimMachineState *s =3D RX_GDBSIM_MACHINE(machine); RxGdbSimMachineClass *rxc =3D RX_GDBSIM_MACHINE_GET_CLASS(machine); + RX62NClass *rx62nc; MemoryRegion *sysmem =3D get_system_memory(); const char *kernel_filename =3D machine->kernel_filename; const char *dtb_filename =3D machine->dtb; - + rx_kernel_info_t kernel_info; if (machine->ram_size < mc->default_ram_size) { char *sz =3D size_to_str(mc->default_ram_size); error_report("Invalid RAM size, should be more than %s", sz); @@ -101,49 +117,33 @@ static void rx_gdbsim_init(MachineState *machine) =20 /* Initialize MCU */ object_initialize_child(OBJECT(machine), "mcu", &s->mcu, rxc->mcu_name= ); + rx62nc =3D RX62N_MCU_GET_CLASS(&s->mcu); object_property_set_link(OBJECT(&s->mcu), "main-bus", OBJECT(sysmem), &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); - 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. - */ - kernel_offset =3D machine->ram_size / 2; - rx_load_image(RXCPU(first_cpu), kernel_filename, - SDRAM_BASE + kernel_offset, kernel_offset); - if (dtb_filename) { - ram_addr_t dtb_offset; - int dtb_size; - void *dtb; - - dtb =3D load_device_tree(dtb_filename, &dtb_size); - if (dtb =3D=3D NULL) { - error_report("Couldn't open dtb file %s", dtb_filename); - exit(1); - } - if (machine->kernel_cmdline && - qemu_fdt_setprop_string(dtb, "/chosen", "bootargs", - machine->kernel_cmdline) < 0) { - error_report("Couldn't set /chosen/bootargs"); - exit(1); + kernel_info.ram_start =3D SDRAM_BASE; + kernel_info.ram_size =3D machine->ram_size; + kernel_info.filename =3D kernel_filename; + kernel_info.dtbname =3D dtb_filename; + kernel_info.cmdline =3D machine->kernel_cmdline; + if (!load_kernel(&kernel_info)) { + exit(1); + } + set_bootstrap(kernel_info.entry, kernel_info.dtb_address); + } else { + if (bios_name) { + if (!load_bios(bios_name, rx62nc->rom_flash_size, &error_abort= )) { + exit(0); } - /* DTB is located at the end of SDRAM space. */ - 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 */ - RXCPU(first_cpu)->env.regs[1] =3D SDRAM_BASE + dtb_offset; + } 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 b9c217ebfa..4b5c3c1079 100644 --- a/hw/rx/rx62n.c +++ b/hw/rx/rx62n.c @@ -60,21 +60,6 @@ #define RX62N_XTAL_MAX_HZ (14 * 1000 * 1000) #define RX62N_PCLK_MAX_HZ (50 * 1000 * 1000) =20 -typedef struct RX62NClass { - /*< private >*/ - DeviceClass parent_class; - /*< public >*/ - const char *name; - uint64_t ram_size; - uint64_t rom_flash_size; - uint64_t data_flash_size; -} RX62NClass; - -#define RX62N_MCU_CLASS(klass) \ - OBJECT_CLASS_CHECK(RX62NClass, (klass), TYPE_RX62N_MCU) -#define RX62N_MCU_GET_CLASS(obj) \ - OBJECT_GET_CLASS(RX62NClass, (obj), TYPE_RX62N_MCU) - /* * IRQ -> IPR mapping table * 0x00 - 0x91: IPR no (IPR00 to IPR91) @@ -245,15 +230,6 @@ static void rx62n_realize(DeviceState *dev, Error **er= rp) rxc->rom_flash_size, &error_abort); memory_region_add_subregion(s->sysmem, RX62N_CFLASH_BASE, &s->c_flash); =20 - if (!s->kernel) { - if (bios_name) { - rom_add_file_fixed(bios_name, RX62N_CFLASH_BASE, 0); - } else if (!qtest_enabled()) { - error_report("No bios or kernel specified"); - exit(1); - } - } - /* Initialize CPU */ object_initialize_child(OBJECT(s), "cpu", &s->cpu, TYPE_RX62N_CPU); qdev_realize(DEVICE(&s->cpu), NULL, &error_abort); @@ -270,7 +246,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 From nobody Sun Nov 16 04:02:32 2025 Delivered-To: importer@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+importer=patchew.org@nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1598532333; cv=none; d=zohomail.com; s=zohoarc; b=O1aUM/GX+Wdx7uR40uaXiiGtp5XDVlxnHm5ufgP5lvgtnMrgH9ZFdRt1QbDAWL2zXkOpXgB345hfZPRcQljQXPkhWvDPrBDasgXVgS65i5HvvqVkNiaFpoCOpWqLLw3+rkrT75ZQwO1gkzitmUipTJUWrkVYUxnWP43JS9LKf+o= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1598532333; 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=Gt3qotUA3aOdGAEAjpN6wAS9fYReYuWE+cIUp73tjDc=; b=fypCSz7hxHOTUJrAV0rxfzkY8132N7ZtI2puhrno3f390gnJpmwskdLmCniM7DVh2YCUKdgcQE6ZIFEBftkSwGPPt2rpEvJfA0qMc4ZgaYRIT19EcYXvrUNXrsIdz2g7evzFYHBLIvUFDaV+8l1EKMEqsV+aiDYzfeyOk3jkJPU= 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+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1598532333549754.2878651090082; Thu, 27 Aug 2020 05:45:33 -0700 (PDT) Received: from localhost ([::1]:35244 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kBHHY-0002nR-3f for importer@patchew.org; Thu, 27 Aug 2020 08:45:32 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:59014) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kBHBT-00082T-Jm for qemu-devel@nongnu.org; Thu, 27 Aug 2020 08:39:15 -0400 Received: from mail03.asahi-net.or.jp ([202.224.55.15]:39208) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kBHBO-0005uR-1U for qemu-devel@nongnu.org; Thu, 27 Aug 2020 08:39:15 -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 47DB7268A6; Thu, 27 Aug 2020 21:39:06 +0900 (JST) Received: from yo-satoh-debian.localdomain (ZM005235.ppp.dion.ne.jp [222.8.5.235]) by sakura.ysato.name (Postfix) with ESMTPSA id E2D131C0792; Thu, 27 Aug 2020 21:39:05 +0900 (JST) From: Yoshinori Sato To: qemu-devel@nongnu.org Subject: [PATCH 05/20] hw/rx: Add RX62N Clock generator Date: Thu, 27 Aug 2020 21:38:44 +0900 Message-Id: <20200827123859.81793-6-ysato@users.sourceforge.jp> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200827123859.81793-1-ysato@users.sourceforge.jp> References: <20200827123859.81793-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+importer=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-detected-operating-system: by eggs.gnu.org: First seen = 2020/08/27 08:39:06 X-ACL-Warn: Detected OS = ??? 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+importer=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 | 5 +- hw/rx/rx62n-cpg.c | 344 ++++++++++++++++++++++++++++++++++++++ hw/rx/rx62n.c | 52 +++--- hw/rx/meson.build | 2 +- 5 files changed, 447 insertions(+), 28 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 32e460bbad..e0ca1cfc33 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" =20 #define TYPE_RX62N_MCU "rx62n-mcu" @@ -70,9 +71,9 @@ typedef 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; @@ -84,8 +85,6 @@ typedef 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 4b5c3c1079..ec63fa5db1 100644 --- a/hw/rx/rx62n.c +++ b/hw/rx/rx62n.c @@ -47,6 +47,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,10 +57,6 @@ #define RX62N_CMT_IRQ 28 #define RX62N_SCI_IRQ 214 =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) - /* * IRQ -> IPR mapping table * 0x00 - 0x91: IPR no (IPR00 to IPR91) @@ -149,36 +146,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) @@ -190,7 +196,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; @@ -200,26 +205,23 @@ 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); RX62NClass *rxc =3D RX62N_MCU_GET_CLASS(dev); =20 - if (s->xtal_freq_hz =3D=3D 0) { - error_setg(errp, "\"xtal-frequency-hz\" property must be provided.= "); - return; - } - /* XTAL range: 8-14 MHz */ - if (s->xtal_freq_hz < RX62N_XTAL_MIN_HZ - || s->xtal_freq_hz > RX62N_XTAL_MAX_HZ) { - 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); @@ -236,11 +238,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 e73850f303..3a81d85a53 100644 --- a/hw/rx/meson.build +++ b/hw/rx/meson.build @@ -1,6 +1,6 @@ rx_ss =3D ss.source_set() rx_ss.add(files('loader.c')) 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 Nov 16 04:02:32 2025 Delivered-To: importer@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+importer=patchew.org@nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1598532439; cv=none; d=zohomail.com; s=zohoarc; b=DWxPSMrq2tC7LDsUf+ChXcyPN6WLMygr/9Hm89l6+VoSDDdNZ7IoEXDXWTF2Wy9p8h6sA+wj2YAAa90zlLZnvHOAHO3ZWCLqxQB4TT/fwVTxj5WHGqFU0LwBeF48nbJbGTI++i/fwwHMgka6+rL/XE1fWL6+5BARejgcK4wymaE= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1598532439; 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=6Pn4gb50QenLrQ4+kK0Up54TDf2H31SIiiLqmwVXnGc=; b=nFi4O8qwaAclHMdW1R9FAGBKgG+Ui8Kz2QCE/5vQsaYvzSDvegOYhUAMb6QqoM3SgTmKNk+/shmxcXPbeqs2bL2y4kUQKBwMoU7cagfPo5GmIp2zBifb+BySoX75opwlozLrqWdJ1QLajA0wYc3cEaNEb+yf6+htcfGEwSSX2ro= 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+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1598532439330291.6581999554197; Thu, 27 Aug 2020 05:47:19 -0700 (PDT) Received: from localhost ([::1]:42178 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kBHJF-0005fm-VK for importer@patchew.org; Thu, 27 Aug 2020 08:47:17 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:59022) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kBHBT-00083F-RO for qemu-devel@nongnu.org; Thu, 27 Aug 2020 08:39:15 -0400 Received: from mail03.asahi-net.or.jp ([202.224.55.15]:39211) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kBHBN-0005uV-Vh for qemu-devel@nongnu.org; Thu, 27 Aug 2020 08:39:15 -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 9380A26B17; Thu, 27 Aug 2020 21:39:06 +0900 (JST) Received: from yo-satoh-debian.localdomain (ZM005235.ppp.dion.ne.jp [222.8.5.235]) by sakura.ysato.name (Postfix) with ESMTPSA id 3009B1C0696; Thu, 27 Aug 2020 21:39:06 +0900 (JST) From: Yoshinori Sato To: qemu-devel@nongnu.org Subject: [PATCH 06/20] hw/timer: Renesas 8bit timer emulation. Date: Thu, 27 Aug 2020 21:38:45 +0900 Message-Id: <20200827123859.81793-7-ysato@users.sourceforge.jp> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200827123859.81793-1-ysato@users.sourceforge.jp> References: <20200827123859.81793-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+importer=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-detected-operating-system: by eggs.gnu.org: First seen = 2020/08/27 08:39:06 X-ACL-Warn: Detected OS = ??? 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+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" Rewrite for clock API. Signed-off-by: Yoshinori Sato --- include/hw/timer/renesas_tmr.h | 55 ---- include/hw/timer/renesas_tmr8.h | 67 ++++ hw/timer/renesas_tmr.c | 477 ---------------------------- hw/timer/renesas_tmr8.c | 540 ++++++++++++++++++++++++++++++++ hw/timer/Kconfig | 3 +- hw/timer/meson.build | 2 +- 6 files changed, 610 insertions(+), 534 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 cf3baa7a28..0000000000 --- a/include/hw/timer/renesas_tmr.h +++ /dev/null @@ -1,55 +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" - -#define TYPE_RENESAS_TMR "renesas-tmr" -#define RTMR(obj) OBJECT_CHECK(RTMRState, (obj), TYPE_RENESAS_TMR) - -enum timer_event { - cmia =3D 0, - cmib =3D 1, - ovi =3D 2, - none =3D 3, - TMR_NR_EVENTS =3D 4 -}; - -enum { - TMR_CH =3D 2, - TMR_NR_IRQ =3D 3 * TMR_CH -}; - -typedef 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]; -} RTMRState; - -#endif diff --git a/include/hw/timer/renesas_tmr8.h b/include/hw/timer/renesas_tmr= 8.h new file mode 100644 index 0000000000..23935bd4a3 --- /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" +#define RenesasTMR8(obj) \ + OBJECT_CHECK(RenesasTMR8State, (obj), TYPE_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 446f2eacdd..0000000000 --- a/hw/timer/renesas_tmr.c +++ /dev/null @@ -1,477 +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 INTERNAL 0x01 -#define 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 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; - - if (FIELD_EX8(tmr->tccr[1], TCCR, CSS) =3D=3D 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); - } - switch (FIELD_EX8(tmr->tccr[0], TCCR, CSS)) { - case INTERNAL: - elapsed =3D elapsed_time(tmr, 0, delta); - tcnt[0] =3D tmr->tcnt[0] + elapsed; - break; - case CASCADING: - if (ovf > 0) { - tcnt[0] =3D tmr->tcnt[0] + ovf; - } - break; - } - } else { - tcnt[0] =3D tmr->tcnt[0]; - tcnt[1] =3D tmr->tcnt[1]; - } - if (size =3D=3D 1) { - return tcnt[ch]; - } else { - 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); - } - 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 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 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..39deabce47 --- /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 + * + * 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; + 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) +{ + RenesasTMR8State *tmr =3D 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 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 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 RenesasTMR8(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 RenesasTMR8(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); +} + +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, +}; + +static void tmr8_register_types(void) +{ + type_register_static(&tmr8_info); +} + +type_init(tmr8_register_types) diff --git a/hw/timer/Kconfig b/hw/timer/Kconfig index 8749edfb6a..5288660cda 100644 --- a/hw/timer/Kconfig +++ b/hw/timer/Kconfig @@ -36,7 +36,7 @@ config CMSDK_APB_DUALTIMER bool select PTIMER =20 -config RENESAS_TMR +config RENESAS_TMR8 bool =20 config RENESAS_CMT @@ -44,3 +44,4 @@ config RENESAS_CMT =20 config AVR_TIMER16 bool + diff --git a/hw/timer/meson.build b/hw/timer/meson.build index 9f0a267c83..a02e45fdbd 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_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')) --=20 2.20.1 From nobody Sun Nov 16 04:02:32 2025 Delivered-To: importer@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+importer=patchew.org@nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1598532004; cv=none; d=zohomail.com; s=zohoarc; b=AUN7Ty8kpb8B8FsYex+5EcAQCd4/ALyITD5wFlFDk/Eb6CZ6Bix5xxAKKLcG5fJOvOGIdVm5BXTMDHrobuv4PsHTkCTfrWIy+Yp4qmjHRa9tPixO18Bu1wSDjDBb7Jx2ubl4zaIQiYQBaI9RE2+/Gd/tCKsWywlMFO3gDrzh3II= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1598532004; 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=GzCjR9npuMKROF8wYgtU/iKtyIlfVnMqaH5/KHHNbdQ=; b=aIdduZb3P//jMdQYIJSmikX88spS6ui1zQgJAG/TwyzpjYWln3x3Ri3ALL6QqZtK7CEUA8f/QBD9yuYKE71XsN/ojIoDsBXGKK4G8typJOX+OqzAUGu2WbW8ZxzXfF9CFSkpv6PFbHdl8xPX61cXm2GwLj8n1Z6QAT5cSP7xhsI= 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+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1598532004021760.8423571330328; Thu, 27 Aug 2020 05:40:04 -0700 (PDT) Received: from localhost ([::1]:38804 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kBHCE-0001Bd-Lr for importer@patchew.org; Thu, 27 Aug 2020 08:40:02 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:58920) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kBHBQ-0007xM-Q9 for qemu-devel@nongnu.org; Thu, 27 Aug 2020 08:39:12 -0400 Received: from mail03.asahi-net.or.jp ([202.224.55.15]:39213) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kBHBN-0005uW-Ut for qemu-devel@nongnu.org; Thu, 27 Aug 2020 08:39:12 -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 C66D52703C; Thu, 27 Aug 2020 21:39:06 +0900 (JST) Received: from yo-satoh-debian.localdomain (ZM005235.ppp.dion.ne.jp [222.8.5.235]) by sakura.ysato.name (Postfix) with ESMTPSA id 7DB941C0792; Thu, 27 Aug 2020 21:39:06 +0900 (JST) From: Yoshinori Sato To: qemu-devel@nongnu.org Subject: [PATCH 07/20] hw/rx: RX62N convert new 8bit timer. Date: Thu, 27 Aug 2020 21:38:46 +0900 Message-Id: <20200827123859.81793-8-ysato@users.sourceforge.jp> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200827123859.81793-1-ysato@users.sourceforge.jp> References: <20200827123859.81793-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+importer=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-detected-operating-system: by eggs.gnu.org: First seen = 2020/08/27 08:39:06 X-ACL-Warn: Detected OS = ??? 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+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" Signed-off-by: Yoshinori Sato --- include/hw/rx/rx62n.h | 4 ++-- hw/rx/rx62n.c | 2 +- hw/rx/Kconfig | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/hw/rx/rx62n.h b/include/hw/rx/rx62n.h index e0ca1cfc33..75945bae50 100644 --- a/include/hw/rx/rx62n.h +++ b/include/hw/rx/rx62n.h @@ -26,7 +26,7 @@ =20 #include "target/rx/cpu.h" #include "hw/intc/rx_icu.h" -#include "hw/timer/renesas_tmr.h" +#include "hw/timer/renesas_tmr8.h" #include "hw/timer/renesas_cmt.h" #include "hw/char/renesas_sci.h" #include "hw/rx/rx62n-cpg.h" @@ -68,7 +68,7 @@ typedef struct RX62NState { =20 RXCPU cpu; RXICUState icu; - RTMRState tmr[RX62N_NR_TMR]; + RenesasTMR8State tmr[RX62N_NR_TMR]; RCMTState cmt[RX62N_NR_CMT]; RSCIState sci[RX62N_NR_SCI]; RX62NCPGState cpg; diff --git a/hw/rx/rx62n.c b/hw/rx/rx62n.c index ec63fa5db1..0223396110 100644 --- a/hw/rx/rx62n.c +++ b/hw/rx/rx62n.c @@ -149,7 +149,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; diff --git a/hw/rx/Kconfig b/hw/rx/Kconfig index a63e4a5520..0406f27bee 100644 --- a/hw/rx/Kconfig +++ b/hw/rx/Kconfig @@ -1,7 +1,7 @@ config RX62N_MCU bool select RX_ICU - select RENESAS_TMR + select RENESAS_TMR8 select RENESAS_CMT select RENESAS_SCI =20 --=20 2.20.1 From nobody Sun Nov 16 04:02:32 2025 Delivered-To: importer@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+importer=patchew.org@nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1598532090; cv=none; d=zohomail.com; s=zohoarc; b=YLwc27xKxQWWEM48Xi6AlEmODl2uAAP+85e07GeJkltb6QaGCThw/SxNTOP9jO3CfPmKP+6BfKd5WuSuRdyKRtbI4zt+aRTDX9mdkRV9PMQd1eOihDGtBqqrkJQx5scYyiIu47OmiFnx3gQVzgjsp6LpQu933buBtkmR+eQFQT0= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1598532090; 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=STnL4YXSOT8TrsQL9xwkOcs2QdaNx1TdOPHDyKUizLg=; b=ZDm7iP6ThQkh3TjRMJK0kuAN+xJpyIYtZ/KWcnU//kuuqbi/GZbzO7j49yQoljNOGU6zLEnnaHketg+xSSDmM4nF1gmtWpIwR6UuRKPKXDhjI3Q9PC8RWQRjfQBRhVzv3omsF3K+Mm0Hfl1PTM/Ji9mdIvNPeVHCABkf2gM0bC8= 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+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1598532090024309.60671197583827; Thu, 27 Aug 2020 05:41:30 -0700 (PDT) Received: from localhost ([::1]:47604 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kBHDc-0004mm-L7 for importer@patchew.org; Thu, 27 Aug 2020 08:41:28 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:59000) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kBHBT-00081U-9n for qemu-devel@nongnu.org; Thu, 27 Aug 2020 08:39:15 -0400 Received: from mail01.asahi-net.or.jp ([202.224.55.13]:47883) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kBHBN-0005uu-S5 for qemu-devel@nongnu.org; Thu, 27 Aug 2020 08:39:14 -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 15835108666; Thu, 27 Aug 2020 21:39:07 +0900 (JST) Received: from yo-satoh-debian.localdomain (ZM005235.ppp.dion.ne.jp [222.8.5.235]) by sakura.ysato.name (Postfix) with ESMTPSA id B1FA71C0696; Thu, 27 Aug 2020 21:39:06 +0900 (JST) From: Yoshinori Sato To: qemu-devel@nongnu.org Subject: [PATCH 08/20] hw/timer: Renesas TMU/CMT module. Date: Thu, 27 Aug 2020 21:38:47 +0900 Message-Id: <20200827123859.81793-9-ysato@users.sourceforge.jp> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200827123859.81793-1-ysato@users.sourceforge.jp> References: <20200827123859.81793-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+importer=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-detected-operating-system: by eggs.gnu.org: First seen = 2020/08/27 08:39:06 X-ACL-Warn: Detected OS = ??? 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+importer=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 | 103 +++++ hw/timer/renesas_timer.c | 639 +++++++++++++++++++++++++++++++ hw/timer/Kconfig | 4 +- hw/timer/meson.build | 2 +- 4 files changed, 745 insertions(+), 3 deletions(-) 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..27300ae574 --- /dev/null +++ b/include/hw/timer/renesas_timer.h @@ -0,0 +1,103 @@ +/* + * 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" +#define RenesasTimerBase(obj) \ + OBJECT_CHECK(RenesasTimerBaseState, (obj), TYPE_RENESAS_TIMER_BASE) +#define TYPE_RENESAS_CMT "renesas-cmt" +#define RenesasCMT(obj) OBJECT_CHECK(RenesasCMTState, (obj), TYPE_RENESAS_= CMT) +#define TYPE_RENESAS_TMU "renesas-tmu" +#define RenesasTMU(obj) OBJECT_CHECK(RenesasTMUState, (obj), TYPE_RENESAS_= TMU) + +#define RenesasTimer_GET_CLASS(obj) \ + OBJECT_GET_CLASS(RenesasTimerBaseClass, obj, TYPE_RENESAS_TIMER_BASE) +#define TimerBaseClass(klass) \ + OBJECT_CLASS_CHECK(RenesasTimerBaseClass, klass, TYPE_RENESAS_TIMER_BA= SE) +#define CMTClass(klass) \ + OBJECT_CLASS_CHECK(RenesasCMTClass, klass, TYPE_RENESAS_CMT) +#define TMUClass(klass) \ + OBJECT_CLASS_CHECK(RenesasTMUClass, klass, TYPE_RENESAS_TMU) + +enum { + TIMER_CH_CMT =3D 2, + TIMER_CH_TMU =3D 3, +}; + +enum { + CMT_NR_IRQ =3D 1 * TIMER_CH_CMT, +}; + +struct RTIMERState; + +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 RTIMERState *tmrp; +}; + +typedef struct RenesasTimerBaseState { + SysBusDevice parent_obj; + + uint64_t input_freq; + MemoryRegion memory; + MemoryRegion memory_p4; + MemoryRegion memory_a7; + 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; +} 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..e1da328d1b --- /dev/null +++ b/hw/timer/renesas_timer.c @@ -0,0 +1,639 @@ +/* + * Renesas 16bit Compare-match timer + * + * Datasheet: RX62N Group, RX621 Group User's Manual: Hardware + * (Rev.1.40 R01UH0033EJ0140) + * + * Copyright (c) 2019 Yoshinori Sato + * + * This program is free software; you can redistribute it and/or 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 RenesasTimer_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 RenesasTimer_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 RenesasTimer_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) +{ + RenesasTimerBaseState *tmr =3D RenesasTimerBase(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 RenesasCMT(opaque); + RenesasTimerBaseState *tmr =3D RenesasTimerBase(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(RenesasTimerBase(cmt)); + } else { + ch =3D addr / 4; + if (addr < 4) { + /* skip CMSTR */ + addr--; + } + reg =3D 2 - (addr % 4); + return channel_read(RenesasTimerBase(cmt), ch, reg); + } +} + +static uint64_t tmu_read(void *opaque, hwaddr addr, unsigned size) +{ + RenesasTMUState *tmu =3D RenesasTMU(opaque); + RenesasTimerBaseState *tmr =3D RenesasTimerBase(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(RenesasTimerBase(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(RenesasTimerBase(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 RenesasTimer_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 RenesasTimerBase(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(RenesasTimerBase(tmr), ch, val, 0x0043); + } else { + channel_write(RenesasTimerBase(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 RenesasTMU(opaque); + RenesasTimerBaseState *tmr =3D RenesasTimerBase(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 RenesasCMT(dev); + RenesasTimerBaseState *tmr =3D RenesasTimerBase(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 RenesasCMT(obj); + RenesasTimerBaseState *tmr =3D RenesasTimerBase(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); +} + +static void tmu_realize(DeviceState *dev, Error **errp) +{ + SysBusDevice *d =3D SYS_BUS_DEVICE(dev); + RenesasTMUState *tmu =3D RenesasTMU(dev); + RenesasTimerBaseState *tmr =3D RenesasTimerBase(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 RenesasTimerBase(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(&tmr->memory_p4, NULL, "renesas-tmu-p4", + &tmr->memory, 0, 0x30); + sysbus_init_mmio(d, &tmr->memory_p4); + memory_region_init_alias(&tmr->memory_a7, NULL, "renesas-tmu-a7", + &tmr->memory, 0, 0x30); + sysbus_init_mmio(d, &tmr->memory_a7); + tmr->pck =3D qdev_init_clock_in(DEVICE(obj), "pck", + tmr_pck_update, tmr); +} + +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 TimerBaseClass(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 TimerBaseClass(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 TimerBaseClass(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 5288660cda..4d21b50ab0 100644 --- a/hw/timer/Kconfig +++ b/hw/timer/Kconfig @@ -39,9 +39,9 @@ config CMSDK_APB_DUALTIMER config RENESAS_TMR8 bool =20 -config RENESAS_CMT +config AVR_TIMER16 bool =20 -config AVR_TIMER16 +config RENESAS_TIMER bool =20 diff --git a/hw/timer/meson.build b/hw/timer/meson.build index a02e45fdbd..6aed6d1e5f 100644 --- a/hw/timer/meson.build +++ b/hw/timer/meson.build @@ -9,7 +9,7 @@ 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_TMR8', if_true: files('renesas_tmr8.c= ')) -softmmu_ss.add(when: 'CONFIG_RENESAS_CMT', if_true: files('renesas_cmt.c')) +softmmu_ss.add(when: 'CONFIG_RENESAS_TIMER', if_true: files('renesas_timer= .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 Nov 16 04:02:32 2025 Delivered-To: importer@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+importer=patchew.org@nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1598532084; cv=none; d=zohomail.com; s=zohoarc; b=auboQDxNjCUzF7aPl+o6guNoX2iRf7/jIliztCoqYpX9+E8WoJzKFvFv6b8czSIZdsVt9XDwxg+LB74dKt/kB65nKcwctMlCMd2fNmplEI08HU9Px3GndDI8yTsE/Iwa40jCqzPRTl02l9yw/m+9r0e0dUd02xz3TzSge/PB8Bc= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1598532084; 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=J9XPedIwenJDeHKWnIlk6RLhGZ/2YCW7jNoejCtdXCE=; b=U5lasvtTX0HtJ4tHkopXuQoN4Edo0H1Ac1ZaHry02YurrdqmwaCfipLkjJXBuqFbzJeezL42GZLNoU5Sejmf69mBCryxNiHpn8Qivlx+PPSjYv6lOj4N3yTnPXoUBEZ8ngguEIsFjVanJnh+c0ys4+RKUJJrLKvXm4gC1FP0nOU= 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+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1598532084483775.2406974719443; Thu, 27 Aug 2020 05:41:24 -0700 (PDT) Received: from localhost ([::1]:46998 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kBHDX-0004Y6-53 for importer@patchew.org; Thu, 27 Aug 2020 08:41:23 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:58928) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kBHBR-0007xb-BS for qemu-devel@nongnu.org; Thu, 27 Aug 2020 08:39:13 -0400 Received: from mail01.asahi-net.or.jp ([202.224.55.13]:47886) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kBHBO-0005vG-17 for qemu-devel@nongnu.org; Thu, 27 Aug 2020 08:39:13 -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 4C9D3108673; Thu, 27 Aug 2020 21:39:07 +0900 (JST) Received: from yo-satoh-debian.localdomain (ZM005235.ppp.dion.ne.jp [222.8.5.235]) by sakura.ysato.name (Postfix) with ESMTPSA id F34F41C0792; Thu, 27 Aug 2020 21:39:06 +0900 (JST) From: Yoshinori Sato To: qemu-devel@nongnu.org Subject: [PATCH 09/20] hw/timer: Remove renesas_cmt. Date: Thu, 27 Aug 2020 21:38:48 +0900 Message-Id: <20200827123859.81793-10-ysato@users.sourceforge.jp> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200827123859.81793-1-ysato@users.sourceforge.jp> References: <20200827123859.81793-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+importer=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-detected-operating-system: by eggs.gnu.org: First seen = 2020/08/27 08:39:06 X-ACL-Warn: Detected OS = ??? 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+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" This module replaced to unified renesas_timer. Signed-off-by: Yoshinori Sato --- include/hw/timer/renesas_cmt.h | 40 ----- hw/timer/renesas_cmt.c | 283 --------------------------------- 2 files changed, 323 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 e28a15cb38..0000000000 --- a/include/hw/timer/renesas_cmt.h +++ /dev/null @@ -1,40 +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" - -#define TYPE_RENESAS_CMT "renesas-cmt" -#define RCMT(obj) OBJECT_CHECK(RCMTState, (obj), TYPE_RENESAS_CMT) - -enum { - CMT_CH =3D 2, - CMT_NR_IRQ =3D 1 * CMT_CH -}; - -typedef 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]; -} RCMTState; - -#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) --=20 2.20.1 From nobody Sun Nov 16 04:02:32 2025 Delivered-To: importer@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+importer=patchew.org@nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1598532333; cv=none; d=zohomail.com; s=zohoarc; b=e/b4Z4iWWy3O0wk23+5s/vSMmGwgaP8vHg0vRBmQ7k1oFjtIOVw+cb+mZVR4ZVk+Kgp9yoRDwtuTM+JTfC/vJ3XhGyKK9DwfOxM2iAnaoo/gUG0VOi6OLEyWKpky7bjN6w81Fi8S5cw0WRlBRSnrJK8a08EluZdFqho6k4RrDM0= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1598532333; 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=0EVHARyCZd7YpicJcUGddBOfRQ38zYmVvRpK3sT7h5k=; b=O+jnqNCnQPAodOBcCB2PJkPXlLCe0kKjMqsq+RB4rq5/7mRzbYpmrWWp7A1MzFRWpjqwpSSwdES/3cg5+li73iws2DqQk5D3aZqbJH6lnEjEBmpy1DBhmYCuDc44aIoCYmpLVoF+i0GMZa3BnuglASSUE2kTpWLa43KlzwuwkmA= 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+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1598532333258122.49300727990033; Thu, 27 Aug 2020 05:45:33 -0700 (PDT) Received: from localhost ([::1]:35272 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kBHHX-0002nr-SK for importer@patchew.org; Thu, 27 Aug 2020 08:45:31 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:59006) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kBHBT-000825-GT for qemu-devel@nongnu.org; Thu, 27 Aug 2020 08:39:15 -0400 Received: from mail01.asahi-net.or.jp ([202.224.55.13]:47889) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kBHBO-0005vN-BQ for qemu-devel@nongnu.org; Thu, 27 Aug 2020 08:39:15 -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 5E1B41086BE; Thu, 27 Aug 2020 21:39:07 +0900 (JST) Received: from yo-satoh-debian.localdomain (ZM005235.ppp.dion.ne.jp [222.8.5.235]) by sakura.ysato.name (Postfix) with ESMTPSA id 36E431C0696; Thu, 27 Aug 2020 21:39:07 +0900 (JST) From: Yoshinori Sato To: qemu-devel@nongnu.org Subject: [PATCH 10/20] hw/rx: Convert to renesas_timer Date: Thu, 27 Aug 2020 21:38:49 +0900 Message-Id: <20200827123859.81793-11-ysato@users.sourceforge.jp> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200827123859.81793-1-ysato@users.sourceforge.jp> References: <20200827123859.81793-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+importer=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-detected-operating-system: by eggs.gnu.org: First seen = 2020/08/27 08:39:06 X-ACL-Warn: Detected OS = ??? 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+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" Signed-off-by: Yoshinori Sato --- include/hw/rx/rx62n.h | 4 ++-- hw/rx/Kconfig | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/hw/rx/rx62n.h b/include/hw/rx/rx62n.h index 75945bae50..1182ca24de 100644 --- a/include/hw/rx/rx62n.h +++ b/include/hw/rx/rx62n.h @@ -27,7 +27,7 @@ #include "target/rx/cpu.h" #include "hw/intc/rx_icu.h" #include "hw/timer/renesas_tmr8.h" -#include "hw/timer/renesas_cmt.h" +#include "hw/timer/renesas_timer.h" #include "hw/char/renesas_sci.h" #include "hw/rx/rx62n-cpg.h" #include "qemu/units.h" @@ -69,7 +69,7 @@ typedef struct RX62NState { RXCPU cpu; RXICUState icu; RenesasTMR8State tmr[RX62N_NR_TMR]; - RCMTState cmt[RX62N_NR_CMT]; + RenesasCMTState cmt[RX62N_NR_CMT]; RSCIState sci[RX62N_NR_SCI]; RX62NCPGState cpg; =20 diff --git a/hw/rx/Kconfig b/hw/rx/Kconfig index 0406f27bee..d1812870ea 100644 --- a/hw/rx/Kconfig +++ b/hw/rx/Kconfig @@ -2,7 +2,7 @@ config RX62N_MCU bool select RX_ICU select RENESAS_TMR8 - select RENESAS_CMT + select RENESAS_TIMER select RENESAS_SCI =20 config RX_GDBSIM --=20 2.20.1 From nobody Sun Nov 16 04:02:32 2025 Delivered-To: importer@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+importer=patchew.org@nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1598532216; cv=none; d=zohomail.com; s=zohoarc; b=N0P0iPsNy/+XXH2539Pta7gSKEGw2pJjrwrUcw311rTnXSKNZTsJ6Pp3hwUNEAph8+Qwt2M57UnFP4qnEjQmXGRVPqFnOXgXXOL2x2l6o5Mj9jTmp0ooGevpxwB7RYYLThQaahRNpXzarznMrd4XtOAkP0PevBza7oX2TzenjjU= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1598532216; 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=wQkoi27NggHoOPzbRygdnNV76EFmJ9a5UcdcvhEYrVg=; b=e/BgSrRSpcEHHJCN/pMB6oNs5KzybNmpSNjUOw4RXR8rqZHbXeSl5zDfn0reZJpKYuqojj5Nw/EkdJcP+oR0uQYTCz9yii7SPEx+tQ7ZYAgQ3yUrnjBXtdIEqQQbvf0vIJLBromSrT1fUPW/W53mX5V6CiHSF79PnnoJPskWhYA= 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+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1598532216482528.0038333979452; Thu, 27 Aug 2020 05:43:36 -0700 (PDT) Received: from localhost ([::1]:56228 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kBHFf-0008Fa-1M for importer@patchew.org; Thu, 27 Aug 2020 08:43:35 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:59120) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kBHBY-0008Fj-6Y for qemu-devel@nongnu.org; Thu, 27 Aug 2020 08:39:20 -0400 Received: from mail01.asahi-net.or.jp ([202.224.55.13]:47907) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kBHBR-0005xf-De for qemu-devel@nongnu.org; Thu, 27 Aug 2020 08:39:19 -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 C75071086CC; Thu, 27 Aug 2020 21:39:07 +0900 (JST) Received: from yo-satoh-debian.localdomain (ZM005235.ppp.dion.ne.jp [222.8.5.235]) by sakura.ysato.name (Postfix) with ESMTPSA id 68AA81C0792; Thu, 27 Aug 2020 21:39:07 +0900 (JST) From: Yoshinori Sato To: qemu-devel@nongnu.org Subject: [PATCH 11/20] hw/char: Renesas SCI module. Date: Thu, 27 Aug 2020 21:38:50 +0900 Message-Id: <20200827123859.81793-12-ysato@users.sourceforge.jp> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200827123859.81793-1-ysato@users.sourceforge.jp> References: <20200827123859.81793-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+importer=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-detected-operating-system: by eggs.gnu.org: First seen = 2020/08/27 08:39:06 X-ACL-Warn: Detected OS = ??? 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+importer=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 | 1040 +++++++++++++++++++++++++++------ 2 files changed, 967 insertions(+), 202 deletions(-) diff --git a/include/hw/char/renesas_sci.h b/include/hw/char/renesas_sci.h index efdebc620a..07140e8aad 100644 --- a/include/hw/char/renesas_sci.h +++ b/include/hw/char/renesas_sci.h @@ -1,51 +1,138 @@ /* * 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 "hw/clock.h" =20 +#define TYPE_RENESAS_SCI_COMMON "renesas-sci-common" +#define RSCICommon(obj) OBJECT_CHECK(RSCICommonState, (obj), \ + TYPE_RENESAS_SCI_COMMON) #define TYPE_RENESAS_SCI "renesas-sci" #define RSCI(obj) OBJECT_CHECK(RSCIState, (obj), TYPE_RENESAS_SCI) +#define TYPE_RENESAS_SCIA "renesas-scia" +#define RSCIA(obj) OBJECT_CHECK(RSCIAState, (obj), TYPE_RENESAS_SCIA) +#define TYPE_RENESAS_SCIF "renesas-scif" +#define RSCIF(obj) OBJECT_CHECK(RSCIFState, (obj), TYPE_RENESAS_SCIF) + +#define SCI_GET_CLASS(obj) \ + OBJECT_GET_CLASS(RenesasSCICommonClass, obj, TYPE_RENESAS_SCI_COMMON) +#define SCI_COMMON_CLASS(klass) \ + OBJECT_CLASS_CHECK(RenesasSCICommonClass, klass, TYPE_RENESAS_SCI_COMM= ON) +#define SCI_CLASS(klass) \ + OBJECT_CLASS_CHECK(RenesasSCIClass, klass, TYPE_RENESAS_SCI) +#define SCIA_CLASS(klass) \ + OBJECT_CLASS_CHECK(RenesasSCIAClass, klass, TYPE_RENESAS_SCIA) +#define SCIF_CLASS(klass) \ + OBJECT_CLASS_CHECK(RenesasSCIFClass, klass, TYPE_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, }; =20 -typedef struct { - /*< private >*/ - SysBusDevice parent_obj; - /*< public >*/ +enum { + RXTOUT, + RXNEXT, + TXEMPTY, + TXEND, + NR_SCI_EVENT, +}; =20 +typedef struct RSCICommonState { + SysBusDevice parent_obj; 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 RSCICommonState *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; +} RSCICommonState; + +typedef struct { + RSCICommonState parent_obj; + + /* SCI specific register */ + uint8_t sptr; } RSCIState; =20 -#endif +typedef struct { + RSCICommonState parent_obj; + + /* SCIa specific register */ + uint8_t scmr; + uint8_t semr; +} RSCIAState; + +typedef struct { + RSCICommonState parent_obj; + + /* SCIF specific register */ + uint16_t fcr; + uint16_t sptr; + uint16_t lsr; + + /* internal use */ + uint16_t read_lsr; + int tdcnt; +} RSCIFState; + +typedef struct RenesasSCICommonClass { + SysBusDeviceClass parent; + + const struct MemoryRegionOps *ops; + void (*irq_fn)(RSCICommonState *sci, int request); + int (*divrate)(RSCICommonState *sci); +} RenesasSCICommonClass; + +typedef struct RenesasSCIClass { + RenesasSCICommonClass parent; + + void (*p_irq_fn)(RSCICommonState *sci, int request); +} RenesasSCIClass; + +typedef struct RenesasSCIAClass { + RenesasSCICommonClass parent; + + void (*p_irq_fn)(RSCICommonState *sci, int request); + int (*p_divrate)(RSCICommonState *sci); +} RenesasSCIAClass; + +typedef struct RenesasSCIFClass { + RenesasSCICommonClass parent; + + void (*p_irq_fn)(RSCICommonState *sci, int request); +} RenesasSCIFClass; diff --git a/hw/char/renesas_sci.c b/hw/char/renesas_sci.c index 5d7c6e6523..24c23709ee 100644 --- a/hw/char/renesas_sci.c +++ b/hw/char/renesas_sci.c @@ -1,12 +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) + * (Rev.1.40 R01UH0033EJ0140) + * And SH7751 Group, SH7751R Group User's Manual: Hardware + * (Rev.4.01 R01UH0457EJ0401) * - * Copyright (c) 2019 Yoshinori Sato - * - * SPDX-License-Identifier: GPL-2.0-or-later + * 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, @@ -23,14 +23,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-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. + */ +REG16(SMR, 0) /* 8bit */ FIELD(SMR, CKS, 0, 2) FIELD(SMR, MP, 2, 1) FIELD(SMR, STOP, 3, 1) @@ -38,263 +49,839 @@ 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) +REG16(BRR, 2) /* 8bit */ +REG16(SCR, 4) + 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) +REG16(TDR, 6) /* 8bit */ +REG16(SSR, 8) /* 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) +REG16(FSR, 8) + 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) +REG16(RDR, 10) /* 8bit */ +REG16(SCMR, 12) /* 8bit */ FIELD(SCMR, SMIF, 0, 1) FIELD(SCMR, SINV, 2, 1) FIELD(SCMR, SDIR, 3, 1) FIELD(SCMR, BCP2, 7, 1) -REG8(SEMR, 7) +REG16(FCR, 12) + 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) +REG16(SEMR, 14) /* 8bit */ FIELD(SEMR, ACS0, 0, 1) FIELD(SEMR, ABCS, 4, 1) +REG16(FDR, 14) + FIELD(FDR, Rn, 0, 4) + FIELD(FDR, Tn, 8, 4) +REG16(SPTR, 16) + 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) +REG16(LSR, 18) + FIELD(LSR, ORER, 0, 1) + +#define SCIF_FIFO_DEPTH 16 + +static const int sci_rtrg[] =3D {1, 4, 8, 14}; =20 -static int can_receive(void *opaque) +static void update_event_time(RSCICommonState *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(RSCICommonState *sci_common, int req) +{ + int irq =3D 0; + int rie; + int tie; + RSCIState *sci =3D RSCI(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(RSCICommonState *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(RSCICommonState *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); } =20 -static void send_byte(RSCIState *sci) +static int sci_can_receive(void *opaque) +{ + RSCICommonState *sci =3D RSCICommon(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) +{ + RSCICommonState *sci =3D RSCICommon(opaque); + RenesasSCICommonClass *rc =3D SCI_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) +{ + RSCIFState *scif =3D RSCIF(opaque); + RSCICommonState *sci =3D RSCICommon(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) +{ + RSCIFState *scif =3D RSCIF(opaque); + RSCICommonState *sci =3D RSCICommon(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); + } +} + +static void sci_send_byte(RSCICommonState *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(RSCIFState *scif) +{ + RSCICommonState *sci =3D RSCICommon(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(RSCICommonState *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(RSCICommonState *sci) +{ + int64_t next_event =3D 0; + RenesasSCICommonClass *rc =3D SCI_GET_CLASS(sci); + if (!fifo8_is_empty(&sci->rxfifo)) { + 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 { + /* Trigger 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; +} + +static int64_t sci_tx_empty(RSCICommonState *sci) +{ + int64_t ret =3D 0; + RenesasSCICommonClass *rc =3D SCI_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->ssr =3D FIELD_DP8(sci->ssr, SSR, TEND, 1); - if (FIELD_EX8(sci->scr, SCR, TEIE)) { - qemu_set_irq(sci->irq[TEI], 1); + sci->Xsr =3D FIELD_DP16(sci->Xsr, SSR, TEND, 1); + rc->irq_fn(sci, BRI_TEI); + } + return ret; +} + +static int64_t scif_tx_empty(RSCICommonState *sci) +{ + RSCIFState *scif =3D RSCIF(sci); + scif->tdcnt -=3D transmit_byte(scif); + sci->Xsr =3D FIELD_DP16(sci->Xsr, FSR, TDFE, 1); + scif_irq(sci, TXI); + return 0; +} + +static int64_t scif_tx_end(RSCICommonState *sci) +{ + RSCIFState *scif =3D RSCIF(sci); + scif->tdcnt =3D 0; + sci->Xsr =3D FIELD_DP16(sci->Xsr, FSR, TEND, 1); + return 0; +} + +static void sci_timer_event(void *opaque) +{ + RSCICommonState *sci =3D RSCICommon(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; + } + if (sci->event[i].time > 0) { + next =3D MIN(next, sci->event[i].time); } } + if (next < INT64_MAX) { + timer_mod(sci->event_timer, next); + } else { + timer_del(sci->event_timer); + } } =20 -static void update_trtime(RSCIState *sci) +static int static_divrate(RSCICommonState *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; + /* SCI / SCIF have static divide rate */ + return 32; } =20 -static bool sci_is_tr_enabled(RSCIState *sci) +static int scia_divrate(RSCICommonState *sci) { - return FIELD_EX8(sci->scr, SCR, TE) || FIELD_EX8(sci->scr, SCR, RE); + /* + * SEMR.ABCS =3D 0 -> 32 + * SEMR.ABCS =3D 1 -> 16 + */ + RSCIAState *scia =3D RSCIA(sci); + return 16 * (2 - FIELD_EX8(scia->semr, SEMR, ABCS)); } =20 -static void sci_write(void *opaque, hwaddr offset, uint64_t val, unsigned = size) +static void update_trtime(RSCICommonState *sci) { - RSCIState *sci =3D RSCI(opaque); + RenesasSCICommonClass *rc =3D SCI_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; =20 - switch (offset) { - case A_SMR: - if (!sci_is_tr_enabled(sci)) { - sci->smr =3D val; - update_trtime(sci); + /* 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) +{ + RSCICommonState *sci =3D RSCICommon(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(RSCICommonState *sci, hwaddr addr) +{ + return (addr << 1) >> sci->regshift; +} + +static void sci_common_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + RSCICommonState *sci =3D RSCICommon(opaque); + RenesasSCICommonClass *rc =3D SCI_GET_CLASS(opaque); + 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, 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: - if (!sci_is_tr_enabled(sci)) { - sci->brr =3D val; - update_trtime(sci); - } + sci->brr =3D val; + update_trtime(sci); break; - 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]); - } + 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) +{ + RSCICommonState *sci =3D RSCICommon(opaque); + RenesasSCICommonClass *rc =3D SCI_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(RSCICommon(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: + RSCI(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) +{ + RSCICommonState *sci =3D RSCICommon(opaque); + RSCIAState *scia =3D RSCIA(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); + RSCICommonState *sci =3D RSCICommon(opaque); + RSCIFState *scif =3D RSCIF(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) +{ + RSCICommonState *sci =3D RSCICommon(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; + return fifo8_pop(&sci->rxfifo); 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) +{ + RSCICommonState *sci =3D RSCICommon(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 RSCI(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); + RSCICommonState *sci =3D RSCICommon(opaque); + RSCIAState *scia =3D RSCIA(opaque); + uint64_t ret; + + if (clock_is_enabled(sci->pck)) { + addr =3D map_address(sci, addr); + switch (addr) { + case A_TDR: + return sci->tdr; + case A_RDR: + ret =3D fifo8_pop(&sci->rxfifo); + sci->Xsr =3D FIELD_DP16(sci->Xsr, SSR, RDRF, 0); + return ret; + 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) +{ + RSCIFState *scif =3D RSCIF(opaque); + RSCICommonState *sci =3D RSCICommon(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) +{ + RSCICommonState *sci =3D RSCICommon(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); } =20 static void sci_event(void *opaque, QEMUChrEvent event) { - RSCIState *sci =3D RSCI(opaque); + RSCICommonState *sci =3D RSCICommon(opaque); + RenesasSCICommonClass *rc =3D SCI_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) +{ + RSCICommonState *sci =3D RSCICommon(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); + RSCICommonState *sci =3D RSCICommon(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->regshift =3D sci->regshift / 8 - 1; + 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(RSCICommonState *sci, int size) { - SysBusDevice *d =3D SYS_BUS_DEVICE(obj); - RSCIState *sci =3D RSCI(obj); - int i; + SysBusDevice *d =3D SYS_BUS_DEVICE(sci); + RenesasSCICommonClass *rc =3D SCI_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) +{ + RSCIState *sci =3D RSCI(dev); + RSCICommonState *common =3D RSCICommon(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) +{ + RSCIAState *sci =3D RSCIA(dev); + RSCICommonState *common =3D RSCICommon(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) +{ + RSCIFState *sci =3D RSCIF(dev); + RSCICommonState *common =3D RSCICommon(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 { @@ -302,49 +889,140 @@ 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", RSCICommonState, regshift, 8), + DEFINE_PROP_UINT32("unit", RSCICommonState, unit, 0), + DEFINE_PROP_CHR("chardev", RSCICommonState, chr), DEFINE_PROP_END_OF_LIST(), }; =20 -static void rsci_class_init(ObjectClass *klass, void *data) +static void rsci_init(Object *obj) { + RSCICommonState *sci =3D RSCICommon(obj); + sci->event[RXNEXT].handler =3D sci_rx_next; + sci->event[TXEMPTY].handler =3D sci_tx_empty; +} + +static void rscif_init(Object *obj) +{ + RSCICommonState *sci =3D RSCICommon(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) +{ + RenesasSCICommonClass *rc =3D SCI_COMMON_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); + RenesasSCICommonClass *comm_rc =3D SCI_COMMON_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) +{ + RenesasSCICommonClass *comm_rc =3D SCI_COMMON_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) +{ + RenesasSCICommonClass *comm_rc =3D SCI_COMMON_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_COMMON, + .parent =3D TYPE_SYS_BUS_DEVICE, + .instance_size =3D sizeof(RSCICommonState), + .instance_init =3D rsci_common_init, + .class_init =3D rsci_common_class_init, + .class_size =3D sizeof(RenesasSCICommonClass), + .abstract =3D true, + }, + { + .name =3D TYPE_RENESAS_SCI, + .parent =3D TYPE_RENESAS_SCI_COMMON, + .instance_size =3D sizeof(RSCIState), + .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_COMMON, + .instance_size =3D sizeof(RSCIAState), + /* 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_COMMON, + .instance_size =3D sizeof(RSCIFState), + .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 Nov 16 04:02:32 2025 Delivered-To: importer@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+importer=patchew.org@nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1598532251; cv=none; d=zohomail.com; s=zohoarc; b=oGMSSiMb6M1M0VuNKZbSa2tPYAnlD3GaZuO3PyWxeJnDtrS3pHjPHs+ICi+YBkazDnOJjW0Fz5ppgalAm2u/9vD8AfbZVBYRBUdI2MFZWw/hTkN7jrSFsUCXpx+a3VA6KRLq+5Syc/W+J8IDRSF23d0DsDAvk0/FHDn7qqBTjQw= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1598532251; 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=MKS+tVBEIp1GzHm9ibeb4HDSIAdTDVxmzhHnxlR2myk=; b=gKE6KjbqzyC63jYsWeAQBhfnY7uDGsjVKVuaV6vCYbZX7R6qi+XrDDng01qY2bg8/Nq85IPG7GMyMZlQlipwbDBPgZjNpMX6Gw9C/JflYz+mBUauHCHteb2+K/N5S02HjgCZz9QBilc8TojAmSZAAjTZN4cQjq8AphQhHVwWkQw= 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+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1598532251983453.38461202563735; Thu, 27 Aug 2020 05:44:11 -0700 (PDT) Received: from localhost ([::1]:58590 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kBHGE-0000mr-OL for importer@patchew.org; Thu, 27 Aug 2020 08:44:10 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:59068) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kBHBV-00087P-D0 for qemu-devel@nongnu.org; Thu, 27 Aug 2020 08:39:17 -0400 Received: from mail01.asahi-net.or.jp ([202.224.55.13]:47908) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kBHBR-0005xg-F8 for qemu-devel@nongnu.org; Thu, 27 Aug 2020 08:39:16 -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 F28311086DC; Thu, 27 Aug 2020 21:39:07 +0900 (JST) Received: from yo-satoh-debian.localdomain (ZM005235.ppp.dion.ne.jp [222.8.5.235]) by sakura.ysato.name (Postfix) with ESMTPSA id B20451C0696; Thu, 27 Aug 2020 21:39:07 +0900 (JST) From: Yoshinori Sato To: qemu-devel@nongnu.org Subject: [PATCH 12/20] hw/rx/rx62n: Use New SCI module. Date: Thu, 27 Aug 2020 21:38:51 +0900 Message-Id: <20200827123859.81793-13-ysato@users.sourceforge.jp> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200827123859.81793-1-ysato@users.sourceforge.jp> References: <20200827123859.81793-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+importer=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-detected-operating-system: by eggs.gnu.org: First seen = 2020/08/27 08:39:06 X-ACL-Warn: Detected OS = ??? 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+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" Signed-off-by: Yoshinori Sato --- include/hw/rx/rx62n.h | 2 +- hw/rx/rx62n.c | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/include/hw/rx/rx62n.h b/include/hw/rx/rx62n.h index 1182ca24de..f463148799 100644 --- a/include/hw/rx/rx62n.h +++ b/include/hw/rx/rx62n.h @@ -70,7 +70,7 @@ typedef struct RX62NState { RXICUState icu; RenesasTMR8State tmr[RX62N_NR_TMR]; RenesasCMTState cmt[RX62N_NR_CMT]; - RSCIState sci[RX62N_NR_SCI]; + RSCIAState sci[RX62N_NR_SCI]; RX62NCPGState cpg; =20 MemoryRegion *sysmem; diff --git a/hw/rx/rx62n.c b/hw/rx/rx62n.c index 0223396110..f61383a4c2 100644 --- a/hw/rx/rx62n.c +++ b/hw/rx/rx62n.c @@ -191,11 +191,13 @@ 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); sysbus_realize(sci, &error_abort); =20 irqbase =3D RX62N_SCI_IRQ + SCI_NR_IRQ * unit; @@ -203,6 +205,9 @@ static void register_sci(RX62NState *s, int unit) sysbus_connect_irq(sci, i, s->irq[irqbase + i]); } sysbus_mmio_map(sci, 0, RX62N_SCI_BASE + unit * 0x08); + snprintf(ckname, sizeof(ckname), "pck_sci-%d", unit); + qdev_connect_clock_in(DEVICE(sci), "pck", + qdev_get_clock_out(DEVICE(&s->cpg), ckname)); } =20 static void register_cpg(RX62NState *s) --=20 2.20.1 From nobody Sun Nov 16 04:02:32 2025 Delivered-To: importer@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+importer=patchew.org@nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1598532584; cv=none; d=zohomail.com; s=zohoarc; b=YXNCTyDeKBW3pgPpCwdJ31Drb/vLznKWHQa9DQPZn/CgMJ3bcQj/uuADyUGoBqQwqk+nuiAr74q82oP50WEv7YIGKXAGP/gpOuqWYsz3fTv3FUhxh89/1zVgMKGf73cjaXOFwAGbZl8xGuqef15igO8wi9tUsXNLsLbufLbLNdg= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1598532584; 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=vi2D2I7FW+8rkdtJlqdM+WXBnV+GyKDQhvlbTeEd1XA=; b=a1/wxuN1uwFjzOs94ex8hBCTgXHs2JE7gNLEjA8HdZlE/2h8RRSATL9z0tZX3E7nTzZDaT+ZfZ/9LdR3Te9oB702/07jvIxujEhwrxMBAkXK18hrZ/D25S+OQaiKNgY5qW1+FYaodtBNJuJWv7Gzc5EFTd0n6n7gvKQxh1nhQ9Y= 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+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1598532584425866.4246607341701; Thu, 27 Aug 2020 05:49:44 -0700 (PDT) Received: from localhost ([::1]:51142 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kBHLb-0000tn-2C for importer@patchew.org; Thu, 27 Aug 2020 08:49:43 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:59124) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kBHBY-0008H1-KF for qemu-devel@nongnu.org; Thu, 27 Aug 2020 08:39:20 -0400 Received: from mail01.asahi-net.or.jp ([202.224.55.13]:47912) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kBHBS-0005y4-31 for qemu-devel@nongnu.org; Thu, 27 Aug 2020 08:39:20 -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 66DA5108926; Thu, 27 Aug 2020 21:39:08 +0900 (JST) Received: from yo-satoh-debian.localdomain (ZM005235.ppp.dion.ne.jp [222.8.5.235]) by sakura.ysato.name (Postfix) with ESMTPSA id DFE8D1C0792; Thu, 27 Aug 2020 21:39:07 +0900 (JST) From: Yoshinori Sato To: qemu-devel@nongnu.org Subject: [PATCH 13/20] hw/timer: Add Renesas MTU2 Date: Thu, 27 Aug 2020 21:38:52 +0900 Message-Id: <20200827123859.81793-14-ysato@users.sourceforge.jp> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200827123859.81793-1-ysato@users.sourceforge.jp> References: <20200827123859.81793-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+importer=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-detected-operating-system: by eggs.gnu.org: First seen = 2020/08/27 08:39:06 X-ACL-Warn: Detected OS = ??? 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+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" Signed-off-by: Yoshinori Sato --- include/hw/timer/renesas_mtu.h | 90 +++ hw/timer/renesas_mtu.c | 1312 ++++++++++++++++++++++++++++++++ hw/timer/Kconfig | 2 + hw/timer/meson.build | 1 + 4 files changed, 1405 insertions(+) create mode 100644 include/hw/timer/renesas_mtu.h create mode 100644 hw/timer/renesas_mtu.c diff --git a/include/hw/timer/renesas_mtu.h b/include/hw/timer/renesas_mtu.h new file mode 100644 index 0000000000..27df14b308 --- /dev/null +++ b/include/hw/timer/renesas_mtu.h @@ -0,0 +1,90 @@ +/* + * Renesas Multi-function Timer Uint Object + * + * Copyright (c) 2020 Yoshinori Sato + * + * This code is licensed under the GPL version 2 or later. + * + */ + +#ifndef HW_RENESAS_MTU_H +#define HW_RENESAS_MTU_H + +#include "hw/sysbus.h" +#include "hw/qdev-clock.h" + +#define TYPE_RENESAS_MTU2 "renesas-mtu2" +#define RenesasMTU2(obj) \ + OBJECT_CHECK(RenesasMTU2State, (obj), TYPE_RENESAS_MTU2) + +#define MTU2Class(klass) \ + OBJECT_CLASS_CHECK(RenesasMTU2Class, klass, TYPE_RENESAS_MTU2) + +enum { + NR_MAX_IRQ =3D 7, + MTU_NR_IRQ =3D 7 + 4 + 4 + 5 + 5 + 3, +}; + +struct RenesasMTU2State; + +typedef struct { + uint8_t tcr; + uint8_t tmdr; + uint8_t tsr; + uint16_t tior; + uint16_t tier; + uint32_t tcnt; + uint16_t tgr[6]; + + int num_gr; + int64_t base; + int64_t next; + int64_t clk; + bool start; + bool cntclr; + bool ier; + QEMUTimer *timer; + int ch; + qemu_irq irq[NR_MAX_IRQ]; + int next_cnt; + struct RenesasMTU2State *mtu; +} RenesasMTURegs; + +typedef struct RenesasMTU2State { + SysBusDevice parent_obj; + RenesasMTURegs r[5]; + RenesasMTURegs r5[3]; + uint8_t tbtm; + uint8_t ticcr; + uint16_t tadcr; + uint16_t tadcor[2]; + uint16_t tadcobr[2]; + /* CH A registers */ + uint8_t toer; + uint8_t tgcr; + uint8_t tocr[2]; + uint16_t tcdr; + uint16_t tddr; + uint16_t tcnts; + uint16_t tcbr; + uint8_t titcr; + uint8_t titcnt; + uint8_t tbter; + uint8_t tder; + uint8_t tolbr; + uint8_t twcr; + uint8_t trwer; + uint8_t tsyr; + + Clock *pck; + int64_t input_freq; + MemoryRegion memory[3]; + uint8_t trwer_r; + uint32_t unit; +} RenesasMTU2State; + +typedef struct { + SysBusDeviceClass parent; +} RenesasMTU2Class; + +#endif diff --git a/hw/timer/renesas_mtu.c b/hw/timer/renesas_mtu.c new file mode 100644 index 0000000000..fc204f10ce --- /dev/null +++ b/hw/timer/renesas_mtu.c @@ -0,0 +1,1312 @@ +/* + * Renesas Multi-function Timer Uint + * + * Datasheet: RX62N Group, RX621 Group User's Manual: Hardware + * (Rev.1.40 R01UH0033EJ0140) + * + * Copyright (c) 2019 Yoshinori Sato + * + * This program is free software; you can redistribute it and/or 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_mtu.h" +#include "qemu/error-report.h" + +REG8(TCR_012, 0) +REG8(TMDR_012, 1) +REG8(TIORH_012, 2) +REG8(TIORL_012, 3) +REG8(TIER_012, 4) +REG8(TSR_012, 5) +REG16(TCNT_012, 6) +REG16(TGRA_012, 8) +REG16(TGRB_012, 10) +REG16(TGRC_012, 12) +REG16(TGRD_012, 14) +REG8(TICCR_1, 16) +REG16(TGRE_0, 32) +REG16(TGRF_0, 34) +REG8(TIER2_0, 36) +REG8(TBTM_0, 38) + +REG8(TCR_3, 0) +REG8(TCR_4, 1) +REG8(TMDR_3, 2) +REG8(TMDR_4, 3) +REG8(TIORH_3, 4) +REG8(TIORL_3, 5) +REG8(TIORH_4, 6) +REG8(TIORL_4, 7) +REG8(TIER_3, 8) +REG8(TIER_4, 9) +REG8(TOER, 10) + FIELD(TOER, OE3B, 0, 1) + FIELD(TOER, OE4A, 1, 1) + FIELD(TOER, OE4B, 2, 1) + FIELD(TOER, OE3D, 3, 1) + FIELD(TOER, OE4C, 4, 1) + FIELD(TOER, OE4D, 5, 1) +REG8(TGCR, 13) + FIELD(TGCR, BDC, 6, 1) + FIELD(TGCR, N, 5, 1) + FIELD(TGCR, P, 4, 1) + FIELD(TGCR, FB, 3, 1) + FIELD(TGCR, WF, 2, 1) + FIELD(TGCR, VF, 1, 1) + FIELD(TGCR, UF, 0, 1) +REG8(TOCR1, 14) + FIELD(TOCR1, OLSP, 0, 1) + FIELD(TOCR1, OLSN, 1, 1) + FIELD(TOCR1, TOCS, 2, 1) + FIELD(TOCR1, TOCL, 3, 1) + FIELD(TOCR1, PSYE, 6, 1) +REG8(TOCR2, 15) + FIELD(TOCR2, OLS1P, 0, 1) + FIELD(TOCR2, OLS1N, 1, 1) + FIELD(TOCR2, OLS2P, 2, 1) + FIELD(TOCR2, OLS2N, 3, 1) + FIELD(TOCR2, OLS3P, 4, 1) + FIELD(TOCR2, OLS3N, 5, 1) + FIELD(TOCR2, BF, 6, 2) +REG16(TCNT_3, 16) +REG16(TCNT_4, 18) +REG16(TCDR, 20) +REG16(TDDR, 22) +REG16(TGRA_3, 24) +REG16(TGRB_3, 26) +REG16(TGRA_4, 28) +REG16(TGRB_4, 30) +REG16(TCNTS, 32) +REG16(TCBR, 34) +REG16(TGRC_3, 36) +REG16(TGRD_3, 38) +REG16(TGRC_4, 40) +REG16(TGRD_4, 42) +REG8(TSR_3, 44) +REG8(TSR_4, 45) +REG8(TITCR, 48) + FIELD(TITCR, T4VCOR, 0, 3) + FIELD(TITCR, T4VEN, 3, 1) + FIELD(TITCR, T3ACOR, 4, 3) + FIELD(TITCR, T3AEN, 7, 1) +REG8(TITCNT, 49) + FIELD(TITCNT, T4VCNT, 0, 3) + FIELD(TITCNT, T3ACNT, 4, 3) +REG8(TBTER, 50) + FIELD(TBTER, BTE, 0, 2) +REG8(TDER, 52) + FIELD(TDER, TDER, 0, 1) +REG8(TOLBR, 54) + FIELD(TOLBR, OLS1P, 0, 1) + FIELD(TOLBR, OLS1N, 1, 1) + FIELD(TOLBR, OLS2P, 2, 1) + FIELD(TOLBR, OLS2N, 3, 1) + FIELD(TOLBR, OLS3P, 4, 1) + FIELD(TOLBR, OLS3N, 5, 1) +REG8(TBTM_3, 56) +REG8(TBTM_4, 57) +REG16(TADCR_4, 64) +REG16(TADCORA_4, 68) +REG16(TADCORB_4, 70) +REG16(TADCOBRA_4, 72) +REG16(TADCOBRB_4, 74) +REG8(TWCR, 96) + FIELD(TWCR, WRE, 0, 1) + FIELD(TWCR, CCE, 7, 1) +REG8(TSTR, 128) + FIELD(TSTR, CST0, 0, 1) + FIELD(TSTR, CST1, 1, 1) + FIELD(TSTR, CST2, 2, 1) + FIELD(TSTR, CSTL, 0, 3) + FIELD(TSTR, CST3, 6, 1) + FIELD(TSTR, CST4, 7, 1) + FIELD(TSTR, CSTH, 6, 2) +REG8(TSYR, 129) + FIELD(TSYR, SYNC0, 0, 1) + FIELD(TSYR, SYNC1, 1, 1) + FIELD(TSYR, SYNC2, 2, 1) + FIELD(TSYR, SYNC3, 6, 1) + FIELD(TSYR, SYNC4, 7, 1) +REG8(TRWER, 132) + FIELD(TRWER, RWE, 0, 1) + +REG16(TCNTU_5, 0) +REG16(TGRU_5, 2) +REG16(TCRU_5, 4) +REG8(TIORU_5, 6) +REG16(TCNTV_5, 16) +REG16(TGRV_5, 18) +REG8(TCRV_5, 20) +REG8(TIORV_5, 22) +REG16(TCNTW_5, 32) +REG16(TGRW_5, 34) +REG8(TCRW_5, 36) +REG8(TIORW_5, 38) +REG8(TIER_5, 50) + FIELD(TIER_5, TGIEW5, 0, 1) + FIELD(TIER_5, TGIEV5, 1, 1) + FIELD(TIER_5, TGIEU5, 2, 1) + FIELD(TIER_5, TGIE5, 0, 3) +REG8(TSTR_5, 52) + FIELD(TSTR_5, CSTW5, 0, 1) + FIELD(TSTR_5, CSTV5, 1, 1) + FIELD(TSTR_5, CSTU5, 2, 1) + FIELD(TSTR_5, CST5, 0, 3) +REG8(TCNTCMPCLR_5, 54) + FIELD(TCNTCMPCLR_5, CMPCLRW5, 0, 1) + FIELD(TCNTCMPCLR_5, CMPCLRV5, 1, 1) + FIELD(TCNTCMPCLR_5, CMPCLRU5, 2, 1) + FIELD(TCNTCMPCLR_5, CMPCLR5, 0, 3) + +REG8(TCR, 1) + FIELD(TCR, TPSC, 0, 3) + FIELD(TCR, CKEG, 3, 2) + FIELD(TCR, CCLR, 5, 3) +REG8(TMDR, 2) + FIELD(TMDR, MD, 0, 4) + FIELD(TMDR, BFA, 4, 1) + FIELD(TMDR, BFB, 5, 1) + FIELD(TMDR, BFE, 6, 1) +REG16(TIOR, 3) + FIELD(TIOR, IOA, 0, 3) + FIELD(TIOR, IOB, 4, 3) + FIELD(TIOR, IOC, 8, 3) + FIELD(TIOR, IOD, 12, 3) +REG8(TIOR5, 4) + FIELD(TIOR5, IOC, 0, 4) +REG8(TCNTCMPCLR, 5) + FIELD(TCNTCMPCLR, CMPCLR5W, 0, 1) + FIELD(TCNTCMPCLR, CMPCLR5V, 1, 1) + FIELD(TCNTCMPCLR, CMPCLR5U, 2, 1) + FIELD(TCNTCMPCLR, CMPCLR5, 0, 3) +REG8(TIER, 6) + FIELD(TIER, TGIEA, 0, 1) + FIELD(TIER, TGIEB, 1, 1) + FIELD(TIER, TGIEC, 2, 1) + FIELD(TIER, TGIED, 3, 1) + FIELD(TIER, TGIE, 0, 4) + FIELD(TIER, TCIEV, 4, 1) + FIELD(TIER, TCIEU, 5, 1) + FIELD(TIER, TTGE2, 6, 1) + FIELD(TIER, TTGE, 7, 1) +REG8(TIER2, 7) + FIELD(TIER2, TGIEE, 0, 1) + FIELD(TIER2, TGIEF, 1, 1) + FIELD(TIER2, TGIE, 0, 2) +REG8(TSR, 8) + FIELD(TSR, TCFD, 7, 1) +REG8(TBTM, 9) + FIELD(TBTM, TTSA, 0, 1) + FIELD(TBTM, TTSB, 1, 1) + FIELD(TBTM, TTSE, 2, 1) +REG8(TICCR, 10) + FIELD(TICCR, I1AE, 0, 1) + FIELD(TICCR, I1BE, 1, 1) + FIELD(TICCR, I2AE, 2, 1) + FIELD(TICCR, I2BE, 3, 1) +REG16(TADCR, 11) + FIELD(TADCR, ITB4VE, 0, 1) + FIELD(TADCR, ITB3AE, 1, 1) + FIELD(TADCR, ITA4VE, 2, 1) + FIELD(TADCR, ITA3AE, 3, 1) + FIELD(TADCR, DT4BE, 4, 1) + FIELD(TADCR, UT4BE, 5, 1) + FIELD(TADCR, DT4AE, 6, 1) + FIELD(TADCR, UT4AE, 7, 1) + FIELD(TADCR, BF, 0, 1) +REG16(TCNT, 12) +REG16(TGRA, 13) +REG16(TGRB, 14) +REG16(TGRC, 15) +REG16(TGRD, 16) +REG16(TGRE, 17) +REG16(TGRF, 18) +REG8(TIORH, 19) +REG8(TIORL, 20) +REG16(TADCOBRA, 21) +REG16(TADCOBRB, 22) +REG16(TADCORA, 23) +REG16(TADCORB, 24) + +static const int div_rate[6][8] =3D { + [0] =3D {1, 4, 16, 64, 0, 0, 0, 0, }, + [1] =3D {1, 4, 16, 64, 0, 0, 256, 0, }, + [2] =3D {1, 4, 16, 64, 0, 0, 0, 1024, }, + [3] =3D {1, 4, 16, 64, 256, 1024, 0, 0, }, + [4] =3D {1, 4, 16, 64, 256, 1024, 0, 0, }, + [5] =3D {1, 4, 16, 64, 0, 0, 0, 0, }, +}; + +static bool is_cascade(RenesasMTU2State *mtu) +{ + if (mtu =3D=3D NULL) { + return false; + } + if (FIELD_EX8(mtu->r[1].tcr, TCR, TPSC) !=3D 7 || + mtu->r[2].ier) { + return false; + } + return true; +} + +static void mtu2_event(void *opaque); +static void set_next_event(RenesasMTURegs *r) +{ + int gr; + int64_t next; + uint32_t wcnt; + int ch =3D r->ch; + RenesasMTU2State *mtu =3D r->mtu; + + if (ch =3D=3D 1 && is_cascade(mtu)) { + /* If cascade count mode, skip ch1 event */ + return; + } + if (r->start) { + if (ch !=3D 2 || !is_cascade(mtu)) { + /* normal counter */ + r->next_cnt =3D 0x10000; + for (gr =3D 0; gr < r->num_gr; gr++) { + if (r->tcnt <=3D r->tgr[gr]) { + r->next_cnt =3D MIN(r->next_cnt, r->tgr[gr] + 1); + } + } + next =3D (r->next_cnt - r->tcnt) * r->clk; + g_assert(next > 0); + } else { + /* 32bit freerun counter */ + wcnt =3D mtu->r[2].tcnt; + wcnt =3D deposit32(wcnt, 16, 16, mtu->r[1].tcnt); + next =3D (0x100000000LL - wcnt) * r->clk; + } + g_assert(next > 0); + r->next =3D r->base + next; + if (r->timer =3D=3D NULL) { + r->timer =3D timer_new_ns(QEMU_CLOCK_VIRTUAL, + mtu2_event, r); + } + timer_mod(r->timer, r->next); + } else { + if (r->timer) { + timer_del(r->timer); + } + } +} + +static void mtu2_5_event(void *opaque); +static void set_next_event5(RenesasMTURegs *r) +{ + int64_t next; + + r->next_cnt =3D r->cntclr ? r->tgr[0] : 0x10000; + if (r->start) { + next =3D (r->next_cnt - r->tcnt) * r->clk; + g_assert(next > 0); + r->next =3D r->base + next; + if (r->timer =3D=3D NULL) { + r->timer =3D timer_new_ns(QEMU_CLOCK_VIRTUAL, + mtu2_5_event, r); + } + timer_mod(r->timer, r->next); + } else { + if (r->timer) { + timer_del(r->timer); + } + } +} + +static void tgr_match(RenesasMTURegs *r, int clr_gr) +{ + int gr; + + for (gr =3D 0; gr < r->num_gr; gr++) { + if (r->next_cnt =3D=3D r->tgr[gr]) { + /* TGR match */ + if (clr_gr =3D=3D gr) { + r->tcnt =3D 0; + } else { + r->tcnt =3D r->next_cnt; + } + if (extract16(r->tier, (gr < 4 ? gr : gr + 4), 1)) { + qemu_irq_pulse(r->irq[gr]); + } + } + } +} + +static int clr_gr(uint8_t tcr, int ch) +{ + switch (FIELD_EX8(tcr, TCR, CCLR)) { + case 1: + return 0; + case 2: + return 1; + case 5: + return 2; + case 6: + return 3; + default: + return -1; + } +} + +static void mtu2_event(void *opaque) +{ + RenesasMTURegs *r =3D opaque; + RenesasMTU2State *mtu =3D r->mtu; + uint32_t sync; + int ch; + + if (r->ch !=3D 2 || !is_cascade(mtu)) { + tgr_match(r, clr_gr(r->tcr, r->ch)); + if (r->next_cnt =3D=3D 0x10000) { + /* Count overflow */ + r->tcnt =3D 0; + r->base =3D r->next; + if (FIELD_EX16(r->tier, TIER, TCIEV)) { + qemu_irq_pulse(r->irq[r->num_gr]); + } + if (r->ch =3D=3D 2 && FIELD_EX8(mtu->r[1].tcr, TCR, TPSC) =3D= =3D 7) { + mtu->r[1].tcnt++; + tgr_match(&mtu->r[1], clr_gr(mtu->r[1].tcr, 1)); + if (mtu->r[1].tcnt >=3D 0x10000) { + mtu->r[1].tcnt =3D 0; + if (FIELD_EX16(mtu->r[1].tier, TIER, TCIEV)) { + qemu_irq_pulse(mtu->r[1].irq[mtu->r[1].num_gr]); + } + } + } + } + } else { + r->tcnt =3D 0; + mtu->r[1].tcnt =3D 0; + r->base =3D r->next; + if (FIELD_EX16(mtu->r[1].tier, TIER, TCIEV)) { + qemu_irq_pulse(mtu->r[1].irq[mtu->r[1].num_gr]); + } + } + set_next_event(r); + if (r->tcnt =3D=3D 0) { + sync =3D extract8(mtu->tsyr, 0, 3); + sync =3D deposit32(sync, 3, 2, extract8(mtu->tsyr, 6, 2)); + if (extract32(sync, r->ch, 1)) { + /* Syncronus clear */ + for (ch =3D 0; ch < 5; ch++) { + if (ch =3D=3D r->ch || !extract8(sync, ch, 1)) { + continue; + } + if ((FIELD_EX8(mtu->r[ch].tcr, TCR, CCLR) & 3) =3D=3D 3) { + mtu->r[ch].tcnt =3D 0; + set_next_event(&mtu->r[ch]); + } + } + } + } +} + +static void mtu2_5_event(void *opaque) +{ + RenesasMTURegs *r =3D opaque; + + if (r->next_cnt < 0x10000) { + if (r->ier) { + qemu_irq_pulse(r->irq[0]); + } + if (r->cntclr) { + r->tcnt =3D 0; + r->base =3D r->next; + } + } else { + r->tcnt =3D 0; + r->base =3D r->next; + } + set_next_event5(r); +} + +static uint16_t read_tcnt(RenesasMTURegs *r) +{ + int64_t now; + uint32_t wcnt; + + if (r->start) { + now =3D qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + if (!is_cascade(r->mtu)) { + if (r->ch =3D=3D 1 && FIELD_EX8(r->mtu->r[1].tcr, TCR, TPSC) = =3D=3D 7) { + return r->tcnt; + } else { + return (r->tcnt + (now - r->base) / r->clk) & 0xffff; + } + } else { + wcnt =3D r->mtu->r[2].tcnt; + wcnt =3D deposit32(wcnt, 16, 16, r->mtu->r[1].tcnt); + wcnt +=3D (now - r->mtu->r[2].base) / r->mtu->r[2].clk; + switch (r->ch) { + case 1: + return extract32(wcnt, 16, 16); + case 2: + return extract32(wcnt, 0, 16); + default: + g_assert_not_reached(); + } + } + } else { + return r->tcnt; + } +} + +static void mtu_pck_update(void *opaque) +{ + RenesasMTU2State *mtu =3D RenesasMTU2(opaque); + int ch; + for (ch =3D 0; ch < 5; ch++) { + mtu->r[ch].tcnt =3D read_tcnt(&mtu->r[ch]); + } + for (ch =3D 0; ch < 3; ch++) { + mtu->r5[ch].tcnt =3D read_tcnt(&mtu->r5[ch]); + } + mtu->input_freq =3D clock_get_hz(mtu->pck); + if (clock_is_enabled(mtu->pck)) { + for (ch =3D 0; ch < 5; ch++) { + set_next_event(&mtu->r[ch]); + } + for (ch =3D 0; ch < 3; ch++) { + set_next_event5(&mtu->r5[ch]); + } + } else { + for (ch =3D 0; ch < 5; ch++) { + if (mtu->r[ch].timer) { + timer_del(mtu->r[ch].timer); + } + } + for (ch =3D 0; ch < 3; ch++) { + if (mtu->r5[ch].timer) { + timer_del(mtu->r5[ch].timer); + } + } + } +} + +static bool mtu2_low_valid_size(hwaddr addr, unsigned size) +{ + if ((A_TCNT_012 <=3D addr && addr < (A_TGRD_012 + 2)) || + (A_TGRE_0 <=3D addr && addr < (A_TGRF_0 + 2))) { + if (size =3D=3D 2) { + return true; + } + } else { + if (size =3D=3D 1) { + return true; + } + } + return false; +} + +static uint64_t mtu2_low_read(void *opaque, hwaddr addr, unsigned size) +{ + RenesasMTU2State *mtu =3D RenesasMTU2(opaque); + int gr; + int ch =3D (addr >> 7) & 3; + addr &=3D 0x7f; + + if (!mtu2_low_valid_size(addr, size)) { + qemu_log_mask(LOG_GUEST_ERROR, + "renesas_mtu: Invalid access size %d of 0x%" + HWADDR_PRIX "\n", size, addr); + return UINT64_MAX; + } + if (!clock_is_enabled(mtu->pck)) { + qemu_log_mask(LOG_GUEST_ERROR, + "renesas_mtu: Unit %d is stopped.\n", mtu->unit); + return UINT64_MAX; + } + switch (addr) { + case A_TCR_012: + return mtu->r[ch].tcr; + case A_TMDR_012: + return mtu->r[ch].tmdr; + case A_TIORL_012: + return extract16(mtu->r[ch].tior, 0, 8); + case A_TIORH_012: + return extract16(mtu->r[ch].tior, 8, 8); + case A_TIER_012: + return extract16(mtu->r[ch].tier, 0, 8); + case A_TIER2_0: + if (ch =3D=3D 0) { + return extract16(mtu->r[ch].tier, 8, 8); + } else { + goto no_register; + } + case A_TSR_012: + return mtu->r[ch].tsr; + case A_TBTM_0: + if (ch =3D=3D 0) { + return mtu->tbtm; + } else { + goto no_register; + } + case A_TICCR_1: + if (ch =3D=3D 1) { + return mtu->ticcr; + } else { + goto no_register; + } + case A_TCNT_012: + return read_tcnt(&mtu->r[ch]); + case A_TGRA_012: + case A_TGRB_012: + case A_TGRC_012: + case A_TGRD_012: + gr =3D ((addr - A_TGRA_012) >> 1) & 3; + if (gr < mtu->r[ch].num_gr) { + return mtu->r[ch].tgr[gr]; + } else { + goto no_register; + } + case A_TGRE_0: + case A_TGRF_0: + if (ch =3D=3D 0) { + gr =3D (((addr - A_TGRE_0) >> 1) & 2) + 4; + return mtu->r[0].tgr[gr]; + } else { + goto no_register; + } + no_register: + default: + qemu_log_mask(LOG_GUEST_ERROR, + "renesas_mtu: Unknown register %08lx\n", + addr); + return UINT64_MAX; + } +} + +static bool mtu2_high_valid_size(hwaddr addr, unsigned size) +{ + if ((A_TCNT_3 <=3D addr && addr < (A_TGRD_4 + 2)) || + (A_TADCR <=3D addr && addr < (A_TADCORB + 2)) || + (A_TCDR <=3D addr && addr < (A_TCBR + 2))) { + if (size =3D=3D 2) { + return true; + } + } else { + if (size =3D=3D 1) { + return true; + } + } + return false; +} + +static uint64_t mtu2_high_read(void *opaque, hwaddr addr, unsigned size) +{ + RenesasMTU2State *mtu =3D RenesasMTU2(opaque); + int ch =3D 3 + (addr & 1); + int ch_w =3D 3 + ((addr >> 1) & 1); + uint32_t ret; + + if (!mtu2_high_valid_size(addr, size)) { + qemu_log_mask(LOG_GUEST_ERROR, + "renesas_mtu: Invalid access size %d\n", + size); + return UINT64_MAX; + } + if (addr < 0x20 && ((mtu->trwer & 1) =3D=3D 0)) { + qemu_log_mask(LOG_GUEST_ERROR, + "renesas_mtu: register read protected " + "0x%" HWADDR_PRIX "\n", addr); + return UINT64_MAX; + } + if (!clock_is_enabled(mtu->pck)) { + qemu_log_mask(LOG_GUEST_ERROR, + "renesas_mtu: Unit %d is stopped.\n", mtu->unit); + return UINT64_MAX; + } + switch (addr) { + case A_TCR_3: + case A_TCR_4: + return mtu->r[ch].tcr; + case A_TMDR_3: + case A_TMDR_4: + return mtu->r[ch].tmdr; + case A_TIORL_3: + case A_TIORL_4: + return extract32(mtu->r[ch_w].tior, 0, 8); + case A_TIORH_3: + case A_TIORH_4: + return extract32(mtu->r[ch_w].tior, 8, 8); + case A_TIER_3: + case A_TIER_4: + return mtu->r[ch].tier; + case A_TSR_3: + case A_TSR_4: + return mtu->r[ch].tsr; + case A_TCNT_3: + case A_TCNT_4: + return read_tcnt(&mtu->r[ch]); + case A_TGRA_3: + case A_TGRB_3: + case A_TGRA_4: + case A_TGRB_4: + return mtu->r[3 + ((addr >> 2) & 1)].tgr[(addr >> 1) & 1]; + case A_TGRC_3: + case A_TGRD_3: + case A_TGRC_4: + case A_TGRD_4: + return mtu->r[3 + ((addr >> 2) & 1)].tgr[2 + ((addr >> 1) & 1)]; + case A_TADCR_4: + return mtu->tadcr; + case A_TADCOBRA_4: + case A_TADCOBRB_4: + return mtu->tadcobr[(addr >> 1) & 1]; + case A_TADCORA_4: + case A_TADCORB_4: + return mtu->tadcor[(addr >> 1) & 1]; + case A_TOER: + return mtu->toer; + case A_TGCR: + return mtu->tgcr; + case A_TOCR1: + case A_TOCR2: + return mtu->tocr[addr & 1]; + case A_TCDR: + return mtu->tcdr; + case A_TDDR: + return mtu->tddr; + case A_TCNTS: + return mtu->tcnts; + case A_TCBR: + return mtu->tcbr; + case A_TITCR: + return mtu->titcr; + case A_TITCNT: + return mtu->titcnt; + case A_TBTER: + return mtu->tbter; + case A_TDER: + return mtu->tder; + case A_TOLBR: + return mtu->tolbr; + case A_TWCR: + return mtu->twcr; + case A_TSTR: + ret =3D 0; + for (ch =3D 0; ch < 5; ch++) { + ret =3D deposit32(ret, (ch < 3 ? ch : ch + 3), 1, mtu->r[ch].s= tart); + } + return ret; + case A_TSYR: + return mtu->tsyr; + case A_TRWER: + mtu->trwer_r =3D mtu->trwer; + return mtu->trwer; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "renesas_mtu: Unknown register 0x%" HWADDR_PRIX "\n", + addr); + return UINT64_MAX; + } +} + +static bool mtu2_5_valid_size(hwaddr addr, unsigned size) +{ + if (addr < A_TIER_5) { + addr &=3D 0x0f; + if (addr < A_TCRU_5) { + if (size =3D=3D 2) { + return true; + } + } else { + if (size =3D=3D 1) { + return true; + } + } + } else { + if (size =3D=3D 1) { + return true; + } + } + return false; +} + +static uint64_t mtu2_5_read(void *opaque, hwaddr addr, unsigned size) +{ + RenesasMTU2State *mtu =3D RenesasMTU2(opaque); + int ch; + uint32_t ret; + ch =3D addr >> 4; + if (!mtu2_5_valid_size(addr, size)) { + qemu_log_mask(LOG_GUEST_ERROR, + "renesas_mtu: Invalid access size at " + "0x%" HWADDR_PRIX "\n", addr); + } + if (!clock_is_enabled(mtu->pck)) { + qemu_log_mask(LOG_GUEST_ERROR, + "renesas_mtu: Unit %d is stopped.\n", mtu->unit); + return UINT64_MAX; + } + if (ch < 3) { + switch (addr & 0x0f) { + case A_TCNTU_5: + return read_tcnt(&mtu->r5[ch]); + case A_TGRU_5: + return mtu->r5[ch].tgr[0]; + case A_TCRU_5: + return mtu->r5[ch].tcr; + case A_TIORU_5: + return mtu->r5[ch].tior; + } + } else { + switch (addr) { + case A_TIER_5: + ret =3D 0; + for (ch =3D 0; ch < 3; ch++) { + ret =3D deposit32(ret, ch, 1, mtu->r5[ch].ier); + } + return ret; + case A_TSTR_5: + ret =3D 0; + for (ch =3D 0; ch < 3; ch++) { + ret =3D deposit32(ret, ch, 1, mtu->r5[ch].start); + } + return ret; + case A_TCNTCMPCLR_5: + ret =3D 0; + for (ch =3D 0; ch < 3; ch++) { + ret =3D deposit32(ret, ch, 1, mtu->r5[ch].cntclr); + } + return ret; + } + } + qemu_log_mask(LOG_GUEST_ERROR, + "renesas_mtu: Unknown register " + "0x%" HWADDR_PRIX "\n", addr); + return UINT64_MAX; +} + +static bool is_ext_clock(int ch, int tcr) +{ + int tpsc =3D FIELD_EX8(tcr, TCR, TPSC); + if (ch =3D=3D 1 && tcr =3D=3D 7) { + return false; + } else { + return div_rate[ch][tpsc] =3D=3D 0; + } +} + +static void set_cnt_clock(int64_t input_freq, RenesasMTURegs *r) +{ + int tpsc =3D FIELD_EX8(r->tcr, TCR, TPSC); + int ckeg =3D FIELD_EX8(r->tcr, TCR, CKEG); + int div =3D div_rate[r->ch][tpsc]; + int64_t clk; + + if (div >=3D 4 && ckeg >=3D 2) { + div /=3D 2; + } + if (div > 0) { + clk =3D NANOSECONDS_PER_SECOND / input_freq; + r->clk =3D clk * div; + } +} + +#define NOT_SUPPORT_REG_VAL(val, name) \ + if (val !=3D 0) { \ + qemu_log_mask(LOG_UNIMP, \ + "renesas_mtu: " #name " %02x is not supported.\n", \ + (uint8_t)val); \ + } + +static void mtu2_low_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + RenesasMTU2State *mtu =3D RenesasMTU2(opaque); + int ch =3D (addr >> 7) & 3; + addr &=3D 0x7f; + if (!mtu2_low_valid_size(addr, size)) { + qemu_log_mask(LOG_GUEST_ERROR, + "renesas_mtu: Invalid access size %d of " + "0x%" HWADDR_PRIX "\n", size, addr); + return; + } + if (!clock_is_enabled(mtu->pck)) { + qemu_log_mask(LOG_GUEST_ERROR, + "renesas_mtu: Unit %d is stopped.\n", mtu->unit); + return; + } + + switch (addr) { + case A_TCR_012: + if (mtu->r[ch].start) { + qemu_log_mask(LOG_GUEST_ERROR, + "renesas_mtu: CH %d is already started.\n", ch); + } + if (is_ext_clock(ch, val)) { + qemu_log_mask(LOG_UNIMP, + "renesas_mtu: External clock not supported.\n"); + } + mtu->r[ch].tcr =3D val; + set_cnt_clock(mtu->input_freq, &mtu->r[ch]); + set_next_event(&mtu->r[ch]); + break; + case A_TMDR_012: + mtu->r[ch].tmdr =3D val; + break; + case A_TIORL_012: + mtu->r[ch].tior =3D deposit32(mtu->r[ch].tior, 0, 8, val); + NOT_SUPPORT_REG_VAL(val, TIORL); + break; + case A_TIORH_012: + mtu->r[ch].tior =3D deposit32(mtu->r[ch].tior, 8, 8, val); + NOT_SUPPORT_REG_VAL(val, TIORH); + break; + case A_TIER_012: + mtu->r[ch].tier =3D deposit32(mtu->r[ch].tier, 0, 8, val); + break; + case A_TIER2_0: + if (ch =3D=3D 0) { + mtu->r[ch].tier =3D deposit32(mtu->r[ch].tior, 8, 8, val); + } else { + goto no_register; + } + break; + case A_TSR_012: + mtu->r[ch].tsr =3D deposit32(mtu->r[ch].tsr, 6, 1, extract32(val, = 6, 1)); + break; + case A_TBTM_0: + if (ch =3D=3D 0) { + mtu->tbtm =3D val; + break; + } else { + goto no_register; + } + case A_TICCR_1: + if (ch =3D=3D 1) { + mtu->ticcr =3D val; + break; + } else { + goto no_register; + } + case A_TCNT_012: + mtu->r[ch].tcnt =3D val; + if (mtu->r[ch].start) { + mtu->r[ch].base =3D qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + } + set_next_event(&mtu->r[ch]); + break; + case A_TGRA_012: + case A_TGRB_012: + case A_TGRC_012: + case A_TGRD_012: + mtu->r[ch].tgr[((addr - A_TGRA_012) >> 1) & 3] =3D val; + set_next_event(&mtu->r[ch]); + break; + case A_TGRE_0: + case A_TGRF_0: + if (ch =3D=3D 0) { + mtu->r[ch].tgr[(((addr - A_TGRE_0) >> 1) & 2) + 4] =3D val; + set_next_event(&mtu->r[ch]); + break; + } else { + goto no_register; + } + default: + no_register: + qemu_log_mask(LOG_GUEST_ERROR, + "renesas_mtu: Unknown register 0x%" HWADDR_PRIX "\n", + addr); + break; + } +} + +static void mtu2_high_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + RenesasMTU2State *mtu =3D RenesasMTU2(opaque); + int ch =3D 3 + (addr & 1); + int ch_w =3D 3 + ((addr >> 1) & 1); + int64_t now; + + if (!mtu2_high_valid_size(addr, size)) { + qemu_log_mask(LOG_GUEST_ERROR, + "renesas_mtu: Invalid access size %d\n", + size); + return; + } + if (addr < 0x20 && ((mtu->trwer & 1) =3D=3D 0)) { + qemu_log_mask(LOG_GUEST_ERROR, + "renesas_mtu: register write protected " + "0x%" HWADDR_PRIX "\n", addr); + return; + } + if (!clock_is_enabled(mtu->pck)) { + qemu_log_mask(LOG_GUEST_ERROR, + "renesas_mtu: Unit %d is stopped.\n", mtu->unit); + return; + } + + switch (addr) { + case A_TCR_3: + case A_TCR_4: + if (mtu->r[ch].start) { + qemu_log_mask(LOG_GUEST_ERROR, + "renesas_mtu: CH %d is already started.\n", ch); + } + if (is_ext_clock(ch, val)) { + qemu_log_mask(LOG_UNIMP, + "renesas_mtu: External clock not supported.\n"); + } + mtu->r[ch].tcr =3D val; + set_cnt_clock(mtu->input_freq, &mtu->r[ch]); + set_next_event(&mtu->r[ch]); + break; + case A_TMDR_3: + case A_TMDR_4: + mtu->r[ch].tmdr =3D val; + NOT_SUPPORT_REG_VAL(val, TMDR); + break; + case A_TIORL_3: + case A_TIORL_4: + mtu->r[ch_w].tior =3D deposit32(mtu->r[ch_w].tior, 0, 8, val); + NOT_SUPPORT_REG_VAL(val, TIORL); + break; + case A_TIORH_3: + case A_TIORH_4: + mtu->r[ch_w].tior =3D deposit32(mtu->r[ch_w].tior, 8, 8, val); + NOT_SUPPORT_REG_VAL(val, TIORH); + break; + case A_TIER_3: + case A_TIER_4: + mtu->r[ch].tier =3D val; + set_next_event(&mtu->r[ch]); + break; + case A_TSR_3: + case A_TSR_4: + mtu->r[ch].tsr =3D val; + break; + case A_TCNT_3: + case A_TCNT_4: + mtu->r[ch_w].tcnt =3D val; + if (mtu->r[ch].start) { + mtu->r[ch].base =3D qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + } + set_next_event(&mtu->r[ch]); + break; + case A_TGRA_3: + case A_TGRA_4: + case A_TGRB_3: + case A_TGRB_4: + mtu->r[3 + ((addr >> 2) & 1)].tgr[(addr >> 1) & 1] =3D val; + set_next_event(&mtu->r[3 + ((addr >> 2) & 1)]); + break; + case A_TGRC_3: + case A_TGRD_3: + case A_TGRC_4: + case A_TGRD_4: + mtu->r[3 + ((addr >> 2) & 1)].tgr[2 + ((addr >> 1) & 1)] =3D val; + set_next_event(&mtu->r[3 + ((addr >> 2) & 1)]); + break; + case A_TADCR_4: + mtu->tadcr =3D val; + NOT_SUPPORT_REG_VAL(val, TADCR); + break; + case A_TADCOBRA_4: + case A_TADCOBRB_4: + mtu->tadcobr[(addr >> 1) & 1] =3D val; + case A_TADCORA_4: + case A_TADCORB_4: + mtu->tadcor[(addr >> 1) & 1] =3D val; + case A_TOER: + mtu->toer =3D val; + break; + case A_TGCR: + mtu->tgcr =3D val; + break; + case A_TOCR1: + case A_TOCR2: + mtu->tocr[addr & 1] =3D val; + break; + case A_TCDR: + mtu->tcdr =3D val; + break; + case A_TDDR: + mtu->tddr =3D val; + break; + case A_TCNTS: + mtu->tcnts =3D val; + break; + case A_TCBR: + mtu->tcbr =3D val; + break; + case A_TITCR: + mtu->titcr =3D val; + break; + case A_TITCNT: + mtu->titcnt =3D val; + break; + case A_TBTER: + mtu->tbter =3D val; + break; + case A_TDER: + mtu->tder =3D val; + break; + case A_TOLBR: + mtu->tolbr =3D val; + break; + case A_TWCR: + mtu->twcr =3D val; + break; + case A_TSTR: + val =3D deposit64(val, 3, 2, extract64(val, 6, 2)); + now =3D qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + for (ch =3D 0; ch < 5; ch++) { + if (mtu->r[ch].start !=3D extract32(val, ch, 1)) { + mtu->r[ch].start =3D extract32(val, ch, 1); + if (mtu->r[ch].start) { + mtu->r[ch].base =3D now; + } + set_next_event(&mtu->r[ch]); + } + } + break; + case A_TSYR: + mtu->tsyr =3D val; + break; + case A_TRWER: + if (mtu->trwer_r) { + mtu->trwer =3D FIELD_DP8(mtu->trwer, TRWER, RWE, + FIELD_EX8(val, TRWER, RWE)); + mtu->trwer_r =3D 0; + } else { + qemu_log_mask(LOG_GUEST_ERROR, + "renesas_mtu: TRWER protected.\n"); + } + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "renesas_mtu: Unknown register " + "0x%" HWADDR_PRIX "\n", addr); + break; + } +} + +static void mtu2_5_write(void *opaque, hwaddr addr, uint64_t val, unsigned= size) +{ + RenesasMTU2State *mtu =3D RenesasMTU2(opaque); + int ch; + int64_t now; + + ch =3D addr >> 4; + if (!mtu2_5_valid_size(addr, size)) { + qemu_log_mask(LOG_GUEST_ERROR, + "renesas_mtu: Invalid access size at " + "0x%" HWADDR_PRIX "\n", addr); + return; + } + if (!clock_is_enabled(mtu->pck)) { + qemu_log_mask(LOG_GUEST_ERROR, + "renesas_mtu: Unit %d is stopped.\n", mtu->unit); + return; + } + if (ch < 3) { + switch (addr & 0x0f) { + case A_TCNTU_5: + mtu->r5[ch].tcnt =3D val; + set_next_event5(&mtu->r5[ch]); + break; + case A_TGRU_5: + mtu->r5[ch].tgr[0] =3D val; + set_next_event5(&mtu->r5[ch]); + break; + case A_TCRU_5: + mtu->r5[ch].tcr =3D val; + set_next_event5(&mtu->r5[ch]); + break; + case A_TIORU_5: + mtu->r5[ch].tior =3D val; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "renesas_mtu: Unknown register 0x%" + HWADDR_PRIX "\n", addr); + break; + } + } else { + switch (addr & 0xff) { + case A_TIER_5: + for (ch =3D 0; ch < 3; ch++) { + mtu->r5[ch].ier =3D extract64(val, ch, 1); + } + break; + case A_TSTR_5: + now =3D qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + for (ch =3D 0; ch < 3; ch++) { + if (mtu->r5[ch].start !=3D extract64(val, ch, 1)) { + mtu->r5[ch].start =3D extract64(val, ch, 1); + if (mtu->r5[ch].start) { + mtu->r5[ch].base =3D now; + } + set_next_event5(&mtu->r5[ch]); + } + } + break; + case A_TCNTCMPCLR_5: + for (ch =3D 0; ch < 3; ch++) { + if (mtu->r5[ch].cntclr !=3D extract64(val, ch, 1)) { + mtu->r5[ch].cntclr =3D extract64(val, ch, 1); + set_next_event5(&mtu->r5[ch]); + } + } + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "renesas_mtu: Unknown register %08lx\n", + addr); + break; + } + } +} + +static const MemoryRegionOps mtu2_low_ops =3D { + .write =3D mtu2_low_write, + .read =3D mtu2_low_read, + .endianness =3D DEVICE_NATIVE_ENDIAN, + .impl =3D { + .min_access_size =3D 1, + .max_access_size =3D 2, + }, +}; + +static const MemoryRegionOps mtu2_high_ops =3D { + .write =3D mtu2_high_write, + .read =3D mtu2_high_read, + .endianness =3D DEVICE_NATIVE_ENDIAN, + .impl =3D { + .min_access_size =3D 1, + .max_access_size =3D 2, + }, +}; + +static const MemoryRegionOps mtu2_5_ops =3D { + .write =3D mtu2_5_write, + .read =3D mtu2_5_read, + .endianness =3D DEVICE_NATIVE_ENDIAN, + .impl =3D { + .min_access_size =3D 1, + .max_access_size =3D 2, + }, +}; + +static void mtu_reg_init(int channel, RenesasMTU2State *mtu, RenesasMTUReg= s *r) +{ + int grn; + static const int gr[] =3D {6, 2, 2, 4, 4}; + r->ch =3D channel; + r->mtu =3D mtu; + r->tsr =3D 0xc0; + r->num_gr =3D gr[channel]; + for (grn =3D 0; grn < r->num_gr; grn++) { + r->tgr[grn] =3D 0xffff; + } +} + +static void mtu2_realize(DeviceState *dev, Error **errp) +{ + int ch; + RenesasMTU2State *mtu =3D RenesasMTU2(dev); + + for (ch =3D 0; ch < 5; ch++) { + mtu_reg_init(ch, mtu, &mtu->r[ch]); + if (clock_is_enabled(mtu->pck)) { + set_cnt_clock(mtu->input_freq, &mtu->r[ch]); + } + } + for (ch =3D 0; ch < 3; ch++) { + mtu->r5[ch].mtu =3D NULL; + mtu->r5[ch].tgr[0] =3D 0xffff; + if (clock_is_enabled(mtu->pck)) { + set_cnt_clock(mtu->input_freq, &mtu->r5[ch]); + } + } + mtu->ticcr =3D 0x00; + mtu->toer =3D 0xc0; + mtu->tgcr =3D 0x80; + mtu->tcdr =3D mtu->tddr =3D 0xffff; + mtu->tcbr =3D 0xffff; + mtu->tder =3D 0x01; + mtu->trwer =3D 0x01; +} + +static void mtu2_init(Object *obj) +{ + int ch, irq; + static int nr_irq[] =3D {7, 4, 4, 5, 5}; + SysBusDevice *d =3D SYS_BUS_DEVICE(obj); + RenesasMTU2State *mtu =3D RenesasMTU2(obj); + + memory_region_init_io(&mtu->memory[0], OBJECT(mtu), &mtu2_low_ops, + mtu, "renesas-mtu2-low", 0x180); + sysbus_init_mmio(d, &mtu->memory[0]); + memory_region_init_io(&mtu->memory[1], OBJECT(mtu), &mtu2_high_ops, + mtu, "renesas-mtu2-high", 0x90); + sysbus_init_mmio(d, &mtu->memory[1]); + memory_region_init_io(&mtu->memory[2], OBJECT(mtu), &mtu2_5_ops, + mtu, "renesas-mtu2-5", 0x40); + sysbus_init_mmio(d, &mtu->memory[2]); + for (ch =3D 0; ch < 5; ch++) { + for (irq =3D 0; irq < nr_irq[ch]; irq++) { + sysbus_init_irq(d, &mtu->r[ch].irq[irq]); + } + } + for (ch =3D 0; ch < 3; ch++) { + sysbus_init_irq(d, &mtu->r5[ch].irq[0]); + } + mtu->pck =3D qdev_init_clock_in(DEVICE(d), "pck", + mtu_pck_update, mtu); +} + +static Property mtu_properties[] =3D { + DEFINE_PROP_UINT32("unit", RenesasMTU2State, unit, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void mtu2_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(klass); + + dc->realize =3D mtu2_realize; + device_class_set_props(dc, mtu_properties); +} + +static const TypeInfo renesas_mtu_info =3D { + .name =3D TYPE_RENESAS_MTU2, + .parent =3D TYPE_SYS_BUS_DEVICE, + .instance_size =3D sizeof(RenesasMTU2State), + .instance_init =3D mtu2_init, + .class_init =3D mtu2_class_init, + .class_size =3D sizeof(RenesasMTU2Class), +}; + +static void mtu_register_types(void) +{ + type_register_static(&renesas_mtu_info); +} + +type_init(mtu_register_types) diff --git a/hw/timer/Kconfig b/hw/timer/Kconfig index 4d21b50ab0..b4553d7847 100644 --- a/hw/timer/Kconfig +++ b/hw/timer/Kconfig @@ -45,3 +45,5 @@ config AVR_TIMER16 config RENESAS_TIMER bool =20 +config RENESAS_MTU + bool diff --git a/hw/timer/meson.build b/hw/timer/meson.build index 6aed6d1e5f..4d16a59c02 100644 --- a/hw/timer/meson.build +++ b/hw/timer/meson.build @@ -10,6 +10,7 @@ softmmu_ss.add(when: 'CONFIG_CMSDK_APB_DUALTIMER', if_tru= e: files('cmsdk-apb-dua softmmu_ss.add(when: 'CONFIG_CMSDK_APB_TIMER', if_true: files('cmsdk-apb-t= imer.c')) softmmu_ss.add(when: 'CONFIG_RENESAS_TMR8', if_true: files('renesas_tmr8.c= ')) softmmu_ss.add(when: 'CONFIG_RENESAS_TIMER', if_true: files('renesas_timer= .c')) +softmmu_ss.add(when: 'CONFIG_RENESAS_MTU', if_true: files('renesas_mtu.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 Nov 16 04:02:32 2025 Delivered-To: importer@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+importer=patchew.org@nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1598532521; cv=none; d=zohomail.com; s=zohoarc; b=EwFPtXgAvqRNhnoZhQeNbsZ89sGxV+N7eFASNucrKFjGCuLph8wiPeKgDhEbEvYiMEkBsIqm4rRTe1tC/PXPoszhi84joz+WmxAgOMpXMUGQ2oWYy7tFNnGzxP2S1xWvR5Md43J22ZpaA09h8nNDW1JmfMX0LwIOxc7jnYCY5Iw= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1598532521; 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=fqMp84u5387B3rArRzugUP9WrP3UNOOwxr0a6UPy8VQ=; b=I+fZW/0JfKJqXkyMsSbUte/661R3Adm9oaPiLAL0AsAbSl5gCw00oqXi5pKT3emQsibkoU+dBPEsgC1E/de+OVDHnmaizXuzyhXd3FB+UBe5sQWbbQ89cvDUQIdI5XZ0G3tJsG3Fu1q2J7HMRYopnUBDO2Fccf4IVd3Gf3WL9ro= 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+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1598532521511227.7217538268917; Thu, 27 Aug 2020 05:48:41 -0700 (PDT) Received: from localhost ([::1]:46760 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kBHKZ-0007Xm-TY for importer@patchew.org; Thu, 27 Aug 2020 08:48:39 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:59086) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kBHBW-0008Ax-Lh for qemu-devel@nongnu.org; Thu, 27 Aug 2020 08:39:18 -0400 Received: from mail01.asahi-net.or.jp ([202.224.55.13]:47911) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kBHBS-0005y5-3g for qemu-devel@nongnu.org; Thu, 27 Aug 2020 08:39:18 -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 95A8910894A; Thu, 27 Aug 2020 21:39:08 +0900 (JST) Received: from yo-satoh-debian.localdomain (ZM005235.ppp.dion.ne.jp [222.8.5.235]) by sakura.ysato.name (Postfix) with ESMTPSA id 50D301C0696; Thu, 27 Aug 2020 21:39:08 +0900 (JST) From: Yoshinori Sato To: qemu-devel@nongnu.org Subject: [PATCH 14/20] hw/rx/rx62n: RX62N Add MTU module Date: Thu, 27 Aug 2020 21:38:53 +0900 Message-Id: <20200827123859.81793-15-ysato@users.sourceforge.jp> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200827123859.81793-1-ysato@users.sourceforge.jp> References: <20200827123859.81793-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+importer=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-detected-operating-system: by eggs.gnu.org: First seen = 2020/08/27 08:39:06 X-ACL-Warn: Detected OS = ??? 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+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" Signed-off-by: Yoshinori Sato Reviewed-by: Philippe Mathieu-Daud=C3=A9 --- include/hw/rx/rx62n.h | 3 +++ hw/rx/rx62n.c | 28 ++++++++++++++++++++++++++++ hw/rx/Kconfig | 1 + 3 files changed, 32 insertions(+) diff --git a/include/hw/rx/rx62n.h b/include/hw/rx/rx62n.h index f463148799..170c8cb6fc 100644 --- a/include/hw/rx/rx62n.h +++ b/include/hw/rx/rx62n.h @@ -28,6 +28,7 @@ #include "hw/intc/rx_icu.h" #include "hw/timer/renesas_tmr8.h" #include "hw/timer/renesas_timer.h" +#include "hw/timer/renesas_mtu.h" #include "hw/char/renesas_sci.h" #include "hw/rx/rx62n-cpg.h" #include "qemu/units.h" @@ -45,6 +46,7 @@ #define RX62N_NR_TMR 2 #define RX62N_NR_CMT 2 #define RX62N_NR_SCI 6 +#define RX62N_NR_MTU 2 =20 typedef struct RX62NClass { /*< private >*/ @@ -70,6 +72,7 @@ typedef struct RX62NState { RXICUState icu; RenesasTMR8State tmr[RX62N_NR_TMR]; RenesasCMTState cmt[RX62N_NR_CMT]; + RenesasMTU2State mtu[RX62N_NR_MTU]; RSCIAState sci[RX62N_NR_SCI]; RX62NCPGState cpg; =20 diff --git a/hw/rx/rx62n.c b/hw/rx/rx62n.c index f61383a4c2..344be846bc 100644 --- a/hw/rx/rx62n.c +++ b/hw/rx/rx62n.c @@ -46,6 +46,7 @@ #define RX62N_ICU_BASE 0x00087000 #define RX62N_TMR_BASE 0x00088200 #define RX62N_CMT_BASE 0x00088000 +#define RX62N_MTU_BASE 0x00088600 #define RX62N_SCI_BASE 0x00088240 #define RX62N_CPG_BASE 0x00080010 =20 @@ -55,6 +56,7 @@ */ #define RX62N_TMR_IRQ 174 #define RX62N_CMT_IRQ 28 +#define RX62N_MTU_IRQ 114 #define RX62N_SCI_IRQ 214 =20 /* @@ -187,6 +189,30 @@ static void register_cmt(RX62NState *s, int unit) qdev_get_clock_out(DEVICE(&s->cpg), ckname)); } =20 +static void register_mtu(RX62NState *s, int unit) +{ + SysBusDevice *mtu; + int i, irqbase; + char ckname[16]; + + object_initialize_child(OBJECT(s), "mtu[*]", &s->mtu[unit], + TYPE_RENESAS_MTU2); + mtu =3D SYS_BUS_DEVICE(&s->mtu[unit]); + qdev_prop_set_uint32(DEVICE(mtu), "unit", unit); + + sysbus_mmio_map(mtu, 0, RX62N_MTU_BASE + 0x100 + unit * 0x400); + sysbus_mmio_map(mtu, 1, RX62N_MTU_BASE + unit * 0x400); + sysbus_mmio_map(mtu, 2, RX62N_MTU_BASE + 0x280 + unit * 0x400); + irqbase =3D RX62N_MTU_IRQ + MTU_NR_IRQ * unit; + for (i =3D 0; i < MTU_NR_IRQ; i++) { + sysbus_connect_irq(mtu, i, s->irq[irqbase + i]); + } + sysbus_realize(mtu, &error_abort); + snprintf(ckname, sizeof(ckname), "pck_mtu-%d", unit); + qdev_connect_clock_in(DEVICE(mtu), "pck", + qdev_get_clock_out(DEVICE(&s->cpg), ckname)); +} + static void register_sci(RX62NState *s, int unit) { SysBusDevice *sci; @@ -248,6 +274,8 @@ static void rx62n_realize(DeviceState *dev, Error **err= p) register_tmr(s, 1); register_cmt(s, 0); register_cmt(s, 1); + register_mtu(s, 0); + register_mtu(s, 1); register_sci(s, 0); sysbus_realize(SYS_BUS_DEVICE(&s->cpg), &error_abort); } diff --git a/hw/rx/Kconfig b/hw/rx/Kconfig index d1812870ea..887a5782bb 100644 --- a/hw/rx/Kconfig +++ b/hw/rx/Kconfig @@ -4,6 +4,7 @@ config RX62N_MCU select RENESAS_TMR8 select RENESAS_TIMER select RENESAS_SCI + select RENESAS_MTU =20 config RX_GDBSIM bool --=20 2.20.1 From nobody Sun Nov 16 04:02:32 2025 Delivered-To: importer@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+importer=patchew.org@nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1598532578; cv=none; d=zohomail.com; s=zohoarc; b=lhHjw22oQeBDPg2wcL5BYotyWW2oGxLHc/iGJTs3dXXrqplpcxb2nfzzWB4CGQzLBIJZ3mlx5i7DyhVTvKJIv9qOLPVzHxnP4EAjfOKjgNRc7LgJYJbb4IurbLgXSGtPN5u+SveZUTZF+cO6LSXa4MohS1VHrV+QEyxM3XraLgY= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1598532578; 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=oIWTuw7UjgarCZqNUyl9ZhOSARDgtd4T2ZKjFFO6TDI=; b=VT2uiQmLxExzyhnVs8fkVZ2e8sYncT2zQ1P1CrsPWJrlqUV94Y3KUZ5fFJvV58MskMltXXs8iZGRUcp/aKjp4dkiW2T545PNd6YD+fkz9gMYFo35pzlDlH05Amc5SsvtPZnaZh6Dgyik7DwC8tCap+4tXMSC5whSImVwjiaoVHE= 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+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1598532578932849.378878316418; Thu, 27 Aug 2020 05:49:38 -0700 (PDT) Received: from localhost ([::1]:50832 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kBHLV-0000m8-It for importer@patchew.org; Thu, 27 Aug 2020 08:49:37 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:59140) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kBHBf-0000CE-GF for qemu-devel@nongnu.org; Thu, 27 Aug 2020 08:39:27 -0400 Received: from mail01.asahi-net.or.jp ([202.224.55.13]:47915) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kBHBd-0005yl-09 for qemu-devel@nongnu.org; Thu, 27 Aug 2020 08:39:27 -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 CA76D108974; Thu, 27 Aug 2020 21:39:08 +0900 (JST) Received: from yo-satoh-debian.localdomain (ZM005235.ppp.dion.ne.jp [222.8.5.235]) by sakura.ysato.name (Postfix) with ESMTPSA id 813D91C0792; Thu, 27 Aug 2020 21:39:08 +0900 (JST) From: Yoshinori Sato To: qemu-devel@nongnu.org Subject: [PATCH 15/20] hw/net: Add generic Bit-bang MDIO PHY. Date: Thu, 27 Aug 2020 21:38:54 +0900 Message-Id: <20200827123859.81793-16-ysato@users.sourceforge.jp> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200827123859.81793-1-ysato@users.sourceforge.jp> References: <20200827123859.81793-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+importer=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-detected-operating-system: by eggs.gnu.org: First seen = 2020/08/27 08:39:06 X-ACL-Warn: Detected OS = ??? 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+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" Only supported link status. Signed-off-by: Yoshinori Sato --- include/hw/net/mdio.h | 126 ++++++++++++++++++++ hw/net/mdio.c | 264 ++++++++++++++++++++++++++++++++++++++++++ hw/net/Kconfig | 3 + hw/net/meson.build | 2 + 4 files changed, 395 insertions(+) create mode 100644 include/hw/net/mdio.h create mode 100644 hw/net/mdio.c diff --git a/include/hw/net/mdio.h b/include/hw/net/mdio.h new file mode 100644 index 0000000000..55a7170e67 --- /dev/null +++ b/include/hw/net/mdio.h @@ -0,0 +1,126 @@ +/* + * MDIO PHY emulation + * + * Copyright 2020 Yoshinori Sato + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 2 of the License. + * + * This program is distributed in the hope that 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 for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ + +#ifndef MDIO_H +#define MDIO_H + +#include "hw/qdev-core.h" +#include "hw/net/mii.h" + +typedef enum mdio_pin { + mdio_z =3D -1, + mdio_l =3D 0, + mdio_h =3D 1, +} MDIOPin; + +#define TYPE_ETHER_PHY "ether-phy" +#define TYPE_ETHER_PHY_CLASS(obj) \ + OBJECT_GET_CLASS(EtherPHYClass, (obj), TYPE_ETHER_PHY) +#define EtherPHYClass(klass) \ + OBJECT_CHECK_CLASS(EtherPHYClass, (klass), TYPE_ETHER_PHY) +#define EtherPHY(obj) \ + OBJECT_CHECK(PHYState, (obj), TYPE_ETHER_PHY) + +#define TYPE_ETHER_MDIO_BB "ether-mdio-bb" +#define TYPE_ETHER_MDIO_BB_CLASS(obj) \ + OBJECT_GET_CLASS(MDIO_BBClass, (obj), TYPE_ETHER_MDIO_BB) +#define MDIO_BBClass(klass) \ + OBJECT_CHECK_CLASS(MDIO_BBClass, (klass), TYPE_ETHER_MDIO_BB) +#define MDIO_BB(obj) \ + OBJECT_CHECK(MDIOState, (obj), TYPE_ETHER_MDIO_BB) + +typedef enum { + phy_out_p =3D 0, /* Link up is 'H' */ + phy_out_n =3D 1, /* Link up is 'L' */ +} phy_output_polarity; + +typedef struct { + DeviceState parent; + + uint16_t regs[32]; + uint32_t identifier; + bool link_ok; + phy_output_polarity link_out_pol; + uint16_t bmsr; + uint16_t anlpar; +} PHYState; + +#define MDIO_ANLPAR_LINK \ + (MII_ANLPAR_TXFD | MII_ANLPAR_TX | MII_ANLPAR_10FD | MII_ANLPAR_10 | \ + MII_ANLPAR_CSMACD) + +typedef enum { + BB_PRE, + BB_ST, + BB_CMD, + BB_TA_R, + BB_TA_W, + BB_DATA_R, + BB_DATA_W, + BB_INH, +} mdio_bb_state; + +typedef struct { + DeviceState parent; + + PHYState *phy; + mdio_bb_state bb_state; + int pclk; + int bits; + int cmd; + int phyad; + int selphy; + int regad; + int data; + int mdi_pin; + int mdo_pin; +} MDIOState; + +#define mdio_get_phy(s) (s->phy) + +typedef struct { + DeviceClass parent; +} EtherPHYClass; + +typedef struct { + DeviceClass parent; +} MDIO_BBClass; + +/* Generic PHY interface */ +void mdio_phy_set_link(PHYState *s, bool ok); +int mdio_phy_linksta(PHYState *s); +uint16_t mdio_phy_read(PHYState *s, int addr); +void mdio_phy_write(PHYState *s, int addr, uint16_t val); + +/* Bit-bang MDIO operation */ +static inline MDIOPin mdio_read_mdi_pin(MDIOState *s) +{ + return s->mdi_pin; +} + +static inline void mdio_set_mdo_pin(MDIOState *s, MDIOPin mdo) +{ + s->mdo_pin =3D mdo; +} + +void mdio_set_mdc_pin(MDIOState *s, int clk); + +#endif diff --git a/hw/net/mdio.c b/hw/net/mdio.c new file mode 100644 index 0000000000..39670e70c6 --- /dev/null +++ b/hw/net/mdio.c @@ -0,0 +1,264 @@ +/* + * Bit-bang MII emulation + * + * Copyright 2020 Yoshinori Sato + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 2 of the License. + * + * This program is distributed in the hope that 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 for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ + +#include "qemu/osdep.h" +#include "qemu/bitops.h" +#include "qemu/log.h" +#include "hw/qdev-properties.h" +#include "hw/net/mdio.h" + +void mdio_phy_set_link(PHYState *s, bool ok) +{ + if (ok) { + s->regs[MII_BMSR] |=3D MII_BMSR_LINK_ST; + s->regs[MII_ANLPAR] |=3D MDIO_ANLPAR_LINK; + } else { + s->regs[MII_BMSR] &=3D ~(MII_BMSR_LINK_ST | MII_BMSR_AUTONEG); + s->regs[MII_ANLPAR] &=3D MDIO_ANLPAR_LINK; + } + s->link_ok =3D ok; +} + +static void mdio_phy_reset(PHYState *s) +{ + memset(s->regs, 0, sizeof(s->regs)); + s->regs[MII_BMSR] =3D s->bmsr; + s->regs[MII_ANLPAR] =3D s->anlpar; + s->regs[MII_PHYID1] =3D extract32(s->identifier, 16, 16); + s->regs[MII_PHYID2] =3D extract32(s->identifier, 0, 16); + mdio_phy_set_link(s, s->link_ok); +} + +uint16_t mdio_phy_read(PHYState *s, int addr) +{ + if (addr >=3D 0 && addr < 32) { + return s->regs[addr]; + } else { + qemu_log_mask(LOG_GUEST_ERROR, + "mdio: Register %04x invalid address.\n", addr); + return 0; + } +} + +int mdio_phy_linksta(PHYState *s) +{ + return s->link_ok ^ s->link_out_pol; +} + +void mdio_phy_write(PHYState *s, int addr, uint16_t val) +{ + switch (addr) { + case MII_BMCR: + s->regs[MII_BMCR] =3D val & 0xfd80; + if (val & MII_BMCR_RESET) { + mdio_phy_reset(s); + } + break; + case MII_BMSR: + case MII_ANLPAR: + /* Read only */ + qemu_log_mask(LOG_GUEST_ERROR, + "mdio: Register %04x is read only register.\n", addr= ); + break; + case MII_PHYID1: + case MII_PHYID2: + s->regs[addr] =3D val; + break; + case MII_ANAR: + s->regs[addr] =3D val & 0x2dff; + break; + default: + qemu_log_mask(LOG_UNIMP, + "mdio: Register %04x not implemented\n", addr); + break; + } +} + +static Property phy_properties[] =3D { + DEFINE_PROP_UINT32("phy-id", PHYState, identifier, 0), + DEFINE_PROP_UINT32("link-out-pol", PHYState, link_out_pol, 0), + DEFINE_PROP_UINT16("bmsr", PHYState, bmsr, 0), + DEFINE_PROP_UINT16("anlpar", PHYState, anlpar, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void phy_realize(DeviceState *dev, Error **errp) +{ + PHYState *s =3D EtherPHY(dev); + mdio_phy_reset(s); +} + +static void phy_class_init(ObjectClass *klass, void *class_data) +{ + DeviceClass *dc =3D DEVICE_CLASS(klass); + device_class_set_props(dc, phy_properties); + dc->realize =3D phy_realize; +} + +/* shift in MDO */ +static void read_mdo(MDIOState *s) +{ + int op; + s->bits++; + switch (s->bb_state) { + case BB_PRE: /* preamble */ + if (s->mdo_pin =3D=3D 0) { + /* ST 1st bit found */ + s->bb_state =3D BB_ST; + } + break; + case BB_ST: /* ST 2nd bit */ + if (s->mdo_pin =3D=3D 0) { + s->bb_state =3D BB_CMD; + s->cmd =3D 0; + s->bits =3D 2; + s->selphy =3D -1; + s->regad =3D -1; + } else { + s->bb_state =3D BB_PRE; + } + break; + case BB_CMD: + s->cmd <<=3D 1; + s->cmd |=3D (s->mdo_pin & 1); + if (s->bits =3D=3D 14) { + op =3D extract32(s->cmd, 10, 2); + s->selphy =3D extract32(s->cmd, 5, 5); + s->regad =3D extract32(s->cmd, 0, 5); + switch (op) { + case 0x02: /* READ */ + s->bb_state =3D BB_TA_R; + break; + case 0x01: /* WRITE */ + s->bb_state =3D BB_TA_W; + break; + default: + s->bb_state =3D BB_INH; + break; + } + } + break; + case BB_TA_R: + s->mdi_pin =3D 0; + if (s->bits =3D=3D 16) { + if (s->phyad =3D=3D s->selphy) { + s->data =3D mdio_phy_read(s->phy, s->regad); + s->bb_state =3D BB_DATA_R; + } else { + s->bb_state =3D BB_INH; + } + } + break; + case BB_TA_W: + if (s->bits =3D=3D 16) { + s->bb_state =3D BB_DATA_W; + } + break; + case BB_DATA_W: + s->data <<=3D 1; + s->data |=3D (s->mdo_pin & 1); + if (s->bits =3D=3D 32) { + if (s->phyad =3D=3D s->selphy) { + mdio_phy_write(s->phy, s->regad, s->data); + } + s->bb_state =3D BB_PRE; + } + break; + case BB_INH: + case BB_DATA_R: + if (s->bits =3D=3D 32) { + s->bb_state =3D BB_PRE; + } + break; + } +} + +/* shift out MDI */ +static void write_mdi(MDIOState *s) +{ + switch (s->bb_state) { + case BB_DATA_R: + s->mdi_pin =3D (s->data >> 15) & 1; + s->data <<=3D 1; + break; + case BB_TA_R: + s->mdi_pin =3D 0; + break; + default: + s->mdi_pin =3D mdio_z; + break; + } +} + +/* MDIO pin operation */ +void mdio_set_mdc_pin(MDIOState *s, int clk) +{ + if (s->pclk ^ (clk & 1)) { + s->pclk =3D (clk & 1); + if (s->pclk =3D=3D 1) { + /* rising edge */ + read_mdo(s); + } else { + /* faling edge */ + write_mdi(s); + } + } +} + +static Property bb_properties[] =3D { + DEFINE_PROP_INT32("address", MDIOState, phyad, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void bb_init(Object *obj) +{ + MDIOState *s =3D MDIO_BB(obj); + + object_property_add_link(obj, "phy", + TYPE_ETHER_PHY, + (Object **)&s->phy, + qdev_prop_allow_set_link_before_realize, + OBJ_PROP_LINK_STRONG); +} + +static void bb_class_init(ObjectClass *klass, void *class_data) +{ + DeviceClass *dc =3D DEVICE_CLASS(klass); + device_class_set_props(dc, bb_properties); +} + +static const TypeInfo phy_types_info[] =3D { + { + .name =3D TYPE_ETHER_PHY, + .parent =3D TYPE_DEVICE, + .class_init =3D phy_class_init, + .instance_size =3D sizeof(PHYState), + }, + { + .name =3D TYPE_ETHER_MDIO_BB, + .parent =3D TYPE_DEVICE, + .class_init =3D bb_class_init, + .instance_size =3D sizeof(MDIOState), + .instance_init =3D bb_init, + }, +}; + +DEFINE_TYPES(phy_types_info); diff --git a/hw/net/Kconfig b/hw/net/Kconfig index e43c96dae0..e6a32a2ab0 100644 --- a/hw/net/Kconfig +++ b/hw/net/Kconfig @@ -143,3 +143,6 @@ config CAN_SJA1000 default y if PCI_DEVICES depends on PCI select CAN_BUS + +config MDIO_PHY + bool diff --git a/hw/net/meson.build b/hw/net/meson.build index 4a7051b54a..faa4e3d2c0 100644 --- a/hw/net/meson.build +++ b/hw/net/meson.build @@ -64,4 +64,6 @@ softmmu_ss.add(when: 'CONFIG_ROCKER', if_true: files( ), if_false: files('rocker/qmp-norocker.c')) softmmu_ss.add(when: 'CONFIG_ALL', if_true: files('rocker/qmp-norocker.c')) =20 +softmmu_ss.add(when: 'CONFIG_MDIO_PHY', if_true: files('mdio.c')) + subdir('can') --=20 2.20.1 From nobody Sun Nov 16 04:02:32 2025 Delivered-To: importer@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+importer=patchew.org@nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1598532521; cv=none; d=zohomail.com; s=zohoarc; b=nFyeDFkcpK7n0hba4XjvgwmxQZyubYRx43x4X5RWf0yq4DYduKKGKjQqb/QR5M6o41hf59odAzutkgRN98VpBr+hIpnqC9hUuVaY2+lA/yRhphOmXpllcbo/WgxMGjt7xSlv0qO+pZOKlCcMMMODkgxnKkmJenzkvEwEwpNm+Og= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1598532521; 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=Hf0CjX54kvZUdem7FJDKQcyMjttAoahzMO5LBJQoxw0=; b=Aguuwc4PpNuax2Wzml0Nvi3ofU+FDTlqmOp0sXDY+x7qDjbDm+4b429DgXkJUYI+ov3uZOmwwrH+LoHGnYPaf85CrA4wCAdqjRUr3ZeopKezZoZA9XGTy8kVyI78fQTXIz/h9NOh7oMpBsCz5lnXfkrZlNK0pidSPE6KXKcwrAE= 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+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1598532521942204.77097587900823; Thu, 27 Aug 2020 05:48:41 -0700 (PDT) Received: from localhost ([::1]:46756 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kBHKa-0007Xe-CT for importer@patchew.org; Thu, 27 Aug 2020 08:48:40 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:59122) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kBHBY-0008Gn-Iq for qemu-devel@nongnu.org; Thu, 27 Aug 2020 08:39:20 -0400 Received: from mail01.asahi-net.or.jp ([202.224.55.13]:47914) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kBHBS-0005yk-Vx for qemu-devel@nongnu.org; Thu, 27 Aug 2020 08:39:20 -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 2C08F10866C; Thu, 27 Aug 2020 21:39:09 +0900 (JST) Received: from yo-satoh-debian.localdomain (ZM005235.ppp.dion.ne.jp [222.8.5.235]) by sakura.ysato.name (Postfix) with ESMTPSA id BA5631C0696; Thu, 27 Aug 2020 21:39:08 +0900 (JST) From: Yoshinori Sato To: qemu-devel@nongnu.org Subject: [PATCH 16/20] hw/net: Add Renesas On-chip Ethernet MAC Date: Thu, 27 Aug 2020 21:38:55 +0900 Message-Id: <20200827123859.81793-17-ysato@users.sourceforge.jp> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200827123859.81793-1-ysato@users.sourceforge.jp> References: <20200827123859.81793-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+importer=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-detected-operating-system: by eggs.gnu.org: First seen = 2020/08/27 08:39:06 X-ACL-Warn: Detected OS = ??? 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+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" Signed-off-by: Yoshinori Sato --- include/hw/net/renesas_eth.h | 57 +++ hw/net/renesas_eth.c | 875 +++++++++++++++++++++++++++++++++++ hw/net/Kconfig | 5 + hw/net/meson.build | 1 + 4 files changed, 938 insertions(+) create mode 100644 include/hw/net/renesas_eth.h create mode 100644 hw/net/renesas_eth.c diff --git a/include/hw/net/renesas_eth.h b/include/hw/net/renesas_eth.h new file mode 100644 index 0000000000..e0026c6434 --- /dev/null +++ b/include/hw/net/renesas_eth.h @@ -0,0 +1,57 @@ +/* + * Renesas ETHERC / EDMAC + * + * Copyright 2019 Yoshinori Sato + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 2 of the License. + * + * This program is distributed in the hope that 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 for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ + +#include "hw/sysbus.h" +#include "net/net.h" +#include "hw/net/mdio.h" +#include "hw/register.h" +#include "hw/clock.h" + +#define TYPE_RENESAS_ETH "renesas_eth" +#define RenesasEth(obj) OBJECT_CHECK(RenesasEthState, (obj), TYPE_RENESAS_= ETH) + +#define RENESAS_ETHERC_R_MAX (0x100 / 4) +#define RENESAS_EDMAC_R_MAX (0x100 / 4) + +typedef struct RenesasEthState { + SysBusDevice parent_obj; + + NICState *nic; + NICConf conf; + MemoryRegion etherc_mem; + MemoryRegion edmac_mem; + qemu_irq irq; + + /* ETHERC registers */ + RegisterInfo etherc_regs_info[RENESAS_ETHERC_R_MAX]; + uint32_t etherc_regs[RENESAS_ETHERC_R_MAX]; + + /* EDMAC register */ + RegisterInfo edmac_regs_info[RENESAS_EDMAC_R_MAX]; + uint32_t edmac_regs[RENESAS_EDMAC_R_MAX]; + + int descsize; + int rcv_bcast; + uint8_t macadr[6]; + int link_sta; + MDIOState *mdiodev; + Clock *ick; +} RenesasEthState; diff --git a/hw/net/renesas_eth.c b/hw/net/renesas_eth.c new file mode 100644 index 0000000000..d5fc2bb30c --- /dev/null +++ b/hw/net/renesas_eth.c @@ -0,0 +1,875 @@ +/* + * Renesas ETHERC / EDMAC + * + * Copyright 2019 Yoshinori Sato + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 2 of the License. + * + * This program is distributed in the hope that 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 for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ + +#include "qemu/osdep.h" + +#include "hw/hw.h" +#include "sysemu/dma.h" +#include "qemu/log.h" +#include "hw/qdev-properties.h" +#include "hw/qdev-clock.h" +#include "net/net.h" +#include "sysemu/sysemu.h" +#include "hw/irq.h" +#include "hw/net/renesas_eth.h" + +/* ETHERC Registers */ +REG32(ECMR, 0x00) + FIELD(ECMR, PRM, 0, 1) + FIELD(ECMR, DM, 1, 1) + FIELD(ECMR, RTM, 2, 1) + FIELD(ECMR, ILB, 3, 1) + FIELD(ECMR, TE, 5, 1) + FIELD(ECMR, RE, 6, 1) + FIELD(ECMR, MPDE, 9, 1) + FIELD(ECMR, PRCREF, 12, 1) + FIELD(ECMR, TXF, 16, 1) + FIELD(ECMR, RXF, 17, 1) + FIELD(ECMR, PFR, 18, 1) + FIELD(ECMR, ZPF, 19, 1) + FIELD(ECMR, TPC, 20, 1) +REG32(RFLR, 0x08) + FIELD(RFLR, RFL, 0, 12) +REG32(ECSR, 0x10) + FIELD(ECSR, ICD, 0, 1) + FIELD(ECSR, MPD, 1, 1) + FIELD(ECSR, LCHNG, 2, 1) + FIELD(ECSR, PSRTO, 4, 1) + FIELD(ECSR, BFR, 5, 1) +REG32(ECSIPR, 0x18) + FIELD(ECSIPR, ICDIP, 0, 1) + FIELD(ECSIPR, MPDIP, 1, 1) + FIELD(ECSIPR, LCHNGIP, 2, 1) + FIELD(ECSIPR, PSRTOIP, 4, 1) + FIELD(ECSIPR, BFSIPR, 5, 1) +REG32(PIR, 0x20) + FIELD(PIR, MDC, 0, 1) + FIELD(PIR, MMD, 1, 1) + FIELD(PIR, MDO, 2, 1) + FIELD(PIR, MDI, 3, 1) +REG32(PSR, 0x28) + FIELD(PSR, LMON, 0, 1) +REG32(RDMLR, 0x40) + FIELD(RDMLR, RMD, 0, 20) +REG32(IPGR, 0x50) + FIELD(IPGR, IPG, 0, 5) +REG32(APR, 0x54) + FIELD(APR, AP, 0, 16) +REG32(MPR, 0x58) + FIELD(MPR, MP, 0, 16) +REG32(RFCF, 0x60) + FIELD(RFCF, RPAUSE, 0, 8) +REG32(TPAUSER, 0x64) +REG32(TPAUSECR, 0x68) + FIELD(TPAUSECR, TXP, 0, 8) + FIELD(TPAUSER, TPAUSE, 0, 16) +REG32(BCFRR, 0x6c) + FIELD(BCFRR, BCF, 0, 16) +REG32(MAHR, 0xc0) + FIELD(MAHR, MA, 0, 32) +REG32(MALR, 0xc8) + FIELD(MALR, MA, 0, 16) +REG32(TROCR, 0xd0) +REG32(CDCR, 0xd4) +REG32(LCCR, 0xd8) +REG32(CNDCR, 0xdc) +REG32(CEFCR, 0xe4) +REG32(FRECR, 0xe8) +REG32(TSFRCR, 0xec) +REG32(TLFRCR, 0xf0) +REG32(RFCR, 0xf4) +REG32(MAFCR, 0xf8) + +/* EDMAC register */ +REG32(EDMR, 0x00) + FIELD(EDMR, SWR, 0, 1) + FIELD(EDMR, DL, 4, 2) + FIELD(EDMR, DE, 6, 1) +REG32(EDTRR, 0x08) + FIELD(EDTRR, TR, 0, 1) +REG32(EDRRR, 0x10) + FIELD(EDRRR, RR, 0, 1) +REG32(TDLAR, 0x18) +REG32(RDLAR, 0x20) +REG32(EESR, 0x28) + FIELD(EESR, CERF, 0, 1) + FIELD(EESR, PRE, 1, 1) + FIELD(EESR, RTSF, 2, 1) + FIELD(EESR, RTLF, 3, 1) + FIELD(EESR, RRF, 4, 1) + FIELD(EESR, RMAF, 7, 1) + FIELD(EESR, TRO, 8, 1) + FIELD(EESR, CD, 9, 1) + FIELD(EESR, RDESC, 0, 10) + FIELD(EESR, DLC, 10, 1) + FIELD(EESR, CND, 11, 1) + FIELD(EESR, RDOF, 16, 1) + FIELD(EESR, RDE, 17, 1) + FIELD(EESR, FR, 18, 1) + FIELD(EESR, TFUF, 19, 1) + FIELD(EESR, TDE, 20, 1) + FIELD(EESR, TC, 21, 1) + FIELD(EESR, ECI, 22, 1) + FIELD(EESR, ADE, 23, 1) + FIELD(EESR, RFCOF, 24, 1) + FIELD(EESR, RABT, 25, 1) + FIELD(EESR, TABT, 26, 1) + FIELD(EESR, TWB, 30, 1) +REG32(EESIPR, 0x30) + FIELD(EESIPR, CERFIP, 0, 1) + FIELD(EESIPR, PREIP, 1, 1) + FIELD(EESIPR, RTSFIP, 2, 1) + FIELD(EESIPR, RTLFIP, 3, 1) + FIELD(EESIPR, RRFIP, 4, 1) + FIELD(EESIPR, RMAFIP, 7, 1) + FIELD(EESIPR, TROIP, 8, 1) + FIELD(EESIPR, CDIP, 9, 1) + FIELD(EESIPR, DLCIP, 10, 1) + FIELD(EESIPR, CNDIP, 11, 1) + FIELD(EESIPR, RDOFIP, 16, 1) + FIELD(EESIPR, RDEIP, 17, 1) + FIELD(EESIPR, FRIP, 18, 1) + FIELD(EESIPR, TFUFIP, 19, 1) + FIELD(EESIPR, TDEIP, 20, 1) + FIELD(EESIPR, TCIP, 21, 1) + FIELD(EESIPR, ECIIP, 22, 1) + FIELD(EESIPR, ADEIP, 23, 1) + FIELD(EESIPR, RFCOFIP, 24, 1) + FIELD(EESIPR, RABTIP, 25, 1) + FIELD(EESIPR, TABTIP, 26, 1) + FIELD(EESIPR, TWBIP, 30, 1) +REG32(TRSCER, 0x38) + FIELD(TRSCER, RRFCE, 4, 1) + FIELD(TRSCER, RMAFCE, 7, 1) +REG32(RMFCR, 0x40) + FIELD(RMFCR, MFC, 0, 16) +REG32(TFTR, 0x48) + FIELD(TFTR, TFT, 0, 11) +REG32(FDR, 0x50) + FIELD(FDR, RFD, 0, 5) + FIELD(FDR, TFD, 8, 5) +REG32(RMCR, 0x58) + FIELD(RMCR, RNR, 0, 1) + FIELD(RMCR, RNC, 1, 1) +REG32(TFUCR, 0x64) + FIELD(TFUCR, UNDER, 0, 16) +REG32(RFOCR, 0x68) + FIELD(RFOCR, OVER, 0, 16) +REG32(IOSR, 0x6c) + FIELD(IOSR, ELB, 0, 1); +REG32(FCFTR, 0x70) + FIELD(FCFTR, RFDO, 0, 3) + FIELD(FCFTR, RFFO, 16, 3) +REG32(RPADIR, 0x78) + FIELD(RPADIR, PADR, 0, 6) + FIELD(RPADIR, PADS, 16, 2) +REG32(TRIMD, 0x7c) + FIELD(TRIMD, TIS, 0, 1) + FIELD(TRIMD, TIM, 4, 1) +REG32(RBWAR, 0xc8) +REG32(RDFAR, 0xcc) +REG32(TBRAR, 0xd4) +REG32(TDFAR, 0xd8) + +/* Transmit Descriptor */ +REG32(TD0, 0x0000) + FIELD(TD0, TFS0, 0, 1) + FIELD(TD0, TFS1, 1, 1) + FIELD(TD0, TFS2, 2, 1) + FIELD(TD0, TFS3, 3, 1) + FIELD(TD0, TFS8, 8, 1) + FIELD(TD0, TWBI, 26, 1) + FIELD(TD0, TFE, 27, 1) + FIELD(TD0, TFP, 28, 2) + FIELD(TD0, TDLE, 30, 1) + FIELD(TD0, TACT, 31, 1) +REG32(TD1, 0x0004) + FIELD(TD1, TBL, 16, 16) +REG32(TD2, 0x0008) + FIELD(TD2, TBA, 0, 32) + +/* Receive Descriptor */ +REG32(RD0, 0x0000) + FIELD(RD0, RFS, 0, 10) + FIELD(RD0, RFS0, 0, 1) + FIELD(RD0, RFS1, 1, 1) + FIELD(RD0, RFS2, 2, 1) + FIELD(RD0, RFS3, 3, 1) + FIELD(RD0, RFS4, 4, 1) + FIELD(RD0, RFS7, 7, 1) + FIELD(RD0, RFS8, 8, 1) + FIELD(RD0, RFS9, 9, 1) + FIELD(RD0, RFE, 27, 1) + FIELD(RD0, RFP, 28, 2) + FIELD(RD0, RFP0, 28, 1) + FIELD(RD0, RDLE, 30, 1) + FIELD(RD0, RACT, 31, 1) +REG32(RD1, 0x0004) + FIELD(RD1, RFL, 0, 16) + FIELD(RD1, RBL, 16, 16) +REG32(RD2, 0x0008) + FIELD(RD2, RBA, 0, 32) + +static void renesas_eth_set_irq(RenesasEthState *s) +{ + if (s->edmac_regs[R_EESR] & s->edmac_regs[R_EESIPR]) { + qemu_set_irq(s->irq, 1); + } else { + qemu_set_irq(s->irq, 0); + } +} + +static bool renesas_eth_can_receive(NetClientState *nc) +{ + RenesasEthState *s =3D RenesasEth(qemu_get_nic_opaque(nc)); + + return FIELD_EX32(s->edmac_regs[R_EDRRR], EDRRR, RR); +} + +static void set_ecsr(RenesasEthState *s, int bit) +{ + s->etherc_regs[R_ECSR] =3D deposit32(s->etherc_regs[R_ECSR], bit, 1, 1= ); + if (s->etherc_regs[R_ECSR] & s->etherc_regs[R_ECSIPR]) { + s->edmac_regs[R_EESR] =3D FIELD_DP32(s->edmac_regs[R_EESR], + EESR, ECI, 1); + } + renesas_eth_set_irq(s); +} + +static void renesas_eth_set_link_status(NetClientState *nc) +{ + RenesasEthState *s =3D RenesasEth(qemu_get_nic_opaque(nc)); + int old_lmon, new_lmon; + if (s->mdiodev) { + old_lmon =3D mdio_phy_linksta(mdio_get_phy(s->mdiodev)); + mdio_phy_set_link(mdio_get_phy(s->mdiodev), !nc->link_down); + new_lmon =3D mdio_phy_linksta(mdio_get_phy(s->mdiodev)); + if (old_lmon ^ new_lmon) { + set_ecsr(s, R_ECSR_LCHNG_SHIFT); + } + } +} + +static void edmac_write(RenesasEthState *s, const uint8_t *buf, + size_t size, int pad) +{ + uint32_t rdesc[3]; + uint32_t eesr; + int state =3D 0; + + while (size > 0) { + size_t wsize; + /* RDESC read */ + dma_memory_read(&address_space_memory, + s->edmac_regs[R_RDFAR], rdesc, sizeof(rdesc)); + if (FIELD_EX32(rdesc[0], RD0, RACT)) { + if (state =3D=3D 0) { + /* Fist block */ + rdesc[0] =3D FIELD_DP32(rdesc[0], RD0, RFP, 2); + } + state++; + s->edmac_regs[R_RBWAR] =3D rdesc[2]; + wsize =3D MIN(FIELD_EX32(rdesc[1], RD1, RBL), size); + /* Write receive data */ + dma_memory_write(&address_space_memory, + s->edmac_regs[R_RBWAR], buf, wsize); + buf +=3D wsize; + size -=3D wsize; + rdesc[1] =3D FIELD_DP32(rdesc[1], RD1, RFL, wsize); + if (size =3D=3D 0) { + /* Last descriptor */ + rdesc[0] =3D FIELD_DP32(rdesc[0], RD0, RFP0, 1); + if (FIELD_EX32(s->edmac_regs[R_RMCR], RMCR, RNR) =3D=3D 0)= { + s->edmac_regs[R_EDRRR] =3D FIELD_DP32(s->edmac_regs[R_= EDRRR], + EDRRR, RR, 0); + } + s->edmac_regs[R_EESR] =3D FIELD_DP32(s->edmac_regs[R_EESR], + EESR, FR, 1); + renesas_eth_set_irq(s); + } + eesr =3D FIELD_EX32(s->edmac_regs[R_EESR], EESR, RDESC); + rdesc[0] =3D FIELD_DP32(rdesc[0], RD0, RFS, + eesr & ~(s->edmac_regs[R_TRSCER])); + rdesc[0] =3D FIELD_DP32(rdesc[0], RD0, RFE, eesr !=3D 0); + rdesc[0] =3D FIELD_DP32(rdesc[0], RD0, RACT, 0); + /* RDESC write back */ + dma_memory_write(&address_space_memory, + s->edmac_regs[R_RDFAR], rdesc, sizeof(rdesc)); + if (FIELD_EX32(rdesc[0], RD0, RDLE)) { + s->edmac_regs[R_RDFAR] =3D s->edmac_regs[R_RDLAR]; + } else { + s->edmac_regs[R_RDFAR] +=3D s->descsize; + } + s->edmac_regs[R_EESR] =3D FIELD_DP32(s->edmac_regs[R_EESR], + EESR, FR, 1); + } else { + /* no active RDESC */ + if (FIELD_EX32(s->edmac_regs[R_RMCR], RMCR, RNC) =3D=3D 0) { + s->edmac_regs[R_EDRRR] =3D FIELD_DP32(s->edmac_regs[R_EDRR= R], + EDRRR, RR, 0); + } + s->edmac_regs[R_EESR] =3D FIELD_DP32(s->edmac_regs[R_EESR], + EESR, RDE, 1); + break; + } + } + renesas_eth_set_irq(s); +} + +static inline void update_count(uint32_t *cnt) +{ + if (*cnt < UINT32_MAX) { + /* Satulate on 32bit value */ + (*cnt)++; + } +} + +#define MIN_BUF_SIZE 60 +static ssize_t renesas_eth_receive(NetClientState *nc, + const uint8_t *buf, size_t size) +{ + RenesasEthState *s =3D RenesasEth(qemu_get_nic_opaque(nc)); + static const uint8_t bcast_addr[] =3D { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + }; + static const uint8_t pad[3] =3D { 0 }; + uint8_t buf1[MIN_BUF_SIZE]; + bool receive =3D false; + size_t pads; + uint32_t rflr; + + if (size >=3D 6) { + if (memcmp(buf, bcast_addr, sizeof(bcast_addr)) =3D=3D 0) { + /* broadcast */ + if (s->etherc_regs[R_BCFRR] =3D=3D 0 || + s->etherc_regs[R_BCFRR] < s->rcv_bcast) { + s->rcv_bcast++; + receive =3D true; + } + } else if (buf[0] & 0x1) { + /* multicast */ + receive =3D true; + s->edmac_regs[R_EESR] =3D FIELD_DP32(s->edmac_regs[R_EESR], + EESR, RMAF, 1); + update_count(&s->edmac_regs[R_MAFCR]); + } else if (FIELD_EX32(s->edmac_regs[R_ECMR], ECMR, PRM)) { + /* promiscas */ + receive =3D true; + } else if (memcmp(buf, s->macadr, sizeof(s->macadr)) =3D=3D 0) { + /* normal */ + receive =3D true; + } + } + if (!receive) { + return size; + } + /* if too small buffer, then expand it */ + if (size < MIN_BUF_SIZE) { + memcpy(buf1, buf, size); + memset(buf1 + size, 0, MIN_BUF_SIZE - size); + buf =3D buf1; + size =3D MIN_BUF_SIZE; + } + + rflr =3D FIELD_EX32(s->etherc_regs[R_RFLR], RFLR, RFL); + rflr =3D MAX(rflr, 1518); + if (size > rflr) { + update_count(&s->etherc_regs[R_TLFRCR]); + s->edmac_regs[R_EESR] =3D FIELD_DP32(s->edmac_regs[R_EESR], + EESR, RTLF, 1); + } + pads =3D FIELD_EX32(s->edmac_regs[R_RPADIR], RPADIR, PADS); + if (pads > 0) { + int pos =3D FIELD_EX32(s->edmac_regs[R_RPADIR], RPADIR, PADR); + uint8_t *padbuf =3D g_new(uint8_t, size + pads); + if (size > pos) { + if (pos > 0) { + memcpy(padbuf, buf, pos); + } + memcpy(padbuf + pos, pad, pads); + memcpy(padbuf + pos + pads, buf + pos, size - pos); + } else { + pads =3D 0; + } + edmac_write(s, padbuf, size + pads, pads); + g_free(padbuf); + } else { + edmac_write(s, buf, size, 0); + } + return size; +} + +static size_t edmac_read(RenesasEthState *s, uint8_t **buf) +{ + uint32_t tdesc[3]; + uint32_t size =3D 0; + + *buf =3D NULL; + for (;;) { + size_t rsize; + dma_memory_read(&address_space_memory, + s->edmac_regs[R_TDFAR], tdesc, sizeof(tdesc)); + if (FIELD_EX32(tdesc[0], TD0, TACT)) { + s->edmac_regs[R_TBRAR] =3D tdesc[2]; + rsize =3D FIELD_EX32(tdesc[1], TD1, TBL); + *buf =3D g_realloc(*buf, size + rsize); + dma_memory_read(&address_space_memory, + s->edmac_regs[R_TBRAR], *buf + size, rsize); + tdesc[0] =3D FIELD_DP32(tdesc[0], TD0, TACT, 0); + dma_memory_write(&address_space_memory, + s->edmac_regs[R_TDFAR], tdesc, sizeof(tdesc)); + size +=3D rsize; + if (FIELD_EX32(tdesc[0], TD0, TDLE)) { + s->edmac_regs[R_TDFAR] =3D s->edmac_regs[R_TDLAR]; + } else { + s->edmac_regs[R_TDFAR] +=3D s->descsize; + } + if (FIELD_EX32(tdesc[0], TD0, TFP) & 1) { + break; + } + } else { + s->edmac_regs[R_EESR] =3D FIELD_DP32(s->edmac_regs[R_EESR], + EESR, TDE, 1); + renesas_eth_set_irq(s); + break; + } + } + return size; +} + +static void renesas_eth_start_xmit(RenesasEthState *s) +{ + uint8_t *txbuf; + size_t size; + + size =3D edmac_read(s, &txbuf); + qemu_send_packet(qemu_get_queue(s->nic), txbuf, size); + g_free(txbuf); + s->edmac_regs[R_EESR] =3D FIELD_DP32(s->edmac_regs[R_EESR], EESR, TWB,= 1); + s->edmac_regs[R_EDTRR] =3D FIELD_DP32(s->edmac_regs[R_EDTRR], EDTRR, T= R, 0); + renesas_eth_set_irq(s); +} + +static void renesas_eth_reset(RenesasEthState *s) +{ + int i; + + for (i =3D 0; i < RENESAS_ETHERC_R_MAX; i++) { + register_reset(&s->etherc_regs_info[i]); + } + for (i =3D 0; i < RENESAS_EDMAC_R_MAX; i++) { + register_reset(&s->edmac_regs_info[i]); + } +} + +static uint64_t ecsr_pre_write(RegisterInfo *reg, uint64_t val) +{ + RenesasEthState *s =3D RenesasEth(reg->opaque); + uint32_t old_val =3D s->etherc_regs[R_ECSR]; + + val ^=3D old_val; + val &=3D old_val; + return val; +} + +static void ecsr_post_write(RegisterInfo *reg, uint64_t val) +{ + RenesasEthState *s =3D RenesasEth(reg->opaque); + + if (s->etherc_regs[R_ECSR] & s->etherc_regs[R_ECSIPR]) { + s->edmac_regs[R_EESR] =3D FIELD_DP32(s->edmac_regs[R_EESR], + EESR, ECI, 1); + } else { + s->edmac_regs[R_EESR] =3D FIELD_DP32(s->edmac_regs[R_EESR], + EESR, ECI, 0); + } + renesas_eth_set_irq(s); +} + +static void pir_post_write(RegisterInfo *reg, uint64_t val) +{ + RenesasEthState *s =3D RenesasEth(reg->opaque); + if (s->mdiodev) { + mdio_set_mdc_pin(s->mdiodev, FIELD_EX32(val, PIR, MDC)); + if (FIELD_EX32(val, PIR, MMD)) { + mdio_set_mdo_pin(s->mdiodev, FIELD_EX32(val, PIR, MDO)); + } + } +} + +static uint64_t pir_post_read(RegisterInfo *reg, uint64_t val) +{ + RenesasEthState *s =3D RenesasEth(reg->opaque); + if (s->mdiodev) { + val =3D FIELD_DP64(val, PIR, MDI, mdio_read_mdi_pin(s->mdiodev)); + } + return val; +} + +static uint64_t mar_pre_write(RegisterInfo *reg, uint64_t val) +{ + RenesasEthState *s =3D RenesasEth(reg->opaque); + if (FIELD_EX32(s->edmac_regs[R_EDTRR], EDTRR, TR) || + FIELD_EX32(s->edmac_regs[R_EDRRR], EDRRR, RR)) { + qemu_log_mask(LOG_GUEST_ERROR, + "renesas_eth: Tx/Rx enabled in MAR write.\n"); + } + return val; +} + +static void mar_post_write(RegisterInfo *reg, uint64_t val) +{ + int i; + RenesasEthState *s =3D RenesasEth(reg->opaque); + for (i =3D 0; i < 4; i++) { + s->macadr[i] =3D extract32(s->etherc_regs[R_MAHR], 8 * (3 - i), 8); + } + for (i =3D 0; i < 2; i++) { + s->macadr[i + 4] =3D extract32(s->etherc_regs[R_MALR], 8 * (1 - i)= , 8); + } +} + +static uint64_t etherc_counter_write(RegisterInfo *reg, uint64_t val) +{ + /* Counter register clear in any write operation */ + return 0; +} + +static void edmr_post_write(RegisterInfo *reg, uint64_t val) +{ + RenesasEthState *s =3D RenesasEth(reg->opaque); + uint32_t TDLAR, RMFCR, TFUCR, RFOCR; + int dl; + + if (FIELD_EX32(val, EDMR, SWR)) { + /* Following register keep for SWR */ + TDLAR =3D s->edmac_regs[R_TDLAR]; + RMFCR =3D s->edmac_regs[R_RMFCR]; + TFUCR =3D s->edmac_regs[R_TFUCR]; + RFOCR =3D s->edmac_regs[R_RFOCR]; + renesas_eth_reset(s); + s->edmac_regs[R_TDLAR] =3D TDLAR; + s->edmac_regs[R_RMFCR] =3D RMFCR; + s->edmac_regs[R_TFUCR] =3D TFUCR; + s->edmac_regs[R_RFOCR] =3D RFOCR; + } + dl =3D FIELD_EX32(val, EDMR, DL) % 3; + s->descsize =3D 16 << dl; +} + +static void edtrr_post_write(RegisterInfo *reg, uint64_t val) +{ + RenesasEthState *s =3D RenesasEth(reg->opaque); + if (FIELD_EX32(val, EDTRR, TR)) { + renesas_eth_start_xmit(s); + } +} + +static uint64_t eesr_pre_write(RegisterInfo *reg, uint64_t val) +{ + uint32_t eesr; + RenesasEthState *s =3D RenesasEth(reg->opaque); + /* flag clear for write 1 */ + eesr =3D s->edmac_regs[R_EESR]; + val =3D FIELD_DP64(val, EESR, ECI, 0); /* Keep ECI value */ + eesr &=3D ~val; + return eesr; +} + +static void eesr_post_write(RegisterInfo *reg, uint64_t val) +{ + RenesasEthState *s =3D RenesasEth(reg->opaque); + renesas_eth_set_irq(s); +} + +static void tdlar_post_write(RegisterInfo *reg, uint64_t val) +{ + RenesasEthState *s =3D RenesasEth(reg->opaque); + s->edmac_regs[R_TDFAR] =3D s->edmac_regs[R_TDLAR]; +} + +static void rdlar_post_write(RegisterInfo *reg, uint64_t val) +{ + RenesasEthState *s =3D RenesasEth(reg->opaque); + s->edmac_regs[R_RDFAR] =3D s->edmac_regs[R_RDLAR]; +} + +static uint64_t fdr_pre_write(RegisterInfo *reg, uint64_t val) +{ + RenesasEthState *s =3D RenesasEth(reg->opaque); + if (FIELD_EX32(val, FDR, TFD) !=3D 7 || FIELD_EX32(val, FDR, RFD) !=3D= 7) { + qemu_log_mask(LOG_GUEST_ERROR, + "renesas_eth: invalid FDR setting %" + HWADDR_PRIX ".\n", val); + } + if (FIELD_EX32(s->edmac_regs[R_EDTRR], EDTRR, TR) || + FIELD_EX32(s->edmac_regs[R_EDRRR], EDRRR, RR)) { + qemu_log_mask(LOG_GUEST_ERROR, + "renesas_eth: Tx/Rx enabled in FDR write.\n"); + } + return val; +} + +static uint64_t edmac_reg_read(void *opaque, hwaddr addr, unsigned int siz= e) +{ + RegisterInfoArray *ra =3D opaque; + RenesasEthState *s =3D RenesasEth(ra->r[0]->opaque); + if (clock_is_enabled(s->ick)) { + return register_read_memory(ra, addr, size); + } else { + qemu_log_mask(LOG_GUEST_ERROR, + "renesas_eth: EDMAC module stopped.\n"); + return UINT64_MAX; + } +} + +static void edmac_reg_write(void *opaque, hwaddr addr, + uint64_t value, unsigned int size) +{ + RegisterInfoArray *ra =3D opaque; + RenesasEthState *s =3D RenesasEth(ra->r[0]->opaque); + if (clock_is_enabled(s->ick)) { + register_write_memory(ra, addr, value, size); + } else { + qemu_log_mask(LOG_GUEST_ERROR, + "renesas_eth: EDMAC module stopped.\n"); + } +} + +static const MemoryRegionOps renesas_etherc_ops =3D { + .read =3D register_read_memory, + .write =3D register_write_memory, + .endianness =3D DEVICE_NATIVE_ENDIAN, + .impl =3D { + .min_access_size =3D 4, + .max_access_size =3D 4, + }, +}; + +static const MemoryRegionOps renesas_edmac_ops =3D { + .read =3D edmac_reg_read, + .write =3D edmac_reg_write, + .endianness =3D DEVICE_NATIVE_ENDIAN, + .impl =3D { + .min_access_size =3D 4, + .max_access_size =3D 4, + }, +}; + +static NetClientInfo net_renesas_eth_info =3D { + .type =3D NET_CLIENT_DRIVER_NIC, + .size =3D sizeof(NICState), + .can_receive =3D renesas_eth_can_receive, + .receive =3D renesas_eth_receive, + .link_status_changed =3D renesas_eth_set_link_status, +}; + +static const RegisterAccessInfo renesas_etherc_regs_info[] =3D { + { .name =3D "ECMR", .addr =3D A_ECMR, + .rsvd =3D 0xffe0ed90, }, + { .name =3D "RFLR", .addr =3D A_RFLR, + .rsvd =3D 0xfffff000, }, + { .name =3D "ECSR", .addr =3D A_ECSR, + .rsvd =3D 0xffffffc8, + .pre_write =3D ecsr_pre_write, + .post_write =3D ecsr_post_write, }, + { .name =3D "ECSIPR", .addr =3D A_ECSIPR, + .rsvd =3D 0xffffffc8, + .post_write =3D ecsr_post_write, }, + { .name =3D "PIR", .addr =3D A_PIR, + .rsvd =3D 0xfffffff0, + .post_write =3D pir_post_write, + .post_read =3D pir_post_read, }, + { .name =3D "PSR", .addr =3D A_PSR, + .rsvd =3D 0xfffffffe, }, + { .name =3D "RDMLR", .addr =3D A_RDMLR, + .rsvd =3D 0xfff00000, }, + { .name =3D "IPGR", .addr =3D A_IPGR, + .rsvd =3D 0xffffffe0, .reset =3D 0x00000014, }, + { .name =3D "APR", .addr =3D A_APR, + .rsvd =3D 0xffff0000, }, + { .name =3D "MPR", .addr =3D A_MPR, + .rsvd =3D 0xffff0000, }, + { .name =3D "RFCF", .addr =3D A_RFCF, + .rsvd =3D 0xffffff00, }, + { .name =3D "TPAUSER", .addr =3D A_TPAUSER, + .rsvd =3D 0xffff0000, }, + { .name =3D "TPAUSECR", .addr =3D A_TPAUSECR, + .rsvd =3D 0xffffff00, }, + { .name =3D "BCFRR", .addr =3D A_BCFRR, + .rsvd =3D 0xffff0000, }, + { .name =3D "MAHR", .addr =3D A_MAHR, + .pre_write =3D mar_pre_write, + .post_write =3D mar_post_write, }, + { .name =3D "MALR", .addr =3D A_MALR, + .rsvd =3D 0xffff0000, + .pre_write =3D mar_pre_write, + .post_write =3D mar_post_write, }, + { .name =3D "TROCR", .addr =3D A_TROCR, + .pre_write =3D etherc_counter_write, }, + { .name =3D "CDCR", .addr =3D A_CDCR, + .pre_write =3D etherc_counter_write, }, + { .name =3D "LCCR", .addr =3D A_LCCR, + .pre_write =3D etherc_counter_write, }, + { .name =3D "CNDCR", .addr =3D A_CNDCR, + .pre_write =3D etherc_counter_write, }, + { .name =3D "CEFCR", .addr =3D A_CEFCR, + .pre_write =3D etherc_counter_write, }, + { .name =3D "FRECR", .addr =3D A_FRECR, + .pre_write =3D etherc_counter_write, }, + { .name =3D "TSFRCR", .addr =3D A_TSFRCR, + .pre_write =3D etherc_counter_write, }, + { .name =3D "TLFRCR", .addr =3D A_TLFRCR, + .pre_write =3D etherc_counter_write, }, + { .name =3D "RFCR", .addr =3D A_RFCR, + .pre_write =3D etherc_counter_write, }, + { .name =3D "MAFCR", .addr =3D A_MAFCR, + .pre_write =3D etherc_counter_write, }, +}; + +static const RegisterAccessInfo renesas_edmac_regs_info[] =3D { + { .name =3D "EDMR", .addr =3D A_EDMR, + .rsvd =3D 0xfffffff8e, + .post_write =3D edmr_post_write, }, + { .name =3D "EDTRR", .addr =3D A_EDTRR, + .rsvd =3D 0xffffffffe, + .post_write =3D edtrr_post_write, }, + { .name =3D "EDRRR", .addr =3D A_EDRRR, + .rsvd =3D 0xffffffffe, }, + { .name =3D "TDLAR", .addr =3D A_TDLAR, + .post_write =3D tdlar_post_write, }, + { .name =3D "RDLAR", .addr =3D A_RDLAR, + .post_write =3D rdlar_post_write, }, + { .name =3D "EESR", .addr =3D A_EESR, + .rsvd =3D 0xb800f0c0, .ro =3D 0x00400000, + .pre_write =3D eesr_pre_write, + .post_write =3D eesr_post_write, }, + { .name =3D "EESIPR", .addr =3D A_EESIPR, + .rsvd =3D 0xb800f060, + .post_write =3D eesr_post_write, }, + { .name =3D "TRSCER", .addr =3D A_TRSCER, + .rsvd =3D 0xfffffd6f, }, + { .name =3D "RMFCR", .addr =3D A_RMFCR, + .rsvd =3D 0xffff0000, }, + { .name =3D "TFTR", .addr =3D A_TFTR, + .rsvd =3D 0xfffff800, }, + { .name =3D "FDR", .addr =3D A_FDR, + .rsvd =3D 0xffffe0e0, + .pre_write =3D fdr_pre_write, }, + { .name =3D "RMCR", .addr =3D A_RMCR, + .rsvd =3D 0xfffffffc, }, + { .name =3D "TFUCR", .addr =3D A_TFUCR, + .rsvd =3D 0xffff0000, + .pre_write =3D etherc_counter_write, }, + { .name =3D "RFOCR", .addr =3D A_RFOCR, + .rsvd =3D 0xffff0000, + .pre_write =3D etherc_counter_write, }, + { .name =3D "RBWAR", .addr =3D A_RBWAR, + .ro =3D 0xffffffff, .rsvd =3D 0xffff0000, }, + { .name =3D "RDFAR", .addr =3D A_RDFAR, + .ro =3D 0xffffffff, .rsvd =3D 0xffff0000, }, + { .name =3D "TBRAR", .addr =3D A_TBRAR, + .ro =3D 0xffffffff, .rsvd =3D 0xffff0000, }, + { .name =3D "TDFAR", .addr =3D A_TDFAR, + .ro =3D 0xffffffff, .rsvd =3D 0xffff0000, }, + { .name =3D "FCFTR", .addr =3D A_FCFTR, + .rsvd =3D 0xfff8fff8, }, + { .name =3D "RPADIR", .addr =3D A_RPADIR, + .rsvd =3D 0xfffcffc0, }, + { .name =3D "TRIMD", .addr =3D A_TRIMD, + .rsvd =3D 0xffffffee, }, + { .name =3D "IOSR", .addr =3D A_IOSR, + .rsvd =3D 0xfffffffe, }, +}; + +static void renesas_eth_realize(DeviceState *dev, Error **errp) +{ + RenesasEthState *s =3D RenesasEth(dev); + + s->nic =3D qemu_new_nic(&net_renesas_eth_info, &s->conf, + object_get_typename(OBJECT(s)), dev->id, s); + + renesas_eth_reset(s); + if (s->mdiodev) { + mdio_phy_set_link(mdio_get_phy(s->mdiodev), + !qemu_get_queue(s->nic)->link_down); + } +} + +static Property renesas_eth_properties[] =3D { + DEFINE_NIC_PROPERTIES(RenesasEthState, conf), + DEFINE_PROP_LINK("mdio", RenesasEthState, mdiodev, TYPE_ETHER_MDIO_BB, + MDIOState *), + DEFINE_PROP_END_OF_LIST(), +}; + +static void renesas_eth_init(Object *obj) +{ + SysBusDevice *d =3D SYS_BUS_DEVICE(obj); + RenesasEthState *s =3D RenesasEth(obj); + RegisterInfoArray *ra_etherc; + RegisterInfoArray *ra_edmac; + + memory_region_init(&s->etherc_mem, obj, "renesas-etherc", 0x100); + ra_etherc =3D register_init_block32(DEVICE(d), renesas_etherc_regs_inf= o, + ARRAY_SIZE(renesas_etherc_regs_info), + s->etherc_regs_info, s->etherc_regs, + &renesas_etherc_ops, + false, 0x100); + memory_region_add_subregion(&s->etherc_mem, 0x00, &ra_etherc->mem); + sysbus_init_mmio(d, &s->etherc_mem); + + memory_region_init(&s->edmac_mem, obj, "renesas-edmac", 0x100); + ra_edmac =3D register_init_block32(DEVICE(d), renesas_edmac_regs_info, + ARRAY_SIZE(renesas_edmac_regs_info), + s->edmac_regs_info, s->edmac_regs, + &renesas_edmac_ops, + false, 0x100); + memory_region_add_subregion(&s->edmac_mem, 0x00, &ra_edmac->mem); + sysbus_init_mmio(d, &s->edmac_mem); + + sysbus_init_irq(d, &s->irq); + s->ick =3D qdev_init_clock_in(DEVICE(d), "ick", NULL, NULL); +} + +static void renesas_eth_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(klass); + + set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); + device_class_set_props(dc, renesas_eth_properties); + dc->realize =3D renesas_eth_realize; +} + +static const TypeInfo renesas_eth_info =3D { + .name =3D TYPE_RENESAS_ETH, + .parent =3D TYPE_SYS_BUS_DEVICE, + .instance_size =3D sizeof(RenesasEthState), + .instance_init =3D renesas_eth_init, + .class_init =3D renesas_eth_class_init, +}; + +static void renesas_eth_register_types(void) +{ + type_register_static(&renesas_eth_info); +} + +type_init(renesas_eth_register_types) diff --git a/hw/net/Kconfig b/hw/net/Kconfig index e6a32a2ab0..7cb3aeadeb 100644 --- a/hw/net/Kconfig +++ b/hw/net/Kconfig @@ -146,3 +146,8 @@ config CAN_SJA1000 =20 config MDIO_PHY bool + +config RENESAS_ETH + bool + select MDIO_PHY + select REGISTER diff --git a/hw/net/meson.build b/hw/net/meson.build index faa4e3d2c0..0f64af7b8f 100644 --- a/hw/net/meson.build +++ b/hw/net/meson.build @@ -65,5 +65,6 @@ softmmu_ss.add(when: 'CONFIG_ROCKER', if_true: files( softmmu_ss.add(when: 'CONFIG_ALL', if_true: files('rocker/qmp-norocker.c')) =20 softmmu_ss.add(when: 'CONFIG_MDIO_PHY', if_true: files('mdio.c')) +softmmu_ss.add(when: 'CONFIG_RENESAS_ETH', if_true: files('renesas_eth.c')) =20 subdir('can') --=20 2.20.1 From nobody Sun Nov 16 04:02:32 2025 Delivered-To: importer@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+importer=patchew.org@nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1598532208; cv=none; d=zohomail.com; s=zohoarc; b=AWLOKbOHYmmSUX31GIkhh1vOGO/0Ah7ZXA94YZkZzYfDACU2TZYjhiLUgr3PonDsauQ23ZLPLe4yNSTVdZCsFJtlKGE2col2IsIlqbGtJtfVwfN0SfwQwldrC/o1kVZtn5Hm9Alo/zOo2atEvGPOWE9/zJMzghYp64oVUwwWDeg= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1598532208; 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=VWudiIVVw4gM5TAuKUWCTFAZ15QelhR7Amegn1Sfbf4=; b=OxCgOIImoTity2hfKGr1wff1lrocVktd54lA4nwMtvOwuieNP935hEfLjMbvt2k2vTBO28bZKLuilT5a3JIssKqpTYUklKK46aFrwTUzLXE5BP8WadtRWJYSJmhnscHE2Zucc+f34pekE0uEVwlngWNZZfGMrkJQaRl5WCLGE+U= 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+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1598532208277427.16224776221975; Thu, 27 Aug 2020 05:43:28 -0700 (PDT) Received: from localhost ([::1]:55346 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kBHFW-0007ue-VG for importer@patchew.org; Thu, 27 Aug 2020 08:43:26 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:58990) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kBHBS-000800-RF for qemu-devel@nongnu.org; Thu, 27 Aug 2020 08:39:14 -0400 Received: from mail03.asahi-net.or.jp ([202.224.55.15]:39222) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kBHBO-0005wU-AR for qemu-devel@nongnu.org; Thu, 27 Aug 2020 08:39:14 -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 5EA3D26A0D; Thu, 27 Aug 2020 21:39:09 +0900 (JST) Received: from yo-satoh-debian.localdomain (ZM005235.ppp.dion.ne.jp [222.8.5.235]) by sakura.ysato.name (Postfix) with ESMTPSA id 167771C0792; Thu, 27 Aug 2020 21:39:09 +0900 (JST) From: Yoshinori Sato To: qemu-devel@nongnu.org Subject: [PATCH 17/20] hw/rx/rx62n: Add Ethernet support. Date: Thu, 27 Aug 2020 21:38:56 +0900 Message-Id: <20200827123859.81793-18-ysato@users.sourceforge.jp> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200827123859.81793-1-ysato@users.sourceforge.jp> References: <20200827123859.81793-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+importer=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-detected-operating-system: by eggs.gnu.org: First seen = 2020/08/27 08:39:06 X-ACL-Warn: Detected OS = ??? 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+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" Signed-off-by: Yoshinori Sato --- include/hw/rx/rx62n.h | 3 +++ hw/rx/rx62n.c | 26 ++++++++++++++++++++++++++ hw/rx/Kconfig | 3 ++- 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/include/hw/rx/rx62n.h b/include/hw/rx/rx62n.h index 170c8cb6fc..4f11ca3fd9 100644 --- a/include/hw/rx/rx62n.h +++ b/include/hw/rx/rx62n.h @@ -30,6 +30,7 @@ #include "hw/timer/renesas_timer.h" #include "hw/timer/renesas_mtu.h" #include "hw/char/renesas_sci.h" +#include "hw/net/renesas_eth.h" #include "hw/rx/rx62n-cpg.h" #include "qemu/units.h" =20 @@ -74,6 +75,8 @@ typedef struct RX62NState { RenesasCMTState cmt[RX62N_NR_CMT]; RenesasMTU2State mtu[RX62N_NR_MTU]; RSCIAState sci[RX62N_NR_SCI]; + RenesasEthState ether; + MDIOState *mdio; RX62NCPGState cpg; =20 MemoryRegion *sysmem; diff --git a/hw/rx/rx62n.c b/hw/rx/rx62n.c index 344be846bc..8b41cdf90c 100644 --- a/hw/rx/rx62n.c +++ b/hw/rx/rx62n.c @@ -28,6 +28,7 @@ #include "hw/loader.h" #include "hw/sysbus.h" #include "hw/qdev-properties.h" +#include "hw/net/mdio.h" #include "sysemu/sysemu.h" #include "sysemu/qtest.h" #include "cpu.h" @@ -48,6 +49,8 @@ #define RX62N_CMT_BASE 0x00088000 #define RX62N_MTU_BASE 0x00088600 #define RX62N_SCI_BASE 0x00088240 +#define RX62N_EDMAC_BASE 0x000c0000 +#define RX62N_ETHER_BASE 0x000c0100 #define RX62N_CPG_BASE 0x00080010 =20 /* @@ -58,6 +61,7 @@ #define RX62N_CMT_IRQ 28 #define RX62N_MTU_IRQ 114 #define RX62N_SCI_IRQ 214 +#define RX62N_EDMAC_IRQ 32 =20 /* * IRQ -> IPR mapping table @@ -236,6 +240,25 @@ static void register_sci(RX62NState *s, int unit) qdev_get_clock_out(DEVICE(&s->cpg), ckname)); } =20 +static void register_eth(RX62NState *s, NICInfo *nd) +{ + SysBusDevice *etherc; + + qemu_check_nic_model(nd, TYPE_RENESAS_ETH); + object_initialize_child(OBJECT(s), "ether", + &s->ether, TYPE_RENESAS_ETH); + etherc =3D SYS_BUS_DEVICE(&s->ether); + qdev_set_nic_properties(DEVICE(etherc), nd); + object_property_set_link(OBJECT(etherc), "mdio", + OBJECT(s->mdio), &error_abort); + sysbus_realize(etherc, &error_abort); + sysbus_connect_irq(etherc, 0, s->irq[RX62N_EDMAC_IRQ]); + sysbus_mmio_map(etherc, 0, RX62N_ETHER_BASE); + sysbus_mmio_map(etherc, 1, RX62N_EDMAC_BASE); + qdev_connect_clock_in(DEVICE(etherc), "ick", + qdev_get_clock_out(DEVICE(&s->cpg), "ick_edmac")= ); +} + static void register_cpg(RX62NState *s) { SysBusDevice *cpg; @@ -277,6 +300,7 @@ static void rx62n_realize(DeviceState *dev, Error **err= p) register_mtu(s, 0); register_mtu(s, 1); register_sci(s, 0); + register_eth(s, nd_table); sysbus_realize(SYS_BUS_DEVICE(&s->cpg), &error_abort); } =20 @@ -284,6 +308,8 @@ static Property rx62n_properties[] =3D { DEFINE_PROP_LINK("main-bus", RX62NState, sysmem, TYPE_MEMORY_REGION, MemoryRegion *), DEFINE_PROP_UINT32("xtal-frequency-hz", RX62NState, xtal_freq_hz, 0), + DEFINE_PROP_LINK("mdiodev", RX62NState, mdio, TYPE_ETHER_MDIO_BB, + MDIOState *), DEFINE_PROP_END_OF_LIST(), }; =20 diff --git a/hw/rx/Kconfig b/hw/rx/Kconfig index 887a5782bb..f20ea63fd9 100644 --- a/hw/rx/Kconfig +++ b/hw/rx/Kconfig @@ -3,8 +3,9 @@ config RX62N_MCU select RX_ICU select RENESAS_TMR8 select RENESAS_TIMER - select RENESAS_SCI select RENESAS_MTU + select RENESAS_SCI + select RENESAS_ETH =20 config RX_GDBSIM bool --=20 2.20.1 From nobody Sun Nov 16 04:02:32 2025 Delivered-To: importer@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+importer=patchew.org@nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1598532364; cv=none; d=zohomail.com; s=zohoarc; b=e7lvlA2jfrpbnkUzAASQGbMfmSnjlfNGGFD2grLYdZjrBUakYPEEERx+HsdMl/WNfG9Pfoh/7D25qEB8SZGkoZfSKg6XXBYAEMKOhOQeXr+Z1lOiNh2jvtFxm8QeoH8xqtV7YU81PHYS6pwHayt1LfudUgeR0bIhquSsyOOH9/g= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1598532364; 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=GtS9zww2uI9JlGnHUkPEZw786WMh7PRdXYUFHEqeMnc=; b=U2a4NEgwXbwXVl9ecm6vWaqEXttH9aqLBqoLQE2qjsQz7NSERXjqhhpWgpiVRkhx0Vsh3rRq1E9eUoXyeHUkdrlIVNVUczetecMlqabHJ7Fv2OrCLMxSQdcPNluwD3b+mBQJYo9KCQOTxVDJeImG4wsKBqyk+0DBOODBrcCzIFM= 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+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1598532364820503.0927470375393; Thu, 27 Aug 2020 05:46:04 -0700 (PDT) Received: from localhost ([::1]:38338 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kBHI3-00045x-M0 for importer@patchew.org; Thu, 27 Aug 2020 08:46:03 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:59072) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kBHBV-00087j-FK for qemu-devel@nongnu.org; Thu, 27 Aug 2020 08:39:17 -0400 Received: from mail02.asahi-net.or.jp ([202.224.55.14]:56309) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kBHBP-0005wW-6A for qemu-devel@nongnu.org; Thu, 27 Aug 2020 08:39:17 -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 8DE1826838; Thu, 27 Aug 2020 21:39:09 +0900 (JST) Received: from yo-satoh-debian.localdomain (ZM005235.ppp.dion.ne.jp [222.8.5.235]) by sakura.ysato.name (Postfix) with ESMTPSA id 495171C0696; Thu, 27 Aug 2020 21:39:09 +0900 (JST) From: Yoshinori Sato To: qemu-devel@nongnu.org Subject: [PATCH 18/20] hw/rx: Add Tokudenkairo TKDN-RX62N-BRD Date: Thu, 27 Aug 2020 21:38:57 +0900 Message-Id: <20200827123859.81793-19-ysato@users.sourceforge.jp> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200827123859.81793-1-ysato@users.sourceforge.jp> References: <20200827123859.81793-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+importer=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-detected-operating-system: by eggs.gnu.org: First seen = 2020/08/27 08:39:06 X-ACL-Warn: Detected OS = ??? 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+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" Hardware information. http://www.tokudenkairo.co.jp/rx62n/ (Japanese) Signed-off-by: Yoshinori Sato --- default-configs/rx-softmmu.mak | 1 + hw/rx/tkdn-rx62n.c | 192 +++++++++++++++++++++++++++++++++ hw/rx/Kconfig | 6 ++ hw/rx/meson.build | 1 + 4 files changed, 200 insertions(+) create mode 100644 hw/rx/tkdn-rx62n.c diff --git a/default-configs/rx-softmmu.mak b/default-configs/rx-softmmu.mak index df2b4e4f42..ea8731d67b 100644 --- a/default-configs/rx-softmmu.mak +++ b/default-configs/rx-softmmu.mak @@ -1,3 +1,4 @@ # Default configuration for rx-softmmu =20 CONFIG_RX_GDBSIM=3Dy +CONFIG_TKDN_RX62N=3Dy diff --git a/hw/rx/tkdn-rx62n.c b/hw/rx/tkdn-rx62n.c new file mode 100644 index 0000000000..3db0fc8294 --- /dev/null +++ b/hw/rx/tkdn-rx62n.c @@ -0,0 +1,192 @@ +/* + * Tokushudenshikairo TKDN-RX62N-BRD + * + * 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 "qemu/cutils.h" +#include "qapi/error.h" +#include "qemu-common.h" +#include "cpu.h" +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/loader.h" +#include "hw/rx/loader.h" +#include "hw/qdev-properties.h" +#include "hw/rx/rx62n.h" +#include "net/net.h" +#include "hw/net/mii.h" +#include "hw/boards.h" +#include "sysemu/sysemu.h" +#include "sysemu/qtest.h" +#include "sysemu/device_tree.h" + +typedef struct { + /*< private >*/ + MachineState parent_obj; + /*< public >*/ + RX62NState mcu; + PHYState phy; + MDIOState mdio; +} TKDN_RX62NMachineState; + +#define TYPE_TKDN_RX62N_MACHINE MACHINE_TYPE_NAME("tkdn-rx62n-brd") + +#define TKDN_RX62N_MACHINE(obj) \ + OBJECT_CHECK(TKDN_RX62NMachineState, (obj), TYPE_TKDN_RX62N_MACHINE) + +#define TINYBOOT_TOP (0xffffff00) + +static void set_bootstrap(hwaddr entry, hwaddr dtb) +{ + /* 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; + + *((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); +} + +/* Link 100BaseTX-FD */ +#define BMSR (MII_BMSR_100TX_FD | MII_BMSR_100TX_HD | \ + MII_BMSR_10T_FD | MII_BMSR_10T_HD | MII_BMSR_MFPS | \ + MII_BMSR_AN_COMP | MII_BMSR_AUTONEG) +#define ANLPAR (MII_ANLPAR_TXFD | MII_ANAR_CSMACD) + +static void tkdn_rx62n_net_init(MachineState *m, RX62NState *s, + NICInfo *nd) +{ + TKDN_RX62NMachineState *t =3D TKDN_RX62N_MACHINE(m); + object_initialize_child(OBJECT(t), "ether-phy", + &t->phy, TYPE_ETHER_PHY); + qdev_prop_set_uint32(DEVICE(&t->phy), "phy-id", 0x0007c0f0); /* LAN872= 0A */ + qdev_prop_set_uint32(DEVICE(&t->phy), "link-out-pol", phy_out_p); + qdev_prop_set_uint16(DEVICE(&t->phy), "bmsr", BMSR); + qdev_prop_set_uint16(DEVICE(&t->phy), "anlpar", ANLPAR); + qdev_realize(DEVICE(&t->phy), NULL, &error_abort); + + object_initialize_child(OBJECT(t), "mdio-bb", + &t->mdio, TYPE_ETHER_MDIO_BB); + object_property_set_link(OBJECT(&t->mdio), "phy", + OBJECT(&t->phy), &error_abort); + qdev_prop_set_int32(DEVICE(&t->mdio), "address", 0); + qdev_realize(DEVICE(&t->mdio), NULL, &error_abort); +} + +#define SDRAM_BASE 0x08000000 + +static void tkdn_rx62n_init(MachineState *machine) +{ + MachineClass *mc =3D MACHINE_GET_CLASS(machine); + TKDN_RX62NMachineState *s =3D TKDN_RX62N_MACHINE(machine); + RX62NClass *rx62nc; + MemoryRegion *sysmem =3D get_system_memory(); + const char *kernel_filename =3D machine->kernel_filename; + const char *dtb_filename =3D machine->dtb; + rx_kernel_info_t kernel_info; + + if (machine->ram_size < mc->default_ram_size) { + char *sz =3D size_to_str(mc->default_ram_size); + error_report("Invalid RAM size, should be more than %s", sz); + g_free(sz); + } + + /* Allocate memory space */ + memory_region_add_subregion(sysmem, SDRAM_BASE, machine->ram); + + /* Initialize MCU */ + object_initialize_child(OBJECT(machine), "mcu", + &s->mcu, TYPE_R5F562N8_MCU); + rx62nc =3D RX62N_MCU_GET_CLASS(&s->mcu); + object_property_set_link(OBJECT(&s->mcu), "main-bus", OBJECT(sysmem), + &error_abort); + object_property_set_uint(OBJECT(&s->mcu), "xtal-frequency-hz", + 12 * 1000 * 1000, &error_abort); + tkdn_rx62n_net_init(machine, &s->mcu, nd_table); + object_property_set_link(OBJECT(&s->mcu), "mdiodev", + OBJECT(&s->mdio), &error_abort); + /* Load kernel and dtb */ + if (kernel_filename) { + kernel_info.ram_start =3D SDRAM_BASE; + kernel_info.ram_size =3D machine->ram_size; + kernel_info.filename =3D kernel_filename; + kernel_info.dtbname =3D dtb_filename; + kernel_info.cmdline =3D machine->kernel_cmdline; + if (!load_kernel(&kernel_info)) { + exit(1); + } + set_bootstrap(kernel_info.entry, kernel_info.dtb_address); + } else { + if (bios_name) { + if (!load_bios(bios_name, rx62nc->rom_flash_size, &error_abort= )) { + exit(0); + } + } else if (!qtest_enabled()) { + error_report("No bios or kernel specified"); + exit(1); + } + } + qdev_realize(DEVICE(&s->mcu), NULL, &error_abort); +} + +static void tkdn_rx62n_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc =3D MACHINE_CLASS(oc); + + mc->desc =3D "TokushuDenshiKairo Inc, TKDN-RX62N-BRD"; + mc->init =3D tkdn_rx62n_init; + mc->is_default =3D 0; + mc->default_cpu_type =3D TYPE_RX62N_CPU; + mc->default_ram_size =3D 16 * MiB; + mc->default_ram_id =3D "ext-sdram"; +} + +static const TypeInfo tkdn_rx62n_type =3D { + .name =3D TYPE_TKDN_RX62N_MACHINE, + .parent =3D TYPE_MACHINE, + .instance_size =3D sizeof(TKDN_RX62NMachineState), + .class_init =3D tkdn_rx62n_class_init, +}; + +static void tkdn_rx62n_machine_init(void) +{ + type_register_static(&tkdn_rx62n_type); +} + +type_init(tkdn_rx62n_machine_init) diff --git a/hw/rx/Kconfig b/hw/rx/Kconfig index f20ea63fd9..0ef20d0c3c 100644 --- a/hw/rx/Kconfig +++ b/hw/rx/Kconfig @@ -11,3 +11,9 @@ config RX_GDBSIM bool select RX62N_MCU select FITLOADER + +config TKDN_RX62N + bool + select RX62N_MCU + select FITLOADER + diff --git a/hw/rx/meson.build b/hw/rx/meson.build index 3a81d85a53..0a741e091c 100644 --- a/hw/rx/meson.build +++ b/hw/rx/meson.build @@ -1,6 +1,7 @@ rx_ss =3D ss.source_set() rx_ss.add(files('loader.c')) rx_ss.add(when: 'CONFIG_RX_GDBSIM', if_true: files('rx-gdbsim.c')) +rx_ss.add(when: 'CONFIG_TKDN_RX62N', if_true: files('tkdn-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 Nov 16 04:02:32 2025 Delivered-To: importer@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+importer=patchew.org@nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1598532129; cv=none; d=zohomail.com; s=zohoarc; b=hiq/9j8ntdXJ+xQhd3kcuF+/v6wtALsS0W1MPmi8/+S2y1WRdUmY+HWBKK6coEjX1N8G7IcYHY0e9UQqNnLPGLEc6DYREEvPVbKqu+BepoBstFjvZr4/+SNqe5LsuGLbaMWoE54mLCw4lXTqkvnUKU0WB+xBr4vHIVk4+qpKCxo= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1598532129; 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=SZVcaaGgIPF0KoMQNnGwlSeWvNphOTnJAwKxb4Ua9Ng=; b=X4yYi8U0FxMCqp8yMFPT5YdC1tbka8/yxT7lT0SJSGvUS7FV/Q2VI22q4zm1CtBRAEWIkWZyRWuAwWGcQcFMZ2ygdv896sv4793qnUaCurMIrjeO8agfUo8LBS093BnZUMupt6T40XcSCkdzZnmtxko+IJJS33Q7CnVnoXp0zAU= 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+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1598532129063706.7308424523835; Thu, 27 Aug 2020 05:42:09 -0700 (PDT) Received: from localhost ([::1]:50276 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kBHEF-0005qg-M1 for importer@patchew.org; Thu, 27 Aug 2020 08:42:07 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:59066) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kBHBV-00086e-4C for qemu-devel@nongnu.org; Thu, 27 Aug 2020 08:39:17 -0400 Received: from mail02.asahi-net.or.jp ([202.224.55.14]:56311) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kBHBO-0005wY-Np for qemu-devel@nongnu.org; Thu, 27 Aug 2020 08:39:16 -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 BFCF72683A; Thu, 27 Aug 2020 21:39:09 +0900 (JST) Received: from yo-satoh-debian.localdomain (ZM005235.ppp.dion.ne.jp [222.8.5.235]) by sakura.ysato.name (Postfix) with ESMTPSA id 783C81C0792; Thu, 27 Aug 2020 21:39:09 +0900 (JST) From: Yoshinori Sato To: qemu-devel@nongnu.org Subject: [PATCH 19/20] hw/rx: Add CQ-FRK-RX62N target Date: Thu, 27 Aug 2020 21:38:58 +0900 Message-Id: <20200827123859.81793-20-ysato@users.sourceforge.jp> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200827123859.81793-1-ysato@users.sourceforge.jp> References: <20200827123859.81793-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+importer=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-detected-operating-system: by eggs.gnu.org: First seen = 2020/08/27 08:39:06 X-ACL-Warn: Detected OS = ??? 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+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" It most popular RX target board in Japan. Signed-off-by: Yoshinori Sato --- default-configs/rx-softmmu.mak | 1 + hw/rx/cq-frk-rx62n.c | 94 ++++++++++++++++++++++++++++++++++ hw/rx/Kconfig | 3 ++ hw/rx/meson.build | 1 + 4 files changed, 99 insertions(+) create mode 100644 hw/rx/cq-frk-rx62n.c diff --git a/default-configs/rx-softmmu.mak b/default-configs/rx-softmmu.mak index ea8731d67b..dbbaee8809 100644 --- a/default-configs/rx-softmmu.mak +++ b/default-configs/rx-softmmu.mak @@ -2,3 +2,4 @@ =20 CONFIG_RX_GDBSIM=3Dy CONFIG_TKDN_RX62N=3Dy +CONFIG_FRK_RX62N=3Dy diff --git a/hw/rx/cq-frk-rx62n.c b/hw/rx/cq-frk-rx62n.c new file mode 100644 index 0000000000..a1cd9cb2ad --- /dev/null +++ b/hw/rx/cq-frk-rx62n.c @@ -0,0 +1,94 @@ +/* + * CQ publishing CQ-FRK-RX62N + * + * 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 "qemu/cutils.h" +#include "qapi/error.h" +#include "qemu-common.h" +#include "cpu.h" +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/loader.h" +#include "hw/rx/loader.h" +#include "hw/qdev-properties.h" +#include "hw/rx/rx62n.h" +#include "sysemu/sysemu.h" +#include "sysemu/qtest.h" +#include "sysemu/device_tree.h" +#include "hw/boards.h" + +typedef struct { + /*< private >*/ + MachineState parent_obj; + /*< public >*/ + RX62NState mcu; +} FRK_RX62NMachineState; + +#define TYPE_FRK_RX62N_MACHINE MACHINE_TYPE_NAME("cq-frk-rx62n") + +#define FRK_RX62N_MACHINE(obj) \ + OBJECT_CHECK(FRK_RX62NMachineState, (obj), TYPE_FRK_RX62N_MACHINE) + +static void frk_rx62n_init(MachineState *machine) +{ + FRK_RX62NMachineState *s =3D FRK_RX62N_MACHINE(machine); + RX62NClass *rx62nc; + MemoryRegion *sysmem =3D get_system_memory(); + + /* Initialize MCU */ + object_initialize_child(OBJECT(machine), "mcu", + &s->mcu, TYPE_R5F562N7_MCU); + rx62nc =3D RX62N_MCU_GET_CLASS(&s->mcu); + object_property_set_link(OBJECT(&s->mcu), "main-bus", OBJECT(sysmem), + &error_abort); + object_property_set_uint(OBJECT(&s->mcu), "xtal-frequency-hz", + 12 * 1000 * 1000, &error_abort); + if (bios_name) { + if (!load_bios(bios_name, rx62nc->rom_flash_size, &error_abort)) { + exit(0); + } + } else if (!qtest_enabled()) { + error_report("No bios specified"); + exit(1); + } + qdev_realize(DEVICE(&s->mcu), NULL, &error_abort); +} + +static void frk_rx62n_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc =3D MACHINE_CLASS(oc); + + mc->desc =3D "CQ publishing CQ-FRK-RX62N"; + mc->init =3D frk_rx62n_init; + mc->is_default =3D 0; + mc->default_cpu_type =3D TYPE_RX62N_CPU; +} + +static const TypeInfo frk_rx62n_type =3D { + .name =3D MACHINE_TYPE_NAME("cq-frk-rx62n"), + .parent =3D TYPE_MACHINE, + .instance_size =3D sizeof(FRK_RX62NMachineState), + .class_init =3D frk_rx62n_class_init, +}; + +static void frk_rx62n_machine_init(void) +{ + type_register_static(&frk_rx62n_type); +} + +type_init(frk_rx62n_machine_init) diff --git a/hw/rx/Kconfig b/hw/rx/Kconfig index 0ef20d0c3c..ab2c472510 100644 --- a/hw/rx/Kconfig +++ b/hw/rx/Kconfig @@ -17,3 +17,6 @@ config TKDN_RX62N select RX62N_MCU select FITLOADER =20 +config FRK_RX62N + bool + select RX62N_MCU diff --git a/hw/rx/meson.build b/hw/rx/meson.build index 0a741e091c..0f26f1fcb2 100644 --- a/hw/rx/meson.build +++ b/hw/rx/meson.build @@ -2,6 +2,7 @@ rx_ss =3D ss.source_set() rx_ss.add(files('loader.c')) rx_ss.add(when: 'CONFIG_RX_GDBSIM', if_true: files('rx-gdbsim.c')) rx_ss.add(when: 'CONFIG_TKDN_RX62N', if_true: files('tkdn-rx62n.c')) +rx_ss.add(when: 'CONFIG_FRK_RX62N', if_true: files('cq-frk-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 Nov 16 04:02:32 2025 Delivered-To: importer@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+importer=patchew.org@nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1598532439; cv=none; d=zohomail.com; s=zohoarc; b=kC+WG668HsTlpqWAGvbkdmDSOYnRSjZUs58DMVKDr5eFb57kPOP810C+53wpq/uV+v5p5wes8gwZ0GeLEM8UZBlgImV3vBNZoaIl2badMTOebysfmAsPoRkJWlYlBEVEZYe4+2puN6ewI6mRn5BmC/yvfrkS6DOLFCYYt8NRFRQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1598532439; 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=dcKzI+i0ObIidFlO4pGNNwka6LM+Lxg6wosqbMrXIDQ=; b=ZbXhxD0v4AEYLyo4e11OXHt7XzJY0Pn2sKRx/sof0wf2dzlc3E18HdrSmMCZU8kJsqs6lpdDz7F6xY529oXAXKgz0f313BbVaApLL+dKpHYYlbDsGzvez89IRxfNcW1zRr7DfQFhNY5zS4OZgZDR4jUfjXhP53YmriJb0UCyMLE= 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+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1598532439242895.2975350863081; Thu, 27 Aug 2020 05:47:19 -0700 (PDT) Received: from localhost ([::1]:42186 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kBHJF-0005fu-Vt for importer@patchew.org; Thu, 27 Aug 2020 08:47:18 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:59076) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kBHBV-00087v-Kw for qemu-devel@nongnu.org; Thu, 27 Aug 2020 08:39:17 -0400 Received: from mail03.asahi-net.or.jp ([202.224.55.15]:39228) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kBHBR-0005xj-H4 for qemu-devel@nongnu.org; Thu, 27 Aug 2020 08:39:17 -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 0069026AF9; Thu, 27 Aug 2020 21:39:10 +0900 (JST) Received: from yo-satoh-debian.localdomain (ZM005235.ppp.dion.ne.jp [222.8.5.235]) by sakura.ysato.name (Postfix) with ESMTPSA id A78621C0696; Thu, 27 Aug 2020 21:39:09 +0900 (JST) From: Yoshinori Sato To: qemu-devel@nongnu.org Subject: [PATCH 20/20] MAINTAINERS: Update RX entry Date: Thu, 27 Aug 2020 21:38:59 +0900 Message-Id: <20200827123859.81793-21-ysato@users.sourceforge.jp> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200827123859.81793-1-ysato@users.sourceforge.jp> References: <20200827123859.81793-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+importer=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-detected-operating-system: by eggs.gnu.org: First seen = 2020/08/27 08:39:06 X-ACL-Warn: Detected OS = ??? 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+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" Signed-off-by: Yoshinori Sato --- MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 5a22c8be42..cee8448a73 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2054,9 +2054,11 @@ F: hw/char/renesas_sci.c F: hw/char/sh_serial.c F: hw/timer/renesas_*.c F: hw/timer/sh_timer.c +F: hw/net/renesas_eth.c F: include/hw/char/renesas_sci.h F: include/hw/sh4/sh.h F: include/hw/timer/renesas_*.h +F: include/hw/net/renesas_eth.h =20 Renesas RX peripherals M: Yoshinori Sato --=20 2.20.1