diff --git a/boards/infineon/kit_pse84_eval/kit_pse84_eval_m33.yaml b/boards/infineon/kit_pse84_eval/kit_pse84_eval_m33.yaml index 4ed08e4335b0f..6098c98595f4b 100644 --- a/boards/infineon/kit_pse84_eval/kit_pse84_eval_m33.yaml +++ b/boards/infineon/kit_pse84_eval/kit_pse84_eval_m33.yaml @@ -12,6 +12,7 @@ toolchain: - zephyr supported: - clock_control + - dma - gpio - pin_ctrl - uart diff --git a/boards/infineon/kit_pse84_eval/kit_pse84_eval_m55.yaml b/boards/infineon/kit_pse84_eval/kit_pse84_eval_m55.yaml index af184f3bfb135..8a2b038a885eb 100644 --- a/boards/infineon/kit_pse84_eval/kit_pse84_eval_m55.yaml +++ b/boards/infineon/kit_pse84_eval/kit_pse84_eval_m55.yaml @@ -12,6 +12,7 @@ toolchain: - zephyr supported: - clock_control + - dma - gpio - pin_ctrl - uart diff --git a/drivers/dma/CMakeLists.txt b/drivers/dma/CMakeLists.txt index 240e7f364e182..bfbcdc43f7b1e 100644 --- a/drivers/dma/CMakeLists.txt +++ b/drivers/dma/CMakeLists.txt @@ -40,6 +40,7 @@ zephyr_library_sources_ifdef(CONFIG_DMA_MAX32 dma_max32.c) zephyr_library_sources_ifdef(CONFIG_DMA_MCUX_SMARTDMA dma_mcux_smartdma.c) zephyr_library_sources_ifdef(CONFIG_DMA_ANDES_ATCDMACX00 dma_andes_atcdmacx00.c) zephyr_library_sources_ifdef(CONFIG_DMA_INFINEON_CAT1 dma_ifx_cat1.c) +zephyr_library_sources_ifdef(CONFIG_DMA_PDL_INFINEON_CAT1 dma_ifx_cat1_pdl.c) zephyr_library_sources_ifdef(CONFIG_DMA_SEDI dma_sedi.c) zephyr_library_sources_ifdef(CONFIG_DMA_SI32 dma_si32.c) zephyr_library_sources_ifdef(CONFIG_DMA_SILABS_LDMA dma_silabs_ldma.c) diff --git a/drivers/dma/Kconfig.ifx_cat1 b/drivers/dma/Kconfig.ifx_cat1 index 18066589773e7..c434664fbeaf0 100644 --- a/drivers/dma/Kconfig.ifx_cat1 +++ b/drivers/dma/Kconfig.ifx_cat1 @@ -12,3 +12,18 @@ config DMA_INFINEON_CAT1 select USE_INFINEON_DMA help This option enables the DMA driver for Infineon CAT1 family. + +config DMA_PDL_INFINEON_CAT1 + bool "Infineon CAT1 DMA driver" + default y + depends on DT_HAS_INFINEON_CAT1_DMA_PDL_ENABLED + select USE_INFINEON_DMA + help + This option enables the DMA driver for Infineon CAT1 family. + +config INFINEON_DESCRIPTOR_POOL_SIZE + int + default 10 + depends on DMA_PDL_INFINEON_CAT1 + help + This option provides the descritor pool size used for the DMA PDL driver diff --git a/drivers/dma/dma_ifx_cat1_pdl.c b/drivers/dma/dma_ifx_cat1_pdl.c new file mode 100644 index 0000000000000..d6c7e16b6ccde --- /dev/null +++ b/drivers/dma/dma_ifx_cat1_pdl.c @@ -0,0 +1,659 @@ +/* + * Copyright (c) 2025 Infineon Technologies AG, + * or an affiliate of Infineon Technologies AG. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @brief DMA driver for Infineon CAT1 MCU family. + */ + +#define DT_DRV_COMPAT infineon_cat1_dma_pdl + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +LOG_MODULE_REGISTER(ifx_cat1_dma, CONFIG_DMA_LOG_LEVEL); + +#define DMA_CH_NUM 29 + +struct ifx_cat1_dma_channel { + uint32_t channel_direction: 3; + uint32_t complete_callback_en: 1; + uint32_t error_callback_dis: 1; + + cy_stc_dma_descriptor_t descr; + IRQn_Type irq; + + /* store config data from dma_config structure */ + dma_callback_t callback; + void *user_data; +}; + +struct ifx_cat1_dma_data { + struct ifx_cat1_dma_channel *channels; + cy_stc_dma_descriptor_t descriptor_pool[CONFIG_INFINEON_DESCRIPTOR_POOL_SIZE]; +}; + +struct ifx_cat1_dma_config { + DW_Type *regs; + void (*irq_configure)(void); + bool enable_chaining; + + struct ifx_cat1_dma_channel_dt_info *channels_dt_info; + uint8_t channels_dt_count; +}; + +struct ifx_cat1_dma_channel_dt_info { + uint8_t channel_id; + cy_stc_dma_channel_config_t config; + cy_stc_dma_descriptor_config_t *descr; + uint8_t descr_num; +}; + +static cy_stc_dma_descriptor_t *ifx_cat1_dma_alloc_descriptor(const struct device *dev) +{ + uint32_t i; + struct ifx_cat1_dma_data *data = dev->data; + + for (i = 0u; i < CONFIG_INFINEON_DESCRIPTOR_POOL_SIZE; i++) { + if (data->descriptor_pool[i].src == 0) { + data->descriptor_pool[i].src = 0xFF; + return &data->descriptor_pool[i]; + } + } + + return NULL; +} + +void ifx_cat1_dma_free_descriptor(cy_stc_dma_descriptor_t *descr) +{ + if (descr != NULL) { + memset(descr, 0, sizeof(cy_stc_dma_descriptor_t)); + } +} + +static struct ifx_cat1_dma_channel_dt_info *ifx_cat1_get_config_from_dt(const struct device *dev, + uint32_t channel) +{ + const struct ifx_cat1_dma_config *const cfg = dev->config; + uint32_t i; + + if (cfg->channels_dt_info != NULL) { + for (i = 0u; i < cfg->channels_dt_count; i++) { + if (cfg->channels_dt_info[i].channel_id == channel) { + return &cfg->channels_dt_info[i]; + } + } + } + return NULL; +} + +int ifx_cat1_dma_trig(const struct device *dev, uint32_t channel) +{ + const struct ifx_cat1_dma_config *const cfg = dev->config; + + /* Set SW trigger for the channel */ + Cy_DMA_Channel_SetSWTrigger(cfg->regs, channel); + + return 0; +} + +cy_en_dma_data_size_t _convert_dma_data_size_z_to_pdl(struct dma_config *config) +{ + cy_en_dma_data_size_t pdl_dma_data_size = CY_DMA_BYTE; + + switch (config->source_data_size) { + case 1: + /* One byte */ + pdl_dma_data_size = CY_DMA_BYTE; + break; + case 2: + /* Half word (two bytes) */ + pdl_dma_data_size = CY_DMA_HALFWORD; + break; + case 4: + /* Full word (four bytes) */ + pdl_dma_data_size = CY_DMA_WORD; + break; + } + return pdl_dma_data_size; +} + +int _convert_dma_xy_increment_z_to_pdl(uint32_t addr_adj) +{ + switch (addr_adj) { + case DMA_ADDR_ADJ_INCREMENT: + return 1; + + case DMA_ADDR_ADJ_DECREMENT: + return -1; + + case DMA_ADDR_ADJ_NO_CHANGE: + return 0; + + default: + return 0; + } +} + +/* Configure a channel */ +static int ifx_cat1_dma_config(const struct device *dev, uint32_t channel, + struct dma_config *config) +{ + bool use_dt_config = false; + cy_en_dma_status_t dma_status; + struct ifx_cat1_dma_data *data = dev->data; + const struct ifx_cat1_dma_config *const cfg = dev->config; + + cy_stc_dma_channel_config_t channel_config = {0u}; + cy_stc_dma_descriptor_config_t descriptor_config = {0u}; + cy_stc_dma_descriptor_t *descriptor = NULL; + int err = 0; + + if (channel >= DMA_CH_NUM) { + LOG_ERR("Unsupported channel"); + return -EINVAL; + } + + /* Support only the same data width for source and dest */ + if (config->dest_data_size != config->source_data_size) { + LOG_ERR("Source and dest data size differ."); + return -EINVAL; + } + + /* Support only the same burst_length for source and dest */ + if (config->dest_burst_length != config->source_burst_length) { + LOG_ERR("Source and dest burst_length differ."); + return -EINVAL; + } + + /* DataWire only supports <=256 byte burst and <=256 bytes per burst */ + if ((config->dest_burst_length > 256) || + (config->dest_burst_length <= 1 && config->head_block->block_size > 256) || + (config->dest_burst_length > 0 && + config->head_block->block_size > (config->dest_burst_length * 256))) { + LOG_ERR("DMA (DW) only supports <=256 byte burst and <=256 bytes per burst"); + return -EINVAL; + } + + if (config->dest_data_size != 1 && config->dest_data_size != 2 && + config->dest_data_size != 4) { + LOG_ERR("dest_data_size must be 1, 2, or 4 (%" PRIu32 ")", config->dest_data_size); + return -EINVAL; + } + + data->channels[channel].callback = config->dma_callback; + data->channels[channel].user_data = config->user_data; + data->channels[channel].channel_direction = config->channel_direction; + data->channels[channel].complete_callback_en = config->complete_callback_en; + data->channels[channel].error_callback_dis = config->error_callback_dis; + + /* Lock and page in the channel configuration */ + uint32_t key = irq_lock(); + + /* Get first descriptor */ + descriptor = &data->channels[channel].descr; + + /* If we have Descriptor configuration in DT for this channel, + * so use it and skip configuration from dma_config. + */ + struct ifx_cat1_dma_channel_dt_info *dma_channel_dt_info = + ifx_cat1_get_config_from_dt(dev, channel); + + if (dma_channel_dt_info != NULL) { + /* Use configuration from device tree */ + uint32_t descr_index = (uint32_t)dma_channel_dt_info->config.descriptor; + + /* Get channel configuration */ + channel_config = dma_channel_dt_info->config; + + /* Get descriptor configuration */ + descriptor_config = dma_channel_dt_info->descr[descr_index]; + + /* Set source and destination for descriptor */ + descriptor_config.srcAddress = (void *)config->head_block->source_address; + descriptor_config.dstAddress = (void *)config->head_block->dest_address; + + /* Initialize descriptor */ + dma_status = Cy_DMA_Descriptor_Init(descriptor, &descriptor_config); + if (dma_status != CY_DMA_SUCCESS) { + err = -EIO; + goto handle_error; + } + + use_dt_config = true; + } else { + /* Retrigger descriptor immediately */ + descriptor_config.retrigger = CY_DMA_RETRIG_IM; + + /* Setup Interrupt Type + * if config->complete_callback_en = 0, callback invoked at completion only. + * if config->complete_callback_en = 1, callback invoked at + * completion of each block. + */ + if (!config->complete_callback_en) { + descriptor_config.interruptType = CY_DMA_DESCR_CHAIN; + } else { + descriptor_config.interruptType = CY_DMA_DESCR; + } + + /* Keep CHANNEL_ENABLED if BURST transfer (config->dest_burst_length != 0) */ + if (config->dest_burst_length != 0) { + descriptor_config.channelState = CY_DMA_CHANNEL_ENABLED; + } else { + descriptor_config.channelState = CY_DMA_CHANNEL_DISABLED; + } + + descriptor_config.triggerOutType = CY_DMA_DESCR_CHAIN; + descriptor_config.triggerInType = CY_DMA_DESCR_CHAIN; + + /* Set data size byte / 2 bytes / word */ + descriptor_config.dataSize = _convert_dma_data_size_z_to_pdl(config); + + /* By default, transfer what the user set for dataSize. However, + * if transferring between memory and a peripheral, make sure the + * peripheral access is using words. + */ + descriptor_config.srcTransferSize = CY_DMA_TRANSFER_SIZE_DATA; + descriptor_config.dstTransferSize = CY_DMA_TRANSFER_SIZE_DATA; + + if (config->channel_direction == PERIPHERAL_TO_MEMORY) { + descriptor_config.srcTransferSize = CY_DMA_TRANSFER_SIZE_WORD; + } else if (config->channel_direction == MEMORY_TO_PERIPHERAL) { + descriptor_config.dstTransferSize = CY_DMA_TRANSFER_SIZE_WORD; + } + + struct dma_block_config *block_config = config->head_block; + + for (uint32_t i = 0u; i < config->block_count; i++) { + + /* Setup destination increment for X source loop */ + descriptor_config.srcXincrement = + _convert_dma_xy_increment_z_to_pdl(block_config->source_addr_adj); + + /* Setup destination increment for X destination loop */ + descriptor_config.dstXincrement = + _convert_dma_xy_increment_z_to_pdl(block_config->dest_addr_adj); + + /* Setup 1D/2D descriptor for each data block */ + if (config->dest_burst_length != 0) { + descriptor_config.descriptorType = CY_DMA_2D_TRANSFER; + descriptor_config.xCount = config->dest_burst_length; + descriptor_config.yCount = DIV_ROUND_UP(block_config->block_size, + config->dest_burst_length); + descriptor_config.srcYincrement = + descriptor_config.srcXincrement * config->dest_burst_length; + descriptor_config.dstYincrement = + descriptor_config.dstXincrement * config->dest_burst_length; + } else { + descriptor_config.descriptorType = CY_DMA_1D_TRANSFER; + descriptor_config.xCount = block_config->block_size; + descriptor_config.yCount = 1; + descriptor_config.srcYincrement = 0; + descriptor_config.dstYincrement = 0; + } + + /* Set source and destination for descriptor */ + descriptor_config.srcAddress = (void *)block_config->source_address; + descriptor_config.dstAddress = (void *)block_config->dest_address; + + /* Allocate next descriptor if need */ + if (i + 1u < config->block_count) { + descriptor_config.nextDescriptor = + ifx_cat1_dma_alloc_descriptor(dev); + if (descriptor_config.nextDescriptor == NULL) { + LOG_ERR("ERROR: can not allocate DMA descriptor"); + } + } else { + if (cfg->enable_chaining) { + descriptor_config.nextDescriptor = descriptor; + } else { + descriptor_config.nextDescriptor = NULL; + } + } + + /* initialize descriptor */ + dma_status = Cy_DMA_Descriptor_Init(descriptor, &descriptor_config); + if (dma_status != CY_DMA_SUCCESS) { + err = -EIO; + goto handle_error; + } + + block_config = block_config->next_block; + descriptor = descriptor_config.nextDescriptor; + } + } + + /* Set a descriptor for the specified DMA channel */ + channel_config.descriptor = &data->channels[channel].descr; + + /* Set a priority for the DMA channel */ + if (use_dt_config == false) { + Cy_DMA_Channel_SetPriority(cfg->regs, channel, config->channel_priority); + } + + /* Initialize channel */ + dma_status = Cy_DMA_Channel_Init(cfg->regs, channel, &channel_config); + if (dma_status != CY_DMA_SUCCESS) { + err = -EIO; + goto handle_error; + } + + /* Enable DMA interrupt source. */ + Cy_DMA_Channel_SetInterruptMask(cfg->regs, channel, CY_DMA_INTR_MASK); + + /* Enable the interrupt */ + irq_enable(data->channels[channel].irq); + + /* Flush the cache before starting DMA to ensure that the modifications made in cache are + * written back to the memory + */ +#ifdef CONFIG_CPU_HAS_DCACHE + SCB_CleanDCache(); +#endif + + Cy_DMA_Channel_Enable(cfg->regs, channel); + + /* Invalidate the cache after DMA transfer to reload the updated memory (its important to do + * this after the DMA Enable, otherwise, the updates made by DMA transfer are not copied to + * cache and will lead to errors) + */ +#ifdef CONFIG_CPU_HAS_DCACHE + SCB_InvalidateDCache(); +#endif + +handle_error: + irq_unlock(key); + return err; +} + +static int ifx_cat1_dma_start(const struct device *dev, uint32_t channel) +{ + const struct ifx_cat1_dma_config *const cfg = dev->config; + + if (channel >= DMA_CH_NUM) { + LOG_ERR("Unsupported channel"); + return -EINVAL; + } + + /* Flush the cache before starting DMA to ensure that the modifications made in cache are + * written back to the memory + */ +#ifdef CONFIG_CPU_HAS_DCACHE + SCB_CleanDCache(); +#endif + + /* Enable DMA channel */ + Cy_DMA_Channel_Enable(cfg->regs, channel); + + ifx_cat1_dma_trig(dev, channel); + + /* Invalidate the cache after DMA transfer to reload the updated memory (its important to do + * this after the DMA Enable, otherwise, the updates made by DMA transfer are not copied to + * cache and will lead to errors) + */ +#ifdef CONFIG_CPU_HAS_DCACHE + SCB_InvalidateDCache(); +#endif + + return 0; +} + +static int ifx_cat1_dma_stop(const struct device *dev, uint32_t channel) +{ + const struct ifx_cat1_dma_config *const cfg = dev->config; + + if (channel >= DMA_CH_NUM) { + LOG_ERR("Unsupported channel"); + return -EINVAL; + } + + /* Disable DMA channel */ + Cy_DMA_Channel_Disable(cfg->regs, channel); + + return 0; +} + +int ifx_cat1_dma_reload(const struct device *dev, uint32_t channel, uint32_t src, uint32_t dst, + size_t size) +{ + if (channel >= DMA_CH_NUM) { + LOG_ERR("Unsupported channel"); + return -EINVAL; + } + + register struct ifx_cat1_dma_data *data = dev->data; + register const struct ifx_cat1_dma_config *const cfg = dev->config; + register cy_stc_dma_descriptor_t *descriptor = &data->channels[channel].descr; + + /* Set a descriptor for the specified DMA channel */ + descriptor->src = src; + descriptor->dst = dst; + + /* Flush the cache before starting DMA to ensure that the modifications made in cache are + * written back to the memory + */ +#ifdef CONFIG_CPU_HAS_DCACHE + SCB_CleanDCache(); +#endif + + /* Initialize channel */ + Cy_DMA_Channel_Enable(cfg->regs, channel); + + /* Invalidate the cache after DMA transfer to reload the updated memory (its important to do + * this after the DMA Enable, otherwise, the updates made by DMA transfer are not copied to + * cache and will lead to errors) + */ +#ifdef CONFIG_CPU_HAS_DCACHE + SCB_InvalidateDCache(); +#endif + + return 0; +} + +static int ifx_cat1_dma_get_status(const struct device *dev, uint32_t channel, + struct dma_status *stat) +{ + struct ifx_cat1_dma_data *data = dev->data; + const struct ifx_cat1_dma_config *const cfg = dev->config; + + if (channel >= DMA_CH_NUM) { + LOG_ERR("Unsupported channel"); + return -EINVAL; + } + + if (stat != NULL) { + /* Check is current DMA channel busy or idle */ + uint32_t active_ch = Cy_DMA_GetActiveChannel(cfg->regs); + + /* busy status info */ + stat->busy = (active_ch & (1ul << channel)) ? true : false; + + /* direction info */ + stat->dir = data->channels[channel].channel_direction; + } + + return 0; +} + +static int ifx_cat1_dma_init(const struct device *dev) +{ + const struct ifx_cat1_dma_config *const cfg = dev->config; + + /* Enable DMA block to start descriptor execution process */ + Cy_DMA_Enable(cfg->regs); + + /* Configure IRQ */ + cfg->irq_configure(); + + return 0; +} + +/* Handles DMA interrupts and dispatches to the individual channel */ +struct ifx_cat1_dma_irq_context { + const struct device *dev; + uint32_t channel; +}; + +static void ifx_cat1_dma_isr(struct ifx_cat1_dma_irq_context *irq_context) +{ + uint32_t channel = irq_context->channel; + struct ifx_cat1_dma_data *data = irq_context->dev->data; + const struct ifx_cat1_dma_config *cfg = irq_context->dev->config; + dma_callback_t callback = data->channels[channel].callback; + int status = -EIO; + + /* Get interrupt type and call users event callback if they have enabled that event */ + switch (Cy_DMA_Channel_GetStatus(cfg->regs, channel)) { + case CY_DMA_INTR_CAUSE_COMPLETION: + status = 0; + break; + case CY_DMA_INTR_CAUSE_DESCR_BUS_ERROR: /* Descriptor bus error */ + case CY_DMA_INTR_CAUSE_SRC_BUS_ERROR: /* Source bus error */ + case CY_DMA_INTR_CAUSE_DST_BUS_ERROR: /* Destination bus error */ + case CY_DMA_INTR_CAUSE_SRC_MISAL: /* Source address is not aligned */ + case CY_DMA_INTR_CAUSE_DST_MISAL: /* Destination address is not aligned */ + case CY_DMA_INTR_CAUSE_CURR_PTR_NULL: /* Current descr pointer is NULL */ + case CY_DMA_INTR_CAUSE_ACTIVE_CH_DISABLED: /* Active channel is disabled */ + default: + status = -EIO; + LOG_WRN("Error in DMA transfer"); + break; + } + + /* Clear all interrupts */ + Cy_DMA_Channel_ClearInterrupt(cfg->regs, channel); + + /* return if callback is not registered */ + if (callback == NULL) { + return; + } + + /* Give callback with error status only if enabled */ + if (status != 0 && !data->channels[channel].error_callback_dis) { + return; + } + + callback(irq_context->dev, data->channels[channel].user_data, channel, status); +} + +static const struct dma_driver_api ifx_cat1_dma_api = { + .config = ifx_cat1_dma_config, + .start = ifx_cat1_dma_start, + .stop = ifx_cat1_dma_stop, + .reload = ifx_cat1_dma_reload, + .get_status = ifx_cat1_dma_get_status, +}; + +#define NODE_CHILD_IS_EMPTY(node_id) IS_EMPTY(DT_SUPPORTS_DEP_ORDS(node_id)) + +/* DMA descriptors configuration */ +#define DESCRIPTOR_CONFIG(id) \ + { \ + .retrigger = DT_ENUM_IDX_OR(id, retrigger, CY_DMA_RETRIG_IM), \ + .interruptType = DT_ENUM_IDX_OR(id, interrupt_type, CY_DMA_DESCR), \ + .triggerOutType = DT_ENUM_IDX_OR(id, trigger_out_type, CY_DMA_DESCR), \ + .triggerInType = DT_ENUM_IDX_OR(id, trigger_in_type, CY_DMA_DESCR), \ + .channelState = DT_ENUM_IDX_OR(id, channel_state, CY_DMA_CHANNEL_DISABLED), \ + \ + .dataSize = DT_ENUM_IDX_OR(id, data_size, CY_DMA_BYTE), \ + .srcTransferSize = \ + DT_ENUM_IDX_OR(id, src_transfer_size, CY_DMA_TRANSFER_SIZE_DATA), \ + .dstTransferSize = \ + DT_ENUM_IDX_OR(id, dst_transfer_size, CY_DMA_TRANSFER_SIZE_DATA), \ + \ + .descriptorType = DT_ENUM_IDX(id, descriptor_type), \ + \ + .srcXincrement = DT_PROP_OR(id, src_x_increment, 0), \ + .dstXincrement = DT_PROP_OR(id, dst_x_increment, 0), \ + .xCount = DT_PROP_OR(id, x_count, 0), \ + \ + .srcYincrement = DT_PROP_OR(id, src_y_increment, 0), \ + .dstYincrement = DT_PROP_OR(id, src_y_increment, 0), \ + .yCount = DT_PROP_OR(id, y_count, 0), \ + }, + +/* DMA channel configuration */ +#define CHANNELS_CONFIG(chan_id) \ + {.channel_id = DT_REG_ADDR(chan_id), \ + .config = {.priority = DT_PROP_OR(chan_id, priority, 3), \ + .preemptible = DT_PROP_OR(chan_id, preemptible, 0), \ + .descriptor = DT_PROP_OR(chan_id, descriptor, 0)}, \ + COND_CODE_1(DT_NODE_EXISTS(DT_CHILD(chan_id, descriptor_0)), \ + (.descr = (cy_stc_dma_descriptor_config_t *)&descriptor_conf_##chan_id, \ + .descr_num = sizeof(descriptor_conf_##chan_id) / \ + sizeof(cy_stc_dma_descriptor_config_t)), \ + (.descr = NULL, .descr_num = 0))}, + +#define DESCRIPTOR_FOREACH_CHILD_FUNC(chan_id) \ + COND_CODE_1(DT_NODE_EXISTS(DT_CHILD(chan_id, descriptor_0)), \ + (static const cy_stc_dma_descriptor_config_t descriptor_conf_##chan_id[] = \ + {DT_CAT(chan_id, _FOREACH_CHILD)(DESCRIPTOR_CONFIG)};), \ + (EMPTY)) + +#define GET_CHANNEL_DT_INFO(inst) \ + DT_INST_FOREACH_CHILD(inst, DESCRIPTOR_FOREACH_CHILD_FUNC) \ + static const struct ifx_cat1_dma_channel_dt_info ifx_cat1_dma_channel_dt_info_##inst[] = { \ + DT_INST_FOREACH_CHILD(inst, CHANNELS_CONFIG)}; + +#define IRQ_CONFIGURE(n, inst) \ + static const struct ifx_cat1_dma_irq_context irq_context##inst##n = { \ + .dev = DEVICE_DT_INST_GET(inst), \ + .channel = n, \ + }; \ + \ + IRQ_CONNECT(DT_INST_IRQ_BY_IDX(inst, n, irq), DT_INST_IRQ_BY_IDX(inst, n, priority), \ + ifx_cat1_dma_isr, &irq_context##inst##n, 0); \ + \ + ifx_cat1_dma_channels##inst[n].irq = DT_INST_IRQ_BY_IDX(inst, n, irq); + +#define CONFIGURE_ALL_IRQS(inst, n) LISTIFY(n, IRQ_CONFIGURE, (), inst) + +#define INFINEON_CAT1_DMA_INIT(n) \ + \ + static void ifx_cat1_dma_irq_configure##n(void); \ + \ + COND_CODE_0(NODE_CHILD_IS_EMPTY(DT_DRV_INST(n)), (GET_CHANNEL_DT_INFO(n);), (EMPTY)) \ + \ + static struct ifx_cat1_dma_channel \ + ifx_cat1_dma_channels##n[DT_INST_PROP(n, dma_channels)]; \ + \ + static __aligned(32) struct ifx_cat1_dma_data ifx_cat1_dma_data##n = { \ + .channels = ifx_cat1_dma_channels##n, \ + }; \ + \ + static const struct ifx_cat1_dma_config ifx_cat1_dma_config##n = { \ + .regs = (DW_Type *)DT_INST_REG_ADDR(n), \ + .irq_configure = ifx_cat1_dma_irq_configure##n, \ + .enable_chaining = DT_INST_PROP(n, enable_chaining), \ + \ + COND_CODE_0(NODE_CHILD_IS_EMPTY(DT_DRV_INST(n)), \ + (.channels_dt_info = (struct ifx_cat1_dma_channel_dt_info *) \ + ifx_cat1_dma_channel_dt_info_##n, \ + .channels_dt_count = sizeof(ifx_cat1_dma_channel_dt_info_##n) / \ + sizeof(struct ifx_cat1_dma_channel_dt_info)), \ + (.channels_dt_info = NULL, .channels_dt_count = 0)) \ + \ + }; \ + \ + static void ifx_cat1_dma_irq_configure##n(void) \ + { \ + extern struct ifx_cat1_dma_channel ifx_cat1_dma_channels##n[]; \ + CONFIGURE_ALL_IRQS(n, DT_NUM_IRQS(DT_DRV_INST(n))); \ + } \ + \ + DEVICE_DT_INST_DEFINE(n, &ifx_cat1_dma_init, NULL, &ifx_cat1_dma_data##n, \ + &ifx_cat1_dma_config##n, PRE_KERNEL_1, CONFIG_DMA_INIT_PRIORITY, \ + &ifx_cat1_dma_api); + +DT_INST_FOREACH_STATUS_OKAY(INFINEON_CAT1_DMA_INIT) diff --git a/dts/bindings/dma/infineon,cat1-dma-pdl.yaml b/dts/bindings/dma/infineon,cat1-dma-pdl.yaml new file mode 100644 index 0000000000000..508aabeb4c4a6 --- /dev/null +++ b/dts/bindings/dma/infineon,cat1-dma-pdl.yaml @@ -0,0 +1,216 @@ +# Copyright (c) 2025 Infineon Technologies AG, +# or an affiliate of Infineon Technologies AG. +# +# SPDX-License-Identifier: Apache-2.0 + +title: Infineon CAT1 DMA PDL Driver + +description: | + Driver to support DMA for Infineon CAT1 devices, including PSOC Edge 84. This + driver is based on the Infineon PDL. + +compatible: "infineon,cat1-dma-pdl" + +include: dma-controller.yaml + +properties: + reg: + required: true + + interrupts: + required: true + + "#dma-cells": + const: 1 + + enable-chaining: + type: boolean + description: | + This property can be used to enable descriptor chaining + +child-binding: + description: Channel configuration. + + properties: + reg: + type: array + required: true + description: Channel identifier. + + priority: + type: int + description: | + This property can be used to specify priority of the channel in the + DMA block. Lower number takes precedence (range 0..3). + + preemptible: + type: int + description: | + preemptible. + Makes the channel preemptible by another higher priority channel. + + descriptor: + type: int + description: | + Select initial DMA descriptor. + + child-binding: + description: Descriptor configuration. + + properties: + reg: + type: array + required: true + description: Descriptor identifier. + + retrigger: + type: string + description: | + Specifies whether the DW controller should wait for the input trigger to be deactivated. + Options for descriptor retriggering: + dma_retrig_im - retrigger immediately, + dma_retrig_4cyc - retrigger after 4 clk_slow cycles, + dma_retrig_16cyc - retrigger after 16 clk_slow cycles, + dma_wait_for_react - wait for trigger reactivation. + enum: + - "dma_retrig_im" + - "dma_retrig_4cyc" + - "dma_retrig_16cyc" + - "dma_wait_for_react" + + interrupt-type: + type: string + description: | + Sets the event that triggers an interrupt. Options for interrupt-type: + dma_1element - One element transfer, + dma_x_loop - One X loop transfer, + dma_descr - One descriptor transfer, + dma_descr_chain - Entire descriptor chain transfer. + enum: + - "dma_1element" + - "dma_x_loop" + - "dma_descr" + - "dma_descr_chain" + + trigger-out-type: + type: string + description: | + Sets the event that triggers an output. Options for trigger-out-type: + dma_1element - One element transfer, + dma_x_loop - One X loop transfer, + dma_descr - One descriptor transfer, + dma_descr_chain - Entire descriptor chain transfer. + enum: + - "dma_1element" + - "dma_x_loop" + - "dma_descr" + - "dma_descr_chain" + + trigger-in-type: + type: string + description: | + Sets what type of transfer is triggered. Options for trigger-in-type: + dma_1element - One element transfer, + dma_x_loop - One X loop transfer, + dma_descr - One descriptor transfer, + dma_descr_chain - Entire descriptor chain transfer. + enum: + - "dma_1element" + - "dma_x_loop" + - "dma_descr" + - "dma_descr_chain" + + channel-state: + type: string + description: | + Specifies whether the channel is enabled or disabled on completion of descriptor. + Options for channel-state: + dma_channel_enabled - Channel stays enabled, + dma_channel_disabled - Channel stays disabled. + enum: + - "dma_channel_enabled" + - "dma_channel_disabled" + + data-size: + type: string + description: | + The size of the data bus for transfer. Options for data-size: + dma_byte - One byte, + dma_halfword - Two bytes, + dma_word - Four bytes. + enum: + - "dma_byte" + - "dma_halfword" + - "dma_word" + + src-transfer-size: + type: string + description: | + The source transfer size. Options for src-transfer-size: + dma_transfer_size_data - As specified by dataSize, + dma_transfer_size_word - A full word (four bytes). + enum: + - "dma_transfer_size_data" + - "dma_transfer_size_word" + + dst-transfer-size: + type: string + description: | + The destination transfer size. Options for dst-transfer-size: + dma_transfer_size_data - As specified by dataSize, + dma_transfer_size_word - A full word (four bytes). + enum: + - "dma_transfer_size_data" + - "dma_transfer_size_word" + + descriptor-type: + type: string + description: | + Contains the options for the descriptor type. Options for descriptor_type: + dma_single_transfer - single transfer, + dma_1d_transfer - 1d transfer, + dma_2d_transfer - 2d transfer, + dma_crc_transfer - crc transfer. supported by the cpuss_ver2 only. + enum: + - "dma_single_transfer" + - "dma_1d_transfer" + - "dma_2d_transfer" + - "dma_crc_transfer" + + src-x-increment: + type: int + description: | + The address increment of the source after each X-loop. + + dst-x-increment: + type: int + description: | + The address increment of the destination after each X-loop. + + x-count: + type: int + description: | + The number of transfers in an X-loop. + + src-y-increment: + type: int + description: | + The address increment of the source after each Y-loop transfer. + + dst-y-increment: + type: int + description: | + The address increment of the destination after each Y-loop transfer. + + y-count: + type: int + description: | + The number of X-loops in the Y-loop. + + next-descriptor: + type: int + description: | + The next descriptor to chain after completion. + +dma-cells: + - channel diff --git a/modules/hal_infineon/mtb-dsl-pse8xxgp/CMakeLists.txt b/modules/hal_infineon/mtb-dsl-pse8xxgp/CMakeLists.txt index 54352b9df0ec4..2a9892f7b65be 100644 --- a/modules/hal_infineon/mtb-dsl-pse8xxgp/CMakeLists.txt +++ b/modules/hal_infineon/mtb-dsl-pse8xxgp/CMakeLists.txt @@ -53,7 +53,6 @@ endif() if(CONFIG_USE_INFINEON_DMA OR CONFIG_USE_INFINEON_ADC OR CONFIG_USE_INFINEON_SMIF) zephyr_library_sources(${pdl_drv_dir}/source/cy_dma.c) - zephyr_library_sources(${pdl_drv_dir}/source/cy_dmac.c) endif() zephyr_library_sources(${pdl_drv_dir}/source/cy_syspm_v4.c) diff --git a/tests/drivers/dma/chan_blen_transfer/boards/kit_pse84_eval_pse846gps2dbzc4a_m33.overlay b/tests/drivers/dma/chan_blen_transfer/boards/kit_pse84_eval_pse846gps2dbzc4a_m33.overlay new file mode 100644 index 0000000000000..70b972a071323 --- /dev/null +++ b/tests/drivers/dma/chan_blen_transfer/boards/kit_pse84_eval_pse846gps2dbzc4a_m33.overlay @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2025 Infineon Technologies AG, + * or an affiliate of Infineon Technologies AG. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +tst_dma0: &dma0 { + status = "okay"; +}; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/kit_pse84_eval_pse846gps2dbzc4a_m55.overlay b/tests/drivers/dma/chan_blen_transfer/boards/kit_pse84_eval_pse846gps2dbzc4a_m55.overlay new file mode 100644 index 0000000000000..70b972a071323 --- /dev/null +++ b/tests/drivers/dma/chan_blen_transfer/boards/kit_pse84_eval_pse846gps2dbzc4a_m55.overlay @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2025 Infineon Technologies AG, + * or an affiliate of Infineon Technologies AG. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +tst_dma0: &dma0 { + status = "okay"; +}; diff --git a/tests/drivers/dma/loop_transfer/boards/kit_pse84_eval_pse846gps2dbzc4a_m33.conf b/tests/drivers/dma/loop_transfer/boards/kit_pse84_eval_pse846gps2dbzc4a_m33.conf new file mode 100644 index 0000000000000..c6ce885f98d4b --- /dev/null +++ b/tests/drivers/dma/loop_transfer/boards/kit_pse84_eval_pse846gps2dbzc4a_m33.conf @@ -0,0 +1,6 @@ +# Copyright (c) 2025 Infineon Technologies AG, +# or an affiliate of Infineon Technologies AG. +# +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_DMA_LOOP_TRANSFER_SIZE=256 diff --git a/tests/drivers/dma/loop_transfer/boards/kit_pse84_eval_pse846gps2dbzc4a_m33.overlay b/tests/drivers/dma/loop_transfer/boards/kit_pse84_eval_pse846gps2dbzc4a_m33.overlay new file mode 100644 index 0000000000000..70b972a071323 --- /dev/null +++ b/tests/drivers/dma/loop_transfer/boards/kit_pse84_eval_pse846gps2dbzc4a_m33.overlay @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2025 Infineon Technologies AG, + * or an affiliate of Infineon Technologies AG. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +tst_dma0: &dma0 { + status = "okay"; +}; diff --git a/tests/drivers/dma/loop_transfer/boards/kit_pse84_eval_pse846gps2dbzc4a_m55.conf b/tests/drivers/dma/loop_transfer/boards/kit_pse84_eval_pse846gps2dbzc4a_m55.conf new file mode 100644 index 0000000000000..c6ce885f98d4b --- /dev/null +++ b/tests/drivers/dma/loop_transfer/boards/kit_pse84_eval_pse846gps2dbzc4a_m55.conf @@ -0,0 +1,6 @@ +# Copyright (c) 2025 Infineon Technologies AG, +# or an affiliate of Infineon Technologies AG. +# +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_DMA_LOOP_TRANSFER_SIZE=256 diff --git a/tests/drivers/dma/loop_transfer/boards/kit_pse84_eval_pse846gps2dbzc4a_m55.overlay b/tests/drivers/dma/loop_transfer/boards/kit_pse84_eval_pse846gps2dbzc4a_m55.overlay new file mode 100644 index 0000000000000..70b972a071323 --- /dev/null +++ b/tests/drivers/dma/loop_transfer/boards/kit_pse84_eval_pse846gps2dbzc4a_m55.overlay @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2025 Infineon Technologies AG, + * or an affiliate of Infineon Technologies AG. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +tst_dma0: &dma0 { + status = "okay"; +};