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)
{
struct dwc3_ep *dep;
struct dwc3_ep *dep = NULL;
u32 windex = le16_to_cpu(wIndex_le);
u32 epnum;
u32 epnum, ep_index;
u8 num, direction;
epnum = (windex & USB_ENDPOINT_NUMBER_MASK) << 1;
if ((windex & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)
epnum |= 1;
epnum = windex & USB_ENDPOINT_NUMBER_MASK;
direction = windex & USB_ENDPOINT_DIR_MASK;
ep_index = 0;
dep = dwc->eps[epnum];
if (!dep) {
dev_warn(dwc->dev, "epnum %d, windex 0x%08x\n", epnum, windex);
return NULL;
for (num = 0; num < dwc->num_eps; num++) {
dep = dwc->eps[num];
if (!dep) {
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 NULL;

View File

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