diff options
author | Maarten Lankhorst <maarten.lankhorst@linux.intel.com> | 2022-02-07 19:01:37 +0300 |
---|---|---|
committer | Maarten Lankhorst <maarten.lankhorst@linux.intel.com> | 2022-02-07 19:03:24 +0300 |
commit | 542898c5aa5c6a3179dffb1d1606884a63f75fed (patch) | |
tree | ba096d8eab6a4230782333a036b5de578456eec0 /drivers/usb/dwc2 | |
parent | ccbeca4ca04302d129602093c8d611065e3f7958 (diff) | |
parent | 53dbee4926d3706ca9e03f3928fa85b5ec3bc0cc (diff) | |
download | linux-542898c5aa5c6a3179dffb1d1606884a63f75fed.tar.xz |
Merge remote-tracking branch 'drm/drm-next' into drm-misc-next
First backmerge into drm-misc-next. Required for more helpers backmerged,
and to pull in 5.17 (rc2).
Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Diffstat (limited to 'drivers/usb/dwc2')
-rw-r--r-- | drivers/usb/dwc2/core.h | 6 | ||||
-rw-r--r-- | drivers/usb/dwc2/drd.c | 51 | ||||
-rw-r--r-- | drivers/usb/dwc2/gadget.c | 19 | ||||
-rw-r--r-- | drivers/usb/dwc2/hcd.c | 7 | ||||
-rw-r--r-- | drivers/usb/dwc2/platform.c | 66 |
5 files changed, 97 insertions, 52 deletions
diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h index 37185eb66ae4..8a63da3ab39d 100644 --- a/drivers/usb/dwc2/core.h +++ b/drivers/usb/dwc2/core.h @@ -869,6 +869,8 @@ struct dwc2_hregs_backup { * - USB_DR_MODE_HOST * - USB_DR_MODE_OTG * @role_sw: usb_role_switch handle + * @role_sw_default_mode: default operation mode of controller while usb role + * is USB_ROLE_NONE * @hcd_enabled: Host mode sub-driver initialization indicator. * @gadget_enabled: Peripheral mode sub-driver initialization indicator. * @ll_hw_enabled: Status of low-level hardware resources. @@ -1065,6 +1067,7 @@ struct dwc2_hsotg { enum usb_otg_state op_state; enum usb_dr_mode dr_mode; struct usb_role_switch *role_sw; + enum usb_dr_mode role_sw_default_mode; unsigned int hcd_enabled:1; unsigned int gadget_enabled:1; unsigned int ll_hw_enabled:1; @@ -1151,8 +1154,7 @@ struct dwc2_hsotg { struct list_head periodic_sched_queued; struct list_head split_order; u16 periodic_usecs; - unsigned long hs_periodic_bitmap[ - DIV_ROUND_UP(DWC2_HS_SCHEDULE_US, BITS_PER_LONG)]; + DECLARE_BITMAP(hs_periodic_bitmap, DWC2_HS_SCHEDULE_US); u16 periodic_qh_count; bool new_connection; diff --git a/drivers/usb/dwc2/drd.c b/drivers/usb/dwc2/drd.c index aa6eb76f64dd..1b39c4776369 100644 --- a/drivers/usb/dwc2/drd.c +++ b/drivers/usb/dwc2/drd.c @@ -13,6 +13,10 @@ #include <linux/usb/role.h> #include "core.h" +#define dwc2_ovr_gotgctl(gotgctl) \ + ((gotgctl) |= GOTGCTL_BVALOEN | GOTGCTL_AVALOEN | GOTGCTL_VBVALOEN | \ + GOTGCTL_DBNCE_FLTR_BYPASS) + static void dwc2_ovr_init(struct dwc2_hsotg *hsotg) { unsigned long flags; @@ -21,9 +25,12 @@ static void dwc2_ovr_init(struct dwc2_hsotg *hsotg) spin_lock_irqsave(&hsotg->lock, flags); gotgctl = dwc2_readl(hsotg, GOTGCTL); - gotgctl |= GOTGCTL_BVALOEN | GOTGCTL_AVALOEN | GOTGCTL_VBVALOEN; - gotgctl |= GOTGCTL_DBNCE_FLTR_BYPASS; + dwc2_ovr_gotgctl(gotgctl); gotgctl &= ~(GOTGCTL_BVALOVAL | GOTGCTL_AVALOVAL | GOTGCTL_VBVALOVAL); + if (hsotg->role_sw_default_mode == USB_DR_MODE_HOST) + gotgctl |= GOTGCTL_AVALOVAL | GOTGCTL_VBVALOVAL; + else if (hsotg->role_sw_default_mode == USB_DR_MODE_PERIPHERAL) + gotgctl |= GOTGCTL_BVALOVAL | GOTGCTL_VBVALOVAL; dwc2_writel(hsotg, gotgctl, GOTGCTL); spin_unlock_irqrestore(&hsotg->lock, flags); @@ -40,6 +47,9 @@ static int dwc2_ovr_avalid(struct dwc2_hsotg *hsotg, bool valid) (!valid && !(gotgctl & GOTGCTL_ASESVLD))) return -EALREADY; + /* Always enable overrides to handle the resume case */ + dwc2_ovr_gotgctl(gotgctl); + gotgctl &= ~GOTGCTL_BVALOVAL; if (valid) gotgctl |= GOTGCTL_AVALOVAL | GOTGCTL_VBVALOVAL; @@ -59,6 +69,9 @@ static int dwc2_ovr_bvalid(struct dwc2_hsotg *hsotg, bool valid) (!valid && !(gotgctl & GOTGCTL_BSESVLD))) return -EALREADY; + /* Always enable overrides to handle the resume case */ + dwc2_ovr_gotgctl(gotgctl); + gotgctl &= ~GOTGCTL_AVALOVAL; if (valid) gotgctl |= GOTGCTL_BVALOVAL | GOTGCTL_VBVALOVAL; @@ -105,6 +118,14 @@ static int dwc2_drd_role_sw_set(struct usb_role_switch *sw, enum usb_role role) spin_lock_irqsave(&hsotg->lock, flags); + if (role == USB_ROLE_NONE) { + /* default operation mode when usb role is USB_ROLE_NONE */ + if (hsotg->role_sw_default_mode == USB_DR_MODE_HOST) + role = USB_ROLE_HOST; + else if (hsotg->role_sw_default_mode == USB_DR_MODE_PERIPHERAL) + role = USB_ROLE_DEVICE; + } + if (role == USB_ROLE_HOST) { already = dwc2_ovr_avalid(hsotg, true); } else if (role == USB_ROLE_DEVICE) { @@ -146,6 +167,7 @@ int dwc2_drd_init(struct dwc2_hsotg *hsotg) if (!device_property_read_bool(hsotg->dev, "usb-role-switch")) return 0; + hsotg->role_sw_default_mode = usb_get_role_switch_default_mode(hsotg->dev); role_sw_desc.driver_data = hsotg; role_sw_desc.fwnode = dev_fwnode(hsotg->dev); role_sw_desc.set = dwc2_drd_role_sw_set; @@ -183,6 +205,31 @@ void dwc2_drd_suspend(struct dwc2_hsotg *hsotg) void dwc2_drd_resume(struct dwc2_hsotg *hsotg) { u32 gintsts, gintmsk; + enum usb_role role; + + if (hsotg->role_sw) { + /* get last known role (as the get ops isn't implemented by this driver) */ + role = usb_role_switch_get_role(hsotg->role_sw); + + if (role == USB_ROLE_NONE) { + if (hsotg->role_sw_default_mode == USB_DR_MODE_HOST) + role = USB_ROLE_HOST; + else if (hsotg->role_sw_default_mode == USB_DR_MODE_PERIPHERAL) + role = USB_ROLE_DEVICE; + } + + /* restore last role that may have been lost */ + if (role == USB_ROLE_HOST) + dwc2_ovr_avalid(hsotg, true); + else if (role == USB_ROLE_DEVICE) + dwc2_ovr_bvalid(hsotg, true); + + dwc2_force_mode(hsotg, role == USB_ROLE_HOST); + + dev_dbg(hsotg->dev, "resuming %s-session valid\n", + role == USB_ROLE_NONE ? "No" : + role == USB_ROLE_HOST ? "A" : "B"); + } if (hsotg->role_sw && !hsotg->params.external_id_pin_ctl) { gintsts = dwc2_readl(hsotg, GINTSTS); diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index ab8d7dad9f56..eee3504397e6 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -4974,7 +4974,18 @@ int dwc2_gadget_init(struct dwc2_hsotg *hsotg) hsotg->params.g_np_tx_fifo_size); dev_dbg(dev, "RXFIFO size: %d\n", hsotg->params.g_rx_fifo_size); - hsotg->gadget.max_speed = USB_SPEED_HIGH; + switch (hsotg->params.speed) { + case DWC2_SPEED_PARAM_LOW: + hsotg->gadget.max_speed = USB_SPEED_LOW; + break; + case DWC2_SPEED_PARAM_FULL: + hsotg->gadget.max_speed = USB_SPEED_FULL; + break; + default: + hsotg->gadget.max_speed = USB_SPEED_HIGH; + break; + } + hsotg->gadget.ops = &dwc2_hsotg_gadget_ops; hsotg->gadget.name = dev_name(dev); hsotg->gadget.otg_caps = &hsotg->params.otg_caps; @@ -5086,7 +5097,7 @@ int dwc2_hsotg_suspend(struct dwc2_hsotg *hsotg) hsotg->gadget.speed = USB_SPEED_UNKNOWN; spin_unlock_irqrestore(&hsotg->lock, flags); - for (ep = 0; ep < hsotg->num_of_eps; ep++) { + for (ep = 1; ep < hsotg->num_of_eps; ep++) { if (hsotg->eps_in[ep]) dwc2_hsotg_ep_disable_lock(&hsotg->eps_in[ep]->ep); if (hsotg->eps_out[ep]) @@ -5217,7 +5228,7 @@ int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg, int remote_wakeup) * as result BNA interrupt asserted on hibernation exit * by restoring from saved area. */ - if (hsotg->params.g_dma_desc && + if (using_desc_dma(hsotg) && (dr->diepctl[i] & DXEPCTL_EPENA)) dr->diepdma[i] = hsotg->eps_in[i]->desc_list_dma; dwc2_writel(hsotg, dr->dtxfsiz[i], DPTXFSIZN(i)); @@ -5229,7 +5240,7 @@ int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg, int remote_wakeup) * as result BNA interrupt asserted on hibernation exit * by restoring from saved area. */ - if (hsotg->params.g_dma_desc && + if (using_desc_dma(hsotg) && (dr->doepctl[i] & DXEPCTL_EPENA)) dr->doepdma[i] = hsotg->eps_out[i]->desc_list_dma; dwc2_writel(hsotg, dr->doepdma[i], DOEPDMA(i)); diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index 13c779a28e94..f63a27d11fac 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -4399,11 +4399,12 @@ static int _dwc2_hcd_suspend(struct usb_hcd *hcd) * If not hibernation nor partial power down are supported, * clock gating is used to save power. */ - if (!hsotg->params.no_clock_gating) + if (!hsotg->params.no_clock_gating) { dwc2_host_enter_clock_gating(hsotg); - /* After entering suspend, hardware is not accessible */ - clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + /* After entering suspend, hardware is not accessible */ + clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + } break; default: goto skip_power_saving; diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c index c8f18f3ba9e3..c8ba87df7abe 100644 --- a/drivers/usb/dwc2/platform.c +++ b/drivers/usb/dwc2/platform.c @@ -222,20 +222,16 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg) int i, ret; hsotg->reset = devm_reset_control_get_optional(hsotg->dev, "dwc2"); - if (IS_ERR(hsotg->reset)) { - ret = PTR_ERR(hsotg->reset); - dev_err(hsotg->dev, "error getting reset control %d\n", ret); - return ret; - } + if (IS_ERR(hsotg->reset)) + return dev_err_probe(hsotg->dev, PTR_ERR(hsotg->reset), + "error getting reset control\n"); reset_control_deassert(hsotg->reset); hsotg->reset_ecc = devm_reset_control_get_optional(hsotg->dev, "dwc2-ecc"); - if (IS_ERR(hsotg->reset_ecc)) { - ret = PTR_ERR(hsotg->reset_ecc); - dev_err(hsotg->dev, "error getting reset control for ecc %d\n", ret); - return ret; - } + if (IS_ERR(hsotg->reset_ecc)) + return dev_err_probe(hsotg->dev, PTR_ERR(hsotg->reset_ecc), + "error getting reset control for ecc\n"); reset_control_deassert(hsotg->reset_ecc); @@ -251,11 +247,8 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg) case -ENOSYS: hsotg->phy = NULL; break; - case -EPROBE_DEFER: - return ret; default: - dev_err(hsotg->dev, "error getting phy %d\n", ret); - return ret; + return dev_err_probe(hsotg->dev, ret, "error getting phy\n"); } } @@ -268,12 +261,8 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg) case -ENXIO: hsotg->uphy = NULL; break; - case -EPROBE_DEFER: - return ret; default: - dev_err(hsotg->dev, "error getting usb phy %d\n", - ret); - return ret; + return dev_err_probe(hsotg->dev, ret, "error getting usb phy\n"); } } } @@ -282,10 +271,8 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg) /* Clock */ hsotg->clk = devm_clk_get_optional(hsotg->dev, "otg"); - if (IS_ERR(hsotg->clk)) { - dev_err(hsotg->dev, "cannot get otg clock\n"); - return PTR_ERR(hsotg->clk); - } + if (IS_ERR(hsotg->clk)) + return dev_err_probe(hsotg->dev, PTR_ERR(hsotg->clk), "cannot get otg clock\n"); /* Regulators */ for (i = 0; i < ARRAY_SIZE(hsotg->supplies); i++) @@ -293,12 +280,9 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg) ret = devm_regulator_bulk_get(hsotg->dev, ARRAY_SIZE(hsotg->supplies), hsotg->supplies); - if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(hsotg->dev, "failed to request supplies: %d\n", - ret); - return ret; - } + if (ret) + return dev_err_probe(hsotg->dev, ret, "failed to request supplies\n"); + return 0; } @@ -558,16 +542,12 @@ static int dwc2_driver_probe(struct platform_device *dev) hsotg->usb33d = devm_regulator_get(hsotg->dev, "usb33d"); if (IS_ERR(hsotg->usb33d)) { retval = PTR_ERR(hsotg->usb33d); - if (retval != -EPROBE_DEFER) - dev_err(hsotg->dev, - "failed to request usb33d supply: %d\n", - retval); + dev_err_probe(hsotg->dev, retval, "failed to request usb33d supply\n"); goto error; } retval = regulator_enable(hsotg->usb33d); if (retval) { - dev_err(hsotg->dev, - "failed to enable usb33d supply: %d\n", retval); + dev_err_probe(hsotg->dev, retval, "failed to enable usb33d supply\n"); goto error; } @@ -575,12 +555,14 @@ static int dwc2_driver_probe(struct platform_device *dev) ggpio |= GGPIO_STM32_OTG_GCCFG_IDEN; ggpio |= GGPIO_STM32_OTG_GCCFG_VBDEN; dwc2_writel(hsotg, ggpio, GGPIO); + + /* ID/VBUS detection startup time */ + usleep_range(5000, 7000); } retval = dwc2_drd_init(hsotg); if (retval) { - if (retval != -EPROBE_DEFER) - dev_err(hsotg->dev, "failed to initialize dual-role\n"); + dev_err_probe(hsotg->dev, retval, "failed to initialize dual-role\n"); goto error_init; } @@ -748,10 +730,12 @@ static int __maybe_unused dwc2_resume(struct device *dev) spin_unlock_irqrestore(&dwc2->lock, flags); } - /* Need to restore FORCEDEVMODE/FORCEHOSTMODE */ - dwc2_force_dr_mode(dwc2); - - dwc2_drd_resume(dwc2); + if (!dwc2->role_sw) { + /* Need to restore FORCEDEVMODE/FORCEHOSTMODE */ + dwc2_force_dr_mode(dwc2); + } else { + dwc2_drd_resume(dwc2); + } if (dwc2_is_device_mode(dwc2)) ret = dwc2_hsotg_resume(dwc2); |