aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcin Wojtas <mw@FreeBSD.org>2021-05-27 18:39:12 +0000
committerMarcin Wojtas <mw@FreeBSD.org>2021-06-02 07:55:20 +0000
commitc80e2ca57e0c1b3647b55471584c6d32214232ea (patch)
tree43b3077b0986ce0bd8c62e51a12e5e875a78f16a
parentdf868762841b93d934413651818e510ea443def8 (diff)
downloadsrc-c80e2ca57e0c1b3647b55471584c6d32214232ea.tar.gz
src-c80e2ca57e0c1b3647b55471584c6d32214232ea.zip
sdhci_xenon: improve the VCCQ voltage switch sequence
Improve the VCCQ voltage switch, so that to properly handle the SDHCI_HOST_CONTROL2 register signaling flags and along with manipulating the regulator. Reviewed by: manu Obtained from: Semihalf Sponsored by: Marvell Differential Revision: https://reviews.freebsd.org/D30564 MFC after: 2 weeks
-rw-r--r--sys/dev/sdhci/sdhci_xenon.c84
1 files changed, 68 insertions, 16 deletions
diff --git a/sys/dev/sdhci/sdhci_xenon.c b/sys/dev/sdhci/sdhci_xenon.c
index f92d02608abb..42f36b619b36 100644
--- a/sys/dev/sdhci/sdhci_xenon.c
+++ b/sys/dev/sdhci/sdhci_xenon.c
@@ -388,35 +388,87 @@ sdhci_xenon_switch_vccq(device_t brdev, device_t reqdev)
{
struct sdhci_xenon_softc *sc;
struct sdhci_slot *slot;
+ uint16_t hostctrl2;
int uvolt, err;
+ slot = device_get_ivars(reqdev);
+
+ if (slot->version < SDHCI_SPEC_300)
+ return (0);
+
sc = device_get_softc(brdev);
if (sc->mmc_helper.vqmmc_supply == NULL)
return EOPNOTSUPP;
- slot = device_get_ivars(reqdev);
+ err = 0;
+
+ hostctrl2 = bus_read_2(sc->mem_res, SDHCI_HOST_CONTROL2);
switch (slot->host.ios.vccq) {
- case vccq_180:
- uvolt = 1800000;
- break;
case vccq_330:
+ if (!(hostctrl2 & SDHCI_CTRL2_S18_ENABLE))
+ return (0);
+ hostctrl2 &= ~SDHCI_CTRL2_S18_ENABLE;
+ bus_write_2(sc->mem_res, SDHCI_HOST_CONTROL2, hostctrl2);
+
uvolt = 3300000;
- break;
+ err = regulator_set_voltage(sc->mmc_helper.vqmmc_supply,
+ uvolt, uvolt);
+ if (err != 0) {
+ device_printf(sc->dev,
+ "Cannot set vqmmc to %d<->%d\n",
+ uvolt,
+ uvolt);
+ return (err);
+ }
+
+ /*
+ * According to the 'SD Host Controller Simplified
+ * Specification 4.20 the host driver should take more
+ * than 5ms for stable time of host voltage regulator
+ * from changing 1.8V Signaling Enable.
+ */
+ DELAY(5000);
+ hostctrl2 = bus_read_2(sc->mem_res, SDHCI_HOST_CONTROL2);
+ if (!(hostctrl2 & SDHCI_CTRL2_S18_ENABLE))
+ return (0);
+ return EAGAIN;
+ case vccq_180:
+ if (!(slot->host.caps & MMC_CAP_SIGNALING_180)) {
+ return EINVAL;
+ }
+ if (hostctrl2 & SDHCI_CTRL2_S18_ENABLE)
+ return (0);
+ hostctrl2 |= SDHCI_CTRL2_S18_ENABLE;
+ bus_write_2(sc->mem_res, SDHCI_HOST_CONTROL2, hostctrl2);
+
+ uvolt = 1800000;
+ err = regulator_set_voltage(sc->mmc_helper.vqmmc_supply,
+ uvolt, uvolt);
+ if (err != 0) {
+ device_printf(sc->dev,
+ "Cannot set vqmmc to %d<->%d\n",
+ uvolt,
+ uvolt);
+ return (err);
+ }
+
+ /*
+ * According to the 'SD Host Controller Simplified
+ * Specification 4.20 the host driver should take more
+ * than 5ms for stable time of host voltage regulator
+ * from changing 1.8V Signaling Enable.
+ */
+ DELAY(5000);
+ hostctrl2 = bus_read_2(sc->mem_res, SDHCI_HOST_CONTROL2);
+ if (hostctrl2 & SDHCI_CTRL2_S18_ENABLE)
+ return (0);
+ return EAGAIN;
default:
+ device_printf(brdev,
+ "Attempt to set unsupported signaling voltage\n");
return EINVAL;
}
-
- err = regulator_set_voltage(sc->mmc_helper.vqmmc_supply, uvolt, uvolt);
- if (err != 0) {
- device_printf(sc->dev,
- "Cannot set vqmmc to %d<->%d\n",
- uvolt,
- uvolt);
- return (err);
- }
-
- return (0);
}
static int