Skip to content

Commit 1ebfcf3

Browse files
committed
[nrf fromtree] drivers: udc_dwc2: Reset core on shutdown
OUT endpoint 0 cannot be disabled and therefore the only way to forcibly reclaim the buffer is to reset the core. The reset does not finish if PHY clock is not running, but just triggering the reset seems to be enough to be able to reclaim the buffer. Signed-off-by: Tomasz Moń <[email protected]> (cherry picked from commit 2395452)
1 parent a4741f2 commit 1ebfcf3

File tree

1 file changed

+24
-12
lines changed

1 file changed

+24
-12
lines changed

drivers/usb/udc/udc_dwc2.c

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1661,15 +1661,6 @@ static int udc_dwc2_ep_deactivate(const struct device *dev,
16611661
sys_write32(dxepctl, dxepctl_reg);
16621662
dwc2_set_epint(dev, cfg, false);
16631663

1664-
if (cfg->addr == USB_CONTROL_EP_OUT) {
1665-
struct net_buf *buf = udc_buf_get_all(dev, cfg->addr);
1666-
1667-
/* Release the buffer allocated in dwc2_ctrl_feed_dout() */
1668-
if (buf) {
1669-
net_buf_unref(buf);
1670-
}
1671-
}
1672-
16731664
return 0;
16741665
}
16751666

@@ -1875,10 +1866,16 @@ static int dwc2_core_soft_reset(const struct device *dev)
18751866
}
18761867

18771868
k_busy_wait(1);
1869+
1870+
if (dwc2_quirk_is_phy_clk_off(dev)) {
1871+
/* Software reset won't finish without PHY clock */
1872+
return -EIO;
1873+
}
18781874
} while (sys_read32(grstctl_reg) & USB_DWC2_GRSTCTL_CSFTRST &&
18791875
!(sys_read32(grstctl_reg) & USB_DWC2_GRSTCTL_CSFTRSTDONE));
18801876

1881-
sys_clear_bits(grstctl_reg, USB_DWC2_GRSTCTL_CSFTRST | USB_DWC2_GRSTCTL_CSFTRSTDONE);
1877+
/* CSFTRSTDONE is W1C so the write must have the bit set to clear it */
1878+
sys_clear_bits(grstctl_reg, USB_DWC2_GRSTCTL_CSFTRST);
18821879

18831880
return 0;
18841881
}
@@ -2177,10 +2174,9 @@ static int udc_dwc2_disable(const struct device *dev)
21772174
struct udc_dwc2_data *const priv = udc_get_private(dev);
21782175
struct usb_dwc2_reg *const base = dwc2_get_base(dev);
21792176
mem_addr_t dctl_reg = (mem_addr_t)&base->dctl;
2177+
struct net_buf *buf;
21802178
int err;
21812179

2182-
/* Enable soft disconnect */
2183-
sys_set_bits(dctl_reg, USB_DWC2_DCTL_SFTDISCON);
21842180
LOG_DBG("Disable device %p", dev);
21852181

21862182
if (udc_ep_disable_internal(dev, USB_CONTROL_EP_OUT)) {
@@ -2203,6 +2199,22 @@ static int udc_dwc2_disable(const struct device *dev)
22032199

22042200
sys_clear_bits((mem_addr_t)&base->gahbcfg, USB_DWC2_GAHBCFG_GLBINTRMASK);
22052201

2202+
/* Enable soft disconnect */
2203+
sys_set_bits(dctl_reg, USB_DWC2_DCTL_SFTDISCON);
2204+
2205+
/* OUT endpoint 0 cannot be disabled by software. The buffer allocated
2206+
* in dwc2_ctrl_feed_dout() can only be freed after core reset if the
2207+
* core was in Buffer DMA mode.
2208+
*
2209+
* Soft Reset does timeout if PHY clock is not running. However, just
2210+
* triggering Soft Reset seems to be enough on shutdown clean up.
2211+
*/
2212+
dwc2_core_soft_reset(dev);
2213+
buf = udc_buf_get_all(dev, USB_CONTROL_EP_OUT);
2214+
if (buf) {
2215+
net_buf_unref(buf);
2216+
}
2217+
22062218
err = dwc2_quirk_disable(dev);
22072219
if (err) {
22082220
LOG_ERR("Quirk disable failed %d", err);

0 commit comments

Comments
 (0)