]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - cpu/ppc4xx/serial.c
ppc4xx: Add PPC405EX support
[karo-tx-uboot.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_405EX) || 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 #elif defined(CONFIG_405EX)
322 #define UART0_BASE      0xef600200
323 #define UART1_BASE      0xef600300
324 #define CR0_MASK        0x000000ff
325 #define CR0_EXTCLK_ENA  0x00800000
326 #define CR0_UDIV_POS    0
327 #define UDIV_SUBTRACT   0
328 #define UART0_SDR       sdr_uart0
329 #define UART1_SDR       sdr_uart1
330 #else /* CONFIG_405GP || CONFIG_405CR */
331 #define UART0_BASE      0xef600300
332 #define UART1_BASE      0xef600400
333 #define CR0_MASK        0x00001fff
334 #define CR0_EXTCLK_ENA  0x000000c0
335 #define CR0_UDIV_POS    1
336 #define UDIV_MAX        32
337 #endif
338
339 /* using serial port 0 or 1 as U-Boot console ? */
340 #if defined(CONFIG_UART1_CONSOLE)
341 #define ACTING_UART0_BASE       UART1_BASE
342 #define ACTING_UART1_BASE       UART0_BASE
343 #else
344 #define ACTING_UART0_BASE       UART0_BASE
345 #define ACTING_UART1_BASE       UART1_BASE
346 #endif
347
348 #if defined(CONFIG_SERIAL_MULTI)
349 #define UART_BASE       dev_base
350 #else
351 #define UART_BASE       ACTING_UART0_BASE
352 #endif
353
354 #if defined(CONFIG_405EP) && defined(CFG_EXT_SERIAL_CLOCK)
355 #error "External serial clock not supported on AMCC PPC405EP!"
356 #endif
357
358 #define UART_RBR    0x00
359 #define UART_THR    0x00
360 #define UART_IER    0x01
361 #define UART_IIR    0x02
362 #define UART_FCR    0x02
363 #define UART_LCR    0x03
364 #define UART_MCR    0x04
365 #define UART_LSR    0x05
366 #define UART_MSR    0x06
367 #define UART_SCR    0x07
368 #define UART_DLL    0x00
369 #define UART_DLM    0x01
370
371 /*-----------------------------------------------------------------------------+
372   | Line Status Register.
373   +-----------------------------------------------------------------------------*/
374 /*#define asyncLSRport1           ACTING_UART0_BASE+0x05 */
375 #define asyncLSRDataReady1            0x01
376 #define asyncLSROverrunError1         0x02
377 #define asyncLSRParityError1          0x04
378 #define asyncLSRFramingError1         0x08
379 #define asyncLSRBreakInterrupt1       0x10
380 #define asyncLSRTxHoldEmpty1          0x20
381 #define asyncLSRTxShiftEmpty1         0x40
382 #define asyncLSRRxFifoError1          0x80
383
384 /*-----------------------------------------------------------------------------+
385   | Miscellanies defines.
386   +-----------------------------------------------------------------------------*/
387 /*#define asyncTxBufferport1      ACTING_UART0_BASE+0x00 */
388 /*#define asyncRxBufferport1      ACTING_UART0_BASE+0x00 */
389
390 #ifdef CONFIG_SERIAL_SOFTWARE_FIFO
391 /*-----------------------------------------------------------------------------+
392   | Fifo
393   +-----------------------------------------------------------------------------*/
394 typedef struct {
395         char *rx_buffer;
396         ulong rx_put;
397         ulong rx_get;
398 } serial_buffer_t;
399
400 volatile static serial_buffer_t buf_info;
401 #endif
402
403 #if (defined(CONFIG_440) || defined(CONFIG_405EX)) &&  \
404         !defined(CFG_EXT_SERIAL_CLOCK)
405 static void serial_divs (int baudrate, unsigned long *pudiv,
406                          unsigned short *pbdiv)
407 {
408         sys_info_t sysinfo;
409         unsigned long div;              /* total divisor udiv * bdiv */
410         unsigned long umin;             /* minimum udiv */
411         unsigned short diff;            /* smallest diff */
412         unsigned long udiv;             /* best udiv */
413         unsigned short idiff;           /* current diff */
414         unsigned short ibdiv;           /* current bdiv */
415         unsigned long i;
416         unsigned long est;              /* current estimate */
417
418         get_sys_info(&sysinfo);
419
420         udiv = 32;                      /* Assume lowest possible serial clk */
421         div = sysinfo.freqPLB / (16 * baudrate); /* total divisor */
422         umin = sysinfo.pllOpbDiv << 1;  /* 2 x OPB divisor */
423         diff = 32;                      /* highest possible */
424
425         /* i is the test udiv value -- start with the largest
426          * possible (32) to minimize serial clock and constrain
427          * search to umin.
428          */
429         for (i = 32; i > umin; i--) {
430                 ibdiv = div / i;
431                 est = i * ibdiv;
432                 idiff = (est > div) ? (est-div) : (div-est);
433                 if (idiff == 0) {
434                         udiv = i;
435                         break;      /* can't do better */
436                 } else if (idiff < diff) {
437                         udiv = i;       /* best so far */
438                         diff = idiff;   /* update lowest diff*/
439                 }
440         }
441
442         *pudiv = udiv;
443         *pbdiv = div / udiv;
444 }
445
446 #elif defined(CONFIG_405EZ)
447
448 static void serial_divs (int baudrate, unsigned long *pudiv,
449                          unsigned short *pbdiv)
450 {
451         sys_info_t sysinfo;
452         unsigned long div;              /* total divisor udiv * bdiv */
453         unsigned long umin;             /* minimum udiv */
454         unsigned short diff;            /* smallest diff */
455         unsigned long udiv;             /* best udiv */
456         unsigned short idiff;           /* current diff */
457         unsigned short ibdiv;           /* current bdiv */
458         unsigned long i;
459         unsigned long est;              /* current estimate */
460         unsigned long plloutb;
461         unsigned long cpr_pllc;
462         u32 reg;
463
464         /* check the pll feedback source */
465         mfcpr(cprpllc, cpr_pllc);
466
467         get_sys_info(&sysinfo);
468
469         plloutb = ((CONFIG_SYS_CLK_FREQ * ((cpr_pllc & PLLC_SRC_MASK) ?
470                 sysinfo.pllFwdDivB : sysinfo.pllFwdDiv) * sysinfo.pllFbkDiv) /
471                 sysinfo.pllFwdDivB);
472         udiv = 256;                     /* Assume lowest possible serial clk */
473         div = plloutb / (16 * baudrate); /* total divisor */
474         umin = (plloutb / get_OPB_freq()) << 1; /* 2 x OPB divisor */
475         diff = 256;                     /* highest possible */
476
477         /* i is the test udiv value -- start with the largest
478          * possible (256) to minimize serial clock and constrain
479          * search to umin.
480          */
481         for (i = 256; i > umin; i--) {
482                 ibdiv = div / i;
483                 est = i * ibdiv;
484                 idiff = (est > div) ? (est-div) : (div-est);
485                 if (idiff == 0) {
486                         udiv = i;
487                         break;      /* can't do better */
488                 } else if (idiff < diff) {
489                         udiv = i;       /* best so far */
490                         diff = idiff;   /* update lowest diff*/
491                 }
492         }
493
494         *pudiv = udiv;
495         mfcpr(cprperd0, reg);
496         reg &= ~0x0000ffff;
497         reg |= ((udiv - 0) << 8) | (udiv - 0);
498         mtcpr(cprperd0, reg);
499         *pbdiv = div / udiv;
500 }
501 #endif /* defined(CONFIG_440) && !defined(CFG_EXT_SERIAL_CLK) */
502
503 /*
504  * Minimal serial functions needed to use one of the SMC ports
505  * as serial console interface.
506  */
507
508 #if defined(CONFIG_440)
509 #if defined(CONFIG_SERIAL_MULTI)
510 int serial_init_dev (unsigned long dev_base)
511 #else
512 int serial_init(void)
513 #endif
514 {
515         unsigned long reg;
516         unsigned long udiv;
517         unsigned short bdiv;
518         volatile char val;
519 #ifdef CFG_EXT_SERIAL_CLOCK
520         unsigned long tmp;
521 #endif
522
523         MFREG(UART0_SDR, reg);
524         reg &= ~CR0_MASK;
525
526 #ifdef CFG_EXT_SERIAL_CLOCK
527         reg |= CR0_EXTCLK_ENA;
528         udiv = 1;
529         tmp  = gd->baudrate * 16;
530         bdiv = (CFG_EXT_SERIAL_CLOCK + tmp / 2) / tmp;
531 #else
532         /* For 440, the cpu clock is on divider chain A, UART on divider
533          * chain B ... so cpu clock is irrelevant. Get the "optimized"
534          * values that are subject to the 1/2 opb clock constraint
535          */
536         serial_divs (gd->baudrate, &udiv, &bdiv);
537 #endif
538
539         reg |= (udiv - UDIV_SUBTRACT) << CR0_UDIV_POS;  /* set the UART divisor */
540
541         /*
542          * Configure input clock to baudrate generator for all
543          * available serial ports here
544          */
545         MTREG(UART0_SDR, reg);
546 #if defined(UART1_SDR)
547         MTREG(UART1_SDR, reg);
548 #endif
549 #if defined(UART2_SDR)
550         MTREG(UART2_SDR, reg);
551 #endif
552 #if defined(UART3_SDR)
553         MTREG(UART3_SDR, reg);
554 #endif
555
556         out8(UART_BASE + UART_LCR, 0x80);       /* set DLAB bit */
557         out8(UART_BASE + UART_DLL, bdiv);       /* set baudrate divisor */
558         out8(UART_BASE + UART_DLM, bdiv >> 8);  /* set baudrate divisor */
559         out8(UART_BASE + UART_LCR, 0x03);       /* clear DLAB; set 8 bits, no parity */
560         out8(UART_BASE + UART_FCR, 0x00);       /* disable FIFO */
561         out8(UART_BASE + UART_MCR, 0x00);       /* no modem control DTR RTS */
562         val = in8(UART_BASE + UART_LSR);        /* clear line status */
563         val = in8(UART_BASE + UART_RBR);        /* read receive buffer */
564         out8(UART_BASE + UART_SCR, 0x00);       /* set scratchpad */
565         out8(UART_BASE + UART_IER, 0x00);       /* set interrupt enable reg */
566
567         return (0);
568 }
569
570 #else /* !defined(CONFIG_440) */
571
572 #if defined(CONFIG_SERIAL_MULTI)
573 int serial_init_dev (unsigned long dev_base)
574 #else
575 int serial_init (void)
576 #endif
577 {
578         unsigned long reg;
579         unsigned long tmp;
580         unsigned long clk;
581         unsigned long udiv;
582         unsigned short bdiv;
583         volatile char val;
584
585 #ifdef CONFIG_405EX
586         clk = tmp = 0;
587         mfsdr(UART0_SDR, reg);
588         reg &= ~CR0_MASK;
589 #ifdef CFG_EXT_SERIAL_CLOCK
590         reg |= CR0_EXTCLK_ENA;
591         udiv = 1;
592         tmp  = gd->baudrate * 16;
593         bdiv = (CFG_EXT_SERIAL_CLOCK + tmp / 2) / tmp;
594 #else
595         serial_divs(gd->baudrate, &udiv, &bdiv);
596 #endif
597         reg |= (udiv - UDIV_SUBTRACT) << CR0_UDIV_POS;  /* set the UART divisor */
598
599         /*
600          * Configure input clock to baudrate generator for all
601          * available serial ports here
602          */
603         mtsdr(UART0_SDR, reg);
604
605 #if defined(UART1_SDR)
606         mtsdr(UART1_SDR, reg);
607 #endif
608
609 #elif defined(CONFIG_405EZ)
610         serial_divs(gd->baudrate, &udiv, &bdiv);
611         clk = tmp = reg = 0;
612 #else
613 #ifdef CONFIG_405EP
614         reg = mfdcr(cpc0_ucr) & ~(UCR0_MASK | UCR1_MASK);
615         clk = gd->cpu_clk;
616         tmp = CFG_BASE_BAUD * 16;
617         udiv = (clk + tmp / 2) / tmp;
618         if (udiv > UDIV_MAX)                    /* max. n bits for udiv */
619                 udiv = UDIV_MAX;
620         reg |= (udiv) << UCR0_UDIV_POS;         /* set the UART divisor */
621         reg |= (udiv) << UCR1_UDIV_POS;         /* set the UART divisor */
622         mtdcr (cpc0_ucr, reg);
623 #else /* CONFIG_405EP */
624         reg = mfdcr(cntrl0) & ~CR0_MASK;
625 #ifdef CFG_EXT_SERIAL_CLOCK
626         clk = CFG_EXT_SERIAL_CLOCK;
627         udiv = 1;
628         reg |= CR0_EXTCLK_ENA;
629 #else
630         clk = gd->cpu_clk;
631 #ifdef CFG_405_UART_ERRATA_59
632         udiv = 31;                      /* Errata 59: stuck at 31 */
633 #else
634         tmp = CFG_BASE_BAUD * 16;
635         udiv = (clk + tmp / 2) / tmp;
636         if (udiv > UDIV_MAX)                    /* max. n bits for udiv */
637                 udiv = UDIV_MAX;
638 #endif
639 #endif
640         reg |= (udiv - 1) << CR0_UDIV_POS;      /* set the UART divisor */
641         mtdcr (cntrl0, reg);
642 #endif /* CONFIG_405EP */
643         tmp = gd->baudrate * udiv * 16;
644         bdiv = (clk + tmp / 2) / tmp;
645 #endif /* CONFIG_405EX */
646
647         out8(UART_BASE + UART_LCR, 0x80);       /* set DLAB bit */
648         out8(UART_BASE + UART_DLL, bdiv);       /* set baudrate divisor */
649         out8(UART_BASE + UART_DLM, bdiv >> 8);  /* set baudrate divisor */
650         out8(UART_BASE + UART_LCR, 0x03);       /* clear DLAB; set 8 bits, no parity */
651         out8(UART_BASE + UART_FCR, 0x00);       /* disable FIFO */
652         out8(UART_BASE + UART_MCR, 0x00);       /* no modem control DTR RTS */
653         val = in8(UART_BASE + UART_LSR);        /* clear line status */
654         val = in8(UART_BASE + UART_RBR);        /* read receive buffer */
655         out8(UART_BASE + UART_SCR, 0x00);       /* set scratchpad */
656         out8(UART_BASE + UART_IER, 0x00);       /* set interrupt enable reg */
657
658         return (0);
659 }
660
661 #endif /* if defined(CONFIG_440) */
662
663 #if defined(CONFIG_SERIAL_MULTI)
664 void serial_setbrg_dev (unsigned long dev_base)
665 #else
666 void serial_setbrg (void)
667 #endif
668 {
669 #if defined(CONFIG_SERIAL_MULTI)
670         serial_init_dev(dev_base);
671 #else
672         serial_init();
673 #endif
674 }
675
676 #if defined(CONFIG_SERIAL_MULTI)
677 void serial_putc_dev (unsigned long dev_base, const char c)
678 #else
679 void serial_putc (const char c)
680 #endif
681 {
682         int i;
683
684         if (c == '\n')
685 #if defined(CONFIG_SERIAL_MULTI)
686                 serial_putc_dev (dev_base, '\r');
687 #else
688                 serial_putc ('\r');
689 #endif
690
691         /* check THRE bit, wait for transmiter available */
692         for (i = 1; i < 3500; i++) {
693                 if ((in8 (UART_BASE + UART_LSR) & 0x20) == 0x20)
694                         break;
695                 udelay (100);
696         }
697         out8 (UART_BASE + UART_THR, c); /* put character out */
698 }
699
700 #if defined(CONFIG_SERIAL_MULTI)
701 void serial_puts_dev (unsigned long dev_base, const char *s)
702 #else
703 void serial_puts (const char *s)
704 #endif
705 {
706         while (*s) {
707 #if defined(CONFIG_SERIAL_MULTI)
708                 serial_putc_dev (dev_base, *s++);
709 #else
710                 serial_putc (*s++);
711 #endif
712         }
713 }
714
715 #if defined(CONFIG_SERIAL_MULTI)
716 int serial_getc_dev (unsigned long dev_base)
717 #else
718 int serial_getc (void)
719 #endif
720 {
721         unsigned char status = 0;
722
723         while (1) {
724 #if defined(CONFIG_HW_WATCHDOG)
725                 WATCHDOG_RESET ();      /* Reset HW Watchdog, if needed */
726 #endif  /* CONFIG_HW_WATCHDOG */
727                 status = in8 (UART_BASE + UART_LSR);
728                 if ((status & asyncLSRDataReady1) != 0x0) {
729                         break;
730                 }
731                 if ((status & ( asyncLSRFramingError1 |
732                                 asyncLSROverrunError1 |
733                                 asyncLSRParityError1  |
734                                 asyncLSRBreakInterrupt1 )) != 0) {
735                         out8 (UART_BASE + UART_LSR,
736                               asyncLSRFramingError1 |
737                               asyncLSROverrunError1 |
738                               asyncLSRParityError1  |
739                               asyncLSRBreakInterrupt1);
740                 }
741         }
742         return (0x000000ff & (int) in8 (UART_BASE));
743 }
744
745 #if defined(CONFIG_SERIAL_MULTI)
746 int serial_tstc_dev (unsigned long dev_base)
747 #else
748 int serial_tstc (void)
749 #endif
750 {
751         unsigned char status;
752
753         status = in8 (UART_BASE + UART_LSR);
754         if ((status & asyncLSRDataReady1) != 0x0) {
755                 return (1);
756         }
757         if ((status & ( asyncLSRFramingError1 |
758                         asyncLSROverrunError1 |
759                         asyncLSRParityError1  |
760                         asyncLSRBreakInterrupt1 )) != 0) {
761                 out8 (UART_BASE + UART_LSR,
762                       asyncLSRFramingError1 |
763                       asyncLSROverrunError1 |
764                       asyncLSRParityError1  |
765                       asyncLSRBreakInterrupt1);
766         }
767         return 0;
768 }
769
770 #ifdef CONFIG_SERIAL_SOFTWARE_FIFO
771
772 void serial_isr (void *arg)
773 {
774         int space;
775         int c;
776         const int rx_get = buf_info.rx_get;
777         int rx_put = buf_info.rx_put;
778
779         if (rx_get <= rx_put) {
780                 space = CONFIG_SERIAL_SOFTWARE_FIFO - (rx_put - rx_get);
781         } else {
782                 space = rx_get - rx_put;
783         }
784         while (serial_tstc_dev (ACTING_UART0_BASE)) {
785                 c = serial_getc_dev (ACTING_UART0_BASE);
786                 if (space) {
787                         buf_info.rx_buffer[rx_put++] = c;
788                         space--;
789                 }
790                 if (rx_put == CONFIG_SERIAL_SOFTWARE_FIFO)
791                         rx_put = 0;
792                 if (space < CONFIG_SERIAL_SOFTWARE_FIFO / 4) {
793                         /* Stop flow by setting RTS inactive */
794                         out8 (ACTING_UART0_BASE + UART_MCR,
795                               in8 (ACTING_UART0_BASE + UART_MCR) & (0xFF ^ 0x02));
796                 }
797         }
798         buf_info.rx_put = rx_put;
799 }
800
801 void serial_buffered_init (void)
802 {
803         serial_puts ("Switching to interrupt driven serial input mode.\n");
804         buf_info.rx_buffer = malloc (CONFIG_SERIAL_SOFTWARE_FIFO);
805         buf_info.rx_put = 0;
806         buf_info.rx_get = 0;
807
808         if (in8 (ACTING_UART0_BASE + UART_MSR) & 0x10) {
809                 serial_puts ("Check CTS signal present on serial port: OK.\n");
810         } else {
811                 serial_puts ("WARNING: CTS signal not present on serial port.\n");
812         }
813
814         irq_install_handler ( VECNUM_U0 /*UART0 */ /*int vec */ ,
815                               serial_isr /*interrupt_handler_t *handler */ ,
816                               (void *) &buf_info /*void *arg */ );
817
818         /* Enable "RX Data Available" Interrupt on UART */
819         /* out8(ACTING_UART0_BASE + UART_IER, in8(ACTING_UART0_BASE + UART_IER) |0x01); */
820         out8 (ACTING_UART0_BASE + UART_IER, 0x01);
821         /* Set DTR active */
822         out8 (ACTING_UART0_BASE + UART_MCR, in8 (ACTING_UART0_BASE + UART_MCR) | 0x01);
823         /* Start flow by setting RTS active */
824         out8 (ACTING_UART0_BASE + UART_MCR, in8 (ACTING_UART0_BASE + UART_MCR) | 0x02);
825         /* Setup UART FIFO: RX trigger level: 4 byte, Enable FIFO */
826         out8 (ACTING_UART0_BASE + UART_FCR, (1 << 6) | 1);
827 }
828
829 void serial_buffered_putc (const char c)
830 {
831         /* Wait for CTS */
832 #if defined(CONFIG_HW_WATCHDOG)
833         while (!(in8 (ACTING_UART0_BASE + UART_MSR) & 0x10))
834                 WATCHDOG_RESET ();
835 #else
836         while (!(in8 (ACTING_UART0_BASE + UART_MSR) & 0x10));
837 #endif
838         serial_putc (c);
839 }
840
841 void serial_buffered_puts (const char *s)
842 {
843         serial_puts (s);
844 }
845
846 int serial_buffered_getc (void)
847 {
848         int space;
849         int c;
850         int rx_get = buf_info.rx_get;
851         int rx_put;
852
853 #if defined(CONFIG_HW_WATCHDOG)
854         while (rx_get == buf_info.rx_put)
855                 WATCHDOG_RESET ();
856 #else
857         while (rx_get == buf_info.rx_put);
858 #endif
859         c = buf_info.rx_buffer[rx_get++];
860         if (rx_get == CONFIG_SERIAL_SOFTWARE_FIFO)
861                 rx_get = 0;
862         buf_info.rx_get = rx_get;
863
864         rx_put = buf_info.rx_put;
865         if (rx_get <= rx_put) {
866                 space = CONFIG_SERIAL_SOFTWARE_FIFO - (rx_put - rx_get);
867         } else {
868                 space = rx_get - rx_put;
869         }
870         if (space > CONFIG_SERIAL_SOFTWARE_FIFO / 2) {
871                 /* Start flow by setting RTS active */
872                 out8 (ACTING_UART0_BASE + UART_MCR, in8 (ACTING_UART0_BASE + UART_MCR) | 0x02);
873         }
874
875         return c;
876 }
877
878 int serial_buffered_tstc (void)
879 {
880         return (buf_info.rx_get != buf_info.rx_put) ? 1 : 0;
881 }
882
883 #endif  /* CONFIG_SERIAL_SOFTWARE_FIFO */
884
885 #if defined(CONFIG_CMD_KGDB)
886 /*
887   AS HARNOIS : according to CONFIG_KGDB_SER_INDEX kgdb uses serial port
888   number 0 or number 1
889   - if CONFIG_KGDB_SER_INDEX = 1 => serial port number 0 :
890   configuration has been already done
891   - if CONFIG_KGDB_SER_INDEX = 2 => serial port number 1 :
892   configure port 1 for serial I/O with rate = CONFIG_KGDB_BAUDRATE
893 */
894 #if (CONFIG_KGDB_SER_INDEX & 2)
895 void kgdb_serial_init (void)
896 {
897         volatile char val;
898         unsigned short br_reg;
899
900         get_clocks ();
901         br_reg = (((((gd->cpu_clk / 16) / 18) * 10) / CONFIG_KGDB_BAUDRATE) +
902                   5) / 10;
903         /*
904          * Init onboard 16550 UART
905          */
906         out8 (ACTING_UART1_BASE + UART_LCR, 0x80);      /* set DLAB bit */
907         out8 (ACTING_UART1_BASE + UART_DLL, (br_reg & 0x00ff)); /* set divisor for 9600 baud */
908         out8 (ACTING_UART1_BASE + UART_DLM, ((br_reg & 0xff00) >> 8));  /* set divisor for 9600 baud */
909         out8 (ACTING_UART1_BASE + UART_LCR, 0x03);      /* line control 8 bits no parity */
910         out8 (ACTING_UART1_BASE + UART_FCR, 0x00);      /* disable FIFO */
911         out8 (ACTING_UART1_BASE + UART_MCR, 0x00);      /* no modem control DTR RTS */
912         val = in8 (ACTING_UART1_BASE + UART_LSR);       /* clear line status */
913         val = in8 (ACTING_UART1_BASE + UART_RBR);       /* read receive buffer */
914         out8 (ACTING_UART1_BASE + UART_SCR, 0x00);      /* set scratchpad */
915         out8 (ACTING_UART1_BASE + UART_IER, 0x00);      /* set interrupt enable reg */
916 }
917
918 void putDebugChar (const char c)
919 {
920         if (c == '\n')
921                 serial_putc ('\r');
922
923         out8 (ACTING_UART1_BASE + UART_THR, c); /* put character out */
924
925         /* check THRE bit, wait for transfer done */
926         while ((in8 (ACTING_UART1_BASE + UART_LSR) & 0x20) != 0x20);
927 }
928
929 void putDebugStr (const char *s)
930 {
931         while (*s) {
932                 serial_putc (*s++);
933         }
934 }
935
936 int getDebugChar (void)
937 {
938         unsigned char status = 0;
939
940         while (1) {
941                 status = in8 (ACTING_UART1_BASE + UART_LSR);
942                 if ((status & asyncLSRDataReady1) != 0x0) {
943                         break;
944                 }
945                 if ((status & ( asyncLSRFramingError1 |
946                                 asyncLSROverrunError1 |
947                                 asyncLSRParityError1  |
948                                 asyncLSRBreakInterrupt1 )) != 0) {
949                         out8 (ACTING_UART1_BASE + UART_LSR,
950                               asyncLSRFramingError1 |
951                               asyncLSROverrunError1 |
952                               asyncLSRParityError1  |
953                               asyncLSRBreakInterrupt1);
954                 }
955         }
956         return (0x000000ff & (int) in8 (ACTING_UART1_BASE));
957 }
958
959 void kgdb_interruptible (int yes)
960 {
961         return;
962 }
963
964 #else   /* ! (CONFIG_KGDB_SER_INDEX & 2) */
965
966 void kgdb_serial_init (void)
967 {
968         serial_printf ("[on serial] ");
969 }
970
971 void putDebugChar (int c)
972 {
973         serial_putc (c);
974 }
975
976 void putDebugStr (const char *str)
977 {
978         serial_puts (str);
979 }
980
981 int getDebugChar (void)
982 {
983         return serial_getc ();
984 }
985
986 void kgdb_interruptible (int yes)
987 {
988         return;
989 }
990 #endif  /* (CONFIG_KGDB_SER_INDEX & 2) */
991 #endif
992
993
994 #if defined(CONFIG_SERIAL_MULTI)
995 int serial0_init(void)
996 {
997         return (serial_init_dev(UART0_BASE));
998 }
999
1000 int serial1_init(void)
1001 {
1002         return (serial_init_dev(UART1_BASE));
1003 }
1004 void serial0_setbrg (void)
1005 {
1006         serial_setbrg_dev(UART0_BASE);
1007 }
1008 void serial1_setbrg (void)
1009 {
1010         serial_setbrg_dev(UART1_BASE);
1011 }
1012
1013 void serial0_putc(const char c)
1014 {
1015         serial_putc_dev(UART0_BASE,c);
1016 }
1017
1018 void serial1_putc(const char c)
1019 {
1020         serial_putc_dev(UART1_BASE, c);
1021 }
1022 void serial0_puts(const char *s)
1023 {
1024         serial_puts_dev(UART0_BASE, s);
1025 }
1026
1027 void serial1_puts(const char *s)
1028 {
1029         serial_puts_dev(UART1_BASE, s);
1030 }
1031
1032 int serial0_getc(void)
1033 {
1034         return(serial_getc_dev(UART0_BASE));
1035 }
1036
1037 int serial1_getc(void)
1038 {
1039         return(serial_getc_dev(UART1_BASE));
1040 }
1041 int serial0_tstc(void)
1042 {
1043         return (serial_tstc_dev(UART0_BASE));
1044 }
1045
1046 int serial1_tstc(void)
1047 {
1048         return (serial_tstc_dev(UART1_BASE));
1049 }
1050
1051 struct serial_device serial0_device =
1052 {
1053         "serial0",
1054         "UART0",
1055         serial0_init,
1056         serial0_setbrg,
1057         serial0_getc,
1058         serial0_tstc,
1059         serial0_putc,
1060         serial0_puts,
1061 };
1062
1063 struct serial_device serial1_device =
1064 {
1065         "serial1",
1066         "UART1",
1067         serial1_init,
1068         serial1_setbrg,
1069         serial1_getc,
1070         serial1_tstc,
1071         serial1_putc,
1072         serial1_puts,
1073 };
1074 #endif /* CONFIG_SERIAL_MULTI */
1075
1076 #endif  /* CONFIG_405GP || CONFIG_405CR */