The default methods are overriden to add the activation/deactivation of the memory regions according to the gating state: Regions are enabled only when powered and clocked. As powering-up triggers a reset call, memory regions should be reset in specialized sysbus devices.
Signed-off-by: Damien Hedde <damien.he...@greensocs.com> --- include/hw/sysbus.h | 3 +++ hw/core/sysbus.c | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/include/hw/sysbus.h b/include/hw/sysbus.h index 0b59a3b8d6..e17165e78f 100644 --- a/include/hw/sysbus.h +++ b/include/hw/sysbus.h @@ -59,6 +59,9 @@ typedef struct SysBusDeviceClass { */ char *(*explicit_ofw_unit_address)(const SysBusDevice *dev); void (*connect_irq_notifier)(SysBusDevice *dev, qemu_irq irq); + + DeviceGatingUpdate parent_power_update; + DeviceGatingUpdate parent_clock_update; } SysBusDeviceClass; struct SysBusDevice { diff --git a/hw/core/sysbus.c b/hw/core/sysbus.c index 3c8e53b188..4a2dfbe907 100644 --- a/hw/core/sysbus.c +++ b/hw/core/sysbus.c @@ -325,6 +325,39 @@ MemoryRegion *sysbus_address_space(SysBusDevice *dev) return get_system_memory(); } +/* + * Action take on power or clock update. + */ +static void sysbus_device_gating_update(DeviceState *dev) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + int i; + + for (i = 0;; i++) { + MemoryRegion *mr = sysbus_mmio_get_region(sbd, i); + if (!mr) { + break; + } + memory_region_set_enabled(mr, dev->powered && dev->clocked); + } +} + +/* + * Action take on power update. + * + * Call parent method before doing local action. + * So that we override any action taken in parent method (eg if reset + * is called due to leaving OFF state) + */ +static void sysbus_device_power_update(DeviceState *dev) +{ + SysBusDeviceClass *sbdk = SYS_BUS_DEVICE_GET_CLASS(dev); + + sbdk->parent_power_update(dev); + + sysbus_device_gating_update(dev); +} + static void sysbus_device_class_init(ObjectClass *klass, void *data) { DeviceClass *k = DEVICE_CLASS(klass); @@ -341,6 +374,12 @@ static void sysbus_device_class_init(ObjectClass *klass, void *data) * subclass needs to override it and set user_creatable=true. */ k->user_creatable = false; + + SysBusDeviceClass *sbdk = SYS_BUS_DEVICE_CLASS(klass); + device_class_set_parent_power_update(k, + sysbus_device_power_update, &sbdk->parent_power_update); + device_class_set_parent_clock_update(k, + sysbus_device_gating_update, &sbdk->parent_clock_update); } static const TypeInfo sysbus_device_type_info = { -- 2.18.0