drivers: dma: dma_mcux_lpc: Adjusted dma driver for channel chaining.
Added to the configuration function to enable
channel chaining for the DMA_LPC that utilizes
the total of the SOC OTrig channels.
Signed-off-by: Emilio Benavente <emilio.benavente@nxp.com>
diff --git a/drivers/dma/dma_mcux_lpc.c b/drivers/dma/dma_mcux_lpc.c
index 29e37a5..c6da0eb 100644
--- a/drivers/dma/dma_mcux_lpc.c
+++ b/drivers/dma/dma_mcux_lpc.c
@@ -24,6 +24,9 @@
struct dma_mcux_lpc_config {
DMA_Type *base;
uint32_t num_of_channels;
+ uint32_t otrig_base_address;
+ uint32_t itrig_base_address;
+ uint8_t num_of_otrigs;
void (*irq_config_func)(const struct device *dev);
};
@@ -42,11 +45,18 @@
bool busy;
};
+struct dma_otrig {
+ int8_t source_channel;
+ int8_t linked_channel;
+};
+
struct dma_mcux_lpc_dma_data {
struct channel_data *channel_data;
+ struct dma_otrig *otrig_array;
int8_t *channel_index;
uint8_t num_channels_used;
};
+K_SEM_DEFINE(is_otrig_being_configured, 1, 1)
#define NXP_LPC_DMA_MAX_XFER ((DMA_CHANNEL_XFERCFG_XFERCOUNT_MASK >> \
DMA_CHANNEL_XFERCFG_XFERCOUNT_SHIFT) + 1)
@@ -60,6 +70,8 @@
#define DEV_DMA_HANDLE(dev, ch) \
((dma_handle_t *)(&(DEV_CHANNEL_DATA(dev, ch)->dma_handle)))
+#define EMPTY_OTRIG -1
+
static void nxp_lpc_dma_callback(dma_handle_t *handle, void *param,
bool transferDone, uint32_t intmode)
{
@@ -254,6 +266,7 @@
struct dma_block_config *block_config = config->head_block;
uint32_t virtual_channel;
uint32_t total_dma_channels;
+ uint8_t otrig_index;
uint8_t src_inc, dst_inc;
bool is_periph = true;
uint8_t width = MIN(config->source_data_size, config->dest_data_size);
@@ -360,16 +373,89 @@
LOG_DBG("channel is %d", p_handle->channel);
- if (config->source_chaining_en && config->dest_chaining_en) {
- LOG_DBG("link dma out 0 to channel %d", config->linked_channel);
- /* Link DMA_OTRIG 0 to channel */
- INPUTMUX_AttachSignal(INPUTMUX, 0, config->linked_channel);
+ if (k_sem_take(&is_otrig_being_configured, K_MSEC(200))) {
+ LOG_ERR("DMA attempted to configure an Otrig mux"
+ " while the mux was in use.");
+ return -EACCES;
}
data->descriptors_queued = false;
data->num_of_descriptors = 0;
data->width = width;
data->curr_descriptor = NULL;
+ if (config->source_chaining_en || config->dest_chaining_en) {
+ /* Chaining is enabled */
+ if (!dev_config->otrig_base_address || !dev_config->itrig_base_address) {
+ LOG_ERR("Calling function tried to setup up channel"
+ " chaining but the current platform is missing"
+ " the correct trigger base addresses.");
+ k_sem_give(&is_otrig_being_configured);
+ return -ENXIO;
+ }
+
+ LOG_DBG("link dma 0 channel %d with channel %d",
+ channel, config->linked_channel);
+ uint8_t is_otrig_available = 0;
+
+ for (otrig_index = 0; otrig_index < dev_config->num_of_otrigs;
+ ++otrig_index) {
+ if (dma_data->otrig_array[otrig_index].linked_channel == EMPTY_OTRIG ||
+ dma_data->otrig_array[otrig_index].source_channel == channel) {
+ if (dma_data->otrig_array[otrig_index].source_channel == channel) {
+ int ChannelToDisable =
+ dma_data->otrig_array[otrig_index].linked_channel;
+ DMA_DisableChannel(DEV_BASE(dev), ChannelToDisable);
+ DEV_BASE(dev)->CHANNEL[ChannelToDisable].CFG &=
+ ~DMA_CHANNEL_CFG_HWTRIGEN_MASK;
+ }
+ is_otrig_available = 1;
+ break;
+ }
+ }
+ if (!is_otrig_available) {
+ LOG_ERR("Calling function tried to setup up multiple"
+ " channels to be configured but the dma driver has"
+ " run out of OTrig Muxes");
+ k_sem_give(&is_otrig_being_configured);
+ return -EINVAL;
+ }
+
+ /* Since INPUTMUX handles the dma signals and
+ * must be hardware triggered via the INPUTMUX
+ * hardware.
+ */
+ DEV_BASE(dev)->CHANNEL[config->linked_channel].CFG |=
+ DMA_CHANNEL_CFG_HWTRIGEN_MASK;
+
+ DMA_EnableChannel(DEV_BASE(dev), config->linked_channel);
+
+ /* Link OTrig Muxes with passed-in channels */
+ INPUTMUX_AttachSignal(INPUTMUX, otrig_index,
+ dev_config->otrig_base_address + channel);
+ INPUTMUX_AttachSignal(INPUTMUX, config->linked_channel,
+ dev_config->itrig_base_address + otrig_index);
+
+ /* Otrig is now connected with linked channel */
+ dma_data->otrig_array[otrig_index].source_channel = channel;
+ dma_data->otrig_array[otrig_index].linked_channel = config->linked_channel;
+ } else {
+ /* Chaining is _NOT_ enabled, Freeing connected OTrig */
+ for (otrig_index = 0; otrig_index < dev_config->num_of_otrigs; otrig_index++) {
+ if (dma_data->otrig_array[otrig_index].linked_channel != EMPTY_OTRIG &&
+ (channel == dma_data->otrig_array[otrig_index].source_channel)) {
+ int ChannelToDisable =
+ dma_data->otrig_array[otrig_index].linked_channel;
+ DMA_DisableChannel(DEV_BASE(dev), ChannelToDisable);
+ DEV_BASE(dev)->CHANNEL[ChannelToDisable].CFG &=
+ ~DMA_CHANNEL_CFG_HWTRIGEN_MASK;
+ dma_data->otrig_array[otrig_index].linked_channel = EMPTY_OTRIG;
+ dma_data->otrig_array[otrig_index].source_channel = EMPTY_OTRIG;
+ break;
+ }
+ }
+ }
+
+ k_sem_give(&is_otrig_being_configured);
/* Check if we need to queue DMA descriptors */
if ((block_config->block_size / width > NXP_LPC_DMA_MAX_XFER) ||
@@ -585,9 +671,16 @@
static int dma_mcux_lpc_init(const struct device *dev)
{
+ const struct dma_mcux_lpc_config *config = dev->config;
struct dma_mcux_lpc_dma_data *data = dev->data;
int total_dma_channels;
+ /* Indicate that the Otrig Muxes are not connected */
+ for (int i = 0; i < config->num_of_otrigs; i++) {
+ data->otrig_array[i].source_channel = EMPTY_OTRIG;
+ data->otrig_array[i].linked_channel = EMPTY_OTRIG;
+ }
+
#if defined FSL_FEATURE_DMA_NUMBER_OF_CHANNELS
total_dma_channels = FSL_FEATURE_DMA_NUMBER_OF_CHANNELS;
#else
@@ -637,6 +730,9 @@
static const struct dma_mcux_lpc_config dma_##n##_config = { \
.base = (DMA_Type *)DT_INST_REG_ADDR(n), \
.num_of_channels = DT_INST_PROP(n, dma_channels), \
+ .num_of_otrigs = DT_INST_PROP(n, nxp_dma_num_of_otrigs), \
+ .otrig_base_address = DT_INST_PROP_OR(n, nxp_dma_otrig_base_address, 0x0), \
+ .itrig_base_address = DT_INST_PROP_OR(n, nxp_dma_itrig_base_address, 0x0), \
IRQ_FUNC_INIT \
}
@@ -654,12 +750,16 @@
static struct channel_data dma_##n##_channel_data_arr \
[DT_INST_PROP(n, dma_channels)] = {0}; \
\
+ static struct dma_otrig dma_##n##_otrig_arr \
+ [DT_INST_PROP(n, nxp_dma_num_of_otrigs)] = {0}; \
+ \
static int8_t \
dma_##n##_channel_index_arr[TOTAL_DMA_CHANNELS] = {0}; \
\
static struct dma_mcux_lpc_dma_data dma_data_##n = { \
.channel_data = dma_##n##_channel_data_arr, \
.channel_index = dma_##n##_channel_index_arr, \
+ .otrig_array = dma_##n##_otrig_arr, \
}; \
\
DEVICE_DT_INST_DEFINE(n, \