blob: 9bebff8512375af6fe9394e9b8adfaac387a65df [file] [log] [blame]
wdenk945af8d2003-07-16 21:53:01 +00001/*
2 * (C) Copyright 2000 - 2003
3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4 *
5 * See file CREDITS for list of people who contributed to this
6 * project.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21 * MA 02111-1307 USA
22 *
23 * Hacked for MPC8260 by Murray.Jensen@cmst.csiro.au, 19-Oct-00, with
Stefan Roesea47a12b2010-04-15 16:07:28 +020024 * changes based on the file arch/powerpc/mbxboot/m8260_tty.c from the
wdenk945af8d2003-07-16 21:53:01 +000025 * Linux/PPC sources (m8260_tty.c had no copyright info in it).
Wolfgang Denkc12cffc2006-06-16 17:04:45 +020026 *
27 * Martin Krause, 8 Jun 2006
28 * Added CONFIG_SERIAL_MULTI support
wdenk945af8d2003-07-16 21:53:01 +000029 */
30
31/*
32 * Minimal serial functions needed to use one of the PSC ports
33 * as serial console interface.
34 */
35
36#include <common.h>
Mike Frysinger6c768ca2011-04-29 18:03:29 +000037#include <linux/compiler.h>
wdenk945af8d2003-07-16 21:53:01 +000038#include <mpc5xxx.h>
39
Wolfgang Denkc12cffc2006-06-16 17:04:45 +020040#if defined (CONFIG_SERIAL_MULTI)
41#include <serial.h>
42#endif
43
Wolfgang Denkd87080b2006-03-31 18:32:53 +020044DECLARE_GLOBAL_DATA_PTR;
45
wdenk945af8d2003-07-16 21:53:01 +000046#if defined(CONFIG_PSC_CONSOLE)
47
48#if CONFIG_PSC_CONSOLE == 1
49#define PSC_BASE MPC5XXX_PSC1
50#elif CONFIG_PSC_CONSOLE == 2
51#define PSC_BASE MPC5XXX_PSC2
52#elif CONFIG_PSC_CONSOLE == 3
53#define PSC_BASE MPC5XXX_PSC3
wdenk945af8d2003-07-16 21:53:01 +000054#elif CONFIG_PSC_CONSOLE == 4
55#define PSC_BASE MPC5XXX_PSC4
56#elif CONFIG_PSC_CONSOLE == 5
57#define PSC_BASE MPC5XXX_PSC5
58#elif CONFIG_PSC_CONSOLE == 6
59#define PSC_BASE MPC5XXX_PSC6
60#else
61#error CONFIG_PSC_CONSOLE must be in 1 ... 6
62#endif
63
Wolfgang Denkc12cffc2006-06-16 17:04:45 +020064#if defined(CONFIG_SERIAL_MULTI) && !defined(CONFIG_PSC_CONSOLE2)
65#error you must define CONFIG_PSC_CONSOLE2 if CONFIG_SERIAL_MULTI is set
66#endif
67
68#if defined(CONFIG_SERIAL_MULTI)
69#if CONFIG_PSC_CONSOLE2 == 1
70#define PSC_BASE2 MPC5XXX_PSC1
71#elif CONFIG_PSC_CONSOLE2 == 2
72#define PSC_BASE2 MPC5XXX_PSC2
73#elif CONFIG_PSC_CONSOLE2 == 3
74#define PSC_BASE2 MPC5XXX_PSC3
Wolfgang Denkc12cffc2006-06-16 17:04:45 +020075#elif CONFIG_PSC_CONSOLE2 == 4
76#define PSC_BASE2 MPC5XXX_PSC4
77#elif CONFIG_PSC_CONSOLE2 == 5
78#define PSC_BASE2 MPC5XXX_PSC5
79#elif CONFIG_PSC_CONSOLE2 == 6
80#define PSC_BASE2 MPC5XXX_PSC6
81#else
82#error CONFIG_PSC_CONSOLE2 must be in 1 ... 6
83#endif
84#endif /* CONFIG_SERIAL_MULTI */
85
86#if defined(CONFIG_SERIAL_MULTI)
87int serial_init_dev (unsigned long dev_base)
88#else
wdenk945af8d2003-07-16 21:53:01 +000089int serial_init (void)
Wolfgang Denkc12cffc2006-06-16 17:04:45 +020090#endif
wdenk945af8d2003-07-16 21:53:01 +000091{
Wolfgang Denkc12cffc2006-06-16 17:04:45 +020092#if defined(CONFIG_SERIAL_MULTI)
93 volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)dev_base;
94#else
wdenk945af8d2003-07-16 21:53:01 +000095 volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)PSC_BASE;
Wolfgang Denkc12cffc2006-06-16 17:04:45 +020096#endif
wdenk945af8d2003-07-16 21:53:01 +000097 unsigned long baseclk;
98 int div;
99
100 /* reset PSC */
101 psc->command = PSC_SEL_MODE_REG_1;
102
103 /* select clock sources */
wdenk945af8d2003-07-16 21:53:01 +0000104 psc->psc_clock_select = 0;
wdenkb98fff12004-02-09 20:51:26 +0000105 baseclk = (gd->ipb_clk + 16) / 32;
wdenk945af8d2003-07-16 21:53:01 +0000106
107 /* switch to UART mode */
108 psc->sicr = 0;
109
110 /* configure parity, bit length and so on */
wdenk945af8d2003-07-16 21:53:01 +0000111 psc->mode = PSC_MODE_8_BITS | PSC_MODE_PARNONE;
wdenk945af8d2003-07-16 21:53:01 +0000112 psc->mode = PSC_MODE_ONE_STOP;
113
114 /* set up UART divisor */
wdenkb98fff12004-02-09 20:51:26 +0000115 div = (baseclk + (gd->baudrate/2)) / gd->baudrate;
116 psc->ctur = (div >> 8) & 0xff;
wdenk945af8d2003-07-16 21:53:01 +0000117 psc->ctlr = div & 0xff;
118
119 /* disable all interrupts */
120 psc->psc_imr = 0;
121
122 /* reset and enable Rx/Tx */
123 psc->command = PSC_RST_RX;
124 psc->command = PSC_RST_TX;
125 psc->command = PSC_RX_ENABLE | PSC_TX_ENABLE;
126
127 return (0);
128}
129
Wolfgang Denkc12cffc2006-06-16 17:04:45 +0200130#if defined(CONFIG_SERIAL_MULTI)
131void serial_putc_dev (unsigned long dev_base, const char c)
132#else
133void serial_putc(const char c)
134#endif
wdenk945af8d2003-07-16 21:53:01 +0000135{
Wolfgang Denkc12cffc2006-06-16 17:04:45 +0200136#if defined(CONFIG_SERIAL_MULTI)
137 volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)dev_base;
138#else
wdenk945af8d2003-07-16 21:53:01 +0000139 volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)PSC_BASE;
Wolfgang Denkc12cffc2006-06-16 17:04:45 +0200140#endif
wdenk945af8d2003-07-16 21:53:01 +0000141
142 if (c == '\n')
Wolfgang Denkc12cffc2006-06-16 17:04:45 +0200143#if defined(CONFIG_SERIAL_MULTI)
144 serial_putc_dev (dev_base, '\r');
145#else
wdenk945af8d2003-07-16 21:53:01 +0000146 serial_putc('\r');
Wolfgang Denkc12cffc2006-06-16 17:04:45 +0200147#endif
wdenk945af8d2003-07-16 21:53:01 +0000148
149 /* Wait for last character to go. */
150 while (!(psc->psc_status & PSC_SR_TXEMP))
151 ;
152
153 psc->psc_buffer_8 = c;
154}
155
Wolfgang Denkc12cffc2006-06-16 17:04:45 +0200156#if defined(CONFIG_SERIAL_MULTI)
Wolfgang Denke8143e72006-08-30 23:09:00 +0200157void serial_putc_raw_dev(unsigned long dev_base, const char c)
158#else
159void serial_putc_raw(const char c)
160#endif
161{
162#if defined(CONFIG_SERIAL_MULTI)
163 volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)dev_base;
164#else
165 volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)PSC_BASE;
166#endif
167 /* Wait for last character to go. */
168 while (!(psc->psc_status & PSC_SR_TXEMP))
169 ;
170
171 psc->psc_buffer_8 = c;
172}
173
174
175#if defined(CONFIG_SERIAL_MULTI)
Wolfgang Denkc12cffc2006-06-16 17:04:45 +0200176void serial_puts_dev (unsigned long dev_base, const char *s)
177#else
178void serial_puts (const char *s)
179#endif
wdenk945af8d2003-07-16 21:53:01 +0000180{
181 while (*s) {
Wolfgang Denkc12cffc2006-06-16 17:04:45 +0200182#if defined(CONFIG_SERIAL_MULTI)
183 serial_putc_dev (dev_base, *s++);
184#else
wdenk945af8d2003-07-16 21:53:01 +0000185 serial_putc (*s++);
Wolfgang Denkc12cffc2006-06-16 17:04:45 +0200186#endif
wdenk945af8d2003-07-16 21:53:01 +0000187 }
188}
189
Wolfgang Denkc12cffc2006-06-16 17:04:45 +0200190#if defined(CONFIG_SERIAL_MULTI)
191int serial_getc_dev (unsigned long dev_base)
192#else
193int serial_getc(void)
194#endif
wdenk945af8d2003-07-16 21:53:01 +0000195{
Wolfgang Denkc12cffc2006-06-16 17:04:45 +0200196#if defined(CONFIG_SERIAL_MULTI)
197 volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)dev_base;
198#else
wdenk945af8d2003-07-16 21:53:01 +0000199 volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)PSC_BASE;
Wolfgang Denkc12cffc2006-06-16 17:04:45 +0200200#endif
wdenk945af8d2003-07-16 21:53:01 +0000201
202 /* Wait for a character to arrive. */
203 while (!(psc->psc_status & PSC_SR_RXRDY))
204 ;
205
206 return psc->psc_buffer_8;
207}
208
Wolfgang Denkc12cffc2006-06-16 17:04:45 +0200209#if defined(CONFIG_SERIAL_MULTI)
210int serial_tstc_dev (unsigned long dev_base)
211#else
212int serial_tstc(void)
213#endif
wdenk945af8d2003-07-16 21:53:01 +0000214{
Wolfgang Denkc12cffc2006-06-16 17:04:45 +0200215#if defined(CONFIG_SERIAL_MULTI)
216 volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)dev_base;
217#else
wdenk945af8d2003-07-16 21:53:01 +0000218 volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)PSC_BASE;
Wolfgang Denkc12cffc2006-06-16 17:04:45 +0200219#endif
wdenk945af8d2003-07-16 21:53:01 +0000220
221 return (psc->psc_status & PSC_SR_RXRDY);
222}
223
Wolfgang Denkc12cffc2006-06-16 17:04:45 +0200224#if defined(CONFIG_SERIAL_MULTI)
225void serial_setbrg_dev (unsigned long dev_base)
226#else
227void serial_setbrg(void)
228#endif
wdenk945af8d2003-07-16 21:53:01 +0000229{
Wolfgang Denkc12cffc2006-06-16 17:04:45 +0200230#if defined(CONFIG_SERIAL_MULTI)
231 volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)dev_base;
232#else
wdenk945af8d2003-07-16 21:53:01 +0000233 volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)PSC_BASE;
Wolfgang Denkc12cffc2006-06-16 17:04:45 +0200234#endif
wdenk945af8d2003-07-16 21:53:01 +0000235 unsigned long baseclk, div;
236
wdenk342717f2005-06-27 13:30:03 +0000237 baseclk = (gd->ipb_clk + 16) / 32;
wdenk945af8d2003-07-16 21:53:01 +0000238
239 /* set up UART divisor */
wdenk342717f2005-06-27 13:30:03 +0000240 div = (baseclk + (gd->baudrate/2)) / gd->baudrate;
Wolfgang Denk9f221d02005-09-25 01:09:58 +0200241 psc->ctur = (div >> 8) & 0xFF;
242 psc->ctlr = div & 0xff;
wdenk945af8d2003-07-16 21:53:01 +0000243}
Wolfgang Denkc12cffc2006-06-16 17:04:45 +0200244
245#if defined(CONFIG_SERIAL_MULTI)
Wolfgang Denke8143e72006-08-30 23:09:00 +0200246void serial_setrts_dev (unsigned long dev_base, int s)
247#else
248void serial_setrts(int s)
249#endif
250{
251#if defined(CONFIG_SERIAL_MULTI)
252 volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)dev_base;
253#else
254 volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)PSC_BASE;
255#endif
256
257 if (s) {
258 /* Assert RTS (become LOW) */
259 psc->op1 = 0x1;
260 }
261 else {
262 /* Negate RTS (become HIGH) */
263 psc->op0 = 0x1;
264 }
265}
266
267#if defined(CONFIG_SERIAL_MULTI)
268int serial_getcts_dev (unsigned long dev_base)
269#else
270int serial_getcts(void)
271#endif
272{
273#if defined(CONFIG_SERIAL_MULTI)
274 volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)dev_base;
275#else
276 volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)PSC_BASE;
277#endif
278
279 return (psc->ip & 0x1) ? 0 : 1;
280}
281
282#if defined(CONFIG_SERIAL_MULTI)
Wolfgang Denkc12cffc2006-06-16 17:04:45 +0200283int serial0_init(void)
284{
285 return (serial_init_dev(PSC_BASE));
286}
287
288int serial1_init(void)
289{
290 return (serial_init_dev(PSC_BASE2));
291}
292void serial0_setbrg (void)
293{
294 serial_setbrg_dev(PSC_BASE);
295}
296void serial1_setbrg (void)
297{
298 serial_setbrg_dev(PSC_BASE2);
299}
300
301void serial0_putc(const char c)
302{
303 serial_putc_dev(PSC_BASE,c);
304}
305
306void serial1_putc(const char c)
307{
308 serial_putc_dev(PSC_BASE2, c);
309}
310void serial0_puts(const char *s)
311{
312 serial_puts_dev(PSC_BASE, s);
313}
314
315void serial1_puts(const char *s)
316{
317 serial_puts_dev(PSC_BASE2, s);
318}
319
320int serial0_getc(void)
321{
322 return(serial_getc_dev(PSC_BASE));
323}
324
325int serial1_getc(void)
326{
327 return(serial_getc_dev(PSC_BASE2));
328}
329int serial0_tstc(void)
330{
331 return (serial_tstc_dev(PSC_BASE));
332}
333
334int serial1_tstc(void)
335{
336 return (serial_tstc_dev(PSC_BASE2));
337}
338
339struct serial_device serial0_device =
340{
Marek Vasut90bad892012-09-09 18:48:28 +0200341 .name = "serial0",
342 .start = serial0_init,
343 .stop = NULL,
344 .setbrg = serial0_setbrg,
345 .getc = serial0_getc,
346 .tstc = serial0_tstc,
347 .putc = serial0_putc,
348 .puts = serial0_puts,
Wolfgang Denkc12cffc2006-06-16 17:04:45 +0200349};
350
Mike Frysinger6c768ca2011-04-29 18:03:29 +0000351__weak struct serial_device *default_serial_console(void)
352{
353 return &serial0_device;
354}
355
Wolfgang Denkc12cffc2006-06-16 17:04:45 +0200356struct serial_device serial1_device =
357{
Marek Vasut90bad892012-09-09 18:48:28 +0200358 .name = "serial1",
359 .start = serial1_init,
360 .stop = NULL,
361 .setbrg = serial1_setbrg,
362 .getc = serial1_getc,
363 .tstc = serial1_tstc,
364 .putc = serial1_putc,
365 .puts = serial1_puts,
Wolfgang Denkc12cffc2006-06-16 17:04:45 +0200366};
367#endif /* CONFIG_SERIAL_MULTI */
368
wdenk945af8d2003-07-16 21:53:01 +0000369#endif /* CONFIG_PSC_CONSOLE */