]>
Commit | Line | Data |
---|---|---|
c021880a WD |
1 | /* |
2 | * (INCA) ASC UART support | |
3 | */ | |
4 | ||
3e38691e WD |
5 | #include <config.h> |
6 | ||
5da627a4 WD |
7 | #if defined(CONFIG_PURPLE) || defined(CONFIG_INCA_IP) |
8 | ||
3e38691e WD |
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 | ||
c021880a WD |
18 | #include <common.h> |
19 | #include <asm/inca-ip.h> | |
5da627a4 | 20 | #include "asc_serial.h" |
c021880a | 21 | |
3e38691e WD |
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 */ | |
8bde7f77 | 28 | #define SFPI_INTCON_BASEADDR 0xBF0F0000 |
3e38691e WD |
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 */ | |
53677ef1 | 37 | #define FBS_ISR_AR 0x00000020 /* ASC receive interrupt */ |
3e38691e WD |
38 | #define FBS_ISR_AE 0x00000010 /* ASC error interrupt */ |
39 | #define FBS_ISR_AB 0x00000008 /* ASC transmit buffer interrupt */ | |
53677ef1 | 40 | #define FBS_ISR_AS 0x00000004 /* ASC start of autobaud detection interrupt */ |
3e38691e WD |
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 | ||
c021880a WD |
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 | { | |
3e38691e | 76 | #ifdef CONFIG_INCA_IP |
c021880a WD |
77 | /* we have to set PMU.EN13 bit to enable an ASC device*/ |
78 | INCAASC_PMU_ENABLE(13); | |
3e38691e | 79 | #endif |
8bde7f77 | 80 | |
c021880a WD |
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); | |
8bde7f77 | 84 | |
c021880a WD |
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 | ||
3e38691e | 91 | #ifdef ASC_FIFO_PRESENT |
c021880a WD |
92 | /* TXFIFO's filling level */ |
93 | SET_BITFIELD(pAsc->asc_txfcon, ASCTXFCON_TXFITLMASK, | |
8bde7f77 | 94 | ASCTXFCON_TXFITLOFF, INCAASC_TXFIFO_FL); |
c021880a WD |
95 | /* enable TXFIFO */ |
96 | SET_BIT(pAsc->asc_txfcon, ASCTXFCON_TXFEN); | |
97 | ||
98 | /* RXFIFO's filling level */ | |
8bde7f77 WD |
99 | SET_BITFIELD(pAsc->asc_txfcon, ASCRXFCON_RXFITLMASK, |
100 | ASCRXFCON_RXFITLOFF, INCAASC_RXFIFO_FL); | |
c021880a WD |
101 | /* enable RXFIFO */ |
102 | SET_BIT(pAsc->asc_rxfcon, ASCRXFCON_RXFEN); | |
3e38691e | 103 | #endif |
c021880a WD |
104 | |
105 | /* enable error signals */ | |
106 | SET_BIT(pAsc->asc_con, ASCCON_FEN); | |
107 | SET_BIT(pAsc->asc_con, ASCCON_OEN); | |
108 | ||
3e38691e | 109 | #ifdef CONFIG_INCA_IP |
c021880a WD |
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); | |
3e38691e | 115 | #endif |
c021880a | 116 | |
3e38691e | 117 | #ifdef ASC_FIFO_PRESENT |
c021880a WD |
118 | /* set FIFOs into the transparent mode */ |
119 | SET_BIT(pAsc->asc_txfcon, ASCTXFCON_TXTMEN); | |
120 | SET_BIT(pAsc->asc_rxfcon, ASCRXFCON_RXTMEN); | |
3e38691e | 121 | #endif |
c021880a WD |
122 | |
123 | /* set baud rate */ | |
124 | serial_setbrg(); | |
125 | ||
126 | /* set the options */ | |
127 | serial_setopt(); | |
8bde7f77 | 128 | |
c021880a WD |
129 | return 0; |
130 | } | |
131 | ||
132 | void serial_setbrg (void) | |
133 | { | |
134 | ulong uiReloadValue, fdv; | |
135 | ulong f_ASC; | |
136 | ||
3e38691e | 137 | #ifdef CONFIG_INCA_IP |
c021880a | 138 | f_ASC = incaip_get_fpiclk(); |
3e38691e WD |
139 | #else |
140 | f_ASC = ASC_CLOCK_RATE; | |
141 | #endif | |
c021880a WD |
142 | |
143 | #ifndef INCAASC_USE_FDV | |
144 | fdv = 2; | |
145 | uiReloadValue = (f_ASC / (fdv * 16 * CONFIG_BAUDRATE)) - 1; | |
8bde7f77 | 146 | #else |
c021880a WD |
147 | fdv = INCAASC_FDV_HIGH_BAUDRATE; |
148 | uiReloadValue = (f_ASC / (8192 * CONFIG_BAUDRATE / fdv)) - 1; | |
149 | #endif /* INCAASC_USE_FDV */ | |
8bde7f77 | 150 | |
c021880a WD |
151 | if ( (uiReloadValue < 0) || (uiReloadValue > 8191) ) |
152 | { | |
153 | #ifndef INCAASC_USE_FDV | |
8bde7f77 WD |
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; | |
c021880a | 159 | #endif /* INCAASC_USE_FDV */ |
8bde7f77 WD |
160 | |
161 | if ( (uiReloadValue < 0) || (uiReloadValue > 8191) ) | |
162 | { | |
163 | return; /* can't impossibly generate that baud rate */ | |
164 | } | |
c021880a WD |
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 ) | |
8bde7f77 | 179 | CLEAR_BIT(pAsc->asc_con, ASCCON_BRS); /* BRS = 0 */ |
c021880a | 180 | else |
8bde7f77 | 181 | SET_BIT(pAsc->asc_con, ASCCON_BRS); /* BRS = 1 */ |
c021880a WD |
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: | |
8bde7f77 WD |
222 | con = ASCCON_M_7ASYNCPAR; /* 7-bit-data and parity bit */ |
223 | break; | |
c021880a WD |
224 | |
225 | /* 8-bit-data */ | |
226 | case ASCOPT_CS8: | |
8bde7f77 WD |
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 | /* | |
c021880a | 234 | * only 7 and 8-bit frames are supported |
8bde7f77 | 235 | * if we don't use IOCTL extensions |
c021880a WD |
236 | */ |
237 | default: | |
8bde7f77 | 238 | return -1; |
c021880a WD |
239 | } |
240 | ||
241 | if ( ASC_OPTIONS & ASCOPT_STOPB ) | |
8bde7f77 | 242 | SET_BIT(con, ASCCON_STP); /* 2 stop bits */ |
c021880a | 243 | else |
8bde7f77 | 244 | CLEAR_BIT(con, ASCCON_STP); /* 1 stop bit */ |
c021880a WD |
245 | |
246 | if ( ASC_OPTIONS & ASCOPT_PARENB ) | |
8bde7f77 | 247 | SET_BIT(con, ASCCON_PEN); /* enable parity checking */ |
c021880a | 248 | else |
8bde7f77 WD |
249 | CLEAR_BIT(con, ASCCON_PEN); /* disable parity checking */ |
250 | ||
c021880a | 251 | if ( ASC_OPTIONS & ASCOPT_PARODD ) |
8bde7f77 | 252 | SET_BIT(con, ASCCON_ODD); /* odd parity */ |
c021880a | 253 | else |
8bde7f77 | 254 | CLEAR_BIT(con, ASCCON_ODD); /* even parity */ |
c021880a WD |
255 | |
256 | if ( ASC_OPTIONS & ASCOPT_CREAD ) | |
8bde7f77 | 257 | SET_BIT(pAsc->asc_whbcon, ASCWHBCON_SETREN); /* Receiver enable */ |
c021880a WD |
258 | |
259 | pAsc->asc_con |= con; | |
260 | ||
261 | return 0; | |
262 | } | |
263 | ||
264 | void serial_putc (const char c) | |
265 | { | |
3e38691e | 266 | #ifdef ASC_FIFO_PRESENT |
c021880a | 267 | uint txFl = 0; |
3e38691e WD |
268 | #else |
269 | uint timeout = 0; | |
270 | #endif | |
c021880a WD |
271 | |
272 | if (c == '\n') serial_putc ('\r'); | |
273 | ||
3e38691e | 274 | #ifdef ASC_FIFO_PRESENT |
c021880a WD |
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 ); | |
3e38691e WD |
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 | |
c021880a WD |
293 | |
294 | pAsc->asc_tbuf = c; /* write char to Transmit Buffer Register */ | |
3e38691e WD |
295 | |
296 | #ifndef ASC_FIFO_PRESENT | |
297 | *(volatile unsigned long*)(SFPI_INTCON_BASEADDR + FBS_ISR) = FBS_ISR_AB | | |
8bde7f77 | 298 | FBS_ISR_AT; |
3e38691e | 299 | #endif |
8bde7f77 | 300 | |
c021880a WD |
301 | /* check for errors */ |
302 | if ( pAsc->asc_con & ASCCON_OE ) | |
303 | { | |
8bde7f77 WD |
304 | SET_BIT(pAsc->asc_whbcon, ASCWHBCON_CLROE); |
305 | return; | |
c021880a WD |
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); | |
8bde7f77 | 326 | |
c021880a WD |
327 | c = (char)(pAsc->asc_rbuf & symbol_mask); |
328 | ||
3e38691e WD |
329 | #ifndef ASC_FIFO_PRESENT |
330 | *(volatile unsigned long*)(SFPI_INTCON_BASEADDR + FBS_ISR) = FBS_ISR_AR; | |
331 | #endif | |
332 | ||
c021880a WD |
333 | return c; |
334 | } | |
335 | ||
336 | int serial_tstc (void) | |
337 | { | |
338 | int res = 1; | |
339 | ||
3e38691e | 340 | #ifdef ASC_FIFO_PRESENT |
c021880a WD |
341 | if ( (pAsc->asc_fstat & ASCFSTAT_RXFFLMASK) == 0 ) |
342 | { | |
8bde7f77 | 343 | res = 0; |
c021880a | 344 | } |
3e38691e WD |
345 | #else |
346 | if (!(*(volatile unsigned long*)(SFPI_INTCON_BASEADDR + FBS_ISR) & | |
8bde7f77 WD |
347 | FBS_ISR_AR)) |
348 | ||
3e38691e | 349 | { |
8bde7f77 | 350 | res = 0; |
3e38691e WD |
351 | } |
352 | #endif | |
c021880a WD |
353 | else if ( pAsc->asc_con & ASCCON_FE ) |
354 | { | |
8bde7f77 WD |
355 | SET_BIT(pAsc->asc_whbcon, ASCWHBCON_CLRFE); |
356 | res = 0; | |
c021880a WD |
357 | } |
358 | else if ( pAsc->asc_con & ASCCON_PE ) | |
359 | { | |
8bde7f77 WD |
360 | SET_BIT(pAsc->asc_whbcon, ASCWHBCON_CLRPE); |
361 | res = 0; | |
c021880a WD |
362 | } |
363 | else if ( pAsc->asc_con & ASCCON_OE ) | |
364 | { | |
8bde7f77 WD |
365 | SET_BIT(pAsc->asc_whbcon, ASCWHBCON_CLROE); |
366 | res = 0; | |
c021880a WD |
367 | } |
368 | ||
369 | return res; | |
370 | } | |
5da627a4 | 371 | #endif /* CONFIG_PURPLE || CONFIG_INCA_IP */ |