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