Attached are some patches that update the recently added tcpcib(4)
driver with support for using the HPET as a timecounter, based on
amdpcib(4).
Here's the updated dmesg:
---8---
tcpcib0 at pci0 dev 31 function 0 Intel E600 LPC rev 0x00: 64-bit 14318179 Hz
timer rev 1: watchdog
---8---
Here's the sysctl output from my Soekris net6501:
# sysctl kern.timecounter
kern.timecounter.tick=1
kern.timecounter.timestepwarnings=0
kern.timecounter.hardware=tcpcib0
kern.timecounter.choice=i8254(0) tcpcib0(1000) dummy(-100)
I'm aware there's also acpihpet(4) which might normally take control of
this bit of the hardware however the Soekris net6501 at least lacks any
ACPI support at present so the hardware is currently unused. I presume
on an E600-based system with ACPI, acpihpet(4) will bagsy the hardware
first and so the bus_space_map() call in tcpcib(4) will silently fail.
I also removed a couple of overzealous tcpcib_wdt_unlock()'s that are
not needed before writing to the registers that follow, I re-tested and
the watchdog still triggers as expected.
Matt
--- sys/dev/pci/tcpcib.c.orig Wed May 30 12:19:41 2012
+++ sys/dev/pci/tcpcib.cWed May 30 12:59:23 2012
@@ -17,12 +17,13 @@
*/
/*
- * Intel Atom E600 series LPC bridge also containing watchdog
+ * Intel Atom E600 series LPC bridge also containing HPET and watchdog
*/
#include sys/param.h
#include sys/systm.h
#include sys/device.h
+#include sys/timetc.h
#include machine/bus.h
@@ -52,18 +53,42 @@
#defineE600_WDT_WDTLR_ENABLE (1 1)/* Watchdog Timer
Enable */
#defineE600_WDT_WDTLR_TIMEOUT (1 2)/* WDT Timeout
Configuration */
+#defineE600_HPET_BASE 0xfed0 /* HPET register base */
+#defineE600_HPET_SIZE 0x0400 /* HPET register size */
+
+#defineE600_HPET_GCID 0x000 /* Capabilities and ID
*/
+#defineE600_HPET_GCID_WIDTH(1 13) /* Counter Size */
+#defineE600_HPET_PERIOD0x004 /* Counter Tick Period
*/
+#defineE600_HPET_GC0x010 /* General
Configuration */
+#defineE600_HPET_GC_ENABLE (1 0)/* Overall Enable */
+#defineE600_HPET_GIS 0x020 /* General Interrupt
Status */
+#defineE600_HPET_MCV 0x0f0 /* Main Counter Value */
+#defineE600_HPET_T0C 0x100 /* Timer 0 Config and
Capabilities */
+#defineE600_HPET_T0CV 0x108 /* Timer 0 Comparator
Value */
+#defineE600_HPET_T1C 0x120 /* Timer 1 Config and
Capabilities */
+#defineE600_HPET_T1CV 0x128 /* Timer 1 Comparator
Value */
+#defineE600_HPET_T2C 0x140 /* Timer 2 Config and
Capabilities */
+#defineE600_HPET_T2CV 0x148 /* Timer 2 Comparator
Value */
+
struct tcpcib_softc {
struct device sc_dev;
/* Keep track of which parts of the hardware are active */
int sc_active;
#defineE600_WDT_ACTIVE (1 0)
+#defineE600_HPET_ACTIVE(1 1)
/* Watchdog interface */
bus_space_tag_t sc_wdt_iot;
bus_space_handle_t sc_wdt_ioh;
int sc_wdt_period;
+
+ /* High Precision Event Timer */
+ bus_space_tag_t sc_hpet_iot;
+ bus_space_handle_t sc_hpet_ioh;
+
+ struct timecounter sc_hpet_timecounter;
};
struct cfdriver tcpcib_cd = {
@@ -79,6 +104,8 @@
voidtcpcib_wdt_start(struct tcpcib_softc *);
voidtcpcib_wdt_stop(struct tcpcib_softc *);
+u_int tcpcib_hpet_get_timecount(struct timecounter *tc);
+
struct cfattach tcpcib_ca = {
sizeof(struct tcpcib_softc), tcpcib_match, tcpcib_attach,
NULL, tcpcib_activate
@@ -112,7 +139,6 @@
* Set watchdog to perform a cold reset toggling the GPIO pin and the
* prescaler set to 1ms-10m resolution
*/
- tcpcib_wdt_unlock(sc);
bus_space_write_1(sc-sc_wdt_iot, sc-sc_wdt_ioh, E600_WDT_WDTCR,
E600_WDT_WDTCR_ENABLE);
tcpcib_wdt_unlock(sc);
@@ -129,7 +155,6 @@
tcpcib_wdt_start(struct tcpcib_softc *sc)
{
/* Enable watchdog */
- tcpcib_wdt_unlock(sc);
bus_space_write_1(sc-sc_wdt_iot, sc-sc_wdt_ioh, E600_WDT_WDTLR,
E600_WDT_WDTLR_ENABLE);
}
@@ -141,7 +166,6 @@
tcpcib_wdt_unlock(sc);
bus_space_write_1(sc-sc_wdt_iot, sc-sc_wdt_ioh, E600_WDT_RR1,
E600_WDT_RR1_RELOAD);
- tcpcib_wdt_unlock(sc);
bus_space_write_1(sc-sc_wdt_iot, sc-sc_wdt_ioh, E600_WDT_WDTLR, 0);
}
@@ -160,10 +184,43 @@
{
struct tcpcib_softc *sc = (struct tcpcib_softc *)self;
struct pci_attach_args *pa = aux;
- u_int32_t reg, wdtbase;
+ struct timecounter *tc = sc-sc_hpet_timecounter;
+ u_int32_t reg, wdtbase, period;
sc-sc_active = 0;
+ /* High Precision