From 4552a0ca61cb2133bc77dc432ea20538ea28638a Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 24 May 2012 09:19:31 +0300 Subject: usb: dwc3: fix a WARN and a comment we're now have DWC3_EP0_BOUNCE_SIZE to tell us the actual size of the bufer. Let's use that instead of ep0 wMaxPacketSize. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/ep0.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 9e8a3dce69f..e6ca218ef13 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -821,14 +821,14 @@ static void dwc3_ep0_do_control_data(struct dwc3 *dwc, return; } - WARN_ON(req->request.length > dep->endpoint.maxpacket); + WARN_ON(req->request.length > DWC3_EP0_BOUNCE_SIZE); dwc->ep0_bounced = true; /* - * REVISIT in case request length is bigger than EP0 - * wMaxPacketSize, we will need two chained TRBs to handle - * the transfer. + * REVISIT in case request length is bigger than + * DWC3_EP0_BOUNCE_SIZE we will need two chained + * TRBs to handle the transfer. */ ret = dwc3_ep0_start_trans(dwc, event->endpoint_number, dwc->ep0_bounce_addr, dep->endpoint.maxpacket, -- cgit v1.2.3 From a0807881af93646b5d94b5594119df609e756945 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 4 May 2012 13:03:54 +0300 Subject: usb: dwc3: handle pending unaligned Control OUT data phase correctly When DWC3_EP_PENDING_REQUEST flag is set for a Control OUT Data phase transfer, we would be missing the proper handling for unaligned OUT requests, thus hanging a transfer. Since proper handling is already done on dwc3_ep0_do_control_data(), we simply re-factor that function so it can be re-used from __dwc3_gadget_ep0_queue(). Reported-by: Pratyush Anand Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/ep0.c | 72 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 43 insertions(+), 29 deletions(-) diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index e6ca218ef13..15ec36eb461 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -55,6 +55,8 @@ #include "io.h" static void dwc3_ep0_do_control_status(struct dwc3 *dwc, u32 epnum); +static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, + struct dwc3_ep *dep, struct dwc3_request *req); static const char *dwc3_ep0_state_string(enum dwc3_ep0_state state) { @@ -150,9 +152,8 @@ static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep, return 0; } - ret = dwc3_ep0_start_trans(dwc, direction, - req->request.dma, req->request.length, - DWC3_TRBCTL_CONTROL_DATA); + __dwc3_ep0_do_control_data(dwc, dwc->eps[direction], req); + dep->flags &= ~(DWC3_EP_PENDING_REQUEST | DWC3_EP0_DIR_IN); } else if (dwc->delayed_status) { @@ -787,35 +788,23 @@ static void dwc3_ep0_do_control_setup(struct dwc3 *dwc, dwc3_ep0_out_start(dwc); } -static void dwc3_ep0_do_control_data(struct dwc3 *dwc, - const struct dwc3_event_depevt *event) +static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, + struct dwc3_ep *dep, struct dwc3_request *req) { - struct dwc3_ep *dep; - struct dwc3_request *req; int ret; - dep = dwc->eps[0]; - - if (list_empty(&dep->request_list)) { - dev_vdbg(dwc->dev, "pending request for EP0 Data phase\n"); - dep->flags |= DWC3_EP_PENDING_REQUEST; - - if (event->endpoint_number) - dep->flags |= DWC3_EP0_DIR_IN; - return; - } - - req = next_request(&dep->request_list); - req->direction = !!event->endpoint_number; + req->direction = !!dep->number; if (req->request.length == 0) { - ret = dwc3_ep0_start_trans(dwc, event->endpoint_number, + ret = dwc3_ep0_start_trans(dwc, dep->number, dwc->ctrl_req_addr, 0, DWC3_TRBCTL_CONTROL_DATA); } else if ((req->request.length % dep->endpoint.maxpacket) - && (event->endpoint_number == 0)) { + && (dep->number == 0)) { + u32 transfer_size; + ret = usb_gadget_map_request(&dwc->gadget, &req->request, - event->endpoint_number); + dep->number); if (ret) { dev_dbg(dwc->dev, "failed to map request\n"); return; @@ -823,6 +812,9 @@ static void dwc3_ep0_do_control_data(struct dwc3 *dwc, WARN_ON(req->request.length > DWC3_EP0_BOUNCE_SIZE); + transfer_size = roundup(req->request.length, + (u32) dep->endpoint.maxpacket); + dwc->ep0_bounced = true; /* @@ -830,25 +822,47 @@ static void dwc3_ep0_do_control_data(struct dwc3 *dwc, * DWC3_EP0_BOUNCE_SIZE we will need two chained * TRBs to handle the transfer. */ - ret = dwc3_ep0_start_trans(dwc, event->endpoint_number, - dwc->ep0_bounce_addr, dep->endpoint.maxpacket, + ret = dwc3_ep0_start_trans(dwc, dep->number, + dwc->ep0_bounce_addr, transfer_size, DWC3_TRBCTL_CONTROL_DATA); } else { ret = usb_gadget_map_request(&dwc->gadget, &req->request, - event->endpoint_number); + dep->number); if (ret) { dev_dbg(dwc->dev, "failed to map request\n"); return; } - ret = dwc3_ep0_start_trans(dwc, event->endpoint_number, - req->request.dma, req->request.length, - DWC3_TRBCTL_CONTROL_DATA); + ret = dwc3_ep0_start_trans(dwc, dep->number, req->request.dma, + req->request.length, DWC3_TRBCTL_CONTROL_DATA); } WARN_ON(ret < 0); } +static void dwc3_ep0_do_control_data(struct dwc3 *dwc, + const struct dwc3_event_depevt *event) +{ + struct dwc3_ep *dep; + struct dwc3_request *req; + + dep = dwc->eps[0]; + + if (list_empty(&dep->request_list)) { + dev_vdbg(dwc->dev, "pending request for EP0 Data phase\n"); + dep->flags |= DWC3_EP_PENDING_REQUEST; + + if (event->endpoint_number) + dep->flags |= DWC3_EP0_DIR_IN; + return; + } + + req = next_request(&dep->request_list); + dep = dwc->eps[event->endpoint_number]; + + __dwc3_ep0_do_control_data(dwc, dep, req); +} + static int dwc3_ep0_start_control_status(struct dwc3_ep *dep) { struct dwc3 *dwc = dep->dwc; -- cgit v1.2.3 From c74c6d4a024d95e81283ee4c38be6fa7baee27f9 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 4 May 2012 13:08:22 +0300 Subject: usb: dwc3: ep0: switch over to IS_ALIGNED IS_ALIGNED provides a much faster operation for checking proper size alignment then a modulo operation. Let's use it. Reported-by: Pratyush Anand Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/ep0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 15ec36eb461..477127aecb9 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -799,7 +799,7 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, ret = dwc3_ep0_start_trans(dwc, dep->number, dwc->ctrl_req_addr, 0, DWC3_TRBCTL_CONTROL_DATA); - } else if ((req->request.length % dep->endpoint.maxpacket) + } else if (!IS_ALIGNED(req->request.length, dep->endpoint.maxpacket) && (dep->number == 0)) { u32 transfer_size; -- cgit v1.2.3 From 788a23f49686d82fa95b83ac7752d6322f1dad44 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 21 May 2012 14:22:41 +0300 Subject: usb: dwc3: ep0: align on function signature On our Transfer Not Ready handlers, only dwc3_ep0_do_control_status() had a different list of parameters. Align on the parameters in order to keep consistency. No functional changes. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/ep0.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 477127aecb9..75d5722db93 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -54,7 +54,7 @@ #include "gadget.h" #include "io.h" -static void dwc3_ep0_do_control_status(struct dwc3 *dwc, u32 epnum); +static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep); static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, struct dwc3_ep *dep, struct dwc3_request *req); @@ -160,7 +160,7 @@ static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep, dwc->delayed_status = false; if (dwc->ep0state == EP0_STATUS_PHASE) - dwc3_ep0_do_control_status(dwc, 1); + __dwc3_ep0_do_control_status(dwc, dwc->eps[1]); else dev_dbg(dwc->dev, "too early for delayed status\n"); } @@ -875,10 +875,8 @@ static int dwc3_ep0_start_control_status(struct dwc3_ep *dep) dwc->ctrl_req_addr, 0, type); } -static void dwc3_ep0_do_control_status(struct dwc3 *dwc, u32 epnum) +static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep) { - struct dwc3_ep *dep = dwc->eps[epnum]; - if (dwc->resize_fifos) { dev_dbg(dwc->dev, "starting to resize fifos\n"); dwc3_gadget_resize_tx_fifos(dwc); @@ -888,6 +886,14 @@ static void dwc3_ep0_do_control_status(struct dwc3 *dwc, u32 epnum) WARN_ON(dwc3_ep0_start_control_status(dep)); } +static void dwc3_ep0_do_control_status(struct dwc3 *dwc, + const struct dwc3_event_depevt *event) +{ + struct dwc3_ep *dep = dwc->eps[event->endpoint_number]; + + __dwc3_ep0_do_control_status(dwc, dep); +} + static void dwc3_ep0_xfernotready(struct dwc3 *dwc, const struct dwc3_event_depevt *event) { @@ -988,7 +994,7 @@ static void dwc3_ep0_xfernotready(struct dwc3 *dwc, return; } - dwc3_ep0_do_control_status(dwc, event->endpoint_number); + dwc3_ep0_do_control_status(dwc, event); } } -- cgit v1.2.3 From 33b84c2c06d25a3321326d91438e106b4fd5ad9f Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 21 May 2012 14:35:17 +0300 Subject: usb: dwc3: ep0: fix a typo in comment s/has/have. No functional changes, just a typo fix on a code comment. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/ep0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 75d5722db93..e31bcd65e7e 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -900,7 +900,7 @@ static void dwc3_ep0_xfernotready(struct dwc3 *dwc, dwc->setup_packet_pending = true; /* - * This part is very tricky: If we has just handled + * This part is very tricky: If we have just handled * XferNotReady(Setup) and we're now expecting a * XferComplete but, instead, we receive another * XferNotReady(Setup), we should STALL and restart -- cgit v1.2.3 From a092532483e3200a53c8b1170b3988cc668c07ef Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 22 May 2012 10:24:11 +0300 Subject: usb: dwc3: gadget: remove trailing semicolon That semicolon doesn't do anything, it's not needed and should be removed. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 3df1a1973b0..045799356a2 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1032,7 +1032,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) dev_dbg(dwc->dev, "%s: failed to kick transfers\n", dep->name); } - }; + } return 0; } -- cgit v1.2.3 From 2c61a8efce75951148fa07f2cd7ec53ad9d9fbb3 Mon Sep 17 00:00:00 2001 From: Paul Zimmerman Date: Wed, 15 Feb 2012 18:56:58 -0800 Subject: usb: dwc3: add definitions for new registers This patch adds definitions for some new registers that have been added to later versions of the controller, up to v2.10a. Signed-off-by: Paul Zimmerman Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.h | 94 +++++++++++++++++++++++++++++++++++++---------- drivers/usb/dwc3/gadget.h | 5 +++ 2 files changed, 80 insertions(+), 19 deletions(-) diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index f69c877add0..4d5c63dae14 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -67,6 +67,7 @@ #define DWC3_DEVICE_EVENT_CONNECT_DONE 2 #define DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE 3 #define DWC3_DEVICE_EVENT_WAKEUP 4 +#define DWC3_DEVICE_EVENT_HIBER_REQ 5 #define DWC3_DEVICE_EVENT_EOPF 6 #define DWC3_DEVICE_EVENT_SOF 7 #define DWC3_DEVICE_EVENT_ERRATIC_ERROR 9 @@ -171,28 +172,36 @@ #define DWC3_GCTL_PRTCAP_DEVICE 2 #define DWC3_GCTL_PRTCAP_OTG 3 -#define DWC3_GCTL_CORESOFTRESET (1 << 11) -#define DWC3_GCTL_SCALEDOWN(n) ((n) << 4) -#define DWC3_GCTL_SCALEDOWN_MASK DWC3_GCTL_SCALEDOWN(3) -#define DWC3_GCTL_DISSCRAMBLE (1 << 3) -#define DWC3_GCTL_DSBLCLKGTNG (1 << 0) +#define DWC3_GCTL_CORESOFTRESET (1 << 11) +#define DWC3_GCTL_SCALEDOWN(n) ((n) << 4) +#define DWC3_GCTL_SCALEDOWN_MASK DWC3_GCTL_SCALEDOWN(3) +#define DWC3_GCTL_DISSCRAMBLE (1 << 3) +#define DWC3_GCTL_GBLHIBERNATIONEN (1 << 1) +#define DWC3_GCTL_DSBLCLKGTNG (1 << 0) /* Global USB2 PHY Configuration Register */ -#define DWC3_GUSB2PHYCFG_PHYSOFTRST (1 << 31) -#define DWC3_GUSB2PHYCFG_SUSPHY (1 << 6) +#define DWC3_GUSB2PHYCFG_PHYSOFTRST (1 << 31) +#define DWC3_GUSB2PHYCFG_SUSPHY (1 << 6) /* Global USB3 PIPE Control Register */ -#define DWC3_GUSB3PIPECTL_PHYSOFTRST (1 << 31) -#define DWC3_GUSB3PIPECTL_SUSPHY (1 << 17) +#define DWC3_GUSB3PIPECTL_PHYSOFTRST (1 << 31) +#define DWC3_GUSB3PIPECTL_SUSPHY (1 << 17) /* Global TX Fifo Size Register */ -#define DWC3_GTXFIFOSIZ_TXFDEF(n) ((n) & 0xffff) -#define DWC3_GTXFIFOSIZ_TXFSTADDR(n) ((n) & 0xffff0000) +#define DWC3_GTXFIFOSIZ_TXFDEF(n) ((n) & 0xffff) +#define DWC3_GTXFIFOSIZ_TXFSTADDR(n) ((n) & 0xffff0000) /* Global HWPARAMS1 Register */ #define DWC3_GHWPARAMS1_EN_PWROPT(n) (((n) & (3 << 24)) >> 24) #define DWC3_GHWPARAMS1_EN_PWROPT_NO 0 #define DWC3_GHWPARAMS1_EN_PWROPT_CLK 1 +#define DWC3_GHWPARAMS1_EN_PWROPT_HIB 2 +#define DWC3_GHWPARAMS1_PWROPT(n) ((n) << 24) +#define DWC3_GHWPARAMS1_PWROPT_MASK DWC3_GHWPARAMS1_PWROPT(3) + +/* Global HWPARAMS4 Register */ +#define DWC3_GHWPARAMS4_HIBER_SCRATCHBUFS(n) (((n) & (0x0f << 13)) >> 13) +#define DWC3_MAX_HIBER_SCRATCHBUFS 15 /* Device Configuration Register */ #define DWC3_DCFG_LPM_CAP (1 << 22) @@ -206,6 +215,8 @@ #define DWC3_DCFG_LOWSPEED (2 << 0) #define DWC3_DCFG_FULLSPEED1 (3 << 0) +#define DWC3_DCFG_LPM_CAP (1 << 22) + /* Device Control Register */ #define DWC3_DCTL_RUN_STOP (1 << 31) #define DWC3_DCTL_CSFTRST (1 << 30) @@ -216,14 +227,20 @@ #define DWC3_DCTL_APPL1RES (1 << 23) -#define DWC3_DCTL_TRGTULST_MASK (0x0f << 17) -#define DWC3_DCTL_TRGTULST(n) ((n) << 17) - -#define DWC3_DCTL_TRGTULST_U2 (DWC3_DCTL_TRGTULST(2)) -#define DWC3_DCTL_TRGTULST_U3 (DWC3_DCTL_TRGTULST(3)) -#define DWC3_DCTL_TRGTULST_SS_DIS (DWC3_DCTL_TRGTULST(4)) -#define DWC3_DCTL_TRGTULST_RX_DET (DWC3_DCTL_TRGTULST(5)) -#define DWC3_DCTL_TRGTULST_SS_INACT (DWC3_DCTL_TRGTULST(6)) +/* These apply for core versions 1.87a and earlier */ +#define DWC3_DCTL_TRGTULST_MASK (0x0f << 17) +#define DWC3_DCTL_TRGTULST(n) ((n) << 17) +#define DWC3_DCTL_TRGTULST_U2 (DWC3_DCTL_TRGTULST(2)) +#define DWC3_DCTL_TRGTULST_U3 (DWC3_DCTL_TRGTULST(3)) +#define DWC3_DCTL_TRGTULST_SS_DIS (DWC3_DCTL_TRGTULST(4)) +#define DWC3_DCTL_TRGTULST_RX_DET (DWC3_DCTL_TRGTULST(5)) +#define DWC3_DCTL_TRGTULST_SS_INACT (DWC3_DCTL_TRGTULST(6)) + +/* These apply for core versions 1.94a and later */ +#define DWC3_DCTL_KEEP_CONNECT (1 << 19) +#define DWC3_DCTL_L1_HIBER_EN (1 << 18) +#define DWC3_DCTL_CRS (1 << 17) +#define DWC3_DCTL_CSS (1 << 16) #define DWC3_DCTL_INITU2ENA (1 << 12) #define DWC3_DCTL_ACCEPTU2ENA (1 << 11) @@ -249,6 +266,7 @@ #define DWC3_DEVTEN_ERRTICERREN (1 << 9) #define DWC3_DEVTEN_SOFEN (1 << 7) #define DWC3_DEVTEN_EOPFEN (1 << 6) +#define DWC3_DEVTEN_HIBERNATIONREQEVTEN (1 << 5) #define DWC3_DEVTEN_WKUPEVTEN (1 << 4) #define DWC3_DEVTEN_ULSTCNGEN (1 << 3) #define DWC3_DEVTEN_CONNECTDONEEN (1 << 2) @@ -256,7 +274,15 @@ #define DWC3_DEVTEN_DISCONNEVTEN (1 << 0) /* Device Status Register */ +#define DWC3_DSTS_DCNRD (1 << 29) + +/* This applies for core versions 1.87a and earlier */ #define DWC3_DSTS_PWRUPREQ (1 << 24) + +/* These apply for core versions 1.94a and later */ +#define DWC3_DSTS_RSS (1 << 25) +#define DWC3_DSTS_SSS (1 << 24) + #define DWC3_DSTS_COREIDLE (1 << 23) #define DWC3_DSTS_DEVCTRLHLT (1 << 22) @@ -280,6 +306,11 @@ #define DWC3_DGCMD_SET_LMP 0x01 #define DWC3_DGCMD_SET_PERIODIC_PAR 0x02 #define DWC3_DGCMD_XMIT_FUNCTION 0x03 + +/* These apply for core versions 1.94a and later */ +#define DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO 0x04 +#define DWC3_DGCMD_SET_SCRATCHPAD_ADDR_HI 0x05 + #define DWC3_DGCMD_SELECTED_FIFO_FLUSH 0x09 #define DWC3_DGCMD_ALL_FIFO_FLUSH 0x0a #define DWC3_DGCMD_SET_ENDPOINT_NRDY 0x0c @@ -287,6 +318,15 @@ #define DWC3_DGCMD_STATUS(n) (((n) >> 15) & 1) #define DWC3_DGCMD_CMDACT (1 << 10) +#define DWC3_DGCMD_CMDIOC (1 << 8) + +/* Device Generic Command Parameter Register */ +#define DWC3_DGCMDPAR_FORCE_LINKPM_ACCEPT (1 << 0) +#define DWC3_DGCMDPAR_FIFO_NUM(n) ((n) << 0) +#define DWC3_DGCMDPAR_RX_FIFO (0 << 5) +#define DWC3_DGCMDPAR_TX_FIFO (1 << 5) +#define DWC3_DGCMDPAR_LOOPBACK_DIS (0 << 0) +#define DWC3_DGCMDPAR_LOOPBACK_ENA (1 << 0) /* Device Endpoint Command Register */ #define DWC3_DEPCMD_PARAM_SHIFT 16 @@ -303,7 +343,10 @@ #define DWC3_DEPCMD_STARTTRANSFER (0x06 << 0) #define DWC3_DEPCMD_CLEARSTALL (0x05 << 0) #define DWC3_DEPCMD_SETSTALL (0x04 << 0) +/* This applies for core versions 1.90a and earlier */ #define DWC3_DEPCMD_GETSEQNUMBER (0x03 << 0) +/* This applies for core versions 1.94a and later */ +#define DWC3_DEPCMD_GETEPSTATE (0x03 << 0) #define DWC3_DEPCMD_SETTRANSFRESOURCE (0x02 << 0) #define DWC3_DEPCMD_SETEPCONFIG (0x01 << 0) @@ -437,6 +480,8 @@ enum dwc3_link_state { DWC3_LINK_STATE_HRESET = 0x09, DWC3_LINK_STATE_CMPLY = 0x0a, DWC3_LINK_STATE_LPBK = 0x0b, + DWC3_LINK_STATE_RESET = 0x0e, + DWC3_LINK_STATE_RESUME = 0x0f, DWC3_LINK_STATE_MASK = 0x0f, }; @@ -455,6 +500,7 @@ enum dwc3_device_state { #define DWC3_TRBSTS_OK 0 #define DWC3_TRBSTS_MISSED_ISOC 1 #define DWC3_TRBSTS_SETUP_PENDING 2 +#define DWC3_TRB_STS_XFER_IN_PROG 4 /* TRB Control */ #define DWC3_TRB_CTRL_HWO (1 << 0) @@ -543,6 +589,14 @@ struct dwc3_request { unsigned queued:1; }; +/* + * struct dwc3_scratchpad_array - hibernation scratchpad array + * (format defined by hw) + */ +struct dwc3_scratchpad_array { + __le64 dma_adr[DWC3_MAX_HIBER_SCRATCHBUFS]; +}; + /** * struct dwc3 - representation of our controller * @ctrl_req: usb control request which is used for ep0 @@ -624,8 +678,10 @@ struct dwc3 { #define DWC3_REVISION_180A 0x5533180a #define DWC3_REVISION_183A 0x5533183a #define DWC3_REVISION_185A 0x5533185a +#define DWC3_REVISION_187A 0x5533187a #define DWC3_REVISION_188A 0x5533188a #define DWC3_REVISION_190A 0x5533190a +#define DWC3_REVISION_194A 0x5533194a #define DWC3_REVISION_200A 0x5533200a #define DWC3_REVISION_202A 0x5533202a #define DWC3_REVISION_210A 0x5533210a diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h index 95ef6a2f776..39ced0b0851 100644 --- a/drivers/usb/dwc3/gadget.h +++ b/drivers/usb/dwc3/gadget.h @@ -66,7 +66,12 @@ struct dwc3; #define DWC3_DEPCFG_FIFO_NUMBER(n) ((n) << 17) #define DWC3_DEPCFG_BURST_SIZE(n) ((n) << 22) #define DWC3_DEPCFG_DATA_SEQ_NUM(n) ((n) << 26) +/* This applies for core versions earlier than 1.94a */ #define DWC3_DEPCFG_IGN_SEQ_NUM (1 << 31) +/* These apply for core versions 1.94a and later */ +#define DWC3_DEPCFG_ACTION_INIT (0 << 30) +#define DWC3_DEPCFG_ACTION_RESTORE (1 << 30) +#define DWC3_DEPCFG_ACTION_MODIFY (2 << 30) /* DEPXFERCFG parameter 0 */ #define DWC3_DEPXFERCFG_NUM_XFER_RES(n) ((n) & 0xffff) -- cgit v1.2.3 From aed430e5139af3e2c251f52db7fc6c5e2ce2b714 Mon Sep 17 00:00:00 2001 From: Paul Zimmerman Date: Fri, 27 Apr 2012 12:52:01 +0300 Subject: usb: dwc3: gadget: reinitialize retries retries is used twice without being reinitialized. Signed-off-by: Paul Zimmerman Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 045799356a2..c21516aef5e 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -108,6 +108,7 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state) dwc3_writel(dwc->regs, DWC3_DCTL, reg); /* wait for a change in DSTS */ + retries = 10000; while (--retries) { reg = dwc3_readl(dwc->regs, DWC3_DSTS); -- cgit v1.2.3 From d7a46a8dfc45191b39daa19c05d3ff74d1881f15 Mon Sep 17 00:00:00 2001 From: Paul Zimmerman Date: Fri, 27 Apr 2012 12:54:05 +0300 Subject: usb: dwc3: gadget: rename phy_power() to phy_suspend() those two functions don't power PHYs, they simply put them in suspend state. Rename to reflect better what functions actually do. Signed-off-by: Paul Zimmerman Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index c21516aef5e..852bde5cc13 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1894,30 +1894,30 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc) dwc->setup_packet_pending = false; } -static void dwc3_gadget_usb3_phy_power(struct dwc3 *dwc, int on) +static void dwc3_gadget_usb3_phy_suspend(struct dwc3 *dwc, int suspend) { u32 reg; reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); - if (on) - reg &= ~DWC3_GUSB3PIPECTL_SUSPHY; - else + if (suspend) reg |= DWC3_GUSB3PIPECTL_SUSPHY; + else + reg &= ~DWC3_GUSB3PIPECTL_SUSPHY; dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); } -static void dwc3_gadget_usb2_phy_power(struct dwc3 *dwc, int on) +static void dwc3_gadget_usb2_phy_suspend(struct dwc3 *dwc, int suspend) { u32 reg; reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); - if (on) - reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; - else + if (suspend) reg |= DWC3_GUSB2PHYCFG_SUSPHY; + else + reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); } @@ -1962,9 +1962,9 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) /* after reset -> Default State */ dwc->dev_state = DWC3_DEFAULT_STATE; - /* Enable PHYs */ - dwc3_gadget_usb2_phy_power(dwc, true); - dwc3_gadget_usb3_phy_power(dwc, true); + /* Resume PHYs */ + dwc3_gadget_usb2_phy_suspend(dwc, false); + dwc3_gadget_usb3_phy_suspend(dwc, false); if (dwc->gadget.speed != USB_SPEED_UNKNOWN) dwc3_disconnect_gadget(dwc); @@ -2010,16 +2010,16 @@ static void dwc3_update_ram_clk_sel(struct dwc3 *dwc, u32 speed) dwc3_writel(dwc->regs, DWC3_GCTL, reg); } -static void dwc3_gadget_disable_phy(struct dwc3 *dwc, u8 speed) +static void dwc3_gadget_phy_suspend(struct dwc3 *dwc, u8 speed) { switch (speed) { case USB_SPEED_SUPER: - dwc3_gadget_usb2_phy_power(dwc, false); + dwc3_gadget_usb2_phy_suspend(dwc, true); break; case USB_SPEED_HIGH: case USB_SPEED_FULL: case USB_SPEED_LOW: - dwc3_gadget_usb3_phy_power(dwc, false); + dwc3_gadget_usb3_phy_suspend(dwc, true); break; } } @@ -2082,8 +2082,8 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) break; } - /* Disable unneded PHY */ - dwc3_gadget_disable_phy(dwc, dwc->gadget.speed); + /* Suspend unneded PHY */ + dwc3_gadget_phy_suspend(dwc, dwc->gadget.speed); dep = dwc->eps[0]; ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL); -- cgit v1.2.3 From 802fde983e8a3391e059bd41fc272993ae642816 Mon Sep 17 00:00:00 2001 From: Paul Zimmerman Date: Fri, 27 Apr 2012 13:10:52 +0300 Subject: usb: dwc3: support new revisions of DWC3 core Recent cores (>= 1.94a) have a set of new features, commands and a slightly different programming model. This patch aims to support those changes. Signed-off-by: Paul Zimmerman Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 83 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 70 insertions(+), 13 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 852bde5cc13..04048333ec1 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -100,6 +100,23 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state) int retries = 10000; u32 reg; + /* + * Wait until device controller is ready. Only applies to 1.94a and + * later RTL. + */ + if (dwc->revision >= DWC3_REVISION_194A) { + while (--retries) { + reg = dwc3_readl(dwc->regs, DWC3_DSTS); + if (reg & DWC3_DSTS_DCNRD) + udelay(5); + else + break; + } + + if (retries <= 0) + return -ETIMEDOUT; + } + reg = dwc3_readl(dwc->regs, DWC3_DCTL); reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK; @@ -107,6 +124,13 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state) reg |= DWC3_DCTL_ULSTCHNGREQ(state); dwc3_writel(dwc->regs, DWC3_DCTL, reg); + /* + * The following code is racy when called from dwc3_gadget_wakeup, + * and is not needed, at least on newer versions + */ + if (dwc->revision >= DWC3_REVISION_194A) + return 0; + /* wait for a change in DSTS */ retries = 10000; while (--retries) { @@ -266,8 +290,8 @@ static const char *dwc3_gadget_ep_cmd_string(u8 cmd) return "Clear Stall"; case DWC3_DEPCMD_SETSTALL: return "Set Stall"; - case DWC3_DEPCMD_GETSEQNUMBER: - return "Get Data Sequence Number"; + case DWC3_DEPCMD_GETEPSTATE: + return "Get Endpoint State"; case DWC3_DEPCMD_SETTRANSFRESOURCE: return "Set Endpoint Transfer Resource"; case DWC3_DEPCMD_SETEPCONFIG: @@ -1280,9 +1304,12 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g) goto out; } - /* write zeroes to Link Change Request */ - reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK; - dwc3_writel(dwc->regs, DWC3_DCTL, reg); + /* Recent versions do this automatically */ + if (dwc->revision < DWC3_REVISION_194A) { + /* write zeroes to Link Change Request */ + reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK; + dwc3_writel(dwc->regs, DWC3_DCTL, reg); + } /* poll until Link State changes to ON */ timeout = jiffies + msecs_to_jiffies(100); @@ -1326,9 +1353,14 @@ static void dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on) reg = dwc3_readl(dwc->regs, DWC3_DCTL); if (is_on) { - reg &= ~DWC3_DCTL_TRGTULST_MASK; - reg |= (DWC3_DCTL_RUN_STOP - | DWC3_DCTL_TRGTULST_RX_DET); + if (dwc->revision <= DWC3_REVISION_187A) { + reg &= ~DWC3_DCTL_TRGTULST_MASK; + reg |= DWC3_DCTL_TRGTULST_RX_DET; + } + + if (dwc->revision >= DWC3_REVISION_194A) + reg &= ~DWC3_DCTL_KEEP_CONNECT; + reg |= DWC3_DCTL_RUN_STOP; } else { reg &= ~DWC3_DCTL_RUN_STOP; } @@ -1468,6 +1500,7 @@ static int dwc3_gadget_stop(struct usb_gadget *g, return 0; } + static const struct usb_gadget_ops dwc3_gadget_ops = { .get_frame = dwc3_gadget_get_frame, .wakeup = dwc3_gadget_wakeup, @@ -1962,9 +1995,12 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) /* after reset -> Default State */ dwc->dev_state = DWC3_DEFAULT_STATE; - /* Resume PHYs */ - dwc3_gadget_usb2_phy_suspend(dwc, false); - dwc3_gadget_usb3_phy_suspend(dwc, false); + /* Recent versions support automatic phy suspend and don't need this */ + if (dwc->revision < DWC3_REVISION_194A) { + /* Resume PHYs */ + dwc3_gadget_usb2_phy_suspend(dwc, false); + dwc3_gadget_usb3_phy_suspend(dwc, false); + } if (dwc->gadget.speed != USB_SPEED_UNKNOWN) dwc3_disconnect_gadget(dwc); @@ -2082,8 +2118,11 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) break; } - /* Suspend unneded PHY */ - dwc3_gadget_phy_suspend(dwc, dwc->gadget.speed); + /* Recent versions support automatic phy suspend and don't need this */ + if (dwc->revision < DWC3_REVISION_194A) { + /* Suspend unneeded PHY */ + dwc3_gadget_phy_suspend(dwc, dwc->gadget.speed); + } dep = dwc->eps[0]; ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL); @@ -2389,6 +2428,24 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc) DWC3_DEVTEN_DISCONNEVTEN); dwc3_writel(dwc->regs, DWC3_DEVTEN, reg); + /* Enable USB2 LPM and automatic phy suspend only on recent versions */ + if (dwc->revision >= DWC3_REVISION_194A) { + reg = dwc3_readl(dwc->regs, DWC3_DCFG); + reg |= DWC3_DCFG_LPM_CAP; + dwc3_writel(dwc->regs, DWC3_DCFG, reg); + + reg = dwc3_readl(dwc->regs, DWC3_DCTL); + reg &= ~(DWC3_DCTL_HIRD_THRES_MASK | DWC3_DCTL_L1_HIBER_EN); + + /* TODO: This should be configurable */ + reg |= DWC3_DCTL_HIRD_THRES(31); + + dwc3_writel(dwc->regs, DWC3_DCTL, reg); + + dwc3_gadget_usb2_phy_suspend(dwc, true); + dwc3_gadget_usb3_phy_suspend(dwc, true); + } + ret = device_register(&dwc->gadget.dev); if (ret) { dev_err(dwc->dev, "failed to register gadget device\n"); -- cgit v1.2.3 From 7acd85e0eb2ed300edf123178445237059b35fb9 Mon Sep 17 00:00:00 2001 From: Paul Zimmerman Date: Fri, 27 Apr 2012 14:28:02 +0300 Subject: usb: dwc3: core: make sure evt->lpos is correctly initialized The same event buffers will be reused when coming out of hibernation, so we must reinitialize them properly to avoid any mistakes. While at that, also take dwc3_event_buffers_setup() out of __devinit section. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 1040bdb8dc8..49c060205c9 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -255,7 +255,7 @@ static int __devinit dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length) * * Returns 0 on success otherwise negative errno. */ -static int __devinit dwc3_event_buffers_setup(struct dwc3 *dwc) +static int dwc3_event_buffers_setup(struct dwc3 *dwc) { struct dwc3_event_buffer *evt; int n; @@ -266,6 +266,8 @@ static int __devinit dwc3_event_buffers_setup(struct dwc3 *dwc) evt->buf, (unsigned long long) evt->dma, evt->length); + evt->lpos = 0; + dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), lower_32_bits(evt->dma)); dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), @@ -285,6 +287,9 @@ static void dwc3_event_buffers_cleanup(struct dwc3 *dwc) for (n = 0; n < dwc->num_event_buffers; n++) { evt = dwc->ev_buffs[n]; + + evt->lpos = 0; + dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 0); dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 0); dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), 0); -- cgit v1.2.3 From fcc023c726b5879d8f3f0f0f48c45d09055272c4 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 24 May 2012 10:27:56 +0300 Subject: usb: dwc3: gadget: prevent DCTL register corruption If we don't read out the contents of the register (in order to reinitialize 'reg' variable) we will be writing unknown contents to the DCTL register whenever we try to use dwc3_gadget_wakeup() function. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 04048333ec1..867c476853e 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1307,6 +1307,7 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g) /* Recent versions do this automatically */ if (dwc->revision < DWC3_REVISION_194A) { /* write zeroes to Link Change Request */ + reg = dwc3_readl(dwc->regs, DWC3_DCTL); reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK; dwc3_writel(dwc->regs, DWC3_DCTL, reg); } -- cgit v1.2.3 From c4430a26948b84c0d820e83f8c640229f960d3b6 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 24 May 2012 10:30:01 +0300 Subject: usb: dwc3: gadget: disable U1/U2 on disconnect If we get a disconnect IRQ, we should take the core out of low power mode so we can reconnect afterwards. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 867c476853e..054ee5ec5c1 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1906,11 +1906,9 @@ static void dwc3_clear_stall_all_ep(struct dwc3 *dwc) static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc) { + int reg; + dev_vdbg(dwc->dev, "%s\n", __func__); -#if 0 - XXX - U1/U2 is powersave optimization. Skip it for now. Anyway we need to - enable it before we can disable it. reg = dwc3_readl(dwc->regs, DWC3_DCTL); reg &= ~DWC3_DCTL_INITU1ENA; @@ -1918,7 +1916,6 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc) reg &= ~DWC3_DCTL_INITU2ENA; dwc3_writel(dwc->regs, DWC3_DCTL, reg); -#endif dwc3_stop_active_transfers(dwc); dwc3_disconnect_gadget(dwc); -- cgit v1.2.3 From 5cbe8c220c1e126dd0855ad57fe4491b267132b9 Mon Sep 17 00:00:00 2001 From: Gerard CAUVY Date: Thu, 24 May 2012 12:47:36 +0300 Subject: usb: dwc3: gadget: move AcceptU1Ena and AcceptU2Ena to Reset IRQ According to the databook, the DWC3 Core will reset those bits to 0 on USB Bus Reset. This means we must re-enable those bits on every reset interrupt. Because we will always get a Reset interrupt after loading a gadget driver, we can, instead of re-enabling something that was just lost, move the handling of those bits to the Reset Interrupt. This patch fixes USB30CV U1/U2 Test. Signed-off-by: Gerard CAUVY Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 054ee5ec5c1..a9fc7c4a5a2 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2006,6 +2006,7 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) reg = dwc3_readl(dwc->regs, DWC3_DCTL); reg &= ~DWC3_DCTL_TSTCTRL_MASK; reg &= ~(DWC3_DCTL_INITU1ENA | DWC3_DCTL_INITU2ENA); + reg |= (DWC3_DCTL_ACCEPTU1ENA | DWC3_DCTL_ACCEPTU2ENA); dwc3_writel(dwc->regs, DWC3_DCTL, reg); dwc->test_mode = false; @@ -2410,10 +2411,6 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc) reg |= DWC3_DCFG_LPM_CAP; dwc3_writel(dwc->regs, DWC3_DCFG, reg); - reg = dwc3_readl(dwc->regs, DWC3_DCTL); - reg |= DWC3_DCTL_ACCEPTU1ENA | DWC3_DCTL_ACCEPTU2ENA; - dwc3_writel(dwc->regs, DWC3_DCTL, reg); - /* Enable all but Start and End of Frame IRQs */ reg = (DWC3_DEVTEN_VNDRDEVTSTRCVEDEN | DWC3_DEVTEN_EVNTOVERFLOWEN | -- cgit v1.2.3 From ef21ede65ee3e0dfd8f2cb37de8892816e2f1257 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 31 May 2012 10:29:49 +0300 Subject: usb: dwc3: ep0: simplify error handling on dwc3_ep0_inspect_setup There's no need for returning early. Instead, we can call dwc3_ep0_stall_and_restart() conditionally. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/ep0.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index e31bcd65e7e..83fcf392dda 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -641,11 +641,11 @@ static void dwc3_ep0_inspect_setup(struct dwc3 *dwc, const struct dwc3_event_depevt *event) { struct usb_ctrlrequest *ctrl = dwc->ctrl_req; - int ret; + int ret = -EINVAL; u32 len; if (!dwc->gadget_driver) - goto err; + goto out; len = le16_to_cpu(ctrl->wLength); if (!len) { @@ -666,11 +666,9 @@ static void dwc3_ep0_inspect_setup(struct dwc3 *dwc, if (ret == USB_GADGET_DELAYED_STATUS) dwc->delayed_status = true; - if (ret >= 0) - return; - -err: - dwc3_ep0_stall_and_restart(dwc); +out: + if (ret < 0) + dwc3_ep0_stall_and_restart(dwc); } static void dwc3_ep0_complete_data(struct dwc3 *dwc, -- cgit v1.2.3 From c8cf7af452ad2eb49cad13450090cdc432b5a06d Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 31 May 2012 11:00:28 +0300 Subject: usb: dwc3: ep0: be careful with endianness on SetSEL command USB is always little endian, but this driver could run on non little endian cpus. Let's be carefull with that. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/ep0.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 83fcf392dda..3185fe14591 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -515,8 +515,8 @@ static void dwc3_ep0_set_sel_cmpl(struct usb_ep *ep, struct usb_request *req) dwc->u1sel = timing.u1sel; dwc->u1pel = timing.u1pel; - dwc->u2sel = timing.u2sel; - dwc->u2pel = timing.u2pel; + dwc->u2sel = le16_to_cpu(timing.u2sel); + dwc->u2pel = le16_to_cpu(timing.u2pel); reg = dwc3_readl(dwc->regs, DWC3_DCTL); if (reg & DWC3_DCTL_INITU2ENA) -- cgit v1.2.3 From 85a781019b9b4b935f6b1792a1f48f1a3aee988f Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 31 May 2012 12:32:37 +0300 Subject: usb: dwc3: ep0: rename dwc3_ep0_complete_req to dwc3_ep0_complete_status That's a much more intuitive name as that function is only called at the completion of a Status Phase. It also matches dwc3_ep0_complete_data() for the completion of Data Phase. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/ep0.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 3185fe14591..90eb1ba6545 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -722,7 +722,7 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, } } -static void dwc3_ep0_complete_req(struct dwc3 *dwc, +static void dwc3_ep0_complete_status(struct dwc3 *dwc, const struct dwc3_event_depevt *event) { struct dwc3_request *r; @@ -773,7 +773,7 @@ static void dwc3_ep0_xfer_complete(struct dwc3 *dwc, case EP0_STATUS_PHASE: dev_vdbg(dwc->dev, "Status Phase\n"); - dwc3_ep0_complete_req(dwc, event); + dwc3_ep0_complete_status(dwc, event); break; default: WARN(true, "UNKNOWN ep0state %d\n", dwc->ep0state); -- cgit v1.2.3 From 206dd69a62a06197b308fa0decfd0b649fcc2811 Mon Sep 17 00:00:00 2001 From: Pratyush Anand Date: Mon, 21 May 2012 12:42:54 +0530 Subject: USB: DWC3: Generate interrupt on each TRB as default option Currently in case of isoc, interrupt is programmed after each TRB_NUM/4 ie 8th TRB. A TRB is programmed against each submitted request from gadget. If we do not want to limit the minimum number of necessary request to be submitted from gadget then we must receive interrupt on each TRB submission. There can be such situation with a gadget working with ping-pong buffer. If a gadget does not want to receive interrupt after each request completion then it may set no_interrupt flag. Signed-off-by: Pratyush Anand Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index a9fc7c4a5a2..be87e82b36c 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -766,8 +766,7 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, case USB_ENDPOINT_XFER_ISOC: trb->ctrl = DWC3_TRBCTL_ISOCHRONOUS_FIRST; - /* IOC every DWC3_TRB_NUM / 4 so we can refill */ - if (!(cur_slot % (DWC3_TRB_NUM / 4))) + if (!req->request.no_interrupt) trb->ctrl |= DWC3_TRB_CTRL_IOC; break; -- cgit v1.2.3 From 389f2828bb2a5f2acde9bdeffde02743684c1d86 Mon Sep 17 00:00:00 2001 From: Pratyush Anand Date: Mon, 21 May 2012 12:46:26 +0530 Subject: USB: DWC3: Correct DWC3_TRB_SIZE_TRBSTS definition Correct define for DWC3_TRB_SIZE_TRBSTS. Signed-off-by: Pratyush Anand Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 4d5c63dae14..ce43b1f5f34 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -495,7 +495,7 @@ enum dwc3_device_state { #define DWC3_TRB_SIZE_MASK (0x00ffffff) #define DWC3_TRB_SIZE_LENGTH(n) ((n) & DWC3_TRB_SIZE_MASK) #define DWC3_TRB_SIZE_PCM1(n) (((n) & 0x03) << 24) -#define DWC3_TRB_SIZE_TRBSTS(n) (((n) & (0x0f << 28) >> 28)) +#define DWC3_TRB_SIZE_TRBSTS(n) (((n) & (0x0f << 28)) >> 28) #define DWC3_TRBSTS_OK 0 #define DWC3_TRBSTS_MISSED_ISOC 1 -- cgit v1.2.3 From d05b81824e672a48b3566634622849866de2b787 Mon Sep 17 00:00:00 2001 From: Pratyush Anand Date: Mon, 21 May 2012 14:51:30 +0530 Subject: USB: DWC3: Correct DWC3_DSTS_SOFFN_MASK definition SOF Number is bit16:3 of DSTS. Correct the mask accordingly. Signed-off-by: Pratyush Anand Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index ce43b1f5f34..e402022b9e1 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -291,7 +291,7 @@ #define DWC3_DSTS_RXFIFOEMPTY (1 << 17) -#define DWC3_DSTS_SOFFN_MASK (0x3ff << 3) +#define DWC3_DSTS_SOFFN_MASK (0x3fff << 3) #define DWC3_DSTS_SOFFN(n) (((n) & DWC3_DSTS_SOFFN_MASK) >> 3) #define DWC3_DSTS_CONNECTSPD (7 << 0) -- cgit v1.2.3 From d6d6ec7b8854ab62f7f3907656d5d29eb47532e7 Mon Sep 17 00:00:00 2001 From: Pratyush Anand Date: Fri, 25 May 2012 18:54:56 +0530 Subject: usb: dwc3: Fix missed isoc IN transaction If an IN transfer is missed on isoc endpoint, then driver must insure that next ep_queue is properly handled. This patch fixes this issue by starting a new transfer for next queued request. Signed-off-by: Pratyush Anand Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.h | 3 ++ drivers/usb/dwc3/gadget.c | 73 +++++++++++++++++++++++++++++++---------------- 2 files changed, 52 insertions(+), 24 deletions(-) diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index e402022b9e1..fcb8be2ec1c 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -405,6 +405,7 @@ struct dwc3_event_buffer { * @number: endpoint number (1 - 15) * @type: set to bmAttributes & USB_ENDPOINT_XFERTYPE_MASK * @res_trans_idx: Resource transfer index + * @current_uf: Current uf received through last event parameter * @interval: the intervall on which the ISOC transfer is started * @name: a human readable name e.g. ep1out-bulk * @direction: true for TX, false for RX @@ -428,6 +429,7 @@ struct dwc3_ep { #define DWC3_EP_WEDGE (1 << 2) #define DWC3_EP_BUSY (1 << 4) #define DWC3_EP_PENDING_REQUEST (1 << 5) +#define DWC3_EP_MISSED_ISOC (1 << 6) /* This last one is specific to EP0 */ #define DWC3_EP0_DIR_IN (1 << 31) @@ -437,6 +439,7 @@ struct dwc3_ep { u8 number; u8 type; u8 res_trans_idx; + u16 current_uf; u32 interval; char name[20]; diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index be87e82b36c..0cab69e5138 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -990,6 +990,34 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param, return 0; } +static void __dwc3_gadget_start_isoc(struct dwc3 *dwc, + struct dwc3_ep *dep, u32 cur_uf) +{ + u32 uf; + + if (list_empty(&dep->request_list)) { + dev_vdbg(dwc->dev, "ISOC ep %s run out for requests.\n", + dep->name); + return; + } + + /* 4 micro frames in the future */ + uf = cur_uf + dep->interval * 4; + + __dwc3_gadget_kick_transfer(dep, uf, 1); +} + +static void dwc3_gadget_start_isoc(struct dwc3 *dwc, + 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); +} + static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) { struct dwc3 *dwc = dep->dwc; @@ -1019,8 +1047,14 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) list_add_tail(&req->list, &dep->request_list); - if (usb_endpoint_xfer_isoc(dep->endpoint.desc) && (dep->flags & DWC3_EP_BUSY)) - dep->flags |= DWC3_EP_PENDING_REQUEST; + if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) { + if (dep->flags & DWC3_EP_BUSY) { + dep->flags |= DWC3_EP_PENDING_REQUEST; + } else if (dep->flags & DWC3_EP_MISSED_ISOC) { + __dwc3_gadget_start_isoc(dwc, dep, dep->current_uf); + dep->flags &= ~DWC3_EP_MISSED_ISOC; + } + } /* * There are two special cases: @@ -1591,6 +1625,7 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, struct dwc3_trb *trb; unsigned int count; unsigned int s_pkt = 0; + unsigned int trb_status; do { req = next_request(&dep->req_queued); @@ -1616,9 +1651,18 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, if (dep->direction) { if (count) { - dev_err(dwc->dev, "incomplete IN transfer %s\n", - dep->name); - status = -ECONNRESET; + trb_status = DWC3_TRB_SIZE_TRBSTS(trb->size); + if (trb_status == DWC3_TRBSTS_MISSED_ISOC) { + dev_dbg(dwc->dev, "incomplete IN transfer %s\n", + dep->name); + dep->current_uf = event->parameters & + ~(dep->interval - 1); + dep->flags |= DWC3_EP_MISSED_ISOC; + } else { + dev_err(dwc->dev, "incomplete IN transfer %s\n", + dep->name); + status = -ECONNRESET; + } } } else { if (count && (event->status & DEPEVT_STATUS_SHORT)) @@ -1690,25 +1734,6 @@ static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc, } } -static void dwc3_gadget_start_isoc(struct dwc3 *dwc, - struct dwc3_ep *dep, const struct dwc3_event_depevt *event) -{ - u32 uf, mask; - - if (list_empty(&dep->request_list)) { - dev_vdbg(dwc->dev, "ISOC ep %s run out for requests.\n", - dep->name); - return; - } - - mask = ~(dep->interval - 1); - uf = event->parameters & mask; - /* 4 micro frames in the future */ - uf += dep->interval * 4; - - __dwc3_gadget_kick_transfer(dep, uf, 1); -} - static void dwc3_process_ep_cmd_complete(struct dwc3_ep *dep, const struct dwc3_event_depevt *event) { -- cgit v1.2.3 From 70b674bfeb735557fc03cdc125ffe6d34218fcfd Mon Sep 17 00:00:00 2001 From: Pratyush Anand Date: Sun, 3 Jun 2012 19:43:19 +0530 Subject: usb: dwc3: Fix break from cleanup request loop If event status says that its last completed TRB but TRB is still owned by HW then break from the loop, because we are not going to get correct TRB status from trb control/size register. Signed-off-by: Pratyush Anand Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 0cab69e5138..854f3a3c883 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1681,7 +1681,8 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, if (s_pkt) break; if ((event->status & DEPEVT_STATUS_LST) && - (trb->ctrl & DWC3_TRB_CTRL_LST)) + (trb->ctrl & (DWC3_TRB_CTRL_LST | + DWC3_TRB_CTRL_HWO))) break; if ((event->status & DEPEVT_STATUS_IOC) && (trb->ctrl & DWC3_TRB_CTRL_IOC)) -- cgit v1.2.3 From 6dbc10c61d5841f64945fd94977fa8fa1c0192da Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 17 Feb 2012 11:58:14 +0200 Subject: usb: dwc3: gadget: drop useless code We never set CMDIOC bit for Start Transfer command, so that code will never be used. Tested-by: Pratyush Anand Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 854f3a3c883..056ace8ab97 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1765,9 +1765,6 @@ static void dwc3_ep_cmd_compl(struct dwc3_ep *dep, case DWC3_DEPCMD_ENDTRANSFER: dwc3_process_ep_cmd_complete(dep, event); break; - case DWC3_DEPCMD_STARTTRANSFER: - dep->res_trans_idx = param & 0x7f; - break; default: printk(KERN_ERR "%s() unknown /unexpected type: %d\n", __func__, cmd_type); -- cgit v1.2.3 From ea53b8828c50b7a5138a8931c41b2671682c86b5 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 17 Feb 2012 12:10:04 +0200 Subject: usb: dwc3: gadget: don't wait for ep cmd IRQ That IRQ is causing way too much trouble. We have a different handling which was agreed with IP provider and has been tested with FPGA and OMAP5. Tested-by: Pratyush Anand Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 66 +++++++++++++++++++---------------------------- 1 file changed, 27 insertions(+), 39 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 056ace8ab97..0f19978d484 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -555,9 +555,34 @@ static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep) { struct dwc3_request *req; - if (!list_empty(&dep->req_queued)) + if (!list_empty(&dep->req_queued)) { dwc3_stop_active_transfer(dwc, dep->number); + /* + * NOTICE: We are violating what the Databook says about the + * EndTransfer command. Ideally we would _always_ wait for the + * EndTransfer Command Completion IRQ, but that's causing too + * much trouble synchronizing between us and gadget driver. + * + * We have discussed this with the IP Provider and it was + * suggested to giveback all requests here, but give HW some + * extra time to synchronize with the interconnect. We're using + * an arbitraty 100us delay for that. + * + * Note also that a similar handling was tested by Synopsys + * (thanks a lot Paul) and nothing bad has come out of it. + * In short, what we're doing is: + * + * - Issue EndTransfer WITH CMDIOC bit set + * - Wait 100us + * - giveback all requests to gadget driver + */ + udelay(100); + + req = next_request(&dep->req_queued); + dwc3_gadget_giveback(dep, req, -ESHUTDOWN); + } + while (!list_empty(&dep->request_list)) { req = next_request(&dep->request_list); @@ -1735,43 +1760,6 @@ static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc, } } -static void dwc3_process_ep_cmd_complete(struct dwc3_ep *dep, - const struct dwc3_event_depevt *event) -{ - struct dwc3 *dwc = dep->dwc; - struct dwc3_event_depevt mod_ev = *event; - - /* - * We were asked to remove one request. It is possible that this - * request and a few others were started together and have the same - * transfer index. Since we stopped the complete endpoint we don't - * know how many requests were already completed (and not yet) - * reported and how could be done (later). We purge them all until - * the end of the list. - */ - mod_ev.status = DEPEVT_STATUS_LST; - dwc3_cleanup_done_reqs(dwc, dep, &mod_ev, -ESHUTDOWN); - dep->flags &= ~DWC3_EP_BUSY; - /* pending requests are ignored and are queued on XferNotReady */ -} - -static void dwc3_ep_cmd_compl(struct dwc3_ep *dep, - const struct dwc3_event_depevt *event) -{ - u32 param = event->parameters; - u32 cmd_type = (param >> 8) & ((1 << 5) - 1); - - switch (cmd_type) { - case DWC3_DEPCMD_ENDTRANSFER: - dwc3_process_ep_cmd_complete(dep, event); - break; - default: - printk(KERN_ERR "%s() unknown /unexpected type: %d\n", - __func__, cmd_type); - break; - }; -} - static void dwc3_endpoint_interrupt(struct dwc3 *dwc, const struct dwc3_event_depevt *event) { @@ -1853,7 +1841,7 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc, dev_dbg(dwc->dev, "%s FIFO Overrun\n", dep->name); break; case DWC3_DEPEVT_EPCMDCMPLT: - dwc3_ep_cmd_compl(dep, event); + dev_vdbg(dwc->dev, "Endpoint Command Complete\n"); break; } } -- cgit v1.2.3 From 1e2360eadaa33c09bb72afb14f74b6c6ab2aca66 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 6 Jun 2012 09:18:12 +0300 Subject: usb: dwc3: gadget: don't call stop_active_transfers() on disconnect In case we get disconnected, we will call gadget driver's disconnect method, which should make sure to disable all endpoints. At that point we will call stop_active_transfers() to make sure we didn't leave any pending request on the controller. Tested-by: Pratyush Anand Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 0f19978d484..52d0f67e33d 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1927,7 +1927,6 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc) reg &= ~DWC3_DCTL_INITU2ENA; dwc3_writel(dwc->regs, DWC3_DCTL, reg); - dwc3_stop_active_transfers(dwc); dwc3_disconnect_gadget(dwc); dwc->start_config_issued = false; -- cgit v1.2.3 From 3336abb5b608300550136ddab7a7101b30d45fa7 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 6 Jun 2012 09:19:35 +0300 Subject: usb: dwc3: gadget: ignore endpoint IRQs when endpoint is disabled By the time we're disabling the endpoint, HW could already have posted more events to our event buffer. In that case, we will receive endpoint events for a disabled endpoint. In order to protect ourselves from that situation, we simply ignore endpoint interrupts whenever the endpoint is disabled. Tested-by: Pratyush Anand Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 52d0f67e33d..8e00756ee52 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1768,6 +1768,9 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc, dep = dwc->eps[epnum]; + if (!(dep->flags & DWC3_EP_ENABLED)) + return; + dev_vdbg(dwc->dev, "%s: %s\n", dep->name, dwc3_ep_event_string(event->endpoint_event)); -- cgit v1.2.3 From 7e39b817ee64a8b67282c76f52aaabddc8a5cd26 Mon Sep 17 00:00:00 2001 From: Pratyush Anand Date: Wed, 6 Jun 2012 19:18:29 +0530 Subject: usb: dwc3: Correct DWC3_DCTL_HIRD_THRES definition The definition of DWC3_DCTL_HIRD_THRES macro is completely wrong. It will only work for when we want to read the register's contents for that bitfield. Change the macro so that it can be used to writing to the register, and when we need to read, we can add extra right shift of 24 bits. Signed-off-by: Pratyush Anand [ balbi@ti.com: add a commit log ] Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index fcb8be2ec1c..d3e56cfb29c 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -223,7 +223,7 @@ #define DWC3_DCTL_LSFTRST (1 << 29) #define DWC3_DCTL_HIRD_THRES_MASK (0x1f << 24) -#define DWC3_DCTL_HIRD_THRES(n) (((n) & DWC3_DCTL_HIRD_THRES_MASK) >> 24) +#define DWC3_DCTL_HIRD_THRES(n) ((n) << 24) #define DWC3_DCTL_APPL1RES (1 << 23) -- cgit v1.2.3 From dcae3573b98b2205961bfa5821427f5664422cd8 Mon Sep 17 00:00:00 2001 From: Pratyush Anand Date: Wed, 6 Jun 2012 19:36:17 +0530 Subject: usb: dwc3: resume phy during gadget initialization on recent cores It is needed to enumerate recent cores like 2.10a. Signed-off-by: Pratyush Anand Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 8e00756ee52..38cd13ffae9 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2449,8 +2449,8 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc) dwc3_writel(dwc->regs, DWC3_DCTL, reg); - dwc3_gadget_usb2_phy_suspend(dwc, true); - dwc3_gadget_usb3_phy_suspend(dwc, true); + dwc3_gadget_usb2_phy_suspend(dwc, false); + dwc3_gadget_usb3_phy_suspend(dwc, false); } ret = device_register(&dwc->gadget.dev); -- cgit v1.2.3 From 1591633ed6c4c3994944f31ddb59bc072a2ed0ca Mon Sep 17 00:00:00 2001 From: Pratyush Anand Date: Fri, 15 Jun 2012 11:54:36 +0530 Subject: usb: dwc3: giveback all queued request when ep disabled or reset received In case of ep_disable and reset interrupt is received and, still there was at least one request queued for dma transfer, then endpoint is stopped first. Once endpoint is stopped, callback for all queued request must be called. Signed-off-by: Pratyush Anand Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 38cd13ffae9..f6fb42da2e6 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -579,8 +579,11 @@ static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep) */ udelay(100); - req = next_request(&dep->req_queued); - dwc3_gadget_giveback(dep, req, -ESHUTDOWN); + while (!list_empty(&dep->req_queued)) { + req = next_request(&dep->req_queued); + + dwc3_gadget_giveback(dep, req, -ESHUTDOWN); + } } while (!list_empty(&dep->request_list)) { -- cgit v1.2.3 From 45c396ce6bdad60ee94e6eed8cc7f09678651102 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 18 Jun 2012 11:32:37 +0530 Subject: usb: dwc3: Remove duplicate header file inclusion module.h header file was included twice. Signed-off-by: Sachin Kamat Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/dwc3-exynos.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c index d1903019808..b8f00389fa3 100644 --- a/drivers/usb/dwc3/dwc3-exynos.c +++ b/drivers/usb/dwc3/dwc3-exynos.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include "core.h" -- cgit v1.2.3 From 45627ac6a4f063d19b0bd9863d20ac1dabda99a7 Mon Sep 17 00:00:00 2001 From: Pratyush Anand Date: Thu, 21 Jun 2012 17:44:28 +0530 Subject: USB: DWC3: Put 100 ms delay for phy to be stable Before taking core out of reset phy must be stable. So wait for 100ms after clear phy reset. Signed-off-by: Pratyush Anand Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 49c060205c9..ac151e9acf2 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -148,6 +148,8 @@ static void dwc3_core_soft_reset(struct dwc3 *dwc) reg &= ~DWC3_GUSB2PHYCFG_PHYSOFTRST; dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); + mdelay(100); + /* After PHYs are stable we can take Core out of reset state */ reg = dwc3_readl(dwc->regs, DWC3_GCTL); reg &= ~DWC3_GCTL_CORESOFTRESET; -- cgit v1.2.3 From 58a0f23fddd0a71d8fa22e6ef7627298a8ed29a6 Mon Sep 17 00:00:00 2001 From: Pratyush Anand Date: Thu, 21 Jun 2012 17:44:29 +0530 Subject: USB: DWC3: Issue device soft reset before core soft reset Synopsys specification clearly states under section "Device Power-On or Soft Reset" that DCTL.CSftRst=1 should be first step. So, just follow what specification says. Signed-off-by: Pratyush Anand Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index ac151e9acf2..c34452a7304 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -335,8 +335,6 @@ static int __devinit dwc3_core_init(struct dwc3 *dwc) } dwc->revision = reg; - dwc3_core_soft_reset(dwc); - /* issue device SoftReset too */ timeout = jiffies + msecs_to_jiffies(500); dwc3_writel(dwc->regs, DWC3_DCTL, DWC3_DCTL_CSFTRST); @@ -354,6 +352,8 @@ static int __devinit dwc3_core_init(struct dwc3 *dwc) cpu_relax(); } while (true); + dwc3_core_soft_reset(dwc); + dwc3_cache_hwparams(dwc); reg = dwc3_readl(dwc->regs, DWC3_GCTL); -- cgit v1.2.3 From 3daf74d78dfcd552445c35f1b82a271ca305ceb9 Mon Sep 17 00:00:00 2001 From: Pratyush Anand Date: Sat, 23 Jun 2012 02:23:08 +0530 Subject: usb: dwc3: remove WARN_ON from dwc_stop_active_transfer Now we are sure that, if res_trans_idx is zero, then endpoint has been stopped. So it's safe to just return if endpoint is already stopped. No need to generate warning anymore. While doing so, it's better to return when res_trans_idx is zero and decrease one level of indentation. Signed-off-by: Pratyush Anand [ balbi@ti.com: slightly changed commit log ] Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index f6fb42da2e6..9ac4835d7b6 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1870,16 +1870,16 @@ static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum) dep = dwc->eps[epnum]; - WARN_ON(!dep->res_trans_idx); - if (dep->res_trans_idx) { - cmd = DWC3_DEPCMD_ENDTRANSFER; - cmd |= DWC3_DEPCMD_HIPRI_FORCERM | DWC3_DEPCMD_CMDIOC; - cmd |= DWC3_DEPCMD_PARAM(dep->res_trans_idx); - memset(¶ms, 0, sizeof(params)); - ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, ¶ms); - WARN_ON_ONCE(ret); - dep->res_trans_idx = 0; - } + if (!dep->res_trans_idx) + return; + + cmd = DWC3_DEPCMD_ENDTRANSFER; + cmd |= DWC3_DEPCMD_HIPRI_FORCERM | DWC3_DEPCMD_CMDIOC; + cmd |= DWC3_DEPCMD_PARAM(dep->res_trans_idx); + memset(¶ms, 0, sizeof(params)); + ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, ¶ms); + WARN_ON_ONCE(ret); + dep->res_trans_idx = 0; } static void dwc3_stop_active_transfers(struct dwc3 *dwc) -- cgit v1.2.3 From b511e5e76bf488cd3eec1048483a3898393a4dca Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 6 Jun 2012 12:00:50 +0300 Subject: usb: dwc3: gadget: split special cases of ep_queue() It makes it easier to read and also avoids setting DWC3_EP_PENDING_REQUEST just so the next branch evaluates true. No functional changes otherwise. Cc: Pratyush Anand Cc: Paul Zimmerman Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 50 ++++++++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 9ac4835d7b6..1c98aee051a 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1075,17 +1075,8 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) list_add_tail(&req->list, &dep->request_list); - if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) { - if (dep->flags & DWC3_EP_BUSY) { - dep->flags |= DWC3_EP_PENDING_REQUEST; - } else if (dep->flags & DWC3_EP_MISSED_ISOC) { - __dwc3_gadget_start_isoc(dwc, dep, dep->current_uf); - dep->flags &= ~DWC3_EP_MISSED_ISOC; - } - } - /* - * There are two special cases: + * There are a few special cases: * * 1. XferNotReady with empty list of requests. We need to kick the * transfer here in that situation, otherwise we will be NAKing @@ -1094,24 +1085,29 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) * able to receive the data until the next request is queued. * The following code is handling exactly that. * - * 2. XferInProgress on Isoc EP with an active transfer. We need to - * kick the transfer here after queuing a request, otherwise the - * core may not see the modified TRB(s). */ if (dep->flags & DWC3_EP_PENDING_REQUEST) { int ret; - int start_trans = 1; - u8 trans_idx = dep->res_trans_idx; - if (usb_endpoint_xfer_isoc(dep->endpoint.desc) && - (dep->flags & DWC3_EP_BUSY)) { - start_trans = 0; - WARN_ON_ONCE(!trans_idx); - } else { - trans_idx = 0; + ret = __dwc3_gadget_kick_transfer(dep, 0, true); + if (ret && ret != -EBUSY) { + struct dwc3 *dwc = dep->dwc; + + dev_dbg(dwc->dev, "%s: failed to kick transfers\n", + dep->name); } + } - ret = __dwc3_gadget_kick_transfer(dep, trans_idx, start_trans); + /* + * 2. XferInProgress on Isoc EP with an active transfer. We need to + * kick the transfer here after queuing a request, otherwise the + * core may not see the modified TRB(s). + */ + if (usb_endpoint_xfer_isoc(dep->endpoint.desc) && + (dep->flags & DWC3_EP_BUSY)) { + WARN_ON_ONCE(!dep->res_trans_idx); + ret = __dwc3_gadget_kick_transfer(dep, dep->res_trans_idx, + false); if (ret && ret != -EBUSY) { struct dwc3 *dwc = dep->dwc; @@ -1120,6 +1116,16 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) } } + /* + * 3. Missed ISOC Handling. We need to start isoc transfer on the saved + * uframe number. + */ + if (usb_endpoint_xfer_isoc(dep->endpoint.desc) && + (dep->flags & DWC3_EP_MISSED_ISOC)) { + __dwc3_gadget_start_isoc(dwc, dep, dep->current_uf); + dep->flags &= ~DWC3_EP_MISSED_ISOC; + } + return 0; } -- cgit v1.2.3 From b4996a8631e80a2aaddb5c487ff6b9ad37315f70 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 6 Jun 2012 12:04:13 +0300 Subject: usb: dwc3: rename res_trans_idx to resource_index resource_index is more human readable. No functional changes. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.h | 4 ++-- drivers/usb/dwc3/ep0.c | 4 ++-- drivers/usb/dwc3/gadget.c | 16 ++++++++-------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index d3e56cfb29c..151eca876df 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -404,7 +404,7 @@ struct dwc3_event_buffer { * @current_trb: index of current used trb * @number: endpoint number (1 - 15) * @type: set to bmAttributes & USB_ENDPOINT_XFERTYPE_MASK - * @res_trans_idx: Resource transfer index + * @resource_index: Resource transfer index * @current_uf: Current uf received through last event parameter * @interval: the intervall on which the ISOC transfer is started * @name: a human readable name e.g. ep1out-bulk @@ -438,7 +438,7 @@ struct dwc3_ep { u8 number; u8 type; - u8 res_trans_idx; + u8 resource_index; u16 current_uf; u32 interval; diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 90eb1ba6545..9a8f26cef0a 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -113,7 +113,7 @@ static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma, } dep->flags |= DWC3_EP_BUSY; - dep->res_trans_idx = dwc3_gadget_ep_get_transfer_index(dwc, + dep->resource_index = dwc3_gadget_ep_get_transfer_index(dwc, dep->number); dwc->ep0_next_event = DWC3_EP0_COMPLETE; @@ -757,7 +757,7 @@ static void dwc3_ep0_xfer_complete(struct dwc3 *dwc, struct dwc3_ep *dep = dwc->eps[event->endpoint_number]; dep->flags &= ~DWC3_EP_BUSY; - dep->res_trans_idx = 0; + dep->resource_index = 0; dwc->setup_packet_pending = false; switch (dwc->ep0state) { diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 1c98aee051a..1b5fbdd859c 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1010,9 +1010,9 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param, dep->flags |= DWC3_EP_BUSY; if (start_new) { - dep->res_trans_idx = dwc3_gadget_ep_get_transfer_index(dwc, + dep->resource_index = dwc3_gadget_ep_get_transfer_index(dwc, dep->number); - WARN_ON_ONCE(!dep->res_trans_idx); + WARN_ON_ONCE(!dep->resource_index); } return 0; @@ -1105,8 +1105,8 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) */ if (usb_endpoint_xfer_isoc(dep->endpoint.desc) && (dep->flags & DWC3_EP_BUSY)) { - WARN_ON_ONCE(!dep->res_trans_idx); - ret = __dwc3_gadget_kick_transfer(dep, dep->res_trans_idx, + WARN_ON_ONCE(!dep->resource_index); + ret = __dwc3_gadget_kick_transfer(dep, dep->resource_index, false); if (ret && ret != -EBUSY) { struct dwc3 *dwc = dep->dwc; @@ -1790,7 +1790,7 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc, switch (event->endpoint_event) { case DWC3_DEPEVT_XFERCOMPLETE: - dep->res_trans_idx = 0; + dep->resource_index = 0; if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) { dev_dbg(dwc->dev, "%s is an Isochronous endpoint\n", @@ -1876,16 +1876,16 @@ static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum) dep = dwc->eps[epnum]; - if (!dep->res_trans_idx) + if (!dep->resource_index) return; cmd = DWC3_DEPCMD_ENDTRANSFER; cmd |= DWC3_DEPCMD_HIPRI_FORCERM | DWC3_DEPCMD_CMDIOC; - cmd |= DWC3_DEPCMD_PARAM(dep->res_trans_idx); + cmd |= DWC3_DEPCMD_PARAM(dep->resource_index); memset(¶ms, 0, sizeof(params)); ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, ¶ms); WARN_ON_ONCE(ret); - dep->res_trans_idx = 0; + dep->resource_index = 0; } static void dwc3_stop_active_transfers(struct dwc3 *dwc) -- cgit v1.2.3 From 9be2395186b3504aa5e337bd3284afb4966caae7 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 25 Jun 2012 17:09:28 +0300 Subject: usb: dwc3: gadget: remove duplicated code from __dwc3_gadget_ep_set_halt whenever we want to stall ep0, we always call dwc3_ep0_stall_and_restart() which makes sure to send ep0state properly rendering the code in __dwc3_gadget_ep_set_halt() duplicated. Reported-by: Pratyush Anand Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 1b5fbdd859c..d98549a7b8b 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1209,15 +1209,6 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value) memset(¶ms, 0x00, sizeof(params)); if (value) { - if (dep->number == 0 || dep->number == 1) { - /* - * Whenever EP0 is stalled, we will restart - * the state machine, thus moving back to - * Setup Phase - */ - dwc->ep0state = EP0_SETUP_PHASE; - } - ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, DWC3_DEPCMD_SETSTALL, ¶ms); if (ret) -- cgit v1.2.3 From 5c81ababecd7ddae08ca944a65d8030cd393013c Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 25 Jun 2012 19:30:49 +0300 Subject: usb: dwc3: ep0: prevent starting transfers twice on ep0 In case we try to start an invalid test mode, we will call dwc3_ep0_stall_and_restart() but we will also call dwc3_ep0_out_start() which will start a second transfer on ep0. Let's prevent any problems by returning early in the error case. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/ep0.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 9a8f26cef0a..8244eb53082 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -744,6 +744,7 @@ static void dwc3_ep0_complete_status(struct dwc3 *dwc, dev_dbg(dwc->dev, "Invalid Test #%d\n", dwc->test_mode_nr); dwc3_ep0_stall_and_restart(dwc); + return; } } -- cgit v1.2.3 From 08f0d96670c53898b4154e7945e77cdd966003f7 Mon Sep 17 00:00:00 2001 From: Pratyush Anand Date: Mon, 25 Jun 2012 22:40:43 +0530 Subject: usb: dwc3: correct set_halt implementation for ep0 set_halt for ep0 is called to stall a deferred control responses by the gadget. We already have a function to stall default control endpoint. This patch points set_halt for ep0 to the already available function. Signed-off-by: Pratyush Anand Signed-off-by: Michel Sanches Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/ep0.c | 10 ++++++++++ drivers/usb/dwc3/gadget.c | 7 +++++-- drivers/usb/dwc3/gadget.h | 1 + 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 8244eb53082..1315e787a31 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -225,6 +225,16 @@ static void dwc3_ep0_stall_and_restart(struct dwc3 *dwc) dwc3_ep0_out_start(dwc); } +int dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value) +{ + struct dwc3_ep *dep = to_dwc3_ep(ep); + struct dwc3 *dwc = dep->dwc; + + dwc3_ep0_stall_and_restart(dwc); + + return 0; +} + void dwc3_ep0_out_start(struct dwc3 *dwc) { int ret; diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index d98549a7b8b..13f257db243 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1268,7 +1268,10 @@ static int dwc3_gadget_ep_set_wedge(struct usb_ep *ep) dep->flags |= DWC3_EP_WEDGE; spin_unlock_irqrestore(&dwc->lock, flags); - return dwc3_gadget_ep_set_halt(ep, 1); + if (dep->number == 0 || dep->number == 1) + return dwc3_gadget_ep0_set_halt(ep, 1); + else + return dwc3_gadget_ep_set_halt(ep, 1); } /* -------------------------------------------------------------------------- */ @@ -1286,7 +1289,7 @@ static const struct usb_ep_ops dwc3_gadget_ep0_ops = { .free_request = dwc3_gadget_ep_free_request, .queue = dwc3_gadget_ep0_queue, .dequeue = dwc3_gadget_ep_dequeue, - .set_halt = dwc3_gadget_ep_set_halt, + .set_halt = dwc3_gadget_ep0_set_halt, .set_wedge = dwc3_gadget_ep_set_wedge, }; diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h index 39ced0b0851..99e6d724882 100644 --- a/drivers/usb/dwc3/gadget.h +++ b/drivers/usb/dwc3/gadget.h @@ -111,6 +111,7 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state); void dwc3_ep0_interrupt(struct dwc3 *dwc, const struct dwc3_event_depevt *event); void dwc3_ep0_out_start(struct dwc3 *dwc); +int dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value); int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request, gfp_t gfp_flags); int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value); -- cgit v1.2.3 From cbc725b371f80710c5c611db78a501a6cd314ec3 Mon Sep 17 00:00:00 2001 From: Pratyush Anand Date: Mon, 2 Jul 2012 10:21:52 +0530 Subject: usb: dwc3: keep default hird threshold value as 4b1100 as per data book any HIRD threshold value greater than 4b1100 is invalid. So set the maximum valid value as default values. Signed-off-by: Pratyush Anand Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 13f257db243..f732f2ccb9b 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2448,7 +2448,7 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc) reg &= ~(DWC3_DCTL_HIRD_THRES_MASK | DWC3_DCTL_L1_HIBER_EN); /* TODO: This should be configurable */ - reg |= DWC3_DCTL_HIRD_THRES(31); + reg |= DWC3_DCTL_HIRD_THRES(28); dwc3_writel(dwc->regs, DWC3_DCTL, reg); -- cgit v1.2.3 From dd864f20b382b131bfe10c87c5c81985f5bafa54 Mon Sep 17 00:00:00 2001 From: Pratyush Anand Date: Mon, 2 Jul 2012 10:21:53 +0530 Subject: usb: dwc3: no need to clear INIT{U1,U2}ENA bits as per databook, these bits are cleared by hardware on each USB reset, so no need to clear it explicitly by software in reset ISR. Signed-off-by: Pratyush Anand Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index f732f2ccb9b..e7450931125 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2020,7 +2020,6 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) reg = dwc3_readl(dwc->regs, DWC3_DCTL); reg &= ~DWC3_DCTL_TSTCTRL_MASK; - reg &= ~(DWC3_DCTL_INITU1ENA | DWC3_DCTL_INITU2ENA); reg |= (DWC3_DCTL_ACCEPTU1ENA | DWC3_DCTL_ACCEPTU2ENA); dwc3_writel(dwc->regs, DWC3_DCTL, reg); dwc->test_mode = false; -- cgit v1.2.3 From e274a31e29b6a097c32f526493f4ebce10856dcb Mon Sep 17 00:00:00 2001 From: Pratyush Anand Date: Mon, 2 Jul 2012 10:21:54 +0530 Subject: usb: dwc3: enable ACCEPT{U1,U2}ENA when SetConfiguration received As per databook, ACCEPT{U1,U2}ENA bits should be set after receiving SetConfiguration Command. Signed-off-by: Pratyush Anand Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/ep0.c | 9 +++++++++ drivers/usb/dwc3/gadget.c | 1 - 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 1315e787a31..9b94886b66e 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -474,6 +474,7 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) { u32 cfg; int ret; + u32 reg; dwc->start_config_issued = false; cfg = le16_to_cpu(ctrl->wValue); @@ -488,6 +489,14 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) /* if the cfg matches and the cfg is non zero */ if (cfg && (!ret || (ret == USB_GADGET_DELAYED_STATUS))) { dwc->dev_state = DWC3_CONFIGURED_STATE; + /* + * Enable transition to U1/U2 state when + * nothing is pending from application. + */ + reg = dwc3_readl(dwc->regs, DWC3_DCTL); + reg |= (DWC3_DCTL_ACCEPTU1ENA | DWC3_DCTL_ACCEPTU2ENA); + dwc3_writel(dwc->regs, DWC3_DCTL, reg); + dwc->resize_fifos = true; dev_dbg(dwc->dev, "resize fifos flag SET\n"); } diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index e7450931125..39626e366a8 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2020,7 +2020,6 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) reg = dwc3_readl(dwc->regs, DWC3_DCTL); reg &= ~DWC3_DCTL_TSTCTRL_MASK; - reg |= (DWC3_DCTL_ACCEPTU1ENA | DWC3_DCTL_ACCEPTU2ENA); dwc3_writel(dwc->regs, DWC3_DCTL, reg); dwc->test_mode = false; -- cgit v1.2.3 From 6f17f74b3d8345663f5fcfd834145685110075bd Mon Sep 17 00:00:00 2001 From: Pratyush Anand Date: Mon, 2 Jul 2012 10:21:55 +0530 Subject: usb: dwc3: return error in case of run/stop timeout Although timeout has never been experienced, still to make it meaningful, its better to return error if it ever occurs. Signed-off-by: Pratyush Anand Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 39626e366a8..aedc1c5cfac 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1408,7 +1408,7 @@ static int dwc3_gadget_set_selfpowered(struct usb_gadget *g, return 0; } -static void dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on) +static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on) { u32 reg; u32 timeout = 500; @@ -1440,7 +1440,7 @@ static void dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on) } timeout--; if (!timeout) - break; + return -ETIMEDOUT; udelay(1); } while (1); @@ -1448,20 +1448,23 @@ static void dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on) dwc->gadget_driver ? dwc->gadget_driver->function : "no-function", is_on ? "connect" : "disconnect"); + + return 0; } static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on) { struct dwc3 *dwc = gadget_to_dwc(g); unsigned long flags; + int ret; is_on = !!is_on; spin_lock_irqsave(&dwc->lock, flags); - dwc3_gadget_run_stop(dwc, is_on); + ret = dwc3_gadget_run_stop(dwc, is_on); spin_unlock_irqrestore(&dwc->lock, flags); - return 0; + return ret; } static int dwc3_gadget_start(struct usb_gadget *g, -- cgit v1.2.3