SAMA5 UDPHS: Fix some issues with TX interrupt handling
This commit is contained in:
parent
74d0e02850
commit
adc7248d6c
@ -186,28 +186,26 @@
|
|||||||
#define SAM_TRACEINTID_EP0SETUPOUT 0x000d
|
#define SAM_TRACEINTID_EP0SETUPOUT 0x000d
|
||||||
#define SAM_TRACEINTID_EP0SETUPSETADDRESS 0x000e
|
#define SAM_TRACEINTID_EP0SETUPSETADDRESS 0x000e
|
||||||
#define SAM_TRACEINTID_EPGETSTATUS 0x000f
|
#define SAM_TRACEINTID_EPGETSTATUS 0x000f
|
||||||
#define SAM_TRACEINTID_EPINDONE 0x0010
|
#define SAM_TRACEINTID_EPINQEMPTY 0x0010
|
||||||
#define SAM_TRACEINTID_EPINQEMPTY 0x0011
|
#define SAM_TRACEINTID_EPOUTQEMPTY 0x0011
|
||||||
#define SAM_TRACEINTID_EPOUTQEMPTY 0x0012
|
#define SAM_TRACEINTID_GETCONFIG 0x0012
|
||||||
#define SAM_TRACEINTID_GETCONFIG 0x0013
|
#define SAM_TRACEINTID_GETSETDESC 0x0013
|
||||||
#define SAM_TRACEINTID_GETSETDESC 0x0014
|
#define SAM_TRACEINTID_GETSETIF 0x0014
|
||||||
#define SAM_TRACEINTID_GETSETIF 0x0015
|
#define SAM_TRACEINTID_GETSTATUS 0x0015
|
||||||
#define SAM_TRACEINTID_GETSTATUS 0x0016
|
#define SAM_TRACEINTID_IFGETSTATUS 0x0016
|
||||||
#define SAM_TRACEINTID_IFGETSTATUS 0x0017
|
#define SAM_TRACEINTID_INTERRUPT 0x0017
|
||||||
#define SAM_TRACEINTID_INTERRUPT 0x0018
|
#define SAM_TRACEINTID_INTSOF 0x0018
|
||||||
#define SAM_TRACEINTID_INTSOF 0x0019
|
#define SAM_TRACEINTID_NOSTDREQ 0x0019
|
||||||
#define SAM_TRACEINTID_NOSTDREQ 0x001a
|
#define SAM_TRACEINTID_PENDING 0x001a
|
||||||
#define SAM_TRACEINTID_PENDING 0x001b
|
#define SAM_TRACEINTID_RXRDY 0x001b
|
||||||
#define SAM_TRACEINTID_RXRDY 0x001c
|
#define SAM_TRACEINTID_RXSETUP 0x001c
|
||||||
#define SAM_TRACEINTID_RXSETUP 0x001d
|
#define SAM_TRACEINTID_SETCONFIG 0x001d
|
||||||
#define SAM_TRACEINTID_SETADDRESS 0x001e
|
#define SAM_TRACEINTID_SETFEATURE 0x001e
|
||||||
#define SAM_TRACEINTID_SETCONFIG 0x001f
|
#define SAM_TRACEINTID_STALLSNT 0x001f
|
||||||
#define SAM_TRACEINTID_SETFEATURE 0x0020
|
#define SAM_TRACEINTID_SYNCHFRAME 0x0020
|
||||||
#define SAM_TRACEINTID_STALLSNT 0x0021
|
#define SAM_TRACEINTID_TXRDY 0x0021
|
||||||
#define SAM_TRACEINTID_SYNCHFRAME 0x0022
|
#define SAM_TRACEINTID_UPSTRRES 0x0022
|
||||||
#define SAM_TRACEINTID_TXRDY 0x0023
|
#define SAM_TRACEINTID_WAKEUP 0x0023
|
||||||
#define SAM_TRACEINTID_UPSTRRES 0x0024
|
|
||||||
#define SAM_TRACEINTID_WAKEUP 0x0025
|
|
||||||
|
|
||||||
/* Ever-present MIN and MAX macros */
|
/* Ever-present MIN and MAX macros */
|
||||||
|
|
||||||
@ -399,7 +397,7 @@ static inline void sam_putreg(uint32_t regval, uintptr_t regaddr);
|
|||||||
static void sam_suspend(struct sam_usbdev_s *priv);
|
static void sam_suspend(struct sam_usbdev_s *priv);
|
||||||
static void sam_resume(struct sam_usbdev_s *priv);
|
static void sam_resume(struct sam_usbdev_s *priv);
|
||||||
|
|
||||||
/* DMA/Request Helpers ******************************************************/
|
/* DMA Transfer Helpers *****************************************************/
|
||||||
|
|
||||||
#ifdef CONFIG_SAMA5_UDPHS_SCATTERGATHER
|
#ifdef CONFIG_SAMA5_UDPHS_SCATTERGATHER
|
||||||
static struct sam_dtd_s *sam_dtd_alloc(struct sam_usbdev_s *priv);
|
static struct sam_dtd_s *sam_dtd_alloc(struct sam_usbdev_s *priv);
|
||||||
@ -422,6 +420,7 @@ static inline void
|
|||||||
sam_req_abort(struct sam_ep_s *privep,
|
sam_req_abort(struct sam_ep_s *privep,
|
||||||
struct sam_req_s *privreq, int16_t result);
|
struct sam_req_s *privreq, int16_t result);
|
||||||
static void sam_req_complete(struct sam_ep_s *privep, int16_t result);
|
static void sam_req_complete(struct sam_ep_s *privep, int16_t result);
|
||||||
|
static void sam_ep_txrdy(unsigned int epno);
|
||||||
static int sam_req_wrnodma(struct sam_usbdev_s *priv,
|
static int sam_req_wrnodma(struct sam_usbdev_s *priv,
|
||||||
struct sam_ep_s *privep, struct sam_req_s *privreq);
|
struct sam_ep_s *privep, struct sam_req_s *privreq);
|
||||||
static int sam_req_write(struct sam_usbdev_s *priv,
|
static int sam_req_write(struct sam_usbdev_s *priv,
|
||||||
@ -613,7 +612,6 @@ const struct trace_msg_t g_usb_trace_strings_intdecode[] =
|
|||||||
TRACE_STR(SAM_TRACEINTID_EP0SETUPOUT),
|
TRACE_STR(SAM_TRACEINTID_EP0SETUPOUT),
|
||||||
TRACE_STR(SAM_TRACEINTID_EP0SETUPSETADDRESS),
|
TRACE_STR(SAM_TRACEINTID_EP0SETUPSETADDRESS),
|
||||||
TRACE_STR(SAM_TRACEINTID_EPGETSTATUS),
|
TRACE_STR(SAM_TRACEINTID_EPGETSTATUS),
|
||||||
TRACE_STR(SAM_TRACEINTID_EPINDONE),
|
|
||||||
TRACE_STR(SAM_TRACEINTID_EPINQEMPTY),
|
TRACE_STR(SAM_TRACEINTID_EPINQEMPTY),
|
||||||
TRACE_STR(SAM_TRACEINTID_EPOUTQEMPTY),
|
TRACE_STR(SAM_TRACEINTID_EPOUTQEMPTY),
|
||||||
TRACE_STR(SAM_TRACEINTID_GETCONFIG),
|
TRACE_STR(SAM_TRACEINTID_GETCONFIG),
|
||||||
@ -627,7 +625,6 @@ const struct trace_msg_t g_usb_trace_strings_intdecode[] =
|
|||||||
TRACE_STR(SAM_TRACEINTID_PENDING),
|
TRACE_STR(SAM_TRACEINTID_PENDING),
|
||||||
TRACE_STR(SAM_TRACEINTID_RXRDY),
|
TRACE_STR(SAM_TRACEINTID_RXRDY),
|
||||||
TRACE_STR(SAM_TRACEINTID_RXSETUP),
|
TRACE_STR(SAM_TRACEINTID_RXSETUP),
|
||||||
TRACE_STR(SAM_TRACEINTID_SETADDRESS),
|
|
||||||
TRACE_STR(SAM_TRACEINTID_SETCONFIG),
|
TRACE_STR(SAM_TRACEINTID_SETCONFIG),
|
||||||
TRACE_STR(SAM_TRACEINTID_SETFEATURE),
|
TRACE_STR(SAM_TRACEINTID_SETFEATURE),
|
||||||
TRACE_STR(SAM_TRACEINTID_STALLSNT),
|
TRACE_STR(SAM_TRACEINTID_STALLSNT),
|
||||||
@ -986,8 +983,6 @@ static int sam_req_wrdma(struct sam_usbdev_s *priv, struct sam_ep_s *privep,
|
|||||||
regval = sam_getreg(SAM_UDPHS_IEN);
|
regval = sam_getreg(SAM_UDPHS_IEN);
|
||||||
regval |= UDPHS_INT_EPT(epno);
|
regval |= UDPHS_INT_EPT(epno);
|
||||||
sam_putreg(regval, SAM_UDPHS_IEN);
|
sam_putreg(regval, SAM_UDPHS_IEN);
|
||||||
|
|
||||||
sam_putreg(UDPHS_EPTCTL_TXRDY, SAM_UDPHS_EPTCTLENB(epno));
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1140,9 +1135,6 @@ static void sam_req_complete(struct sam_ep_s *privep, int16_t result)
|
|||||||
|
|
||||||
if (privreq)
|
if (privreq)
|
||||||
{
|
{
|
||||||
DEBUGASSERT((privep->epstate == UDPHS_EPSTATE_RECEIVING) ||
|
|
||||||
(privep->epstate == UDPHS_EPSTATE_SENDING))
|
|
||||||
|
|
||||||
/* Save the result in the request structure */
|
/* Save the result in the request structure */
|
||||||
|
|
||||||
privreq->req.result = result;
|
privreq->req.result = result;
|
||||||
@ -1159,6 +1151,36 @@ static void sam_req_complete(struct sam_ep_s *privep, int16_t result)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: sam_ep_txrdy
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* IN data has been loaded in the endpoint FIFO. Manage the endpoint to
|
||||||
|
* (1) initiate sending of the data and (2) receive the TXRDY interrupt
|
||||||
|
* when the transfer completes.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static void sam_ep_txrdy(unsigned int epno)
|
||||||
|
{
|
||||||
|
/* Set TXRDY to indicate that the packet is ready to send (this works even
|
||||||
|
* for zero length packets). We will get an TXCOMP interrupt with TXRDY
|
||||||
|
* cleared. Then we are able to send the next packet.
|
||||||
|
*/
|
||||||
|
|
||||||
|
sam_putreg(UDPHS_EPTSETSTA_TXRDY, SAM_UDPHS_EPTSETSTA(epno));
|
||||||
|
|
||||||
|
/* Clear the NAK IN bit to stop NAKing IN tokens from the host. We now
|
||||||
|
* have data ready to go.
|
||||||
|
*/
|
||||||
|
|
||||||
|
sam_putreg(UDPHS_EPTSTA_NAKIN, SAM_UDPHS_EPTCLRSTA(epno));
|
||||||
|
|
||||||
|
/* Enable the TXRDY interrupt on the endpoint */
|
||||||
|
|
||||||
|
sam_putreg(UDPHS_EPTCTL_TXRDY, SAM_UDPHS_EPTCTLENB(epno));
|
||||||
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: sam_req_wrnodma
|
* Name: sam_req_wrnodma
|
||||||
*
|
*
|
||||||
@ -1267,18 +1289,11 @@ static int sam_req_wrnodma(struct sam_usbdev_s *priv, struct sam_ep_s *privep,
|
|||||||
privep->epstate = UDPHS_EPSTATE_SENDING;
|
privep->epstate = UDPHS_EPSTATE_SENDING;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set TXRDY to indicate that the packet is ready to send (this works even
|
/* Initiate the transfer and configure to receive the transfer complete
|
||||||
* for zero length packets). We will get an TXCOMP interrupt with TXRDY
|
* interrupt.
|
||||||
* cleared. Then we are able to send the next packet.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
sam_putreg(UDPHS_EPTSETSTA_TXRDY, SAM_UDPHS_EPTSETSTA(epno));
|
sam_ep_txrdy(epno);
|
||||||
|
|
||||||
/* Clear the NAK IN bit to stop NAKing IN tokens from the host. We now
|
|
||||||
* have data ready to go.
|
|
||||||
*/
|
|
||||||
|
|
||||||
sam_putreg(UDPHS_EPTSTA_NAKIN, SAM_UDPHS_EPTCLRSTA(epno));
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1396,11 +1411,12 @@ static int sam_req_write(struct sam_usbdev_s *priv, struct sam_ep_s *privep)
|
|||||||
privep->epstate = UDPHS_EPSTATE_SENDING;
|
privep->epstate = UDPHS_EPSTATE_SENDING;
|
||||||
privep->txnullpkt = 0;
|
privep->txnullpkt = 0;
|
||||||
privreq->inflight = 0;
|
privreq->inflight = 0;
|
||||||
sam_putreg(UDPHS_EPTSETSTA_TXRDY, SAM_UDPHS_EPTSETSTA(epno));
|
|
||||||
|
|
||||||
/* Clear the NAK IN bit to stop NAKing IN tokens from the host. */
|
/* Initiate the zero length transfer and configure to receive the
|
||||||
|
* transfer complete interrupt.
|
||||||
|
*/
|
||||||
|
|
||||||
sam_putreg(UDPHS_EPTSTA_NAKIN, SAM_UDPHS_EPTCLRSTA(epno));
|
sam_ep_txrdy(epno);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If all of the bytes were sent (including any final null packet)
|
/* If all of the bytes were sent (including any final null packet)
|
||||||
@ -1429,6 +1445,8 @@ static int sam_req_write(struct sam_usbdev_s *priv, struct sam_ep_s *privep)
|
|||||||
sam_putreg(regval, SAM_UDPHS_IEN);
|
sam_putreg(regval, SAM_UDPHS_IEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Disable the TXRDY interrupt */
|
||||||
|
|
||||||
sam_putreg(UDPHS_EPTCTL_TXRDY, SAM_UDPHS_EPTCTLDIS(epno));
|
sam_putreg(UDPHS_EPTCTL_TXRDY, SAM_UDPHS_EPTCTLDIS(epno));
|
||||||
privep->txnullpkt = 0;
|
privep->txnullpkt = 0;
|
||||||
sam_req_complete(privep, OK);
|
sam_req_complete(privep, OK);
|
||||||
@ -1659,18 +1677,11 @@ static void sam_ep0_wrstatus(const uint8_t *buffer, size_t buflen)
|
|||||||
*fifo++ = *buffer++;
|
*fifo++ = *buffer++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set TXRDY to indicate that the packet is ready to send (this works even
|
/* Initiate the transfer and configure to receive the transfer complete
|
||||||
* for zero length packets). We will get an TXCOMP interrupt with TXRDY
|
* interrupt.
|
||||||
* cleared. Then we are able to send the next packet.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
sam_putreg(UDPHS_EPTSETSTA_TXRDY, SAM_UDPHS_EPTSETSTA(EP0));
|
sam_ep_txrdy(EP0);
|
||||||
|
|
||||||
/* Clear the NAK IN bit to stop NAKing IN tokens from the host. We now
|
|
||||||
* have data ready to go.
|
|
||||||
*/
|
|
||||||
|
|
||||||
sam_putreg(UDPHS_EPTSTA_NAKIN, SAM_UDPHS_EPTCLRSTA(EP0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@ -2004,7 +2015,6 @@ static void sam_ep0_setup(struct sam_usbdev_s *priv)
|
|||||||
* len: 0; data = none
|
* len: 0; data = none
|
||||||
*/
|
*/
|
||||||
|
|
||||||
usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_EP0SETUPSETADDRESS), value.w);
|
|
||||||
if ((priv->ctrl.type & USB_REQ_RECIPIENT_MASK) != USB_REQ_RECIPIENT_DEVICE ||
|
if ((priv->ctrl.type & USB_REQ_RECIPIENT_MASK) != USB_REQ_RECIPIENT_DEVICE ||
|
||||||
index.w != 0 || len.w != 0 || value.w > 127)
|
index.w != 0 || len.w != 0 || value.w > 127)
|
||||||
{
|
{
|
||||||
@ -2018,7 +2028,7 @@ static void sam_ep0_setup(struct sam_usbdev_s *priv)
|
|||||||
* be set when the zero-length packet transfer completes.
|
* be set when the zero-length packet transfer completes.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_SETADDRESS), value.w);
|
usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_EP0SETUPSETADDRESS), value.w);
|
||||||
priv->devaddr = value.w;
|
priv->devaddr = value.w;
|
||||||
ep0result = UDPHS_EP0SETUP_ADDRESS;
|
ep0result = UDPHS_EP0SETUP_ADDRESS;
|
||||||
}
|
}
|
||||||
@ -2168,8 +2178,9 @@ static void sam_ep0_setup(struct sam_usbdev_s *priv)
|
|||||||
* 1b. ep0result == UDPHS_EP0SETUP_ADDRESS
|
* 1b. ep0result == UDPHS_EP0SETUP_ADDRESS
|
||||||
*
|
*
|
||||||
* A special case is the case where epstate=UDPHS_EPSTATE_EP0ADDRESS.
|
* A special case is the case where epstate=UDPHS_EPSTATE_EP0ADDRESS.
|
||||||
* This that the above processing generated an additional state where
|
* This means that the above processing generated an additional state
|
||||||
* we need to wait to obtain our device address.
|
* where we need to wait until we complete the status phase before
|
||||||
|
* applying the new device address.
|
||||||
*
|
*
|
||||||
* 2. ep0result == UDPHS_EP0SETUP_DISPATCHED;
|
* 2. ep0result == UDPHS_EP0SETUP_DISPATCHED;
|
||||||
*
|
*
|
||||||
@ -2406,7 +2417,9 @@ static void sam_ep_interrupt(struct sam_usbdev_s *priv, int epno)
|
|||||||
if (privep->epstate == UDPHS_EPSTATE_SENDING ||
|
if (privep->epstate == UDPHS_EPSTATE_SENDING ||
|
||||||
privep->epstate == UDPHS_EPSTATE_EP0STATUSIN)
|
privep->epstate == UDPHS_EPSTATE_EP0STATUSIN)
|
||||||
{
|
{
|
||||||
/* Continue/resume processing the write requests */
|
/* Continue/resume processing the write requests. TXRDY will
|
||||||
|
* be disabled when the last transfer completes.
|
||||||
|
*/
|
||||||
|
|
||||||
privep->epstate = UDPHS_EPSTATE_IDLE;
|
privep->epstate = UDPHS_EPSTATE_IDLE;
|
||||||
(void)sam_req_write(priv, privep);
|
(void)sam_req_write(priv, privep);
|
||||||
@ -2422,11 +2435,20 @@ static void sam_ep_interrupt(struct sam_usbdev_s *priv, int epno)
|
|||||||
else if (privep->epstate == UDPHS_EPSTATE_EP0ADDRESS)
|
else if (privep->epstate == UDPHS_EPSTATE_EP0ADDRESS)
|
||||||
{
|
{
|
||||||
usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_ADDRESSED), priv->devaddr);
|
usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_ADDRESSED), priv->devaddr);
|
||||||
|
DEBUGASSERT(epno == EP0);
|
||||||
|
|
||||||
|
/* Set the device address */
|
||||||
|
|
||||||
sam_setdevaddr(priv, priv->devaddr);
|
sam_setdevaddr(priv, priv->devaddr);
|
||||||
|
|
||||||
|
/* Disable the further TXRDY interrupts on EP0. */
|
||||||
|
|
||||||
|
sam_putreg(UDPHS_EPTCTL_TXRDY, SAM_UDPHS_EPTCTLDIS(epno));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
usbtrace(TRACE_DEVERROR(SAM_TRACEERR_TXRDYERR), privep->epstate);
|
usbtrace(TRACE_DEVERROR(SAM_TRACEERR_TXRDYERR), privep->epstate);
|
||||||
|
sam_putreg(UDPHS_EPTCTL_TXRDY, SAM_UDPHS_EPTCTLDIS(epno));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2455,7 +2477,7 @@ static void sam_ep_interrupt(struct sam_usbdev_s *priv, int epno)
|
|||||||
|
|
||||||
/* Did we just receive the data associated with an OUT SETUP command? */
|
/* Did we just receive the data associated with an OUT SETUP command? */
|
||||||
|
|
||||||
else if (privep->epstate != UDPHS_EPSTATE_EP0DATAOUT)
|
else if (privep->epstate == UDPHS_EPSTATE_EP0DATAOUT)
|
||||||
{
|
{
|
||||||
uint16_t len;
|
uint16_t len;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user