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>
This commit is contained in:
commit
d495e432c0
@ -455,6 +455,8 @@ config ASPEED_SOC
|
||||
select EMC141X
|
||||
select UNIMP
|
||||
select LED
|
||||
select PMBUS
|
||||
select MAX31785
|
||||
|
||||
config MPS2
|
||||
bool
|
||||
|
136
hw/arm/aspeed.c
136
hw/arm/aspeed.c
@ -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,
|
||||
|
@ -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",
|
||||
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));
|
||||
}
|
||||
|
@ -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_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_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)
|
||||
|
@ -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_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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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,7 +1169,20 @@ static void decode_new_cmd(Flash *s, uint32_t value)
|
||||
break;
|
||||
|
||||
case WRSR:
|
||||
if (s->write_enable) {
|
||||
/*
|
||||
* 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;
|
||||
@ -1180,7 +1197,6 @@ static void decode_new_cmd(Flash *s, uint32_t value)
|
||||
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
|
||||
}
|
||||
};
|
||||
|
@ -76,6 +76,8 @@ static int sii9022_event(I2CSlave *i2c, enum i2c_event event)
|
||||
break;
|
||||
case I2C_NACK:
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -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;
|
||||
|
@ -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) ||
|
||||
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))) {
|
||||
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);
|
||||
|
@ -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;
|
||||
|
@ -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",
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
152
hw/misc/aspeed_peci.c
Normal 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);
|
@ -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];
|
||||
}
|
||||
|
||||
|
@ -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'))
|
||||
|
@ -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"
|
||||
|
||||
|
@ -75,6 +75,8 @@ int at24c_eeprom_event(I2CSlave *s, enum i2c_event event)
|
||||
break;
|
||||
case I2C_NACK:
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -34,3 +34,7 @@ config LSM303DLHC_MAG
|
||||
config ISL_PMBUS_VR
|
||||
bool
|
||||
depends on PMBUS
|
||||
|
||||
config MAX31785
|
||||
bool
|
||||
depends on PMBUS
|
||||
|
@ -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
573
hw/sensor/max31785.c
Normal 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)
|
@ -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'))
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
29
include/hw/misc/aspeed_peci.h
Normal file
29
include/hw/misc/aspeed_peci.h
Normal 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
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user