From d6b0925fc8bd507afea9ff18ff849f7dc1227acb Mon Sep 17 00:00:00 2001 From: Frank Wang Date: Wed, 8 Jun 2022 15:43:49 +0800 Subject: [PATCH] usb: dwc3: resize tx fifos for rockchip platform Due to TX FIFO size limits on Rockchip platform, we need to resize TX FIFOs more precisely based on USB transfer type and Speed, so implement the private method hooked to the original function. If you want to enable the Tx fifos resize on rockchip platform, add the property "tx-fifo-resize" in DTS usbdrd_dwc3 node. By default, we recommend not to enable the Tx fifo resize, because the default TxFIFO depth configuration in the GTXFIFOSIZ(#n) is enough for most of USB composite device. And for mult UVC function (e.g 2 * UVC + 1 * UAC + ADB), it needs to enable the Tx fifo resize for UVC streaming endpoints with 1024 maxpacket. Note that, the Tx fifos resize code only assign 64 bytes TxFIFO depth for interrupt endpoint which usually used for MTP and HID function. If you want to support HID EP-IN to transfer maxpacket more than 64 bytes, you need to change the maxpacket of usb_endpoint_xfer_int(dep->endpoint.desc) in the __dwc3_gadget_resize_tx_fifos(). Signed-off-by: Frank Wang Signed-off-by: William Wu Change-Id: I8ff1ed206ac423e9076c8054eb07138658720f25 --- drivers/usb/dwc3/gadget.c | 98 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 623afe6ba90f..7589bcdc9a27 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -748,6 +748,101 @@ void dwc3_gadget_clear_tx_fifos(struct dwc3 *dwc) dwc->num_ep_resized = 0; } +/** + * __dwc3_gadget_resize_tx_fifos - reallocate fifo spaces for Rockchip platform + * + * @dep: pointer to dwc3_ep structure + * + * According to the different USB transfer type and Speed, + * 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. + */ +static int __dwc3_gadget_resize_tx_fifos(struct dwc3_ep *dep) +{ + struct dwc3 *dwc = dep->dwc; + u32 fifo_0_start, last_fifo_depth, ram1_depth; + u32 fifo_size, maxpacket, mdwidth, mult; + u32 tmp; + + if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) { + /* + * Set enough tx fifos for Isochronous endpoints to get better + * performance and more compliance with bus latency. + */ + maxpacket = dep->endpoint.maxpacket; + if (gadget_is_superspeed(dwc->gadget)) + mult = dep->endpoint.mult * dep->endpoint.maxburst; + else + mult = dep->endpoint.mult; + + mult = mult > 0 ? mult * 2 : 3; + if (mult > 6) + mult = 6; + } else if (usb_endpoint_xfer_bulk(dep->endpoint.desc)) { + /* + * Set enough tx fifos for Bulk endpoints to get + * better transmission performance. + */ + mult = 3; + if (gadget_is_superspeed(dwc->gadget)) { + if (dep->endpoint.maxburst > mult) { + mult = dep->endpoint.maxburst; + if (mult > 6) + mult = 6; + } + maxpacket = 1024; + } else { + maxpacket = 512; + } + } else if (usb_endpoint_xfer_int(dep->endpoint.desc)) { + /* + * REVIST: we assume that the maxpacket of interrupt + * endpoint is 64 Bytes for MTP and the other functions. + */ + mult = 1; + maxpacket = 64; + } else { + goto out; + } + + mdwidth = dwc3_mdwidth(dwc); + mdwidth >>= 3; /* bits convert to bytes */ + ram1_depth = dwc3_gadget_get_tx_fifos_size(dwc); + last_fifo_depth = dwc->last_fifo_depth; + + /* Calculate the fifo size for this EP */ + tmp = mult * (maxpacket + mdwidth); + tmp += mdwidth; + fifo_size = DIV_ROUND_UP(tmp, mdwidth); + + /* Check if TXFIFOs start at non-zero addr */ + tmp = dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(0)); + fifo_0_start = DWC3_GTXFIFOSIZ_TXFSTADDR(tmp); + fifo_size |= (fifo_0_start + (last_fifo_depth << 16)); + + if (DWC3_IP_IS(DWC3)) + last_fifo_depth += DWC3_GTXFIFOSIZ_TXFDEP(fifo_size); + else + last_fifo_depth += DWC31_GTXFIFOSIZ_TXFDEP(fifo_size); + + /* Check fifo size allocation doesn't exceed available RAM size. */ + if (last_fifo_depth >= ram1_depth) { + dev_err(dwc->dev, "Fifosize(0x%x) > RAM size(0x%x) %s depth(0x%x)\n", + last_fifo_depth, ram1_depth, + dep->endpoint.name, fifo_size & 0xfff); + return -ENOMEM; + } + + dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(dep->number >> 1), fifo_size); + dep->flags |= DWC3_EP_TXFIFO_RESIZED; + dwc->last_fifo_depth = last_fifo_depth; + dwc->num_ep_resized++; + +out: + return 0; +} + /* * dwc3_gadget_resize_tx_fifos - reallocate fifo spaces for current use-case * @dwc: pointer to our context structure @@ -793,6 +888,9 @@ static int dwc3_gadget_resize_tx_fifos(struct dwc3_ep *dep) if (dep->flags & DWC3_EP_TXFIFO_RESIZED) return 0; + if (IS_REACHABLE(CONFIG_ARCH_ROCKCHIP)) + return __dwc3_gadget_resize_tx_fifos(dep); + ram1_depth = dwc3_gadget_get_tx_fifos_size(dwc); if ((dep->endpoint.maxburst > 1 &&