Module Name:    src
Committed By:   jmcneill
Date:           Tue Aug  4 01:21:55 UTC 2015

Modified Files:
        src/sys/dev/sdmmc: sdmmc_mem.c

Log Message:
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.


To generate a diff of this commit:
cvs rdiff -u -r1.43 -r1.44 src/sys/dev/sdmmc/sdmmc_mem.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/sdmmc/sdmmc_mem.c
diff -u src/sys/dev/sdmmc/sdmmc_mem.c:1.43 src/sys/dev/sdmmc/sdmmc_mem.c:1.44
--- src/sys/dev/sdmmc/sdmmc_mem.c:1.43	Tue Aug  4 00:32:05 2015
+++ src/sys/dev/sdmmc/sdmmc_mem.c	Tue Aug  4 01:21:55 2015
@@ -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_set_bus_width(struct sd
 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 @@ sdmmc_mem_enable(struct sdmmc_softc *sc)
 	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 @@ mmc_mode:
 			goto out;
 		}
 
-		delay(1000);
-
-		/*
-		 * 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 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);
+		error = sdmmc_mem_signal_voltage(sc, SDMMC_SIGNAL_VOLTAGE_180);
 		if (error)
 			goto out;
 
-		delay(1000);
-
 		SET(sc->sc_flags, SMF_UHS_MODE);
 	}
 
@@ -295,6 +263,48 @@ out:
 	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 @@ sdmmc_mem_sd_init(struct sdmmc_softc *sc
 
 		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;

Reply via email to