usb/dwc: Corrected how packets are written and loaded to the DWC2 FIFOs on the H7

This commit is contained in:
dragonmux
2024-04-17 18:48:31 +01:00
committed by Piotr Esden-Tempski
parent 7da573f9eb
commit 714e7b1c91
2 changed files with 35 additions and 16 deletions

View File

@@ -86,7 +86,11 @@
#define OTG_PCGCCTL 0xE00 #define OTG_PCGCCTL 0xE00
/* Data FIFO */ /* Data FIFO */
#if defined(STM32H7)
#define OTG_FIFO(x) (0x1000U * (x + 1U))
#else
#define OTG_FIFO(x) (((x) + 1U) << 12U) #define OTG_FIFO(x) (((x) + 1U) << 12U)
#endif
/* Global CSRs */ /* Global CSRs */

View File

@@ -206,47 +206,62 @@ void dwc_ep_nak_set(usbd_device *usbd_dev, uint8_t addr, uint8_t nak)
uint16_t dwc_ep_write_packet(usbd_device *usbd_dev, uint8_t addr, uint16_t dwc_ep_write_packet(usbd_device *usbd_dev, uint8_t addr,
const void *buf, uint16_t len) const void *buf, uint16_t len)
{ {
const uint32_t *buf32 = buf;
#if defined(__ARM_ARCH_6M__)
const uint8_t *buf8 = buf;
uint32_t word32;
#endif /* defined(__ARM_ARCH_6M__) */
int i;
addr &= 0x7F; addr &= 0x7F;
/* Return if endpoint is already enabled. */ /* Return if endpoint is already enabled. */
#if defined(STM32H7)
if (REBASE(OTG_DIEPCTL(addr)) & OTG_DIEPCTL0_EPENA) {
return 0;
}
/* Enable endpoint for transmission. */
REBASE(OTG_DIEPTSIZ(addr)) = OTG_DIEPSIZ0_PKTCNT | (len & OTG_DIEPSIZ0_XFRSIZ_MASK);
REBASE(OTG_DIEPCTL(addr)) |= OTG_DIEPCTL0_EPENA | OTG_DIEPCTL0_CNAK;
const uint8_t *buf8 = buf;
/* Figure out where to copy the data to */
volatile uint32_t *const fifo = (volatile uint32_t *)(usbd_dev->driver->base_address + OTG_FIFO(addr));
/* Copy the data into the FIFO for this endpoint */
for (size_t offset = 0; offset < len; offset += 4) {
uint32_t data = 0;
const size_t amount = MIN(len - offset, 4U);
memcpy(&data, buf8 + offset, amount);
fifo[offset >> 2U] = data;
}
#else
if (REBASE(OTG_DIEPTSIZ(addr)) & OTG_DIEPSIZ0_PKTCNT) { if (REBASE(OTG_DIEPTSIZ(addr)) & OTG_DIEPSIZ0_PKTCNT) {
return 0; return 0;
} }
/* Enable endpoint for transmission. */ /* Enable endpoint for transmission. */
REBASE(OTG_DIEPTSIZ(addr)) = OTG_DIEPSIZ0_PKTCNT | len; REBASE(OTG_DIEPTSIZ(addr)) = OTG_DIEPSIZ0_PKTCNT | (len & OTG_DIEPSIZ0_XFRSIZ_MASK);
REBASE(OTG_DIEPCTL(addr)) |= OTG_DIEPCTL0_EPENA | REBASE(OTG_DIEPCTL(addr)) |= OTG_DIEPCTL0_EPENA | OTG_DIEPCTL0_CNAK;
OTG_DIEPCTL0_CNAK;
const uint32_t *buf32 = buf;
/* Copy buffer to endpoint FIFO, note - memcpy does not work. /* Copy buffer to endpoint FIFO, note - memcpy does not work.
* ARMv7M supports non-word-aligned accesses, ARMv6M does not. */ * ARMv7M supports non-word-aligned accesses, ARMv6M does not. */
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) #if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
for (i = len; i > 0; i -= 4) { for (size_t i = 0; i < len; i += 4) {
REBASE(OTG_FIFO(addr)) = *buf32++; REBASE(OTG_FIFO(addr)) = *buf32++;
} }
#endif /* defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) */ #endif /* defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) */
#if defined(__ARM_ARCH_6M__) #if defined(__ARM_ARCH_6M__)
const uint8_t *buf8 = buf;
/* Take care of word-aligned and non-word-aligned buffers */ /* Take care of word-aligned and non-word-aligned buffers */
if (((uint32_t)buf8 & 0x3) == 0) { if (((uintptr_t)buf8 & 0x3) == 0) {
for (i = len; i > 0; i -= 4) { for (size_t i = 0; i < len; i += 4) {
REBASE(OTG_FIFO(addr)) = *buf32++; REBASE(OTG_FIFO(addr)) = *buf32++;
} }
} else { } else {
for (i = len; i > 0; i -= 4) { for (size_t i = 0; i < len; i += 4) {
memcpy(&word32, buf8, 4); uint32_t word32;
memcpy(&word32, buf8 + i, 4);
REBASE(OTG_FIFO(addr)) = word32; REBASE(OTG_FIFO(addr)) = word32;
buf8 += 4;
} }
} }
#endif /* defined(__ARM_ARCH_6M__) */ #endif /* defined(__ARM_ARCH_6M__) */
#endif
return len; return len;
} }