From patchwork Mon Mar 18 08:39:21 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: liguang X-Patchwork-Id: 228407 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 0C2362C00BF for ; Mon, 18 Mar 2013 20:11:59 +1100 (EST) Received: from localhost ([::1]:34715 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UHW6l-0007xl-4e for incoming@patchwork.ozlabs.org; Mon, 18 Mar 2013 05:11:55 -0400 Received: from eggs.gnu.org ([208.118.235.92]:56681) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UHW6R-0007xe-MQ for qemu-devel@nongnu.org; Mon, 18 Mar 2013 05:11:41 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1UHW6N-00030N-TN for qemu-devel@nongnu.org; Mon, 18 Mar 2013 05:11:35 -0400 Received: from [222.73.24.84] (port=37255 helo=song.cn.fujitsu.com) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UHW6N-0002zt-9z for qemu-devel@nongnu.org; Mon, 18 Mar 2013 05:11:31 -0400 X-IronPort-AV: E=Sophos;i="4.84,863,1355068800"; d="scan'208";a="6893213" Received: from unknown (HELO tang.cn.fujitsu.com) ([10.167.250.3]) by song.cn.fujitsu.com with ESMTP; 18 Mar 2013 17:09:00 +0800 Received: from fnstmail02.fnst.cn.fujitsu.com (tang.cn.fujitsu.com [127.0.0.1]) by tang.cn.fujitsu.com (8.14.3/8.13.1) with ESMTP id r2I8eu7T022623 for ; Mon, 18 Mar 2013 16:40:57 +0800 Received: from liguang.fnst.cn.fujitsu.com ([10.167.233.147]) by fnstmail02.fnst.cn.fujitsu.com (Lotus Domino Release 8.5.3) with ESMTP id 2013031816393338-941544 ; Mon, 18 Mar 2013 16:39:33 +0800 From: liguang To: qemu-devel@nongnu.org Date: Mon, 18 Mar 2013 16:39:21 +0800 Message-Id: <1363595961-30137-1-git-send-email-lig.fnst@cn.fujitsu.com> X-Mailer: git-send-email 1.7.2.5 X-MIMETrack: Itemize by SMTP Server on mailserver/fnst(Release 8.5.3|September 15, 2011) at 2013/03/18 16:39:33, Serialize by Router on mailserver/fnst(Release 8.5.3|September 15, 2011) at 2013/03/18 16:39:34, Serialize complete at 2013/03/18 16:39:34 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 222.73.24.84 Cc: liguang Subject: [Qemu-devel] [PATCH][RFC 05/14] power: add power chip emulation X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org 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 --- 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