Merge git://www.denx.de/git/u-boot
[platform/kernel/u-boot.git] / post / cpu / ppc4xx / uart.c
1 /*
2  * (C) Copyright 2007
3  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4  *
5  * Author: Igor Lisitsin <igor@emcraft.com>
6  *
7  * See file CREDITS for list of people who contributed to this
8  * project.
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License as
12  * published by the Free Software Foundation; either version 2 of
13  * the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
23  * MA 02111-1307 USA
24  */
25
26 #include <common.h>
27
28 /*
29  * UART test
30  *
31  * The controllers are configured to loopback mode and several
32  * characters are transmitted.
33  */
34
35 #ifdef CONFIG_POST
36
37 #include <post.h>
38
39 #if CONFIG_POST & CFG_POST_UART
40
41 #include <asm/processor.h>
42 #include <serial.h>
43
44 #define UART0_BASE  CFG_PERIPHERAL_BASE + 0x00000300
45 #define UART1_BASE  CFG_PERIPHERAL_BASE + 0x00000400
46 #define UART2_BASE  CFG_PERIPHERAL_BASE + 0x00000500
47 #define UART3_BASE  CFG_PERIPHERAL_BASE + 0x00000600
48
49 #define CR0_MASK        0xdfffffff
50 #define CR0_EXTCLK_ENA  0x00800000
51 #define CR0_UDIV_POS    0
52 #define UDIV_SUBTRACT   0
53 #define UART0_SDR       sdr_uart0
54 #define UART1_SDR       sdr_uart1
55 #define UART2_SDR       sdr_uart2
56 #define UART3_SDR       sdr_uart3
57 #define MFREG(a, d)     mfsdr(a, d)
58 #define MTREG(a, d)     mtsdr(a, d)
59
60 #define UART_RBR    0x00
61 #define UART_THR    0x00
62 #define UART_IER    0x01
63 #define UART_IIR    0x02
64 #define UART_FCR    0x02
65 #define UART_LCR    0x03
66 #define UART_MCR    0x04
67 #define UART_LSR    0x05
68 #define UART_MSR    0x06
69 #define UART_SCR    0x07
70 #define UART_DLL    0x00
71 #define UART_DLM    0x01
72
73 /*
74   Line Status Register.
75 */
76 #define asyncLSRDataReady1            0x01
77 #define asyncLSROverrunError1         0x02
78 #define asyncLSRParityError1          0x04
79 #define asyncLSRFramingError1         0x08
80 #define asyncLSRBreakInterrupt1       0x10
81 #define asyncLSRTxHoldEmpty1          0x20
82 #define asyncLSRTxShiftEmpty1         0x40
83 #define asyncLSRRxFifoError1          0x80
84
85 DECLARE_GLOBAL_DATA_PTR;
86
87 static int uart_post_init (unsigned long dev_base)
88 {
89         unsigned long reg;
90         unsigned long udiv;
91         unsigned short bdiv;
92         volatile char val;
93 #ifdef CFG_EXT_SERIAL_CLOCK
94         unsigned long tmp;
95 #endif
96         int i;
97
98         for (i = 0; i < 3500; i++) {
99                 if (in8 (dev_base + UART_LSR) & asyncLSRTxHoldEmpty1)
100                         break;
101                 udelay (100);
102         }
103         MFREG(UART0_SDR, reg);
104         reg &= ~CR0_MASK;
105
106 #ifdef CFG_EXT_SERIAL_CLOCK
107         reg |= CR0_EXTCLK_ENA;
108         udiv = 1;
109         tmp  = gd->baudrate * 16;
110         bdiv = (CFG_EXT_SERIAL_CLOCK + tmp / 2) / tmp;
111 #else
112         /* For 440, the cpu clock is on divider chain A, UART on divider
113          * chain B ... so cpu clock is irrelevant. Get the "optimized"
114          * values that are subject to the 1/2 opb clock constraint
115          */
116         serial_divs (gd->baudrate, &udiv, &bdiv);
117 #endif
118
119         reg |= (udiv - UDIV_SUBTRACT) << CR0_UDIV_POS;  /* set the UART divisor */
120
121         /*
122          * Configure input clock to baudrate generator for all
123          * available serial ports here
124          */
125         MTREG(UART0_SDR, reg);
126 #if defined(UART1_SDR)
127         MTREG(UART1_SDR, reg);
128 #endif
129 #if defined(UART2_SDR)
130         MTREG(UART2_SDR, reg);
131 #endif
132 #if defined(UART3_SDR)
133         MTREG(UART3_SDR, reg);
134 #endif
135
136         out8(dev_base + UART_LCR, 0x80);        /* set DLAB bit */
137         out8(dev_base + UART_DLL, bdiv);        /* set baudrate divisor */
138         out8(dev_base + UART_DLM, bdiv >> 8);   /* set baudrate divisor */
139         out8(dev_base + UART_LCR, 0x03);        /* clear DLAB; set 8 bits, no parity */
140         out8(dev_base + UART_FCR, 0x00);        /* disable FIFO */
141         out8(dev_base + UART_MCR, 0x10);        /* enable loopback mode */
142         val = in8(dev_base + UART_LSR);         /* clear line status */
143         val = in8(dev_base + UART_RBR);         /* read receive buffer */
144         out8(dev_base + UART_SCR, 0x00);        /* set scratchpad */
145         out8(dev_base + UART_IER, 0x00);        /* set interrupt enable reg */
146
147         return 0;
148 }
149
150 static void uart_post_putc (unsigned long dev_base, char c)
151 {
152         int i;
153
154         out8 (dev_base + UART_THR, c);  /* put character out */
155
156         /* Wait for transfer completion */
157         for (i = 0; i < 3500; i++) {
158                 if (in8 (dev_base + UART_LSR) & asyncLSRTxHoldEmpty1)
159                         break;
160                 udelay (100);
161         }
162 }
163
164 static int uart_post_getc (unsigned long dev_base)
165 {
166         int i;
167
168         /* Wait for character available */
169         for (i = 0; i < 3500; i++) {
170                 if (in8 (dev_base + UART_LSR) & asyncLSRDataReady1)
171                         break;
172                 udelay (100);
173         }
174         return 0xff & in8 (dev_base + UART_RBR);
175 }
176
177 static int test_ctlr (unsigned long dev_base, int index)
178 {
179         int res = -1;
180         char test_str[] = "*** UART Test String ***\r\n";
181         int i;
182
183         uart_post_init (dev_base);
184
185         for (i = 0; i < sizeof (test_str) - 1; i++) {
186                 uart_post_putc (dev_base, test_str[i]);
187                 if (uart_post_getc (dev_base) != test_str[i])
188                         goto done;
189         }
190         res = 0;
191 done:
192         if (res)
193                 post_log ("uart%d test failed\n", index);
194
195         return res;
196 }
197
198 int uart_post_test (int flags)
199 {
200         int i, res = 0;
201         static unsigned long base[] = {
202                 UART0_BASE, UART1_BASE, UART2_BASE, UART3_BASE
203         };
204
205         for (i = 0; i < sizeof (base) / sizeof (base[0]); i++) {
206                 if (test_ctlr (base[i], i))
207                         res = -1;
208         }
209         serial_reinit_all ();
210
211         return res;
212 }
213
214 #endif /* CONFIG_POST & CFG_POST_UART */
215 #endif /* CONFIG_POST */