PERFORCE change 111376 for review
Warner Losh
imp at FreeBSD.org
Sat Dec 9 21:54:21 PST 2006
http://perforce.freebsd.org/chv.cgi?CH=111376
Change 111376 by imp at imp_lighthouse on 2006/12/10 05:54:18
MF FreeBSD-tsc-6 (by Patrick Schweiger)
o Add support for reading/writing the registers via sysctl
to facilitate debugging
o Make rx_buf __aligned(32) for strength! well, to make its work.
I'm unsure why this is necessary.
o Fix initialization sequence to properly reflect ordering
constraints.
o tweak setup
o fix math error in calculating length (maybe the comment here
could be better)
o Simplify sc->rx_ptr computation
o Move PREREAD dma sync into setup of RPR/RNPR rather than
doing it unconditionally for all buffers at startup.
o minor locking tweak to avoid a lock leak
o Return the data we have when we get it, rather than waiting for
the buffer to fill (well, and some other bogus things)
Affected files ...
.. //depot/projects/arm/src/sys/arm/at91/at91_ssc.c#19 edit
Differences ...
==== //depot/projects/arm/src/sys/arm/at91/at91_ssc.c#19 (text+ko) ====
@@ -34,6 +34,7 @@
#include <sys/module.h>
#include <sys/mutex.h>
#include <sys/rman.h>
+#include <sys/sysctl.h>
#include <sys/uio.h>
#include <machine/bus.h>
@@ -58,7 +59,7 @@
bus_dma_tag_t tag; /* bus dma tag */
bus_dmamap_t tx_map;
int txdone;
- uint8_t rx_buf[MAX_BUF];
+ uint8_t __aligned(32) rx_buf[MAX_BUF];
uint8_t *rx_ptr;
bus_dmamap_t rx_map[NRX_BUF];
bus_addr_t rx_pa[NRX_BUF];
@@ -68,10 +69,37 @@
uint8_t *rd_end;
};
+struct ssc_sysctl_register_list
+{
+ char *nodename;
+ uint32_t offset;
+ char *comment;
+};
+
+static struct ssc_sysctl_register_list ssc_register_oids[] =
+{
+ { "0x00", 0x00, "Control Register" },
+ { "0x04", 0x04, "Clock Mode Register" },
+ { "0x10", 0x10, "Receive Clock Mode Register" },
+ { "0x14", 0x14, "Receive Frame Mode Register" },
+ { "0x18", 0x18, "Transmit Clock Mode Register" },
+ { "0x1C", 0x1C, "Transmit Frame Mode Register" },
+ { "0x20", 0x20, "Receive Holding Register" },
+ { "0x24", 0x24, "Transmit Holding Register" },
+ { "0x30", 0x30, "Receive Sync. Holding Register" },
+ { "0x34", 0x34, "Transmit Sync. Holding Register" },
+ { "0x40", 0x40, "Status Register" },
+ { "0x44", 0x44, "Interrupt Enable Register" },
+ { "0x48", 0x48, "Interrupt Disable Register" },
+ { "0x4C", 0x4C, "Interrupt Mask Register" },
+ { NULL, 0xFF, NULL }
+};
+
static void at91_ssc_loadread(void *arg, bus_dma_segment_t *segs, int nsegs,
int error);
static void at91_ssc_loadwrite(void *arg, bus_dma_segment_t *segs, int nsegs,
bus_size_t size, int error);
+static int sysctl_ssc_gen_handler(SYSCTL_HANDLER_ARGS);
static inline uint32_t
RD4(struct at91_ssc_softc *sc, bus_size_t off)
@@ -144,15 +172,23 @@
AT91_SSC_LOCK_INIT(sc);
/*
- * Activate the interrupt
+ * Register the sysctl handler.
*/
- err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
- at91_ssc_intr, sc, &sc->intrhand);
- if (err) {
- AT91_SSC_LOCK_DESTROY(sc);
- goto out;
+ for (i = 0 ; ssc_register_oids[i].nodename != NULL; i++)
+ {
+ const struct ssc_sysctl_register_list *oid = &ssc_register_oids[i];
+
+ SYSCTL_ADD_PROC(
+ device_get_sysctl_ctx(dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+ i, oid->nodename, CTLTYPE_UINT | CTLFLAG_RW,
+ sc, oid->offset, sysctl_ssc_gen_handler, "I",
+ oid->comment);
}
+ // perform software reset before DMA read buffer setup
+ WR4(sc, SSC_CR, SSC_CR_SWRST);
+
/*
* Allocate DMA tags and maps
*/
@@ -165,7 +201,7 @@
if (err != 0)
goto out;
for (i = 0; i < NRX_BUF; i++) {
- err = bus_dmamap_create(sc->tag, 0, &sc->rx_map[i]);
+ err = bus_dmamap_create(sc->tag, 0, &sc->rx_map[i]);
if (err != 0)
goto out;
err = bus_dmamap_load(sc->tag, sc->rx_map[i], sc->rx_buf +
@@ -173,6 +209,17 @@
if (err != 0)
goto out;
}
+
+ /*
+ * Activate the interrupt
+ */
+ err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
+ at91_ssc_intr, sc, &sc->intrhand);
+ if (err) {
+ AT91_SSC_LOCK_DESTROY(sc);
+ goto out;
+ }
+
// We use two buffers for read, and we bounce between them.
@@ -186,16 +233,19 @@
sc->rd_end = sc->rd_buf;
// Init for TSC needs
- WR4(sc, SSC_CR, SSC_CR_SWRST);
WR4(sc, SSC_CMR, 0); // clock divider unused
WR4(sc, SSC_RCMR,
- SSC_RCMR_CKS_RK | SSC_RCMR_CKO_NONE | SSC_RCMR_START_FALL_EDGE_RF);
+ SSC_RCMR_CKS_RK | SSC_RCMR_CKO_NONE |
+ SSC_RCMR_START_FALL_EDGE_RF | SSC_RCMR_CKI);
+
WR4(sc, SSC_RFMR,
- 0x1f | SSC_RFMR_MSFBF | SSC_RFMR_FSOS_NONE);
+ 0x1f | SSC_RFMR_MSFBF | SSC_RFMR_FSOS_NONE); // input only
+
WR4(sc, SSC_TCMR,
SSC_TCMR_CKS_TK | SSC_TCMR_CKO_NONE | SSC_TCMR_START_CONT);
+
WR4(sc, SSC_TFMR,
- 0x1f | SSC_TFMR_DATDEF | SSC_TFMR_MSFBF | SSC_TFMR_FSOS_NEG_PULSE);
+ 0x1f | SSC_TFMR_DATDEF | SSC_TFMR_MSFBF | SSC_TFMR_FSOS_LOW);
out:
if (err)
@@ -280,7 +330,12 @@
bus_dmamap_sync(sc->tag, sc->rx_map[sc->rxcur],
BUS_DMASYNC_POSTREAD);
WR4(sc, PDC_PTCR, PDC_PTCR_RXTDIS);
- len = ONE_BUF - RD4(sc, PDC_RCR) * 4 + 4;
+
+ // PDC_RNCR value has been moved to PDC_RCR at the time the
+ // ENDRX interrupt was triggered, its original value already
+ // accounted for the fact that RCR would receive one datum
+ len = ONE_BUF - RD4(sc, PDC_RCR) * 4;
+
sc->rxcur = (sc->rxcur + 1) % NRX_BUF;
WR4(sc, PDC_RPR, sc->rx_pa[sc->rxcur]);
WR4(sc, PDC_RCR, 1);
@@ -293,9 +348,7 @@
memcpy(sc->rd_end, sc->rx_ptr, len);
sc->rd_end += len;
}
- sc->rx_ptr += ONE_BUF;
- if (sc->rx_ptr >= sc->rx_buf + sizeof(sc->rx_buf))
- sc->rx_ptr = sc->rx_buf;
+ sc->rx_ptr = sc->rx_buf + ONE_BUF * sc->rxcur;
sc->rxdone++;
wakeup(&sc->rxdone);
}
@@ -338,17 +391,17 @@
sc = arg;
if (error != 0)
return;
- bus_dmamap_sync(sc->tag, sc->rx_map[sc->rxcur], BUS_DMASYNC_PREREAD);
sc->rx_pa[sc->rxcur] = segs[0].ds_addr;
if (sc->rx_ptr == NULL) {
WR4(sc, PDC_RPR, sc->rx_pa[sc->rxcur]);
WR4(sc, PDC_RCR, 1);
WR4(sc, PDC_RNPR, sc->rx_pa[sc->rxcur] + 4);
WR4(sc, PDC_RNCR, ONE_BUF / 4 - 1);
+ bus_dmamap_sync(sc->tag, sc->rx_map[sc->rxcur], BUS_DMASYNC_PREREAD);
WR4(sc, SSC_IER, SSC_SR_ENDRX);
WR4(sc, SSC_CR, SSC_CR_RXEN);
WR4(sc, PDC_PTCR, PDC_PTCR_RXTEN);
- sc->rx_ptr = sc->rx_buf;
+ sc->rx_ptr = sc->rx_buf + ONE_BUF * sc->rxcur;
}
sc->rxcur = (sc->rxcur + 1) % NRX_BUF;
}
@@ -377,10 +430,10 @@
int err, ret, len;
sc = CDEV2SOFTC(dev);
- AT91_SSC_LOCK(sc);
// must read a multiple of 4 bytes
if ((uio->uio_resid & 0x3) != 0)
return (EINVAL);
+ AT91_SSC_LOCK(sc);
err = 0;
ret = 0;
while (uio->uio_resid) {
@@ -388,8 +441,12 @@
// some data, then go ahead and return what we have now.
if (sc->rd_end == sc->rd_buf && ret != 0)
break;
- err = msleep(&sc->rxdone, &sc->sc_mtx, PCATCH | PZERO,
- "sscrd", 0);
+
+ if (sc->rd_end != sc->rd_buf)
+ err = 0;
+ else
+ err = msleep(&sc->rxdone, &sc->sc_mtx, PCATCH | PZERO,
+ "sscrd", 0);
if (err != 0)
break;
if (sc->rd_end == sc->rd_buf)
@@ -466,4 +523,27 @@
sizeof(struct at91_ssc_softc),
};
+static int
+sysctl_ssc_gen_handler(SYSCTL_HANDLER_ARGS)
+{
+ struct at91_ssc_softc *sc = arg1;
+ int err;
+
+ uint32_t val, newval = 0;
+ val = RD4(sc, arg2);
+
+ if (req->newptr)
+ {
+ if ((err = SYSCTL_IN(req, &newval, sizeof(newval))) != 0)
+ return err;
+ WR4(sc, arg2, newval);
+ }
+ else
+ {
+ return SYSCTL_OUT(req, &val, sizeof(val));
+ }
+
+ return 0;
+}
+
DRIVER_MODULE(at91_ssc, atmelarm, at91_ssc_driver, at91_ssc_devclass, 0, 0);
More information about the p4-projects
mailing list