blob: 3d1124e0b27def7f97d42fd56e817079b4bc1266 [file] [log] [blame]
wdenkfe8c2802002-11-03 00:38:21 +00001/*
Wolfgang Denkb9365a22006-07-21 11:56:05 +02002 * (C) Copyright 2000-2006
wdenkfe8c2802002-11-03 00:38:21 +00003 * 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 */
Stefan Roese3248f632007-10-22 16:22:40 +020023
wdenkfe8c2802002-11-03 00:38:21 +000024/*
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 */
Stefan Roese3248f632007-10-22 16:22:40 +020043
wdenkfe8c2802002-11-03 00:38:21 +000044#include <common.h>
45#include <commproc.h>
46#include <asm/processor.h>
Stefan Roese3248f632007-10-22 16:22:40 +020047#include <asm/io.h>
wdenkfe8c2802002-11-03 00:38:21 +000048#include <watchdog.h>
Matthias Fuchs6e9233d2008-01-08 15:50:49 +010049#include <asm/ppc4xx-intvec.h>
wdenkfe8c2802002-11-03 00:38:21 +000050
wdenkff36fd82005-01-09 22:28:56 +000051#ifdef CONFIG_SERIAL_MULTI
52#include <serial.h>
53#endif
54
wdenk42dfe7a2004-03-14 22:25:36 +000055#ifdef CONFIG_SERIAL_SOFTWARE_FIFO
wdenkfe8c2802002-11-03 00:38:21 +000056#include <malloc.h>
57#endif
58
Wolfgang Denkd87080b2006-03-31 18:32:53 +020059DECLARE_GLOBAL_DATA_PTR;
60
Stefan Roesee01bd212007-03-21 13:38:59 +010061#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
62 defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
Stefan Roesedbbd1252007-10-05 17:10:59 +020063 defined(CONFIG_405EX) || defined(CONFIG_440)
wdenkfe8c2802002-11-03 00:38:21 +000064
65#if defined(CONFIG_440)
Stefan Roese887e2ec2006-09-07 11:51:23 +020066#if defined(CONFIG_440EP) || defined(CONFIG_440GR) || \
67 defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
Stefan Roesec157d8e2005-08-01 16:41:48 +020068#define UART0_BASE CFG_PERIPHERAL_BASE + 0x00000300
69#define UART1_BASE CFG_PERIPHERAL_BASE + 0x00000400
70#else
wdenkfe8c2802002-11-03 00:38:21 +000071#define UART0_BASE CFG_PERIPHERAL_BASE + 0x00000200
72#define UART1_BASE CFG_PERIPHERAL_BASE + 0x00000300
Stefan Roesec157d8e2005-08-01 16:41:48 +020073#endif
Stefan Roese6e7fb6e2005-11-29 18:18:21 +010074
Marian Balakowicz6c5879f2006-06-30 16:30:46 +020075#if defined(CONFIG_440SP) || defined(CONFIG_440SPE)
Stefan Roese6e7fb6e2005-11-29 18:18:21 +010076#define UART2_BASE CFG_PERIPHERAL_BASE + 0x00000600
77#endif
78
Stefan Roese887e2ec2006-09-07 11:51:23 +020079#if defined(CONFIG_440GP)
wdenkfe8c2802002-11-03 00:38:21 +000080#define CR0_MASK 0x3fff0000
81#define CR0_EXTCLK_ENA 0x00600000
82#define CR0_UDIV_POS 16
Stefan Roese887e2ec2006-09-07 11:51:23 +020083#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) */
Stefan Roesee01bd212007-03-21 13:38:59 +0100107#elif defined(CONFIG_405EP) || defined(CONFIG_405EZ)
stroese8749cfb2003-05-23 11:25:57 +0000108#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
Stefan Roesedbbd1252007-10-05 17:10:59 +0200115#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
stroese8749cfb2003-05-23 11:25:57 +0000124#else /* CONFIG_405GP || CONFIG_405CR */
wdenkfe8c2802002-11-03 00:38:21 +0000125#define UART0_BASE 0xef600300
126#define UART1_BASE 0xef600400
127#define CR0_MASK 0x00001fff
stroesed7787c62003-02-17 16:06:06 +0000128#define CR0_EXTCLK_ENA 0x000000c0
wdenkfe8c2802002-11-03 00:38:21 +0000129#define CR0_UDIV_POS 1
stroese8749cfb2003-05-23 11:25:57 +0000130#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
Stefan Roese887e2ec2006-09-07 11:51:23 +0200140#endif
141
stroese8749cfb2003-05-23 11:25:57 +0000142#if defined(CONFIG_405EP) && defined(CFG_EXT_SERIAL_CLOCK)
Wolfgang Denk0c8721a2005-09-23 11:05:55 +0200143#error "External serial clock not supported on AMCC PPC405EP!"
wdenkfe8c2802002-11-03 00:38:21 +0000144#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 +-----------------------------------------------------------------------------*/
wdenkfe8c2802002-11-03 00:38:21 +0000162#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
wdenk42dfe7a2004-03-14 22:25:36 +0000171#ifdef CONFIG_SERIAL_SOFTWARE_FIFO
wdenkfe8c2802002-11-03 00:38:21 +0000172/*-----------------------------------------------------------------------------+
173 | Fifo
174 +-----------------------------------------------------------------------------*/
175typedef struct {
176 char *rx_buffer;
177 ulong rx_put;
178 ulong rx_get;
179} serial_buffer_t;
180
181volatile static serial_buffer_t buf_info;
182#endif
183
Stefan Roese3248f632007-10-22 16:22:40 +0200184static 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
Stefan Roesef10493c2007-10-23 11:31:05 +0200195 gd->uart_clk = CFG_EXT_SERIAL_CLOCK;
Stefan Roese3248f632007-10-22 16:22:40 +0200196#else
Stefan Roesef10493c2007-10-23 11:31:05 +0200197 gd->uart_clk = sys_info.freqUART / udiv;
Stefan Roese3248f632007-10-22 16:22:40 +0200198#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)
wdenkfe8c2802002-11-03 00:38:21 +0000214static void serial_divs (int baudrate, unsigned long *pudiv,
Stefan Roesee01bd212007-03-21 13:38:59 +0100215 unsigned short *pbdiv)
wdenkfe8c2802002-11-03 00:38:21 +0000216{
Stefan Roesee01bd212007-03-21 13:38:59 +0100217 sys_info_t sysinfo;
wdenkfe8c2802002-11-03 00:38:21 +0000218 unsigned long div; /* total divisor udiv * bdiv */
219 unsigned long umin; /* minimum udiv */
Stefan Roesee01bd212007-03-21 13:38:59 +0100220 unsigned short diff; /* smallest diff */
221 unsigned long udiv; /* best udiv */
222 unsigned short idiff; /* current diff */
223 unsigned short ibdiv; /* current bdiv */
wdenkfe8c2802002-11-03 00:38:21 +0000224 unsigned long i;
Stefan Roesee01bd212007-03-21 13:38:59 +0100225 unsigned long est; /* current estimate */
wdenkfe8c2802002-11-03 00:38:21 +0000226
Stefan Roesee01bd212007-03-21 13:38:59 +0100227 get_sys_info(&sysinfo);
wdenkfe8c2802002-11-03 00:38:21 +0000228
Stefan Roesee01bd212007-03-21 13:38:59 +0100229 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 */
wdenkfe8c2802002-11-03 00:38:21 +0000233
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 */
Stefan Roesee01bd212007-03-21 13:38:59 +0100238 for (i = 32; i > umin; i--) {
239 ibdiv = div / i;
wdenkfe8c2802002-11-03 00:38:21 +0000240 est = i * ibdiv;
241 idiff = (est > div) ? (est-div) : (div-est);
Stefan Roesee01bd212007-03-21 13:38:59 +0100242 if (idiff == 0) {
wdenkfe8c2802002-11-03 00:38:21 +0000243 udiv = i;
244 break; /* can't do better */
Stefan Roesee01bd212007-03-21 13:38:59 +0100245 } else if (idiff < diff) {
wdenkfe8c2802002-11-03 00:38:21 +0000246 udiv = i; /* best so far */
247 diff = idiff; /* update lowest diff*/
248 }
249 }
250
251 *pudiv = udiv;
Stefan Roesee01bd212007-03-21 13:38:59 +0100252 *pbdiv = div / udiv;
253}
wdenkfe8c2802002-11-03 00:38:21 +0000254
Stefan Roesee01bd212007-03-21 13:38:59 +0100255#elif defined(CONFIG_405EZ)
256
257static 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;
Stefan Roese273db7e2007-08-13 09:05:33 +0200270 unsigned long cpr_pllc;
Stefan Roesee01bd212007-03-21 13:38:59 +0100271 u32 reg;
272
Stefan Roese273db7e2007-08-13 09:05:33 +0200273 /* check the pll feedback source */
274 mfcpr(cprpllc, cpr_pllc);
275
Stefan Roesee01bd212007-03-21 13:38:59 +0100276 get_sys_info(&sysinfo);
277
Stefan Roese429d9572007-08-14 15:03:17 +0200278 plloutb = ((CONFIG_SYS_CLK_FREQ * ((cpr_pllc & PLLC_SRC_MASK) ?
Stefan Roese3248f632007-10-22 16:22:40 +0200279 sysinfo.pllFwdDivB : sysinfo.pllFwdDiv) *
280 sysinfo.pllFbkDiv) / sysinfo.pllFwdDivB);
Stefan Roesee01bd212007-03-21 13:38:59 +0100281 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;
wdenkfe8c2802002-11-03 00:38:21 +0000309}
Stefan Roese887e2ec2006-09-07 11:51:23 +0200310#endif /* defined(CONFIG_440) && !defined(CFG_EXT_SERIAL_CLK) */
wdenkfe8c2802002-11-03 00:38:21 +0000311
wdenkfe8c2802002-11-03 00:38:21 +0000312/*
313 * Minimal serial functions needed to use one of the SMC ports
314 * as serial console interface.
315 */
316
317#if defined(CONFIG_440)
Stefan Roese3248f632007-10-22 16:22:40 +0200318int serial_init_dev(unsigned long base)
wdenkfe8c2802002-11-03 00:38:21 +0000319{
wdenkfe8c2802002-11-03 00:38:21 +0000320 unsigned long reg;
321 unsigned long udiv;
322 unsigned short bdiv;
wdenkfe8c2802002-11-03 00:38:21 +0000323#ifdef CFG_EXT_SERIAL_CLOCK
324 unsigned long tmp;
325#endif
326
Stefan Roese887e2ec2006-09-07 11:51:23 +0200327 MFREG(UART0_SDR, reg);
wdenkba56f622004-02-06 23:19:44 +0000328 reg &= ~CR0_MASK;
Stefan Roese887e2ec2006-09-07 11:51:23 +0200329
wdenkfe8c2802002-11-03 00:38:21 +0000330#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
Stefan Roese887e2ec2006-09-07 11:51:23 +0200343 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);
wdenkff36fd82005-01-09 22:28:56 +0000352#endif
Stefan Roese887e2ec2006-09-07 11:51:23 +0200353#if defined(UART2_SDR)
354 MTREG(UART2_SDR, reg);
355#endif
356#if defined(UART3_SDR)
357 MTREG(UART3_SDR, reg);
wdenkba56f622004-02-06 23:19:44 +0000358#endif
wdenkff36fd82005-01-09 22:28:56 +0000359
Stefan Roese3248f632007-10-22 16:22:40 +0200360 serial_init_common(base, udiv, bdiv);
Stefan Roese887e2ec2006-09-07 11:51:23 +0200361
wdenkfe8c2802002-11-03 00:38:21 +0000362 return (0);
363}
364
365#else /* !defined(CONFIG_440) */
366
Stefan Roese3248f632007-10-22 16:22:40 +0200367int serial_init_dev (unsigned long base)
wdenkfe8c2802002-11-03 00:38:21 +0000368{
wdenkfe8c2802002-11-03 00:38:21 +0000369 unsigned long reg;
370 unsigned long tmp;
371 unsigned long clk;
372 unsigned long udiv;
373 unsigned short bdiv;
wdenkfe8c2802002-11-03 00:38:21 +0000374
Stefan Roesedbbd1252007-10-05 17:10:59 +0200375#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)
Stefan Roesee01bd212007-03-21 13:38:59 +0100400 serial_divs(gd->baudrate, &udiv, &bdiv);
401 clk = tmp = reg = 0;
402#else
stroese8749cfb2003-05-23 11:25:57 +0000403#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 */
wdenkfe8c2802002-11-03 00:38:21 +0000414 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;
stroese8749cfb2003-05-23 11:25:57 +0000426 if (udiv > UDIV_MAX) /* max. n bits for udiv */
427 udiv = UDIV_MAX;
wdenkfe8c2802002-11-03 00:38:21 +0000428#endif
429#endif
wdenkfe8c2802002-11-03 00:38:21 +0000430 reg |= (udiv - 1) << CR0_UDIV_POS; /* set the UART divisor */
431 mtdcr (cntrl0, reg);
stroese8749cfb2003-05-23 11:25:57 +0000432#endif /* CONFIG_405EP */
wdenkfe8c2802002-11-03 00:38:21 +0000433 tmp = gd->baudrate * udiv * 16;
434 bdiv = (clk + tmp / 2) / tmp;
Stefan Roesedbbd1252007-10-05 17:10:59 +0200435#endif /* CONFIG_405EX */
wdenkfe8c2802002-11-03 00:38:21 +0000436
Stefan Roese3248f632007-10-22 16:22:40 +0200437 serial_init_common(base, udiv, bdiv);
Stefan Roese887e2ec2006-09-07 11:51:23 +0200438
wdenkfe8c2802002-11-03 00:38:21 +0000439 return (0);
440}
441
442#endif /* if defined(CONFIG_440) */
443
Stefan Roese3248f632007-10-22 16:22:40 +0200444void serial_setbrg_dev(unsigned long base)
wdenkfe8c2802002-11-03 00:38:21 +0000445{
Stefan Roese3248f632007-10-22 16:22:40 +0200446 serial_init_dev(base);
wdenkfe8c2802002-11-03 00:38:21 +0000447}
448
Stefan Roese3248f632007-10-22 16:22:40 +0200449void serial_putc_dev(unsigned long base, const char c)
wdenkfe8c2802002-11-03 00:38:21 +0000450{
451 int i;
452
453 if (c == '\n')
Stefan Roese3248f632007-10-22 16:22:40 +0200454 serial_putc_dev(base, '\r');
wdenkfe8c2802002-11-03 00:38:21 +0000455
456 /* check THRE bit, wait for transmiter available */
457 for (i = 1; i < 3500; i++) {
Stefan Roese3248f632007-10-22 16:22:40 +0200458 if ((in_8((u8 *)base + UART_LSR) & 0x20) == 0x20)
wdenkfe8c2802002-11-03 00:38:21 +0000459 break;
460 udelay (100);
461 }
Stefan Roese3248f632007-10-22 16:22:40 +0200462
463 out_8((u8 *)base + UART_THR, c); /* put character out */
wdenkfe8c2802002-11-03 00:38:21 +0000464}
465
Stefan Roese3248f632007-10-22 16:22:40 +0200466void serial_puts_dev (unsigned long base, const char *s)
wdenkfe8c2802002-11-03 00:38:21 +0000467{
Stefan Roese3248f632007-10-22 16:22:40 +0200468 while (*s)
469 serial_putc_dev (base, *s++);
wdenkfe8c2802002-11-03 00:38:21 +0000470}
471
Stefan Roese3248f632007-10-22 16:22:40 +0200472int serial_getc_dev (unsigned long base)
wdenkfe8c2802002-11-03 00:38:21 +0000473{
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 */
Stefan Roese3248f632007-10-22 16:22:40 +0200480
481 status = in_8((u8 *)base + UART_LSR);
482 if ((status & asyncLSRDataReady1) != 0x0)
wdenkfe8c2802002-11-03 00:38:21 +0000483 break;
Stefan Roese3248f632007-10-22 16:22:40 +0200484
wdenkfe8c2802002-11-03 00:38:21 +0000485 if ((status & ( asyncLSRFramingError1 |
486 asyncLSROverrunError1 |
487 asyncLSRParityError1 |
488 asyncLSRBreakInterrupt1 )) != 0) {
Stefan Roese3248f632007-10-22 16:22:40 +0200489 out_8((u8 *)base + UART_LSR,
wdenkfe8c2802002-11-03 00:38:21 +0000490 asyncLSRFramingError1 |
491 asyncLSROverrunError1 |
492 asyncLSRParityError1 |
493 asyncLSRBreakInterrupt1);
494 }
495 }
Stefan Roese3248f632007-10-22 16:22:40 +0200496
497 return (0x000000ff & (int) in_8((u8 *)base));
wdenkfe8c2802002-11-03 00:38:21 +0000498}
499
Stefan Roese3248f632007-10-22 16:22:40 +0200500int serial_tstc_dev (unsigned long base)
wdenkfe8c2802002-11-03 00:38:21 +0000501{
502 unsigned char status;
503
Stefan Roese3248f632007-10-22 16:22:40 +0200504 status = in_8((u8 *)base + UART_LSR);
505 if ((status & asyncLSRDataReady1) != 0x0)
wdenkfe8c2802002-11-03 00:38:21 +0000506 return (1);
Stefan Roese3248f632007-10-22 16:22:40 +0200507
wdenkfe8c2802002-11-03 00:38:21 +0000508 if ((status & ( asyncLSRFramingError1 |
509 asyncLSROverrunError1 |
510 asyncLSRParityError1 |
511 asyncLSRBreakInterrupt1 )) != 0) {
Stefan Roese3248f632007-10-22 16:22:40 +0200512 out_8((u8 *)base + UART_LSR,
wdenkfe8c2802002-11-03 00:38:21 +0000513 asyncLSRFramingError1 |
514 asyncLSROverrunError1 |
515 asyncLSRParityError1 |
516 asyncLSRBreakInterrupt1);
517 }
Stefan Roese3248f632007-10-22 16:22:40 +0200518
wdenkfe8c2802002-11-03 00:38:21 +0000519 return 0;
520}
521
wdenk42dfe7a2004-03-14 22:25:36 +0000522#ifdef CONFIG_SERIAL_SOFTWARE_FIFO
wdenkfe8c2802002-11-03 00:38:21 +0000523
524void 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
Stefan Roese3248f632007-10-22 16:22:40 +0200531 if (rx_get <= rx_put)
wdenkfe8c2802002-11-03 00:38:21 +0000532 space = CONFIG_SERIAL_SOFTWARE_FIFO - (rx_put - rx_get);
Stefan Roese3248f632007-10-22 16:22:40 +0200533 else
wdenkfe8c2802002-11-03 00:38:21 +0000534 space = rx_get - rx_put;
Stefan Roese3248f632007-10-22 16:22:40 +0200535
wdenkff36fd82005-01-09 22:28:56 +0000536 while (serial_tstc_dev (ACTING_UART0_BASE)) {
537 c = serial_getc_dev (ACTING_UART0_BASE);
wdenkfe8c2802002-11-03 00:38:21 +0000538 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 */
Stefan Roese3248f632007-10-22 16:22:40 +0200546 out_8((u8 *)ACTING_UART0_BASE + UART_MCR,
547 in_8((u8 *)ACTING_UART0_BASE + UART_MCR) &
548 (0xFF ^ 0x02));
wdenkfe8c2802002-11-03 00:38:21 +0000549 }
550 }
551 buf_info.rx_put = rx_put;
552}
553
554void 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
Stefan Roese3248f632007-10-22 16:22:40 +0200561 if (in_8((u8 *)ACTING_UART0_BASE + UART_MSR) & 0x10)
wdenkfe8c2802002-11-03 00:38:21 +0000562 serial_puts ("Check CTS signal present on serial port: OK.\n");
Stefan Roese3248f632007-10-22 16:22:40 +0200563 else
wdenkfe8c2802002-11-03 00:38:21 +0000564 serial_puts ("WARNING: CTS signal not present on serial port.\n");
wdenkfe8c2802002-11-03 00:38:21 +0000565
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 */
Stefan Roese3248f632007-10-22 16:22:40 +0200571 out_8(ACTING_UART0_BASE + UART_IER, 0x01);
wdenkfe8c2802002-11-03 00:38:21 +0000572 /* Set DTR active */
Stefan Roese3248f632007-10-22 16:22:40 +0200573 out_8(ACTING_UART0_BASE + UART_MCR,
574 in_8((u8 *)ACTING_UART0_BASE + UART_MCR) | 0x01);
wdenkfe8c2802002-11-03 00:38:21 +0000575 /* Start flow by setting RTS active */
Stefan Roese3248f632007-10-22 16:22:40 +0200576 out_8(ACTING_UART0_BASE + UART_MCR,
577 in_8((u8 *)ACTING_UART0_BASE + UART_MCR) | 0x02);
wdenkfe8c2802002-11-03 00:38:21 +0000578 /* Setup UART FIFO: RX trigger level: 4 byte, Enable FIFO */
Stefan Roese3248f632007-10-22 16:22:40 +0200579 out_8(ACTING_UART0_BASE + UART_FCR, (1 << 6) | 1);
wdenkfe8c2802002-11-03 00:38:21 +0000580}
581
582void serial_buffered_putc (const char c)
583{
584 /* Wait for CTS */
585#if defined(CONFIG_HW_WATCHDOG)
Stefan Roese3248f632007-10-22 16:22:40 +0200586 while (!(in_8((u8 *)ACTING_UART0_BASE + UART_MSR) & 0x10))
wdenkfe8c2802002-11-03 00:38:21 +0000587 WATCHDOG_RESET ();
588#else
Stefan Roese3248f632007-10-22 16:22:40 +0200589 while (!(in_8((u8 *)ACTING_UART0_BASE + UART_MSR) & 0x10));
wdenkfe8c2802002-11-03 00:38:21 +0000590#endif
591 serial_putc (c);
592}
593
594void serial_buffered_puts (const char *s)
595{
596 serial_puts (s);
597}
598
599int 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;
Stefan Roese3248f632007-10-22 16:22:40 +0200618 if (rx_get <= rx_put)
wdenkfe8c2802002-11-03 00:38:21 +0000619 space = CONFIG_SERIAL_SOFTWARE_FIFO - (rx_put - rx_get);
Stefan Roese3248f632007-10-22 16:22:40 +0200620 else
wdenkfe8c2802002-11-03 00:38:21 +0000621 space = rx_get - rx_put;
Stefan Roese3248f632007-10-22 16:22:40 +0200622
wdenkfe8c2802002-11-03 00:38:21 +0000623 if (space > CONFIG_SERIAL_SOFTWARE_FIFO / 2) {
624 /* Start flow by setting RTS active */
Stefan Roese3248f632007-10-22 16:22:40 +0200625 out_8(ACTING_UART0_BASE + UART_MCR,
626 in_8((u8 *)ACTING_UART0_BASE + UART_MCR) | 0x02);
wdenkfe8c2802002-11-03 00:38:21 +0000627 }
628
629 return c;
630}
631
632int 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
Jon Loeliger3a1ed1e2007-07-09 18:57:22 -0500639#if defined(CONFIG_CMD_KGDB)
wdenkfe8c2802002-11-03 00:38:21 +0000640/*
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)
649void kgdb_serial_init (void)
650{
Stefan Roese3248f632007-10-22 16:22:40 +0200651 u8 val;
652 u16 br_reg;
wdenkfe8c2802002-11-03 00:38:21 +0000653
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 */
Stefan Roese3248f632007-10-22 16:22:40 +0200660 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 */
wdenkfe8c2802002-11-03 00:38:21 +0000670}
671
wdenkfe8c2802002-11-03 00:38:21 +0000672void putDebugChar (const char c)
673{
674 if (c == '\n')
675 serial_putc ('\r');
676
Stefan Roese3248f632007-10-22 16:22:40 +0200677 out_8((u8 *)ACTING_UART1_BASE + UART_THR, c); /* put character out */
wdenkfe8c2802002-11-03 00:38:21 +0000678
679 /* check THRE bit, wait for transfer done */
Stefan Roese3248f632007-10-22 16:22:40 +0200680 while ((in_8((u8 *)ACTING_UART1_BASE + UART_LSR) & 0x20) != 0x20);
wdenkfe8c2802002-11-03 00:38:21 +0000681}
682
wdenkfe8c2802002-11-03 00:38:21 +0000683void putDebugStr (const char *s)
684{
Stefan Roese3248f632007-10-22 16:22:40 +0200685 while (*s)
wdenkfe8c2802002-11-03 00:38:21 +0000686 serial_putc (*s++);
wdenkfe8c2802002-11-03 00:38:21 +0000687}
688
wdenkfe8c2802002-11-03 00:38:21 +0000689int getDebugChar (void)
690{
691 unsigned char status = 0;
692
693 while (1) {
Stefan Roese3248f632007-10-22 16:22:40 +0200694 status = in_8((u8 *)ACTING_UART1_BASE + UART_LSR);
695 if ((status & asyncLSRDataReady1) != 0x0)
wdenkfe8c2802002-11-03 00:38:21 +0000696 break;
Stefan Roese3248f632007-10-22 16:22:40 +0200697
698 if ((status & (asyncLSRFramingError1 |
699 asyncLSROverrunError1 |
700 asyncLSRParityError1 |
701 asyncLSRBreakInterrupt1 )) != 0) {
702 out_8((u8 *)ACTING_UART1_BASE + UART_LSR,
wdenkfe8c2802002-11-03 00:38:21 +0000703 asyncLSRFramingError1 |
704 asyncLSROverrunError1 |
705 asyncLSRParityError1 |
706 asyncLSRBreakInterrupt1);
707 }
708 }
Stefan Roese3248f632007-10-22 16:22:40 +0200709
710 return (0x000000ff & (int) in_8((u8 *)ACTING_UART1_BASE));
wdenkfe8c2802002-11-03 00:38:21 +0000711}
712
wdenkfe8c2802002-11-03 00:38:21 +0000713void kgdb_interruptible (int yes)
714{
715 return;
716}
717
718#else /* ! (CONFIG_KGDB_SER_INDEX & 2) */
719
720void kgdb_serial_init (void)
721{
722 serial_printf ("[on serial] ");
723}
724
725void putDebugChar (int c)
726{
727 serial_putc (c);
728}
729
730void putDebugStr (const char *str)
731{
732 serial_puts (str);
733}
734
735int getDebugChar (void)
736{
737 return serial_getc ();
738}
739
740void kgdb_interruptible (int yes)
741{
742 return;
743}
744#endif /* (CONFIG_KGDB_SER_INDEX & 2) */
Jon Loeliger068b60a2007-07-10 10:27:39 -0500745#endif
wdenkfe8c2802002-11-03 00:38:21 +0000746
wdenkff36fd82005-01-09 22:28:56 +0000747
748#if defined(CONFIG_SERIAL_MULTI)
749int serial0_init(void)
750{
751 return (serial_init_dev(UART0_BASE));
752}
753
754int serial1_init(void)
755{
756 return (serial_init_dev(UART1_BASE));
757}
Stefan Roese3248f632007-10-22 16:22:40 +0200758
wdenkff36fd82005-01-09 22:28:56 +0000759void serial0_setbrg (void)
760{
761 serial_setbrg_dev(UART0_BASE);
762}
Stefan Roese3248f632007-10-22 16:22:40 +0200763
wdenkff36fd82005-01-09 22:28:56 +0000764void serial1_setbrg (void)
765{
766 serial_setbrg_dev(UART1_BASE);
767}
768
769void serial0_putc(const char c)
770{
771 serial_putc_dev(UART0_BASE,c);
772}
773
774void serial1_putc(const char c)
775{
776 serial_putc_dev(UART1_BASE, c);
777}
Stefan Roese3248f632007-10-22 16:22:40 +0200778
wdenkff36fd82005-01-09 22:28:56 +0000779void serial0_puts(const char *s)
780{
781 serial_puts_dev(UART0_BASE, s);
782}
783
784void serial1_puts(const char *s)
785{
786 serial_puts_dev(UART1_BASE, s);
787}
788
789int serial0_getc(void)
790{
791 return(serial_getc_dev(UART0_BASE));
792}
793
794int serial1_getc(void)
795{
796 return(serial_getc_dev(UART1_BASE));
797}
Stefan Roese3248f632007-10-22 16:22:40 +0200798
wdenkff36fd82005-01-09 22:28:56 +0000799int serial0_tstc(void)
800{
801 return (serial_tstc_dev(UART0_BASE));
802}
803
804int serial1_tstc(void)
805{
806 return (serial_tstc_dev(UART1_BASE));
807}
808
809struct 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
821struct 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};
Stefan Roese3248f632007-10-22 16:22:40 +0200832#else
833/*
834 * Wrapper functions
835 */
836int serial_init(void)
837{
838 return serial_init_dev(ACTING_UART0_BASE);
839}
840
841void serial_setbrg(void)
842{
843 serial_setbrg_dev(ACTING_UART0_BASE);
844}
845
846void serial_putc(const char c)
847{
848 serial_putc_dev(ACTING_UART0_BASE, c);
849}
850
851void serial_puts(const char *s)
852{
853 serial_puts_dev(ACTING_UART0_BASE, s);
854}
855
856int serial_getc(void)
857{
858 return serial_getc_dev(ACTING_UART0_BASE);
859}
860
861int serial_tstc(void)
862{
863 return serial_tstc_dev(ACTING_UART0_BASE);
864}
wdenkff36fd82005-01-09 22:28:56 +0000865#endif /* CONFIG_SERIAL_MULTI */
866
wdenkfe8c2802002-11-03 00:38:21 +0000867#endif /* CONFIG_405GP || CONFIG_405CR */