Current-Users archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

sdmmc(4) High-Speed support



Hi! all,


I support high-speed for sdmmc(4).

It test on Marvell Sheevaplug only.  Sheevaplug supports 3.3V 50MHz.
In a word not test over 50MHz... ;-)
And, this will work for mvsdio and sdhc@pci now.


My microSD card:

ld0 at sdmmc0: <SU04G>
ld0: 3781 MB, 1920 cyl, 64 head, 63 sec, 512 bytes/sect x 7744512 sectors
ld0: 4-bit width, bus clock 50.000 MHz

# dd if=/dev/rld0c of=/dev/null bs=1m

result:
  1. 3965190144 bytes transferred in 637.395 secs (6220930 bytes/sec)
  2. 3965190144 bytes transferred in 215.435 secs (18405505 bytes/sec)
  3. 3965190144 bytes transferred in 636.993 secs (6224856 bytes/sec)
  4. 3965190144 bytes transferred in 215.857 secs (18369523 bytes/sec)
  5. 3965190144 bytes transferred in 639.168 secs (6203674 bytes/sec)

We have the possibility of using the bounce buffer.  X-<
And, it is slower to write.

Thanks,
--
kiyohara
Index: arch/arm/xscale/pxa2x0_mci.c
===================================================================
RCS file: /cvsroot/src/sys/arch/arm/xscale/pxa2x0_mci.c,v
retrieving revision 1.6
diff -u -r1.6 pxa2x0_mci.c
--- arch/arm/xscale/pxa2x0_mci.c        1 Oct 2010 09:54:56 -0000       1.6
+++ arch/arm/xscale/pxa2x0_mci.c        1 Oct 2010 13:24:35 -0000
@@ -101,6 +101,7 @@
 static int     pxamci_bus_power(sdmmc_chipset_handle_t, uint32_t);
 static int     pxamci_bus_clock(sdmmc_chipset_handle_t, int);
 static int     pxamci_bus_width(sdmmc_chipset_handle_t, int);
+static int     pxamci_bus_rod(sdmmc_chipset_handle_t, int);
 static void    pxamci_exec_command(sdmmc_chipset_handle_t,
                    struct sdmmc_command *);
 static void    pxamci_card_enable_intr(sdmmc_chipset_handle_t, int);
@@ -124,6 +125,7 @@
        .bus_power              = pxamci_bus_power,
        .bus_clock              = pxamci_bus_clock,
        .bus_width              = pxamci_bus_width,
+       .bus_rod                = pxamci_bus_rod,
 
        /* command execution */
        .exec_command           = pxamci_exec_command,
@@ -548,6 +550,14 @@
        return rv;
 }
 
+static int
+pxamci_bus_rod(sdmmc_chipset_handle_t sch, int on)
+{
+
+       /* not support */
+       return -1;
+}
+
 static void
 pxamci_exec_command(sdmmc_chipset_handle_t sch, struct sdmmc_command *cmd)
 {
Index: dev/ic/w83l518d_sdmmc.c
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/w83l518d_sdmmc.c,v
retrieving revision 1.2
diff -u -r1.2 w83l518d_sdmmc.c
--- dev/ic/w83l518d_sdmmc.c     19 Aug 2010 14:58:22 -0000      1.2
+++ dev/ic/w83l518d_sdmmc.c     1 Oct 2010 13:24:44 -0000
@@ -75,6 +75,7 @@
 static int     wb_sdmmc_bus_power(sdmmc_chipset_handle_t, uint32_t);
 static int     wb_sdmmc_bus_clock(sdmmc_chipset_handle_t, int);
 static int     wb_sdmmc_bus_width(sdmmc_chipset_handle_t, int);
+static int     wb_sdmmc_bus_rod(sdmmc_chipset_handle_t, int);
 static void    wb_sdmmc_exec_command(sdmmc_chipset_handle_t,
                                      struct sdmmc_command *);
 static void    wb_sdmmc_card_enable_intr(sdmmc_chipset_handle_t, int);
@@ -89,6 +90,7 @@
        .bus_power = wb_sdmmc_bus_power,
        .bus_clock = wb_sdmmc_bus_clock,
        .bus_width = wb_sdmmc_bus_width,
+       .bus_width = wb_sdmmc_bus_rod,
        .exec_command = wb_sdmmc_exec_command,
        .card_enable_intr = wb_sdmmc_card_enable_intr,
        .card_intr_ack = wb_sdmmc_card_intr_ack,
@@ -311,6 +313,14 @@
        return 0;
 }
 
+static int
+wb_sdmmc_bus_rod(sdmmc_chipset_handle_t sch, int on)
+{
+
+       /* Not support */
+       return -1;
+}
+
 
 static void
 wb_sdmmc_rsp_read_long(struct wb_softc *wb, struct sdmmc_command *cmd)
Index: dev/marvell/mvsdio.c
===================================================================
RCS file: /cvsroot/src/sys/dev/marvell/mvsdio.c,v
retrieving revision 1.1
diff -u -r1.1 mvsdio.c
--- dev/marvell/mvsdio.c        23 Sep 2010 12:36:01 -0000      1.1
+++ dev/marvell/mvsdio.c        1 Oct 2010 13:24:45 -0000
@@ -236,7 +236,7 @@
        saa.saa_sct = &mvsdio_chip_functions;
        saa.saa_sch = sc;
        saa.saa_dmat = sc->sc_dmat;
-       saa.saa_clkmin = 100;                   /* XXXX: 100 kHz */
+       saa.saa_clkmin = 100;           /* XXXX: 100 kHz from SheevaPlug LSP */
        saa.saa_clkmax = MVSDIO_MAX_CLOCK;
        saa.saa_caps = SMC_CAPS_AUTO_STOP | SMC_CAPS_4BIT_MODE | SMC_CAPS_DMA;
 #ifndef MVSDIO_CARD_DETECT
Index: dev/sdmmc/sdhc.c
===================================================================
RCS file: /cvsroot/src/sys/dev/sdmmc/sdhc.c,v
retrieving revision 1.7
diff -u -r1.7 sdhc.c
--- dev/sdmmc/sdhc.c    27 Mar 2010 03:04:52 -0000      1.7
+++ dev/sdmmc/sdhc.c    1 Oct 2010 13:24:46 -0000
@@ -112,6 +112,7 @@
 static int     sdhc_bus_power(sdmmc_chipset_handle_t, uint32_t);
 static int     sdhc_bus_clock(sdmmc_chipset_handle_t, int);
 static int     sdhc_bus_width(sdmmc_chipset_handle_t, int);
+static int     sdhc_bus_rod(sdmmc_chipset_handle_t, int);
 static void    sdhc_card_enable_intr(sdmmc_chipset_handle_t, int);
 static void    sdhc_card_intr_ack(sdmmc_chipset_handle_t);
 static void    sdhc_exec_command(sdmmc_chipset_handle_t,
@@ -144,6 +145,7 @@
        sdhc_bus_power,
        sdhc_bus_clock,
        sdhc_bus_width,
+       sdhc_bus_rod,
 
        /* command execution */
        sdhc_exec_command,
@@ -630,6 +632,11 @@
         */
        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);
+
 out:
        mutex_exit(&hp->host_mtx);
 
@@ -664,6 +671,14 @@
        return 0;
 }
 
+static int
+sdhc_bus_rod(sdmmc_chipset_handle_t sch, int on)
+{
+
+       /* Nothing ?? */
+       return 0;
+}
+
 static void
 sdhc_card_enable_intr(sdmmc_chipset_handle_t sch, int enable)
 {
Index: dev/sdmmc/sdmmc.c
===================================================================
RCS file: /cvsroot/src/sys/dev/sdmmc/sdmmc.c,v
retrieving revision 1.4
diff -u -r1.4 sdmmc.c
--- dev/sdmmc/sdmmc.c   1 Oct 2010 09:50:42 -0000       1.4
+++ dev/sdmmc/sdmmc.c   1 Oct 2010 13:24:46 -0000
@@ -369,20 +369,6 @@
                goto err;
        }
 
-       /*
-        * Set SD/MMC bus clock.
-        */
-#ifdef SDMMC_DEBUG
-       if ((sc->sc_busclk / 1000) != 0) {
-               DPRINTF(1,("%s: bus clock: %u.%03u MHz\n", DEVNAME(sc),
-                   sc->sc_busclk / 1000, sc->sc_busclk % 1000));
-       } else {
-               DPRINTF(1,("%s: bus clock: %u KHz\n", DEVNAME(sc),
-                   sc->sc_busclk % 1000));
-       }
-#endif
-       (void)sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, sc->sc_busclk);
-
        SIMPLEQ_FOREACH(sf, &sc->sf_head, sf_list) {
                if (ISSET(sc->sc_flags, SMF_IO_MODE) && sf->number < 1)
                        continue;
Index: dev/sdmmc/sdmmc_io.c
===================================================================
RCS file: /cvsroot/src/sys/dev/sdmmc/sdmmc_io.c,v
retrieving revision 1.2
diff -u -r1.2 sdmmc_io.c
--- dev/sdmmc/sdmmc_io.c        5 Dec 2009 22:34:43 -0000       1.2
+++ dev/sdmmc/sdmmc_io.c        1 Oct 2010 13:24:46 -0000
@@ -206,6 +206,12 @@
 #endif
        }
 
+       if (sc->sc_busclk > sf->csd.tran_speed)
+               sc->sc_busclk = sf->csd.tran_speed;
+       error = sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, sc->sc_busclk);
+       if (error)
+               aprint_error_dev(sc->sc_dev, "can't change bus clock\n");
+
 out:
        SDMMC_UNLOCK(sc);
 
Index: dev/sdmmc/sdmmc_mem.c
===================================================================
RCS file: /cvsroot/src/sys/dev/sdmmc/sdmmc_mem.c,v
retrieving revision 1.12
diff -u -r1.12 sdmmc_mem.c
--- dev/sdmmc/sdmmc_mem.c       1 Oct 2010 09:50:42 -0000       1.12
+++ dev/sdmmc/sdmmc_mem.c       1 Oct 2010 13:24:47 -0000
@@ -66,6 +66,8 @@
 #define DPRINTF(s)     do {} while (/*CONSTCOND*/0)
 #endif
 
+static int sdmmc_mem_sd_init(struct sdmmc_softc *, struct sdmmc_function *);
+static int sdmmc_mem_mmc_init(struct sdmmc_softc *, struct sdmmc_function *);
 static int sdmmc_mem_send_cid(struct sdmmc_softc *, sdmmc_response *);
 static int sdmmc_mem_send_csd(struct sdmmc_softc *, struct sdmmc_function *,
     sdmmc_response *);
@@ -74,6 +76,7 @@
 static int sdmmc_mem_decode_scr(struct sdmmc_softc *, struct sdmmc_function *);
 static int sdmmc_mem_send_cxd_data(struct sdmmc_softc *, int, void *, size_t);
 static int sdmmc_set_bus_width(struct sdmmc_function *, int);
+static int sdmmc_mem_sd_switch(struct sdmmc_function *, int, int, int, void *);
 static int sdmmc_mem_mmc_switch(struct sdmmc_function *, uint8_t, uint8_t,
     uint8_t);
 static int sdmmc_mem_spi_read_ocr(struct sdmmc_softc *, uint32_t, uint32_t *);
@@ -253,6 +256,13 @@
                        break;
        }
 
+       if (!ISSET(sc->sc_caps, SMC_CAPS_SPI_MODE))
+               /*
+                * Change ROD to Push-pull.
+                * Go to Data Transfer Mode, if possible.
+                */
+               sdmmc_chip_bus_rod(sc->sc_sct, sc->sc_sch, 0);
+
        /*
         * All cards are either inactive or awaiting further commands.
         * Read the CSDs and decode the raw CID for each card.
@@ -313,6 +323,7 @@
                        SET(sf->flags, SFF_SDHC);
                        csd->capacity = SD_CSD_V2_CAPACITY(resp);
                        csd->read_bl_len = SD_CSD_V2_BL_LEN;
+                       csd->ccc = SD_CSD_CCC(resp);
                        break;
 
                case SD_CSD_CSDVER_1_0:
@@ -356,9 +367,6 @@
        if ((1 << csd->read_bl_len) > SDMMC_SECTOR_SIZE)
                csd->capacity *= (1 << csd->read_bl_len) / SDMMC_SECTOR_SIZE;
 
-       if (sc->sc_busclk > csd->tran_speed)
-               sc->sc_busclk = csd->tran_speed;
-
 #ifdef SDMMC_DUMP_CSD
        sdmmc_print_csd(resp, csd);
 #endif
@@ -436,7 +444,7 @@
 int
 sdmmc_mem_init(struct sdmmc_softc *sc, struct sdmmc_function *sf)
 {
-       int width, value, error = 0;
+       int error = 0;
 
        SDMMC_LOCK(sc);
 
@@ -452,58 +460,10 @@
                        goto out;
        }
 
-        /* change bus width if supported */
-       sf->width = 1;
-       if (ISSET(sc->sc_flags, SMF_SD_MODE)) {
-               error = sdmmc_mem_send_scr(sc, sf, sf->raw_scr);
-               if (error) {
-                       DPRINTF(("%s: SD_SEND_SCR send failed.\n",
-                           SDMMCDEVNAME(sc)));
-                       goto out;
-               }
-               error = sdmmc_mem_decode_scr(sc, sf);
-               if (error)
-                       goto out;
-
-               if (ISSET(sc->sc_caps, SMC_CAPS_4BIT_MODE) &&
-                   ISSET(sf->scr.bus_width, SCR_SD_BUS_WIDTHS_4BIT)) {
-                       error = sdmmc_set_bus_width(sf, 4);
-                       if (error) {
-                               DPRINTF(("%s: can't change bus width"
-                                   " (%d bit)\n", SDMMCDEVNAME(sc), 4));
-                               goto out;
-                       }
-                       sf->width = 4;
-               }
-       } else if (sf->csd.mmcver >= MMC_CSD_MMCVER_4_0) {
-               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->sc_sct,
-                                   sc->sc_sch, width);
-                       else {
-                               DPRINTF(("%s: can't change bus width"
-                                   " (%d bit)\n", SDMMCDEVNAME(sc), width));
-                               goto out;
-                       }
-
-                       /* XXXX: need bus test? (using by CMD14 & CMD19) */
-
-                       sf->width = width;
-               }
-       }
+       if (ISSET(sc->sc_flags, SMF_SD_MODE))
+               error = sdmmc_mem_sd_init(sc, sf);
+       else
+               error = sdmmc_mem_mmc_init(sc, sf);
 
 out:
        SDMMC_UNLOCK(sc);
@@ -617,6 +577,215 @@
 }
 
 static int
+sdmmc_mem_sd_init(struct sdmmc_softc *sc, struct sdmmc_function *sf)
+{
+       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 },
+       };
+       int host_ocr, support_func, best_func, error, g, i;
+       char status[64];
+
+       error = sdmmc_mem_send_scr(sc, sf, sf->raw_scr);
+       if (error) {
+               aprint_error_dev(sc->sc_dev, "SD_SEND_SCR send failed.\n");
+               return error;
+       }
+       error = sdmmc_mem_decode_scr(sc, sf);
+       if (error)
+               return error;
+
+       if (ISSET(sc->sc_caps, SMC_CAPS_4BIT_MODE) &&
+           ISSET(sf->scr.bus_width, SCR_SD_BUS_WIDTHS_4BIT)) {
+               error = sdmmc_set_bus_width(sf, 4);
+               if (error) {
+                       aprint_error_dev(sc->sc_dev,
+                           "can't change bus width (%d bit)\n", 4);
+                       return error;
+               }
+               sf->width = 4;
+       } else
+               sf->width = 1;
+
+       if (sf->scr.sd_spec >= SCR_SD_SPEC_VER_1_10 &&
+           ISSET(sf->csd.ccc, SD_CSD_CCC_SWITCH)) {
+               error = sdmmc_mem_sd_switch(sf, 0, 1, 0, status);
+               if (error) {
+                       aprint_error_dev(sc->sc_dev,
+                           "switch func mode 0 failed\n");
+                       return error;
+               }
+
+               host_ocr = sdmmc_chip_host_ocr(sc->sc_sct, sc->sc_sch);
+               support_func = SFUNC_STATUS_GROUP(status, 1);
+               best_func = 0;
+               for (i = 0, g = 1;
+                   i < __arraycount(switch_group0_functions); i++, g <<= 1) {
+                       if (!(switch_group0_functions[i].v & host_ocr))
+                               continue;
+                       if (g & support_func)
+                               best_func = i;
+               }
+               if (best_func != 0) {
+                       error =
+                           sdmmc_mem_sd_switch(sf, 1, 1, best_func, status);
+                       if (error) {
+                               aprint_error_dev(sc->sc_dev,
+                                   "switch func mode 1 failed:"
+                                   " group 1 function %d(0x%2x)\n",
+                                   best_func, support_func);
+                               return error;
+                       }
+                       sf->csd.tran_speed =
+                           switch_group0_functions[best_func].freq;
+
+                       /* 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->sc_sct, sc->sc_sch,
+                           sc->sc_busclk);
+                       if (error) {
+                               aprint_error_dev(sc->sc_dev,
+                                   "can't change bus clock\n");
+                               return error;
+                       }
+               } else
+                       if (sc->sc_busclk > sf->csd.tran_speed)
+                               sc->sc_busclk = sf->csd.tran_speed;
+       }
+
+       return 0;
+}
+
+static int
+sdmmc_mem_mmc_init(struct sdmmc_softc *sc, struct sdmmc_function *sf)
+{
+       int width, value, hs_timing, error;
+       char ext_csd[512];
+
+       if (sf->csd.mmcver >= MMC_CSD_MMCVER_4_0) {
+               error = sdmmc_mem_send_cxd_data(sc,
+                   MMC_SEND_EXT_CSD, ext_csd, sizeof(ext_csd));
+               if (error) {
+                       aprint_error_dev(sc->sc_dev, "can't read EXT_CSD\n");
+                       return error;
+               }
+               if (ext_csd[EXT_CSD_STRUCTURE] > EXT_CSD_STRUCTURE_VER_1_2) {
+                       aprint_error_dev(sc->sc_dev,
+                           "unrecognised future version\n");
+                       return error;
+               }
+               hs_timing = 0;
+               switch (ext_csd[EXT_CSD_CARD_TYPE]) {
+               case EXT_CSD_CARD_TYPE_26M:
+                       sf->csd.tran_speed = 26000;     /* 26MHz */
+                       break;
+
+               case EXT_CSD_CARD_TYPE_52M | EXT_CSD_CARD_TYPE_26M:
+                       sf->csd.tran_speed = 52000;     /* 52MHz */
+                       hs_timing = 1;
+
+                       error = sdmmc_mem_mmc_switch(sf, EXT_CSD_CMD_SET_NORMAL,
+                           EXT_CSD_HS_TIMING, hs_timing);
+                       if (error) {
+                               aprint_error_dev(sc->sc_dev,
+                                   "can't change high speed\n");
+                               return error;
+                       }
+                       break;
+
+               default:
+                       aprint_error_dev(sc->sc_dev,
+                           "unknwon CARD_TYPE: 0x%x\n",
+                           ext_csd[EXT_CSD_CARD_TYPE]);
+                       return error;
+               }
+               if (sc->sc_busclk > sf->csd.tran_speed)
+                       sc->sc_busclk = sf->csd.tran_speed;
+               error =
+                   sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, sc->sc_busclk);
+               if (error) {
+                       aprint_error_dev(sc->sc_dev,
+                           "can't change bus clock\n");
+                       return error;
+               }
+               if (hs_timing) {
+                       error = sdmmc_mem_send_cxd_data(sc,
+                           MMC_SEND_EXT_CSD, ext_csd, sizeof(ext_csd));
+                       if (error) {
+                               aprint_error_dev(sc->sc_dev,
+                                   "can't re-read EXT_CSD\n");
+                               return error;
+                       }
+                       if (ext_csd[EXT_CSD_HS_TIMING] != hs_timing) {
+                               aprint_error_dev(sc->sc_dev,
+                                   "HS_TIMING set failed\n");
+                               return EINVAL;
+                       }
+               }
+
+               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->sc_sct,
+                                   sc->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) */
+               }
+               sf->width = width;
+       } else {
+               if (sc->sc_busclk > sf->csd.tran_speed)
+                       sc->sc_busclk = sf->csd.tran_speed;
+               error =
+                   sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, sc->sc_busclk);
+               if (error) {
+                       aprint_error_dev(sc->sc_dev,
+                           "can't change bus clock\n");
+                       return error;
+               }
+               sf->width = 1;
+       }
+
+       return 0;
+}
+
+static int
 sdmmc_mem_send_cid(struct sdmmc_softc *sc, sdmmc_response *resp)
 {
        struct sdmmc_command cmd;
@@ -842,19 +1011,6 @@
        return error;
 }
 
-int
-sdmmc_mem_send_extcsd(struct sdmmc_softc *sc)
-{
-       char buf[512];
-       int error;
-
-       error = sdmmc_mem_send_cxd_data(sc, MMC_SEND_EXT_CSD, buf, 512);
-
-       /*XXX*/
-
-       return error;
-}
-
 static int
 sdmmc_set_bus_width(struct sdmmc_function *sf, int width)
 {
@@ -889,6 +1045,84 @@
 }
 
 static int
+sdmmc_mem_sd_switch(struct sdmmc_function *sf, int mode, int group,
+    int function, void *status)
+{
+       struct sdmmc_softc *sc = sf->sc;
+       struct sdmmc_command cmd;
+       bus_dma_segment_t ds[1];
+       void *ptr = NULL;
+       int gsft, rseg, 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 > 16)
+               return EINVAL;
+
+       gsft = (group - 1) << 2;
+
+       if (ISSET(sc->sc_caps, SMC_CAPS_DMA)) {
+               error = bus_dmamem_alloc(sc->sc_dmat, statlen, PAGE_SIZE, 0, ds,
+                   1, &rseg, BUS_DMA_NOWAIT);
+               if (error)
+                       goto out;
+               error = bus_dmamem_map(sc->sc_dmat, ds, 1, statlen, &ptr,
+                   BUS_DMA_NOWAIT);
+               if (error)
+                       goto dmamem_free;
+               error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmap, ptr, statlen,
+                   NULL, BUS_DMA_NOWAIT|BUS_DMA_STREAMING|BUS_DMA_READ);
+               if (error)
+                       goto dmamem_unmap;
+
+               bus_dmamap_sync(sc->sc_dmat, sc->sc_dmap, 0, statlen,
+                   BUS_DMASYNC_PREREAD);
+       } else {
+               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;
+       if (ISSET(sc->sc_caps, SMC_CAPS_DMA))
+               cmd.c_dmamap = sc->sc_dmap;
+
+       error = sdmmc_mmc_command(sc, &cmd);
+       if (error == 0) {
+               if (ISSET(sc->sc_caps, SMC_CAPS_DMA)) {
+                       bus_dmamap_sync(sc->sc_dmat, sc->sc_dmap, 0, statlen,
+                           BUS_DMASYNC_POSTREAD);
+               }
+               memcpy(status, ptr, statlen);
+       }
+
+out:
+       if (ptr != NULL) {
+               if (ISSET(sc->sc_caps, SMC_CAPS_DMA)) {
+                       bus_dmamap_unload(sc->sc_dmat, sc->sc_dmap);
+dmamem_unmap:
+                       bus_dmamem_unmap(sc->sc_dmat, ptr, statlen);
+dmamem_free:
+                       bus_dmamem_free(sc->sc_dmat, ds, rseg);
+               } else {
+                       free(ptr, M_DEVBUF);
+               }
+       }
+       return error;
+}
+
+static int
 sdmmc_mem_mmc_switch(struct sdmmc_function *sf, uint8_t set, uint8_t index,
     uint8_t value)
 {
Index: dev/sdmmc/sdmmcchip.h
===================================================================
RCS file: /cvsroot/src/sys/dev/sdmmc/sdmmcchip.h,v
retrieving revision 1.2
diff -u -r1.2 sdmmcchip.h
--- dev/sdmmc/sdmmcchip.h       6 Apr 2010 15:10:09 -0000       1.2
+++ dev/sdmmc/sdmmcchip.h       1 Oct 2010 13:24:47 -0000
@@ -44,10 +44,11 @@
        /* write protect */
        int             (*write_protect)(sdmmc_chipset_handle_t);
 
-       /* bus power, clock frequency and width */
+       /* bus power, clock frequency, width and ROD(OpenDrain/PushPull) */
        int             (*bus_power)(sdmmc_chipset_handle_t, uint32_t);
        int             (*bus_clock)(sdmmc_chipset_handle_t, int);
        int             (*bus_width)(sdmmc_chipset_handle_t, int);
+       int             (*bus_rod)(sdmmc_chipset_handle_t, int);
 
        /* command execution */
        void            (*exec_command)(sdmmc_chipset_handle_t,
@@ -72,13 +73,15 @@
 /* write protect */
 #define sdmmc_chip_write_protect(tag, handle)                          \
        ((tag)->write_protect((handle)))
-/* bus power, clock frequency and width */
+/* bus power, clock frequency, width and rod */
 #define sdmmc_chip_bus_power(tag, handle, ocr)                         \
        ((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)))
+#define sdmmc_chip_bus_rod(tag, handle, width)                         \
+       ((tag)->bus_rod((handle), (width)))
 /* command execution */
 #define sdmmc_chip_exec_command(tag, handle, cmdp)                     \
        ((tag)->exec_command((handle), (cmdp)))
Index: dev/sdmmc/sdmmcreg.h
===================================================================
RCS file: /cvsroot/src/sys/dev/sdmmc/sdmmcreg.h,v
retrieving revision 1.4
diff -u -r1.4 sdmmcreg.h
--- dev/sdmmc/sdmmcreg.h        6 Apr 2010 15:10:09 -0000       1.4
+++ dev/sdmmc/sdmmcreg.h        1 Oct 2010 13:24:47 -0000
@@ -56,6 +56,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 */
@@ -108,7 +109,11 @@
 #define SD_ARG_BUS_WIDTH_4             2
 
 /* EXT_CSD fields */
-#define EXT_CSD_BUS_WIDTH              183     /* R/W */
+#define EXT_CSD_BUS_WIDTH              183     /* WO */
+#define EXT_CSD_HS_TIMING              185     /* R/W */
+#define EXT_CSD_REV                    192     /* RO */
+#define EXT_CSD_STRUCTURE              194     /* RO */
+#define EXT_CSD_CARD_TYPE              196     /* RO */
 
 /* EXT_CSD field definitions */
 #define EXT_CSD_CMD_SET_NORMAL         (1U << 0)
@@ -120,6 +125,15 @@
 #define EXT_CSD_BUS_WIDTH_4            1       /* 4 bit mode */
 #define EXT_CSD_BUS_WIDTH_8            2       /* 8 bit mode */
 
+/* EXT_CSD_STRUCTURE */
+#define EXT_CSD_STRUCTURE_VER_1_0      0       /* CSD Version No.1.0 */
+#define EXT_CSD_STRUCTURE_VER_1_1      1       /* CSD Version No.1.1 */
+#define EXT_CSD_STRUCTURE_VER_1_2      2       /* Version 4.1-4.2-4.3 */
+
+/* EXT_CSD_CARD_TYPE */
+#define EXT_CSD_CARD_TYPE_26M          (1 << 0)
+#define EXT_CSD_CARD_TYPE_52M          (1 << 1)
+
 /* MMC_SWITCH access mode */
 #define MMC_SWITCH_MODE_CMD_SET                0x00    /* Change the command 
set */
 #define MMC_SWITCH_MODE_SET_BITS       0x01    /* Set bits in value */
@@ -219,7 +233,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)
@@ -273,7 +295,9 @@
 #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 */
+#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 */
@@ -285,6 +309,10 @@
 #define SCR_RESERVED(scr)              MMC_RSP_BITS((scr), 32, 16)
 #define SCR_RESERVED2(scr)             MMC_RSP_BITS((scr), 0, 32)
 
+/* Status of Switch Function */
+#define SFUNC_STATUS_GROUP(status, group) \
+       be16toh(__bitfield((uint32_t *)(status), (7 - (group)) << 4, 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))
 static inline int
Index: dev/sdmmc/sdmmcvar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/sdmmc/sdmmcvar.h,v
retrieving revision 1.7
diff -u -r1.7 sdmmcvar.h
--- dev/sdmmc/sdmmcvar.h        1 Oct 2010 09:50:42 -0000       1.7
+++ dev/sdmmc/sdmmcvar.h        1 Oct 2010 13:24:47 -0000
@@ -40,6 +40,7 @@
        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 */
        /* ... */
 };
 
@@ -329,7 +330,6 @@
 int    sdmmc_mem_send_op_cond(struct sdmmc_softc *, uint32_t, uint32_t *);
 int    sdmmc_mem_send_if_cond(struct sdmmc_softc *, uint32_t, uint32_t *);
 int    sdmmc_mem_set_blocklen(struct sdmmc_softc *, struct sdmmc_function *);
-int    sdmmc_mem_send_extcsd(struct sdmmc_softc *sc);
 int    sdmmc_mem_read_block(struct sdmmc_function *, uint32_t, u_char *,
            size_t);
 int    sdmmc_mem_write_block(struct sdmmc_function *, uint32_t, u_char *,


Home | Main Index | Thread Index | Old Index