summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/arch/i386/pci/elan520.c65
-rw-r--r--sys/arch/i386/pci/elan520reg.h23
2 files changed, 81 insertions, 7 deletions
diff --git a/sys/arch/i386/pci/elan520.c b/sys/arch/i386/pci/elan520.c
index a97345b3ab5..e380c841af6 100644
--- a/sys/arch/i386/pci/elan520.c
+++ b/sys/arch/i386/pci/elan520.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: elan520.c,v 1.12 2006/12/12 23:14:27 dim Exp $ */
+/* $OpenBSD: elan520.c,v 1.13 2007/05/23 11:55:11 markus Exp $ */
/* $NetBSD: elan520.c,v 1.4 2002/10/02 05:47:15 thorpej Exp $ */
/*-
@@ -48,6 +48,8 @@
#include <sys/device.h>
#include <sys/gpio.h>
#include <sys/sysctl.h>
+#include <sys/time.h>
+#include <sys/timetc.h>
#include <machine/bus.h>
@@ -66,6 +68,9 @@ struct elansc_softc {
/* GPIO interface */
struct gpio_chipset_tag sc_gpio_gc;
gpio_pin_t sc_gpio_pins[ELANSC_PIO_NPINS];
+
+ /* GP timer */
+ struct timecounter sc_tc;
} *elansc;
int elansc_match(struct device *, void *, void *);
@@ -83,6 +88,8 @@ int elansc_gpio_pin_read(void *, int);
void elansc_gpio_pin_write(void *, int, int);
void elansc_gpio_pin_ctl(void *, int, int);
+u_int elansc_tc_read(struct timecounter *);
+
struct cfattach elansc_ca = {
sizeof(struct elansc_softc), elansc_match, elansc_attach
};
@@ -120,11 +127,10 @@ elansc_attach(struct device *parent, struct device *self, void *aux)
struct elansc_softc *sc = (void *) self;
struct pci_attach_args *pa = aux;
struct gpiobus_attach_args gba;
- uint16_t rev;
- uint8_t ressta, cpuctl;
- int pin;
- int reg, shift;
- u_int16_t data;
+ struct timecounter *tc;
+ uint16_t rev, data;
+ uint8_t ressta, cpuctl, tmr;
+ int pin, reg, shift;
sc->sc_memt = pa->pa_memt;
if (bus_space_map(sc->sc_memt, MMCR_BASE_ADDR, NBPG, 0,
@@ -198,6 +204,53 @@ elansc_attach(struct device *parent, struct device *self, void *aux)
/* Attach GPIO framework */
config_found(&sc->sc_dev, &gba, gpiobus_print);
+
+ /* Disable GP1/2, clear the current count, and set the period to max */
+ bus_space_write_2(sc->sc_memt, sc->sc_memh, GPTMR1CTL,
+ GPTMRCTL_ENB_WR | GPTMRCTL_CONT_CMP |
+ GPTMRCTL_PSC_SEL | GPTMRCTL_RTG);
+ bus_space_write_2(sc->sc_memt, sc->sc_memh, GPTMR1CNT, 0);
+ bus_space_write_2(sc->sc_memt, sc->sc_memh, GPTMR1MAXCMPA, 0);
+
+ bus_space_write_2(sc->sc_memt, sc->sc_memh, GPTMR2CTL,
+ GPTMRCTL_ENB_WR | GPTMRCTL_CONT_CMP);
+ bus_space_write_2(sc->sc_memt, sc->sc_memh, GPTMR2CNT, 0);
+ bus_space_write_2(sc->sc_memt, sc->sc_memh, GPTMR2MAXCMPA, 0);
+
+ tmr = bus_space_read_1(sc->sc_memt, sc->sc_memh, SWTMRCFG);
+
+ /* Enable GP1/2 */
+ bus_space_write_2(sc->sc_memt, sc->sc_memh, GPTMR1CTL,
+ GPTMRCTL_ENB | GPTMRCTL_ENB_WR | GPTMRCTL_CONT_CMP |
+ GPTMRCTL_PSC_SEL | GPTMRCTL_RTG);
+ bus_space_write_2(sc->sc_memt, sc->sc_memh, GPTMR2CTL,
+ GPTMRCTL_ENB | GPTMRCTL_ENB_WR | GPTMRCTL_CONT_CMP);
+
+ /* Attach timer */
+ tc = &sc->sc_tc;
+ tc->tc_get_timecount = elansc_tc_read;
+ tc->tc_poll_pps = NULL;
+ tc->tc_counter_mask = ~0;
+ tc->tc_frequency = (tmr & 1) ? (33000000 / 4) : (33333333 / 4);
+ tc->tc_name = sc->sc_dev.dv_xname;
+ tc->tc_quality = 1000;
+ tc->tc_priv = sc;
+ tc_init(tc);
+}
+
+u_int
+elansc_tc_read(struct timecounter *tc)
+{
+ struct elansc_softc *sc = tc->tc_priv;
+ u_int32_t m1, m2, l;
+
+ do {
+ m1 = bus_space_read_2(sc->sc_memt, sc->sc_memh, GPTMR1CNT);
+ l = bus_space_read_2(sc->sc_memt, sc->sc_memh, GPTMR2CNT);
+ m2 = bus_space_read_2(sc->sc_memt, sc->sc_memh, GPTMR1CNT);
+ } while (m1 != m2);
+
+ return ((m1 << 16) | l);
}
void
diff --git a/sys/arch/i386/pci/elan520reg.h b/sys/arch/i386/pci/elan520reg.h
index 2f954bdcaea..60d00d556f2 100644
--- a/sys/arch/i386/pci/elan520reg.h
+++ b/sys/arch/i386/pci/elan520reg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: elan520reg.h,v 1.2 2004/06/05 15:06:22 grange Exp $ */
+/* $OpenBSD: elan520reg.h,v 1.3 2007/05/23 11:55:11 markus Exp $ */
/* $NetBSD: elan520reg.h,v 1.1 2002/08/12 01:03:14 thorpej Exp $ */
/*-
@@ -146,4 +146,25 @@
#define RESSTA_ICE_HRST_DET 0x20 /* AMDebug(tm) soft reset detect */
#define RESSTA_SCP_RST 0x40 /* SCP reset detect */
+/*
+ * General-Purpose Timers
+ */
+#define SWTMRCFG 0xc64 /* Software Timer Configuration */
+#define GPTMR0CTL 0xc72 /* GP Timer 0 mode/control */
+#define GPTMR0CNT 0xc74 /* GP Timer 0 current count value */
+#define GPTMR0MAXCMPA 0xc76 /* GP Timer 0 maxcount value A */
+#define GPTMR0MAXCMPB 0xc78 /* GP Timer 0 maxcount value B */
+#define GPTMR1CTL 0xc7a /* GP Timer 1 mode/control */
+#define GPTMR1CNT 0xc7c /* GP Timer 1 current count value */
+#define GPTMR1MAXCMPA 0xc7e /* GP Timer 1 maxcount value A */
+#define GPTMR1MAXCMPB 0xc80 /* GP Timer 1 maxcount value B */
+#define GPTMR2CTL 0xc82 /* GP Timer 2 mode/control */
+#define GPTMR2CNT 0xc84 /* GP Timer 2 current count value */
+#define GPTMR2MAXCMPA 0xc8e /* GP Timer 2 maxcount value A */
+#define GPTMRCTL_CONT_CMP 0x0001 /* GP Timer continuous mode */
+#define GPTMRCTL_RTG 0x0010 /* GP Timer retrigger */
+#define GPTMRCTL_PSC_SEL 0x0008 /* GP Timer prescaler */
+#define GPTMRCTL_ENB 0x8000 /* GP Timer enable */
+#define GPTMRCTL_ENB_WR 0x4000 /* GP Timer enable bit write */
+
#endif /* _I386_PCI_ELAN520REG_H_ */