Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DCD_DWC2][ESP32P4][HS] Added cache synchronization #2877

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 26 additions & 1 deletion src/portable/synopsys/dwc2/dcd_dwc2.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,20 @@
// MACRO TYPEDEF CONSTANT ENUM
//--------------------------------------------------------------------+

#ifdef DWC2_MEM_CACHE_LINE_SIZE
CFG_TUD_MEM_SECTION struct {
union {
Copy link
Contributor Author

@roma-jam roma-jam Nov 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a manual tweak to protect* memory after the aligned _setup_packet buffer.
I have doubts, that __attribute__((aligned(x)) protects the memory after non-aligned variable, so I decided to solve it this way. At least there is nothing about that in the GCC doc.
Anyway, suggestions are welcome.

I referred to: https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html#index-aligned-variable-attribute

For class buffers (such as mscd cbw and csw, cdc epout and epin and so on, it is better to optimize in class driver code and different PR, IMHO). But anyway also should be done.

UPD:
*to protect from being vanished during cache sync operation

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, this will be a bit of an headache. gcc attribute alignment only ensure the variale alignement only, its size can be smaler, that would leave rom for other variable/data which can be corrupted when memroy to cache is called. I will try to figure out a way to address this.

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_MEM_CACHE_LINE_SIZE

typedef struct {
uint8_t* buffer;
Expand Down Expand Up @@ -348,6 +361,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
dcd_dcache_clean(xfer->buffer, total_bytes);
}
dep->diepdma = (uintptr_t) xfer->buffer;
}

Expand Down Expand Up @@ -847,6 +865,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
dcd_dcache_invalidate((uint8_t*) _setup_packet, _sizeof_setup_packet());
dcd_event_setup_received(rhport, (uint8_t*) _setup_packet, true);
return;
}
Expand All @@ -872,7 +895,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
dcd_dcache_invalidate(xfer->buffer, xfer->total_len);
dcd_event_xfer_complete(rhport, epnum, xfer->total_len, XFER_RESULT_SUCCESS, true);
}
}
Expand Down
27 changes: 27 additions & 0 deletions src/portable/synopsys/dwc2/dwc2_esp32.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@
#include "soc/periph_defs.h"
#include "soc/usb_wrap_struct.h"

#if (CFG_TUD_DWC2_DMA_ENABLE && SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE)
#include "sdkconfig.h"
#include "esp_cache.h"
#include "esp_log.h"

#define DWC2_MEM_CACHE_LINE_SIZE CONFIG_CACHE_L1_CACHE_LINE_SIZE
#endif // SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE

#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3)
#define DWC2_FS_REG_BASE 0x60080000UL
#define DWC2_EP_MAX 7
Expand Down Expand Up @@ -111,6 +119,25 @@ TU_ATTR_ALWAYS_INLINE static inline void dwc2_phy_update(dwc2_regs_t* dwc2, uint
// maybe usb_utmi_hal_disable()
}

#if (CFG_TUD_DWC2_DMA_ENABLE && SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE)
void dcd_dcache_clean(void const* addr, uint32_t data_size) {
int flags = ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED;
if (addr != NULL && data_size) {
esp_err_t ret = esp_cache_msync((void *) addr, data_size, flags);
assert(ret == ESP_OK);
}
}

void dcd_dcache_invalidate(void const* addr, uint32_t data_size) {
int flags = ESP_CACHE_MSYNC_FLAG_DIR_M2C;
if (addr != NULL && data_size) {
data_size = (data_size < DWC2_MEM_CACHE_LINE_SIZE)? DWC2_MEM_CACHE_LINE_SIZE : data_size;
esp_err_t ret = esp_cache_msync((void *) addr, data_size, flags);
assert(ret == ESP_OK);
}
}
#endif // CFG_TUD_DWC2_DMA_ENABLE && SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE

#ifdef __cplusplus
}
#endif
Expand Down
Loading