usb: gadget: dwc2: avoid reset core before devices connected

Theoretically, the UDC register need not reconfig when GINTSTS.USBRst
is set, and only do core reset if the devices was connected before.
This change adds _connected_ flag to check the devices was really
connected or not. As an optimization, reset device address to zero
while GINTSTS.USBRst is set.

This patch fix usb connect failed when continuously perform the
'fastboot reboot-bootloader' command.

Change-Id: I6a78228e147d2274329d922ac3f3ffef19492e7e
Signed-off-by: Frank Wang <frank.wang@rock-chips.com>
This commit is contained in:
Frank Wang 2017-11-08 15:36:48 +08:00 committed by Kever Yang
parent d007e7964b
commit a52e8dd4da
4 changed files with 16 additions and 2 deletions

View File

@ -169,6 +169,7 @@ static void udc_disable(struct dwc2_udc *dev)
dev->ep0state = WAIT_FOR_SETUP;
dev->gadget.speed = USB_SPEED_UNKNOWN;
dev->usb_address = 0;
dev->connected = 0;
otg_phy_off(dev);
}

View File

@ -86,6 +86,7 @@ struct dwc2_udc {
unsigned char usb_address;
unsigned req_pending:1, req_std:1;
unsigned connected:1;
};
#define ep_is_in(EP) (((EP)->bEndpointAddress&USB_DIR_IN) == USB_DIR_IN)

View File

@ -238,6 +238,7 @@ struct dwc2_usbotg_reg {
#define DEV_SPEED_FULL_SPEED_11 (0x3 << 0)
#define EP_MISS_CNT(x) (x << 18)
#define DEVICE_ADDRESS(x) (x << 4)
#define DCFG_DEVADDR_MASK (0x7f << 4)
/* Core Reset Register (GRSTCTL) */
#define TX_FIFO_FLUSH (0x1 << 5)

View File

@ -544,6 +544,9 @@ static int dwc2_udc_irq(int irq, void *_dev)
}
if (intr_status & INT_RESET) {
u32 temp;
u32 connected = dev->connected;
usb_status = readl(&reg->gotgctl);
debug_cond(DEBUG_ISR,
"\tReset interrupt - (GOTGCTL):0x%x\n", usb_status);
@ -554,7 +557,15 @@ static int dwc2_udc_irq(int irq, void *_dev)
debug_cond(DEBUG_ISR,
"\t\tOTG core got reset (%d)!!\n",
reset_available);
reconfig_usbd(dev);
/* Reset device address to zero */
temp = readl(&reg->dcfg);
temp &= ~DCFG_DEVADDR_MASK;
writel(temp, &reg->dcfg);
/* Soft reset the core if connected */
if (connected)
reconfig_usbd(dev);
dev->ep0state = WAIT_FOR_SETUP;
reset_available = 0;
dwc2_udc_pre_setup();
@ -1348,7 +1359,7 @@ static void dwc2_ep0_setup(struct dwc2_udc *dev)
if (usb_ctrl->bRequestType
!= (USB_TYPE_STANDARD | USB_RECIP_DEVICE))
break;
dev->connected = 1;
udc_set_address(dev, usb_ctrl->wValue);
return;