From d815649c512fc785508315ead66a43385cf55bfb Mon Sep 17 00:00:00 2001 From: Philippe Mathieu-Daudé Date: Thu, 25 Jan 2024 06:55:43 +0100 Subject: hw/arm/aspeed: Introduce aspeed_soc_cpu_type() helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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é Reviewed-by: Cédric Le Goater Reviewed-by: Richard Henderson Reviewed-by: Gavin Shan Signed-off-by: Cédric Le Goater --- include/hw/arm/aspeed_soc.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/hw') diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h index cb832bc1ee..a060a59918 100644 --- a/include/hw/arm/aspeed_soc.h +++ b/include/hw/arm/aspeed_soc.h @@ -143,6 +143,7 @@ struct AspeedSoCClass { qemu_irq (*get_irq)(AspeedSoCState *s, int dev); }; +const char *aspeed_soc_cpu_type(AspeedSoCClass *sc); enum { ASPEED_DEV_SPI_BOOT, -- cgit 1.4.1 From dc13909ed03c05275deb32512e9d8f8e34d79c3b Mon Sep 17 00:00:00 2001 From: Philippe Mathieu-Daudé Date: Thu, 25 Jan 2024 06:55:44 +0100 Subject: hw/arm/aspeed: Check for CPU types in machine_run_board_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Reviewed-by: Richard Henderson Reviewed-by: Gavin Shan Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Cédric Le Goater --- 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 ++++- include/hw/arm/aspeed_soc.h | 3 ++- 6 files changed, 27 insertions(+), 6 deletions(-) (limited to 'include/hw') diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index d2d490a6d1..fc8355cdce 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -1149,6 +1149,7 @@ 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 dca601a3f9..c3b5116a6a 100644 --- a/hw/arm/aspeed_ast10x0.c +++ b/hw/arm/aspeed_ast10x0.c @@ -417,13 +417,17 @@ 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 3baf95916d..8829561bb6 100644 --- a/hw/arm/aspeed_ast2400.c +++ b/hw/arm/aspeed_ast2400.c @@ -503,6 +503,10 @@ 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); @@ -511,7 +515,7 @@ 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; @@ -527,6 +531,10 @@ 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); @@ -535,7 +543,7 @@ 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 b264433cf0..46baba0e41 100644 --- a/hw/arm/aspeed_ast2600.c +++ b/hw/arm/aspeed_ast2600.c @@ -629,13 +629,17 @@ 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 36ca189ce9..123a0c432c 100644 --- a/hw/arm/aspeed_soc_common.c +++ b/hw/arm/aspeed_soc_common.c @@ -20,7 +20,10 @@ 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) diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h index a060a59918..0db5a41e71 100644 --- a/include/hw/arm/aspeed_soc.h +++ b/include/hw/arm/aspeed_soc.h @@ -128,7 +128,8 @@ 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; -- cgit 1.4.1 From 99f0c046f46dae7a7ede7d298de429c3596e76e6 Mon Sep 17 00:00:00 2001 From: Ninad Palsule Date: Fri, 26 Jan 2024 04:49:46 -0600 Subject: hw/fsi: Introduce IBM's Local bus MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Signed-off-by: Ninad Palsule Reviewed-by: Cédric Le Goater [ 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 --- hw/Kconfig | 1 + hw/fsi/Kconfig | 2 ++ hw/fsi/lbus.c | 43 +++++++++++++++++++++++++++++++++++++++++++ hw/fsi/meson.build | 1 + hw/fsi/trace-events | 0 hw/fsi/trace.h | 1 + hw/meson.build | 1 + include/hw/fsi/lbus.h | 32 ++++++++++++++++++++++++++++++++ meson.build | 1 + 9 files changed, 82 insertions(+) create mode 100644 hw/fsi/Kconfig create mode 100644 hw/fsi/lbus.c create mode 100644 hw/fsi/meson.build create mode 100644 hw/fsi/trace-events create mode 100644 hw/fsi/trace.h create mode 100644 include/hw/fsi/lbus.h (limited to 'include/hw') diff --git a/hw/Kconfig b/hw/Kconfig index 9ca7b38c31..2c00936c28 100644 --- a/hw/Kconfig +++ b/hw/Kconfig @@ -9,6 +9,7 @@ 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 0000000000..9c34a418d7 --- /dev/null +++ b/hw/fsi/Kconfig @@ -0,0 +1,2 @@ +config FSI + bool diff --git a/hw/fsi/lbus.c b/hw/fsi/lbus.c new file mode 100644 index 0000000000..44d2319087 --- /dev/null +++ b/hw/fsi/lbus.c @@ -0,0 +1,43 @@ +/* + * 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/fsi/meson.build b/hw/fsi/meson.build new file mode 100644 index 0000000000..93ba19dd04 --- /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 0000000000..e69de29bb2 diff --git a/hw/fsi/trace.h b/hw/fsi/trace.h new file mode 100644 index 0000000000..ee67c7fb04 --- /dev/null +++ b/hw/fsi/trace.h @@ -0,0 +1 @@ +#include "trace/trace-hw_fsi.h" diff --git a/hw/meson.build b/hw/meson.build index f01fac4617..463d702683 100644 --- a/hw/meson.build +++ b/hw/meson.build @@ -44,6 +44,7 @@ subdir('virtio') subdir('watchdog') subdir('xen') subdir('xenpv') +subdir('fsi') subdir('alpha') subdir('arm') diff --git a/include/hw/fsi/lbus.h b/include/hw/fsi/lbus.h new file mode 100644 index 0000000000..e8a22e22a8 --- /dev/null +++ b/include/hw/fsi/lbus.h @@ -0,0 +1,32 @@ +/* + * 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/meson.build b/meson.build index 5ffa8c9716..b5d6dc94a8 100644 --- a/meson.build +++ b/meson.build @@ -3289,6 +3289,7 @@ if have_system 'hw/char', 'hw/display', 'hw/dma', + 'hw/fsi', 'hw/hyperv', 'hw/i2c', 'hw/i386', -- cgit 1.4.1 From ca782334cb821a84d701133a6421516d264cf0d3 Mon Sep 17 00:00:00 2001 From: Ninad Palsule Date: Fri, 26 Jan 2024 04:49:47 -0600 Subject: hw/fsi: Introduce IBM's scratchpad device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Signed-off-by: Ninad Palsule Reviewed-by: Cédric Le Goater [ clg: - moved object FSIScratchPad under FSICFAMState - moved FSIScratchPad code under cfam.c ] Signed-off-by: Cédric Le Goater --- hw/fsi/lbus.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++-- hw/fsi/trace-events | 2 ++ include/hw/fsi/lbus.h | 11 ++++++++ 3 files changed, 89 insertions(+), 2 deletions(-) (limited to 'include/hw') diff --git a/hw/fsi/lbus.c b/hw/fsi/lbus.c index 44d2319087..20495f42fd 100644 --- a/hw/fsi/lbus.c +++ b/hw/fsi/lbus.c @@ -8,11 +8,12 @@ #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); @@ -34,10 +35,83 @@ 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 e69de29bb2..c5753e2791 100644 --- a/hw/fsi/trace-events +++ b/hw/fsi/trace-events @@ -0,0 +1,2 @@ +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 diff --git a/include/hw/fsi/lbus.h b/include/hw/fsi/lbus.h index e8a22e22a8..558268c013 100644 --- a/include/hw/fsi/lbus.h +++ b/include/hw/fsi/lbus.h @@ -29,4 +29,15 @@ 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 */ -- cgit 1.4.1 From f4de3ca160c897ed3157ab8f0ad33ed93fe4bfe0 Mon Sep 17 00:00:00 2001 From: Ninad Palsule Date: Fri, 26 Jan 2024 04:49:48 -0600 Subject: hw/fsi: Introduce IBM's FSI Bus MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Signed-off-by: Ninad Palsule Reviewed-by: Cédric Le Goater [ 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 --- hw/fsi/fsi.c | 22 ++++++++++++++++++++++ hw/fsi/meson.build | 2 +- include/hw/fsi/fsi.h | 19 +++++++++++++++++++ 3 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 hw/fsi/fsi.c create mode 100644 include/hw/fsi/fsi.h (limited to 'include/hw') diff --git a/hw/fsi/fsi.c b/hw/fsi/fsi.c new file mode 100644 index 0000000000..60cb03f7a2 --- /dev/null +++ b/hw/fsi/fsi.c @@ -0,0 +1,22 @@ +/* + * 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 93ba19dd04..574f5f9289 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')) diff --git a/include/hw/fsi/fsi.h b/include/hw/fsi/fsi.h new file mode 100644 index 0000000000..50e8f5c888 --- /dev/null +++ b/include/hw/fsi/fsi.h @@ -0,0 +1,19 @@ +/* + * 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 */ -- cgit 1.4.1 From 6a2897bb5f28944997a0c8410b6d2ee162b9ae98 Mon Sep 17 00:00:00 2001 From: Ninad Palsule Date: Fri, 26 Jan 2024 04:49:49 -0600 Subject: hw/fsi: Introduce IBM's fsi-slave model MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Signed-off-by: Ninad Palsule Reviewed-by: Cédric Le Goater Signed-off-by: Cédric Le Goater --- hw/fsi/fsi.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++-- hw/fsi/trace-events | 2 ++ include/hw/fsi/fsi.h | 18 +++++++++++ 3 files changed, 102 insertions(+), 2 deletions(-) (limited to 'include/hw') diff --git a/hw/fsi/fsi.c b/hw/fsi/fsi.c index 60cb03f7a2..9a5f4e616f 100644 --- a/hw/fsi/fsi.c +++ b/hw/fsi/fsi.c @@ -5,18 +5,98 @@ * 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 c5753e2791..8f29adb7df 100644 --- a/hw/fsi/trace-events +++ b/hw/fsi/trace-events @@ -1,2 +1,4 @@ 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 diff --git a/include/hw/fsi/fsi.h b/include/hw/fsi/fsi.h index 50e8f5c888..e00f6ef078 100644 --- a/include/hw/fsi/fsi.h +++ b/include/hw/fsi/fsi.h @@ -7,7 +7,13 @@ #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) @@ -16,4 +22,16 @@ 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 */ -- cgit 1.4.1 From f32f8e4d20b00e9b1fc1fcdd61050312d9ec75f6 Mon Sep 17 00:00:00 2001 From: Ninad Palsule Date: Fri, 26 Jan 2024 04:49:50 -0600 Subject: hw/fsi: Introduce IBM's cfam MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Signed-off-by: Ninad Palsule Reviewed-by: Cédric Le Goater [ 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 --- hw/fsi/cfam.c | 168 ++++++++++++++++++++++++++++++++++++++++++++++++++ hw/fsi/meson.build | 2 +- hw/fsi/trace-events | 5 ++ include/hw/fsi/cfam.h | 34 ++++++++++ 4 files changed, 208 insertions(+), 1 deletion(-) create mode 100644 hw/fsi/cfam.c create mode 100644 include/hw/fsi/cfam.h (limited to 'include/hw') diff --git a/hw/fsi/cfam.c b/hw/fsi/cfam.c new file mode 100644 index 0000000000..c62f0f78de --- /dev/null +++ b/hw/fsi/cfam.c @@ -0,0 +1,168 @@ +/* + * 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 574f5f9289..96403d4efc 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 8f29adb7df..b542956fb3 100644 --- a/hw/fsi/trace-events +++ b/hw/fsi/trace-events @@ -2,3 +2,8 @@ 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 diff --git a/include/hw/fsi/cfam.h b/include/hw/fsi/cfam.h new file mode 100644 index 0000000000..7abc3b287b --- /dev/null +++ b/include/hw/fsi/cfam.h @@ -0,0 +1,34 @@ +/* + * 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 */ -- cgit 1.4.1 From ca0331073722d27b033ca43a827f04fdf2a2bcce Mon Sep 17 00:00:00 2001 From: Ninad Palsule Date: Fri, 26 Jan 2024 04:49:51 -0600 Subject: hw/fsi: Introduce IBM's FSI master MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Signed-off-by: Ninad Palsule Reviewed-by: Cédric Le Goater [ clg: - move FSICFAMState object under FSIMasterState - introduced fsi_master_init() - reworked fsi_master_realize() - dropped FSIBus definition ] Signed-off-by: Cédric Le Goater --- hw/fsi/fsi-master.c | 170 ++++++++++++++++++++++++++++++++++++++++++++ hw/fsi/meson.build | 2 +- hw/fsi/trace-events | 2 + include/hw/fsi/fsi-master.h | 32 +++++++++ 4 files changed, 205 insertions(+), 1 deletion(-) create mode 100644 hw/fsi/fsi-master.c create mode 100644 include/hw/fsi/fsi-master.h (limited to 'include/hw') diff --git a/hw/fsi/fsi-master.c b/hw/fsi/fsi-master.c new file mode 100644 index 0000000000..a5f0598c98 --- /dev/null +++ b/hw/fsi/fsi-master.c @@ -0,0 +1,170 @@ +/* + * 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 96403d4efc..7803b3afd1 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 b542956fb3..bf417b6dc3 100644 --- a/hw/fsi/trace-events +++ b/hw/fsi/trace-events @@ -7,3 +7,5 @@ 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 diff --git a/include/hw/fsi/fsi-master.h b/include/hw/fsi/fsi-master.h new file mode 100644 index 0000000000..68e5f56db2 --- /dev/null +++ b/include/hw/fsi/fsi-master.h @@ -0,0 +1,32 @@ +/* + * 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 */ -- cgit 1.4.1 From eb04c35da2c063515667e513028d64e27178365f Mon Sep 17 00:00:00 2001 From: Ninad Palsule Date: Fri, 26 Jan 2024 04:49:52 -0600 Subject: hw/fsi: Aspeed APB2OPB & On-chip peripheral bus MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Signed-off-by: Ninad Palsule Reviewed-by: Cédric Le Goater [ 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 - introduced fsi_aspeed_apb2opb_rw to fix endianness issue ] Signed-off-by: Cédric Le Goater --- hw/arm/Kconfig | 1 + hw/fsi/Kconfig | 5 + hw/fsi/aspeed_apb2opb.c | 367 ++++++++++++++++++++++++++++++++++++++++ hw/fsi/meson.build | 1 + hw/fsi/trace-events | 2 + include/hw/fsi/aspeed_apb2opb.h | 46 +++++ 6 files changed, 422 insertions(+) create mode 100644 hw/fsi/aspeed_apb2opb.c create mode 100644 include/hw/fsi/aspeed_apb2opb.h (limited to 'include/hw') diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index f927878152..db08a00a45 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -580,6 +580,7 @@ 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 9c34a418d7..9cee657a0f 100644 --- a/hw/fsi/Kconfig +++ b/hw/fsi/Kconfig @@ -1,2 +1,7 @@ +config FSI_APB2OPB_ASPEED + bool + depends on ASPEED_SOC + select FSI + config FSI bool diff --git a/hw/fsi/aspeed_apb2opb.c b/hw/fsi/aspeed_apb2opb.c new file mode 100644 index 0000000000..ea50718b6a --- /dev/null +++ b/hw/fsi/aspeed_apb2opb.c @@ -0,0 +1,367 @@ +/* + * 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 MemTxResult fsi_aspeed_apb2opb_rw(AddressSpace *as, hwaddr addr, + MemTxAttrs attrs, uint32_t *data, + uint32_t size, bool is_write) +{ + MemTxResult res; + + if (is_write) { + switch (size) { + case 4: + address_space_stl_le(as, addr, *data, attrs, &res); + break; + case 2: + address_space_stw_le(as, addr, *data, attrs, &res); + break; + case 1: + address_space_stb(as, addr, *data, attrs, &res); + break; + default: + g_assert_not_reached(); + } + } else { + switch (size) { + case 4: + *data = address_space_ldl_le(as, addr, attrs, &res); + break; + case 2: + *data = address_space_lduw_le(as, addr, attrs, &res); + break; + case 1: + *data = address_space_ldub(as, addr, attrs, &res); + break; + default: + g_assert_not_reached(); + } + } + return res; +} + +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 = fsi_aspeed_apb2opb_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/fsi/meson.build b/hw/fsi/meson.build index 7803b3afd1..a18a076552 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 bf417b6dc3..9e286d08d3 100644 --- a/hw/fsi/trace-events +++ b/hw/fsi/trace-events @@ -9,3 +9,5 @@ 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 diff --git a/include/hw/fsi/aspeed_apb2opb.h b/include/hw/fsi/aspeed_apb2opb.h new file mode 100644 index 0000000000..f6a2387abf --- /dev/null +++ b/include/hw/fsi/aspeed_apb2opb.h @@ -0,0 +1,46 @@ +/* + * 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 */ -- cgit 1.4.1 From 3fd941f3f10da2d3c08cac4f183b76b2388b7c53 Mon Sep 17 00:00:00 2001 From: Ninad Palsule Date: Fri, 26 Jan 2024 04:49:53 -0600 Subject: hw/arm: Hook up FSI module in AST2600 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Signed-off-by: Ninad Palsule Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Cédric Le Goater Signed-off-by: Cédric Le Goater --- hw/arm/aspeed_ast2600.c | 19 +++++++++++++++++++ include/hw/arm/aspeed_soc.h | 4 ++++ 2 files changed, 23 insertions(+) (limited to 'include/hw') diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c index 46baba0e41..4ee32ea99d 100644 --- a/hw/arm/aspeed_ast2600.c +++ b/hw/arm/aspeed_ast2600.c @@ -76,6 +76,8 @@ 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, }; @@ -133,6 +135,8 @@ 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 */ }; @@ -266,6 +270,10 @@ 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); + } } /* @@ -625,6 +633,17 @@ 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) diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h index 0db5a41e71..9d0af84a8c 100644 --- a/include/hw/arm/aspeed_soc.h +++ b/include/hw/arm/aspeed_soc.h @@ -36,6 +36,7 @@ #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 @@ -90,6 +91,7 @@ struct AspeedSoCState { UnimplementedDeviceState udc; UnimplementedDeviceState sgpiom; UnimplementedDeviceState jtag[ASPEED_JTAG_NUM]; + AspeedAPB2OPBState fsi[2]; }; #define TYPE_ASPEED_SOC "aspeed-soc" @@ -216,6 +218,8 @@ enum { ASPEED_DEV_SGPIOM, ASPEED_DEV_JTAG0, ASPEED_DEV_JTAG1, + ASPEED_DEV_FSI1, + ASPEED_DEV_FSI2, }; #define ASPEED_SOC_SPI_BOOT_ADDR 0x0 -- cgit 1.4.1