Revision 990b150e
b/hw/acpi.c | ||
---|---|---|
24 | 24 |
#include "sysemu.h" |
25 | 25 |
#include "i2c.h" |
26 | 26 |
#include "smbus.h" |
27 |
#include "acpi.h" |
|
27 | 28 |
|
28 | 29 |
//#define DEBUG |
29 | 30 |
|
30 |
/* i82731AB (PIIX4) compatible power management function */ |
|
31 |
#define PM_FREQ 3579545 |
|
32 |
|
|
33 | 31 |
#define ACPI_DBG_IO_ADDR 0xb044 |
34 | 32 |
|
35 | 33 |
typedef struct PIIX4PMState { |
... | ... | |
51 | 49 |
int kvm_enabled; |
52 | 50 |
} PIIX4PMState; |
53 | 51 |
|
54 |
#define RSM_STS (1 << 15) |
|
55 |
#define PWRBTN_STS (1 << 8) |
|
56 |
#define RTC_EN (1 << 10) |
|
57 |
#define PWRBTN_EN (1 << 8) |
|
58 |
#define GBL_EN (1 << 5) |
|
59 |
#define TMROF_EN (1 << 0) |
|
60 |
|
|
61 |
#define SCI_EN (1 << 0) |
|
62 |
|
|
63 |
#define SUS_EN (1 << 13) |
|
64 |
|
|
65 | 52 |
#define ACPI_ENABLE 0xf1 |
66 | 53 |
#define ACPI_DISABLE 0xf0 |
67 | 54 |
|
... | ... | |
70 | 57 |
static uint32_t get_pmtmr(PIIX4PMState *s) |
71 | 58 |
{ |
72 | 59 |
uint32_t d; |
73 |
d = muldiv64(qemu_get_clock(vm_clock), PM_FREQ, get_ticks_per_sec());
|
|
60 |
d = muldiv64(qemu_get_clock(vm_clock), PM_TIMER_FREQUENCY, get_ticks_per_sec());
|
|
74 | 61 |
return d & 0xffffff; |
75 | 62 |
} |
76 | 63 |
|
... | ... | |
78 | 65 |
{ |
79 | 66 |
int64_t d; |
80 | 67 |
|
81 |
d = muldiv64(qemu_get_clock(vm_clock), PM_FREQ, get_ticks_per_sec()); |
|
68 |
d = muldiv64(qemu_get_clock(vm_clock), PM_TIMER_FREQUENCY, |
|
69 |
get_ticks_per_sec()); |
|
82 | 70 |
if (d >= s->tmr_overflow_time) |
83 |
s->pmsts |= TMROF_EN;
|
|
71 |
s->pmsts |= ACPI_BITMASK_TIMER_STATUS;
|
|
84 | 72 |
return s->pmsts; |
85 | 73 |
} |
86 | 74 |
|
... | ... | |
91 | 79 |
|
92 | 80 |
pmsts = get_pmsts(s); |
93 | 81 |
sci_level = (((pmsts & s->pmen) & |
94 |
(RTC_EN | PWRBTN_EN | GBL_EN | TMROF_EN)) != 0); |
|
82 |
(ACPI_BITMASK_RT_CLOCK_ENABLE | |
|
83 |
ACPI_BITMASK_POWER_BUTTON_ENABLE | |
|
84 |
ACPI_BITMASK_GLOBAL_LOCK_ENABLE | |
|
85 |
ACPI_BITMASK_TIMER_ENABLE)) != 0); |
|
95 | 86 |
qemu_set_irq(s->irq, sci_level); |
96 | 87 |
/* schedule a timer interruption if needed */ |
97 |
if ((s->pmen & TMROF_EN) && !(pmsts & TMROF_EN)) { |
|
98 |
expire_time = muldiv64(s->tmr_overflow_time, get_ticks_per_sec(), PM_FREQ); |
|
88 |
if ((s->pmen & ACPI_BITMASK_TIMER_ENABLE) && |
|
89 |
!(pmsts & ACPI_BITMASK_TIMER_STATUS)) { |
|
90 |
expire_time = muldiv64(s->tmr_overflow_time, get_ticks_per_sec(), |
|
91 |
PM_TIMER_FREQUENCY); |
|
99 | 92 |
qemu_mod_timer(s->tmr_timer, expire_time); |
100 | 93 |
} else { |
101 | 94 |
qemu_del_timer(s->tmr_timer); |
... | ... | |
118 | 111 |
int64_t d; |
119 | 112 |
int pmsts; |
120 | 113 |
pmsts = get_pmsts(s); |
121 |
if (pmsts & val & TMROF_EN) {
|
|
114 |
if (pmsts & val & ACPI_BITMASK_TIMER_STATUS) {
|
|
122 | 115 |
/* if TMRSTS is reset, then compute the new overflow time */ |
123 |
d = muldiv64(qemu_get_clock(vm_clock), PM_FREQ,
|
|
116 |
d = muldiv64(qemu_get_clock(vm_clock), PM_TIMER_FREQUENCY,
|
|
124 | 117 |
get_ticks_per_sec()); |
125 | 118 |
s->tmr_overflow_time = (d + 0x800000LL) & ~0x7fffffLL; |
126 | 119 |
} |
... | ... | |
135 | 128 |
case 0x04: |
136 | 129 |
{ |
137 | 130 |
int sus_typ; |
138 |
s->pmcntrl = val & ~(SUS_EN);
|
|
139 |
if (val & SUS_EN) {
|
|
131 |
s->pmcntrl = val & ~(ACPI_BITMASK_SLEEP_ENABLE);
|
|
132 |
if (val & ACPI_BITMASK_SLEEP_ENABLE) {
|
|
140 | 133 |
/* change suspend type */ |
141 | 134 |
sus_typ = (val >> 10) & 7; |
142 | 135 |
switch(sus_typ) { |
... | ... | |
144 | 137 |
qemu_system_shutdown_request(); |
145 | 138 |
break; |
146 | 139 |
case 1: |
147 |
/* RSM_STS should be set on resume. Pretend that resume |
|
148 |
was caused by power button */ |
|
149 |
s->pmsts |= (RSM_STS | PWRBTN_STS); |
|
140 |
/* ACPI_BITMASK_WAKE_STATUS should be set on resume. |
|
141 |
Pretend that resume was caused by power button */ |
|
142 |
s->pmsts |= (ACPI_BITMASK_WAKE_STATUS | |
|
143 |
ACPI_BITMASK_POWER_BUTTON_STATUS); |
|
150 | 144 |
qemu_system_reset_request(); |
151 | 145 |
if (s->cmos_s3) { |
152 | 146 |
qemu_irq_raise(s->cmos_s3); |
... | ... | |
226 | 220 |
|
227 | 221 |
/* ACPI specs 3.0, 4.7.2.5 */ |
228 | 222 |
if (val == ACPI_ENABLE) { |
229 |
s->pmcntrl |= SCI_EN;
|
|
223 |
s->pmcntrl |= ACPI_BITMASK_SCI_ENABLE;
|
|
230 | 224 |
} else if (val == ACPI_DISABLE) { |
231 |
s->pmcntrl &= ~SCI_EN;
|
|
225 |
s->pmcntrl &= ~ACPI_BITMASK_SCI_ENABLE;
|
|
232 | 226 |
} |
233 | 227 |
|
234 | 228 |
if (s->dev.config[0x5b] & (1 << 1)) { |
... | ... | |
320 | 314 |
|
321 | 315 |
if (!s) { |
322 | 316 |
qemu_system_shutdown_request(); |
323 |
} else if (s->pmen & PWRBTN_EN) {
|
|
324 |
s->pmsts |= PWRBTN_EN;
|
|
317 |
} else if (s->pmen & ACPI_BITMASK_POWER_BUTTON_ENABLE) {
|
|
318 |
s->pmsts |= ACPI_BITMASK_POWER_BUTTON_STATUS;
|
|
325 | 319 |
pm_update_sci(s); |
326 | 320 |
} |
327 | 321 |
} |
b/hw/acpi.h | ||
---|---|---|
1 |
#ifndef QEMU_HW_ACPI_H |
|
2 |
#define QEMU_HW_ACPI_H |
|
3 |
/* |
|
4 |
* Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp> |
|
5 |
* VA Linux Systems Japan K.K. |
|
6 |
* |
|
7 |
* This library is free software; you can redistribute it and/or |
|
8 |
* modify it under the terms of the GNU Lesser General Public |
|
9 |
* License as published by the Free Software Foundation; either |
|
10 |
* version 2 of the License, or (at your option) any later version. |
|
11 |
* |
|
12 |
* This library is distributed in the hope that it will be useful, |
|
13 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
14 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
15 |
* Lesser General Public License for more details. |
|
16 |
* |
|
17 |
* You should have received a copy of the GNU Lesser General Public |
|
18 |
* License along with this library; if not, write to the Free Software |
|
19 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA |
|
20 |
*/ |
|
21 |
|
|
22 |
/* from linux include/acpi/actype.h */ |
|
23 |
/* Default ACPI register widths */ |
|
24 |
|
|
25 |
#define ACPI_GPE_REGISTER_WIDTH 8 |
|
26 |
#define ACPI_PM1_REGISTER_WIDTH 16 |
|
27 |
#define ACPI_PM2_REGISTER_WIDTH 8 |
|
28 |
#define ACPI_PM_TIMER_WIDTH 32 |
|
29 |
|
|
30 |
/* PM Timer ticks per second (HZ) */ |
|
31 |
#define PM_TIMER_FREQUENCY 3579545 |
|
32 |
|
|
33 |
|
|
34 |
/* ACPI fixed hardware registers */ |
|
35 |
|
|
36 |
/* from linux/drivers/acpi/acpica/aclocal.h */ |
|
37 |
/* Masks used to access the bit_registers */ |
|
38 |
|
|
39 |
/* PM1x_STS */ |
|
40 |
#define ACPI_BITMASK_TIMER_STATUS 0x0001 |
|
41 |
#define ACPI_BITMASK_BUS_MASTER_STATUS 0x0010 |
|
42 |
#define ACPI_BITMASK_GLOBAL_LOCK_STATUS 0x0020 |
|
43 |
#define ACPI_BITMASK_POWER_BUTTON_STATUS 0x0100 |
|
44 |
#define ACPI_BITMASK_SLEEP_BUTTON_STATUS 0x0200 |
|
45 |
#define ACPI_BITMASK_RT_CLOCK_STATUS 0x0400 |
|
46 |
#define ACPI_BITMASK_PCIEXP_WAKE_STATUS 0x4000 /* ACPI 3.0 */ |
|
47 |
#define ACPI_BITMASK_WAKE_STATUS 0x8000 |
|
48 |
|
|
49 |
#define ACPI_BITMASK_ALL_FIXED_STATUS (\ |
|
50 |
ACPI_BITMASK_TIMER_STATUS | \ |
|
51 |
ACPI_BITMASK_BUS_MASTER_STATUS | \ |
|
52 |
ACPI_BITMASK_GLOBAL_LOCK_STATUS | \ |
|
53 |
ACPI_BITMASK_POWER_BUTTON_STATUS | \ |
|
54 |
ACPI_BITMASK_SLEEP_BUTTON_STATUS | \ |
|
55 |
ACPI_BITMASK_RT_CLOCK_STATUS | \ |
|
56 |
ACPI_BITMASK_WAKE_STATUS) |
|
57 |
|
|
58 |
/* PM1x_EN */ |
|
59 |
#define ACPI_BITMASK_TIMER_ENABLE 0x0001 |
|
60 |
#define ACPI_BITMASK_GLOBAL_LOCK_ENABLE 0x0020 |
|
61 |
#define ACPI_BITMASK_POWER_BUTTON_ENABLE 0x0100 |
|
62 |
#define ACPI_BITMASK_SLEEP_BUTTON_ENABLE 0x0200 |
|
63 |
#define ACPI_BITMASK_RT_CLOCK_ENABLE 0x0400 |
|
64 |
#define ACPI_BITMASK_PCIEXP_WAKE_DISABLE 0x4000 /* ACPI 3.0 */ |
|
65 |
|
|
66 |
/* PM1x_CNT */ |
|
67 |
#define ACPI_BITMASK_SCI_ENABLE 0x0001 |
|
68 |
#define ACPI_BITMASK_BUS_MASTER_RLD 0x0002 |
|
69 |
#define ACPI_BITMASK_GLOBAL_LOCK_RELEASE 0x0004 |
|
70 |
#define ACPI_BITMASK_SLEEP_TYPE 0x1C00 |
|
71 |
#define ACPI_BITMASK_SLEEP_ENABLE 0x2000 |
|
72 |
|
|
73 |
/* PM2_CNT */ |
|
74 |
#define ACPI_BITMASK_ARB_DISABLE 0x0001 |
|
75 |
|
|
76 |
/* PM_TMR */ |
|
77 |
|
|
78 |
#endif /* !QEMU_HW_ACPI_H */ |
Also available in: Unified diff