From f0cdce4eaa54ed1e7ac0165afe12fb1cee32a027 Mon Sep 17 00:00:00 2001 From: William Wu Date: Tue, 28 Nov 2017 11:43:01 +0800 Subject: [PATCH] usb: dwc_otg_310: use wait-till-ready timeout loop for ep deactivate In some error case, it may fail to set the NAK bit or Disable bit for endpoint when do ep deactivate operation. We need to use wait-till-ready timeout loop for ep deactivate instead of while loop. Change-Id: I0e5ed61b2528f89910333c5eb907677e492fe3a0 Signed-off-by: William Wu --- drivers/usb/dwc_otg_310/dwc_otg_cil.c | 109 +++++++++++++++----------- drivers/usb/dwc_otg_310/dwc_otg_cil.h | 5 ++ drivers/usb/dwc_otg_310/dwc_otg_pcd.c | 15 ---- 3 files changed, 68 insertions(+), 61 deletions(-) diff --git a/drivers/usb/dwc_otg_310/dwc_otg_cil.c b/drivers/usb/dwc_otg_310/dwc_otg_cil.c index 76beb5692b89..b862a5a61308 100644 --- a/drivers/usb/dwc_otg_310/dwc_otg_cil.c +++ b/drivers/usb/dwc_otg_310/dwc_otg_cil.c @@ -3110,6 +3110,20 @@ void set_pid_isoc(dwc_hc_t *hc) } } +int dwc_otg_wait_bit_set(volatile u32 *reg, u32 bit, u32 timeout) +{ + int i; + + for (i = 0; i < timeout; i++) { + if (DWC_READ_REG32(reg) & bit) + return 0; + + dwc_udelay(1); + } + + return -ETIMEDOUT; +} + /** * This function does the setup for a data transfer for a host channel and * starts the transfer. May be called in either Slave mode or DMA mode. In @@ -3883,73 +3897,76 @@ void dwc_otg_ep_deactivate(dwc_otg_core_if_t *core_if, dwc_ep_t *ep) depctl_data_t depctl = {.d32 = 0 }; if (ep->is_in) { diepint_data_t diepint = {.d32 = 0 }; + dwc_otg_dev_in_ep_regs_t *in_ep_reg; + + in_ep_reg = core_if->dev_if->in_ep_regs[ep->num]; depctl.b.snak = 1; - DWC_WRITE_REG32(&core_if->dev_if-> - in_ep_regs[ep->num]->diepctl, + DWC_WRITE_REG32(&in_ep_reg->diepctl, depctl.d32); - do { - dwc_udelay(10); - diepint.d32 = - DWC_READ_REG32(&core_if->dev_if-> - in_ep_regs[ep-> - num]->diepint); - } while (!diepint.b.inepnakeff); + diepint.b.inepnakeff = 1; - DWC_WRITE_REG32(&core_if->dev_if-> - in_ep_regs[ep->num]->diepint, - diepint.d32); + if (dwc_otg_wait_bit_set(&in_ep_reg->diepint, + diepint.d32, 1000)) { + DWC_WARN("%s: timeout diepctl.snak\n", + __func__); + } else { + DWC_WRITE_REG32(&in_ep_reg->diepint, + diepint.d32); + } + depctl.d32 = 0; depctl.b.epdis = 1; - DWC_WRITE_REG32(&core_if->dev_if-> - in_ep_regs[ep->num]->diepctl, + DWC_WRITE_REG32(&in_ep_reg->diepctl, depctl.d32); - do { - dwc_udelay(10); - diepint.d32 = - DWC_READ_REG32(&core_if->dev_if-> - in_ep_regs[ep-> - num]->diepint); - } while (!diepint.b.epdisabled); + + diepint.d32 = 0; diepint.b.epdisabled = 1; - DWC_WRITE_REG32(&core_if->dev_if-> - in_ep_regs[ep->num]->diepint, - diepint.d32); + if (dwc_otg_wait_bit_set(&in_ep_reg->diepint, + diepint.d32, 1000)) { + DWC_WARN("%s: timeout diepctl.epdis\n", + __func__); + } else { + DWC_WRITE_REG32(&in_ep_reg->diepint, + diepint.d32); + } } else { dctl_data_t dctl = {.d32 = 0 }; gintmsk_data_t gintsts = {.d32 = 0 }; doepint_data_t doepint = {.d32 = 0 }; + dwc_otg_dev_out_ep_regs_t *out_ep_reg; + + out_ep_reg = core_if->dev_if->out_ep_regs[ep->num]; + dctl.b.sgoutnak = 1; - DWC_MODIFY_REG32(&core_if->dev_if-> - dev_global_regs->dctl, 0, dctl.d32); - do { - dwc_udelay(10); - gintsts.d32 = - DWC_READ_REG32(&core_if->core_global_regs-> - gintsts); - } while (!gintsts.b.goutnakeff); + DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, + 0, dctl.d32); + gintsts.d32 = 0; gintsts.b.goutnakeff = 1; - DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, - gintsts.d32); + if (dwc_otg_wait_bit_set(&core_if->core_global_regs->gintsts, + gintsts.d32, 1000)) { + DWC_WARN("%s: timeout dctl.sgoutnak\n", + __func__); + } else { + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, + gintsts.d32); + } depctl.d32 = 0; depctl.b.epdis = 1; depctl.b.snak = 1; - DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[ep->num]-> - doepctl, depctl.d32); - do { - dwc_udelay(10); - doepint.d32 = - DWC_READ_REG32(&core_if-> - dev_if->out_ep_regs[ep-> - num]-> - doepint); - } while (!doepint.b.epdisabled); + DWC_WRITE_REG32(&out_ep_reg->doepctl, depctl.d32); doepint.b.epdisabled = 1; - DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[ep->num]-> - doepint, doepint.d32); + if (dwc_otg_wait_bit_set(&out_ep_reg->doepint, + doepint.d32, 1000)) { + DWC_WARN("%s: timeout doepctl.epdis\n", + __func__); + } else { + DWC_WRITE_REG32(&out_ep_reg->doepint, + doepint.d32); + } dctl.d32 = 0; dctl.b.cgoutnak = 1; diff --git a/drivers/usb/dwc_otg_310/dwc_otg_cil.h b/drivers/usb/dwc_otg_310/dwc_otg_cil.h index aac00808fbc8..b7cee654ef9e 100644 --- a/drivers/usb/dwc_otg_310/dwc_otg_cil.h +++ b/drivers/usb/dwc_otg_310/dwc_otg_cil.h @@ -1053,6 +1053,11 @@ extern void hc_xfer_timeout(void *ptr); */ extern void ep_xfer_timeout(void *ptr); +/* + * This function is called when set register and wait for completion. + */ +int dwc_otg_wait_bit_set(volatile u32 *reg, u32 bit, u32 timeout); + /* * The following functions are functions for works * using during handling some interrupts diff --git a/drivers/usb/dwc_otg_310/dwc_otg_pcd.c b/drivers/usb/dwc_otg_310/dwc_otg_pcd.c index 45f763e8031c..ce7263df4556 100644 --- a/drivers/usb/dwc_otg_310/dwc_otg_pcd.c +++ b/drivers/usb/dwc_otg_310/dwc_otg_pcd.c @@ -1706,21 +1706,6 @@ out_unlocked: } -static int dwc_otg_wait_bit_set(volatile uint32_t *reg, - uint32_t bit, uint32_t timeout) -{ - int i; - - for (i = 0; i < timeout; i++) { - if (DWC_READ_REG32(reg) & bit) - return 0; - - dwc_udelay(1); - } - - return -ETIMEDOUT; -} - static void dwc_otg_pcd_ep_stop_transfer(dwc_otg_core_if_t *core_if, dwc_ep_t *ep) {