blob: 0e132268c82c26e5de1b491e2eb5b3ec980ae235 [file] [log] [blame]
wdenk4989f872004-03-14 15:06:13 +00001/*
2 * (C) Copyright 2000
3 * Rob Taylor, Flying Pig Systems. robt@flyingpig.com.
4 *
5 * (C) Copyright 2004
6 * ARM Ltd.
7 * Philippe Robin, <philippe.robin@arm.com>
8 *
9 * See file CREDITS for list of people who contributed to this
10 * project.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License as
14 * published by the Free Software Foundation; either version 2 of
15 * the License, or (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
25 * MA 02111-1307 USA
26 */
27
28/* Simple U-Boot driver for the PrimeCell PL011 UARTs on the IntegratorCP */
29/* Should be fairly simple to make it work with the PL010 as well */
30
31#include <common.h>
32
33#ifdef CFG_PL011_SERIAL
34
35#include "serial_pl011.h"
36
37#define IO_WRITE(addr, val) (*(volatile unsigned int *)(addr) = (val))
38#define IO_READ(addr) (*(volatile unsigned int *)(addr))
39
40/*
wdenkc35ba4e2004-03-14 22:25:36 +000041 * IntegratorCP has two UARTs, use the first one, at 38400-8-N-1
wdenk4989f872004-03-14 15:06:13 +000042 * Versatile PB has four UARTs.
43 */
44#define NUM_PORTS 2
45#define CONSOLE_PORT CONFIG_CONS_INDEX
46#define baudRate CONFIG_BAUDRATE
wdenkc35ba4e2004-03-14 22:25:36 +000047static volatile unsigned char *const port[NUM_PORTS] = {
48 (void *) (CFG_SERIAL0),
49 (void *) (CFG_SERIAL1)
50};
wdenk4989f872004-03-14 15:06:13 +000051
52
wdenkc35ba4e2004-03-14 22:25:36 +000053static void pl011_putc (int portnum, char c);
54static int pl011_getc (int portnum);
55static int pl011_tstc (int portnum);
wdenk4989f872004-03-14 15:06:13 +000056
57
58int serial_init (void)
59{
wdenkc35ba4e2004-03-14 22:25:36 +000060 unsigned int temp;
61 unsigned int divider;
62 unsigned int remainder;
63 unsigned int fraction;
wdenk4989f872004-03-14 15:06:13 +000064
wdenkc35ba4e2004-03-14 22:25:36 +000065 /*
66 ** First, disable everything.
67 */
68 IO_WRITE (port[CONSOLE_PORT] + UART_PL011_CR, 0x0);
wdenk4989f872004-03-14 15:06:13 +000069
wdenkc35ba4e2004-03-14 22:25:36 +000070 /*
71 ** Set baud rate
72 **
73 ** IBRD = UART_CLK / (16 * BAUD_RATE)
74 ** FBRD = ROUND((64 * MOD(UART_CLK,(16 * BAUD_RATE))) / (16 * BAUD_RATE))
75 */
wdenk4989f872004-03-14 15:06:13 +000076#ifdef CONFIG_VERSATILE
wdenkc35ba4e2004-03-14 22:25:36 +000077 temp = 16 * baudRate;
78 divider = 24000000 / temp;
79 remainder = 24000000 % temp;
80 temp = (8 * remainder) / baudRate;
81 fraction = (temp >> 1) + (temp & 1);
wdenk4989f872004-03-14 15:06:13 +000082#endif
83#ifdef CONFIG_INTEGRATOR
wdenkc35ba4e2004-03-14 22:25:36 +000084 temp = 16 * baudRate;
85 divider = 14745600 / temp;
86 remainder = 14745600 % temp;
87 temp = (8 * remainder) / baudRate;
88 fraction = (temp >> 1) + (temp & 1);
wdenk4989f872004-03-14 15:06:13 +000089#endif
wdenk4989f872004-03-14 15:06:13 +000090
wdenkc35ba4e2004-03-14 22:25:36 +000091 IO_WRITE (port[CONSOLE_PORT] + UART_PL011_IBRD, divider);
92 IO_WRITE (port[CONSOLE_PORT] + UART_PL011_FBRD, fraction);
wdenk4989f872004-03-14 15:06:13 +000093
wdenkc35ba4e2004-03-14 22:25:36 +000094 /*
95 ** Set the UART to be 8 bits, 1 stop bit, no parity, fifo enabled.
96 */
97 IO_WRITE (port[CONSOLE_PORT] + UART_PL011_LCRH,
98 (UART_PL011_LCRH_WLEN_8 | UART_PL011_LCRH_FEN));
wdenk4989f872004-03-14 15:06:13 +000099
wdenkc35ba4e2004-03-14 22:25:36 +0000100 /*
101 ** Finally, enable the UART
102 */
103 IO_WRITE (port[CONSOLE_PORT] + UART_PL011_CR,
104 (UART_PL011_CR_UARTEN | UART_PL011_CR_TXE |
105 UART_PL011_CR_RXE));
106
107 return (0);
wdenk4989f872004-03-14 15:06:13 +0000108}
109
wdenkc35ba4e2004-03-14 22:25:36 +0000110void serial_putc (const char c)
wdenk4989f872004-03-14 15:06:13 +0000111{
112 if (c == '\n')
wdenkc35ba4e2004-03-14 22:25:36 +0000113 pl011_putc (CONSOLE_PORT, '\r');
wdenk4989f872004-03-14 15:06:13 +0000114
wdenkc35ba4e2004-03-14 22:25:36 +0000115 pl011_putc (CONSOLE_PORT, c);
wdenk4989f872004-03-14 15:06:13 +0000116}
117
wdenkc35ba4e2004-03-14 22:25:36 +0000118void serial_puts (const char *s)
wdenk4989f872004-03-14 15:06:13 +0000119{
120 while (*s) {
121 serial_putc (*s++);
122 }
123}
124
wdenkc35ba4e2004-03-14 22:25:36 +0000125int serial_getc (void)
wdenk4989f872004-03-14 15:06:13 +0000126{
wdenkc35ba4e2004-03-14 22:25:36 +0000127 return pl011_getc (CONSOLE_PORT);
wdenk4989f872004-03-14 15:06:13 +0000128}
129
wdenkc35ba4e2004-03-14 22:25:36 +0000130int serial_tstc (void)
wdenk4989f872004-03-14 15:06:13 +0000131{
wdenkc35ba4e2004-03-14 22:25:36 +0000132 return pl011_tstc (CONSOLE_PORT);
wdenk4989f872004-03-14 15:06:13 +0000133}
134
wdenkc35ba4e2004-03-14 22:25:36 +0000135void serial_setbrg (void)
wdenk4989f872004-03-14 15:06:13 +0000136{
137}
138
wdenkc35ba4e2004-03-14 22:25:36 +0000139static void pl011_putc (int portnum, char c)
wdenk4989f872004-03-14 15:06:13 +0000140{
wdenkc35ba4e2004-03-14 22:25:36 +0000141 /* Wait until there is space in the FIFO */
142 while (IO_READ (port[portnum] + UART_PL01x_FR) & UART_PL01x_FR_TXFF);
143
144 /* Send the character */
145 IO_WRITE (port[portnum] + UART_PL01x_DR, c);
wdenk4989f872004-03-14 15:06:13 +0000146}
147
wdenkc35ba4e2004-03-14 22:25:36 +0000148static int pl011_getc (int portnum)
wdenk4989f872004-03-14 15:06:13 +0000149{
wdenkc35ba4e2004-03-14 22:25:36 +0000150 unsigned int data;
151
152 /* Wait until there is data in the FIFO */
153 while (IO_READ (port[portnum] + UART_PL01x_FR) & UART_PL01x_FR_RXFE);
wdenk4989f872004-03-14 15:06:13 +0000154
wdenkc35ba4e2004-03-14 22:25:36 +0000155 data = IO_READ (port[portnum] + UART_PL01x_DR);
156
157 /* Check for an error flag */
158 if (data & 0xFFFFFF00) {
159 /* Clear the error */
160 IO_WRITE (port[portnum] + UART_PL01x_ECR, 0xFFFFFFFF);
161 return -1;
162 }
163
164 return (int) data;
wdenk4989f872004-03-14 15:06:13 +0000165}
166
wdenkc35ba4e2004-03-14 22:25:36 +0000167static int pl011_tstc (int portnum)
wdenk4989f872004-03-14 15:06:13 +0000168{
wdenkc35ba4e2004-03-14 22:25:36 +0000169 return !(IO_READ (port[portnum] + UART_PL01x_FR) &
170 UART_PL01x_FR_RXFE);
wdenk4989f872004-03-14 15:06:13 +0000171}
172
173#endif