Skip to content

Commit 7383e86

Browse files
committed
[nrf fromtree] drivers: udc_dwc2: Disable endpoint while hibernated
When the endpoint is disabled while the core is hibernated, there are timeouts waiting for interrupts. It is not clear how the stack should behave when class and/or application wants to disable the endpoint while device is suspended. The problem was originally observed when the endpoints were disabled as a result of usbd_disable() call. Avoid the timeouts by modifying the backup values instead of the real registers (which are not accessible when hibernated). Split the 32-bit txf_set variable into two 16-bit variables (txf_set and pending_tx_flush) because maximum number of TxFIFO instances is 16. The txf_set variable is used as-is, while the pending_tx_flush is used to keep track of TxFIFOs that have to be flushed on hibernation exit. Signed-off-by: Tomasz Moń <[email protected]> (cherry picked from commit 2be960a)
1 parent 3d114bd commit 7383e86

File tree

1 file changed

+45
-1
lines changed

1 file changed

+45
-1
lines changed

drivers/usb/udc/udc_dwc2.c

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,11 +110,12 @@ struct udc_dwc2_data {
110110
struct k_event xfer_finished;
111111
struct dwc2_reg_backup backup;
112112
uint32_t ghwcfg1;
113-
uint32_t txf_set;
114113
uint32_t max_xfersize;
115114
uint32_t max_pktcnt;
116115
uint32_t tx_len[16];
117116
uint32_t rx_siz[16];
117+
uint16_t txf_set;
118+
uint16_t pending_tx_flush;
118119
uint16_t dfifodepth;
119120
uint16_t rxfifo_depth;
120121
uint16_t max_txfifo_depth[16];
@@ -1484,6 +1485,7 @@ static int dwc2_unset_dedicated_fifo(const struct device *dev,
14841485
static void udc_dwc2_ep_disable(const struct device *dev,
14851486
struct udc_ep_config *const cfg, bool stall)
14861487
{
1488+
struct udc_dwc2_data *const priv = udc_get_private(dev);
14871489
struct usb_dwc2_reg *const base = dwc2_get_base(dev);
14881490
uint8_t ep_idx = USB_EP_GET_IDX(cfg->addr);
14891491
mem_addr_t dxepctl_reg;
@@ -1493,6 +1495,40 @@ static void udc_dwc2_ep_disable(const struct device *dev,
14931495
dxepctl_reg = dwc2_get_dxepctl_reg(dev, cfg->addr);
14941496
dxepctl = sys_read32(dxepctl_reg);
14951497

1498+
if (priv->hibernated) {
1499+
/* Currently USB stack calls this function while hibernated,
1500+
* for example if usbd_disable() is called. We cannot access the
1501+
* real registers when hibernated, so just modify backup values
1502+
* that will be restored on hibernation exit.
1503+
*/
1504+
if (USB_EP_DIR_IS_OUT(cfg->addr)) {
1505+
dxepctl = priv->backup.doepctl[ep_idx];
1506+
1507+
dxepctl &= ~USB_DWC2_DEPCTL_EPENA;
1508+
if (stall) {
1509+
dxepctl |= USB_DWC2_DEPCTL_STALL;
1510+
} else {
1511+
dxepctl |= USB_DWC2_DEPCTL_SNAK;
1512+
}
1513+
1514+
priv->backup.doepctl[ep_idx] = dxepctl;
1515+
} else {
1516+
dxepctl = priv->backup.diepctl[ep_idx];
1517+
1518+
dxepctl &= ~USB_DWC2_DEPCTL_EPENA;
1519+
dxepctl |= USB_DWC2_DEPCTL_SNAK;
1520+
if (stall) {
1521+
dxepctl |= USB_DWC2_DEPCTL_STALL;
1522+
}
1523+
1524+
priv->backup.diepctl[ep_idx] = dxepctl;
1525+
1526+
priv->pending_tx_flush |= BIT(usb_dwc2_get_depctl_txfnum(dxepctl));
1527+
}
1528+
1529+
return;
1530+
}
1531+
14961532
if (!is_iso && (dxepctl & USB_DWC2_DEPCTL_NAKSTS)) {
14971533
/* Endpoint already sends forced NAKs. STALL if necessary. */
14981534
if (stall) {
@@ -2162,6 +2198,7 @@ static int udc_dwc2_disable(const struct device *dev)
21622198
if (priv->hibernated) {
21632199
dwc2_exit_hibernation(dev, false, true);
21642200
priv->hibernated = 0;
2201+
priv->pending_tx_flush = 0;
21652202
}
21662203

21672204
sys_clear_bits((mem_addr_t)&base->gahbcfg, USB_DWC2_GAHBCFG_GLBINTRMASK);
@@ -2926,6 +2963,13 @@ static void dwc2_handle_hibernation_exit(const struct device *dev,
29262963
k_event_post(&priv->drv_evt, BIT(DWC2_DRV_EVT_EP_FINISHED));
29272964
}
29282965
}
2966+
2967+
while (priv->pending_tx_flush) {
2968+
unsigned int fifo = find_lsb_set(priv->pending_tx_flush) - 1;
2969+
2970+
priv->pending_tx_flush &= ~BIT(fifo);
2971+
dwc2_flush_tx_fifo(dev, fifo);
2972+
}
29292973
}
29302974

29312975
static uint8_t pull_next_ep_from_bitmap(uint32_t *bitmap)

0 commit comments

Comments
 (0)