Skip to content

Commit c1fb75b

Browse files
nhutnguyenkckartben
authored andcommitted
drivers: serial: Add polling mode support for RZ/G3S
This is the initial commit to support UART driver for Renesas RZ/G3S. The driver only implements polling API for minimal support. Signed-off-by: Nhut Nguyen <[email protected]> Signed-off-by: Binh Nguyen <[email protected]>
1 parent 25ed9c9 commit c1fb75b

File tree

7 files changed

+393
-0
lines changed

7 files changed

+393
-0
lines changed

drivers/serial/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ zephyr_library_sources_ifdef(CONFIG_UART_QUICKLOGIC_USBSERIALPORT_S3B uart_ql_us
5858
zephyr_library_sources_ifdef(CONFIG_UART_RA8_SCI_B uart_renesas_ra8_sci_b.c)
5959
zephyr_library_sources_ifdef(CONFIG_UART_RCAR uart_rcar.c)
6060
zephyr_library_sources_ifdef(CONFIG_UART_RENESAS_RA uart_renesas_ra.c)
61+
zephyr_library_sources_ifdef(CONFIG_UART_RENESAS_RZ_SCIF uart_renesas_rz_scif.c)
6162
zephyr_library_sources_ifdef(CONFIG_UART_RPI_PICO_PIO uart_rpi_pico_pio.c)
6263
zephyr_library_sources_ifdef(CONFIG_UART_RTT_DRIVER uart_rtt.c)
6364
zephyr_library_sources_ifdef(CONFIG_UART_RV32M1_LPUART uart_rv32m1_lpuart.c)

drivers/serial/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ rsource "Kconfig.ql_usbserialport_s3b"
199199
rsource "Kconfig.rcar"
200200
rsource "Kconfig.renesas_ra"
201201
rsource "Kconfig.renesas_ra8"
202+
rsource "Kconfig.renesas_rz"
202203
rsource "Kconfig.rpi_pico"
203204
rsource "Kconfig.rtt"
204205
rsource "Kconfig.rv32m1_lpuart"

drivers/serial/Kconfig.renesas_rz

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Copyright (c) 2024 Renesas Electronics Corporation
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
config UART_RENESAS_RZ_SCIF
5+
bool "Renesas RZ SCIF UART"
6+
default y
7+
depends on DT_HAS_RENESAS_RZ_SCIF_UART_ENABLED
8+
select SERIAL_HAS_DRIVER
9+
select USE_RZ_FSP_SCIF_UART
10+
select PINCTRL
11+
help
12+
Enable Renesas RZ SCIF UART Driver.
13+
14+
if UART_RENESAS_RZ_SCIF
15+
16+
config UART_RENESAS_RZG_INIT_DELAY_MS
17+
int "UART initialization delay in milliseconds"
18+
default 8000
19+
help
20+
This option is to make a delay to wait for the A55 to complete its setting first
21+
before UART initialization of M33.
22+
23+
endif

drivers/serial/uart_renesas_rz_scif.c

Lines changed: 301 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,301 @@
1+
/*
2+
* Copyright (c) 2024 Renesas Electronics Corporation
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
#define DT_DRV_COMPAT renesas_rz_scif_uart
7+
8+
#include <zephyr/drivers/pinctrl.h>
9+
#include <zephyr/drivers/uart.h>
10+
#include <zephyr/logging/log.h>
11+
#include "r_scif_uart.h"
12+
13+
LOG_MODULE_REGISTER(rz_scif_uart);
14+
15+
struct uart_rz_scif_config {
16+
const struct pinctrl_dev_config *pin_config;
17+
const uart_api_t *fsp_api;
18+
};
19+
20+
struct uart_rz_scif_data {
21+
struct uart_config uart_config;
22+
uart_cfg_t *fsp_cfg;
23+
scif_uart_instance_ctrl_t *fsp_ctrl;
24+
};
25+
26+
static int uart_rz_scif_poll_in(const struct device *dev, unsigned char *c)
27+
{
28+
struct uart_rz_scif_data *data = dev->data;
29+
R_SCIFA0_Type *reg = data->fsp_ctrl->p_reg;
30+
31+
if (reg->FDR_b.R == 0U) {
32+
/* There are no characters available to read. */
33+
return -1;
34+
}
35+
*c = reg->FRDR;
36+
37+
return 0;
38+
}
39+
40+
static void uart_rz_scif_poll_out(const struct device *dev, unsigned char c)
41+
{
42+
struct uart_rz_scif_data *data = dev->data;
43+
R_SCIFA0_Type *reg = data->fsp_ctrl->p_reg;
44+
45+
while (!reg->FSR_b.TDFE) {
46+
}
47+
48+
reg->FTDR = c;
49+
50+
while (!reg->FSR_b.TEND) {
51+
}
52+
}
53+
54+
static int uart_rz_scif_err_check(const struct device *dev)
55+
{
56+
struct uart_rz_scif_data *data = dev->data;
57+
R_SCIFA0_Type *reg = data->fsp_ctrl->p_reg;
58+
59+
const uint32_t fsr = reg->FSR;
60+
const uint32_t lsr = reg->LSR;
61+
int errors = 0;
62+
63+
if ((lsr & R_SCIFA0_LSR_ORER_Msk) != 0) {
64+
errors |= UART_ERROR_OVERRUN;
65+
}
66+
if ((fsr & R_SCIFA0_FSR_PER_Msk) != 0) {
67+
errors |= UART_ERROR_PARITY;
68+
}
69+
if ((fsr & R_SCIFA0_FSR_FER_Pos) != 0) {
70+
errors |= UART_ERROR_FRAMING;
71+
}
72+
73+
return errors;
74+
}
75+
76+
static int uart_rz_scif_apply_config(const struct device *dev)
77+
{
78+
struct uart_rz_scif_data *data = dev->data;
79+
80+
struct uart_config *uart_config = &data->uart_config;
81+
uart_cfg_t *fsp_cfg = data->fsp_cfg;
82+
83+
scif_baud_setting_t baud_setting;
84+
scif_uart_extended_cfg_t config_extend;
85+
const scif_uart_extended_cfg_t *fsp_config_extend = fsp_cfg->p_extend;
86+
87+
fsp_err_t fsp_err;
88+
89+
fsp_err = R_SCIF_UART_BaudCalculate(data->fsp_ctrl, uart_config->baudrate, false, 5000,
90+
&baud_setting);
91+
if (fsp_err) {
92+
return -EIO;
93+
}
94+
95+
memcpy(fsp_config_extend->p_baud_setting, &baud_setting, sizeof(scif_baud_setting_t));
96+
97+
switch (uart_config->data_bits) {
98+
case UART_CFG_DATA_BITS_7:
99+
fsp_cfg->data_bits = UART_DATA_BITS_7;
100+
break;
101+
case UART_CFG_DATA_BITS_8:
102+
fsp_cfg->data_bits = UART_DATA_BITS_8;
103+
break;
104+
default:
105+
return -ENOTSUP;
106+
}
107+
108+
switch (uart_config->parity) {
109+
case UART_CFG_PARITY_NONE:
110+
fsp_cfg->parity = UART_PARITY_OFF;
111+
break;
112+
case UART_CFG_PARITY_ODD:
113+
fsp_cfg->parity = UART_PARITY_ODD;
114+
break;
115+
case UART_CFG_PARITY_EVEN:
116+
fsp_cfg->parity = UART_PARITY_EVEN;
117+
break;
118+
default:
119+
return -ENOTSUP;
120+
}
121+
122+
switch (uart_config->stop_bits) {
123+
case UART_CFG_STOP_BITS_1:
124+
fsp_cfg->stop_bits = UART_STOP_BITS_1;
125+
break;
126+
case UART_CFG_STOP_BITS_2:
127+
fsp_cfg->stop_bits = UART_STOP_BITS_2;
128+
break;
129+
default:
130+
return -ENOTSUP;
131+
}
132+
133+
memcpy(&config_extend, fsp_config_extend->p_baud_setting, sizeof(scif_baud_setting_t));
134+
135+
switch (uart_config->flow_ctrl) {
136+
case UART_CFG_FLOW_CTRL_NONE:
137+
config_extend.flow_control = SCIF_UART_FLOW_CONTROL_NONE;
138+
config_extend.uart_mode = SCIF_UART_MODE_RS232;
139+
config_extend.rs485_setting.enable = SCI_UART_RS485_DISABLE;
140+
break;
141+
case UART_CFG_FLOW_CTRL_RTS_CTS:
142+
config_extend.flow_control = SCIF_UART_FLOW_CONTROL_AUTO;
143+
config_extend.uart_mode = SCIF_UART_MODE_RS232;
144+
config_extend.rs485_setting.enable = SCI_UART_RS485_DISABLE;
145+
break;
146+
default:
147+
return -ENOTSUP;
148+
}
149+
150+
memcpy(fsp_config_extend->p_baud_setting, &config_extend, sizeof(scif_baud_setting_t));
151+
152+
return 0;
153+
}
154+
155+
#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE
156+
157+
static int uart_rz_scif_configure(const struct device *dev, const struct uart_config *cfg)
158+
{
159+
int err;
160+
fsp_err_t fsp_err;
161+
const struct uart_rz_scif_config *config = dev->config;
162+
struct uart_rz_scif_data *data = dev->data;
163+
164+
memcpy(&data->uart_config, cfg, sizeof(struct uart_config));
165+
166+
err = uart_rz_scif_apply_config(dev);
167+
168+
if (err) {
169+
return err;
170+
}
171+
172+
fsp_err = config->fsp_api->close(data->fsp_ctrl);
173+
if (fsp_err) {
174+
return -EIO;
175+
}
176+
177+
fsp_err = config->fsp_api->open(data->fsp_ctrl, data->fsp_cfg);
178+
if (fsp_err) {
179+
return -EIO;
180+
}
181+
182+
R_SCIFA0_Type *reg = data->fsp_ctrl->p_reg;
183+
/* Temporarily disable the DRI interrupt caused by receive data ready */
184+
/* TODO: support interrupt-driven api */
185+
reg->SCR_b.RIE = 0;
186+
187+
return err;
188+
}
189+
190+
static int uart_rz_scif_config_get(const struct device *dev, struct uart_config *cfg)
191+
{
192+
struct uart_rz_scif_data *data = dev->data;
193+
194+
memcpy(cfg, &data->uart_config, sizeof(struct uart_config));
195+
return 0;
196+
}
197+
198+
#endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */
199+
200+
static const struct uart_driver_api uart_rz_scif_driver_api = {
201+
.poll_in = uart_rz_scif_poll_in,
202+
.poll_out = uart_rz_scif_poll_out,
203+
.err_check = uart_rz_scif_err_check,
204+
#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE
205+
.configure = uart_rz_scif_configure,
206+
.config_get = uart_rz_scif_config_get,
207+
#endif
208+
};
209+
210+
static int uart_rz_scif_init(const struct device *dev)
211+
{
212+
const struct uart_rz_scif_config *config = dev->config;
213+
struct uart_rz_scif_data *data = dev->data;
214+
int ret;
215+
216+
/* Configure dt provided device signals when available */
217+
ret = pinctrl_apply_state(config->pin_config, PINCTRL_STATE_DEFAULT);
218+
if (ret < 0) {
219+
return ret;
220+
}
221+
222+
/* uart_rz_scif_apply_config must be called first before open api */
223+
ret = uart_rz_scif_apply_config(dev);
224+
if (ret < 0) {
225+
return ret;
226+
}
227+
228+
config->fsp_api->open(data->fsp_ctrl, data->fsp_cfg);
229+
230+
R_SCIFA0_Type *reg = data->fsp_ctrl->p_reg;
231+
/* Temporarily disable the DRI interrupt caused by receive data ready */
232+
/* TODO: support interrupt-driven api */
233+
reg->SCR_b.RIE = 0;
234+
235+
return 0;
236+
}
237+
238+
#define UART_RZG_INIT(n) \
239+
static scif_uart_instance_ctrl_t g_uart##n##_ctrl; \
240+
static scif_baud_setting_t g_uart##n##_baud_setting; \
241+
static scif_uart_extended_cfg_t g_uart##n##_cfg_extend = { \
242+
.bri_ipl = DT_INST_IRQ_BY_NAME(n, bri, priority), \
243+
.bri_irq = DT_INST_IRQ_BY_NAME(n, bri, irq), \
244+
.clock = SCIF_UART_CLOCK_INT, \
245+
.noise_cancel = SCIF_UART_NOISE_CANCELLATION_ENABLE, \
246+
.p_baud_setting = &g_uart##n##_baud_setting, \
247+
.rx_fifo_trigger = SCIF_UART_RECEIVE_TRIGGER_MAX, \
248+
.rts_fifo_trigger = SCIF_UART_RTS_TRIGGER_14, \
249+
.uart_mode = SCIF_UART_MODE_RS232, \
250+
.flow_control = SCIF_UART_FLOW_CONTROL_NONE, \
251+
.rs485_setting = \
252+
{ \
253+
.enable = (sci_uart_rs485_enable_t)NULL, \
254+
.polarity = SCI_UART_RS485_DE_POLARITY_HIGH, \
255+
.de_control_pin = \
256+
(bsp_io_port_pin_t)SCIF_UART_INVALID_16BIT_PARAM, \
257+
}, \
258+
}; \
259+
static uart_cfg_t g_uart##n##_cfg = { \
260+
.channel = DT_INST_PROP(n, channel), \
261+
.p_callback = NULL, \
262+
.p_context = NULL, \
263+
.p_extend = &g_uart##n##_cfg_extend, \
264+
.p_transfer_tx = NULL, \
265+
.p_transfer_rx = NULL, \
266+
.rxi_ipl = DT_INST_IRQ_BY_NAME(n, rxi, priority), \
267+
.txi_ipl = DT_INST_IRQ_BY_NAME(n, txi, priority), \
268+
.tei_ipl = DT_INST_IRQ_BY_NAME(n, tei, priority), \
269+
.eri_ipl = DT_INST_IRQ_BY_NAME(n, eri, priority), \
270+
.rxi_irq = DT_INST_IRQ_BY_NAME(n, rxi, irq), \
271+
.txi_irq = DT_INST_IRQ_BY_NAME(n, txi, irq), \
272+
.tei_irq = DT_INST_IRQ_BY_NAME(n, tei, irq), \
273+
.eri_irq = DT_INST_IRQ_BY_NAME(n, eri, irq), \
274+
}; \
275+
PINCTRL_DT_INST_DEFINE(n); \
276+
static const struct uart_rz_scif_config uart_rz_scif_config_##n = { \
277+
.pin_config = PINCTRL_DT_INST_DEV_CONFIG_GET(n), .fsp_api = &g_uart_on_scif}; \
278+
static struct uart_rz_scif_data uart_rz_scif_data_##n = { \
279+
.uart_config = \
280+
{ \
281+
.baudrate = DT_INST_PROP_OR(n, current_speed, 115200), \
282+
.parity = DT_INST_ENUM_IDX_OR(n, parity, UART_CFG_PARITY_NONE), \
283+
.stop_bits = \
284+
DT_INST_ENUM_IDX_OR(n, stop_bits, UART_CFG_STOP_BITS_1), \
285+
.data_bits = \
286+
DT_INST_ENUM_IDX_OR(n, data_bits, UART_CFG_DATA_BITS_8), \
287+
.flow_ctrl = DT_INST_PROP_OR(n, hw_flow_control, \
288+
UART_CFG_FLOW_CTRL_NONE), \
289+
}, \
290+
.fsp_cfg = &g_uart##n##_cfg, \
291+
.fsp_ctrl = &g_uart##n##_ctrl, \
292+
}; \
293+
static int uart_rz_scif_init_##n(const struct device *dev) \
294+
{ \
295+
return uart_rz_scif_init(dev); \
296+
} \
297+
DEVICE_DT_INST_DEFINE(n, &uart_rz_scif_init_##n, NULL, &uart_rz_scif_data_##n, \
298+
&uart_rz_scif_config_##n, PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY, \
299+
&uart_rz_scif_driver_api);
300+
301+
DT_INST_FOREACH_STATUS_OKAY(UART_RZG_INIT)

dts/arm/renesas/rz/rzg/r9a08g045.dtsi

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,55 @@
3737
reg = <0x41030000 DT_SIZE_K(64)>;
3838
reg-names = "pinctrl";
3939
};
40+
41+
scif0: serial@4004b800 {
42+
compatible = "renesas,rz-scif-uart";
43+
channel = <0>;
44+
reg = <0x4004b800 0x18>;
45+
interrupts = <320 1>, <321 1>, <322 1>, <323 1>, <324 1>;
46+
interrupt-names = "eri", "bri", "rxi", "txi", "tei";
47+
status = "disabled";
48+
};
49+
scif1: serial@4004bc00 {
50+
compatible = "renesas,rz-scif-uart";
51+
channel = <1>;
52+
reg = <0x4004bc00 0x18>;
53+
interrupts = <325 1>, <326 1>, <327 1>, <328 1>, <329 1>;
54+
interrupt-names = "eri", "bri", "rxi", "txi", "tei";
55+
status = "disabled";
56+
};
57+
scif2: serial@4004c000 {
58+
compatible = "renesas,rz-scif-uart";
59+
channel = <2>;
60+
reg = <0x4004c000 0x18>;
61+
interrupts = <330 1>, <331 1>, <332 1>, <333 1>, <334 1>;
62+
interrupt-names = "eri", "bri", "rxi", "txi", "tei";
63+
status = "disabled";
64+
};
65+
scif3: serial@4004c400 {
66+
compatible = "renesas,rz-scif-uart";
67+
channel = <3>;
68+
reg = <0x4004c400 0x18>;
69+
interrupts = <335 1>, <336 1>, <337 1>, <338 1>, <339 1>;
70+
interrupt-names = "eri", "bri", "rxi", "txi", "tei";
71+
status = "disabled";
72+
};
73+
scif4: serial@4004c800 {
74+
compatible = "renesas,rz-scif-uart";
75+
channel = <4>;
76+
reg = <0x4004c800 0x18>;
77+
interrupts = <340 1>, <341 1>, <342 1>, <343 1>, <344 1>;
78+
interrupt-names = "eri", "bri", "rxi", "txi", "tei";
79+
status = "disabled";
80+
};
81+
scif5: serial@4004e000 {
82+
compatible = "renesas,rz-scif-uart";
83+
channel = <5>;
84+
reg = <0x4004e000 0x18>;
85+
interrupts = <345 1>, <346 1>, <347 1>, <348 1>, <349 1>;
86+
interrupt-names = "eri", "bri", "rxi", "txi", "tei";
87+
status = "disabled";
88+
};
4089
};
4190
};
4291

0 commit comments

Comments
 (0)