diff --git a/arch/arm/src/common/up_initialize.c b/arch/arm/src/common/up_initialize.c index 995a319e64..d12a23de10 100644 --- a/arch/arm/src/common/up_initialize.c +++ b/arch/arm/src/common/up_initialize.c @@ -124,6 +124,19 @@ void up_initialize(void) up_irqinitialize(); + /* Initialize the DMA subsystem if the weak function stm32_dmainitialize has been + * brought into the build + */ + +#ifdef CONFIG_ARCH_DMA +#ifdef CONFIG_HAVE_WEAKFUNCTIONS + if (up_dmainitialize) +#endif + { + up_dmainitialize(); + } +#endif + /* Initialize the system timer interrupt */ #if !defined(CONFIG_SUPPRESS_INTERRUPTS) && !defined(CONFIG_SUPPRESS_TIMER_INTS) diff --git a/arch/arm/src/common/up_internal.h b/arch/arm/src/common/up_internal.h index ee58647949..9abf4a0b61 100644 --- a/arch/arm/src/common/up_internal.h +++ b/arch/arm/src/common/up_internal.h @@ -156,6 +156,9 @@ extern void up_boot(void); extern void up_copystate(uint32 *dest, uint32 *src); extern void up_decodeirq(uint32 *regs); extern void up_irqinitialize(void); +#ifdef CONFIG_ARCH_DMA +extern void weak_function up_dmainitialize(void); +#endif extern int up_saveusercontext(uint32 *saveregs); extern void up_fullcontextrestore(uint32 *restoreregs) __attribute__ ((noreturn)); extern void up_switchcontext(uint32 *saveregs, uint32 *restoreregs); diff --git a/arch/arm/src/stm32/stm32_dma.c b/arch/arm/src/stm32/stm32_dma.c index 7fc5cb6f55..feda25a4ed 100755 --- a/arch/arm/src/stm32/stm32_dma.c +++ b/arch/arm/src/stm32/stm32_dma.c @@ -44,9 +44,12 @@ #include #include +#include +#include #include #include "up_arch.h" +#include "up_internal.h" #include "os_internal.h" #include "chip.h" #include "stm32_dma.h" @@ -64,6 +67,10 @@ # define DMA_NCHANNELS DMA1_NCHANNELS #endif +#ifndef CONFIG_DMA_PRI +# define CONFIG_DMA_PRI NVIC_SYSH_PRIORITY_DEFAULT +#endif + /* Convert the DMA channel base address to the DMA register block address */ #define DMA_BASE(ch) (ch & 0xfffffc00) @@ -76,7 +83,7 @@ struct stm32_dma_s { - ubyte chan; /* DMA channel number */ + ubyte chan; /* DMA channel number (0-6) */ ubyte irq; /* DMA channel IRQ number */ sem_t sem; /* Used to wait for DMA channel to become available */ uint32 base; /* DMA register channel base address */ @@ -93,69 +100,69 @@ struct stm32_dma_s static struct stm32_dma_s g_dma[DMA_NCHANNELS] = { { - .chan = STM32_DMA1_CHAN1, - .irq = STM32_IRQ_DMA1CH1, + .chan = 0, + .irq = STM32_IRQ_DMA1CH1, .base = STM32_DMA1_BASE + STM32_DMACHAN_OFFSET(0), }, { - .chan = STM32_DMA1_CHAN2, - .irq = STM32_IRQ_DMA1CH2, + .chan = 1, + .irq = STM32_IRQ_DMA1CH2, .base = STM32_DMA1_BASE + STM32_DMACHAN_OFFSET(1), }, { - .chan = STM32_DMA1_CHAN3, - .irq = STM32_IRQ_DMA1CH3, + .chan = 2, + .irq = STM32_IRQ_DMA1CH3, .base = STM32_DMA1_BASE + STM32_DMACHAN_OFFSET(2), }, { - .chan = STM32_DMA1_CHAN4, - .irq = STM32_IRQ_DMA1CH4, + .chan = 3, + .irq = STM32_IRQ_DMA1CH4, .base = STM32_DMA1_BASE + STM32_DMACHAN_OFFSET(3), }, { - .chan = STM32_DMA1_CHAN5, - .irq = STM32_IRQ_DMA1CH5, + .chan = 4, + .irq = STM32_IRQ_DMA1CH5, .base = STM32_DMA1_BASE + STM32_DMACHAN_OFFSET(4), }, { - .chan = STM32_DMA1_CHAN6, - .irq = STM32_IRQ_DMA1CH6, + .chan = 5, + .irq = STM32_IRQ_DMA1CH6, .base = STM32_DMA1_BASE + STM32_DMACHAN_OFFSET(5), }, { - .chan = STM32_DMA1_CHAN7, - .irq = STM32_IRQ_DMA1CH7, + .chan = 6, + .irq = STM32_IRQ_DMA1CH7, .base = STM32_DMA1_BASE + STM32_DMACHAN_OFFSET(6), }, #if STM32_NDMA > 1 { - .chan = STM32_DMA2_CHAN1, - .irq = STM32_IRQ_DMA2CH1, + .chan = 0, + .irq = STM32_IRQ_DMA2CH1, .base = STM32_DMA2_BASE + STM32_DMACHAN_OFFSET(0), }, { - .chan = STM32_DMA2_CHAN2, - .irq = STM32_IRQ_DMA2CH2, + .chan = 1, + .irq = STM32_IRQ_DMA2CH2, .base = STM32_DMA2_BASE + STM32_DMACHAN_OFFSET(1), }, { - .chan = STM32_DMA2_CHAN3, - .irq = STM32_IRQ_DMA2CH3, + .chan = 2, + .irq = STM32_IRQ_DMA2CH3, .base = STM32_DMA2_BASE + STM32_DMACHAN_OFFSET(2), }, { - .chan = STM32_DMA2_CHAN4, + .chan = 3, #ifdef CONFIG_STM32_CONNECTIVITY_LINE - .irq = STM32_IRQ_DMA2CH4, + .irq = STM32_IRQ_DMA2CH4, #else .irq = STM32_IRQ_DMA2CH45, #endif .base = STM32_DMA2_BASE + STM32_DMACHAN_OFFSET(3), }, { - .chan = STM32_DMA2_CHAN5, + .chan = 4, #ifdef CONFIG_STM32_CONNECTIVITY_LINE - .irq = STM32_IRQ_DMA2CH5, + .irq = STM32_IRQ_DMA2CH5, #else .irq = STM32_IRQ_DMA2CH45, #endif @@ -227,6 +234,33 @@ static inline void stm32_dmagive(FAR struct stm32_dma_s *dmach) (void)sem_post(&dmach->sem); } +/************************************************************************************ + * Name: stm32_dmachandisable + * + * Description: + * Disable the DMA channel + * + ************************************************************************************/ + +static void stm32_dmachandisable(struct stm32_dma_s *dmach) +{ + uint32 regval; + + /* Disable all interrupts at the DMA controller */ + + regval = dmachan_getreg(dmach, STM32_DMACHAN_CCR_OFFSET); + regval &= ~DMA_CCR_ALLINTS; + + /* Disable the DMA channel */ + + regval &= ~DMA_CCR_EN; + dmachan_putreg(dmach, STM32_DMACHAN_CCR_OFFSET, regval); + + /* Clear pending channel interrupts */ + + dmabase_putreg(dmach, STM32_DMA_IFCR_OFFSET, DMA_ISR_CHAN_MASK(dmach->chan)); +} + /************************************************************************************ * Name: stm32_dmainterrupt * @@ -239,13 +273,13 @@ static int stm32_dmainterrupt(int irq, void *context) { struct stm32_dma_s *dmach; uint32 isr; - int chan; + int chndx; /* Get the channel structure from the interrupt number */ if (irq >= STM32_IRQ_DMA1CH1 && irq <= STM32_IRQ_DMA1CH7) { - chan = irq - STM32_IRQ_DMA1CH1; + chndx = irq - STM32_IRQ_DMA1CH1; } else #if STM32_NDMA > 1 @@ -255,28 +289,28 @@ static int stm32_dmainterrupt(int irq, void *context) if (irq >= STM32_IRQ_DMA2CH1 && irq <= STM32_IRQ_DMA2CH45) #endif { - chan = irq - STM32_IRQ_DMA2CH1 + DMA1_NCHANNELS; + chndx = irq - STM32_IRQ_DMA2CH1 + DMA1_NCHANNELS; } else #endif { PANIC(OSERR_INTERNAL); } - dmach = &g_dma[chan]; + dmach = &g_dma[chndx]; /* Get the interrupt status (for this channel only) */ - isr = dmabase_getreg(dmach, STM32_DMA_ISR_OFFSET) & ~DMA_ISR_CHAN_MASK(chan); + isr = dmabase_getreg(dmach, STM32_DMA_ISR_OFFSET) & DMA_ISR_CHAN_MASK(dmach->chan); - /* Clear pending interrupts (for this channel only) */ + /* Disable the DMA channel */ - dmabase_putreg(dmach, STM32_DMA_IFCR_OFFSET, isr); + stm32_dmachandisable(dmach); /* Invoke the callback */ if (dmach->callback) { - dmach->callback(dmach, isr >> DMA_ISR_CHAN_SHIFT(chan), dmach->arg); + dmach->callback(dmach, isr >> DMA_ISR_CHAN_SHIFT(dmach->chan), dmach->arg); } return OK; } @@ -296,16 +330,33 @@ static int stm32_dmainterrupt(int irq, void *context) * ****************************************************************************/ -void weak_function stm32_dmainitialize(void) +void weak_function up_dmainitialize(void) { - int chan; + struct stm32_dma_s *dmach; + int chndx; - /* Attach DMA interrupt vectors */ + /* Initialize each DMA channel */ - for (chan = 0; chan < DMA_NCHANNELS; chan++) + for (chndx = 0; chndx < DMA_NCHANNELS; chndx++) { - sem_init(&g_dma[chan].sem, 0, 1); - irq_attach(g_dma[chan].irq, stm32_dmainterrupt); + dmach = &g_dma[chndx]; + sem_init(&dmach->sem, 0, 1); + + /* Attach DMA interrupt vectors */ + + (void)irq_attach(dmach->irq, stm32_dmainterrupt); + + /* Disable the DMA channel */ + + stm32_dmachandisable(dmach); + + /* Enable the IRQ at the NVIC (still disabled at the DMA controller) */ + + up_enable_irq(dmach->irq); + + /* Set the interrrupt priority */ + + up_prioritize_irq(dmach->irq, CONFIG_DMA_PRI); } } @@ -314,7 +365,7 @@ void weak_function stm32_dmainitialize(void) * * Description: * Allocate a DMA channel. This function gives the caller mutually - * exclusive access to the DMA channel specified by the 'chan' argument. + * exclusive access to the DMA channel specified by the 'chndx' argument. * DMA channels are shared on the STM32: Devices sharing the same DMA * channel cannot do DMA concurrently! See the DMACHAN_* definitions in * stm32_dma.h. @@ -330,8 +381,8 @@ void weak_function stm32_dmainitialize(void) * version. Feel free to do that if that is what you need. * * Returned Value: - * Provided that 'chan' is valid, this function ALWAYS returns a non-NULL, - * void* DMA channel handle. (If 'chan' is invalid, the function will + * Provided that 'chndx' is valid, this function ALWAYS returns a non-NULL, + * void* DMA channel handle. (If 'chndx' is invalid, the function will * assert if debug is enabled or do something ignorant otherwise). * * Assumptions: @@ -341,11 +392,11 @@ void weak_function stm32_dmainitialize(void) * ****************************************************************************/ -DMA_HANDLE stm32_dmachannel(int chan) +DMA_HANDLE stm32_dmachannel(int chndx) { - struct stm32_dma_s *dmach = &g_dma[chan]; + struct stm32_dma_s *dmach = &g_dma[chndx]; - DEBUGASSERT(chan < DMA_NCHANNELS); + DEBUGASSERT(chndx < DMA_NCHANNELS); /* Get exclusive access to the DMA channel -- OR wait until the channel * is available if it is currently being used by another driver @@ -478,3 +529,44 @@ void stm32_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg, boole ccr |= (half ? (DMA_CCR_HTIE|DMA_CCR_TEIE) : (DMA_CCR_TCIE|DMA_CCR_TEIE)); dmachan_putreg(dmach, STM32_DMACHAN_CCR_OFFSET, ccr); } + +/**************************************************************************** + * Name: stm32_dmadump + * + * Description: + * Dump DMA register contents + * + * Assumptions: + * - DMA handle allocated by stm32_dmachannel() + * + ****************************************************************************/ + +#ifdef CONFIG_DEBUG_DMA +void stm32_dmadump(DMA_HANDLE handle, const char *msg) +{ + struct stm32_dma_s *dmach = (struct stm32_dma_s *)handle; + uint32 dmabase = DMA_BASE(dmach->base); + irqstate_t flags; + uint32 addr; + + dmalldbg("%s: base: %08x Channel base: %08x \n", msg, dmabase, dmach->base); + + flags = irqsave(); + addr = dmabase + STM32_DMA_ISR_OFFSET; + dmalldbg(" ISRC[%08x]: %08x\n", addr, getreg32(addr)); + + addr = dmach->base + STM32_DMACHAN_CCR_OFFSET; + dmalldbg(" CCR[%08x]: %08x\n", addr, getreg32(addr)); + + addr = dmach->base + STM32_DMACHAN_CNDTR_OFFSET; + dmalldbg(" CNDTR[%08x]: %08x\n", addr, getreg32(addr)); + + addr = dmach->base + STM32_DMACHAN_CPAR_OFFSET; + dmalldbg(" CPAR[%08x]: %08x\n", addr, getreg32(addr)); + + addr = dmach->base + STM32_DMACHAN_CMAR_OFFSET; + dmalldbg(" CMAR[%08x]: %08x\n", addr, getreg32(addr)); + irqrestore(flags); +} +#endif + diff --git a/arch/arm/src/stm32/stm32_dma.h b/arch/arm/src/stm32/stm32_dma.h index f5409d7f6d..e2e16edbd3 100644 --- a/arch/arm/src/stm32/stm32_dma.h +++ b/arch/arm/src/stm32/stm32_dma.h @@ -229,6 +229,7 @@ #define DMA_IFCR_CHAN6_MASK (DMA_CHAN_MASK << DMA_IFCR_CHAN6_SHIFT) #define DMA_IFCR_CHAN7_SHIFT (24) /* Bits 27-24: DMA Channel 7 interrupt flag clear */ #define DMA_IFCR_CHAN7_MASK (DMA_CHAN_MASK << DMA_IFCR_CHAN7_SHIFT) +#define DMA_IFCR_ALLCHANNELS (0x0fffffff) #define DMA_IFCR_CGIF(n) (DMA_CHAN_GIF_BIT << DMA_IFCR_CHAN_SHIFT(n)) #define DMA_IFCR_CTCIF(n) (DMA_CHAN_TCIF_BIT << DMA_IFCR_CHAN_SHIFT(n)) @@ -263,6 +264,8 @@ #define DMA_CCR_TCIE (1 << 1) /* Bit 1: Transfer complete interrupt enable */ #define DMA_CCR_EN (1 << 0) /* Bit 0: Channel enable */ +#define DMA_CCR_ALLINTS (DMA_CCR_TEIE|DMA_CCR_HTIE|DMA_CCR_TCIE) + /* DMA channel number of data register */ #define DMA_CNDTR_NDT_SHIFT (0) /* Bits 15-0: Number of data to Transfer */ diff --git a/arch/arm/src/stm32/stm32_internal.h b/arch/arm/src/stm32/stm32_internal.h index 9964c1130a..b567c5d0f0 100755 --- a/arch/arm/src/stm32/stm32_internal.h +++ b/arch/arm/src/stm32/stm32_internal.h @@ -50,6 +50,12 @@ * Definitions ************************************************************************************/ +/* Configuration ********************************************************************/ + +#if !defined(CONFIG_DEBUG) || !defined(CONFIG_DEBUG_VERBOSE) +# undef CONFIG_DEBUG_DMA +#endif + /* NVIC priority levels *************************************************************/ #define NVIC_SYSH_PRIORITY_MIN 0xff /* All bits set in minimum priority */ @@ -265,19 +271,6 @@ EXTERN int stm32_dumpgpio(uint32 pinset, const char *msg); # define stm32_dumpgpio(p,m) #endif -/**************************************************************************** - * Name: stm32_dmainitialize - * - * Description: - * Initialize the DMA subsystem - * - * Returned Value: - * None - * - ****************************************************************************/ - -EXTERN void weak_function stm32_dmainitialize(void); - /**************************************************************************** * Name: stm32_dmachannel * @@ -359,6 +352,23 @@ EXTERN void stm32_dmasetup(DMA_HANDLE handle, uint32 paddr, uint32 maddr, EXTERN void stm32_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg, boolean half); +/**************************************************************************** + * Name: stm32_dmadump + * + * Description: + * Dump DMA register contents + * + * Assumptions: + * - DMA handle allocated by stm32_dmachannel() + * + ****************************************************************************/ + +#ifdef CONFIG_DEBUG_DMA +EXTERN void stm32_dmadump(DMA_HANDLE handle, const char *msg); +#else +# define stm32_dmadump(handle) +#endif + /************************************************************************************ * Function: stm32_ethinitialize * @@ -445,31 +455,31 @@ EXTERN int stm32_usbpullup(FAR struct usbdev_s *dev, boolean enable); struct usbdev_s; EXTERN void stm32_usbsuspend(FAR struct usbdev_s *dev, boolean resume); -/**************************************************************************** - * Name: sdio_initialize - * - * Description: - * Initialize SDIO for operation. - * +/**************************************************************************** + * Name: sdio_initialize + * + * Description: + * Initialize SDIO for operation. + * * Input Parameters: * slotno - Not used. * * Returned Values: * A reference to an SDIO interface structure. NULL is returned on failures. - * - ****************************************************************************/ + * + ****************************************************************************/ -struct sdio_dev_s; /* See include/nuttx/sdio.h */ -EXTERN FAR struct sdio_dev_s *sdio_initialize(int slotno); - -/**************************************************************************** - * Name: sdio_mediachange - * +struct sdio_dev_s; /* See include/nuttx/sdio.h */ +EXTERN FAR struct sdio_dev_s *sdio_initialize(int slotno); + +/**************************************************************************** + * Name: sdio_mediachange + * * Description: * Called by board-specific logic -- posssible from an interrupt handler -- * in order to signal to the driver that a card has been inserted or - * removed from the slot - * + * removed from the slot + * * Input Parameters: * dev - An instance of the SDIO driver device state structure. * cardinslot - TRUE is a card has been detected in the slot; FALSE if a @@ -478,27 +488,27 @@ EXTERN FAR struct sdio_dev_s *sdio_initialize(int slotno); * * Returned Values: * None - * - ****************************************************************************/ - + * + ****************************************************************************/ + EXTERN void sdio_mediachange(FAR struct sdio_dev_s *dev, boolean cardinslot); -/**************************************************************************** - * Name: sdio_wrprotect - * +/**************************************************************************** + * Name: sdio_wrprotect + * * Description: * Called by board-specific logic to report if the card in the slot is * mechanically write protected. - * + * * Input Parameters: * dev - An instance of the SDIO driver device state structure. * wrprotect - TRUE is a card is writeprotected. * * Returned Values: * None - * - ****************************************************************************/ - + * + ****************************************************************************/ + EXTERN void sdio_wrprotect(FAR struct sdio_dev_s *dev, boolean wrprotect); #undef EXTERN diff --git a/arch/arm/src/stm32/stm32_sdio.c b/arch/arm/src/stm32/stm32_sdio.c index b46147f041..b3b6d47fd5 100644 --- a/arch/arm/src/stm32/stm32_sdio.c +++ b/arch/arm/src/stm32/stm32_sdio.c @@ -118,10 +118,10 @@ /* DMA CCR register settings */ -#define SDIO_RXDMA16_CONFIG (CONFIG_SDIO_DMAPRIO|DMA_CCR_MSIZE_16BITS|\ - DMA_CCR_PSIZE_16BITS|DMA_CCR_MINC) -#define SDIO_TXDMA16_CONFIG (CONFIG_SDIO_DMAPRIO|DMA_CCR_MSIZE_16BITS|\ - DMA_CCR_PSIZE_16BITS|DMA_CCR_MINC|DMA_CCR_DIR) +#define SDIO_RXDMA32_CONFIG (CONFIG_SDIO_DMAPRIO|DMA_CCR_MSIZE_32BITS|\ + DMA_CCR_PSIZE_32BITS|DMA_CCR_MINC) +#define SDIO_TXDMA32_CONFIG (CONFIG_SDIO_DMAPRIO|DMA_CCR_MSIZE_32BITS|\ + DMA_CCR_PSIZE_32BITS|DMA_CCR_MINC|DMA_CCR_DIR) /* FIFO sizes */ @@ -528,6 +528,8 @@ static void stm32_dmacallback(DMA_HANDLE handle, ubyte isr, void *arg) /* We don't really do anything at the completion of DMA. The termination * of the transfer is driven by the SDIO interrupts. */ + + stm32_dmadump(handle, "DMA Callback"); } #endif @@ -837,6 +839,15 @@ static void stm32_endtransfer(struct stm32_dev_s *priv, sdio_eventset_t wkupeven priv->remaining = 0; + /* DMA debug instrumentation */ + +#if defined(CONFIG_SDIO_DMA) && defined(CONFIG_DEBUG_DMA) + if (priv->dmamode) + { + stm32_dmadump(priv->dma, "End of Transfer"); + } +#endif + /* Is a data transfer complete event expected? */ if ((priv->waitevents & wkupevent) != 0) @@ -1978,6 +1989,8 @@ static int stm32_dmarecvsetup(FAR struct sdio_dev_s *dev, FAR ubyte *buffer, if (priv->widebus) { + stm32_dmadump(priv->dma, "Before RECV Setup"); + /* Save the destination buffer information for use by the interrupt handler */ priv->buffer = (uint32*)buffer; @@ -1995,11 +2008,12 @@ static int stm32_dmarecvsetup(FAR struct sdio_dev_s *dev, FAR ubyte *buffer, putreg32(1, SDIO_DCTRL_DMAEN_BB); stm32_dmasetup(priv->dma, STM32_SDIO_FIFO, (uint32)buffer, - (buflen + 3) >> 2, SDIO_RXDMA16_CONFIG); + (buflen + 3) >> 2, SDIO_RXDMA32_CONFIG); /* Start the DMA */ stm32_dmastart(priv->dma, stm32_dmacallback, priv, FALSE); + stm32_dmadump(priv->dma, "After RECV Setup"); ret = OK; } return ret; @@ -2027,7 +2041,7 @@ static int stm32_dmarecvsetup(FAR struct sdio_dev_s *dev, FAR ubyte *buffer, #ifdef CONFIG_SDIO_DMA static int stm32_dmasendsetup(FAR struct sdio_dev_s *dev, - FAR const ubyte *buffer, size_t buflen) + FAR const ubyte *buffer, size_t buflen) { struct stm32_dev_s *priv = (struct stm32_dev_s *)dev; uint32 dblocksize; @@ -2044,6 +2058,8 @@ static int stm32_dmasendsetup(FAR struct sdio_dev_s *dev, if (priv->widebus) { + stm32_dmadump(priv->dma, "Before SEND Setup"); + /* Save the source buffer information for use by the interrupt handler */ priv->buffer = (uint32*)buffer; @@ -2062,12 +2078,13 @@ static int stm32_dmasendsetup(FAR struct sdio_dev_s *dev, /* Configure the TX DMA */ stm32_dmasetup(priv->dma, STM32_SDIO_FIFO, (uint32)buffer, - (buflen + 3) >> 2, SDIO_TXDMA16_CONFIG); + (buflen + 3) >> 2, SDIO_TXDMA32_CONFIG); putreg32(1, SDIO_DCTRL_DMAEN_BB); /* Start the DMA */ stm32_dmastart(priv->dma, stm32_dmacallback, priv, FALSE); + stm32_dmadump(priv->dma, "After SEND Setup"); ret = OK; } return ret;