aboutsummaryrefslogtreecommitdiff
path: root/hw/acpi/ich9.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/acpi/ich9.c')
-rw-r--r--hw/acpi/ich9.c57
1 files changed, 56 insertions, 1 deletions
diff --git a/hw/acpi/ich9.c b/hw/acpi/ich9.c
index f4dc7a84be..5fb7a879d6 100644
--- a/hw/acpi/ich9.c
+++ b/hw/acpi/ich9.c
@@ -30,6 +30,7 @@
#include "qemu/timer.h"
#include "sysemu/sysemu.h"
#include "hw/acpi/acpi.h"
+#include "hw/acpi/tco.h"
#include "sysemu/kvm.h"
#include "exec/address-spaces.h"
@@ -92,8 +93,16 @@ static void ich9_smi_writel(void *opaque, hwaddr addr, uint64_t val,
unsigned width)
{
ICH9LPCPMRegs *pm = opaque;
+ TCOIORegs *tr = &pm->tco_regs;
+ uint64_t tco_en;
+
switch (addr) {
case 0:
+ tco_en = pm->smi_en & ICH9_PMIO_SMI_EN_TCO_EN;
+ /* once TCO_LOCK bit is set, TCO_EN bit cannot be overwritten */
+ if (tr->tco.cnt1 & TCO_LOCK) {
+ val = (val & ~ICH9_PMIO_SMI_EN_TCO_EN) | tco_en;
+ }
pm->smi_en &= ~pm->smi_en_wmask;
pm->smi_en |= (val & pm->smi_en_wmask);
break;
@@ -159,6 +168,25 @@ static const VMStateDescription vmstate_memhp_state = {
}
};
+static bool vmstate_test_use_tco(void *opaque)
+{
+ ICH9LPCPMRegs *s = opaque;
+ return s->enable_tco;
+}
+
+static const VMStateDescription vmstate_tco_io_state = {
+ .name = "ich9_pm/tco",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .needed = vmstate_test_use_tco,
+ .fields = (VMStateField[]) {
+ VMSTATE_STRUCT(tco_regs, ICH9LPCPMRegs, 1, vmstate_tco_io_sts,
+ TCOIORegs),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
const VMStateDescription vmstate_ich9_pm = {
.name = "ich9_pm",
.version_id = 1,
@@ -179,6 +207,10 @@ const VMStateDescription vmstate_ich9_pm = {
.subsections = (const VMStateDescription*[]) {
&vmstate_memhp_state,
NULL
+ },
+ .subsections = (const VMStateDescription*[]) {
+ &vmstate_tco_io_state,
+ NULL
}
};
@@ -209,7 +241,8 @@ static void pm_powerdown_req(Notifier *n, void *opaque)
acpi_pm1_evt_power_down(&pm->acpi_regs);
}
-void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm, bool smm_enabled,
+void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm,
+ bool smm_enabled, bool enable_tco,
qemu_irq sci_irq)
{
memory_region_init(&pm->io, OBJECT(lpc_pci), "ich9-pm", ICH9_PMIO_SIZE);
@@ -232,6 +265,12 @@ void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm, bool smm_enabled,
memory_region_add_subregion(&pm->io, ICH9_PMIO_SMI_EN, &pm->io_smi);
pm->smm_enabled = smm_enabled;
+
+ pm->enable_tco = enable_tco;
+ if (pm->enable_tco) {
+ acpi_pm_tco_init(&pm->tco_regs, &pm->io);
+ }
+
pm->irq = sci_irq;
qemu_register_reset(pm_reset, pm);
pm->powerdown_notifier.notify = pm_powerdown_req;
@@ -352,6 +391,18 @@ out:
error_propagate(errp, local_err);
}
+static bool ich9_pm_get_enable_tco(Object *obj, Error **errp)
+{
+ ICH9LPCState *s = ICH9_LPC_DEVICE(obj);
+ return s->pm.enable_tco;
+}
+
+static void ich9_pm_set_enable_tco(Object *obj, bool value, Error **errp)
+{
+ ICH9LPCState *s = ICH9_LPC_DEVICE(obj);
+ s->pm.enable_tco = value;
+}
+
void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm, Error **errp)
{
static const uint32_t gpe0_len = ICH9_PMIO_GPE0_LEN;
@@ -383,6 +434,10 @@ void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm, Error **errp)
ich9_pm_get_s4_val,
ich9_pm_set_s4_val,
NULL, pm, NULL);
+ object_property_add_bool(obj, ACPI_PM_PROP_TCO_ENABLED,
+ ich9_pm_get_enable_tco,
+ ich9_pm_set_enable_tco,
+ NULL);
}
void ich9_pm_device_plug_cb(ICH9LPCPMRegs *pm, DeviceState *dev, Error **errp)