drivers: serial: add support of hscif driver for RCar boards

Add support of HSCIF UART driver for Renesas boards.

Signed-off-by: Mykola Kvach <mykola_kvach@epam.com>
This commit is contained in:
Mykola Kvach 2024-01-25 23:52:44 +02:00 committed by Fabio Baltieri
commit 448466a970
4 changed files with 81 additions and 41 deletions

View file

@ -37,10 +37,13 @@ static struct cpg_clk_info_table core_props[] = {
RCAR_CORE_CLK_INFO_ITEM(R8A779F0_CLK_CL16M, RCAR_CPG_NONE, RCAR_CPG_NONE, RCAR_CORE_CLK_INFO_ITEM(R8A779F0_CLK_CL16M, RCAR_CPG_NONE, RCAR_CPG_NONE,
RCAR_CPG_KHZ(16660)), RCAR_CPG_KHZ(16660)),
RCAR_CORE_CLK_INFO_ITEM(R8A779F0_CLK_SASYNCPERD1, RCAR_CPG_NONE, RCAR_CPG_NONE,
266666666),
}; };
/* NOTE: the array MUST be sorted by module field */ /* NOTE: the array MUST be sorted by module field */
static struct cpg_clk_info_table mod_props[] = { static struct cpg_clk_info_table mod_props[] = {
RCAR_MOD_CLK_INFO_ITEM(514, R8A779F0_CLK_SASYNCPERD1),
RCAR_MOD_CLK_INFO_ITEM(702, R8A779F0_CLK_S0D12_PER), RCAR_MOD_CLK_INFO_ITEM(702, R8A779F0_CLK_S0D12_PER),
RCAR_MOD_CLK_INFO_ITEM(704, R8A779F0_CLK_S0D12_PER), RCAR_MOD_CLK_INFO_ITEM(704, R8A779F0_CLK_S0D12_PER),

View file

@ -6,7 +6,7 @@
config UART_RCAR config UART_RCAR
bool "Renesas R-Car UART Driver" bool "Renesas R-Car UART Driver"
default y default y
depends on DT_HAS_RENESAS_RCAR_SCIF_ENABLED depends on DT_HAS_RENESAS_RCAR_SCIF_ENABLED || DT_HAS_RENESAS_RCAR_HSCIF_ENABLED
select SERIAL_HAS_DRIVER select SERIAL_HAS_DRIVER
select SERIAL_SUPPORT_INTERRUPT select SERIAL_SUPPORT_INTERRUPT
help help

View file

@ -25,6 +25,7 @@ struct uart_rcar_cfg {
#ifdef CONFIG_UART_INTERRUPT_DRIVEN #ifdef CONFIG_UART_INTERRUPT_DRIVEN
void (*irq_config_func)(const struct device *dev); void (*irq_config_func)(const struct device *dev);
#endif #endif
bool is_hscif;
}; };
struct uart_rcar_data { struct uart_rcar_data {
@ -51,6 +52,7 @@ struct uart_rcar_data {
#define SCLSR 0x24 /* Line Status Register */ #define SCLSR 0x24 /* Line Status Register */
#define DL 0x30 /* Frequency Division Register */ #define DL 0x30 /* Frequency Division Register */
#define CKS 0x34 /* Clock Select Register */ #define CKS 0x34 /* Clock Select Register */
#define HSSRR 0x40 /* Sampling Rate Register */
/* SCSMR (Serial Mode Register) */ /* SCSMR (Serial Mode Register) */
#define SCSMR_C_A BIT(7) /* Communication Mode */ #define SCSMR_C_A BIT(7) /* Communication Mode */
@ -104,6 +106,10 @@ struct uart_rcar_data {
#define SCLSR_TO BIT(2) /* Timeout */ #define SCLSR_TO BIT(2) /* Timeout */
#define SCLSR_ORER BIT(0) /* Overrun Error */ #define SCLSR_ORER BIT(0) /* Overrun Error */
/* HSSRR (Sampling Rate Register) */
#define HSSRR_SRE BIT(15) /* Sampling Rate Register Enable */
#define HSSRR_SRCYC_DEF_VAL 0x7 /* Sampling rate default value */
static uint8_t uart_rcar_read_8(const struct device *dev, uint32_t offs) static uint8_t uart_rcar_read_8(const struct device *dev, uint32_t offs)
{ {
return sys_read8(DEVICE_MMIO_GET(dev) + offs); return sys_read8(DEVICE_MMIO_GET(dev) + offs);
@ -131,9 +137,14 @@ static void uart_rcar_set_baudrate(const struct device *dev,
uint32_t baud_rate) uint32_t baud_rate)
{ {
struct uart_rcar_data *data = dev->data; struct uart_rcar_data *data = dev->data;
const struct uart_rcar_cfg *cfg = dev->config;
uint8_t reg_val; uint8_t reg_val;
reg_val = ((data->clk_rate + 16 * baud_rate) / (32 * baud_rate) - 1); if (cfg->is_hscif) {
reg_val = data->clk_rate / (2 * (HSSRR_SRCYC_DEF_VAL + 1) * baud_rate) - 1;
} else {
reg_val = ((data->clk_rate + 16 * baud_rate) / (32 * baud_rate) - 1);
}
uart_rcar_write_8(dev, SCBRR, reg_val); uart_rcar_write_8(dev, SCBRR, reg_val);
} }
@ -186,6 +197,7 @@ static int uart_rcar_configure(const struct device *dev,
const struct uart_config *cfg) const struct uart_config *cfg)
{ {
struct uart_rcar_data *data = dev->data; struct uart_rcar_data *data = dev->data;
const struct uart_rcar_cfg *cfg_drv = dev->config;
uint16_t reg_val; uint16_t reg_val;
k_spinlock_key_t key; k_spinlock_key_t key;
@ -229,6 +241,11 @@ static int uart_rcar_configure(const struct device *dev,
SCSMR_CKS1 | SCSMR_CKS0); SCSMR_CKS1 | SCSMR_CKS0);
uart_rcar_write_16(dev, SCSMR, reg_val); uart_rcar_write_16(dev, SCSMR, reg_val);
if (cfg_drv->is_hscif) {
/* TODO: calculate the optimal sampling and bit rates based on error rate */
uart_rcar_write_16(dev, HSSRR, HSSRR_SRE | HSSRR_SRCYC_DEF_VAL);
}
/* Set baudrate */ /* Set baudrate */
uart_rcar_set_baudrate(dev, cfg->baudrate); uart_rcar_set_baudrate(dev, cfg->baudrate);
@ -523,47 +540,44 @@ static const struct uart_driver_api uart_rcar_driver_api = {
}; };
/* Device Instantiation */ /* Device Instantiation */
#define UART_RCAR_DECLARE_CFG(n, IRQ_FUNC_INIT) \ #define UART_RCAR_DECLARE_CFG(n, IRQ_FUNC_INIT, compat) \
PINCTRL_DT_INST_DEFINE(n); \ PINCTRL_DT_INST_DEFINE(n); \
static const struct uart_rcar_cfg uart_rcar_cfg_##n = { \ static const struct uart_rcar_cfg uart_rcar_cfg_##compat##n = { \
DEVICE_MMIO_ROM_INIT(DT_DRV_INST(n)), \ DEVICE_MMIO_ROM_INIT(DT_DRV_INST(n)), \
.clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)), \ .clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)), \
.mod_clk.module = \ .mod_clk.module = DT_INST_CLOCKS_CELL_BY_IDX(n, 0, module), \
DT_INST_CLOCKS_CELL_BY_IDX(n, 0, module), \ .mod_clk.domain = DT_INST_CLOCKS_CELL_BY_IDX(n, 0, domain), \
.mod_clk.domain = \ .bus_clk.module = DT_INST_CLOCKS_CELL_BY_IDX(n, 1, module), \
DT_INST_CLOCKS_CELL_BY_IDX(n, 0, domain), \ .bus_clk.domain = DT_INST_CLOCKS_CELL_BY_IDX(n, 1, domain), \
.bus_clk.module = \ .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \
DT_INST_CLOCKS_CELL_BY_IDX(n, 1, module), \ .is_hscif = DT_NODE_HAS_COMPAT(DT_DRV_INST(n), renesas_rcar_hscif), \
.bus_clk.domain = \ IRQ_FUNC_INIT \
DT_INST_CLOCKS_CELL_BY_IDX(n, 1, domain), \
.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \
IRQ_FUNC_INIT \
} }
#ifdef CONFIG_UART_INTERRUPT_DRIVEN #ifdef CONFIG_UART_INTERRUPT_DRIVEN
#define UART_RCAR_CONFIG_FUNC(n) \ #define UART_RCAR_CONFIG_FUNC(n, compat) \
static void irq_config_func_##n(const struct device *dev) \ static void irq_config_func_##compat##n(const struct device *dev) \
{ \ { \
IRQ_CONNECT(DT_INST_IRQN(n), \ IRQ_CONNECT(DT_INST_IRQN(n), \
DT_INST_IRQ(n, priority), \ DT_INST_IRQ(n, priority), \
uart_rcar_isr, \ uart_rcar_isr, \
DEVICE_DT_INST_GET(n), 0); \ DEVICE_DT_INST_GET(n), 0); \
\ \
irq_enable(DT_INST_IRQN(n)); \ irq_enable(DT_INST_IRQN(n)); \
} }
#define UART_RCAR_IRQ_CFG_FUNC_INIT(n) \ #define UART_RCAR_IRQ_CFG_FUNC_INIT(n, compat) \
.irq_config_func = irq_config_func_##n .irq_config_func = irq_config_func_##compat##n
#define UART_RCAR_INIT_CFG(n) \ #define UART_RCAR_INIT_CFG(n, compat) \
UART_RCAR_DECLARE_CFG(n, UART_RCAR_IRQ_CFG_FUNC_INIT(n)) UART_RCAR_DECLARE_CFG(n, UART_RCAR_IRQ_CFG_FUNC_INIT(n, compat), compat)
#else #else
#define UART_RCAR_CONFIG_FUNC(n) #define UART_RCAR_CONFIG_FUNC(n, compat)
#define UART_RCAR_IRQ_CFG_FUNC_INIT #define UART_RCAR_IRQ_CFG_FUNC_INIT
#define UART_RCAR_INIT_CFG(n) \ #define UART_RCAR_INIT_CFG(n, compat) \
UART_RCAR_DECLARE_CFG(n, UART_RCAR_IRQ_CFG_FUNC_INIT) UART_RCAR_DECLARE_CFG(n, UART_RCAR_IRQ_CFG_FUNC_INIT, compat)
#endif #endif
#define UART_RCAR_INIT(n) \ #define UART_RCAR_INIT(n, compat) \
static struct uart_rcar_data uart_rcar_data_##n = { \ static struct uart_rcar_data uart_rcar_data_##compat##n = { \
.current_config = { \ .current_config = { \
.baudrate = DT_INST_PROP(n, current_speed), \ .baudrate = DT_INST_PROP(n, current_speed), \
.parity = UART_CFG_PARITY_NONE, \ .parity = UART_CFG_PARITY_NONE, \
@ -573,18 +587,23 @@ static const struct uart_driver_api uart_rcar_driver_api = {
}, \ }, \
}; \ }; \
\ \
static const struct uart_rcar_cfg uart_rcar_cfg_##n; \ static const struct uart_rcar_cfg uart_rcar_cfg_##compat##n; \
\ \
DEVICE_DT_INST_DEFINE(n, \ DEVICE_DT_INST_DEFINE(n, \
uart_rcar_init, \ uart_rcar_init, \
NULL, \ NULL, \
&uart_rcar_data_##n, \ &uart_rcar_data_##compat##n, \
&uart_rcar_cfg_##n, \ &uart_rcar_cfg_##compat##n, \
PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY, \ PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY, \
&uart_rcar_driver_api); \ &uart_rcar_driver_api); \
\ \
UART_RCAR_CONFIG_FUNC(n) \ UART_RCAR_CONFIG_FUNC(n, compat) \
\ \
UART_RCAR_INIT_CFG(n); UART_RCAR_INIT_CFG(n, compat);
DT_INST_FOREACH_STATUS_OKAY(UART_RCAR_INIT) DT_INST_FOREACH_STATUS_OKAY_VARGS(UART_RCAR_INIT, DT_DRV_COMPAT)
#undef DT_DRV_COMPAT
#define DT_DRV_COMPAT renesas_rcar_hscif
DT_INST_FOREACH_STATUS_OKAY_VARGS(UART_RCAR_INIT, DT_DRV_COMPAT)

View file

@ -0,0 +1,18 @@
# Copyright (c) 2024, EPAM Systems
# SPDX-License-Identifier: Apache-2.0
description: Renesas R-Car HSCIF controller
compatible: "renesas,rcar-hscif"
include: [uart-controller.yaml, pinctrl-device.yaml]
properties:
reg:
required: true
clocks:
required: true
current-speed:
required: true