]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - cpu/mips/serial.c
ebda509b1168e6adfb15f9d47ce18ff12f6bbb02
[karo-tx-uboot.git] / cpu / mips / serial.c
1 /*
2  * (INCA) ASC UART support
3  */
4
5 #include <common.h>
6 #include <asm/inca-ip.h>
7 #include "serial.h"
8
9 #define SET_BIT(reg, mask)                  reg |= (mask)
10 #define CLEAR_BIT(reg, mask)                reg &= (~mask)
11 #define CLEAR_BITS(reg, mask)               CLEAR_BIT(reg, mask)
12 #define SET_BITS(reg, mask)                 SET_BIT(reg, mask)
13 #define SET_BITFIELD(reg, mask, off, val)   {reg &= (~mask); reg |= (val << off);}
14
15 extern uint incaip_get_fpiclk(void);
16
17 static int serial_setopt (void);
18
19 /* pointer to ASC register base address */
20 static volatile incaAsc_t *pAsc = (incaAsc_t *)INCA_IP_ASC;
21
22 /******************************************************************************
23 *
24 * serial_init - initialize a INCAASC channel
25 *
26 * This routine initializes the number of data bits, parity
27 * and set the selected baud rate. Interrupts are disabled.
28 * Set the modem control signals if the option is selected.
29 *
30 * RETURNS: N/A
31 */
32
33 int serial_init (void)
34 {
35     /* we have to set PMU.EN13 bit to enable an ASC device*/
36     INCAASC_PMU_ENABLE(13);
37     
38     /* and we have to set CLC register*/
39     CLEAR_BIT(pAsc->asc_clc, ASCCLC_DISS);
40     SET_BITFIELD(pAsc->asc_clc, ASCCLC_RMCMASK, ASCCLC_RMCOFFSET, 0x0001);
41     
42     /* initialy we are in async mode */
43     pAsc->asc_con = ASCCON_M_8ASYNC;
44
45     /* select input port */
46     pAsc->asc_pisel = (CONSOLE_TTY & 0x1);
47
48     /* TXFIFO's filling level */
49     SET_BITFIELD(pAsc->asc_txfcon, ASCTXFCON_TXFITLMASK,
50                     ASCTXFCON_TXFITLOFF, INCAASC_TXFIFO_FL);
51     /* enable TXFIFO */
52     SET_BIT(pAsc->asc_txfcon, ASCTXFCON_TXFEN);
53
54     /* RXFIFO's filling level */
55     SET_BITFIELD(pAsc->asc_txfcon, ASCRXFCON_RXFITLMASK, 
56                     ASCRXFCON_RXFITLOFF, INCAASC_RXFIFO_FL);
57     /* enable RXFIFO */
58     SET_BIT(pAsc->asc_rxfcon, ASCRXFCON_RXFEN);
59
60     /* enable error signals */
61     SET_BIT(pAsc->asc_con, ASCCON_FEN);
62     SET_BIT(pAsc->asc_con, ASCCON_OEN);
63
64     /* acknowledge ASC interrupts */
65     ASC_INTERRUPTS_CLEAR(INCAASC_IRQ_LINE_ALL);
66
67     /* disable ASC interrupts */
68     ASC_INTERRUPTS_DISABLE(INCAASC_IRQ_LINE_ALL);
69
70     /* set FIFOs into the transparent mode */
71     SET_BIT(pAsc->asc_txfcon, ASCTXFCON_TXTMEN);
72     SET_BIT(pAsc->asc_rxfcon, ASCRXFCON_RXTMEN);
73
74     /* set baud rate */
75     serial_setbrg();
76
77     /* set the options */
78     serial_setopt();
79     
80     return 0;
81 }
82
83 void serial_setbrg (void)
84 {
85     ulong      uiReloadValue, fdv;
86     ulong      f_ASC;
87
88     f_ASC = incaip_get_fpiclk();
89
90 #ifndef INCAASC_USE_FDV
91     fdv = 2;
92     uiReloadValue = (f_ASC / (fdv * 16 * CONFIG_BAUDRATE)) - 1;
93 #else 
94     fdv = INCAASC_FDV_HIGH_BAUDRATE;
95     uiReloadValue = (f_ASC / (8192 * CONFIG_BAUDRATE / fdv)) - 1;
96 #endif /* INCAASC_USE_FDV */
97     
98     if ( (uiReloadValue < 0) || (uiReloadValue > 8191) )
99     {
100 #ifndef INCAASC_USE_FDV
101         fdv = 3;
102         uiReloadValue = (f_ASC / (fdv * 16 * CONFIG_BAUDRATE)) - 1;
103 #else 
104         fdv = INCAASC_FDV_LOW_BAUDRATE;
105         uiReloadValue = (f_ASC / (8192 * CONFIG_BAUDRATE / fdv)) - 1;
106 #endif /* INCAASC_USE_FDV */
107         
108         if ( (uiReloadValue < 0) || (uiReloadValue > 8191) )
109         {
110             return;    /* can't impossibly generate that baud rate */
111         }
112     }
113
114     /* Disable Baud Rate Generator; BG should only be written when R=0 */
115     CLEAR_BIT(pAsc->asc_con, ASCCON_R);
116
117 #ifndef INCAASC_USE_FDV
118     /*
119      * Disable Fractional Divider (FDE)
120      * Divide clock by reload-value + constant (BRS)
121      */
122     /* FDE = 0 */
123     CLEAR_BIT(pAsc->asc_con, ASCCON_FDE);
124
125     if ( fdv == 2 )
126         CLEAR_BIT(pAsc->asc_con, ASCCON_BRS);   /* BRS = 0 */
127     else
128         SET_BIT(pAsc->asc_con, ASCCON_BRS); /* BRS = 1 */
129
130 #else /* INCAASC_USE_FDV */
131
132     /* Enable Fractional Divider */
133     SET_BIT(pAsc->asc_con, ASCCON_FDE); /* FDE = 1 */
134
135     /* Set fractional divider value */
136     pAsc->asc_fdv = fdv & ASCFDV_VALUE_MASK;
137
138 #endif /* INCAASC_USE_FDV */
139
140     /* Set reload value in BG */
141     pAsc->asc_bg = uiReloadValue;
142
143     /* Enable Baud Rate Generator */
144     SET_BIT(pAsc->asc_con, ASCCON_R);           /* R = 1 */
145 }
146
147 /*******************************************************************************
148 *
149 * serial_setopt - set the serial options
150 *
151 * Set the channel operating mode to that specified. Following options
152 * are supported: CREAD, CSIZE, PARENB, and PARODD.
153 *
154 * Note, this routine disables the transmitter.  The calling routine
155 * may have to re-enable it.
156 *
157 * RETURNS:
158 * Returns 0 to indicate success, otherwise -1 is returned
159 */
160
161 static int serial_setopt (void)
162 {
163     ulong  con;
164
165     switch ( ASC_OPTIONS & ASCOPT_CSIZE )
166     {
167     /* 7-bit-data */
168     case ASCOPT_CS7:
169         con = ASCCON_M_7ASYNCPAR;   /* 7-bit-data and parity bit */
170         break;
171
172     /* 8-bit-data */
173     case ASCOPT_CS8:
174         if ( ASC_OPTIONS & ASCOPT_PARENB )
175             con = ASCCON_M_8ASYNCPAR;   /* 8-bit-data and parity bit */
176         else
177             con = ASCCON_M_8ASYNC;      /* 8-bit-data no parity */
178         break;
179     
180     /* 
181      *  only 7 and 8-bit frames are supported
182      *  if we don't use IOCTL extensions 
183      */
184     default:
185         return -1;
186     }
187
188     if ( ASC_OPTIONS & ASCOPT_STOPB )
189         SET_BIT(con, ASCCON_STP);       /* 2 stop bits */
190     else
191         CLEAR_BIT(con, ASCCON_STP);     /* 1 stop bit */
192
193     if ( ASC_OPTIONS & ASCOPT_PARENB )
194         SET_BIT(con, ASCCON_PEN);           /* enable parity checking */    
195     else
196         CLEAR_BIT(con, ASCCON_PEN);         /* disable parity checking */
197     
198     if ( ASC_OPTIONS & ASCOPT_PARODD )
199         SET_BIT(con, ASCCON_ODD);       /* odd parity */
200     else
201         CLEAR_BIT(con, ASCCON_ODD);     /* even parity */
202
203     if ( ASC_OPTIONS & ASCOPT_CREAD )
204         SET_BIT(pAsc->asc_whbcon, ASCWHBCON_SETREN); /* Receiver enable */
205
206     pAsc->asc_con |= con;
207
208     return 0;
209 }
210
211 void serial_putc (const char c)
212 {
213     uint txFl = 0;
214
215     if (c == '\n') serial_putc ('\r');
216
217     /* check do we have a free space in the TX FIFO */
218     /* get current filling level */
219     do
220     {
221         txFl = ( pAsc->asc_fstat & ASCFSTAT_TXFFLMASK ) >> ASCFSTAT_TXFFLOFF;
222     }
223     while ( txFl == INCAASC_TXFIFO_FULL );
224
225     pAsc->asc_tbuf = c; /* write char to Transmit Buffer Register */
226     /* check for errors */
227     if ( pAsc->asc_con & ASCCON_OE )
228     {
229         SET_BIT(pAsc->asc_whbcon, ASCWHBCON_CLROE);
230         return;
231     }
232 }
233
234 void serial_puts (const char *s)
235 {
236     while (*s)
237     {
238         serial_putc (*s++);
239     }
240 }
241
242 int serial_getc (void)
243 {
244     ulong symbol_mask;
245     char c;
246
247     while (!serial_tstc());
248
249     symbol_mask =
250         ((ASC_OPTIONS & ASCOPT_CSIZE) == ASCOPT_CS7) ? (0x7f) : (0xff);
251     
252     c = (char)(pAsc->asc_rbuf & symbol_mask);
253
254     return c;
255 }
256
257 int serial_tstc (void)
258 {
259     int res = 1;
260
261     if ( (pAsc->asc_fstat & ASCFSTAT_RXFFLMASK) == 0 )
262     {
263         res = 0;
264     }
265     else if ( pAsc->asc_con & ASCCON_FE )
266     {
267         SET_BIT(pAsc->asc_whbcon, ASCWHBCON_CLRFE);
268         res = 0;
269     }
270     else if ( pAsc->asc_con & ASCCON_PE )
271     {
272         SET_BIT(pAsc->asc_whbcon, ASCWHBCON_CLRPE);
273         res = 0;
274     }
275     else if ( pAsc->asc_con & ASCCON_OE )
276     {
277         SET_BIT(pAsc->asc_whbcon, ASCWHBCON_CLROE);
278         res = 0;
279     }
280
281     return res;
282 }