summaryrefslogtreecommitdiffstats
path: root/sys/arm
diff options
context:
space:
mode:
authorian <ian@FreeBSD.org>2016-01-24 22:06:56 +0000
committerian <ian@FreeBSD.org>2016-01-24 22:06:56 +0000
commitd334c6626811b46e187e354b29cb278f40871783 (patch)
treef1ae59f3f0b8c233e9f5f2ecd9c8c26c40fd69fa /sys/arm
parente24c3b20d06b07f1ab29cac41517fc3325c2d973 (diff)
downloadFreeBSD-src-d334c6626811b46e187e354b29cb278f40871783.zip
FreeBSD-src-d334c6626811b46e187e354b29cb278f40871783.tar.gz
MFC r294032:
Fix the handling of the "PDC write transfer length" erratum for at91. The problem affects revision 1xx hardware as well as later versions. Also, the recommended workaround is to set the PDC count register for a 12-byte transfer when the actual size is less than that, but there is no need to extend or zero-out the data buffer, because the blklen register contains the real transfer size and only that many bytes will be transferred. Also add a sysctl to turn debugging printfs on or off on the fly.
Diffstat (limited to 'sys/arm')
-rw-r--r--sys/arm/at91/at91_mci.c21
1 files changed, 10 insertions, 11 deletions
diff --git a/sys/arm/at91/at91_mci.c b/sys/arm/at91/at91_mci.c
index 5d58228..a506715 100644
--- a/sys/arm/at91/at91_mci.c
+++ b/sys/arm/at91/at91_mci.c
@@ -446,6 +446,9 @@ at91_mci_attach(device_t dev)
CTLFLAG_RW, &sc->allow_overclock, 0,
"Allow up to 30MHz clock for 25MHz request when next highest speed 15MHz or less.");
+ SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "debug",
+ CTLFLAG_RWTUN, &mci_debug, 0, "enable debug output");
+
/*
* Our real min freq is master_clock/512, but upper driver layers are
* going to set the min speed during card discovery, and the right speed
@@ -783,15 +786,6 @@ at91_mci_start_cmd(struct at91_mci_softc *sc, struct mmc_command *cmd)
WR4(sc, PDC_PTCR, PDC_PTCR_RXTEN);
} else {
len = min(BBSIZE, remaining);
- /*
- * If this is MCI1 revision 2xx controller, apply
- * a work-around for the "Data Write Operation and
- * number of bytes" erratum.
- */
- if ((sc->sc_cap & CAP_MCI1_REV2XX) && len < 12) {
- len = 12;
- memset(sc->bbuf_vaddr[0], 0, 12);
- }
at91_bswap_buf(sc, sc->bbuf_vaddr[0], data->data, len);
err = bus_dmamap_load(sc->dmatag, sc->bbuf_map[0],
sc->bbuf_vaddr[0], len, at91_mci_getaddr,
@@ -800,8 +794,13 @@ at91_mci_start_cmd(struct at91_mci_softc *sc, struct mmc_command *cmd)
panic("IO write dmamap_load failed\n");
bus_dmamap_sync(sc->dmatag, sc->bbuf_map[0],
BUS_DMASYNC_PREWRITE);
+ /*
+ * Erratum workaround: PDC transfer length on a write
+ * must not be smaller than 12 bytes (3 words); only
+ * blklen bytes (set above) are actually transferred.
+ */
WR4(sc, PDC_TPR,paddr);
- WR4(sc, PDC_TCR, len / 4);
+ WR4(sc, PDC_TCR, (len < 12) ? 3 : len / 4);
sc->bbuf_len[0] = len;
remaining -= len;
if (remaining == 0) {
@@ -818,7 +817,7 @@ at91_mci_start_cmd(struct at91_mci_softc *sc, struct mmc_command *cmd)
bus_dmamap_sync(sc->dmatag, sc->bbuf_map[1],
BUS_DMASYNC_PREWRITE);
WR4(sc, PDC_TNPR, paddr);
- WR4(sc, PDC_TNCR, len / 4);
+ WR4(sc, PDC_TNCR, (len < 12) ? 3 : len / 4);
sc->bbuf_len[1] = len;
remaining -= len;
}
OpenPOWER on IntegriCloud