:p
atchew
Login
The following changes since commit e029fe22caad9b75c7ab69bd4e84853c11fb71e0: Merge tag 'pull-qapi-2024-01-26' of https://repo.or.cz/qemu/armbru into staging (2024-01-26 10:21:27 +0000) are available in the Git repository at: https://github.com/legoater/qemu/ tags/pull-aspeed-20240126 for you to fetch changes up to b40769f4b49d15485ffaaa7acade3e3593ee6daa: hw/fsi: Update MAINTAINER list (2024-01-26 14:22:08 +0100) ---------------------------------------------------------------- aspeed queue: * Update of buildroot images to 2023.11 (6.6.3 kernel) * Check of the valid CPU type supported by aspeed machines * Simplified models for the IBM's FSI bus and the Aspeed controller bridge ---------------------------------------------------------------- Cédric Le Goater (1): tests/avocado/machine_aspeed.py: Update buildroot images to 2023.11 Ninad Palsule (11): hw/fsi: Introduce IBM's Local bus hw/fsi: Introduce IBM's scratchpad device hw/fsi: Introduce IBM's FSI Bus hw/fsi: Introduce IBM's fsi-slave model hw/fsi: Introduce IBM's cfam hw/fsi: Introduce IBM's FSI master hw/fsi: Aspeed APB2OPB & On-chip peripheral bus hw/arm: Hook up FSI module in AST2600 hw/fsi: Added qtest hw/fsi: Added FSI documentation hw/fsi: Update MAINTAINER list Philippe Mathieu-Daudé (5): hw/arm/aspeed: Remove dead code hw/arm/aspeed: Set default CPU count using aspeed_soc_num_cpus() hw/arm/aspeed: Init CPU defaults in a common helper hw/arm/aspeed: Introduce aspeed_soc_cpu_type() helper hw/arm/aspeed: Check for CPU types in machine_run_board_init() MAINTAINERS | 9 ++ docs/specs/fsi.rst | 122 +++++++++++++++ docs/specs/index.rst | 1 + meson.build | 1 + hw/fsi/trace.h | 1 + include/hw/arm/aspeed_soc.h | 8 +- include/hw/fsi/aspeed_apb2opb.h | 46 ++++++ include/hw/fsi/cfam.h | 34 +++++ include/hw/fsi/fsi-master.h | 32 ++++ include/hw/fsi/fsi.h | 37 +++++ include/hw/fsi/lbus.h | 43 ++++++ hw/arm/aspeed.c | 70 ++++----- hw/arm/aspeed_ast10x0.c | 8 +- hw/arm/aspeed_ast2400.c | 15 +- hw/arm/aspeed_ast2600.c | 28 +++- hw/arm/aspeed_soc_common.c | 8 + hw/fsi/aspeed_apb2opb.c | 329 ++++++++++++++++++++++++++++++++++++++++ hw/fsi/cfam.c | 168 ++++++++++++++++++++ hw/fsi/fsi-master.c | 170 +++++++++++++++++++++ hw/fsi/fsi.c | 102 +++++++++++++ hw/fsi/lbus.c | 117 ++++++++++++++ tests/qtest/aspeed-fsi-test.c | 205 +++++++++++++++++++++++++ hw/Kconfig | 1 + hw/arm/Kconfig | 1 + hw/fsi/Kconfig | 7 + hw/fsi/meson.build | 2 + hw/fsi/trace-events | 13 ++ hw/meson.build | 1 + tests/avocado/machine_aspeed.py | 18 +-- tests/qtest/meson.build | 1 + 30 files changed, 1540 insertions(+), 58 deletions(-) create mode 100644 docs/specs/fsi.rst create mode 100644 hw/fsi/trace.h create mode 100644 include/hw/fsi/aspeed_apb2opb.h create mode 100644 include/hw/fsi/cfam.h create mode 100644 include/hw/fsi/fsi-master.h create mode 100644 include/hw/fsi/fsi.h create mode 100644 include/hw/fsi/lbus.h create mode 100644 hw/fsi/aspeed_apb2opb.c create mode 100644 hw/fsi/cfam.c create mode 100644 hw/fsi/fsi-master.c create mode 100644 hw/fsi/fsi.c create mode 100644 hw/fsi/lbus.c create mode 100644 tests/qtest/aspeed-fsi-test.c create mode 100644 hw/fsi/Kconfig create mode 100644 hw/fsi/meson.build create mode 100644 hw/fsi/trace-events
Compared to mainline buildroot, these images have some customization : - Linux version is bumped to 6.6.3 and built with a custom config - U-Boot is switched to the one provided by OpenBMC for more support - defconfigs extra tools for dev See branch [1] for more details. There are a few changes since last update, commit ed1f5ff84209. Images all have a password now and I2C devices have been updated in the Linux ast2600-evb device tree [2]. Do the necessary adjustements. [1] https://github.com/legoater/buildroot/commits/aspeed-2023.11 [2] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=9deb10cf160e Signed-off-by: Cédric Le Goater <clg@kaod.org> --- tests/avocado/machine_aspeed.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/avocado/machine_aspeed.py b/tests/avocado/machine_aspeed.py index XXXXXXX..XXXXXXX 100644 --- a/tests/avocado/machine_aspeed.py +++ b/tests/avocado/machine_aspeed.py @@ -XXX,XX +XXX,XX @@ def do_test_arm_aspeed_buildroot_start(self, image, cpu_id, pattern='Aspeed EVB' time.sleep(0.1) exec_command(self, 'root') time.sleep(0.1) + exec_command(self, "passw0rd") def do_test_arm_aspeed_buildroot_poweroff(self): exec_command_and_wait_for_pattern(self, 'poweroff', @@ -XXX,XX +XXX,XX @@ def test_arm_ast2500_evb_buildroot(self): """ image_url = ('https://github.com/legoater/qemu-aspeed-boot/raw/master/' - 'images/ast2500-evb/buildroot-2022.11-2-g15d3648df9/flash.img') - image_hash = ('f96d11db521fe7a2787745e9e391225deeeec3318ee0fc07c8b799b8833dd474') + 'images/ast2500-evb/buildroot-2023.11/flash.img') + image_hash = ('c23db6160cf77d0258397eb2051162c8473a56c441417c52a91ba217186e715f') image_path = self.fetch_asset(image_url, asset_hash=image_hash, algorithm='sha256') self.vm.add_args('-device', 'tmp105,bus=aspeed.i2c.bus.3,address=0x4d,id=tmp-test'); - self.do_test_arm_aspeed_buildroot_start(image_path, '0x0') + self.do_test_arm_aspeed_buildroot_start(image_path, '0x0', 'Aspeed AST2500 EVB') exec_command_and_wait_for_pattern(self, 'echo lm75 0x4d > /sys/class/i2c-dev/i2c-3/device/new_device', @@ -XXX,XX +XXX,XX @@ def test_arm_ast2600_evb_buildroot(self): """ image_url = ('https://github.com/legoater/qemu-aspeed-boot/raw/master/' - 'images/ast2600-evb/buildroot-2022.11-2-g15d3648df9/flash.img') - image_hash = ('e598d86e5ea79671ca8b59212a326c911bc8bea728dec1a1f5390d717a28bb8b') + 'images/ast2600-evb/buildroot-2023.11/flash.img') + image_hash = ('b62808daef48b438d0728ee07662290490ecfa65987bb91294cafb1bb7ad1a68') image_path = self.fetch_asset(image_url, asset_hash=image_hash, algorithm='sha256') @@ -XXX,XX +XXX,XX @@ def test_arm_ast2600_evb_buildroot(self): 'ds1338,bus=aspeed.i2c.bus.3,address=0x32'); self.vm.add_args('-device', 'i2c-echo,bus=aspeed.i2c.bus.3,address=0x42'); - self.do_test_arm_aspeed_buildroot_start(image_path, '0xf00') + self.do_test_arm_aspeed_buildroot_start(image_path, '0xf00', 'Aspeed AST2600 EVB') exec_command_and_wait_for_pattern(self, 'echo lm75 0x4d > /sys/class/i2c-dev/i2c-3/device/new_device', 'i2c i2c-3: new_device: Instantiated device lm75 at 0x4d'); exec_command_and_wait_for_pattern(self, - 'cat /sys/class/hwmon/hwmon0/temp1_input', '0') + 'cat /sys/class/hwmon/hwmon1/temp1_input', '0') self.vm.cmd('qom-set', path='/machine/peripheral/tmp-test', property='temperature', value=18000); exec_command_and_wait_for_pattern(self, - 'cat /sys/class/hwmon/hwmon0/temp1_input', '18000') + 'cat /sys/class/hwmon/hwmon1/temp1_input', '18000') exec_command_and_wait_for_pattern(self, 'echo ds1307 0x32 > /sys/class/i2c-dev/i2c-3/device/new_device', @@ -XXX,XX +XXX,XX @@ def test_arm_ast2600_evb_buildroot_tpm(self): self.vm.add_args('-device', 'tpm-tis-i2c,tpmdev=tpm0,bus=aspeed.i2c.bus.12,address=0x2e') self.do_test_arm_aspeed_buildroot_start(image_path, '0xf00', 'Aspeed AST2600 EVB') - exec_command(self, "passw0rd") exec_command_and_wait_for_pattern(self, 'echo tpm_tis_i2c 0x2e > /sys/bus/i2c/devices/i2c-12/new_device', -- 2.43.0
From: Philippe Mathieu-Daudé <philmd@linaro.org> Remove copy/paste typo from commit 6c323aba40 ("hw/arm/aspeed: Adding new machine Tiogapass in QEMU"). Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Cédric Le Goater <clg@kaod.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Gavin Shan <gshan@redhat.com> Signed-off-by: Cédric Le Goater <clg@kaod.org> --- hw/arm/aspeed.c | 1 - 1 file changed, 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_tiogapass_class_init(ObjectClass *oc, void *data) mc->default_ram_size = 1 * GiB; mc->default_cpus = mc->min_cpus = mc->max_cpus = aspeed_soc_num_cpus(amc->soc_name); - aspeed_soc_num_cpus(amc->soc_name); }; static void aspeed_machine_sonorapass_class_init(ObjectClass *oc, void *data) -- 2.43.0
From: Philippe Mathieu-Daudé <philmd@linaro.org> Since commit b7f1a0cb76 ("arm/aspeed: Compute the number of CPUs from the SoC definition") Aspeed machines use the aspeed_soc_num_cpus() helper to set the number of CPUs. Use it for the ast1030-evb (commit 356b230ed1 "aspeed/soc: Add AST1030 support") and supermicrox11-bmc (commit 40a38df55e "hw/arm/aspeed: Add board model for Supermicro X11 BMC") machines. Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Cédric Le Goater <clg@kaod.org> Reviewed-by: Gavin Shan <gshan@redhat.com> Signed-off-by: Cédric Le Goater <clg@kaod.org> --- hw/arm/aspeed.c | 5 ++++- 1 file changed, 4 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_supermicrox11_bmc_class_init(ObjectClass *oc, amc->macs_mask = ASPEED_MAC0_ON | ASPEED_MAC1_ON; amc->i2c_init = palmetto_bmc_i2c_init; mc->default_ram_size = 256 * MiB; + mc->default_cpus = mc->min_cpus = mc->max_cpus = + aspeed_soc_num_cpus(amc->soc_name); } static void aspeed_machine_supermicro_x11spi_bmc_class_init(ObjectClass *oc, @@ -XXX,XX +XXX,XX @@ static void aspeed_minibmc_machine_ast1030_evb_class_init(ObjectClass *oc, mc->init = aspeed_minibmc_machine_init; amc->i2c_init = ast1030_evb_i2c_init; mc->default_ram_size = 0; - mc->default_cpus = mc->min_cpus = mc->max_cpus = 1; amc->fmc_model = "sst25vf032b"; amc->spi_model = "sst25vf032b"; amc->num_cs = 2; amc->macs_mask = 0; + mc->default_cpus = mc->min_cpus = mc->max_cpus = + aspeed_soc_num_cpus(amc->soc_name); } static void aspeed_machine_qcom_dc_scm_v1_class_init(ObjectClass *oc, -- 2.43.0
From: Philippe Mathieu-Daudé <philmd@linaro.org> Rework aspeed_soc_num_cpus() as a new init_cpus_defaults() helper to reduce code duplication. Reviewed-by: Cédric Le Goater <clg@kaod.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Gavin Shan <gshan@redhat.com> Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Cédric Le Goater <clg@kaod.org> --- hw/arm/aspeed.c | 71 +++++++++++++++++++------------------------------ 1 file changed, 28 insertions(+), 43 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 aspeed_machine_class_props_init(ObjectClass *oc) "Change the SPI Flash model"); } -static int aspeed_soc_num_cpus(const char *soc_name) +static void aspeed_machine_class_init_cpus_defaults(MachineClass *mc) { - AspeedSoCClass *sc = ASPEED_SOC_CLASS(object_class_by_name(soc_name)); - return sc->num_cpus; + AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(mc); + AspeedSoCClass *sc = ASPEED_SOC_CLASS(object_class_by_name(amc->soc_name)); + + mc->default_cpus = sc->num_cpus; + mc->min_cpus = sc->num_cpus; + mc->max_cpus = sc->num_cpus; } static void aspeed_machine_class_init(ObjectClass *oc, void *data) @@ -XXX,XX +XXX,XX @@ static void aspeed_machine_palmetto_class_init(ObjectClass *oc, void *data) amc->num_cs = 1; amc->i2c_init = palmetto_bmc_i2c_init; mc->default_ram_size = 256 * MiB; - mc->default_cpus = mc->min_cpus = mc->max_cpus = - aspeed_soc_num_cpus(amc->soc_name); + aspeed_machine_class_init_cpus_defaults(mc); }; static void aspeed_machine_quanta_q71l_class_init(ObjectClass *oc, void *data) @@ -XXX,XX +XXX,XX @@ static void aspeed_machine_quanta_q71l_class_init(ObjectClass *oc, void *data) amc->num_cs = 1; amc->i2c_init = quanta_q71l_bmc_i2c_init; mc->default_ram_size = 128 * MiB; - mc->default_cpus = mc->min_cpus = mc->max_cpus = - aspeed_soc_num_cpus(amc->soc_name); + aspeed_machine_class_init_cpus_defaults(mc); } static void aspeed_machine_supermicrox11_bmc_class_init(ObjectClass *oc, @@ -XXX,XX +XXX,XX @@ static void aspeed_machine_supermicrox11_bmc_class_init(ObjectClass *oc, amc->macs_mask = ASPEED_MAC0_ON | ASPEED_MAC1_ON; amc->i2c_init = palmetto_bmc_i2c_init; mc->default_ram_size = 256 * MiB; - mc->default_cpus = mc->min_cpus = mc->max_cpus = - aspeed_soc_num_cpus(amc->soc_name); + aspeed_machine_class_init_cpus_defaults(mc); } static void aspeed_machine_supermicro_x11spi_bmc_class_init(ObjectClass *oc, @@ -XXX,XX +XXX,XX @@ static void aspeed_machine_supermicro_x11spi_bmc_class_init(ObjectClass *oc, amc->macs_mask = ASPEED_MAC0_ON | ASPEED_MAC1_ON; amc->i2c_init = palmetto_bmc_i2c_init; mc->default_ram_size = 512 * MiB; - mc->default_cpus = mc->min_cpus = mc->max_cpus = - aspeed_soc_num_cpus(amc->soc_name); + aspeed_machine_class_init_cpus_defaults(mc); } static void aspeed_machine_ast2500_evb_class_init(ObjectClass *oc, void *data) @@ -XXX,XX +XXX,XX @@ static void aspeed_machine_ast2500_evb_class_init(ObjectClass *oc, void *data) amc->num_cs = 1; amc->i2c_init = ast2500_evb_i2c_init; mc->default_ram_size = 512 * MiB; - mc->default_cpus = mc->min_cpus = mc->max_cpus = - aspeed_soc_num_cpus(amc->soc_name); + aspeed_machine_class_init_cpus_defaults(mc); }; static void aspeed_machine_yosemitev2_class_init(ObjectClass *oc, void *data) @@ -XXX,XX +XXX,XX @@ static void aspeed_machine_yosemitev2_class_init(ObjectClass *oc, void *data) amc->num_cs = 2; amc->i2c_init = yosemitev2_bmc_i2c_init; mc->default_ram_size = 512 * MiB; - mc->default_cpus = mc->min_cpus = mc->max_cpus = - aspeed_soc_num_cpus(amc->soc_name); + aspeed_machine_class_init_cpus_defaults(mc); }; static void aspeed_machine_romulus_class_init(ObjectClass *oc, void *data) @@ -XXX,XX +XXX,XX @@ static void aspeed_machine_romulus_class_init(ObjectClass *oc, void *data) amc->num_cs = 2; amc->i2c_init = romulus_bmc_i2c_init; mc->default_ram_size = 512 * MiB; - mc->default_cpus = mc->min_cpus = mc->max_cpus = - aspeed_soc_num_cpus(amc->soc_name); + aspeed_machine_class_init_cpus_defaults(mc); }; static void aspeed_machine_tiogapass_class_init(ObjectClass *oc, void *data) @@ -XXX,XX +XXX,XX @@ static void aspeed_machine_tiogapass_class_init(ObjectClass *oc, void *data) amc->num_cs = 2; amc->i2c_init = tiogapass_bmc_i2c_init; mc->default_ram_size = 1 * GiB; - mc->default_cpus = mc->min_cpus = mc->max_cpus = - aspeed_soc_num_cpus(amc->soc_name); + aspeed_machine_class_init_cpus_defaults(mc); }; static void aspeed_machine_sonorapass_class_init(ObjectClass *oc, void *data) @@ -XXX,XX +XXX,XX @@ static void aspeed_machine_sonorapass_class_init(ObjectClass *oc, void *data) amc->num_cs = 2; amc->i2c_init = sonorapass_bmc_i2c_init; mc->default_ram_size = 512 * MiB; - mc->default_cpus = mc->min_cpus = mc->max_cpus = - aspeed_soc_num_cpus(amc->soc_name); + aspeed_machine_class_init_cpus_defaults(mc); }; static void aspeed_machine_witherspoon_class_init(ObjectClass *oc, void *data) @@ -XXX,XX +XXX,XX @@ static void aspeed_machine_witherspoon_class_init(ObjectClass *oc, void *data) amc->num_cs = 2; amc->i2c_init = witherspoon_bmc_i2c_init; mc->default_ram_size = 512 * MiB; - mc->default_cpus = mc->min_cpus = mc->max_cpus = - aspeed_soc_num_cpus(amc->soc_name); + aspeed_machine_class_init_cpus_defaults(mc); }; static void aspeed_machine_ast2600_evb_class_init(ObjectClass *oc, void *data) @@ -XXX,XX +XXX,XX @@ static void aspeed_machine_ast2600_evb_class_init(ObjectClass *oc, void *data) 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 = - aspeed_soc_num_cpus(amc->soc_name); + aspeed_machine_class_init_cpus_defaults(mc); }; static void aspeed_machine_tacoma_class_init(ObjectClass *oc, void *data) @@ -XXX,XX +XXX,XX @@ static void aspeed_machine_tacoma_class_init(ObjectClass *oc, void *data) amc->macs_mask = ASPEED_MAC2_ON; amc->i2c_init = witherspoon_bmc_i2c_init; /* Same board layout */ mc->default_ram_size = 1 * GiB; - mc->default_cpus = mc->min_cpus = mc->max_cpus = - aspeed_soc_num_cpus(amc->soc_name); + aspeed_machine_class_init_cpus_defaults(mc); }; static void aspeed_machine_g220a_class_init(ObjectClass *oc, void *data) @@ -XXX,XX +XXX,XX @@ static void aspeed_machine_g220a_class_init(ObjectClass *oc, void *data) 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 = - aspeed_soc_num_cpus(amc->soc_name); + aspeed_machine_class_init_cpus_defaults(mc); }; static void aspeed_machine_fp5280g2_class_init(ObjectClass *oc, void *data) @@ -XXX,XX +XXX,XX @@ static void aspeed_machine_fp5280g2_class_init(ObjectClass *oc, void *data) amc->macs_mask = ASPEED_MAC0_ON | ASPEED_MAC1_ON; amc->i2c_init = fp5280g2_bmc_i2c_init; mc->default_ram_size = 512 * MiB; - mc->default_cpus = mc->min_cpus = mc->max_cpus = - aspeed_soc_num_cpus(amc->soc_name); + aspeed_machine_class_init_cpus_defaults(mc); }; static void aspeed_machine_rainier_class_init(ObjectClass *oc, void *data) @@ -XXX,XX +XXX,XX @@ static void aspeed_machine_rainier_class_init(ObjectClass *oc, void *data) amc->macs_mask = ASPEED_MAC2_ON | ASPEED_MAC3_ON; amc->i2c_init = rainier_bmc_i2c_init; mc->default_ram_size = 1 * GiB; - mc->default_cpus = mc->min_cpus = mc->max_cpus = - aspeed_soc_num_cpus(amc->soc_name); + aspeed_machine_class_init_cpus_defaults(mc); }; #define FUJI_BMC_RAM_SIZE ASPEED_RAM_SIZE(2 * GiB) @@ -XXX,XX +XXX,XX @@ static void aspeed_machine_fuji_class_init(ObjectClass *oc, void *data) 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); + aspeed_machine_class_init_cpus_defaults(mc); }; #define BLETCHLEY_BMC_RAM_SIZE ASPEED_RAM_SIZE(2 * GiB) @@ -XXX,XX +XXX,XX @@ static void aspeed_machine_bletchley_class_init(ObjectClass *oc, void *data) amc->macs_mask = ASPEED_MAC2_ON; amc->i2c_init = bletchley_bmc_i2c_init; mc->default_ram_size = BLETCHLEY_BMC_RAM_SIZE; - mc->default_cpus = mc->min_cpus = mc->max_cpus = - aspeed_soc_num_cpus(amc->soc_name); + aspeed_machine_class_init_cpus_defaults(mc); } static void fby35_reset(MachineState *state, ShutdownCause reason) @@ -XXX,XX +XXX,XX @@ static void aspeed_machine_fby35_class_init(ObjectClass *oc, void *data) amc->i2c_init = fby35_i2c_init; /* FIXME: Replace this macro with something more general */ mc->default_ram_size = FUJI_BMC_RAM_SIZE; + aspeed_machine_class_init_cpus_defaults(mc); } #define AST1030_INTERNAL_FLASH_SIZE (1024 * 1024) @@ -XXX,XX +XXX,XX @@ static void aspeed_minibmc_machine_ast1030_evb_class_init(ObjectClass *oc, amc->spi_model = "sst25vf032b"; amc->num_cs = 2; amc->macs_mask = 0; - mc->default_cpus = mc->min_cpus = mc->max_cpus = - aspeed_soc_num_cpus(amc->soc_name); + aspeed_machine_class_init_cpus_defaults(mc); } static void aspeed_machine_qcom_dc_scm_v1_class_init(ObjectClass *oc, @@ -XXX,XX +XXX,XX @@ static void aspeed_machine_qcom_dc_scm_v1_class_init(ObjectClass *oc, amc->macs_mask = ASPEED_MAC2_ON | ASPEED_MAC3_ON; amc->i2c_init = qcom_dc_scm_bmc_i2c_init; mc->default_ram_size = 1 * GiB; - mc->default_cpus = mc->min_cpus = mc->max_cpus = - aspeed_soc_num_cpus(amc->soc_name); + aspeed_machine_class_init_cpus_defaults(mc); }; static void aspeed_machine_qcom_firework_class_init(ObjectClass *oc, @@ -XXX,XX +XXX,XX @@ static void aspeed_machine_qcom_firework_class_init(ObjectClass *oc, amc->macs_mask = ASPEED_MAC2_ON | ASPEED_MAC3_ON; amc->i2c_init = qcom_dc_scm_firework_i2c_init; mc->default_ram_size = 1 * GiB; - mc->default_cpus = mc->min_cpus = mc->max_cpus = - aspeed_soc_num_cpus(amc->soc_name); + aspeed_machine_class_init_cpus_defaults(mc); }; static const TypeInfo aspeed_machine_types[] = { -- 2.43.0
From: Philippe Mathieu-Daudé <philmd@linaro.org> In order to alter AspeedSoCClass::cpu_type in the next commit, introduce the aspeed_soc_cpu_type() helper to retrieve the per-SoC CPU type from AspeedSoCClass. Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Cédric Le Goater <clg@kaod.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Gavin Shan <gshan@redhat.com> Signed-off-by: Cédric Le Goater <clg@kaod.org> --- include/hw/arm/aspeed_soc.h | 1 + hw/arm/aspeed_ast10x0.c | 2 +- hw/arm/aspeed_ast2400.c | 3 ++- hw/arm/aspeed_ast2600.c | 3 ++- hw/arm/aspeed_soc_common.c | 5 +++++ 5 files changed, 11 insertions(+), 3 deletions(-) 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 AspeedSoCClass { qemu_irq (*get_irq)(AspeedSoCState *s, int dev); }; +const char *aspeed_soc_cpu_type(AspeedSoCClass *sc); enum { ASPEED_DEV_SPI_BOOT, diff --git a/hw/arm/aspeed_ast10x0.c b/hw/arm/aspeed_ast10x0.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/aspeed_ast10x0.c +++ b/hw/arm/aspeed_ast10x0.c @@ -XXX,XX +XXX,XX @@ static void aspeed_soc_ast1030_realize(DeviceState *dev_soc, Error **errp) /* AST1030 CPU Core */ armv7m = DEVICE(&a->armv7m); qdev_prop_set_uint32(armv7m, "num-irq", 256); - qdev_prop_set_string(armv7m, "cpu-type", sc->cpu_type); + qdev_prop_set_string(armv7m, "cpu-type", aspeed_soc_cpu_type(sc)); qdev_connect_clock_in(armv7m, "cpuclk", s->sysclk); object_property_set_link(OBJECT(&a->armv7m), "memory", OBJECT(s->memory), &error_abort); diff --git a/hw/arm/aspeed_ast2400.c b/hw/arm/aspeed_ast2400.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/aspeed_ast2400.c +++ b/hw/arm/aspeed_ast2400.c @@ -XXX,XX +XXX,XX @@ static void aspeed_ast2400_soc_init(Object *obj) } for (i = 0; i < sc->num_cpus; i++) { - object_initialize_child(obj, "cpu[*]", &a->cpu[i], sc->cpu_type); + object_initialize_child(obj, "cpu[*]", &a->cpu[i], + aspeed_soc_cpu_type(sc)); } snprintf(typename, sizeof(typename), "aspeed.scu-%s", socname); 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_init(Object *obj) } for (i = 0; i < sc->num_cpus; i++) { - object_initialize_child(obj, "cpu[*]", &a->cpu[i], sc->cpu_type); + object_initialize_child(obj, "cpu[*]", &a->cpu[i], + aspeed_soc_cpu_type(sc)); } snprintf(typename, sizeof(typename), "aspeed.scu-%s", socname); diff --git a/hw/arm/aspeed_soc_common.c b/hw/arm/aspeed_soc_common.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/aspeed_soc_common.c +++ b/hw/arm/aspeed_soc_common.c @@ -XXX,XX +XXX,XX @@ #include "hw/char/serial.h" +const char *aspeed_soc_cpu_type(AspeedSoCClass *sc) +{ + return sc->cpu_type; +} + qemu_irq aspeed_soc_get_irq(AspeedSoCState *s, int dev) { return ASPEED_SOC_GET_CLASS(s)->get_irq(s, dev); -- 2.43.0
From: Philippe Mathieu-Daudé <philmd@linaro.org> Aspeed SoCs use a single CPU type (set as AspeedSoCClass::cpu_type). Convert it to a NULL-terminated array (of a single non-NULL element). Set MachineClass::valid_cpu_types[] to use the common machine code to provide hints when the requested CPU is invalid (see commit e702cbc19e ("machine: Improve is_cpu_type_supported()"). Reviewed-by: Cédric Le Goater <clg@kaod.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Gavin Shan <gshan@redhat.com> Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Cédric Le Goater <clg@kaod.org> --- include/hw/arm/aspeed_soc.h | 3 ++- hw/arm/aspeed.c | 1 + hw/arm/aspeed_ast10x0.c | 6 +++++- hw/arm/aspeed_ast2400.c | 12 ++++++++++-- hw/arm/aspeed_ast2600.c | 6 +++++- hw/arm/aspeed_soc_common.c | 5 ++++- 6 files changed, 27 insertions(+), 6 deletions(-) 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 AspeedSoCClass { DeviceClass parent_class; const char *name; - const char *cpu_type; + /** valid_cpu_types: NULL terminated array of a single CPU type. */ + const char * const *valid_cpu_types; uint32_t silicon_rev; uint64_t sram_size; uint64_t secsram_size; 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_class_init_cpus_defaults(MachineClass *mc) mc->default_cpus = sc->num_cpus; mc->min_cpus = sc->num_cpus; mc->max_cpus = sc->num_cpus; + mc->valid_cpu_types = sc->valid_cpu_types; } static void aspeed_machine_class_init(ObjectClass *oc, void *data) diff --git a/hw/arm/aspeed_ast10x0.c b/hw/arm/aspeed_ast10x0.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/aspeed_ast10x0.c +++ b/hw/arm/aspeed_ast10x0.c @@ -XXX,XX +XXX,XX @@ static void aspeed_soc_ast1030_realize(DeviceState *dev_soc, Error **errp) static void aspeed_soc_ast1030_class_init(ObjectClass *klass, void *data) { + static const char * const valid_cpu_types[] = { + ARM_CPU_TYPE_NAME("cortex-m4"), /* TODO cortex-m4f */ + NULL + }; DeviceClass *dc = DEVICE_CLASS(klass); AspeedSoCClass *sc = ASPEED_SOC_CLASS(dc); dc->realize = aspeed_soc_ast1030_realize; sc->name = "ast1030-a1"; - sc->cpu_type = ARM_CPU_TYPE_NAME("cortex-m4"); /* TODO cortex-m4f */ + sc->valid_cpu_types = valid_cpu_types; sc->silicon_rev = AST1030_A1_SILICON_REV; sc->sram_size = 0xc0000; sc->secsram_size = 0x40000; /* 256 * KiB */ diff --git a/hw/arm/aspeed_ast2400.c b/hw/arm/aspeed_ast2400.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/aspeed_ast2400.c +++ b/hw/arm/aspeed_ast2400.c @@ -XXX,XX +XXX,XX @@ static void aspeed_ast2400_soc_realize(DeviceState *dev, Error **errp) static void aspeed_soc_ast2400_class_init(ObjectClass *oc, void *data) { + static const char * const valid_cpu_types[] = { + ARM_CPU_TYPE_NAME("arm926"), + NULL + }; AspeedSoCClass *sc = ASPEED_SOC_CLASS(oc); DeviceClass *dc = DEVICE_CLASS(oc); @@ -XXX,XX +XXX,XX @@ static void aspeed_soc_ast2400_class_init(ObjectClass *oc, void *data) dc->user_creatable = false; sc->name = "ast2400-a1"; - sc->cpu_type = ARM_CPU_TYPE_NAME("arm926"); + sc->valid_cpu_types = valid_cpu_types; sc->silicon_rev = AST2400_A1_SILICON_REV; sc->sram_size = 0x8000; sc->spis_num = 1; @@ -XXX,XX +XXX,XX @@ static void aspeed_soc_ast2400_class_init(ObjectClass *oc, void *data) static void aspeed_soc_ast2500_class_init(ObjectClass *oc, void *data) { + static const char * const valid_cpu_types[] = { + ARM_CPU_TYPE_NAME("arm1176"), + NULL + }; AspeedSoCClass *sc = ASPEED_SOC_CLASS(oc); DeviceClass *dc = DEVICE_CLASS(oc); @@ -XXX,XX +XXX,XX @@ static void aspeed_soc_ast2500_class_init(ObjectClass *oc, void *data) dc->user_creatable = false; sc->name = "ast2500-a1"; - sc->cpu_type = ARM_CPU_TYPE_NAME("arm1176"); + sc->valid_cpu_types = valid_cpu_types; sc->silicon_rev = AST2500_A1_SILICON_REV; sc->sram_size = 0x9000; sc->spis_num = 2; 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) static void aspeed_soc_ast2600_class_init(ObjectClass *oc, void *data) { + static const char * const valid_cpu_types[] = { + ARM_CPU_TYPE_NAME("cortex-a7"), + NULL + }; DeviceClass *dc = DEVICE_CLASS(oc); AspeedSoCClass *sc = ASPEED_SOC_CLASS(oc); dc->realize = aspeed_soc_ast2600_realize; sc->name = "ast2600-a3"; - sc->cpu_type = ARM_CPU_TYPE_NAME("cortex-a7"); + sc->valid_cpu_types = valid_cpu_types; sc->silicon_rev = AST2600_A3_SILICON_REV; sc->sram_size = 0x16400; sc->spis_num = 2; diff --git a/hw/arm/aspeed_soc_common.c b/hw/arm/aspeed_soc_common.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/aspeed_soc_common.c +++ b/hw/arm/aspeed_soc_common.c @@ -XXX,XX +XXX,XX @@ const char *aspeed_soc_cpu_type(AspeedSoCClass *sc) { - return sc->cpu_type; + assert(sc->valid_cpu_types); + assert(sc->valid_cpu_types[0]); + assert(!sc->valid_cpu_types[1]); + return sc->valid_cpu_types[0]; } qemu_irq aspeed_soc_get_irq(AspeedSoCState *s, int dev) -- 2.43.0
From: Ninad Palsule <ninad@linux.ibm.com> This is a part of patchset where IBM's Flexible Service Interface is introduced. The LBUS is modelled to maintain mapped memory for the devices. The memory is mapped after CFAM config, peek table and FSI slave registers. Signed-off-by: Andrew Jeffery <andrew@aj.id.au> Signed-off-by: Ninad Palsule <ninad@linux.ibm.com> Reviewed-by: Cédric Le Goater <clg@kaod.org> [ clg: - removed lbus_add_device() bc unused - removed lbus_create_device() bc used only once - removed "address" property - updated meson.build to build fsi dir - included an empty hw/fsi/trace-events ] Signed-off-by: Cédric Le Goater <clg@kaod.org> --- meson.build | 1 + hw/fsi/trace.h | 1 + include/hw/fsi/lbus.h | 32 ++++++++++++++++++++++++++++++++ hw/fsi/lbus.c | 43 +++++++++++++++++++++++++++++++++++++++++++ hw/Kconfig | 1 + hw/fsi/Kconfig | 2 ++ hw/fsi/meson.build | 1 + hw/fsi/trace-events | 0 hw/meson.build | 1 + 9 files changed, 82 insertions(+) create mode 100644 hw/fsi/trace.h create mode 100644 include/hw/fsi/lbus.h create mode 100644 hw/fsi/lbus.c create mode 100644 hw/fsi/Kconfig create mode 100644 hw/fsi/meson.build create mode 100644 hw/fsi/trace-events diff --git a/meson.build b/meson.build index XXXXXXX..XXXXXXX 100644 --- a/meson.build +++ b/meson.build @@ -XXX,XX +XXX,XX @@ if have_system 'hw/char', 'hw/display', 'hw/dma', + 'hw/fsi', 'hw/hyperv', 'hw/i2c', 'hw/i386', diff --git a/hw/fsi/trace.h b/hw/fsi/trace.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/hw/fsi/trace.h @@ -0,0 +1 @@ +#include "trace/trace-hw_fsi.h" diff --git a/include/hw/fsi/lbus.h b/include/hw/fsi/lbus.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/include/hw/fsi/lbus.h @@ -XXX,XX +XXX,XX @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * Copyright (C) 2024 IBM Corp. + * + * IBM Local bus and connected device structures. + */ +#ifndef FSI_LBUS_H +#define FSI_LBUS_H + +#include "hw/qdev-core.h" +#include "qemu/units.h" +#include "exec/memory.h" + +#define TYPE_FSI_LBUS_DEVICE "fsi.lbus.device" +OBJECT_DECLARE_SIMPLE_TYPE(FSILBusDevice, FSI_LBUS_DEVICE) + +typedef struct FSILBusDevice { + DeviceState parent; + + MemoryRegion iomem; +} FSILBusDevice; + +#define TYPE_FSI_LBUS "fsi.lbus" +OBJECT_DECLARE_SIMPLE_TYPE(FSILBus, FSI_LBUS) + +typedef struct FSILBus { + BusState bus; + + MemoryRegion mr; +} FSILBus; + +#endif /* FSI_LBUS_H */ diff --git a/hw/fsi/lbus.c b/hw/fsi/lbus.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/hw/fsi/lbus.c @@ -XXX,XX +XXX,XX @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * Copyright (C) 2024 IBM Corp. + * + * IBM Local bus where FSI slaves are connected + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/fsi/lbus.h" + +#include "hw/qdev-properties.h" + +#include "trace.h" + +static void fsi_lbus_init(Object *o) +{ + FSILBus *lbus = FSI_LBUS(o); + + memory_region_init(&lbus->mr, OBJECT(lbus), TYPE_FSI_LBUS, 1 * MiB); +} + +static const TypeInfo fsi_lbus_info = { + .name = TYPE_FSI_LBUS, + .parent = TYPE_BUS, + .instance_init = fsi_lbus_init, + .instance_size = sizeof(FSILBus), +}; + +static const TypeInfo fsi_lbus_device_type_info = { + .name = TYPE_FSI_LBUS_DEVICE, + .parent = TYPE_DEVICE, + .instance_size = sizeof(FSILBusDevice), + .abstract = true, +}; + +static void fsi_lbus_register_types(void) +{ + type_register_static(&fsi_lbus_info); + type_register_static(&fsi_lbus_device_type_info); +} + +type_init(fsi_lbus_register_types); diff --git a/hw/Kconfig b/hw/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/hw/Kconfig +++ b/hw/Kconfig @@ -XXX,XX +XXX,XX @@ source core/Kconfig source cxl/Kconfig source display/Kconfig source dma/Kconfig +source fsi/Kconfig source gpio/Kconfig source hyperv/Kconfig source i2c/Kconfig diff --git a/hw/fsi/Kconfig b/hw/fsi/Kconfig new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/hw/fsi/Kconfig @@ -XXX,XX +XXX,XX @@ +config FSI + bool diff --git a/hw/fsi/meson.build b/hw/fsi/meson.build new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/hw/fsi/meson.build @@ -0,0 +1 @@ +system_ss.add(when: 'CONFIG_FSI', if_true: files('lbus.c')) diff --git a/hw/fsi/trace-events b/hw/fsi/trace-events new file mode 100644 index XXXXXXX..XXXXXXX diff --git a/hw/meson.build b/hw/meson.build index XXXXXXX..XXXXXXX 100644 --- a/hw/meson.build +++ b/hw/meson.build @@ -XXX,XX +XXX,XX @@ subdir('virtio') subdir('watchdog') subdir('xen') subdir('xenpv') +subdir('fsi') subdir('alpha') subdir('arm') -- 2.43.0
From: Ninad Palsule <ninad@linux.ibm.com> This is a part of patchset where IBM's Flexible Service Interface is introduced. The scratchpad provides a set of non-functional registers. The firmware is free to use them, hardware does not support any special management support. The scratchpad registers can be read or written from LBUS slave. The scratch pad is managed under FSI CFAM state. Signed-off-by: Andrew Jeffery <andrew@aj.id.au> Signed-off-by: Ninad Palsule <ninad@linux.ibm.com> Reviewed-by: Cédric Le Goater <clg@kaod.org> [ clg: - moved object FSIScratchPad under FSICFAMState - moved FSIScratchPad code under cfam.c ] Signed-off-by: Cédric Le Goater <clg@kaod.org> --- include/hw/fsi/lbus.h | 11 ++++++ hw/fsi/lbus.c | 78 +++++++++++++++++++++++++++++++++++++++++-- hw/fsi/trace-events | 2 ++ 3 files changed, 89 insertions(+), 2 deletions(-) diff --git a/include/hw/fsi/lbus.h b/include/hw/fsi/lbus.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/fsi/lbus.h +++ b/include/hw/fsi/lbus.h @@ -XXX,XX +XXX,XX @@ typedef struct FSILBus { MemoryRegion mr; } FSILBus; +#define TYPE_FSI_SCRATCHPAD "fsi.scratchpad" +#define SCRATCHPAD(obj) OBJECT_CHECK(FSIScratchPad, (obj), TYPE_FSI_SCRATCHPAD) + +#define FSI_SCRATCHPAD_NR_REGS 4 + +typedef struct FSIScratchPad { + FSILBusDevice parent; + + uint32_t regs[FSI_SCRATCHPAD_NR_REGS]; +} FSIScratchPad; + #endif /* FSI_LBUS_H */ diff --git a/hw/fsi/lbus.c b/hw/fsi/lbus.c index XXXXXXX..XXXXXXX 100644 --- a/hw/fsi/lbus.c +++ b/hw/fsi/lbus.c @@ -XXX,XX +XXX,XX @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "hw/fsi/lbus.h" - #include "hw/qdev-properties.h" - +#include "qemu/log.h" #include "trace.h" +#define TO_REG(offset) ((offset) >> 2) + static void fsi_lbus_init(Object *o) { FSILBus *lbus = FSI_LBUS(o); @@ -XXX,XX +XXX,XX @@ static const TypeInfo fsi_lbus_device_type_info = { .abstract = true, }; +static uint64_t fsi_scratchpad_read(void *opaque, hwaddr addr, unsigned size) +{ + FSIScratchPad *s = SCRATCHPAD(opaque); + int reg = TO_REG(addr); + + trace_fsi_scratchpad_read(addr, size); + + if (reg >= FSI_SCRATCHPAD_NR_REGS) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n", + __func__, addr); + return 0; + } + + return s->regs[reg]; +} + +static void fsi_scratchpad_write(void *opaque, hwaddr addr, uint64_t data, + unsigned size) +{ + FSIScratchPad *s = SCRATCHPAD(opaque); + + trace_fsi_scratchpad_write(addr, size, data); + int reg = TO_REG(addr); + + if (reg >= FSI_SCRATCHPAD_NR_REGS) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n", + __func__, addr); + return; + } + + s->regs[reg] = data; +} + +static const struct MemoryRegionOps scratchpad_ops = { + .read = fsi_scratchpad_read, + .write = fsi_scratchpad_write, + .endianness = DEVICE_BIG_ENDIAN, +}; + +static void fsi_scratchpad_realize(DeviceState *dev, Error **errp) +{ + FSILBusDevice *ldev = FSI_LBUS_DEVICE(dev); + + memory_region_init_io(&ldev->iomem, OBJECT(ldev), &scratchpad_ops, + ldev, TYPE_FSI_SCRATCHPAD, 0x400); +} + +static void fsi_scratchpad_reset(DeviceState *dev) +{ + FSIScratchPad *s = SCRATCHPAD(dev); + + memset(s->regs, 0, sizeof(s->regs)); +} + +static void fsi_scratchpad_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->bus_type = TYPE_FSI_LBUS; + dc->realize = fsi_scratchpad_realize; + dc->reset = fsi_scratchpad_reset; +} + +static const TypeInfo fsi_scratchpad_info = { + .name = TYPE_FSI_SCRATCHPAD, + .parent = TYPE_FSI_LBUS_DEVICE, + .instance_size = sizeof(FSIScratchPad), + .class_init = fsi_scratchpad_class_init, +}; + static void fsi_lbus_register_types(void) { type_register_static(&fsi_lbus_info); type_register_static(&fsi_lbus_device_type_info); + type_register_static(&fsi_scratchpad_info); } type_init(fsi_lbus_register_types); diff --git a/hw/fsi/trace-events b/hw/fsi/trace-events index XXXXXXX..XXXXXXX 100644 --- a/hw/fsi/trace-events +++ b/hw/fsi/trace-events @@ -XXX,XX +XXX,XX @@ +fsi_scratchpad_read(uint64_t addr, uint32_t size) "@0x%" PRIx64 " size=%d" +fsi_scratchpad_write(uint64_t addr, uint32_t size, uint64_t data) "@0x%" PRIx64 " size=%d value=0x%"PRIx64 -- 2.43.0
From: Ninad Palsule <ninad@linux.ibm.com> This is a part of patchset where FSI bus is introduced. The FSI bus is a simple bus where FSI master is attached. Signed-off-by: Andrew Jeffery <andrew@aj.id.au> Signed-off-by: Ninad Palsule <ninad@linux.ibm.com> Reviewed-by: Cédric Le Goater <clg@kaod.org> [ clg: - removed include/hw/fsi/engine-scratchpad.h and hw/fsi/engine-scratchpad.c - dropped FSI_SCRATCHPAD - included FSIBus definition - dropped hw/fsi/trace-events changes ] Signed-off-by: Cédric Le Goater <clg@kaod.org> --- include/hw/fsi/fsi.h | 19 +++++++++++++++++++ hw/fsi/fsi.c | 22 ++++++++++++++++++++++ hw/fsi/meson.build | 2 +- 3 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 include/hw/fsi/fsi.h create mode 100644 hw/fsi/fsi.c diff --git a/include/hw/fsi/fsi.h b/include/hw/fsi/fsi.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/include/hw/fsi/fsi.h @@ -XXX,XX +XXX,XX @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * Copyright (C) 2024 IBM Corp. + * + * IBM Flexible Service Interface + */ +#ifndef FSI_FSI_H +#define FSI_FSI_H + +#include "hw/qdev-core.h" + +#define TYPE_FSI_BUS "fsi.bus" +OBJECT_DECLARE_SIMPLE_TYPE(FSIBus, FSI_BUS) + +typedef struct FSIBus { + BusState bus; +} FSIBus; + +#endif /* FSI_FSI_H */ diff --git a/hw/fsi/fsi.c b/hw/fsi/fsi.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/hw/fsi/fsi.c @@ -XXX,XX +XXX,XX @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * Copyright (C) 2024 IBM Corp. + * + * IBM Flexible Service Interface + */ +#include "qemu/osdep.h" + +#include "hw/fsi/fsi.h" + +static const TypeInfo fsi_bus_info = { + .name = TYPE_FSI_BUS, + .parent = TYPE_BUS, + .instance_size = sizeof(FSIBus), +}; + +static void fsi_bus_register_types(void) +{ + type_register_static(&fsi_bus_info); +} + +type_init(fsi_bus_register_types); diff --git a/hw/fsi/meson.build b/hw/fsi/meson.build index XXXXXXX..XXXXXXX 100644 --- a/hw/fsi/meson.build +++ b/hw/fsi/meson.build @@ -1 +1 @@ -system_ss.add(when: 'CONFIG_FSI', if_true: files('lbus.c')) +system_ss.add(when: 'CONFIG_FSI', if_true: files('lbus.c','fsi.c')) -- 2.43.0
From: Ninad Palsule <ninad@linux.ibm.com> This is a part of patchset where IBM's Flexible Service Interface is introduced. The FSI slave: The slave is the terminal point of the FSI bus for FSI symbols addressed to it. Slaves can be cascaded off of one another. The slave's configuration registers appear in address space of the CFAM to which it is attached. Signed-off-by: Andrew Jeffery <andrew@aj.id.au> Signed-off-by: Ninad Palsule <ninad@linux.ibm.com> Reviewed-by: Cédric Le Goater <clg@kaod.org> Signed-off-by: Cédric Le Goater <clg@kaod.org> --- include/hw/fsi/fsi.h | 18 ++++++++++ hw/fsi/fsi.c | 84 ++++++++++++++++++++++++++++++++++++++++++-- hw/fsi/trace-events | 2 ++ 3 files changed, 102 insertions(+), 2 deletions(-) diff --git a/include/hw/fsi/fsi.h b/include/hw/fsi/fsi.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/fsi/fsi.h +++ b/include/hw/fsi/fsi.h @@ -XXX,XX +XXX,XX @@ #ifndef FSI_FSI_H #define FSI_FSI_H +#include "exec/memory.h" #include "hw/qdev-core.h" +#include "hw/fsi/lbus.h" +#include "qemu/bitops.h" + +/* Bitwise operations at the word level. */ +#define BE_GENMASK(hb, lb) MAKE_64BIT_MASK((lb), ((hb) - (lb) + 1)) #define TYPE_FSI_BUS "fsi.bus" OBJECT_DECLARE_SIMPLE_TYPE(FSIBus, FSI_BUS) @@ -XXX,XX +XXX,XX @@ typedef struct FSIBus { BusState bus; } FSIBus; +#define TYPE_FSI_SLAVE "fsi.slave" +OBJECT_DECLARE_SIMPLE_TYPE(FSISlaveState, FSI_SLAVE) + +#define FSI_SLAVE_CONTROL_NR_REGS ((0x40 >> 2) + 1) + +typedef struct FSISlaveState { + DeviceState parent; + + MemoryRegion iomem; + uint32_t regs[FSI_SLAVE_CONTROL_NR_REGS]; +} FSISlaveState; + #endif /* FSI_FSI_H */ diff --git a/hw/fsi/fsi.c b/hw/fsi/fsi.c index XXXXXXX..XXXXXXX 100644 --- a/hw/fsi/fsi.c +++ b/hw/fsi/fsi.c @@ -XXX,XX +XXX,XX @@ * IBM Flexible Service Interface */ #include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu/log.h" +#include "trace.h" #include "hw/fsi/fsi.h" +#define TO_REG(x) ((x) >> 2) + static const TypeInfo fsi_bus_info = { .name = TYPE_FSI_BUS, .parent = TYPE_BUS, .instance_size = sizeof(FSIBus), }; -static void fsi_bus_register_types(void) +static uint64_t fsi_slave_read(void *opaque, hwaddr addr, unsigned size) +{ + FSISlaveState *s = FSI_SLAVE(opaque); + int reg = TO_REG(addr); + + trace_fsi_slave_read(addr, size); + + if (reg >= FSI_SLAVE_CONTROL_NR_REGS) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Out of bounds read: 0x%"HWADDR_PRIx" for %u\n", + __func__, addr, size); + return 0; + } + + return s->regs[reg]; +} + +static void fsi_slave_write(void *opaque, hwaddr addr, uint64_t data, + unsigned size) +{ + FSISlaveState *s = FSI_SLAVE(opaque); + int reg = TO_REG(addr); + + trace_fsi_slave_write(addr, size, data); + + if (reg >= FSI_SLAVE_CONTROL_NR_REGS) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Out of bounds write: 0x%"HWADDR_PRIx" for %u\n", + __func__, addr, size); + return; + } + + s->regs[reg] = data; +} + +static const struct MemoryRegionOps fsi_slave_ops = { + .read = fsi_slave_read, + .write = fsi_slave_write, + .endianness = DEVICE_BIG_ENDIAN, +}; + +static void fsi_slave_reset(DeviceState *dev) +{ + FSISlaveState *s = FSI_SLAVE(dev); + + /* Initialize registers */ + memset(s->regs, 0, sizeof(s->regs)); +} + +static void fsi_slave_init(Object *o) +{ + FSISlaveState *s = FSI_SLAVE(o); + + memory_region_init_io(&s->iomem, OBJECT(s), &fsi_slave_ops, + s, TYPE_FSI_SLAVE, 0x400); +} + +static void fsi_slave_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->bus_type = TYPE_FSI_BUS; + dc->desc = "FSI Slave"; + dc->reset = fsi_slave_reset; +} + +static const TypeInfo fsi_slave_info = { + .name = TYPE_FSI_SLAVE, + .parent = TYPE_DEVICE, + .instance_init = fsi_slave_init, + .instance_size = sizeof(FSISlaveState), + .class_init = fsi_slave_class_init, +}; + +static void fsi_register_types(void) { type_register_static(&fsi_bus_info); + type_register_static(&fsi_slave_info); } -type_init(fsi_bus_register_types); +type_init(fsi_register_types); diff --git a/hw/fsi/trace-events b/hw/fsi/trace-events index XXXXXXX..XXXXXXX 100644 --- a/hw/fsi/trace-events +++ b/hw/fsi/trace-events @@ -XXX,XX +XXX,XX @@ fsi_scratchpad_read(uint64_t addr, uint32_t size) "@0x%" PRIx64 " size=%d" fsi_scratchpad_write(uint64_t addr, uint32_t size, uint64_t data) "@0x%" PRIx64 " size=%d value=0x%"PRIx64 +fsi_slave_read(uint64_t addr, uint32_t size) "@0x%" PRIx64 " size=%d" +fsi_slave_write(uint64_t addr, uint32_t size, uint64_t data) "@0x%" PRIx64 " size=%d value=0x%"PRIx64 -- 2.43.0
From: Ninad Palsule <ninad@linux.ibm.com> This is a part of patchset where IBM's Flexible Service Interface is introduced. The Common FRU Access Macro (CFAM), an address space containing various "engines" that drive accesses on busses internal and external to the POWER chip. Examples include the SBEFIFO and I2C masters. The engines hang off of an internal Local Bus (LBUS) which is described by the CFAM configuration block. Signed-off-by: Andrew Jeffery <andrew@aj.id.au> Signed-off-by: Ninad Palsule <ninad@linux.ibm.com> Reviewed-by: Cédric Le Goater <clg@kaod.org> [ clg: - moved object FSIScratchPad under FSICFAMState - moved FSIScratchPad code under cfam.c - introduced fsi_cfam_instance_init() - reworked fsi_cfam_realize() ] Signed-off-by: Cédric Le Goater <clg@kaod.org> --- include/hw/fsi/cfam.h | 34 +++++++++ hw/fsi/cfam.c | 168 ++++++++++++++++++++++++++++++++++++++++++ hw/fsi/meson.build | 2 +- hw/fsi/trace-events | 5 ++ 4 files changed, 208 insertions(+), 1 deletion(-) create mode 100644 include/hw/fsi/cfam.h create mode 100644 hw/fsi/cfam.c diff --git a/include/hw/fsi/cfam.h b/include/hw/fsi/cfam.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/include/hw/fsi/cfam.h @@ -XXX,XX +XXX,XX @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * Copyright (C) 2024 IBM Corp. + * + * IBM Common FRU Access Macro + */ +#ifndef FSI_CFAM_H +#define FSI_CFAM_H + +#include "exec/memory.h" + +#include "hw/fsi/fsi.h" +#include "hw/fsi/lbus.h" + +#define TYPE_FSI_CFAM "cfam" +#define FSI_CFAM(obj) OBJECT_CHECK(FSICFAMState, (obj), TYPE_FSI_CFAM) + +/* P9-ism */ +#define CFAM_CONFIG_NR_REGS 0x28 + +typedef struct FSICFAMState { + /* < private > */ + FSISlaveState parent; + + /* CFAM config address space */ + MemoryRegion config_iomem; + + MemoryRegion mr; + + FSILBus lbus; + FSIScratchPad scratchpad; +} FSICFAMState; + +#endif /* FSI_CFAM_H */ diff --git a/hw/fsi/cfam.c b/hw/fsi/cfam.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/hw/fsi/cfam.c @@ -XXX,XX +XXX,XX @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * Copyright (C) 2024 IBM Corp. + * + * IBM Common FRU Access Macro + */ + +#include "qemu/osdep.h" +#include "qemu/units.h" + +#include "qapi/error.h" +#include "trace.h" + +#include "hw/fsi/cfam.h" +#include "hw/fsi/fsi.h" + +#include "hw/qdev-properties.h" + +#define ENGINE_CONFIG_NEXT BIT(31) +#define ENGINE_CONFIG_TYPE_PEEK (0x02 << 4) +#define ENGINE_CONFIG_TYPE_FSI (0x03 << 4) +#define ENGINE_CONFIG_TYPE_SCRATCHPAD (0x06 << 4) + +/* Valid, slots, version, type, crc */ +#define CFAM_CONFIG_REG(__VER, __TYPE, __CRC) \ + (ENGINE_CONFIG_NEXT | \ + 0x00010000 | \ + (__VER) | \ + (__TYPE) | \ + (__CRC)) + +#define TO_REG(x) ((x) >> 2) + +#define CFAM_CONFIG_CHIP_ID TO_REG(0x00) +#define CFAM_CONFIG_PEEK_STATUS TO_REG(0x04) +#define CFAM_CONFIG_CHIP_ID_P9 0xc0022d15 +#define CFAM_CONFIG_CHIP_ID_BREAK 0xc0de0000 + +static uint64_t fsi_cfam_config_read(void *opaque, hwaddr addr, unsigned size) +{ + trace_fsi_cfam_config_read(addr, size); + + switch (addr) { + case 0x00: + return CFAM_CONFIG_CHIP_ID_P9; + case 0x04: + return CFAM_CONFIG_REG(0x1000, ENGINE_CONFIG_TYPE_PEEK, 0xc); + case 0x08: + return CFAM_CONFIG_REG(0x5000, ENGINE_CONFIG_TYPE_FSI, 0xa); + case 0xc: + return CFAM_CONFIG_REG(0x1000, ENGINE_CONFIG_TYPE_SCRATCHPAD, 0x7); + default: + /* + * The config table contains different engines from 0xc onwards. + * The scratch pad is already added at address 0xc. We need to add + * future engines from address 0x10 onwards. Returning 0 as engine + * is not implemented. + */ + return 0; + } +} + +static void fsi_cfam_config_write(void *opaque, hwaddr addr, uint64_t data, + unsigned size) +{ + FSICFAMState *cfam = FSI_CFAM(opaque); + + trace_fsi_cfam_config_write(addr, size, data); + + switch (TO_REG(addr)) { + case CFAM_CONFIG_CHIP_ID: + case CFAM_CONFIG_PEEK_STATUS: + if (data == CFAM_CONFIG_CHIP_ID_BREAK) { + bus_cold_reset(BUS(&cfam->lbus)); + } + break; + default: + trace_fsi_cfam_config_write_noaddr(addr, size, data); + } +} + +static const struct MemoryRegionOps cfam_config_ops = { + .read = fsi_cfam_config_read, + .write = fsi_cfam_config_write, + .valid.max_access_size = 4, + .valid.min_access_size = 4, + .impl.max_access_size = 4, + .impl.min_access_size = 4, + .endianness = DEVICE_BIG_ENDIAN, +}; + +static uint64_t fsi_cfam_unimplemented_read(void *opaque, hwaddr addr, + unsigned size) +{ + trace_fsi_cfam_unimplemented_read(addr, size); + + return 0; +} + +static void fsi_cfam_unimplemented_write(void *opaque, hwaddr addr, + uint64_t data, unsigned size) +{ + trace_fsi_cfam_unimplemented_write(addr, size, data); +} + +static const struct MemoryRegionOps fsi_cfam_unimplemented_ops = { + .read = fsi_cfam_unimplemented_read, + .write = fsi_cfam_unimplemented_write, + .endianness = DEVICE_BIG_ENDIAN, +}; + +static void fsi_cfam_instance_init(Object *obj) +{ + FSICFAMState *s = FSI_CFAM(obj); + + object_initialize_child(obj, "scratchpad", &s->scratchpad, + TYPE_FSI_SCRATCHPAD); +} + +static void fsi_cfam_realize(DeviceState *dev, Error **errp) +{ + FSICFAMState *cfam = FSI_CFAM(dev); + FSISlaveState *slave = FSI_SLAVE(dev); + + /* Each slave has a 2MiB address space */ + memory_region_init_io(&cfam->mr, OBJECT(cfam), &fsi_cfam_unimplemented_ops, + cfam, TYPE_FSI_CFAM, 2 * MiB); + + qbus_init(&cfam->lbus, sizeof(cfam->lbus), TYPE_FSI_LBUS, DEVICE(cfam), + NULL); + + memory_region_init_io(&cfam->config_iomem, OBJECT(cfam), &cfam_config_ops, + cfam, TYPE_FSI_CFAM ".config", 0x400); + + memory_region_add_subregion(&cfam->mr, 0, &cfam->config_iomem); + memory_region_add_subregion(&cfam->mr, 0x800, &slave->iomem); + memory_region_add_subregion(&cfam->mr, 0xc00, &cfam->lbus.mr); + + /* Add scratchpad engine */ + if (!qdev_realize(DEVICE(&cfam->scratchpad), BUS(&cfam->lbus), errp)) { + return; + } + + FSILBusDevice *fsi_dev = FSI_LBUS_DEVICE(&cfam->scratchpad); + memory_region_add_subregion(&cfam->lbus.mr, 0, &fsi_dev->iomem); +} + +static void fsi_cfam_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + dc->bus_type = TYPE_FSI_BUS; + dc->realize = fsi_cfam_realize; +} + +static const TypeInfo fsi_cfam_info = { + .name = TYPE_FSI_CFAM, + .parent = TYPE_FSI_SLAVE, + .instance_init = fsi_cfam_instance_init, + .instance_size = sizeof(FSICFAMState), + .class_init = fsi_cfam_class_init, +}; + +static void fsi_cfam_register_types(void) +{ + type_register_static(&fsi_cfam_info); +} + +type_init(fsi_cfam_register_types); diff --git a/hw/fsi/meson.build b/hw/fsi/meson.build index XXXXXXX..XXXXXXX 100644 --- a/hw/fsi/meson.build +++ b/hw/fsi/meson.build @@ -1 +1 @@ -system_ss.add(when: 'CONFIG_FSI', if_true: files('lbus.c','fsi.c')) +system_ss.add(when: 'CONFIG_FSI', if_true: files('lbus.c','fsi.c','cfam.c')) diff --git a/hw/fsi/trace-events b/hw/fsi/trace-events index XXXXXXX..XXXXXXX 100644 --- a/hw/fsi/trace-events +++ b/hw/fsi/trace-events @@ -XXX,XX +XXX,XX @@ fsi_scratchpad_read(uint64_t addr, uint32_t size) "@0x%" PRIx64 " size=%d" fsi_scratchpad_write(uint64_t addr, uint32_t size, uint64_t data) "@0x%" PRIx64 " size=%d value=0x%"PRIx64 fsi_slave_read(uint64_t addr, uint32_t size) "@0x%" PRIx64 " size=%d" fsi_slave_write(uint64_t addr, uint32_t size, uint64_t data) "@0x%" PRIx64 " size=%d value=0x%"PRIx64 +fsi_cfam_config_read(uint64_t addr, uint32_t size) "@0x%" PRIx64 " size=%d" +fsi_cfam_config_write(uint64_t addr, uint32_t size, uint64_t data) "@0x%" PRIx64 " size=%d value=0x%"PRIx64 +fsi_cfam_unimplemented_read(uint64_t addr, uint32_t size) "@0x%" PRIx64 " size=%d" +fsi_cfam_unimplemented_write(uint64_t addr, uint32_t size, uint64_t data) "@0x%" PRIx64 " size=%d value=0x%"PRIx64 +fsi_cfam_config_write_noaddr(uint64_t addr, uint32_t size, uint64_t data) "@0x%" PRIx64 " size=%d value=0x%"PRIx64 -- 2.43.0
From: Ninad Palsule <ninad@linux.ibm.com> This is a part of patchset where IBM's Flexible Service Interface is introduced. This commit models the FSI master. CFAM is hanging out of FSI master which is a bus controller. The FSI master: A controller in the platform service processor (e.g. BMC) driving CFAM engine accesses into the POWER chip. At the hardware level FSI is a bit-based protocol supporting synchronous and DMA-driven accesses of engines in a CFAM. Signed-off-by: Andrew Jeffery <andrew@aj.id.au> Signed-off-by: Ninad Palsule <ninad@linux.ibm.com> Reviewed-by: Cédric Le Goater <clg@kaod.org> [ clg: - move FSICFAMState object under FSIMasterState - introduced fsi_master_init() - reworked fsi_master_realize() - dropped FSIBus definition ] Signed-off-by: Cédric Le Goater <clg@kaod.org> --- include/hw/fsi/fsi-master.h | 32 +++++++ hw/fsi/fsi-master.c | 170 ++++++++++++++++++++++++++++++++++++ hw/fsi/meson.build | 2 +- hw/fsi/trace-events | 2 + 4 files changed, 205 insertions(+), 1 deletion(-) create mode 100644 include/hw/fsi/fsi-master.h create mode 100644 hw/fsi/fsi-master.c diff --git a/include/hw/fsi/fsi-master.h b/include/hw/fsi/fsi-master.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/include/hw/fsi/fsi-master.h @@ -XXX,XX +XXX,XX @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * Copyright (C) 2024 IBM Corp. + * + * IBM Flexible Service Interface Master + */ +#ifndef FSI_FSI_MASTER_H +#define FSI_FSI_MASTER_H + +#include "exec/memory.h" +#include "hw/qdev-core.h" +#include "hw/fsi/fsi.h" +#include "hw/fsi/cfam.h" + +#define TYPE_FSI_MASTER "fsi.master" +OBJECT_DECLARE_SIMPLE_TYPE(FSIMasterState, FSI_MASTER) + +#define FSI_MASTER_NR_REGS ((0x2e0 >> 2) + 1) + +typedef struct FSIMasterState { + DeviceState parent; + MemoryRegion iomem; + MemoryRegion opb2fsi; + + FSIBus bus; + + uint32_t regs[FSI_MASTER_NR_REGS]; + FSICFAMState cfam; +} FSIMasterState; + + +#endif /* FSI_FSI_H */ diff --git a/hw/fsi/fsi-master.c b/hw/fsi/fsi-master.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/hw/fsi/fsi-master.c @@ -XXX,XX +XXX,XX @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * Copyright (C) 2024 IBM Corp. + * + * IBM Flexible Service Interface master + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu/log.h" +#include "trace.h" + +#include "hw/fsi/fsi-master.h" + +#define TYPE_OP_BUS "opb" + +#define TO_REG(x) ((x) >> 2) + +#define FSI_MENP0 TO_REG(0x010) +#define FSI_MENP32 TO_REG(0x014) +#define FSI_MSENP0 TO_REG(0x018) +#define FSI_MLEVP0 TO_REG(0x018) +#define FSI_MSENP32 TO_REG(0x01c) +#define FSI_MLEVP32 TO_REG(0x01c) +#define FSI_MCENP0 TO_REG(0x020) +#define FSI_MREFP0 TO_REG(0x020) +#define FSI_MCENP32 TO_REG(0x024) +#define FSI_MREFP32 TO_REG(0x024) + +#define FSI_MVER TO_REG(0x074) +#define FSI_MRESP0 TO_REG(0x0d0) + +#define FSI_MRESB0 TO_REG(0x1d0) +#define FSI_MRESB0_RESET_GENERAL BIT(31) +#define FSI_MRESB0_RESET_ERROR BIT(30) + +static uint64_t fsi_master_read(void *opaque, hwaddr addr, unsigned size) +{ + FSIMasterState *s = FSI_MASTER(opaque); + int reg = TO_REG(addr); + + trace_fsi_master_read(addr, size); + + if (reg >= FSI_MASTER_NR_REGS) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Out of bounds read: 0x%"HWADDR_PRIx" for %u\n", + __func__, addr, size); + return 0; + } + + return s->regs[reg]; +} + +static void fsi_master_write(void *opaque, hwaddr addr, uint64_t data, + unsigned size) +{ + FSIMasterState *s = FSI_MASTER(opaque); + int reg = TO_REG(addr); + + trace_fsi_master_write(addr, size, data); + + if (reg >= FSI_MASTER_NR_REGS) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Out of bounds write: %"HWADDR_PRIx" for %u\n", + __func__, addr, size); + return; + } + + switch (reg) { + case FSI_MENP0: + s->regs[FSI_MENP0] = data; + break; + case FSI_MENP32: + s->regs[FSI_MENP32] = data; + break; + case FSI_MSENP0: + s->regs[FSI_MENP0] |= data; + break; + case FSI_MSENP32: + s->regs[FSI_MENP32] |= data; + break; + case FSI_MCENP0: + s->regs[FSI_MENP0] &= ~data; + break; + case FSI_MCENP32: + s->regs[FSI_MENP32] &= ~data; + break; + case FSI_MRESP0: + /* Perform necessary resets leave register 0 to indicate no errors */ + break; + case FSI_MRESB0: + if (data & FSI_MRESB0_RESET_GENERAL) { + device_cold_reset(DEVICE(opaque)); + } + if (data & FSI_MRESB0_RESET_ERROR) { + /* FIXME: this seems dubious */ + device_cold_reset(DEVICE(opaque)); + } + break; + default: + s->regs[reg] = data; + } +} + +static const struct MemoryRegionOps fsi_master_ops = { + .read = fsi_master_read, + .write = fsi_master_write, + .endianness = DEVICE_BIG_ENDIAN, +}; + +static void fsi_master_init(Object *o) +{ + FSIMasterState *s = FSI_MASTER(o); + + object_initialize_child(o, "cfam", &s->cfam, TYPE_FSI_CFAM); + + qbus_init(&s->bus, sizeof(s->bus), TYPE_FSI_BUS, DEVICE(s), NULL); + + memory_region_init_io(&s->iomem, OBJECT(s), &fsi_master_ops, s, + TYPE_FSI_MASTER, 0x10000000); + memory_region_init(&s->opb2fsi, OBJECT(s), "fsi.opb2fsi", 0x10000000); +} + +static void fsi_master_realize(DeviceState *dev, Error **errp) +{ + FSIMasterState *s = FSI_MASTER(dev); + + if (!qdev_realize(DEVICE(&s->cfam), BUS(&s->bus), errp)) { + return; + } + + /* address ? */ + memory_region_add_subregion(&s->opb2fsi, 0, &s->cfam.mr); +} + +static void fsi_master_reset(DeviceState *dev) +{ + FSIMasterState *s = FSI_MASTER(dev); + + /* Initialize registers */ + memset(s->regs, 0, sizeof(s->regs)); + + /* ASPEED default */ + s->regs[FSI_MVER] = 0xe0050101; +} + +static void fsi_master_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->bus_type = TYPE_OP_BUS; + dc->desc = "FSI Master"; + dc->realize = fsi_master_realize; + dc->reset = fsi_master_reset; +} + +static const TypeInfo fsi_master_info = { + .name = TYPE_FSI_MASTER, + .parent = TYPE_DEVICE, + .instance_init = fsi_master_init, + .instance_size = sizeof(FSIMasterState), + .class_init = fsi_master_class_init, +}; + +static void fsi_register_types(void) +{ + type_register_static(&fsi_master_info); +} + +type_init(fsi_register_types); diff --git a/hw/fsi/meson.build b/hw/fsi/meson.build index XXXXXXX..XXXXXXX 100644 --- a/hw/fsi/meson.build +++ b/hw/fsi/meson.build @@ -1 +1 @@ -system_ss.add(when: 'CONFIG_FSI', if_true: files('lbus.c','fsi.c','cfam.c')) +system_ss.add(when: 'CONFIG_FSI', if_true: files('lbus.c','fsi.c','cfam.c','fsi-master.c')) diff --git a/hw/fsi/trace-events b/hw/fsi/trace-events index XXXXXXX..XXXXXXX 100644 --- a/hw/fsi/trace-events +++ b/hw/fsi/trace-events @@ -XXX,XX +XXX,XX @@ fsi_cfam_config_write(uint64_t addr, uint32_t size, uint64_t data) "@0x%" PRIx64 fsi_cfam_unimplemented_read(uint64_t addr, uint32_t size) "@0x%" PRIx64 " size=%d" fsi_cfam_unimplemented_write(uint64_t addr, uint32_t size, uint64_t data) "@0x%" PRIx64 " size=%d value=0x%"PRIx64 fsi_cfam_config_write_noaddr(uint64_t addr, uint32_t size, uint64_t data) "@0x%" PRIx64 " size=%d value=0x%"PRIx64 +fsi_master_read(uint64_t addr, uint32_t size) "@0x%" PRIx64 " size=%d" +fsi_master_write(uint64_t addr, uint32_t size, uint64_t data) "@0x%" PRIx64 " size=%d value=0x%"PRIx64 -- 2.43.0
From: Ninad Palsule <ninad@linux.ibm.com> This is a part of patchset where IBM's Flexible Service Interface is introduced. An APB-to-OPB bridge enabling access to the OPB from the ARM core in the AST2600. Hardware limitations prevent the OPB from being directly mapped into APB, so all accesses are indirect through the bridge. The On-Chip Peripheral Bus (OPB): A low-speed bus typically found in POWER processors. This now makes an appearance in the ASPEED SoC due to tight integration of the FSI master IP with the OPB, mainly the existence of an MMIO-mapping of the CFAM address straight onto a sub-region of the OPB address space. Signed-off-by: Andrew Jeffery <andrew@aj.id.au> Signed-off-by: Ninad Palsule <ninad@linux.ibm.com> Reviewed-by: Cédric Le Goater <clg@kaod.org> [ clg: - moved FSIMasterState under AspeedAPB2OPBState - modified fsi_opb_fsi_master_address() and fsi_opb_opb2fsi_address() - instroduced fsi_aspeed_apb2opb_init() - reworked fsi_aspeed_apb2opb_realize() - removed FSIMasterState object and fsi_opb_realize() - simplified OPBus ] Signed-off-by: Cédric Le Goater <clg@kaod.org> --- include/hw/fsi/aspeed_apb2opb.h | 46 +++++ hw/fsi/aspeed_apb2opb.c | 329 ++++++++++++++++++++++++++++++++ hw/arm/Kconfig | 1 + hw/fsi/Kconfig | 5 + hw/fsi/meson.build | 1 + hw/fsi/trace-events | 2 + 6 files changed, 384 insertions(+) create mode 100644 include/hw/fsi/aspeed_apb2opb.h create mode 100644 hw/fsi/aspeed_apb2opb.c diff --git a/include/hw/fsi/aspeed_apb2opb.h b/include/hw/fsi/aspeed_apb2opb.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/include/hw/fsi/aspeed_apb2opb.h @@ -XXX,XX +XXX,XX @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * Copyright (C) 2024 IBM Corp. + * + * ASPEED APB2OPB Bridge + * IBM On-Chip Peripheral Bus + */ +#ifndef FSI_ASPEED_APB2OPB_H +#define FSI_ASPEED_APB2OPB_H + +#include "exec/memory.h" +#include "hw/fsi/fsi-master.h" +#include "hw/sysbus.h" + +#define TYPE_FSI_OPB "fsi.opb" + +#define TYPE_OP_BUS "opb" +OBJECT_DECLARE_SIMPLE_TYPE(OPBus, OP_BUS) + +typedef struct OPBus { + BusState bus; + + MemoryRegion mr; + AddressSpace as; +} OPBus; + +#define TYPE_ASPEED_APB2OPB "aspeed.apb2opb" +OBJECT_DECLARE_SIMPLE_TYPE(AspeedAPB2OPBState, ASPEED_APB2OPB) + +#define ASPEED_APB2OPB_NR_REGS ((0xe8 >> 2) + 1) + +#define ASPEED_FSI_NUM 2 + +typedef struct AspeedAPB2OPBState { + SysBusDevice parent_obj; + + MemoryRegion iomem; + + uint32_t regs[ASPEED_APB2OPB_NR_REGS]; + qemu_irq irq; + + OPBus opb[ASPEED_FSI_NUM]; + FSIMasterState fsi[ASPEED_FSI_NUM]; +} AspeedAPB2OPBState; + +#endif /* FSI_ASPEED_APB2OPB_H */ diff --git a/hw/fsi/aspeed_apb2opb.c b/hw/fsi/aspeed_apb2opb.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/hw/fsi/aspeed_apb2opb.c @@ -XXX,XX +XXX,XX @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * Copyright (C) 2024 IBM Corp. + * + * ASPEED APB-OPB FSI interface + * IBM On-chip Peripheral Bus + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qom/object.h" +#include "qapi/error.h" +#include "trace.h" + +#include "hw/fsi/aspeed_apb2opb.h" +#include "hw/qdev-core.h" + +#define TO_REG(x) (x >> 2) + +#define APB2OPB_VERSION TO_REG(0x00) +#define APB2OPB_TRIGGER TO_REG(0x04) + +#define APB2OPB_CONTROL TO_REG(0x08) +#define APB2OPB_CONTROL_OFF BE_GENMASK(31, 13) + +#define APB2OPB_OPB2FSI TO_REG(0x0c) +#define APB2OPB_OPB2FSI_OFF BE_GENMASK(31, 22) + +#define APB2OPB_OPB0_SEL TO_REG(0x10) +#define APB2OPB_OPB1_SEL TO_REG(0x28) +#define APB2OPB_OPB_SEL_EN BIT(0) + +#define APB2OPB_OPB0_MODE TO_REG(0x14) +#define APB2OPB_OPB1_MODE TO_REG(0x2c) +#define APB2OPB_OPB_MODE_RD BIT(0) + +#define APB2OPB_OPB0_XFER TO_REG(0x18) +#define APB2OPB_OPB1_XFER TO_REG(0x30) +#define APB2OPB_OPB_XFER_FULL BIT(1) +#define APB2OPB_OPB_XFER_HALF BIT(0) + +#define APB2OPB_OPB0_ADDR TO_REG(0x1c) +#define APB2OPB_OPB0_WRITE_DATA TO_REG(0x20) + +#define APB2OPB_OPB1_ADDR TO_REG(0x34) +#define APB2OPB_OPB1_WRITE_DATA TO_REG(0x38) + +#define APB2OPB_IRQ_STS TO_REG(0x48) +#define APB2OPB_IRQ_STS_OPB1_TX_ACK BIT(17) +#define APB2OPB_IRQ_STS_OPB0_TX_ACK BIT(16) + +#define APB2OPB_OPB0_WRITE_WORD_ENDIAN TO_REG(0x4c) +#define APB2OPB_OPB0_WRITE_WORD_ENDIAN_BE 0x0011101b +#define APB2OPB_OPB0_WRITE_BYTE_ENDIAN TO_REG(0x50) +#define APB2OPB_OPB0_WRITE_BYTE_ENDIAN_BE 0x0c330f3f +#define APB2OPB_OPB1_WRITE_WORD_ENDIAN TO_REG(0x54) +#define APB2OPB_OPB1_WRITE_BYTE_ENDIAN TO_REG(0x58) +#define APB2OPB_OPB0_READ_BYTE_ENDIAN TO_REG(0x5c) +#define APB2OPB_OPB1_READ_BYTE_ENDIAN TO_REG(0x60) +#define APB2OPB_OPB0_READ_WORD_ENDIAN_BE 0x00030b1b + +#define APB2OPB_OPB0_READ_DATA TO_REG(0x84) +#define APB2OPB_OPB1_READ_DATA TO_REG(0x90) + +/* + * The following magic values came from AST2600 data sheet + * The register values are defined under section "FSI controller" + * as initial values. + */ +static const uint32_t aspeed_apb2opb_reset[ASPEED_APB2OPB_NR_REGS] = { + [APB2OPB_VERSION] = 0x000000a1, + [APB2OPB_OPB0_WRITE_WORD_ENDIAN] = 0x0044eee4, + [APB2OPB_OPB0_WRITE_BYTE_ENDIAN] = 0x0055aaff, + [APB2OPB_OPB1_WRITE_WORD_ENDIAN] = 0x00117717, + [APB2OPB_OPB1_WRITE_BYTE_ENDIAN] = 0xffaa5500, + [APB2OPB_OPB0_READ_BYTE_ENDIAN] = 0x0044eee4, + [APB2OPB_OPB1_READ_BYTE_ENDIAN] = 0x00117717 +}; + +static void fsi_opb_fsi_master_address(FSIMasterState *fsi, hwaddr addr) +{ + memory_region_transaction_begin(); + memory_region_set_address(&fsi->iomem, addr); + memory_region_transaction_commit(); +} + +static void fsi_opb_opb2fsi_address(FSIMasterState *fsi, hwaddr addr) +{ + memory_region_transaction_begin(); + memory_region_set_address(&fsi->opb2fsi, addr); + memory_region_transaction_commit(); +} + +static uint64_t fsi_aspeed_apb2opb_read(void *opaque, hwaddr addr, + unsigned size) +{ + AspeedAPB2OPBState *s = ASPEED_APB2OPB(opaque); + unsigned int reg = TO_REG(addr); + + trace_fsi_aspeed_apb2opb_read(addr, size); + + if (reg >= ASPEED_APB2OPB_NR_REGS) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Out of bounds read: 0x%"HWADDR_PRIx" for %u\n", + __func__, addr, size); + return 0; + } + + return s->regs[reg]; +} + +static void fsi_aspeed_apb2opb_write(void *opaque, hwaddr addr, uint64_t data, + unsigned size) +{ + AspeedAPB2OPBState *s = ASPEED_APB2OPB(opaque); + unsigned int reg = TO_REG(addr); + + trace_fsi_aspeed_apb2opb_write(addr, size, data); + + if (reg >= ASPEED_APB2OPB_NR_REGS) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Out of bounds write: %"HWADDR_PRIx" for %u\n", + __func__, addr, size); + return; + } + + switch (reg) { + case APB2OPB_CONTROL: + fsi_opb_fsi_master_address(&s->fsi[0], + data & APB2OPB_CONTROL_OFF); + break; + case APB2OPB_OPB2FSI: + fsi_opb_opb2fsi_address(&s->fsi[0], + data & APB2OPB_OPB2FSI_OFF); + break; + case APB2OPB_OPB0_WRITE_WORD_ENDIAN: + if (data != APB2OPB_OPB0_WRITE_WORD_ENDIAN_BE) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bridge needs to be driven as BE (0x%x)\n", + __func__, APB2OPB_OPB0_WRITE_WORD_ENDIAN_BE); + } + break; + case APB2OPB_OPB0_WRITE_BYTE_ENDIAN: + if (data != APB2OPB_OPB0_WRITE_BYTE_ENDIAN_BE) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bridge needs to be driven as BE (0x%x)\n", + __func__, APB2OPB_OPB0_WRITE_BYTE_ENDIAN_BE); + } + break; + case APB2OPB_OPB0_READ_BYTE_ENDIAN: + if (data != APB2OPB_OPB0_READ_WORD_ENDIAN_BE) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bridge needs to be driven as BE (0x%x)\n", + __func__, APB2OPB_OPB0_READ_WORD_ENDIAN_BE); + } + break; + case APB2OPB_TRIGGER: + { + uint32_t opb, op_mode, op_size, op_addr, op_data; + MemTxResult result; + bool is_write; + int index; + AddressSpace *as; + + assert((s->regs[APB2OPB_OPB0_SEL] & APB2OPB_OPB_SEL_EN) ^ + (s->regs[APB2OPB_OPB1_SEL] & APB2OPB_OPB_SEL_EN)); + + if (s->regs[APB2OPB_OPB0_SEL] & APB2OPB_OPB_SEL_EN) { + opb = 0; + op_mode = s->regs[APB2OPB_OPB0_MODE]; + op_size = s->regs[APB2OPB_OPB0_XFER]; + op_addr = s->regs[APB2OPB_OPB0_ADDR]; + op_data = s->regs[APB2OPB_OPB0_WRITE_DATA]; + } else if (s->regs[APB2OPB_OPB1_SEL] & APB2OPB_OPB_SEL_EN) { + opb = 1; + op_mode = s->regs[APB2OPB_OPB1_MODE]; + op_size = s->regs[APB2OPB_OPB1_XFER]; + op_addr = s->regs[APB2OPB_OPB1_ADDR]; + op_data = s->regs[APB2OPB_OPB1_WRITE_DATA]; + } else { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Invalid operation: 0x%"HWADDR_PRIx" for %u\n", + __func__, addr, size); + return; + } + + if (op_size & ~(APB2OPB_OPB_XFER_HALF | APB2OPB_OPB_XFER_FULL)) { + qemu_log_mask(LOG_GUEST_ERROR, + "OPB transaction failed: Unrecognized access width: %d\n", + op_size); + return; + } + + op_size += 1; + is_write = !(op_mode & APB2OPB_OPB_MODE_RD); + index = opb ? APB2OPB_OPB1_READ_DATA : APB2OPB_OPB0_READ_DATA; + as = &s->opb[opb].as; + + result = address_space_rw(as, op_addr, MEMTXATTRS_UNSPECIFIED, + &op_data, op_size, is_write); + if (result != MEMTX_OK) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: OPB %s failed @%08x\n", + __func__, is_write ? "write" : "read", op_addr); + return; + } + + if (!is_write) { + s->regs[index] = op_data; + } + + s->regs[APB2OPB_IRQ_STS] |= opb ? APB2OPB_IRQ_STS_OPB1_TX_ACK + : APB2OPB_IRQ_STS_OPB0_TX_ACK; + break; + } + } + + s->regs[reg] = data; +} + +static const struct MemoryRegionOps aspeed_apb2opb_ops = { + .read = fsi_aspeed_apb2opb_read, + .write = fsi_aspeed_apb2opb_write, + .valid.max_access_size = 4, + .valid.min_access_size = 4, + .impl.max_access_size = 4, + .impl.min_access_size = 4, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void fsi_aspeed_apb2opb_init(Object *o) +{ + AspeedAPB2OPBState *s = ASPEED_APB2OPB(o); + int i; + + for (i = 0; i < ASPEED_FSI_NUM; i++) { + object_initialize_child(o, "fsi-master[*]", &s->fsi[i], + TYPE_FSI_MASTER); + } +} + +static void fsi_aspeed_apb2opb_realize(DeviceState *dev, Error **errp) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + AspeedAPB2OPBState *s = ASPEED_APB2OPB(dev); + int i; + + /* + * TODO: The OPBus model initializes the OPB address space in + * the .instance_init handler and this is problematic for test + * device-introspect-test. To avoid a memory corruption and a QEMU + * crash, qbus_init() should be called from realize(). Something to + * improve. Possibly, OPBus could also be removed. + */ + for (i = 0; i < ASPEED_FSI_NUM; i++) { + qbus_init(&s->opb[i], sizeof(s->opb[i]), TYPE_OP_BUS, DEVICE(s), + NULL); + } + + sysbus_init_irq(sbd, &s->irq); + + memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_apb2opb_ops, s, + TYPE_ASPEED_APB2OPB, 0x1000); + sysbus_init_mmio(sbd, &s->iomem); + + for (i = 0; i < ASPEED_FSI_NUM; i++) { + if (!qdev_realize(DEVICE(&s->fsi[i]), BUS(&s->opb[i]), errp)) { + return; + } + + memory_region_add_subregion(&s->opb[i].mr, 0x80000000, + &s->fsi[i].iomem); + + memory_region_add_subregion(&s->opb[i].mr, 0xa0000000, + &s->fsi[i].opb2fsi); + } +} + +static void fsi_aspeed_apb2opb_reset(DeviceState *dev) +{ + AspeedAPB2OPBState *s = ASPEED_APB2OPB(dev); + + memcpy(s->regs, aspeed_apb2opb_reset, ASPEED_APB2OPB_NR_REGS); +} + +static void fsi_aspeed_apb2opb_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->desc = "ASPEED APB2OPB Bridge"; + dc->realize = fsi_aspeed_apb2opb_realize; + dc->reset = fsi_aspeed_apb2opb_reset; +} + +static const TypeInfo aspeed_apb2opb_info = { + .name = TYPE_ASPEED_APB2OPB, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_init = fsi_aspeed_apb2opb_init, + .instance_size = sizeof(AspeedAPB2OPBState), + .class_init = fsi_aspeed_apb2opb_class_init, +}; + +static void aspeed_apb2opb_register_types(void) +{ + type_register_static(&aspeed_apb2opb_info); +} + +type_init(aspeed_apb2opb_register_types); + +static void fsi_opb_init(Object *o) +{ + OPBus *opb = OP_BUS(o); + + memory_region_init(&opb->mr, 0, TYPE_FSI_OPB, UINT32_MAX); + address_space_init(&opb->as, &opb->mr, TYPE_FSI_OPB); +} + +static const TypeInfo opb_info = { + .name = TYPE_OP_BUS, + .parent = TYPE_BUS, + .instance_init = fsi_opb_init, + .instance_size = sizeof(OPBus), +}; + +static void fsi_opb_register_types(void) +{ + type_register_static(&opb_info); +} + +type_init(fsi_opb_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 LED select PMBUS select MAX31785 + select FSI_APB2OPB_ASPEED config MPS2 bool diff --git a/hw/fsi/Kconfig b/hw/fsi/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/hw/fsi/Kconfig +++ b/hw/fsi/Kconfig @@ -XXX,XX +XXX,XX @@ +config FSI_APB2OPB_ASPEED + bool + depends on ASPEED_SOC + select FSI + config FSI bool diff --git a/hw/fsi/meson.build b/hw/fsi/meson.build index XXXXXXX..XXXXXXX 100644 --- a/hw/fsi/meson.build +++ b/hw/fsi/meson.build @@ -1 +1,2 @@ system_ss.add(when: 'CONFIG_FSI', if_true: files('lbus.c','fsi.c','cfam.c','fsi-master.c')) +system_ss.add(when: 'CONFIG_FSI_APB2OPB_ASPEED', if_true: files('aspeed_apb2opb.c')) diff --git a/hw/fsi/trace-events b/hw/fsi/trace-events index XXXXXXX..XXXXXXX 100644 --- a/hw/fsi/trace-events +++ b/hw/fsi/trace-events @@ -XXX,XX +XXX,XX @@ fsi_cfam_unimplemented_write(uint64_t addr, uint32_t size, uint64_t data) "@0x%" fsi_cfam_config_write_noaddr(uint64_t addr, uint32_t size, uint64_t data) "@0x%" PRIx64 " size=%d value=0x%"PRIx64 fsi_master_read(uint64_t addr, uint32_t size) "@0x%" PRIx64 " size=%d" fsi_master_write(uint64_t addr, uint32_t size, uint64_t data) "@0x%" PRIx64 " size=%d value=0x%"PRIx64 +fsi_aspeed_apb2opb_read(uint64_t addr, uint32_t size) "@0x%" PRIx64 " size=%d" +fsi_aspeed_apb2opb_write(uint64_t addr, uint32_t size, uint64_t data) "@0x%" PRIx64 " size=%d value=0x%"PRIx64 -- 2.43.0
From: Ninad Palsule <ninad@linux.ibm.com> This patchset introduces IBM's Flexible Service Interface(FSI). Time for some fun with inter-processor buses. FSI allows a service processor access to the internal buses of a host POWER processor to perform configuration or debugging. FSI has long existed in POWER processes and so comes with some baggage, including how it has been integrated into the ASPEED SoC. Working backwards from the POWER processor, the fundamental pieces of interest for the implementation are: 1. The Common FRU Access Macro (CFAM), an address space containing various "engines" that drive accesses on buses internal and external to the POWER chip. Examples include the SBEFIFO and I2C masters. The engines hang off of an internal Local Bus (LBUS) which is described by the CFAM configuration block. 2. The FSI slave: The slave is the terminal point of the FSI bus for FSI symbols addressed to it. Slaves can be cascaded off of one another. The slave's configuration registers appear in address space of the CFAM to which it is attached. 3. The FSI master: A controller in the platform service processor (e.g. BMC) driving CFAM engine accesses into the POWER chip. At the hardware level FSI is a bit-based protocol supporting synchronous and DMA-driven accesses of engines in a CFAM. 4. The On-Chip Peripheral Bus (OPB): A low-speed bus typically found in POWER processors. This now makes an appearance in the ASPEED SoC due to tight integration of the FSI master IP with the OPB, mainly the existence of an MMIO-mapping of the CFAM address straight onto a sub-region of the OPB address space. 5. An APB-to-OPB bridge enabling access to the OPB from the ARM core in the AST2600. Hardware limitations prevent the OPB from being directly mapped into APB, so all accesses are indirect through the bridge. The implementation appears as following in the qemu device tree: (qemu) info qtree bus: main-system-bus type System ... dev: aspeed.apb2opb, id "" gpio-out "sysbus-irq" 1 mmio 000000001e79b000/0000000000001000 bus: opb.1 type opb dev: fsi.master, id "" bus: fsi.bus.1 type fsi.bus dev: cfam.config, id "" dev: cfam, id "" bus: fsi.lbus.1 type lbus dev: scratchpad, id "" address = 0 (0x0) bus: opb.0 type opb dev: fsi.master, id "" bus: fsi.bus.0 type fsi.bus dev: cfam.config, id "" dev: cfam, id "" bus: fsi.lbus.0 type lbus dev: scratchpad, id "" address = 0 (0x0) The LBUS is modelled to maintain the qdev bus hierarchy and to take advantage of the object model to automatically generate the CFAM configuration block. The configuration block presents engines in the order they are attached to the CFAM's LBUS. Engine implementations should subclass the LBusDevice and set the 'config' member of LBusDeviceClass to match the engine's type. CFAM designs offer a lot of flexibility, for instance it is possible for a CFAM to be simultaneously driven from multiple FSI links. The modeling is not so complete; it's assumed that each CFAM is attached to a single FSI slave (as a consequence the CFAM subclasses the FSI slave). As for FSI, its symbols and wire-protocol are not modelled at all. This is not necessary to get FSI off the ground thanks to the mapping of the CFAM address space onto the OPB address space - the models follow this directly and map the CFAM memory region into the OPB's memory region. Future work includes supporting more advanced accesses that drive the FSI master directly rather than indirectly via the CFAM mapping, which will require implementing the FSI state machine and methods for each of the FSI symbols on the slave. Further down the track we can also look at supporting the bitbanged SoftFSI drivers in Linux by extending the FSI slave model to resolve sequences of GPIO IRQs into FSI symbols, and calling the associated symbol method on the slave to map the access onto the CFAM. Testing: Tested by reading cfam config address 0 on rainier machine type. root@p10bmc:~# pdbg -a getcfam 0x0 p0: 0x0 = 0xc0022d15 Signed-off-by: Andrew Jeffery <andrew@aj.id.au> Signed-off-by: Ninad Palsule <ninad@linux.ibm.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Cédric Le Goater <clg@kaod.org> Signed-off-by: Cédric Le Goater <clg@kaod.org> --- include/hw/arm/aspeed_soc.h | 4 ++++ hw/arm/aspeed_ast2600.c | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+) 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 @@ #include "hw/misc/aspeed_lpc.h" #include "hw/misc/unimp.h" #include "hw/misc/aspeed_peci.h" +#include "hw/fsi/aspeed_apb2opb.h" #include "hw/char/serial.h" #define ASPEED_SPIS_NUM 2 @@ -XXX,XX +XXX,XX @@ struct AspeedSoCState { UnimplementedDeviceState udc; UnimplementedDeviceState sgpiom; UnimplementedDeviceState jtag[ASPEED_JTAG_NUM]; + AspeedAPB2OPBState fsi[2]; }; #define TYPE_ASPEED_SOC "aspeed-soc" @@ -XXX,XX +XXX,XX @@ enum { ASPEED_DEV_SGPIOM, ASPEED_DEV_JTAG0, ASPEED_DEV_JTAG1, + ASPEED_DEV_FSI1, + ASPEED_DEV_FSI2, }; #define ASPEED_SOC_SPI_BOOT_ADDR 0x0 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 const hwaddr aspeed_soc_ast2600_memmap[] = { [ASPEED_DEV_UART12] = 0x1E790600, [ASPEED_DEV_UART13] = 0x1E790700, [ASPEED_DEV_VUART] = 0x1E787000, + [ASPEED_DEV_FSI1] = 0x1E79B000, + [ASPEED_DEV_FSI2] = 0x1E79B100, [ASPEED_DEV_I3C] = 0x1E7A0000, [ASPEED_DEV_SDRAM] = 0x80000000, }; @@ -XXX,XX +XXX,XX @@ static const int aspeed_soc_ast2600_irqmap[] = { [ASPEED_DEV_ETH4] = 33, [ASPEED_DEV_KCS] = 138, /* 138 -> 142 */ [ASPEED_DEV_DP] = 62, + [ASPEED_DEV_FSI1] = 100, + [ASPEED_DEV_FSI2] = 101, [ASPEED_DEV_I3C] = 102, /* 102 -> 107 */ }; @@ -XXX,XX +XXX,XX @@ static void aspeed_soc_ast2600_init(Object *obj) object_initialize_child(obj, "emmc-boot-controller", &s->emmc_boot_controller, TYPE_UNIMPLEMENTED_DEVICE); + + for (i = 0; i < ASPEED_FSI_NUM; i++) { + object_initialize_child(obj, "fsi[*]", &s->fsi[i], TYPE_ASPEED_APB2OPB); + } } /* @@ -XXX,XX +XXX,XX @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) return; } aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->sbc), 0, sc->memmap[ASPEED_DEV_SBC]); + + /* FSI */ + for (i = 0; i < ASPEED_FSI_NUM; i++) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->fsi[i]), errp)) { + return; + } + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->fsi[i]), 0, + sc->memmap[ASPEED_DEV_FSI1 + i]); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->fsi[i]), 0, + aspeed_soc_get_irq(s, ASPEED_DEV_FSI1 + i)); + } } static void aspeed_soc_ast2600_class_init(ObjectClass *oc, void *data) -- 2.43.0
From: Ninad Palsule <ninad@linux.ibm.com> Added basic qtests for FSI model. Signed-off-by: Ninad Palsule <ninad@linux.ibm.com> Acked-by: Thomas Huth <thuth@redhat.com> Signed-off-by: Cédric Le Goater <clg@kaod.org> --- tests/qtest/aspeed-fsi-test.c | 205 ++++++++++++++++++++++++++++++++++ tests/qtest/meson.build | 1 + 2 files changed, 206 insertions(+) create mode 100644 tests/qtest/aspeed-fsi-test.c diff --git a/tests/qtest/aspeed-fsi-test.c b/tests/qtest/aspeed-fsi-test.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tests/qtest/aspeed-fsi-test.c @@ -XXX,XX +XXX,XX @@ +/* + * QTest testcases for IBM's Flexible Service Interface (FSI) + * + * Copyright (c) 2023 IBM Corporation + * + * Authors: + * Ninad Palsule <ninad@linux.ibm.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include <glib/gstdio.h> + +#include "qemu/module.h" +#include "libqtest-single.h" + +/* Registers from ast2600 specifications */ +#define ASPEED_FSI_ENGINER_TRIGGER 0x04 +#define ASPEED_FSI_OPB0_BUS_SELECT 0x10 +#define ASPEED_FSI_OPB1_BUS_SELECT 0x28 +#define ASPEED_FSI_OPB0_RW_DIRECTION 0x14 +#define ASPEED_FSI_OPB1_RW_DIRECTION 0x2c +#define ASPEED_FSI_OPB0_XFER_SIZE 0x18 +#define ASPEED_FSI_OPB1_XFER_SIZE 0x30 +#define ASPEED_FSI_OPB0_BUS_ADDR 0x1c +#define ASPEED_FSI_OPB1_BUS_ADDR 0x34 +#define ASPEED_FSI_INTRRUPT_CLEAR 0x40 +#define ASPEED_FSI_INTRRUPT_STATUS 0x48 +#define ASPEED_FSI_OPB0_BUS_STATUS 0x80 +#define ASPEED_FSI_OPB1_BUS_STATUS 0x8c +#define ASPEED_FSI_OPB0_READ_DATA 0x84 +#define ASPEED_FSI_OPB1_READ_DATA 0x90 + +/* + * FSI Base addresses from the ast2600 specifications. + */ +#define AST2600_OPB_FSI0_BASE_ADDR 0x1e79b000 +#define AST2600_OPB_FSI1_BASE_ADDR 0x1e79b100 + +static uint32_t aspeed_fsi_base_addr; + +static uint32_t aspeed_fsi_readl(QTestState *s, uint32_t reg) +{ + return qtest_readl(s, aspeed_fsi_base_addr + reg); +} + +static void aspeed_fsi_writel(QTestState *s, uint32_t reg, uint32_t val) +{ + qtest_writel(s, aspeed_fsi_base_addr + reg, val); +} + +/* Setup base address and select register */ +static void test_fsi_setup(QTestState *s, uint32_t base_addr) +{ + uint32_t curval; + + aspeed_fsi_base_addr = base_addr; + + /* Set the base select register */ + if (base_addr == AST2600_OPB_FSI0_BASE_ADDR) { + /* Unselect FSI1 */ + aspeed_fsi_writel(s, ASPEED_FSI_OPB1_BUS_SELECT, 0x0); + curval = aspeed_fsi_readl(s, ASPEED_FSI_OPB1_BUS_SELECT); + g_assert_cmpuint(curval, ==, 0x0); + + /* Select FSI0 */ + aspeed_fsi_writel(s, ASPEED_FSI_OPB0_BUS_SELECT, 0x1); + curval = aspeed_fsi_readl(s, ASPEED_FSI_OPB0_BUS_SELECT); + g_assert_cmpuint(curval, ==, 0x1); + } else if (base_addr == AST2600_OPB_FSI1_BASE_ADDR) { + /* Unselect FSI0 */ + aspeed_fsi_writel(s, ASPEED_FSI_OPB0_BUS_SELECT, 0x0); + curval = aspeed_fsi_readl(s, ASPEED_FSI_OPB0_BUS_SELECT); + g_assert_cmpuint(curval, ==, 0x0); + + /* Select FSI1 */ + aspeed_fsi_writel(s, ASPEED_FSI_OPB1_BUS_SELECT, 0x1); + curval = aspeed_fsi_readl(s, ASPEED_FSI_OPB1_BUS_SELECT); + g_assert_cmpuint(curval, ==, 0x1); + } else { + g_assert_not_reached(); + } +} + +static void test_fsi_reg_change(QTestState *s, uint32_t reg, uint32_t newval) +{ + uint32_t base; + uint32_t curval; + + base = aspeed_fsi_readl(s, reg); + aspeed_fsi_writel(s, reg, newval); + curval = aspeed_fsi_readl(s, reg); + g_assert_cmpuint(curval, ==, newval); + aspeed_fsi_writel(s, reg, base); + curval = aspeed_fsi_readl(s, reg); + g_assert_cmpuint(curval, ==, base); +} + +static void test_fsi0_master_regs(const void *data) +{ + QTestState *s = (QTestState *)data; + + test_fsi_setup(s, AST2600_OPB_FSI0_BASE_ADDR); + + test_fsi_reg_change(s, ASPEED_FSI_OPB0_RW_DIRECTION, 0xF3F4F514); + test_fsi_reg_change(s, ASPEED_FSI_OPB0_XFER_SIZE, 0xF3F4F518); + test_fsi_reg_change(s, ASPEED_FSI_OPB0_BUS_ADDR, 0xF3F4F51c); + test_fsi_reg_change(s, ASPEED_FSI_INTRRUPT_CLEAR, 0xF3F4F540); + test_fsi_reg_change(s, ASPEED_FSI_INTRRUPT_STATUS, 0xF3F4F548); + test_fsi_reg_change(s, ASPEED_FSI_OPB0_BUS_STATUS, 0xF3F4F580); + test_fsi_reg_change(s, ASPEED_FSI_OPB0_READ_DATA, 0xF3F4F584); +} + +static void test_fsi1_master_regs(const void *data) +{ + QTestState *s = (QTestState *)data; + + test_fsi_setup(s, AST2600_OPB_FSI1_BASE_ADDR); + + test_fsi_reg_change(s, ASPEED_FSI_OPB1_RW_DIRECTION, 0xF3F4F514); + test_fsi_reg_change(s, ASPEED_FSI_OPB1_XFER_SIZE, 0xF3F4F518); + test_fsi_reg_change(s, ASPEED_FSI_OPB1_BUS_ADDR, 0xF3F4F51c); + test_fsi_reg_change(s, ASPEED_FSI_INTRRUPT_CLEAR, 0xF3F4F540); + test_fsi_reg_change(s, ASPEED_FSI_INTRRUPT_STATUS, 0xF3F4F548); + test_fsi_reg_change(s, ASPEED_FSI_OPB1_BUS_STATUS, 0xF3F4F580); + test_fsi_reg_change(s, ASPEED_FSI_OPB1_READ_DATA, 0xF3F4F584); +} + +static void test_fsi0_getcfam_addr0(const void *data) +{ + QTestState *s = (QTestState *)data; + uint32_t curval; + + test_fsi_setup(s, AST2600_OPB_FSI0_BASE_ADDR); + + /* Master access direction read */ + aspeed_fsi_writel(s, ASPEED_FSI_OPB0_RW_DIRECTION, 0x1); + /* word */ + aspeed_fsi_writel(s, ASPEED_FSI_OPB0_XFER_SIZE, 0x3); + /* Address */ + aspeed_fsi_writel(s, ASPEED_FSI_OPB0_BUS_ADDR, 0xa0000000); + aspeed_fsi_writel(s, ASPEED_FSI_INTRRUPT_CLEAR, 0x1); + aspeed_fsi_writel(s, ASPEED_FSI_ENGINER_TRIGGER, 0x1); + + curval = aspeed_fsi_readl(s, ASPEED_FSI_INTRRUPT_STATUS); + g_assert_cmpuint(curval, ==, 0x10000); + curval = aspeed_fsi_readl(s, ASPEED_FSI_OPB0_BUS_STATUS); + g_assert_cmpuint(curval, ==, 0x0); + curval = aspeed_fsi_readl(s, ASPEED_FSI_OPB0_READ_DATA); + g_assert_cmpuint(curval, ==, 0x152d02c0); +} + +static void test_fsi1_getcfam_addr0(const void *data) +{ + QTestState *s = (QTestState *)data; + uint32_t curval; + + test_fsi_setup(s, AST2600_OPB_FSI1_BASE_ADDR); + + /* Master access direction read */ + aspeed_fsi_writel(s, ASPEED_FSI_OPB1_RW_DIRECTION, 0x1); + + aspeed_fsi_writel(s, ASPEED_FSI_OPB1_XFER_SIZE, 0x3); + aspeed_fsi_writel(s, ASPEED_FSI_OPB1_BUS_ADDR, 0xa0000000); + aspeed_fsi_writel(s, ASPEED_FSI_INTRRUPT_CLEAR, 0x1); + aspeed_fsi_writel(s, ASPEED_FSI_ENGINER_TRIGGER, 0x1); + + curval = aspeed_fsi_readl(s, ASPEED_FSI_INTRRUPT_STATUS); + g_assert_cmpuint(curval, ==, 0x20000); + curval = aspeed_fsi_readl(s, ASPEED_FSI_OPB1_BUS_STATUS); + g_assert_cmpuint(curval, ==, 0x0); + curval = aspeed_fsi_readl(s, ASPEED_FSI_OPB1_READ_DATA); + g_assert_cmpuint(curval, ==, 0x152d02c0); +} + +int main(int argc, char **argv) +{ + int ret = -1; + QTestState *s; + + g_test_init(&argc, &argv, NULL); + + s = qtest_init("-machine ast2600-evb "); + + /* Tests for OPB/FSI0 */ + qtest_add_data_func("/aspeed-fsi-test/test_fsi0_master_regs", s, + test_fsi0_master_regs); + + qtest_add_data_func("/aspeed-fsi-test/test_fsi0_getcfam_addr0", s, + test_fsi0_getcfam_addr0); + + /* Tests for OPB/FSI1 */ + qtest_add_data_func("/aspeed-fsi-test/test_fsi1_master_regs", s, + test_fsi1_master_regs); + + qtest_add_data_func("/aspeed-fsi-test/test_fsi1_getcfam_addr0", s, + test_fsi1_getcfam_addr0); + + ret = g_test_run(); + qtest_quit(s); + + return ret; +} 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_arm = \ (config_all_devices.has_key('CONFIG_VEXPRESS') ? ['test-arm-mptimer'] : []) + \ (config_all_devices.has_key('CONFIG_MICROBIT') ? ['microbit-test'] : []) + \ (config_all_devices.has_key('CONFIG_STM32L4X5_SOC') ? qtests_stm32l4x5 : []) + \ + (config_all_devices.has_key('CONFIG_FSI_APB2OPB_ASPEED') ? ['aspeed-fsi-test'] : []) + \ ['arm-cpu-features', 'boot-serial-test'] -- 2.43.0
From: Ninad Palsule <ninad@linux.ibm.com> Documentation for IBM FSI model. Signed-off-by: Ninad Palsule <ninad@linux.ibm.com> Reviewed-by: Cédric Le Goater <clg@kaod.org> [ clg : - Removed source file list - Fixed aspeed machine reference ] Signed-off-by: Cédric Le Goater <clg@kaod.org> --- docs/specs/fsi.rst | 122 +++++++++++++++++++++++++++++++++++++++++++ docs/specs/index.rst | 1 + 2 files changed, 123 insertions(+) create mode 100644 docs/specs/fsi.rst diff --git a/docs/specs/fsi.rst b/docs/specs/fsi.rst new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/docs/specs/fsi.rst @@ -XXX,XX +XXX,XX @@ +====================================== +IBM's Flexible Service Interface (FSI) +====================================== + +The QEMU FSI emulation implements hardware interfaces between ASPEED SOC, FSI +master/slave and the end engine. + +FSI is a point-to-point two wire interface which is capable of supporting +distances of up to 4 meters. FSI interfaces have been used successfully for +many years in IBM servers to attach IBM Flexible Support Processors(FSP) to +CPUs and IBM ASICs. + +FSI allows a service processor access to the internal buses of a host POWER +processor to perform configuration or debugging. FSI has long existed in POWER +processes and so comes with some baggage, including how it has been integrated +into the ASPEED SoC. + +Working backwards from the POWER processor, the fundamental pieces of interest +for the implementation are: (see the `FSI specification`_ for more details) + +1. The Common FRU Access Macro (CFAM), an address space containing various + "engines" that drive accesses on buses internal and external to the POWER + chip. Examples include the SBEFIFO and I2C masters. The engines hang off of + an internal Local Bus (LBUS) which is described by the CFAM configuration + block. + +2. The FSI slave: The slave is the terminal point of the FSI bus for FSI + symbols addressed to it. Slaves can be cascaded off of one another. The + slave's configuration registers appear in address space of the CFAM to + which it is attached. + +3. The FSI master: A controller in the platform service processor (e.g. BMC) + driving CFAM engine accesses into the POWER chip. At the hardware level + FSI is a bit-based protocol supporting synchronous and DMA-driven accesses + of engines in a CFAM. + +4. The On-Chip Peripheral Bus (OPB): A low-speed bus typically found in POWER + processors. This now makes an appearance in the ASPEED SoC due to tight + integration of the FSI master IP with the OPB, mainly the existence of an + MMIO-mapping of the CFAM address straight onto a sub-region of the OPB + address space. + +5. An APB-to-OPB bridge enabling access to the OPB from the ARM core in the + AST2600. Hardware limitations prevent the OPB from being directly mapped + into APB, so all accesses are indirect through the bridge. + +The LBUS is modelled to maintain the qdev bus hierarchy and to take advantages +of the object model to automatically generate the CFAM configuration block. +The configuration block presents engines in the order they are attached to the +CFAM's LBUS. Engine implementations should subclass the LBusDevice and set the +'config' member of LBusDeviceClass to match the engine's type. + +CFAM designs offer a lot of flexibility, for instance it is possible for a +CFAM to be simultaneously driven from multiple FSI links. The modeling is not +so complete; it's assumed that each CFAM is attached to a single FSI slave (as +a consequence the CFAM subclasses the FSI slave). + +As for FSI, its symbols and wire-protocol are not modelled at all. This is not +necessary to get FSI off the ground thanks to the mapping of the CFAM address +space onto the OPB address space - the models follow this directly and map the +CFAM memory region into the OPB's memory region. + +The following commands start the ``rainier-bmc`` machine with built-in FSI +model. There are no model specific arguments. Please check this document to +learn more about Aspeed ``rainier-bmc`` machine: (:doc:`../../system/arm/aspeed`) + +.. code-block:: console + + qemu-system-arm -M rainier-bmc -nographic \ + -kernel fitImage-linux.bin \ + -dtb aspeed-bmc-ibm-rainier.dtb \ + -initrd obmc-phosphor-initramfs.rootfs.cpio.xz \ + -drive file=obmc-phosphor-image.rootfs.wic.qcow2,if=sd,index=2 \ + -append "rootwait console=ttyS4,115200n8 root=PARTLABEL=rofs-a" + +The implementation appears as following in the qemu device tree: + +.. code-block:: console + + (qemu) info qtree + bus: main-system-bus + type System + ... + dev: aspeed.apb2opb, id "" + gpio-out "sysbus-irq" 1 + mmio 000000001e79b000/0000000000001000 + bus: opb.1 + type opb + dev: fsi.master, id "" + bus: fsi.bus.1 + type fsi.bus + dev: cfam.config, id "" + dev: cfam, id "" + bus: lbus.1 + type lbus + dev: scratchpad, id "" + address = 0 (0x0) + bus: opb.0 + type opb + dev: fsi.master, id "" + bus: fsi.bus.0 + type fsi.bus + dev: cfam.config, id "" + dev: cfam, id "" + bus: lbus.0 + type lbus + dev: scratchpad, id "" + address = 0 (0x0) + +pdbg is a simple application to allow debugging of the host POWER processors +from the BMC. (see the `pdbg source repository`_ for more details) + +.. code-block:: console + + root@p10bmc:~# pdbg -a getcfam 0x0 + p0: 0x0 = 0xc0022d15 + +.. _FSI specification: + https://openpowerfoundation.org/specifications/fsi/ + +.. _pdbg source repository: + https://github.com/open-power/pdbg diff --git a/docs/specs/index.rst b/docs/specs/index.rst index XXXXXXX..XXXXXXX 100644 --- a/docs/specs/index.rst +++ b/docs/specs/index.rst @@ -XXX,XX +XXX,XX @@ guest hardware that is specific to QEMU. acpi_erst sev-guest-firmware fw_cfg + fsi vmw_pvscsi-spec edu ivshmem-spec -- 2.43.0
From: Ninad Palsule <ninad@linux.ibm.com> Added maintainer for IBM FSI model Signed-off-by: Ninad Palsule <ninad@linux.ibm.com> Reviewed-by: Cédric Le Goater <clg@kaod.org> Signed-off-by: Cédric Le Goater <clg@kaod.org> --- MAINTAINERS | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index XXXXXXX..XXXXXXX 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -XXX,XX +XXX,XX @@ F: tests/qtest/adm1272-test.c F: tests/qtest/max34451-test.c F: tests/qtest/isl_pmbus_vr-test.c +FSI +M: Ninad Palsule <ninad@linux.ibm.com> +R: Cédric Le Goater <clg@kaod.org> +S: Maintained +F: hw/fsi/* +F: include/hw/fsi/* +F: docs/specs/fsi.rst +F: tests/qtest/fsi-test.c + Firmware schema specifications M: Philippe Mathieu-Daudé <philmd@linaro.org> R: Daniel P. Berrange <berrange@redhat.com> -- 2.43.0
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