arch/{nrf52|nrf53}/usbd: various fixes to improve USB stability
USBD has many limitation that make it hard to work properly: - only one EasyDMA channel which must be shared for all EPs - only one DMA transfer can take place at a time - some registers are unavailable during DMA transfer - in case of any problems, the peripheral silently blocks, or lose the transmitted bytes without information for the user This commit is trying to fix these problem and makes the USBS stack more reliable. Tested with high-speed CDCACM data transfers and that's the best I've been able to get in terms of stability.
This commit is contained in:
parent
693898d566
commit
2f58b55b4d
@ -47,6 +47,7 @@
|
||||
#define NRF52_USBD_TASKS_DPDMDRIVE_OFFSET (0x0058)
|
||||
#define NRF52_USBD_TASKS_PDPMNODRIVE_OFFSET (0x005c)
|
||||
#define NRF52_USBD_EVENTS_USBRESET_OFFSET (0x0100)
|
||||
#define NRF52_USBD_EVENTS_STARTED_OFFSET (0x0104)
|
||||
#define NRF52_USBD_EVENTS_ENDEPIN_OFFSET(n) (0x0108 + (0x04 * n))
|
||||
#define NRF52_USBD_EVENTS_EP0DATADONE_OFFSET (0x0128)
|
||||
#define NRF52_USBD_EVENTS_ENDISOIN_OFFSET (0x012c)
|
||||
@ -112,6 +113,7 @@
|
||||
#define NRF52_USBD_TASKS_DPDMDRIVE (NRF52_USBD_BASE + NRF52_USBD_TASKS_DPDMDRIVE_OFFSET)
|
||||
#define NRF52_USBD_TASKS_PDPMNODRIVE (NRF52_USBD_BASE + NRF52_USBD_TASKS_PDPMNODRIVE_OFFSET)
|
||||
#define NRF52_USBD_EVENTS_USBRESET (NRF52_USBD_BASE + NRF52_USBD_EVENTS_USBRESET_OFFSET)
|
||||
#define NRF52_USBD_EVENTS_STARTED (NRF52_USBD_BASE + NRF52_USBD_EVENTS_STARTED_OFFSET)
|
||||
#define NRF52_USBD_EVENTS_ENDEPIN(n) (NRF52_USBD_BASE + NRF52_USBD_EVENTS_ENDEPIN_OFFSET(n))
|
||||
#define NRF52_USBD_EVENTS_EP0DATADONE (NRF52_USBD_BASE + NRF52_USBD_EVENTS_EP0DATADONE_OFFSET)
|
||||
#define NRF52_USBD_EVENTS_ENDISOIN (NRF52_USBD_BASE + NRF52_USBD_EVENTS_ENDISOIN_OFFSEN)
|
||||
@ -197,6 +199,7 @@
|
||||
#define USBD_INT_EP0SETUP (1 << 23) /* Enable/disable interrupt EP0SETUP */
|
||||
#define USBD_INT_EPDATA (1 << 24) /* Enable/disable interrupt EPDATA */
|
||||
#define USBD_INT_ALL (0x1fffffff)
|
||||
#define USBD_INT_ALL_NUM (25)
|
||||
|
||||
/* EVENTCAUSE */
|
||||
|
||||
|
@ -24,8 +24,6 @@
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdint.h>
|
||||
@ -79,6 +77,7 @@
|
||||
#define NRF52_TRACEERR_INVALIDCTRLREQ 0x17
|
||||
#define NRF52_TRACEERR_BADGETSTATUS 0x18
|
||||
#define NRF52_TRACEERR_EPINREQEMPTY 0x19
|
||||
#define NRF52_TRACEERR_DMABUSY 0x20
|
||||
|
||||
/* Trace interrupt codes */
|
||||
|
||||
@ -184,11 +183,23 @@
|
||||
USBD_INT_EP0DATADONE | \
|
||||
USBD_INT_USBEVENT | \
|
||||
USBD_INT_EP0SETUP | \
|
||||
USBD_INT_EPDATA | \
|
||||
USBD_INT_ENDEPIN(0) | \
|
||||
USBD_INT_ENDEPOUT(0))
|
||||
USBD_INT_EPDATA)
|
||||
#endif
|
||||
|
||||
/* Interrupts that signal DMA transfer complete:
|
||||
* ENDEPIN0-7, ENDEPOUT0-7, ENDISOIN, ENDISOOUT
|
||||
*/
|
||||
|
||||
#define NRF52_USBD_DMAIRQ (USBD_INT_ENDEPIN(0) | USBD_INT_ENDEPIN(1) | \
|
||||
USBD_INT_ENDEPIN(2) | USBD_INT_ENDEPIN(3) | \
|
||||
USBD_INT_ENDEPIN(4) | USBD_INT_ENDEPIN(5) | \
|
||||
USBD_INT_ENDEPIN(6) | USBD_INT_ENDEPIN(7) | \
|
||||
USBD_INT_ENDEPOUT(0) | USBD_INT_ENDEPOUT(1) | \
|
||||
USBD_INT_ENDEPOUT(2) | USBD_INT_ENDEPOUT(3) | \
|
||||
USBD_INT_ENDEPOUT(4) | USBD_INT_ENDEPOUT(5) | \
|
||||
USBD_INT_ENDEPOUT(6) | USBD_INT_ENDEPOUT(7) | \
|
||||
USBD_INT_ENDISOIN | USBD_INT_ENDISOOUT)
|
||||
|
||||
/****************************************************************************
|
||||
* Private Type Definitions
|
||||
****************************************************************************/
|
||||
@ -259,7 +270,12 @@ struct nrf52_usbdev_s
|
||||
uint8_t ep0indone; /* 1: EP0 IN transfer complete */
|
||||
uint8_t ep0outdone; /* 1: EP0 OUT transfer complete */
|
||||
uint8_t epavail[2]; /* Bitset of available OUT/IN endpoints */
|
||||
|
||||
/* DMA access control */
|
||||
|
||||
bool dmanow; /* DMA transfer pending */
|
||||
uint16_t dmaepinwait; /* EP IN waiting for DMA */
|
||||
uint16_t dmaepoutwait; /* EP OUT waitning for DMA */
|
||||
|
||||
/* E0 SETUP data buffering.
|
||||
*
|
||||
@ -360,8 +376,10 @@ static void nrf52_eventinterrupt(struct nrf52_usbdev_s *priv);
|
||||
static void nrf52_ep0setupinterrupt(struct nrf52_usbdev_s *priv);
|
||||
static void nrf52_ep0datainterrupt(struct nrf52_usbdev_s *priv);
|
||||
static void nrf52_epdatainterrupt(struct nrf52_usbdev_s *priv);
|
||||
static void nrf52_endepininterrupt(struct nrf52_usbdev_s *priv);
|
||||
static void nrf52_endepoutinterrupt(struct nrf52_usbdev_s *priv);
|
||||
static void nrf52_endepininterrupt(struct nrf52_usbdev_s *priv,
|
||||
uint32_t irqnow);
|
||||
static void nrf52_endepoutinterrupt(struct nrf52_usbdev_s *priv,
|
||||
uint32_t irqnow);
|
||||
|
||||
/* First level interrupt processing */
|
||||
|
||||
@ -563,10 +581,7 @@ const struct trace_msg_t g_usb_trace_strings_intdecode[] =
|
||||
static void nrf52_startdma_task(struct nrf52_usbdev_s *priv, uint32_t addr)
|
||||
{
|
||||
usbtrace(TRACE_INTDECODE(NRF52_TRACEINTID_DMATASK), addr);
|
||||
|
||||
*(volatile uint32_t *)0x40027c1c = 0x00000082;
|
||||
nrf52_putreg(1, addr);
|
||||
|
||||
priv->dmanow = true;
|
||||
}
|
||||
|
||||
@ -575,9 +590,6 @@ static void nrf52_startdma_ack(struct nrf52_usbdev_s *priv)
|
||||
if (priv->dmanow == true)
|
||||
{
|
||||
usbtrace(TRACE_INTDECODE(NRF52_TRACEINTID_DMAACK), 0);
|
||||
|
||||
*(volatile uint32_t *)0x40027c1c = 0x00000000;
|
||||
|
||||
priv->dmanow = false;
|
||||
}
|
||||
}
|
||||
@ -1020,18 +1032,26 @@ static void nrf52_epin_transfer(struct nrf52_ep_s *privep, uint8_t *buf,
|
||||
DEBUGASSERT(privep->eptype != USB_EP_ATTR_XFER_ISOC);
|
||||
DEBUGASSERT(nbytes <= 64);
|
||||
|
||||
if (nbytes > 0)
|
||||
/* Configure EasyDMA */
|
||||
|
||||
if (buf)
|
||||
{
|
||||
/* Configure EasyDMA */
|
||||
|
||||
DEBUGASSERT(nrf52_easydma_valid((uint32_t)buf));
|
||||
nrf52_putreg((uint32_t)buf, NRF52_USBD_EPIN_PTR(privep->epphy));
|
||||
nrf52_putreg(nbytes, NRF52_USBD_EPIN_MAXCNT(privep->epphy));
|
||||
|
||||
/* Start EPIN task - DMA transfer */
|
||||
|
||||
nrf52_epin_start(priv, privep->epphy);
|
||||
}
|
||||
|
||||
nrf52_putreg((uint32_t)buf, NRF52_USBD_EPIN_PTR(privep->epphy));
|
||||
nrf52_putreg(nbytes, NRF52_USBD_EPIN_MAXCNT(privep->epphy));
|
||||
|
||||
/* Start EPIN task - DMA transfer */
|
||||
|
||||
nrf52_epin_start(priv, privep->epphy);
|
||||
|
||||
/* Busy wait for ENDEPIN to prevent any access to USBD registers during
|
||||
* EasyDMA transfer. Otherwise USBD is not stable.
|
||||
*/
|
||||
|
||||
while (nrf52_getreg(NRF52_USBD_EVENTS_ENDEPIN(privep->epphy)) == 0 &&
|
||||
nrf52_getreg(NRF52_USBD_EVENTS_USBRESET) == 0);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -1067,9 +1087,18 @@ static void nrf52_epout_transfer(struct nrf52_ep_s *privep)
|
||||
DEBUGASSERT(privep && privep->dev);
|
||||
priv = (struct nrf52_usbdev_s *)privep->dev;
|
||||
|
||||
/* Number of bytes received last in the data stage of this OUT endpoint */
|
||||
if (privep->epphy == 0)
|
||||
{
|
||||
nbytes = USBDEV_EP0_MAXSIZE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Number of bytes received last in the data stage of this OUT
|
||||
* endpoint
|
||||
*/
|
||||
|
||||
nbytes = nrf52_getreg(NRF52_USBD_SIZE_EPOUT(privep->epphy));
|
||||
nbytes = nrf52_getreg(NRF52_USBD_SIZE_EPOUT(privep->epphy));
|
||||
}
|
||||
|
||||
/* Configure EasyDMA */
|
||||
|
||||
@ -1081,6 +1110,13 @@ static void nrf52_epout_transfer(struct nrf52_ep_s *privep)
|
||||
/* Start EPOUT task */
|
||||
|
||||
nrf52_epout_start(priv, privep->epphy);
|
||||
|
||||
/* Busy wait for ENDEPOUT to prevent any access to USBD registers during
|
||||
* EasyDMA transfer. Otherwise USBD is not stable.
|
||||
*/
|
||||
|
||||
while (nrf52_getreg(NRF52_USBD_EVENTS_ENDEPOUT(privep->epphy)) == 0 &&
|
||||
nrf52_getreg(NRF52_USBD_EVENTS_USBRESET) == 0);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -1099,6 +1135,15 @@ static void nrf52_epin_request(struct nrf52_usbdev_s *priv,
|
||||
int bytesleft = 0;
|
||||
int nbytes = 0;
|
||||
|
||||
/* If DMA is busy, add EP IN to the waiting list */
|
||||
|
||||
if (priv->dmanow == true)
|
||||
{
|
||||
usbtrace(TRACE_DEVERROR(NRF52_TRACEERR_DMABUSY), privep->epphy);
|
||||
priv->dmaepinwait |= (1 << privep->epphy);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check the request from the head of the endpoint request queue */
|
||||
|
||||
privreq = nrf52_rqpeek(privep);
|
||||
@ -1145,6 +1190,16 @@ static void nrf52_epin_request(struct nrf52_usbdev_s *priv,
|
||||
|
||||
privreq->req.xfrd += nbytes;
|
||||
}
|
||||
else if (privreq->req.len == 0)
|
||||
{
|
||||
/* Zero-length packet */
|
||||
|
||||
nrf52_epin_transfer(privep, NULL, 0);
|
||||
|
||||
/* ACK zero-length DMA transfer right away */
|
||||
|
||||
nrf52_startdma_ack(priv);
|
||||
}
|
||||
|
||||
/* Has all the request data been sent? */
|
||||
|
||||
@ -1189,7 +1244,6 @@ static void nrf52_epout_complete(struct nrf52_ep_s *privep)
|
||||
|
||||
privreq = nrf52_rqpeek(privep);
|
||||
DEBUGASSERT(privreq);
|
||||
|
||||
if (!privreq)
|
||||
{
|
||||
/* An OUT transfer completed, but no packet to receive the data. This
|
||||
@ -1210,10 +1264,6 @@ static void nrf52_epout_complete(struct nrf52_ep_s *privep)
|
||||
|
||||
usbtrace(TRACE_COMPLETE(privep->epphy), privreq->req.xfrd);
|
||||
nrf52_req_complete(privep, OK);
|
||||
|
||||
/* Allow OUT trafic on this endpoint */
|
||||
|
||||
nrf52_epout_allow(privep);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -1342,6 +1392,15 @@ static void nrf52_epout_handle(struct nrf52_usbdev_s *priv,
|
||||
|
||||
DEBUGASSERT(privep->epphy != EP0);
|
||||
|
||||
/* If DMA is busy, add EP OUT to the waiting list */
|
||||
|
||||
if (priv->dmanow == true)
|
||||
{
|
||||
usbtrace(TRACE_DEVERROR(NRF52_TRACEERR_DMABUSY), privep->epphy);
|
||||
priv->dmaepoutwait |= (1 << privep->epphy);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Loop until a valid request is found (or the request queue is empty).
|
||||
* The loop is only need to look at the request queue again is an
|
||||
* invalid read request is encountered.
|
||||
@ -1776,8 +1835,6 @@ static void nrf52_ep0datainterrupt(struct nrf52_usbdev_s *priv)
|
||||
{
|
||||
struct nrf52_ep_s *privep = NULL;
|
||||
|
||||
nrf52_startdma_ack(priv);
|
||||
|
||||
if (USB_REQ_ISOUT(priv->ctrlreq.type))
|
||||
{
|
||||
/* Prepare EP OUT DMA transfer */
|
||||
@ -1787,11 +1844,6 @@ static void nrf52_ep0datainterrupt(struct nrf52_usbdev_s *priv)
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Handle IN request */
|
||||
|
||||
privep = &priv->epin[EP0];
|
||||
nrf52_epin_request(priv, privep);
|
||||
|
||||
if (priv->ep0indone)
|
||||
{
|
||||
/* Allows status stage on control endpoint 0 */
|
||||
@ -1799,6 +1851,13 @@ static void nrf52_ep0datainterrupt(struct nrf52_usbdev_s *priv)
|
||||
nrf52_ep0status_start(priv);
|
||||
priv->ep0indone = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Handle IN request */
|
||||
|
||||
privep = &priv->epin[EP0];
|
||||
nrf52_epin_request(priv, privep);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1816,12 +1875,14 @@ static void nrf52_epdatainterrupt(struct nrf52_usbdev_s *priv)
|
||||
uint32_t datastatus = 0;
|
||||
int epno = 0;
|
||||
|
||||
nrf52_startdma_ack(priv);
|
||||
|
||||
/* Get pending data status */
|
||||
|
||||
datastatus = nrf52_getreg(NRF52_USBD_EPDATASTATUS);
|
||||
|
||||
/* Clear register */
|
||||
|
||||
nrf52_putreg(datastatus, NRF52_USBD_EPDATASTATUS);
|
||||
|
||||
/* Ignore EP0 */
|
||||
|
||||
for (epno = 1; epno < NRF52_NENDPOINTS; epno += 1)
|
||||
@ -1842,61 +1903,51 @@ static void nrf52_epdatainterrupt(struct nrf52_usbdev_s *priv)
|
||||
nrf52_epout_handle(priv, privep);
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear register */
|
||||
|
||||
nrf52_putreg(datastatus, NRF52_USBD_EPDATASTATUS);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nrf52_endepin
|
||||
* Name: nrf52_endepininterrupt
|
||||
*
|
||||
* Description:
|
||||
* Handle ENDEPIN events
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void nrf52_endepininterrupt(struct nrf52_usbdev_s *priv)
|
||||
static void nrf52_endepininterrupt(struct nrf52_usbdev_s *priv,
|
||||
uint32_t irqnow)
|
||||
{
|
||||
int epno = 0;
|
||||
|
||||
nrf52_startdma_ack(priv);
|
||||
|
||||
/* Process each pending IN endpoint interrupt */
|
||||
|
||||
for (epno = 0; epno < NRF52_NENDPOINTS; epno += 1)
|
||||
{
|
||||
if (nrf52_getreg(NRF52_USBD_EVENTS_ENDEPIN(epno)))
|
||||
if (irqnow & USBD_INT_ENDEPIN(epno))
|
||||
{
|
||||
usbtrace(TRACE_INTDECODE(NRF52_TRACEINTID_ENDEPIN), epno);
|
||||
|
||||
/* Clear event */
|
||||
|
||||
nrf52_putreg(0, NRF52_USBD_EVENTS_ENDEPIN(epno));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nrf52_endepout
|
||||
* Name: nrf52_endepoutinterrupt
|
||||
*
|
||||
* Description:
|
||||
* Handle ENDEPOUT events
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void nrf52_endepoutinterrupt(struct nrf52_usbdev_s *priv)
|
||||
static void nrf52_endepoutinterrupt(struct nrf52_usbdev_s *priv,
|
||||
uint32_t irqnow)
|
||||
{
|
||||
struct nrf52_ep_s *privep = NULL;
|
||||
int epno = 0;
|
||||
|
||||
nrf52_startdma_ack(priv);
|
||||
|
||||
/* Process each pending OUT endpoint interrupt */
|
||||
|
||||
for (epno = 0; epno < NRF52_NENDPOINTS; epno += 1)
|
||||
{
|
||||
if (nrf52_getreg(NRF52_USBD_EVENTS_ENDEPOUT(epno)))
|
||||
if (irqnow & USBD_INT_ENDEPOUT(epno))
|
||||
{
|
||||
usbtrace(TRACE_INTDECODE(NRF52_TRACEINTID_ENDEPOUT), epno);
|
||||
|
||||
@ -1925,10 +1976,6 @@ static void nrf52_endepoutinterrupt(struct nrf52_usbdev_s *priv)
|
||||
privep = &priv->epout[epno];
|
||||
nrf52_epout_receive(privep);
|
||||
}
|
||||
|
||||
/* Clear event */
|
||||
|
||||
nrf52_putreg(0, NRF52_USBD_EVENTS_ENDEPOUT(epno));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1943,70 +1990,135 @@ static void nrf52_endepoutinterrupt(struct nrf52_usbdev_s *priv)
|
||||
|
||||
static int nrf52_usbinterrupt(int irq, void *context, void *arg)
|
||||
{
|
||||
struct nrf52_usbdev_s *priv = &g_usbdev;
|
||||
struct nrf52_usbdev_s *priv = &g_usbdev;
|
||||
struct nrf52_ep_s *privep = NULL;
|
||||
uint32_t irqnow = 0;
|
||||
uint32_t offset = 0;
|
||||
int i = 0;
|
||||
|
||||
usbtrace(TRACE_INTENTRY(NRF52_TRACEINTID_USB), 0);
|
||||
|
||||
/* Handle all events */
|
||||
|
||||
for (i = 0; i < USBD_INT_ALL_NUM; i++)
|
||||
{
|
||||
/* Get EVENT offset */
|
||||
|
||||
offset = NRF52_USBD_EVENTS_USBRESET + 0x04 * i;
|
||||
|
||||
/* Get EVENT state */
|
||||
|
||||
irqnow |= nrf52_getreg(offset) << i;
|
||||
|
||||
/* Clear EVENT */
|
||||
|
||||
nrf52_putreg(0, offset);
|
||||
}
|
||||
|
||||
/* USB reset interrupt */
|
||||
|
||||
if (nrf52_getreg(NRF52_USBD_EVENTS_USBRESET))
|
||||
if (irqnow & USBD_INT_USBRESET)
|
||||
{
|
||||
usbtrace(TRACE_INTDECODE(NRF52_TRACEINTID_DEVRESET), 0);
|
||||
nrf52_usbreset(priv);
|
||||
nrf52_putreg(0, NRF52_USBD_EVENTS_USBRESET);
|
||||
goto intout;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USBDEV_SOFINTERRUPT
|
||||
/* Handle SOF */
|
||||
|
||||
if (nrf52_getreg(NRF52_USBD_EVENTS_SOF))
|
||||
if (irqnow & USBD_INT_SOF)
|
||||
{
|
||||
usbtrace(TRACE_INTDECODE(NRF52_TRACEINTID_SOF), 0);
|
||||
nrf52_putreg(0, NRF52_USBD_EVENTS_SOF);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Handle USBEVENT */
|
||||
|
||||
if (nrf52_getreg(NRF52_USBD_EVENTS_USBEVENT))
|
||||
if (irqnow & USBD_INT_USBEVENT)
|
||||
{
|
||||
usbtrace(TRACE_INTDECODE(NRF52_TRACEINTID_USBEVENT), 0);
|
||||
nrf52_eventinterrupt(priv);
|
||||
nrf52_putreg(0, NRF52_USBD_EVENTS_USBEVENT);
|
||||
}
|
||||
|
||||
/* DMA transfer complete */
|
||||
|
||||
if (irqnow & NRF52_USBD_DMAIRQ)
|
||||
{
|
||||
nrf52_startdma_ack(priv);
|
||||
}
|
||||
|
||||
/* Handle EP0SETUP */
|
||||
|
||||
if (nrf52_getreg(NRF52_USBD_EVENTS_EP0SETUP))
|
||||
if (irqnow & USBD_INT_EP0SETUP)
|
||||
{
|
||||
usbtrace(TRACE_INTDECODE(NRF52_TRACEINTID_EP0SETUP), 0);
|
||||
nrf52_ep0setupinterrupt(priv);
|
||||
nrf52_putreg(0, NRF52_USBD_EVENTS_EP0SETUP);
|
||||
}
|
||||
|
||||
/* Handle EP0DATADONE */
|
||||
|
||||
if (nrf52_getreg(NRF52_USBD_EVENTS_EP0DATADONE))
|
||||
if (irqnow & USBD_INT_EP0DATADONE)
|
||||
{
|
||||
usbtrace(TRACE_INTDECODE(NRF52_TRACEINTID_EP0DATADONE), 0);
|
||||
nrf52_ep0datainterrupt(priv);
|
||||
nrf52_putreg(0, NRF52_USBD_EVENTS_EP0DATADONE);
|
||||
}
|
||||
|
||||
/* Handle ENDEPOUT */
|
||||
|
||||
nrf52_endepoutinterrupt(priv, irqnow);
|
||||
|
||||
/* Handle ENDEPIN */
|
||||
|
||||
nrf52_endepininterrupt(priv, irqnow);
|
||||
|
||||
/* Handle EPDATA */
|
||||
|
||||
if (nrf52_getreg(NRF52_USBD_EVENTS_EPDATA))
|
||||
if (irqnow & USBD_INT_EPDATA)
|
||||
{
|
||||
usbtrace(TRACE_INTDECODE(NRF52_TRACEINTID_EPDATA), 0);
|
||||
nrf52_epdatainterrupt(priv);
|
||||
nrf52_putreg(0, NRF52_USBD_EVENTS_EPDATA);
|
||||
}
|
||||
|
||||
/* Handle all END events */
|
||||
/* Try to handle waiting OUT DMA requests */
|
||||
|
||||
nrf52_endepininterrupt(priv);
|
||||
nrf52_endepoutinterrupt(priv);
|
||||
if (priv->dmanow == false)
|
||||
{
|
||||
if (priv->dmaepoutwait)
|
||||
{
|
||||
for (i = 0; i < NRF52_NENDPOINTS; i++)
|
||||
{
|
||||
if (priv->dmaepoutwait & (1 << i))
|
||||
{
|
||||
priv->dmaepoutwait &= ~(1 << i);
|
||||
|
||||
privep = &priv->epout[i];
|
||||
nrf52_epout_handle(priv, privep);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Try to handle waiting IN DMA requests */
|
||||
|
||||
if (priv->dmanow == false)
|
||||
{
|
||||
if (priv->dmaepinwait)
|
||||
{
|
||||
for (i = 0; i < NRF52_NENDPOINTS; i++)
|
||||
{
|
||||
if (priv->dmaepinwait & (1 << i))
|
||||
{
|
||||
priv->dmaepinwait &= ~(1 << i);
|
||||
|
||||
privep = &priv->epin[i];
|
||||
nrf52_epin_request(priv, privep);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
intout:
|
||||
usbtrace(TRACE_INTEXIT(NRF52_TRACEINTID_USB), 0);
|
||||
@ -2029,7 +2141,6 @@ intout:
|
||||
static int nrf52_epout_configure(struct nrf52_ep_s *privep, uint8_t eptype,
|
||||
uint16_t maxpacket)
|
||||
{
|
||||
uint32_t mpsiz = 0;
|
||||
uint32_t regval = 0;
|
||||
|
||||
usbtrace(TRACE_EPCONFIGURE, privep->epphy);
|
||||
@ -2040,15 +2151,10 @@ static int nrf52_epout_configure(struct nrf52_ep_s *privep, uint8_t eptype,
|
||||
{
|
||||
DEBUGASSERT(eptype == USB_EP_ATTR_XFER_CONTROL);
|
||||
|
||||
/* EP0OUT MPSIZ and EPTYP is read only ! */
|
||||
/* EP0OUT EPTYP is read only ! */
|
||||
|
||||
mpsiz = 0;
|
||||
eptype = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
mpsiz = maxpacket;
|
||||
}
|
||||
|
||||
/* Enable the endpoint */
|
||||
|
||||
@ -2056,10 +2162,6 @@ static int nrf52_epout_configure(struct nrf52_ep_s *privep, uint8_t eptype,
|
||||
regval |= USBD_EPOUTEN_OUT(privep->epphy);
|
||||
nrf52_putreg(regval, NRF52_USBD_EPOUTEN);
|
||||
|
||||
/* Configure the max packet size */
|
||||
|
||||
nrf52_putreg(mpsiz, NRF52_USBD_EPOUT_MAXCNT(privep->epphy));
|
||||
|
||||
/* Save the endpoint configuration */
|
||||
|
||||
privep->ep.maxpacket = maxpacket;
|
||||
@ -2095,15 +2197,10 @@ static int nrf52_epout_configure(struct nrf52_ep_s *privep, uint8_t eptype,
|
||||
static int nrf52_epin_configure(struct nrf52_ep_s *privep, uint8_t eptype,
|
||||
uint16_t maxpacket)
|
||||
{
|
||||
uint32_t mpsiz = 0;
|
||||
uint32_t regval = 0;
|
||||
|
||||
usbtrace(TRACE_EPCONFIGURE, privep->epphy);
|
||||
|
||||
/* The packet size is in bytes for all EP */
|
||||
|
||||
mpsiz = maxpacket;
|
||||
|
||||
if (privep->epphy == EP0)
|
||||
{
|
||||
DEBUGASSERT(eptype == USB_EP_ATTR_XFER_CONTROL);
|
||||
@ -2119,21 +2216,13 @@ static int nrf52_epin_configure(struct nrf52_ep_s *privep, uint8_t eptype,
|
||||
regval |= USBD_EPINEN_IN(privep->epphy);
|
||||
nrf52_putreg(regval, NRF52_USBD_EPINEN);
|
||||
|
||||
/* Configure the max packet size */
|
||||
|
||||
nrf52_putreg(mpsiz, NRF52_USBD_EPIN_MAXCNT(privep->epphy));
|
||||
|
||||
/* Save the endpoint configuration */
|
||||
|
||||
privep->ep.maxpacket = maxpacket;
|
||||
privep->eptype = eptype;
|
||||
privep->stalled = false;
|
||||
|
||||
/* Enable the interrupt for this endpoint */
|
||||
|
||||
regval = nrf52_getreg(NRF52_USBD_INTEN);
|
||||
regval |= USBD_INT_ENDEPIN(privep->epphy);
|
||||
nrf52_putreg(regval, NRF52_USBD_INTEN);
|
||||
/* NOTE: don't enable EPIN END interrupts as they cause EPIN locks */
|
||||
|
||||
return OK;
|
||||
}
|
||||
@ -2265,12 +2354,6 @@ static void nrf52_epin_disable(struct nrf52_ep_s *privep)
|
||||
regval &= ~USBD_EPINEN_IN(privep->epphy);
|
||||
nrf52_putreg(regval, NRF52_USBD_EPINEN);
|
||||
|
||||
/* Disable endpoint interrupts */
|
||||
|
||||
regval = nrf52_getreg(NRF52_USBD_INTEN);
|
||||
regval &= ~USBD_INT_ENDEPIN(privep->epphy);
|
||||
nrf52_putreg(regval, NRF52_USBD_INTEN);
|
||||
|
||||
/* Cancel any queued write requests */
|
||||
|
||||
nrf52_req_cancel(privep, -ESHUTDOWN);
|
||||
|
@ -47,6 +47,7 @@
|
||||
#define NRF53_USBD_TASKS_DPDMDRIVE_OFFSET (0x0058)
|
||||
#define NRF53_USBD_TASKS_PDPMNODRIVE_OFFSET (0x005c)
|
||||
#define NRF53_USBD_EVENTS_USBRESET_OFFSET (0x0100)
|
||||
#define NRF53_USBD_EVENTS_STARTED_OFFSET (0x0104)
|
||||
#define NRF53_USBD_EVENTS_ENDEPIN_OFFSET(n) (0x0108 + (0x04 * n))
|
||||
#define NRF53_USBD_EVENTS_EP0DATADONE_OFFSET (0x0128)
|
||||
#define NRF53_USBD_EVENTS_ENDISOIN_OFFSET (0x012c)
|
||||
@ -112,6 +113,7 @@
|
||||
#define NRF53_USBD_TASKS_DPDMDRIVE (NRF53_USBD_BASE + NRF53_USBD_TASKS_DPDMDRIVE_OFFSET)
|
||||
#define NRF53_USBD_TASKS_PDPMNODRIVE (NRF53_USBD_BASE + NRF53_USBD_TASKS_PDPMNODRIVE_OFFSET)
|
||||
#define NRF53_USBD_EVENTS_USBRESET (NRF53_USBD_BASE + NRF53_USBD_EVENTS_USBRESET_OFFSET)
|
||||
#define NRF53_USBD_EVENTS_STARTED (NRF53_USBD_BASE + NRF53_USBD_EVENTS_STARTED_OFFSET)
|
||||
#define NRF53_USBD_EVENTS_ENDEPIN(n) (NRF53_USBD_BASE + NRF53_USBD_EVENTS_ENDEPIN_OFFSET(n))
|
||||
#define NRF53_USBD_EVENTS_EP0DATADONE (NRF53_USBD_BASE + NRF53_USBD_EVENTS_EP0DATADONE_OFFSET)
|
||||
#define NRF53_USBD_EVENTS_ENDISOIN (NRF53_USBD_BASE + NRF53_USBD_EVENTS_ENDISOIN_OFFSEN)
|
||||
@ -197,6 +199,7 @@
|
||||
#define USBD_INT_EP0SETUP (1 << 23) /* Enable/disable interrupt EP0SETUP */
|
||||
#define USBD_INT_EPDATA (1 << 24) /* Enable/disable interrupt EPDATA */
|
||||
#define USBD_INT_ALL (0x1fffffff)
|
||||
#define USBD_INT_ALL_NUM (25)
|
||||
|
||||
/* EVENTCAUSE */
|
||||
|
||||
|
@ -24,8 +24,6 @@
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdint.h>
|
||||
@ -79,6 +77,7 @@
|
||||
#define NRF53_TRACEERR_INVALIDCTRLREQ 0x17
|
||||
#define NRF53_TRACEERR_BADGETSTATUS 0x18
|
||||
#define NRF53_TRACEERR_EPINREQEMPTY 0x19
|
||||
#define NRF53_TRACEERR_DMABUSY 0x20
|
||||
|
||||
/* Trace interrupt codes */
|
||||
|
||||
@ -184,11 +183,23 @@
|
||||
USBD_INT_EP0DATADONE | \
|
||||
USBD_INT_USBEVENT | \
|
||||
USBD_INT_EP0SETUP | \
|
||||
USBD_INT_EPDATA | \
|
||||
USBD_INT_ENDEPIN(0) | \
|
||||
USBD_INT_ENDEPOUT(0))
|
||||
USBD_INT_EPDATA)
|
||||
#endif
|
||||
|
||||
/* Interrupts that signal DMA transfer complete:
|
||||
* ENDEPIN0-7, ENDEPOUT0-7, ENDISOIN, ENDISOOUT
|
||||
*/
|
||||
|
||||
#define NRF53_USBD_DMAIRQ (USBD_INT_ENDEPIN(0) | USBD_INT_ENDEPIN(1) | \
|
||||
USBD_INT_ENDEPIN(2) | USBD_INT_ENDEPIN(3) | \
|
||||
USBD_INT_ENDEPIN(4) | USBD_INT_ENDEPIN(5) | \
|
||||
USBD_INT_ENDEPIN(6) | USBD_INT_ENDEPIN(7) | \
|
||||
USBD_INT_ENDEPOUT(0) | USBD_INT_ENDEPOUT(1) | \
|
||||
USBD_INT_ENDEPOUT(2) | USBD_INT_ENDEPOUT(3) | \
|
||||
USBD_INT_ENDEPOUT(4) | USBD_INT_ENDEPOUT(5) | \
|
||||
USBD_INT_ENDEPOUT(6) | USBD_INT_ENDEPOUT(7) | \
|
||||
USBD_INT_ENDISOIN | USBD_INT_ENDISOOUT)
|
||||
|
||||
/****************************************************************************
|
||||
* Private Type Definitions
|
||||
****************************************************************************/
|
||||
@ -259,7 +270,12 @@ struct nrf53_usbdev_s
|
||||
uint8_t ep0indone; /* 1: EP0 IN transfer complete */
|
||||
uint8_t ep0outdone; /* 1: EP0 OUT transfer complete */
|
||||
uint8_t epavail[2]; /* Bitset of available OUT/IN endpoints */
|
||||
|
||||
/* DMA access control */
|
||||
|
||||
bool dmanow; /* DMA transfer pending */
|
||||
uint16_t dmaepinwait; /* EP IN waiting for DMA */
|
||||
uint16_t dmaepoutwait; /* EP OUT waitning for DMA */
|
||||
|
||||
/* E0 SETUP data buffering.
|
||||
*
|
||||
@ -360,8 +376,10 @@ static void nrf53_eventinterrupt(struct nrf53_usbdev_s *priv);
|
||||
static void nrf53_ep0setupinterrupt(struct nrf53_usbdev_s *priv);
|
||||
static void nrf53_ep0datainterrupt(struct nrf53_usbdev_s *priv);
|
||||
static void nrf53_epdatainterrupt(struct nrf53_usbdev_s *priv);
|
||||
static void nrf53_endepininterrupt(struct nrf53_usbdev_s *priv);
|
||||
static void nrf53_endepoutinterrupt(struct nrf53_usbdev_s *priv);
|
||||
static void nrf53_endepininterrupt(struct nrf53_usbdev_s *priv,
|
||||
uint32_t irqnow);
|
||||
static void nrf53_endepoutinterrupt(struct nrf53_usbdev_s *priv,
|
||||
uint32_t irqnow);
|
||||
|
||||
/* First level interrupt processing */
|
||||
|
||||
@ -563,10 +581,7 @@ const struct trace_msg_t g_usb_trace_strings_intdecode[] =
|
||||
static void nrf53_startdma_task(struct nrf53_usbdev_s *priv, uint32_t addr)
|
||||
{
|
||||
usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_DMATASK), addr);
|
||||
|
||||
*(volatile uint32_t *)0x40027c1c = 0x00000082;
|
||||
nrf53_putreg(1, addr);
|
||||
|
||||
priv->dmanow = true;
|
||||
}
|
||||
|
||||
@ -575,9 +590,6 @@ static void nrf53_startdma_ack(struct nrf53_usbdev_s *priv)
|
||||
if (priv->dmanow == true)
|
||||
{
|
||||
usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_DMAACK), 0);
|
||||
|
||||
*(volatile uint32_t *)0x40027c1c = 0x00000000;
|
||||
|
||||
priv->dmanow = false;
|
||||
}
|
||||
}
|
||||
@ -1020,18 +1032,26 @@ static void nrf53_epin_transfer(struct nrf53_ep_s *privep, uint8_t *buf,
|
||||
DEBUGASSERT(privep->eptype != USB_EP_ATTR_XFER_ISOC);
|
||||
DEBUGASSERT(nbytes <= 64);
|
||||
|
||||
if (nbytes > 0)
|
||||
/* Configure EasyDMA */
|
||||
|
||||
if (buf)
|
||||
{
|
||||
/* Configure EasyDMA */
|
||||
|
||||
DEBUGASSERT(nrf53_easydma_valid((uint32_t)buf));
|
||||
nrf53_putreg((uint32_t)buf, NRF53_USBD_EPIN_PTR(privep->epphy));
|
||||
nrf53_putreg(nbytes, NRF53_USBD_EPIN_MAXCNT(privep->epphy));
|
||||
|
||||
/* Start EPIN task - DMA transfer */
|
||||
|
||||
nrf53_epin_start(priv, privep->epphy);
|
||||
}
|
||||
|
||||
nrf53_putreg((uint32_t)buf, NRF53_USBD_EPIN_PTR(privep->epphy));
|
||||
nrf53_putreg(nbytes, NRF53_USBD_EPIN_MAXCNT(privep->epphy));
|
||||
|
||||
/* Start EPIN task - DMA transfer */
|
||||
|
||||
nrf53_epin_start(priv, privep->epphy);
|
||||
|
||||
/* Busy wait for ENDEPIN to prevent any access to USBD registers during
|
||||
* EasyDMA transfer. Otherwise USBD is not stable.
|
||||
*/
|
||||
|
||||
while (nrf53_getreg(NRF53_USBD_EVENTS_ENDEPIN(privep->epphy)) == 0 &&
|
||||
nrf53_getreg(NRF53_USBD_EVENTS_USBRESET) == 0);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -1067,9 +1087,18 @@ static void nrf53_epout_transfer(struct nrf53_ep_s *privep)
|
||||
DEBUGASSERT(privep && privep->dev);
|
||||
priv = (struct nrf53_usbdev_s *)privep->dev;
|
||||
|
||||
/* Number of bytes received last in the data stage of this OUT endpoint */
|
||||
if (privep->epphy == 0)
|
||||
{
|
||||
nbytes = USBDEV_EP0_MAXSIZE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Number of bytes received last in the data stage of this OUT
|
||||
* endpoint
|
||||
*/
|
||||
|
||||
nbytes = nrf53_getreg(NRF53_USBD_SIZE_EPOUT(privep->epphy));
|
||||
nbytes = nrf53_getreg(NRF53_USBD_SIZE_EPOUT(privep->epphy));
|
||||
}
|
||||
|
||||
/* Configure EasyDMA */
|
||||
|
||||
@ -1081,6 +1110,13 @@ static void nrf53_epout_transfer(struct nrf53_ep_s *privep)
|
||||
/* Start EPOUT task */
|
||||
|
||||
nrf53_epout_start(priv, privep->epphy);
|
||||
|
||||
/* Busy wait for ENDEPOUT to prevent any access to USBD registers during
|
||||
* EasyDMA transfer. Otherwise USBD is not stable.
|
||||
*/
|
||||
|
||||
while (nrf53_getreg(NRF53_USBD_EVENTS_ENDEPOUT(privep->epphy)) == 0 &&
|
||||
nrf53_getreg(NRF53_USBD_EVENTS_USBRESET) == 0);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -1099,6 +1135,15 @@ static void nrf53_epin_request(struct nrf53_usbdev_s *priv,
|
||||
int bytesleft = 0;
|
||||
int nbytes = 0;
|
||||
|
||||
/* If DMA is busy, add EP IN to the waiting list */
|
||||
|
||||
if (priv->dmanow == true)
|
||||
{
|
||||
usbtrace(TRACE_DEVERROR(NRF53_TRACEERR_DMABUSY), privep->epphy);
|
||||
priv->dmaepinwait |= (1 << privep->epphy);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check the request from the head of the endpoint request queue */
|
||||
|
||||
privreq = nrf53_rqpeek(privep);
|
||||
@ -1145,6 +1190,16 @@ static void nrf53_epin_request(struct nrf53_usbdev_s *priv,
|
||||
|
||||
privreq->req.xfrd += nbytes;
|
||||
}
|
||||
else if (privreq->req.len == 0)
|
||||
{
|
||||
/* Zero-length packet */
|
||||
|
||||
nrf53_epin_transfer(privep, NULL, 0);
|
||||
|
||||
/* ACK zero-length DMA transfer right away */
|
||||
|
||||
nrf53_startdma_ack(priv);
|
||||
}
|
||||
|
||||
/* Has all the request data been sent? */
|
||||
|
||||
@ -1189,7 +1244,6 @@ static void nrf53_epout_complete(struct nrf53_ep_s *privep)
|
||||
|
||||
privreq = nrf53_rqpeek(privep);
|
||||
DEBUGASSERT(privreq);
|
||||
|
||||
if (!privreq)
|
||||
{
|
||||
/* An OUT transfer completed, but no packet to receive the data. This
|
||||
@ -1210,10 +1264,6 @@ static void nrf53_epout_complete(struct nrf53_ep_s *privep)
|
||||
|
||||
usbtrace(TRACE_COMPLETE(privep->epphy), privreq->req.xfrd);
|
||||
nrf53_req_complete(privep, OK);
|
||||
|
||||
/* Allow OUT trafic on this endpoint */
|
||||
|
||||
nrf53_epout_allow(privep);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -1342,6 +1392,15 @@ static void nrf53_epout_handle(struct nrf53_usbdev_s *priv,
|
||||
|
||||
DEBUGASSERT(privep->epphy != EP0);
|
||||
|
||||
/* If DMA is busy, add EP OUT to the waiting list */
|
||||
|
||||
if (priv->dmanow == true)
|
||||
{
|
||||
usbtrace(TRACE_DEVERROR(NRF53_TRACEERR_DMABUSY), privep->epphy);
|
||||
priv->dmaepoutwait |= (1 << privep->epphy);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Loop until a valid request is found (or the request queue is empty).
|
||||
* The loop is only need to look at the request queue again is an
|
||||
* invalid read request is encountered.
|
||||
@ -1776,8 +1835,6 @@ static void nrf53_ep0datainterrupt(struct nrf53_usbdev_s *priv)
|
||||
{
|
||||
struct nrf53_ep_s *privep = NULL;
|
||||
|
||||
nrf53_startdma_ack(priv);
|
||||
|
||||
if (USB_REQ_ISOUT(priv->ctrlreq.type))
|
||||
{
|
||||
/* Prepare EP OUT DMA transfer */
|
||||
@ -1787,11 +1844,6 @@ static void nrf53_ep0datainterrupt(struct nrf53_usbdev_s *priv)
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Handle IN request */
|
||||
|
||||
privep = &priv->epin[EP0];
|
||||
nrf53_epin_request(priv, privep);
|
||||
|
||||
if (priv->ep0indone)
|
||||
{
|
||||
/* Allows status stage on control endpoint 0 */
|
||||
@ -1799,6 +1851,13 @@ static void nrf53_ep0datainterrupt(struct nrf53_usbdev_s *priv)
|
||||
nrf53_ep0status_start(priv);
|
||||
priv->ep0indone = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Handle IN request */
|
||||
|
||||
privep = &priv->epin[EP0];
|
||||
nrf53_epin_request(priv, privep);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1816,12 +1875,14 @@ static void nrf53_epdatainterrupt(struct nrf53_usbdev_s *priv)
|
||||
uint32_t datastatus = 0;
|
||||
int epno = 0;
|
||||
|
||||
nrf53_startdma_ack(priv);
|
||||
|
||||
/* Get pending data status */
|
||||
|
||||
datastatus = nrf53_getreg(NRF53_USBD_EPDATASTATUS);
|
||||
|
||||
/* Clear register */
|
||||
|
||||
nrf53_putreg(datastatus, NRF53_USBD_EPDATASTATUS);
|
||||
|
||||
/* Ignore EP0 */
|
||||
|
||||
for (epno = 1; epno < NRF53_NENDPOINTS; epno += 1)
|
||||
@ -1842,61 +1903,51 @@ static void nrf53_epdatainterrupt(struct nrf53_usbdev_s *priv)
|
||||
nrf53_epout_handle(priv, privep);
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear register */
|
||||
|
||||
nrf53_putreg(datastatus, NRF53_USBD_EPDATASTATUS);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nrf53_endepin
|
||||
* Name: nrf53_endepininterrupt
|
||||
*
|
||||
* Description:
|
||||
* Handle ENDEPIN events
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void nrf53_endepininterrupt(struct nrf53_usbdev_s *priv)
|
||||
static void nrf53_endepininterrupt(struct nrf53_usbdev_s *priv,
|
||||
uint32_t irqnow)
|
||||
{
|
||||
int epno = 0;
|
||||
|
||||
nrf53_startdma_ack(priv);
|
||||
|
||||
/* Process each pending IN endpoint interrupt */
|
||||
|
||||
for (epno = 0; epno < NRF53_NENDPOINTS; epno += 1)
|
||||
{
|
||||
if (nrf53_getreg(NRF53_USBD_EVENTS_ENDEPIN(epno)))
|
||||
if (irqnow & USBD_INT_ENDEPIN(epno))
|
||||
{
|
||||
usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_ENDEPIN), epno);
|
||||
|
||||
/* Clear event */
|
||||
|
||||
nrf53_putreg(0, NRF53_USBD_EVENTS_ENDEPIN(epno));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nrf53_endepout
|
||||
* Name: nrf53_endepoutinterrupt
|
||||
*
|
||||
* Description:
|
||||
* Handle ENDEPOUT events
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void nrf53_endepoutinterrupt(struct nrf53_usbdev_s *priv)
|
||||
static void nrf53_endepoutinterrupt(struct nrf53_usbdev_s *priv,
|
||||
uint32_t irqnow)
|
||||
{
|
||||
struct nrf53_ep_s *privep = NULL;
|
||||
int epno = 0;
|
||||
|
||||
nrf53_startdma_ack(priv);
|
||||
|
||||
/* Process each pending OUT endpoint interrupt */
|
||||
|
||||
for (epno = 0; epno < NRF53_NENDPOINTS; epno += 1)
|
||||
{
|
||||
if (nrf53_getreg(NRF53_USBD_EVENTS_ENDEPOUT(epno)))
|
||||
if (irqnow & USBD_INT_ENDEPOUT(epno))
|
||||
{
|
||||
usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_ENDEPOUT), epno);
|
||||
|
||||
@ -1925,10 +1976,6 @@ static void nrf53_endepoutinterrupt(struct nrf53_usbdev_s *priv)
|
||||
privep = &priv->epout[epno];
|
||||
nrf53_epout_receive(privep);
|
||||
}
|
||||
|
||||
/* Clear event */
|
||||
|
||||
nrf53_putreg(0, NRF53_USBD_EVENTS_ENDEPOUT(epno));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1943,70 +1990,135 @@ static void nrf53_endepoutinterrupt(struct nrf53_usbdev_s *priv)
|
||||
|
||||
static int nrf53_usbinterrupt(int irq, void *context, void *arg)
|
||||
{
|
||||
struct nrf53_usbdev_s *priv = &g_usbdev;
|
||||
struct nrf53_usbdev_s *priv = &g_usbdev;
|
||||
struct nrf53_ep_s *privep = NULL;
|
||||
uint32_t irqnow = 0;
|
||||
uint32_t offset = 0;
|
||||
int i = 0;
|
||||
|
||||
usbtrace(TRACE_INTENTRY(NRF53_TRACEINTID_USB), 0);
|
||||
|
||||
/* Handle all events */
|
||||
|
||||
for (i = 0; i < USBD_INT_ALL_NUM; i++)
|
||||
{
|
||||
/* Get EVENT offset */
|
||||
|
||||
offset = NRF53_USBD_EVENTS_USBRESET + 0x04 * i;
|
||||
|
||||
/* Get EVENT state */
|
||||
|
||||
irqnow |= nrf53_getreg(offset) << i;
|
||||
|
||||
/* Clear EVENT */
|
||||
|
||||
nrf53_putreg(0, offset);
|
||||
}
|
||||
|
||||
/* USB reset interrupt */
|
||||
|
||||
if (nrf53_getreg(NRF53_USBD_EVENTS_USBRESET))
|
||||
if (irqnow & USBD_INT_USBRESET)
|
||||
{
|
||||
usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_DEVRESET), 0);
|
||||
nrf53_usbreset(priv);
|
||||
nrf53_putreg(0, NRF53_USBD_EVENTS_USBRESET);
|
||||
goto intout;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USBDEV_SOFINTERRUPT
|
||||
/* Handle SOF */
|
||||
|
||||
if (nrf53_getreg(NRF53_USBD_EVENTS_SOF))
|
||||
if (irqnow & USBD_INT_SOF)
|
||||
{
|
||||
usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_SOF), 0);
|
||||
nrf53_putreg(0, NRF53_USBD_EVENTS_SOF);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Handle USBEVENT */
|
||||
|
||||
if (nrf53_getreg(NRF53_USBD_EVENTS_USBEVENT))
|
||||
if (irqnow & USBD_INT_USBEVENT)
|
||||
{
|
||||
usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_USBEVENT), 0);
|
||||
nrf53_eventinterrupt(priv);
|
||||
nrf53_putreg(0, NRF53_USBD_EVENTS_USBEVENT);
|
||||
}
|
||||
|
||||
/* DMA transfer complete */
|
||||
|
||||
if (irqnow & NRF53_USBD_DMAIRQ)
|
||||
{
|
||||
nrf53_startdma_ack(priv);
|
||||
}
|
||||
|
||||
/* Handle EP0SETUP */
|
||||
|
||||
if (nrf53_getreg(NRF53_USBD_EVENTS_EP0SETUP))
|
||||
if (irqnow & USBD_INT_EP0SETUP)
|
||||
{
|
||||
usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_EP0SETUP), 0);
|
||||
nrf53_ep0setupinterrupt(priv);
|
||||
nrf53_putreg(0, NRF53_USBD_EVENTS_EP0SETUP);
|
||||
}
|
||||
|
||||
/* Handle EP0DATADONE */
|
||||
|
||||
if (nrf53_getreg(NRF53_USBD_EVENTS_EP0DATADONE))
|
||||
if (irqnow & USBD_INT_EP0DATADONE)
|
||||
{
|
||||
usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_EP0DATADONE), 0);
|
||||
nrf53_ep0datainterrupt(priv);
|
||||
nrf53_putreg(0, NRF53_USBD_EVENTS_EP0DATADONE);
|
||||
}
|
||||
|
||||
/* Handle ENDEPOUT */
|
||||
|
||||
nrf53_endepoutinterrupt(priv, irqnow);
|
||||
|
||||
/* Handle ENDEPIN */
|
||||
|
||||
nrf53_endepininterrupt(priv, irqnow);
|
||||
|
||||
/* Handle EPDATA */
|
||||
|
||||
if (nrf53_getreg(NRF53_USBD_EVENTS_EPDATA))
|
||||
if (irqnow & USBD_INT_EPDATA)
|
||||
{
|
||||
usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_EPDATA), 0);
|
||||
nrf53_epdatainterrupt(priv);
|
||||
nrf53_putreg(0, NRF53_USBD_EVENTS_EPDATA);
|
||||
}
|
||||
|
||||
/* Handle all END events */
|
||||
/* Try to handle waiting OUT DMA requests */
|
||||
|
||||
nrf53_endepininterrupt(priv);
|
||||
nrf53_endepoutinterrupt(priv);
|
||||
if (priv->dmanow == false)
|
||||
{
|
||||
if (priv->dmaepoutwait)
|
||||
{
|
||||
for (i = 0; i < NRF53_NENDPOINTS; i++)
|
||||
{
|
||||
if (priv->dmaepoutwait & (1 << i))
|
||||
{
|
||||
priv->dmaepoutwait &= ~(1 << i);
|
||||
|
||||
privep = &priv->epout[i];
|
||||
nrf53_epout_handle(priv, privep);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Try to handle waiting IN DMA requests */
|
||||
|
||||
if (priv->dmanow == false)
|
||||
{
|
||||
if (priv->dmaepinwait)
|
||||
{
|
||||
for (i = 0; i < NRF53_NENDPOINTS; i++)
|
||||
{
|
||||
if (priv->dmaepinwait & (1 << i))
|
||||
{
|
||||
priv->dmaepinwait &= ~(1 << i);
|
||||
|
||||
privep = &priv->epin[i];
|
||||
nrf53_epin_request(priv, privep);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
intout:
|
||||
usbtrace(TRACE_INTEXIT(NRF53_TRACEINTID_USB), 0);
|
||||
@ -2029,7 +2141,6 @@ intout:
|
||||
static int nrf53_epout_configure(struct nrf53_ep_s *privep, uint8_t eptype,
|
||||
uint16_t maxpacket)
|
||||
{
|
||||
uint32_t mpsiz = 0;
|
||||
uint32_t regval = 0;
|
||||
|
||||
usbtrace(TRACE_EPCONFIGURE, privep->epphy);
|
||||
@ -2040,15 +2151,10 @@ static int nrf53_epout_configure(struct nrf53_ep_s *privep, uint8_t eptype,
|
||||
{
|
||||
DEBUGASSERT(eptype == USB_EP_ATTR_XFER_CONTROL);
|
||||
|
||||
/* EP0OUT MPSIZ and EPTYP is read only ! */
|
||||
/* EP0OUT EPTYP is read only ! */
|
||||
|
||||
mpsiz = 0;
|
||||
eptype = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
mpsiz = maxpacket;
|
||||
}
|
||||
|
||||
/* Enable the endpoint */
|
||||
|
||||
@ -2056,10 +2162,6 @@ static int nrf53_epout_configure(struct nrf53_ep_s *privep, uint8_t eptype,
|
||||
regval |= USBD_EPOUTEN_OUT(privep->epphy);
|
||||
nrf53_putreg(regval, NRF53_USBD_EPOUTEN);
|
||||
|
||||
/* Configure the max packet size */
|
||||
|
||||
nrf53_putreg(mpsiz, NRF53_USBD_EPOUT_MAXCNT(privep->epphy));
|
||||
|
||||
/* Save the endpoint configuration */
|
||||
|
||||
privep->ep.maxpacket = maxpacket;
|
||||
@ -2095,15 +2197,10 @@ static int nrf53_epout_configure(struct nrf53_ep_s *privep, uint8_t eptype,
|
||||
static int nrf53_epin_configure(struct nrf53_ep_s *privep, uint8_t eptype,
|
||||
uint16_t maxpacket)
|
||||
{
|
||||
uint32_t mpsiz = 0;
|
||||
uint32_t regval = 0;
|
||||
|
||||
usbtrace(TRACE_EPCONFIGURE, privep->epphy);
|
||||
|
||||
/* The packet size is in bytes for all EP */
|
||||
|
||||
mpsiz = maxpacket;
|
||||
|
||||
if (privep->epphy == EP0)
|
||||
{
|
||||
DEBUGASSERT(eptype == USB_EP_ATTR_XFER_CONTROL);
|
||||
@ -2119,21 +2216,13 @@ static int nrf53_epin_configure(struct nrf53_ep_s *privep, uint8_t eptype,
|
||||
regval |= USBD_EPINEN_IN(privep->epphy);
|
||||
nrf53_putreg(regval, NRF53_USBD_EPINEN);
|
||||
|
||||
/* Configure the max packet size */
|
||||
|
||||
nrf53_putreg(mpsiz, NRF53_USBD_EPIN_MAXCNT(privep->epphy));
|
||||
|
||||
/* Save the endpoint configuration */
|
||||
|
||||
privep->ep.maxpacket = maxpacket;
|
||||
privep->eptype = eptype;
|
||||
privep->stalled = false;
|
||||
|
||||
/* Enable the interrupt for this endpoint */
|
||||
|
||||
regval = nrf53_getreg(NRF53_USBD_INTEN);
|
||||
regval |= USBD_INT_ENDEPIN(privep->epphy);
|
||||
nrf53_putreg(regval, NRF53_USBD_INTEN);
|
||||
/* NOTE: don't enable EPIN END interrupts as they cause EPIN locks */
|
||||
|
||||
return OK;
|
||||
}
|
||||
@ -2265,12 +2354,6 @@ static void nrf53_epin_disable(struct nrf53_ep_s *privep)
|
||||
regval &= ~USBD_EPINEN_IN(privep->epphy);
|
||||
nrf53_putreg(regval, NRF53_USBD_EPINEN);
|
||||
|
||||
/* Disable endpoint interrupts */
|
||||
|
||||
regval = nrf53_getreg(NRF53_USBD_INTEN);
|
||||
regval &= ~USBD_INT_ENDEPIN(privep->epphy);
|
||||
nrf53_putreg(regval, NRF53_USBD_INTEN);
|
||||
|
||||
/* Cancel any queued write requests */
|
||||
|
||||
nrf53_req_cancel(privep, -ESHUTDOWN);
|
||||
|
Loading…
x
Reference in New Issue
Block a user