--- zzzz-none-000/linux-4.4.271/drivers/usb/dwc3/core.c 2021-06-03 06:22:09.000000000 +0000 +++ hawkeye-5590-750/linux-4.4.271/drivers/usb/dwc3/core.c 2023-04-19 10:22:29.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; @@ -59,6 +103,7 @@ reg |= DWC3_GCTL_PRTCAPDIR(mode); dwc3_writel(dwc->regs, DWC3_GCTL, reg); } +EXPORT_SYMBOL(dwc3_set_mode); /** * dwc3_core_soft_reset - Issues core soft reset and PHY reset @@ -171,6 +216,64 @@ } /** + * dwc3_ref_clk_adjustment - Reference clock settings for SOF and ITP + * Default reference clock configurations are calculated assuming + * 19.2 MHz clock source. For other clock source, this will set + * configuration in DWC3_GFLADJ register + * @dwc: Pointer to our controller context structure + * @ref_clk_adj: Value of reference clock settings + */ +static void dwc3_ref_clk_adjustment(struct dwc3 *dwc, u32 ref_clk_adj) +{ + u32 reg; + + if (ref_clk_adj == 0) + return; + + reg = dwc3_readl(dwc->regs, DWC3_GFLADJ); + reg &= ~DWC3_GFLADJ_REFCLK_MASK; + reg |= (ref_clk_adj << DWC3_GFLADJ_REFCLK_SEL); + dwc3_writel(dwc->regs, DWC3_GFLADJ, reg); +} + +/** + * dwc3_ref_clk_period - Reference clock period configuration + * Default reference clock period is calculated assuming + * 19.2 MHz as clock source. For other clock source, this + * will set clock period in DWC3_GUCTL register + * @dwc: Pointer to our controller context structure + * @ref_clk_per: reference clock period in ns + */ +static void dwc3_ref_clk_period(struct dwc3 *dwc, u32 ref_clk_per) +{ + u32 reg; + + if (ref_clk_per == 0) + return; + + reg = dwc3_readl(dwc->regs, DWC3_GUCTL); + reg &= ~DWC3_GUCTL_REFCLKPER_MASK; + reg |= (ref_clk_per << DWC3_GUCTL_REFCLKPER_SEL); + dwc3_writel(dwc->regs, DWC3_GUCTL, reg); +} + +/** + * dwc3_30m_sb_sel_adjustment - 30MHZ side band sel adjustment + * + * @dwc: Pointer to our controller context structure + * @ref_clk_per: 30MHz side band sel value + */ +static void dwc3_30m_sb_sel_adjustment(struct dwc3 *dwc, int sb_30m_sel) +{ + u32 reg; + + reg = dwc3_readl(dwc->regs, DWC3_GFLADJ); + reg &= ~DWC3_GFLADJ_30MHZ_SDBND_SEL_MASK; + reg |= (sb_30m_sel << 7); + dwc3_writel(dwc->regs, DWC3_GFLADJ, reg); +} + +/** * dwc3_free_one_event_buffer - Frees one event buffer * @dwc: Pointer to our controller context structure * @evt: Pointer to event buffer to be freed @@ -265,7 +368,7 @@ * * Returns 0 on success otherwise negative errno. */ -static int dwc3_event_buffers_setup(struct dwc3 *dwc) +int dwc3_event_buffers_setup(struct dwc3 *dwc) { struct dwc3_event_buffer *evt; int n; @@ -289,6 +392,7 @@ return 0; } +EXPORT_SYMBOL(dwc3_event_buffers_setup); static void dwc3_event_buffers_cleanup(struct dwc3 *dwc) { @@ -419,6 +523,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 +666,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. @@ -649,6 +765,12 @@ if (ret) goto err2; + if (dwc->disable_ep_cache_eviction_quirk) { + reg = dwc3_readl(dwc->regs, DWC3_GUCTL2); + reg |= DWC3_GCTL2_ENABLEEPCACHEEVICT; + dwc3_writel(dwc->regs, DWC3_GUCTL2, reg); + } + return 0; err2: @@ -666,7 +788,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); @@ -747,6 +882,7 @@ switch (dwc->dr_mode) { case USB_DR_MODE_PERIPHERAL: + dwc->vbus_active = 1; dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); ret = dwc3_gadget_init(dwc); if (ret) { @@ -764,12 +900,6 @@ break; case USB_DR_MODE_OTG: dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG); - ret = dwc3_host_init(dwc); - if (ret) { - dev_err(dev, "failed to initialize host\n"); - return ret; - } - ret = dwc3_gadget_init(dwc); if (ret) { dev_err(dev, "failed to initialize gadget\n"); @@ -794,7 +924,6 @@ dwc3_host_exit(dwc); break; case USB_DR_MODE_OTG: - dwc3_host_exit(dwc); dwc3_gadget_exit(dwc); break; default: @@ -818,12 +947,14 @@ u8 tx_de_emphasis; u8 hird_threshold; u32 fladj = 0; + u32 ref_clk_adj = 0; + u32 ref_clk_per = 0; int ret; void __iomem *regs; void *mem; - + u32 sb_30m_sel = 0; mem = devm_kzalloc(dev, sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL); if (!mem) return -ENOMEM; @@ -894,6 +1025,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"); @@ -929,6 +1076,16 @@ &dwc->hsphy_interface); device_property_read_u32(dev, "snps,quirk-frame-length-adjustment", &fladj); + device_property_read_u32(dev, "snps,quirk-ref-clock-adjustment", + &ref_clk_adj); + device_property_read_u32(dev, "snps,quirk-ref-clock-period", + &ref_clk_per); + dwc->emulation = of_property_read_bool(dev->of_node, + "qcom,emulation"); + dwc->disable_ep_cache_eviction_quirk = device_property_read_bool(dev, + "snps,dis_ep_cache_eviction"); + device_property_read_u32(dev, "snps,quirk-30m-sb-sel", + &sb_30m_sel); if (pdata) { dwc->maximum_speed = pdata->maximum_speed; @@ -963,6 +1120,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; @@ -976,6 +1143,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; @@ -1011,6 +1182,9 @@ if (dwc->dr_mode == USB_DR_MODE_UNKNOWN) dwc->dr_mode = USB_DR_MODE_OTG; + if (dwc->dr_mode == USB_DR_MODE_OTG) + dwc->is_drd = 1; + ret = dwc3_core_init(dwc); if (ret) { dev_err(dev, "failed to initialize core\n"); @@ -1020,6 +1194,16 @@ /* Adjust Frame Length */ dwc3_frame_length_adjustment(dwc, fladj); + /* Adjust 30m side band sel */ + if (device_property_present(dev, "snps,quirk-30m-sb-sel")) + dwc3_30m_sb_sel_adjustment(dwc, sb_30m_sel); + + /* Adjust Reference Clock Settings */ + dwc3_ref_clk_adjustment(dwc, ref_clk_adj); + + /* Adjust Reference Clock Period */ + dwc3_ref_clk_period(dwc, ref_clk_per); + usb_phy_set_suspend(dwc->usb2_phy, 0); usb_phy_set_suspend(dwc->usb3_phy, 0); ret = phy_power_on(dwc->usb2_generic_phy);