blob: 6cb523d3c7bf5428d03497341d11906e93d50bcf [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
24 * changes based on the file arch/ppc/mbxboot/m8260_tty.c from the
25 * 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>
37#include <mpc5xxx.h>
38
Wolfgang Denkc12cffc2006-06-16 17:04:45 +020039#if defined (CONFIG_SERIAL_MULTI)
40#include <serial.h>
41#endif
42
Wolfgang Denkd87080b2006-03-31 18:32:53 +020043DECLARE_GLOBAL_DATA_PTR;
44
wdenk945af8d2003-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
53#elif defined(CONFIG_MGT5100)
54#error CONFIG_PSC_CONSOLE must be in 1, 2 or 3
55#elif CONFIG_PSC_CONSOLE == 4
56#define PSC_BASE MPC5XXX_PSC4
57#elif CONFIG_PSC_CONSOLE == 5
58#define PSC_BASE MPC5XXX_PSC5
59#elif CONFIG_PSC_CONSOLE == 6
60#define PSC_BASE MPC5XXX_PSC6
61#else
62#error CONFIG_PSC_CONSOLE must be in 1 ... 6
63#endif
64
Wolfgang Denkc12cffc2006-06-16 17:04:45 +020065#if defined(CONFIG_SERIAL_MULTI) && !defined(CONFIG_PSC_CONSOLE2)
66#error you must define CONFIG_PSC_CONSOLE2 if CONFIG_SERIAL_MULTI is set
67#endif
68
69#if defined(CONFIG_SERIAL_MULTI)
70#if CONFIG_PSC_CONSOLE2 == 1
71#define PSC_BASE2 MPC5XXX_PSC1
72#elif CONFIG_PSC_CONSOLE2 == 2
73#define PSC_BASE2 MPC5XXX_PSC2
74#elif CONFIG_PSC_CONSOLE2 == 3
75#define PSC_BASE2 MPC5XXX_PSC3
76#elif defined(CONFIG_MGT5100)
77#error CONFIG_PSC_CONSOLE2 must be in 1, 2 or 3
78#elif CONFIG_PSC_CONSOLE2 == 4
79#define PSC_BASE2 MPC5XXX_PSC4
80#elif CONFIG_PSC_CONSOLE2 == 5
81#define PSC_BASE2 MPC5XXX_PSC5
82#elif CONFIG_PSC_CONSOLE2 == 6
83#define PSC_BASE2 MPC5XXX_PSC6
84#else
85#error CONFIG_PSC_CONSOLE2 must be in 1 ... 6
86#endif
87#endif /* CONFIG_SERIAL_MULTI */
88
89#if defined(CONFIG_SERIAL_MULTI)
90int serial_init_dev (unsigned long dev_base)
91#else
wdenk945af8d2003-07-16 21:53:01 +000092int serial_init (void)
Wolfgang Denkc12cffc2006-06-16 17:04:45 +020093#endif
wdenk945af8d2003-07-16 21:53:01 +000094{
Wolfgang Denkc12cffc2006-06-16 17:04:45 +020095#if defined(CONFIG_SERIAL_MULTI)
96 volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)dev_base;
97#else
wdenk945af8d2003-07-16 21:53:01 +000098 volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)PSC_BASE;
Wolfgang Denkc12cffc2006-06-16 17:04:45 +020099#endif
wdenk945af8d2003-07-16 21:53:01 +0000100 unsigned long baseclk;
101 int div;
102
103 /* reset PSC */
104 psc->command = PSC_SEL_MODE_REG_1;
105
106 /* select clock sources */
107#if defined(CONFIG_MGT5100)
108 psc->psc_clock_select = 0xdd00;
wdenkb98fff12004-02-09 20:51:26 +0000109 baseclk = (CFG_MPC5XXX_CLKIN + 16) / 32;
wdenk945af8d2003-07-16 21:53:01 +0000110#elif defined(CONFIG_MPC5200)
111 psc->psc_clock_select = 0;
wdenkb98fff12004-02-09 20:51:26 +0000112 baseclk = (gd->ipb_clk + 16) / 32;
wdenk945af8d2003-07-16 21:53:01 +0000113#endif
114
115 /* switch to UART mode */
116 psc->sicr = 0;
117
118 /* configure parity, bit length and so on */
119#if defined(CONFIG_MGT5100)
120 psc->mode = PSC_MODE_ERR | PSC_MODE_8_BITS | PSC_MODE_PARNONE;
121#elif defined(CONFIG_MPC5200)
122 psc->mode = PSC_MODE_8_BITS | PSC_MODE_PARNONE;
123#endif
124 psc->mode = PSC_MODE_ONE_STOP;
125
126 /* set up UART divisor */
wdenkb98fff12004-02-09 20:51:26 +0000127 div = (baseclk + (gd->baudrate/2)) / gd->baudrate;
128 psc->ctur = (div >> 8) & 0xff;
wdenk945af8d2003-07-16 21:53:01 +0000129 psc->ctlr = div & 0xff;
130
131 /* disable all interrupts */
132 psc->psc_imr = 0;
133
134 /* reset and enable Rx/Tx */
135 psc->command = PSC_RST_RX;
136 psc->command = PSC_RST_TX;
137 psc->command = PSC_RX_ENABLE | PSC_TX_ENABLE;
138
139 return (0);
140}
141
Wolfgang Denkc12cffc2006-06-16 17:04:45 +0200142#if defined(CONFIG_SERIAL_MULTI)
143void serial_putc_dev (unsigned long dev_base, const char c)
144#else
145void serial_putc(const char c)
146#endif
wdenk945af8d2003-07-16 21:53:01 +0000147{
Wolfgang Denkc12cffc2006-06-16 17:04:45 +0200148#if defined(CONFIG_SERIAL_MULTI)
149 volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)dev_base;
150#else
wdenk945af8d2003-07-16 21:53:01 +0000151 volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)PSC_BASE;
Wolfgang Denkc12cffc2006-06-16 17:04:45 +0200152#endif
wdenk945af8d2003-07-16 21:53:01 +0000153
154 if (c == '\n')
Wolfgang Denkc12cffc2006-06-16 17:04:45 +0200155#if defined(CONFIG_SERIAL_MULTI)
156 serial_putc_dev (dev_base, '\r');
157#else
wdenk945af8d2003-07-16 21:53:01 +0000158 serial_putc('\r');
Wolfgang Denkc12cffc2006-06-16 17:04:45 +0200159#endif
wdenk945af8d2003-07-16 21:53:01 +0000160
161 /* Wait for last character to go. */
162 while (!(psc->psc_status & PSC_SR_TXEMP))
163 ;
164
165 psc->psc_buffer_8 = c;
166}
167
Wolfgang Denkc12cffc2006-06-16 17:04:45 +0200168#if defined(CONFIG_SERIAL_MULTI)
169void serial_puts_dev (unsigned long dev_base, const char *s)
170#else
171void serial_puts (const char *s)
172#endif
wdenk945af8d2003-07-16 21:53:01 +0000173{
174 while (*s) {
Wolfgang Denkc12cffc2006-06-16 17:04:45 +0200175#if defined(CONFIG_SERIAL_MULTI)
176 serial_putc_dev (dev_base, *s++);
177#else
wdenk945af8d2003-07-16 21:53:01 +0000178 serial_putc (*s++);
Wolfgang Denkc12cffc2006-06-16 17:04:45 +0200179#endif
wdenk945af8d2003-07-16 21:53:01 +0000180 }
181}
182
Wolfgang Denkc12cffc2006-06-16 17:04:45 +0200183#if defined(CONFIG_SERIAL_MULTI)
184int serial_getc_dev (unsigned long dev_base)
185#else
186int serial_getc(void)
187#endif
wdenk945af8d2003-07-16 21:53:01 +0000188{
Wolfgang Denkc12cffc2006-06-16 17:04:45 +0200189#if defined(CONFIG_SERIAL_MULTI)
190 volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)dev_base;
191#else
wdenk945af8d2003-07-16 21:53:01 +0000192 volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)PSC_BASE;
Wolfgang Denkc12cffc2006-06-16 17:04:45 +0200193#endif
wdenk945af8d2003-07-16 21:53:01 +0000194
195 /* Wait for a character to arrive. */
196 while (!(psc->psc_status & PSC_SR_RXRDY))
197 ;
198
199 return psc->psc_buffer_8;
200}
201
Wolfgang Denkc12cffc2006-06-16 17:04:45 +0200202#if defined(CONFIG_SERIAL_MULTI)
203int serial_tstc_dev (unsigned long dev_base)
204#else
205int serial_tstc(void)
206#endif
wdenk945af8d2003-07-16 21:53:01 +0000207{
Wolfgang Denkc12cffc2006-06-16 17:04:45 +0200208#if defined(CONFIG_SERIAL_MULTI)
209 volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)dev_base;
210#else
wdenk945af8d2003-07-16 21:53:01 +0000211 volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)PSC_BASE;
Wolfgang Denkc12cffc2006-06-16 17:04:45 +0200212#endif
wdenk945af8d2003-07-16 21:53:01 +0000213
214 return (psc->psc_status & PSC_SR_RXRDY);
215}
216
Wolfgang Denkc12cffc2006-06-16 17:04:45 +0200217#if defined(CONFIG_SERIAL_MULTI)
218void serial_setbrg_dev (unsigned long dev_base)
219#else
220void serial_setbrg(void)
221#endif
wdenk945af8d2003-07-16 21:53:01 +0000222{
Wolfgang Denkc12cffc2006-06-16 17:04:45 +0200223#if defined(CONFIG_SERIAL_MULTI)
224 volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)dev_base;
225#else
wdenk945af8d2003-07-16 21:53:01 +0000226 volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)PSC_BASE;
Wolfgang Denkc12cffc2006-06-16 17:04:45 +0200227#endif
wdenk945af8d2003-07-16 21:53:01 +0000228 unsigned long baseclk, div;
229
230#if defined(CONFIG_MGT5100)
Wolfgang Denk9f221d02005-09-25 01:09:58 +0200231 baseclk = (CFG_MPC5XXX_CLKIN + 16) / 32;
wdenk945af8d2003-07-16 21:53:01 +0000232#elif defined(CONFIG_MPC5200)
wdenk342717f2005-06-27 13:30:03 +0000233 baseclk = (gd->ipb_clk + 16) / 32;
wdenk945af8d2003-07-16 21:53:01 +0000234#endif
235
236 /* set up UART divisor */
wdenk342717f2005-06-27 13:30:03 +0000237 div = (baseclk + (gd->baudrate/2)) / gd->baudrate;
Wolfgang Denk9f221d02005-09-25 01:09:58 +0200238 psc->ctur = (div >> 8) & 0xFF;
239 psc->ctlr = div & 0xff;
wdenk945af8d2003-07-16 21:53:01 +0000240}
Wolfgang Denkc12cffc2006-06-16 17:04:45 +0200241
242#if defined(CONFIG_SERIAL_MULTI)
243int serial0_init(void)
244{
245 return (serial_init_dev(PSC_BASE));
246}
247
248int serial1_init(void)
249{
250 return (serial_init_dev(PSC_BASE2));
251}
252void serial0_setbrg (void)
253{
254 serial_setbrg_dev(PSC_BASE);
255}
256void serial1_setbrg (void)
257{
258 serial_setbrg_dev(PSC_BASE2);
259}
260
261void serial0_putc(const char c)
262{
263 serial_putc_dev(PSC_BASE,c);
264}
265
266void serial1_putc(const char c)
267{
268 serial_putc_dev(PSC_BASE2, c);
269}
270void serial0_puts(const char *s)
271{
272 serial_puts_dev(PSC_BASE, s);
273}
274
275void serial1_puts(const char *s)
276{
277 serial_puts_dev(PSC_BASE2, s);
278}
279
280int serial0_getc(void)
281{
282 return(serial_getc_dev(PSC_BASE));
283}
284
285int serial1_getc(void)
286{
287 return(serial_getc_dev(PSC_BASE2));
288}
289int serial0_tstc(void)
290{
291 return (serial_tstc_dev(PSC_BASE));
292}
293
294int serial1_tstc(void)
295{
296 return (serial_tstc_dev(PSC_BASE2));
297}
298
299struct serial_device serial0_device =
300{
301 "serial0",
302 "UART0",
303 serial0_init,
304 serial0_setbrg,
305 serial0_getc,
306 serial0_tstc,
307 serial0_putc,
308 serial0_puts,
309};
310
311struct serial_device serial1_device =
312{
313 "serial1",
314 "UART1",
315 serial1_init,
316 serial1_setbrg,
317 serial1_getc,
318 serial1_tstc,
319 serial1_putc,
320 serial1_puts,
321};
322#endif /* CONFIG_SERIAL_MULTI */
323
wdenk945af8d2003-07-16 21:53:01 +0000324#endif /* CONFIG_PSC_CONSOLE */