From 8c92beb70e5bdc7fd56f20cb88ffe3e0144af14e Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Thu, 29 Aug 2013 17:34:05 -0600 Subject: [PATCH] SAMA5 UDPHS interrupt decoding logic --- arch/arm/src/sama5/chip/sam_udphs.h | 54 +++--- arch/arm/src/sama5/sam_udphs.c | 278 +++++++++++++++------------- 2 files changed, 178 insertions(+), 154 deletions(-) diff --git a/arch/arm/src/sama5/chip/sam_udphs.h b/arch/arm/src/sama5/chip/sam_udphs.h index 9e90cc9633..c205945ef9 100644 --- a/arch/arm/src/sama5/chip/sam_udphs.h +++ b/arch/arm/src/sama5/chip/sam_udphs.h @@ -220,31 +220,35 @@ /* UDPHS Interrupt Enable Register and UDPHS Interrupt Status Register */ -#define UDPHS_IEN_EPT(ep) (1 << +((ep)+8)) /* Endpoint ep Interrupt */ -# define UDPHS_IEN_EPT0 (1 << 8) /* Bit 8: Endpoint 0 Interrupt */ -# define UDPHS_IEN_EPT1 (1 << 9) /* Bit 9: Endpoint 1 Interrupt */ -# define UDPHS_IEN_EPT2 (1 << 10) /* Bit 0: Endpoint 2 Interrupt */ -# define UDPHS_IEN_EPT3 (1 << 11) /* Bit 1: Endpoint 3 Interrupt */ -# define UDPHS_IEN_EPT4 (1 << 12) /* Bit 2: Endpoint 4 Interrupt */ -# define UDPHS_IEN_EPT5 (1 << 13) /* Bit 3: Endpoint 5 Interrupt */ -# define UDPHS_IEN_EPT6 (1 << 14) /* Bit 4: Endpoint 6 Interrupt */ -# define UDPHS_IEN_EPT7 (1 << 15) /* Bit 5: Endpoint 7 Interrupt */ -# define UDPHS_IEN_EPT8 (1 << 16) /* Bit 6: Endpoint 8 Interrupt */ -# define UDPHS_IEN_EPT9 (1 << 17) /* Bit 7: Endpoint 9 Interrupt */ -# define UDPHS_IEN_EPT10 (1 << 18) /* Bit 8: Endpoint 10 Interrupt */ -# define UDPHS_IEN_EPT11 (1 << 19) /* Bit 9: Endpoint 11 Interrupt */ -# define UDPHS_IEN_EPT12 (1 << 20) /* Bit 0: Endpoint 12 Interrupt */ -# define UDPHS_IEN_EPT13 (1 << 21) /* Bit 1: Endpoint 13 Interrupt */ -# define UDPHS_IEN_EPT14 (1 << 22) /* Bit 2: Endpoint 14 Interrupt */ -# define UDPHS_IEN_EPT15 (1 << 23) /* Bit 3: Endpoint 15 Interrupt */ -#define UDPHS_IEN_DMA(ch) (1 << ((ch)+24) /* DMA Channel ch Interrupt */ -# define UDPHS_IEN_DMA1 (1 << 25) /* Bit 5: DMA Channel 1 Interrupt */ -# define UDPHS_IEN_DMA2 (1 << 26) /* Bit 6: DMA Channel 2 Interrupt */ -# define UDPHS_IEN_DMA3 (1 << 27) /* Bit 7: DMA Channel 3 Interrupt */ -# define UDPHS_IEN_DMA4 (1 << 28) /* Bit 8: DMA Channel 4 Interrupt */ -# define UDPHS_IEN_DMA5 (1 << 29) /* Bit 9: DMA Channel 5 Interrupt */ -# define UDPHS_IEN_DMA6 (1 << 30) /* Bit 0: DMA Channel 6 Interrupt */ -# define UDPHS_IEN_DMA7 (1 << 31) /* Bit 1: DMA Channel 7 Interrupt */ +#define UDPHS_INT_EPT_SHIFT (8) /* Bits 8-23: Endpoint interrupts */ +#define UDPHS_INT_EPT_MASK (0xffff << UDPHS_INT_EPT_SHIFT) +#define UDPHS_INT_EPT(ep) (1 << +((ep)+8)) /* Endpoint ep Interrupt */ +# define UDPHS_INT_EPT0 (1 << 8) /* Bit 8: Endpoint 0 Interrupt */ +# define UDPHS_INT_EPT1 (1 << 9) /* Bit 9: Endpoint 1 Interrupt */ +# define UDPHS_INT_EPT2 (1 << 10) /* Bit 10: Endpoint 2 Interrupt */ +# define UDPHS_INT_EPT3 (1 << 11) /* Bit 11: Endpoint 3 Interrupt */ +# define UDPHS_INT_EPT4 (1 << 12) /* Bit 12: Endpoint 4 Interrupt */ +# define UDPHS_INT_EPT5 (1 << 13) /* Bit 13: Endpoint 5 Interrupt */ +# define UDPHS_INT_EPT6 (1 << 14) /* Bit 14: Endpoint 6 Interrupt */ +# define UDPHS_INT_EPT7 (1 << 15) /* Bit 15: Endpoint 7 Interrupt */ +# define UDPHS_INT_EPT8 (1 << 16) /* Bit 16: Endpoint 8 Interrupt */ +# define UDPHS_INT_EPT9 (1 << 17) /* Bit 17: Endpoint 9 Interrupt */ +# define UDPHS_INT_EPT10 (1 << 18) /* Bit 18: Endpoint 10 Interrupt */ +# define UDPHS_INT_EPT11 (1 << 19) /* Bit 19: Endpoint 11 Interrupt */ +# define UDPHS_INT_EPT12 (1 << 20) /* Bit 20: Endpoint 12 Interrupt */ +# define UDPHS_INT_EPT13 (1 << 21) /* Bit 21: Endpoint 13 Interrupt */ +# define UDPHS_INT_EPT14 (1 << 22) /* Bit 22: Endpoint 14 Interrupt */ +# define UDPHS_INT_EPT15 (1 << 23) /* Bit 23: Endpoint 15 Interrupt */ +#define UDPHS_INT_DMA_SHIFT (25) /* Bits 25-31: Endpoint interrupts */ +#define UDPHS_INT_DMA_MASK (0x7f << UDPHS_INT_DMA_SHIFT) +#define UDPHS_INT_DMA(ch) (1 << ((ch)+24) /* DMA Channel ch Interrupt */ +# define UDPHS_INT_DMA1 (1 << 25) /* Bit 25: DMA Channel 1 Interrupt */ +# define UDPHS_INT_DMA2 (1 << 26) /* Bit 26: DMA Channel 2 Interrupt */ +# define UDPHS_INT_DMA3 (1 << 27) /* Bit 27: DMA Channel 3 Interrupt */ +# define UDPHS_INT_DMA4 (1 << 28) /* Bit 28: DMA Channel 4 Interrupt */ +# define UDPHS_INT_DMA5 (1 << 29) /* Bit 29: DMA Channel 5 Interrupt */ +# define UDPHS_INT_DMA6 (1 << 30) /* Bit 30: DMA Channel 6 Interrupt */ +# define UDPHS_INT_DMA7 (1 << 31) /* Bit 31: DMA Channel 7 Interrupt */ /* UDPHS Endpoints Reset Register */ diff --git a/arch/arm/src/sama5/sam_udphs.c b/arch/arm/src/sama5/sam_udphs.c index 0cc05a75f5..4fde302ddc 100644 --- a/arch/arm/src/sama5/sam_udphs.c +++ b/arch/arm/src/sama5/sam_udphs.c @@ -441,9 +441,9 @@ static void sam_ep0setup(struct sam_usbdev_s *priv); static void sam_ep0out(struct sam_usbdev_s *priv); static void sam_ep0in(struct sam_usbdev_s *priv); static inline void - sam_ep0done(struct sam_usbdev_s *priv, uint16_t istr); + sam_ep0done(struct sam_usbdev_s *priv, uint16_t intsta); static void sam_lptransfer(struct sam_usbdev_s *priv); -static int sam_uhphs_interrupt(int irq, void *context); +static int sam_udphs_interrupt(int irq, void *context); /* Endpoint helpers *********************************************************/ @@ -688,7 +688,7 @@ static void sam_dumpep(struct sam_usbdev_s *priv, int epno) /* Common registers */ lldbg("CNTR: %04x\n", getreg16(SAM_USB_CNTR)); - lldbg("ISTR: %04x\n", getreg16(SAM_USB_ISTR)); + lldbg("ISTR: %04x\n", getreg16(SAM_UDPHS_INTSTA)); lldbg("FNR: %04x\n", getreg16(SAM_USB_FNR)); lldbg("DADDR: %04x\n", getreg16(SAM_USB_DADDR)); lldbg("BTABLE: %04x\n", getreg16(SAM_USB_BTABLE)); @@ -1741,7 +1741,7 @@ static void sam_ep0out(struct sam_usbdev_s *priv) * Name: sam_ep0done ****************************************************************************/ -static inline void sam_ep0done(struct sam_usbdev_s *priv, uint32_t istr) +static inline void sam_ep0done(struct sam_usbdev_s *priv, uint32_t intsta) { uint32_t epr; @@ -1762,11 +1762,11 @@ static inline void sam_ep0done(struct sam_usbdev_s *priv, uint32_t istr) * packet sent to or received from the host PC. */ - if ((istr & USB_ISTR_DIR) == 0) + if ((intsta & USB_ISTR_DIR) == 0) { /* EP0 IN: device-to-host (DIR=0) */ - usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_EP0IN), istr); + usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_EP0IN), intsta); sam_clrepctrtx(EP0); sam_ep0in(priv); } @@ -1867,23 +1867,23 @@ static inline void sam_ep0done(struct sam_usbdev_s *priv, uint32_t istr) static void sam_lptransfer(struct sam_usbdev_s *priv) { uint8_t epno; - uint32_t istr; + uint32_t intsta; /* Stay in loop while LP interrupts are pending */ - while (((istr = sam_getreg(SAM_USB_ISTR)) & USB_ISTR_CTR) != 0) + while (((intsta = sam_getreg(SAM_UDPHS_INTSTA)) & USB_ISTR_CTR) != 0) { - sam_putreg((uint32_t)~USB_ISTR_CTR, SAM_USB_ISTR); + sam_putreg((uint32_t)~USB_ISTR_CTR, SAM_UDPHS_INTSTA); /* Extract highest priority endpoint number */ - epno = (uint8_t)(istr & USB_ISTR_EPID_MASK); + epno = (uint8_t)(intsta & USB_ISTR_EPID_MASK); /* Handle EP0 completion events */ if (epno == 0) { - sam_ep0done(priv, istr); + sam_ep0done(priv, intsta); } /* Handle other endpoint completion events */ @@ -1896,118 +1896,154 @@ static void sam_lptransfer(struct sam_usbdev_s *priv) } /**************************************************************************** - * Name: sam_uhphs_interrupt + * Name: sam_udphs_interrupt ****************************************************************************/ -static int sam_uhphs_interrupt(int irq, void *context) +static int sam_udphs_interrupt(int irq, void *context) { /* For now there is only one USB controller, but we will always refer to - * it using a pointer to make any future ports to multiple USB controllers + * it using a pointer to make any future ports to multiple UDPHS controllers * easier. */ struct sam_usbdev_s *priv = &g_usbdev; - uint32_t istr; - uint8_t epno; + uint32_t intsta; + uint32_t ien; + uint32_t pending; + int i; - /* Handle correct transfer event for isochronous and double-buffer bulk transfers. */ + /* Get the set of pending interrupts */ - istr = sam_getreg(SAM_USB_ISTR); - usbtrace(TRACE_INTENTRY(SAM_TRACEINTID_INTERRUPT), istr); - while ((istr & USB_ISTR_CTR) != 0) - { - sam_putreg((uint32_t)~USB_ISTR_CTR, SAM_USB_ISTR); - - /* Extract highest priority endpoint number */ + intsta = sam_getreg(SAM_UDPHS_INTSTA); + usbtrace(TRACE_INTENTRY(SAM_TRACEINTID_INTERRUPT), intsta); - epno = (uint8_t)(istr & USB_ISTR_EPID_MASK); + inten = sam_getreg(SAM_UDPHS_IEN); + pending = insta & inten; - /* And handle the completion event */ - - sam_epdone(priv, epno); - - /* Fetch the status again for the next time through the loop */ - - istr = sam_getreg(SAM_USB_ISTR); - } - - /* Handle Reset interrupts. When this event occurs, the peripheral is left - * in the same conditions it is left by the system reset (but with the - * USB controller enabled). + /* Handle all pending UDPHS interrupts (and new interrupts that become + * pending) */ - if ((istr & USB_ISTR_RESET) != 0) + while (pending) { - /* Reset interrupt received. Clear the RESET interrupt status. */ + usbtrace(TRACE_INTENTRY(SAM_TRACEINTID_INTERRUPT), intsta); - sam_putreg(~USB_ISTR_RESET, SAM_USB_ISTR); - usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_RESET), istr); + /* Suspend, treated last */ - /* Restore our power-up state and exit now because istr is no longer - * valid. - */ + if ((pending == UDPHS_INT_DETSUSPD) != 0) + { + usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_DETSUSPD), (uint16_t)pending); - sam_reset(priv); - goto exit_lpinterrupt; + /* Enable wakeup interrupts */ + + regval = inten; + regval &= ~UDPHS_INT_DETSUSPD; + regval |= (UDPHS_INT_WAKEUP | UDPHS_INT_ENDOFRSM); + sam_putreg(regval, SAM_UDPHS_IEN); + + /* Acknowledge interrupt */ + + sam_putreg(UDPHS_INT_DETSUSPD | UDPHS_INT_WAKEUP, SAM_UDPHS_CLRINT); + sam_suspend(priv); + } + + /* SOF interrupt*/ + + else if ((pending & UDPHS_INT_INTSOF) != 0) + { + /* Acknowledge interrupt */ + + usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_INTSOF), (uint16_t)pending); + sam_putreg(UDPHS_INT_INTSOF, SAM_UDPHS_CLRINT); + } + + /* Resume */ + + else if ((pending & UDPHS_INT_WAKEUP) != 0 || + (pending & UDPHS_INT_ENDOFRSM) != 0) + { + usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_WAKEUP), (uint16_t)pending); + sam_resume(priv); + + /* Acknowledge interrupt */ + + sam_putreg(UDPHS_INT_WAKEUP | UDPHS_INT_ENDOFRSM | UDPHS_INT_DETSUSPD, + SAM_UDPHS_CLRINT); + + /* Enable suspend interrupts */ + + inten &= ~UDPHS_INT_WAKEUP; + inten |= (UDPHS_INT_ENDOFRSM | UDPHS_INT_DETSUSPD); + sam_putreg(inten, SAM_UDPHS_IEN); + } + + /* Bus reset */ + + if ((pending & UDPHS_INT_ENDRESET) != 0) + { + usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_ENDRESET), (uint16_t)pending); + + /* Clear and enable the suspend interrupt */ + + sam_putreg(UDPHS_INT_WAKEUP | UDPHS_INT_DETSUSPD, SAM_UDPHS_CLRINT); + + inten |= UDPHS_INT_DETSUSPD; + sam_putreg(inten, SAM_UDPHS_IEN); + + /* Handle the reset */ + + sam_reset(); + + /* Acknowledge the interrupt */ + + sam_putreg(UDPHS_INT_ENDRESET, SAM_UDPHS_CLRINT); + } + + /* Upstream resume */ + + else if ((pending & UDPHS_INT_UPSTRRES) != 0) + { + /* Acknowledge interrupt */ + + usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_UPSTRRES), (uint16_t)pending); + sam_putreg(UDPHS_INT_ENDRESET, SAM_UDPHS_CLRINT); + pUdp->UDPHS_CLRINT = UDPHS_INT_UPSTRRES; + } + + /* DMA interrupts */ + + if ((pending & UDPHS_INT_DMA_MASK) != 0) + { + for (i = 1; i <= SAM_UDPHS_NDMACHANNELS; i++) + { + if ((pending & UDPHS_INT_DMA(i)) != 0) + { + sam_dma_interrupt(priv, i); + } + } + } + + /* Endpoint Interrupts */ + + if ((pending & UDPHS_INT_EPT_MASK) != 0) + { + for (i = 1; i <= SAM_UDPHS_NENDPOINTS; i++) + { + if ((pending & UDPHS_INT_EPT(i)) != 0) + { + sam_ep_interrupt(priv, i); + } + } + } + + /* Re-sample the set of pending interrupts */ + + intsta = sam_getreg(SAM_UDPHS_INTSTA); + inten = sam_getreg(SAM_UDPHS_IEN); + pending = insta & inten; } - /* Handle Wakeup interrupts. This interrupt is only enable while the USB is - * suspended. - */ - - if ((istr & USB_ISTR_WKUP & priv->imask) != 0) - { - /* Wakeup interrupt received. Clear the WKUP interrupt status. The - * cause of the resume is indicated in the FNR register - */ - - sam_putreg(~USB_ISTR_WKUP, SAM_USB_ISTR); - usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_WKUP), sam_getreg(SAM_USB_FNR)); - - /* Perform the wakeup action */ - - sam_initresume(priv); - priv->rsmstate = RSMSTATE_IDLE; - - /* Disable ESOF polling, disable the wakeup interrupt, and - * re-enable the suspend interrupt. Clear any pending SUSP - * interrupts. - */ - - sam_setimask(priv, USB_CNTR_SUSPM, USB_CNTR_ESOFM|USB_CNTR_WKUPM); - sam_putreg(~USB_CNTR_SUSPM, SAM_USB_ISTR); - } - - if ((istr & USB_ISTR_SUSP & priv->imask) != 0) - { - usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_SUSP), 0); - sam_suspend(priv); - - /* Clear of the ISTR bit must be done after setting of USB_CNTR_FSUSP */ - - sam_putreg(~USB_ISTR_SUSP, SAM_USB_ISTR); - } - - if ((istr & USB_ISTR_ESOF & priv->imask) != 0) - { - sam_putreg(~USB_ISTR_ESOF, SAM_USB_ISTR); - - /* Resume handling timing is made with ESOFs */ - - usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_ESOF), 0); - sam_esofpoll(priv); - } - - if ((istr & USB_ISTR_CTR & priv->imask) != 0) - { - /* Low priority endpoint correct transfer interrupt */ - - usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_LPCTR), istr); - sam_lptransfer(priv); - } - -exit_lpinterrupt: - usbtrace(TRACE_INTEXIT(SAM_TRACEINTID_INTERRUPT), sam_getreg(SAM_USB_EP0R)); + usbtrace(TRACE_INTEXIT(SAM_TRACEINTID_INTERRUPT), insta); return OK; } @@ -2871,7 +2907,7 @@ static int sam_wakeup(struct usbdev_s *dev) */ sam_setimask(priv, USB_CNTR_ESOFM, USB_CNTR_WKUPM|USB_CNTR_SUSPM); - sam_putreg(~USB_ISTR_ESOF, SAM_USB_ISTR); + sam_putreg(~USB_ISTR_ESOF, SAM_UDPHS_INTSTA); irqrestore(flags); return OK; } @@ -2991,7 +3027,7 @@ static void sam_hw_reset(struct sam_usbdev_s *priv) /* Clear any pending interrupts */ - sam_putreg(0, SAM_USB_ISTR); + sam_putreg(0, SAM_UDPHS_INTSTA); /* Enable interrupts at the USB controller */ @@ -3227,7 +3263,7 @@ static void sam_hw_shutdown(struct sam_usbdev_s *priv) /* Clear any pending interrupts */ - sam_putreg(0, SAM_USB_ISTR); + sam_putreg(0, SAM_UDPHS_INTSTA); /* Disconnect the device / disable the pull-up */ @@ -3290,17 +3326,10 @@ void up_usbinitialize(void) * them when we need them later. */ - if (irq_attach(SAM_IRQ_UHPHS, sam_uhphs_interrupt) != 0) + if (irq_attach(SAM_IRQ_UHPHS, sam_udphs_interrupt) != 0) { usbtrace(TRACE_DEVERROR(SAM_TRACEERR_IRQREGISTRATION), - (uint16_t)SAM_IRQ_USBHP); - goto errout; - } - - if (irq_attach(SAM_IRQ_USBLP, sam_lpinterrupt) != 0) - { - usbtrace(TRACE_DEVERROR(SAM_TRACEERR_IRQREGISTRATION), - (uint16_t)SAM_IRQ_USBLP); + (uint16_t)SAM_IRQ_UDPHS); goto errout; } @@ -3335,12 +3364,10 @@ void up_usbuninitialize(void) flags = irqsave(); usbtrace(TRACE_DEVUNINIT, 0); - /* Disable and detach the USB IRQs */ + /* Disable and detach the UDPHS IRQ */ - up_disable_irq(SAM_IRQ_USBHP); - up_disable_irq(SAM_IRQ_USBLP); - irq_detach(SAM_IRQ_USBHP); - irq_detach(SAM_IRQ_USBLP); + up_disable_irq(SAM_IRQ_UDPHS); + irq_detach(SAM_IRQ_UDPHS); if (priv->driver) { @@ -3411,13 +3438,7 @@ int usbdev_register(struct usbdevclass_driver_s *driver) /* Enable USB controller interrupts at the NVIC */ - up_enable_irq(SAM_IRQ_USBHP); - up_enable_irq(SAM_IRQ_USBLP); - - /* Set the interrrupt priority */ - - up_prioritize_irq(SAM_IRQ_USBHP, CONFIG_USB_PRI); - up_prioritize_irq(SAM_IRQ_USBLP, CONFIG_USB_PRI); + up_enable_irq(SAM_IRQ_UDPHS); /* Enable pull-up to connect the device. The host should enumerate us * some time after this @@ -3473,8 +3494,7 @@ int usbdev_unregister(struct usbdevclass_driver_s *driver) /* Disable USB controller interrupts (but keep them attached) */ - up_disable_irq(SAM_IRQ_USBHP); - up_disable_irq(SAM_IRQ_USBLP); + up_disable_irq(SAM_IRQ_UDPHS); /* Put the hardware in an inactive state. Then bring the hardware back up * in the reset state (this is probably not necessary, the sam_reset()