From 4728f53974d243ca4d491da0be069688ade6f3c7 Mon Sep 17 00:00:00 2001 From: Rob Bradford Date: Thu, 6 Dec 2018 13:00:25 +0000 Subject: [PATCH] hw: virt: Add basic ACPI timer support For the reduced ACPI platform implement the basic ACPI PM_TMR support. Implement only the basic counter and not the optional interupt triggering when the counter's carry changes value. This is useful for implementing basic timekeeping in early firmware. Signed-off-by: Rob Bradford --- hw/acpi/reduced.c | 3 +++ hw/i386/virt/acpi.c | 24 ++++++++++++++++++++++++ include/hw/acpi/reduced.h | 1 + 3 files changed, 28 insertions(+) diff --git a/hw/acpi/reduced.c b/hw/acpi/reduced.c index 0b0089c631..60156a9ca8 100644 --- a/hw/acpi/reduced.c +++ b/hw/acpi/reduced.c @@ -132,6 +132,9 @@ static void build_fadt_reduced(GArray *table_data, BIOSLinker *linker, .sleep_status_reg = { .space_id = AML_AS_SYSTEM_IO, .bit_width = 8, .bit_offset = 0, .address = ACPI_REDUCED_SLEEP_STATUS_IOPORT }, + .pm_tmr = { .space_id = AML_AS_SYSTEM_IO, + .bit_width = 32, .bit_offset = 0, + .address = ACPI_REDUCED_PMTIMER_IOPORT }, }; build_fadt(table_data, linker, &fadt, NULL, NULL); diff --git a/hw/i386/virt/acpi.c b/hw/i386/virt/acpi.c index e5035864cb..a570eabaca 100644 --- a/hw/i386/virt/acpi.c +++ b/hw/i386/virt/acpi.c @@ -57,6 +57,7 @@ typedef struct VirtAcpiState { MemoryRegion sleep_iomem; MemoryRegion sleep_status_iomem; MemoryRegion reset_iomem; + MemoryRegion pm_timer_iomem; } VirtAcpiState; #define TYPE_VIRT_ACPI "virt-acpi" @@ -209,6 +210,25 @@ static const MemoryRegionOps virt_reset_ops = { .write = virt_acpi_reset_write, }; +static void virt_acpi_pm_timer_write(void *opaque, hwaddr addr, + uint64_t val, unsigned width) +{ + return; +} + +static uint64_t virt_acpi_pm_timer_read(void *opaque, hwaddr addr, + unsigned width) +{ + uint64_t counter = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), + PM_TIMER_FREQUENCY, NANOSECONDS_PER_SECOND); + return counter & 0xffffff; +} + +const MemoryRegionOps virt_pm_timer_ops = { + .write = virt_acpi_pm_timer_write, + .read = virt_acpi_pm_timer_read, +}; + static void virt_device_realize(DeviceState *dev, Error **errp) { VirtAcpiState *s = VIRT_ACPI(dev); @@ -236,6 +256,10 @@ static void virt_device_realize(DeviceState *dev, Error **errp) memory_region_init_io(&s->reset_iomem, OBJECT(dev), &virt_reset_ops, s, TYPE_VIRT_ACPI, 1); sysbus_add_io(sys, ACPI_REDUCED_RESET_IOPORT, &s->reset_iomem); + + memory_region_init_io(&s->pm_timer_iomem, OBJECT(dev), + &virt_pm_timer_ops, s, TYPE_VIRT_ACPI, 4); + sysbus_add_io(sys, ACPI_REDUCED_PMTIMER_IOPORT, &s->pm_timer_iomem); } DeviceState *virt_acpi_init(qemu_irq *gsi, PCIBus *pci_bus) diff --git a/include/hw/acpi/reduced.h b/include/hw/acpi/reduced.h index 812493ab74..32b359251e 100644 --- a/include/hw/acpi/reduced.h +++ b/include/hw/acpi/reduced.h @@ -7,6 +7,7 @@ #define ACPI_REDUCED_SLEEP_STATUS_IOPORT 0x3D0 #define ACPI_REDUCED_RESET_IOPORT 0x3C0 #define ACPI_REDUCED_RESET_VALUE 4 +#define ACPI_REDUCED_PMTIMER_IOPORT 0x3E0 void acpi_reduced_setup(MachineState *machine, AcpiConfiguration *conf);