diff options
Diffstat (limited to 'drivers/usb')
| -rw-r--r-- | drivers/usb/gadget/Makefile | 8 | ||||
| -rw-r--r-- | drivers/usb/gadget/f_dfu.c | 43 | ||||
| -rw-r--r-- | drivers/usb/gadget/f_dfu.h | 2 | ||||
| -rw-r--r-- | drivers/usb/gadget/fotg210.c | 15 | ||||
| -rw-r--r-- | drivers/usb/host/ehci-exynos.c | 41 | ||||
| -rw-r--r-- | drivers/usb/host/ehci-hcd.c | 5 | ||||
| -rw-r--r-- | drivers/usb/host/ehci-pci.c | 28 | 
7 files changed, 127 insertions, 15 deletions
| diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index f52d3f450..f13b172a6 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -5,12 +5,8 @@  # SPDX-License-Identifier:	GPL-2.0+  # -# if defined(CONFIG_USB_GADGET) || defined(CONFIG_USB_ETHER) -#   Everytime you forget how crufty makefiles can get things like -#   this remind you... -ifneq (,$(CONFIG_USB_GADGET)$(CONFIG_USB_ETHER)) -obj-y += epautoconf.o config.o usbstring.o -endif +obj-$(CONFIG_USB_GADGET) += epautoconf.o config.o usbstring.o +obj-$(CONFIG_USB_ETHER) += epautoconf.o config.o usbstring.o  # new USB gadget layer dependencies  ifdef CONFIG_USB_GADGET diff --git a/drivers/usb/gadget/f_dfu.c b/drivers/usb/gadget/f_dfu.c index 37d04a192..a045864d7 100644 --- a/drivers/usb/gadget/f_dfu.c +++ b/drivers/usb/gadget/f_dfu.c @@ -40,6 +40,7 @@ struct f_dfu {  	/* Send/received block number is handy for data integrity check */  	int                             blk_seq_num; +	unsigned int                    poll_timeout;  };  typedef int (*dfu_state_fn) (struct f_dfu *, @@ -128,6 +129,33 @@ static struct usb_gadget_strings *dfu_strings[] = {  	NULL,  }; +static void dfu_set_poll_timeout(struct dfu_status *dstat, unsigned int ms) +{ +	/* +	 * The bwPollTimeout DFU_GETSTATUS request payload provides information +	 * about minimum time, in milliseconds, that the host should wait before +	 * sending a subsequent DFU_GETSTATUS request +	 * +	 * This permits the device to vary the delay depending on its need to +	 * erase or program the memory +	 * +	 */ + +	unsigned char *p = (unsigned char *)&ms; + +	if (!ms || (ms & ~DFU_POLL_TIMEOUT_MASK)) { +		dstat->bwPollTimeout[0] = 0; +		dstat->bwPollTimeout[1] = 0; +		dstat->bwPollTimeout[2] = 0; + +		return; +	} + +	dstat->bwPollTimeout[0] = *p++; +	dstat->bwPollTimeout[1] = *p++; +	dstat->bwPollTimeout[2] = *p; +} +  /*-------------------------------------------------------------------------*/  static void dnload_request_complete(struct usb_ep *ep, struct usb_request *req) @@ -157,11 +185,15 @@ static void handle_getstatus(struct usb_request *req)  		break;  	} +	dfu_set_poll_timeout(dstat, 0); + +	if (f_dfu->poll_timeout) +		if (!(f_dfu->blk_seq_num % +		      (dfu_get_buf_size() / DFU_USB_BUFSIZ))) +			dfu_set_poll_timeout(dstat, f_dfu->poll_timeout); +  	/* send status response */  	dstat->bStatus = f_dfu->dfu_status; -	dstat->bwPollTimeout[0] = 0; -	dstat->bwPollTimeout[1] = 0; -	dstat->bwPollTimeout[2] = 0;  	dstat->bState = f_dfu->dfu_state;  	dstat->iString = 0;  } @@ -723,8 +755,9 @@ static int dfu_bind_config(struct usb_configuration *c)  	f_dfu->usb_function.unbind = dfu_unbind;  	f_dfu->usb_function.set_alt = dfu_set_alt;  	f_dfu->usb_function.disable = dfu_disable; -	f_dfu->usb_function.strings = dfu_generic_strings, -	f_dfu->usb_function.setup = dfu_handle, +	f_dfu->usb_function.strings = dfu_generic_strings; +	f_dfu->usb_function.setup = dfu_handle; +	f_dfu->poll_timeout = DFU_DEFAULT_POLL_TIMEOUT;  	status = usb_add_function(c, &f_dfu->usb_function);  	if (status) diff --git a/drivers/usb/gadget/f_dfu.h b/drivers/usb/gadget/f_dfu.h index cc2c45567..0c29954ad 100644 --- a/drivers/usb/gadget/f_dfu.h +++ b/drivers/usb/gadget/f_dfu.h @@ -82,4 +82,6 @@ struct dfu_function_descriptor {  	__le16				wTransferSize;  	__le16				bcdDFUVersion;  } __packed; + +#define DFU_POLL_TIMEOUT_MASK           (0xFFFFFFUL)  #endif /* __F_DFU_H_ */ diff --git a/drivers/usb/gadget/fotg210.c b/drivers/usb/gadget/fotg210.c index 6e19db15f..3acf6a1f4 100644 --- a/drivers/usb/gadget/fotg210.c +++ b/drivers/usb/gadget/fotg210.c @@ -245,6 +245,7 @@ static int fotg210_dma(struct fotg210_ep *ep, struct fotg210_request *req)  		if (ep->id == 0) {  			/* Wait until cx/ep0 fifo empty */  			fotg210_cxwait(chip, CXFIFO_CXFIFOE); +			udelay(1);  			writel(DMAFIFO_CX, ®s->dma_fifo);  		} else {  			/* Wait until epx fifo empty */ @@ -847,6 +848,13 @@ int usb_gadget_handle_interrupts(void)  	/* CX interrupts */  	if (gisr & GISR_GRP0) {  		st = readl(®s->gisr0); +		/* +		 * Write 1 and then 0 works for both W1C & RW. +		 * +		 * HW v1.11.0+: It's a W1C register (write 1 clear) +		 * HW v1.10.0-: It's a R/W register (write 0 clear) +		 */ +		writel(st & GISR0_CXABORT, ®s->gisr0);  		writel(0, ®s->gisr0);  		if (st & GISR0_CXERR) @@ -873,6 +881,13 @@ int usb_gadget_handle_interrupts(void)  	/* Device Status Interrupts */  	if (gisr & GISR_GRP2) {  		st = readl(®s->gisr2); +		/* +		 * Write 1 and then 0 works for both W1C & RW. +		 * +		 * HW v1.11.0+: It's a W1C register (write 1 clear) +		 * HW v1.10.0-: It's a R/W register (write 0 clear) +		 */ +		writel(st, ®s->gisr2);  		writel(0, ®s->gisr2);  		if (st & GISR2_RESET) diff --git a/drivers/usb/host/ehci-exynos.c b/drivers/usb/host/ehci-exynos.c index 66b4de0b2..9356878eb 100644 --- a/drivers/usb/host/ehci-exynos.c +++ b/drivers/usb/host/ehci-exynos.c @@ -88,6 +88,8 @@ static int exynos_usb_parse_dt(const void *blob, struct exynos_ehci *exynos)  /* Setup the EHCI host controller. */  static void setup_usb_phy(struct exynos_usb_phy *usb)  { +	u32 hsic_ctrl; +  	set_usbhost_mode(USB20_PHY_CFG_HOST_LINK_EN);  	set_usbhost_phy_ctrl(POWER_USB_HOST_PHY_CTRL_EN); @@ -112,6 +114,32 @@ static void setup_usb_phy(struct exynos_usb_phy *usb)  	clrbits_le32(&usb->usbphyctrl0,  			HOST_CTRL0_LINKSWRST |  			HOST_CTRL0_UTMISWRST); + +	/* HSIC Phy Setting */ +	hsic_ctrl = (HSIC_CTRL_FORCESUSPEND | +			HSIC_CTRL_FORCESLEEP | +			HSIC_CTRL_SIDDQ); + +	clrbits_le32(&usb->hsicphyctrl1, hsic_ctrl); +	clrbits_le32(&usb->hsicphyctrl2, hsic_ctrl); + +	hsic_ctrl = (((HSIC_CTRL_REFCLKDIV_12 & HSIC_CTRL_REFCLKDIV_MASK) +				<< HSIC_CTRL_REFCLKDIV_SHIFT) +			| ((HSIC_CTRL_REFCLKSEL & HSIC_CTRL_REFCLKSEL_MASK) +				<< HSIC_CTRL_REFCLKSEL_SHIFT) +			| HSIC_CTRL_UTMISWRST); + +	setbits_le32(&usb->hsicphyctrl1, hsic_ctrl); +	setbits_le32(&usb->hsicphyctrl2, hsic_ctrl); + +	udelay(10); + +	clrbits_le32(&usb->hsicphyctrl1, HSIC_CTRL_PHYSWRST | +					HSIC_CTRL_UTMISWRST); + +	clrbits_le32(&usb->hsicphyctrl2, HSIC_CTRL_PHYSWRST | +					HSIC_CTRL_UTMISWRST); +  	udelay(20);  	/* EHCI Ctrl setting */ @@ -125,6 +153,8 @@ static void setup_usb_phy(struct exynos_usb_phy *usb)  /* Reset the EHCI host controller. */  static void reset_usb_phy(struct exynos_usb_phy *usb)  { +	u32 hsic_ctrl; +  	/* HOST_PHY reset */  	setbits_le32(&usb->usbphyctrl0,  			HOST_CTRL0_PHYSWRST | @@ -133,6 +163,15 @@ static void reset_usb_phy(struct exynos_usb_phy *usb)  			HOST_CTRL0_FORCESUSPEND |  			HOST_CTRL0_FORCESLEEP); +	/* HSIC Phy reset */ +	hsic_ctrl = (HSIC_CTRL_FORCESUSPEND | +			HSIC_CTRL_FORCESLEEP | +			HSIC_CTRL_SIDDQ | +			HSIC_CTRL_PHYSWRST); + +	setbits_le32(&usb->hsicphyctrl1, hsic_ctrl); +	setbits_le32(&usb->hsicphyctrl2, hsic_ctrl); +  	set_usbhost_phy_ctrl(POWER_USB_HOST_PHY_CTRL_DISABLE);  } @@ -164,6 +203,8 @@ int ehci_hcd_init(int index, enum usb_init_type init,  	setup_usb_phy(ctx->usb); +	board_usb_init(index, init); +  	*hccr = ctx->hcd;  	*hcor = (struct ehci_hcor *)((uint32_t) *hccr  				+ HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase))); diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 8bd1eb8a9..17187caed 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -201,6 +201,9 @@ static int ehci_shutdown(struct ehci_ctrl *ctrl)  	int i, ret = 0;  	uint32_t cmd, reg; +	if (!ctrl || !ctrl->hcor) +		return -EINVAL; +  	cmd = ehci_readl(&ctrl->hcor->or_usbcmd);  	cmd &= ~(CMD_PSE | CMD_ASE);  	ehci_writel(&ctrl->hcor->or_usbcmd, cmd); @@ -945,7 +948,7 @@ int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)  #endif  	/* Set the high address word (aka segment) for 64-bit controller */  	if (ehci_readl(&ehcic[index].hccr->cr_hccparams) & 1) -		ehci_writel(ehcic[index].hcor->or_ctrldssegment, 0); +		ehci_writel(&ehcic[index].hcor->or_ctrldssegment, 0);  	qh_list = &ehcic[index].qh_list; diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index 7a1ffe5e2..991b19998 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -54,9 +54,31 @@ static pci_dev_t ehci_find_class(int index)  					bdf += PCI_BDF(0, 0, 1)) {  				pci_read_config_dword(bdf, PCI_CLASS_REVISION,  						      &class); -				if ((class >> 8 == PCI_CLASS_SERIAL_USB_EHCI) -						&& !index--) -					return bdf; +				class >>= 8; +				/* +				 * Here be dragons! In case we have multiple +				 * PCI EHCI controllers, this function will +				 * be called multiple times as well. This +				 * function will scan the PCI busses, always +				 * starting from bus 0, device 0, function 0, +				 * until it finds an USB controller. The USB +				 * stack gives us an 'index' of a controller +				 * that is currently being registered, which +				 * is a number, starting from 0 and growing +				 * in ascending order as controllers are added. +				 * To avoid probing the same controller in tne +				 * subsequent runs of this function, we will +				 * skip 'index - 1' detected controllers and +				 * report the index'th controller. +				 */ +				if (class != PCI_CLASS_SERIAL_USB_EHCI) +					continue; +				if (index) { +					index--; +					continue; +				} +				/* Return index'th controller. */ +				return bdf;  			}  		}  	} |