From be25aa31f6720e0efe96e8656f46adf0ccbbce50 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 26 Nov 2024 10:20:38 +0700 Subject: [PATCH] hcd dwc2 add dcache support, usbh correctly use cache line size with TUH_EPBUF_DEF --- .../components/tinyusb_src/CMakeLists.txt | 3 +- src/host/hcd.h | 6 +- src/host/usbh.c | 72 ++++++++++++------- src/portable/synopsys/dwc2/dcd_dwc2.c | 2 +- src/portable/synopsys/dwc2/hcd_dwc2.c | 28 +++++++- 5 files changed, 78 insertions(+), 33 deletions(-) diff --git a/hw/bsp/espressif/components/tinyusb_src/CMakeLists.txt b/hw/bsp/espressif/components/tinyusb_src/CMakeLists.txt index 9f55c8d5a..95fb2e440 100644 --- a/hw/bsp/espressif/components/tinyusb_src/CMakeLists.txt +++ b/hw/bsp/espressif/components/tinyusb_src/CMakeLists.txt @@ -18,7 +18,8 @@ list(APPEND compile_definitions if (target STREQUAL esp32p4) # P4 change alignment to 64 (DCache line size) for possible DMA configuration list(APPEND compile_definitions - CFG_TUSB_MEM_ALIGN=__attribute__\(\(aligned\(64\)\)\) + CFG_TUD_MEM_ALIGN=__attribute__\(\(aligned\(64\)\)\) + CFG_TUH_MEM_ALIGN=__attribute__\(\(aligned\(64\)\)\) ) endif () diff --git a/src/host/hcd.h b/src/host/hcd.h index 6518e6fd2..56b6fdb5d 100644 --- a/src/host/hcd.h +++ b/src/host/hcd.h @@ -103,15 +103,15 @@ typedef struct { // clean/flush data cache: write cache -> memory. // Required before an DMA TX transfer to make sure data is in memory -bool hcd_dcache_clean(void const* addr, uint32_t data_size) TU_ATTR_WEAK; +bool hcd_dcache_clean(void const* addr, uint32_t data_size); // invalidate data cache: mark cache as invalid, next read will read from memory // Required BOTH before and after an DMA RX transfer -bool hcd_dcache_invalidate(void const* addr, uint32_t data_size) TU_ATTR_WEAK; +bool hcd_dcache_invalidate(void const* addr, uint32_t data_size); // clean and invalidate data cache // Required before an DMA transfer where memory is both read/write by DMA -bool hcd_dcache_clean_invalidate(void const* addr, uint32_t data_size) TU_ATTR_WEAK; +bool hcd_dcache_clean_invalidate(void const* addr, uint32_t data_size); //--------------------------------------------------------------------+ // Controller API diff --git a/src/host/usbh.c b/src/host/usbh.c index b0a2b2160..f2683e235 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -65,6 +65,21 @@ TU_ATTR_WEAK void tuh_event_hook_cb(uint8_t rhport, uint32_t eventid, bool in_is (void) in_isr; } +TU_ATTR_WEAK bool hcd_dcache_clean(const void* addr, uint32_t data_size) { + (void) addr; (void) data_size; + return false; +} + +TU_ATTR_WEAK bool hcd_dcache_invalidate(const void* addr, uint32_t data_size) { + (void) addr; (void) data_size; + return false; +} + +TU_ATTR_WEAK bool hcd_dcache_clean_invalidate(const void* addr, uint32_t data_size) { + (void) addr; (void) data_size; + return false; +} + //--------------------------------------------------------------------+ // USBH-HCD common data structure //--------------------------------------------------------------------+ @@ -249,14 +264,10 @@ static usbh_device_t _usbh_devices[TOTAL_DEVICES]; OSAL_QUEUE_DEF(usbh_int_set, _usbh_qdef, CFG_TUH_TASK_QUEUE_SZ, hcd_event_t); static osal_queue_t _usbh_q; -CFG_TUH_MEM_SECTION CFG_TUH_MEM_ALIGN -static uint8_t _usbh_ctrl_buf[CFG_TUH_ENUMERATION_BUFSIZE]; - // Control transfers: since most controllers do not support multiple control transfers // on multiple devices concurrently and control transfers are not used much except for // enumeration, we will only execute control transfers one at a time. -CFG_TUH_MEM_SECTION struct { - CFG_TUH_MEM_ALIGN tusb_control_request_t request; +static struct { uint8_t* buffer; tuh_xfer_cb_t complete_cb; uintptr_t user_data; @@ -264,7 +275,14 @@ CFG_TUH_MEM_SECTION struct { uint8_t daddr; volatile uint8_t stage; volatile uint16_t actual_len; -}_ctrl_xfer; +} _ctrl_xfer; + +typedef struct { + TUH_EPBUF_TYPE_DEF(request, tusb_control_request_t); + TUH_EPBUF_DEF(ctrl, CFG_TUH_ENUMERATION_BUFSIZE); +} usbh_epbuf_t; + +CFG_TUH_MEM_SECTION static usbh_epbuf_t _usbh_epbuf; //------------- Helper Function -------------// @@ -475,7 +493,7 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr) { switch (event.event_id) { case HCD_EVENT_DEVICE_ATTACH: - // due to the shared _usbh_ctrl_buf, we must complete enumerating one device before enumerating another one. + // due to the shared control buffer, we must complete enumerating one device before enumerating another one. // TODO better to have an separated queue for newly attached devices if (_dev0.enumerating) { // Some device can cause multiple duplicated attach events @@ -622,10 +640,10 @@ bool tuh_control_xfer (tuh_xfer_t* xfer) { _ctrl_xfer.daddr = daddr; _ctrl_xfer.actual_len = 0; - _ctrl_xfer.request = (*xfer->setup); _ctrl_xfer.buffer = xfer->buffer; _ctrl_xfer.complete_cb = xfer->complete_cb; _ctrl_xfer.user_data = xfer->user_data; + _usbh_epbuf.request = (*xfer->setup); } (void) osal_mutex_unlock(_usbh_mutex); @@ -639,7 +657,7 @@ bool tuh_control_xfer (tuh_xfer_t* xfer) { TU_LOG_BUF_USBH(xfer->setup, 8); if (xfer->complete_cb) { - TU_ASSERT( hcd_setup_send(rhport, daddr, (uint8_t const*) &_ctrl_xfer.request) ); + TU_ASSERT( hcd_setup_send(rhport, daddr, (uint8_t const*) &_usbh_epbuf.request) ); }else { // blocking if complete callback is not provided // change callback to internal blocking, and result as user argument @@ -649,7 +667,7 @@ bool tuh_control_xfer (tuh_xfer_t* xfer) { _ctrl_xfer.user_data = (uintptr_t) &result; _ctrl_xfer.complete_cb = _control_blocking_complete_cb; - TU_ASSERT( hcd_setup_send(rhport, daddr, (uint8_t*) &_ctrl_xfer.request) ); + TU_ASSERT( hcd_setup_send(rhport, daddr, (uint8_t*) &_usbh_epbuf.request) ); while (result == XFER_RESULT_INVALID) { // Note: this can be called within an callback ie. part of tuh_task() @@ -681,7 +699,7 @@ static void _control_xfer_complete(uint8_t daddr, xfer_result_t result) { TU_LOG_USBH("\r\n"); // duplicate xfer since user can execute control transfer within callback - tusb_control_request_t const request = _ctrl_xfer.request; + tusb_control_request_t const request = _usbh_epbuf.request; tuh_xfer_t xfer_temp = { .daddr = daddr, .ep_addr = 0, @@ -704,7 +722,7 @@ static bool usbh_control_xfer_cb (uint8_t daddr, uint8_t ep_addr, xfer_result_t (void) ep_addr; const uint8_t rhport = usbh_get_rhport(daddr); - tusb_control_request_t const * request = &_ctrl_xfer.request; + tusb_control_request_t const * request = &_usbh_epbuf.request; if (XFER_RESULT_SUCCESS != result) { TU_LOG_USBH("[%u:%u] Control %s, xferred_bytes = %" PRIu32 "\r\n", rhport, daddr, result == XFER_RESULT_STALLED ? "STALLED" : "FAILED", xferred_bytes); @@ -817,7 +835,7 @@ uint8_t usbh_get_rhport(uint8_t dev_addr) { } uint8_t *usbh_get_enum_buf(void) { - return _usbh_ctrl_buf; + return _usbh_epbuf.ctrl; } void usbh_int_set(bool enabled) { @@ -1279,7 +1297,7 @@ static void process_removing_device(uint8_t rhport, uint8_t hub_addr, uint8_t hu // Enumeration Process // is a lengthy process with a series of control transfer to configure // newly attached device. -// NOTE: due to the shared _usbh_ctrl_buf, we must complete enumerating +// NOTE: due to the shared control buffer, we must complete enumerating // one device before enumerating another one. //--------------------------------------------------------------------+ @@ -1347,7 +1365,7 @@ static void process_enumeration(tuh_xfer_t* xfer) { case ENUM_HUB_CLEAR_RESET_1: { hub_port_status_response_t port_status; - memcpy(&port_status, _usbh_ctrl_buf, sizeof(hub_port_status_response_t)); + memcpy(&port_status, _usbh_epbuf.ctrl, sizeof(hub_port_status_response_t)); if (!port_status.status.connection) { // device unplugged while delaying, nothing else to do @@ -1368,13 +1386,13 @@ static void process_enumeration(tuh_xfer_t* xfer) { case ENUM_HUB_GET_STATUS_2: tusb_time_delay_ms_api(ENUM_RESET_DELAY_MS); - TU_ASSERT(hub_port_get_status(_dev0.hub_addr, _dev0.hub_port, _usbh_ctrl_buf, + TU_ASSERT(hub_port_get_status(_dev0.hub_addr, _dev0.hub_port, _usbh_epbuf.ctrl, process_enumeration, ENUM_HUB_CLEAR_RESET_2),); break; case ENUM_HUB_CLEAR_RESET_2: { hub_port_status_response_t port_status; - memcpy(&port_status, _usbh_ctrl_buf, sizeof(hub_port_status_response_t)); + memcpy(&port_status, _usbh_epbuf.ctrl, sizeof(hub_port_status_response_t)); // Acknowledge Port Reset Change if Reset Successful if (port_status.change.reset) { @@ -1392,7 +1410,7 @@ static void process_enumeration(tuh_xfer_t* xfer) { // Get first 8 bytes of device descriptor for Control Endpoint size TU_LOG_USBH("Get 8 byte of Device Descriptor\r\n"); - TU_ASSERT(tuh_descriptor_get_device(addr0, _usbh_ctrl_buf, 8, + TU_ASSERT(tuh_descriptor_get_device(addr0, _usbh_epbuf.ctrl, 8, process_enumeration, ENUM_SET_ADDR),); break; } @@ -1443,13 +1461,13 @@ static void process_enumeration(tuh_xfer_t* xfer) { // Get full device descriptor TU_LOG_USBH("Get Device Descriptor\r\n"); - TU_ASSERT(tuh_descriptor_get_device(new_addr, _usbh_ctrl_buf, sizeof(tusb_desc_device_t), + TU_ASSERT(tuh_descriptor_get_device(new_addr, _usbh_epbuf.ctrl, sizeof(tusb_desc_device_t), process_enumeration, ENUM_GET_9BYTE_CONFIG_DESC),); break; } case ENUM_GET_9BYTE_CONFIG_DESC: { - tusb_desc_device_t const* desc_device = (tusb_desc_device_t const*) _usbh_ctrl_buf; + tusb_desc_device_t const* desc_device = (tusb_desc_device_t const*) _usbh_epbuf.ctrl; usbh_device_t* dev = get_device(daddr); TU_ASSERT(dev,); @@ -1459,18 +1477,18 @@ static void process_enumeration(tuh_xfer_t* xfer) { dev->i_product = desc_device->iProduct; dev->i_serial = desc_device->iSerialNumber; - // if (tuh_attach_cb) tuh_attach_cb((tusb_desc_device_t*) _usbh_ctrl_buf); + // if (tuh_attach_cb) tuh_attach_cb((tusb_desc_device_t*) _usbh_epbuf.ctrl); // Get 9-byte for total length uint8_t const config_idx = CONFIG_NUM - 1; TU_LOG_USBH("Get Configuration[0] Descriptor (9 bytes)\r\n"); - TU_ASSERT(tuh_descriptor_get_configuration(daddr, config_idx, _usbh_ctrl_buf, 9, + TU_ASSERT(tuh_descriptor_get_configuration(daddr, config_idx, _usbh_epbuf.ctrl, 9, process_enumeration, ENUM_GET_FULL_CONFIG_DESC),); break; } case ENUM_GET_FULL_CONFIG_DESC: { - uint8_t const* desc_config = _usbh_ctrl_buf; + uint8_t const* desc_config = _usbh_epbuf.ctrl; // Use offsetof to avoid pointer to the odd/misaligned address uint16_t const total_len = tu_le16toh( @@ -1482,7 +1500,7 @@ static void process_enumeration(tuh_xfer_t* xfer) { // Get full configuration descriptor uint8_t const config_idx = CONFIG_NUM - 1; TU_LOG_USBH("Get Configuration[0] Descriptor\r\n"); - TU_ASSERT(tuh_descriptor_get_configuration(daddr, config_idx, _usbh_ctrl_buf, total_len, + TU_ASSERT(tuh_descriptor_get_configuration(daddr, config_idx, _usbh_epbuf.ctrl, total_len, process_enumeration, ENUM_SET_CONFIG),); break; } @@ -1500,7 +1518,7 @@ static void process_enumeration(tuh_xfer_t* xfer) { // Parse configuration & set up drivers // driver_open() must not make any usb transfer - TU_ASSERT(_parse_configuration_descriptor(daddr, (tusb_desc_configuration_t*) _usbh_ctrl_buf),); + TU_ASSERT(_parse_configuration_descriptor(daddr, (tusb_desc_configuration_t*) _usbh_epbuf.ctrl),); // Start the Set Configuration process for interfaces (itf = TUSB_INDEX_INVALID_8) // Since driver can perform control transfer within its set_config, this is done asynchronously. @@ -1561,7 +1579,7 @@ static bool enum_new_device(hcd_event_t* event) { tusb_time_delay_ms_api(ENUM_DEBOUNCING_DELAY_MS); // ENUM_HUB_GET_STATUS - TU_ASSERT(hub_port_get_status(_dev0.hub_addr, _dev0.hub_port, _usbh_ctrl_buf, + TU_ASSERT(hub_port_get_status(_dev0.hub_addr, _dev0.hub_port, _usbh_epbuf.ctrl, process_enumeration, ENUM_HUB_CLEAR_RESET_1)); } #endif // hub @@ -1589,7 +1607,7 @@ static uint8_t get_new_address(bool is_hub) { } static bool enum_request_set_addr(void) { - tusb_desc_device_t const* desc_device = (tusb_desc_device_t const*) _usbh_ctrl_buf; + tusb_desc_device_t const* desc_device = (tusb_desc_device_t const*) _usbh_epbuf.ctrl; // Get new address uint8_t const new_addr = get_new_address(desc_device->bDeviceClass == TUSB_CLASS_HUB); diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c index 8a9d06bc2..04108499d 100644 --- a/src/portable/synopsys/dwc2/dcd_dwc2.c +++ b/src/portable/synopsys/dwc2/dcd_dwc2.c @@ -31,7 +31,7 @@ #if CFG_TUD_ENABLED && defined(TUP_USBIP_DWC2) -#if !CFG_TUD_DWC2_SLAVE_ENABLE && !CFG_TUH_DWC2_DMA_ENABLE +#if !(CFG_TUD_DWC2_SLAVE_ENABLE || CFG_TUH_DWC2_DMA_ENABLE) #error DWC2 require either CFG_TUD_DWC2_SLAVE_ENABLE or CFG_TUH_DWC2_DMA_ENABLE to be enabled #endif diff --git a/src/portable/synopsys/dwc2/hcd_dwc2.c b/src/portable/synopsys/dwc2/hcd_dwc2.c index 8e0162ed6..ebbb6200a 100644 --- a/src/portable/synopsys/dwc2/hcd_dwc2.c +++ b/src/portable/synopsys/dwc2/hcd_dwc2.c @@ -28,6 +28,10 @@ #if CFG_TUH_ENABLED && defined(TUP_USBIP_DWC2) +#if !(CFG_TUH_DWC2_SLAVE_ENABLE || CFG_TUH_DWC2_DMA_ENABLE) +#error DWC2 require either CFG_TUH_DWC2_SLAVE_ENABLE or CFG_TUH_DWC2_DMA_ENABLE to be enabled +#endif + // Debug level for DWC2 #define DWC2_DEBUG 2 @@ -132,6 +136,23 @@ TU_ATTR_ALWAYS_INLINE static inline bool dma_host_enabled(const dwc2_regs_t* dwc return CFG_TUH_DWC2_DMA_ENABLE && dwc2->ghwcfg2_bm.arch == GHWCFG2_ARCH_INTERNAL_DMA; } +#if CFG_TUH_MEM_DCACHE_ENABLE +bool hcd_dcache_clean(const void* addr, uint32_t data_size) { + TU_VERIFY(addr && data_size); + return dwc2_dcache_clean(addr, data_size); +} + +bool hcd_dcache_invalidate(const void* addr, uint32_t data_size) { + TU_VERIFY(addr && data_size); + return dwc2_dcache_invalidate(addr, data_size); +} + +bool hcd_dcache_clean_invalidate(const void* addr, uint32_t data_size) { + TU_VERIFY(addr && data_size); + return dwc2_dcache_clean_invalidate(addr, data_size); +} +#endif + // Allocate a channel for new transfer TU_ATTR_ALWAYS_INLINE static inline uint8_t channel_alloc(dwc2_regs_t* dwc2) { const uint8_t max_channel = DWC2_CHANNEL_COUNT(dwc2); @@ -555,6 +576,7 @@ static bool channel_xfer_start(dwc2_regs_t* dwc2, uint8_t ch_id) { if (hcchar_bm->ep_dir == TUSB_DIR_IN) { channel_send_in_token(dwc2, channel); } else { + hcd_dcache_clean(edpt->buffer, edpt->buflen); channel->hcchar |= HCCHAR_CHENA; } } else { @@ -1119,13 +1141,17 @@ static void handle_channel_irq(uint8_t rhport, bool in_isr) { const uint32_t hcint = channel->hcint; channel->hcint = hcint; // clear interrupt - bool is_done; + bool is_done = false; if (is_dma) { #if CFG_TUH_DWC2_DMA_ENABLE if (hcchar_bm.ep_dir == TUSB_DIR_OUT) { is_done = handle_channel_out_dma(dwc2, ch_id, hcint); } else { is_done = handle_channel_in_dma(dwc2, ch_id, hcint); + if (is_done && (channel->hcdma > xfer->xferred_bytes)) { + // hcdma is increased by word --> need to align4 + hcd_dcache_invalidate((void*) tu_align4(channel->hcdma - xfer->xferred_bytes), xfer->xferred_bytes); + } } #endif } else {