blob: b5f32e2820fe1a9849dcb6e0ad4f9d1d9373c715 [file] [log] [blame]
wdenkbb1b8262003-03-27 12:09:35 +00001/*
2 * (INCA) ASC UART support
3 */
4
wdenkb02744a2003-04-05 00:53:31 +00005#include <config.h>
wdenkbb1b8262003-03-27 12:09:35 +00006#include <common.h>
7#include <asm/inca-ip.h>
Marek Vasut2a9d9352012-09-13 01:20:07 +02008#include <serial.h>
9#include <linux/compiler.h>
wdenk9b7f3842003-10-09 20:09:04 +000010#include "asc_serial.h"
wdenkbb1b8262003-03-27 12:09:35 +000011
wdenkb02744a2003-04-05 00:53:31 +000012
wdenkbb1b8262003-03-27 12:09:35 +000013#define SET_BIT(reg, mask) reg |= (mask)
14#define CLEAR_BIT(reg, mask) reg &= (~mask)
15#define CLEAR_BITS(reg, mask) CLEAR_BIT(reg, mask)
16#define SET_BITS(reg, mask) SET_BIT(reg, mask)
17#define SET_BITFIELD(reg, mask, off, val) {reg &= (~mask); reg |= (val << off);}
18
19extern uint incaip_get_fpiclk(void);
20
21static int serial_setopt (void);
22
23/* pointer to ASC register base address */
24static volatile incaAsc_t *pAsc = (incaAsc_t *)INCA_IP_ASC;
25
26/******************************************************************************
27*
28* serial_init - initialize a INCAASC channel
29*
30* This routine initializes the number of data bits, parity
31* and set the selected baud rate. Interrupts are disabled.
32* Set the modem control signals if the option is selected.
33*
34* RETURNS: N/A
35*/
36
Marek Vasut2a9d9352012-09-13 01:20:07 +020037static int asc_serial_init(void)
wdenkbb1b8262003-03-27 12:09:35 +000038{
39 /* we have to set PMU.EN13 bit to enable an ASC device*/
40 INCAASC_PMU_ENABLE(13);
wdenk57b2d802003-06-27 21:31:46 +000041
wdenkbb1b8262003-03-27 12:09:35 +000042 /* and we have to set CLC register*/
43 CLEAR_BIT(pAsc->asc_clc, ASCCLC_DISS);
44 SET_BITFIELD(pAsc->asc_clc, ASCCLC_RMCMASK, ASCCLC_RMCOFFSET, 0x0001);
wdenk57b2d802003-06-27 21:31:46 +000045
wdenkbb1b8262003-03-27 12:09:35 +000046 /* initialy we are in async mode */
47 pAsc->asc_con = ASCCON_M_8ASYNC;
48
49 /* select input port */
50 pAsc->asc_pisel = (CONSOLE_TTY & 0x1);
51
52 /* TXFIFO's filling level */
53 SET_BITFIELD(pAsc->asc_txfcon, ASCTXFCON_TXFITLMASK,
wdenk57b2d802003-06-27 21:31:46 +000054 ASCTXFCON_TXFITLOFF, INCAASC_TXFIFO_FL);
wdenkbb1b8262003-03-27 12:09:35 +000055 /* enable TXFIFO */
56 SET_BIT(pAsc->asc_txfcon, ASCTXFCON_TXFEN);
57
58 /* RXFIFO's filling level */
wdenk57b2d802003-06-27 21:31:46 +000059 SET_BITFIELD(pAsc->asc_txfcon, ASCRXFCON_RXFITLMASK,
60 ASCRXFCON_RXFITLOFF, INCAASC_RXFIFO_FL);
wdenkbb1b8262003-03-27 12:09:35 +000061 /* enable RXFIFO */
62 SET_BIT(pAsc->asc_rxfcon, ASCRXFCON_RXFEN);
63
64 /* enable error signals */
65 SET_BIT(pAsc->asc_con, ASCCON_FEN);
66 SET_BIT(pAsc->asc_con, ASCCON_OEN);
67
68 /* acknowledge ASC interrupts */
69 ASC_INTERRUPTS_CLEAR(INCAASC_IRQ_LINE_ALL);
70
71 /* disable ASC interrupts */
72 ASC_INTERRUPTS_DISABLE(INCAASC_IRQ_LINE_ALL);
73
74 /* set FIFOs into the transparent mode */
75 SET_BIT(pAsc->asc_txfcon, ASCTXFCON_TXTMEN);
76 SET_BIT(pAsc->asc_rxfcon, ASCRXFCON_RXTMEN);
77
78 /* set baud rate */
79 serial_setbrg();
80
81 /* set the options */
82 serial_setopt();
wdenk57b2d802003-06-27 21:31:46 +000083
wdenkbb1b8262003-03-27 12:09:35 +000084 return 0;
85}
86
Marek Vasut2a9d9352012-09-13 01:20:07 +020087static void asc_serial_setbrg(void)
wdenkbb1b8262003-03-27 12:09:35 +000088{
89 ulong uiReloadValue, fdv;
90 ulong f_ASC;
91
92 f_ASC = incaip_get_fpiclk();
93
94#ifndef INCAASC_USE_FDV
95 fdv = 2;
96 uiReloadValue = (f_ASC / (fdv * 16 * CONFIG_BAUDRATE)) - 1;
wdenk57b2d802003-06-27 21:31:46 +000097#else
wdenkbb1b8262003-03-27 12:09:35 +000098 fdv = INCAASC_FDV_HIGH_BAUDRATE;
99 uiReloadValue = (f_ASC / (8192 * CONFIG_BAUDRATE / fdv)) - 1;
100#endif /* INCAASC_USE_FDV */
wdenk57b2d802003-06-27 21:31:46 +0000101
wdenkbb1b8262003-03-27 12:09:35 +0000102 if ( (uiReloadValue < 0) || (uiReloadValue > 8191) )
103 {
104#ifndef INCAASC_USE_FDV
wdenk57b2d802003-06-27 21:31:46 +0000105 fdv = 3;
106 uiReloadValue = (f_ASC / (fdv * 16 * CONFIG_BAUDRATE)) - 1;
107#else
108 fdv = INCAASC_FDV_LOW_BAUDRATE;
109 uiReloadValue = (f_ASC / (8192 * CONFIG_BAUDRATE / fdv)) - 1;
wdenkbb1b8262003-03-27 12:09:35 +0000110#endif /* INCAASC_USE_FDV */
wdenk57b2d802003-06-27 21:31:46 +0000111
112 if ( (uiReloadValue < 0) || (uiReloadValue > 8191) )
113 {
114 return; /* can't impossibly generate that baud rate */
115 }
wdenkbb1b8262003-03-27 12:09:35 +0000116 }
117
118 /* Disable Baud Rate Generator; BG should only be written when R=0 */
119 CLEAR_BIT(pAsc->asc_con, ASCCON_R);
120
121#ifndef INCAASC_USE_FDV
122 /*
123 * Disable Fractional Divider (FDE)
124 * Divide clock by reload-value + constant (BRS)
125 */
126 /* FDE = 0 */
127 CLEAR_BIT(pAsc->asc_con, ASCCON_FDE);
128
129 if ( fdv == 2 )
wdenk57b2d802003-06-27 21:31:46 +0000130 CLEAR_BIT(pAsc->asc_con, ASCCON_BRS); /* BRS = 0 */
wdenkbb1b8262003-03-27 12:09:35 +0000131 else
wdenk57b2d802003-06-27 21:31:46 +0000132 SET_BIT(pAsc->asc_con, ASCCON_BRS); /* BRS = 1 */
wdenkbb1b8262003-03-27 12:09:35 +0000133
134#else /* INCAASC_USE_FDV */
135
136 /* Enable Fractional Divider */
137 SET_BIT(pAsc->asc_con, ASCCON_FDE); /* FDE = 1 */
138
139 /* Set fractional divider value */
140 pAsc->asc_fdv = fdv & ASCFDV_VALUE_MASK;
141
142#endif /* INCAASC_USE_FDV */
143
144 /* Set reload value in BG */
145 pAsc->asc_bg = uiReloadValue;
146
147 /* Enable Baud Rate Generator */
148 SET_BIT(pAsc->asc_con, ASCCON_R); /* R = 1 */
149}
150
151/*******************************************************************************
152*
153* serial_setopt - set the serial options
154*
155* Set the channel operating mode to that specified. Following options
156* are supported: CREAD, CSIZE, PARENB, and PARODD.
157*
158* Note, this routine disables the transmitter. The calling routine
159* may have to re-enable it.
160*
161* RETURNS:
162* Returns 0 to indicate success, otherwise -1 is returned
163*/
164
165static int serial_setopt (void)
166{
167 ulong con;
168
169 switch ( ASC_OPTIONS & ASCOPT_CSIZE )
170 {
171 /* 7-bit-data */
172 case ASCOPT_CS7:
wdenk57b2d802003-06-27 21:31:46 +0000173 con = ASCCON_M_7ASYNCPAR; /* 7-bit-data and parity bit */
174 break;
wdenkbb1b8262003-03-27 12:09:35 +0000175
176 /* 8-bit-data */
177 case ASCOPT_CS8:
wdenk57b2d802003-06-27 21:31:46 +0000178 if ( ASC_OPTIONS & ASCOPT_PARENB )
179 con = ASCCON_M_8ASYNCPAR; /* 8-bit-data and parity bit */
180 else
181 con = ASCCON_M_8ASYNC; /* 8-bit-data no parity */
182 break;
183
184 /*
wdenkbb1b8262003-03-27 12:09:35 +0000185 * only 7 and 8-bit frames are supported
wdenk57b2d802003-06-27 21:31:46 +0000186 * if we don't use IOCTL extensions
wdenkbb1b8262003-03-27 12:09:35 +0000187 */
188 default:
wdenk57b2d802003-06-27 21:31:46 +0000189 return -1;
wdenkbb1b8262003-03-27 12:09:35 +0000190 }
191
192 if ( ASC_OPTIONS & ASCOPT_STOPB )
wdenk57b2d802003-06-27 21:31:46 +0000193 SET_BIT(con, ASCCON_STP); /* 2 stop bits */
wdenkbb1b8262003-03-27 12:09:35 +0000194 else
wdenk57b2d802003-06-27 21:31:46 +0000195 CLEAR_BIT(con, ASCCON_STP); /* 1 stop bit */
wdenkbb1b8262003-03-27 12:09:35 +0000196
197 if ( ASC_OPTIONS & ASCOPT_PARENB )
wdenk57b2d802003-06-27 21:31:46 +0000198 SET_BIT(con, ASCCON_PEN); /* enable parity checking */
wdenkbb1b8262003-03-27 12:09:35 +0000199 else
wdenk57b2d802003-06-27 21:31:46 +0000200 CLEAR_BIT(con, ASCCON_PEN); /* disable parity checking */
201
wdenkbb1b8262003-03-27 12:09:35 +0000202 if ( ASC_OPTIONS & ASCOPT_PARODD )
wdenk57b2d802003-06-27 21:31:46 +0000203 SET_BIT(con, ASCCON_ODD); /* odd parity */
wdenkbb1b8262003-03-27 12:09:35 +0000204 else
wdenk57b2d802003-06-27 21:31:46 +0000205 CLEAR_BIT(con, ASCCON_ODD); /* even parity */
wdenkbb1b8262003-03-27 12:09:35 +0000206
207 if ( ASC_OPTIONS & ASCOPT_CREAD )
wdenk57b2d802003-06-27 21:31:46 +0000208 SET_BIT(pAsc->asc_whbcon, ASCWHBCON_SETREN); /* Receiver enable */
wdenkbb1b8262003-03-27 12:09:35 +0000209
210 pAsc->asc_con |= con;
211
212 return 0;
213}
214
Marek Vasut2a9d9352012-09-13 01:20:07 +0200215static void asc_serial_putc(const char c)
wdenkbb1b8262003-03-27 12:09:35 +0000216{
217 uint txFl = 0;
218
219 if (c == '\n') serial_putc ('\r');
220
221 /* check do we have a free space in the TX FIFO */
222 /* get current filling level */
223 do
224 {
225 txFl = ( pAsc->asc_fstat & ASCFSTAT_TXFFLMASK ) >> ASCFSTAT_TXFFLOFF;
226 }
227 while ( txFl == INCAASC_TXFIFO_FULL );
228
229 pAsc->asc_tbuf = c; /* write char to Transmit Buffer Register */
wdenkb02744a2003-04-05 00:53:31 +0000230
wdenkbb1b8262003-03-27 12:09:35 +0000231 /* check for errors */
232 if ( pAsc->asc_con & ASCCON_OE )
233 {
wdenk57b2d802003-06-27 21:31:46 +0000234 SET_BIT(pAsc->asc_whbcon, ASCWHBCON_CLROE);
235 return;
wdenkbb1b8262003-03-27 12:09:35 +0000236 }
237}
238
Marek Vasut2a9d9352012-09-13 01:20:07 +0200239static void asc_serial_puts(const char *s)
wdenkbb1b8262003-03-27 12:09:35 +0000240{
241 while (*s)
242 {
243 serial_putc (*s++);
244 }
245}
246
Marek Vasut2a9d9352012-09-13 01:20:07 +0200247static int asc_serial_getc(void)
wdenkbb1b8262003-03-27 12:09:35 +0000248{
249 ulong symbol_mask;
250 char c;
251
252 while (!serial_tstc());
253
254 symbol_mask =
255 ((ASC_OPTIONS & ASCOPT_CSIZE) == ASCOPT_CS7) ? (0x7f) : (0xff);
wdenk57b2d802003-06-27 21:31:46 +0000256
wdenkbb1b8262003-03-27 12:09:35 +0000257 c = (char)(pAsc->asc_rbuf & symbol_mask);
258
259 return c;
260}
261
Marek Vasut2a9d9352012-09-13 01:20:07 +0200262static int asc_serial_tstc(void)
wdenkbb1b8262003-03-27 12:09:35 +0000263{
264 int res = 1;
265
266 if ( (pAsc->asc_fstat & ASCFSTAT_RXFFLMASK) == 0 )
267 {
wdenk57b2d802003-06-27 21:31:46 +0000268 res = 0;
wdenkbb1b8262003-03-27 12:09:35 +0000269 }
wdenkbb1b8262003-03-27 12:09:35 +0000270 else if ( pAsc->asc_con & ASCCON_FE )
271 {
wdenk57b2d802003-06-27 21:31:46 +0000272 SET_BIT(pAsc->asc_whbcon, ASCWHBCON_CLRFE);
273 res = 0;
wdenkbb1b8262003-03-27 12:09:35 +0000274 }
275 else if ( pAsc->asc_con & ASCCON_PE )
276 {
wdenk57b2d802003-06-27 21:31:46 +0000277 SET_BIT(pAsc->asc_whbcon, ASCWHBCON_CLRPE);
278 res = 0;
wdenkbb1b8262003-03-27 12:09:35 +0000279 }
280 else if ( pAsc->asc_con & ASCCON_OE )
281 {
wdenk57b2d802003-06-27 21:31:46 +0000282 SET_BIT(pAsc->asc_whbcon, ASCWHBCON_CLROE);
283 res = 0;
wdenkbb1b8262003-03-27 12:09:35 +0000284 }
285
286 return res;
287}
Marek Vasut2a9d9352012-09-13 01:20:07 +0200288
289#ifdef CONFIG_SERIAL_MULTI
290static struct serial_device asc_serial_drv = {
291 .name = "asc_serial",
292 .start = asc_serial_init,
293 .stop = NULL,
294 .setbrg = asc_serial_setbrg,
295 .putc = asc_serial_putc,
296 .puts = asc_serial_puts,
297 .getc = asc_serial_getc,
298 .tstc = asc_serial_tstc,
299};
300
301void asc_serial_initialize(void)
302{
303 serial_register(&asc_serial_drv);
304}
305
306__weak struct serial_device *default_serial_console(void)
307{
308 return &asc_serial_drv;
309}
310#else
311int serial_init(void)
312{
313 return asc_serial_init();
314}
315
316void serial_setbrg(void)
317{
318 asc_serial_setbrg();
319}
320
321void serial_putc(const char c)
322{
323 asc_serial_putc(c);
324}
325
326void serial_puts(const char *s)
327{
328 asc_serial_puts(s);
329}
330
331int serial_getc(void)
332{
333 return asc_serial_getc();
334}
335
336int serial_tstc(void)
337{
338 return asc_serial_tstc();
339}
340#endif