From d239ae204c402ab21e65718636d226bce79edec9 Mon Sep 17 00:00:00 2001 From: Marc Desvaux Date: Mon, 6 Nov 2023 09:25:47 +0100 Subject: [PATCH 1/6] drivers: usb: device: usb_dc_stm32 issue USB drivers Isochronous endpoint issue with USB drivers on STM32G491 we setup an isochronous endpoint and are having an issue where every other frame sends the desired data sandwiched between garbage data. For isochronous the parameter ep_kind into the fonction : HAL_PCDEx_PMAConfig(PCD_HandleTypeDef *hpcd, uint16_t ep_addr, uint16_t ep_kind, uint32_t pmaadress) must be PCD_DBL_BUF. The parameter pmaadress (EP address in The PMA) is like that: EP address in The PMA: In case of single buffer endpoint this parameter is 16-bit value providing the address in PMA allocated to endpoint. In case of double buffer endpoint this parameter is a 32-bit value providing the endpoint buffer 0 address in the LSB part of 32-bit value and endpoint buffer 1 address in the MSB part of 32-bit value. Signed-off-by: Marc Desvaux --- drivers/usb/device/usb_dc_stm32.c | 35 ++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/drivers/usb/device/usb_dc_stm32.c b/drivers/usb/device/usb_dc_stm32.c index de0a8bc2a2777b..fe2c0b65f5da1c 100644 --- a/drivers/usb/device/usb_dc_stm32.c +++ b/drivers/usb/device/usb_dc_stm32.c @@ -639,20 +639,39 @@ int usb_dc_ep_configure(const struct usb_dc_ep_cfg_data * const ep_cfg) LOG_DBG("ep 0x%02x, previous ep_mps %u, ep_mps %u, ep_type %u", ep_cfg->ep_addr, ep_state->ep_mps, ep_cfg->ep_mps, ep_cfg->ep_type); - #if defined(USB) || defined(USB_DRD_FS) if (ep_cfg->ep_mps > ep_state->ep_pma_buf_len) { - if (USB_RAM_SIZE <= - (usb_dc_stm32_state.pma_offset + ep_cfg->ep_mps)) { + if (ep_cfg->ep_type == USB_DC_EP_ISOCHRONOUS) { + if (USB_RAM_SIZE <= + (usb_dc_stm32_state.pma_offset + ep_cfg->ep_mps*2)) { + return -EINVAL; + } + } else if (USB_RAM_SIZE <= + (usb_dc_stm32_state.pma_offset + ep_cfg->ep_mps)) { return -EINVAL; } - HAL_PCDEx_PMAConfig(&usb_dc_stm32_state.pcd, ep, PCD_SNG_BUF, - usb_dc_stm32_state.pma_offset); - ep_state->ep_pma_buf_len = ep_cfg->ep_mps; - usb_dc_stm32_state.pma_offset += ep_cfg->ep_mps; + + if (ep_cfg->ep_type == USB_DC_EP_ISOCHRONOUS) { + HAL_PCDEx_PMAConfig(&usb_dc_stm32_state.pcd, ep, PCD_DBL_BUF, + usb_dc_stm32_state.pma_offset + + ((usb_dc_stm32_state.pma_offset + ep_cfg->ep_mps) << 16)); + ep_state->ep_pma_buf_len = ep_cfg->ep_mps*2; + usb_dc_stm32_state.pma_offset += ep_cfg->ep_mps*2; + } else { + HAL_PCDEx_PMAConfig(&usb_dc_stm32_state.pcd, ep, PCD_SNG_BUF, + usb_dc_stm32_state.pma_offset); + ep_state->ep_pma_buf_len = ep_cfg->ep_mps; + usb_dc_stm32_state.pma_offset += ep_cfg->ep_mps; + } } -#endif + if (ep_cfg->ep_type == USB_DC_EP_ISOCHRONOUS) { + ep_state->ep_mps = ep_cfg->ep_mps*2; + } else { + ep_state->ep_mps = ep_cfg->ep_mps; + } +#else ep_state->ep_mps = ep_cfg->ep_mps; +#endif switch (ep_cfg->ep_type) { case USB_DC_EP_CONTROL: From b0765fa376fb22cd1bc354123a59af0092d260e0 Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Thu, 7 Dec 2023 12:35:49 +0100 Subject: [PATCH 2/6] drivers: usb stm32H5 and stm32U5 have an independent power supply The stm32H5 mcu has an independent USB supply to be enabled at init with LL_PWR_EnableVDDUSB function like the stm32U5 serie. Both series have PWR_USBSCR_USB33SV bit in their USBSCR POWER reg. and other series all have PWR_CR2_USV bit in their CR2 POWER reg. Signed-off-by: Francois Ramu --- drivers/usb/device/usb_dc_stm32.c | 11 +++++++---- drivers/usb/udc/udc_stm32.c | 9 ++++++--- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/usb/device/usb_dc_stm32.c b/drivers/usb/device/usb_dc_stm32.c index fe2c0b65f5da1c..d1434d3ab4b962 100644 --- a/drivers/usb/device/usb_dc_stm32.c +++ b/drivers/usb/device/usb_dc_stm32.c @@ -217,10 +217,13 @@ static int usb_dc_stm32_clock_enable(void) return -ENODEV; } -#ifdef CONFIG_SOC_SERIES_STM32U5X - /* VDDUSB independent USB supply (PWR clock is on) */ +#ifdef PWR_USBSCR_USB33SV + /* + * VDDUSB independent USB supply (PWR clock is on) + * with LL_PWR_EnableVDDUSB function (higher case) + */ LL_PWR_EnableVDDUSB(); -#endif /* CONFIG_SOC_SERIES_STM32U5X */ +#endif /* PWR_USBSCR_USB33SV */ if (DT_INST_NUM_CLOCKS(0) > 1) { if (clock_control_configure(clk, (clock_control_subsys_t)&pclken[1], @@ -508,7 +511,7 @@ int usb_dc_attach(void) /* * Required for at least STM32L4 devices as they electrically - * isolate USB features from VDDUSB. It must be enabled before + * isolate USB features from VddUSB. It must be enabled before * USB can function. Refer to section 5.1.3 in DM00083560 or * DM00310109. */ diff --git a/drivers/usb/udc/udc_stm32.c b/drivers/usb/udc/udc_stm32.c index 88070329cc30a9..bfa3ee8e0f76c7 100644 --- a/drivers/usb/udc/udc_stm32.c +++ b/drivers/usb/udc/udc_stm32.c @@ -914,10 +914,13 @@ static int priv_clock_enable(void) return -ENODEV; } -#ifdef CONFIG_SOC_SERIES_STM32U5X - /* VDDUSB independent USB supply (PWR clock is on) */ +#if defined(PWR_USBSCR_USB33SV) + /* + * VDDUSB independent USB supply (PWR clock is on) + * with LL_PWR_EnableVDDUSB function (higher case) + */ LL_PWR_EnableVDDUSB(); -#endif /* CONFIG_SOC_SERIES_STM32U5X */ +#endif /* PWR_USBSCR_USB33SV */ #if defined(CONFIG_SOC_SERIES_STM32H7X) LL_PWR_EnableUSBVoltageDetector(); From d6c100a769bc7b05b993c8e17335ea261a677eed Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Wed, 3 Jan 2024 12:58:58 +0100 Subject: [PATCH 3/6] drivers: usb: stm32U5 usb device controller Like the stm32H5, stm32u5 usb device has an independent power supply, but control bit is PWR_SVMCR_USV. The control bit for the stm32H5 is PWR_USBSCR_USB33SV (no change) Signed-off-by: Francois Ramu --- drivers/usb/device/usb_dc_stm32.c | 5 +++-- drivers/usb/udc/udc_stm32.c | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/usb/device/usb_dc_stm32.c b/drivers/usb/device/usb_dc_stm32.c index d1434d3ab4b962..326c6e284a2d55 100644 --- a/drivers/usb/device/usb_dc_stm32.c +++ b/drivers/usb/device/usb_dc_stm32.c @@ -217,13 +217,14 @@ static int usb_dc_stm32_clock_enable(void) return -ENODEV; } -#ifdef PWR_USBSCR_USB33SV +#if defined(PWR_USBSCR_USB33SV) || defined(PWR_SVMCR_USV) + /* * VDDUSB independent USB supply (PWR clock is on) * with LL_PWR_EnableVDDUSB function (higher case) */ LL_PWR_EnableVDDUSB(); -#endif /* PWR_USBSCR_USB33SV */ +#endif /* PWR_USBSCR_USB33SV or PWR_SVMCR_USV */ if (DT_INST_NUM_CLOCKS(0) > 1) { if (clock_control_configure(clk, (clock_control_subsys_t)&pclken[1], diff --git a/drivers/usb/udc/udc_stm32.c b/drivers/usb/udc/udc_stm32.c index bfa3ee8e0f76c7..e11228619b8f35 100644 --- a/drivers/usb/udc/udc_stm32.c +++ b/drivers/usb/udc/udc_stm32.c @@ -914,13 +914,13 @@ static int priv_clock_enable(void) return -ENODEV; } -#if defined(PWR_USBSCR_USB33SV) +#if defined(PWR_USBSCR_USB33SV) || defined(PWR_SVMCR_USV) /* * VDDUSB independent USB supply (PWR clock is on) * with LL_PWR_EnableVDDUSB function (higher case) */ LL_PWR_EnableVDDUSB(); -#endif /* PWR_USBSCR_USB33SV */ +#endif /* PWR_USBSCR_USB33SV or PWR_SVMCR_USV */ #if defined(CONFIG_SOC_SERIES_STM32H7X) LL_PWR_EnableUSBVoltageDetector(); From 68b9bb3f48c80b0add26f772799243b608cc27ad Mon Sep 17 00:00:00 2001 From: Marc Desvaux Date: Fri, 19 Jan 2024 10:38:38 +0100 Subject: [PATCH 4/6] drivers: usb_dc_stm32: Fix OUT transfer issue The driver cannot handle OUT transactions for an endpoint with an MPS smaller than 64 bytes. To solve the issue, we will not use one fixed value, EP_MPS, but instead use the actual MPS of an endpoint, ep_state->ep_mps. Signed-off-by: Marc Desvaux Signed-off-by: Loic Poulain --- drivers/usb/device/usb_dc_stm32.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/device/usb_dc_stm32.c b/drivers/usb/device/usb_dc_stm32.c index 326c6e284a2d55..13131061610064 100644 --- a/drivers/usb/device/usb_dc_stm32.c +++ b/drivers/usb/device/usb_dc_stm32.c @@ -784,7 +784,7 @@ int usb_dc_ep_enable(const uint8_t ep) if (USB_EP_DIR_IS_OUT(ep) && ep != EP0_OUT) { return usb_dc_ep_start_read(ep, usb_dc_stm32_state.ep_buf[USB_EP_GET_IDX(ep)], - EP_MPS); + ep_state->ep_mps); } return 0; @@ -923,7 +923,7 @@ int usb_dc_ep_read_continue(uint8_t ep) */ if (!ep_state->read_count) { usb_dc_ep_start_read(ep, usb_dc_stm32_state.ep_buf[USB_EP_GET_IDX(ep)], - EP_MPS); + ep_state->ep_mps); } return 0; From 71095ffca3d12eeae571469487d2360b37e41e59 Mon Sep 17 00:00:00 2001 From: Armin Brauns Date: Wed, 27 Mar 2024 13:52:08 +0000 Subject: [PATCH 5/6] usb: stm32: fix calculation of TX FIFO sizes The RX FIFO size is in words, so needs to be subtracted from the total memory size *after* it's divided by 4. Fixes #70789. Signed-off-by: Armin Brauns --- drivers/usb/device/usb_dc_stm32.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/usb/device/usb_dc_stm32.c b/drivers/usb/device/usb_dc_stm32.c index 13131061610064..7be05d95ee3ed0 100644 --- a/drivers/usb/device/usb_dc_stm32.c +++ b/drivers/usb/device/usb_dc_stm32.c @@ -131,10 +131,10 @@ static const struct gpio_dt_spec ulpi_reset = #define TX_FIFO_NUM USB_NUM_BIDIR_ENDPOINTS /* We need a minimum size for RX FIFO */ -#define USB_FIFO_RX_MIN 160 +#define RX_FIFO_EP_WORDS 160 /* 4-byte words TX FIFO */ -#define TX_FIFO_WORDS ((USB_RAM_SIZE - USB_FIFO_RX_MIN - 64) / 4) +#define TX_FIFO_WORDS ((USB_RAM_SIZE - 64) / 4 - RX_FIFO_EP_WORDS) /* Allocate FIFO memory evenly between the TX FIFOs */ /* except the first TX endpoint need only 64 bytes */ @@ -446,7 +446,7 @@ static int usb_dc_stm32_init(void) #else /* USB_OTG_FS */ /* TODO: make this dynamic (depending usage) */ - HAL_PCDEx_SetRxFiFo(&usb_dc_stm32_state.pcd, USB_FIFO_RX_MIN); + HAL_PCDEx_SetRxFiFo(&usb_dc_stm32_state.pcd, RX_FIFO_EP_WORDS); for (i = 0U; i < USB_NUM_BIDIR_ENDPOINTS; i++) { if (i == 0) { /* first endpoint need only 64 byte for EP_TYPE_CTRL */ From d65978cfb2537bb2940547600ce13528ca0bc704 Mon Sep 17 00:00:00 2001 From: Armin Brauns Date: Wed, 27 Mar 2024 13:52:42 +0000 Subject: [PATCH 6/6] usb: stm32: clarify calculation of FIFO sizes Magic constants throughout the code made this difficult to reason about, especially with two different units of measurement (bytes and words) at play. Signed-off-by: Armin Brauns --- drivers/usb/device/usb_dc_stm32.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/usb/device/usb_dc_stm32.c b/drivers/usb/device/usb_dc_stm32.c index 7be05d95ee3ed0..75ce9442f8e822 100644 --- a/drivers/usb/device/usb_dc_stm32.c +++ b/drivers/usb/device/usb_dc_stm32.c @@ -130,14 +130,14 @@ static const struct gpio_dt_spec ulpi_reset = /* We need n TX IN FIFOs */ #define TX_FIFO_NUM USB_NUM_BIDIR_ENDPOINTS -/* We need a minimum size for RX FIFO */ +/* We need a minimum size for RX FIFO - exact number seemingly determined through trial and error */ #define RX_FIFO_EP_WORDS 160 -/* 4-byte words TX FIFO */ -#define TX_FIFO_WORDS ((USB_RAM_SIZE - 64) / 4 - RX_FIFO_EP_WORDS) - /* Allocate FIFO memory evenly between the TX FIFOs */ /* except the first TX endpoint need only 64 bytes */ +#define TX_FIFO_EP_0_WORDS 16 +#define TX_FIFO_WORDS (USB_RAM_SIZE / 4 - RX_FIFO_EP_WORDS - TX_FIFO_EP_0_WORDS) +/* Number of words for each remaining TX endpoint FIFO */ #define TX_FIFO_EP_WORDS (TX_FIFO_WORDS / (TX_FIFO_NUM - 1)) #endif /* USB */ @@ -450,7 +450,8 @@ static int usb_dc_stm32_init(void) for (i = 0U; i < USB_NUM_BIDIR_ENDPOINTS; i++) { if (i == 0) { /* first endpoint need only 64 byte for EP_TYPE_CTRL */ - HAL_PCDEx_SetTxFiFo(&usb_dc_stm32_state.pcd, i, 16); + HAL_PCDEx_SetTxFiFo(&usb_dc_stm32_state.pcd, i, + TX_FIFO_EP_0_WORDS); } else { HAL_PCDEx_SetTxFiFo(&usb_dc_stm32_state.pcd, i, TX_FIFO_EP_WORDS);