]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
0b135cfc NI |
2 | /* |
3 | * SuperH SCIF device driver. | |
48ca882c | 4 | * Copyright (C) 2013 Renesas Electronics Corporation |
59088e4a | 5 | * Copyright (C) 2007,2008,2010, 2014 Nobuhiro Iwamatsu |
3f6c8e36 | 6 | * Copyright (C) 2002 - 2008 Paul Mundt |
0b135cfc NI |
7 | */ |
8 | ||
401d1c4f | 9 | #include <asm/global_data.h> |
fc83c927 | 10 | #include <asm/io.h> |
0b135cfc | 11 | #include <asm/processor.h> |
ef7ab756 PB |
12 | #include <clk.h> |
13 | #include <dm.h> | |
966caedf | 14 | #include <dm/device_compat.h> |
59088e4a | 15 | #include <dm/platform_data/serial_sh.h> |
ef7ab756 PB |
16 | #include <errno.h> |
17 | #include <linux/compiler.h> | |
c05ed00a | 18 | #include <linux/delay.h> |
966caedf | 19 | #include <reset.h> |
ef7ab756 | 20 | #include <serial.h> |
59088e4a | 21 | #include "serial_sh.h" |
0b135cfc | 22 | |
359787cf YS |
23 | DECLARE_GLOBAL_DATA_PTR; |
24 | ||
10e91cfd | 25 | #if defined(CONFIG_CPU_SH7780) |
3f6c8e36 NI |
26 | static int scif_rxfill(struct uart_port *port) |
27 | { | |
28 | return sci_in(port, SCRFDR) & 0xff; | |
29 | } | |
30 | #elif defined(CONFIG_CPU_SH7763) | |
31 | static int scif_rxfill(struct uart_port *port) | |
0b135cfc | 32 | { |
3f6c8e36 | 33 | if ((port->mapbase == 0xffe00000) || |
59088e4a | 34 | (port->mapbase == 0xffe08000)) { |
3f6c8e36 NI |
35 | /* SCIF0/1*/ |
36 | return sci_in(port, SCRFDR) & 0xff; | |
37 | } else { | |
38 | /* SCIF2 */ | |
39 | return sci_in(port, SCFDR) & SCIF2_RFDC_MASK; | |
40 | } | |
41 | } | |
3ecff1d7 | 42 | #else |
3f6c8e36 NI |
43 | static int scif_rxfill(struct uart_port *port) |
44 | { | |
45 | return sci_in(port, SCFDR) & SCIF_RFDC_MASK; | |
46 | } | |
3ecff1d7 | 47 | #endif |
3f6c8e36 | 48 | |
59088e4a | 49 | static void sh_serial_init_generic(struct uart_port *port) |
3f6c8e36 | 50 | { |
59088e4a NI |
51 | sci_out(port, SCSCR , SCSCR_INIT(port)); |
52 | sci_out(port, SCSCR , SCSCR_INIT(port)); | |
53 | sci_out(port, SCSMR, 0); | |
54 | sci_out(port, SCSMR, 0); | |
55 | sci_out(port, SCFCR, SCFCR_RFRST|SCFCR_TFRST); | |
56 | sci_in(port, SCFCR); | |
57 | sci_out(port, SCFCR, 0); | |
67180fe1 MV |
58 | #if defined(CONFIG_RZA1) |
59 | sci_out(port, SCSPTR, 0x0003); | |
60 | #endif | |
bbe36e29 | 61 | |
caf3503c | 62 | #if IS_ENABLED(CONFIG_RCAR_GEN2) || IS_ENABLED(CONFIG_RCAR_GEN3) || IS_ENABLED(CONFIG_RCAR_GEN4) |
bbe36e29 HP |
63 | if (port->type == PORT_HSCIF) |
64 | sci_out(port, HSSRR, HSSRR_SRE | HSSRR_SRCYC8); | |
caf3503c | 65 | #endif |
0b135cfc NI |
66 | } |
67 | ||
59088e4a NI |
68 | static void |
69 | sh_serial_setbrg_generic(struct uart_port *port, int clk, int baudrate) | |
7c791b3f | 70 | { |
59088e4a NI |
71 | if (port->clk_mode == EXT_CLK) { |
72 | unsigned short dl = DL_VALUE(baudrate, clk); | |
73 | sci_out(port, DL, dl); | |
89f99a62 | 74 | /* Need wait: Clock * 1/dl * 1/16 */ |
59088e4a NI |
75 | udelay((1000000 * dl * 16 / clk) * 1000 + 1); |
76 | } else { | |
77 | sci_out(port, SCBRR, SCBRR_VALUE(baudrate, clk)); | |
78 | } | |
7c791b3f TK |
79 | } |
80 | ||
59088e4a | 81 | static void handle_error(struct uart_port *port) |
0b135cfc | 82 | { |
0f924d88 PB |
83 | /* |
84 | * Most errors are cleared by resetting the relevant error bits to zero | |
85 | * in the FSR & LSR registers. For each register, a read followed by a | |
86 | * write is needed according to the relevant datasheets. | |
87 | */ | |
88 | unsigned short status = sci_in(port, SCxSR); | |
89 | sci_out(port, SCxSR, status & ~SCxSR_ERRORS(port)); | |
59088e4a NI |
90 | sci_in(port, SCLSR); |
91 | sci_out(port, SCLSR, 0x00); | |
0f924d88 PB |
92 | |
93 | /* | |
94 | * To clear framing errors, we also need to read and discard a | |
95 | * character. | |
96 | */ | |
97 | if ((port->type != PORT_SCI) && (status & SCIF_FER)) | |
98 | sci_in(port, SCxRDR); | |
59088e4a NI |
99 | } |
100 | ||
101 | static int serial_raw_putc(struct uart_port *port, const char c) | |
102 | { | |
103 | /* Tx fifo is empty */ | |
104 | if (!(sci_in(port, SCxSR) & SCxSR_TEND(port))) | |
105 | return -EAGAIN; | |
0b135cfc | 106 | |
59088e4a NI |
107 | sci_out(port, SCxTDR, c); |
108 | sci_out(port, SCxSR, sci_in(port, SCxSR) & ~SCxSR_TEND(port)); | |
109 | ||
110 | return 0; | |
0b135cfc NI |
111 | } |
112 | ||
59088e4a | 113 | static int serial_rx_fifo_level(struct uart_port *port) |
0b135cfc | 114 | { |
59088e4a | 115 | return scif_rxfill(port); |
0b135cfc NI |
116 | } |
117 | ||
59088e4a | 118 | static int sh_serial_tstc_generic(struct uart_port *port) |
0b135cfc | 119 | { |
59088e4a NI |
120 | if (sci_in(port, SCxSR) & SCIF_ERRORS) { |
121 | handle_error(port); | |
7c791b3f TK |
122 | return 0; |
123 | } | |
124 | ||
59088e4a | 125 | return serial_rx_fifo_level(port) ? 1 : 0; |
0b135cfc NI |
126 | } |
127 | ||
59088e4a | 128 | static int serial_getc_check(struct uart_port *port) |
08c5fabe | 129 | { |
0b135cfc NI |
130 | unsigned short status; |
131 | ||
59088e4a | 132 | status = sci_in(port, SCxSR); |
0b135cfc | 133 | |
3f6c8e36 | 134 | if (status & SCIF_ERRORS) |
59088e4a NI |
135 | handle_error(port); |
136 | if (sci_in(port, SCLSR) & SCxSR_ORER(port)) | |
137 | handle_error(port); | |
f5ba5c90 MV |
138 | status &= (SCIF_DR | SCxSR_RDxF(port)); |
139 | if (status) | |
140 | return status; | |
141 | return scif_rxfill(port); | |
0b135cfc NI |
142 | } |
143 | ||
59088e4a | 144 | static int sh_serial_getc_generic(struct uart_port *port) |
0b135cfc | 145 | { |
08c5fabe | 146 | unsigned short status; |
0b135cfc | 147 | char ch; |
ab09f433 | 148 | |
59088e4a NI |
149 | if (!serial_getc_check(port)) |
150 | return -EAGAIN; | |
0b135cfc | 151 | |
59088e4a NI |
152 | ch = sci_in(port, SCxRDR); |
153 | status = sci_in(port, SCxSR); | |
0b135cfc | 154 | |
59088e4a | 155 | sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); |
0b135cfc | 156 | |
3f6c8e36 | 157 | if (status & SCIF_ERRORS) |
59088e4a NI |
158 | handle_error(port); |
159 | ||
160 | if (sci_in(port, SCLSR) & SCxSR_ORER(port)) | |
161 | handle_error(port); | |
162 | ||
163 | return ch; | |
164 | } | |
165 | ||
5c44ddcb | 166 | #if CONFIG_IS_ENABLED(DM_SERIAL) |
59088e4a NI |
167 | |
168 | static int sh_serial_pending(struct udevice *dev, bool input) | |
169 | { | |
170 | struct uart_port *priv = dev_get_priv(dev); | |
171 | ||
172 | return sh_serial_tstc_generic(priv); | |
173 | } | |
174 | ||
175 | static int sh_serial_putc(struct udevice *dev, const char ch) | |
176 | { | |
177 | struct uart_port *priv = dev_get_priv(dev); | |
178 | ||
179 | return serial_raw_putc(priv, ch); | |
180 | } | |
181 | ||
182 | static int sh_serial_getc(struct udevice *dev) | |
183 | { | |
184 | struct uart_port *priv = dev_get_priv(dev); | |
185 | ||
186 | return sh_serial_getc_generic(priv); | |
187 | } | |
188 | ||
189 | static int sh_serial_setbrg(struct udevice *dev, int baudrate) | |
190 | { | |
8a8d24bd | 191 | struct sh_serial_plat *plat = dev_get_plat(dev); |
59088e4a NI |
192 | struct uart_port *priv = dev_get_priv(dev); |
193 | ||
194 | sh_serial_setbrg_generic(priv, plat->clk, baudrate); | |
195 | ||
196 | return 0; | |
197 | } | |
198 | ||
199 | static int sh_serial_probe(struct udevice *dev) | |
200 | { | |
8a8d24bd | 201 | struct sh_serial_plat *plat = dev_get_plat(dev); |
59088e4a | 202 | struct uart_port *priv = dev_get_priv(dev); |
966caedf PB |
203 | struct reset_ctl rst; |
204 | int ret; | |
59088e4a NI |
205 | |
206 | priv->membase = (unsigned char *)plat->base; | |
207 | priv->mapbase = plat->base; | |
208 | priv->type = plat->type; | |
209 | priv->clk_mode = plat->clk_mode; | |
210 | ||
966caedf PB |
211 | /* De-assert the module reset if it is defined. */ |
212 | ret = reset_get_by_index(dev, 0, &rst); | |
213 | if (!ret) { | |
214 | ret = reset_deassert(&rst); | |
215 | if (ret < 0) { | |
216 | dev_err(dev, "failed to de-assert reset line\n"); | |
217 | return ret; | |
218 | } | |
219 | } | |
220 | ||
59088e4a NI |
221 | sh_serial_init_generic(priv); |
222 | ||
223 | return 0; | |
224 | } | |
225 | ||
226 | static const struct dm_serial_ops sh_serial_ops = { | |
227 | .putc = sh_serial_putc, | |
228 | .pending = sh_serial_pending, | |
229 | .getc = sh_serial_getc, | |
230 | .setbrg = sh_serial_setbrg, | |
231 | }; | |
232 | ||
5c44ddcb | 233 | #if CONFIG_IS_ENABLED(OF_CONTROL) |
359787cf | 234 | static const struct udevice_id sh_serial_id[] ={ |
747431b9 | 235 | {.compatible = "renesas,sci", .data = PORT_SCI}, |
359787cf | 236 | {.compatible = "renesas,scif", .data = PORT_SCIF}, |
966caedf | 237 | {.compatible = "renesas,scif-r9a07g044", .data = PORT_SCIFA}, |
359787cf | 238 | {.compatible = "renesas,scifa", .data = PORT_SCIFA}, |
bbe36e29 | 239 | {.compatible = "renesas,hscif", .data = PORT_HSCIF}, |
359787cf YS |
240 | {} |
241 | }; | |
242 | ||
d1998a9f | 243 | static int sh_serial_of_to_plat(struct udevice *dev) |
359787cf | 244 | { |
8a8d24bd | 245 | struct sh_serial_plat *plat = dev_get_plat(dev); |
8171499d | 246 | struct clk sh_serial_clk; |
359787cf | 247 | fdt_addr_t addr; |
8171499d | 248 | int ret; |
359787cf | 249 | |
2548493a | 250 | addr = dev_read_addr(dev); |
c493756a | 251 | if (!addr) |
359787cf YS |
252 | return -EINVAL; |
253 | ||
254 | plat->base = addr; | |
8171499d MV |
255 | |
256 | ret = clk_get_by_name(dev, "fck", &sh_serial_clk); | |
791c174d MV |
257 | if (!ret) { |
258 | ret = clk_enable(&sh_serial_clk); | |
259 | if (!ret) | |
260 | plat->clk = clk_get_rate(&sh_serial_clk); | |
261 | } else { | |
8171499d MV |
262 | plat->clk = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), |
263 | "clock", 1); | |
791c174d | 264 | } |
8171499d | 265 | |
359787cf YS |
266 | plat->type = dev_get_driver_data(dev); |
267 | return 0; | |
268 | } | |
269 | #endif | |
270 | ||
59088e4a NI |
271 | U_BOOT_DRIVER(serial_sh) = { |
272 | .name = "serial_sh", | |
273 | .id = UCLASS_SERIAL, | |
359787cf | 274 | .of_match = of_match_ptr(sh_serial_id), |
d1998a9f | 275 | .of_to_plat = of_match_ptr(sh_serial_of_to_plat), |
8a8d24bd | 276 | .plat_auto = sizeof(struct sh_serial_plat), |
59088e4a NI |
277 | .probe = sh_serial_probe, |
278 | .ops = &sh_serial_ops, | |
46879196 | 279 | #if !CONFIG_IS_ENABLED(OF_CONTROL) |
59088e4a | 280 | .flags = DM_FLAG_PRE_RELOC, |
46879196 | 281 | #endif |
41575d8e | 282 | .priv_auto = sizeof(struct uart_port), |
59088e4a | 283 | }; |
836d1bff MV |
284 | #endif |
285 | ||
286 | #if !CONFIG_IS_ENABLED(DM_SERIAL) || IS_ENABLED(CONFIG_DEBUG_UART_SCIF) | |
59088e4a | 287 | |
836d1bff MV |
288 | #if defined(CFG_SCIF_A) |
289 | #define SCIF_BASE_PORT PORT_SCIFA | |
290 | #elif defined(CFG_SCI) | |
291 | #define SCIF_BASE_PORT PORT_SCI | |
bbe36e29 HP |
292 | #elif defined(CFG_HSCIF) |
293 | #define SCIF_BASE_PORT PORT_HSCIF | |
836d1bff MV |
294 | #else |
295 | #define SCIF_BASE_PORT PORT_SCIF | |
296 | #endif | |
297 | ||
298 | static void sh_serial_init_nodm(struct uart_port *port) | |
299 | { | |
300 | sh_serial_init_generic(port); | |
301 | serial_setbrg(); | |
302 | } | |
303 | ||
304 | static void sh_serial_putc_nondm(struct uart_port *port, const char c) | |
305 | { | |
306 | if (c == '\n') { | |
307 | while (1) { | |
308 | if (serial_raw_putc(port, '\r') != -EAGAIN) | |
309 | break; | |
310 | } | |
311 | } | |
312 | while (1) { | |
313 | if (serial_raw_putc(port, c) != -EAGAIN) | |
314 | break; | |
315 | } | |
316 | } | |
317 | #endif | |
59088e4a | 318 | |
836d1bff | 319 | #if !CONFIG_IS_ENABLED(DM_SERIAL) |
59088e4a NI |
320 | #if defined(CONFIG_CONS_SCIF0) |
321 | # define SCIF_BASE SCIF0_BASE | |
322 | #elif defined(CONFIG_CONS_SCIF1) | |
323 | # define SCIF_BASE SCIF1_BASE | |
324 | #elif defined(CONFIG_CONS_SCIF2) | |
325 | # define SCIF_BASE SCIF2_BASE | |
326 | #elif defined(CONFIG_CONS_SCIF3) | |
327 | # define SCIF_BASE SCIF3_BASE | |
328 | #elif defined(CONFIG_CONS_SCIF4) | |
329 | # define SCIF_BASE SCIF4_BASE | |
330 | #elif defined(CONFIG_CONS_SCIF5) | |
331 | # define SCIF_BASE SCIF5_BASE | |
332 | #elif defined(CONFIG_CONS_SCIF6) | |
333 | # define SCIF_BASE SCIF6_BASE | |
334 | #elif defined(CONFIG_CONS_SCIF7) | |
335 | # define SCIF_BASE SCIF7_BASE | |
451e22fa MV |
336 | #elif defined(CONFIG_CONS_SCIFA0) |
337 | # define SCIF_BASE SCIFA0_BASE | |
59088e4a NI |
338 | #else |
339 | # error "Default SCIF doesn't set....." | |
340 | #endif | |
341 | ||
59088e4a NI |
342 | static struct uart_port sh_sci = { |
343 | .membase = (unsigned char *)SCIF_BASE, | |
344 | .mapbase = SCIF_BASE, | |
345 | .type = SCIF_BASE_PORT, | |
5e12d7d0 | 346 | #ifdef CFG_SCIF_USE_EXT_CLK |
59088e4a NI |
347 | .clk_mode = EXT_CLK, |
348 | #endif | |
349 | }; | |
350 | ||
351 | static void sh_serial_setbrg(void) | |
352 | { | |
353 | DECLARE_GLOBAL_DATA_PTR; | |
354 | struct uart_port *port = &sh_sci; | |
355 | ||
356 | sh_serial_setbrg_generic(port, CONFIG_SH_SCIF_CLK_FREQ, gd->baudrate); | |
357 | } | |
358 | ||
359 | static int sh_serial_init(void) | |
360 | { | |
836d1bff | 361 | sh_serial_init_nodm(&sh_sci); |
59088e4a NI |
362 | |
363 | return 0; | |
364 | } | |
365 | ||
366 | static void sh_serial_putc(const char c) | |
367 | { | |
836d1bff | 368 | sh_serial_putc_nondm(&sh_sci, c); |
59088e4a NI |
369 | } |
370 | ||
371 | static int sh_serial_tstc(void) | |
372 | { | |
373 | struct uart_port *port = &sh_sci; | |
374 | ||
375 | return sh_serial_tstc_generic(port); | |
376 | } | |
377 | ||
378 | static int sh_serial_getc(void) | |
379 | { | |
380 | struct uart_port *port = &sh_sci; | |
381 | int ch; | |
382 | ||
383 | while (1) { | |
384 | ch = sh_serial_getc_generic(port); | |
385 | if (ch != -EAGAIN) | |
386 | break; | |
387 | } | |
0b135cfc | 388 | |
08c5fabe | 389 | return ch; |
0b135cfc | 390 | } |
8bdd7efa | 391 | |
8bdd7efa MV |
392 | static struct serial_device sh_serial_drv = { |
393 | .name = "sh_serial", | |
394 | .start = sh_serial_init, | |
395 | .stop = NULL, | |
396 | .setbrg = sh_serial_setbrg, | |
397 | .putc = sh_serial_putc, | |
ec3fd689 | 398 | .puts = default_serial_puts, |
8bdd7efa MV |
399 | .getc = sh_serial_getc, |
400 | .tstc = sh_serial_tstc, | |
401 | }; | |
402 | ||
403 | void sh_serial_initialize(void) | |
404 | { | |
405 | serial_register(&sh_serial_drv); | |
406 | } | |
407 | ||
408 | __weak struct serial_device *default_serial_console(void) | |
409 | { | |
410 | return &sh_serial_drv; | |
411 | } | |
59088e4a | 412 | #endif /* CONFIG_DM_SERIAL */ |
836d1bff MV |
413 | |
414 | #ifdef CONFIG_DEBUG_UART_SCIF | |
415 | #include <debug_uart.h> | |
416 | ||
417 | static struct uart_port debug_uart_sci = { | |
418 | .membase = (unsigned char *)CONFIG_DEBUG_UART_BASE, | |
419 | .mapbase = CONFIG_DEBUG_UART_BASE, | |
420 | .type = SCIF_BASE_PORT, | |
421 | #ifdef CFG_SCIF_USE_EXT_CLK | |
422 | .clk_mode = EXT_CLK, | |
423 | #endif | |
424 | }; | |
425 | ||
426 | static inline void _debug_uart_init(void) | |
427 | { | |
428 | sh_serial_init_nodm(&debug_uart_sci); | |
429 | } | |
430 | ||
431 | static inline void _debug_uart_putc(int c) | |
432 | { | |
433 | sh_serial_putc_nondm(&debug_uart_sci, c); | |
434 | } | |
435 | ||
436 | DEBUG_UART_FUNCS | |
437 | ||
438 | #endif |