From nobody Mon May 6 01:33:55 2024 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; dmarc=fail(p=quarantine dis=none) header.from=opensource.wdc.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1630625391406251.98734103871618; Thu, 2 Sep 2021 16:29:51 -0700 (PDT) Received: from localhost ([::1]:37818 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1mLw9W-00037K-Dc for importer@patchew.org; Thu, 02 Sep 2021 19:29:50 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:54250) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mLw5W-0005Wi-6B for qemu-devel@nongnu.org; Thu, 02 Sep 2021 19:25:42 -0400 Received: from esa2.hgst.iphmx.com ([68.232.143.124]:40993) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mLw5S-00053D-2J for qemu-devel@nongnu.org; Thu, 02 Sep 2021 19:25:41 -0400 Received: from h199-255-45-14.hgst.com (HELO uls-op-cesaep01.wdc.com) ([199.255.45.14]) by ob1.hgst.iphmx.com with ESMTP; 03 Sep 2021 07:25:36 +0800 Received: from uls-op-cesaip01.wdc.com ([10.248.3.36]) by uls-op-cesaep01.wdc.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Sep 2021 16:02:21 -0700 Received: from usg-ed-osssrv.wdc.com ([10.3.10.180]) by uls-op-cesaip01.wdc.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Sep 2021 16:25:36 -0700 Received: from usg-ed-osssrv.wdc.com (usg-ed-osssrv.wdc.com [127.0.0.1]) by usg-ed-osssrv.wdc.com (Postfix) with ESMTP id 4H0xqg6v08z1RvlY for ; Thu, 2 Sep 2021 16:25:35 -0700 (PDT) Received: from usg-ed-osssrv.wdc.com ([127.0.0.1]) by usg-ed-osssrv.wdc.com (usg-ed-osssrv.wdc.com [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id HLRBRBKy2iIM for ; Thu, 2 Sep 2021 16:25:31 -0700 (PDT) Received: from toolbox.alistair23.me (unknown [10.225.165.17]) by usg-ed-osssrv.wdc.com (Postfix) with ESMTPSA id 4H0xqW2p7fz1RvlP; Thu, 2 Sep 2021 16:25:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=wdc.com; i=@wdc.com; q=dns/txt; s=dkim.wdc.com; t=1630625137; x=1662161137; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=MD8/msSLo1R3TNvr51J6POulyhehlKwRgHqBIWlES7E=; b=o24TuzjAYit1CZ28SYFiYL7onyhWdzpE7Y0r6+cwsHfvZ2AvL6V8IRNn 3e1VEZZ1/dX+ZVGZI65nsnDkInO96VdS6sniROLKIQBcs5E5Y62ZcrjeJ 1LJmvc3f3X3TcuaJ46mG/tPvN563Y2St2Rzoj742q8BRYkvbmmY/Oc36X 19mPeoomedaec0St+dU/88qLIBJ18RsbyeJ0YROyFf7NidGZLJmw56DSb M9NvPwNUTf55libqXT/ASZ2PxndHRw0LK8unq3v8j032/hQcPvwuFvk4D tVzTPAcIT3L6NN1viObsM6e8iXxHj7T8T4sOdJ0rhHBLAAYWfyqfnqLGL g==; X-IronPort-AV: E=Sophos;i="5.85,263,1624291200"; d="scan'208";a="282883287" IronPort-SDR: ClHN4hu3rkmGFl/HYfbtzmg96nLpbA6izKKwdMs6NMDEo18AWTpysYMIa1riM1KdvGzqugLh/M ABKkAp8gVaT+OkZZtUVIomGVAmT1uB2d2C86Wyp0ssUqiMPvJ6XUtYsdCVStdYU8gFrpRU+8d3 DehRAUeWUYIuAjk3IsUDi7J8v1BurQ6H9ewJ3sYT7swc8GmlFtgPO9xedQBHAtsUcRTIqkBayP 9gCbFEUOLiBT0jwZUc8opyuOfrNB+bNCUFY86f4jVDIbQelHShA3Et3sl+7pk7PvI0yazNXNHI x9+1myKdZtbS7pQNe3s0lh/I IronPort-SDR: KTWcz0FpF7A6iSVOtUcCWSymzuLI6Qo0F5xLdpiFE6pw1KxYlBI1EpT6GYygGsy7QPsv9rJgOt zw6oihmiFikSt4NKTPjS0baByI3mis/fKok+rNth+lZC/8njilUBImO5cT/1yBshPIfOkA5SZC 6A4Hpvy5M8YWp4lI3pPRaTbmya0JbEzaZpgcTJAxhKTs3B9xkHw1uqEKoLJIRBxAYi2uOk76Dx 34hFwW3bRA+RGJONRQ32KN32/3DbjiFy6wq/5ed3OXraGu/+JR2VxFBpX4/U9NmHnPBgQO7lvq Nsc= WDCIronportException: Internal Authentication-Results: usg-ed-osssrv.wdc.com (amavisd-new); dkim=pass reason="pass (just generated, assumed good)" header.d=opensource.wdc.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d= opensource.wdc.com; h=content-transfer-encoding:mime-version :references:in-reply-to:x-mailer:message-id:date:subject:to :from; s=dkim; t=1630625131; x=1633217132; bh=MD8/msSLo1R3TNvr51 J6POulyhehlKwRgHqBIWlES7E=; b=c6NOTi0UVWxnyxtqIi6dg6N07Dr/UwqGZF x5iBKro9nrTEt116Kz2a9xKKWaAWGta9PAKfT1UTxLFUymdYYIghhvA+YVu0fTR+ 9U7Qwgo8rkr5x+nhI2Wc0MAtR9if5XO53nYeWLnrXQmVGJM8Ha60+U9SLAgAH9PO jyhg6e9sPdRz9fmpsJGtM7OCUlf7shkOEkiDVPyrvwD8SxZx3/vJYlAUE3jFqXrM FnCFSvEfUxfKsP1Nok2AblikJhcqHU5ZnPxCwHu02JigaxokfT9BF0OfWhlbG1nk o5Ximu3CTO5RDXNHGPnE31Gp9Nw98jrx8ddkB/mO5QKL1b244dpQ== X-Virus-Scanned: amavisd-new at usg-ed-osssrv.wdc.com From: Alistair Francis To: qemu-devel@nongnu.org, qemu-riscv@nongnu.org Cc: bmeng.cn@gmail.com, palmer@dabbelt.com, alistair.francis@wdc.com, alistair23@gmail.com Subject: [PATCH v2 1/2] hw/timer: Add SiFive PWM support Date: Fri, 3 Sep 2021 09:25:21 +1000 Message-Id: X-Mailer: git-send-email 2.31.1 In-Reply-To: References: 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: pass client-ip=68.232.143.124; envelope-from=prvs=8724dbd3c=alistair.francis@opensource.wdc.com; helo=esa2.hgst.iphmx.com X-Spam_score_int: -43 X-Spam_score: -4.4 X-Spam_bar: ---- X-Spam_report: (-4.4 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham 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: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZM-MESSAGEID: 1630625392623100001 Content-Type: text/plain; charset="utf-8" From: Alistair Francis This is the initial commit of the SiFive PWM timer. This is used by guest software are a timer and is included in the SiFive FU540 SoC. Signed-off-by: Justin Restivo Signed-off-by: Alexandra Clifford Signed-off-by: Amanda Strnad Signed-off-by: Alistair Francis --- include/hw/timer/sifive_pwm.h | 62 +++++ hw/timer/sifive_pwm.c | 467 ++++++++++++++++++++++++++++++++++ hw/timer/Kconfig | 3 + hw/timer/meson.build | 1 + hw/timer/trace-events | 6 + 5 files changed, 539 insertions(+) create mode 100644 include/hw/timer/sifive_pwm.h create mode 100644 hw/timer/sifive_pwm.c diff --git a/include/hw/timer/sifive_pwm.h b/include/hw/timer/sifive_pwm.h new file mode 100644 index 0000000000..e8bedca76e --- /dev/null +++ b/include/hw/timer/sifive_pwm.h @@ -0,0 +1,62 @@ +/* + * SiFive FU540 PWM + * + * Copyright (c) 2020 Western Digital + * + * Author: Alistair Francis + * + * Permission is hereby granted, free of charge, to any person obtaining a= copy + * of this software and associated documentation files (the "Software"), t= o deal + * in the Software without restriction, including without limitation the r= ights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or se= ll + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included= in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS= OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OT= HER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING= FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS = IN + * THE SOFTWARE. + */ + +#ifndef HW_SIFIVE_PWM_H +#define HW_SIFIVE_PWM_H + +#include "hw/sysbus.h" +#include "qemu/timer.h" +#include "qom/object.h" + +#define TYPE_SIFIVE_PWM "sifive-pwm" + +#define SIFIVE_PWM(obj) \ + OBJECT_CHECK(SiFiveUPwmState, (obj), TYPE_SIFIVE_PWM) + +#define SIFIVE_PWM_CHANS 4 +#define SIFIVE_PWM_IRQS SIFIVE_PWM_CHANS + +typedef struct SiFiveUPwmState { + /* */ + SysBusDevice parent_obj; + + /* */ + MemoryRegion mmio; + QEMUTimer timer[SIFIVE_PWM_CHANS]; + /* + * if en bit(s) set, is the number of ticks when pwmcount was 0 + * if en bit(s) not set, is the number of ticks in pwmcount + */ + uint64_t tick_offset; + uint64_t freq_hz; + + uint32_t pwmcfg; + uint32_t pwmcmp[SIFIVE_PWM_CHANS]; + + qemu_irq irqs[SIFIVE_PWM_IRQS]; +} SiFiveUPwmState; + +#endif /* HW_SIFIVE_PWM_H */ diff --git a/hw/timer/sifive_pwm.c b/hw/timer/sifive_pwm.c new file mode 100644 index 0000000000..61a97f9b46 --- /dev/null +++ b/hw/timer/sifive_pwm.c @@ -0,0 +1,467 @@ +/* + * SiFive PWM + * + * Copyright (c) 2020 Western Digital + * + * Author: Alistair Francis + * + * Permission is hereby granted, free of charge, to any person obtaining a= copy + * of this software and associated documentation files (the "Software"), t= o deal + * in the Software without restriction, including without limitation the r= ights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or se= ll + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included= in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS= OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OT= HER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING= FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS = IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "hw/irq.h" +#include "hw/timer/sifive_pwm.h" +#include "hw/qdev-properties.h" +#include "hw/registerfields.h" +#include "migration/vmstate.h" +#include "qemu/log.h" +#include "qemu/module.h" + +#define HAS_PWM_EN_BITS(cfg) ((cfg & R_CONFIG_ENONESHOT_MASK) || \ + (cfg & R_CONFIG_ENALWAYS_MASK)) + +#define PWMCMP_MASK 0xFFFF +#define PWMCOUNT_MASK 0x7FFFFFFF + +REG32(CONFIG, 0x00) + FIELD(CONFIG, SCALE, 0, 4) + FIELD(CONFIG, STICKY, 8, 1) + FIELD(CONFIG, ZEROCMP, 9, 1) + FIELD(CONFIG, DEGLITCH, 10, 1) + FIELD(CONFIG, ENALWAYS, 12, 1) + FIELD(CONFIG, ENONESHOT, 13, 1) + FIELD(CONFIG, CMP0CENTER, 16, 1) + FIELD(CONFIG, CMP1CENTER, 17, 1) + FIELD(CONFIG, CMP2CENTER, 18, 1) + FIELD(CONFIG, CMP3CENTER, 19, 1) + FIELD(CONFIG, CMP0GANG, 24, 1) + FIELD(CONFIG, CMP1GANG, 25, 1) + FIELD(CONFIG, CMP2GANG, 26, 1) + FIELD(CONFIG, CMP3GANG, 27, 1) + FIELD(CONFIG, CMP0IP, 28, 1) + FIELD(CONFIG, CMP1IP, 29, 1) + FIELD(CONFIG, CMP2IP, 30, 1) + FIELD(CONFIG, CMP3IP, 31, 1) +REG32(COUNT, 0x08) +REG32(PWMS, 0x10) +REG32(PWMCMP0, 0x20) +REG32(PWMCMP1, 0x24) +REG32(PWMCMP2, 0x28) +REG32(PWMCMP3, 0x2C) + +static inline uint64_t sifive_u_pwm_ns_to_ticks(SiFiveUPwmState *s, + uint64_t time) +{ + return muldiv64(time, s->freq_hz, NANOSECONDS_PER_SECOND); +} + +static inline uint64_t sifive_u_pwm_ticks_to_ns(SiFiveUPwmState *s, + uint64_t ticks) +{ + return muldiv64(ticks, NANOSECONDS_PER_SECOND, s->freq_hz); +} + +static inline uint64_t sifive_u_pwm_compute_scale(SiFiveUPwmState *s) +{ + return s->pwmcfg & R_CONFIG_SCALE_MASK; +} + +static void sifive_u_pwm_set_alarms(SiFiveUPwmState *s) +{ + uint64_t now_ns =3D qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + + if (HAS_PWM_EN_BITS(s->pwmcfg)) { + /* + * Subtract ticks from number of ticks when the timer was zero + * and mask to the register width. + */ + uint64_t pwmcount =3D (sifive_u_pwm_ns_to_ticks(s, now_ns) - + s->tick_offset) & PWMCOUNT_MASK; + uint64_t scale =3D sifive_u_pwm_compute_scale(s); + /* PWMs only contains PWMCMP_MASK bits starting at scale */ + uint64_t pwms =3D (pwmcount & (PWMCMP_MASK << scale)) >> scale; + + for (int i =3D 0; i < SIFIVE_PWM_CHANS; i++) { + uint64_t pwmcmp =3D s->pwmcmp[i] & PWMCMP_MASK; + uint64_t pwmcmp_ticks =3D pwmcmp << scale; + + /* + * Per circuit diagram and spec, both cases raises correspondi= ng + * IP bit one clock cycle after time expires. + */ + if (pwmcmp > pwms) { + uint64_t offset =3D pwmcmp_ticks - pwmcount + 1; + uint64_t when_to_fire =3D now_ns + + sifive_u_pwm_ticks_to_ns(s, offs= et); + + trace_sifive_pwm_set_alarm(when_to_fire, now_ns); + timer_mod(&s->timer[i], when_to_fire); + } else { + /* Schedule interrupt for next cycle */ + trace_sifive_pwm_set_alarm(now_ns + 1, now_ns); + timer_mod(&s->timer[i], now_ns + 1); + } + + } + } else { + /* + * If timer incrementing disabled, just do pwms > pwmcmp check sin= ce + * a write may have happened to PWMs. + */ + uint64_t pwmcount =3D (s->tick_offset) & PWMCOUNT_MASK; + uint64_t scale =3D sifive_u_pwm_compute_scale(s); + uint64_t pwms =3D (pwmcount & (PWMCMP_MASK << scale)) >> scale; + + for (int i =3D 0; i < SIFIVE_PWM_CHANS; i++) { + uint64_t pwmcmp =3D s->pwmcmp[i] & PWMCMP_MASK; + + if (pwms >=3D pwmcmp) { + trace_sifive_pwm_set_alarm(now_ns + 1, now_ns); + timer_mod(&s->timer[i], now_ns + 1); + } else { + /* Effectively disable timer by scheduling far in future. = */ + trace_sifive_pwm_set_alarm(0xFFFFFFFFFFFFFF, now_ns); + timer_mod(&s->timer[i], 0xFFFFFFFFFFFFFF); + } + } + } +} + +static void sifive_u_pwm_interrupt(SiFiveUPwmState *s, int num) +{ + uint64_t now =3D sifive_u_pwm_ns_to_ticks(s, + qemu_clock_get_ns(QEMU_CLOCK_VIRTU= AL)); + bool was_incrementing =3D HAS_PWM_EN_BITS(s->pwmcfg); + + trace_sifive_pwm_interrupt(num); + + s->pwmcfg |=3D R_CONFIG_CMP0IP_MASK << num; + qemu_irq_raise(s->irqs[num]); + + /* + * If the zerocmp is set and pwmcmp0 raised the interrupt + * reset the zero ticks. + */ + if ((s->pwmcfg & R_CONFIG_ZEROCMP_MASK) && (num =3D=3D 0)) { + /* If reset signal conditions, disable ENONESHOT. */ + s->pwmcfg &=3D ~R_CONFIG_ENONESHOT_MASK; + + if (was_incrementing) { + /* If incrementing, time in ticks is when pwmcount is zero */ + s->tick_offset =3D now; + } else { + /* If not incrementing, pwmcount =3D 0 */ + s->tick_offset =3D 0; + } + } + + /* + * If carryout bit set, which we discern via looking for overflow, + * also reset ENONESHOT. + */ + if (was_incrementing && + ((now & PWMCOUNT_MASK) < (s->tick_offset & PWMCOUNT_MASK))) { + s->pwmcfg &=3D ~R_CONFIG_ENONESHOT_MASK; + } + + /* Schedule or disable interrupts */ + sifive_u_pwm_set_alarms(s); + + /* If was enabled, and now not enabled, switch tick rep */ + if (was_incrementing && !HAS_PWM_EN_BITS(s->pwmcfg)) { + s->tick_offset =3D (now - s->tick_offset) & PWMCOUNT_MASK; + } +} + +static void sifive_u_pwm_interrupt_0(void *opaque) +{ + SiFiveUPwmState *s =3D opaque; + + sifive_u_pwm_interrupt(s, 0); +} + +static void sifive_u_pwm_interrupt_1(void *opaque) +{ + SiFiveUPwmState *s =3D opaque; + + sifive_u_pwm_interrupt(s, 1); +} + +static void sifive_u_pwm_interrupt_2(void *opaque) +{ + SiFiveUPwmState *s =3D opaque; + + sifive_u_pwm_interrupt(s, 2); +} + +static void sifive_u_pwm_interrupt_3(void *opaque) +{ + SiFiveUPwmState *s =3D opaque; + + sifive_u_pwm_interrupt(s, 3); +} + +static uint64_t sifive_u_pwm_read(void *opaque, hwaddr addr, + unsigned int size) +{ + SiFiveUPwmState *s =3D opaque; + uint64_t cur_time, scale; + uint64_t now =3D sifive_u_pwm_ns_to_ticks(s, + qemu_clock_get_ns(QEMU_CLOCK_VIRTU= AL)); + + trace_sifive_pwm_read(addr); + + switch (addr) { + case A_CONFIG: + return s->pwmcfg; + case A_COUNT: + cur_time =3D s->tick_offset; + + if (HAS_PWM_EN_BITS(s->pwmcfg)) { + cur_time =3D now - cur_time; + } + + /* + * Return the value in the counter with bit 31 always 0 + * This is allowed to wrap around so we don't need to check that. + */ + return cur_time & PWMCOUNT_MASK; + case A_PWMS: + cur_time =3D s->tick_offset; + scale =3D sifive_u_pwm_compute_scale(s); + + if (HAS_PWM_EN_BITS(s->pwmcfg)) { + cur_time =3D now - cur_time; + } + + return ((cur_time & PWMCOUNT_MASK) >> scale) & PWMCMP_MASK; + case A_PWMCMP0: + return s->pwmcmp[0] & PWMCMP_MASK; + case A_PWMCMP1: + return s->pwmcmp[1] & PWMCMP_MASK; + case A_PWMCMP2: + return s->pwmcmp[2] & PWMCMP_MASK; + case A_PWMCMP3: + return s->pwmcmp[3] & PWMCMP_MASK; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr); + return 0; + } + + return 0; +} + +static void sifive_u_pwm_write(void *opaque, hwaddr addr, + uint64_t val64, unsigned int size) +{ + SiFiveUPwmState *s =3D opaque; + uint32_t value =3D val64; + uint64_t new_offset, scale; + uint64_t now =3D sifive_u_pwm_ns_to_ticks(s, + qemu_clock_get_ns(QEMU_CLOCK_VIRTU= AL)); + + trace_sifive_pwm_write(value, addr); + + switch (addr) { + case A_CONFIG: + if (value & (R_CONFIG_CMP0CENTER_MASK | R_CONFIG_CMP1CENTER_MASK | + R_CONFIG_CMP2CENTER_MASK | R_CONFIG_CMP3CENTER_MASK))= { + qemu_log_mask(LOG_UNIMP, "%s: CMPxCENTER is not supported\n", + __func__); + } + + if (value & (R_CONFIG_CMP0GANG_MASK | R_CONFIG_CMP1GANG_MASK | + R_CONFIG_CMP2GANG_MASK | R_CONFIG_CMP3GANG_MASK)) { + qemu_log_mask(LOG_UNIMP, "%s: CMPxGANG is not supported\n", + __func__); + } + + if (value & (R_CONFIG_CMP0IP_MASK | R_CONFIG_CMP1IP_MASK | + R_CONFIG_CMP2IP_MASK | R_CONFIG_CMP3IP_MASK)) { + qemu_log_mask(LOG_UNIMP, "%s: CMPxIP is not supported\n", + __func__); + } + + if (!(value & R_CONFIG_CMP0IP_MASK)) { + qemu_irq_lower(s->irqs[0]); + } + + if (!(value & R_CONFIG_CMP1IP_MASK)) { + qemu_irq_lower(s->irqs[1]); + } + + if (!(value & R_CONFIG_CMP2IP_MASK)) { + qemu_irq_lower(s->irqs[2]); + } + + if (!(value & R_CONFIG_CMP3IP_MASK)) { + qemu_irq_lower(s->irqs[3]); + } + + /* + * If this write enables the timer increment + * set the time when pwmcount was zero to be cur_time - pwmcount. + * If this write disables the timer increment + * convert back from pwmcount to the time in ticks + * when pwmcount was zero. + */ + if ((!HAS_PWM_EN_BITS(s->pwmcfg) && HAS_PWM_EN_BITS(value)) || + (HAS_PWM_EN_BITS(s->pwmcfg) && !HAS_PWM_EN_BITS(value))) { + s->tick_offset =3D (now - s->tick_offset) & PWMCOUNT_MASK; + } + + s->pwmcfg =3D value; + break; + case A_COUNT: + /* The guest changed the counter, updated the offset value. */ + new_offset =3D value; + + if (HAS_PWM_EN_BITS(s->pwmcfg)) { + new_offset =3D now - new_offset; + } + + s->tick_offset =3D new_offset; + break; + case A_PWMS: + scale =3D sifive_u_pwm_compute_scale(s); + new_offset =3D (((value & PWMCMP_MASK) << scale) & PWMCOUNT_MASK); + + if (HAS_PWM_EN_BITS(s->pwmcfg)) { + new_offset =3D now - new_offset; + } + + s->tick_offset =3D new_offset; + break; + case A_PWMCMP0: + s->pwmcmp[0] =3D value & PWMCMP_MASK; + break; + case A_PWMCMP1: + s->pwmcmp[1] =3D value & PWMCMP_MASK; + break; + case A_PWMCMP2: + s->pwmcmp[2] =3D value & PWMCMP_MASK; + break; + case A_PWMCMP3: + s->pwmcmp[3] =3D value & PWMCMP_MASK; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr); + } + + /* Update the alarms to reflect possible updated values */ + sifive_u_pwm_set_alarms(s); +} + +static void sifive_u_pwm_reset(DeviceState *dev) +{ + SiFiveUPwmState *s =3D SIFIVE_PWM(dev); + uint64_t now =3D qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + + s->pwmcfg =3D 0x00000000; + s->pwmcmp[0] =3D 0x00000000; + s->pwmcmp[1] =3D 0x00000000; + s->pwmcmp[2] =3D 0x00000000; + s->pwmcmp[3] =3D 0x00000000; + + s->tick_offset =3D sifive_u_pwm_ns_to_ticks(s, now); +} + +static const MemoryRegionOps sifive_u_pwm_ops =3D { + .read =3D sifive_u_pwm_read, + .write =3D sifive_u_pwm_write, + .endianness =3D DEVICE_NATIVE_ENDIAN, +}; + +static const VMStateDescription vmstate_sifive_u_pwm =3D { + .name =3D TYPE_SIFIVE_PWM, + .version_id =3D 1, + .minimum_version_id =3D 1, + .fields =3D (VMStateField[]) { + VMSTATE_TIMER_ARRAY(timer, SiFiveUPwmState, 4), + VMSTATE_UINT64(tick_offset, SiFiveUPwmState), + VMSTATE_UINT32(pwmcfg, SiFiveUPwmState), + VMSTATE_UINT32_ARRAY(pwmcmp, SiFiveUPwmState, 4), + VMSTATE_END_OF_LIST() + } +}; + +static Property sifive_u_pwm_properties[] =3D { + /* 0.5Ghz per spec after FSBL */ + DEFINE_PROP_UINT64("clock-frequency", struct SiFiveUPwmState, + freq_hz, 500000000ULL), + DEFINE_PROP_END_OF_LIST(), +}; + +static void sifive_u_pwm_init(Object *obj) +{ + SiFiveUPwmState *s =3D SIFIVE_PWM(obj); + int i; + + for (i =3D 0; i < SIFIVE_PWM_IRQS; i++) { + sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irqs[i]); + } + + memory_region_init_io(&s->mmio, obj, &sifive_u_pwm_ops, s, + TYPE_SIFIVE_PWM, 0x100); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); +} + +static void sifive_u_pwm_realize(DeviceState *dev, Error **errp) +{ + SiFiveUPwmState *s =3D SIFIVE_PWM(dev); + + timer_init_ns(&s->timer[0], QEMU_CLOCK_VIRTUAL, + sifive_u_pwm_interrupt_0, s); + + timer_init_ns(&s->timer[1], QEMU_CLOCK_VIRTUAL, + sifive_u_pwm_interrupt_1, s); + + timer_init_ns(&s->timer[2], QEMU_CLOCK_VIRTUAL, + sifive_u_pwm_interrupt_2, s); + + timer_init_ns(&s->timer[3], QEMU_CLOCK_VIRTUAL, + sifive_u_pwm_interrupt_3, s); +} + +static void sifive_u_pwm_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(klass); + + dc->reset =3D sifive_u_pwm_reset; + device_class_set_props(dc, sifive_u_pwm_properties); + dc->vmsd =3D &vmstate_sifive_u_pwm; + dc->realize =3D sifive_u_pwm_realize; +} + +static const TypeInfo sifive_u_pwm_info =3D { + .name =3D TYPE_SIFIVE_PWM, + .parent =3D TYPE_SYS_BUS_DEVICE, + .instance_size =3D sizeof(SiFiveUPwmState), + .instance_init =3D sifive_u_pwm_init, + .class_init =3D sifive_u_pwm_class_init, +}; + +static void sifive_u_pwm_register_types(void) +{ + type_register_static(&sifive_u_pwm_info); +} + +type_init(sifive_u_pwm_register_types) diff --git a/hw/timer/Kconfig b/hw/timer/Kconfig index 1e73da7e12..010be7ed1f 100644 --- a/hw/timer/Kconfig +++ b/hw/timer/Kconfig @@ -25,6 +25,9 @@ config ALLWINNER_A10_PIT bool select PTIMER =20 +config SIFIVE_PWM + bool + config STM32F2XX_TIMER bool =20 diff --git a/hw/timer/meson.build b/hw/timer/meson.build index e67478a8f1..03092e2ceb 100644 --- a/hw/timer/meson.build +++ b/hw/timer/meson.build @@ -35,5 +35,6 @@ softmmu_ss.add(when: 'CONFIG_STELLARIS_GPTM', if_true: fi= les('stellaris-gptm.c') softmmu_ss.add(when: 'CONFIG_STM32F2XX_TIMER', if_true: files('stm32f2xx_t= imer.c')) softmmu_ss.add(when: 'CONFIG_XILINX', if_true: files('xilinx_timer.c')) specific_ss.add(when: 'CONFIG_IBEX', if_true: files('ibex_timer.c')) +softmmu_ss.add(when: 'CONFIG_SIFIVE_PWM', if_true: files('sifive_pwm.c')) =20 specific_ss.add(when: 'CONFIG_AVR_TIMER16', if_true: files('avr_timer16.c'= )) diff --git a/hw/timer/trace-events b/hw/timer/trace-events index 5234c0ea9e..d0edcd2a80 100644 --- a/hw/timer/trace-events +++ b/hw/timer/trace-events @@ -88,3 +88,9 @@ sse_counter_reset(void) "SSE system counter: reset" sse_timer_read(uint64_t offset, uint64_t data, unsigned size) "SSE system = timer read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u" sse_timer_write(uint64_t offset, uint64_t data, unsigned size) "SSE system= timer write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u" sse_timer_reset(void) "SSE system timer: reset" + +# sifive_pwm.c +sifive_pwm_set_alarm(uint64_t alarm, uint64_t now) "Setting alarm to: 0x%"= PRIx64 ", now: 0x%" PRIx64 +sifive_pwm_interrupt(int num) "Interrupt %d" +sifive_pwm_read(uint64_t offset) "Read at address: 0x%" PRIx64 +sifive_pwm_write(uint64_t data, uint64_t offset) "Write 0x%" PRIx64 " at a= ddress: 0x%" PRIx64 --=20 2.31.1 From nobody Mon May 6 01:33:55 2024 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; dmarc=fail(p=quarantine dis=none) header.from=opensource.wdc.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1630625368031927.7626205885335; Thu, 2 Sep 2021 16:29:28 -0700 (PDT) Received: from localhost ([::1]:36742 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1mLw98-0002Ns-Tv for importer@patchew.org; Thu, 02 Sep 2021 19:29:27 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:54348) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mLw5d-0005aS-Pq for qemu-devel@nongnu.org; Thu, 02 Sep 2021 19:25:49 -0400 Received: from esa6.hgst.iphmx.com ([216.71.154.45]:52038) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mLw5b-00059g-2W for qemu-devel@nongnu.org; Thu, 02 Sep 2021 19:25:49 -0400 Received: from h199-255-45-14.hgst.com (HELO uls-op-cesaep01.wdc.com) ([199.255.45.14]) by ob1.hgst.iphmx.com with ESMTP; 03 Sep 2021 07:25:46 +0800 Received: from uls-op-cesaip01.wdc.com ([10.248.3.36]) by uls-op-cesaep01.wdc.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Sep 2021 16:02:30 -0700 Received: from usg-ed-osssrv.wdc.com ([10.3.10.180]) by uls-op-cesaip01.wdc.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Sep 2021 16:25:46 -0700 Received: from usg-ed-osssrv.wdc.com (usg-ed-osssrv.wdc.com [127.0.0.1]) by usg-ed-osssrv.wdc.com (Postfix) with ESMTP id 4H0xqs3r5yz1RvlT for ; Thu, 2 Sep 2021 16:25:45 -0700 (PDT) Received: from usg-ed-osssrv.wdc.com ([127.0.0.1]) by usg-ed-osssrv.wdc.com (usg-ed-osssrv.wdc.com [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id 40jvczu_02HS for ; Thu, 2 Sep 2021 16:25:44 -0700 (PDT) Received: from toolbox.alistair23.me (unknown [10.225.165.17]) by usg-ed-osssrv.wdc.com (Postfix) with ESMTPSA id 4H0xqm6R1Gz1RvlP; Thu, 2 Sep 2021 16:25:40 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=wdc.com; i=@wdc.com; q=dns/txt; s=dkim.wdc.com; t=1630625147; x=1662161147; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=rShATVOyZt9SnfwqKRn0y8UZ0rHTTM6iAVUUXimZzFU=; b=JwEm3OE4HFv0OgClRqZTibBWESV7/b9Bx4gV5rhcT2vc0cx65KzK2H/X jXGrOhDY5eRmJTxkUf1fnYTUyy6R0puvh0itclv9UaTfvTF4X69IatnZp Db/ZVYVX4jbiG/hNZKqR79gi46eKCRtG9NCY8VKe90CTehZ5cDiRvwqry Tiy7HrIcMORwBRCN5AckYRe98mKA1dDwDDrrvwAwyRixYS+DCd0yJc9aL H4gKvWAWcSnVdrT5uEA4K6Qf+TM2qo3yuNamhw+BYh+nCA8YuHTOdNj6m 2xi/2wGVtz8LOP36KiqKgFzkBZBgh2jvrEH6kv5B8yPHra7MkpO+j8m/N w==; X-IronPort-AV: E=Sophos;i="5.85,263,1624291200"; d="scan'208";a="179628325" IronPort-SDR: iBK602wISFvcMrq+KMQh9bhki49PBJ3Kqc7OvWufAgYODoBvax7iK5BAKzAhU1FU6+oyDavLDl 9yKjIAWjg7Oqy1PdRYRPE1b/X5AtkjARAG17+MSjuIm13sBiWaDducMpI0knpKLamMQ9lBzD46 XEVMYJwO3SNSjBwz48kSM4J6DjL6OJ5IUfVSvwubamx5VtXWyl+W0WeD/TL4yTVt1MVcEMLCni dKjCs2rug/DrLNalCg2kN0MzwRLSBB0wJP3rX1WIxYlzLZyD99WjH4OzAmgReDF2LloJZvMTiI 3DvjXe3NXJseYWC7pT13oOWI IronPort-SDR: EtjINgYXSpWsshjUuQmP0pKZ2fiI8EQtHenMKDl7ixlP20d5WLyi1/QoSvWtj4dO8BQHWCtMH5 D1EYmQGn2lygLoDVcb88Hm4soNbV8SAB444JJqBS1cXGO2YTdbgH5PtgZFVCDqzYP9ZNtnXQRz OVbMSij+dW4dti/Ot2tk5lzbRys+G5LbOq8oYZlkfxtAMAVcABaoZmgunxnnrHK03u/PQJOABq AqYkba2rxtYtQcWOijbNUxfQZba21hWYg5ohnXfwN2Lv0yzKuD+fIDs/omWFZ1fdguJfQVm5nC DAs= WDCIronportException: Internal Authentication-Results: usg-ed-osssrv.wdc.com (amavisd-new); dkim=pass reason="pass (just generated, assumed good)" header.d=opensource.wdc.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d= opensource.wdc.com; h=content-transfer-encoding:mime-version :references:in-reply-to:x-mailer:message-id:date:subject:to :from; s=dkim; t=1630625144; x=1633217145; bh=rShATVOyZt9SnfwqKR n0y8UZ0rHTTM6iAVUUXimZzFU=; b=fqKXGeALMC++GrKEV6SNH5k1PcBq8wzgSK qe52J4hLHa+lYYMpB032LuhnPaxOYakUAvQdtrrHJuYqcLLxcXmq0XA1iZaWlG/+ eeVXowb/y547ohCQU7j3LHt6+YQRa5ImJEdyvhihva+iLMBtTGNJfPcv15sktJCb QzkWC52MJEEUnKkEjVYlkk9u184wat3TibR0fT16kAQ9Rl4UsxgeLD8NLS+ZPDKg bHmhjlXsUL6vjKqISuoVzB2rDZo9po2uqJ+f5tiO2pCiH22UeYkg/ikmB9mFrveR v3ot6n6Tq8e3dmibAPKkESStAXhe0BjY9kfJaaQnFBFQnO8JPaMQ== X-Virus-Scanned: amavisd-new at usg-ed-osssrv.wdc.com From: Alistair Francis To: qemu-devel@nongnu.org, qemu-riscv@nongnu.org Cc: bmeng.cn@gmail.com, palmer@dabbelt.com, alistair.francis@wdc.com, alistair23@gmail.com Subject: [PATCH v2 2/2] sifive_u: Connect the SiFive PWM device Date: Fri, 3 Sep 2021 09:25:34 +1000 Message-Id: X-Mailer: git-send-email 2.31.1 In-Reply-To: References: 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: pass client-ip=216.71.154.45; envelope-from=prvs=8724dbd3c=alistair.francis@opensource.wdc.com; helo=esa6.hgst.iphmx.com X-Spam_score_int: -43 X-Spam_score: -4.4 X-Spam_bar: ---- X-Spam_report: (-4.4 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham 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: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZM-MESSAGEID: 1630625369092100001 Content-Type: text/plain; charset="utf-8" From: Alistair Francis Connect the SiFive PWM device and expose it via the device tree. Signed-off-by: Alistair Francis --- include/hw/riscv/sifive_u.h | 14 +++++++++- hw/riscv/sifive_u.c | 55 ++++++++++++++++++++++++++++++++++++- hw/timer/sifive_pwm.c | 1 + hw/riscv/Kconfig | 1 + 4 files changed, 69 insertions(+), 2 deletions(-) diff --git a/include/hw/riscv/sifive_u.h b/include/hw/riscv/sifive_u.h index 2656b39808..0d010c7309 100644 --- a/include/hw/riscv/sifive_u.h +++ b/include/hw/riscv/sifive_u.h @@ -27,6 +27,7 @@ #include "hw/misc/sifive_u_otp.h" #include "hw/misc/sifive_u_prci.h" #include "hw/ssi/sifive_spi.h" +#include "hw/timer/sifive_pwm.h" =20 #define TYPE_RISCV_U_SOC "riscv.sifive.u.soc" #define RISCV_U_SOC(obj) \ @@ -49,6 +50,7 @@ typedef struct SiFiveUSoCState { SiFiveSPIState spi0; SiFiveSPIState spi2; CadenceGEMState gem; + SiFiveUPwmState pwm[2]; =20 uint32_t serial; char *cpu_type; @@ -92,7 +94,9 @@ enum { SIFIVE_U_DEV_FLASH0, SIFIVE_U_DEV_DRAM, SIFIVE_U_DEV_GEM, - SIFIVE_U_DEV_GEM_MGMT + SIFIVE_U_DEV_GEM_MGMT, + SIFIVE_U_DEV_PWM0, + SIFIVE_U_DEV_PWM1 }; =20 enum { @@ -126,6 +130,14 @@ enum { SIFIVE_U_PDMA_IRQ5 =3D 28, SIFIVE_U_PDMA_IRQ6 =3D 29, SIFIVE_U_PDMA_IRQ7 =3D 30, + SIFIVE_U_DEV_PWM0_0 =3D 42, + SIFIVE_U_DEV_PWM0_1 =3D 43, + SIFIVE_U_DEV_PWM0_2 =3D 44, + SIFIVE_U_DEV_PWM0_3 =3D 45, + SIFIVE_U_DEV_PWM1_0 =3D 46, + SIFIVE_U_DEV_PWM1_1 =3D 47, + SIFIVE_U_DEV_PWM1_2 =3D 48, + SIFIVE_U_DEV_PWM1_3 =3D 49, SIFIVE_U_QSPI0_IRQ =3D 51, SIFIVE_U_GEM_IRQ =3D 53 }; diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index 6cc1a62b0f..ed2e75df36 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -17,6 +17,7 @@ * 7) DMA (Direct Memory Access Controller) * 8) SPI0 connected to an SPI flash * 9) SPI2 connected to an SD card + * 10) PWM0 and PWM1 * * This board currently generates devicetree dynamically that indicates at= least * two harts and up to five harts. @@ -75,6 +76,8 @@ static const MemMapEntry sifive_u_memmap[] =3D { [SIFIVE_U_DEV_PRCI] =3D { 0x10000000, 0x1000 }, [SIFIVE_U_DEV_UART0] =3D { 0x10010000, 0x1000 }, [SIFIVE_U_DEV_UART1] =3D { 0x10011000, 0x1000 }, + [SIFIVE_U_DEV_PWM0] =3D { 0x10020000, 0x1000 }, + [SIFIVE_U_DEV_PWM1] =3D { 0x10021000, 0x1000 }, [SIFIVE_U_DEV_QSPI0] =3D { 0x10040000, 0x1000 }, [SIFIVE_U_DEV_QSPI2] =3D { 0x10050000, 0x1000 }, [SIFIVE_U_DEV_GPIO] =3D { 0x10060000, 0x1000 }, @@ -441,6 +444,38 @@ static void create_fdt(SiFiveUState *s, const MemMapEn= try *memmap, qemu_fdt_setprop_cell(fdt, nodename, "reg", 0x0); g_free(nodename); =20 + nodename =3D g_strdup_printf("/soc/pwm@%lx", + (long)memmap[SIFIVE_U_DEV_PWM0].base); + qemu_fdt_add_subnode(fdt, nodename); + qemu_fdt_setprop_string(fdt, nodename, "compatible", "sifive,pwm0"); + qemu_fdt_setprop_cells(fdt, nodename, "reg", + 0x0, memmap[SIFIVE_U_DEV_PWM0].base, + 0x0, memmap[SIFIVE_U_DEV_PWM0].size); + qemu_fdt_setprop_cell(fdt, nodename, "interrupt-parent", plic_phandle); + qemu_fdt_setprop_cells(fdt, nodename, "interrupts", + SIFIVE_U_DEV_PWM0_0, SIFIVE_U_DEV_PWM0_1, + SIFIVE_U_DEV_PWM0_2, SIFIVE_U_DEV_PWM0_3); + qemu_fdt_setprop_cells(fdt, nodename, "clocks", + prci_phandle, PRCI_CLK_TLCLK); + qemu_fdt_setprop_cell(fdt, nodename, "#pwm-cells", 0); + g_free(nodename); + + nodename =3D g_strdup_printf("/soc/pwm@%lx", + (long)memmap[SIFIVE_U_DEV_PWM1].base); + qemu_fdt_add_subnode(fdt, nodename); + qemu_fdt_setprop_string(fdt, nodename, "compatible", "sifive,pwm0"); + qemu_fdt_setprop_cells(fdt, nodename, "reg", + 0x0, memmap[SIFIVE_U_DEV_PWM1].base, + 0x0, memmap[SIFIVE_U_DEV_PWM1].size); + qemu_fdt_setprop_cell(fdt, nodename, "interrupt-parent", plic_phandle); + qemu_fdt_setprop_cells(fdt, nodename, "interrupts", + SIFIVE_U_DEV_PWM1_0, SIFIVE_U_DEV_PWM1_1, + SIFIVE_U_DEV_PWM1_2, SIFIVE_U_DEV_PWM1_3); + qemu_fdt_setprop_cells(fdt, nodename, "clocks", + prci_phandle, PRCI_CLK_TLCLK); + qemu_fdt_setprop_cell(fdt, nodename, "#pwm-cells", 0); + g_free(nodename); + nodename =3D g_strdup_printf("/soc/serial@%lx", (long)memmap[SIFIVE_U_DEV_UART1].base); qemu_fdt_add_subnode(fdt, nodename); @@ -765,6 +800,8 @@ static void sifive_u_soc_instance_init(Object *obj) object_initialize_child(obj, "pdma", &s->dma, TYPE_SIFIVE_PDMA); object_initialize_child(obj, "spi0", &s->spi0, TYPE_SIFIVE_SPI); object_initialize_child(obj, "spi2", &s->spi2, TYPE_SIFIVE_SPI); + object_initialize_child(obj, "pwm0", &s->pwm[0], TYPE_SIFIVE_PWM); + object_initialize_child(obj, "pwm1", &s->pwm[1], TYPE_SIFIVE_PWM); } =20 static void sifive_u_soc_realize(DeviceState *dev, Error **errp) @@ -777,7 +814,7 @@ static void sifive_u_soc_realize(DeviceState *dev, Erro= r **errp) MemoryRegion *l2lim_mem =3D g_new(MemoryRegion, 1); char *plic_hart_config; size_t plic_hart_config_len; - int i; + int i, j; NICInfo *nd =3D &nd_table[0]; =20 qdev_prop_set_uint32(DEVICE(&s->u_cpus), "num-harts", ms->smp.cpus - 1= ); @@ -904,6 +941,22 @@ static void sifive_u_soc_realize(DeviceState *dev, Err= or **errp) sysbus_connect_irq(SYS_BUS_DEVICE(&s->gem), 0, qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_GEM_IRQ)= ); =20 + /* PWM */ + for (i =3D 0; i < 2; i++) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->pwm[i]), errp)) { + return; + } + sysbus_mmio_map(SYS_BUS_DEVICE(&s->pwm[i]), 0, + memmap[SIFIVE_U_DEV_PWM0].base + (0x1000 *= i)); + + /* Connect PWM interrupts to the PLIC */ + for (j =3D 0; j < SIFIVE_PWM_IRQS; j++) { + sysbus_connect_irq(SYS_BUS_DEVICE(&s->pwm[i]), j, + qdev_get_gpio_in(DEVICE(s->plic), + SIFIVE_U_DEV_PWM0_0 + (i * 4) + j)= ); + } + } + create_unimplemented_device("riscv.sifive.u.gem-mgmt", memmap[SIFIVE_U_DEV_GEM_MGMT].base, memmap[SIFIVE_U_DEV_GEM_MGMT].= size); =20 diff --git a/hw/timer/sifive_pwm.c b/hw/timer/sifive_pwm.c index 61a97f9b46..3b533d4484 100644 --- a/hw/timer/sifive_pwm.c +++ b/hw/timer/sifive_pwm.c @@ -25,6 +25,7 @@ */ =20 #include "qemu/osdep.h" +#include "trace.h" #include "hw/irq.h" #include "hw/timer/sifive_pwm.h" #include "hw/qdev-properties.h" diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig index ff75add6f3..d56c339ef6 100644 --- a/hw/riscv/Kconfig +++ b/hw/riscv/Kconfig @@ -69,6 +69,7 @@ config SIFIVE_U select SIFIVE_UART select SIFIVE_U_OTP select SIFIVE_U_PRCI + select SIFIVE_PWM select SSI_M25P80 select SSI_SD select UNIMP --=20 2.31.1