Source-Changes-HG archive

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

[src/trunk]: src/sys/dev/sdmmc Support High-Speed mode.



details:   https://anonhg.NetBSD.org/src/rev/9c0b8d995e09
branches:  trunk
changeset: 757960:9c0b8d995e09
user:      kiyohara <kiyohara%NetBSD.org@localhost>
date:      Thu Oct 07 12:24:23 2010 +0000

description:
Support High-Speed mode.

diffstat:

 sys/dev/sdmmc/sdmmc.c     |   18 +-
 sys/dev/sdmmc/sdmmc_io.c  |   15 +-
 sys/dev/sdmmc/sdmmc_mem.c |  373 +++++++++++++++++++++++++++++++++++++--------
 sys/dev/sdmmc/sdmmcreg.h  |   36 +++-
 sys/dev/sdmmc/sdmmcvar.h  |    7 +-
 5 files changed, 354 insertions(+), 95 deletions(-)

diffs (truncated from 673 to 300 lines):

diff -r 9dfc8487f01b -r 9c0b8d995e09 sys/dev/sdmmc/sdmmc.c
--- a/sys/dev/sdmmc/sdmmc.c     Thu Oct 07 12:06:09 2010 +0000
+++ b/sys/dev/sdmmc/sdmmc.c     Thu Oct 07 12:24:23 2010 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: sdmmc.c,v 1.4 2010/10/01 09:50:42 kiyohara Exp $       */
+/*     $NetBSD: sdmmc.c,v 1.5 2010/10/07 12:24:23 kiyohara Exp $       */
 /*     $OpenBSD: sdmmc.c,v 1.18 2009/01/09 10:58:38 jsg Exp $  */
 
 /*
@@ -50,7 +50,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sdmmc.c,v 1.4 2010/10/01 09:50:42 kiyohara Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sdmmc.c,v 1.5 2010/10/07 12:24:23 kiyohara Exp $");
 
 #include <sys/param.h>
 #include <sys/device.h>
@@ -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;
diff -r 9dfc8487f01b -r 9c0b8d995e09 sys/dev/sdmmc/sdmmc_io.c
--- a/sys/dev/sdmmc/sdmmc_io.c  Thu Oct 07 12:06:09 2010 +0000
+++ b/sys/dev/sdmmc/sdmmc_io.c  Thu Oct 07 12:24:23 2010 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: sdmmc_io.c,v 1.2 2009/12/05 22:34:43 pooka Exp $       */
+/*     $NetBSD: sdmmc_io.c,v 1.3 2010/10/07 12:24:23 kiyohara Exp $    */
 /*     $OpenBSD: sdmmc_io.c,v 1.10 2007/09/17 01:33:33 krw Exp $       */
 
 /*
@@ -20,7 +20,7 @@
 /* Routines for SD I/O cards. */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sdmmc_io.c,v 1.2 2009/12/05 22:34:43 pooka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sdmmc_io.c,v 1.3 2010/10/07 12:24:23 kiyohara Exp $");
 
 #include <sys/param.h>
 #include <sys/kernel.h>
@@ -158,6 +158,9 @@
        sc->sc_fn0 = sf0;
        SIMPLEQ_INSERT_TAIL(&sc->sf_head, sf0, sf_list);
 
+       /* Go to Data Transfer Mode, if possible. */
+       sdmmc_chip_bus_rod(sc->sc_sct, sc->sc_sch, 0);
+
        /* Verify that the RCA has been set by selecting the card. */
        error = sdmmc_select_card(sc, sf0);
        if (error) {
@@ -204,6 +207,14 @@
                if (sdmmcdebug)
                        sdmmc_print_cis(sf);
 #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:
diff -r 9dfc8487f01b -r 9c0b8d995e09 sys/dev/sdmmc/sdmmc_mem.c
--- a/sys/dev/sdmmc/sdmmc_mem.c Thu Oct 07 12:06:09 2010 +0000
+++ b/sys/dev/sdmmc/sdmmc_mem.c Thu Oct 07 12:24:23 2010 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: sdmmc_mem.c,v 1.12 2010/10/01 09:50:42 kiyohara Exp $  */
+/*     $NetBSD: sdmmc_mem.c,v 1.13 2010/10/07 12:24:23 kiyohara Exp $  */
 /*     $OpenBSD: sdmmc_mem.c,v 1.10 2009/01/09 10:55:22 jsg Exp $      */
 
 /*
@@ -46,7 +46,7 @@
 /* Routines for SD/MMC memory cards. */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sdmmc_mem.c,v 1.12 2010/10/01 09:50:42 kiyohara Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sdmmc_mem.c,v 1.13 2010/10/07 12:24:23 kiyohara Exp $");
 
 #include <sys/param.h>
 #include <sys/kernel.h>
@@ -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,10 @@
                        break;
        }
 
+       if (!ISSET(sc->sc_caps, SMC_CAPS_SPI_MODE))
+               /* 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 +320,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 +364,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 +441,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 +457,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 +574,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;



Home | Main Index | Thread Index | Old Index