firmware/br-ext-chip-goke/board/gk7205v200/kernel/patches/00_drivers-usb-dwc3-gadget....

977 lines
26 KiB
Diff

--- linux-4.9.37/drivers/usb/dwc3/gadget.c 2017-07-12 16:42:41.000000000 +0300
+++ linux-4.9.y/drivers/usb/dwc3/gadget.c 2021-06-07 13:01:34.000000000 +0300
@@ -35,6 +35,15 @@
#include "gadget.h"
#include "io.h"
+static void dwc3_gadget_sync_connected_status(struct dwc3 *dwc);
+static int __dwc3_gadget_get_frame(struct dwc3 *dwc);
+static void dwc3_gadget_endpoint_frame_from_event(struct dwc3_ep *dep,
+ const struct dwc3_event_depevt *event);
+static bool __dwc3_gadget_target_frame_elapsed(struct dwc3_ep *dep);
+
+#define DWC3_ALIGN_FRAME(d) (((d)->frame_number + (d)->interval) \
+ & ~((d)->interval - 1))
+
/**
* dwc3_gadget_set_test_mode - Enables USB2 Test Modes
* @dwc: pointer to our context structure
@@ -139,9 +148,6 @@
udelay(5);
}
- dwc3_trace(trace_dwc3_gadget,
- "link state change request timed out");
-
return -ETIMEDOUT;
}
@@ -153,7 +159,7 @@
* if it is point to the link TRB, wrap around to the beginning. The
* link TRB is always at the last TRB entry.
*/
-static void dwc3_ep_inc_trb(u8 *index)
+static void dwc3_ep_inc_trb(u32 *index)
{
(*index)++;
if (*index == (DWC3_TRB_NUM - 1))
@@ -247,7 +253,7 @@
struct dwc3_gadget_ep_cmd_params *params)
{
struct dwc3 *dwc = dep->dwc;
- u32 timeout = 500;
+ u32 timeout = 5000;
u32 reg;
int cmd_status = 0;
@@ -563,8 +569,6 @@
u32 reg;
int ret;
- dwc3_trace(trace_dwc3_gadget, "Enabling %s", dep->name);
-
if (!(dep->flags & DWC3_EP_ENABLED)) {
ret = dwc3_gadget_start_config(dwc, dep);
if (ret)
@@ -590,7 +594,7 @@
dwc3_writel(dwc->regs, DWC3_DALEPENA, reg);
if (usb_endpoint_xfer_control(desc))
- return 0;
+ goto out;
/* Initialize the TRB ring */
dep->trb_dequeue = 0;
@@ -608,15 +612,19 @@
trb_link->ctrl |= DWC3_TRB_CTRL_HWO;
}
+
+out:
+ trace_dwc3_gadget_ep_enable(dep);
+
return 0;
}
-static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force);
+static void dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force);
static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep)
{
struct dwc3_request *req;
- dwc3_stop_active_transfer(dwc, dep->number, true);
+ dwc3_stop_active_transfer(dep, true);
/* - giveback all requests to gadget driver */
while (!list_empty(&dep->started_list)) {
@@ -645,7 +653,7 @@
struct dwc3 *dwc = dep->dwc;
u32 reg;
- dwc3_trace(trace_dwc3_gadget, "Disabling %s", dep->name);
+ trace_dwc3_gadget_ep_disable(dep);
dwc3_remove_requests(dwc, dep);
@@ -787,10 +795,7 @@
struct dwc3 *dwc = dep->dwc;
struct usb_gadget *gadget = &dwc->gadget;
enum usb_device_speed speed = gadget->speed;
-
- dwc3_trace(trace_dwc3_gadget, "%s: req %p dma %08llx length %d%s",
- dep->name, req, (unsigned long long) dma,
- length, chain ? " chain" : "");
+ unsigned int chain_skip = 0;
trb = &dep->trb_pool[dep->trb_enqueue];
@@ -816,12 +821,55 @@
case USB_ENDPOINT_XFER_ISOC:
if (!node) {
trb->ctrl = DWC3_TRBCTL_ISOCHRONOUS_FIRST;
-
+ /*
+ * USB Specification 2.0 Section 5.9.2 states that: "If
+ * there is only a single transaction in the microframe,
+ * only a DATA0 data packet PID is used. If there are
+ * two transactions per microframe, DATA1 is used for
+ * the first transaction data packet and DATA0 is used
+ * for the second transaction data packet. If there are
+ * three transactions per microframe, DATA2 is used for
+ * the first transaction data packet, DATA1 is used for
+ * the second, and DATA0 is used for the third."
+ *
+ * IOW, we should satisfy the following cases:
+ *
+ * 1) length <= maxpacket
+ * - DATA0
+ *
+ * 2) maxpacket < length <= (2 * maxpacket)
+ * - DATA1, DATA0
+ *
+ * 3) (2 * maxpacket) < length <= (3 * maxpacket)
+ * - DATA2, DATA1, DATA0
+ */
if (speed == USB_SPEED_HIGH) {
struct usb_ep *ep = &dep->endpoint;
- trb->size |= DWC3_TRB_SIZE_PCM1(ep->mult - 1);
+ //unsigned int mult = ep->mult - 1;
+ unsigned int mult = 2; //backport commit ec5bb87e4e2a1d3a35563a7bcfac9febf67aba9d
+ unsigned int maxp = usb_endpoint_maxp(ep->desc);
+
+ if (length <= (2 * maxp))
+ mult--;
+
+ if (length <= maxp)
+ mult--;
+
+ trb->size |= DWC3_TRB_SIZE_PCM1(mult);
+
+ /*
+ * If there are three transactions per mframe,
+ * and each transcation length = 1024B, no any
+ * chain trb needed, so skip it.
+ */
+ if (length == (3 * maxp))
+ chain_skip = 1;
}
+
+ if (speed == USB_SPEED_SUPER)
+ chain_skip = 1;
} else {
+ chain_skip = 1;
trb->ctrl = DWC3_TRBCTL_ISOCHRONOUS;
}
@@ -848,7 +896,7 @@
(dwc3_calc_trbs_left(dep) == 0))
trb->ctrl |= DWC3_TRB_CTRL_IOC | DWC3_TRB_CTRL_ISP_IMI;
- if (chain)
+ if ((!chain_skip) && chain)
trb->ctrl |= DWC3_TRB_CTRL_CHN;
if (usb_endpoint_xfer_bulk(dep->endpoint.desc) && dep->stream_capable)
@@ -868,9 +916,9 @@
* index is 0, we will wrap backwards, skip the link TRB, and return
* the one just before that.
*/
-static struct dwc3_trb *dwc3_ep_prev_trb(struct dwc3_ep *dep, u8 index)
+static struct dwc3_trb *dwc3_ep_prev_trb(struct dwc3_ep *dep, u32 index)
{
- u8 tmp = index;
+ u32 tmp = index;
if (!tmp)
tmp = DWC3_TRB_NUM - 1;
@@ -881,7 +929,7 @@
static u32 dwc3_calc_trbs_left(struct dwc3_ep *dep)
{
struct dwc3_trb *tmp;
- u8 trbs_left;
+ u32 trbs_left;
/*
* If enqueue & dequeue are equal than it is either full or empty.
@@ -910,11 +958,13 @@
static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep,
struct dwc3_request *req)
{
+ struct dwc3 *dwc = dep->dwc;
+ struct usb_gadget *gadget = &dwc->gadget;
+ enum usb_device_speed speed = gadget->speed;
struct scatterlist *sg = req->sg;
struct scatterlist *s;
- unsigned int length;
+ unsigned int length, i;
dma_addr_t dma;
- int i;
for_each_sg(sg, s, req->num_pending_sgs, i) {
unsigned chain = true;
@@ -925,8 +975,11 @@
if (sg_is_last(s))
chain = false;
- dwc3_prepare_one_trb(dep, req, dma, length,
- chain, i);
+ if ((speed == USB_SPEED_HIGH) &&
+ usb_endpoint_xfer_isoc(dep->endpoint.desc))
+ dwc3_prepare_one_trb(dep, req, dma, length, chain, 0);
+ else
+ dwc3_prepare_one_trb(dep, req, dma, length, chain, i);
if (!dwc3_calc_trbs_left(dep))
break;
@@ -994,11 +1047,22 @@
memset(&params, 0, sizeof(params));
- if (starting) {
+ if (starting && !(dep->flags&DWC3_EP_UPDATE)) {
params.param0 = upper_32_bits(req->trb_dma);
params.param1 = lower_32_bits(req->trb_dma);
- cmd = DWC3_DEPCMD_STARTTRANSFER |
- DWC3_DEPCMD_PARAM(cmd_param);
+
+ if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
+ while (__dwc3_gadget_target_frame_elapsed(dep))
+ dep->frame_number = DWC3_ALIGN_FRAME(dep);
+
+ dep->frame_number = DWC3_ALIGN_FRAME(dep);
+ cmd_param = dep->frame_number;
+ }
+
+ cmd = DWC3_DEPCMD_STARTTRANSFER | DWC3_DEPCMD_PARAM(cmd_param);
+
+ if (usb_endpoint_xfer_isoc(dep->endpoint.desc))
+ dep->flags |= DWC3_EP_UPDATE;
} else {
cmd = DWC3_DEPCMD_UPDATETRANSFER |
DWC3_DEPCMD_PARAM(dep->resource_index);
@@ -1027,34 +1091,36 @@
return 0;
}
-static void __dwc3_gadget_start_isoc(struct dwc3 *dwc,
- struct dwc3_ep *dep, u32 cur_uf)
-{
- u32 uf;
+static bool __dwc3_gadget_target_frame_elapsed(struct dwc3_ep *dep) {
+ u16 cframe = __dwc3_gadget_get_frame(dep->dwc);
+ u16 eframe = dep->frame_number & DWC3_EVENT_PRAM_SOFFN_MASK;
+
+ if (eframe == cframe)
+ return true;
+
+ return (((eframe - cframe) & DWC3_EVENT_PRAM_SOFFN_MASK)
+ > DWC3_EVENT_PRAM_MAX_SOFFN / 2);
+}
+static void __dwc3_gadget_start_isoc(struct dwc3_ep *dep)
+{
if (list_empty(&dep->pending_list)) {
- dwc3_trace(trace_dwc3_gadget,
- "ISOC ep %s run out for requests",
- dep->name);
dep->flags |= DWC3_EP_PENDING_REQUEST;
return;
}
- /* 4 micro frames in the future */
- uf = cur_uf + dep->interval * 4;
+ while (__dwc3_gadget_target_frame_elapsed(dep))
+ dep->frame_number = DWC3_ALIGN_FRAME(dep);
- __dwc3_gadget_kick_transfer(dep, uf);
+ dep->frame_number = DWC3_ALIGN_FRAME(dep);
+ __dwc3_gadget_kick_transfer(dep, dep->frame_number);
}
-static void dwc3_gadget_start_isoc(struct dwc3 *dwc,
- struct dwc3_ep *dep, const struct dwc3_event_depevt *event)
+static void dwc3_gadget_start_isoc(struct dwc3_ep *dep,
+ const struct dwc3_event_depevt *event)
{
- u32 cur_uf, mask;
-
- mask = ~(dep->interval - 1);
- cur_uf = event->parameters & mask;
-
- __dwc3_gadget_start_isoc(dwc, dep, cur_uf);
+ dwc3_gadget_endpoint_frame_from_event(dep, event);
+ __dwc3_gadget_start_isoc(dep);
}
static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
@@ -1063,16 +1129,15 @@
int ret;
if (!dep->endpoint.desc) {
- dwc3_trace(trace_dwc3_gadget,
- "trying to queue request %p to disabled %s",
- &req->request, dep->endpoint.name);
+ dev_err(dwc->dev, "%s: can't queue to disabled endpoint\n",
+ dep->name);
return -ESHUTDOWN;
}
if (WARN(req->dep != dep, "request %pK belongs to '%s'\n",
&req->request, req->dep->name)) {
- dwc3_trace(trace_dwc3_gadget, "request %pK belongs to '%s'",
- &req->request, req->dep->name);
+ dev_err(dwc->dev, "%s: request %p belongs to '%s'\n",
+ dep->name, &req->request, req->dep->name);
return -EINVAL;
}
@@ -1106,7 +1171,7 @@
if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
if ((dep->flags & DWC3_EP_PENDING_REQUEST) &&
list_empty(&dep->started_list)) {
- dwc3_stop_active_transfer(dwc, dep->number, true);
+ dwc3_stop_active_transfer(dep, true);
dep->flags = DWC3_EP_ENABLED;
}
return 0;
@@ -1116,10 +1181,6 @@
return 0;
ret = __dwc3_gadget_kick_transfer(dep, 0);
- if (ret && ret != -EBUSY)
- dwc3_trace(trace_dwc3_gadget,
- "%s: failed to kick transfers",
- dep->name);
if (ret == -EBUSY)
ret = 0;
@@ -1138,7 +1199,6 @@
struct usb_request *request;
struct usb_ep *ep = &dep->endpoint;
- dwc3_trace(trace_dwc3_gadget, "queueing ZLP");
request = dwc3_gadget_ep_alloc_request(ep, GFP_ATOMIC);
if (!request)
return -ENOMEM;
@@ -1197,6 +1257,10 @@
spin_lock_irqsave(&dwc->lock, flags);
+
+ if (list_empty(&dep->pending_list) && list_empty(&dep->started_list) )
+ goto out0 ;
+
list_for_each_entry(r, &dep->pending_list, list) {
if (r == req)
break;
@@ -1209,7 +1273,7 @@
}
if (r == req) {
/* wait until it is processed */
- dwc3_stop_active_transfer(dwc, dep->number, true);
+ dwc3_stop_active_transfer(dep, true);
goto out1;
}
dev_err(dwc->dev, "request %pK was not queued to %s\n",
@@ -1247,9 +1311,6 @@
unsigned transfer_in_flight;
unsigned started;
- if (dep->flags & DWC3_EP_STALL)
- return 0;
-
if (dep->number > 1)
trb = dwc3_ep_prev_trb(dep, dep->trb_enqueue);
else
@@ -1260,9 +1321,6 @@
if (!protocol && ((dep->direction && transfer_in_flight) ||
(!dep->direction && started))) {
- dwc3_trace(trace_dwc3_gadget,
- "%s: pending request, cannot halt",
- dep->name);
return -EAGAIN;
}
@@ -1274,8 +1332,6 @@
else
dep->flags |= DWC3_EP_STALL;
} else {
- if (!(dep->flags & DWC3_EP_STALL))
- return 0;
ret = dwc3_send_clear_stall_ep_cmd(dep);
if (ret)
@@ -1355,15 +1411,21 @@
/* -------------------------------------------------------------------------- */
-static int dwc3_gadget_get_frame(struct usb_gadget *g)
+static int __dwc3_gadget_get_frame(struct dwc3 *dwc)
{
- struct dwc3 *dwc = gadget_to_dwc(g);
u32 reg;
reg = dwc3_readl(dwc->regs, DWC3_DSTS);
return DWC3_DSTS_SOFFN(reg);
}
+static int dwc3_gadget_get_frame(struct usb_gadget *g)
+{
+ struct dwc3 *dwc = gadget_to_dwc(g);
+
+ return __dwc3_gadget_get_frame(dwc);
+}
+
static int __dwc3_gadget_wakeup(struct dwc3 *dwc)
{
int retries;
@@ -1384,10 +1446,8 @@
speed = reg & DWC3_DSTS_CONNECTSPD;
if ((speed == DWC3_DSTS_SUPERSPEED) ||
- (speed == DWC3_DSTS_SUPERSPEED_PLUS)) {
- dwc3_trace(trace_dwc3_gadget, "no wakeup on SuperSpeed");
+ (speed == DWC3_DSTS_SUPERSPEED_PLUS))
return 0;
- }
link_state = DWC3_DSTS_USBLNKST(reg);
@@ -1396,9 +1456,6 @@
case DWC3_LINK_STATE_U3: /* in HS, means SUSPEND */
break;
default:
- dwc3_trace(trace_dwc3_gadget,
- "can't wakeup from '%s'",
- dwc3_gadget_link_string(link_state));
return -EINVAL;
}
@@ -1503,11 +1560,6 @@
if (!timeout)
return -ETIMEDOUT;
- dwc3_trace(trace_dwc3_gadget, "gadget %s data soft-%s",
- dwc->gadget_driver
- ? dwc->gadget_driver->function : "no-function",
- is_on ? "connect" : "disconnect");
-
return 0;
}
@@ -1677,6 +1729,7 @@
/* begin to receive SETUP packets */
dwc->ep0state = EP0_SETUP_PHASE;
+ dwc->link_state = DWC3_LINK_STATE_SS_DIS;
dwc3_ep0_out_start(dwc);
dwc3_gadget_enable_irq(dwc);
@@ -1767,6 +1820,81 @@
.udc_stop = dwc3_gadget_stop,
};
+static int dwc3_gadget_init_hw_all_endpoints(struct dwc3 *dwc)
+{
+ struct dwc3_ep *dep;
+ struct dwc3_hwparams *parms = &dwc->hwparams;
+ u32 direction = dwc->eps_directions;
+ u8 num_eps = DWC3_NUM_EPS(parms);
+ u8 num_in_eps = 0;
+ u8 num_out_eps = 0;
+ u8 epnum = 0;
+ u8 i;
+
+ if (!direction)
+ direction = DWC3_EPS_DEFAULT_DIRECTIONS;
+
+ for (i = 0; i < num_eps; i++) {
+ if (direction & 0x1)
+ epnum = (num_in_eps++ << 1) + 1;
+ else
+ epnum = (num_out_eps++ << 1);
+
+ dep = kzalloc(sizeof(*dep), GFP_KERNEL);
+ if (!dep)
+ return -ENOMEM;
+
+ dep->dwc = dwc;
+ dep->number = epnum;
+ dep->direction = !!(direction & 0x1);
+ dep->regs = dwc->regs + DWC3_DEP_BASE(i);
+ dwc->eps[i] = dep;
+
+ snprintf(dep->name, sizeof(dep->name), "ep%d%s", epnum >> 1,
+ (epnum & 1) ? "in" : "out");
+
+ dep->endpoint.name = dep->name;
+ spin_lock_init(&dep->lock);
+
+ if (epnum == 0 || epnum == 1) {
+ usb_ep_set_maxpacket_limit(&dep->endpoint, 512);
+ dep->endpoint.maxburst = 1;
+ dep->endpoint.ops = &dwc3_gadget_ep0_ops;
+ if (!epnum)
+ dwc->gadget.ep0 = &dep->endpoint;
+ } else {
+ int ret;
+
+ usb_ep_set_maxpacket_limit(&dep->endpoint, 1024);
+ dep->endpoint.max_streams = 15;
+ dep->endpoint.ops = &dwc3_gadget_ep_ops;
+ list_add_tail(&dep->endpoint.ep_list,
+ &dwc->gadget.ep_list);
+
+ ret = dwc3_alloc_trb_pool(dep);
+ if (ret)
+ return ret;
+ }
+
+ if (epnum == 0 || epnum == 1) {
+ dep->endpoint.caps.type_control = true;
+ } else {
+ dep->endpoint.caps.type_iso = true;
+ dep->endpoint.caps.type_bulk = true;
+ dep->endpoint.caps.type_int = true;
+ }
+
+ dep->endpoint.caps.dir_in = !!(direction & 0x1);
+ dep->endpoint.caps.dir_out = !(direction & 0x1);
+ direction = (direction >> 1);
+
+ INIT_LIST_HEAD(&dep->pending_list);
+ INIT_LIST_HEAD(&dep->started_list);
+ }
+
+ return 0;
+}
+
/* -------------------------------------------------------------------------- */
static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,
@@ -1794,8 +1922,6 @@
dep->endpoint.name = dep->name;
spin_lock_init(&dep->lock);
- dwc3_trace(trace_dwc3_gadget, "initializing %s", dep->name);
-
if (epnum == 0 || epnum == 1) {
usb_ep_set_maxpacket_limit(&dep->endpoint, 512);
dep->endpoint.maxburst = 1;
@@ -1840,17 +1966,24 @@
INIT_LIST_HEAD(&dwc->gadget.ep_list);
+ if (dwc->eps_new_init) {
+ ret = dwc3_gadget_init_hw_all_endpoints(dwc);
+ if (ret < 0) {
+ dev_err(dwc->dev, "failed to initialize OUT endpoints\n");
+ return ret;
+ }
+ return 0;
+ }
+
ret = dwc3_gadget_init_hw_endpoints(dwc, dwc->num_out_eps, 0);
if (ret < 0) {
- dwc3_trace(trace_dwc3_gadget,
- "failed to allocate OUT endpoints");
+ dev_err(dwc->dev, "failed to initialize OUT endpoints\n");
return ret;
}
ret = dwc3_gadget_init_hw_endpoints(dwc, dwc->num_in_eps, 1);
if (ret < 0) {
- dwc3_trace(trace_dwc3_gadget,
- "failed to allocate IN endpoints");
+ dev_err(dwc->dev, "failed to initialize IN endpoints\n");
return ret;
}
@@ -1886,14 +2019,12 @@
/* -------------------------------------------------------------------------- */
-static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep,
- struct dwc3_request *req, struct dwc3_trb *trb,
- const struct dwc3_event_depevt *event, int status,
- int chain)
+static int __dwc3_cleanup_done_trbs(struct dwc3_ep *dep, struct dwc3_request *req,
+ struct dwc3_trb *trb, const struct dwc3_event_depevt *event,
+ int status, int chain)
{
unsigned int count;
unsigned int s_pkt = 0;
- unsigned int trb_status;
dwc3_ep_inc_deq(dep);
@@ -1922,37 +2053,6 @@
req->request.actual += count;
if (dep->direction) {
- if (count) {
- trb_status = DWC3_TRB_SIZE_TRBSTS(trb->size);
- if (trb_status == DWC3_TRBSTS_MISSED_ISOC) {
- dwc3_trace(trace_dwc3_gadget,
- "%s: incomplete IN transfer",
- dep->name);
- /*
- * If missed isoc occurred and there is
- * no request queued then issue END
- * TRANSFER, so that core generates
- * next xfernotready and we will issue
- * a fresh START TRANSFER.
- * If there are still queued request
- * then wait, do not issue either END
- * or UPDATE TRANSFER, just attach next
- * request in pending_list during
- * giveback.If any future queued request
- * is successfully transferred then we
- * will issue UPDATE TRANSFER for all
- * request in the pending_list.
- */
- dep->flags |= DWC3_EP_MISSED_ISOC;
- } else {
- dev_err(dwc->dev, "incomplete IN transfer %s\n",
- dep->name);
- status = -ECONNRESET;
- }
- } else {
- dep->flags &= ~DWC3_EP_MISSED_ISOC;
- }
- } else {
if (count && (event->status & DEPEVT_STATUS_SHORT))
s_pkt = 1;
}
@@ -1967,7 +2067,7 @@
return 0;
}
-static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
+static int dwc3_cleanup_done_reqs(struct dwc3_ep *dep,
const struct dwc3_event_depevt *event, int status)
{
struct dwc3_request *req, *n;
@@ -1994,14 +2094,14 @@
req->sg = sg_next(s);
req->num_pending_sgs--;
- ret = __dwc3_cleanup_done_trbs(dwc, dep, req, trb,
+ ret = __dwc3_cleanup_done_trbs(dep, req, trb,
event, status, chain);
if (ret)
break;
}
} else {
trb = &dep->trb_pool[dep->trb_dequeue];
- ret = __dwc3_cleanup_done_trbs(dwc, dep, req, trb,
+ ret = __dwc3_cleanup_done_trbs(dep, req, trb,
event, status, chain);
}
@@ -2045,9 +2145,9 @@
* flag, so that END TRANSFER is issued when an
* entry is added into request list.
*/
- dep->flags = DWC3_EP_PENDING_REQUEST;
+ dep->flags |= DWC3_EP_PENDING_REQUEST;
} else {
- dwc3_stop_active_transfer(dwc, dep->number, true);
+ dwc3_stop_active_transfer(dep, true);
dep->flags = DWC3_EP_ENABLED;
}
return 1;
@@ -2059,19 +2159,28 @@
return 1;
}
-static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc,
- struct dwc3_ep *dep, const struct dwc3_event_depevt *event)
+static void dwc3_gadget_endpoint_frame_from_event(struct dwc3_ep *dep,
+ const struct dwc3_event_depevt *event)
+{
+ dep->frame_number = event->parameters;
+}
+
+static void dwc3_endpoint_transfer_complete(struct dwc3_ep *dep,
+ const struct dwc3_event_depevt *event)
{
+ struct dwc3 *dwc = dep->dwc;
unsigned status = 0;
int clean_busy;
u32 is_xfer_complete;
+ dwc3_gadget_endpoint_frame_from_event(dep, event);
+
is_xfer_complete = (event->endpoint_event == DWC3_DEPEVT_XFERCOMPLETE);
if (event->status & DEPEVT_STATUS_BUSERR)
status = -ECONNRESET;
- clean_busy = dwc3_cleanup_done_reqs(dwc, dep, event, status);
+ clean_busy = dwc3_cleanup_done_reqs(dep, event, status);
if (clean_busy && (!dep->endpoint.desc || is_xfer_complete ||
usb_endpoint_xfer_isoc(dep->endpoint.desc)))
dep->flags &= ~DWC3_EP_BUSY;
@@ -2109,12 +2218,16 @@
if (!dep->endpoint.desc)
return;
- if (!usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
+ if (!usb_endpoint_xfer_isoc(dep->endpoint.desc) || (dep->flags&DWC3_EP_ENABLED)) {
int ret;
-
- ret = __dwc3_gadget_kick_transfer(dep, 0);
- if (!ret || ret == -EBUSY)
- return;
+ if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
+ (!(dep->flags & (DWC3_EP_BUSY | DWC3_EP_UPDATE)))) {
+ __dwc3_gadget_start_isoc(dep);
+ } else {
+ ret = __dwc3_gadget_kick_transfer(dep, 0);
+ if (!ret || ret == -EBUSY)
+ return;
+ }
}
}
@@ -2139,37 +2252,24 @@
dep->resource_index = 0;
if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
- dwc3_trace(trace_dwc3_gadget,
- "%s is an Isochronous endpoint",
- dep->name);
+ dev_err(dwc->dev, "XferComplete for Isochronous endpoint\n");
return;
}
- dwc3_endpoint_transfer_complete(dwc, dep, event);
+ dwc3_endpoint_transfer_complete(dep, event);
break;
case DWC3_DEPEVT_XFERINPROGRESS:
- dwc3_endpoint_transfer_complete(dwc, dep, event);
+ dwc3_endpoint_transfer_complete(dep, event);
break;
case DWC3_DEPEVT_XFERNOTREADY:
if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
- dwc3_gadget_start_isoc(dwc, dep, event);
+ dwc3_gadget_start_isoc(dep, event);
} else {
- int active;
int ret;
- active = event->status & DEPEVT_STATUS_TRANSFER_ACTIVE;
-
- dwc3_trace(trace_dwc3_gadget, "%s: reason %s",
- dep->name, active ? "Transfer Active"
- : "Transfer Not Active");
-
ret = __dwc3_gadget_kick_transfer(dep, 0);
if (!ret || ret == -EBUSY)
return;
-
- dwc3_trace(trace_dwc3_gadget,
- "%s: failed to kick transfers",
- dep->name);
}
break;
@@ -2179,26 +2279,9 @@
dep->name);
return;
}
-
- switch (event->status) {
- case DEPEVT_STREAMEVT_FOUND:
- dwc3_trace(trace_dwc3_gadget,
- "Stream %d found and started",
- event->parameters);
-
- break;
- case DEPEVT_STREAMEVT_NOTFOUND:
- /* FALLTHROUGH */
- default:
- dwc3_trace(trace_dwc3_gadget,
- "unable to find suitable stream");
- }
break;
case DWC3_DEPEVT_RXTXFIFOEVT:
- dwc3_trace(trace_dwc3_gadget, "%s FIFO Overrun", dep->name);
- break;
case DWC3_DEPEVT_EPCMDCMPLT:
- dwc3_trace(trace_dwc3_gadget, "Endpoint Command Complete");
break;
}
}
@@ -2242,15 +2325,13 @@
}
}
-static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force)
+static void dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force)
{
- struct dwc3_ep *dep;
+ struct dwc3 *dwc = dep->dwc;
struct dwc3_gadget_ep_cmd_params params;
u32 cmd;
int ret;
- dep = dwc->eps[epnum];
-
if (!dep->resource_index)
return;
@@ -2596,8 +2677,6 @@
(pwropt != DWC3_GHWPARAMS1_EN_PWROPT_HIB)) {
if ((dwc->link_state == DWC3_LINK_STATE_U3) &&
(next == DWC3_LINK_STATE_RESUME)) {
- dwc3_trace(trace_dwc3_gadget,
- "ignoring transition U3 -> Resume");
return;
}
}
@@ -2731,11 +2810,7 @@
break;
case DWC3_DEVICE_EVENT_EOPF:
/* It changed to be suspend event for version 2.30a and above */
- if (dwc->revision < DWC3_REVISION_230A) {
- dwc3_trace(trace_dwc3_gadget, "End of Periodic Frame");
- } else {
- dwc3_trace(trace_dwc3_gadget, "U3/L1-L2 Suspend Event");
-
+ if (dwc->revision >= DWC3_REVISION_230A) {
/*
* Ignore suspend event until the gadget enters into
* USB_STATE_CONFIGURED state.
@@ -2746,26 +2821,21 @@
}
break;
case DWC3_DEVICE_EVENT_SOF:
- dwc3_trace(trace_dwc3_gadget, "Start of Periodic Frame");
- break;
case DWC3_DEVICE_EVENT_ERRATIC_ERROR:
- dwc3_trace(trace_dwc3_gadget, "Erratic Error");
- break;
case DWC3_DEVICE_EVENT_CMD_CMPL:
- dwc3_trace(trace_dwc3_gadget, "Command Complete");
- break;
case DWC3_DEVICE_EVENT_OVERFLOW:
- dwc3_trace(trace_dwc3_gadget, "Overflow");
break;
+
default:
dev_WARN(dwc->dev, "UNKNOWN IRQ %d\n", event->type);
}
+ dwc3_gadget_sync_connected_status(dwc);
}
static void dwc3_process_event_entry(struct dwc3 *dwc,
const union dwc3_event *event)
{
- trace_dwc3_event(event->raw);
+ trace_dwc3_event(event->raw, dwc);
/* Endpoint IRQ, handle it and return early */
if (event->type.is_devspec == 0) {
@@ -2984,8 +3054,7 @@
* composite.c that we are USB 2.0 + LPM ECN.
*/
if (dwc->revision < DWC3_REVISION_220A)
- dwc3_trace(trace_dwc3_gadget,
- "Changing max_speed on rev %08x",
+ dev_info(dwc->dev, "changing max_speed on rev %08x\n",
dwc->revision);
dwc->gadget.max_speed = dwc->maximum_speed;
@@ -3005,6 +3074,8 @@
if (ret)
goto err5;
+ dwc3_proc_init(dwc);
+
ret = usb_add_gadget_udc(dwc->dev, &dwc->gadget);
if (ret) {
dev_err(dwc->dev, "failed to register udc\n");
@@ -3042,6 +3113,8 @@
{
usb_del_gadget_udc(&dwc->gadget);
+ dwc3_proc_shutdown(dwc);
+
dwc3_gadget_free_endpoints(dwc);
dma_free_coherent(dwc->dev, DWC3_EP0_BOUNCE_SIZE,
@@ -3106,3 +3179,70 @@
enable_irq(dwc->irq_gadget);
}
}
+
+/*
+ * dwc3_gadget_sync_connected_status() function just for
+ * user space get udc connected status. and this function
+ * just report three status: Disconnected, Connected host,
+ * Connected charger.
+ *
+ * After some tests, report connected udc connected status by
+ * DSTS register, [21:18]USB Link Status and [2:0] Connect Speed.
+ *
+ * How to identify whitch status is the UDC connected?
+ * 1. Host connected:
+ * Host would reset udc, so dwc3 core get reset event interrupt,
+ * dwc3_gadget_reset_interrupt() set dwc->connected = true,
+ * so check connected host by dwc->connected == true
+ *
+ * 2. Disconnected:
+ * When vbus detect 5V lose, dwc3 core generated a disconnect event intr.
+ * dwc3_gadget_disconnect_interrupt() set dwc->connected = false.
+ * so check disconnected by dwc->connected == false
+ *
+ * 3. Charger connected: (Fixedme)
+ * As dwc3 core size, DP keep pullup register when connected to charger.
+ * no any port reset action created, so dwc3 would entry FullSpeed mode.
+ * so chect connected charger by FullSpeed && dwc->connectd == false
+ *
+ */
+static void dwc3_gadget_sync_connected_status(struct dwc3 *dwc)
+{
+ u32 reg;
+ u8 speed;
+ u8 state;
+ static int prev = UDC_DISCONNECTED;
+
+ reg = dwc3_readl(dwc->regs, DWC3_DSTS);
+ speed = reg & DWC3_DSTS_CONNECTSPD;
+ state = DWC3_DSTS_USBLNKST(reg);
+
+ /*
+ * step1 check is connected host?
+ */
+ if (dwc->connected == true) {
+ if (prev != UDC_CONNECT_HOST)
+ dwc->udc_connect_status = UDC_CONNECT_HOST;
+ goto out;
+ }
+
+ /*
+ * step2 disconectd status && fullspeed mode,
+ * as connected charger.
+ */
+ if ((speed == DWC3_DSTS_FULLSPEED) && (state != DWC3_LINK_STATE_SS_DIS)) {
+ if (prev != UDC_CONNECT_CHARGER)
+ dwc->udc_connect_status = UDC_CONNECT_CHARGER;
+ goto out;
+ }
+
+ /*
+ * step3 not host and charger connected, so just
+ * disconnectd.
+ */
+ if (prev != UDC_DISCONNECTED)
+ dwc->udc_connect_status = UDC_DISCONNECTED;
+
+out:
+ prev = dwc->udc_connect_status;
+}