aspeed queue:

* m25p80 improvements (Iris)
 * Code cleanup in preparation of multi SoC machine (Peter)
 * New MAX31785 model (Mahesh)
 * New Qualcomm machines (Jae and Graeme)
 * Core I2C slave mode (Klaus)
 * Aspeed I2C slave mode for old and new register interface (Peter and Klaus)
 * New Aspeed PECI model (Peter)
 * Various small fixes
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEoPZlSPBIlev+awtgUaNDx8/77KEFAmK9UfQACgkQUaNDx8/7
 7KFYWhAAtlx3aaEacrn/ONNHjk6G9Fxku56gAbaIiuiaIWNOj3/T2frPsnmbO8x8
 EKrgUYB8i8PFve/fJYA5vZUzIddPTaHkULZ12JQoGVg0L9hDBbizslN5lJWRXoSv
 9r3DF9nahzLKRNvzoBfuKjHDQ2cwHoFgYmKmlYpDcgfmBcl16uzZy8jvxg/Tghur
 umH4IJMjeDNz/kLfINoO/m+kuFPVXmbTJNwl8uK5MUVDTgVSqharywWlUizugBVH
 StLE+GmBPylTuYXyiOzLTkoGJeeHp3sQ1DmyI4DD83odjnfxa0BGMGDVhD35exXi
 9tLY9FgQ4smATuyN0UGAKZTBmzpI+ov0HMzvH4lUMR8i8daBuEet3RVr/DqkOP4h
 LEVTRWTaTJip24ohgw4K/b86pI9nTJWVPGV56eZGYmnqufnvf/upNU65/nCsF/xD
 i1TdS+zJWxhjgGEepg9cTmxxUlA4jVNNbl6dvAgS5Jr6Igrd1BlCSXjmyhO3NRPZ
 bgOuvCb3RyxAY4+/9wphx2/t5X2VIU6R8EAjnh+7nIgBhOQU5SZ6uefFVYZq8xx+
 IYEDHj3saiRa4FHmyOgeRxRaQj/Vvs83PPti2rPmJuieqiClJmbE+XfTIamoxVIv
 5USlKmMRRVI69MjsjwFi/gOaV/N1EUgcFoYbnvwZ+Md3fg5+70M=
 =oUKu
 -----END PGP SIGNATURE-----

Merge tag 'pull-aspeed-20220630' of https://github.com/legoater/qemu into staging

aspeed queue:

* m25p80 improvements (Iris)
* Code cleanup in preparation of multi SoC machine (Peter)
* New MAX31785 model (Mahesh)
* New Qualcomm machines (Jae and Graeme)
* Core I2C slave mode (Klaus)
* Aspeed I2C slave mode for old and new register interface (Peter and Klaus)
* New Aspeed PECI model (Peter)
* Various small fixes

# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCAAdFiEEoPZlSPBIlev+awtgUaNDx8/77KEFAmK9UfQACgkQUaNDx8/7
# 7KFYWhAAtlx3aaEacrn/ONNHjk6G9Fxku56gAbaIiuiaIWNOj3/T2frPsnmbO8x8
# EKrgUYB8i8PFve/fJYA5vZUzIddPTaHkULZ12JQoGVg0L9hDBbizslN5lJWRXoSv
# 9r3DF9nahzLKRNvzoBfuKjHDQ2cwHoFgYmKmlYpDcgfmBcl16uzZy8jvxg/Tghur
# umH4IJMjeDNz/kLfINoO/m+kuFPVXmbTJNwl8uK5MUVDTgVSqharywWlUizugBVH
# StLE+GmBPylTuYXyiOzLTkoGJeeHp3sQ1DmyI4DD83odjnfxa0BGMGDVhD35exXi
# 9tLY9FgQ4smATuyN0UGAKZTBmzpI+ov0HMzvH4lUMR8i8daBuEet3RVr/DqkOP4h
# LEVTRWTaTJip24ohgw4K/b86pI9nTJWVPGV56eZGYmnqufnvf/upNU65/nCsF/xD
# i1TdS+zJWxhjgGEepg9cTmxxUlA4jVNNbl6dvAgS5Jr6Igrd1BlCSXjmyhO3NRPZ
# bgOuvCb3RyxAY4+/9wphx2/t5X2VIU6R8EAjnh+7nIgBhOQU5SZ6uefFVYZq8xx+
# IYEDHj3saiRa4FHmyOgeRxRaQj/Vvs83PPti2rPmJuieqiClJmbE+XfTIamoxVIv
# 5USlKmMRRVI69MjsjwFi/gOaV/N1EUgcFoYbnvwZ+Md3fg5+70M=
# =oUKu
# -----END PGP SIGNATURE-----
# gpg: Signature made Thu 30 Jun 2022 01:04:12 PM +0530
# 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-20220630' of https://github.com/legoater/qemu: (27 commits)
  hw/misc/aspeed: Add PECI controller
  hw/i2c/aspeed: Add new-registers DMA slave mode RX support
  hw/i2c/aspeed: add slave device in old register mode
  hw/i2c: add asynchronous send
  hw/i2c: support multiple masters
  hw/i2c/aspeed: Fix MASTER_EN missing error message
  hw/i2c/aspeed: Fix DMA len write-enable bit handling
  hw/i2c/aspeed: Fix R_I2CD_FUN_CTRL reference
  hw/arm/aspeed: firework: add I2C MUXes for VR channels
  hw/arm/aspeed: firework: Add Thermal Diodes
  hw/arm/aspeed: Add MAX31785 Fan controllers
  hw/sensor: add Maxim MAX31785 device
  hw/i2c: pmbus: Page #255 is valid page for read requests.
  hw/arm/aspeed: add Qualcomm Firework BMC machine
  hw/arm/aspeed: add support for the Qualcomm DC-SCM v1 board
  aspeed: Remove use of qemu_get_cpu
  aspeed: Map unimplemented devices in SoC memory
  aspeed: Remove usage of sysbus_mmio_map
  aspeed: Add memory property to Aspeed SoC
  aspeed: Set CPU memory property explicitly
  ...

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
master
Richard Henderson 2022-06-30 22:04:12 +05:30
commit d495e432c0
30 changed files with 1574 additions and 181 deletions

View File

@ -455,6 +455,8 @@ config ASPEED_SOC
select EMC141X
select UNIMP
select LED
select PMBUS
select MAX31785
config MPS2
bool

View File

@ -174,26 +174,9 @@ struct AspeedMachineState {
#define BLETCHLEY_BMC_HW_STRAP1 AST2600_EVB_HW_STRAP1
#define BLETCHLEY_BMC_HW_STRAP2 AST2600_EVB_HW_STRAP2
/*
* The max ram region is for firmwares that scan the address space
* with load/store to guess how much RAM the SoC has.
*/
static uint64_t max_ram_read(void *opaque, hwaddr offset, unsigned size)
{
return 0;
}
static void max_ram_write(void *opaque, hwaddr offset, uint64_t value,
unsigned size)
{
/* Discard writes */
}
static const MemoryRegionOps max_ram_ops = {
.read = max_ram_read,
.write = max_ram_write,
.endianness = DEVICE_NATIVE_ENDIAN,
};
/* Qualcomm DC-SCM hardware value */
#define QCOM_DC_SCM_V1_BMC_HW_STRAP1 0x00000000
#define QCOM_DC_SCM_V1_BMC_HW_STRAP2 0x00000041
#define AST_SMP_MAILBOX_BASE 0x1e6e2180
#define AST_SMP_MBOX_FIELD_ENTRY (AST_SMP_MAILBOX_BASE + 0x0)
@ -324,20 +307,16 @@ static void aspeed_machine_init(MachineState *machine)
AspeedMachineClass *amc = ASPEED_MACHINE_GET_CLASS(machine);
AspeedSoCClass *sc;
DriveInfo *drive0 = drive_get(IF_MTD, 0, 0);
ram_addr_t max_ram_size;
int i;
NICInfo *nd = &nd_table[0];
memory_region_init(&bmc->ram_container, NULL, "aspeed-ram-container",
4 * GiB);
memory_region_add_subregion(&bmc->ram_container, 0, machine->ram);
object_initialize_child(OBJECT(machine), "soc", &bmc->soc, amc->soc_name);
sc = ASPEED_SOC_GET_CLASS(&bmc->soc);
/*
* This will error out if isize is not supported by memory controller.
* This will error out if the RAM size is not supported by the
* memory controller of the SoC.
*/
object_property_set_uint(OBJECT(&bmc->soc), "ram-size", machine->ram_size,
&error_fatal);
@ -354,6 +333,8 @@ static void aspeed_machine_init(MachineState *machine)
&error_abort);
object_property_set_int(OBJECT(&bmc->soc), "hw-strap2", amc->hw_strap2,
&error_abort);
object_property_set_link(OBJECT(&bmc->soc), "memory",
OBJECT(get_system_memory()), &error_abort);
object_property_set_link(OBJECT(&bmc->soc), "dram",
OBJECT(machine->ram), &error_abort);
if (machine->kernel_filename) {
@ -369,16 +350,6 @@ static void aspeed_machine_init(MachineState *machine)
amc->uart_default);
qdev_realize(DEVICE(&bmc->soc), NULL, &error_abort);
memory_region_add_subregion(get_system_memory(),
sc->memmap[ASPEED_DEV_SDRAM],
&bmc->ram_container);
max_ram_size = object_property_get_uint(OBJECT(&bmc->soc), "max-ram-size",
&error_abort);
memory_region_init_io(&bmc->max_ram, NULL, &max_ram_ops, NULL,
"max_ram", max_ram_size - machine->ram_size);
memory_region_add_subregion(&bmc->ram_container, machine->ram_size, &bmc->max_ram);
aspeed_board_init_flashes(&bmc->soc.fmc,
bmc->fmc_model ? bmc->fmc_model : amc->fmc_model,
amc->num_cs, 0);
@ -611,7 +582,6 @@ static void witherspoon_bmc_i2c_init(AspeedMachineState *bmc)
LEDState *led;
/* Bus 3: TODO bmp280@77 */
/* Bus 3: TODO max31785@52 */
dev = DEVICE(i2c_slave_new(TYPE_PCA9552, 0x60));
qdev_prop_set_string(dev, "description", "pca1");
i2c_slave_realize_and_unref(I2C_SLAVE(dev),
@ -627,6 +597,7 @@ static void witherspoon_bmc_i2c_init(AspeedMachineState *bmc)
qdev_get_gpio_in(DEVICE(led), 0));
}
i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 3), "dps310", 0x76);
i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 3), "max31785", 0x52);
i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 4), "tmp423", 0x4c);
i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 5), "tmp423", 0x4c);
@ -771,13 +742,13 @@ static void rainier_bmc_i2c_init(AspeedMachineState *bmc)
create_pca9552(soc, 7, 0x31);
create_pca9552(soc, 7, 0x32);
create_pca9552(soc, 7, 0x33);
/* Bus 7: TODO max31785@52 */
create_pca9552(soc, 7, 0x60);
create_pca9552(soc, 7, 0x61);
i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 7), "dps310", 0x76);
/* Bus 7: TODO si7021-a20@20 */
i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 7), TYPE_TMP105,
0x48);
i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 7), "max31785", 0x52);
aspeed_eeprom_init(aspeed_i2c_get_bus(&soc->i2c, 7), 0x50, 64 * KiB);
aspeed_eeprom_init(aspeed_i2c_get_bus(&soc->i2c, 7), 0x51, 64 * KiB);
@ -984,6 +955,45 @@ static void fby35_i2c_init(AspeedMachineState *bmc)
*/
}
static void qcom_dc_scm_bmc_i2c_init(AspeedMachineState *bmc)
{
AspeedSoCState *soc = &bmc->soc;
i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 15), "tmp105", 0x4d);
}
static void qcom_dc_scm_firework_i2c_init(AspeedMachineState *bmc)
{
AspeedSoCState *soc = &bmc->soc;
I2CSlave *therm_mux, *cpuvr_mux;
/* Create the generic DC-SCM hardware */
qcom_dc_scm_bmc_i2c_init(bmc);
/* Now create the Firework specific hardware */
/* I2C7 CPUVR MUX */
cpuvr_mux = i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 7),
"pca9546", 0x70);
i2c_slave_create_simple(pca954x_i2c_get_bus(cpuvr_mux, 0), "pca9548", 0x72);
i2c_slave_create_simple(pca954x_i2c_get_bus(cpuvr_mux, 1), "pca9548", 0x72);
i2c_slave_create_simple(pca954x_i2c_get_bus(cpuvr_mux, 2), "pca9548", 0x72);
i2c_slave_create_simple(pca954x_i2c_get_bus(cpuvr_mux, 3), "pca9548", 0x72);
/* I2C8 Thermal Diodes*/
therm_mux = i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 8),
"pca9548", 0x70);
i2c_slave_create_simple(pca954x_i2c_get_bus(therm_mux, 0), TYPE_LM75, 0x4C);
i2c_slave_create_simple(pca954x_i2c_get_bus(therm_mux, 1), TYPE_LM75, 0x4C);
i2c_slave_create_simple(pca954x_i2c_get_bus(therm_mux, 2), TYPE_LM75, 0x48);
i2c_slave_create_simple(pca954x_i2c_get_bus(therm_mux, 3), TYPE_LM75, 0x48);
i2c_slave_create_simple(pca954x_i2c_get_bus(therm_mux, 4), TYPE_LM75, 0x48);
/* I2C9 Fan Controller (MAX31785) */
i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 9), "max31785", 0x52);
i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 9), "max31785", 0x54);
}
static bool aspeed_get_mmio_exec(Object *obj, Error **errp)
{
return ASPEED_MACHINE(obj)->mmio_exec;
@ -1371,6 +1381,8 @@ static void aspeed_minibmc_machine_init(MachineState *machine)
object_initialize_child(OBJECT(machine), "soc", &bmc->soc, amc->soc_name);
qdev_connect_clock_in(DEVICE(&bmc->soc), "sysclk", sysclk);
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);
qdev_realize(DEVICE(&bmc->soc), NULL, &error_abort);
@ -1429,6 +1441,46 @@ static void aspeed_minibmc_machine_ast1030_evb_class_init(ObjectClass *oc,
amc->macs_mask = 0;
}
static void aspeed_machine_qcom_dc_scm_v1_class_init(ObjectClass *oc,
void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc);
mc->desc = "Qualcomm DC-SCM V1 BMC (Cortex A7)";
amc->soc_name = "ast2600-a3";
amc->hw_strap1 = QCOM_DC_SCM_V1_BMC_HW_STRAP1;
amc->hw_strap2 = QCOM_DC_SCM_V1_BMC_HW_STRAP2;
amc->fmc_model = "n25q512a";
amc->spi_model = "n25q512a";
amc->num_cs = 2;
amc->macs_mask = ASPEED_MAC2_ON | ASPEED_MAC3_ON;
amc->i2c_init = qcom_dc_scm_bmc_i2c_init;
mc->default_ram_size = 1 * GiB;
mc->default_cpus = mc->min_cpus = mc->max_cpus =
aspeed_soc_num_cpus(amc->soc_name);
};
static void aspeed_machine_qcom_firework_class_init(ObjectClass *oc,
void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc);
mc->desc = "Qualcomm DC-SCM V1/Firework BMC (Cortex A7)";
amc->soc_name = "ast2600-a3";
amc->hw_strap1 = QCOM_DC_SCM_V1_BMC_HW_STRAP1;
amc->hw_strap2 = QCOM_DC_SCM_V1_BMC_HW_STRAP2;
amc->fmc_model = "n25q512a";
amc->spi_model = "n25q512a";
amc->num_cs = 2;
amc->macs_mask = ASPEED_MAC2_ON | ASPEED_MAC3_ON;
amc->i2c_init = qcom_dc_scm_firework_i2c_init;
mc->default_ram_size = 1 * GiB;
mc->default_cpus = mc->min_cpus = mc->max_cpus =
aspeed_soc_num_cpus(amc->soc_name);
};
static const TypeInfo aspeed_machine_types[] = {
{
.name = MACHINE_TYPE_NAME("palmetto-bmc"),
@ -1466,6 +1518,14 @@ static const TypeInfo aspeed_machine_types[] = {
.name = MACHINE_TYPE_NAME("g220a-bmc"),
.parent = TYPE_ASPEED_MACHINE,
.class_init = aspeed_machine_g220a_class_init,
}, {
.name = MACHINE_TYPE_NAME("qcom-dc-scm-v1-bmc"),
.parent = TYPE_ASPEED_MACHINE,
.class_init = aspeed_machine_qcom_dc_scm_v1_class_init,
}, {
.name = MACHINE_TYPE_NAME("qcom-firework-bmc"),
.parent = TYPE_ASPEED_MACHINE,
.class_init = aspeed_machine_qcom_firework_class_init,
}, {
.name = MACHINE_TYPE_NAME("fp5280g2-bmc"),
.parent = TYPE_ASPEED_MACHINE,

View File

@ -47,6 +47,7 @@ static const hwaddr aspeed_soc_ast1030_memmap[] = {
[ASPEED_DEV_UART13] = 0x7E790700,
[ASPEED_DEV_WDT] = 0x7E785000,
[ASPEED_DEV_LPC] = 0x7E789000,
[ASPEED_DEV_PECI] = 0x7E78B000,
[ASPEED_DEV_I2C] = 0x7E7B0000,
};
@ -75,6 +76,7 @@ static const int aspeed_soc_ast1030_irqmap[] = {
[ASPEED_DEV_TIMER8] = 23,
[ASPEED_DEV_WDT] = 24,
[ASPEED_DEV_LPC] = 35,
[ASPEED_DEV_PECI] = 38,
[ASPEED_DEV_FMC] = 39,
[ASPEED_DEV_PWM] = 44,
[ASPEED_DEV_ADC] = 46,
@ -133,6 +135,8 @@ static void aspeed_soc_ast1030_init(Object *obj)
object_initialize_child(obj, "lpc", &s->lpc, TYPE_ASPEED_LPC);
object_initialize_child(obj, "peci", &s->peci, TYPE_ASPEED_PECI);
object_initialize_child(obj, "sbc", &s->sbc, TYPE_ASPEED_SBC);
for (i = 0; i < sc->wdts_num; i++) {
@ -142,13 +146,16 @@ static void aspeed_soc_ast1030_init(Object *obj)
snprintf(typename, sizeof(typename), "aspeed.gpio-%s", socname);
object_initialize_child(obj, "gpio", &s->gpio, typename);
object_initialize_child(obj, "iomem", &s->iomem, TYPE_UNIMPLEMENTED_DEVICE);
object_initialize_child(obj, "sbc-unimplemented", &s->sbc_unimplemented,
TYPE_UNIMPLEMENTED_DEVICE);
}
static void aspeed_soc_ast1030_realize(DeviceState *dev_soc, Error **errp)
{
AspeedSoCState *s = ASPEED_SOC(dev_soc);
AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
MemoryRegion *system_memory = get_system_memory();
DeviceState *armv7m;
Error *err = NULL;
int i;
@ -159,12 +166,12 @@ static void aspeed_soc_ast1030_realize(DeviceState *dev_soc, Error **errp)
}
/* General I/O memory space to catch all unimplemented device */
create_unimplemented_device("aspeed.sbc",
sc->memmap[ASPEED_DEV_SBC],
0x40000);
create_unimplemented_device("aspeed.io",
sc->memmap[ASPEED_DEV_IOMEM],
ASPEED_SOC_IOMEM_SIZE);
aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->iomem), "aspeed.io",
sc->memmap[ASPEED_DEV_IOMEM],
ASPEED_SOC_IOMEM_SIZE);
aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->sbc_unimplemented),
"aspeed.sbc", sc->memmap[ASPEED_DEV_SBC],
0x40000);
/* AST1030 CPU Core */
armv7m = DEVICE(&s->armv7m);
@ -172,7 +179,7 @@ static void aspeed_soc_ast1030_realize(DeviceState *dev_soc, Error **errp)
qdev_prop_set_string(armv7m, "cpu-type", sc->cpu_type);
qdev_connect_clock_in(armv7m, "cpuclk", s->sysclk);
object_property_set_link(OBJECT(&s->armv7m), "memory",
OBJECT(system_memory), &error_abort);
OBJECT(s->memory), &error_abort);
sysbus_realize(SYS_BUS_DEVICE(&s->armv7m), &error_abort);
/* Internal SRAM */
@ -181,7 +188,7 @@ static void aspeed_soc_ast1030_realize(DeviceState *dev_soc, Error **errp)
error_propagate(errp, err);
return;
}
memory_region_add_subregion(system_memory,
memory_region_add_subregion(s->memory,
sc->memmap[ASPEED_DEV_SRAM],
&s->sram);
@ -189,7 +196,7 @@ static void aspeed_soc_ast1030_realize(DeviceState *dev_soc, Error **errp)
if (!sysbus_realize(SYS_BUS_DEVICE(&s->scu), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->scu), 0, sc->memmap[ASPEED_DEV_SCU]);
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->scu), 0, sc->memmap[ASPEED_DEV_SCU]);
/* I2C */
@ -198,7 +205,7 @@ static void aspeed_soc_ast1030_realize(DeviceState *dev_soc, Error **errp)
if (!sysbus_realize(SYS_BUS_DEVICE(&s->i2c), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c), 0, sc->memmap[ASPEED_DEV_I2C]);
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->i2c), 0, sc->memmap[ASPEED_DEV_I2C]);
for (i = 0; i < ASPEED_I2C_GET_CLASS(&s->i2c)->num_busses; i++) {
qemu_irq irq = qdev_get_gpio_in(DEVICE(&s->armv7m),
sc->irqmap[ASPEED_DEV_I2C] + i);
@ -206,11 +213,20 @@ static void aspeed_soc_ast1030_realize(DeviceState *dev_soc, Error **errp)
sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c.busses[i]), 0, irq);
}
/* PECI */
if (!sysbus_realize(SYS_BUS_DEVICE(&s->peci), errp)) {
return;
}
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->peci), 0,
sc->memmap[ASPEED_DEV_PECI]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->peci), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_PECI));
/* LPC */
if (!sysbus_realize(SYS_BUS_DEVICE(&s->lpc), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->lpc), 0, sc->memmap[ASPEED_DEV_LPC]);
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->lpc), 0, sc->memmap[ASPEED_DEV_LPC]);
/* Connect the LPC IRQ to the GIC. It is otherwise unused. */
sysbus_connect_irq(SYS_BUS_DEVICE(&s->lpc), 0,
@ -244,7 +260,7 @@ static void aspeed_soc_ast1030_realize(DeviceState *dev_soc, Error **errp)
if (!sysbus_realize(SYS_BUS_DEVICE(&s->timerctrl), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->timerctrl), 0,
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->timerctrl), 0,
sc->memmap[ASPEED_DEV_TIMER1]);
for (i = 0; i < ASPEED_TIMER_NR_TIMERS; i++) {
qemu_irq irq = aspeed_soc_get_irq(s, ASPEED_DEV_TIMER1 + i);
@ -255,7 +271,7 @@ static void aspeed_soc_ast1030_realize(DeviceState *dev_soc, Error **errp)
if (!sysbus_realize(SYS_BUS_DEVICE(&s->adc), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->adc), 0, sc->memmap[ASPEED_DEV_ADC]);
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->adc), 0, sc->memmap[ASPEED_DEV_ADC]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->adc), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_ADC));
@ -265,8 +281,8 @@ static void aspeed_soc_ast1030_realize(DeviceState *dev_soc, Error **errp)
if (!sysbus_realize(SYS_BUS_DEVICE(&s->fmc), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->fmc), 0, sc->memmap[ASPEED_DEV_FMC]);
sysbus_mmio_map(SYS_BUS_DEVICE(&s->fmc), 1,
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->fmc), 0, sc->memmap[ASPEED_DEV_FMC]);
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->fmc), 1,
ASPEED_SMC_GET_CLASS(&s->fmc)->flash_window_base);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->fmc), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_FMC));
@ -278,9 +294,9 @@ static void aspeed_soc_ast1030_realize(DeviceState *dev_soc, Error **errp)
if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 0,
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->spi[i]), 0,
sc->memmap[ASPEED_DEV_SPI1 + i]);
sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 1,
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->spi[i]), 1,
ASPEED_SMC_GET_CLASS(&s->spi[i])->flash_window_base);
}
@ -288,7 +304,7 @@ static void aspeed_soc_ast1030_realize(DeviceState *dev_soc, Error **errp)
if (!sysbus_realize(SYS_BUS_DEVICE(&s->sbc), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->sbc), 0, sc->memmap[ASPEED_DEV_SBC]);
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->sbc), 0, sc->memmap[ASPEED_DEV_SBC]);
/* Watch dog */
for (i = 0; i < sc->wdts_num; i++) {
@ -299,7 +315,7 @@ static void aspeed_soc_ast1030_realize(DeviceState *dev_soc, Error **errp)
if (!sysbus_realize(SYS_BUS_DEVICE(&s->wdt[i]), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt[i]), 0,
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->wdt[i]), 0,
sc->memmap[ASPEED_DEV_WDT] + i * awc->offset);
}
@ -307,7 +323,8 @@ static void aspeed_soc_ast1030_realize(DeviceState *dev_soc, Error **errp)
if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio), 0, sc->memmap[ASPEED_DEV_GPIO]);
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->gpio), 0,
sc->memmap[ASPEED_DEV_GPIO]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_GPIO));
}

View File

@ -59,6 +59,7 @@ static const hwaddr aspeed_soc_ast2600_memmap[] = {
[ASPEED_DEV_LPC] = 0x1E789000,
[ASPEED_DEV_IBT] = 0x1E789140,
[ASPEED_DEV_I2C] = 0x1E78A000,
[ASPEED_DEV_PECI] = 0x1E78B000,
[ASPEED_DEV_UART1] = 0x1E783000,
[ASPEED_DEV_UART2] = 0x1E78D000,
[ASPEED_DEV_UART3] = 0x1E78E000,
@ -122,6 +123,7 @@ static const int aspeed_soc_ast2600_irqmap[] = {
[ASPEED_DEV_LPC] = 35,
[ASPEED_DEV_IBT] = 143,
[ASPEED_DEV_I2C] = 110, /* 110 -> 125 */
[ASPEED_DEV_PECI] = 38,
[ASPEED_DEV_ETH1] = 2,
[ASPEED_DEV_ETH2] = 3,
[ASPEED_DEV_HACE] = 4,
@ -180,6 +182,8 @@ static void aspeed_soc_ast2600_init(Object *obj)
snprintf(typename, sizeof(typename), "aspeed.i2c-%s", socname);
object_initialize_child(obj, "i2c", &s->i2c, typename);
object_initialize_child(obj, "peci", &s->peci, TYPE_ASPEED_PECI);
snprintf(typename, sizeof(typename), "aspeed.fmc-%s", socname);
object_initialize_child(obj, "fmc", &s->fmc, typename);
@ -197,8 +201,6 @@ static void aspeed_soc_ast2600_init(Object *obj)
object_initialize_child(obj, "sdmc", &s->sdmc, typename);
object_property_add_alias(obj, "ram-size", OBJECT(&s->sdmc),
"ram-size");
object_property_add_alias(obj, "max-ram-size", OBJECT(&s->sdmc),
"max-ram-size");
for (i = 0; i < sc->wdts_num; i++) {
snprintf(typename, sizeof(typename), "aspeed.wdt-%s", socname);
@ -248,6 +250,13 @@ static void aspeed_soc_ast2600_init(Object *obj)
object_initialize_child(obj, "i3c", &s->i3c, TYPE_ASPEED_I3C);
object_initialize_child(obj, "sbc", &s->sbc, TYPE_ASPEED_SBC);
object_initialize_child(obj, "iomem", &s->iomem, TYPE_UNIMPLEMENTED_DEVICE);
object_initialize_child(obj, "video", &s->video, TYPE_UNIMPLEMENTED_DEVICE);
object_initialize_child(obj, "dpmcu", &s->dpmcu, TYPE_UNIMPLEMENTED_DEVICE);
object_initialize_child(obj, "emmc-boot-controller",
&s->emmc_boot_controller,
TYPE_UNIMPLEMENTED_DEVICE);
}
/*
@ -269,17 +278,18 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
qemu_irq irq;
/* IO space */
create_unimplemented_device("aspeed_soc.io", sc->memmap[ASPEED_DEV_IOMEM],
ASPEED_SOC_IOMEM_SIZE);
aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->iomem), "aspeed.io",
sc->memmap[ASPEED_DEV_IOMEM],
ASPEED_SOC_IOMEM_SIZE);
/* Video engine stub */
create_unimplemented_device("aspeed.video", sc->memmap[ASPEED_DEV_VIDEO],
0x1000);
aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->video), "aspeed.video",
sc->memmap[ASPEED_DEV_VIDEO], 0x1000);
/* eMMC Boot Controller stub */
create_unimplemented_device("aspeed.emmc-boot-controller",
sc->memmap[ASPEED_DEV_EMMC_BC],
0x1000);
aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->emmc_boot_controller),
"aspeed.emmc-boot-controller",
sc->memmap[ASPEED_DEV_EMMC_BC], 0x1000);
/* CPU */
for (i = 0; i < sc->num_cpus; i++) {
@ -292,6 +302,8 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
object_property_set_int(OBJECT(&s->cpu[i]), "cntfrq", 1125000000,
&error_abort);
object_property_set_link(OBJECT(&s->cpu[i]), "memory",
OBJECT(s->memory), &error_abort);
if (!qdev_realize(DEVICE(&s->cpu[i]), NULL, errp)) {
return;
@ -306,11 +318,11 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
&error_abort);
sysbus_realize(SYS_BUS_DEVICE(&s->a7mpcore), &error_abort);
sysbus_mmio_map(SYS_BUS_DEVICE(&s->a7mpcore), 0, ASPEED_A7MPCORE_ADDR);
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->a7mpcore), 0, ASPEED_A7MPCORE_ADDR);
for (i = 0; i < sc->num_cpus; i++) {
SysBusDevice *sbd = SYS_BUS_DEVICE(&s->a7mpcore);
DeviceState *d = DEVICE(qemu_get_cpu(i));
DeviceState *d = DEVICE(&s->cpu[i]);
irq = qdev_get_gpio_in(d, ARM_CPU_IRQ);
sysbus_connect_irq(sbd, i, irq);
@ -329,24 +341,25 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
error_propagate(errp, err);
return;
}
memory_region_add_subregion(get_system_memory(),
memory_region_add_subregion(s->memory,
sc->memmap[ASPEED_DEV_SRAM], &s->sram);
/* DPMCU */
create_unimplemented_device("aspeed.dpmcu", sc->memmap[ASPEED_DEV_DPMCU],
ASPEED_SOC_DPMCU_SIZE);
aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->dpmcu), "aspeed.dpmcu",
sc->memmap[ASPEED_DEV_DPMCU],
ASPEED_SOC_DPMCU_SIZE);
/* SCU */
if (!sysbus_realize(SYS_BUS_DEVICE(&s->scu), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->scu), 0, sc->memmap[ASPEED_DEV_SCU]);
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->scu), 0, sc->memmap[ASPEED_DEV_SCU]);
/* RTC */
if (!sysbus_realize(SYS_BUS_DEVICE(&s->rtc), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->rtc), 0, sc->memmap[ASPEED_DEV_RTC]);
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->rtc), 0, sc->memmap[ASPEED_DEV_RTC]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->rtc), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_RTC));
@ -356,7 +369,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
if (!sysbus_realize(SYS_BUS_DEVICE(&s->timerctrl), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->timerctrl), 0,
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->timerctrl), 0,
sc->memmap[ASPEED_DEV_TIMER1]);
for (i = 0; i < ASPEED_TIMER_NR_TIMERS; i++) {
qemu_irq irq = aspeed_soc_get_irq(s, ASPEED_DEV_TIMER1 + i);
@ -367,7 +380,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
if (!sysbus_realize(SYS_BUS_DEVICE(&s->adc), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->adc), 0, sc->memmap[ASPEED_DEV_ADC]);
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->adc), 0, sc->memmap[ASPEED_DEV_ADC]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->adc), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_ADC));
@ -380,7 +393,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
if (!sysbus_realize(SYS_BUS_DEVICE(&s->i2c), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c), 0, sc->memmap[ASPEED_DEV_I2C]);
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->i2c), 0, sc->memmap[ASPEED_DEV_I2C]);
for (i = 0; i < ASPEED_I2C_GET_CLASS(&s->i2c)->num_busses; i++) {
qemu_irq irq = qdev_get_gpio_in(DEVICE(&s->a7mpcore),
sc->irqmap[ASPEED_DEV_I2C] + i);
@ -388,14 +401,23 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c.busses[i]), 0, irq);
}
/* PECI */
if (!sysbus_realize(SYS_BUS_DEVICE(&s->peci), errp)) {
return;
}
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->peci), 0,
sc->memmap[ASPEED_DEV_PECI]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->peci), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_PECI));
/* FMC, The number of CS is set at the board level */
object_property_set_link(OBJECT(&s->fmc), "dram", OBJECT(s->dram_mr),
&error_abort);
if (!sysbus_realize(SYS_BUS_DEVICE(&s->fmc), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->fmc), 0, sc->memmap[ASPEED_DEV_FMC]);
sysbus_mmio_map(SYS_BUS_DEVICE(&s->fmc), 1,
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->fmc), 0, sc->memmap[ASPEED_DEV_FMC]);
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->fmc), 1,
ASPEED_SMC_GET_CLASS(&s->fmc)->flash_window_base);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->fmc), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_FMC));
@ -407,9 +429,9 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 0,
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->spi[i]), 0,
sc->memmap[ASPEED_DEV_SPI1 + i]);
sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 1,
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->spi[i]), 1,
ASPEED_SMC_GET_CLASS(&s->spi[i])->flash_window_base);
}
@ -418,7 +440,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
if (!sysbus_realize(SYS_BUS_DEVICE(&s->ehci[i]), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->ehci[i]), 0,
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->ehci[i]), 0,
sc->memmap[ASPEED_DEV_EHCI1 + i]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->ehci[i]), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_EHCI1 + i));
@ -428,7 +450,8 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
if (!sysbus_realize(SYS_BUS_DEVICE(&s->sdmc), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->sdmc), 0, sc->memmap[ASPEED_DEV_SDMC]);
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->sdmc), 0,
sc->memmap[ASPEED_DEV_SDMC]);
/* Watch dog */
for (i = 0; i < sc->wdts_num; i++) {
@ -439,10 +462,15 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
if (!sysbus_realize(SYS_BUS_DEVICE(&s->wdt[i]), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt[i]), 0,
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->wdt[i]), 0,
sc->memmap[ASPEED_DEV_WDT] + i * awc->offset);
}
/* RAM */
if (!aspeed_soc_dram_init(s, errp)) {
return;
}
/* Net */
for (i = 0; i < sc->macs_num; i++) {
object_property_set_bool(OBJECT(&s->ftgmac100[i]), "aspeed", true,
@ -450,7 +478,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
if (!sysbus_realize(SYS_BUS_DEVICE(&s->ftgmac100[i]), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->ftgmac100[i]), 0,
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->ftgmac100[i]), 0,
sc->memmap[ASPEED_DEV_ETH1 + i]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->ftgmac100[i]), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_ETH1 + i));
@ -461,7 +489,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->mii[i]), 0,
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->mii[i]), 0,
sc->memmap[ASPEED_DEV_MII1 + i]);
}
@ -469,7 +497,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
if (!sysbus_realize(SYS_BUS_DEVICE(&s->xdma), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->xdma), 0,
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->xdma), 0,
sc->memmap[ASPEED_DEV_XDMA]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->xdma), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_XDMA));
@ -478,14 +506,14 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio), 0, sc->memmap[ASPEED_DEV_GPIO]);
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->gpio), 0, sc->memmap[ASPEED_DEV_GPIO]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_GPIO));
if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio_1_8v), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio_1_8v), 0,
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->gpio_1_8v), 0,
sc->memmap[ASPEED_DEV_GPIO_1_8V]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio_1_8v), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_GPIO_1_8V));
@ -494,7 +522,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
if (!sysbus_realize(SYS_BUS_DEVICE(&s->sdhci), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->sdhci), 0,
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->sdhci), 0,
sc->memmap[ASPEED_DEV_SDHCI]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->sdhci), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_SDHCI));
@ -503,7 +531,8 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
if (!sysbus_realize(SYS_BUS_DEVICE(&s->emmc), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->emmc), 0, sc->memmap[ASPEED_DEV_EMMC]);
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->emmc), 0,
sc->memmap[ASPEED_DEV_EMMC]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->emmc), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_EMMC));
@ -511,7 +540,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
if (!sysbus_realize(SYS_BUS_DEVICE(&s->lpc), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->lpc), 0, sc->memmap[ASPEED_DEV_LPC]);
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->lpc), 0, sc->memmap[ASPEED_DEV_LPC]);
/* Connect the LPC IRQ to the GIC. It is otherwise unused. */
sysbus_connect_irq(SYS_BUS_DEVICE(&s->lpc), 0,
@ -547,7 +576,8 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
if (!sysbus_realize(SYS_BUS_DEVICE(&s->hace), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->hace), 0, sc->memmap[ASPEED_DEV_HACE]);
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->hace), 0,
sc->memmap[ASPEED_DEV_HACE]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->hace), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_HACE));
@ -555,7 +585,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
if (!sysbus_realize(SYS_BUS_DEVICE(&s->i3c), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->i3c), 0, sc->memmap[ASPEED_DEV_I3C]);
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->i3c), 0, sc->memmap[ASPEED_DEV_I3C]);
for (i = 0; i < ASPEED_I3C_NR_DEVICES; i++) {
qemu_irq irq = qdev_get_gpio_in(DEVICE(&s->a7mpcore),
sc->irqmap[ASPEED_DEV_I3C] + i);
@ -567,7 +597,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
if (!sysbus_realize(SYS_BUS_DEVICE(&s->sbc), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->sbc), 0, sc->memmap[ASPEED_DEV_SBC]);
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->sbc), 0, sc->memmap[ASPEED_DEV_SBC]);
}
static void aspeed_soc_ast2600_class_init(ObjectClass *oc, void *data)

View File

@ -11,6 +11,7 @@
*/
#include "qemu/osdep.h"
#include "qemu/units.h"
#include "qapi/error.h"
#include "hw/misc/unimp.h"
#include "hw/arm/aspeed_soc.h"
@ -45,6 +46,7 @@ static const hwaddr aspeed_soc_ast2400_memmap[] = {
[ASPEED_DEV_LPC] = 0x1E789000,
[ASPEED_DEV_IBT] = 0x1E789140,
[ASPEED_DEV_I2C] = 0x1E78A000,
[ASPEED_DEV_PECI] = 0x1E78B000,
[ASPEED_DEV_ETH1] = 0x1E660000,
[ASPEED_DEV_ETH2] = 0x1E680000,
[ASPEED_DEV_UART1] = 0x1E783000,
@ -80,6 +82,7 @@ static const hwaddr aspeed_soc_ast2500_memmap[] = {
[ASPEED_DEV_LPC] = 0x1E789000,
[ASPEED_DEV_IBT] = 0x1E789140,
[ASPEED_DEV_I2C] = 0x1E78A000,
[ASPEED_DEV_PECI] = 0x1E78B000,
[ASPEED_DEV_ETH1] = 0x1E660000,
[ASPEED_DEV_ETH2] = 0x1E680000,
[ASPEED_DEV_UART1] = 0x1E783000,
@ -118,6 +121,7 @@ static const int aspeed_soc_ast2400_irqmap[] = {
[ASPEED_DEV_PWM] = 28,
[ASPEED_DEV_LPC] = 8,
[ASPEED_DEV_I2C] = 12,
[ASPEED_DEV_PECI] = 15,
[ASPEED_DEV_ETH1] = 2,
[ASPEED_DEV_ETH2] = 3,
[ASPEED_DEV_XDMA] = 6,
@ -174,6 +178,8 @@ static void aspeed_soc_init(Object *obj)
snprintf(typename, sizeof(typename), "aspeed.i2c-%s", socname);
object_initialize_child(obj, "i2c", &s->i2c, typename);
object_initialize_child(obj, "peci", &s->peci, TYPE_ASPEED_PECI);
snprintf(typename, sizeof(typename), "aspeed.fmc-%s", socname);
object_initialize_child(obj, "fmc", &s->fmc, typename);
@ -191,8 +197,6 @@ static void aspeed_soc_init(Object *obj)
object_initialize_child(obj, "sdmc", &s->sdmc, typename);
object_property_add_alias(obj, "ram-size", OBJECT(&s->sdmc),
"ram-size");
object_property_add_alias(obj, "max-ram-size", OBJECT(&s->sdmc),
"max-ram-size");
for (i = 0; i < sc->wdts_num; i++) {
snprintf(typename, sizeof(typename), "aspeed.wdt-%s", socname);
@ -224,6 +228,9 @@ static void aspeed_soc_init(Object *obj)
snprintf(typename, sizeof(typename), "aspeed.hace-%s", socname);
object_initialize_child(obj, "hace", &s->hace, typename);
object_initialize_child(obj, "iomem", &s->iomem, TYPE_UNIMPLEMENTED_DEVICE);
object_initialize_child(obj, "video", &s->video, TYPE_UNIMPLEMENTED_DEVICE);
}
static void aspeed_soc_realize(DeviceState *dev, Error **errp)
@ -234,15 +241,18 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
Error *err = NULL;
/* IO space */
create_unimplemented_device("aspeed_soc.io", sc->memmap[ASPEED_DEV_IOMEM],
ASPEED_SOC_IOMEM_SIZE);
aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->iomem), "aspeed.io",
sc->memmap[ASPEED_DEV_IOMEM],
ASPEED_SOC_IOMEM_SIZE);
/* Video engine stub */
create_unimplemented_device("aspeed.video", sc->memmap[ASPEED_DEV_VIDEO],
0x1000);
aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->video), "aspeed.video",
sc->memmap[ASPEED_DEV_VIDEO], 0x1000);
/* CPU */
for (i = 0; i < sc->num_cpus; i++) {
object_property_set_link(OBJECT(&s->cpu[i]), "memory",
OBJECT(s->memory), &error_abort);
if (!qdev_realize(DEVICE(&s->cpu[i]), NULL, errp)) {
return;
}
@ -255,20 +265,20 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
error_propagate(errp, err);
return;
}
memory_region_add_subregion(get_system_memory(),
memory_region_add_subregion(s->memory,
sc->memmap[ASPEED_DEV_SRAM], &s->sram);
/* SCU */
if (!sysbus_realize(SYS_BUS_DEVICE(&s->scu), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->scu), 0, sc->memmap[ASPEED_DEV_SCU]);
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->scu), 0, sc->memmap[ASPEED_DEV_SCU]);
/* VIC */
if (!sysbus_realize(SYS_BUS_DEVICE(&s->vic), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->vic), 0, sc->memmap[ASPEED_DEV_VIC]);
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->vic), 0, sc->memmap[ASPEED_DEV_VIC]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->vic), 0,
qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_IRQ));
sysbus_connect_irq(SYS_BUS_DEVICE(&s->vic), 1,
@ -278,7 +288,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
if (!sysbus_realize(SYS_BUS_DEVICE(&s->rtc), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->rtc), 0, sc->memmap[ASPEED_DEV_RTC]);
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->rtc), 0, sc->memmap[ASPEED_DEV_RTC]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->rtc), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_RTC));
@ -288,7 +298,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
if (!sysbus_realize(SYS_BUS_DEVICE(&s->timerctrl), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->timerctrl), 0,
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->timerctrl), 0,
sc->memmap[ASPEED_DEV_TIMER1]);
for (i = 0; i < ASPEED_TIMER_NR_TIMERS; i++) {
qemu_irq irq = aspeed_soc_get_irq(s, ASPEED_DEV_TIMER1 + i);
@ -299,7 +309,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
if (!sysbus_realize(SYS_BUS_DEVICE(&s->adc), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->adc), 0, sc->memmap[ASPEED_DEV_ADC]);
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->adc), 0, sc->memmap[ASPEED_DEV_ADC]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->adc), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_ADC));
@ -312,18 +322,27 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
if (!sysbus_realize(SYS_BUS_DEVICE(&s->i2c), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c), 0, sc->memmap[ASPEED_DEV_I2C]);
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->i2c), 0, sc->memmap[ASPEED_DEV_I2C]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_I2C));
/* PECI */
if (!sysbus_realize(SYS_BUS_DEVICE(&s->peci), errp)) {
return;
}
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->peci), 0,
sc->memmap[ASPEED_DEV_PECI]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->peci), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_PECI));
/* FMC, The number of CS is set at the board level */
object_property_set_link(OBJECT(&s->fmc), "dram", OBJECT(s->dram_mr),
&error_abort);
if (!sysbus_realize(SYS_BUS_DEVICE(&s->fmc), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->fmc), 0, sc->memmap[ASPEED_DEV_FMC]);
sysbus_mmio_map(SYS_BUS_DEVICE(&s->fmc), 1,
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->fmc), 0, sc->memmap[ASPEED_DEV_FMC]);
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->fmc), 1,
ASPEED_SMC_GET_CLASS(&s->fmc)->flash_window_base);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->fmc), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_FMC));
@ -333,9 +352,9 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 0,
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->spi[i]), 0,
sc->memmap[ASPEED_DEV_SPI1 + i]);
sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 1,
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->spi[i]), 1,
ASPEED_SMC_GET_CLASS(&s->spi[i])->flash_window_base);
}
@ -344,7 +363,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
if (!sysbus_realize(SYS_BUS_DEVICE(&s->ehci[i]), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->ehci[i]), 0,
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->ehci[i]), 0,
sc->memmap[ASPEED_DEV_EHCI1 + i]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->ehci[i]), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_EHCI1 + i));
@ -354,7 +373,8 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
if (!sysbus_realize(SYS_BUS_DEVICE(&s->sdmc), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->sdmc), 0, sc->memmap[ASPEED_DEV_SDMC]);
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->sdmc), 0,
sc->memmap[ASPEED_DEV_SDMC]);
/* Watch dog */
for (i = 0; i < sc->wdts_num; i++) {
@ -365,10 +385,15 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
if (!sysbus_realize(SYS_BUS_DEVICE(&s->wdt[i]), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt[i]), 0,
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->wdt[i]), 0,
sc->memmap[ASPEED_DEV_WDT] + i * awc->offset);
}
/* RAM */
if (!aspeed_soc_dram_init(s, errp)) {
return;
}
/* Net */
for (i = 0; i < sc->macs_num; i++) {
object_property_set_bool(OBJECT(&s->ftgmac100[i]), "aspeed", true,
@ -376,7 +401,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
if (!sysbus_realize(SYS_BUS_DEVICE(&s->ftgmac100[i]), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->ftgmac100[i]), 0,
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->ftgmac100[i]), 0,
sc->memmap[ASPEED_DEV_ETH1 + i]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->ftgmac100[i]), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_ETH1 + i));
@ -386,7 +411,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
if (!sysbus_realize(SYS_BUS_DEVICE(&s->xdma), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->xdma), 0,
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->xdma), 0,
sc->memmap[ASPEED_DEV_XDMA]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->xdma), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_XDMA));
@ -395,7 +420,8 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio), 0, sc->memmap[ASPEED_DEV_GPIO]);
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->gpio), 0,
sc->memmap[ASPEED_DEV_GPIO]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_GPIO));
@ -403,7 +429,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
if (!sysbus_realize(SYS_BUS_DEVICE(&s->sdhci), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->sdhci), 0,
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->sdhci), 0,
sc->memmap[ASPEED_DEV_SDHCI]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->sdhci), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_SDHCI));
@ -412,7 +438,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
if (!sysbus_realize(SYS_BUS_DEVICE(&s->lpc), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->lpc), 0, sc->memmap[ASPEED_DEV_LPC]);
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->lpc), 0, sc->memmap[ASPEED_DEV_LPC]);
/* Connect the LPC IRQ to the VIC */
sysbus_connect_irq(SYS_BUS_DEVICE(&s->lpc), 0,
@ -445,11 +471,14 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
if (!sysbus_realize(SYS_BUS_DEVICE(&s->hace), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->hace), 0, sc->memmap[ASPEED_DEV_HACE]);
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->hace), 0,
sc->memmap[ASPEED_DEV_HACE]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->hace), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_HACE));
}
static Property aspeed_soc_properties[] = {
DEFINE_PROP_LINK("memory", AspeedSoCState, memory, TYPE_MEMORY_REGION,
MemoryRegion *),
DEFINE_PROP_LINK("dram", AspeedSoCState, dram_mr, TYPE_MEMORY_REGION,
MemoryRegion *),
DEFINE_PROP_UINT32("uart-default", AspeedSoCState, uart_default,
@ -549,15 +578,73 @@ void aspeed_soc_uart_init(AspeedSoCState *s)
int i, uart;
/* Attach an 8250 to the IO space as our UART */
serial_mm_init(get_system_memory(), sc->memmap[s->uart_default], 2,
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++;
}
serial_mm_init(get_system_memory(), sc->memmap[uart], 2,
serial_mm_init(s->memory, sc->memmap[uart], 2,
aspeed_soc_get_irq(s, uart), 38400,
serial_hd(i), DEVICE_LITTLE_ENDIAN);
}
}
/*
* SDMC should be realized first to get correct RAM size and max size
* values
*/
bool aspeed_soc_dram_init(AspeedSoCState *s, Error **errp)
{
AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
ram_addr_t ram_size, max_ram_size;
ram_size = object_property_get_uint(OBJECT(&s->sdmc), "ram-size",
&error_abort);
max_ram_size = object_property_get_uint(OBJECT(&s->sdmc), "max-ram-size",
&error_abort);
memory_region_init(&s->dram_container, OBJECT(s), "ram-container",
max_ram_size);
memory_region_add_subregion(&s->dram_container, 0, s->dram_mr);
/*
* Add a memory region beyond the RAM region to let firmwares scan
* the address space with load/store and guess how much RAM the
* SoC has.
*/
if (ram_size < max_ram_size) {
DeviceState *dev = qdev_new(TYPE_UNIMPLEMENTED_DEVICE);
qdev_prop_set_string(dev, "name", "ram-empty");
qdev_prop_set_uint64(dev, "size", max_ram_size - ram_size);
if (!sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), errp)) {
return false;
}
memory_region_add_subregion_overlap(&s->dram_container, ram_size,
sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0), -1000);
}
memory_region_add_subregion(s->memory,
sc->memmap[ASPEED_DEV_SDRAM], &s->dram_container);
return true;
}
void aspeed_mmio_map(AspeedSoCState *s, SysBusDevice *dev, int n, hwaddr addr)
{
memory_region_add_subregion(s->memory, addr,
sysbus_mmio_get_region(dev, n));
}
void aspeed_mmio_map_unimplemented(AspeedSoCState *s, SysBusDevice *dev,
const char *name, hwaddr addr, uint64_t size)
{
qdev_prop_set_string(DEVICE(dev), "name", name);
qdev_prop_set_uint64(DEVICE(dev), "size", size);
sysbus_realize(dev, &error_abort);
memory_region_add_subregion_overlap(s->memory, addr,
sysbus_mmio_get_region(dev, 0), -1000);
}

View File

@ -1305,6 +1305,8 @@ static int pxa2xx_i2c_event(I2CSlave *i2c, enum i2c_event event)
case I2C_NACK:
s->status |= 1 << 1; /* set ACKNAK */
break;
default:
return -1;
}
pxa2xx_i2c_update(s);

View File

@ -472,11 +472,13 @@ struct Flash {
uint8_t spansion_cr2v;
uint8_t spansion_cr3v;
uint8_t spansion_cr4v;
bool wp_level;
bool write_enable;
bool four_bytes_address_mode;
bool reset_enable;
bool quad_enable;
bool aai_enable;
bool status_register_write_disabled;
uint8_t ear;
int64_t dirty_page;
@ -723,6 +725,8 @@ static void complete_collecting_data(Flash *s)
flash_erase(s, s->cur_addr, s->cmd_in_progress);
break;
case WRSR:
s->status_register_write_disabled = extract32(s->data[0], 7, 1);
switch (get_man(s)) {
case MAN_SPANSION:
s->quad_enable = !!(s->data[1] & 0x02);
@ -1165,22 +1169,34 @@ static void decode_new_cmd(Flash *s, uint32_t value)
break;
case WRSR:
if (s->write_enable) {
switch (get_man(s)) {
case MAN_SPANSION:
s->needed_bytes = 2;
s->state = STATE_COLLECTING_DATA;
break;
case MAN_MACRONIX:
s->needed_bytes = 2;
s->state = STATE_COLLECTING_VAR_LEN_DATA;
break;
default:
s->needed_bytes = 1;
s->state = STATE_COLLECTING_DATA;
}
s->pos = 0;
/*
* If WP# is low and status_register_write_disabled is high,
* status register writes are disabled.
* This is also called "hardware protected mode" (HPM). All other
* combinations of the two states are called "software protected mode"
* (SPM), and status register writes are permitted.
*/
if ((s->wp_level == 0 && s->status_register_write_disabled)
|| !s->write_enable) {
qemu_log_mask(LOG_GUEST_ERROR,
"M25P80: Status register write is disabled!\n");
break;
}
switch (get_man(s)) {
case MAN_SPANSION:
s->needed_bytes = 2;
s->state = STATE_COLLECTING_DATA;
break;
case MAN_MACRONIX:
s->needed_bytes = 2;
s->state = STATE_COLLECTING_VAR_LEN_DATA;
break;
default:
s->needed_bytes = 1;
s->state = STATE_COLLECTING_DATA;
}
s->pos = 0;
break;
case WRDI:
@ -1195,6 +1211,8 @@ 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;
if (get_man(s) == MAN_MACRONIX || get_man(s) == MAN_ISSI) {
s->data[0] |= (!!s->quad_enable) << 6;
}
@ -1484,6 +1502,14 @@ static uint32_t m25p80_transfer8(SSIPeripheral *ss, uint32_t tx)
return r;
}
static void m25p80_write_protect_pin_irq_handler(void *opaque, int n, int level)
{
Flash *s = M25P80(opaque);
/* WP# is just a single pin. */
assert(n == 0);
s->wp_level = !!level;
}
static void m25p80_realize(SSIPeripheral *ss, Error **errp)
{
Flash *s = M25P80(ss);
@ -1515,12 +1541,18 @@ static void m25p80_realize(SSIPeripheral *ss, Error **errp)
s->storage = blk_blockalign(NULL, s->size);
memset(s->storage, 0xFF, s->size);
}
qdev_init_gpio_in_named(DEVICE(s),
m25p80_write_protect_pin_irq_handler, "WP#", 1);
}
static void m25p80_reset(DeviceState *d)
{
Flash *s = M25P80(d);
s->wp_level = true;
s->status_register_write_disabled = false;
reset_memory(s);
}
@ -1587,6 +1619,25 @@ static const VMStateDescription vmstate_m25p80_aai_enable = {
}
};
static bool m25p80_wp_level_srwd_needed(void *opaque)
{
Flash *s = (Flash *)opaque;
return !s->wp_level || s->status_register_write_disabled;
}
static const VMStateDescription vmstate_m25p80_write_protect = {
.name = "m25p80/write_protect",
.version_id = 1,
.minimum_version_id = 1,
.needed = m25p80_wp_level_srwd_needed,
.fields = (VMStateField[]) {
VMSTATE_BOOL(wp_level, Flash),
VMSTATE_BOOL(status_register_write_disabled, Flash),
VMSTATE_END_OF_LIST()
}
};
static const VMStateDescription vmstate_m25p80 = {
.name = "m25p80",
.version_id = 0,
@ -1618,6 +1669,7 @@ static const VMStateDescription vmstate_m25p80 = {
.subsections = (const VMStateDescription * []) {
&vmstate_m25p80_data_read_loop,
&vmstate_m25p80_aai_enable,
&vmstate_m25p80_write_protect,
NULL
}
};

View File

@ -76,6 +76,8 @@ static int sii9022_event(I2CSlave *i2c, enum i2c_event event)
break;
case I2C_NACK:
break;
default:
return -1;
}
return 0;

View File

@ -196,6 +196,8 @@ static int ssd0303_event(I2CSlave *i2c, enum i2c_event event)
case I2C_NACK:
/* Nothing to do. */
break;
default:
return -1;
}
return 0;

View File

@ -58,7 +58,7 @@ static inline void aspeed_i2c_bus_raise_interrupt(AspeedI2CBus *bus)
ARRAY_FIELD_EX32(bus->regs, I2CD_INTR_STS, SLAVE_ADDR_RX_MATCH) ?
"slave-match|" : "",
SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, NORMAL_STOP) ?
"normal|" : "",
"stop|" : "",
SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, ABNORMAL) ?
"abnormal" : "");
@ -78,6 +78,18 @@ static inline void aspeed_i2c_bus_raise_interrupt(AspeedI2CBus *bus)
}
}
static inline void aspeed_i2c_bus_raise_slave_interrupt(AspeedI2CBus *bus)
{
AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller);
if (!bus->regs[R_I2CS_INTR_STS]) {
return;
}
bus->controller->intr_status |= 1 << bus->id;
qemu_irq_raise(aic->bus_get_irq(bus));
}
static uint64_t aspeed_i2c_bus_old_read(AspeedI2CBus *bus, hwaddr offset,
unsigned size)
{
@ -140,8 +152,17 @@ static uint64_t aspeed_i2c_bus_new_read(AspeedI2CBus *bus, hwaddr offset,
case A_I2CM_DMA_LEN_STS:
case A_I2CC_DMA_ADDR:
case A_I2CC_DMA_LEN:
case A_I2CS_DEV_ADDR:
case A_I2CS_DMA_RX_ADDR:
case A_I2CS_DMA_LEN:
case A_I2CS_CMD:
case A_I2CS_INTR_CTRL:
case A_I2CS_DMA_LEN_STS:
/* Value is already set, don't do anything. */
break;
case A_I2CS_INTR_STS:
break;
case A_I2CM_CMD:
value = SHARED_FIELD_DP32(value, BUS_BUSY_STS, i2c_bus_busy(bus->bus));
break;
@ -547,12 +568,7 @@ static void aspeed_i2c_bus_new_write(AspeedI2CBus *bus, hwaddr offset,
switch (offset) {
case A_I2CC_FUN_CTRL:
if (SHARED_FIELD_EX32(value, SLAVE_EN)) {
qemu_log_mask(LOG_UNIMP, "%s: slave mode not implemented\n",
__func__);
break;
}
bus->regs[R_I2CD_FUN_CTRL] = value & 0x007dc3ff;
bus->regs[R_I2CC_FUN_CTRL] = value;
break;
case A_I2CC_AC_TIMING:
bus->regs[R_I2CC_AC_TIMING] = value & 0x1ffff0ff;
@ -580,6 +596,7 @@ static void aspeed_i2c_bus_new_write(AspeedI2CBus *bus, hwaddr offset,
bus->controller->intr_status &= ~(1 << bus->id);
qemu_irq_lower(aic->bus_get_irq(bus));
}
aspeed_i2c_bus_raise_slave_interrupt(bus);
break;
}
bus->regs[R_I2CM_INTR_STS] &= ~(value & 0xf007f07f);
@ -601,7 +618,7 @@ static void aspeed_i2c_bus_new_write(AspeedI2CBus *bus, hwaddr offset,
}
if (!aspeed_i2c_bus_is_master(bus)) {
qemu_log_mask(LOG_UNIMP, "%s: slave mode not implemented\n",
qemu_log_mask(LOG_GUEST_ERROR, "%s: Master mode is not enabled\n",
__func__);
break;
}
@ -644,18 +661,18 @@ static void aspeed_i2c_bus_new_write(AspeedI2CBus *bus, hwaddr offset,
RX_BUF_LEN) + 1;
break;
case A_I2CM_DMA_LEN:
w1t = ARRAY_FIELD_EX32(bus->regs, I2CM_DMA_LEN, RX_BUF_LEN_W1T) ||
ARRAY_FIELD_EX32(bus->regs, I2CM_DMA_LEN, TX_BUF_LEN_W1T);
w1t = FIELD_EX32(value, I2CM_DMA_LEN, RX_BUF_LEN_W1T) ||
FIELD_EX32(value, I2CM_DMA_LEN, TX_BUF_LEN_W1T);
/* If none of the w1t bits are set, just write to the reg as normal. */
if (!w1t) {
bus->regs[R_I2CM_DMA_LEN] = value;
break;
}
if (ARRAY_FIELD_EX32(bus->regs, I2CM_DMA_LEN, RX_BUF_LEN_W1T)) {
if (FIELD_EX32(value, I2CM_DMA_LEN, RX_BUF_LEN_W1T)) {
ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN, RX_BUF_LEN,
FIELD_EX32(value, I2CM_DMA_LEN, RX_BUF_LEN));
}
if (ARRAY_FIELD_EX32(bus->regs, I2CM_DMA_LEN, TX_BUF_LEN_W1T)) {
if (FIELD_EX32(value, I2CM_DMA_LEN, TX_BUF_LEN_W1T)) {
ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN, TX_BUF_LEN,
FIELD_EX32(value, I2CM_DMA_LEN, TX_BUF_LEN));
}
@ -668,15 +685,53 @@ static void aspeed_i2c_bus_new_write(AspeedI2CBus *bus, hwaddr offset,
case A_I2CC_DMA_LEN:
/* RO */
break;
case A_I2CS_DMA_LEN_STS:
case A_I2CS_DMA_TX_ADDR:
case A_I2CS_DMA_RX_ADDR:
case A_I2CS_DEV_ADDR:
case A_I2CS_INTR_CTRL:
case A_I2CS_INTR_STS:
case A_I2CS_CMD:
bus->regs[R_I2CS_DEV_ADDR] = value;
break;
case A_I2CS_DMA_RX_ADDR:
bus->regs[R_I2CS_DMA_RX_ADDR] = value;
break;
case A_I2CS_DMA_LEN:
qemu_log_mask(LOG_UNIMP, "%s: Slave mode is not implemented\n",
assert(FIELD_EX32(value, I2CS_DMA_LEN, TX_BUF_LEN) == 0);
if (FIELD_EX32(value, I2CS_DMA_LEN, RX_BUF_LEN_W1T)) {
ARRAY_FIELD_DP32(bus->regs, I2CS_DMA_LEN, RX_BUF_LEN,
FIELD_EX32(value, I2CS_DMA_LEN, RX_BUF_LEN));
} else {
bus->regs[R_I2CS_DMA_LEN] = value;
}
break;
case A_I2CS_CMD:
if (FIELD_EX32(value, I2CS_CMD, W1_CTRL)) {
bus->regs[R_I2CS_CMD] |= value;
} else {
bus->regs[R_I2CS_CMD] = value;
}
i2c_slave_set_address(bus->slave, bus->regs[R_I2CS_DEV_ADDR]);
break;
case A_I2CS_INTR_CTRL:
bus->regs[R_I2CS_INTR_CTRL] = value;
break;
case A_I2CS_INTR_STS:
if (ARRAY_FIELD_EX32(bus->regs, I2CS_INTR_CTRL, PKT_CMD_DONE)) {
if (ARRAY_FIELD_EX32(bus->regs, I2CS_INTR_STS, PKT_CMD_DONE) &&
FIELD_EX32(value, I2CS_INTR_STS, PKT_CMD_DONE)) {
bus->regs[R_I2CS_INTR_STS] &= 0xfffc0000;
}
} else {
bus->regs[R_I2CS_INTR_STS] &= ~value;
}
if (!bus->regs[R_I2CS_INTR_STS]) {
bus->controller->intr_status &= ~(1 << bus->id);
qemu_irq_lower(aic->bus_get_irq(bus));
}
aspeed_i2c_bus_raise_interrupt(bus);
break;
case A_I2CS_DMA_LEN_STS:
bus->regs[R_I2CS_DMA_LEN_STS] = 0;
break;
case A_I2CS_DMA_TX_ADDR:
qemu_log_mask(LOG_UNIMP, "%s: Slave mode DMA TX is not implemented\n",
__func__);
break;
default:
@ -696,9 +751,7 @@ static void aspeed_i2c_bus_old_write(AspeedI2CBus *bus, hwaddr offset,
switch (offset) {
case A_I2CD_FUN_CTRL:
if (SHARED_FIELD_EX32(value, SLAVE_EN)) {
qemu_log_mask(LOG_UNIMP, "%s: slave mode not implemented\n",
__func__);
break;
i2c_slave_set_address(bus->slave, bus->regs[R_I2CD_DEV_ADDR]);
}
bus->regs[R_I2CD_FUN_CTRL] = value & 0x0071C3FF;
break;
@ -719,12 +772,15 @@ static void aspeed_i2c_bus_old_write(AspeedI2CBus *bus, hwaddr offset,
bus->controller->intr_status &= ~(1 << bus->id);
qemu_irq_lower(aic->bus_get_irq(bus));
}
if (handle_rx && (SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CD_CMD,
M_RX_CMD) ||
SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CD_CMD,
M_S_RX_CMD_LAST))) {
aspeed_i2c_handle_rx_cmd(bus);
aspeed_i2c_bus_raise_interrupt(bus);
if (handle_rx) {
if (SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CD_CMD, M_RX_CMD) ||
SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CD_CMD,
M_S_RX_CMD_LAST)) {
aspeed_i2c_handle_rx_cmd(bus);
aspeed_i2c_bus_raise_interrupt(bus);
} else if (aspeed_i2c_get_state(bus) == I2CD_STXD) {
i2c_ack(bus->bus);
}
}
break;
case A_I2CD_DEV_ADDR:
@ -744,7 +800,7 @@ static void aspeed_i2c_bus_old_write(AspeedI2CBus *bus, hwaddr offset,
}
if (!aspeed_i2c_bus_is_master(bus)) {
qemu_log_mask(LOG_UNIMP, "%s: slave mode not implemented\n",
qemu_log_mask(LOG_GUEST_ERROR, "%s: Master mode is not enabled\n",
__func__);
break;
}
@ -1036,6 +1092,127 @@ static const TypeInfo aspeed_i2c_info = {
.abstract = true,
};
static int aspeed_i2c_bus_new_slave_event(AspeedI2CBus *bus,
enum i2c_event event)
{
switch (event) {
case I2C_START_SEND_ASYNC:
if (!SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CS_CMD, RX_DMA_EN)) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Slave mode RX DMA is not enabled\n", __func__);
return -1;
}
ARRAY_FIELD_DP32(bus->regs, I2CS_DMA_LEN_STS, RX_LEN, 0);
bus->regs[R_I2CC_DMA_ADDR] =
ARRAY_FIELD_EX32(bus->regs, I2CS_DMA_RX_ADDR, ADDR);
bus->regs[R_I2CC_DMA_LEN] =
ARRAY_FIELD_EX32(bus->regs, I2CS_DMA_LEN, RX_BUF_LEN) + 1;
i2c_ack(bus->bus);
break;
case I2C_FINISH:
ARRAY_FIELD_DP32(bus->regs, I2CS_INTR_STS, PKT_CMD_DONE, 1);
ARRAY_FIELD_DP32(bus->regs, I2CS_INTR_STS, SLAVE_ADDR_RX_MATCH, 1);
SHARED_ARRAY_FIELD_DP32(bus->regs, R_I2CS_INTR_STS, NORMAL_STOP, 1);
SHARED_ARRAY_FIELD_DP32(bus->regs, R_I2CS_INTR_STS, RX_DONE, 1);
aspeed_i2c_bus_raise_slave_interrupt(bus);
break;
default:
qemu_log_mask(LOG_UNIMP, "%s: i2c event %d unimplemented\n",
__func__, event);
return -1;
}
return 0;
}
static int aspeed_i2c_bus_slave_event(I2CSlave *slave, enum i2c_event event)
{
BusState *qbus = qdev_get_parent_bus(DEVICE(slave));
AspeedI2CBus *bus = ASPEED_I2C_BUS(qbus->parent);
uint32_t reg_intr_sts = aspeed_i2c_bus_intr_sts_offset(bus);
uint32_t reg_byte_buf = aspeed_i2c_bus_byte_buf_offset(bus);
uint32_t value;
if (aspeed_i2c_is_new_mode(bus->controller)) {
return aspeed_i2c_bus_new_slave_event(bus, event);
}
switch (event) {
case I2C_START_SEND_ASYNC:
value = SHARED_ARRAY_FIELD_EX32(bus->regs, reg_byte_buf, TX_BUF);
SHARED_ARRAY_FIELD_DP32(bus->regs, reg_byte_buf, RX_BUF, value << 1);
ARRAY_FIELD_DP32(bus->regs, I2CD_INTR_STS, SLAVE_ADDR_RX_MATCH, 1);
SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, RX_DONE, 1);
aspeed_i2c_set_state(bus, I2CD_STXD);
break;
case I2C_FINISH:
SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, NORMAL_STOP, 1);
aspeed_i2c_set_state(bus, I2CD_IDLE);
break;
default:
return -1;
}
aspeed_i2c_bus_raise_interrupt(bus);
return 0;
}
static void aspeed_i2c_bus_new_slave_send_async(AspeedI2CBus *bus, uint8_t data)
{
assert(address_space_write(&bus->controller->dram_as,
bus->regs[R_I2CC_DMA_ADDR],
MEMTXATTRS_UNSPECIFIED, &data, 1) == MEMTX_OK);
bus->regs[R_I2CC_DMA_ADDR]++;
bus->regs[R_I2CC_DMA_LEN]--;
ARRAY_FIELD_DP32(bus->regs, I2CS_DMA_LEN_STS, RX_LEN,
ARRAY_FIELD_EX32(bus->regs, I2CS_DMA_LEN_STS, RX_LEN) + 1);
i2c_ack(bus->bus);
}
static void aspeed_i2c_bus_slave_send_async(I2CSlave *slave, uint8_t data)
{
BusState *qbus = qdev_get_parent_bus(DEVICE(slave));
AspeedI2CBus *bus = ASPEED_I2C_BUS(qbus->parent);
uint32_t reg_intr_sts = aspeed_i2c_bus_intr_sts_offset(bus);
uint32_t reg_byte_buf = aspeed_i2c_bus_byte_buf_offset(bus);
if (aspeed_i2c_is_new_mode(bus->controller)) {
return aspeed_i2c_bus_new_slave_send_async(bus, data);
}
SHARED_ARRAY_FIELD_DP32(bus->regs, reg_byte_buf, RX_BUF, data);
SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, RX_DONE, 1);
aspeed_i2c_bus_raise_interrupt(bus);
}
static void aspeed_i2c_bus_slave_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
dc->desc = "Aspeed I2C Bus Slave";
sc->event = aspeed_i2c_bus_slave_event;
sc->send_async = aspeed_i2c_bus_slave_send_async;
}
static const TypeInfo aspeed_i2c_bus_slave_info = {
.name = TYPE_ASPEED_I2C_BUS_SLAVE,
.parent = TYPE_I2C_SLAVE,
.instance_size = sizeof(AspeedI2CBusSlave),
.class_init = aspeed_i2c_bus_slave_class_init,
};
static void aspeed_i2c_bus_reset(DeviceState *dev)
{
AspeedI2CBus *s = ASPEED_I2C_BUS(dev);
@ -1060,6 +1237,8 @@ static void aspeed_i2c_bus_realize(DeviceState *dev, Error **errp)
sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq);
s->bus = i2c_init_bus(dev, name);
s->slave = i2c_slave_create_simple(s->bus, TYPE_ASPEED_I2C_BUS_SLAVE,
0xff);
memory_region_init_io(&s->mr, OBJECT(s), &aspeed_i2c_bus_ops,
s, name, aic->reg_size);
@ -1219,6 +1398,7 @@ static const TypeInfo aspeed_1030_i2c_info = {
static void aspeed_i2c_register_types(void)
{
type_register_static(&aspeed_i2c_bus_info);
type_register_static(&aspeed_i2c_bus_slave_info);
type_register_static(&aspeed_i2c_info);
type_register_static(&aspeed_2400_i2c_info);
type_register_static(&aspeed_2500_i2c_info);

View File

@ -13,6 +13,7 @@
#include "migration/vmstate.h"
#include "qapi/error.h"
#include "qemu/module.h"
#include "qemu/main-loop.h"
#include "trace.h"
#define I2C_BROADCAST 0x00
@ -62,6 +63,7 @@ I2CBus *i2c_init_bus(DeviceState *parent, const char *name)
bus = I2C_BUS(qbus_new(TYPE_I2C_BUS, parent, name));
QLIST_INIT(&bus->current_devs);
QSIMPLEQ_INIT(&bus->pending_masters);
vmstate_register(NULL, VMSTATE_INSTANCE_ID_ANY, &vmstate_i2c_bus, bus);
return bus;
}
@ -74,7 +76,7 @@ void i2c_slave_set_address(I2CSlave *dev, uint8_t address)
/* Return nonzero if bus is busy. */
int i2c_bus_busy(I2CBus *bus)
{
return !QLIST_EMPTY(&bus->current_devs);
return !QLIST_EMPTY(&bus->current_devs) || bus->bh;
}
bool i2c_scan_bus(I2CBus *bus, uint8_t address, bool broadcast,
@ -159,7 +161,8 @@ static int i2c_do_start_transfer(I2CBus *bus, uint8_t address,
start condition. */
if (sc->event) {
trace_i2c_event("start", s->address);
trace_i2c_event(event == I2C_START_SEND ? "start" : "start_async",
s->address);
rv = sc->event(s, event);
if (rv && !bus->broadcast) {
if (bus_scanned) {
@ -180,6 +183,26 @@ int i2c_start_transfer(I2CBus *bus, uint8_t address, bool is_recv)
: I2C_START_SEND);
}
void i2c_bus_master(I2CBus *bus, QEMUBH *bh)
{
if (i2c_bus_busy(bus)) {
I2CPendingMaster *node = g_new(struct I2CPendingMaster, 1);
node->bh = bh;
QSIMPLEQ_INSERT_TAIL(&bus->pending_masters, node, entry);
return;
}
bus->bh = bh;
qemu_bh_schedule(bus->bh);
}
void i2c_bus_release(I2CBus *bus)
{
bus->bh = NULL;
}
int i2c_start_recv(I2CBus *bus, uint8_t address)
{
return i2c_do_start_transfer(bus, address, I2C_START_RECV);
@ -190,6 +213,11 @@ int i2c_start_send(I2CBus *bus, uint8_t address)
return i2c_do_start_transfer(bus, address, I2C_START_SEND);
}
int i2c_start_send_async(I2CBus *bus, uint8_t address)
{
return i2c_do_start_transfer(bus, address, I2C_START_SEND_ASYNC);
}
void i2c_end_transfer(I2CBus *bus)
{
I2CSlaveClass *sc;
@ -206,6 +234,16 @@ void i2c_end_transfer(I2CBus *bus)
g_free(node);
}
bus->broadcast = false;
if (!QSIMPLEQ_EMPTY(&bus->pending_masters)) {
I2CPendingMaster *node = QSIMPLEQ_FIRST(&bus->pending_masters);
bus->bh = node->bh;
QSIMPLEQ_REMOVE_HEAD(&bus->pending_masters, entry);
g_free(node);
qemu_bh_schedule(bus->bh);
}
}
int i2c_send(I2CBus *bus, uint8_t data)
@ -229,6 +267,23 @@ int i2c_send(I2CBus *bus, uint8_t data)
return ret ? -1 : 0;
}
int i2c_send_async(I2CBus *bus, uint8_t data)
{
I2CNode *node = QLIST_FIRST(&bus->current_devs);
I2CSlave *slave = node->elt;
I2CSlaveClass *sc = I2C_SLAVE_GET_CLASS(slave);
if (!sc->send_async) {
return -1;
}
trace_i2c_send_async(slave->address, data);
sc->send_async(slave, data);
return 0;
}
uint8_t i2c_recv(I2CBus *bus)
{
uint8_t data = 0xff;
@ -265,6 +320,17 @@ void i2c_nack(I2CBus *bus)
}
}
void i2c_ack(I2CBus *bus)
{
if (!bus->bh) {
return;
}
trace_i2c_ack();
qemu_bh_schedule(bus->bh);
}
static int i2c_slave_post_load(void *opaque, int version_id)
{
I2CSlave *dev = opaque;

View File

@ -284,14 +284,10 @@ static uint8_t pmbus_receive_byte(SMBusDevice *smd)
/*
* Reading from all pages will return the value from page 0,
* this is unspecified behaviour in general.
* means that all subsequent commands are to be applied to all output.
*/
if (pmdev->page == PB_ALL_PAGES) {
index = 0;
qemu_log_mask(LOG_GUEST_ERROR,
"%s: tried to read from all pages\n",
__func__);
pmbus_cml_error(pmdev);
} else if (pmdev->page > pmdev->num_pages - 1) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: page %d is out of range\n",

View File

@ -143,6 +143,10 @@ static int smbus_i2c_event(I2CSlave *s, enum i2c_event event)
dev->mode = SMBUS_CONFUSED;
break;
}
break;
default:
return -1;
}
return 0;

View File

@ -4,7 +4,9 @@
i2c_event(const char *event, uint8_t address) "%s(addr:0x%02x)"
i2c_send(uint8_t address, uint8_t data) "send(addr:0x%02x) data:0x%02x"
i2c_send_async(uint8_t address, uint8_t data) "send_async(addr:0x%02x) data:0x%02x"
i2c_recv(uint8_t address, uint8_t data) "recv(addr:0x%02x) data:0x%02x"
i2c_ack(void) ""
# aspeed_i2c.c

View File

@ -338,10 +338,10 @@ static void aspeed_hace_write(void *opaque, hwaddr addr, uint64_t data,
int algo;
data &= ahc->hash_mask;
if ((data & HASH_HMAC_MASK)) {
if ((data & HASH_DIGEST_HMAC)) {
qemu_log_mask(LOG_UNIMP,
"%s: HMAC engine command mode %"PRIx64" not implemented\n",
__func__, (data & HASH_HMAC_MASK) >> 8);
"%s: HMAC mode not implemented\n",
__func__);
}
if (data & BIT(1)) {
qemu_log_mask(LOG_UNIMP,

152
hw/misc/aspeed_peci.c Normal file
View File

@ -0,0 +1,152 @@
/*
* Aspeed PECI Controller
*
* 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/log.h"
#include "hw/irq.h"
#include "hw/misc/aspeed_peci.h"
#include "hw/registerfields.h"
#include "trace.h"
#define ASPEED_PECI_CC_RSP_SUCCESS (0x40U)
/* Command Register */
REG32(PECI_CMD, 0x08)
FIELD(PECI_CMD, FIRE, 0, 1)
/* Interrupt Control Register */
REG32(PECI_INT_CTRL, 0x18)
/* Interrupt Status Register */
REG32(PECI_INT_STS, 0x1C)
FIELD(PECI_INT_STS, CMD_DONE, 0, 1)
/* Rx/Tx Data Buffer Registers */
REG32(PECI_WR_DATA0, 0x20)
REG32(PECI_RD_DATA0, 0x30)
static void aspeed_peci_raise_interrupt(AspeedPECIState *s, uint32_t status)
{
trace_aspeed_peci_raise_interrupt(s->regs[R_PECI_INT_CTRL], status);
s->regs[R_PECI_INT_STS] = s->regs[R_PECI_INT_CTRL] & status;
if (!s->regs[R_PECI_INT_STS]) {
return;
}
qemu_irq_raise(s->irq);
}
static uint64_t aspeed_peci_read(void *opaque, hwaddr offset, unsigned size)
{
AspeedPECIState *s = ASPEED_PECI(opaque);
uint64_t data;
if (offset >= ASPEED_PECI_NR_REGS << 2) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n",
__func__, offset);
return 0;
}
data = s->regs[offset >> 2];
trace_aspeed_peci_read(offset, data);
return data;
}
static void aspeed_peci_write(void *opaque, hwaddr offset, uint64_t data,
unsigned size)
{
AspeedPECIState *s = ASPEED_PECI(opaque);
trace_aspeed_peci_write(offset, data);
if (offset >= ASPEED_PECI_NR_REGS << 2) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n",
__func__, offset);
return;
}
switch (offset) {
case A_PECI_INT_STS:
s->regs[R_PECI_INT_STS] &= ~data;
if (!s->regs[R_PECI_INT_STS]) {
qemu_irq_lower(s->irq);
}
break;
case A_PECI_CMD:
/*
* Only the FIRE bit is writable. Once the command is complete, it
* should be cleared. Since we complete the command immediately, the
* value is not stored in the register array.
*/
if (!FIELD_EX32(data, PECI_CMD, FIRE)) {
break;
}
if (s->regs[R_PECI_INT_STS]) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: Interrupt status must be "
"cleared before firing another command: 0x%08x\n",
__func__, s->regs[R_PECI_INT_STS]);
break;
}
s->regs[R_PECI_RD_DATA0] = ASPEED_PECI_CC_RSP_SUCCESS;
s->regs[R_PECI_WR_DATA0] = ASPEED_PECI_CC_RSP_SUCCESS;
aspeed_peci_raise_interrupt(s,
FIELD_DP32(0, PECI_INT_STS, CMD_DONE, 1));
break;
default:
s->regs[offset / sizeof(s->regs[0])] = data;
break;
}
}
static const MemoryRegionOps aspeed_peci_ops = {
.read = aspeed_peci_read,
.write = aspeed_peci_write,
.endianness = DEVICE_LITTLE_ENDIAN,
};
static void aspeed_peci_realize(DeviceState *dev, Error **errp)
{
AspeedPECIState *s = ASPEED_PECI(dev);
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
memory_region_init_io(&s->mmio, OBJECT(s), &aspeed_peci_ops, s,
TYPE_ASPEED_PECI, 0x1000);
sysbus_init_mmio(sbd, &s->mmio);
sysbus_init_irq(sbd, &s->irq);
}
static void aspeed_peci_reset(DeviceState *dev)
{
AspeedPECIState *s = ASPEED_PECI(dev);
memset(s->regs, 0, sizeof(s->regs));
}
static void aspeed_peci_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = aspeed_peci_realize;
dc->reset = aspeed_peci_reset;
dc->desc = "Aspeed PECI Controller";
}
static const TypeInfo aspeed_peci_types[] = {
{
.name = TYPE_ASPEED_PECI,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(AspeedPECIState),
.class_init = aspeed_peci_class_init,
.abstract = false,
},
};
DEFINE_TYPES(aspeed_peci_types);

View File

@ -270,6 +270,7 @@ static uint64_t aspeed_scu_read(void *opaque, hwaddr offset, unsigned size)
break;
}
trace_aspeed_scu_read(offset, size, s->regs[reg]);
return s->regs[reg];
}
@ -637,6 +638,7 @@ static uint64_t aspeed_ast2600_scu_read(void *opaque, hwaddr offset,
break;
}
trace_aspeed_scu_read(offset, size, s->regs[reg]);
return s->regs[reg];
}

View File

@ -116,7 +116,8 @@ softmmu_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files(
'aspeed_scu.c',
'aspeed_sbc.c',
'aspeed_sdmc.c',
'aspeed_xdma.c'))
'aspeed_xdma.c',
'aspeed_peci.c'))
softmmu_ss.add(when: 'CONFIG_MSF2', if_true: files('msf2-sysreg.c'))
softmmu_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_rng.c'))

View File

@ -69,6 +69,7 @@ slavio_led_mem_readw(uint32_t ret) "Read diagnostic LED 0x%04x"
# aspeed_scu.c
aspeed_scu_write(uint64_t offset, unsigned size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32
aspeed_scu_read(uint64_t offset, unsigned size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32
# mps2-scc.c
mps2_scc_read(uint64_t offset, uint64_t data, unsigned size) "MPS2 SCC read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
@ -209,6 +210,11 @@ aspeed_i3c_device_write(uint32_t deviceid, uint64_t offset, uint64_t data) "I3C
aspeed_sdmc_write(uint64_t reg, uint64_t data) "reg @0x%" PRIx64 " data: 0x%" PRIx64
aspeed_sdmc_read(uint64_t reg, uint64_t data) "reg @0x%" PRIx64 " data: 0x%" PRIx64
# aspeed_peci.c
aspeed_peci_read(uint64_t offset, uint64_t data) "offset 0x%" PRIx64 " data 0x%" PRIx64
aspeed_peci_write(uint64_t offset, uint64_t data) "offset 0x%" PRIx64 " data 0x%" PRIx64
aspeed_peci_raise_interrupt(uint32_t ctrl, uint32_t status) "ctrl 0x%" PRIx32 " status 0x%" PRIx32
# bcm2835_property.c
bcm2835_mbox_property(uint32_t tag, uint32_t bufsize, size_t resplen) "mbox property tag:0x%08x in_sz:%u out_sz:%zu"

View File

@ -75,6 +75,8 @@ int at24c_eeprom_event(I2CSlave *s, enum i2c_event event)
break;
case I2C_NACK:
break;
default:
return -1;
}
return 0;
}

View File

@ -34,3 +34,7 @@ config LSM303DLHC_MAG
config ISL_PMBUS_VR
bool
depends on PMBUS
config MAX31785
bool
depends on PMBUS

View File

@ -427,6 +427,8 @@ static int lsm303dlhc_mag_event(I2CSlave *i2c, enum i2c_event event)
break;
case I2C_NACK:
break;
default:
return -1;
}
s->len = 0;

573
hw/sensor/max31785.c Normal file
View File

@ -0,0 +1,573 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Maxim MAX31785 PMBus 6-Channel Fan Controller
*
* Datasheet:
* https://datasheets.maximintegrated.com/en/ds/MAX31785.pdf
*
* Copyright(c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include "qemu/osdep.h"
#include "hw/i2c/pmbus_device.h"
#include "hw/irq.h"
#include "migration/vmstate.h"
#include "qapi/error.h"
#include "qapi/visitor.h"
#include "qemu/log.h"
#include "qemu/module.h"
#define TYPE_MAX31785 "max31785"
#define MAX31785(obj) OBJECT_CHECK(MAX31785State, (obj), TYPE_MAX31785)
/* MAX31785 mfr specific PMBus commands */
#define MAX31785_MFR_MODE 0xD1
#define MAX31785_MFR_PSEN_CONFIG 0xD2
#define MAX31785_MFR_VOUT_PEAK 0xD4
#define MAX31785_MFR_TEMPERATURE_PEAK 0xD6
#define MAX31785_MFR_VOUT_MIN 0xD7
#define MAX31785_MFR_FAULT_RESPONSE 0xD9
#define MAX31785_MFR_NV_FAULT_LOG 0xDC
#define MAX31785_MFR_TIME_COUNT 0xDD
#define MAX31785_MFR_TEMP_SENSOR_CONFIG 0xF0
#define MAX31785_MFR_FAN_CONFIG 0xF1
#define MAX31785_MFR_FAN_LUT 0xF2
#define MAX31785_MFR_READ_FAN_PWM 0xF3
#define MAX31785_MFR_FAN_FAULT_LIMIT 0xF5
#define MAX31785_MFR_FAN_WARN_LIMIT 0xF6
#define MAX31785_MFR_FAN_RUN_TIME 0xF7
#define MAX31785_MFR_FAN_PWM_AVG 0xF8
#define MAX31785_MFR_FAN_PWM2RPM 0xF9
/* defaults as per the data sheet */
#define MAX31785_DEFAULT_CAPABILITY 0x10
#define MAX31785_DEFAULT_VOUT_MODE 0x40
#define MAX31785_DEFAULT_VOUT_SCALE_MONITOR 0x7FFF
#define MAX31785_DEFAULT_FAN_COMMAND_1 0x7FFF
#define MAX31785_DEFAULT_OV_FAULT_LIMIT 0x7FFF
#define MAX31785_DEFAULT_OV_WARN_LIMIT 0x7FFF
#define MAX31785_DEFAULT_OT_FAULT_LIMIT 0x7FFF
#define MAX31785_DEFAULT_OT_WARN_LIMIT 0x7FFF
#define MAX31785_DEFAULT_PMBUS_REVISION 0x11
#define MAX31785_DEFAULT_MFR_ID 0x4D
#define MAX31785_DEFAULT_MFR_MODEL 0x53
#define MAX31785_DEFAULT_MFR_REVISION 0x3030
#define MAX31785A_DEFAULT_MFR_REVISION 0x3040
#define MAX31785B_DEFAULT_MFR_REVISION 0x3061
#define MAX31785B_DEFAULT_MFR_TEMPERATURE_PEAK 0x8000
#define MAX31785B_DEFAULT_MFR_VOUT_MIN 0x7FFF
#define MAX31785_DEFAULT_TEXT 0x3130313031303130
/* MAX31785 pages */
#define MAX31785_TOTAL_NUM_PAGES 23
#define MAX31785_FAN_PAGES 6
#define MAX31785_MIN_FAN_PAGE 0
#define MAX31785_MAX_FAN_PAGE 5
#define MAX31785_MIN_TEMP_PAGE 6
#define MAX31785_MAX_TEMP_PAGE 16
#define MAX31785_MIN_ADC_VOLTAGE_PAGE 17
#define MAX31785_MAX_ADC_VOLTAGE_PAGE 22
/* FAN_CONFIG_1_2 */
#define MAX31785_MFR_FAN_CONFIG 0xF1
#define MAX31785_FAN_CONFIG_ENABLE BIT(7)
#define MAX31785_FAN_CONFIG_RPM_PWM BIT(6)
#define MAX31785_FAN_CONFIG_PULSE(pulse) (pulse << 4)
#define MAX31785_DEFAULT_FAN_CONFIG_1_2(pulse) \
(MAX31785_FAN_CONFIG_ENABLE | MAX31785_FAN_CONFIG_PULSE(pulse))
#define MAX31785_DEFAULT_MFR_FAN_CONFIG 0x0000
/* fan speed in RPM */
#define MAX31785_DEFAULT_FAN_SPEED 0x7fff
#define MAX31785_DEFAULT_FAN_STATUS 0x00
#define MAX31785_DEFAULT_FAN_MAX_PWM 0x2710
/*
* MAX31785State:
* @code: The command code received
* @page: Each page corresponds to a device monitored by the Max 31785
* The page register determines the available commands depending on device
* _____________________________________________________________________________
* | 0 | Fan Connected to PWM0 |
* |_______|___________________________________________________________________|
* | 1 | Fan Connected to PWM1 |
* |_______|___________________________________________________________________|
* | 2 | Fan Connected to PWM2 |
* |_______|___________________________________________________________________|
* | 3 | Fan Connected to PWM3 |
* |_______|___________________________________________________________________|
* | 4 | Fan Connected to PWM4 |
* |_______|___________________________________________________________________|
* | 5 | Fan Connected to PWM5 |
* |_______|___________________________________________________________________|
* | 6 | Remote Thermal Diode Connected to ADC 0 |
* |_______|___________________________________________________________________|
* | 7 | Remote Thermal Diode Connected to ADC 1 |
* |_______|___________________________________________________________________|
* | 8 | Remote Thermal Diode Connected to ADC 2 |
* |_______|___________________________________________________________________|
* | 9 | Remote Thermal Diode Connected to ADC 3 |
* |_______|___________________________________________________________________|
* | 10 | Remote Thermal Diode Connected to ADC 4 |
* |_______|___________________________________________________________________|
* | 11 | Remote Thermal Diode Connected to ADC 5 |
* |_______|___________________________________________________________________|
* | 12 | Internal Temperature Sensor |
* |_______|___________________________________________________________________|
* | 13 | Remote I2C Temperature Sensor with Address 0 |
* |_______|___________________________________________________________________|
* | 14 | Remote I2C Temperature Sensor with Address 1 |
* |_______|___________________________________________________________________|
* | 15 | Remote I2C Temperature Sensor with Address 2 |
* |_______|___________________________________________________________________|
* | 16 | Remote I2C Temperature Sensor with Address 3 |
* |_______|___________________________________________________________________|
* | 17 | Remote I2C Temperature Sensor with Address 4 |
* |_______|___________________________________________________________________|
* | 17 | Remote Voltage Connected to ADC0 |
* |_______|___________________________________________________________________|
* | 18 | Remote Voltage Connected to ADC1 |
* |_______|___________________________________________________________________|
* | 19 | Remote Voltage Connected to ADC2 |
* |_______|___________________________________________________________________|
* | 20 | Remote Voltage Connected to ADC3 |
* |_______|___________________________________________________________________|
* | 21 | Remote Voltage Connected to ADC4 |
* |_______|___________________________________________________________________|
* | 22 | Remote Voltage Connected to ADC5 |
* |_______|___________________________________________________________________|
* |23-254 | Reserved |
* |_______|___________________________________________________________________|
* | 255 | Applies to all pages |
* |_______|___________________________________________________________________|
*/
/* Place holder to save the max31785 mfr specific registers */
typedef struct MAX31785State {
PMBusDevice parent;
uint16_t mfr_mode[MAX31785_TOTAL_NUM_PAGES];
uint16_t vout_peak[MAX31785_TOTAL_NUM_PAGES];
uint16_t temperature_peak[MAX31785_TOTAL_NUM_PAGES];
uint16_t vout_min[MAX31785_TOTAL_NUM_PAGES];
uint8_t fault_response[MAX31785_TOTAL_NUM_PAGES];
uint32_t time_count[MAX31785_TOTAL_NUM_PAGES];
uint16_t temp_sensor_config[MAX31785_TOTAL_NUM_PAGES];
uint16_t fan_config[MAX31785_TOTAL_NUM_PAGES];
uint16_t read_fan_pwm[MAX31785_TOTAL_NUM_PAGES];
uint16_t fan_fault_limit[MAX31785_TOTAL_NUM_PAGES];
uint16_t fan_warn_limit[MAX31785_TOTAL_NUM_PAGES];
uint16_t fan_run_time[MAX31785_TOTAL_NUM_PAGES];
uint16_t fan_pwm_avg[MAX31785_TOTAL_NUM_PAGES];
uint64_t fan_pwm2rpm[MAX31785_TOTAL_NUM_PAGES];
uint64_t mfr_location;
uint64_t mfr_date;
uint64_t mfr_serial;
uint16_t mfr_revision;
} MAX31785State;
static uint8_t max31785_read_byte(PMBusDevice *pmdev)
{
MAX31785State *s = MAX31785(pmdev);
switch (pmdev->code) {
case PMBUS_FAN_CONFIG_1_2:
if (pmdev->page <= MAX31785_MAX_FAN_PAGE) {
pmbus_send8(pmdev, pmdev->pages[pmdev->page].fan_config_1_2);
}
break;
case PMBUS_FAN_COMMAND_1:
if (pmdev->page <= MAX31785_MAX_FAN_PAGE) {
pmbus_send16(pmdev, pmdev->pages[pmdev->page].fan_command_1);
}
break;
case PMBUS_READ_FAN_SPEED_1:
if (pmdev->page <= MAX31785_MAX_FAN_PAGE) {
pmbus_send16(pmdev, pmdev->pages[pmdev->page].read_fan_speed_1);
}
break;
case PMBUS_STATUS_FANS_1_2:
if (pmdev->page <= MAX31785_MAX_FAN_PAGE) {
pmbus_send16(pmdev, pmdev->pages[pmdev->page].status_fans_1_2);
}
break;
case PMBUS_MFR_REVISION:
pmbus_send16(pmdev, MAX31785_DEFAULT_MFR_REVISION);
break;
case PMBUS_MFR_ID:
pmbus_send8(pmdev, 0x4d); /* Maxim */
break;
case PMBUS_MFR_MODEL:
pmbus_send8(pmdev, 0x53);
break;
case PMBUS_MFR_LOCATION:
pmbus_send64(pmdev, s->mfr_location);
break;
case PMBUS_MFR_DATE:
pmbus_send64(pmdev, s->mfr_date);
break;
case PMBUS_MFR_SERIAL:
pmbus_send64(pmdev, s->mfr_serial);
break;
case MAX31785_MFR_MODE:
pmbus_send16(pmdev, s->mfr_mode[pmdev->page]);
break;
case MAX31785_MFR_VOUT_PEAK:
if ((pmdev->page >= MAX31785_MIN_ADC_VOLTAGE_PAGE) &&
(pmdev->page <= MAX31785_MAX_ADC_VOLTAGE_PAGE)) {
pmbus_send16(pmdev, s->vout_peak[pmdev->page]);
}
break;
case MAX31785_MFR_TEMPERATURE_PEAK:
if ((pmdev->page >= MAX31785_MIN_TEMP_PAGE) &&
(pmdev->page <= MAX31785_MAX_TEMP_PAGE)) {
pmbus_send16(pmdev, s->temperature_peak[pmdev->page]);
}
break;
case MAX31785_MFR_VOUT_MIN:
if ((pmdev->page >= MAX31785_MIN_ADC_VOLTAGE_PAGE) &&
(pmdev->page <= MAX31785_MAX_ADC_VOLTAGE_PAGE)) {
pmbus_send16(pmdev, s->vout_min[pmdev->page]);
}
break;
case MAX31785_MFR_FAULT_RESPONSE:
pmbus_send8(pmdev, s->fault_response[pmdev->page]);
break;
case MAX31785_MFR_TIME_COUNT: /* R/W 32 */
pmbus_send32(pmdev, s->time_count[pmdev->page]);
break;
case MAX31785_MFR_TEMP_SENSOR_CONFIG: /* R/W 16 */
if ((pmdev->page >= MAX31785_MIN_TEMP_PAGE) &&
(pmdev->page <= MAX31785_MAX_TEMP_PAGE)) {
pmbus_send16(pmdev, s->temp_sensor_config[pmdev->page]);
}
break;
case MAX31785_MFR_FAN_CONFIG: /* R/W 16 */
if (pmdev->page <= MAX31785_MAX_FAN_PAGE) {
pmbus_send16(pmdev, s->fan_config[pmdev->page]);
}
break;
case MAX31785_MFR_READ_FAN_PWM: /* R/W 16 */
if (pmdev->page <= MAX31785_MAX_FAN_PAGE) {
pmbus_send16(pmdev, s->read_fan_pwm[pmdev->page]);
}
break;
case MAX31785_MFR_FAN_FAULT_LIMIT: /* R/W 16 */
if (pmdev->page <= MAX31785_MAX_FAN_PAGE) {
pmbus_send16(pmdev, s->fan_fault_limit[pmdev->page]);
}
break;
case MAX31785_MFR_FAN_WARN_LIMIT: /* R/W 16 */
if (pmdev->page <= MAX31785_MAX_FAN_PAGE) {
pmbus_send16(pmdev, s->fan_warn_limit[pmdev->page]);
}
break;
case MAX31785_MFR_FAN_RUN_TIME: /* R/W 16 */
if (pmdev->page <= MAX31785_MAX_FAN_PAGE) {
pmbus_send16(pmdev, s->fan_run_time[pmdev->page]);
}
break;
case MAX31785_MFR_FAN_PWM_AVG: /* R/W 16 */
if (pmdev->page <= MAX31785_MAX_FAN_PAGE) {
pmbus_send16(pmdev, s->fan_pwm_avg[pmdev->page]);
}
break;
case MAX31785_MFR_FAN_PWM2RPM: /* R/W 64 */
if (pmdev->page <= MAX31785_MAX_FAN_PAGE) {
pmbus_send64(pmdev, s->fan_pwm2rpm[pmdev->page]);
}
break;
default:
qemu_log_mask(LOG_GUEST_ERROR,
"%s: reading from unsupported register: 0x%02x\n",
__func__, pmdev->code);
break;
}
return 0xFF;
}
static int max31785_write_data(PMBusDevice *pmdev, const uint8_t *buf,
uint8_t len)
{
MAX31785State *s = MAX31785(pmdev);
if (len == 0) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: writing empty data\n", __func__);
return -1;
}
pmdev->code = buf[0]; /* PMBus command code */
if (len == 1) {
return 0;
}
/* Exclude command code from buffer */
buf++;
len--;
switch (pmdev->code) {
case PMBUS_FAN_CONFIG_1_2:
if (pmdev->page <= MAX31785_MAX_FAN_PAGE) {
pmdev->pages[pmdev->page].fan_config_1_2 = pmbus_receive8(pmdev);
}
break;
case PMBUS_FAN_COMMAND_1:
if (pmdev->page <= MAX31785_MAX_FAN_PAGE) {
pmdev->pages[pmdev->page].fan_command_1 = pmbus_receive16(pmdev);
pmdev->pages[pmdev->page].read_fan_speed_1 =
((MAX31785_DEFAULT_FAN_SPEED / MAX31785_DEFAULT_FAN_MAX_PWM) *
pmdev->pages[pmdev->page].fan_command_1);
}
break;
case PMBUS_MFR_LOCATION: /* R/W 64 */
s->mfr_location = pmbus_receive64(pmdev);
break;
case PMBUS_MFR_DATE: /* R/W 64 */
s->mfr_date = pmbus_receive64(pmdev);
break;
case PMBUS_MFR_SERIAL: /* R/W 64 */
s->mfr_serial = pmbus_receive64(pmdev);
break;
case MAX31785_MFR_MODE: /* R/W word */
s->mfr_mode[pmdev->page] = pmbus_receive16(pmdev);
break;
case MAX31785_MFR_VOUT_PEAK: /* R/W word */
if ((pmdev->page >= MAX31785_MIN_ADC_VOLTAGE_PAGE) &&
(pmdev->page <= MAX31785_MAX_ADC_VOLTAGE_PAGE)) {
s->vout_peak[pmdev->page] = pmbus_receive16(pmdev);
}
break;
case MAX31785_MFR_TEMPERATURE_PEAK: /* R/W word */
if ((pmdev->page >= 6) && (pmdev->page <= 16)) {
s->temperature_peak[pmdev->page] = pmbus_receive16(pmdev);
}
break;
case MAX31785_MFR_VOUT_MIN: /* R/W word */
if ((pmdev->page >= MAX31785_MIN_ADC_VOLTAGE_PAGE) &&
(pmdev->page <= MAX31785_MAX_ADC_VOLTAGE_PAGE)) {
s->vout_min[pmdev->page] = pmbus_receive16(pmdev);
}
break;
case MAX31785_MFR_FAULT_RESPONSE: /* R/W 8 */
s->fault_response[pmdev->page] = pmbus_receive8(pmdev);
break;
case MAX31785_MFR_TIME_COUNT: /* R/W 32 */
s->time_count[pmdev->page] = pmbus_receive32(pmdev);
break;
case MAX31785_MFR_TEMP_SENSOR_CONFIG: /* R/W 16 */
if ((pmdev->page >= MAX31785_MIN_TEMP_PAGE) &&
(pmdev->page <= MAX31785_MAX_TEMP_PAGE)) {
s->temp_sensor_config[pmdev->page] = pmbus_receive16(pmdev);
}
break;
case MAX31785_MFR_FAN_CONFIG: /* R/W 16 */
if (pmdev->page <= MAX31785_MAX_FAN_PAGE) {
s->fan_config[pmdev->page] = pmbus_receive16(pmdev);
}
break;
case MAX31785_MFR_FAN_FAULT_LIMIT: /* R/W 16 */
if (pmdev->page <= MAX31785_MAX_FAN_PAGE) {
s->fan_fault_limit[pmdev->page] = pmbus_receive16(pmdev);
}
break;
case MAX31785_MFR_FAN_WARN_LIMIT: /* R/W 16 */
if (pmdev->page <= MAX31785_MAX_FAN_PAGE) {
s->fan_warn_limit[pmdev->page] = pmbus_receive16(pmdev);
}
break;
case MAX31785_MFR_FAN_RUN_TIME: /* R/W 16 */
if (pmdev->page <= MAX31785_MAX_FAN_PAGE) {
s->fan_run_time[pmdev->page] = pmbus_receive16(pmdev);
}
break;
case MAX31785_MFR_FAN_PWM_AVG: /* R/W 16 */
if (pmdev->page <= MAX31785_MAX_FAN_PAGE) {
s->fan_pwm_avg[pmdev->page] = pmbus_receive16(pmdev);
}
break;
case MAX31785_MFR_FAN_PWM2RPM: /* R/W 64 */
if (pmdev->page <= MAX31785_MAX_FAN_PAGE) {
s->fan_pwm2rpm[pmdev->page] = pmbus_receive64(pmdev);
}
break;
default:
qemu_log_mask(LOG_GUEST_ERROR,
"%s: writing to unsupported register: 0x%02x\n",
__func__, pmdev->code);
break;
}
return 0;
}
static void max31785_exit_reset(Object *obj)
{
PMBusDevice *pmdev = PMBUS_DEVICE(obj);
MAX31785State *s = MAX31785(obj);
pmdev->capability = MAX31785_DEFAULT_CAPABILITY;
for (int i = MAX31785_MIN_FAN_PAGE; i <= MAX31785_MAX_FAN_PAGE; i++) {
pmdev->pages[i].vout_mode = MAX31785_DEFAULT_VOUT_MODE;
pmdev->pages[i].fan_command_1 = MAX31785_DEFAULT_FAN_COMMAND_1;
pmdev->pages[i].revision = MAX31785_DEFAULT_PMBUS_REVISION;
pmdev->pages[i].fan_config_1_2 = MAX31785_DEFAULT_FAN_CONFIG_1_2(0);
pmdev->pages[i].read_fan_speed_1 = MAX31785_DEFAULT_FAN_SPEED;
pmdev->pages[i].status_fans_1_2 = MAX31785_DEFAULT_FAN_STATUS;
}
for (int i = MAX31785_MIN_TEMP_PAGE; i <= MAX31785_MAX_TEMP_PAGE; i++) {
pmdev->pages[i].vout_mode = MAX31785_DEFAULT_VOUT_MODE;
pmdev->pages[i].revision = MAX31785_DEFAULT_PMBUS_REVISION;
pmdev->pages[i].ot_fault_limit = MAX31785_DEFAULT_OT_FAULT_LIMIT;
pmdev->pages[i].ot_warn_limit = MAX31785_DEFAULT_OT_WARN_LIMIT;
}
for (int i = MAX31785_MIN_ADC_VOLTAGE_PAGE;
i <= MAX31785_MAX_ADC_VOLTAGE_PAGE;
i++) {
pmdev->pages[i].vout_mode = MAX31785_DEFAULT_VOUT_MODE;
pmdev->pages[i].revision = MAX31785_DEFAULT_PMBUS_REVISION;
pmdev->pages[i].vout_scale_monitor =
MAX31785_DEFAULT_VOUT_SCALE_MONITOR;
pmdev->pages[i].vout_ov_fault_limit = MAX31785_DEFAULT_OV_FAULT_LIMIT;
pmdev->pages[i].vout_ov_warn_limit = MAX31785_DEFAULT_OV_WARN_LIMIT;
}
s->mfr_location = MAX31785_DEFAULT_TEXT;
s->mfr_date = MAX31785_DEFAULT_TEXT;
s->mfr_serial = MAX31785_DEFAULT_TEXT;
}
static const VMStateDescription vmstate_max31785 = {
.name = TYPE_MAX31785,
.version_id = 0,
.minimum_version_id = 0,
.fields = (VMStateField[]){
VMSTATE_PMBUS_DEVICE(parent, MAX31785State),
VMSTATE_UINT16_ARRAY(mfr_mode, MAX31785State,
MAX31785_TOTAL_NUM_PAGES),
VMSTATE_UINT16_ARRAY(vout_peak, MAX31785State,
MAX31785_TOTAL_NUM_PAGES),
VMSTATE_UINT16_ARRAY(temperature_peak, MAX31785State,
MAX31785_TOTAL_NUM_PAGES),
VMSTATE_UINT16_ARRAY(vout_min, MAX31785State,
MAX31785_TOTAL_NUM_PAGES),
VMSTATE_UINT8_ARRAY(fault_response, MAX31785State,
MAX31785_TOTAL_NUM_PAGES),
VMSTATE_UINT32_ARRAY(time_count, MAX31785State,
MAX31785_TOTAL_NUM_PAGES),
VMSTATE_UINT16_ARRAY(temp_sensor_config, MAX31785State,
MAX31785_TOTAL_NUM_PAGES),
VMSTATE_UINT16_ARRAY(fan_config, MAX31785State,
MAX31785_TOTAL_NUM_PAGES),
VMSTATE_UINT16_ARRAY(read_fan_pwm, MAX31785State,
MAX31785_TOTAL_NUM_PAGES),
VMSTATE_UINT16_ARRAY(fan_fault_limit, MAX31785State,
MAX31785_TOTAL_NUM_PAGES),
VMSTATE_UINT16_ARRAY(fan_warn_limit, MAX31785State,
MAX31785_TOTAL_NUM_PAGES),
VMSTATE_UINT16_ARRAY(fan_run_time, MAX31785State,
MAX31785_TOTAL_NUM_PAGES),
VMSTATE_UINT16_ARRAY(fan_pwm_avg, MAX31785State,
MAX31785_TOTAL_NUM_PAGES),
VMSTATE_UINT64_ARRAY(fan_pwm2rpm, MAX31785State,
MAX31785_TOTAL_NUM_PAGES),
VMSTATE_UINT64(mfr_location, MAX31785State),
VMSTATE_UINT64(mfr_date, MAX31785State),
VMSTATE_UINT64(mfr_serial, MAX31785State),
VMSTATE_END_OF_LIST()
}
};
static void max31785_init(Object *obj)
{
PMBusDevice *pmdev = PMBUS_DEVICE(obj);
for (int i = MAX31785_MIN_FAN_PAGE; i <= MAX31785_MAX_FAN_PAGE; i++) {
pmbus_page_config(pmdev, i, PB_HAS_VOUT_MODE);
}
for (int i = MAX31785_MIN_TEMP_PAGE; i <= MAX31785_MAX_TEMP_PAGE; i++) {
pmbus_page_config(pmdev, i, PB_HAS_VOUT_MODE | PB_HAS_TEMPERATURE);
}
for (int i = MAX31785_MIN_ADC_VOLTAGE_PAGE;
i <= MAX31785_MAX_ADC_VOLTAGE_PAGE;
i++) {
pmbus_page_config(pmdev, i, PB_HAS_VOUT_MODE | PB_HAS_VOUT |
PB_HAS_VOUT_RATING);
}
}
static void max31785_class_init(ObjectClass *klass, void *data)
{
ResettableClass *rc = RESETTABLE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
PMBusDeviceClass *k = PMBUS_DEVICE_CLASS(klass);
dc->desc = "Maxim MAX31785 6-Channel Fan Controller";
dc->vmsd = &vmstate_max31785;
k->write_data = max31785_write_data;
k->receive_byte = max31785_read_byte;
k->device_num_pages = MAX31785_TOTAL_NUM_PAGES;
rc->phases.exit = max31785_exit_reset;
}
static const TypeInfo max31785_info = {
.name = TYPE_MAX31785,
.parent = TYPE_PMBUS_DEVICE,
.instance_size = sizeof(MAX31785State),
.instance_init = max31785_init,
.class_init = max31785_class_init,
};
static void max31785_register_types(void)
{
type_register_static(&max31785_info);
}
type_init(max31785_register_types)

View File

@ -6,3 +6,4 @@ softmmu_ss.add(when: 'CONFIG_ADM1272', if_true: files('adm1272.c'))
softmmu_ss.add(when: 'CONFIG_MAX34451', if_true: files('max34451.c'))
softmmu_ss.add(when: 'CONFIG_LSM303DLHC_MAG', if_true: files('lsm303dlhc_mag.c'))
softmmu_ss.add(when: 'CONFIG_ISL_PMBUS_VR', if_true: files('isl_pmbus_vr.c'))
softmmu_ss.add(when: 'CONFIG_MAX31785', if_true: files('max31785.c'))

View File

@ -488,7 +488,7 @@ static uint64_t aspeed_smc_flash_read(void *opaque, hwaddr addr, unsigned size)
switch (aspeed_smc_flash_mode(fl)) {
case CTRL_USERMODE:
for (i = 0; i < size; i++) {
ret |= ssi_transfer(s->spi, 0x0) << (8 * i);
ret |= (uint64_t) ssi_transfer(s->spi, 0x0) << (8 * i);
}
break;
case CTRL_READMODE:
@ -497,7 +497,7 @@ static uint64_t aspeed_smc_flash_read(void *opaque, hwaddr addr, unsigned size)
aspeed_smc_flash_setup(fl, addr);
for (i = 0; i < size; i++) {
ret |= ssi_transfer(s->spi, 0x0) << (8 * i);
ret |= (uint64_t) ssi_transfer(s->spi, 0x0) << (8 * i);
}
aspeed_smc_flash_unselect(fl);

View File

@ -34,6 +34,8 @@
#include "hw/usb/hcd-ehci.h"
#include "qom/object.h"
#include "hw/misc/aspeed_lpc.h"
#include "hw/misc/unimp.h"
#include "hw/misc/aspeed_peci.h"
#define ASPEED_SPIS_NUM 2
#define ASPEED_EHCIS_NUM 2
@ -49,7 +51,9 @@ struct AspeedSoCState {
ARMCPU cpu[ASPEED_CPUS_NUM];
A15MPPrivState a7mpcore;
ARMv7MState armv7m;
MemoryRegion *memory;
MemoryRegion *dram_mr;
MemoryRegion dram_container;
MemoryRegion sram;
AspeedVICState vic;
AspeedRtcState rtc;
@ -64,6 +68,7 @@ struct AspeedSoCState {
AspeedSMCState spi[ASPEED_SPIS_NUM];
EHCISysBusState ehci[ASPEED_EHCIS_NUM];
AspeedSBCState sbc;
UnimplementedDeviceState sbc_unimplemented;
AspeedSDMCState sdmc;
AspeedWDTState wdt[ASPEED_WDTS_NUM];
FTGMAC100State ftgmac100[ASPEED_MACS_NUM];
@ -73,8 +78,13 @@ struct AspeedSoCState {
AspeedSDHCIState sdhci;
AspeedSDHCIState emmc;
AspeedLPCState lpc;
AspeedPECIState peci;
uint32_t uart_default;
Clock *sysclk;
UnimplementedDeviceState iomem;
UnimplementedDeviceState video;
UnimplementedDeviceState emmc_boot_controller;
UnimplementedDeviceState dpmcu;
};
#define TYPE_ASPEED_SOC "aspeed-soc"
@ -145,6 +155,7 @@ enum {
ASPEED_DEV_LPC,
ASPEED_DEV_IBT,
ASPEED_DEV_I2C,
ASPEED_DEV_PECI,
ASPEED_DEV_ETH1,
ASPEED_DEV_ETH2,
ASPEED_DEV_ETH3,
@ -165,5 +176,10 @@ enum {
qemu_irq aspeed_soc_get_irq(AspeedSoCState *s, int dev);
void aspeed_soc_uart_init(AspeedSoCState *s);
bool aspeed_soc_dram_init(AspeedSoCState *s, Error **errp);
void aspeed_mmio_map(AspeedSoCState *s, SysBusDevice *dev, int n, hwaddr addr);
void aspeed_mmio_map_unimplemented(AspeedSoCState *s, SysBusDevice *dev,
const char *name, hwaddr addr,
uint64_t size);
#endif /* ASPEED_SOC_H */

View File

@ -174,6 +174,8 @@ REG32(I2CM_DMA_LEN, 0x1c)
FIELD(I2CM_DMA_LEN, TX_BUF_LEN_W1T, 15, 1)
FIELD(I2CM_DMA_LEN, TX_BUF_LEN, 0, 11)
REG32(I2CS_INTR_CTRL, 0x20)
FIELD(I2CS_INTR_CTRL, PKT_CMD_FAIL, 17, 1)
FIELD(I2CS_INTR_CTRL, PKT_CMD_DONE, 16, 1)
REG32(I2CS_INTR_STS, 0x24)
/* 31:29 shared with I2CD_INTR_STS[31:29] */
FIELD(I2CS_INTR_STS, SLAVE_PARKING_STS, 24, 2)
@ -184,6 +186,7 @@ REG32(I2CS_INTR_STS, 0x24)
FIELD(I2CS_INTR_STS, PKT_CMD_FAIL, 17, 1)
FIELD(I2CS_INTR_STS, PKT_CMD_DONE, 16, 1)
/* 14:0 shared with I2CD_INTR_STS[14:0] */
FIELD(I2CS_INTR_STS, SLAVE_ADDR_RX_MATCH, 7, 1)
REG32(I2CS_CMD, 0x28)
FIELD(I2CS_CMD, W1_CTRL, 31, 1)
FIELD(I2CS_CMD, PKT_MODE_ACTIVE_ADDR, 17, 2)
@ -223,6 +226,9 @@ struct AspeedI2CBus {
struct AspeedI2CState *controller;
/* slave mode */
I2CSlave *slave;
MemoryRegion mr;
I2CBus *bus;
@ -249,6 +255,11 @@ struct AspeedI2CState {
AddressSpace dram_as;
};
#define TYPE_ASPEED_I2C_BUS_SLAVE "aspeed.i2c.slave"
OBJECT_DECLARE_SIMPLE_TYPE(AspeedI2CBusSlave, ASPEED_I2C_BUS_SLAVE)
struct AspeedI2CBusSlave {
I2CSlave i2c;
};
struct AspeedI2CClass {
SysBusDeviceClass parent_class;

View File

@ -12,6 +12,7 @@
enum i2c_event {
I2C_START_RECV,
I2C_START_SEND,
I2C_START_SEND_ASYNC,
I2C_FINISH,
I2C_NACK /* Masker NACKed a receive byte. */
};
@ -28,6 +29,9 @@ struct I2CSlaveClass {
/* Master to slave. Returns non-zero for a NAK, 0 for success. */
int (*send)(I2CSlave *s, uint8_t data);
/* Master to slave (asynchronous). Receiving slave must call i2c_ack(). */
void (*send_async)(I2CSlave *s, uint8_t data);
/*
* Slave to master. This cannot fail, the device should always
* return something here.
@ -69,13 +73,25 @@ struct I2CNode {
QLIST_ENTRY(I2CNode) next;
};
typedef struct I2CPendingMaster I2CPendingMaster;
struct I2CPendingMaster {
QEMUBH *bh;
QSIMPLEQ_ENTRY(I2CPendingMaster) entry;
};
typedef QLIST_HEAD(I2CNodeList, I2CNode) I2CNodeList;
typedef QSIMPLEQ_HEAD(I2CPendingMasters, I2CPendingMaster) I2CPendingMasters;
struct I2CBus {
BusState qbus;
I2CNodeList current_devs;
I2CPendingMasters pending_masters;
uint8_t saved_address;
bool broadcast;
/* Set from slave currently mastering the bus. */
QEMUBH *bh;
};
I2CBus *i2c_init_bus(DeviceState *parent, const char *name);
@ -115,9 +131,23 @@ int i2c_start_recv(I2CBus *bus, uint8_t address);
*/
int i2c_start_send(I2CBus *bus, uint8_t address);
/**
* i2c_start_send_async: start an asynchronous 'send' transfer on an I2C bus.
*
* @bus: #I2CBus to be used
* @address: address of the slave
*
* Return: 0 on success, -1 on error
*/
int i2c_start_send_async(I2CBus *bus, uint8_t address);
void i2c_end_transfer(I2CBus *bus);
void i2c_nack(I2CBus *bus);
void i2c_ack(I2CBus *bus);
void i2c_bus_master(I2CBus *bus, QEMUBH *bh);
void i2c_bus_release(I2CBus *bus);
int i2c_send(I2CBus *bus, uint8_t data);
int i2c_send_async(I2CBus *bus, uint8_t data);
uint8_t i2c_recv(I2CBus *bus);
bool i2c_scan_bus(I2CBus *bus, uint8_t address, bool broadcast,
I2CNodeList *current_devs);

View File

@ -0,0 +1,29 @@
/*
* Aspeed PECI Controller
*
* 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.
*/
#ifndef ASPEED_PECI_H
#define ASPEED_PECI_H
#include "hw/sysbus.h"
#define ASPEED_PECI_NR_REGS ((0xFC + 4) >> 2)
#define TYPE_ASPEED_PECI "aspeed.peci"
OBJECT_DECLARE_SIMPLE_TYPE(AspeedPECIState, ASPEED_PECI);
struct AspeedPECIState {
/* <private> */
SysBusDevice parent;
MemoryRegion mmio;
qemu_irq irq;
uint32_t regs[ASPEED_PECI_NR_REGS];
};
#endif

View File

@ -56,7 +56,9 @@ enum {
BULK_ERASE = 0xc7,
READ = 0x03,
PP = 0x02,
WRSR = 0x1,
WREN = 0x6,
SRWD = 0x80,
RESET_ENABLE = 0x66,
RESET_MEMORY = 0x99,
EN_4BYTE_ADDR = 0xB7,
@ -441,6 +443,64 @@ static void test_read_status_reg(void)
flash_reset();
}
static void test_status_reg_write_protection(void)
{
uint8_t r;
spi_conf(CONF_ENABLE_W0);
/* default case: WP# is high and SRWD is low -> status register writable */
spi_ctrl_start_user();
writeb(ASPEED_FLASH_BASE, WREN);
/* test ability to write SRWD */
writeb(ASPEED_FLASH_BASE, WRSR);
writeb(ASPEED_FLASH_BASE, SRWD);
writeb(ASPEED_FLASH_BASE, RDSR);
r = readb(ASPEED_FLASH_BASE);
spi_ctrl_stop_user();
g_assert_cmphex(r & SRWD, ==, SRWD);
/* WP# high and SRWD high -> status register writable */
spi_ctrl_start_user();
writeb(ASPEED_FLASH_BASE, WREN);
/* test ability to write SRWD */
writeb(ASPEED_FLASH_BASE, WRSR);
writeb(ASPEED_FLASH_BASE, 0);
writeb(ASPEED_FLASH_BASE, RDSR);
r = readb(ASPEED_FLASH_BASE);
spi_ctrl_stop_user();
g_assert_cmphex(r & SRWD, ==, 0);
/* WP# low and SRWD low -> status register writable */
qtest_set_irq_in(global_qtest,
"/machine/soc/fmc/ssi.0/child[0]", "WP#", 0, 0);
spi_ctrl_start_user();
writeb(ASPEED_FLASH_BASE, WREN);
/* test ability to write SRWD */
writeb(ASPEED_FLASH_BASE, WRSR);
writeb(ASPEED_FLASH_BASE, SRWD);
writeb(ASPEED_FLASH_BASE, RDSR);
r = readb(ASPEED_FLASH_BASE);
spi_ctrl_stop_user();
g_assert_cmphex(r & SRWD, ==, SRWD);
/* WP# low and SRWD high -> status register NOT writable */
spi_ctrl_start_user();
writeb(ASPEED_FLASH_BASE, WREN);
/* test ability to write SRWD */
writeb(ASPEED_FLASH_BASE, WRSR);
writeb(ASPEED_FLASH_BASE, 0);
writeb(ASPEED_FLASH_BASE, RDSR);
r = readb(ASPEED_FLASH_BASE);
spi_ctrl_stop_user();
/* write is not successful */
g_assert_cmphex(r & SRWD, ==, SRWD);
qtest_set_irq_in(global_qtest,
"/machine/soc/fmc/ssi.0/child[0]", "WP#", 0, 1);
flash_reset();
}
static char tmp_path[] = "/tmp/qtest.m25p80.XXXXXX";
int main(int argc, char **argv)
@ -467,6 +527,8 @@ int main(int argc, char **argv)
qtest_add_func("/ast2400/smc/read_page_mem", test_read_page_mem);
qtest_add_func("/ast2400/smc/write_page_mem", test_write_page_mem);
qtest_add_func("/ast2400/smc/read_status_reg", test_read_status_reg);
qtest_add_func("/ast2400/smc/status_reg_write_protection",
test_status_reg_write_protection);
flash_reset();
ret = g_test_run();