]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/devs/serial/powerpc/quicc2/v2_0/src/quicc2_scc_serial.c
Initial revision
[karo-tx-redboot.git] / packages / devs / serial / powerpc / quicc2 / v2_0 / src / quicc2_scc_serial.c
1 //==========================================================================
2 //
3 //      io/serial/powerpc/quicc2_scc_serial.c
4 //
5 //      PowerPC QUICC2 (SCC) Serial I/O Interface Module (interrupt driven)
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 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):    mtek
45 // Contributors: gthomas
46 // Date:         1999-06-20
47 // Purpose:      QUICC2 SCC Serial I/O module (interrupt driven version)
48 // Description: 
49 //
50 //####DESCRIPTIONEND####
51 //
52 //==========================================================================
53
54 #include <pkgconf/system.h>
55 #include <pkgconf/io_serial.h>
56 #include <pkgconf/io.h>
57 #include <cyg/io/io.h>
58 #include <cyg/hal/hal_intr.h>
59 #include <cyg/hal/var_intr.h>
60 #include <cyg/io/devtab.h>
61 #include <cyg/io/serial.h>
62 #include <cyg/infra/diag.h>
63 #include <cyg/hal/hal_cache.h>
64 #include <cyg/hal/mpc8260.h>
65 #include CYGBLD_HAL_PLATFORM_H
66
67 #include "quicc2_scc_serial.h"
68 #define QUICC2_VADS_IMM_BASE    0x04700000
69 #define QUICC2_VADS_BCSR_BASE   0x04500000
70
71 #ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC2_SCC
72
73 static bool 
74 quicc2_scc_serial_init(struct cyg_devtab_entry *tab);
75 static bool 
76 quicc2_scc_serial_putc(serial_channel *chan, 
77                        unsigned char c);
78 static Cyg_ErrNo 
79 quicc2_scc_serial_lookup(struct cyg_devtab_entry **tab, 
80                          struct cyg_devtab_entry *sub_tab,
81                          const char *name);
82 static unsigned char 
83 quicc2_scc_serial_getc(serial_channel *chan);
84 static Cyg_ErrNo 
85 quicc2_scc_serial_set_config(serial_channel *chan,
86                              cyg_uint32 key, const void *xbuf,
87                              cyg_uint32 *len);
88 static void 
89 quicc2_scc_serial_start_xmit(serial_channel *chan);
90 static void 
91 quicc2_scc_serial_stop_xmit(serial_channel *chan);
92
93 static cyg_uint32 
94 quicc2_scc_serial_ISR(cyg_vector_t vector, 
95                       cyg_addrword_t data);
96 static void       
97 quicc2_scc_serial_DSR(cyg_vector_t vector, 
98                       cyg_ucount32 count, 
99                       cyg_addrword_t data);
100
101 static SERIAL_FUNS(quicc2_scc_serial_funs, 
102                    quicc2_scc_serial_putc, 
103                    quicc2_scc_serial_getc,
104                    quicc2_scc_serial_set_config,
105                    quicc2_scc_serial_start_xmit,
106                    quicc2_scc_serial_stop_xmit
107     );
108
109 #ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1
110 static quicc2_scc_serial_info quicc2_scc_serial_info1;
111
112 #if CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_BUFSIZE > 0
113 static unsigned char quicc2_scc_serial_out_buf1[CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_BUFSIZE];
114 static unsigned char quicc2_scc_serial_in_buf1[CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_BUFSIZE];
115
116 static SERIAL_CHANNEL_USING_INTERRUPTS(quicc2_scc_serial_channel1,
117                                        quicc2_scc_serial_funs, 
118                                        quicc2_scc_serial_info1,
119                                        CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_BAUD),
120                                        CYG_SERIAL_STOP_DEFAULT,
121                                        CYG_SERIAL_PARITY_DEFAULT,
122                                        CYG_SERIAL_WORD_LENGTH_DEFAULT,
123                                        CYG_SERIAL_FLAGS_DEFAULT,
124                                        &quicc2_scc_serial_out_buf1[0], sizeof(quicc2_scc_serial_out_buf1),
125                                        &quicc2_scc_serial_in_buf1[0], sizeof(quicc2_scc_serial_in_buf1)
126     );
127 #else
128 static SERIAL_CHANNEL(quicc2_scc_serial_channel1,
129                       quicc2_scc_serial_funs, 
130                       quicc2_scc_serial_info1,
131                       CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_BAUD),
132                       CYG_SERIAL_STOP_DEFAULT,
133                       CYG_SERIAL_PARITY_DEFAULT,
134                       CYG_SERIAL_WORD_LENGTH_DEFAULT,
135                       CYG_SERIAL_FLAGS_DEFAULT
136     );
137 #endif
138
139 static unsigned char quicc2_scc1_txbuf[CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_TxNUM]
140                                       [CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_TxSIZE + HAL_DCACHE_LINE_SIZE-1];
141 static unsigned char quicc2_scc1_rxbuf[CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_RxNUM]
142                                       [CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_RxSIZE + HAL_DCACHE_LINE_SIZE-1];
143
144 DEVTAB_ENTRY(quicc2_scc_serial_io1, 
145              CYGDAT_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_NAME,
146              0,                     // Does not depend on a lower level interface
147              &cyg_io_serial_devio, 
148              quicc2_scc_serial_init, 
149              quicc2_scc_serial_lookup,     // Serial driver may need initializing
150              &quicc2_scc_serial_channel1
151     );
152 #endif //  CYGPKG_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1
153
154 #ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2
155 static quicc2_scc_serial_info quicc2_scc_serial_info2;
156
157 #if CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_BUFSIZE > 0
158 static unsigned char quicc2_scc_serial_out_buf2[CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_BUFSIZE];
159 static unsigned char quicc2_scc_serial_in_buf2[CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_BUFSIZE];
160
161 static SERIAL_CHANNEL_USING_INTERRUPTS(quicc2_scc_serial_channel2,
162                                        quicc2_scc_serial_funs, 
163                                        quicc2_scc_serial_info2,
164                                        CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_BAUD),
165                                        CYG_SERIAL_STOP_DEFAULT,
166                                        CYG_SERIAL_PARITY_DEFAULT,
167                                        CYG_SERIAL_WORD_LENGTH_DEFAULT,
168                                        CYG_SERIAL_FLAGS_DEFAULT,
169                                        &quicc2_scc_serial_out_buf2[0], sizeof(quicc2_scc_serial_out_buf2),
170                                        &quicc2_scc_serial_in_buf2[0], sizeof(quicc2_scc_serial_in_buf2)
171     );
172 #else
173 static SERIAL_CHANNEL(quicc2_scc_serial_channel2,
174                       quicc2_scc_serial_funs, 
175                       quicc2_scc_serial_info2,
176                       CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_BAUD),
177                       CYG_SERIAL_STOP_DEFAULT,
178                       CYG_SERIAL_PARITY_DEFAULT,
179                       CYG_SERIAL_WORD_LENGTH_DEFAULT,
180                       CYG_SERIAL_FLAGS_DEFAULT
181     );
182 #endif
183 static unsigned char quicc2_scc2_txbuf[CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_TxNUM]
184                                       [CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_TxSIZE + HAL_DCACHE_LINE_SIZE-1];
185 static unsigned char quicc2_scc2_rxbuf[CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_RxNUM]
186                                       [CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_RxSIZE + HAL_DCACHE_LINE_SIZE-1];
187
188 DEVTAB_ENTRY(quicc2_scc_serial_io2, 
189              CYGDAT_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_NAME,
190              0,                     // Does not depend on a lower level interface
191              &cyg_io_serial_devio, 
192              quicc2_scc_serial_init, 
193              quicc2_scc_serial_lookup,     // Serial driver may need initializing
194              &quicc2_scc_serial_channel2
195     );
196 #endif //  CYGPKG_IO_SERIAL_POWERPC_QUICC2_SCC
197
198 #ifdef CYGDBG_DIAG_BUF
199 extern int enable_diag_uart;
200 #endif // CYGDBG_DIAG_BUF
201
202 // Internal function to actually configure the hardware to 
203 // desired baud rate, stop bits and parity ...
204 static bool
205 quicc2_scc_serial_config_port(serial_channel *chan, 
206                               cyg_serial_info_t *new_config, 
207                               bool init)
208 {
209     quicc2_scc_serial_info *scc_chan = (quicc2_scc_serial_info *)chan->dev_priv;
210     volatile t_PQ2IMM *IMM = (volatile t_PQ2IMM *) QUICC2_VADS_IMM_BASE;
211
212     unsigned long b_rate   = select_baud[new_config->baud];
213
214     if (b_rate == 0) return false;
215
216     // Stop the transmitter while changing baud rate
217     while (IMM->cpm_cpcr & QUICC2_CPCR_READY);
218     IMM->cpm_cpcr = scc_chan->scc_cpcr | QUICC2_CPCR_STOP_TX | QUICC2_CPCR_READY;
219     while (IMM->cpm_cpcr & QUICC2_CPCR_READY);
220
221     // Disable Tx, RX and put them in a reset state
222     scc_chan->scc_regs->gsmr_l &= ~(QUICC2_SCC_GSMR_L_ENT | QUICC2_SCC_GSMR_L_ENR);
223
224     // Set the baud rate
225     *(scc_chan->brg) = (UART_BIT_RATE(b_rate) << 1) | QUICC2_BRG_EN;
226
227     // Set stop bits, word length and parity
228     scc_chan->scc_regs->psmr = QUICC2_SCC_PSMR_ASYNC |
229       select_stop_bits[new_config->stop] |
230       select_word_length[new_config->word_length - CYGNUM_SERIAL_WORD_LENGTH_5] | 
231       select_parity[new_config->parity];
232
233     // Support fractional stop bits 
234     scc_chan->scc_regs->dsr = (new_config->stop & 1) ? QUICC2_SCC_DSR_FULL : QUICC2_SCC_DSR_HALF;
235       
236     // Initialize the parameters
237     while (IMM->cpm_cpcr & QUICC2_CPCR_READY);
238     IMM->cpm_cpcr = scc_chan->scc_cpcr | QUICC2_CPCR_INIT_TX_RX | QUICC2_CPCR_READY;
239     while (IMM->cpm_cpcr & QUICC2_CPCR_READY);
240
241     // Enable Tx and Rx
242     scc_chan->scc_regs->gsmr_l |= (QUICC2_SCC_GSMR_L_ENT | QUICC2_SCC_GSMR_L_ENR);
243
244     if (new_config != &chan->config) {
245         chan->config = *new_config;
246     }
247     return true;
248 }
249
250 // Function to set up internal tables for device.
251 static void
252 quicc2_scc_serial_init_info(quicc2_scc_serial_info *scc_chan,
253                             int SCC_index,
254                             int BRG_index,
255                             int TxBD, int TxNUM, int TxSIZE,
256                             cyg_uint8 *TxBUF,
257                             int RxBD, int RxNUM, int RxSIZE,
258                             cyg_uint8 *RxBUF)
259 {
260   volatile t_PQ2IMM *IMM = (volatile t_PQ2IMM *) QUICC2_VADS_IMM_BASE;
261 #ifdef CYGPKG_HAL_POWERPC_VADS
262   volatile t_BCSR *bcsr  = (volatile t_BCSR *) QUICC2_VADS_BCSR_BASE;
263 #endif
264   t_UartScc_Pram *uart_pram;
265   scc_bd  *txbd, *rxbd;
266   int i;
267   
268   // Disable the channel, just in case 
269   IMM->scc_regs[SCC_index-1].gsmr_l &= ~(QUICC2_SCC_GSMR_L_ENT | QUICC2_SCC_GSMR_L_ENR);
270   
271   switch (SCC_index) {
272     
273   case 1:
274     // Put the data into the info structure 
275     scc_chan->scc_cpcr = QUICC2_CPCR_SCC1;
276     scc_chan->scc_regs = &(IMM->scc_regs[0]);
277     scc_chan->scc_pram = &(IMM->pram.serials.scc_pram[0]);
278     scc_chan->int_vector = CYGNUM_HAL_INTERRUPT_SCC1;
279     
280     // Set-up the PORT D pins
281     IMM->io_regs[PORT_D].psor &= ~QUICC2_SCC1_PORTD_PPAR;
282     IMM->io_regs[PORT_D].psor |=  QUICC2_SCC1_PORTD_PDIR;
283     IMM->io_regs[PORT_D].ppar |=  QUICC2_SCC1_PORTD_PPAR;
284     IMM->io_regs[PORT_D].pdir &= ~QUICC2_SCC1_PORTD_PPAR;
285     IMM->io_regs[PORT_D].pdir |=  QUICC2_SCC1_PORTD_PDIR;
286     IMM->io_regs[PORT_D].podr &= ~QUICC2_SCC1_PORTD_PPAR;
287
288     // Set-up the PORT C pins
289     IMM->io_regs[PORT_C].psor &= ~QUICC2_SCC1_PORTC_PPAR;
290     IMM->io_regs[PORT_C].ppar |=  QUICC2_SCC1_PORTC_PPAR;
291     IMM->io_regs[PORT_C].pdir &= ~QUICC2_SCC1_PORTC_PPAR;
292     IMM->io_regs[PORT_C].podr &= ~QUICC2_SCC1_PORTC_PPAR;
293
294     // Select the baud rate generator and connect it 
295     IMM->cpm_mux_cmxscr &= QUICC2_CMX_SCC1_CLR;
296
297     switch (BRG_index) {
298     case 1:
299       scc_chan->brg = &(IMM->brgs_brgc1);
300       IMM->cpm_mux_cmxscr |= QUICC2_CMX_SCC1_BRG1;
301       break;
302     case 2:
303       scc_chan->brg = &(IMM->brgs_brgc2);
304       IMM->cpm_mux_cmxscr |= QUICC2_CMX_SCC1_BRG2;
305       break;
306     case 3:
307       scc_chan->brg = &(IMM->brgs_brgc3);
308       IMM->cpm_mux_cmxscr |= QUICC2_CMX_SCC1_BRG3;
309       break;
310     case 4:
311       scc_chan->brg = &(IMM->brgs_brgc4);
312       IMM->cpm_mux_cmxscr |= QUICC2_CMX_SCC1_BRG4;
313       break;
314     }
315 #ifdef CYGPKG_HAL_POWERPC_VADS     
316     // Enable the transciever
317     bcsr->bcsr1 &= ~(QUICC2_BCSR_EN_SCC1);
318 #endif
319     break;
320
321   case 2:
322     // Put the data into the info structure 
323     scc_chan->scc_cpcr = QUICC2_CPCR_SCC2;
324     scc_chan->scc_regs = &(IMM->scc_regs[1]);
325     scc_chan->scc_pram = &(IMM->pram.serials.scc_pram[1]);
326     scc_chan->int_vector = CYGNUM_HAL_INTERRUPT_SCC2;
327
328     // Set-up the PORT D pins
329     IMM->io_regs[PORT_D].psor &= ~QUICC2_SCC2_PORTD_PPAR;
330     IMM->io_regs[PORT_D].ppar |=  QUICC2_SCC2_PORTD_PPAR;
331     IMM->io_regs[PORT_D].pdir &= ~QUICC2_SCC2_PORTD_PPAR;
332     IMM->io_regs[PORT_D].pdir |=  QUICC2_SCC2_PORTD_PDIR;
333     IMM->io_regs[PORT_D].podr &= ~QUICC2_SCC2_PORTD_PPAR;
334
335     // Set-up the PORT C pins
336     IMM->io_regs[PORT_C].psor &= ~QUICC2_SCC2_PORTC_PPAR;
337     IMM->io_regs[PORT_C].ppar |=  QUICC2_SCC2_PORTC_PPAR;
338     IMM->io_regs[PORT_C].pdir &= ~QUICC2_SCC2_PORTC_PPAR;
339     IMM->io_regs[PORT_C].podr &= ~QUICC2_SCC2_PORTC_PPAR;
340
341     // Select the baud rate generator and connect it 
342     IMM->cpm_mux_cmxscr &= QUICC2_CMX_SCC2_CLR;
343
344     switch (BRG_index) {
345     case 1:
346       scc_chan->brg = &(IMM->brgs_brgc1);
347       IMM->cpm_mux_cmxscr |= QUICC2_CMX_SCC2_BRG1;
348       break;
349     case 2:
350       scc_chan->brg = &(IMM->brgs_brgc2);
351       IMM->cpm_mux_cmxscr |= QUICC2_CMX_SCC2_BRG2;
352       break;
353     case 3:
354       scc_chan->brg = &(IMM->brgs_brgc3);
355       IMM->cpm_mux_cmxscr |= QUICC2_CMX_SCC2_BRG3;
356       break;
357     case 4:
358       scc_chan->brg = &(IMM->brgs_brgc4);
359       IMM->cpm_mux_cmxscr |= QUICC2_CMX_SCC2_BRG4;
360       break;
361     } 
362 #ifdef CYGPKG_HAL_POWERPC_VADS 
363     // Enable the transciever
364     bcsr->bcsr1 &= ~(QUICC2_BCSR_EN_SCC2);
365 #endif
366     break;
367
368   default:
369     diag_printf("Incorrect SCC index in quicc2_scc_serial_init_info \n");
370     break;
371   }
372
373   // Initialize common SCC PRAM
374   scc_chan->tbase = (scc_bd *) (QUICC2_VADS_IMM_BASE + TxBD);
375   scc_chan->rbase = (scc_bd *) (QUICC2_VADS_IMM_BASE + RxBD);
376   scc_chan->txbd  = (scc_bd *) (QUICC2_VADS_IMM_BASE + TxBD);
377   scc_chan->rxbd  = (scc_bd *) (QUICC2_VADS_IMM_BASE + RxBD);
378   scc_chan->txsize = TxSIZE;
379   scc_chan->rxsize = RxSIZE;
380
381   scc_chan->scc_pram->rbase = RxBD;
382   scc_chan->scc_pram->tbase = TxBD;
383   scc_chan->scc_pram->rfcr  = 0x10;
384   scc_chan->scc_pram->tfcr  = 0x10;
385   scc_chan->scc_pram->mrblr = RxSIZE;
386
387   // Initialize UART PRAM
388   uart_pram = &(scc_chan->scc_pram->SpecificProtocol.u);
389     
390   uart_pram->max_idl = 4;
391   uart_pram->brkcr   = 1;
392   uart_pram->brkln   = 0;
393   uart_pram->parec   = 0;
394   uart_pram->frmec   = 0;
395   uart_pram->nosec   = 0;
396   uart_pram->brkec   = 0;
397   uart_pram->uaddr1  = 0;
398   uart_pram->uaddr2  = 0;
399   uart_pram->toseq   = 0;
400   uart_pram->cc[0] = 0x8000;
401   uart_pram->cc[1] = 0x8000;
402   uart_pram->cc[2] = 0x8000;
403   uart_pram->cc[3] = 0x8000;
404   uart_pram->cc[4] = 0x8000;
405   uart_pram->cc[5] = 0x8000;
406   uart_pram->cc[6] = 0x8000;
407   uart_pram->cc[7] = 0x8000;
408   uart_pram->rccm  = 0xC0FF;
409
410   // Initialize registers
411   scc_chan->scc_regs->gsmr_l = QUICC2_SCC_GSMR_L_INIT;
412   scc_chan->scc_regs->gsmr_h = QUICC2_SCC_GSMR_H_INIT;
413   // scc_chan->scc_regs->psmr   = 0x8000;  // Set by config
414   scc_chan->scc_regs->todr   = 0;
415   //  scc_chan->scc_regs->dsr    = 0x7e7e; // Set by config
416   scc_chan->scc_regs->scce   = 0xffff;
417   scc_chan->scc_regs->sccm   = (QUICC2_SCCE_BSY | QUICC2_SCCE_TX | QUICC2_SCCE_RX);
418
419   /* setup RX buffer descriptors */
420   rxbd = (struct scc_bd *)((char *) QUICC2_VADS_IMM_BASE + RxBD);
421
422   for (i = 0;  i < RxNUM;  i++) {
423     rxbd->ctrl   = QUICC2_BD_CTL_Ready | QUICC2_BD_CTL_Int;
424     rxbd->length = 0;
425     rxbd->buffer = RxBUF;
426
427     RxBUF += RxSIZE;
428     rxbd++;
429   }
430
431   rxbd--;
432   rxbd->ctrl |= QUICC2_BD_CTL_Wrap;  // Last buffer
433
434   /* setup TX buffer descriptors */
435   txbd = (struct scc_bd *)((char *) QUICC2_VADS_IMM_BASE + TxBD);
436
437   for (i = 0;  i < TxNUM;  i++) {
438     txbd->ctrl   = 0;
439     txbd->length = 0;
440     txbd->buffer = TxBUF;
441     TxBUF += TxSIZE;
442     txbd++;
443   }
444
445   txbd--;
446   txbd->ctrl |= QUICC2_BD_CTL_Wrap;  // Last buffer
447   
448   // Issue Init RX & TX Parameters Command 
449   while (IMM->cpm_cpcr & QUICC2_CPCR_READY);
450   IMM->cpm_cpcr = scc_chan->scc_cpcr | QUICC2_CPCR_INIT_TX_RX | QUICC2_CPCR_READY;
451   while (IMM->cpm_cpcr & QUICC2_CPCR_READY);
452
453   return;
454
455 }
456
457 // Function to initialize the device.  Called at bootstrap time.
458 static bool 
459 quicc2_scc_serial_init(struct cyg_devtab_entry *tab)
460 {
461   serial_channel *chan = (serial_channel *)tab->priv;
462   quicc2_scc_serial_info *scc_chan = (quicc2_scc_serial_info *)chan->dev_priv;
463   volatile t_PQ2IMM *IMM = (volatile t_PQ2IMM *) QUICC2_VADS_IMM_BASE;
464   int TxBD, RxBD;
465   static int first_init = 1;
466   int cache_state;
467   
468   HAL_DCACHE_IS_ENABLED(cache_state);
469   HAL_DCACHE_SYNC();
470   HAL_DCACHE_DISABLE();
471
472 #ifdef CYGDBG_IO_INIT
473   diag_printf("QUICC2_SCC SERIAL init - dev: %x\n", 
474               scc_chan->channel);
475 #endif
476     if (first_init) {
477         // Set up tables since many fields are dynamic [computed at runtime]
478         first_init = 0;
479 #ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1
480
481         // Totally reset the CP
482         while (IMM->cpm_cpcr & QUICC2_CPCR_READY);
483         IMM->cpm_cpcr = QUICC2_CPCR_RESET | QUICC2_CPCR_READY;
484         while (IMM->cpm_cpcr & QUICC2_CPCR_READY);
485
486         TxBD = 0x2800;  // Note: this should be configurable
487         RxBD = TxBD + CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_TxNUM*8;
488         quicc2_scc_serial_init_info(&quicc2_scc_serial_info1,
489                                     1, // indicates SCC1
490                                     CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_BRG,
491                                     TxBD, 
492                                     CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_TxNUM,
493                                     CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_TxSIZE,
494                                     ALIGN_TO_CACHELINES(&quicc2_scc1_txbuf[0][0]),
495                                     RxBD, 
496                                     CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_RxNUM,
497                                     CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_RxSIZE,
498                                     ALIGN_TO_CACHELINES(&quicc2_scc1_rxbuf[0][0])
499                                     );
500 #else
501 #ifdef CYGPKG_HAL_POWERPC_MPC8260
502         // Ensure that SCC1 side is initialized first
503         diag_init(); // (pull in constructor that inits diag channel)
504         TxBD = 0x2900;  // Note : this should be inferred from the
505                         // chip state
506 #else
507         // there is no diag device wanting to use the QUICC, so prepare it
508         // for SCC2 use only.
509         while (IMM->cpm_cpcr & QUICC2_CPCR_READY); // Totally reset the CP
510         IMM->cpm_cpcr = QUICC2_CPCR_RESET | QUICC2_CPCR_READY;
511         while (IMM->cpm_cpcr & QUICC2_CPCR_READY);
512         TxBD = 0x2800; // Note: this should be configurable
513 #endif
514 #endif
515 #ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2
516
517         RxBD = TxBD + CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_TxNUM*8;
518         quicc2_scc_serial_init_info(&quicc2_scc_serial_info2,
519                                     2, // indicates SCC2
520                                     CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_BRG,
521                                     TxBD, 
522                                     CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_TxNUM,
523                                     CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_TxSIZE,
524                                     ALIGN_TO_CACHELINES(&quicc2_scc2_txbuf[0][0]),
525                                     RxBD, 
526                                     CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_RxNUM,
527                                     CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_RxSIZE,
528                                     ALIGN_TO_CACHELINES(&quicc2_scc2_rxbuf[0][0])
529             );
530 #endif
531     }
532
533     // Really only required for interrupt driven devices
534     (chan->callbacks->serial_init)(chan);  
535     if (chan->out_cbuf.len != 0) {
536         cyg_drv_interrupt_create(scc_chan->int_vector,
537                                  0, // CYGARC_SIU_PRIORITY_HIGH, - unused 
538                                  (cyg_addrword_t)chan,   //  Data item passed to interrupt handler
539                                  quicc2_scc_serial_ISR,
540                                  quicc2_scc_serial_DSR,
541                                  &scc_chan->serial_interrupt_handle,
542                                  &scc_chan->serial_interrupt);
543         cyg_drv_interrupt_attach(scc_chan->serial_interrupt_handle);
544         cyg_drv_interrupt_acknowledge(scc_chan->int_vector);
545         cyg_drv_interrupt_unmask(scc_chan->int_vector);
546     }
547     quicc2_scc_serial_config_port(chan, &chan->config, true);
548     if (cache_state)
549         HAL_DCACHE_ENABLE();
550     return true;
551 }
552
553 // This routine is called when the device is "looked" up (i.e. attached)
554 static Cyg_ErrNo 
555 quicc2_scc_serial_lookup(struct cyg_devtab_entry **tab, 
556                   struct cyg_devtab_entry *sub_tab,
557                   const char *name)
558 {
559     serial_channel *chan = (serial_channel *)(*tab)->priv;
560     (chan->callbacks->serial_init)(chan);  // Really only required for interrupt driven devices
561     return ENOERR;
562 }
563
564 // Force the current transmit buffer to be sent
565 static void
566 quicc2_scc_serial_flush(quicc2_scc_serial_info *scc_chan)
567 {
568   volatile struct scc_bd *txbd = scc_chan->txbd;
569   int cache_state;
570                                        
571   HAL_DCACHE_IS_ENABLED(cache_state);
572   if (cache_state) {
573     HAL_DCACHE_FLUSH(txbd->buffer, scc_chan->txsize);
574   }
575
576   if ((txbd->length > 0) && 
577       ((txbd->ctrl & (QUICC2_BD_CTL_Ready|QUICC2_BD_CTL_Int)) == 0)) {
578     txbd->ctrl |= QUICC2_BD_CTL_Ready|QUICC2_BD_CTL_Int;  // Signal buffer ready
579     if (txbd->ctrl & QUICC2_BD_CTL_Wrap) {
580       txbd = scc_chan->tbase;
581     } else {
582       txbd++;
583     }
584     scc_chan->txbd = (scc_bd *) txbd;
585   }
586 }
587
588 // Send a character to the device output buffer.
589 // Return 'true' if character is sent to device
590 static bool
591 quicc2_scc_serial_putc(serial_channel *chan, unsigned char c)
592 {
593     quicc2_scc_serial_info *scc_chan = (quicc2_scc_serial_info *)chan->dev_priv;
594     volatile struct scc_bd *txbd, *txfirst;
595     bool res;
596
597     cyg_drv_dsr_lock();  // Avoid race condition testing pointers
598
599     txbd = (scc_bd *)(QUICC2_VADS_IMM_BASE + ((int) scc_chan->scc_pram->tbptr));
600     txfirst = txbd;
601
602     // Scan for a non-busy buffer
603     while (txbd->ctrl & QUICC2_BD_CTL_Ready) {
604       // This buffer is busy, move to next one
605       if (txbd->ctrl & QUICC2_BD_CTL_Wrap) {
606         txbd = scc_chan->tbase;
607       } else {
608         txbd++;
609       }
610       if (txbd == txfirst) break;  // Went all the way around
611     }
612     
613     scc_chan->txbd = (scc_bd *) txbd;
614     if ((txbd->ctrl & (QUICC2_BD_CTL_Ready|QUICC2_BD_CTL_Int)) == 0) {
615       // Transmit buffer is not full/busy
616       txbd->buffer[txbd->length++] = c;
617       if (txbd->length == scc_chan->txsize) {
618         // This buffer is now full, tell SCC to start processing it
619         quicc2_scc_serial_flush(scc_chan);
620       }
621       res = true;
622     } else {
623       // No space
624       res = false;
625     }
626
627     cyg_drv_dsr_unlock();
628     return res;
629 }
630
631 // Fetch a character from the device input buffer, waiting if necessary
632 static unsigned char 
633 quicc2_scc_serial_getc(serial_channel *chan)
634 {
635   unsigned char c;
636   quicc2_scc_serial_info *scc_chan = (quicc2_scc_serial_info *)chan->dev_priv;
637   volatile scc_bd *rxbd = scc_chan->rxbd;
638
639   while ((rxbd->ctrl & QUICC2_BD_CTL_Ready) != 0) ; // WAIT ...
640
641   c = rxbd->buffer[0];
642   rxbd->length = scc_chan->rxsize;
643   rxbd->ctrl |= QUICC2_BD_CTL_Ready;
644   if (rxbd->ctrl & QUICC2_BD_CTL_Wrap) {
645     rxbd = scc_chan->rbase;
646   } else {
647     rxbd++;
648   }
649   scc_chan->rxbd = (scc_bd *) rxbd;
650   return c;
651 }
652
653 // Set up the device characteristics; baud rate, etc.
654 static Cyg_ErrNo
655 quicc2_scc_serial_set_config(serial_channel *chan, cyg_uint32 key,
656                             const void *xbuf, cyg_uint32 *len)
657 {
658   switch (key) {
659   case CYG_IO_SET_CONFIG_SERIAL_INFO:
660     {
661       // FIXME - The documentation says that you can't change the baud rate
662       // again until at least two BRG input clocks have occurred.
663       cyg_serial_info_t *config = (cyg_serial_info_t *)xbuf;
664       if ( *len < sizeof(cyg_serial_info_t) ) {
665         return -EINVAL;
666       }
667       *len = sizeof(cyg_serial_info_t);
668       if ( true != quicc2_scc_serial_config_port(chan, config, false) )
669         return -EINVAL;
670     }
671     break;
672   default:
673     return -EINVAL;
674   }
675   return ENOERR;
676 }
677
678 // Enable the transmitter (interrupt) on the device
679 static void
680 quicc2_scc_serial_start_xmit(serial_channel *chan)
681 {
682   quicc2_scc_serial_info *scc_chan = (quicc2_scc_serial_info *)chan->dev_priv;
683
684   cyg_drv_dsr_lock();
685
686   if (scc_chan->txbd->length == 0) {
687     // See if there is anything to put in this buffer, just to get it going
688     (chan->callbacks->xmt_char)(chan);
689   }
690   if (scc_chan->txbd->length != 0) {
691     // Make sure it gets started
692     quicc2_scc_serial_flush(scc_chan);
693   }
694
695   cyg_drv_dsr_unlock();
696 }
697
698 // Disable the transmitter on the device
699 static void 
700 quicc2_scc_serial_stop_xmit(serial_channel *chan)
701 {
702   quicc2_scc_serial_info *scc_chan = (quicc2_scc_serial_info *)chan->dev_priv;
703   // If anything is in the last buffer, need to get it started
704   if (scc_chan->txbd->length != 0) {
705     quicc2_scc_serial_flush(scc_chan);
706   }
707 }
708
709 // Serial I/O - low level interrupt handler (ISR)
710 static cyg_uint32 
711 quicc2_scc_serial_ISR(cyg_vector_t vector, cyg_addrword_t data)
712 {
713   serial_channel *chan = (serial_channel *)data;
714   quicc2_scc_serial_info *scc_chan = (quicc2_scc_serial_info *)chan->dev_priv;
715   cyg_drv_interrupt_mask(scc_chan->int_vector);
716   return (CYG_ISR_HANDLED|CYG_ISR_CALL_DSR);  // Cause DSR to be run
717 }
718
719 // Serial I/O - high level interrupt handler (DSR)
720 static void       
721 quicc2_scc_serial_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
722 {
723     serial_channel *chan = (serial_channel *)data;
724     quicc2_scc_serial_info *scc_chan = (quicc2_scc_serial_info *)chan->dev_priv;
725     volatile struct scc_regs_8260 *regs = scc_chan->scc_regs;
726     volatile scc_bd *txbd;
727     volatile scc_bd *rxbd = scc_chan->rxbd;
728     scc_bd *rxlast;
729     int i, cache_state;
730
731 #ifdef CYGDBG_DIAG_BUF
732     int _time, _stime;
733     externC cyg_tick_count_t cyg_current_time(void);
734     cyg_drv_isr_lock();
735     enable_diag_uart = 0;
736     HAL_CLOCK_READ(&_time);
737     _stime = (int)cyg_current_time();
738     diag_printf("DSR start - CE: %x, time: %x.%x\n", 
739                regs->scce, _stime, _time);
740     enable_diag_uart = 1;
741 #endif // CYGDBG_DIAG_BUF
742
743     if (regs->scce & QUICC2_SCCE_TX) { // Tx Event
744
745 #ifdef XX_CYGDBG_DIAG_BUF
746       enable_diag_uart = 0;
747       txbd = scc_chan->tbase;
748       for (i = 0;  i < CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_TxNUM;  i++, txbd++) {
749         diag_printf("Tx BD: %x, length: %d, ctl: %x\n", txbd, txbd->length, txbd->ctrl);
750       }
751       enable_diag_uart = 1;
752 #endif // CYGDBG_DIAG_BUF
753
754       regs->scce = QUICC2_SCCE_TX;  // Reset Tx Event
755       txbd = scc_chan->tbase;  // First buffer
756       while (true) {
757         if ((txbd->ctrl & (QUICC2_BD_CTL_Ready|QUICC2_BD_CTL_Int)) == QUICC2_BD_CTL_Int) {
758 #ifdef XX_CYGDBG_DIAG_BUF
759           enable_diag_uart = 0;
760           HAL_CLOCK_READ(&_time);
761           _stime = (int)cyg_current_time();
762           diag_printf("TX Done - Tx: %x, length: %d, time: %x.%x\n", 
763                       txbd, txbd->length, _stime, _time);
764           enable_diag_uart = 1;
765 #endif // CYGDBG_DIAG_BUF
766           txbd->length = 0;
767           txbd->ctrl &= ~QUICC2_BD_CTL_Int;  // Reset interrupt bit
768         }
769
770         if (txbd->ctrl & QUICC2_BD_CTL_Wrap) {
771           txbd = scc_chan->tbase;
772           break;
773         } else {
774           txbd++;
775         }
776       }
777       (chan->callbacks->xmt_char)(chan);
778     }
779
780     while (regs->scce & QUICC2_SCCE_RX) { // Rx Event
781
782       regs->scce = QUICC2_SCCE_RX;  // Reset interrupt state;
783       rxlast = (scc_bd *) ((char *)QUICC2_VADS_IMM_BASE + scc_chan->scc_pram->rbptr );
784
785 #ifdef CYGDBG_DIAG_BUF
786       enable_diag_uart = 0;
787       HAL_CLOCK_READ(&_time);
788       _stime = (int)cyg_current_time();
789       diag_printf("Scan RX - rxbd: %x, rbptr: %x, time: %x.%x\n", 
790                   rxbd, rxlast, _stime, _time);
791 #endif // CYGDBG_DIAG_BUF
792       while (rxbd != rxlast) {
793         if ((rxbd->ctrl & QUICC2_BD_CTL_Ready) == 0) {
794 #ifdef CYGDBG_DIAG_BUF
795           diag_printf("rxbuf: %x, flags: %x, length: %d\n", 
796                       rxbd, rxbd->ctrl, rxbd->length);
797           diag_dump_buf(rxbd->buffer, rxbd->length);
798 #endif // CYGDBG_DIAG_BUF
799
800           for (i = 0;  i < rxbd->length;  i++) {
801             (chan->callbacks->rcv_char)(chan, rxbd->buffer[i]);
802           }
803           // Note: the MBX860 does not seem to snoop/invalidate the data cache properly!
804           HAL_DCACHE_IS_ENABLED(cache_state);
805           if (cache_state) {
806             HAL_DCACHE_INVALIDATE(rxbd->buffer, scc_chan->rxsize);  // Make sure no stale data
807           }
808           
809           rxbd->length = 0;
810           rxbd->ctrl |= QUICC2_BD_CTL_Ready;
811         }
812          
813         if (rxbd->ctrl & QUICC2_BD_CTL_Wrap) {
814           rxbd = scc_chan->rbase;
815         } else {
816           rxbd++;
817         }
818       }
819 #ifdef CYGDBG_DIAG_BUF
820       enable_diag_uart = 1;
821 #endif // CYGDBG_DIAG_BUF
822       scc_chan->rxbd = (scc_bd *) rxbd;
823     }
824
825     if (regs->scce & QUICC2_SCCE_BSY) {
826 #ifdef CYGDBG_DIAG_BUF
827       enable_diag_uart = 0;
828       diag_printf("RX BUSY interrupt\n");
829       enable_diag_uart = 1;
830 #endif // CYGDBG_DIAG_BUF
831       regs->scce = QUICC2_SCCE_BSY;  // Reset interrupt state;
832     }
833 #ifdef CYGDBG_DIAG_BUF
834     enable_diag_uart = 0;
835     HAL_CLOCK_READ(&_time);
836     _stime = (int)cyg_current_time();
837     diag_printf("DSR done - CE: %x, time: %x.%x\n", 
838                 regs->scce, _stime, _time);
839     enable_diag_uart = 1;
840 #endif // CYGDBG_DIAG_BUF
841     cyg_drv_interrupt_acknowledge(scc_chan->int_vector);
842     cyg_drv_interrupt_unmask(scc_chan->int_vector);
843 #ifdef CYGDBG_DIAG_BUF
844     cyg_drv_isr_unlock();
845 #endif // CYGDBG_DIAG_BUF
846 }
847
848 #endif // CYGPKG_IO_SERIAL_POWERPC_QUICC2_SCC
849
850 // ------------------------------------------------------------------------
851 // EOF powerpc/quicc2_scc_serial.c