Source-Changes-HG archive

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

[src/trunk]: src/sys/dev/sdmmc ODROID-C1 has a bug where the card is not powe...



details:   https://anonhg.NetBSD.org/src/rev/d4252a488bca
branches:  trunk
changeset: 809840:d4252a488bca
user:      jmcneill <jmcneill%NetBSD.org@localhost>
date:      Tue Aug 04 01:21:55 2015 +0000

description:
ODROID-C1 has a bug where the card is not power-cycled when the board is
reset. If you had previously switched to 1.8V signaling level, upon reboot
the card will still be in 1.8V mode and you cannot detect it with an S18R
request.

A card in 1.8V mode will report UHS modes though, so if the card reports
SDR50, DDR50, or SDR104 capabilities, and the previous S18R request failed
to switch, use this as an opportunity to re-enable UHS support in the
subsystem and host controller drivers.

diffstat:

 sys/dev/sdmmc/sdmmc_mem.c |  102 +++++++++++++++++++++++++++------------------
 1 files changed, 62 insertions(+), 40 deletions(-)

diffs (160 lines):

diff -r fea706bfdd59 -r d4252a488bca sys/dev/sdmmc/sdmmc_mem.c
--- a/sys/dev/sdmmc/sdmmc_mem.c Tue Aug 04 00:32:05 2015 +0000
+++ b/sys/dev/sdmmc/sdmmc_mem.c Tue Aug 04 01:21:55 2015 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: sdmmc_mem.c,v 1.43 2015/08/04 00:32:05 jmcneill Exp $  */
+/*     $NetBSD: sdmmc_mem.c,v 1.44 2015/08/04 01:21:55 jmcneill Exp $  */
 /*     $OpenBSD: sdmmc_mem.c,v 1.10 2009/01/09 10:55:22 jsg Exp $      */
 
 /*
@@ -45,7 +45,7 @@
 /* Routines for SD/MMC memory cards. */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sdmmc_mem.c,v 1.43 2015/08/04 00:32:05 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sdmmc_mem.c,v 1.44 2015/08/04 01:21:55 jmcneill Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_sdmmc.h"
@@ -82,6 +82,7 @@
 static int sdmmc_mem_sd_switch(struct sdmmc_function *, int, int, int, sdmmc_bitfield512_t *);
 static int sdmmc_mem_mmc_switch(struct sdmmc_function *, uint8_t, uint8_t,
     uint8_t);
+static int sdmmc_mem_signal_voltage(struct sdmmc_softc *, int);
 static int sdmmc_mem_spi_read_ocr(struct sdmmc_softc *, uint32_t, uint32_t *);
 static int sdmmc_mem_single_read_block(struct sdmmc_function *, uint32_t,
     u_char *, size_t);
@@ -138,19 +139,16 @@
        if (ISSET(sc->sc_caps, SMC_CAPS_SPI_MODE))
                sdmmc_spi_chip_initialize(sc->sc_spi_sct, sc->sc_sch);
 
+       /* Reset memory (*must* do that before CMD55 or CMD1). */
+       sdmmc_go_idle_state(sc);
+
        /* Set 3.3V signaling */
        if (sc->sc_sct->signal_voltage) {
-               error = sdmmc_chip_signal_voltage(sc->sc_sct,
-                   sc->sc_sch, SDMMC_SIGNAL_VOLTAGE_330);
+               error = sdmmc_mem_signal_voltage(sc, SDMMC_SIGNAL_VOLTAGE_330);
                if (error)
                        goto out;
-
-               delay(5000);
        }
 
-       /* Reset memory (*must* do that before CMD55 or CMD1). */
-       sdmmc_go_idle_state(sc);
-
        if (ISSET(sc->sc_caps, SMC_CAPS_SPI_MODE)) {
                /* Check SD Ver.2 */
                error = sdmmc_mem_send_if_cond(sc, 0x1aa, &card_ocr);
@@ -248,40 +246,10 @@
                        goto out;
                }
 
-               delay(1000);
-
-               /*
-                * Stop the clock
-                */
-               error = sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch,
-                   SDMMC_SDCLK_OFF, false);
+               error = sdmmc_mem_signal_voltage(sc, SDMMC_SIGNAL_VOLTAGE_180);
                if (error)
                        goto out;
 
-               delay(1000);
-
-               /*
-                * Card switch command was successful, update host controller
-                * signal voltage setting.
-                */
-               DPRINTF(("%s: switching host to 1.8V\n", SDMMCDEVNAME(sc)));
-               error = sdmmc_chip_signal_voltage(sc->sc_sct,
-                   sc->sc_sch, SDMMC_SIGNAL_VOLTAGE_180);
-               if (error)
-                       goto out;
-
-               delay(5000);
-
-               /*
-                * Switch to SDR12 timing
-                */
-               error = sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, 25000,
-                   false);
-               if (error)
-                       goto out;
-
-               delay(1000);
-
                SET(sc->sc_flags, SMF_UHS_MODE);
        }
 
@@ -295,6 +263,48 @@
        return error;
 }
 
+static int
+sdmmc_mem_signal_voltage(struct sdmmc_softc *sc, int signal_voltage)
+{
+       int error;
+
+       /*
+        * Stop the clock
+        */
+       error = sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch,
+           SDMMC_SDCLK_OFF, false);
+       if (error)
+               goto out;
+
+       delay(1000);
+
+       /*
+        * Card switch command was successful, update host controller
+        * signal voltage setting.
+        */
+       DPRINTF(("%s: switching host to %s\n", SDMMCDEVNAME(sc),
+           signal_voltage == SDMMC_SIGNAL_VOLTAGE_180 ? "1.8V" : "3.3V"));
+       error = sdmmc_chip_signal_voltage(sc->sc_sct,
+           sc->sc_sch, signal_voltage);
+       if (error)
+               goto out;
+
+       delay(5000);
+
+       /*
+        * Switch to SDR12 timing
+        */
+       error = sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, 25000,
+           false);
+       if (error)
+               goto out;
+
+       delay(1000);
+
+out:
+       return error;
+}
+
 /*
  * Read the CSD and CID from all cards and assign each card a unique
  * relative card address (RCA).  CMD2 is ignored by SDIO-only cards.
@@ -779,6 +789,18 @@
 
                support_func = SFUNC_STATUS_GROUP(&status, 1);
 
+               if (!ISSET(sc->sc_flags, SMF_UHS_MODE) && support_func & 0x1c) {
+                       /* XXX UHS-I card started in 1.8V mode, switch now */
+                       error = sdmmc_mem_signal_voltage(sc,
+                           SDMMC_SIGNAL_VOLTAGE_180);
+                       if (error) {
+                               aprint_error_dev(sc->sc_dev,
+                                   "failed to recover UHS card\n");
+                               return error;
+                       }
+                       SET(sc->sc_flags, SMF_UHS_MODE);
+               }
+
                for (i = 0; i < __arraycount(switch_group0_functions); i++) {
                        if (!(support_func & (1 << i)))
                                continue;



Home | Main Index | Thread Index | Old Index