From nobody Fri Apr 19 14:46:53 2024 Delivered-To: importer@patchew.org Received-SPF: temperror (zoho.com: Error in retrieving data from DNS) 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=temperror (zoho.com: Error in retrieving data from DNS) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (209.51.188.17 [209.51.188.17]) by mx.zohomail.com with SMTPS id 1549723824531770.2348620426425; Sat, 9 Feb 2019 06:50:24 -0800 (PST) Received: from localhost ([127.0.0.1]:46294 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gsTxM-00083C-La for importer@patchew.org; Sat, 09 Feb 2019 09:50:12 -0500 Received: from eggs.gnu.org ([209.51.188.92]:54051) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gsTwH-0007eK-AI for qemu-devel@nongnu.org; Sat, 09 Feb 2019 09:49:06 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gsTwF-0005xd-KQ for qemu-devel@nongnu.org; Sat, 09 Feb 2019 09:49:05 -0500 Received: from cock.li ([2a06:1700:0:b::c0cc]:52180) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1gsTwB-0005mw-3H; Sat, 09 Feb 2019 09:48:59 -0500 Date: Sat, 9 Feb 2019 16:49:20 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=airmail.cc; s=mail; t=1549723733; bh=Iw+l1CQWO2o0JVkVmofOAm7nfy2fsN7uLm4jNqx+ZzU=; h=Date:From:To:Cc:Subject:From; b=zTPbJufDDORNb/dR8XnDsDHFSMGvJ1IKEo+HokEgDOng0gAnrHHpcJBF1D1aWSH2l H6UKQ/TvpRz4qVYY3UkUIcKE/EBaoJvQGWVdjF0PH2ATbd7xiN+e8pJ7ryDNirOBxM +o/sb8eisfp6o6PPcyS13/4G1ZN4L4S+UK225hzJXYlBsB43zLySKQTcm+7pUuhIPF obWX/zLGRTtwceJ2+AllMXdG3WR/5jhrE7iyotfxNdIlOQDH0A2aCX/KkSOFqehx+L 5HsLPWCWhP5OUk3CPNedsN8z/Lo1jS0Fwzb/Xn3c1AADNvdTsv1tdTv+/bu3dEgDwT YhU7ivuQmcZ9g== From: Mark To: qemu-devel@nongnu.org Message-ID: <20190209144918.GA14036@nyan> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.10.1 (2018-07-13) X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2a06:1700:0:b::c0cc Subject: [Qemu-devel] [v2 PATCH] hw/arm/bcm2835_peripherals: add bcm283x sp804-alike 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: , Cc: Peter Maydell , "open list:Raspberry Pi" , Philippe =?iso-8859-1?Q?Mathieu-Daud=E9?= , Andrew Baumann , "open list:All patches CC here" Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Signed-off-by: Mark --- hw/arm/bcm2835_peripherals.c | 17 ++ hw/timer/Makefile.objs | 2 + hw/timer/bcm283x_timer.c | 299 +++++++++++++++++++++++++++ include/hw/arm/bcm2835_peripherals.h | 2 + include/hw/timer/bcm283x_timer.h | 38 ++++ 5 files changed, 358 insertions(+) create mode 100644 hw/timer/bcm283x_timer.c create mode 100644 include/hw/timer/bcm283x_timer.h diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c index 6be7660e8c..fccdb9509b 100644 --- a/hw/arm/bcm2835_peripherals.c +++ b/hw/arm/bcm2835_peripherals.c @@ -117,6 +117,13 @@ static void bcm2835_peripherals_init(Object *obj) OBJECT(&s->sdhci.sdbus), &error_abort); object_property_add_const_link(OBJECT(&s->gpio), "sdbus-sdhost", OBJECT(&s->sdhost.sdbus), &error_abort); + + /* SP804-alike ARM Timer */ + object_initialize(&s->bcm283xsp804, sizeof(s->bcm283xsp804), + TYPE_BCM283xSP804); + object_property_add_child(obj, "bcm283xsp804", OBJECT(&s->bcm283xsp804= ), + NULL); + qdev_set_parent_bus(DEVICE(&s->bcm283xsp804), sysbus_get_default()); } static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) @@ -334,6 +341,16 @@ static void bcm2835_peripherals_realize(DeviceState *d= ev, Error **errp) error_propagate(errp, err); return; } + + /* SP804-alike ARM Timer */ + object_property_set_bool(OBJECT(&s->bcm283xsp804), true, "realized", &= err); + if (err) { + error_propagate(errp, err); + return; + } + + memory_region_add_subregion(&s->peri_mr, ARMCTRL_TIMER0_1_OFFSET, + sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->bcm283xsp804), 0= )); } static void bcm2835_peripherals_class_init(ObjectClass *oc, void *data) diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs index 0e9a4530f8..09a3706701 100644 --- a/hw/timer/Makefile.objs +++ b/hw/timer/Makefile.objs @@ -47,3 +47,5 @@ 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 + +common-obj-$(CONFIG_RASPI) +=3D bcm283x_timer.o diff --git a/hw/timer/bcm283x_timer.c b/hw/timer/bcm283x_timer.c new file mode 100644 index 0000000000..55e8a68807 --- /dev/null +++ b/hw/timer/bcm283x_timer.c @@ -0,0 +1,299 @@ +#include "qemu/osdep.h" +#include "hw/sysbus.h" +#include "qemu/timer.h" +#include "qemu-common.h" +#include "hw/qdev.h" +#include "hw/ptimer.h" +#include "hw/timer/bcm283x_timer.h" +#include "qemu/main-loop.h" +#include "qemu/log.h" + +/* TODO: implement free-running timer as per BCM283x peripheral specificat= ion */ + +#define TIMER_CTRL_32BIT (1 << 1) +#define TIMER_CTRL_DIV1 (0 << 2) +#define TIMER_CTRL_DIV16 (1 << 2) +#define TIMER_CTRL_DIV256 (2 << 2) +#define TIMER_CTRL_IE (1 << 5) +#define TIMER_CTRL_ENABLE (1 << 7) + +struct bcm283x_timer_state { + ptimer_state *timer; + uint32_t control; + uint32_t limit; + int freq; + int int_level; + qemu_irq irq; + /* Not implemented */ + int prev_div; + /* Not implemented */ + int free_run_cnt; +}; + +static void bcm283x_timer_update(bcm283x_timer_state *s) +{ + if (s->int_level && (s->control & TIMER_CTRL_IE)) { + qemu_irq_raise(s->irq); + } else { + qemu_irq_lower(s->irq); + } +} + +static uint32_t bcm283x_timer_read(void *opaque, hwaddr offset) +{ + bcm283x_timer_state *s =3D (bcm283x_timer_state *) opaque; + + switch (offset >> 2) { + case 0: /* Load register */ + case 6: /* Reload register */ + return s->limit; + case 1: /* Value register */ + return ptimer_get_count(s->timer); + case 2: /* Control register */ + return s->control; + case 3: /* IRQ clear/ACK register */ + /* + * The register is write-only, + * but returns reverse "ARMT" string bytes + */ + return 0x544D5241; + case 4: /* RAW IRQ register */ + return s->int_level; + case 5: /* Masked IRQ register */ + if ((s->control & TIMER_CTRL_IE) =3D=3D 0) { + return 0; + } + return s->int_level; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad offset %x\n", __func__, (int) offset); + return 0; + } +} + +static void bcm283x_timer_recalibrate(bcm283x_timer_state *s, int reload) +{ + uint32_t limit; + + /* Consider timer periodic */ + limit =3D s->limit; + + ptimer_set_limit(s->timer, limit, reload); +} + +static void bcm283x_timer_write(void *opaque, hwaddr offset, uint32_t valu= e) +{ + bcm283x_timer_state *s =3D (bcm283x_timer_state *) opaque; + int freq; + + switch (offset >> 2) { + case 0: /* Load register */ + s->limit =3D value; + bcm283x_timer_recalibrate(s, 1); + break; + case 1: /* Value register */ + /* Read only */ + break; + case 2: /* Control register */ + if (s->control & TIMER_CTRL_ENABLE) { + ptimer_stop(s->timer); + } + + s->control =3D value; + freq =3D s->freq; + + /* Set pre-scaler */ + switch ((value >> 2) & 3) { + case 1: /* 16 */ + freq >>=3D 4; + break; + case 2: /* 256 */ + freq >>=3D 8; + break; + } + + bcm283x_timer_recalibrate(s, s->control & TIMER_CTRL_ENABLE); + ptimer_set_freq(s->timer, freq); + if (s->control & TIMER_CTRL_ENABLE) { + ptimer_run(s->timer, 0); + } + break; + case 3: /* IRQ clear/ACK register */ + s->int_level =3D 0; + break; + case 6: /* Reload register */ + s->limit =3D value; + bcm283x_timer_recalibrate(s, 0); + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad offset %x\n", __func__, (int) offset); + break; + } + + bcm283x_timer_update(s); +} + +static void bcm283x_timer_tick(void *opaque) +{ + bcm283x_timer_state *s =3D (bcm283x_timer_state *) opaque; + s->int_level =3D 1; + bcm283x_timer_update(s); +} + +static const VMStateDescription vmstate_bcm283x_timer =3D { + .name =3D "bcm283x_timer", + .version_id =3D 1, + .minimum_version_id =3D 1, + .fields =3D (VMStateField[]) { + VMSTATE_UINT32(control, bcm283x_timer_state), + VMSTATE_UINT32(limit, bcm283x_timer_state), + VMSTATE_INT32(int_level, bcm283x_timer_state), + VMSTATE_PTIMER(timer, bcm283x_timer_state), + VMSTATE_END_OF_LIST() + } +}; + +static bcm283x_timer_state *bcm283x_timer_init(uint32_t freq) +{ + bcm283x_timer_state *s; + QEMUBH *bh; + + s =3D g_new0(bcm283x_timer_state, 1); + s->freq =3D freq; + s->control =3D TIMER_CTRL_IE; + + bh =3D qemu_bh_new(bcm283x_timer_tick, s); + s->timer =3D ptimer_init(bh, PTIMER_POLICY_DEFAULT); + vmstate_register(NULL, -1, &vmstate_bcm283x_timer, s); + + return s; +} + +/* BCM283x's implementation of SP804 ARM timer */ + +/* + * XXX: BCM's datasheet does not seem to + * provide these values and they may differ + */ +static const uint8_t bcm283xsp803_ids[] =3D { + /* Timer ID */ + 0x04, 0x18, 0x14, 0x00, + /* PrimeCell ID */ + 0x0D, 0xF0, 0x05, 0xB1 +}; + +static void bcm283xsp804_set_irq(void *opaque, int irq, int level) +{ + BCM283xSP804State *s =3D (BCM283xSP804State *) opaque; + + s->level =3D level; + qemu_set_irq(s->irq, s->level); +} + +static uint64_t bcm283xsp804_read(void *opaque, hwaddr offset, unsigned si= ze) +{ + BCM283xSP804State *s =3D (BCM283xSP804State *) opaque; + + if (offset < 0x20) { + return bcm283x_timer_read(s->timer, offset); + } + /* No second timer (0x20 < offset < 0x40) */ + + if (offset >=3D 0xFE0 && offset <=3D 0xFFC) { + return bcm283xsp803_ids[(offset - 0xFE0) >> 2]; + } + + switch (offset) { + /* Unimplemented: integration test control registers */ + case 0xF00: + case 0xF04: + qemu_log_mask(LOG_UNIMP, + "%s: integration test registers unimplemented\n", + __func__); + return 0; + } + + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad offset %x\n", __func__, (int) offset); + return 0; +} + +static void bcm283xsp803_write(void *opaque, hwaddr offset, uint64_t value, + unsigned size) +{ + BCM283xSP804State *s =3D (BCM283xSP804State *) opaque; + + if (offset < 0x20) { + bcm283x_timer_write(s->timer, offset, value); + } + /* No second timer (0x20 < offset < 0x40) */ + + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad offset %x\n", __func__, (int) offset); +} + +static const MemoryRegionOps bcm283xsp804_ops =3D { + .read =3D bcm283xsp804_read, + .write =3D bcm283xsp803_write, + .endianness =3D DEVICE_NATIVE_ENDIAN +}; + +static const VMStateDescription vmstate_bcm283xsp804 =3D { + .name =3D "bcm283xsp804", + .version_id =3D 1, + .minimum_version_id =3D 1, + .fields =3D (VMStateField[]) { + VMSTATE_INT32(level, BCM283xSP804State), + VMSTATE_END_OF_LIST() + } +}; + +static void bcm283xsp804_init(Object *obj) +{ + BCM283xSP804State *s =3D BCM283xSP804(obj); + SysBusDevice *sbd =3D SYS_BUS_DEVICE(obj); + + sysbus_init_irq(sbd, &s->irq); + memory_region_init_io(&s->iomem, obj, &bcm283xsp804_ops, s, + "bcm283xsp804", 0x1000); + + sysbus_init_mmio(sbd, &s->iomem); +} + +static void bcm283xsp804_realize(DeviceState *dev, Error **errp) +{ + BCM283xSP804State *s =3D BCM283xSP804(dev); + + s->timer =3D bcm283x_timer_init(s->freq0); + s->timer->irq =3D qemu_allocate_irq(bcm283xsp804_set_irq, s, 0); +} + +static Property bcm283xsp804_properties[] =3D { + DEFINE_PROP_UINT32("freq0", BCM283xSP804State, freq0, 1000000), + DEFINE_PROP_END_OF_LIST() +}; + +static void bcm283xsp804_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *k =3D DEVICE_CLASS(klass); + + k->realize =3D bcm283xsp804_realize; + k->props =3D bcm283xsp804_properties; + k->vmsd =3D &vmstate_bcm283xsp804; +} + +static const TypeInfo bcm283xsp804_info =3D { + .name =3D TYPE_BCM283xSP804, + .parent =3D TYPE_SYS_BUS_DEVICE, + .instance_size =3D sizeof(BCM283xSP804State), + .instance_init =3D bcm283xsp804_init, + .class_init =3D bcm283xsp804_class_init +}; + +static void bcm283x_timer_register_types(void) +{ + type_register_static(&bcm283xsp804_info); +} + +type_init(bcm283x_timer_register_types) diff --git a/include/hw/arm/bcm2835_peripherals.h b/include/hw/arm/bcm2835_= peripherals.h index f5b193f670..d13aad43cb 100644 --- a/include/hw/arm/bcm2835_peripherals.h +++ b/include/hw/arm/bcm2835_peripherals.h @@ -23,6 +23,7 @@ #include "hw/sd/sdhci.h" #include "hw/sd/bcm2835_sdhost.h" #include "hw/gpio/bcm2835_gpio.h" +#include "hw/timer/bcm283x_timer.h" #define TYPE_BCM2835_PERIPHERALS "bcm2835-peripherals" #define BCM2835_PERIPHERALS(obj) \ @@ -48,6 +49,7 @@ typedef struct BCM2835PeripheralState { SDHCIState sdhci; BCM2835SDHostState sdhost; BCM2835GpioState gpio; + BCM283xSP804State bcm283xsp804; } BCM2835PeripheralState; #endif /* BCM2835_PERIPHERALS_H */ diff --git a/include/hw/timer/bcm283x_timer.h b/include/hw/timer/bcm283x_ti= mer.h new file mode 100644 index 0000000000..f5e8dcddfc --- /dev/null +++ b/include/hw/timer/bcm283x_timer.h @@ -0,0 +1,38 @@ +/* + * Broadcom BCM283x ARM timer variant based on ARM SP804 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ +#ifndef HW_TIMER_BCM2835_TIMER_H +#define HW_TIMER_BCM2835_TIMER_H + +#include "hw/sysbus.h" + +#define TYPE_BCM283xSP804 "bcm283xsp804" +#define BCM283xSP804(obj) + OBJECT_CHECK(BCM283xSP804State, (obj), TYPE_BCM283xSP804) + +typedef struct bcm283x_timer_state bcm283x_timer_state; + +typedef struct { + SysBusDevice parent_obj; + + MemoryRegion iomem; + bcm283x_timer_state *timer; + uint32_t freq0; + int level; + qemu_irq irq; +} BCM283xSP804State; + +#endif -- 2.20.1