xref: /dflybsd-src/sys/dev/acpica/acpi_hpet.c (revision df21e16d16b51cf8e1828be094b4866e5d0a1bc8)
15db2f26eSSascha Wildner /*-
25db2f26eSSascha Wildner  * Copyright (c) 2005 Poul-Henning Kamp
35db2f26eSSascha Wildner  * All rights reserved.
45db2f26eSSascha Wildner  *
55db2f26eSSascha Wildner  * Redistribution and use in source and binary forms, with or without
65db2f26eSSascha Wildner  * modification, are permitted provided that the following conditions
75db2f26eSSascha Wildner  * are met:
85db2f26eSSascha Wildner  * 1. Redistributions of source code must retain the above copyright
95db2f26eSSascha Wildner  *    notice, this list of conditions and the following disclaimer.
105db2f26eSSascha Wildner  * 2. Redistributions in binary form must reproduce the above copyright
115db2f26eSSascha Wildner  *    notice, this list of conditions and the following disclaimer in the
125db2f26eSSascha Wildner  *    documentation and/or other materials provided with the distribution.
135db2f26eSSascha Wildner  *
145db2f26eSSascha Wildner  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
155db2f26eSSascha Wildner  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
165db2f26eSSascha Wildner  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
175db2f26eSSascha Wildner  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
185db2f26eSSascha Wildner  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
195db2f26eSSascha Wildner  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
205db2f26eSSascha Wildner  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
215db2f26eSSascha Wildner  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
225db2f26eSSascha Wildner  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
235db2f26eSSascha Wildner  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
245db2f26eSSascha Wildner  * SUCH DAMAGE.
255db2f26eSSascha Wildner  *
265db2f26eSSascha Wildner  * $FreeBSD: src/sys/dev/acpica/acpi_hpet.c,v 1.12.2.1.2.1 2008/11/25 02:59:29 kensmith Exp $
275db2f26eSSascha Wildner  */
285db2f26eSSascha Wildner 
295db2f26eSSascha Wildner #include "opt_acpi.h"
305db2f26eSSascha Wildner 
315db2f26eSSascha Wildner #include <sys/param.h>
325db2f26eSSascha Wildner #include <sys/bus.h>
335db2f26eSSascha Wildner #include <sys/kernel.h>
345db2f26eSSascha Wildner #include <sys/module.h>
355db2f26eSSascha Wildner #include <sys/systimer.h>
365db2f26eSSascha Wildner #include <sys/rman.h>
375db2f26eSSascha Wildner 
385db2f26eSSascha Wildner #include "acpi.h"
395db2f26eSSascha Wildner #include "accommon.h"
405db2f26eSSascha Wildner #include "acpivar.h"
415db2f26eSSascha Wildner #include "acpi_hpet.h"
425db2f26eSSascha Wildner 
435db2f26eSSascha Wildner /* Hooks for the ACPICA debugging infrastructure */
445db2f26eSSascha Wildner #define _COMPONENT	ACPI_TIMER
455db2f26eSSascha Wildner ACPI_MODULE_NAME("HPET")
465db2f26eSSascha Wildner 
475db2f26eSSascha Wildner static bus_space_handle_t	acpi_hpet_bsh;
485db2f26eSSascha Wildner static bus_space_tag_t		acpi_hpet_bst;
495db2f26eSSascha Wildner static u_long			acpi_hpet_res_start;
505db2f26eSSascha Wildner 
515db2f26eSSascha Wildner struct acpi_hpet_softc {
525db2f26eSSascha Wildner 	device_t		dev;
535db2f26eSSascha Wildner 	struct resource		*mem_res;
545db2f26eSSascha Wildner 	ACPI_HANDLE		handle;
555db2f26eSSascha Wildner };
565db2f26eSSascha Wildner 
575db2f26eSSascha Wildner #define DEV_HPET(x)	(acpi_get_magic(x) == (uintptr_t)&acpi_hpet_devclass)
585db2f26eSSascha Wildner 
595db2f26eSSascha Wildner static sysclock_t	acpi_hpet_get_timecount(void);
605db2f26eSSascha Wildner static void		acpi_hpet_construct(struct cputimer *, sysclock_t);
615db2f26eSSascha Wildner 
625db2f26eSSascha Wildner static int		acpi_hpet_identify(driver_t *, device_t);
635db2f26eSSascha Wildner static int		acpi_hpet_probe(device_t);
645db2f26eSSascha Wildner static int		acpi_hpet_attach(device_t);
655db2f26eSSascha Wildner static int		acpi_hpet_resume(device_t);
665db2f26eSSascha Wildner static int		acpi_hpet_suspend(device_t);
675db2f26eSSascha Wildner 
685db2f26eSSascha Wildner static void		acpi_hpet_test(struct acpi_hpet_softc *sc);
695db2f26eSSascha Wildner static u_int		acpi_hpet_read(void);
705db2f26eSSascha Wildner static void		acpi_hpet_enable(struct acpi_hpet_softc *);
715db2f26eSSascha Wildner static void		acpi_hpet_disable(struct acpi_hpet_softc *);
725db2f26eSSascha Wildner 
735db2f26eSSascha Wildner static char *hpet_ids[] = { "PNP0103", NULL };
745db2f26eSSascha Wildner 
755db2f26eSSascha Wildner static struct cputimer acpi_hpet_timer = {
760087561dSSepherosa Ziehau 	.next		= SLIST_ENTRY_INITIALIZER,
770087561dSSepherosa Ziehau 	.name		= "HPET",
780087561dSSepherosa Ziehau 	.pri		= CPUTIMER_PRI_HPET,
790087561dSSepherosa Ziehau 	.type		= CPUTIMER_HPET,
800087561dSSepherosa Ziehau 	.count		= acpi_hpet_get_timecount,
810087561dSSepherosa Ziehau 	.fromhz		= cputimer_default_fromhz,
820087561dSSepherosa Ziehau 	.fromus		= cputimer_default_fromus,
830087561dSSepherosa Ziehau 	.construct	= acpi_hpet_construct,
840087561dSSepherosa Ziehau 	.destruct	= cputimer_default_destruct,
850087561dSSepherosa Ziehau 	.freq		= 0	/* determined later */
865db2f26eSSascha Wildner };
875db2f26eSSascha Wildner 
885db2f26eSSascha Wildner static device_method_t acpi_hpet_methods[] = {
895db2f26eSSascha Wildner 	DEVMETHOD(device_identify,	acpi_hpet_identify),
905db2f26eSSascha Wildner 	DEVMETHOD(device_probe,		acpi_hpet_probe),
915db2f26eSSascha Wildner 	DEVMETHOD(device_attach,	acpi_hpet_attach),
925db2f26eSSascha Wildner 	DEVMETHOD(device_suspend,	acpi_hpet_suspend),
935db2f26eSSascha Wildner 	DEVMETHOD(device_resume,	acpi_hpet_resume),
94d3c9c58eSSascha Wildner 	DEVMETHOD_END
955db2f26eSSascha Wildner };
965db2f26eSSascha Wildner 
975db2f26eSSascha Wildner static driver_t acpi_hpet_driver = {
985db2f26eSSascha Wildner 	"acpi_hpet",
995db2f26eSSascha Wildner 	acpi_hpet_methods,
1005db2f26eSSascha Wildner 	sizeof(struct acpi_hpet_softc),
101*df21e16dSImre Vadász 	.gpri = KOBJ_GPRI_ACPI+2
1025db2f26eSSascha Wildner };
1035db2f26eSSascha Wildner 
1045db2f26eSSascha Wildner static devclass_t acpi_hpet_devclass;
1055db2f26eSSascha Wildner DRIVER_MODULE(acpi_hpet, acpi, acpi_hpet_driver, acpi_hpet_devclass, NULL, NULL);
1065db2f26eSSascha Wildner MODULE_DEPEND(acpi_hpet, acpi, 1, 1, 1);
1075db2f26eSSascha Wildner 
1085db2f26eSSascha Wildner static u_int
1095db2f26eSSascha Wildner acpi_hpet_read(void)
1105db2f26eSSascha Wildner {
1115db2f26eSSascha Wildner 	return bus_space_read_4(acpi_hpet_bst, acpi_hpet_bsh,
1125db2f26eSSascha Wildner 				HPET_MAIN_COUNTER);
1135db2f26eSSascha Wildner }
1145db2f26eSSascha Wildner 
1155db2f26eSSascha Wildner /*
1165db2f26eSSascha Wildner  * Locate the ACPI timer using the FADT, set up and allocate the I/O resources
1175db2f26eSSascha Wildner  * we will be using.
1185db2f26eSSascha Wildner  */
1195db2f26eSSascha Wildner static int
1205db2f26eSSascha Wildner acpi_hpet_identify(driver_t *driver, device_t parent)
1215db2f26eSSascha Wildner {
1225db2f26eSSascha Wildner 	ACPI_TABLE_HPET *hpet;
1235db2f26eSSascha Wildner 	ACPI_TABLE_HEADER *hdr;
1245db2f26eSSascha Wildner 	ACPI_STATUS status;
1255db2f26eSSascha Wildner 	device_t child;
1265db2f26eSSascha Wildner 
1275db2f26eSSascha Wildner 	/*
1285db2f26eSSascha Wildner 	 * Just try once, do nothing if the 'acpi' bus is rescanned.
1295db2f26eSSascha Wildner 	 */
1305db2f26eSSascha Wildner 	if (device_get_state(parent) == DS_ATTACHED)
1315db2f26eSSascha Wildner 		return 0;
1325db2f26eSSascha Wildner 
1335db2f26eSSascha Wildner 	ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
1345db2f26eSSascha Wildner 
1355db2f26eSSascha Wildner 	/* Only one HPET device can be added. */
1365db2f26eSSascha Wildner 	if (devclass_get_device(acpi_hpet_devclass, 0))
1375db2f26eSSascha Wildner 		return ENXIO;
1385db2f26eSSascha Wildner 
1395db2f26eSSascha Wildner 	/* Currently, ID and minimum clock tick info is unused. */
1405db2f26eSSascha Wildner 
1415db2f26eSSascha Wildner 	status = AcpiGetTable(ACPI_SIG_HPET, 1, &hdr);
1425db2f26eSSascha Wildner 	if (ACPI_FAILURE(status))
1435db2f26eSSascha Wildner 		return ENXIO;
1445db2f26eSSascha Wildner 
1455db2f26eSSascha Wildner 	/*
1465db2f26eSSascha Wildner 	 * The unit number could be derived from hdr->Sequence but we only
1475db2f26eSSascha Wildner 	 * support one HPET device.
1485db2f26eSSascha Wildner 	 */
1495db2f26eSSascha Wildner 	hpet = (ACPI_TABLE_HPET *)hdr;
1505db2f26eSSascha Wildner 	if (hpet->Sequence != 0) {
1515db2f26eSSascha Wildner 		kprintf("ACPI HPET table warning: Sequence is non-zero (%d)\n",
1525db2f26eSSascha Wildner 			hpet->Sequence);
1535db2f26eSSascha Wildner 	}
1545db2f26eSSascha Wildner 
1555db2f26eSSascha Wildner 	child = BUS_ADD_CHILD(parent, parent, 0, "acpi_hpet", 0);
1565db2f26eSSascha Wildner 	if (child == NULL) {
1575db2f26eSSascha Wildner 		device_printf(parent, "%s: can't add acpi_hpet0\n", __func__);
1585db2f26eSSascha Wildner 		return ENXIO;
1595db2f26eSSascha Wildner 	}
1605db2f26eSSascha Wildner 
1615db2f26eSSascha Wildner 	/* Record a magic value so we can detect this device later. */
1625db2f26eSSascha Wildner 	acpi_set_magic(child, (uintptr_t)&acpi_hpet_devclass);
1635db2f26eSSascha Wildner 
1645db2f26eSSascha Wildner 	acpi_hpet_res_start = hpet->Address.Address;
1655db2f26eSSascha Wildner 	if (bus_set_resource(child, SYS_RES_MEMORY, 0,
1665db2f26eSSascha Wildner 			     hpet->Address.Address, HPET_MEM_WIDTH, -1)) {
1675db2f26eSSascha Wildner 		device_printf(child, "could not set iomem resources: "
1685db2f26eSSascha Wildner 			      "0x%jx, %d\n", (uintmax_t)hpet->Address.Address,
1695db2f26eSSascha Wildner 			      HPET_MEM_WIDTH);
1705db2f26eSSascha Wildner 		return ENOMEM;
1715db2f26eSSascha Wildner 	}
1725db2f26eSSascha Wildner 	return 0;
1735db2f26eSSascha Wildner }
1745db2f26eSSascha Wildner 
1755db2f26eSSascha Wildner static int
1765db2f26eSSascha Wildner acpi_hpet_probe(device_t dev)
1775db2f26eSSascha Wildner {
1785db2f26eSSascha Wildner 	ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
1795db2f26eSSascha Wildner 
1805db2f26eSSascha Wildner 	if (acpi_disabled("hpet"))
1815db2f26eSSascha Wildner 		return ENXIO;
1825db2f26eSSascha Wildner 
1835db2f26eSSascha Wildner 	if (!DEV_HPET(dev) &&
1845db2f26eSSascha Wildner 	    (ACPI_ID_PROBE(device_get_parent(dev), dev, hpet_ids) == NULL ||
1855db2f26eSSascha Wildner 	     device_get_unit(dev) != 0))
1865db2f26eSSascha Wildner 		return ENXIO;
1875db2f26eSSascha Wildner 
1885db2f26eSSascha Wildner 	device_set_desc(dev, "High Precision Event Timer");
1895db2f26eSSascha Wildner 	return 0;
1905db2f26eSSascha Wildner }
1915db2f26eSSascha Wildner 
1925db2f26eSSascha Wildner static int
1935db2f26eSSascha Wildner acpi_hpet_attach(device_t dev)
1945db2f26eSSascha Wildner {
1955db2f26eSSascha Wildner 	struct acpi_hpet_softc *sc;
1965db2f26eSSascha Wildner 	int rid;
1975db2f26eSSascha Wildner 	uint32_t val, val2;
1985db2f26eSSascha Wildner 	uintmax_t freq;
1995db2f26eSSascha Wildner 
2005db2f26eSSascha Wildner 	ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
2015db2f26eSSascha Wildner 
2025db2f26eSSascha Wildner 	sc = device_get_softc(dev);
2035db2f26eSSascha Wildner 	sc->dev = dev;
2045db2f26eSSascha Wildner 	sc->handle = acpi_get_handle(dev);
2055db2f26eSSascha Wildner 
2065db2f26eSSascha Wildner 	rid = 0;
2075db2f26eSSascha Wildner 	sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
2085db2f26eSSascha Wildner 					     RF_ACTIVE);
2095db2f26eSSascha Wildner 	if (sc->mem_res == NULL) {
2105db2f26eSSascha Wildner 		/*
2115db2f26eSSascha Wildner 		 * We only need to make sure that main counter
2125db2f26eSSascha Wildner 		 * is accessable.
2135db2f26eSSascha Wildner 		 */
2145db2f26eSSascha Wildner 		device_printf(dev, "can't map %dB register space, try %dB\n",
2155db2f26eSSascha Wildner 			      HPET_MEM_WIDTH, HPET_MEM_WIDTH_MIN);
2165db2f26eSSascha Wildner 		rid = 0;
2175db2f26eSSascha Wildner 		sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
2185db2f26eSSascha Wildner 				acpi_hpet_res_start,
2195db2f26eSSascha Wildner 				acpi_hpet_res_start + HPET_MEM_WIDTH_MIN - 1,
2205db2f26eSSascha Wildner 				HPET_MEM_WIDTH_MIN, RF_ACTIVE);
2215db2f26eSSascha Wildner 		if (sc->mem_res == NULL)
2225db2f26eSSascha Wildner 			return ENOMEM;
2235db2f26eSSascha Wildner 	}
2245db2f26eSSascha Wildner 
2255db2f26eSSascha Wildner 	/* Validate that we can access the whole region. */
2265db2f26eSSascha Wildner 	if (rman_get_size(sc->mem_res) < HPET_MEM_WIDTH_MIN) {
2275db2f26eSSascha Wildner 		device_printf(dev, "memory region width %ld too small\n",
2285db2f26eSSascha Wildner 			      rman_get_size(sc->mem_res));
2295db2f26eSSascha Wildner 		bus_release_resource(dev, SYS_RES_MEMORY, rid, sc->mem_res);
2305db2f26eSSascha Wildner 		return ENXIO;
2315db2f26eSSascha Wildner 	}
2325db2f26eSSascha Wildner 
2335db2f26eSSascha Wildner 	acpi_hpet_bsh = rman_get_bushandle(sc->mem_res);
2345db2f26eSSascha Wildner 	acpi_hpet_bst = rman_get_bustag(sc->mem_res);
2355db2f26eSSascha Wildner 
2365db2f26eSSascha Wildner 	/* Be sure timer is enabled. */
2375db2f26eSSascha Wildner 	acpi_hpet_enable(sc);
2385db2f26eSSascha Wildner 
2395db2f26eSSascha Wildner 	/* Read basic statistics about the timer. */
2405db2f26eSSascha Wildner 	val = bus_space_read_4(acpi_hpet_bst, acpi_hpet_bsh, HPET_PERIOD);
2415db2f26eSSascha Wildner 	if (val == 0) {
2425db2f26eSSascha Wildner 		device_printf(dev, "invalid period\n");
2435db2f26eSSascha Wildner 		acpi_hpet_disable(sc);
2445db2f26eSSascha Wildner 		bus_release_resource(dev, SYS_RES_MEMORY, rid, sc->mem_res);
2455db2f26eSSascha Wildner 		return ENXIO;
2465db2f26eSSascha Wildner 	}
2475db2f26eSSascha Wildner 
2485db2f26eSSascha Wildner 	freq = (1000000000000000LL + val / 2) / val;
2495db2f26eSSascha Wildner 	if (bootverbose) {
2505db2f26eSSascha Wildner 		val = bus_space_read_4(acpi_hpet_bst, acpi_hpet_bsh,
2515db2f26eSSascha Wildner 				       HPET_CAPABILITIES);
2525db2f26eSSascha Wildner 		device_printf(dev,
2535db2f26eSSascha Wildner 		    "vend: 0x%x, rev: 0x%x, num: %d, opts:%s%s\n",
2545db2f26eSSascha Wildner 		    val >> 16, val & HPET_CAP_REV_ID,
2555db2f26eSSascha Wildner 		    (val & HPET_CAP_NUM_TIM) >> 8,
2565db2f26eSSascha Wildner 		    (val & HPET_CAP_LEG_RT) ? " legacy_route" : "",
2575db2f26eSSascha Wildner 		    (val & HPET_CAP_COUNT_SIZE) ? " 64-bit" : "");
2585db2f26eSSascha Wildner 	}
2595db2f26eSSascha Wildner 
2605db2f26eSSascha Wildner 	if (ktestenv("debug.acpi.hpet_test"))
2615db2f26eSSascha Wildner 		acpi_hpet_test(sc);
2625db2f26eSSascha Wildner 
2635db2f26eSSascha Wildner 	/*
2645db2f26eSSascha Wildner 	 * Don't attach if the timer never increments.  Since the spec
2655db2f26eSSascha Wildner 	 * requires it to be at least 10 MHz, it has to change in 1 us.
2665db2f26eSSascha Wildner 	 */
2675db2f26eSSascha Wildner 	val = bus_space_read_4(acpi_hpet_bst, acpi_hpet_bsh,
2685db2f26eSSascha Wildner 			       HPET_MAIN_COUNTER);
2695db2f26eSSascha Wildner 	DELAY(1);
2705db2f26eSSascha Wildner 	val2 = bus_space_read_4(acpi_hpet_bst, acpi_hpet_bsh,
2715db2f26eSSascha Wildner 				HPET_MAIN_COUNTER);
2725db2f26eSSascha Wildner 	if (val == val2) {
2735db2f26eSSascha Wildner 		device_printf(dev, "HPET never increments, disabling\n");
2745db2f26eSSascha Wildner 		acpi_hpet_disable(sc);
2755db2f26eSSascha Wildner 		bus_release_resource(dev, SYS_RES_MEMORY, rid, sc->mem_res);
2765db2f26eSSascha Wildner 		return ENXIO;
2775db2f26eSSascha Wildner 	}
2785db2f26eSSascha Wildner 
2795db2f26eSSascha Wildner 	acpi_hpet_timer.freq = freq;
2805db2f26eSSascha Wildner 	device_printf(dev, "frequency %u\n", acpi_hpet_timer.freq);
2815db2f26eSSascha Wildner 
2825db2f26eSSascha Wildner 	cputimer_register(&acpi_hpet_timer);
2835db2f26eSSascha Wildner 	cputimer_select(&acpi_hpet_timer, 0);
2845db2f26eSSascha Wildner 
2855db2f26eSSascha Wildner 	return 0;
2865db2f26eSSascha Wildner }
2875db2f26eSSascha Wildner 
2885db2f26eSSascha Wildner /*
2895db2f26eSSascha Wildner  * Construct the timer.  Adjust the base so the system clock does not
2905db2f26eSSascha Wildner  * jump weirdly.
2915db2f26eSSascha Wildner  */
2925db2f26eSSascha Wildner static void
2935db2f26eSSascha Wildner acpi_hpet_construct(struct cputimer *timer, sysclock_t oldclock)
2945db2f26eSSascha Wildner {
2955db2f26eSSascha Wildner 	timer->base = 0;
2965db2f26eSSascha Wildner 	timer->base = oldclock - acpi_hpet_get_timecount();
2975db2f26eSSascha Wildner }
2985db2f26eSSascha Wildner 
2995db2f26eSSascha Wildner static sysclock_t
3005db2f26eSSascha Wildner acpi_hpet_get_timecount(void)
3015db2f26eSSascha Wildner {
3025db2f26eSSascha Wildner 	return acpi_hpet_read() + acpi_hpet_timer.base;
3035db2f26eSSascha Wildner }
3045db2f26eSSascha Wildner 
3055db2f26eSSascha Wildner static void
3065db2f26eSSascha Wildner acpi_hpet_enable(struct acpi_hpet_softc *sc)
3075db2f26eSSascha Wildner {
3085db2f26eSSascha Wildner 	uint32_t val;
3095db2f26eSSascha Wildner 
3105db2f26eSSascha Wildner 	val = bus_space_read_4(acpi_hpet_bst, acpi_hpet_bsh, HPET_CONFIG);
3115db2f26eSSascha Wildner 	bus_space_write_4(acpi_hpet_bst, acpi_hpet_bsh, HPET_CONFIG,
3125db2f26eSSascha Wildner 			  val | HPET_CNF_ENABLE);
3135db2f26eSSascha Wildner }
3145db2f26eSSascha Wildner 
3155db2f26eSSascha Wildner static void
3165db2f26eSSascha Wildner acpi_hpet_disable(struct acpi_hpet_softc *sc)
3175db2f26eSSascha Wildner {
3185db2f26eSSascha Wildner 	uint32_t val;
3195db2f26eSSascha Wildner 
3205db2f26eSSascha Wildner 	val = bus_space_read_4(acpi_hpet_bst, acpi_hpet_bsh, HPET_CONFIG);
3215db2f26eSSascha Wildner 	bus_space_write_4(acpi_hpet_bst, acpi_hpet_bsh, HPET_CONFIG,
3225db2f26eSSascha Wildner 			  val & ~HPET_CNF_ENABLE);
3235db2f26eSSascha Wildner }
3245db2f26eSSascha Wildner 
3255db2f26eSSascha Wildner static int
3265db2f26eSSascha Wildner acpi_hpet_suspend(device_t dev)
3275db2f26eSSascha Wildner {
3285db2f26eSSascha Wildner 	/*
3295db2f26eSSascha Wildner 	 * According to IA-PC HPET specification rev 1.0a
3305db2f26eSSascha Wildner 	 *
3315db2f26eSSascha Wildner 	 * Page 10, 2.3.3:
3325db2f26eSSascha Wildner 	 * "1. The Event Timer registers (including the main counter)
3335db2f26eSSascha Wildner 	 *  are not expected to be preserved through an S3, S4, or S5
3345db2f26eSSascha Wildner 	 *  state."
3355db2f26eSSascha Wildner 	 *
3365db2f26eSSascha Wildner 	 * Page 11, 2.3.3:
3375db2f26eSSascha Wildner 	 * "3. The main counter is permitted, but not required, to run
3385db2f26eSSascha Wildner 	 *  during S1 or S2 states. ..."
3395db2f26eSSascha Wildner 	 *
3405db2f26eSSascha Wildner 	 * These mean we are not allowed to enter any of Sx states,
3415db2f26eSSascha Wildner 	 * if HPET is used as the sys_cputimer.
3425db2f26eSSascha Wildner 	 */
3435db2f26eSSascha Wildner 	if (sys_cputimer != &acpi_hpet_timer) {
3445db2f26eSSascha Wildner 		struct acpi_hpet_softc *sc;
3455db2f26eSSascha Wildner 
3465db2f26eSSascha Wildner 		sc = device_get_softc(dev);
3475db2f26eSSascha Wildner 		acpi_hpet_disable(sc);
3485db2f26eSSascha Wildner 
3495db2f26eSSascha Wildner 		return 0;
3505db2f26eSSascha Wildner 	} else {
3515db2f26eSSascha Wildner 		return EOPNOTSUPP;
3525db2f26eSSascha Wildner 	}
3535db2f26eSSascha Wildner }
3545db2f26eSSascha Wildner 
3555db2f26eSSascha Wildner static int
3565db2f26eSSascha Wildner acpi_hpet_resume(device_t dev)
3575db2f26eSSascha Wildner {
3585db2f26eSSascha Wildner 	if (sys_cputimer != &acpi_hpet_timer) {
3595db2f26eSSascha Wildner 		struct acpi_hpet_softc *sc;
3605db2f26eSSascha Wildner 
3615db2f26eSSascha Wildner 		sc = device_get_softc(dev);
3625db2f26eSSascha Wildner 		acpi_hpet_enable(sc);
3635db2f26eSSascha Wildner 	}
3645db2f26eSSascha Wildner 	return 0;
3655db2f26eSSascha Wildner }
3665db2f26eSSascha Wildner 
3675db2f26eSSascha Wildner /* Print some basic latency/rate information to assist in debugging. */
3685db2f26eSSascha Wildner static void
3695db2f26eSSascha Wildner acpi_hpet_test(struct acpi_hpet_softc *sc)
3705db2f26eSSascha Wildner {
3715db2f26eSSascha Wildner 	int i;
3725db2f26eSSascha Wildner 	uint32_t u1, u2;
3735db2f26eSSascha Wildner 	struct timeval b0, b1, b2;
3745db2f26eSSascha Wildner 	struct timespec ts;
3755db2f26eSSascha Wildner 
3765db2f26eSSascha Wildner 	microuptime(&b0);
3775db2f26eSSascha Wildner 	microuptime(&b0);
3785db2f26eSSascha Wildner 	microuptime(&b1);
3795db2f26eSSascha Wildner 	u1 = bus_space_read_4(acpi_hpet_bst, acpi_hpet_bsh, HPET_MAIN_COUNTER);
3805db2f26eSSascha Wildner 	for (i = 1; i < 1000; i++) {
3815db2f26eSSascha Wildner 		u2 = bus_space_read_4(acpi_hpet_bst, acpi_hpet_bsh,
3825db2f26eSSascha Wildner 				      HPET_MAIN_COUNTER);
3835db2f26eSSascha Wildner 	}
3845db2f26eSSascha Wildner 	microuptime(&b2);
3855db2f26eSSascha Wildner 	u2 = bus_space_read_4(acpi_hpet_bst, acpi_hpet_bsh, HPET_MAIN_COUNTER);
3865db2f26eSSascha Wildner 
3875db2f26eSSascha Wildner 	timevalsub(&b2, &b1);
3885db2f26eSSascha Wildner 	timevalsub(&b1, &b0);
3895db2f26eSSascha Wildner 	timevalsub(&b2, &b1);
3905db2f26eSSascha Wildner 
3915db2f26eSSascha Wildner 	TIMEVAL_TO_TIMESPEC(&b2, &ts);
3925db2f26eSSascha Wildner 
3935db2f26eSSascha Wildner 	device_printf(sc->dev, "%ld.%09ld: %u ... %u = %u\n",
3945db2f26eSSascha Wildner 	    (long)b2.tv_sec, b2.tv_usec, u1, u2, u2 - u1);
3955db2f26eSSascha Wildner 
3965db2f26eSSascha Wildner 	device_printf(sc->dev, "time per call: %ld ns\n", ts.tv_nsec / 1000);
3975db2f26eSSascha Wildner }
398