[coreboot-gerrit] New patch to review for coreboot: rockchip/rk3399: Add code to neuter Type-C PHY for firmware USB

Martin Roth (martinroth@google.com) gerrit at coreboot.org
Tue Aug 9 18:00:20 CEST 2016


Martin Roth (martinroth at google.com) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/16125

-gerrit

commit 2ffcffda4ec8cc2f18dba15f35a1040d301faf02
Author: Julius Werner <jwerner at chromium.org>
Date:   Wed Aug 3 19:18:39 2016 -0700

    rockchip/rk3399: Add code to neuter Type-C PHY for firmware USB
    
    The Rockchip RK3399 integrates a USB Type-C PHY in charge of things like
    SuperSpeed line muxing for rotated cable orientations in the SoC. While
    fancy, this is very complicated and we don't want to implement support
    for the whole thing in firmware. The USB Type-C standard has
    intentionally been designed in a way that the USB 2.0 (HighSpeed) lines
    always "just work" in any orientation (by just shorting different pins
    in the connector together) so that simple use cases like ours can get
    basic USB functionality without much hassle.
    
    However, a semi-configured Type-C PHY can confuse USB 3.0 capable
    devices into thinking we're actually supporting SuperSpeed, and fail at
    that rather than establishing a reliable HighSpeed connection. This
    patch sets enough bits in the Type-C PHY to electrically isolate the
    SuperSpeed lines from the connector so that the connected device isn't
    going to get any fancy ideas and reliably falls back to USB 2.0.
    
    Also clean up the rest of the USB code while we're at it: avoid writing
    a few bits that are already in the right state from their reset values
    anyway, or reading values whose content we already know for this SoC.
    Rename the USB controllers to the name actually used in the Rockchip
    documentation (USB OTGx) rather than the name blindly copied from
    Exynos code (USB DRDx).
    
    BRANCH=None
    BUG=chrome-os-partner:54621
    TEST=Plug a USB 3.0 Patriot Memory stick into both ports in all
    orientations, observe how it gets reliably detected now (safe for some
    known hardware issues on my board).
    
    Change-Id: Ifce6bcddd69f2e8f2e2a2f48faf65551e084da1e
    Signed-off-by: Martin Roth <martinroth at chromium.org>
    Original-Commit-Id: c526906f998bf66067d3addb8b3d3a126c188b1e
    Original-Change-Id: Ie80a201a58764c4d851fe4a5098a5acfc4bcebdf
    Original-Signed-off-by: Julius Werner <jwerner at chromium.org>
    Original-Reviewed-on: https://chromium-review.googlesource.com/366160
    Original-Reviewed-by: liangfeng wu <wulf at rock-chips.com>
    Original-Reviewed-by: Shelley Chen <shchen at chromium.org>
    Original-Reviewed-by: <515506667 at qq.com>
---
 src/mainboard/google/gru/mainboard.c             |   4 +-
 src/soc/rockchip/rk3399/include/soc/addressmap.h |   6 +-
 src/soc/rockchip/rk3399/include/soc/usb.h        |  36 +++++---
 src/soc/rockchip/rk3399/romstage.c               |  10 +-
 src/soc/rockchip/rk3399/usb.c                    | 112 ++++++++++++-----------
 5 files changed, 89 insertions(+), 79 deletions(-)

diff --git a/src/mainboard/google/gru/mainboard.c b/src/mainboard/google/gru/mainboard.c
index ca71dad..a20103a 100644
--- a/src/mainboard/google/gru/mainboard.c
+++ b/src/mainboard/google/gru/mainboard.c
@@ -164,8 +164,8 @@ static void configure_display(void)
 
 static void setup_usb(void)
 {
-	setup_usb_drd0_dwc3();
-	setup_usb_drd1_dwc3();
+	setup_usb_otg0();
+	setup_usb_otg1();
 }
 
 static void setup_rtc(void)
diff --git a/src/soc/rockchip/rk3399/include/soc/addressmap.h b/src/soc/rockchip/rk3399/include/soc/addressmap.h
index e65674c..d316c38 100644
--- a/src/soc/rockchip/rk3399/include/soc/addressmap.h
+++ b/src/soc/rockchip/rk3399/include/soc/addressmap.h
@@ -70,8 +70,10 @@
 #define DDRC1_BASE_ADDR		0xffa88000
 #define SERVER_MSCH1_BASE_ADDR	0xffa8c000
 
-#define USB_DRD0_DWC3_BASE	0xfe80c100
-#define USB_DRD1_DWC3_BASE	0xfe90c100
+#define USB_OTG0_DWC3_BASE	0xfe80c100
+#define USB_OTG1_DWC3_BASE	0xfe90c100
+#define USB_OTG0_TCPHY_BASE	0xff7c0000
+#define USB_OTG1_TCPHY_BASE	0xff800000
 
 #define IC_BASES  { I2C0_BASE, I2C1_BASE, I2C2_BASE, I2C3_BASE,		\
 			I2C4_BASE, I2C5_BASE, I2C6_BASE, I2C7_BASE, I2C8_BASE }
diff --git a/src/soc/rockchip/rk3399/include/soc/usb.h b/src/soc/rockchip/rk3399/include/soc/usb.h
index 4276a2b..46d3752 100644
--- a/src/soc/rockchip/rk3399/include/soc/usb.h
+++ b/src/soc/rockchip/rk3399/include/soc/usb.h
@@ -32,11 +32,10 @@
 #define DWC3_GCTL_CLK_PIPE			(1)
 #define DWC3_GCTL_CLK_PIPEHALF			(2)
 #define DWC3_GCTL_CLK_MASK			(3)
-#define DWC3_GCTL_PRTCAP(n)			(((n) & (3 << 12)) >> 12)
-#define DWC3_GCTL_PRTCAPDIR(n)			((n) << 12)
-#define DWC3_GCTL_PRTCAP_HOST			1
-#define DWC3_GCTL_PRTCAP_DEVICE			2
-#define DWC3_GCTL_PRTCAP_OTG			3
+#define DWC3_GCTL_PRTCAP_MASK			(3 << 12)
+#define DWC3_GCTL_PRTCAP_HOST			(1 << 12)
+#define DWC3_GCTL_PRTCAP_DEVICE			(2 << 12)
+#define DWC3_GCTL_PRTCAP_OTG			(3 << 12)
 #define DWC3_GCTL_CORESOFTRESET			(1 << 11)
 #define DWC3_GCTL_SCALEDOWN(n)			((n) << 4)
 #define DWC3_GCTL_SCALEDOWN_MASK		DWC3_GCTL_SCALEDOWN(3)
@@ -63,7 +62,7 @@
 #define DWC3_GUSB3PIPECTL_PHYSOFTRST		(1 << 31)
 #define DWC3_GUSB3PIPECTL_SUSPHY		(1 << 17)
 
-struct rockchip_usb_drd_dwc3 {
+struct rockchip_usb_dwc3 {
 	uint32_t sbuscfg0;
 	uint32_t sbuscfg1;
 	uint32_t txthrcfg;
@@ -107,15 +106,22 @@ struct rockchip_usb_drd_dwc3 {
 	uint8_t reserved6[60];
 };
 
-static struct rockchip_usb_drd_dwc3 * const rockchip_usb_drd0_dwc3 =
-		(void *)USB_DRD0_DWC3_BASE;
-static struct rockchip_usb_drd_dwc3 * const rockchip_usb_drd1_dwc3 =
-		(void *)USB_DRD1_DWC3_BASE;
+static struct rockchip_usb_dwc3 * const rockchip_usb_otg0_dwc3 =
+		(void *)USB_OTG0_DWC3_BASE;
+static struct rockchip_usb_dwc3 * const rockchip_usb_otg1_dwc3 =
+		(void *)USB_OTG1_DWC3_BASE;
 
-/* Call reset _ before setup_ */
-void reset_usb_drd0_dwc3(void);
-void reset_usb_drd1_dwc3(void);
-void setup_usb_drd0_dwc3(void);
-void setup_usb_drd1_dwc3(void);
+/* TODO: define struct overlay if we ever need more registers from this */
+#define TCPHY_ISOLATION_CTRL_OFFSET	0x3207c
+#define TCPHY_ISOLATION_CTRL_EN		(1 << 15)
+#define TCPHY_ISOLATION_CTRL_CMN_EN	(1 << 14)
+#define TCPHY_ISOLATION_CTRL_MODE_SEL	(1 << 12)
+#define TCPHY_ISOLATION_CTRL_LN_EN(ln)	(1 << (ln))
+
+/* Call reset_ before setup_ */
+void reset_usb_otg0(void);
+void reset_usb_otg1(void);
+void setup_usb_otg0(void);
+void setup_usb_otg1(void);
 
 #endif /* __SOC_ROCKCHIP_RK3399_USB_H_ */
diff --git a/src/soc/rockchip/rk3399/romstage.c b/src/soc/rockchip/rk3399/romstage.c
index 11454d3..f2ed96a 100644
--- a/src/soc/rockchip/rk3399/romstage.c
+++ b/src/soc/rockchip/rk3399/romstage.c
@@ -93,12 +93,10 @@ static void init_dvs_outputs(void)
 
 static void prepare_usb(void)
 {
-	/*
-	 * Do dwc3 core soft reset and phy reset. Kick these resets
-	 * off early so they get at least 100ms to settle.
-	 */
-	reset_usb_drd0_dwc3();
-	reset_usb_drd1_dwc3();
+	/* Do dwc3 core soft reset and phy reset. Kick these resets
+	 * off early so they get at least 100ms to settle. */
+	reset_usb_otg0();
+	reset_usb_otg1();
 }
 
 void main(void)
diff --git a/src/soc/rockchip/rk3399/usb.c b/src/soc/rockchip/rk3399/usb.c
index df0305f..f638a1e 100644
--- a/src/soc/rockchip/rk3399/usb.c
+++ b/src/soc/rockchip/rk3399/usb.c
@@ -14,57 +14,58 @@
  */
 
 #include <arch/io.h>
+#include <assert.h>
 #include <console/console.h>
 #include <delay.h>
 #include <soc/usb.h>
 
-static void reset_dwc3(struct rockchip_usb_drd_dwc3 *dwc3_reg)
+/* SuperSpeed over Type-C is hard. We don't care about speed in firmware: just
+ * gate off the SuperSpeed lines to have an unimpaired USB 2.0 connection. */
+static void isolate_tcphy(uintptr_t base)
+{
+	write32((void *)(base + TCPHY_ISOLATION_CTRL_OFFSET),
+		TCPHY_ISOLATION_CTRL_EN |
+		TCPHY_ISOLATION_CTRL_CMN_EN |
+		TCPHY_ISOLATION_CTRL_MODE_SEL |
+		TCPHY_ISOLATION_CTRL_LN_EN(7) |
+		TCPHY_ISOLATION_CTRL_LN_EN(6) |
+		TCPHY_ISOLATION_CTRL_LN_EN(5) |
+		TCPHY_ISOLATION_CTRL_LN_EN(4) |
+		TCPHY_ISOLATION_CTRL_LN_EN(3) |
+		TCPHY_ISOLATION_CTRL_LN_EN(2) |
+		TCPHY_ISOLATION_CTRL_LN_EN(1) |
+		TCPHY_ISOLATION_CTRL_LN_EN(0));
+}
+
+static void reset_dwc3(struct rockchip_usb_dwc3 *dwc3)
 {
 	/* Before Resetting PHY, put Core in Reset */
-	setbits_le32(&dwc3_reg->ctl, DWC3_GCTL_CORESOFTRESET);
+	setbits_le32(&dwc3->ctl, DWC3_GCTL_CORESOFTRESET);
 	/* Assert USB3 PHY reset */
-	setbits_le32(&dwc3_reg->usb3pipectl, DWC3_GUSB3PIPECTL_PHYSOFTRST);
+	setbits_le32(&dwc3->usb3pipectl, DWC3_GUSB3PIPECTL_PHYSOFTRST);
 	/* Assert USB2 PHY reset */
-	setbits_le32(&dwc3_reg->usb2phycfg, DWC3_GUSB2PHYCFG_PHYSOFTRST);
+	setbits_le32(&dwc3->usb2phycfg, DWC3_GUSB2PHYCFG_PHYSOFTRST);
 }
 
-static void setup_dwc3(struct rockchip_usb_drd_dwc3 *dwc3_reg)
+static void setup_dwc3(struct rockchip_usb_dwc3 *dwc3)
 {
-	u32 reg;
-	u32 revision;
-	u32 dwc3_hwparams1;
-
-	/* Clear USB3 PHY reset */
-	clrbits_le32(&dwc3_reg->usb3pipectl, DWC3_GUSB3PIPECTL_PHYSOFTRST);
-	/* Clear USB2 PHY reset */
-	clrbits_le32(&dwc3_reg->usb2phycfg, DWC3_GUSB2PHYCFG_PHYSOFTRST);
-	/* After PHYs are stable we can take Core out of reset state */
-	clrbits_le32(&dwc3_reg->ctl, DWC3_GCTL_CORESOFTRESET);
+	u32 usb2phycfg = read32(&dwc3->usb2phycfg);
+	u32 ctl = read32(&dwc3->ctl);
 
-	revision = read32(&dwc3_reg->snpsid);
-	/* This should read as U3 followed by revision number */
-	if ((revision & DWC3_GSNPSID_MASK) != 0x55330000) {
-		printk(BIOS_ERR, "ERROR: not a DesignWare USB3 DRD Core\n");
-		return;
-	}
+	/* Ensure reset_dwc3() has been called before this. */
+	assert(ctl & DWC3_GCTL_CORESOFTRESET);
 
-	dwc3_hwparams1 = read32(&dwc3_reg->hwparams1);
+	/* Clear USB3 PHY reset (oddly enough, this is really necessary). */
+	clrbits_le32(&dwc3->usb3pipectl, DWC3_GUSB3PIPECTL_PHYSOFTRST);
 
-	reg = read32(&dwc3_reg->ctl);
-	reg &= ~DWC3_GCTL_SCALEDOWN_MASK;
-	reg &= ~DWC3_GCTL_DISSCRAMBLE;
-	if (DWC3_GHWPARAMS1_EN_PWROPT(dwc3_hwparams1) ==
-	    DWC3_GHWPARAMS1_EN_PWROPT_CLK)
-		reg &= ~DWC3_GCTL_DSBLCLKGTNG;
-	else
-		printk(BIOS_DEBUG, "No power optimization available\n");
-
-	write32(&dwc3_reg->ctl, reg);
+	/* Clear USB2 PHY and core reset. */
+	usb2phycfg &= ~DWC3_GUSB2PHYCFG_PHYSOFTRST;
+	ctl &= ~DWC3_GCTL_CORESOFTRESET;
 
 	/* We are hard-coding DWC3 core to Host Mode */
-	clrsetbits_le32(&dwc3_reg->ctl,
-			DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG),
-			DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_HOST));
+	ctl &= ~DWC3_GCTL_PRTCAP_MASK;
+	ctl |= DWC3_GCTL_PRTCAP_HOST;
+
 	/*
 	 * Configure USB phy interface of DWC3 core.
 	 * For Rockchip rk3399 SOC DWC3 core:
@@ -73,35 +74,38 @@ static void setup_dwc3(struct rockchip_usb_drd_dwc3 *dwc3_reg)
 	 * 3. Set USBTRDTIM to the corresponding value
 	 * according to the UTMI+ PHY interface.
 	 */
-	reg = read32(&dwc3_reg->usb2phycfg);
-	reg &= ~(DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS |
-		DWC3_GUSB2PHYCFG_USB2TRDTIM_MASK |
-		DWC3_GUSB2PHYCFG_PHYIF_MASK);
-	reg |= DWC3_GUSB2PHYCFG_PHYIF(1) |
-	       DWC3_GUSB2PHYCFG_USBTRDTIM(USBTRDTIM_UTMI_16_BIT);
-	write32(&dwc3_reg->usb2phycfg, reg);
+	usb2phycfg &= ~(DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS |
+			DWC3_GUSB2PHYCFG_USB2TRDTIM_MASK |
+			DWC3_GUSB2PHYCFG_PHYIF_MASK);
+	usb2phycfg |= DWC3_GUSB2PHYCFG_PHYIF(1) |
+		      DWC3_GUSB2PHYCFG_USBTRDTIM(USBTRDTIM_UTMI_16_BIT);
+
+	write32(&dwc3->usb2phycfg, usb2phycfg);
+	write32(&dwc3->ctl, ctl);
 }
 
-void reset_usb_drd0_dwc3(void)
+void reset_usb_otg0(void)
 {
-	printk(BIOS_DEBUG, "Starting DWC3 reset for USB DRD0\n");
-	reset_dwc3(rockchip_usb_drd0_dwc3);
+	printk(BIOS_DEBUG, "Starting DWC3 reset for USB OTG0\n");
+	reset_dwc3(rockchip_usb_otg0_dwc3);
 }
 
-void reset_usb_drd1_dwc3(void)
+void reset_usb_otg1(void)
 {
-	printk(BIOS_DEBUG, "Starting DWC3 reset for USB DRD1\n");
-	reset_dwc3(rockchip_usb_drd1_dwc3);
+	printk(BIOS_DEBUG, "Starting DWC3 reset for USB OTG1\n");
+	reset_dwc3(rockchip_usb_otg1_dwc3);
 }
 
-void setup_usb_drd0_dwc3(void)
+void setup_usb_otg0(void)
 {
-	setup_dwc3(rockchip_usb_drd0_dwc3);
-	printk(BIOS_DEBUG, "DWC3 setup for USB DRD0 finished\n");
+	isolate_tcphy(USB_OTG0_TCPHY_BASE);
+	setup_dwc3(rockchip_usb_otg0_dwc3);
+	printk(BIOS_DEBUG, "DWC3 setup for USB OTG0 finished\n");
 }
 
-void setup_usb_drd1_dwc3(void)
+void setup_usb_otg1(void)
 {
-	setup_dwc3(rockchip_usb_drd1_dwc3);
-	printk(BIOS_DEBUG, "DWC3 setup for USB DRD1 finished\n");
+	isolate_tcphy(USB_OTG1_TCPHY_BASE);
+	setup_dwc3(rockchip_usb_otg1_dwc3);
+	printk(BIOS_DEBUG, "DWC3 setup for USB OTG1 finished\n");
 }



More information about the coreboot-gerrit mailing list