Hi tech@

Here is a diff that updates our sdmmc stack with support for
other frequencies than 25Mhz and for 4 pins transfers. Big
chunks of this code comes directly from NetBSD sdmmc stack.

Normally this diff should speedup things for some sdcards and
for some controllers.

I tried this diff on the only sdmmc controller I have (ommmc).
It will be awesome if people could give me feedback for these
drivers :

 rtsx
 sdhc
 imxesdhc
 pxammc
 w83l518d_sdmmc

Any OK/Comments ?

Index: arch/arm/xscale/pxa2x0_mmc.c
===================================================================
RCS file: /cvs/src/sys/arch/arm/xscale/pxa2x0_mmc.c,v
retrieving revision 1.11
diff -u -p -u -p -r1.11 pxa2x0_mmc.c
--- arch/arm/xscale/pxa2x0_mmc.c        22 Aug 2012 13:37:04 -0000      1.11
+++ arch/arm/xscale/pxa2x0_mmc.c        6 Nov 2013 16:59:38 -0000
@@ -56,6 +56,7 @@ u_int32_t pxammc_host_ocr(sdmmc_chipset_
 int    pxammc_host_maxblklen(sdmmc_chipset_handle_t);
 int    pxammc_card_detect(sdmmc_chipset_handle_t);
 int    pxammc_bus_power(sdmmc_chipset_handle_t, u_int32_t);
+int    pxammc_bus_width(sdmmc_chipset_handle_t, int);
 int    pxammc_bus_clock(sdmmc_chipset_handle_t, int);
 void   pxammc_exec_command(sdmmc_chipset_handle_t, struct sdmmc_command *);
 void   pxammc_clock_stop(struct pxammc_softc *);
@@ -90,6 +91,7 @@ struct sdmmc_chip_functions pxammc_funct
        /* bus power and clock frequency */
        pxammc_bus_power,
        pxammc_bus_clock,
+       pxammc_bus_width,
        /* command execution */
        pxammc_exec_command
 };
@@ -179,6 +181,8 @@ pxammc_attach(struct pxammc_softc *sc, v
         */
        bzero(&saa, sizeof saa);
        saa.saa_busname = "sdmmc";
+       saa.saa_clkmax = SDMMC_SDCLK_25MHZ;
+
        saa.sct = &pxammc_functions;
        saa.sch = sc;
        saa.flags = SMF_STOP_AFTER_MULTIPLE;
@@ -274,6 +278,12 @@ pxammc_bus_power(sdmmc_chipset_handle_t 
        DPRINTF(0,("%s: driver lacks set_power() function\n",
            sc->sc_dev.dv_xname));
        return ENXIO;
+}
+
+int
+pxammc_bus_width(sdmmc_chipset_handle_t sch, int width)
+{
+       return (0);
 }
 
 int
Index: arch/armv7/imx/imxesdhc.c
===================================================================
RCS file: /cvs/src/sys/arch/armv7/imx/imxesdhc.c,v
retrieving revision 1.3
diff -u -p -u -p -r1.3 imxesdhc.c
--- arch/armv7/imx/imxesdhc.c   27 Oct 2013 20:27:09 -0000      1.3
+++ arch/armv7/imx/imxesdhc.c   6 Nov 2013 16:59:43 -0000
@@ -195,6 +195,7 @@ int imxesdhc_host_maxblklen(sdmmc_chipse
 int    imxesdhc_card_detect(sdmmc_chipset_handle_t);
 int    imxesdhc_bus_power(sdmmc_chipset_handle_t, uint32_t);
 int    imxesdhc_bus_clock(sdmmc_chipset_handle_t, int);
+int    imxesdhc_bus_width(sdmmc_chipset_handle_t, int);
 void   imxesdhc_card_intr_mask(sdmmc_chipset_handle_t, int);
 void   imxesdhc_card_intr_ack(sdmmc_chipset_handle_t);
 void   imxesdhc_exec_command(sdmmc_chipset_handle_t, struct sdmmc_command *);
@@ -225,6 +226,7 @@ struct sdmmc_chip_functions imxesdhc_fun
        /* bus power and clock frequency */
        imxesdhc_bus_power,
        imxesdhc_bus_clock,
+       imxesdhc_bus_width,
        /* command execution */
        imxesdhc_exec_command,
        /* card interrupt */
@@ -319,6 +321,7 @@ imxesdhc_attach(struct device *parent, s
 
        bzero(&saa, sizeof(saa));
        saa.saa_busname = "sdmmc";
+       saa.saa_clkmax = SDMMC_SDCLK_25MHZ;
        saa.sct = &imxesdhc_functions;
        saa.sch = sc;
 
@@ -327,7 +330,7 @@ imxesdhc_attach(struct device *parent, s
                error = 0;
                goto err;
        }
-       
+
        return;
 
 err:
@@ -483,6 +486,12 @@ imxesdhc_card_detect(sdmmc_chipset_handl
  */
 int
 imxesdhc_bus_power(sdmmc_chipset_handle_t sch, uint32_t ocr)
+{
+       return 0;
+}
+
+int
+imxesdhc_bus_width(sdmmc_chipset_handle_t sch, int freq)
 {
        return 0;
 }
Index: arch/armv7/omap/ommmc.c
===================================================================
RCS file: /cvs/src/sys/arch/armv7/omap/ommmc.c,v
retrieving revision 1.9
diff -u -p -u -p -r1.9 ommmc.c
--- arch/armv7/omap/ommmc.c     28 Oct 2013 20:45:20 -0000      1.9
+++ arch/armv7/omap/ommmc.c     6 Nov 2013 16:59:43 -0000
@@ -228,6 +228,7 @@ int ommmc_host_maxblklen(sdmmc_chipset_h
 int    ommmc_card_detect(sdmmc_chipset_handle_t);
 int    ommmc_bus_power(sdmmc_chipset_handle_t, uint32_t);
 int    ommmc_bus_clock(sdmmc_chipset_handle_t, int);
+int    ommmc_bus_width(sdmmc_chipset_handle_t, int);
 void   ommmc_card_intr_mask(sdmmc_chipset_handle_t, int);
 void   ommmc_card_intr_ack(sdmmc_chipset_handle_t);
 void   ommmc_exec_command(sdmmc_chipset_handle_t, struct sdmmc_command *);
@@ -259,6 +260,7 @@ struct sdmmc_chip_functions ommmc_functi
        /* bus power and clock frequency */
        ommmc_bus_power,
        ommmc_bus_clock,
+       ommmc_bus_width,
        /* command execution */
        ommmc_exec_command,
        /* card interrupt */
@@ -386,9 +388,10 @@ ommmc_attach(struct device *parent, stru
         */
        bzero(&saa, sizeof(saa));
        saa.saa_busname = "sdmmc";
+       saa.saa_clkmax = 96000;
        saa.sct = &ommmc_functions;
        saa.sch = sc;
-       saa.caps = 0;
+       saa.caps = SMC_CAPS_4BIT_MODE;
        if (caps & MMCHS_CAPA_HSS)
                saa.caps |= SMC_CAPS_MMC_HIGHSPEED;
 
@@ -624,6 +627,30 @@ ommmc_clock_divisor(struct ommmc_softc *
        printf("divisor failure\n");
        /* No divisor found. */
        return (-1);
+}
+
+int
+ommmc_bus_width(sdmmc_chipset_handle_t sch, int width)
+{
+       struct ommmc_softc *sc = sch;
+
+       switch (width) {
+       case 1:
+               printf("%s: BW 1\n", DEVNAME(sc));
+               HCLR4(sc, MMCHS_HCTL, MMCHS_HCTL_DTW);
+               HCLR4(sc, MMCHS_CON, MMCHS_CON_DW8);
+               break;
+       case 4:
+               printf("%s: BW 4\n", DEVNAME(sc));
+               HSET4(sc, MMCHS_HCTL, MMCHS_HCTL_DTW);
+               HCLR4(sc, MMCHS_CON, MMCHS_CON_DW8);
+               break;
+       default:
+               printf("%s: bus width %i not supported\n", DEVNAME(sc), width);
+               break;
+       }
+
+       return (0);
 }
 
 /*
Index: dev/ic/rtsx.c
===================================================================
RCS file: /cvs/src/sys/dev/ic/rtsx.c,v
retrieving revision 1.5
diff -u -p -u -p -r1.5 rtsx.c
--- dev/ic/rtsx.c       6 Nov 2013 13:51:02 -0000       1.5
+++ dev/ic/rtsx.c       6 Nov 2013 16:59:44 -0000
@@ -97,6 +97,7 @@ int   rtsx_host_maxblklen(sdmmc_chipset_ha
 int    rtsx_card_detect(sdmmc_chipset_handle_t);
 int    rtsx_bus_power(sdmmc_chipset_handle_t, u_int32_t);
 int    rtsx_bus_clock(sdmmc_chipset_handle_t, int);
+int    rtsx_bus_width(sdmmc_chipset_handle_t, int);
 void   rtsx_exec_command(sdmmc_chipset_handle_t, struct sdmmc_command *);
 int    rtsx_init(struct rtsx_softc *, int);
 void   rtsx_soft_reset(struct rtsx_softc *);
@@ -147,6 +148,7 @@ struct sdmmc_chip_functions rtsx_functio
        /* bus power and clock frequency */
        rtsx_bus_power,
        rtsx_bus_clock,
+       rtsx_bus_width,
        /* command execution */
        rtsx_exec_command,
        /* card interrupt */
@@ -196,8 +198,10 @@ rtsx_attach(struct rtsx_softc *sc, bus_s
         */
        bzero(&saa, sizeof(saa));
        saa.saa_busname = "sdmmc";
+       saa.saa_clkmax = SDMMC_SDCLK_25MHZ;
        saa.sct = &rtsx_functions;
        saa.sch = sc;
+       saa.caps = SMC_CAPS_4BIT_MODE;
        saa.flags = SMF_STOP_AFTER_MULTIPLE;
 
        sc->sdmmc = config_found(&sc->sc_dev, &saa, NULL);
@@ -207,7 +211,7 @@ rtsx_attach(struct rtsx_softc *sc, bus_s
        /* Now handle cards discovered during attachment. */
        if (ISSET(sc->flags, RTSX_F_CARD_PRESENT))
                rtsx_card_insert(sc);
-       
+
        return 0;
 }
 
@@ -602,14 +606,19 @@ rtsx_bus_power(sdmmc_chipset_handle_t sc
                goto ret;
        }
 
-       error = rtsx_set_bus_width(sc, 1);
-       if (error)
-               goto ret;
 
        error = rtsx_bus_power_on(sc);
 ret:
        splx(s);
        return error;
+}
+
+int
+rtsx_bus_width(sdmmc_chipset_handle_t sch, int width)
+{
+       struct rtsx_softc *sc = sch;
+
+       return (rtsx_set_bus_width(sc, width));
 }
 
 /*
Index: dev/ic/w83l518d_sdmmc.c
===================================================================
RCS file: /cvs/src/sys/dev/ic/w83l518d_sdmmc.c,v
retrieving revision 1.1
diff -u -p -u -p -r1.1 w83l518d_sdmmc.c
--- dev/ic/w83l518d_sdmmc.c     3 Oct 2009 19:51:53 -0000       1.1
+++ dev/ic/w83l518d_sdmmc.c     6 Nov 2013 16:59:44 -0000
@@ -66,9 +66,7 @@ int   wb_sdmmc_write_protect(sdmmc_chipset
 #endif
 int    wb_sdmmc_bus_power(sdmmc_chipset_handle_t, uint32_t);
 int    wb_sdmmc_bus_clock(sdmmc_chipset_handle_t, int);
-#if 0
 int    wb_sdmmc_bus_width(sdmmc_chipset_handle_t, int);
-#endif
 void   wb_sdmmc_exec_command(sdmmc_chipset_handle_t,
                              struct sdmmc_command *);
 void   wb_sdmmc_card_intr_mask(sdmmc_chipset_handle_t, int);
@@ -85,12 +83,10 @@ struct sdmmc_chip_functions wb_sdmmc_chi
 #ifdef notyet
        .write_protect = wb_sdmmc_write_protect,
 #endif
-       /* bus power and clock frequency */
+       /* bus power, width and clock frequency */
        wb_sdmmc_bus_power,
        wb_sdmmc_bus_clock,
-#if 0
-       .bus_width = wb_sdmmc_bus_width,
-#endif
+       wb_sdmmc_bus_width,
        /* command execution */
        wb_sdmmc_exec_command,
        /* card interrupt */
@@ -190,6 +186,7 @@ wb_sdmmc_attach(struct wb_softc *wb)
 
        memset(&saa, 0, sizeof(saa));
        saa.saa_busname = "sdmmc";
+       saa.saa_clkmax = SDMMC_SDCLK_25MHZ;
        saa.sct = &wb_sdmmc_chip_functions;
        saa.sch = wb;
        saa.flags = SMF_STOP_AFTER_MULTIPLE;
@@ -279,6 +276,14 @@ wb_sdmmc_bus_power(sdmmc_chipset_handle_
        REPORT(sch, "TRACE: sdmmc/bus_power(wb, ocr=%d)\n", ocr);
 
        return 0;
+}
+
+int
+wb_sdmmc_bus_width(sdmmc_chipset_handle_t sch, int width)
+{
+       REPORT(sch, "TRACE: sdmmc/bus_width(wb, width=%d)\n", width);
+
+       return (0);
 }
 
 int
Index: dev/sdmmc/sdhc.c
===================================================================
RCS file: /cvs/src/sys/dev/sdmmc/sdhc.c,v
retrieving revision 1.36
diff -u -p -u -p -r1.36 sdhc.c
--- dev/sdmmc/sdhc.c    31 May 2013 21:28:32 -0000      1.36
+++ dev/sdmmc/sdhc.c    6 Nov 2013 16:59:44 -0000
@@ -82,6 +82,7 @@ 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);
 void   sdhc_exec_command(sdmmc_chipset_handle_t, struct sdmmc_command *);
@@ -112,6 +113,7 @@ 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 */
@@ -231,6 +233,8 @@ sdhc_host_found(struct sdhc_softc *sc, b
        bzero(&saa, sizeof(saa));
        saa.saa_busname = "sdmmc";
        saa.sct = &sdhc_functions;
+       saa.saa_clkmax = hp->clkbase;
+       saa.caps = SMC_CAPS_4BIT_MODE;
        saa.sch = hp;
 
        hp->sdmmc = config_found(&sc->sc_dev, &saa, NULL);
@@ -238,7 +242,7 @@ sdhc_host_found(struct sdhc_softc *sc, b
                error = 0;
                goto err;
        }
-       
+
        return 0;
 
 err:
@@ -457,6 +461,22 @@ sdhc_clock_divisor(struct sdhc_host *hp,
  * Set or change SDCLK frequency or disable the SD clock.
  * Return zero on success.
  */
+int
+sdhc_bus_width(sdmmc_chipset_handle_t sch, int width)
+{
+       struct sdhc_host *hp = (struct sdhc_host *)sch;
+       int reg;
+
+       reg = HREAD1(hp, SDHC_HOST_CTL);
+       reg &= ~SDHC_4BIT_MODE;
+       if (width == 4)
+               reg |= SDHC_4BIT_MODE;
+
+       HWRITE1(hp, SDHC_HOST_CTL, reg);
+
+       return (0);
+}
+
 int
 sdhc_bus_clock(sdmmc_chipset_handle_t sch, int freq)
 {
Index: dev/sdmmc/sdmmc.c
===================================================================
RCS file: /cvs/src/sys/dev/sdmmc/sdmmc.c,v
retrieving revision 1.28
diff -u -p -u -p -r1.28 sdmmc.c
--- dev/sdmmc/sdmmc.c   12 Sep 2013 11:54:04 -0000      1.28
+++ dev/sdmmc/sdmmc.c   6 Nov 2013 16:59:44 -0000
@@ -106,6 +106,9 @@ sdmmc_attach(struct device *parent, stru
        sc->sch = saa->sch;
        sc->sc_flags = saa->flags;
        sc->sc_caps = saa->caps;
+       sc->sc_clkmax = saa->saa_clkmax;
+       sc->sc_busclk = saa->saa_clkmax;
+       sc->sc_buswidth = 1;
        sc->sc_max_xfer = saa->max_xfer;
 
        SIMPLEQ_INIT(&sc->sf_head);
@@ -417,11 +420,6 @@ sdmmc_enable(struct sdmmc_softc *sc)
            (error = sdmmc_mem_enable(sc)) != 0)
                goto err;
 
-       /* XXX respect host and card capabilities */
-       if (ISSET(sc->sc_flags, SMF_SD_MODE))
-               (void)sdmmc_chip_bus_clock(sc->sct, sc->sch,
-                   SDMMC_SDCLK_25MHZ);
-
  err:
        if (error != 0)
                sdmmc_disable(sc);
@@ -440,8 +438,10 @@ sdmmc_disable(struct sdmmc_softc *sc)
        (void)sdmmc_select_card(sc, NULL);
 
        /* Turn off bus power and clock. */
+       (void)sdmmc_chip_bus_width(sc->sct, sc->sch, 1);
        (void)sdmmc_chip_bus_clock(sc->sct, sc->sch, SDMMC_SDCLK_OFF);
        (void)sdmmc_chip_bus_power(sc->sct, sc->sch, 0);
+       sc->sc_busclk = sc->sc_clkmax;
 }
 
 /*
@@ -688,37 +688,6 @@ sdmmc_set_relative_addr(struct sdmmc_sof
        if (ISSET(sc->sc_flags, SMF_SD_MODE))
                sf->rca = SD_R6_RCA(cmd.c_resp);
        return 0;
-}
-
-/*
- * Switch card and host to the maximum supported bus width.
- */
-int
-sdmmc_set_bus_width(struct sdmmc_function *sf)
-{
-       struct sdmmc_softc *sc = sf->sc;
-       struct sdmmc_command cmd;
-       int error;
-
-       rw_enter_write(&sc->sc_lock);
-
-       if (!ISSET(sc->sc_flags, SMF_SD_MODE)) {
-               rw_exit(&sc->sc_lock);
-               return EOPNOTSUPP;
-       }
-
-       if ((error = sdmmc_select_card(sc, sf)) != 0) {
-               rw_exit(&sc->sc_lock);
-               return error;
-       }
-
-       bzero(&cmd, sizeof cmd);
-       cmd.c_opcode = SD_APP_SET_BUS_WIDTH;
-       cmd.c_arg = SD_ARG_BUS_WIDTH_4;
-       cmd.c_flags = SCF_CMD_AC | SCF_RSP_R1;
-       error = sdmmc_app_command(sc, &cmd);
-       rw_exit(&sc->sc_lock);
-       return error;
 }
 
 int
Index: dev/sdmmc/sdmmc_io.c
===================================================================
RCS file: /cvs/src/sys/dev/sdmmc/sdmmc_io.c,v
retrieving revision 1.19
diff -u -p -u -p -r1.19 sdmmc_io.c
--- dev/sdmmc/sdmmc_io.c        24 Aug 2010 14:52:23 -0000      1.19
+++ dev/sdmmc/sdmmc_io.c        6 Nov 2013 16:59:44 -0000
@@ -171,11 +171,18 @@ sdmmc_io_scan(struct sdmmc_softc *sc)
 int
 sdmmc_io_init(struct sdmmc_softc *sc, struct sdmmc_function *sf)
 {
+       int error = 0;
+       uint8_t reg;
+
        rw_assert_wrlock(&sc->sc_lock);
 
        if (sf->number == 0) {
-               sdmmc_io_write_1(sf, SD_IO_CCCR_BUS_WIDTH,
-                   CCCR_BUS_WIDTH_1);
+               reg = sdmmc_io_read_1(sf, SD_IO_CCCR_CAPABILITY);
+               if (!(reg & CCCR_CAPS_LSC) || (reg & CCCR_CAPS_4BLS)) {
+                       sdmmc_io_write_1(sf, SD_IO_CCCR_BUS_WIDTH,
+                           CCCR_BUS_WIDTH_4);
+                       sf->width = 4;
+               }
 
                if (sdmmc_read_cis(sf, &sf->cis) != 0) {
                        printf("%s: can't read CIS\n", DEVNAME(sc));
@@ -187,6 +194,23 @@ sdmmc_io_init(struct sdmmc_softc *sc, st
 
                if (sdmmc_verbose)
                        sdmmc_print_cis(sf);
+
+               reg = sdmmc_io_read_1(sf, SD_IO_CCCR_HIGH_SPEED);
+               if (reg & CCCR_HIGH_SPEED_SHS) {
+                       reg |= CCCR_HIGH_SPEED_EHS;
+                       sdmmc_io_write_1(sf, SD_IO_CCCR_HIGH_SPEED, reg);
+
+                       sf->csd.tran_speed = SDMMC_SDCLK_50MHZ;
+
+                       /* Wait 400KHz x 8 clock */
+                       delay(1);
+               }
+
+               if (sc->sc_busclk > sf->csd.tran_speed)
+                       sc->sc_busclk = sf->csd.tran_speed;
+               error = sdmmc_chip_bus_clock(sc->sct, sc->sch, sc->sc_busclk);
+               if (error)
+                       printf("%s: can't change bus clock\n", DEVNAME(sc));
        }
        return 0;
 }
Index: dev/sdmmc/sdmmc_ioreg.h
===================================================================
RCS file: /cvs/src/sys/dev/sdmmc/sdmmc_ioreg.h,v
retrieving revision 1.4
diff -u -p -u -p -r1.4 sdmmc_ioreg.h
--- dev/sdmmc/sdmmc_ioreg.h     2 Jun 2007 01:48:37 -0000       1.4
+++ dev/sdmmc/sdmmc_ioreg.h     6 Nov 2013 16:59:44 -0000
@@ -71,7 +71,19 @@
 #define SD_IO_CCCR_BUS_WIDTH           0x07
 #define  CCCR_BUS_WIDTH_4              (1<<1)
 #define  CCCR_BUS_WIDTH_1              (1<<0)
+#define SD_IO_CCCR_CAPABILITY          0x08
+#define  CCCR_CAPS_SDC                 (1<<0)
+#define  CCCR_CAPS_SMB                 (1<<1) /* Multi-Block support */
+#define  CCCR_CAPS_SRB                 (1<<2) /* Read Wait support */
+#define  CCCR_CAPS_SBS                 (1<<3) /* Suspend/Resume support */
+#define  CCCR_CAPS_S4MI                        (1<<4) /* intr support in 4-bit 
mode */
+#define  CCCR_CAPS_E4MI                        (1<<5) /* enable intr in 4-bit 
mode */
+#define  CCCR_CAPS_LSC                 (1<<6) /* Low speed card */
+#define  CCCR_CAPS_4BLS                        (1<<7) /* 4-bit support for low 
speed */
 #define SD_IO_CCCR_CISPTR              0x09 /* XXX 9-10, 10-11, or 9-12 */
+#define SD_IO_CCCR_HIGH_SPEED          0x13
+#define  CCCR_HIGH_SPEED_SHS           (1<<0) /* Support High-Speed */
+#define  CCCR_HIGH_SPEED_EHS           (1<<1) /* Enable High-Speed */
 
 /* Function Basic Registers (FBR) */
 #define SD_IO_FBR_START                        0x00100
Index: dev/sdmmc/sdmmc_mem.c
===================================================================
RCS file: /cvs/src/sys/dev/sdmmc/sdmmc_mem.c,v
retrieving revision 1.18
diff -u -p -u -p -r1.18 sdmmc_mem.c
--- dev/sdmmc/sdmmc_mem.c       22 Oct 2013 16:49:27 -0000      1.18
+++ dev/sdmmc/sdmmc_mem.c       6 Nov 2013 16:59:44 -0000
@@ -24,10 +24,13 @@
 #include <sys/malloc.h>
 #include <sys/systm.h>
 
+#include <sys/endian.h>
+
 #include <dev/sdmmc/sdmmcchip.h>
 #include <dev/sdmmc/sdmmcreg.h>
 #include <dev/sdmmc/sdmmcvar.h>
 
+typedef struct { uint32_t _bits[512/32]; } __packed sdmmc_bitfield512_t;
 int    sdmmc_decode_csd(struct sdmmc_softc *, sdmmc_response,
            struct sdmmc_function *);
 int    sdmmc_decode_cid(struct sdmmc_softc *, sdmmc_response,
@@ -240,7 +243,23 @@ int
 sdmmc_decode_csd(struct sdmmc_softc *sc, sdmmc_response resp,
     struct sdmmc_function *sf)
 {
+       /* TRAN_SPEED(2:0): transfer rate exponent */
+       static const int speed_exponent[8] = {
+               100 *    1,     /* 100 Kbits/s */
+                 1 * 1000,     /*   1 Mbits/s */
+                10 * 1000,     /*  10 Mbits/s */
+               100 * 1000,     /* 100 Mbits/s */
+                        0,
+                        0,
+                        0,
+                        0,
+       };
+       /* TRAN_SPEED(6:3): time mantissa */
+       static const int speed_mantissa[16] = {
+               0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80,
+       };
        struct sdmmc_csd *csd = &sf->csd;
+       int e, m;
 
        if (ISSET(sc->sc_flags, SMF_SD_MODE)) {
                /*
@@ -265,6 +284,13 @@ sdmmc_decode_csd(struct sdmmc_softc *sc,
                        break;
                }
 
+               csd->mmcver = SD_CSD_MMCVER(resp);
+               csd->write_bl_len = SD_CSD_WRITE_BL_LEN(resp);
+               csd->r2w_factor = SD_CSD_R2W_FACTOR(resp);
+               e = SD_CSD_SPEED_EXP(resp);
+               m = SD_CSD_SPEED_MANT(resp);
+               csd->tran_speed = speed_exponent[e] * speed_mantissa[m] / 10;
+               csd->ccc = SD_CSD_CCC(resp);
        } else {
                csd->csdver = MMC_CSD_CSDVER(resp);
                if (csd->csdver == MMC_CSD_CSDVER_1_0 ||
@@ -273,6 +299,12 @@ sdmmc_decode_csd(struct sdmmc_softc *sc,
                        csd->mmcver = MMC_CSD_MMCVER(resp);
                        csd->capacity = MMC_CSD_CAPACITY(resp);
                        csd->read_bl_len = MMC_CSD_READ_BL_LEN(resp);
+                       csd->write_bl_len = MMC_CSD_WRITE_BL_LEN(resp);
+                       csd->r2w_factor = MMC_CSD_R2W_FACTOR(resp);
+                       e = MMC_CSD_TRAN_SPEED_EXP(resp);
+                       m = MMC_CSD_TRAN_SPEED_MANT(resp);
+                       csd->tran_speed = speed_exponent[e] *
+                           speed_mantissa[m] / 10;
                } else {
                        printf("%s: unknown MMC CSD structure version 0x%x\n",
                            DEVNAME(sc), csd->csdver);
@@ -375,6 +407,39 @@ out:
        return error;
 }
 
+static int
+sdmmc_set_bus_width(struct sdmmc_function *sf, int width)
+{
+       struct sdmmc_softc *sc = sf->sc;
+       struct sdmmc_command cmd;
+       int error;
+
+       if (ISSET(sc->sc_caps, SMC_CAPS_SPI_MODE))
+               return ENODEV;
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.c_opcode = SD_APP_SET_BUS_WIDTH;
+       cmd.c_flags = SCF_RSP_R1 | SCF_CMD_AC;
+
+       switch (width) {
+       case 1:
+               cmd.c_arg = SD_ARG_BUS_WIDTH_1;
+               break;
+
+       case 4:
+               cmd.c_arg = SD_ARG_BUS_WIDTH_4;
+               break;
+
+       default:
+               return EINVAL;
+       }
+
+       error = sdmmc_app_command(sc, &cmd);
+       if (error == 0)
+               error = sdmmc_chip_bus_width(sc->sct, sc->sch, width);
+       return error;
+}
+
 int
 sdmmc_mem_mmc_switch(struct sdmmc_function *sf, uint8_t set, uint8_t index,
     uint8_t value)
@@ -413,12 +478,234 @@ sdmmc_mem_init(struct sdmmc_softc *sc, s
        return error;
 }
 
+static int
+sdmmc_mem_send_scr(struct sdmmc_softc *sc, struct sdmmc_function *sf,
+    uint32_t scr[2])
+{
+       struct sdmmc_command cmd;
+       void *ptr = NULL;
+       int datalen = 8;
+       int error = 0;
+
+       /* Don't lock */
+
+       ptr = malloc(datalen, M_DEVBUF, M_NOWAIT | M_ZERO);
+       if (ptr == NULL)
+               goto out;
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.c_data = ptr;
+       cmd.c_datalen = datalen;
+       cmd.c_blklen = datalen;
+       cmd.c_arg = 0;
+       cmd.c_flags = SCF_CMD_ADTC | SCF_CMD_READ | SCF_RSP_R1 | SCF_RSP_SPI_R1;
+       cmd.c_opcode = SD_APP_SEND_SCR;
+
+       error = sdmmc_app_command(sc, &cmd);
+       if (error == 0)
+               memcpy(scr, ptr, datalen);
+
+out:
+       if (ptr != NULL)
+               free(ptr, M_DEVBUF);
+       DPRINTF(("%s: sdmem_mem_send_scr: error = %d\n", SDMMCDEVNAME(sc),
+           error));
+
+       return (error);
+}
+
+static int
+sdmmc_mem_decode_scr(struct sdmmc_softc *sc, struct sdmmc_function *sf)
+{
+       sdmmc_response resp;
+       int ver;
+
+       memset(resp, 0, sizeof(resp));
+       /*
+        * Change the raw-scr received from the DMA stream to resp.
+        */
+       resp[0] = betoh32(sf->raw_scr[1]) >> 8;         // LSW
+       resp[1] = betoh32(sf->raw_scr[0]);              // MSW
+       resp[0] |= (resp[1] & 0xff) << 24;
+       resp[1] >>= 8;
+
+       ver = SCR_STRUCTURE(resp);
+       sf->scr.sd_spec = SCR_SD_SPEC(resp);
+       sf->scr.bus_width = SCR_SD_BUS_WIDTHS(resp);
+
+       DPRINTF(("%s: sdmmc_mem_decode_scr: %08x%08x spec=%d, bus width=%d\n",
+           SDMMCDEVNAME(sc), resp[1], resp[0],
+           sf->scr.sd_spec, sf->scr.bus_width));
+
+       if (ver != 0) {
+               DPRINTF(("%s: unknown structure version: %d\n",
+                   SDMMCDEVNAME(sc), ver));
+               return EINVAL;
+       }
+       return 0;
+}
+
+/* make 512-bit BE quantity __bitfield()-compatible */
+static void
+sdmmc_be512_to_bitfield512(sdmmc_bitfield512_t *buf) {
+       size_t i;
+       uint32_t tmp0, tmp1;
+       const size_t bitswords = nitems(buf->_bits);
+       for (i = 0; i < bitswords/2; i++) {
+               tmp0 = buf->_bits[i];
+               tmp1 = buf->_bits[bitswords - 1 - i];
+               buf->_bits[i] = betoh32(tmp1);
+               buf->_bits[bitswords - 1 - i] = betoh32(tmp0);
+       }
+}
+
+static int
+sdmmc_mem_sd_switch(struct sdmmc_function *sf, int mode, int group,
+    int function, sdmmc_bitfield512_t *status)
+{
+       struct sdmmc_softc *sc = sf->sc;
+       struct sdmmc_command cmd;
+       void *ptr = NULL;
+       int gsft, error = 0;
+       const int statlen = 64;
+
+       if (sf->scr.sd_spec >= SCR_SD_SPEC_VER_1_10 &&
+           !ISSET(sf->csd.ccc, SD_CSD_CCC_SWITCH))
+               return EINVAL;
+
+       if (group <= 0 || group > 6 ||
+           function < 0 || function > 15)
+               return EINVAL;
+
+       gsft = (group - 1) << 2;
+
+       ptr = malloc(statlen, M_DEVBUF, M_NOWAIT | M_ZERO);
+       if (ptr == NULL)
+               goto out;
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.c_data = ptr;
+       cmd.c_datalen = statlen;
+       cmd.c_blklen = statlen;
+       cmd.c_opcode = SD_SEND_SWITCH_FUNC;
+       cmd.c_arg =
+           (!!mode << 31) | (function << gsft) | (0x00ffffff & ~(0xf << gsft));
+       cmd.c_flags = SCF_CMD_ADTC | SCF_CMD_READ | SCF_RSP_R1 | SCF_RSP_SPI_R1;
+
+       error = sdmmc_mmc_command(sc, &cmd);
+       if (error == 0)
+               memcpy(status, ptr, statlen);
+
+out:
+       if (ptr != NULL)
+               if (ISSET(sc->sc_caps, SMC_CAPS_DMA))
+                       free(ptr, M_DEVBUF);
+
+       if (error == 0)
+               sdmmc_be512_to_bitfield512(status);
+
+       return error;
+}
 int
 sdmmc_mem_sd_init(struct sdmmc_softc *sc, struct sdmmc_function *sf)
 {
-       /* XXX */
+       sdmmc_bitfield512_t status; /* Switch Function Status */
+       int support_func;
+       int best_func;
+       int host_ocr;
+       int error;
+       int g;
+       int i;
+       struct {
+               int v;
+               int freq;
+       } switch_group0_functions[] = {
+               /* Default/SDR12 */
+               { MMC_OCR_1_7V_1_8V | MMC_OCR_1_8V_1_9V |
+                 MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V,         25000 },
+
+               /* High-Speed/SDR25 */
+               { MMC_OCR_1_7V_1_8V | MMC_OCR_1_8V_1_9V |
+                 MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V,         50000 },
+
+               /* SDR50 */
+               { MMC_OCR_1_7V_1_8V | MMC_OCR_1_8V_1_9V,        100000 },
+
+               /* SDR104 */
+               { MMC_OCR_1_7V_1_8V | MMC_OCR_1_8V_1_9V,        208000 },
+
+               /* DDR50 */
+               { MMC_OCR_1_7V_1_8V | MMC_OCR_1_8V_1_9V,         50000 },
+       };
+
+       if ((error = sdmmc_mem_send_scr(sc, sf, sf->raw_scr))) {
+               printf("%s: SD_SEND_SCR send failed.\n", DEVNAME(sc));
+               return (error);
+       }
+       if ((error = sdmmc_mem_decode_scr(sc, sf)))
+               return (error);
 
-       return 0;
+       if (ISSET(sc->sc_caps, SMC_CAPS_4BIT_MODE) &&
+           ISSET(sf->scr.bus_width, SCR_SD_BUS_WIDTHS_4BIT)) {
+               DPRINTF(("%s: change bus width\n", SDMMCDEVNAME(sc)));
+               error = sdmmc_set_bus_width(sf, 4);
+               if (error) {
+                       printf("%s: can't change bus width (%d bit)\n",
+                           DEVNAME(sc), 4);
+                       return error;
+               }
+               sf->width = 4;
+       }
+
+       if (sf->scr.sd_spec >= SCR_SD_SPEC_VER_1_10 &&
+           ISSET(sf->csd.ccc, SD_CSD_CCC_SWITCH)) {
+               DPRINTF(("%s: switch func mode 0\n", DEVNAME(sc)));
+               error = sdmmc_mem_sd_switch(sf, 0, 1, 0, &status);
+               if (error) {
+                       printf("%s: switch func mode 0 failed\n",
+                           DEVNAME(sc));
+                       return error;
+               }
+
+               host_ocr = sdmmc_chip_host_ocr(sc->sct, sc->sch);
+               support_func = SFUNC_STATUS_GROUP(&status, 1);
+               best_func = 0;
+               for (i = 0, g = 1;
+                   i < nitems(switch_group0_functions); i++, g <<= 1) {
+                       if (!(switch_group0_functions[i].v & host_ocr))
+                               continue;
+                       if (g & support_func)
+                               best_func = i;
+               }
+               if (ISSET(sc->sc_caps, SMC_CAPS_SD_HIGHSPEED) &&
+                   best_func != 0) {
+                       printf("%s: switch func mode 1(func=%d)\n",
+                           DEVNAME(sc), best_func);
+                       error =
+                           sdmmc_mem_sd_switch(sf, 1, 1, best_func, &status);
+                       if (error) {
+                               printf("%s: switch func mode 1 failed:"
+                                   " group 1 function %d(0x%2x)\n",
+                                   DEVNAME(sc), best_func, support_func);
+                               return error;
+                       }
+                       sf->csd.tran_speed =
+                           switch_group0_functions[best_func].freq;
+
+                       /* Wait 400KHz x 8 clock (2.5us * 8 + slop) */
+                       DELAY(25);
+               }
+       }
+
+       /* change bus clock */
+       if (sc->sc_busclk > sf->csd.tran_speed)
+               sc->sc_busclk = sf->csd.tran_speed;
+       error = sdmmc_chip_bus_clock(sc->sct, sc->sch, sc->sc_busclk);
+       if (error) {
+               printf("%s: can't change bus clock\n", DEVNAME(sc));
+               return (error);
+       }
+       return (0);
 }
 
 int
@@ -468,8 +755,9 @@ sdmmc_mem_mmc_init(struct sdmmc_softc *s
                        }
                }
 
-               error =
-                   sdmmc_chip_bus_clock(sc->sct, sc->sch, speed);
+               if (sc->sc_busclk > sf->csd.tran_speed)
+                       sc->sc_busclk = sf->csd.tran_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;
@@ -487,6 +775,14 @@ sdmmc_mem_mmc_init(struct sdmmc_softc *s
                                printf("%s, HS_TIMING set failed\n", 
DEVNAME(sc));
                                return EINVAL;
                        }
+               }
+       } else {
+               if (sc->sc_busclk > sf->csd.tran_speed)
+                       sc->sc_busclk = sf->csd.tran_speed;
+               error = sdmmc_chip_bus_clock(sc->sct, sc->sch, sc->sc_busclk);
+               if (error) {
+                       printf("%s: can't change bus clock\n");
+                       return (error);
                }
        }
 
Index: dev/sdmmc/sdmmcchip.h
===================================================================
RCS file: /cvs/src/sys/dev/sdmmc/sdmmcchip.h,v
retrieving revision 1.5
diff -u -p -u -p -r1.5 sdmmcchip.h
--- dev/sdmmc/sdmmcchip.h       12 Sep 2013 11:54:04 -0000      1.5
+++ dev/sdmmc/sdmmcchip.h       6 Nov 2013 16:59:44 -0000
@@ -35,6 +35,7 @@ struct sdmmc_chip_functions {
        /* bus power and clock frequency */
        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 *);
@@ -59,6 +60,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)))
@@ -72,6 +75,7 @@ struct sdmmc_chip_functions {
 #define SDMMC_SDCLK_OFF                0
 #define SDMMC_SDCLK_400KHZ     400
 #define SDMMC_SDCLK_25MHZ      25000
+#define SDMMC_SDCLK_50MHZ      50000
 
 struct sdmmcbus_attach_args {
        const char *saa_busname;
@@ -80,6 +84,7 @@ struct sdmmcbus_attach_args {
        int     flags;
        int     caps;
        long    max_xfer;
+       long    saa_clkmax;
 };
 
 void   sdmmc_needs_discover(struct device *);
Index: dev/sdmmc/sdmmcreg.h
===================================================================
RCS file: /cvs/src/sys/dev/sdmmc/sdmmcreg.h,v
retrieving revision 1.5
diff -u -p -u -p -r1.5 sdmmcreg.h
--- dev/sdmmc/sdmmcreg.h        12 Sep 2013 11:54:04 -0000      1.5
+++ dev/sdmmc/sdmmcreg.h        6 Nov 2013 16:59:44 -0000
@@ -40,11 +40,14 @@
 
 /* SD commands */                              /* response type */
 #define SD_SEND_RELATIVE_ADDR          3       /* R6 */
+#define SD_SEND_SWITCH_FUNC            6       /* R1 */
 #define SD_SEND_IF_COND                        8       /* R7 */
 
 /* SD application commands */                  /* response type */
 #define SD_APP_SET_BUS_WIDTH           6       /* R1 */
+#define SD_APP_SD_STATUS               13      /* R1 */
 #define SD_APP_OP_COND                 41      /* R3 */
+#define SD_APP_SEND_SCR                        51      /* R1 */
 
 /* OCR bits */
 #define MMC_OCR_MEM_READY              (1<<31) /* memory power-up status bit */
@@ -80,6 +83,7 @@
 #define MMC_R1(resp)                   ((resp)[0])
 #define MMC_R3(resp)                   ((resp)[0])
 #define SD_R6(resp)                    ((resp)[0])
+#define MMC_SPI_R1(resp)               ((resp)[0])
 
 /* RCA argument and response */
 #define MMC_ARG_RCA(rca)               ((rca) << 16)
@@ -136,11 +140,15 @@
 #define  MMC_CSD_MMCVER_2_0            2 /* MMC 2.0 - 2.2 */
 #define  MMC_CSD_MMCVER_3_1            3 /* MMC 3.1 - 3.3 */
 #define  MMC_CSD_MMCVER_4_0            4 /* MMC 4 */
+#define MMC_CSD_TRAN_SPEED_MANT(resp)  MMC_RSP_BITS((resp), 99, 4)
+#define MMC_CSD_TRAN_SPEED_EXP(resp)   MMC_RSP_BITS((resp), 96, 3)
 #define MMC_CSD_READ_BL_LEN(resp)      MMC_RSP_BITS((resp), 80, 4)
 #define MMC_CSD_C_SIZE(resp)           MMC_RSP_BITS((resp), 62, 12)
 #define MMC_CSD_CAPACITY(resp)         ((MMC_CSD_C_SIZE((resp))+1) << \
                                         (MMC_CSD_C_SIZE_MULT((resp))+2))
 #define MMC_CSD_C_SIZE_MULT(resp)      MMC_RSP_BITS((resp), 47, 3)
+#define MMC_CSD_R2W_FACTOR(resp)       MMC_RSP_BITS((resp), 26, 3)
+#define MMC_CSD_WRITE_BL_LEN(resp)     MMC_RSP_BITS((resp), 22, 4)
 
 /* MMC v1 R2 response (CID) */
 #define MMC_CID_MID_V1(resp)           MMC_RSP_BITS((resp), 104, 24)
@@ -178,13 +186,25 @@
 #define SD_CSD_CSDVER(resp)            MMC_RSP_BITS((resp), 126, 2)
 #define  SD_CSD_CSDVER_1_0             0
 #define  SD_CSD_CSDVER_2_0             1
+#define SD_CSD_MMCVER(resp)            MMC_RSP_BITS((resp), 122, 4)
 #define SD_CSD_TAAC(resp)              MMC_RSP_BITS((resp), 112, 8)
 #define  SD_CSD_TAAC_1_5_MSEC          0x26
 #define SD_CSD_NSAC(resp)              MMC_RSP_BITS((resp), 104, 8)
 #define SD_CSD_SPEED(resp)             MMC_RSP_BITS((resp), 96, 8)
+#define SD_CSD_SPEED_MANT(resp)                MMC_RSP_BITS((resp), 99, 4)
+#define SD_CSD_SPEED_EXP(resp)         MMC_RSP_BITS((resp), 96, 3)
 #define  SD_CSD_SPEED_25_MHZ           0x32
 #define  SD_CSD_SPEED_50_MHZ           0x5a
 #define SD_CSD_CCC(resp)               MMC_RSP_BITS((resp), 84, 12)
+#define  SD_CSD_CCC_BASIC              (1 << 0)        /* basic */
+#define  SD_CSD_CCC_BR                 (1 << 2)        /* block read */
+#define  SD_CSD_CCC_BW                 (1 << 4)        /* block write */
+#define  SD_CSD_CCC_ERACE              (1 << 5)        /* erase */
+#define  SD_CSD_CCC_WP                 (1 << 6)        /* write protection */
+#define  SD_CSD_CCC_LC                 (1 << 7)        /* lock card */
+#define  SD_CSD_CCC_AS                 (1 << 8)        /*application specific*/
+#define  SD_CSD_CCC_IOM                        (1 << 9)        /* I/O mode */
+#define  SD_CSD_CCC_SWITCH             (1 << 10)       /* switch */
 #define  SD_CSD_CCC_ALL                        0x5f5
 #define SD_CSD_READ_BL_LEN(resp)       MMC_RSP_BITS((resp), 80, 4)
 #define SD_CSD_READ_BL_PARTIAL(resp)   MMC_RSP_BITS((resp), 79, 1)
@@ -234,6 +254,32 @@
 #define SD_CID_REV(resp)               MMC_RSP_BITS((resp), 56, 8)
 #define SD_CID_PSN(resp)               MMC_RSP_BITS((resp), 24, 32)
 #define SD_CID_MDT(resp)               MMC_RSP_BITS((resp), 8, 12)
+
+/* SCR (SD Configuration Register) */
+#define SCR_STRUCTURE(scr)             MMC_RSP_BITS((scr), 60, 4)
+#define  SCR_STRUCTURE_VER_1_0         0 /* Version 1.0 */
+#define SCR_SD_SPEC(scr)               MMC_RSP_BITS((scr), 56, 4)
+#define  SCR_SD_SPEC_VER_1_0           0 /* Version 1.0 and 1.01 */
+#define  SCR_SD_SPEC_VER_1_10          1 /* Version 1.10 */
+#define  SCR_SD_SPEC_VER_2             2 /* Version 2.00 or Version 3.0X */
+#define SCR_DATA_STAT_AFTER_ERASE(scr) MMC_RSP_BITS((scr), 55, 1)
+#define SCR_SD_SECURITY(scr)           MMC_RSP_BITS((scr), 52, 3)
+#define  SCR_SD_SECURITY_NONE          0 /* no security */
+#define  SCR_SD_SECURITY_1_0           1 /* security protocol 1.0 */
+#define  SCR_SD_SECURITY_1_0_2         2 /* security protocol 1.0 */
+#define SCR_SD_BUS_WIDTHS(scr)         MMC_RSP_BITS((scr), 48, 4)
+#define  SCR_SD_BUS_WIDTHS_1BIT                (1 << 0) /* 1bit (DAT0) */
+#define  SCR_SD_BUS_WIDTHS_4BIT                (1 << 2) /* 4bit (DAT0-3) */
+#define SCR_SD_SPEC3(scr)              MMC_RSP_BITS((scr), 47, 1)
+#define SCR_EX_SECURITY(scr)           MMC_RSP_BITS((scr), 43, 4)
+#define SCR_RESERVED(scr)              MMC_RSP_BITS((scr), 34, 9)
+#define SCR_CMD_SUPPORT_CMD23(scr)     MMC_RSP_BITS((scr), 33, 1)
+#define SCR_CMD_SUPPORT_CMD20(scr)     MMC_RSP_BITS((scr), 32, 1)
+#define SCR_RESERVED2(scr)             MMC_RSP_BITS((scr), 0, 32)
+
+/* Status of Switch Function */
+#define SFUNC_STATUS_GROUP(status, group) \
+       (__bitfield((uint32_t *)(status), 400 + (group - 1) * 16, 16))
 
 /* Might be slow, but it should work on big and little endian systems. */
 #define MMC_RSP_BITS(resp, start, len) __bitfield((resp), (start)-8, (len))
Index: dev/sdmmc/sdmmcvar.h
===================================================================
RCS file: /cvs/src/sys/dev/sdmmc/sdmmcvar.h,v
retrieving revision 1.22
diff -u -p -u -p -r1.22 sdmmcvar.h
--- dev/sdmmc/sdmmcvar.h        12 Sep 2013 11:54:04 -0000      1.22
+++ dev/sdmmc/sdmmcvar.h        6 Nov 2013 16:59:44 -0000
@@ -34,6 +34,10 @@ struct sdmmc_csd {
        int     capacity;       /* total number of sectors */
        int     sector_size;    /* sector size in bytes */
        int     read_bl_len;    /* block length for reads */
+       int     write_bl_len;   /* block length for writes */
+       int     r2w_factor;
+       int     tran_speed;     /* transfer speed (kbit/s) */
+       int     ccc;            /* Card Command Class for SD */
        /* ... */
 };
 
@@ -46,6 +50,11 @@ struct sdmmc_cid {
        int     mdt;            /* manufacturing date */
 };
 
+struct sdmmc_scr {
+       int     sd_spec;
+       int     bus_width;
+};
+
 typedef u_int32_t sdmmc_response[4];
 
 struct sdmmc_softc;
@@ -88,6 +97,11 @@ struct sdmmc_command {
 #define SCF_RSP_CRC     0x0400
 #define SCF_RSP_IDX     0x0800
 #define SCF_RSP_PRESENT         0x1000
+/* SPI */
+#define SCF_RSP_SPI_S1 (1U << 10)
+#define SCF_RSP_SPI_S2 (1U << 11)
+#define SCF_RSP_SPI_B4 (1U << 12)
+#define SCF_RSP_SPI_BSY        (1U << 13)
 /* response types */
 #define SCF_RSP_R0      0 /* none */
 #define SCF_RSP_R1      (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX)
@@ -99,6 +113,14 @@ struct sdmmc_command {
 #define SCF_RSP_R5B     (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX|SCF_RSP_BSY)
 #define SCF_RSP_R6      (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX)
 #define SCF_RSP_R7      (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX)
+/* SPI */
+#define SCF_RSP_SPI_R1 (SCF_RSP_SPI_S1)
+#define SCF_RSP_SPI_R1B        (SCF_RSP_SPI_S1|SCF_RSP_SPI_BSY)
+#define SCF_RSP_SPI_R2 (SCF_RSP_SPI_S1|SCF_RSP_SPI_S2)
+#define SCF_RSP_SPI_R3 (SCF_RSP_SPI_S1|SCF_RSP_SPI_B4)
+#define SCF_RSP_SPI_R4 (SCF_RSP_SPI_S1|SCF_RSP_SPI_B4)
+#define SCF_RSP_SPI_R5 (SCF_RSP_SPI_S1|SCF_RSP_SPI_S2)
+#define SCF_RSP_SPI_R7 (SCF_RSP_SPI_S1|SCF_RSP_SPI_B4)
        int              c_error;       /* errno value on completion */
 
        /* Host controller owned fields for data xfer in progress */
@@ -134,6 +156,7 @@ struct sdmmc_function {
        /* common members */
        struct sdmmc_softc *sc;         /* card slot softc */
        u_int16_t rca;                  /* relative card address */
+       int width;                      /* bus width */
        int flags;
 #define SFF_ERROR              0x0001  /* function is poo; ignore it */
 #define SFF_SDHC               0x0002  /* SD High Capacity card */
@@ -146,6 +169,8 @@ struct sdmmc_function {
        struct sdmmc_csd csd;           /* decoded CSD value */
        struct sdmmc_cid cid;           /* decoded CID value */
        sdmmc_response raw_cid;         /* temp. storage for decoding */
+       uint32_t raw_scr[2];
+       struct sdmmc_scr scr;           /* decoded SCR value */
 };
 
 /*
@@ -177,6 +202,9 @@ struct sdmmc_softc {
 #define SMC_CAPS_SD_HIGHSPEED  0x0100  /* SD high-speed timing */
 #define SMC_CAPS_MMC_HIGHSPEED 0x0200  /* MMC high-speed timing */
 
+       long sc_busclk;
+       int sc_buswidth;                /* host bus width */
+       long sc_clkmax;
        int sc_function_count;          /* number of I/O functions (SDIO) */
        struct sdmmc_function *sc_card; /* selected card */
        struct sdmmc_function *sc_fn0;  /* function 0, the card itself */

Reply via email to