blob: 8693c1ed140bedb5232038b9f1c332f21b5dcf8e [file] [log] [blame]
Nobuhiro Iwamatsu0b135cf2007-05-13 20:58:00 +09001/*
2 * SuperH SCIF device driver.
Nobuhiro Iwamatsu48ca8822013-07-23 13:58:20 +09003 * Copyright (C) 2013 Renesas Electronics Corporation
Nobuhiro Iwamatsu59088e42015-02-12 13:48:04 +09004 * Copyright (C) 2007,2008,2010, 2014 Nobuhiro Iwamatsu
Nobuhiro Iwamatsu3f6c8e32010-10-26 03:55:15 +09005 * Copyright (C) 2002 - 2008 Paul Mundt
Wolfgang Denk61fb15c52007-12-27 01:52:50 +01006 *
Wolfgang Denk1a459662013-07-08 09:37:19 +02007 * SPDX-License-Identifier: GPL-2.0+
Nobuhiro Iwamatsu0b135cf2007-05-13 20:58:00 +09008 */
9
10#include <common.h>
Nobuhiro Iwamatsu59088e42015-02-12 13:48:04 +090011#include <errno.h>
12#include <dm.h>
Jean-Christophe PLAGNIOL-VILLARDfc83c922009-01-11 16:35:16 +010013#include <asm/io.h>
Nobuhiro Iwamatsu0b135cf2007-05-13 20:58:00 +090014#include <asm/processor.h>
Marek Vasut8bdd7ef2012-09-14 22:40:08 +020015#include <serial.h>
16#include <linux/compiler.h>
Nobuhiro Iwamatsu59088e42015-02-12 13:48:04 +090017#include <dm/platform_data/serial_sh.h>
18#include "serial_sh.h"
19
20#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)
25{
26 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) ||
32 (port->mapbase == 0xffe08000)) {
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}
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}
48#else
49static int scif_rxfill(struct uart_port *port)
50{
51 return sci_in(port, SCFDR) & SCIF_RFDC_MASK;
52}
53#endif
54
55static void sh_serial_init_generic(struct uart_port *port)
56{
57 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);
64}
65
66static void
67sh_serial_setbrg_generic(struct uart_port *port, int clk, int baudrate)
68{
69 if (port->clk_mode == EXT_CLK) {
70 unsigned short dl = DL_VALUE(baudrate, clk);
71 sci_out(port, DL, dl);
Nobuhiro Iwamatsu89f99a62014-12-10 14:42:05 +090072 /* Need wait: Clock * 1/dl * 1/16 */
Nobuhiro Iwamatsu59088e42015-02-12 13:48:04 +090073 udelay((1000000 * dl * 16 / clk) * 1000 + 1);
74 } else {
75 sci_out(port, SCBRR, SCBRR_VALUE(baudrate, clk));
76 }
77}
78
79static void handle_error(struct uart_port *port)
80{
81 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;
92
93 sci_out(port, SCxTDR, c);
94 sci_out(port, SCxSR, sci_in(port, SCxSR) & ~SCxSR_TEND(port));
95
96 return 0;
97}
98
99static int serial_rx_fifo_level(struct uart_port *port)
100{
101 return scif_rxfill(port);
102}
103
104static int sh_serial_tstc_generic(struct uart_port *port)
105{
106 if (sci_in(port, SCxSR) & SCIF_ERRORS) {
107 handle_error(port);
108 return 0;
109 }
110
111 return serial_rx_fifo_level(port) ? 1 : 0;
112}
113
114static int serial_getc_check(struct uart_port *port)
115{
116 unsigned short status;
117
118 status = sci_in(port, SCxSR);
119
120 if (status & SCIF_ERRORS)
121 handle_error(port);
122 if (sci_in(port, SCLSR) & SCxSR_ORER(port))
123 handle_error(port);
124 return status & (SCIF_DR | SCxSR_RDxF(port));
125}
126
127static int sh_serial_getc_generic(struct uart_port *port)
128{
129 unsigned short status;
130 char ch;
131
132 if (!serial_getc_check(port))
133 return -EAGAIN;
134
135 ch = sci_in(port, SCxRDR);
136 status = sci_in(port, SCxSR);
137
138 sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
139
140 if (status & SCIF_ERRORS)
141 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 */
John Rigby29565322010-12-20 18:27:51 -0700214
Nobuhiro Iwamatsuab09f432008-08-22 17:48:51 +0900215#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
Phil Edworthy99744b72012-05-15 22:15:51 +0000227#elif defined(CONFIG_CONS_SCIF6)
228# define SCIF_BASE SCIF6_BASE
229#elif defined(CONFIG_CONS_SCIF7)
230# define SCIF_BASE SCIF7_BASE
Nobuhiro Iwamatsu0b135cf2007-05-13 20:58:00 +0900231#else
Nobuhiro Iwamatsuab09f432008-08-22 17:48:51 +0900232# error "Default SCIF doesn't set....."
Nobuhiro Iwamatsu0b135cf2007-05-13 20:58:00 +0900233#endif
234
Nobuhiro Iwamatsu3f6c8e32010-10-26 03:55:15 +0900235#if defined(CONFIG_SCIF_A)
236 #define SCIF_BASE_PORT PORT_SCIFA
Yoshihiro Shimoda7c10c572008-01-09 14:30:02 +0900237#else
Nobuhiro Iwamatsu3f6c8e32010-10-26 03:55:15 +0900238 #define SCIF_BASE_PORT PORT_SCIF
Yoshihiro Shimoda7c10c572008-01-09 14:30:02 +0900239#endif
240
Nobuhiro Iwamatsu3f6c8e32010-10-26 03:55:15 +0900241static struct uart_port sh_sci = {
Nobuhiro Iwamatsu59088e42015-02-12 13:48:04 +0900242 .membase = (unsigned char *)SCIF_BASE,
Nobuhiro Iwamatsu3f6c8e32010-10-26 03:55:15 +0900243 .mapbase = SCIF_BASE,
244 .type = SCIF_BASE_PORT,
Nobuhiro Iwamatsu59088e42015-02-12 13:48:04 +0900245#ifdef CONFIG_SCIF_USE_EXT_CLK
246 .clk_mode = EXT_CLK,
247#endif
Nobuhiro Iwamatsu3f6c8e32010-10-26 03:55:15 +0900248};
Nobuhiro Iwamatsu0b135cf2007-05-13 20:58:00 +0900249
Marek Vasut8bdd7ef2012-09-14 22:40:08 +0200250static void sh_serial_setbrg(void)
Nobuhiro Iwamatsu0b135cf2007-05-13 20:58:00 +0900251{
Nobuhiro Iwamatsu3f6c8e32010-10-26 03:55:15 +0900252 DECLARE_GLOBAL_DATA_PTR;
Nobuhiro Iwamatsu59088e42015-02-12 13:48:04 +0900253 struct uart_port *port = &sh_sci;
254
255 sh_serial_setbrg_generic(port, CONFIG_SH_SCIF_CLK_FREQ, gd->baudrate);
Nobuhiro Iwamatsu0b135cf2007-05-13 20:58:00 +0900256}
257
Marek Vasut8bdd7ef2012-09-14 22:40:08 +0200258static int sh_serial_init(void)
Nobuhiro Iwamatsu0b135cf2007-05-13 20:58:00 +0900259{
Nobuhiro Iwamatsu59088e42015-02-12 13:48:04 +0900260 struct uart_port *port = &sh_sci;
Nobuhiro Iwamatsu0b135cf2007-05-13 20:58:00 +0900261
Nobuhiro Iwamatsu59088e42015-02-12 13:48:04 +0900262 sh_serial_init_generic(port);
Nobuhiro Iwamatsu0b135cf2007-05-13 20:58:00 +0900263 serial_setbrg();
Nobuhiro Iwamatsu59088e42015-02-12 13:48:04 +0900264
Nobuhiro Iwamatsu0b135cf2007-05-13 20:58:00 +0900265 return 0;
266}
267
Marek Vasut8bdd7ef2012-09-14 22:40:08 +0200268static void sh_serial_putc(const char c)
Nobuhiro Iwamatsu0b135cf2007-05-13 20:58:00 +0900269{
Nobuhiro Iwamatsu59088e42015-02-12 13:48:04 +0900270 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 }
Nobuhiro Iwamatsu0b135cf2007-05-13 20:58:00 +0900282}
283
Marek Vasut8bdd7ef2012-09-14 22:40:08 +0200284static int sh_serial_tstc(void)
Nobuhiro Iwamatsu0b135cf2007-05-13 20:58:00 +0900285{
Nobuhiro Iwamatsu59088e42015-02-12 13:48:04 +0900286 struct uart_port *port = &sh_sci;
Tetsuyuki Kobayashi7c791b32012-11-19 21:37:38 +0000287
Nobuhiro Iwamatsu59088e42015-02-12 13:48:04 +0900288 return sh_serial_tstc_generic(port);
Nobuhiro Iwamatsu0b135cf2007-05-13 20:58:00 +0900289}
290
Marek Vasut8bdd7ef2012-09-14 22:40:08 +0200291static int sh_serial_getc(void)
Nobuhiro Iwamatsu0b135cf2007-05-13 20:58:00 +0900292{
Nobuhiro Iwamatsu59088e42015-02-12 13:48:04 +0900293 struct uart_port *port = &sh_sci;
294 int ch;
Nobuhiro Iwamatsuab09f432008-08-22 17:48:51 +0900295
Nobuhiro Iwamatsu59088e42015-02-12 13:48:04 +0900296 while (1) {
297 ch = sh_serial_getc_generic(port);
298 if (ch != -EAGAIN)
299 break;
300 }
Nobuhiro Iwamatsu0b135cf2007-05-13 20:58:00 +0900301
Nobuhiro Iwamatsu08c5fab2008-06-06 16:16:08 +0900302 return ch;
Nobuhiro Iwamatsu0b135cf2007-05-13 20:58:00 +0900303}
Marek Vasut8bdd7ef2012-09-14 22:40:08 +0200304
Marek Vasut8bdd7ef2012-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 Vasutec3fd682012-10-06 14:07:02 +0000311 .puts = default_serial_puts,
Marek Vasut8bdd7ef2012-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 Iwamatsu59088e42015-02-12 13:48:04 +0900325#endif /* CONFIG_DM_SERIAL */