git: 7518736826a2 - stable/13 - sdhci_xenon: improve the VCCQ voltage switch sequence

From: Marcin Wojtas <mw_at_FreeBSD.org>
Date: Mon, 07 Mar 2022 16:00:08 UTC
The branch stable/13 has been updated by mw:

URL: https://cgit.FreeBSD.org/src/commit/?id=7518736826a2569e2799595d444cbdf0c9c82e5a

commit 7518736826a2569e2799595d444cbdf0c9c82e5a
Author:     Marcin Wojtas <mw@FreeBSD.org>
AuthorDate: 2021-05-27 18:39:12 +0000
Commit:     Marcin Wojtas <mw@FreeBSD.org>
CommitDate: 2022-03-07 15:59:50 +0000

    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
    
    (cherry picked from commit c80e2ca57e0c1b3647b55471584c6d32214232ea)
---
 sys/dev/sdhci/sdhci_xenon.c | 84 ++++++++++++++++++++++++++++++++++++---------
 1 file 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