summaryrefslogtreecommitdiff
path: root/src/portable
diff options
context:
space:
mode:
authorHa Thach <[email protected]>2025-07-07 22:02:30 +0700
committerGitHub <[email protected]>2025-07-07 22:02:30 +0700
commit9990e4bf0cb5c472136f5ddd884f01e362c8b500 (patch)
tree11442d0326bcf1a7fa4c528b53a4127d6ff72a20 /src/portable
parenta2ee6da299b70908726abae055ff27576f369019 (diff)
parent3eb04518796e81e41ff119dc5acf33bf5241fdec (diff)
Merge pull request #2963 from HiFiPhile/stm32_cache
Add DWC2 cache maintenance routines for STM32
Diffstat (limited to 'src/portable')
-rw-r--r--src/portable/synopsys/dwc2/dwc2_stm32.h71
1 files changed, 71 insertions, 0 deletions
diff --git a/src/portable/synopsys/dwc2/dwc2_stm32.h b/src/portable/synopsys/dwc2/dwc2_stm32.h
index dc4251c29..5f2b8419c 100644
--- a/src/portable/synopsys/dwc2/dwc2_stm32.h
+++ b/src/portable/synopsys/dwc2/dwc2_stm32.h
@@ -279,6 +279,77 @@ static inline void dwc2_phy_update(dwc2_regs_t* dwc2, uint8_t hs_phy_type) {
}
}
+//------------- 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_DWC2_MEM_UNCACHED_REGIONS
+#define CFG_DWC2_MEM_UNCACHED_REGIONS
+#endif
+
+static mem_region_t uncached_regions[] = {
+ // DTCM (although USB DMA can't transfer to/from DTCM)
+#if CFG_TUSB_MCU == OPT_MCU_STM32H7
+ {.start = 0x20000000, .end = 0x2001FFFF},
+#elif CFG_TUSB_MCU == OPT_MCU_STM32H7RS
+ // DTCM (although USB DMA can't transfer to/from DTCM)
+ {.start = 0x20000000, .end = 0x2002FFFF},
+#elif CFG_TUSB_MCU == OPT_MCU_STM32F7
+ // DTCM
+ {.start = 0x20000000, .end = 0x2000FFFF},
+#else
+#error "Cache maintenance is not supported yet"
+#endif
+ CFG_DWC2_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) {
+ 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 dwc2_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 dwc2_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 dwc2_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
+
#ifdef __cplusplus
}
#endif