diff options
| -rw-r--r-- | sys/dev/acpica/acpi_hpet.c | 78 |
1 files changed, 58 insertions, 20 deletions
diff --git a/sys/dev/acpica/acpi_hpet.c b/sys/dev/acpica/acpi_hpet.c index ab64c11aa052..77c6a7d678f7 100644 --- a/sys/dev/acpica/acpi_hpet.c +++ b/sys/dev/acpica/acpi_hpet.c @@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$"); #include <contrib/dev/acpica/acpi.h> #include <dev/acpica/acpivar.h> +#include <dev/acpica/acpi_hpet.h> ACPI_SERIAL_DECL(hpet, "ACPI HPET support"); @@ -58,12 +59,6 @@ static void acpi_hpet_test(struct acpi_hpet_softc *sc); static char *hpet_ids[] = { "PNP0103", NULL }; -#define HPET_MEM_WIDTH 0x400 /* Expected memory region size */ -#define HPET_OFFSET_INFO 0 /* Location of info in region */ -#define HPET_OFFSET_PERIOD 4 /* Location of period (1/hz) */ -#define HPET_OFFSET_ENABLE 0x10 /* Location of enable word */ -#define HPET_OFFSET_VALUE 0xf0 /* Location of actual timer value */ - #define DEV_HPET(x) (acpi_get_magic(x) == (uintptr_t)&acpi_hpet_devclass) struct timecounter hpet_timecounter = { @@ -79,7 +74,25 @@ hpet_get_timecount(struct timecounter *tc) struct acpi_hpet_softc *sc; sc = tc->tc_priv; - return (bus_read_4(sc->mem_res, HPET_OFFSET_VALUE)); + return (bus_read_4(sc->mem_res, HPET_MAIN_COUNTER)); +} + +static void +hpet_enable(struct acpi_hpet_softc *sc) +{ + uint32_t val; + + val = bus_read_4(sc->mem_res, HPET_CONFIG); + bus_write_4(sc->mem_res, HPET_CONFIG, val | HPET_CNF_ENABLE); +} + +static void +hpet_disable(struct acpi_hpet_softc *sc) +{ + uint32_t val; + + val = bus_read_4(sc->mem_res, HPET_CONFIG); + bus_write_4(sc->mem_res, HPET_CONFIG, val & ~HPET_CNF_ENABLE); } /* Discover the HPET via the ACPI table of the same name. */ @@ -166,18 +179,26 @@ acpi_hpet_attach(device_t dev) } /* Be sure timer is enabled. */ - bus_write_4(sc->mem_res, HPET_OFFSET_ENABLE, 1); + hpet_enable(sc); /* Read basic statistics about the timer. */ - val = bus_read_4(sc->mem_res, HPET_OFFSET_PERIOD); + val = bus_read_4(sc->mem_res, HPET_PERIOD); + if (val == 0) { + device_printf(dev, "invalid period\n"); + hpet_disable(sc); + bus_free_resource(dev, SYS_RES_MEMORY, sc->mem_res); + return (ENXIO); + } + freq = (1000000000000000LL + val / 2) / val; if (bootverbose) { - val = bus_read_4(sc->mem_res, HPET_OFFSET_INFO); + val = bus_read_4(sc->mem_res, HPET_CAPABILITIES); device_printf(dev, "vend: 0x%x rev: 0x%x num: %d hz: %jd opts:%s%s\n", - val >> 16, val & 0xff, (val >> 18) & 0xf, freq, - ((val >> 15) & 1) ? " leg_route" : "", - ((val >> 13) & 1) ? " count_size" : ""); + val >> 16, val & HPET_CAP_REV_ID, + (val & HPET_CAP_NUM_TIM) >> 8, freq, + (val & HPET_CAP_LEG_RT) ? " legacy_route" : "", + (val & HPET_CAP_COUNT_SIZE) ? " 64-bit" : ""); } if (testenv("debug.acpi.hpet_test")) @@ -187,12 +208,12 @@ acpi_hpet_attach(device_t dev) * Don't attach if the timer never increments. Since the spec * requires it to be at least 10 MHz, it has to change in 1 us. */ - val = bus_read_4(sc->mem_res, HPET_OFFSET_VALUE); + val = bus_read_4(sc->mem_res, HPET_MAIN_COUNTER); DELAY(1); - val2 = bus_read_4(sc->mem_res, HPET_OFFSET_VALUE); + val2 = bus_read_4(sc->mem_res, HPET_MAIN_COUNTER); if (val == val2) { device_printf(dev, "HPET never increments, disabling\n"); - bus_write_4(sc->mem_res, HPET_OFFSET_ENABLE, 0); + hpet_disable(sc); bus_free_resource(dev, SYS_RES_MEMORY, sc->mem_res); return (ENXIO); } @@ -214,13 +235,29 @@ acpi_hpet_detach(device_t dev) } static int +acpi_hpet_suspend(device_t dev) +{ + struct acpi_hpet_softc *sc; + + /* + * Disable the timer during suspend. The timer will not lose + * its state in S1 or S2, but we are required to disable + * it. + */ + sc = device_get_softc(dev); + hpet_disable(sc); + + return (0); +} + +static int acpi_hpet_resume(device_t dev) { struct acpi_hpet_softc *sc; /* Re-enable the timer after a resume to keep the clock advancing. */ sc = device_get_softc(dev); - bus_write_4(sc->mem_res, HPET_OFFSET_ENABLE, 1); + hpet_enable(sc); return (0); } @@ -237,11 +274,11 @@ acpi_hpet_test(struct acpi_hpet_softc *sc) binuptime(&b0); binuptime(&b0); binuptime(&b1); - u1 = bus_read_4(sc->mem_res, HPET_OFFSET_VALUE); + u1 = bus_read_4(sc->mem_res, HPET_MAIN_COUNTER); for (i = 1; i < 1000; i++) - u2 = bus_read_4(sc->mem_res, HPET_OFFSET_VALUE); + u2 = bus_read_4(sc->mem_res, HPET_MAIN_COUNTER); binuptime(&b2); - u2 = bus_read_4(sc->mem_res, HPET_OFFSET_VALUE); + u2 = bus_read_4(sc->mem_res, HPET_MAIN_COUNTER); bintime_sub(&b2, &b1); bintime_sub(&b1, &b0); @@ -260,6 +297,7 @@ static device_method_t acpi_hpet_methods[] = { DEVMETHOD(device_probe, acpi_hpet_probe), DEVMETHOD(device_attach, acpi_hpet_attach), DEVMETHOD(device_detach, acpi_hpet_detach), + DEVMETHOD(device_suspend, acpi_hpet_suspend), DEVMETHOD(device_resume, acpi_hpet_resume), {0, 0} |
