blob: dafeed742df49e7d56bf2774314ea535c228be22 [file] [log] [blame]
wdenk78f66222002-08-27 10:27:51 +00001/*
2 * (C) Copyright 2000
3 * Rob Taylor, Flying Pig Systems. robt@flyingpig.com.
4 *
Wolfgang Denkd79de1d2013-07-08 09:37:19 +02005 * SPDX-License-Identifier: GPL-2.0+
wdenk78f66222002-08-27 10:27:51 +00006 */
7
8#include <common.h>
Mike Frysingerf96c0422011-04-29 18:03:29 +00009#include <linux/compiler.h>
wdenk78f66222002-08-27 10:27:51 +000010
wdenk78f66222002-08-27 10:27:51 +000011#include <ns16550.h>
Jean-Christophe PLAGNIOL-VILLARDa44b9aa2008-08-13 01:40:40 +020012#ifdef CONFIG_NS87308
wdenk78f66222002-08-27 10:27:51 +000013#include <ns87308.h>
14#endif
15
Wolfgang Denk44df5612006-08-30 23:02:10 +020016#include <serial.h>
Wolfgang Denk44df5612006-08-30 23:02:10 +020017
Scott Wood2fecf6d2012-10-16 15:43:15 -050018#ifndef CONFIG_NS16550_MIN_FUNCTIONS
19
Wolfgang Denk6405a152006-03-31 18:32:53 +020020DECLARE_GLOBAL_DATA_PTR;
21
wdenke0c812a2005-04-03 15:51:42 +000022#if !defined(CONFIG_CONS_INDEX)
Andrew Bradford86832ec2012-10-25 08:21:31 -040023#elif (CONFIG_CONS_INDEX < 1) || (CONFIG_CONS_INDEX > 6)
wdenke0c812a2005-04-03 15:51:42 +000024#error "Invalid console index value."
25#endif
26
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020027#if CONFIG_CONS_INDEX == 1 && !defined(CONFIG_SYS_NS16550_COM1)
wdenke0c812a2005-04-03 15:51:42 +000028#error "Console port 1 defined but not configured."
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020029#elif CONFIG_CONS_INDEX == 2 && !defined(CONFIG_SYS_NS16550_COM2)
wdenke0c812a2005-04-03 15:51:42 +000030#error "Console port 2 defined but not configured."
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020031#elif CONFIG_CONS_INDEX == 3 && !defined(CONFIG_SYS_NS16550_COM3)
wdenke0c812a2005-04-03 15:51:42 +000032#error "Console port 3 defined but not configured."
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020033#elif CONFIG_CONS_INDEX == 4 && !defined(CONFIG_SYS_NS16550_COM4)
wdenke0c812a2005-04-03 15:51:42 +000034#error "Console port 4 defined but not configured."
Andrew Bradford86832ec2012-10-25 08:21:31 -040035#elif CONFIG_CONS_INDEX == 5 && !defined(CONFIG_SYS_NS16550_COM5)
36#error "Console port 5 defined but not configured."
37#elif CONFIG_CONS_INDEX == 6 && !defined(CONFIG_SYS_NS16550_COM6)
38#error "Console port 6 defined but not configured."
wdenke0c812a2005-04-03 15:51:42 +000039#endif
40
41/* Note: The port number specified in the functions is 1 based.
42 * the array is 0 based.
43 */
Andrew Bradford86832ec2012-10-25 08:21:31 -040044static NS16550_t serial_ports[6] = {
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020045#ifdef CONFIG_SYS_NS16550_COM1
46 (NS16550_t)CONFIG_SYS_NS16550_COM1,
wdenk78f66222002-08-27 10:27:51 +000047#else
wdenke0c812a2005-04-03 15:51:42 +000048 NULL,
wdenk78f66222002-08-27 10:27:51 +000049#endif
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020050#ifdef CONFIG_SYS_NS16550_COM2
51 (NS16550_t)CONFIG_SYS_NS16550_COM2,
wdenke0c812a2005-04-03 15:51:42 +000052#else
53 NULL,
54#endif
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020055#ifdef CONFIG_SYS_NS16550_COM3
56 (NS16550_t)CONFIG_SYS_NS16550_COM3,
wdenke0c812a2005-04-03 15:51:42 +000057#else
58 NULL,
59#endif
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020060#ifdef CONFIG_SYS_NS16550_COM4
Andrew Bradford86832ec2012-10-25 08:21:31 -040061 (NS16550_t)CONFIG_SYS_NS16550_COM4,
62#else
63 NULL,
64#endif
65#ifdef CONFIG_SYS_NS16550_COM5
66 (NS16550_t)CONFIG_SYS_NS16550_COM5,
67#else
68 NULL,
69#endif
70#ifdef CONFIG_SYS_NS16550_COM6
71 (NS16550_t)CONFIG_SYS_NS16550_COM6
wdenke0c812a2005-04-03 15:51:42 +000072#else
73 NULL
74#endif
75};
wdenk78f66222002-08-27 10:27:51 +000076
wdenke0c812a2005-04-03 15:51:42 +000077#define PORT serial_ports[port-1]
Wolfgang Denk44df5612006-08-30 23:02:10 +020078
Wolfgang Denk44df5612006-08-30 23:02:10 +020079/* Multi serial device functions */
80#define DECLARE_ESERIAL_FUNCTIONS(port) \
Kim Phillips561cda92012-10-29 13:34:47 +000081 static int eserial##port##_init(void) \
82 { \
83 int clock_divisor; \
84 clock_divisor = calc_divisor(serial_ports[port-1]); \
85 NS16550_init(serial_ports[port-1], clock_divisor); \
86 return 0 ; \
87 } \
88 static void eserial##port##_setbrg(void) \
89 { \
90 serial_setbrg_dev(port); \
91 } \
92 static int eserial##port##_getc(void) \
93 { \
94 return serial_getc_dev(port); \
95 } \
96 static int eserial##port##_tstc(void) \
97 { \
98 return serial_tstc_dev(port); \
99 } \
100 static void eserial##port##_putc(const char c) \
101 { \
102 serial_putc_dev(port, c); \
103 } \
104 static void eserial##port##_puts(const char *s) \
105 { \
106 serial_puts_dev(port, s); \
107 }
Wolfgang Denk44df5612006-08-30 23:02:10 +0200108
109/* Serial device descriptor */
Marek Vasut5bcdf242012-09-09 18:48:28 +0200110#define INIT_ESERIAL_STRUCTURE(port, __name) { \
111 .name = __name, \
112 .start = eserial##port##_init, \
113 .stop = NULL, \
114 .setbrg = eserial##port##_setbrg, \
115 .getc = eserial##port##_getc, \
116 .tstc = eserial##port##_tstc, \
117 .putc = eserial##port##_putc, \
118 .puts = eserial##port##_puts, \
119}
Wolfgang Denk44df5612006-08-30 23:02:10 +0200120
wdenke0c812a2005-04-03 15:51:42 +0000121static int calc_divisor (NS16550_t port)
wdenk78f66222002-08-27 10:27:51 +0000122{
Masahiro Yamadaef2c62f2014-07-11 20:29:04 +0900123 const unsigned int mode_x_div = 16;
124
Masahiro Yamada75ab6cb2014-07-11 20:29:03 +0900125 return DIV_ROUND_CLOSEST(CONFIG_SYS_NS16550_CLK,
Masahiro Yamadaef2c62f2014-07-11 20:29:04 +0900126 mode_x_div * gd->baudrate);
wdenkf6f96f72003-07-15 20:04:06 +0000127}
wdenk78f66222002-08-27 10:27:51 +0000128
wdenk78f66222002-08-27 10:27:51 +0000129void
wdenke0c812a2005-04-03 15:51:42 +0000130_serial_putc(const char c,const int port)
wdenk78f66222002-08-27 10:27:51 +0000131{
132 if (c == '\n')
wdenke0c812a2005-04-03 15:51:42 +0000133 NS16550_putc(PORT, '\r');
134
135 NS16550_putc(PORT, c);
136}
wdenk78f66222002-08-27 10:27:51 +0000137
wdenke0c812a2005-04-03 15:51:42 +0000138void
139_serial_putc_raw(const char c,const int port)
140{
141 NS16550_putc(PORT, c);
wdenk78f66222002-08-27 10:27:51 +0000142}
143
144void
wdenke0c812a2005-04-03 15:51:42 +0000145_serial_puts (const char *s,const int port)
wdenk78f66222002-08-27 10:27:51 +0000146{
147 while (*s) {
wdenke0c812a2005-04-03 15:51:42 +0000148 _serial_putc (*s++,port);
wdenk78f66222002-08-27 10:27:51 +0000149 }
150}
151
152
153int
wdenke0c812a2005-04-03 15:51:42 +0000154_serial_getc(const int port)
wdenk78f66222002-08-27 10:27:51 +0000155{
wdenke0c812a2005-04-03 15:51:42 +0000156 return NS16550_getc(PORT);
wdenk78f66222002-08-27 10:27:51 +0000157}
158
159int
wdenke0c812a2005-04-03 15:51:42 +0000160_serial_tstc(const int port)
wdenk78f66222002-08-27 10:27:51 +0000161{
wdenke0c812a2005-04-03 15:51:42 +0000162 return NS16550_tstc(PORT);
wdenk78f66222002-08-27 10:27:51 +0000163}
164
165void
wdenke0c812a2005-04-03 15:51:42 +0000166_serial_setbrg (const int port)
wdenk78f66222002-08-27 10:27:51 +0000167{
wdenkf6f96f72003-07-15 20:04:06 +0000168 int clock_divisor;
wdenk78f66222002-08-27 10:27:51 +0000169
wdenke0c812a2005-04-03 15:51:42 +0000170 clock_divisor = calc_divisor(PORT);
171 NS16550_reinit(PORT, clock_divisor);
172}
173
Wolfgang Denk44df5612006-08-30 23:02:10 +0200174static inline void
175serial_putc_dev(unsigned int dev_index,const char c)
176{
177 _serial_putc(c,dev_index);
178}
wdenke0c812a2005-04-03 15:51:42 +0000179
Wolfgang Denk4df0da52006-10-09 00:42:01 +0200180static inline void
Wolfgang Denk44df5612006-08-30 23:02:10 +0200181serial_putc_raw_dev(unsigned int dev_index,const char c)
182{
183 _serial_putc_raw(c,dev_index);
184}
wdenke0c812a2005-04-03 15:51:42 +0000185
Wolfgang Denk44df5612006-08-30 23:02:10 +0200186static inline void
187serial_puts_dev(unsigned int dev_index,const char *s)
188{
189 _serial_puts(s,dev_index);
190}
wdenke0c812a2005-04-03 15:51:42 +0000191
Wolfgang Denk44df5612006-08-30 23:02:10 +0200192static inline int
193serial_getc_dev(unsigned int dev_index)
194{
195 return _serial_getc(dev_index);
196}
wdenke0c812a2005-04-03 15:51:42 +0000197
Wolfgang Denk44df5612006-08-30 23:02:10 +0200198static inline int
199serial_tstc_dev(unsigned int dev_index)
200{
201 return _serial_tstc(dev_index);
202}
wdenke0c812a2005-04-03 15:51:42 +0000203
Wolfgang Denk44df5612006-08-30 23:02:10 +0200204static inline void
205serial_setbrg_dev(unsigned int dev_index)
206{
207 _serial_setbrg(dev_index);
208}
Wolfgang Denk44df5612006-08-30 23:02:10 +0200209
Scott Wood6c3c4e22013-01-18 15:42:16 +0000210#if defined(CONFIG_SYS_NS16550_COM1)
Wolfgang Denk44df5612006-08-30 23:02:10 +0200211DECLARE_ESERIAL_FUNCTIONS(1);
Wolfgang Denk4df0da52006-10-09 00:42:01 +0200212struct serial_device eserial1_device =
Mike Frysinger1ef72f62011-04-29 18:03:31 +0000213 INIT_ESERIAL_STRUCTURE(1, "eserial0");
Scott Wood6c3c4e22013-01-18 15:42:16 +0000214#endif
215#if defined(CONFIG_SYS_NS16550_COM2)
Wolfgang Denk44df5612006-08-30 23:02:10 +0200216DECLARE_ESERIAL_FUNCTIONS(2);
217struct serial_device eserial2_device =
Mike Frysinger1ef72f62011-04-29 18:03:31 +0000218 INIT_ESERIAL_STRUCTURE(2, "eserial1");
Scott Wood6c3c4e22013-01-18 15:42:16 +0000219#endif
220#if defined(CONFIG_SYS_NS16550_COM3)
Wolfgang Denk44df5612006-08-30 23:02:10 +0200221DECLARE_ESERIAL_FUNCTIONS(3);
222struct serial_device eserial3_device =
Mike Frysinger1ef72f62011-04-29 18:03:31 +0000223 INIT_ESERIAL_STRUCTURE(3, "eserial2");
Scott Wood6c3c4e22013-01-18 15:42:16 +0000224#endif
225#if defined(CONFIG_SYS_NS16550_COM4)
Wolfgang Denk44df5612006-08-30 23:02:10 +0200226DECLARE_ESERIAL_FUNCTIONS(4);
227struct serial_device eserial4_device =
Mike Frysinger1ef72f62011-04-29 18:03:31 +0000228 INIT_ESERIAL_STRUCTURE(4, "eserial3");
Scott Wood6c3c4e22013-01-18 15:42:16 +0000229#endif
230#if defined(CONFIG_SYS_NS16550_COM5)
Andrew Bradford86832ec2012-10-25 08:21:31 -0400231DECLARE_ESERIAL_FUNCTIONS(5);
232struct serial_device eserial5_device =
233 INIT_ESERIAL_STRUCTURE(5, "eserial4");
Scott Wood6c3c4e22013-01-18 15:42:16 +0000234#endif
235#if defined(CONFIG_SYS_NS16550_COM6)
Andrew Bradford86832ec2012-10-25 08:21:31 -0400236DECLARE_ESERIAL_FUNCTIONS(6);
237struct serial_device eserial6_device =
238 INIT_ESERIAL_STRUCTURE(6, "eserial5");
Scott Wood6c3c4e22013-01-18 15:42:16 +0000239#endif
Mike Frysingerf96c0422011-04-29 18:03:29 +0000240
241__weak struct serial_device *default_serial_console(void)
242{
243#if CONFIG_CONS_INDEX == 1
244 return &eserial1_device;
245#elif CONFIG_CONS_INDEX == 2
246 return &eserial2_device;
247#elif CONFIG_CONS_INDEX == 3
248 return &eserial3_device;
249#elif CONFIG_CONS_INDEX == 4
250 return &eserial4_device;
Andrew Bradford86832ec2012-10-25 08:21:31 -0400251#elif CONFIG_CONS_INDEX == 5
252 return &eserial5_device;
253#elif CONFIG_CONS_INDEX == 6
254 return &eserial6_device;
Mike Frysingerf96c0422011-04-29 18:03:29 +0000255#else
256#error "Bad CONFIG_CONS_INDEX."
257#endif
258}
259
Marek Vasut3f085062012-09-12 20:02:05 +0200260void ns16550_serial_initialize(void)
261{
262#if defined(CONFIG_SYS_NS16550_COM1)
263 serial_register(&eserial1_device);
264#endif
265#if defined(CONFIG_SYS_NS16550_COM2)
266 serial_register(&eserial2_device);
267#endif
268#if defined(CONFIG_SYS_NS16550_COM3)
269 serial_register(&eserial3_device);
270#endif
271#if defined(CONFIG_SYS_NS16550_COM4)
272 serial_register(&eserial4_device);
273#endif
Andrew Bradford86832ec2012-10-25 08:21:31 -0400274#if defined(CONFIG_SYS_NS16550_COM5)
275 serial_register(&eserial5_device);
276#endif
277#if defined(CONFIG_SYS_NS16550_COM6)
278 serial_register(&eserial6_device);
279#endif
Marek Vasut3f085062012-09-12 20:02:05 +0200280}
Scott Wood2fecf6d2012-10-16 15:43:15 -0500281
282#endif /* !CONFIG_NS16550_MIN_FUNCTIONS */