* Matt Dainty <[email protected]> [2012-06-02 12:52:53]:
> 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<---
As before but with the verbosity of the attach line tuned down a notch
and not printing extra ':'s as pointed out by Theo. So now it looks
like this:
---8<---
tcpcib0 at pci0 dev 31 function 0 "Intel E600 LPC" rev 0x00: 14318179 Hz timer,
watchdog
---8<---
Matt
--- sys/dev/pci/tcpcib.c.orig Wed May 30 12:19:41 2012
+++ sys/dev/pci/tcpcib.c Wed May 30 16:21:13 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 @@
#define E600_WDT_WDTLR_ENABLE (1 << 1) /* Watchdog Timer
Enable */
#define E600_WDT_WDTLR_TIMEOUT (1 << 2) /* WDT Timeout
Configuration */
+#define E600_HPET_BASE 0xfed00000 /* HPET register base */
+#define E600_HPET_SIZE 0x00000400 /* HPET register size */
+
+#define E600_HPET_GCID 0x000 /* Capabilities and ID
*/
+#define E600_HPET_GCID_WIDTH (1 << 13) /* Counter Size */
+#define E600_HPET_PERIOD 0x004 /* Counter Tick Period
*/
+#define E600_HPET_GC 0x010 /* General
Configuration */
+#define E600_HPET_GC_ENABLE (1 << 0) /* Overall Enable */
+#define E600_HPET_GIS 0x020 /* General Interrupt
Status */
+#define E600_HPET_MCV 0x0f0 /* Main Counter Value */
+#define E600_HPET_T0C 0x100 /* Timer 0 Config and
Capabilities */
+#define E600_HPET_T0CV 0x108 /* Timer 0 Comparator
Value */
+#define E600_HPET_T1C 0x120 /* Timer 1 Config and
Capabilities */
+#define E600_HPET_T1CV 0x128 /* Timer 1 Comparator
Value */
+#define E600_HPET_T2C 0x140 /* Timer 2 Config and
Capabilities */
+#define E600_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;
#define E600_WDT_ACTIVE (1 << 0)
+#define E600_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 @@
void tcpcib_wdt_start(struct tcpcib_softc *);
void tcpcib_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,38 @@
{
struct tcpcib_softc *sc = (struct tcpcib_softc *)self;
struct pci_attach_args *pa = aux;
+ struct timecounter *tc = &sc->sc_hpet_timecounter;
u_int32_t reg, wdtbase;
sc->sc_active = 0;
+ /* High Precision Event Timer */
+ sc->sc_hpet_iot = pa->pa_memt;
+ if (bus_space_map(sc->sc_hpet_iot, E600_HPET_BASE, E600_HPET_SIZE, 0,
+ &sc->sc_hpet_ioh) == 0) {
+ tc->tc_get_timecount = tcpcib_hpet_get_timecount;
+ /* XXX 64-bit counter is not supported! */
+ tc->tc_counter_mask = 0xffffffff;
+
+ reg = bus_space_read_4(sc->sc_hpet_iot, sc->sc_hpet_ioh,
+ E600_HPET_PERIOD);
+ /* femtosecs -> Hz */
+ tc->tc_frequency = 1000000000000000ULL / reg;
+
+ tc->tc_name = sc->sc_dev.dv_xname;
+ tc->tc_quality = 1000;
+ tc->tc_priv = sc;
+ tc_init(tc);
+
+ /* Enable counting */
+ bus_space_write_4(sc->sc_hpet_iot, sc->sc_hpet_ioh,
+ E600_HPET_GC, E600_HPET_GC_ENABLE);
+
+ sc->sc_active |= E600_HPET_ACTIVE;
+
+ printf(": %llu Hz timer", tc->tc_frequency);
+ }
+
/* Map Watchdog I/O space */
reg = pci_conf_read(pa->pa_pc, pa->pa_tag, E600_LPC_WDTBA);
wdtbase = reg & 0xffff;
@@ -172,10 +224,11 @@
if (PCI_MAPREG_IO_ADDR(wdtbase) == 0 ||
bus_space_map(sc->sc_wdt_iot, PCI_MAPREG_IO_ADDR(wdtbase),
E600_WDT_SIZE, 0, &sc->sc_wdt_ioh)) {
- printf(": can't map watchdog I/O space");
+ printf("%c can't map watchdog I/O space",
+ sc->sc_active ? ',' : ':');
goto corepcib;
}
- printf(": watchdog");
+ printf("%c watchdog", sc->sc_active ? ',' : ':');
/* Check for reboot on timeout */
reg = bus_space_read_1(sc->sc_wdt_iot, sc->sc_wdt_ioh,
@@ -235,6 +288,9 @@
} else
tcpcib_wdt_stop(sc);
}
+ if (sc->sc_active & E600_HPET_ACTIVE)
+ bus_space_write_4(sc->sc_hpet_iot, sc->sc_hpet_ioh,
+ E600_HPET_GC, E600_HPET_GC_ENABLE);
break;
}
return (0);
@@ -266,4 +322,14 @@
sc->sc_wdt_period = period;
return (period);
+}
+
+u_int
+tcpcib_hpet_get_timecount(struct timecounter *tc)
+{
+ struct tcpcib_softc *sc = tc->tc_priv;
+
+ /* XXX 64-bit counter is not supported! */
+ return bus_space_read_4(sc->sc_hpet_iot, sc->sc_hpet_ioh,
+ E600_HPET_MCV);
}
--- share/man/man4/man4.i386/tcpcib.4.orig Wed May 30 12:38:14 2012
+++ share/man/man4/man4.i386/tcpcib.4 Wed May 30 16:23:42 2012
@@ -19,7 +19,7 @@
.Os
.Sh NAME
.Nm tcpcib
-.Nd Intel Atom E600 series LPC bridge and watchdog timer
+.Nd Intel Atom E600 series LPC bridge, timecounter and watchdog timer
.Sh SYNOPSIS
.Cd "tcpcib* at pci?"
.Cd "isa* at tcpcib?"
@@ -27,7 +27,11 @@
The
.Nm
driver provides support for the Intel Atom E600 series LPC bridge and
-provides the standard
+implements a 64-bit 14.3 MHz timecounter using the HPET timer.
+.Pp
+The
+.Nm
+driver also provides the standard
.Xr watchdog 4
interface to the watchdog timer and may be used with
.Xr watchdogd 8 .
@@ -60,6 +64,6 @@
.Sh BUGS
Apart from the core
.Xr pcib 4
-functionality and the
+functionality, timecounter and the
.Xr watchdog 4
interface, the driver doesn't support any other aspects of the hardware.
--- share/man/man4/man4.amd64/tcpcib.4.orig Wed May 30 12:55:24 2012
+++ share/man/man4/man4.amd64/tcpcib.4 Wed May 30 16:23:34 2012
@@ -19,7 +19,7 @@
.Os
.Sh NAME
.Nm tcpcib
-.Nd Intel Atom E600 series LPC bridge and watchdog timer
+.Nd Intel Atom E600 series LPC bridge, timecounter and watchdog timer
.Sh SYNOPSIS
.Cd "tcpcib* at pci?"
.Cd "isa* at tcpcib?"
@@ -27,7 +27,11 @@
The
.Nm
driver provides support for the Intel Atom E600 series LPC bridge and
-provides the standard
+implements a 64-bit 14.3 MHz timecounter using the HPET timer.
+.Pp
+The
+.Nm
+driver also provides the standard
.Xr watchdog 4
interface to the watchdog timer and may be used with
.Xr watchdogd 8 .
@@ -60,6 +64,6 @@
.Sh BUGS
Apart from the core
.Xr pcib 4
-functionality and the
+functionality, timecounter and the
.Xr watchdog 4
interface, the driver doesn't support any other aspects of the hardware.