this power chip manage on/off/wakeup/suspend power state transition, when state changed, it will trigger all callbacks embedded in all device object. This just like power action in real world.
Signed-off-by: liguang <[email protected]> --- Makefile.objs | 1 + power.c | 133 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ power.h | 41 +++++++++++++++++ 3 files changed, 175 insertions(+), 0 deletions(-) create mode 100644 power.c create mode 100644 power.h diff --git a/Makefile.objs b/Makefile.objs index a68cdac..a895e7d 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -73,6 +73,7 @@ common-obj-y += bt-host.o bt-vhci.o common-obj-y += dma-helpers.o common-obj-y += vl.o +common-obj-y += power.o common-obj-$(CONFIG_SLIRP) += slirp/ diff --git a/power.c b/power.c new file mode 100644 index 0000000..ce9cdab --- /dev/null +++ b/power.c @@ -0,0 +1,133 @@ +#include "power.h" +#include "qemu/main-loop.h" + + +PowerChip pmc; + +void power_management_set(PowerState ps) +{ + switch (ps) { + case POWER_OFF: + case POWER_ON: + case POWER_SUSPEND: + case POWER_WAKEUP: + pmc.power_state = ps; + break; + case POWER_RESET: + pmc.power_state = ps | POWER_OFF; + break; + default: + pmc.power_state = POWER_IDLE; + break; + } +} + +static void power_management_on(DeviceState *dev) +{ + qbus_reset_all_fn(sysbus_get_default()); +} + +static void power_management_off(DeviceState *dev) +{ + qbus_power_off(sysbus_get_default()); +} + +static void power_management_suspend(DeviceState *dev) +{ + qbus_power_suspend(sysbus_get_default()); +} + +static void power_management_wakeup(DeviceState *dev) +{ + qbus_power_wakeup(sysbus_get_default()); +} + +WakeupReason power_management_wakeup_reason(void) +{ + return pmc.wakeup_reason; +} + +void power_management_wakeup_reason_set(WakeupReason wr) +{ + pmc.wakeup_reason = wr; +} + +void power_management_wakeup_capability(WakeupReason wr, bool ok) +{ + switch (wr) { + case QEMU_WAKEUP_REASON_RTC: + case QEMU_WAKEUP_REASON_PMTIMER: + if (ok) { + pmc.wakeup_capability |= 1 << wr; + } else { + pmc.wakeup_capability &= ~(1 << wr); + } + default: + break; + } +} + +PowerState power_management(void) +{ + int reset = pmc.power_state & 0x80; + + switch (pmc.power_state & 0xf) { + case POWER_ON: + power_management_on(NULL); + break; + case POWER_OFF: + power_management_off(NULL); + if (reset) { + pmc.power_state = POWER_ON; + } + break; + case POWER_SUSPEND: + power_management_suspend(NULL); + break; + case POWER_WAKEUP: + if (1 << pmc.wakeup_reason & pmc.wakeup_capability) { + power_management_wakeup(NULL); + } + default: + break; + } + + if (reset == 0) { + pmc.power_state = POWER_IDLE; + } + + return pmc.power_state; +} + +static void power_chip_init(Object *obj) +{ + pmc.power_state = POWER_IDLE; + pmc.wakeup_reason = QEMU_WAKEUP_REASON_UNKNOWN; + pmc.wakeup_capability = QEMU_WAKEUP_REASON_RTC | QEMU_WAKEUP_REASON_PMTIMER; +} + +static void power_chip_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->on = power_management_on; + dc->off = power_management_off; + dc->wakeup = power_management_wakeup; + dc->suspend = power_management_suspend; +} + +static const TypeInfo power_chip_info = { + .name = TYPE_POWER_CHIP, + .parent = NULL, + .instance_size = sizeof(PowerChip), + .instance_init = power_chip_init, + .class_init = power_chip_class_init, +}; + +static void power_chip_types(void) +{ + type_register_static(&power_chip_info); +} + +type_init(power_chip_types); + diff --git a/power.h b/power.h new file mode 100644 index 0000000..e36fd31 --- /dev/null +++ b/power.h @@ -0,0 +1,41 @@ +#ifndef ____POWER_H_ +#define ____POWER_H_ + +#include "hw/qdev.h" +#include "hw/qdev-core.h" + + +typedef enum PowerState { + POWER_IDLE = 0, + POWER_OFF = 0x1, + POWER_ON = 0x2, + POWER_RESET = 0x80, + POWER_SUSPEND = 0x4, + POWER_WAKEUP = 0x8, +} PowerState; + +typedef enum WakeupReason { + QEMU_WAKEUP_REASON_UNKNOWN = -1, + QEMU_WAKEUP_REASON_OTHER = 0, + QEMU_WAKEUP_REASON_RTC, + QEMU_WAKEUP_REASON_PMTIMER, +} WakeupReason; + +typedef struct PowerChip { + DeviceState dev; + PowerState power_state; + WakeupReason wakeup_reason; + int wakeup_capability; +} PowerChip; + +#define TYPE_POWER_CHIP "power-chip" + +#define PMC(obj) OBJECT_CHECK(PowerChip, (obj), TYPE_CPU) + +void power_management_set(PowerState ps); +PowerState power_management(void); +WakeupReason power_management_wakeup_reason(void); +void power_management_wakeup_reason_set(WakeupReason wr); +void power_management_wakeup_capability(WakeupReason wr, bool ok); + +#endif -- 1.7.2.5
