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;