]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/hal/powerpc/quicc/v2_0/src/quicc_smc1.c
Initial revision
[karo-tx-redboot.git] / packages / hal / powerpc / quicc / v2_0 / src / quicc_smc1.c
1 //==========================================================================
2 //
3 //      quicc_smc1.c
4 //
5 //      PowerPC QUICC basic Serial IO using port(s) SMC1/SMC2/SCC1/SCC2/SCC3
6 //
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12 // Copyright (C) 2002, 2003 Gary Thomas
13 //
14 // eCos is free software; you can redistribute it and/or modify it under
15 // the terms of the GNU General Public License as published by the Free
16 // Software Foundation; either version 2 or (at your option) any later version.
17 //
18 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
19 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
21 // for more details.
22 //
23 // You should have received a copy of the GNU General Public License along
24 // with eCos; if not, write to the Free Software Foundation, Inc.,
25 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 //
27 // As a special exception, if other files instantiate templates or use macros
28 // or inline functions from this file, or you compile this file and link it
29 // with other works to produce a work based on this file, this file does not
30 // by itself cause the resulting work to be covered by the GNU General Public
31 // License. However the source code for this file must still be made available
32 // in accordance with section (3) of the GNU General Public License.
33 //
34 // This exception does not invalidate any other reasons why a work based on
35 // this file might be covered by the GNU General Public License.
36 //
37 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
38 // at http://sources.redhat.com/ecos/ecos-license/
39 // -------------------------------------------
40 //####ECOSGPLCOPYRIGHTEND####
41 //==========================================================================
42 //#####DESCRIPTIONBEGIN####
43 //
44 // Author(s):    Red Hat
45 // Contributors: hmt, gthomas
46 // Date:         1999-06-08
47 // Purpose:      Provide basic Serial IO for MPC8xx boards (like Motorola MBX)
48 // Description:  Serial IO for MPC8xx boards which connect their debug channel
49 //               to SMCx or SCCx; or any QUICC user who wants to use SMCx/SCCx
50 // Usage:
51 // Notes:        
52 //
53 //####DESCRIPTIONEND####
54 //
55 //==========================================================================
56
57 #include <pkgconf/hal.h>
58 #include <pkgconf/hal_powerpc_quicc.h>
59 #include <cyg/infra/cyg_type.h>
60 #include <cyg/hal/hal_cache.h>
61
62 #include <cyg/hal/hal_arch.h>
63
64 // eCos headers decribing PowerQUICC:
65 #include <cyg/hal/quicc/ppc8xx.h>
66
67 #include <cyg/hal/quicc/quicc_smc1.h>
68
69 #include <cyg/hal/hal_stub.h>           // target_register_t
70 #include <cyg/hal/hal_intr.h>           // HAL_INTERRUPT_UNMASK(...)
71 #include <cyg/hal/hal_if.h>             // Calling interface definitions
72 #include <cyg/hal/hal_misc.h>           // Helper functions
73 #include <cyg/hal/drv_api.h>            // CYG_ISR_HANDLED
74 #include <string.h>                     // memset
75
76 #define UART_BIT_RATE(n) ((((int)(CYGHWR_HAL_POWERPC_BOARD_SPEED*1000000)/16)/n)-1)
77 #define UART_BAUD_RATE CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL_BAUD
78
79 // Note: buffers will be placed just after descriptors
80 // Sufficient space should be provided between descrptors
81 // for the buffers (single characters)
82
83 struct port_info {
84     int                         Txnum;   // Number of Tx buffers
85     int                         Rxnum;   // Number of Rx buffers
86     int                         intnum;  // Interrupt bit
87     int                         timeout; // Timeout in msec
88     int                         pram;    // [Pointer] to PRAM data
89     int                         regs;    // [Pointer] to control registers
90     volatile struct cp_bufdesc *next_rxbd;
91     int                         irq;     // Interrupt state
92     int                         init;    // Has port been initialized?
93     volatile unsigned long     *brg;     // Baud rate generator
94 };
95
96 static struct port_info ports[] = {
97 #if CYGNUM_HAL_QUICC_SMC1 > 0
98     { 1, 4, CYGNUM_HAL_INTERRUPT_CPM_SMC1, 1000,
99       (int)&((EPPC *)0)->pram[2].scc.pothers.smc_modem.psmc.u, 
100       (int)&((EPPC *)0)->smc_regs[0]
101     }, 
102 #endif
103 #if CYGNUM_HAL_QUICC_SMC2 > 0
104     { 1, 4, CYGNUM_HAL_INTERRUPT_CPM_SMC2_PIP, 1000,
105       (int)&((EPPC *)0)->pram[3].scc.pothers.smc_modem.psmc.u, 
106       (int)&((EPPC *)0)->smc_regs[1]
107     }, 
108 #endif
109 #if CYGNUM_HAL_QUICC_SCC1 > 0
110     { 1, 4, CYGNUM_HAL_INTERRUPT_CPM_SCC1, 1000,
111       (int)&((EPPC *)0)->pram[0].scc.pscc.u, 
112       (int)&((EPPC *)0)->scc_regs[0]
113     },
114 #endif
115 #if CYGNUM_HAL_QUICC_SCC2 > 0
116     { 1, 4, CYGNUM_HAL_INTERRUPT_CPM_SCC2, 1000,
117       (int)&((EPPC *)0)->pram[1].scc.pscc.u, 
118       (int)&((EPPC *)0)->scc_regs[1]
119     },
120 #endif
121 #if CYGNUM_HAL_QUICC_SCC3 > 0
122     { 1, 4, CYGNUM_HAL_INTERRUPT_CPM_SCC3, 1000,
123       (int)&((EPPC *)0)->pram[2].scc.pscc.u, 
124       (int)&((EPPC *)0)->scc_regs[2]
125     },
126 #endif
127 };
128
129 /*
130  *  Initialize SMCX as a uart.
131  *
132  *  Comments below reference Motorola's "MPC860 User Manual".
133  *  The basic initialization steps are from Section 16.15.8
134  *  of that manual.
135  */     
136 static void
137 cyg_hal_smcx_init_channel(struct port_info *info, int port)
138 {
139     EPPC *eppc = eppc_base();
140     int i;
141     volatile struct smc_uart_pram *uart_pram = (volatile struct smc_uart_pram *)((char *)eppc + info->pram);
142     volatile struct smc_regs *regs = (volatile struct smc_regs *)((char *)eppc + info->regs);
143     struct cp_bufdesc *txbd, *rxbd;
144
145     if (info->init) return;
146     info->init = 1;
147
148     switch (port) {
149 #if CYGNUM_HAL_QUICC_SMC1 > 0
150     case QUICC_CPM_SMC1:
151         /*
152          *  Set up the PortB pins for UART operation.
153          *  Set PAR and DIR to allow SMCTXD1 and SMRXD1
154          *  (Table 16-39)
155          */
156         eppc->pip_pbpar |= 0xc0;
157         eppc->pip_pbdir &= ~0xc0;
158
159         break;
160 #endif
161 #if CYGNUM_HAL_QUICC_SMC2 > 0
162     case QUICC_CPM_SMC2:
163         /*
164          *  Set up the PortA pins for UART operation.
165          *  Set PAR and DIR to allow SMCTXD2 and SMRXD2
166          *  (Table 16-39)
167          */
168         eppc->pio_papar |= 0xc0;
169         eppc->pio_padir &= ~0xc0;
170         eppc->pio_paodr &= ~0xc0;
171
172         break;
173 #endif
174     }
175
176     // Set up baud rate generator.  These are allocated from a
177     // pool, based on the port number and type.  The allocator
178     // will arrange to have the selected baud rate clock steered
179     // to this device.
180     info->brg = _mpc8xx_allocate_brg(port);
181     *(info->brg) = 0x10000 | (UART_BIT_RATE(UART_BAUD_RATE)<<1);
182
183     /*
184      *  Set pointers to buffer descriptors.
185      *  (Sections 16.15.4.1, 16.15.7.12, and 16.15.7.13)
186      */
187     uart_pram->rbase = _mpc8xx_allocBd(sizeof(struct cp_bufdesc)*info->Rxnum + info->Rxnum);
188     uart_pram->tbase = _mpc8xx_allocBd(sizeof(struct cp_bufdesc)*info->Txnum + info->Txnum);
189
190     /*
191      *  SDMA & LCD bus request level 5
192      *  (Section 16.10.2.1)
193      */
194     eppc->dma_sdcr = 1;
195
196     /*
197      *  Set Rx and Tx function code
198      *  (Section 16.15.4.2)
199      */
200     uart_pram->rfcr = 0x18;
201     uart_pram->tfcr = 0x18;
202
203     /* max receive buffer length */
204     uart_pram->mrblr = 1;
205
206     /* disable max_idle feature */
207     uart_pram->max_idl = 0;
208
209     /* no last brk char received */
210     uart_pram->brkln = 0;
211
212     /* no break condition occurred */
213     uart_pram->brkec = 0;
214
215     /* 1 break char sent on top XMIT */
216     uart_pram->brkcr = 1;
217
218     /* setup RX buffer descriptors */
219     rxbd = (struct cp_bufdesc *)((char *)eppc + uart_pram->rbase);
220     info->next_rxbd = rxbd;
221     for (i = 0;  i < info->Rxnum;  i++) {
222         rxbd->length = 0;
223         rxbd->buffer = ((char *)eppc + (uart_pram->rbase+(info->Rxnum*sizeof(struct cp_bufdesc))))+i;
224         rxbd->ctrl   = QUICC_BD_CTL_Ready | QUICC_BD_CTL_Int;
225         rxbd++;
226     }
227     rxbd--;
228     rxbd->ctrl   |= QUICC_BD_CTL_Wrap;
229
230     /* setup TX buffer descriptor */
231     txbd = (struct cp_bufdesc *)((char *)eppc + uart_pram->tbase);
232     txbd->length = 1;
233     txbd->buffer = ((char *)eppc + (uart_pram->tbase+(info->Txnum*sizeof(struct cp_bufdesc))));
234     txbd->ctrl   = 0x2000;
235
236     /*
237      *  Clear any previous events. Mask interrupts.
238      *  (Section 16.15.7.14 and 16.15.7.15)
239      */
240     regs->smc_smce = 0xff;
241     regs->smc_smcm = 1; // RX interrupts only, for ctrl-c
242
243     /*
244      *  Set 8,n,1 characters, then also enable rx and tx.
245      *  (Section 16.15.7.11)
246      */
247     regs->smc_smcmr = 0x4820;
248     regs->smc_smcmr = 0x4823;
249
250     /*
251      *  Init Rx & Tx params for SMCx
252      */
253     eppc->cp_cr = QUICC_CPM_CR_INIT_TXRX | port | QUICC_CPM_CR_BUSY;
254
255     info->irq = 0;  // Interrupts not enabled
256 }
257
258
259 //#define UART_BUFSIZE 32
260
261 //static bsp_queue_t uart_queue;
262 //static char uart_buffer[UART_BUFSIZE];
263
264 #define QUICC_SMCE_TX     0x02    // Tx interrupt
265 #define QUICC_SMCE_RX     0x01    // Rx interrupt
266 #define QUICC_SMCMR_TEN       (1<<1)        // Enable transmitter
267 #define QUICC_SMCMR_REN       (1<<0)        // Enable receiver
268
269 #ifdef CYGDBG_DIAG_BUF
270 extern int enable_diag_uart;
271 #endif // CYGDBG_DIAG_BUF
272
273 static void 
274 cyg_hal_sxx_putc(void* __ch_data, cyg_uint8 ch)
275 {
276     volatile struct cp_bufdesc *bd, *first;
277     EPPC *eppc = eppc_base();
278     struct port_info *info = (struct port_info *)__ch_data;
279     volatile struct smc_uart_pram *uart_pram = (volatile struct smc_uart_pram *)((char *)eppc + info->pram);
280     volatile struct smc_regs *regs = (volatile struct smc_regs *)((char *)eppc + info->regs);
281     int timeout;
282     int cache_state;
283     CYGARC_HAL_SAVE_GP();
284
285     /* tx buffer descriptor */
286     bd = (struct cp_bufdesc *)((char *)eppc + uart_pram->tbptr);
287
288     // Scan for a free buffer
289     first = bd;
290     while (bd->ctrl & QUICC_BD_CTL_Ready) {
291         if (bd->ctrl & QUICC_BD_CTL_Wrap) {
292             bd = (struct cp_bufdesc *)((char *)eppc + uart_pram->tbase);
293         } else {
294             bd++;
295         }
296         if (bd == first) break;
297     }
298
299     while (bd->ctrl & QUICC_BD_CTL_Ready) ;  // Wait for buffer free
300     if (bd->ctrl & QUICC_BD_CTL_Int) {
301         // This buffer has just completed interrupt output.  Reset bits
302         bd->ctrl &= ~QUICC_BD_CTL_Int;
303         bd->length = 0;
304     }
305
306     bd->length = 1;
307     bd->buffer[0] = ch;
308     bd->ctrl      |= QUICC_BD_CTL_Ready;
309     // Flush cache if necessary - buffer may be in cacheable memory
310     HAL_DCACHE_IS_ENABLED(cache_state);
311     if (cache_state) {
312       HAL_DCACHE_FLUSH(bd->buffer, 1);
313     }
314
315 #ifdef CYGDBG_DIAG_BUF
316         enable_diag_uart = 0;
317 #endif // CYGDBG_DIAG_BUF
318     timeout = 0;
319     while (bd->ctrl & QUICC_BD_CTL_Ready) {
320 // Wait until buffer free
321         if (++timeout == 0x7FFFF) {
322             // A really long time!
323 #ifdef CYGDBG_DIAG_BUF
324             diag_printf("bd fail? bd: %x, ctrl: %x, tx state: %x\n", bd, bd->ctrl, uart_pram->tstate);
325 #endif // CYGDBG_DIAG_BUF
326             regs->smc_smcmr &= ~QUICC_SMCMR_TEN;  // Disable transmitter
327             bd->ctrl &= ~QUICC_BD_CTL_Ready;
328             regs->smc_smcmr |= QUICC_SMCMR_TEN;   // Enable transmitter
329             bd->ctrl |= QUICC_BD_CTL_Ready;
330             timeout = 0;
331 #ifdef CYGDBG_DIAG_BUF
332             diag_printf("bd retry? bd: %x, ctrl: %x, tx state: %x\n", bd, bd->ctrl, uart_pram->tstate);
333             first = (struct cp_bufdesc *)((char *)eppc + uart_pram->tbase);
334             while (true) {
335                 diag_printf("bd: %x, ctrl: %x, length: %x\n", first, first->ctrl, first->length);
336                 if (first->ctrl & QUICC_BD_CTL_Wrap) break;
337                 first++;
338             }
339 #endif // CYGDBG_DIAG_BUF
340         }
341     }
342     while (bd->ctrl & QUICC_BD_CTL_Ready) ;  // Wait until buffer free
343     bd->length = 0;
344 #ifdef CYGDBG_DIAG_BUF
345     enable_diag_uart = 1;
346 #endif // CYGDBG_DIAG_BUF
347
348     CYGARC_HAL_RESTORE_GP();
349 }
350
351
352 /*
353  * Get a character from a port, non-blocking
354  * This function can be called on either an SMC or SCC port
355  */
356 static cyg_bool
357 cyg_hal_sxx_getc_nonblock(void* __ch_data, cyg_uint8* ch)
358 {
359     volatile struct cp_bufdesc *bd;
360     EPPC *eppc = eppc_base();
361     struct port_info *info = (struct port_info *)__ch_data;
362     volatile struct smc_uart_pram *uart_pram = (volatile struct smc_uart_pram *)((char *)eppc + info->pram);
363     int cache_state;
364
365     /* rx buffer descriptor */
366     bd = info->next_rxbd;
367
368     if (bd->ctrl & QUICC_BD_CTL_Ready)
369         return false;
370
371     *ch = bd->buffer[0];
372
373     bd->length = 0;
374     bd->buffer[0] = '\0';
375     bd->ctrl |= QUICC_BD_CTL_Ready;
376     if (bd->ctrl & QUICC_BD_CTL_Wrap) {
377         bd = (struct cp_bufdesc *)((char *)eppc + uart_pram->rbase);
378     } else {
379         bd++;
380     }
381     info->next_rxbd = bd;
382
383     // Note: the MBX860 does not seem to snoop/invalidate the data cache properly!
384     HAL_DCACHE_IS_ENABLED(cache_state);
385     if (cache_state) {
386         HAL_DCACHE_INVALIDATE(bd->buffer, uart_pram->mrblr);  // Make sure no stale data
387     }
388
389     return true;
390 }
391
392 /*
393  * Get a character from a port, blocking
394  * This function can be called on either an SMC or SCC port
395  */
396 static cyg_uint8
397 cyg_hal_sxx_getc(void* __ch_data)
398 {
399     cyg_uint8 ch;
400     CYGARC_HAL_SAVE_GP();
401
402     while(!cyg_hal_sxx_getc_nonblock(__ch_data, &ch));
403
404     CYGARC_HAL_RESTORE_GP();
405     return ch;
406 }
407
408
409 static void
410 cyg_hal_sxx_write(void* __ch_data, const cyg_uint8* __buf, 
411                          cyg_uint32 __len)
412 {
413     CYGARC_HAL_SAVE_GP();
414
415     while(__len-- > 0)
416         cyg_hal_sxx_putc(__ch_data, *__buf++);
417
418     CYGARC_HAL_RESTORE_GP();
419 }
420
421 /*
422  * Read a sequence of characters from a port
423  * This function can be called on either an SMC or SCC port
424  */
425 static void
426 cyg_hal_sxx_read(void* __ch_data, cyg_uint8* __buf, cyg_uint32 __len)
427 {
428     CYGARC_HAL_SAVE_GP();
429
430     while(__len-- > 0)
431         *__buf++ = cyg_hal_sxx_getc(__ch_data);
432
433     CYGARC_HAL_RESTORE_GP();
434 }
435
436 /*
437  * Read a character from a port, with a timeout
438  * This function can be called on either an SMC or SCC port
439  */
440 static cyg_bool
441 cyg_hal_sxx_getc_timeout(void* __ch_data, cyg_uint8* ch)
442 {
443     struct port_info *info = (struct port_info *)__ch_data;
444     int delay_count = info->timeout * 10; // delay in .1 ms steps
445     cyg_bool res;
446     CYGARC_HAL_SAVE_GP();
447
448     for(;;) {
449         res = cyg_hal_sxx_getc_nonblock(__ch_data, ch);
450         if (res || 0 == delay_count--)
451             break;
452         
453         CYGACC_CALL_IF_DELAY_US(100);
454     }
455
456     CYGARC_HAL_RESTORE_GP();
457     return res;
458 }
459
460 /*
461  * Control/query the state of a port
462  * This function can be called on either an SMC or SCC port
463  */
464 static int
465 cyg_hal_sxx_control(void *__ch_data, __comm_control_cmd_t __func, ...)
466 {
467     struct port_info *info = (struct port_info *)__ch_data;
468     int ret = 0;
469     CYGARC_HAL_SAVE_GP();
470
471     switch (__func) {
472     case __COMMCTL_IRQ_ENABLE:
473         HAL_INTERRUPT_UNMASK(info->intnum);
474         info->irq = 1;
475         break;
476     case __COMMCTL_IRQ_DISABLE:
477         ret = info->irq;
478         info->irq = 0;
479         HAL_INTERRUPT_MASK(info->intnum);
480         break;
481     case __COMMCTL_DBG_ISR_VECTOR:
482         ret = info->intnum;
483         break;
484     case __COMMCTL_SET_TIMEOUT:
485     {
486         va_list ap;
487
488         va_start(ap, __func);
489
490         ret = info->timeout;
491         info->timeout = va_arg(ap, cyg_uint32);
492
493         va_end(ap);
494     }        
495     default:
496         break;
497     }
498     CYGARC_HAL_RESTORE_GP();
499     return ret;
500 }
501
502 /*
503  * Low-level interrupt (ISR) handler
504  * This function can be called on only an SMC port
505  */
506 static int
507 cyg_hal_smcx_isr(void *__ch_data, int* __ctrlc, 
508                  CYG_ADDRWORD __vector, CYG_ADDRWORD __data)
509 {
510     EPPC *eppc = eppc_base();
511     volatile struct cp_bufdesc *bd;
512     struct port_info *info = (struct port_info *)__ch_data;
513     volatile struct smc_regs *regs = (volatile struct smc_regs *)((char *)eppc + info->regs);
514     volatile struct smc_uart_pram *uart_pram = (volatile struct smc_uart_pram *)((char *)eppc + info->pram);
515     char ch;
516     int res = 0;
517     CYGARC_HAL_SAVE_GP();
518
519     *__ctrlc = 0;
520     if (regs->smc_smce & QUICC_SMCE_RX) {
521
522         regs->smc_smce = QUICC_SMCE_RX;
523
524         /* rx buffer descriptors */
525         bd = info->next_rxbd;
526
527         if ((bd->ctrl & QUICC_BD_CTL_Ready) == 0) {
528             
529             // then there be a character waiting
530             ch = bd->buffer[0];
531             bd->length = 1;
532             bd->ctrl   |= QUICC_BD_CTL_Ready | QUICC_BD_CTL_Int;
533             if (bd->ctrl & QUICC_BD_CTL_Wrap) {
534                 bd = (struct cp_bufdesc *)((char *)eppc + uart_pram->rbase);
535             } else {
536                 bd++;
537             }
538             info->next_rxbd = bd;
539         
540             if( cyg_hal_is_break( &ch , 1 ) )
541                 *__ctrlc = 1;
542         }
543
544         // Interrupt handled. Acknowledge it.
545         HAL_INTERRUPT_ACKNOWLEDGE(info->intnum);
546         res = CYG_ISR_HANDLED;
547     }
548
549     CYGARC_HAL_RESTORE_GP();
550     return res;
551 }
552
553 #if (CYGNUM_HAL_QUICC_SCC1+CYGNUM_HAL_QUICC_SCC2+CYGNUM_HAL_QUICC_SCC3) > 0
554 /*
555  *  Initialize an SCC as a uart.
556  *
557  *  Comments below reference Motorola's "MPC860 User Manual".
558  *  The basic initialization steps are from Section 16.15.8
559  *  of that manual.
560  */     
561 static void
562 cyg_hal_sccx_init_channel(struct port_info *info, int port)
563 {
564     EPPC *eppc = eppc_base();
565     int i;
566     volatile struct uart_pram *uart_pram = (volatile struct uart_pram *)((char *)eppc + info->pram);
567     volatile struct scc_regs *regs = (volatile struct scc_regs *)((char *)eppc + info->regs);
568     struct cp_bufdesc *txbd, *rxbd;
569
570     if (info->init) return;
571     info->init = 1;
572
573     /*
574      *  Set up the Port pins for UART operation.
575      */
576     switch (port) {
577 #if CYGNUM_HAL_QUICC_SCC1 > 0
578     case QUICC_CPM_SCC1:
579         eppc->pio_papar |= 0x03;
580         eppc->pio_padir &= ~0x03;
581         eppc->pio_paodr &= ~0x03;
582
583         /* CTS on PortC.11 */
584         eppc->pio_pcdir &= 0x800;
585         eppc->pio_pcpar &= 0x800;
586         eppc->pio_pcso  |= 0x800;
587
588         /* RTS on PortB.19 */
589         eppc->pip_pbpar |= 0x1000;
590         eppc->pip_pbdir |= 0x1000;
591
592         break;
593 #endif
594 #if CYGNUM_HAL_QUICC_SCC2 > 0
595     case QUICC_CPM_SCC2:
596 #error FIXME
597         eppc->pio_papar |= 0x0C;
598         eppc->pio_padir &= ~0x0C;
599         eppc->pio_paodr &= ~0x0C;
600
601         /* CTS on PortC.11 */
602         eppc->pio_pcdir &= 0xC00;
603         eppc->pio_pcpar &= 0xC00;
604         eppc->pio_pcso  |= 0xC00;
605
606         /* RTS on PortB.19 */
607         eppc->pip_pbpar |= 0x2000;
608         eppc->pip_pbdir |= 0x2000;
609
610         break;
611 #endif
612 #if CYGNUM_HAL_QUICC_SCC3 > 0
613     case QUICC_CPM_SCC3:
614 #if defined(CYGHWR_HAL_POWERPC_MPC8XX_850)
615 #if 0
616 // CAUTION!  Enabling these bits made the port get stuck :-(
617         /* CTS/RTS/CD on PortC.4/5/13 */
618         eppc->pio_pcdir &= 0x0C04;
619         eppc->pio_pcpar &= 0x0C00;
620 //        eppc->pio_pcpar |= 0x0004;
621         eppc->pio_pcso  |= 0x0C00;
622 #endif
623
624         /* RxD/TxD on PortB.24/25 */
625         eppc->pip_pbpar |= 0x00C0;
626         eppc->pip_pbdir |= 0x00C0;
627         eppc->pip_pbodr &= ~0x00C0;
628
629 #elif defined(CYGHWR_HAL_POWERPC_MPC8XX_852T)
630         eppc->pio_papar |= 0x30;
631         eppc->pio_padir &= ~0x30;
632         eppc->pio_paodr &= ~0x30;
633 #else
634 #error "Cannot route SCC3 I/O"
635 #endif // 850T
636         break;
637 #endif // SCC3
638     }
639
640     // Set up baud rate generator.  These are allocated from a
641     // pool, based on the port number and type.  The allocator
642     // will arrange to have the selected baud rate clock steered
643     // to this device.
644     info->brg = _mpc8xx_allocate_brg(port);
645     *(info->brg) = 0x10000 | (UART_BIT_RATE(UART_BAUD_RATE)<<1);
646
647     /*
648      *  Set pointers to buffer descriptors.
649      */
650     uart_pram->rbase = _mpc8xx_allocBd(sizeof(struct cp_bufdesc)*info->Rxnum + info->Rxnum);
651     uart_pram->tbase = _mpc8xx_allocBd(sizeof(struct cp_bufdesc)*info->Txnum + info->Txnum);
652
653     /*
654      *  SDMA & LCD bus request level 5
655      */
656     eppc->dma_sdcr = 1;
657
658     /*
659      *  Set Rx and Tx function code
660      */
661     uart_pram->rfcr = 0x18;
662     uart_pram->tfcr = 0x18;
663
664     /* max receive buffer length */
665     uart_pram->mrblr = 1;
666
667     /* disable max_idle feature */
668     uart_pram->max_idl = 0;
669
670     /* no last brk char received */
671     uart_pram->brkln = 0;
672
673     /* no break condition occurred */
674     uart_pram->brkec = 0;
675
676     /* 1 break char sent on top XMIT */
677     uart_pram->brkcr = 1;
678
679     /* character mask */
680     uart_pram->rccm  = 0xC0FF;
681
682     /* control characters */
683     for (i = 0;  i < 8;  i++) {
684         uart_pram->cc[i] = 0x8000;  // Mark unused
685     }
686
687     /* setup RX buffer descriptors */
688     rxbd = (struct cp_bufdesc *)((char *)eppc + uart_pram->rbase);
689     info->next_rxbd = rxbd;
690     for (i = 0;  i < info->Rxnum;  i++) {
691         rxbd->length = 0;
692         rxbd->buffer = ((char *)eppc + (uart_pram->rbase+(info->Rxnum*sizeof(struct cp_bufdesc))))+i;
693         rxbd->ctrl   = QUICC_BD_CTL_Ready | QUICC_BD_CTL_Int;
694         rxbd++;
695     }
696     rxbd--;
697     rxbd->ctrl   |= QUICC_BD_CTL_Wrap;
698
699     /* setup TX buffer descriptor */
700     txbd = (struct cp_bufdesc *)((char *)eppc + uart_pram->tbase);
701     txbd->length = 0;
702     txbd->buffer = ((char *)eppc + (uart_pram->tbase+(info->Txnum*sizeof(struct cp_bufdesc))));
703     txbd->ctrl   = 0x2000;
704
705     /*
706      *  Clear any previous events. Mask interrupts.
707      *  (Section 16.15.7.14 and 16.15.7.15)
708      */
709     regs->scc_scce = 0xffff;
710     regs->scc_sccm = 1; // RX interrupts only, for ctrl-c
711
712     /*
713      *  Set 8,n,1 characters
714      */
715     regs->scc_psmr = (3<<12);
716     regs->scc_gsmr_h = 0x20;          // 8bit FIFO
717     regs->scc_gsmr_l = 0x00028004;    // 16x TxCLK, 16x RxCLK, UART
718
719     /*
720      *  Init Rx & Tx params for SCCX
721      */
722     eppc->cp_cr = QUICC_CPM_CR_INIT_TXRX | port | QUICC_CPM_CR_BUSY;
723
724     regs->scc_gsmr_l |= 0x30;         // Enable Rx, Tx
725
726     info->irq = 0;
727 }
728
729 static int
730 cyg_hal_sccx_isr(void *__ch_data, int* __ctrlc, 
731                  CYG_ADDRWORD __vector, CYG_ADDRWORD __data)
732 {
733     EPPC *eppc = eppc_base();
734     volatile struct cp_bufdesc *bd;
735     struct port_info *info = (struct port_info *)__ch_data;
736     volatile struct scc_regs *regs = (volatile struct scc_regs *)((char *)eppc + info->regs);
737     volatile struct uart_pram *uart_pram = (volatile struct uart_pram *)((char *)eppc + info->pram);
738     char ch;
739     int res = 0;
740     CYGARC_HAL_SAVE_GP();
741
742     *__ctrlc = 0;
743     if (regs->scc_scce & QUICC_SMCE_RX) {
744
745         regs->scc_scce = QUICC_SMCE_RX;
746
747         /* rx buffer descriptors */
748         bd = info->next_rxbd;
749
750         if ((bd->ctrl & QUICC_BD_CTL_Ready) == 0) {
751             
752             // then there be a character waiting
753             ch = bd->buffer[0];
754             bd->length = 1;
755             bd->ctrl   |= QUICC_BD_CTL_Ready | QUICC_BD_CTL_Int;
756             if (bd->ctrl & QUICC_BD_CTL_Wrap) {
757                 bd = (struct cp_bufdesc *)((char *)eppc + uart_pram->rbase);
758             } else {
759                 bd++;
760             }
761             info->next_rxbd = bd;
762         
763             if( cyg_hal_is_break( &ch , 1 ) )
764                 *__ctrlc = 1;
765         }
766
767         // Interrupt handled. Acknowledge it.
768         HAL_INTERRUPT_ACKNOWLEDGE(info->intnum);
769         res = CYG_ISR_HANDLED;
770     }
771
772     CYGARC_HAL_RESTORE_GP();
773     return res;
774 }
775 #endif // CYGNUM_HAL_QUICC_SCCX
776
777 /*
778  * Early initialization of comm channels. Must not rely
779  * on interrupts, yet. Interrupt operation can be enabled
780  * in _bsp_board_init().
781  */
782 void
783 cyg_hal_plf_serial_init(void)
784 {
785     hal_virtual_comm_table_t* comm;
786     int cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
787
788     static int init = 0;  // It's wrong to do this more than once
789     int chan = 0;
790     if (init) return;
791     init++;
792
793     // Setup procs in the vector table
794
795 #if CYGNUM_HAL_QUICC_SMC1 > 0
796     // Set up SMC1
797     cyg_hal_smcx_init_channel(&ports[chan], QUICC_CPM_SMC1);
798     CYGACC_CALL_IF_SET_CONSOLE_COMM(chan);// Should be configurable!
799     comm = CYGACC_CALL_IF_CONSOLE_PROCS();
800     CYGACC_COMM_IF_CH_DATA_SET(*comm, &ports[chan]);
801     CYGACC_COMM_IF_WRITE_SET(*comm, cyg_hal_sxx_write);
802     CYGACC_COMM_IF_READ_SET(*comm, cyg_hal_sxx_read);
803     CYGACC_COMM_IF_PUTC_SET(*comm, cyg_hal_sxx_putc);
804     CYGACC_COMM_IF_GETC_SET(*comm, cyg_hal_sxx_getc);
805     CYGACC_COMM_IF_CONTROL_SET(*comm, cyg_hal_sxx_control);
806     CYGACC_COMM_IF_DBG_ISR_SET(*comm, cyg_hal_smcx_isr);
807     CYGACC_COMM_IF_GETC_TIMEOUT_SET(*comm, cyg_hal_sxx_getc_timeout);
808     chan++;
809 #endif
810
811 #if CYGNUM_HAL_QUICC_SMC2 > 0
812     // Set up SMC2
813     cyg_hal_smcx_init_channel(&ports[chan], QUICC_CPM_SMC2);
814     CYGACC_CALL_IF_SET_CONSOLE_COMM(chan);// Should be configurable!
815     comm = CYGACC_CALL_IF_CONSOLE_PROCS();
816     CYGACC_COMM_IF_CH_DATA_SET(*comm, &ports[chan]);
817     CYGACC_COMM_IF_WRITE_SET(*comm, cyg_hal_sxx_write);
818     CYGACC_COMM_IF_READ_SET(*comm, cyg_hal_sxx_read);
819     CYGACC_COMM_IF_PUTC_SET(*comm, cyg_hal_sxx_putc);
820     CYGACC_COMM_IF_GETC_SET(*comm, cyg_hal_sxx_getc);
821     CYGACC_COMM_IF_CONTROL_SET(*comm, cyg_hal_sxx_control);
822     CYGACC_COMM_IF_DBG_ISR_SET(*comm, cyg_hal_smcx_isr);
823     CYGACC_COMM_IF_GETC_TIMEOUT_SET(*comm, cyg_hal_sxx_getc_timeout);
824     chan++;
825 #endif
826
827 #if CYGNUM_HAL_QUICC_SCC1 > 0
828     // Set  up SCC1
829     cyg_hal_sccx_init_channel(&ports[chan], QUICC_CPM_SCC1);
830     CYGACC_CALL_IF_SET_CONSOLE_COMM(chan);// Should be configurable!
831     comm = CYGACC_CALL_IF_CONSOLE_PROCS();
832     CYGACC_COMM_IF_CH_DATA_SET(*comm, &ports[chan]);
833     CYGACC_COMM_IF_WRITE_SET(*comm, cyg_hal_sxx_write);
834     CYGACC_COMM_IF_READ_SET(*comm, cyg_hal_sxx_read);
835     CYGACC_COMM_IF_PUTC_SET(*comm, cyg_hal_sxx_putc);
836     CYGACC_COMM_IF_GETC_SET(*comm, cyg_hal_sxx_getc);
837     CYGACC_COMM_IF_CONTROL_SET(*comm, cyg_hal_sxx_control);
838     CYGACC_COMM_IF_DBG_ISR_SET(*comm, cyg_hal_sccx_isr);
839     CYGACC_COMM_IF_GETC_TIMEOUT_SET(*comm, cyg_hal_sxx_getc_timeout);
840     chan++;
841 #endif
842
843 #if CYGNUM_HAL_QUICC_SCC2 > 0
844     // Set  up SCC2
845     cyg_hal_sccx_init_channel(&ports[chan], QUICC_CPM_SCC2);
846     CYGACC_CALL_IF_SET_CONSOLE_COMM(chan);// Should be configurable!
847     comm = CYGACC_CALL_IF_CONSOLE_PROCS();
848     CYGACC_COMM_IF_CH_DATA_SET(*comm, &ports[chan]);
849     CYGACC_COMM_IF_WRITE_SET(*comm, cyg_hal_sxx_write);
850     CYGACC_COMM_IF_READ_SET(*comm, cyg_hal_sxx_read);
851     CYGACC_COMM_IF_PUTC_SET(*comm, cyg_hal_sxx_putc);
852     CYGACC_COMM_IF_GETC_SET(*comm, cyg_hal_sxx_getc);
853     CYGACC_COMM_IF_CONTROL_SET(*comm, cyg_hal_sxx_control);
854     CYGACC_COMM_IF_DBG_ISR_SET(*comm, cyg_hal_sccx_isr);
855     CYGACC_COMM_IF_GETC_TIMEOUT_SET(*comm, cyg_hal_sxx_getc_timeout);
856     chan++;
857 #endif
858
859 #if CYGNUM_HAL_QUICC_SCC3 > 0
860     // Set  up SCC3
861     cyg_hal_sccx_init_channel(&ports[chan], QUICC_CPM_SCC3);
862     CYGACC_CALL_IF_SET_CONSOLE_COMM(chan);// Should be configurable!
863     comm = CYGACC_CALL_IF_CONSOLE_PROCS();
864     CYGACC_COMM_IF_CH_DATA_SET(*comm, &ports[chan]);
865     CYGACC_COMM_IF_WRITE_SET(*comm, cyg_hal_sxx_write);
866     CYGACC_COMM_IF_READ_SET(*comm, cyg_hal_sxx_read);
867     CYGACC_COMM_IF_PUTC_SET(*comm, cyg_hal_sxx_putc);
868     CYGACC_COMM_IF_GETC_SET(*comm, cyg_hal_sxx_getc);
869     CYGACC_COMM_IF_CONTROL_SET(*comm, cyg_hal_sxx_control);
870     CYGACC_COMM_IF_DBG_ISR_SET(*comm, cyg_hal_sccx_isr);
871     CYGACC_COMM_IF_GETC_TIMEOUT_SET(*comm, cyg_hal_sxx_getc_timeout);
872     chan++;
873 #endif
874
875     // Restore original console
876     CYGACC_CALL_IF_SET_CONSOLE_COMM(cur);
877 }
878
879 // EOF quicc_smc1.c