aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2022-07-15 11:33:39 +0100
committerPeter Maydell <peter.maydell@linaro.org>2022-07-15 11:33:39 +0100
commit44bfcf628b1531f11ecc21ae96d025a238e1083f (patch)
tree8358899566ea8d4ebd646486ad8fce958f477c1b /hw
parent285f64fcbf86dac2be6dbd0a8a32872bcff3cacb (diff)
parentf0418558302ef9e140681e04250fc1ca265f3140 (diff)
downloadqemu-44bfcf628b1531f11ecc21ae96d025a238e1083f.zip
qemu-44bfcf628b1531f11ecc21ae96d025a238e1083f.tar.gz
qemu-44bfcf628b1531f11ecc21ae96d025a238e1083f.tar.bz2
Merge tag 'pull-aspeed-20220714' of https://github.com/legoater/qemu into staging
aspeed queue: * New ISL69259 device model * New fby35 multi-SoC machine (AST1030 BIC + AST2600 BMC) * Aspeed GPIO fixes * Extension of m25p80 with write protect bits * More avocado tests using the Aspeed SDK # gpg: Signature made Thu 14 Jul 2022 15:28:09 BST # gpg: using RSA key A0F66548F04895EBFE6B0B6051A343C7CFFBECA1 # gpg: Good signature from "Cédric Le Goater <clg@kaod.org>" [undefined] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: A0F6 6548 F048 95EB FE6B 0B60 51A3 43C7 CFFB ECA1 * tag 'pull-aspeed-20220714' of https://github.com/legoater/qemu: aspeed: Add fby35-bmc slot GPIO's hw/gpio/aspeed: Don't let guests modify input pins qtest/aspeed_gpio: Add input pin modification test hw: m25p80: add tests for BP and TB bit write protect hw: m25p80: Add Block Protect and Top Bottom bits for write protect test/avocado/machine_aspeed.py: Add SDK tests docs: aspeed: Minor updates docs: aspeed: Add fby35 multi-SoC machine section aspeed: Add AST1030 (BIC) to fby35 aspeed: fby35: Add a bootrom for the BMC aspeed: Add AST2600 (BMC) to fby35 aspeed: Add fby35 skeleton aspeed: Make aspeed_board_init_flashes public aspeed: Refactor UART init for multi-SoC machines aspeed: Create SRAM name from first CPU index hw/sensor: Add Renesas ISL69259 device model hw/sensor: Add IC_DEVICE_ID to ISL voltage regulators hw/i2c/pmbus: Add idle state to return 0xff's aspeed: sbc: Allow per-machine settings Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw')
-rw-r--r--hw/arm/aspeed.c38
-rw-r--r--hw/arm/aspeed_ast10x0.c13
-rw-r--r--hw/arm/aspeed_ast2600.c13
-rw-r--r--hw/arm/aspeed_soc.c55
-rw-r--r--hw/arm/fby35.c188
-rw-r--r--hw/arm/meson.build3
-rw-r--r--hw/block/m25p80.c102
-rw-r--r--hw/gpio/aspeed_gpio.c15
-rw-r--r--hw/i2c/pmbus_device.c9
-rw-r--r--hw/misc/aspeed_sbc.c42
-rw-r--r--hw/sensor/isl_pmbus_vr.c40
11 files changed, 467 insertions, 51 deletions
diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c
index 3340187..4193a3d 100644
--- a/hw/arm/aspeed.c
+++ b/hw/arm/aspeed.c
@@ -26,6 +26,7 @@
#include "qemu/error-report.h"
#include "qemu/units.h"
#include "hw/qdev-clock.h"
+#include "sysemu/sysemu.h"
static struct arm_boot_info aspeed_board_binfo = {
.board_id = -1, /* device-tree-only board */
@@ -261,7 +262,7 @@ static void write_boot_rom(DriveInfo *dinfo, hwaddr addr, size_t rom_size,
rom_add_blob_fixed("aspeed.boot_rom", storage, rom_size, addr);
}
-static void aspeed_board_init_flashes(AspeedSMCState *s, const char *flashtype,
+void aspeed_board_init_flashes(AspeedSMCState *s, const char *flashtype,
unsigned int count, int unit0)
{
int i;
@@ -301,6 +302,21 @@ static void sdhci_attach_drive(SDHCIState *sdhci, DriveInfo *dinfo)
&error_fatal);
}
+static void connect_serial_hds_to_uarts(AspeedMachineState *bmc)
+{
+ AspeedMachineClass *amc = ASPEED_MACHINE_GET_CLASS(bmc);
+ AspeedSoCState *s = &bmc->soc;
+ AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
+
+ aspeed_soc_uart_set_chr(s, amc->uart_default, serial_hd(0));
+ for (int i = 1, uart = ASPEED_DEV_UART1; i < sc->uarts_num; i++, uart++) {
+ if (uart == amc->uart_default) {
+ continue;
+ }
+ aspeed_soc_uart_set_chr(s, uart, serial_hd(i));
+ }
+}
+
static void aspeed_machine_init(MachineState *machine)
{
AspeedMachineState *bmc = ASPEED_MACHINE(machine);
@@ -346,8 +362,7 @@ static void aspeed_machine_init(MachineState *machine)
object_property_set_int(OBJECT(&bmc->soc), "hw-prot-key",
ASPEED_SCU_PROT_KEY, &error_abort);
}
- qdev_prop_set_uint32(DEVICE(&bmc->soc), "uart-default",
- amc->uart_default);
+ connect_serial_hds_to_uarts(bmc);
qdev_realize(DEVICE(&bmc->soc), NULL, &error_abort);
aspeed_board_init_flashes(&bmc->soc.fmc,
@@ -1343,11 +1358,23 @@ static void fby35_reset(MachineState *state)
qemu_devices_reset();
- /* Board ID */
+ /* Board ID: 7 (Class-1, 4 slots) */
object_property_set_bool(OBJECT(gpio), "gpioV4", true, &error_fatal);
object_property_set_bool(OBJECT(gpio), "gpioV5", true, &error_fatal);
object_property_set_bool(OBJECT(gpio), "gpioV6", true, &error_fatal);
object_property_set_bool(OBJECT(gpio), "gpioV7", false, &error_fatal);
+
+ /* Slot presence pins, inverse polarity. (False means present) */
+ object_property_set_bool(OBJECT(gpio), "gpioH4", false, &error_fatal);
+ object_property_set_bool(OBJECT(gpio), "gpioH5", true, &error_fatal);
+ object_property_set_bool(OBJECT(gpio), "gpioH6", true, &error_fatal);
+ object_property_set_bool(OBJECT(gpio), "gpioH7", true, &error_fatal);
+
+ /* Slot 12v power pins, normal polarity. (True means powered-on) */
+ object_property_set_bool(OBJECT(gpio), "gpioB2", true, &error_fatal);
+ object_property_set_bool(OBJECT(gpio), "gpioB3", false, &error_fatal);
+ object_property_set_bool(OBJECT(gpio), "gpioB4", false, &error_fatal);
+ object_property_set_bool(OBJECT(gpio), "gpioB5", false, &error_fatal);
}
static void aspeed_machine_fby35_class_init(ObjectClass *oc, void *data)
@@ -1383,8 +1410,7 @@ static void aspeed_minibmc_machine_init(MachineState *machine)
object_property_set_link(OBJECT(&bmc->soc), "memory",
OBJECT(get_system_memory()), &error_abort);
- qdev_prop_set_uint32(DEVICE(&bmc->soc), "uart-default",
- amc->uart_default);
+ connect_serial_hds_to_uarts(bmc);
qdev_realize(DEVICE(&bmc->soc), NULL, &error_abort);
aspeed_board_init_flashes(&bmc->soc.fmc,
diff --git a/hw/arm/aspeed_ast10x0.c b/hw/arm/aspeed_ast10x0.c
index 33ef331..4d0b9b1 100644
--- a/hw/arm/aspeed_ast10x0.c
+++ b/hw/arm/aspeed_ast10x0.c
@@ -144,6 +144,10 @@ static void aspeed_soc_ast1030_init(Object *obj)
object_initialize_child(obj, "wdt[*]", &s->wdt[i], typename);
}
+ for (i = 0; i < sc->uarts_num; i++) {
+ object_initialize_child(obj, "uart[*]", &s->uart[i], TYPE_SERIAL_MM);
+ }
+
snprintf(typename, sizeof(typename), "aspeed.gpio-%s", socname);
object_initialize_child(obj, "gpio", &s->gpio, typename);
@@ -159,6 +163,7 @@ static void aspeed_soc_ast1030_realize(DeviceState *dev_soc, Error **errp)
DeviceState *armv7m;
Error *err = NULL;
int i;
+ g_autofree char *sram_name = NULL;
if (!clock_has_source(s->sysclk)) {
error_setg(errp, "sysclk clock must be wired up by the board code");
@@ -183,7 +188,9 @@ static void aspeed_soc_ast1030_realize(DeviceState *dev_soc, Error **errp)
sysbus_realize(SYS_BUS_DEVICE(&s->armv7m), &error_abort);
/* Internal SRAM */
- memory_region_init_ram(&s->sram, NULL, "aspeed.sram", sc->sram_size, &err);
+ sram_name = g_strdup_printf("aspeed.sram.%d",
+ CPU(s->armv7m.cpu)->cpu_index);
+ memory_region_init_ram(&s->sram, OBJECT(s), sram_name, sc->sram_size, &err);
if (err != NULL) {
error_propagate(errp, err);
return;
@@ -252,7 +259,9 @@ static void aspeed_soc_ast1030_realize(DeviceState *dev_soc, Error **errp)
sc->irqmap[ASPEED_DEV_KCS] + aspeed_lpc_kcs_4));
/* UART */
- aspeed_soc_uart_init(s);
+ if (!aspeed_soc_uart_realize(s, errp)) {
+ return;
+ }
/* Timer */
object_property_set_link(OBJECT(&s->timerctrl), "scu", OBJECT(&s->scu),
diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c
index 3f0611a..aa2cd90 100644
--- a/hw/arm/aspeed_ast2600.c
+++ b/hw/arm/aspeed_ast2600.c
@@ -214,6 +214,10 @@ static void aspeed_soc_ast2600_init(Object *obj)
object_initialize_child(obj, "mii[*]", &s->mii[i], TYPE_ASPEED_MII);
}
+ for (i = 0; i < sc->uarts_num; i++) {
+ object_initialize_child(obj, "uart[*]", &s->uart[i], TYPE_SERIAL_MM);
+ }
+
snprintf(typename, sizeof(typename), TYPE_ASPEED_XDMA "-%s", socname);
object_initialize_child(obj, "xdma", &s->xdma, typename);
@@ -276,6 +280,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
Error *err = NULL;
qemu_irq irq;
+ g_autofree char *sram_name = NULL;
/* IO space */
aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->iomem), "aspeed.io",
@@ -335,8 +340,8 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
}
/* SRAM */
- memory_region_init_ram(&s->sram, OBJECT(dev), "aspeed.sram",
- sc->sram_size, &err);
+ sram_name = g_strdup_printf("aspeed.sram.%d", CPU(&s->cpu[0])->cpu_index);
+ memory_region_init_ram(&s->sram, OBJECT(s), sram_name, sc->sram_size, &err);
if (err) {
error_propagate(errp, err);
return;
@@ -385,7 +390,9 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
aspeed_soc_get_irq(s, ASPEED_DEV_ADC));
/* UART */
- aspeed_soc_uart_init(s);
+ if (!aspeed_soc_uart_realize(s, errp)) {
+ return;
+ }
/* I2C */
object_property_set_link(OBJECT(&s->i2c), "dram", OBJECT(s->dram_mr),
diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c
index 0f675e7..b05b9dd 100644
--- a/hw/arm/aspeed_soc.c
+++ b/hw/arm/aspeed_soc.c
@@ -208,6 +208,10 @@ static void aspeed_soc_init(Object *obj)
TYPE_FTGMAC100);
}
+ for (i = 0; i < sc->uarts_num; i++) {
+ object_initialize_child(obj, "uart[*]", &s->uart[i], TYPE_SERIAL_MM);
+ }
+
snprintf(typename, sizeof(typename), TYPE_ASPEED_XDMA "-%s", socname);
object_initialize_child(obj, "xdma", &s->xdma, typename);
@@ -239,6 +243,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
AspeedSoCState *s = ASPEED_SOC(dev);
AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
Error *err = NULL;
+ g_autofree char *sram_name = NULL;
/* IO space */
aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->iomem), "aspeed.io",
@@ -259,8 +264,8 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
}
/* SRAM */
- memory_region_init_ram(&s->sram, OBJECT(dev), "aspeed.sram",
- sc->sram_size, &err);
+ sram_name = g_strdup_printf("aspeed.sram.%d", CPU(&s->cpu[0])->cpu_index);
+ memory_region_init_ram(&s->sram, OBJECT(s), sram_name, sc->sram_size, &err);
if (err) {
error_propagate(errp, err);
return;
@@ -314,7 +319,9 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
aspeed_soc_get_irq(s, ASPEED_DEV_ADC));
/* UART */
- aspeed_soc_uart_init(s);
+ if (!aspeed_soc_uart_realize(s, errp)) {
+ return;
+ }
/* I2C */
object_property_set_link(OBJECT(&s->i2c), "dram", OBJECT(s->dram_mr),
@@ -481,8 +488,6 @@ static Property aspeed_soc_properties[] = {
MemoryRegion *),
DEFINE_PROP_LINK("dram", AspeedSoCState, dram_mr, TYPE_MEMORY_REGION,
MemoryRegion *),
- DEFINE_PROP_UINT32("uart-default", AspeedSoCState, uart_default,
- ASPEED_DEV_UART5),
DEFINE_PROP_END_OF_LIST(),
};
@@ -572,23 +577,37 @@ qemu_irq aspeed_soc_get_irq(AspeedSoCState *s, int dev)
return ASPEED_SOC_GET_CLASS(s)->get_irq(s, dev);
}
-void aspeed_soc_uart_init(AspeedSoCState *s)
+bool aspeed_soc_uart_realize(AspeedSoCState *s, Error **errp)
{
AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
- int i, uart;
-
- /* Attach an 8250 to the IO space as our UART */
- serial_mm_init(s->memory, sc->memmap[s->uart_default], 2,
- aspeed_soc_get_irq(s, s->uart_default), 38400,
- serial_hd(0), DEVICE_LITTLE_ENDIAN);
- for (i = 1, uart = ASPEED_DEV_UART1; i < sc->uarts_num; i++, uart++) {
- if (uart == s->uart_default) {
- uart++;
+ SerialMM *smm;
+
+ for (int i = 0, uart = ASPEED_DEV_UART1; i < sc->uarts_num; i++, uart++) {
+ smm = &s->uart[i];
+
+ /* Chardev property is set by the machine. */
+ qdev_prop_set_uint8(DEVICE(smm), "regshift", 2);
+ qdev_prop_set_uint32(DEVICE(smm), "baudbase", 38400);
+ qdev_set_legacy_instance_id(DEVICE(smm), sc->memmap[uart], 2);
+ qdev_prop_set_uint8(DEVICE(smm), "endianness", DEVICE_LITTLE_ENDIAN);
+ if (!sysbus_realize(SYS_BUS_DEVICE(smm), errp)) {
+ return false;
}
- serial_mm_init(s->memory, sc->memmap[uart], 2,
- aspeed_soc_get_irq(s, uart), 38400,
- serial_hd(i), DEVICE_LITTLE_ENDIAN);
+
+ sysbus_connect_irq(SYS_BUS_DEVICE(smm), 0, aspeed_soc_get_irq(s, uart));
+ aspeed_mmio_map(s, SYS_BUS_DEVICE(smm), 0, sc->memmap[uart]);
}
+
+ return true;
+}
+
+void aspeed_soc_uart_set_chr(AspeedSoCState *s, int dev, Chardev *chr)
+{
+ AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
+ int i = dev - ASPEED_DEV_UART1;
+
+ g_assert(0 <= i && i < ARRAY_SIZE(s->uart) && i < sc->uarts_num);
+ qdev_prop_set_chr(DEVICE(&s->uart[i]), "chardev", chr);
}
/*
diff --git a/hw/arm/fby35.c b/hw/arm/fby35.c
new file mode 100644
index 0000000..79605f3
--- /dev/null
+++ b/hw/arm/fby35.c
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) Meta Platforms, Inc. and affiliates. (http://www.meta.com)
+ *
+ * This code is licensed under the GPL version 2 or later. See the COPYING
+ * file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/units.h"
+#include "qapi/error.h"
+#include "sysemu/sysemu.h"
+#include "sysemu/block-backend.h"
+#include "hw/boards.h"
+#include "hw/qdev-clock.h"
+#include "hw/arm/aspeed_soc.h"
+#include "hw/arm/boot.h"
+
+#define TYPE_FBY35 MACHINE_TYPE_NAME("fby35")
+OBJECT_DECLARE_SIMPLE_TYPE(Fby35State, FBY35);
+
+struct Fby35State {
+ MachineState parent_obj;
+
+ MemoryRegion bmc_memory;
+ MemoryRegion bmc_dram;
+ MemoryRegion bmc_boot_rom;
+ MemoryRegion bic_memory;
+ Clock *bic_sysclk;
+
+ AspeedSoCState bmc;
+ AspeedSoCState bic;
+
+ bool mmio_exec;
+};
+
+#define FBY35_BMC_RAM_SIZE (2 * GiB)
+#define FBY35_BMC_FIRMWARE_ADDR 0x0
+
+static void fby35_bmc_write_boot_rom(DriveInfo *dinfo, MemoryRegion *mr,
+ hwaddr offset, size_t rom_size,
+ Error **errp)
+{
+ BlockBackend *blk = blk_by_legacy_dinfo(dinfo);
+ g_autofree void *storage = NULL;
+ int64_t size;
+
+ /*
+ * The block backend size should have already been 'validated' by
+ * the creation of the m25p80 object.
+ */
+ size = blk_getlength(blk);
+ if (size <= 0) {
+ error_setg(errp, "failed to get flash size");
+ return;
+ }
+
+ if (rom_size > size) {
+ rom_size = size;
+ }
+
+ storage = g_malloc0(rom_size);
+ if (blk_pread(blk, 0, rom_size, storage, 0) < 0) {
+ error_setg(errp, "failed to read the initial flash content");
+ return;
+ }
+
+ /* TODO: find a better way to install the ROM */
+ memcpy(memory_region_get_ram_ptr(mr) + offset, storage, rom_size);
+}
+
+static void fby35_bmc_init(Fby35State *s)
+{
+ DriveInfo *drive0 = drive_get(IF_MTD, 0, 0);
+
+ memory_region_init(&s->bmc_memory, OBJECT(s), "bmc-memory", UINT64_MAX);
+ memory_region_init_ram(&s->bmc_dram, OBJECT(s), "bmc-dram",
+ FBY35_BMC_RAM_SIZE, &error_abort);
+
+ object_initialize_child(OBJECT(s), "bmc", &s->bmc, "ast2600-a3");
+ object_property_set_int(OBJECT(&s->bmc), "ram-size", FBY35_BMC_RAM_SIZE,
+ &error_abort);
+ object_property_set_link(OBJECT(&s->bmc), "memory", OBJECT(&s->bmc_memory),
+ &error_abort);
+ object_property_set_link(OBJECT(&s->bmc), "dram", OBJECT(&s->bmc_dram),
+ &error_abort);
+ object_property_set_int(OBJECT(&s->bmc), "hw-strap1", 0x000000C0,
+ &error_abort);
+ object_property_set_int(OBJECT(&s->bmc), "hw-strap2", 0x00000003,
+ &error_abort);
+ aspeed_soc_uart_set_chr(&s->bmc, ASPEED_DEV_UART5, serial_hd(0));
+ qdev_realize(DEVICE(&s->bmc), NULL, &error_abort);
+
+ aspeed_board_init_flashes(&s->bmc.fmc, "n25q00", 2, 0);
+
+ /* Install first FMC flash content as a boot rom. */
+ if (drive0) {
+ AspeedSMCFlash *fl = &s->bmc.fmc.flashes[0];
+ MemoryRegion *boot_rom = g_new(MemoryRegion, 1);
+ uint64_t size = memory_region_size(&fl->mmio);
+
+ if (s->mmio_exec) {
+ memory_region_init_alias(boot_rom, NULL, "aspeed.boot_rom",
+ &fl->mmio, 0, size);
+ memory_region_add_subregion(&s->bmc_memory, FBY35_BMC_FIRMWARE_ADDR,
+ boot_rom);
+ } else {
+
+ memory_region_init_rom(boot_rom, NULL, "aspeed.boot_rom",
+ size, &error_abort);
+ memory_region_add_subregion(&s->bmc_memory, FBY35_BMC_FIRMWARE_ADDR,
+ boot_rom);
+ fby35_bmc_write_boot_rom(drive0, boot_rom, FBY35_BMC_FIRMWARE_ADDR,
+ size, &error_abort);
+ }
+ }
+}
+
+static void fby35_bic_init(Fby35State *s)
+{
+ s->bic_sysclk = clock_new(OBJECT(s), "SYSCLK");
+ clock_set_hz(s->bic_sysclk, 200000000ULL);
+
+ memory_region_init(&s->bic_memory, OBJECT(s), "bic-memory", UINT64_MAX);
+
+ object_initialize_child(OBJECT(s), "bic", &s->bic, "ast1030-a1");
+ qdev_connect_clock_in(DEVICE(&s->bic), "sysclk", s->bic_sysclk);
+ object_property_set_link(OBJECT(&s->bic), "memory", OBJECT(&s->bic_memory),
+ &error_abort);
+ aspeed_soc_uart_set_chr(&s->bic, ASPEED_DEV_UART5, serial_hd(1));
+ qdev_realize(DEVICE(&s->bic), NULL, &error_abort);
+
+ aspeed_board_init_flashes(&s->bic.fmc, "sst25vf032b", 2, 2);
+ aspeed_board_init_flashes(&s->bic.spi[0], "sst25vf032b", 2, 4);
+ aspeed_board_init_flashes(&s->bic.spi[1], "sst25vf032b", 2, 6);
+}
+
+static void fby35_init(MachineState *machine)
+{
+ Fby35State *s = FBY35(machine);
+
+ fby35_bmc_init(s);
+ fby35_bic_init(s);
+}
+
+
+static bool fby35_get_mmio_exec(Object *obj, Error **errp)
+{
+ return FBY35(obj)->mmio_exec;
+}
+
+static void fby35_set_mmio_exec(Object *obj, bool value, Error **errp)
+{
+ FBY35(obj)->mmio_exec = value;
+}
+
+static void fby35_instance_init(Object *obj)
+{
+ FBY35(obj)->mmio_exec = false;
+}
+
+static void fby35_class_init(ObjectClass *oc, void *data)
+{
+ MachineClass *mc = MACHINE_CLASS(oc);
+
+ mc->desc = "Meta Platforms fby35";
+ mc->init = fby35_init;
+ mc->no_floppy = 1;
+ mc->no_cdrom = 1;
+ mc->min_cpus = mc->max_cpus = mc->default_cpus = 3;
+
+ object_class_property_add_bool(oc, "execute-in-place",
+ fby35_get_mmio_exec,
+ fby35_set_mmio_exec);
+ object_class_property_set_description(oc, "execute-in-place",
+ "boot directly from CE0 flash device");
+}
+
+static const TypeInfo fby35_types[] = {
+ {
+ .name = MACHINE_TYPE_NAME("fby35"),
+ .parent = TYPE_MACHINE,
+ .class_init = fby35_class_init,
+ .instance_size = sizeof(Fby35State),
+ .instance_init = fby35_instance_init,
+ },
+};
+
+DEFINE_TYPES(fby35_types);
diff --git a/hw/arm/meson.build b/hw/arm/meson.build
index 2d83813..92f9f6e 100644
--- a/hw/arm/meson.build
+++ b/hw/arm/meson.build
@@ -51,7 +51,8 @@ arm_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files(
'aspeed_soc.c',
'aspeed.c',
'aspeed_ast2600.c',
- 'aspeed_ast10x0.c'))
+ 'aspeed_ast10x0.c',
+ 'fby35.c'))
arm_ss.add(when: 'CONFIG_MPS2', if_true: files('mps2.c'))
arm_ss.add(when: 'CONFIG_MPS2', if_true: files('mps2-tz.c'))
arm_ss.add(when: 'CONFIG_MSF2', if_true: files('msf2-soc.c'))
diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c
index 46dd9ee..a8d2519 100644
--- a/hw/block/m25p80.c
+++ b/hw/block/m25p80.c
@@ -36,21 +36,19 @@
#include "trace.h"
#include "qom/object.h"
-/* Fields for FlashPartInfo->flags */
-
-/* erase capabilities */
-#define ER_4K 1
-#define ER_32K 2
-/* set to allow the page program command to write 0s back to 1. Useful for
- * modelling EEPROM with SPI flash command set
- */
-#define EEPROM 0x100
-
/* 16 MiB max in 3 byte address mode */
#define MAX_3BYTES_SIZE 0x1000000
-
#define SPI_NOR_MAX_ID_LEN 6
+/* Fields for FlashPartInfo->flags */
+enum spi_flash_option_flags {
+ ER_4K = BIT(0),
+ ER_32K = BIT(1),
+ EEPROM = BIT(2),
+ HAS_SR_TB = BIT(3),
+ HAS_SR_BP3_BIT6 = BIT(4),
+};
+
typedef struct FlashPartInfo {
const char *part_name;
/*
@@ -251,7 +249,8 @@ static const FlashPartInfo known_devices[] = {
{ INFO("n25q512a11", 0x20bb20, 0, 64 << 10, 1024, ER_4K) },
{ INFO("n25q512a13", 0x20ba20, 0, 64 << 10, 1024, ER_4K) },
{ INFO("n25q128", 0x20ba18, 0, 64 << 10, 256, 0) },
- { INFO("n25q256a", 0x20ba19, 0, 64 << 10, 512, ER_4K) },
+ { INFO("n25q256a", 0x20ba19, 0, 64 << 10, 512,
+ ER_4K | HAS_SR_BP3_BIT6 | HAS_SR_TB) },
{ INFO("n25q512a", 0x20ba20, 0, 64 << 10, 1024, ER_4K) },
{ INFO("n25q512ax3", 0x20ba20, 0x1000, 64 << 10, 1024, ER_4K) },
{ INFO("mt25ql512ab", 0x20ba20, 0x1044, 64 << 10, 1024, ER_4K | ER_32K) },
@@ -478,6 +477,11 @@ struct Flash {
bool reset_enable;
bool quad_enable;
bool aai_enable;
+ bool block_protect0;
+ bool block_protect1;
+ bool block_protect2;
+ bool block_protect3;
+ bool top_bottom_bit;
bool status_register_write_disabled;
uint8_t ear;
@@ -623,12 +627,36 @@ void flash_write8(Flash *s, uint32_t addr, uint8_t data)
{
uint32_t page = addr / s->pi->page_size;
uint8_t prev = s->storage[s->cur_addr];
+ uint32_t block_protect_value = (s->block_protect3 << 3) |
+ (s->block_protect2 << 2) |
+ (s->block_protect1 << 1) |
+ (s->block_protect0 << 0);
if (!s->write_enable) {
qemu_log_mask(LOG_GUEST_ERROR, "M25P80: write with write protect!\n");
return;
}
+ if (block_protect_value > 0) {
+ uint32_t num_protected_sectors = 1 << (block_protect_value - 1);
+ uint32_t sector = addr / s->pi->sector_size;
+
+ /* top_bottom_bit == 0 means TOP */
+ if (!s->top_bottom_bit) {
+ if (s->pi->n_sectors <= sector + num_protected_sectors) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "M25P80: write with write protect!\n");
+ return;
+ }
+ } else {
+ if (sector < num_protected_sectors) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "M25P80: write with write protect!\n");
+ return;
+ }
+ }
+ }
+
if ((prev ^ data) & data) {
trace_m25p80_programming_zero_to_one(s, addr, prev, data);
}
@@ -726,6 +754,15 @@ static void complete_collecting_data(Flash *s)
break;
case WRSR:
s->status_register_write_disabled = extract32(s->data[0], 7, 1);
+ s->block_protect0 = extract32(s->data[0], 2, 1);
+ s->block_protect1 = extract32(s->data[0], 3, 1);
+ s->block_protect2 = extract32(s->data[0], 4, 1);
+ if (s->pi->flags & HAS_SR_TB) {
+ s->top_bottom_bit = extract32(s->data[0], 5, 1);
+ }
+ if (s->pi->flags & HAS_SR_BP3_BIT6) {
+ s->block_protect3 = extract32(s->data[0], 6, 1);
+ }
switch (get_man(s)) {
case MAN_SPANSION:
@@ -1212,6 +1249,15 @@ static void decode_new_cmd(Flash *s, uint32_t value)
case RDSR:
s->data[0] = (!!s->write_enable) << 1;
s->data[0] |= (!!s->status_register_write_disabled) << 7;
+ s->data[0] |= (!!s->block_protect0) << 2;
+ s->data[0] |= (!!s->block_protect1) << 3;
+ s->data[0] |= (!!s->block_protect2) << 4;
+ if (s->pi->flags & HAS_SR_TB) {
+ s->data[0] |= (!!s->top_bottom_bit) << 5;
+ }
+ if (s->pi->flags & HAS_SR_BP3_BIT6) {
+ s->data[0] |= (!!s->block_protect3) << 6;
+ }
if (get_man(s) == MAN_MACRONIX || get_man(s) == MAN_ISSI) {
s->data[0] |= (!!s->quad_enable) << 6;
@@ -1552,6 +1598,11 @@ static void m25p80_reset(DeviceState *d)
s->wp_level = true;
s->status_register_write_disabled = false;
+ s->block_protect0 = false;
+ s->block_protect1 = false;
+ s->block_protect2 = false;
+ s->block_protect3 = false;
+ s->top_bottom_bit = false;
reset_memory(s);
}
@@ -1638,6 +1689,32 @@ static const VMStateDescription vmstate_m25p80_write_protect = {
}
};
+static bool m25p80_block_protect_needed(void *opaque)
+{
+ Flash *s = (Flash *)opaque;
+
+ return s->block_protect0 ||
+ s->block_protect1 ||
+ s->block_protect2 ||
+ s->block_protect3 ||
+ s->top_bottom_bit;
+}
+
+static const VMStateDescription vmstate_m25p80_block_protect = {
+ .name = "m25p80/block_protect",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = m25p80_block_protect_needed,
+ .fields = (VMStateField[]) {
+ VMSTATE_BOOL(block_protect0, Flash),
+ VMSTATE_BOOL(block_protect1, Flash),
+ VMSTATE_BOOL(block_protect2, Flash),
+ VMSTATE_BOOL(block_protect3, Flash),
+ VMSTATE_BOOL(top_bottom_bit, Flash),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static const VMStateDescription vmstate_m25p80 = {
.name = "m25p80",
.version_id = 0,
@@ -1670,6 +1747,7 @@ static const VMStateDescription vmstate_m25p80 = {
&vmstate_m25p80_data_read_loop,
&vmstate_m25p80_aai_enable,
&vmstate_m25p80_write_protect,
+ &vmstate_m25p80_block_protect,
NULL
}
};
diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c
index a62a673..1e267dd 100644
--- a/hw/gpio/aspeed_gpio.c
+++ b/hw/gpio/aspeed_gpio.c
@@ -268,7 +268,7 @@ static ptrdiff_t aspeed_gpio_set_idx(AspeedGPIOState *s, GPIOSets *regs)
}
static void aspeed_gpio_update(AspeedGPIOState *s, GPIOSets *regs,
- uint32_t value)
+ uint32_t value, uint32_t mode_mask)
{
uint32_t input_mask = regs->input_mask;
uint32_t direction = regs->direction;
@@ -277,7 +277,8 @@ static void aspeed_gpio_update(AspeedGPIOState *s, GPIOSets *regs,
uint32_t diff;
int gpio;
- diff = old ^ new;
+ diff = (old ^ new);
+ diff &= mode_mask;
if (diff) {
for (gpio = 0; gpio < ASPEED_GPIOS_PER_SET; gpio++) {
uint32_t mask = 1 << gpio;
@@ -339,7 +340,7 @@ static void aspeed_gpio_set_pin_level(AspeedGPIOState *s, uint32_t set_idx,
value &= ~pin_mask;
}
- aspeed_gpio_update(s, &s->sets[set_idx], value);
+ aspeed_gpio_update(s, &s->sets[set_idx], value, ~s->sets[set_idx].direction);
}
/*
@@ -653,7 +654,7 @@ static void aspeed_gpio_write_index_mode(void *opaque, hwaddr offset,
reg_value = update_value_control_source(set, set->data_value,
reg_value);
set->data_read = reg_value;
- aspeed_gpio_update(s, set, reg_value);
+ aspeed_gpio_update(s, set, reg_value, set->direction);
return;
case gpio_reg_idx_direction:
reg_value = set->direction;
@@ -753,7 +754,7 @@ static void aspeed_gpio_write_index_mode(void *opaque, hwaddr offset,
__func__, offset, data, reg_idx_type);
return;
}
- aspeed_gpio_update(s, set, set->data_value);
+ aspeed_gpio_update(s, set, set->data_value, UINT32_MAX);
return;
}
@@ -799,7 +800,7 @@ static void aspeed_gpio_write(void *opaque, hwaddr offset, uint64_t data,
data &= props->output;
data = update_value_control_source(set, set->data_value, data);
set->data_read = data;
- aspeed_gpio_update(s, set, data);
+ aspeed_gpio_update(s, set, data, set->direction);
return;
case gpio_reg_direction:
/*
@@ -875,7 +876,7 @@ static void aspeed_gpio_write(void *opaque, hwaddr offset, uint64_t data,
PRIx64"\n", __func__, offset);
return;
}
- aspeed_gpio_update(s, set, set->data_value);
+ aspeed_gpio_update(s, set, set->data_value, UINT32_MAX);
return;
}
diff --git a/hw/i2c/pmbus_device.c b/hw/i2c/pmbus_device.c
index 749a33a..4071a88 100644
--- a/hw/i2c/pmbus_device.c
+++ b/hw/i2c/pmbus_device.c
@@ -261,6 +261,11 @@ void pmbus_check_limits(PMBusDevice *pmdev)
}
}
+void pmbus_idle(PMBusDevice *pmdev)
+{
+ pmdev->code = PMBUS_IDLE_STATE;
+}
+
/* assert the status_cml error upon receipt of malformed command */
static void pmbus_cml_error(PMBusDevice *pmdev)
{
@@ -980,6 +985,10 @@ static uint8_t pmbus_receive_byte(SMBusDevice *smd)
}
break;
+ case PMBUS_IDLE_STATE:
+ pmbus_send8(pmdev, PMBUS_ERR_BYTE);
+ break;
+
case PMBUS_CLEAR_FAULTS: /* Send Byte */
case PMBUS_PAGE_PLUS_WRITE: /* Block Write-only */
case PMBUS_STORE_DEFAULT_ALL: /* Send Byte */
diff --git a/hw/misc/aspeed_sbc.c b/hw/misc/aspeed_sbc.c
index bfa8b81..c6f328e 100644
--- a/hw/misc/aspeed_sbc.c
+++ b/hw/misc/aspeed_sbc.c
@@ -11,6 +11,7 @@
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "qemu/error-report.h"
+#include "hw/qdev-properties.h"
#include "hw/misc/aspeed_sbc.h"
#include "qapi/error.h"
#include "migration/vmstate.h"
@@ -19,6 +20,27 @@
#define R_STATUS (0x014 / 4)
#define R_QSR (0x040 / 4)
+/* R_STATUS */
+#define ABR_EN BIT(14) /* Mirrors SCU510[11] */
+#define ABR_IMAGE_SOURCE BIT(13)
+#define SPI_ABR_IMAGE_SOURCE BIT(12)
+#define SB_CRYPTO_KEY_EXP_DONE BIT(11)
+#define SB_CRYPTO_BUSY BIT(10)
+#define OTP_WP_EN BIT(9)
+#define OTP_ADDR_WP_EN BIT(8)
+#define LOW_SEC_KEY_EN BIT(7)
+#define SECURE_BOOT_EN BIT(6)
+#define UART_BOOT_EN BIT(5)
+/* bit 4 reserved*/
+#define OTP_CHARGE_PUMP_READY BIT(3)
+#define OTP_IDLE BIT(2)
+#define OTP_MEM_IDLE BIT(1)
+#define OTP_COMPARE_STATUS BIT(0)
+
+/* QSR */
+#define QSR_RSA_MASK (0x3 << 12)
+#define QSR_HASH_MASK (0x3 << 10)
+
static uint64_t aspeed_sbc_read(void *opaque, hwaddr addr, unsigned int size)
{
AspeedSBCState *s = ASPEED_SBC(opaque);
@@ -80,8 +102,17 @@ static void aspeed_sbc_reset(DeviceState *dev)
memset(s->regs, 0, sizeof(s->regs));
/* Set secure boot enabled with RSA4096_SHA256 and enable eMMC ABR */
- s->regs[R_STATUS] = 0x000044C6;
- s->regs[R_QSR] = 0x07C07C89;
+ s->regs[R_STATUS] = OTP_IDLE | OTP_MEM_IDLE;
+
+ if (s->emmc_abr) {
+ s->regs[R_STATUS] &= ABR_EN;
+ }
+
+ if (s->signing_settings) {
+ s->regs[R_STATUS] &= SECURE_BOOT_EN;
+ }
+
+ s->regs[R_QSR] = s->signing_settings;
}
static void aspeed_sbc_realize(DeviceState *dev, Error **errp)
@@ -105,6 +136,12 @@ static const VMStateDescription vmstate_aspeed_sbc = {
}
};
+static Property aspeed_sbc_properties[] = {
+ DEFINE_PROP_BOOL("emmc-abr", AspeedSBCState, emmc_abr, 0),
+ DEFINE_PROP_UINT32("signing-settings", AspeedSBCState, signing_settings, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
static void aspeed_sbc_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -112,6 +149,7 @@ static void aspeed_sbc_class_init(ObjectClass *klass, void *data)
dc->realize = aspeed_sbc_realize;
dc->reset = aspeed_sbc_reset;
dc->vmsd = &vmstate_aspeed_sbc;
+ device_class_set_props(dc, aspeed_sbc_properties);
}
static const TypeInfo aspeed_sbc_info = {
diff --git a/hw/sensor/isl_pmbus_vr.c b/hw/sensor/isl_pmbus_vr.c
index e11e028..eb344dd 100644
--- a/hw/sensor/isl_pmbus_vr.c
+++ b/hw/sensor/isl_pmbus_vr.c
@@ -15,6 +15,18 @@
static uint8_t isl_pmbus_vr_read_byte(PMBusDevice *pmdev)
{
+ ISLState *s = ISL69260(pmdev);
+
+ switch (pmdev->code) {
+ case PMBUS_IC_DEVICE_ID:
+ if (!s->ic_device_id_len) {
+ break;
+ }
+ pmbus_send(pmdev, s->ic_device_id, s->ic_device_id_len);
+ pmbus_idle(pmdev);
+ return 0;
+ }
+
qemu_log_mask(LOG_GUEST_ERROR,
"%s: reading from unsupported register: 0x%02x\n",
__func__, pmdev->code);
@@ -107,6 +119,18 @@ static void raa228000_exit_reset(Object *obj)
pmdev->pages[0].read_temperature_3 = 0;
}
+static void isl69259_exit_reset(Object *obj)
+{
+ ISLState *s = ISL69260(obj);
+ static const uint8_t ic_device_id[] = {0x04, 0x00, 0x81, 0xD2, 0x49, 0x3c};
+ g_assert(sizeof(ic_device_id) <= sizeof(s->ic_device_id));
+
+ isl_pmbus_vr_exit_reset(obj);
+
+ s->ic_device_id_len = sizeof(ic_device_id);
+ memcpy(s->ic_device_id, ic_device_id, sizeof(ic_device_id));
+}
+
static void isl_pmbus_vr_add_props(Object *obj, uint64_t *flags, uint8_t pages)
{
PMBusDevice *pmdev = PMBUS_DEVICE(obj);
@@ -245,6 +269,21 @@ static void raa229004_class_init(ObjectClass *klass, void *data)
isl_pmbus_vr_class_init(klass, data, 2);
}
+static void isl69259_class_init(ObjectClass *klass, void *data)
+{
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ dc->desc = "Renesas ISL69259 Digital Multiphase Voltage Regulator";
+ rc->phases.exit = isl69259_exit_reset;
+ isl_pmbus_vr_class_init(klass, data, 2);
+}
+
+static const TypeInfo isl69259_info = {
+ .name = TYPE_ISL69259,
+ .parent = TYPE_ISL69260,
+ .class_init = isl69259_class_init,
+};
+
static const TypeInfo isl69260_info = {
.name = TYPE_ISL69260,
.parent = TYPE_PMBUS_DEVICE,
@@ -271,6 +310,7 @@ static const TypeInfo raa228000_info = {
static void isl_pmbus_vr_register_types(void)
{
+ type_register_static(&isl69259_info);
type_register_static(&isl69260_info);
type_register_static(&raa228000_info);
type_register_static(&raa229004_info);