blob: 1a57c3dd1f22acb9414510935364c2715ac470ef [file] [log] [blame]
Igor Lisitsina11e0692007-03-28 19:06:19 +04001/*
2 * (C) Copyright 2007
3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4 *
Sergei Poselenovb4489622007-07-05 08:17:37 +02005 * Author: Igor Lisitsin <igor@emcraft.com>
6 *
Igor Lisitsina11e0692007-03-28 19:06:19 +04007 * 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
Igor Lisitsina11e0692007-03-28 19:06:19 +040035#include <post.h>
36
37#if CONFIG_POST & CFG_POST_UART
38
Stefan Roeseeb2b4012007-08-14 14:39:44 +020039/*
40 * This table defines the UART's that should be tested and can
41 * be overridden in the board config file
42 */
43#ifndef CFG_POST_UART_TABLE
44#define CFG_POST_UART_TABLE {UART0_BASE, UART1_BASE, UART2_BASE, UART3_BASE}
45#endif
46
Igor Lisitsina11e0692007-03-28 19:06:19 +040047#include <asm/processor.h>
48#include <serial.h>
49
Stefan Roeseeb2b4012007-08-14 14:39:44 +020050#if defined(CONFIG_440)
51#if defined(CONFIG_440EP) || defined(CONFIG_440GR) || \
52 defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
Igor Lisitsina11e0692007-03-28 19:06:19 +040053#define UART0_BASE CFG_PERIPHERAL_BASE + 0x00000300
54#define UART1_BASE CFG_PERIPHERAL_BASE + 0x00000400
55#define UART2_BASE CFG_PERIPHERAL_BASE + 0x00000500
56#define UART3_BASE CFG_PERIPHERAL_BASE + 0x00000600
Stefan Roeseeb2b4012007-08-14 14:39:44 +020057#else
58#define UART0_BASE CFG_PERIPHERAL_BASE + 0x00000200
59#define UART1_BASE CFG_PERIPHERAL_BASE + 0x00000300
60#endif
Igor Lisitsina11e0692007-03-28 19:06:19 +040061
Stefan Roeseeb2b4012007-08-14 14:39:44 +020062#if defined(CONFIG_440SP) || defined(CONFIG_440SPE)
63#define UART2_BASE CFG_PERIPHERAL_BASE + 0x00000600
64#endif
65
66#if defined(CONFIG_440GP)
67#define CR0_MASK 0x3fff0000
68#define CR0_EXTCLK_ENA 0x00600000
69#define CR0_UDIV_POS 16
70#define UDIV_SUBTRACT 1
71#define UART0_SDR cntrl0
72#define MFREG(a, d) d = mfdcr(a)
73#define MTREG(a, d) mtdcr(a, d)
74#else /* #if defined(CONFIG_440GP) */
75/* all other 440 PPC's access clock divider via sdr register */
Igor Lisitsina11e0692007-03-28 19:06:19 +040076#define CR0_MASK 0xdfffffff
77#define CR0_EXTCLK_ENA 0x00800000
78#define CR0_UDIV_POS 0
79#define UDIV_SUBTRACT 0
80#define UART0_SDR sdr_uart0
81#define UART1_SDR sdr_uart1
Stefan Roeseb2815f72008-06-06 16:10:41 +020082#if defined(CONFIG_440EP) || defined(CONFIG_440EPX) || \
83 defined(CONFIG_440GR) || defined(CONFIG_440GRX) || \
84 defined(CONFIG_440SP) || defined(CONFIG_440SPE)
Igor Lisitsina11e0692007-03-28 19:06:19 +040085#define UART2_SDR sdr_uart2
Stefan Roeseeb2b4012007-08-14 14:39:44 +020086#endif
Stefan Roeseb2815f72008-06-06 16:10:41 +020087#if defined(CONFIG_440EP) || defined(CONFIG_440EPX) || \
88 defined(CONFIG_440GR) || defined(CONFIG_440GRX)
Igor Lisitsina11e0692007-03-28 19:06:19 +040089#define UART3_SDR sdr_uart3
Stefan Roeseeb2b4012007-08-14 14:39:44 +020090#endif
Igor Lisitsina11e0692007-03-28 19:06:19 +040091#define MFREG(a, d) mfsdr(a, d)
92#define MTREG(a, d) mtsdr(a, d)
Stefan Roeseeb2b4012007-08-14 14:39:44 +020093#endif /* #if defined(CONFIG_440GP) */
94#elif defined(CONFIG_405EP) || defined(CONFIG_405EZ)
95#define UART0_BASE 0xef600300
96#define UART1_BASE 0xef600400
97#define UCR0_MASK 0x0000007f
98#define UCR1_MASK 0x00007f00
99#define UCR0_UDIV_POS 0
100#define UCR1_UDIV_POS 8
101#define UDIV_MAX 127
Stefan Roesea424a8b2007-10-05 17:04:57 +0200102#elif defined(CONFIG_405EX)
103#define UART0_BASE 0xef600200
104#define UART1_BASE 0xef600300
105#define CR0_MASK 0x000000ff
106#define CR0_EXTCLK_ENA 0x00800000
107#define CR0_UDIV_POS 0
108#define UDIV_SUBTRACT 0
109#define UART0_SDR sdr_uart0
110#define UART1_SDR sdr_uart1
111#define MFREG(a, d) mfsdr(a, d)
112#define MTREG(a, d) mtsdr(a, d)
Stefan Roeseeb2b4012007-08-14 14:39:44 +0200113#else /* CONFIG_405GP || CONFIG_405CR */
114#define UART0_BASE 0xef600300
115#define UART1_BASE 0xef600400
116#define CR0_MASK 0x00001fff
117#define CR0_EXTCLK_ENA 0x000000c0
118#define CR0_UDIV_POS 1
119#define UDIV_MAX 32
120#endif
Igor Lisitsina11e0692007-03-28 19:06:19 +0400121
122#define UART_RBR 0x00
123#define UART_THR 0x00
124#define UART_IER 0x01
125#define UART_IIR 0x02
126#define UART_FCR 0x02
127#define UART_LCR 0x03
128#define UART_MCR 0x04
129#define UART_LSR 0x05
130#define UART_MSR 0x06
131#define UART_SCR 0x07
132#define UART_DLL 0x00
133#define UART_DLM 0x01
134
135/*
Stefan Roeseeb2b4012007-08-14 14:39:44 +0200136 * Line Status Register.
137 */
Igor Lisitsina11e0692007-03-28 19:06:19 +0400138#define asyncLSRDataReady1 0x01
139#define asyncLSROverrunError1 0x02
140#define asyncLSRParityError1 0x04
141#define asyncLSRFramingError1 0x08
142#define asyncLSRBreakInterrupt1 0x10
143#define asyncLSRTxHoldEmpty1 0x20
144#define asyncLSRTxShiftEmpty1 0x40
145#define asyncLSRRxFifoError1 0x80
146
147DECLARE_GLOBAL_DATA_PTR;
148
Stefan Roesea424a8b2007-10-05 17:04:57 +0200149#if defined(CONFIG_440) || defined(CONFIG_405EX)
Yuri Tikhonov29cb25d2007-08-10 08:25:22 +0200150#if !defined(CFG_EXT_SERIAL_CLOCK)
151static void serial_divs (int baudrate, unsigned long *pudiv,
152 unsigned short *pbdiv)
153{
154 sys_info_t sysinfo;
155 unsigned long div; /* total divisor udiv * bdiv */
156 unsigned long umin; /* minimum udiv */
157 unsigned short diff; /* smallest diff */
158 unsigned long udiv; /* best udiv */
159 unsigned short idiff; /* current diff */
160 unsigned short ibdiv; /* current bdiv */
161 unsigned long i;
162 unsigned long est; /* current estimate */
163
164 get_sys_info(&sysinfo);
165
166 udiv = 32; /* Assume lowest possible serial clk */
167 div = sysinfo.freqPLB / (16 * baudrate); /* total divisor */
168 umin = sysinfo.pllOpbDiv << 1; /* 2 x OPB divisor */
169 diff = 32; /* highest possible */
170
171 /* i is the test udiv value -- start with the largest
172 * possible (32) to minimize serial clock and constrain
173 * search to umin.
174 */
175 for (i = 32; i > umin; i--) {
176 ibdiv = div / i;
177 est = i * ibdiv;
178 idiff = (est > div) ? (est-div) : (div-est);
179 if (idiff == 0) {
180 udiv = i;
181 break; /* can't do better */
182 } else if (idiff < diff) {
183 udiv = i; /* best so far */
184 diff = idiff; /* update lowest diff*/
185 }
186 }
187
188 *pudiv = udiv;
189 *pbdiv = div / udiv;
190}
191#endif
192
Igor Lisitsina11e0692007-03-28 19:06:19 +0400193static int uart_post_init (unsigned long dev_base)
194{
Stefan Roesea424a8b2007-10-05 17:04:57 +0200195 unsigned long reg = 0;
Igor Lisitsina11e0692007-03-28 19:06:19 +0400196 unsigned long udiv;
197 unsigned short bdiv;
198 volatile char val;
199#ifdef CFG_EXT_SERIAL_CLOCK
200 unsigned long tmp;
201#endif
202 int i;
203
204 for (i = 0; i < 3500; i++) {
205 if (in8 (dev_base + UART_LSR) & asyncLSRTxHoldEmpty1)
206 break;
207 udelay (100);
208 }
209 MFREG(UART0_SDR, reg);
210 reg &= ~CR0_MASK;
211
212#ifdef CFG_EXT_SERIAL_CLOCK
213 reg |= CR0_EXTCLK_ENA;
214 udiv = 1;
215 tmp = gd->baudrate * 16;
216 bdiv = (CFG_EXT_SERIAL_CLOCK + tmp / 2) / tmp;
217#else
218 /* For 440, the cpu clock is on divider chain A, UART on divider
219 * chain B ... so cpu clock is irrelevant. Get the "optimized"
220 * values that are subject to the 1/2 opb clock constraint
221 */
222 serial_divs (gd->baudrate, &udiv, &bdiv);
223#endif
224
225 reg |= (udiv - UDIV_SUBTRACT) << CR0_UDIV_POS; /* set the UART divisor */
226
227 /*
228 * Configure input clock to baudrate generator for all
229 * available serial ports here
230 */
231 MTREG(UART0_SDR, reg);
232#if defined(UART1_SDR)
233 MTREG(UART1_SDR, reg);
234#endif
235#if defined(UART2_SDR)
236 MTREG(UART2_SDR, reg);
237#endif
238#if defined(UART3_SDR)
239 MTREG(UART3_SDR, reg);
240#endif
241
242 out8(dev_base + UART_LCR, 0x80); /* set DLAB bit */
243 out8(dev_base + UART_DLL, bdiv); /* set baudrate divisor */
244 out8(dev_base + UART_DLM, bdiv >> 8); /* set baudrate divisor */
245 out8(dev_base + UART_LCR, 0x03); /* clear DLAB; set 8 bits, no parity */
246 out8(dev_base + UART_FCR, 0x00); /* disable FIFO */
247 out8(dev_base + UART_MCR, 0x10); /* enable loopback mode */
248 val = in8(dev_base + UART_LSR); /* clear line status */
249 val = in8(dev_base + UART_RBR); /* read receive buffer */
250 out8(dev_base + UART_SCR, 0x00); /* set scratchpad */
251 out8(dev_base + UART_IER, 0x00); /* set interrupt enable reg */
252
253 return 0;
254}
255
Stefan Roeseeb2b4012007-08-14 14:39:44 +0200256#else /* CONFIG_440 */
257
258static int uart_post_init (unsigned long dev_base)
259{
260 unsigned long reg;
261 unsigned long tmp;
262 unsigned long clk;
263 unsigned long udiv;
264 unsigned short bdiv;
265 volatile char val;
266 int i;
267
268 for (i = 0; i < 3500; i++) {
269 if (in8 (dev_base + UART_LSR) & asyncLSRTxHoldEmpty1)
270 break;
271 udelay (100);
272 }
273
274#if defined(CONFIG_405EZ)
275 serial_divs(gd->baudrate, &udiv, &bdiv);
276 clk = tmp = reg = 0;
277#else
278#ifdef CONFIG_405EP
279 reg = mfdcr(cpc0_ucr) & ~(UCR0_MASK | UCR1_MASK);
280 clk = gd->cpu_clk;
281 tmp = CFG_BASE_BAUD * 16;
282 udiv = (clk + tmp / 2) / tmp;
283 if (udiv > UDIV_MAX) /* max. n bits for udiv */
284 udiv = UDIV_MAX;
285 reg |= (udiv) << UCR0_UDIV_POS; /* set the UART divisor */
286 reg |= (udiv) << UCR1_UDIV_POS; /* set the UART divisor */
287 mtdcr (cpc0_ucr, reg);
288#else /* CONFIG_405EP */
289 reg = mfdcr(cntrl0) & ~CR0_MASK;
290#ifdef CFG_EXT_SERIAL_CLOCK
291 clk = CFG_EXT_SERIAL_CLOCK;
292 udiv = 1;
293 reg |= CR0_EXTCLK_ENA;
294#else
295 clk = gd->cpu_clk;
296#ifdef CFG_405_UART_ERRATA_59
297 udiv = 31; /* Errata 59: stuck at 31 */
298#else
299 tmp = CFG_BASE_BAUD * 16;
300 udiv = (clk + tmp / 2) / tmp;
301 if (udiv > UDIV_MAX) /* max. n bits for udiv */
302 udiv = UDIV_MAX;
303#endif
304#endif
305 reg |= (udiv - 1) << CR0_UDIV_POS; /* set the UART divisor */
306 mtdcr (cntrl0, reg);
307#endif /* CONFIG_405EP */
308 tmp = gd->baudrate * udiv * 16;
309 bdiv = (clk + tmp / 2) / tmp;
310#endif /* CONFIG_405EZ */
311
312 out8(dev_base + UART_LCR, 0x80); /* set DLAB bit */
313 out8(dev_base + UART_DLL, bdiv); /* set baudrate divisor */
314 out8(dev_base + UART_DLM, bdiv >> 8); /* set baudrate divisor */
315 out8(dev_base + UART_LCR, 0x03); /* clear DLAB; set 8 bits, no parity */
316 out8(dev_base + UART_FCR, 0x00); /* disable FIFO */
317 out8(dev_base + UART_MCR, 0x10); /* enable loopback mode */
318 val = in8(dev_base + UART_LSR); /* clear line status */
319 val = in8(dev_base + UART_RBR); /* read receive buffer */
320 out8(dev_base + UART_SCR, 0x00); /* set scratchpad */
321 out8(dev_base + UART_IER, 0x00); /* set interrupt enable reg */
322
323 return (0);
324}
325#endif /* CONFIG_440 */
326
Igor Lisitsina11e0692007-03-28 19:06:19 +0400327static void uart_post_putc (unsigned long dev_base, char c)
328{
329 int i;
330
331 out8 (dev_base + UART_THR, c); /* put character out */
332
333 /* Wait for transfer completion */
334 for (i = 0; i < 3500; i++) {
335 if (in8 (dev_base + UART_LSR) & asyncLSRTxHoldEmpty1)
336 break;
337 udelay (100);
338 }
339}
340
341static int uart_post_getc (unsigned long dev_base)
342{
343 int i;
344
345 /* Wait for character available */
346 for (i = 0; i < 3500; i++) {
347 if (in8 (dev_base + UART_LSR) & asyncLSRDataReady1)
348 break;
349 udelay (100);
350 }
351 return 0xff & in8 (dev_base + UART_RBR);
352}
353
354static int test_ctlr (unsigned long dev_base, int index)
355{
356 int res = -1;
357 char test_str[] = "*** UART Test String ***\r\n";
358 int i;
359
360 uart_post_init (dev_base);
361
362 for (i = 0; i < sizeof (test_str) - 1; i++) {
363 uart_post_putc (dev_base, test_str[i]);
364 if (uart_post_getc (dev_base) != test_str[i])
365 goto done;
366 }
367 res = 0;
368done:
369 if (res)
370 post_log ("uart%d test failed\n", index);
371
372 return res;
373}
374
375int uart_post_test (int flags)
376{
377 int i, res = 0;
Stefan Roeseeb2b4012007-08-14 14:39:44 +0200378 static unsigned long base[] = CFG_POST_UART_TABLE;
Igor Lisitsina11e0692007-03-28 19:06:19 +0400379
380 for (i = 0; i < sizeof (base) / sizeof (base[0]); i++) {
381 if (test_ctlr (base[i], i))
382 res = -1;
383 }
384 serial_reinit_all ();
385
386 return res;
387}
388
389#endif /* CONFIG_POST & CFG_POST_UART */