From nobody Wed Nov 5 02:34:09 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=linaro.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1532971268552618.8140272679486; Mon, 30 Jul 2018 10:21:08 -0700 (PDT) Received: from localhost ([::1]:53725 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fkBGR-0008SO-LQ for importer@patchew.org; Mon, 30 Jul 2018 12:43:19 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:37459) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fkAyr-0001NT-DU for qemu-devel@nongnu.org; Mon, 30 Jul 2018 12:25:10 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fkAyp-0001Ds-Tk for qemu-devel@nongnu.org; Mon, 30 Jul 2018 12:25:09 -0400 Received: from orth.archaic.org.uk ([2001:8b0:1d0::2]:43834) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fkAyn-0001Ab-7C; Mon, 30 Jul 2018 12:25:05 -0400 Received: from pm215 by orth.archaic.org.uk with local (Exim 4.89) (envelope-from ) id 1fkAyh-0004KN-SZ; Mon, 30 Jul 2018 17:24:59 +0100 From: Peter Maydell To: qemu-arm@nongnu.org, qemu-devel@nongnu.org Date: Mon, 30 Jul 2018 17:24:54 +0100 Message-Id: <20180730162458.23186-2-peter.maydell@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20180730162458.23186-1-peter.maydell@linaro.org> References: <20180730162458.23186-1-peter.maydell@linaro.org> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2001:8b0:1d0::2 Subject: [Qemu-devel] [PATCH 1/5] hw/misc/mps2-fpgaio: Implement 1Hz and 100Hz counters X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: patches@linaro.org Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" The MPS2 FPGAIO block includes some simple free-running counters. Implement these. Signed-off-by: Peter Maydell --- include/hw/misc/mps2-fpgaio.h | 4 +++ hw/misc/mps2-fpgaio.c | 53 ++++++++++++++++++++++++++++++++++- 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/include/hw/misc/mps2-fpgaio.h b/include/hw/misc/mps2-fpgaio.h index eedf17ebc6d..ec057d38c76 100644 --- a/include/hw/misc/mps2-fpgaio.h +++ b/include/hw/misc/mps2-fpgaio.h @@ -38,6 +38,10 @@ typedef struct { uint32_t misc; =20 uint32_t prescale_clk; + + /* These hold the CLOCK_VIRTUAL ns tick when the CLK1HZ/CLK100HZ was z= ero */ + int64_t clk1hz_tick_offset; + int64_t clk100hz_tick_offset; } MPS2FPGAIO; =20 #endif diff --git a/hw/misc/mps2-fpgaio.c b/hw/misc/mps2-fpgaio.c index 7394a057d82..bbc28f641f0 100644 --- a/hw/misc/mps2-fpgaio.c +++ b/hw/misc/mps2-fpgaio.c @@ -22,6 +22,7 @@ #include "hw/sysbus.h" #include "hw/registerfields.h" #include "hw/misc/mps2-fpgaio.h" +#include "qemu/timer.h" =20 REG32(LED0, 0) REG32(BUTTON, 8) @@ -32,10 +33,21 @@ REG32(PRESCALE, 0x1c) REG32(PSCNTR, 0x20) REG32(MISC, 0x4c) =20 +static uint32_t counter_from_tickoff(int64_t now, int64_t tick_offset, int= frq) +{ + return muldiv64(now - tick_offset, frq, NANOSECONDS_PER_SECOND); +} + +static int64_t tickoff_from_counter(int64_t now, uint32_t count, int frq) +{ + return now - muldiv64(count, NANOSECONDS_PER_SECOND, frq); +} + static uint64_t mps2_fpgaio_read(void *opaque, hwaddr offset, unsigned siz= e) { MPS2FPGAIO *s =3D MPS2_FPGAIO(opaque); uint64_t r; + int64_t now; =20 switch (offset) { case A_LED0: @@ -54,10 +66,15 @@ static uint64_t mps2_fpgaio_read(void *opaque, hwaddr o= ffset, unsigned size) r =3D s->misc; break; case A_CLK1HZ: + now =3D qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + r =3D counter_from_tickoff(now, s->clk1hz_tick_offset, 1); + break; case A_CLK100HZ: + now =3D qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + r =3D counter_from_tickoff(now, s->clk100hz_tick_offset, 100); + break; case A_COUNTER: case A_PSCNTR: - /* These are all upcounters of various frequencies. */ qemu_log_mask(LOG_UNIMP, "MPS2 FPGAIO: counters unimplemented\n"); r =3D 0; break; @@ -76,6 +93,7 @@ static void mps2_fpgaio_write(void *opaque, hwaddr offset= , uint64_t value, unsigned size) { MPS2FPGAIO *s =3D MPS2_FPGAIO(opaque); + int64_t now; =20 trace_mps2_fpgaio_write(offset, value, size); =20 @@ -100,6 +118,14 @@ static void mps2_fpgaio_write(void *opaque, hwaddr off= set, uint64_t value, "MPS2 FPGAIO: MISC control bits unimplemented\n"); s->misc =3D value; break; + case A_CLK1HZ: + now =3D qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + s->clk1hz_tick_offset =3D tickoff_from_counter(now, value, 1); + break; + case A_CLK100HZ: + now =3D qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + s->clk100hz_tick_offset =3D tickoff_from_counter(now, value, 100); + break; default: qemu_log_mask(LOG_GUEST_ERROR, "MPS2 FPGAIO write: bad offset 0x%x\n", (int) offset= ); @@ -116,11 +142,14 @@ static const MemoryRegionOps mps2_fpgaio_ops =3D { static void mps2_fpgaio_reset(DeviceState *dev) { MPS2FPGAIO *s =3D MPS2_FPGAIO(dev); + int64_t now =3D qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); =20 trace_mps2_fpgaio_reset(); s->led0 =3D 0; s->prescale =3D 0; s->misc =3D 0; + s->clk1hz_tick_offset =3D tickoff_from_counter(now, 0, 1); + s->clk100hz_tick_offset =3D tickoff_from_counter(now, 0, 100); } =20 static void mps2_fpgaio_init(Object *obj) @@ -133,6 +162,24 @@ static void mps2_fpgaio_init(Object *obj) sysbus_init_mmio(sbd, &s->iomem); } =20 +static bool mps2_fpgaio_counters_needed(void *opaque) +{ + /* Currently vmstate.c insists all subsections have a 'needed' functio= n */ + return true; +} + +static const VMStateDescription mps2_fpgaio_counters_vmstate =3D { + .name =3D "mps2-fpgaio/counters", + .version_id =3D 1, + .minimum_version_id =3D 1, + .needed =3D mps2_fpgaio_counters_needed, + .fields =3D (VMStateField[]) { + VMSTATE_INT64(clk1hz_tick_offset, MPS2FPGAIO), + VMSTATE_INT64(clk100hz_tick_offset, MPS2FPGAIO), + VMSTATE_END_OF_LIST() + } +}; + static const VMStateDescription mps2_fpgaio_vmstate =3D { .name =3D "mps2-fpgaio", .version_id =3D 1, @@ -142,6 +189,10 @@ static const VMStateDescription mps2_fpgaio_vmstate = =3D { VMSTATE_UINT32(prescale, MPS2FPGAIO), VMSTATE_UINT32(misc, MPS2FPGAIO), VMSTATE_END_OF_LIST() + }, + .subsections =3D (const VMStateDescription*[]) { + &mps2_fpgaio_counters_vmstate, + NULL } }; =20 --=20 2.17.1 From nobody Wed Nov 5 02:34:09 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=linaro.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1532970972928718.507918017163; Mon, 30 Jul 2018 10:16:12 -0700 (PDT) Received: from localhost ([::1]:53831 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fkBY8-0007mL-Db for importer@patchew.org; Mon, 30 Jul 2018 13:01:36 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:37455) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fkAyr-0001N8-3q for qemu-devel@nongnu.org; Mon, 30 Jul 2018 12:25:10 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fkAyp-0001Di-Lx for qemu-devel@nongnu.org; Mon, 30 Jul 2018 12:25:09 -0400 Received: from orth.archaic.org.uk ([2001:8b0:1d0::2]:43834) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fkAym-0001Ab-8B; Mon, 30 Jul 2018 12:25:04 -0400 Received: from pm215 by orth.archaic.org.uk with local (Exim 4.89) (envelope-from ) id 1fkAyi-0004Ke-Hj; Mon, 30 Jul 2018 17:25:00 +0100 From: Peter Maydell To: qemu-arm@nongnu.org, qemu-devel@nongnu.org Date: Mon, 30 Jul 2018 17:24:55 +0100 Message-Id: <20180730162458.23186-3-peter.maydell@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20180730162458.23186-1-peter.maydell@linaro.org> References: <20180730162458.23186-1-peter.maydell@linaro.org> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2001:8b0:1d0::2 Subject: [Qemu-devel] [PATCH 2/5] hw/misc/mps2-fpgaio: Implement PSCNTR and COUNTER X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: patches@linaro.org Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" In the MPS2 FPGAIO, PSCNTR is a free-running downcounter with a reload value configured via the PRESCALE register, and COUNTER counts up by 1 every time PSCNTR reaches zero. Implement these counters. We can just increment the counters migration subsection's version ID because we only added it in the previous commit, so no released QEMU versions will be using it. Signed-off-by: Peter Maydell Reviewed-by: Alistair Francis --- include/hw/misc/mps2-fpgaio.h | 6 +++ hw/misc/mps2-fpgaio.c | 97 +++++++++++++++++++++++++++++++++-- 2 files changed, 99 insertions(+), 4 deletions(-) diff --git a/include/hw/misc/mps2-fpgaio.h b/include/hw/misc/mps2-fpgaio.h index ec057d38c76..69e265cd4b2 100644 --- a/include/hw/misc/mps2-fpgaio.h +++ b/include/hw/misc/mps2-fpgaio.h @@ -37,6 +37,12 @@ typedef struct { uint32_t prescale; uint32_t misc; =20 + /* QEMU_CLOCK_VIRTUAL time at which counter and pscntr were last synce= d */ + int64_t pscntr_sync_ticks; + /* Values of COUNTER and PSCNTR at time pscntr_sync_ticks */ + uint32_t counter; + uint32_t pscntr; + uint32_t prescale_clk; =20 /* These hold the CLOCK_VIRTUAL ns tick when the CLK1HZ/CLK100HZ was z= ero */ diff --git a/hw/misc/mps2-fpgaio.c b/hw/misc/mps2-fpgaio.c index bbc28f641f0..5cf10ebd66a 100644 --- a/hw/misc/mps2-fpgaio.c +++ b/hw/misc/mps2-fpgaio.c @@ -43,6 +43,77 @@ static int64_t tickoff_from_counter(int64_t now, uint32_= t count, int frq) return now - muldiv64(count, NANOSECONDS_PER_SECOND, frq); } =20 +static void resync_counter(MPS2FPGAIO *s) +{ + /* + * Update s->counter and s->pscntr to their true current values + * by calculating how many times PSCNTR has ticked since the + * last time we did a resync. + */ + int64_t now =3D qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + int64_t elapsed =3D now - s->pscntr_sync_ticks; + + /* + * Round elapsed down to a whole number of PSCNTR ticks, so we don't + * lose time if we do multiple resyncs in a single tick. + */ + uint64_t ticks =3D muldiv64(elapsed, s->prescale_clk, NANOSECONDS_PER_= SECOND); + + /* + * Work out what PSCNTR and COUNTER have moved to. We assume that + * PSCNTR reloads from PRESCALE one tick-period after it hits zero, + * and that COUNTER increments at the same moment. + */ + if (ticks =3D=3D 0) { + /* We haven't ticked since the last time we were asked */ + return; + } else if (ticks < s->pscntr) { + /* We haven't yet reached zero, just reduce the PSCNTR */ + s->pscntr -=3D ticks; + } else { + if (s->prescale =3D=3D 0) { + /* + * If the reload value is zero then the PSCNTR will stick + * at zero once it reaches it, and so we will increment + * COUNTER every tick after that. + */ + s->counter +=3D ticks - s->pscntr; + s->pscntr =3D 0; + } else { + /* + * This is the complicated bit. This ASCII art diagram gives an + * example with PRESCALE=3D=3D5 PSCNTR=3D=3D7: + * + * ticks 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 + * PSCNTR 7 6 5 4 3 2 1 0 5 4 3 2 1 0 5 + * cinc 1 2 + * y 0 1 2 3 4 5 6 7 8 9 10 11 12 + * x 0 1 2 3 4 5 0 1 2 3 4 5 0 + * + * where x =3D y % (s->prescale + 1) + * and so PSCNTR =3D s->prescale - x + * and COUNTER is incremented by y / (s->prescale + 1) + * + * The case where PSCNTR < PRESCALE works out the same, + * though we must be careful to calculate y as 64-bit unsigned + * for all parts of the expression. + * y < 0 is not possible because that implies ticks < s->pscnt= r. + */ + uint64_t y =3D ticks - s->pscntr + s->prescale; + s->pscntr =3D s->prescale - (y % (s->prescale + 1)); + s->counter +=3D y / (s->prescale + 1); + } + } + + /* + * Only advance the sync time to the timestamp of the last PSCNTR tick, + * not all the way to 'now', so we don't lose time if we do multiple + * resyncs in a single tick. + */ + s->pscntr_sync_ticks +=3D muldiv64(ticks, NANOSECONDS_PER_SECOND, + s->prescale_clk); +} + static uint64_t mps2_fpgaio_read(void *opaque, hwaddr offset, unsigned siz= e) { MPS2FPGAIO *s =3D MPS2_FPGAIO(opaque); @@ -74,9 +145,12 @@ static uint64_t mps2_fpgaio_read(void *opaque, hwaddr o= ffset, unsigned size) r =3D counter_from_tickoff(now, s->clk100hz_tick_offset, 100); break; case A_COUNTER: + resync_counter(s); + r =3D s->counter; + break; case A_PSCNTR: - qemu_log_mask(LOG_UNIMP, "MPS2 FPGAIO: counters unimplemented\n"); - r =3D 0; + resync_counter(s); + r =3D s->pscntr; break; default: qemu_log_mask(LOG_GUEST_ERROR, @@ -107,6 +181,7 @@ static void mps2_fpgaio_write(void *opaque, hwaddr offs= et, uint64_t value, s->led0 =3D value & 0x3; break; case A_PRESCALE: + resync_counter(s); s->prescale =3D value; break; case A_MISC: @@ -126,6 +201,14 @@ static void mps2_fpgaio_write(void *opaque, hwaddr off= set, uint64_t value, now =3D qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); s->clk100hz_tick_offset =3D tickoff_from_counter(now, value, 100); break; + case A_COUNTER: + resync_counter(s); + s->counter =3D value; + break; + case A_PSCNTR: + resync_counter(s); + s->pscntr =3D value; + break; default: qemu_log_mask(LOG_GUEST_ERROR, "MPS2 FPGAIO write: bad offset 0x%x\n", (int) offset= ); @@ -150,6 +233,9 @@ static void mps2_fpgaio_reset(DeviceState *dev) s->misc =3D 0; s->clk1hz_tick_offset =3D tickoff_from_counter(now, 0, 1); s->clk100hz_tick_offset =3D tickoff_from_counter(now, 0, 100); + s->counter =3D 0; + s->pscntr =3D 0; + s->pscntr_sync_ticks =3D now; } =20 static void mps2_fpgaio_init(Object *obj) @@ -170,12 +256,15 @@ static bool mps2_fpgaio_counters_needed(void *opaque) =20 static const VMStateDescription mps2_fpgaio_counters_vmstate =3D { .name =3D "mps2-fpgaio/counters", - .version_id =3D 1, - .minimum_version_id =3D 1, + .version_id =3D 2, + .minimum_version_id =3D 2, .needed =3D mps2_fpgaio_counters_needed, .fields =3D (VMStateField[]) { VMSTATE_INT64(clk1hz_tick_offset, MPS2FPGAIO), VMSTATE_INT64(clk100hz_tick_offset, MPS2FPGAIO), + VMSTATE_UINT32(counter, MPS2FPGAIO), + VMSTATE_UINT32(pscntr, MPS2FPGAIO), + VMSTATE_INT64(pscntr_sync_ticks, MPS2FPGAIO), VMSTATE_END_OF_LIST() } }; --=20 2.17.1 From nobody Wed Nov 5 02:34:09 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=linaro.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1532971238697530.548393191572; Mon, 30 Jul 2018 10:20:38 -0700 (PDT) Received: from localhost ([::1]:53745 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fkBJF-0002pN-Bd for importer@patchew.org; Mon, 30 Jul 2018 12:46:14 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:37497) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fkAyu-0001Sh-9U for qemu-devel@nongnu.org; Mon, 30 Jul 2018 12:25:15 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fkAyr-0001H0-JT for qemu-devel@nongnu.org; Mon, 30 Jul 2018 12:25:12 -0400 Received: from orth.archaic.org.uk ([2001:8b0:1d0::2]:43826) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fkAyk-00019i-Ow; Mon, 30 Jul 2018 12:25:03 -0400 Received: from pm215 by orth.archaic.org.uk with local (Exim 4.89) (envelope-from ) id 1fkAyj-0004Kt-6U; Mon, 30 Jul 2018 17:25:01 +0100 From: Peter Maydell To: qemu-arm@nongnu.org, qemu-devel@nongnu.org Date: Mon, 30 Jul 2018 17:24:56 +0100 Message-Id: <20180730162458.23186-4-peter.maydell@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20180730162458.23186-1-peter.maydell@linaro.org> References: <20180730162458.23186-1-peter.maydell@linaro.org> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2001:8b0:1d0::2 Subject: [Qemu-devel] [PATCH 3/5] hw/timer/cmsdk-apb-dualtimer: Implement CMSDK dual timer module X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: patches@linaro.org Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" The Arm Cortex-M System Design Kit includes a "dual-input timer module" which combines two programmable down-counters. Implement a model of this device. Signed-off-by: Peter Maydell --- hw/timer/Makefile.objs | 1 + include/hw/timer/cmsdk-apb-dualtimer.h | 72 ++++ hw/timer/cmsdk-apb-dualtimer.c | 515 +++++++++++++++++++++++++ MAINTAINERS | 2 + default-configs/arm-softmmu.mak | 1 + hw/timer/trace-events | 5 + 6 files changed, 596 insertions(+) create mode 100644 include/hw/timer/cmsdk-apb-dualtimer.h create mode 100644 hw/timer/cmsdk-apb-dualtimer.c diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs index e16b2b913ce..b32194d153d 100644 --- a/hw/timer/Makefile.objs +++ b/hw/timer/Makefile.objs @@ -44,4 +44,5 @@ common-obj-$(CONFIG_ASPEED_SOC) +=3D aspeed_timer.o =20 common-obj-$(CONFIG_SUN4V_RTC) +=3D sun4v-rtc.o common-obj-$(CONFIG_CMSDK_APB_TIMER) +=3D cmsdk-apb-timer.o +common-obj-$(CONFIG_CMSDK_APB_DUALTIMER) +=3D cmsdk-apb-dualtimer.o common-obj-$(CONFIG_MSF2) +=3D mss-timer.o diff --git a/include/hw/timer/cmsdk-apb-dualtimer.h b/include/hw/timer/cmsd= k-apb-dualtimer.h new file mode 100644 index 00000000000..9843a9dbb1d --- /dev/null +++ b/include/hw/timer/cmsdk-apb-dualtimer.h @@ -0,0 +1,72 @@ +/* + * ARM CMSDK APB dual-timer emulation + * + * Copyright (c) 2018 Linaro Limited + * Written by Peter Maydell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ + +/* + * This is a model of the "APB dual-input timer" which is part of the Cort= ex-M + * System Design Kit (CMSDK) and documented in the Cortex-M System + * Design Kit Technical Reference Manual (ARM DDI0479C): + * https://developer.arm.com/products/system-design/system-design-kits/cor= tex-m-system-design-kit + * + * QEMU interface: + * + QOM property "pclk-frq": frequency at which the timer is clocked + * + sysbus MMIO region 0: the register bank + * + sysbus IRQ 0: combined timer interrupt TIMINTC + * + sysbus IRO 1: timer block 1 interrupt TIMINT1 + * + sysbus IRQ 2: timer block 2 interrupt TIMINT2 + */ + +#ifndef CMSDK_APB_DUALTIMER_H +#define CMSDK_APB_DUALTIMER_H + +#include "hw/sysbus.h" +#include "hw/ptimer.h" + +#define TYPE_CMSDK_APB_DUALTIMER "cmsdk-apb-dualtimer" +#define CMSDK_APB_DUALTIMER(obj) OBJECT_CHECK(CMSDKAPBDualTimer, (obj), \ + TYPE_CMSDK_APB_DUALTIMER) + +typedef struct CMSDKAPBDualTimer CMSDKAPBDualTimer; + +/* One of the two identical timer modules in the dual-timer module */ +typedef struct CMSDKAPBDualTimerModule { + CMSDKAPBDualTimer *parent; + struct ptimer_state *timer; + qemu_irq timerint; + /* + * We must track the guest LOAD and VALUE register state by hand + * rather than leaving this state only in the ptimer limit/count, + * because if CONTROL.SIZE is 0 then only the low 16 bits of the + * counter actually counts, but the high half is still guest + * accessible. + */ + uint32_t load; + uint32_t value; + uint32_t control; + uint32_t intstatus; +} CMSDKAPBDualTimerModule; + +#define CMSDK_APB_DUALTIMER_NUM_MODULES 2 + +struct CMSDKAPBDualTimer { + /*< private >*/ + SysBusDevice parent_obj; + + /*< public >*/ + MemoryRegion iomem; + qemu_irq timerintc; + uint32_t pclk_frq; + + CMSDKAPBDualTimerModule timermod[CMSDK_APB_DUALTIMER_NUM_MODULES]; + uint32_t timeritcr; + uint32_t timeritop; +}; + +#endif diff --git a/hw/timer/cmsdk-apb-dualtimer.c b/hw/timer/cmsdk-apb-dualtimer.c new file mode 100644 index 00000000000..4b005e28136 --- /dev/null +++ b/hw/timer/cmsdk-apb-dualtimer.c @@ -0,0 +1,515 @@ +/* + * ARM CMSDK APB dual-timer emulation + * + * Copyright (c) 2018 Linaro Limited + * Written by Peter Maydell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ + +/* + * This is a model of the "APB dual-input timer" which is part of the Cort= ex-M + * System Design Kit (CMSDK) and documented in the Cortex-M System + * Design Kit Technical Reference Manual (ARM DDI0479C): + * https://developer.arm.com/products/system-design/system-design-kits/cor= tex-m-system-design-kit + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "trace.h" +#include "qapi/error.h" +#include "qemu/main-loop.h" +#include "hw/sysbus.h" +#include "hw/registerfields.h" +#include "hw/timer/cmsdk-apb-dualtimer.h" + +REG32(TIMER1LOAD, 0x0) +REG32(TIMER1VALUE, 0x4) +REG32(TIMER1CONTROL, 0x8) + FIELD(CONTROL, ONESHOT, 0, 1) + FIELD(CONTROL, SIZE, 1, 1) + FIELD(CONTROL, PRESCALE, 2, 2) + FIELD(CONTROL, INTEN, 5, 1) + FIELD(CONTROL, MODE, 6, 1) + FIELD(CONTROL, ENABLE, 7, 1) +#define R_CONTROL_VALID_MASK (R_CONTROL_ONESHOT_MASK | R_CONTROL_SIZE_MASK= | \ + R_CONTROL_PRESCALE_MASK | R_CONTROL_INTEN_MA= SK | \ + R_CONTROL_MODE_MASK | R_CONTROL_ENABLE_MASK) +REG32(TIMER1INTCLR, 0xc) +REG32(TIMER1RIS, 0x10) +REG32(TIMER1MIS, 0x14) +REG32(TIMER1BGLOAD, 0x18) +REG32(TIMER2LOAD, 0x20) +REG32(TIMER2VALUE, 0x24) +REG32(TIMER2CONTROL, 0x28) +REG32(TIMER2INTCLR, 0x2c) +REG32(TIMER2RIS, 0x30) +REG32(TIMER2MIS, 0x34) +REG32(TIMER2BGLOAD, 0x38) +REG32(TIMERITCR, 0xf00) + FIELD(TIMERITCR, ENABLE, 0, 1) +#define R_TIMERITCR_VALID_MASK R_TIMERITCR_ENABLE_MASK +REG32(TIMERITOP, 0xf04) + FIELD(TIMERITOP, TIMINT1, 0, 1) + FIELD(TIMERITOP, TIMINT2, 1, 1) +#define R_TIMERITOP_VALID_MASK (R_TIMERITOP_TIMINT1_MASK | \ + R_TIMERITOP_TIMINT2_MASK) +REG32(PID4, 0xfd0) +REG32(PID5, 0xfd4) +REG32(PID6, 0xfd8) +REG32(PID7, 0xfdc) +REG32(PID0, 0xfe0) +REG32(PID1, 0xfe4) +REG32(PID2, 0xfe8) +REG32(PID3, 0xfec) +REG32(CID0, 0xff0) +REG32(CID1, 0xff4) +REG32(CID2, 0xff8) +REG32(CID3, 0xffc) + +/* PID/CID values */ +static const int timer_id[] =3D { + 0x04, 0x00, 0x00, 0x00, /* PID4..PID7 */ + 0x23, 0xb8, 0x1b, 0x00, /* PID0..PID3 */ + 0x0d, 0xf0, 0x05, 0xb1, /* CID0..CID3 */ +}; + +static bool cmsdk_dualtimermod_intstatus(CMSDKAPBDualTimerModule *m) +{ + /* Return masked interrupt status for the timer module */ + return m->intstatus && (m->control & R_CONTROL_INTEN_MASK); +} + +static void cmsdk_apb_dualtimer_update(CMSDKAPBDualTimer *s) +{ + bool timint1, timint2, timintc; + + if (s->timeritcr) { + /* Integration test mode: outputs driven directly from TIMERITOP b= its */ + timint1 =3D s->timeritop & R_TIMERITOP_TIMINT1_MASK; + timint2 =3D s->timeritop & R_TIMERITOP_TIMINT2_MASK; + } else { + timint1 =3D cmsdk_dualtimermod_intstatus(&s->timermod[0]); + timint2 =3D cmsdk_dualtimermod_intstatus(&s->timermod[1]); + } + + timintc =3D timint1 || timint2; + + qemu_set_irq(s->timermod[0].timerint, timint1); + qemu_set_irq(s->timermod[1].timerint, timint2); + qemu_set_irq(s->timerintc, timintc); +} + +static void cmsdk_dualtimermod_write_control(CMSDKAPBDualTimerModule *m, + uint32_t newctrl) +{ + /* Handle a write to the CONTROL register */ + uint32_t changed; + + newctrl &=3D R_CONTROL_VALID_MASK; + + changed =3D m->control ^ newctrl; + + if (changed & ~newctrl & R_CONTROL_ENABLE_MASK) { + /* ENABLE cleared, stop timer before any further changes */ + ptimer_stop(m->timer); + } + + if (changed & R_CONTROL_PRESCALE_MASK) { + int divisor; + + switch (FIELD_EX32(newctrl, CONTROL, PRESCALE)) { + case 0: + divisor =3D 1; + break; + case 1: + divisor =3D 16; + break; + case 2: + divisor =3D 256; + break; + case 3: + /* UNDEFINED; complain, and arbitrarily treat like 2 */ + qemu_log_mask(LOG_GUEST_ERROR, + "CMSDK APB dual-timer: CONTROL.PRESCALE=3D=3D0b1= 1" + " is undefined behaviour\n"); + divisor =3D 256; + break; + default: + g_assert_not_reached(); + } + ptimer_set_freq(m->timer, m->parent->pclk_frq / divisor); + } + + if (changed & R_CONTROL_MODE_MASK) { + uint32_t load; + if (newctrl & R_CONTROL_MODE_MASK) { + /* Periodic: the limit is the LOAD register value */ + load =3D m->load; + } else { + /* Free-running: counter wraps around */ + load =3D ptimer_get_limit(m->timer); + if (!(m->control & R_CONTROL_SIZE_MASK)) { + load =3D deposit32(load, 16, 16, extract32(m->load, 16, 16= )); + } + m->load =3D load; + load =3D 0xffffffff; + } + if (!(m->control & R_CONTROL_SIZE_MASK)) { + load &=3D 0xffff; + } + ptimer_set_limit(m->timer, load, 0); + } + + if (changed & R_CONTROL_SIZE_MASK) { + /* Timer switched between 16 and 32 bit count */ + uint32_t value, load; + + value =3D ptimer_get_count(m->timer); + load =3D ptimer_get_limit(m->timer); + if (newctrl & R_CONTROL_SIZE_MASK) { + /* 16 -> 32, top half of VALUE is in struct field */ + value =3D deposit32(value, 16, 16, extract32(m->value, 16, 16)= ); + } else { + /* 32 -> 16: save top half to struct field and truncate */ + m->value =3D value; + value &=3D 0xffff; + } + + if (newctrl & R_CONTROL_MODE_MASK) { + /* Periodic, timer limit has LOAD value */ + if (newctrl & R_CONTROL_SIZE_MASK) { + load =3D deposit32(load, 16, 16, extract32(m->load, 16, 16= )); + } else { + m->load =3D load; + load &=3D 0xffff; + } + } else { + /* Free-running, timer limit is set to give wraparound */ + if (newctrl & R_CONTROL_SIZE_MASK) { + load =3D 0xffffffff; + } else { + load =3D 0xffff; + } + } + ptimer_set_count(m->timer, value); + ptimer_set_limit(m->timer, load, 0); + } + + if (newctrl & R_CONTROL_ENABLE_MASK) { + /* + * ENABLE is set; start the timer after all other changes. + * We start it even if the ENABLE bit didn't actually change, + * in case the timer was an expired one-shot timer that has + * now been changed into a free-running or periodic timer. + */ + ptimer_run(m->timer, !!(newctrl & R_CONTROL_ONESHOT_MASK)); + } + + m->control =3D newctrl; +} + +static uint64_t cmsdk_apb_dualtimer_read(void *opaque, hwaddr offset, + unsigned size) +{ + CMSDKAPBDualTimer *s =3D CMSDK_APB_DUALTIMER(opaque); + uint64_t r; + + if (offset >=3D A_TIMERITCR) { + switch (offset) { + case A_TIMERITCR: + r =3D s->timeritcr; + break; + case A_PID4 ... A_CID3: + r =3D timer_id[(offset - A_PID4) / 4]; + break; + default: + bad_offset: + qemu_log_mask(LOG_GUEST_ERROR, + "CMSDK APB dual-timer read: bad offset %x\n", + (int) offset); + r =3D 0; + break; + } + } else { + int timer =3D offset >> 5; + CMSDKAPBDualTimerModule *m; + + if (timer >=3D ARRAY_SIZE(s->timermod)) { + goto bad_offset; + } + + m =3D &s->timermod[timer]; + + switch (offset & 0x1F) { + case A_TIMER1LOAD: + case A_TIMER1BGLOAD: + if (m->control & R_CONTROL_MODE_MASK) { + /* + * Periodic: the ptimer limit is the LOAD register value, = (or + * just the low 16 bits of it if the timer is in 16-bit mo= de) + */ + r =3D ptimer_get_limit(m->timer); + if (!(m->control & R_CONTROL_SIZE_MASK)) { + r =3D deposit32(r, 16, 16, extract32(m->load, 16, 16)); + } + } else { + /* Free-running: LOAD register value is just in m->load */ + r =3D m->load; + } + break; + case A_TIMER1VALUE: + r =3D ptimer_get_count(m->timer); + if (!(m->control & R_CONTROL_SIZE_MASK)) { + r =3D deposit32(r, 16, 16, extract32(m->value, 16, 16)); + } + break; + case A_TIMER1CONTROL: + r =3D m->control; + break; + case A_TIMER1RIS: + r =3D m->intstatus; + break; + case A_TIMER1MIS: + r =3D cmsdk_dualtimermod_intstatus(m); + break; + default: + goto bad_offset; + } + } + + trace_cmsdk_apb_dualtimer_read(offset, r, size); + return r; +} + +static void cmsdk_apb_dualtimer_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + CMSDKAPBDualTimer *s =3D CMSDK_APB_DUALTIMER(opaque); + + trace_cmsdk_apb_dualtimer_write(offset, value, size); + + if (offset >=3D A_TIMERITCR) { + switch (offset) { + case A_TIMERITCR: + s->timeritcr =3D value & R_TIMERITCR_VALID_MASK; + cmsdk_apb_dualtimer_update(s); + case A_TIMERITOP: + s->timeritop =3D value & R_TIMERITOP_VALID_MASK; + cmsdk_apb_dualtimer_update(s); + default: + bad_offset: + qemu_log_mask(LOG_GUEST_ERROR, + "CMSDK APB dual-timer write: bad offset %x\n", + (int) offset); + break; + } + } else { + int timer =3D offset >> 5; + CMSDKAPBDualTimerModule *m; + + if (timer >=3D ARRAY_SIZE(s->timermod)) { + goto bad_offset; + } + + m =3D &s->timermod[timer]; + + switch (offset & 0x1F) { + case A_TIMER1LOAD: + /* Set the limit, and immediately reload the count from it */ + m->load =3D value; + m->value =3D value; + if (!(m->control & R_CONTROL_SIZE_MASK)) { + value &=3D 0xffff; + } + if (!(m->control & R_CONTROL_MODE_MASK)) { + /* + * In free-running mode this won't set the limit but will + * still change the current count value. + */ + ptimer_set_count(m->timer, value); + } else { + if (!value) { + ptimer_stop(m->timer); + } + ptimer_set_limit(m->timer, value, 1); + if (value && (m->control & R_CONTROL_ENABLE_MASK)) { + /* Force possibly-expired oneshot timer to restart */ + ptimer_run(m->timer, 1); + } + } + break; + case A_TIMER1BGLOAD: + /* Set the limit, but not the current count */ + m->load =3D value; + if (!(m->control & R_CONTROL_MODE_MASK)) { + /* In free-running mode there is no limit */ + break; + } + if (!(m->control & R_CONTROL_SIZE_MASK)) { + value &=3D 0xffff; + } + ptimer_set_limit(m->timer, value, 0); + break; + case A_TIMER1CONTROL: + cmsdk_dualtimermod_write_control(m, value); + cmsdk_apb_dualtimer_update(s); + break; + case A_TIMER1INTCLR: + m->intstatus =3D 0; + cmsdk_apb_dualtimer_update(s); + break; + default: + goto bad_offset; + } + } +} + +static const MemoryRegionOps cmsdk_apb_dualtimer_ops =3D { + .read =3D cmsdk_apb_dualtimer_read, + .write =3D cmsdk_apb_dualtimer_write, + .endianness =3D DEVICE_LITTLE_ENDIAN, + /* byte/halfword accesses are just zero-padded on reads and writes */ + .impl.min_access_size =3D 4, + .impl.max_access_size =3D 4, + .valid.min_access_size =3D 1, + .valid.max_access_size =3D 4, +}; + +static void cmsdk_dualtimermod_tick(void *opaque) +{ + CMSDKAPBDualTimerModule *m =3D opaque; + + m->intstatus =3D 1; + cmsdk_apb_dualtimer_update(m->parent); +} + +static void cmsdk_dualtimermod_reset(CMSDKAPBDualTimerModule *m) +{ + m->control =3D R_CONTROL_INTEN_MASK; + m->intstatus =3D 0; + m->load =3D 0; + m->value =3D 0xffffffff; + ptimer_stop(m->timer); + /* + * We start in free-running mode, with VALUE at 0xffffffff, and + * in 16-bit counter mode. This means that the ptimer count and + * limit must both be set to 0xffff, so we wrap at 16 bits. + */ + ptimer_set_limit(m->timer, 0xffff, 1); + ptimer_set_freq(m->timer, m->parent->pclk_frq); +} + +static void cmsdk_apb_dualtimer_reset(DeviceState *dev) +{ + CMSDKAPBDualTimer *s =3D CMSDK_APB_DUALTIMER(dev); + int i; + + trace_cmsdk_apb_dualtimer_reset(); + + for (i =3D 0; i < ARRAY_SIZE(s->timermod); i++) { + cmsdk_dualtimermod_reset(&s->timermod[i]); + } + s->timeritcr =3D 0; + s->timeritop =3D 0; +} + +static void cmsdk_apb_dualtimer_init(Object *obj) +{ + SysBusDevice *sbd =3D SYS_BUS_DEVICE(obj); + CMSDKAPBDualTimer *s =3D CMSDK_APB_DUALTIMER(obj); + int i; + + memory_region_init_io(&s->iomem, obj, &cmsdk_apb_dualtimer_ops, + s, "cmsdk-apb-dualtimer", 0x1000); + sysbus_init_mmio(sbd, &s->iomem); + sysbus_init_irq(sbd, &s->timerintc); + + for (i =3D 0; i < ARRAY_SIZE(s->timermod); i++) { + sysbus_init_irq(sbd, &s->timermod[i].timerint); + } +} + +static void cmsdk_apb_dualtimer_realize(DeviceState *dev, Error **errp) +{ + CMSDKAPBDualTimer *s =3D CMSDK_APB_DUALTIMER(dev); + int i; + + if (s->pclk_frq =3D=3D 0) { + error_setg(errp, "CMSDK APB timer: pclk-frq property must be set"); + return; + } + + for (i =3D 0; i < ARRAY_SIZE(s->timermod); i++) { + CMSDKAPBDualTimerModule *m =3D &s->timermod[i]; + QEMUBH *bh =3D qemu_bh_new(cmsdk_dualtimermod_tick, m); + + m->parent =3D s; + m->timer =3D ptimer_init(bh, + PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD | + PTIMER_POLICY_TRIGGER_ONLY_ON_DECREMENT | + PTIMER_POLICY_NO_IMMEDIATE_RELOAD | + PTIMER_POLICY_NO_COUNTER_ROUND_DOWN); + } +} + +static const VMStateDescription cmsdk_dualtimermod_vmstate =3D { + .name =3D "cmsdk-apb-dualtimer-module", + .version_id =3D 1, + .minimum_version_id =3D 1, + .fields =3D (VMStateField[]) { + VMSTATE_PTIMER(timer, CMSDKAPBDualTimerModule), + VMSTATE_UINT32(load, CMSDKAPBDualTimerModule), + VMSTATE_UINT32(value, CMSDKAPBDualTimerModule), + VMSTATE_UINT32(control, CMSDKAPBDualTimerModule), + VMSTATE_UINT32(intstatus, CMSDKAPBDualTimerModule), + VMSTATE_END_OF_LIST() + } +}; + +static const VMStateDescription cmsdk_apb_dualtimer_vmstate =3D { + .name =3D "cmsdk-apb-dualtimer", + .version_id =3D 1, + .minimum_version_id =3D 1, + .fields =3D (VMStateField[]) { + VMSTATE_STRUCT_ARRAY(timermod, CMSDKAPBDualTimer, + CMSDK_APB_DUALTIMER_NUM_MODULES, + 1, cmsdk_dualtimermod_vmstate, + CMSDKAPBDualTimerModule), + VMSTATE_UINT32(timeritcr, CMSDKAPBDualTimer), + VMSTATE_UINT32(timeritop, CMSDKAPBDualTimer), + VMSTATE_END_OF_LIST() + } +}; + +static Property cmsdk_apb_dualtimer_properties[] =3D { + DEFINE_PROP_UINT32("pclk-frq", CMSDKAPBDualTimer, pclk_frq, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void cmsdk_apb_dualtimer_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(klass); + + dc->realize =3D cmsdk_apb_dualtimer_realize; + dc->vmsd =3D &cmsdk_apb_dualtimer_vmstate; + dc->reset =3D cmsdk_apb_dualtimer_reset; + dc->props =3D cmsdk_apb_dualtimer_properties; +} + +static const TypeInfo cmsdk_apb_dualtimer_info =3D { + .name =3D TYPE_CMSDK_APB_DUALTIMER, + .parent =3D TYPE_SYS_BUS_DEVICE, + .instance_size =3D sizeof(CMSDKAPBDualTimer), + .instance_init =3D cmsdk_apb_dualtimer_init, + .class_init =3D cmsdk_apb_dualtimer_class_init, +}; + +static void cmsdk_apb_dualtimer_register_types(void) +{ + type_register_static(&cmsdk_apb_dualtimer_info); +} + +type_init(cmsdk_apb_dualtimer_register_types); diff --git a/MAINTAINERS b/MAINTAINERS index 666e9368126..2c1a55ca207 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -453,6 +453,8 @@ F: hw/timer/pl031.c F: include/hw/arm/primecell.h F: hw/timer/cmsdk-apb-timer.c F: include/hw/timer/cmsdk-apb-timer.h +F: hw/timer/cmsdk-apb-dualtimer.c +F: include/hw/timer/cmsdk-apb-dualtimer.h F: hw/char/cmsdk-apb-uart.c F: include/hw/char/cmsdk-apb-uart.h F: hw/misc/tz-ppc.c diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.= mak index 834d45cfaf9..046e8903839 100644 --- a/default-configs/arm-softmmu.mak +++ b/default-configs/arm-softmmu.mak @@ -103,6 +103,7 @@ CONFIG_STM32F2XX_SPI=3Dy CONFIG_STM32F205_SOC=3Dy =20 CONFIG_CMSDK_APB_TIMER=3Dy +CONFIG_CMSDK_APB_DUALTIMER=3Dy CONFIG_CMSDK_APB_UART=3Dy =20 CONFIG_MPS2_FPGAIO=3Dy diff --git a/hw/timer/trace-events b/hw/timer/trace-events index e6e042fddb7..fa4213df5be 100644 --- a/hw/timer/trace-events +++ b/hw/timer/trace-events @@ -61,5 +61,10 @@ cmsdk_apb_timer_read(uint64_t offset, uint64_t data, uns= igned size) "CMSDK APB t cmsdk_apb_timer_write(uint64_t offset, uint64_t data, unsigned size) "CMSD= K APB timer write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u" cmsdk_apb_timer_reset(void) "CMSDK APB timer: reset" =20 +# hw/timer/cmsdk_apb_dualtimer.c +cmsdk_apb_dualtimer_read(uint64_t offset, uint64_t data, unsigned size) "C= MSDK APB dualtimer read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u" +cmsdk_apb_dualtimer_write(uint64_t offset, uint64_t data, unsigned size) "= CMSDK APB dualtimer write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u" +cmsdk_apb_dualtimer_reset(void) "CMSDK APB dualtimer: reset" + # hw/timer/xlnx-zynqmp-rtc.c xlnx_zynqmp_rtc_gettime(int year, int month, int day, int hour, int min, i= nt sec) "Get time from host: %d-%d-%d %2d:%02d:%02d" --=20 2.17.1 From nobody Wed Nov 5 02:34:09 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=linaro.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1532971188574181.5091946488493; Mon, 30 Jul 2018 10:19:48 -0700 (PDT) Received: from localhost ([::1]:53675 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fkB87-0000of-Qm for importer@patchew.org; Mon, 30 Jul 2018 12:34:43 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:37416) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fkAyp-0001KZ-2x for qemu-devel@nongnu.org; Mon, 30 Jul 2018 12:25:08 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fkAyo-0001Ck-32 for qemu-devel@nongnu.org; Mon, 30 Jul 2018 12:25:07 -0400 Received: from orth.archaic.org.uk ([2001:8b0:1d0::2]:43834) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fkAyl-0001Ab-07; Mon, 30 Jul 2018 12:25:03 -0400 Received: from pm215 by orth.archaic.org.uk with local (Exim 4.89) (envelope-from ) id 1fkAyk-0004Lf-0m; Mon, 30 Jul 2018 17:25:02 +0100 From: Peter Maydell To: qemu-arm@nongnu.org, qemu-devel@nongnu.org Date: Mon, 30 Jul 2018 17:24:57 +0100 Message-Id: <20180730162458.23186-5-peter.maydell@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20180730162458.23186-1-peter.maydell@linaro.org> References: <20180730162458.23186-1-peter.maydell@linaro.org> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2001:8b0:1d0::2 Subject: [Qemu-devel] [PATCH 4/5] hw/arm/iotkit: Wire up the dualtimer X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: patches@linaro.org Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Now we have a model of the CMSDK dual timer, we can wire it up in the IoTKit. Signed-off-by: Peter Maydell --- include/hw/arm/iotkit.h | 3 ++- hw/arm/iotkit.c | 8 +++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/include/hw/arm/iotkit.h b/include/hw/arm/iotkit.h index 2cddde55dd1..3e6d806e352 100644 --- a/include/hw/arm/iotkit.h +++ b/include/hw/arm/iotkit.h @@ -56,6 +56,7 @@ #include "hw/misc/tz-ppc.h" #include "hw/misc/tz-mpc.h" #include "hw/timer/cmsdk-apb-timer.h" +#include "hw/timer/cmsdk-apb-dualtimer.h" #include "hw/misc/unimp.h" #include "hw/or-irq.h" #include "hw/core/split-irq.h" @@ -87,7 +88,7 @@ typedef struct IoTKit { SplitIRQ mpc_irq_splitter[IOTS_NUM_EXP_MPC + IOTS_NUM_MPC]; qemu_or_irq mpc_irq_orgate; =20 - UnimplementedDeviceState dualtimer; + CMSDKAPBDualTimer dualtimer; UnimplementedDeviceState s32ktimer; =20 MemoryRegion container; diff --git a/hw/arm/iotkit.c b/hw/arm/iotkit.c index 8cadc8b1608..130d013909e 100644 --- a/hw/arm/iotkit.c +++ b/hw/arm/iotkit.c @@ -139,7 +139,7 @@ static void iotkit_init(Object *obj) sysbus_init_child_obj(obj, "timer1", &s->timer1, sizeof(s->timer1), TYPE_CMSDK_APB_TIMER); sysbus_init_child_obj(obj, "dualtimer", &s->dualtimer, sizeof(s->dualt= imer), - TYPE_UNIMPLEMENTED_DEVICE); + TYPE_CMSDK_APB_DUALTIMER); object_initialize_child(obj, "ppc-irq-orgate", &s->ppc_irq_orgate, sizeof(s->ppc_irq_orgate), TYPE_OR_IRQ, &error_abort, NULL); @@ -390,13 +390,15 @@ static void iotkit_realize(DeviceState *dev, Error **= errp) return; } =20 - qdev_prop_set_string(DEVICE(&s->dualtimer), "name", "Dual timer"); - qdev_prop_set_uint64(DEVICE(&s->dualtimer), "size", 0x1000); + + qdev_prop_set_uint32(DEVICE(&s->dualtimer), "pclk-frq", s->mainclk_frq= ); object_property_set_bool(OBJECT(&s->dualtimer), true, "realized", &err= ); if (err) { error_propagate(errp, err); return; } + sysbus_connect_irq(SYS_BUS_DEVICE(&s->dualtimer), 0, + qdev_get_gpio_in(DEVICE(&s->armv7m), 5)); mr =3D sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->dualtimer), 0); object_property_set_link(OBJECT(&s->apb_ppc0), OBJECT(mr), "port[2]", = &err); if (err) { --=20 2.17.1 From nobody Wed Nov 5 02:34:09 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=linaro.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 15329699287592.6055176770233857; Mon, 30 Jul 2018 09:58:48 -0700 (PDT) Received: from localhost ([::1]:53810 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fkBVP-00056v-KA for importer@patchew.org; Mon, 30 Jul 2018 12:58:47 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:37430) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fkAyp-0001LO-NA for qemu-devel@nongnu.org; Mon, 30 Jul 2018 12:25:08 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fkAyo-0001D1-J8 for qemu-devel@nongnu.org; Mon, 30 Jul 2018 12:25:07 -0400 Received: from orth.archaic.org.uk ([2001:8b0:1d0::2]:43826) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fkAym-00019i-8w; Mon, 30 Jul 2018 12:25:04 -0400 Received: from pm215 by orth.archaic.org.uk with local (Exim 4.89) (envelope-from ) id 1fkAyk-0004MC-Mh; Mon, 30 Jul 2018 17:25:02 +0100 From: Peter Maydell To: qemu-arm@nongnu.org, qemu-devel@nongnu.org Date: Mon, 30 Jul 2018 17:24:58 +0100 Message-Id: <20180730162458.23186-6-peter.maydell@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20180730162458.23186-1-peter.maydell@linaro.org> References: <20180730162458.23186-1-peter.maydell@linaro.org> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2001:8b0:1d0::2 Subject: [Qemu-devel] [PATCH 5/5] hw/arm/mps2: Wire up dual-timer in mps2-an385 and mps2-an511 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: patches@linaro.org Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" The MPS2 FPGA images for the Cortex-M3 (mps2-an385 and mps2-511) both include a CMSDK dual-timer module. Wire this up. Signed-off-by: Peter Maydell --- hw/arm/mps2.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/hw/arm/mps2.c b/hw/arm/mps2.c index c3946da3173..b0125ca0ebf 100644 --- a/hw/arm/mps2.c +++ b/hw/arm/mps2.c @@ -34,6 +34,7 @@ #include "hw/misc/unimp.h" #include "hw/char/cmsdk-apb-uart.h" #include "hw/timer/cmsdk-apb-timer.h" +#include "hw/timer/cmsdk-apb-dualtimer.h" #include "hw/misc/mps2-scc.h" #include "hw/devices.h" #include "net/net.h" @@ -64,6 +65,7 @@ typedef struct { MemoryRegion blockram_m3; MemoryRegion sram; MPS2SCC scc; + CMSDKAPBDualTimer dualtimer; } MPS2MachineState; =20 #define TYPE_MPS2_MACHINE "mps2" @@ -296,6 +298,15 @@ static void mps2_common_init(MachineState *machine) cmsdk_apb_timer_create(0x40000000, qdev_get_gpio_in(armv7m, 8), SYSCLK= _FRQ); cmsdk_apb_timer_create(0x40001000, qdev_get_gpio_in(armv7m, 9), SYSCLK= _FRQ); =20 + sysbus_init_child_obj(OBJECT(mms), "dualtimer", &mms->dualtimer, + sizeof(mms->dualtimer), TYPE_CMSDK_APB_DUALTIMER= ); + qdev_prop_set_uint32(DEVICE(&mms->dualtimer), "pclk-frq", SYSCLK_FRQ); + object_property_set_bool(OBJECT(&mms->dualtimer), true, "realized", + &error_fatal); + sysbus_connect_irq(SYS_BUS_DEVICE(&mms->dualtimer), 0, + qdev_get_gpio_in(armv7m, 10)); + sysbus_mmio_map(SYS_BUS_DEVICE(&mms->dualtimer), 0, 0x40002000); + object_initialize(&mms->scc, sizeof(mms->scc), TYPE_MPS2_SCC); sccdev =3D DEVICE(&mms->scc); qdev_set_parent_bus(sccdev, sysbus_get_default()); --=20 2.17.1