diff --git a/boards/st/stm32mp257f_ev1/stm32mp257f_ev1_stm32mp257fxx_m33.yaml b/boards/st/stm32mp257f_ev1/stm32mp257f_ev1_stm32mp257fxx_m33.yaml index f319715640e5a..40952967eb87e 100644 --- a/boards/st/stm32mp257f_ev1/stm32mp257f_ev1_stm32mp257fxx_m33.yaml +++ b/boards/st/stm32mp257f_ev1/stm32mp257f_ev1_stm32mp257fxx_m33.yaml @@ -11,6 +11,7 @@ supported: - shell - i2c - spi + - dma testing: ignore_tags: - cmsis_rtos_v2 diff --git a/drivers/dma/CMakeLists.txt b/drivers/dma/CMakeLists.txt index 65cba01a5f2ef..d8b8c3863a232 100644 --- a/drivers/dma/CMakeLists.txt +++ b/drivers/dma/CMakeLists.txt @@ -8,6 +8,7 @@ zephyr_library_sources_ifdef(CONFIG_DMA_SAM_XDMAC dma_sam_xdmac.c) zephyr_library_sources_ifdef(CONFIG_DMA_STM32U5 dma_stm32u5.c) zephyr_library_sources_ifdef(CONFIG_DMA_STM32_V1 dma_stm32.c dma_stm32_v1.c) zephyr_library_sources_ifdef(CONFIG_DMA_STM32_V2 dma_stm32.c dma_stm32_v2.c) +zephyr_library_sources_ifdef(CONFIG_DMA_STM32_V3 dma_stm32_v3.c) zephyr_library_sources_ifdef(CONFIG_DMA_STM32_BDMA dma_stm32_bdma.c) zephyr_library_sources_ifdef(CONFIG_DMAMUX_STM32 dmamux_stm32.c) zephyr_library_sources_ifdef(CONFIG_DMA_DW dma_dw.c dma_dw_common.c) diff --git a/drivers/dma/Kconfig.stm32 b/drivers/dma/Kconfig.stm32 index 944c068c42442..1d44e48d557d6 100644 --- a/drivers/dma/Kconfig.stm32 +++ b/drivers/dma/Kconfig.stm32 @@ -3,6 +3,7 @@ # Copyright (c) 2016 Intel Corporation # Copyright (c) 2019 Song Qiang # Copyright (c) 2023 Jeroen van Dooren, Nobleo Technology +# Copyright (C) 2025 Savoir-faire Linux, Inc. # SPDX-License-Identifier: Apache-2.0 config DMA_STM32 @@ -12,6 +13,7 @@ config DMA_STM32 depends on DT_HAS_ST_STM32_DMA_V1_ENABLED \ || DT_HAS_ST_STM32_DMA_V2_ENABLED \ || DT_HAS_ST_STM32_DMA_V2BIS_ENABLED \ + || DT_HAS_ST_STM32_DMA_V3_ENABLED \ || DT_HAS_ST_STM32_BDMA_ENABLED help Driver for STM32 DMA V1, V2, V2bis and BDMA types. @@ -44,6 +46,16 @@ config DMA_STM32_V2 With the versions V2 bis of DMA, the peripheral request (slot) is not a parameter of the dma-cell. +config DMA_STM32_V3 + bool "STM32 DMA V3 driver" + default y + depends on DT_HAS_ST_STM32_DMA_V3_ENABLED + help + Driver for STM32 HPDMA (High Performance DMA) type. + It is used in STM32MP2 series SoCs. + It differs from the DMA driver due to advanced features + it supports such as scatter-gather and burst transfers. + config DMAMUX_STM32 bool default y diff --git a/drivers/dma/dma_stm32_v3.c b/drivers/dma/dma_stm32_v3.c new file mode 100644 index 0000000000000..16b656d308630 --- /dev/null +++ b/drivers/dma/dma_stm32_v3.c @@ -0,0 +1,868 @@ +/* + * Copyright (C) 2025 Savoir-faire Linux, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +LOG_MODULE_REGISTER(dma_stm32_v3, CONFIG_DMA_LOG_LEVEL); + +#define DT_DRV_COMPAT st_stm32_dma_v3 +#define DMA_STM32_MAX_DATA_ITEMS 0xffff + +/* Since the descriptors pool is allocated statically, we define the number of + * descriptors per channel to be used for linked list trasnfers. + */ +#define DMA_STM32_NUM_DESCRIPTORS_PER_CHANNEL 24 +#define POLLING_TIMEOUT_US (10 * USEC_PER_MSEC) + +struct dma_stm32_descriptor { + uint32_t channel_tr1; + uint32_t channel_tr2; + uint32_t channel_br1; + uint32_t channel_sar; + uint32_t channel_dar; + uint32_t channel_llr; +}; + +struct dma_stm32_channel { + uint32_t direction; + bool hal_override; + bool busy; + uint32_t state; + uint32_t src_size; + uint32_t dst_size; + void *user_data; + uint32_t complete_callback_en; + dma_callback_t dma_callback; + bool cyclic; + int block_count; +}; + +struct dma_stm32_data { + struct dma_context dma_ctx; +}; + +struct dma_stm32_config { + struct stm32_pclken pclken; + void (*config_irq)(const struct device *dev); + DMA_TypeDef *base; + uint32_t max_channels; + struct dma_stm32_channel *channels; + uint32_t *linked_list_buffer; +}; + +static int dma_stm32_id_to_channel(uint32_t id, uint32_t *channel) +{ + static const uint32_t channel_nr[] = { + LL_DMA_CHANNEL_0, LL_DMA_CHANNEL_1, LL_DMA_CHANNEL_2, LL_DMA_CHANNEL_3, + LL_DMA_CHANNEL_4, LL_DMA_CHANNEL_5, LL_DMA_CHANNEL_6, LL_DMA_CHANNEL_7, + LL_DMA_CHANNEL_8, LL_DMA_CHANNEL_9, LL_DMA_CHANNEL_10, LL_DMA_CHANNEL_11, + LL_DMA_CHANNEL_12, LL_DMA_CHANNEL_13, LL_DMA_CHANNEL_14, LL_DMA_CHANNEL_15, + }; + + if (id >= ARRAY_SIZE(channel_nr)) { + LOG_ERR("Invalid channel ID %d", id); + return -EINVAL; + } + + *channel = channel_nr[id]; + return 0; +} + +static DMA_Channel_TypeDef *dma_stm32_get_channel_addr(DMA_TypeDef *dma, uint32_t channel) +{ + return (DMA_Channel_TypeDef *)((uintptr_t)dma + LL_DMA_CH_OFFSET_TAB[channel]); +} + +static int dma_stm32_get_src_inc_mode(enum dma_addr_adj increment, uint32_t *ll_increment) +{ + switch (increment) { + case DMA_ADDR_ADJ_INCREMENT: + *ll_increment = LL_DMA_SRC_INCREMENT; + break; + case DMA_ADDR_ADJ_NO_CHANGE: + *ll_increment = LL_DMA_SRC_FIXED; + break; + case DMA_ADDR_ADJ_DECREMENT: + LOG_ERR("Decrement mode not supported for source address adjustment"); + return -ENOTSUP; + default: + LOG_ERR("Invalid source increment mode: %d", increment); + return -EINVAL; + } + + return 0; +} + +static int dma_stm32_get_dest_inc_mode(enum dma_addr_adj increment, uint32_t *ll_increment) +{ + switch (increment) { + case DMA_ADDR_ADJ_INCREMENT: + *ll_increment = LL_DMA_DEST_INCREMENT; + break; + case DMA_ADDR_ADJ_NO_CHANGE: + *ll_increment = LL_DMA_DEST_FIXED; + break; + case DMA_ADDR_ADJ_DECREMENT: + LOG_ERR("Decrement mode not supported for destination address adjustment"); + return -ENOTSUP; + default: + LOG_ERR("Invalid destination increment mode: %d", increment); + return -EINVAL; + } + + return 0; +} + +static void dma_stm32_get_src_data_width(uint32_t size, uint32_t *ll_src_data_width) +{ + static const uint32_t table_src_size[] = { + LL_DMA_SRC_DATAWIDTH_BYTE, + LL_DMA_SRC_DATAWIDTH_HALFWORD, + LL_DMA_SRC_DATAWIDTH_WORD, + LL_DMA_SRC_DATAWIDTH_DOUBLEWORD, + }; + + *ll_src_data_width = table_src_size[LOG2(size)]; +} + +static void dma_stm32_get_dest_data_width(uint32_t size, uint32_t *ll_dest_data_width) +{ + static const uint32_t table_dst_size[] = { + LL_DMA_DEST_DATAWIDTH_BYTE, + LL_DMA_DEST_DATAWIDTH_HALFWORD, + LL_DMA_DEST_DATAWIDTH_WORD, + LL_DMA_DEST_DATAWIDTH_DOUBLEWORD, + }; + + *ll_dest_data_width = table_dst_size[LOG2(size)]; +} + +static int dma_stm32_get_ll_direction(enum dma_channel_direction direction, uint32_t *ll_direction) +{ + switch (direction) { + case MEMORY_TO_MEMORY: + *ll_direction = LL_DMA_DIRECTION_MEMORY_TO_MEMORY; + break; + case MEMORY_TO_PERIPHERAL: + *ll_direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; + break; + case PERIPHERAL_TO_MEMORY: + *ll_direction = LL_DMA_DIRECTION_PERIPH_TO_MEMORY; + break; + default: + LOG_ERR("Direction error. %d", direction); + return -EINVAL; + } + + return 0; +} + +static int dma_stm32_get_priority(uint8_t priority, uint32_t *ll_priority) +{ + static const uint32_t table_priority[] = { + LL_DMA_LOW_PRIORITY_LOW_WEIGHT, + LL_DMA_LOW_PRIORITY_MID_WEIGHT, + LL_DMA_LOW_PRIORITY_HIGH_WEIGHT, + LL_DMA_HIGH_PRIORITY, + }; + + if (priority >= ARRAY_SIZE(table_priority)) { + LOG_ERR("Priority error."); + return -EINVAL; + } + + *ll_priority = table_priority[priority]; + return 0; +} + +static bool dma_stm32_is_tc_irq_active(DMA_TypeDef *dma, uint32_t channel) +{ + return LL_DMA_IsEnabledIT_TC(dma, channel) && LL_DMA_IsActiveFlag_TC(dma, channel); +} + +static bool dma_stm32_is_ht_irq_active(DMA_TypeDef *dma, uint32_t channel) +{ + return LL_DMA_IsEnabledIT_HT(dma, channel) && LL_DMA_IsActiveFlag_HT(dma, channel); +} + +static void dma_stm32_disable_it(DMA_TypeDef *dma, uint32_t channel) +{ + mem_addr_t dma_channel_ccr_reg = (mem_addr_t)&dma_stm32_get_channel_addr(dma, channel)->CCR; + + sys_clear_bits(dma_channel_ccr_reg, DMA_CCR_TCIE | DMA_CCR_HTIE | DMA_CCR_USEIE | + DMA_CCR_ULEIE | DMA_CCR_DTEIE | DMA_CCR_SUSPIE); +} + +static void dma_stm32_enable_it(DMA_TypeDef *dma, uint32_t channel) +{ + mem_addr_t dma_channel_ccr_reg = (mem_addr_t)&dma_stm32_get_channel_addr(dma, channel)->CCR; + + sys_set_bits(dma_channel_ccr_reg, + DMA_CCR_TCIE | DMA_CCR_USEIE | DMA_CCR_ULEIE | DMA_CCR_DTEIE); +} + +static void dma_stm32_dump_channel_irq(DMA_TypeDef *dma, uint32_t channel) +{ + LOG_INF("tc: %d, ht: %d, dte: %d, ule: %d, use: %d", LL_DMA_IsActiveFlag_TC(dma, channel), + LL_DMA_IsActiveFlag_HT(dma, channel), LL_DMA_IsActiveFlag_DTE(dma, channel), + LL_DMA_IsActiveFlag_ULE(dma, channel), LL_DMA_IsActiveFlag_USE(dma, channel)); +} + +static void dma_stm32_clear_channel_irq(DMA_TypeDef *dma, uint32_t channel) +{ + mem_addr_t dma_channel_cfcr_reg = + (mem_addr_t)&dma_stm32_get_channel_addr(dma, channel)->CFCR; + + sys_set_bits(dma_channel_cfcr_reg, DMA_CFCR_TCF | DMA_CFCR_HTF | DMA_CFCR_DTEF | + DMA_CFCR_ULEF | DMA_CFCR_USEF | DMA_CFCR_TOF | + DMA_CFCR_SUSPF); +} + +static int dma_stm32_disable_channel(DMA_TypeDef *dma, uint32_t channel) +{ + LL_DMA_DisableChannel(dma, channel); + if (WAIT_FOR(!LL_DMA_IsEnabledChannel(dma, channel), POLLING_TIMEOUT_US, k_msleep(1))) { + return 0; + } + + LOG_ERR("Timeout waiting for channel %d to disable", channel); + return -ETIMEDOUT; +} + +static int dma_stm32_validate_transfer_sizes(struct dma_config *config) +{ + if (config->head_block->block_size > DMA_STM32_MAX_DATA_ITEMS) { + LOG_ERR("Data size exceeds the maximum limit: %d>%d", + config->head_block->block_size, DMA_STM32_MAX_DATA_ITEMS); + return -EINVAL; + } + + if (config->source_data_size != 8U && config->source_data_size != 4U && + config->source_data_size != 2U && config->source_data_size != 1U) { + LOG_ERR("Invalid source data size: %u, only 1, 2, 4, 8 bytes supported", + config->source_data_size); + return -EINVAL; + } + LOG_DBG("Source data size: %u", config->source_data_size); + + if (config->dest_data_size != 8U && config->dest_data_size != 4U && + config->dest_data_size != 2U && config->dest_data_size != 1U) { + LOG_ERR("Invalid destination data size: %u, only 1, 2, 4, 8 bytes supported", + config->dest_data_size); + return -EINVAL; + } + LOG_DBG("Destination data size: %u", config->dest_data_size); + + /* TODO: support different data sizes */ + if (config->source_data_size != config->dest_data_size) { + LOG_ERR("Source and destination data sizes do not match: (%u != %u) - not " + "supported yet", + config->source_data_size, config->dest_data_size); + return -ENOTSUP; + } + + return 0; +} + +static void dma_stm32_configure_linked_list(uint32_t channel, struct dma_config *config, + uint32_t *linked_list_node, DMA_TypeDef *dma) +{ + uint32_t next_desc = 1; + struct dma_block_config *block_config; + uint32_t registers_update = 0; + uint32_t addr_offset = 0; + uint32_t descriptor_index = 0; + uint32_t base_addr = 0; + uint32_t next_desc_addr = 0; + + block_config = config->head_block; + base_addr = (uint32_t)&linked_list_node[descriptor_index]; + + LL_DMA_SetLinkedListBaseAddr(dma, channel, base_addr); + + for (uint32_t i = 0; i < config->block_count; i++) { + registers_update = 0; + LOG_DBG("Configuring block descriptor %d for channel %d", i, channel); + + linked_list_node[descriptor_index] = block_config->source_address; + descriptor_index++; + linked_list_node[descriptor_index] = block_config->dest_address; + descriptor_index++; + + if (i < config->block_count - 1) { + registers_update |= + LL_DMA_UPDATE_CSAR | LL_DMA_UPDATE_CDAR | LL_DMA_UPDATE_CLLR; + block_config = block_config->next_block; + next_desc_addr = (uint32_t)&linked_list_node[descriptor_index + 1]; + } else if (config->cyclic) { + LOG_DBG("Last descriptor %d for channel %d, linking to first", i, channel); + registers_update |= + LL_DMA_UPDATE_CSAR | LL_DMA_UPDATE_CDAR | LL_DMA_UPDATE_CLLR; + next_desc_addr = base_addr; + } else { + LOG_DBG("Last descriptor %d for channel %d, no link", i, channel); + registers_update = 0; + next_desc = 0; + } + + if (next_desc != 0) { + addr_offset = next_desc_addr & GENMASK(15, 2); + registers_update |= addr_offset; + } + + linked_list_node[descriptor_index] = registers_update; + descriptor_index++; + + if (i == 0) { + LL_DMA_ConfigLinkUpdate(dma, channel, registers_update, addr_offset); + } + } +} + +int dma_stm32_configure(const struct device *dev, uint32_t id, struct dma_config *config) +{ + const struct dma_stm32_config *dev_config; + struct dma_stm32_channel *channel_config; + struct dma_stm32_descriptor hwdesc; + uint32_t channel; + DMA_TypeDef *dma; + uint32_t src_inc_mode; + uint32_t dest_inc_mode; + uint32_t src_data_width_size; + uint32_t dest_data_width_size; + uint32_t ll_priority; + uint32_t ll_direction; + int ret = 0; + uint32_t ccr = 0; + + if (dev == NULL || config == NULL) { + LOG_ERR("Invalid arguments: dev=%p, config=%p", dev, config); + return -EINVAL; + } + + dev_config = dev->config; + if (id >= dev_config->max_channels) { + LOG_ERR("Invalid channel ID %d, max channels %d", id, dev_config->max_channels); + return -EINVAL; + } + + channel_config = &dev_config->channels[id]; + if (channel_config->busy) { + LOG_ERR("Channel %d is busy", id); + return -EBUSY; + } + + ret = dma_stm32_id_to_channel(id, &channel); + if (ret < 0) { + return ret; + } + + dma = dev_config->base; + + ret = dma_stm32_disable_channel(dma, channel); + if (ret < 0) { + LOG_ERR("Failed to disable DMA channel %d", id); + return ret; + } + + dma_stm32_clear_channel_irq(dma, channel); + + ret = dma_stm32_validate_transfer_sizes(config); + if (ret < 0) { + return ret; + } + + ret = dma_stm32_get_src_inc_mode(config->head_block->source_addr_adj, &src_inc_mode); + if (ret < 0) { + return ret; + } + LOG_DBG("Source address increment: %d", src_inc_mode); + + ret = dma_stm32_get_dest_inc_mode(config->head_block->dest_addr_adj, &dest_inc_mode); + if (ret < 0) { + return ret; + } + LOG_DBG("Destination address increment: %d", dest_inc_mode); + + dma_stm32_get_src_data_width(config->source_data_size, &src_data_width_size); + dma_stm32_get_dest_data_width(config->dest_data_size, &dest_data_width_size); + + ret = dma_stm32_get_priority(config->channel_priority, &ll_priority); + if (ret < 0) { + return ret; + } + + ret = dma_stm32_get_ll_direction(config->channel_direction, &ll_direction); + if (ret < 0) { + return ret; + } + + channel_config->busy = true; + channel_config->dma_callback = config->dma_callback; + channel_config->direction = config->channel_direction; + channel_config->user_data = config->user_data; + channel_config->src_size = config->source_data_size; + channel_config->dst_size = config->dest_data_size; + channel_config->cyclic = config->cyclic; + channel_config->complete_callback_en = config->complete_callback_en; + + dma_stm32_disable_it(dma, channel); + + /* Reset any previous linked list configuration */ + LL_DMA_SetLinkedListBaseAddr(dma, channel, 0); + + int linked_list_needed = (config->block_count > 1) || config->cyclic; + + if (!linked_list_needed) { + ccr |= LL_DMA_LSM_1LINK_EXECUTION; + } else { + ccr |= LL_DMA_LSM_FULL_EXECUTION; + + dma_stm32_configure_linked_list(channel, config, + dev_config->linked_list_buffer + + id * DMA_STM32_NUM_DESCRIPTORS_PER_CHANNEL, + dma); + } + + /* TODO: support port specifier from configuration */ + ccr |= ll_priority; + ccr |= LL_DMA_LINK_ALLOCATED_PORT0; + + LL_DMA_ConfigControl(dma, channel, ccr); + + hwdesc.channel_tr1 = + dest_inc_mode | dest_data_width_size | src_inc_mode | src_data_width_size; + + LL_DMA_ConfigTransfer(dma, channel, hwdesc.channel_tr1); + + LL_DMA_ConfigBurstLength(dma, channel, config->source_burst_length, + config->dest_burst_length); + + hwdesc.channel_tr2 = ll_direction; + + if (linked_list_needed) { + if (channel_config->complete_callback_en == 1) { + hwdesc.channel_tr2 |= LL_DMA_TCEM_EACH_LLITEM_TRANSFER; + LOG_DBG("Enabling TC callback at the end of each linked list item"); + } else { + hwdesc.channel_tr2 |= LL_DMA_TCEM_LAST_LLITEM_TRANSFER; + LOG_DBG("Enabling TC callback at the end of last linked list item"); + } + } else { + hwdesc.channel_tr2 |= LL_DMA_TCEM_BLK_TRANSFER; + LOG_DBG("Enabling TC callback at the end of the block"); + } + + LL_DMA_ConfigChannelTransfer(dma, channel, hwdesc.channel_tr2); + + if (ll_direction != LL_DMA_DIRECTION_MEMORY_TO_MEMORY) { + LL_DMA_SetPeriphRequest(dma, channel, config->dma_slot); + } + + hwdesc.channel_br1 = config->head_block->block_size; + + LL_DMA_SetBlkDataLength(dma, channel, hwdesc.channel_br1); + + hwdesc.channel_sar = config->head_block->source_address; + hwdesc.channel_dar = config->head_block->dest_address; + + LL_DMA_ConfigAddresses(dma, channel, hwdesc.channel_sar, hwdesc.channel_dar); + + dma_stm32_enable_it(dma, channel); + + return 0; +} + +static int dma_stm32_reload(const struct device *dev, uint32_t id, uint32_t src, uint32_t dst, + size_t size) +{ + const struct dma_stm32_config *dev_config; + struct dma_stm32_channel *channel_config; + uint32_t channel; + DMA_TypeDef *dma; + int ret = 0; + + if (dev == NULL) { + LOG_ERR("Invalid device pointer"); + return -EINVAL; + } + + dev_config = dev->config; + + if (id >= dev_config->max_channels) { + LOG_ERR("Invalid channel ID %d, max channels %d", id, dev_config->max_channels); + return -EINVAL; + } + + channel_config = &dev_config->channels[id]; + dma = dev_config->base; + + ret = dma_stm32_id_to_channel(id, &channel); + if (ret < 0) { + return ret; + } + + ret = dma_stm32_disable_channel(dma, channel); + if (ret < 0) { + return ret; + } + + LL_DMA_ConfigAddresses(dma, channel, src, dst); + + LL_DMA_SetBlkDataLength(dma, channel, size); + + channel_config->busy = true; + + LL_DMA_EnableChannel(dma, channel); + + return 0; +} + +static int dma_stm32_start(const struct device *dev, uint32_t id) +{ + const struct dma_stm32_config *dev_config; + struct dma_stm32_channel *channel_config; + uint32_t channel; + DMA_TypeDef *dma; + int ret = 0; + + if (dev == NULL) { + LOG_ERR("Invalid device pointer"); + return -EINVAL; + } + + dev_config = dev->config; + + if (id >= dev_config->max_channels) { + LOG_ERR("Invalid channel ID %d, max channels %d", id, dev_config->max_channels); + return -EINVAL; + } + + channel_config = &dev_config->channels[id]; + dma = dev_config->base; + + ret = dma_stm32_id_to_channel(id, &channel); + if (ret < 0) { + return ret; + } + + if (LL_DMA_IsEnabledChannel(dma, channel)) { + LOG_INF("Channel %d is already enabled", id); + return 0; + } + + /* When starting the dma, the stream is busy before enabling */ + channel_config->busy = true; + + dma_stm32_clear_channel_irq(dma, channel); + + LL_DMA_EnableChannel(dma, channel); + + return 0; +} + +static int dma_stm32_stop(const struct device *dev, uint32_t id) +{ + const struct dma_stm32_config *dev_config; + struct dma_stm32_channel *channel_config; + uint32_t channel; + DMA_TypeDef *dma; + int ret = 0; + + if (dev == NULL) { + LOG_ERR("Invalid device pointer"); + return -EINVAL; + } + + dev_config = dev->config; + + if (id >= dev_config->max_channels) { + LOG_ERR("Invalid channel ID %d, max channels %d", id, dev_config->max_channels); + return -EINVAL; + } + + channel_config = &dev_config->channels[id]; + dma = dev_config->base; + + ret = dma_stm32_id_to_channel(id, &channel); + if (ret < 0) { + return ret; + } + + if (channel_config->hal_override) { + channel_config->busy = false; + return 0; + } + + if (!LL_DMA_IsEnabledChannel(dma, channel)) { + return 0; + } + + dma_stm32_clear_channel_irq(dma, channel); + + dma_stm32_disable_it(dma, channel); + + if (dma_stm32_disable_channel(dma, channel)) { + LOG_ERR("Failed to disable DMA channel %d", id); + return -EBUSY; + } + + channel_config->busy = false; + + return 0; +} + +static int dma_stm32_get_status(const struct device *dev, uint32_t id, struct dma_status *status) +{ + const struct dma_stm32_config *dev_config; + struct dma_stm32_channel *channel_config; + uint32_t channel; + DMA_TypeDef *dma; + int ret = 0; + + if (dev == NULL) { + LOG_ERR("Invalid device pointer"); + return -EINVAL; + } + + dev_config = dev->config; + + if (id >= dev_config->max_channels) { + LOG_ERR("Invalid channel ID %d, max channels %d", id, dev_config->max_channels); + return -EINVAL; + } + + channel_config = &dev_config->channels[id]; + dma = dev_config->base; + + ret = dma_stm32_id_to_channel(id, &channel); + if (ret < 0) { + return ret; + } + + status->pending_length = LL_DMA_GetBlkDataLength(dma, channel); + status->dir = channel_config->direction; + status->busy = channel_config->busy; + + return 0; +} + +static int dma_stm32_suspend(const struct device *dev, uint32_t id) +{ + const struct dma_stm32_config *dev_config; + uint32_t channel; + DMA_TypeDef *dma; + int ret = 0; + + if (dev == NULL) { + LOG_ERR("Invalid device pointer"); + return -EINVAL; + } + + dev_config = dev->config; + + if (id >= dev_config->max_channels) { + LOG_ERR("Invalid channel ID %d, max channels %d", id, dev_config->max_channels); + return -EINVAL; + } + + dma = dev_config->base; + + ret = dma_stm32_id_to_channel(id, &channel); + if (ret < 0) { + return ret; + } + + LL_DMA_SuspendChannel(dma, channel); + if (WAIT_FOR(LL_DMA_IsActiveFlag_SUSP(dma, channel), POLLING_TIMEOUT_US, k_msleep(1))) { + return 0; + } + + LOG_ERR("Timeout waiting for channel %d to suspend", channel); + return -ETIMEDOUT; +} + +static int dma_stm32_resume(const struct device *dev, uint32_t id) +{ + const struct dma_stm32_config *dev_config; + uint32_t channel; + DMA_TypeDef *dma; + int ret = 0; + + if (dev == NULL) { + LOG_ERR("Invalid device pointer"); + return -EINVAL; + } + + dev_config = dev->config; + + if (id >= dev_config->max_channels) { + LOG_ERR("Invalid channel ID %d, max channels %d", id, dev_config->max_channels); + return -EINVAL; + } + + dma = dev_config->base; + + ret = dma_stm32_id_to_channel(id, &channel); + if (ret < 0) { + return ret; + } + + dma = dev_config->base; + + LL_DMA_ResumeChannel(dma, channel); + + return 0; +} + +static void dma_stm32_irq_handler(const struct device *dev, uint32_t id) +{ + const struct dma_stm32_config *dev_config = dev->config; + struct dma_stm32_channel *channel_config; + uint32_t channel; + DMA_TypeDef *dma; + uint32_t callback_arg; + int ret; + + channel_config = &dev_config->channels[id]; + + ret = dma_stm32_id_to_channel(id, &channel); + if (ret < 0) { + return; + } + + dma = dev_config->base; + + /* The busy channel is pertinent if not overridden by the HAL */ + if (!channel_config->hal_override && !channel_config->busy) { + /* + * When DMA channel is not overridden by HAL, + * ignore irq if the channel is not busy anymore + */ + dma_stm32_clear_channel_irq(dma, channel); + return; + } + callback_arg = id; + + if (dma_stm32_is_ht_irq_active(dma, channel)) { + if (!channel_config->hal_override) { + LL_DMA_ClearFlag_HT(dma, channel); + } + + channel_config->dma_callback(dev, channel_config->user_data, callback_arg, + DMA_STATUS_BLOCK); + } else if (dma_stm32_is_tc_irq_active(dma, channel)) { + if (!channel_config->hal_override) { + LL_DMA_ClearFlag_TC(dma, channel); + } + + if (channel_config->complete_callback_en == 1) { + channel_config->dma_callback(dev, channel_config->user_data, callback_arg, + DMA_STATUS_BLOCK); + } else { + if (!channel_config->cyclic) { + channel_config->busy = false; + } + channel_config->dma_callback(dev, channel_config->user_data, callback_arg, + DMA_STATUS_COMPLETE); + } + } else { + LOG_ERR("Transfer Error."); + channel_config->busy = false; + dma_stm32_dump_channel_irq(dma, channel); + dma_stm32_clear_channel_irq(dma, channel); + channel_config->dma_callback(dev, channel_config->user_data, callback_arg, -EIO); + } +} + +static int dma_stm32_init(const struct device *dev) +{ + const struct dma_stm32_config *dev_config = dev->config; + struct dma_stm32_data *dev_data = dev->data; + + for (uint32_t i = 0; i < dev_config->max_channels; i++) { + dev_config->channels[i].busy = false; + } + + memset(dev_data, 0, sizeof(*dev_data)); + dev_config->config_irq(dev); + + return 0; +} + +static DEVICE_API(dma, dma_funcs) = { + .config = dma_stm32_configure, + .reload = dma_stm32_reload, + .start = dma_stm32_start, + .stop = dma_stm32_stop, + .get_status = dma_stm32_get_status, + .suspend = dma_stm32_suspend, + .resume = dma_stm32_resume, +}; + +#define DMA_STM32_IRQ_CONNECT_CHANNEL(chan, dma) \ + do { \ + IRQ_CONNECT(DT_INST_IRQ_BY_IDX(dma, chan, irq), \ + DT_INST_IRQ_BY_IDX(dma, chan, priority), dma_stm32_irq_##dma##_##chan, \ + DEVICE_DT_INST_GET(dma), 0); \ + irq_enable(DT_INST_IRQ_BY_IDX(dma, chan, irq)); \ + } while (0) + +#define DMA_STM32_IRQ_CONNECT(index) \ + static void dma_stm32_config_irq_##index(const struct device *dev) \ + { \ + ARG_UNUSED(dev); \ + \ + LISTIFY(DT_INST_PROP(index, dma_channels), \ + DMA_STM32_IRQ_CONNECT_CHANNEL, (;), index); \ + } + +#define DMA_STM32_DEFINE_IRQ_HANDLER(chan, dma) \ + static void dma_stm32_irq_##dma##_##chan(const struct device *dev) \ + { \ + dma_stm32_irq_handler(dev, chan); \ + } + +#define DMA_STM32_INIT_DEV(index) \ + BUILD_ASSERT(DT_INST_PROP(index, dma_channels) == DT_NUM_IRQS(DT_DRV_INST(index)), \ + "Nb of Channels and IRQ mismatch"); \ + \ + LISTIFY(DT_INST_PROP(index, dma_channels), \ + DMA_STM32_DEFINE_IRQ_HANDLER, (;), index); \ + \ + DMA_STM32_IRQ_CONNECT(index); \ + \ + static struct dma_stm32_channel dma_stm32_channels_##index[DT_INST_PROP_OR( \ + index, dma_channels, DT_NUM_IRQS(DT_DRV_INST(index)))]; \ + \ + static uint32_t dma_stm32_linked_list_buffer##index \ + [DMA_STM32_NUM_DESCRIPTORS_PER_CHANNEL * \ + DT_INST_PROP_OR(index, dma_channels, DT_NUM_IRQS(DT_DRV_INST(index)))] __nocache; \ + \ + const struct dma_stm32_config dma_stm32_config_##index = { \ + COND_CODE_1(DT_NODE_HAS_PROP(__node, clocks), \ + (.pclken = { .bus = __bus, .enr = __cenr },), \ + (/* Nothing if clocks not present */)) \ + .config_irq = dma_stm32_config_irq_##index, \ + .base = (DMA_TypeDef *)DT_INST_REG_ADDR(index), \ + .max_channels = \ + DT_INST_PROP_OR(index, dma_channels, DT_NUM_IRQS(DT_DRV_INST(index))), \ + .channels = dma_stm32_channels_##index, \ + .linked_list_buffer = dma_stm32_linked_list_buffer##index \ + }; \ + \ + static struct dma_stm32_data dma_stm32_data_##index = {}; \ + \ + DEVICE_DT_INST_DEFINE(index, dma_stm32_init, NULL, &dma_stm32_data_##index, \ + &dma_stm32_config_##index, PRE_KERNEL_1, CONFIG_DMA_INIT_PRIORITY, \ + &dma_funcs); + +DT_INST_FOREACH_STATUS_OKAY(DMA_STM32_INIT_DEV) diff --git a/drivers/serial/Kconfig.stm32 b/drivers/serial/Kconfig.stm32 index 83ca475c1180e..2ade613849a21 100644 --- a/drivers/serial/Kconfig.stm32 +++ b/drivers/serial/Kconfig.stm32 @@ -14,7 +14,8 @@ config UART_STM32 if DT_HAS_ST_STM32_DMA_V1_ENABLED || \ DT_HAS_ST_STM32_DMA_V2_ENABLED || \ DT_HAS_ST_STM32_DMA_V2BIS_ENABLED || \ - DT_HAS_ST_STM32U5_DMA_ENABLED + DT_HAS_ST_STM32U5_DMA_ENABLED || \ + DT_HAS_ST_STM32_DMA_V3_ENABLED select DMA if UART_ASYNC_API select RESET select PINCTRL diff --git a/dts/arm/st/mp2/stm32mp2_m33.dtsi b/dts/arm/st/mp2/stm32mp2_m33.dtsi index 1d52adb6c97ea..7bdde23d96f90 100644 --- a/dts/arm/st/mp2/stm32mp2_m33.dtsi +++ b/dts/arm/st/mp2/stm32mp2_m33.dtsi @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -430,6 +431,20 @@ interrupts = <8 0>; status = "disabled"; }; + + hpdma3: dma@40420000 { + compatible = "st,stm32-dma-v3"; + reg = <0x40420000 DT_SIZE_K(4)>; + #dma-cells = <3>; + interrupts = <65 0>, <66 0>, <67 0>, <68 0>, + <69 0>, <70 0>, <71 0>, <72 0>, + <73 0>, <74 0>, <75 0>, <76 0>, + <77 0>, <78 0>; + dma-channels = <14>; + dma-requests = <183>; + dma-offset = <0>; + status = "disabled"; + }; }; clocks { diff --git a/dts/bindings/dma/st,stm32-dma-v3.yaml b/dts/bindings/dma/st,stm32-dma-v3.yaml new file mode 100644 index 0000000000000..cc151725835b6 --- /dev/null +++ b/dts/bindings/dma/st,stm32-dma-v3.yaml @@ -0,0 +1,76 @@ +# Copyright (C) 2025 Savoir-faire Linux, Inc. +# SPDX-License-Identifier: Apache-2.0 + +description: | + STM32 DMA controller V3. + + This DMA controller is what is used in the STM32MP2 series SoCs in the form + of HPDMA, high-performance DMA. It supports 16 independent DMA channels + and 256 DMA requests from peripherals. + DMA clients connected to the STM32 HPDMA controller must use a three-cell + specifier for each channel. + + It is a phandle to the STM32 DMA3 controller plus the following three integer + cells: + 1. channel: The DMA channel number (0 to 15) + 2. request: The DMA request line number (0 to 255) + 3. channel-config: A 32-bit mask specifying the DMA channel configuration + which is device dependent (see 'dma_stm32.h'): + - bit 5: Cyclic Mode + 0x0: STM32_DMA_MODE_NORMAL + 0x1: STM32_DMA_MODE_CYCLIC + - bits 6-7: Direction + 0x0: STM32_DMA_MEMORY_TO_MEMORY: MEM to MEM + 0x1: STM32_DMA_MEMORY_TO_PERIPH: MEM to PERIPH + 0x2: STM32_DMA_PERIPH_TO_MEMORY: PERIPH to MEM + 0x3: reserved for PERIPH to PERIPH + - bit 9: Peripheral Address Increment + 0x0: STM32_DMA_PERIPH_NO_INC: no address increment between transfers + 0x1: STM32_DMA_PERIPH_INC: increment address between transfers + - bit 10: Memory Address Increment + 0x0: STM32_DMA_MEM_NO_INC: no address increment between transfers + 0x1: STM32_DMA_MEM_INC: increment address between transfers + - bits 11-12: Peripheral Data Size + 0x0: STM32_DMA_PERIPH_8BITS: Byte (8 bits) + 0x1: STM32_DMA_PERIPH_16BITS: Half-word (16 bits) + 0x2: STM32_DMA_PERIPH_32BITS: Word (32 bits) + 0x3: STM32_DMA_PERIPH_64BITS: Double-word (64 bits) + - bits 13-14: Memory Data Size + 0x0: STM32_DMA_MEM_8BITS: Byte (8 bits) + 0x1: STM32_DMA_MEM_16BITS: Half-word (16 bits) + 0x2: STM32_DMA_MEM_32BITS: Word (32 bits) + 0x3: STM32_DMA_MEM_64BITS: Double-word (64 bits) + - bit 15: Reserved + - bits 16-17: Priority Level + 0x0: STM32_DMA_PRIORITY_LOW: Low + 0x1: STM32_DMA_PRIORITY_MEDIUM: Medium + 0x2: STM32_DMA_PRIORITY_HIGH: High + 0x3: STM32_DMA_PRIORITY_VERY_HIGH: Very High + + For the client part, example for stm32mp257f-ev1 on the CM33 using the HPDMA3 + instance: + rx using channel 0 with request 17 for uart5_rx + tx using channel 1 with request 18 for uart5_tx + uart5 { + dmas = <&hpdma3 0 18 (STM32_DMA_PERIPH_TX | STM32_DMA_PRIORITY_HIGH)>, + <&hpdma3 1 17 (STM32_DMA_PERIPH_RX | STM32_DMA_PRIORITY_HIGH)>; + dma-names = "tx", "rx"; + }; + +compatible: "st,stm32-dma-v3" + +include: + - name: st,stm32-dma.yaml + +properties: + "#dma-cells": + const: 3 + +# Parameter syntax of stm32 follows the dma client dts syntax +# in the Linux kernel declared in +# https://git.kernel.org/pub/scm/linux/kernel/git/devicetree/devicetree-rebasing.git/plain/Bindings/dma/stm32/st,stm32-dma3.yaml + +dma-cells: + - channel + - slot + - channel-config diff --git a/include/zephyr/drivers/dma/dma_stm32.h b/include/zephyr/drivers/dma/dma_stm32.h index d369ab2ae2ce5..7aeb875198956 100644 --- a/include/zephyr/drivers/dma/dma_stm32.h +++ b/include/zephyr/drivers/dma/dma_stm32.h @@ -57,30 +57,30 @@ /* macros for channel-config */ /* enable circular buffer */ -#define STM32_DMA_CONFIG_CYCLIC(config) ((config >> 5) & 0x1) +#define STM32_DMA_CONFIG_CYCLIC(config) (((config) >> 5) & 0x1) /* direction defined on bits 6-7 */ /* 0 -> MEM_TO_MEM, 1 -> MEM_TO_PERIPH, 2 -> PERIPH_TO_MEM */ -#define STM32_DMA_CONFIG_DIRECTION(config) ((config >> 6) & 0x3) +#define STM32_DMA_CONFIG_DIRECTION(config) (((config) >> 6) & 0x3) /* periph increment defined on bit 9 as true/false */ -#define STM32_DMA_CONFIG_PERIPHERAL_ADDR_INC(config) ((config >> 9) & 0x1) +#define STM32_DMA_CONFIG_PERIPHERAL_ADDR_INC(config) (((config) >> 9) & 0x1) /* mem increment defined on bit 10 as true/false */ -#define STM32_DMA_CONFIG_MEMORY_ADDR_INC(config) ((config >> 10) & 0x1) +#define STM32_DMA_CONFIG_MEMORY_ADDR_INC(config) (((config) >> 10) & 0x1) /* periph data size defined on bits 11-12 */ /* 0 -> 1 byte, 1 -> 2 bytes, 2 -> 4 bytes */ #define STM32_DMA_CONFIG_PERIPHERAL_DATA_SIZE(config) \ - (1 << ((config >> 11) & 0x3)) + (1 << (((config) >> 11) & 0x3)) /* memory data size defined on bits 13, 14 */ /* 0 -> 1 byte, 1 -> 2 bytes, 2 -> 4 bytes */ #define STM32_DMA_CONFIG_MEMORY_DATA_SIZE(config) \ - (1 << ((config >> 13) & 0x3)) + (1 << (((config) >> 13) & 0x3)) /* priority increment offset defined on bit 15 */ -#define STM32_DMA_CONFIG_PERIPHERAL_INC_FIXED(config) ((config >> 15) & 0x1) +#define STM32_DMA_CONFIG_PERIPHERAL_INC_FIXED(config) (((config) >> 15) & 0x1) /* priority defined on bits 16-17 as 0, 1, 2, 3 */ -#define STM32_DMA_CONFIG_PRIORITY(config) ((config >> 16) & 0x3) +#define STM32_DMA_CONFIG_PRIORITY(config) (((config) >> 16) & 0x3) /* macro for features (only for dma-v1) */ #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_dma_v1) -#define STM32_DMA_FEATURES_FIFO_THRESHOLD(features) (features & 0x3) +#define STM32_DMA_FEATURES_FIFO_THRESHOLD(features) ((features) & 0x3) #else #define STM32_DMA_FEATURES_FIFO_THRESHOLD(features) 0 #endif diff --git a/include/zephyr/dt-bindings/clock/stm32mp2_clock.h b/include/zephyr/dt-bindings/clock/stm32mp2_clock.h index 5a11ed64d4049..4fc6ffaa249b5 100644 --- a/include/zephyr/dt-bindings/clock/stm32mp2_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32mp2_clock.h @@ -39,6 +39,12 @@ #define STM32_CLOCK_PERIPH_GPIOK 0x554 #define STM32_CLOCK_PERIPH_GPIOZ 0x558 +/* HPDMA/LPDMA */ +#define STM32_CLOCK_PERIPH_HPDMA1 0x55C +#define STM32_CLOCK_PERIPH_HPDMA2 0x560 +#define STM32_CLOCK_PERIPH_HPDMA3 0x564 +#define STM32_CLOCK_PERIPH_LPDMA1 0x568 + /* SPI Peripheral */ #define STM32_CLOCK_PERIPH_SPI1 0x758 #define STM32_CLOCK_PERIPH_SPI2 0x75C diff --git a/include/zephyr/dt-bindings/dma/stm32_dma.h b/include/zephyr/dt-bindings/dma/stm32_dma.h index 6eb1e5be139f0..345eb9d882fee 100644 --- a/include/zephyr/dt-bindings/dma/stm32_dma.h +++ b/include/zephyr/dt-bindings/dma/stm32_dma.h @@ -11,46 +11,46 @@ * @{ */ /** DMA cyclic mode config on bit 5*/ -#define STM32_DMA_CH_CFG_MODE(val) ((val & 0x1) << 5) +#define STM32_DMA_CH_CFG_MODE(val) (((val) & 0x1) << 5) #define STM32_DMA_MODE_NORMAL STM32_DMA_CH_CFG_MODE(0) #define STM32_DMA_MODE_CYCLIC STM32_DMA_CH_CFG_MODE(1) /** DMA transfer direction config on bits 6-7 */ -#define STM32_DMA_CH_CFG_DIRECTION(val) ((val & 0x3) << 6) +#define STM32_DMA_CH_CFG_DIRECTION(val) (((val) & 0x3) << 6) #define STM32_DMA_MEMORY_TO_MEMORY STM32_DMA_CH_CFG_DIRECTION(0) #define STM32_DMA_MEMORY_TO_PERIPH STM32_DMA_CH_CFG_DIRECTION(1) #define STM32_DMA_PERIPH_TO_MEMORY STM32_DMA_CH_CFG_DIRECTION(2) #define STM32_DMA_PERIPH_TO_PERIPH STM32_DMA_CH_CFG_DIRECTION(3) /** DMA Peripheral increment Address config on bit 9 */ -#define STM32_DMA_CH_CFG_PERIPH_ADDR_INC(val) ((val & 0x1) << 9) +#define STM32_DMA_CH_CFG_PERIPH_ADDR_INC(val) (((val) & 0x1) << 9) #define STM32_DMA_PERIPH_NO_INC STM32_DMA_CH_CFG_PERIPH_ADDR_INC(0) #define STM32_DMA_PERIPH_INC STM32_DMA_CH_CFG_PERIPH_ADDR_INC(1) /** DMA Memory increment Address config on bit 10 */ -#define STM32_DMA_CH_CFG_MEM_ADDR_INC(val) ((val & 0x1) << 10) +#define STM32_DMA_CH_CFG_MEM_ADDR_INC(val) (((val) & 0x1) << 10) #define STM32_DMA_MEM_NO_INC STM32_DMA_CH_CFG_MEM_ADDR_INC(0) #define STM32_DMA_MEM_INC STM32_DMA_CH_CFG_MEM_ADDR_INC(1) /** DMA Peripheral data size config on bits 11, 12 */ -#define STM32_DMA_CH_CFG_PERIPH_WIDTH(val) ((val & 0x3) << 11) +#define STM32_DMA_CH_CFG_PERIPH_WIDTH(val) (((val) & 0x3) << 11) #define STM32_DMA_PERIPH_8BITS STM32_DMA_CH_CFG_PERIPH_WIDTH(0) #define STM32_DMA_PERIPH_16BITS STM32_DMA_CH_CFG_PERIPH_WIDTH(1) #define STM32_DMA_PERIPH_32BITS STM32_DMA_CH_CFG_PERIPH_WIDTH(2) /** DMA Memory data size config on bits 13, 14 */ -#define STM32_DMA_CH_CFG_MEM_WIDTH(val) ((val & 0x3) << 13) +#define STM32_DMA_CH_CFG_MEM_WIDTH(val) (((val) & 0x3) << 13) #define STM32_DMA_MEM_8BITS STM32_DMA_CH_CFG_MEM_WIDTH(0) #define STM32_DMA_MEM_16BITS STM32_DMA_CH_CFG_MEM_WIDTH(1) #define STM32_DMA_MEM_32BITS STM32_DMA_CH_CFG_MEM_WIDTH(2) /** DMA Peripheral increment offset config on bit 15 */ -#define STM32_DMA_CH_CFG_PERIPH_INC_FIXED(val) ((val & 0x1) << 15) +#define STM32_DMA_CH_CFG_PERIPH_INC_FIXED(val) (((val) & 0x1) << 15) #define STM32_DMA_OFFSET_LINKED_BUS STM32_DMA_CH_CFG_PERIPH_INC_FIXED(0) #define STM32_DMA_OFFSET_FIXED_4 STM32_DMA_CH_CFG_PERIPH_INC_FIXED(1) /** DMA Priority config on bits 16, 17*/ -#define STM32_DMA_CH_CFG_PRIORITY(val) ((val & 0x3) << 16) +#define STM32_DMA_CH_CFG_PRIORITY(val) (((val) & 0x3) << 16) #define STM32_DMA_PRIORITY_LOW STM32_DMA_CH_CFG_PRIORITY(0) #define STM32_DMA_PRIORITY_MEDIUM STM32_DMA_CH_CFG_PRIORITY(1) #define STM32_DMA_PRIORITY_HIGH STM32_DMA_CH_CFG_PRIORITY(2) diff --git a/samples/boards/st/uart/circular_dma/boards/stm32mp257f_ev1_stm32mp257fxx_m33.overlay b/samples/boards/st/uart/circular_dma/boards/stm32mp257f_ev1_stm32mp257fxx_m33.overlay new file mode 100644 index 0000000000000..aebe5bbb2a05b --- /dev/null +++ b/samples/boards/st/uart/circular_dma/boards/stm32mp257f_ev1_stm32mp257fxx_m33.overlay @@ -0,0 +1,17 @@ +/* + * Copyright (C) 2025 Savoir-faire Linux, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&uart5 { + dmas = <&hpdma3 0 18 STM32_DMA_PERIPH_TX>, + <&hpdma3 1 17 (STM32_DMA_PERIPH_RX | STM32_DMA_MEM_8BITS | + STM32_DMA_MODE_CYCLIC)>; + dma-names = "tx", "rx"; + fifo-enable; +}; + +&hpdma3 { + status = "okay"; +}; diff --git a/samples/drivers/uart/async_api/boards/stm32mp257f_ev1_stm32mp257fxx_m33.overlay b/samples/drivers/uart/async_api/boards/stm32mp257f_ev1_stm32mp257fxx_m33.overlay new file mode 100644 index 0000000000000..cfd1d156a687f --- /dev/null +++ b/samples/drivers/uart/async_api/boards/stm32mp257f_ev1_stm32mp257fxx_m33.overlay @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2025 Savoir-faire Linux, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&uart5 { + dmas = <&hpdma3 1 18 (STM32_DMA_PERIPH_TX)>, + <&hpdma3 0 17 (STM32_DMA_PERIPH_RX)>; + dma-names = "tx", "rx"; + fifo-enable; +}; + +&hpdma3 { + status = "okay"; +}; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/stm32mp257f_ev1_stm32mp257fxx_m33.conf b/tests/drivers/dma/chan_blen_transfer/boards/stm32mp257f_ev1_stm32mp257fxx_m33.conf new file mode 100644 index 0000000000000..0f291d964a897 --- /dev/null +++ b/tests/drivers/dma/chan_blen_transfer/boards/stm32mp257f_ev1_stm32mp257fxx_m33.conf @@ -0,0 +1,5 @@ +# Copyright (C) 2025 Savoir-faire Linux, Inc. +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_DMA_TRANSFER_CHANNEL_NR_0=0 +CONFIG_DMA_TRANSFER_CHANNEL_NR_1=13 diff --git a/tests/drivers/dma/chan_blen_transfer/boards/stm32mp257f_ev1_stm32mp257fxx_m33.overlay b/tests/drivers/dma/chan_blen_transfer/boards/stm32mp257f_ev1_stm32mp257fxx_m33.overlay new file mode 100644 index 0000000000000..ba0692a68950f --- /dev/null +++ b/tests/drivers/dma/chan_blen_transfer/boards/stm32mp257f_ev1_stm32mp257fxx_m33.overlay @@ -0,0 +1,9 @@ +/* + * Copyright (C) 2025 Savoir-faire Linux, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +tst_dma0: &hpdma3 { + status = "okay"; +}; diff --git a/tests/drivers/dma/cyclic/boards/stm32mp257f_ev1_stm32mp257fxx_m33.overlay b/tests/drivers/dma/cyclic/boards/stm32mp257f_ev1_stm32mp257fxx_m33.overlay new file mode 100644 index 0000000000000..10ee0cedddb37 --- /dev/null +++ b/tests/drivers/dma/cyclic/boards/stm32mp257f_ev1_stm32mp257fxx_m33.overlay @@ -0,0 +1,15 @@ +/* + * Copyright (C) 2025 Savoir-faire Linux, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + dma0 = &hpdma3; + }; +}; + +&hpdma3 { + status = "okay"; +}; diff --git a/tests/drivers/dma/cyclic/testcase.yaml b/tests/drivers/dma/cyclic/testcase.yaml index ab5959ca0ebd8..98d03e37cd44f 100644 --- a/tests/drivers/dma/cyclic/testcase.yaml +++ b/tests/drivers/dma/cyclic/testcase.yaml @@ -7,4 +7,5 @@ tests: platform_allow: - xmc47_relax_kit - xmc45_relax_kit + - stm32mp257f_ev1/stm32mp257fxx/m33 filter: dt_alias_exists("dma0") diff --git a/tests/drivers/dma/loop_transfer/boards/stm32mp257f_ev1_stm32mp257fxx_m33.conf b/tests/drivers/dma/loop_transfer/boards/stm32mp257f_ev1_stm32mp257fxx_m33.conf new file mode 100644 index 0000000000000..6f8f2b132e2c6 --- /dev/null +++ b/tests/drivers/dma/loop_transfer/boards/stm32mp257f_ev1_stm32mp257fxx_m33.conf @@ -0,0 +1,4 @@ +# Copyright (C) 2025 Savoir-faire Linux, Inc. +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_DMA_LOOP_TRANSFER_CHANNEL_NR=0 diff --git a/tests/drivers/dma/loop_transfer/boards/stm32mp257f_ev1_stm32mp257fxx_m33.overlay b/tests/drivers/dma/loop_transfer/boards/stm32mp257f_ev1_stm32mp257fxx_m33.overlay new file mode 100644 index 0000000000000..ba0692a68950f --- /dev/null +++ b/tests/drivers/dma/loop_transfer/boards/stm32mp257f_ev1_stm32mp257fxx_m33.overlay @@ -0,0 +1,9 @@ +/* + * Copyright (C) 2025 Savoir-faire Linux, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +tst_dma0: &hpdma3 { + status = "okay"; +}; diff --git a/tests/drivers/dma/scatter_gather/boards/stm32mp257f_ev1_stm32mp257fxx_m33.conf b/tests/drivers/dma/scatter_gather/boards/stm32mp257f_ev1_stm32mp257fxx_m33.conf new file mode 100644 index 0000000000000..dc1f88384740d --- /dev/null +++ b/tests/drivers/dma/scatter_gather/boards/stm32mp257f_ev1_stm32mp257fxx_m33.conf @@ -0,0 +1,4 @@ +# Copyright (C) 2025 Savoir-faire Linux, Inc. +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_DMA_SG_CHANNEL_NR=0 diff --git a/tests/drivers/dma/scatter_gather/boards/stm32mp257f_ev1_stm32mp257fxx_m33.overlay b/tests/drivers/dma/scatter_gather/boards/stm32mp257f_ev1_stm32mp257fxx_m33.overlay new file mode 100644 index 0000000000000..10ee0cedddb37 --- /dev/null +++ b/tests/drivers/dma/scatter_gather/boards/stm32mp257f_ev1_stm32mp257fxx_m33.overlay @@ -0,0 +1,15 @@ +/* + * Copyright (C) 2025 Savoir-faire Linux, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + dma0 = &hpdma3; + }; +}; + +&hpdma3 { + status = "okay"; +}; diff --git a/tests/drivers/dma/scatter_gather/testcase.yaml b/tests/drivers/dma/scatter_gather/testcase.yaml index 0e08abae59da4..a4073ec786c94 100644 --- a/tests/drivers/dma/scatter_gather/testcase.yaml +++ b/tests/drivers/dma/scatter_gather/testcase.yaml @@ -21,6 +21,7 @@ tests: - adp_xc7k/ae350 - adp_xc7k/ae350/clic - bg29_rb4420a + - stm32mp257f_ev1/stm32mp257fxx/m33 filter: dt_alias_exists("dma0") integration_platforms: - intel_adsp/cavs25