diff --git a/drivers/usb/dwc3/dwc3-msm-core.c b/drivers/usb/dwc3/dwc3-msm-core.c index b8cf5be79321..b2a28143984b 100644 --- a/drivers/usb/dwc3/dwc3-msm-core.c +++ b/drivers/usb/dwc3/dwc3-msm-core.c @@ -587,6 +587,8 @@ struct dwc3_msm { bool dis_sending_cm_l1_quirk; bool use_eusb2_phy; bool force_gen1; + bool cached_dis_u1_entry_quirk; + bool cached_dis_u2_entry_quirk; }; #define USB_HSPHY_3P3_VOL_MIN 3050000 /* uV */ @@ -3204,6 +3206,47 @@ static void dwc3_msm_update_imem_pid(struct dwc3 *dwc) } } +static void mdwc3_usb2_phy_soft_reset(struct dwc3_msm *mdwc) +{ + u32 val; + + val = dwc3_msm_read_reg(mdwc->base, DWC3_GUSB2PHYCFG(0)); + dwc3_msm_write_reg(mdwc->base, DWC3_GUSB2PHYCFG(0), + val | DWC3_GUSB2PHYCFG_PHYSOFTRST); + udelay(20); + val = dwc3_msm_read_reg(mdwc->base, DWC3_GUSB2PHYCFG(0)); + val &= ~DWC3_GUSB2PHYCFG_PHYSOFTRST; + dwc3_msm_write_reg(mdwc->base, DWC3_GUSB2PHYCFG(0), val); +} + +static void mdwc3_update_u1u2_value(struct dwc3 *dwc) +{ + struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent); + static bool read_u1u2; + + /* cache DT based initial value once */ + if (!read_u1u2) { + mdwc->cached_dis_u1_entry_quirk = dwc->dis_u1_entry_quirk; + mdwc->cached_dis_u2_entry_quirk = dwc->dis_u2_entry_quirk; + read_u1u2 = true; + dbg_log_string("cached_dt_param: u1_disable:%d u2_disable:%d\n", + mdwc->cached_dis_u1_entry_quirk, mdwc->cached_dis_u2_entry_quirk); + } + + /* Enable u1u2 for USB super speed (gen1) only with quirks enable it */ + if (dwc->speed == DWC3_DSTS_SUPERSPEED) { + dwc->dis_u1_entry_quirk = mdwc->cached_dis_u1_entry_quirk; + dwc->dis_u2_entry_quirk = mdwc->cached_dis_u2_entry_quirk; + } else { + dwc->dis_u1_entry_quirk = true; + dwc->dis_u2_entry_quirk = true; + } + + dbg_log_string("speed:%d u1:%s u2:%s\n", + dwc->speed, dwc->dis_u1_entry_quirk ? "disabled" : "enabled", + dwc->dis_u2_entry_quirk ? "disabled" : "enabled"); +} + void dwc3_msm_notify_event(struct dwc3 *dwc, enum dwc3_notify_event event, unsigned int value) { @@ -3234,6 +3277,20 @@ void dwc3_msm_notify_event(struct dwc3 *dwc, break; case DWC3_CONTROLLER_CONNDONE_EVENT: dev_dbg(mdwc->dev, "DWC3_CONTROLLER_CONNDONE_EVENT received\n"); + + /* + * SW WA for CV9 RESET DEVICE TEST(TD 9.23) compliance failure. + * Visit eUSB2 phy driver for more details. + */ + WARN_ON(mdwc->hs_phy->flags & PHY_HOST_MODE); + if (mdwc->use_eusb2_phy && + (dwc->gadget->speed >= USB_SPEED_SUPER)) { + usb_phy_notify_connect(mdwc->hs_phy, dwc->gadget->speed); + udelay(20); + /* Perform usb2 phy soft reset as given workaround */ + mdwc3_usb2_phy_soft_reset(mdwc); + } + /* * Add power event if the dbm indicates coming out of L1 by * interrupt @@ -3244,6 +3301,7 @@ void dwc3_msm_notify_event(struct dwc3 *dwc, PWR_EVNT_LPM_OUT_L1_MASK, 1); atomic_set(&mdwc->in_lpm, 0); + mdwc3_update_u1u2_value(dwc); break; case DWC3_GSI_EVT_BUF_ALLOC: dev_dbg(mdwc->dev, "DWC3_GSI_EVT_BUF_ALLOC\n");