diff --git a/drivers/dma/CMakeLists.txt b/drivers/dma/CMakeLists.txt index 43f7a87a247..6baf9aed587 100644 --- a/drivers/dma/CMakeLists.txt +++ b/drivers/dma/CMakeLists.txt @@ -33,6 +33,7 @@ zephyr_library_sources_ifdef(CONFIG_DMA_ESP32 dma_esp32_gdma.c) zephyr_library_sources_ifdef(CONFIG_DMA_MCHP_XEC dma_mchp_xec.c) zephyr_library_sources_ifdef(CONFIG_DMA_XMC4XXX dma_xmc4xxx.c) zephyr_library_sources_ifdef(CONFIG_DMA_RPI_PICO dma_rpi_pico.c) +zephyr_library_sources_ifdef(CONFIG_DMA_RENESAS_RZ dma_renesas_rz.c) zephyr_library_sources_ifdef(CONFIG_MCUX_PXP dma_mcux_pxp.c) zephyr_library_sources_ifdef(CONFIG_DMA_MAX32 dma_max32.c) zephyr_library_sources_ifdef(CONFIG_DMA_MCUX_SMARTDMA dma_mcux_smartdma.c) diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index f89364d459f..f43fe237b5e 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -58,6 +58,8 @@ source "drivers/dma/Kconfig.xmc4xxx" source "drivers/dma/Kconfig.rpi_pico" +source "drivers/dma/Kconfig.renesas_rz" + source "drivers/dma/Kconfig.ifx_cat1" source "drivers/dma/Kconfig.intel_lpss" diff --git a/drivers/dma/Kconfig.renesas_rz b/drivers/dma/Kconfig.renesas_rz new file mode 100644 index 00000000000..fd40f348ace --- /dev/null +++ b/drivers/dma/Kconfig.renesas_rz @@ -0,0 +1,10 @@ +# Copyright (c) 2024 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +config DMA_RENESAS_RZ + bool "Renesas RZ DMAC" + default y + depends on DT_HAS_RENESAS_RZ_DMA_ENABLED + select USE_RZ_FSP_DMA + help + Enable Renesas RZ DMA Driver. diff --git a/drivers/dma/dma_renesas_rz.c b/drivers/dma/dma_renesas_rz.c new file mode 100644 index 00000000000..258561ae95e --- /dev/null +++ b/drivers/dma/dma_renesas_rz.c @@ -0,0 +1,639 @@ +/* + * Copyright (c) 2024 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ +#define DT_DRV_COMPAT renesas_rz_dma + +#include +#include "r_dmac_b.h" +#include +#include "dma_renesas_rz.h" +LOG_MODULE_REGISTER(renesas_rz_dma); + +/* FSP DMAC handler should be called within DMA ISR */ +void dmac_b_int_isr(void); +void dmac_b_err_isr(void); + +struct dmac_cb_ctx { + const struct device *dmac_dev; + uint32_t channel; +}; + +struct dma_channel_data { + transfer_ctrl_t *fsp_ctrl; + transfer_cfg_t fsp_cfg; + + /* INTID associated with the channel */ + int irq; + int irq_ipl; + + /* DMA call back */ + dma_callback_t user_cb; + void *user_data; + struct dmac_cb_ctx cb_ctx; + + bool is_configured; + uint32_t direction; +}; + +struct dma_renesas_rz_config { + uint8_t unit; + uint8_t num_channels; + void (*irq_configure)(void); + const transfer_api_t *fsp_api; +}; + +struct dma_renesas_rz_data { + /* Dma context should be the first in data structure */ + struct dma_context ctx; + struct dma_channel_data *channels; +}; + +static void dmac_rz_cb_handler(dmac_b_callback_args_t *args) +{ + struct dmac_cb_ctx *cb_ctx = (struct dmac_cb_ctx *)args->p_context; + uint32_t channel = cb_ctx->channel; + const struct device *dev = cb_ctx->dmac_dev; + struct dma_renesas_rz_data *data = dev->data; + dma_callback_t user_cb = data->channels[channel].user_cb; + void *user_data = data->channels[channel].user_data; + + if (user_cb) { + user_cb(dev, user_data, channel, args->event); + } +} + +static int dma_channel_common_checks(const struct device *dev, uint32_t channel) +{ + const struct dma_renesas_rz_config *config = dev->config; + struct dma_renesas_rz_data *data = dev->data; + + if (channel >= config->num_channels) { + LOG_ERR("%d: Invalid DMA channel %d.", __LINE__, channel); + return -EINVAL; + } + + if (!data->channels[channel].is_configured) { + LOG_ERR("%d: DMA channel %d should first be configured.", __LINE__, channel); + return -EINVAL; + } + + return 0; +} + +static inline int dma_channel_config_check_parameters(const struct device *dev, + struct dma_config *cfg) +{ + if ((cfg == NULL) || (cfg->head_block == NULL)) { + LOG_ERR("%d: Missing configuration structure.", __LINE__); + return -EFAULT; + } + + if (1 < cfg->block_count) { + LOG_ERR("%d: Link Mode is not supported, but only support 1 block per transfer", + __LINE__); + return -ENOTSUP; + } + + if (cfg->source_chaining_en || cfg->dest_chaining_en) { + LOG_ERR("%d:Channel Chainning is not supported.", __LINE__); + return -ENOTSUP; + } + + if (cfg->head_block->dest_scatter_count || cfg->head_block->source_gather_count || + cfg->head_block->source_gather_interval || cfg->head_block->dest_scatter_interval) { + LOG_ERR("%d: Scater and gather are not supported.", __LINE__); + return -ENOTSUP; + } + + return 0; +} + +static int dma_channel_set_size(uint32_t size) +{ + int transfer_size; + + switch (size) { + case 1: + transfer_size = TRANSFER_SIZE_1_BYTE; + break; + case 2: + transfer_size = TRANSFER_SIZE_2_BYTE; + break; + case 4: + transfer_size = TRANSFER_SIZE_4_BYTE; + break; + case 8: + transfer_size = TRANSFER_SIZE_8_BYTE; + break; + case 32: + transfer_size = TRANSFER_SIZE_32_BYTE; + break; + case 64: + transfer_size = TRANSFER_SIZE_64_BYTE; + break; + case 128: + transfer_size = TRANSFER_SIZE_128_BYTE; + break; + default: + LOG_ERR("%d: Unsupported data width.", __LINE__); + return -ENOTSUP; + } + + return transfer_size; +} + +static inline int dma_channel_config_save_parameters(const struct device *dev, uint32_t channel, + struct dma_config *cfg) +{ + const struct dma_renesas_rz_config *config = dev->config; + struct dma_renesas_rz_data *data = dev->data; + transfer_info_t *p_info = data->channels[channel].fsp_cfg.p_info; + dmac_b_extended_cfg_t *p_extend = + (dmac_b_extended_cfg_t *)data->channels[channel].fsp_cfg.p_extend; + + memset(p_info, 0, sizeof(*p_info)); + memset(p_extend, 0, sizeof(*p_extend)); + + /* Save transfer properties required by FSP */ + switch (cfg->head_block->dest_addr_adj) { + case DMA_ADDR_ADJ_NO_CHANGE: + p_info->dest_addr_mode = TRANSFER_ADDR_MODE_FIXED; + break; + case DMA_ADDR_ADJ_INCREMENT: + p_info->dest_addr_mode = TRANSFER_ADDR_MODE_INCREMENTED; + break; + default: + LOG_ERR("%d, Unsupported destination address adjustemnt.", __LINE__); + return -ENOTSUP; + } + + switch (cfg->head_block->source_addr_adj) { + case DMA_ADDR_ADJ_NO_CHANGE: + p_info->src_addr_mode = TRANSFER_ADDR_MODE_FIXED; + break; + case DMA_ADDR_ADJ_INCREMENT: + p_info->src_addr_mode = TRANSFER_ADDR_MODE_INCREMENTED; + break; + default: + LOG_ERR("%d, Unsupported source address adjustemnt.", __LINE__); + return -ENOTSUP; + } + + /* Convert data size following FSP convention */ + p_info->src_size = dma_channel_set_size(cfg->source_data_size); + p_info->dest_size = dma_channel_set_size(cfg->dest_data_size); + + /* Save transfer properties required by FSP */ + p_info->p_src = (void const *volatile)cfg->head_block->source_address; + p_info->p_dest = (void *volatile)cfg->head_block->dest_address; + p_info->length = cfg->head_block->block_size; + + /* + * Properties of next 1 registers are assigned default value following FSP because transfer + * continuous is not supported. + */ + p_info->p_next1_src = NULL; + p_info->p_next1_dest = NULL; + p_info->next1_length = 1; + p_extend->continuous_setting = DMAC_B_CONTINUOUS_SETTING_TRANSFER_ONCE; + + /* Save DMAC properties required by FSP */ + p_extend->unit = config->unit; + p_extend->channel = channel; + + /* Save INTID and priority */ + p_extend->dmac_int_irq = data->channels[channel].irq; + p_extend->dmac_int_ipl = data->channels[channel].irq_ipl; + + /* Save callback and data and use the generic handler. */ + data->channels[channel].user_cb = cfg->dma_callback; + data->channels[channel].user_data = cfg->user_data; + data->channels[channel].cb_ctx.dmac_dev = dev; + data->channels[channel].cb_ctx.channel = channel; + p_extend->p_callback = dmac_rz_cb_handler; + p_extend->p_context = (void *)&data->channels[channel].cb_ctx; + + /* Save default value following FSP version */ + p_extend->ack_mode = DMAC_B_ACK_MODE_MASK_DACK_OUTPUT; + p_extend->external_detection_mode = DMAC_B_EXTERNAL_DETECTION_NO_DETECTION; + p_extend->internal_detection_mode = DMAC_B_INTERNAL_DETECTION_NO_DETECTION; + + /* Save properties with respect to a specific case */ + switch (cfg->channel_direction) { + case MEMORY_TO_MEMORY: + p_info->mode = TRANSFER_MODE_BLOCK; + p_extend->activation_request_source_select = + DMAC_B_REQUEST_DIRECTION_DESTINATION_MODULE; + p_extend->activation_source = DMAC_TRIGGER_EVENT_SOFTWARE_TRIGGER; + break; + case PERIPHERAL_TO_MEMORY: + p_info->mode = TRANSFER_MODE_NORMAL; + p_extend->activation_request_source_select = + DMAC_B_REQUEST_DIRECTION_DESTINATION_MODULE; + p_extend->activation_source = cfg->dma_slot; + break; + case MEMORY_TO_PERIPHERAL: + p_info->mode = TRANSFER_MODE_NORMAL; + p_extend->activation_request_source_select = DMAC_B_REQUEST_DIRECTION_SOURCE_MODULE; + p_extend->activation_source = cfg->dma_slot; + break; + default: + LOG_ERR("%d: Unsupported direction mode.", __LINE__); + return -ENOTSUP; + } + + data->channels[channel].direction = cfg->channel_direction; + + /* + * Only support two priority modes, 0 is the highest priority with respect to FIXED + * Priority, Round Robin otherwise. + */ + if (cfg->channel_priority == 0) { + p_extend->channel_scheduling = DMAC_B_CHANNEL_SCHEDULING_FIXED; + } else { + p_extend->channel_scheduling = DMAC_B_CHANNEL_SCHEDULING_ROUND_ROBIN; + } + + if (1 < cfg->block_count) { + LOG_ERR("%d: Link Mode is not supported.", __LINE__); + } else { + p_extend->dmac_mode = DMAC_B_MODE_SELECT_REGISTER; + } + + return 0; +} + +static int dma_renesas_rz_get_status(const struct device *dev, uint32_t channel, + struct dma_status *status) +{ + const struct dma_renesas_rz_config *config = dev->config; + struct dma_renesas_rz_data *data = dev->data; + + int ret = dma_channel_common_checks(dev, channel); + + if (ret) { + return ret; + } + + transfer_info_t *p_info; + + p_info = data->channels[channel].fsp_cfg.p_info; + transfer_properties_t properties; + + ret = config->fsp_api->infoGet(data->channels[channel].fsp_ctrl, &properties); + if (FSP_SUCCESS != (fsp_err_t)ret) { + LOG_ERR("%d: Failed to get info dma channel %d info with status %d.", __LINE__, + channel, ret); + return -EIO; + } + + memset(status, 0, sizeof(*status)); + + status->dir = data->channels[channel].direction; + status->pending_length = properties.transfer_length_remaining; + status->busy = status->pending_length ? true : false; + status->total_copied = p_info->length - properties.transfer_length_remaining; + + return 0; +} + +static int dma_renesas_rz_suspend(const struct device *dev, uint32_t channel) +{ + struct dma_renesas_rz_data *data = dev->data; + + int ret = dma_channel_common_checks(dev, channel); + + if (ret) { + return ret; + } + + dmac_b_instance_ctrl_t *p_ctrl = (dmac_b_instance_ctrl_t *)data->channels[channel].fsp_ctrl; + + uint8_t group = DMA_PRV_GROUP(channel); + uint8_t prv_channel = DMA_PRV_CHANNEL(channel); + + /* Set transfer status is suspend */ + p_ctrl->p_reg->GRP[group].CH[prv_channel].CHCTRL = R_DMAC_B0_GRP_CH_CHCTRL_SETSUS_Msk; + + /* Check whether a transfer is suspended. */ + FSP_HARDWARE_REGISTER_WAIT(p_ctrl->p_reg->GRP[group].CH[prv_channel].CHSTAT_b.SUS, 1); + + return 0; +} + +static int dma_renesas_rz_resume(const struct device *dev, uint32_t channel) +{ + struct dma_renesas_rz_data *data = dev->data; + + int ret = dma_channel_common_checks(dev, channel); + + if (ret) { + return ret; + } + + dmac_b_instance_ctrl_t *p_ctrl = (dmac_b_instance_ctrl_t *)data->channels[channel].fsp_ctrl; + + uint8_t group = DMA_PRV_GROUP(channel); + uint8_t prv_channel = DMA_PRV_CHANNEL(channel); + + /* Check whether a transfer is suspended. */ + if (0 == p_ctrl->p_reg->GRP[group].CH[prv_channel].CHSTAT_b.SUS) { + LOG_ERR("%d: DMA channel not suspend.", channel); + return -EINVAL; + } + + /* Restore transfer status from suspend */ + p_ctrl->p_reg->GRP[group].CH[prv_channel].CHCTRL |= R_DMAC_B0_GRP_CH_CHCTRL_CLRSUS_Msk; + + return 0; +} + +static int dma_renesas_rz_stop(const struct device *dev, uint32_t channel) +{ + const struct dma_renesas_rz_config *config = dev->config; + struct dma_renesas_rz_data *data = dev->data; + + int ret = dma_channel_common_checks(dev, channel); + + if (ret) { + return ret; + } + + ret = config->fsp_api->disable(data->channels[channel].fsp_ctrl); + + if (FSP_SUCCESS != (fsp_err_t)ret) { + LOG_ERR("%d: Failed to stop dma channel %d info with status %d.", __LINE__, channel, + ret); + return -EIO; + } + + return 0; +} + +static int dma_renesas_rz_start(const struct device *dev, uint32_t channel) +{ + const struct dma_renesas_rz_config *config = dev->config; + struct dma_renesas_rz_data *data = dev->data; + dmac_b_extended_cfg_t const *p_extend; + + int ret = dma_channel_common_checks(dev, channel); + + if (ret) { + return ret; + } + + p_extend = data->channels[channel].fsp_cfg.p_extend; + + ret = config->fsp_api->enable(data->channels[channel].fsp_ctrl); + + if (FSP_SUCCESS != (fsp_err_t)ret) { + LOG_ERR("%d: Failed to start %d dma channel with status %d.", __LINE__, channel, + ret); + return -EIO; + } + + if (DMAC_TRIGGER_EVENT_SOFTWARE_TRIGGER == p_extend->activation_source) { + ret = config->fsp_api->softwareStart(data->channels[channel].fsp_ctrl, + (transfer_start_mode_t)NULL); + + if (FSP_SUCCESS != (fsp_err_t)ret) { + LOG_ERR("%d: Failed to trigger %d dma channel with status %d.", __LINE__, + channel, ret); + return -EIO; + } + } + + return 0; +} +static int dma_renesas_rz_config(const struct device *dev, uint32_t channel, + struct dma_config *dma_cfg) +{ + const struct dma_renesas_rz_config *config = dev->config; + struct dma_renesas_rz_data *data = dev->data; + struct dma_channel_data *channel_cfg; + int ret; + + if (channel >= config->num_channels) { + LOG_ERR("%d: Invalid DMA channel %d.", __LINE__, channel); + return -EINVAL; + } + + ret = dma_channel_config_check_parameters(dev, dma_cfg); + + if (ret) { + return ret; + } + + ret = dma_channel_config_save_parameters(dev, channel, dma_cfg); + if (ret) { + return ret; + } + + channel_cfg = &data->channels[channel]; + + /* To avoid assertions we should first close the driver instance if already enabled + */ + if (data->channels[channel].is_configured) { + config->fsp_api->close(channel_cfg->fsp_ctrl); + } + + ret = config->fsp_api->open(channel_cfg->fsp_ctrl, &channel_cfg->fsp_cfg); + + if (FSP_SUCCESS != (fsp_err_t)ret) { + LOG_ERR("%d: Failed to configure %d dma channel with status %d.", __LINE__, channel, + ret); + return -EIO; + } + /* Mark that requested channel is configured successfully. */ + data->channels[channel].is_configured = true; + return 0; +} + +static int dma_renesas_rz_reload(const struct device *dev, uint32_t channel, uint32_t src, + uint32_t dst, size_t size) +{ + const struct dma_renesas_rz_config *config = dev->config; + struct dma_renesas_rz_data *data = dev->data; + + int ret = dma_channel_common_checks(dev, channel); + + if (ret) { + return ret; + } + + if (size == 0) { + LOG_ERR("%d: Size must to not equal to 0 %d.", __LINE__, size); + return -EINVAL; + } + + transfer_info_t *p_info = data->channels[channel].fsp_cfg.p_info; + + p_info->length = size; + p_info->p_src = (void const *volatile)src; + p_info->p_dest = (void *volatile)dst; + + ret = config->fsp_api->reconfigure(data->channels[channel].fsp_ctrl, p_info); + + if (FSP_SUCCESS != (fsp_err_t)ret) { + LOG_ERR("%d: Failed to reload %d dma channel with status %d.", __LINE__, channel, + ret); + return -EIO; + } + + return 0; +} + +static int dma_renesas_rz_get_attribute(const struct device *dev, uint32_t type, uint32_t *val) +{ + if (val == NULL) { + LOG_ERR("%d: Invalid attribute context.", __LINE__); + return -EINVAL; + } + + switch (type) { + case DMA_ATTR_BUFFER_ADDRESS_ALIGNMENT: + case DMA_ATTR_BUFFER_SIZE_ALIGNMENT: + case DMA_ATTR_COPY_ALIGNMENT: + return -ENOSYS; + case DMA_ATTR_MAX_BLOCK_COUNT: + /* + * this is restricted to 1 because SG and Link Mode configurations are not + * supported + */ + *val = 1; + break; + default: + return -EINVAL; + } + return 0; +} + +static bool dma_renesas_rz_channel_filter(const struct device *dev, int channel, void *filter_param) +{ + ARG_UNUSED(filter_param); + + const struct dma_renesas_rz_config *config = dev->config; + struct dma_renesas_rz_data *data = dev->data; + + if (channel >= config->num_channels) { + LOG_ERR("%d: Invalid DMA channel %d.", __LINE__, channel); + return -EINVAL; + } + + irq_enable(data->channels[channel].irq); + /* All DMA channels support triggered by periodic sources so always return true */ + return true; +} + +static void dma_renesas_rz_channel_release(const struct device *dev, uint32_t channel) +{ + const struct dma_renesas_rz_config *config = dev->config; + struct dma_renesas_rz_data *data = dev->data; + fsp_err_t ret; + + if (channel >= config->num_channels) { + LOG_ERR("%d: Invalid DMA channel %d.", __LINE__, channel); + } + + irq_disable(data->channels[channel].irq); + ret = config->fsp_api->close(data->channels[channel].fsp_ctrl); + + if (ret != FSP_SUCCESS) { + LOG_ERR("%d: Failed to release %d dma channel with status %d.", __LINE__, channel, + ret); + } +} + +static DEVICE_API(dma, dma_api) = { + .reload = dma_renesas_rz_reload, + .config = dma_renesas_rz_config, + .start = dma_renesas_rz_start, + .stop = dma_renesas_rz_stop, + .suspend = dma_renesas_rz_suspend, + .resume = dma_renesas_rz_resume, + .get_status = dma_renesas_rz_get_status, + .get_attribute = dma_renesas_rz_get_attribute, + .chan_filter = dma_renesas_rz_channel_filter, + .chan_release = dma_renesas_rz_channel_release, +}; + +static int renesas_rz_dma_init(const struct device *dev) +{ + const struct dma_renesas_rz_config *config = dev->config; + + config->irq_configure(); + + return 0; +} + +static void dmac_err_isr(const void *arg) +{ + ARG_UNUSED(arg); + + /* Call FSP DMAC ERR ISR */ + dmac_b_err_isr(); +} + +static void dmac_irq_isr(const void *arg) +{ + ARG_UNUSED(arg); + + /* Call FSP DMAC ISR */ + dmac_b_int_isr(); +} + +#define IRQ_ERR_CONFIGURE(inst, name) \ + IRQ_CONNECT( \ + DT_INST_IRQ_BY_NAME(inst, name, irq), DT_INST_IRQ_BY_NAME(inst, name, priority), \ + dmac_err_isr, DEVICE_DT_INST_GET(inst), \ + COND_CODE_1(DT_IRQ_HAS_CELL_AT_NAME(DT_DRV_INST(inst), name, flags), \ + (DT_INST_IRQ_BY_NAME(inst, name, flags)), (0))); \ + irq_enable(DT_INST_IRQ_BY_NAME(inst, name, irq)); + +#define IRQ_CONFIGURE(n, inst) \ + IRQ_CONNECT(DT_INST_IRQ_BY_IDX(inst, n, irq), DT_INST_IRQ_BY_IDX(inst, n, priority), \ + dmac_irq_isr, DEVICE_DT_INST_GET(inst), \ + COND_CODE_1(DT_IRQ_HAS_CELL_AT_IDX(DT_DRV_INST(inst), n, flags), \ + (DT_INST_IRQ_BY_IDX(inst, n, flags)), (0))); + +#define CONFIGURE_ALL_IRQS(inst, n) LISTIFY(n, IRQ_CONFIGURE, (), inst) + +#define DMA_RZ_INIT(inst) \ + static void dma_rz_##inst##_irq_configure(void) \ + { \ + CONFIGURE_ALL_IRQS(inst, DT_INST_PROP(inst, dma_channels)); \ + COND_CODE_1(DT_INST_IRQ_HAS_NAME(inst, err1), \ + (IRQ_ERR_CONFIGURE(inst, err1)), ()) \ + } \ + \ + static const struct dma_renesas_rz_config dma_renesas_rz_config_##inst = { \ + .unit = inst, \ + .num_channels = DT_INST_PROP(inst, dma_channels), \ + .irq_configure = dma_rz_##inst##_irq_configure, \ + .fsp_api = &g_transfer_on_dmac_b}; \ + \ + static dmac_b_instance_ctrl_t g_transfer_ctrl[DT_INST_PROP(inst, dma_channels)]; \ + static transfer_info_t g_transfer_info[DT_INST_PROP(inst, dma_channels)]; \ + static dmac_b_extended_cfg_t g_transfer_extend[DT_INST_PROP(inst, dma_channels)]; \ + static struct dma_channel_data \ + dma_rz_##inst##_channels[DT_INST_PROP(inst, dma_channels)] = \ + DMA_CHANNEL_ARRAY(inst); \ + \ + ATOMIC_DEFINE(dma_rz_atomic##inst, DT_INST_PROP(inst, dma_channels)); \ + \ + static struct dma_renesas_rz_data dma_renesas_rz_data_##inst = { \ + .ctx = \ + { \ + .magic = DMA_MAGIC, \ + .atomic = dma_rz_atomic##inst, \ + .dma_channels = DT_INST_PROP(inst, dma_channels), \ + }, \ + .channels = dma_rz_##inst##_channels}; \ + \ + DEVICE_DT_INST_DEFINE(inst, renesas_rz_dma_init, NULL, &dma_renesas_rz_data_##inst, \ + &dma_renesas_rz_config_##inst, PRE_KERNEL_1, \ + CONFIG_DMA_INIT_PRIORITY, &dma_api); + +DT_INST_FOREACH_STATUS_OKAY(DMA_RZ_INIT); diff --git a/drivers/dma/dma_renesas_rz.h b/drivers/dma/dma_renesas_rz.h new file mode 100644 index 00000000000..30a9fee135f --- /dev/null +++ b/drivers/dma/dma_renesas_rz.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2024 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/* used to store interrupt and priority for channels */ +#define DMA_CHANNEL_DECLARE(n, inst) \ + { \ + .fsp_ctrl = (transfer_ctrl_t *)&g_transfer_ctrl[n], \ + .fsp_cfg = \ + { \ + .p_info = &g_transfer_info[n], \ + .p_extend = &g_transfer_extend[n], \ + }, \ + .irq = DT_INST_IRQ_BY_IDX(inst, n, irq), \ + .irq_ipl = DT_INST_IRQ_BY_IDX(inst, n, priority), \ + } + +/* Generate an array of DMA channel data structures */ +#define DMA_CHANNEL_ARRAY(inst) \ + {LISTIFY(DT_INST_PROP(inst, dma_channels), DMA_CHANNEL_DECLARE, (,), inst) } + +#define DMA_PRV_CHANNEL(channel) (channel % 8) +#define DMA_PRV_GROUP(channel) (channel / 8) diff --git a/dts/bindings/dma/renesas,rz-dma.yaml b/dts/bindings/dma/renesas,rz-dma.yaml new file mode 100644 index 00000000000..8934f2253d1 --- /dev/null +++ b/dts/bindings/dma/renesas,rz-dma.yaml @@ -0,0 +1,39 @@ +# Copyright (c) 2024 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +description: | + RZ DMA controller + + channel: Select channel for data transmitting + + config: A 32bit mask specifying the DMA channel configuration + + Example of devicetree configuration + + &ssi0 { + status = "okay"; + + dmas = <&dma0 0 RZ_DMA_PERIPH_TO_MEM>, <&dma0 5 RZ_DMA_MEM_TO_PERIPH> + dma-names = "rx", "tx"; + }; + +compatible: "renesas,rz-dma" + +include: [dma-controller.yaml, pinctrl-device.yaml] + +properties: + reg: + required: true + + interrupts: + required: true + + dma-channels: + required: true + + "#dma-cells": + const: 2 + +dma-cells: + - channel + - config diff --git a/include/zephyr/dt-bindings/dma/renesas_rz_dma.h b/include/zephyr/dt-bindings/dma/renesas_rz_dma.h new file mode 100644 index 00000000000..a21506f9bb5 --- /dev/null +++ b/include/zephyr/dt-bindings/dma/renesas_rz_dma.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2024 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_DMA_RENESAS_RZ_DMA_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_DMA_RENESAS_RZ_DMA_H_ + +/* mode: bit 0 (0: Normal, 1: Block) */ +/* source data size: bit 1, 2, 3 (0b000 -> 0b111) */ +/* dest data size: bit 4, 5, 6 (0b000 -> 0b111) */ +/* source addr mode: bit 7 (0: incremented, 1: fixed) */ +/* dest addr mode: bit 8 (0: incremented, 1: fixed) */ + +#define RZ_DMA_MODE_NORMAL (0U) +#define RZ_DMA_MODE_BLOCK (1U) + +/* DMA source data size config on bits 1, 2, 3 */ +#define RZ_DMA_CFG_SRC_DATA_SIZE(val) ((val & 0x7) << 1) +#define RZ_DMA_SRC_1_BYTE RZ_DMA_CFG_SRC_DATA_SIZE(0) +#define RZ_DMA_SRC_2_BYTE RZ_DMA_CFG_SRC_DATA_SIZE(1) +#define RZ_DMA_SRC_4_BYTE RZ_DMA_CFG_SRC_DATA_SIZE(2) +#define RZ_DMA_SRC_8_BYTE RZ_DMA_CFG_SRC_DATA_SIZE(3) +#define RZ_DMA_SRC_16_BYTE RZ_DMA_CFG_SRC_DATA_SIZE(4) +#define RZ_DMA_SRC_32_BYTE RZ_DMA_CFG_SRC_DATA_SIZE(5) +#define RZ_DMA_SRC_64_BYTE RZ_DMA_CFG_SRC_DATA_SIZE(6) +#define RZ_DMA_SRC_128_BYTE RZ_DMA_CFG_SRC_DATA_SIZE(7) + +/* DMA destination data size config on bits 4, 5, 6 */ +#define RZ_DMA_CFG_DEST_DATA_SIZE(val) ((val & 0x7) << 4) +#define RZ_DMA_DEST_1_BYTE RZ_DMA_CFG_DEST_DATA_SIZE(0) +#define RZ_DMA_DEST_2_BYTE RZ_DMA_CFG_DEST_DATA_SIZE(1) +#define RZ_DMA_DEST_4_BYTE RZ_DMA_CFG_DEST_DATA_SIZE(2) +#define RZ_DMA_DEST_8_BYTE RZ_DMA_CFG_DEST_DATA_SIZE(3) +#define RZ_DMA_DEST_16_BYTE RZ_DMA_CFG_DEST_DATA_SIZE(4) +#define RZ_DMA_DEST_32_BYTE RZ_DMA_CFG_DEST_DATA_SIZE(5) +#define RZ_DMA_DEST_64_BYTE RZ_DMA_CFG_DEST_DATA_SIZE(6) +#define RZ_DMA_DEST_128_BYTE RZ_DMA_CFG_DEST_DATA_SIZE(7) + +/* DMA source address mode config on bit 7 */ +#define RZ_DMA_CFG_SRC_ADDR_MODE(val) ((val & 0x1) << 7) +#define RZ_DMA_SRC_INCREMENTED RZ_DMA_CFG_SRC_ADDR_MODE(0) +#define RZ_DMA_SRC_FIXED RZ_DMA_CFG_SRC_ADDR_MODE(1) + +/* DMA source address mode config on bit 8 */ +#define RZ_DMA_CFG_DEST_ADDR_MODE(val) ((val & 0x1) << 8) +#define RZ_DMA_DEST_INCREMENTED RZ_DMA_CFG_DEST_ADDR_MODE(0) +#define RZ_DMA_DEST_FIXED RZ_DMA_CFG_DEST_ADDR_MODE(1) + +/* DMA usual combination for peripheral transfer */ +#define RZ_DMA_MEM_TO_PERIPH \ + (RZ_DMA_MODE_NORMAL | RZ_DMA_SRC_INCREMENTED | RZ_DMA_DEST_FIXED | RZ_DMA_SRC_1_BYTE | \ + RZ_DMA_DEST_1_BYTE) +#define RZ_DMA_PERIPH_TO_MEM \ + (RZ_DMA_MODE_NORMAL | RZ_DMA_SRC_FIXED | RZ_DMA_DEST_INCREMENTED | RZ_DMA_SRC_1_BYTE | \ + RZ_DMA_DEST_1_BYTE) + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_DMA_RENESAS_RZ_DMA_H_ */ diff --git a/modules/Kconfig.renesas_fsp b/modules/Kconfig.renesas_fsp index 7bc5bbc006e..f8001233c8f 100644 --- a/modules/Kconfig.renesas_fsp +++ b/modules/Kconfig.renesas_fsp @@ -197,6 +197,12 @@ config USE_RZ_FSP_EXT_IRQ bool help Enable RZ FSP External IRQ driver + +config USE_RZ_FSP_DMA + bool + help + Enable RZ FSP DMA driver + config USE_RZ_FSP_MHU bool help