1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24#include <common.h>
25#include <linux/compiler.h>
26#include <asm/io.h>
27#include <asm/arch/uart.h>
28#include <asm/arch/clk.h>
29#include <serial.h>
30
31DECLARE_GLOBAL_DATA_PTR;
32
33static inline struct s5p_uart *s5p_get_base_uart(int dev_index)
34{
35 u32 offset = dev_index * sizeof(struct s5p_uart);
36 return (struct s5p_uart *)(samsung_get_base_uart() + offset);
37}
38
39
40
41
42
43
44
45
46static const int udivslot[] = {
47 0,
48 0x0080,
49 0x0808,
50 0x0888,
51 0x2222,
52 0x4924,
53 0x4a52,
54 0x54aa,
55 0x5555,
56 0xd555,
57 0xd5d5,
58 0xddd5,
59 0xdddd,
60 0xdfdd,
61 0xdfdf,
62 0xffdf,
63};
64
65void serial_setbrg_dev(const int dev_index)
66{
67 struct s5p_uart *const uart = s5p_get_base_uart(dev_index);
68 u32 uclk = get_uart_clk(dev_index);
69 u32 baudrate = gd->baudrate;
70 u32 val;
71
72 val = uclk / baudrate;
73
74 writel(val / 16 - 1, &uart->ubrdiv);
75
76 if (s5p_uart_divslot())
77 writew(udivslot[val % 16], &uart->rest.slot);
78 else
79 writeb(val % 16, &uart->rest.value);
80}
81
82
83
84
85
86int serial_init_dev(const int dev_index)
87{
88 struct s5p_uart *const uart = s5p_get_base_uart(dev_index);
89
90
91 writel(0, &uart->ufcon);
92 writel(0, &uart->umcon);
93
94 writel(0x3, &uart->ulcon);
95
96 writel(0x245, &uart->ucon);
97
98 serial_setbrg_dev(dev_index);
99
100 return 0;
101}
102
103static int serial_err_check(const int dev_index, int op)
104{
105 struct s5p_uart *const uart = s5p_get_base_uart(dev_index);
106 unsigned int mask;
107
108
109
110
111
112
113
114
115 if (op)
116 mask = 0x8;
117 else
118 mask = 0xf;
119
120 return readl(&uart->uerstat) & mask;
121}
122
123
124
125
126
127
128int serial_getc_dev(const int dev_index)
129{
130 struct s5p_uart *const uart = s5p_get_base_uart(dev_index);
131
132
133 while (!(readl(&uart->utrstat) & 0x1)) {
134 if (serial_err_check(dev_index, 0))
135 return 0;
136 }
137
138 return (int)(readb(&uart->urxh) & 0xff);
139}
140
141
142
143
144void serial_putc_dev(const char c, const int dev_index)
145{
146 struct s5p_uart *const uart = s5p_get_base_uart(dev_index);
147
148
149 while (!(readl(&uart->utrstat) & 0x2)) {
150 if (serial_err_check(dev_index, 1))
151 return;
152 }
153
154 writeb(c, &uart->utxh);
155
156
157 if (c == '\n')
158 serial_putc('\r');
159}
160
161
162
163
164int serial_tstc_dev(const int dev_index)
165{
166 struct s5p_uart *const uart = s5p_get_base_uart(dev_index);
167
168 return (int)(readl(&uart->utrstat) & 0x1);
169}
170
171void serial_puts_dev(const char *s, const int dev_index)
172{
173 while (*s)
174 serial_putc_dev(*s++, dev_index);
175}
176
177
178#define DECLARE_S5P_SERIAL_FUNCTIONS(port) \
179int s5p_serial##port##_init(void) { return serial_init_dev(port); } \
180void s5p_serial##port##_setbrg(void) { serial_setbrg_dev(port); } \
181int s5p_serial##port##_getc(void) { return serial_getc_dev(port); } \
182int s5p_serial##port##_tstc(void) { return serial_tstc_dev(port); } \
183void s5p_serial##port##_putc(const char c) { serial_putc_dev(c, port); } \
184void s5p_serial##port##_puts(const char *s) { serial_puts_dev(s, port); }
185
186#define INIT_S5P_SERIAL_STRUCTURE(port, __name) { \
187 .name = __name, \
188 .start = s5p_serial##port##_init, \
189 .stop = NULL, \
190 .setbrg = s5p_serial##port##_setbrg, \
191 .getc = s5p_serial##port##_getc, \
192 .tstc = s5p_serial##port##_tstc, \
193 .putc = s5p_serial##port##_putc, \
194 .puts = s5p_serial##port##_puts, \
195}
196
197DECLARE_S5P_SERIAL_FUNCTIONS(0);
198struct serial_device s5p_serial0_device =
199 INIT_S5P_SERIAL_STRUCTURE(0, "s5pser0");
200DECLARE_S5P_SERIAL_FUNCTIONS(1);
201struct serial_device s5p_serial1_device =
202 INIT_S5P_SERIAL_STRUCTURE(1, "s5pser1");
203DECLARE_S5P_SERIAL_FUNCTIONS(2);
204struct serial_device s5p_serial2_device =
205 INIT_S5P_SERIAL_STRUCTURE(2, "s5pser2");
206DECLARE_S5P_SERIAL_FUNCTIONS(3);
207struct serial_device s5p_serial3_device =
208 INIT_S5P_SERIAL_STRUCTURE(3, "s5pser3");
209
210__weak struct serial_device *default_serial_console(void)
211{
212#if defined(CONFIG_SERIAL0)
213 return &s5p_serial0_device;
214#elif defined(CONFIG_SERIAL1)
215 return &s5p_serial1_device;
216#elif defined(CONFIG_SERIAL2)
217 return &s5p_serial2_device;
218#elif defined(CONFIG_SERIAL3)
219 return &s5p_serial3_device;
220#else
221#error "CONFIG_SERIAL? missing."
222#endif
223}
224
225void s5p_serial_initialize(void)
226{
227 serial_register(&s5p_serial0_device);
228 serial_register(&s5p_serial1_device);
229 serial_register(&s5p_serial2_device);
230 serial_register(&s5p_serial3_device);
231}
232