[PATCH] usb: xhci-plat: Add generic PHY support
Generic phy support added in xhci platform driver. In the case of multiple phys to the xhci controller, this approach is helpful to pass multiple phandles to xhci platform driver from xhci device node. Signed-off-by: Srinath Mannam Reviewed-by: Ray Jui Reviewed-by: Scott Branden diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index 676ea45..c734e2e 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -84,6 +85,52 @@ static int xhci_plat_start(struct usb_hcd *hcd) return xhci_run(hcd); } +static int xhci_platform_phy_on(struct usb_hcd *hcd) +{ + struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd); + int ret, phy_num; + + if (hcd->usb_phy) { + ret = usb_phy_init(hcd->usb_phy); + if (ret) + return ret; + } + for (phy_num = 0; phy_num < priv->num_phys; phy_num++) { + ret = phy_init(priv->phys[phy_num]); + if (ret) + goto err_exit_phy; + ret = phy_power_on(priv->phys[phy_num]); + if (ret) { + phy_exit(priv->phys[phy_num]); + goto err_exit_phy; + } + } + + return 0; + +err_exit_phy: + while (--phy_num >= 0) { + phy_power_off(priv->phys[phy_num]); + phy_exit(priv->phys[phy_num]); + } + + return ret; +} + +static void xhci_platform_phy_off(struct usb_hcd *hcd) +{ + struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd); + int phy_num; + + if (hcd->usb_phy) + usb_phy_shutdown(hcd->usb_phy); + + for (phy_num = 0; phy_num < priv->num_phys; phy_num++) { + phy_power_off(priv->phys[phy_num]); + phy_exit(priv->phys[phy_num]); + } +} + #ifdef CONFIG_OF static const struct xhci_plat_priv xhci_plat_marvell_armada = { .init_quirk = xhci_mvebu_mbus_init_quirk, @@ -146,8 +193,9 @@ static int xhci_plat_probe(struct platform_device *pdev) struct resource *res; struct usb_hcd *hcd; struct clk *clk; + struct xhci_plat_priv *priv; int ret; - int irq; + int irq, phy_num; if (usb_disabled()) return -ENODEV; @@ -199,10 +247,10 @@ static int xhci_plat_probe(struct platform_device *pdev) } xhci = hcd_to_xhci(hcd); + priv = hcd_to_xhci_priv(hcd); match = of_match_node(usb_xhci_of_match, node); if (match) { const struct xhci_plat_priv *priv_match = match->data; - struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd); /* Just copy data for now */ if (priv_match) @@ -233,12 +281,32 @@ static int xhci_plat_probe(struct platform_device *pdev) if (ret == -EPROBE_DEFER) goto put_usb3_hcd; hcd->usb_phy = NULL; - } else { - ret = usb_phy_init(hcd->usb_phy); - if (ret) + } + + priv->num_phys = of_count_phandle_with_args(pdev->dev.of_node, + "phys", "#phy-cells"); + + if (priv->num_phys > 0) { + priv->phys = devm_kcalloc(&pdev->dev, priv->num_phys, + sizeof(struct phy *), GFP_KERNEL); + if (!priv->phys) + return -ENOMEM; + } else + priv->num_phys = 0; + + for (phy_num = 0; phy_num < priv->num_phys; phy_num++) { + priv->phys[phy_num] = devm_of_phy_get_by_index( + &pdev->dev, pdev->dev.of_node, phy_num); + if (IS_ERR(priv->phys[phy_num])) { + ret = PTR_ERR(priv->phys[phy_num]); goto put_usb3_hcd; + } } + ret = xhci_platform_phy_on(hcd); + if (ret < 0) + goto put_usb3_hcd; + ret = usb_add_hcd(hcd, irq, IRQF_SHARED); if (ret) goto disable_usb_phy; @@ -254,7 +322,7 @@ dealloc_usb2_hcd: usb_remove_hcd(hcd); disable_usb_phy: - usb_phy_shutdown(hcd->usb_phy); + xhci_platform_phy_off(hcd); put_usb3_hcd: usb_put_hcd(xhci->shared_hcd); @@ -276,7 +344,7 @@ static int xhci_plat_remove(struct platform_device *dev) struct clk *clk = xhci->clk; usb_remove_hcd(xhci->shared_hcd); - usb_phy_shutdown(hcd->usb_phy); + xhci_platform_phy_off(hcd); usb_remove_hcd(hcd); usb_put_hcd(xhci->shared_hcd); diff --git a/drivers/usb/host/xhci-plat.h b/dr
Re: [PATCH] usb: xhci-plat: Add generic PHY support
++ Felipe Balbi Thanks & Regards, Srinath Mannam. On Thu, Jul 14, 2016 at 2:03 PM, Srinath Mannam wrote: > Generic phy support added in xhci platform driver. > In the case of multiple phys to the xhci controller, this approach > is helpful to pass multiple phandles to xhci platform driver from > xhci device node. > > Signed-off-by: Srinath Mannam > Reviewed-by: Ray Jui > Reviewed-by: Scott Branden > > diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c > index 676ea45..c734e2e 100644 > --- a/drivers/usb/host/xhci-plat.c > +++ b/drivers/usb/host/xhci-plat.c > @@ -15,6 +15,7 @@ > #include > #include > #include > +#include > #include > #include > #include > @@ -84,6 +85,52 @@ static int xhci_plat_start(struct usb_hcd *hcd) > return xhci_run(hcd); > } > > +static int xhci_platform_phy_on(struct usb_hcd *hcd) > +{ > + struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd); > + int ret, phy_num; > + > + if (hcd->usb_phy) { > + ret = usb_phy_init(hcd->usb_phy); > + if (ret) > + return ret; > + } > + for (phy_num = 0; phy_num < priv->num_phys; phy_num++) { > + ret = phy_init(priv->phys[phy_num]); > + if (ret) > + goto err_exit_phy; > + ret = phy_power_on(priv->phys[phy_num]); > + if (ret) { > + phy_exit(priv->phys[phy_num]); > + goto err_exit_phy; > + } > + } > + > + return 0; > + > +err_exit_phy: > + while (--phy_num >= 0) { > + phy_power_off(priv->phys[phy_num]); > + phy_exit(priv->phys[phy_num]); > + } > + > + return ret; > +} > + > +static void xhci_platform_phy_off(struct usb_hcd *hcd) > +{ > + struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd); > + int phy_num; > + > + if (hcd->usb_phy) > + usb_phy_shutdown(hcd->usb_phy); > + > + for (phy_num = 0; phy_num < priv->num_phys; phy_num++) { > + phy_power_off(priv->phys[phy_num]); > + phy_exit(priv->phys[phy_num]); > + } > +} > + > #ifdef CONFIG_OF > static const struct xhci_plat_priv xhci_plat_marvell_armada = { > .init_quirk = xhci_mvebu_mbus_init_quirk, > @@ -146,8 +193,9 @@ static int xhci_plat_probe(struct platform_device *pdev) > struct resource *res; > struct usb_hcd *hcd; > struct clk *clk; > + struct xhci_plat_priv *priv; > int ret; > - int irq; > + int irq, phy_num; > > if (usb_disabled()) > return -ENODEV; > @@ -199,10 +247,10 @@ static int xhci_plat_probe(struct platform_device *pdev) > } > > xhci = hcd_to_xhci(hcd); > + priv = hcd_to_xhci_priv(hcd); > match = of_match_node(usb_xhci_of_match, node); > if (match) { > const struct xhci_plat_priv *priv_match = match->data; > - struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd); > > /* Just copy data for now */ > if (priv_match) > @@ -233,12 +281,32 @@ static int xhci_plat_probe(struct platform_device *pdev) > if (ret == -EPROBE_DEFER) > goto put_usb3_hcd; > hcd->usb_phy = NULL; > - } else { > - ret = usb_phy_init(hcd->usb_phy); > - if (ret) > + } > + > + priv->num_phys = of_count_phandle_with_args(pdev->dev.of_node, > + "phys", "#phy-cells"); > + > + if (priv->num_phys > 0) { > + priv->phys = devm_kcalloc(&pdev->dev, priv->num_phys, > + sizeof(struct phy *), GFP_KERNEL); > + if (!priv->phys) > + return -ENOMEM; > + } else > + priv->num_phys = 0; > + > + for (phy_num = 0; phy_num < priv->num_phys; phy_num++) { > + priv->phys[phy_num] = devm_of_phy_get_by_index( > + &pdev->dev, pdev->dev.of_node, phy_num); > + if (IS_ERR(priv->phys[phy_num])) { > + ret = PTR_ERR(priv->phys[phy_num]); > goto put_usb3_hcd; > + } > } > > + ret = xhci_platform_phy_on(hcd); > +
[PATCH] usb: gadget: bdc: 64-bit pointer capability check
Corrected the register to check the 64-bit pointer capability state. 64-bit pointer implementation capability was checking in wrong register, which causes the BDC enumeration failure in 64-bit memory address. Fixes: efed421a94e6 ("usb: gadget: Add UDC driver for Broadcom USB3.0 device controller IP BDC") Signed-off-by: Srinath Mannam --- drivers/usb/gadget/udc/bdc/bdc_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/udc/bdc/bdc_core.c b/drivers/usb/gadget/udc/bdc/bdc_core.c index ccb9c21..e9bd8d4 100644 --- a/drivers/usb/gadget/udc/bdc/bdc_core.c +++ b/drivers/usb/gadget/udc/bdc/bdc_core.c @@ -475,7 +475,7 @@ static int bdc_probe(struct platform_device *pdev) bdc->dev = dev; dev_dbg(bdc->dev, "bdc->regs: %p irq=%d\n", bdc->regs, bdc->irq); - temp = bdc_readl(bdc->regs, BDC_BDCSC); + temp = bdc_readl(bdc->regs, BDC_BDCCAP1); if ((temp & BDC_P64) && !dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64))) { dev_dbg(bdc->dev, "Using 64-bit address\n"); -- 2.7.4 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Need PHY reset after USB device disconnected
Hi Mathias, In our SOC, xHCI controller has three ports. In that one is SS and two HS ports, all ports are connected with separate phy controller. We have a bug in HS phy controllers. Because of this bug, HS phy controller needs to reset after disconnected the device in the corresponding HS port. I could not find any available mechanism or quirks in kernel to handle these cases. So, I did modifications in xhci-plat.c, xhci.c and xhci-hub.c files to fix this issue. But the modifications are not cleaner to upstream. Please help me in the implementation of proper fix. Below are the code changes. --- drivers/usb/host/xhci-hub.c | 9 + drivers/usb/host/xhci-plat.c | 11 +++ drivers/usb/host/xhci.c | 2 ++ drivers/usb/host/xhci.h | 1 + 4 files changed, 23 insertions(+) diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 0ef1690..3fdb07d 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -1193,6 +1193,15 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, case USB_PORT_FEAT_C_PORT_CONFIG_ERROR: xhci_clear_port_change_bit(xhci, wValue, wIndex, port_array[wIndex], temp); + if ((wValue == USB_PORT_FEAT_C_CONNECTION) && + !(temp & PORT_CONNECT) && + (hcd->speed < HCD_USB3)) { + + hcd->driver->port_power(hcd, + wIndex + + xhci->num_usb3_ports, + false); + } break; case USB_PORT_FEAT_ENABLE: xhci_disable_port(hcd, xhci, wIndex, diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index 1a1d6b8..2e1facd 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -30,11 +30,13 @@ static struct hc_driver __read_mostly xhci_plat_hc_driver; static int xhci_plat_setup(struct usb_hcd *hcd); static int xhci_plat_start(struct usb_hcd *hcd); +static int xhci_plat_portpower(struct usb_hcd *hcd, int portnum, bool enable); static const struct xhci_driver_overrides xhci_plat_overrides __initconst = { .extra_priv_size = sizeof(struct xhci_plat_priv), .reset = xhci_plat_setup, .start = xhci_plat_start, + .port_power = xhci_plat_portpower, }; static void xhci_priv_plat_start(struct usb_hcd *hcd) @@ -64,6 +66,15 @@ static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci) */ xhci->quirks |= XHCI_PLAT; } +static int xhci_plat_portpower(struct usb_hcd *hcd, int portnum, bool enable) +{ + struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd); + + if (enable == false) + phy_reset(priv->phys[portnum]); + + return 0; +} /* called during probe() after chip reset completes */ static int xhci_plat_setup(struct usb_hcd *hcd) diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 1a4ca02..a41c009 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -5028,6 +5028,8 @@ void xhci_init_driver(struct hc_driver *drv, drv->reset = over->reset; if (over->start) drv->start = over->start; + if (over->port_power) + drv->port_power = over->port_power; } } EXPORT_SYMBOL_GPL(xhci_init_driver); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index f945380..08c573c 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1692,6 +1692,7 @@ struct xhci_driver_overrides { size_t extra_priv_size; int (*reset)(struct usb_hcd *hcd); int (*start)(struct usb_hcd *hcd); + int (*port_power)(struct usb_hcd *hcd, int portnum, bool enable); }; #defineXHCI_CFC_DELAY 10 -- 2.7.4 Regards, Srinath. -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: Need PHY reset after USB device disconnected
Hi Mathias, Please provide your suggestions to resolve this. Thank you. Regards, Srinath. On Thu, Aug 3, 2017 at 11:42 PM, Srinath Mannam wrote: > Hi Mathias, > > In our SOC, xHCI controller has three ports. In that one is SS and two > HS ports, all ports are connected with separate phy controller. > > We have a bug in HS phy controllers. > Because of this bug, HS phy controller needs to reset after > disconnected the device in the corresponding HS port. > > I could not find any available mechanism or quirks in kernel to handle > these cases. > So, I did modifications in xhci-plat.c, xhci.c and xhci-hub.c files to > fix this issue. > > But the modifications are not cleaner to upstream. > > Please help me in the implementation of proper fix. > > Below are the code changes. > > --- > drivers/usb/host/xhci-hub.c | 9 + > drivers/usb/host/xhci-plat.c | 11 +++ > drivers/usb/host/xhci.c | 2 ++ > drivers/usb/host/xhci.h | 1 + > 4 files changed, 23 insertions(+) > > diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c > index 0ef1690..3fdb07d 100644 > --- a/drivers/usb/host/xhci-hub.c > +++ b/drivers/usb/host/xhci-hub.c > @@ -1193,6 +1193,15 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 > typeReq, u16 wValue, > case USB_PORT_FEAT_C_PORT_CONFIG_ERROR: > xhci_clear_port_change_bit(xhci, wValue, wIndex, > port_array[wIndex], temp); > + if ((wValue == USB_PORT_FEAT_C_CONNECTION) && > + !(temp & PORT_CONNECT) && > + (hcd->speed < HCD_USB3)) { > + > + hcd->driver->port_power(hcd, > + wIndex + > + xhci->num_usb3_ports, > + false); > + } > break; > case USB_PORT_FEAT_ENABLE: > xhci_disable_port(hcd, xhci, wIndex, > diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c > index 1a1d6b8..2e1facd 100644 > --- a/drivers/usb/host/xhci-plat.c > +++ b/drivers/usb/host/xhci-plat.c > @@ -30,11 +30,13 @@ static struct hc_driver __read_mostly xhci_plat_hc_driver; > > static int xhci_plat_setup(struct usb_hcd *hcd); > static int xhci_plat_start(struct usb_hcd *hcd); > +static int xhci_plat_portpower(struct usb_hcd *hcd, int portnum, bool > enable); > > static const struct xhci_driver_overrides xhci_plat_overrides __initconst = { > .extra_priv_size = sizeof(struct xhci_plat_priv), > .reset = xhci_plat_setup, > .start = xhci_plat_start, > + .port_power = xhci_plat_portpower, > }; > > static void xhci_priv_plat_start(struct usb_hcd *hcd) > @@ -64,6 +66,15 @@ static void xhci_plat_quirks(struct device *dev, > struct xhci_hcd *xhci) > */ > xhci->quirks |= XHCI_PLAT; > } > +static int xhci_plat_portpower(struct usb_hcd *hcd, int portnum, bool enable) > +{ > + struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd); > + > + if (enable == false) > + phy_reset(priv->phys[portnum]); > + > + return 0; > +} > > /* called during probe() after chip reset completes */ > static int xhci_plat_setup(struct usb_hcd *hcd) > diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c > index 1a4ca02..a41c009 100644 > --- a/drivers/usb/host/xhci.c > +++ b/drivers/usb/host/xhci.c > @@ -5028,6 +5028,8 @@ void xhci_init_driver(struct hc_driver *drv, > drv->reset = over->reset; > if (over->start) > drv->start = over->start; > + if (over->port_power) > + drv->port_power = over->port_power; > } > } > EXPORT_SYMBOL_GPL(xhci_init_driver); > diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h > index f945380..08c573c 100644 > --- a/drivers/usb/host/xhci.h > +++ b/drivers/usb/host/xhci.h > @@ -1692,6 +1692,7 @@ struct xhci_driver_overrides { > size_t extra_priv_size; > int (*reset)(struct usb_hcd *hcd); > int (*start)(struct usb_hcd *hcd); > + int (*port_power)(struct usb_hcd *hcd, int portnum, bool enable); > }; > > #defineXHCI_CFC_DELAY 10 > -- > 2.7.4 > > > Regards, > Srinath. -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] usb: xhci-plat: Add generic PHY support
Hi Mathias Nyman, Please review and provide your comments to the changes in this patch. Regards, srinath. On Thu, Jul 14, 2016 at 3:29 PM, Felipe Balbi wrote: > > Hi, > > Srinath Mannam writes: >> Generic phy support added in xhci platform driver. >> In the case of multiple phys to the xhci controller, this approach >> is helpful to pass multiple phandles to xhci platform driver from >> xhci device node. >> >> Signed-off-by: Srinath Mannam >> Reviewed-by: Ray Jui >> Reviewed-by: Scott Branden > > I have no issues with this, but Mathias is off for a few weeks. > > -- > balbi -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] usb: xhci-plat: Add generic PHY support
Hi Mathias Nyman, Could you please provide your inputs on this? If you find it in good condition, please consider it for the next release. Thanks & Regards, Srinath. On Wed, Aug 3, 2016 at 7:03 PM, Srinath Mannam wrote: > Hi Mathias Nyman, > > Please review and provide your comments to the changes in this patch. > > Regards, > srinath. > > On Thu, Jul 14, 2016 at 3:29 PM, Felipe Balbi > wrote: >> >> Hi, >> >> Srinath Mannam writes: >>> Generic phy support added in xhci platform driver. >>> In the case of multiple phys to the xhci controller, this approach >>> is helpful to pass multiple phandles to xhci platform driver from >>> xhci device node. >>> >>> Signed-off-by: Srinath Mannam >>> Reviewed-by: Ray Jui >>> Reviewed-by: Scott Branden >> >> I have no issues with this, but Mathias is off for a few weeks. >> >> -- >> balbi -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 2/2] drivers: xhci: Add quirk to reset xHCI port PHY
Add a quirk to reset xHCI port PHY on port disconnect event. Stingray USB HS PHY has an issue, that USB High Speed device detected at Full Speed after the same port has connected to Full speed device. This problem can be resolved with that port PHY reset on disconnect. Signed-off-by: Srinath Mannam Reviewed-by: Ray Jui --- drivers/usb/core/hcd.c | 6 ++ drivers/usb/core/phy.c | 21 + drivers/usb/core/phy.h | 1 + drivers/usb/host/xhci-plat.c | 3 +++ drivers/usb/host/xhci-ring.c | 9 ++--- drivers/usb/host/xhci.h | 1 + include/linux/usb/hcd.h | 1 + 7 files changed, 39 insertions(+), 3 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 015b126..e2b87a6 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -2663,6 +2663,12 @@ int usb_hcd_find_raw_port_number(struct usb_hcd *hcd, int port1) return hcd->driver->find_raw_port_number(hcd, port1); } +int usb_hcd_phy_port_reset(struct usb_hcd *hcd, int port) +{ + return usb_phy_roothub_port_reset(hcd->phy_roothub, port); +} +EXPORT_SYMBOL_GPL(usb_hcd_phy_port_reset); + static int usb_hcd_request_irqs(struct usb_hcd *hcd, unsigned int irqnum, unsigned long irqflags) { diff --git a/drivers/usb/core/phy.c b/drivers/usb/core/phy.c index 38b2c77..c64767d 100644 --- a/drivers/usb/core/phy.c +++ b/drivers/usb/core/phy.c @@ -162,6 +162,27 @@ void usb_phy_roothub_power_off(struct usb_phy_roothub *phy_roothub) } EXPORT_SYMBOL_GPL(usb_phy_roothub_power_off); +int usb_phy_roothub_port_reset(struct usb_phy_roothub *phy_roothub, int port) +{ + struct usb_phy_roothub *roothub_entry; + struct list_head *head; + int i = 0; + + if (!phy_roothub) + return -EINVAL; + + head = &phy_roothub->list; + + list_for_each_entry(roothub_entry, head, list) { + if (i == port) + return phy_reset(roothub_entry->phy); + i++; + } + + return -ENODEV; +} +EXPORT_SYMBOL_GPL(usb_phy_roothub_port_reset); + int usb_phy_roothub_suspend(struct device *controller_dev, struct usb_phy_roothub *phy_roothub) { diff --git a/drivers/usb/core/phy.h b/drivers/usb/core/phy.h index 88a3c03..e8be444 100644 --- a/drivers/usb/core/phy.h +++ b/drivers/usb/core/phy.h @@ -18,6 +18,7 @@ int usb_phy_roothub_exit(struct usb_phy_roothub *phy_roothub); int usb_phy_roothub_power_on(struct usb_phy_roothub *phy_roothub); void usb_phy_roothub_power_off(struct usb_phy_roothub *phy_roothub); +int usb_phy_roothub_port_reset(struct usb_phy_roothub *phy_roothub, int port); int usb_phy_roothub_suspend(struct device *controller_dev, struct usb_phy_roothub *phy_roothub); diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index ef09cb0..5a3b486 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -289,6 +289,9 @@ static int xhci_plat_probe(struct platform_device *pdev) if (device_property_read_bool(tmpdev, "quirk-broken-port-ped")) xhci->quirks |= XHCI_BROKEN_PORT_PED; + if (device_property_read_bool(tmpdev, "usb-phy-port-reset")) + xhci->quirks |= XHCI_RESET_PHY_ON_DISCONNECT; + device_property_read_u32(tmpdev, "imod-interval-ns", &xhci->imod_interval); } diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 40fa25c..2dc3116 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1685,9 +1685,12 @@ static void handle_port_status(struct xhci_hcd *xhci, if (hcd->speed < HCD_USB3) { xhci_test_and_clear_bit(xhci, port, PORT_PLC); - if ((xhci->quirks & XHCI_RESET_PLL_ON_DISCONNECT) && - (portsc & PORT_CSC) && !(portsc & PORT_CONNECT)) - xhci_cavium_reset_phy_quirk(xhci); + if ((portsc & PORT_CSC) && !(portsc & PORT_CONNECT)) { + if (xhci->quirks & XHCI_RESET_PLL_ON_DISCONNECT) + xhci_cavium_reset_phy_quirk(xhci); + else if (xhci->quirks & XHCI_RESET_PHY_ON_DISCONNECT) + usb_hcd_phy_port_reset(hcd, port_id - 1); + } } cleanup: diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 652dc36..530c5ff 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1846,6 +1846,7 @@ struct xhci_hcd { #define XHCI_DEFAULT_PM_RUNTIME_ALLOW BIT_ULL(33) #define XHCI_RESET_PLL_ON_DISCONNECT BIT_ULL(34) #define XHCI_SNPS_BROKEN_SUSPENDBIT_ULL(35) +#define XHCI_RESET_PHY_ON_DISCONNECT BIT_ULL(36) unsigne
[PATCH 0/2] Reset xHCI port PHY on disconnect
This patch set adds a quirk in xHCI driver to reset PHY of xHCI port on its disconnect event. This patch set is based on Linux-5.0-rc2. Srinath Mannam (2): dt-bindings: usb-xhci: Add usb-phy-port-reset property drivers: xhci: Add quirk to reset xHCI port PHY Documentation/devicetree/bindings/usb/usb-xhci.txt | 1 + drivers/usb/core/hcd.c | 6 ++ drivers/usb/core/phy.c | 21 + drivers/usb/core/phy.h | 1 + drivers/usb/host/xhci-plat.c | 3 +++ drivers/usb/host/xhci-ring.c | 9 ++--- drivers/usb/host/xhci.h| 1 + include/linux/usb/hcd.h| 1 + 8 files changed, 40 insertions(+), 3 deletions(-) -- 2.7.4
[PATCH 1/2] dt-bindings: usb-xhci: Add usb-phy-port-reset property
Add usb-phy-port-reset optional property to set quirk in xhci platform driver which forces USB port PHY reset on port disconnect event. Signed-off-by: Srinath Mannam Reviewed-by: Ray Jui --- Documentation/devicetree/bindings/usb/usb-xhci.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/usb/usb-xhci.txt b/Documentation/devicetree/bindings/usb/usb-xhci.txt index fea8b15..ecbdb15 100644 --- a/Documentation/devicetree/bindings/usb/usb-xhci.txt +++ b/Documentation/devicetree/bindings/usb/usb-xhci.txt @@ -40,6 +40,7 @@ Optional properties: - usb3-lpm-capable: determines if platform is USB3 LPM capable - quirk-broken-port-ped: set if the controller has broken port disable mechanism - imod-interval-ns: default interrupt moderation interval is 5000ns + - usb-phy-port-reset: set this to do USB PORT PHY reset while disconnect - phys : see usb-hcd.txt in the current directory additionally the properties from usb-hcd.txt (in the current directory) are -- 2.7.4
Re: [PATCH 2/2] drivers: xhci: Add quirk to reset xHCI port PHY
Hi Mathias, Thanks for review, please see my comments below inline. On Thu, Feb 7, 2019 at 8:32 PM Mathias Nyman wrote: > > On 05.02.2019 08:18, Srinath Mannam wrote: > > Add a quirk to reset xHCI port PHY on port disconnect event. > > Stingray USB HS PHY has an issue, that USB High Speed device detected > > at Full Speed after the same port has connected to Full speed device. > > This problem can be resolved with that port PHY reset on disconnect. > > > > Signed-off-by: Srinath Mannam > > Reviewed-by: Ray Jui > > --- > > drivers/usb/core/hcd.c | 6 ++ > > drivers/usb/core/phy.c | 21 + > > drivers/usb/core/phy.h | 1 + > > drivers/usb/host/xhci-plat.c | 3 +++ > > drivers/usb/host/xhci-ring.c | 9 ++--- > > drivers/usb/host/xhci.h | 1 + > > include/linux/usb/hcd.h | 1 + > > 7 files changed, 39 insertions(+), 3 deletions(-) > > > > diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c > > index 015b126..e2b87a6 100644 > > --- a/drivers/usb/core/hcd.c > > +++ b/drivers/usb/core/hcd.c > > @@ -2663,6 +2663,12 @@ int usb_hcd_find_raw_port_number(struct usb_hcd > > *hcd, int port1) > > return hcd->driver->find_raw_port_number(hcd, port1); > > } > > > > +int usb_hcd_phy_port_reset(struct usb_hcd *hcd, int port) > > +{ > > + return usb_phy_roothub_port_reset(hcd->phy_roothub, port); > > +} > > +EXPORT_SYMBOL_GPL(usb_hcd_phy_port_reset); > > + > > static int usb_hcd_request_irqs(struct usb_hcd *hcd, > > unsigned int irqnum, unsigned long irqflags) > > { > > diff --git a/drivers/usb/core/phy.c b/drivers/usb/core/phy.c > > index 38b2c77..c64767d 100644 > > --- a/drivers/usb/core/phy.c > > +++ b/drivers/usb/core/phy.c > > @@ -162,6 +162,27 @@ void usb_phy_roothub_power_off(struct usb_phy_roothub > > *phy_roothub) > > } > > EXPORT_SYMBOL_GPL(usb_phy_roothub_power_off); > > > > +int usb_phy_roothub_port_reset(struct usb_phy_roothub *phy_roothub, int > > port) > > +{ > > + struct usb_phy_roothub *roothub_entry; > > + struct list_head *head; > > + int i = 0; > > + > > + if (!phy_roothub) > > + return -EINVAL; > > + > > + head = &phy_roothub->list; > > + > > + list_for_each_entry(roothub_entry, head, list) { > > + if (i == port) > > + return phy_reset(roothub_entry->phy); > > + i++; > > + } > > I'm not that familiar with SoC's that have several PHYs per controller, > but this looks odd. > > For the above code to work wouldn't it require that each port has their own > PHY, > and the PHYs are added to the list of usb_phy_roothub is in the same order as > usb ports? > > Or is there something I don't understand here? > In our SOC (Stingray), xHCI controller has three ports and each port connected to separate PHY. Stingray xHCI controller supports both SS and HS ports and connected separate PHYs. We passed PHY phandlers in xHCI DT node in the order of port numbers. as shown below xHCI DT node. So that all PHYs added to usb_phy_roothub are in order of port numbers. xhci1: usb@11000 { compatible = "generic-xhci"; reg = <0x00011000 0x1000>; interrupts = ; phys = <&usb1_phy1>, <&usbphy2>, <&usb1_phy0>; phy-names = "phy0", "phy1", "phy2"; dma-coherent; status = "disabled"; }; But we have issue with HS PHYs, so that those PHYs are required to reset. Regards, Srinath. > -Mathias >
Re: [PATCH 2/2] drivers: xhci: Add quirk to reset xHCI port PHY
Hi Mathias, Thanks for comments, Please find my comments below inline. On Fri, Feb 8, 2019 at 6:00 PM Mathias Nyman wrote: > > On 07.02.2019 17:17, Srinath Mannam wrote: > > Hi Mathias, > > > > Thanks for review, please see my comments below inline. > > > > On Thu, Feb 7, 2019 at 8:32 PM Mathias Nyman > > wrote: > >> > >> On 05.02.2019 08:18, Srinath Mannam wrote: > >>> Add a quirk to reset xHCI port PHY on port disconnect event. > >>> Stingray USB HS PHY has an issue, that USB High Speed device detected > >>> at Full Speed after the same port has connected to Full speed device. > >>> This problem can be resolved with that port PHY reset on disconnect. > >>> > >>> Signed-off-by: Srinath Mannam > >>> Reviewed-by: Ray Jui > >>> --- > >>>drivers/usb/core/hcd.c | 6 ++ > >>>drivers/usb/core/phy.c | 21 + > >>>drivers/usb/core/phy.h | 1 + > >>>drivers/usb/host/xhci-plat.c | 3 +++ > >>>drivers/usb/host/xhci-ring.c | 9 ++--- > >>>drivers/usb/host/xhci.h | 1 + > >>>include/linux/usb/hcd.h | 1 + > >>>7 files changed, 39 insertions(+), 3 deletions(-) > >>> > >>> diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c > >>> index 015b126..e2b87a6 100644 > >>> --- a/drivers/usb/core/hcd.c > >>> +++ b/drivers/usb/core/hcd.c > >>> @@ -2663,6 +2663,12 @@ int usb_hcd_find_raw_port_number(struct usb_hcd > >>> *hcd, int port1) > >>>return hcd->driver->find_raw_port_number(hcd, port1); > >>>} > >>> > >>> +int usb_hcd_phy_port_reset(struct usb_hcd *hcd, int port) > >>> +{ > >>> + return usb_phy_roothub_port_reset(hcd->phy_roothub, port); > >>> +} > >>> +EXPORT_SYMBOL_GPL(usb_hcd_phy_port_reset); > >>> + > >>>static int usb_hcd_request_irqs(struct usb_hcd *hcd, > >>>unsigned int irqnum, unsigned long irqflags) > >>>{ > >>> diff --git a/drivers/usb/core/phy.c b/drivers/usb/core/phy.c > >>> index 38b2c77..c64767d 100644 > >>> --- a/drivers/usb/core/phy.c > >>> +++ b/drivers/usb/core/phy.c > >>> @@ -162,6 +162,27 @@ void usb_phy_roothub_power_off(struct > >>> usb_phy_roothub *phy_roothub) > >>>} > >>>EXPORT_SYMBOL_GPL(usb_phy_roothub_power_off); > >>> > >>> +int usb_phy_roothub_port_reset(struct usb_phy_roothub *phy_roothub, int > >>> port) > >>> +{ > >>> + struct usb_phy_roothub *roothub_entry; > >>> + struct list_head *head; > >>> + int i = 0; > >>> + > >>> + if (!phy_roothub) > >>> + return -EINVAL; > >>> + > >>> + head = &phy_roothub->list; > >>> + > >>> + list_for_each_entry(roothub_entry, head, list) { > >>> + if (i == port) > >>> + return phy_reset(roothub_entry->phy); > >>> + i++; > >>> + } > >> > >> I'm not that familiar with SoC's that have several PHYs per controller, > >> but this looks odd. > >> > >> For the above code to work wouldn't it require that each port has their > >> own PHY, > >> and the PHYs are added to the list of usb_phy_roothub is in the same order > >> as usb ports? > >> > >> Or is there something I don't understand here? > >> > > In our SOC (Stingray), xHCI controller has three ports and each port > > connected to separate PHY. > > Stingray xHCI controller supports both SS and HS ports and connected > > separate PHYs. > > We passed PHY phandlers in xHCI DT node in the order of port numbers. > > as shown below xHCI DT node. > > So that all PHYs added to usb_phy_roothub are in order of port numbers. > > xhci1: usb@11000 { > > compatible = "generic-xhci"; > > reg = <0x00011000 0x1000>; > > interrupts = ; > > phys = <&usb1_phy1>, <&usbphy2>, <&usb1_phy0>; > > phy-names = "phy0", "phy1", "phy2"; > > dma-coherent; > > sta
Re: [PATCH 1/2] dt-bindings: usb-xhci: Add usb-phy-port-reset property
Hi Rob, Thanks for the review, Please see my comments below in line. Regards, Srinath. On Tue, Feb 26, 2019 at 3:08 AM Rob Herring wrote: > > On Tue, Feb 05, 2019 at 11:48:53AM +0530, Srinath Mannam wrote: > > Add usb-phy-port-reset optional property to set quirk in xhci platform > > driver which forces USB port PHY reset on port disconnect event. > > > > Signed-off-by: Srinath Mannam > > Reviewed-by: Ray Jui > > --- > > Documentation/devicetree/bindings/usb/usb-xhci.txt | 1 + > > 1 file changed, 1 insertion(+) > > > > diff --git a/Documentation/devicetree/bindings/usb/usb-xhci.txt > > b/Documentation/devicetree/bindings/usb/usb-xhci.txt > > index fea8b15..ecbdb15 100644 > > --- a/Documentation/devicetree/bindings/usb/usb-xhci.txt > > +++ b/Documentation/devicetree/bindings/usb/usb-xhci.txt > > @@ -40,6 +40,7 @@ Optional properties: > >- usb3-lpm-capable: determines if platform is USB3 LPM capable > >- quirk-broken-port-ped: set if the controller has broken port disable > > mechanism > >- imod-interval-ns: default interrupt moderation interval is 5000ns > > + - usb-phy-port-reset: set this to do USB PORT PHY reset while disconnect > >- phys : see usb-hcd.txt in the current directory > > This should be implied by the HCI or phy compatible string (depending > on who exactly needs the quirky behavior). Stingray USB HS PHY connected to xHCI port has an issue, if full speed devices connected to this port then after all High Speed devices connected to this port are detected at full speed instead of high speed. So that we need to do PHY (which is connected to port) reset on xHCI port disconnect event. That is the reason we required to add quirk in xHCI. > > Rob
Re: [PATCH 1/2] dt-bindings: usb-xhci: Add usb-phy-port-reset property
Hi Rob, Thanks for the information. Please find my comments below. Regards, Srinath. On Tue, Feb 26, 2019 at 11:33 PM Rob Herring wrote: > > On Mon, Feb 25, 2019 at 10:57 PM Srinath Mannam > wrote: > > > > Hi Rob, > > Thanks for the review, Please see my comments below in line. > > > > Regards, > > Srinath. > > On Tue, Feb 26, 2019 at 3:08 AM Rob Herring wrote: > > > > > > On Tue, Feb 05, 2019 at 11:48:53AM +0530, Srinath Mannam wrote: > > > > Add usb-phy-port-reset optional property to set quirk in xhci platform > > > > driver which forces USB port PHY reset on port disconnect event. > > > > > > > > Signed-off-by: Srinath Mannam > > > > Reviewed-by: Ray Jui > > > > --- > > > > Documentation/devicetree/bindings/usb/usb-xhci.txt | 1 + > > > > 1 file changed, 1 insertion(+) > > > > > > > > diff --git a/Documentation/devicetree/bindings/usb/usb-xhci.txt > > > > b/Documentation/devicetree/bindings/usb/usb-xhci.txt > > > > index fea8b15..ecbdb15 100644 > > > > --- a/Documentation/devicetree/bindings/usb/usb-xhci.txt > > > > +++ b/Documentation/devicetree/bindings/usb/usb-xhci.txt > > > > @@ -40,6 +40,7 @@ Optional properties: > > > >- usb3-lpm-capable: determines if platform is USB3 LPM capable > > > >- quirk-broken-port-ped: set if the controller has broken port > > > > disable mechanism > > > >- imod-interval-ns: default interrupt moderation interval is 5000ns > > > > + - usb-phy-port-reset: set this to do USB PORT PHY reset while > > > > disconnect > > > >- phys : see usb-hcd.txt in the current directory > > > > > > This should be implied by the HCI or phy compatible string (depending > > > on who exactly needs the quirky behavior). > > Stingray USB HS PHY connected to xHCI port has an issue, if full speed > > devices connected to this port then > > after all High Speed devices connected to this port are detected at > > full speed instead of high speed. > > So that we need to do PHY (which is connected to port) reset on xHCI > > port disconnect event. > > That is the reason we required to add quirk in xHCI. > > So, by looking at the xhci host and phy compatible strings (or maybe > just the phy) you can determine whether you need to reset the port or > not. All the information you need is in DT already. xHCI controller in our SOC has three ports each port has one PHY(SS/HS) connected to it. HS PHY has to reset on its corresponding port disconnect event. port disconnect event is captured in xHCI host framework so, quirk has to be registered in xHCI framework only. But we are using "generic-xhci" generic compatible string for our xHCI controller. As per your advice, we will add new compatible string in xhci-plat.c driver for our xHCI controller and will add quirk part of that. Thank you. > > Rob
[PATCH v2 1/5] phy: Add phy ports in attrs
Add phy ports bitmask to contain enabled PHY ports. set and get APIs added to set and get phy ports value. Signed-off-by: Srinath Mannam --- include/linux/phy/phy.h | 10 ++ 1 file changed, 10 insertions(+) diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h index 15032f14..b8bca1d 100644 --- a/include/linux/phy/phy.h +++ b/include/linux/phy/phy.h @@ -109,10 +109,12 @@ struct phy_ops { /** * struct phy_attrs - represents phy attributes * @bus_width: Data path width implemented by PHY + * @phy_ports: Bitmask of enabled ports * @mode: PHY mode */ struct phy_attrs { u32 bus_width; + u32 phy_ports; enum phy_mode mode; }; @@ -225,6 +227,14 @@ static inline void phy_set_bus_width(struct phy *phy, int bus_width) { phy->attrs.bus_width = bus_width; } +static inline int phy_get_phy_ports(struct phy *phy) +{ + return phy->attrs.phy_ports; +} +static inline void phy_set_phy_ports(struct phy *phy, int phy_ports) +{ + phy->attrs.phy_ports |= phy_ports; +} struct phy *phy_get(struct device *dev, const char *string); struct phy *phy_optional_get(struct device *dev, const char *string); struct phy *devm_phy_get(struct device *dev, const char *string); -- 2.7.4
[PATCH v2 3/5] phy: sr-usb: Set phy ports
set phy ports value in xlate handler which is taken from second argument of PHY phandle. Signed-off-by: Srinath Mannam --- drivers/phy/broadcom/phy-bcm-sr-usb.c | 9 - 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/phy/broadcom/phy-bcm-sr-usb.c b/drivers/phy/broadcom/phy-bcm-sr-usb.c index fe6c589..5274e45 100644 --- a/drivers/phy/broadcom/phy-bcm-sr-usb.c +++ b/drivers/phy/broadcom/phy-bcm-sr-usb.c @@ -278,9 +278,16 @@ static struct phy *bcm_usb_phy_xlate(struct device *dev, if (WARN_ON(phy_idx > 1)) return ERR_PTR(-ENODEV); + if (args->args[1]) + phy_set_phy_ports(phy_cfg[phy_idx].phy, args->args[1]); + return phy_cfg[phy_idx].phy; - } else + } else { + if (args->args[0]) + phy_set_phy_ports(phy_cfg->phy, args->args[0]); + return phy_cfg->phy; + } } static int bcm_usb_phy_create(struct device *dev, struct device_node *node, -- 2.7.4
[PATCH v2 2/5] dt-bindings: phy: Modify Stingray USB PHY #phy-cells
Increase #phy-cells from 1 to 2 to have bitmask of PHY enabled ports. Signed-off-by: Srinath Mannam --- .../devicetree/bindings/phy/brcm,stingray-usb-phy.txt | 14 -- 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Documentation/devicetree/bindings/phy/brcm,stingray-usb-phy.txt b/Documentation/devicetree/bindings/phy/brcm,stingray-usb-phy.txt index 4ba2989..aeb0568 100644 --- a/Documentation/devicetree/bindings/phy/brcm,stingray-usb-phy.txt +++ b/Documentation/devicetree/bindings/phy/brcm,stingray-usb-phy.txt @@ -6,9 +6,11 @@ Required properties: - "brcm,sr-usb-hs-phy" is a single HS PHY. - reg: offset and length of the PHY blocks registers - #phy-cells: - - Must be 1 for brcm,sr-usb-combo-phy as it expects one argument to indicate - the PHY number of two PHYs. 0 for HS PHY and 1 for SS PHY. - - Must be 0 for brcm,sr-usb-hs-phy. + - Must be 2 for brcm,sr-usb-combo-phy. + - Cell 1 - PHY Number, 0 for HS PHY and 1 for SS PHY. + - Cell 2 - Bitmask of enabled ports connected to USB Host controller. + - Must be 1 for brcm,sr-usb-hs-phy to indicate Bit mask of ports connected + to USB Host controller. Refer to phy/phy-bindings.txt for the generic PHY binding properties @@ -16,17 +18,17 @@ Example: usbphy0: usb-phy@0 { compatible = "brcm,sr-usb-combo-phy"; reg = <0x 0x100>; - #phy-cells = <1>; + #phy-cells = <2>; }; usbphy1: usb-phy@1 { compatible = "brcm,sr-usb-combo-phy"; reg = <0x0001 0x100>, - #phy-cells = <1>; + #phy-cells = <2>; }; usbphy2: usb-phy@2 { compatible = "brcm,sr-usb-hs-phy"; reg = <0x0002 0x100>, - #phy-cells = <0>; + #phy-cells = <1>; }; -- 2.7.4
[PATCH v2 5/5] drivers: xhci: Add quirk to reset xHCI port PHY
Stingray USB HS PHY has an issue, that USB High Speed device detects at Full Speed if the same port was connected to Full speed device. This problem can be resolved by resetting that port's PHY on disconnect. Add a quirk to reset xHCI port PHY on port disconnect event. XHCI_RESET_PHY_ON_DISCONNECT quirk is introduced with xhci_plat_brcm_sr platform data. New quirks parameter added in xhci_plat_priv structure to assign platform specific quirks. Signed-off-by: Srinath Mannam --- drivers/usb/core/hcd.c | 6 ++ drivers/usb/core/phy.c | 19 +++ drivers/usb/core/phy.h | 1 + drivers/usb/host/xhci-plat.c | 10 ++ drivers/usb/host/xhci-plat.h | 1 + drivers/usb/host/xhci-ring.c | 9 ++--- drivers/usb/host/xhci.h | 1 + include/linux/usb/hcd.h | 1 + 8 files changed, 45 insertions(+), 3 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 94d2255..a23441b 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -2675,6 +2675,12 @@ int usb_hcd_find_raw_port_number(struct usb_hcd *hcd, int port1) return hcd->driver->find_raw_port_number(hcd, port1); } +int usb_hcd_phy_port_reset(struct usb_hcd *hcd, int port) +{ + return usb_phy_roothub_port_reset(hcd->phy_roothub, port); +} +EXPORT_SYMBOL_GPL(usb_hcd_phy_port_reset); + static int usb_hcd_request_irqs(struct usb_hcd *hcd, unsigned int irqnum, unsigned long irqflags) { diff --git a/drivers/usb/core/phy.c b/drivers/usb/core/phy.c index 7580493..4d1ac31 100644 --- a/drivers/usb/core/phy.c +++ b/drivers/usb/core/phy.c @@ -190,6 +190,25 @@ void usb_phy_roothub_power_off(struct usb_phy_roothub *phy_roothub) } EXPORT_SYMBOL_GPL(usb_phy_roothub_power_off); +int usb_phy_roothub_port_reset(struct usb_phy_roothub *phy_roothub, int port) +{ + struct usb_phy_roothub *roothub_entry; + struct list_head *head; + + if (!phy_roothub) + return -EINVAL; + + head = &phy_roothub->list; + + list_for_each_entry(roothub_entry, head, list) { + if (phy_get_phy_ports(roothub_entry->phy) & BIT(port)) + return phy_reset(roothub_entry->phy); + } + + return -ENODEV; +} +EXPORT_SYMBOL_GPL(usb_phy_roothub_port_reset); + int usb_phy_roothub_suspend(struct device *controller_dev, struct usb_phy_roothub *phy_roothub) { diff --git a/drivers/usb/core/phy.h b/drivers/usb/core/phy.h index dad564e..3f682e8 100644 --- a/drivers/usb/core/phy.h +++ b/drivers/usb/core/phy.h @@ -20,6 +20,7 @@ int usb_phy_roothub_set_mode(struct usb_phy_roothub *phy_roothub, enum phy_mode mode); int usb_phy_roothub_power_on(struct usb_phy_roothub *phy_roothub); void usb_phy_roothub_power_off(struct usb_phy_roothub *phy_roothub); +int usb_phy_roothub_port_reset(struct usb_phy_roothub *phy_roothub, int port); int usb_phy_roothub_suspend(struct device *controller_dev, struct usb_phy_roothub *phy_roothub); diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index 998241f..af23e92 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -47,6 +47,9 @@ static void xhci_priv_plat_start(struct usb_hcd *hcd) static int xhci_priv_init_quirk(struct usb_hcd *hcd) { struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd); + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + + xhci->quirks |= priv->quirks; if (!priv->init_quirk) return 0; @@ -116,6 +119,10 @@ static const struct xhci_plat_priv xhci_plat_renesas_rcar_gen3 = { .resume_quirk = xhci_rcar_resume_quirk, }; +static const struct xhci_plat_priv xhci_plat_brcm_sr = { + .quirks = XHCI_RESET_PHY_ON_DISCONNECT, +}; + static const struct of_device_id usb_xhci_of_match[] = { { .compatible = "generic-xhci", @@ -151,6 +158,9 @@ static const struct of_device_id usb_xhci_of_match[] = { }, { .compatible = "renesas,rcar-gen3-xhci", .data = &xhci_plat_renesas_rcar_gen3, + }, { + .compatible = "brcm,sr-xhci", + .data = &xhci_plat_brcm_sr, }, {}, }; diff --git a/drivers/usb/host/xhci-plat.h b/drivers/usb/host/xhci-plat.h index ae29f22..0cd61c6 100644 --- a/drivers/usb/host/xhci-plat.h +++ b/drivers/usb/host/xhci-plat.h @@ -15,6 +15,7 @@ struct xhci_plat_priv { void (*plat_start)(struct usb_hcd *); int (*init_quirk)(struct usb_hcd *); int (*resume_quirk)(struct usb_hcd *); + unsigned long long quirks; }; #define hcd_to_xhci_priv(h) ((struct xhci_plat_priv *)hcd_to_xhci(h)->priv) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index feffceb..77e94e8 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-r
[PATCH v2 0/4] Reset xHCI port PHY on disconnect
This patch set adds a quirk in xHCI driver to reset PHY of xHCI port on its disconnect event. This patch set is based on Linux-5.2-rc4. Changes from v1: - Addressed Mathias's comments - Modified mapping of HC ports and their corresponding PHYs - Addressed Rob's comments - Removed usb-phy-port-reset DT property. - Added quirk in platform data using HCI compatible string. - Add phy ports in phy attr structure to have enabled ports bitmask. - Modified #phy-cells of sr-phy to pass phy ports bitmask. Srinath Mannam (4): phy: Add phy ports in attrs dt-bindings: phy: Modify Stingray USB PHY #phy-cells phy: sr-usb: Set phy ports dt-bindings: usb-xhci: Add platform specific compatible for Stingray xHCI drivers: xhci: Add quirk to reset xHCI port PHY .../devicetree/bindings/phy/brcm,stingray-usb-phy.txt | 14 -- Documentation/devicetree/bindings/usb/usb-xhci.txt| 1 + drivers/phy/broadcom/phy-bcm-sr-usb.c | 9 - drivers/usb/core/hcd.c| 6 ++ drivers/usb/core/phy.c| 19 +++ drivers/usb/core/phy.h| 1 + drivers/usb/host/xhci-plat.c | 10 ++ drivers/usb/host/xhci-plat.h | 1 + drivers/usb/host/xhci-ring.c | 9 ++--- drivers/usb/host/xhci.h | 1 + include/linux/phy/phy.h | 10 ++ include/linux/usb/hcd.h | 1 + 12 files changed, 72 insertions(+), 10 deletions(-) -- 2.7.4
[PATCH v2 4/5] dt-bindings: usb-xhci: Add platform specific compatible for Stingray xHCI
Add Platform specific compatible, because xHCI of this SoC has an issue with HS port which has to reset on disconnect event. Signed-off-by: Srinath Mannam --- Documentation/devicetree/bindings/usb/usb-xhci.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/usb/usb-xhci.txt b/Documentation/devicetree/bindings/usb/usb-xhci.txt index 97400e8..ee1f051 100644 --- a/Documentation/devicetree/bindings/usb/usb-xhci.txt +++ b/Documentation/devicetree/bindings/usb/usb-xhci.txt @@ -22,6 +22,7 @@ Required properties: device - "renesas,rcar-gen3-xhci" for a generic R-Car Gen3 or RZ/G2 compatible device +- "brcm,sr-xhci" for Stingray SoC - "xhci-platform" (deprecated) When compatible with the generic version, nodes must list the -- 2.7.4