1 //==========================================================================
3 // io/serial/powerpc/quicc2_scc_serial.c
5 // PowerPC QUICC2 (SCC) Serial I/O Interface Module (interrupt driven)
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
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.
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
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.
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.
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.
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####
45 // Contributors: gthomas
47 // Purpose: QUICC2 SCC Serial I/O module (interrupt driven version)
50 //####DESCRIPTIONEND####
52 //==========================================================================
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
67 #include "quicc2_scc_serial.h"
68 #define QUICC2_VADS_IMM_BASE 0x04700000
69 #define QUICC2_VADS_BCSR_BASE 0x04500000
71 #ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC2_SCC
74 quicc2_scc_serial_init(struct cyg_devtab_entry *tab);
76 quicc2_scc_serial_putc(serial_channel *chan,
79 quicc2_scc_serial_lookup(struct cyg_devtab_entry **tab,
80 struct cyg_devtab_entry *sub_tab,
83 quicc2_scc_serial_getc(serial_channel *chan);
85 quicc2_scc_serial_set_config(serial_channel *chan,
86 cyg_uint32 key, const void *xbuf,
89 quicc2_scc_serial_start_xmit(serial_channel *chan);
91 quicc2_scc_serial_stop_xmit(serial_channel *chan);
94 quicc2_scc_serial_ISR(cyg_vector_t vector,
97 quicc2_scc_serial_DSR(cyg_vector_t vector,
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
109 #ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1
110 static quicc2_scc_serial_info quicc2_scc_serial_info1;
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];
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)
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
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];
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
152 #endif // CYGPKG_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1
154 #ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2
155 static quicc2_scc_serial_info quicc2_scc_serial_info2;
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];
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)
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
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];
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
196 #endif // CYGPKG_IO_SERIAL_POWERPC_QUICC2_SCC
198 #ifdef CYGDBG_DIAG_BUF
199 extern int enable_diag_uart;
200 #endif // CYGDBG_DIAG_BUF
202 // Internal function to actually configure the hardware to
203 // desired baud rate, stop bits and parity ...
205 quicc2_scc_serial_config_port(serial_channel *chan,
206 cyg_serial_info_t *new_config,
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;
212 unsigned long b_rate = select_baud[new_config->baud];
214 if (b_rate == 0) return false;
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);
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);
225 *(scc_chan->brg) = (UART_BIT_RATE(b_rate) << 1) | QUICC2_BRG_EN;
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];
233 // Support fractional stop bits
234 scc_chan->scc_regs->dsr = (new_config->stop & 1) ? QUICC2_SCC_DSR_FULL : QUICC2_SCC_DSR_HALF;
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);
242 scc_chan->scc_regs->gsmr_l |= (QUICC2_SCC_GSMR_L_ENT | QUICC2_SCC_GSMR_L_ENR);
244 if (new_config != &chan->config) {
245 chan->config = *new_config;
250 // Function to set up internal tables for device.
252 quicc2_scc_serial_init_info(quicc2_scc_serial_info *scc_chan,
255 int TxBD, int TxNUM, int TxSIZE,
257 int RxBD, int RxNUM, int RxSIZE,
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;
264 t_UartScc_Pram *uart_pram;
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);
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;
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;
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;
294 // Select the baud rate generator and connect it
295 IMM->cpm_mux_cmxscr &= QUICC2_CMX_SCC1_CLR;
299 scc_chan->brg = &(IMM->brgs_brgc1);
300 IMM->cpm_mux_cmxscr |= QUICC2_CMX_SCC1_BRG1;
303 scc_chan->brg = &(IMM->brgs_brgc2);
304 IMM->cpm_mux_cmxscr |= QUICC2_CMX_SCC1_BRG2;
307 scc_chan->brg = &(IMM->brgs_brgc3);
308 IMM->cpm_mux_cmxscr |= QUICC2_CMX_SCC1_BRG3;
311 scc_chan->brg = &(IMM->brgs_brgc4);
312 IMM->cpm_mux_cmxscr |= QUICC2_CMX_SCC1_BRG4;
315 #ifdef CYGPKG_HAL_POWERPC_VADS
316 // Enable the transciever
317 bcsr->bcsr1 &= ~(QUICC2_BCSR_EN_SCC1);
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;
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;
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;
341 // Select the baud rate generator and connect it
342 IMM->cpm_mux_cmxscr &= QUICC2_CMX_SCC2_CLR;
346 scc_chan->brg = &(IMM->brgs_brgc1);
347 IMM->cpm_mux_cmxscr |= QUICC2_CMX_SCC2_BRG1;
350 scc_chan->brg = &(IMM->brgs_brgc2);
351 IMM->cpm_mux_cmxscr |= QUICC2_CMX_SCC2_BRG2;
354 scc_chan->brg = &(IMM->brgs_brgc3);
355 IMM->cpm_mux_cmxscr |= QUICC2_CMX_SCC2_BRG3;
358 scc_chan->brg = &(IMM->brgs_brgc4);
359 IMM->cpm_mux_cmxscr |= QUICC2_CMX_SCC2_BRG4;
362 #ifdef CYGPKG_HAL_POWERPC_VADS
363 // Enable the transciever
364 bcsr->bcsr1 &= ~(QUICC2_BCSR_EN_SCC2);
369 diag_printf("Incorrect SCC index in quicc2_scc_serial_init_info \n");
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;
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;
387 // Initialize UART PRAM
388 uart_pram = &(scc_chan->scc_pram->SpecificProtocol.u);
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;
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);
419 /* setup RX buffer descriptors */
420 rxbd = (struct scc_bd *)((char *) QUICC2_VADS_IMM_BASE + RxBD);
422 for (i = 0; i < RxNUM; i++) {
423 rxbd->ctrl = QUICC2_BD_CTL_Ready | QUICC2_BD_CTL_Int;
425 rxbd->buffer = RxBUF;
432 rxbd->ctrl |= QUICC2_BD_CTL_Wrap; // Last buffer
434 /* setup TX buffer descriptors */
435 txbd = (struct scc_bd *)((char *) QUICC2_VADS_IMM_BASE + TxBD);
437 for (i = 0; i < TxNUM; i++) {
440 txbd->buffer = TxBUF;
446 txbd->ctrl |= QUICC2_BD_CTL_Wrap; // Last buffer
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);
457 // Function to initialize the device. Called at bootstrap time.
459 quicc2_scc_serial_init(struct cyg_devtab_entry *tab)
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;
465 static int first_init = 1;
468 HAL_DCACHE_IS_ENABLED(cache_state);
470 HAL_DCACHE_DISABLE();
472 #ifdef CYGDBG_IO_INIT
473 diag_printf("QUICC2_SCC SERIAL init - dev: %x\n",
477 // Set up tables since many fields are dynamic [computed at runtime]
479 #ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1
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);
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,
490 CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_BRG,
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]),
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])
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
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
515 #ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2
517 RxBD = TxBD + CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_TxNUM*8;
518 quicc2_scc_serial_init_info(&quicc2_scc_serial_info2,
520 CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_BRG,
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]),
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])
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);
547 quicc2_scc_serial_config_port(chan, &chan->config, true);
553 // This routine is called when the device is "looked" up (i.e. attached)
555 quicc2_scc_serial_lookup(struct cyg_devtab_entry **tab,
556 struct cyg_devtab_entry *sub_tab,
559 serial_channel *chan = (serial_channel *)(*tab)->priv;
560 (chan->callbacks->serial_init)(chan); // Really only required for interrupt driven devices
564 // Force the current transmit buffer to be sent
566 quicc2_scc_serial_flush(quicc2_scc_serial_info *scc_chan)
568 volatile struct scc_bd *txbd = scc_chan->txbd;
571 HAL_DCACHE_IS_ENABLED(cache_state);
573 HAL_DCACHE_FLUSH(txbd->buffer, scc_chan->txsize);
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;
584 scc_chan->txbd = (scc_bd *) txbd;
588 // Send a character to the device output buffer.
589 // Return 'true' if character is sent to device
591 quicc2_scc_serial_putc(serial_channel *chan, unsigned char c)
593 quicc2_scc_serial_info *scc_chan = (quicc2_scc_serial_info *)chan->dev_priv;
594 volatile struct scc_bd *txbd, *txfirst;
597 cyg_drv_dsr_lock(); // Avoid race condition testing pointers
599 txbd = (scc_bd *)(QUICC2_VADS_IMM_BASE + ((int) scc_chan->scc_pram->tbptr));
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;
610 if (txbd == txfirst) break; // Went all the way around
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);
627 cyg_drv_dsr_unlock();
631 // Fetch a character from the device input buffer, waiting if necessary
633 quicc2_scc_serial_getc(serial_channel *chan)
636 quicc2_scc_serial_info *scc_chan = (quicc2_scc_serial_info *)chan->dev_priv;
637 volatile scc_bd *rxbd = scc_chan->rxbd;
639 while ((rxbd->ctrl & QUICC2_BD_CTL_Ready) != 0) ; // WAIT ...
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;
649 scc_chan->rxbd = (scc_bd *) rxbd;
653 // Set up the device characteristics; baud rate, etc.
655 quicc2_scc_serial_set_config(serial_channel *chan, cyg_uint32 key,
656 const void *xbuf, cyg_uint32 *len)
659 case CYG_IO_SET_CONFIG_SERIAL_INFO:
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) ) {
667 *len = sizeof(cyg_serial_info_t);
668 if ( true != quicc2_scc_serial_config_port(chan, config, false) )
678 // Enable the transmitter (interrupt) on the device
680 quicc2_scc_serial_start_xmit(serial_channel *chan)
682 quicc2_scc_serial_info *scc_chan = (quicc2_scc_serial_info *)chan->dev_priv;
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);
690 if (scc_chan->txbd->length != 0) {
691 // Make sure it gets started
692 quicc2_scc_serial_flush(scc_chan);
695 cyg_drv_dsr_unlock();
698 // Disable the transmitter on the device
700 quicc2_scc_serial_stop_xmit(serial_channel *chan)
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);
709 // Serial I/O - low level interrupt handler (ISR)
711 quicc2_scc_serial_ISR(cyg_vector_t vector, cyg_addrword_t data)
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
719 // Serial I/O - high level interrupt handler (DSR)
721 quicc2_scc_serial_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
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;
731 #ifdef CYGDBG_DIAG_BUF
733 externC cyg_tick_count_t cyg_current_time(void);
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
743 if (regs->scce & QUICC2_SCCE_TX) { // Tx Event
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);
751 enable_diag_uart = 1;
752 #endif // CYGDBG_DIAG_BUF
754 regs->scce = QUICC2_SCCE_TX; // Reset Tx Event
755 txbd = scc_chan->tbase; // First buffer
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
767 txbd->ctrl &= ~QUICC2_BD_CTL_Int; // Reset interrupt bit
770 if (txbd->ctrl & QUICC2_BD_CTL_Wrap) {
771 txbd = scc_chan->tbase;
777 (chan->callbacks->xmt_char)(chan);
780 while (regs->scce & QUICC2_SCCE_RX) { // Rx Event
782 regs->scce = QUICC2_SCCE_RX; // Reset interrupt state;
783 rxlast = (scc_bd *) ((char *)QUICC2_VADS_IMM_BASE + scc_chan->scc_pram->rbptr );
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
800 for (i = 0; i < rxbd->length; i++) {
801 (chan->callbacks->rcv_char)(chan, rxbd->buffer[i]);
803 // Note: the MBX860 does not seem to snoop/invalidate the data cache properly!
804 HAL_DCACHE_IS_ENABLED(cache_state);
806 HAL_DCACHE_INVALIDATE(rxbd->buffer, scc_chan->rxsize); // Make sure no stale data
810 rxbd->ctrl |= QUICC2_BD_CTL_Ready;
813 if (rxbd->ctrl & QUICC2_BD_CTL_Wrap) {
814 rxbd = scc_chan->rbase;
819 #ifdef CYGDBG_DIAG_BUF
820 enable_diag_uart = 1;
821 #endif // CYGDBG_DIAG_BUF
822 scc_chan->rxbd = (scc_bd *) rxbd;
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;
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
848 #endif // CYGPKG_IO_SERIAL_POWERPC_QUICC2_SCC
850 // ------------------------------------------------------------------------
851 // EOF powerpc/quicc2_scc_serial.c