diff options
Diffstat (limited to 'drivers/usb/dwc3/core.c')
-rw-r--r-- | drivers/usb/dwc3/core.c | 122 |
1 files changed, 108 insertions, 14 deletions
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 35d092456bec..7287a763cd0c 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -49,6 +49,57 @@ #define DWC3_DEFAULT_AUTOSUSPEND_DELAY 5000 /* ms */ +/** + * dwc3_get_dr_mode - Validates and sets dr_mode + * @dwc: pointer to our context structure + */ +static int dwc3_get_dr_mode(struct dwc3 *dwc) +{ + enum usb_dr_mode mode; + struct device *dev = dwc->dev; + unsigned int hw_mode; + + if (dwc->dr_mode == USB_DR_MODE_UNKNOWN) + dwc->dr_mode = USB_DR_MODE_OTG; + + mode = dwc->dr_mode; + hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0); + + switch (hw_mode) { + case DWC3_GHWPARAMS0_MODE_GADGET: + if (IS_ENABLED(CONFIG_USB_DWC3_HOST)) { + dev_err(dev, + "Controller does not support host mode.\n"); + return -EINVAL; + } + mode = USB_DR_MODE_PERIPHERAL; + break; + case DWC3_GHWPARAMS0_MODE_HOST: + if (IS_ENABLED(CONFIG_USB_DWC3_GADGET)) { + dev_err(dev, + "Controller does not support device mode.\n"); + return -EINVAL; + } + mode = USB_DR_MODE_HOST; + break; + default: + if (IS_ENABLED(CONFIG_USB_DWC3_HOST)) + mode = USB_DR_MODE_HOST; + else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET)) + mode = USB_DR_MODE_PERIPHERAL; + } + + if (mode != dwc->dr_mode) { + dev_warn(dev, + "Configuration mismatch. dr_mode forced to %s\n", + mode == USB_DR_MODE_HOST ? "host" : "gadget"); + + dwc->dr_mode = mode; + } + + return 0; +} + void dwc3_set_mode(struct dwc3 *dwc, u32 mode) { u32 reg; @@ -448,6 +499,9 @@ static int dwc3_phy_setup(struct dwc3 *dwc) if (dwc->dis_u3_susphy_quirk) reg &= ~DWC3_GUSB3PIPECTL_SUSPHY; + if (dwc->dis_del_phy_power_chg_quirk) + reg &= ~DWC3_GUSB3PIPECTL_DEPOCHANGE; + dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); @@ -485,6 +539,23 @@ static int dwc3_phy_setup(struct dwc3 *dwc) break; } + switch (dwc->hsphy_mode) { + case USBPHY_INTERFACE_MODE_UTMI: + reg &= ~(DWC3_GUSB2PHYCFG_PHYIF_MASK | + DWC3_GUSB2PHYCFG_USBTRDTIM_MASK); + reg |= DWC3_GUSB2PHYCFG_PHYIF(UTMI_PHYIF_8_BIT) | + DWC3_GUSB2PHYCFG_USBTRDTIM(USBTRDTIM_UTMI_8_BIT); + break; + case USBPHY_INTERFACE_MODE_UTMIW: + reg &= ~(DWC3_GUSB2PHYCFG_PHYIF_MASK | + DWC3_GUSB2PHYCFG_USBTRDTIM_MASK); + reg |= DWC3_GUSB2PHYCFG_PHYIF(UTMI_PHYIF_16_BIT) | + DWC3_GUSB2PHYCFG_USBTRDTIM(USBTRDTIM_UTMI_16_BIT); + break; + default: + break; + } + /* * Above 1.94a, it is recommended to set DWC3_GUSB2PHYCFG_SUSPHY to * '0' during coreConsultant configuration. So default value will @@ -500,6 +571,9 @@ static int dwc3_phy_setup(struct dwc3 *dwc) if (dwc->dis_enblslpm_quirk) reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM; + if (dwc->dis_u2_freeclk_exists_quirk) + reg &= ~DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS; + dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); return 0; @@ -666,6 +740,32 @@ static int dwc3_core_init(struct dwc3 *dwc) goto err4; } + switch (dwc->dr_mode) { + case USB_DR_MODE_PERIPHERAL: + dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); + break; + case USB_DR_MODE_HOST: + dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST); + break; + case USB_DR_MODE_OTG: + dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG); + break; + default: + dev_warn(dwc->dev, "Unsupported mode %d\n", dwc->dr_mode); + break; + } + + /* + * ENDXFER polling is available on version 3.10a and later of + * the DWC_usb3 controller. It is NOT available in the + * DWC_usb31 controller. + */ + if (!dwc3_is_usb31(dwc) && dwc->revision >= DWC3_REVISION_310A) { + reg = dwc3_readl(dwc->regs, DWC3_GUCTL2); + reg |= DWC3_GUCTL2_RST_ACTBITLATER; + dwc3_writel(dwc->regs, DWC3_GUCTL2, reg); + } + return 0; err4: @@ -763,7 +863,6 @@ static int dwc3_core_init_mode(struct dwc3 *dwc) switch (dwc->dr_mode) { case USB_DR_MODE_PERIPHERAL: - dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); ret = dwc3_gadget_init(dwc); if (ret) { if (ret != -EPROBE_DEFER) @@ -772,7 +871,6 @@ static int dwc3_core_init_mode(struct dwc3 *dwc) } break; case USB_DR_MODE_HOST: - dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST); ret = dwc3_host_init(dwc); if (ret) { if (ret != -EPROBE_DEFER) @@ -781,7 +879,6 @@ static int dwc3_core_init_mode(struct dwc3 *dwc) } break; case USB_DR_MODE_OTG: - dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG); ret = dwc3_host_init(dwc); if (ret) { if (ret != -EPROBE_DEFER) @@ -888,6 +985,7 @@ static int dwc3_probe(struct platform_device *pdev) dwc->maximum_speed = usb_get_maximum_speed(dev); dwc->dr_mode = usb_get_dr_mode(dev); + dwc->hsphy_mode = of_usb_get_phy_mode(dev->of_node); dwc->has_lpm_erratum = device_property_read_bool(dev, "snps,has-lpm-erratum"); @@ -924,6 +1022,10 @@ static int dwc3_probe(struct platform_device *pdev) "snps,dis_enblslpm_quirk"); dwc->dis_rxdet_inp3_quirk = device_property_read_bool(dev, "snps,dis_rxdet_inp3_quirk"); + dwc->dis_u2_freeclk_exists_quirk = device_property_read_bool(dev, + "snps,dis-u2-freeclk-exists-quirk"); + dwc->dis_del_phy_power_chg_quirk = device_property_read_bool(dev, + "snps,dis-del-phy-power-chg-quirk"); dwc->tx_de_emphasis_quirk = device_property_read_bool(dev, "snps,tx_de_emphasis_quirk"); @@ -972,17 +1074,9 @@ static int dwc3_probe(struct platform_device *pdev) goto err2; } - if (IS_ENABLED(CONFIG_USB_DWC3_HOST) && - (dwc->dr_mode == USB_DR_MODE_OTG || - dwc->dr_mode == USB_DR_MODE_UNKNOWN)) - dwc->dr_mode = USB_DR_MODE_HOST; - else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET) && - (dwc->dr_mode == USB_DR_MODE_OTG || - dwc->dr_mode == USB_DR_MODE_UNKNOWN)) - dwc->dr_mode = USB_DR_MODE_PERIPHERAL; - - if (dwc->dr_mode == USB_DR_MODE_UNKNOWN) - dwc->dr_mode = USB_DR_MODE_OTG; + ret = dwc3_get_dr_mode(dwc); + if (ret) + goto err3; ret = dwc3_alloc_scratch_buffers(dwc); if (ret) |