The diff below implements some speedups for sdhc(4).  In particular:

* Implement high speed mode
* Implement support for 4-bit and 8-bit busses
* Use DMA for block transfers

High speed mode and wider bus support are only used for (e)MMC for
now, but DMA support should benefit SD cards as well.

Most of this code was derived from the imrpovements made over at
NetBSD.  However, I chose to only implement for ADMA2 and not for the
older SDMA and ADMA1 mechanisms.  These older DMA mechanism have
severe limitations and it seems that most of the available hardware
supports ADAM2.  And of course PIO (programmed IO) will continue to
work just fine for hardware that doesn't support ADMA2.

Emulates SCSI transfers continue to be bounced through the sdmmc task
thread.  That probably limits the total throughput a bit.
Nevertheless, with this diff I can read from eMMC in the Lenovo Bay
Trail stick at 40MB/s, which is quite an improvement from the 5MB/s I
reached before.

This is probably several commit's worth of changes, but this provides
them all in an easily testable form.

Please test and/or review.


Index: dev/sdmmc/sdhc.c
===================================================================
RCS file: /cvs/src/sys/dev/sdmmc/sdhc.c,v
retrieving revision 1.43
diff -u -p -r1.43 sdhc.c
--- dev/sdmmc/sdhc.c    30 Mar 2016 09:58:01 -0000      1.43
+++ dev/sdmmc/sdhc.c    28 Apr 2016 10:27:28 -0000
@@ -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 */
@@ -82,8 +87,10 @@ int  sdhc_host_maxblklen(sdmmc_chipset_ha
 int    sdhc_card_detect(sdmmc_chipset_handle_t);
 int    sdhc_bus_power(sdmmc_chipset_handle_t, u_int32_t);
 int    sdhc_bus_clock(sdmmc_chipset_handle_t, int);
+int    sdhc_bus_width(sdmmc_chipset_handle_t, int);
 void   sdhc_card_intr_mask(sdmmc_chipset_handle_t, int);
 void   sdhc_card_intr_ack(sdmmc_chipset_handle_t);
+int    sdhc_signal_voltage(sdmmc_chipset_handle_t, int);
 void   sdhc_exec_command(sdmmc_chipset_handle_t, struct sdmmc_command *);
 int    sdhc_start_command(struct sdhc_host *, struct sdmmc_command *);
 int    sdhc_wait_state(struct sdhc_host *, u_int32_t, u_int32_t);
@@ -112,11 +119,13 @@ struct sdmmc_chip_functions sdhc_functio
        /* bus power and clock frequency */
        sdhc_bus_power,
        sdhc_bus_clock,
+       sdhc_bus_width,
        /* command execution */
        sdhc_exec_command,
        /* card interrupt */
        sdhc_card_intr_mask,
-       sdhc_card_intr_ack
+       sdhc_card_intr_ack,
+       sdhc_signal_voltage
 };
 
 struct cfdriver sdhc_cd = {
@@ -135,6 +144,7 @@ sdhc_host_found(struct sdhc_softc *sc, b
        struct sdhc_host *hp;
        int error = 1;
        int max_clock;
+       uint32_t caps2 = 0;
 #ifdef SDHC_DEBUG
        u_int16_t version;
 
@@ -174,7 +184,7 @@ sdhc_host_found(struct sdhc_softc *sc, b
                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);
 
        /*
@@ -210,6 +220,14 @@ sdhc_host_found(struct sdhc_softc *sc, b
        /*
         * Determine SD bus voltage levels supported by the controller.
         */
+       if (ISSET(caps, SDHC_HIGH_SPEED_SUPP))
+               SET(hp->ocr, MMC_OCR_HCS);
+       if (ISSET(caps2, SDHC_SDR50_SUPP))
+               SET(hp->ocr, MMC_OCR_S18A);
+       if (ISSET(caps2, SDHC_DDR50_SUPP))
+               SET(hp->ocr, MMC_OCR_S18A);
+       if (ISSET(caps2, SDHC_SDR104_SUPP))
+               SET(hp->ocr, MMC_OCR_S18A);
        if (ISSET(caps, SDHC_VOLTAGE_SUPP_1_8V))
                SET(hp->ocr, MMC_OCR_1_65V_1_95V);
        if (ISSET(caps, SDHC_VOLTAGE_SUPP_3_0V))
@@ -236,6 +254,46 @@ sdhc_host_found(struct sdhc_softc *sc, b
                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 +302,16 @@ sdhc_host_found(struct sdhc_softc *sc, b
        saa.saa_busname = "sdmmc";
        saa.sct = &sdhc_functions;
        saa.sch = hp;
+       saa.dmat = sc->sc_dmat;
+       saa.caps = SMC_CAPS_4BIT_MODE;
+
+       if (ISSET(caps, SDHC_HIGH_SPEED_SUPP))
+               saa.caps |= SMC_CAPS_MMC_HIGHSPEED;
+       if (ISSET(caps, SDHC_8BIT_MODE_SUPP))
+               saa.caps |= SMC_CAPS_8BIT_MODE;
+
+       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) {
@@ -486,6 +554,7 @@ sdhc_bus_clock(sdmmc_chipset_handle_t sc
        int sdclk;
        int timo;
        int error = 0;
+//     int ddr = 0;
 
        s = splsdmmc();
 
@@ -503,6 +572,27 @@ sdhc_bus_clock(sdmmc_chipset_handle_t sc
        if (freq == SDMMC_SDCLK_OFF)
                goto ret;
 
+#if 0
+       if (SDHC_SPEC_VERSION(hp->version) >= SDHC_SPEC_V3) {
+               HCLR2(hp, SDHC_HOST_CTL2, SDHC_UHS_MODE_SELECT_MASK);
+               if (freq > 100000) {
+                       HSET2(hp, SDHC_HOST_CTL2, SDHC_UHS_MODE_SELECT_SDR104);
+               } else if (freq > 50000) {
+                       HSET2(hp, SDHC_HOST_CTL2, SDHC_UHS_MODE_SELECT_SDR50);
+               } else if (freq > 25000) {
+                       if (ddr) {
+                               HSET2(hp, SDHC_HOST_CTL2,
+                                   SDHC_UHS_MODE_SELECT_DDR50);
+                       } else {
+                               HSET2(hp, SDHC_HOST_CTL2,
+                                   SDHC_UHS_MODE_SELECT_SDR25);
+                       }
+               } else if (freq > 400) {
+                       HSET2(hp, SDHC_HOST_CTL2, SDHC_UHS_MODE_SELECT_SDR12);
+               }
+       }
+#endif
+
        /*
         * Set the minimum base clock frequency divisor.
         */
@@ -536,11 +626,53 @@ sdhc_bus_clock(sdmmc_chipset_handle_t sc
         */
        HSET2(hp, SDHC_CLOCK_CTL, SDHC_SDCLK_ENABLE);
 
+       if (freq > 25000)
+               HSET1(hp, SDHC_HOST_CTL, SDHC_HIGH_SPEED);
+       else
+               HCLR1(hp, SDHC_HOST_CTL, SDHC_HIGH_SPEED);
+
 ret:
        splx(s);
        return error;
 }
 
+int
+sdhc_bus_width(sdmmc_chipset_handle_t sch, int width)
+{
+       struct sdhc_host *hp = (struct sdhc_host *)sch;
+       int reg;
+       int s;
+
+       switch (width) {
+       case 1:
+       case 4:
+       case 8:
+               break;
+       default:
+               DPRINTF(0,("%s: unsupported bus width (%d)\n",
+                   DEVNAME(hp->sc), width));
+               return 1;
+       }
+
+       s = splsdmmc();
+
+       reg = HREAD1(hp, SDHC_HOST_CTL);
+       reg &= ~SDHC_4BIT_MODE;
+       if (SDHC_SPEC_VERSION(hp->version) >= SDHC_SPEC_V3) {
+               reg &= ~SDHC_8BIT_MODE;
+       }
+       if (width == 4) {
+               reg |= SDHC_4BIT_MODE;
+       } else if (width == 8 && SDHC_SPEC_VERSION(hp->version) >= 
SDHC_SPEC_V3) {
+               reg |= SDHC_8BIT_MODE;
+       }
+       HWRITE1(hp, SDHC_HOST_CTL, reg);
+
+       splx(s);
+
+       return 0;
+}
+
 void
 sdhc_card_intr_mask(sdmmc_chipset_handle_t sch, int enable)
 {
@@ -564,6 +696,32 @@ sdhc_card_intr_ack(sdmmc_chipset_handle_
 }
 
 int
+sdhc_signal_voltage(sdmmc_chipset_handle_t sch, int signal_voltage)
+{
+       struct sdhc_host *hp = (struct sdhc_host *)sch;
+       int error = 0;
+       int s;
+
+       s = splsdmmc();
+
+       switch (signal_voltage) {
+       case SDMMC_SIGNAL_VOLTAGE_180:
+               HSET2(hp, SDHC_HOST_CTL2, SDHC_1_8V_SIGNAL_EN);
+               break;
+       case SDMMC_SIGNAL_VOLTAGE_330:
+               HCLR2(hp, SDHC_HOST_CTL2, SDHC_1_8V_SIGNAL_EN);
+               break;
+       default:
+               error = EINVAL;
+               break;
+       }
+
+       splx(s);
+
+       return error;
+}
+
+int
 sdhc_wait_state(struct sdhc_host *hp, u_int32_t mask, u_int32_t value)
 {
        u_int32_t state;
@@ -641,11 +799,14 @@ sdhc_exec_command(sdmmc_chipset_handle_t
 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 +849,9 @@ sdhc_start_command(struct sdhc_host *hp,
                        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)
@@ -725,6 +885,34 @@ sdhc_start_command(struct sdhc_host *hp,
        HSET1(hp, SDHC_HOST_CTL, SDHC_LED_ON);
 
        /* XXX: 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 +940,25 @@ sdhc_transfer_data(struct sdhc_host *hp,
        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 +999,7 @@ sdhc_transfer_data(struct sdhc_host *hp,
            SDHC_TRANSFER_TIMEOUT))
                error = ETIMEDOUT;
 
+done:
        if (error != 0)
                cmd->c_error = error;
        SET(cmd->c_flags, SCF_ITSDONE);
Index: dev/sdmmc/sdhcreg.h
===================================================================
RCS file: /cvs/src/sys/dev/sdmmc/sdhcreg.h,v
retrieving revision 1.5
diff -u -p -r1.5 sdhcreg.h
--- dev/sdmmc/sdhcreg.h 11 Jan 2016 06:54:53 -0000      1.5
+++ dev/sdmmc/sdhcreg.h 28 Apr 2016 10:27:29 -0000
@@ -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
@@ -201,5 +238,19 @@
        "\20\11ACMD12\10CL\7DEB\6DCRC\5DT\4CI\3CEB\2CCRC\1CT"
 #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
Index: dev/sdmmc/sdhcvar.h
===================================================================
RCS file: /cvs/src/sys/dev/sdmmc/sdhcvar.h,v
retrieving revision 1.8
diff -u -p -r1.8 sdhcvar.h
--- dev/sdmmc/sdhcvar.h 30 Mar 2016 09:58:01 -0000      1.8
+++ dev/sdmmc/sdhcvar.h 28 Apr 2016 10:27:29 -0000
@@ -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 *);
 };
 
Index: dev/sdmmc/sdmmc.c
===================================================================
RCS file: /cvs/src/sys/dev/sdmmc/sdmmc.c,v
retrieving revision 1.39
diff -u -p -r1.39 sdmmc.c
--- dev/sdmmc/sdmmc.c   19 Mar 2016 11:41:56 -0000      1.39
+++ dev/sdmmc/sdmmc.c   28 Apr 2016 10:27:29 -0000
@@ -97,14 +97,25 @@ sdmmc_attach(struct device *parent, stru
 {
        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("QQQ\n");
+                       return;
+               }
+       }
 
        SIMPLEQ_INIT(&sc->sf_head);
        TAILQ_INIT(&sc->sc_tskq);
Index: dev/sdmmc/sdmmc_mem.c
===================================================================
RCS file: /cvs/src/sys/dev/sdmmc/sdmmc_mem.c,v
retrieving revision 1.22
diff -u -p -r1.22 sdmmc_mem.c
--- dev/sdmmc/sdmmc_mem.c       8 Nov 2015 12:10:27 -0000       1.22
+++ dev/sdmmc/sdmmc_mem.c       28 Apr 2016 10:27:29 -0000
@@ -40,16 +40,18 @@ int sdmmc_mem_set_blocklen(struct sdmmc_
 int    sdmmc_mem_send_cxd_data(struct sdmmc_softc *, int, void *, size_t);
 int    sdmmc_mem_mmc_switch(struct sdmmc_function *, uint8_t, uint8_t, 
uint8_t);
 
+int    sdmmc_mem_signal_voltage(struct sdmmc_softc *, int);
+
 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
@@ -65,6 +67,8 @@ sdmmc_mem_enable(struct sdmmc_softc *sc)
 {
        u_int32_t host_ocr;
        u_int32_t card_ocr;
+       u_int32_t new_ocr;
+       int error;
 
        rw_assert_wrlock(&sc->sc_lock);
 
@@ -116,13 +120,79 @@ sdmmc_mem_enable(struct sdmmc_softc *sc)
                host_ocr |= SD_OCR_SDHC_CAP;
 
        /* Send the new OCR value until all cards are ready. */
-       if (sdmmc_mem_send_op_cond(sc, host_ocr, NULL) != 0) {
+       if (sdmmc_mem_send_op_cond(sc, host_ocr, &new_ocr) != 0) {
                DPRINTF(("%s: can't send memory OCR\n", DEVNAME(sc)));
                return 1;
        }
+
+       if (ISSET(sc->sc_flags, SMF_SD_MODE) && ISSET(new_ocr, MMC_OCR_S18A)) {
+               /*
+                * Card and host support low voltage mode, begin switch
+                * sequence.
+                */
+               struct sdmmc_command cmd;
+               memset(&cmd, 0, sizeof(cmd));
+               cmd.c_arg = 0;
+               cmd.c_flags = SCF_CMD_AC | SCF_RSP_R1;
+               cmd.c_opcode = SD_VOLTAGE_SWITCH;
+               DPRINTF(("%s: switching card to 1.8V\n", SDMMCDEVNAME(sc)));
+               error = sdmmc_mmc_command(sc, &cmd);
+               if (error) {
+                       DPRINTF(("%s: voltage switch command failed\n",
+                           DEVNAME(sc)));
+                       return 1;
+               }
+
+               error = sdmmc_mem_signal_voltage(sc, SDMMC_SIGNAL_VOLTAGE_180);
+               if (error)
+                       return 1;
+
+               SET(sc->sc_flags, SMF_UHS_MODE);
+       }
+
        return 0;
 }
 
+int
+sdmmc_mem_signal_voltage(struct sdmmc_softc *sc, int signal_voltage)
+{
+       int error;
+
+       /*
+        * Stop the clock
+        */
+       error = sdmmc_chip_bus_clock(sc->sct, sc->sch, SDMMC_SDCLK_OFF);
+       if (error)
+               goto out;
+
+       delay(1000);
+
+       /*
+        * Card switch command was successful, update host controller
+        * signal voltage setting.
+        */
+       DPRINTF(("%s: switching host to %s\n", DEVNAME(sc),
+           signal_voltage == SDMMC_SIGNAL_VOLTAGE_180 ? "1.8V" : "3.3V"));
+       error = sdmmc_chip_signal_voltage(sc->sct,
+           sc->sch, signal_voltage);
+       if (error)
+               goto out;
+
+       delay(5000);
+
+       /*
+        * Switch to SDR12 timing
+        */
+       error = sdmmc_chip_bus_clock(sc->sct, sc->sch, 25000);
+       if (error)
+               goto out;
+
+       delay(1000);
+
+out:
+       return error;
+}
+
 /*
  * Read the CSD and CID from all cards and assign each card a unique
  * relative card address (RCA).  CMD2 is ignored by SDIO-only cards.
@@ -424,6 +494,7 @@ sdmmc_mem_sd_init(struct sdmmc_softc *sc
 int
 sdmmc_mem_mmc_init(struct sdmmc_softc *sc, struct sdmmc_function *sf)
 {
+       int width, value;
        int error = 0;
        u_int8_t ext_csd[512];
        int speed = 0;
@@ -449,6 +520,34 @@ sdmmc_mem_mmc_init(struct sdmmc_softc *s
                        printf("%s: unknown CARD_TYPE 0x%x\n", DEVNAME(sc),
                            ext_csd[EXT_CSD_CARD_TYPE]);
                }
+
+               if (ISSET(sc->sc_caps, SMC_CAPS_8BIT_MODE)) {
+                       width = 8;
+                       value = EXT_CSD_BUS_WIDTH_8;
+               } else if (ISSET(sc->sc_caps, SMC_CAPS_4BIT_MODE)) {
+                       width = 4;
+                       value = EXT_CSD_BUS_WIDTH_4;
+               } else {
+                       width = 1;
+                       value = EXT_CSD_BUS_WIDTH_1;
+               }
+
+               if (width != 1) {
+                       error = sdmmc_mem_mmc_switch(sf, EXT_CSD_CMD_SET_NORMAL,
+                           EXT_CSD_BUS_WIDTH, value);
+                       if (error == 0)
+                               error = sdmmc_chip_bus_width(sc->sct,
+                                   sc->sch, width);
+                       else {
+                               DPRINTF(("%s: can't change bus width"
+                                   " (%d bit)\n", SDMMCDEVNAME(sc), width));
+                               return error;
+                       }
+
+                       /* XXXX: need bus test? (using by CMD14 & CMD19) */
+                       delay(10000);
+               }
+
                if (!ISSET(sc->sc_caps, SMC_CAPS_MMC_HIGHSPEED))
                        hs_timing = 0;
 
@@ -461,10 +560,11 @@ sdmmc_mem_mmc_init(struct sdmmc_softc *s
                                    DEVNAME(sc));
                                return error;
                        }
+
+                       delay(10000);
                }
 
-               error =
-                   sdmmc_chip_bus_clock(sc->sct, sc->sch, speed);
+               error = sdmmc_chip_bus_clock(sc->sct, sc->sch, speed);
                if (error != 0) {
                        printf("%s: can't change bus clock\n", DEVNAME(sc));
                        return error;
@@ -478,7 +578,7 @@ sdmmc_mem_mmc_init(struct sdmmc_softc *s
                                printf("%s: can't re-read EXT_CSD\n", 
DEVNAME(sc));
                                return error;
                        }
-                       if (ext_csd[EXT_CSD_HS_TIMING] != 1) {
+                       if (ext_csd[EXT_CSD_HS_TIMING] != hs_timing) {
                                printf("%s, HS_TIMING set failed\n", 
DEVNAME(sc));
                                return EINVAL;
                        }
@@ -566,8 +666,8 @@ sdmmc_mem_set_blocklen(struct sdmmc_soft
 }
 
 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 +688,7 @@ sdmmc_mem_read_block_subr(struct sdmmc_f
        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 +728,8 @@ sdmmc_mem_single_read_block(struct sdmmc
        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 +748,42 @@ sdmmc_mem_read_block(struct sdmmc_functi
 
        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 +803,7 @@ sdmmc_mem_write_block_subr(struct sdmmc_
        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 +842,8 @@ sdmmc_mem_single_write_block(struct sdmm
        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 +862,35 @@ sdmmc_mem_write_block(struct sdmmc_funct
 
        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);
 }
Index: dev/sdmmc/sdmmcchip.h
===================================================================
RCS file: /cvs/src/sys/dev/sdmmc/sdmmcchip.h,v
retrieving revision 1.5
diff -u -p -r1.5 sdmmcchip.h
--- dev/sdmmc/sdmmcchip.h       12 Sep 2013 11:54:04 -0000      1.5
+++ dev/sdmmc/sdmmcchip.h       28 Apr 2016 10:27:29 -0000
@@ -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;
@@ -32,15 +34,21 @@ struct sdmmc_chip_functions {
        int     (*host_maxblklen)(sdmmc_chipset_handle_t);
        /* card detection */
        int     (*card_detect)(sdmmc_chipset_handle_t);
-       /* bus power and clock frequency */
+       /* bus power, clock frequency and width */
        int     (*bus_power)(sdmmc_chipset_handle_t, u_int32_t);
        int     (*bus_clock)(sdmmc_chipset_handle_t, int);
+       int     (*bus_width)(sdmmc_chipset_handle_t, int);
        /* command execution */
        void    (*exec_command)(sdmmc_chipset_handle_t,
                    struct sdmmc_command *);
        /* card interrupt */
        void    (*card_intr_mask)(sdmmc_chipset_handle_t, int);
        void    (*card_intr_ack)(sdmmc_chipset_handle_t);
+
+       /* UHS functions */
+       int     (*signal_voltage)(sdmmc_chipset_handle_t, int);
+       int     (*bus_clock_ddr)(sdmmc_chipset_handle_t, int, bool);
+       int     (*execute_tuning)(sdmmc_chipset_handle_t, int);
 };
 
 /* host controller reset */
@@ -59,6 +67,8 @@ struct sdmmc_chip_functions {
        ((tag)->bus_power((handle), (ocr)))
 #define sdmmc_chip_bus_clock(tag, handle, freq)                                
\
        ((tag)->bus_clock((handle), (freq)))
+#define sdmmc_chip_bus_width(tag, handle, width)                       \
+       ((tag)->bus_width((handle), (width)))
 /* command execution */
 #define sdmmc_chip_exec_command(tag, handle, cmdp)                     \
        ((tag)->exec_command((handle), (cmdp)))
@@ -67,16 +77,26 @@ struct sdmmc_chip_functions {
        ((tag)->card_intr_mask((handle), (enable)))
 #define sdmmc_chip_card_intr_ack(tag, handle)                          \
        ((tag)->card_intr_ack((handle)))
+/* UHS functions */
+#define sdmmc_chip_signal_voltage(tag, handle, voltage)                        
\
+       ((tag)->signal_voltage((handle), (voltage)))
+#define sdmmc_chip_execute_tuning(tag, handle, timing)                 \
+       ((tag)->execute_tuning ? (tag)->execute_tuning((handle), (timing)) : 
EINVAL)
 
 /* clock frequencies for sdmmc_chip_bus_clock() */
 #define SDMMC_SDCLK_OFF                0
 #define SDMMC_SDCLK_400KHZ     400
 #define SDMMC_SDCLK_25MHZ      25000
 
+/* voltage levels for sdmmc_chip_signal_voltage() */
+#define SDMMC_SIGNAL_VOLTAGE_330       0
+#define SDMMC_SIGNAL_VOLTAGE_180       1
+
 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;
Index: dev/sdmmc/sdmmcreg.h
===================================================================
RCS file: /cvs/src/sys/dev/sdmmc/sdmmcreg.h,v
retrieving revision 1.8
diff -u -p -r1.8 sdmmcreg.h
--- dev/sdmmc/sdmmcreg.h        10 Jan 2016 14:11:43 -0000      1.8
+++ dev/sdmmc/sdmmcreg.h        28 Apr 2016 10:27:29 -0000
@@ -41,6 +41,7 @@
 /* SD commands */                              /* response type */
 #define SD_SEND_RELATIVE_ADDR          3       /* R6 */
 #define SD_SEND_IF_COND                        8       /* R7 */
+#define SD_VOLTAGE_SWITCH              11      /* R1 */
 
 /* SD application commands */                  /* response type */
 #define SD_APP_SET_BUS_WIDTH           6       /* R1 */
@@ -48,9 +49,11 @@
 
 /* OCR bits */
 #define MMC_OCR_MEM_READY              (1<<31) /* memory power-up status bit */
+#define MMC_OCR_HCS                    (1<<30) /* SD only */
 #define MMC_OCR_ACCESS_MODE_MASK       0x60000000 /* bits 30:29 */
 #define MMC_OCR_SECTOR_MODE            (1<<30)
 #define MMC_OCR_BYTE_MODE              (1<<29)
+#define MMC_OCR_S18A                   (1<<24)
 #define MMC_OCR_3_5V_3_6V              (1<<23)
 #define MMC_OCR_3_4V_3_5V              (1<<22)
 #define MMC_OCR_3_3V_3_4V              (1<<21)
Index: dev/sdmmc/sdmmcvar.h
===================================================================
RCS file: /cvs/src/sys/dev/sdmmc/sdmmcvar.h,v
retrieving revision 1.22
diff -u -p -r1.22 sdmmcvar.h
--- dev/sdmmc/sdmmcvar.h        12 Sep 2013 11:54:04 -0000      1.22
+++ dev/sdmmc/sdmmcvar.h        28 Apr 2016 10:27:29 -0000
@@ -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) */
@@ -164,6 +172,7 @@ struct sdmmc_softc {
 #define SMF_CARD_ATTACHED      0x0020  /* card driver(s) attached */
 #define        SMF_STOP_AFTER_MULTIPLE 0x0040  /* send a stop after a multiple 
cmd */
 #define SMF_CONFIG_PENDING     0x0080  /* config_pending_incr() called */
+#define SMF_UHS_MODE           0x1000  /* host in UHS mode */
 
        uint32_t sc_caps;               /* host capability */
 #define SMC_CAPS_AUTO_STOP     0x0001  /* send CMD12 automagically by host */
Index: dev/acpi/sdhc_acpi.c
===================================================================
RCS file: /cvs/src/sys/dev/acpi/sdhc_acpi.c,v
retrieving revision 1.7
diff -u -p -r1.7 sdhc_acpi.c
--- dev/acpi/sdhc_acpi.c        26 Apr 2016 19:10:10 -0000      1.7
+++ dev/acpi/sdhc_acpi.c        28 Apr 2016 10:27:29 -0000
@@ -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, 
        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
Index: dev/ic/rtsx.c
===================================================================
RCS file: /cvs/src/sys/dev/ic/rtsx.c,v
retrieving revision 1.12
diff -u -p -r1.12 rtsx.c
--- dev/ic/rtsx.c       28 Apr 2015 07:55:13 -0000      1.12
+++ dev/ic/rtsx.c       28 Apr 2016 10:27:29 -0000
@@ -146,6 +146,7 @@ struct sdmmc_chip_functions rtsx_functio
        /* bus power and clock frequency */
        rtsx_bus_power,
        rtsx_bus_clock,
+       NULL,
        /* command execution */
        rtsx_exec_command,
        /* card interrupt */
Index: dev/pci/sdhc_pci.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/sdhc_pci.c,v
retrieving revision 1.19
diff -u -p -r1.19 sdhc_pci.c
--- dev/pci/sdhc_pci.c  24 Nov 2015 19:38:01 -0000      1.19
+++ dev/pci/sdhc_pci.c  28 Apr 2016 10:27:30 -0000
@@ -149,6 +149,7 @@ sdhc_pci_attach(struct device *parent, s
 
        /* 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.
Index: arch/armv7/exynos/exesdhc.c
===================================================================
RCS file: /cvs/src/sys/arch/armv7/exynos/exesdhc.c,v
retrieving revision 1.5
diff -u -p -r1.5 exesdhc.c
--- arch/armv7/exynos/exesdhc.c 24 Apr 2016 00:57:23 -0000      1.5
+++ arch/armv7/exynos/exesdhc.c 28 Apr 2016 10:27:30 -0000
@@ -228,6 +228,7 @@ struct sdmmc_chip_functions exesdhc_func
        /* bus power and clock frequency */
        exesdhc_bus_power,
        exesdhc_bus_clock,
+       NULL,
        /* command execution */
        exesdhc_exec_command,
        /* card interrupt */
Index: arch/armv7/imx/imxesdhc.c
===================================================================
RCS file: /cvs/src/sys/arch/armv7/imx/imxesdhc.c,v
retrieving revision 1.13
diff -u -p -r1.13 imxesdhc.c
--- arch/armv7/imx/imxesdhc.c   10 Jan 2016 14:11:43 -0000      1.13
+++ arch/armv7/imx/imxesdhc.c   28 Apr 2016 10:27:30 -0000
@@ -226,6 +226,7 @@ struct sdmmc_chip_functions imxesdhc_fun
        /* bus power and clock frequency */
        imxesdhc_bus_power,
        imxesdhc_bus_clock,
+       NULL,
        /* command execution */
        imxesdhc_exec_command,
        /* card interrupt */



Reply via email to