424 lines
16 KiB
C
424 lines
16 KiB
C
/************************************************************************************
|
|
* arch/arm/src/imxrt/imxrt_dmac.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
|
|
|
|
/* General Usage:
|
|
*
|
|
* 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
|
|
************************************************************************************/
|
|
|
|
/* Configuration flags.
|
|
*
|
|
* REVISIT: Many missing options that should be represented as flags:
|
|
* 1. Bandwidth
|
|
* 2. Source/Destination modulo
|
|
*/
|
|
|
|
#define EDMA_CONFIG_LINKTYPE_SHIFT (0) /* Bits 0-1: Link type */
|
|
#define EDMA_CONFIG_LINKTYPE_MASK (3 << EDMA_CONFIG_LINKTYPE_SHIFT)
|
|
# define EDMA_CONFIG_LINKTYPE_LINKNONE (0 << EDMA_CONFIG_LINKTYPE_SHIFT) /* No channel link */
|
|
# define EDMA_CONFIG_LINKTYPE_MINORLINK (1 << EDMA_CONFIG_LINKTYPE_SHIFT) /* Channel link after each minor loop */
|
|
# define EDMA_CONFIG_LINKTYPE_MAJORLINK (2 << EDMA_CONFIG_LINKTYPE_SHIFT) /* Channel link when major loop count exhausted */
|
|
|
|
/************************************************************************************
|
|
* Public Types
|
|
************************************************************************************/
|
|
|
|
typedef FAR void *DMACH_HANDLE;
|
|
typedef void (*edma_callback_t)(DMACH_HANDLE handle, void *arg, bool done, int result);
|
|
|
|
/* eDMA transfer type */
|
|
|
|
enum imxrt_edma_xfrtype_e
|
|
{
|
|
eDMA_MEM2MEM = 0, /* Transfer from memory to memory */
|
|
eDMA_PERIPH2MEM, /* Transfer from peripheral to memory */
|
|
eDMA_MEM2PERIPH, /* Transfer from memory to peripheral */
|
|
};
|
|
|
|
/* This structure holds the source/destination transfer attribute configuration. */
|
|
|
|
struct imxrt_edma_xfrconfig_s
|
|
{
|
|
uint32_t saddr; /* Source data address. */
|
|
uint32_t daddr; /* Destination data address. */
|
|
int16_t soff; /* Sign-extended offset for current source address. */
|
|
int16_t doff; /* Sign-extended offset for current destination address. */
|
|
uint16_t iter; /* Major loop iteration count. */
|
|
uint8_t flags; /* See EDMA_CONFIG_* definitions */
|
|
uint8_t ssize; /* Source data transfer size (see TCD_ATTR_SIZE_* definitions in rdware/. */
|
|
uint8_t dsize; /* Destination data transfer size. */
|
|
uint8_t ttype; /* Transfer type (see enum imxrt_edma_xfrtype_e). */
|
|
#ifdef CONFIG_IMXRT_EDMA_EMLIM
|
|
uint16_t nbytes; /* Bytes to transfer in a minor loop */
|
|
#else
|
|
uint32_t nbytes; /* Bytes to transfer in a minor loop */
|
|
#endif
|
|
#ifdef CONFIG_IMXRT_EDMA_ELINK
|
|
DMACH_HANDLE linkch; /* Link channel (With EDMA_CONFIG_LINKTYPE_* flags) */
|
|
#endif
|
|
};
|
|
|
|
/* The following is used for sampling DMA registers when CONFIG DEBUG_DMA is selected */
|
|
|
|
#ifdef CONFIG_DEBUG_DMA
|
|
struct imxrt_dmaregs_s
|
|
{
|
|
uint8_t chan; /* Sampled channel */
|
|
|
|
/* 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 */
|
|
uint16_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_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_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 /* __ASSEMBLY__ */
|
|
#endif /* __ARCH_ARM_SRC_IMXRT_IMXRT_EDMAC_H */
|