--- zzzz-none-000/linux-4.4.60/drivers/usb/dwc3/core.c 2017-04-08 07:53:53.000000000 +0000 +++ scorpion-7490-727/linux-4.4.60/drivers/usb/dwc3/core.c 2021-02-04 17:41:59.000000000 +0000 @@ -50,6 +50,50 @@ /* -------------------------------------------------------------------------- */ +void dwc3_usb2phy_suspend(void *priv, + enum usb_device_speed speed, bool suspend) +{ + struct dwc3 *dwc = (struct dwc3 *) priv; + u32 reg; + + if (speed > USB_SPEED_HIGH) + return; + + if (!dwc->enable_usb2susphy_quirk) + return; + + if (suspend) { + /* Enable Suspend USB2.0 HS/FS/LS PHY (SusPHY) */ + reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); + reg |= DWC3_GUSB2PHYCFG_SUSPHY; + dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); + } else { + /* Disable Suspend USB2.0 HS/FS/LS PHY (SusPHY) */ + reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); + reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; + dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); + } +} + +void dwc3_usb2phy_host_discon(void *priv, bool enable) +{ + struct dwc3 *dwc = (struct dwc3 *) priv; + u32 reg; + + if (!dwc->enable_usb2_host_discon_quirk) + return; + + if (enable) { + reg = phy_io_read(dwc->usb2_generic_phy, dwc->phy_misc_reg); + reg |= dwc->phy_host_disc_on; + phy_io_write(dwc->usb2_generic_phy, reg, dwc->phy_misc_reg); + } else { + reg = phy_io_read(dwc->usb2_generic_phy, dwc->phy_misc_reg); + reg &= ~dwc->phy_host_disc_on; + phy_io_write(dwc->usb2_generic_phy, reg, dwc->phy_misc_reg); + } +} + void dwc3_set_mode(struct dwc3 *dwc, u32 mode) { u32 reg; @@ -419,6 +463,33 @@ } /** + * dwc3_read_revision - Reads the revision number + * @dwc: Pointer to our controller context structure + * + * Returns 0 on success. + */ +static int dwc3_read_revision(struct dwc3 *dwc) +{ + u32 reg; + + reg = dwc3_readl(dwc->regs, DWC3_GSNPSID); + /* This should read as U3 followed by revision number */ + if ((reg & DWC3_GSNPSID_MASK) == 0x55330000) { + /* Detected DWC_usb3 IP */ + dwc->revision = reg; + } else if ((reg & DWC3_GSNPSID_MASK) == 0x33310000) { + /* Detected DWC_usb31 IP */ + dwc->revision = dwc3_readl(dwc->regs, DWC3_VER_NUMBER); + dwc->revision |= DWC3_REVISION_IS_DWC31; + } else { + dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n"); + return -ENODEV; + } + + return 0; +} + +/** * dwc3_phy_setup - Configure USB PHY Interface of DWC3 Core * @dwc: Pointer to our controller context structure * @@ -535,21 +606,6 @@ u32 reg; int ret; - reg = dwc3_readl(dwc->regs, DWC3_GSNPSID); - /* This should read as U3 followed by revision number */ - if ((reg & DWC3_GSNPSID_MASK) == 0x55330000) { - /* Detected DWC_usb3 IP */ - dwc->revision = reg; - } else if ((reg & DWC3_GSNPSID_MASK) == 0x33310000) { - /* Detected DWC_usb31 IP */ - dwc->revision = dwc3_readl(dwc->regs, DWC3_VER_NUMBER); - dwc->revision |= DWC3_REVISION_IS_DWC31; - } else { - dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n"); - ret = -ENODEV; - goto err0; - } - /* * Write Linux Version Code to our GUID register so it's easy to figure * out which kernel version a bug was found. @@ -648,7 +704,15 @@ ret = dwc3_setup_scratch_buffers(dwc); if (ret) goto err2; - + /* + * Enable ENABLEEPCACHEEVICT for 3.00a dwc3 host, + * fixed in 3.20a controller + */ + if (dwc->revision == DWC3_REVISION_300A) { + reg = dwc3_readl(dwc->regs, DWC3_GUCTL2); + reg |= DWC3_GCTL2_ENABLEEPCACHEEVICT; + dwc3_writel(dwc->regs, DWC3_GUCTL2, reg); + } return 0; err2: @@ -666,7 +730,20 @@ static void dwc3_core_exit(struct dwc3 *dwc) { + u32 reg; + dwc3_free_scratch_buffers(dwc); + + /* Assert USB3 PHY reset */ + reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); + reg |= DWC3_GUSB3PIPECTL_PHYSOFTRST; + dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); + + /* Assert USB2 PHY reset */ + reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); + reg |= DWC3_GUSB2PHYCFG_PHYSOFTRST; + dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); + usb_phy_shutdown(dwc->usb2_phy); usb_phy_shutdown(dwc->usb3_phy); phy_exit(dwc->usb2_generic_phy); @@ -891,6 +968,22 @@ &hird_threshold); dwc->usb3_lpm_capable = device_property_read_bool(dev, "snps,usb3_lpm_capable"); + dwc->enable_usb2susphy_quirk = device_property_read_bool(dev, + "usb2-susphy-quirk"); + dwc->usb3_dev_reset_quirk = device_property_read_bool(dev, + "usb3_dev_reset_quirk"); + dwc->enable_usb2_host_discon_quirk = + device_property_read_bool(dev, "usb2-host-discon-quirk"); + + if ((dwc->enable_usb2_host_discon_quirk) && + (device_property_read_u32(dev, + "usb2-host-discon-phy-misc-reg", + &dwc->phy_misc_reg) || + device_property_read_u32(dev, "usb2-host-discon-mask", + &dwc->phy_host_disc_on))) { + dev_err(dev, "missing discon quirk params\n"); + return -ENODEV; + } dwc->needs_fifo_resize = device_property_read_bool(dev, "tx-fifo-resize"); @@ -926,6 +1019,8 @@ &dwc->hsphy_interface); device_property_read_u32(dev, "snps,quirk-frame-length-adjustment", &fladj); + dwc->emulation = of_property_read_bool(dev->of_node, + "qcom,emulation"); if (pdata) { dwc->maximum_speed = pdata->maximum_speed; @@ -960,6 +1055,16 @@ fladj = pdata->fladj_value; } + if (dwc->enable_usb2susphy_quirk) { + dwc->susphy.priv = (void *)dwc; + dwc->susphy.set_suspend = &dwc3_usb2phy_suspend; + } + + if (dwc->enable_usb2_host_discon_quirk) { + dwc->susphy.priv = (void *)dwc; + dwc->susphy.set_host_discon = &dwc3_usb2phy_host_discon; + } + /* default to superspeed if no maximum_speed passed */ if (dwc->maximum_speed == USB_SPEED_UNKNOWN) dwc->maximum_speed = USB_SPEED_SUPER; @@ -973,6 +1078,10 @@ platform_set_drvdata(pdev, dwc); dwc3_cache_hwparams(dwc); + ret = dwc3_read_revision(dwc); + if (ret) + goto err0; + ret = dwc3_phy_setup(dwc); if (ret) goto err0;