blob: 3641c9f83408edc038503a50c621dbcb2dd2fb92 [file] [log] [blame]
Nobuhiro Iwamatsu970dc332007-05-13 20:58:00 +09001/*
2 * SuperH SCIF device driver.
Nobuhiro Iwamatsu788b73f2013-07-23 13:58:20 +09003 * Copyright (C) 2013 Renesas Electronics Corporation
Nobuhiro Iwamatsu6d020352015-02-12 13:48:04 +09004 * Copyright (C) 2007,2008,2010, 2014 Nobuhiro Iwamatsu
Nobuhiro Iwamatsua5579ca2010-10-26 03:55:15 +09005 * Copyright (C) 2002 - 2008 Paul Mundt
Wolfgang Denk0a5c2142007-12-27 01:52:50 +01006 *
Wolfgang Denkd79de1d2013-07-08 09:37:19 +02007 * SPDX-License-Identifier: GPL-2.0+
Nobuhiro Iwamatsu970dc332007-05-13 20:58:00 +09008 */
9
10#include <common.h>
Nobuhiro Iwamatsu6d020352015-02-12 13:48:04 +090011#include <errno.h>
12#include <dm.h>
Jean-Christophe PLAGNIOL-VILLARDb27a8e32009-01-11 16:35:16 +010013#include <asm/io.h>
Nobuhiro Iwamatsu970dc332007-05-13 20:58:00 +090014#include <asm/processor.h>
Marek Vasut904d3d72012-09-14 22:40:08 +020015#include <serial.h>
16#include <linux/compiler.h>
Nobuhiro Iwamatsu6d020352015-02-12 13:48:04 +090017#include <dm/platform_data/serial_sh.h>
18#include "serial_sh.h"
Nobuhiro Iwamatsu970dc332007-05-13 20:58:00 +090019
Nobuhiro Iwamatsua5579ca2010-10-26 03:55:15 +090020#if defined(CONFIG_CPU_SH7760) || \
21 defined(CONFIG_CPU_SH7780) || \
22 defined(CONFIG_CPU_SH7785) || \
23 defined(CONFIG_CPU_SH7786)
24static int scif_rxfill(struct uart_port *port)
Nobuhiro Iwamatsu970dc332007-05-13 20:58:00 +090025{
Nobuhiro Iwamatsua5579ca2010-10-26 03:55:15 +090026 return sci_in(port, SCRFDR) & 0xff;
27}
28#elif defined(CONFIG_CPU_SH7763)
29static int scif_rxfill(struct uart_port *port)
30{
31 if ((port->mapbase == 0xffe00000) ||
Nobuhiro Iwamatsu6d020352015-02-12 13:48:04 +090032 (port->mapbase == 0xffe08000)) {
Nobuhiro Iwamatsua5579ca2010-10-26 03:55:15 +090033 /* SCIF0/1*/
34 return sci_in(port, SCRFDR) & 0xff;
35 } else {
36 /* SCIF2 */
37 return sci_in(port, SCFDR) & SCIF2_RFDC_MASK;
38 }
39}
40#elif defined(CONFIG_ARCH_SH7372)
41static int scif_rxfill(struct uart_port *port)
42{
43 if (port->type == PORT_SCIFA)
44 return sci_in(port, SCFDR) & SCIF_RFDC_MASK;
45 else
46 return sci_in(port, SCRFDR);
47}
Nobuhiro Iwamatsu1b36beb2008-03-06 14:05:53 +090048#else
Nobuhiro Iwamatsua5579ca2010-10-26 03:55:15 +090049static int scif_rxfill(struct uart_port *port)
50{
51 return sci_in(port, SCFDR) & SCIF_RFDC_MASK;
52}
Nobuhiro Iwamatsu1b36beb2008-03-06 14:05:53 +090053#endif
Nobuhiro Iwamatsua5579ca2010-10-26 03:55:15 +090054
Nobuhiro Iwamatsu6d020352015-02-12 13:48:04 +090055static void sh_serial_init_generic(struct uart_port *port)
Nobuhiro Iwamatsua5579ca2010-10-26 03:55:15 +090056{
Nobuhiro Iwamatsu6d020352015-02-12 13:48:04 +090057 sci_out(port, SCSCR , SCSCR_INIT(port));
58 sci_out(port, SCSCR , SCSCR_INIT(port));
59 sci_out(port, SCSMR, 0);
60 sci_out(port, SCSMR, 0);
61 sci_out(port, SCFCR, SCFCR_RFRST|SCFCR_TFRST);
62 sci_in(port, SCFCR);
63 sci_out(port, SCFCR, 0);
Nobuhiro Iwamatsu970dc332007-05-13 20:58:00 +090064}
65
Nobuhiro Iwamatsu6d020352015-02-12 13:48:04 +090066static void
67sh_serial_setbrg_generic(struct uart_port *port, int clk, int baudrate)
Tetsuyuki Kobayashi5d2b5a22012-11-19 21:37:38 +000068{
Nobuhiro Iwamatsu6d020352015-02-12 13:48:04 +090069 if (port->clk_mode == EXT_CLK) {
70 unsigned short dl = DL_VALUE(baudrate, clk);
71 sci_out(port, DL, dl);
72 /* Need wait: Clock * 1/dl × 1/16 */
73 udelay((1000000 * dl * 16 / clk) * 1000 + 1);
74 } else {
75 sci_out(port, SCBRR, SCBRR_VALUE(baudrate, clk));
76 }
Tetsuyuki Kobayashi5d2b5a22012-11-19 21:37:38 +000077}
78
Nobuhiro Iwamatsu6d020352015-02-12 13:48:04 +090079static void handle_error(struct uart_port *port)
Nobuhiro Iwamatsu970dc332007-05-13 20:58:00 +090080{
Nobuhiro Iwamatsu6d020352015-02-12 13:48:04 +090081 sci_in(port, SCxSR);
82 sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port));
83 sci_in(port, SCLSR);
84 sci_out(port, SCLSR, 0x00);
85}
86
87static int serial_raw_putc(struct uart_port *port, const char c)
88{
89 /* Tx fifo is empty */
90 if (!(sci_in(port, SCxSR) & SCxSR_TEND(port)))
91 return -EAGAIN;
Nobuhiro Iwamatsu970dc332007-05-13 20:58:00 +090092
Nobuhiro Iwamatsu6d020352015-02-12 13:48:04 +090093 sci_out(port, SCxTDR, c);
94 sci_out(port, SCxSR, sci_in(port, SCxSR) & ~SCxSR_TEND(port));
95
96 return 0;
Nobuhiro Iwamatsu970dc332007-05-13 20:58:00 +090097}
98
Nobuhiro Iwamatsu6d020352015-02-12 13:48:04 +090099static int serial_rx_fifo_level(struct uart_port *port)
Nobuhiro Iwamatsu970dc332007-05-13 20:58:00 +0900100{
Nobuhiro Iwamatsu6d020352015-02-12 13:48:04 +0900101 return scif_rxfill(port);
Nobuhiro Iwamatsu970dc332007-05-13 20:58:00 +0900102}
103
Nobuhiro Iwamatsu6d020352015-02-12 13:48:04 +0900104static int sh_serial_tstc_generic(struct uart_port *port)
Nobuhiro Iwamatsu970dc332007-05-13 20:58:00 +0900105{
Nobuhiro Iwamatsu6d020352015-02-12 13:48:04 +0900106 if (sci_in(port, SCxSR) & SCIF_ERRORS) {
107 handle_error(port);
Tetsuyuki Kobayashi5d2b5a22012-11-19 21:37:38 +0000108 return 0;
109 }
110
Nobuhiro Iwamatsu6d020352015-02-12 13:48:04 +0900111 return serial_rx_fifo_level(port) ? 1 : 0;
Nobuhiro Iwamatsu970dc332007-05-13 20:58:00 +0900112}
113
Nobuhiro Iwamatsu6d020352015-02-12 13:48:04 +0900114static int serial_getc_check(struct uart_port *port)
Nobuhiro Iwamatsu6564b1a2008-06-06 16:16:08 +0900115{
Nobuhiro Iwamatsu970dc332007-05-13 20:58:00 +0900116 unsigned short status;
117
Nobuhiro Iwamatsu6d020352015-02-12 13:48:04 +0900118 status = sci_in(port, SCxSR);
Nobuhiro Iwamatsu970dc332007-05-13 20:58:00 +0900119
Nobuhiro Iwamatsua5579ca2010-10-26 03:55:15 +0900120 if (status & SCIF_ERRORS)
Nobuhiro Iwamatsu6d020352015-02-12 13:48:04 +0900121 handle_error(port);
122 if (sci_in(port, SCLSR) & SCxSR_ORER(port))
123 handle_error(port);
124 return status & (SCIF_DR | SCxSR_RDxF(port));
Nobuhiro Iwamatsu970dc332007-05-13 20:58:00 +0900125}
126
Nobuhiro Iwamatsu6d020352015-02-12 13:48:04 +0900127static int sh_serial_getc_generic(struct uart_port *port)
Nobuhiro Iwamatsu970dc332007-05-13 20:58:00 +0900128{
Nobuhiro Iwamatsu6564b1a2008-06-06 16:16:08 +0900129 unsigned short status;
Nobuhiro Iwamatsu970dc332007-05-13 20:58:00 +0900130 char ch;
Nobuhiro Iwamatsufcabccc2008-08-22 17:48:51 +0900131
Nobuhiro Iwamatsu6d020352015-02-12 13:48:04 +0900132 if (!serial_getc_check(port))
133 return -EAGAIN;
Nobuhiro Iwamatsu970dc332007-05-13 20:58:00 +0900134
Nobuhiro Iwamatsu6d020352015-02-12 13:48:04 +0900135 ch = sci_in(port, SCxRDR);
136 status = sci_in(port, SCxSR);
Nobuhiro Iwamatsu970dc332007-05-13 20:58:00 +0900137
Nobuhiro Iwamatsu6d020352015-02-12 13:48:04 +0900138 sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
Nobuhiro Iwamatsu970dc332007-05-13 20:58:00 +0900139
Nobuhiro Iwamatsua5579ca2010-10-26 03:55:15 +0900140 if (status & SCIF_ERRORS)
Nobuhiro Iwamatsu6d020352015-02-12 13:48:04 +0900141 handle_error(port);
142
143 if (sci_in(port, SCLSR) & SCxSR_ORER(port))
144 handle_error(port);
145
146 return ch;
147}
148
149#ifdef CONFIG_DM_SERIAL
150
151static int sh_serial_pending(struct udevice *dev, bool input)
152{
153 struct uart_port *priv = dev_get_priv(dev);
154
155 return sh_serial_tstc_generic(priv);
156}
157
158static int sh_serial_putc(struct udevice *dev, const char ch)
159{
160 struct uart_port *priv = dev_get_priv(dev);
161
162 return serial_raw_putc(priv, ch);
163}
164
165static int sh_serial_getc(struct udevice *dev)
166{
167 struct uart_port *priv = dev_get_priv(dev);
168
169 return sh_serial_getc_generic(priv);
170}
171
172static int sh_serial_setbrg(struct udevice *dev, int baudrate)
173{
174 struct sh_serial_platdata *plat = dev_get_platdata(dev);
175 struct uart_port *priv = dev_get_priv(dev);
176
177 sh_serial_setbrg_generic(priv, plat->clk, baudrate);
178
179 return 0;
180}
181
182static int sh_serial_probe(struct udevice *dev)
183{
184 struct sh_serial_platdata *plat = dev_get_platdata(dev);
185 struct uart_port *priv = dev_get_priv(dev);
186
187 priv->membase = (unsigned char *)plat->base;
188 priv->mapbase = plat->base;
189 priv->type = plat->type;
190 priv->clk_mode = plat->clk_mode;
191
192 sh_serial_init_generic(priv);
193
194 return 0;
195}
196
197static const struct dm_serial_ops sh_serial_ops = {
198 .putc = sh_serial_putc,
199 .pending = sh_serial_pending,
200 .getc = sh_serial_getc,
201 .setbrg = sh_serial_setbrg,
202};
203
204U_BOOT_DRIVER(serial_sh) = {
205 .name = "serial_sh",
206 .id = UCLASS_SERIAL,
207 .probe = sh_serial_probe,
208 .ops = &sh_serial_ops,
209 .flags = DM_FLAG_PRE_RELOC,
210 .priv_auto_alloc_size = sizeof(struct uart_port),
211};
212
213#else /* CONFIG_DM_SERIAL */
214
215#if defined(CONFIG_CONS_SCIF0)
216# define SCIF_BASE SCIF0_BASE
217#elif defined(CONFIG_CONS_SCIF1)
218# define SCIF_BASE SCIF1_BASE
219#elif defined(CONFIG_CONS_SCIF2)
220# define SCIF_BASE SCIF2_BASE
221#elif defined(CONFIG_CONS_SCIF3)
222# define SCIF_BASE SCIF3_BASE
223#elif defined(CONFIG_CONS_SCIF4)
224# define SCIF_BASE SCIF4_BASE
225#elif defined(CONFIG_CONS_SCIF5)
226# define SCIF_BASE SCIF5_BASE
227#elif defined(CONFIG_CONS_SCIF6)
228# define SCIF_BASE SCIF6_BASE
229#elif defined(CONFIG_CONS_SCIF7)
230# define SCIF_BASE SCIF7_BASE
231#else
232# error "Default SCIF doesn't set....."
233#endif
234
235#if defined(CONFIG_SCIF_A)
236 #define SCIF_BASE_PORT PORT_SCIFA
237#else
238 #define SCIF_BASE_PORT PORT_SCIF
239#endif
240
241static struct uart_port sh_sci = {
242 .membase = (unsigned char *)SCIF_BASE,
243 .mapbase = SCIF_BASE,
244 .type = SCIF_BASE_PORT,
245#ifdef CONFIG_SCIF_USE_EXT_CLK
246 .clk_mode = EXT_CLK,
247#endif
248};
249
250static void sh_serial_setbrg(void)
251{
252 DECLARE_GLOBAL_DATA_PTR;
253 struct uart_port *port = &sh_sci;
254
255 sh_serial_setbrg_generic(port, CONFIG_SH_SCIF_CLK_FREQ, gd->baudrate);
256}
257
258static int sh_serial_init(void)
259{
260 struct uart_port *port = &sh_sci;
261
262 sh_serial_init_generic(port);
263 serial_setbrg();
264
265 return 0;
266}
267
268static void sh_serial_putc(const char c)
269{
270 struct uart_port *port = &sh_sci;
271
272 if (c == '\n') {
273 while (1) {
274 if (serial_raw_putc(port, '\r') != -EAGAIN)
275 break;
276 }
277 }
278 while (1) {
279 if (serial_raw_putc(port, c) != -EAGAIN)
280 break;
281 }
282}
283
284static int sh_serial_tstc(void)
285{
286 struct uart_port *port = &sh_sci;
287
288 return sh_serial_tstc_generic(port);
289}
290
291static int sh_serial_getc(void)
292{
293 struct uart_port *port = &sh_sci;
294 int ch;
295
296 while (1) {
297 ch = sh_serial_getc_generic(port);
298 if (ch != -EAGAIN)
299 break;
300 }
Nobuhiro Iwamatsu970dc332007-05-13 20:58:00 +0900301
Nobuhiro Iwamatsu6564b1a2008-06-06 16:16:08 +0900302 return ch;
Nobuhiro Iwamatsu970dc332007-05-13 20:58:00 +0900303}
Marek Vasut904d3d72012-09-14 22:40:08 +0200304
Marek Vasut904d3d72012-09-14 22:40:08 +0200305static struct serial_device sh_serial_drv = {
306 .name = "sh_serial",
307 .start = sh_serial_init,
308 .stop = NULL,
309 .setbrg = sh_serial_setbrg,
310 .putc = sh_serial_putc,
Marek Vasutd9c64492012-10-06 14:07:02 +0000311 .puts = default_serial_puts,
Marek Vasut904d3d72012-09-14 22:40:08 +0200312 .getc = sh_serial_getc,
313 .tstc = sh_serial_tstc,
314};
315
316void sh_serial_initialize(void)
317{
318 serial_register(&sh_serial_drv);
319}
320
321__weak struct serial_device *default_serial_console(void)
322{
323 return &sh_serial_drv;
324}
Nobuhiro Iwamatsu6d020352015-02-12 13:48:04 +0900325#endif /* CONFIG_DM_SERIAL */