blob: 01270655ae414b8e4c25bc9f2eab16ee9eb997c2 [file] [log] [blame]
wdenk21136db2003-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 Roese88fbf932010-04-15 16:07:28 +020024 * changes based on the file arch/powerpc/mbxboot/m8260_tty.c from the
wdenk21136db2003-07-16 21:53:01 +000025 * Linux/PPC sources (m8260_tty.c had no copyright info in it).
Wolfgang Denk16c3a452006-06-16 17:04:45 +020026 *
27 * Martin Krause, 8 Jun 2006
28 * Added CONFIG_SERIAL_MULTI support
wdenk21136db2003-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>
37#include <mpc5xxx.h>
38
Wolfgang Denk16c3a452006-06-16 17:04:45 +020039#if defined (CONFIG_SERIAL_MULTI)
40#include <serial.h>
41#endif
42
Wolfgang Denk6405a152006-03-31 18:32:53 +020043DECLARE_GLOBAL_DATA_PTR;
44
wdenk21136db2003-07-16 21:53:01 +000045#if defined(CONFIG_PSC_CONSOLE)
46
47#if CONFIG_PSC_CONSOLE == 1
48#define PSC_BASE MPC5XXX_PSC1
49#elif CONFIG_PSC_CONSOLE == 2
50#define PSC_BASE MPC5XXX_PSC2
51#elif CONFIG_PSC_CONSOLE == 3
52#define PSC_BASE MPC5XXX_PSC3
wdenk21136db2003-07-16 21:53:01 +000053#elif CONFIG_PSC_CONSOLE == 4
54#define PSC_BASE MPC5XXX_PSC4
55#elif CONFIG_PSC_CONSOLE == 5
56#define PSC_BASE MPC5XXX_PSC5
57#elif CONFIG_PSC_CONSOLE == 6
58#define PSC_BASE MPC5XXX_PSC6
59#else
60#error CONFIG_PSC_CONSOLE must be in 1 ... 6
61#endif
62
Wolfgang Denk16c3a452006-06-16 17:04:45 +020063#if defined(CONFIG_SERIAL_MULTI) && !defined(CONFIG_PSC_CONSOLE2)
64#error you must define CONFIG_PSC_CONSOLE2 if CONFIG_SERIAL_MULTI is set
65#endif
66
67#if defined(CONFIG_SERIAL_MULTI)
68#if CONFIG_PSC_CONSOLE2 == 1
69#define PSC_BASE2 MPC5XXX_PSC1
70#elif CONFIG_PSC_CONSOLE2 == 2
71#define PSC_BASE2 MPC5XXX_PSC2
72#elif CONFIG_PSC_CONSOLE2 == 3
73#define PSC_BASE2 MPC5XXX_PSC3
Wolfgang Denk16c3a452006-06-16 17:04:45 +020074#elif CONFIG_PSC_CONSOLE2 == 4
75#define PSC_BASE2 MPC5XXX_PSC4
76#elif CONFIG_PSC_CONSOLE2 == 5
77#define PSC_BASE2 MPC5XXX_PSC5
78#elif CONFIG_PSC_CONSOLE2 == 6
79#define PSC_BASE2 MPC5XXX_PSC6
80#else
81#error CONFIG_PSC_CONSOLE2 must be in 1 ... 6
82#endif
83#endif /* CONFIG_SERIAL_MULTI */
84
85#if defined(CONFIG_SERIAL_MULTI)
86int serial_init_dev (unsigned long dev_base)
87#else
wdenk21136db2003-07-16 21:53:01 +000088int serial_init (void)
Wolfgang Denk16c3a452006-06-16 17:04:45 +020089#endif
wdenk21136db2003-07-16 21:53:01 +000090{
Wolfgang Denk16c3a452006-06-16 17:04:45 +020091#if defined(CONFIG_SERIAL_MULTI)
92 volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)dev_base;
93#else
wdenk21136db2003-07-16 21:53:01 +000094 volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)PSC_BASE;
Wolfgang Denk16c3a452006-06-16 17:04:45 +020095#endif
wdenk21136db2003-07-16 21:53:01 +000096 unsigned long baseclk;
97 int div;
98
99 /* reset PSC */
100 psc->command = PSC_SEL_MODE_REG_1;
101
102 /* select clock sources */
wdenk21136db2003-07-16 21:53:01 +0000103 psc->psc_clock_select = 0;
wdenkca262162004-02-09 20:51:26 +0000104 baseclk = (gd->ipb_clk + 16) / 32;
wdenk21136db2003-07-16 21:53:01 +0000105
106 /* switch to UART mode */
107 psc->sicr = 0;
108
109 /* configure parity, bit length and so on */
wdenk21136db2003-07-16 21:53:01 +0000110 psc->mode = PSC_MODE_8_BITS | PSC_MODE_PARNONE;
wdenk21136db2003-07-16 21:53:01 +0000111 psc->mode = PSC_MODE_ONE_STOP;
112
113 /* set up UART divisor */
wdenkca262162004-02-09 20:51:26 +0000114 div = (baseclk + (gd->baudrate/2)) / gd->baudrate;
115 psc->ctur = (div >> 8) & 0xff;
wdenk21136db2003-07-16 21:53:01 +0000116 psc->ctlr = div & 0xff;
117
118 /* disable all interrupts */
119 psc->psc_imr = 0;
120
121 /* reset and enable Rx/Tx */
122 psc->command = PSC_RST_RX;
123 psc->command = PSC_RST_TX;
124 psc->command = PSC_RX_ENABLE | PSC_TX_ENABLE;
125
126 return (0);
127}
128
Wolfgang Denk16c3a452006-06-16 17:04:45 +0200129#if defined(CONFIG_SERIAL_MULTI)
130void serial_putc_dev (unsigned long dev_base, const char c)
131#else
132void serial_putc(const char c)
133#endif
wdenk21136db2003-07-16 21:53:01 +0000134{
Wolfgang Denk16c3a452006-06-16 17:04:45 +0200135#if defined(CONFIG_SERIAL_MULTI)
136 volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)dev_base;
137#else
wdenk21136db2003-07-16 21:53:01 +0000138 volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)PSC_BASE;
Wolfgang Denk16c3a452006-06-16 17:04:45 +0200139#endif
wdenk21136db2003-07-16 21:53:01 +0000140
141 if (c == '\n')
Wolfgang Denk16c3a452006-06-16 17:04:45 +0200142#if defined(CONFIG_SERIAL_MULTI)
143 serial_putc_dev (dev_base, '\r');
144#else
wdenk21136db2003-07-16 21:53:01 +0000145 serial_putc('\r');
Wolfgang Denk16c3a452006-06-16 17:04:45 +0200146#endif
wdenk21136db2003-07-16 21:53:01 +0000147
148 /* Wait for last character to go. */
149 while (!(psc->psc_status & PSC_SR_TXEMP))
150 ;
151
152 psc->psc_buffer_8 = c;
153}
154
Wolfgang Denk16c3a452006-06-16 17:04:45 +0200155#if defined(CONFIG_SERIAL_MULTI)
Wolfgang Denkd4321d32006-08-30 23:09:00 +0200156void serial_putc_raw_dev(unsigned long dev_base, const char c)
157#else
158void serial_putc_raw(const char c)
159#endif
160{
161#if defined(CONFIG_SERIAL_MULTI)
162 volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)dev_base;
163#else
164 volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)PSC_BASE;
165#endif
166 /* Wait for last character to go. */
167 while (!(psc->psc_status & PSC_SR_TXEMP))
168 ;
169
170 psc->psc_buffer_8 = c;
171}
172
173
174#if defined(CONFIG_SERIAL_MULTI)
Wolfgang Denk16c3a452006-06-16 17:04:45 +0200175void serial_puts_dev (unsigned long dev_base, const char *s)
176#else
177void serial_puts (const char *s)
178#endif
wdenk21136db2003-07-16 21:53:01 +0000179{
180 while (*s) {
Wolfgang Denk16c3a452006-06-16 17:04:45 +0200181#if defined(CONFIG_SERIAL_MULTI)
182 serial_putc_dev (dev_base, *s++);
183#else
wdenk21136db2003-07-16 21:53:01 +0000184 serial_putc (*s++);
Wolfgang Denk16c3a452006-06-16 17:04:45 +0200185#endif
wdenk21136db2003-07-16 21:53:01 +0000186 }
187}
188
Wolfgang Denk16c3a452006-06-16 17:04:45 +0200189#if defined(CONFIG_SERIAL_MULTI)
190int serial_getc_dev (unsigned long dev_base)
191#else
192int serial_getc(void)
193#endif
wdenk21136db2003-07-16 21:53:01 +0000194{
Wolfgang Denk16c3a452006-06-16 17:04:45 +0200195#if defined(CONFIG_SERIAL_MULTI)
196 volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)dev_base;
197#else
wdenk21136db2003-07-16 21:53:01 +0000198 volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)PSC_BASE;
Wolfgang Denk16c3a452006-06-16 17:04:45 +0200199#endif
wdenk21136db2003-07-16 21:53:01 +0000200
201 /* Wait for a character to arrive. */
202 while (!(psc->psc_status & PSC_SR_RXRDY))
203 ;
204
205 return psc->psc_buffer_8;
206}
207
Wolfgang Denk16c3a452006-06-16 17:04:45 +0200208#if defined(CONFIG_SERIAL_MULTI)
209int serial_tstc_dev (unsigned long dev_base)
210#else
211int serial_tstc(void)
212#endif
wdenk21136db2003-07-16 21:53:01 +0000213{
Wolfgang Denk16c3a452006-06-16 17:04:45 +0200214#if defined(CONFIG_SERIAL_MULTI)
215 volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)dev_base;
216#else
wdenk21136db2003-07-16 21:53:01 +0000217 volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)PSC_BASE;
Wolfgang Denk16c3a452006-06-16 17:04:45 +0200218#endif
wdenk21136db2003-07-16 21:53:01 +0000219
220 return (psc->psc_status & PSC_SR_RXRDY);
221}
222
Wolfgang Denk16c3a452006-06-16 17:04:45 +0200223#if defined(CONFIG_SERIAL_MULTI)
224void serial_setbrg_dev (unsigned long dev_base)
225#else
226void serial_setbrg(void)
227#endif
wdenk21136db2003-07-16 21:53:01 +0000228{
Wolfgang Denk16c3a452006-06-16 17:04:45 +0200229#if defined(CONFIG_SERIAL_MULTI)
230 volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)dev_base;
231#else
wdenk21136db2003-07-16 21:53:01 +0000232 volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)PSC_BASE;
Wolfgang Denk16c3a452006-06-16 17:04:45 +0200233#endif
wdenk21136db2003-07-16 21:53:01 +0000234 unsigned long baseclk, div;
235
wdenka2b932d2005-06-27 13:30:03 +0000236 baseclk = (gd->ipb_clk + 16) / 32;
wdenk21136db2003-07-16 21:53:01 +0000237
238 /* set up UART divisor */
wdenka2b932d2005-06-27 13:30:03 +0000239 div = (baseclk + (gd->baudrate/2)) / gd->baudrate;
Wolfgang Denk42a14192005-09-25 01:09:58 +0200240 psc->ctur = (div >> 8) & 0xFF;
241 psc->ctlr = div & 0xff;
wdenk21136db2003-07-16 21:53:01 +0000242}
Wolfgang Denk16c3a452006-06-16 17:04:45 +0200243
244#if defined(CONFIG_SERIAL_MULTI)
Wolfgang Denkd4321d32006-08-30 23:09:00 +0200245void serial_setrts_dev (unsigned long dev_base, int s)
246#else
247void serial_setrts(int s)
248#endif
249{
250#if defined(CONFIG_SERIAL_MULTI)
251 volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)dev_base;
252#else
253 volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)PSC_BASE;
254#endif
255
256 if (s) {
257 /* Assert RTS (become LOW) */
258 psc->op1 = 0x1;
259 }
260 else {
261 /* Negate RTS (become HIGH) */
262 psc->op0 = 0x1;
263 }
264}
265
266#if defined(CONFIG_SERIAL_MULTI)
267int serial_getcts_dev (unsigned long dev_base)
268#else
269int serial_getcts(void)
270#endif
271{
272#if defined(CONFIG_SERIAL_MULTI)
273 volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)dev_base;
274#else
275 volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)PSC_BASE;
276#endif
277
278 return (psc->ip & 0x1) ? 0 : 1;
279}
280
281#if defined(CONFIG_SERIAL_MULTI)
Wolfgang Denk16c3a452006-06-16 17:04:45 +0200282int serial0_init(void)
283{
284 return (serial_init_dev(PSC_BASE));
285}
286
287int serial1_init(void)
288{
289 return (serial_init_dev(PSC_BASE2));
290}
291void serial0_setbrg (void)
292{
293 serial_setbrg_dev(PSC_BASE);
294}
295void serial1_setbrg (void)
296{
297 serial_setbrg_dev(PSC_BASE2);
298}
299
300void serial0_putc(const char c)
301{
302 serial_putc_dev(PSC_BASE,c);
303}
304
305void serial1_putc(const char c)
306{
307 serial_putc_dev(PSC_BASE2, c);
308}
309void serial0_puts(const char *s)
310{
311 serial_puts_dev(PSC_BASE, s);
312}
313
314void serial1_puts(const char *s)
315{
316 serial_puts_dev(PSC_BASE2, s);
317}
318
319int serial0_getc(void)
320{
321 return(serial_getc_dev(PSC_BASE));
322}
323
324int serial1_getc(void)
325{
326 return(serial_getc_dev(PSC_BASE2));
327}
328int serial0_tstc(void)
329{
330 return (serial_tstc_dev(PSC_BASE));
331}
332
333int serial1_tstc(void)
334{
335 return (serial_tstc_dev(PSC_BASE2));
336}
337
338struct serial_device serial0_device =
339{
340 "serial0",
341 "UART0",
342 serial0_init,
Anatolij Gustschin99d25f92010-04-24 19:27:04 +0200343 NULL,
Wolfgang Denk16c3a452006-06-16 17:04:45 +0200344 serial0_setbrg,
345 serial0_getc,
346 serial0_tstc,
347 serial0_putc,
348 serial0_puts,
349};
350
351struct serial_device serial1_device =
352{
353 "serial1",
354 "UART1",
355 serial1_init,
Anatolij Gustschin99d25f92010-04-24 19:27:04 +0200356 NULL,
Wolfgang Denk16c3a452006-06-16 17:04:45 +0200357 serial1_setbrg,
358 serial1_getc,
359 serial1_tstc,
360 serial1_putc,
361 serial1_puts,
362};
363#endif /* CONFIG_SERIAL_MULTI */
364
wdenk21136db2003-07-16 21:53:01 +0000365#endif /* CONFIG_PSC_CONSOLE */