3#if SOC_USB_OTG_SUPPORTED && defined(CONFIG_IDF_TARGET_ESP32S3) && \
4 CONFIG_IDF_TARGET_ESP32S3
10#include "esp_heap_caps.h"
11#include "esp_memory_utils.h"
12#include "hal/cache_hal.h"
14namespace LibXR::ESPUSBDetail
17#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE || SOC_PSRAM_DMA_CAPABLE
18extern "C" esp_err_t esp_cache_msync(
void* addr,
size_t size,
int flags);
20constexpr int kCacheSyncFlagUnaligned = (1 << 1);
21constexpr int kCacheSyncFlagDirC2M = (1 << 2);
22constexpr int kCacheSyncFlagDirM2C = (1 << 3);
24bool CacheSyncDmaBuffer(
const void* addr,
size_t size,
bool cache_to_mem,
27 if ((addr ==
nullptr) || (size == 0U))
32 uint32_t cache_level = 0;
33 uint32_t cache_id = 0;
34 const bool cache_supported = cache_hal_vaddr_to_cache_level_id(
35 static_cast<uint32_t
>(
reinterpret_cast<uintptr_t
>(addr)), size, &cache_level,
42 int flags = cache_to_mem ? kCacheSyncFlagDirC2M : kCacheSyncFlagDirM2C;
43 if (allow_unaligned && cache_to_mem)
45 flags |= kCacheSyncFlagUnaligned;
47 return esp_cache_msync(
const_cast<void*
>(addr), size, flags) == ESP_OK;
50bool CacheSyncDmaBuffer(
const void*,
size_t,
bool,
bool) {
return true; }
53size_t AlignUp(
size_t value,
size_t align)
59 return ((value + align - 1U) / align) * align;
62esp_dma_mem_info_t UsbDmaMemInfo()
64 esp_dma_mem_info_t info = {};
65 info.extra_heap_caps = MALLOC_CAP_INTERNAL;
66 info.dma_alignment_bytes = kWordSize;
70bool CanUseDirectInDmaBuffer(
const void* ptr,
size_t size)
72 if ((ptr ==
nullptr) || (size == 0U))
77 auto* start =
static_cast<const uint8_t*
>(ptr);
78 auto* end = start + size - 1U;
79 return esp_ptr_dma_capable(start) && esp_ptr_dma_capable(end) &&
80 esp_ptr_word_aligned(ptr);
83bool CanUseDirectOutDmaBuffer(
const void* ptr,
size_t size)
85 if ((ptr ==
nullptr) || (size == 0U))
90 auto* start =
static_cast<const uint8_t*
>(ptr);
91 auto* end = start + size - 1U;
92 if (!esp_ptr_dma_capable(start) || !esp_ptr_dma_capable(end) ||
93 !esp_ptr_word_aligned(ptr) ||
94 !esp_dma_is_buffer_alignment_satisfied(ptr, size, UsbDmaMemInfo()))
99 uint32_t cache_level = 0;
100 uint32_t cache_id = 0;
101 const bool cache_supported = cache_hal_vaddr_to_cache_level_id(
102 static_cast<uint32_t
>(
reinterpret_cast<uintptr_t
>(ptr)), size, &cache_level,
104 if (!cache_supported)
109 const uintptr_t addr =
reinterpret_cast<uintptr_t
>(ptr);
110 return ((addr % kUsbDmaAlignment) == 0U) && (AlignUp(size, kUsbDmaAlignment) == size);
113uint16_t CalcRxFifoWords(uint16_t largest_packet_size, uint8_t ep_count)
115 return static_cast<uint16_t
>(13U + 1U + 2U * (((largest_packet_size + 3U) / 4U) + 1U) +
119uint16_t CalcConfiguredRxFifoWords(uint16_t largest_packet_size, uint8_t ep_count,
122 uint16_t words = CalcRxFifoWords(largest_packet_size, ep_count);
125 words = std::max<uint16_t>(words, kEsp32SxFsDmaMinRxFifoWords);
130uint16_t GetHardwareFifoDepthWords()
132 auto* dev =
reinterpret_cast<usb_dwc_dev_t*
>(kDwc2FsRegBase);
133 return static_cast<uint16_t
>(dev->ghwcfg3_reg.dfifodepth);
136uint8_t EncodeEp0Mps(uint16_t packet_size)
157 return static_cast<uint16_t
>(std::min<uint16_t>(requested, 64U));
159 return static_cast<uint16_t
>(std::min<uint16_t>(requested, 64U));
161 return static_cast<uint16_t
>(std::min<uint16_t>(requested, 64U));
163 return static_cast<uint16_t
>(std::min<uint16_t>(requested, 1023U));
169uint16_t CalcTxFifoWords(uint16_t packet_size,
bool dma_enabled)
171 uint16_t words =
static_cast<uint16_t
>((packet_size + 3U) / 4U);
174 words = std::max<uint16_t>(words, kEsp32SxFsMinTxFifoWords);
179volatile uint32_t* GetEndpointFifo(usb_dwc_dev_t* dev, uint8_t ep_num)
181 uintptr_t base =
reinterpret_cast<uintptr_t
>(dev);
182 return reinterpret_cast<volatile uint32_t*
>(
183 base + kFifoBaseOffset +
static_cast<uintptr_t
>(ep_num) * kFifoStride);
186void WriteFifoPacket(
volatile uint32_t* fifo,
const uint8_t* src,
size_t size)
188 for (
size_t offset = 0; offset < size; offset += kWordSize)
191 const size_t chunk = std::min(kWordSize, size - offset);
192 std::memcpy(&word, src + offset, chunk);
197void ReadFifoPacket(
const volatile uint32_t* fifo, uint8_t* dst,
size_t size)
199 for (
size_t offset = 0; offset < size; offset += kWordSize)
201 const uint32_t word = fifo[0];
202 const size_t chunk = std::min(kWordSize, size - offset);
203 std::memcpy(dst + offset, &word, chunk);
207uint16_t PacketCount(
size_t size, uint16_t max_packet_size)
213 return static_cast<uint16_t
>((size + max_packet_size - 1U) / max_packet_size);
216void FlushTxFifo(usb_dwc_dev_t* dev, uint8_t fifo_num)
218 dev->grstctl_reg.txfnum = fifo_num;
219 dev->grstctl_reg.txfflsh = 1;
220 while (dev->grstctl_reg.txfflsh)
225void DisableInEndpointAndWait(usb_dwc_dev_t* dev)
227 auto& ctl = dev->diepctl0_reg;
228 auto& intr = dev->diepint0_reg;
235 while (!intr.inepnakeff)
239 usb_dwc_diepint0_reg_t clear_nak = {};
240 clear_nak.inepnakeff = 1;
241 intr.val = clear_nak.val;
244 while (!intr.epdisbld)
248 usb_dwc_diepint0_reg_t clear_dis = {};
249 clear_dis.epdisbld = 1;
250 intr.val = clear_dis.val;
251 FlushTxFifo(dev, 0U);
254void DisableInEndpointAndWait(usb_dwc_dev_t* dev, uint8_t ep_num)
256 auto& ctl = dev->in_eps[ep_num - 1U].diepctl_reg;
257 auto& intr = dev->in_eps[ep_num - 1U].diepint_reg;
264 while (!intr.inepnakeff)
268 usb_dwc_diepint_reg_t clear_nak = {};
269 clear_nak.inepnakeff = 1;
270 intr.val = clear_nak.val;
273 while (!intr.epdisbld)
277 usb_dwc_diepint_reg_t clear_dis = {};
278 clear_dis.epdisbld = 1;
279 intr.val = clear_dis.val;
280 FlushTxFifo(dev, ep_num);
@ ISOCHRONOUS
等时端点 / Isochronous
@ INTERRUPT
中断端点 / Interrupt