* arch/arm/src/imxrt/imxrt_edma.h
*
* Copyright (C) 2018 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Portions of the eDMA logic derive from NXP sample code which has a
* compatible BSD 3-clause license:
*
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* Copyright 2016-2017 NXP
* All rights reserved
*
* 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
*
* 1. Allocate a DMA channel
*
* DMACH_HANDLE handle;
* handle = edma_dmach_alloc(dmamux, dchpri);
*
* Where 'dmamux' is the channel DMAMUX configuration register setting and
* 'dchpri' is the channel DCHPRIO priority register setting.
*
* 2. Create the transfer configuration:
*
* struct imxrt_edma_xfrconfig_s config;
* config.saddr = ..;
* config.daddr = ..;
* etc.
*
* 3. Setup the transfer in hardware:
*
* int ret;
* ret = imxrt_dmach_xfrsetup(handle, &config);
*
* 4. If you are setting up a scatter gather DMA
* (with CONFIG_IMXRT_EDMA_NTCD > 0),
* then repeat steps 2 and 3 for each segment of the transfer.
*
* 5. Start the DMA:
*
* ret = imxrt_dmach_start(handle, my_callback_func, priv);
*
* Where my_callback_func() is called when the DMA completes or an error
* occurs. 'priv' represents some internal driver state that will be
* provided with the callback.
*
* 6. If you need to stop the DMA and free resources (such as if a timeout
* occurs), then:
*
* i mxrt_dmach_stop(handle);
*
* 7. The callback will be received when the DMA completes (or an error
* occurs). After that, you may free the DMA channel, or re-use it on
* subsequent DMAs.
*
* imxrt_dmach_free(handle);
*
* Almost non-invasive debug instrumentation is available. You may call
* imxrt_dmasample() to save the current state of the eDMA registers at any
* given point in time. At some later, postmortem analysis, you can dump the
* content of the buffered registers with imxrt_dmadump(). imxrt_dmasample()
* is also available for monitoring DMA progress.
*/
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdint.h>
#include "hardware/imxrt_edma.h"
* Pre-processor Definitions
****************************************************************************/
*
* REVISIT: Many missing options that should be represented as flags:
* 1. Bandwidth
* 2. Source/Destination modulo
*/
#define EDMA_CONFIG_LINKTYPE_SHIFT (0)
#define EDMA_CONFIG_LINKTYPE_MASK (3 << EDMA_CONFIG_LINKTYPE_SHIFT)
# define EDMA_CONFIG_LINKTYPE_LINKNONE (0 << EDMA_CONFIG_LINKTYPE_SHIFT)
# define EDMA_CONFIG_LINKTYPE_MINORLINK (1 << EDMA_CONFIG_LINKTYPE_SHIFT)
# define EDMA_CONFIG_LINKTYPE_MAJORLINK (2 << EDMA_CONFIG_LINKTYPE_SHIFT)
#define EDMA_CONFIG_LOOP_SHIFT (2)
#define EDMA_CONFIG_LOOP_MASK (3 << EDMA_CONFIG_LOOP_SHIFT)
# define EDMA_CONFIG_LOOPNONE (0 << EDMA_CONFIG_LOOP_SHIFT)
# define EDMA_CONFIG_LOOPSRC (1 << EDMA_CONFIG_LOOP_SHIFT)
# define EDMA_CONFIG_LOOPDEST (2 << EDMA_CONFIG_LOOP_SHIFT)
#define EDMA_CONFIG_INTHALF (1 << 4)
#define EDMA_CONFIG_INTMAJOR (1 << 5)
* Default is only on last completion
* if using scatter gather
*/
* Public Types
****************************************************************************/
typedef void *DMACH_HANDLE;
typedef void (*edma_callback_t)(DMACH_HANDLE handle,
void *arg, bool done, int result);
enum kinetis_edma_sizes_e
{
EDMA_8BIT = 0,
EDMA_16BIT = 1,
EDMA_32BIT = 2,
};
* configuration.
*/
struct imxrt_edma_xfrconfig_s
{
uint32_t saddr;
uint32_t daddr;
int16_t soff;
int16_t doff;
uint16_t iter;
uint8_t flags;
uint8_t ssize;
uint8_t dsize;
#ifdef CONFIG_IMXRT_EDMA_EMLIM
uint16_t nbytes;
#else
uint32_t nbytes;
#endif
#ifdef CONFIG_IMXRT_EDMA_ELINK
DMACH_HANDLE linkch;
#endif
};
* when CONFIG DEBUG_DMA is selected
*/
#ifdef CONFIG_DEBUG_DMA
struct imxrt_dmaregs_s
{
uint8_t chan;
uint32_t cr;
uint32_t es;
uint32_t erq;
uint32_t req;
uint32_t err;
uint32_t hrs;
uint32_t ears;
uint8_t dchpri;
uint32_t saddr;
uint16_t soff;
uint16_t attr;
uint32_t nbml;
uint32_t slast;
uint32_t daddr;
uint16_t doff;
uint16_t citer;
uint32_t dlastsga;
uint16_t csr;
uint16_t biter;
uint32_t dmamux;
};
#endif
* 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_dmach_alloc
*
* Allocate a DMA channel. This function sets aside a DMA channel,
* initializes the DMAMUX for the channel, then gives the caller exclusive
* access to the DMA channel.
*
* Input Parameters:
* dmamux - DMAMUX configuration see DMAMUX channel configuration register
* bit-field definitions in hardware/imxrt_dmamux.h.
* Settings include:
*
* DMAMUX_CHCFG_SOURCE Chip-specific DMA source (required)
* DMAMUX_CHCFG_AON DMA Channel Always Enable (optional)
* DMAMUX_CHCFG_TRIG DMA Channel Trigger Enable (optional)
* DMAMUX_CHCFG_ENBL DMA Mux Channel Enable (required)
*
* A value of zero will disable the DMAMUX channel.
* dchpri - DCHPRI channel priority configuration. See DCHPRI channel
* configuration register bit-field definitions in
* hardware/imxrt_edma.h. Meaningful settings include:
*
* EDMA_DCHPRI_CHPRI Channel Arbitration Priority
* DCHPRI_DPA Disable Preempt Ability
* DCHPRI_ECP Enable Channel Preemption
*
* The power-on default, 0x05, is a reasonable choice.
*
* Returned Value:
* If a DMA channel is available, this function returns a non-NULL, void*
* DMA channel handle. NULL is returned on any failure.
*
****************************************************************************/
DMACH_HANDLE imxrt_dmach_alloc(uint32_t dmamux, uint8_t dchpri);
* Name: imxrt_dmach_free
*
* Description:
* Release a DMA channel.
* NOTE: The 'handle' used in this argument must NEVER be used again until
* imxrt_dmach_alloc() is called again to re-gain a valid handle.
*
* Returned Value:
* None
*
****************************************************************************/
void imxrt_dmach_free(DMACH_HANDLE handle);
* Name: imxrt_dmach_xfrsetup
*
* Description:
* This function adds the eDMA transfer to the DMA sequence. The request
* is setup according to the content of the transfer configuration
* structure. For "normal" DMA, imxrt_dmach_xfrsetup is called only once.
* Scatter/gather DMA is accomplished by calling this function repeatedly,
* once for each transfer in the sequence. Scatter/gather DMA processing
* is enabled automatically when the second transfer configuration is
* received.
*
* This function may be called multiple times to handle multiple,
* discontinuous transfers (scatter-gather)
*
* Input Parameters:
* handle - DMA channel handle created by imxrt_dmach_alloc()
* config - A DMA transfer configuration instance, populated by the
* The content of 'config' describes the transfer
*
* Returned Value
* Zero (OK) is returned on success; a negated errno value is returned on
* any failure.
*
****************************************************************************/
int imxrt_dmach_xfrsetup(DMACH_HANDLE handle,
const struct imxrt_edma_xfrconfig_s *config);
* Name: imxrt_dmach_start
*
* Description:
* Start the DMA transfer by enabling the channel DMA request. This
* function should be called after the final call to imxrt_dmasetup() in
* order to avoid race conditions.
*
* At the conclusion of each major DMA loop, a callback to the
* user-provided function is made: |For "normal" DMAs, this will
* correspond to the DMA DONE interrupt; for scatter gather DMAs, multiple
* interrupts will be generated with the final being the DONE interrupt.
*
* At the conclusion of the DMA, the DMA channel is reset, all TCDs are
* freed, and the callback function is called with the the success/fail
* result of the DMA.
*
* NOTE: On Rx DMAs (peripheral-to-memory or memory-to-memory), it is
* necessary to invalidate the destination memory. That is not done
* automatically by the DMA module. Invalidation of the destination memory
* regions is the responsibility of the caller.
*
* Input Parameters:
* handle - DMA channel handle created by imxrt_dmach_alloc()
* callback - The callback to be invoked when the DMA is completes or is
* aborted.
* arg - An argument that accompanies the callback
*
* Returned Value:
* Zero (OK) is returned on success; a negated errno value is returned on
* any failure.
*
****************************************************************************/
int imxrt_dmach_start(DMACH_HANDLE handle,
edma_callback_t callback, void *arg);
* Name: imxrt_dmach_stop
*
* Description:
* Cancel the DMA. After imxrt_dmach_stop() is called, the DMA channel is
* reset, all TCDs are freed, and imxrt_dmarx/txsetup() must be called
* before imxrt_dmach_start() can be called again
*
* Input Parameters:
* handle - DMA channel handle created by imxrt_dmach_alloc()
*
* Returned Value:
* None.
*
****************************************************************************/
void imxrt_dmach_stop(DMACH_HANDLE handle);
* Name: imxrt_dmach_getcount
*
* Description:
* This function checks the TCD (Task Control Descriptor) status for a
* specified eDMA channel and returns the the number of major loop counts
* that have not finished.
*
* NOTES:
* 1. This function can only be used to get unfinished major loop count of
* transfer without the next TCD, or it might be inaccuracy.
* 2. The unfinished/remaining transfer bytes cannot be obtained directly
* from registers while the channel is running.
*
* Because to calculate the remaining bytes, the initial NBYTES configured
* in DMA_TCDn_NBYTES_MLNO register is needed while the eDMA IP does not
* support getting it while a channel is active. In another words, the
* NBYTES value reading is always the actual (decrementing) NBYTES value
* the dma_engine is working with while a channel is running.
* Consequently, to get the remaining transfer bytes, a software-saved
* initial value of NBYTES (for example copied before enabling the channel)
* is needed. The formula to calculate it is shown below:
*
* RemainingBytes = RemainingMajorLoopCount * NBYTES
* (initially configured)
*
* Input Parameters:
* handle - DMA channel handle created by imxrt_dmach_alloc()
*
* Returned Value:
* Major loop count which has not been transferred yet for the current TCD.
*
****************************************************************************/
unsigned int imxrt_dmach_getcount(DMACH_HANDLE handle);
* Name: imxrt_dmach_idle
*
* Description:
* This function checks if the dma is idle
*
* Returned Value:
* 0 - if idle
* !0 - not
*
****************************************************************************/
unsigned int imxrt_dmach_idle(DMACH_HANDLE handle);
* Name: imxrt_dmasample
*
* Description:
* Sample DMA register contents
*
****************************************************************************/
#ifdef CONFIG_DEBUG_DMA
void imxrt_dmasample(DMACH_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(const struct imxrt_dmaregs_s *regs, const char *msg);
#else
# define imxrt_dmadump(handle,regs,msg)
#endif
#undef EXTERN
#if defined(__cplusplus)
}
#endif
#endif
#endif