1 /*
2  * (INCA) ASC UART support
3  */
4 
5 #include <config.h>
6 
7 #ifdef CONFIG_PURPLE
8 #define	serial_init	asc_serial_init
9 #define	serial_putc	asc_serial_putc
10 #define	serial_puts	asc_serial_puts
11 #define	serial_getc	asc_serial_getc
12 #define	serial_tstc	asc_serial_tstc
13 #define	serial_setbrg	asc_serial_setbrg
14 #endif
15 
16 #include <common.h>
17 #include <asm/inca-ip.h>
18 #include "asc_serial.h"
19 
20 #ifdef CONFIG_PURPLE
21 
22 #undef ASC_FIFO_PRESENT
23 #define TOUT_LOOP	100000
24 
25 /* Set base address for second FPI interrupt control register bank */
26 #define SFPI_INTCON_BASEADDR	0xBF0F0000
27 
28 /* Register offset from base address */
29 #define FBS_ISR		0x00000000	/* Interrupt status register */
30 #define FBS_IMR		0x00000008	/* Interrupt mask register */
31 #define FBS_IDIS	0x00000010	/* Interrupt disable register */
32 
33 /* Interrupt status register bits */
34 #define FBS_ISR_AT	0x00000040	/* ASC transmit interrupt */
35 #define FBS_ISR_AR	0x00000020	/* ASC receive interrupt */
36 #define FBS_ISR_AE	0x00000010	/* ASC error interrupt */
37 #define FBS_ISR_AB	0x00000008	/* ASC transmit buffer interrupt */
38 #define FBS_ISR_AS      0x00000004	/* ASC start of autobaud detection interrupt */
39 #define FBS_ISR_AF	0x00000002	/* ASC end of autobaud detection interrupt */
40 
41 #else
42 
43 #define ASC_FIFO_PRESENT
44 
45 #endif
46 
47 
48 #define SET_BIT(reg, mask)                  reg |= (mask)
49 #define CLEAR_BIT(reg, mask)                reg &= (~mask)
50 #define CLEAR_BITS(reg, mask)               CLEAR_BIT(reg, mask)
51 #define SET_BITS(reg, mask)                 SET_BIT(reg, mask)
52 #define SET_BITFIELD(reg, mask, off, val)   {reg &= (~mask); reg |= (val << off);}
53 
54 extern uint incaip_get_fpiclk(void);
55 
56 static int serial_setopt (void);
57 
58 /* pointer to ASC register base address */
59 static volatile incaAsc_t *pAsc = (incaAsc_t *)INCA_IP_ASC;
60 
61 /******************************************************************************
62 *
63 * serial_init - initialize a INCAASC channel
64 *
65 * This routine initializes the number of data bits, parity
66 * and set the selected baud rate. Interrupts are disabled.
67 * Set the modem control signals if the option is selected.
68 *
69 * RETURNS: N/A
70 */
71 
serial_init(void)72 int serial_init (void)
73 {
74 #ifdef CONFIG_INCA_IP
75     /* we have to set PMU.EN13 bit to enable an ASC device*/
76     INCAASC_PMU_ENABLE(13);
77 #endif
78 
79     /* and we have to set CLC register*/
80     CLEAR_BIT(pAsc->asc_clc, ASCCLC_DISS);
81     SET_BITFIELD(pAsc->asc_clc, ASCCLC_RMCMASK, ASCCLC_RMCOFFSET, 0x0001);
82 
83     /* initialy we are in async mode */
84     pAsc->asc_con = ASCCON_M_8ASYNC;
85 
86     /* select input port */
87     pAsc->asc_pisel = (CONSOLE_TTY & 0x1);
88 
89 #ifdef ASC_FIFO_PRESENT
90     /* TXFIFO's filling level */
91     SET_BITFIELD(pAsc->asc_txfcon, ASCTXFCON_TXFITLMASK,
92 		    ASCTXFCON_TXFITLOFF, INCAASC_TXFIFO_FL);
93     /* enable TXFIFO */
94     SET_BIT(pAsc->asc_txfcon, ASCTXFCON_TXFEN);
95 
96     /* RXFIFO's filling level */
97     SET_BITFIELD(pAsc->asc_txfcon, ASCRXFCON_RXFITLMASK,
98 		    ASCRXFCON_RXFITLOFF, INCAASC_RXFIFO_FL);
99     /* enable RXFIFO */
100     SET_BIT(pAsc->asc_rxfcon, ASCRXFCON_RXFEN);
101 #endif
102 
103     /* enable error signals */
104     SET_BIT(pAsc->asc_con, ASCCON_FEN);
105     SET_BIT(pAsc->asc_con, ASCCON_OEN);
106 
107 #ifdef CONFIG_INCA_IP
108     /* acknowledge ASC interrupts */
109     ASC_INTERRUPTS_CLEAR(INCAASC_IRQ_LINE_ALL);
110 
111     /* disable ASC interrupts */
112     ASC_INTERRUPTS_DISABLE(INCAASC_IRQ_LINE_ALL);
113 #endif
114 
115 #ifdef ASC_FIFO_PRESENT
116     /* set FIFOs into the transparent mode */
117     SET_BIT(pAsc->asc_txfcon, ASCTXFCON_TXTMEN);
118     SET_BIT(pAsc->asc_rxfcon, ASCRXFCON_RXTMEN);
119 #endif
120 
121     /* set baud rate */
122     serial_setbrg();
123 
124     /* set the options */
125     serial_setopt();
126 
127     return 0;
128 }
129 
serial_setbrg(void)130 void serial_setbrg (void)
131 {
132     ulong      uiReloadValue, fdv;
133     ulong      f_ASC;
134 
135 #ifdef CONFIG_INCA_IP
136     f_ASC = incaip_get_fpiclk();
137 #else
138     f_ASC = ASC_CLOCK_RATE;
139 #endif
140 
141 #ifndef INCAASC_USE_FDV
142     fdv = 2;
143     uiReloadValue = (f_ASC / (fdv * 16 * CONFIG_BAUDRATE)) - 1;
144 #else
145     fdv = INCAASC_FDV_HIGH_BAUDRATE;
146     uiReloadValue = (f_ASC / (8192 * CONFIG_BAUDRATE / fdv)) - 1;
147 #endif /* INCAASC_USE_FDV */
148 
149     if ( (uiReloadValue < 0) || (uiReloadValue > 8191) )
150     {
151 #ifndef INCAASC_USE_FDV
152 	fdv = 3;
153 	uiReloadValue = (f_ASC / (fdv * 16 * CONFIG_BAUDRATE)) - 1;
154 #else
155 	fdv = INCAASC_FDV_LOW_BAUDRATE;
156 	uiReloadValue = (f_ASC / (8192 * CONFIG_BAUDRATE / fdv)) - 1;
157 #endif /* INCAASC_USE_FDV */
158 
159 	if ( (uiReloadValue < 0) || (uiReloadValue > 8191) )
160 	{
161 	    return;    /* can't impossibly generate that baud rate */
162 	}
163     }
164 
165     /* Disable Baud Rate Generator; BG should only be written when R=0 */
166     CLEAR_BIT(pAsc->asc_con, ASCCON_R);
167 
168 #ifndef INCAASC_USE_FDV
169     /*
170      * Disable Fractional Divider (FDE)
171      * Divide clock by reload-value + constant (BRS)
172      */
173     /* FDE = 0 */
174     CLEAR_BIT(pAsc->asc_con, ASCCON_FDE);
175 
176     if ( fdv == 2 )
177 	CLEAR_BIT(pAsc->asc_con, ASCCON_BRS);   /* BRS = 0 */
178     else
179 	SET_BIT(pAsc->asc_con, ASCCON_BRS); /* BRS = 1 */
180 
181 #else /* INCAASC_USE_FDV */
182 
183     /* Enable Fractional Divider */
184     SET_BIT(pAsc->asc_con, ASCCON_FDE); /* FDE = 1 */
185 
186     /* Set fractional divider value */
187     pAsc->asc_fdv = fdv & ASCFDV_VALUE_MASK;
188 
189 #endif /* INCAASC_USE_FDV */
190 
191     /* Set reload value in BG */
192     pAsc->asc_bg = uiReloadValue;
193 
194     /* Enable Baud Rate Generator */
195     SET_BIT(pAsc->asc_con, ASCCON_R);           /* R = 1 */
196 }
197 
198 /*******************************************************************************
199 *
200 * serial_setopt - set the serial options
201 *
202 * Set the channel operating mode to that specified. Following options
203 * are supported: CREAD, CSIZE, PARENB, and PARODD.
204 *
205 * Note, this routine disables the transmitter.  The calling routine
206 * may have to re-enable it.
207 *
208 * RETURNS:
209 * Returns 0 to indicate success, otherwise -1 is returned
210 */
211 
serial_setopt(void)212 static int serial_setopt (void)
213 {
214     ulong  con;
215 
216     switch ( ASC_OPTIONS & ASCOPT_CSIZE )
217     {
218     /* 7-bit-data */
219     case ASCOPT_CS7:
220 	con = ASCCON_M_7ASYNCPAR;   /* 7-bit-data and parity bit */
221 	break;
222 
223     /* 8-bit-data */
224     case ASCOPT_CS8:
225 	if ( ASC_OPTIONS & ASCOPT_PARENB )
226 	    con = ASCCON_M_8ASYNCPAR;   /* 8-bit-data and parity bit */
227 	else
228 	    con = ASCCON_M_8ASYNC;      /* 8-bit-data no parity */
229 	break;
230 
231     /*
232      *  only 7 and 8-bit frames are supported
233      *  if we don't use IOCTL extensions
234      */
235     default:
236 	return -1;
237     }
238 
239     if ( ASC_OPTIONS & ASCOPT_STOPB )
240 	SET_BIT(con, ASCCON_STP);       /* 2 stop bits */
241     else
242 	CLEAR_BIT(con, ASCCON_STP);     /* 1 stop bit */
243 
244     if ( ASC_OPTIONS & ASCOPT_PARENB )
245 	SET_BIT(con, ASCCON_PEN);           /* enable parity checking */
246     else
247 	CLEAR_BIT(con, ASCCON_PEN);         /* disable parity checking */
248 
249     if ( ASC_OPTIONS & ASCOPT_PARODD )
250 	SET_BIT(con, ASCCON_ODD);       /* odd parity */
251     else
252 	CLEAR_BIT(con, ASCCON_ODD);     /* even parity */
253 
254     if ( ASC_OPTIONS & ASCOPT_CREAD )
255 	SET_BIT(pAsc->asc_whbcon, ASCWHBCON_SETREN); /* Receiver enable */
256 
257     pAsc->asc_con |= con;
258 
259     return 0;
260 }
261 
serial_putc(const char c)262 void serial_putc (const char c)
263 {
264 #ifdef ASC_FIFO_PRESENT
265     uint txFl = 0;
266 #else
267     uint timeout = 0;
268 #endif
269 
270     if (c == '\n') serial_putc ('\r');
271 
272 #ifdef ASC_FIFO_PRESENT
273     /* check do we have a free space in the TX FIFO */
274     /* get current filling level */
275     do
276     {
277 	txFl = ( pAsc->asc_fstat & ASCFSTAT_TXFFLMASK ) >> ASCFSTAT_TXFFLOFF;
278     }
279     while ( txFl == INCAASC_TXFIFO_FULL );
280 #else
281 
282     while(!(*(volatile unsigned long*)(SFPI_INTCON_BASEADDR + FBS_ISR) &
283 			   FBS_ISR_AB))
284     {
285 	    if (timeout++ > TOUT_LOOP)
286 	    {
287 		    break;
288 	    }
289     }
290 #endif
291 
292     pAsc->asc_tbuf = c; /* write char to Transmit Buffer Register */
293 
294 #ifndef ASC_FIFO_PRESENT
295     *(volatile unsigned long*)(SFPI_INTCON_BASEADDR + FBS_ISR) = FBS_ISR_AB |
296 								 FBS_ISR_AT;
297 #endif
298 
299     /* check for errors */
300     if ( pAsc->asc_con & ASCCON_OE )
301     {
302 	SET_BIT(pAsc->asc_whbcon, ASCWHBCON_CLROE);
303 	return;
304     }
305 }
306 
serial_puts(const char * s)307 void serial_puts (const char *s)
308 {
309     while (*s)
310     {
311 	serial_putc (*s++);
312     }
313 }
314 
serial_getc(void)315 int serial_getc (void)
316 {
317     ulong symbol_mask;
318     char c;
319 
320     while (!serial_tstc());
321 
322     symbol_mask =
323 	((ASC_OPTIONS & ASCOPT_CSIZE) == ASCOPT_CS7) ? (0x7f) : (0xff);
324 
325     c = (char)(pAsc->asc_rbuf & symbol_mask);
326 
327 #ifndef ASC_FIFO_PRESENT
328     *(volatile unsigned long*)(SFPI_INTCON_BASEADDR + FBS_ISR) = FBS_ISR_AR;
329 #endif
330 
331     return c;
332 }
333 
serial_tstc(void)334 int serial_tstc (void)
335 {
336     int res = 1;
337 
338 #ifdef ASC_FIFO_PRESENT
339     if ( (pAsc->asc_fstat & ASCFSTAT_RXFFLMASK) == 0 )
340     {
341 	res = 0;
342     }
343 #else
344     if (!(*(volatile unsigned long*)(SFPI_INTCON_BASEADDR + FBS_ISR) &
345 								FBS_ISR_AR))
346 
347     {
348 	res = 0;
349     }
350 #endif
351     else if ( pAsc->asc_con & ASCCON_FE )
352     {
353 	SET_BIT(pAsc->asc_whbcon, ASCWHBCON_CLRFE);
354 	res = 0;
355     }
356     else if ( pAsc->asc_con & ASCCON_PE )
357     {
358 	SET_BIT(pAsc->asc_whbcon, ASCWHBCON_CLRPE);
359 	res = 0;
360     }
361     else if ( pAsc->asc_con & ASCCON_OE )
362     {
363 	SET_BIT(pAsc->asc_whbcon, ASCWHBCON_CLROE);
364 	res = 0;
365     }
366 
367     return res;
368 }
369