|
@@ -385,24 +385,66 @@ static void dwc3_free_trb_pool(struct dwc3_ep *dep)
|
|
|
dep->trb_pool_dma = 0;
|
|
|
}
|
|
|
|
|
|
+static int dwc3_gadget_set_xfer_resource(struct dwc3 *dwc, struct dwc3_ep *dep);
|
|
|
+
|
|
|
+/**
|
|
|
+ * dwc3_gadget_start_config - Configure EP resources
|
|
|
+ * @dwc: pointer to our controller context structure
|
|
|
+ * @dep: endpoint that is being enabled
|
|
|
+ *
|
|
|
+ * The assignment of transfer resources cannot perfectly follow the
|
|
|
+ * data book due to the fact that the controller driver does not have
|
|
|
+ * all knowledge of the configuration in advance. It is given this
|
|
|
+ * information piecemeal by the composite gadget framework after every
|
|
|
+ * SET_CONFIGURATION and SET_INTERFACE. Trying to follow the databook
|
|
|
+ * programming model in this scenario can cause errors. For two
|
|
|
+ * reasons:
|
|
|
+ *
|
|
|
+ * 1) The databook says to do DEPSTARTCFG for every SET_CONFIGURATION
|
|
|
+ * and SET_INTERFACE (8.1.5). This is incorrect in the scenario of
|
|
|
+ * multiple interfaces.
|
|
|
+ *
|
|
|
+ * 2) The databook does not mention doing more DEPXFERCFG for new
|
|
|
+ * endpoint on alt setting (8.1.6).
|
|
|
+ *
|
|
|
+ * The following simplified method is used instead:
|
|
|
+ *
|
|
|
+ * All hardware endpoints can be assigned a transfer resource and this
|
|
|
+ * setting will stay persistent until either a core reset or
|
|
|
+ * hibernation. So whenever we do a DEPSTARTCFG(0) we can go ahead and
|
|
|
+ * do DEPXFERCFG for every hardware endpoint as well. We are
|
|
|
+ * guaranteed that there are as many transfer resources as endpoints.
|
|
|
+ *
|
|
|
+ * This function is called for each endpoint when it is being enabled
|
|
|
+ * but is triggered only when called for EP0-out, which always happens
|
|
|
+ * first, and which should only happen in one of the above conditions.
|
|
|
+ */
|
|
|
static int dwc3_gadget_start_config(struct dwc3 *dwc, struct dwc3_ep *dep)
|
|
|
{
|
|
|
struct dwc3_gadget_ep_cmd_params params;
|
|
|
u32 cmd;
|
|
|
+ int i;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ if (dep->number)
|
|
|
+ return 0;
|
|
|
|
|
|
memset(¶ms, 0x00, sizeof(params));
|
|
|
+ cmd = DWC3_DEPCMD_DEPSTARTCFG;
|
|
|
|
|
|
- if (dep->number != 1) {
|
|
|
- cmd = DWC3_DEPCMD_DEPSTARTCFG;
|
|
|
- /* XferRscIdx == 0 for ep0 and 2 for the remaining */
|
|
|
- if (dep->number > 1) {
|
|
|
- if (dwc->start_config_issued)
|
|
|
- return 0;
|
|
|
- dwc->start_config_issued = true;
|
|
|
- cmd |= DWC3_DEPCMD_PARAM(2);
|
|
|
- }
|
|
|
+ ret = dwc3_send_gadget_ep_cmd(dwc, 0, cmd, ¶ms);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
|
|
|
- return dwc3_send_gadget_ep_cmd(dwc, 0, cmd, ¶ms);
|
|
|
+ for (i = 0; i < DWC3_ENDPOINTS_NUM; i++) {
|
|
|
+ struct dwc3_ep *dep = dwc->eps[i];
|
|
|
+
|
|
|
+ if (!dep)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ ret = dwc3_gadget_set_xfer_resource(dwc, dep);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
@@ -516,10 +558,6 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
|
|
|
struct dwc3_trb *trb_st_hw;
|
|
|
struct dwc3_trb *trb_link;
|
|
|
|
|
|
- ret = dwc3_gadget_set_xfer_resource(dwc, dep);
|
|
|
- if (ret)
|
|
|
- return ret;
|
|
|
-
|
|
|
dep->endpoint.desc = desc;
|
|
|
dep->comp_desc = comp_desc;
|
|
|
dep->type = usb_endpoint_type(desc);
|
|
@@ -1636,8 +1674,6 @@ static int dwc3_gadget_start(struct usb_gadget *g,
|
|
|
}
|
|
|
dwc3_writel(dwc->regs, DWC3_DCFG, reg);
|
|
|
|
|
|
- dwc->start_config_issued = false;
|
|
|
-
|
|
|
/* Start with SuperSpeed Default */
|
|
|
dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
|
|
|
|
|
@@ -2237,7 +2273,6 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc)
|
|
|
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
|
|
|
|
|
|
dwc3_disconnect_gadget(dwc);
|
|
|
- dwc->start_config_issued = false;
|
|
|
|
|
|
dwc->gadget.speed = USB_SPEED_UNKNOWN;
|
|
|
dwc->setup_packet_pending = false;
|
|
@@ -2288,7 +2323,6 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
|
|
|
|
|
|
dwc3_stop_active_transfers(dwc);
|
|
|
dwc3_clear_stall_all_ep(dwc);
|
|
|
- dwc->start_config_issued = false;
|
|
|
|
|
|
/* Reset device address to zero */
|
|
|
reg = dwc3_readl(dwc->regs, DWC3_DCFG);
|