From 3fb9c86f9620ce1618294042408014eb32cc9f21 Mon Sep 17 00:00:00 2001 From: Roman Leonov Date: Tue, 19 Nov 2024 11:28:04 +0100 Subject: [PATCH] feature(dcd_dwc2): Added cache synchronization --- src/portable/synopsys/dwc2/dcd_dwc2.c | 44 ++++++++++++++++++++++++- src/portable/synopsys/dwc2/dwc2_esp32.h | 37 +++++++++++++++++++++ 2 files changed, 80 insertions(+), 1 deletion(-) diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c index 7dec4ef3e1..2d97c7c337 100644 --- a/src/portable/synopsys/dwc2/dcd_dwc2.c +++ b/src/portable/synopsys/dwc2/dcd_dwc2.c @@ -47,7 +47,37 @@ // MACRO TYPEDEF CONSTANT ENUM //--------------------------------------------------------------------+ +#ifdef DWC2_ENABLE_MEM_CACHE + +#ifndef DWC2_MEM_CACHE_LINE_SIZE +#warning "Cache line size not specified, use default(64b) instead" +# define DWC2_MEM_CACHE_LINE_SIZE 0x40 +#endif // DWC2_MEM_CACHE_LINE_SIZE + +CFG_TUD_MEM_SECTION struct { + union { + uint32_t data[2]; + uint8_t buffer[DWC2_MEM_CACHE_LINE_SIZE]; + }; +} _cache_aligned_setup_packet; + +#define _setup_packet _cache_aligned_setup_packet.data +#define _sizeof_setup_packet() DWC2_MEM_CACHE_LINE_SIZE +#else static CFG_TUD_MEM_SECTION TU_ATTR_ALIGNED(4) uint32_t _setup_packet[2]; +#define _sizeof_setup_packet() sizeof(_setup_packet) +#endif // DWC2_ENABLE_MEM_CACHE + +// When DMA requires cache synchronization for memory +// Data synchronization: cache to memory +#ifndef dsync_c2m +#define dsync_c2m(_addr, _size) +#endif // dsync_c2m + +// Data synchronization: memory to cache +#ifndef dsync_m2c +#define dsync_m2c(_addr, _size) +#endif // dsync_m2c typedef struct { uint8_t* buffer; @@ -348,6 +378,11 @@ static void edpt_schedule_packets(uint8_t rhport, const uint8_t epnum, const uin const bool is_dma = dma_device_enabled(dwc2); if(is_dma) { + if (dir == TUSB_DIR_IN && total_bytes != 0) { + // CACHE HINT + // The xfer->buffer has new data for Host, move it to memory for DMA to transfer it + dsync_c2m(xfer->buffer, total_bytes); + } dep->diepdma = (uintptr_t) xfer->buffer; } @@ -848,6 +883,11 @@ static void handle_epout_dma(uint8_t rhport, uint8_t epnum, dwc2_doepint_t doepi if (doepint_bm.setup_phase_done) { dma_setup_prepare(rhport); + // CACHE HINT + // When cache is enabled, _setup_packet must have cache line size alignment + // and there should be no valuable data in memory after. + // Thus, specific struct is used as a buffer for setup packet data + dsync_m2c((uint8_t*) _setup_packet, _sizeof_setup_packet()); dcd_event_setup_received(rhport, (uint8_t*) _setup_packet, true); return; } @@ -873,7 +913,9 @@ static void handle_epout_dma(uint8_t rhport, uint8_t epnum, dwc2_doepint_t doepi if(epnum == 0 && xfer->total_len == 0) { dma_setup_prepare(rhport); } - + // CACHE HINT + // Some data has been received by DMA, fetch the data from memory to cache + dsync_m2c(xfer->buffer, xfer->total_len); dcd_event_xfer_complete(rhport, epnum, xfer->total_len, XFER_RESULT_SUCCESS, true); } } diff --git a/src/portable/synopsys/dwc2/dwc2_esp32.h b/src/portable/synopsys/dwc2/dwc2_esp32.h index 42ab4b80f3..e82bad4bfd 100644 --- a/src/portable/synopsys/dwc2/dwc2_esp32.h +++ b/src/portable/synopsys/dwc2/dwc2_esp32.h @@ -39,6 +39,18 @@ #include "soc/periph_defs.h" #include "soc/usb_wrap_struct.h" +#if TU_CHECK_MCU(OPT_MCU_ESP32P4) +#if (CFG_TUD_DWC2_DMA_ENABLE && SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE) +#include "sdkconfig.h" +#include "hal/cache_hal.h" +#include "esp_cache.h" +#include "esp_log.h" + +#define DWC2_MEM_CACHE_LINE_SIZE CONFIG_CACHE_L1_CACHE_LINE_SIZE +#define DWC2_ENABLE_MEM_CACHE +#endif // SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE +#endif // OPT_MCU_ESP32P4 + #if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3) #define DWC2_FS_REG_BASE 0x60080000UL #define DWC2_EP_MAX 7 @@ -111,6 +123,31 @@ TU_ATTR_ALWAYS_INLINE static inline void dwc2_phy_update(dwc2_regs_t* dwc2, uint // maybe usb_utmi_hal_disable() } +#ifdef DWC2_ENABLE_MEM_CACHE +TU_ATTR_ALWAYS_INLINE static inline void dwc2_dcd_sync_cache_to_memory(void *addr, size_t size) { + int flags = ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED; + if (addr != NULL && size) { + ESP_EARLY_LOGV("ESP32_DWC", "cache to mem sync, addr 0x%"PRIx32", size %d", (uintptr_t)addr, size); + esp_err_t ret = esp_cache_msync(addr, size, flags); + assert(ret == ESP_OK); + } +} + +TU_ATTR_ALWAYS_INLINE static inline void dwc2_dcd_sync_memory_to_cache(void *addr, size_t size) { + int flags = ESP_CACHE_MSYNC_FLAG_DIR_M2C; + if (addr != NULL && size) { + ESP_EARLY_LOGV("ESP32_DWC", "mem to cache sync, addr 0x%"PRIx32", size %d (%s)", (uintptr_t)addr, size); + size = (size < DWC2_MEM_CACHE_LINE_SIZE)? DWC2_MEM_CACHE_LINE_SIZE : size; + esp_err_t ret = esp_cache_msync(addr, size, flags); + assert(ret == ESP_OK); + } +} + +#define dsync_c2m(_addr, _size) dwc2_dcd_sync_cache_to_memory((_addr), (_size)) +#define dsync_m2c(_addr, _size) dwc2_dcd_sync_memory_to_cache((_addr), (_size)) + +#endif // DWC2_ENABLE_MEM_CACHE + #ifdef __cplusplus } #endif