:p
atchew
Login
The following changes since commit c99e34e537f13a431a80e3e414e5904e9dd0a116: Merge remote-tracking branch 'remotes/vivier2/tags/linux-user-for-6.2-pull-request' into staging (2021-09-16 21:09:18 +0100) are available in the Git repository at: https://github.com/legoater/qemu/ tags/pull-aspeed-20210920 for you to fetch changes up to febbe308bf9477767ca92e8ed5f265b0001fcef9: hw/arm/aspeed: Add Fuji machine type (2021-09-20 08:50:59 +0200) ---------------------------------------------------------------- Aspeed patches : * MAC enablement fixes (Guenter) * Watchdog and pca9552 fixes (Andrew) * GPIO fixes (Joel) * AST2600A3 SoC and DPS310 models (Joel) * New Fuji BMC machine (Peter) ---------------------------------------------------------------- Andrew Jeffery (3): watchdog: aspeed: Sanitize control register values watchdog: aspeed: Fix sequential control writes misc/pca9552: Fix LED status register indexing in pca955x_get_led() Guenter Roeck (2): hw: arm: aspeed: Enable eth0 interface for aspeed-ast2600-evb hw: arm: aspeed: Enable mac0/1 instead of mac1/2 for g220a Joel Stanley (6): hw: aspeed_gpio: Simplify 1.8V defines hw: aspeed_gpio: Clarify GPIO controller name arm/aspeed: rainier: Add i2c eeproms and muxes aspeed: Emulate the AST2600A3 hw/misc: Add Infineon DPS310 sensor model arm/aspeed: Add DPS310 to Witherspoon and Rainier Peter Delevoryas (3): hw/arm/aspeed: Initialize AST2600 UART clock selection registers hw/arm/aspeed: Allow machine to set UART default hw/arm/aspeed: Add Fuji machine type include/hw/arm/aspeed.h | 1 + include/hw/arm/aspeed_soc.h | 1 + include/hw/misc/aspeed_scu.h | 2 + include/hw/watchdog/wdt_aspeed.h | 1 + hw/arm/aspeed.c | 182 +++++++++++++++++++++++++++++-- hw/arm/aspeed_ast2600.c | 14 +-- hw/arm/aspeed_soc.c | 8 +- hw/gpio/aspeed_gpio.c | 97 +++++++++-------- hw/misc/aspeed_scu.c | 40 +++++-- hw/misc/pca9552.c | 2 +- hw/sensor/dps310.c | 225 +++++++++++++++++++++++++++++++++++++++ hw/watchdog/wdt_aspeed.c | 26 ++++- hw/arm/Kconfig | 1 + hw/sensor/Kconfig | 4 + hw/sensor/meson.build | 1 + 15 files changed, 529 insertions(+), 76 deletions(-) create mode 100644 hw/sensor/dps310.c
From: Guenter Roeck <linux@roeck-us.net> Commit 7582591ae7 ("aspeed: Support AST2600A1 silicon revision") switched the silicon revision for AST2600 to revision A1. On revision A1, the first Ethernet interface is operational. Enable it. Signed-off-by: Guenter Roeck <linux@roeck-us.net> Reviewed-by: Joel Stanley <joel@jms.id.au> Reviewed-by: Cédric Le Goater <clg@kaod.org> Message-Id: <20210808200457.889955-1-linux@roeck-us.net> Signed-off-by: Cédric Le Goater <clg@kaod.org> --- hw/arm/aspeed.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -XXX,XX +XXX,XX @@ static void aspeed_machine_ast2600_evb_class_init(ObjectClass *oc, void *data) amc->fmc_model = "w25q512jv"; amc->spi_model = "mx66u51235f"; amc->num_cs = 1; - amc->macs_mask = ASPEED_MAC1_ON | ASPEED_MAC2_ON | ASPEED_MAC3_ON; + amc->macs_mask = ASPEED_MAC0_ON | ASPEED_MAC1_ON | ASPEED_MAC2_ON | + ASPEED_MAC3_ON; amc->i2c_init = ast2600_evb_i2c_init; mc->default_ram_size = 1 * GiB; mc->default_cpus = mc->min_cpus = mc->max_cpus = -- 2.31.1
From: Guenter Roeck <linux@roeck-us.net> According to its dts file in the Linux kernel, we need mac0 and mac1 enabled instead of mac1 and mac2. Also, g220a is based on aspeed-g5 (ast2500) which doesn't even have the third interface. Signed-off-by: Guenter Roeck <linux@roeck-us.net> Reviewed-by: Cédric Le Goater <clg@kaod.org> Message-Id: <20210810035742.550391-1-linux@roeck-us.net> Signed-off-by: Cédric Le Goater <clg@kaod.org> --- hw/arm/aspeed.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -XXX,XX +XXX,XX @@ static void aspeed_machine_g220a_class_init(ObjectClass *oc, void *data) amc->fmc_model = "n25q512a"; amc->spi_model = "mx25l25635e"; amc->num_cs = 2; - amc->macs_mask = ASPEED_MAC1_ON | ASPEED_MAC2_ON; + amc->macs_mask = ASPEED_MAC0_ON | ASPEED_MAC1_ON; amc->i2c_init = g220a_bmc_i2c_init; mc->default_ram_size = 1024 * MiB; mc->default_cpus = mc->min_cpus = mc->max_cpus = -- 2.31.1
From: Andrew Jeffery <andrew@aj.id.au> While some of the critical fields remain the same, there is variation in the definition of the control register across the SoC generations. Reserved regions are adjusted, while in other cases the mutability or behaviour of fields change. Introduce a callback to sanitize the value on writes to ensure model behaviour reflects the hardware. Fixes: 854123bf8d4b ("wdt: Add Aspeed watchdog device model") Signed-off-by: Andrew Jeffery <andrew@aj.id.au> Reviewed-by: Cédric Le Goater <clg@kaod.org> Message-Id: <20210709053107.1829304-2-andrew@aj.id.au> Signed-off-by: Cédric Le Goater <clg@kaod.org> --- include/hw/watchdog/wdt_aspeed.h | 1 + hw/watchdog/wdt_aspeed.c | 24 ++++++++++++++++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/include/hw/watchdog/wdt_aspeed.h b/include/hw/watchdog/wdt_aspeed.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/watchdog/wdt_aspeed.h +++ b/include/hw/watchdog/wdt_aspeed.h @@ -XXX,XX +XXX,XX @@ struct AspeedWDTClass { uint32_t reset_ctrl_reg; void (*reset_pulse)(AspeedWDTState *s, uint32_t property); void (*wdt_reload)(AspeedWDTState *s); + uint64_t (*sanitize_ctrl)(uint64_t data); }; #endif /* WDT_ASPEED_H */ diff --git a/hw/watchdog/wdt_aspeed.c b/hw/watchdog/wdt_aspeed.c index XXXXXXX..XXXXXXX 100644 --- a/hw/watchdog/wdt_aspeed.c +++ b/hw/watchdog/wdt_aspeed.c @@ -XXX,XX +XXX,XX @@ static void aspeed_wdt_reload_1mhz(AspeedWDTState *s) } } +static uint64_t aspeed_2400_sanitize_ctrl(uint64_t data) +{ + return data & 0xffff; +} + +static uint64_t aspeed_2500_sanitize_ctrl(uint64_t data) +{ + return (data & ~(0xfUL << 8)) | WDT_CTRL_1MHZ_CLK; +} + +static uint64_t aspeed_2600_sanitize_ctrl(uint64_t data) +{ + return data & ~(0x7UL << 7); +} static void aspeed_wdt_write(void *opaque, hwaddr offset, uint64_t data, unsigned size) { AspeedWDTState *s = ASPEED_WDT(opaque); AspeedWDTClass *awc = ASPEED_WDT_GET_CLASS(s); - bool enable = data & WDT_CTRL_ENABLE; + bool enable; offset >>= 2; @@ -XXX,XX +XXX,XX @@ static void aspeed_wdt_write(void *opaque, hwaddr offset, uint64_t data, } break; case WDT_CTRL: + data = awc->sanitize_ctrl(data); + enable = data & WDT_CTRL_ENABLE; if (enable && !aspeed_wdt_is_enabled(s)) { s->regs[WDT_CTRL] = data; awc->wdt_reload(s); @@ -XXX,XX +XXX,XX @@ static const MemoryRegionOps aspeed_wdt_ops = { static void aspeed_wdt_reset(DeviceState *dev) { AspeedWDTState *s = ASPEED_WDT(dev); + AspeedWDTClass *awc = ASPEED_WDT_GET_CLASS(s); s->regs[WDT_STATUS] = 0x3EF1480; s->regs[WDT_RELOAD_VALUE] = 0x03EF1480; s->regs[WDT_RESTART] = 0; - s->regs[WDT_CTRL] = 0; + s->regs[WDT_CTRL] = awc->sanitize_ctrl(0); s->regs[WDT_RESET_WIDTH] = 0xFF; timer_del(s->timer); @@ -XXX,XX +XXX,XX @@ static void aspeed_2400_wdt_class_init(ObjectClass *klass, void *data) awc->ext_pulse_width_mask = 0xff; awc->reset_ctrl_reg = SCU_RESET_CONTROL1; awc->wdt_reload = aspeed_wdt_reload; + awc->sanitize_ctrl = aspeed_2400_sanitize_ctrl; } static const TypeInfo aspeed_2400_wdt_info = { @@ -XXX,XX +XXX,XX @@ static void aspeed_2500_wdt_class_init(ObjectClass *klass, void *data) awc->reset_ctrl_reg = SCU_RESET_CONTROL1; awc->reset_pulse = aspeed_2500_wdt_reset_pulse; awc->wdt_reload = aspeed_wdt_reload_1mhz; + awc->sanitize_ctrl = aspeed_2500_sanitize_ctrl; } static const TypeInfo aspeed_2500_wdt_info = { @@ -XXX,XX +XXX,XX @@ static void aspeed_2600_wdt_class_init(ObjectClass *klass, void *data) awc->reset_ctrl_reg = AST2600_SCU_RESET_CONTROL1; awc->reset_pulse = aspeed_2500_wdt_reset_pulse; awc->wdt_reload = aspeed_wdt_reload_1mhz; + awc->sanitize_ctrl = aspeed_2600_sanitize_ctrl; } static const TypeInfo aspeed_2600_wdt_info = { -- 2.31.1
From: Andrew Jeffery <andrew@aj.id.au> The logic in the handling for the control register required toggling the enable state for writes to stick. Rework the condition chain to allow sequential writes that do not update the enable state. Fixes: 854123bf8d4b ("wdt: Add Aspeed watchdog device model") Signed-off-by: Andrew Jeffery <andrew@aj.id.au> Reviewed-by: Cédric Le Goater <clg@kaod.org> Message-Id: <20210709053107.1829304-3-andrew@aj.id.au> Signed-off-by: Cédric Le Goater <clg@kaod.org> --- hw/watchdog/wdt_aspeed.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/watchdog/wdt_aspeed.c b/hw/watchdog/wdt_aspeed.c index XXXXXXX..XXXXXXX 100644 --- a/hw/watchdog/wdt_aspeed.c +++ b/hw/watchdog/wdt_aspeed.c @@ -XXX,XX +XXX,XX @@ static void aspeed_wdt_write(void *opaque, hwaddr offset, uint64_t data, } else if (!enable && aspeed_wdt_is_enabled(s)) { s->regs[WDT_CTRL] = data; timer_del(s->timer); + } else { + s->regs[WDT_CTRL] = data; } break; case WDT_RESET_WIDTH: -- 2.31.1
From: Joel Stanley <joel@jms.id.au> There's no need to define the registers relative to the 0x800 offset where the controller is mapped, as the device is instantiated as it's own model at the correct memory address. Simplify the defines and remove the offset to save future confusion. Signed-off-by: Joel Stanley <joel@jms.id.au> Reviewed-by: Rashmica Gupta <rashmica.g@gmail.com> Reviewed-by: Cédric Le Goater <clg@kaod.org> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org> Message-Id: <20210713065854.134634-3-joel@jms.id.au> Signed-off-by: Cédric Le Goater <clg@kaod.org> --- hw/gpio/aspeed_gpio.c | 73 +++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 37 deletions(-) diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c index XXXXXXX..XXXXXXX 100644 --- a/hw/gpio/aspeed_gpio.c +++ b/hw/gpio/aspeed_gpio.c @@ -XXX,XX +XXX,XX @@ /* AST2600 only - 1.8V gpios */ /* - * The AST2600 has same 3.6V gpios as the AST2400 (memory offsets 0x0-0x198) - * and additional 1.8V gpios (memory offsets 0x800-0x9D4). + * The AST2600 two copies of the GPIO controller: the same 3.6V gpios as the + * AST2400 (memory offsets 0x0-0x198) and a second controller with 1.8V gpios + * (memory offsets 0x800-0x9D4). */ -#define GPIO_1_8V_REG_OFFSET 0x800 -#define GPIO_1_8V_ABCD_DATA_VALUE ((0x800 - GPIO_1_8V_REG_OFFSET) >> 2) -#define GPIO_1_8V_ABCD_DIRECTION ((0x804 - GPIO_1_8V_REG_OFFSET) >> 2) -#define GPIO_1_8V_ABCD_INT_ENABLE ((0x808 - GPIO_1_8V_REG_OFFSET) >> 2) -#define GPIO_1_8V_ABCD_INT_SENS_0 ((0x80C - GPIO_1_8V_REG_OFFSET) >> 2) -#define GPIO_1_8V_ABCD_INT_SENS_1 ((0x810 - GPIO_1_8V_REG_OFFSET) >> 2) -#define GPIO_1_8V_ABCD_INT_SENS_2 ((0x814 - GPIO_1_8V_REG_OFFSET) >> 2) -#define GPIO_1_8V_ABCD_INT_STATUS ((0x818 - GPIO_1_8V_REG_OFFSET) >> 2) -#define GPIO_1_8V_ABCD_RESET_TOLERANT ((0x81C - GPIO_1_8V_REG_OFFSET) >> 2) -#define GPIO_1_8V_E_DATA_VALUE ((0x820 - GPIO_1_8V_REG_OFFSET) >> 2) -#define GPIO_1_8V_E_DIRECTION ((0x824 - GPIO_1_8V_REG_OFFSET) >> 2) -#define GPIO_1_8V_E_INT_ENABLE ((0x828 - GPIO_1_8V_REG_OFFSET) >> 2) -#define GPIO_1_8V_E_INT_SENS_0 ((0x82C - GPIO_1_8V_REG_OFFSET) >> 2) -#define GPIO_1_8V_E_INT_SENS_1 ((0x830 - GPIO_1_8V_REG_OFFSET) >> 2) -#define GPIO_1_8V_E_INT_SENS_2 ((0x834 - GPIO_1_8V_REG_OFFSET) >> 2) -#define GPIO_1_8V_E_INT_STATUS ((0x838 - GPIO_1_8V_REG_OFFSET) >> 2) -#define GPIO_1_8V_E_RESET_TOLERANT ((0x83C - GPIO_1_8V_REG_OFFSET) >> 2) -#define GPIO_1_8V_ABCD_DEBOUNCE_1 ((0x840 - GPIO_1_8V_REG_OFFSET) >> 2) -#define GPIO_1_8V_ABCD_DEBOUNCE_2 ((0x844 - GPIO_1_8V_REG_OFFSET) >> 2) -#define GPIO_1_8V_E_DEBOUNCE_1 ((0x848 - GPIO_1_8V_REG_OFFSET) >> 2) -#define GPIO_1_8V_E_DEBOUNCE_2 ((0x84C - GPIO_1_8V_REG_OFFSET) >> 2) -#define GPIO_1_8V_DEBOUNCE_TIME_1 ((0x850 - GPIO_1_8V_REG_OFFSET) >> 2) -#define GPIO_1_8V_DEBOUNCE_TIME_2 ((0x854 - GPIO_1_8V_REG_OFFSET) >> 2) -#define GPIO_1_8V_DEBOUNCE_TIME_3 ((0x858 - GPIO_1_8V_REG_OFFSET) >> 2) -#define GPIO_1_8V_ABCD_COMMAND_SRC_0 ((0x860 - GPIO_1_8V_REG_OFFSET) >> 2) -#define GPIO_1_8V_ABCD_COMMAND_SRC_1 ((0x864 - GPIO_1_8V_REG_OFFSET) >> 2) -#define GPIO_1_8V_E_COMMAND_SRC_0 ((0x868 - GPIO_1_8V_REG_OFFSET) >> 2) -#define GPIO_1_8V_E_COMMAND_SRC_1 ((0x86C - GPIO_1_8V_REG_OFFSET) >> 2) -#define GPIO_1_8V_ABCD_DATA_READ ((0x8C0 - GPIO_1_8V_REG_OFFSET) >> 2) -#define GPIO_1_8V_E_DATA_READ ((0x8C4 - GPIO_1_8V_REG_OFFSET) >> 2) -#define GPIO_1_8V_ABCD_INPUT_MASK ((0x9D0 - GPIO_1_8V_REG_OFFSET) >> 2) -#define GPIO_1_8V_E_INPUT_MASK ((0x9D4 - GPIO_1_8V_REG_OFFSET) >> 2) -#define GPIO_1_8V_MEM_SIZE 0x9D8 -#define GPIO_1_8V_REG_ARRAY_SIZE ((GPIO_1_8V_MEM_SIZE - \ - GPIO_1_8V_REG_OFFSET) >> 2) +#define GPIO_1_8V_ABCD_DATA_VALUE (0x000 >> 2) +#define GPIO_1_8V_ABCD_DIRECTION (0x004 >> 2) +#define GPIO_1_8V_ABCD_INT_ENABLE (0x008 >> 2) +#define GPIO_1_8V_ABCD_INT_SENS_0 (0x00C >> 2) +#define GPIO_1_8V_ABCD_INT_SENS_1 (0x010 >> 2) +#define GPIO_1_8V_ABCD_INT_SENS_2 (0x014 >> 2) +#define GPIO_1_8V_ABCD_INT_STATUS (0x018 >> 2) +#define GPIO_1_8V_ABCD_RESET_TOLERANT (0x01C >> 2) +#define GPIO_1_8V_E_DATA_VALUE (0x020 >> 2) +#define GPIO_1_8V_E_DIRECTION (0x024 >> 2) +#define GPIO_1_8V_E_INT_ENABLE (0x028 >> 2) +#define GPIO_1_8V_E_INT_SENS_0 (0x02C >> 2) +#define GPIO_1_8V_E_INT_SENS_1 (0x030 >> 2) +#define GPIO_1_8V_E_INT_SENS_2 (0x034 >> 2) +#define GPIO_1_8V_E_INT_STATUS (0x038 >> 2) +#define GPIO_1_8V_E_RESET_TOLERANT (0x03C >> 2) +#define GPIO_1_8V_ABCD_DEBOUNCE_1 (0x040 >> 2) +#define GPIO_1_8V_ABCD_DEBOUNCE_2 (0x044 >> 2) +#define GPIO_1_8V_E_DEBOUNCE_1 (0x048 >> 2) +#define GPIO_1_8V_E_DEBOUNCE_2 (0x04C >> 2) +#define GPIO_1_8V_DEBOUNCE_TIME_1 (0x050 >> 2) +#define GPIO_1_8V_DEBOUNCE_TIME_2 (0x054 >> 2) +#define GPIO_1_8V_DEBOUNCE_TIME_3 (0x058 >> 2) +#define GPIO_1_8V_ABCD_COMMAND_SRC_0 (0x060 >> 2) +#define GPIO_1_8V_ABCD_COMMAND_SRC_1 (0x064 >> 2) +#define GPIO_1_8V_E_COMMAND_SRC_0 (0x068 >> 2) +#define GPIO_1_8V_E_COMMAND_SRC_1 (0x06C >> 2) +#define GPIO_1_8V_ABCD_DATA_READ (0x0C0 >> 2) +#define GPIO_1_8V_E_DATA_READ (0x0C4 >> 2) +#define GPIO_1_8V_ABCD_INPUT_MASK (0x1D0 >> 2) +#define GPIO_1_8V_E_INPUT_MASK (0x1D4 >> 2) +#define GPIO_1_8V_MEM_SIZE 0x1D8 +#define GPIO_1_8V_REG_ARRAY_SIZE (GPIO_1_8V_MEM_SIZE >> 2) static int aspeed_evaluate_irq(GPIOSets *regs, int gpio_prev_high, int gpio) { -- 2.31.1
From: Joel Stanley <joel@jms.id.au> There are two GPIO controllers in the ast2600; one is 3.3V and the other is 1.8V. Signed-off-by: Joel Stanley <joel@jms.id.au> Reviewed-by: Rashmica Gupta <rashmica.g@gmail.com> Reviewed-by: Cédric Le Goater <clg@kaod.org> Message-Id: <20210713065854.134634-4-joel@jms.id.au> Signed-off-by: Cédric Le Goater <clg@kaod.org> --- hw/gpio/aspeed_gpio.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c index XXXXXXX..XXXXXXX 100644 --- a/hw/gpio/aspeed_gpio.c +++ b/hw/gpio/aspeed_gpio.c @@ -XXX,XX +XXX,XX @@ #define GPIO_YZAAAB_DIRECTION (0x1E4 >> 2) #define GPIO_AC_DATA_VALUE (0x1E8 >> 2) #define GPIO_AC_DIRECTION (0x1EC >> 2) -#define GPIO_3_6V_MEM_SIZE 0x1F0 -#define GPIO_3_6V_REG_ARRAY_SIZE (GPIO_3_6V_MEM_SIZE >> 2) +#define GPIO_3_3V_MEM_SIZE 0x1F0 +#define GPIO_3_3V_REG_ARRAY_SIZE (GPIO_3_3V_MEM_SIZE >> 2) /* AST2600 only - 1.8V gpios */ /* - * The AST2600 two copies of the GPIO controller: the same 3.6V gpios as the + * The AST2600 two copies of the GPIO controller: the same 3.3V gpios as the * AST2400 (memory offsets 0x0-0x198) and a second controller with 1.8V gpios * (memory offsets 0x800-0x9D4). */ @@ -XXX,XX +XXX,XX @@ static uint32_t update_value_control_source(GPIOSets *regs, uint32_t old_value, return new_value; } -static const AspeedGPIOReg aspeed_3_6v_gpios[GPIO_3_6V_REG_ARRAY_SIZE] = { +static const AspeedGPIOReg aspeed_3_3v_gpios[GPIO_3_3V_REG_ARRAY_SIZE] = { /* Set ABCD */ [GPIO_ABCD_DATA_VALUE] = { 0, gpio_reg_data_value }, [GPIO_ABCD_DIRECTION] = { 0, gpio_reg_direction }, @@ -XXX,XX +XXX,XX @@ static const GPIOSetProperties ast2500_set_props[] = { [7] = {0x000000ff, 0x000000ff, {"AC"} }, }; -static GPIOSetProperties ast2600_3_6v_set_props[] = { +static GPIOSetProperties ast2600_3_3v_set_props[] = { [0] = {0xffffffff, 0xffffffff, {"A", "B", "C", "D"} }, [1] = {0xffffffff, 0xffffffff, {"E", "F", "G", "H"} }, [2] = {0xffffffff, 0xffffffff, {"I", "J", "K", "L"} }, @@ -XXX,XX +XXX,XX @@ static void aspeed_gpio_ast2400_class_init(ObjectClass *klass, void *data) agc->nr_gpio_pins = 216; agc->nr_gpio_sets = 7; agc->gap = 196; - agc->reg_table = aspeed_3_6v_gpios; + agc->reg_table = aspeed_3_3v_gpios; } static void aspeed_gpio_2500_class_init(ObjectClass *klass, void *data) @@ -XXX,XX +XXX,XX @@ static void aspeed_gpio_2500_class_init(ObjectClass *klass, void *data) agc->nr_gpio_pins = 228; agc->nr_gpio_sets = 8; agc->gap = 220; - agc->reg_table = aspeed_3_6v_gpios; + agc->reg_table = aspeed_3_3v_gpios; } -static void aspeed_gpio_ast2600_3_6v_class_init(ObjectClass *klass, void *data) +static void aspeed_gpio_ast2600_3_3v_class_init(ObjectClass *klass, void *data) { AspeedGPIOClass *agc = ASPEED_GPIO_CLASS(klass); - agc->props = ast2600_3_6v_set_props; + agc->props = ast2600_3_3v_set_props; agc->nr_gpio_pins = 208; agc->nr_gpio_sets = 7; - agc->reg_table = aspeed_3_6v_gpios; + agc->reg_table = aspeed_3_3v_gpios; } static void aspeed_gpio_ast2600_1_8v_class_init(ObjectClass *klass, void *data) @@ -XXX,XX +XXX,XX @@ static const TypeInfo aspeed_gpio_ast2500_info = { .instance_init = aspeed_gpio_init, }; -static const TypeInfo aspeed_gpio_ast2600_3_6v_info = { +static const TypeInfo aspeed_gpio_ast2600_3_3v_info = { .name = TYPE_ASPEED_GPIO "-ast2600", .parent = TYPE_ASPEED_GPIO, - .class_init = aspeed_gpio_ast2600_3_6v_class_init, + .class_init = aspeed_gpio_ast2600_3_3v_class_init, .instance_init = aspeed_gpio_init, }; @@ -XXX,XX +XXX,XX @@ static void aspeed_gpio_register_types(void) type_register_static(&aspeed_gpio_info); type_register_static(&aspeed_gpio_ast2400_info); type_register_static(&aspeed_gpio_ast2500_info); - type_register_static(&aspeed_gpio_ast2600_3_6v_info); + type_register_static(&aspeed_gpio_ast2600_3_3v_info); type_register_static(&aspeed_gpio_ast2600_1_8v_info); } -- 2.31.1
From: Andrew Jeffery <andrew@aj.id.au> There was a bit of a thinko in the state calculation where every odd pin in was reported in e.g. "pwm0" mode rather than "off". This was the result of an incorrect bit shift for the 2-bit field representing each LED state. Fixes: a90d8f84674d ("misc/pca9552: Add qom set and get") Signed-off-by: Andrew Jeffery <andrew@aj.id.au> Reviewed-by: Cédric Le Goater <clg@kaod.org> Message-Id: <20210723043624.348158-1-andrew@aj.id.au> Signed-off-by: Cédric Le Goater <clg@kaod.org> --- hw/misc/pca9552.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/misc/pca9552.c b/hw/misc/pca9552.c index XXXXXXX..XXXXXXX 100644 --- a/hw/misc/pca9552.c +++ b/hw/misc/pca9552.c @@ -XXX,XX +XXX,XX @@ static void pca955x_get_led(Object *obj, Visitor *v, const char *name, * reading the INPUTx reg */ reg = PCA9552_LS0 + led / 4; - state = (pca955x_read(s, reg) >> (led % 8)) & 0x3; + state = (pca955x_read(s, reg) >> ((led % 4) * 2)) & 0x3; visit_type_str(v, name, (char **)&led_state[state], errp); } -- 2.31.1
From: Joel Stanley <joel@jms.id.au> These are the devices documented by the Rainier device tree. With this we can see the guest discovering the multiplexers and probing the eeprom devices: i2c i2c-2: Added multiplexed i2c bus 16 i2c i2c-2: Added multiplexed i2c bus 17 i2c i2c-2: Added multiplexed i2c bus 18 i2c i2c-2: Added multiplexed i2c bus 19 i2c-mux-gpio i2cmux: 4 port mux on 1e78a180.i2c-bus adapter at24 20-0050: 8192 byte 24c64 EEPROM, writable, 1 bytes/write i2c i2c-4: Added multiplexed i2c bus 20 at24 21-0051: 8192 byte 24c64 EEPROM, writable, 1 bytes/write i2c i2c-4: Added multiplexed i2c bus 21 at24 22-0052: 8192 byte 24c64 EEPROM, writable, 1 bytes/write Signed-off-by: Joel Stanley <joel@jms.id.au> [ clg: Introduced aspeed_eeprom_init ] Message-Id: <20210629142336.750058-2-clg@kaod.org> Signed-off-by: Cédric Le Goater <clg@kaod.org> --- hw/arm/aspeed.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -XXX,XX +XXX,XX @@ static void g220a_bmc_i2c_init(AspeedMachineState *bmc) eeprom_buf); } +static void aspeed_eeprom_init(I2CBus *bus, uint8_t addr, uint32_t rsize) +{ + I2CSlave *i2c_dev = i2c_slave_new("at24c-eeprom", addr); + DeviceState *dev = DEVICE(i2c_dev); + + qdev_prop_set_uint32(dev, "rom-size", rsize); + i2c_slave_realize_and_unref(i2c_dev, bus, &error_abort); +} + static void rainier_bmc_i2c_init(AspeedMachineState *bmc) { AspeedSoCState *soc = &bmc->soc; + I2CSlave *i2c_mux; + + aspeed_eeprom_init(aspeed_i2c_get_bus(&soc->i2c, 0), 0x51, 32 * KiB); /* The rainier expects a TMP275 but a TMP105 is compatible */ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 4), TYPE_TMP105, @@ -XXX,XX +XXX,XX @@ static void rainier_bmc_i2c_init(AspeedMachineState *bmc) 0x49); i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 4), TYPE_TMP105, 0x4a); + i2c_mux = i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 4), + "pca9546", 0x70); + aspeed_eeprom_init(pca954x_i2c_get_bus(i2c_mux, 0), 0x50, 64 * KiB); + aspeed_eeprom_init(pca954x_i2c_get_bus(i2c_mux, 1), 0x51, 64 * KiB); + aspeed_eeprom_init(pca954x_i2c_get_bus(i2c_mux, 2), 0x52, 64 * KiB); i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 5), TYPE_TMP105, 0x48); i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 5), TYPE_TMP105, 0x49); + i2c_mux = i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 5), + "pca9546", 0x70); + aspeed_eeprom_init(pca954x_i2c_get_bus(i2c_mux, 0), 0x50, 64 * KiB); + aspeed_eeprom_init(pca954x_i2c_get_bus(i2c_mux, 1), 0x51, 64 * KiB); i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 6), TYPE_TMP105, 0x48); @@ -XXX,XX +XXX,XX @@ static void rainier_bmc_i2c_init(AspeedMachineState *bmc) 0x4a); i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 6), TYPE_TMP105, 0x4b); + i2c_mux = i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 6), + "pca9546", 0x70); + aspeed_eeprom_init(pca954x_i2c_get_bus(i2c_mux, 0), 0x50, 64 * KiB); + aspeed_eeprom_init(pca954x_i2c_get_bus(i2c_mux, 1), 0x51, 64 * KiB); + aspeed_eeprom_init(pca954x_i2c_get_bus(i2c_mux, 2), 0x50, 64 * KiB); + aspeed_eeprom_init(pca954x_i2c_get_bus(i2c_mux, 3), 0x51, 64 * KiB); /* Bus 7: TODO dps310@76 */ /* Bus 7: TODO max31785@52 */ @@ -XXX,XX +XXX,XX @@ static void rainier_bmc_i2c_init(AspeedMachineState *bmc) /* Bus 7: TODO si7021-a20@20 */ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 7), TYPE_TMP105, 0x48); + 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); i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 8), TYPE_TMP105, 0x48); i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 8), TYPE_TMP105, 0x4a); + aspeed_eeprom_init(aspeed_i2c_get_bus(&soc->i2c, 8), 0x50, 64 * KiB); + aspeed_eeprom_init(aspeed_i2c_get_bus(&soc->i2c, 8), 0x51, 64 * KiB); i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 8), "pca9552", 0x61); /* Bus 8: ucd90320@11 */ /* Bus 8: ucd90320@b */ @@ -XXX,XX +XXX,XX @@ static void rainier_bmc_i2c_init(AspeedMachineState *bmc) i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 9), "tmp423", 0x4c); i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 9), "tmp423", 0x4d); + aspeed_eeprom_init(aspeed_i2c_get_bus(&soc->i2c, 9), 0x50, 128 * KiB); i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 10), "tmp423", 0x4c); i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 10), "tmp423", 0x4d); + aspeed_eeprom_init(aspeed_i2c_get_bus(&soc->i2c, 10), 0x50, 128 * KiB); i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 11), TYPE_TMP105, 0x48); i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 11), TYPE_TMP105, 0x49); + i2c_mux = i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 11), + "pca9546", 0x70); + aspeed_eeprom_init(pca954x_i2c_get_bus(i2c_mux, 0), 0x50, 64 * KiB); + aspeed_eeprom_init(pca954x_i2c_get_bus(i2c_mux, 1), 0x51, 64 * KiB); + + + aspeed_eeprom_init(aspeed_i2c_get_bus(&soc->i2c, 13), 0x50, 64 * KiB); + + aspeed_eeprom_init(aspeed_i2c_get_bus(&soc->i2c, 14), 0x50, 64 * KiB); + + aspeed_eeprom_init(aspeed_i2c_get_bus(&soc->i2c, 15), 0x50, 64 * KiB); } static bool aspeed_get_mmio_exec(Object *obj, Error **errp) -- 2.31.1
From: Joel Stanley <joel@jms.id.au> This is the latest revision of the ASPEED 2600 SoC. As there is no need to model multiple revisions of the same SoC for the moment, update the SCU AST2600 to model the A3 revision instead of the A1 and adapt the AST2600 SoC and machines. Reset values are taken from v8 of the datasheet. Signed-off-by: Joel Stanley <joel@jms.id.au> [ clg: - Introduced an Aspeed "ast2600-a3" SoC class - Commit log update ] Message-Id: <20210629142336.750058-3-clg@kaod.org> Signed-off-by: Cédric Le Goater <clg@kaod.org> --- include/hw/misc/aspeed_scu.h | 2 ++ hw/arm/aspeed.c | 6 +++--- hw/arm/aspeed_ast2600.c | 6 +++--- hw/misc/aspeed_scu.c | 36 +++++++++++++++++++++++++++++------- 4 files changed, 37 insertions(+), 13 deletions(-) diff --git a/include/hw/misc/aspeed_scu.h b/include/hw/misc/aspeed_scu.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/misc/aspeed_scu.h +++ b/include/hw/misc/aspeed_scu.h @@ -XXX,XX +XXX,XX @@ struct AspeedSCUState { #define AST2500_A1_SILICON_REV 0x04010303U #define AST2600_A0_SILICON_REV 0x05000303U #define AST2600_A1_SILICON_REV 0x05010303U +#define AST2600_A2_SILICON_REV 0x05020303U +#define AST2600_A3_SILICON_REV 0x05030303U #define ASPEED_IS_AST2500(si_rev) ((((si_rev) >> 24) & 0xff) == 0x04) diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -XXX,XX +XXX,XX @@ static void aspeed_machine_ast2600_evb_class_init(ObjectClass *oc, void *data) AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc); mc->desc = "Aspeed AST2600 EVB (Cortex-A7)"; - amc->soc_name = "ast2600-a1"; + amc->soc_name = "ast2600-a3"; amc->hw_strap1 = AST2600_EVB_HW_STRAP1; amc->hw_strap2 = AST2600_EVB_HW_STRAP2; amc->fmc_model = "w25q512jv"; @@ -XXX,XX +XXX,XX @@ static void aspeed_machine_tacoma_class_init(ObjectClass *oc, void *data) AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc); mc->desc = "OpenPOWER Tacoma BMC (Cortex-A7)"; - amc->soc_name = "ast2600-a1"; + amc->soc_name = "ast2600-a3"; amc->hw_strap1 = TACOMA_BMC_HW_STRAP1; amc->hw_strap2 = TACOMA_BMC_HW_STRAP2; amc->fmc_model = "mx66l1g45g"; @@ -XXX,XX +XXX,XX @@ static void aspeed_machine_rainier_class_init(ObjectClass *oc, void *data) AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc); mc->desc = "IBM Rainier BMC (Cortex-A7)"; - amc->soc_name = "ast2600-a1"; + amc->soc_name = "ast2600-a3"; amc->hw_strap1 = RAINIER_BMC_HW_STRAP1; amc->hw_strap2 = RAINIER_BMC_HW_STRAP2; amc->fmc_model = "mx66l1g45g"; diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/aspeed_ast2600.c +++ b/hw/arm/aspeed_ast2600.c @@ -XXX,XX +XXX,XX @@ static void aspeed_soc_ast2600_class_init(ObjectClass *oc, void *data) dc->realize = aspeed_soc_ast2600_realize; - sc->name = "ast2600-a1"; + sc->name = "ast2600-a3"; sc->cpu_type = ARM_CPU_TYPE_NAME("cortex-a7"); - sc->silicon_rev = AST2600_A1_SILICON_REV; + sc->silicon_rev = AST2600_A3_SILICON_REV; sc->sram_size = 0x16400; sc->spis_num = 2; sc->ehcis_num = 2; @@ -XXX,XX +XXX,XX @@ static void aspeed_soc_ast2600_class_init(ObjectClass *oc, void *data) } static const TypeInfo aspeed_soc_ast2600_type_info = { - .name = "ast2600-a1", + .name = "ast2600-a3", .parent = TYPE_ASPEED_SOC, .instance_size = sizeof(AspeedSoCState), .instance_init = aspeed_soc_ast2600_init, diff --git a/hw/misc/aspeed_scu.c b/hw/misc/aspeed_scu.c index XXXXXXX..XXXXXXX 100644 --- a/hw/misc/aspeed_scu.c +++ b/hw/misc/aspeed_scu.c @@ -XXX,XX +XXX,XX @@ #define AST2600_CLK_STOP_CTRL_CLR TO_REG(0x84) #define AST2600_CLK_STOP_CTRL2 TO_REG(0x90) #define AST2600_CLK_STOP_CTRL2_CLR TO_REG(0x94) +#define AST2600_DEBUG_CTRL TO_REG(0xC8) +#define AST2600_DEBUG_CTRL2 TO_REG(0xD8) #define AST2600_SDRAM_HANDSHAKE TO_REG(0x100) #define AST2600_HPLL_PARAM TO_REG(0x200) #define AST2600_HPLL_EXT TO_REG(0x204) +#define AST2600_APLL_PARAM TO_REG(0x210) +#define AST2600_APLL_EXT TO_REG(0x214) +#define AST2600_MPLL_PARAM TO_REG(0x220) #define AST2600_MPLL_EXT TO_REG(0x224) +#define AST2600_EPLL_PARAM TO_REG(0x240) #define AST2600_EPLL_EXT TO_REG(0x244) +#define AST2600_DPLL_PARAM TO_REG(0x260) +#define AST2600_DPLL_EXT TO_REG(0x264) #define AST2600_CLK_SEL TO_REG(0x300) #define AST2600_CLK_SEL2 TO_REG(0x304) -#define AST2600_CLK_SEL3 TO_REG(0x310) +#define AST2600_CLK_SEL3 TO_REG(0x308) +#define AST2600_CLK_SEL4 TO_REG(0x310) +#define AST2600_CLK_SEL5 TO_REG(0x314) #define AST2600_HW_STRAP1 TO_REG(0x500) #define AST2600_HW_STRAP1_CLR TO_REG(0x504) #define AST2600_HW_STRAP1_PROT TO_REG(0x508) @@ -XXX,XX +XXX,XX @@ static uint32_t aspeed_silicon_revs[] = { AST2500_A1_SILICON_REV, AST2600_A0_SILICON_REV, AST2600_A1_SILICON_REV, + AST2600_A2_SILICON_REV, + AST2600_A3_SILICON_REV, }; bool is_supported_silicon_rev(uint32_t silicon_rev) @@ -XXX,XX +XXX,XX @@ static const MemoryRegionOps aspeed_ast2600_scu_ops = { .valid.unaligned = false, }; -static const uint32_t ast2600_a1_resets[ASPEED_AST2600_SCU_NR_REGS] = { +static const uint32_t ast2600_a3_resets[ASPEED_AST2600_SCU_NR_REGS] = { [AST2600_SYS_RST_CTRL] = 0xF7C3FED8, - [AST2600_SYS_RST_CTRL2] = 0xFFFFFFFC, + [AST2600_SYS_RST_CTRL2] = 0x0DFFFFFC, [AST2600_CLK_STOP_CTRL] = 0xFFFF7F8A, [AST2600_CLK_STOP_CTRL2] = 0xFFF0FFF0, + [AST2600_DEBUG_CTRL] = 0x00000FFF, + [AST2600_DEBUG_CTRL2] = 0x000000FF, [AST2600_SDRAM_HANDSHAKE] = 0x00000000, - [AST2600_HPLL_PARAM] = 0x1000405F, + [AST2600_HPLL_PARAM] = 0x1000408F, + [AST2600_APLL_PARAM] = 0x1000405F, + [AST2600_MPLL_PARAM] = 0x1008405F, + [AST2600_EPLL_PARAM] = 0x1004077F, + [AST2600_DPLL_PARAM] = 0x1078405F, + [AST2600_CLK_SEL] = 0xF3940000, + [AST2600_CLK_SEL2] = 0x00700000, + [AST2600_CLK_SEL3] = 0x00000000, + [AST2600_CLK_SEL4] = 0xF3F40000, + [AST2600_CLK_SEL5] = 0x30000000, [AST2600_CHIP_ID0] = 0x1234ABCD, [AST2600_CHIP_ID1] = 0x88884444, - }; static void aspeed_ast2600_scu_reset(DeviceState *dev) @@ -XXX,XX +XXX,XX @@ static void aspeed_ast2600_scu_reset(DeviceState *dev) * of actual revision. QEMU and Linux only support A1 onwards so this is * sufficient. */ - s->regs[AST2600_SILICON_REV] = AST2600_A1_SILICON_REV; + s->regs[AST2600_SILICON_REV] = AST2600_A3_SILICON_REV; s->regs[AST2600_SILICON_REV2] = s->silicon_rev; s->regs[AST2600_HW_STRAP1] = s->hw_strap1; s->regs[AST2600_HW_STRAP2] = s->hw_strap2; @@ -XXX,XX +XXX,XX @@ static void aspeed_2600_scu_class_init(ObjectClass *klass, void *data) dc->desc = "ASPEED 2600 System Control Unit"; dc->reset = aspeed_ast2600_scu_reset; - asc->resets = ast2600_a1_resets; + asc->resets = ast2600_a3_resets; asc->calc_hpll = aspeed_2500_scu_calc_hpll; /* No change since AST2500 */ asc->apb_divider = 4; asc->nr_regs = ASPEED_AST2600_SCU_NR_REGS; -- 2.31.1
From: Joel Stanley <joel@jms.id.au> This contains some hardcoded register values that were obtained from the hardware after reading the temperature. It does enough to test the Linux kernel driver. The FIFO mode, IRQs and operation modes other than the default as used by Linux are not modelled. Signed-off-by: Joel Stanley <joel@jms.id.au> Message-Id: <20210616073358.750472-2-joel@jms.id.au> [ clg: - Fixed sequential reading - Reworked regs_reset_state array - Moved model under hw/sensor/ ] Message-Id: <20210629142336.750058-4-clg@kaod.org> Signed-off-by: Cédric Le Goater <clg@kaod.org> --- hw/sensor/dps310.c | 225 ++++++++++++++++++++++++++++++++++++++++++ hw/arm/Kconfig | 1 + hw/sensor/Kconfig | 4 + hw/sensor/meson.build | 1 + 4 files changed, 231 insertions(+) create mode 100644 hw/sensor/dps310.c diff --git a/hw/sensor/dps310.c b/hw/sensor/dps310.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/hw/sensor/dps310.c @@ -XXX,XX +XXX,XX @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright 2017-2021 Joel Stanley <joel@jms.id.au>, IBM Corporation + * + * Infineon DPS310 temperature and humidity sensor + * + * https://www.infineon.com/cms/en/product/sensor/pressure-sensors/pressure-sensors-for-iot/dps310/ + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "hw/hw.h" +#include "hw/i2c/i2c.h" +#include "qapi/error.h" +#include "qapi/visitor.h" +#include "migration/vmstate.h" + +#define NUM_REGISTERS 0x33 + +typedef struct DPS310State { + /*< private >*/ + I2CSlave i2c; + + /*< public >*/ + uint8_t regs[NUM_REGISTERS]; + + uint8_t len; + uint8_t pointer; + +} DPS310State; + +#define TYPE_DPS310 "dps310" +#define DPS310(obj) OBJECT_CHECK(DPS310State, (obj), TYPE_DPS310) + +#define DPS310_PRS_B2 0x00 +#define DPS310_PRS_B1 0x01 +#define DPS310_PRS_B0 0x02 +#define DPS310_TMP_B2 0x03 +#define DPS310_TMP_B1 0x04 +#define DPS310_TMP_B0 0x05 +#define DPS310_PRS_CFG 0x06 +#define DPS310_TMP_CFG 0x07 +#define DPS310_TMP_RATE_BITS (0x70) +#define DPS310_MEAS_CFG 0x08 +#define DPS310_MEAS_CTRL_BITS (0x07) +#define DPS310_PRESSURE_EN BIT(0) +#define DPS310_TEMP_EN BIT(1) +#define DPS310_BACKGROUND BIT(2) +#define DPS310_PRS_RDY BIT(4) +#define DPS310_TMP_RDY BIT(5) +#define DPS310_SENSOR_RDY BIT(6) +#define DPS310_COEF_RDY BIT(7) +#define DPS310_CFG_REG 0x09 +#define DPS310_RESET 0x0c +#define DPS310_RESET_MAGIC (BIT(0) | BIT(3)) +#define DPS310_COEF_BASE 0x10 +#define DPS310_COEF_LAST 0x21 +#define DPS310_COEF_SRC 0x28 + +static void dps310_reset(DeviceState *dev) +{ + DPS310State *s = DPS310(dev); + + static const uint8_t regs_reset_state[sizeof(s->regs)] = { + 0xfe, 0x2f, 0xee, 0x02, 0x69, 0xa6, 0x00, 0x80, 0xc7, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x0e, 0x1e, 0xdd, 0x13, 0xca, 0x5f, 0x21, 0x52, + 0xf9, 0xc6, 0x04, 0xd1, 0xdb, 0x47, 0x00, 0x5b, 0xfb, 0x3a, 0x00, 0x00, + 0x20, 0x49, 0x4e, 0xa5, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x60, 0x15, 0x02 + }; + + memcpy(s->regs, regs_reset_state, sizeof(s->regs)); + s->pointer = 0; + + /* TODO: assert these after some timeout ? */ + s->regs[DPS310_MEAS_CFG] = DPS310_COEF_RDY | DPS310_SENSOR_RDY + | DPS310_TMP_RDY | DPS310_PRS_RDY; +} + +static uint8_t dps310_read(DPS310State *s, uint8_t reg) +{ + if (reg >= sizeof(s->regs)) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: register 0x%02x out of bounds\n", + __func__, s->pointer); + return 0xFF; + } + + switch (reg) { + case DPS310_PRS_B2: + case DPS310_PRS_B1: + case DPS310_PRS_B0: + case DPS310_TMP_B2: + case DPS310_TMP_B1: + case DPS310_TMP_B0: + case DPS310_PRS_CFG: + case DPS310_TMP_CFG: + case DPS310_MEAS_CFG: + case DPS310_CFG_REG: + case DPS310_COEF_BASE...DPS310_COEF_LAST: + case DPS310_COEF_SRC: + case 0x32: /* Undocumented register to indicate workaround not required */ + return s->regs[reg]; + default: + qemu_log_mask(LOG_UNIMP, "%s: register 0x%02x unimplemented\n", + __func__, reg); + return 0xFF; + } +} + +static void dps310_write(DPS310State *s, uint8_t reg, uint8_t data) +{ + if (reg >= sizeof(s->regs)) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: register %d out of bounds\n", + __func__, s->pointer); + return; + } + + switch (reg) { + case DPS310_RESET: + if (data == DPS310_RESET_MAGIC) { + device_cold_reset(DEVICE(s)); + } + break; + case DPS310_PRS_CFG: + case DPS310_TMP_CFG: + case DPS310_MEAS_CFG: + case DPS310_CFG_REG: + s->regs[reg] = data; + break; + default: + qemu_log_mask(LOG_UNIMP, "%s: register 0x%02x unimplemented\n", + __func__, reg); + return; + } +} + +static uint8_t dps310_rx(I2CSlave *i2c) +{ + DPS310State *s = DPS310(i2c); + + if (s->len == 1) { + return dps310_read(s, s->pointer++); + } else { + return 0xFF; + } +} + +static int dps310_tx(I2CSlave *i2c, uint8_t data) +{ + DPS310State *s = DPS310(i2c); + + if (s->len == 0) { + /* + * first byte is the register pointer for a read or write + * operation + */ + s->pointer = data; + s->len++; + } else if (s->len == 1) { + dps310_write(s, s->pointer++, data); + } + + return 0; +} + +static int dps310_event(I2CSlave *i2c, enum i2c_event event) +{ + DPS310State *s = DPS310(i2c); + + switch (event) { + case I2C_START_SEND: + s->pointer = 0xFF; + s->len = 0; + break; + case I2C_START_RECV: + if (s->len != 1) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid recv sequence\n", + __func__); + } + break; + default: + break; + } + + return 0; +} + +static const VMStateDescription vmstate_dps310 = { + .name = "DPS310", + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT8(len, DPS310State), + VMSTATE_UINT8_ARRAY(regs, DPS310State, NUM_REGISTERS), + VMSTATE_UINT8(pointer, DPS310State), + VMSTATE_I2C_SLAVE(i2c, DPS310State), + VMSTATE_END_OF_LIST() + } +}; + +static void dps310_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); + + k->event = dps310_event; + k->recv = dps310_rx; + k->send = dps310_tx; + dc->reset = dps310_reset; + dc->vmsd = &vmstate_dps310; +} + +static const TypeInfo dps310_info = { + .name = TYPE_DPS310, + .parent = TYPE_I2C_SLAVE, + .instance_size = sizeof(DPS310State), + .class_init = dps310_class_init, +}; + +static void dps310_register_types(void) +{ + type_register_static(&dps310_info); +} + +type_init(dps310_register_types) diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -XXX,XX +XXX,XX @@ config ASPEED_SOC select DS1338 select FTGMAC100 select I2C + select DPS310 select PCA9552 select SERIAL select SMBUS_EEPROM diff --git a/hw/sensor/Kconfig b/hw/sensor/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/hw/sensor/Kconfig +++ b/hw/sensor/Kconfig @@ -XXX,XX +XXX,XX @@ config TMP421 bool depends on I2C +config DPS310 + bool + depends on I2C + config EMC141X bool depends on I2C diff --git a/hw/sensor/meson.build b/hw/sensor/meson.build index XXXXXXX..XXXXXXX 100644 --- a/hw/sensor/meson.build +++ b/hw/sensor/meson.build @@ -XXX,XX +XXX,XX @@ softmmu_ss.add(when: 'CONFIG_TMP105', if_true: files('tmp105.c')) softmmu_ss.add(when: 'CONFIG_TMP421', if_true: files('tmp421.c')) +softmmu_ss.add(when: 'CONFIG_DPS310', if_true: files('dps310.c')) softmmu_ss.add(when: 'CONFIG_EMC141X', if_true: files('emc141x.c')) softmmu_ss.add(when: 'CONFIG_ADM1272', if_true: files('adm1272.c')) softmmu_ss.add(when: 'CONFIG_MAX34451', if_true: files('max34451.c')) -- 2.31.1
From: Joel Stanley <joel@jms.id.au> Witherspoon uses the DPS310 as a temperature sensor. Rainier uses it as a temperature and humidity sensor. Signed-off-by: Joel Stanley <joel@jms.id.au> Reviewed-by: Cédric Le Goater <clg@kaod.org> Message-Id: <20210629142336.750058-5-clg@kaod.org> Signed-off-by: Cédric Le Goater <clg@kaod.org> --- hw/arm/aspeed.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -XXX,XX +XXX,XX @@ static void witherspoon_bmc_i2c_init(AspeedMachineState *bmc) /* Bus 3: TODO bmp280@77 */ /* Bus 3: TODO max31785@52 */ - /* Bus 3: TODO dps310@76 */ dev = DEVICE(i2c_slave_new(TYPE_PCA9552, 0x60)); qdev_prop_set_string(dev, "description", "pca1"); i2c_slave_realize_and_unref(I2C_SLAVE(dev), @@ -XXX,XX +XXX,XX @@ static void witherspoon_bmc_i2c_init(AspeedMachineState *bmc) qdev_connect_gpio_out(dev, pca1_leds[i].gpio_id, 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, 4), "tmp423", 0x4c); i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 5), "tmp423", 0x4c); @@ -XXX,XX +XXX,XX @@ static void rainier_bmc_i2c_init(AspeedMachineState *bmc) aspeed_eeprom_init(pca954x_i2c_get_bus(i2c_mux, 2), 0x50, 64 * KiB); aspeed_eeprom_init(pca954x_i2c_get_bus(i2c_mux, 3), 0x51, 64 * KiB); - /* Bus 7: TODO dps310@76 */ /* Bus 7: TODO max31785@52 */ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 7), "pca9552", 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); -- 2.31.1
From: Peter Delevoryas <pdel@fb.com> UART5 is typically used as the default debug UART on the AST2600, but UART1 is also designed to be a debug UART. All the AST2600 UART's have semi-configurable clock rates through registers in the System Control Unit (SCU), but only UART5 works out of the box with zero-initialized values. The rest of the UART's expect a few of the registers to be initialized to non-zero values, or else the clock rate calculation will yield zero or undefined (due to a divide-by-zero). For reference, the U-Boot clock rate driver here shows the calculation: https://github.com/facebook/openbmc-uboot/blob/15f7e0dc01d8/drivers/clk/aspeed/clk_ast2600.c#L357 To summarize, UART5 allows selection from 4 rates: 24 MHz, 192 MHz, 24 / 13 MHz, and 192 / 13 MHz. The other UART's allow selecting either the "low" rate (UARTCLK) or the "high" rate (HUARTCLK). UARTCLK and HUARTCLK are configurable themselves: UARTCLK = UXCLK * R / (N * 2) HUARTCLK = HUXCLK * HR / (HN * 2) UXCLK and HUXCLK are also configurable, and depend on the APLL and/or HPLL clock rates, which also derive from complicated calculations. Long story short, there's lots of multiplication and division from configurable registers, and most of these registers are zero-initialized in QEMU, which at best is unexpected and at worst causes this clock rate driver to hang from divide-by-zero's. This can also be difficult to diagnose, because it may cause U-Boot to hang before serial console initialization completes, requiring intervention from gdb. This change just initializes all of these registers with default values from the datasheet. To test this, I used Facebook's AST2600 OpenBMC image for "fuji", with the following diff applied (because fuji uses UART1 for console output, not UART5). @@ -323,8 +323,8 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) } /* UART - attach an 8250 to the IO space as our UART5 */ - serial_mm_init(get_system_memory(), sc->memmap[ASPEED_DEV_UART5], 2, - aspeed_soc_get_irq(s, ASPEED_DEV_UART5), + serial_mm_init(get_system_memory(), sc->memmap[ASPEED_DEV_UART1], 2, + aspeed_soc_get_irq(s, ASPEED_DEV_UART1), 38400, serial_hd(0), DEVICE_LITTLE_ENDIAN); /* I2C */ Without these clock rate registers being initialized, U-Boot hangs in the clock rate driver from a divide-by-zero, because the UART1 clock rate register reads return zero, and there's no console output. After initializing them with default values, fuji boots successfully. Signed-off-by: Peter Delevoryas <pdel@fb.com> Reviewed-by: Joel Stanley <joel@jms.id.au> [ clg: Removed _PARAM suffix ] Message-Id: <20210906134023.3711031-2-pdel@fb.com> Signed-off-by: Cédric Le Goater <clg@kaod.org> --- hw/misc/aspeed_scu.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hw/misc/aspeed_scu.c b/hw/misc/aspeed_scu.c index XXXXXXX..XXXXXXX 100644 --- a/hw/misc/aspeed_scu.c +++ b/hw/misc/aspeed_scu.c @@ -XXX,XX +XXX,XX @@ #define AST2600_CLK_SEL3 TO_REG(0x308) #define AST2600_CLK_SEL4 TO_REG(0x310) #define AST2600_CLK_SEL5 TO_REG(0x314) +#define AST2600_UARTCLK TO_REG(0x338) +#define AST2600_HUARTCLK TO_REG(0x33C) #define AST2600_HW_STRAP1 TO_REG(0x500) #define AST2600_HW_STRAP1_CLR TO_REG(0x504) #define AST2600_HW_STRAP1_PROT TO_REG(0x508) @@ -XXX,XX +XXX,XX @@ static const uint32_t ast2600_a3_resets[ASPEED_AST2600_SCU_NR_REGS] = { [AST2600_CLK_SEL3] = 0x00000000, [AST2600_CLK_SEL4] = 0xF3F40000, [AST2600_CLK_SEL5] = 0x30000000, + [AST2600_UARTCLK] = 0x00014506, + [AST2600_HUARTCLK] = 0x000145C0, [AST2600_CHIP_ID0] = 0x1234ABCD, [AST2600_CHIP_ID1] = 0x88884444, }; -- 2.31.1
From: Peter Delevoryas <pdel@fb.com> When you run QEMU with an Aspeed machine and a single serial device using stdio like this: qemu -machine ast2600-evb -drive ... -serial stdio The guest OS can read and write to the UART5 registers at 0x1E784000 and it will receive from stdin and write to stdout. The Aspeed SoC's have a lot more UART's though (AST2500 has 5, AST2600 has 13) and depending on the board design, may be using any of them as the serial console. (See "stdout-path" in a DTS to check which one is chosen). Most boards, including all of those currently defined in hw/arm/aspeed.c, just use UART5, but some use UART1. This change adds some flexibility for different boards without requiring users to change their command-line invocation of QEMU. I tested this doesn't break existing code by booting an AST2500 OpenBMC image and an AST2600 OpenBMC image, each using UART5 as the console. Then I tested switching the default to UART1 and booting an AST2600 OpenBMC image that uses UART1, and that worked too. Signed-off-by: Peter Delevoryas <pdel@fb.com> Reviewed-by: Cédric Le Goater <clg@kaod.org> Message-Id: <20210901153615.2746885-2-pdel@fb.com> Signed-off-by: Cédric Le Goater <clg@kaod.org> --- include/hw/arm/aspeed.h | 1 + include/hw/arm/aspeed_soc.h | 1 + hw/arm/aspeed.c | 3 +++ hw/arm/aspeed_ast2600.c | 8 ++++---- hw/arm/aspeed_soc.c | 8 +++++--- 5 files changed, 14 insertions(+), 7 deletions(-) diff --git a/include/hw/arm/aspeed.h b/include/hw/arm/aspeed.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/arm/aspeed.h +++ b/include/hw/arm/aspeed.h @@ -XXX,XX +XXX,XX @@ struct AspeedMachineClass { uint32_t num_cs; uint32_t macs_mask; void (*i2c_init)(AspeedMachineState *bmc); + uint32_t uart_default; }; diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/arm/aspeed_soc.h +++ b/include/hw/arm/aspeed_soc.h @@ -XXX,XX +XXX,XX @@ struct AspeedSoCState { AspeedSDHCIState sdhci; AspeedSDHCIState emmc; AspeedLPCState lpc; + uint32_t uart_default; }; #define TYPE_ASPEED_SOC "aspeed-soc" diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -XXX,XX +XXX,XX @@ static void aspeed_machine_init(MachineState *machine) object_property_set_int(OBJECT(&bmc->soc), "hw-prot-key", ASPEED_SCU_PROT_KEY, &error_abort); } + qdev_prop_set_uint32(DEVICE(&bmc->soc), "uart-default", + amc->uart_default); qdev_realize(DEVICE(&bmc->soc), NULL, &error_abort); memory_region_add_subregion(get_system_memory(), @@ -XXX,XX +XXX,XX @@ static void aspeed_machine_class_init(ObjectClass *oc, void *data) mc->no_parallel = 1; mc->default_ram_id = "ram"; amc->macs_mask = ASPEED_MAC0_ON; + amc->uart_default = ASPEED_DEV_UART5; aspeed_machine_class_props_init(oc); } diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/aspeed_ast2600.c +++ b/hw/arm/aspeed_ast2600.c @@ -XXX,XX +XXX,XX @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) sysbus_connect_irq(SYS_BUS_DEVICE(&s->timerctrl), i, irq); } - /* UART - attach an 8250 to the IO space as our UART5 */ - serial_mm_init(get_system_memory(), sc->memmap[ASPEED_DEV_UART5], 2, - aspeed_soc_get_irq(s, ASPEED_DEV_UART5), - 38400, serial_hd(0), DEVICE_LITTLE_ENDIAN); + /* UART - attach an 8250 to the IO space as our UART */ + serial_mm_init(get_system_memory(), sc->memmap[s->uart_default], 2, + aspeed_soc_get_irq(s, s->uart_default), 38400, + serial_hd(0), DEVICE_LITTLE_ENDIAN); /* I2C */ object_property_set_link(OBJECT(&s->i2c), "dram", OBJECT(s->dram_mr), diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/aspeed_soc.c +++ b/hw/arm/aspeed_soc.c @@ -XXX,XX +XXX,XX @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) sysbus_connect_irq(SYS_BUS_DEVICE(&s->timerctrl), i, irq); } - /* UART - attach an 8250 to the IO space as our UART5 */ - serial_mm_init(get_system_memory(), sc->memmap[ASPEED_DEV_UART5], 2, - aspeed_soc_get_irq(s, ASPEED_DEV_UART5), 38400, + /* UART - attach an 8250 to the IO space as our UART */ + serial_mm_init(get_system_memory(), sc->memmap[s->uart_default], 2, + aspeed_soc_get_irq(s, s->uart_default), 38400, serial_hd(0), DEVICE_LITTLE_ENDIAN); /* I2C */ @@ -XXX,XX +XXX,XX @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) static Property aspeed_soc_properties[] = { DEFINE_PROP_LINK("dram", AspeedSoCState, dram_mr, TYPE_MEMORY_REGION, MemoryRegion *), + DEFINE_PROP_UINT32("uart-default", AspeedSoCState, uart_default, + ASPEED_DEV_UART5), DEFINE_PROP_END_OF_LIST(), }; -- 2.31.1
From: Peter Delevoryas <pdel@fb.com> This adds a new machine type "fuji-bmc" based on the following device tree: https://github.com/torvalds/linux/blob/40cb6373b46/arch/arm/boot/dts/aspeed-bmc-facebook-fuji.dts Most of the i2c devices are not there, they're added here: https://github.com/facebook/openbmc/blob/fb2ed12002fb/meta-facebook/meta-fuji/recipes-utils/openbmc-utils/files/setup_i2c.sh I tested this by building a Fuji image from Facebook's OpenBMC repo, booting, and ssh'ing from host-to-guest. Signed-off-by: Peter Delevoryas <pdel@fb.com> Reviewed-by: Joel Stanley <joel@jms.id.au> [ clg: On 32-bit hosts, lower RAM to 1G because of 2047 MB limit ] Message-Id: <20210906133124.3674661-1-pdel@fb.com> Signed-off-by: Cédric Le Goater <clg@kaod.org> --- hw/arm/aspeed.c | 120 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -XXX,XX +XXX,XX @@ struct AspeedMachineState { #define RAINIER_BMC_HW_STRAP1 0x00000000 #define RAINIER_BMC_HW_STRAP2 0x00000000 +/* Fuji hardware value */ +#define FUJI_BMC_HW_STRAP1 0x00000000 +#define FUJI_BMC_HW_STRAP2 0x00000000 + /* * The max ram region is for firmwares that scan the address space * with load/store to guess how much RAM the SoC has. @@ -XXX,XX +XXX,XX @@ static void rainier_bmc_i2c_init(AspeedMachineState *bmc) aspeed_eeprom_init(aspeed_i2c_get_bus(&soc->i2c, 15), 0x50, 64 * KiB); } +static void get_pca9548_channels(I2CBus *bus, uint8_t mux_addr, + I2CBus **channels) +{ + I2CSlave *mux = i2c_slave_create_simple(bus, "pca9548", mux_addr); + for (int i = 0; i < 8; i++) { + channels[i] = pca954x_i2c_get_bus(mux, i); + } +} + +#define TYPE_LM75 TYPE_TMP105 +#define TYPE_TMP75 TYPE_TMP105 +#define TYPE_TMP422 "tmp422" + +static void fuji_bmc_i2c_init(AspeedMachineState *bmc) +{ + AspeedSoCState *soc = &bmc->soc; + I2CBus *i2c[144] = {}; + + for (int i = 0; i < 16; i++) { + i2c[i] = aspeed_i2c_get_bus(&soc->i2c, i); + } + I2CBus *i2c180 = i2c[2]; + I2CBus *i2c480 = i2c[8]; + I2CBus *i2c600 = i2c[11]; + + get_pca9548_channels(i2c180, 0x70, &i2c[16]); + get_pca9548_channels(i2c480, 0x70, &i2c[24]); + /* NOTE: The device tree skips [32, 40) in the alias numbering */ + get_pca9548_channels(i2c600, 0x77, &i2c[40]); + get_pca9548_channels(i2c[24], 0x71, &i2c[48]); + get_pca9548_channels(i2c[25], 0x72, &i2c[56]); + get_pca9548_channels(i2c[26], 0x76, &i2c[64]); + get_pca9548_channels(i2c[27], 0x76, &i2c[72]); + for (int i = 0; i < 8; i++) { + get_pca9548_channels(i2c[40 + i], 0x76, &i2c[80 + i * 8]); + } + + i2c_slave_create_simple(i2c[17], TYPE_LM75, 0x4c); + i2c_slave_create_simple(i2c[17], TYPE_LM75, 0x4d); + + aspeed_eeprom_init(i2c[19], 0x52, 64 * KiB); + aspeed_eeprom_init(i2c[20], 0x50, 2 * KiB); + aspeed_eeprom_init(i2c[22], 0x52, 2 * KiB); + + i2c_slave_create_simple(i2c[3], TYPE_LM75, 0x48); + i2c_slave_create_simple(i2c[3], TYPE_LM75, 0x49); + i2c_slave_create_simple(i2c[3], TYPE_LM75, 0x4a); + i2c_slave_create_simple(i2c[3], TYPE_TMP422, 0x4c); + + aspeed_eeprom_init(i2c[8], 0x51, 64 * KiB); + i2c_slave_create_simple(i2c[8], TYPE_LM75, 0x4a); + + i2c_slave_create_simple(i2c[50], TYPE_LM75, 0x4c); + aspeed_eeprom_init(i2c[50], 0x52, 64 * KiB); + i2c_slave_create_simple(i2c[51], TYPE_TMP75, 0x48); + i2c_slave_create_simple(i2c[52], TYPE_TMP75, 0x49); + + i2c_slave_create_simple(i2c[59], TYPE_TMP75, 0x48); + i2c_slave_create_simple(i2c[60], TYPE_TMP75, 0x49); + + aspeed_eeprom_init(i2c[65], 0x53, 64 * KiB); + i2c_slave_create_simple(i2c[66], TYPE_TMP75, 0x49); + i2c_slave_create_simple(i2c[66], TYPE_TMP75, 0x48); + aspeed_eeprom_init(i2c[68], 0x52, 64 * KiB); + aspeed_eeprom_init(i2c[69], 0x52, 64 * KiB); + aspeed_eeprom_init(i2c[70], 0x52, 64 * KiB); + aspeed_eeprom_init(i2c[71], 0x52, 64 * KiB); + + aspeed_eeprom_init(i2c[73], 0x53, 64 * KiB); + i2c_slave_create_simple(i2c[74], TYPE_TMP75, 0x49); + i2c_slave_create_simple(i2c[74], TYPE_TMP75, 0x48); + aspeed_eeprom_init(i2c[76], 0x52, 64 * KiB); + aspeed_eeprom_init(i2c[77], 0x52, 64 * KiB); + aspeed_eeprom_init(i2c[78], 0x52, 64 * KiB); + aspeed_eeprom_init(i2c[79], 0x52, 64 * KiB); + aspeed_eeprom_init(i2c[28], 0x50, 2 * KiB); + + for (int i = 0; i < 8; i++) { + aspeed_eeprom_init(i2c[81 + i * 8], 0x56, 64 * KiB); + i2c_slave_create_simple(i2c[82 + i * 8], TYPE_TMP75, 0x48); + i2c_slave_create_simple(i2c[83 + i * 8], TYPE_TMP75, 0x4b); + i2c_slave_create_simple(i2c[84 + i * 8], TYPE_TMP75, 0x4a); + } +} + static bool aspeed_get_mmio_exec(Object *obj, Error **errp) { return ASPEED_MACHINE(obj)->mmio_exec; @@ -XXX,XX +XXX,XX @@ static void aspeed_machine_rainier_class_init(ObjectClass *oc, void *data) aspeed_soc_num_cpus(amc->soc_name); }; +/* On 32-bit hosts, lower RAM to 1G because of the 2047 MB limit */ +#if HOST_LONG_BITS == 32 +#define FUJI_BMC_RAM_SIZE (1 * GiB) +#else +#define FUJI_BMC_RAM_SIZE (2 * GiB) +#endif + +static void aspeed_machine_fuji_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc); + + mc->desc = "Facebook Fuji BMC (Cortex-A7)"; + amc->soc_name = "ast2600-a3"; + amc->hw_strap1 = FUJI_BMC_HW_STRAP1; + amc->hw_strap2 = FUJI_BMC_HW_STRAP2; + amc->fmc_model = "mx66l1g45g"; + amc->spi_model = "mx66l1g45g"; + amc->num_cs = 2; + amc->macs_mask = ASPEED_MAC3_ON; + amc->i2c_init = fuji_bmc_i2c_init; + amc->uart_default = ASPEED_DEV_UART1; + mc->default_ram_size = FUJI_BMC_RAM_SIZE; + 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"), @@ -XXX,XX +XXX,XX @@ static const TypeInfo aspeed_machine_types[] = { .name = MACHINE_TYPE_NAME("rainier-bmc"), .parent = TYPE_ASPEED_MACHINE, .class_init = aspeed_machine_rainier_class_init, + }, { + .name = MACHINE_TYPE_NAME("fuji-bmc"), + .parent = TYPE_ASPEED_MACHINE, + .class_init = aspeed_machine_fuji_class_init, }, { .name = TYPE_ASPEED_MACHINE, .parent = TYPE_MACHINE, -- 2.31.1
The following changes since commit c77283dd5d79149f4e7e9edd00f65416c648ee59: Merge tag 'pull-request-2025-07-02' of https://gitlab.com/thuth/qemu into staging (2025-07-03 06:01:41 -0400) are available in the Git repository at: https://github.com/legoater/qemu/ tags/pull-aspeed-20250704 for you to fetch changes up to 3a34dad2c0d25cebafed40696bbbdeb7ff4b9c7d: tests/functional: Add gb200 tests (2025-07-03 17:36:45 +0200) ---------------------------------------------------------------- aspeed queue: * Improved AST2700 SoC modeling (SDMC, SCU) * Fixed hardware strapping of 'bletchley-bmc' machine * Added new Meta 'catalina-bmc' machine and functional test using OpenBMC * Improved AST2600 SCU protection key modeling * Introduced AST2600 SCU unit tests * Deprecated 'ast2700a0-evb' machine * Added new NVIDIA 'gb200-bmc' machine and functional test using OpenBMC ---------------------------------------------------------------- Ed Tanous (4): hw/arm/aspeed: Add second SPI chip to Aspeed model docs: add support for gb200-bmc hw/arm/aspeed: Add GB200 BMC target tests/functional: Add gb200 tests Jamin Lin (3): hw/misc/aspeed_sdmc: Skipping dram_init in u-boot for AST2700 hw/misc/aspeed_scu: Support the Frequency Counter Control register for AST2700 aspeed: Deprecate the ast2700a0-evb machine Patrick Williams (2): hw/arm/aspeed: bletchley: update hw strap values hw/arm/aspeed: add Catalina machine type Tan Siewert (2): hw/misc/aspeed_scu: Handle AST2600 protection key registers correctly tests/qtest: Add test for ASPEED SCU docs/about/deprecated.rst | 8 + docs/system/arm/aspeed.rst | 4 +- hw/arm/aspeed_eeprom.h | 3 + include/hw/arm/aspeed.h | 2 + hw/arm/aspeed.c | 285 ++++++++++++++++++++++- hw/arm/aspeed_eeprom.c | 21 ++ hw/misc/aspeed_scu.c | 22 +- hw/misc/aspeed_sdmc.c | 3 + tests/qtest/aspeed_scu-test.c | 231 ++++++++++++++++++ hw/arm/Kconfig | 1 + tests/functional/aspeed.py | 9 +- tests/functional/meson.build | 4 + tests/functional/test_arm_aspeed_catalina.py | 25 ++ tests/functional/test_arm_aspeed_gb200nvl_bmc.py | 26 +++ tests/qtest/meson.build | 1 + 15 files changed, 636 insertions(+), 9 deletions(-) create mode 100644 tests/qtest/aspeed_scu-test.c create mode 100755 tests/functional/test_arm_aspeed_catalina.py create mode 100644 tests/functional/test_arm_aspeed_gb200nvl_bmc.py
From: Jamin Lin <jamin_lin@aspeedtech.com> On AST2700 SoC, QEMU now sets BIT6 in VGA0 SCRATCH register to indicate that DDR training has completed, thus skipping the dram_init(). To align with the recent U-Boot changes, where the Main Control Register's BIT16 is checked to skip the dram_init() process, this patch sets BIT16 in the SDMC Main Control Register at reset time. This allows both the main U-Boot stage to correctly detect and bypass DRAM initialization when running under QEMU. Reference: - QEMU: https://github.com/qemu/qemu/commit/2d082fea485ee455a70ed3e963cdf9a70f34858a - U-Boot: https://github.com/AspeedTech-BMC/u-boot/commit/94e5435504fb0d8888f5c1bfd3fa284cdd6aaf9b Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com> Reviewed-by: Cédric Le Goater <clg@redhat.com> Link: https://lore.kernel.org/qemu-devel/20250618080006.846355-2-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater <clg@redhat.com> --- hw/misc/aspeed_sdmc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/misc/aspeed_sdmc.c b/hw/misc/aspeed_sdmc.c index XXXXXXX..XXXXXXX 100644 --- a/hw/misc/aspeed_sdmc.c +++ b/hw/misc/aspeed_sdmc.c @@ -XXX,XX +XXX,XX @@ static void aspeed_2700_sdmc_reset(DeviceState *dev) /* Set ram size bit and defaults values */ s->regs[R_MAIN_CONF] = asc->compute_conf(s, 0); + /* Skipping dram init */ + s->regs[R_MAIN_CONTROL] = BIT(16); + if (s->unlocked) { s->regs[R_2700_PROT] = PROT_UNLOCKED; } -- 2.50.0
From: Jamin Lin <jamin_lin@aspeedtech.com> According to the datasheet: BIT[1] (SCU_FREQ_OSC_EN) enables the oscillator frequency measurement counter. BIT[6] (SCU_FREQ_DONE) indicates the measurement is finished. Firmware polls BIT[6] to determine when measurement is complete. The flag can be cleared by writing BIT[1] to 0. To simulate this hardware behavior in QEMU: If BIT[1] is set to 1, BIT[6] is immediately set to 1 to avoid firmware hanging during polling. If BIT[1] is cleared to 0, BIT[6] is also cleared to 0 to match hardware semantics. The initial value of this register is initialized to 0x80, reflecting the default value confirmed from an EVB register dump. Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com> Reviewed-by: Cédric Le Goater <clg@redhat.com> Link: https://lore.kernel.org/qemu-devel/20250618080006.846355-3-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater <clg@redhat.com> --- hw/misc/aspeed_scu.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hw/misc/aspeed_scu.c b/hw/misc/aspeed_scu.c index XXXXXXX..XXXXXXX 100644 --- a/hw/misc/aspeed_scu.c +++ b/hw/misc/aspeed_scu.c @@ -XXX,XX +XXX,XX @@ #define AST2700_SCUIO_UARTCLK_GEN TO_REG(0x330) #define AST2700_SCUIO_HUARTCLK_GEN TO_REG(0x334) #define AST2700_SCUIO_CLK_DUTY_MEAS_RST TO_REG(0x388) +#define AST2700_SCUIO_FREQ_CNT_CTL TO_REG(0x3A0) #define SCU_IO_REGION_SIZE 0x1000 @@ -XXX,XX +XXX,XX @@ static void aspeed_ast2700_scuio_write(void *opaque, hwaddr offset, s->regs[reg - 1] ^= data; updated = true; break; + case AST2700_SCUIO_FREQ_CNT_CTL: + s->regs[reg] = deposit32(s->regs[reg], 6, 1, !!(data & BIT(1))); + updated = true; + break; default: qemu_log_mask(LOG_GUEST_ERROR, "%s: Unhandled write at offset 0x%" HWADDR_PRIx "\n", @@ -XXX,XX +XXX,XX @@ static const uint32_t ast2700_a0_resets_io[ASPEED_AST2700_SCU_NR_REGS] = { [AST2700_SCUIO_UARTCLK_GEN] = 0x00014506, [AST2700_SCUIO_HUARTCLK_GEN] = 0x000145c0, [AST2700_SCUIO_CLK_DUTY_MEAS_RST] = 0x0c9100d2, + [AST2700_SCUIO_FREQ_CNT_CTL] = 0x00000080, }; static void aspeed_2700_scuio_class_init(ObjectClass *klass, const void *data) -- 2.50.0
From: Patrick Williams <patrick@stwcx.xyz> Update the Bletchley hardware strap register values per actual hardware: ``` root@bmc:~# devmem 0x1e6e2500 0x00002000 root@bmc:~# devmem 0x1e6e2510 0x00000801 ``` Signed-off-by: Patrick Williams <patrick@stwcx.xyz> Reviewed-by: Cédric Le Goater <clg@redhat.com> Link: https://lore.kernel.org/qemu-devel/20250619035850.2682690-1-patrick@stwcx.xyz Signed-off-by: Cédric Le Goater <clg@redhat.com> --- hw/arm/aspeed.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -XXX,XX +XXX,XX @@ struct AspeedMachineState { #define FUJI_BMC_HW_STRAP2 0x00000000 /* Bletchley hardware value */ -/* TODO: Leave same as EVB for now. */ -#define BLETCHLEY_BMC_HW_STRAP1 AST2600_EVB_HW_STRAP1 -#define BLETCHLEY_BMC_HW_STRAP2 AST2600_EVB_HW_STRAP2 +#define BLETCHLEY_BMC_HW_STRAP1 0x00002000 +#define BLETCHLEY_BMC_HW_STRAP2 0x00000801 /* Qualcomm DC-SCM hardware value */ #define QCOM_DC_SCM_V1_BMC_HW_STRAP1 0x00000000 -- 2.50.0
From: Patrick Williams <patrick@stwcx.xyz> Add the 'catalina-bmc' machine type based on the kernel DTS[1] as of 6.16-rc2. The i2c model is as complete as the current QEMU models support, but in some cases I substituted devices that are close enough for present functionality. Strap registers are were verified with hardware. This has been tested with an openbmc image built from [2]. Add a functional test in line with Bletchley, pointing at an image obtained from the OpenBMC Jenkins server. [1]: https://github.com/torvalds/linux/blob/v6.16-rc2/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-catalina.dts [2]: https://github.com/openbmc/openbmc/commit/5bc73ec261f981d5e586bda5ac78eb0cbd5f92b0 Signed-off-by: Patrick Williams <patrick@stwcx.xyz> Reviewed-by: Cédric Le Goater <clg@redhat.com> Link: https://lore.kernel.org/qemu-devel/20250619151458.2831859-1-patrick@stwcx.xyz Signed-off-by: Cédric Le Goater <clg@redhat.com> --- hw/arm/aspeed.c | 200 +++++++++++++++++++ hw/arm/Kconfig | 1 + tests/functional/meson.build | 2 + tests/functional/test_arm_aspeed_catalina.py | 25 +++ 4 files changed, 228 insertions(+) create mode 100755 tests/functional/test_arm_aspeed_catalina.py diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -XXX,XX +XXX,XX @@ #include "hw/i2c/i2c_mux_pca954x.h" #include "hw/i2c/smbus_eeprom.h" #include "hw/gpio/pca9552.h" +#include "hw/gpio/pca9554.h" #include "hw/nvram/eeprom_at24c.h" #include "hw/sensor/tmp105.h" #include "hw/misc/led.h" @@ -XXX,XX +XXX,XX @@ static void fuji_bmc_i2c_init(AspeedMachineState *bmc) } #define TYPE_TMP421 "tmp421" +#define TYPE_DS1338 "ds1338" + +/* Catalina hardware value */ +#define CATALINA_BMC_HW_STRAP1 0x00002002 +#define CATALINA_BMC_HW_STRAP2 0x00000800 + +#define CATALINA_BMC_RAM_SIZE ASPEED_RAM_SIZE(2 * GiB) + +static void catalina_bmc_i2c_init(AspeedMachineState *bmc) +{ + /* Reference from v6.16-rc2 aspeed-bmc-facebook-catalina.dts */ + + AspeedSoCState *soc = bmc->soc; + I2CBus *i2c[16] = {}; + I2CSlave *i2c_mux; + + /* busses 0-15 are all used. */ + for (int i = 0; i < ARRAY_SIZE(i2c); i++) { + i2c[i] = aspeed_i2c_get_bus(&soc->i2c, i); + } + + /* &i2c0 */ + /* i2c-mux@71 (PCA9546) on i2c0 */ + i2c_slave_create_simple(i2c[0], TYPE_PCA9546, 0x71); + + /* i2c-mux@72 (PCA9546) on i2c0 */ + i2c_mux = i2c_slave_create_simple(i2c[0], TYPE_PCA9546, 0x72); + + /* i2c0mux1ch1 */ + /* io_expander7 - pca9535@20 */ + i2c_slave_create_simple(pca954x_i2c_get_bus(i2c_mux, 1), + TYPE_PCA9552, 0x20); + /* eeprom@50 */ + at24c_eeprom_init(pca954x_i2c_get_bus(i2c_mux, 1), 0x50, 8 * KiB); + + /* i2c-mux@73 (PCA9546) on i2c0 */ + i2c_slave_create_simple(i2c[0], TYPE_PCA9546, 0x73); + + /* i2c-mux@75 (PCA9546) on i2c0 */ + i2c_slave_create_simple(i2c[0], TYPE_PCA9546, 0x75); + + /* i2c-mux@76 (PCA9546) on i2c0 */ + i2c_mux = i2c_slave_create_simple(i2c[0], TYPE_PCA9546, 0x76); + + /* i2c0mux4ch1 */ + /* io_expander8 - pca9535@21 */ + i2c_slave_create_simple(pca954x_i2c_get_bus(i2c_mux, 1), + TYPE_PCA9552, 0x21); + /* eeprom@50 */ + at24c_eeprom_init(pca954x_i2c_get_bus(i2c_mux, 1), 0x50, 8 * KiB); + + /* i2c-mux@77 (PCA9546) on i2c0 */ + i2c_slave_create_simple(i2c[0], TYPE_PCA9546, 0x77); + + + /* &i2c1 */ + /* i2c-mux@70 (PCA9548) on i2c1 */ + i2c_mux = i2c_slave_create_simple(i2c[1], TYPE_PCA9548, 0x70); + /* i2c1mux0ch0 */ + /* ina238@41 - no model */ + /* ina238@42 - no model */ + /* ina238@44 - no model */ + /* i2c1mux0ch1 */ + /* ina238@41 - no model */ + /* ina238@43 - no model */ + /* i2c1mux0ch4 */ + /* ltc4287@42 - no model */ + /* ltc4287@43 - no model */ + + /* i2c1mux0ch5 */ + /* eeprom@54 */ + at24c_eeprom_init(pca954x_i2c_get_bus(i2c_mux, 5), 0x54, 8 * KiB); + /* tpm75@4f */ + i2c_slave_create_simple(pca954x_i2c_get_bus(i2c_mux, 5), TYPE_TMP75, 0x4f); + + /* i2c1mux0ch6 */ + /* io_expander5 - pca9554@27 */ + i2c_slave_create_simple(pca954x_i2c_get_bus(i2c_mux, 6), + TYPE_PCA9554, 0x27); + /* io_expander6 - pca9555@25 */ + i2c_slave_create_simple(pca954x_i2c_get_bus(i2c_mux, 6), + TYPE_PCA9552, 0x25); + /* eeprom@51 */ + at24c_eeprom_init(pca954x_i2c_get_bus(i2c_mux, 6), 0x51, 8 * KiB); + + /* i2c1mux0ch7 */ + /* eeprom@53 */ + at24c_eeprom_init(pca954x_i2c_get_bus(i2c_mux, 7), 0x53, 8 * KiB); + /* temperature-sensor@4b - tmp75 */ + i2c_slave_create_simple(pca954x_i2c_get_bus(i2c_mux, 7), TYPE_TMP75, 0x4b); + + /* &i2c2 */ + /* io_expander0 - pca9555@20 */ + i2c_slave_create_simple(i2c[2], TYPE_PCA9552, 0x20); + /* io_expander0 - pca9555@21 */ + i2c_slave_create_simple(i2c[2], TYPE_PCA9552, 0x21); + /* io_expander0 - pca9555@27 */ + i2c_slave_create_simple(i2c[2], TYPE_PCA9552, 0x27); + /* eeprom@50 */ + at24c_eeprom_init(i2c[2], 0x50, 8 * KiB); + /* eeprom@51 */ + at24c_eeprom_init(i2c[2], 0x51, 8 * KiB); + + /* &i2c5 */ + /* i2c-mux@70 (PCA9548) on i2c5 */ + i2c_mux = i2c_slave_create_simple(i2c[5], TYPE_PCA9548, 0x70); + /* i2c5mux0ch6 */ + /* eeprom@52 */ + at24c_eeprom_init(pca954x_i2c_get_bus(i2c_mux, 6), 0x52, 8 * KiB); + /* i2c5mux0ch7 */ + /* ina230@40 - no model */ + /* ina230@41 - no model */ + /* ina230@44 - no model */ + /* ina230@45 - no model */ + + /* &i2c6 */ + /* io_expander3 - pca9555@21 */ + i2c_slave_create_simple(i2c[6], TYPE_PCA9552, 0x21); + /* rtc@6f - nct3018y */ + i2c_slave_create_simple(i2c[6], TYPE_DS1338, 0x6f); + + /* &i2c9 */ + /* io_expander4 - pca9555@4f */ + i2c_slave_create_simple(i2c[9], TYPE_PCA9552, 0x4f); + /* temperature-sensor@4b - tpm75 */ + i2c_slave_create_simple(i2c[9], TYPE_TMP75, 0x4b); + /* eeprom@50 */ + at24c_eeprom_init(i2c[9], 0x50, 8 * KiB); + /* eeprom@56 */ + at24c_eeprom_init(i2c[9], 0x56, 8 * KiB); + + /* &i2c10 */ + /* temperature-sensor@1f - tpm421 */ + i2c_slave_create_simple(i2c[10], TYPE_TMP421, 0x1f); + /* eeprom@50 */ + at24c_eeprom_init(i2c[10], 0x50, 8 * KiB); + + /* &i2c11 */ + /* ssif-bmc@10 - no model */ + + /* &i2c12 */ + /* eeprom@50 */ + at24c_eeprom_init(i2c[12], 0x50, 8 * KiB); + + /* &i2c13 */ + /* eeprom@50 */ + at24c_eeprom_init(i2c[13], 0x50, 8 * KiB); + /* eeprom@54 */ + at24c_eeprom_init(i2c[13], 0x54, 256); + /* eeprom@55 */ + at24c_eeprom_init(i2c[13], 0x55, 256); + /* eeprom@57 */ + at24c_eeprom_init(i2c[13], 0x57, 256); + + /* &i2c14 */ + /* io_expander9 - pca9555@10 */ + i2c_slave_create_simple(i2c[14], TYPE_PCA9552, 0x10); + /* io_expander10 - pca9555@11 */ + i2c_slave_create_simple(i2c[14], TYPE_PCA9552, 0x11); + /* io_expander11 - pca9555@12 */ + i2c_slave_create_simple(i2c[14], TYPE_PCA9552, 0x12); + /* io_expander12 - pca9555@13 */ + i2c_slave_create_simple(i2c[14], TYPE_PCA9552, 0x13); + /* io_expander13 - pca9555@14 */ + i2c_slave_create_simple(i2c[14], TYPE_PCA9552, 0x14); + /* io_expander14 - pca9555@15 */ + i2c_slave_create_simple(i2c[14], TYPE_PCA9552, 0x15); + + /* &i2c15 */ + /* temperature-sensor@1f - tmp421 */ + i2c_slave_create_simple(i2c[15], TYPE_TMP421, 0x1f); + /* eeprom@52 */ + at24c_eeprom_init(i2c[15], 0x52, 8 * KiB); +} static void bletchley_bmc_i2c_init(AspeedMachineState *bmc) { @@ -XXX,XX +XXX,XX @@ static void aspeed_machine_bletchley_class_init(ObjectClass *oc, aspeed_machine_class_init_cpus_defaults(mc); } +static void aspeed_machine_catalina_class_init(ObjectClass *oc, + const void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc); + + mc->desc = "Facebook Catalina BMC (Cortex-A7)"; + amc->soc_name = "ast2600-a3"; + amc->hw_strap1 = CATALINA_BMC_HW_STRAP1; + amc->hw_strap2 = CATALINA_BMC_HW_STRAP2; + amc->fmc_model = "w25q01jvq"; + amc->spi_model = NULL; + amc->num_cs = 2; + amc->macs_mask = ASPEED_MAC2_ON; + amc->i2c_init = catalina_bmc_i2c_init; + mc->auto_create_sdcard = true; + mc->default_ram_size = CATALINA_BMC_RAM_SIZE; + aspeed_machine_class_init_cpus_defaults(mc); + aspeed_machine_ast2600_class_emmc_init(oc); +} + static void fby35_reset(MachineState *state, ResetType type) { AspeedMachineState *bmc = ASPEED_MACHINE(state); @@ -XXX,XX +XXX,XX @@ static const TypeInfo aspeed_machine_types[] = { .name = MACHINE_TYPE_NAME("bletchley-bmc"), .parent = TYPE_ASPEED_MACHINE, .class_init = aspeed_machine_bletchley_class_init, + }, { + .name = MACHINE_TYPE_NAME("catalina-bmc"), + .parent = TYPE_ASPEED_MACHINE, + .class_init = aspeed_machine_catalina_class_init, }, { .name = MACHINE_TYPE_NAME("fby35-bmc"), .parent = MACHINE_TYPE_NAME("ast2600-evb"), diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -XXX,XX +XXX,XX @@ config ASPEED_SOC select I2C select DPS310 select PCA9552 + select PCA9554 select SERIAL_MM select SMBUS_EEPROM select PCA954X diff --git a/tests/functional/meson.build b/tests/functional/meson.build index XXXXXXX..XXXXXXX 100644 --- a/tests/functional/meson.build +++ b/tests/functional/meson.build @@ -XXX,XX +XXX,XX @@ test_timeouts = { 'arm_aspeed_ast2500' : 720, 'arm_aspeed_ast2600' : 1200, 'arm_aspeed_bletchley' : 480, + 'arm_aspeed_catalina' : 480, 'arm_aspeed_rainier' : 480, 'arm_bpim2u' : 500, 'arm_collie' : 180, @@ -XXX,XX +XXX,XX @@ tests_arm_system_thorough = [ 'arm_aspeed_ast2500', 'arm_aspeed_ast2600', 'arm_aspeed_bletchley', + 'arm_aspeed_catalina', 'arm_aspeed_rainier', 'arm_bpim2u', 'arm_canona1100', diff --git a/tests/functional/test_arm_aspeed_catalina.py b/tests/functional/test_arm_aspeed_catalina.py new file mode 100755 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tests/functional/test_arm_aspeed_catalina.py @@ -XXX,XX +XXX,XX @@ +#!/usr/bin/env python3 +# +# Functional test that boots the ASPEED machines +# +# SPDX-License-Identifier: GPL-2.0-or-later + +from qemu_test import Asset +from aspeed import AspeedTest + + +class CatalinaMachine(AspeedTest): + + ASSET_CATALINA_FLASH = Asset( + 'https://github.com/legoater/qemu-aspeed-boot/raw/a866feb5ef81245b4827a214584bf6bcc72939f6/images/catalina-bmc/obmc-phosphor-image-catalina-20250619123021.static.mtd.xz', + '287402e1ba021991e06be1d098f509444a02a3d81a73a932f66528b159e864f9') + + def test_arm_ast2600_catalina_openbmc(self): + image_path = self.uncompress(self.ASSET_CATALINA_FLASH) + + self.do_test_arm_aspeed_openbmc('catalina-bmc', image=image_path, + uboot='2019.04', cpu_id='0xf00', + soc='AST2600 rev A3') + +if __name__ == '__main__': + AspeedTest.main() -- 2.50.0
From: Tan Siewert <tan@siewert.io> The AST2600 SCU has two protection key registers (0x00 and 0x10) that both need to be unlocked. (Un-)locking 0x00 modifies both protection key registers, while modifying 0x10 only modifies itself. This commit updates the SCU write logic to reject writes unless both protection key registers are unlocked, matching the behaviour of real hardware. Signed-off-by: Tan Siewert <tan@siewert.io> Reviewed-by: Jamin Lin <jamin_lin@aspeedtech.com> Link: https://lore.kernel.org/qemu-devel/20250619085329.42125-1-tan@siewert.io Signed-off-by: Cédric Le Goater <clg@redhat.com> --- hw/misc/aspeed_scu.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/hw/misc/aspeed_scu.c b/hw/misc/aspeed_scu.c index XXXXXXX..XXXXXXX 100644 --- a/hw/misc/aspeed_scu.c +++ b/hw/misc/aspeed_scu.c @@ -XXX,XX +XXX,XX @@ #define BMC_DEV_ID TO_REG(0x1A4) #define AST2600_PROT_KEY TO_REG(0x00) +#define AST2600_PROT_KEY2 TO_REG(0x10) #define AST2600_SILICON_REV TO_REG(0x04) #define AST2600_SILICON_REV2 TO_REG(0x14) #define AST2600_SYS_RST_CTRL TO_REG(0x40) @@ -XXX,XX +XXX,XX @@ static void aspeed_ast2600_scu_write(void *opaque, hwaddr offset, int reg = TO_REG(offset); /* Truncate here so bitwise operations below behave as expected */ uint32_t data = data64; + bool prot_data_state = data == ASPEED_SCU_PROT_KEY; + bool unlocked = s->regs[AST2600_PROT_KEY] && s->regs[AST2600_PROT_KEY2]; if (reg >= ASPEED_AST2600_SCU_NR_REGS) { qemu_log_mask(LOG_GUEST_ERROR, @@ -XXX,XX +XXX,XX @@ static void aspeed_ast2600_scu_write(void *opaque, hwaddr offset, return; } - if (reg > PROT_KEY && !s->regs[PROT_KEY]) { + if ((reg != AST2600_PROT_KEY && reg != AST2600_PROT_KEY2) && !unlocked) { qemu_log_mask(LOG_GUEST_ERROR, "%s: SCU is locked!\n", __func__); + return; } trace_aspeed_scu_write(offset, size, data); switch (reg) { case AST2600_PROT_KEY: - s->regs[reg] = (data == ASPEED_SCU_PROT_KEY) ? 1 : 0; + /* + * Writing a value to SCU000 will modify both protection + * registers to each protection register individually. + */ + s->regs[AST2600_PROT_KEY] = prot_data_state; + s->regs[AST2600_PROT_KEY2] = prot_data_state; + return; + case AST2600_PROT_KEY2: + s->regs[AST2600_PROT_KEY2] = prot_data_state; return; case AST2600_HW_STRAP1: case AST2600_HW_STRAP2: -- 2.50.0
From: Tan Siewert <tan@siewert.io> This adds basic tests for the ASPEED System Control Unit (SCU) and its protection mechanism on the AST2500 and AST2600 platforms. The tests verify: - That SCU protection registers can be unlocked and locked again - That modifying the primary protection register on AST2600 also affects the secondary one - That writes to protected SCU registers are blocked unless protection registers are unlocked explicitly These tests ensure proper emulation of hardware locking behaviour and help catch regressions in SCU access logic. Signed-off-by: Tan Siewert <tan@siewert.io> Reviewed-by: Cédric Le Goater <clg@redhat.com> Link: https://lore.kernel.org/qemu-devel/20250630112646.74944-1-tan@siewert.io [ clg: Reordered file list in meson.build ] Signed-off-by: Cédric Le Goater <clg@redhat.com> --- tests/qtest/aspeed_scu-test.c | 231 ++++++++++++++++++++++++++++++++++ tests/qtest/meson.build | 1 + 2 files changed, 232 insertions(+) create mode 100644 tests/qtest/aspeed_scu-test.c diff --git a/tests/qtest/aspeed_scu-test.c b/tests/qtest/aspeed_scu-test.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tests/qtest/aspeed_scu-test.c @@ -XXX,XX +XXX,XX @@ +/* + * QTest testcase for the ASPEED AST2500 and AST2600 SCU. + * + * SPDX-License-Identifier: GPL-2.0-or-later + * Copyright (C) 2025 Tan Siewert + */ + +#include "qemu/osdep.h" +#include "libqtest-single.h" + +/* + * SCU base, as well as protection key are + * the same on AST2500 and 2600. + */ +#define AST_SCU_BASE 0x1E6E2000 +#define AST_SCU_PROT_LOCK_STATE 0x0 +#define AST_SCU_PROT_LOCK_VALUE 0x2 +#define AST_SCU_PROT_UNLOCK_STATE 0x1 +#define AST_SCU_PROT_UNLOCK_VALUE 0x1688A8A8 + +#define AST2500_MACHINE "-machine ast2500-evb" +#define AST2500_SCU_PROT_REG 0x00 +#define AST2500_SCU_MISC_2_CONTROL_REG 0x4C + +#define AST2600_MACHINE "-machine ast2600-evb" +/* AST2600 has two protection registers */ +#define AST2600_SCU_PROT_REG 0x000 +#define AST2600_SCU_PROT_REG2 0x010 +#define AST2600_SCU_MISC_2_CONTROL_REG 0x0C4 + +#define TEST_LOCK_ARBITRARY_VALUE 0xABCDEFAB + +/** + * Assert that a given register matches an expected value. + * + * Reads the register and checks if its value equals the expected value. + * + * @param *s - QTest machine state + * @param reg - Address of the register to be checked + * @param expected - Expected register value + */ +static inline void assert_register_eq(QTestState *s, + uint32_t reg, + uint32_t expected) +{ + uint32_t value = qtest_readl(s, reg); + g_assert_cmphex(value, ==, expected); +} + +/** + * Assert that a given register does not match a specific value. + * + * Reads the register and checks that its value is not equal to the + * provided value. + * + * @param *s - QTest machine state + * @param reg - Address of the register to be checked + * @param not_expected - Value the register must not contain + */ +static inline void assert_register_neq(QTestState *s, + uint32_t reg, + uint32_t not_expected) +{ + uint32_t value = qtest_readl(s, reg); + g_assert_cmphex(value, !=, not_expected); +} + +/** + * Test whether the SCU can be locked and unlocked correctly. + * + * When testing multiple registers, this function assumes that writing + * to the first register also affects the others. However, writing to + * any other register only affects itself. + * + * @param *machine - input machine configuration, passed directly + * to QTest + * @param regs[] - List of registers to be checked + * @param regc - amount of arguments for registers to be checked + */ +static void test_protection_register(const char *machine, + const uint32_t regs[], + const int regc) +{ + QTestState *s = qtest_init(machine); + + for (int i = 0; i < regc; i++) { + uint32_t reg = regs[i]; + + qtest_writel(s, reg, AST_SCU_PROT_UNLOCK_VALUE); + assert_register_eq(s, reg, AST_SCU_PROT_UNLOCK_STATE); + + /** + * Check that other registers are unlocked too, if more + * than one is available. + */ + if (regc > 1 && i == 0) { + /* Initialise at 1 instead of 0 to skip first */ + for (int j = 1; j < regc; j++) { + uint32_t add_reg = regs[j]; + assert_register_eq(s, add_reg, AST_SCU_PROT_UNLOCK_STATE); + } + } + + /* Lock the register again */ + qtest_writel(s, reg, AST_SCU_PROT_LOCK_VALUE); + assert_register_eq(s, reg, AST_SCU_PROT_LOCK_STATE); + + /* And the same for locked state */ + if (regc > 1 && i == 0) { + /* Initialise at 1 instead of 0 to skip first */ + for (int j = 1; j < regc; j++) { + uint32_t add_reg = regs[j]; + assert_register_eq(s, add_reg, AST_SCU_PROT_LOCK_STATE); + } + } + } + + qtest_quit(s); +} + +static void test_2500_protection_register(void) +{ + uint32_t regs[] = { AST_SCU_BASE + AST2500_SCU_PROT_REG }; + + test_protection_register(AST2500_MACHINE, + regs, + ARRAY_SIZE(regs)); +} + +static void test_2600_protection_register(void) +{ + /** + * The AST2600 has two protection registers, both + * being required to be unlocked to do any operation. + * + * Modifying SCU000 also modifies SCU010, but modifying + * SCU010 only will keep SCU000 untouched. + */ + uint32_t regs[] = { AST_SCU_BASE + AST2600_SCU_PROT_REG, + AST_SCU_BASE + AST2600_SCU_PROT_REG2 }; + + test_protection_register(AST2600_MACHINE, + regs, + ARRAY_SIZE(regs)); +} + +/** + * Test if SCU register writes are correctly allowed or blocked + * depending on the protection register state. + * + * The test first locks the protection register and verifies that + * writes to the target SCU register are rejected. It then unlocks + * the protection register and confirms that the written value is + * retained when unlocked. + * + * @param *machine - input machine configuration, passed directly + * to QTest + * @param protection_register - first SCU protection key register + * (only one for keeping it simple) + * @param test_register - Register to be used for writing arbitrary + * values + */ +static void test_write_permission_lock_state(const char *machine, + const uint32_t protection_register, + const uint32_t test_register) +{ + QTestState *s = qtest_init(machine); + + /* Arbitrary value to lock provided SCU protection register */ + qtest_writel(s, protection_register, AST_SCU_PROT_LOCK_VALUE); + + /* Ensure that the SCU is really locked */ + assert_register_eq(s, protection_register, AST_SCU_PROT_LOCK_STATE); + + /* Write a known arbitrary value to test that the write is blocked */ + qtest_writel(s, test_register, TEST_LOCK_ARBITRARY_VALUE); + + /* We do not want to have the written value to be saved */ + assert_register_neq(s, test_register, TEST_LOCK_ARBITRARY_VALUE); + + /** + * Unlock the SCU and verify that it can be written to. + * Assumes that the first SCU protection register is sufficient to + * unlock all protection registers, if multiple are present. + */ + qtest_writel(s, protection_register, AST_SCU_PROT_UNLOCK_VALUE); + assert_register_eq(s, protection_register, AST_SCU_PROT_UNLOCK_STATE); + + /* Write a known arbitrary value to test that the write works */ + qtest_writel(s, test_register, TEST_LOCK_ARBITRARY_VALUE); + + /* Ensure that the written value is retained */ + assert_register_eq(s, test_register, TEST_LOCK_ARBITRARY_VALUE); + + qtest_quit(s); +} + +static void test_2500_write_permission_lock_state(void) +{ + test_write_permission_lock_state( + AST2500_MACHINE, + AST_SCU_BASE + AST2500_SCU_PROT_REG, + AST_SCU_BASE + AST2500_SCU_MISC_2_CONTROL_REG + ); +} + +static void test_2600_write_permission_lock_state(void) +{ + test_write_permission_lock_state( + AST2600_MACHINE, + AST_SCU_BASE + AST2600_SCU_PROT_REG, + AST_SCU_BASE + AST2600_SCU_MISC_2_CONTROL_REG + ); +} + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + + qtest_add_func("/ast2500/scu/protection_register", + test_2500_protection_register); + qtest_add_func("/ast2600/scu/protection_register", + test_2600_protection_register); + + qtest_add_func("/ast2500/scu/write_permission_lock_state", + test_2500_write_permission_lock_state); + qtest_add_func("/ast2600/scu/write_permission_lock_state", + test_2600_write_permission_lock_state); + + return g_test_run(); +} diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -XXX,XX +XXX,XX @@ qtests_npcm8xx = \ qtests_aspeed = \ ['aspeed_gpio-test', 'aspeed_hace-test', + 'aspeed_scu-test', 'aspeed_smc-test'] qtests_aspeed64 = \ ['ast2700-gpio-test', -- 2.50.0
From: Jamin Lin <jamin_lin@aspeedtech.com> The ast2700a0-evb machine represents the first revision of the AST2700 and serves as the initial engineering sample rather than a production version. A newer revision, A1, is now supported, and the ast2700a1-evb should replace the older A0 version. Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com> Reviewed-by: Cédric Le Goater <clg@redhat.com> Link: https://lore.kernel.org/qemu-devel/20250703052400.2927831-1-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater <clg@redhat.com> --- docs/about/deprecated.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index XXXXXXX..XXXXXXX 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -XXX,XX +XXX,XX @@ deprecated; use the new name ``dtb-randomness`` instead. The new name better reflects the way this property affects all random data within the device tree blob, not just the ``kaslr-seed`` node. +Arm ``ast2700a0-evb`` machine (since 10.1) +'''''''''''''''''''''''''''''''''''''''''' + +The ``ast2700a0-evb`` machine represents the first revision of the AST2700 +and serves as the initial engineering sample rather than a production version. +A newer revision, A1, is now supported, and the ``ast2700a1-evb`` should +replace the older A0 version. + Mips ``mipssim`` machine (since 10.0) ''''''''''''''''''''''''''''''''''''' -- 2.50.0
From: Ed Tanous <etanous@nvidia.com> Aspeed2600 has two spi lanes; Add a new struct that can mount the second SPI. Signed-off-by: Ed Tanous <etanous@nvidia.com> Reviewed-by: Cédric Le Goater <clg@redhat.com> Link: https://lore.kernel.org/qemu-devel/20250703144249.3348879-2-etanous@nvidia.com Signed-off-by: Cédric Le Goater <clg@redhat.com> --- include/hw/arm/aspeed.h | 2 ++ hw/arm/aspeed.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/include/hw/arm/aspeed.h b/include/hw/arm/aspeed.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/arm/aspeed.h +++ b/include/hw/arm/aspeed.h @@ -XXX,XX +XXX,XX @@ struct AspeedMachineClass { uint32_t hw_strap2; const char *fmc_model; const char *spi_model; + const char *spi2_model; uint32_t num_cs; + uint32_t num_cs2; uint32_t macs_mask; void (*i2c_init)(AspeedMachineState *bmc); uint32_t uart_default; diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -XXX,XX +XXX,XX @@ static void aspeed_machine_init(MachineState *machine) aspeed_board_init_flashes(&bmc->soc->spi[0], bmc->spi_model ? bmc->spi_model : amc->spi_model, 1, amc->num_cs); + aspeed_board_init_flashes(&bmc->soc->spi[1], + amc->spi2_model, 1, amc->num_cs2); } if (machine->kernel_filename && sc->num_cpus > 1) { -- 2.50.0
From: Ed Tanous <etanous@nvidia.com> This patch updates the docs for support of gb200-bmc. Signed-off-by: Ed Tanous <etanous@nvidia.com> Reviewed-by: Cédric Le Goater <clg@redhat.com> Link: https://lore.kernel.org/qemu-devel/20250703144249.3348879-3-etanous@nvidia.com Signed-off-by: Cédric Le Goater <clg@redhat.com> --- docs/system/arm/aspeed.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/system/arm/aspeed.rst b/docs/system/arm/aspeed.rst index XXXXXXX..XXXXXXX 100644 --- a/docs/system/arm/aspeed.rst +++ b/docs/system/arm/aspeed.rst @@ -XXX,XX +XXX,XX @@ -Aspeed family boards (``ast2500-evb``, ``ast2600-evb``, ``ast2700-evb``, ``bletchley-bmc``, ``fuji-bmc``, ``fby35-bmc``, ``fp5280g2-bmc``, ``g220a-bmc``, ``palmetto-bmc``, ``qcom-dc-scm-v1-bmc``, ``qcom-firework-bmc``, ``quanta-q71l-bmc``, ``rainier-bmc``, ``romulus-bmc``, ``sonorapass-bmc``, ``supermicrox11-bmc``, ``supermicrox11spi-bmc``, ``tiogapass-bmc``, ``witherspoon-bmc``, ``yosemitev2-bmc``) -================================================================================================================================================================================================================================================================================================================================================================================================================================= +Aspeed family boards (``ast2500-evb``, ``ast2600-evb``, ``ast2700-evb``, ``bletchley-bmc``, ``fuji-bmc``, ``gb200nvl-bmc``, ``fby35-bmc``, ``fp5280g2-bmc``, ``g220a-bmc``, ``palmetto-bmc``, ``qcom-dc-scm-v1-bmc``, ``qcom-firework-bmc``, ``quanta-q71l-bmc``, ``rainier-bmc``, ``romulus-bmc``, ``sonorapass-bmc``, ``supermicrox11-bmc``, ``supermicrox11spi-bmc``, ``tiogapass-bmc``, ``witherspoon-bmc``, ``yosemitev2-bmc``) The QEMU Aspeed machines model BMCs of various OpenPOWER systems and Aspeed evaluation boards. They are based on different releases of the @@ -XXX,XX +XXX,XX @@ AST2600 SoC based machines : - ``fuji-bmc`` Facebook Fuji BMC - ``bletchley-bmc`` Facebook Bletchley BMC - ``fby35-bmc`` Facebook fby35 BMC +- ``gb200nvl-bmc`` Nvidia GB200nvl BMC - ``qcom-dc-scm-v1-bmc`` Qualcomm DC-SCM V1 BMC - ``qcom-firework-bmc`` Qualcomm Firework BMC -- 2.50.0
From: Ed Tanous <etanous@nvidia.com> GB200nvl72 is a system for for accelerated compute. This is a model for the BMC target within the system. This is based on the device tree aspeed-bmc-nvidia-gb200nvl-bmc.dts from: [1] https://github.com/openbmc/linux/blob/dev-6.6/arch/arm/boot/dts/aspeed/aspeed-bmc-nvidia-gb200nvl-bmc.dts Signed-off-by: Ed Tanous <etanous@nvidia.com> Reviewed-by: Cédric Le Goater <clg@redhat.com> Link: https://lore.kernel.org/qemu-devel/20250703144249.3348879-4-etanous@nvidia.com Signed-off-by: Cédric Le Goater <clg@redhat.com> --- hw/arm/aspeed_eeprom.h | 3 ++ hw/arm/aspeed.c | 78 ++++++++++++++++++++++++++++++++++++++++++ hw/arm/aspeed_eeprom.c | 21 ++++++++++++ 3 files changed, 102 insertions(+) diff --git a/hw/arm/aspeed_eeprom.h b/hw/arm/aspeed_eeprom.h index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/aspeed_eeprom.h +++ b/hw/arm/aspeed_eeprom.h @@ -XXX,XX +XXX,XX @@ extern const size_t rainier_bb_fruid_len; extern const uint8_t rainier_bmc_fruid[]; extern const size_t rainier_bmc_fruid_len; +extern const uint8_t gb200nvl_bmc_fruid[]; +extern const size_t gb200nvl_bmc_fruid_len; + #endif diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -XXX,XX +XXX,XX @@ struct AspeedMachineState { #define BLETCHLEY_BMC_HW_STRAP1 0x00002000 #define BLETCHLEY_BMC_HW_STRAP2 0x00000801 +/* GB200NVL hardware value */ +#define GB200NVL_BMC_HW_STRAP1 AST2600_EVB_HW_STRAP1 +#define GB200NVL_BMC_HW_STRAP2 AST2600_EVB_HW_STRAP2 + /* Qualcomm DC-SCM hardware value */ #define QCOM_DC_SCM_V1_BMC_HW_STRAP1 0x00000000 #define QCOM_DC_SCM_V1_BMC_HW_STRAP2 0x00000041 @@ -XXX,XX +XXX,XX @@ static void create_pca9552(AspeedSoCState *soc, int bus_id, int addr) TYPE_PCA9552, addr); } +static I2CSlave *create_pca9554(AspeedSoCState *soc, int bus_id, int addr) +{ + return i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, bus_id), + TYPE_PCA9554, addr); +} + static void sonorapass_bmc_i2c_init(AspeedMachineState *bmc) { AspeedSoCState *soc = bmc->soc; @@ -XXX,XX +XXX,XX @@ static void bletchley_bmc_i2c_init(AspeedMachineState *bmc) i2c_slave_create_simple(i2c[12], TYPE_PCA9552, 0x67); } + +static void gb200nvl_bmc_i2c_init(AspeedMachineState *bmc) +{ + AspeedSoCState *soc = bmc->soc; + I2CBus *i2c[15] = {}; + DeviceState *dev; + for (int i = 0; i < sizeof(i2c) / sizeof(i2c[0]); i++) { + if ((i == 11) || (i == 12) || (i == 13)) { + continue; + } + i2c[i] = aspeed_i2c_get_bus(&soc->i2c, i); + } + + /* Bus 5 Expander */ + create_pca9554(soc, 4, 0x21); + + /* Mux I2c Expanders */ + i2c_slave_create_simple(i2c[5], "pca9546", 0x71); + i2c_slave_create_simple(i2c[5], "pca9546", 0x72); + i2c_slave_create_simple(i2c[5], "pca9546", 0x73); + i2c_slave_create_simple(i2c[5], "pca9546", 0x75); + i2c_slave_create_simple(i2c[5], "pca9546", 0x76); + i2c_slave_create_simple(i2c[5], "pca9546", 0x77); + + /* Bus 10 */ + dev = DEVICE(create_pca9554(soc, 9, 0x20)); + + /* Set FPGA_READY */ + object_property_set_str(OBJECT(dev), "pin1", "high", &error_fatal); + + create_pca9554(soc, 9, 0x21); + at24c_eeprom_init(i2c[9], 0x50, 64 * KiB); + at24c_eeprom_init(i2c[9], 0x51, 64 * KiB); + + /* Bus 11 */ + at24c_eeprom_init_rom(i2c[10], 0x50, 256, gb200nvl_bmc_fruid, + gb200nvl_bmc_fruid_len); +} + static void fby35_i2c_init(AspeedMachineState *bmc) { AspeedSoCState *soc = bmc->soc; @@ -XXX,XX +XXX,XX @@ static void aspeed_machine_catalina_class_init(ObjectClass *oc, aspeed_machine_ast2600_class_emmc_init(oc); } +#define GB200NVL_BMC_RAM_SIZE ASPEED_RAM_SIZE(1 * GiB) + +static void aspeed_machine_gb200nvl_class_init(ObjectClass *oc, + const void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc); + + mc->desc = "Nvidia GB200NVL BMC (Cortex-A7)"; + amc->soc_name = "ast2600-a3"; + amc->hw_strap1 = GB200NVL_BMC_HW_STRAP1; + amc->hw_strap2 = GB200NVL_BMC_HW_STRAP2; + amc->fmc_model = "mx66u51235f"; + amc->spi_model = "mx66u51235f"; + amc->num_cs = 2; + + amc->spi2_model = "mx66u51235f"; + amc->num_cs2 = 1; + amc->macs_mask = ASPEED_MAC0_ON | ASPEED_MAC1_ON; + amc->i2c_init = gb200nvl_bmc_i2c_init; + mc->default_ram_size = GB200NVL_BMC_RAM_SIZE; + aspeed_machine_class_init_cpus_defaults(mc); + aspeed_machine_ast2600_class_emmc_init(oc); +} + static void fby35_reset(MachineState *state, ResetType type) { AspeedMachineState *bmc = ASPEED_MACHINE(state); @@ -XXX,XX +XXX,XX @@ static const TypeInfo aspeed_machine_types[] = { .name = MACHINE_TYPE_NAME("bletchley-bmc"), .parent = TYPE_ASPEED_MACHINE, .class_init = aspeed_machine_bletchley_class_init, + }, { + .name = MACHINE_TYPE_NAME("gb200nvl-bmc"), + .parent = TYPE_ASPEED_MACHINE, + .class_init = aspeed_machine_gb200nvl_class_init, }, { .name = MACHINE_TYPE_NAME("catalina-bmc"), .parent = TYPE_ASPEED_MACHINE, diff --git a/hw/arm/aspeed_eeprom.c b/hw/arm/aspeed_eeprom.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/aspeed_eeprom.c +++ b/hw/arm/aspeed_eeprom.c @@ -XXX,XX +XXX,XX @@ const uint8_t rainier_bmc_fruid[] = { 0x31, 0x50, 0x46, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, }; +const uint8_t gb200nvl_bmc_fruid[] = { + 0x01, 0x00, 0x00, 0x01, 0x0b, 0x00, 0x00, 0xf3, 0x01, 0x0a, 0x19, 0x1f, + 0x0f, 0xe6, 0xc6, 0x4e, 0x56, 0x49, 0x44, 0x49, 0x41, 0xc5, 0x50, 0x33, + 0x38, 0x30, 0x39, 0xcd, 0x31, 0x35, 0x38, 0x33, 0x33, 0x32, 0x34, 0x38, + 0x30, 0x30, 0x31, 0x35, 0x30, 0xd2, 0x36, 0x39, 0x39, 0x2d, 0x31, 0x33, + 0x38, 0x30, 0x39, 0x2d, 0x30, 0x34, 0x30, 0x34, 0x2d, 0x36, 0x30, 0x30, + 0xc0, 0x01, 0x01, 0xd6, 0x4d, 0x41, 0x43, 0x3a, 0x20, 0x33, 0x43, 0x3a, + 0x36, 0x44, 0x3a, 0x36, 0x36, 0x3a, 0x31, 0x34, 0x3a, 0x43, 0x38, 0x3a, + 0x37, 0x41, 0xc1, 0x3b, 0x01, 0x09, 0x19, 0xc6, 0x4e, 0x56, 0x49, 0x44, + 0x49, 0x41, 0xc9, 0x50, 0x33, 0x38, 0x30, 0x39, 0x2d, 0x42, 0x4d, 0x43, + 0xd2, 0x36, 0x39, 0x39, 0x2d, 0x31, 0x33, 0x38, 0x30, 0x39, 0x2d, 0x30, + 0x34, 0x30, 0x34, 0x2d, 0x36, 0x30, 0x30, 0xc4, 0x41, 0x45, 0x2e, 0x31, + 0xcd, 0x31, 0x35, 0x38, 0x33, 0x33, 0x32, 0x34, 0x38, 0x30, 0x30, 0x31, + 0x35, 0x30, 0xc0, 0xc4, 0x76, 0x30, 0x2e, 0x31, 0xc1, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xb4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + +}; + const size_t tiogapass_bmc_fruid_len = sizeof(tiogapass_bmc_fruid); const size_t fby35_nic_fruid_len = sizeof(fby35_nic_fruid); const size_t fby35_bb_fruid_len = sizeof(fby35_bb_fruid); @@ -XXX,XX +XXX,XX @@ const size_t fby35_bmc_fruid_len = sizeof(fby35_bmc_fruid); const size_t yosemitev2_bmc_fruid_len = sizeof(yosemitev2_bmc_fruid); const size_t rainier_bb_fruid_len = sizeof(rainier_bb_fruid); const size_t rainier_bmc_fruid_len = sizeof(rainier_bmc_fruid); +const size_t gb200nvl_bmc_fruid_len = sizeof(gb200nvl_bmc_fruid); + -- 2.50.0
From: Ed Tanous <etanous@nvidia.com> To support the newly added gb200 machine, add appropriate tests and extend do_test_arm_aspeed_openbmc() to support the hostname of this new system: "gb200nvl-obmc". Signed-off-by: Ed Tanous <etanous@nvidia.com> Reviewed-by: Cédric Le Goater <clg@redhat.com> Link: https://lore.kernel.org/qemu-devel/20250703144249.3348879-5-etanous@nvidia.com [ clg: Adjust commit log to document do_test_arm_aspeed_openbmc() change ] Signed-off-by: Cédric Le Goater <clg@redhat.com> --- tests/functional/aspeed.py | 9 +++++-- tests/functional/meson.build | 2 ++ .../test_arm_aspeed_gb200nvl_bmc.py | 26 +++++++++++++++++++ 3 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 tests/functional/test_arm_aspeed_gb200nvl_bmc.py diff --git a/tests/functional/aspeed.py b/tests/functional/aspeed.py index XXXXXXX..XXXXXXX 100644 --- a/tests/functional/aspeed.py +++ b/tests/functional/aspeed.py @@ -XXX,XX +XXX,XX @@ class AspeedTest(LinuxKernelTest): def do_test_arm_aspeed_openbmc(self, machine, image, uboot='2019.04', - cpu_id='0x0', soc='AST2500 rev A1'): - hostname = machine.removesuffix('-bmc') + cpu_id='0x0', soc='AST2500 rev A1', + image_hostname=None): + # Allow for the image hostname to not end in "-bmc" + if image_hostname is not None: + hostname = image_hostname + else: + hostname = machine.removesuffix('-bmc') self.set_machine(machine) self.vm.set_console() diff --git a/tests/functional/meson.build b/tests/functional/meson.build index XXXXXXX..XXXXXXX 100644 --- a/tests/functional/meson.build +++ b/tests/functional/meson.build @@ -XXX,XX +XXX,XX @@ test_timeouts = { 'arm_aspeed_ast2600' : 1200, 'arm_aspeed_bletchley' : 480, 'arm_aspeed_catalina' : 480, + 'arm_aspeed_gb200nvl_bmc' : 480, 'arm_aspeed_rainier' : 480, 'arm_bpim2u' : 500, 'arm_collie' : 180, @@ -XXX,XX +XXX,XX @@ tests_arm_system_thorough = [ 'arm_aspeed_ast2600', 'arm_aspeed_bletchley', 'arm_aspeed_catalina', + 'arm_aspeed_gb200nvl_bmc', 'arm_aspeed_rainier', 'arm_bpim2u', 'arm_canona1100', diff --git a/tests/functional/test_arm_aspeed_gb200nvl_bmc.py b/tests/functional/test_arm_aspeed_gb200nvl_bmc.py new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tests/functional/test_arm_aspeed_gb200nvl_bmc.py @@ -XXX,XX +XXX,XX @@ +#!/usr/bin/env python3 +# +# Functional test that boots the ASPEED machines +# +# SPDX-License-Identifier: GPL-2.0-or-later + +from qemu_test import Asset +from aspeed import AspeedTest + + +class GB200Machine(AspeedTest): + + ASSET_GB200_FLASH = Asset( + 'https://github.com/legoater/qemu-aspeed-boot/raw/refs/heads/master/images/gb200nvl-obmc/obmc-phosphor-image-gb200nvl-obmc-20250702182348.static.mtd.xz', + 'b84819317cb3dc762895ad507705978ef000bfc77c50c33a63bdd37921db0dbc') + + def test_arm_aspeed_gb200_openbmc(self): + image_path = self.uncompress(self.ASSET_GB200_FLASH) + + self.do_test_arm_aspeed_openbmc('gb200nvl-bmc', image=image_path, + uboot='2019.04', cpu_id='0xf00', + soc='AST2600 rev A3', + image_hostname='gb200nvl-obmc') + +if __name__ == '__main__': + AspeedTest.main() -- 2.50.0