]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - cpu/mips/asc_serial.c
* Patch by Steven Scholz, 10 Oct 2003
[karo-tx-uboot.git] / cpu / mips / asc_serial.c
1 /*
2  * (INCA) ASC UART support
3  */
4
5 #include <config.h>
6
7 #if defined(CONFIG_PURPLE) || defined(CONFIG_INCA_IP)
8
9 #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
18 #include <common.h>
19 #include <asm/inca-ip.h>
20 #include "asc_serial.h"
21
22 #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 */
28 #define SFPI_INTCON_BASEADDR    0xBF0F0000
29
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
50 #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
56 extern uint incaip_get_fpiclk(void);
57
58 static int serial_setopt (void);
59
60 /* pointer to ASC register base address */
61 static 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
74 int serial_init (void)
75 {
76 #ifdef CONFIG_INCA_IP
77     /* we have to set PMU.EN13 bit to enable an ASC device*/
78     INCAASC_PMU_ENABLE(13);
79 #endif
80
81     /* 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);
84
85     /* 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
91 #ifdef ASC_FIFO_PRESENT
92     /* TXFIFO's filling level */
93     SET_BITFIELD(pAsc->asc_txfcon, ASCTXFCON_TXFITLMASK,
94                     ASCTXFCON_TXFITLOFF, INCAASC_TXFIFO_FL);
95     /* enable TXFIFO */
96     SET_BIT(pAsc->asc_txfcon, ASCTXFCON_TXFEN);
97
98     /* RXFIFO's filling level */
99     SET_BITFIELD(pAsc->asc_txfcon, ASCRXFCON_RXFITLMASK,
100                     ASCRXFCON_RXFITLOFF, INCAASC_RXFIFO_FL);
101     /* enable RXFIFO */
102     SET_BIT(pAsc->asc_rxfcon, ASCRXFCON_RXFEN);
103 #endif
104
105     /* enable error signals */
106     SET_BIT(pAsc->asc_con, ASCCON_FEN);
107     SET_BIT(pAsc->asc_con, ASCCON_OEN);
108
109 #ifdef CONFIG_INCA_IP
110     /* acknowledge ASC interrupts */
111     ASC_INTERRUPTS_CLEAR(INCAASC_IRQ_LINE_ALL);
112
113     /* disable ASC interrupts */
114     ASC_INTERRUPTS_DISABLE(INCAASC_IRQ_LINE_ALL);
115 #endif
116
117 #ifdef ASC_FIFO_PRESENT
118     /* set FIFOs into the transparent mode */
119     SET_BIT(pAsc->asc_txfcon, ASCTXFCON_TXTMEN);
120     SET_BIT(pAsc->asc_rxfcon, ASCRXFCON_RXTMEN);
121 #endif
122
123     /* set baud rate */
124     serial_setbrg();
125
126     /* set the options */
127     serial_setopt();
128
129     return 0;
130 }
131
132 void serial_setbrg (void)
133 {
134     ulong      uiReloadValue, fdv;
135     ulong      f_ASC;
136
137 #ifdef CONFIG_INCA_IP
138     f_ASC = incaip_get_fpiclk();
139 #else
140     f_ASC = ASC_CLOCK_RATE;
141 #endif
142
143 #ifndef INCAASC_USE_FDV
144     fdv = 2;
145     uiReloadValue = (f_ASC / (fdv * 16 * CONFIG_BAUDRATE)) - 1;
146 #else
147     fdv = INCAASC_FDV_HIGH_BAUDRATE;
148     uiReloadValue = (f_ASC / (8192 * CONFIG_BAUDRATE / fdv)) - 1;
149 #endif /* INCAASC_USE_FDV */
150
151     if ( (uiReloadValue < 0) || (uiReloadValue > 8191) )
152     {
153 #ifndef INCAASC_USE_FDV
154         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;
159 #endif /* INCAASC_USE_FDV */
160
161         if ( (uiReloadValue < 0) || (uiReloadValue > 8191) )
162         {
163             return;    /* can't impossibly generate that baud rate */
164         }
165     }
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 )
179         CLEAR_BIT(pAsc->asc_con, ASCCON_BRS);   /* BRS = 0 */
180     else
181         SET_BIT(pAsc->asc_con, ASCCON_BRS); /* BRS = 1 */
182
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
214 static int serial_setopt (void)
215 {
216     ulong  con;
217
218     switch ( ASC_OPTIONS & ASCOPT_CSIZE )
219     {
220     /* 7-bit-data */
221     case ASCOPT_CS7:
222         con = ASCCON_M_7ASYNCPAR;   /* 7-bit-data and parity bit */
223         break;
224
225     /* 8-bit-data */
226     case ASCOPT_CS8:
227         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     /*
234      *  only 7 and 8-bit frames are supported
235      *  if we don't use IOCTL extensions
236      */
237     default:
238         return -1;
239     }
240
241     if ( ASC_OPTIONS & ASCOPT_STOPB )
242         SET_BIT(con, ASCCON_STP);       /* 2 stop bits */
243     else
244         CLEAR_BIT(con, ASCCON_STP);     /* 1 stop bit */
245
246     if ( ASC_OPTIONS & ASCOPT_PARENB )
247         SET_BIT(con, ASCCON_PEN);           /* enable parity checking */
248     else
249         CLEAR_BIT(con, ASCCON_PEN);         /* disable parity checking */
250
251     if ( ASC_OPTIONS & ASCOPT_PARODD )
252         SET_BIT(con, ASCCON_ODD);       /* odd parity */
253     else
254         CLEAR_BIT(con, ASCCON_ODD);     /* even parity */
255
256     if ( ASC_OPTIONS & ASCOPT_CREAD )
257         SET_BIT(pAsc->asc_whbcon, ASCWHBCON_SETREN); /* Receiver enable */
258
259     pAsc->asc_con |= con;
260
261     return 0;
262 }
263
264 void serial_putc (const char c)
265 {
266 #ifdef ASC_FIFO_PRESENT
267     uint txFl = 0;
268 #else
269     uint timeout = 0;
270 #endif
271
272     if (c == '\n') serial_putc ('\r');
273
274 #ifdef ASC_FIFO_PRESENT
275     /* 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 );
282 #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
293
294     pAsc->asc_tbuf = c; /* write char to Transmit Buffer Register */
295
296 #ifndef ASC_FIFO_PRESENT
297     *(volatile unsigned long*)(SFPI_INTCON_BASEADDR + FBS_ISR) = FBS_ISR_AB |
298                                                                  FBS_ISR_AT;
299 #endif
300
301     /* check for errors */
302     if ( pAsc->asc_con & ASCCON_OE )
303     {
304         SET_BIT(pAsc->asc_whbcon, ASCWHBCON_CLROE);
305         return;
306     }
307 }
308
309 void serial_puts (const char *s)
310 {
311     while (*s)
312     {
313         serial_putc (*s++);
314     }
315 }
316
317 int 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);
326
327     c = (char)(pAsc->asc_rbuf & symbol_mask);
328
329 #ifndef ASC_FIFO_PRESENT
330     *(volatile unsigned long*)(SFPI_INTCON_BASEADDR + FBS_ISR) = FBS_ISR_AR;
331 #endif
332
333     return c;
334 }
335
336 int serial_tstc (void)
337 {
338     int res = 1;
339
340 #ifdef ASC_FIFO_PRESENT
341     if ( (pAsc->asc_fstat & ASCFSTAT_RXFFLMASK) == 0 )
342     {
343         res = 0;
344     }
345 #else
346     if (!(*(volatile unsigned long*)(SFPI_INTCON_BASEADDR + FBS_ISR) &
347                                                                 FBS_ISR_AR))
348
349     {
350         res = 0;
351     }
352 #endif
353     else if ( pAsc->asc_con & ASCCON_FE )
354     {
355         SET_BIT(pAsc->asc_whbcon, ASCWHBCON_CLRFE);
356         res = 0;
357     }
358     else if ( pAsc->asc_con & ASCCON_PE )
359     {
360         SET_BIT(pAsc->asc_whbcon, ASCWHBCON_CLRPE);
361         res = 0;
362     }
363     else if ( pAsc->asc_con & ASCCON_OE )
364     {
365         SET_BIT(pAsc->asc_whbcon, ASCWHBCON_CLROE);
366         res = 0;
367     }
368
369     return res;
370 }
371 #endif /* CONFIG_PURPLE || CONFIG_INCA_IP */