git: 36b80dba1742 - main - sdhci_fsl_fdt: Add full support for software reset

From: Wojciech Macek <wma_at_FreeBSD.org>
Date: Fri, 05 Nov 2021 09:19:20 UTC
The branch main has been updated by wma:

URL: https://cgit.FreeBSD.org/src/commit/?id=36b80dba1742acfeecfe8c26516c5cf16fd1346d

commit 36b80dba1742acfeecfe8c26516c5cf16fd1346d
Author:     Artur Rojek <ar@semihalf.com>
AuthorDate: 2021-11-05 09:16:30 +0000
Commit:     Wojciech Macek <wma@FreeBSD.org>
CommitDate: 2021-11-05 09:18:57 +0000

    sdhci_fsl_fdt: Add full support for software reset
    
    When performing software reset, this controller does not clear all the
    required hw registers. In particular, tuning block is left in enabled
    state, inhibiting operation of some eMMC cards. The existing solution
    was to disable the ability to call SDHCI_RESET_ALL.
    
    As this issue is now better understood, enable the SDHCI_RESET_ALL flag,
    provide a custom reset devmethod and clear selected registers by hand.
    
    Obtained from: Semihalf
    Sponsored by: Alstom Group
    Differential revision: https://reviews.freebsd.org/D32705
---
 sys/dev/sdhci/sdhci_fsl_fdt.c | 28 +++++++++++++++++++++++++---
 1 file changed, 25 insertions(+), 3 deletions(-)

diff --git a/sys/dev/sdhci/sdhci_fsl_fdt.c b/sys/dev/sdhci/sdhci_fsl_fdt.c
index 5aec394b9192..77af367c5366 100644
--- a/sys/dev/sdhci/sdhci_fsl_fdt.c
+++ b/sys/dev/sdhci/sdhci_fsl_fdt.c
@@ -86,6 +86,9 @@ __FBSDID("$FreeBSD$");
 #define	SDHCI_FSL_HOST_VERSION		0xfc
 #define	SDHCI_FSL_CAPABILITIES2		0x114
 
+#define	SDHCI_FSL_TBCTL			0x120
+#define	SDHCI_FSL_TBCTL_TBEN		(1 << 2)
+
 #define	SDHCI_FSL_ESDHC_CTRL		0x40c
 #define	SDHCI_FSL_ESDHC_CTRL_SNOOP	(1 << 6)
 #define	SDHCI_FSL_ESDHC_CTRL_CLK_DIV2	(1 << 19)
@@ -347,9 +350,6 @@ sdhci_fsl_fdt_write_1(device_t dev, struct sdhci_slot *slot, bus_size_t off,
 		return;
 	case SDHCI_POWER_CONTROL:
 		return;
-	case SDHCI_SOFTWARE_RESET:
-		val &= ~SDHCI_RESET_ALL;
-	/* FALLTHROUGH. */
 	default:
 		val32 = RD4(sc, off & ~3);
 		val32 &= ~(UINT8_MAX << (off & 3) * 8);
@@ -803,6 +803,27 @@ sdhci_fsl_fdt_read_ivar(device_t bus, device_t child, int which,
 	return (sdhci_generic_read_ivar(bus, child, which, result));
 }
 
+static void
+sdhci_fsl_fdt_reset(device_t dev, struct sdhci_slot *slot, uint8_t mask)
+{
+	struct sdhci_fsl_fdt_softc *sc;
+	uint32_t val;
+
+	sdhci_generic_reset(dev, slot, mask);
+
+	if (!(mask & SDHCI_RESET_ALL))
+		return;
+
+	sc = device_get_softc(dev);
+
+	/* Some registers have to be cleared by hand. */
+	if (slot->version >= SDHCI_SPEC_300) {
+		val = RD4(sc, SDHCI_FSL_TBCTL);
+		val &= ~SDHCI_FSL_TBCTL_TBEN;
+		WR4(sc, SDHCI_FSL_TBCTL, val);
+	}
+}
+
 static const device_method_t sdhci_fsl_fdt_methods[] = {
 	/* Device interface. */
 	DEVMETHOD(device_probe,			sdhci_fsl_fdt_probe),
@@ -831,6 +852,7 @@ static const device_method_t sdhci_fsl_fdt_methods[] = {
 	DEVMETHOD(sdhci_write_4,		sdhci_fsl_fdt_write_4),
 	DEVMETHOD(sdhci_write_multi_4,		sdhci_fsl_fdt_write_multi_4),
 	DEVMETHOD(sdhci_get_card_present,	sdhci_fsl_fdt_get_card_present),
+	DEVMETHOD(sdhci_reset,			sdhci_fsl_fdt_reset),
 	DEVMETHOD_END
 };