From 77997cf50dc20739256cddba2e1b5e692f7223dd Mon Sep 17 00:00:00 2001 From: Sai Santhosh Malae Date: Mon, 21 Jul 2025 21:20:28 +0530 Subject: [PATCH 1/5] drivers: dma: siwx91x: GPDMA clock initialization for siwx91x Clock driver changes required for initializing the GPDMA clock for the siwx91x driver Signed-off-by: Sai Santhosh Malae --- drivers/clock_control/clock_control_silabs_siwx91x.c | 3 +++ include/zephyr/dt-bindings/clock/silabs/siwx91x-clock.h | 1 + 2 files changed, 4 insertions(+) diff --git a/drivers/clock_control/clock_control_silabs_siwx91x.c b/drivers/clock_control/clock_control_silabs_siwx91x.c index a09895bb358e2..7772f17b26c16 100644 --- a/drivers/clock_control/clock_control_silabs_siwx91x.c +++ b/drivers/clock_control/clock_control_silabs_siwx91x.c @@ -107,6 +107,9 @@ static int siwx91x_clock_on(const struct device *dev, clock_control_subsys_t sys case SIWX91X_ADC_CLK: RSI_ADC_PowerControl(ADC_POWER_ON); break; + case SIWX91X_CLK_GPDMA0: + RSI_CLK_PeripheralClkEnable(M4CLK, RPDMA_CLK, ENABLE_STATIC_CLK); + break; default: return -EINVAL; } diff --git a/include/zephyr/dt-bindings/clock/silabs/siwx91x-clock.h b/include/zephyr/dt-bindings/clock/silabs/siwx91x-clock.h index 1bd454b53f5e7..49f2188dae602 100644 --- a/include/zephyr/dt-bindings/clock/silabs/siwx91x-clock.h +++ b/include/zephyr/dt-bindings/clock/silabs/siwx91x-clock.h @@ -22,5 +22,6 @@ #define SIWX91X_CLK_ULP_I2S 15 #define SIWX91X_CLK_STATIC_ULP_I2S 16 #define SIWX91X_ADC_CLK 17 +#define SIWX91X_CLK_GPDMA0 18 #endif From 0e2259fc413840b607bbf5471ac9eb358453e3aa Mon Sep 17 00:00:00 2001 From: Sai Santhosh Malae Date: Mon, 21 Jul 2025 21:23:33 +0530 Subject: [PATCH 2/5] 'drivers: dma: siwx91x: Add siwx91x GPDMA driver Implement GPDMA driver for siwx91x device Signed-off-by: Sai Santhosh Malae --- drivers/dma/CMakeLists.txt | 1 + drivers/dma/Kconfig.siwx91x | 16 + drivers/dma/dma_silabs_siwx91x_gpdma.c | 538 ++++++++++++++++++ modules/hal_silabs/wiseconnect/CMakeLists.txt | 4 + 4 files changed, 559 insertions(+) create mode 100644 drivers/dma/dma_silabs_siwx91x_gpdma.c diff --git a/drivers/dma/CMakeLists.txt b/drivers/dma/CMakeLists.txt index 42d5c969a7e9a..6ef4bf84b5167 100644 --- a/drivers/dma/CMakeLists.txt +++ b/drivers/dma/CMakeLists.txt @@ -44,6 +44,7 @@ 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) zephyr_library_sources_ifdef(CONFIG_DMA_SILABS_SIWX91X dma_silabs_siwx91x.c) +zephyr_library_sources_ifdef(CONFIG_DMA_SILABS_SIWX91X_GPDMA dma_silabs_siwx91x_gpdma.c) zephyr_library_sources_ifdef(CONFIG_DMA_SMARTBOND dma_smartbond.c) zephyr_library_sources_ifdef(CONFIG_DMA_NXP_SOF_HOST_DMA dma_nxp_sof_host_dma.c) zephyr_library_sources_ifdef(CONFIG_DMA_EMUL dma_emul.c) diff --git a/drivers/dma/Kconfig.siwx91x b/drivers/dma/Kconfig.siwx91x index a13491aa9efb2..1762de105a374 100644 --- a/drivers/dma/Kconfig.siwx91x +++ b/drivers/dma/Kconfig.siwx91x @@ -9,6 +9,14 @@ config DMA_SILABS_SIWX91X help Enable the High Power(HP)/Ultra Low Power(ULP) DMA driver for the Silabs SiWx91x SoC series. +config DMA_SILABS_SIWX91X_GPDMA + bool "Silabs SiWx91x GPDMA driver" + default y + select SYS_MEM_BLOCKS + depends on DT_HAS_SILABS_GPDMA_ENABLED + help + Enable the GDMA driver for the Silabs SiWx91x SoC series. + if DMA_SILABS_SIWX91X config DMA_SILABS_SIWX91X_SG_BUFFER_COUNT @@ -16,3 +24,11 @@ config DMA_SILABS_SIWX91X_SG_BUFFER_COUNT default 30 endif + +if DMA_SILABS_SIWX91X_GPDMA + +config GPDMA_SILABS_SIWX91X_DESCRIPTOR_COUNT + int "The maximum GPDMA descriptor count" + default 32 + +endif diff --git a/drivers/dma/dma_silabs_siwx91x_gpdma.c b/drivers/dma/dma_silabs_siwx91x_gpdma.c new file mode 100644 index 0000000000000..dc9170b1d4c71 --- /dev/null +++ b/drivers/dma/dma_silabs_siwx91x_gpdma.c @@ -0,0 +1,538 @@ +/* + * Copyright (c) 2025 Silicon Laboratories Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include "rsi_gpdma.h" +#include "rsi_rom_gpdma.h" + +#define DT_DRV_COMPAT silabs_gpdma +#define GPDMA_DESC_MAX_TRANSFER_SIZE 4096 +#define GPDMA_MAX_CHANNEL_FIFO_SIZE 64 +#define GPDMA_MAX_PRIORITY 3 +#define GPDMA_MIN_PRIORITY 0 + +LOG_MODULE_REGISTER(si91x_gpdma, CONFIG_DMA_LOG_LEVEL); + +enum gpdma_xfer_dir { + SIWX91X_TRANSFER_MEM_TO_MEM = 0, + SIWX91X_TRANSFER_MEM_TO_PER = 1, + SIWX91X_TRANSFER_PER_TO_MEM = 2, + SIWX91X_TRANSFER_DIR_INVALID = 4, +}; + +enum gpdma_data_width { + SIWX91X_DATA_WIDTH_8 = 0, + SIWX91X_DATA_WIDTH_16 = 1, + SIWX91X_DATA_WIDTH_32 = 2, + SIWX91X_DATA_WIDTH_INVALID = 3, +}; + +struct siwx91x_gpdma_channel_info { + dma_callback_t cb; + void *cb_data; + RSI_GPDMA_DESC_T *desc; + enum gpdma_xfer_dir xfer_direction; +}; + +struct siwx91x_gpdma_config { + GPDMA_G_Type *reg; /* GPDMA base address */ + GPDMA_C_Type *channel_reg; /* GPDMA channel registers address */ + const struct device *clock_dev; + clock_control_subsys_t clock_subsys; + void (*irq_configure)(void); +}; + +struct siwx19x_gpdma_data { + struct dma_context dma_ctx; + GPDMA_DATACONTEXT_T hal_ctx; + struct sys_mem_blocks *desc_pool; + struct k_spinlock desc_pool_lock; + struct siwx91x_gpdma_channel_info *chan_info; + uint8_t reload_compatible; +}; + +static bool siwx91x_gpdma_is_priority_valid(uint32_t channel_priority) +{ + return (channel_priority >= GPDMA_MIN_PRIORITY && channel_priority <= GPDMA_MAX_PRIORITY); +} + +static enum gpdma_xfer_dir siwx91x_gpdma_xfer_dir(uint32_t dir) +{ + switch (dir) { + case MEMORY_TO_MEMORY: + return SIWX91X_TRANSFER_MEM_TO_MEM; + case MEMORY_TO_PERIPHERAL: + return SIWX91X_TRANSFER_MEM_TO_PER; + case PERIPHERAL_TO_MEMORY: + return SIWX91X_TRANSFER_PER_TO_MEM; + default: + return SIWX91X_TRANSFER_DIR_INVALID; + } +} + +static enum gpdma_data_width siwx91x_gpdma_data_size(uint32_t data_size) +{ + switch (data_size) { + case 1: + return SIWX91X_DATA_WIDTH_8; + case 2: + return SIWX91X_DATA_WIDTH_16; + case 4: + return SIWX91X_DATA_WIDTH_32; + default: + return SIWX91X_DATA_WIDTH_INVALID; + } +} + +static int siwx91x_gpdma_ahb_blen(uint8_t blen) +{ + if (blen == 1) { + return AHBBURST_SIZE_1; + } else if (blen <= 4) { + return AHBBURST_SIZE_4; + } else if (blen <= 8) { + return AHBBURST_SIZE_8; + } else if (blen <= 16) { + return AHBBURST_SIZE_16; + } else if (blen <= 20) { + return AHBBURST_SIZE_20; + } else if (blen <= 24) { + return AHBBURST_SIZE_24; + } else if (blen <= 28) { + return AHBBURST_SIZE_28; + } else if (blen <= 32) { + return AHBBURST_SIZE_32; + } else { + return -EINVAL; + } +} + +static void siwx91x_gpdma_free_desc(sys_mem_blocks_t *mem_block, RSI_GPDMA_DESC_T *block) +{ + RSI_GPDMA_DESC_T *cur_desc = block; + uint32_t *next_desc = NULL; + + do { + next_desc = cur_desc->pNextLink; + sys_mem_blocks_free(mem_block, 1, (void **)&cur_desc); + cur_desc = (RSI_GPDMA_DESC_T *)next_desc; + } while (next_desc != NULL); +} + +static int siwx91x_gpdma_desc_config(struct siwx19x_gpdma_data *data, + const struct dma_config *config, + const RSI_GPDMA_DESC_T *xfer_cfg, uint32_t channel) +{ + uint16_t max_xfer_size = GPDMA_DESC_MAX_TRANSFER_SIZE - config->source_data_size; + const struct dma_block_config *block_addr = config->head_block; + RSI_GPDMA_DESC_T *cur_desc = NULL; + RSI_GPDMA_DESC_T *prev_desc = NULL; + k_spinlock_key_t key; + int ret; + + for (int i = 0; i < config->block_count; i++) { + if (block_addr->block_size > max_xfer_size) { + LOG_ERR("Maximum xfer size should be <= %d\n", max_xfer_size); + goto free_desc; + } + + key = k_spin_lock(&data->desc_pool_lock); + ret = sys_mem_blocks_alloc(data->desc_pool, 1, (void **)&cur_desc); + k_spin_unlock(&data->desc_pool_lock, key); + if (ret) { + goto free_desc; + } + + if (prev_desc == NULL) { + data->chan_info[channel].desc = cur_desc; + } + + memset(cur_desc, 0, 32); + + ret = RSI_GPDMA_BuildDescriptors(&data->hal_ctx, (RSI_GPDMA_DESC_T *)xfer_cfg, + cur_desc, prev_desc); + if (ret) { + goto free_desc; + } + + cur_desc->src = (void *)block_addr->source_address; + cur_desc->dest = (void *)block_addr->dest_address; + cur_desc->chnlCtrlConfig.transSize = block_addr->block_size; + + if (block_addr->dest_addr_adj == DMA_ADDR_ADJ_NO_CHANGE) { + cur_desc->chnlCtrlConfig.dstFifoMode = 1; + } + + if (block_addr->source_addr_adj == DMA_ADDR_ADJ_NO_CHANGE) { + cur_desc->chnlCtrlConfig.srcFifoMode = 1; + } + + prev_desc = cur_desc; + block_addr = block_addr->next_block; + } + + if (block_addr != NULL) { + /* next_block address for last block must be null */ + goto free_desc; + } + + ret = RSI_GPDMA_SetupChannelTransfer(&data->hal_ctx, channel, + data->chan_info[channel].desc); + if (ret) { + goto free_desc; + } + + return 0; + +free_desc: + key = k_spin_lock(&data->desc_pool_lock); + siwx91x_gpdma_free_desc(data->desc_pool, data->chan_info[channel].desc); + k_spin_unlock(&data->desc_pool_lock, key); + return -EINVAL; +} + +static int siwx91x_gpdma_xfer_configure(const struct device *dev, const struct dma_config *config, + uint32_t channel) +{ + struct siwx19x_gpdma_data *data = dev->data; + RSI_GPDMA_DESC_T xfer_cfg = {}; + int ret; + + xfer_cfg.chnlCtrlConfig.transType = siwx91x_gpdma_xfer_dir(config->channel_direction); + if (xfer_cfg.chnlCtrlConfig.transType == SIWX91X_TRANSFER_DIR_INVALID) { + return -EINVAL; + } + + data->chan_info[channel].xfer_direction = config->channel_direction; + + if (config->dest_data_size != config->source_data_size) { + LOG_ERR("Data size mismatch\n"); + return -EINVAL; + } + + if (config->dest_burst_length != config->source_burst_length) { + LOG_ERR("Burst length mismatch\n"); + return -EINVAL; + } + + if (config->source_data_size * config->source_burst_length >= GPDMA_MAX_CHANNEL_FIFO_SIZE) { + LOG_ERR("FIFO overflow detected: data_size × burst_length = %d >= %d (maximum " + "allowed)\n", + config->source_data_size * config->source_burst_length, + GPDMA_MAX_CHANNEL_FIFO_SIZE); + return -EINVAL; + } + + xfer_cfg.chnlCtrlConfig.srcDataWidth = siwx91x_gpdma_data_size(config->source_data_size); + if (xfer_cfg.chnlCtrlConfig.destDataWidth == SIWX91X_DATA_WIDTH_INVALID) { + return -EINVAL; + } + + xfer_cfg.chnlCtrlConfig.destDataWidth = xfer_cfg.chnlCtrlConfig.srcDataWidth; + + if (config->block_count == 1) { + xfer_cfg.chnlCtrlConfig.linkListOn = 0; + data->reload_compatible = 1; + } else { + xfer_cfg.chnlCtrlConfig.linkListOn = 1; + data->reload_compatible = 0; + } + xfer_cfg.chnlCtrlConfig.linkInterrupt = config->complete_callback_en; + + if (xfer_cfg.chnlCtrlConfig.transType == SIWX91X_TRANSFER_MEM_TO_PER) { + xfer_cfg.miscChnlCtrlConfig.destChannelId = config->dma_slot; + } else if (xfer_cfg.chnlCtrlConfig.transType == SIWX91X_TRANSFER_PER_TO_MEM) { + xfer_cfg.miscChnlCtrlConfig.srcChannelId = config->dma_slot; + } + + xfer_cfg.miscChnlCtrlConfig.ahbBurstSize = + siwx91x_gpdma_ahb_blen(config->source_burst_length); + xfer_cfg.miscChnlCtrlConfig.destDataBurst = config->dest_burst_length; + xfer_cfg.miscChnlCtrlConfig.srcDataBurst = config->source_burst_length; + + ret = siwx91x_gpdma_desc_config(data, config, &xfer_cfg, channel); + if (ret) { + return ret; + } + + return 0; +} + +static int siwx91x_gpdma_configure(const struct device *dev, uint32_t channel, + struct dma_config *config) +{ + const struct siwx91x_gpdma_config *cfg = dev->config; + struct siwx19x_gpdma_data *data = dev->data; + RSI_GPDMA_CHA_CFG_T gpdma_channel_cfg = { + .descFetchDoneIntr = config->complete_callback_en, + .hrespErr = 1, + .gpdmacErr = 1, + .xferDoneIntr = 1, + .dmaCh = channel, + }; + int ret; + + if (channel >= data->dma_ctx.dma_channels) { + return -EINVAL; + } + + if (config->cyclic) { + return -ENOTSUP; + } + + if (sys_test_bit((mem_addr_t)&cfg->reg->GLOBAL.DMA_CHNL_ENABLE_REG, channel)) { + /* Transfer in progress */ + return -EIO; + } + + if (!siwx91x_gpdma_is_priority_valid(config->channel_priority)) { + LOG_ERR("Invalid priority values: (valid range: 0-3)\n"); + return -EINVAL; + } + gpdma_channel_cfg.channelPrio = config->channel_priority; + + if (RSI_GPDMA_SetupChannel(&data->hal_ctx, &gpdma_channel_cfg)) { + return -EIO; + } + + ret = siwx91x_gpdma_xfer_configure(dev, config, channel); + if (ret) { + return -EINVAL; + } + + cfg->channel_reg->CHANNEL_CONFIG[channel].FIFO_CONFIG_REGS = 0; + /* Allocate 8 rows of FIFO for each channel (64 bytes) */ + cfg->channel_reg->CHANNEL_CONFIG[channel].FIFO_CONFIG_REGS_b.FIFO_SIZE = 7; + cfg->channel_reg->CHANNEL_CONFIG[channel].FIFO_CONFIG_REGS_b.FIFO_STRT_ADDR = (channel * 8); + + data->chan_info[channel].cb = config->dma_callback; + data->chan_info[channel].cb_data = config->user_data; + + return 0; +} + +static int siwx91x_gpdma_reload(const struct device *dev, uint32_t channel, uint32_t src, + uint32_t dst, size_t size) +{ + const struct siwx91x_gpdma_config *cfg = dev->config; + struct siwx19x_gpdma_data *data = dev->data; + int data_size = siwx91x_gpdma_data_size( + cfg->channel_reg->CHANNEL_CONFIG[channel].CHANNEL_CTRL_REG_CHNL_b.SRC_DATA_WIDTH); + + if (channel >= data->dma_ctx.dma_channels) { + return -EINVAL; + } + + if (!data->reload_compatible) { + return -ENOTSUP; + } + + if (sys_test_bit((mem_addr_t)&cfg->reg->GLOBAL.DMA_CHNL_ENABLE_REG, channel)) { + /* Transfer in progress */ + return -EIO; + } + + if (data_size < 0) { + return -EINVAL; + } + + if (size > (GPDMA_DESC_MAX_TRANSFER_SIZE - data_size)) { + LOG_ERR("Maximum xfer size should be <= %d\n", + GPDMA_DESC_MAX_TRANSFER_SIZE - data_size); + return -EINVAL; + } + + cfg->channel_reg->CHANNEL_CONFIG[channel].SRC_ADDR_REG_CHNL = src; + cfg->channel_reg->CHANNEL_CONFIG[channel].DEST_ADDR_REG_CHNL = dst; + cfg->channel_reg->CHANNEL_CONFIG[channel].CHANNEL_CTRL_REG_CHNL_b.DMA_BLK_SIZE = size; + + return 0; +} + +static int siwx91x_gpdma_start(const struct device *dev, uint32_t channel) +{ + struct siwx19x_gpdma_data *data = dev->data; + + if (channel >= data->dma_ctx.dma_channels) { + return -EINVAL; + } + + if (RSI_GPDMA_DMAChannelTrigger(&data->hal_ctx, channel)) { + return -EINVAL; + } + + return 0; +} + +static int siwx91x_gpdma_stop(const struct device *dev, uint32_t channel) +{ + struct siwx19x_gpdma_data *data = dev->data; + k_spinlock_key_t key; + + if (channel >= data->dma_ctx.dma_channels) { + return -EINVAL; + } + + if (RSI_GPDMA_AbortChannel(&data->hal_ctx, channel)) { + return -EINVAL; + } + + key = k_spin_lock(&data->desc_pool_lock); + siwx91x_gpdma_free_desc(data->desc_pool, data->chan_info[channel].desc); + k_spin_unlock(&data->desc_pool_lock, key); + + return 0; +} + +static int siwx91x_gpdma_get_status(const struct device *dev, uint32_t channel, + struct dma_status *stat) +{ + const struct siwx91x_gpdma_config *cfg = dev->config; + struct siwx19x_gpdma_data *data = dev->data; + + if (channel >= data->dma_ctx.dma_channels) { + return -EINVAL; + } + + if (!atomic_test_bit(data->dma_ctx.atomic, channel)) { + return -EINVAL; + } + + stat->busy = sys_test_bit((mem_addr_t)&cfg->reg->GLOBAL.DMA_CHNL_ENABLE_REG, channel); + stat->dir = data->chan_info[channel].xfer_direction; + + return 0; +} + +bool siwx91x_gpdma_chan_filter(const struct device *dev, int channel, void *filter_param) +{ + ARG_UNUSED(dev); + + if (!filter_param) { + return false; + } + + if (*(int *)filter_param == channel) { + return true; + } else { + return false; + } +} + +static int siwx91x_gpdma_init(const struct device *dev) +{ + const struct siwx91x_gpdma_config *cfg = dev->config; + struct siwx19x_gpdma_data *data = dev->data; + RSI_GPDMA_INIT_T gpdma_init = { + .pUserData = NULL, + .baseG = (uint32_t)cfg->reg, + .baseC = (uint32_t)cfg->channel_reg, + .sramBase = (uint32_t)data->desc_pool->buffer, + }; + RSI_GPDMA_HANDLE_T gpdma_handle; + int ret; + + ret = clock_control_on(cfg->clock_dev, cfg->clock_subsys); + if (ret) { + return ret; + } + + gpdma_handle = RSI_GPDMA_Init(&data->hal_ctx, &gpdma_init); + if (gpdma_handle != &data->hal_ctx) { + return -EIO; + } + + cfg->irq_configure(); + + return 0; +} + +static void siwx91x_gpdma_isr(const struct device *dev) +{ + const struct siwx91x_gpdma_config *cfg = dev->config; + struct siwx19x_gpdma_data *data = dev->data; + uint32_t channel = find_lsb_set(cfg->reg->GLOBAL.INTERRUPT_REG) - 1; + uint32_t channel_int_status = cfg->reg->GLOBAL.INTERRUPT_STAT_REG; + uint32_t channel_shift = channel * 4; + uint32_t abort_mask = (BIT(0) | BIT(3)) << channel_shift; + uint32_t desc_fetch_mask = BIT(1) << channel_shift; + uint32_t done_mask = BIT(2) << channel_shift; + k_spinlock_key_t key; + + if (channel_int_status & abort_mask) { + RSI_GPDMA_AbortChannel(&data->hal_ctx, channel); + cfg->reg->GLOBAL.INTERRUPT_STAT_REG = abort_mask; + } + + if (channel_int_status & desc_fetch_mask) { + cfg->reg->GLOBAL.INTERRUPT_STAT_REG = desc_fetch_mask; + if (data->chan_info[channel].cb) { + data->chan_info[channel].cb(dev, data->chan_info[channel].cb_data, channel, + 0); + } + } + + if (channel_int_status & done_mask) { + key = k_spin_lock(&data->desc_pool_lock); + siwx91x_gpdma_free_desc(data->desc_pool, data->chan_info[channel].desc); + k_spin_unlock(&data->desc_pool_lock, key); + data->chan_info[channel].desc = NULL; + cfg->reg->GLOBAL.INTERRUPT_STAT_REG = done_mask; + if (data->chan_info[channel].cb) { + data->chan_info[channel].cb(dev, data->chan_info[channel].cb_data, channel, + 0); + } + } +} + +static DEVICE_API(dma, siwx91x_gpdma_api) = { + .config = siwx91x_gpdma_configure, + .reload = siwx91x_gpdma_reload, + .start = siwx91x_gpdma_start, + .stop = siwx91x_gpdma_stop, + .get_status = siwx91x_gpdma_get_status, + .chan_filter = siwx91x_gpdma_chan_filter, +}; + +#define SIWX91X_GPDMA_INIT(inst) \ + static ATOMIC_DEFINE(siwx91x_gdma_atomic_##inst, \ + DT_INST_PROP(inst, silabs_dma_channel_count)); \ + SYS_MEM_BLOCKS_DEFINE_STATIC(siwx91x_gpdma_desc_pool_##inst, 32, \ + CONFIG_GPDMA_SILABS_SIWX91X_DESCRIPTOR_COUNT, 32); \ + static struct siwx91x_gpdma_channel_info \ + siwx91x_gpdma_chan_info_##inst[DT_INST_PROP(inst, silabs_dma_channel_count)]; \ + static struct siwx19x_gpdma_data siwx91x_gpdma_data_##inst = { \ + .dma_ctx.magic = DMA_MAGIC, \ + .dma_ctx.dma_channels = DT_INST_PROP(inst, silabs_dma_channel_count), \ + .dma_ctx.atomic = siwx91x_gdma_atomic_##inst, \ + .desc_pool = &siwx91x_gpdma_desc_pool_##inst, \ + .chan_info = siwx91x_gpdma_chan_info_##inst, \ + }; \ + static void siwx91x_gpdma_irq_configure_##inst(void) \ + { \ + IRQ_CONNECT(DT_INST_IRQ(inst, irq), DT_INST_IRQ(inst, priority), \ + siwx91x_gpdma_isr, DEVICE_DT_INST_GET(inst), 0); \ + irq_enable(DT_INST_IRQ(inst, irq)); \ + } \ + \ + static const struct siwx91x_gpdma_config siwx91x_gpdma_cfg_##inst = { \ + .reg = (GPDMA_G_Type *)DT_INST_REG_ADDR(inst), \ + .channel_reg = (GPDMA_C_Type *)DT_INST_PROP(inst, silabs_channel_reg_base), \ + .clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(inst)), \ + .clock_subsys = (clock_control_subsys_t)DT_INST_PHA(inst, clocks, clkid), \ + .irq_configure = siwx91x_gpdma_irq_configure_##inst, \ + }; \ + DEVICE_DT_INST_DEFINE(inst, siwx91x_gpdma_init, NULL, &siwx91x_gpdma_data_##inst, \ + &siwx91x_gpdma_cfg_##inst, POST_KERNEL, CONFIG_DMA_INIT_PRIORITY, \ + &siwx91x_gpdma_api); + +DT_INST_FOREACH_STATUS_OKAY(SIWX91X_GPDMA_INIT) diff --git a/modules/hal_silabs/wiseconnect/CMakeLists.txt b/modules/hal_silabs/wiseconnect/CMakeLists.txt index d9a42795b4d5f..3bd43ecc26d7f 100644 --- a/modules/hal_silabs/wiseconnect/CMakeLists.txt +++ b/modules/hal_silabs/wiseconnect/CMakeLists.txt @@ -94,6 +94,10 @@ zephyr_compile_definitions_ifdef(CONFIG_ADC_SILABS_SIWX91X ADC_CONTEXT_USES_KERNEL_TIMER ) +zephyr_compile_definitions_ifdef(CONFIG_DMA_SILABS_SIWX91X_GPDMA + GPDMA_ROMDRIVER_PRESENT +) + zephyr_library_sources_ifdef(CONFIG_DMA_SILABS_SIWX91X ${WISECONNECT_DIR}/components/device/silabs/si91x/mcu/drivers/rom_driver/src/rsi_rom_table_si91x.c ) From 06b4b3145924a07d16799d8571cdafc0d0c7d7e8 Mon Sep 17 00:00:00 2001 From: Sai Santhosh Malae Date: Mon, 21 Jul 2025 21:21:50 +0530 Subject: [PATCH 3/5] drivers: dma: siwx91x: DTS changes for siwx91x GPDMA driver 1. Create a YAML file for gpdma node 2. Add GPDMA node in the siwx917.dtsi Signed-off-by: Sai Santhosh Malae --- dts/arm/silabs/siwg917.dtsi | 14 ++++++ dts/bindings/dma/silabs,gpdma.yaml | 72 ++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+) create mode 100644 dts/bindings/dma/silabs,gpdma.yaml diff --git a/dts/arm/silabs/siwg917.dtsi b/dts/arm/silabs/siwg917.dtsi index ceb79d35152cc..46a4adf5dcfed 100644 --- a/dts/arm/silabs/siwg917.dtsi +++ b/dts/arm/silabs/siwg917.dtsi @@ -410,6 +410,20 @@ #io-channel-cells = <1>; status = "disabled"; }; + + gpdma0: gpdma@21080000 { + compatible = "silabs,gpdma"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x21080000 0x1720>; + interrupts = <31 0>; + interrupt-names = "gpdma0"; + clocks = <&clock0 SIWX91X_CLK_GPDMA0>; + silabs,channel-reg-base = <0x21081004>; + silabs,dma-channel-count = <8>; + #dma-cells = <2>; + status = "disabled"; + }; }; }; diff --git a/dts/bindings/dma/silabs,gpdma.yaml b/dts/bindings/dma/silabs,gpdma.yaml new file mode 100644 index 0000000000000..ffedcf1d97fe5 --- /dev/null +++ b/dts/bindings/dma/silabs,gpdma.yaml @@ -0,0 +1,72 @@ +description: | + Silicon Labs SiWx91x General Purpose DMA (GPDMA) Controller + + The SiWx91x GPDMA controller provides high-performance DMA transfers for + memory-to-memory, memory-to-peripheral, and peripheral-to-memory operations. + It supports up to 8 channels. + + Usage in Device Tree Overlays: + + To enable GPDMA for a peripheral (e.g., SPI), add the following to your overlay: + + ```dts + &spi0 { + status = "okay"; + cs-gpios = <&gpiob 12 GPIO_ACTIVE_LOW>; + pinctrl-0 = <&spi0_default>; + pinctrl-names = "default"; + + dmas = <&gpdma0 0 11>, <&gpdma0 1 10>; + dma-names = "tx", "rx"; + + slow@0 { + compatible = "test-spi-loopback-slow"; + reg = <0>; + spi-max-frequency = <500000>; + }; + fast@1 { + compatible = "test-spi-loopback-fast"; + reg = <1>; + spi-max-frequency = <10000000>; + }; + }; + + &gpdma0 { + status = "okay"; + }; + ``` + + DMA Configuration: + - Channel 0: Used for TX (transmit) operations + - Channel 1: Used for RX (receive) operations + - Slot 11: Peripheral slot for SPI TX + - Slot 10: Peripheral slot for SPI RX + + The GPDMA controller automatically handles descriptor management and + interrupt generation for transfer completion and error conditions. + +compatible: "silabs,gpdma" + +include: dma-controller.yaml + +properties: + reg: + required: true + + silabs,channel-reg-base: + type: int + description: | + Base address for channel specific registers. + + silabs,dma-channel-count: + type: int + description: | + Base address for channel specific registers. + + "#dma-cells": + const: 2 + +# Parameter syntax +dma-cells: + - channel + - slot From 7a977ba551419e2dcf7c52bdf1f1716cbb6dabd5 Mon Sep 17 00:00:00 2001 From: Sai Santhosh Malae Date: Mon, 21 Jul 2025 21:24:50 +0530 Subject: [PATCH 4/5] drivers: dma: siwx91x: dma_chan_blen test app support Add siwx917_rb4338a board overlay and config files Signed-off-by: Sai Santhosh Malae --- .../chan_blen_transfer/boards/siwx917_rb4338a.conf | 2 ++ .../chan_blen_transfer/boards/siwx917_rb4338a.overlay | 11 +++++++++++ 2 files changed, 13 insertions(+) create mode 100644 tests/drivers/dma/chan_blen_transfer/boards/siwx917_rb4338a.conf create mode 100644 tests/drivers/dma/chan_blen_transfer/boards/siwx917_rb4338a.overlay diff --git a/tests/drivers/dma/chan_blen_transfer/boards/siwx917_rb4338a.conf b/tests/drivers/dma/chan_blen_transfer/boards/siwx917_rb4338a.conf new file mode 100644 index 0000000000000..9c5a9e9034b06 --- /dev/null +++ b/tests/drivers/dma/chan_blen_transfer/boards/siwx917_rb4338a.conf @@ -0,0 +1,2 @@ +CONFIG_DMA_TRANSFER_CHANNEL_NR_0=0 +CONFIG_DMA_TRANSFER_CHANNEL_NR_1=7 diff --git a/tests/drivers/dma/chan_blen_transfer/boards/siwx917_rb4338a.overlay b/tests/drivers/dma/chan_blen_transfer/boards/siwx917_rb4338a.overlay new file mode 100644 index 0000000000000..51af366267987 --- /dev/null +++ b/tests/drivers/dma/chan_blen_transfer/boards/siwx917_rb4338a.overlay @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2025 Silicon Laboratories, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&gpdma0 { + status = "okay"; +}; + +tst_dma0: &gpdma0 { }; From 6619bef14f9804455c133b3a56c827ef083a6c40 Mon Sep 17 00:00:00 2001 From: Sai Santhosh Malae Date: Wed, 13 Aug 2025 21:34:37 +0530 Subject: [PATCH 5/5] drivers: dma: siwx91x: Sort CMakeLists.txt items sort library sources and compile time definitions in wiseconnect CMakeLists.txt Signed-off-by: Sai Santhosh Malae --- modules/hal_silabs/wiseconnect/CMakeLists.txt | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/modules/hal_silabs/wiseconnect/CMakeLists.txt b/modules/hal_silabs/wiseconnect/CMakeLists.txt index 3bd43ecc26d7f..e034a67ae582c 100644 --- a/modules/hal_silabs/wiseconnect/CMakeLists.txt +++ b/modules/hal_silabs/wiseconnect/CMakeLists.txt @@ -77,29 +77,29 @@ zephyr_library_sources( ${WISECONNECT_DIR}/components/device/silabs/si91x/mcu/core/chip/src/iPMU_prog/iPMU_dotc/rsi_system_config_917.c ) -zephyr_library_sources_ifdef(CONFIG_ENTROPY_SILABS_SIWX91X - ${WISECONNECT_DIR}/components/device/silabs/si91x/mcu/drivers/peripheral_drivers/src/rsi_rng.c -) - zephyr_library_sources_ifdef(CONFIG_ADC_SILABS_SIWX91X ${WISECONNECT_DIR}/components/device/silabs/si91x/mcu/drivers/peripheral_drivers/src/aux_reference_volt_config.c ${WISECONNECT_DIR}/components/device/silabs/si91x/mcu/drivers/systemlevel/src/rsi_bod.c ) -zephyr_compile_definitions_ifdef(CONFIG_DMA_SILABS_SIWX91X - UDMA_ROMDRIVER_PRESENT -) - zephyr_compile_definitions_ifdef(CONFIG_ADC_SILABS_SIWX91X ADC_CONTEXT_USES_KERNEL_TIMER ) +zephyr_library_sources_ifdef(CONFIG_DMA_SILABS_SIWX91X + ${WISECONNECT_DIR}/components/device/silabs/si91x/mcu/drivers/rom_driver/src/rsi_rom_table_si91x.c +) + +zephyr_compile_definitions_ifdef(CONFIG_DMA_SILABS_SIWX91X + UDMA_ROMDRIVER_PRESENT +) + zephyr_compile_definitions_ifdef(CONFIG_DMA_SILABS_SIWX91X_GPDMA GPDMA_ROMDRIVER_PRESENT ) -zephyr_library_sources_ifdef(CONFIG_DMA_SILABS_SIWX91X - ${WISECONNECT_DIR}/components/device/silabs/si91x/mcu/drivers/rom_driver/src/rsi_rom_table_si91x.c +zephyr_library_sources_ifdef(CONFIG_ENTROPY_SILABS_SIWX91X + ${WISECONNECT_DIR}/components/device/silabs/si91x/mcu/drivers/peripheral_drivers/src/rsi_rng.c ) zephyr_library_sources_ifdef(CONFIG_MEMC_SILABS_SIWX91X_QSPI