nuttx/arch/arm/src/efm32/efm32_dma.c

832 lines
24 KiB
C
Raw Normal View History

/****************************************************************************
* arch/arm/src/efm32/efm32_dma.c
*
* Copyright (C) 2014 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* 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 <nuttx/config.h>
#include <sys/types.h>
#include <stdint.h>
#include <stdbool.h>
#include <semaphore.h>
#include <assert.h>
#include <errno.h>
#include <nuttx/arch.h>
#include "up_arch.h"
#include "chip/efm32_cmu.h"
#include "chip/efm32_dma.h"
#include "efm32_dma.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define ALIGN_MASK(s) ((1 << s) - 1)
#define ALIGN_DOWN(v,m) ((v) & ~m)
#define ALIGN_UP(v,m) (((v) + (m)) & ~m)
/****************************************************************************
* Public Types
****************************************************************************/
/* This structure describes one DMA channel */
struct dma_channel_s
{
uint8_t chan; /* DMA channel number (0-EFM32_DMA_NCHANNELS) */
bool inuse; /* TRUE: The DMA channel is in use */
dma_config_t config; /* Current configuration */
dma_callback_t callback; /* Callback invoked when the DMA completes */
void *arg; /* Argument passed to callback function */
};
/* This structure describes the state of the DMA controller */
struct dma_controller_s
{
sem_t exclsem; /* Protects channel table */
sem_t chansem; /* Count of free channels */
};
/****************************************************************************
* Private Data
****************************************************************************/
/* This is the overall state of the DMA controller */
static struct dma_controller_s g_dmac;
/* This is the array of all DMA channels */
static struct dma_channel_s g_dmach[EFM32_DMA_NCHANNELS];
/* This array describes the available channel control data structures. Each
* structure must be aligned to a 256 address boundary. The last 8 or 9
* bits of address are provided by the DMA controller:
*
* 8-Channels:
* Bit 7: Selects the alternate descriptor list
* Bits 4-6: The DMA channel (0-7)
* Bits 2-3: Selects the descriptor field
* Bits 0-1: Always zero
*
* 12-Channels:
* Bit 8: Selects the alternate descriptor list
* Bits 4-7: The DMA channel (0-11)
* Bits 2-3: Selects the descriptor field
* Bits 0-1: Always zero
*/
#if EFM32_DMA_NCHANNELS <= 8
# define DESC_TABLE_SIZE 8
# define DESC_TABLE_ALIGN 256 /* 2*8*16 */
#elif EFM32_DMA_NCHANNELS <= 16
# define DESC_TABLE_SIZE 16
# define DESC_TABLE_ALIGN 512 /* 2*16*16 */
#else
# error Unknown descriptor table size
#endif
#ifdef CONFIG_EFM32_DMA_ALTDSEC
static struct dma_descriptor_s g_descriptors[DESC_TABLE_SIZE + EFM32_DMA_NCHANNELS]
__attribute__((aligned(DESC_TABLE_ALIGN)));
#else
static struct dma_descriptor_s g_descriptors[EFM32_DMA_NCHANNELS]
__attribute__((aligned(DESC_TABLE_ALIGN)));
#endif
/****************************************************************************
* Public Data
****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: efm32_set_chctrl
*
* Description:
* Set the channel control register
*
****************************************************************************/
static void efm32_set_chctrl(struct dma_channel_s *dmach, dma_config_t config)
{
uintptr_t regaddr;
uint32_t decoded;
uint32_t regval;
decoded = (uint32_t)(config & EFM32_DMA_SIGSEL_MASK) >> EFM32_DMA_SIGSEL_SHIFT;
regval = (decoded << _DMA_CH_CTRL_SIGSEL_SHIFT);
decoded = (uint32_t)(config & EFM32_DMA_SOURCSEL_MASK) >> EFM32_DMA_SOURCSEL_SHIFT;
regval |= (decoded << _DMA_CH_CTRL_SOURCESEL_SHIFT);
regaddr = EFM32_DMA_CHn_CTRL(dmach->chan);
putreg32(regval, regaddr);
}
/****************************************************************************
* Name: efm32_align_shift
*
* Description:
* Set the channel control register
*
****************************************************************************/
static inline unsigned int efm32_align_shift(dma_config_t config)
{
unsigned int shift;
shift = (config & EFM32_DMA_XFERSIZE_MASK) >> EFM32_DMA_XFERSIZE_SHIFT;
DEBUGASSERT(shift != 3);
return shift;
}
/****************************************************************************
* Name: efm32_get_descriptor
*
* Description:
* Get the address of the primary or alternate descriptor assigned to the
* DMA channel
*
****************************************************************************/
static inline struct dma_descriptor_s *
efm32_get_descriptor(struct dma_channel_s *dmach, bool alt)
{
uintptr_t base = alt ? getreg32(EFM32_DMA_ALTCTRLBASE) :
getreg32(EFM32_DMA_CTRLBASE);
return ((struct dma_descriptor_s *)base) + dmach->chan;
}
/****************************************************************************
* Name: efm32_dmac_interrupt
*
* Description:
* DMA interrupt handler
*
****************************************************************************/
static int efm32_dmac_interrupt(int irq, void *context)
{
struct dma_channel_s *dmach;
unsigned int chndx;
uint32_t pending;
uint32_t bit;
/* Get the set of pending, unmasked global XDMAC interrupts */
pending = getreg32(EFM32_DMA_IF) & getreg32(EFM32_DMA_IEN);
putreg32(pending, EFM32_DMA_IFC);
/* Check each bit to see which channel(s) have interrupted */
for (chndx = 0; chndx < EFM32_DMA_NCHANNELS && pending != 0; chndx++)
{
/* Are any interrupts pending for this channel? */
bit = 1 << chndx;
if ((pending & bit) != 0)
{
dmach = &g_dmach[chndx];
/* Put the DMA channel in the stopped state */
efm32_dmastop((DMA_HANDLE)dmach);
/* Call the DMA completion callback */
if (dmach->callback)
{
dmach->callback((DMA_HANDLE)dmach, OK, dmach->arg);
dmach->callback = NULL;
}
dmach->arg = NULL;
/* Clear the bit in the sampled set of pending interrupts */
pending &= !bit;
}
}
return OK;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: up_dmainitialize
*
* Description:
* Initialize the DMA subsystem
*
* Returned Value:
* None
*
****************************************************************************/
void weak_function up_dmainitialize(void)
{
uint32_t regval;
int i;
dmallvdbg("Initialize XDMAC0\n");
/* Initialize the channel list */
sem_init(&g_dmac.exclsem, 0, 1);
sem_init(&g_dmac.chansem, 0, EFM32_DMA_NCHANNELS);
for (i = 0; i < EFM32_DMA_NCHANNELS; i++)
{
g_dmach[i].chan = i;
}
/* Enable clocking to the DMA module. DMA is clocked by HFCORECLK. */
regval = getreg32(EFM32_CMU_HFCORECLKEN0);
regval |= CMU_HFCORECLKEN0_DMA;
putreg32(regval, EFM32_CMU_HFCORECLKEN0);
/* Set the control base addresses. Note: EFM32_DMA_ALTCTRLBASE
* is a read-only register that provides the location where hardware
* will obtain the alternative descriptors.
*/
putreg32((uint32_t)g_descriptors, EFM32_DMA_CTRLBASE);
/* Attach DMA interrupt vector */
(void)irq_attach(EFM32_IRQ_DMA, efm32_dmac_interrupt);
/* Enable the DMA controller */
putreg32(DMA_CONFIG_EN, EFM32_DMA_CONFIG);
/* Enable the IRQ at the AIC (still disabled at the DMA controller) */
up_enable_irq(EFM32_IRQ_DMA);
}
/****************************************************************************
* Name: efm32_dmachannel
*
* Description:
* Allocate a DMA channel. This function gives the caller mutually
* exclusive access to a DMA channel.
*
* If no DMA channel is available, then efm32_dmachannel() will wait
* until the holder of a channel relinquishes the channel by calling
* efm32_dmafree().
*
* Input parameters:
* None
*
* Returned Value:
* This function ALWAYS returns a non-NULL, void* DMA channel handle.
*
* Assumptions:
* - The caller can wait for a DMA channel to be freed if it is not
* available.
*
****************************************************************************/
DMA_HANDLE efm32_dmachannel(void)
{
struct dma_channel_s *dmach;
unsigned int chndx;
uint32_t bit;
/* Take a count from from the channel counting semaphore. We may block
* if there are no free channels. When we get the count, then we can
* be assured that a channel is available in the channel list and is
* reserved for us.
*/
while (sem_wait(&g_dmac.chansem) < 0)
{
/* sem_wait should fail only if it is awakened by a a signal */
DEBUGASSERT(errno == EINTR);
}
/* Get exclusive access to the DMA channel list */
while (sem_wait(&g_dmac.exclsem) < 0)
{
/* sem_wait should fail only if it is awakened by a a signal */
DEBUGASSERT(errno == EINTR);
}
/* Search for an available DMA channel */
for (chndx = 0, dmach = NULL; chndx < EFM32_DMA_NCHANNELS; chndx++)
{
struct dma_channel_s *candidate = &g_dmach[chndx];
if (!candidate->inuse)
{
dmach = candidate;
dmach->inuse = true;
/* Clear any pending channel interrupts */
bit = 1 << chndx;
putreg32(bit, EFM32_DMA_IFC);
/* Disable the channel */
putreg32(bit, EFM32_DMA_CHENC);
break;
}
}
sem_post(&g_dmac.exclsem);
/* Since we have reserved a DMA descriptor by taking a count from chansem,
* it would be a serious logic failure if we could not find a free channel
* for our use.
*/
DEBUGASSERT(dmach);
return (DMA_HANDLE)dmach;
}
/****************************************************************************
* Name: efm32_dmafree
*
* Description:
* Release a DMA channel. If another thread is waiting for this DMA channel
* in a call to efm32_dmachannel, then this function will re-assign the
* DMA channel to that thread and wake it up. NOTE: The 'handle' used
* in this argument must NEVER be used again until efm32_dmachannel() is
* called again to re-gain access to the channel.
*
* Returned Value:
* None
*
* Assumptions:
* - The caller holds the DMA channel.
* - There is no DMA in progress
*
****************************************************************************/
void efm32_dmafree(DMA_HANDLE handle)
{
struct dma_channel_s *dmach = (struct dma_channel_s *)handle;
DEBUGASSERT(dmach != NULL && dmach->inuse);
dmavdbg("DMA channel %d\n", dmach->chan);
/* Disable the channel */
putreg32(1 << dmach->chan, EFM32_DMA_CHENC);
/* Mark the channel no longer in use. Clearing the in-use flag is an atomic
* operation and so should be safe.
*/
dmach->inuse = false;
/* And increment the count of free channels... possibly waking up a
* thread that may be waiting for a channel.
*/
sem_post(&g_dmac.chansem);
}
/****************************************************************************
* Name: efm32_rxdmasetup
*
* Description:
* Configure an RX (peripheral-to-memory) DMA before starting the transfer.
*
* Input Parameters:
* paddr - Peripheral address (source)
* maddr - Memory address (destination)
* nbytes - Number of bytes to transfer. Must be an even multiple of the
* configured transfer size.
* config - Channel configuration selections
*
****************************************************************************/
void efm32_rxdmasetup(DMA_HANDLE handle, uintptr_t paddr, uintptr_t maddr,
size_t nbytes, dma_config_t config)
{
struct dma_channel_s *dmach = (struct dma_channel_s *)handle;
struct dma_descriptor_s *desc;
unsigned int xfersize;
unsigned int shift;
uint32_t regval;
2014-10-26 18:22:16 +01:00
uint32_t incr;
uint32_t mask;
DEBUGASSERT(dmach != NULL && dmach->inuse);
/* Get the properly alignment shift and mask */
shift = efm32_align_shift(config);
mask = ALIGN_MASK(shift);
/* Make sure that the number of bytes we are asked to transfer is a multiple
* of the transfer size.
*/
xfersize = (1 << shift);
nbytes = ALIGN_DOWN(nbytes, mask);
DEBUGASSERT(nbytes > 0);
/* Save the configuration (for efm32_dmastart()). */
dmach->config = config;
/* Configure for the selected peripheral */
efm32_set_chctrl(dmach, config);
/* Configure the primary channel descriptor */
desc = efm32_get_descriptor(dmach, false);
desc->srcend = (uint32_t *)paddr;
desc->dstend = (uint32_t *)(maddr + nbytes - xfersize);
/* No source increment, destination increments according to transfer size.
* No privileges. Arbitrate after each transfer. Default priority.
*/
regval = DMA_CTRL_SRC_INC_NONE | DMA_CTRL_DST_PROT_NON_PRIVILEGED |
DMA_CTRL_SRC_PROT_NON_PRIVILEGED | DMA_CTRL_R_POWER_1 |
(0 << _DMA_CTRL_NEXT_USEBURST_SHIFT) | _DMA_CTRL_CYCLE_CTRL_BASIC;
switch (shift)
{
default:
case 0: /* Byte transfer */
2014-10-26 18:22:16 +01:00
regval |= DMA_CTRL_DST_SIZE_BYTE | DMA_CTRL_SRC_SIZE_BYTE;
incr = DMA_CTRL_DST_INC_BYTE;
break;
case 1: /* Half word transfer */
2014-10-26 18:22:16 +01:00
regval |= DMA_CTRL_DST_SIZE_HALFWORD | DMA_CTRL_SRC_SIZE_HALFWORD;
incr = DMA_CTRL_DST_INC_HALFWORD;
break;
case 2: /* Word transfer */
2014-10-26 18:22:16 +01:00
regval |= DMA_CTRL_DST_SIZE_WORD | DMA_CTRL_SRC_SIZE_WORD;
incr = DMA_CTRL_DST_INC_WORD;
break;
}
2014-10-26 18:22:16 +01:00
/* Do we need to increment the memory address? */
if ((config & EFM32_DMA_MEMINCR_MASK) == EFM32_DMA_MEMINCR)
{
regval |= incr;
}
/* Set the number of transfers (minus 1) */
2014-10-25 23:29:23 +02:00
DEBUGASSERT((nbytes >> shift) < 1024);
regval |= ((nbytes >> shift) - 1) << _DMA_CTRL_N_MINUS_1_SHIFT;
desc->ctrl = regval;
desc->user = 0;
}
/****************************************************************************
* Name: efm32_txdmasetup
*
* Description:
* Configure an TX (memory-to-memory) DMA before starting the transfer.
*
* Input Parameters:
* paddr - Peripheral address (destination)
* maddr - Memory address (source)
* nbytes - Number of bytes to transfer. Must be an even multiple of the
* configured transfer size.
* config - Channel configuration selections
*
****************************************************************************/
void efm32_txdmasetup(DMA_HANDLE handle, uintptr_t paddr, uintptr_t maddr,
size_t nbytes, dma_config_t config)
{
struct dma_channel_s *dmach = (struct dma_channel_s *)handle;
struct dma_descriptor_s *desc;
unsigned int xfersize;
unsigned int shift;
uint32_t regval;
2014-10-26 18:22:16 +01:00
uint32_t incr;
uint32_t mask;
DEBUGASSERT(dmach != NULL && dmach->inuse);
/* Get the properly alignment shift and mask */
shift = efm32_align_shift(config);
mask = ALIGN_MASK(shift);
/* Make sure that the number of bytes we are asked to transfer is a multiple
* of the transfer size.
*/
xfersize = (1 << shift);
nbytes = ALIGN_DOWN(nbytes, mask);
DEBUGASSERT(nbytes > 0);
/* Save the configuration (for efm32_dmastart()). */
dmach->config = config;
/* Configure for the selected peripheral */
efm32_set_chctrl(dmach, config);
/* Configure the primary channel descriptor */
desc = efm32_get_descriptor(dmach, false);
desc->srcend = (uint32_t *)(maddr + nbytes - xfersize);
desc->dstend = (uint32_t *)paddr;
/* No destination increment, source increments according to transfer size.
* No privileges. Arbitrate after each transfer. Default priority.
*/
regval = DMA_CTRL_DST_INC_NONE | DMA_CTRL_DST_PROT_NON_PRIVILEGED |
2014-10-26 18:22:16 +01:00
DMA_CTRL_SRC_PROT_NON_PRIVILEGED | DMA_CTRL_R_POWER_1 |
(0 << _DMA_CTRL_NEXT_USEBURST_SHIFT) | _DMA_CTRL_CYCLE_CTRL_BASIC;
switch (shift)
{
default:
case 0: /* Byte transfer */
2014-10-26 18:22:16 +01:00
regval |= DMA_CTRL_DST_SIZE_BYTE | DMA_CTRL_SRC_SIZE_BYTE;
incr = DMA_CTRL_SRC_INC_BYTE;
break;
case 1: /* Half word transfer */
2014-10-26 18:22:16 +01:00
regval |= DMA_CTRL_DST_SIZE_HALFWORD | DMA_CTRL_SRC_SIZE_HALFWORD;
incr = DMA_CTRL_SRC_INC_HALFWORD;
break;
case 2: /* Word transfer */
2014-10-26 18:22:16 +01:00
regval |= DMA_CTRL_DST_SIZE_WORD | DMA_CTRL_SRC_SIZE_WORD;
incr = DMA_CTRL_SRC_INC_WORD;
break;
}
2014-10-26 18:22:16 +01:00
/* Do we need to increment the memory address? */
if ((config & EFM32_DMA_MEMINCR_MASK) == EFM32_DMA_MEMINCR)
{
regval |= incr;
}
/* Set the number of transfers (minus 1) */
2014-10-25 23:29:23 +02:00
DEBUGASSERT((nbytes >> shift) < 1024);
regval |= ((nbytes >> shift) - 1) << _DMA_CTRL_N_MINUS_1_SHIFT;
desc->ctrl = regval;
desc->user = 0;
}
/****************************************************************************
* Name: efm32_dmastart
*
* Description:
* Start the DMA transfer
*
* Assumptions:
* - DMA handle allocated by efm32_dmachannel()
* - No DMA in progress
*
****************************************************************************/
void efm32_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg)
{
struct dma_channel_s *dmach = (struct dma_channel_s *)handle;
irqstate_t flags;
uint32_t regval;
uint32_t bit;
DEBUGASSERT(dmach && dmach->inuse && dmach->desc);
/* Save the DMA complete callback info */
dmach->callback = callback;
dmach->arg = arg;
/* Finish configuring the channel */
bit = 1 << dmach->chan;
if ((dmach->config & EFM32_DMA_SINGLE_MASK) == EFM32_DMA_BUFFER_FULL)
{
/* Disable the single requests for the channel (i.e. do not react to data
* available, wait for buffer full)
*/
putreg32(bit, EFM32_DMA_CHUSEBURSTS);
/* Enable buffer-full requests for the channel */
putreg32(bit, EFM32_DMA_CHREQMASKC);
}
else
{
/* Enable the single requests for the channel */
putreg32(bit, EFM32_DMA_CHUSEBURSTC);
/* Disable buffer-full requests for the channel */
putreg32(bit, EFM32_DMA_CHREQMASKS);
}
2014-10-25 23:29:23 +02:00
/* Use the primary data structure for the channel */
putreg32(bit, EFM32_DMA_CHALTC);
/* Enable DMA completion interrupts */
flags = irqsave();
regval = getreg32(EFM32_DMA_IEN);
regval |= bit;
putreg32(regval, EFM32_DMA_IEN);
/* Enable the channel */
putreg32(bit, EFM32_DMA_CHENS);
irqrestore(flags);
}
/****************************************************************************
* Name: efm32_dmastop
*
* Description:
* Cancel the DMA. After efm32_dmastop() is called, the DMA channel is
* reset and efm32_dmasetup() must be called before efm32_dmastart() can be
* called again
*
* Assumptions:
* - DMA handle allocated by efm32_dmachannel()
*
****************************************************************************/
void efm32_dmastop(DMA_HANDLE handle)
{
struct dma_channel_s *dmach = (struct dma_channel_s *)handle;
irqstate_t flags;
uint32_t regval;
uint32_t bit;
DEBUGASSERT(dmach);
bit = 1 << dmach->chan;
/* Disable the channel */
flags = irqsave();
putreg32(bit, EFM32_DMA_CHENC);
/* Disable Channel interrupts */
regval = getreg32(EFM32_DMA_IEN);
regval |= bit;
putreg32(regval, EFM32_DMA_IEN);
irqrestore(flags);
}
/****************************************************************************
* Name: efm32_dmasample
*
* Description:
* Sample DMA register contents
*
* Assumptions:
* - DMA handle allocated by efm32_dmachannel()
*
****************************************************************************/
#ifdef CONFIG_DEBUG_DMA
void efm32_dmasample(DMA_HANDLE handle, struct efm32_dmaregs_s *regs)
{
struct dma_channel_s *dmach = (struct dma_channel_s *)handle;
uintptr_t regaddr;
irqstate_t flags;
/* Sample DMA registers. */
flags = irqsave();
regs->status = getreg32(EFM32_DMA_STATUS);
regs->ctrlbase = getreg32(EFM32_DMA_CTRLBASE);
regs->altctrlbase = getreg32(EFM32_DMA_ALTCTRLBASE);
regs->chwaitstatus = getreg32(EFM32_DMA_CHWAITSTATUS);
regs->chusebursts = getreg32(EFM32_DMA_CHUSEBURSTS);
regs->chreqmasks = getreg32(EFM32_DMA_CHREQMASKS);
regs->chens = getreg32(EFM32_DMA_CHENS);
regs->chalts = getreg32(EFM32_DMA_CHALTS);
regs->chpris = getreg32(EFM32_DMA_CHPRIS);
regs->errorc = getreg32(EFM32_DMA_ERRORC);
regs->chreqstatus = getreg32(EFM32_DMA_CHREQSTATUS);
regs->chsreqstatus = getreg32(EFM32_DMA_CHSREQSTATUS);
regs->ifr = getreg32(EFM32_DMA_IF);
regs->ien = getreg32(EFM32_DMA_IEN);
#if defined(CONFIG_EFM32_EFM32GG)
regs->ctrl = getreg32(EFM32_DMA_CTRL);
regs->rds = getreg32(EFM32_DMA_RDS);
regs->loop0 = getreg32(EFM32_DMA_LOOP0);
regs->loop1 = getreg32(EFM32_DMA_LOOP1);
regs->rect0 = getreg32(EFM32_DMA_RECT0);
#endif
/* Sample channel control register */
regaddr = EFM32_DMA_CHn_CTRL(dmach->chan)
regs->chnctrl = getreg32(regaddr);
irqrestore(flags);
}
#endif
/****************************************************************************
* Name: efm32_dmadump
*
* Description:
* Dump previously sampled DMA register contents
*
* Assumptions:
* - DMA handle allocated by efm32_dmachannel()
*
****************************************************************************/
#ifdef CONFIG_DEBUG_DMA
void efm32_dmadump(DMA_HANDLE handle, const struct efm32_dmaregs_s *regs,
const char *msg)
{
struct dma_channel_s *dmach = (struct dma_channel_s *)handle;
dmadbg("%s\n", msg);
dmadbg(" DMA Registers:\n");
dmadbg(" STATUS: %08x\n", regs->status);
dmadbg(" CTRLBASE: %08x\n", regs->ctrlbase);
dmadbg(" ALTCTRLBASE: %08x\n", regs->altctrlbase);
dmadbg(" CHWAITSTATUS: %08x\n", regs->chwaitstatus);
dmadbg(" CHUSEBURSTS: %08x\n", regs->chusebursts);
dmadbg(" CHREQMASKS: %08x\n", regs->chreqmasks);
dmadbg(" CHENS: %08x\n", regs->chens);
dmadbg(" CHALTS: %08x\n", regs->chalts);
dmadbg(" CHPRIS: %08x\n", regs->chpris);
dmadbg(" ERRORC: %08x\n", regs->errorc);
dmadbg(" CHREQSTATUS: %08x\n", regs->chreqstatus);
dmadbg(" CHSREQSTATUS: %08x\n", regs->chsreqstatus);
dmadbg(" IEN: %08x\n", regs->ien);
#if defined(CONFIG_EFM32_EFM32GG)
dmadbg(" CTRL: %08x\n", regs->ctrl);
dmadbg(" RDS: %08x\n", regs->rds);
dmadbg(" LOOP0: %08x\n", regs->loop0);
dmadbg(" LOOP1: %08x\n", regs->loop1);
dmadbg(" RECT0: %08x\n", regs->rect0);
#endif
dmadbg(" DMA Channel %d Registers:\n", dmach->chan);
dmadbg(" CHCTRL: %08x\n", regs->chnctrl);
}
#endif