This bumps the clock rate up to 50 MHz if the SD card supports that.
And basically all modern cards do support that.

This probably needs to get some wider testing.


Index: sdmmc.c
===================================================================
RCS file: /cvs/src/sys/dev/sdmmc/sdmmc.c,v
retrieving revision 1.42
diff -u -p -r1.42 sdmmc.c
--- sdmmc.c     1 May 2016 22:07:42 -0000       1.42
+++ sdmmc.c     1 May 2016 22:22:27 -0000
@@ -438,11 +438,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);
Index: sdmmc_io.c
===================================================================
RCS file: /cvs/src/sys/dev/sdmmc/sdmmc_io.c,v
retrieving revision 1.23
diff -u -p -r1.23 sdmmc_io.c
--- sdmmc_io.c  23 Apr 2016 14:15:59 -0000      1.23
+++ sdmmc_io.c  1 May 2016 22:22:28 -0000
@@ -182,6 +182,12 @@ sdmmc_io_init(struct sdmmc_softc *sc, st
        if (sdmmc_verbose)
                sdmmc_print_cis(sf);
 
+       if (sf->number == 0) {
+               /* XXX respect host and card capabilities */
+               (void)sdmmc_chip_bus_clock(sc->sct, sc->sch,
+                   SDMMC_SDCLK_25MHZ);
+       }
+
        return 0;
 }
 
Index: sdmmc_mem.c
===================================================================
RCS file: /cvs/src/sys/dev/sdmmc/sdmmc_mem.c,v
retrieving revision 1.26
diff -u -p -r1.26 sdmmc_mem.c
--- sdmmc_mem.c 1 May 2016 18:29:44 -0000       1.26
+++ sdmmc_mem.c 1 May 2016 22:22:28 -0000
@@ -28,6 +28,10 @@
 #include <dev/sdmmc/sdmmcreg.h>
 #include <dev/sdmmc/sdmmcvar.h>
 
+typedef struct { uint32_t _bits[512/32]; } __packed __aligned(4) 
sdmmc_bitfield512_t;
+
+void   sdmmc_be512_to_bitfield512(sdmmc_bitfield512_t *);
+
 int    sdmmc_decode_csd(struct sdmmc_softc *, sdmmc_response,
            struct sdmmc_function *);
 int    sdmmc_decode_cid(struct sdmmc_softc *, sdmmc_response,
@@ -269,7 +273,7 @@ sdmmc_decode_csd(struct sdmmc_softc *sc,
                        return 1;
                        break;
                }
-
+               csd->ccc = SD_CSD_CCC(resp);
        } else {
                csd->csdver = MMC_CSD_CSDVER(resp);
                if (csd->csdver == MMC_CSD_CSDVER_1_0 ||
@@ -364,9 +368,8 @@ sdmmc_mem_send_scr(struct sdmmc_softc *s
        cmd.c_opcode = SD_APP_SEND_SCR;
 
        error = sdmmc_app_command(sc, &cmd);
-       if (error == 0) {
+       if (error == 0)
                memcpy(scr, ptr, datalen);
-       }
 
 out:
        if (ptr != NULL)
@@ -475,6 +478,53 @@ sdmmc_set_bus_width(struct sdmmc_functio
 }
 
 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;
+
+       error = sdmmc_mmc_command(sc, &cmd);
+       if (error == 0)
+               memcpy(status, ptr, statlen);
+
+out:
+       if (ptr != NULL)
+               free(ptr, M_DEVBUF, statlen);
+
+       if (error == 0)
+               sdmmc_be512_to_bitfield512(status);
+
+       return error;
+}
+
+int
 sdmmc_mem_mmc_switch(struct sdmmc_function *sf, uint8_t set, uint8_t index,
     uint8_t value)
 {
@@ -512,11 +562,26 @@ sdmmc_mem_init(struct sdmmc_softc *sc, s
        return error;
 }
 
+/* make 512-bit BE quantity __bitfield()-compatible */
+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] = be32toh(tmp1);
+               buf->_bits[bitswords - 1 - i] = be32toh(tmp0);
+       }
+}
+
 int
 sdmmc_mem_sd_init(struct sdmmc_softc *sc, struct sdmmc_function *sf)
 {
+       int support_func, best_func, bus_clock, error;
+       sdmmc_bitfield512_t status; /* Switch Function Status */
        uint32_t raw_scr[2];
-       int error;
 
        error = sdmmc_mem_send_scr(sc, raw_scr);
        if (error) {
@@ -535,6 +600,47 @@ sdmmc_mem_sd_init(struct sdmmc_softc *sc
                        printf("%s: can't change bus width\n", DEVNAME(sc));
                        return error;
                }
+       }
+
+       best_func = 0;
+       bus_clock = 25000;
+       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;
+               }
+
+               support_func = SFUNC_STATUS_GROUP(&status, 1);
+
+               if (support_func & (1 << SD_ACCESS_MODE_SDR25))
+                       best_func = 1;
+
+               if (best_func != 0) {
+                       DPRINTF(("%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;
+                       }
+                       bus_clock = 50000;
+
+                       /* Wait 400KHz x 8 clock (2.5us * 8 + slop) */
+                       delay(25);
+               }
+       }
+
+       /* change bus clock */
+       error = sdmmc_chip_bus_clock(sc->sct, sc->sch, bus_clock);
+       if (error) {
+               printf("%s: can't change bus clock\n", DEVNAME(sc));
+               return error;
        }
 
        return 0;
Index: sdmmcreg.h
===================================================================
RCS file: /cvs/src/sys/dev/sdmmc/sdmmcreg.h,v
retrieving revision 1.9
diff -u -p -r1.9 sdmmcreg.h
--- sdmmcreg.h  1 May 2016 16:04:39 -0000       1.9
+++ sdmmcreg.h  1 May 2016 22:22:28 -0000
@@ -40,6 +40,7 @@
 
 /* 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 */
@@ -187,7 +188,15 @@
 #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_ALL                        0x5f5
+#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_READ_BL_LEN(resp)       MMC_RSP_BITS((resp), 80, 4)
 #define SD_CSD_READ_BL_PARTIAL(resp)   MMC_RSP_BITS((resp), 79, 1)
 #define SD_CSD_WRITE_BLK_MISALIGN(resp)        MMC_RSP_BITS((resp), 78, 1)
@@ -259,6 +268,16 @@
 #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))
+
+#define SD_ACCESS_MODE_SDR12   0
+#define SD_ACCESS_MODE_SDR25   1
+#define SD_ACCESS_MODE_SDR50   2
+#define SD_ACCESS_MODE_SDR104  3
+#define SD_ACCESS_MODE_DDR50   4
 
 /* 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: sdmmcvar.h
===================================================================
RCS file: /cvs/src/sys/dev/sdmmc/sdmmcvar.h,v
retrieving revision 1.24
diff -u -p -r1.24 sdmmcvar.h
--- sdmmcvar.h  1 May 2016 16:04:39 -0000       1.24
+++ sdmmcvar.h  1 May 2016 22:22:28 -0000
@@ -36,6 +36,7 @@ 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     ccc;            /* Card Command Class for SD */
        /* ... */
 };
 

Reply via email to