usb: dwc3: gadget: fix ep init for unequal num of in/out eps

Some SoCs have different number of endpoints between the EP-IN
and EP-OUT (e.g. RK3399/RV1126 have 7 in endpoints and 6 out
endpoints), it will fail to init all of the endpoints.

In my test case, I use RV1126 dwc3 to support 3 UVC functions
at the same time, and each UVC function need one in endpoint
for control interface and one in endpoint for streaming interface,
so it needs to init 7 in endpoints (include ep0-in) in this case.
Without this patch, it will fail to init the ep7-in because
it set the wrong DWC3_DEP_BASE for ep7-in.

According to dwc3 databook, the register DALEPENA and the "USB
Endpoint Number" field of Parameter1 are doing 1:1 mapping for
endpoints, meaning physical endpoints 2 maps to logical endpoint
2:
Bit[0]: USB EP0-OUT
Bit[1]: USB EP0-IN
Bit[2]: USB EP1-OUT
Bit[3]: USB EP1-IN
...
Bit[13]: USB EP7-IN

The dwc3 driver use dep->number to index endpoint number and init
the DALEPENA and the "USB Endpoint Number" field of Parameter1.
For RV1126, it should set dep->number to 13 for EP7-IN.

But the registers DEPCMDPAR2(#n),DEPCMDPAR1(#n), DEPCMDPAR0(#n),
and DEPCMD(#n) don't 1:1 mapping for endpoints. For RV1126, it
should set #n to 12 for EP7-IN. And the event->endpoint_number
in the dwc3_endpoint_interrupt() is equal to 12 for EP7-IN.

Fixes: c2185009e2 ("usb: dwc3: gadget: fix init endpoints and resize tx fifos")
Change-Id: I0898306196f4dacf09b0de3cf4d76d9026b6315c
Signed-off-by: William Wu <william.wu@rock-chips.com>
This commit is contained in:
William Wu
2020-07-30 11:51:17 +08:00
committed by Tao Huang
parent db245aeba5
commit 49b5c0d29f
2 changed files with 43 additions and 33 deletions

View File

@@ -283,21 +283,33 @@ void dwc3_ep0_out_start(struct dwc3 *dwc)
static struct dwc3_ep *dwc3_wIndex_to_dep(struct dwc3 *dwc, __le16 wIndex_le) static struct dwc3_ep *dwc3_wIndex_to_dep(struct dwc3 *dwc, __le16 wIndex_le)
{ {
struct dwc3_ep *dep; struct dwc3_ep *dep = NULL;
u32 windex = le16_to_cpu(wIndex_le); u32 windex = le16_to_cpu(wIndex_le);
u32 epnum; u32 epnum, ep_index;
u8 num, direction;
epnum = (windex & USB_ENDPOINT_NUMBER_MASK) << 1; epnum = windex & USB_ENDPOINT_NUMBER_MASK;
if ((windex & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) direction = windex & USB_ENDPOINT_DIR_MASK;
epnum |= 1; ep_index = 0;
dep = dwc->eps[epnum]; for (num = 0; num < dwc->num_eps; num++) {
if (!dep) { dep = dwc->eps[num];
dev_warn(dwc->dev, "epnum %d, windex 0x%08x\n", epnum, windex); if (!dep) {
return NULL; dev_warn(dwc->dev, "dep is NULL, num %d, windex 0x%08x\n",
num, windex);
return NULL;
}
if ((direction == USB_DIR_IN && dep->direction) ||
(direction == USB_DIR_OUT && !dep->direction))
ep_index++;
if (ep_index == epnum + 1)
break;
} }
if (dep->flags & DWC3_EP_ENABLED)
if (dep && (dep->flags & DWC3_EP_ENABLED))
return dep; return dep;
return NULL; return NULL;

View File

@@ -162,27 +162,26 @@ static int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc)
int last_fifo_depth; int last_fifo_depth;
int fifo_size; int fifo_size;
int mdwidth; int mdwidth;
u8 num, num_in_eps; u8 num, fifo_number;
if (!dwc->needs_fifo_resize) if (!dwc->needs_fifo_resize)
return 0; return 0;
num_in_eps = DWC3_NUM_IN_EPS(&dwc->hwparams);
mdwidth = DWC3_MDWIDTH(dwc->hwparams.hwparams0); mdwidth = DWC3_MDWIDTH(dwc->hwparams.hwparams0);
/* MDWIDTH is represented in bits, we need it in bytes */ /* MDWIDTH is represented in bits, we need it in bytes */
mdwidth >>= 3; mdwidth >>= 3;
fifo_number = 0;
fifo_size = dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(0)); fifo_size = dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(0));
last_fifo_depth = DWC3_GTXFIFOSIZ_TXFSTADDR(fifo_size) >> 16; last_fifo_depth = DWC3_GTXFIFOSIZ_TXFSTADDR(fifo_size) >> 16;
for (num = 0; num < num_in_eps; num++) { for (num = 0; num < dwc->num_eps; num++) {
u8 epnum = (num << 1) | 1; struct dwc3_ep *dep = dwc->eps[num];
struct dwc3_ep *dep = dwc->eps[epnum];
int fifo_number = dep->number >> 1;
int mult = 1; int mult = 1;
int tmp; int tmp;
if (!(dep->flags & DWC3_EP_ENABLED)) /* Skip out endpoints */
if (!dep || !dep->direction ||
!(dep->flags & DWC3_EP_ENABLED))
continue; continue;
if (usb_endpoint_xfer_bulk(dep->endpoint.desc)) { if (usb_endpoint_xfer_bulk(dep->endpoint.desc)) {
@@ -217,6 +216,7 @@ static int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc)
fifo_size); fifo_size);
last_fifo_depth += (fifo_size & 0xffff); last_fifo_depth += (fifo_size & 0xffff);
fifo_number++;
} }
return 0; return 0;
@@ -2360,13 +2360,24 @@ static int dwc3_gadget_init_endpoint(struct dwc3 *dwc, u8 epnum)
bool direction = epnum & 1; bool direction = epnum & 1;
int ret; int ret;
u8 num = epnum >> 1; u8 num = epnum >> 1;
u8 num_in_eps, num_out_eps;
num_in_eps = DWC3_NUM_IN_EPS(&dwc->hwparams);
num_out_eps = dwc->num_eps - num_in_eps;
dep = kzalloc(sizeof(*dep), GFP_KERNEL); dep = kzalloc(sizeof(*dep), GFP_KERNEL);
if (!dep) if (!dep)
return -ENOMEM; return -ENOMEM;
/* reconfig direction and num if num_out_eps != num_in_eps */
if ((!direction && ((epnum >> 1) + 1) > num_out_eps) ||
(direction && ((epnum >> 1) + 1) > num_in_eps)) {
direction = !direction;
num = num + (epnum & 1);
}
dep->dwc = dwc; dep->dwc = dwc;
dep->number = epnum; dep->number = num << 1 | direction;
dep->direction = direction; dep->direction = direction;
dep->regs = dwc->regs + DWC3_DEP_BASE(epnum); dep->regs = dwc->regs + DWC3_DEP_BASE(epnum);
dwc->eps[epnum] = dep; dwc->eps[epnum] = dep;
@@ -2407,25 +2418,12 @@ static int dwc3_gadget_init_endpoint(struct dwc3 *dwc, u8 epnum)
static int dwc3_gadget_init_endpoints(struct dwc3 *dwc, u8 total) static int dwc3_gadget_init_endpoints(struct dwc3 *dwc, u8 total)
{ {
u8 epnum, num; u8 epnum;
u8 num_in_eps, num_out_eps;
bool direction;
num_in_eps = DWC3_NUM_IN_EPS(&dwc->hwparams);
num_out_eps = total - num_in_eps;
INIT_LIST_HEAD(&dwc->gadget.ep_list); INIT_LIST_HEAD(&dwc->gadget.ep_list);
for (epnum = 0; epnum < total; epnum++) { for (epnum = 0; epnum < total; epnum++) {
int ret; int ret;
direction = epnum & 1;
num = (epnum >> 1) + 1;
if ((!direction && num > num_out_eps) ||
(direction && num > num_in_eps)) {
total++;
continue;
}
ret = dwc3_gadget_init_endpoint(dwc, epnum); ret = dwc3_gadget_init_endpoint(dwc, epnum);
if (ret) if (ret)