From nobody Sat Nov 8 10:42:31 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 1550149694989393.3141880396423; Thu, 14 Feb 2019 05:08:14 -0800 (PST) Received: from localhost ([127.0.0.1]:48318 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1guGkN-0007Xq-Qm for importer@patchew.org; Thu, 14 Feb 2019 08:08:11 -0500 Received: from eggs.gnu.org ([209.51.188.92]:49748) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1guGeQ-0002vd-JI for qemu-devel@nongnu.org; Thu, 14 Feb 2019 08:02:08 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1guGUW-0006yg-If for qemu-devel@nongnu.org; Thu, 14 Feb 2019 07:51:54 -0500 Received: from mail-wr1-x443.google.com ([2a00:1450:4864:20::443]:46427) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1guGUR-0006fa-HX for qemu-devel@nongnu.org; Thu, 14 Feb 2019 07:51:46 -0500 Received: by mail-wr1-x443.google.com with SMTP id l9so6308990wrt.13 for ; Thu, 14 Feb 2019 04:51:23 -0800 (PST) Received: from orth.archaic.org.uk (orth.archaic.org.uk. [81.2.115.148]) by smtp.gmail.com with ESMTPSA id j3sm1488073wmb.39.2019.02.14.04.51.20 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 14 Feb 2019 04:51:21 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=wx+BYpvHTW57CyXGJ3HudXtRv2dk+GGAZ3zOw47Rw9I=; b=M3l+fQYoOO5SzX3Fyu4sAkXuBkZf3FzJ5ASsuxfv++NmA7lBb67Xw4QoQqCNoyKrg2 EKh0fH1DjggwXP3ta4ana7uma2grGjQ1Os/KSASPZl7zLB9yxAUJlxfIVieK/E/0hxA3 04CrYdWTGsIcmB48ub+/4ksgUwklyBf72RRRiJXZAc44vVSkOw1tbb9Iy3Rm6/ddDWUW b9Aq6he96L9I60IcLvQXl6bjqjhl/3ismN6AL4et6AzvZfI3SNU5biot1d3a1E+GHj8C /PQ5BRsPOIadpeAEltWgQRVI1j3xwW6asVuQpYBqFr47A/4fd+Qkf4qtx73D+KgxUNlR NKYg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=wx+BYpvHTW57CyXGJ3HudXtRv2dk+GGAZ3zOw47Rw9I=; b=q1xurBhLGIukgMkM5kpbWRjwkucH+/tIyXMVwl6wS3g52P/RMfXM36zvODvCFV61yG b/ghQABBBdk6ZKurJYh5/xShSsQqDuEpZKjbRR6FMnICTO8ewMdk+oVbSjCZ09m18khR vOYnU4emPzAZkl9SMM3mda+JTk26iqEfSyR96hanwKYF736JUn2dBXu9xZ8fjgVdLvJZ oGEhltMWsaTBD7ps2llmlIRlMYaitVM/VrQqSuRONCQARGeqi8aHYCSMCdNuPtFE9cvP g6wDh+gKYD2qOTVVGX5nff/nlT3Ykn3L2uH0sJRgfMNYJQo0TJWN6LxtwOpUJcMPmask Lspg== X-Gm-Message-State: AHQUAuZQjOXZvzHx9d1eaRBF0oCezHkyX3nldQkBS8WI6lnVZYy3/JXT JvqXY2UvZhl761AY57AJEUDyI4CmWDHASw== X-Google-Smtp-Source: AHgI3IYzA0UztR0Yocth+LE77RFtK5S5c1gwRDTXuUxaVYzvEVdQP8fYEzVvCKGLjhAStrwcKPGPlQ== X-Received: by 2002:adf:f388:: with SMTP id m8mr2923482wro.133.1550148682278; Thu, 14 Feb 2019 04:51:22 -0800 (PST) From: Peter Maydell To: qemu-arm@nongnu.org, qemu-devel@nongnu.org Date: Thu, 14 Feb 2019 12:51:04 +0000 Message-Id: <20190214125107.22178-12-peter.maydell@linaro.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190214125107.22178-1-peter.maydell@linaro.org> References: <20190214125107.22178-1-peter.maydell@linaro.org> MIME-Version: 1.0 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] [PATCH 11/14] hw/arm/musca: Add PPCs 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-DKIM: fail (Header signature does not verify) Content-Type: text/plain; charset="utf-8" Many of the devices on the Musca board live behind TrustZone Peripheral Protection Controllers (PPCs); add models of the PPCs, using a similar scheme to the MPS2 board models. This commit wires up the PPCs with "unimplemented device" stubs behind them in the correct places in the address map. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson --- hw/arm/musca.c | 289 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 289 insertions(+) diff --git a/hw/arm/musca.c b/hw/arm/musca.c index cc624c7d160..8774e0b87b7 100644 --- a/hw/arm/musca.c +++ b/hw/arm/musca.c @@ -27,8 +27,11 @@ #include "hw/arm/armsse.h" #include "hw/boards.h" #include "hw/core/split-irq.h" +#include "hw/misc/tz-ppc.h" +#include "hw/misc/unimp.h" =20 #define MUSCA_NUMIRQ_MAX 96 +#define MUSCA_PPC_MAX 3 =20 typedef enum MuscaType { MUSCA_A, @@ -48,6 +51,24 @@ typedef struct { =20 ARMSSE sse; SplitIRQ cpu_irq_splitter[MUSCA_NUMIRQ_MAX]; + SplitIRQ sec_resp_splitter; + TZPPC ppc[MUSCA_PPC_MAX]; + MemoryRegion container; + UnimplementedDeviceState eflash[2]; + UnimplementedDeviceState qspi; + UnimplementedDeviceState mpc[5]; + UnimplementedDeviceState mhu[2]; + UnimplementedDeviceState pwm[3]; + UnimplementedDeviceState i2s; + UnimplementedDeviceState uart[2]; + UnimplementedDeviceState i2c[2]; + UnimplementedDeviceState spi; + UnimplementedDeviceState scc; + UnimplementedDeviceState timer; + UnimplementedDeviceState rtc; + UnimplementedDeviceState pvt; + UnimplementedDeviceState sdio; + UnimplementedDeviceState gpio; } MuscaMachineState; =20 #define TYPE_MUSCA_MACHINE "musca" @@ -68,6 +89,94 @@ typedef struct { */ #define SYSCLK_FRQ 40000000 =20 +/* + * Most of the devices in the Musca board sit behind Peripheral Protection + * Controllers. These data structures define the layout of which devices + * sit behind which PPCs. + * The devfn for each port is a function which creates, configures + * and initializes the device, returning the MemoryRegion which + * needs to be plugged into the downstream end of the PPC port. + */ +typedef MemoryRegion *MakeDevFn(MuscaMachineState *mms, void *opaque, + const char *name, hwaddr size); + +typedef struct PPCPortInfo { + const char *name; + MakeDevFn *devfn; + void *opaque; + hwaddr addr; + hwaddr size; +} PPCPortInfo; + +typedef struct PPCInfo { + const char *name; + PPCPortInfo ports[TZ_NUM_PORTS]; +} PPCInfo; + +static MemoryRegion *make_unimp_dev(MuscaMachineState *mms, + void *opaque, const char *name, hwaddr= size) +{ + /* + * Initialize, configure and realize a TYPE_UNIMPLEMENTED_DEVICE, + * and return a pointer to its MemoryRegion. + */ + UnimplementedDeviceState *uds =3D opaque; + + sysbus_init_child_obj(OBJECT(mms), name, uds, + sizeof(UnimplementedDeviceState), + TYPE_UNIMPLEMENTED_DEVICE); + qdev_prop_set_string(DEVICE(uds), "name", name); + qdev_prop_set_uint64(DEVICE(uds), "size", size); + object_property_set_bool(OBJECT(uds), true, "realized", &error_fatal); + return sysbus_mmio_get_region(SYS_BUS_DEVICE(uds), 0); +} + +static MemoryRegion *make_musca_a_devs(MuscaMachineState *mms, void *opaqu= e, + const char *name, hwaddr size) +{ + /* + * Create the container MemoryRegion for all the devices that live + * behind the Musca-A PPC's single port. These devices don't have a PPC + * port each, but we use the PPCPortInfo struct as a convenient way + * to describe them. Note that addresses here are relative to the base + * address of the PPC port region: 0x40100000, and devices appear both + * at the 0x4... NS region and the 0x5... S region. + */ + int i; + MemoryRegion *container =3D &mms->container; + + const PPCPortInfo devices[] =3D { + { "uart0", make_unimp_dev, &mms->uart[0], 0x1000, 0x1000 }, + { "uart1", make_unimp_dev, &mms->uart[1], 0x2000, 0x1000 }, + { "spi", make_unimp_dev, &mms->spi, 0x3000, 0x1000 }, + { "i2c0", make_unimp_dev, &mms->i2c[0], 0x4000, 0x1000 }, + { "i2c1", make_unimp_dev, &mms->i2c[1], 0x5000, 0x1000 }, + { "i2s", make_unimp_dev, &mms->i2s, 0x6000, 0x1000 }, + { "pwm0", make_unimp_dev, &mms->pwm[0], 0x7000, 0x1000 }, + { "rtc", make_unimp_dev, &mms->rtc, 0x8000, 0x1000 }, + { "qspi", make_unimp_dev, &mms->qspi, 0xa000, 0x1000 }, + { "timer", make_unimp_dev, &mms->timer, 0xb000, 0x1000 }, + { "scc", make_unimp_dev, &mms->scc, 0xc000, 0x1000 }, + { "pwm1", make_unimp_dev, &mms->pwm[1], 0xe000, 0x1000 }, + { "pwm2", make_unimp_dev, &mms->pwm[2], 0xf000, 0x1000 }, + { "gpio", make_unimp_dev, &mms->gpio, 0x10000, 0x1000 }, + { "mpc0", make_unimp_dev, &mms->mpc[0], 0x12000, 0x1000 }, + { "mpc1", make_unimp_dev, &mms->mpc[1], 0x13000, 0x1000 }, + }; + + memory_region_init(container, OBJECT(mms), "musca-device-container", s= ize); + + for (i =3D 0; i < ARRAY_SIZE(devices); i++) { + const PPCPortInfo *pinfo =3D &devices[i]; + MemoryRegion *mr; + + mr =3D pinfo->devfn(mms, pinfo->opaque, pinfo->name, pinfo->size); + memory_region_add_subregion(container, pinfo->addr, mr); + } + + return &mms->container; +} + static void musca_init(MachineState *machine) { MuscaMachineState *mms =3D MUSCA_MACHINE(machine); @@ -75,6 +184,9 @@ static void musca_init(MachineState *machine) MachineClass *mc =3D MACHINE_GET_CLASS(machine); MemoryRegion *system_memory =3D get_system_memory(); DeviceState *ssedev; + DeviceState *dev_splitter; + const PPCInfo *ppcs; + int num_ppcs; int i; =20 assert(mmc->num_irqs <=3D MUSCA_NUMIRQ_MAX); @@ -121,6 +233,183 @@ static void musca_init(MachineState *machine) "EXP_CPU1_IRQ", i)); } =20 + /* + * The sec_resp_cfg output from the SSE-200 must be split into multiple + * lines, one for each of the PPCs we create here. + */ + object_initialize(&mms->sec_resp_splitter, sizeof(mms->sec_resp_splitt= er), + TYPE_SPLIT_IRQ); + object_property_add_child(OBJECT(machine), "sec-resp-splitter", + OBJECT(&mms->sec_resp_splitter), &error_fata= l); + object_property_set_int(OBJECT(&mms->sec_resp_splitter), + ARRAY_SIZE(mms->ppc), "num-lines", &error_fata= l); + object_property_set_bool(OBJECT(&mms->sec_resp_splitter), true, + "realized", &error_fatal); + dev_splitter =3D DEVICE(&mms->sec_resp_splitter); + qdev_connect_gpio_out_named(ssedev, "sec_resp_cfg", 0, + qdev_get_gpio_in(dev_splitter, 0)); + + /* + * Most of the devices in the board are behind Peripheral Protection + * Controllers. The required order for initializing things is: + * + initialize the PPC + * + initialize, configure and realize downstream devices + * + connect downstream device MemoryRegions to the PPC + * + realize the PPC + * + map the PPC's MemoryRegions to the places in the address map + * where the downstream devices should appear + * + wire up the PPC's control lines to the SSE object + * + * The PPC mapping differs for the -A and -B1 variants; the -A version + * is much simpler, using only a single port of a single PPC and putti= ng + * all the devices behind that. + */ + const PPCInfo a_ppcs[] =3D { { + .name =3D "ahb_ppcexp0", + .ports =3D { + { "musca-devices", make_musca_a_devs, 0, 0x40100000, 0x100= 000 }, + }, + }, + }; + + /* + * Devices listed with an 0x4.. address appear in both the NS 0x4.. re= gion + * and the 0x5.. S region. Devices listed with an 0x5.. address appear + * only in the S region. + */ + const PPCInfo b1_ppcs[] =3D { { + .name =3D "apb_ppcexp0", + .ports =3D { + { "eflash0", make_unimp_dev, &mms->eflash[0], + 0x52400000, 0x1000 }, + { "eflash1", make_unimp_dev, &mms->eflash[1], + 0x52500000, 0x1000 }, + { "qspi", make_unimp_dev, &mms->qspi, 0x42800000, 0x100000= }, + { "mpc0", make_unimp_dev, &mms->mpc[0], 0x52000000, 0x1000= }, + { "mpc1", make_unimp_dev, &mms->mpc[1], 0x52100000, 0x1000= }, + { "mpc2", make_unimp_dev, &mms->mpc[2], 0x52200000, 0x1000= }, + { "mpc3", make_unimp_dev, &mms->mpc[3], 0x52300000, 0x1000= }, + { "mhu0", make_unimp_dev, &mms->mhu[0], 0x42600000, 0x1000= 00 }, + { "mhu1", make_unimp_dev, &mms->mhu[1], 0x42700000, 0x1000= 00 }, + { }, /* port 9: unused */ + { }, /* port 10: unused */ + { }, /* port 11: unused */ + { }, /* port 12: unused */ + { }, /* port 13: unused */ + { "mpc4", make_unimp_dev, &mms->mpc[4], 0x52e00000, 0x1000= }, + }, + }, { + .name =3D "apb_ppcexp1", + .ports =3D { + { "pwm0", make_unimp_dev, &mms->pwm[0], 0x40101000, 0x1000= }, + { "pwm1", make_unimp_dev, &mms->pwm[1], 0x40102000, 0x1000= }, + { "pwm2", make_unimp_dev, &mms->pwm[2], 0x40103000, 0x1000= }, + { "i2s", make_unimp_dev, &mms->i2s, 0x40104000, 0x1000 }, + { "uart0", make_unimp_dev, &mms->uart[0], 0x40105000, 0x10= 00 }, + { "uart1", make_unimp_dev, &mms->uart[1], 0x40106000, 0x10= 00 }, + { "i2c0", make_unimp_dev, &mms->i2c[0], 0x40108000, 0x1000= }, + { "i2c1", make_unimp_dev, &mms->i2c[1], 0x40109000, 0x1000= }, + { "spi", make_unimp_dev, &mms->spi, 0x4010a000, 0x1000 }, + { "scc", make_unimp_dev, &mms->scc, 0x5010b000, 0x1000 }, + { "timer", make_unimp_dev, &mms->timer, 0x4010c000, 0x1000= }, + { "rtc", make_unimp_dev, &mms->rtc, 0x4010d000, 0x1000 }, + { "pvt", make_unimp_dev, &mms->pvt, 0x4010e000, 0x1000 }, + { "sdio", make_unimp_dev, &mms->sdio, 0x4010f000, 0x1000 }, + }, + }, { + .name =3D "ahb_ppcexp0", + .ports =3D { + { }, /* port 0: unused */ + { "gpio", make_unimp_dev, &mms->gpio, 0x41000000, 0x1000 }, + }, + }, + }; + + switch (mmc->type) { + case MUSCA_A: + ppcs =3D a_ppcs; + num_ppcs =3D ARRAY_SIZE(a_ppcs); + break; + case MUSCA_B1: + ppcs =3D b1_ppcs; + num_ppcs =3D ARRAY_SIZE(b1_ppcs); + break; + default: + g_assert_not_reached(); + } + assert(num_ppcs <=3D MUSCA_PPC_MAX); + + for (i =3D 0; i < num_ppcs; i++) { + const PPCInfo *ppcinfo =3D &ppcs[i]; + TZPPC *ppc =3D &mms->ppc[i]; + DeviceState *ppcdev; + int port; + char *gpioname; + + sysbus_init_child_obj(OBJECT(machine), ppcinfo->name, ppc, + sizeof(TZPPC), TYPE_TZ_PPC); + ppcdev =3D DEVICE(ppc); + + for (port =3D 0; port < TZ_NUM_PORTS; port++) { + const PPCPortInfo *pinfo =3D &ppcinfo->ports[port]; + MemoryRegion *mr; + char *portname; + + if (!pinfo->devfn) { + continue; + } + + mr =3D pinfo->devfn(mms, pinfo->opaque, pinfo->name, pinfo->si= ze); + portname =3D g_strdup_printf("port[%d]", port); + object_property_set_link(OBJECT(ppc), OBJECT(mr), + portname, &error_fatal); + g_free(portname); + } + + object_property_set_bool(OBJECT(ppc), true, "realized", &error_fat= al); + + for (port =3D 0; port < TZ_NUM_PORTS; port++) { + const PPCPortInfo *pinfo =3D &ppcinfo->ports[port]; + + if (!pinfo->devfn) { + continue; + } + sysbus_mmio_map(SYS_BUS_DEVICE(ppc), port, pinfo->addr); + + gpioname =3D g_strdup_printf("%s_nonsec", ppcinfo->name); + qdev_connect_gpio_out_named(ssedev, gpioname, port, + qdev_get_gpio_in_named(ppcdev, + "cfg_nonsec= ", + port)); + g_free(gpioname); + gpioname =3D g_strdup_printf("%s_ap", ppcinfo->name); + qdev_connect_gpio_out_named(ssedev, gpioname, port, + qdev_get_gpio_in_named(ppcdev, + "cfg_ap", p= ort)); + g_free(gpioname); + } + + gpioname =3D g_strdup_printf("%s_irq_enable", ppcinfo->name); + qdev_connect_gpio_out_named(ssedev, gpioname, 0, + qdev_get_gpio_in_named(ppcdev, + "irq_enable", 0= )); + g_free(gpioname); + gpioname =3D g_strdup_printf("%s_irq_clear", ppcinfo->name); + qdev_connect_gpio_out_named(ssedev, gpioname, 0, + qdev_get_gpio_in_named(ppcdev, + "irq_clear", 0)= ); + g_free(gpioname); + gpioname =3D g_strdup_printf("%s_irq_status", ppcinfo->name); + qdev_connect_gpio_out_named(ppcdev, "irq", 0, + qdev_get_gpio_in_named(ssedev, + gpioname, 0)); + g_free(gpioname); + + qdev_connect_gpio_out(dev_splitter, i, + qdev_get_gpio_in_named(ppcdev, + "cfg_sec_resp", 0)); + } + armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename, 0x200= 0000); } =20 --=20 2.20.1