blob: 7239804b9d4bc34afb8599d2b516b8a4347c60cf [file] [log] [blame]
wdenkbb1b8262003-03-27 12:09:35 +00001/*
2 * (INCA) ASC UART support
3 */
4
wdenkb02744a2003-04-05 00:53:31 +00005#include <config.h>
wdenkbb1b8262003-03-27 12:09:35 +00006#include <common.h>
7#include <asm/inca-ip.h>
wdenk9b7f3842003-10-09 20:09:04 +00008#include "asc_serial.h"
wdenkbb1b8262003-03-27 12:09:35 +00009
wdenkb02744a2003-04-05 00:53:31 +000010
wdenkbb1b8262003-03-27 12:09:35 +000011#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
17extern uint incaip_get_fpiclk(void);
18
19static int serial_setopt (void);
20
21/* pointer to ASC register base address */
22static 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
35int serial_init (void)
36{
37 /* we have to set PMU.EN13 bit to enable an ASC device*/
38 INCAASC_PMU_ENABLE(13);
wdenk57b2d802003-06-27 21:31:46 +000039
wdenkbb1b8262003-03-27 12:09:35 +000040 /* 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);
wdenk57b2d802003-06-27 21:31:46 +000043
wdenkbb1b8262003-03-27 12:09:35 +000044 /* 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,
wdenk57b2d802003-06-27 21:31:46 +000052 ASCTXFCON_TXFITLOFF, INCAASC_TXFIFO_FL);
wdenkbb1b8262003-03-27 12:09:35 +000053 /* enable TXFIFO */
54 SET_BIT(pAsc->asc_txfcon, ASCTXFCON_TXFEN);
55
56 /* RXFIFO's filling level */
wdenk57b2d802003-06-27 21:31:46 +000057 SET_BITFIELD(pAsc->asc_txfcon, ASCRXFCON_RXFITLMASK,
58 ASCRXFCON_RXFITLOFF, INCAASC_RXFIFO_FL);
wdenkbb1b8262003-03-27 12:09:35 +000059 /* 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();
wdenk57b2d802003-06-27 21:31:46 +000081
wdenkbb1b8262003-03-27 12:09:35 +000082 return 0;
83}
84
85void 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;
wdenk57b2d802003-06-27 21:31:46 +000095#else
wdenkbb1b8262003-03-27 12:09:35 +000096 fdv = INCAASC_FDV_HIGH_BAUDRATE;
97 uiReloadValue = (f_ASC / (8192 * CONFIG_BAUDRATE / fdv)) - 1;
98#endif /* INCAASC_USE_FDV */
wdenk57b2d802003-06-27 21:31:46 +000099
wdenkbb1b8262003-03-27 12:09:35 +0000100 if ( (uiReloadValue < 0) || (uiReloadValue > 8191) )
101 {
102#ifndef INCAASC_USE_FDV
wdenk57b2d802003-06-27 21:31:46 +0000103 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;
wdenkbb1b8262003-03-27 12:09:35 +0000108#endif /* INCAASC_USE_FDV */
wdenk57b2d802003-06-27 21:31:46 +0000109
110 if ( (uiReloadValue < 0) || (uiReloadValue > 8191) )
111 {
112 return; /* can't impossibly generate that baud rate */
113 }
wdenkbb1b8262003-03-27 12:09:35 +0000114 }
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 )
wdenk57b2d802003-06-27 21:31:46 +0000128 CLEAR_BIT(pAsc->asc_con, ASCCON_BRS); /* BRS = 0 */
wdenkbb1b8262003-03-27 12:09:35 +0000129 else
wdenk57b2d802003-06-27 21:31:46 +0000130 SET_BIT(pAsc->asc_con, ASCCON_BRS); /* BRS = 1 */
wdenkbb1b8262003-03-27 12:09:35 +0000131
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
163static int serial_setopt (void)
164{
165 ulong con;
166
167 switch ( ASC_OPTIONS & ASCOPT_CSIZE )
168 {
169 /* 7-bit-data */
170 case ASCOPT_CS7:
wdenk57b2d802003-06-27 21:31:46 +0000171 con = ASCCON_M_7ASYNCPAR; /* 7-bit-data and parity bit */
172 break;
wdenkbb1b8262003-03-27 12:09:35 +0000173
174 /* 8-bit-data */
175 case ASCOPT_CS8:
wdenk57b2d802003-06-27 21:31:46 +0000176 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 /*
wdenkbb1b8262003-03-27 12:09:35 +0000183 * only 7 and 8-bit frames are supported
wdenk57b2d802003-06-27 21:31:46 +0000184 * if we don't use IOCTL extensions
wdenkbb1b8262003-03-27 12:09:35 +0000185 */
186 default:
wdenk57b2d802003-06-27 21:31:46 +0000187 return -1;
wdenkbb1b8262003-03-27 12:09:35 +0000188 }
189
190 if ( ASC_OPTIONS & ASCOPT_STOPB )
wdenk57b2d802003-06-27 21:31:46 +0000191 SET_BIT(con, ASCCON_STP); /* 2 stop bits */
wdenkbb1b8262003-03-27 12:09:35 +0000192 else
wdenk57b2d802003-06-27 21:31:46 +0000193 CLEAR_BIT(con, ASCCON_STP); /* 1 stop bit */
wdenkbb1b8262003-03-27 12:09:35 +0000194
195 if ( ASC_OPTIONS & ASCOPT_PARENB )
wdenk57b2d802003-06-27 21:31:46 +0000196 SET_BIT(con, ASCCON_PEN); /* enable parity checking */
wdenkbb1b8262003-03-27 12:09:35 +0000197 else
wdenk57b2d802003-06-27 21:31:46 +0000198 CLEAR_BIT(con, ASCCON_PEN); /* disable parity checking */
199
wdenkbb1b8262003-03-27 12:09:35 +0000200 if ( ASC_OPTIONS & ASCOPT_PARODD )
wdenk57b2d802003-06-27 21:31:46 +0000201 SET_BIT(con, ASCCON_ODD); /* odd parity */
wdenkbb1b8262003-03-27 12:09:35 +0000202 else
wdenk57b2d802003-06-27 21:31:46 +0000203 CLEAR_BIT(con, ASCCON_ODD); /* even parity */
wdenkbb1b8262003-03-27 12:09:35 +0000204
205 if ( ASC_OPTIONS & ASCOPT_CREAD )
wdenk57b2d802003-06-27 21:31:46 +0000206 SET_BIT(pAsc->asc_whbcon, ASCWHBCON_SETREN); /* Receiver enable */
wdenkbb1b8262003-03-27 12:09:35 +0000207
208 pAsc->asc_con |= con;
209
210 return 0;
211}
212
213void 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 */
wdenkb02744a2003-04-05 00:53:31 +0000228
wdenkbb1b8262003-03-27 12:09:35 +0000229 /* check for errors */
230 if ( pAsc->asc_con & ASCCON_OE )
231 {
wdenk57b2d802003-06-27 21:31:46 +0000232 SET_BIT(pAsc->asc_whbcon, ASCWHBCON_CLROE);
233 return;
wdenkbb1b8262003-03-27 12:09:35 +0000234 }
235}
236
237void serial_puts (const char *s)
238{
239 while (*s)
240 {
241 serial_putc (*s++);
242 }
243}
244
245int 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);
wdenk57b2d802003-06-27 21:31:46 +0000254
wdenkbb1b8262003-03-27 12:09:35 +0000255 c = (char)(pAsc->asc_rbuf & symbol_mask);
256
257 return c;
258}
259
260int serial_tstc (void)
261{
262 int res = 1;
263
264 if ( (pAsc->asc_fstat & ASCFSTAT_RXFFLMASK) == 0 )
265 {
wdenk57b2d802003-06-27 21:31:46 +0000266 res = 0;
wdenkbb1b8262003-03-27 12:09:35 +0000267 }
wdenkbb1b8262003-03-27 12:09:35 +0000268 else if ( pAsc->asc_con & ASCCON_FE )
269 {
wdenk57b2d802003-06-27 21:31:46 +0000270 SET_BIT(pAsc->asc_whbcon, ASCWHBCON_CLRFE);
271 res = 0;
wdenkbb1b8262003-03-27 12:09:35 +0000272 }
273 else if ( pAsc->asc_con & ASCCON_PE )
274 {
wdenk57b2d802003-06-27 21:31:46 +0000275 SET_BIT(pAsc->asc_whbcon, ASCWHBCON_CLRPE);
276 res = 0;
wdenkbb1b8262003-03-27 12:09:35 +0000277 }
278 else if ( pAsc->asc_con & ASCCON_OE )
279 {
wdenk57b2d802003-06-27 21:31:46 +0000280 SET_BIT(pAsc->asc_whbcon, ASCWHBCON_CLROE);
281 res = 0;
wdenkbb1b8262003-03-27 12:09:35 +0000282 }
283
284 return res;
285}