From 59d7d4c5178d18b58414194271ad85e30ecaff92 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Mon, 17 Jun 2019 11:06:02 +0200 Subject: [PATCH 01/30] dt-bindings: usb: renesas_usbhs: Rename bindings documentation file For consistency with the naming of (most) other documentation files for DT bindings for Renesas IP blocks rename the Renesas USBHS documentation file from renesas-usbhs.txt to renesas,usbhs.txt. Signed-off-by: Simon Horman Signed-off-by: Felipe Balbi --- .../bindings/usb/{renesas_usbhs.txt => renesas,usbhs.txt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Documentation/devicetree/bindings/usb/{renesas_usbhs.txt => renesas,usbhs.txt} (100%) diff --git a/Documentation/devicetree/bindings/usb/renesas_usbhs.txt b/Documentation/devicetree/bindings/usb/renesas,usbhs.txt similarity index 100% rename from Documentation/devicetree/bindings/usb/renesas_usbhs.txt rename to Documentation/devicetree/bindings/usb/renesas,usbhs.txt From 23c46801d14cb647afefc9ec9a7f785777251e76 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Mon, 17 Jun 2019 11:06:03 +0200 Subject: [PATCH 02/30] dt-bindings: usb: renesas_gen3: Rename bindings documentation file For consistency with the naming of (most) other documentation files for DT bindings for Renesas IP blocks rename the Renesas USB3.0 peripheral documentation file from renesas-gen3.txt to renesas,gen3.txt. Signed-off-by: Simon Horman Signed-off-by: Felipe Balbi --- .../bindings/usb/{renesas_usb3.txt => renesas,usb3.txt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Documentation/devicetree/bindings/usb/{renesas_usb3.txt => renesas,usb3.txt} (100%) diff --git a/Documentation/devicetree/bindings/usb/renesas_usb3.txt b/Documentation/devicetree/bindings/usb/renesas,usb3.txt similarity index 100% rename from Documentation/devicetree/bindings/usb/renesas_usb3.txt rename to Documentation/devicetree/bindings/usb/renesas,usb3.txt From f90db10779adab4b2bb12dd5de661616b6fda9e3 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Fri, 14 Jun 2019 10:58:24 +0200 Subject: [PATCH 03/30] usb: dwc3: meson-g12a: Add support for IRQ based OTG switching Add support for the OTG ID change interrupt to switch between Host and Device mode. Tested on the Hardkernel Odroid-N2 board. Signed-off-by: Neil Armstrong Reviewed-by: Martin Blumenstingl Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/dwc3-meson-g12a.c | 36 +++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-meson-g12a.c b/drivers/usb/dwc3/dwc3-meson-g12a.c index 2aec31a2eacb..bca7e92a10e9 100644 --- a/drivers/usb/dwc3/dwc3-meson-g12a.c +++ b/drivers/usb/dwc3/dwc3-meson-g12a.c @@ -11,9 +11,7 @@ * - Control registers for each USB2 Ports * - Control registers for the USB PHY layer * - SuperSpeed PHY can be enabled only if port is used - * - * TOFIX: - * - Add dynamic OTG switching with ID change interrupt + * - Dynamic OTG switching with ID change interrupt */ #include @@ -348,6 +346,22 @@ static enum usb_role dwc3_meson_g12a_role_get(struct device *dev) USB_ROLE_HOST : USB_ROLE_DEVICE; } +static irqreturn_t dwc3_meson_g12a_irq_thread(int irq, void *data) +{ + struct dwc3_meson_g12a *priv = data; + enum phy_mode otg_id; + + otg_id = dwc3_meson_g12a_get_id(priv); + if (otg_id != priv->otg_phy_mode) { + if (dwc3_meson_g12a_otg_mode_set(priv, otg_id)) + dev_warn(priv->dev, "Failed to switch OTG mode\n"); + } + + regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_IRQ, 0); + + return IRQ_HANDLED; +} + static struct device *dwc3_meson_g12_find_child(struct device *dev, const char *compatible) { @@ -374,7 +388,7 @@ static int dwc3_meson_g12a_probe(struct platform_device *pdev) void __iomem *base; struct resource *res; enum phy_mode otg_id; - int ret, i; + int ret, i, irq; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -436,6 +450,19 @@ static int dwc3_meson_g12a_probe(struct platform_device *pdev) /* Get dr_mode */ priv->otg_mode = usb_get_dr_mode(dev); + if (priv->otg_mode == USB_DR_MODE_OTG) { + /* Ack irq before registering */ + regmap_update_bits(priv->regmap, USB_R5, + USB_R5_ID_DIG_IRQ, 0); + + irq = platform_get_irq(pdev, 0); + ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, + dwc3_meson_g12a_irq_thread, + IRQF_ONESHOT, pdev->name, priv); + if (ret) + return ret; + } + dwc3_meson_g12a_usb_init(priv); /* Init PHYs */ @@ -460,7 +487,6 @@ static int dwc3_meson_g12a_probe(struct platform_device *pdev) /* Setup OTG mode corresponding to the ID pin */ if (priv->otg_mode == USB_DR_MODE_OTG) { - /* TOFIX Handle ID mode toggling via IRQ */ otg_id = dwc3_meson_g12a_get_id(priv); if (otg_id != priv->otg_phy_mode) { if (dwc3_meson_g12a_otg_mode_set(priv, otg_id)) From 1112cf4c4109473fd8a30a4678d25f9321ef5d67 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Fri, 14 Jun 2019 08:52:53 +0200 Subject: [PATCH 04/30] usb: dwc2: Force 8bit UTMI width for Samsung Exynos SoCs Samsung Exynos SoCs require to force UTMI width to 8bit, otherwise the host side of the shared USB2 PHY doesn't work. Reported-by: Krzysztof Kozlowski Fixes: 707d80f0a3c5 ("usb: dwc2: gadget: Replace phyif with phy_utmi_width") Signed-off-by: Marek Szyprowski Acked-by: Minas Harutyunyan Acked-by: Krzysztof Kozlowski Tested-by: Krzysztof Kozlowski Signed-off-by: Felipe Balbi --- drivers/usb/dwc2/params.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c index 6900eea57526..9ece4affb9d4 100644 --- a/drivers/usb/dwc2/params.c +++ b/drivers/usb/dwc2/params.c @@ -76,6 +76,7 @@ static void dwc2_set_s3c6400_params(struct dwc2_hsotg *hsotg) struct dwc2_core_params *p = &hsotg->params; p->power_down = 0; + p->phy_utmi_width = 8; } static void dwc2_set_rk_params(struct dwc2_hsotg *hsotg) From cd5f9726773b654f8e1cfd6ec1a989c558fa164b Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Mon, 20 May 2019 10:56:03 -0700 Subject: [PATCH 05/30] Documentation: dt-bindings: Add snps,need-phy-for-wake for dwc2 USB Some SoCs with a dwc2 USB controller may need to keep the PHY on to support remote wakeup. Allow specifying this as a device tree property. Reviewed-by: Rob Herring Signed-off-by: Douglas Anderson Signed-off-by: Felipe Balbi --- Documentation/devicetree/bindings/usb/dwc2.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/usb/dwc2.txt b/Documentation/devicetree/bindings/usb/dwc2.txt index 49eac0dc86b0..aafff3a6904d 100644 --- a/Documentation/devicetree/bindings/usb/dwc2.txt +++ b/Documentation/devicetree/bindings/usb/dwc2.txt @@ -42,6 +42,8 @@ Refer to phy/phy-bindings.txt for generic phy consumer properties - g-rx-fifo-size: size of rx fifo size in gadget mode. - g-np-tx-fifo-size: size of non-periodic tx fifo size in gadget mode. - g-tx-fifo-size: size of periodic tx fifo per endpoint (except ep0) in gadget mode. +- snps,need-phy-for-wake: If present indicates that the phy needs to be left + on for remote wakeup during suspend. - snps,reset-phy-on-wake: If present indicates that we need to reset the PHY when we detect a wakeup. This is due to a hardware errata. @@ -58,4 +60,5 @@ Example: clock-names = "otg"; phys = <&usbphy>; phy-names = "usb2-phy"; + snps,need-phy-for-wake; }; From 1d390437f605db28596ad4c4bfeca2fed052c025 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Mon, 20 May 2019 10:56:05 -0700 Subject: [PATCH 06/30] ARM: dts: rockchip: Allow wakeup from rk3288-veyron's dwc2 USB ports We want to be able to wake from USB if a device is plugged in that wants remote wakeup. Enable it on both dwc2 controllers. NOTE: this is added specifically to veyron and not to rk3288 in general since it's not known whether all rk3288 boards are designed to support USB wakeup. It is plausible that some boards could shut down important rails in S3. Also note that currently wakeup doesn't seem to happen unless you use the "deep" suspend mode (where SDRAM is turned off). Presumably the shallow suspend mode is gating some sort of clock that's important but I couldn't easily figure out how to get it working. Signed-off-by: Douglas Anderson Signed-off-by: Felipe Balbi --- arch/arm/boot/dts/rk3288-veyron.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/boot/dts/rk3288-veyron.dtsi b/arch/arm/boot/dts/rk3288-veyron.dtsi index 1252522392c7..1d8bfed7830c 100644 --- a/arch/arm/boot/dts/rk3288-veyron.dtsi +++ b/arch/arm/boot/dts/rk3288-veyron.dtsi @@ -424,6 +424,7 @@ &usb_host1 { status = "okay"; + snps,need-phy-for-wake; }; &usb_otg { @@ -432,6 +433,7 @@ assigned-clocks = <&cru SCLK_USBPHY480M_SRC>; assigned-clock-parents = <&usbphy0>; dr_mode = "host"; + snps,need-phy-for-wake; }; &vopb { From c846b03ff767149d75d4d8dca6d3d4945a21074a Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Mon, 20 May 2019 10:56:04 -0700 Subject: [PATCH 07/30] USB: dwc2: Don't turn off the usbphy in suspend if wakeup is enabled If the 'snps,need-phy-for-wake' is set in the device tree then: - We know that we can wakeup, so call device_set_wakeup_capable(). The USB core will use this knowledge to enable wakeup by default. - We know that we should keep the PHY on during suspend if something on our root hub needs remote wakeup. This requires the patch (USB: Export usb_wakeup_enabled_descendants()). Note that we don't keep the PHY on at suspend time if it's not needed because it would be a power draw. If we later find some users of dwc2 that can support wakeup without keeping the PHY on we may want to add a way to call device_set_wakeup_capable() without keeping the PHY on at suspend time. Signed-off-by: Douglas Anderson Signed-off-by: Chris Zhong Signed-off-by: Felipe Balbi --- drivers/usb/dwc2/core.h | 8 ++++++++ drivers/usb/dwc2/hcd.c | 19 +++++++++++++++++++ drivers/usb/dwc2/platform.c | 23 ++++++++++++++++++++--- 3 files changed, 47 insertions(+), 3 deletions(-) diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h index 152ac41dfb2d..d08d070a0fb6 100644 --- a/drivers/usb/dwc2/core.h +++ b/drivers/usb/dwc2/core.h @@ -861,6 +861,9 @@ struct dwc2_hregs_backup { * @hibernated: True if core is hibernated * @reset_phy_on_wake: Quirk saying that we should assert PHY reset on a * remote wakeup. + * @phy_off_for_suspend: Status of whether we turned the PHY off at suspend. + * @need_phy_for_wake: Quirk saying that we should keep the PHY on at + * suspend if we need USB to wake us up. * @frame_number: Frame number read from the core. For both device * and host modes. The value ranges are from 0 * to HFNUM_MAX_FRNUM. @@ -1049,6 +1052,8 @@ struct dwc2_hsotg { unsigned int ll_hw_enabled:1; unsigned int hibernated:1; unsigned int reset_phy_on_wake:1; + unsigned int need_phy_for_wake:1; + unsigned int phy_off_for_suspend:1; u16 frame_number; struct phy *phy; @@ -1438,6 +1443,7 @@ int dwc2_restore_host_registers(struct dwc2_hsotg *hsotg); int dwc2_host_enter_hibernation(struct dwc2_hsotg *hsotg); int dwc2_host_exit_hibernation(struct dwc2_hsotg *hsotg, int rem_wakeup, int reset); +bool dwc2_host_can_poweroff_phy(struct dwc2_hsotg *dwc2); static inline void dwc2_host_schedule_phy_reset(struct dwc2_hsotg *hsotg) { schedule_work(&hsotg->phy_reset_work); } #else @@ -1463,6 +1469,8 @@ static inline int dwc2_host_enter_hibernation(struct dwc2_hsotg *hsotg) static inline int dwc2_host_exit_hibernation(struct dwc2_hsotg *hsotg, int rem_wakeup, int reset) { return 0; } +static inline bool dwc2_host_can_poweroff_phy(struct dwc2_hsotg *dwc2) +{ return false; } static inline void dwc2_host_schedule_phy_reset(struct dwc2_hsotg *hsotg) {} #endif diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index 2192a2873c7c..4c78a390c958 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -5587,3 +5587,22 @@ int dwc2_host_exit_hibernation(struct dwc2_hsotg *hsotg, int rem_wakeup, dev_dbg(hsotg->dev, "Host hibernation restore complete\n"); return ret; } + +bool dwc2_host_can_poweroff_phy(struct dwc2_hsotg *dwc2) +{ + struct usb_device *root_hub = dwc2_hsotg_to_hcd(dwc2)->self.root_hub; + + /* If the controller isn't allowed to wakeup then we can power off. */ + if (!device_may_wakeup(dwc2->dev)) + return true; + + /* + * We don't want to power off the PHY if something under the + * root hub has wakeup enabled. + */ + if (usb_wakeup_enabled_descendants(root_hub)) + return false; + + /* No reason to keep the PHY powered, so allow poweroff */ + return true; +} diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c index d10a7f8daec3..3e6c3c8a32ff 100644 --- a/drivers/usb/dwc2/platform.c +++ b/drivers/usb/dwc2/platform.c @@ -447,6 +447,10 @@ static int dwc2_driver_probe(struct platform_device *dev) if (retval) goto error; + hsotg->need_phy_for_wake = + of_property_read_bool(dev->dev.of_node, + "snps,need-phy-for-wake"); + /* * Reset before dwc2_get_hwparams() then it could get power-on real * reset value form registers. @@ -478,6 +482,14 @@ static int dwc2_driver_probe(struct platform_device *dev) hsotg->gadget_enabled = 1; } + /* + * If we need PHY for wakeup we must be wakeup capable. + * When we have a device that can wake without the PHY we + * can adjust this condition. + */ + if (hsotg->need_phy_for_wake) + device_set_wakeup_capable(&dev->dev, true); + hsotg->reset_phy_on_wake = of_property_read_bool(dev->dev.of_node, "snps,reset-phy-on-wake"); @@ -516,13 +528,17 @@ error: static int __maybe_unused dwc2_suspend(struct device *dev) { struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev); + bool is_device_mode = dwc2_is_device_mode(dwc2); int ret = 0; - if (dwc2_is_device_mode(dwc2)) + if (is_device_mode) dwc2_hsotg_suspend(dwc2); - if (dwc2->ll_hw_enabled) + if (dwc2->ll_hw_enabled && + (is_device_mode || dwc2_host_can_poweroff_phy(dwc2))) { ret = __dwc2_lowlevel_hw_disable(dwc2); + dwc2->phy_off_for_suspend = true; + } return ret; } @@ -532,11 +548,12 @@ static int __maybe_unused dwc2_resume(struct device *dev) struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev); int ret = 0; - if (dwc2->ll_hw_enabled) { + if (dwc2->phy_off_for_suspend && dwc2->ll_hw_enabled) { ret = __dwc2_lowlevel_hw_enable(dwc2); if (ret) return ret; } + dwc2->phy_off_for_suspend = false; if (dwc2_is_device_mode(dwc2)) ret = dwc2_hsotg_resume(dwc2); From 4833a94eb383f5b22775077ff92ddaae90440921 Mon Sep 17 00:00:00 2001 From: Fei Yang Date: Wed, 12 Jun 2019 15:13:26 -0700 Subject: [PATCH 08/30] usb: gadget: f_fs: data_len used before properly set The following line of code in function ffs_epfile_io is trying to set flag io_data->use_sg in case buffer required is larger than one page. io_data->use_sg = gadget->sg_supported && data_len > PAGE_SIZE; However at this point of time the variable data_len has not been set to the proper buffer size yet. The consequence is that io_data->use_sg is always set regardless what buffer size really is, because the condition (data_len > PAGE_SIZE) is effectively an unsigned comparison between -EINVAL and PAGE_SIZE which would always result in TRUE. Fixes: 772a7a724f69 ("usb: gadget: f_fs: Allow scatter-gather buffers") Signed-off-by: Fei Yang Cc: stable Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_fs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 47be961f1bf3..c7ed90084d1a 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -997,7 +997,6 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) * earlier */ gadget = epfile->ffs->gadget; - io_data->use_sg = gadget->sg_supported && data_len > PAGE_SIZE; spin_lock_irq(&epfile->ffs->eps_lock); /* In the meantime, endpoint got disabled or changed. */ @@ -1012,6 +1011,8 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) */ if (io_data->read) data_len = usb_ep_align_maybe(gadget, ep->ep, data_len); + + io_data->use_sg = gadget->sg_supported && data_len > PAGE_SIZE; spin_unlock_irq(&epfile->ffs->eps_lock); data = ffs_alloc_buffer(io_data, data_len); From f4408a98c4e6f90af032bc473f987acd89fd81d9 Mon Sep 17 00:00:00 2001 From: Jonas Stenvall Date: Thu, 13 Jun 2019 11:34:33 +0200 Subject: [PATCH 09/30] usb: gadget: u_audio: Fixed variable declaration coding style issue Fixed a coding style issue, replacing unsigned with unsigned int. Reviewed-by: Eugeniu Rosca Signed-off-by: Jonas Stenvall Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/u_audio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/function/u_audio.c b/drivers/usb/gadget/function/u_audio.c index fb5ed97572e5..56906d15fb55 100644 --- a/drivers/usb/gadget/function/u_audio.c +++ b/drivers/usb/gadget/function/u_audio.c @@ -40,7 +40,7 @@ struct uac_rtd_params { void *rbuf; - unsigned max_psize; /* MaxPacketSize of endpoint */ + unsigned int max_psize; /* MaxPacketSize of endpoint */ struct uac_req *ureq; spinlock_t lock; @@ -78,7 +78,7 @@ static const struct snd_pcm_hardware uac_pcm_hardware = { static void u_audio_iso_complete(struct usb_ep *ep, struct usb_request *req) { - unsigned pending; + unsigned int pending; unsigned long flags, flags2; unsigned int hw_ptr; int status = req->status; From 0604160d8c0b6082727182398d432a68bdd58872 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Fri, 31 May 2019 10:59:57 +0100 Subject: [PATCH 10/30] usb: gadget: udc: renesas_usb3: Enhance role switch support The RZ/G2E cat874 board has a type-c connector connected to hd3ss3220 usb type-c drp port controller. Enhance role switch support to assign the role requested by connector device using the usb role switch class framework. Reviewed-by: Yoshihiro Shimoda Tested-by: Yoshihiro Shimoda Signed-off-by: Biju Das Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/renesas_usb3.c | 91 ++++++++++++++++++++++++--- 1 file changed, 84 insertions(+), 7 deletions(-) diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c index 7dc248546fd4..5a960fce31c5 100644 --- a/drivers/usb/gadget/udc/renesas_usb3.c +++ b/drivers/usb/gadget/udc/renesas_usb3.c @@ -351,6 +351,8 @@ struct renesas_usb3 { int disabled_count; struct usb_request *ep0_req; + + enum usb_role connection_state; u16 test_mode; u8 ep0_buf[USB3_EP0_BUF_SIZE]; bool softconnect; @@ -359,6 +361,7 @@ struct renesas_usb3 { bool extcon_usb; /* check vbus and set EXTCON_USB */ bool forced_b_device; bool start_to_connect; + bool role_sw_by_connector; }; #define gadget_to_renesas_usb3(_gadget) \ @@ -699,8 +702,11 @@ static void usb3_mode_config(struct renesas_usb3 *usb3, bool host, bool a_dev) unsigned long flags; spin_lock_irqsave(&usb3->lock, flags); - usb3_set_mode_by_role_sw(usb3, host); - usb3_vbus_out(usb3, a_dev); + if (!usb3->role_sw_by_connector || + usb3->connection_state != USB_ROLE_NONE) { + usb3_set_mode_by_role_sw(usb3, host); + usb3_vbus_out(usb3, a_dev); + } /* for A-Peripheral or forced B-device mode */ if ((!host && a_dev) || usb3->start_to_connect) usb3_connect(usb3); @@ -716,7 +722,8 @@ static void usb3_check_id(struct renesas_usb3 *usb3) { usb3->extcon_host = usb3_is_a_device(usb3); - if (usb3->extcon_host && !usb3->forced_b_device) + if ((!usb3->role_sw_by_connector && usb3->extcon_host && + !usb3->forced_b_device) || usb3->connection_state == USB_ROLE_HOST) usb3_mode_config(usb3, true, true); else usb3_mode_config(usb3, false, false); @@ -2343,14 +2350,65 @@ static enum usb_role renesas_usb3_role_switch_get(struct device *dev) return cur_role; } -static int renesas_usb3_role_switch_set(struct device *dev, - enum usb_role role) +static void handle_ext_role_switch_states(struct device *dev, + enum usb_role role) +{ + struct renesas_usb3 *usb3 = dev_get_drvdata(dev); + struct device *host = usb3->host_dev; + enum usb_role cur_role = renesas_usb3_role_switch_get(dev); + + switch (role) { + case USB_ROLE_NONE: + usb3->connection_state = USB_ROLE_NONE; + if (usb3->driver) + usb3_disconnect(usb3); + usb3_vbus_out(usb3, false); + break; + case USB_ROLE_DEVICE: + if (usb3->connection_state == USB_ROLE_NONE) { + usb3->connection_state = USB_ROLE_DEVICE; + usb3_set_mode(usb3, false); + if (usb3->driver) + usb3_connect(usb3); + } else if (cur_role == USB_ROLE_HOST) { + device_release_driver(host); + usb3_set_mode(usb3, false); + if (usb3->driver) + usb3_connect(usb3); + } + usb3_vbus_out(usb3, false); + break; + case USB_ROLE_HOST: + if (usb3->connection_state == USB_ROLE_NONE) { + if (usb3->driver) + usb3_disconnect(usb3); + + usb3->connection_state = USB_ROLE_HOST; + usb3_set_mode(usb3, true); + usb3_vbus_out(usb3, true); + if (device_attach(host) < 0) + dev_err(dev, "device_attach(host) failed\n"); + } else if (cur_role == USB_ROLE_DEVICE) { + usb3_disconnect(usb3); + /* Must set the mode before device_attach of the host */ + usb3_set_mode(usb3, true); + /* This device_attach() might sleep */ + if (device_attach(host) < 0) + dev_err(dev, "device_attach(host) failed\n"); + } + break; + default: + break; + } +} + +static void handle_role_switch_states(struct device *dev, + enum usb_role role) { struct renesas_usb3 *usb3 = dev_get_drvdata(dev); struct device *host = usb3->host_dev; enum usb_role cur_role = renesas_usb3_role_switch_get(dev); - pm_runtime_get_sync(dev); if (cur_role == USB_ROLE_HOST && role == USB_ROLE_DEVICE) { device_release_driver(host); usb3_set_mode(usb3, false); @@ -2361,6 +2419,20 @@ static int renesas_usb3_role_switch_set(struct device *dev, if (device_attach(host) < 0) dev_err(dev, "device_attach(host) failed\n"); } +} + +static int renesas_usb3_role_switch_set(struct device *dev, + enum usb_role role) +{ + struct renesas_usb3 *usb3 = dev_get_drvdata(dev); + + pm_runtime_get_sync(dev); + + if (usb3->role_sw_by_connector) + handle_ext_role_switch_states(dev, role); + else + handle_role_switch_states(dev, role); + pm_runtime_put(dev); return 0; @@ -2650,7 +2722,7 @@ static const unsigned int renesas_usb3_cable[] = { EXTCON_NONE, }; -static const struct usb_role_switch_desc renesas_usb3_role_switch_desc = { +static struct usb_role_switch_desc renesas_usb3_role_switch_desc = { .set = renesas_usb3_role_switch_set, .get = renesas_usb3_role_switch_get, .allow_userspace_control = true, @@ -2741,6 +2813,11 @@ static int renesas_usb3_probe(struct platform_device *pdev) if (ret < 0) goto err_dev_create; + if (device_property_read_bool(&pdev->dev, "usb-role-switch")) { + usb3->role_sw_by_connector = true; + renesas_usb3_role_switch_desc.fwnode = dev_fwnode(&pdev->dev); + } + INIT_WORK(&usb3->role_work, renesas_usb3_role_work); usb3->role_sw = usb_role_switch_register(&pdev->dev, &renesas_usb3_role_switch_desc); From 67929a7ded5263106931521c3455e3250f0a26ff Mon Sep 17 00:00:00 2001 From: Hariprasad Kelam Date: Wed, 5 Jun 2019 19:42:53 +0530 Subject: [PATCH 11/30] usb: gadget: at91_udc: Remove unneeded variable at91_wakeup is always returning -EINVAL. But usb_gadget_wakeup expects 0 on success and negative number on failure. As per current implementation this function wont fail. This patch removes unneeded variable and returns 0. Issue identified by coccicheck drivers/usb/gadget/udc/at91_udc.c:802:6-12: Unneeded variable: "status". Return "- EINVAL" on line 821 Signed-off-by: Hariprasad Kelam Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/at91_udc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/usb/gadget/udc/at91_udc.c b/drivers/usb/gadget/udc/at91_udc.c index 03959dc86cfd..194ffb1ed462 100644 --- a/drivers/usb/gadget/udc/at91_udc.c +++ b/drivers/usb/gadget/udc/at91_udc.c @@ -799,7 +799,6 @@ static int at91_wakeup(struct usb_gadget *gadget) { struct at91_udc *udc = to_udc(gadget); u32 glbstate; - int status = -EINVAL; unsigned long flags; DBG("%s\n", __func__ ); @@ -818,7 +817,7 @@ static int at91_wakeup(struct usb_gadget *gadget) done: spin_unlock_irqrestore(&udc->lock, flags); - return status; + return 0; } /* reinit == restore initial software state */ From 811e5c3d3c4adf0b037fab3417395d3060a4492a Mon Sep 17 00:00:00 2001 From: Hariprasad Kelam Date: Wed, 5 Jun 2019 17:41:17 +0530 Subject: [PATCH 12/30] fotg210-udc: Remove unneeded variable This patch fixes below warning reported by coccicheck drivers/usb/gadget/udc/fotg210-udc.c:484:5-8: Unneeded variable: "ret". Return "0" on line 507 Signed-off-by: Hariprasad Kelam Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/fotg210-udc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/usb/gadget/udc/fotg210-udc.c b/drivers/usb/gadget/udc/fotg210-udc.c index cec49294bac6..21f3e6c4e4d6 100644 --- a/drivers/usb/gadget/udc/fotg210-udc.c +++ b/drivers/usb/gadget/udc/fotg210-udc.c @@ -481,7 +481,6 @@ static int fotg210_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedge) struct fotg210_ep *ep; struct fotg210_udc *fotg210; unsigned long flags; - int ret = 0; ep = container_of(_ep, struct fotg210_ep, ep); @@ -504,7 +503,7 @@ static int fotg210_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedge) } spin_unlock_irqrestore(&ep->fotg210->lock, flags); - return ret; + return 0; } static int fotg210_ep_set_halt(struct usb_ep *_ep, int value) From 48f5e7493a6a0ac2cf6cf41835495a1f67f4a57c Mon Sep 17 00:00:00 2001 From: Hariprasad Kelam Date: Wed, 5 Jun 2019 17:34:25 +0530 Subject: [PATCH 13/30] USB: omap_udc: Remove unneeded variable With the current implementation omap_udc_stop is always returning -ENODEV. Added changes to return 0 and remove variable status. Issue identified with coccicheck drivers/usb/gadget/udc/omap_udc.c:2106:6-12: Unneeded variable: "status". Return "- ENODEV" on line 2128 Signed-off-by: Hariprasad Kelam Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/omap_udc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/usb/gadget/udc/omap_udc.c b/drivers/usb/gadget/udc/omap_udc.c index fcf13ef33b31..f36f0730afab 100644 --- a/drivers/usb/gadget/udc/omap_udc.c +++ b/drivers/usb/gadget/udc/omap_udc.c @@ -2103,7 +2103,6 @@ done: static int omap_udc_stop(struct usb_gadget *g) { unsigned long flags; - int status = -ENODEV; if (udc->dc_clk != NULL) omap_udc_enable_clock(1); @@ -2125,7 +2124,7 @@ static int omap_udc_stop(struct usb_gadget *g) if (udc->dc_clk != NULL) omap_udc_enable_clock(0); - return status; + return 0; } /*-------------------------------------------------------------------------*/ From 508595515f4bcfe36246e4a565cf280937aeaade Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Mon, 3 Jun 2019 19:05:28 +0200 Subject: [PATCH 14/30] usb: gadget: Zero ffs_io_data In some cases the "Allocate & copy" block in ffs_epfile_io() is not executed. Consequently, in such a case ffs_alloc_buffer() is never called and struct ffs_io_data is not initialized properly. This in turn leads to problems when ffs_free_buffer() is called at the end of ffs_epfile_io(). This patch uses kzalloc() instead of kmalloc() in the aio case and memset() in non-aio case to properly initialize struct ffs_io_data. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_fs.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index c7ed90084d1a..213ff03c8a9f 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -1183,11 +1183,12 @@ static ssize_t ffs_epfile_write_iter(struct kiocb *kiocb, struct iov_iter *from) ENTER(); if (!is_sync_kiocb(kiocb)) { - p = kmalloc(sizeof(io_data), GFP_KERNEL); + p = kzalloc(sizeof(io_data), GFP_KERNEL); if (unlikely(!p)) return -ENOMEM; p->aio = true; } else { + memset(p, 0, sizeof(*p)); p->aio = false; } @@ -1219,11 +1220,12 @@ static ssize_t ffs_epfile_read_iter(struct kiocb *kiocb, struct iov_iter *to) ENTER(); if (!is_sync_kiocb(kiocb)) { - p = kmalloc(sizeof(io_data), GFP_KERNEL); + p = kzalloc(sizeof(io_data), GFP_KERNEL); if (unlikely(!p)) return -ENOMEM; p->aio = true; } else { + memset(p, 0, sizeof(*p)); p->aio = false; } From d78cc1a4b72a455ae53c434ddb8835035a332c5b Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 30 May 2019 19:14:58 +0100 Subject: [PATCH 15/30] usb: gadget: net2272: remove redundant assignments to pointer 's' The pointer 's' is being assigned however the pointer is never used with either of these values before it it reassigned much later on. I suspect it was going to be used in the output of the main control registers scnprintf but was omitted. The assignments of 's' to the driver name or the literal string are redundant and can be removed. Addresses-Coverity: ("Unused value") Signed-off-by: Colin Ian King Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/net2272.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/usb/gadget/udc/net2272.c b/drivers/usb/gadget/udc/net2272.c index 564aeee1a1fe..247de0faaeb7 100644 --- a/drivers/usb/gadget/udc/net2272.c +++ b/drivers/usb/gadget/udc/net2272.c @@ -1178,11 +1178,6 @@ registers_show(struct device *_dev, struct device_attribute *attr, char *buf) size = PAGE_SIZE; spin_lock_irqsave(&dev->lock, flags); - if (dev->driver) - s = dev->driver->driver.name; - else - s = "(none)"; - /* Main Control Registers */ t = scnprintf(next, size, "%s version %s," "chiprev %02x, locctl %02x\n" From ad408a1596b45868e38d0504f2ec1d5fb06f17d4 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Wed, 29 May 2019 13:54:43 -0700 Subject: [PATCH 16/30] Revert "usb: dwc2: host: Setting qtd to NULL after freeing it" This reverts commit b0d659022e5c96ee5c4bd62d22d3da2d66de306b. The reverted commit does nothing but adding two unnecessary lines of code. It sets a local variable to NULL in two functions, but that variable is not used anywhere in the rest of those functions. This is just confusing, so let's remove it. Cc: Vardan Mikayelyan Cc: John Youn Cc: Douglas Anderson Cc: Felipe Balbi Acked-by: Minas Harutyunyan Reviewed-by: Douglas Anderson Signed-off-by: Guenter Roeck Signed-off-by: Felipe Balbi --- drivers/usb/dwc2/hcd.c | 1 - drivers/usb/dwc2/hcd.h | 1 - 2 files changed, 2 deletions(-) diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index 4c78a390c958..ee144ff8af5b 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -4685,7 +4685,6 @@ fail2: spin_unlock_irqrestore(&hsotg->lock, flags); urb->hcpriv = NULL; kfree(qtd); - qtd = NULL; fail1: if (qh_allocated) { struct dwc2_qtd *qtd2, *qtd2_tmp; diff --git a/drivers/usb/dwc2/hcd.h b/drivers/usb/dwc2/hcd.h index ce6445a06588..8ca6d12a6f57 100644 --- a/drivers/usb/dwc2/hcd.h +++ b/drivers/usb/dwc2/hcd.h @@ -582,7 +582,6 @@ static inline void dwc2_hcd_qtd_unlink_and_free(struct dwc2_hsotg *hsotg, { list_del(&qtd->qtd_list_entry); kfree(qtd); - qtd = NULL; } /* Descriptor DMA support functions */ From 8bc529b25354d4ed1dcd3d3663ada5775e7acaec Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Mon, 17 Jun 2019 13:51:02 +0100 Subject: [PATCH 17/30] soc: qcom: geni: Add support for ACPI When booting with ACPI as the active set of configuration tables, all; clocks, regulators, pin functions ect are expected to be at their ideal values/levels/rates, thus the associated frameworks are unavailable. Ensure calls to these APIs are shielded when ACPI is enabled. Signed-off-by: Lee Jones Acked-by: Ard Biesheuvel Signed-off-by: Felipe Balbi --- drivers/soc/qcom/qcom-geni-se.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/drivers/soc/qcom/qcom-geni-se.c b/drivers/soc/qcom/qcom-geni-se.c index 6b8ef01472e9..d5cf953b4337 100644 --- a/drivers/soc/qcom/qcom-geni-se.c +++ b/drivers/soc/qcom/qcom-geni-se.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +#include #include #include #include @@ -450,6 +451,9 @@ int geni_se_resources_off(struct geni_se *se) { int ret; + if (has_acpi_companion(se->dev)) + return 0; + ret = pinctrl_pm_select_sleep_state(se->dev); if (ret) return ret; @@ -487,6 +491,9 @@ int geni_se_resources_on(struct geni_se *se) { int ret; + if (has_acpi_companion(se->dev)) + return 0; + ret = geni_se_clks_on(se); if (ret) return ret; @@ -724,12 +731,14 @@ static int geni_se_probe(struct platform_device *pdev) if (IS_ERR(wrapper->base)) return PTR_ERR(wrapper->base); - wrapper->ahb_clks[0].id = "m-ahb"; - wrapper->ahb_clks[1].id = "s-ahb"; - ret = devm_clk_bulk_get(dev, NUM_AHB_CLKS, wrapper->ahb_clks); - if (ret) { - dev_err(dev, "Err getting AHB clks %d\n", ret); - return ret; + if (!has_acpi_companion(&pdev->dev)) { + wrapper->ahb_clks[0].id = "m-ahb"; + wrapper->ahb_clks[1].id = "s-ahb"; + ret = devm_clk_bulk_get(dev, NUM_AHB_CLKS, wrapper->ahb_clks); + if (ret) { + dev_err(dev, "Err getting AHB clks %d\n", ret); + return ret; + } } dev_set_drvdata(dev, wrapper); From 2bc02355f8ba2c1f108ec8b16a673b467a17228c Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Mon, 17 Jun 2019 13:51:03 +0100 Subject: [PATCH 18/30] usb: dwc3: qcom: Add support for booting with ACPI In Linux, the DWC3 core exists as its own independent platform device. Thus when describing relationships in Device Tree, the current default boot configuration table option, the DWC3 core often resides as a child of the platform specific node. Both of which are given their own address space descriptions and the drivers can be mostly agnostic to each other. However, other Operating Systems have taken a more monolithic approach, which is evident in the configuration ACPI tables for the Qualcomm Snapdragon SDM850, where all DWC3 (core and platform) components are described under a single IO memory region. To ensure successful booting using the supplied ACPI tables, we need to devise a way to chop up the address regions provided and subsequently register the DWC3 core with the resultant information, which is precisely what this patch aims to achieve. Signed-off-by: Lee Jones Reviewed-by: Bjorn Andersson Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/Kconfig | 2 +- drivers/usb/dwc3/dwc3-qcom.c | 206 ++++++++++++++++++++++++++++++----- 2 files changed, 179 insertions(+), 29 deletions(-) diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig index 4a62045cc812..89abc6078703 100644 --- a/drivers/usb/dwc3/Kconfig +++ b/drivers/usb/dwc3/Kconfig @@ -128,7 +128,7 @@ config USB_DWC3_QCOM tristate "Qualcomm Platform" depends on ARCH_QCOM || COMPILE_TEST depends on EXTCON || !EXTCON - depends on OF + depends on (OF || ACPI) default USB_DWC3 help Some Qualcomm SoCs use DesignWare Core IP for USB2/3 diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c index 184df4daa590..0cb63f6c92d9 100644 --- a/drivers/usb/dwc3/dwc3-qcom.c +++ b/drivers/usb/dwc3/dwc3-qcom.c @@ -4,6 +4,7 @@ * Inspired by dwc3-of-simple.c */ +#include #include #include #include @@ -38,6 +39,20 @@ #define PWR_EVNT_LPM_IN_L2_MASK BIT(4) #define PWR_EVNT_LPM_OUT_L2_MASK BIT(5) +#define SDM845_QSCRATCH_BASE_OFFSET 0xf8800 +#define SDM845_QSCRATCH_SIZE 0x400 +#define SDM845_DWC3_CORE_SIZE 0xcd00 + +struct dwc3_acpi_pdata { + u32 qscratch_base_offset; + u32 qscratch_base_size; + u32 dwc3_core_base_size; + int hs_phy_irq_index; + int dp_hs_phy_irq_index; + int dm_hs_phy_irq_index; + int ss_phy_irq_index; +}; + struct dwc3_qcom { struct device *dev; void __iomem *qscratch_base; @@ -56,6 +71,8 @@ struct dwc3_qcom { struct notifier_block vbus_nb; struct notifier_block host_nb; + const struct dwc3_acpi_pdata *acpi_pdata; + enum usb_dr_mode mode; bool is_suspended; bool pm_suspended; @@ -300,12 +317,27 @@ static void dwc3_qcom_select_utmi_clk(struct dwc3_qcom *qcom) PIPE_UTMI_CLK_DIS); } +static int dwc3_qcom_get_irq(struct platform_device *pdev, + const char *name, int num) +{ + struct device_node *np = pdev->dev.of_node; + int ret; + + if (np) + ret = platform_get_irq_byname(pdev, name); + else + ret = platform_get_irq(pdev, num); + + return ret; +} + static int dwc3_qcom_setup_irq(struct platform_device *pdev) { struct dwc3_qcom *qcom = platform_get_drvdata(pdev); + const struct dwc3_acpi_pdata *pdata = qcom->acpi_pdata; int irq, ret; - - irq = platform_get_irq_byname(pdev, "hs_phy_irq"); + irq = dwc3_qcom_get_irq(pdev, "hs_phy_irq", + pdata ? pdata->hs_phy_irq_index : -1); if (irq > 0) { /* Keep wakeup interrupts disabled until suspend */ irq_set_status_flags(irq, IRQ_NOAUTOEN); @@ -320,7 +352,8 @@ static int dwc3_qcom_setup_irq(struct platform_device *pdev) qcom->hs_phy_irq = irq; } - irq = platform_get_irq_byname(pdev, "dp_hs_phy_irq"); + irq = dwc3_qcom_get_irq(pdev, "dp_hs_phy_irq", + pdata ? pdata->dp_hs_phy_irq_index : -1); if (irq > 0) { irq_set_status_flags(irq, IRQ_NOAUTOEN); ret = devm_request_threaded_irq(qcom->dev, irq, NULL, @@ -334,7 +367,8 @@ static int dwc3_qcom_setup_irq(struct platform_device *pdev) qcom->dp_hs_phy_irq = irq; } - irq = platform_get_irq_byname(pdev, "dm_hs_phy_irq"); + irq = dwc3_qcom_get_irq(pdev, "dm_hs_phy_irq", + pdata ? pdata->dm_hs_phy_irq_index : -1); if (irq > 0) { irq_set_status_flags(irq, IRQ_NOAUTOEN); ret = devm_request_threaded_irq(qcom->dev, irq, NULL, @@ -348,7 +382,8 @@ static int dwc3_qcom_setup_irq(struct platform_device *pdev) qcom->dm_hs_phy_irq = irq; } - irq = platform_get_irq_byname(pdev, "ss_phy_irq"); + irq = dwc3_qcom_get_irq(pdev, "ss_phy_irq", + pdata ? pdata->ss_phy_irq_index : -1); if (irq > 0) { irq_set_status_flags(irq, IRQ_NOAUTOEN); ret = devm_request_threaded_irq(qcom->dev, irq, NULL, @@ -371,11 +406,11 @@ static int dwc3_qcom_clk_init(struct dwc3_qcom *qcom, int count) struct device_node *np = dev->of_node; int i; - qcom->num_clocks = count; - - if (!count) + if (!np || !count) return 0; + qcom->num_clocks = count; + qcom->clks = devm_kcalloc(dev, qcom->num_clocks, sizeof(struct clk *), GFP_KERNEL); if (!qcom->clks) @@ -409,12 +444,103 @@ static int dwc3_qcom_clk_init(struct dwc3_qcom *qcom, int count) return 0; } -static int dwc3_qcom_probe(struct platform_device *pdev) +static int dwc3_qcom_acpi_register_core(struct platform_device *pdev) { + struct dwc3_qcom *qcom = platform_get_drvdata(pdev); + struct device *dev = &pdev->dev; + struct resource *res, *child_res = NULL; + int irq; + int ret; + + qcom->dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO); + if (!qcom->dwc3) + return -ENOMEM; + + qcom->dwc3->dev.parent = dev; + qcom->dwc3->dev.type = dev->type; + qcom->dwc3->dev.dma_mask = dev->dma_mask; + qcom->dwc3->dev.dma_parms = dev->dma_parms; + qcom->dwc3->dev.coherent_dma_mask = dev->coherent_dma_mask; + + child_res = kcalloc(2, sizeof(*child_res), GFP_KERNEL); + if (!child_res) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "failed to get memory resource\n"); + ret = -ENODEV; + goto out; + } + + child_res[0].flags = res->flags; + child_res[0].start = res->start; + child_res[0].end = child_res[0].start + + qcom->acpi_pdata->dwc3_core_base_size; + + irq = platform_get_irq(pdev, 0); + child_res[1].flags = IORESOURCE_IRQ; + child_res[1].start = child_res[1].end = irq; + + ret = platform_device_add_resources(qcom->dwc3, child_res, 2); + if (ret) { + dev_err(&pdev->dev, "failed to add resources\n"); + goto out; + } + + ret = platform_device_add(qcom->dwc3); + if (ret) + dev_err(&pdev->dev, "failed to add device\n"); + +out: + kfree(child_res); + return ret; +} + +static int dwc3_qcom_of_register_core(struct platform_device *pdev) +{ + struct dwc3_qcom *qcom = platform_get_drvdata(pdev); struct device_node *np = pdev->dev.of_node, *dwc3_np; struct device *dev = &pdev->dev; + int ret; + + dwc3_np = of_get_child_by_name(np, "dwc3"); + if (!dwc3_np) { + dev_err(dev, "failed to find dwc3 core child\n"); + return -ENODEV; + } + + ret = of_platform_populate(np, NULL, NULL, dev); + if (ret) { + dev_err(dev, "failed to register dwc3 core - %d\n", ret); + return ret; + } + + qcom->dwc3 = of_find_device_by_node(dwc3_np); + if (!qcom->dwc3) { + dev_err(dev, "failed to get dwc3 platform device\n"); + return -ENODEV; + } + + return 0; +} + +static const struct dwc3_acpi_pdata sdm845_acpi_pdata = { + .qscratch_base_offset = SDM845_QSCRATCH_BASE_OFFSET, + .qscratch_base_size = SDM845_QSCRATCH_SIZE, + .dwc3_core_base_size = SDM845_DWC3_CORE_SIZE, + .hs_phy_irq_index = 1, + .dp_hs_phy_irq_index = 4, + .dm_hs_phy_irq_index = 3, + .ss_phy_irq_index = 2 +}; + +static int dwc3_qcom_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct device *dev = &pdev->dev; struct dwc3_qcom *qcom; - struct resource *res; + struct resource *res, *parent_res = NULL; int ret, i; bool ignore_pipe_clk; @@ -425,6 +551,14 @@ static int dwc3_qcom_probe(struct platform_device *pdev) platform_set_drvdata(pdev, qcom); qcom->dev = &pdev->dev; + if (has_acpi_companion(dev)) { + qcom->acpi_pdata = acpi_device_get_match_data(dev); + if (!qcom->acpi_pdata) { + dev_err(&pdev->dev, "no supporting ACPI device data\n"); + return -EINVAL; + } + } + qcom->resets = devm_reset_control_array_get_optional_exclusive(dev); if (IS_ERR(qcom->resets)) { ret = PTR_ERR(qcom->resets); @@ -454,7 +588,21 @@ static int dwc3_qcom_probe(struct platform_device *pdev) } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - qcom->qscratch_base = devm_ioremap_resource(dev, res); + + if (np) { + parent_res = res; + } else { + parent_res = kmemdup(res, sizeof(struct resource), GFP_KERNEL); + if (!parent_res) + return -ENOMEM; + + parent_res->start = res->start + + qcom->acpi_pdata->qscratch_base_offset; + parent_res->end = parent_res->start + + qcom->acpi_pdata->qscratch_base_size; + } + + qcom->qscratch_base = devm_ioremap_resource(dev, parent_res); if (IS_ERR(qcom->qscratch_base)) { dev_err(dev, "failed to map qscratch, err=%d\n", ret); ret = PTR_ERR(qcom->qscratch_base); @@ -462,13 +610,8 @@ static int dwc3_qcom_probe(struct platform_device *pdev) } ret = dwc3_qcom_setup_irq(pdev); - if (ret) - goto clk_disable; - - dwc3_np = of_get_child_by_name(np, "dwc3"); - if (!dwc3_np) { - dev_err(dev, "failed to find dwc3 core child\n"); - ret = -ENODEV; + if (ret) { + dev_err(dev, "failed to setup IRQs, err=%d\n", ret); goto clk_disable; } @@ -481,16 +624,13 @@ static int dwc3_qcom_probe(struct platform_device *pdev) if (ignore_pipe_clk) dwc3_qcom_select_utmi_clk(qcom); - ret = of_platform_populate(np, NULL, NULL, dev); - if (ret) { - dev_err(dev, "failed to register dwc3 core - %d\n", ret); - goto clk_disable; - } + if (np) + ret = dwc3_qcom_of_register_core(pdev); + else + ret = dwc3_qcom_acpi_register_core(pdev); - qcom->dwc3 = of_find_device_by_node(dwc3_np); - if (!qcom->dwc3) { - dev_err(&pdev->dev, "failed to get dwc3 platform device\n"); - ret = -ENODEV; + if (ret) { + dev_err(dev, "failed to register DWC3 Core, err=%d\n", ret); goto depopulate; } @@ -514,7 +654,10 @@ static int dwc3_qcom_probe(struct platform_device *pdev) return 0; depopulate: - of_platform_depopulate(&pdev->dev); + if (np) + of_platform_depopulate(&pdev->dev); + else + platform_device_put(pdev); clk_disable: for (i = qcom->num_clocks - 1; i >= 0; i--) { clk_disable_unprepare(qcom->clks[i]); @@ -601,6 +744,12 @@ static const struct of_device_id dwc3_qcom_of_match[] = { }; MODULE_DEVICE_TABLE(of, dwc3_qcom_of_match); +static const struct acpi_device_id dwc3_qcom_acpi_match[] = { + { "QCOM2430", (unsigned long)&sdm845_acpi_pdata }, + { }, +}; +MODULE_DEVICE_TABLE(acpi, dwc3_qcom_acpi_match); + static struct platform_driver dwc3_qcom_driver = { .probe = dwc3_qcom_probe, .remove = dwc3_qcom_remove, @@ -608,6 +757,7 @@ static struct platform_driver dwc3_qcom_driver = { .name = "dwc3-qcom", .pm = &dwc3_qcom_dev_pm_ops, .of_match_table = dwc3_qcom_of_match, + .acpi_match_table = ACPI_PTR(dwc3_qcom_acpi_match), }, }; From a6e456209d088df31eacfa877d40194c755ca153 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Mon, 17 Jun 2019 13:51:04 +0100 Subject: [PATCH 19/30] usb: dwc3: qcom: Start USB in 'host mode' on the SDM845 When booting with Device Tree, the current default boot configuration table option, the request to boot via 'host mode' comes from the 'dr_mode' property. A property of the same name can be used inside ACPI tables too. However it is missing from the SDM845's ACPI tables so we have to supply this information using Platform Device Properties instead. This does not change the behaviour of any currently supported devices. The property is only set on ACPI enabled platforms, thus for H/W booting DT, unless a 'dr_mode' property is present, the default is still OTG (On-The-Go) as per [0]. Any new ACPI devices added will also be able to over-ride this implementation by providing a 'dr_mode' property in their ACPI tables. In cases where 'dr_mode' is omitted from the tables AND 'host mode' should not be the default (very unlikely), then we will have to add some way of choosing between them at run time - most likely by ACPI HID. [0] Documentation/devicetree/bindings/usb/generic.txt Signed-off-by: Lee Jones Reviewed-by: Bjorn Andersson Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/dwc3-qcom.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c index 0cb63f6c92d9..2d050303d564 100644 --- a/drivers/usb/dwc3/dwc3-qcom.c +++ b/drivers/usb/dwc3/dwc3-qcom.c @@ -444,6 +444,11 @@ static int dwc3_qcom_clk_init(struct dwc3_qcom *qcom, int count) return 0; } +static const struct property_entry dwc3_qcom_acpi_properties[] = { + PROPERTY_ENTRY_STRING("dr_mode", "host"), + {} +}; + static int dwc3_qcom_acpi_register_core(struct platform_device *pdev) { struct dwc3_qcom *qcom = platform_get_drvdata(pdev); @@ -488,6 +493,13 @@ static int dwc3_qcom_acpi_register_core(struct platform_device *pdev) goto out; } + ret = platform_device_add_properties(qcom->dwc3, + dwc3_qcom_acpi_properties); + if (ret < 0) { + dev_err(&pdev->dev, "failed to add properties\n"); + goto out; + } + ret = platform_device_add(qcom->dwc3); if (ret) dev_err(&pdev->dev, "failed to add device\n"); From 7f5d6a4696170ca7394d9dcecd5a54ebe2b9a067 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Mon, 17 Jun 2019 13:51:05 +0100 Subject: [PATCH 20/30] usb: dwc3: qcom: Improve error handling dwc3_qcom_clk_init() is called with of_count_phandle_with_args() as an argument. If of_count_phandle_with_args() returns an error, the number of clocks will be a negative value and will lead to undefined behaviour. Ensure we check for an error before attempting to blindly use the value. Signed-off-by: Lee Jones Reviewed-by: Bjorn Andersson Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/dwc3-qcom.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c index 2d050303d564..c59e9d8e8609 100644 --- a/drivers/usb/dwc3/dwc3-qcom.c +++ b/drivers/usb/dwc3/dwc3-qcom.c @@ -409,6 +409,9 @@ static int dwc3_qcom_clk_init(struct dwc3_qcom *qcom, int count) if (!np || !count) return 0; + if (count < 0) + return count; + qcom->num_clocks = count; qcom->clks = devm_kcalloc(dev, qcom->num_clocks, From dc1b5d9aed1794b5a1c6b0da46e372cc09974cbc Mon Sep 17 00:00:00 2001 From: Enric Balletbo i Serra Date: Thu, 13 Jun 2019 17:01:07 +0200 Subject: [PATCH 21/30] usb: dwc3: Fix core validation in probe, move after clocks are enabled The required clocks needs to be enabled before the first register access. After commit fe8abf332b8f ("usb: dwc3: support clocks and resets for DWC3 core"), this happens when the dwc3_core_is_valid function is called, but the mentioned commit adds that call in the wrong place, before the clocks are enabled. So, move that call after the clk_bulk_enable() to ensure the clocks are enabled and the reset deasserted. I detected this while, as experiment, I tried to move the clocks and resets from the glue layer to the DWC3 core on a Samsung Chromebook Plus. That was not detected before because, in most cases, the glue layer initializes SoC-specific things and then populates the child "snps,dwc3" with those clocks already enabled. Fixes: b873e2d0ea1ef ("usb: dwc3: Do core validation early on probe") Signed-off-by: Enric Balletbo i Serra Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 4aff1d8dbc4f..6e9e172010fc 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -1423,11 +1423,6 @@ static int dwc3_probe(struct platform_device *pdev) dwc->regs = regs; dwc->regs_size = resource_size(&dwc_res); - if (!dwc3_core_is_valid(dwc)) { - dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n"); - return -ENODEV; - } - dwc3_get_properties(dwc); dwc->reset = devm_reset_control_get_optional_shared(dev, NULL); @@ -1460,6 +1455,12 @@ static int dwc3_probe(struct platform_device *pdev) if (ret) goto unprepare_clks; + if (!dwc3_core_is_valid(dwc)) { + dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n"); + ret = -ENODEV; + goto disable_clks; + } + platform_set_drvdata(pdev, dwc); dwc3_cache_hwparams(dwc); @@ -1525,6 +1526,7 @@ err1: pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); +disable_clks: clk_bulk_disable(dwc->num_clks, dwc->clks); unprepare_clks: clk_bulk_unprepare(dwc->num_clks, dwc->clks); From 4d20a6107050b45da976e28dc23274eb9ff1c242 Mon Sep 17 00:00:00 2001 From: Kefeng Wang Date: Sat, 25 May 2019 19:58:08 +0800 Subject: [PATCH 22/30] usb: dwc3: qcom: Use of_clk_get_parent_count() Use of_clk_get_parent_count() instead of open coding. Signed-off-by: Kefeng Wang Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/dwc3-qcom.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c index c59e9d8e8609..261af9e38ddd 100644 --- a/drivers/usb/dwc3/dwc3-qcom.c +++ b/drivers/usb/dwc3/dwc3-qcom.c @@ -595,8 +595,7 @@ static int dwc3_qcom_probe(struct platform_device *pdev) goto reset_assert; } - ret = dwc3_qcom_clk_init(qcom, of_count_phandle_with_args(np, - "clocks", "#clock-cells")); + ret = dwc3_qcom_clk_init(qcom, of_clk_get_parent_count(np)); if (ret) { dev_err(dev, "failed to get clocks\n"); goto reset_assert; From 34cc761bdcc84fa7b9c5fd4e1f8548df6979f194 Mon Sep 17 00:00:00 2001 From: Anurag Kumar Vulisha Date: Fri, 10 May 2019 12:37:26 +0530 Subject: [PATCH 23/30] doc: dt: bindings: usb: dwc3: Update entries for disabling U1 and U2 This patch updates the documentation with the information related to the quirks that needs to be added for disabling the link entering into the U1 and U2 states Reviewed-by: Rob Herring Signed-off-by: Anurag Kumar Vulisha Signed-off-by: Felipe Balbi --- Documentation/devicetree/bindings/usb/dwc3.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt index 8e5265e9f658..66780a47ad85 100644 --- a/Documentation/devicetree/bindings/usb/dwc3.txt +++ b/Documentation/devicetree/bindings/usb/dwc3.txt @@ -64,6 +64,8 @@ Optional properties: - snps,dis_u2_susphy_quirk: when set core will disable USB2 suspend phy. - snps,dis_enblslpm_quirk: when set clears the enblslpm in GUSB2PHYCFG, disabling the suspend signal to the PHY. + - snps,dis-u1-entry-quirk: set if link entering into U1 needs to be disabled. + - snps,dis-u2-entry-quirk: set if link entering into U2 needs to be disabled. - snps,dis_rxdet_inp3_quirk: when set core will disable receiver detection in PHY P3 power state. - snps,dis-u2-freeclk-exists-quirk: when set, clear the u2_freeclk_exists From 4ed9890c4c44d2ead7b57ad65425e3fbe9b9d42a Mon Sep 17 00:00:00 2001 From: Anurag Kumar Vulisha Date: Fri, 10 May 2019 12:37:27 +0530 Subject: [PATCH 24/30] usb: gadget: send usb_gadget as an argument in get_config_params Passing struct usb_gadget * as an extra argument in get_config_params makes gadget drivers to easily update the U1DevExitLat & U2DevExitLat values based on the values passed from the device tree. This patch does the same Signed-off-by: Anurag Kumar Vulisha Signed-off-by: Felipe Balbi --- drivers/usb/gadget/composite.c | 2 +- include/linux/usb/gadget.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index b8a15840b4ff..9118b42c70b6 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -653,7 +653,7 @@ static int bos_desc(struct usb_composite_dev *cdev) /* Get Controller configuration */ if (cdev->gadget->ops->get_config_params) { - cdev->gadget->ops->get_config_params( + cdev->gadget->ops->get_config_params(cdev->gadget, &dcd_config_params); } else { dcd_config_params.bU1devExitLat = diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 7595056b96c1..fb19141151d8 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -310,7 +310,8 @@ struct usb_gadget_ops { int (*pullup) (struct usb_gadget *, int is_on); int (*ioctl)(struct usb_gadget *, unsigned code, unsigned long param); - void (*get_config_params)(struct usb_dcd_config_params *); + void (*get_config_params)(struct usb_gadget *, + struct usb_dcd_config_params *); int (*udc_start)(struct usb_gadget *, struct usb_gadget_driver *); int (*udc_stop)(struct usb_gadget *); From 729dcffd1ed319c9738456543f382d0801e768b8 Mon Sep 17 00:00:00 2001 From: Anurag Kumar Vulisha Date: Fri, 10 May 2019 12:37:28 +0530 Subject: [PATCH 25/30] usb: dwc3: gadget: Add support for disabling U1 and U2 entries Gadget applications may have a requirement to disable the U1 and U2 entry based on the usecase. Below are few usecases where the disabling U1/U2 entries may be possible. Usecase 1: When combining dwc3 with an redriver for a USB Type-C device solution, it sometimes have problems with leaving U1/U2 for certain hosts, resulting in link training errors and reconnects. For this U1/U2 state entries may be avoided. Usecase 2: When performing performance benchmarking on mass storage gadget the U1 and U2 entries can be disabled. Usecase 3: When periodic transfers like ISOC transfers are used with bInterval of 1 which doesn't require the link to enter into U1 or U2 state entry (since ping is issued from host for every uframe interval). In this case the U1 and U2 entry can be disabled. Disablement of U1/U2 can be done by setting U1DevExitLat and U2DevExitLat values to 0 in the BOS descriptor. Host on seeing 0 value for U1DevExitLat and U2DevExitLat, it doesn't send SET_SEL requests to the gadget. There may be some hosts which may send SET_SEL requests even after seeing 0 in the UxDevExitLat of BOS descriptor. To aviod U1/U2 entries for these type of hosts, dwc3 controller can be programmed to reject those U1/U2 requests by not enabling ACCEPTUxENA bits in DCTL register. This patch updates the same. Signed-off-by: Anurag Kumar Vulisha Signed-off-by: Claus H. Stovgaard Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.c | 4 ++++ drivers/usb/dwc3/core.h | 4 ++++ drivers/usb/dwc3/ep0.c | 9 ++++++++- drivers/usb/dwc3/gadget.c | 20 ++++++++++++++++++++ drivers/usb/dwc3/gadget.h | 6 ++++++ 5 files changed, 42 insertions(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 6e9e172010fc..c9bb93a2c81e 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -1282,6 +1282,10 @@ static void dwc3_get_properties(struct dwc3 *dwc) "snps,dis_u2_susphy_quirk"); dwc->dis_enblslpm_quirk = device_property_read_bool(dev, "snps,dis_enblslpm_quirk"); + dwc->dis_u1_entry_quirk = device_property_read_bool(dev, + "snps,dis-u1-entry-quirk"); + dwc->dis_u2_entry_quirk = device_property_read_bool(dev, + "snps,dis-u2-entry-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, diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index f19cbeb01087..241b491489d9 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -1014,6 +1014,8 @@ struct dwc3_scratchpad_array { * @dis_u2_susphy_quirk: set if we disable usb2 suspend phy * @dis_enblslpm_quirk: set if we clear enblslpm in GUSB2PHYCFG, * disabling the suspend signal to the PHY. + * @dis_u1_entry_quirk: set if link entering into U1 state needs to be disabled. + * @dis_u2_entry_quirk: set if link entering into U2 state needs to be disabled. * @dis_rxdet_inp3_quirk: set if we disable Rx.Detect in P3 * @dis_u2_freeclk_exists_quirk : set if we clear u2_freeclk_exists * in GUSB2PHYCFG, specify that USB2 PHY doesn't @@ -1205,6 +1207,8 @@ struct dwc3 { unsigned dis_u3_susphy_quirk:1; unsigned dis_u2_susphy_quirk:1; unsigned dis_enblslpm_quirk:1; + unsigned dis_u1_entry_quirk:1; + unsigned dis_u2_entry_quirk:1; unsigned dis_rxdet_inp3_quirk:1; unsigned dis_u2_freeclk_exists_quirk:1; unsigned dis_del_phy_power_chg_quirk:1; diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 8efde178eef4..3996b9c4ff8d 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -379,6 +379,8 @@ static int dwc3_ep0_handle_u1(struct dwc3 *dwc, enum usb_device_state state, if ((dwc->speed != DWC3_DSTS_SUPERSPEED) && (dwc->speed != DWC3_DSTS_SUPERSPEED_PLUS)) return -EINVAL; + if (set && dwc->dis_u1_entry_quirk) + return -EINVAL; reg = dwc3_readl(dwc->regs, DWC3_DCTL); if (set) @@ -401,6 +403,8 @@ static int dwc3_ep0_handle_u2(struct dwc3 *dwc, enum usb_device_state state, if ((dwc->speed != DWC3_DSTS_SUPERSPEED) && (dwc->speed != DWC3_DSTS_SUPERSPEED_PLUS)) return -EINVAL; + if (set && dwc->dis_u2_entry_quirk) + return -EINVAL; reg = dwc3_readl(dwc->regs, DWC3_DCTL); if (set) @@ -626,7 +630,10 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) * nothing is pending from application. */ reg = dwc3_readl(dwc->regs, DWC3_DCTL); - reg |= (DWC3_DCTL_ACCEPTU1ENA | DWC3_DCTL_ACCEPTU2ENA); + if (!dwc->dis_u1_entry_quirk) + reg |= DWC3_DCTL_ACCEPTU1ENA; + if (!dwc->dis_u2_entry_quirk) + reg |= DWC3_DCTL_ACCEPTU2ENA; dwc3_writel(dwc->regs, DWC3_DCTL, reg); } break; diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index d67655384eb2..2751d3e98f5f 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2073,6 +2073,25 @@ out: return 0; } +static void dwc3_gadget_config_params(struct usb_gadget *g, + struct usb_dcd_config_params *params) +{ + struct dwc3 *dwc = gadget_to_dwc(g); + + /* U1 Device exit Latency */ + if (dwc->dis_u1_entry_quirk) + params->bU1devExitLat = 0; + else + params->bU1devExitLat = DWC3_DEFAULT_U1_DEV_EXIT_LAT; + + /* U2 Device exit Latency */ + if (dwc->dis_u2_entry_quirk) + params->bU2DevExitLat = 0; + else + params->bU2DevExitLat = + cpu_to_le16(DWC3_DEFAULT_U2_DEV_EXIT_LAT); +} + static void dwc3_gadget_set_speed(struct usb_gadget *g, enum usb_device_speed speed) { @@ -2142,6 +2161,7 @@ static const struct usb_gadget_ops dwc3_gadget_ops = { .udc_start = dwc3_gadget_start, .udc_stop = dwc3_gadget_stop, .udc_set_speed = dwc3_gadget_set_speed, + .get_config_params = dwc3_gadget_config_params, }; /* -------------------------------------------------------------------------- */ diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h index 3ed738e86ea7..5faf4d1249e0 100644 --- a/drivers/usb/dwc3/gadget.h +++ b/drivers/usb/dwc3/gadget.h @@ -48,6 +48,12 @@ struct dwc3; /* DEPXFERCFG parameter 0 */ #define DWC3_DEPXFERCFG_NUM_XFER_RES(n) ((n) & 0xffff) +/* U1 Device exit Latency */ +#define DWC3_DEFAULT_U1_DEV_EXIT_LAT 0x0A /* Less then 10 microsec */ + +/* U2 Device exit Latency */ +#define DWC3_DEFAULT_U2_DEV_EXIT_LAT 0x1FF /* Less then 511 microsec */ + /* -------------------------------------------------------------------------- */ #define to_dwc3_request(r) (container_of(r, struct dwc3_request, request)) From e70b3f5da00119e057b7faa557753fee7f786f17 Mon Sep 17 00:00:00 2001 From: EJ Hsu Date: Fri, 10 May 2019 19:02:10 +0800 Subject: [PATCH 26/30] usb: gadget: storage: Remove warning message This change is to fix below warning message in following scenario: usb_composite_setup_continue: Unexpected call When system tried to enter suspend, the fsg_disable() will be called to disable fsg driver and send a signal to fsg_main_thread. However, at this point, the fsg_main_thread has already been frozen and can not respond to this signal. So, this signal will be pended until fsg_main_thread wakes up. Once system resumes from suspend, fsg_main_thread will detect a signal pended and do some corresponding action (in handle_exception()). Then, host will send some setup requests (get descriptor, set configuration...) to UDC driver trying to enumerate this device. During the handling of "set configuration" request, it will try to sync up with fsg_main_thread by sending a signal (which is the same as the signal sent by fsg_disable) to it. In a similar manner, once the fsg_main_thread receives this signal, it will call handle_exception() to handle the request. However, if the fsg_main_thread wakes up from suspend a little late and "set configuration" request from Host arrives a little earlier, fsg_main_thread might come across the request from "set configuration" when it handles the signal from fsg_disable(). In this case, it will handle this request as well. So, when fsg_main_thread tries to handle the signal sent from "set configuration" later, there will nothing left to do and warning message "Unexpected call" is printed. Acked-by: Alan Stern Signed-off-by: EJ Hsu Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_mass_storage.c | 21 ++++++++++++++------ drivers/usb/gadget/function/storage_common.h | 1 + 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index 043f97ad8f22..982c3e89eb0d 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -2293,8 +2293,7 @@ static int fsg_set_alt(struct usb_function *f, unsigned intf, unsigned alt) static void fsg_disable(struct usb_function *f) { struct fsg_dev *fsg = fsg_from_func(f); - fsg->common->new_fsg = NULL; - raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE); + raise_exception(fsg->common, FSG_STATE_DISCONNECT); } @@ -2307,6 +2306,7 @@ static void handle_exception(struct fsg_common *common) enum fsg_state old_state; struct fsg_lun *curlun; unsigned int exception_req_tag; + struct fsg_dev *fsg; /* * Clear the existing signals. Anything but SIGUSR1 is converted @@ -2413,9 +2413,19 @@ static void handle_exception(struct fsg_common *common) break; case FSG_STATE_CONFIG_CHANGE: - do_set_interface(common, common->new_fsg); - if (common->new_fsg) + fsg = common->new_fsg; + /* + * Add a check here to double confirm if a disconnect event + * occurs and common->new_fsg has been cleared. + */ + if (fsg) { + do_set_interface(common, fsg); usb_composite_setup_continue(common->cdev); + } + break; + + case FSG_STATE_DISCONNECT: + do_set_interface(common, NULL); break; case FSG_STATE_EXIT: @@ -2989,8 +2999,7 @@ static void fsg_unbind(struct usb_configuration *c, struct usb_function *f) DBG(fsg, "unbind\n"); if (fsg->common->fsg == fsg) { - fsg->common->new_fsg = NULL; - raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE); + raise_exception(fsg->common, FSG_STATE_DISCONNECT); /* FIXME: make interruptible or killable somehow? */ wait_event(common->fsg_wait, common->fsg != fsg); } diff --git a/drivers/usb/gadget/function/storage_common.h b/drivers/usb/gadget/function/storage_common.h index e5e3a2553aaa..12687f7e3de9 100644 --- a/drivers/usb/gadget/function/storage_common.h +++ b/drivers/usb/gadget/function/storage_common.h @@ -161,6 +161,7 @@ enum fsg_state { FSG_STATE_ABORT_BULK_OUT, FSG_STATE_PROTOCOL_RESET, FSG_STATE_CONFIG_CHANGE, + FSG_STATE_DISCONNECT, FSG_STATE_EXIT, FSG_STATE_TERMINATED }; From d29fcf7078bc8be2b6366cbd4418265b53c94fac Mon Sep 17 00:00:00 2001 From: Kiruthika Varadarajan Date: Tue, 18 Jun 2019 08:39:06 +0000 Subject: [PATCH 27/30] usb: gadget: ether: Fix race between gether_disconnect and rx_submit On spin lock release in rx_submit, gether_disconnect get a chance to run, it makes port_usb NULL, rx_submit access NULL port USB, hence null pointer crash. Fixed by releasing the lock in rx_submit after port_usb is used. Fixes: 2b3d942c4878 ("usb ethernet gadget: split out network core") Cc: Signed-off-by: Kiruthika Varadarajan Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/u_ether.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c index 737bd77a575d..2929bb47a618 100644 --- a/drivers/usb/gadget/function/u_ether.c +++ b/drivers/usb/gadget/function/u_ether.c @@ -186,11 +186,12 @@ rx_submit(struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags) out = dev->port_usb->out_ep; else out = NULL; - spin_unlock_irqrestore(&dev->lock, flags); if (!out) + { + spin_unlock_irqrestore(&dev->lock, flags); return -ENOTCONN; - + } /* Padding up to RX_EXTRA handles minor disagreements with host. * Normally we use the USB "terminate on short read" convention; @@ -214,6 +215,7 @@ rx_submit(struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags) if (dev->port_usb->is_fixed) size = max_t(size_t, size, dev->port_usb->fixed_out_len); + spin_unlock_irqrestore(&dev->lock, flags); skb = __netdev_alloc_skb(dev->net, size + NET_IP_ALIGN, gfp_flags); if (skb == NULL) { From 37e444c8296c14cb5768a1197b24cfc07ee8e0cd Mon Sep 17 00:00:00 2001 From: Daniel M German Date: Wed, 19 Jun 2019 21:50:38 -0700 Subject: [PATCH 28/30] usb: Replace snprintf with scnprintf in gether_get_ifname snprintf returns the actual length of the buffer created; however, this is not the case if snprintf truncates its parameter. See https://lwn.net/Articles/69419/ for a detailed explanation. The current code correctly handles this case at the expense of extra code in the return statement. scnprintf does returns the actual length of the buffer created making the ?: operator unnecessary in the return statement. This change does not alter the functionality of the code. Signed-off-by: Daniel M German Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/u_ether.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c index 2929bb47a618..fbe96ef1ac7a 100644 --- a/drivers/usb/gadget/function/u_ether.c +++ b/drivers/usb/gadget/function/u_ether.c @@ -1006,9 +1006,9 @@ int gether_get_ifname(struct net_device *net, char *name, int len) int ret; rtnl_lock(); - ret = snprintf(name, len, "%s\n", netdev_name(net)); + ret = scnprintf(name, len, "%s\n", netdev_name(net)); rtnl_unlock(); - return ret < len ? ret : len; + return ret; } EXPORT_SYMBOL_GPL(gether_get_ifname); From dbb0569de852fb4576d6f62078d515f989a181ca Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 11 Jun 2018 11:21:12 +0300 Subject: [PATCH 29/30] usb: dwc3: pci: Add Support for Intel Elkhart Lake Devices This patch simply adds a new PCI Device ID Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/dwc3-pci.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index 8cced3609e24..f9b550081550 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -34,6 +34,7 @@ #define PCI_DEVICE_ID_INTEL_CNPLP 0x9dee #define PCI_DEVICE_ID_INTEL_CNPH 0xa36e #define PCI_DEVICE_ID_INTEL_ICLLP 0x34ee +#define PCI_DEVICE_ID_INTEL_EHLLP 0x4b7e #define PCI_INTEL_BXT_DSM_GUID "732b85d5-b7a7-4a1b-9ba0-4bbd00ffd511" #define PCI_INTEL_BXT_FUNC_PMU_PWR 4 @@ -339,6 +340,9 @@ static const struct pci_device_id dwc3_pci_id_table[] = { { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICLLP), (kernel_ulong_t) &dwc3_pci_intel_properties, }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_EHLLP), + (kernel_ulong_t) &dwc3_pci_intel_properties, }, + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_NL_USB), (kernel_ulong_t) &dwc3_pci_amd_properties, }, { } /* Terminating Entry */ From aa23ce847ddac1fd5ffe987ff12e12ff48318e45 Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Thu, 20 Jun 2019 16:12:31 +0800 Subject: [PATCH 30/30] usb: dwc3: remove unused @lock member of dwc3_ep struct The member @lock of dwc3_ep struct is only initialized, and not used elsewhere, so remove it. Signed-off-by: Chunfeng Yun Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.h | 2 -- drivers/usb/dwc3/gadget.c | 2 -- 2 files changed, 4 deletions(-) diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 241b491489d9..3dd783b889cb 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -649,7 +649,6 @@ struct dwc3_event_buffer { * @cancelled_list: list of cancelled requests for this endpoint * @pending_list: list of pending requests for this endpoint * @started_list: list of started requests on this endpoint - * @lock: spinlock for endpoint request queue traversal * @regs: pointer to first endpoint register * @trb_pool: array of transaction buffers * @trb_pool_dma: dma address of @trb_pool @@ -677,7 +676,6 @@ struct dwc3_ep { struct list_head pending_list; struct list_head started_list; - spinlock_t lock; void __iomem *regs; struct dwc3_trb *trb_pool; diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 2751d3e98f5f..173f5329d3d9 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2271,8 +2271,6 @@ static int dwc3_gadget_init_endpoint(struct dwc3 *dwc, u8 epnum) dep->endpoint.comp_desc = NULL; } - spin_lock_init(&dep->lock); - if (num == 0) ret = dwc3_gadget_init_control_endpoint(dep); else if (direction)