Module Name:    src
Committed By:   mlelstv
Date:           Mon Oct 28 06:00:14 UTC 2019

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

Log Message:
Skip setting power when the voltage doesn't change.
Also increase some timeouts.


To generate a diff of this commit:
cvs rdiff -u -r1.104 -r1.105 src/sys/dev/sdmmc/sdhc.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/sdhc.c
diff -u src/sys/dev/sdmmc/sdhc.c:1.104 src/sys/dev/sdmmc/sdhc.c:1.105
--- src/sys/dev/sdmmc/sdhc.c:1.104	Wed Oct 23 05:20:52 2019
+++ src/sys/dev/sdmmc/sdhc.c	Mon Oct 28 06:00:14 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: sdhc.c,v 1.104 2019/10/23 05:20:52 hkenken Exp $	*/
+/*	$NetBSD: sdhc.c,v 1.105 2019/10/28 06:00:14 mlelstv Exp $	*/
 /*	$OpenBSD: sdhc.c,v 1.25 2009/01/13 19:44:20 grange Exp $	*/
 
 /*
@@ -23,7 +23,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sdhc.c,v 1.104 2019/10/23 05:20:52 hkenken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sdhc.c,v 1.105 2019/10/28 06:00:14 mlelstv Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_sdmmc.h"
@@ -98,6 +98,8 @@ struct sdhc_host {
 	bus_dmamap_t		adma_map;
 	bus_dma_segment_t	adma_segs[1];
 	void			*adma2;
+
+	uint8_t			vdd;	/* last vdd setting */
 };
 
 #define HDEVNAME(hp)	(device_xname((hp)->sc->sc_dev))
@@ -156,10 +158,16 @@ hwrite2(struct sdhc_host *hp, bus_size_t
 	}
 }
 
+static void
+hwrite4(struct sdhc_host *hp, bus_size_t o, uint32_t val)
+{
+
+	bus_space_write_4(hp->iot, hp->ioh, o, val);
+}
+
 #define HWRITE1(hp, reg, val)		hwrite1(hp, reg, val)
 #define HWRITE2(hp, reg, val)		hwrite2(hp, reg, val)
-#define HWRITE4(hp, reg, val)						\
-	bus_space_write_4((hp)->iot, (hp)->ioh, (reg), (val))
+#define HWRITE4(hp, reg, val)		hwrite4(hp, reg, val)
 
 #define HCLR1(hp, reg, bits)						\
 	do if (bits) HWRITE1((hp), (reg), HREAD1((hp), (reg)) & ~(bits)); while (0)
@@ -788,6 +796,9 @@ sdhc_host_reset1(sdmmc_chipset_handle_t 
 		HWRITE2(hp, SDHC_NINTR_SIGNAL_EN, 0);
 	}
 
+	/* Let sdhc_bus_power restore power */
+	hp->vdd = 0;
+
 	/*
 	 * Reset the entire host controller and wait up to 100ms for
 	 * the controller to clear the reset bit.
@@ -902,6 +913,7 @@ sdhc_bus_power(sdmmc_chipset_handle_t sc
 	int error = 0;
 	const uint32_t pcmask =
 	    ~(SDHC_BUS_POWER | (SDHC_VOLTAGE_MASK << SDHC_VOLTAGE_SHIFT));
+	uint32_t reg;
 
 	mutex_enter(&hp->intr_lock);
 
@@ -909,8 +921,10 @@ sdhc_bus_power(sdmmc_chipset_handle_t sc
 	 * Disable bus power before voltage change.
 	 */
 	if (!ISSET(hp->sc->sc_flags, SDHC_FLAG_32BIT_ACCESS)
-	    && !ISSET(hp->sc->sc_flags, SDHC_FLAG_NO_PWR0))
+	    && !ISSET(hp->sc->sc_flags, SDHC_FLAG_NO_PWR0)) {
+		hp->vdd = 0;
 		HWRITE1(hp, SDHC_POWER_CTL, 0);
+	}
 
 	/* If power is disabled, reset the host and return now. */
 	if (ocr == 0) {
@@ -935,6 +949,12 @@ sdhc_bus_power(sdmmc_chipset_handle_t sc
 		goto out;
 	}
 
+	/*
+	 * Did voltage change ?
+	 */
+	if (vdd == hp->vdd)
+		goto out;
+
 	if (!ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)) {
 		/*
 		 * Enable bus power.  Wait at least 1 ms (or 74 clocks) plus
@@ -945,13 +965,14 @@ sdhc_bus_power(sdmmc_chipset_handle_t sc
 			HWRITE1(hp, SDHC_POWER_CTL,
 			    (vdd << SDHC_VOLTAGE_SHIFT) | SDHC_BUS_POWER);
 		} else {
-			HWRITE1(hp, SDHC_POWER_CTL,
-			    HREAD1(hp, SDHC_POWER_CTL) & pcmask);
+			reg = HREAD1(hp, SDHC_POWER_CTL) & pcmask;
+			HWRITE1(hp, SDHC_POWER_CTL, reg);
 			sdmmc_delay(1);
-			HWRITE1(hp, SDHC_POWER_CTL,
-			    (vdd << SDHC_VOLTAGE_SHIFT));
+			reg |= (vdd << SDHC_VOLTAGE_SHIFT);
+			HWRITE1(hp, SDHC_POWER_CTL, reg);
 			sdmmc_delay(1);
-			HSET1(hp, SDHC_POWER_CTL, SDHC_BUS_POWER);
+			reg |= SDHC_BUS_POWER;
+			HWRITE1(hp, SDHC_POWER_CTL, reg);
 			sdmmc_delay(10000);
 		}
 
@@ -966,6 +987,9 @@ sdhc_bus_power(sdmmc_chipset_handle_t sc
 		}
 	}
 
+	/* power successfully changed */
+	hp->vdd = vdd;
+
 out:
 	mutex_exit(&hp->intr_lock);
 
@@ -1522,7 +1546,7 @@ sdhc_wait_state(struct sdhc_host *hp, ui
 	uint32_t state;
 	int timeout;
 
-	for (timeout = 10000; timeout > 0; timeout--) {
+	for (timeout = 100000; timeout > 0; timeout--) {
 		if (((state = HREAD4(hp, SDHC_PRESENT_STATE)) & mask) == value)
 			return 0;
 		sdmmc_delay(10);
@@ -1587,7 +1611,7 @@ sdhc_exec_command(sdmmc_chipset_handle_t
 	 * is marked done for any other reason.
 	 */
 	probing = (cmd->c_flags & SCF_TOUT_OK) != 0;
-	if (!sdhc_wait_intr(hp, SDHC_COMMAND_COMPLETE, SDHC_COMMAND_TIMEOUT, probing)) {
+	if (!sdhc_wait_intr(hp, SDHC_COMMAND_COMPLETE, SDHC_COMMAND_TIMEOUT*3, probing)) {
 		DPRINTF(1,("%s: timeout for command\n", __func__));
 		sdmmc_delay(50);
 		cmd->c_error = ETIMEDOUT;

Reply via email to