blob: f8c9d921e283028c5fe199efa7b081bbfc08d09f [file] [log] [blame]
Masahiro Yamada7f368552014-10-03 19:21:05 +09001/*
2 * Copyright (C) 2012-2014 Panasonic Corporation
3 * Author: Masahiro Yamada <yamada.m@jp.panasonic.com>
4 *
5 * Based on serial_ns16550.c
6 * (C) Copyright 2000
7 * Rob Taylor, Flying Pig Systems. robt@flyingpig.com.
8 *
9 * SPDX-License-Identifier: GPL-2.0+
10 */
11
12#include <common.h>
13#include <serial.h>
14
15#define UART_REG(x) \
16 u8 x; \
17 u8 postpad_##x[3];
18
19/*
20 * Note: Register map is slightly different from that of 16550.
21 */
22struct uniphier_serial {
23 UART_REG(rbr); /* 0x00 */
24 UART_REG(ier); /* 0x04 */
25 UART_REG(iir); /* 0x08 */
26 UART_REG(fcr); /* 0x0c */
27 u8 mcr; /* 0x10 */
28 u8 lcr;
29 u16 __postpad;
30 UART_REG(lsr); /* 0x14 */
31 UART_REG(msr); /* 0x18 */
32 u32 __none1;
33 u32 __none2;
34 u16 dlr;
35 u16 __postpad2;
36};
37
38#define thr rbr
39
40/*
41 * These are the definitions for the Line Control Register
42 */
43#define UART_LCR_WLS_8 0x03 /* 8 bit character length */
44
45/*
46 * These are the definitions for the Line Status Register
47 */
48#define UART_LSR_DR 0x01 /* Data ready */
49#define UART_LSR_THRE 0x20 /* Xmit holding register empty */
50
51DECLARE_GLOBAL_DATA_PTR;
52
53static void uniphier_serial_init(struct uniphier_serial *port)
54{
55 const unsigned int mode_x_div = 16;
56 unsigned int divisor;
57
58 writeb(UART_LCR_WLS_8, &port->lcr);
59
60 divisor = DIV_ROUND_CLOSEST(CONFIG_SYS_UNIPHIER_UART_CLK,
61 mode_x_div * gd->baudrate);
62
63 writew(divisor, &port->dlr);
64}
65
66static void uniphier_serial_setbrg(struct uniphier_serial *port)
67{
68 uniphier_serial_init(port);
69}
70
71static int uniphier_serial_tstc(struct uniphier_serial *port)
72{
73 return (readb(&port->lsr) & UART_LSR_DR) != 0;
74}
75
76static int uniphier_serial_getc(struct uniphier_serial *port)
77{
78 while (!uniphier_serial_tstc(port))
79 ;
80
81 return readb(&port->rbr);
82}
83
84static void uniphier_serial_putc(struct uniphier_serial *port, const char c)
85{
86 if (c == '\n')
87 uniphier_serial_putc(port, '\r');
88
89 while (!(readb(&port->lsr) & UART_LSR_THRE))
90 ;
91
92 writeb(c, &port->thr);
93}
94
95static struct uniphier_serial *serial_ports[4] = {
96#ifdef CONFIG_SYS_UNIPHIER_SERIAL_BASE0
97 (struct uniphier_serial *)CONFIG_SYS_UNIPHIER_SERIAL_BASE0,
98#else
99 NULL,
100#endif
101#ifdef CONFIG_SYS_UNIPHIER_SERIAL_BASE1
102 (struct uniphier_serial *)CONFIG_SYS_UNIPHIER_SERIAL_BASE1,
103#else
104 NULL,
105#endif
106#ifdef CONFIG_SYS_UNIPHIER_SERIAL_BASE2
107 (struct uniphier_serial *)CONFIG_SYS_UNIPHIER_SERIAL_BASE2,
108#else
109 NULL,
110#endif
111#ifdef CONFIG_SYS_UNIPHIER_SERIAL_BASE3
112 (struct uniphier_serial *)CONFIG_SYS_UNIPHIER_SERIAL_BASE3,
113#else
114 NULL,
115#endif
116};
117
118/* Multi serial device functions */
119#define DECLARE_ESERIAL_FUNCTIONS(port) \
120 static int eserial##port##_init(void) \
121 { \
122 uniphier_serial_init(serial_ports[port]); \
123 return 0 ; \
124 } \
125 static void eserial##port##_setbrg(void) \
126 { \
127 uniphier_serial_setbrg(serial_ports[port]); \
128 } \
129 static int eserial##port##_getc(void) \
130 { \
131 return uniphier_serial_getc(serial_ports[port]); \
132 } \
133 static int eserial##port##_tstc(void) \
134 { \
135 return uniphier_serial_tstc(serial_ports[port]); \
136 } \
137 static void eserial##port##_putc(const char c) \
138 { \
139 uniphier_serial_putc(serial_ports[port], c); \
140 }
141
142/* Serial device descriptor */
143#define INIT_ESERIAL_STRUCTURE(port, __name) { \
144 .name = __name, \
145 .start = eserial##port##_init, \
146 .stop = NULL, \
147 .setbrg = eserial##port##_setbrg, \
148 .getc = eserial##port##_getc, \
149 .tstc = eserial##port##_tstc, \
150 .putc = eserial##port##_putc, \
151 .puts = default_serial_puts, \
152}
153
154#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE0)
155DECLARE_ESERIAL_FUNCTIONS(0);
156struct serial_device uniphier_serial0_device =
157 INIT_ESERIAL_STRUCTURE(0, "ttyS0");
158#endif
159#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE1)
160DECLARE_ESERIAL_FUNCTIONS(1);
161struct serial_device uniphier_serial1_device =
162 INIT_ESERIAL_STRUCTURE(1, "ttyS1");
163#endif
164#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE2)
165DECLARE_ESERIAL_FUNCTIONS(2);
166struct serial_device uniphier_serial2_device =
167 INIT_ESERIAL_STRUCTURE(2, "ttyS2");
168#endif
169#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE3)
170DECLARE_ESERIAL_FUNCTIONS(3);
171struct serial_device uniphier_serial3_device =
172 INIT_ESERIAL_STRUCTURE(3, "ttyS3");
173#endif
174
175__weak struct serial_device *default_serial_console(void)
176{
177#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE0)
178 return &uniphier_serial0_device;
179#elif defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE1)
180 return &uniphier_serial1_device;
181#elif defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE2)
182 return &uniphier_serial2_device;
183#elif defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE3)
184 return &uniphier_serial3_device;
185#else
186#error "No uniphier serial ports configured."
187#endif
188}
189
190void uniphier_serial_initialize(void)
191{
192#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE0)
193 serial_register(&uniphier_serial0_device);
194#endif
195#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE1)
196 serial_register(&uniphier_serial1_device);
197#endif
198#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE2)
199 serial_register(&uniphier_serial2_device);
200#endif
201#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE3)
202 serial_register(&uniphier_serial3_device);
203#endif
204}