From 256fb7670af430bea6be8b05f6449d2c838dfb8f Mon Sep 17 00:00:00 2001 From: William Wu Date: Fri, 5 Jul 2019 15:09:19 +0800 Subject: [PATCH] usb: dwc3: gadget: support to resize TxFIFOs dynamically We need to dynamically resize the TxFIFOs for some cases where the default values don't match. Test on RK1808-stick board, configurate the usb with four functions "rndis, ntb, mass_storage, acm", the default values of TxFIFOs is: GTXFIFOSIZ(0) = 0x00000042 GTXFIFOSIZ(1) = 0x00420184 GTXFIFOSIZ(2) = 0x01c60184 GTXFIFOSIZ(3) = 0x034a0184 GTXFIFOSIZ(4) = 0x04ce0184 GTXFIFOSIZ(5) = 0x06520184 GTXFIFOSIZ(6) = 0x07d6002a The ep6-in is used for acm ep-in which maxpacket is 1024B, but the default fifo size of ep6-in is only 336B, less than the length of the ep maxpacket, it cause acm works abnormally. This patch creates a simple function to allocate enough TxFIFO space for each of the enabled endpoints. Change-Id: I389ffdba4f3721ed6ef192f0c85f41fdeff645ce Signed-off-by: William Wu --- drivers/usb/dwc3/core.c | 2 + drivers/usb/dwc3/core.h | 2 + drivers/usb/dwc3/gadget.c | 82 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index d95c6be576b4..21f7c8e43dcc 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -1048,6 +1048,8 @@ static int dwc3_probe(struct platform_device *pdev) device_property_read_u32_array(dev, "snps,grx-threshold-cfg", dwc->grxthrcfg, 2); + dwc->needs_fifo_resize = device_property_read_bool(dev, + "snps,tx-fifo-resize"); /* default to superspeed if no maximum_speed passed */ if (dwc->maximum_speed == USB_SPEED_UNKNOWN) diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index ccba0662ec9e..345205acf416 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -843,6 +843,7 @@ struct dwc3_scratchpad_array { * 1 - -3.5dB de-emphasis * 2 - No de-emphasis * 3 - Reserved + * @needs_fifo_resize: set if we want to resize TXFIFO. */ struct dwc3 { struct usb_ctrlrequest *ctrl_req; @@ -995,6 +996,7 @@ struct dwc3 { unsigned tx_de_emphasis_quirk:1; unsigned tx_de_emphasis:2; + unsigned needs_fifo_resize:1; }; /* -------------------------------------------------------------------------- */ diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index adf7b07f820a..5f890de12a13 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -145,6 +145,86 @@ 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. + */ +static int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc) +{ + int last_fifo_depth = 0; + int fifo_size; + int mdwidth; + u8 num; + + if (!dwc->needs_fifo_resize) + return 0; + + mdwidth = DWC3_MDWIDTH(dwc->hwparams.hwparams0); + + /* MDWIDTH is represented in bits, we need it in bytes */ + mdwidth >>= 3; + + for (num = 0; num < dwc->num_in_eps; num++) { + u8 epnum = (num << 1) | 1; + struct dwc3_ep *dep = dwc->eps[epnum]; + int fifo_number = dep->number >> 1; + int mult = 1; + int tmp; + + if (!(dep->flags & DWC3_EP_ENABLED)) + continue; + + if (usb_endpoint_xfer_bulk(dep->endpoint.desc) || + usb_endpoint_xfer_isoc(dep->endpoint.desc)) + mult = 3; + + /* + * REVISIT: the following assumes we will always have enough + * space available on the FIFO RAM for all possible use cases. + * Make sure that's true somehow and change FIFO allocation + * accordingly. + * + * If we have Bulk or Isochronous endpoints, we want + * them to be able to be very, very fast. So we're giving + * those endpoints a fifo_size which is enough for 3 full + * packets + */ + tmp = mult * (dep->endpoint.maxpacket + mdwidth); + tmp += mdwidth; + + fifo_size = DIV_ROUND_UP(tmp, mdwidth); + + fifo_size |= (last_fifo_depth << 16); + + dev_dbg(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; +} + /** * dwc3_ep_inc_trb() - Increment a TRB index. * @index - Pointer to the TRB index to increment. @@ -714,6 +794,8 @@ static int dwc3_gadget_ep_enable(struct usb_ep *ep, ret = __dwc3_gadget_ep_enable(dep, desc, ep->comp_desc, false, false); spin_unlock_irqrestore(&dwc->lock, flags); + dwc3_gadget_resize_tx_fifos(dwc); + return ret; }