dcd/samx7x: synchronize DMA and cache options

Signed-off-by: HiFiPhile <admin@hifiphile.com>
This commit is contained in:
HiFiPhile
2026-02-27 10:58:01 +01:00
parent fc9f63e62d
commit bb8845c8e8
4 changed files with 111 additions and 36 deletions

View File

@ -172,6 +172,10 @@
#define TUP_RHPORT_HIGHSPEED 1
#define TUD_ENDPOINT_ONE_DIRECTION_ONLY
// Enable dcache if DMA is enabled
#define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT CFG_TUD_SAMX7X_DMA_ENABLE
#define CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT 32
#elif TU_CHECK_MCU(OPT_MCU_PIC32MZ)
#define TUP_DCD_ENDPOINT_MAX 8
#define TUD_ENDPOINT_ONE_DIRECTION_ONLY

View File

@ -31,7 +31,7 @@
#include "device/dcd.h"
#include "sam.h"
#include "common_usb_regs.h"
#include "samx7x_common.h"
//--------------------------------------------------------------------+
// MACRO TYPEDEF CONSTANT ENUM DECLARATION
//--------------------------------------------------------------------+
@ -87,18 +87,22 @@ static const tusb_desc_endpoint_t ep0_desc =
.wMaxPacketSize = CFG_TUD_ENDPOINT0_SIZE,
};
TU_ATTR_ALWAYS_INLINE static inline void CleanInValidateCache(uint32_t *addr, int32_t size)
{
if (SCB->CCR & SCB_CCR_DC_Msk)
{
SCB_CleanInvalidateDCache_by_Addr(addr, size);
}
else
{
__DSB();
__ISB();
}
#if CFG_TUD_MEM_DCACHE_ENABLE
bool dcd_dcache_clean(const void* addr, uint32_t data_size) {
TU_VERIFY(addr && data_size);
return samx7x_dcache_clean(addr, data_size);
}
bool dcd_dcache_invalidate(const void* addr, uint32_t data_size) {
TU_VERIFY(addr && data_size);
return samx7x_dcache_invalidate(addr, data_size);
}
bool dcd_dcache_clean_invalidate(const void* addr, uint32_t data_size) {
TU_VERIFY(addr && data_size);
return samx7x_dcache_clean_invalidate(addr, data_size);
}
#endif
//------------------------------------------------------------------
// Device API
//------------------------------------------------------------------
@ -255,7 +259,7 @@ static void dcd_ep_handler(uint8_t ep_ix)
memcpy(xfer->buffer + xfer->queued_len, ptr, count);
} else
{
tu_fifo_write_n(xfer->fifo, ptr, count);
tu_hwfifo_read_to_fifo(ptr, xfer->fifo, count, NULL);
}
xfer->queued_len = (uint16_t)(xfer->queued_len + count);
}
@ -309,7 +313,7 @@ static void dcd_ep_handler(uint8_t ep_ix)
{
memcpy(xfer->buffer + xfer->queued_len, ptr, count);
} else {
tu_fifo_write_n(xfer->fifo, ptr, count);
tu_hwfifo_read_to_fifo(ptr, xfer->fifo, count, NULL);
}
xfer->queued_len = (uint16_t)(xfer->queued_len + count);
}
@ -362,6 +366,7 @@ static void dcd_dma_handler(uint8_t ep_ix)
dcd_event_xfer_complete(0, 0x80 + ep_ix, count, XFER_RESULT_SUCCESS, true);
} else
{
dcd_dcache_invalidate(xfer->buffer, xfer->total_len);
dcd_event_xfer_complete(0, ep_ix, count, XFER_RESULT_SUCCESS, true);
}
}
@ -588,7 +593,7 @@ static void dcd_transmit_packet(xfer_ctl_t * xfer, uint8_t ep_ix)
}
else
{
tu_fifo_read_n(xfer->fifo, ptr, len);
tu_hwfifo_write_from_fifo(ptr, xfer->fifo, len, NULL);
}
__DSB();
__ISB();
@ -623,35 +628,18 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t t
if (EP_DMA_SUPPORT(epnum) && total_bytes != 0)
{
// Force the CPU to flush the buffer. We increase the size by 32 because the call aligns the
// address to 32-byte boundaries.
CleanInValidateCache((uint32_t*) tu_align((uint32_t) buffer, 4), total_bytes + 31);
uint32_t udd_dma_ctrl = total_bytes << DEVDMACONTROL_BUFF_LENGTH_Pos;
if (dir == TUSB_DIR_OUT)
{
udd_dma_ctrl |= DEVDMACONTROL_END_TR_IT | DEVDMACONTROL_END_TR_EN;
} else {
udd_dma_ctrl |= DEVDMACONTROL_END_B_EN;
dcd_dcache_clean(xfer->buffer, total_bytes);
}
USB_REG->DEVDMA[epnum - 1].DEVDMAADDRESS = (uint32_t)buffer;
udd_dma_ctrl |= DEVDMACONTROL_END_BUFFIT | DEVDMACONTROL_CHANN_ENB;
// Disable IRQs to have a short sequence
// between read of EOT_STA and DMA enable
uint32_t irq_state = __get_PRIMASK();
__disable_irq();
if (!(USB_REG->DEVDMA[epnum - 1].DEVDMASTATUS & DEVDMASTATUS_END_TR_ST))
{
USB_REG->DEVDMA[epnum - 1].DEVDMACONTROL = udd_dma_ctrl;
USB_REG->DEVIER = DEVIER_DMA_1 << (epnum - 1);
__set_PRIMASK(irq_state);
return true;
}
__set_PRIMASK(irq_state);
// Here a ZLP has been received
// and the DMA transfer must be not started.
// It is the end of transfer
return false;
USB_REG->DEVDMA[epnum - 1].DEVDMACONTROL = udd_dma_ctrl;
USB_REG->DEVIER = DEVIER_DMA_1 << (epnum - 1);
} else
{
if (dir == TUSB_DIR_OUT)

View File

@ -2098,7 +2098,72 @@ typedef struct
#define FIFO_RAM_ADDR 0xA0100000u
// Errata: The DMA feature is not available for Pipe/Endpoint 7
#define EP_DMA_SUPPORT(epnum) (epnum >= 1 && epnum <= 6)
#define EP_DMA_SUPPORT(epnum) (epnum >= 1 && epnum <= 6 && CFG_TUD_SAMX7X_DMA_ENABLE)
//------------- DCache -------------//
#if CFG_TUD_MEM_DCACHE_ENABLE || CFG_TUH_MEM_DCACHE_ENABLE
typedef struct {
uintptr_t start;
uintptr_t end;
} mem_region_t;
// Can be used to define additional uncached regions
#ifndef CFG_SAMX7X_MEM_UNCACHED_REGIONS
#define CFG_SAMX7X_MEM_UNCACHED_REGIONS
#endif
static mem_region_t uncached_regions[] = {
// DTCM
{.start = 0x20000000, .end = 0x203fffff},
CFG_SAMX7X_MEM_UNCACHED_REGIONS
};
TU_ATTR_ALWAYS_INLINE static inline uint32_t round_up_to_cache_line_size(uint32_t size) {
if (size & (CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT-1)) {
size = (size & ~(CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT-1)) + CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT;
}
return size;
}
TU_ATTR_ALWAYS_INLINE static inline bool is_cache_mem(uintptr_t addr) {
if (0 == (SCB->CCR & SCB_CCR_DC_Msk)) {
return false; // D-Cache is disabled
}
for (unsigned int i = 0; i < TU_ARRAY_SIZE(uncached_regions); i++) {
if (uncached_regions[i].start <= addr && addr <= uncached_regions[i].end) { return false; }
}
return true;
}
TU_ATTR_ALWAYS_INLINE static inline bool samx7x_dcache_clean(void const* addr, uint32_t data_size) {
const uintptr_t addr32 = (uintptr_t) addr;
if (is_cache_mem(addr32)) {
data_size = round_up_to_cache_line_size(data_size);
SCB_CleanDCache_by_Addr((uint32_t *) addr32, (int32_t) data_size);
}
return true;
}
TU_ATTR_ALWAYS_INLINE static inline bool samx7x_dcache_invalidate(void const* addr, uint32_t data_size) {
const uintptr_t addr32 = (uintptr_t) addr;
if (is_cache_mem(addr32)) {
data_size = round_up_to_cache_line_size(data_size);
SCB_InvalidateDCache_by_Addr((void*) addr32, (int32_t) data_size);
}
return true;
}
TU_ATTR_ALWAYS_INLINE static inline bool samx7x_dcache_clean_invalidate(void const* addr, uint32_t data_size) {
const uintptr_t addr32 = (uintptr_t) addr;
if (is_cache_mem(addr32)) {
data_size = round_up_to_cache_line_size(data_size);
SCB_CleanInvalidateDCache_by_Addr((uint32_t *) addr32, (int32_t) data_size);
}
return true;
}
#endif
#else // TODO : SAM3U

View File

@ -394,6 +394,24 @@
// odd byte with byte access
#endif
//------- Microchip SAMX7X -------//
// DMA mode for device
#ifndef CFG_TUD_SAMX7X_DMA_ENABLE
#ifndef CFG_TUD_SAMX7X_DMA_ENABLE_DEFAULT
#define CFG_TUD_SAMX7X_DMA_ENABLE_DEFAULT 0
#endif
#define CFG_TUD_SAMX7X_DMA_ENABLE CFG_TUD_SAMX7X_DMA_ENABLE_DEFAULT
#endif
#if (CFG_TUSB_MCU == OPT_MCU_SAMX7X)
#define CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE 4
#define CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE 4
#define CFG_TUSB_FIFO_HWFIFO_DATA_ODD_16BIT_ACCESS
#define CFG_TUSB_FIFO_HWFIFO_DATA_ODD_8BIT_ACCESS
#define CFG_TUD_EDPT_DEDICATED_HWFIFO 1
#endif
//--------------------------------------------------------------------
// RootHub Mode detection
//--------------------------------------------------------------------