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