summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/acpi/sdhc_acpi.c7
-rw-r--r--sys/dev/pci/sdhc_pci.c3
-rw-r--r--sys/dev/sdmmc/sdhc.c111
-rw-r--r--sys/dev/sdmmc/sdhcreg.h57
-rw-r--r--sys/dev/sdmmc/sdhcvar.h4
-rw-r--r--sys/dev/sdmmc/sdmmc.c17
-rw-r--r--sys/dev/sdmmc/sdmmc_mem.c86
-rw-r--r--sys/dev/sdmmc/sdmmcchip.h5
-rw-r--r--sys/dev/sdmmc/sdmmcvar.h10
9 files changed, 267 insertions, 33 deletions
diff --git a/sys/dev/acpi/sdhc_acpi.c b/sys/dev/acpi/sdhc_acpi.c
index 421c73fd716..f141cd628fd 100644
--- a/sys/dev/acpi/sdhc_acpi.c
+++ b/sys/dev/acpi/sdhc_acpi.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sdhc_acpi.c,v 1.7 2016/04/26 19:10:10 kettenis Exp $ */
+/* $OpenBSD: sdhc_acpi.c,v 1.8 2016/04/30 11:32:23 kettenis Exp $ */
/*
* Copyright (c) 2016 Mark Kettenis
*
@@ -29,6 +29,8 @@
#include <dev/sdmmc/sdhcvar.h>
#include <dev/sdmmc/sdmmcvar.h>
+extern struct bus_dma_tag pci_bus_dma_tag;
+
struct sdhc_acpi_softc {
struct sdhc_softc sc;
struct acpi_softc *sc_acpi;
@@ -134,7 +136,8 @@ sdhc_acpi_attach(struct device *parent, struct device *self, void *aux)
printf("\n");
sc->sc.sc_host = &sc->sc_host;
- sdhc_host_found(&sc->sc, sc->sc_memt, sc->sc_memh, sc->sc_size, 0, 0);
+ sc->sc.sc_dmat = &pci_bus_dma_tag;
+ sdhc_host_found(&sc->sc, sc->sc_memt, sc->sc_memh, sc->sc_size, 1, 0);
}
int
diff --git a/sys/dev/pci/sdhc_pci.c b/sys/dev/pci/sdhc_pci.c
index 4f5b8c19e10..d1b6688f573 100644
--- a/sys/dev/pci/sdhc_pci.c
+++ b/sys/dev/pci/sdhc_pci.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sdhc_pci.c,v 1.19 2015/11/24 19:38:01 kettenis Exp $ */
+/* $OpenBSD: sdhc_pci.c,v 1.20 2016/04/30 11:32:23 kettenis Exp $ */
/*
* Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
@@ -149,6 +149,7 @@ sdhc_pci_attach(struct device *parent, struct device *self, void *aux)
/* Enable use of DMA if supported by the interface. */
usedma = PCI_INTERFACE(pa->pa_class) == SDHC_PCI_INTERFACE_DMA;
+ sc->sc.sc_dmat = pa->pa_dmat;
/*
* Map and attach all hosts supported by the host controller.
diff --git a/sys/dev/sdmmc/sdhc.c b/sys/dev/sdmmc/sdhc.c
index f033593b5ee..3e8f1868476 100644
--- a/sys/dev/sdmmc/sdhc.c
+++ b/sys/dev/sdmmc/sdhc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sdhc.c,v 1.43 2016/03/30 09:58:01 kettenis Exp $ */
+/* $OpenBSD: sdhc.c,v 1.44 2016/04/30 11:32:23 kettenis Exp $ */
/*
* Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
@@ -36,6 +36,7 @@
#define SDHC_COMMAND_TIMEOUT hz
#define SDHC_BUFFER_TIMEOUT hz
#define SDHC_TRANSFER_TIMEOUT hz
+#define SDHC_DMA_TIMEOUT (hz*3)
struct sdhc_host {
struct sdhc_softc *sc; /* host controller device */
@@ -50,6 +51,10 @@ struct sdhc_host {
u_int8_t regs[14]; /* host controller state */
u_int16_t intr_status; /* soft interrupt status */
u_int16_t intr_error_status; /* soft error status */
+
+ bus_dmamap_t adma_map;
+ bus_dma_segment_t adma_segs[1];
+ caddr_t adma2;
};
/* flag values */
@@ -174,7 +179,7 @@ sdhc_host_found(struct sdhc_softc *sc, bus_space_tag_t iot,
caps = HREAD4(hp, SDHC_CAPABILITIES);
/* Use DMA if the host system and the controller support it. */
- if (usedma && ISSET(caps, SDHC_DMA_SUPPORT))
+ if (usedma && ISSET(caps, SDHC_ADMA2_SUPP))
SET(hp->flags, SHF_USE_DMA);
/*
@@ -236,6 +241,46 @@ sdhc_host_found(struct sdhc_softc *sc, bus_space_tag_t iot,
break;
}
+ if (ISSET(hp->flags, SHF_USE_DMA)) {
+ 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 | BUS_DMA_ZERO);
+ if (error)
+ goto adma_done;
+ error = bus_dmamem_map(sc->sc_dmat, hp->adma_segs, rseg,
+ PAGE_SIZE, &hp->adma2, BUS_DMA_WAITOK);
+ if (error) {
+ bus_dmamem_free(sc->sc_dmat, hp->adma_segs, rseg);
+ goto adma_done;
+ }
+ error = bus_dmamap_create(sc->sc_dmat, PAGE_SIZE, 1, PAGE_SIZE,
+ 0, BUS_DMA_WAITOK, &hp->adma_map);
+ if (error) {
+ bus_dmamem_unmap(sc->sc_dmat, hp->adma2, PAGE_SIZE);
+ bus_dmamem_free(sc->sc_dmat, hp->adma_segs, rseg);
+ 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) {
+ 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, rseg);
+ goto adma_done;
+ }
+
+ adma_done:
+ if (error) {
+ printf("%s: can't allocate DMA descriptor table\n",
+ DEVNAME(hp->sc));
+ CLR(hp->flags, SHF_USE_DMA);
+ }
+ }
+
/*
* Attach the generic SD/MMC bus driver. (The bus driver must
* not invoke any chipset functions before it is attached.)
@@ -244,6 +289,9 @@ sdhc_host_found(struct sdhc_softc *sc, bus_space_tag_t iot,
saa.saa_busname = "sdmmc";
saa.sct = &sdhc_functions;
saa.sch = hp;
+ saa.dmat = sc->sc_dmat;
+ if (ISSET(hp->flags, SHF_USE_DMA))
+ saa.caps |= SMC_CAPS_DMA;
hp->sdmmc = config_found(&sc->sc_dev, &saa, NULL);
if (hp->sdmmc == NULL) {
@@ -641,11 +689,14 @@ sdhc_exec_command(sdmmc_chipset_handle_t sch, struct sdmmc_command *cmd)
int
sdhc_start_command(struct sdhc_host *hp, struct sdmmc_command *cmd)
{
+ struct sdhc_adma2_descriptor32 *desc = (void *)hp->adma2;
+ struct sdhc_softc *sc = hp->sc;
u_int16_t blksize = 0;
u_int16_t blkcount = 0;
u_int16_t mode;
u_int16_t command;
int error;
+ int seg;
int s;
DPRINTF(1,("%s: start cmd %u arg=%#x data=%#x dlen=%d flags=%#x "
@@ -688,10 +739,9 @@ sdhc_start_command(struct sdhc_host *hp, struct sdmmc_command *cmd)
mode |= SDHC_AUTO_CMD12_ENABLE;
}
}
-#ifdef notyet
- if (ISSET(hp->flags, SHF_USE_DMA))
+ if (cmd->c_dmamap && cmd->c_datalen > 0 &&
+ ISSET(hp->flags, SHF_USE_DMA))
mode |= SDHC_DMA_ENABLE;
-#endif
/*
* Prepare command register value. (2.2.6)
@@ -724,7 +774,36 @@ sdhc_start_command(struct sdhc_host *hp, struct sdmmc_command *cmd)
/* Alert the user not to remove the card. */
HSET1(hp, SDHC_HOST_CTL, SDHC_LED_ON);
- /* XXX: Set DMA start address if SHF_USE_DMA is set. */
+ /* Set DMA start address if SHF_USE_DMA is set. */
+ if (cmd->c_dmamap && ISSET(hp->flags, SHF_USE_DMA)) {
+ for (seg = 0; seg < cmd->c_dmamap->dm_nsegs; seg++) {
+ bus_addr_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;
+
+ attr = SDHC_ADMA2_VALID | SDHC_ADMA2_ACT_TRANS;
+ if (seg == cmd->c_dmamap->dm_nsegs - 1)
+ attr |= SDHC_ADMA2_END;
+
+ desc[seg].attribute = htole16(attr);
+ desc[seg].length = htole16(len);
+ desc[seg].address = htole32(paddr);
+ }
+
+ 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);
+
+ HWRITE4(hp, SDHC_ADMA_SYSTEM_ADDR,
+ hp->adma_map->dm_segs[0].ds_addr);
+ }
DPRINTF(1,("%s: cmd=%#x mode=%#x blksize=%d blkcount=%d\n",
DEVNAME(hp->sc), command, mode, blksize, blkcount));
@@ -752,6 +831,25 @@ sdhc_transfer_data(struct sdhc_host *hp, struct sdmmc_command *cmd)
int mask;
int error;
+ if (cmd->c_dmamap) {
+ int status;
+
+ error = 0;
+ for (;;) {
+ status = sdhc_wait_intr(hp,
+ SDHC_DMA_INTERRUPT|SDHC_TRANSFER_COMPLETE,
+ SDHC_DMA_TIMEOUT);
+ if (status & SDHC_TRANSFER_COMPLETE)
+ break;
+ if (!status) {
+ error = ETIMEDOUT;
+ break;
+ }
+ }
+
+ goto done;
+ }
+
mask = ISSET(cmd->c_flags, SCF_CMD_READ) ?
SDHC_BUFFER_READ_ENABLE : SDHC_BUFFER_WRITE_ENABLE;
error = 0;
@@ -792,6 +890,7 @@ sdhc_transfer_data(struct sdhc_host *hp, struct sdmmc_command *cmd)
SDHC_TRANSFER_TIMEOUT))
error = ETIMEDOUT;
+done:
if (error != 0)
cmd->c_error = error;
SET(cmd->c_flags, SCF_ITSDONE);
diff --git a/sys/dev/sdmmc/sdhcreg.h b/sys/dev/sdmmc/sdhcreg.h
index c7e9bc85764..300d14a1c38 100644
--- a/sys/dev/sdmmc/sdhcreg.h
+++ b/sys/dev/sdmmc/sdhcreg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: sdhcreg.h,v 1.5 2016/01/11 06:54:53 kettenis Exp $ */
+/* $OpenBSD: sdhcreg.h,v 1.6 2016/04/30 11:32:23 kettenis Exp $ */
/*
* Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
@@ -80,6 +80,10 @@
#define SDHC_CMD_INHIBIT_CMD (1<<0)
#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_4BIT_MODE (1<<1)
#define SDHC_LED_ON (1<<0)
@@ -137,12 +141,25 @@
#define SDHC_EINTR_SIGNAL_EN 0x3a
#define SDHC_EINTR_SIGNAL_MASK 0x01ff /* excluding vendor signals */
#define SDHC_CMD12_ERROR_STATUS 0x3c
+#define SDHC_HOST_CTL2 0x3e
+#define SDHC_SAMPLING_CLOCK_SEL (1<<7)
+#define SDHC_EXECUTE_TUNING (1<<6)
+#define SDHC_1_8V_SIGNAL_EN (1<<3)
+#define SDHC_UHS_MODE_SELECT_SHIFT 0
+#define SDHC_UHS_MODE_SELECT_MASK 0x7
+#define SDHC_UHS_MODE_SELECT_SDR12 0
+#define SDHC_UHS_MODE_SELECT_SDR25 1
+#define SDHC_UHS_MODE_SELECT_SDR50 2
+#define SDHC_UHS_MODE_SELECT_SDR104 3
+#define SDHC_UHS_MODE_SELECT_DDR50 4
#define SDHC_CAPABILITIES 0x40
#define SDHC_VOLTAGE_SUPP_1_8V (1<<26)
#define SDHC_VOLTAGE_SUPP_3_0V (1<<25)
#define SDHC_VOLTAGE_SUPP_3_3V (1<<24)
-#define SDHC_DMA_SUPPORT (1<<22)
+#define SDHC_SDMA_SUPP (1<<22)
#define SDHC_HIGH_SPEED_SUPP (1<<21)
+#define SDHC_ADMA2_SUPP (1<<19)
+#define SDHC_8BIT_MODE_SUPP (1<<18)
#define SDHC_MAX_BLK_LEN_512 0
#define SDHC_MAX_BLK_LEN_1024 1
#define SDHC_MAX_BLK_LEN_2048 2
@@ -154,7 +171,27 @@
#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_CAPABILITIES_1 0x44
+#define SDHC_CAPABILITIES2 0x44
+#define SDHC_SDR50_SUPP (1<<0)
+#define SDHC_SDR104_SUPP (1<<1)
+#define SDHC_DDR50_SUPP (1<<2)
+#define SDHC_DRIVER_TYPE_A (1<<4)
+#define SDHC_DRIVER_TYPE_C (1<<5)
+#define SDHC_DRIVER_TYPE_D (1<<6)
+#define SDHC_TIMER_COUNT_SHIFT 8
+#define SDHC_TIMER_COUNT_MASK 0xf
+#define SDHC_TUNING_SDR50 (1<<13)
+#define SDHC_RETUNING_MODES_SHIFT 14
+#define SDHC_RETUNING_MODES_MASK 0x3
+#define SDHC_RETUNING_MODE_1 (0 << SDHC_RETUNING_MODES_SHIFT)
+#define SDHC_RETUNING_MODE_2 (1 << SDHC_RETUNING_MODES_SHIFT)
+#define SDHC_RETUNING_MODE_3 (2 << SDHC_RETUNING_MODES_SHIFT)
+#define SDHC_CLOCK_MULTIPLIER_SHIFT 16
+#define SDHC_CLOCK_MULTIPLIER_MASK 0xff
+#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_MAX_CAPABILITIES 0x48
#define SDHC_SLOT_INTR_STATUS 0xfc
#define SDHC_HOST_CTL_VERSION 0xfe
@@ -202,4 +239,18 @@
#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 {
+ uint16_t attribute;
+ uint16_t length;
+ uint32_t address;
+} __packed;
+
#endif
diff --git a/sys/dev/sdmmc/sdhcvar.h b/sys/dev/sdmmc/sdhcvar.h
index edd1c27f1f7..e6a419e2719 100644
--- a/sys/dev/sdmmc/sdhcvar.h
+++ b/sys/dev/sdmmc/sdhcvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: sdhcvar.h,v 1.8 2016/03/30 09:58:01 kettenis Exp $ */
+/* $OpenBSD: sdhcvar.h,v 1.9 2016/04/30 11:32:23 kettenis Exp $ */
/*
* Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
@@ -29,6 +29,8 @@ struct sdhc_softc {
int sc_nhosts;
u_int sc_flags;
+ bus_dma_tag_t sc_dmat;
+
int (*sc_card_detect)(struct sdhc_softc *);
};
diff --git a/sys/dev/sdmmc/sdmmc.c b/sys/dev/sdmmc/sdmmc.c
index 2adfce82d69..4ba2b65e1e3 100644
--- a/sys/dev/sdmmc/sdmmc.c
+++ b/sys/dev/sdmmc/sdmmc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sdmmc.c,v 1.39 2016/03/19 11:41:56 mpi Exp $ */
+/* $OpenBSD: sdmmc.c,v 1.40 2016/04/30 11:32:23 kettenis Exp $ */
/*
* Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
@@ -97,15 +97,26 @@ sdmmc_attach(struct device *parent, struct device *self, void *aux)
{
struct sdmmc_softc *sc = (struct sdmmc_softc *)self;
struct sdmmcbus_attach_args *saa = aux;
+ int error;
printf("\n");
sc->sct = saa->sct;
sc->sch = saa->sch;
+ sc->sc_dmat = saa->dmat;
sc->sc_flags = saa->flags;
sc->sc_caps = saa->caps;
sc->sc_max_xfer = saa->max_xfer;
+ if (ISSET(sc->sc_caps, SMC_CAPS_DMA)) {
+ error = bus_dmamap_create(sc->sc_dmat, MAXPHYS, SDMMC_MAXNSEGS,
+ MAXPHYS, 0, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW, &sc->sc_dmap);
+ if (error) {
+ printf("%s: can't create DMA map\n", DEVNAME(sc));
+ return;
+ }
+ }
+
SIMPLEQ_INIT(&sc->sf_head);
TAILQ_INIT(&sc->sc_tskq);
TAILQ_INIT(&sc->sc_intrq);
@@ -138,6 +149,10 @@ sdmmc_detach(struct device *self, int flags)
wakeup(&sc->sc_tskq);
tsleep(sc, PWAIT, "mmcdie", 0);
}
+
+ if (sc->sc_dmap)
+ bus_dmamap_destroy(sc->sc_dmat, sc->sc_dmap);
+
return 0;
}
diff --git a/sys/dev/sdmmc/sdmmc_mem.c b/sys/dev/sdmmc/sdmmc_mem.c
index da2d4c042a0..188d3392d5b 100644
--- a/sys/dev/sdmmc/sdmmc_mem.c
+++ b/sys/dev/sdmmc/sdmmc_mem.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sdmmc_mem.c,v 1.22 2015/11/08 12:10:27 jsg Exp $ */
+/* $OpenBSD: sdmmc_mem.c,v 1.23 2016/04/30 11:32:23 kettenis Exp $ */
/*
* Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
@@ -44,12 +44,12 @@ int sdmmc_mem_sd_init(struct sdmmc_softc *, struct sdmmc_function *);
int sdmmc_mem_mmc_init(struct sdmmc_softc *, struct sdmmc_function *);
int sdmmc_mem_single_read_block(struct sdmmc_function *, int, u_char *,
size_t);
-int sdmmc_mem_read_block_subr(struct sdmmc_function *, int, u_char *,
- size_t);
+int sdmmc_mem_read_block_subr(struct sdmmc_function *, bus_dmamap_t,
+ int, u_char *, size_t);
int sdmmc_mem_single_write_block(struct sdmmc_function *, int, u_char *,
size_t);
-int sdmmc_mem_write_block_subr(struct sdmmc_function *, int, u_char *,
- size_t);
+int sdmmc_mem_write_block_subr(struct sdmmc_function *, bus_dmamap_t,
+ int, u_char *, size_t);
#ifdef SDMMC_DEBUG
#define DPRINTF(s) printf s
@@ -566,8 +566,8 @@ sdmmc_mem_set_blocklen(struct sdmmc_softc *sc, struct sdmmc_function *sf)
}
int
-sdmmc_mem_read_block_subr(struct sdmmc_function *sf, int blkno, u_char *data,
- size_t datalen)
+sdmmc_mem_read_block_subr(struct sdmmc_function *sf, bus_dmamap_t dmap,
+ int blkno, u_char *data, size_t datalen)
{
struct sdmmc_softc *sc = sf->sc;
struct sdmmc_command cmd;
@@ -588,6 +588,7 @@ sdmmc_mem_read_block_subr(struct sdmmc_function *sf, int blkno, u_char *data,
else
cmd.c_arg = blkno << 9;
cmd.c_flags = SCF_CMD_ADTC | SCF_CMD_READ | SCF_RSP_R1;
+ cmd.c_dmamap = dmap;
error = sdmmc_mmc_command(sc, &cmd);
if (error != 0)
@@ -627,8 +628,8 @@ sdmmc_mem_single_read_block(struct sdmmc_function *sf, int blkno, u_char *data,
int i;
for (i = 0; i < datalen / sf->csd.sector_size; i++) {
- error = sdmmc_mem_read_block_subr(sf, blkno + i, data + i *
- sf->csd.sector_size, sf->csd.sector_size);
+ error = sdmmc_mem_read_block_subr(sf, NULL, blkno + i,
+ data + i * sf->csd.sector_size, sf->csd.sector_size);
if (error)
break;
}
@@ -647,17 +648,42 @@ sdmmc_mem_read_block(struct sdmmc_function *sf, int blkno, u_char *data,
if (ISSET(sc->sc_caps, SMC_CAPS_SINGLE_ONLY)) {
error = sdmmc_mem_single_read_block(sf, blkno, data, datalen);
- } else {
- error = sdmmc_mem_read_block_subr(sf, blkno, data, datalen);
+ goto out;
}
+ if (!ISSET(sc->sc_caps, SMC_CAPS_DMA)) {
+ error = sdmmc_mem_read_block_subr(sf, NULL, blkno,
+ data, datalen);
+ goto out;
+ }
+
+ /* DMA transfer */
+ error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmap, data, datalen,
+ NULL, BUS_DMA_NOWAIT|BUS_DMA_READ);
+ if (error)
+ goto out;
+
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmap, 0, datalen,
+ BUS_DMASYNC_PREREAD);
+
+ error = sdmmc_mem_read_block_subr(sf, sc->sc_dmap, blkno, data,
+ datalen);
+ if (error)
+ goto unload;
+
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmap, 0, datalen,
+ BUS_DMASYNC_POSTREAD);
+unload:
+ bus_dmamap_unload(sc->sc_dmat, sc->sc_dmap);
+
+out:
rw_exit(&sc->sc_lock);
return (error);
}
int
-sdmmc_mem_write_block_subr(struct sdmmc_function *sf, int blkno, u_char *data,
- size_t datalen)
+sdmmc_mem_write_block_subr(struct sdmmc_function *sf, bus_dmamap_t dmap,
+ int blkno, u_char *data, size_t datalen)
{
struct sdmmc_softc *sc = sf->sc;
struct sdmmc_command cmd;
@@ -677,6 +703,7 @@ sdmmc_mem_write_block_subr(struct sdmmc_function *sf, int blkno, u_char *data,
else
cmd.c_arg = blkno << 9;
cmd.c_flags = SCF_CMD_ADTC | SCF_RSP_R1;
+ cmd.c_dmamap = dmap;
error = sdmmc_mmc_command(sc, &cmd);
if (error != 0)
@@ -715,8 +742,8 @@ sdmmc_mem_single_write_block(struct sdmmc_function *sf, int blkno, u_char *data,
int i;
for (i = 0; i < datalen / sf->csd.sector_size; i++) {
- error = sdmmc_mem_write_block_subr(sf, blkno + i, data + i *
- sf->csd.sector_size, sf->csd.sector_size);
+ error = sdmmc_mem_write_block_subr(sf, NULL, blkno + i,
+ data + i * sf->csd.sector_size, sf->csd.sector_size);
if (error)
break;
}
@@ -735,10 +762,35 @@ sdmmc_mem_write_block(struct sdmmc_function *sf, int blkno, u_char *data,
if (ISSET(sc->sc_caps, SMC_CAPS_SINGLE_ONLY)) {
error = sdmmc_mem_single_write_block(sf, blkno, data, datalen);
- } else {
- error = sdmmc_mem_write_block_subr(sf, blkno, data, datalen);
+ goto out;
+ }
+
+ if (!ISSET(sc->sc_caps, SMC_CAPS_DMA)) {
+ error = sdmmc_mem_write_block_subr(sf, NULL, blkno,
+ data, datalen);
+ goto out;
}
+ /* DMA transfer */
+ error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmap, data, datalen,
+ NULL, BUS_DMA_NOWAIT|BUS_DMA_WRITE);
+ if (error)
+ goto out;
+
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmap, 0, datalen,
+ BUS_DMASYNC_PREWRITE);
+
+ error = sdmmc_mem_write_block_subr(sf, sc->sc_dmap, blkno, data,
+ datalen);
+ if (error)
+ goto unload;
+
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmap, 0, datalen,
+ BUS_DMASYNC_POSTWRITE);
+unload:
+ bus_dmamap_unload(sc->sc_dmat, sc->sc_dmap);
+
+out:
rw_exit(&sc->sc_lock);
return (error);
}
diff --git a/sys/dev/sdmmc/sdmmcchip.h b/sys/dev/sdmmc/sdmmcchip.h
index 14c772fafb1..4b7eedd5296 100644
--- a/sys/dev/sdmmc/sdmmcchip.h
+++ b/sys/dev/sdmmc/sdmmcchip.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: sdmmcchip.h,v 1.5 2013/09/12 11:54:04 rapha Exp $ */
+/* $OpenBSD: sdmmcchip.h,v 1.6 2016/04/30 11:32:23 kettenis Exp $ */
/*
* Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
@@ -19,6 +19,8 @@
#ifndef _SDMMC_CHIP_H_
#define _SDMMC_CHIP_H_
+#include <machine/bus.h>
+
struct sdmmc_command;
typedef struct sdmmc_chip_functions *sdmmc_chipset_tag_t;
@@ -77,6 +79,7 @@ struct sdmmcbus_attach_args {
const char *saa_busname;
sdmmc_chipset_tag_t sct;
sdmmc_chipset_handle_t sch;
+ bus_dma_tag_t dmat;
int flags;
int caps;
long max_xfer;
diff --git a/sys/dev/sdmmc/sdmmcvar.h b/sys/dev/sdmmc/sdmmcvar.h
index 1da8de541fa..d2d929ed6da 100644
--- a/sys/dev/sdmmc/sdmmcvar.h
+++ b/sys/dev/sdmmc/sdmmcvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: sdmmcvar.h,v 1.22 2013/09/12 11:54:04 rapha Exp $ */
+/* $OpenBSD: sdmmcvar.h,v 1.23 2016/04/30 11:32:23 kettenis Exp $ */
/*
* Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
@@ -22,6 +22,8 @@
#include <sys/queue.h>
#include <sys/rwlock.h>
+#include <machine/bus.h>
+
#include <scsi/scsi_all.h>
#include <scsi/scsiconf.h>
@@ -72,6 +74,7 @@ struct sdmmc_command {
u_int16_t c_opcode; /* SD or MMC command index */
u_int32_t c_arg; /* SD/MMC command argument */
sdmmc_response c_resp; /* response buffer */
+ bus_dmamap_t c_dmamap;
void *c_data; /* buffer to send or read into */
int c_datalen; /* length of data buffer */
int c_blklen; /* block length */
@@ -156,6 +159,11 @@ struct sdmmc_softc {
#define DEVNAME(sc) ((sc)->sc_dev.dv_xname)
sdmmc_chipset_tag_t sct; /* host controller chipset tag */
sdmmc_chipset_handle_t sch; /* host controller chipset handle */
+
+ bus_dma_tag_t sc_dmat;
+ bus_dmamap_t sc_dmap;
+#define SDMMC_MAXNSEGS ((MAXPHYS / PAGE_SIZE) + 1)
+
int sc_flags;
#define SMF_SD_MODE 0x0001 /* host in SD mode (MMC otherwise) */
#define SMF_IO_MODE 0x0002 /* host in I/O mode (SD mode only) */