blob: 6f0e4f2520143a2909ff73585f2d1576b9a276da [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>
Marek Vasut2a9d9352012-09-13 01:20:07 +02008#include <serial.h>
9#include <linux/compiler.h>
wdenk9b7f3842003-10-09 20:09:04 +000010#include "asc_serial.h"
wdenkbb1b8262003-03-27 12:09:35 +000011
wdenkb02744a2003-04-05 00:53:31 +000012
wdenkbb1b8262003-03-27 12:09:35 +000013#define SET_BIT(reg, mask) reg |= (mask)
14#define CLEAR_BIT(reg, mask) reg &= (~mask)
15#define CLEAR_BITS(reg, mask) CLEAR_BIT(reg, mask)
16#define SET_BITS(reg, mask) SET_BIT(reg, mask)
17#define SET_BITFIELD(reg, mask, off, val) {reg &= (~mask); reg |= (val << off);}
18
19extern uint incaip_get_fpiclk(void);
20
21static int serial_setopt (void);
22
23/* pointer to ASC register base address */
24static volatile incaAsc_t *pAsc = (incaAsc_t *)INCA_IP_ASC;
25
26/******************************************************************************
27*
28* serial_init - initialize a INCAASC channel
29*
30* This routine initializes the number of data bits, parity
31* and set the selected baud rate. Interrupts are disabled.
32* Set the modem control signals if the option is selected.
33*
34* RETURNS: N/A
35*/
36
Marek Vasut2a9d9352012-09-13 01:20:07 +020037static int asc_serial_init(void)
wdenkbb1b8262003-03-27 12:09:35 +000038{
39 /* we have to set PMU.EN13 bit to enable an ASC device*/
40 INCAASC_PMU_ENABLE(13);
wdenk57b2d802003-06-27 21:31:46 +000041
wdenkbb1b8262003-03-27 12:09:35 +000042 /* and we have to set CLC register*/
43 CLEAR_BIT(pAsc->asc_clc, ASCCLC_DISS);
44 SET_BITFIELD(pAsc->asc_clc, ASCCLC_RMCMASK, ASCCLC_RMCOFFSET, 0x0001);
wdenk57b2d802003-06-27 21:31:46 +000045
wdenkbb1b8262003-03-27 12:09:35 +000046 /* initialy we are in async mode */
47 pAsc->asc_con = ASCCON_M_8ASYNC;
48
49 /* select input port */
50 pAsc->asc_pisel = (CONSOLE_TTY & 0x1);
51
52 /* TXFIFO's filling level */
53 SET_BITFIELD(pAsc->asc_txfcon, ASCTXFCON_TXFITLMASK,
wdenk57b2d802003-06-27 21:31:46 +000054 ASCTXFCON_TXFITLOFF, INCAASC_TXFIFO_FL);
wdenkbb1b8262003-03-27 12:09:35 +000055 /* enable TXFIFO */
56 SET_BIT(pAsc->asc_txfcon, ASCTXFCON_TXFEN);
57
58 /* RXFIFO's filling level */
wdenk57b2d802003-06-27 21:31:46 +000059 SET_BITFIELD(pAsc->asc_txfcon, ASCRXFCON_RXFITLMASK,
60 ASCRXFCON_RXFITLOFF, INCAASC_RXFIFO_FL);
wdenkbb1b8262003-03-27 12:09:35 +000061 /* enable RXFIFO */
62 SET_BIT(pAsc->asc_rxfcon, ASCRXFCON_RXFEN);
63
64 /* enable error signals */
65 SET_BIT(pAsc->asc_con, ASCCON_FEN);
66 SET_BIT(pAsc->asc_con, ASCCON_OEN);
67
68 /* acknowledge ASC interrupts */
69 ASC_INTERRUPTS_CLEAR(INCAASC_IRQ_LINE_ALL);
70
71 /* disable ASC interrupts */
72 ASC_INTERRUPTS_DISABLE(INCAASC_IRQ_LINE_ALL);
73
74 /* set FIFOs into the transparent mode */
75 SET_BIT(pAsc->asc_txfcon, ASCTXFCON_TXTMEN);
76 SET_BIT(pAsc->asc_rxfcon, ASCRXFCON_RXTMEN);
77
78 /* set baud rate */
79 serial_setbrg();
80
81 /* set the options */
82 serial_setopt();
wdenk57b2d802003-06-27 21:31:46 +000083
wdenkbb1b8262003-03-27 12:09:35 +000084 return 0;
85}
86
Marek Vasut2a9d9352012-09-13 01:20:07 +020087static void asc_serial_setbrg(void)
wdenkbb1b8262003-03-27 12:09:35 +000088{
89 ulong uiReloadValue, fdv;
90 ulong f_ASC;
91
92 f_ASC = incaip_get_fpiclk();
93
94#ifndef INCAASC_USE_FDV
95 fdv = 2;
96 uiReloadValue = (f_ASC / (fdv * 16 * CONFIG_BAUDRATE)) - 1;
wdenk57b2d802003-06-27 21:31:46 +000097#else
wdenkbb1b8262003-03-27 12:09:35 +000098 fdv = INCAASC_FDV_HIGH_BAUDRATE;
99 uiReloadValue = (f_ASC / (8192 * CONFIG_BAUDRATE / fdv)) - 1;
100#endif /* INCAASC_USE_FDV */
wdenk57b2d802003-06-27 21:31:46 +0000101
wdenkbb1b8262003-03-27 12:09:35 +0000102 if ( (uiReloadValue < 0) || (uiReloadValue > 8191) )
103 {
104#ifndef INCAASC_USE_FDV
wdenk57b2d802003-06-27 21:31:46 +0000105 fdv = 3;
106 uiReloadValue = (f_ASC / (fdv * 16 * CONFIG_BAUDRATE)) - 1;
107#else
108 fdv = INCAASC_FDV_LOW_BAUDRATE;
109 uiReloadValue = (f_ASC / (8192 * CONFIG_BAUDRATE / fdv)) - 1;
wdenkbb1b8262003-03-27 12:09:35 +0000110#endif /* INCAASC_USE_FDV */
wdenk57b2d802003-06-27 21:31:46 +0000111
112 if ( (uiReloadValue < 0) || (uiReloadValue > 8191) )
113 {
114 return; /* can't impossibly generate that baud rate */
115 }
wdenkbb1b8262003-03-27 12:09:35 +0000116 }
117
118 /* Disable Baud Rate Generator; BG should only be written when R=0 */
119 CLEAR_BIT(pAsc->asc_con, ASCCON_R);
120
121#ifndef INCAASC_USE_FDV
122 /*
123 * Disable Fractional Divider (FDE)
124 * Divide clock by reload-value + constant (BRS)
125 */
126 /* FDE = 0 */
127 CLEAR_BIT(pAsc->asc_con, ASCCON_FDE);
128
129 if ( fdv == 2 )
wdenk57b2d802003-06-27 21:31:46 +0000130 CLEAR_BIT(pAsc->asc_con, ASCCON_BRS); /* BRS = 0 */
wdenkbb1b8262003-03-27 12:09:35 +0000131 else
wdenk57b2d802003-06-27 21:31:46 +0000132 SET_BIT(pAsc->asc_con, ASCCON_BRS); /* BRS = 1 */
wdenkbb1b8262003-03-27 12:09:35 +0000133
134#else /* INCAASC_USE_FDV */
135
136 /* Enable Fractional Divider */
137 SET_BIT(pAsc->asc_con, ASCCON_FDE); /* FDE = 1 */
138
139 /* Set fractional divider value */
140 pAsc->asc_fdv = fdv & ASCFDV_VALUE_MASK;
141
142#endif /* INCAASC_USE_FDV */
143
144 /* Set reload value in BG */
145 pAsc->asc_bg = uiReloadValue;
146
147 /* Enable Baud Rate Generator */
148 SET_BIT(pAsc->asc_con, ASCCON_R); /* R = 1 */
149}
150
151/*******************************************************************************
152*
153* serial_setopt - set the serial options
154*
155* Set the channel operating mode to that specified. Following options
156* are supported: CREAD, CSIZE, PARENB, and PARODD.
157*
158* Note, this routine disables the transmitter. The calling routine
159* may have to re-enable it.
160*
161* RETURNS:
162* Returns 0 to indicate success, otherwise -1 is returned
163*/
164
165static int serial_setopt (void)
166{
167 ulong con;
168
169 switch ( ASC_OPTIONS & ASCOPT_CSIZE )
170 {
171 /* 7-bit-data */
172 case ASCOPT_CS7:
wdenk57b2d802003-06-27 21:31:46 +0000173 con = ASCCON_M_7ASYNCPAR; /* 7-bit-data and parity bit */
174 break;
wdenkbb1b8262003-03-27 12:09:35 +0000175
176 /* 8-bit-data */
177 case ASCOPT_CS8:
wdenk57b2d802003-06-27 21:31:46 +0000178 if ( ASC_OPTIONS & ASCOPT_PARENB )
179 con = ASCCON_M_8ASYNCPAR; /* 8-bit-data and parity bit */
180 else
181 con = ASCCON_M_8ASYNC; /* 8-bit-data no parity */
182 break;
183
184 /*
wdenkbb1b8262003-03-27 12:09:35 +0000185 * only 7 and 8-bit frames are supported
wdenk57b2d802003-06-27 21:31:46 +0000186 * if we don't use IOCTL extensions
wdenkbb1b8262003-03-27 12:09:35 +0000187 */
188 default:
wdenk57b2d802003-06-27 21:31:46 +0000189 return -1;
wdenkbb1b8262003-03-27 12:09:35 +0000190 }
191
192 if ( ASC_OPTIONS & ASCOPT_STOPB )
wdenk57b2d802003-06-27 21:31:46 +0000193 SET_BIT(con, ASCCON_STP); /* 2 stop bits */
wdenkbb1b8262003-03-27 12:09:35 +0000194 else
wdenk57b2d802003-06-27 21:31:46 +0000195 CLEAR_BIT(con, ASCCON_STP); /* 1 stop bit */
wdenkbb1b8262003-03-27 12:09:35 +0000196
197 if ( ASC_OPTIONS & ASCOPT_PARENB )
wdenk57b2d802003-06-27 21:31:46 +0000198 SET_BIT(con, ASCCON_PEN); /* enable parity checking */
wdenkbb1b8262003-03-27 12:09:35 +0000199 else
wdenk57b2d802003-06-27 21:31:46 +0000200 CLEAR_BIT(con, ASCCON_PEN); /* disable parity checking */
201
wdenkbb1b8262003-03-27 12:09:35 +0000202 if ( ASC_OPTIONS & ASCOPT_PARODD )
wdenk57b2d802003-06-27 21:31:46 +0000203 SET_BIT(con, ASCCON_ODD); /* odd parity */
wdenkbb1b8262003-03-27 12:09:35 +0000204 else
wdenk57b2d802003-06-27 21:31:46 +0000205 CLEAR_BIT(con, ASCCON_ODD); /* even parity */
wdenkbb1b8262003-03-27 12:09:35 +0000206
207 if ( ASC_OPTIONS & ASCOPT_CREAD )
wdenk57b2d802003-06-27 21:31:46 +0000208 SET_BIT(pAsc->asc_whbcon, ASCWHBCON_SETREN); /* Receiver enable */
wdenkbb1b8262003-03-27 12:09:35 +0000209
210 pAsc->asc_con |= con;
211
212 return 0;
213}
214
Marek Vasut2a9d9352012-09-13 01:20:07 +0200215static void asc_serial_putc(const char c)
wdenkbb1b8262003-03-27 12:09:35 +0000216{
217 uint txFl = 0;
218
219 if (c == '\n') serial_putc ('\r');
220
221 /* check do we have a free space in the TX FIFO */
222 /* get current filling level */
223 do
224 {
225 txFl = ( pAsc->asc_fstat & ASCFSTAT_TXFFLMASK ) >> ASCFSTAT_TXFFLOFF;
226 }
227 while ( txFl == INCAASC_TXFIFO_FULL );
228
229 pAsc->asc_tbuf = c; /* write char to Transmit Buffer Register */
wdenkb02744a2003-04-05 00:53:31 +0000230
wdenkbb1b8262003-03-27 12:09:35 +0000231 /* check for errors */
232 if ( pAsc->asc_con & ASCCON_OE )
233 {
wdenk57b2d802003-06-27 21:31:46 +0000234 SET_BIT(pAsc->asc_whbcon, ASCWHBCON_CLROE);
235 return;
wdenkbb1b8262003-03-27 12:09:35 +0000236 }
237}
238
Marek Vasut2a9d9352012-09-13 01:20:07 +0200239static int asc_serial_getc(void)
wdenkbb1b8262003-03-27 12:09:35 +0000240{
241 ulong symbol_mask;
242 char c;
243
244 while (!serial_tstc());
245
246 symbol_mask =
247 ((ASC_OPTIONS & ASCOPT_CSIZE) == ASCOPT_CS7) ? (0x7f) : (0xff);
wdenk57b2d802003-06-27 21:31:46 +0000248
wdenkbb1b8262003-03-27 12:09:35 +0000249 c = (char)(pAsc->asc_rbuf & symbol_mask);
250
251 return c;
252}
253
Marek Vasut2a9d9352012-09-13 01:20:07 +0200254static int asc_serial_tstc(void)
wdenkbb1b8262003-03-27 12:09:35 +0000255{
256 int res = 1;
257
258 if ( (pAsc->asc_fstat & ASCFSTAT_RXFFLMASK) == 0 )
259 {
wdenk57b2d802003-06-27 21:31:46 +0000260 res = 0;
wdenkbb1b8262003-03-27 12:09:35 +0000261 }
wdenkbb1b8262003-03-27 12:09:35 +0000262 else if ( pAsc->asc_con & ASCCON_FE )
263 {
wdenk57b2d802003-06-27 21:31:46 +0000264 SET_BIT(pAsc->asc_whbcon, ASCWHBCON_CLRFE);
265 res = 0;
wdenkbb1b8262003-03-27 12:09:35 +0000266 }
267 else if ( pAsc->asc_con & ASCCON_PE )
268 {
wdenk57b2d802003-06-27 21:31:46 +0000269 SET_BIT(pAsc->asc_whbcon, ASCWHBCON_CLRPE);
270 res = 0;
wdenkbb1b8262003-03-27 12:09:35 +0000271 }
272 else if ( pAsc->asc_con & ASCCON_OE )
273 {
wdenk57b2d802003-06-27 21:31:46 +0000274 SET_BIT(pAsc->asc_whbcon, ASCWHBCON_CLROE);
275 res = 0;
wdenkbb1b8262003-03-27 12:09:35 +0000276 }
277
278 return res;
279}
Marek Vasut2a9d9352012-09-13 01:20:07 +0200280
Marek Vasut2a9d9352012-09-13 01:20:07 +0200281static struct serial_device asc_serial_drv = {
282 .name = "asc_serial",
283 .start = asc_serial_init,
284 .stop = NULL,
285 .setbrg = asc_serial_setbrg,
286 .putc = asc_serial_putc,
Marek Vasutd9c64492012-10-06 14:07:02 +0000287 .puts = default_serial_puts,
Marek Vasut2a9d9352012-09-13 01:20:07 +0200288 .getc = asc_serial_getc,
289 .tstc = asc_serial_tstc,
290};
291
292void asc_serial_initialize(void)
293{
294 serial_register(&asc_serial_drv);
295}
296
297__weak struct serial_device *default_serial_console(void)
298{
299 return &asc_serial_drv;
300}