diff --git a/arch/arm/include/imxrt/imxrt105x_irq.h b/arch/arm/include/imxrt/imxrt105x_irq.h index e67db08aa6..0030975df7 100644 --- a/arch/arm/include/imxrt/imxrt105x_irq.h +++ b/arch/arm/include/imxrt/imxrt105x_irq.h @@ -60,12 +60,12 @@ #define IMXRT_IRQ_EDMA7_23 (IMXRT_IRQ_EXTINT + 7) /* eDMA Channel 7/23 Transfer Complete */ #define IMXRT_IRQ_EDMA8_24 (IMXRT_IRQ_EXTINT + 8) /* eDMA Channel 8/24 Transfer Complete */ #define IMXRT_IRQ_EDMA9_25 (IMXRT_IRQ_EXTINT + 9) /* eDMA Channel 9/25 Transfer Complete */ -#define IMXRT_IRQ_EDMA0_26 (IMXRT_IRQ_EXTINT + 10) /* eDMA Channel 10/26 Transfer Complete */ -#define IMXRT_IRQ_EDMA1_27 (IMXRT_IRQ_EXTINT + 11) /* eDMA Channel 11/27 Transfer Complete */ -#define IMXRT_IRQ_EDMA2_28 (IMXRT_IRQ_EXTINT + 12) /* eDMA Channel 12/28 Transfer Complete */ -#define IMXRT_IRQ_EDMA3_29 (IMXRT_IRQ_EXTINT + 13) /* eDMA Channel 13/29 Transfer Complete */ -#define IMXRT_IRQ_EDMA4_30 (IMXRT_IRQ_EXTINT + 14) /* eDMA Channel 14/30 Transfer Complete */ -#define IMXRT_IRQ_EDMA5_31 (IMXRT_IRQ_EXTINT + 15) /* eDMA Channel 15/31 Transfer Complete */ +#define IMXRT_IRQ_EDMA10_26 (IMXRT_IRQ_EXTINT + 10) /* eDMA Channel 10/26 Transfer Complete */ +#define IMXRT_IRQ_EDMA11_27 (IMXRT_IRQ_EXTINT + 11) /* eDMA Channel 11/27 Transfer Complete */ +#define IMXRT_IRQ_EDMA12_28 (IMXRT_IRQ_EXTINT + 12) /* eDMA Channel 12/28 Transfer Complete */ +#define IMXRT_IRQ_EDMA13_29 (IMXRT_IRQ_EXTINT + 13) /* eDMA Channel 13/29 Transfer Complete */ +#define IMXRT_IRQ_EDMA14_30 (IMXRT_IRQ_EXTINT + 14) /* eDMA Channel 14/30 Transfer Complete */ +#define IMXRT_IRQ_EDMA15_31 (IMXRT_IRQ_EXTINT + 15) /* eDMA Channel 15/31 Transfer Complete */ #define IMXRT_IRQ_EDMA_ERROR (IMXRT_IRQ_EXTINT + 16) /* Error Interrupt, Channels 0-15 / 16-31 */ #define IMXRT_IRQ_CM70 (IMXRT_IRQ_EXTINT + 17) /* CTI trigger outputs (internal: CTIIRQ[0]) */ #define IMXRT_IRQ_CM71 (IMXRT_IRQ_EXTINT + 18) /* CTI trigger outputs (internal: CTIIRQ[1]) */ diff --git a/arch/arm/src/imxrt/Kconfig b/arch/arm/src/imxrt/Kconfig index c32b8fdd7d..35fa03aa96 100644 --- a/arch/arm/src/imxrt/Kconfig +++ b/arch/arm/src/imxrt/Kconfig @@ -70,6 +70,11 @@ endmenu # FlexIO Peripherals menu "LPUART Peripherals" +config IMXRT_EDMA + bool "eDMA" + default n + depends on EXPERIMENTAL + config IMXRT_LPUART1 bool "LPUART1" default n diff --git a/arch/arm/src/imxrt/Make.defs b/arch/arm/src/imxrt/Make.defs index 2ce1d6fc99..9b5b7932ea 100644 --- a/arch/arm/src/imxrt/Make.defs +++ b/arch/arm/src/imxrt/Make.defs @@ -119,3 +119,7 @@ ifeq ($(CONFIG_BUILD_PROTECTED),y) CHIP_CSRCS += imxrt_userspace.c endif endif + +ifeq ($(CONFIG_IMXRT_EDMA),y) +CHIP_CSRCS += imxrt_edma.c +endif diff --git a/arch/arm/src/imxrt/chip/imxrt_edma.h b/arch/arm/src/imxrt/chip/imxrt_edma.h index a5c4ad2b2e..c5119f11f9 100644 --- a/arch/arm/src/imxrt/chip/imxrt_edma.h +++ b/arch/arm/src/imxrt/chip/imxrt_edma.h @@ -47,6 +47,8 @@ * Pre-processor definitions ****************************************************************************************************/ +#define IMXRT_EDMA_NCHANNELS 32 + /* eDMA Register Offsets ****************************************************************************/ #define IMXRT_EDMA_CR_OFFSET 0x0000 /* Control */ @@ -564,18 +566,18 @@ #define IMXRT_EDMA_DCHPRI29 (IMXRT_EDMA_BASE + IMXRT_EDMA_DCHPRI2_OFFSET) #define IMXRT_EDMA_DCHPRI28 (IMXRT_EDMA_BASE + IMXRT_EDMA_DCHPRI3_OFFSET) -#define IMXRT_EDMA_TCD(n) (IMXRT_EDMA_BASE + IMXRT_EDMA_TCD_OFFSET(n)) -#define IMXRT_EDMA_TCD_SADDR(n) (IMXRT_EDMA_TCD(n) + IMXRT_EDMA_TCD_SADDR_OFFSET) -#define IMXRT_EDMA_TCD_SOFF(n) (IMXRT_EDMA_TCD(n) + IMXRT_EDMA_TCD_SOFF_OFFSET) -#define IMXRT_EDMA_TCD_ATTR(n) (IMXRT_EDMA_TCD(n) + IMXRT_EDMA_TCD_ATTR_OFFSET) -#define IMXRT_EDMA_TCD_NBYTES_ML(n) (IMXRT_EDMA_TCD(n) + IMXRT_EDMA_TCD_NBYTES_ML_OFFSET) -#define IMXRT_EDMA_TCD_SLAST(n) (IMXRT_EDMA_TCD(n) + IMXRT_EDMA_TCD_SLAST_OFFSET) -#define IMXRT_EDMA_TCD_DADDR(n) (IMXRT_EDMA_TCD(n) + IMXRT_EDMA_TCD_DADDR_OFFSET) -#define IMXRT_EDMA_TCD_DOFF(n) (IMXRT_EDMA_TCD(n) + IMXRT_EDMA_TCD_DOFF_OFFSET) -#define IMXRT_EDMA_TCD_CITER_ELINK(n) (IMXRT_EDMA_TCD(n) + IMXRT_EDMA_TCD_CITER_ELINK_OFFSET) -#define IMXRT_EDMA_TCD_DLASTSGA(n) (IMXRT_EDMA_TCD(n) + IMXRT_EDMA_TCD_DLASTSGA_OFFSET) -#define IMXRT_EDMA_TCD_CSR(n) (IMXRT_EDMA_TCD(n) + IMXRT_EDMA_TCD_CSR_OFFSET) -#define IMXRT_EDMA_TCD_BITER_ELINK(n) (IMXRT_EDMA_TCD(n) + IMXRT_EDMA_TCD_BITER_ELINK_OFFSET) +#define IMXRT_EDMA_TCD_BASE(n) (IMXRT_EDMA_BASE + IMXRT_EDMA_TCD_OFFSET(n)) +#define IMXRT_EDMA_TCD_SADDR(n) (IMXRT_EDMA_TCD_BASE(n) + IMXRT_EDMA_TCD_SADDR_OFFSET) +#define IMXRT_EDMA_TCD_SOFF(n) (IMXRT_EDMA_TCD_BASE(n) + IMXRT_EDMA_TCD_SOFF_OFFSET) +#define IMXRT_EDMA_TCD_ATTR(n) (IMXRT_EDMA_TCD_BASE(n) + IMXRT_EDMA_TCD_ATTR_OFFSET) +#define IMXRT_EDMA_TCD_NBYTES_ML(n) (IMXRT_EDMA_TCD_BASE(n) + IMXRT_EDMA_TCD_NBYTES_ML_OFFSET) +#define IMXRT_EDMA_TCD_SLAST(n) (IMXRT_EDMA_TCD_BASE(n) + IMXRT_EDMA_TCD_SLAST_OFFSET) +#define IMXRT_EDMA_TCD_DADDR(n) (IMXRT_EDMA_TCD_BASE(n) + IMXRT_EDMA_TCD_DADDR_OFFSET) +#define IMXRT_EDMA_TCD_DOFF(n) (IMXRT_EDMA_TCD_BASE(n) + IMXRT_EDMA_TCD_DOFF_OFFSET) +#define IMXRT_EDMA_TCD_CITER_ELINK(n) (IMXRT_EDMA_TCD_BASE(n) + IMXRT_EDMA_TCD_CITER_ELINK_OFFSET) +#define IMXRT_EDMA_TCD_DLASTSGA(n) (IMXRT_EDMA_TCD_BASE(n) + IMXRT_EDMA_TCD_DLASTSGA_OFFSET) +#define IMXRT_EDMA_TCD_CSR(n) (IMXRT_EDMA_TCD_BASE(n) + IMXRT_EDMA_TCD_CSR_OFFSET) +#define IMXRT_EDMA_TCD_BITER_ELINK(n) (IMXRT_EDMA_TCD_BASE(n) + IMXRT_EDMA_TCD_BITER_ELINK_OFFSET) #define IMXRT_EDMA_TCD0_SADDR (IMXRT_EDMA_BASE + IMXRT_EDMA_TCD0_SADDR_OFFSET) #define IMXRT_EDMA_TCD0_SOFF (IMXRT_EDMA_BASE + IMXRT_EDMA_TCD0_SOFF_OFFSET) diff --git a/arch/arm/src/imxrt/imxrt_edma.c b/arch/arm/src/imxrt/imxrt_edma.c new file mode 100644 index 0000000000..a136427037 --- /dev/null +++ b/arch/arm/src/imxrt/imxrt_edma.c @@ -0,0 +1,647 @@ +/**************************************************************************** + * arch/arm/src/imxrt/sam3u_edma.c + * + * Copyright (C) 2018 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "up_arch.h" +#include "cache.h" +#include "up_internal.h" +#include "sched/sched.h" + +#include "chip.h" +#include "chip/imxrt_edma.h" +#include "imxrt_edma.h" + +#ifdef CONFIG_IMXRT_EDMA + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* This structure describes one DMA channel */ + +struct imxrt_dmach_s +{ + uint8_t chan; /* DMA channel number (0-IMXRT_EDMA_NCHANNELS) */ + bool inuse; /* TRUE: The DMA channel is in use */ + bool rx; /* TRUE: Peripheral to memory transfer */ + uint32_t flags; /* DMA channel flags */ + uint32_t cfg; /* Pre-calculated CFG register for transfer */ + dma_callback_t callback; /* Callback invoked when the DMA completes */ + void *arg; /* Argument passed to callback function */ + uint32_t rxaddr; /* RX memory address */ + size_t rxsize; /* Size of RX memory region */ +}; + +/* This structure describes the state of the eDMA controller */ + +struct imxrt_edma_s +{ + /* These semaphores protect the DMA channel and descriptor tables */ + + sem_t chsem; /* Protects channel table */ + sem_t dsem; /* Protects descriptor table */ + + /* This array describes each DMA channel */ + + struct imxrt_dmach_s dmach[IMXRT_EDMA_NCHANNELS]; +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* The state of the eDMA */ + +static struct imxrt_edma_s g_edma; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: imxrt_takechsem() and imxrt_givechsem() + * + * Description: + * Used to get exclusive access to the DMA channel table + * + ****************************************************************************/ + +static void imxrt_takechsem(void) +{ + int ret; + + do + { + /* Take the semaphore (perhaps waiting) */ + + ret = nxsem_wait(&g_edma.chsem); + + /* The only case that an error should occur here is if the wait was + * awakened by a signal. + */ + + DEBUGASSERT(ret == OK || ret == -EINTR || ret == -ECANCELED); + } + while (ret == -EINTR); +} + +static inline void imxrt_givechsem(void) +{ + (void)nxsem_post(&g_edma.chsem); +} + +/**************************************************************************** + * Name: imxrt_takedsem() and imxrt_givedsem() + * + * Description: + * Used to wait for availability of descriptors in the descriptor table. + * + ****************************************************************************/ + +static void imxrt_takedsem(void) +{ + int ret; + + do + { + /* Take the semaphore (perhaps waiting) */ + + ret = nxsem_wait(&g_edma.dsem); + + /* The only case that an error should occur here is if the wait was + * awakened by a signal. + */ + + DEBUGASSERT(ret == OK || ret == -EINTR || ret == -ECANCELED); + } + while (ret == -EINTR); +} + +static inline void imxrt_givedsem(void) +{ + (void)nxsem_post(&g_edma.dsem); +} + +/**************************************************************************** + * Name: imxrt_getdmach + * + * Description: + * Read a eDMA channel register + * + ****************************************************************************/ + +static inline uint32_t imxrt_getdmach(struct imxrt_dmach_s *dmach, + unsigned int offset) +{ + return getreg32(IMXRT_EDMA_TCD_BASE(dmach->chan) + offset); +} + +/**************************************************************************** + * Name: imxrt_putdmach + * + * Description: + * Write a value to a eDMA channel register + * + ****************************************************************************/ + +static inline void imxrt_putdmach(struct imxrt_dmach_s *dmach, uint32_t value, + unsigned int offset) +{ + putreg32(value, IMXRT_EDMA_TCD_BASE(dmach->chan) + offset); +} + +/**************************************************************************** + * Name: imxrt_dmaterminate + * + * Description: + * Terminate the DMA transfer and disable the DMA channel + * + ****************************************************************************/ + +static void imxrt_dmaterminate(struct imxrt_dmach_s *dmach, int result) +{ + struct imxrt_edma_s *dmac = imxrt_controller(dmach); + + /* Disable all channel interrupts */ + + /* Disable the channel. */ + + /* If this was an RX DMA (peripheral-to-memory), then invalidate the cache + * to force reloads from memory. + */ + + if (dmach->rx) + { + arch_invalidate_dcache(dmach->rxaddr, dmach->rxaddr + dmach->rxsize); + } + + /* Perform the DMA complete callback */ + + if (dmach->callback) + { + dmach->callback((DMA_HANDLE)dmach, dmach->arg, result); + } + + dmach->callback = NULL; + dmach->arg = NULL; +} + +/**************************************************************************** + * Name: imxrt_dmach_interrupt + * + * Description: + * DMA interrupt handler + * + ****************************************************************************/ + +static void imxrt_dmach_interrupt(struct imxrt_dmach_s *dmach) +{ +#warning Missing logic + /* Get the eDMA status register value. Ignore all masked interrupt + * status bits. + */ + + /* Check if the any transfer has completed or any errors have occurred. */ +} + +/**************************************************************************** + * Name: imxrt_edma_interrupt + * + * Description: + * DMA interrupt handler + * + ****************************************************************************/ + +static int imxrt_edma_interrupt(int irq, void *context, FAR void *arg) +{ + struct imxrt_dmach_s *dmach; + unsigned int chan; + + /* 'arg' should the the DMA channel instance. + * + * NOTE that there are only 16 vectors for 32 DMA channels. The 'arg' will + * always be the lower-numbered DMA channel. The other DMA channel will + * have a channel number 16 greater that this one. + */ + + dmach = (struct imxrt_dmach_s *)arg; + DEBUGASSERT(dmach != NULL); + chan = dmach->chan; + DEBUGASSERT(chan < IMXRT_EDMA_NCHANNELS && dmach == &g_edma.dmach[chan]); + + /* Check for an interrupt on the lower numbered DMA channel */ + + imxrt_dmach_interrupt(dmach); + + /* Check for an interrupt on the lower numbered DMA channel */ + + chan += 16; + DEBUGASSERT(chan < IMXRT_EDMA_NCHANNELS); + dmach = &g_edma.dmach[chan]; + imxrt_dmach_interrupt(dmach); + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_dmainitialize + * + * Description: + * Initialize the DMA subsystem + * + * Returned Value: + * None + * + ****************************************************************************/ + +void weak_function up_dmainitialize(void) +{ + int i; + + dmainfo("Initialize eDMA\n"); + + /* Enable peripheral clock */ + + /* Enable data structures */ + + memset(&g_edma, 0, sizeof()); + for (i = 0; i < IMXRT_EDMA_NCHANNELS; i++) + { + g_edma.dmach[i].chan = i; + } + + /* Initialize semaphores */ + + nxsem_init(&g_edma.chsem, 0, 1); + nxsem_init(&g_edma.dsem, 0, SAM_NDMACHAN); + + /* Attach DMA interrupt vectors. + * + * NOTE that there are only 16 vectors for 32 DMA channels. + */ + + (void)irq_attach(IMXRT_IRQ_EDMA0_16, imxrt_edma_interrupt, &g_edma.dmach[0]); + (void)irq_attach(IMXRT_IRQ_EDMA1_17, imxrt_edma_interrupt, &g_edma.dmach[1]); + (void)irq_attach(IMXRT_IRQ_EDMA2_18, imxrt_edma_interrupt, &g_edma.dmach[2]); + (void)irq_attach(IMXRT_IRQ_EDMA3_19, imxrt_edma_interrupt, &g_edma.dmach[3]); + (void)irq_attach(IMXRT_IRQ_EDMA4_20, imxrt_edma_interrupt, &g_edma.dmach[4]); + (void)irq_attach(IMXRT_IRQ_EDMA5_21, imxrt_edma_interrupt, &g_edma.dmach[5]); + (void)irq_attach(IMXRT_IRQ_EDMA6_22, imxrt_edma_interrupt, &g_edma.dmach[6]); + (void)irq_attach(IMXRT_IRQ_EDMA7_23, imxrt_edma_interrupt, &g_edma.dmach[7]); + (void)irq_attach(IMXRT_IRQ_EDMA8_24, imxrt_edma_interrupt, &g_edma.dmach[8]); + (void)irq_attach(IMXRT_IRQ_EDMA9_25, imxrt_edma_interrupt, &g_edma.dmach[9]); + (void)irq_attach(IMXRT_IRQ_EDMA10_26, imxrt_edma_interrupt, &g_edma.dmach[10]); + (void)irq_attach(IMXRT_IRQ_EDMA11_27, imxrt_edma_interrupt, &g_edma.dmach[11]); + (void)irq_attach(IMXRT_IRQ_EDMA12_28, imxrt_edma_interrupt, &g_edma.dmach[12]); + (void)irq_attach(IMXRT_IRQ_EDMA13_29, imxrt_edma_interrupt, &g_edma.dmach[13]); + (void)irq_attach(IMXRT_IRQ_EDMA14_30, imxrt_edma_interrupt, &g_edma.dmach[14]); + (void)irq_attach(IMXRT_IRQ_EDMA15_31, imxrt_edma_interrupt, &g_edma.dmach[15]); + + /* Disable all DMA interrupts at the eDMA controller */ + + /* Disable all DMA channels */ + + /* Enable the DMA controller */ + + /* Enable the IRQ at the NVIC (still disabled at the eDMA controller) */ + + up_enable_irq(IMXRT_IRQ_EDMA0_16); + up_enable_irq(IMXRT_IRQ_EDMA1_17); + up_enable_irq(IMXRT_IRQ_EDMA2_18); + up_enable_irq(IMXRT_IRQ_EDMA3_19); + up_enable_irq(IMXRT_IRQ_EDMA4_20); + up_enable_irq(IMXRT_IRQ_EDMA5_21); + up_enable_irq(IMXRT_IRQ_EDMA6_22); + up_enable_irq(IMXRT_IRQ_EDMA7_23); + up_enable_irq(IMXRT_IRQ_EDMA8_24); + up_enable_irq(IMXRT_IRQ_EDMA9_25); + up_enable_irq(IMXRT_IRQ_EDMA10_26); + up_enable_irq(IMXRT_IRQ_EDMA11_27); + up_enable_irq(IMXRT_IRQ_EDMA12_28); + up_enable_irq(IMXRT_IRQ_EDMA13_29); + up_enable_irq(IMXRT_IRQ_EDMA14_30); + up_enable_irq(IMXRT_IRQ_EDMA15_31); +} + +/**************************************************************************** + * Name: imxrt_dmachannel + * + * Allocate a DMA channel. This function sets aside a DMA channel then + * gives the caller exclusive access to the DMA channel. + * + * The naming convention in all of the DMA interfaces is that one side is + * the 'peripheral' and the other is 'memory'. However, the interface + * could still be used if, for example, both sides were memory although + * the naming would be awkward. + * + * Returned Value: + * If a DMA channel is available, this function returns a non-NULL, void* + * DMA channel handle. NULL is returned on any failure. + * + ****************************************************************************/ + +DMA_HANDLE imxrt_dmachannel(void) +{ + struct imxrt_dmach_s *dmach; + unsigned int chndx; + + /* Search for an available DMA channel */ + + dmach = NULL; + imxrt_takechsem(); + for (chndx = 0; chndx < SAM_NDMACHAN; chndx++) + { + struct imxrt_dmach_s *candidate = &g_edma.dmach[chndx]; + if (!candidate->inuse) + { + dmach = candidate; + dmach->inuse = true; + + /* Clear any pending interrupts on the channel */ + + /* Disable the channel. */ + + break; + } + } + + imxrt_givechsem(); + + /* Show the result of the allocation */ + + if (dmach != NULL) + { + dmainfo("CH%d: returning dmach: %p\n", dmach->chan, dmach); + } + else + { + dmaerr("ERROR: Failed allocate eDMA channel\n"); + } + + return (DMA_HANDLE)dmach; +} + +/**************************************************************************** + * Name: imxrt_dmafree + * + * Description: + * Release a DMA channel. NOTE: The 'handle' used in this argument must + * NEVER be used again until imxrt_dmachannel() is called again to re-gain + * a valid handle. + * + * Returned Value: + * None + * + ****************************************************************************/ + +void imxrt_dmafree(DMA_HANDLE handle) +{ + struct imxrt_dmach_s *dmach = (struct imxrt_dmach_s *)handle; + + dmainfo("dmach: %p\n", dmach); + DEBUGASSERT((dmach != NULL) && (dmach->inuse)); + + /* Mark the channel no longer in use. Clearing the inuse flag is an atomic + * operation and so should be safe. + */ + + dmach->flags = 0; + dmach->inuse = false; /* No longer in use */ +} + +/**************************************************************************** + * Name: imxrt_dmatxsetup + * + * Description: + * Configure DMA for transmit of one buffer (memory to peripheral). This + * function may be called multiple times to handle large and/or dis- + * continuous transfers. Calls to imxrt_dmatxsetup() and imxrt_dmarxsetup() + * must not be intermixed on the same transfer, however. + * + ****************************************************************************/ + +int imxrt_dmatxsetup(DMA_HANDLE handle, uint8_t pchan, uint32_t maddr, + size_t nbytes, uint32_t chflags) +{ + struct imxrt_dmach_s *dmach = (struct imxrt_dmach_s *)handle; + int ret = OK; + + dmainfo("dmach: %p pchan: %u maddr: %08x nbytes: %d chflags %08x\n", + dmach, (int)pchan, (int)maddr, (int)nbytes, (unsigned int)chflags); + DEBUGASSERT(dmach != NULL); + +#warning Missing logic + + /* Save an indication so that the DMA interrupt completion logic will know + * that this was not an RX transfer. + */ + + dmach->rx = false; + + /* Clean caches associated with the DMA memory */ + + arch_clean_dcache(maddr, maddr + nbytes); + return ret; +} + +/**************************************************************************** + * Name: imxrt_dmarxsetup + * + * Description: + * Configure DMA for receipt of one buffer (peripheral to memory). This + * function may be called multiple times to handle large and/or dis- + * continuous transfers. Calls to imxrt_dmatxsetup() and imxrt_dmarxsetup() + * must not be intermixed on the same transfer, however. + * + ****************************************************************************/ + +int imxrt_dmarxsetup(DMA_HANDLE handle, uint8_t pchan, uint32_t maddr, + size_t nbytes, uint32_t chflags) +{ + struct imxrt_dmach_s *dmach = (struct imxrt_dmach_s *)handle; + size_t maxtransfer; + size_t remaining; + int ret = OK; + + dmainfo("dmach: %p pchan: %u maddr: %08x nbytes: %d chflags %08x\n", + dmach, (int)pchan, (int)maddr, (int)nbytes, (unsigned int)chflags); + DEBUGASSERT(dmach); + +#warning Missing logic + + /* Save an indication so that the DMA interrupt completion logic will know + * that this was an RX transfer and will invalidate the cache. + */ + + dmach->rx = true; + dmach->rxaddr = maddr; + dmach->rxsize = nbytes; + + /* Clean caches associated with the DMA memory */ + + arch_clean_dcache(maddr, maddr + nbytes); + return ret; +} + +/**************************************************************************** + * Name: imxrt_dmastart + * + * Description: + * Start the DMA transfer + * + ****************************************************************************/ + +int imxrt_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg) +{ + struct imxrt_dmach_s *dmach = (struct imxrt_dmach_s *)handle; + int ret = -EINVAL; + + dmainfo("dmach: %p callback: %p arg: %p\n", dmach, callback, arg); + DEBUGASSERT(dmach != NULL); + + /* Verify that the DMA has been setup (i.e., at least one entry in the + * link list). + */ + + /* Save the callback info. This will be invoked whent the DMA commpletes */ + + dmach->callback = callback; + dmach->arg = arg; + +#warning Missing logic + + return ret; +} + +/**************************************************************************** + * Name: imxrt_dmastop + * + * Description: + * Cancel the DMA. After imxrt_dmastop() is called, the DMA channel is + * reset and imxrt_dmarx/txsetup() must be called before imxrt_dmastart() + * can be called again + * + ****************************************************************************/ + +void imxrt_dmastop(DMA_HANDLE handle) +{ + struct imxrt_dmach_s *dmach = (struct imxrt_dmach_s *)handle; + irqstate_t flags; + + dmainfo("dmach: %p\n", dmach); + DEBUGASSERT(dmach != NULL); + + flags = spin_lock_irqsave(); + imxrt_dmaterminate(dmach, -EINTR); + spin_unlock_irqrestore(flags); +} + +/**************************************************************************** + * Name: imxrt_dmasample + * + * Description: + * Sample DMA register contents + * + * Assumptions: + * - DMA handle allocated by imxrt_dmachannel() + * + ****************************************************************************/ + +#ifdef CONFIG_DEBUG_DMA +void imxrt_dmasample(DMA_HANDLE handle, struct imxrt_dmaregs_s *regs) +{ + struct imxrt_dmach_s *dmach = (struct imxrt_dmach_s *)handle; + irqstate_t flags; + + /* Sample global registers */ + + flags = spin_lock_irqsave(); +#warning Missing logic + + /* Sample channel registers */ +#warning Missing logic + + spin_unlock_irqrestore(flags); +} +#endif /* CONFIG_DEBUG_DMA */ + +/**************************************************************************** + * Name: imxrt_dmadump + * + * Description: + * Dump previously sampled DMA register contents + * + * Assumptions: + * - DMA handle allocated by imxrt_dmachannel() + * + ****************************************************************************/ + +#ifdef CONFIG_DEBUG_DMA +void imxrt_dmadump(DMA_HANDLE handle, const struct imxrt_dmaregs_s *regs, + const char *msg) +{ + struct imxrt_dmach_s *dmach = (struct imxrt_dmach_s *)handle; + + dmainfo("%s\n", msg); + dmainfo(" DMA Global Registers:\n"); +#warning Missing logic + dmainfo(" DMA Channel Registers:\n"); +#warning Missing logic +} +#endif /* CONFIG_DEBUG_DMA */ +#endif /* CONFIG_IMXRT_EDMA */ diff --git a/arch/arm/src/imxrt/imxrt_edma.h b/arch/arm/src/imxrt/imxrt_edma.h new file mode 100644 index 0000000000..da7f67fec2 --- /dev/null +++ b/arch/arm/src/imxrt/imxrt_edma.h @@ -0,0 +1,248 @@ +/************************************************************************************ + * arch/arm/src/imxrt/imxrt_dmac.h + * + * Copyright (C) 2018 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ************************************************************************************/ + +#ifndef __ARCH_ARM_SRC_IMXRT_IMXRT_EDMAC_H +#define __ARCH_ARM_SRC_IMXRT_IMXRT_EDMAC_H + +/************************************************************************************ + * Included Files + ************************************************************************************/ + +#include + +#include + +/************************************************************************************ + * Pre-processor Definitions + ************************************************************************************/ + +/* DMA ******************************************************************************/ + +/* Flags used to characterize the DMA channel. The naming convention is that one + * side is the peripheral and the other is memory (however, the interface could still + * be used if, for example, both sides were memory although the naming would be + * awkward) + */ + +#define DMACH_FLAG_ + +/************************************************************************************ + * Public Types + ************************************************************************************/ + +typedef FAR void *DMA_HANDLE; +typedef void (*dma_callback_t)(DMA_HANDLE handle, void *arg, int result); + +/* The following is used for sampling DMA registers when CONFIG DEBUG_DMA is selected */ + +#ifdef CONFIG_DEBUG_DMA +struct imxrt_dmaregs_s +{ + /* eDMA Global Registers */ + + uint32_t cr; /* Control */ + uint32_t es; /* Error Status */ + uint32_t erq; /* Enable Request */ + uint32_t req; /* Interrupt Request */ + uint32_t err; /* Error */ + uint32_t hrs; /* Hardware Request Status */ + uint32_t ears; /* Enable Asynchronous Request in Stop */ + + /* eDMA Channel registers */ + + uint8_t dchpri; /* Channel priority */ + + /* eDMA TCD */ + + uint32_t saddr; /* TCD Source Address */ + uint16_t soff; /* TCD Signed Source Address Offset */ + uint16_t attr; /* TCD Transfer Attributes */ + uint32_t nbml; /* TCD Signed Minor Loop Offset / Byte Count */ + uint32_t slast; /* TCD Last Source Address Adjustment */ + uint32_t daddr; /* TCD Destination Address */ + uint16_t doff; /* TCD Signed Destination Address Offset */ + uint16_t citer; /* TCD Current Minor Loop Link, Major Loop Count */ + uint32_t dlastsga; /* TCD Last Destination Address Adjustment/Scatter Gather Address */ + uint32_t csr; /* TCD Control and Status */ + uint16_t biter; /* TCD Beginning Minor Loop Link, Major Loop Count */ + + /* DMAMUX registers */ + + uint32_t dmamux; /* Channel configuration */ +}; +#endif /* CONFIG_DEBUG_DMA */ + +/************************************************************************************ + * Inline Functions + ************************************************************************************/ + +#ifndef __ASSEMBLY__ + +/************************************************************************************ + * Public Data + ************************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/************************************************************************************ + * Public Function Prototypes + ************************************************************************************/ + +/************************************************************************************ + * Name: imxrt_dmachannel + * + * Description: + * Allocate a DMA channel. This function sets aside a DMA channel then gives the + * caller exclusive access to the DMA channel. + * + * The naming convention in all of the DMA interfaces is that one side is the + * 'peripheral' and the other is 'memory'. However, the interface could still + * be used if, for example, both sides were memory although the naming would be + * awkward. + * + * Returned Value: + * If a DMA channel is available, this function returns a non-NULL, void* DMA + * channel handle. NULL is returned on any failure. + * + ************************************************************************************/ + +DMA_HANDLE imxrt_dmachannel(void); + +/************************************************************************************ + * Name: imxrt_dmafree + * + * Description: + * Release a DMA channel. NOTE: The 'handle' used in this argument must NEVER be + * used again until imxrt_dmachannel() is called again to re-gain a valid handle. + * + * Returned Value: + * None + * + ************************************************************************************/ + +void imxrt_dmafree(DMA_HANDLE handle); + +/************************************************************************************ + * Name: imxrt_dmatxsetup + * + * Description: + * Configure DMA for transmit of one buffer (memory to peripheral). This function + * may be called multiple times to handle large and/or discontinuous transfers. + * Calls to imxrt_dmatxsetup() and imxrt_dmarxsetup() must not be intermixed on the + * same transfer, however. + * + ************************************************************************************/ + +int imxrt_dmatxsetup(DMA_HANDLE handle, uint8_t pchan, uint32_t maddr, size_t nbytes, + uint32_t chflags); + +/************************************************************************************ + * Name: imxrt_dmarxsetup + * + * Description: + * Configure DMA for receipt of one buffer (peripheral to memory). This function + * may be called multiple times to handle large and/or discontinuous transfers. + * Calls to imxrt_dmatxsetup() and imxrt_dmarxsetup() must not be intermixed on the + * same transfer, however. + * + ************************************************************************************/ + +int imxrt_dmarxsetup(DMA_HANDLE handle, uint8_t pchan, uint32_t maddr, size_t nbytes, + uint32_t chflags); + +/************************************************************************************ + * Name: imxrt_dmastart + * + * Description: + * Start the DMA transfer + * + ************************************************************************************/ + +int imxrt_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg); + +/************************************************************************************ + * Name: imxrt_dmastop + * + * Description: + * Cancel the DMA. After imxrt_dmastop() is called, the DMA channel is reset and + * imxrt_dmarx/txsetup() must be called before imxrt_dmastart() can be called again + * + ************************************************************************************/ + +void imxrt_dmastop(DMA_HANDLE handle); + +/************************************************************************************ + * Name: imxrt_dmasample + * + * Description: + * Sample DMA register contents + * + ************************************************************************************/ + +#ifdef CONFIG_DEBUG_DMA +void imxrt_dmasample(DMA_HANDLE handle, struct imxrt_dmaregs_s *regs); +#else +# define imxrt_dmasample(handle,regs) +#endif + +/************************************************************************************ + * Name: imxrt_dmadump + * + * Description: + * Dump previously sampled DMA register contents + * + ************************************************************************************/ + +#ifdef CONFIG_DEBUG_DMA +void imxrt_dmadump(DMA_HANDLE handle, const struct imxrt_dmaregs_s *regs, + const char *msg); +#else +# define imxrt_dmadump(handle,regs,msg) +#endif + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_ARM_SRC_IMXRT_IMXRT_EDMAC_H */ diff --git a/arch/arm/src/kinetis/kinetis_dma.c b/arch/arm/src/kinetis/kinetis_dma.c index fda8c5fb4f..a6fa063cd9 100644 --- a/arch/arm/src/kinetis/kinetis_dma.c +++ b/arch/arm/src/kinetis/kinetis_dma.c @@ -132,8 +132,8 @@ void kinetis_dmafree(DMA_HANDLE handle) * ****************************************************************************/ -int kinetis_dmarxsetup(DMA_HANDLE handle, uint32_t control, uint32_t config, - uint32_t srcaddr, uint32_t destaddr, size_t nbytes) +int kinetis_dmasetup(DMA_HANDLE handle, uint32_t control, uint32_t config, + uint32_t srcaddr, uint32_t destaddr, size_t nbytes) { return -1; } diff --git a/arch/arm/src/kinetis/kinetis_dma.h b/arch/arm/src/kinetis/kinetis_dma.h index 38f03f87a3..e232b150ff 100644 --- a/arch/arm/src/kinetis/kinetis_dma.h +++ b/arch/arm/src/kinetis/kinetis_dma.h @@ -156,8 +156,8 @@ void kinetis_dmafree(DMA_HANDLE handle); * ****************************************************************************/ -int kinetis_dmarxsetup(DMA_HANDLE handle, uint32_t control, uint32_t config, - uint32_t srcaddr, uint32_t destaddr, size_t nbytes); +int kinetis_dmasetup(DMA_HANDLE handle, uint32_t control, uint32_t config, + uint32_t srcaddr, uint32_t destaddr, size_t nbytes); /**************************************************************************** * Name: kinetis_dmastart diff --git a/arch/arm/src/lpc43xx/lpc43_gpdma.c b/arch/arm/src/lpc43xx/lpc43_gpdma.c index f68577e131..4e7c6773e4 100644 --- a/arch/arm/src/lpc43xx/lpc43_gpdma.c +++ b/arch/arm/src/lpc43xx/lpc43_gpdma.c @@ -460,8 +460,8 @@ void lpc43_dmafree(DMA_HANDLE handle) * ****************************************************************************/ -int lpc43_dmarxsetup(DMA_HANDLE handle, uint32_t control, uint32_t config, - uint32_t srcaddr, uint32_t destaddr, size_t nbytes) +int lpc43_dmasetup(DMA_HANDLE handle, uint32_t control, uint32_t config, + uint32_t srcaddr, uint32_t destaddr, size_t nbytes) { struct lpc43_dmach_s *dmach = (DMA_HANDLE)handle; uint32_t chbit; diff --git a/arch/arm/src/lpc43xx/lpc43_gpdma.h b/arch/arm/src/lpc43xx/lpc43_gpdma.h index db304c801a..d40e303f7a 100644 --- a/arch/arm/src/lpc43xx/lpc43_gpdma.h +++ b/arch/arm/src/lpc43xx/lpc43_gpdma.h @@ -158,8 +158,8 @@ void lpc43_dmafree(DMA_HANDLE handle); * ****************************************************************************/ -int lpc43_dmarxsetup(DMA_HANDLE handle, uint32_t control, uint32_t config, - uint32_t srcaddr, uint32_t destaddr, size_t nbytes); +int lpc43_dmasetup(DMA_HANDLE handle, uint32_t control, uint32_t config, + uint32_t srcaddr, uint32_t destaddr, size_t nbytes); /**************************************************************************** * Name: lpc43_dmastart