blob: d95ec3fd2fc27de91e4c4bf03f115834b0b5edd1 [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>
6
wdenk9b7f3842003-10-09 20:09:04 +00007#if defined(CONFIG_PURPLE) || defined(CONFIG_INCA_IP)
8
wdenkb02744a2003-04-05 00:53:31 +00009#ifdef CONFIG_PURPLE
10#define serial_init asc_serial_init
11#define serial_putc asc_serial_putc
12#define serial_puts asc_serial_puts
13#define serial_getc asc_serial_getc
14#define serial_tstc asc_serial_tstc
15#define serial_setbrg asc_serial_setbrg
16#endif
17
wdenkbb1b8262003-03-27 12:09:35 +000018#include <common.h>
19#include <asm/inca-ip.h>
wdenk9b7f3842003-10-09 20:09:04 +000020#include "asc_serial.h"
wdenkbb1b8262003-03-27 12:09:35 +000021
wdenkb02744a2003-04-05 00:53:31 +000022#ifdef CONFIG_PURPLE
23
24#undef ASC_FIFO_PRESENT
25#define TOUT_LOOP 100000
26
27/* Set base address for second FPI interrupt control register bank */
wdenk57b2d802003-06-27 21:31:46 +000028#define SFPI_INTCON_BASEADDR 0xBF0F0000
wdenkb02744a2003-04-05 00:53:31 +000029
30/* Register offset from base address */
31#define FBS_ISR 0x00000000 /* Interrupt status register */
32#define FBS_IMR 0x00000008 /* Interrupt mask register */
33#define FBS_IDIS 0x00000010 /* Interrupt disable register */
34
35/* Interrupt status register bits */
36#define FBS_ISR_AT 0x00000040 /* ASC transmit interrupt */
37#define FBS_ISR_AR 0x00000020 /* ASC receive interrupt */
38#define FBS_ISR_AE 0x00000010 /* ASC error interrupt */
39#define FBS_ISR_AB 0x00000008 /* ASC transmit buffer interrupt */
40#define FBS_ISR_AS 0x00000004 /* ASC start of autobaud detection interrupt */
41#define FBS_ISR_AF 0x00000002 /* ASC end of autobaud detection interrupt */
42
43#else
44
45#define ASC_FIFO_PRESENT
46
47#endif
48
49
wdenkbb1b8262003-03-27 12:09:35 +000050#define SET_BIT(reg, mask) reg |= (mask)
51#define CLEAR_BIT(reg, mask) reg &= (~mask)
52#define CLEAR_BITS(reg, mask) CLEAR_BIT(reg, mask)
53#define SET_BITS(reg, mask) SET_BIT(reg, mask)
54#define SET_BITFIELD(reg, mask, off, val) {reg &= (~mask); reg |= (val << off);}
55
56extern uint incaip_get_fpiclk(void);
57
58static int serial_setopt (void);
59
60/* pointer to ASC register base address */
61static volatile incaAsc_t *pAsc = (incaAsc_t *)INCA_IP_ASC;
62
63/******************************************************************************
64*
65* serial_init - initialize a INCAASC channel
66*
67* This routine initializes the number of data bits, parity
68* and set the selected baud rate. Interrupts are disabled.
69* Set the modem control signals if the option is selected.
70*
71* RETURNS: N/A
72*/
73
74int serial_init (void)
75{
wdenkb02744a2003-04-05 00:53:31 +000076#ifdef CONFIG_INCA_IP
wdenkbb1b8262003-03-27 12:09:35 +000077 /* we have to set PMU.EN13 bit to enable an ASC device*/
78 INCAASC_PMU_ENABLE(13);
wdenkb02744a2003-04-05 00:53:31 +000079#endif
wdenk57b2d802003-06-27 21:31:46 +000080
wdenkbb1b8262003-03-27 12:09:35 +000081 /* and we have to set CLC register*/
82 CLEAR_BIT(pAsc->asc_clc, ASCCLC_DISS);
83 SET_BITFIELD(pAsc->asc_clc, ASCCLC_RMCMASK, ASCCLC_RMCOFFSET, 0x0001);
wdenk57b2d802003-06-27 21:31:46 +000084
wdenkbb1b8262003-03-27 12:09:35 +000085 /* initialy we are in async mode */
86 pAsc->asc_con = ASCCON_M_8ASYNC;
87
88 /* select input port */
89 pAsc->asc_pisel = (CONSOLE_TTY & 0x1);
90
wdenkb02744a2003-04-05 00:53:31 +000091#ifdef ASC_FIFO_PRESENT
wdenkbb1b8262003-03-27 12:09:35 +000092 /* TXFIFO's filling level */
93 SET_BITFIELD(pAsc->asc_txfcon, ASCTXFCON_TXFITLMASK,
wdenk57b2d802003-06-27 21:31:46 +000094 ASCTXFCON_TXFITLOFF, INCAASC_TXFIFO_FL);
wdenkbb1b8262003-03-27 12:09:35 +000095 /* enable TXFIFO */
96 SET_BIT(pAsc->asc_txfcon, ASCTXFCON_TXFEN);
97
98 /* RXFIFO's filling level */
wdenk57b2d802003-06-27 21:31:46 +000099 SET_BITFIELD(pAsc->asc_txfcon, ASCRXFCON_RXFITLMASK,
100 ASCRXFCON_RXFITLOFF, INCAASC_RXFIFO_FL);
wdenkbb1b8262003-03-27 12:09:35 +0000101 /* enable RXFIFO */
102 SET_BIT(pAsc->asc_rxfcon, ASCRXFCON_RXFEN);
wdenkb02744a2003-04-05 00:53:31 +0000103#endif
wdenkbb1b8262003-03-27 12:09:35 +0000104
105 /* enable error signals */
106 SET_BIT(pAsc->asc_con, ASCCON_FEN);
107 SET_BIT(pAsc->asc_con, ASCCON_OEN);
108
wdenkb02744a2003-04-05 00:53:31 +0000109#ifdef CONFIG_INCA_IP
wdenkbb1b8262003-03-27 12:09:35 +0000110 /* acknowledge ASC interrupts */
111 ASC_INTERRUPTS_CLEAR(INCAASC_IRQ_LINE_ALL);
112
113 /* disable ASC interrupts */
114 ASC_INTERRUPTS_DISABLE(INCAASC_IRQ_LINE_ALL);
wdenkb02744a2003-04-05 00:53:31 +0000115#endif
wdenkbb1b8262003-03-27 12:09:35 +0000116
wdenkb02744a2003-04-05 00:53:31 +0000117#ifdef ASC_FIFO_PRESENT
wdenkbb1b8262003-03-27 12:09:35 +0000118 /* set FIFOs into the transparent mode */
119 SET_BIT(pAsc->asc_txfcon, ASCTXFCON_TXTMEN);
120 SET_BIT(pAsc->asc_rxfcon, ASCRXFCON_RXTMEN);
wdenkb02744a2003-04-05 00:53:31 +0000121#endif
wdenkbb1b8262003-03-27 12:09:35 +0000122
123 /* set baud rate */
124 serial_setbrg();
125
126 /* set the options */
127 serial_setopt();
wdenk57b2d802003-06-27 21:31:46 +0000128
wdenkbb1b8262003-03-27 12:09:35 +0000129 return 0;
130}
131
132void serial_setbrg (void)
133{
134 ulong uiReloadValue, fdv;
135 ulong f_ASC;
136
wdenkb02744a2003-04-05 00:53:31 +0000137#ifdef CONFIG_INCA_IP
wdenkbb1b8262003-03-27 12:09:35 +0000138 f_ASC = incaip_get_fpiclk();
wdenkb02744a2003-04-05 00:53:31 +0000139#else
140 f_ASC = ASC_CLOCK_RATE;
141#endif
wdenkbb1b8262003-03-27 12:09:35 +0000142
143#ifndef INCAASC_USE_FDV
144 fdv = 2;
145 uiReloadValue = (f_ASC / (fdv * 16 * CONFIG_BAUDRATE)) - 1;
wdenk57b2d802003-06-27 21:31:46 +0000146#else
wdenkbb1b8262003-03-27 12:09:35 +0000147 fdv = INCAASC_FDV_HIGH_BAUDRATE;
148 uiReloadValue = (f_ASC / (8192 * CONFIG_BAUDRATE / fdv)) - 1;
149#endif /* INCAASC_USE_FDV */
wdenk57b2d802003-06-27 21:31:46 +0000150
wdenkbb1b8262003-03-27 12:09:35 +0000151 if ( (uiReloadValue < 0) || (uiReloadValue > 8191) )
152 {
153#ifndef INCAASC_USE_FDV
wdenk57b2d802003-06-27 21:31:46 +0000154 fdv = 3;
155 uiReloadValue = (f_ASC / (fdv * 16 * CONFIG_BAUDRATE)) - 1;
156#else
157 fdv = INCAASC_FDV_LOW_BAUDRATE;
158 uiReloadValue = (f_ASC / (8192 * CONFIG_BAUDRATE / fdv)) - 1;
wdenkbb1b8262003-03-27 12:09:35 +0000159#endif /* INCAASC_USE_FDV */
wdenk57b2d802003-06-27 21:31:46 +0000160
161 if ( (uiReloadValue < 0) || (uiReloadValue > 8191) )
162 {
163 return; /* can't impossibly generate that baud rate */
164 }
wdenkbb1b8262003-03-27 12:09:35 +0000165 }
166
167 /* Disable Baud Rate Generator; BG should only be written when R=0 */
168 CLEAR_BIT(pAsc->asc_con, ASCCON_R);
169
170#ifndef INCAASC_USE_FDV
171 /*
172 * Disable Fractional Divider (FDE)
173 * Divide clock by reload-value + constant (BRS)
174 */
175 /* FDE = 0 */
176 CLEAR_BIT(pAsc->asc_con, ASCCON_FDE);
177
178 if ( fdv == 2 )
wdenk57b2d802003-06-27 21:31:46 +0000179 CLEAR_BIT(pAsc->asc_con, ASCCON_BRS); /* BRS = 0 */
wdenkbb1b8262003-03-27 12:09:35 +0000180 else
wdenk57b2d802003-06-27 21:31:46 +0000181 SET_BIT(pAsc->asc_con, ASCCON_BRS); /* BRS = 1 */
wdenkbb1b8262003-03-27 12:09:35 +0000182
183#else /* INCAASC_USE_FDV */
184
185 /* Enable Fractional Divider */
186 SET_BIT(pAsc->asc_con, ASCCON_FDE); /* FDE = 1 */
187
188 /* Set fractional divider value */
189 pAsc->asc_fdv = fdv & ASCFDV_VALUE_MASK;
190
191#endif /* INCAASC_USE_FDV */
192
193 /* Set reload value in BG */
194 pAsc->asc_bg = uiReloadValue;
195
196 /* Enable Baud Rate Generator */
197 SET_BIT(pAsc->asc_con, ASCCON_R); /* R = 1 */
198}
199
200/*******************************************************************************
201*
202* serial_setopt - set the serial options
203*
204* Set the channel operating mode to that specified. Following options
205* are supported: CREAD, CSIZE, PARENB, and PARODD.
206*
207* Note, this routine disables the transmitter. The calling routine
208* may have to re-enable it.
209*
210* RETURNS:
211* Returns 0 to indicate success, otherwise -1 is returned
212*/
213
214static int serial_setopt (void)
215{
216 ulong con;
217
218 switch ( ASC_OPTIONS & ASCOPT_CSIZE )
219 {
220 /* 7-bit-data */
221 case ASCOPT_CS7:
wdenk57b2d802003-06-27 21:31:46 +0000222 con = ASCCON_M_7ASYNCPAR; /* 7-bit-data and parity bit */
223 break;
wdenkbb1b8262003-03-27 12:09:35 +0000224
225 /* 8-bit-data */
226 case ASCOPT_CS8:
wdenk57b2d802003-06-27 21:31:46 +0000227 if ( ASC_OPTIONS & ASCOPT_PARENB )
228 con = ASCCON_M_8ASYNCPAR; /* 8-bit-data and parity bit */
229 else
230 con = ASCCON_M_8ASYNC; /* 8-bit-data no parity */
231 break;
232
233 /*
wdenkbb1b8262003-03-27 12:09:35 +0000234 * only 7 and 8-bit frames are supported
wdenk57b2d802003-06-27 21:31:46 +0000235 * if we don't use IOCTL extensions
wdenkbb1b8262003-03-27 12:09:35 +0000236 */
237 default:
wdenk57b2d802003-06-27 21:31:46 +0000238 return -1;
wdenkbb1b8262003-03-27 12:09:35 +0000239 }
240
241 if ( ASC_OPTIONS & ASCOPT_STOPB )
wdenk57b2d802003-06-27 21:31:46 +0000242 SET_BIT(con, ASCCON_STP); /* 2 stop bits */
wdenkbb1b8262003-03-27 12:09:35 +0000243 else
wdenk57b2d802003-06-27 21:31:46 +0000244 CLEAR_BIT(con, ASCCON_STP); /* 1 stop bit */
wdenkbb1b8262003-03-27 12:09:35 +0000245
246 if ( ASC_OPTIONS & ASCOPT_PARENB )
wdenk57b2d802003-06-27 21:31:46 +0000247 SET_BIT(con, ASCCON_PEN); /* enable parity checking */
wdenkbb1b8262003-03-27 12:09:35 +0000248 else
wdenk57b2d802003-06-27 21:31:46 +0000249 CLEAR_BIT(con, ASCCON_PEN); /* disable parity checking */
250
wdenkbb1b8262003-03-27 12:09:35 +0000251 if ( ASC_OPTIONS & ASCOPT_PARODD )
wdenk57b2d802003-06-27 21:31:46 +0000252 SET_BIT(con, ASCCON_ODD); /* odd parity */
wdenkbb1b8262003-03-27 12:09:35 +0000253 else
wdenk57b2d802003-06-27 21:31:46 +0000254 CLEAR_BIT(con, ASCCON_ODD); /* even parity */
wdenkbb1b8262003-03-27 12:09:35 +0000255
256 if ( ASC_OPTIONS & ASCOPT_CREAD )
wdenk57b2d802003-06-27 21:31:46 +0000257 SET_BIT(pAsc->asc_whbcon, ASCWHBCON_SETREN); /* Receiver enable */
wdenkbb1b8262003-03-27 12:09:35 +0000258
259 pAsc->asc_con |= con;
260
261 return 0;
262}
263
264void serial_putc (const char c)
265{
wdenkb02744a2003-04-05 00:53:31 +0000266#ifdef ASC_FIFO_PRESENT
wdenkbb1b8262003-03-27 12:09:35 +0000267 uint txFl = 0;
wdenkb02744a2003-04-05 00:53:31 +0000268#else
269 uint timeout = 0;
270#endif
wdenkbb1b8262003-03-27 12:09:35 +0000271
272 if (c == '\n') serial_putc ('\r');
273
wdenkb02744a2003-04-05 00:53:31 +0000274#ifdef ASC_FIFO_PRESENT
wdenkbb1b8262003-03-27 12:09:35 +0000275 /* check do we have a free space in the TX FIFO */
276 /* get current filling level */
277 do
278 {
279 txFl = ( pAsc->asc_fstat & ASCFSTAT_TXFFLMASK ) >> ASCFSTAT_TXFFLOFF;
280 }
281 while ( txFl == INCAASC_TXFIFO_FULL );
wdenkb02744a2003-04-05 00:53:31 +0000282#else
283
284 while(!(*(volatile unsigned long*)(SFPI_INTCON_BASEADDR + FBS_ISR) &
285 FBS_ISR_AB))
286 {
287 if (timeout++ > TOUT_LOOP)
288 {
289 break;
290 }
291 }
292#endif
wdenkbb1b8262003-03-27 12:09:35 +0000293
294 pAsc->asc_tbuf = c; /* write char to Transmit Buffer Register */
wdenkb02744a2003-04-05 00:53:31 +0000295
296#ifndef ASC_FIFO_PRESENT
297 *(volatile unsigned long*)(SFPI_INTCON_BASEADDR + FBS_ISR) = FBS_ISR_AB |
wdenk57b2d802003-06-27 21:31:46 +0000298 FBS_ISR_AT;
wdenkb02744a2003-04-05 00:53:31 +0000299#endif
wdenk57b2d802003-06-27 21:31:46 +0000300
wdenkbb1b8262003-03-27 12:09:35 +0000301 /* check for errors */
302 if ( pAsc->asc_con & ASCCON_OE )
303 {
wdenk57b2d802003-06-27 21:31:46 +0000304 SET_BIT(pAsc->asc_whbcon, ASCWHBCON_CLROE);
305 return;
wdenkbb1b8262003-03-27 12:09:35 +0000306 }
307}
308
309void serial_puts (const char *s)
310{
311 while (*s)
312 {
313 serial_putc (*s++);
314 }
315}
316
317int serial_getc (void)
318{
319 ulong symbol_mask;
320 char c;
321
322 while (!serial_tstc());
323
324 symbol_mask =
325 ((ASC_OPTIONS & ASCOPT_CSIZE) == ASCOPT_CS7) ? (0x7f) : (0xff);
wdenk57b2d802003-06-27 21:31:46 +0000326
wdenkbb1b8262003-03-27 12:09:35 +0000327 c = (char)(pAsc->asc_rbuf & symbol_mask);
328
wdenkb02744a2003-04-05 00:53:31 +0000329#ifndef ASC_FIFO_PRESENT
330 *(volatile unsigned long*)(SFPI_INTCON_BASEADDR + FBS_ISR) = FBS_ISR_AR;
331#endif
332
wdenkbb1b8262003-03-27 12:09:35 +0000333 return c;
334}
335
336int serial_tstc (void)
337{
338 int res = 1;
339
wdenkb02744a2003-04-05 00:53:31 +0000340#ifdef ASC_FIFO_PRESENT
wdenkbb1b8262003-03-27 12:09:35 +0000341 if ( (pAsc->asc_fstat & ASCFSTAT_RXFFLMASK) == 0 )
342 {
wdenk57b2d802003-06-27 21:31:46 +0000343 res = 0;
wdenkbb1b8262003-03-27 12:09:35 +0000344 }
wdenkb02744a2003-04-05 00:53:31 +0000345#else
346 if (!(*(volatile unsigned long*)(SFPI_INTCON_BASEADDR + FBS_ISR) &
wdenk57b2d802003-06-27 21:31:46 +0000347 FBS_ISR_AR))
348
wdenkb02744a2003-04-05 00:53:31 +0000349 {
wdenk57b2d802003-06-27 21:31:46 +0000350 res = 0;
wdenkb02744a2003-04-05 00:53:31 +0000351 }
352#endif
wdenkbb1b8262003-03-27 12:09:35 +0000353 else if ( pAsc->asc_con & ASCCON_FE )
354 {
wdenk57b2d802003-06-27 21:31:46 +0000355 SET_BIT(pAsc->asc_whbcon, ASCWHBCON_CLRFE);
356 res = 0;
wdenkbb1b8262003-03-27 12:09:35 +0000357 }
358 else if ( pAsc->asc_con & ASCCON_PE )
359 {
wdenk57b2d802003-06-27 21:31:46 +0000360 SET_BIT(pAsc->asc_whbcon, ASCWHBCON_CLRPE);
361 res = 0;
wdenkbb1b8262003-03-27 12:09:35 +0000362 }
363 else if ( pAsc->asc_con & ASCCON_OE )
364 {
wdenk57b2d802003-06-27 21:31:46 +0000365 SET_BIT(pAsc->asc_whbcon, ASCWHBCON_CLROE);
366 res = 0;
wdenkbb1b8262003-03-27 12:09:35 +0000367 }
368
369 return res;
370}
wdenk9b7f3842003-10-09 20:09:04 +0000371#endif /* CONFIG_PURPLE || CONFIG_INCA_IP */