Skip to content

Commit c5a057b

Browse files
Aymeric Ailletcarlescufi
authored andcommitted
drivers: serial: add Renesas R-Car driver
This patch add support for polling based UART on the Renesas R-Car SCIF (Serial Communication Interface with FIFO) This hardware block can be found on various Renesas R-Car SoC series. It allows to get console on R-Car Gen3 H3ULCB board. Signed-off-by: Aymeric Aillet <[email protected]>
1 parent 9a90dff commit c5a057b

File tree

5 files changed

+319
-0
lines changed

5 files changed

+319
-0
lines changed

CODEOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,7 @@
293293
/drivers/serial/*xmc4xxx* @parthitce
294294
/drivers/serial/*nuvoton* @ssekar15
295295
/drivers/serial/*apbuart* @martin-aberg
296+
/drivers/serial/*rcar* @aaillet
296297
/drivers/disk/ @jfischer-no
297298
/drivers/disk/sdmmc_sdhc.h @JunYangNXP
298299
/drivers/disk/sdmmc_spi.c @JunYangNXP

drivers/serial/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ zephyr_library_sources_ifdef(CONFIG_UART_XMC4XXX uart_xmc4xxx.c)
3838
zephyr_library_sources_ifdef(CONFIG_UART_NPCX uart_npcx.c)
3939
zephyr_library_sources_ifdef(CONFIG_UART_APBUART uart_apbuart.c)
4040
zephyr_library_sources_ifdef(CONFIG_USB_CDC_ACM ${ZEPHYR_BASE}/misc/empty_file.c)
41+
zephyr_library_sources_ifdef(CONFIG_UART_RCAR uart_rcar.c)
4142

4243
zephyr_library_sources_ifdef(CONFIG_USERSPACE uart_handlers.c)
4344

drivers/serial/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,4 +134,6 @@ source "drivers/serial/Kconfig.npcx"
134134

135135
source "drivers/serial/Kconfig.apbuart"
136136

137+
source "drivers/serial/Kconfig.rcar"
138+
137139
endif # SERIAL

drivers/serial/Kconfig.rcar

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Reneas R-Car UART configuration options
2+
3+
# Copyright (c) 2021 IoT.bzh
4+
# SPDX-License-Identifier: Apache-2.0
5+
6+
config UART_RCAR
7+
bool "Renesas R-Car UART Driver"
8+
select SERIAL_HAS_DRIVER
9+
depends on SOC_FAMILY_RCAR
10+
help
11+
Enable Renesas R-Car UART Driver.

drivers/serial/uart_rcar.c

Lines changed: 304 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,304 @@
1+
/*
2+
* Copyright (c) 2021 IoT.bzh
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#define DT_DRV_COMPAT renesas_rcar_scif
8+
9+
#include <errno.h>
10+
#include <device.h>
11+
#include <devicetree.h>
12+
#include <drivers/uart.h>
13+
#include <drivers/clock_control.h>
14+
#include <drivers/clock_control/rcar_clock_control.h>
15+
16+
struct uart_rcar_cfg {
17+
uint32_t reg_addr;
18+
const struct device *clock_dev;
19+
struct rcar_cpg_clk mod_clk;
20+
struct rcar_cpg_clk bus_clk;
21+
};
22+
23+
struct uart_rcar_data {
24+
struct uart_config current_config;
25+
uint32_t clk_rate;
26+
};
27+
28+
/* Registers */
29+
#define SCSMR 0x00 /* Serial Mode Register */
30+
#define SCBRR 0x04 /* Bit Rate Register */
31+
#define SCSCR 0x08 /* Serial Control Register */
32+
#define SCFTDR 0x0c /* Transmit FIFO Data Register */
33+
#define SCFSR 0x10 /* Serial Status Register */
34+
#define SCFRDR 0x14 /* Receive FIFO Data Register */
35+
#define SCFCR 0x18 /* FIFO Control Register */
36+
#define SCFDR 0x1c /* FIFO Data Count Register */
37+
#define SCSPTR 0x20 /* Serial Port Register */
38+
#define SCLSR 0x24 /* Line Status Register */
39+
#define DL 0x30 /* Frequency Division Register */
40+
#define CKS 0x34 /* Clock Select Register */
41+
42+
/* SCSMR (Serial Mode Register) */
43+
#define SCSMR_C_A BIT(7) /* Communication Mode */
44+
#define SCSMR_CHR BIT(6) /* 7-bit Character Length */
45+
#define SCSMR_PE BIT(5) /* Parity Enable */
46+
#define SCSMR_O_E BIT(4) /* Odd Parity */
47+
#define SCSMR_STOP BIT(3) /* Stop Bit Length */
48+
#define SCSMR_CKS1 BIT(1) /* Clock Select 1 */
49+
#define SCSMR_CKS0 BIT(0) /* Clock Select 0 */
50+
51+
/* SCSCR (Serial Control Register) */
52+
#define SCSCR_TEIE BIT(11) /* Transmit End Interrupt Enable */
53+
#define SCSCR_TIE BIT(7) /* Transmit Interrupt Enable */
54+
#define SCSCR_RIE BIT(6) /* Receive Interrupt Enable */
55+
#define SCSCR_TE BIT(5) /* Transmit Enable */
56+
#define SCSCR_RE BIT(4) /* Receive Enable */
57+
#define SCSCR_REIE BIT(3) /* Receive Error Interrupt Enable */
58+
#define SCSCR_TOIE BIT(2) /* Timeout Interrupt Enable */
59+
#define SCSCR_CKE1 BIT(1) /* Clock Enable 1 */
60+
#define SCSCR_CKE0 BIT(0) /* Clock Enable 0 */
61+
62+
/* SCFCR (FIFO Control Register) */
63+
#define SCFCR_RTRG1 BIT(7) /* Receive FIFO Data Count Trigger 1 */
64+
#define SCFCR_RTRG0 BIT(6) /* Receive FIFO Data Count Trigger 0 */
65+
#define SCFCR_TTRG1 BIT(5) /* Transmit FIFO Data Count Trigger 1 */
66+
#define SCFCR_TTRG0 BIT(4) /* Transmit FIFO Data Count Trigger 0 */
67+
#define SCFCR_MCE BIT(3) /* Modem Control Enable */
68+
#define SCFCR_TFRST BIT(2) /* Transmit FIFO Data Register Reset */
69+
#define SCFCR_RFRST BIT(1) /* Receive FIFO Data Register Reset */
70+
#define SCFCR_LOOP BIT(0) /* Loopback Test */
71+
72+
/* SCFSR (Serial Status Register) */
73+
#define SCFSR_PER3 BIT(15) /* Parity Error Count 3 */
74+
#define SCFSR_PER2 BIT(14) /* Parity Error Count 2 */
75+
#define SCFSR_PER1 BIT(13) /* Parity Error Count 1 */
76+
#define SCFSR_PER0 BIT(12) /* Parity Error Count 0 */
77+
#define SCFSR_FER3 BIT(11) /* Framing Error Count 3 */
78+
#define SCFSR_FER2 BIT(10) /* Framing Error Count 2 */
79+
#define SCFSR_FER_1 BIT(9) /* Framing Error Count 1 */
80+
#define SCFSR_FER0 BIT(8) /* Framing Error Count 0 */
81+
#define SCFSR_ER BIT(7) /* Receive Error */
82+
#define SCFSR_TEND BIT(6) /* Transmission ended */
83+
#define SCFSR_TDFE BIT(5) /* Transmit FIFO Data Empty */
84+
#define SCFSR_BRK BIT(4) /* Break Detect */
85+
#define SCFSR_FER BIT(3) /* Framing Error */
86+
#define SCFSR_PER BIT(2) /* Parity Error */
87+
#define SCFSR_RDF BIT(1) /* Receive FIFO Data Full */
88+
#define SCFSR_DR BIT(0) /* Receive Data Ready */
89+
90+
/* SCLSR (Line Status Register) on (H)SCIF */
91+
#define SCLSR_TO BIT(2) /* Timeout */
92+
#define SCLSR_ORER BIT(0) /* Overrun Error */
93+
94+
/* Helper macros for UART */
95+
#define DEV_UART_CFG(dev) \
96+
((const struct uart_rcar_cfg *)(dev)->config)
97+
#define DEV_UART_DATA(dev) \
98+
((struct uart_rcar_data *)(dev)->data)
99+
100+
static void uart_rcar_write_8(const struct uart_rcar_cfg *config,
101+
uint32_t offs, uint8_t value)
102+
{
103+
sys_write8(value, config->reg_addr + offs);
104+
}
105+
106+
static uint16_t uart_rcar_read_16(const struct uart_rcar_cfg *config,
107+
uint32_t offs)
108+
{
109+
return sys_read16(config->reg_addr + offs);
110+
}
111+
112+
static void uart_rcar_write_16(const struct uart_rcar_cfg *config,
113+
uint32_t offs, uint16_t value)
114+
{
115+
sys_write16(value, config->reg_addr + offs);
116+
}
117+
118+
static void uart_rcar_set_baudrate(const struct device *dev,
119+
uint32_t baud_rate)
120+
{
121+
const struct uart_rcar_cfg *config = DEV_UART_CFG(dev);
122+
struct uart_rcar_data *data = DEV_UART_DATA(dev);
123+
uint8_t reg_val;
124+
125+
reg_val = ((data->clk_rate + 16 * baud_rate) / (32 * baud_rate) - 1);
126+
uart_rcar_write_8(config, SCBRR, reg_val);
127+
}
128+
129+
static int uart_rcar_poll_in(const struct device *dev, unsigned char *p_char)
130+
{
131+
const struct uart_rcar_cfg *config = DEV_UART_CFG(dev);
132+
uint16_t reg_val;
133+
134+
/* Receive FIFO empty */
135+
if (!((uart_rcar_read_16(config, SCFSR)) & SCFSR_RDF)) {
136+
return -1;
137+
}
138+
139+
*p_char = uart_rcar_read_16(config, SCFRDR);
140+
141+
reg_val = uart_rcar_read_16(config, SCFSR);
142+
reg_val &= ~SCFSR_RDF;
143+
uart_rcar_write_16(config, SCFSR, reg_val);
144+
145+
return 0;
146+
}
147+
148+
static void uart_rcar_poll_out(const struct device *dev, unsigned char out_char)
149+
{
150+
const struct uart_rcar_cfg *config = DEV_UART_CFG(dev);
151+
uint16_t reg_val;
152+
153+
/* Wait for empty space in transmit FIFO */
154+
while (!(uart_rcar_read_16(config, SCFSR) & SCFSR_TDFE)) {
155+
}
156+
157+
uart_rcar_write_8(config, SCFTDR, out_char);
158+
159+
reg_val = uart_rcar_read_16(config, SCFSR);
160+
reg_val &= ~(SCFSR_TDFE | SCFSR_TEND);
161+
uart_rcar_write_16(config, SCFSR, reg_val);
162+
}
163+
164+
static int uart_rcar_configure(const struct device *dev,
165+
const struct uart_config *cfg)
166+
{
167+
const struct uart_rcar_cfg *config = DEV_UART_CFG(dev);
168+
struct uart_rcar_data *data = DEV_UART_DATA(dev);
169+
170+
uint16_t reg_val;
171+
172+
if (cfg->parity != UART_CFG_PARITY_NONE ||
173+
cfg->stop_bits != UART_CFG_STOP_BITS_1 ||
174+
cfg->data_bits != UART_CFG_DATA_BITS_8 ||
175+
cfg->flow_ctrl != UART_CFG_FLOW_CTRL_NONE) {
176+
return -ENOTSUP;
177+
}
178+
179+
/* Disable Transmit and Receive */
180+
reg_val = uart_rcar_read_16(config, SCSCR);
181+
reg_val &= ~(SCSCR_TE | SCSCR_RE);
182+
uart_rcar_write_16(config, SCSCR, reg_val);
183+
184+
/* Emptying Transmit and Receive FIFO */
185+
reg_val = uart_rcar_read_16(config, SCFCR);
186+
reg_val |= (SCFCR_TFRST | SCFCR_RFRST);
187+
uart_rcar_write_16(config, SCFCR, reg_val);
188+
189+
/* Resetting Errors Registers */
190+
reg_val = uart_rcar_read_16(config, SCFSR);
191+
reg_val &= ~(SCFSR_ER | SCFSR_DR | SCFSR_BRK | SCFSR_RDF);
192+
uart_rcar_write_16(config, SCFSR, reg_val);
193+
194+
reg_val = uart_rcar_read_16(config, SCLSR);
195+
reg_val &= ~(SCLSR_TO | SCLSR_ORER);
196+
uart_rcar_write_16(config, SCLSR, reg_val);
197+
198+
/* Clock selection */
199+
reg_val = uart_rcar_read_16(config, SCSCR);
200+
reg_val &= ~(SCSCR_CKE1 | SCSCR_CKE0 | SCSCR_TIE | SCSCR_RIE |
201+
SCSCR_TE | SCSCR_RE | SCSCR_TOIE);
202+
uart_rcar_write_16(config, SCSCR, reg_val);
203+
204+
/* Serial Configuration (8N1) & Clock Source selection */
205+
reg_val = uart_rcar_read_16(config, SCSMR);
206+
reg_val &= ~(SCSMR_C_A | SCSMR_CHR | SCSMR_PE | SCSMR_O_E | SCSMR_STOP |
207+
SCSMR_CKS1 | SCSMR_CKS0);
208+
uart_rcar_write_16(config, SCSMR, reg_val);
209+
210+
/* Set baudrate */
211+
uart_rcar_set_baudrate(dev, cfg->baudrate);
212+
213+
/* FIFOs data count trigger configuration */
214+
reg_val = uart_rcar_read_16(config, SCFCR);
215+
reg_val &= ~(SCFCR_RTRG1 | SCFCR_RTRG0 | SCFCR_TTRG1 | SCFCR_TTRG0 |
216+
SCFCR_MCE | SCFCR_TFRST | SCFCR_RFRST);
217+
uart_rcar_write_16(config, SCFCR, reg_val);
218+
219+
/* Enable Transmit & Receive */
220+
reg_val = uart_rcar_read_16(config, SCSCR);
221+
reg_val |= (SCSCR_TE | SCSCR_RE);
222+
reg_val &= ~(SCSCR_TIE | SCSCR_RIE | SCSCR_TEIE | SCSCR_REIE |
223+
SCSCR_TOIE);
224+
uart_rcar_write_16(config, SCSCR, reg_val);
225+
226+
data->current_config = *cfg;
227+
228+
return 0;
229+
}
230+
231+
static int uart_rcar_config_get(const struct device *dev,
232+
struct uart_config *cfg)
233+
{
234+
struct uart_rcar_data *data = DEV_UART_DATA(dev);
235+
236+
*cfg = data->current_config;
237+
238+
return 0;
239+
}
240+
241+
static int uart_rcar_init(const struct device *dev)
242+
{
243+
const struct uart_rcar_cfg *config = DEV_UART_CFG(dev);
244+
struct uart_rcar_data *data = DEV_UART_DATA(dev);
245+
int ret;
246+
247+
ret = clock_control_on(config->clock_dev,
248+
(clock_control_subsys_t *)&config->mod_clk);
249+
if (ret < 0) {
250+
return ret;
251+
}
252+
253+
ret = clock_control_get_rate(config->clock_dev,
254+
(clock_control_subsys_t *)&config->bus_clk,
255+
&data->clk_rate);
256+
if (ret < 0) {
257+
return ret;
258+
}
259+
260+
return uart_rcar_configure(dev, &data->current_config);
261+
}
262+
263+
static const struct uart_driver_api uart_rcar_driver_api = {
264+
.poll_in = uart_rcar_poll_in,
265+
.poll_out = uart_rcar_poll_out,
266+
.configure = uart_rcar_configure,
267+
.config_get = uart_rcar_config_get,
268+
};
269+
270+
/* Device Instantiation */
271+
#define UART_RCAR_INIT(n) \
272+
static const struct uart_rcar_cfg uart_rcar_cfg_##n = { \
273+
.reg_addr = DT_INST_REG_ADDR(n), \
274+
.clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)), \
275+
.mod_clk.module = \
276+
DT_INST_CLOCKS_CELL_BY_IDX(n, 0, module), \
277+
.mod_clk.domain = \
278+
DT_INST_CLOCKS_CELL_BY_IDX(n, 0, domain), \
279+
.bus_clk.module = \
280+
DT_INST_CLOCKS_CELL_BY_IDX(n, 1, module), \
281+
.bus_clk.domain = \
282+
DT_INST_CLOCKS_CELL_BY_IDX(n, 1, domain), \
283+
}; \
284+
\
285+
static struct uart_rcar_data uart_rcar_data_##n = { \
286+
.current_config = { \
287+
.baudrate = DT_INST_PROP(n, current_speed), \
288+
.parity = UART_CFG_PARITY_NONE, \
289+
.stop_bits = UART_CFG_STOP_BITS_1, \
290+
.data_bits = UART_CFG_DATA_BITS_8, \
291+
.flow_ctrl = UART_CFG_FLOW_CTRL_NONE, \
292+
}, \
293+
}; \
294+
\
295+
DEVICE_DT_INST_DEFINE(n, \
296+
uart_rcar_init, \
297+
NULL, \
298+
&uart_rcar_data_##n, \
299+
&uart_rcar_cfg_##n, \
300+
PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \
301+
&uart_rcar_driver_api \
302+
); \
303+
304+
DT_INST_FOREACH_STATUS_OKAY(UART_RCAR_INIT)

0 commit comments

Comments
 (0)