PERFORCE change 100942 for review

Warner Losh imp at FreeBSD.org
Fri Jul 7 22:47:59 UTC 2006


http://perforce.freebsd.org/chv.cgi?CH=100942

Change 100942 by imp at imp_lighthouse on 2006/07/07 22:47:13

	Add the meat of the TC drivre that TSC will need.  Not sure
	if this should be MF->FreeBSD or not...  won't hurt to be here
	in p4.

Affected files ...

.. //depot/projects/arm/src/sys/arm/at91/at91_tc.c#2 edit
.. //depot/projects/arm/src/sys/arm/at91/at91_tcreg.h#2 edit

Differences ...

==== //depot/projects/arm/src/sys/arm/at91/at91_tc.c#2 (text+ko) ====

@@ -29,13 +29,14 @@
 
 #include <sys/param.h>
 #include <sys/systm.h>
+#include <sys/bus.h>
 #include <sys/kernel.h>
+#include <sys/lock.h>
 #include <sys/module.h>
+#include <sys/mutex.h>
 #include <sys/time.h>
-#include <sys/bus.h>
-#include <sys/resource.h>
+#include <sys/timetc.h>
 #include <sys/rman.h>
-#include <sys/timetc.h>
 
 #include <machine/bus.h>
 #include <machine/cpu.h>
@@ -50,6 +51,7 @@
 #define MAX_COUNTER 3
 
 struct at91tc_counter {
+	void *intrhand;			/* Interrupt handle */
 	struct resource *irq_res;	/* IRQ resource */
 	struct at91tc_softc *sc;
 	bus_size_t offset;
@@ -59,6 +61,9 @@
 	struct resource	*mem_res;	/* Memory resource */
 	device_t dev;
 	struct at91tc_counter tc[MAX_COUNTER];
+	struct mtx sc_mtx;		/* basically a perimeter lock */
+	struct cdev *cdev;
+	int overflows;
 };
 
 #define RD4(counter, off) \
@@ -70,8 +75,26 @@
 #define WR4sc(sc, off, val) \
 	bus_write_4(sc->mem_res, (off), (val))
 
+#define AT91TC_LOCK(_sc)		mtx_lock(&(_sc)->sc_mtx)
+#define	AT91TC_UNLOCK(_sc)		mtx_unlock(&(_sc)->sc_mtx)
+#define AT91TC_LOCK_INIT(_sc) \
+	mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->dev), \
+	    "tc", MTX_DEF)
+#define AT91TC_LOCK_DESTROY(_sc)	mtx_destroy(&_sc->sc_mtx);
+#define AT91TC_ASSERT_LOCKED(_sc)	mtx_assert(&_sc->sc_mtx, MA_OWNED);
+#define AT91TC_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED);
+#define CDEV2SOFTC(dev)		((dev)->si_drv1)
+
 
+/* helper routines */
+static int at91tc_activate(device_t dev);
+static void at91tc_deactivate(device_t dev);
+static void at91tc_counter_init(struct at91tc_softc *, struct at91tc_counter *,
+    int unit);
+
 #ifdef AT91_TSC
+static driver_intr_t at91tc_counter_isr;
+
 static struct at91tc_counter *at91tc_tc;
 
 static unsigned
@@ -104,14 +127,146 @@
 static int
 at91tc_attach(device_t dev)
 {
+	struct at91tc_softc *sc = device_get_softc(dev);
+	int err, i;
+
+	sc->dev = dev;
+	err = at91tc_activate(dev);
+	if (err)
+		goto out;
+	AT91TC_LOCK_INIT(sc);
+
+	sc->tc[0].offset = TC_TC0_OFFSET;
+	sc->tc[1].offset = TC_TC1_OFFSET;
+	sc->tc[2].offset = TC_TC2_OFFSET;
 
 #ifdef AT91_TSC
 	if (device_get_unit(dev) == 0)
+		// On the TSC board, we have 5MHz going into TIOA2.  Setup
+		// TC1's XC1 to use this.
+		WR4sc(sc, TC_BMR, TC_BMR_XC1_TIOA2);
+#endif
+	for (i = 0; i < MAX_COUNTER; i++)
+		at91tc_counter_init(sc, &sc->tc[i], i);
+#ifdef AT91_TSC
+	if (device_get_unit(dev) == 0) {
+		// XXX need cdev
+		// Init our timecounter.
+		at91tc_tc = &sc->tc[0];
 		tc_init(&at91tc_timecounter);
+	}
 #endif
+out:;
+	return (err);
+}
+
+static int
+at91tc_activate(device_t dev)
+{
+	struct at91tc_softc *sc;
+	int rid;
+
+	sc = device_get_softc(dev);
+	rid = 0;
+	sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+	    RF_ACTIVE);
+	if (sc->mem_res == NULL)
+		goto errout;
 	return (0);
+errout:;
+	at91tc_deactivate(dev);
+	return (ENOMEM);
 }
 
+static void
+at91tc_tc_deactivate(struct at91tc_counter *tc)
+{
+	if (tc->intrhand)
+		bus_teardown_intr(tc->sc->dev, tc->irq_res, tc->intrhand);
+	tc->intrhand = 0;
+	if (tc->irq_res)
+		bus_release_resource(tc->sc->dev, SYS_RES_IRQ,
+		    rman_get_rid(tc->irq_res), tc->irq_res);
+	tc->irq_res = 0;
+}
+
+static void
+at91tc_deactivate(device_t dev)
+{
+	struct at91tc_softc *sc;
+	int i;
+
+	sc = device_get_softc(dev);
+	for (i = 0; i < MAX_COUNTER; i++)
+		at91tc_tc_deactivate(&sc->tc[i]);
+	bus_generic_detach(sc->dev);
+	if (sc->mem_res)
+		bus_release_resource(dev, SYS_RES_IOPORT,
+		    rman_get_rid(sc->mem_res), sc->mem_res);
+	sc->mem_res = 0;
+	return;
+}
+
+static void
+at91tc_counter_init(struct at91tc_softc *sc, struct at91tc_counter *tc,
+    int unit)
+{
+#ifdef AT91_TSC
+	int rid;
+#endif
+
+	tc->sc = sc;
+#ifdef AT91_TSC
+	// Only TC1 is needed.  All others are disabled.
+	if (unit != 1 || device_get_unit(sc->dev) != 0) {
+#endif
+		WR4(tc, TC_CCR, TC_CCR_CLKDIS);
+		WR4(tc, TC_IDR, 0xffffffff);
+		return;
+#ifdef AT91_TSC
+	}
+
+	rid = 0;
+	tc->irq_res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, &rid,
+	    RF_ACTIVE);
+	if (tc->irq_res == NULL)
+		return;
+	if (bus_setup_intr(sc->dev, tc->irq_res, INTR_TYPE_MISC | INTR_FAST,
+	    at91tc_counter_isr, tc, &tc->intrhand) != 0)
+		return;
+
+	// Setup TC1 into Capture Mode (WAVE=0), clocked by our external
+	// 5MHz, loading RA on rise and RB on falling edge
+	WR4(tc, TC_CMR, TC_CMR_XC1 | TC_CMR_BURST_NONE | TC_CMR_ETRGEDG_NONE |
+	    TC_CMR_LDRA_RISE | TC_CMR_LDRB_FALL);
+
+	WR4(tc, TC_IDR, 0xffffffff);
+	WR4(tc, TC_IER, TC_SR_COVFS | TC_SR_LOVRS | TC_SR_LDRAS | TC_SR_LDRBS);
+
+	// Now that we have ISR setup, we can enable clocks and go!
+	WR4(tc, TC_CCR, TC_CCR_SWTRG | TC_CCR_CLKEN);
+#endif
+}
+
+#ifdef AT91_TSC
+static void
+at91tc_counter_isr(void *argp)
+{
+	struct at91tc_counter *tc = argp;
+	uint32_t status;
+
+	status = RD4(tc, TC_SR);
+	if (status & TC_SR_COVFS)
+		tc->sc->overflows++;
+	if (status & TC_SR_LOVRS)
+		printf("Didn't read RA or RB in time\n");
+	if (status & TC_SR_LDRAS)
+		printf("RA loaded at 0x%x\n", RD4(tc, TC_RA) & 0xffff);
+	if (status & TC_SR_LDRBS)
+		printf("RB loaded at 0x%x\n", RD4(tc, TC_RB) & 0xffff);
+}
+#endif
+
 static device_method_t at91tc_methods[] = {
 	DEVMETHOD(device_probe, at91tc_probe),
 	DEVMETHOD(device_attach, at91tc_attach),
@@ -119,7 +274,7 @@
 };
 
 static driver_t at91tc_driver = {
-	"at91_st",
+	"at91_tc",
 	at91tc_methods,
 	sizeof(struct at91tc_softc),
 };

==== //depot/projects/arm/src/sys/arm/at91/at91_tcreg.h#2 (text+ko) ====

@@ -96,7 +96,7 @@
 #define	TC_RB		0x18		/* RB: Register B */
 #define	TC_RC		0x1c		/* RC: Register C */
 #define	TC_SR		0x20		/* SR: Status Register */
-#define		TC_SR_COVRS	0x00001		/* Counter Overflow Status */
+#define		TC_SR_COVFS	0x00001		/* Counter Overflow Status */
 #define		TC_SR_LOVRS	0x00002		/* Load Overrun Status */
 #define		TC_SR_CPAS	0x00004		/* RA Compare Status */
 #define		TC_SR_CPBS	0x00008		/* RB Compare Status */


More information about the p4-projects mailing list