drivers: dtc: support dtc driver on RSK_RX130_512KB.

Initial commit to support DTC driver on Renesas RX130.
* drivers: DTC: implementation for DTC driver on RX130.
* dts: rx: update dts node in SoC layer to support DTC on RX130.

Signed-off-by: Phi Tran <phi.tran.jg@bp.renesas.com>
This commit is contained in:
Phi Tran
2024-12-18 11:51:37 +07:00
committed by Johan Hedberg
parent e3aeb4bfd9
commit 58dac199c2
9 changed files with 602 additions and 2 deletions

View File

@@ -11,6 +11,7 @@ add_subdirectory_ifdef(CONFIG_DEVMUX devmux)
add_subdirectory_ifdef(CONFIG_NORDIC_VPR_LAUNCHER nordic_vpr_launcher)
add_subdirectory_ifdef(CONFIG_MCUX_FLEXIO mcux_flexio)
add_subdirectory_ifdef(CONFIG_RENESAS_RA_EXTERNAL_INTERRUPT renesas_ra_external_interrupt)
add_subdirectory_ifdef(CONFIG_RENESAS_RX_DTC renesas_rx_dtc)
add_subdirectory_ifdef(CONFIG_RENESAS_RX_EXTERNAL_INTERRUPT renesas_rx_external_interrupt)
add_subdirectory_ifdef(CONFIG_NXP_RTXXX_DSP_CTRL nxp_rtxxx_dsp_ctrl)
add_subdirectory_ifdef(CONFIG_STM32N6_AXISRAM stm32n6_axisram)

View File

@@ -17,6 +17,7 @@ source "drivers/misc/nordic_vpr_launcher/Kconfig"
source "drivers/misc/mcux_flexio/Kconfig"
source "drivers/misc/interconn/Kconfig"
source "drivers/misc/renesas_ra_external_interrupt/Kconfig"
source "drivers/misc/renesas_rx_dtc/Kconfig"
source "drivers/misc/renesas_rx_external_interrupt/Kconfig"
source "drivers/misc/nxp_rtxxx_dsp_ctrl/Kconfig"
source "drivers/misc/stm32n6_axisram/Kconfig"

View File

@@ -0,0 +1,5 @@
# SPDX-License-Identifier: Apache-2.0
zephyr_library()
zephyr_library_sources_ifdef(CONFIG_RENESAS_RX_DTC renesas_rx_dtc.c)

View File

@@ -0,0 +1,10 @@
# Copyright (c) 2025 Renesas Electronics Corporation
# SPDX-License-Identifier: Apache-2.0
# Renesas RX Data Transfer Controller (DTC) Option
config RENESAS_RX_DTC
bool "Renesas RX Data Transfer Controller (DTC) Driver"
depends on DT_HAS_RENESAS_RX_DTC_ENABLED
help
Enable config options for Renesas RX Data Transfer Controller

View File

@@ -0,0 +1,330 @@
/*
* Copyright (c) 2025 Renesas Electronics Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/gpio/gpio_utils.h>
#include <zephyr/drivers/clock_control.h>
#include <zephyr/irq.h>
#include <soc.h>
#include <zephyr/drivers/misc/renesas_rx_dtc/renesas_rx_dtc.h>
#include "platform.h"
#define DT_DRV_COMPAT renesas_rx_dtc
struct dtc_renesas_rx_config {
volatile struct st_dtc *reg;
const struct device *clock;
struct clock_control_rx_subsys_cfg clock_subsys;
};
struct dtc_renesas_rx_data {
dtc_act_status_t dtc_vt_status[DTC_VECTOR_TABLE_ENTRIES];
};
static transfer_info_t *gp_dtc_vector_table[DTC_VECTOR_TABLE_ENTRIES] DTC_ALIGN_VARIABLE(1024)
DTC_SECTION_ATTRIBUTE;
static void dtc_renesas_rx_wait_for_transfer(const struct device *dev, uint8_t activation_irq)
{
const struct dtc_renesas_rx_config *config = dev->config;
if (!is_valid_activation_irq(activation_irq) || !(config->reg->DTCSTS.BIT.ACT)) {
return;
}
while (activation_irq == config->reg->DTCSTS.BIT.VECN) {
/* Wait for the transfer to complete. */
k_sleep(K_MSEC(1));
}
}
int dtc_renesas_rx_enable_transfer(uint8_t activation_irq)
{
transfer_info_t *p_info = gp_dtc_vector_table[activation_irq];
if (!is_valid_activation_irq(activation_irq)) {
return -EINVAL;
}
if (NULL == p_info) {
return -EACCES;
}
irq_disable(activation_irq);
ICU.DTCER[activation_irq].BIT.DTCE = 1;
irq_enable(activation_irq);
return 0;
}
int dtc_renesas_rx_disable_transfer(uint8_t activation_irq)
{
transfer_info_t *p_info = gp_dtc_vector_table[activation_irq];
if (!is_valid_activation_irq(activation_irq)) {
return -EINVAL;
}
if (NULL == p_info) {
return -EACCES;
}
/* Clear DTC enable bit in ICU. */
ICU.DTCER[activation_irq].BIT.DTCE = 0;
irq_disable(activation_irq);
return 0;
}
void rx_dtc_block_repeat_initialize(transfer_info_t *p_info)
{
uint32_t i = 0;
do {
/* Update the CRA register to the desired settings */
if (TRANSFER_MODE_NORMAL != p_info[i].transfer_settings_word_b.mode) {
uint8_t CRAL = p_info[i].length & DTC_PRV_MASK_CRAL;
p_info[i].length = (uint16_t)((CRAL << DTC_PRV_OFFSET_CRAH) | CRAL);
}
} while (TRANSFER_CHAIN_MODE_DISABLED != p_info[i++].transfer_settings_word_b.chain_mode);
}
void dtc_renesas_rx_get_transfer_status(const struct device *dev,
struct dtc_transfer_status *status)
{
const struct dtc_renesas_rx_config *config = dev->config;
if (0 == (config->reg->DTCSTS.WORD & DTC_PRV_ACT_BIT_MASK)) {
status->in_progress = false;
} else {
status->in_progress = true;
status->activation_irq = (uint8_t)(config->reg->DTCSTS.WORD & DTC_PRV_VECT_NR_MASK);
}
}
int dtc_renesas_rx_off(const struct device *dev)
{
const struct dtc_renesas_rx_config *config = dev->config;
int ret = 0;
config->reg->DTCST.BIT.DTCST = 0;
while (config->reg->DTCSTS.BIT.ACT) {
/* Wait for the DTC to stop. */
__asm__ volatile("nop");
}
/* Disable the power for DTC module. */
ret = clock_control_off(config->clock, (clock_control_subsys_t)&config->clock_subsys);
return ret;
}
int dtc_renesas_rx_on(const struct device *dev)
{
const struct dtc_renesas_rx_config *config = dev->config;
int ret = 0;
/* Enable the power for DTC module. */
ret = clock_control_on(config->clock, (clock_control_subsys_t)&config->clock_subsys);
if (ret < 0) {
return ret;
}
config->reg->DTCST.BIT.DTCST = 1;
return ret;
}
int dtc_renesas_rx_configuration(const struct device *dev, uint8_t activation_irq,
transfer_info_t *p_info)
{
struct dtc_renesas_rx_data *data = dev->data;
const struct dtc_renesas_rx_config *config = dev->config;
if (!is_valid_activation_irq(activation_irq)) {
return -EINVAL;
}
/* Re configuration */
if (!data->dtc_vt_status[activation_irq]) {
dtc_renesas_rx_disable_transfer(activation_irq);
dtc_renesas_rx_wait_for_transfer(dev, activation_irq);
}
rx_dtc_block_repeat_initialize(p_info);
/* Disable read skip prior to modifying settings. */
config->reg->DTCCR.BIT.RRS = 0;
/* Update the entry in the DTC Vector table. */
gp_dtc_vector_table[activation_irq] = p_info;
/* Enable read skip after all settings are written. */
config->reg->DTCCR.BIT.RRS = 1;
data->dtc_vt_status[activation_irq] = DTC_ACT_CONFIGURED;
return 0;
}
int dtc_renesas_rx_start_transfer(const struct device *dev, uint8_t activation_irq)
{
struct dtc_renesas_rx_data *data = dev->data;
int ret;
if (!is_valid_activation_irq(activation_irq)) {
return -EINVAL;
}
if (data->dtc_vt_status[activation_irq] == DTC_ACT_IDLE) {
return -EACCES;
}
ret = dtc_renesas_rx_enable_transfer(activation_irq);
if (ret < 0) {
return ret;
}
data->dtc_vt_status[activation_irq] = DTC_ACT_IN_PROGRESS;
return 0;
}
int dtc_renesas_rx_stop_transfer(const struct device *dev, uint8_t activation_irq)
{
struct dtc_renesas_rx_data *data = dev->data;
int ret;
if (!is_valid_activation_irq(activation_irq)) {
return -EINVAL;
}
if (!data->dtc_vt_status[activation_irq]) {
return -EACCES;
}
ret = dtc_renesas_rx_disable_transfer(activation_irq);
if (ret < 0) {
return ret;
}
/* Clear pointer in vector table. */
data->dtc_vt_status[activation_irq] = DTC_ACT_IDLE;
gp_dtc_vector_table[activation_irq] = NULL;
return 0;
}
int dtc_renesas_rx_reset_transfer(const struct device *dev, uint8_t activation_irq,
void const *p_src, void *p_dest, uint16_t const num_transfers)
{
const struct dtc_renesas_rx_config *config = dev->config;
transfer_info_t *const gp_dtc_vector = gp_dtc_vector_table[activation_irq];
int err = 0;
if (!is_valid_activation_irq(activation_irq)) {
return -EINVAL;
}
err = dtc_renesas_rx_disable_transfer(activation_irq);
if (err < 0) {
return err;
}
dtc_renesas_rx_wait_for_transfer(dev, activation_irq);
config->reg->DTCCR.BIT.RRS = 0;
/* Reset transfer based on input parameters. */
if (NULL != p_src) {
gp_dtc_vector->p_src = p_src;
}
if (NULL != p_dest) {
gp_dtc_vector->p_dest = p_dest;
}
if (TRANSFER_MODE_BLOCK == gp_dtc_vector->transfer_settings_word_b.mode) {
gp_dtc_vector->num_blocks = num_transfers;
} else if (TRANSFER_MODE_NORMAL == gp_dtc_vector->transfer_settings_word_b.mode) {
gp_dtc_vector->length = num_transfers;
} else {
/* Do nothing */
}
config->reg->DTCCR.BIT.RRS = 1;
dtc_renesas_rx_enable_transfer(activation_irq);
return err;
}
int dtc_renesas_rx_info_get(const struct device *dev, uint8_t activation_irq,
transfer_properties_t *const p_properties)
{
if (!is_valid_activation_irq(activation_irq)) {
return -EINVAL;
}
transfer_info_t *p_info = gp_dtc_vector_table[activation_irq];
p_properties->block_count_max = 0U;
p_properties->block_count_remaining = 0U;
if (TRANSFER_MODE_NORMAL != p_info->transfer_settings_word_b.mode) {
/* Repeat and Block Mode */
/* transfer_length_max is the same for Block and repeat mode. */
p_properties->transfer_length_max = DTC_MAX_REPEAT_TRANSFER_LENGTH;
p_properties->transfer_length_remaining = p_info->length & DTC_PRV_MASK_CRAL;
if (TRANSFER_MODE_BLOCK == p_info->transfer_settings_word_b.mode) {
p_properties->block_count_max = DTC_MAX_BLOCK_COUNT;
p_properties->block_count_remaining = p_info->num_blocks;
}
} else {
p_properties->transfer_length_max = DTC_MAX_NORMAL_TRANSFER_LENGTH;
p_properties->transfer_length_remaining = p_info->length;
}
return 0;
}
static int dtc_renesas_rx_init(const struct device *dev)
{
const struct dtc_renesas_rx_config *config = dev->config;
int ret;
memset(&gp_dtc_vector_table, 0, DTC_VECTOR_TABLE_ENTRIES * sizeof(transfer_info_t *));
/* Set DTC vector table. */
config->reg->DTCVBR = gp_dtc_vector_table;
/* Full-address mode */
config->reg->DTCADMOD.BIT.SHORT = 0;
/* Turn on module DTC */
ret = dtc_renesas_rx_on(dev);
return ret;
}
#define DTC_DEVICE_INIT(index) \
static const struct dtc_renesas_rx_config p_transfer_cfg = { \
.reg = (struct st_dtc *)DT_INST_REG_ADDR(index), \
.clock = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(index)), \
.clock_subsys = \
{ \
.mstp = DT_INST_CLOCKS_CELL(index, mstp), \
.stop_bit = DT_INST_CLOCKS_CELL(index, stop_bit), \
}, \
}; \
static struct dtc_renesas_rx_data p_transfer_data; \
\
DEVICE_DT_INST_DEFINE(index, &dtc_renesas_rx_init, NULL, &p_transfer_data, \
&p_transfer_cfg, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \
NULL);
DT_INST_FOREACH_STATUS_OKAY(DTC_DEVICE_INIT);

View File

@@ -0,0 +1,8 @@
# Copyright (c) 2025 Renesas Electronics Corporation
# SPDX-License-Identifier: Apache-2.0
description: Renesas RX Data Transfer Controller (DTC)
compatible: "renesas,rx-dtc"
include: [base.yaml]

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2024 Renesas Electronics Corporation
* Copyright (c) 2024 - 2025 Renesas Electronics Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -57,6 +57,13 @@
};
};
dtc: rx-dtc@82400 {
compatible = "renesas,rx-dtc";
reg = <0x00082400 0x01>;
clocks = <&iclk MSTPA 28>;
status = "okay";
};
soc {
#address-cells = <1>;
#size-cells = <1>;

View File

@@ -0,0 +1,238 @@
/*
* Copyright (c) 2025 Renesas Electronics Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_DRIVERS_MISC_RENESAS_RX_DTC_H_
#define ZEPHYR_DRIVERS_MISC_RENESAS_RX_DTC_H_
#include <zephyr/drivers/gpio.h>
#define DTC_PLACE_IN_SECTION(x) __attribute__((section(x))) __attribute__((__used__))
#define DTC_ALIGN_VARIABLE(x) __aligned(x)
#define DTC_SECTION_ATTRIBUTE DTC_PLACE_IN_SECTION(".dtc_vector_table")
#define DTC_VECTOR_TABLE_ENTRIES (CONFIG_NUM_IRQS)
#define DTC_PRV_ACT_BIT_MASK (1 << 15) /* DTC Active flag (DTCSTS.ACT) bit mask */
#define DTC_PRV_VECT_NR_MASK (0x00FF) /* DTC-Activating Vector Number bits mask */
/* Counter Register A Lower Byte Mask */
#define DTC_PRV_MASK_CRAL (0xFFU)
/* Counter Register A Upper Byte Offset */
#define DTC_PRV_OFFSET_CRAH (8U)
/* Max configurable number of transfers in NORMAL MODE */
#define DTC_MAX_NORMAL_TRANSFER_LENGTH (0x10000)
/* Max number of transfers per repeat for REPEAT MODE */
#define DTC_MAX_REPEAT_TRANSFER_LENGTH (0x100)
/* Max number of transfers per block in BLOCK MODE */
#define DTC_MAX_BLOCK_TRANSFER_LENGTH (0x100)
/* Max configurable number of blocks to transfer in BLOCK MODE */
#define DTC_MAX_BLOCK_COUNT (0x10000)
typedef enum e_transfer_addr_mode {
TRANSFER_ADDR_MODE_FIXED = 0,
TRANSFER_ADDR_MODE_OFFSET = 1,
TRANSFER_ADDR_MODE_INCREMENTED = 2,
TRANSFER_ADDR_MODE_DECREMENTED = 3
} transfer_addr_mode_t;
typedef enum e_transfer_repeat_area {
TRANSFER_REPEAT_AREA_DESTINATION = 0,
TRANSFER_REPEAT_AREA_SOURCE = 1
} transfer_repeat_area_t;
typedef enum e_transfer_irq {
TRANSFER_IRQ_END = 0,
TRANSFER_IRQ_EACH = 1
} transfer_irq_t;
typedef enum e_transfer_chain_mode {
TRANSFER_CHAIN_MODE_DISABLED = 0,
TRANSFER_CHAIN_MODE_EACH = 2,
TRANSFER_CHAIN_MODE_END = 3
} transfer_chain_mode_t;
typedef enum e_transfer_size {
TRANSFER_SIZE_1_BYTE = 0,
TRANSFER_SIZE_2_BYTE = 1,
TRANSFER_SIZE_4_BYTE = 2
} transfer_size_t;
typedef enum e_transfer_mode {
TRANSFER_MODE_NORMAL = 0,
TRANSFER_MODE_REPEAT = 1,
TRANSFER_MODE_BLOCK = 2,
TRANSFER_MODE_REPEAT_BLOCK = 3
} transfer_mode_t;
typedef enum e_dtc_act_status {
DTC_ACT_IDLE = 0,
DTC_ACT_CONFIGURED = 1,
DTC_ACT_IN_PROGRESS = 2,
} dtc_act_status_t;
typedef struct st_transfer_info {
union {
struct {
unsigned int: 16;
unsigned int: 2;
transfer_addr_mode_t dest_addr_mode: 2;
transfer_repeat_area_t repeat_area: 1;
transfer_irq_t irq: 1;
transfer_chain_mode_t chain_mode: 2;
unsigned int: 2;
transfer_addr_mode_t src_addr_mode: 2;
transfer_size_t size: 2;
transfer_mode_t mode: 2;
} transfer_settings_word_b;
uint32_t transfer_settings_word;
};
void const *volatile p_src;
void *volatile p_dest;
volatile uint16_t num_blocks;
volatile uint16_t length;
} transfer_info_t;
typedef struct st_transfer_properties {
uint32_t block_count_max; /* Maximum number of blocks */
uint32_t block_count_remaining; /* Number of blocks remaining */
uint32_t transfer_length_max; /* Maximum number of transfers */
uint32_t transfer_length_remaining; /* Number of transfers remaining */
} transfer_properties_t;
struct dtc_transfer_status {
uint8_t activation_irq;
bool in_progress;
};
/**
* @brief Turn off module DTC.
* @param dev DTC device instance.
*
* @retval 0 On success.
*/
int dtc_renesas_rx_off(const struct device *dev);
/**
* @brief Turn on module DTC.
* @param dev DTC device instance.
*
* @retval 0 On success.
*/
int dtc_renesas_rx_on(const struct device *dev);
/**
* @brief Configure the p_info state and write p_info to DTC vector table.
*
* @param dev DTC device instance.
* @param activation_irq activation source.
* @param p_info transfer info.
*
* @retval 0 On success.
* @retval -EINVAL if activation source is invalid.
*/
int dtc_renesas_rx_configuration(const struct device *dev, uint8_t activation_irq,
transfer_info_t *p_info);
/**
* @brief Enable transfer in ICU on this activation source.
*
* @param activation_irq activation source.
*
* @retval 0 On success.
* @retval -EINVAL if activation source is invalid.
*/
int dtc_renesas_rx_enable_transfer(uint8_t activation_irq);
/**
* @brief Disable transfer in ICU on this activation source.
*
* @param activation_irq activation source.
*
* @retval 0 On success.
* @retval -EINVAL if activation source is invalid.
*/
int dtc_renesas_rx_disable_transfer(uint8_t activation_irq);
/**
* @brief Start transfers on this activation source.
*
* @param dev DTC device instance.
* @param activation_irq activation source.
*
* @retval 0 On success.
* @retval -EINVAL if activation source is invalid.
* @retval -EACCES if this activation source in dtc vector table is not configured.
*/
int dtc_renesas_rx_start_transfer(const struct device *dev, uint8_t activation_irq);
/**
* @brief Stop transfers on this activation source.
*
* @param dev DTC device instance.
* @param activation_irq activation source.
*
* @retval 0 On success.
* @retval -EINVAL if activation source is invalid.
* @retval -EACCES if this activation source in dtc vector table is not configured.
*/
int dtc_renesas_rx_stop_transfer(const struct device *dev, uint8_t activation_irq);
/**
* @brief Reset transfer on this activation source.
*
* @param dev DTC device instance.
* @param activation_irq Activation source IRQ number.
* @param p_src Pointer to the source address for the transfer.
* @param p_dest Pointer to the destination address for the transfer.
* @param num_transfers Number of data units to transfer.
*
* @retval 0 On success.
* @retval -EINVAL If activation source is invalid.
*/
int dtc_renesas_rx_reset_transfer(const struct device *dev, uint8_t activation_irq,
void const *p_src, void *p_dest, uint16_t const num_transfers);
/**
* @brief Get status transfer of DTC module and store it into status pointer.
*
* @param dev DTC device instance.
* @param status DTC status.
*/
void dtc_renesas_rx_get_transfer_status(const struct device *dev,
struct dtc_transfer_status *status);
/**
* @brief Get information about this transfer and store it into p_properties.
*
* @param dev DTC device instance.
* @param activation_irq Activation source IRQ number.
* @param p_properties Pointer to structure to receive driver-specific transfer properties.
*
* @retval 0 On success.
* @retval -EINVAL If activation source is invalid.
*/
int dtc_renesas_rx_info_get(const struct device *dev, uint8_t activation_irq,
transfer_properties_t *const p_properties);
static ALWAYS_INLINE bool is_valid_activation_irq(uint8_t activation_irq)
{
if (activation_irq < 0 || activation_irq > DTC_VECTOR_TABLE_ENTRIES) {
return false;
}
return true;
}
#endif /* ZEPHYR_DRIVERS_MISC_RENESAS_RX_DTC_H_ */

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2024 -2025 Renesas Electronics Corporation
* Copyright (c) 2024 - 2025 Renesas Electronics Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/