Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/dev/sdmmc Add ADMA2 support, which enables scatter gathe...
details: https://anonhg.NetBSD.org/src/rev/97d3856d0f26
branches: trunk
changeset: 809724:97d3856d0f26
user: jmcneill <jmcneill%NetBSD.org@localhost>
date: Wed Jul 29 12:11:13 2015 +0000
description:
Add ADMA2 support, which enables scatter gather DMA for data transfers on
controllers that support it.
diffstat:
sys/dev/sdmmc/sdhc.c | 154 +++++++++++++++++++++++++++++++++++++++++++++--
sys/dev/sdmmc/sdhcreg.h | 35 +++++++++-
sys/dev/sdmmc/sdhcvar.h | 3 +-
3 files changed, 180 insertions(+), 12 deletions(-)
diffs (truncated from 330 to 300 lines):
diff -r 9713c480c66e -r 97d3856d0f26 sys/dev/sdmmc/sdhc.c
--- a/sys/dev/sdmmc/sdhc.c Wed Jul 29 12:05:10 2015 +0000
+++ b/sys/dev/sdmmc/sdhc.c Wed Jul 29 12:11:13 2015 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: sdhc.c,v 1.62 2015/07/28 07:14:48 skrll Exp $ */
+/* $NetBSD: sdhc.c,v 1.63 2015/07/29 12:11:13 jmcneill Exp $ */
/* $OpenBSD: sdhc.c,v 1.25 2009/01/13 19:44:20 grange Exp $ */
/*
@@ -23,7 +23,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sdhc.c,v 1.62 2015/07/28 07:14:48 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sdhc.c,v 1.63 2015/07/29 12:11:13 jmcneill Exp $");
#ifdef _KERNEL_OPT
#include "opt_sdmmc.h"
@@ -86,6 +86,13 @@
#define SHF_USE_4BIT_MODE 0x0002
#define SHF_USE_8BIT_MODE 0x0004
#define SHF_MODE_DMAEN 0x0008 /* needs SDHC_DMA_ENABLE in mode */
+#define SHF_USE_ADMA2_32 0x0010
+#define SHF_USE_ADMA2_64 0x0020
+#define SHF_USE_ADMA2_MASK 0x0030
+
+ bus_dmamap_t adma_map;
+ bus_dma_segment_t adma_segs[1];
+ void *adma2;
};
#define HDEVNAME(hp) (device_xname((hp)->sc->sc_dev))
@@ -246,6 +253,7 @@
struct sdhc_host *hp;
uint32_t caps;
uint16_t sdhcver;
+ int error;
/* Allocate one more host structure. */
hp = malloc(sizeof(struct sdhc_host), M_DEVBUF, M_WAITOK|M_ZERO);
@@ -321,11 +329,30 @@
(ISSET(sc->sc_flags, SDHC_FLAG_USE_DMA &&
ISSET(caps, SDHC_DMA_SUPPORT)))) {
SET(hp->flags, SHF_USE_DMA);
- if (!ISSET(sc->sc_flags, SDHC_FLAG_EXTERNAL_DMA) ||
- ISSET(sc->sc_flags, SDHC_FLAG_EXTDMA_DMAEN))
+
+ if (ISSET(sc->sc_flags, SDHC_FLAG_USE_ADMA2) &&
+ ISSET(caps, SDHC_ADMA2_SUPP)) {
SET(hp->flags, SHF_MODE_DMAEN);
-
- aprint_normal(", DMA");
+ /*
+ * 64-bit mode was present in the 2.00 spec, removed
+ * from 3.00, and re-added in 4.00 with a different
+ * descriptor layout. We only support 2.00 and 3.00
+ * descriptors for now.
+ */
+ if (hp->specver == SDHC_SPEC_VERS_200 &&
+ ISSET(caps, SDHC_64BIT_SYS_BUS)) {
+ SET(hp->flags, SHF_USE_ADMA2_64);
+ aprint_normal(", 64-bit ADMA2");
+ } else {
+ SET(hp->flags, SHF_USE_ADMA2_32);
+ aprint_normal(", 32-bit ADMA2");
+ }
+ } else {
+ if (!ISSET(sc->sc_flags, SDHC_FLAG_EXTERNAL_DMA) ||
+ ISSET(sc->sc_flags, SDHC_FLAG_EXTDMA_DMAEN))
+ SET(hp->flags, SHF_MODE_DMAEN);
+ aprint_normal(", SDMA");
+ }
} else {
aprint_normal(", PIO");
}
@@ -417,6 +444,47 @@
aprint_normal(", %u byte blocks", hp->maxblklen);
aprint_normal("\n");
+ if (ISSET(hp->flags, SHF_USE_ADMA2_MASK)) {
+ int rseg;
+
+ /* Allocate ADMA2 descriptor memory */
+ error = bus_dmamem_alloc(sc->sc_dmat, PAGE_SIZE, PAGE_SIZE,
+ PAGE_SIZE, hp->adma_segs, 1, &rseg, BUS_DMA_WAITOK);
+ if (error) {
+ aprint_error_dev(sc->sc_dev,
+ "ADMA2 dmamem_alloc failed (%d)\n", error);
+ goto adma_done;
+ }
+ error = bus_dmamem_map(sc->sc_dmat, hp->adma_segs, rseg,
+ PAGE_SIZE, (void **)&hp->adma2, BUS_DMA_WAITOK);
+ if (error) {
+ aprint_error_dev(sc->sc_dev,
+ "ADMA2 dmamem_map failed (%d)\n", error);
+ goto adma_done;
+ }
+ error = bus_dmamap_create(sc->sc_dmat, PAGE_SIZE, 1, PAGE_SIZE,
+ 0, BUS_DMA_WAITOK, &hp->adma_map);
+ if (error) {
+ aprint_error_dev(sc->sc_dev,
+ "ADMA2 dmamap_create failed (%d)\n", error);
+ goto adma_done;
+ }
+ error = bus_dmamap_load(sc->sc_dmat, hp->adma_map,
+ hp->adma2, PAGE_SIZE, NULL,
+ BUS_DMA_WAITOK|BUS_DMA_WRITE);
+ if (error) {
+ aprint_error_dev(sc->sc_dev,
+ "ADMA2 dmamap_load failed (%d)\n", error);
+ goto adma_done;
+ }
+
+ memset(hp->adma2, 0, PAGE_SIZE);
+
+adma_done:
+ if (error)
+ CLR(hp->flags, SHF_USE_ADMA2_MASK);
+ }
+
/*
* Attach the generic SD/MMC bus driver. (The bus driver must
* not invoke any chipset functions before it is attached.)
@@ -496,6 +564,12 @@
bus_space_unmap(hp->iot, hp->ioh, hp->ios);
hp->ios = 0;
}
+ if (ISSET(hp->flags, SHF_USE_ADMA2_MASK)) {
+ bus_dmamap_unload(sc->sc_dmat, hp->adma_map);
+ bus_dmamap_destroy(sc->sc_dmat, hp->adma_map);
+ bus_dmamem_unmap(sc->sc_dmat, hp->adma2, PAGE_SIZE);
+ bus_dmamem_free(sc->sc_dmat, hp->adma_segs, 1);
+ }
free(hp, M_DEVBUF);
sc->sc_host[n] = NULL;
}
@@ -1294,9 +1368,57 @@
}
/* Set DMA start address. */
- if (ISSET(mode, SDHC_DMA_ENABLE) &&
- !ISSET(sc->sc_flags, SDHC_FLAG_EXTERNAL_DMA))
+ if (ISSET(hp->flags, SHF_USE_ADMA2_MASK) && cmd->c_datalen > 0) {
+ for (int seg = 0; seg < cmd->c_dmamap->dm_nsegs; seg++) {
+ paddr_t paddr =
+ cmd->c_dmamap->dm_segs[seg].ds_addr;
+ uint16_t len =
+ cmd->c_dmamap->dm_segs[seg].ds_len == 65536 ?
+ 0 : cmd->c_dmamap->dm_segs[seg].ds_len;
+ uint16_t attr =
+ SDHC_ADMA2_VALID | SDHC_ADMA2_ACT_TRANS;
+ if (seg == cmd->c_dmamap->dm_nsegs - 1) {
+ attr |= SDHC_ADMA2_END;
+ }
+ if (ISSET(hp->flags, SHF_USE_ADMA2_32)) {
+ struct sdhc_adma2_descriptor32 *desc =
+ hp->adma2;
+ desc[seg].attribute = htole16(attr);
+ desc[seg].length = htole16(len);
+ desc[seg].address = htole32(paddr);
+ } else {
+ struct sdhc_adma2_descriptor64 *desc =
+ hp->adma2;
+ desc[seg].attribute = htole16(attr);
+ desc[seg].length = htole16(len);
+ desc[seg].address = htole32(paddr & 0xffffffff);
+ desc[seg].address_hi = htole32(
+ (uint64_t)paddr >> 32);
+ }
+ }
+ if (ISSET(hp->flags, SHF_USE_ADMA2_32)) {
+ struct sdhc_adma2_descriptor32 *desc = hp->adma2;
+ desc[cmd->c_dmamap->dm_nsegs].attribute = htole16(0);
+ } else {
+ struct sdhc_adma2_descriptor64 *desc = hp->adma2;
+ desc[cmd->c_dmamap->dm_nsegs].attribute = htole16(0);
+ }
+ bus_dmamap_sync(sc->sc_dmat, hp->adma_map, 0, PAGE_SIZE,
+ BUS_DMASYNC_PREWRITE);
+ HCLR1(hp, SDHC_HOST_CTL, SDHC_DMA_SELECT);
+ HSET1(hp, SDHC_HOST_CTL, SDHC_DMA_SELECT_ADMA2);
+
+ const paddr_t desc_addr = hp->adma_map->dm_segs[0].ds_addr;
+
+ HWRITE4(hp, SDHC_ADMA_SYSTEM_ADDR, desc_addr & 0xffffffff);
+ if (ISSET(hp->flags, SHF_USE_ADMA2_64)) {
+ HWRITE4(hp, SDHC_ADMA_SYSTEM_ADDR + 4,
+ (uint64_t)desc_addr >> 32);
+ }
+ } else if (ISSET(mode, SDHC_DMA_ENABLE) &&
+ !ISSET(sc->sc_flags, SDHC_FLAG_EXTERNAL_DMA)) {
HWRITE4(hp, SDHC_DMA_ADDR, cmd->c_dmamap->dm_segs[0].ds_addr);
+ }
/*
* Start a CPU data transfer. Writing to the high order byte
@@ -1386,6 +1508,11 @@
error = ETIMEDOUT;
break;
}
+
+ if (ISSET(hp->flags, SHF_USE_ADMA2_MASK)) {
+ continue;
+ }
+
if ((status & SDHC_DMA_INTERRUPT) == 0) {
continue;
}
@@ -1410,6 +1537,11 @@
KASSERT(seg < cmd->c_dmamap->dm_nsegs);
}
+ if (ISSET(hp->flags, SHF_USE_ADMA2_MASK)) {
+ bus_dmamap_sync(hp->sc->sc_dmat, hp->adma_map, 0,
+ PAGE_SIZE, BUS_DMASYNC_POSTWRITE);
+ }
+
return error;
}
@@ -1769,6 +1901,12 @@
/* Claim this interrupt. */
done = 1;
+ if (ISSET(error, SDHC_ADMA_ERROR)) {
+ uint8_t adma_err = HREAD1(hp, SDHC_ADMA_ERROR_STATUS);
+ printf("%s: ADMA error, status %02x\n", HDEVNAME(hp),
+ adma_err);
+ }
+
/*
* Service error interrupts.
*/
diff -r 9713c480c66e -r 97d3856d0f26 sys/dev/sdmmc/sdhcreg.h
--- a/sys/dev/sdmmc/sdhcreg.h Wed Jul 29 12:05:10 2015 +0000
+++ b/sys/dev/sdmmc/sdhcreg.h Wed Jul 29 12:11:13 2015 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: sdhcreg.h,v 1.13 2015/05/02 12:10:24 jmcneill Exp $ */
+/* $NetBSD: sdhcreg.h,v 1.14 2015/07/29 12:11:14 jmcneill Exp $ */
/* $OpenBSD: sdhcreg.h,v 1.4 2006/07/30 17:20:40 fgsch Exp $ */
/*
@@ -75,6 +75,9 @@
#define SDHC_CMD_INHIBIT_MASK 0x0003
#define SDHC_HOST_CTL 0x28
#define SDHC_8BIT_MODE (1<<5)
+#define SDHC_DMA_SELECT (3<<3)
+#define SDHC_DMA_SELECT_SDMA (0<<3)
+#define SDHC_DMA_SELECT_ADMA2 (2<<3)
#define SDHC_HIGH_SPEED (1<<2)
#define SDHC_ESDHC_8BIT_MODE (1<<2) /* eSDHC */
#define SDHC_4BIT_MODE (1<<1)
@@ -121,6 +124,7 @@
#define SDHC_NINTR_STATUS_MASK 0x81ff
#define SDHC_EINTR_STATUS 0x32
#define SDHC_DMA_ERROR (1<<12)
+#define SDHC_ADMA_ERROR (1<<9)
#define SDHC_AUTO_CMD12_ERROR (1<<8)
#define SDHC_CURRENT_LIMIT_ERROR (1<<7)
#define SDHC_DATA_END_BIT_ERROR (1<<6)
@@ -130,13 +134,13 @@
#define SDHC_CMD_END_BIT_ERROR (1<<2)
#define SDHC_CMD_CRC_ERROR (1<<1)
#define SDHC_CMD_TIMEOUT_ERROR (1<<0)
-#define SDHC_EINTR_STATUS_MASK 0x01ff /* excluding vendor signals */
+#define SDHC_EINTR_STATUS_MASK 0x03ff /* excluding vendor signals */
#define SDHC_NINTR_STATUS_EN 0x34
#define SDHC_EINTR_STATUS_EN 0x36
#define SDHC_NINTR_SIGNAL_EN 0x38
#define SDHC_NINTR_SIGNAL_MASK 0x01ff
#define SDHC_EINTR_SIGNAL_EN 0x3a
-#define SDHC_EINTR_SIGNAL_MASK 0x01ff /* excluding vendor signals */
+#define SDHC_EINTR_SIGNAL_MASK 0x03ff /* excluding vendor signals */
#define SDHC_CMD12_ERROR_STATUS 0x3c
#define SDHC_CAPABILITIES 0x40
#define SDHC_SHARED_BUS_SLOT (1<<31)
@@ -163,6 +167,10 @@
#define SDHC_TIMEOUT_FREQ_UNIT (1<<7) /* 0=KHz, 1=MHz */
#define SDHC_TIMEOUT_FREQ_SHIFT 0
#define SDHC_TIMEOUT_FREQ_MASK 0x1f
+#define SDHC_ADMA_ERROR_STATUS 0x54
+#define SDHC_ADMA_LENGTH_MISMATCH (1<<2)
+#define SDHC_ADMA_ERROR_STATE (3<<0)
+#define SDHC_ADMA_SYSTEM_ADDR 0x58
#define SDHC_WATERMARK_LEVEL 0x44 /* ESDHC */
#define SDHC_WATERMARK_WRITE_SHIFT 16
#define SDHC_WATERMARK_WRITE_MASK 0xff
@@ -214,4 +222,25 @@
#define SDHC_CAPABILITIES_BITS \
"\20\33Vdd1.8V\32Vdd3.0V\31Vdd3.3V\30SUSPEND\27DMA\26HIGHSPEED"
+#define SDHC_ADMA2_VALID (1<<0)
+#define SDHC_ADMA2_END (1<<1)
+#define SDHC_ADMA2_INT (1<<2)
+#define SDHC_ADMA2_ACT (3<<4)
+#define SDHC_ADMA2_ACT_NOP (0<<4)
+#define SDHC_ADMA2_ACT_TRANS (2<<4)
+#define SDHC_ADMA2_ACT_LINK (3<<4)
+
+struct sdhc_adma2_descriptor32 {
Home |
Main Index |
Thread Index |
Old Index