From 9cfd924bbadfbf8501fde3a08545526d5d19a0b3 Mon Sep 17 00:00:00 2001 From: patacongo Date: Tue, 21 Aug 2012 18:13:35 +0000 Subject: Several bug fixes for STM32 OTG FS host driver git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@5043 42af7a65-404d-4744-a932-0658087f49c3 --- nuttx/arch/arm/src/stm32/chip/stm32_otgfs.h | 26 +- nuttx/arch/arm/src/stm32/stm32_otgfshost.c | 442 ++++++++++++++-------------- 2 files changed, 226 insertions(+), 242 deletions(-) (limited to 'nuttx') diff --git a/nuttx/arch/arm/src/stm32/chip/stm32_otgfs.h b/nuttx/arch/arm/src/stm32/chip/stm32_otgfs.h index f6966a598..ee34172cf 100644 --- a/nuttx/arch/arm/src/stm32/chip/stm32_otgfs.h +++ b/nuttx/arch/arm/src/stm32/chip/stm32_otgfs.h @@ -205,6 +205,10 @@ #define STM32_OTGFS_DOEPTSIZ2_OFFSET 0x00b50 /* Device OUT endpoint-2 transfer size register */ #define STM32_OTGFS_DOEPTSIZ3_OFFSET 0x00b70 /* Device OUT endpoint-3 transfer size register */ +/* Power and clock gating registers */ + +#define STM32_OTGFS_PCGCCTL_OFFSET 0x0e00 /* Power and clock gating control register */ + /* Data FIFO (DFIFO) access registers */ #define STM32_OTGFS_DFIFO_DEP_OFFSET(n) (0x1000 + ((n) << 12)) @@ -216,15 +220,11 @@ #define STM32_OTGFS_DFIFO_DEP1_OFFSET 0x2000 /* 0x2000-0x2ffc Device IN/OUT Endpoint 1 DFIFO Write/Read Access */ #define STM32_OTGFS_DFIFO_HCH1_OFFSET 0x2000 /* 0x2000-0x2ffc Host OUT/IN Channel 1 DFIFO Read/Write Access */ -#define STM32_OTGFS_DFIFO_DEP2_OFFSET 0x3000 /* 0x3000-0x3ffc Device IN/OUT Endpoint 1 DFIFO Write/Read Access */ -#define STM32_OTGFS_DFIFO_HCH2_OFFSET 0x3000 /* 0x3000-0x3ffc Host OUT/IN Channel 1 DFIFO Read/Write Access */ +#define STM32_OTGFS_DFIFO_DEP2_OFFSET 0x3000 /* 0x3000-0x3ffc Device IN/OUT Endpoint 2 DFIFO Write/Read Access */ +#define STM32_OTGFS_DFIFO_HCH2_OFFSET 0x3000 /* 0x3000-0x3ffc Host OUT/IN Channel 2 DFIFO Read/Write Access */ -#define STM32_OTGFS_DFIFO_DEP3_OFFSET 0x4000 /* 0x4000-0x4ffc Device IN/OUT Endpoint 1 DFIFO Write/Read Access */ -#define STM32_OTGFS_DFIFO_HCH3_OFFSET 0x4000 /* 0x4000-0x4ffc Host OUT/IN Channel 1 DFIFO Read/Write Access */ - -/* Power and clock gating registers */ - -#define STM32_OTGFS_PCGCCTL_OFFSET 0x0e00 /* Power and clock gating control register */ +#define STM32_OTGFS_DFIFO_DEP3_OFFSET 0x4000 /* 0x4000-0x4ffc Device IN/OUT Endpoint 3 DFIFO Write/Read Access */ +#define STM32_OTGFS_DFIFO_HCH3_OFFSET 0x4000 /* 0x4000-0x4ffc Host OUT/IN Channel 3 DFIFO Read/Write Access */ /* Register Addresses *******************************************************************************/ @@ -361,6 +361,10 @@ #define STM32_OTGFS_DOEPTSIZ2 (STM32_OTGFS_BASE+STM32_OTGFS_DOEPTSIZ2_OFFSET) #define STM32_OTGFS_DOEPTSIZ3 (STM32_OTGFS_BASE+STM32_OTGFS_DOEPTSIZ3_OFFSET) +/* Power and clock gating registers */ + +#define STM32_OTGFS_PCGCCTL (STM32_OTGFS_BASE+STM32_OTGFS_PCGCCTL_OFFSET) + /* Data FIFO (DFIFO) access registers */ #define STM32_OTGFS_DFIFO_DEP(n) (STM32_OTGFS_BASE+STM32_OTGFS_DFIFO_DEP_OFFSET(n)) @@ -378,10 +382,6 @@ #define STM32_OTGFS_DFIFO_DEP3 (STM32_OTGFS_BASE+STM32_OTGFS_DFIFO_DEP3_OFFSET) #define STM32_OTGFS_DFIFO_HCH3 (STM32_OTGFS_BASE+STM32_OTGFS_DFIFO_HCH3_OFFSET) -/* Power and clock gating registers */ - -#define STM32_OTGFS_PCGCCTL (STM32_OTGFS_BASE+STM32_OTGFS_PCGCCTL_OFFSET) - /* Register Bitfield Definitions ********************************************************************/ /* Core global control and status registers */ @@ -1006,8 +1006,6 @@ # define OTGFS_DOEPTSIZ_RXDPID_DATA1 (2 << OTGFS_DOEPTSIZ_RXDPID_SHIFT) # define OTGFS_DOEPTSIZ_RXDPID_MDATA (3 << OTGFS_DOEPTSIZ_RXDPID_SHIFT) /* Bit 31: Reserved, must be kept at reset value */ -/* Power and clock gating registers */ - /* Power and clock gating control register */ #define OTGFS_PCGCCTL_STPPCLK (1 << 0) /* Bit 0: Stop PHY clock */ diff --git a/nuttx/arch/arm/src/stm32/stm32_otgfshost.c b/nuttx/arch/arm/src/stm32/stm32_otgfshost.c index 398f2dff6..e6ea2de06 100644 --- a/nuttx/arch/arm/src/stm32/stm32_otgfshost.c +++ b/nuttx/arch/arm/src/stm32/stm32_otgfshost.c @@ -268,6 +268,7 @@ static int stm32_chan_alloc(FAR struct stm32_usbhost_s *priv); static inline void stm32_chan_free(FAR struct stm32_usbhost_s *priv, int chidx); static inline void stm32_chan_freeall(FAR struct stm32_usbhost_s *priv); static void stm32_chan_configure(FAR struct stm32_usbhost_s *priv, int chidx); +static void stm32_chan_halt(FAR struct stm32_usbhost_s *priv, int chidx); static int stm32_chan_waitsetup(FAR struct stm32_usbhost_s *priv, FAR struct stm32_chan_s *chan); static int stm32_chan_wait(FAR struct stm32_usbhost_s *priv, @@ -291,7 +292,6 @@ static int stm32_ctrl_recvdata(FAR struct stm32_usbhost_s *priv, static void stm32_gint_wrpacket(FAR struct stm32_usbhost_s *priv, FAR uint8_t *buffer, int chidx, int buflen); -static void stm32_gint_halttxchan(FAR struct stm32_usbhost_s *priv, int chidx); static inline void stm32_gint_hcinisr(FAR struct stm32_usbhost_s *priv, int chidx); static inline void stm32_gint_hcoutisr(FAR struct stm32_usbhost_s *priv, @@ -610,6 +610,13 @@ static int stm32_chan_alloc(FAR struct stm32_usbhost_s *priv) static void stm32_chan_free(FAR struct stm32_usbhost_s *priv, int chidx) { DEBUGASSERT((unsigned)chidx < STM32_NHOST_CHANNELS); + + /* Halt the channel */ + + stm32_chan_halt(priv, chidx); + + /* Mark the channel available */ + priv->chan[chidx].inuse = false; } @@ -625,11 +632,11 @@ static inline void stm32_chan_freeall(FAR struct stm32_usbhost_s *priv) { uint8_t chidx; - /* Clear address an "in-use" flag for all host channels */ + /* Free all host channels */ for (chidx = 2; chidx < STM32_NHOST_CHANNELS ; chidx ++) { - priv->chan[chidx].inuse = false; + stm32_chan_free(priv, chidx); } } @@ -753,6 +760,82 @@ static void stm32_chan_configure(FAR struct stm32_usbhost_s *priv, int chidx) stm32_putreg(STM32_OTGFS_HCCHAR(chidx), regval); } +/******************************************************************************* + * Name: stm32_chan_halt + * + * Description: + * Halt the channel associated with 'chidx' by setting the CHannel DISable + * (CHDIS) bit in in the HCCHAR register. + * + *******************************************************************************/ + +static void stm32_chan_halt(FAR struct stm32_usbhost_s *priv, int chidx) +{ + uint32_t hcchar; + uint32_t intmsk; + uint32_t eptype; + unsigned int avail; + + /* "The application can disable any channel by programming the OTG_FS_HCCHARx + * register with the CHDIS and CHENA bits set to 1. This enables the OTG_FS + * host to flush the posted requests (if any) and generates a channel halted + * interrupt. The application must wait for the CHH interrupt in OTG_FS_HCINTx + * before reallocating the channel for other transactions. The OTG_FS host + * does not interrupt the transaction that has already been started on the + * USB." + */ + + hcchar = stm32_getreg(STM32_OTGFS_HCCHAR(chidx)); + hcchar |= (OTGFS_HCCHAR_CHDIS | OTGFS_HCCHAR_CHENA); + + /* Get the endpoint type from the HCCHAR register */ + + eptype = (hcchar & OTGFS_HCCHAR_EPTYP_MASK); + + /* Check for space in the Tx FIFO to issue the halt. + * + * "Before disabling a channel, the application must ensure that there is at + * least one free space available in the non-periodic request queue (when + * disabling a non-periodic channel) or the periodic request queue (when + * disabling a periodic channel). The application can simply flush the + * posted requests when the Request queue is full (before disabling the + * channel), by programming the OTG_FS_HCCHARx register with the CHDIS bit + * set to 1, and the CHENA bit cleared to 0. + */ + + if (eptype == OTGFS_HCCHAR_EPTYP_CTRL || eptype == OTGFS_HCCHAR_EPTYP_BULK) + { + /* Get the number of words available in the non-periodic Tx FIFO. */ + + avail = stm32_getreg(STM32_OTGFS_HNPTXSTS) & OTGFS_HNPTXSTS_NPTXFSAV_MASK; + } + else /* if (eptype == OTGFS_HCCHAR_EPTYP_ISOC || eptype == OTGFS_HCCHAR_EPTYP_INTR) */ + { + /* Get the number of words available in the non-periodic Tx FIFO. */ + + avail = stm32_getreg(STM32_OTGFS_HPTXSTS) & OTGFS_HPTXSTS_PTXFSAVL_MASK; + } + + /* Check if there is any space available in the Tx FIFO. */ + + if (avail == 0) + { + /* The Tx FIFO is full... disable the channel to flush the requests */ + + hcchar &= ~OTGFS_HCCHAR_CHENA; + } + + /* Unmask the CHannel Halted (CHH) interrupt */ + + intmsk = stm32_getreg(STM32_OTGFS_HCINTMSK(chidx)); + intmsk |= OTGFS_HCINT_CHH; + stm32_putreg(STM32_OTGFS_HCINTMSK(chidx), intmsk); + + /* Halt the channel by setting CHDIS (and maybe CHENA) in the HCCHAR */ + + stm32_putreg(STM32_OTGFS_HCCHAR(chidx), hcchar); +} + /******************************************************************************* * Name: stm32_chan_waitsetup * @@ -891,49 +974,51 @@ static void stm32_transfer_start(FAR struct stm32_usbhost_s *priv, int chidx) priv->chan[chidx].xfrlen = 0; /* Compute the expected number of packets associated to the transfer. - * If it is a IN endpoint, then we need to round down to the number - * of full, maximally sized packets that can fit in the read buffer. + * If the transfer length is zero (or less than the size of one maximum + * size packet), then one packet is expected. */ - maxpacket = priv->chan[chidx].maxpacket; - if (priv->chan[chidx].in) - { - npackets = priv->chan[chidx].buflen / maxpacket; - - /* A read buffer must at least one max packet size in length */ - - DEBUGASSERT(npackets > 0); - - /* For the buffer length to an even multiple of maxpacket */ - - priv->chan[chidx].buflen = npackets * maxpacket; - } - - /* If it is an OUT endpoint, then we need round up to include any - * possible partial, final packet. + /* If the transfer size is greater than one packet, then xalculate the + * number of packets that will be received/sent, including any partial + * final packet. */ - else if (priv->chan[chidx].buflen > 0) + maxpacket = priv->chan[chidx].maxpacket; + + if (priv->chan[chidx].buflen > maxpacket) { npackets = (priv->chan[chidx].buflen + maxpacket - 1) / maxpacket; - } - /* Otherwise, we are sending a single zero-length packet */ + /* Clip if the buffer length if it exceeds the maximum number of + * packets that can be transferred (this should not happen). + */ + if (npackets > STM32_MAX_PKTCOUNT) + { + npackets = STM32_MAX_PKTCOUNT; + priv->chan[chidx].buflen = STM32_MAX_PKTCOUNT * maxpacket; + } + } else { + /* One packet will be sent/received (might be a zero length packet) */ + npackets = 1; } - /* Clip it the buffer length if it exceeds the maximum number of - * packets that can be transferred (this should not happen). + /* If it is an IN transfer, then adjust the size of the buffer UP to + * a full number of packets. Hmmm... couldn't this cause an overrun + * into unallocated memory? */ - if (npackets > STM32_MAX_PKTCOUNT) +#if 0 /* Think about this */ + if (priv->chan[chidx].in) { - npackets = STM32_MAX_PKTCOUNT; - priv->chan[chidx].buflen = STM32_MAX_PKTCOUNT * maxpacket; + /* Force the buffer length to an even multiple of maxpacket */ + + priv->chan[chidx].buflen = npackets * maxpacket; } +#endif /* Setup the HCTSIZn register */ @@ -957,8 +1042,8 @@ static void stm32_transfer_start(FAR struct stm32_usbhost_s *priv, int chidx) regval |= OTGFS_HCCHAR_CHENA; stm32_putreg(STM32_OTGFS_HCCHAR(chidx), regval); - /* If this is an out transfer, then we need to do more.. we need to copy the - * outgoing data into the correct TxFIFO. + /* If this is an out transfer, then we need to do more.. we need to copy + * the outgoing data into the correct TxFIFO. */ if (!priv->chan[chidx].in && priv->chan[chidx].buflen > 0) @@ -1016,11 +1101,11 @@ static void stm32_transfer_start(FAR struct stm32_usbhost_s *priv, int chidx) /* Write packet into the Tx FIFO. */ - stm32_gint_wrpacket(priv, priv->chan[chidx].buffer, chidx, priv->chan[chidx].buflen); + stm32_gint_wrpacket(priv, priv->chan[chidx].buffer, chidx, + priv->chan[chidx].buflen); } } - /******************************************************************************* * Name: stm32_getframe * @@ -1078,9 +1163,23 @@ static int stm32_ctrl_sendsetup(FAR struct stm32_usbhost_s *priv, /* Wait for the transfer to complete */ ret = stm32_chan_wait(priv, chan); + + /* Return on success and for all failures other than EAGAIN. EAGAIN + * means that the device NAKed the SETUP command and that we should + * try a few more times. + */ + if (ret != -EAGAIN) { - udbg("Transfer failed: %d\n", ret); + /* Output some debug information if the transfer failed */ + + if (ret < 0) + { + udbg("Transfer failed: %d\n", ret); + } + + /* Return the result in any event */ + return ret; } @@ -1217,61 +1316,6 @@ static void stm32_gint_wrpacket(FAR struct stm32_usbhost_s *priv, } } -/******************************************************************************* - * Name: stm32_gint_halttxchan - * - * Description: - * Halt the Tx channel associated with 'chidx' by setting the CHannel DISable - * (CHDIS) bit in in the HCCHAR register. - * - *******************************************************************************/ - -static void stm32_gint_halttxchan(FAR struct stm32_usbhost_s *priv, int chidx) -{ - uint32_t hcchar; - uint32_t eptype; - unsigned int avail; - - /* Prepare to set the CHannel DISable and the CHannel ENAble bits in the - * HCCHAR register. - */ - - hcchar = stm32_getreg(STM32_OTGFS_HCCHAR(chidx)); - hcchar |= (OTGFS_HCCHAR_CHDIS | OTGFS_HCCHAR_CHENA); - - /* Get the endpoint type from the HCCHAR register */ - - eptype = (hcchar & OTGFS_HCCHAR_EPTYP_MASK); - - /* Check for space in the Tx FIFO to issue the halt */ - - if (eptype == OTGFS_HCCHAR_EPTYP_CTRL || eptype == OTGFS_HCCHAR_EPTYP_BULK) - { - /* Get the number of words available in the non-periodic Tx FIFO. */ - - avail = stm32_getreg(STM32_OTGFS_HNPTXSTS) & OTGFS_HNPTXSTS_NPTXFSAV_MASK; - } - else /* if (eptype == OTGFS_HCCHAR_EPTYP_ISOC || eptype == OTGFS_HCCHAR_EPTYP_INTR) */ - { - /* Get the number of words available in the non-periodic Tx FIFO. */ - - avail = stm32_getreg(STM32_OTGFS_HPTXSTS) & OTGFS_HPTXSTS_PTXFSAVL_MASK; - } - - /* Check if there is any space available in the Tx FIFO. */ - - if (avail == 0) - { - /* The Tx FIFO is full... disable the channel */ - - hcchar &= ~OTGFS_HCCHAR_CHENA; - } - - /* Halt the channel by setting CHDIS in the HCCHAR */ - - stm32_putreg(STM32_OTGFS_HCCHAR(chidx), hcchar); -} - /******************************************************************************* * Name: stm32_gint_hcinisr * @@ -1314,31 +1358,26 @@ static inline void stm32_gint_hcinisr(FAR struct stm32_usbhost_s *priv, { /* Clear the pending the ACK response received/transmitted (ACK) interrupt */ - hcint &= ~OTGFS_HCINT_ACK; - stm32_putreg(STM32_OTGFS_HCINT(chidx), hcint); + stm32_putreg(STM32_OTGFS_HCINT(chidx), OTGFS_HCINT_ACK); } /* Check for a pending STALL response receive (STALL) interrupt */ else if ((pending & OTGFS_HCINT_STALL) != 0) { - /* Unmask the CHannel Halted (CHH) interrupt */ - - hcintmsk |= OTGFS_HCINT_CHH; - stm32_putreg(STM32_OTGFS_HCINTMSK(chidx), hcintmsk); - /* Set the stall state */ chan->chstate = CHSTATE_STALL; /* Clear the NAK and STALL Conditions. */ - hcint &= ~(OTGFS_HCINT_NAK | OTGFS_HCINT_STALL); - stm32_putreg(STM32_OTGFS_HCINT(chidx), hcint); + stm32_putreg(STM32_OTGFS_HCINT(chidx), (OTGFS_HCINT_NAK | OTGFS_HCINT_STALL)); - /* Halt the Tx channel */ + /* Halt the channel when a STALL, TXERR, BBERR or DTERR interrupt is + * received on the channel. + */ - stm32_gint_halttxchan(priv, chidx); + stm32_chan_halt(priv, chidx); /* When there is a STALL, clear any pending NAK so that it is nor * processed below. @@ -1351,19 +1390,15 @@ static inline void stm32_gint_hcinisr(FAR struct stm32_usbhost_s *priv, else if ((pending & OTGFS_HCINT_DTERR) != 0) { - /* Unmask the CHannel Halted (CHH) interrupt */ - - hcintmsk |= OTGFS_HCINT_CHH; - stm32_putreg(STM32_OTGFS_HCINTMSK(chidx), hcintmsk); - - /* Halt the Tx channel */ + /* Halt the channel when a STALL, TXERR, BBERR or DTERR interrupt is + * received on the channel. + */ - stm32_gint_halttxchan(priv, chidx); + stm32_chan_halt(priv, chidx); /* Clear the NAK and data toggle error conditions */ - hcint &= ~(OTGFS_HCINT_NAK | OTGFS_HCINT_DTERR); - stm32_putreg(STM32_OTGFS_HCINT(chidx), hcint); + stm32_putreg(STM32_OTGFS_HCINT(chidx), (OTGFS_HCINT_NAK | OTGFS_HCINT_DTERR)); /* Set the Data Toggle ERRor (DTERR) state */ @@ -1374,51 +1409,38 @@ static inline void stm32_gint_hcinisr(FAR struct stm32_usbhost_s *priv, if ((pending & OTGFS_HCINT_FRMOR) != 0) { - /* Unmask the CHannel Halted (CHH) interrupt */ - - hcintmsk |= OTGFS_HCINT_CHH; - stm32_putreg(STM32_OTGFS_HCINTMSK(chidx), hcintmsk); - - /* Halt the Tx channel */ + /* Halt the channel (probably not necessary for FRMOR) */ - stm32_gint_halttxchan(priv, chidx); + stm32_chan_halt(priv, chidx); /* Clear the FRaMe OverRun (FRMOR) condition */ - hcint &= ~OTGFS_HCINT_FRMOR; - stm32_putreg(STM32_OTGFS_HCINT(chidx), hcint); + stm32_putreg(STM32_OTGFS_HCINT(chidx), OTGFS_HCINT_FRMOR); } /* Check for a pending TransFeR Completed (XFRC) interrupt */ else if ((pending & OTGFS_HCINT_XFRC) != 0) { - /* Set the trnansfer complete state and reset the error count */ + /* Set the transfer complete state and reset the error count */ chan->chstate = CHSTATE_XFRC; chan->nerrors = 0; /* Clear the TransFeR Completed (XFRC) condition */ - hcint &= ~OTGFS_HCINT_XFRC; - stm32_putreg(STM32_OTGFS_HCINT(chidx), hcint); + stm32_putreg(STM32_OTGFS_HCINT(chidx), OTGFS_HCINT_XFRC); if ((eptype == OTGFS_HCCHAR_EPTYP_CTRL) || (eptype == OTGFS_HCCHAR_EPTYP_BULK)) { - /* Unmask the CHannel Halted (CHH) interrupt */ - - hcintmsk |= OTGFS_HCINT_CHH; - stm32_putreg(STM32_OTGFS_HCINTMSK(chidx), hcintmsk); + /* Halt the channel ( probably not necessary for XFRC) */ - /* Halt the Tx channel */ - - stm32_gint_halttxchan(priv, chidx); + stm32_chan_halt(priv, chidx); /* Clear any pending NAK condition */ - hcint &= ~OTGFS_HCINT_NAK; - stm32_putreg(STM32_OTGFS_HCINT(chidx), hcint); + stm32_putreg(STM32_OTGFS_HCINT(chidx), OTGFS_HCINT_NAK); /* Toggle the IN data state */ @@ -1443,6 +1465,7 @@ static inline void stm32_gint_hcinisr(FAR struct stm32_usbhost_s *priv, { /* Mask the CHannel Halted (CHH) interrupt */ + hcintmsk = stm32_getreg(STM32_OTGFS_HCINTMSK(chidx)); hcintmsk &= ~OTGFS_HCINT_CHH; stm32_putreg(STM32_OTGFS_HCINTMSK(chidx), hcintmsk); @@ -1478,32 +1501,27 @@ static inline void stm32_gint_hcinisr(FAR struct stm32_usbhost_s *priv, /* Clear the CHannel Halted (CHH) condition */ - hcint &= ~OTGFS_HCINT_CHH; - stm32_putreg(STM32_OTGFS_HCINT(chidx), hcint); + stm32_putreg(STM32_OTGFS_HCINT(chidx), OTGFS_HCINT_CHH); } /* Check for a pending Transaction ERror (TXERR) interrupt */ else if ((pending & OTGFS_HCINT_TXERR) != 0) { - /* Unmask the CHannel Halted (CHH) interrupt */ - - hcintmsk |= OTGFS_HCINT_CHH; - stm32_putreg(STM32_OTGFS_HCINTMSK(chidx), hcintmsk); - /* Increment the error count and set the transaction error state */ chan->nerrors++; chan->chstate = CHSTATE_TXERR; - /* Halt the Tx channel */ + /* Halt the channel when a STALL, TXERR, BBERR or DTERR interrupt is + * received on the channel. + */ - stm32_gint_halttxchan(priv, chidx); + stm32_chan_halt(priv, chidx); /* Clear the Transaction ERror (TXERR) condition */ - hcint &= ~OTGFS_HCINT_TXERR; - stm32_putreg(STM32_OTGFS_HCINT(chidx), hcint); + stm32_putreg(STM32_OTGFS_HCINT(chidx), OTGFS_HCINT_TXERR); } /* Check for a pending NAK response received (NAK) interrupt */ @@ -1514,14 +1532,9 @@ static inline void stm32_gint_hcinisr(FAR struct stm32_usbhost_s *priv, if (eptype == OTGFS_HCCHAR_EPTYP_INTR) { - /* Unmask the CHannel Halted (CHH) interrupt */ - - hcintmsk |= OTGFS_HCINT_CHH; - stm32_putreg(STM32_OTGFS_HCINTMSK(chidx), hcintmsk); + /* Halt the channel (probably not necessary on NAK) */ - /* Halt the Tx channel */ - - stm32_gint_halttxchan(priv, chidx); + stm32_chan_halt(priv, chidx); } else if ((eptype == OTGFS_HCCHAR_EPTYP_CTRL) || (eptype == OTGFS_HCCHAR_EPTYP_BULK)) @@ -1541,8 +1554,7 @@ static inline void stm32_gint_hcinisr(FAR struct stm32_usbhost_s *priv, /* Clear the NAK condition */ - hcint &= ~OTGFS_HCINT_NAK; - stm32_putreg(STM32_OTGFS_HCINT(chidx), hcint); + stm32_putreg(STM32_OTGFS_HCINT(chidx), OTGFS_HCINT_NAK); } /* Check for a transfer complete event */ @@ -1584,27 +1596,20 @@ static inline void stm32_gint_hcoutisr(FAR struct stm32_usbhost_s *priv, { /* Clear the pending the ACK response received/transmitted (ACK) interrupt */ - hcint &= ~OTGFS_HCINT_ACK; - stm32_putreg(STM32_OTGFS_HCINT(chidx), hcint); + stm32_putreg(STM32_OTGFS_HCINT(chidx), OTGFS_HCINT_ACK); } /* Check for a pending FRaMe OverRun (FRMOR) interrupt */ else if ((pending & OTGFS_HCINT_FRMOR) != 0) { - /* Unmask the CHannel Halted (CHH) interrupt */ - - hcintmsk |= OTGFS_HCINT_CHH; - stm32_putreg(STM32_OTGFS_HCINTMSK(chidx), hcintmsk); + /* Halt the channel (probably not necessary for FRMOR) */ - /* Halt the Tx channel */ - - stm32_gint_halttxchan(priv, chidx); + stm32_chan_halt(priv, chidx); /* Clear the pending the FRaMe OverRun (FRMOR) interrupt */ - hcint &= ~OTGFS_HCINT_FRMOR; - stm32_putreg(STM32_OTGFS_HCINT(chidx), hcint); + stm32_putreg(STM32_OTGFS_HCINT(chidx), OTGFS_HCINT_FRMOR); } /* Check for a pending TransFeR Completed (XFRC) interrupt */ @@ -1613,19 +1618,13 @@ static inline void stm32_gint_hcoutisr(FAR struct stm32_usbhost_s *priv, { chan->nerrors = 0; - /* Unmask the CHannel Halted (CHH) interrupt */ - - hcintmsk |= OTGFS_HCINT_CHH; - stm32_putreg(STM32_OTGFS_HCINTMSK(chidx), hcintmsk); - - /* Halt the Tx channel */ + /* Halt the channel (shouldn't be necessary on XFRC) */ - stm32_gint_halttxchan(priv, chidx); + stm32_chan_halt(priv, chidx); /* Clear the pending the TransFeR Completed (XFRC) interrupt */ - hcint &= ~OTGFS_HCINT_XFRC; - stm32_putreg(STM32_OTGFS_HCINT(chidx), hcint); + stm32_putreg(STM32_OTGFS_HCINT(chidx), OTGFS_HCINT_XFRC); /* Set the transfer completed state */ @@ -1638,17 +1637,13 @@ static inline void stm32_gint_hcoutisr(FAR struct stm32_usbhost_s *priv, { /* Clear the pending the STALL response receiv (STALL) interrupt */ - hcint &= ~OTGFS_HCINT_STALL; - stm32_putreg(STM32_OTGFS_HCINT(chidx), hcint); - - /* Unmask the CHannel Halted (CHH) interrupt */ - - hcintmsk |= OTGFS_HCINT_CHH; - stm32_putreg(STM32_OTGFS_HCINTMSK(chidx), hcintmsk); + stm32_putreg(STM32_OTGFS_HCINT(chidx), OTGFS_HCINT_STALL); - /* Halt the Tx channel */ + /* Halt the channel when a STALL, TXERR, BBERR or DTERR interrupt is + * received on the channel. + */ - stm32_gint_halttxchan(priv, chidx); + stm32_chan_halt(priv, chidx); /* Set the stall state */ @@ -1663,19 +1658,13 @@ static inline void stm32_gint_hcoutisr(FAR struct stm32_usbhost_s *priv, chan->nerrors = 0; - /* Unmask the CHannel Halted (CHH) interrupt */ - - hcintmsk |= OTGFS_HCINT_CHH; - stm32_putreg(STM32_OTGFS_HCINTMSK(chidx), hcintmsk); - - /* Halt the Tx channel */ + /* Halt the channel (probably not necessary on NAK) */ - stm32_gint_halttxchan(priv, chidx); + stm32_chan_halt(priv, chidx); /* Clear the pending the NAK response received (NAK) interrupt */ - hcint &= ~OTGFS_HCINT_NAK; - stm32_putreg(STM32_OTGFS_HCINT(chidx), hcint); + stm32_putreg(STM32_OTGFS_HCINT(chidx), OTGFS_HCINT_NAK); /* Set the NAK state */ @@ -1686,14 +1675,11 @@ static inline void stm32_gint_hcoutisr(FAR struct stm32_usbhost_s *priv, else if ((pending & OTGFS_HCINT_TXERR) != 0) { - /* Unmask the CHannel Halted (CHH) interrupt */ - - hcintmsk |= OTGFS_HCINT_CHH; - stm32_putreg(STM32_OTGFS_HCINTMSK(chidx), hcintmsk); - - /* Halt the Tx channel */ + /* Halt the channel when a STALL, TXERR, BBERR or DTERR interrupt is + * received on the channel. + */ - stm32_gint_halttxchan(priv, chidx); + stm32_chan_halt(priv, chidx); /* Increment the number of errors */ @@ -1705,8 +1691,7 @@ static inline void stm32_gint_hcoutisr(FAR struct stm32_usbhost_s *priv, /* Clear the pending the Transaction ERror (TXERR) interrupt */ - hcint &= ~OTGFS_HCINT_TXERR; - stm32_putreg(STM32_OTGFS_HCINT(chidx), hcint); + stm32_putreg(STM32_OTGFS_HCINT(chidx), OTGFS_HCINT_TXERR); } /* Check for a pending response received (xxx) interrupt */ @@ -1716,19 +1701,13 @@ static inline void stm32_gint_hcoutisr(FAR struct stm32_usbhost_s *priv, { chan->nerrors = 0; - /* Unmask the CHannel Halted (CHH) interrupt */ - - hcintmsk |= OTGFS_HCINT_CHH; - stm32_putreg(STM32_OTGFS_HCINTMSK(chidx), hcintmsk); - - /* Halt the Tx channel */ + /* Halt the channel */ - stm32_gint_halttxchan(priv, chidx); + stm32_chan_halt(priv, chidx); /* Clear the pending the response received (xxx) interrupt */ - hcint &= ~OTGFS_HCINT_NYET; - stm32_putreg(STM32_OTGFS_HCINT(chidx), hcint); + stm32_putreg(STM32_OTGFS_HCINT(chidx), OTGFS_HCINT_NYET); /* Set the NYET state */ @@ -1740,14 +1719,11 @@ static inline void stm32_gint_hcoutisr(FAR struct stm32_usbhost_s *priv, else if (pending & OTGFS_HCINT_DTERR) { - /* Unmask the CHannel Halted (CHH) interrupt */ - - hcintmsk |= OTGFS_HCINT_CHH; - stm32_putreg(STM32_OTGFS_HCINTMSK(chidx), hcintmsk); - - /* Halt the Tx channel */ + /* Halt the channel when a STALL, TXERR, BBERR or DTERR interrupt is + * received on the channel. + */ - stm32_gint_halttxchan(priv, chidx); + stm32_chan_halt(priv, chidx); /* Set the data toggle error state */ @@ -1755,8 +1731,7 @@ static inline void stm32_gint_hcoutisr(FAR struct stm32_usbhost_s *priv, /* Clear the pending the Data Toggle ERRor (DTERR) and NAK interrupts */ - hcint &= ~(OTGFS_HCINT_DTERR | OTGFS_HCINT_NAK); - stm32_putreg(STM32_OTGFS_HCINT(chidx), hcint); + stm32_putreg(STM32_OTGFS_HCINT(chidx), (OTGFS_HCINT_DTERR | OTGFS_HCINT_NAK)); } /* Check for a pending CHannel Halted (CHH) interrupt */ @@ -1765,6 +1740,7 @@ static inline void stm32_gint_hcoutisr(FAR struct stm32_usbhost_s *priv, { /* Mask the CHannel Halted (CHH) interrupt */ + hcintmsk = stm32_getreg(STM32_OTGFS_HCINTMSK(chidx)); hcintmsk &= ~OTGFS_HCINT_CHH; stm32_putreg(STM32_OTGFS_HCINTMSK(chidx), hcintmsk); @@ -1815,8 +1791,7 @@ static inline void stm32_gint_hcoutisr(FAR struct stm32_usbhost_s *priv, /* Clear the pending the CHannel Halted (CHH) interrupt */ - hcint &= ~OTGFS_HCINT_CHH; - stm32_putreg(STM32_OTGFS_HCINT(chidx), hcint); + stm32_putreg(STM32_OTGFS_HCINT(chidx), OTGFS_HCINT_CHH); } /* Check for a transfer complete event */ @@ -2408,15 +2383,28 @@ static int stm32_gint_isr(int irq, FAR void *context) * host mode */ - /* Get the unmasked bits in the GINT status */ + /* Loop while there are pending interrupts to process. This loop may save a + * little interrupt handling overhead. + */ + + for (;;) + { + /* Get the unmasked bits in the GINT status */ - pending = stm32_getreg(STM32_OTGFS_GINTSTS); - pending &= stm32_getreg(STM32_OTGFS_GINTMSK); + pending = stm32_getreg(STM32_OTGFS_GINTSTS); + pending &= stm32_getreg(STM32_OTGFS_GINTMSK); - /* The process each pending, unmasked GINT interrupts */ + /* Return from the interrupt when there are no furhter pending + * interrupts. + */ + + if (pending == 0) + { + return OK; + } + + /* Otherwise, process each pending, unmasked GINT interrupts */ - if (pending != 0) - { ullvdbg("GINTSTS: %08x\n", pending); /* Handle the start of frame interrupt */ @@ -2478,6 +2466,8 @@ static int stm32_gint_isr(int irq, FAR void *context) } } + /* We won't get here */ + return OK; } @@ -2919,11 +2909,7 @@ static int stm32_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) stm32_takesem(&priv->exclsem); - /* Halt the channel */ - - stm32_gint_halttxchan(priv, chidx); - - /* Mark the channel avaiable */ + /* Halt the channel and mark the channel avaiable */ stm32_chan_free(priv, chidx); -- cgit v1.2.3