diff options
Diffstat (limited to 'drivers/usb/dwc3/gadget.c')
| -rw-r--r-- | drivers/usb/dwc3/gadget.c | 145 | 
1 files changed, 99 insertions, 46 deletions
| diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index aebcf8ec0716..dd80e5ca8c78 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -308,13 +308,12 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned int cmd,  	}  	if (DWC3_DEPCMD_CMD(cmd) == DWC3_DEPCMD_STARTTRANSFER) { -		int		needs_wakeup; +		int link_state; -		needs_wakeup = (dwc->link_state == DWC3_LINK_STATE_U1 || -				dwc->link_state == DWC3_LINK_STATE_U2 || -				dwc->link_state == DWC3_LINK_STATE_U3); - -		if (unlikely(needs_wakeup)) { +		link_state = dwc3_gadget_get_link_state(dwc); +		if (link_state == DWC3_LINK_STATE_U1 || +		    link_state == DWC3_LINK_STATE_U2 || +		    link_state == DWC3_LINK_STATE_U3) {  			ret = __dwc3_gadget_wakeup(dwc);  			dev_WARN_ONCE(dwc->dev, ret, "wakeup failed --> %d\n",  					ret); @@ -608,12 +607,14 @@ static int dwc3_gadget_set_ep_config(struct dwc3_ep *dep, unsigned int action)  		u8 bInterval_m1;  		/* -		 * Valid range for DEPCFG.bInterval_m1 is from 0 to 13, and it -		 * must be set to 0 when the controller operates in full-speed. +		 * Valid range for DEPCFG.bInterval_m1 is from 0 to 13. +		 * +		 * NOTE: The programming guide incorrectly stated bInterval_m1 +		 * must be set to 0 when operating in fullspeed. Internally the +		 * controller does not have this limitation. See DWC_usb3x +		 * programming guide section 3.2.2.1.  		 */  		bInterval_m1 = min_t(u8, desc->bInterval - 1, 13); -		if (dwc->gadget->speed == USB_SPEED_FULL) -			bInterval_m1 = 0;  		if (usb_endpoint_type(desc) == USB_ENDPOINT_XFER_INT &&  		    dwc->gadget->speed == USB_SPEED_FULL) @@ -729,8 +730,16 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, unsigned int action)  			 * All stream eps will reinitiate stream on NoStream  			 * rejection until we can determine that the host can  			 * prime after the first transfer. +			 * +			 * However, if the controller is capable of +			 * TXF_FLUSH_BYPASS, then IN direction endpoints will +			 * automatically restart the stream without the driver +			 * initiation.  			 */ -			dep->flags |= DWC3_EP_FORCE_RESTART_STREAM; +			if (!dep->direction || +			    !(dwc->hwparams.hwparams9 & +			      DWC3_GHWPARAMS9_DEV_TXF_FLUSH_BYPASS)) +				dep->flags |= DWC3_EP_FORCE_RESTART_STREAM;  		}  	} @@ -783,8 +792,6 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)  	trace_dwc3_gadget_ep_disable(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, false); @@ -793,16 +800,18 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)  	reg &= ~DWC3_DALEPENA_EP(dep->number);  	dwc3_writel(dwc->regs, DWC3_DALEPENA, reg); -	dep->stream_capable = false; -	dep->type = 0; -	dep->flags = 0; -  	/* Clear out the ep descriptors for non-ep0 */  	if (dep->number > 1) {  		dep->endpoint.comp_desc = NULL;  		dep->endpoint.desc = NULL;  	} +	dwc3_remove_requests(dwc, dep); + +	dep->stream_capable = false; +	dep->type = 0; +	dep->flags = 0; +  	return 0;  } @@ -1402,7 +1411,7 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep)  		dwc3_stop_active_transfer(dep, true, true);  		list_for_each_entry_safe(req, tmp, &dep->started_list, list) -			dwc3_gadget_move_cancelled_request(req); +			dwc3_gadget_move_cancelled_request(req, DWC3_REQUEST_STATUS_DEQUEUED);  		/* If ep isn't started, then there's no end transfer pending */  		if (!(dep->flags & DWC3_EP_END_TRANSFER_PENDING)) @@ -1617,7 +1626,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)  {  	struct dwc3		*dwc = dep->dwc; -	if (!dep->endpoint.desc || !dwc->pullups_connected) { +	if (!dep->endpoint.desc || !dwc->pullups_connected || !dwc->connected) {  		dev_err(dwc->dev, "%s: can't queue to disabled endpoint\n",  				dep->name);  		return -ESHUTDOWN; @@ -1729,10 +1738,25 @@ static void dwc3_gadget_ep_cleanup_cancelled_requests(struct dwc3_ep *dep)  {  	struct dwc3_request		*req;  	struct dwc3_request		*tmp; +	struct dwc3			*dwc = dep->dwc;  	list_for_each_entry_safe(req, tmp, &dep->cancelled_list, list) {  		dwc3_gadget_ep_skip_trbs(dep, req); -		dwc3_gadget_giveback(dep, req, -ECONNRESET); +		switch (req->status) { +		case DWC3_REQUEST_STATUS_DISCONNECTED: +			dwc3_gadget_giveback(dep, req, -ESHUTDOWN); +			break; +		case DWC3_REQUEST_STATUS_DEQUEUED: +			dwc3_gadget_giveback(dep, req, -ECONNRESET); +			break; +		case DWC3_REQUEST_STATUS_STALLED: +			dwc3_gadget_giveback(dep, req, -EPIPE); +			break; +		default: +			dev_err(dwc->dev, "request cancelled with wrong reason:%d\n", req->status); +			dwc3_gadget_giveback(dep, req, -ECONNRESET); +			break; +		}  	}  } @@ -1776,7 +1800,8 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep,  			 * cancelled.  			 */  			list_for_each_entry_safe(r, t, &dep->started_list, list) -				dwc3_gadget_move_cancelled_request(r); +				dwc3_gadget_move_cancelled_request(r, +						DWC3_REQUEST_STATUS_DEQUEUED);  			dep->flags &= ~DWC3_EP_WAIT_TRANSFER_COMPLETE; @@ -1848,7 +1873,7 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol)  		dwc3_stop_active_transfer(dep, true, true);  		list_for_each_entry_safe(req, tmp, &dep->started_list, list) -			dwc3_gadget_move_cancelled_request(req); +			dwc3_gadget_move_cancelled_request(req, DWC3_REQUEST_STATUS_STALLED);  		if (dep->flags & DWC3_EP_END_TRANSFER_PENDING) {  			dep->flags |= DWC3_EP_PENDING_CLEAR_STALL; @@ -1973,6 +1998,8 @@ static int __dwc3_gadget_wakeup(struct dwc3 *dwc)  	case DWC3_LINK_STATE_RESET:  	case DWC3_LINK_STATE_RX_DET:	/* in HS, means Early Suspend */  	case DWC3_LINK_STATE_U3:	/* in HS, means SUSPEND */ +	case DWC3_LINK_STATE_U2:	/* in HS, means Sleep (L1) */ +	case DWC3_LINK_STATE_U1:  	case DWC3_LINK_STATE_RESUME:  		break;  	default: @@ -2083,7 +2110,7 @@ static void __dwc3_gadget_set_speed(struct dwc3 *dwc)  	u32			reg;  	speed = dwc->gadget_max_speed; -	if (speed > dwc->maximum_speed) +	if (speed == USB_SPEED_UNKNOWN || speed > dwc->maximum_speed)  		speed = dwc->maximum_speed;  	if (speed == USB_SPEED_SUPER_PLUS && @@ -2113,9 +2140,6 @@ static void __dwc3_gadget_set_speed(struct dwc3 *dwc)  		reg |= DWC3_DCFG_SUPERSPEED;  	} else {  		switch (speed) { -		case USB_SPEED_LOW: -			reg |= DWC3_DCFG_LOWSPEED; -			break;  		case USB_SPEED_FULL:  			reg |= DWC3_DCFG_FULLSPEED;  			break; @@ -2247,6 +2271,7 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)  	if (!is_on) {  		u32 count; +		dwc->connected = false;  		/*  		 * In the Synopsis DesignWare Cores USB3 Databook Rev. 3.30a  		 * Section 4.1.8 Table 4-7, it states that for a device-initiated @@ -2271,7 +2296,6 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)  			dwc->ev_buf->lpos = (dwc->ev_buf->lpos + count) %  						dwc->ev_buf->length;  		} -		dwc->connected = false;  	} else {  		__dwc3_gadget_start(dwc);  	} @@ -2340,9 +2364,7 @@ static void dwc3_gadget_setup_nump(struct dwc3 *dwc)  	u32 reg;  	ram2_depth = DWC3_GHWPARAMS7_RAM2_DEPTH(dwc->hwparams.hwparams7); -	mdwidth = DWC3_GHWPARAMS0_MDWIDTH(dwc->hwparams.hwparams0); -	if (DWC3_IP_IS(DWC32)) -		mdwidth += DWC3_GHWPARAMS6_MDWIDTH(dwc->hwparams.hwparams6); +	mdwidth = dwc3_mdwidth(dwc);  	nump = ((ram2_depth * mdwidth / 8) - 24 - 16) / 1024;  	nump = min_t(u32, nump, 16); @@ -2388,6 +2410,17 @@ static int __dwc3_gadget_start(struct dwc3 *dwc)  	dwc3_gadget_setup_nump(dwc); +	/* +	 * Currently the controller handles single stream only. So, Ignore +	 * Packet Pending bit for stream selection and don't search for another +	 * stream if the host sends Data Packet with PP=0 (for OUT direction) or +	 * ACK with NumP=0 and PP=0 (for IN direction). This slightly improves +	 * the stream performance. +	 */ +	reg = dwc3_readl(dwc->regs, DWC3_DCFG); +	reg |= DWC3_DCFG_IGNSTRMPP; +	dwc3_writel(dwc->regs, DWC3_DCFG, reg); +  	/* Start with SuperSpeed Default */  	dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512); @@ -2523,6 +2556,7 @@ static void dwc3_gadget_set_ssp_rate(struct usb_gadget *g,  	unsigned long		flags;  	spin_lock_irqsave(&dwc->lock, flags); +	dwc->gadget_max_speed = USB_SPEED_SUPER_PLUS;  	dwc->gadget_ssp_rate = rate;  	spin_unlock_irqrestore(&dwc->lock, flags);  } @@ -2530,11 +2564,19 @@ static void dwc3_gadget_set_ssp_rate(struct usb_gadget *g,  static int dwc3_gadget_vbus_draw(struct usb_gadget *g, unsigned int mA)  {  	struct dwc3		*dwc = gadget_to_dwc(g); +	union power_supply_propval	val = {0}; +	int				ret;  	if (dwc->usb2_phy)  		return usb_phy_set_power(dwc->usb2_phy, mA); -	return 0; +	if (!dwc->usb_psy) +		return -EOPNOTSUPP; + +	val.intval = 1000 * mA; +	ret = power_supply_set_property(dwc->usb_psy, POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, &val); + +	return ret;  }  static const struct usb_gadget_ops dwc3_gadget_ops = { @@ -2570,12 +2612,10 @@ static int dwc3_gadget_init_control_endpoint(struct dwc3_ep *dep)  static int dwc3_gadget_init_in_endpoint(struct dwc3_ep *dep)  {  	struct dwc3 *dwc = dep->dwc; -	int mdwidth; +	u32 mdwidth;  	int size; -	mdwidth = DWC3_MDWIDTH(dwc->hwparams.hwparams0); -	if (DWC3_IP_IS(DWC32)) -		mdwidth += DWC3_GHWPARAMS6_MDWIDTH(dwc->hwparams.hwparams6); +	mdwidth = dwc3_mdwidth(dwc);  	/* MDWIDTH is represented in bits, we need it in bytes */  	mdwidth /= 8; @@ -2617,12 +2657,10 @@ static int dwc3_gadget_init_in_endpoint(struct dwc3_ep *dep)  static int dwc3_gadget_init_out_endpoint(struct dwc3_ep *dep)  {  	struct dwc3 *dwc = dep->dwc; -	int mdwidth; +	u32 mdwidth;  	int size; -	mdwidth = DWC3_MDWIDTH(dwc->hwparams.hwparams0); -	if (DWC3_IP_IS(DWC32)) -		mdwidth += DWC3_GHWPARAMS6_MDWIDTH(dwc->hwparams.hwparams6); +	mdwidth = dwc3_mdwidth(dwc);  	/* MDWIDTH is represented in bits, convert to bytes */  	mdwidth /= 8; @@ -2912,6 +2950,11 @@ static void dwc3_gadget_ep_cleanup_completed_requests(struct dwc3_ep *dep,  static bool dwc3_gadget_ep_should_continue(struct dwc3_ep *dep)  {  	struct dwc3_request	*req; +	struct dwc3		*dwc = dep->dwc; + +	if (!dep->endpoint.desc || !dwc->pullups_connected || +	    !dwc->connected) +		return false;  	if (!list_empty(&dep->pending_list))  		return true; @@ -3321,7 +3364,14 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)  {  	u32			reg; -	dwc->connected = true; +	/* +	 * Ideally, dwc3_reset_gadget() would trigger the function +	 * drivers to stop any active transfers through ep disable. +	 * However, for functions which defer ep disable, such as mass +	 * storage, we will need to rely on the call to stop active +	 * transfers here, and avoid allowing of request queuing. +	 */ +	dwc->connected = false;  	/*  	 * WORKAROUND: DWC3 revisions <1.88a have an issue which @@ -3362,6 +3412,7 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)  	 * transfers."  	 */  	dwc3_stop_active_transfers(dwc); +	dwc->connected = true;  	reg = dwc3_readl(dwc->regs, DWC3_DCTL);  	reg &= ~DWC3_DCTL_TSTCTRL_MASK; @@ -3448,11 +3499,6 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)  		dwc->gadget->ep0->maxpacket = 64;  		dwc->gadget->speed = USB_SPEED_FULL;  		break; -	case DWC3_DSTS_LOWSPEED: -		dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(8); -		dwc->gadget->ep0->maxpacket = 8; -		dwc->gadget->speed = USB_SPEED_LOW; -		break;  	}  	dwc->eps[1]->endpoint.maxpacket = dwc->gadget->ep0->maxpacket; @@ -3460,6 +3506,7 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)  	/* Enable USB2 LPM Capability */  	if (!DWC3_VER_IS_WITHIN(DWC3, ANY, 194A) && +	    !dwc->usb2_gadget_lpm_disable &&  	    (speed != DWC3_DSTS_SUPERSPEED) &&  	    (speed != DWC3_DSTS_SUPERSPEED_PLUS)) {  		reg = dwc3_readl(dwc->regs, DWC3_DCFG); @@ -3486,6 +3533,12 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)  		dwc3_gadget_dctl_write_safe(dwc, reg);  	} else { +		if (dwc->usb2_gadget_lpm_disable) { +			reg = dwc3_readl(dwc->regs, DWC3_DCFG); +			reg &= ~DWC3_DCFG_LPM_CAP; +			dwc3_writel(dwc->regs, DWC3_DCFG, reg); +		} +  		reg = dwc3_readl(dwc->regs, DWC3_DCTL);  		reg &= ~DWC3_DCTL_HIRD_THRES_MASK;  		dwc3_gadget_dctl_write_safe(dwc, reg); @@ -3934,7 +3987,7 @@ int dwc3_gadget_init(struct dwc3 *dwc)  	dwc->gadget->ssp_rate		= USB_SSP_GEN_UNKNOWN;  	dwc->gadget->sg_supported	= true;  	dwc->gadget->name		= "dwc3-gadget"; -	dwc->gadget->lpm_capable	= true; +	dwc->gadget->lpm_capable	= !dwc->usb2_gadget_lpm_disable;  	/*  	 * FIXME We might be setting max_speed to <SUPER, however versions | 
