blob: be217fcf8db85d97bfd1cbd5ef0aeed90040c8da [file] [log] [blame]
Igor Lisitsin95bcd382007-03-28 19:06:19 +04001/*
2 * (C) Copyright 2007
3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4 *
Sergei Poselenov3190dbe2007-07-05 08:17:37 +02005 * Author: Igor Lisitsin <igor@emcraft.com>
6 *
Igor Lisitsin95bcd382007-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 Lisitsin95bcd382007-03-28 19:06:19 +040035#include <post.h>
36
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020037#if CONFIG_POST & CONFIG_SYS_POST_UART
Igor Lisitsin95bcd382007-03-28 19:06:19 +040038
Stefan Roese32a444b2007-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 */
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020043#ifndef CONFIG_SYS_POST_UART_TABLE
44#define CONFIG_SYS_POST_UART_TABLE {UART0_BASE, UART1_BASE, UART2_BASE, UART3_BASE}
Stefan Roese32a444b2007-08-14 14:39:44 +020045#endif
46
Igor Lisitsin95bcd382007-03-28 19:06:19 +040047#include <asm/processor.h>
48#include <serial.h>
49
Stefan Roese32a444b2007-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)
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020053#define UART0_BASE CONFIG_SYS_PERIPHERAL_BASE + 0x00000300
54#define UART1_BASE CONFIG_SYS_PERIPHERAL_BASE + 0x00000400
55#define UART2_BASE CONFIG_SYS_PERIPHERAL_BASE + 0x00000500
56#define UART3_BASE CONFIG_SYS_PERIPHERAL_BASE + 0x00000600
Stefan Roese32a444b2007-08-14 14:39:44 +020057#else
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020058#define UART0_BASE CONFIG_SYS_PERIPHERAL_BASE + 0x00000200
59#define UART1_BASE CONFIG_SYS_PERIPHERAL_BASE + 0x00000300
Stefan Roese32a444b2007-08-14 14:39:44 +020060#endif
61
62#if defined(CONFIG_440SP) || defined(CONFIG_440SPE)
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020063#define UART2_BASE CONFIG_SYS_PERIPHERAL_BASE + 0x00000600
Stefan Roese32a444b2007-08-14 14:39:44 +020064#endif
Igor Lisitsin95bcd382007-03-28 19:06:19 +040065
Stefan Roese32a444b2007-08-14 14:39:44 +020066#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
Stefan Roese918010a2009-09-09 16:25:29 +020071#define UART0_SDR CPC0_CR0
Stefan Roese32a444b2007-08-14 14:39:44 +020072#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 Lisitsin95bcd382007-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
Stefan Roese918010a2009-09-09 16:25:29 +020080#define UART0_SDR SDR0_UART0
81#define UART1_SDR SDR0_UART1
Stefan Roese422853e2008-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)
Stefan Roese918010a2009-09-09 16:25:29 +020085#define UART2_SDR SDR0_UART2
Stefan Roese32a444b2007-08-14 14:39:44 +020086#endif
Stefan Roese422853e2008-06-06 16:10:41 +020087#if defined(CONFIG_440EP) || defined(CONFIG_440EPX) || \
88 defined(CONFIG_440GR) || defined(CONFIG_440GRX)
Stefan Roese918010a2009-09-09 16:25:29 +020089#define UART3_SDR SDR0_UART3
Stefan Roese32a444b2007-08-14 14:39:44 +020090#endif
Igor Lisitsin95bcd382007-03-28 19:06:19 +040091#define MFREG(a, d) mfsdr(a, d)
92#define MTREG(a, d) mtsdr(a, d)
Stefan Roese32a444b2007-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 Roese418d2a52007-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
Stefan Roese918010a2009-09-09 16:25:29 +0200109#define UART0_SDR SDR0_UART0
110#define UART1_SDR SDR0_UART1
Stefan Roese418d2a52007-10-05 17:04:57 +0200111#define MFREG(a, d) mfsdr(a, d)
112#define MTREG(a, d) mtsdr(a, d)
Stefan Roese32a444b2007-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 Lisitsin95bcd382007-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 Roese32a444b2007-08-14 14:39:44 +0200136 * Line Status Register.
137 */
Igor Lisitsin95bcd382007-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 Roese418d2a52007-10-05 17:04:57 +0200149#if defined(CONFIG_440) || defined(CONFIG_405EX)
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200150#if !defined(CONFIG_SYS_EXT_SERIAL_CLOCK)
Yuri Tikhonovbf211d02007-08-10 08:25:22 +0200151static 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 Lisitsin95bcd382007-03-28 19:06:19 +0400193static int uart_post_init (unsigned long dev_base)
194{
Stefan Roese418d2a52007-10-05 17:04:57 +0200195 unsigned long reg = 0;
Igor Lisitsin95bcd382007-03-28 19:06:19 +0400196 unsigned long udiv;
197 unsigned short bdiv;
198 volatile char val;
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200199#ifdef CONFIG_SYS_EXT_SERIAL_CLOCK
Igor Lisitsin95bcd382007-03-28 19:06:19 +0400200 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
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200212#ifdef CONFIG_SYS_EXT_SERIAL_CLOCK
Igor Lisitsin95bcd382007-03-28 19:06:19 +0400213 reg |= CR0_EXTCLK_ENA;
214 udiv = 1;
215 tmp = gd->baudrate * 16;
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200216 bdiv = (CONFIG_SYS_EXT_SERIAL_CLOCK + tmp / 2) / tmp;
Igor Lisitsin95bcd382007-03-28 19:06:19 +0400217#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}
Stefan Roese32a444b2007-08-14 14:39:44 +0200255
256#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
Stefan Roese918010a2009-09-09 16:25:29 +0200279 reg = mfdcr(CPC0_UCR) & ~(UCR0_MASK | UCR1_MASK);
Stefan Roese32a444b2007-08-14 14:39:44 +0200280 clk = gd->cpu_clk;
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200281 tmp = CONFIG_SYS_BASE_BAUD * 16;
Stefan Roese32a444b2007-08-14 14:39:44 +0200282 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 */
Stefan Roese918010a2009-09-09 16:25:29 +0200287 mtdcr (CPC0_UCR, reg);
Stefan Roese32a444b2007-08-14 14:39:44 +0200288#else /* CONFIG_405EP */
Stefan Roese918010a2009-09-09 16:25:29 +0200289 reg = mfdcr(CPC0_CR0) & ~CR0_MASK;
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200290#ifdef CONFIG_SYS_EXT_SERIAL_CLOCK
291 clk = CONFIG_SYS_EXT_SERIAL_CLOCK;
Stefan Roese32a444b2007-08-14 14:39:44 +0200292 udiv = 1;
293 reg |= CR0_EXTCLK_ENA;
294#else
295 clk = gd->cpu_clk;
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200296#ifdef CONFIG_SYS_405_UART_ERRATA_59
Stefan Roese32a444b2007-08-14 14:39:44 +0200297 udiv = 31; /* Errata 59: stuck at 31 */
298#else
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200299 tmp = CONFIG_SYS_BASE_BAUD * 16;
Stefan Roese32a444b2007-08-14 14:39:44 +0200300 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 */
Stefan Roese918010a2009-09-09 16:25:29 +0200306 mtdcr (CPC0_CR0, reg);
Stefan Roese32a444b2007-08-14 14:39:44 +0200307#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 */
Igor Lisitsin95bcd382007-03-28 19:06:19 +0400326
327static 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;
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200378 static unsigned long base[] = CONFIG_SYS_POST_UART_TABLE;
Igor Lisitsin95bcd382007-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
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200389#endif /* CONFIG_POST & CONFIG_SYS_POST_UART */