factor out ACPI PM1a EVT logic.
Later this will be used by ich9 acpi.
Cc: Blue Swirl <blauwirbel@gmail.com>
Cc: Huacai Chen <zltjiangshi@gmail.com>
Cc: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>
*/
+#include "sysemu.h"
#include "hw.h"
#include "pc.h"
#include "acpi.h"
return -1;
}
+/* ACPI PM1a EVT */
+uint16_t acpi_pm1_evt_get_sts(ACPIPM1EVT *pm1, int64_t overflow_time)
+{
+ int64_t d = acpi_pm_tmr_get_clock();
+ if (d >= overflow_time) {
+ pm1->sts |= ACPI_BITMASK_TIMER_STATUS;
+ }
+ return pm1->sts;
+}
+
+void acpi_pm1_evt_write_sts(ACPIPM1EVT *pm1, ACPIPMTimer *tmr, uint16_t val)
+{
+ uint16_t pm1_sts = acpi_pm1_evt_get_sts(pm1, tmr->overflow_time);
+ if (pm1_sts & val & ACPI_BITMASK_TIMER_STATUS) {
+ /* if TMRSTS is reset, then compute the new overflow time */
+ acpi_pm_tmr_calc_overflow_time(tmr);
+ }
+ pm1->sts &= ~val;
+}
+
+void acpi_pm1_evt_power_down(ACPIPM1EVT *pm1, ACPIPMTimer *tmr)
+{
+ if (!pm1) {
+ qemu_system_shutdown_request();
+ } else if (pm1->en & ACPI_BITMASK_POWER_BUTTON_ENABLE) {
+ pm1->sts |= ACPI_BITMASK_POWER_BUTTON_STATUS;
+ tmr->update_sci(tmr);
+ }
+}
+
+void acpi_pm1_evt_reset(ACPIPM1EVT *pm1)
+{
+ pm1->sts = 0;
+ pm1->en = 0;
+}
+
/* ACPI PM_TMR */
void acpi_pm_tmr_update(ACPIPMTimer *tmr, bool enable)
{
get_ticks_per_sec());
}
+/* PM1a_EVT: piix and ich9 don't implement PM1b. */
+struct ACPIPM1EVT
+{
+ uint16_t sts;
+ uint16_t en;
+};
+typedef struct ACPIPM1EVT ACPIPM1EVT;
+
+uint16_t acpi_pm1_evt_get_sts(ACPIPM1EVT *pm1, int64_t overflow_time);
+void acpi_pm1_evt_write_sts(ACPIPM1EVT *pm1, ACPIPMTimer *tmr, uint16_t val);
+void acpi_pm1_evt_power_down(ACPIPM1EVT *pm1, ACPIPMTimer *tmr);
+void acpi_pm1_evt_reset(ACPIPM1EVT *pm1);
+
#endif /* !QEMU_HW_ACPI_H */
typedef struct PIIX4PMState {
PCIDevice dev;
IORange ioport;
- uint16_t pmsts;
- uint16_t pmen;
+ ACPIPM1EVT pm1a;
uint16_t pmcntrl;
APMState apm;
#define ACPI_ENABLE 0xf1
#define ACPI_DISABLE 0xf0
-static int get_pmsts(PIIX4PMState *s)
-{
- int64_t d = acpi_pm_tmr_get_clock();
- if (d >= s->tmr.overflow_time)
- s->pmsts |= ACPI_BITMASK_TIMER_STATUS;
- return s->pmsts;
-}
-
static void pm_update_sci(PIIX4PMState *s)
{
int sci_level, pmsts;
- pmsts = get_pmsts(s);
- sci_level = (((pmsts & s->pmen) &
+ pmsts = acpi_pm1_evt_get_sts(&s->pm1a, s->tmr.overflow_time);
+ sci_level = (((pmsts & s->pm1a.en) &
(ACPI_BITMASK_RT_CLOCK_ENABLE |
ACPI_BITMASK_POWER_BUTTON_ENABLE |
ACPI_BITMASK_GLOBAL_LOCK_ENABLE |
qemu_set_irq(s->irq, sci_level);
/* schedule a timer interruption if needed */
- acpi_pm_tmr_update(&s->tmr, (s->pmen & ACPI_BITMASK_TIMER_ENABLE) &&
+ acpi_pm_tmr_update(&s->tmr, (s->pm1a.en & ACPI_BITMASK_TIMER_ENABLE) &&
!(pmsts & ACPI_BITMASK_TIMER_STATUS));
}
switch(addr) {
case 0x00:
- {
- int pmsts;
- pmsts = get_pmsts(s);
- if (pmsts & val & ACPI_BITMASK_TIMER_STATUS) {
- /* if TMRSTS is reset, then compute the new overflow time */
- acpi_pm_tmr_calc_overflow_time(&s->tmr);
- }
- s->pmsts &= ~val;
- pm_update_sci(s);
- }
+ acpi_pm1_evt_write_sts(&s->pm1a, &s->tmr, val);
+ pm_update_sci(s);
break;
case 0x02:
- s->pmen = val;
+ s->pm1a.en = val;
pm_update_sci(s);
break;
case 0x04:
case 1:
/* ACPI_BITMASK_WAKE_STATUS should be set on resume.
Pretend that resume was caused by power button */
- s->pmsts |= (ACPI_BITMASK_WAKE_STATUS |
- ACPI_BITMASK_POWER_BUTTON_STATUS);
+ s->pm1a.sts |= (ACPI_BITMASK_WAKE_STATUS |
+ ACPI_BITMASK_POWER_BUTTON_STATUS);
qemu_system_reset_request();
if (s->cmos_s3) {
qemu_irq_raise(s->cmos_s3);
switch(addr) {
case 0x00:
- val = get_pmsts(s);
+ val = acpi_pm1_evt_get_sts(&s->pm1a, s->tmr.overflow_time);
break;
case 0x02:
- val = s->pmen;
+ val = s->pm1a.en;
break;
case 0x04:
val = s->pmcntrl;
.post_load = vmstate_acpi_post_load,
.fields = (VMStateField []) {
VMSTATE_PCI_DEVICE(dev, PIIX4PMState),
- VMSTATE_UINT16(pmsts, PIIX4PMState),
- VMSTATE_UINT16(pmen, PIIX4PMState),
+ VMSTATE_UINT16(pm1a.sts, PIIX4PMState),
+ VMSTATE_UINT16(pm1a.en, PIIX4PMState),
VMSTATE_UINT16(pmcntrl, PIIX4PMState),
VMSTATE_STRUCT(apm, PIIX4PMState, 0, vmstate_apm, APMState),
VMSTATE_TIMER(tmr.timer, PIIX4PMState),
static void piix4_powerdown(void *opaque, int irq, int power_failing)
{
PIIX4PMState *s = opaque;
+ ACPIPM1EVT *pm1a = s? &s->pm1a: NULL;
+ ACPIPMTimer *tmr = s? &s->tmr: NULL;
- if (!s) {
- qemu_system_shutdown_request();
- } else if (s->pmen & ACPI_BITMASK_POWER_BUTTON_ENABLE) {
- s->pmsts |= ACPI_BITMASK_POWER_BUTTON_STATUS;
- pm_update_sci(s);
- }
+ acpi_pm1_evt_power_down(pm1a, tmr);
}
static int piix4_pm_initfn(PCIDevice *dev)
typedef struct VT686PMState {
PCIDevice dev;
- uint16_t pmsts;
- uint16_t pmen;
+ ACPIPM1EVT pm1a;
uint16_t pmcntrl;
APMState apm;
ACPIPMTimer tmr;
PCIDevice dev;
} VT686MC97State;
-#define RTC_EN (1 << 10)
-#define PWRBTN_EN (1 << 8)
-#define GBL_EN (1 << 5)
-#define TMROF_EN (1 << 0)
-#define SUS_EN (1 << 13)
-
-#define ACPI_ENABLE 0xf1
-#define ACPI_DISABLE 0xf0
-
-static int get_pmsts(VT686PMState *s)
-{
- int64_t d = acpi_pm_tmr_get_clock();
- if (d >= s->tmr.overflow_time) {
- s->pmsts |= ACPI_BITMASK_TIMER_STATUS;
- }
- return s->pmsts;
-}
-
static void pm_update_sci(VT686PMState *s)
{
int sci_level, pmsts;
- pmsts = get_pmsts(s);
- sci_level = (((pmsts & s->pmen) &
- (RTC_EN | PWRBTN_EN | GBL_EN | TMROF_EN)) != 0);
+ pmsts = acpi_pm1_evt_get_sts(&s->pm1a, s->tmr.overflow_time);
+ sci_level = (((pmsts & s->pm1a.en) &
+ (ACPI_BITMASK_RT_CLOCK_ENABLE |
+ ACPI_BITMASK_POWER_BUTTON_ENABLE |
+ ACPI_BITMASK_GLOBAL_LOCK_ENABLE |
+ ACPI_BITMASK_TIMER_ENABLE)) != 0);
qemu_set_irq(s->dev.irq[0], sci_level);
/* schedule a timer interruption if needed */
- acpi_pm_tmr_update(&s->tmr, (s->pmen & ACPI_BITMASK_TIMER_ENABLE) &&
+ acpi_pm_tmr_update(&s->tmr, (s->pm1a.en & ACPI_BITMASK_TIMER_ENABLE) &&
!(pmsts & ACPI_BITMASK_TIMER_STATUS));
}
addr &= 0x0f;
switch (addr) {
case 0x00:
- {
- int pmsts;
- pmsts = get_pmsts(s);
- if (pmsts & val & TMROF_EN) {
- /* if TMRSTS is reset, then compute the new overflow time */
- acpi_pm_tmr_calc_overflow_time(&s->tmr);
- }
- s->pmsts &= ~val;
- pm_update_sci(s);
- }
+ acpi_pm1_evt_write_sts(&s->pm1a, &s->tmr, val);
+ pm_update_sci(s);
break;
case 0x02:
- s->pmen = val;
+ s->pm1a.en = val;
pm_update_sci(s);
break;
case 0x04:
addr &= 0x0f;
switch (addr) {
case 0x00:
- val = get_pmsts(s);
+ val = acpi_pm1_evt_get_sts(&s->pm1a, s->tmr.overflow_time);
break;
case 0x02:
- val = s->pmen;
+ val = s->pm1a.en;
break;
case 0x04:
val = s->pmcntrl;
.post_load = vmstate_acpi_post_load,
.fields = (VMStateField []) {
VMSTATE_PCI_DEVICE(dev, VT686PMState),
- VMSTATE_UINT16(pmsts, VT686PMState),
- VMSTATE_UINT16(pmen, VT686PMState),
+ VMSTATE_UINT16(pm1a.sts, VT686PMState),
+ VMSTATE_UINT16(pm1a.en, VT686PMState),
VMSTATE_UINT16(pmcntrl, VT686PMState),
VMSTATE_STRUCT(apm, VT686PMState, 0, vmstate_apm, APMState),
VMSTATE_TIMER(tmr.timer, VT686PMState),