drivers: udc_dwc2: Fix timeouts when disabling endpoints

Do not set NAK bit again for endpoints that already have NAK bit set.
Do not wait for OUT endpoint 0 disable because it cannot be disabled by
application (DOEPCTL0 EPDis bit is Read-Only).

Disable endpoints before disabling interrupts because it is necessary to
handle RXFLVL interrupt (in Slave mode) for GOUTNAKEFF to become active.

Signed-off-by: Tomasz Moń <tomasz.mon@nordicsemi.no>
This commit is contained in:
Tomasz Moń 2024-05-21 11:56:28 +02:00 committed by Henrik Brix Andersen
commit 4db14f83e5

View file

@ -1258,6 +1258,16 @@ static void udc_dwc2_ep_disable(const struct device *dev,
dxepctl_reg = dwc2_get_dxepctl_reg(dev, cfg->addr);
dxepctl = sys_read32(dxepctl_reg);
if (dxepctl & USB_DWC2_DEPCTL_NAKSTS) {
/* Endpoint already sends forced NAKs. STALL if necessary. */
if (stall) {
dxepctl |= USB_DWC2_DEPCTL_STALL;
sys_write32(dxepctl, dxepctl_reg);
}
return;
}
if (USB_EP_DIR_IS_OUT(cfg->addr)) {
mem_addr_t dctl_reg, gintsts_reg, doepint_reg;
uint32_t dctl;
@ -1278,7 +1288,11 @@ static void udc_dwc2_ep_disable(const struct device *dev,
dwc2_wait_for_bit(gintsts_reg, USB_DWC2_GINTSTS_GOUTNAKEFF);
dxepctl |= USB_DWC2_DEPCTL_EPENA | USB_DWC2_DEPCTL_EPDIS;
/* The application cannot disable control OUT endpoint 0. */
if (ep_idx != 0) {
dxepctl |= USB_DWC2_DEPCTL_EPENA | USB_DWC2_DEPCTL_EPDIS;
}
if (stall) {
/* For OUT endpoints STALL is set instead of SNAK */
dxepctl |= USB_DWC2_DEPCTL_STALL;
@ -1287,7 +1301,9 @@ static void udc_dwc2_ep_disable(const struct device *dev,
}
sys_write32(dxepctl, dxepctl_reg);
dwc2_wait_for_bit(doepint_reg, USB_DWC2_DOEPINT_EPDISBLD);
if (ep_idx != 0) {
dwc2_wait_for_bit(doepint_reg, USB_DWC2_DOEPINT_EPDISBLD);
}
/* Clear Endpoint Disabled interrupt */
sys_write32(USB_DWC2_DIEPINT_EPDISBLD, doepint_reg);
@ -1712,9 +1728,6 @@ static int udc_dwc2_disable(const struct device *dev)
sys_set_bits(dctl_reg, USB_DWC2_DCTL_SFTDISCON);
LOG_DBG("Disable device %p", dev);
config->irq_disable_func(dev);
sys_clear_bits((mem_addr_t)&base->gahbcfg, USB_DWC2_GAHBCFG_GLBINTRMASK);
if (udc_ep_disable_internal(dev, USB_CONTROL_EP_OUT)) {
LOG_DBG("Failed to disable control endpoint");
return -EIO;
@ -1725,6 +1738,9 @@ static int udc_dwc2_disable(const struct device *dev)
return -EIO;
}
config->irq_disable_func(dev);
sys_clear_bits((mem_addr_t)&base->gahbcfg, USB_DWC2_GAHBCFG_GLBINTRMASK);
err = dwc2_quirk_disable(dev);
if (err) {
LOG_ERR("Quirk disable failed %d", err);