1 //==========================================================================
3 // io/serial/powerpc/quicc_smc_serial.c
5 // PowerPC QUICC (SMC/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) 2003 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: QUICC SMC 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/io/devtab.h>
60 #include <cyg/io/serial.h>
61 #include <cyg/infra/diag.h>
62 #include <cyg/hal/hal_cache.h>
63 #include <cyg/hal/quicc/ppc8xx.h>
64 #include CYGBLD_HAL_PLATFORM_H
66 #ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC_SMC
68 #include "quicc_smc_serial.h"
70 typedef struct quicc_sxx_serial_info {
71 CYG_ADDRWORD channel; // Which channel SMCx/SCCx
72 short int_num; // Interrupt number
73 short type; // Channel type - SCC or SMC
74 unsigned long *brg; // Which baud rate generator
75 void *pram; // Parameter RAM pointer
76 void *ctl; // SMC/SCC control registers
77 volatile struct cp_bufdesc *txbd, *rxbd; // Next Tx,Rx descriptor to use
78 struct cp_bufdesc *tbase, *rbase; // First Tx,Rx descriptor
79 int txsize, rxsize; // Length of individual buffers
80 cyg_interrupt serial_interrupt;
81 cyg_handle_t serial_interrupt_handle;
82 } quicc_sxx_serial_info;
84 static bool quicc_sxx_serial_init(struct cyg_devtab_entry *tab);
85 static bool quicc_sxx_serial_putc(serial_channel *chan, unsigned char c);
86 static Cyg_ErrNo quicc_sxx_serial_lookup(struct cyg_devtab_entry **tab,
87 struct cyg_devtab_entry *sub_tab,
89 static unsigned char quicc_sxx_serial_getc(serial_channel *chan);
90 static Cyg_ErrNo quicc_sxx_serial_set_config(serial_channel *chan,
91 cyg_uint32 key, const void *xbuf,
93 static void quicc_sxx_serial_start_xmit(serial_channel *chan);
94 static void quicc_sxx_serial_stop_xmit(serial_channel *chan);
96 static cyg_uint32 quicc_sxx_serial_ISR(cyg_vector_t vector, cyg_addrword_t data);
97 static void quicc_sxx_serial_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data);
99 static SERIAL_FUNS(quicc_sxx_serial_funs,
100 quicc_sxx_serial_putc,
101 quicc_sxx_serial_getc,
102 quicc_sxx_serial_set_config,
103 quicc_sxx_serial_start_xmit,
104 quicc_sxx_serial_stop_xmit
107 #ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC_SMC_SMC1
108 static quicc_sxx_serial_info quicc_sxx_serial_info_smc1 = {
109 QUICC_CPM_SMC1, // Channel indicator
110 CYGNUM_HAL_INTERRUPT_CPM_SMC1, // interrupt
113 #if CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_BUFSIZE > 0
114 static unsigned char quicc_smc_serial_out_buf_smc1[CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_BUFSIZE];
115 static unsigned char quicc_smc_serial_in_buf_smc1[CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_BUFSIZE];
117 static SERIAL_CHANNEL_USING_INTERRUPTS(quicc_sxx_serial_channel_smc1,
118 quicc_sxx_serial_funs,
119 quicc_sxx_serial_info_smc1,
120 CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_BAUD),
121 CYG_SERIAL_STOP_DEFAULT,
122 CYG_SERIAL_PARITY_DEFAULT,
123 CYG_SERIAL_WORD_LENGTH_DEFAULT,
124 CYG_SERIAL_FLAGS_DEFAULT,
125 &quicc_smc_serial_out_buf_smc1[0], sizeof(quicc_smc_serial_out_buf_smc1),
126 &quicc_smc_serial_in_buf_smc1[0], sizeof(quicc_smc_serial_in_buf_smc1)
129 static SERIAL_CHANNEL(quicc_sxx_serial_channel_smc1,
130 quicc_sxx_serial_funs,
131 quicc_sxx_serial_info_smc1,
132 CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_BAUD),
133 CYG_SERIAL_STOP_DEFAULT,
134 CYG_SERIAL_PARITY_DEFAULT,
135 CYG_SERIAL_WORD_LENGTH_DEFAULT,
136 CYG_SERIAL_FLAGS_DEFAULT
140 static unsigned char quicc_smc1_txbuf[CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_TxNUM*CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_TxSIZE] __attribute__((aligned(HAL_DCACHE_LINE_SIZE)));
141 static unsigned char quicc_smc1_rxbuf[CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_RxNUM*CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_RxSIZE] __attribute__((aligned(HAL_DCACHE_LINE_SIZE)));
143 DEVTAB_ENTRY(quicc_smc_serial_io_smc1,
144 CYGDAT_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_NAME,
145 0, // Does not depend on a lower level interface
146 &cyg_io_serial_devio,
147 quicc_sxx_serial_init,
148 quicc_sxx_serial_lookup, // Serial driver may need initializing
149 &quicc_sxx_serial_channel_smc1
151 #endif // CYGPKG_IO_SERIAL_POWERPC_QUICC_SMC_SMC1
153 #ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC_SMC_SMC2
154 static quicc_sxx_serial_info quicc_sxx_serial_info_smc2 = {
155 QUICC_CPM_SMC2, // Channel indicator
156 CYGNUM_HAL_INTERRUPT_CPM_SMC2_PIP, // interrupt
159 #if CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_BUFSIZE > 0
160 static unsigned char quicc_smc_serial_out_buf_smc2[CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_BUFSIZE];
161 static unsigned char quicc_smc_serial_in_buf_smc2[CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_BUFSIZE];
163 static SERIAL_CHANNEL_USING_INTERRUPTS(quicc_sxx_serial_channel_smc2,
164 quicc_sxx_serial_funs,
165 quicc_sxx_serial_info_smc2,
166 CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_BAUD),
167 CYG_SERIAL_STOP_DEFAULT,
168 CYG_SERIAL_PARITY_DEFAULT,
169 CYG_SERIAL_WORD_LENGTH_DEFAULT,
170 CYG_SERIAL_FLAGS_DEFAULT,
171 &quicc_smc_serial_out_buf_smc2[0], sizeof(quicc_smc_serial_out_buf_smc2),
172 &quicc_smc_serial_in_buf_smc2[0], sizeof(quicc_smc_serial_in_buf_smc2)
175 static SERIAL_CHANNEL(quicc_sxx_serial_channel_smc2,
176 quicc_sxx_serial_funs,
177 quicc_sxx_serial_info_smc2,
178 CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_BAUD),
179 CYG_SERIAL_STOP_DEFAULT,
180 CYG_SERIAL_PARITY_DEFAULT,
181 CYG_SERIAL_WORD_LENGTH_DEFAULT,
182 CYG_SERIAL_FLAGS_DEFAULT
185 static unsigned char quicc_smc2_txbuf[CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_TxNUM*CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_TxSIZE] __attribute__((aligned(HAL_DCACHE_LINE_SIZE)));
186 static unsigned char quicc_smc2_rxbuf[CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_RxNUM*CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_RxSIZE] __attribute__((aligned(HAL_DCACHE_LINE_SIZE)));
188 DEVTAB_ENTRY(quicc_smc_serial_io_smc2,
189 CYGDAT_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_NAME,
190 0, // Does not depend on a lower level interface
191 &cyg_io_serial_devio,
192 quicc_sxx_serial_init,
193 quicc_sxx_serial_lookup, // Serial driver may need initializing
194 &quicc_sxx_serial_channel_smc2
196 #endif // CYGPKG_IO_SERIAL_POWERPC_QUICC_SMC_SMC2
198 #ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC_SMC_SCC1
199 static quicc_sxx_serial_info quicc_sxx_serial_info_scc1 = {
200 QUICC_CPM_SCC1, // Channel indicator
201 CYGNUM_HAL_INTERRUPT_CPM_SCC1, // interrupt
204 #if CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC1_BUFSIZE > 0
205 static unsigned char quicc_smc_serial_out_buf_scc1[CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC1_BUFSIZE];
206 static unsigned char quicc_smc_serial_in_buf_scc1[CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC1_BUFSIZE];
208 static SERIAL_CHANNEL_USING_INTERRUPTS(quicc_sxx_serial_channel_scc1,
209 quicc_sxx_serial_funs,
210 quicc_sxx_serial_info_scc1,
211 CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC1_BAUD),
212 CYG_SERIAL_STOP_DEFAULT,
213 CYG_SERIAL_PARITY_DEFAULT,
214 CYG_SERIAL_WORD_LENGTH_DEFAULT,
215 CYG_SERIAL_FLAGS_DEFAULT,
216 &quicc_smc_serial_out_buf_scc1[0], sizeof(quicc_smc_serial_out_buf_scc1),
217 &quicc_smc_serial_in_buf_scc1[0], sizeof(quicc_smc_serial_in_buf_scc1)
220 static SERIAL_CHANNEL(quicc_sxx_serial_channel_scc1,
221 quicc_sxx_serial_funs,
222 quicc_sxx_serial_info_scc1,
223 CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC1_BAUD),
224 CYG_SERIAL_STOP_DEFAULT,
225 CYG_SERIAL_PARITY_DEFAULT,
226 CYG_SERIAL_WORD_LENGTH_DEFAULT,
227 CYG_SERIAL_FLAGS_DEFAULT
230 static unsigned char quicc_scc1_txbuf[CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC1_TxNUM*CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC1_TxSIZE] __attribute__((aligned(HAL_DCACHE_LINE_SIZE)));
231 static unsigned char quicc_scc1_rxbuf[CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC1_RxNUM*CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC1_RxSIZE] __attribute__((aligned(HAL_DCACHE_LINE_SIZE)));
233 DEVTAB_ENTRY(quicc_smc_serial_io_scc1,
234 CYGDAT_IO_SERIAL_POWERPC_QUICC_SMC_SCC1_NAME,
235 0, // Does not depend on a lower level interface
236 &cyg_io_serial_devio,
237 quicc_sxx_serial_init,
238 quicc_sxx_serial_lookup, // Serial driver may need initializing
239 &quicc_sxx_serial_channel_scc1
241 #endif // CYGPKG_IO_SERIAL_POWERPC_QUICC_SMC_SCC1
243 #ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC_SMC_SCC2
244 static quicc_sxx_serial_info quicc_sxx_serial_info_scc2 = {
245 QUICC_CPM_SCC2, // Channel indicator
246 CYGNUM_HAL_INTERRUPT_CPM_SCC2, // interrupt
249 #if CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC2_BUFSIZE > 0
250 static unsigned char quicc_smc_serial_out_buf_scc2[CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC2_BUFSIZE];
251 static unsigned char quicc_smc_serial_in_buf_scc2[CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC2_BUFSIZE];
253 static SERIAL_CHANNEL_USING_INTERRUPTS(quicc_sxx_serial_channel_scc2,
254 quicc_sxx_serial_funs,
255 quicc_sxx_serial_info_scc2,
256 CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC2_BAUD),
257 CYG_SERIAL_STOP_DEFAULT,
258 CYG_SERIAL_PARITY_DEFAULT,
259 CYG_SERIAL_WORD_LENGTH_DEFAULT,
260 CYG_SERIAL_FLAGS_DEFAULT,
261 &quicc_smc_serial_out_buf_scc2[0], sizeof(quicc_smc_serial_out_buf_scc2),
262 &quicc_smc_serial_in_buf_scc2[0], sizeof(quicc_smc_serial_in_buf_scc2)
265 static SERIAL_CHANNEL(quicc_sxx_serial_channel_scc2,
266 quicc_sxx_serial_funs,
267 quicc_sxx_serial_info_scc2,
268 CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC2_BAUD),
269 CYG_SERIAL_STOP_DEFAULT,
270 CYG_SERIAL_PARITY_DEFAULT,
271 CYG_SERIAL_WORD_LENGTH_DEFAULT,
272 CYG_SERIAL_FLAGS_DEFAULT
275 static unsigned char quicc_scc2_txbuf[CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC2_TxNUM*CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC2_TxSIZE] __attribute__((aligned(HAL_DCACHE_LINE_SIZE)));
276 static unsigned char quicc_scc2_rxbuf[CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC2_RxNUM*CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC2_RxSIZE] __attribute__((aligned(HAL_DCACHE_LINE_SIZE)));
278 DEVTAB_ENTRY(quicc_smc_serial_io_scc2,
279 CYGDAT_IO_SERIAL_POWERPC_QUICC_SMC_SCC2_NAME,
280 0, // Does not depend on a lower level interface
281 &cyg_io_serial_devio,
282 quicc_sxx_serial_init,
283 quicc_sxx_serial_lookup, // Serial driver may need initializing
284 &quicc_sxx_serial_channel_scc2
286 #endif // CYGPKG_IO_SERIAL_POWERPC_QUICC_SMC_SCC2
288 #ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC_SMC_SCC3
289 static quicc_sxx_serial_info quicc_sxx_serial_info_scc3 = {
290 QUICC_CPM_SCC3, // Channel indicator
291 CYGNUM_HAL_INTERRUPT_CPM_SCC3, // interrupt
294 #if CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC3_BUFSIZE > 0
295 static unsigned char quicc_smc_serial_out_buf_scc3[CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC3_BUFSIZE];
296 static unsigned char quicc_smc_serial_in_buf_scc3[CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC3_BUFSIZE];
298 static SERIAL_CHANNEL_USING_INTERRUPTS(quicc_sxx_serial_channel_scc3,
299 quicc_sxx_serial_funs,
300 quicc_sxx_serial_info_scc3,
301 CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC3_BAUD),
302 CYG_SERIAL_STOP_DEFAULT,
303 CYG_SERIAL_PARITY_DEFAULT,
304 CYG_SERIAL_WORD_LENGTH_DEFAULT,
305 CYG_SERIAL_FLAGS_DEFAULT,
306 &quicc_smc_serial_out_buf_scc3[0], sizeof(quicc_smc_serial_out_buf_scc3),
307 &quicc_smc_serial_in_buf_scc3[0], sizeof(quicc_smc_serial_in_buf_scc3)
310 static SERIAL_CHANNEL(quicc_sxx_serial_channel_scc3,
311 quicc_sxx_serial_funs,
312 quicc_sxx_serial_info_scc3,
313 CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC3_BAUD),
314 CYG_SERIAL_STOP_DEFAULT,
315 CYG_SERIAL_PARITY_DEFAULT,
316 CYG_SERIAL_WORD_LENGTH_DEFAULT,
317 CYG_SERIAL_FLAGS_DEFAULT
320 static unsigned char quicc_scc3_txbuf[CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC3_TxNUM*CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC3_TxSIZE] __attribute__((aligned(HAL_DCACHE_LINE_SIZE)));
321 static unsigned char quicc_scc3_rxbuf[CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC3_RxNUM*CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC3_RxSIZE] __attribute__((aligned(HAL_DCACHE_LINE_SIZE)));
323 DEVTAB_ENTRY(quicc_smc_serial_io_scc3,
324 CYGDAT_IO_SERIAL_POWERPC_QUICC_SMC_SCC3_NAME,
325 0, // Does not depend on a lower level interface
326 &cyg_io_serial_devio,
327 quicc_sxx_serial_init,
328 quicc_sxx_serial_lookup, // Serial driver may need initializing
329 &quicc_sxx_serial_channel_scc3
331 #endif // CYGPKG_IO_SERIAL_POWERPC_QUICC_SMC_SCC3
333 // Internal function to actually configure the hardware to desired baud rate, etc.
335 quicc_smc_serial_config_port(serial_channel *chan, cyg_serial_info_t *new_config, bool init)
337 quicc_sxx_serial_info *smc_chan = (quicc_sxx_serial_info *)chan->dev_priv;
338 unsigned int baud_divisor = select_baud[new_config->baud];
340 EPPC *eppc = eppc_base();
341 volatile struct smc_regs *ctl = (volatile struct smc_regs *)smc_chan->ctl;
343 if (baud_divisor == 0) return false;
344 // Disable channel during setup
345 ctl->smc_smcmr = QUICC_SMCMR_UART; // Disabled, UART mode
346 HAL_IO_BARRIER(); // Inforce I/O ordering
347 // Disable port interrupts while changing hardware
348 _lcr = smc_select_word_length[new_config->word_length - CYGNUM_SERIAL_WORD_LENGTH_5] |
349 smc_select_stop_bits[new_config->stop] |
350 smc_select_parity[new_config->parity];
351 // Stop transmitter while changing baud rate
352 eppc->cp_cr = smc_chan->channel | QUICC_SMC_CMD_Go | QUICC_SMC_CMD_StopTx;
353 HAL_IO_BARRIER(); // Inforce I/O ordering
354 // Set baud rate generator
355 *smc_chan->brg = 0x10000 | (UART_BITRATE(baud_divisor)<<1);
357 // Enable channel with new configuration
358 ctl->smc_smcmr = QUICC_SMCMR_UART|QUICC_SMCMR_TEN|QUICC_SMCMR_REN|_lcr;
359 HAL_IO_BARRIER(); // Inforce I/O ordering
360 eppc->cp_cr = smc_chan->channel | QUICC_SMC_CMD_Go | QUICC_SMC_CMD_RestartTx;
361 if (new_config != &chan->config) {
362 chan->config = *new_config;
367 // Function to set up internal tables for device.
369 quicc_smc_serial_init_info(quicc_sxx_serial_info *smc_chan,
370 volatile struct smc_uart_pram *uart_pram,
371 volatile struct smc_regs *ctl,
372 int TxBD, int TxNUM, int TxSIZE,
374 int RxBD, int RxNUM, int RxSIZE,
379 EPPC *eppc = eppc_base();
380 struct cp_bufdesc *txbd, *rxbd;
383 smc_chan->pram = (void *)uart_pram;
384 smc_chan->ctl = (void *)ctl;
386 // Set up baud rate generator
387 smc_chan->brg = _mpc8xx_allocate_brg(port);
389 // Disable channel during setup
390 ctl->smc_smcmr = QUICC_SMCMR_UART; // Disabled, UART mode
393 * Set up the PortB pins for UART operation.
394 * Set PAR and DIR to allow SMCTXDx and SMRXDx
397 eppc->pip_pbpar |= portBmask;
398 eppc->pip_pbdir &= ~portBmask;
400 * SDMA & LCD bus request level 5
401 * (Section 16.10.2.1)
405 * Set Rx and Tx function code
406 * (Section 16.15.4.2)
408 uart_pram->rfcr = 0x18;
409 uart_pram->tfcr = 0x18;
411 * Set pointers to buffer descriptors.
412 * (Sections 16.15.4.1, 16.15.7.12, and 16.15.7.13)
414 uart_pram->rbase = RxBD;
415 uart_pram->tbase = TxBD;
416 /* tx and rx buffer descriptors */
417 txbd = (struct cp_bufdesc *)((char *)eppc + TxBD);
418 rxbd = (struct cp_bufdesc *)((char *)eppc + RxBD);
419 smc_chan->txbd = txbd;
420 smc_chan->tbase = txbd;
421 smc_chan->txsize = TxSIZE;
422 smc_chan->rxbd = rxbd;
423 smc_chan->rbase = rxbd;
424 smc_chan->rxsize = RxSIZE;
425 /* max receive buffer length */
426 uart_pram->mrblr = RxSIZE;
427 /* set max_idle feature - generate interrupt after 4 chars idle period */
428 uart_pram->max_idl = 4;
429 /* no last brk char received */
430 uart_pram->brkln = 0;
431 /* no break condition occurred */
432 uart_pram->brkec = 0;
433 /* 1 break char sent on top XMIT */
434 uart_pram->brkcr = 1;
435 /* setup RX buffer descriptors */
436 for (i = 0; i < RxNUM; i++) {
438 rxbd->buffer = RxBUF;
439 rxbd->ctrl = QUICC_BD_CTL_Ready | QUICC_BD_CTL_Int;
440 if (i == (RxNUM-1)) rxbd->ctrl |= QUICC_BD_CTL_Wrap; // Last buffer
444 /* setup TX buffer descriptors */
445 for (i = 0; i < TxNUM; i++) {
447 txbd->buffer = TxBUF;
449 if (i == (TxNUM-1)) txbd->ctrl |= QUICC_BD_CTL_Wrap; // Last buffer
454 * Reset Rx & Tx params
456 HAL_IO_BARRIER(); // Inforce I/O ordering
457 eppc->cp_cr = smc_chan->channel | QUICC_SMC_CMD_Go | QUICC_SMC_CMD_InitTxRx;
458 HAL_IO_BARRIER(); // Inforce I/O ordering
460 * Clear any previous events. Enable interrupts.
461 * (Section 16.15.7.14 and 16.15.7.15)
463 ctl->smc_smce = 0xFF;
464 ctl->smc_smcm = QUICC_SMCE_BSY|QUICC_SMCE_TX|QUICC_SMCE_RX;
467 // Internal function to actually configure the hardware to desired baud rate, etc.
469 quicc_scc_serial_config_port(serial_channel *chan, cyg_serial_info_t *new_config, bool init)
471 quicc_sxx_serial_info *scc_chan = (quicc_sxx_serial_info *)chan->dev_priv;
472 unsigned int baud_divisor = select_baud[new_config->baud];
473 EPPC *eppc = eppc_base();
474 volatile struct scc_regs *regs = (volatile struct scc_regs *)scc_chan->ctl;
476 if (baud_divisor == 0) return false;
477 // Set baud rate generator
478 *scc_chan->brg = 0x10000 | (UART_BITRATE(baud_divisor)<<1);
479 // Disable channel during setup
480 HAL_IO_BARRIER(); // Inforce I/O ordering
481 regs->scc_gsmr_l = 0;
482 regs->scc_psmr = QUICC_SCC_PSMR_ASYNC |
483 scc_select_word_length[new_config->word_length - CYGNUM_SERIAL_WORD_LENGTH_5] |
484 scc_select_stop_bits[new_config->stop] |
485 scc_select_parity[new_config->parity];
487 // Enable channel with new configuration
488 regs->scc_gsmr_h = 0x20; // 8bit FIFO
489 regs->scc_gsmr_l = 0x00028004; // 16x TxCLK, 16x RxCLK, UART
492 * Init Rx & Tx params for SCCX
494 HAL_IO_BARRIER(); // Inforce I/O ordering
495 eppc->cp_cr = QUICC_CPM_CR_INIT_TXRX | scc_chan->channel | QUICC_CPM_CR_BUSY;
497 HAL_IO_BARRIER(); // Inforce I/O ordering
498 regs->scc_gsmr_l |= (QUICC_SCC_GSMR_L_Tx | QUICC_SCC_GSMR_L_Rx); // Enable Rx, Tx
499 if (new_config != &chan->config) {
500 chan->config = *new_config;
505 // Function to set up internal tables for device.
507 quicc_scc_serial_init_info(quicc_sxx_serial_info *scc_chan,
508 volatile struct uart_pram *uart_pram,
509 volatile struct scc_regs *ctl,
510 int TxBD, int TxNUM, int TxSIZE,
512 int RxBD, int RxNUM, int RxSIZE,
514 int portAmask, int portBmask, int portCmask,
517 EPPC *eppc = eppc_base();
518 struct cp_bufdesc *txbd, *rxbd;
521 // Disable channel during setup
523 scc_chan->pram = (void *)uart_pram;
524 scc_chan->ctl = (void *)ctl;
526 // Set up baud rate generator
527 scc_chan->brg = _mpc8xx_allocate_brg(port);
530 * Set up the PortA/B/C pins for UART operation.
532 eppc->pio_papar |= portAmask;
533 eppc->pio_padir &= ~portAmask;
534 eppc->pio_paodr &= ~portAmask;
536 eppc->pio_pcdir &= portCmask;
537 eppc->pio_pcpar &= portCmask;
538 eppc->pio_pcso |= portCmask;
540 eppc->pip_pbpar |= portBmask;
541 eppc->pip_pbdir |= portBmask;
544 * SDMA & LCD bus request level 5
545 * (Section 16.10.2.1)
549 * Set Rx and Tx function code
550 * (Section 16.15.4.2)
552 uart_pram->rfcr = 0x18;
553 uart_pram->tfcr = 0x18;
555 * Set pointers to buffer descriptors.
556 * (Sections 16.15.4.1, 16.15.7.12, and 16.15.7.13)
558 uart_pram->rbase = RxBD;
559 uart_pram->tbase = TxBD;
560 /* tx and rx buffer descriptors */
561 txbd = (struct cp_bufdesc *)((char *)eppc + TxBD);
562 rxbd = (struct cp_bufdesc *)((char *)eppc + RxBD);
563 scc_chan->txbd = txbd;
564 scc_chan->tbase = txbd;
565 scc_chan->txsize = TxSIZE;
566 scc_chan->rxbd = rxbd;
567 scc_chan->rbase = rxbd;
568 scc_chan->rxsize = RxSIZE;
569 /* max receive buffer length */
570 uart_pram->mrblr = RxSIZE;
571 /* set max_idle feature - generate interrupt after 4 chars idle period */
572 uart_pram->max_idl = 4;
573 /* no last brk char received */
574 uart_pram->brkln = 0;
575 /* no break condition occurred */
576 uart_pram->brkec = 0;
577 /* 1 break char sent on top XMIT */
578 uart_pram->brkcr = 1;
580 uart_pram->rccm = 0xC0FF;
581 /* control characters */
582 for (i = 0; i < 8; i++) {
583 uart_pram->cc[i] = 0x8000; // Mark unused
585 /* setup RX buffer descriptors */
586 for (i = 0; i < RxNUM; i++) {
588 rxbd->buffer = RxBUF;
589 rxbd->ctrl = QUICC_BD_CTL_Ready | QUICC_BD_CTL_Int;
590 if (i == (RxNUM-1)) rxbd->ctrl |= QUICC_BD_CTL_Wrap; // Last buffer
594 /* setup TX buffer descriptors */
595 for (i = 0; i < TxNUM; i++) {
597 txbd->buffer = TxBUF;
599 if (i == (TxNUM-1)) txbd->ctrl |= QUICC_BD_CTL_Wrap; // Last buffer
604 * Reset Rx & Tx params
606 HAL_IO_BARRIER(); // Inforce I/O ordering
607 eppc->cp_cr = scc_chan->channel | QUICC_SMC_CMD_Go | QUICC_SMC_CMD_InitTxRx;
609 * Clear any previous events. Enable interrupts.
610 * (Section 16.15.7.14 and 16.15.7.15)
612 HAL_IO_BARRIER(); // Inforce I/O ordering
613 ctl->scc_scce = 0xFFFF;
614 ctl->scc_sccm = (QUICC_SCCE_BSY | QUICC_SCCE_TX | QUICC_SCCE_RX);
617 // Function to initialize the device. Called at bootstrap time.
619 quicc_sxx_serial_init(struct cyg_devtab_entry *tab)
621 serial_channel *chan = (serial_channel *)tab->priv;
622 quicc_sxx_serial_info *smc_chan = (quicc_sxx_serial_info *)chan->dev_priv;
623 volatile EPPC *eppc = (volatile EPPC *)eppc_base();
627 HAL_DCACHE_IS_ENABLED(cache_state);
629 HAL_DCACHE_DISABLE();
630 #ifdef CYGDBG_IO_INIT
631 diag_printf("QUICC_SMC SERIAL init - dev: %x.%d = %s\n", smc_chan->channel, smc_chan->int_num, tab->name);
633 #ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC_SMC_SMC1
634 if (chan == &quicc_sxx_serial_channel_smc1) {
635 TxBD = _mpc8xx_allocBd(sizeof(struct cp_bufdesc)*CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_TxNUM);
636 RxBD = _mpc8xx_allocBd(sizeof(struct cp_bufdesc)*CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_RxNUM);
637 quicc_smc_serial_init_info(&quicc_sxx_serial_info_smc1,
638 &eppc->pram[2].scc.pothers.smc_modem.psmc.u, // PRAM
639 &eppc->smc_regs[0], // Control registers
641 CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_TxNUM,
642 CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_TxSIZE,
643 &quicc_smc1_txbuf[0],
645 CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_RxNUM,
646 CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_RxSIZE,
647 &quicc_smc1_rxbuf[0],
653 #ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC_SMC_SMC2
654 if (chan == &quicc_sxx_serial_channel_smc2) {
655 TxBD = _mpc8xx_allocBd(sizeof(struct cp_bufdesc)*CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_TxNUM);
656 RxBD = _mpc8xx_allocBd(sizeof(struct cp_bufdesc)*CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_RxNUM);
657 quicc_smc_serial_init_info(&quicc_sxx_serial_info_smc2,
658 &eppc->pram[3].scc.pothers.smc_modem.psmc.u, // PRAM
659 &eppc->smc_regs[1], // Control registers
661 CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_TxNUM,
662 CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_TxSIZE,
663 &quicc_smc2_txbuf[0],
665 CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_RxNUM,
666 CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_RxSIZE,
667 &quicc_smc2_rxbuf[0],
673 #ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC_SMC_SCC1
674 if (chan == &quicc_sxx_serial_channel_scc1) {
675 TxBD = _mpc8xx_allocBd(sizeof(struct cp_bufdesc)*CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC1_TxNUM);
676 RxBD = _mpc8xx_allocBd(sizeof(struct cp_bufdesc)*CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC1_RxNUM);
677 quicc_scc_serial_init_info(&quicc_sxx_serial_info_scc1,
678 &eppc->pram[0].scc.pscc.u, // PRAM
679 &eppc->scc_regs[0], // Control registersn
681 CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC1_TxNUM,
682 CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC1_TxSIZE,
683 &quicc_scc1_txbuf[0],
685 CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC1_RxNUM,
686 CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC1_RxSIZE,
687 &quicc_scc1_rxbuf[0],
688 0x0003, // PortA mask
689 0x1000, // PortB mask
690 0x0800, // PortC mask
695 #ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC_SMC_SCC2
696 if (chan == &quicc_sxx_serial_channel_scc2) {
697 TxBD = _mpc8xx_allocBd(sizeof(struct cp_bufdesc)*CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC2_TxNUM);
698 RxBD = _mpc8xx_allocBd(sizeof(struct cp_bufdesc)*CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC2_RxNUM);
699 quicc_scc_serial_init_info(&quicc_sxx_serial_info_scc2,
700 &eppc->pram[1].scc.pscc.u, // PRAM
701 &eppc->scc_regs[1], // Control registersn
703 CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC2_TxNUM,
704 CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC2_TxSIZE,
705 &quicc_scc2_txbuf[0],
707 CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC2_RxNUM,
708 CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC2_RxSIZE,
709 &quicc_scc2_rxbuf[0],
710 0x000C, // PortA mask
711 0x2000, // PortB mask
712 0x0C00, // PortC mask
717 #ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC_SMC_SCC3
718 if (chan == &quicc_sxx_serial_channel_scc3) {
719 TxBD = _mpc8xx_allocBd(sizeof(struct cp_bufdesc)*CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC3_TxNUM);
720 RxBD = _mpc8xx_allocBd(sizeof(struct cp_bufdesc)*CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC3_RxNUM);
721 quicc_scc_serial_init_info(&quicc_sxx_serial_info_scc3,
722 &eppc->pram[2].scc.pscc.u, // PRAM
723 &eppc->scc_regs[2], // Control registersn
725 CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC3_TxNUM,
726 CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC3_TxSIZE,
727 &quicc_scc3_txbuf[0],
729 CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC3_RxNUM,
730 CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC3_RxSIZE,
731 &quicc_scc3_rxbuf[0],
732 #if defined(CYGHWR_HAL_POWERPC_MPC8XX_850)
733 0x0000, // PortA mask
734 0x00C0, // PortB mask
735 0x0000, // PortC mask
736 #elif defined(CYGHWR_HAL_POWERPC_MPC8XX_852T)
737 0x0030, // PortA mask
738 0x0000, // PortB mask
739 0x0000, // PortC mask
740 #elif defined(CYGHWR_HAL_POWERPC_MPC8XX_823)
741 0x0000, // PortA mask
742 0x00C0, // PortB mask
743 0x0000, // PortC mask
745 #error "Cannot route SCC3"
751 (chan->callbacks->serial_init)(chan); // Really only required for interrupt driven devices
752 if (chan->out_cbuf.len != 0) {
753 cyg_drv_interrupt_create(smc_chan->int_num,
754 CYGARC_SIU_PRIORITY_HIGH, // Priority - unused (but asserted)
755 (cyg_addrword_t)chan, // Data item passed to interrupt handler
756 quicc_sxx_serial_ISR,
757 quicc_sxx_serial_DSR,
758 &smc_chan->serial_interrupt_handle,
759 &smc_chan->serial_interrupt);
760 cyg_drv_interrupt_attach(smc_chan->serial_interrupt_handle);
761 cyg_drv_interrupt_unmask(smc_chan->int_num);
763 if (smc_chan->type == _SMC_CHAN) {
764 quicc_smc_serial_config_port(chan, &chan->config, true);
766 quicc_scc_serial_config_port(chan, &chan->config, true);
773 // This routine is called when the device is "looked" up (i.e. attached)
775 quicc_sxx_serial_lookup(struct cyg_devtab_entry **tab,
776 struct cyg_devtab_entry *sub_tab,
779 serial_channel *chan = (serial_channel *)(*tab)->priv;
780 (chan->callbacks->serial_init)(chan); // Really only required for interrupt driven devices
784 // Force the current transmit buffer to be sent
786 quicc_sxx_serial_flush(quicc_sxx_serial_info *smc_chan)
788 volatile struct cp_bufdesc *txbd = smc_chan->txbd;
791 HAL_DCACHE_IS_ENABLED(cache_state);
793 HAL_DCACHE_FLUSH(txbd->buffer, smc_chan->txsize);
795 if ((txbd->length > 0) &&
796 ((txbd->ctrl & (QUICC_BD_CTL_Ready|QUICC_BD_CTL_Int)) == 0)) {
797 txbd->ctrl |= QUICC_BD_CTL_Ready|QUICC_BD_CTL_Int; // Signal buffer ready
798 if (txbd->ctrl & QUICC_BD_CTL_Wrap) {
799 txbd = smc_chan->tbase;
803 smc_chan->txbd = txbd;
807 // Send a character to the device output buffer.
808 // Return 'true' if character is sent to device
810 quicc_sxx_serial_putc(serial_channel *chan, unsigned char c)
812 quicc_sxx_serial_info *smc_chan = (quicc_sxx_serial_info *)chan->dev_priv;
813 volatile struct cp_bufdesc *txbd, *txfirst;
814 volatile struct smc_uart_pram *pram = (volatile struct smc_uart_pram *)smc_chan->pram;
815 EPPC *eppc = eppc_base();
818 cyg_drv_dsr_lock(); // Avoid race condition testing pointers
819 txbd = (struct cp_bufdesc *)((char *)eppc + pram->tbptr);
821 // Scan for a non-busy buffer
822 while (txbd->ctrl & QUICC_BD_CTL_Ready) {
823 // This buffer is busy, move to next one
824 if (txbd->ctrl & QUICC_BD_CTL_Wrap) {
825 txbd = smc_chan->tbase;
829 if (txbd == txfirst) break; // Went all the way around
831 smc_chan->txbd = txbd;
832 if ((txbd->ctrl & (QUICC_BD_CTL_Ready|QUICC_BD_CTL_Int)) == 0) {
833 // Transmit buffer is not full/busy
834 txbd->buffer[txbd->length++] = c;
835 if (txbd->length == smc_chan->txsize) {
836 // This buffer is now full, tell SMC to start processing it
837 quicc_sxx_serial_flush(smc_chan);
844 cyg_drv_dsr_unlock();
848 // Fetch a character from the device input buffer, waiting if necessary
850 quicc_sxx_serial_getc(serial_channel *chan)
853 quicc_sxx_serial_info *smc_chan = (quicc_sxx_serial_info *)chan->dev_priv;
854 volatile struct cp_bufdesc *rxbd = smc_chan->rxbd;
856 while ((rxbd->ctrl & QUICC_BD_CTL_Ready) != 0) ;
858 rxbd->length = smc_chan->rxsize;
859 rxbd->ctrl |= QUICC_BD_CTL_Ready;
860 if (rxbd->ctrl & QUICC_BD_CTL_Wrap) {
861 rxbd = smc_chan->rbase;
865 smc_chan->rxbd = (struct cp_bufdesc *)rxbd;
869 // Set up the device characteristics; baud rate, etc.
871 quicc_sxx_serial_set_config(serial_channel *chan, cyg_uint32 key,
872 const void *xbuf, cyg_uint32 *len)
877 case CYG_IO_SET_CONFIG_SERIAL_INFO:
879 // FIXME - The documentation says that you can't change the baud rate
880 // again until at least two BRG input clocks have occurred.
881 cyg_serial_info_t *config = (cyg_serial_info_t *)xbuf;
882 quicc_sxx_serial_info *smc_chan = (quicc_sxx_serial_info *)chan->dev_priv;
883 if ( *len < sizeof(cyg_serial_info_t) ) {
886 *len = sizeof(cyg_serial_info_t);
887 if (smc_chan->type == _SMC_CHAN) {
888 res = quicc_smc_serial_config_port(chan, config, true);
890 res = quicc_scc_serial_config_port(chan, config, true);
902 // Enable the transmitter (interrupt) on the device
904 quicc_sxx_serial_start_xmit(serial_channel *chan)
906 quicc_sxx_serial_info *smc_chan = (quicc_sxx_serial_info *)chan->dev_priv;
908 if (smc_chan->txbd->length == 0) {
909 // See if there is anything to put in this buffer, just to get it going
910 (chan->callbacks->xmt_char)(chan);
912 if (smc_chan->txbd->length != 0) {
913 // Make sure it gets started
914 quicc_sxx_serial_flush(smc_chan);
916 cyg_drv_dsr_unlock();
919 // Disable the transmitter on the device
921 quicc_sxx_serial_stop_xmit(serial_channel *chan)
923 quicc_sxx_serial_info *smc_chan = (quicc_sxx_serial_info *)chan->dev_priv;
924 // If anything is in the last buffer, need to get it started
925 if (smc_chan->txbd->length != 0) {
926 quicc_sxx_serial_flush(smc_chan);
930 // Serial I/O - low level interrupt handler (ISR)
932 quicc_sxx_serial_ISR(cyg_vector_t vector, cyg_addrword_t data)
934 serial_channel *chan = (serial_channel *)data;
935 quicc_sxx_serial_info *smc_chan = (quicc_sxx_serial_info *)chan->dev_priv;
936 cyg_drv_interrupt_mask(smc_chan->int_num);
937 return (CYG_ISR_HANDLED|CYG_ISR_CALL_DSR); // Cause DSR to be run
940 // Serial I/O - high level interrupt handler (DSR)
942 quicc_smc_serial_DSR(serial_channel *chan)
944 quicc_sxx_serial_info *smc_chan = (quicc_sxx_serial_info *)chan->dev_priv;
945 volatile struct smc_regs *ctl = (volatile struct smc_regs *)smc_chan->ctl;
946 volatile struct cp_bufdesc *txbd;
947 volatile struct cp_bufdesc *rxbd = smc_chan->rxbd;
948 volatile struct smc_uart_pram *pram = (volatile struct smc_uart_pram *)smc_chan->pram;
949 struct cp_bufdesc *rxlast;
952 if (ctl->smc_smce & QUICC_SMCE_TX) {
953 // Transmit interrupt
954 ctl->smc_smce = QUICC_SMCE_TX; // Reset interrupt state;
955 txbd = smc_chan->tbase; // First buffer
957 if ((txbd->ctrl & (QUICC_BD_CTL_Ready|QUICC_BD_CTL_Int)) == QUICC_BD_CTL_Int) {
959 txbd->ctrl &= ~QUICC_BD_CTL_Int; // Reset interrupt bit
961 if (txbd->ctrl & QUICC_BD_CTL_Wrap) {
962 txbd = smc_chan->tbase;
968 (chan->callbacks->xmt_char)(chan);
970 while (ctl->smc_smce & QUICC_SMCE_RX) {
972 ctl->smc_smce = QUICC_SMCE_RX; // Reset interrupt state;
973 rxlast = (struct cp_bufdesc *) (
974 (char *)eppc_base() + pram->rbptr );
975 while (rxbd != rxlast) {
976 if ((rxbd->ctrl & QUICC_BD_CTL_Ready) == 0) {
977 for (i = 0; i < rxbd->length; i++) {
978 (chan->callbacks->rcv_char)(chan, rxbd->buffer[i]);
980 // Note: the MBX860 does not seem to snoop/invalidate the data cache properly!
981 HAL_DCACHE_IS_ENABLED(cache_state);
983 HAL_DCACHE_INVALIDATE(rxbd->buffer, smc_chan->rxsize); // Make sure no stale data
986 rxbd->ctrl |= QUICC_BD_CTL_Ready;
988 if (rxbd->ctrl & QUICC_BD_CTL_Wrap) {
989 rxbd = smc_chan->rbase;
994 smc_chan->rxbd = (struct cp_bufdesc *)rxbd;
996 if (ctl->smc_smce & QUICC_SMCE_BSY) {
997 ctl->smc_smce = QUICC_SMCE_BSY; // Reset interrupt state;
999 cyg_drv_interrupt_acknowledge(smc_chan->int_num);
1000 cyg_drv_interrupt_unmask(smc_chan->int_num);
1004 quicc_scc_serial_DSR(serial_channel *chan)
1006 quicc_sxx_serial_info *smc_chan = (quicc_sxx_serial_info *)chan->dev_priv;
1007 volatile struct scc_regs *ctl = (volatile struct scc_regs *)smc_chan->ctl;
1008 volatile struct cp_bufdesc *txbd;
1009 volatile struct cp_bufdesc *rxbd = smc_chan->rxbd;
1010 volatile struct uart_pram *pram = (volatile struct uart_pram *)smc_chan->pram;
1011 struct cp_bufdesc *rxlast;
1014 if (ctl->scc_scce & QUICC_SCCE_TX) {
1015 // Transmit interrupt
1016 ctl->scc_scce = QUICC_SCCE_TX; // Reset interrupt state;
1017 txbd = smc_chan->tbase; // First buffer
1019 if ((txbd->ctrl & (QUICC_BD_CTL_Ready|QUICC_BD_CTL_Int)) == QUICC_BD_CTL_Int) {
1021 txbd->ctrl &= ~QUICC_BD_CTL_Int; // Reset interrupt bit
1023 if (txbd->ctrl & QUICC_BD_CTL_Wrap) {
1024 txbd = smc_chan->tbase;
1030 (chan->callbacks->xmt_char)(chan);
1032 while (ctl->scc_scce & QUICC_SCCE_RX) {
1033 // Receive interrupt
1034 ctl->scc_scce = QUICC_SCCE_RX; // Reset interrupt state;
1035 rxlast = (struct cp_bufdesc *) ((char *)eppc_base() + pram->rbptr);
1036 while (rxbd != rxlast) {
1037 if ((rxbd->ctrl & QUICC_BD_CTL_Ready) == 0) {
1038 for (i = 0; i < rxbd->length; i++) {
1039 (chan->callbacks->rcv_char)(chan, rxbd->buffer[i]);
1041 // Note: the MBX860 does not seem to snoop/invalidate the data cache properly!
1042 HAL_DCACHE_IS_ENABLED(cache_state);
1044 HAL_DCACHE_INVALIDATE(rxbd->buffer, smc_chan->rxsize); // Make sure no stale data
1047 rxbd->ctrl |= QUICC_BD_CTL_Ready;
1049 if (rxbd->ctrl & QUICC_BD_CTL_Wrap) {
1050 rxbd = smc_chan->rbase;
1055 smc_chan->rxbd = (struct cp_bufdesc *)rxbd;
1057 if (ctl->scc_scce & QUICC_SCCE_BSY) {
1058 ctl->scc_scce = QUICC_SCCE_BSY; // Reset interrupt state;
1060 cyg_drv_interrupt_acknowledge(smc_chan->int_num);
1061 cyg_drv_interrupt_unmask(smc_chan->int_num);
1065 quicc_sxx_serial_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
1067 serial_channel *chan = (serial_channel *)data;
1068 quicc_sxx_serial_info *smc_chan = (quicc_sxx_serial_info *)chan->dev_priv;
1070 if (smc_chan->type == _SMC_CHAN) {
1071 quicc_smc_serial_DSR(chan);
1073 quicc_scc_serial_DSR(chan);
1078 show_rxbd(int dump_all)
1080 #ifdef CYGDBG_DIAG_BUF
1081 EPPC *eppc = eppc_base();
1082 struct smc_uart_pram *pram = &eppc->pram[2].scc.pothers.smc_modem.psmc.u;
1083 struct cp_bufdesc *rxbd = (struct cp_bufdesc *)((char *)eppc+pram->rbase);
1084 int _enable = enable_diag_uart;
1085 enable_diag_uart = 0;
1087 diag_printf("SMC Mask: %x, Events: %x, Rbase: %x, Rbptr: %x\n",
1088 eppc->smc_regs[0].smc_smcm, eppc->smc_regs[0].smc_smce,
1089 pram->rbase, pram->rbptr);
1091 diag_printf("Rx BD: %x, ctl: %x, length: %d\n", rxbd, rxbd->ctrl, rxbd->length);
1092 if (rxbd->ctrl & QUICC_BD_CTL_Wrap) break;
1096 enable_diag_uart = _enable;
1097 if (dump_all) dump_diag_buf();
1098 #endif // CYGDBG_DIAG_BUF
1100 #endif // CYGPKG_IO_SERIAL_POWERPC_QUICC_SMC
1102 // ------------------------------------------------------------------------
1103 // EOF powerpc/quicc_smc_serial.c