diff mbox

[RFC,05/14] power: add power chip emulation

Message ID 1363595961-30137-1-git-send-email-lig.fnst@cn.fujitsu.com
State New
Headers show

Commit Message

liguang March 18, 2013, 8:39 a.m. UTC
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 <lig.fnst@cn.fujitsu.com>
---
 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 mbox

Patch

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