]>
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 | ||
9 | #include <common.h> | |
59088e4a | 10 | #include <errno.h> |
8171499d | 11 | #include <clk.h> |
59088e4a | 12 | #include <dm.h> |
fc83c927 | 13 | #include <asm/io.h> |
0b135cfc | 14 | #include <asm/processor.h> |
8bdd7efa MV |
15 | #include <serial.h> |
16 | #include <linux/compiler.h> | |
59088e4a | 17 | #include <dm/platform_data/serial_sh.h> |
c05ed00a | 18 | #include <linux/delay.h> |
59088e4a | 19 | #include "serial_sh.h" |
0b135cfc | 20 | |
359787cf YS |
21 | DECLARE_GLOBAL_DATA_PTR; |
22 | ||
10e91cfd | 23 | #if defined(CONFIG_CPU_SH7780) |
3f6c8e36 NI |
24 | static int scif_rxfill(struct uart_port *port) |
25 | { | |
26 | return sci_in(port, SCRFDR) & 0xff; | |
27 | } | |
28 | #elif defined(CONFIG_CPU_SH7763) | |
29 | static int scif_rxfill(struct uart_port *port) | |
0b135cfc | 30 | { |
3f6c8e36 | 31 | if ((port->mapbase == 0xffe00000) || |
59088e4a | 32 | (port->mapbase == 0xffe08000)) { |
3f6c8e36 NI |
33 | /* SCIF0/1*/ |
34 | return sci_in(port, SCRFDR) & 0xff; | |
35 | } else { | |
36 | /* SCIF2 */ | |
37 | return sci_in(port, SCFDR) & SCIF2_RFDC_MASK; | |
38 | } | |
39 | } | |
3ecff1d7 | 40 | #else |
3f6c8e36 NI |
41 | static int scif_rxfill(struct uart_port *port) |
42 | { | |
43 | return sci_in(port, SCFDR) & SCIF_RFDC_MASK; | |
44 | } | |
3ecff1d7 | 45 | #endif |
3f6c8e36 | 46 | |
59088e4a | 47 | static void sh_serial_init_generic(struct uart_port *port) |
3f6c8e36 | 48 | { |
59088e4a NI |
49 | sci_out(port, SCSCR , SCSCR_INIT(port)); |
50 | sci_out(port, SCSCR , SCSCR_INIT(port)); | |
51 | sci_out(port, SCSMR, 0); | |
52 | sci_out(port, SCSMR, 0); | |
53 | sci_out(port, SCFCR, SCFCR_RFRST|SCFCR_TFRST); | |
54 | sci_in(port, SCFCR); | |
55 | sci_out(port, SCFCR, 0); | |
67180fe1 MV |
56 | #if defined(CONFIG_RZA1) |
57 | sci_out(port, SCSPTR, 0x0003); | |
58 | #endif | |
0b135cfc NI |
59 | } |
60 | ||
59088e4a NI |
61 | static void |
62 | sh_serial_setbrg_generic(struct uart_port *port, int clk, int baudrate) | |
7c791b3f | 63 | { |
59088e4a NI |
64 | if (port->clk_mode == EXT_CLK) { |
65 | unsigned short dl = DL_VALUE(baudrate, clk); | |
66 | sci_out(port, DL, dl); | |
89f99a62 | 67 | /* Need wait: Clock * 1/dl * 1/16 */ |
59088e4a NI |
68 | udelay((1000000 * dl * 16 / clk) * 1000 + 1); |
69 | } else { | |
70 | sci_out(port, SCBRR, SCBRR_VALUE(baudrate, clk)); | |
71 | } | |
7c791b3f TK |
72 | } |
73 | ||
59088e4a | 74 | static void handle_error(struct uart_port *port) |
0b135cfc | 75 | { |
59088e4a NI |
76 | sci_in(port, SCxSR); |
77 | sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port)); | |
78 | sci_in(port, SCLSR); | |
79 | sci_out(port, SCLSR, 0x00); | |
80 | } | |
81 | ||
82 | static int serial_raw_putc(struct uart_port *port, const char c) | |
83 | { | |
84 | /* Tx fifo is empty */ | |
85 | if (!(sci_in(port, SCxSR) & SCxSR_TEND(port))) | |
86 | return -EAGAIN; | |
0b135cfc | 87 | |
59088e4a NI |
88 | sci_out(port, SCxTDR, c); |
89 | sci_out(port, SCxSR, sci_in(port, SCxSR) & ~SCxSR_TEND(port)); | |
90 | ||
91 | return 0; | |
0b135cfc NI |
92 | } |
93 | ||
59088e4a | 94 | static int serial_rx_fifo_level(struct uart_port *port) |
0b135cfc | 95 | { |
59088e4a | 96 | return scif_rxfill(port); |
0b135cfc NI |
97 | } |
98 | ||
59088e4a | 99 | static int sh_serial_tstc_generic(struct uart_port *port) |
0b135cfc | 100 | { |
59088e4a NI |
101 | if (sci_in(port, SCxSR) & SCIF_ERRORS) { |
102 | handle_error(port); | |
7c791b3f TK |
103 | return 0; |
104 | } | |
105 | ||
59088e4a | 106 | return serial_rx_fifo_level(port) ? 1 : 0; |
0b135cfc NI |
107 | } |
108 | ||
59088e4a | 109 | static int serial_getc_check(struct uart_port *port) |
08c5fabe | 110 | { |
0b135cfc NI |
111 | unsigned short status; |
112 | ||
59088e4a | 113 | status = sci_in(port, SCxSR); |
0b135cfc | 114 | |
3f6c8e36 | 115 | if (status & SCIF_ERRORS) |
59088e4a NI |
116 | handle_error(port); |
117 | if (sci_in(port, SCLSR) & SCxSR_ORER(port)) | |
118 | handle_error(port); | |
119 | return status & (SCIF_DR | SCxSR_RDxF(port)); | |
0b135cfc NI |
120 | } |
121 | ||
59088e4a | 122 | static int sh_serial_getc_generic(struct uart_port *port) |
0b135cfc | 123 | { |
08c5fabe | 124 | unsigned short status; |
0b135cfc | 125 | char ch; |
ab09f433 | 126 | |
59088e4a NI |
127 | if (!serial_getc_check(port)) |
128 | return -EAGAIN; | |
0b135cfc | 129 | |
59088e4a NI |
130 | ch = sci_in(port, SCxRDR); |
131 | status = sci_in(port, SCxSR); | |
0b135cfc | 132 | |
59088e4a | 133 | sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); |
0b135cfc | 134 | |
3f6c8e36 | 135 | if (status & SCIF_ERRORS) |
59088e4a NI |
136 | handle_error(port); |
137 | ||
138 | if (sci_in(port, SCLSR) & SCxSR_ORER(port)) | |
139 | handle_error(port); | |
140 | ||
141 | return ch; | |
142 | } | |
143 | ||
5c44ddcb | 144 | #if CONFIG_IS_ENABLED(DM_SERIAL) |
59088e4a NI |
145 | |
146 | static int sh_serial_pending(struct udevice *dev, bool input) | |
147 | { | |
148 | struct uart_port *priv = dev_get_priv(dev); | |
149 | ||
150 | return sh_serial_tstc_generic(priv); | |
151 | } | |
152 | ||
153 | static int sh_serial_putc(struct udevice *dev, const char ch) | |
154 | { | |
155 | struct uart_port *priv = dev_get_priv(dev); | |
156 | ||
157 | return serial_raw_putc(priv, ch); | |
158 | } | |
159 | ||
160 | static int sh_serial_getc(struct udevice *dev) | |
161 | { | |
162 | struct uart_port *priv = dev_get_priv(dev); | |
163 | ||
164 | return sh_serial_getc_generic(priv); | |
165 | } | |
166 | ||
167 | static int sh_serial_setbrg(struct udevice *dev, int baudrate) | |
168 | { | |
169 | struct sh_serial_platdata *plat = dev_get_platdata(dev); | |
170 | struct uart_port *priv = dev_get_priv(dev); | |
171 | ||
172 | sh_serial_setbrg_generic(priv, plat->clk, baudrate); | |
173 | ||
174 | return 0; | |
175 | } | |
176 | ||
177 | static int sh_serial_probe(struct udevice *dev) | |
178 | { | |
179 | struct sh_serial_platdata *plat = dev_get_platdata(dev); | |
180 | struct uart_port *priv = dev_get_priv(dev); | |
181 | ||
182 | priv->membase = (unsigned char *)plat->base; | |
183 | priv->mapbase = plat->base; | |
184 | priv->type = plat->type; | |
185 | priv->clk_mode = plat->clk_mode; | |
186 | ||
187 | sh_serial_init_generic(priv); | |
188 | ||
189 | return 0; | |
190 | } | |
191 | ||
192 | static const struct dm_serial_ops sh_serial_ops = { | |
193 | .putc = sh_serial_putc, | |
194 | .pending = sh_serial_pending, | |
195 | .getc = sh_serial_getc, | |
196 | .setbrg = sh_serial_setbrg, | |
197 | }; | |
198 | ||
5c44ddcb | 199 | #if CONFIG_IS_ENABLED(OF_CONTROL) |
359787cf | 200 | static const struct udevice_id sh_serial_id[] ={ |
747431b9 | 201 | {.compatible = "renesas,sci", .data = PORT_SCI}, |
359787cf YS |
202 | {.compatible = "renesas,scif", .data = PORT_SCIF}, |
203 | {.compatible = "renesas,scifa", .data = PORT_SCIFA}, | |
204 | {} | |
205 | }; | |
206 | ||
207 | static int sh_serial_ofdata_to_platdata(struct udevice *dev) | |
208 | { | |
209 | struct sh_serial_platdata *plat = dev_get_platdata(dev); | |
8171499d | 210 | struct clk sh_serial_clk; |
359787cf | 211 | fdt_addr_t addr; |
8171499d | 212 | int ret; |
359787cf | 213 | |
2548493a | 214 | addr = dev_read_addr(dev); |
c493756a | 215 | if (!addr) |
359787cf YS |
216 | return -EINVAL; |
217 | ||
218 | plat->base = addr; | |
8171499d MV |
219 | |
220 | ret = clk_get_by_name(dev, "fck", &sh_serial_clk); | |
791c174d MV |
221 | if (!ret) { |
222 | ret = clk_enable(&sh_serial_clk); | |
223 | if (!ret) | |
224 | plat->clk = clk_get_rate(&sh_serial_clk); | |
225 | } else { | |
8171499d MV |
226 | plat->clk = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), |
227 | "clock", 1); | |
791c174d | 228 | } |
8171499d | 229 | |
359787cf YS |
230 | plat->type = dev_get_driver_data(dev); |
231 | return 0; | |
232 | } | |
233 | #endif | |
234 | ||
59088e4a NI |
235 | U_BOOT_DRIVER(serial_sh) = { |
236 | .name = "serial_sh", | |
237 | .id = UCLASS_SERIAL, | |
359787cf YS |
238 | .of_match = of_match_ptr(sh_serial_id), |
239 | .ofdata_to_platdata = of_match_ptr(sh_serial_ofdata_to_platdata), | |
240 | .platdata_auto_alloc_size = sizeof(struct sh_serial_platdata), | |
59088e4a NI |
241 | .probe = sh_serial_probe, |
242 | .ops = &sh_serial_ops, | |
46879196 | 243 | #if !CONFIG_IS_ENABLED(OF_CONTROL) |
59088e4a | 244 | .flags = DM_FLAG_PRE_RELOC, |
46879196 | 245 | #endif |
59088e4a NI |
246 | .priv_auto_alloc_size = sizeof(struct uart_port), |
247 | }; | |
248 | ||
249 | #else /* CONFIG_DM_SERIAL */ | |
250 | ||
251 | #if defined(CONFIG_CONS_SCIF0) | |
252 | # define SCIF_BASE SCIF0_BASE | |
253 | #elif defined(CONFIG_CONS_SCIF1) | |
254 | # define SCIF_BASE SCIF1_BASE | |
255 | #elif defined(CONFIG_CONS_SCIF2) | |
256 | # define SCIF_BASE SCIF2_BASE | |
257 | #elif defined(CONFIG_CONS_SCIF3) | |
258 | # define SCIF_BASE SCIF3_BASE | |
259 | #elif defined(CONFIG_CONS_SCIF4) | |
260 | # define SCIF_BASE SCIF4_BASE | |
261 | #elif defined(CONFIG_CONS_SCIF5) | |
262 | # define SCIF_BASE SCIF5_BASE | |
263 | #elif defined(CONFIG_CONS_SCIF6) | |
264 | # define SCIF_BASE SCIF6_BASE | |
265 | #elif defined(CONFIG_CONS_SCIF7) | |
266 | # define SCIF_BASE SCIF7_BASE | |
451e22fa MV |
267 | #elif defined(CONFIG_CONS_SCIFA0) |
268 | # define SCIF_BASE SCIFA0_BASE | |
59088e4a NI |
269 | #else |
270 | # error "Default SCIF doesn't set....." | |
271 | #endif | |
272 | ||
273 | #if defined(CONFIG_SCIF_A) | |
274 | #define SCIF_BASE_PORT PORT_SCIFA | |
747431b9 YS |
275 | #elif defined(CONFIG_SCI) |
276 | #define SCIF_BASE_PORT PORT_SCI | |
59088e4a NI |
277 | #else |
278 | #define SCIF_BASE_PORT PORT_SCIF | |
279 | #endif | |
280 | ||
281 | static struct uart_port sh_sci = { | |
282 | .membase = (unsigned char *)SCIF_BASE, | |
283 | .mapbase = SCIF_BASE, | |
284 | .type = SCIF_BASE_PORT, | |
285 | #ifdef CONFIG_SCIF_USE_EXT_CLK | |
286 | .clk_mode = EXT_CLK, | |
287 | #endif | |
288 | }; | |
289 | ||
290 | static void sh_serial_setbrg(void) | |
291 | { | |
292 | DECLARE_GLOBAL_DATA_PTR; | |
293 | struct uart_port *port = &sh_sci; | |
294 | ||
295 | sh_serial_setbrg_generic(port, CONFIG_SH_SCIF_CLK_FREQ, gd->baudrate); | |
296 | } | |
297 | ||
298 | static int sh_serial_init(void) | |
299 | { | |
300 | struct uart_port *port = &sh_sci; | |
301 | ||
302 | sh_serial_init_generic(port); | |
303 | serial_setbrg(); | |
304 | ||
305 | return 0; | |
306 | } | |
307 | ||
308 | static void sh_serial_putc(const char c) | |
309 | { | |
310 | struct uart_port *port = &sh_sci; | |
311 | ||
312 | if (c == '\n') { | |
313 | while (1) { | |
314 | if (serial_raw_putc(port, '\r') != -EAGAIN) | |
315 | break; | |
316 | } | |
317 | } | |
318 | while (1) { | |
319 | if (serial_raw_putc(port, c) != -EAGAIN) | |
320 | break; | |
321 | } | |
322 | } | |
323 | ||
324 | static int sh_serial_tstc(void) | |
325 | { | |
326 | struct uart_port *port = &sh_sci; | |
327 | ||
328 | return sh_serial_tstc_generic(port); | |
329 | } | |
330 | ||
331 | static int sh_serial_getc(void) | |
332 | { | |
333 | struct uart_port *port = &sh_sci; | |
334 | int ch; | |
335 | ||
336 | while (1) { | |
337 | ch = sh_serial_getc_generic(port); | |
338 | if (ch != -EAGAIN) | |
339 | break; | |
340 | } | |
0b135cfc | 341 | |
08c5fabe | 342 | return ch; |
0b135cfc | 343 | } |
8bdd7efa | 344 | |
8bdd7efa MV |
345 | static struct serial_device sh_serial_drv = { |
346 | .name = "sh_serial", | |
347 | .start = sh_serial_init, | |
348 | .stop = NULL, | |
349 | .setbrg = sh_serial_setbrg, | |
350 | .putc = sh_serial_putc, | |
ec3fd689 | 351 | .puts = default_serial_puts, |
8bdd7efa MV |
352 | .getc = sh_serial_getc, |
353 | .tstc = sh_serial_tstc, | |
354 | }; | |
355 | ||
356 | void sh_serial_initialize(void) | |
357 | { | |
358 | serial_register(&sh_serial_drv); | |
359 | } | |
360 | ||
361 | __weak struct serial_device *default_serial_console(void) | |
362 | { | |
363 | return &sh_serial_drv; | |
364 | } | |
59088e4a | 365 | #endif /* CONFIG_DM_SERIAL */ |