> Date: Thu, 28 Apr 2016 12:28:59 +0200 (CEST)
> From: Mark Kettenis <[email protected]>
> 
> 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.

jsg@ noticed I missed ommc(4) on armv7.  New diff below.

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 11:24:08 -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 11:24:08 -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 11:24:08 -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 11:24:08 -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 11:24:08 -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 11:24:08 -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 11:24:08 -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 11:24:08 -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 11:24:08 -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 11:24:09 -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 11:24:09 -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 11:24:09 -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 11:24:09 -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 */
Index: arch/armv7/omap/ommmc.c
===================================================================
RCS file: /cvs/src/sys/arch/armv7/omap/ommmc.c,v
retrieving revision 1.15
diff -u -p -r1.15 ommmc.c
--- arch/armv7/omap/ommmc.c     10 Jan 2016 14:11:43 -0000      1.15
+++ arch/armv7/omap/ommmc.c     28 Apr 2016 11:24:09 -0000
@@ -260,6 +260,7 @@ struct sdmmc_chip_functions ommmc_functi
        /* bus power and clock frequency */
        ommmc_bus_power,
        ommmc_bus_clock,
+       NULL,
        /* command execution */
        ommmc_exec_command,
        /* card interrupt */

Reply via email to