]>
Commit | Line | Data |
---|---|---|
0b135cfc NI |
1 | /* |
2 | * SuperH SCIF device driver. | |
48ca882c | 3 | * Copyright (C) 2013 Renesas Electronics Corporation |
59088e4a | 4 | * Copyright (C) 2007,2008,2010, 2014 Nobuhiro Iwamatsu |
3f6c8e36 | 5 | * Copyright (C) 2002 - 2008 Paul Mundt |
61fb15c5 | 6 | * |
1a459660 | 7 | * SPDX-License-Identifier: GPL-2.0+ |
0b135cfc NI |
8 | */ |
9 | ||
10 | #include <common.h> | |
59088e4a NI |
11 | #include <errno.h> |
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 NI |
17 | #include <dm/platform_data/serial_sh.h> |
18 | #include "serial_sh.h" | |
0b135cfc | 19 | |
359787cf YS |
20 | DECLARE_GLOBAL_DATA_PTR; |
21 | ||
3f6c8e36 NI |
22 | #if defined(CONFIG_CPU_SH7760) || \ |
23 | defined(CONFIG_CPU_SH7780) || \ | |
24 | defined(CONFIG_CPU_SH7785) || \ | |
25 | defined(CONFIG_CPU_SH7786) | |
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 | } | |
42 | #elif defined(CONFIG_ARCH_SH7372) | |
43 | static int scif_rxfill(struct uart_port *port) | |
44 | { | |
45 | if (port->type == PORT_SCIFA) | |
46 | return sci_in(port, SCFDR) & SCIF_RFDC_MASK; | |
47 | else | |
48 | return sci_in(port, SCRFDR); | |
49 | } | |
3ecff1d7 | 50 | #else |
3f6c8e36 NI |
51 | static int scif_rxfill(struct uart_port *port) |
52 | { | |
53 | return sci_in(port, SCFDR) & SCIF_RFDC_MASK; | |
54 | } | |
3ecff1d7 | 55 | #endif |
3f6c8e36 | 56 | |
59088e4a | 57 | static void sh_serial_init_generic(struct uart_port *port) |
3f6c8e36 | 58 | { |
59088e4a NI |
59 | sci_out(port, SCSCR , SCSCR_INIT(port)); |
60 | sci_out(port, SCSCR , SCSCR_INIT(port)); | |
61 | sci_out(port, SCSMR, 0); | |
62 | sci_out(port, SCSMR, 0); | |
63 | sci_out(port, SCFCR, SCFCR_RFRST|SCFCR_TFRST); | |
64 | sci_in(port, SCFCR); | |
65 | sci_out(port, SCFCR, 0); | |
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 | { |
59088e4a NI |
83 | sci_in(port, SCxSR); |
84 | sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port)); | |
85 | sci_in(port, SCLSR); | |
86 | sci_out(port, SCLSR, 0x00); | |
87 | } | |
88 | ||
89 | static int serial_raw_putc(struct uart_port *port, const char c) | |
90 | { | |
91 | /* Tx fifo is empty */ | |
92 | if (!(sci_in(port, SCxSR) & SCxSR_TEND(port))) | |
93 | return -EAGAIN; | |
0b135cfc | 94 | |
59088e4a NI |
95 | sci_out(port, SCxTDR, c); |
96 | sci_out(port, SCxSR, sci_in(port, SCxSR) & ~SCxSR_TEND(port)); | |
97 | ||
98 | return 0; | |
0b135cfc NI |
99 | } |
100 | ||
59088e4a | 101 | static int serial_rx_fifo_level(struct uart_port *port) |
0b135cfc | 102 | { |
59088e4a | 103 | return scif_rxfill(port); |
0b135cfc NI |
104 | } |
105 | ||
59088e4a | 106 | static int sh_serial_tstc_generic(struct uart_port *port) |
0b135cfc | 107 | { |
59088e4a NI |
108 | if (sci_in(port, SCxSR) & SCIF_ERRORS) { |
109 | handle_error(port); | |
7c791b3f TK |
110 | return 0; |
111 | } | |
112 | ||
59088e4a | 113 | return serial_rx_fifo_level(port) ? 1 : 0; |
0b135cfc NI |
114 | } |
115 | ||
59088e4a | 116 | static int serial_getc_check(struct uart_port *port) |
08c5fabe | 117 | { |
0b135cfc NI |
118 | unsigned short status; |
119 | ||
59088e4a | 120 | status = sci_in(port, SCxSR); |
0b135cfc | 121 | |
3f6c8e36 | 122 | if (status & SCIF_ERRORS) |
59088e4a NI |
123 | handle_error(port); |
124 | if (sci_in(port, SCLSR) & SCxSR_ORER(port)) | |
125 | handle_error(port); | |
126 | return status & (SCIF_DR | SCxSR_RDxF(port)); | |
0b135cfc NI |
127 | } |
128 | ||
59088e4a | 129 | static int sh_serial_getc_generic(struct uart_port *port) |
0b135cfc | 130 | { |
08c5fabe | 131 | unsigned short status; |
0b135cfc | 132 | char ch; |
ab09f433 | 133 | |
59088e4a NI |
134 | if (!serial_getc_check(port)) |
135 | return -EAGAIN; | |
0b135cfc | 136 | |
59088e4a NI |
137 | ch = sci_in(port, SCxRDR); |
138 | status = sci_in(port, SCxSR); | |
0b135cfc | 139 | |
59088e4a | 140 | sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); |
0b135cfc | 141 | |
3f6c8e36 | 142 | if (status & SCIF_ERRORS) |
59088e4a NI |
143 | handle_error(port); |
144 | ||
145 | if (sci_in(port, SCLSR) & SCxSR_ORER(port)) | |
146 | handle_error(port); | |
147 | ||
148 | return ch; | |
149 | } | |
150 | ||
151 | #ifdef CONFIG_DM_SERIAL | |
152 | ||
153 | static int sh_serial_pending(struct udevice *dev, bool input) | |
154 | { | |
155 | struct uart_port *priv = dev_get_priv(dev); | |
156 | ||
157 | return sh_serial_tstc_generic(priv); | |
158 | } | |
159 | ||
160 | static int sh_serial_putc(struct udevice *dev, const char ch) | |
161 | { | |
162 | struct uart_port *priv = dev_get_priv(dev); | |
163 | ||
164 | return serial_raw_putc(priv, ch); | |
165 | } | |
166 | ||
167 | static int sh_serial_getc(struct udevice *dev) | |
168 | { | |
169 | struct uart_port *priv = dev_get_priv(dev); | |
170 | ||
171 | return sh_serial_getc_generic(priv); | |
172 | } | |
173 | ||
174 | static int sh_serial_setbrg(struct udevice *dev, int baudrate) | |
175 | { | |
176 | struct sh_serial_platdata *plat = dev_get_platdata(dev); | |
177 | struct uart_port *priv = dev_get_priv(dev); | |
178 | ||
179 | sh_serial_setbrg_generic(priv, plat->clk, baudrate); | |
180 | ||
181 | return 0; | |
182 | } | |
183 | ||
184 | static int sh_serial_probe(struct udevice *dev) | |
185 | { | |
186 | struct sh_serial_platdata *plat = dev_get_platdata(dev); | |
187 | struct uart_port *priv = dev_get_priv(dev); | |
188 | ||
189 | priv->membase = (unsigned char *)plat->base; | |
190 | priv->mapbase = plat->base; | |
191 | priv->type = plat->type; | |
192 | priv->clk_mode = plat->clk_mode; | |
193 | ||
194 | sh_serial_init_generic(priv); | |
195 | ||
196 | return 0; | |
197 | } | |
198 | ||
199 | static const struct dm_serial_ops sh_serial_ops = { | |
200 | .putc = sh_serial_putc, | |
201 | .pending = sh_serial_pending, | |
202 | .getc = sh_serial_getc, | |
203 | .setbrg = sh_serial_setbrg, | |
204 | }; | |
205 | ||
359787cf YS |
206 | #ifdef CONFIG_OF_CONTROL |
207 | static const struct udevice_id sh_serial_id[] ={ | |
747431b9 | 208 | {.compatible = "renesas,sci", .data = PORT_SCI}, |
359787cf YS |
209 | {.compatible = "renesas,scif", .data = PORT_SCIF}, |
210 | {.compatible = "renesas,scifa", .data = PORT_SCIFA}, | |
211 | {} | |
212 | }; | |
213 | ||
214 | static int sh_serial_ofdata_to_platdata(struct udevice *dev) | |
215 | { | |
216 | struct sh_serial_platdata *plat = dev_get_platdata(dev); | |
217 | fdt_addr_t addr; | |
218 | ||
e160f7d4 | 219 | addr = fdtdec_get_addr(gd->fdt_blob, dev_of_offset(dev), "reg"); |
359787cf YS |
220 | if (addr == FDT_ADDR_T_NONE) |
221 | return -EINVAL; | |
222 | ||
223 | plat->base = addr; | |
e160f7d4 SG |
224 | plat->clk = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "clock", |
225 | 1); | |
359787cf YS |
226 | plat->type = dev_get_driver_data(dev); |
227 | return 0; | |
228 | } | |
229 | #endif | |
230 | ||
59088e4a NI |
231 | U_BOOT_DRIVER(serial_sh) = { |
232 | .name = "serial_sh", | |
233 | .id = UCLASS_SERIAL, | |
359787cf YS |
234 | .of_match = of_match_ptr(sh_serial_id), |
235 | .ofdata_to_platdata = of_match_ptr(sh_serial_ofdata_to_platdata), | |
236 | .platdata_auto_alloc_size = sizeof(struct sh_serial_platdata), | |
59088e4a NI |
237 | .probe = sh_serial_probe, |
238 | .ops = &sh_serial_ops, | |
239 | .flags = DM_FLAG_PRE_RELOC, | |
240 | .priv_auto_alloc_size = sizeof(struct uart_port), | |
241 | }; | |
242 | ||
243 | #else /* CONFIG_DM_SERIAL */ | |
244 | ||
245 | #if defined(CONFIG_CONS_SCIF0) | |
246 | # define SCIF_BASE SCIF0_BASE | |
247 | #elif defined(CONFIG_CONS_SCIF1) | |
248 | # define SCIF_BASE SCIF1_BASE | |
249 | #elif defined(CONFIG_CONS_SCIF2) | |
250 | # define SCIF_BASE SCIF2_BASE | |
251 | #elif defined(CONFIG_CONS_SCIF3) | |
252 | # define SCIF_BASE SCIF3_BASE | |
253 | #elif defined(CONFIG_CONS_SCIF4) | |
254 | # define SCIF_BASE SCIF4_BASE | |
255 | #elif defined(CONFIG_CONS_SCIF5) | |
256 | # define SCIF_BASE SCIF5_BASE | |
257 | #elif defined(CONFIG_CONS_SCIF6) | |
258 | # define SCIF_BASE SCIF6_BASE | |
259 | #elif defined(CONFIG_CONS_SCIF7) | |
260 | # define SCIF_BASE SCIF7_BASE | |
261 | #else | |
262 | # error "Default SCIF doesn't set....." | |
263 | #endif | |
264 | ||
265 | #if defined(CONFIG_SCIF_A) | |
266 | #define SCIF_BASE_PORT PORT_SCIFA | |
747431b9 YS |
267 | #elif defined(CONFIG_SCI) |
268 | #define SCIF_BASE_PORT PORT_SCI | |
59088e4a NI |
269 | #else |
270 | #define SCIF_BASE_PORT PORT_SCIF | |
271 | #endif | |
272 | ||
273 | static struct uart_port sh_sci = { | |
274 | .membase = (unsigned char *)SCIF_BASE, | |
275 | .mapbase = SCIF_BASE, | |
276 | .type = SCIF_BASE_PORT, | |
277 | #ifdef CONFIG_SCIF_USE_EXT_CLK | |
278 | .clk_mode = EXT_CLK, | |
279 | #endif | |
280 | }; | |
281 | ||
282 | static void sh_serial_setbrg(void) | |
283 | { | |
284 | DECLARE_GLOBAL_DATA_PTR; | |
285 | struct uart_port *port = &sh_sci; | |
286 | ||
287 | sh_serial_setbrg_generic(port, CONFIG_SH_SCIF_CLK_FREQ, gd->baudrate); | |
288 | } | |
289 | ||
290 | static int sh_serial_init(void) | |
291 | { | |
292 | struct uart_port *port = &sh_sci; | |
293 | ||
294 | sh_serial_init_generic(port); | |
295 | serial_setbrg(); | |
296 | ||
297 | return 0; | |
298 | } | |
299 | ||
300 | static void sh_serial_putc(const char c) | |
301 | { | |
302 | struct uart_port *port = &sh_sci; | |
303 | ||
304 | if (c == '\n') { | |
305 | while (1) { | |
306 | if (serial_raw_putc(port, '\r') != -EAGAIN) | |
307 | break; | |
308 | } | |
309 | } | |
310 | while (1) { | |
311 | if (serial_raw_putc(port, c) != -EAGAIN) | |
312 | break; | |
313 | } | |
314 | } | |
315 | ||
316 | static int sh_serial_tstc(void) | |
317 | { | |
318 | struct uart_port *port = &sh_sci; | |
319 | ||
320 | return sh_serial_tstc_generic(port); | |
321 | } | |
322 | ||
323 | static int sh_serial_getc(void) | |
324 | { | |
325 | struct uart_port *port = &sh_sci; | |
326 | int ch; | |
327 | ||
328 | while (1) { | |
329 | ch = sh_serial_getc_generic(port); | |
330 | if (ch != -EAGAIN) | |
331 | break; | |
332 | } | |
0b135cfc | 333 | |
08c5fabe | 334 | return ch; |
0b135cfc | 335 | } |
8bdd7efa | 336 | |
8bdd7efa MV |
337 | static struct serial_device sh_serial_drv = { |
338 | .name = "sh_serial", | |
339 | .start = sh_serial_init, | |
340 | .stop = NULL, | |
341 | .setbrg = sh_serial_setbrg, | |
342 | .putc = sh_serial_putc, | |
ec3fd689 | 343 | .puts = default_serial_puts, |
8bdd7efa MV |
344 | .getc = sh_serial_getc, |
345 | .tstc = sh_serial_tstc, | |
346 | }; | |
347 | ||
348 | void sh_serial_initialize(void) | |
349 | { | |
350 | serial_register(&sh_serial_drv); | |
351 | } | |
352 | ||
353 | __weak struct serial_device *default_serial_console(void) | |
354 | { | |
355 | return &sh_serial_drv; | |
356 | } | |
59088e4a | 357 | #endif /* CONFIG_DM_SERIAL */ |