diff options
| -rw-r--r-- | drivers/usb/dwc3/core.c | 5 | ||||
| -rw-r--r-- | drivers/usb/dwc3/core.h | 16 | ||||
| -rw-r--r-- | drivers/usb/dwc3/ep0.c | 11 | ||||
| -rw-r--r-- | drivers/usb/dwc3/gadget.c | 74 | 
4 files changed, 104 insertions, 2 deletions
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 7c9df630dbe..d119a1fbf94 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -48,6 +48,7 @@  #include <linux/list.h>  #include <linux/delay.h>  #include <linux/dma-mapping.h> +#include <linux/of.h>  #include <linux/usb/ch9.h>  #include <linux/usb/gadget.h> @@ -404,6 +405,7 @@ static void dwc3_core_exit(struct dwc3 *dwc)  static int __devinit dwc3_probe(struct platform_device *pdev)  { +	struct device_node	*node = pdev->dev.of_node;  	struct resource		*res;  	struct dwc3		*dwc; @@ -469,6 +471,9 @@ static int __devinit dwc3_probe(struct platform_device *pdev)  	else  		dwc->maximum_speed = DWC3_DCFG_SUPERSPEED; +	if (of_get_property(node, "tx-fifo-resize", NULL)) +		dwc->needs_fifo_resize = true; +  	pm_runtime_enable(&pdev->dev);  	pm_runtime_get_sync(&pdev->dev);  	pm_runtime_forbid(&pdev->dev); diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index f4878c4dec0..123c3aa4712 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -172,6 +172,10 @@  #define DWC3_GUSB3PIPECTL_PHYSOFTRST (1 << 31)  #define DWC3_GUSB3PIPECTL_SUSPHY (1 << 17) +/* Global TX Fifo Size Register */ +#define DWC3_GTXFIFOSIZ_TXFDEF(n) ((n) & 0xffff) +#define DWC3_GTXFIFOSIZ_TXFSTADDR(n) ((n) & 0xffff0000) +  /* Global HWPARAMS1 Register */  #define DWC3_GHWPARAMS1_EN_PWROPT(n)	((n & (3 << 24)) >> 24)  #define DWC3_GHWPARAMS1_EN_PWROPT_NO	0 @@ -546,8 +550,13 @@ struct dwc3_hwparams {  #define DWC3_MODE_DRD		2  #define DWC3_MODE_HUB		3 +#define DWC3_MDWIDTH(n)		(((n) & 0xff00) >> 8) +  /* HWPARAMS1 */ -#define DWC3_NUM_INT(n)	(((n) & (0x3f << 15)) >> 15) +#define DWC3_NUM_INT(n)		(((n) & (0x3f << 15)) >> 15) + +/* HWPARAMS7 */ +#define DWC3_RAM1_DEPTH(n)	((n) & 0xffff)  struct dwc3_request {  	struct usb_request	request; @@ -594,6 +603,8 @@ struct dwc3_request {   * @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.   * @ep0_next_event: hold the next expected event   * @ep0state: state of endpoint zero   * @link_state: link state @@ -651,6 +662,8 @@ struct dwc3 {  	unsigned		start_config_issued:1;  	unsigned		setup_packet_pending:1;  	unsigned		delayed_status:1; +	unsigned		needs_fifo_resize:1; +	unsigned		resize_fifos:1;  	enum dwc3_ep0_next	ep0_next_event;  	enum dwc3_ep0_state	ep0state; @@ -812,6 +825,7 @@ union dwc3_event {  /* prototypes */  void dwc3_set_mode(struct dwc3 *dwc, u32 mode); +int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc);  int dwc3_host_init(struct dwc3 *dwc);  void dwc3_host_exit(struct dwc3 *dwc); diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index e90ebb9dd3e..5104dbf4668 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -457,8 +457,11 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)  	case DWC3_ADDRESS_STATE:  		ret = dwc3_ep0_delegate_req(dwc, ctrl);  		/* if the cfg matches and the cfg is non zero */ -		if (cfg && (!ret || (ret == USB_GADGET_DELAYED_STATUS))) +		if (cfg && (!ret || (ret == USB_GADGET_DELAYED_STATUS))) {  			dwc->dev_state = DWC3_CONFIGURED_STATE; +			dwc->resize_fifos = true; +			dev_dbg(dwc->dev, "resize fifos flag SET\n"); +		}  		break;  	case DWC3_CONFIGURED_STATE: @@ -707,6 +710,12 @@ static void dwc3_ep0_do_control_status(struct dwc3 *dwc, u32 epnum)  {  	struct dwc3_ep		*dep = dwc->eps[epnum]; +	if (dwc->resize_fifos) { +		dev_dbg(dwc->dev, "starting to resize fifos\n"); +		dwc3_gadget_resize_tx_fifos(dwc); +		dwc->resize_fifos = 0; +	} +  	WARN_ON(dwc3_ep0_start_control_status(dep));  } diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index d406a75456a..7913d1b50e3 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -125,6 +125,80 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state)  	return -ETIMEDOUT;  } +/** + * dwc3_gadget_resize_tx_fifos - reallocate fifo spaces for current use-case + * @dwc: pointer to our context structure + * + * This function will a best effort FIFO allocation in order + * to improve FIFO usage and throughput, while still allowing + * us to enable as many endpoints as possible. + * + * Keep in mind that this operation will be highly dependent + * on the configured size for RAM1 - which contains TxFifo -, + * the amount of endpoints enabled on coreConsultant tool, and + * the width of the Master Bus. + * + * In the ideal world, we would always be able to satisfy the + * following equation: + * + * ((512 + 2 * MDWIDTH-Bytes) + (Number of IN Endpoints - 1) * \ + * (3 * (1024 + MDWIDTH-Bytes) + MDWIDTH-Bytes)) / MDWIDTH-Bytes + * + * Unfortunately, due to many variables that's not always the case. + */ +int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc) +{ +	int		last_fifo_depth = 0; +	int		ram1_depth; +	int		fifo_size; +	int		mdwidth; +	int		num; + +	if (!dwc->needs_fifo_resize) +		return 0; + +	ram1_depth = DWC3_RAM1_DEPTH(dwc->hwparams.hwparams7); +	mdwidth = DWC3_MDWIDTH(dwc->hwparams.hwparams0); + +	/* MDWIDTH is represented in bits, we need it in bytes */ +	mdwidth >>= 3; + +	/* +	 * FIXME For now we will only allocate 1 wMaxPacketSize space +	 * for each enabled endpoint, later patches will come to +	 * 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; +		int		tmp; + +		if (!(dep->number & 1)) +			continue; + +		if (!(dep->flags & DWC3_EP_ENABLED)) +			continue; + +		tmp = dep->endpoint.maxpacket; +		tmp += mdwidth; +		tmp += mdwidth; + +		fifo_size = DIV_ROUND_UP(tmp, mdwidth); +		fifo_size |= (last_fifo_depth << 16); + +		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); + +		last_fifo_depth += (fifo_size & 0xffff); +	} + +	return 0; +} +  void dwc3_map_buffer_to_dma(struct dwc3_request *req)  {  	struct dwc3			*dwc = req->dep->dwc;  |