dma: add EDMA MCUX support for RT and k6s
tested on mimxrt1060_evt MEMORY_NOCACHE is needed test on frdmk64f special test slot need configure with CONFIG_DMA_TEST_SLOT_START Signed-off-by: Hake Huang <hake.huang@oss.nxp.com>
This commit is contained in:
parent
5582c2f00b
commit
10fc7a38cc
|
@ -218,3 +218,7 @@ arduino_spi: &spi0 {
|
||||||
status = "okay";
|
status = "okay";
|
||||||
bus-speed = <125000>;
|
bus-speed = <125000>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
&edma0 {
|
||||||
|
status = "okay";
|
||||||
|
};
|
||||||
|
|
|
@ -140,4 +140,9 @@ arduino_serial: &lpuart3 {};
|
||||||
status = "okay";
|
status = "okay";
|
||||||
pwr-gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>;
|
pwr-gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>;
|
||||||
cd-gpios = <&gpio2 28 GPIO_ACTIVE_LOW>;
|
cd-gpios = <&gpio2 28 GPIO_ACTIVE_LOW>;
|
||||||
|
status = "okay";
|
||||||
|
};
|
||||||
|
|
||||||
|
&edma0 {
|
||||||
|
status = "okay";
|
||||||
};
|
};
|
||||||
|
|
|
@ -24,3 +24,4 @@ supported:
|
||||||
- sdhc
|
- sdhc
|
||||||
- usb_device
|
- usb_device
|
||||||
- kscan:touch
|
- kscan:touch
|
||||||
|
- dma
|
||||||
|
|
|
@ -11,3 +11,4 @@ zephyr_library_sources_ifdef(CONFIG_DMA_DW dma_dw.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_DMA_NIOS2_MSGDMA dma_nios2_msgdma.c)
|
zephyr_library_sources_ifdef(CONFIG_DMA_NIOS2_MSGDMA dma_nios2_msgdma.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_DMA_SAM0 dma_sam0.c)
|
zephyr_library_sources_ifdef(CONFIG_DMA_SAM0 dma_sam0.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_USERSPACE dma_handlers.c)
|
zephyr_library_sources_ifdef(CONFIG_USERSPACE dma_handlers.c)
|
||||||
|
zephyr_library_sources_ifdef(CONFIG_DMA_MCUX_EDMA dma_mcux_edma.c)
|
||||||
|
|
|
@ -48,4 +48,6 @@ source "drivers/dma/Kconfig.nios2_msgdma"
|
||||||
|
|
||||||
source "drivers/dma/Kconfig.sam0"
|
source "drivers/dma/Kconfig.sam0"
|
||||||
|
|
||||||
|
source "drivers/dma/Kconfig.mcux_edma"
|
||||||
|
|
||||||
endif # DMA
|
endif # DMA
|
||||||
|
|
29
drivers/dma/Kconfig.mcux_edma
Normal file
29
drivers/dma/Kconfig.mcux_edma
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
# DMA configuration options
|
||||||
|
|
||||||
|
# Copyright (c) 2020, NXP
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
config DMA_MCUX_EDMA
|
||||||
|
bool "Enable MCUX DMA driver"
|
||||||
|
depends on HAS_MCUX_EDMA
|
||||||
|
select NOCACHE_MEMORY if HAS_MCUX_CACHE
|
||||||
|
help
|
||||||
|
DMA driver for MCUX series SoCs.
|
||||||
|
|
||||||
|
if DMA_MCUX_EDMA
|
||||||
|
|
||||||
|
config DMA_TCD_QUEUE_SIZE
|
||||||
|
int "number of TCD in a queue for SG mode"
|
||||||
|
default 2
|
||||||
|
help
|
||||||
|
number of TCD in a queue for SG mode
|
||||||
|
|
||||||
|
config DMA_MCUX_TEST_SLOT_START
|
||||||
|
int "test slot start num"
|
||||||
|
depends on SOC_SERIES_KINETIS_K6X
|
||||||
|
default 58
|
||||||
|
help
|
||||||
|
test slot start num
|
||||||
|
|
||||||
|
|
||||||
|
endif # DMA_MCUX_EDMA
|
536
drivers/dma/dma_mcux_edma.c
Normal file
536
drivers/dma/dma_mcux_edma.c
Normal file
|
@ -0,0 +1,536 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 NXP Semiconductor INC.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Common part of DMA drivers for imx rt series.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <soc.h>
|
||||||
|
#include <init.h>
|
||||||
|
#include <kernel.h>
|
||||||
|
#include <devicetree.h>
|
||||||
|
#include <drivers/dma.h>
|
||||||
|
#include <drivers/clock_control.h>
|
||||||
|
|
||||||
|
#include "dma_mcux_edma.h"
|
||||||
|
|
||||||
|
#include <logging/log.h>
|
||||||
|
|
||||||
|
#define DT_DRV_COMPAT nxp_mcux_edma
|
||||||
|
|
||||||
|
LOG_MODULE_REGISTER(dma_mcux_edma, CONFIG_DMA_LOG_LEVEL);
|
||||||
|
|
||||||
|
struct dma_mcux_edma_config {
|
||||||
|
DMA_Type *base;
|
||||||
|
DMAMUX_Type *dmamux_base;
|
||||||
|
void (*irq_config_func)(struct device *dev);
|
||||||
|
};
|
||||||
|
|
||||||
|
static __aligned(32) edma_tcd_t
|
||||||
|
tcdpool[DT_INST_PROP(0, dma_channels)][CONFIG_DMA_TCD_QUEUE_SIZE];
|
||||||
|
|
||||||
|
struct call_back {
|
||||||
|
edma_transfer_config_t transferConfig;
|
||||||
|
edma_handle_t edma_handle;
|
||||||
|
void *callback_arg;
|
||||||
|
void (*dma_callback)(void *callback_arg, uint32_t channel,
|
||||||
|
int error_code);
|
||||||
|
enum dma_channel_direction dir;
|
||||||
|
bool busy;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dma_mcux_edma_data {
|
||||||
|
struct call_back data_cb[DT_INST_PROP(0, dma_channels)];
|
||||||
|
};
|
||||||
|
|
||||||
|
#define DEV_CFG(dev) \
|
||||||
|
((const struct dma_mcux_edma_config *const)dev->config_info)
|
||||||
|
#define DEV_DATA(dev) ((struct dma_mcux_edma_data *)dev->driver_data)
|
||||||
|
#define DEV_BASE(dev) ((DMA_Type *)DEV_CFG(dev)->base)
|
||||||
|
|
||||||
|
#define DEV_DMAMUX_BASE(dev) ((DMAMUX_Type *)DEV_CFG(dev)->dmamux_base)
|
||||||
|
|
||||||
|
#define DEV_CHANNEL_DATA(dev, ch) \
|
||||||
|
((struct call_back *)(&(DEV_DATA(dev)->data_cb[ch])))
|
||||||
|
|
||||||
|
#define DEV_EDMA_HANDLE(dev, ch) \
|
||||||
|
((edma_handle_t *)(&(DEV_CHANNEL_DATA(dev, ch)->edma_handle)))
|
||||||
|
|
||||||
|
static void nxp_edma_callback(edma_handle_t *handle, void *param,
|
||||||
|
bool transferDone, uint32_t tcds)
|
||||||
|
{
|
||||||
|
int ret = 1;
|
||||||
|
struct call_back *data = (struct call_back *)param;
|
||||||
|
uint32_t channel = handle->channel;
|
||||||
|
|
||||||
|
if (transferDone) {
|
||||||
|
data->busy = false;
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
LOG_DBG("transfer %d", tcds);
|
||||||
|
data->dma_callback(data->callback_arg, channel, ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void channel_irq(edma_handle_t *handle)
|
||||||
|
{
|
||||||
|
bool transfer_done;
|
||||||
|
|
||||||
|
/* Clear EDMA interrupt flag */
|
||||||
|
handle->base->CINT = handle->channel;
|
||||||
|
/* Check if transfer is already finished. */
|
||||||
|
transfer_done = ((handle->base->TCD[handle->channel].CSR &
|
||||||
|
DMA_CSR_DONE_MASK) != 0U);
|
||||||
|
|
||||||
|
if (handle->tcdPool == NULL) {
|
||||||
|
(handle->callback)(handle, handle->userData, transfer_done, 0);
|
||||||
|
} else {
|
||||||
|
uint32_t sga = handle->base->TCD[handle->channel].DLAST_SGA;
|
||||||
|
uint32_t sga_index;
|
||||||
|
int32_t tcds_done;
|
||||||
|
uint8_t new_header;
|
||||||
|
|
||||||
|
sga -= (uint32_t)handle->tcdPool;
|
||||||
|
sga_index = sga / sizeof(edma_tcd_t);
|
||||||
|
/* Adjust header positions. */
|
||||||
|
if (transfer_done) {
|
||||||
|
new_header = (uint8_t)sga_index;
|
||||||
|
} else {
|
||||||
|
new_header = sga_index != 0U ?
|
||||||
|
(uint8_t)sga_index - 1U :
|
||||||
|
(uint8_t)handle->tcdSize - 1U;
|
||||||
|
}
|
||||||
|
/* Calculate the number of finished TCDs */
|
||||||
|
if (new_header == (uint8_t)handle->header) {
|
||||||
|
int8_t tmpTcdUsed = handle->tcdUsed;
|
||||||
|
int8_t tmpTcdSize = handle->tcdSize;
|
||||||
|
|
||||||
|
if (tmpTcdUsed == tmpTcdSize) {
|
||||||
|
tcds_done = handle->tcdUsed;
|
||||||
|
} else {
|
||||||
|
tcds_done = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tcds_done = (uint32_t)new_header - (uint32_t)handle->header;
|
||||||
|
if (tcds_done < 0) {
|
||||||
|
tcds_done += handle->tcdSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handle->header = (int8_t)new_header;
|
||||||
|
handle->tcdUsed -= (int8_t)tcds_done;
|
||||||
|
/* Invoke callback function. */
|
||||||
|
if (handle->callback != NULL) {
|
||||||
|
(handle->callback)(handle, handle->userData,
|
||||||
|
transfer_done, tcds_done);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transfer_done) {
|
||||||
|
handle->base->CDNE = handle->channel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dma_mcux_edma_irq_handler(void *arg)
|
||||||
|
{
|
||||||
|
struct device *dev = (struct device *)arg;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
LOG_DBG("IRQ CALLED");
|
||||||
|
for (i = 0; i < DT_INST_PROP(0, dma_channels); i++) {
|
||||||
|
if (DEV_CHANNEL_DATA(dev, i)->busy) {
|
||||||
|
uint32_t flag =
|
||||||
|
EDMA_GetChannelStatusFlags(DEV_BASE(dev), i);
|
||||||
|
if ((flag & (uint32_t)kEDMA_InterruptFlag) != 0U) {
|
||||||
|
LOG_DBG("IRQ OCCURRED");
|
||||||
|
channel_irq(DEV_EDMA_HANDLE(dev, i));
|
||||||
|
LOG_DBG("IRQ DONE");
|
||||||
|
#if defined __CORTEX_M && (__CORTEX_M == 4U)
|
||||||
|
__DSB();
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
LOG_DBG("flag is 0x%x", flag);
|
||||||
|
LOG_DBG("DMA ES 0x%x", DEV_BASE(dev)->ES);
|
||||||
|
LOG_DBG("channel id %d", i);
|
||||||
|
EDMA_ClearChannelStatusFlags(
|
||||||
|
DEV_BASE(dev), i,
|
||||||
|
kEDMA_ErrorFlag | kEDMA_DoneFlag);
|
||||||
|
EDMA_AbortTransfer(DEV_EDMA_HANDLE(dev, i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dma_mcux_edma_error_irq_handler(void *arg)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
uint32_t flag = 0;
|
||||||
|
struct device *dev = (struct device *)arg;
|
||||||
|
|
||||||
|
for (i = 0; i < DT_INST_PROP(0, dma_channels); i++) {
|
||||||
|
if (DEV_CHANNEL_DATA(dev, i)->busy) {
|
||||||
|
flag = EDMA_GetChannelStatusFlags(DEV_BASE(dev), i);
|
||||||
|
LOG_INF("channel %d error status is 0x%x", i, flag);
|
||||||
|
EDMA_ClearChannelStatusFlags(DEV_BASE(dev), i,
|
||||||
|
0xFFFFFFFF);
|
||||||
|
EDMA_AbortTransfer(DEV_EDMA_HANDLE(dev, i));
|
||||||
|
DEV_CHANNEL_DATA(dev, i)->busy = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined __CORTEX_M && (__CORTEX_M == 4U)
|
||||||
|
__DSB();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Configure a channel */
|
||||||
|
static int dma_mcux_edma_configure(struct device *dev, uint32_t channel,
|
||||||
|
struct dma_config *config)
|
||||||
|
{
|
||||||
|
edma_handle_t *p_handle = DEV_EDMA_HANDLE(dev, channel);
|
||||||
|
struct call_back *data = DEV_CHANNEL_DATA(dev, channel);
|
||||||
|
struct dma_block_config *block_config = config->head_block;
|
||||||
|
uint32_t slot = config->dma_slot;
|
||||||
|
edma_transfer_type_t transfer_type;
|
||||||
|
int key;
|
||||||
|
|
||||||
|
if (NULL == dev || NULL == config) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (slot > DT_INST_PROP(0, dma_requests)) {
|
||||||
|
LOG_ERR("source number is outof scope %d", slot);
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (channel > DT_INST_PROP(0, dma_channels)) {
|
||||||
|
LOG_ERR("out of DMA channel %d", channel);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->dir = config->channel_direction;
|
||||||
|
switch (config->channel_direction) {
|
||||||
|
case MEMORY_TO_MEMORY:
|
||||||
|
transfer_type = kEDMA_MemoryToMemory;
|
||||||
|
break;
|
||||||
|
case MEMORY_TO_PERIPHERAL:
|
||||||
|
transfer_type = kEDMA_MemoryToPeripheral;
|
||||||
|
break;
|
||||||
|
case PERIPHERAL_TO_MEMORY:
|
||||||
|
transfer_type = kEDMA_PeripheralToMemory;
|
||||||
|
break;
|
||||||
|
case PERIPHERAL_TO_PERIPHERAL:
|
||||||
|
transfer_type = kEDMA_PeripheralToPeripheral;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_ERR("not support transfer direction");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Lock and page in the channel configuration */
|
||||||
|
key = irq_lock();
|
||||||
|
|
||||||
|
#if DT_INST_PROP(0, nxp_a_on)
|
||||||
|
if (config->source_handshake || config->dest_handshake ||
|
||||||
|
transfer_type == kEDMA_MemoryToMemory) {
|
||||||
|
/*software trigger make the channel always on*/
|
||||||
|
LOG_DBG("ALWAYS ON");
|
||||||
|
DMAMUX_EnableAlwaysOn(DEV_DMAMUX_BASE(dev), channel, true);
|
||||||
|
} else {
|
||||||
|
DMAMUX_SetSource(DEV_DMAMUX_BASE(dev), channel, slot);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
DMAMUX_SetSource(DEV_DMAMUX_BASE(dev), channel, slot);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* dam_imx_rt_set_channel_priority(dev, channel, config); */
|
||||||
|
DMAMUX_EnableChannel(DEV_DMAMUX_BASE(dev), channel);
|
||||||
|
|
||||||
|
if (data->busy) {
|
||||||
|
EDMA_AbortTransfer(p_handle);
|
||||||
|
}
|
||||||
|
EDMA_ResetChannel(DEV_BASE(dev), channel);
|
||||||
|
EDMA_CreateHandle(p_handle, DEV_BASE(dev), channel);
|
||||||
|
EDMA_SetCallback(p_handle, nxp_edma_callback, (void *)data);
|
||||||
|
|
||||||
|
LOG_DBG("channel is %d", p_handle->channel);
|
||||||
|
|
||||||
|
if (config->source_data_size != 4U && config->source_data_size != 2U &&
|
||||||
|
config->source_data_size != 1U && config->source_data_size != 8U &&
|
||||||
|
config->source_data_size != 16U &&
|
||||||
|
config->source_data_size != 32U) {
|
||||||
|
LOG_ERR("Source unit size error, %d", config->source_data_size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config->dest_data_size != 4U && config->dest_data_size != 2U &&
|
||||||
|
config->dest_data_size != 1U && config->dest_data_size != 8U &&
|
||||||
|
config->dest_data_size != 16U && config->dest_data_size != 32U) {
|
||||||
|
LOG_ERR("Dest unit size error, %d", config->dest_data_size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
EDMA_EnableChannelInterrupts(DEV_BASE(dev), channel,
|
||||||
|
kEDMA_ErrorInterruptEnable);
|
||||||
|
|
||||||
|
if (config->source_chaining_en && config->dest_chaining_en) {
|
||||||
|
/*chaining mode only support major link*/
|
||||||
|
LOG_DBG("link major channel %d", config->linked_channel);
|
||||||
|
EDMA_SetChannelLink(DEV_BASE(dev), channel, kEDMA_MajorLink,
|
||||||
|
config->linked_channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (block_config->source_gather_en || block_config->dest_scatter_en) {
|
||||||
|
if (config->block_count > CONFIG_DMA_TCD_QUEUE_SIZE) {
|
||||||
|
LOG_ERR("please config DMA_TCD_QUEUE_SIZE as %d",
|
||||||
|
config->block_count);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
EDMA_InstallTCDMemory(p_handle, tcdpool[channel],
|
||||||
|
CONFIG_DMA_TCD_QUEUE_SIZE);
|
||||||
|
while (block_config != NULL) {
|
||||||
|
EDMA_PrepareTransfer(
|
||||||
|
&(data->transferConfig),
|
||||||
|
(void *)block_config->source_address,
|
||||||
|
config->source_data_size,
|
||||||
|
(void *)block_config->dest_address,
|
||||||
|
config->dest_data_size,
|
||||||
|
config->source_burst_length,
|
||||||
|
block_config->block_size, transfer_type);
|
||||||
|
EDMA_SubmitTransfer(p_handle, &(data->transferConfig));
|
||||||
|
block_config = block_config->next_block;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* block_count shall be 1 */
|
||||||
|
status_t ret;
|
||||||
|
|
||||||
|
EDMA_PrepareTransfer(&(data->transferConfig),
|
||||||
|
(void *)block_config->source_address,
|
||||||
|
config->source_data_size,
|
||||||
|
(void *)block_config->dest_address,
|
||||||
|
config->dest_data_size,
|
||||||
|
config->source_burst_length,
|
||||||
|
block_config->block_size, transfer_type);
|
||||||
|
|
||||||
|
ret = EDMA_SubmitTransfer(p_handle, &(data->transferConfig));
|
||||||
|
edma_tcd_t *tcdRegs =
|
||||||
|
(edma_tcd_t *)(uint32_t)&p_handle->base->TCD[channel];
|
||||||
|
if (ret != kStatus_Success) {
|
||||||
|
LOG_ERR("submit error 0x%x", ret);
|
||||||
|
}
|
||||||
|
LOG_DBG("data csr is 0x%x", tcdRegs->CSR);
|
||||||
|
}
|
||||||
|
|
||||||
|
data->busy = false;
|
||||||
|
if (config->dma_callback) {
|
||||||
|
LOG_DBG("INSTALL call back on channel %d", channel);
|
||||||
|
data->callback_arg = config->callback_arg;
|
||||||
|
data->dma_callback = config->dma_callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
irq_unlock(key);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dma_mcux_edma_start(struct device *dev, uint32_t channel)
|
||||||
|
{
|
||||||
|
struct call_back *data = DEV_CHANNEL_DATA(dev, channel);
|
||||||
|
|
||||||
|
LOG_DBG("START TRANSFER");
|
||||||
|
LOG_DBG("DMAMUX CHCFG 0x%x", DEV_DMAMUX_BASE(dev)->CHCFG[channel]);
|
||||||
|
LOG_DBG("DMA CR 0x%x", DEV_BASE(dev)->CR);
|
||||||
|
data->busy = true;
|
||||||
|
EDMA_StartTransfer(DEV_EDMA_HANDLE(dev, channel));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dma_mcux_edma_stop(struct device *dev, uint32_t channel)
|
||||||
|
{
|
||||||
|
struct dma_mcux_edma_data *data = DEV_DATA(dev);
|
||||||
|
|
||||||
|
if (!data->data_cb[channel].busy) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EDMA_AbortTransfer(DEV_EDMA_HANDLE(dev, channel));
|
||||||
|
EDMA_ClearChannelStatusFlags(DEV_BASE(dev), channel,
|
||||||
|
kEDMA_DoneFlag | kEDMA_ErrorFlag |
|
||||||
|
kEDMA_InterruptFlag);
|
||||||
|
EDMA_ResetChannel(DEV_BASE(dev), channel);
|
||||||
|
data->data_cb[channel].busy = false;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dma_mcux_edma_reload(struct device *dev, uint32_t channel,
|
||||||
|
uint32_t src, uint32_t dst, size_t size)
|
||||||
|
{
|
||||||
|
struct call_back *data = DEV_CHANNEL_DATA(dev, channel);
|
||||||
|
|
||||||
|
if (data->busy) {
|
||||||
|
EDMA_AbortTransfer(DEV_EDMA_HANDLE(dev, channel));
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dma_mcux_edma_get_status(struct device *dev, uint32_t channel,
|
||||||
|
struct dma_status *status)
|
||||||
|
{
|
||||||
|
edma_tcd_t *tcdRegs;
|
||||||
|
|
||||||
|
if (DEV_CHANNEL_DATA(dev, channel)->busy) {
|
||||||
|
status->busy = true;
|
||||||
|
status->pending_length =
|
||||||
|
EDMA_GetRemainingMajorLoopCount(DEV_BASE(dev), channel);
|
||||||
|
} else {
|
||||||
|
status->busy = false;
|
||||||
|
status->pending_length = 0;
|
||||||
|
}
|
||||||
|
status->dir = DEV_CHANNEL_DATA(dev, channel)->dir;
|
||||||
|
LOG_DBG("DMAMUX CHCFG 0x%x", DEV_DMAMUX_BASE(dev)->CHCFG[channel]);
|
||||||
|
LOG_DBG("DMA CR 0x%x", DEV_BASE(dev)->CR);
|
||||||
|
LOG_DBG("DMA INT 0x%x", DEV_BASE(dev)->INT);
|
||||||
|
LOG_DBG("DMA ERQ 0x%x", DEV_BASE(dev)->ERQ);
|
||||||
|
LOG_DBG("DMA ES 0x%x", DEV_BASE(dev)->ES);
|
||||||
|
LOG_DBG("DMA ERR 0x%x", DEV_BASE(dev)->ERR);
|
||||||
|
LOG_DBG("DMA HRS 0x%x", DEV_BASE(dev)->HRS);
|
||||||
|
tcdRegs = (edma_tcd_t *)((uint32_t)&DEV_BASE(dev)->TCD[channel]);
|
||||||
|
LOG_DBG("data csr is 0x%x", tcdRegs->CSR);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct dma_driver_api dma_mcux_edma_api = {
|
||||||
|
.reload = dma_mcux_edma_reload,
|
||||||
|
.config = dma_mcux_edma_configure,
|
||||||
|
.start = dma_mcux_edma_start,
|
||||||
|
.stop = dma_mcux_edma_stop,
|
||||||
|
.get_status = dma_mcux_edma_get_status,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int dma_mcux_edma_init(struct device *dev)
|
||||||
|
{
|
||||||
|
edma_config_t userConfig = { 0 };
|
||||||
|
|
||||||
|
LOG_DBG("INIT NXP EDMA");
|
||||||
|
DMAMUX_Init(DEV_DMAMUX_BASE(dev));
|
||||||
|
EDMA_GetDefaultConfig(&userConfig);
|
||||||
|
EDMA_Init(DEV_BASE(dev), &userConfig);
|
||||||
|
DEV_CFG(dev)->irq_config_func(dev);
|
||||||
|
memset(DEV_DATA(dev), 0, sizeof(struct dma_mcux_edma_data));
|
||||||
|
memset(tcdpool, 0, sizeof(tcdpool));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dma_imx_config_func_0(struct device *dev);
|
||||||
|
|
||||||
|
static const struct dma_mcux_edma_config dma_config_0 = {
|
||||||
|
.base = (DMA_Type *)DT_INST_REG_ADDR(0),
|
||||||
|
.dmamux_base = (DMAMUX_Type *)DT_INST_REG_ADDR_BY_IDX(0, 1),
|
||||||
|
.irq_config_func = dma_imx_config_func_0,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dma_mcux_edma_data dma_data;
|
||||||
|
/*
|
||||||
|
* define the dma
|
||||||
|
*/
|
||||||
|
DEVICE_AND_API_INIT(dma_mcux_edma_0, CONFIG_DMA_0_NAME, &dma_mcux_edma_init,
|
||||||
|
&dma_data, &dma_config_0, POST_KERNEL,
|
||||||
|
CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &dma_mcux_edma_api);
|
||||||
|
|
||||||
|
void dma_imx_config_func_0(struct device *dev)
|
||||||
|
{
|
||||||
|
ARG_UNUSED(dev);
|
||||||
|
|
||||||
|
/*install the dma error handle*/
|
||||||
|
|
||||||
|
IRQ_CONNECT(DT_INST_IRQ_BY_IDX(0, 0, irq),
|
||||||
|
DT_INST_IRQ_BY_IDX(0, 0, priority),
|
||||||
|
dma_mcux_edma_irq_handler, DEVICE_GET(dma_mcux_edma_0), 0);
|
||||||
|
irq_enable(DT_INST_IRQ_BY_IDX(0, 0, irq));
|
||||||
|
|
||||||
|
IRQ_CONNECT(DT_INST_IRQ_BY_IDX(0, 1, irq),
|
||||||
|
DT_INST_IRQ_BY_IDX(0, 1, priority),
|
||||||
|
dma_mcux_edma_irq_handler, DEVICE_GET(dma_mcux_edma_0), 0);
|
||||||
|
irq_enable(DT_INST_IRQ_BY_IDX(0, 1, irq));
|
||||||
|
|
||||||
|
IRQ_CONNECT(DT_INST_IRQ_BY_IDX(0, 2, irq),
|
||||||
|
DT_INST_IRQ_BY_IDX(0, 2, priority),
|
||||||
|
dma_mcux_edma_irq_handler, DEVICE_GET(dma_mcux_edma_0), 0);
|
||||||
|
irq_enable(DT_INST_IRQ_BY_IDX(0, 2, irq));
|
||||||
|
|
||||||
|
IRQ_CONNECT(DT_INST_IRQ_BY_IDX(0, 3, irq),
|
||||||
|
DT_INST_IRQ_BY_IDX(0, 3, priority),
|
||||||
|
dma_mcux_edma_irq_handler, DEVICE_GET(dma_mcux_edma_0), 0);
|
||||||
|
irq_enable(DT_INST_IRQ_BY_IDX(0, 3, irq));
|
||||||
|
|
||||||
|
IRQ_CONNECT(DT_INST_IRQ_BY_IDX(0, 4, irq),
|
||||||
|
DT_INST_IRQ_BY_IDX(0, 4, priority),
|
||||||
|
dma_mcux_edma_irq_handler, DEVICE_GET(dma_mcux_edma_0), 0);
|
||||||
|
irq_enable(DT_INST_IRQ_BY_IDX(0, 4, irq));
|
||||||
|
|
||||||
|
IRQ_CONNECT(DT_INST_IRQ_BY_IDX(0, 5, irq),
|
||||||
|
DT_INST_IRQ_BY_IDX(0, 5, priority),
|
||||||
|
dma_mcux_edma_irq_handler, DEVICE_GET(dma_mcux_edma_0), 0);
|
||||||
|
irq_enable(DT_INST_IRQ_BY_IDX(0, 5, irq));
|
||||||
|
|
||||||
|
IRQ_CONNECT(DT_INST_IRQ_BY_IDX(0, 6, irq),
|
||||||
|
DT_INST_IRQ_BY_IDX(0, 6, priority),
|
||||||
|
dma_mcux_edma_irq_handler, DEVICE_GET(dma_mcux_edma_0), 0);
|
||||||
|
irq_enable(DT_INST_IRQ_BY_IDX(0, 6, irq));
|
||||||
|
|
||||||
|
IRQ_CONNECT(DT_INST_IRQ_BY_IDX(0, 7, irq),
|
||||||
|
DT_INST_IRQ_BY_IDX(0, 7, priority),
|
||||||
|
dma_mcux_edma_irq_handler, DEVICE_GET(dma_mcux_edma_0), 0);
|
||||||
|
irq_enable(DT_INST_IRQ_BY_IDX(0, 7, irq));
|
||||||
|
|
||||||
|
IRQ_CONNECT(DT_INST_IRQ_BY_IDX(0, 8, irq),
|
||||||
|
DT_INST_IRQ_BY_IDX(0, 8, priority),
|
||||||
|
dma_mcux_edma_irq_handler, DEVICE_GET(dma_mcux_edma_0), 0);
|
||||||
|
irq_enable(DT_INST_IRQ_BY_IDX(0, 8, irq));
|
||||||
|
|
||||||
|
IRQ_CONNECT(DT_INST_IRQ_BY_IDX(0, 9, irq),
|
||||||
|
DT_INST_IRQ_BY_IDX(0, 9, priority),
|
||||||
|
dma_mcux_edma_irq_handler, DEVICE_GET(dma_mcux_edma_0), 0);
|
||||||
|
irq_enable(DT_INST_IRQ_BY_IDX(0, 9, irq));
|
||||||
|
|
||||||
|
IRQ_CONNECT(DT_INST_IRQ_BY_IDX(0, 10, irq),
|
||||||
|
DT_INST_IRQ_BY_IDX(0, 10, priority),
|
||||||
|
dma_mcux_edma_irq_handler, DEVICE_GET(dma_mcux_edma_0), 0);
|
||||||
|
irq_enable(DT_INST_IRQ_BY_IDX(0, 10, irq));
|
||||||
|
|
||||||
|
IRQ_CONNECT(DT_INST_IRQ_BY_IDX(0, 11, irq),
|
||||||
|
DT_INST_IRQ_BY_IDX(0, 11, priority),
|
||||||
|
dma_mcux_edma_irq_handler, DEVICE_GET(dma_mcux_edma_0), 0);
|
||||||
|
irq_enable(DT_INST_IRQ_BY_IDX(0, 11, irq));
|
||||||
|
|
||||||
|
IRQ_CONNECT(DT_INST_IRQ_BY_IDX(0, 12, irq),
|
||||||
|
DT_INST_IRQ_BY_IDX(0, 12, priority),
|
||||||
|
dma_mcux_edma_irq_handler, DEVICE_GET(dma_mcux_edma_0), 0);
|
||||||
|
irq_enable(DT_INST_IRQ_BY_IDX(0, 12, irq));
|
||||||
|
|
||||||
|
IRQ_CONNECT(DT_INST_IRQ_BY_IDX(0, 13, irq),
|
||||||
|
DT_INST_IRQ_BY_IDX(0, 13, priority),
|
||||||
|
dma_mcux_edma_irq_handler, DEVICE_GET(dma_mcux_edma_0), 0);
|
||||||
|
irq_enable(DT_INST_IRQ_BY_IDX(0, 13, irq));
|
||||||
|
|
||||||
|
IRQ_CONNECT(DT_INST_IRQ_BY_IDX(0, 14, irq),
|
||||||
|
DT_INST_IRQ_BY_IDX(0, 14, priority),
|
||||||
|
dma_mcux_edma_irq_handler, DEVICE_GET(dma_mcux_edma_0), 0);
|
||||||
|
irq_enable(DT_INST_IRQ_BY_IDX(0, 14, irq));
|
||||||
|
|
||||||
|
IRQ_CONNECT(DT_INST_IRQ_BY_IDX(0, 15, irq),
|
||||||
|
DT_INST_IRQ_BY_IDX(0, 15, priority),
|
||||||
|
dma_mcux_edma_irq_handler, DEVICE_GET(dma_mcux_edma_0), 0);
|
||||||
|
irq_enable(DT_INST_IRQ_BY_IDX(0, 15, irq));
|
||||||
|
|
||||||
|
IRQ_CONNECT(DT_INST_IRQ_BY_IDX(0, 16, irq),
|
||||||
|
DT_INST_IRQ_BY_IDX(0, 16, priority),
|
||||||
|
dma_mcux_edma_error_irq_handler,
|
||||||
|
DEVICE_GET(dma_mcux_edma_0), 0);
|
||||||
|
irq_enable(DT_INST_IRQ_BY_IDX(0, 16, irq));
|
||||||
|
|
||||||
|
LOG_DBG("install irq done");
|
||||||
|
}
|
20
drivers/dma/dma_mcux_edma.h
Normal file
20
drivers/dma/dma_mcux_edma.h
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 NXP Semiconductor INC.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DMA_MCUX_EDMA_H_
|
||||||
|
#define DMA_MCUX_EDMA_H_
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <device.h>
|
||||||
|
#include <drivers/dma.h>
|
||||||
|
#include <soc.h>
|
||||||
|
#include <fsl_common.h>
|
||||||
|
|
||||||
|
#include "fsl_edma.h"
|
||||||
|
#include "fsl_dmamux.h"
|
||||||
|
|
||||||
|
#endif /* DMA_MCUX_EDMA_H_*/
|
|
@ -194,4 +194,9 @@ config HAS_MCUX_TPM
|
||||||
help
|
help
|
||||||
Set if the Timer/PWM Module is present in the SoC
|
Set if the Timer/PWM Module is present in the SoC
|
||||||
|
|
||||||
|
config HAS_MCUX_EDMA
|
||||||
|
bool
|
||||||
|
help
|
||||||
|
Set if the EDMA module is present on the SoC.
|
||||||
|
|
||||||
endif # HAS_MCUX
|
endif # HAS_MCUX
|
||||||
|
|
|
@ -136,6 +136,10 @@ config VIDEO_MCUX_CSI
|
||||||
default y if HAS_MCUX_CSI
|
default y if HAS_MCUX_CSI
|
||||||
depends on VIDEO
|
depends on VIDEO
|
||||||
|
|
||||||
|
config DMA_MCUX_EDMA
|
||||||
|
default y if HAS_MCUX_EDMA
|
||||||
|
depends on DMA
|
||||||
|
|
||||||
source "soc/arm/nxp_imx/rt/Kconfig.defconfig.mimxrt*"
|
source "soc/arm/nxp_imx/rt/Kconfig.defconfig.mimxrt*"
|
||||||
|
|
||||||
endif # SOC_SERIES_IMX_RT
|
endif # SOC_SERIES_IMX_RT
|
||||||
|
|
|
@ -25,6 +25,7 @@ config SOC_MIMXRT1011
|
||||||
select HAS_MCUX_USB_EHCI
|
select HAS_MCUX_USB_EHCI
|
||||||
select HAS_MCUX_USDHC1
|
select HAS_MCUX_USDHC1
|
||||||
select HAS_MCUX_USDHC2
|
select HAS_MCUX_USDHC2
|
||||||
|
select HAS_MCUX_EDMA
|
||||||
|
|
||||||
config SOC_MIMXRT1015
|
config SOC_MIMXRT1015
|
||||||
bool "SOC_MIMXRT1015"
|
bool "SOC_MIMXRT1015"
|
||||||
|
@ -45,6 +46,7 @@ config SOC_MIMXRT1015
|
||||||
select HAS_MCUX_USB_EHCI
|
select HAS_MCUX_USB_EHCI
|
||||||
select HAS_MCUX_USDHC1
|
select HAS_MCUX_USDHC1
|
||||||
select HAS_MCUX_USDHC2
|
select HAS_MCUX_USDHC2
|
||||||
|
select HAS_MCUX_EDMA
|
||||||
|
|
||||||
config SOC_MIMXRT1021
|
config SOC_MIMXRT1021
|
||||||
bool "SOC_MIMXRT1021"
|
bool "SOC_MIMXRT1021"
|
||||||
|
@ -66,6 +68,7 @@ config SOC_MIMXRT1021
|
||||||
select HAS_MCUX_USB_EHCI
|
select HAS_MCUX_USB_EHCI
|
||||||
select HAS_MCUX_USDHC1
|
select HAS_MCUX_USDHC1
|
||||||
select HAS_MCUX_USDHC2
|
select HAS_MCUX_USDHC2
|
||||||
|
select HAS_MCUX_EDMA
|
||||||
|
|
||||||
config SOC_MIMXRT1051
|
config SOC_MIMXRT1051
|
||||||
bool "SOC_MIMXRT1051"
|
bool "SOC_MIMXRT1051"
|
||||||
|
@ -88,6 +91,7 @@ config SOC_MIMXRT1051
|
||||||
select HAS_MCUX_USDHC1
|
select HAS_MCUX_USDHC1
|
||||||
select HAS_MCUX_USDHC2
|
select HAS_MCUX_USDHC2
|
||||||
select HAS_MCUX_CSI
|
select HAS_MCUX_CSI
|
||||||
|
select HAS_MCUX_EDMA
|
||||||
|
|
||||||
config SOC_MIMXRT1052
|
config SOC_MIMXRT1052
|
||||||
bool "SOC_MIMXRT1052"
|
bool "SOC_MIMXRT1052"
|
||||||
|
@ -113,6 +117,7 @@ config SOC_MIMXRT1052
|
||||||
select HAS_MCUX_USDHC1
|
select HAS_MCUX_USDHC1
|
||||||
select HAS_MCUX_USDHC2
|
select HAS_MCUX_USDHC2
|
||||||
select HAS_MCUX_CSI
|
select HAS_MCUX_CSI
|
||||||
|
select HAS_MCUX_EDMA
|
||||||
|
|
||||||
config SOC_MIMXRT1061
|
config SOC_MIMXRT1061
|
||||||
bool "SOC_MIMXRT1061"
|
bool "SOC_MIMXRT1061"
|
||||||
|
@ -134,6 +139,7 @@ config SOC_MIMXRT1061
|
||||||
select HAS_MCUX_USDHC1
|
select HAS_MCUX_USDHC1
|
||||||
select HAS_MCUX_USDHC2
|
select HAS_MCUX_USDHC2
|
||||||
select HAS_MCUX_CSI
|
select HAS_MCUX_CSI
|
||||||
|
select HAS_MCUX_EDMA
|
||||||
|
|
||||||
config SOC_MIMXRT1062
|
config SOC_MIMXRT1062
|
||||||
bool "SOC_MIMXRT1062"
|
bool "SOC_MIMXRT1062"
|
||||||
|
@ -159,6 +165,7 @@ config SOC_MIMXRT1062
|
||||||
select HAS_MCUX_USDHC1
|
select HAS_MCUX_USDHC1
|
||||||
select HAS_MCUX_USDHC2
|
select HAS_MCUX_USDHC2
|
||||||
select HAS_MCUX_CSI
|
select HAS_MCUX_CSI
|
||||||
|
select HAS_MCUX_EDMA
|
||||||
|
|
||||||
config SOC_MIMXRT1064
|
config SOC_MIMXRT1064
|
||||||
bool "SOC_MIMXRT1064"
|
bool "SOC_MIMXRT1064"
|
||||||
|
@ -184,6 +191,7 @@ config SOC_MIMXRT1064
|
||||||
select HAS_MCUX_USDHC1
|
select HAS_MCUX_USDHC1
|
||||||
select HAS_MCUX_USDHC2
|
select HAS_MCUX_USDHC2
|
||||||
select HAS_MCUX_CSI
|
select HAS_MCUX_CSI
|
||||||
|
select HAS_MCUX_EDMA
|
||||||
|
|
||||||
endchoice
|
endchoice
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,10 @@ config NUM_IRQS
|
||||||
config CPU_HAS_CUSTOM_FIXED_SOC_MPU_REGIONS
|
config CPU_HAS_CUSTOM_FIXED_SOC_MPU_REGIONS
|
||||||
default y
|
default y
|
||||||
|
|
||||||
|
config DMA_MCUX_EDMA
|
||||||
|
default y if HAS_MCUX_EDMA
|
||||||
|
depends on DMA
|
||||||
|
|
||||||
source "soc/arm/nxp_kinetis/k6x/Kconfig.defconfig.mk*"
|
source "soc/arm/nxp_kinetis/k6x/Kconfig.defconfig.mk*"
|
||||||
|
|
||||||
endif # SOC_SERIES_KINETIS_K6X
|
endif # SOC_SERIES_KINETIS_K6X
|
||||||
|
|
|
@ -22,6 +22,7 @@ config SOC_MK64F12
|
||||||
select CPU_HAS_FPU
|
select CPU_HAS_FPU
|
||||||
select HAS_MCUX_RTC
|
select HAS_MCUX_RTC
|
||||||
select HAS_MCUX_DAC
|
select HAS_MCUX_DAC
|
||||||
|
select HAS_MCUX_EDMA
|
||||||
|
|
||||||
config SOC_MK66F18
|
config SOC_MK66F18
|
||||||
bool "SOC_MK66F18"
|
bool "SOC_MK66F18"
|
||||||
|
@ -37,6 +38,7 @@ config SOC_MK66F18
|
||||||
select HAS_MCG
|
select HAS_MCG
|
||||||
select CPU_HAS_FPU
|
select CPU_HAS_FPU
|
||||||
select HAS_MCUX_RTC
|
select HAS_MCUX_RTC
|
||||||
|
select HAS_MCUX_EDMA
|
||||||
|
|
||||||
endchoice
|
endchoice
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue