1 //==========================================================================
3 // io/serial/powerpc/mpc8xxx_serial.c
5 // PowerPC MPC8XXX (QUICC-II) (SMC/SCC) Serial I/O Interface Module
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: MPC8XXX Serial I/O module
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/mpc8xxx.h>
64 #include CYGBLD_HAL_PLATFORM_H
66 #include "mpc8xxx_serial.h"
68 typedef struct mpc8xxx_sxx_serial_info {
69 CYG_ADDRWORD channel; // Which channel SMCx/SCCx
70 short int_num; // Interrupt number
71 short type; // Channel type - SCC or SMC
72 unsigned long *brg; // Which baud rate generator
73 void *pram; // Parameter RAM pointer
74 void *ctl; // SMC/SCC control registers
75 volatile struct cp_bufdesc *txbd, *rxbd; // Next Tx,Rx descriptor to use
76 struct cp_bufdesc *tbase, *rbase; // First Tx,Rx descriptor
77 int txsize, rxsize; // Length of individual buffers
78 cyg_interrupt serial_interrupt;
79 cyg_handle_t serial_interrupt_handle;
80 } mpc8xxx_sxx_serial_info;
82 static bool mpc8xxx_sxx_serial_init(struct cyg_devtab_entry *tab);
83 static bool mpc8xxx_sxx_serial_putc(serial_channel *chan, unsigned char c);
84 static Cyg_ErrNo mpc8xxx_sxx_serial_lookup(struct cyg_devtab_entry **tab,
85 struct cyg_devtab_entry *sub_tab,
87 static unsigned char mpc8xxx_sxx_serial_getc(serial_channel *chan);
88 static Cyg_ErrNo mpc8xxx_sxx_serial_set_config(serial_channel *chan,
89 cyg_uint32 key, const void *xbuf,
91 static void mpc8xxx_sxx_serial_start_xmit(serial_channel *chan);
92 static void mpc8xxx_sxx_serial_stop_xmit(serial_channel *chan);
94 static cyg_uint32 mpc8xxx_sxx_serial_ISR(cyg_vector_t vector, cyg_addrword_t data);
95 static void mpc8xxx_sxx_serial_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data);
97 static SERIAL_FUNS(mpc8xxx_sxx_serial_funs,
98 mpc8xxx_sxx_serial_putc,
99 mpc8xxx_sxx_serial_getc,
100 mpc8xxx_sxx_serial_set_config,
101 mpc8xxx_sxx_serial_start_xmit,
102 mpc8xxx_sxx_serial_stop_xmit
105 #ifdef CYGPKG_IO_SERIAL_POWERPC_MPC8XXX_SMC1
106 static mpc8xxx_sxx_serial_info mpc8xxx_sxx_serial_info_smc1 = {
107 SMC1_PAGE_SUBBLOCK, // Channel indicator
108 CYGNUM_HAL_INTERRUPT_SMC1, // interrupt
111 #if CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SMC1_BUFSIZE > 0
112 static unsigned char mpc8xxx_smc_serial_out_buf_smc1[CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SMC1_BUFSIZE];
113 static unsigned char mpc8xxx_smc_serial_in_buf_smc1[CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SMC1_BUFSIZE];
115 static SERIAL_CHANNEL_USING_INTERRUPTS(mpc8xxx_sxx_serial_channel_smc1,
116 mpc8xxx_sxx_serial_funs,
117 mpc8xxx_sxx_serial_info_smc1,
118 CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SMC1_BAUD),
119 CYG_SERIAL_STOP_DEFAULT,
120 CYG_SERIAL_PARITY_DEFAULT,
121 CYG_SERIAL_WORD_LENGTH_DEFAULT,
122 CYG_SERIAL_FLAGS_DEFAULT,
123 &mpc8xxx_smc_serial_out_buf_smc1[0], sizeof(mpc8xxx_smc_serial_out_buf_smc1),
124 &mpc8xxx_smc_serial_in_buf_smc1[0], sizeof(mpc8xxx_smc_serial_in_buf_smc1)
127 static SERIAL_CHANNEL(mpc8xxx_sxx_serial_channel_smc1,
128 mpc8xxx_sxx_serial_funs,
129 mpc8xxx_sxx_serial_info_smc1,
130 CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SMC1_BAUD),
131 CYG_SERIAL_STOP_DEFAULT,
132 CYG_SERIAL_PARITY_DEFAULT,
133 CYG_SERIAL_WORD_LENGTH_DEFAULT,
134 CYG_SERIAL_FLAGS_DEFAULT
138 static unsigned char mpc8xxx_smc1_txbuf[CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SMC1_TxNUM*CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SMC1_TxSIZE] __attribute__((aligned(HAL_DCACHE_LINE_SIZE)));
139 static unsigned char mpc8xxx_smc1_rxbuf[CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SMC1_RxNUM*CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SMC1_RxSIZE] __attribute__((aligned(HAL_DCACHE_LINE_SIZE)));
141 DEVTAB_ENTRY(mpc8xxx_smc_serial_io_smc1,
142 CYGDAT_IO_SERIAL_POWERPC_MPC8XXX_SMC1_NAME,
143 0, // Does not depend on a lower level interface
144 &cyg_io_serial_devio,
145 mpc8xxx_sxx_serial_init,
146 mpc8xxx_sxx_serial_lookup, // Serial driver may need initializing
147 &mpc8xxx_sxx_serial_channel_smc1
149 #endif // CYGPKG_IO_SERIAL_POWERPC_MPC8XXX_SMC1
151 #ifdef CYGPKG_IO_SERIAL_POWERPC_MPC8XXX_SMC2
152 static mpc8xxx_sxx_serial_info mpc8xxx_sxx_serial_info_smc2 = {
153 SMC2_PAGE_SUBBLOCK, // Channel indicator
154 CYGNUM_HAL_INTERRUPT_SMC2, // interrupt
157 #if CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SMC2_BUFSIZE > 0
158 static unsigned char mpc8xxx_smc_serial_out_buf_smc2[CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SMC2_BUFSIZE];
159 static unsigned char mpc8xxx_smc_serial_in_buf_smc2[CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SMC2_BUFSIZE];
161 static SERIAL_CHANNEL_USING_INTERRUPTS(mpc8xxx_sxx_serial_channel_smc2,
162 mpc8xxx_sxx_serial_funs,
163 mpc8xxx_sxx_serial_info_smc2,
164 CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SMC2_BAUD),
165 CYG_SERIAL_STOP_DEFAULT,
166 CYG_SERIAL_PARITY_DEFAULT,
167 CYG_SERIAL_WORD_LENGTH_DEFAULT,
168 CYG_SERIAL_FLAGS_DEFAULT,
169 &mpc8xxx_smc_serial_out_buf_smc2[0], sizeof(mpc8xxx_smc_serial_out_buf_smc2),
170 &mpc8xxx_smc_serial_in_buf_smc2[0], sizeof(mpc8xxx_smc_serial_in_buf_smc2)
173 static SERIAL_CHANNEL(mpc8xxx_sxx_serial_channel_smc2,
174 mpc8xxx_sxx_serial_funs,
175 mpc8xxx_sxx_serial_info_smc2,
176 CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SMC2_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 mpc8xxx_smc2_txbuf[CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SMC2_TxNUM*CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SMC2_TxSIZE] __attribute__((aligned(HAL_DCACHE_LINE_SIZE)));
184 static unsigned char mpc8xxx_smc2_rxbuf[CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SMC2_RxNUM*CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SMC2_RxSIZE] __attribute__((aligned(HAL_DCACHE_LINE_SIZE)));
186 DEVTAB_ENTRY(mpc8xxx_smc_serial_io_smc2,
187 CYGDAT_IO_SERIAL_POWERPC_MPC8XXX_SMC2_NAME,
188 0, // Does not depend on a lower level interface
189 &cyg_io_serial_devio,
190 mpc8xxx_sxx_serial_init,
191 mpc8xxx_sxx_serial_lookup, // Serial driver may need initializing
192 &mpc8xxx_sxx_serial_channel_smc2
194 #endif // CYGPKG_IO_SERIAL_POWERPC_MPC8XXX_SMC2
196 #ifdef CYGPKG_IO_SERIAL_POWERPC_MPC8XXX_SCC1
197 static mpc8xxx_sxx_serial_info mpc8xxx_sxx_serial_info_scc1 = {
198 SCC1_PAGE_SUBBLOCK, // Channel indicator
199 CYGNUM_HAL_INTERRUPT_SCC1, // interrupt
202 #if CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC1_BUFSIZE > 0
203 static unsigned char mpc8xxx_smc_serial_out_buf_scc1[CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC1_BUFSIZE];
204 static unsigned char mpc8xxx_smc_serial_in_buf_scc1[CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC1_BUFSIZE];
206 static SERIAL_CHANNEL_USING_INTERRUPTS(mpc8xxx_sxx_serial_channel_scc1,
207 mpc8xxx_sxx_serial_funs,
208 mpc8xxx_sxx_serial_info_scc1,
209 CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC1_BAUD),
210 CYG_SERIAL_STOP_DEFAULT,
211 CYG_SERIAL_PARITY_DEFAULT,
212 CYG_SERIAL_WORD_LENGTH_DEFAULT,
213 CYG_SERIAL_FLAGS_DEFAULT,
214 &mpc8xxx_smc_serial_out_buf_scc1[0], sizeof(mpc8xxx_smc_serial_out_buf_scc1),
215 &mpc8xxx_smc_serial_in_buf_scc1[0], sizeof(mpc8xxx_smc_serial_in_buf_scc1)
218 static SERIAL_CHANNEL(mpc8xxx_sxx_serial_channel_scc1,
219 mpc8xxx_sxx_serial_funs,
220 mpc8xxx_sxx_serial_info_scc1,
221 CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC1_BAUD),
222 CYG_SERIAL_STOP_DEFAULT,
223 CYG_SERIAL_PARITY_DEFAULT,
224 CYG_SERIAL_WORD_LENGTH_DEFAULT,
225 CYG_SERIAL_FLAGS_DEFAULT
228 static unsigned char mpc8xxx_scc1_txbuf[CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC1_TxNUM*CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC1_TxSIZE] __attribute__((aligned(HAL_DCACHE_LINE_SIZE)));
229 static unsigned char mpc8xxx_scc1_rxbuf[CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC1_RxNUM*CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC1_RxSIZE] __attribute__((aligned(HAL_DCACHE_LINE_SIZE)));
231 DEVTAB_ENTRY(mpc8xxx_smc_serial_io_scc1,
232 CYGDAT_IO_SERIAL_POWERPC_MPC8XXX_SCC1_NAME,
233 0, // Does not depend on a lower level interface
234 &cyg_io_serial_devio,
235 mpc8xxx_sxx_serial_init,
236 mpc8xxx_sxx_serial_lookup, // Serial driver may need initializing
237 &mpc8xxx_sxx_serial_channel_scc1
239 #endif // CYGPKG_IO_SERIAL_POWERPC_MPC8XXX_SCC1
241 #ifdef CYGPKG_IO_SERIAL_POWERPC_MPC8XXX_SCC2
242 static mpc8xxx_sxx_serial_info mpc8xxx_sxx_serial_info_scc2 = {
243 SCC2_PAGE_SUBBLOCK, // Channel indicator
244 CYGNUM_HAL_INTERRUPT_SCC2, // interrupt
247 #if CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC2_BUFSIZE > 0
248 static unsigned char mpc8xxx_smc_serial_out_buf_scc2[CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC2_BUFSIZE];
249 static unsigned char mpc8xxx_smc_serial_in_buf_scc2[CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC2_BUFSIZE];
251 static SERIAL_CHANNEL_USING_INTERRUPTS(mpc8xxx_sxx_serial_channel_scc2,
252 mpc8xxx_sxx_serial_funs,
253 mpc8xxx_sxx_serial_info_scc2,
254 CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC2_BAUD),
255 CYG_SERIAL_STOP_DEFAULT,
256 CYG_SERIAL_PARITY_DEFAULT,
257 CYG_SERIAL_WORD_LENGTH_DEFAULT,
258 CYG_SERIAL_FLAGS_DEFAULT,
259 &mpc8xxx_smc_serial_out_buf_scc2[0], sizeof(mpc8xxx_smc_serial_out_buf_scc2),
260 &mpc8xxx_smc_serial_in_buf_scc2[0], sizeof(mpc8xxx_smc_serial_in_buf_scc2)
263 static SERIAL_CHANNEL(mpc8xxx_sxx_serial_channel_scc2,
264 mpc8xxx_sxx_serial_funs,
265 mpc8xxx_sxx_serial_info_scc2,
266 CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC2_BAUD),
267 CYG_SERIAL_STOP_DEFAULT,
268 CYG_SERIAL_PARITY_DEFAULT,
269 CYG_SERIAL_WORD_LENGTH_DEFAULT,
270 CYG_SERIAL_FLAGS_DEFAULT
273 static unsigned char mpc8xxx_scc2_txbuf[CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC2_TxNUM*CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC2_TxSIZE] __attribute__((aligned(HAL_DCACHE_LINE_SIZE)));
274 static unsigned char mpc8xxx_scc2_rxbuf[CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC2_RxNUM*CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC2_RxSIZE] __attribute__((aligned(HAL_DCACHE_LINE_SIZE)));
276 DEVTAB_ENTRY(mpc8xxx_smc_serial_io_scc2,
277 CYGDAT_IO_SERIAL_POWERPC_MPC8XXX_SCC2_NAME,
278 0, // Does not depend on a lower level interface
279 &cyg_io_serial_devio,
280 mpc8xxx_sxx_serial_init,
281 mpc8xxx_sxx_serial_lookup, // Serial driver may need initializing
282 &mpc8xxx_sxx_serial_channel_scc2
284 #endif // CYGPKG_IO_SERIAL_POWERPC_MPC8XXX_SCC2
286 #ifdef CYGPKG_IO_SERIAL_POWERPC_MPC8XXX_SCC3
287 static mpc8xxx_sxx_serial_info mpc8xxx_sxx_serial_info_scc3 = {
288 SCC3_PAGE_SUBBLOCK, // Channel indicator
289 CYGNUM_HAL_INTERRUPT_SCC3, // interrupt
292 #if CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC3_BUFSIZE > 0
293 static unsigned char mpc8xxx_smc_serial_out_buf_scc3[CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC3_BUFSIZE];
294 static unsigned char mpc8xxx_smc_serial_in_buf_scc3[CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC3_BUFSIZE];
296 static SERIAL_CHANNEL_USING_INTERRUPTS(mpc8xxx_sxx_serial_channel_scc3,
297 mpc8xxx_sxx_serial_funs,
298 mpc8xxx_sxx_serial_info_scc3,
299 CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC3_BAUD),
300 CYG_SERIAL_STOP_DEFAULT,
301 CYG_SERIAL_PARITY_DEFAULT,
302 CYG_SERIAL_WORD_LENGTH_DEFAULT,
303 CYG_SERIAL_FLAGS_DEFAULT,
304 &mpc8xxx_smc_serial_out_buf_scc3[0], sizeof(mpc8xxx_smc_serial_out_buf_scc3),
305 &mpc8xxx_smc_serial_in_buf_scc3[0], sizeof(mpc8xxx_smc_serial_in_buf_scc3)
308 static SERIAL_CHANNEL(mpc8xxx_sxx_serial_channel_scc3,
309 mpc8xxx_sxx_serial_funs,
310 mpc8xxx_sxx_serial_info_scc3,
311 CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC3_BAUD),
312 CYG_SERIAL_STOP_DEFAULT,
313 CYG_SERIAL_PARITY_DEFAULT,
314 CYG_SERIAL_WORD_LENGTH_DEFAULT,
315 CYG_SERIAL_FLAGS_DEFAULT
318 static unsigned char mpc8xxx_scc3_txbuf[CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC3_TxNUM*CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC3_TxSIZE] __attribute__((aligned(HAL_DCACHE_LINE_SIZE)));
319 static unsigned char mpc8xxx_scc3_rxbuf[CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC3_RxNUM*CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC3_RxSIZE] __attribute__((aligned(HAL_DCACHE_LINE_SIZE)));
321 DEVTAB_ENTRY(mpc8xxx_smc_serial_io_scc3,
322 CYGDAT_IO_SERIAL_POWERPC_MPC8XXX_SCC3_NAME,
323 0, // Does not depend on a lower level interface
324 &cyg_io_serial_devio,
325 mpc8xxx_sxx_serial_init,
326 mpc8xxx_sxx_serial_lookup, // Serial driver may need initializing
327 &mpc8xxx_sxx_serial_channel_scc3
329 #endif // CYGPKG_IO_SERIAL_POWERPC_MPC8XXX_SCC3
331 // Internal function to actually configure the hardware to desired baud rate, etc.
333 mpc8xxx_smc_serial_config_port(serial_channel *chan, cyg_serial_info_t *new_config, bool init)
335 mpc8xxx_sxx_serial_info *smc_chan = (mpc8xxx_sxx_serial_info *)chan->dev_priv;
336 unsigned int baud_divisor = select_baud[new_config->baud];
338 volatile struct smc_regs_8260 *ctl = (volatile struct smc_regs_8260*)smc_chan->ctl;
340 if (baud_divisor == 0) return false;
341 // Disable channel during setup
342 ctl->smc_smcmr = MPC8XXX_SMCMR_UART; // Disabled, UART mode
343 HAL_IO_BARRIER(); // Inforce I/O ordering
344 // Disable port interrupts while changing hardware
345 _lcr = smc_select_word_length[new_config->word_length - CYGNUM_SERIAL_WORD_LENGTH_5] |
346 smc_select_stop_bits[new_config->stop] |
347 smc_select_parity[new_config->parity];
348 // Stop transmitter while changing baud rate
349 IMM->cpm_cpcr = smc_chan->channel | CPCR_STOP_TX | CPCR_FLG;
350 HAL_IO_BARRIER(); // Inforce I/O ordering
351 // Set baud rate generator
352 *smc_chan->brg = 0x10000 | (UART_BITRATE(baud_divisor)<<1);
354 // Enable channel with new configuration
355 ctl->smc_smcmr = MPC8XXX_SMCMR_UART|MPC8XXX_SMCMR_TEN|MPC8XXX_SMCMR_REN|_lcr;
356 HAL_IO_BARRIER(); // Inforce I/O ordering
357 IMM->cpm_cpcr = smc_chan->channel | CPCR_INIT_TX_RX_PARAMS | CPCR_FLG;
358 if (new_config != &chan->config) {
359 chan->config = *new_config;
364 // Function to set up internal tables for device.
366 mpc8xxx_smc_serial_init_info(mpc8xxx_sxx_serial_info *smc_chan,
367 t_Smc_Pram *uart_pram,
368 volatile struct smc_regs_8260 *ctl,
370 int TxBD, int TxNUM, int TxSIZE,
372 int RxBD, int RxNUM, int RxSIZE,
375 struct cp_bufdesc *txbd, *rxbd;
378 smc_chan->pram = (void *)uart_pram;
379 smc_chan->ctl = (void *)ctl;
381 // Set up baud rate generator
382 smc_chan->brg = (void *)brg;
384 // Disable channel during setup
385 ctl->smc_smcmr = MPC8XXX_SMCMR_UART; // Disabled, UART mode
387 // Rx, Tx function codes (used for access)
388 uart_pram->rfcr = 0x18;
389 uart_pram->tfcr = 0x18;
391 // Pointers to Rx & Tx buffer descriptor rings
392 uart_pram->rbase = RxBD;
393 uart_pram->tbase = TxBD;
395 /* tx and rx buffer descriptors */
396 txbd = (struct cp_bufdesc *)((char *)IMM + TxBD);
397 rxbd = (struct cp_bufdesc *)((char *)IMM + RxBD);
398 smc_chan->txbd = txbd;
399 smc_chan->tbase = txbd;
400 smc_chan->txsize = TxSIZE;
401 smc_chan->rxbd = rxbd;
402 smc_chan->rbase = rxbd;
403 smc_chan->rxsize = RxSIZE;
405 /* set max_idle feature - generate interrupt after 4 chars idle period */
406 uart_pram->max_idl = 4;
408 /* no last brk char received */
409 uart_pram->brkln = 0;
411 /* no break condition occurred */
412 uart_pram->brkec = 0;
414 /* 1 break char sent on top XMIT */
415 uart_pram->brkcr = 1;
417 /* setup RX buffer descriptors */
418 for (i = 0; i < RxNUM; i++) {
420 rxbd->buffer = RxBUF;
421 rxbd->ctrl = _BD_CTL_Ready | _BD_CTL_Int;
422 if (i == (RxNUM-1)) rxbd->ctrl |= _BD_CTL_Wrap; // Last buffer
426 /* setup TX buffer descriptors */
427 for (i = 0; i < TxNUM; i++) {
429 txbd->buffer = TxBUF;
431 if (i == (TxNUM-1)) txbd->ctrl |= _BD_CTL_Wrap; // Last buffer
436 * Reset Rx & Tx params
438 HAL_IO_BARRIER(); // Inforce I/O ordering
439 IMM->cpm_cpcr = smc_chan->channel | CPCR_INIT_TX_RX_PARAMS | CPCR_FLG;
440 HAL_IO_BARRIER(); // Inforce I/O ordering
442 * Clear any previous events. Enable interrupts.
443 * (Section 16.15.7.14 and 16.15.7.15)
445 ctl->smc_smce = 0xFF;
446 ctl->smc_smcm = SMCE_Bsy|SMCE_Tx|SMCE_Rx;
449 // Internal function to actually configure the hardware to desired baud rate, etc.
451 mpc8xxx_scc_serial_config_port(serial_channel *chan, cyg_serial_info_t *new_config, bool init)
453 mpc8xxx_sxx_serial_info *scc_chan = (mpc8xxx_sxx_serial_info *)chan->dev_priv;
454 unsigned int baud_divisor = select_baud[new_config->baud];
455 volatile struct scc_regs_8260 *regs = (volatile struct scc_regs_8260*)scc_chan->ctl;
457 if (baud_divisor == 0) return false;
458 // Set baud rate generator
459 *scc_chan->brg = 0x10000 | (UART_BITRATE(baud_divisor)<<1);
460 // Disable channel during setup
461 HAL_IO_BARRIER(); // Inforce I/O ordering
463 regs->psmr = MPC8XXX_SCC_PSMR_ASYNC |
464 scc_select_word_length[new_config->word_length - CYGNUM_SERIAL_WORD_LENGTH_5] |
465 scc_select_stop_bits[new_config->stop] |
466 scc_select_parity[new_config->parity];
468 // Enable channel with new configuration
469 regs->gsmr_h = 0x20; // 8bit FIFO
470 regs->gsmr_l = 0x00028004; // 16x TxCLK, 16x RxCLK, UART
473 * Init Rx & Tx params for SCCX
475 HAL_IO_BARRIER(); // Inforce I/O ordering
476 IMM->cpm_cpcr = CPCR_INIT_TX_RX_PARAMS | scc_chan->channel | CPCR_FLG;
478 HAL_IO_BARRIER(); // Inforce I/O ordering
479 regs->gsmr_l |= GSMR_L1_ENT | GSMR_L1_ENR; // Enable Rx, Tx
480 if (new_config != &chan->config) {
481 chan->config = *new_config;
486 // Function to set up internal tables for device.
488 mpc8xxx_scc_serial_init_info(mpc8xxx_sxx_serial_info *scc_chan,
489 volatile t_Scc_Pram *uart_pram,
490 volatile struct scc_regs_8260 *ctl,
492 int TxBD, int TxNUM, int TxSIZE,
494 int RxBD, int RxNUM, int RxSIZE,
497 struct cp_bufdesc *txbd, *rxbd;
500 // Disable channel during setup
502 scc_chan->pram = (void *)uart_pram;
503 scc_chan->ctl = (void *)ctl;
505 // Set up baud rate generator
509 * Set Rx and Tx function code
510 * (Section 16.15.4.2)
512 uart_pram->rfcr = 0x18;
513 uart_pram->tfcr = 0x18;
515 * Set pointers to buffer descriptors.
516 * (Sections 16.15.4.1, 16.15.7.12, and 16.15.7.13)
518 uart_pram->rbase = RxBD;
519 uart_pram->tbase = TxBD;
520 /* tx and rx buffer descriptors */
521 txbd = (struct cp_bufdesc *)((char *)IMM + TxBD);
522 rxbd = (struct cp_bufdesc *)((char *)IMM + RxBD);
523 scc_chan->txbd = txbd;
524 scc_chan->tbase = txbd;
525 scc_chan->txsize = TxSIZE;
526 scc_chan->rxbd = rxbd;
527 scc_chan->rbase = rxbd;
528 scc_chan->rxsize = RxSIZE;
529 /* max receive buffer length */
530 uart_pram->mrblr = RxSIZE;
531 /* set max_idle feature - generate interrupt after 4 chars idle period */
532 uart_pram->SpecificProtocol.u.max_idl = 4;
533 /* no last brk char received */
534 uart_pram->SpecificProtocol.u.brkln = 0;
535 /* no break condition occurred */
536 uart_pram->SpecificProtocol.u.brkec = 0;
537 /* 1 break char sent on top XMIT */
538 uart_pram->SpecificProtocol.u.brkcr = 1;
540 uart_pram->SpecificProtocol.u.rccm = 0xC0FF;
541 /* control characters */
542 for (i = 0; i < 8; i++) {
543 uart_pram->SpecificProtocol.u.cc[i] = 0x8000; // Mark unused
545 /* setup RX buffer descriptors */
546 for (i = 0; i < RxNUM; i++) {
548 rxbd->buffer = RxBUF;
549 rxbd->ctrl = _BD_CTL_Ready | _BD_CTL_Int;
550 if (i == (RxNUM-1)) rxbd->ctrl |= _BD_CTL_Wrap; // Last buffer
554 /* setup TX buffer descriptors */
555 for (i = 0; i < TxNUM; i++) {
557 txbd->buffer = TxBUF;
559 if (i == (TxNUM-1)) txbd->ctrl |= _BD_CTL_Wrap; // Last buffer
564 * Reset Rx & Tx params
566 HAL_IO_BARRIER(); // Inforce I/O ordering
567 IMM->cpm_cpcr = scc_chan->channel | CPCR_INIT_TX_RX_PARAMS | CPCR_FLG;
569 * Clear any previous events. Enable interrupts.
570 * (Section 16.15.7.14 and 16.15.7.15)
572 HAL_IO_BARRIER(); // Inforce I/O ordering
574 ctl->sccm = (SCCE_Bsy | SCCE_Tx | SCCE_Rx);
577 // Function to initialize the device. Called at bootstrap time.
579 mpc8xxx_sxx_serial_init(struct cyg_devtab_entry *tab)
581 serial_channel *chan = (serial_channel *)tab->priv;
582 mpc8xxx_sxx_serial_info *smc_chan = (mpc8xxx_sxx_serial_info *)chan->dev_priv;
586 HAL_DCACHE_IS_ENABLED(cache_state);
588 HAL_DCACHE_DISABLE();
589 #ifdef CYGDBG_IO_INIT
590 diag_printf("MPC8XXX_SMC SERIAL init - dev: %x.%d = %s\n", smc_chan->channel, smc_chan->int_num, tab->name);
592 #ifdef CYGPKG_IO_SERIAL_POWERPC_MPC8XXX_SMC1
593 if (chan == &mpc8xxx_sxx_serial_channel_smc1) {
594 TxBD = _mpc8xxx_allocBd(sizeof(struct cp_bufdesc)*CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SMC1_TxNUM);
595 RxBD = _mpc8xxx_allocBd(sizeof(struct cp_bufdesc)*CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SMC1_RxNUM);
596 mpc8xxx_smc_serial_init_info(&mpc8xxx_sxx_serial_info_smc1,
597 (t_Smc_Pram *)((char *)IMM + DPRAM_SMC1_OFFSET),
598 &IMM->smc_regs[SMC1],
599 (unsigned long *)&IMM->brgs_brgc7,
601 CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SMC1_TxNUM,
602 CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SMC1_TxSIZE,
603 &mpc8xxx_smc1_txbuf[0],
605 CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SMC1_RxNUM,
606 CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SMC1_RxSIZE,
607 &mpc8xxx_smc1_rxbuf[0]
611 #ifdef CYGPKG_IO_SERIAL_POWERPC_MPC8XXX_SMC2
612 #warning "Serial driver on SMC2 is unverified"
613 if (chan == &mpc8xxx_sxx_serial_channel_smc2) {
614 TxBD = _mpc8xxx_allocBd(sizeof(struct cp_bufdesc)*CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SMC2_TxNUM);
615 RxBD = _mpc8xxx_allocBd(sizeof(struct cp_bufdesc)*CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SMC2_RxNUM);
616 mpc8xxx_smc_serial_init_info(&mpc8xxx_sxx_serial_info_smc2,
617 &IMM->pram[3].scc.pothers.smc_modem.psmc.u, // PRAM
618 &IMM->smc_regs[1], // Control registers
621 CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SMC2_TxNUM,
622 CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SMC2_TxSIZE,
623 &mpc8xxx_smc2_txbuf[0],
625 CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SMC2_RxNUM,
626 CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SMC2_RxSIZE,
627 &mpc8xxx_smc2_rxbuf[0]
631 #ifdef CYGPKG_IO_SERIAL_POWERPC_MPC8XXX_SCC1
632 if (chan == &mpc8xxx_sxx_serial_channel_scc1) {
633 TxBD = _mpc8xxx_allocBd(sizeof(struct cp_bufdesc)*CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC1_TxNUM);
634 RxBD = _mpc8xxx_allocBd(sizeof(struct cp_bufdesc)*CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC1_RxNUM);
635 mpc8xxx_scc_serial_init_info(&mpc8xxx_sxx_serial_info_scc1,
636 &IMM->pram.serials.scc_pram[SCC1],
637 &IMM->scc_regs[SCC1],
638 (unsigned long *)&IMM->brgs_brgc1,
640 CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC1_TxNUM,
641 CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC1_TxSIZE,
642 &mpc8xxx_scc1_txbuf[0],
644 CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC1_RxNUM,
645 CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC1_RxSIZE,
646 &mpc8xxx_scc1_rxbuf[0]
650 #ifdef CYGPKG_IO_SERIAL_POWERPC_MPC8XXX_SCC2
651 #warning "Serial driver on SCC2 is unverified"
652 if (chan == &mpc8xxx_sxx_serial_channel_scc2) {
653 TxBD = _mpc8xxx_allocBd(sizeof(struct cp_bufdesc)*CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC2_TxNUM);
654 RxBD = _mpc8xxx_allocBd(sizeof(struct cp_bufdesc)*CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC2_RxNUM);
655 mpc8xxx_scc_serial_init_info(&mpc8xxx_sxx_serial_info_scc2,
656 &IMM->pram[1].scc.pscc.u, // PRAM
657 &IMM->scc_regs[1], // Control registers
660 CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC2_TxNUM,
661 CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC2_TxSIZE,
662 &mpc8xxx_scc2_txbuf[0],
664 CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC2_RxNUM,
665 CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC2_RxSIZE,
666 &mpc8xxx_scc2_rxbuf[0]
670 #ifdef CYGPKG_IO_SERIAL_POWERPC_MPC8XXX_SCC3
671 #warning "Serial driver on SCC3 is unverified"
672 if (chan == &mpc8xxx_sxx_serial_channel_scc3) {
673 TxBD = _mpc8xxx_allocBd(sizeof(struct cp_bufdesc)*CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC3_TxNUM);
674 RxBD = _mpc8xxx_allocBd(sizeof(struct cp_bufdesc)*CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC3_RxNUM);
675 mpc8xxx_scc_serial_init_info(&mpc8xxx_sxx_serial_info_scc3,
676 &IMM->pram[2].scc.pscc.u, // PRAM
677 &IMM->scc_regs[2], // Control registersn
680 CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC3_TxNUM,
681 CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC3_TxSIZE,
682 &mpc8xxx_scc3_txbuf[0],
684 CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC3_RxNUM,
685 CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC3_RxSIZE,
686 &mpc8xxx_scc3_rxbuf[0]
690 (chan->callbacks->serial_init)(chan); // Really only required for interrupt driven devices
691 if (chan->out_cbuf.len != 0) {
692 cyg_drv_interrupt_create(smc_chan->int_num,
693 0, // Priority - unused (but asserted)
694 (cyg_addrword_t)chan, // Data item passed to interrupt handler
695 mpc8xxx_sxx_serial_ISR,
696 mpc8xxx_sxx_serial_DSR,
697 &smc_chan->serial_interrupt_handle,
698 &smc_chan->serial_interrupt);
699 cyg_drv_interrupt_attach(smc_chan->serial_interrupt_handle);
700 cyg_drv_interrupt_unmask(smc_chan->int_num);
702 if (smc_chan->type == _SMC_CHAN) {
703 mpc8xxx_smc_serial_config_port(chan, &chan->config, true);
705 mpc8xxx_scc_serial_config_port(chan, &chan->config, true);
712 // This routine is called when the device is "looked" up (i.e. attached)
714 mpc8xxx_sxx_serial_lookup(struct cyg_devtab_entry **tab,
715 struct cyg_devtab_entry *sub_tab,
718 serial_channel *chan = (serial_channel *)(*tab)->priv;
719 (chan->callbacks->serial_init)(chan); // Really only required for interrupt driven devices
723 // Force the current transmit buffer to be sent
725 mpc8xxx_sxx_serial_flush(mpc8xxx_sxx_serial_info *smc_chan)
727 volatile struct cp_bufdesc *txbd = smc_chan->txbd;
730 HAL_DCACHE_IS_ENABLED(cache_state);
732 HAL_DCACHE_FLUSH(txbd->buffer, smc_chan->txsize);
734 if ((txbd->length > 0) &&
735 ((txbd->ctrl & (_BD_CTL_Ready|_BD_CTL_Int)) == 0)) {
736 txbd->ctrl |= _BD_CTL_Ready|_BD_CTL_Int; // Signal buffer ready
737 if (txbd->ctrl & _BD_CTL_Wrap) {
738 txbd = smc_chan->tbase;
742 smc_chan->txbd = txbd;
746 // Send a character to the device output buffer.
747 // Return 'true' if character is sent to device
749 mpc8xxx_sxx_serial_putc(serial_channel *chan, unsigned char c)
751 mpc8xxx_sxx_serial_info *smc_chan = (mpc8xxx_sxx_serial_info *)chan->dev_priv;
752 volatile struct cp_bufdesc *txbd, *txfirst;
753 volatile t_Smc_Pram *pram = (volatile t_Smc_Pram *)smc_chan->pram;
756 cyg_drv_dsr_lock(); // Avoid race condition testing pointers
757 txbd = (struct cp_bufdesc *)((char *)IMM + pram->tbptr);
759 // Scan for a non-busy buffer
760 while (txbd->ctrl & _BD_CTL_Ready) {
761 // This buffer is busy, move to next one
762 if (txbd->ctrl & _BD_CTL_Wrap) {
763 txbd = smc_chan->tbase;
767 if (txbd == txfirst) break; // Went all the way around
769 smc_chan->txbd = txbd;
770 if ((txbd->ctrl & (_BD_CTL_Ready|_BD_CTL_Int)) == 0) {
771 // Transmit buffer is not full/busy
772 txbd->buffer[txbd->length++] = c;
773 if (txbd->length == smc_chan->txsize) {
774 // This buffer is now full, tell SMC to start processing it
775 mpc8xxx_sxx_serial_flush(smc_chan);
782 cyg_drv_dsr_unlock();
786 // Fetch a character from the device input buffer, waiting if necessary
788 mpc8xxx_sxx_serial_getc(serial_channel *chan)
791 mpc8xxx_sxx_serial_info *smc_chan = (mpc8xxx_sxx_serial_info *)chan->dev_priv;
792 volatile struct cp_bufdesc *rxbd = smc_chan->rxbd;
794 while ((rxbd->ctrl & _BD_CTL_Ready) != 0) ;
796 rxbd->length = smc_chan->rxsize;
797 rxbd->ctrl |= _BD_CTL_Ready;
798 if (rxbd->ctrl & _BD_CTL_Wrap) {
799 rxbd = smc_chan->rbase;
803 smc_chan->rxbd = (struct cp_bufdesc *)rxbd;
807 // Set up the device characteristics; baud rate, etc.
809 mpc8xxx_sxx_serial_set_config(serial_channel *chan, cyg_uint32 key,
810 const void *xbuf, cyg_uint32 *len)
815 case CYG_IO_SET_CONFIG_SERIAL_INFO:
817 // FIXME - The documentation says that you can't change the baud rate
818 // again until at least two BRG input clocks have occurred.
819 cyg_serial_info_t *config = (cyg_serial_info_t *)xbuf;
820 mpc8xxx_sxx_serial_info *smc_chan = (mpc8xxx_sxx_serial_info *)chan->dev_priv;
821 if ( *len < sizeof(cyg_serial_info_t) ) {
824 *len = sizeof(cyg_serial_info_t);
825 if (smc_chan->type == _SMC_CHAN) {
826 res = mpc8xxx_smc_serial_config_port(chan, config, true);
828 res = mpc8xxx_scc_serial_config_port(chan, config, true);
840 // Enable the transmitter (interrupt) on the device
842 mpc8xxx_sxx_serial_start_xmit(serial_channel *chan)
844 mpc8xxx_sxx_serial_info *smc_chan = (mpc8xxx_sxx_serial_info *)chan->dev_priv;
846 if (smc_chan->txbd->length == 0) {
847 // See if there is anything to put in this buffer, just to get it going
848 (chan->callbacks->xmt_char)(chan);
850 if (smc_chan->txbd->length != 0) {
851 // Make sure it gets started
852 mpc8xxx_sxx_serial_flush(smc_chan);
854 cyg_drv_dsr_unlock();
857 // Disable the transmitter on the device
859 mpc8xxx_sxx_serial_stop_xmit(serial_channel *chan)
861 mpc8xxx_sxx_serial_info *smc_chan = (mpc8xxx_sxx_serial_info *)chan->dev_priv;
862 // If anything is in the last buffer, need to get it started
863 if (smc_chan->txbd->length != 0) {
864 mpc8xxx_sxx_serial_flush(smc_chan);
868 // Serial I/O - low level interrupt handler (ISR)
870 mpc8xxx_sxx_serial_ISR(cyg_vector_t vector, cyg_addrword_t data)
872 serial_channel *chan = (serial_channel *)data;
873 mpc8xxx_sxx_serial_info *smc_chan = (mpc8xxx_sxx_serial_info *)chan->dev_priv;
874 cyg_drv_interrupt_mask(smc_chan->int_num);
875 return (CYG_ISR_HANDLED|CYG_ISR_CALL_DSR); // Cause DSR to be run
878 // Serial I/O - high level interrupt handler (DSR)
880 mpc8xxx_smc_serial_DSR(serial_channel *chan)
882 mpc8xxx_sxx_serial_info *smc_chan = (mpc8xxx_sxx_serial_info *)chan->dev_priv;
883 volatile struct smc_regs_8260 *ctl = (volatile struct smc_regs_8260 *)smc_chan->ctl;
884 volatile struct cp_bufdesc *txbd;
885 volatile struct cp_bufdesc *rxbd = smc_chan->rxbd;
886 volatile t_Smc_Pram *pram = (volatile t_Smc_Pram *)smc_chan->pram;
887 struct cp_bufdesc *rxlast;
890 if (ctl->smc_smce & SMCE_Tx) {
891 // Transmit interrupt
892 ctl->smc_smce = SMCE_Tx; // Reset interrupt state;
893 txbd = smc_chan->tbase; // First buffer
895 if ((txbd->ctrl & (_BD_CTL_Ready|_BD_CTL_Int)) == _BD_CTL_Int) {
897 txbd->ctrl &= ~_BD_CTL_Int; // Reset interrupt bit
899 if (txbd->ctrl & _BD_CTL_Wrap) {
900 txbd = smc_chan->tbase;
906 (chan->callbacks->xmt_char)(chan);
908 while (ctl->smc_smce & SMCE_Rx) {
910 ctl->smc_smce = SMCE_Rx; // Reset interrupt state;
911 rxlast = (struct cp_bufdesc *) (
912 (char *)IMM + pram->rbptr );
913 while (rxbd != rxlast) {
914 if ((rxbd->ctrl & _BD_CTL_Ready) == 0) {
915 for (i = 0; i < rxbd->length; i++) {
916 (chan->callbacks->rcv_char)(chan, rxbd->buffer[i]);
918 // Note: the MBX860 does not seem to snoop/invalidate the data cache properly!
919 HAL_DCACHE_IS_ENABLED(cache_state);
921 HAL_DCACHE_INVALIDATE(rxbd->buffer, smc_chan->rxsize); // Make sure no stale data
924 rxbd->ctrl |= _BD_CTL_Ready;
926 if (rxbd->ctrl & _BD_CTL_Wrap) {
927 rxbd = smc_chan->rbase;
932 smc_chan->rxbd = (struct cp_bufdesc *)rxbd;
934 if (ctl->smc_smce & SMCE_Bsy) {
935 ctl->smc_smce = SMCE_Bsy; // Reset interrupt state;
937 cyg_drv_interrupt_acknowledge(smc_chan->int_num);
938 cyg_drv_interrupt_unmask(smc_chan->int_num);
942 mpc8xxx_scc_serial_DSR(serial_channel *chan)
944 mpc8xxx_sxx_serial_info *smc_chan = (mpc8xxx_sxx_serial_info *)chan->dev_priv;
945 volatile struct scc_regs_8260 *ctl = (volatile struct scc_regs_8260 *)smc_chan->ctl;
946 volatile struct cp_bufdesc *txbd;
947 volatile struct cp_bufdesc *rxbd = smc_chan->rxbd;
948 volatile t_Smc_Pram *pram = (volatile t_Smc_Pram *)smc_chan->pram;
949 struct cp_bufdesc *rxlast;
952 if (ctl->scce & SCCE_Tx) {
953 // Transmit interrupt
954 ctl->scce = SCCE_Tx; // Reset interrupt state;
955 txbd = smc_chan->tbase; // First buffer
957 if ((txbd->ctrl & (_BD_CTL_Ready|_BD_CTL_Int)) == _BD_CTL_Int) {
959 txbd->ctrl &= ~_BD_CTL_Int; // Reset interrupt bit
961 if (txbd->ctrl & _BD_CTL_Wrap) {
962 txbd = smc_chan->tbase;
968 (chan->callbacks->xmt_char)(chan);
970 while (ctl->scce & SCCE_Rx) {
972 ctl->scce = SCCE_Rx; // Reset interrupt state;
973 rxlast = (struct cp_bufdesc *) ((char *)IMM + pram->rbptr);
974 while (rxbd != rxlast) {
975 if ((rxbd->ctrl & _BD_CTL_Ready) == 0) {
976 for (i = 0; i < rxbd->length; i++) {
977 (chan->callbacks->rcv_char)(chan, rxbd->buffer[i]);
979 // Note: the MBX860 does not seem to snoop/invalidate the data cache properly!
980 HAL_DCACHE_IS_ENABLED(cache_state);
982 HAL_DCACHE_INVALIDATE(rxbd->buffer, smc_chan->rxsize); // Make sure no stale data
985 rxbd->ctrl |= _BD_CTL_Ready;
987 if (rxbd->ctrl & _BD_CTL_Wrap) {
988 rxbd = smc_chan->rbase;
993 smc_chan->rxbd = (struct cp_bufdesc *)rxbd;
995 if (ctl->scce & SCCE_Bsy) {
996 ctl->scce = SCCE_Bsy; // Reset interrupt state;
998 cyg_drv_interrupt_acknowledge(smc_chan->int_num);
999 cyg_drv_interrupt_unmask(smc_chan->int_num);
1003 mpc8xxx_sxx_serial_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
1005 serial_channel *chan = (serial_channel *)data;
1006 mpc8xxx_sxx_serial_info *smc_chan = (mpc8xxx_sxx_serial_info *)chan->dev_priv;
1008 if (smc_chan->type == _SMC_CHAN) {
1009 mpc8xxx_smc_serial_DSR(chan);
1011 mpc8xxx_scc_serial_DSR(chan);
1015 // ------------------------------------------------------------------------
1016 // EOF powerpc/mpc8xxx_smc_serial.c