diff --git a/src/soc/rockchip/rk3399/include/soc/usb.h b/src/soc/rockchip/rk3399/include/soc/usb.h index 46d3752328..c2fa1a2af4 100644 --- a/src/soc/rockchip/rk3399/include/soc/usb.h +++ b/src/soc/rockchip/rk3399/include/soc/usb.h @@ -111,12 +111,41 @@ static struct rockchip_usb_dwc3 * const rockchip_usb_otg0_dwc3 = static struct rockchip_usb_dwc3 * const rockchip_usb_otg1_dwc3 = (void *)USB_OTG1_DWC3_BASE; -/* 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)) +#define TCPHY_CMN_HSCLK_PLL_CONFIG 0x30 +#define TCPHY_CMN_HSCLK_PLL_MASK 0x33 + +struct rk3399_tcphy { + uint8_t _res0[0x780 - 0x0]; + uint32_t cmn_diag_hsclk_sel; + uint8_t _res1[0x10000 - 0x784]; + struct { + uint8_t _res2[0x3c8 - 0x0]; + uint32_t xcvr_diag_lane_fcm_en_mgn; + uint8_t _res3[0x408 - 0x3cc]; + uint32_t tx_psc_a2; + uint8_t _res4[0x488 - 0x40c]; + uint32_t tx_rcvdet_en_tmr; + uint32_t tx_rcvdet_st_tmr; + uint8_t _res5[0x784 - 0x490]; + uint32_t tx_diag_tx_drv; + uint8_t _res6[0x800 - 0x788]; + } lane[4]; + uint8_t _res7[0x32000 - 0x12000]; + uint32_t pma_cmn_ctrl1; + uint8_t _res8[0x3207c - 0x32004]; + uint32_t isolation_ctrl; +}; +check_member(rk3399_tcphy, lane[2].tx_diag_tx_drv, 0x11784); +check_member(rk3399_tcphy, isolation_ctrl, 0x3207c); + +static struct rk3399_tcphy * const rockchip_usb_otg0_phy = + (void *)USB_OTG0_TCPHY_BASE; +static struct rk3399_tcphy * const rockchip_usb_otg1_phy = + (void *)USB_OTG1_TCPHY_BASE; /* Call reset_ before setup_ */ void reset_usb_otg0(void); diff --git a/src/soc/rockchip/rk3399/usb.c b/src/soc/rockchip/rk3399/usb.c index 4c731bdf17..e6db1e0d6a 100644 --- a/src/soc/rockchip/rk3399/usb.c +++ b/src/soc/rockchip/rk3399/usb.c @@ -24,9 +24,9 @@ /* 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) +static void isolate_tcphy(struct rk3399_tcphy *tcphy) { - write32((void *)(base + TCPHY_ISOLATION_CTRL_OFFSET), + write32(&tcphy->isolation_ctrl, TCPHY_ISOLATION_CTRL_EN | TCPHY_ISOLATION_CTRL_CMN_EN | TCPHY_ISOLATION_CTRL_MODE_SEL | @@ -40,6 +40,42 @@ static void isolate_tcphy(uintptr_t base) TCPHY_ISOLATION_CTRL_LN_EN(0)); } +static void tcphy_cfg_24m(struct rk3399_tcphy *tcphy) +{ + u32 i; + + /* cmn_ref_clk_sel = 3, select the 24Mhz for clk parent + * cmn_psm_clk_dig_div = 2, set the clk division to 2 */ + write32(&tcphy->pma_cmn_ctrl1, 2 << 10 | 3 << 4); + for (i = 0; i < 4; i++) { + /* The following PHY configuration assumes a + * 24 MHz reference clock */ + write32(&tcphy->lane[i].xcvr_diag_lane_fcm_en_mgn, 0x90); + write32(&tcphy->lane[i].tx_rcvdet_en_tmr, 0x960); + write32(&tcphy->lane[i].tx_rcvdet_st_tmr, 0x30); + } + + clrsetbits_le32(&tcphy->cmn_diag_hsclk_sel, + TCPHY_CMN_HSCLK_PLL_MASK, TCPHY_CMN_HSCLK_PLL_CONFIG); +} + +static void tcphy_phy_init(struct rk3399_tcphy *tcphy) +{ + u32 i; + + tcphy_cfg_24m(tcphy); + + for (i = 0; i < 4; i++) { + /* Enable transmitter reset pull down override for all lanes*/ + write32(&tcphy->lane[i].tx_diag_tx_drv, 0x2000); + /* Disable transmitter low current mode, disable TX + * driver common mode, disable TX post-emphasis*/ + write32(&tcphy->lane[i].tx_psc_a2, 0x0000); + } + + isolate_tcphy(tcphy); +} + static void reset_dwc3(struct rockchip_usb_dwc3 *dwc3) { /* Before Resetting PHY, put Core in Reset */ @@ -89,38 +125,54 @@ static void setup_dwc3(struct rockchip_usb_dwc3 *dwc3) void reset_usb_otg0(void) { + printk(BIOS_DEBUG, "Starting DWC3 and TCPHY reset for USB OTG0\n"); + /* Keep whole USB OTG0 controller in reset, then * configure controller to work in USB 2.0 only mode. */ write32(&cru_ptr->softrst_con[18], RK_SETBITS(1 << 5)); write32(&rk3399_grf->usb3otg0_con1, RK_CLRSETBITS(0xf << 12, 1 << 0)); write32(&cru_ptr->softrst_con[18], RK_CLRBITS(1 << 5)); - printk(BIOS_DEBUG, "Starting DWC3 reset for USB OTG0\n"); + tcphy_phy_init(rockchip_usb_otg0_phy); + + /* Clear TCPHY0 reset */ + write32(&cru_ptr->softrst_con[9], RK_CLRBITS(1 << 5)); + reset_dwc3(rockchip_usb_otg0_dwc3); } void reset_usb_otg1(void) { + printk(BIOS_DEBUG, "Starting DWC3 and TCPHY reset for USB OTG1\n"); + /* Keep whole USB OTG1 controller in reset, then * configure controller to work in USB 2.0 only mode. */ write32(&cru_ptr->softrst_con[18], RK_SETBITS(1 << 6)); write32(&rk3399_grf->usb3otg1_con1, RK_CLRSETBITS(0xf << 12, 1 << 0)); write32(&cru_ptr->softrst_con[18], RK_CLRBITS(1 << 6)); - printk(BIOS_DEBUG, "Starting DWC3 reset for USB OTG1\n"); + tcphy_phy_init(rockchip_usb_otg1_phy); + + /* Clear TCPHY1 reset */ + write32(&cru_ptr->softrst_con[9], RK_CLRBITS(1 << 13)); + reset_dwc3(rockchip_usb_otg1_dwc3); } void setup_usb_otg0(void) { - isolate_tcphy(USB_OTG0_TCPHY_BASE); + /* Clear pipe reset */ + write32(&cru_ptr->softrst_con[9], RK_CLRBITS(1 << 4)); + setup_dwc3(rockchip_usb_otg0_dwc3); - printk(BIOS_DEBUG, "DWC3 setup for USB OTG0 finished\n"); + printk(BIOS_DEBUG, "DWC3 and TCPHY setup for USB OTG0 finished\n"); } void setup_usb_otg1(void) { - isolate_tcphy(USB_OTG1_TCPHY_BASE); + /* Clear pipe reset */ + write32(&cru_ptr->softrst_con[9], RK_CLRBITS(1 << 12)); + setup_dwc3(rockchip_usb_otg1_dwc3); - printk(BIOS_DEBUG, "DWC3 setup for USB OTG1 finished\n"); + printk(BIOS_DEBUG, "DWC3 and TCPHY setup for USB OTG1 finished\n"); }