From nobody Thu Dec 18 17:54:24 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.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; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.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=none dis=none) header.from=linaro.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1552661207767327.00828370727993; Fri, 15 Mar 2019 07:46:47 -0700 (PDT) Received: from localhost ([127.0.0.1]:56572 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1h4o6Y-0004vI-CW for importer@patchew.org; Fri, 15 Mar 2019 10:46:38 -0400 Received: from eggs.gnu.org ([209.51.188.92]:60361) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1h4n3l-0007XR-QX for qemu-devel@nongnu.org; Fri, 15 Mar 2019 09:39:45 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1h4mqd-0002YT-LW for qemu-devel@nongnu.org; Fri, 15 Mar 2019 09:26:09 -0400 Received: from mail-wr1-x443.google.com ([2a00:1450:4864:20::443]:38324) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1h4mqd-0002Xy-6i for qemu-devel@nongnu.org; Fri, 15 Mar 2019 09:26:07 -0400 Received: by mail-wr1-x443.google.com with SMTP id g12so9582547wrm.5 for ; Fri, 15 Mar 2019 06:26:07 -0700 (PDT) Received: from orth.archaic.org.uk (orth.archaic.org.uk. [81.2.115.148]) by smtp.gmail.com with ESMTPSA id s3sm2604497wrt.81.2019.03.15.04.39.08 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 15 Mar 2019 04:39:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:subject:date:message-id:in-reply-to:references:mime-version :content-transfer-encoding; bh=h9SCJfs8Kqk6ZFQXqt81KlLK+Mcih/UNoLo0rtCxk14=; b=PuEAaPVz29/iW9cnzf8XUKPCvPoSbwEcCiz/g2ia8arTcTHU9g7KvLWk0l/69QiRBS SQGLZx5voI6C046Wn+b5Mf1vfCi1Sn/dxifNrjqA8b2dSpwuGTFcsXHeN4cn6eJljTbD rT9pc5437PhsgiboXvP2i6IqGZmaMCuZUo3kvyA9OgU9ocLictFDbtCwKKeuOlZplphx u08t1Rf0KbAFFOdbS2QAj4yrd9GmpbAlGiZFBzP8pgGhORYGKytUHFDPj+JIUDRMlLWu AVTtfA4fQYZru185uOUymZ38LtLvztdmdSE2n4UZhHwX2MVXYtsyO1GMVMuGInQnsE9I 27yg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=h9SCJfs8Kqk6ZFQXqt81KlLK+Mcih/UNoLo0rtCxk14=; b=Reii1t8mmmG0OqBiRg64sz2jnjmuM2464LvxzuW2CDQsCsQeHv1R4Sf0Tp6B2I3Wda s8kWpPbNcBpSimbRcgHaCk0QiHCKt83q/eMDl72bf5IlrLDcGRIeeo1wYrfWrDqPjHT/ dJAhOaiL8shhgRm13TOnU2I2Z1QG552CdV49kVueGunaT7qZceYuMv1mupzI5YkgCz41 qg9ZKwsk0zyRVbljSEVezDAqIKUjlpSvEm7SwhjCGSJ8g28DjPbmG7VTPtqSYlbNViEc VAMg2ZAH1QRD9mhN1H/zuS6tnNIcL4W1/Jda5XlICqzBKz7b+xOfv46YrqTAvut+jK3s 5qdA== X-Gm-Message-State: APjAAAV/6fUQ50YLz78CpM4AVN/PSwQrbCKoCOoPA/7/Nx5+FyyaTpQu WMw83XpzQW7qST7Pq+hqfwmzLDgMKaA= X-Google-Smtp-Source: APXvYqwDDJOZi6AuTwQitSsXgMvaM6iRRQLvuYzaNSlGgpwbq+N9y+AALN2bBt7PFRgR7zC3L2gRoQ== X-Received: by 2002:a5d:6288:: with SMTP id k8mr2245085wru.173.1552649950099; Fri, 15 Mar 2019 04:39:10 -0700 (PDT) From: Peter Maydell To: qemu-devel@nongnu.org Date: Fri, 15 Mar 2019 11:39:02 +0000 Message-Id: <20190315113906.6585-2-peter.maydell@linaro.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190315113906.6585-1-peter.maydell@linaro.org> References: <20190315113906.6585-1-peter.maydell@linaro.org> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2a00:1450:4864:20::443 Subject: [Qemu-devel] [PULL 1/5] hw/intc/bcm2836_control: Implement local timer 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: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) From: Zolt=C3=A1n Baldaszti The BCM2836 control logic module includes a simple "local timer" which is a programmable down-counter that can generates an interrupt. Implement this functionality. Signed-off-by: Zolt=C3=A1n Baldaszti [PMM: wrote commit message; wrapped long line; tweaked some comments to match the final version of the code] Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- include/hw/intc/bcm2836_control.h | 9 +++ hw/intc/bcm2836_control.c | 101 +++++++++++++++++++++++++++++- 2 files changed, 108 insertions(+), 2 deletions(-) diff --git a/include/hw/intc/bcm2836_control.h b/include/hw/intc/bcm2836_co= ntrol.h index 613f3c4186f..de061b8929a 100644 --- a/include/hw/intc/bcm2836_control.h +++ b/include/hw/intc/bcm2836_control.h @@ -5,6 +5,9 @@ * Rasperry Pi 2 emulation and refactoring Copyright (c) 2015, Microsoft * Written by Andrew Baumann * + * ARM Local Timer IRQ Copyright (c) 2019. Zolt=C3=A1n Baldaszti + * Added basic IRQ_TIMER interrupt support + * * This code is licensed under the GNU GPLv2 and later. */ =20 @@ -12,6 +15,7 @@ #define BCM2836_CONTROL_H =20 #include "hw/sysbus.h" +#include "qemu/timer.h" =20 /* 4 mailboxes per core, for 16 total */ #define BCM2836_NCORES 4 @@ -39,6 +43,11 @@ typedef struct BCM2836ControlState { bool gpu_irq, gpu_fiq; uint8_t timerirqs[BCM2836_NCORES]; =20 + /* local timer */ + QEMUTimer timer; + uint32_t local_timer_control; + uint8_t route_localtimer; + /* interrupt source registers, post-routing (also input-derived; visib= le) */ uint32_t irqsrc[BCM2836_NCORES]; uint32_t fiqsrc[BCM2836_NCORES]; diff --git a/hw/intc/bcm2836_control.c b/hw/intc/bcm2836_control.c index cfa5bc73659..421469f2ef5 100644 --- a/hw/intc/bcm2836_control.c +++ b/hw/intc/bcm2836_control.c @@ -7,7 +7,9 @@ * This code is licensed under the GNU GPLv2 and later. * * At present, only implements interrupt routing, and mailboxes (i.e., - * not local timer, PMU interrupt, or AXI counters). + * not PMU interrupt, or AXI counters). + * + * ARM Local Timer IRQ Copyright (c) 2019. Zolt=C3=A1n Baldaszti * * Ref: * https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2836/= QA7_rev3.4.pdf @@ -18,6 +20,9 @@ #include "qemu/log.h" =20 #define REG_GPU_ROUTE 0x0c +#define REG_LOCALTIMERROUTING 0x24 +#define REG_LOCALTIMERCONTROL 0x34 +#define REG_LOCALTIMERACK 0x38 #define REG_TIMERCONTROL 0x40 #define REG_MBOXCONTROL 0x50 #define REG_IRQSRC 0x60 @@ -43,6 +48,13 @@ #define IRQ_TIMER 11 #define IRQ_MAX IRQ_TIMER =20 +#define LOCALTIMER_FREQ 38400000 +#define LOCALTIMER_INTFLAG (1 << 31) +#define LOCALTIMER_RELOAD (1 << 30) +#define LOCALTIMER_INTENABLE (1 << 29) +#define LOCALTIMER_ENABLE (1 << 28) +#define LOCALTIMER_VALUE(x) ((x) & 0xfffffff) + static void deliver_local(BCM2836ControlState *s, uint8_t core, uint8_t ir= q, uint32_t controlreg, uint8_t controlidx) { @@ -78,6 +90,20 @@ static void bcm2836_control_update(BCM2836ControlState *= s) s->fiqsrc[s->route_gpu_fiq] |=3D (uint32_t)1 << IRQ_GPU; } =20 + /* + * handle the control module 'local timer' interrupt for one of the + * cores' IRQ/FIQ; this is distinct from the per-CPU timer + * interrupts handled below. + */ + if ((s->local_timer_control & LOCALTIMER_INTENABLE) && + (s->local_timer_control & LOCALTIMER_INTFLAG)) { + if (s->route_localtimer & 4) { + s->fiqsrc[(s->route_localtimer & 3)] |=3D (uint32_t)1 << IRQ_T= IMER; + } else { + s->irqsrc[(s->route_localtimer & 3)] |=3D (uint32_t)1 << IRQ_T= IMER; + } + } + for (i =3D 0; i < BCM2836_NCORES; i++) { /* handle local timer interrupts for this core */ if (s->timerirqs[i]) { @@ -162,6 +188,54 @@ static void bcm2836_control_set_gpu_fiq(void *opaque, = int irq, int level) bcm2836_control_update(s); } =20 +static void bcm2836_control_local_timer_set_next(void *opaque) +{ + BCM2836ControlState *s =3D opaque; + uint64_t next_event; + + assert(LOCALTIMER_VALUE(s->local_timer_control) > 0); + + next_event =3D qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + + muldiv64(LOCALTIMER_VALUE(s->local_timer_control), + NANOSECONDS_PER_SECOND, LOCALTIMER_FREQ); + timer_mod(&s->timer, next_event); +} + +static void bcm2836_control_local_timer_tick(void *opaque) +{ + BCM2836ControlState *s =3D opaque; + + bcm2836_control_local_timer_set_next(s); + + s->local_timer_control |=3D LOCALTIMER_INTFLAG; + bcm2836_control_update(s); +} + +static void bcm2836_control_local_timer_control(void *opaque, uint32_t val) +{ + BCM2836ControlState *s =3D opaque; + + s->local_timer_control =3D val; + if (val & LOCALTIMER_ENABLE) { + bcm2836_control_local_timer_set_next(s); + } else { + timer_del(&s->timer); + } +} + +static void bcm2836_control_local_timer_ack(void *opaque, uint32_t val) +{ + BCM2836ControlState *s =3D opaque; + + if (val & LOCALTIMER_INTFLAG) { + s->local_timer_control &=3D ~LOCALTIMER_INTFLAG; + } + if ((val & LOCALTIMER_RELOAD) && + (s->local_timer_control & LOCALTIMER_ENABLE)) { + bcm2836_control_local_timer_set_next(s); + } +} + static uint64_t bcm2836_control_read(void *opaque, hwaddr offset, unsigned= size) { BCM2836ControlState *s =3D opaque; @@ -170,6 +244,12 @@ static uint64_t bcm2836_control_read(void *opaque, hwa= ddr offset, unsigned size) assert(s->route_gpu_fiq < BCM2836_NCORES && s->route_gpu_irq < BCM2836_NCORES); return ((uint32_t)s->route_gpu_fiq << 2) | s->route_gpu_irq; + } else if (offset =3D=3D REG_LOCALTIMERROUTING) { + return s->route_localtimer; + } else if (offset =3D=3D REG_LOCALTIMERCONTROL) { + return s->local_timer_control; + } else if (offset =3D=3D REG_LOCALTIMERACK) { + return 0; } else if (offset >=3D REG_TIMERCONTROL && offset < REG_MBOXCONTROL) { return s->timercontrol[(offset - REG_TIMERCONTROL) >> 2]; } else if (offset >=3D REG_MBOXCONTROL && offset < REG_IRQSRC) { @@ -195,6 +275,12 @@ static void bcm2836_control_write(void *opaque, hwaddr= offset, if (offset =3D=3D REG_GPU_ROUTE) { s->route_gpu_irq =3D val & 0x3; s->route_gpu_fiq =3D (val >> 2) & 0x3; + } else if (offset =3D=3D REG_LOCALTIMERROUTING) { + s->route_localtimer =3D val & 7; + } else if (offset =3D=3D REG_LOCALTIMERCONTROL) { + bcm2836_control_local_timer_control(s, val); + } else if (offset =3D=3D REG_LOCALTIMERACK) { + bcm2836_control_local_timer_ack(s, val); } else if (offset >=3D REG_TIMERCONTROL && offset < REG_MBOXCONTROL) { s->timercontrol[(offset - REG_TIMERCONTROL) >> 2] =3D val & 0xff; } else if (offset >=3D REG_MBOXCONTROL && offset < REG_IRQSRC) { @@ -227,6 +313,10 @@ static void bcm2836_control_reset(DeviceState *d) =20 s->route_gpu_irq =3D s->route_gpu_fiq =3D 0; =20 + timer_del(&s->timer); + s->route_localtimer =3D 0; + s->local_timer_control =3D 0; + for (i =3D 0; i < BCM2836_NCORES; i++) { s->timercontrol[i] =3D 0; s->mailboxcontrol[i] =3D 0; @@ -263,11 +353,15 @@ static void bcm2836_control_init(Object *obj) /* outputs to CPU cores */ qdev_init_gpio_out_named(dev, s->irq, "irq", BCM2836_NCORES); qdev_init_gpio_out_named(dev, s->fiq, "fiq", BCM2836_NCORES); + + /* create a qemu virtual timer */ + timer_init_ns(&s->timer, QEMU_CLOCK_VIRTUAL, + bcm2836_control_local_timer_tick, s); } =20 static const VMStateDescription vmstate_bcm2836_control =3D { .name =3D TYPE_BCM2836_CONTROL, - .version_id =3D 1, + .version_id =3D 2, .minimum_version_id =3D 1, .fields =3D (VMStateField[]) { VMSTATE_UINT32_ARRAY(mailboxes, BCM2836ControlState, @@ -277,6 +371,9 @@ static const VMStateDescription vmstate_bcm2836_control= =3D { VMSTATE_UINT32_ARRAY(timercontrol, BCM2836ControlState, BCM2836_NC= ORES), VMSTATE_UINT32_ARRAY(mailboxcontrol, BCM2836ControlState, BCM2836_NCORES), + VMSTATE_TIMER_V(timer, BCM2836ControlState, 2), + VMSTATE_UINT32_V(local_timer_control, BCM2836ControlState, 2), + VMSTATE_UINT8_V(route_localtimer, BCM2836ControlState, 2), VMSTATE_END_OF_LIST() } }; --=20 2.20.1