diff options
| author | Mark Brown <broonie@kernel.org> | 2020-12-28 17:20:00 +0300 | 
|---|---|---|
| committer | Mark Brown <broonie@kernel.org> | 2020-12-28 17:20:00 +0300 | 
| commit | 2ae6f64ce1ce304b502461fdfe0b96c8171ae2cc (patch) | |
| tree | 88e987c447daf2c29e2d4c15e58d1029b0cc78c2 /drivers/usb/cdns3 | |
| parent | 3b66e4a8e58a85af3212c7117d7a29c9ef6679a2 (diff) | |
| parent | 5c8fe583cce542aa0b84adc939ce85293de36e5e (diff) | |
| download | linux-2ae6f64ce1ce304b502461fdfe0b96c8171ae2cc.tar.xz | |
Merge tag 'v5.11-rc1' into regulator-5.11
Linux 5.11-rc1
Diffstat (limited to 'drivers/usb/cdns3')
| -rw-r--r-- | drivers/usb/cdns3/cdns3-imx.c | 2 | ||||
| -rw-r--r-- | drivers/usb/cdns3/core.c | 44 | ||||
| -rw-r--r-- | drivers/usb/cdns3/core.h | 4 | ||||
| -rw-r--r-- | drivers/usb/cdns3/gadget-export.h | 3 | ||||
| -rw-r--r-- | drivers/usb/cdns3/gadget.c | 29 | ||||
| -rw-r--r-- | drivers/usb/cdns3/host-export.h | 6 | ||||
| -rw-r--r-- | drivers/usb/cdns3/host.c | 60 | 
7 files changed, 106 insertions, 42 deletions
| diff --git a/drivers/usb/cdns3/cdns3-imx.c b/drivers/usb/cdns3/cdns3-imx.c index 54a2d70a9c73..22a56c4dce67 100644 --- a/drivers/usb/cdns3/cdns3-imx.c +++ b/drivers/usb/cdns3/cdns3-imx.c @@ -151,6 +151,7 @@ static int cdns_imx_platform_suspend(struct device *dev,  	bool suspend, bool wakeup);  static struct cdns3_platform_data cdns_imx_pdata = {  	.platform_suspend = cdns_imx_platform_suspend, +	.quirks		  = CDNS3_DEFAULT_PM_RUNTIME_ALLOW,  };  static const struct of_dev_auxdata cdns_imx_auxdata[] = { @@ -206,7 +207,6 @@ static int cdns_imx_probe(struct platform_device *pdev)  	device_set_wakeup_capable(dev, true);  	pm_runtime_set_active(dev);  	pm_runtime_enable(dev); -	pm_runtime_forbid(dev);  	return ret;  err: diff --git a/drivers/usb/cdns3/core.c b/drivers/usb/cdns3/core.c index a0f73d4711ae..1991cb5cf6bf 100644 --- a/drivers/usb/cdns3/core.c +++ b/drivers/usb/cdns3/core.c @@ -427,7 +427,6 @@ static irqreturn_t cdns3_wakeup_irq(int irq, void *data)   */  static int cdns3_probe(struct platform_device *pdev)  { -	struct usb_role_switch_desc sw_desc = { };  	struct device *dev = &pdev->dev;  	struct resource	*res;  	struct cdns3 *cdns; @@ -466,11 +465,8 @@ static int cdns3_probe(struct platform_device *pdev)  	cdns->xhci_res[1] = *res;  	cdns->dev_irq = platform_get_irq_byname(pdev, "peripheral"); -	if (cdns->dev_irq == -EPROBE_DEFER) -		return cdns->dev_irq; -  	if (cdns->dev_irq < 0) -		dev_err(dev, "couldn't get peripheral irq\n"); +		return cdns->dev_irq;  	regs = devm_platform_ioremap_resource_byname(pdev, "dev");  	if (IS_ERR(regs)) @@ -478,14 +474,9 @@ static int cdns3_probe(struct platform_device *pdev)  	cdns->dev_regs	= regs;  	cdns->otg_irq = platform_get_irq_byname(pdev, "otg"); -	if (cdns->otg_irq == -EPROBE_DEFER) +	if (cdns->otg_irq < 0)  		return cdns->otg_irq; -	if (cdns->otg_irq < 0) { -		dev_err(dev, "couldn't get otg irq\n"); -		return cdns->otg_irq; -	} -  	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "otg");  	if (!res) {  		dev_err(dev, "couldn't get otg resource\n"); @@ -529,18 +520,21 @@ static int cdns3_probe(struct platform_device *pdev)  	if (ret)  		goto err2; -	sw_desc.set = cdns3_role_set; -	sw_desc.get = cdns3_role_get; -	sw_desc.allow_userspace_control = true; -	sw_desc.driver_data = cdns; -	if (device_property_read_bool(dev, "usb-role-switch")) +	if (device_property_read_bool(dev, "usb-role-switch")) { +		struct usb_role_switch_desc sw_desc = { }; + +		sw_desc.set = cdns3_role_set; +		sw_desc.get = cdns3_role_get; +		sw_desc.allow_userspace_control = true; +		sw_desc.driver_data = cdns;  		sw_desc.fwnode = dev->fwnode; -	cdns->role_sw = usb_role_switch_register(dev, &sw_desc); -	if (IS_ERR(cdns->role_sw)) { -		ret = PTR_ERR(cdns->role_sw); -		dev_warn(dev, "Unable to register Role Switch\n"); -		goto err3; +		cdns->role_sw = usb_role_switch_register(dev, &sw_desc); +		if (IS_ERR(cdns->role_sw)) { +			ret = PTR_ERR(cdns->role_sw); +			dev_warn(dev, "Unable to register Role Switch\n"); +			goto err3; +		}  	}  	if (cdns->wakeup_irq) { @@ -551,7 +545,7 @@ static int cdns3_probe(struct platform_device *pdev)  		if (ret) {  			dev_err(cdns->dev, "couldn't register wakeup irq handler\n"); -			goto err3; +			goto err4;  		}  	} @@ -567,7 +561,8 @@ static int cdns3_probe(struct platform_device *pdev)  	device_set_wakeup_capable(dev, true);  	pm_runtime_set_active(dev);  	pm_runtime_enable(dev); -	pm_runtime_forbid(dev); +	if (!(cdns->pdata && (cdns->pdata->quirks & CDNS3_DEFAULT_PM_RUNTIME_ALLOW))) +		pm_runtime_forbid(dev);  	/*  	 * The controller needs less time between bus and controller suspend, @@ -582,7 +577,8 @@ static int cdns3_probe(struct platform_device *pdev)  	return 0;  err4:  	cdns3_drd_exit(cdns); -	usb_role_switch_unregister(cdns->role_sw); +	if (cdns->role_sw) +		usb_role_switch_unregister(cdns->role_sw);  err3:  	set_phy_power_off(cdns);  err2: diff --git a/drivers/usb/cdns3/core.h b/drivers/usb/cdns3/core.h index 8a40d53d5ede..3176f924293a 100644 --- a/drivers/usb/cdns3/core.h +++ b/drivers/usb/cdns3/core.h @@ -42,6 +42,8 @@ struct cdns3_role_driver {  struct cdns3_platform_data {  	int (*platform_suspend)(struct device *dev,  			bool suspend, bool wakeup); +	unsigned long quirks; +#define CDNS3_DEFAULT_PM_RUNTIME_ALLOW	BIT(0)  };  /** @@ -73,6 +75,7 @@ struct cdns3_platform_data {   * @wakeup_pending: wakeup interrupt pending   * @pdata: platform data from glue layer   * @lock: spinlock structure + * @xhci_plat_data: xhci private data structure pointer   */  struct cdns3 {  	struct device			*dev; @@ -106,6 +109,7 @@ struct cdns3 {  	bool				wakeup_pending;  	struct cdns3_platform_data	*pdata;  	spinlock_t			lock; +	struct xhci_plat_priv		*xhci_plat_data;  };  int cdns3_hw_role_switch(struct cdns3 *cdns); diff --git a/drivers/usb/cdns3/gadget-export.h b/drivers/usb/cdns3/gadget-export.h index 577469eee961..702c5a267a92 100644 --- a/drivers/usb/cdns3/gadget-export.h +++ b/drivers/usb/cdns3/gadget-export.h @@ -13,7 +13,6 @@  #ifdef CONFIG_USB_CDNS3_GADGET  int cdns3_gadget_init(struct cdns3 *cdns); -void cdns3_gadget_exit(struct cdns3 *cdns);  #else  static inline int cdns3_gadget_init(struct cdns3 *cdns) @@ -21,8 +20,6 @@ static inline int cdns3_gadget_init(struct cdns3 *cdns)  	return -ENXIO;  } -static inline void cdns3_gadget_exit(struct cdns3 *cdns) { } -  #endif  #endif /* __LINUX_CDNS3_GADGET_EXPORT */ diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c index 66c1e6723eb1..08a4e693c470 100644 --- a/drivers/usb/cdns3/gadget.c +++ b/drivers/usb/cdns3/gadget.c @@ -1114,7 +1114,7 @@ static int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep,  	struct cdns3_device *priv_dev = priv_ep->cdns3_dev;  	struct cdns3_request *priv_req;  	struct cdns3_trb *trb; -	struct cdns3_trb *link_trb; +	struct cdns3_trb *link_trb = NULL;  	dma_addr_t trb_dma;  	u32 togle_pcs = 1;  	int sg_iter = 0; @@ -1193,10 +1193,20 @@ static int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep,  	/* set incorrect Cycle Bit for first trb*/  	control = priv_ep->pcs ? 0 : TRB_CYCLE; +	trb->length = 0; +	if (priv_dev->dev_ver >= DEV_VER_V2) { +		u16 td_size; + +		td_size = DIV_ROUND_UP(request->length, +				       priv_ep->endpoint.maxpacket); +		if (priv_dev->gadget.speed == USB_SPEED_SUPER) +			trb->length = TRB_TDL_SS_SIZE(td_size); +		else +			control |= TRB_TDL_HS_SIZE(td_size); +	}  	do {  		u32 length; -		u16 td_size = 0;  		/* fill TRB */  		control |= TRB_TYPE(TRB_NORMAL); @@ -1208,20 +1218,12 @@ static int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep,  			length = request->length;  		} -		if (likely(priv_dev->dev_ver >= DEV_VER_V2)) -			td_size = DIV_ROUND_UP(length, -					       priv_ep->endpoint.maxpacket); -		else if (priv_ep->flags & EP_TDLCHK_EN) +		if (priv_ep->flags & EP_TDLCHK_EN)  			total_tdl += DIV_ROUND_UP(length,  					       priv_ep->endpoint.maxpacket); -		trb->length = cpu_to_le32(TRB_BURST_LEN(priv_ep->trb_burst_size) | +		trb->length |= cpu_to_le32(TRB_BURST_LEN(priv_ep->trb_burst_size) |  					TRB_LEN(length)); -		if (priv_dev->gadget.speed == USB_SPEED_SUPER) -			trb->length |= cpu_to_le32(TRB_TDL_SS_SIZE(td_size)); -		else -			control |= TRB_TDL_HS_SIZE(td_size); -  		pcs = priv_ep->pcs ? TRB_CYCLE : 0;  		/* @@ -1258,6 +1260,7 @@ static int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep,  		priv_req->end_trb = priv_ep->enqueue;  		cdns3_ep_inc_enq(priv_ep);  		trb = priv_ep->trb_pool + priv_ep->enqueue; +		trb->length = 0;  	} while (sg_iter < num_trb);  	trb = priv_req->trb; @@ -3081,7 +3084,7 @@ static void cdns3_gadget_release(struct device *dev)  	kfree(priv_dev);  } -void cdns3_gadget_exit(struct cdns3 *cdns) +static void cdns3_gadget_exit(struct cdns3 *cdns)  {  	struct cdns3_device *priv_dev; diff --git a/drivers/usb/cdns3/host-export.h b/drivers/usb/cdns3/host-export.h index ae11810f8826..26041718a086 100644 --- a/drivers/usb/cdns3/host-export.h +++ b/drivers/usb/cdns3/host-export.h @@ -9,9 +9,11 @@  #ifndef __LINUX_CDNS3_HOST_EXPORT  #define __LINUX_CDNS3_HOST_EXPORT +struct usb_hcd;  #ifdef CONFIG_USB_CDNS3_HOST  int cdns3_host_init(struct cdns3 *cdns); +int xhci_cdns3_suspend_quirk(struct usb_hcd *hcd);  #else @@ -21,6 +23,10 @@ static inline int cdns3_host_init(struct cdns3 *cdns)  }  static inline void cdns3_host_exit(struct cdns3 *cdns) { } +static inline int xhci_cdns3_suspend_quirk(struct usb_hcd *hcd) +{ +	return 0; +}  #endif /* CONFIG_USB_CDNS3_HOST */ diff --git a/drivers/usb/cdns3/host.c b/drivers/usb/cdns3/host.c index b3e2cb69762c..ec89f2e5430f 100644 --- a/drivers/usb/cdns3/host.c +++ b/drivers/usb/cdns3/host.c @@ -14,6 +14,19 @@  #include "drd.h"  #include "host-export.h"  #include <linux/usb/hcd.h> +#include "../host/xhci.h" +#include "../host/xhci-plat.h" + +#define XECP_PORT_CAP_REG	0x8000 +#define XECP_AUX_CTRL_REG1	0x8120 + +#define CFG_RXDET_P3_EN		BIT(15) +#define LPM_2_STB_SWITCH_EN	BIT(25) + +static const struct xhci_plat_priv xhci_plat_cdns3_xhci = { +	.quirks = XHCI_SKIP_PHY_INIT | XHCI_AVOID_BEI, +	.suspend_quirk = xhci_cdns3_suspend_quirk, +};  static int __cdns3_host_init(struct cdns3 *cdns)  { @@ -39,10 +52,25 @@ static int __cdns3_host_init(struct cdns3 *cdns)  		goto err1;  	} +	cdns->xhci_plat_data = kmemdup(&xhci_plat_cdns3_xhci, +			sizeof(struct xhci_plat_priv), GFP_KERNEL); +	if (!cdns->xhci_plat_data) { +		ret = -ENOMEM; +		goto err1; +	} + +	if (cdns->pdata && (cdns->pdata->quirks & CDNS3_DEFAULT_PM_RUNTIME_ALLOW)) +		cdns->xhci_plat_data->quirks |= XHCI_DEFAULT_PM_RUNTIME_ALLOW; + +	ret = platform_device_add_data(xhci, cdns->xhci_plat_data, +			sizeof(struct xhci_plat_priv)); +	if (ret) +		goto free_memory; +  	ret = platform_device_add(xhci);  	if (ret) {  		dev_err(cdns->dev, "failed to register xHCI device\n"); -		goto err1; +		goto free_memory;  	}  	/* Glue needs to access xHCI region register for Power management */ @@ -51,13 +79,43 @@ static int __cdns3_host_init(struct cdns3 *cdns)  		cdns->xhci_regs = hcd->regs;  	return 0; + +free_memory: +	kfree(cdns->xhci_plat_data);  err1:  	platform_device_put(xhci);  	return ret;  } +int xhci_cdns3_suspend_quirk(struct usb_hcd *hcd) +{ +	struct xhci_hcd	*xhci = hcd_to_xhci(hcd); +	u32 value; + +	if (pm_runtime_status_suspended(hcd->self.controller)) +		return 0; + +	/* set usbcmd.EU3S */ +	value = readl(&xhci->op_regs->command); +	value |= CMD_PM_INDEX; +	writel(value, &xhci->op_regs->command); + +	if (hcd->regs) { +		value = readl(hcd->regs + XECP_AUX_CTRL_REG1); +		value |= CFG_RXDET_P3_EN; +		writel(value, hcd->regs + XECP_AUX_CTRL_REG1); + +		value = readl(hcd->regs + XECP_PORT_CAP_REG); +		value |= LPM_2_STB_SWITCH_EN; +		writel(value, hcd->regs + XECP_PORT_CAP_REG); +	} + +	return 0; +} +  static void cdns3_host_exit(struct cdns3 *cdns)  { +	kfree(cdns->xhci_plat_data);  	platform_device_unregister(cdns->host_dev);  	cdns->host_dev = NULL;  	cdns3_drd_host_off(cdns); | 
