git: 09cdf4878c62 - main - dwc3: add more quirks and checks

From: Bjoern A. Zeeb <bz_at_FreeBSD.org>
Date: Sun, 03 Jul 2022 22:19:39 UTC
The branch main has been updated by bz:

URL: https://cgit.FreeBSD.org/src/commit/?id=09cdf4878c621be4cd229fa88cdccdcdc8c101f7

commit 09cdf4878c621be4cd229fa88cdccdcdc8c101f7
Author:     Bjoern A. Zeeb <bz@FreeBSD.org>
AuthorDate: 2022-07-02 20:56:07 +0000
Commit:     Bjoern A. Zeeb <bz@FreeBSD.org>
CommitDate: 2022-07-03 22:17:35 +0000

    dwc3: add more quirks and checks
    
    Rather than just printing the Global SNPS ID Register store it as well
    so we can do a version check later.
    In addition, for debugging purposes, read the Global Hardware Parameters
    Registers and print them.
    
    Based on the snpsid disable an XHCI feature using a quirk prepared
    in 447c418da03454a2a00bc115a69c62055a6d5272.
    Add the "snps,dis_u3_susphy_quirk" quirk and handle Suspend USB3.0 SS PHY
    after power-on-reset/during core initialization (suggested to be cleared)
    based on the DWC3_GHWPARAMS0 register.
    
    MFC after:      2 weeks
    Obtained from:  an old debugging patch
    Reviewed by:    mw (earlier version), mmel
    Differential Revision: https://reviews.freebsd.org/D35699
---
 sys/dev/usb/controller/dwc3.c | 54 +++++++++++++++++++++++++++++++++++++++----
 sys/dev/usb/controller/dwc3.h |  3 +++
 2 files changed, 53 insertions(+), 4 deletions(-)

diff --git a/sys/dev/usb/controller/dwc3.c b/sys/dev/usb/controller/dwc3.c
index ac94a1327bcf..4b5109291cc4 100644
--- a/sys/dev/usb/controller/dwc3.c
+++ b/sys/dev/usb/controller/dwc3.c
@@ -79,6 +79,7 @@ struct snps_dwc3_softc {
 	phandle_t		node;
 	phy_t			usb2_phy;
 	phy_t			usb3_phy;
+	uint32_t		snpsid;
 };
 
 #define	DWC3_WRITE(_sc, _off, _val)		\
@@ -165,10 +166,30 @@ snsp_dwc3_dump_regs(struct snps_dwc3_softc *sc)
 }
 #endif
 
+#ifdef DWC3_DEBUG
+static void
+snps_dwc3_dump_ctrlparams(struct snps_dwc3_softc *sc)
+{
+	const bus_size_t offs[] = {
+	    DWC3_GHWPARAMS0, DWC3_GHWPARAMS1, DWC3_GHWPARAMS2, DWC3_GHWPARAMS3,
+	    DWC3_GHWPARAMS4, DWC3_GHWPARAMS5, DWC3_GHWPARAMS6, DWC3_GHWPARAMS7,
+	    DWC3_GHWPARAMS8,
+	};
+	uint32_t reg;
+	int i;
+
+	for (i = 0; i < nitems(offs); i++) {
+		reg = DWC3_READ(sc, offs[i]);
+		if (bootverbose)
+			device_printf(sc->dev, "hwparams[%d]: %#012x\n", i, reg);
+	}
+}
+#endif
+
 static void
 snps_dwc3_reset(struct snps_dwc3_softc *sc)
 {
-	uint32_t gctl, phy2, phy3;
+	uint32_t gctl, ghwp0, phy2, phy3;
 
 	if (sc->usb2_phy)
 		phy_enable(sc->usb2_phy);
@@ -179,12 +200,19 @@ snps_dwc3_reset(struct snps_dwc3_softc *sc)
 	gctl |= DWC3_GCTL_CORESOFTRESET;
 	DWC3_WRITE(sc, DWC3_GCTL, gctl);
 
+	ghwp0 = DWC3_READ(sc, DWC3_GHWPARAMS0);
 	phy2 = DWC3_READ(sc, DWC3_GUSB2PHYCFG0);
 	phy2 |= DWC3_GUSB2PHYCFG0_PHYSOFTRST;
+	if ((ghwp0 & DWC3_GHWPARAMS0_MODE_MASK) ==
+	    DWC3_GHWPARAMS0_MODE_DUALROLEDEVICE)
+		phy2 &= ~DWC3_GUSB2PHYCFG0_SUSPENDUSB20;
 	DWC3_WRITE(sc, DWC3_GUSB2PHYCFG0, phy2);
 
 	phy3 = DWC3_READ(sc, DWC3_GUSB3PIPECTL0);
 	phy3 |= DWC3_GUSB3PIPECTL0_PHYSOFTRST;
+	if ((ghwp0 & DWC3_GHWPARAMS0_MODE_MASK) ==
+	    DWC3_GHWPARAMS0_MODE_DUALROLEDEVICE)
+		phy3 &= ~DWC3_GUSB3PIPECTL0_SUSPENDUSB3;
 	DWC3_WRITE(sc, DWC3_GUSB3PIPECTL0, phy3);
 
 	DELAY(1000);
@@ -249,8 +277,10 @@ snps_dwc3_configure_phy(struct snps_dwc3_softc *sc)
 static void
 snps_dwc3_do_quirks(struct snps_dwc3_softc *sc)
 {
-	uint32_t reg;
+	struct xhci_softc *xsc;
+	uint32_t ghwp0, reg;
 
+	ghwp0 = DWC3_READ(sc, DWC3_GHWPARAMS0);
 	reg = DWC3_READ(sc, DWC3_GUSB2PHYCFG0);
 	if (device_has_property(sc->dev, "snps,dis-u2-freeclk-exists-quirk"))
 		reg &= ~DWC3_GUSB2PHYCFG0_U2_FREECLK_EXISTS;
@@ -258,7 +288,8 @@ snps_dwc3_do_quirks(struct snps_dwc3_softc *sc)
 		reg |= DWC3_GUSB2PHYCFG0_U2_FREECLK_EXISTS;
 	if (device_has_property(sc->dev, "snps,dis_u2_susphy_quirk"))
 		reg &= ~DWC3_GUSB2PHYCFG0_SUSPENDUSB20;
-	else
+	else if ((ghwp0 & DWC3_GHWPARAMS0_MODE_MASK) ==
+	    DWC3_GHWPARAMS0_MODE_DUALROLEDEVICE)
 		reg |= DWC3_GUSB2PHYCFG0_SUSPENDUSB20;
 	if (device_has_property(sc->dev, "snps,dis_enblslpm_quirk"))
 		reg &= ~DWC3_GUSB2PHYCFG0_ENBLSLPM;
@@ -276,7 +307,18 @@ snps_dwc3_do_quirks(struct snps_dwc3_softc *sc)
 		reg &= ~DWC3_GUSB3PIPECTL0_DELAYP1TRANS;
 	if (device_has_property(sc->dev, "snps,dis_rxdet_inp3_quirk"))
 		reg |= DWC3_GUSB3PIPECTL0_DISRXDETINP3;
+	if (device_has_property(sc->dev, "snps,dis_u3_susphy_quirk"))
+		reg &= ~DWC3_GUSB3PIPECTL0_SUSPENDUSB3;
+	else if ((ghwp0 & DWC3_GHWPARAMS0_MODE_MASK) ==
+	    DWC3_GHWPARAMS0_MODE_DUALROLEDEVICE)
+		reg |= DWC3_GUSB3PIPECTL0_SUSPENDUSB3;
 	DWC3_WRITE(sc, DWC3_GUSB3PIPECTL0, reg);
+
+	/* Port Disable does not work on <= 3.00a. Disable PORT_PED. */
+	if ((sc->snpsid & 0xffff) <= 0x300a) {
+		xsc = &sc->sc;
+		xsc->sc_quirks |= XHCI_QUIRK_DISABLE_PORT_PED;
+	}
 }
 
 static int
@@ -326,8 +368,12 @@ snps_dwc3_attach(device_t dev)
 	sc->bst = rman_get_bustag(sc->mem_res);
 	sc->bsh = rman_get_bushandle(sc->mem_res);
 
+	sc->snpsid = DWC3_READ(sc, DWC3_GSNPSID);
 	if (bootverbose)
-		device_printf(dev, "snps id: %x\n", DWC3_READ(sc, DWC3_GSNPSID));
+		device_printf(sc->dev, "snps id: %#012x\n", sc->snpsid);
+#ifdef DWC3_DEBUG
+	snps_dwc3_dump_ctrlparams(sc);
+#endif
 
 	/* Get the phys */
 	sc->node = ofw_bus_get_node(dev);
diff --git a/sys/dev/usb/controller/dwc3.h b/sys/dev/usb/controller/dwc3.h
index 862e17b1bcd9..83951d327c8c 100644
--- a/sys/dev/usb/controller/dwc3.h
+++ b/sys/dev/usb/controller/dwc3.h
@@ -59,6 +59,8 @@
 #define	DWC3_GBUSERRADDRHI	0xc134
 #define	DWC3_GPRTBIMAPLO	0xc138
 #define	DWC3_GHWPARAMS0		0xc140
+#define	DWC3_GHWPARAMS0_MODE_DUALROLEDEVICE	0x2
+#define	DWC3_GHWPARAMS0_MODE_MASK		0x3
 #define	DWC3_GHWPARAMS1		0xc144
 #define	DWC3_GHWPARAMS2		0xc148
 #define	DWC3_GHWPARAMS3		0xc14C
@@ -93,6 +95,7 @@
 #define	 DWC3_GUSB3PIPECTL0_PHYSOFTRST		(1 << 31)
 #define	 DWC3_GUSB3PIPECTL0_DISRXDETINP3	(1 << 28)
 #define	 DWC3_GUSB3PIPECTL0_DELAYP1TRANS	(1 << 18)
+#define	 DWC3_GUSB3PIPECTL0_SUSPENDUSB3		(1 << 17)
 
 #define	DWC3_GTXFIFOSIZ(x)	(0xc300 + 0x4 * (x))
 #define	DWC3_GRXFIFOSIZ(x)	(0xc380 + 0x4 * (x))