mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 11:50:43 +09:00
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:
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user