diff options
Diffstat (limited to 'drivers/usb/dwc3')
| -rw-r--r-- | drivers/usb/dwc3/Kconfig | 12 | ||||
| -rw-r--r-- | drivers/usb/dwc3/Makefile | 1 | ||||
| -rw-r--r-- | drivers/usb/dwc3/core.c | 453 | ||||
| -rw-r--r-- | drivers/usb/dwc3/core.h | 105 | ||||
| -rw-r--r-- | drivers/usb/dwc3/dwc3-exynos.c | 77 | ||||
| -rw-r--r-- | drivers/usb/dwc3/dwc3-keystone.c | 202 | ||||
| -rw-r--r-- | drivers/usb/dwc3/dwc3-omap.c | 39 | ||||
| -rw-r--r-- | drivers/usb/dwc3/dwc3-pci.c | 26 | ||||
| -rw-r--r-- | drivers/usb/dwc3/ep0.c | 8 | ||||
| -rw-r--r-- | drivers/usb/dwc3/gadget.c | 297 | ||||
| -rw-r--r-- | drivers/usb/dwc3/gadget.h | 12 | 
11 files changed, 962 insertions, 270 deletions
diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig index 70fc43027a5..261c3b42822 100644 --- a/drivers/usb/dwc3/Kconfig +++ b/drivers/usb/dwc3/Kconfig @@ -44,7 +44,8 @@ comment "Platform Glue Driver Support"  config USB_DWC3_OMAP  	tristate "Texas Instruments OMAP5 and similar Platforms" -	depends on EXTCON +	depends on EXTCON && (ARCH_OMAP2PLUS || COMPILE_TEST) +	depends on OF  	default USB_DWC3  	help  	  Some platforms from Texas Instruments like OMAP5, DRA7xxx and @@ -54,6 +55,7 @@ config USB_DWC3_OMAP  config USB_DWC3_EXYNOS  	tristate "Samsung Exynos Platform" +	depends on ARCH_EXYNOS || COMPILE_TEST  	default USB_DWC3  	help  	  Recent Exynos5 SoCs ship with one DesignWare Core USB3 IP inside, @@ -70,6 +72,14 @@ config USB_DWC3_PCI  	  One such PCIe-based platform is Synopsys' PCIe HAPS model of  	  this IP. +config USB_DWC3_KEYSTONE +	tristate "Texas Instruments Keystone2 Platforms" +	depends on ARCH_KEYSTONE || COMPILE_TEST +	default USB_DWC3 +	help +	  Support of USB2/3 functionality in TI Keystone2 platforms. +	  Say 'Y' or 'M' here if you have one such device +  comment "Debugging features"  config USB_DWC3_DEBUG diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile index dd1760145c4..10ac3e72482 100644 --- a/drivers/usb/dwc3/Makefile +++ b/drivers/usb/dwc3/Makefile @@ -32,3 +32,4 @@ endif  obj-$(CONFIG_USB_DWC3_OMAP)		+= dwc3-omap.o  obj-$(CONFIG_USB_DWC3_EXYNOS)		+= dwc3-exynos.o  obj-$(CONFIG_USB_DWC3_PCI)		+= dwc3-pci.o +obj-$(CONFIG_USB_DWC3_KEYSTONE)		+= dwc3-keystone.o diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 474162e9d01..eb69eb9f06c 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -61,9 +61,10 @@ void dwc3_set_mode(struct dwc3 *dwc, u32 mode)   * dwc3_core_soft_reset - Issues core soft reset and PHY reset   * @dwc: pointer to our context structure   */ -static void dwc3_core_soft_reset(struct dwc3 *dwc) +static int dwc3_core_soft_reset(struct dwc3 *dwc)  {  	u32		reg; +	int		ret;  	/* Before Resetting PHY, put Core in Reset */  	reg = dwc3_readl(dwc->regs, DWC3_GCTL); @@ -82,6 +83,15 @@ static void dwc3_core_soft_reset(struct dwc3 *dwc)  	usb_phy_init(dwc->usb2_phy);  	usb_phy_init(dwc->usb3_phy); +	ret = phy_init(dwc->usb2_generic_phy); +	if (ret < 0) +		return ret; + +	ret = phy_init(dwc->usb3_generic_phy); +	if (ret < 0) { +		phy_exit(dwc->usb2_generic_phy); +		return ret; +	}  	mdelay(100);  	/* Clear USB3 PHY reset */ @@ -100,6 +110,8 @@ static void dwc3_core_soft_reset(struct dwc3 *dwc)  	reg = dwc3_readl(dwc->regs, DWC3_GCTL);  	reg &= ~DWC3_GCTL_CORESOFTRESET;  	dwc3_writel(dwc->regs, DWC3_GCTL, reg); + +	return 0;  }  /** @@ -242,6 +254,90 @@ static void dwc3_event_buffers_cleanup(struct dwc3 *dwc)  	}  } +static int dwc3_alloc_scratch_buffers(struct dwc3 *dwc) +{ +	if (!dwc->has_hibernation) +		return 0; + +	if (!dwc->nr_scratch) +		return 0; + +	dwc->scratchbuf = kmalloc_array(dwc->nr_scratch, +			DWC3_SCRATCHBUF_SIZE, GFP_KERNEL); +	if (!dwc->scratchbuf) +		return -ENOMEM; + +	return 0; +} + +static int dwc3_setup_scratch_buffers(struct dwc3 *dwc) +{ +	dma_addr_t scratch_addr; +	u32 param; +	int ret; + +	if (!dwc->has_hibernation) +		return 0; + +	if (!dwc->nr_scratch) +		return 0; + +	 /* should never fall here */ +	if (!WARN_ON(dwc->scratchbuf)) +		return 0; + +	scratch_addr = dma_map_single(dwc->dev, dwc->scratchbuf, +			dwc->nr_scratch * DWC3_SCRATCHBUF_SIZE, +			DMA_BIDIRECTIONAL); +	if (dma_mapping_error(dwc->dev, scratch_addr)) { +		dev_err(dwc->dev, "failed to map scratch buffer\n"); +		ret = -EFAULT; +		goto err0; +	} + +	dwc->scratch_addr = scratch_addr; + +	param = lower_32_bits(scratch_addr); + +	ret = dwc3_send_gadget_generic_command(dwc, +			DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO, param); +	if (ret < 0) +		goto err1; + +	param = upper_32_bits(scratch_addr); + +	ret = dwc3_send_gadget_generic_command(dwc, +			DWC3_DGCMD_SET_SCRATCHPAD_ADDR_HI, param); +	if (ret < 0) +		goto err1; + +	return 0; + +err1: +	dma_unmap_single(dwc->dev, dwc->scratch_addr, dwc->nr_scratch * +			DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL); + +err0: +	return ret; +} + +static void dwc3_free_scratch_buffers(struct dwc3 *dwc) +{ +	if (!dwc->has_hibernation) +		return; + +	if (!dwc->nr_scratch) +		return; + +	 /* should never fall here */ +	if (!WARN_ON(dwc->scratchbuf)) +		return; + +	dma_unmap_single(dwc->dev, dwc->scratch_addr, dwc->nr_scratch * +			DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL); +	kfree(dwc->scratchbuf); +} +  static void dwc3_core_num_eps(struct dwc3 *dwc)  {  	struct dwc3_hwparams	*parms = &dwc->hwparams; @@ -277,6 +373,7 @@ static void dwc3_cache_hwparams(struct dwc3 *dwc)  static int dwc3_core_init(struct dwc3 *dwc)  {  	unsigned long		timeout; +	u32			hwparams4 = dwc->hwparams.hwparams4;  	u32			reg;  	int			ret; @@ -306,7 +403,9 @@ static int dwc3_core_init(struct dwc3 *dwc)  		cpu_relax();  	} while (true); -	dwc3_core_soft_reset(dwc); +	ret = dwc3_core_soft_reset(dwc); +	if (ret) +		goto err0;  	reg = dwc3_readl(dwc->regs, DWC3_GCTL);  	reg &= ~DWC3_GCTL_SCALEDOWN_MASK; @@ -314,7 +413,29 @@ static int dwc3_core_init(struct dwc3 *dwc)  	switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)) {  	case DWC3_GHWPARAMS1_EN_PWROPT_CLK: -		reg &= ~DWC3_GCTL_DSBLCLKGTNG; +		/** +		 * WORKAROUND: DWC3 revisions between 2.10a and 2.50a have an +		 * issue which would cause xHCI compliance tests to fail. +		 * +		 * Because of that we cannot enable clock gating on such +		 * configurations. +		 * +		 * Refers to: +		 * +		 * STAR#9000588375: Clock Gating, SOF Issues when ref_clk-Based +		 * SOF/ITP Mode Used +		 */ +		if ((dwc->dr_mode == USB_DR_MODE_HOST || +				dwc->dr_mode == USB_DR_MODE_OTG) && +				(dwc->revision >= DWC3_REVISION_210A && +				dwc->revision <= DWC3_REVISION_250A)) +			reg |= DWC3_GCTL_DSBLCLKGTNG | DWC3_GCTL_SOFITPSYNC; +		else +			reg &= ~DWC3_GCTL_DSBLCLKGTNG; +		break; +	case DWC3_GHWPARAMS1_EN_PWROPT_HIB: +		/* enable hibernation here */ +		dwc->nr_scratch = DWC3_GHWPARAMS4_HIBER_SCRATCHBUFS(hwparams4);  		break;  	default:  		dev_dbg(dwc->dev, "No power optimization available\n"); @@ -333,16 +454,166 @@ static int dwc3_core_init(struct dwc3 *dwc)  	dwc3_writel(dwc->regs, DWC3_GCTL, reg); +	ret = dwc3_alloc_scratch_buffers(dwc); +	if (ret) +		goto err1; + +	ret = dwc3_setup_scratch_buffers(dwc); +	if (ret) +		goto err2; +  	return 0; +err2: +	dwc3_free_scratch_buffers(dwc); + +err1: +	usb_phy_shutdown(dwc->usb2_phy); +	usb_phy_shutdown(dwc->usb3_phy); +	phy_exit(dwc->usb2_generic_phy); +	phy_exit(dwc->usb3_generic_phy); +  err0:  	return ret;  }  static void dwc3_core_exit(struct dwc3 *dwc)  { +	dwc3_free_scratch_buffers(dwc);  	usb_phy_shutdown(dwc->usb2_phy);  	usb_phy_shutdown(dwc->usb3_phy); +	phy_exit(dwc->usb2_generic_phy); +	phy_exit(dwc->usb3_generic_phy); +} + +static int dwc3_core_get_phy(struct dwc3 *dwc) +{ +	struct device		*dev = dwc->dev; +	struct device_node	*node = dev->of_node; +	int ret; + +	if (node) { +		dwc->usb2_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0); +		dwc->usb3_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 1); +	} else { +		dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); +		dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3); +	} + +	if (IS_ERR(dwc->usb2_phy)) { +		ret = PTR_ERR(dwc->usb2_phy); +		if (ret == -ENXIO || ret == -ENODEV) { +			dwc->usb2_phy = NULL; +		} else if (ret == -EPROBE_DEFER) { +			return ret; +		} else { +			dev_err(dev, "no usb2 phy configured\n"); +			return ret; +		} +	} + +	if (IS_ERR(dwc->usb3_phy)) { +		ret = PTR_ERR(dwc->usb3_phy); +		if (ret == -ENXIO || ret == -ENODEV) { +			dwc->usb3_phy = NULL; +		} else if (ret == -EPROBE_DEFER) { +			return ret; +		} else { +			dev_err(dev, "no usb3 phy configured\n"); +			return ret; +		} +	} + +	dwc->usb2_generic_phy = devm_phy_get(dev, "usb2-phy"); +	if (IS_ERR(dwc->usb2_generic_phy)) { +		ret = PTR_ERR(dwc->usb2_generic_phy); +		if (ret == -ENOSYS || ret == -ENODEV) { +			dwc->usb2_generic_phy = NULL; +		} else if (ret == -EPROBE_DEFER) { +			return ret; +		} else { +			dev_err(dev, "no usb2 phy configured\n"); +			return ret; +		} +	} + +	dwc->usb3_generic_phy = devm_phy_get(dev, "usb3-phy"); +	if (IS_ERR(dwc->usb3_generic_phy)) { +		ret = PTR_ERR(dwc->usb3_generic_phy); +		if (ret == -ENOSYS || ret == -ENODEV) { +			dwc->usb3_generic_phy = NULL; +		} else if (ret == -EPROBE_DEFER) { +			return ret; +		} else { +			dev_err(dev, "no usb3 phy configured\n"); +			return ret; +		} +	} + +	return 0; +} + +static int dwc3_core_init_mode(struct dwc3 *dwc) +{ +	struct device *dev = dwc->dev; +	int ret; + +	switch (dwc->dr_mode) { +	case USB_DR_MODE_PERIPHERAL: +		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); +		ret = dwc3_gadget_init(dwc); +		if (ret) { +			dev_err(dev, "failed to initialize gadget\n"); +			return ret; +		} +		break; +	case USB_DR_MODE_HOST: +		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST); +		ret = dwc3_host_init(dwc); +		if (ret) { +			dev_err(dev, "failed to initialize host\n"); +			return ret; +		} +		break; +	case USB_DR_MODE_OTG: +		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG); +		ret = dwc3_host_init(dwc); +		if (ret) { +			dev_err(dev, "failed to initialize host\n"); +			return ret; +		} + +		ret = dwc3_gadget_init(dwc); +		if (ret) { +			dev_err(dev, "failed to initialize gadget\n"); +			return ret; +		} +		break; +	default: +		dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode); +		return -EINVAL; +	} + +	return 0; +} + +static void dwc3_core_exit_mode(struct dwc3 *dwc) +{ +	switch (dwc->dr_mode) { +	case USB_DR_MODE_PERIPHERAL: +		dwc3_gadget_exit(dwc); +		break; +	case USB_DR_MODE_HOST: +		dwc3_host_exit(dwc); +		break; +	case USB_DR_MODE_OTG: +		dwc3_host_exit(dwc); +		dwc3_gadget_exit(dwc); +		break; +	default: +		/* do nothing */ +		break; +	}  }  #define DWC3_ALIGN_MASK		(16 - 1) @@ -355,7 +626,7 @@ static int dwc3_probe(struct platform_device *pdev)  	struct resource		*res;  	struct dwc3		*dwc; -	int			ret = -ENOMEM; +	int			ret;  	void __iomem		*regs;  	void			*mem; @@ -367,6 +638,7 @@ static int dwc3_probe(struct platform_device *pdev)  	}  	dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1);  	dwc->mem = mem; +	dwc->dev = dev;  	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);  	if (!res) { @@ -387,57 +659,22 @@ static int dwc3_probe(struct platform_device *pdev)  	if (node) {  		dwc->maximum_speed = of_usb_get_maximum_speed(node); -		dwc->usb2_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0); -		dwc->usb3_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 1); -  		dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize");  		dwc->dr_mode = of_usb_get_dr_mode(node);  	} else if (pdata) {  		dwc->maximum_speed = pdata->maximum_speed; -		dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); -		dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3); -  		dwc->needs_fifo_resize = pdata->tx_fifo_resize;  		dwc->dr_mode = pdata->dr_mode; -	} else { -		dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); -		dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3);  	}  	/* default to superspeed if no maximum_speed passed */  	if (dwc->maximum_speed == USB_SPEED_UNKNOWN)  		dwc->maximum_speed = USB_SPEED_SUPER; -	if (IS_ERR(dwc->usb2_phy)) { -		ret = PTR_ERR(dwc->usb2_phy); - -		/* -		 * if -ENXIO is returned, it means PHY layer wasn't -		 * enabled, so it makes no sense to return -EPROBE_DEFER -		 * in that case, since no PHY driver will ever probe. -		 */ -		if (ret == -ENXIO) -			return ret; - -		dev_err(dev, "no usb2 phy configured\n"); -		return -EPROBE_DEFER; -	} - -	if (IS_ERR(dwc->usb3_phy)) { -		ret = PTR_ERR(dwc->usb3_phy); - -		/* -		 * if -ENXIO is returned, it means PHY layer wasn't -		 * enabled, so it makes no sense to return -EPROBE_DEFER -		 * in that case, since no PHY driver will ever probe. -		 */ -		if (ret == -ENXIO) -			return ret; - -		dev_err(dev, "no usb3 phy configured\n"); -		return -EPROBE_DEFER; -	} +	ret = dwc3_core_get_phy(dwc); +	if (ret) +		return ret;  	dwc->xhci_resources[0].start = res->start;  	dwc->xhci_resources[0].end = dwc->xhci_resources[0].start + @@ -455,15 +692,11 @@ static int dwc3_probe(struct platform_device *pdev)  	if (IS_ERR(regs))  		return PTR_ERR(regs); -	usb_phy_set_suspend(dwc->usb2_phy, 0); -	usb_phy_set_suspend(dwc->usb3_phy, 0); -  	spin_lock_init(&dwc->lock);  	platform_set_drvdata(pdev, dwc);  	dwc->regs	= regs;  	dwc->regs_size	= resource_size(res); -	dwc->dev	= dev;  	dev->dma_mask	= dev->parent->dma_mask;  	dev->dma_parms	= dev->parent->dma_parms; @@ -482,61 +715,39 @@ static int dwc3_probe(struct platform_device *pdev)  		goto err0;  	} +	if (IS_ENABLED(CONFIG_USB_DWC3_HOST)) +		dwc->dr_mode = USB_DR_MODE_HOST; +	else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET)) +		dwc->dr_mode = USB_DR_MODE_PERIPHERAL; + +	if (dwc->dr_mode == USB_DR_MODE_UNKNOWN) +		dwc->dr_mode = USB_DR_MODE_OTG; +  	ret = dwc3_core_init(dwc);  	if (ret) {  		dev_err(dev, "failed to initialize core\n");  		goto err0;  	} +	usb_phy_set_suspend(dwc->usb2_phy, 0); +	usb_phy_set_suspend(dwc->usb3_phy, 0); +	ret = phy_power_on(dwc->usb2_generic_phy); +	if (ret < 0) +		goto err1; + +	ret = phy_power_on(dwc->usb3_generic_phy); +	if (ret < 0) +		goto err_usb2phy_power; +  	ret = dwc3_event_buffers_setup(dwc);  	if (ret) {  		dev_err(dwc->dev, "failed to setup event buffers\n"); -		goto err1; +		goto err_usb3phy_power;  	} -	if (IS_ENABLED(CONFIG_USB_DWC3_HOST)) -		dwc->dr_mode = USB_DR_MODE_HOST; -	else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET)) -		dwc->dr_mode = USB_DR_MODE_PERIPHERAL; - -	if (dwc->dr_mode == USB_DR_MODE_UNKNOWN) -		dwc->dr_mode = USB_DR_MODE_OTG; - -	switch (dwc->dr_mode) { -	case USB_DR_MODE_PERIPHERAL: -		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); -		ret = dwc3_gadget_init(dwc); -		if (ret) { -			dev_err(dev, "failed to initialize gadget\n"); -			goto err2; -		} -		break; -	case USB_DR_MODE_HOST: -		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST); -		ret = dwc3_host_init(dwc); -		if (ret) { -			dev_err(dev, "failed to initialize host\n"); -			goto err2; -		} -		break; -	case USB_DR_MODE_OTG: -		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG); -		ret = dwc3_host_init(dwc); -		if (ret) { -			dev_err(dev, "failed to initialize host\n"); -			goto err2; -		} - -		ret = dwc3_gadget_init(dwc); -		if (ret) { -			dev_err(dev, "failed to initialize gadget\n"); -			goto err2; -		} -		break; -	default: -		dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode); +	ret = dwc3_core_init_mode(dwc); +	if (ret)  		goto err2; -	}  	ret = dwc3_debugfs_init(dwc);  	if (ret) { @@ -549,26 +760,20 @@ static int dwc3_probe(struct platform_device *pdev)  	return 0;  err3: -	switch (dwc->dr_mode) { -	case USB_DR_MODE_PERIPHERAL: -		dwc3_gadget_exit(dwc); -		break; -	case USB_DR_MODE_HOST: -		dwc3_host_exit(dwc); -		break; -	case USB_DR_MODE_OTG: -		dwc3_host_exit(dwc); -		dwc3_gadget_exit(dwc); -		break; -	default: -		/* do nothing */ -		break; -	} +	dwc3_core_exit_mode(dwc);  err2:  	dwc3_event_buffers_cleanup(dwc); +err_usb3phy_power: +	phy_power_off(dwc->usb3_generic_phy); + +err_usb2phy_power: +	phy_power_off(dwc->usb2_generic_phy); +  err1: +	usb_phy_set_suspend(dwc->usb2_phy, 1); +	usb_phy_set_suspend(dwc->usb3_phy, 1);  	dwc3_core_exit(dwc);  err0: @@ -583,28 +788,14 @@ static int dwc3_remove(struct platform_device *pdev)  	usb_phy_set_suspend(dwc->usb2_phy, 1);  	usb_phy_set_suspend(dwc->usb3_phy, 1); +	phy_power_off(dwc->usb2_generic_phy); +	phy_power_off(dwc->usb3_generic_phy); -	pm_runtime_put(&pdev->dev); +	pm_runtime_put_sync(&pdev->dev);  	pm_runtime_disable(&pdev->dev);  	dwc3_debugfs_exit(dwc); - -	switch (dwc->dr_mode) { -	case USB_DR_MODE_PERIPHERAL: -		dwc3_gadget_exit(dwc); -		break; -	case USB_DR_MODE_HOST: -		dwc3_host_exit(dwc); -		break; -	case USB_DR_MODE_OTG: -		dwc3_host_exit(dwc); -		dwc3_gadget_exit(dwc); -		break; -	default: -		/* do nothing */ -		break; -	} - +	dwc3_core_exit_mode(dwc);  	dwc3_event_buffers_cleanup(dwc);  	dwc3_free_event_buffers(dwc);  	dwc3_core_exit(dwc); @@ -643,6 +834,7 @@ static void dwc3_complete(struct device *dev)  	spin_lock_irqsave(&dwc->lock, flags); +	dwc3_event_buffers_setup(dwc);  	switch (dwc->dr_mode) {  	case USB_DR_MODE_PERIPHERAL:  	case USB_DR_MODE_OTG: @@ -650,7 +842,6 @@ static void dwc3_complete(struct device *dev)  		/* FALLTHROUGH */  	case USB_DR_MODE_HOST:  	default: -		dwc3_event_buffers_setup(dwc);  		break;  	} @@ -680,6 +871,8 @@ static int dwc3_suspend(struct device *dev)  	usb_phy_shutdown(dwc->usb3_phy);  	usb_phy_shutdown(dwc->usb2_phy); +	phy_exit(dwc->usb2_generic_phy); +	phy_exit(dwc->usb3_generic_phy);  	return 0;  } @@ -688,10 +881,17 @@ static int dwc3_resume(struct device *dev)  {  	struct dwc3	*dwc = dev_get_drvdata(dev);  	unsigned long	flags; +	int		ret;  	usb_phy_init(dwc->usb3_phy);  	usb_phy_init(dwc->usb2_phy); -	msleep(100); +	ret = phy_init(dwc->usb2_generic_phy); +	if (ret < 0) +		return ret; + +	ret = phy_init(dwc->usb3_generic_phy); +	if (ret < 0) +		goto err_usb2phy_init;  	spin_lock_irqsave(&dwc->lock, flags); @@ -715,6 +915,11 @@ static int dwc3_resume(struct device *dev)  	pm_runtime_enable(dev);  	return 0; + +err_usb2phy_init: +	phy_exit(dwc->usb2_generic_phy); + +	return ret;  }  static const struct dev_pm_ops dwc3_dev_pm_ops = { diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index f8af8d44af8..57332e3768e 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -31,11 +31,14 @@  #include <linux/usb/gadget.h>  #include <linux/usb/otg.h> +#include <linux/phy/phy.h> +  /* Global constants */  #define DWC3_EP0_BOUNCE_SIZE	512  #define DWC3_ENDPOINTS_NUM	32  #define DWC3_XHCI_RESOURCES_NUM	2 +#define DWC3_SCRATCHBUF_SIZE	4096	/* each buffer is assumed to be 4KiB */  #define DWC3_EVENT_SIZE		4	/* bytes */  #define DWC3_EVENT_MAX_NUM	64	/* 2 events/endpoint */  #define DWC3_EVENT_BUFFERS_SIZE	(DWC3_EVENT_SIZE * DWC3_EVENT_MAX_NUM) @@ -157,6 +160,7 @@  #define DWC3_GCTL_PRTCAP_OTG	3  #define DWC3_GCTL_CORESOFTRESET		(1 << 11) +#define DWC3_GCTL_SOFITPSYNC		(1 << 10)  #define DWC3_GCTL_SCALEDOWN(n)		((n) << 4)  #define DWC3_GCTL_SCALEDOWN_MASK	DWC3_GCTL_SCALEDOWN(3)  #define DWC3_GCTL_DISSCRAMBLE		(1 << 3) @@ -318,7 +322,7 @@  /* Device Endpoint Command Register */  #define DWC3_DEPCMD_PARAM_SHIFT		16  #define DWC3_DEPCMD_PARAM(x)		((x) << DWC3_DEPCMD_PARAM_SHIFT) -#define DWC3_DEPCMD_GET_RSC_IDX(x)     (((x) >> DWC3_DEPCMD_PARAM_SHIFT) & 0x7f) +#define DWC3_DEPCMD_GET_RSC_IDX(x)	(((x) >> DWC3_DEPCMD_PARAM_SHIFT) & 0x7f)  #define DWC3_DEPCMD_STATUS(x)		(((x) >> 15) & 1)  #define DWC3_DEPCMD_HIPRI_FORCERM	(1 << 11)  #define DWC3_DEPCMD_CMDACT		(1 << 10) @@ -393,6 +397,7 @@ struct dwc3_event_buffer {   * @busy_slot: first slot which is owned by HW   * @desc: usb_endpoint_descriptor pointer   * @dwc: pointer to DWC controller + * @saved_state: ep state saved during hibernation   * @flags: endpoint flags (wedged, stalled, ...)   * @current_trb: index of current used trb   * @number: endpoint number (1 - 15) @@ -415,6 +420,7 @@ struct dwc3_ep {  	const struct usb_ss_ep_comp_descriptor *comp_desc;  	struct dwc3		*dwc; +	u32			saved_state;  	unsigned		flags;  #define DWC3_EP_ENABLED		(1 << 0)  #define DWC3_EP_STALL		(1 << 1) @@ -598,6 +604,7 @@ struct dwc3_scratchpad_array {   * @ep0_trb: dma address of ep0_trb   * @ep0_usb_req: dummy req used while handling STD USB requests   * @ep0_bounce_addr: dma address of ep0_bounce + * @scratch_addr: dma address of scratchbuf   * @lock: for synchronizing   * @dev: pointer to our struct device   * @xhci: pointer to our xHCI child @@ -606,6 +613,7 @@ struct dwc3_scratchpad_array {   * @gadget_driver: pointer to the gadget driver   * @regs: base address for our registers   * @regs_size: address space size + * @nr_scratch: number of scratch buffers   * @num_event_buffers: calculated number of event buffers   * @u1u2: only used on revisions <1.83a for workaround   * @maximum_speed: maximum speed requested (mainly for testing purposes) @@ -613,16 +621,10 @@ struct dwc3_scratchpad_array {   * @dr_mode: requested mode of operation   * @usb2_phy: pointer to USB2 PHY   * @usb3_phy: pointer to USB3 PHY + * @usb2_generic_phy: pointer to USB2 PHY + * @usb3_generic_phy: pointer to USB3 PHY   * @dcfg: saved contents of DCFG register   * @gctl: saved contents of GCTL register - * @is_selfpowered: true when we are selfpowered - * @three_stage_setup: set if we perform a three phase setup - * @ep0_bounced: true when we used bounce buffer - * @ep0_expect_in: true when we expect a DATA IN transfer - * @start_config_issued: true when StartConfig command has been issued - * @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround - * @needs_fifo_resize: not all users might want fifo resizing, flag it - * @resize_fifos: tells us it's ok to reconfigure our TxFIFO sizes.   * @isoch_delay: wValue from Set Isochronous Delay request;   * @u2sel: parameter from Set SEL request.   * @u2pel: parameter from Set SEL request. @@ -637,15 +639,31 @@ struct dwc3_scratchpad_array {   * @mem: points to start of memory which is used for this struct.   * @hwparams: copy of hwparams registers   * @root: debugfs root folder pointer + * @regset: debugfs pointer to regdump file + * @test_mode: true when we're entering a USB test mode + * @test_mode_nr: test feature selector + * @delayed_status: true when gadget driver asks for delayed status + * @ep0_bounced: true when we used bounce buffer + * @ep0_expect_in: true when we expect a DATA IN transfer + * @has_hibernation: true when dwc3 was configured with Hibernation + * @is_selfpowered: true when we are selfpowered + * @needs_fifo_resize: not all users might want fifo resizing, flag it + * @pullups_connected: true when Run/Stop bit is set + * @resize_fifos: tells us it's ok to reconfigure our TxFIFO sizes. + * @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround + * @start_config_issued: true when StartConfig command has been issued + * @three_stage_setup: set if we perform a three phase setup   */  struct dwc3 {  	struct usb_ctrlrequest	*ctrl_req;  	struct dwc3_trb		*ep0_trb;  	void			*ep0_bounce; +	void			*scratchbuf;  	u8			*setup_buf;  	dma_addr_t		ctrl_req_addr;  	dma_addr_t		ep0_trb_addr;  	dma_addr_t		ep0_bounce_addr; +	dma_addr_t		scratch_addr;  	struct dwc3_request	ep0_usb_req;  	/* device lock */ @@ -665,6 +683,9 @@ struct dwc3 {  	struct usb_phy		*usb2_phy;  	struct usb_phy		*usb3_phy; +	struct phy		*usb2_generic_phy; +	struct phy		*usb3_generic_phy; +  	void __iomem		*regs;  	size_t			regs_size; @@ -674,6 +695,7 @@ struct dwc3 {  	u32			dcfg;  	u32			gctl; +	u32			nr_scratch;  	u32			num_event_buffers;  	u32			u1u2;  	u32			maximum_speed; @@ -695,17 +717,9 @@ struct dwc3 {  #define DWC3_REVISION_230A	0x5533230a  #define DWC3_REVISION_240A	0x5533240a  #define DWC3_REVISION_250A	0x5533250a - -	unsigned		is_selfpowered:1; -	unsigned		three_stage_setup:1; -	unsigned		ep0_bounced:1; -	unsigned		ep0_expect_in:1; -	unsigned		start_config_issued:1; -	unsigned		setup_packet_pending:1; -	unsigned		delayed_status:1; -	unsigned		needs_fifo_resize:1; -	unsigned		resize_fifos:1; -	unsigned		pullups_connected:1; +#define DWC3_REVISION_260A	0x5533260a +#define DWC3_REVISION_270A	0x5533270a +#define DWC3_REVISION_280A	0x5533280a  	enum dwc3_ep0_next	ep0_next_event;  	enum dwc3_ep0_state	ep0state; @@ -730,6 +744,18 @@ struct dwc3 {  	u8			test_mode;  	u8			test_mode_nr; + +	unsigned		delayed_status:1; +	unsigned		ep0_bounced:1; +	unsigned		ep0_expect_in:1; +	unsigned		has_hibernation:1; +	unsigned		is_selfpowered:1; +	unsigned		needs_fifo_resize:1; +	unsigned		pullups_connected:1; +	unsigned		resize_fifos:1; +	unsigned		setup_packet_pending:1; +	unsigned		start_config_issued:1; +	unsigned		three_stage_setup:1;  };  /* -------------------------------------------------------------------------- */ @@ -815,15 +841,15 @@ struct dwc3_event_depevt {   *	12	- VndrDevTstRcved   * @reserved15_12: Reserved, not used   * @event_info: Information about this event - * @reserved31_24: Reserved, not used + * @reserved31_25: Reserved, not used   */  struct dwc3_event_devt {  	u32	one_bit:1;  	u32	device_event:7;  	u32	type:4;  	u32	reserved15_12:4; -	u32	event_info:8; -	u32	reserved31_24:8; +	u32	event_info:9; +	u32	reserved31_25:7;  } __packed;  /** @@ -856,6 +882,19 @@ union dwc3_event {  	struct dwc3_event_gevt		gevt;  }; +/** + * struct dwc3_gadget_ep_cmd_params - representation of endpoint command + * parameters + * @param2: third parameter + * @param1: second parameter + * @param0: first parameter + */ +struct dwc3_gadget_ep_cmd_params { +	u32	param2; +	u32	param1; +	u32	param0; +}; +  /*   * DWC3 Features to be used as Driver Data   */ @@ -881,11 +920,31 @@ static inline void dwc3_host_exit(struct dwc3 *dwc)  #if IS_ENABLED(CONFIG_USB_DWC3_GADGET) || IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)  int dwc3_gadget_init(struct dwc3 *dwc);  void dwc3_gadget_exit(struct dwc3 *dwc); +int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode); +int dwc3_gadget_get_link_state(struct dwc3 *dwc); +int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state); +int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep, +		unsigned cmd, struct dwc3_gadget_ep_cmd_params *params); +int dwc3_send_gadget_generic_command(struct dwc3 *dwc, int cmd, u32 param);  #else  static inline int dwc3_gadget_init(struct dwc3 *dwc)  { return 0; }  static inline void dwc3_gadget_exit(struct dwc3 *dwc)  { } +static inline int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode) +{ return 0; } +static inline int dwc3_gadget_get_link_state(struct dwc3 *dwc) +{ return 0; } +static inline int dwc3_gadget_set_link_state(struct dwc3 *dwc, +		enum dwc3_link_state state) +{ return 0; } + +static inline int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep, +		unsigned cmd, struct dwc3_gadget_ep_cmd_params *params) +{ return 0; } +static inline int dwc3_send_gadget_generic_command(struct dwc3 *dwc, +		int cmd, u32 param) +{ return 0; }  #endif  /* power management interface */ diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c index 2f2e88a3a11..f9fb8adb785 100644 --- a/drivers/usb/dwc3/dwc3-exynos.c +++ b/drivers/usb/dwc3/dwc3-exynos.c @@ -24,9 +24,10 @@  #include <linux/dma-mapping.h>  #include <linux/clk.h>  #include <linux/usb/otg.h> -#include <linux/usb/usb_phy_gen_xceiv.h> +#include <linux/usb/usb_phy_generic.h>  #include <linux/of.h>  #include <linux/of_platform.h> +#include <linux/regulator/consumer.h>  struct dwc3_exynos {  	struct platform_device	*usb2_phy; @@ -34,28 +35,31 @@ struct dwc3_exynos {  	struct device		*dev;  	struct clk		*clk; +	struct regulator	*vdd33; +	struct regulator	*vdd10;  };  static int dwc3_exynos_register_phys(struct dwc3_exynos *exynos)  { -	struct usb_phy_gen_xceiv_platform_data pdata; +	struct usb_phy_generic_platform_data pdata;  	struct platform_device	*pdev;  	int			ret;  	memset(&pdata, 0x00, sizeof(pdata)); -	pdev = platform_device_alloc("usb_phy_gen_xceiv", PLATFORM_DEVID_AUTO); +	pdev = platform_device_alloc("usb_phy_generic", PLATFORM_DEVID_AUTO);  	if (!pdev)  		return -ENOMEM;  	exynos->usb2_phy = pdev;  	pdata.type = USB_PHY_TYPE_USB2; +	pdata.gpio_reset = -1;  	ret = platform_device_add_data(exynos->usb2_phy, &pdata, sizeof(pdata));  	if (ret)  		goto err1; -	pdev = platform_device_alloc("usb_phy_gen_xceiv", PLATFORM_DEVID_AUTO); +	pdev = platform_device_alloc("usb_phy_generic", PLATFORM_DEVID_AUTO);  	if (!pdev) {  		ret = -ENOMEM;  		goto err1; @@ -106,12 +110,12 @@ static int dwc3_exynos_probe(struct platform_device *pdev)  	struct device		*dev = &pdev->dev;  	struct device_node	*node = dev->of_node; -	int			ret = -ENOMEM; +	int			ret;  	exynos = devm_kzalloc(dev, sizeof(*exynos), GFP_KERNEL);  	if (!exynos) {  		dev_err(dev, "not enough memory\n"); -		goto err1; +		return -ENOMEM;  	}  	/* @@ -119,24 +123,22 @@ static int dwc3_exynos_probe(struct platform_device *pdev)  	 * Since shared usb code relies on it, set it here for now.  	 * Once we move to full device tree support this will vanish off.  	 */ -	if (!dev->dma_mask) -		dev->dma_mask = &dev->coherent_dma_mask; -	if (!dev->coherent_dma_mask) -		dev->coherent_dma_mask = DMA_BIT_MASK(32); +	ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32)); +	if (ret) +		return ret;  	platform_set_drvdata(pdev, exynos);  	ret = dwc3_exynos_register_phys(exynos);  	if (ret) {  		dev_err(dev, "couldn't register PHYs\n"); -		goto err1; +		return ret;  	}  	clk = devm_clk_get(dev, "usbdrd30");  	if (IS_ERR(clk)) {  		dev_err(dev, "couldn't get clock\n"); -		ret = -EINVAL; -		goto err1; +		return -EINVAL;  	}  	exynos->dev	= dev; @@ -144,23 +146,48 @@ static int dwc3_exynos_probe(struct platform_device *pdev)  	clk_prepare_enable(exynos->clk); +	exynos->vdd33 = devm_regulator_get(dev, "vdd33"); +	if (IS_ERR(exynos->vdd33)) { +		ret = PTR_ERR(exynos->vdd33); +		goto err2; +	} +	ret = regulator_enable(exynos->vdd33); +	if (ret) { +		dev_err(dev, "Failed to enable VDD33 supply\n"); +		goto err2; +	} + +	exynos->vdd10 = devm_regulator_get(dev, "vdd10"); +	if (IS_ERR(exynos->vdd10)) { +		ret = PTR_ERR(exynos->vdd10); +		goto err3; +	} +	ret = regulator_enable(exynos->vdd10); +	if (ret) { +		dev_err(dev, "Failed to enable VDD10 supply\n"); +		goto err3; +	} +  	if (node) {  		ret = of_platform_populate(node, NULL, NULL, dev);  		if (ret) {  			dev_err(dev, "failed to add dwc3 core\n"); -			goto err2; +			goto err4;  		}  	} else {  		dev_err(dev, "no device node, failed to add dwc3 core\n");  		ret = -ENODEV; -		goto err2; +		goto err4;  	}  	return 0; +err4: +	regulator_disable(exynos->vdd10); +err3: +	regulator_disable(exynos->vdd33);  err2:  	clk_disable_unprepare(clk); -err1:  	return ret;  } @@ -174,6 +201,9 @@ static int dwc3_exynos_remove(struct platform_device *pdev)  	clk_disable_unprepare(exynos->clk); +	regulator_disable(exynos->vdd33); +	regulator_disable(exynos->vdd10); +  	return 0;  } @@ -192,12 +222,27 @@ static int dwc3_exynos_suspend(struct device *dev)  	clk_disable(exynos->clk); +	regulator_disable(exynos->vdd33); +	regulator_disable(exynos->vdd10); +  	return 0;  }  static int dwc3_exynos_resume(struct device *dev)  {  	struct dwc3_exynos *exynos = dev_get_drvdata(dev); +	int ret; + +	ret = regulator_enable(exynos->vdd33); +	if (ret) { +		dev_err(dev, "Failed to enable VDD33 supply\n"); +		return ret; +	} +	ret = regulator_enable(exynos->vdd10); +	if (ret) { +		dev_err(dev, "Failed to enable VDD10 supply\n"); +		return ret; +	}  	clk_enable(exynos->clk); diff --git a/drivers/usb/dwc3/dwc3-keystone.c b/drivers/usb/dwc3/dwc3-keystone.c new file mode 100644 index 00000000000..1fad1618df6 --- /dev/null +++ b/drivers/usb/dwc3/dwc3-keystone.c @@ -0,0 +1,202 @@ +/** + * dwc3-keystone.c - Keystone Specific Glue layer + * + * Copyright (C) 2010-2013 Texas Instruments Incorporated - http://www.ti.com + * + * Author: WingMan Kwok <w-kwok2@ti.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2  of + * the License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + */ + +#include <linux/clk.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/dma-mapping.h> +#include <linux/io.h> +#include <linux/of_platform.h> + +/* USBSS register offsets */ +#define USBSS_REVISION		0x0000 +#define USBSS_SYSCONFIG		0x0010 +#define USBSS_IRQ_EOI		0x0018 +#define USBSS_IRQSTATUS_RAW_0	0x0020 +#define USBSS_IRQSTATUS_0	0x0024 +#define USBSS_IRQENABLE_SET_0	0x0028 +#define USBSS_IRQENABLE_CLR_0	0x002c + +/* IRQ register bits */ +#define USBSS_IRQ_EOI_LINE(n)	BIT(n) +#define USBSS_IRQ_EVENT_ST	BIT(0) +#define USBSS_IRQ_COREIRQ_EN	BIT(0) +#define USBSS_IRQ_COREIRQ_CLR	BIT(0) + +static u64 kdwc3_dma_mask; + +struct dwc3_keystone { +	struct device			*dev; +	struct clk			*clk; +	void __iomem			*usbss; +}; + +static inline u32 kdwc3_readl(void __iomem *base, u32 offset) +{ +	return readl(base + offset); +} + +static inline void kdwc3_writel(void __iomem *base, u32 offset, u32 value) +{ +	writel(value, base + offset); +} + +static void kdwc3_enable_irqs(struct dwc3_keystone *kdwc) +{ +	u32 val; + +	val = kdwc3_readl(kdwc->usbss, USBSS_IRQENABLE_SET_0); +	val |= USBSS_IRQ_COREIRQ_EN; +	kdwc3_writel(kdwc->usbss, USBSS_IRQENABLE_SET_0, val); +} + +static void kdwc3_disable_irqs(struct dwc3_keystone *kdwc) +{ +	u32 val; + +	val = kdwc3_readl(kdwc->usbss, USBSS_IRQENABLE_SET_0); +	val &= ~USBSS_IRQ_COREIRQ_EN; +	kdwc3_writel(kdwc->usbss, USBSS_IRQENABLE_SET_0, val); +} + +static irqreturn_t dwc3_keystone_interrupt(int irq, void *_kdwc) +{ +	struct dwc3_keystone	*kdwc = _kdwc; + +	kdwc3_writel(kdwc->usbss, USBSS_IRQENABLE_CLR_0, USBSS_IRQ_COREIRQ_CLR); +	kdwc3_writel(kdwc->usbss, USBSS_IRQSTATUS_0, USBSS_IRQ_EVENT_ST); +	kdwc3_writel(kdwc->usbss, USBSS_IRQENABLE_SET_0, USBSS_IRQ_COREIRQ_EN); +	kdwc3_writel(kdwc->usbss, USBSS_IRQ_EOI, USBSS_IRQ_EOI_LINE(0)); + +	return IRQ_HANDLED; +} + +static int kdwc3_probe(struct platform_device *pdev) +{ +	struct device		*dev = &pdev->dev; +	struct device_node	*node = pdev->dev.of_node; +	struct dwc3_keystone	*kdwc; +	struct resource		*res; +	int			error, irq; + +	kdwc = devm_kzalloc(dev, sizeof(*kdwc), GFP_KERNEL); +	if (!kdwc) +		return -ENOMEM; + +	platform_set_drvdata(pdev, kdwc); + +	kdwc->dev = dev; + +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	if (!res) { +		dev_err(dev, "missing usbss resource\n"); +		return -EINVAL; +	} + +	kdwc->usbss = devm_ioremap_resource(dev, res); +	if (IS_ERR(kdwc->usbss)) +		return PTR_ERR(kdwc->usbss); + +	kdwc3_dma_mask = dma_get_mask(dev); +	dev->dma_mask = &kdwc3_dma_mask; + +	kdwc->clk = devm_clk_get(kdwc->dev, "usb"); + +	error = clk_prepare_enable(kdwc->clk); +	if (error < 0) { +		dev_dbg(kdwc->dev, "unable to enable usb clock, err %d\n", +			error); +		return error; +	} + +	irq = platform_get_irq(pdev, 0); +	if (irq < 0) { +		dev_err(&pdev->dev, "missing irq\n"); +		goto err_irq; +	} + +	error = devm_request_irq(dev, irq, dwc3_keystone_interrupt, IRQF_SHARED, +			dev_name(dev), kdwc); +	if (error) { +		dev_err(dev, "failed to request IRQ #%d --> %d\n", +				irq, error); +		goto err_irq; +	} + +	kdwc3_enable_irqs(kdwc); + +	error = of_platform_populate(node, NULL, NULL, dev); +	if (error) { +		dev_err(&pdev->dev, "failed to create dwc3 core\n"); +		goto err_core; +	} + +	return 0; + +err_core: +	kdwc3_disable_irqs(kdwc); +err_irq: +	clk_disable_unprepare(kdwc->clk); + +	return error; +} + +static int kdwc3_remove_core(struct device *dev, void *c) +{ +	struct platform_device *pdev = to_platform_device(dev); + +	platform_device_unregister(pdev); + +	return 0; +} + +static int kdwc3_remove(struct platform_device *pdev) +{ +	struct dwc3_keystone *kdwc = platform_get_drvdata(pdev); + +	kdwc3_disable_irqs(kdwc); +	device_for_each_child(&pdev->dev, NULL, kdwc3_remove_core); +	clk_disable_unprepare(kdwc->clk); +	platform_set_drvdata(pdev, NULL); + +	return 0; +} + +static const struct of_device_id kdwc3_of_match[] = { +	{ .compatible = "ti,keystone-dwc3", }, +	{}, +}; +MODULE_DEVICE_TABLE(of, kdwc3_of_match); + +static struct platform_driver kdwc3_driver = { +	.probe		= kdwc3_probe, +	.remove		= kdwc3_remove, +	.driver		= { +		.name	= "keystone-dwc3", +		.owner	        = THIS_MODULE, +		.of_match_table	= kdwc3_of_match, +	}, +}; + +module_platform_driver(kdwc3_driver); + +MODULE_ALIAS("platform:keystone-dwc3"); +MODULE_AUTHOR("WingMan Kwok <w-kwok2@ti.com>"); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("DesignWare USB3 KEYSTONE Glue Layer"); diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c index 7f7ea62e961..07a736acd0f 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c @@ -20,7 +20,6 @@  #include <linux/kernel.h>  #include <linux/slab.h>  #include <linux/interrupt.h> -#include <linux/spinlock.h>  #include <linux/platform_device.h>  #include <linux/platform_data/dwc3-omap.h>  #include <linux/pm_runtime.h> @@ -30,7 +29,6 @@  #include <linux/of.h>  #include <linux/of_platform.h>  #include <linux/extcon.h> -#include <linux/extcon/of_extcon.h>  #include <linux/regulator/consumer.h>  #include <linux/usb/otg.h> @@ -120,9 +118,6 @@  #define USBOTGSS_UTMI_OTG_STATUS_VBUSVALID	(1 << 1)  struct dwc3_omap { -	/* device lock */ -	spinlock_t		lock; -  	struct device		*dev;  	int			irq; @@ -280,8 +275,6 @@ static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)  	struct dwc3_omap	*omap = _omap;  	u32			reg; -	spin_lock(&omap->lock); -  	reg = dwc3_omap_read_irqmisc_status(omap);  	if (reg & USBOTGSS_IRQMISC_DMADISABLECLR) { @@ -322,8 +315,6 @@ static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)  	dwc3_omap_write_irq0_status(omap, reg); -	spin_unlock(&omap->lock); -  	return IRQ_HANDLED;  } @@ -331,7 +322,7 @@ static int dwc3_omap_remove_core(struct device *dev, void *c)  {  	struct platform_device *pdev = to_platform_device(dev); -	platform_device_unregister(pdev); +	of_device_unregister(pdev);  	return 0;  } @@ -402,7 +393,7 @@ static int dwc3_omap_probe(struct platform_device *pdev)  	struct extcon_dev	*edev;  	struct regulator	*vbus_reg = NULL; -	int			ret = -ENOMEM; +	int			ret;  	int			irq;  	int			utmi_mode = 0; @@ -432,11 +423,6 @@ static int dwc3_omap_probe(struct platform_device *pdev)  	}  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	if (!res) { -		dev_err(dev, "missing memory base resource\n"); -		return -EINVAL; -	} -  	base = devm_ioremap_resource(dev, res);  	if (IS_ERR(base))  		return PTR_ERR(base); @@ -449,8 +435,6 @@ static int dwc3_omap_probe(struct platform_device *pdev)  		}  	} -	spin_lock_init(&omap->lock); -  	omap->dev	= dev;  	omap->irq	= irq;  	omap->base	= base; @@ -532,10 +516,10 @@ static int dwc3_omap_probe(struct platform_device *pdev)  	dwc3_omap_enable_irqs(omap);  	if (of_property_read_bool(node, "extcon")) { -		edev = of_extcon_get_extcon_dev(dev, 0); +		edev = extcon_get_edev_by_phandle(dev, 0);  		if (IS_ERR(edev)) {  			dev_vdbg(dev, "couldn't get extcon device\n"); -			ret = PTR_ERR(edev); +			ret = -EPROBE_DEFER;  			goto err2;  		} @@ -615,7 +599,7 @@ static int dwc3_omap_prepare(struct device *dev)  {  	struct dwc3_omap	*omap = dev_get_drvdata(dev); -	dwc3_omap_disable_irqs(omap); +	dwc3_omap_write_irqmisc_set(omap, 0x00);  	return 0;  } @@ -623,8 +607,19 @@ static int dwc3_omap_prepare(struct device *dev)  static void dwc3_omap_complete(struct device *dev)  {  	struct dwc3_omap	*omap = dev_get_drvdata(dev); +	u32			reg; -	dwc3_omap_enable_irqs(omap); +	reg = (USBOTGSS_IRQMISC_OEVT | +			USBOTGSS_IRQMISC_DRVVBUS_RISE | +			USBOTGSS_IRQMISC_CHRGVBUS_RISE | +			USBOTGSS_IRQMISC_DISCHRGVBUS_RISE | +			USBOTGSS_IRQMISC_IDPULLUP_RISE | +			USBOTGSS_IRQMISC_DRVVBUS_FALL | +			USBOTGSS_IRQMISC_CHRGVBUS_FALL | +			USBOTGSS_IRQMISC_DISCHRGVBUS_FALL | +			USBOTGSS_IRQMISC_IDPULLUP_FALL); + +	dwc3_omap_write_irqmisc_set(omap, reg);  }  static int dwc3_omap_suspend(struct device *dev) diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index 2e252aae51c..a60bab7dfa0 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -23,7 +23,7 @@  #include <linux/platform_device.h>  #include <linux/usb/otg.h> -#include <linux/usb/usb_phy_gen_xceiv.h> +#include <linux/usb/usb_phy_generic.h>  /* FIXME define these in <linux/pci_ids.h> */  #define PCI_VENDOR_ID_SYNOPSYS		0x16c3 @@ -40,24 +40,25 @@ struct dwc3_pci {  static int dwc3_pci_register_phys(struct dwc3_pci *glue)  { -	struct usb_phy_gen_xceiv_platform_data pdata; +	struct usb_phy_generic_platform_data pdata;  	struct platform_device	*pdev;  	int			ret;  	memset(&pdata, 0x00, sizeof(pdata)); -	pdev = platform_device_alloc("usb_phy_gen_xceiv", 0); +	pdev = platform_device_alloc("usb_phy_generic", 0);  	if (!pdev)  		return -ENOMEM;  	glue->usb2_phy = pdev;  	pdata.type = USB_PHY_TYPE_USB2; +	pdata.gpio_reset = -1;  	ret = platform_device_add_data(glue->usb2_phy, &pdata, sizeof(pdata));  	if (ret)  		goto err1; -	pdev = platform_device_alloc("usb_phy_gen_xceiv", 1); +	pdev = platform_device_alloc("usb_phy_generic", 1);  	if (!pdev) {  		ret = -ENOMEM;  		goto err1; @@ -98,7 +99,7 @@ static int dwc3_pci_probe(struct pci_dev *pci,  	struct resource		res[2];  	struct platform_device	*dwc3;  	struct dwc3_pci		*glue; -	int			ret = -ENOMEM; +	int			ret;  	struct device		*dev = &pci->dev;  	glue = devm_kzalloc(dev, sizeof(*glue), GFP_KERNEL); @@ -109,7 +110,7 @@ static int dwc3_pci_probe(struct pci_dev *pci,  	glue->dev = dev; -	ret = pci_enable_device(pci); +	ret = pcim_enable_device(pci);  	if (ret) {  		dev_err(dev, "failed to enable pci device\n");  		return -ENODEV; @@ -126,8 +127,7 @@ static int dwc3_pci_probe(struct pci_dev *pci,  	dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO);  	if (!dwc3) {  		dev_err(dev, "couldn't allocate dwc3 device\n"); -		ret = -ENOMEM; -		goto err1; +		return -ENOMEM;  	}  	memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res)); @@ -144,7 +144,7 @@ static int dwc3_pci_probe(struct pci_dev *pci,  	ret = platform_device_add_resources(dwc3, res, ARRAY_SIZE(res));  	if (ret) {  		dev_err(dev, "couldn't add resources to dwc3 device\n"); -		goto err1; +		return ret;  	}  	pci_set_drvdata(pci, glue); @@ -165,11 +165,7 @@ static int dwc3_pci_probe(struct pci_dev *pci,  	return 0;  err3: -	pci_set_drvdata(pci, NULL);  	platform_device_put(dwc3); -err1: -	pci_disable_device(pci); -  	return ret;  } @@ -180,11 +176,9 @@ static void dwc3_pci_remove(struct pci_dev *pci)  	platform_device_unregister(glue->dwc3);  	platform_device_unregister(glue->usb2_phy);  	platform_device_unregister(glue->usb3_phy); -	pci_set_drvdata(pci, NULL); -	pci_disable_device(pci);  } -static DEFINE_PCI_DEVICE_TABLE(dwc3_pci_id_table) = { +static const struct pci_device_id dwc3_pci_id_table[] = {  	{  		PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,  				PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3), diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 7fa93f4bc50..21a352079bc 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -352,7 +352,7 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc,  		break;  	default:  		return -EINVAL; -	}; +	}  	response_pkt = (__le16 *) dwc->setup_buf;  	*response_pkt = cpu_to_le16(usb_status); @@ -459,6 +459,8 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,  			dep = dwc3_wIndex_to_dep(dwc, wIndex);  			if (!dep)  				return -EINVAL; +			if (set == 0 && (dep->flags & DWC3_EP_WEDGE)) +				break;  			ret = __dwc3_gadget_ep_set_halt(dep, set);  			if (ret)  				return -EINVAL; @@ -470,7 +472,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,  	default:  		return -EINVAL; -	}; +	}  	return 0;  } @@ -709,7 +711,7 @@ static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)  		dev_vdbg(dwc->dev, "Forwarding to gadget driver\n");  		ret = dwc3_ep0_delegate_req(dwc, ctrl);  		break; -	}; +	}  	return ret;  } diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 5452c0fce36..dab7927d100 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -68,6 +68,22 @@ int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode)  }  /** + * dwc3_gadget_get_link_state - Gets current state of USB Link + * @dwc: pointer to our context structure + * + * Caller should take care of locking. This function will + * return the link state on success (>= 0) or -ETIMEDOUT. + */ +int dwc3_gadget_get_link_state(struct dwc3 *dwc) +{ +	u32		reg; + +	reg = dwc3_readl(dwc->regs, DWC3_DSTS); + +	return DWC3_DSTS_USBLNKST(reg); +} + +/**   * dwc3_gadget_set_link_state - Sets USB Link to a particular State   * @dwc: pointer to our context structure   * @state: the state to put link into @@ -171,15 +187,12 @@ int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc)  	 * improve this algorithm so that we better use the internal  	 * FIFO space  	 */ -	for (num = 0; num < DWC3_ENDPOINTS_NUM; num++) { -		struct dwc3_ep	*dep = dwc->eps[num]; -		int		fifo_number = dep->number >> 1; +	for (num = 0; num < dwc->num_in_eps; num++) { +		/* bit0 indicates direction; 1 means IN ep */ +		struct dwc3_ep	*dep = dwc->eps[(num << 1) | 1];  		int		mult = 1;  		int		tmp; -		if (!(dep->number & 1)) -			continue; -  		if (!(dep->flags & DWC3_EP_ENABLED))  			continue; @@ -208,8 +221,7 @@ int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc)  		dev_vdbg(dwc->dev, "%s: Fifo Addr %04x Size %d\n",  				dep->name, last_fifo_depth, fifo_size & 0xffff); -		dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(fifo_number), -				fifo_size); +		dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(num), fifo_size);  		last_fifo_depth += (fifo_size & 0xffff);  	} @@ -286,11 +298,76 @@ static const char *dwc3_gadget_ep_cmd_string(u8 cmd)  	}  } +static const char *dwc3_gadget_generic_cmd_string(u8 cmd) +{ +	switch (cmd) { +	case DWC3_DGCMD_SET_LMP: +		return "Set LMP"; +	case DWC3_DGCMD_SET_PERIODIC_PAR: +		return "Set Periodic Parameters"; +	case DWC3_DGCMD_XMIT_FUNCTION: +		return "Transmit Function Wake Device Notification"; +	case DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO: +		return "Set Scratchpad Buffer Array Address Lo"; +	case DWC3_DGCMD_SET_SCRATCHPAD_ADDR_HI: +		return "Set Scratchpad Buffer Array Address Hi"; +	case DWC3_DGCMD_SELECTED_FIFO_FLUSH: +		return "Selected FIFO Flush"; +	case DWC3_DGCMD_ALL_FIFO_FLUSH: +		return "All FIFO Flush"; +	case DWC3_DGCMD_SET_ENDPOINT_NRDY: +		return "Set Endpoint NRDY"; +	case DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK: +		return "Run SoC Bus Loopback Test"; +	default: +		return "UNKNOWN"; +	} +} + +static const char *dwc3_gadget_link_string(enum dwc3_link_state link_state) +{ +	switch (link_state) { +	case DWC3_LINK_STATE_U0: +		return "U0"; +	case DWC3_LINK_STATE_U1: +		return "U1"; +	case DWC3_LINK_STATE_U2: +		return "U2"; +	case DWC3_LINK_STATE_U3: +		return "U3"; +	case DWC3_LINK_STATE_SS_DIS: +		return "SS.Disabled"; +	case DWC3_LINK_STATE_RX_DET: +		return "RX.Detect"; +	case DWC3_LINK_STATE_SS_INACT: +		return "SS.Inactive"; +	case DWC3_LINK_STATE_POLL: +		return "Polling"; +	case DWC3_LINK_STATE_RECOV: +		return "Recovery"; +	case DWC3_LINK_STATE_HRESET: +		return "Hot Reset"; +	case DWC3_LINK_STATE_CMPLY: +		return "Compliance"; +	case DWC3_LINK_STATE_LPBK: +		return "Loopback"; +	case DWC3_LINK_STATE_RESET: +		return "Reset"; +	case DWC3_LINK_STATE_RESUME: +		return "Resume"; +	default: +		return "UNKNOWN link state\n"; +	} +} +  int dwc3_send_gadget_generic_command(struct dwc3 *dwc, int cmd, u32 param)  {  	u32		timeout = 500;  	u32		reg; +	dev_vdbg(dwc->dev, "generic cmd '%s' [%d] param %08x\n", +			dwc3_gadget_generic_cmd_string(cmd), cmd, param); +  	dwc3_writel(dwc->regs, DWC3_DGCMDPAR, param);  	dwc3_writel(dwc->regs, DWC3_DGCMD, cmd | DWC3_DGCMD_CMDACT); @@ -320,9 +397,9 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,  	u32			timeout = 500;  	u32			reg; -	dev_vdbg(dwc->dev, "%s: cmd '%s' params %08x %08x %08x\n", +	dev_vdbg(dwc->dev, "%s: cmd '%s' [%d] params %08x %08x %08x\n",  			dep->name, -			dwc3_gadget_ep_cmd_string(cmd), params->param0, +			dwc3_gadget_ep_cmd_string(cmd), cmd, params->param0,  			params->param1, params->param2);  	dwc3_writel(dwc->regs, DWC3_DEPCMDPAR0(ep), params->param0); @@ -417,7 +494,7 @@ static int dwc3_gadget_start_config(struct dwc3 *dwc, struct dwc3_ep *dep)  static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep,  		const struct usb_endpoint_descriptor *desc,  		const struct usb_ss_ep_comp_descriptor *comp_desc, -		bool ignore) +		bool ignore, bool restore)  {  	struct dwc3_gadget_ep_cmd_params params; @@ -436,6 +513,11 @@ static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep,  	if (ignore)  		params.param0 |= DWC3_DEPCFG_IGN_SEQ_NUM; +	if (restore) { +		params.param0 |= DWC3_DEPCFG_ACTION_RESTORE; +		params.param2 |= dep->saved_state; +	} +  	params.param1 = DWC3_DEPCFG_XFER_COMPLETE_EN  		| DWC3_DEPCFG_XFER_NOT_READY_EN; @@ -494,11 +576,11 @@ static int dwc3_gadget_set_xfer_resource(struct dwc3 *dwc, struct dwc3_ep *dep)  static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,  		const struct usb_endpoint_descriptor *desc,  		const struct usb_ss_ep_comp_descriptor *comp_desc, -		bool ignore) +		bool ignore, bool restore)  {  	struct dwc3		*dwc = dep->dwc;  	u32			reg; -	int			ret = -ENOMEM; +	int			ret;  	dev_vdbg(dwc->dev, "Enabling %s\n", dep->name); @@ -508,7 +590,8 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,  			return ret;  	} -	ret = dwc3_gadget_set_ep_config(dwc, dep, desc, comp_desc, ignore); +	ret = dwc3_gadget_set_ep_config(dwc, dep, desc, comp_desc, ignore, +			restore);  	if (ret)  		return ret; @@ -548,13 +631,13 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,  	return 0;  } -static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum); +static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force);  static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep)  {  	struct dwc3_request		*req;  	if (!list_empty(&dep->req_queued)) { -		dwc3_stop_active_transfer(dwc, dep->number); +		dwc3_stop_active_transfer(dwc, dep->number, true);  		/* - giveback all requests to gadget driver */  		while (!list_empty(&dep->req_queued)) { @@ -586,6 +669,10 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)  	dwc3_remove_requests(dwc, dep); +	/* make sure HW endpoint isn't stalled */ +	if (dep->flags & DWC3_EP_STALL) +		__dwc3_gadget_ep_set_halt(dep, 0); +  	reg = dwc3_readl(dwc->regs, DWC3_DALEPENA);  	reg &= ~DWC3_DALEPENA_EP(dep->number);  	dwc3_writel(dwc->regs, DWC3_DALEPENA, reg); @@ -659,7 +746,7 @@ static int dwc3_gadget_ep_enable(struct usb_ep *ep,  	}  	spin_lock_irqsave(&dwc->lock, flags); -	ret = __dwc3_gadget_ep_enable(dep, desc, ep->comp_desc, false); +	ret = __dwc3_gadget_ep_enable(dep, desc, ep->comp_desc, false, false);  	spin_unlock_irqrestore(&dwc->lock, flags);  	return ret; @@ -741,10 +828,6 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,  			length, last ? " last" : "",  			chain ? " chain" : ""); -	/* Skip the LINK-TRB on ISOC */ -	if (((dep->free_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) && -			usb_endpoint_xfer_isoc(dep->endpoint.desc)) -		dep->free_slot++;  	trb = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK]; @@ -756,6 +839,10 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,  	}  	dep->free_slot++; +	/* Skip the LINK-TRB on ISOC */ +	if (((dep->free_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) && +			usb_endpoint_xfer_isoc(dep->endpoint.desc)) +		dep->free_slot++;  	trb->size = DWC3_TRB_SIZE_LENGTH(length);  	trb->bpl = lower_32_bits(dma); @@ -771,9 +858,6 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,  			trb->ctrl = DWC3_TRBCTL_ISOCHRONOUS_FIRST;  		else  			trb->ctrl = DWC3_TRBCTL_ISOCHRONOUS; - -		if (!req->request.no_interrupt && !chain) -			trb->ctrl |= DWC3_TRB_CTRL_IOC;  		break;  	case USB_ENDPOINT_XFER_BULK: @@ -788,6 +872,9 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,  		BUG();  	} +	if (!req->request.no_interrupt && !chain) +		trb->ctrl |= DWC3_TRB_CTRL_IOC; +  	if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {  		trb->ctrl |= DWC3_TRB_CTRL_ISP_IMI;  		trb->ctrl |= DWC3_TRB_CTRL_CSP; @@ -1077,7 +1164,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)  		 */  		if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {  			if (list_empty(&dep->req_queued)) { -				dwc3_stop_active_transfer(dwc, dep->number); +				dwc3_stop_active_transfer(dwc, dep->number, true);  				dep->flags = DWC3_EP_ENABLED;  			}  			return 0; @@ -1107,6 +1194,23 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)  		return ret;  	} +	/* +	 * 4. Stream Capable Bulk Endpoints. We need to start the transfer +	 * right away, otherwise host will not know we have streams to be +	 * handled. +	 */ +	if (dep->stream_capable) { +		int	ret; + +		ret = __dwc3_gadget_kick_transfer(dep, 0, true); +		if (ret && ret != -EBUSY) { +			struct dwc3	*dwc = dep->dwc; + +			dev_dbg(dwc->dev, "%s: failed to kick transfers\n", +					dep->name); +		} +	} +  	return 0;  } @@ -1163,7 +1267,7 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep,  		}  		if (r == req) {  			/* wait until it is processed */ -			dwc3_stop_active_transfer(dwc, dep->number); +			dwc3_stop_active_transfer(dwc, dep->number, true);  			goto out1;  		}  		dev_err(dwc->dev, "request %p was not queued to %s\n", @@ -1194,23 +1298,18 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value)  		ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,  			DWC3_DEPCMD_SETSTALL, ¶ms);  		if (ret) -			dev_err(dwc->dev, "failed to %s STALL on %s\n", -					value ? "set" : "clear", +			dev_err(dwc->dev, "failed to set STALL on %s\n",  					dep->name);  		else  			dep->flags |= DWC3_EP_STALL;  	} else { -		if (dep->flags & DWC3_EP_WEDGE) -			return 0; -  		ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,  			DWC3_DEPCMD_CLEARSTALL, ¶ms);  		if (ret) -			dev_err(dwc->dev, "failed to %s STALL on %s\n", -					value ? "set" : "clear", +			dev_err(dwc->dev, "failed to clear STALL on %s\n",  					dep->name);  		else -			dep->flags &= ~DWC3_EP_STALL; +			dep->flags &= ~(DWC3_EP_STALL | DWC3_EP_WEDGE);  	}  	return ret; @@ -1390,7 +1489,7 @@ static int dwc3_gadget_set_selfpowered(struct usb_gadget *g,  	return 0;  } -static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on) +static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend)  {  	u32			reg;  	u32			timeout = 500; @@ -1405,9 +1504,17 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on)  		if (dwc->revision >= DWC3_REVISION_194A)  			reg &= ~DWC3_DCTL_KEEP_CONNECT;  		reg |= DWC3_DCTL_RUN_STOP; + +		if (dwc->has_hibernation) +			reg |= DWC3_DCTL_KEEP_CONNECT; +  		dwc->pullups_connected = true;  	} else {  		reg &= ~DWC3_DCTL_RUN_STOP; + +		if (dwc->has_hibernation && !suspend) +			reg &= ~DWC3_DCTL_KEEP_CONNECT; +  		dwc->pullups_connected = false;  	} @@ -1445,7 +1552,7 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)  	is_on = !!is_on;  	spin_lock_irqsave(&dwc->lock, flags); -	ret = dwc3_gadget_run_stop(dwc, is_on); +	ret = dwc3_gadget_run_stop(dwc, is_on, false);  	spin_unlock_irqrestore(&dwc->lock, flags);  	return ret; @@ -1552,14 +1659,16 @@ static int dwc3_gadget_start(struct usb_gadget *g,  	dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);  	dep = dwc->eps[0]; -	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false); +	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false, +			false);  	if (ret) {  		dev_err(dwc->dev, "failed to enable %s\n", dep->name);  		goto err2;  	}  	dep = dwc->eps[1]; -	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false); +	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false, +			false);  	if (ret) {  		dev_err(dwc->dev, "failed to enable %s\n", dep->name);  		goto err3; @@ -1653,7 +1762,7 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,  		dev_vdbg(dwc->dev, "initializing %s\n", dep->name);  		if (epnum == 0 || epnum == 1) { -			dep->endpoint.maxpacket = 512; +			usb_ep_set_maxpacket_limit(&dep->endpoint, 512);  			dep->endpoint.maxburst = 1;  			dep->endpoint.ops = &dwc3_gadget_ep0_ops;  			if (!epnum) @@ -1661,7 +1770,7 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,  		} else {  			int		ret; -			dep->endpoint.maxpacket = 1024; +			usb_ep_set_maxpacket_limit(&dep->endpoint, 1024);  			dep->endpoint.max_streams = 15;  			dep->endpoint.ops = &dwc3_gadget_ep_ops;  			list_add_tail(&dep->endpoint.ep_list, @@ -1852,15 +1961,12 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,  			 */  			dep->flags = DWC3_EP_PENDING_REQUEST;  		} else { -			dwc3_stop_active_transfer(dwc, dep->number); +			dwc3_stop_active_transfer(dwc, dep->number, true);  			dep->flags = DWC3_EP_ENABLED;  		}  		return 1;  	} -	if ((event->status & DEPEVT_STATUS_IOC) && -			(trb->ctrl & DWC3_TRB_CTRL_IOC)) -		return 0;  	return 1;  } @@ -2002,7 +2108,25 @@ static void dwc3_disconnect_gadget(struct dwc3 *dwc)  	}  } -static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum) +static void dwc3_suspend_gadget(struct dwc3 *dwc) +{ +	if (dwc->gadget_driver && dwc->gadget_driver->suspend) { +		spin_unlock(&dwc->lock); +		dwc->gadget_driver->suspend(&dwc->gadget); +		spin_lock(&dwc->lock); +	} +} + +static void dwc3_resume_gadget(struct dwc3 *dwc) +{ +	if (dwc->gadget_driver && dwc->gadget_driver->resume) { +		spin_unlock(&dwc->lock); +		dwc->gadget_driver->resume(&dwc->gadget); +		spin_lock(&dwc->lock); +	} +} + +static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force)  {  	struct dwc3_ep *dep;  	struct dwc3_gadget_ep_cmd_params params; @@ -2034,7 +2158,8 @@ static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum)  	 */  	cmd = DWC3_DEPCMD_ENDTRANSFER; -	cmd |= DWC3_DEPCMD_HIPRI_FORCERM | DWC3_DEPCMD_CMDIOC; +	cmd |= force ? DWC3_DEPCMD_HIPRI_FORCERM : 0; +	cmd |= DWC3_DEPCMD_CMDIOC;  	cmd |= DWC3_DEPCMD_PARAM(dep->resource_index);  	memset(¶ms, 0, sizeof(params));  	ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, ¶ms); @@ -2263,17 +2388,23 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)  		reg |= DWC3_DCTL_HIRD_THRES(12);  		dwc3_writel(dwc->regs, DWC3_DCTL, reg); +	} else { +		reg = dwc3_readl(dwc->regs, DWC3_DCTL); +		reg &= ~DWC3_DCTL_HIRD_THRES_MASK; +		dwc3_writel(dwc->regs, DWC3_DCTL, reg);  	}  	dep = dwc->eps[0]; -	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, true); +	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, true, +			false);  	if (ret) {  		dev_err(dwc->dev, "failed to enable %s\n", dep->name);  		return;  	}  	dep = dwc->eps[1]; -	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, true); +	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, true, +			false);  	if (ret) {  		dev_err(dwc->dev, "failed to enable %s\n", dep->name);  		return; @@ -2379,9 +2510,52 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc,  		}  	} +	switch (next) { +	case DWC3_LINK_STATE_U1: +		if (dwc->speed == USB_SPEED_SUPER) +			dwc3_suspend_gadget(dwc); +		break; +	case DWC3_LINK_STATE_U2: +	case DWC3_LINK_STATE_U3: +		dwc3_suspend_gadget(dwc); +		break; +	case DWC3_LINK_STATE_RESUME: +		dwc3_resume_gadget(dwc); +		break; +	default: +		/* do nothing */ +		break; +	} + +	dev_vdbg(dwc->dev, "link change: %s [%d] -> %s [%d]\n", +			dwc3_gadget_link_string(dwc->link_state), +			dwc->link_state, dwc3_gadget_link_string(next), next); +  	dwc->link_state = next; +} + +static void dwc3_gadget_hibernation_interrupt(struct dwc3 *dwc, +		unsigned int evtinfo) +{ +	unsigned int is_ss = evtinfo & BIT(4); + +	/** +	 * WORKAROUND: DWC3 revison 2.20a with hibernation support +	 * have a known issue which can cause USB CV TD.9.23 to fail +	 * randomly. +	 * +	 * Because of this issue, core could generate bogus hibernation +	 * events which SW needs to ignore. +	 * +	 * Refers to: +	 * +	 * STAR#9000546576: Device Mode Hibernation: Issue in USB 2.0 +	 * Device Fallback from SuperSpeed +	 */ +	if (is_ss ^ (dwc->speed == USB_SPEED_SUPER)) +		return; -	dev_vdbg(dwc->dev, "%s link %d\n", __func__, dwc->link_state); +	/* enter hibernation here */  }  static void dwc3_gadget_interrupt(struct dwc3 *dwc, @@ -2400,6 +2574,13 @@ static void dwc3_gadget_interrupt(struct dwc3 *dwc,  	case DWC3_DEVICE_EVENT_WAKEUP:  		dwc3_gadget_wakeup_interrupt(dwc);  		break; +	case DWC3_DEVICE_EVENT_HIBER_REQ: +		if (dev_WARN_ONCE(dwc->dev, !dwc->has_hibernation, +					"unexpected hibernation event\n")) +			break; + +		dwc3_gadget_hibernation_interrupt(dwc, event->event_info); +		break;  	case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE:  		dwc3_gadget_linksts_change_interrupt(dwc, event->event_info);  		break; @@ -2600,6 +2781,12 @@ int dwc3_gadget_init(struct dwc3 *dwc)  	dwc->gadget.name		= "dwc3-gadget";  	/* +	 * Per databook, DWC3 needs buffer size to be aligned to MaxPacketSize +	 * on ep out. +	 */ +	dwc->gadget.quirk_ep_out_aligned_size = true; + +	/*  	 * REVISIT: Here we should clear all pending IRQs to be  	 * sure we're starting from a well known location.  	 */ @@ -2658,8 +2845,10 @@ void dwc3_gadget_exit(struct dwc3 *dwc)  int dwc3_gadget_prepare(struct dwc3 *dwc)  { -	if (dwc->pullups_connected) +	if (dwc->pullups_connected) {  		dwc3_gadget_disable_irq(dwc); +		dwc3_gadget_run_stop(dwc, true, true); +	}  	return 0;  } @@ -2668,7 +2857,7 @@ void dwc3_gadget_complete(struct dwc3 *dwc)  {  	if (dwc->pullups_connected) {  		dwc3_gadget_enable_irq(dwc); -		dwc3_gadget_run_stop(dwc, true); +		dwc3_gadget_run_stop(dwc, true, false);  	}  } @@ -2691,12 +2880,14 @@ int dwc3_gadget_resume(struct dwc3 *dwc)  	dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);  	dep = dwc->eps[0]; -	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false); +	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false, +			false);  	if (ret)  		goto err0;  	dep = dwc->eps[1]; -	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false); +	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false, +			false);  	if (ret)  		goto err1; diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h index febe1aa7b71..a0ee75b68a8 100644 --- a/drivers/usb/dwc3/gadget.h +++ b/drivers/usb/dwc3/gadget.h @@ -56,12 +56,6 @@ struct dwc3;  /* DEPXFERCFG parameter 0 */  #define DWC3_DEPXFERCFG_NUM_XFER_RES(n)	((n) & 0xffff) -struct dwc3_gadget_ep_cmd_params { -	u32	param2; -	u32	param1; -	u32	param0; -}; -  /* -------------------------------------------------------------------------- */  #define to_dwc3_request(r)	(container_of(r, struct dwc3_request, request)) @@ -85,9 +79,6 @@ static inline void dwc3_gadget_move_request_queued(struct dwc3_request *req)  void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,  		int status); -int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode); -int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state); -  void dwc3_ep0_interrupt(struct dwc3 *dwc,  		const struct dwc3_event_depevt *event);  void dwc3_ep0_out_start(struct dwc3 *dwc); @@ -95,9 +86,6 @@ int dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value);  int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,  		gfp_t gfp_flags);  int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value); -int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep, -		unsigned cmd, struct dwc3_gadget_ep_cmd_params *params); -int dwc3_send_gadget_generic_command(struct dwc3 *dwc, int cmd, u32 param);  /**   * dwc3_gadget_ep_get_transfer_index - Gets transfer index from HW  | 
