blob: ebda509b1168e6adfb15f9d47ce18ff12f6bbb02 [file] [log] [blame]
wdenkc0218802003-03-27 12:09:35 +00001/*
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
15extern uint incaip_get_fpiclk(void);
16
17static int serial_setopt (void);
18
19/* pointer to ASC register base address */
20static 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
33int 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
83void 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
161static 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
211void 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
234void serial_puts (const char *s)
235{
236 while (*s)
237 {
238 serial_putc (*s++);
239 }
240}
241
242int 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
257int 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}