ppc4xx: Rework of 4xx serial driver (1)
[oweals/u-boot.git] / cpu / ppc4xx / 4xx_uart.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 #if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
65     defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
66     defined(CONFIG_405EX) || defined(CONFIG_440)
67
68 #if defined(CONFIG_440)
69 #if defined(CONFIG_440EP) || defined(CONFIG_440GR) || \
70     defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
71 #define UART0_BASE  CFG_PERIPHERAL_BASE + 0x00000300
72 #define UART1_BASE  CFG_PERIPHERAL_BASE + 0x00000400
73 #else
74 #define UART0_BASE  CFG_PERIPHERAL_BASE + 0x00000200
75 #define UART1_BASE  CFG_PERIPHERAL_BASE + 0x00000300
76 #endif
77
78 #if defined(CONFIG_440SP) || defined(CONFIG_440SPE)
79 #define UART2_BASE  CFG_PERIPHERAL_BASE + 0x00000600
80 #endif
81
82 #if defined(CONFIG_440GP)
83 #define CR0_MASK        0x3fff0000
84 #define CR0_EXTCLK_ENA  0x00600000
85 #define CR0_UDIV_POS    16
86 #define UDIV_SUBTRACT   1
87 #define UART0_SDR       cntrl0
88 #define MFREG(a, d)     d = mfdcr(a)
89 #define MTREG(a, d)     mtdcr(a, d)
90 #else /* #if defined(CONFIG_440GP) */
91 /* all other 440 PPC's access clock divider via sdr register */
92 #define CR0_MASK        0xdfffffff
93 #define CR0_EXTCLK_ENA  0x00800000
94 #define CR0_UDIV_POS    0
95 #define UDIV_SUBTRACT   0
96 #define UART0_SDR       sdr_uart0
97 #define UART1_SDR       sdr_uart1
98 #if defined(CONFIG_440EP) || defined(CONFIG_440EPx) || \
99     defined(CONFIG_440GR) || defined(CONFIG_440GRx) || \
100     defined(CONFIG_440SP) || defined(CONFIG_440SPe)
101 #define UART2_SDR       sdr_uart2
102 #endif
103 #if defined(CONFIG_440EP) || defined(CONFIG_440EPx) || \
104     defined(CONFIG_440GR) || defined(CONFIG_440GRx)
105 #define UART3_SDR       sdr_uart3
106 #endif
107 #define MFREG(a, d)     mfsdr(a, d)
108 #define MTREG(a, d)     mtsdr(a, d)
109 #endif /* #if defined(CONFIG_440GP) */
110 #elif defined(CONFIG_405EP) || defined(CONFIG_405EZ)
111 #define UART0_BASE      0xef600300
112 #define UART1_BASE      0xef600400
113 #define UCR0_MASK       0x0000007f
114 #define UCR1_MASK       0x00007f00
115 #define UCR0_UDIV_POS   0
116 #define UCR1_UDIV_POS   8
117 #define UDIV_MAX        127
118 #elif defined(CONFIG_405EX)
119 #define UART0_BASE      0xef600200
120 #define UART1_BASE      0xef600300
121 #define CR0_MASK        0x000000ff
122 #define CR0_EXTCLK_ENA  0x00800000
123 #define CR0_UDIV_POS    0
124 #define UDIV_SUBTRACT   0
125 #define UART0_SDR       sdr_uart0
126 #define UART1_SDR       sdr_uart1
127 #else /* CONFIG_405GP || CONFIG_405CR */
128 #define UART0_BASE      0xef600300
129 #define UART1_BASE      0xef600400
130 #define CR0_MASK        0x00001fff
131 #define CR0_EXTCLK_ENA  0x000000c0
132 #define CR0_UDIV_POS    1
133 #define UDIV_MAX        32
134 #endif
135
136 /* using serial port 0 or 1 as U-Boot console ? */
137 #if defined(CONFIG_UART1_CONSOLE)
138 #define ACTING_UART0_BASE       UART1_BASE
139 #define ACTING_UART1_BASE       UART0_BASE
140 #else
141 #define ACTING_UART0_BASE       UART0_BASE
142 #define ACTING_UART1_BASE       UART1_BASE
143 #endif
144
145 #if defined(CONFIG_SERIAL_MULTI)
146 #define UART_BASE       dev_base
147 #else
148 #define UART_BASE       ACTING_UART0_BASE
149 #endif
150
151 #if defined(CONFIG_405EP) && defined(CFG_EXT_SERIAL_CLOCK)
152 #error "External serial clock not supported on AMCC PPC405EP!"
153 #endif
154
155 #define UART_RBR    0x00
156 #define UART_THR    0x00
157 #define UART_IER    0x01
158 #define UART_IIR    0x02
159 #define UART_FCR    0x02
160 #define UART_LCR    0x03
161 #define UART_MCR    0x04
162 #define UART_LSR    0x05
163 #define UART_MSR    0x06
164 #define UART_SCR    0x07
165 #define UART_DLL    0x00
166 #define UART_DLM    0x01
167
168 /*-----------------------------------------------------------------------------+
169   | Line Status Register.
170   +-----------------------------------------------------------------------------*/
171 /*#define asyncLSRport1           ACTING_UART0_BASE+0x05 */
172 #define asyncLSRDataReady1            0x01
173 #define asyncLSROverrunError1         0x02
174 #define asyncLSRParityError1          0x04
175 #define asyncLSRFramingError1         0x08
176 #define asyncLSRBreakInterrupt1       0x10
177 #define asyncLSRTxHoldEmpty1          0x20
178 #define asyncLSRTxShiftEmpty1         0x40
179 #define asyncLSRRxFifoError1          0x80
180
181 /*-----------------------------------------------------------------------------+
182   | Miscellanies defines.
183   +-----------------------------------------------------------------------------*/
184 /*#define asyncTxBufferport1      ACTING_UART0_BASE+0x00 */
185 /*#define asyncRxBufferport1      ACTING_UART0_BASE+0x00 */
186
187 #ifdef CONFIG_SERIAL_SOFTWARE_FIFO
188 /*-----------------------------------------------------------------------------+
189   | Fifo
190   +-----------------------------------------------------------------------------*/
191 typedef struct {
192         char *rx_buffer;
193         ulong rx_put;
194         ulong rx_get;
195 } serial_buffer_t;
196
197 volatile static serial_buffer_t buf_info;
198 #endif
199
200 #if (defined(CONFIG_440) || defined(CONFIG_405EX)) &&  \
201         !defined(CFG_EXT_SERIAL_CLOCK)
202 static void serial_divs (int baudrate, unsigned long *pudiv,
203                          unsigned short *pbdiv)
204 {
205         sys_info_t sysinfo;
206         unsigned long div;              /* total divisor udiv * bdiv */
207         unsigned long umin;             /* minimum udiv */
208         unsigned short diff;            /* smallest diff */
209         unsigned long udiv;             /* best udiv */
210         unsigned short idiff;           /* current diff */
211         unsigned short ibdiv;           /* current bdiv */
212         unsigned long i;
213         unsigned long est;              /* current estimate */
214
215         get_sys_info(&sysinfo);
216
217         udiv = 32;                      /* Assume lowest possible serial clk */
218         div = sysinfo.freqPLB / (16 * baudrate); /* total divisor */
219         umin = sysinfo.pllOpbDiv << 1;  /* 2 x OPB divisor */
220         diff = 32;                      /* highest possible */
221
222         /* i is the test udiv value -- start with the largest
223          * possible (32) to minimize serial clock and constrain
224          * search to umin.
225          */
226         for (i = 32; i > umin; i--) {
227                 ibdiv = div / i;
228                 est = i * ibdiv;
229                 idiff = (est > div) ? (est-div) : (div-est);
230                 if (idiff == 0) {
231                         udiv = i;
232                         break;      /* can't do better */
233                 } else if (idiff < diff) {
234                         udiv = i;       /* best so far */
235                         diff = idiff;   /* update lowest diff*/
236                 }
237         }
238
239         *pudiv = udiv;
240         *pbdiv = div / udiv;
241 }
242
243 #elif defined(CONFIG_405EZ)
244
245 static void serial_divs (int baudrate, unsigned long *pudiv,
246                          unsigned short *pbdiv)
247 {
248         sys_info_t sysinfo;
249         unsigned long div;              /* total divisor udiv * bdiv */
250         unsigned long umin;             /* minimum udiv */
251         unsigned short diff;            /* smallest diff */
252         unsigned long udiv;             /* best udiv */
253         unsigned short idiff;           /* current diff */
254         unsigned short ibdiv;           /* current bdiv */
255         unsigned long i;
256         unsigned long est;              /* current estimate */
257         unsigned long plloutb;
258         unsigned long cpr_pllc;
259         u32 reg;
260
261         /* check the pll feedback source */
262         mfcpr(cprpllc, cpr_pllc);
263
264         get_sys_info(&sysinfo);
265
266         plloutb = ((CONFIG_SYS_CLK_FREQ * ((cpr_pllc & PLLC_SRC_MASK) ?
267                 sysinfo.pllFwdDivB : sysinfo.pllFwdDiv) * sysinfo.pllFbkDiv) /
268                 sysinfo.pllFwdDivB);
269         udiv = 256;                     /* Assume lowest possible serial clk */
270         div = plloutb / (16 * baudrate); /* total divisor */
271         umin = (plloutb / get_OPB_freq()) << 1; /* 2 x OPB divisor */
272         diff = 256;                     /* highest possible */
273
274         /* i is the test udiv value -- start with the largest
275          * possible (256) to minimize serial clock and constrain
276          * search to umin.
277          */
278         for (i = 256; i > umin; i--) {
279                 ibdiv = div / i;
280                 est = i * ibdiv;
281                 idiff = (est > div) ? (est-div) : (div-est);
282                 if (idiff == 0) {
283                         udiv = i;
284                         break;      /* can't do better */
285                 } else if (idiff < diff) {
286                         udiv = i;       /* best so far */
287                         diff = idiff;   /* update lowest diff*/
288                 }
289         }
290
291         *pudiv = udiv;
292         mfcpr(cprperd0, reg);
293         reg &= ~0x0000ffff;
294         reg |= ((udiv - 0) << 8) | (udiv - 0);
295         mtcpr(cprperd0, reg);
296         *pbdiv = div / udiv;
297 }
298 #endif /* defined(CONFIG_440) && !defined(CFG_EXT_SERIAL_CLK) */
299
300 /*
301  * Minimal serial functions needed to use one of the SMC ports
302  * as serial console interface.
303  */
304
305 #if defined(CONFIG_440)
306 #if defined(CONFIG_SERIAL_MULTI)
307 int serial_init_dev (unsigned long dev_base)
308 #else
309 int serial_init(void)
310 #endif
311 {
312         unsigned long reg;
313         unsigned long udiv;
314         unsigned short bdiv;
315         volatile char val;
316 #ifdef CFG_EXT_SERIAL_CLOCK
317         unsigned long tmp;
318 #endif
319
320         MFREG(UART0_SDR, reg);
321         reg &= ~CR0_MASK;
322
323 #ifdef CFG_EXT_SERIAL_CLOCK
324         reg |= CR0_EXTCLK_ENA;
325         udiv = 1;
326         tmp  = gd->baudrate * 16;
327         bdiv = (CFG_EXT_SERIAL_CLOCK + tmp / 2) / tmp;
328         gd->freqUART = CFG_EXT_SERIAL_CLOCK;
329 #else
330         /* For 440, the cpu clock is on divider chain A, UART on divider
331          * chain B ... so cpu clock is irrelevant. Get the "optimized"
332          * values that are subject to the 1/2 opb clock constraint
333          */
334         serial_divs (gd->baudrate, &udiv, &bdiv);
335
336         /* Correct UART frequency in bd-info struct now that
337          * the UART divisor is available
338          */
339         gd->freqUART = gd->freqUART / udiv;
340 #endif
341
342         reg |= (udiv - UDIV_SUBTRACT) << CR0_UDIV_POS;  /* set the UART divisor */
343
344         /*
345          * Configure input clock to baudrate generator for all
346          * available serial ports here
347          */
348         MTREG(UART0_SDR, reg);
349 #if defined(UART1_SDR)
350         MTREG(UART1_SDR, reg);
351 #endif
352 #if defined(UART2_SDR)
353         MTREG(UART2_SDR, reg);
354 #endif
355 #if defined(UART3_SDR)
356         MTREG(UART3_SDR, reg);
357 #endif
358
359         out8(UART_BASE + UART_LCR, 0x80);       /* set DLAB bit */
360         out8(UART_BASE + UART_DLL, bdiv);       /* set baudrate divisor */
361         out8(UART_BASE + UART_DLM, bdiv >> 8);  /* set baudrate divisor */
362         out8(UART_BASE + UART_LCR, 0x03);       /* clear DLAB; set 8 bits, no parity */
363         out8(UART_BASE + UART_FCR, 0x00);       /* disable FIFO */
364         out8(UART_BASE + UART_MCR, 0x00);       /* no modem control DTR RTS */
365         val = in8(UART_BASE + UART_LSR);        /* clear line status */
366         val = in8(UART_BASE + UART_RBR);        /* read receive buffer */
367         out8(UART_BASE + UART_SCR, 0x00);       /* set scratchpad */
368         out8(UART_BASE + UART_IER, 0x00);       /* set interrupt enable reg */
369
370         return (0);
371 }
372
373 #else /* !defined(CONFIG_440) */
374
375 #if defined(CONFIG_SERIAL_MULTI)
376 int serial_init_dev (unsigned long dev_base)
377 #else
378 int serial_init (void)
379 #endif
380 {
381         unsigned long reg;
382         unsigned long tmp;
383         unsigned long clk;
384         unsigned long udiv;
385         unsigned short bdiv;
386         volatile char val;
387
388 #ifdef CONFIG_405EX
389         clk = tmp = 0;
390         mfsdr(UART0_SDR, reg);
391         reg &= ~CR0_MASK;
392 #ifdef CFG_EXT_SERIAL_CLOCK
393         reg |= CR0_EXTCLK_ENA;
394         udiv = 1;
395         tmp  = gd->baudrate * 16;
396         bdiv = (CFG_EXT_SERIAL_CLOCK + tmp / 2) / tmp;
397 #else
398         serial_divs(gd->baudrate, &udiv, &bdiv);
399 #endif
400         reg |= (udiv - UDIV_SUBTRACT) << CR0_UDIV_POS;  /* set the UART divisor */
401
402         /*
403          * Configure input clock to baudrate generator for all
404          * available serial ports here
405          */
406         mtsdr(UART0_SDR, reg);
407
408 #if defined(UART1_SDR)
409         mtsdr(UART1_SDR, reg);
410 #endif
411
412 #elif defined(CONFIG_405EZ)
413         serial_divs(gd->baudrate, &udiv, &bdiv);
414         clk = tmp = reg = 0;
415 #else
416 #ifdef CONFIG_405EP
417         reg = mfdcr(cpc0_ucr) & ~(UCR0_MASK | UCR1_MASK);
418         clk = gd->cpu_clk;
419         tmp = CFG_BASE_BAUD * 16;
420         udiv = (clk + tmp / 2) / tmp;
421         if (udiv > UDIV_MAX)                    /* max. n bits for udiv */
422                 udiv = UDIV_MAX;
423         reg |= (udiv) << UCR0_UDIV_POS;         /* set the UART divisor */
424         reg |= (udiv) << UCR1_UDIV_POS;         /* set the UART divisor */
425         mtdcr (cpc0_ucr, reg);
426 #else /* CONFIG_405EP */
427         reg = mfdcr(cntrl0) & ~CR0_MASK;
428 #ifdef CFG_EXT_SERIAL_CLOCK
429         clk = CFG_EXT_SERIAL_CLOCK;
430         udiv = 1;
431         reg |= CR0_EXTCLK_ENA;
432 #else
433         clk = gd->cpu_clk;
434 #ifdef CFG_405_UART_ERRATA_59
435         udiv = 31;                      /* Errata 59: stuck at 31 */
436 #else
437         tmp = CFG_BASE_BAUD * 16;
438         udiv = (clk + tmp / 2) / tmp;
439         if (udiv > UDIV_MAX)                    /* max. n bits for udiv */
440                 udiv = UDIV_MAX;
441 #endif
442 #endif
443         reg |= (udiv - 1) << CR0_UDIV_POS;      /* set the UART divisor */
444         mtdcr (cntrl0, reg);
445 #endif /* CONFIG_405EP */
446         tmp = gd->baudrate * udiv * 16;
447         bdiv = (clk + tmp / 2) / tmp;
448 #endif /* CONFIG_405EX */
449
450         /* Correct UART frequency in bd-info struct now that
451          * the UART divisor is available
452          */
453 #ifdef CFG_EXT_SERIAL_CLOCK
454         gd->freqUART = CFG_EXT_SERIAL_CLOCK;
455 #else
456         gd->freqUART = gd->freqUART / udiv;
457 #endif
458
459         out8(UART_BASE + UART_LCR, 0x80);       /* set DLAB bit */
460         out8(UART_BASE + UART_DLL, bdiv);       /* set baudrate divisor */
461         out8(UART_BASE + UART_DLM, bdiv >> 8);  /* set baudrate divisor */
462         out8(UART_BASE + UART_LCR, 0x03);       /* clear DLAB; set 8 bits, no parity */
463         out8(UART_BASE + UART_FCR, 0x00);       /* disable FIFO */
464         out8(UART_BASE + UART_MCR, 0x00);       /* no modem control DTR RTS */
465         val = in8(UART_BASE + UART_LSR);        /* clear line status */
466         val = in8(UART_BASE + UART_RBR);        /* read receive buffer */
467         out8(UART_BASE + UART_SCR, 0x00);       /* set scratchpad */
468         out8(UART_BASE + UART_IER, 0x00);       /* set interrupt enable reg */
469
470         return (0);
471 }
472
473 #endif /* if defined(CONFIG_440) */
474
475 #if defined(CONFIG_SERIAL_MULTI)
476 void serial_setbrg_dev (unsigned long dev_base)
477 #else
478 void serial_setbrg (void)
479 #endif
480 {
481 #if defined(CONFIG_SERIAL_MULTI)
482         serial_init_dev(dev_base);
483 #else
484         serial_init();
485 #endif
486 }
487
488 #if defined(CONFIG_SERIAL_MULTI)
489 void serial_putc_dev (unsigned long dev_base, const char c)
490 #else
491 void serial_putc (const char c)
492 #endif
493 {
494         int i;
495
496         if (c == '\n')
497 #if defined(CONFIG_SERIAL_MULTI)
498                 serial_putc_dev (dev_base, '\r');
499 #else
500                 serial_putc ('\r');
501 #endif
502
503         /* check THRE bit, wait for transmiter available */
504         for (i = 1; i < 3500; i++) {
505                 if ((in8 (UART_BASE + UART_LSR) & 0x20) == 0x20)
506                         break;
507                 udelay (100);
508         }
509         out8 (UART_BASE + UART_THR, c); /* put character out */
510 }
511
512 #if defined(CONFIG_SERIAL_MULTI)
513 void serial_puts_dev (unsigned long dev_base, const char *s)
514 #else
515 void serial_puts (const char *s)
516 #endif
517 {
518         while (*s) {
519 #if defined(CONFIG_SERIAL_MULTI)
520                 serial_putc_dev (dev_base, *s++);
521 #else
522                 serial_putc (*s++);
523 #endif
524         }
525 }
526
527 #if defined(CONFIG_SERIAL_MULTI)
528 int serial_getc_dev (unsigned long dev_base)
529 #else
530 int serial_getc (void)
531 #endif
532 {
533         unsigned char status = 0;
534
535         while (1) {
536 #if defined(CONFIG_HW_WATCHDOG)
537                 WATCHDOG_RESET ();      /* Reset HW Watchdog, if needed */
538 #endif  /* CONFIG_HW_WATCHDOG */
539                 status = in8 (UART_BASE + UART_LSR);
540                 if ((status & asyncLSRDataReady1) != 0x0) {
541                         break;
542                 }
543                 if ((status & ( asyncLSRFramingError1 |
544                                 asyncLSROverrunError1 |
545                                 asyncLSRParityError1  |
546                                 asyncLSRBreakInterrupt1 )) != 0) {
547                         out8 (UART_BASE + UART_LSR,
548                               asyncLSRFramingError1 |
549                               asyncLSROverrunError1 |
550                               asyncLSRParityError1  |
551                               asyncLSRBreakInterrupt1);
552                 }
553         }
554         return (0x000000ff & (int) in8 (UART_BASE));
555 }
556
557 #if defined(CONFIG_SERIAL_MULTI)
558 int serial_tstc_dev (unsigned long dev_base)
559 #else
560 int serial_tstc (void)
561 #endif
562 {
563         unsigned char status;
564
565         status = in8 (UART_BASE + UART_LSR);
566         if ((status & asyncLSRDataReady1) != 0x0) {
567                 return (1);
568         }
569         if ((status & ( asyncLSRFramingError1 |
570                         asyncLSROverrunError1 |
571                         asyncLSRParityError1  |
572                         asyncLSRBreakInterrupt1 )) != 0) {
573                 out8 (UART_BASE + UART_LSR,
574                       asyncLSRFramingError1 |
575                       asyncLSROverrunError1 |
576                       asyncLSRParityError1  |
577                       asyncLSRBreakInterrupt1);
578         }
579         return 0;
580 }
581
582 #ifdef CONFIG_SERIAL_SOFTWARE_FIFO
583
584 void serial_isr (void *arg)
585 {
586         int space;
587         int c;
588         const int rx_get = buf_info.rx_get;
589         int rx_put = buf_info.rx_put;
590
591         if (rx_get <= rx_put) {
592                 space = CONFIG_SERIAL_SOFTWARE_FIFO - (rx_put - rx_get);
593         } else {
594                 space = rx_get - rx_put;
595         }
596         while (serial_tstc_dev (ACTING_UART0_BASE)) {
597                 c = serial_getc_dev (ACTING_UART0_BASE);
598                 if (space) {
599                         buf_info.rx_buffer[rx_put++] = c;
600                         space--;
601                 }
602                 if (rx_put == CONFIG_SERIAL_SOFTWARE_FIFO)
603                         rx_put = 0;
604                 if (space < CONFIG_SERIAL_SOFTWARE_FIFO / 4) {
605                         /* Stop flow by setting RTS inactive */
606                         out8 (ACTING_UART0_BASE + UART_MCR,
607                               in8 (ACTING_UART0_BASE + UART_MCR) & (0xFF ^ 0x02));
608                 }
609         }
610         buf_info.rx_put = rx_put;
611 }
612
613 void serial_buffered_init (void)
614 {
615         serial_puts ("Switching to interrupt driven serial input mode.\n");
616         buf_info.rx_buffer = malloc (CONFIG_SERIAL_SOFTWARE_FIFO);
617         buf_info.rx_put = 0;
618         buf_info.rx_get = 0;
619
620         if (in8 (ACTING_UART0_BASE + UART_MSR) & 0x10) {
621                 serial_puts ("Check CTS signal present on serial port: OK.\n");
622         } else {
623                 serial_puts ("WARNING: CTS signal not present on serial port.\n");
624         }
625
626         irq_install_handler ( VECNUM_U0 /*UART0 */ /*int vec */ ,
627                               serial_isr /*interrupt_handler_t *handler */ ,
628                               (void *) &buf_info /*void *arg */ );
629
630         /* Enable "RX Data Available" Interrupt on UART */
631         /* out8(ACTING_UART0_BASE + UART_IER, in8(ACTING_UART0_BASE + UART_IER) |0x01); */
632         out8 (ACTING_UART0_BASE + UART_IER, 0x01);
633         /* Set DTR active */
634         out8 (ACTING_UART0_BASE + UART_MCR, in8 (ACTING_UART0_BASE + UART_MCR) | 0x01);
635         /* Start flow by setting RTS active */
636         out8 (ACTING_UART0_BASE + UART_MCR, in8 (ACTING_UART0_BASE + UART_MCR) | 0x02);
637         /* Setup UART FIFO: RX trigger level: 4 byte, Enable FIFO */
638         out8 (ACTING_UART0_BASE + UART_FCR, (1 << 6) | 1);
639 }
640
641 void serial_buffered_putc (const char c)
642 {
643         /* Wait for CTS */
644 #if defined(CONFIG_HW_WATCHDOG)
645         while (!(in8 (ACTING_UART0_BASE + UART_MSR) & 0x10))
646                 WATCHDOG_RESET ();
647 #else
648         while (!(in8 (ACTING_UART0_BASE + UART_MSR) & 0x10));
649 #endif
650         serial_putc (c);
651 }
652
653 void serial_buffered_puts (const char *s)
654 {
655         serial_puts (s);
656 }
657
658 int serial_buffered_getc (void)
659 {
660         int space;
661         int c;
662         int rx_get = buf_info.rx_get;
663         int rx_put;
664
665 #if defined(CONFIG_HW_WATCHDOG)
666         while (rx_get == buf_info.rx_put)
667                 WATCHDOG_RESET ();
668 #else
669         while (rx_get == buf_info.rx_put);
670 #endif
671         c = buf_info.rx_buffer[rx_get++];
672         if (rx_get == CONFIG_SERIAL_SOFTWARE_FIFO)
673                 rx_get = 0;
674         buf_info.rx_get = rx_get;
675
676         rx_put = buf_info.rx_put;
677         if (rx_get <= rx_put) {
678                 space = CONFIG_SERIAL_SOFTWARE_FIFO - (rx_put - rx_get);
679         } else {
680                 space = rx_get - rx_put;
681         }
682         if (space > CONFIG_SERIAL_SOFTWARE_FIFO / 2) {
683                 /* Start flow by setting RTS active */
684                 out8 (ACTING_UART0_BASE + UART_MCR, in8 (ACTING_UART0_BASE + UART_MCR) | 0x02);
685         }
686
687         return c;
688 }
689
690 int serial_buffered_tstc (void)
691 {
692         return (buf_info.rx_get != buf_info.rx_put) ? 1 : 0;
693 }
694
695 #endif  /* CONFIG_SERIAL_SOFTWARE_FIFO */
696
697 #if defined(CONFIG_CMD_KGDB)
698 /*
699   AS HARNOIS : according to CONFIG_KGDB_SER_INDEX kgdb uses serial port
700   number 0 or number 1
701   - if CONFIG_KGDB_SER_INDEX = 1 => serial port number 0 :
702   configuration has been already done
703   - if CONFIG_KGDB_SER_INDEX = 2 => serial port number 1 :
704   configure port 1 for serial I/O with rate = CONFIG_KGDB_BAUDRATE
705 */
706 #if (CONFIG_KGDB_SER_INDEX & 2)
707 void kgdb_serial_init (void)
708 {
709         volatile char val;
710         unsigned short br_reg;
711
712         get_clocks ();
713         br_reg = (((((gd->cpu_clk / 16) / 18) * 10) / CONFIG_KGDB_BAUDRATE) +
714                   5) / 10;
715         /*
716          * Init onboard 16550 UART
717          */
718         out8 (ACTING_UART1_BASE + UART_LCR, 0x80);      /* set DLAB bit */
719         out8 (ACTING_UART1_BASE + UART_DLL, (br_reg & 0x00ff)); /* set divisor for 9600 baud */
720         out8 (ACTING_UART1_BASE + UART_DLM, ((br_reg & 0xff00) >> 8));  /* set divisor for 9600 baud */
721         out8 (ACTING_UART1_BASE + UART_LCR, 0x03);      /* line control 8 bits no parity */
722         out8 (ACTING_UART1_BASE + UART_FCR, 0x00);      /* disable FIFO */
723         out8 (ACTING_UART1_BASE + UART_MCR, 0x00);      /* no modem control DTR RTS */
724         val = in8 (ACTING_UART1_BASE + UART_LSR);       /* clear line status */
725         val = in8 (ACTING_UART1_BASE + UART_RBR);       /* read receive buffer */
726         out8 (ACTING_UART1_BASE + UART_SCR, 0x00);      /* set scratchpad */
727         out8 (ACTING_UART1_BASE + UART_IER, 0x00);      /* set interrupt enable reg */
728 }
729
730 void putDebugChar (const char c)
731 {
732         if (c == '\n')
733                 serial_putc ('\r');
734
735         out8 (ACTING_UART1_BASE + UART_THR, c); /* put character out */
736
737         /* check THRE bit, wait for transfer done */
738         while ((in8 (ACTING_UART1_BASE + UART_LSR) & 0x20) != 0x20);
739 }
740
741 void putDebugStr (const char *s)
742 {
743         while (*s) {
744                 serial_putc (*s++);
745         }
746 }
747
748 int getDebugChar (void)
749 {
750         unsigned char status = 0;
751
752         while (1) {
753                 status = in8 (ACTING_UART1_BASE + UART_LSR);
754                 if ((status & asyncLSRDataReady1) != 0x0) {
755                         break;
756                 }
757                 if ((status & ( asyncLSRFramingError1 |
758                                 asyncLSROverrunError1 |
759                                 asyncLSRParityError1  |
760                                 asyncLSRBreakInterrupt1 )) != 0) {
761                         out8 (ACTING_UART1_BASE + UART_LSR,
762                               asyncLSRFramingError1 |
763                               asyncLSROverrunError1 |
764                               asyncLSRParityError1  |
765                               asyncLSRBreakInterrupt1);
766                 }
767         }
768         return (0x000000ff & (int) in8 (ACTING_UART1_BASE));
769 }
770
771 void kgdb_interruptible (int yes)
772 {
773         return;
774 }
775
776 #else   /* ! (CONFIG_KGDB_SER_INDEX & 2) */
777
778 void kgdb_serial_init (void)
779 {
780         serial_printf ("[on serial] ");
781 }
782
783 void putDebugChar (int c)
784 {
785         serial_putc (c);
786 }
787
788 void putDebugStr (const char *str)
789 {
790         serial_puts (str);
791 }
792
793 int getDebugChar (void)
794 {
795         return serial_getc ();
796 }
797
798 void kgdb_interruptible (int yes)
799 {
800         return;
801 }
802 #endif  /* (CONFIG_KGDB_SER_INDEX & 2) */
803 #endif
804
805
806 #if defined(CONFIG_SERIAL_MULTI)
807 int serial0_init(void)
808 {
809         return (serial_init_dev(UART0_BASE));
810 }
811
812 int serial1_init(void)
813 {
814         return (serial_init_dev(UART1_BASE));
815 }
816 void serial0_setbrg (void)
817 {
818         serial_setbrg_dev(UART0_BASE);
819 }
820 void serial1_setbrg (void)
821 {
822         serial_setbrg_dev(UART1_BASE);
823 }
824
825 void serial0_putc(const char c)
826 {
827         serial_putc_dev(UART0_BASE,c);
828 }
829
830 void serial1_putc(const char c)
831 {
832         serial_putc_dev(UART1_BASE, c);
833 }
834 void serial0_puts(const char *s)
835 {
836         serial_puts_dev(UART0_BASE, s);
837 }
838
839 void serial1_puts(const char *s)
840 {
841         serial_puts_dev(UART1_BASE, s);
842 }
843
844 int serial0_getc(void)
845 {
846         return(serial_getc_dev(UART0_BASE));
847 }
848
849 int serial1_getc(void)
850 {
851         return(serial_getc_dev(UART1_BASE));
852 }
853 int serial0_tstc(void)
854 {
855         return (serial_tstc_dev(UART0_BASE));
856 }
857
858 int serial1_tstc(void)
859 {
860         return (serial_tstc_dev(UART1_BASE));
861 }
862
863 struct serial_device serial0_device =
864 {
865         "serial0",
866         "UART0",
867         serial0_init,
868         serial0_setbrg,
869         serial0_getc,
870         serial0_tstc,
871         serial0_putc,
872         serial0_puts,
873 };
874
875 struct serial_device serial1_device =
876 {
877         "serial1",
878         "UART1",
879         serial1_init,
880         serial1_setbrg,
881         serial1_getc,
882         serial1_tstc,
883         serial1_putc,
884         serial1_puts,
885 };
886 #endif /* CONFIG_SERIAL_MULTI */
887
888 #endif  /* CONFIG_405GP || CONFIG_405CR */