arch/arm64/src/imx9/imx9_usbdev.c: Fix the descriptor alignments and cache management

Align all the dtd and dqh on cache line boundaries and clean up the cache management

Signed-off-by: Jukka Laitinen <jukkax@ssrc.tii.ae>
This commit is contained in:
Jukka Laitinen 2024-04-19 09:56:11 +03:00 committed by Xiang Xiao
parent 67b7152034
commit 155c776ba8

View File

@ -54,6 +54,21 @@
* Pre-processor Definitions
****************************************************************************/
#if !defined(ARMV8A_DCACHE_LINESIZE) || ARMV8A_DCACHE_LINESIZE == 0
# undef ARMV8A_DCACHE_LINESIZE
# define ARMV8A_DCACHE_LINESIZE 64
#endif
#define DCACHE_LINEMASK (ARMV8A_DCACHE_LINESIZE - 1)
#if !defined(CONFIG_ARM64_DCACHE_DISABLE)
# define cache_aligned_alloc(s) kmm_memalign(ARMV8A_DCACHE_LINESIZE,(s))
# define CACHE_ALIGNED_DATA aligned_data(ARMV8A_DCACHE_LINESIZE)
#else
# define cache_aligned_alloc kmm_malloc
# define CACHE_ALIGNED_DATA
#endif
/* Configuration ************************************************************/
#ifndef CONFIG_USBDEV_EP0_MAXSIZE
@ -203,31 +218,31 @@ const struct trace_msg_t g_usb_trace_strings_intdecode[] =
};
#endif
#if defined(CONFIG_ARMV7M_DCACHE)
# define cache_aligned_alloc(s) kmm_memalign(ARMV7M_DCACHE_LINESIZE,(s))
# define CACHE_ALIGNED_DATA aligned_data(ARMV7M_DCACHE_LINESIZE)
#else
# define cache_aligned_alloc kmm_malloc
# define CACHE_ALIGNED_DATA
#endif
/* Hardware interface *******************************************************/
/* This represents a Endpoint Transfer Descriptor - note these must be 32
* byte aligned.
*/
/* This represents a Endpoint Transfer Descriptor dQH overlay (32 bytes) */
#define IMX9_DTD_S \
volatile uint32_t nextdesc; /* Address of the next DMA descripto in RAM */ \
volatile uint32_t config; /* Misc. bit encoded configuration information */ \
uint32_t buffer0; /* Buffer start address */ \
uint32_t buffer1; /* Buffer start address */ \
uint32_t buffer2; /* Buffer start address */ \
uint32_t buffer3; /* Buffer start address */ \
uint32_t buffer4; /* Buffer start address */ \
uint32_t xfer_len; /* Software only - transfer len that was queued */ \
struct imx9_dtd_ovl_s
{
IMX9_DTD_S
};
/* This represents a Endpoint Transfer Descriptor - cache line aligned */
struct imx9_dtd_s
{
volatile uint32_t nextdesc; /* Address of the next DMA descripto in RAM */
volatile uint32_t config; /* Misc. bit encoded configuration information */
uint32_t buffer0; /* Buffer start address */
uint32_t buffer1; /* Buffer start address */
uint32_t buffer2; /* Buffer start address */
uint32_t buffer3; /* Buffer start address */
uint32_t buffer4; /* Buffer start address */
uint32_t xfer_len; /* Software only - transfer len that was queued */
};
IMX9_DTD_S
} CACHE_ALIGNED_DATA;
/* DTD nextdesc field */
@ -244,18 +259,15 @@ struct imx9_dtd_s
#define DTD_CONFIG_BUFFER_ERROR (1 << 5) /* Bit 6 : Status Buffer Error */
#define DTD_CONFIG_TRANSACTION_ERROR (1 << 3) /* Bit 3 : Status Transaction Error */
/* This represents a queue head - note these must be aligned to a 2048 byte
* boundary
*/
/* This represents a queue head */
struct imx9_dqh_s
{
uint32_t capability; /* Endpoint capability */
uint32_t currdesc; /* Current dTD pointer */
struct imx9_dtd_s overlay; /* DTD overlay */
struct imx9_dtd_ovl_s overlay; /* DTD overlay */
volatile uint32_t setup[2]; /* Set-up buffer */
uint32_t gap[4]; /* align to 64 bytes */
};
} CACHE_ALIGNED_DATA;
/* DQH capability field */
@ -351,10 +363,10 @@ struct imx9_ep_s
struct imx9_ep0_s
{
uint8_t buf[64] CACHE_ALIGNED_DATA; /* buffer for EP0 short transfers */
uint16_t buf_len; /* buffer length */
struct usb_ctrlreq_s ctrl; /* structure for EP0 short transfers */
uint8_t state; /* state of certain EP0 operations */
uint8_t * const buf; /* buffer for EP0 short transfers */
uint16_t buf_len; /* buffer length */
struct usb_ctrlreq_s ctrl; /* structure for EP0 short transfers */
uint8_t state; /* state of certain EP0 operations */
};
/* This structure retains the state of the USB device controller */
@ -391,10 +403,8 @@ struct imx9_usb_s
/* The endpoint list */
struct imx9_ep_s eplist[IMX9_NPHYSENDPOINTS];
struct imx9_dqh_s qh[IMX9_NPHYSENDPOINTS] aligned_data(2048);
struct imx9_dtd_s td[IMX9_NPHYSENDPOINTS] aligned_data(32);
struct imx9_dqh_s * const qh;
struct imx9_dtd_s * const td;
};
#define EP0STATE_IDLE 0 /* Idle State, leave on receiving a setup packet or epsubmit */
@ -513,12 +523,31 @@ static int imx9_pullup(struct usbdev_s *dev, bool enable);
* Private Data
****************************************************************************/
/* Note: dqh lists must be aligned to a 2048 byte
* boundary, since ENDPTLISTADDR register last 10 bits are tied to 0
*/
#ifdef CONFIG_IMX9_USBDEV_USBC1
static uint8_t g_usb0_ep0buf[64] CACHE_ALIGNED_DATA;
static struct imx9_dqh_s g_usb0_qh[IMX9_NPHYSENDPOINTS] aligned_data(2048);
static struct imx9_dtd_s g_usb0_td[IMX9_NPHYSENDPOINTS];
#endif
#ifdef CONFIG_IMX9_USBDEV_USBC2
static uint8_t g_usb1_ep0buf[64] CACHE_ALIGNED_DATA;
static struct imx9_dqh_s g_usb1_qh[IMX9_NPHYSENDPOINTS] aligned_data(2048);
static struct imx9_dtd_s g_usb1_td[IMX9_NPHYSENDPOINTS];
#endif
static struct imx9_usb_s g_usbdev[] =
{
#ifdef CONFIG_IMX9_USBDEV_USBC1
{
.id = 0,
.base = IMX9_USB_OTG1_BASE,
.ep0.buf = g_usb0_ep0buf,
.qh = g_usb0_qh,
.td = g_usb0_td,
},
#endif
@ -526,6 +555,9 @@ static struct imx9_usb_s g_usbdev[] =
{
.id = 1,
.base = IMX9_USB_OTG2_BASE,
.ep0.buf = g_usb1_ep0buf,
.qh = g_usb1_qh,
.td = g_usb1_td,
},
#endif
};
@ -742,9 +774,9 @@ static inline void imx9_writedtd(struct imx9_dtd_s *dtd,
dtd->buffer4 = (uint32_t)(((uintptr_t) data) + 0x4000) & 0xfffff000;
dtd->xfer_len = nbytes;
up_flush_dcache((uintptr_t)dtd,
up_clean_dcache((uintptr_t)dtd,
(uintptr_t)dtd + sizeof(struct imx9_dtd_s));
up_flush_dcache((uintptr_t)data,
up_clean_dcache((uintptr_t)data,
(uintptr_t)data + nbytes);
}
@ -837,6 +869,9 @@ static void imx9_readsetup(struct imx9_usb_s *priv, uint8_t epphy,
imx9_modifyreg(priv, IMX9_USBDEV_USBCMD_OFFSET, USBDEV_USBCMD_SUTW, 0);
up_clean_dcache((uintptr_t)dqh,
(uintptr_t)dqh + sizeof(struct imx9_dqh_s));
/* Clear the Setup Interrupt */
imx9_putreg(priv, IMX9_USBDEV_ENDPTSETUPSTAT_OFFSET,
@ -1083,6 +1118,11 @@ static void imx9_dispatchrequest(struct imx9_usb_s *priv,
usbtrace(TRACE_INTDECODE(IMX9_TRACEINTID_DISPATCH), 0);
if (priv->driver)
{
/* Invalidate buffer data cache */
up_invalidate_dcache((uintptr_t)priv->ep0.buf,
(uintptr_t)priv->ep0.buf + sizeof(priv->ep0.buf));
/* Forward to the control request to the class driver implementation */
ret = CLASS_SETUP(priv->driver, &priv->usbdev, ctrl, priv->ep0.buf,
@ -1705,14 +1745,6 @@ static void imx9_ep0complete(struct imx9_usb_s *priv, uint8_t epphy)
break;
case EP0STATE_SHORTREAD:
/* Make sure we have updated data after the DMA transfer.
* This invalidation matches the flush in writedtd().
*/
up_invalidate_dcache((uintptr_t)priv->ep0.buf,
(uintptr_t)priv->ep0.buf + sizeof(priv->ep0.buf));
imx9_dispatchrequest(priv, &priv->ep0.ctrl);
imx9_ep0state(priv, EP0STATE_WAIT_NAK_IN);
break;
@ -1834,9 +1866,7 @@ bool imx9_epcomplete(struct imx9_usb_s *priv, uint8_t epphy)
return true;
}
/* Make sure we have updated data after the DMA transfer.
* This invalidation matches the flush in writedtd().
*/
/* Make sure we have updated data after the DMA transfer. */
up_invalidate_dcache((uintptr_t)dtd,
(uintptr_t)dtd + sizeof(struct imx9_dtd_s));