Coding style cleanup
[platform/kernel/u-boot.git] / cpu / ppc4xx / serial.c
1 /*
2  * (C) Copyright 2000-2006
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 /*------------------------------------------------------------------------------+ */
24 /*
25  * This source code has been made available to you by IBM on an AS-IS
26  * basis.  Anyone receiving this source is licensed under IBM
27  * copyrights to use it in any way he or she deems fit, including
28  * copying it, modifying it, compiling it, and redistributing it either
29  * with or without modifications.  No license under IBM patents or
30  * patent applications is to be implied by the copyright license.
31  *
32  * Any user of this software should understand that IBM cannot provide
33  * technical support for this software and will not be responsible for
34  * any consequences resulting from the use of this software.
35  *
36  * Any person who transfers this source code or any derivative work
37  * must include the IBM copyright notice, this paragraph, and the
38  * preceding two paragraphs in the transferred software.
39  *
40  * COPYRIGHT   I B M   CORPORATION 1995
41  * LICENSED MATERIAL  -  PROGRAM PROPERTY OF I B M
42  */
43 /*------------------------------------------------------------------------------- */
44 /*
45  * Travis Sawyer 15 September 2004
46  *    Added CONFIG_SERIAL_MULTI support
47  */
48 #include <common.h>
49 #include <commproc.h>
50 #include <asm/processor.h>
51 #include <watchdog.h>
52 #include "vecnum.h"
53
54 #ifdef CONFIG_SERIAL_MULTI
55 #include <serial.h>
56 #endif
57
58 #ifdef CONFIG_SERIAL_SOFTWARE_FIFO
59 #include <malloc.h>
60 #endif
61
62 DECLARE_GLOBAL_DATA_PTR;
63
64 /*****************************************************************************/
65 #ifdef CONFIG_IOP480
66
67 #define SPU_BASE         0x40000000
68
69 #define spu_LineStat_rc  0x00   /* Line Status Register (Read/Clear) */
70 #define spu_LineStat_w   0x04   /* Line Status Register (Set) */
71 #define spu_Handshk_rc   0x08   /* Handshake Status Register (Read/Clear) */
72 #define spu_Handshk_w    0x0c   /* Handshake Status Register (Set) */
73 #define spu_BRateDivh    0x10   /* Baud rate divisor high */
74 #define spu_BRateDivl    0x14   /* Baud rate divisor low */
75 #define spu_CtlReg       0x18   /* Control Register */
76 #define spu_RxCmd        0x1c   /* Rx Command Register */
77 #define spu_TxCmd        0x20   /* Tx Command Register */
78 #define spu_RxBuff       0x24   /* Rx data buffer */
79 #define spu_TxBuff       0x24   /* Tx data buffer */
80
81 /*-----------------------------------------------------------------------------+
82   | Line Status Register.
83   +-----------------------------------------------------------------------------*/
84 #define asyncLSRport1           0x40000000
85 #define asyncLSRport1set        0x40000004
86 #define asyncLSRDataReady             0x80
87 #define asyncLSRFramingError          0x40
88 #define asyncLSROverrunError          0x20
89 #define asyncLSRParityError           0x10
90 #define asyncLSRBreakInterrupt        0x08
91 #define asyncLSRTxHoldEmpty           0x04
92 #define asyncLSRTxShiftEmpty          0x02
93
94 /*-----------------------------------------------------------------------------+
95   | Handshake Status Register.
96   +-----------------------------------------------------------------------------*/
97 #define asyncHSRport1           0x40000008
98 #define asyncHSRport1set        0x4000000c
99 #define asyncHSRDsr                   0x80
100 #define asyncLSRCts                   0x40
101
102 /*-----------------------------------------------------------------------------+
103   | Control Register.
104   +-----------------------------------------------------------------------------*/
105 #define asyncCRport1            0x40000018
106 #define asyncCRNormal                 0x00
107 #define asyncCRLoopback               0x40
108 #define asyncCRAutoEcho               0x80
109 #define asyncCRDtr                    0x20
110 #define asyncCRRts                    0x10
111 #define asyncCRWordLength7            0x00
112 #define asyncCRWordLength8            0x08
113 #define asyncCRParityDisable          0x00
114 #define asyncCRParityEnable           0x04
115 #define asyncCREvenParity             0x00
116 #define asyncCROddParity              0x02
117 #define asyncCRStopBitsOne            0x00
118 #define asyncCRStopBitsTwo            0x01
119 #define asyncCRDisableDtrRts          0x00
120
121 /*-----------------------------------------------------------------------------+
122   | Receiver Command Register.
123   +-----------------------------------------------------------------------------*/
124 #define asyncRCRport1           0x4000001c
125 #define asyncRCRDisable               0x00
126 #define asyncRCREnable                0x80
127 #define asyncRCRIntDisable            0x00
128 #define asyncRCRIntEnabled            0x20
129 #define asyncRCRDMACh2                0x40
130 #define asyncRCRDMACh3                0x60
131 #define asyncRCRErrorInt              0x10
132 #define asyncRCRPauseEnable           0x08
133
134 /*-----------------------------------------------------------------------------+
135   | Transmitter Command Register.
136   +-----------------------------------------------------------------------------*/
137 #define asyncTCRport1           0x40000020
138 #define asyncTCRDisable               0x00
139 #define asyncTCREnable                0x80
140 #define asyncTCRIntDisable            0x00
141 #define asyncTCRIntEnabled            0x20
142 #define asyncTCRDMACh2                0x40
143 #define asyncTCRDMACh3                0x60
144 #define asyncTCRTxEmpty               0x10
145 #define asyncTCRErrorInt              0x08
146 #define asyncTCRStopPause             0x04
147 #define asyncTCRBreakGen              0x02
148
149 /*-----------------------------------------------------------------------------+
150   | Miscellanies defines.
151   +-----------------------------------------------------------------------------*/
152 #define asyncTxBufferport1      0x40000024
153 #define asyncRxBufferport1      0x40000024
154 #define asyncDLABLsbport1       0x40000014
155 #define asyncDLABMsbport1       0x40000010
156 #define asyncXOFFchar                 0x13
157 #define asyncXONchar                  0x11
158
159 /*
160  * Minimal serial functions needed to use one of the SMC ports
161  * as serial console interface.
162  */
163
164 int serial_init (void)
165 {
166         volatile char val;
167         unsigned short br_reg;
168
169         br_reg = ((((CONFIG_CPUCLOCK * 1000000) / 16) / gd->baudrate) - 1);
170
171         /*
172          * Init onboard UART
173          */
174         out8 (SPU_BASE + spu_LineStat_rc, 0x78); /* Clear all bits in Line Status Reg */
175         out8 (SPU_BASE + spu_BRateDivl, (br_reg & 0x00ff)); /* Set baud rate divisor... */
176         out8 (SPU_BASE + spu_BRateDivh, ((br_reg & 0xff00) >> 8)); /* ... */
177         out8 (SPU_BASE + spu_CtlReg, 0x08);     /* Set 8 bits, no parity and 1 stop bit */
178         out8 (SPU_BASE + spu_RxCmd, 0xb0);      /* Enable Rx */
179         out8 (SPU_BASE + spu_TxCmd, 0x9c);      /* Enable Tx */
180         out8 (SPU_BASE + spu_Handshk_rc, 0xff); /* Clear Handshake */
181         val = in8 (SPU_BASE + spu_RxBuff);      /* Dummy read, to clear receiver */
182
183         return (0);
184 }
185
186 void serial_setbrg (void)
187 {
188         unsigned short br_reg;
189
190         br_reg = ((((CONFIG_CPUCLOCK * 1000000) / 16) / gd->baudrate) - 1);
191
192         out8 (SPU_BASE + spu_BRateDivl, (br_reg & 0x00ff)); /* Set baud rate divisor... */
193         out8 (SPU_BASE + spu_BRateDivh, ((br_reg & 0xff00) >> 8)); /* ... */
194 }
195
196 void serial_putc (const char c)
197 {
198         if (c == '\n')
199                 serial_putc ('\r');
200
201         /* load status from handshake register */
202         if (in8 (SPU_BASE + spu_Handshk_rc) != 00)
203                 out8 (SPU_BASE + spu_Handshk_rc, 0xff); /* Clear Handshake */
204
205         out8 (SPU_BASE + spu_TxBuff, c);        /* Put char */
206
207         while ((in8 (SPU_BASE + spu_LineStat_rc) & 04) != 04) {
208                 if (in8 (SPU_BASE + spu_Handshk_rc) != 00)
209                         out8 (SPU_BASE + spu_Handshk_rc, 0xff); /* Clear Handshake */
210         }
211 }
212
213 void serial_puts (const char *s)
214 {
215         while (*s) {
216                 serial_putc (*s++);
217         }
218 }
219
220 int serial_getc ()
221 {
222         unsigned char status = 0;
223
224         while (1) {
225                 status = in8 (asyncLSRport1);
226                 if ((status & asyncLSRDataReady) != 0x0) {
227                         break;
228                 }
229                 if ((status & ( asyncLSRFramingError |
230                                 asyncLSROverrunError |
231                                 asyncLSRParityError  |
232                                 asyncLSRBreakInterrupt )) != 0) {
233                         (void) out8 (asyncLSRport1,
234                                      asyncLSRFramingError |
235                                      asyncLSROverrunError |
236                                      asyncLSRParityError  |
237                                      asyncLSRBreakInterrupt );
238                 }
239         }
240         return (0x000000ff & (int) in8 (asyncRxBufferport1));
241 }
242
243 int serial_tstc ()
244 {
245         unsigned char status;
246
247         status = in8 (asyncLSRport1);
248         if ((status & asyncLSRDataReady) != 0x0) {
249                 return (1);
250         }
251         if ((status & ( asyncLSRFramingError |
252                         asyncLSROverrunError |
253                         asyncLSRParityError  |
254                         asyncLSRBreakInterrupt )) != 0) {
255                 (void) out8 (asyncLSRport1,
256                              asyncLSRFramingError |
257                              asyncLSROverrunError |
258                              asyncLSRParityError  |
259                              asyncLSRBreakInterrupt);
260         }
261         return 0;
262 }
263
264 #endif  /* CONFIG_IOP480 */
265
266 /*****************************************************************************/
267 #if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
268     defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
269     defined(CONFIG_440)
270
271 #if defined(CONFIG_440)
272 #if defined(CONFIG_440EP) || defined(CONFIG_440GR) || \
273     defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
274 #define UART0_BASE  CFG_PERIPHERAL_BASE + 0x00000300
275 #define UART1_BASE  CFG_PERIPHERAL_BASE + 0x00000400
276 #else
277 #define UART0_BASE  CFG_PERIPHERAL_BASE + 0x00000200
278 #define UART1_BASE  CFG_PERIPHERAL_BASE + 0x00000300
279 #endif
280
281 #if defined(CONFIG_440SP) || defined(CONFIG_440SPE)
282 #define UART2_BASE  CFG_PERIPHERAL_BASE + 0x00000600
283 #endif
284
285 #if defined(CONFIG_440GP)
286 #define CR0_MASK        0x3fff0000
287 #define CR0_EXTCLK_ENA  0x00600000
288 #define CR0_UDIV_POS    16
289 #define UDIV_SUBTRACT   1
290 #define UART0_SDR       cntrl0
291 #define MFREG(a, d)     d = mfdcr(a)
292 #define MTREG(a, d)     mtdcr(a, d)
293 #else /* #if defined(CONFIG_440GP) */
294 /* all other 440 PPC's access clock divider via sdr register */
295 #define CR0_MASK        0xdfffffff
296 #define CR0_EXTCLK_ENA  0x00800000
297 #define CR0_UDIV_POS    0
298 #define UDIV_SUBTRACT   0
299 #define UART0_SDR       sdr_uart0
300 #define UART1_SDR       sdr_uart1
301 #if defined(CONFIG_440EP) || defined(CONFIG_440EPx) || \
302     defined(CONFIG_440GR) || defined(CONFIG_440GRx) || \
303     defined(CONFIG_440SP) || defined(CONFIG_440SPe)
304 #define UART2_SDR       sdr_uart2
305 #endif
306 #if defined(CONFIG_440EP) || defined(CONFIG_440EPx) || \
307     defined(CONFIG_440GR) || defined(CONFIG_440GRx)
308 #define UART3_SDR       sdr_uart3
309 #endif
310 #define MFREG(a, d)     mfsdr(a, d)
311 #define MTREG(a, d)     mtsdr(a, d)
312 #endif /* #if defined(CONFIG_440GP) */
313 #elif defined(CONFIG_405EP) || defined(CONFIG_405EZ)
314 #define UART0_BASE      0xef600300
315 #define UART1_BASE      0xef600400
316 #define UCR0_MASK       0x0000007f
317 #define UCR1_MASK       0x00007f00
318 #define UCR0_UDIV_POS   0
319 #define UCR1_UDIV_POS   8
320 #define UDIV_MAX        127
321 #else /* CONFIG_405GP || CONFIG_405CR */
322 #define UART0_BASE      0xef600300
323 #define UART1_BASE      0xef600400
324 #define CR0_MASK        0x00001fff
325 #define CR0_EXTCLK_ENA  0x000000c0
326 #define CR0_UDIV_POS    1
327 #define UDIV_MAX        32
328 #endif
329
330 /* using serial port 0 or 1 as U-Boot console ? */
331 #if defined(CONFIG_UART1_CONSOLE)
332 #define ACTING_UART0_BASE       UART1_BASE
333 #define ACTING_UART1_BASE       UART0_BASE
334 #else
335 #define ACTING_UART0_BASE       UART0_BASE
336 #define ACTING_UART1_BASE       UART1_BASE
337 #endif
338
339 #if defined(CONFIG_SERIAL_MULTI)
340 #define UART_BASE       dev_base
341 #else
342 #define UART_BASE       ACTING_UART0_BASE
343 #endif
344
345 #if defined(CONFIG_405EP) && defined(CFG_EXT_SERIAL_CLOCK)
346 #error "External serial clock not supported on AMCC PPC405EP!"
347 #endif
348
349 #define UART_RBR    0x00
350 #define UART_THR    0x00
351 #define UART_IER    0x01
352 #define UART_IIR    0x02
353 #define UART_FCR    0x02
354 #define UART_LCR    0x03
355 #define UART_MCR    0x04
356 #define UART_LSR    0x05
357 #define UART_MSR    0x06
358 #define UART_SCR    0x07
359 #define UART_DLL    0x00
360 #define UART_DLM    0x01
361
362 /*-----------------------------------------------------------------------------+
363   | Line Status Register.
364   +-----------------------------------------------------------------------------*/
365 /*#define asyncLSRport1           ACTING_UART0_BASE+0x05 */
366 #define asyncLSRDataReady1            0x01
367 #define asyncLSROverrunError1         0x02
368 #define asyncLSRParityError1          0x04
369 #define asyncLSRFramingError1         0x08
370 #define asyncLSRBreakInterrupt1       0x10
371 #define asyncLSRTxHoldEmpty1          0x20
372 #define asyncLSRTxShiftEmpty1         0x40
373 #define asyncLSRRxFifoError1          0x80
374
375 /*-----------------------------------------------------------------------------+
376   | Miscellanies defines.
377   +-----------------------------------------------------------------------------*/
378 /*#define asyncTxBufferport1      ACTING_UART0_BASE+0x00 */
379 /*#define asyncRxBufferport1      ACTING_UART0_BASE+0x00 */
380
381 #ifdef CONFIG_SERIAL_SOFTWARE_FIFO
382 /*-----------------------------------------------------------------------------+
383   | Fifo
384   +-----------------------------------------------------------------------------*/
385 typedef struct {
386         char *rx_buffer;
387         ulong rx_put;
388         ulong rx_get;
389 } serial_buffer_t;
390
391 volatile static serial_buffer_t buf_info;
392 #endif
393
394 #if defined(CONFIG_440) && !defined(CFG_EXT_SERIAL_CLOCK)
395 static void serial_divs (int baudrate, unsigned long *pudiv,
396                          unsigned short *pbdiv)
397 {
398         sys_info_t sysinfo;
399         unsigned long div;              /* total divisor udiv * bdiv */
400         unsigned long umin;             /* minimum udiv */
401         unsigned short diff;            /* smallest diff */
402         unsigned long udiv;             /* best udiv */
403         unsigned short idiff;           /* current diff */
404         unsigned short ibdiv;           /* current bdiv */
405         unsigned long i;
406         unsigned long est;              /* current estimate */
407
408         get_sys_info(&sysinfo);
409
410         udiv = 32;                      /* Assume lowest possible serial clk */
411         div = sysinfo.freqPLB / (16 * baudrate); /* total divisor */
412         umin = sysinfo.pllOpbDiv << 1;  /* 2 x OPB divisor */
413         diff = 32;                      /* highest possible */
414
415         /* i is the test udiv value -- start with the largest
416          * possible (32) to minimize serial clock and constrain
417          * search to umin.
418          */
419         for (i = 32; i > umin; i--) {
420                 ibdiv = div / i;
421                 est = i * ibdiv;
422                 idiff = (est > div) ? (est-div) : (div-est);
423                 if (idiff == 0) {
424                         udiv = i;
425                         break;      /* can't do better */
426                 } else if (idiff < diff) {
427                         udiv = i;       /* best so far */
428                         diff = idiff;   /* update lowest diff*/
429                 }
430         }
431
432         *pudiv = udiv;
433         *pbdiv = div / udiv;
434 }
435
436 #elif defined(CONFIG_405EZ)
437
438 static void serial_divs (int baudrate, unsigned long *pudiv,
439                          unsigned short *pbdiv)
440 {
441         sys_info_t sysinfo;
442         unsigned long div;              /* total divisor udiv * bdiv */
443         unsigned long umin;             /* minimum udiv */
444         unsigned short diff;            /* smallest diff */
445         unsigned long udiv;             /* best udiv */
446         unsigned short idiff;           /* current diff */
447         unsigned short ibdiv;           /* current bdiv */
448         unsigned long i;
449         unsigned long est;              /* current estimate */
450         unsigned long plloutb;
451         u32 reg;
452
453         get_sys_info(&sysinfo);
454
455         plloutb = ((CONFIG_SYS_CLK_FREQ * sysinfo.pllFwdDiv * sysinfo.pllFbkDiv)
456                    / sysinfo.pllFwdDivB);
457         udiv = 256;                     /* Assume lowest possible serial clk */
458         div = plloutb / (16 * baudrate); /* total divisor */
459         umin = (plloutb / get_OPB_freq()) << 1; /* 2 x OPB divisor */
460         diff = 256;                     /* highest possible */
461
462         /* i is the test udiv value -- start with the largest
463          * possible (256) to minimize serial clock and constrain
464          * search to umin.
465          */
466         for (i = 256; i > umin; i--) {
467                 ibdiv = div / i;
468                 est = i * ibdiv;
469                 idiff = (est > div) ? (est-div) : (div-est);
470                 if (idiff == 0) {
471                         udiv = i;
472                         break;      /* can't do better */
473                 } else if (idiff < diff) {
474                         udiv = i;       /* best so far */
475                         diff = idiff;   /* update lowest diff*/
476                 }
477         }
478
479         *pudiv = udiv;
480         mfcpr(cprperd0, reg);
481         reg &= ~0x0000ffff;
482         reg |= ((udiv - 0) << 8) | (udiv - 0);
483         mtcpr(cprperd0, reg);
484         *pbdiv = div / udiv;
485 }
486 #endif /* defined(CONFIG_440) && !defined(CFG_EXT_SERIAL_CLK) */
487
488 /*
489  * Minimal serial functions needed to use one of the SMC ports
490  * as serial console interface.
491  */
492
493 #if defined(CONFIG_440)
494 #if defined(CONFIG_SERIAL_MULTI)
495 int serial_init_dev (unsigned long dev_base)
496 #else
497 int serial_init(void)
498 #endif
499 {
500         unsigned long reg;
501         unsigned long udiv;
502         unsigned short bdiv;
503         volatile char val;
504 #ifdef CFG_EXT_SERIAL_CLOCK
505         unsigned long tmp;
506 #endif
507
508         MFREG(UART0_SDR, reg);
509         reg &= ~CR0_MASK;
510
511 #ifdef CFG_EXT_SERIAL_CLOCK
512         reg |= CR0_EXTCLK_ENA;
513         udiv = 1;
514         tmp  = gd->baudrate * 16;
515         bdiv = (CFG_EXT_SERIAL_CLOCK + tmp / 2) / tmp;
516 #else
517         /* For 440, the cpu clock is on divider chain A, UART on divider
518          * chain B ... so cpu clock is irrelevant. Get the "optimized"
519          * values that are subject to the 1/2 opb clock constraint
520          */
521         serial_divs (gd->baudrate, &udiv, &bdiv);
522 #endif
523
524         reg |= (udiv - UDIV_SUBTRACT) << CR0_UDIV_POS;  /* set the UART divisor */
525
526         /*
527          * Configure input clock to baudrate generator for all
528          * available serial ports here
529          */
530         MTREG(UART0_SDR, reg);
531 #if defined(UART1_SDR)
532         MTREG(UART1_SDR, reg);
533 #endif
534 #if defined(UART2_SDR)
535         MTREG(UART2_SDR, reg);
536 #endif
537 #if defined(UART3_SDR)
538         MTREG(UART3_SDR, reg);
539 #endif
540
541         out8(UART_BASE + UART_LCR, 0x80);       /* set DLAB bit */
542         out8(UART_BASE + UART_DLL, bdiv);       /* set baudrate divisor */
543         out8(UART_BASE + UART_DLM, bdiv >> 8);  /* set baudrate divisor */
544         out8(UART_BASE + UART_LCR, 0x03);       /* clear DLAB; set 8 bits, no parity */
545         out8(UART_BASE + UART_FCR, 0x00);       /* disable FIFO */
546         out8(UART_BASE + UART_MCR, 0x00);       /* no modem control DTR RTS */
547         val = in8(UART_BASE + UART_LSR);        /* clear line status */
548         val = in8(UART_BASE + UART_RBR);        /* read receive buffer */
549         out8(UART_BASE + UART_SCR, 0x00);       /* set scratchpad */
550         out8(UART_BASE + UART_IER, 0x00);       /* set interrupt enable reg */
551
552         return (0);
553 }
554
555 #else /* !defined(CONFIG_440) */
556
557 #if defined(CONFIG_SERIAL_MULTI)
558 int serial_init_dev (unsigned long dev_base)
559 #else
560 int serial_init (void)
561 #endif
562 {
563         unsigned long reg;
564         unsigned long tmp;
565         unsigned long clk;
566         unsigned long udiv;
567         unsigned short bdiv;
568         volatile char val;
569
570 #if defined(CONFIG_405EZ)
571         serial_divs(gd->baudrate, &udiv, &bdiv);
572         clk = tmp = reg = 0;
573 #else
574 #ifdef CONFIG_405EP
575         reg = mfdcr(cpc0_ucr) & ~(UCR0_MASK | UCR1_MASK);
576         clk = gd->cpu_clk;
577         tmp = CFG_BASE_BAUD * 16;
578         udiv = (clk + tmp / 2) / tmp;
579         if (udiv > UDIV_MAX)                    /* max. n bits for udiv */
580                 udiv = UDIV_MAX;
581         reg |= (udiv) << UCR0_UDIV_POS;         /* set the UART divisor */
582         reg |= (udiv) << UCR1_UDIV_POS;         /* set the UART divisor */
583         mtdcr (cpc0_ucr, reg);
584 #else /* CONFIG_405EP */
585         reg = mfdcr(cntrl0) & ~CR0_MASK;
586 #ifdef CFG_EXT_SERIAL_CLOCK
587         clk = CFG_EXT_SERIAL_CLOCK;
588         udiv = 1;
589         reg |= CR0_EXTCLK_ENA;
590 #else
591         clk = gd->cpu_clk;
592 #ifdef CFG_405_UART_ERRATA_59
593         udiv = 31;                      /* Errata 59: stuck at 31 */
594 #else
595         tmp = CFG_BASE_BAUD * 16;
596         udiv = (clk + tmp / 2) / tmp;
597         if (udiv > UDIV_MAX)                    /* max. n bits for udiv */
598                 udiv = UDIV_MAX;
599 #endif
600 #endif
601         reg |= (udiv - 1) << CR0_UDIV_POS;      /* set the UART divisor */
602         mtdcr (cntrl0, reg);
603 #endif /* CONFIG_405EP */
604         tmp = gd->baudrate * udiv * 16;
605         bdiv = (clk + tmp / 2) / tmp;
606 #endif /* CONFIG_405EZ */
607
608         out8(UART_BASE + UART_LCR, 0x80);       /* set DLAB bit */
609         out8(UART_BASE + UART_DLL, bdiv);       /* set baudrate divisor */
610         out8(UART_BASE + UART_DLM, bdiv >> 8);  /* set baudrate divisor */
611         out8(UART_BASE + UART_LCR, 0x03);       /* clear DLAB; set 8 bits, no parity */
612         out8(UART_BASE + UART_FCR, 0x00);       /* disable FIFO */
613         out8(UART_BASE + UART_MCR, 0x00);       /* no modem control DTR RTS */
614         val = in8(UART_BASE + UART_LSR);        /* clear line status */
615         val = in8(UART_BASE + UART_RBR);        /* read receive buffer */
616         out8(UART_BASE + UART_SCR, 0x00);       /* set scratchpad */
617         out8(UART_BASE + UART_IER, 0x00);       /* set interrupt enable reg */
618
619         return (0);
620 }
621
622 #endif /* if defined(CONFIG_440) */
623
624 #if defined(CONFIG_SERIAL_MULTI)
625 void serial_setbrg_dev (unsigned long dev_base)
626 #else
627 void serial_setbrg (void)
628 #endif
629 {
630 #if defined(CONFIG_SERIAL_MULTI)
631         serial_init_dev(dev_base);
632 #else
633         serial_init();
634 #endif
635 }
636
637 #if defined(CONFIG_SERIAL_MULTI)
638 void serial_putc_dev (unsigned long dev_base, const char c)
639 #else
640 void serial_putc (const char c)
641 #endif
642 {
643         int i;
644
645         if (c == '\n')
646 #if defined(CONFIG_SERIAL_MULTI)
647                 serial_putc_dev (dev_base, '\r');
648 #else
649                 serial_putc ('\r');
650 #endif
651
652         /* check THRE bit, wait for transmiter available */
653         for (i = 1; i < 3500; i++) {
654                 if ((in8 (UART_BASE + UART_LSR) & 0x20) == 0x20)
655                         break;
656                 udelay (100);
657         }
658         out8 (UART_BASE + UART_THR, c); /* put character out */
659 }
660
661 #if defined(CONFIG_SERIAL_MULTI)
662 void serial_puts_dev (unsigned long dev_base, const char *s)
663 #else
664 void serial_puts (const char *s)
665 #endif
666 {
667         while (*s) {
668 #if defined(CONFIG_SERIAL_MULTI)
669                 serial_putc_dev (dev_base, *s++);
670 #else
671                 serial_putc (*s++);
672 #endif
673         }
674 }
675
676 #if defined(CONFIG_SERIAL_MULTI)
677 int serial_getc_dev (unsigned long dev_base)
678 #else
679 int serial_getc (void)
680 #endif
681 {
682         unsigned char status = 0;
683
684         while (1) {
685 #if defined(CONFIG_HW_WATCHDOG)
686                 WATCHDOG_RESET ();      /* Reset HW Watchdog, if needed */
687 #endif  /* CONFIG_HW_WATCHDOG */
688                 status = in8 (UART_BASE + UART_LSR);
689                 if ((status & asyncLSRDataReady1) != 0x0) {
690                         break;
691                 }
692                 if ((status & ( asyncLSRFramingError1 |
693                                 asyncLSROverrunError1 |
694                                 asyncLSRParityError1  |
695                                 asyncLSRBreakInterrupt1 )) != 0) {
696                         out8 (UART_BASE + UART_LSR,
697                               asyncLSRFramingError1 |
698                               asyncLSROverrunError1 |
699                               asyncLSRParityError1  |
700                               asyncLSRBreakInterrupt1);
701                 }
702         }
703         return (0x000000ff & (int) in8 (UART_BASE));
704 }
705
706 #if defined(CONFIG_SERIAL_MULTI)
707 int serial_tstc_dev (unsigned long dev_base)
708 #else
709 int serial_tstc (void)
710 #endif
711 {
712         unsigned char status;
713
714         status = in8 (UART_BASE + UART_LSR);
715         if ((status & asyncLSRDataReady1) != 0x0) {
716                 return (1);
717         }
718         if ((status & ( asyncLSRFramingError1 |
719                         asyncLSROverrunError1 |
720                         asyncLSRParityError1  |
721                         asyncLSRBreakInterrupt1 )) != 0) {
722                 out8 (UART_BASE + UART_LSR,
723                       asyncLSRFramingError1 |
724                       asyncLSROverrunError1 |
725                       asyncLSRParityError1  |
726                       asyncLSRBreakInterrupt1);
727         }
728         return 0;
729 }
730
731 #ifdef CONFIG_SERIAL_SOFTWARE_FIFO
732
733 void serial_isr (void *arg)
734 {
735         int space;
736         int c;
737         const int rx_get = buf_info.rx_get;
738         int rx_put = buf_info.rx_put;
739
740         if (rx_get <= rx_put) {
741                 space = CONFIG_SERIAL_SOFTWARE_FIFO - (rx_put - rx_get);
742         } else {
743                 space = rx_get - rx_put;
744         }
745         while (serial_tstc_dev (ACTING_UART0_BASE)) {
746                 c = serial_getc_dev (ACTING_UART0_BASE);
747                 if (space) {
748                         buf_info.rx_buffer[rx_put++] = c;
749                         space--;
750                 }
751                 if (rx_put == CONFIG_SERIAL_SOFTWARE_FIFO)
752                         rx_put = 0;
753                 if (space < CONFIG_SERIAL_SOFTWARE_FIFO / 4) {
754                         /* Stop flow by setting RTS inactive */
755                         out8 (ACTING_UART0_BASE + UART_MCR,
756                               in8 (ACTING_UART0_BASE + UART_MCR) & (0xFF ^ 0x02));
757                 }
758         }
759         buf_info.rx_put = rx_put;
760 }
761
762 void serial_buffered_init (void)
763 {
764         serial_puts ("Switching to interrupt driven serial input mode.\n");
765         buf_info.rx_buffer = malloc (CONFIG_SERIAL_SOFTWARE_FIFO);
766         buf_info.rx_put = 0;
767         buf_info.rx_get = 0;
768
769         if (in8 (ACTING_UART0_BASE + UART_MSR) & 0x10) {
770                 serial_puts ("Check CTS signal present on serial port: OK.\n");
771         } else {
772                 serial_puts ("WARNING: CTS signal not present on serial port.\n");
773         }
774
775         irq_install_handler ( VECNUM_U0 /*UART0 */ /*int vec */ ,
776                               serial_isr /*interrupt_handler_t *handler */ ,
777                               (void *) &buf_info /*void *arg */ );
778
779         /* Enable "RX Data Available" Interrupt on UART */
780         /* out8(ACTING_UART0_BASE + UART_IER, in8(ACTING_UART0_BASE + UART_IER) |0x01); */
781         out8 (ACTING_UART0_BASE + UART_IER, 0x01);
782         /* Set DTR active */
783         out8 (ACTING_UART0_BASE + UART_MCR, in8 (ACTING_UART0_BASE + UART_MCR) | 0x01);
784         /* Start flow by setting RTS active */
785         out8 (ACTING_UART0_BASE + UART_MCR, in8 (ACTING_UART0_BASE + UART_MCR) | 0x02);
786         /* Setup UART FIFO: RX trigger level: 4 byte, Enable FIFO */
787         out8 (ACTING_UART0_BASE + UART_FCR, (1 << 6) | 1);
788 }
789
790 void serial_buffered_putc (const char c)
791 {
792         /* Wait for CTS */
793 #if defined(CONFIG_HW_WATCHDOG)
794         while (!(in8 (ACTING_UART0_BASE + UART_MSR) & 0x10))
795                 WATCHDOG_RESET ();
796 #else
797         while (!(in8 (ACTING_UART0_BASE + UART_MSR) & 0x10));
798 #endif
799         serial_putc (c);
800 }
801
802 void serial_buffered_puts (const char *s)
803 {
804         serial_puts (s);
805 }
806
807 int serial_buffered_getc (void)
808 {
809         int space;
810         int c;
811         int rx_get = buf_info.rx_get;
812         int rx_put;
813
814 #if defined(CONFIG_HW_WATCHDOG)
815         while (rx_get == buf_info.rx_put)
816                 WATCHDOG_RESET ();
817 #else
818         while (rx_get == buf_info.rx_put);
819 #endif
820         c = buf_info.rx_buffer[rx_get++];
821         if (rx_get == CONFIG_SERIAL_SOFTWARE_FIFO)
822                 rx_get = 0;
823         buf_info.rx_get = rx_get;
824
825         rx_put = buf_info.rx_put;
826         if (rx_get <= rx_put) {
827                 space = CONFIG_SERIAL_SOFTWARE_FIFO - (rx_put - rx_get);
828         } else {
829                 space = rx_get - rx_put;
830         }
831         if (space > CONFIG_SERIAL_SOFTWARE_FIFO / 2) {
832                 /* Start flow by setting RTS active */
833                 out8 (ACTING_UART0_BASE + UART_MCR, in8 (ACTING_UART0_BASE + UART_MCR) | 0x02);
834         }
835
836         return c;
837 }
838
839 int serial_buffered_tstc (void)
840 {
841         return (buf_info.rx_get != buf_info.rx_put) ? 1 : 0;
842 }
843
844 #endif  /* CONFIG_SERIAL_SOFTWARE_FIFO */
845
846 #if (CONFIG_COMMANDS & CFG_CMD_KGDB)
847 /*
848   AS HARNOIS : according to CONFIG_KGDB_SER_INDEX kgdb uses serial port
849   number 0 or number 1
850   - if CONFIG_KGDB_SER_INDEX = 1 => serial port number 0 :
851   configuration has been already done
852   - if CONFIG_KGDB_SER_INDEX = 2 => serial port number 1 :
853   configure port 1 for serial I/O with rate = CONFIG_KGDB_BAUDRATE
854 */
855 #if (CONFIG_KGDB_SER_INDEX & 2)
856 void kgdb_serial_init (void)
857 {
858         volatile char val;
859         unsigned short br_reg;
860
861         get_clocks ();
862         br_reg = (((((gd->cpu_clk / 16) / 18) * 10) / CONFIG_KGDB_BAUDRATE) +
863                   5) / 10;
864         /*
865          * Init onboard 16550 UART
866          */
867         out8 (ACTING_UART1_BASE + UART_LCR, 0x80);      /* set DLAB bit */
868         out8 (ACTING_UART1_BASE + UART_DLL, (br_reg & 0x00ff)); /* set divisor for 9600 baud */
869         out8 (ACTING_UART1_BASE + UART_DLM, ((br_reg & 0xff00) >> 8));  /* set divisor for 9600 baud */
870         out8 (ACTING_UART1_BASE + UART_LCR, 0x03);      /* line control 8 bits no parity */
871         out8 (ACTING_UART1_BASE + UART_FCR, 0x00);      /* disable FIFO */
872         out8 (ACTING_UART1_BASE + UART_MCR, 0x00);      /* no modem control DTR RTS */
873         val = in8 (ACTING_UART1_BASE + UART_LSR);       /* clear line status */
874         val = in8 (ACTING_UART1_BASE + UART_RBR);       /* read receive buffer */
875         out8 (ACTING_UART1_BASE + UART_SCR, 0x00);      /* set scratchpad */
876         out8 (ACTING_UART1_BASE + UART_IER, 0x00);      /* set interrupt enable reg */
877 }
878
879 void putDebugChar (const char c)
880 {
881         if (c == '\n')
882                 serial_putc ('\r');
883
884         out8 (ACTING_UART1_BASE + UART_THR, c); /* put character out */
885
886         /* check THRE bit, wait for transfer done */
887         while ((in8 (ACTING_UART1_BASE + UART_LSR) & 0x20) != 0x20);
888 }
889
890 void putDebugStr (const char *s)
891 {
892         while (*s) {
893                 serial_putc (*s++);
894         }
895 }
896
897 int getDebugChar (void)
898 {
899         unsigned char status = 0;
900
901         while (1) {
902                 status = in8 (ACTING_UART1_BASE + UART_LSR);
903                 if ((status & asyncLSRDataReady1) != 0x0) {
904                         break;
905                 }
906                 if ((status & ( asyncLSRFramingError1 |
907                                 asyncLSROverrunError1 |
908                                 asyncLSRParityError1  |
909                                 asyncLSRBreakInterrupt1 )) != 0) {
910                         out8 (ACTING_UART1_BASE + UART_LSR,
911                               asyncLSRFramingError1 |
912                               asyncLSROverrunError1 |
913                               asyncLSRParityError1  |
914                               asyncLSRBreakInterrupt1);
915                 }
916         }
917         return (0x000000ff & (int) in8 (ACTING_UART1_BASE));
918 }
919
920 void kgdb_interruptible (int yes)
921 {
922         return;
923 }
924
925 #else   /* ! (CONFIG_KGDB_SER_INDEX & 2) */
926
927 void kgdb_serial_init (void)
928 {
929         serial_printf ("[on serial] ");
930 }
931
932 void putDebugChar (int c)
933 {
934         serial_putc (c);
935 }
936
937 void putDebugStr (const char *str)
938 {
939         serial_puts (str);
940 }
941
942 int getDebugChar (void)
943 {
944         return serial_getc ();
945 }
946
947 void kgdb_interruptible (int yes)
948 {
949         return;
950 }
951 #endif  /* (CONFIG_KGDB_SER_INDEX & 2) */
952 #endif  /* CFG_CMD_KGDB */
953
954
955 #if defined(CONFIG_SERIAL_MULTI)
956 int serial0_init(void)
957 {
958         return (serial_init_dev(UART0_BASE));
959 }
960
961 int serial1_init(void)
962 {
963         return (serial_init_dev(UART1_BASE));
964 }
965 void serial0_setbrg (void)
966 {
967         serial_setbrg_dev(UART0_BASE);
968 }
969 void serial1_setbrg (void)
970 {
971         serial_setbrg_dev(UART1_BASE);
972 }
973
974 void serial0_putc(const char c)
975 {
976         serial_putc_dev(UART0_BASE,c);
977 }
978
979 void serial1_putc(const char c)
980 {
981         serial_putc_dev(UART1_BASE, c);
982 }
983 void serial0_puts(const char *s)
984 {
985         serial_puts_dev(UART0_BASE, s);
986 }
987
988 void serial1_puts(const char *s)
989 {
990         serial_puts_dev(UART1_BASE, s);
991 }
992
993 int serial0_getc(void)
994 {
995         return(serial_getc_dev(UART0_BASE));
996 }
997
998 int serial1_getc(void)
999 {
1000         return(serial_getc_dev(UART1_BASE));
1001 }
1002 int serial0_tstc(void)
1003 {
1004         return (serial_tstc_dev(UART0_BASE));
1005 }
1006
1007 int serial1_tstc(void)
1008 {
1009         return (serial_tstc_dev(UART1_BASE));
1010 }
1011
1012 struct serial_device serial0_device =
1013 {
1014         "serial0",
1015         "UART0",
1016         serial0_init,
1017         serial0_setbrg,
1018         serial0_getc,
1019         serial0_tstc,
1020         serial0_putc,
1021         serial0_puts,
1022 };
1023
1024 struct serial_device serial1_device =
1025 {
1026         "serial1",
1027         "UART1",
1028         serial1_init,
1029         serial1_setbrg,
1030         serial1_getc,
1031         serial1_tstc,
1032         serial1_putc,
1033         serial1_puts,
1034 };
1035 #endif /* CONFIG_SERIAL_MULTI */
1036
1037 #endif  /* CONFIG_405GP || CONFIG_405CR */