kinetis:Replace DMA

Kinetis:DMAMUX use hex in mask
This commit is contained in:
David Sidrane
2021-06-25 05:13:42 -07:00
committed by Xiang Xiao
parent 3439c40044
commit 78bf264af0
9 changed files with 2874 additions and 1491 deletions
+97 -7
View File
@@ -751,7 +751,7 @@ config KINETIS_FTFL
---help---
Support FLASH
config KINETIS_DMA
config KINETIS_EDMA
bool "DMA"
default n
depends on KINETIS_HAVE_DMA
@@ -1114,6 +1114,96 @@ config KINETIS_SD4BIT_FREQ
endif
endmenu # Kinetis SDHC Configuration
menu "eDMA Configuration"
depends on KINETIS_EDMA
config KINETIS_EDMA_NTCD
int "Number of transfer descriptors"
default 0
---help---
Number of pre-allocated transfer descriptors. Needed for scatter-
gather DMA. Make to be set to zero to disable in-memory TCDs in
which case only the TCD channel registers will be used and scatter-
will not be supported.
config KINETIS_EDMA_ELINK
bool "Channeling Linking"
default n
---help---
This option enables optional minor or major loop channel linking:
Minor loop channel linking: As the channel completes the minor
loop, this flag enables linking to another channel. The link target
channel initiates a channel service request via an internal
mechanism that sets the TCDn_CSR[START] bit of the specified
channel.
If minor loop channel linking is disabled, this link mechanism is
suppressed in favor of the major loop channel linking.
Major loop channel linking: As the channel completes the minor
loop, this option enables the linking to another channel. The link
target channel initiates a channel service request via an internal
mechanism that sets the TCDn_CSR[START] bit of the linked channel.
config KINETIS_EDMA_ERCA
bool "Round Robin Channel Arbitration"
default n
---help---
Normally, a fixed priority arbitration is used for channel
selection. If this option is selected, round robin arbitration is
used for channel selection.
config KINETIS_EDMA_ERGA
bool "Round Robin Group Arbitration"
default n
---help---
Normally, a fixed priority arbitration is used for channel
selection among the groups. If this option is selected,
round Round robin arbitration is used for selection among
the groups.
config KINETIS_EDMA_HOE
bool "Halt On Error"
default y
---help---
Any error causes the HALT bit to set. Subsequently, all service
requests are ignored until the HALT bit is cleared.
config KINETIS_EDMA_CLM
bool "Continuous Link Mode"
default n
---help---
By default, A minor loop channel link made to itself goes through
channel arbitration before being activated again. If this option is
selected, a minor loop channel link made to itself does not go
through channel arbitration before being activated again. Upon minor
loop completion, the channel activates again if that channel has a
minor loop channel link enabled and the link channel is itself. This
effectively applies the minor loop offsets and restarts the next
minor loop.
config KINETIS_EDMA_EMLIM
bool "Minor Loop Mapping"
default n
---help---
Normally TCD word 2 is a 32-bit NBYTES field. When this option is
enabled, TCD word 2 is redefined to include individual enable fields,
an offset field, and the NBYTES field. The individual enable fields
allow the minor loop offset to be applied to the source address, the
destination address, or both. The NBYTES field is reduced when either
offset is enabled.
config KINETIS_EDMA_EDBG
bool "Enable Debug"
default n
---help---
When in debug mode, the DMA stalls the start of a new channel. Executing
channels are allowed to complete. Channel execution resumes when the
system exits debug mode or the EDBG bit is cleared
endmenu # eDMA Global Configuration
if KINETIS_USBHS && USBHOST
menu "USB host controller driver (HCD) options"
@@ -1208,42 +1298,42 @@ config KINETIS_UARTFIFOS
config KINETIS_UART0_RXDMA
bool "UART0 Rx DMA"
default n
depends on KINETIS_UART0 && KINETIS_DMA
depends on KINETIS_UART0 && KINETIS_EDMA
---help---
In high data rate usage, Rx DMA may eliminate Rx overrun errors
config KINETIS_UART1_RXDMA
bool "UART1 Rx DMA"
default n
depends on KINETIS_UART1 && KINETIS_DMA
depends on KINETIS_UART1 && KINETIS_EDMA
---help---
In high data rate usage, Rx DMA may eliminate Rx overrun errors
config KINETIS_UART2_RXDMA
bool "UART2 Rx DMA"
default n
depends on KINETIS_UART2 && KINETIS_DMA
depends on KINETIS_UART2 && KINETIS_EDMA
---help---
In high data rate usage, Rx DMA may eliminate Rx overrun errors
config KINETIS_UART3_RXDMA
bool "UART3 Rx DMA"
default n
depends on KINETIS_UART3 && KINETIS_DMA
depends on KINETIS_UART3 && KINETIS_EDMA
---help---
In high data rate usage, Rx DMA may eliminate Rx overrun errors
config KINETIS_UART4_RXDMA
bool "UART4 Rx DMA"
default n
depends on KINETIS_UART4 && KINETIS_DMA
depends on KINETIS_UART4 && KINETIS_EDMA
---help---
In high data rate usage, Rx DMA may eliminate Rx overrun errors
config KINETIS_UART5_RXDMA
bool "UART5 Rx DMA"
default n
depends on KINETIS_UART5 && KINETIS_DMA
depends on KINETIS_UART5 && KINETIS_EDMA
---help---
In high data rate usage, Rx DMA may eliminate Rx overrun errors
+2 -2
View File
@@ -140,8 +140,8 @@ CHIP_CSRCS += kinetis_usbhshost.c
endif
endif
ifeq ($(CONFIG_KINETIS_DMA),y)
CHIP_CSRCS += kinetis_dma.c kinetis_pindma.c
ifeq ($(CONFIG_KINETIS_EDMA),y)
CHIP_CSRCS += kinetis_edma.c kinetis_pindma.c
endif
ifeq ($(CONFIG_PWM),y)
File diff suppressed because it is too large Load Diff
@@ -56,7 +56,7 @@
/* Channel n Configuration Register */
#define DMAMUX_CHCFG_SOURCE_SHIFT (0) /* Bits 0-5: DMA Channel Source (slot) */
#define DMAMUX_CHCFG_SOURCE_MASK (63 << DMAMUX_CHCFG_SOURCE_SHIFT)
#define DMAMUX_CHCFG_SOURCE_MASK (0x3f << DMAMUX_CHCFG_SOURCE_SHIFT)
#define DMAMUX_CHCFG_TRIG (1 << 6) /* Bit 6: DMA Channel Trigger Enable */
#define DMAMUX_CHCFG_ENBL (1 << 7) /* Bit 7: DMA Channel Enable */
File diff suppressed because it is too large Load Diff
-455
View File
@@ -1,455 +0,0 @@
/****************************************************************************
* arch/arm/src/kinetis/kinetis_dma.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdint.h>
#include <stdbool.h>
#include <assert.h>
#include <errno.h>
#include <debug.h>
#include <sys/types.h>
#include <nuttx/irq.h>
#include <nuttx/arch.h>
#include <arch/board/board.h>
#include "arm_arch.h"
#include "arm_internal.h"
#include "kinetis_config.h"
#include "chip.h"
#include "kinetis_dma.h"
#include "hardware/kinetis_dmamux.h"
#include "hardware/kinetis_sim.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#ifndef DMA_CHN_PER_GROUP
# define DMA_CHN_PER_GROUP KINETIS_NDMACH /* Number of channels per group */
#endif
/****************************************************************************
* Private Types
****************************************************************************/
struct kinetis_dma_ch
{
bool used;
uint8_t ind;
uint8_t irq;
enum kinetis_dma_direction_e dir;
enum kinetis_dma_data_sz_e data_sz;
dma_callback_t callback;
void *arg;
};
/****************************************************************************
* Private Data
****************************************************************************/
static struct kinetis_dma_ch g_channels[KINETIS_NDMACH];
/****************************************************************************
* Private Functions
****************************************************************************/
static int kinetis_dmainterrupt_int(int irq, void *context,
struct kinetis_dma_ch *ch)
{
/* Clear bit in the interrupt */
putreg8(ch->ind, KINETIS_DMA_CINT);
/* Invoke the callback */
if (ch->callback)
{
ch->callback((DMA_HANDLE)&ch, ch->arg, 0);
}
return OK;
}
static int kinetis_dmainterrupt(int irq, void *context, void *arg)
{
uint8_t irq_int = *(uint8_t *)arg;
uint32_t regval;
regval = getreg32(KINETIS_DMA_INT);
/* Channel irq_int and irq_int + DMA_CHN_PER_GROUP use the same arg. Check
* which one requested an interrupt
*/
if ((regval & (1 << irq_int)) != 0)
{
kinetis_dmainterrupt_int(irq, context, &g_channels[irq_int]);
}
if ((regval & (1 << (irq_int + DMA_CHN_PER_GROUP))) != 0)
{
kinetis_dmainterrupt_int(irq, context,
&g_channels[irq_int + DMA_CHN_PER_GROUP]);
}
return OK;
}
/****************************************************************************
* Public Functions
****************************************************************************/
size_t kinetis_dmaresidual(DMA_HANDLE handle)
{
struct kinetis_dma_ch *ch = (struct kinetis_dma_ch *)handle;
/* Channel Linking Disabled */
return ((getreg16(KINETIS_DMA_TCD_CITER(ch->ind)) >>
DMA_TCD_CITER2_SHIFT) & DMA_TCD_CITER2_MASK);
}
/****************************************************************************
* Name: kinetis_dmainitialize
*
* Description:
* Initialize the DMA subsystem.
*
* Returned Value:
* None
*
****************************************************************************/
void weak_function arm_dma_initialize(void)
{
int i;
uint32_t regval;
int ret;
for (i = KINETIS_NDMACH - 1; i >= 0; i--)
{
g_channels[i].ind = i;
g_channels[i].used = false;
g_channels[i].irq = KINETIS_IRQ_FIRST + (i % DMA_CHN_PER_GROUP);
if (i < DMA_CHN_PER_GROUP)
{
/* Attach DMA interrupt */
ret = irq_attach(g_channels[i].irq, kinetis_dmainterrupt,
(void *)&g_channels[i].ind);
if (ret == OK)
{
/* Enable the IRQ at the NVIC (still disabled at the DMA
* controller)
*/
up_enable_irq(g_channels[i].irq);
}
else
{
g_channels[i].used = true;
g_channels[i + DMA_CHN_PER_GROUP].used = true;
}
}
}
/* Enable clocking for DMA */
regval = getreg32(KINETIS_SIM_SCGC7);
regval |= SIM_SCGC7_DMA;
putreg32(regval, KINETIS_SIM_SCGC7);
/* Configure DMA for round robin arbitration */
regval = 0;
regval |= DMA_CR_ERCA | DMA_CR_ERGA;
putreg32(regval, KINETIS_DMA_CR);
/* Enable clocking for the DMA mux */
regval = getreg32(KINETIS_SIM_SCGC6);
regval |= SIM_SCGC6_DMAMUX0;
putreg32(regval, KINETIS_SIM_SCGC6);
}
/****************************************************************************
* Name: kinetis_dmachannel
*
* Description:
* Allocate a DMA channel. This function sets aside a DMA channel and
* gives the caller exclusive access to the DMA channel.
*
* Returned Value:
* On success, this function returns a non-NULL, void* DMA channel handle.
* NULL is returned on any failure. This function can fail only if no DMA
* channel is available.
*
****************************************************************************/
DMA_HANDLE kinetis_dmachannel(uint8_t src, uint32_t per_addr,
enum kinetis_dma_data_sz_e per_data_sz,
enum kinetis_dma_direction_e dir)
{
int i;
int ch_ind;
uint8_t regval8;
uint16_t regval16;
irqstate_t flags;
struct kinetis_dma_ch *ch;
/* Find available channel */
ch_ind = -1;
flags = enter_critical_section();
for (i = 0; i < KINETIS_NDMACH; i++)
{
if (!g_channels[i].used)
{
ch_ind = i;
g_channels[ch_ind].used = true;
break;
}
}
leave_critical_section(flags);
if (ch_ind == -1)
{
/* No available channel */
return NULL;
}
ch = &g_channels[ch_ind];
/* Copy arguments */
ch->dir = dir;
ch->data_sz = per_data_sz;
/* DMAMUX Set DMA channel source and enable it */
regval8 = ((((uint8_t)src) << DMAMUX_CHCFG_SOURCE_SHIFT) &
DMAMUX_CHCFG_SOURCE_MASK) | DMAMUX_CHCFG_ENBL;
putreg8(regval8, KINETIS_DMAMUX_CHCFG(ch_ind));
/* DMA Set peripheral address in TCD */
if (ch->dir == KINETIS_DMA_DIRECTION_PERIPHERAL_TO_MEMORY)
{
putreg32(per_addr, KINETIS_DMA_TCD_SADDR(ch->ind));
putreg16(0, KINETIS_DMA_TCD_SOFF(ch->ind));
putreg32(0, KINETIS_DMA_TCD_SLAST(ch->ind));
}
else if (ch->dir == KINETIS_DMA_DIRECTION_MEMORY_TO_PERIPHERAL)
{
putreg32(per_addr, KINETIS_DMA_TCD_DADDR(ch->ind));
putreg16(0, KINETIS_DMA_TCD_DOFF(ch->ind));
putreg32(0, KINETIS_DMA_TCD_DLASTSGA(ch->ind));
}
else
{
ch->used = false;
return NULL;
}
/* Set data sizes */
regval16 = (DMA_TCD_ATTR_SSIZE_MASK & ((uint16_t)per_data_sz) <<
DMA_TCD_ATTR_SSIZE_SHIFT);
regval16 |= (DMA_TCD_ATTR_DSIZE_MASK & ((uint16_t)per_data_sz) <<
DMA_TCD_ATTR_DSIZE_SHIFT);
putreg16(regval16, KINETIS_DMA_TCD_ATTR(ch->ind));
/* Set minor loop count */
putreg32(1 << (uint8_t)per_data_sz, KINETIS_DMA_TCD_NBYTES(ch->ind));
return (DMA_HANDLE)ch;
}
/****************************************************************************
* Name: kinetis_dmafree
*
* Description:
* Release a DMA channel. NOTE: The 'handle' used in this argument must
* NEVER be used again until kinetis_dmachannel() is called again to
* re-gain a valid handle.
*
* Returned Value:
* None
*
****************************************************************************/
void kinetis_dmafree(DMA_HANDLE handle)
{
struct kinetis_dma_ch *ch = (struct kinetis_dma_ch *)handle;
irqstate_t flags;
DEBUGASSERT(handle != NULL);
/* Disable DMA channel in the dmamux */
putreg8(0, KINETIS_DMAMUX_CHCFG(ch->ind));
flags = enter_critical_section();
ch->used = false;
leave_critical_section(flags);
}
/****************************************************************************
* Name: kinetis_dmasetup
*
* Description:
* Configure DMA for one transfer.
*
****************************************************************************/
int kinetis_dmasetup(DMA_HANDLE handle, uint32_t mem_addr, size_t ntransfers,
uint16_t control)
{
struct kinetis_dma_ch *ch = (struct kinetis_dma_ch *)handle;
uint16_t regval = 0;
uint32_t nbytes;
if (ntransfers > (DMA_TCD_CITER2_MASK >> DMA_TCD_CITER2_SHIFT))
{
return -EINVAL;
}
DEBUGASSERT(handle != NULL);
nbytes = (uint32_t)ntransfers * (uint32_t)(1 << (uint8_t)ch->data_sz);
if (ch->dir == KINETIS_DMA_DIRECTION_PERIPHERAL_TO_MEMORY)
{
putreg32(mem_addr, KINETIS_DMA_TCD_DADDR(ch->ind));
putreg16(1 << (uint8_t)ch->data_sz, KINETIS_DMA_TCD_DOFF(ch->ind));
putreg32(-nbytes, KINETIS_DMA_TCD_DLASTSGA(ch->ind));
}
else if (ch->dir == KINETIS_DMA_DIRECTION_MEMORY_TO_PERIPHERAL)
{
putreg32(mem_addr, KINETIS_DMA_TCD_SADDR(ch->ind));
putreg16(1 << (uint8_t)ch->data_sz, KINETIS_DMA_TCD_SOFF(ch->ind));
putreg32(-nbytes, KINETIS_DMA_TCD_SLAST(ch->ind));
}
else
{
return -EINVAL;
}
/* Set up channel with control word */
regval = (control & DMA_TCD_CSR_MAJORELINK) ? ch->ind : 0;
regval <<= DMA_TCD_CSR_MAJORLINKCH_SHIFT;
regval &= DMA_TCD_CSR_MAJORLINKCH_MASK;
regval |= (DMA_TCD_CSR_INTMAJOR |
(control & (DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_MAJORELINK)));
putreg16(regval, KINETIS_DMA_TCD_CSR(ch->ind));
/* Set major loop count */
putreg16(ntransfers, KINETIS_DMA_TCD_BITER(ch->ind));
putreg16(ntransfers, KINETIS_DMA_TCD_CITER(ch->ind));
return OK;
}
/****************************************************************************
* Name: kinetis_dmastart
*
* Description:
* Start the DMA transfer
*
****************************************************************************/
int kinetis_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg)
{
struct kinetis_dma_ch *ch = (struct kinetis_dma_ch *)handle;
DEBUGASSERT(handle != NULL);
ch->callback = callback;
ch->arg = arg;
/* Enable request register for this channel */
putreg8(ch->ind, KINETIS_DMA_SERQ);
return OK;
}
/****************************************************************************
* Name: kinetis_dmastop
*
* Description:
* Cancel the DMA. After kinetis_dmastop() is called, the DMA channel is
* reset and kinetis_dmasetup() must be called before kinetis_dmastart()
* can be called again
*
****************************************************************************/
void kinetis_dmastop(DMA_HANDLE handle)
{
struct kinetis_dma_ch *ch = (struct kinetis_dma_ch *)handle;
DEBUGASSERT(handle != NULL);
putreg8(ch->ind, KINETIS_DMA_CERQ);
}
/****************************************************************************
* Name: kinetis_dmasample
*
* Description:
* Sample DMA register contents
*
****************************************************************************/
#ifdef CONFIG_DEBUG_DMA
void kinetis_dmasample(DMA_HANDLE handle, struct kinetis_dmaregs_s *regs)
{
DEBUGASSERT(handle != NULL);
}
#endif
/****************************************************************************
* Name: kinetis_dmadump
*
* Description:
* Dump previously sampled DMA register contents
*
****************************************************************************/
#ifdef CONFIG_DEBUG_DMA
void kinetis_dmadump(DMA_HANDLE handle, const struct kinetis_dmaregs_s *regs,
const char *msg)
{
DEBUGASSERT(handle != NULL);
}
#endif
-250
View File
@@ -1,250 +0,0 @@
/****************************************************************************
* arch/arm/src/kinetis/kinetis_dma.h
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
#ifndef __ARCH_ARM_SRC_KINETEIS_KINETEIS_DMA_H
#define __ARCH_ARM_SRC_KINETEIS_KINETEIS_DMA_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include "hardware/kinetis_dma.h"
/****************************************************************************
* Pre-processor Declarations
****************************************************************************/
/****************************************************************************
* 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 kinetis_dmaglobalregs_s
{
#warning "Missing logic"
/* Global Registers */
};
struct kinetis_dmachanregs_s
{
#warning "Missing logic"
/* Channel Registers */
};
struct kinetis_dmaregs_s
{
/* Global Registers */
struct kinetis_dmaglobalregs_s gbl;
/* Channel Registers */
struct kinetis_dmachanregs_s ch;
};
#endif
enum kinetis_dma_direction_e
{
KINETIS_DMA_DIRECTION_PERIPHERAL_TO_MEMORY,
KINETIS_DMA_DIRECTION_MEMORY_TO_PERIPHERAL
};
/* Kinetis data transfer size */
enum kinetis_dma_data_sz_e
{
KINETIS_DMA_DATA_SZ_8BIT = 0,
KINETIS_DMA_DATA_SZ_16BIT = 1,
KINETIS_DMA_DATA_SZ_32BIT = 2,
};
/****************************************************************************
* Public Data
****************************************************************************/
#ifndef __ASSEMBLY__
#undef EXTERN
#if defined(__cplusplus)
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif
/****************************************************************************
* Public Functions Prototypes
****************************************************************************/
/****************************************************************************
* Name: kinetis_dmainitialize
*
* Description:
* Initialize the GPDMA subsystem.
*
* Returned Value:
* None
*
****************************************************************************/
void kinetis_dmainitialize(void);
/****************************************************************************
* Name: kinetis_dmachannel
*
* Description:
* Allocate a DMA channel. This function sets aside a DMA channel and
* gives the caller exclusive access to the DMA channel.
*
* Input Parameters:
* src - DMA request source
* per_addr - Address of the peripheral data
* per_data_sz - Peripheral data size (register size). Note that if this
* does not agree with the peripheral register size, DMA
* transfers will silently fail during operation.
* dir - transfer direction
*
* Returned Value:
* On success, this function returns a non-NULL, void* DMA channel handle.
* NULL is returned on any failure. This function can fail only if no DMA
* channel is available.
*
****************************************************************************/
DMA_HANDLE kinetis_dmachannel(uint8_t src,
uint32_t per_addr,
enum kinetis_dma_data_sz_e per_data_sz,
enum kinetis_dma_direction_e dir);
/****************************************************************************
* Name: kinetis_dmafree
*
* Description:
* Release a DMA channel. NOTE: The 'handle' used in this argument must
* NEVER be used again until kinetis_dmachannel() is called again to re-
* gain a valid handle.
*
* Returned Value:
* None
*
****************************************************************************/
void kinetis_dmafree(DMA_HANDLE handle);
/****************************************************************************
* Name: kinetis_dmasetup
*
* Description:
* Configure DMA for one transfer.
*
* Input Parameters:
* mem_addr - Memory address
* ntransfers - Number of transfers. Must be 0<= ntransfers <= 0x7FFF
* control - Channel control configuration
*
* Returned Value:
* result: 0 if ok, negative else
*
****************************************************************************/
int kinetis_dmasetup(DMA_HANDLE handle, uint32_t mem_addr,
size_t ntransfers, uint16_t control);
/****************************************************************************
* Name: kinetis_dmastart
*
* Description:
* Start the DMA transfer
*
****************************************************************************/
int kinetis_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg);
/****************************************************************************
* Name: kinetis_dmastop
*
* Description:
* Cancel the DMA. After kinetis_dmastop() is called, the DMA channel is
* reset and kinetis_dmasetup() must be called before kinetis_dmastart()
* can be called again
*
****************************************************************************/
void kinetis_dmastop(DMA_HANDLE handle);
/****************************************************************************
* Name: kinetis_dmaresidual
*
* Description:
* Returns the number of transfers left
*
* Returned Value:
* Residual transfers
****************************************************************************/
size_t kinetis_dmaresidual(DMA_HANDLE handle);
/****************************************************************************
* Name: kinetis_dmasample
*
* Description:
* Sample DMA register contents
*
****************************************************************************/
#ifdef CONFIG_DEBUG_DMA
void kinetis_dmasample(DMA_HANDLE handle, struct kinetis_dmaregs_s *regs);
#else
# define kinetis_dmasample(handle,regs)
#endif
/****************************************************************************
* Name: kinetis_dmadump
*
* Description:
* Dump previously sampled DMA register contents
*
****************************************************************************/
#ifdef CONFIG_DEBUG_DMA
void kinetis_dmadump(DMA_HANDLE handle, const struct kinetis_dmaregs_s *regs,
const char *msg);
#else
# define kinetis_dmadump(handle,regs,msg)
#endif
#undef EXTERN
#if defined(__cplusplus)
}
#endif
#endif /* __ASSEMBLY__ */
#endif /* __ARCH_ARM_SRC_KINETEIS_KINETEIS_DMA_H */
File diff suppressed because it is too large Load Diff
+455
View File
@@ -0,0 +1,455 @@
/****************************************************************************
* arch/arm/src/kinetis/kinetis_edma.h
*
* Copyright (C) 2019 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* This file was leveraged from the NuttX i.MXRT port.
* Portions of that eDMA logic derived 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_KINETIS_KINETIS_EDMAC_H
#define __ARCH_ARM_SRC_KINETIS_KINETIS_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 kinetis_edma_xfrconfig_s config;
* config.saddr = ..;
* config.daddr = ..;
* etc.
*
* 3. Setup the transfer in hardware:
*
* int ret;
* ret = kinetis_dmach_xfrsetup(handle, &config);
*
* 4. If you are setting up a scatter gather DMA
* (with CONFIG_KINETIS_EDMA_NTCD > 0), then repeat steps 2 and 3 for
* each segment of the transfer.
*
* 5. Start the DMA:
*
* ret = kinetis_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.
*
* kinetis_dmach_free(handle);
*
* Almost non-invasive debug instrumentation is available. You may call
* kinetis_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 kinetis_dmadump().
* kinetis_dmasample() is also available for monitoring DMA progress.
*/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdint.h>
#include "hardware/kinetis_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 */
#define EDMA_CONFIG_LOOP_SHIFT (2) /* Bits 2: Loop type */
#define EDMA_CONFIG_LOOP_MASK (3 << EDMA_CONFIG_LOOP_SHIFT)
# define EDMA_CONFIG_LOOPNONE (0 << EDMA_CONFIG_LOOP_SHIFT) /* No looping */
# define EDMA_CONFIG_LOOPSRC (1 << EDMA_CONFIG_LOOP_SHIFT) /* Source looping */
# define EDMA_CONFIG_LOOPDEST (2 << EDMA_CONFIG_LOOP_SHIFT) /* Dest looping */
#define EDMA_CONFIG_INTHALF (1 << 3) /* Bits 3: Int on HALF */
/****************************************************************************
* 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 kinetis_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 */
};
/* eDMA transfer sises */
enum kinetis_edma_sizes_e
{
EDMA_8BIT = 0, /* Transfer data size 8 */
EDMA_16BIT = 1, /* Transfer data size 16 */
EDMA_32BIT = 2, /* Transfer data size 32 */
};
/* This structure holds the source/destination transfer attribute
* configuration.
*/
struct kinetis_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 kinetis_edma_xfrtype_e). */
#ifdef CONFIG_KINETIS_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_KINETIS_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 kinetis_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: kinetis_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/kinetis_dmamux.h.
* Settings include:
*
* DMAMUX_CHCFG_SOURCE Chip-specific DMA source (required)
* 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/kinetis_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 kinetis_dmach_alloc(uint8_t dmamux, uint8_t dchpri);
/****************************************************************************
* Name: kinetis_dmach_free
*
* Description:
* Release a DMA channel.
* NOTE: The 'handle' used in this argument must NEVER be used again
* until kinetis_dmach_alloc() is called again to re-gain a valid handle.
*
* Returned Value:
* None
*
****************************************************************************/
void kinetis_dmach_free(DMACH_HANDLE handle);
/****************************************************************************
* Name: kinetis_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, kinetis_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 kinetis_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 kinetis_dmach_xfrsetup(DMACH_HANDLE *handle,
const struct kinetis_edma_xfrconfig_s *config);
/****************************************************************************
* Name: kinetis_dmach_start
*
* Description:
* Start the DMA transfer by enabling the channel DMA request.
* This function should be called after the final call to
* kinetis_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 kinetis_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 kinetis_dmach_start(DMACH_HANDLE handle,
edma_callback_t callback, void *arg);
/****************************************************************************
* Name: kinetis_dmach_stop
*
* Description:
* Cancel the DMA. After kinetis_dmach_stop() is called, the DMA channel
* is reset, all TCDs are freed, and kinetis_dmarx/txsetup() must be called
* before kinetis_dmach_start() can be called again
*
* Input Parameters:
* handle - DMA channel handle created by kinetis_dmach_alloc()
*
* Returned Value:
* None.
*
****************************************************************************/
void kinetis_dmach_stop(DMACH_HANDLE handle);
/****************************************************************************
* Name: kinetis_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 kinetis_dmach_alloc()
*
* Returned Value:
* Major loop count which has not been transferred yet for the current TCD.
*
****************************************************************************/
unsigned int kinetis_dmach_getcount(DMACH_HANDLE *handle);
/****************************************************************************
* Name: kinetis_dmasample
*
* Description:
* Sample DMA register contents
*
****************************************************************************/
#ifdef CONFIG_DEBUG_DMA
void kinetis_dmasample(DMACH_HANDLE handle, struct kinetis_dmaregs_s *regs);
#else
# define kinetis_dmasample(handle,regs)
#endif
/****************************************************************************
* Name: kinetis_dmadump
*
* Description:
* Dump previously sampled DMA register contents
*
****************************************************************************/
#ifdef CONFIG_DEBUG_DMA
void kinetis_dmadump(const struct kinetis_dmaregs_s *regs, const char *msg);
#else
# define kinetis_dmadump(handle,regs,msg)
#endif
#undef EXTERN
#if defined(__cplusplus)
}
#endif
#endif /* __ASSEMBLY__ */
#endif /* __ARCH_ARM_SRC_KINETIS_KINETIS_EDMAC_H */