Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions boards/nxp/frdm_mcxw71/frdm_mcxw71.dts
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,10 @@
status = "okay";
};

&edma {
status = "okay";
};

&tpm0 {
status = "okay";
pinctrl-0 = <&pinmux_tpm0>;
Expand Down
1 change: 1 addition & 0 deletions boards/nxp/frdm_mcxw71/frdm_mcxw71.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ supported:
- adc
- can
- counter
- dma
- flash
- flexio
- gpio
Expand Down
4 changes: 4 additions & 0 deletions boards/nxp/frdm_mcxw72/frdm_mcxw72_mcxw727c_cpu0.dts
Original file line number Diff line number Diff line change
Expand Up @@ -191,3 +191,7 @@
reg = <0x19>;
};
};

&edma {
status = "okay";
};
1 change: 1 addition & 0 deletions boards/nxp/frdm_mcxw72/frdm_mcxw72_mcxw727c_cpu0.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ supported:
- adc
- can
- counter
- dma
- gpio
- flexio
- i2c
Expand Down
233 changes: 164 additions & 69 deletions drivers/dma/dma_mcux_edma.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ struct dma_mcux_channel_transfer_edma_settings {
uint32_t source_data_size;
uint32_t dest_data_size;
uint32_t source_burst_length;
uint32_t dest_burst_length;
enum dma_channel_direction direction;
edma_transfer_type_t transfer_type;
bool valid;
Expand Down Expand Up @@ -280,15 +279,16 @@ static void dma_mcux_edma_multi_channels_irq_handler(const struct device *dev, u

#if defined(FSL_FEATURE_SOC_DMAMUX_COUNT) && FSL_FEATURE_SOC_DMAMUX_COUNT
static void edma_configure_dmamux(const struct device *dev, uint32_t channel,
struct dma_config *config, edma_transfer_type_t transfer_type)
struct dma_config *config)
{
uint8_t dmamux_channel = DEV_DMAMUX_CHANNEL(dev, channel);
uint8_t dmamux_idx = DEV_DMAMUX_IDX(dev, channel);
uint32_t slot = config->dma_slot;
uint8_t dmamux_idx, dmamux_channel;

dmamux_idx = DEV_DMAMUX_IDX(dev, channel);
dmamux_channel = DEV_DMAMUX_CHANNEL(dev, channel);

#if DT_INST_PROP(0, nxp_a_on)
struct call_back *data = DEV_CHANNEL_DATA(dev, channel);
edma_transfer_type_t transfer_type = data->transfer_settings.transfer_type;

if (config->source_handshake || config->dest_handshake ||
transfer_type == kEDMA_MemoryToMemory) {
/*software trigger make the channel always on*/
Expand Down Expand Up @@ -317,6 +317,22 @@ static void edma_log_dmamux(const struct device *dev, uint32_t channel)
#define edma_log_dmamux(...)
#endif /* FSL_FEATURE_SOC_DMA_MUX_COUNT */

static inline void dma_mcux_edma_configure_muxes(const struct device *dev, uint32_t channel,
struct dma_config *config)
{
edma_configure_dmamux(dev, channel, config);

#if defined(FSL_FEATURE_EDMA_HAS_CHANNEL_MUX) && FSL_FEATURE_EDMA_HAS_CHANNEL_MUX
uint32_t slot = config->dma_slot;
uint32_t hw_channel = dma_mcux_edma_add_channel_gap(dev, channel);

/* First release any peripheral previously associated with this channel */
EDMA_SetChannelMux(DEV_BASE(dev), hw_channel, 0);
EDMA_SetChannelMux(DEV_BASE(dev), hw_channel, slot);
#endif
}


static int dma_mcux_edma_configure_sg_loop(const struct device *dev,
uint32_t channel,
struct dma_config *config,
Expand Down Expand Up @@ -445,6 +461,7 @@ static int dma_mcux_edma_configure_basic(const struct device *dev,
{
edma_handle_t *p_handle = DEV_EDMA_HANDLE(dev, channel);
struct call_back *data = DEV_CHANNEL_DATA(dev, channel);
struct dma_mcux_channel_transfer_edma_settings *xfer_settings = &data->transfer_settings;
struct dma_block_config *block_config = config->head_block;
uint32_t hw_channel;
int ret = 0;
Expand All @@ -456,7 +473,7 @@ static int dma_mcux_edma_configure_basic(const struct device *dev,
config->source_data_size,
(void *)block_config->dest_address,
config->dest_data_size,
config->source_burst_length,
xfer_settings->source_burst_length,
block_config->block_size, transfer_type);

const status_t submit_status = EDMA_SubmitTransfer(p_handle, &(data->transferConfig));
Expand All @@ -471,24 +488,62 @@ static int dma_mcux_edma_configure_basic(const struct device *dev,
return ret;
}

/* Configure a channel */
static int dma_mcux_edma_configure(const struct device *dev, uint32_t channel,
struct dma_config *config)
static int dma_mcux_edma_configure_hardware(const struct device *dev, uint32_t channel,
struct dma_config *config)
{
struct call_back *data = DEV_CHANNEL_DATA(dev, channel);
edma_transfer_type_t transfer_type = data->transfer_settings.transfer_type;
struct dma_block_config *block_config = config->head_block;
bool sg_mode = block_config->source_gather_en || block_config->dest_scatter_en;
uint32_t hw_channel = dma_mcux_edma_add_channel_gap(dev, channel);

dma_mcux_edma_configure_muxes(dev, channel, config);

#if defined(CONFIG_DMA_MCUX_EDMA_V3) && \
(!defined(FSL_FEATURE_SOC_DMAMUX_COUNT) || (FSL_FEATURE_SOC_DMAMUX_COUNT == 0))
if (transfer_type == kEDMA_MemoryToMemory && (sg_mode || config->block_count > 1)) {
LOG_WRN("mem2mem xfer scatter gather not supported");
return -ENOTSUP;
}
#endif

if (sg_mode && config->cyclic) {
dma_mcux_edma_configure_sg_loop(dev, channel, config, transfer_type);
} else if (sg_mode) {
dma_mcux_edma_configure_sg_dynamic(dev, channel, config, transfer_type);
} else {
dma_mcux_edma_configure_basic(dev, channel, config, transfer_type);
}

if (config->dest_chaining_en) {
LOG_DBG("link major channel %d", config->linked_channel);
EDMA_SetChannelLink(DEV_BASE(dev), channel, kEDMA_MajorLink,
config->linked_channel);
}
if (config->source_chaining_en) {
LOG_DBG("link minor channel %d", config->linked_channel);
EDMA_SetChannelLink(DEV_BASE(dev), channel, kEDMA_MinorLink,
config->linked_channel);
}

EDMA_EnableChannelInterrupts(DEV_BASE(dev), hw_channel, kEDMA_ErrorInterruptEnable);

return 0;
}

static inline int dma_mcux_edma_validate_cfg(const struct device *dev,
uint32_t channel,
struct dma_config *config)
{
/* Check for invalid parameters before dereferencing them. */
if (NULL == dev || NULL == config) {
return -EINVAL;
}

uint32_t hw_channel = dma_mcux_edma_add_channel_gap(dev, channel);
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;
bool sg_mode = block_config->source_gather_en || block_config->dest_scatter_en;
uint32_t slot = config->dma_slot;
edma_transfer_type_t transfer_type;
unsigned int key;
int ret = 0;
edma_transfer_type_t *type = &data->transfer_settings.transfer_type;

if (slot >= DEV_CFG(dev)->dma_requests) {
LOG_ERR("source number is out of scope %d", slot);
Expand All @@ -499,27 +554,10 @@ static int dma_mcux_edma_configure(const struct device *dev, uint32_t channel,
LOG_ERR("out of DMA channel %d", channel);
return -EINVAL;
}
LOG_DBG("channel is %d", channel);

data->transfer_settings.valid = false;

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;
}

if (!data_size_valid(config->source_data_size)) {
LOG_ERR("Source unit size error, %d", config->source_data_size);
return -EINVAL;
Expand All @@ -537,60 +575,99 @@ static int dma_mcux_edma_configure(const struct device *dev, uint32_t channel,
}
}

data->transfer_settings.source_data_size = config->source_data_size;
data->transfer_settings.dest_data_size = config->dest_data_size;
data->transfer_settings.source_burst_length = config->source_burst_length;
data->transfer_settings.dest_burst_length = config->dest_burst_length;
data->transfer_settings.direction = config->channel_direction;
data->transfer_settings.transfer_type = transfer_type;
data->transfer_settings.valid = true;
data->transfer_settings.cyclic = config->cyclic;
switch (config->channel_direction) {
case MEMORY_TO_MEMORY:
*type = kEDMA_MemoryToMemory;
break;
case MEMORY_TO_PERIPHERAL:
*type = kEDMA_MemoryToPeripheral;
break;
case PERIPHERAL_TO_MEMORY:
*type = kEDMA_PeripheralToMemory;
break;
case PERIPHERAL_TO_PERIPHERAL:
*type = kEDMA_PeripheralToPeripheral;
break;
default:
LOG_ERR("not support transfer direction");
return -EINVAL;
}

/* Lock and page in the channel configuration */
key = irq_lock();
return 0;
}

edma_configure_dmamux(dev, channel, config, transfer_type);
/* fills out transfer settings struct based on api config */
static inline void dma_mcux_edma_set_xfer_settings(const struct device *dev, uint32_t channel,
struct dma_config *config)
{
struct call_back *data = DEV_CHANNEL_DATA(dev, channel);
struct dma_mcux_channel_transfer_edma_settings *xfer_settings = &data->transfer_settings;

xfer_settings->source_burst_length = config->source_burst_length;
#if defined(CONFIG_DMA_MCUX_EDMA_V3) && \
(!defined(FSL_FEATURE_SOC_DMAMUX_COUNT) || (FSL_FEATURE_SOC_DMAMUX_COUNT == 0))
struct dma_block_config *block_config = config->head_block;

if (xfer_settings->transfer_type == kEDMA_MemoryToMemory) {
xfer_settings->source_burst_length = block_config->block_size;

}
#endif
xfer_settings->source_data_size = config->source_data_size;
xfer_settings->dest_data_size = config->dest_data_size;
xfer_settings->direction = config->channel_direction;
xfer_settings->valid = true;
xfer_settings->cyclic = config->cyclic;
}

/* stops, resets, and creates new MCUX SDK handle for a channel */
static inline void dma_mcux_edma_reset_channel(const struct device *dev, uint32_t channel)
{
struct call_back *data = DEV_CHANNEL_DATA(dev, channel);
edma_handle_t *p_handle = DEV_EDMA_HANDLE(dev, channel);
uint32_t hw_channel = dma_mcux_edma_add_channel_gap(dev, channel);

if (data->busy) {
EDMA_AbortTransfer(p_handle);
}

EDMA_ResetChannel(DEV_BASE(dev), hw_channel);
EDMA_CreateHandle(p_handle, DEV_BASE(dev), hw_channel);
EDMA_SetCallback(p_handle, nxp_edma_callback, (void *)data);
}

#if defined(FSL_FEATURE_EDMA_HAS_CHANNEL_MUX) && FSL_FEATURE_EDMA_HAS_CHANNEL_MUX
/* First release any peripheral previously associated with this channel */
EDMA_SetChannelMux(DEV_BASE(dev), hw_channel, 0);
EDMA_SetChannelMux(DEV_BASE(dev), hw_channel, slot);
#endif

LOG_DBG("channel is %d", channel);
EDMA_EnableChannelInterrupts(DEV_BASE(dev), hw_channel, kEDMA_ErrorInterruptEnable);
/* Configure a channel */
static int dma_mcux_edma_configure(const struct device *dev, uint32_t channel,
struct dma_config *config)
{
unsigned int key;
int ret = 0;

ret = dma_mcux_edma_validate_cfg(dev, channel, config);
if (ret) {
return ret;
}

dma_mcux_edma_set_xfer_settings(dev, channel, config);

/* Lock and page in the channel configuration */
key = irq_lock();

dma_mcux_edma_reset_channel(dev, channel);

/* Initialize all TCD pool as 0*/
for (int i = 0; i < CONFIG_DMA_TCD_QUEUE_SIZE; i++) {
memset(&DEV_CFG(dev)->tcdpool[channel][i], 0,
sizeof(DEV_CFG(dev)->tcdpool[channel][i]));
}

if (sg_mode && config->cyclic) {
dma_mcux_edma_configure_sg_loop(dev, channel, config, transfer_type);
} else if (sg_mode) {
dma_mcux_edma_configure_sg_dynamic(dev, channel, config, transfer_type);
} else {
dma_mcux_edma_configure_basic(dev, channel, config, transfer_type);
ret = dma_mcux_edma_configure_hardware(dev, channel, config);
if (ret) {
return ret;
}

if (config->dest_chaining_en) {
LOG_DBG("link major channel %d", config->linked_channel);
EDMA_SetChannelLink(DEV_BASE(dev), channel, kEDMA_MajorLink,
config->linked_channel);
}
if (config->source_chaining_en) {
LOG_DBG("link minor channel %d", config->linked_channel);
EDMA_SetChannelLink(DEV_BASE(dev), channel, kEDMA_MinorLink,
config->linked_channel);
}
struct call_back *data = DEV_CHANNEL_DATA(dev, channel);

data->busy = false;
if (config->dma_callback) {
Expand All @@ -602,7 +679,7 @@ static int dma_mcux_edma_configure(const struct device *dev, uint32_t channel,

irq_unlock(key);

return ret;
return 0;
}

static int dma_mcux_edma_start(const struct device *dev, uint32_t channel)
Expand All @@ -619,6 +696,14 @@ static int dma_mcux_edma_start(const struct device *dev, uint32_t channel)
#endif
data->busy = true;
EDMA_StartTransfer(DEV_EDMA_HANDLE(dev, channel));
#if defined(CONFIG_DMA_MCUX_EDMA_V3) && \
(!defined(FSL_FEATURE_SOC_DMAMUX_COUNT) || (FSL_FEATURE_SOC_DMAMUX_COUNT == 0))
struct dma_mcux_channel_transfer_edma_settings *xfer_settings = &data->transfer_settings;

if (xfer_settings->transfer_type == kEDMA_MemoryToMemory) {
EDMA_TriggerChannelStart(DEV_BASE(dev), channel);
}
#endif
return 0;
}

Expand Down Expand Up @@ -648,6 +733,16 @@ static int dma_mcux_edma_suspend(const struct device *dev, uint32_t channel)
{
struct call_back *data = DEV_CHANNEL_DATA(dev, channel);

#if defined(CONFIG_DMA_MCUX_EDMA_V3) && \
(!defined(FSL_FEATURE_SOC_DMAMUX_COUNT) || (FSL_FEATURE_SOC_DMAMUX_COUNT == 0))
struct dma_mcux_channel_transfer_edma_settings *xfer_settings = &data->transfer_settings;

if (xfer_settings->transfer_type == kEDMA_MemoryToMemory) {
/* can't suspend this transfer, effectively a not implemented function */
return -ENOSYS;
}
#endif

if (!data->busy) {
return -EINVAL;
}
Expand Down
Loading
Loading