comparison packages/devs/serial/sh/scif/current/src/sh_scif_serial.c @ 130:eb9fd8c04db3 ecos-sw-2000-10-23

Merge from eCos master repository on 2000-10-23-17:01:37-BST
author jlarmour
date Mon, 23 Oct 2000 17:10:57 +0000
parents 0c2b7be0d798
children e2d866e32dac
comparison
equal deleted inserted replaced
129:605a0fc6f385 130:eb9fd8c04db3
50 50
51 #include <cyg/io/io.h> 51 #include <cyg/io/io.h>
52 #include <cyg/hal/hal_intr.h> 52 #include <cyg/hal/hal_intr.h>
53 #include <cyg/io/devtab.h> 53 #include <cyg/io/devtab.h>
54 #include <cyg/infra/diag.h> 54 #include <cyg/infra/diag.h>
55 #include <cyg/infra/cyg_ass.h>
55 #include <cyg/io/serial.h> 56 #include <cyg/io/serial.h>
56 57
57 #include <cyg/hal/sh_regs.h> 58 #include <cyg/hal/sh_regs.h>
58 #include <cyg/hal/hal_cache.h> 59 #include <cyg/hal/hal_cache.h>
59 60
132 serial_rx_interrupt_handle, 133 serial_rx_interrupt_handle,
133 serial_tx_interrupt_handle; 134 serial_tx_interrupt_handle;
134 135
135 volatile bool tx_enabled; // expect tx _serial_ interrupts 136 volatile bool tx_enabled; // expect tx _serial_ interrupts
136 137
138 #if (CYGINT_IO_SERIAL_SH_SCIF_DMA > 0)
139 cyg_bool dma_enable; // Set if DMA mode
140 cyg_uint32 dma_xmt_cr_flags; // CR flags for DMA mode
141 CYG_WORD dma_xmt_int_num; // DMA xmt completion interrupt
142 CYG_ADDRWORD dma_xmt_base; // Base address of DMA channel
143 int dma_xmt_len; // length transferred by DMA
144 cyg_interrupt dma_xmt_interrupt;
145 cyg_handle_t dma_xmt_interrupt_handle;
146 volatile cyg_bool dma_xmt_running; // expect tx _dma_ interrupts
147 #endif
137 } sh3_scif_info; 148 } sh3_scif_info;
138 149
139 static bool sh3_scif_init(struct cyg_devtab_entry *tab); 150 static bool sh3_scif_init(struct cyg_devtab_entry *tab);
140 static bool sh3_scif_putc(serial_channel *chan, unsigned char c); 151 static bool sh3_scif_putc(serial_channel *chan, unsigned char c);
141 static Cyg_ErrNo sh3_scif_lookup(struct cyg_devtab_entry **tab, 152 static Cyg_ErrNo sh3_scif_lookup(struct cyg_devtab_entry **tab,
154 static void sh3_scif_rx_DSR(cyg_vector_t vector, cyg_ucount32 count, 165 static void sh3_scif_rx_DSR(cyg_vector_t vector, cyg_ucount32 count,
155 cyg_addrword_t data); 166 cyg_addrword_t data);
156 static cyg_uint32 sh3_scif_er_ISR(cyg_vector_t vector, cyg_addrword_t data); 167 static cyg_uint32 sh3_scif_er_ISR(cyg_vector_t vector, cyg_addrword_t data);
157 static void sh3_scif_er_DSR(cyg_vector_t vector, cyg_ucount32 count, 168 static void sh3_scif_er_DSR(cyg_vector_t vector, cyg_ucount32 count,
158 cyg_addrword_t data); 169 cyg_addrword_t data);
170
171 #if (CYGINT_IO_SERIAL_SH_SCIF_DMA > 0)
172 static cyg_uint32 sh3_dma_xmt_ISR(cyg_vector_t vector, cyg_addrword_t data);
173 static void sh3_dma_xmt_DSR(cyg_vector_t vector, cyg_ucount32 count,
174 cyg_addrword_t data);
175 #endif
159 176
160 static SERIAL_FUNS(sh3_scif_funs, 177 static SERIAL_FUNS(sh3_scif_funs,
161 sh3_scif_putc, 178 sh3_scif_putc,
162 sh3_scif_getc, 179 sh3_scif_getc,
163 sh3_scif_set_config, 180 sh3_scif_set_config,
280 &sh_chan->serial_er_interrupt); 297 &sh_chan->serial_er_interrupt);
281 cyg_drv_interrupt_attach(sh_chan->serial_er_interrupt_handle); 298 cyg_drv_interrupt_attach(sh_chan->serial_er_interrupt_handle);
282 // This unmasks both interrupt sources. 299 // This unmasks both interrupt sources.
283 cyg_drv_interrupt_unmask(sh_chan->rx_int_num); 300 cyg_drv_interrupt_unmask(sh_chan->rx_int_num);
284 } 301 }
302
303 #if (CYGINT_IO_SERIAL_SH_SCIF_DMA > 0)
304 // Assign DMA channel and interrupt if requested
305 if (sh_chan->dma_enable) {
306 // FIXME: Need a cleaner way to assign DMA channels
307 static int dma_channel = 0;
308 sh_chan->dma_xmt_int_num = dma_channel+CYGNUM_HAL_INTERRUPT_DMAC_DEI0;
309 sh_chan->dma_xmt_base = (dma_channel*0x10)+CYGARC_REG_SAR0;
310 dma_channel++;
311
312 // Enable the DMA engines.
313 HAL_WRITE_UINT16(CYGARC_REG_DMAOR, CYGARC_REG_DMAOR_DME);
314
315 cyg_drv_interrupt_create(sh_chan->dma_xmt_int_num,
316 3,
317 (cyg_addrword_t)chan, // Data item passed to interrupt handler
318 sh3_dma_xmt_ISR,
319 sh3_dma_xmt_DSR,
320 &sh_chan->dma_xmt_interrupt_handle,
321 &sh_chan->dma_xmt_interrupt);
322 cyg_drv_interrupt_attach(sh_chan->dma_xmt_interrupt_handle);
323 cyg_drv_interrupt_unmask(sh_chan->dma_xmt_int_num);
324 }
325 sh_chan->dma_xmt_running = false;
326 #endif // CYGINT_IO_SERIAL_SH_SCIF_DMA
327
285 sh3_scif_config_port(chan, &chan->config, true); 328 sh3_scif_config_port(chan, &chan->config, true);
286 return true; 329 return true;
287 } 330 }
288 331
289 // This routine is called when the device is "looked" up (i.e. attached) 332 // This routine is called when the device is "looked" up (i.e. attached)
363 } 406 }
364 break; 407 break;
365 #ifdef CYGOPT_IO_SERIAL_FLOW_CONTROL_HW 408 #ifdef CYGOPT_IO_SERIAL_FLOW_CONTROL_HW
366 case CYG_IO_SET_CONFIG_SERIAL_HW_RX_FLOW_THROTTLE: 409 case CYG_IO_SET_CONFIG_SERIAL_HW_RX_FLOW_THROTTLE:
367 { 410 {
368 cyg_uint8 _scfcr; 411 // Control RX flow control by disabling/enabling RX interrupt.
412 // When disabled, FIFO will fill up and clear RTS.
413 cyg_uint8 _scscr, mask = 0;
369 sh3_scif_info *ser_chan = (sh3_scif_info *)chan->dev_priv; 414 sh3_scif_info *ser_chan = (sh3_scif_info *)chan->dev_priv;
370 cyg_addrword_t base = ser_chan->ctrl_base; 415 cyg_addrword_t base = ser_chan->ctrl_base;
371 cyg_uint8 *f = (cyg_uint8 *)xbuf; 416 cyg_uint8 *f = (cyg_uint8 *)xbuf;
372 unsigned char mask=0;
373 if ( *len < *f ) 417 if ( *len < *f )
374 return -EINVAL; 418 return -EINVAL;
375 419
376 if ( chan->config.flags & CYGNUM_SERIAL_FLOW_RTSCTS_RX ) 420 if ( chan->config.flags & CYGNUM_SERIAL_FLOW_RTSCTS_RX )
377 mask |= CYGARC_REG_SCFCR1_MCE; 421 mask |= CYGARC_REG_SCSCR2_RIE;
378 HAL_READ_UINT8(base+SCIF_SCFCR, _scfcr); 422 HAL_READ_UINT8(base+SCIF_SCSCR, _scscr);
379 if (*f) // we should throttle 423 if (*f) // we should throttle
380 _scfcr &= ~mask; 424 _scscr &= ~mask;
381 else // we should no longer throttle 425 else // we should no longer throttle
382 _scfcr |= mask; 426 _scscr |= mask;
383 HAL_WRITE_UINT8(base+SCIF_SCFCR, _scfcr); 427 HAL_WRITE_UINT8(base+SCIF_SCSCR, _scscr);
384 } 428 }
385 break; 429 break;
386 case CYG_IO_SET_CONFIG_SERIAL_HW_FLOW_CONFIG: 430 case CYG_IO_SET_CONFIG_SERIAL_HW_FLOW_CONFIG:
387 { 431 {
388 // Clear DSR/DTR flag as it's not supported. 432 // Handle CTS/RTS flag
389 if (chan->config.flags & 433 if ( chan->config.flags &
390 (CYGNUM_SERIAL_FLOW_DSRDTR_RX|CYGNUM_SERIAL_FLOW_DSRDTR_TX)) { 434 (CYGNUM_SERIAL_FLOW_RTSCTS_RX | CYGNUM_SERIAL_FLOW_RTSCTS_TX )){
391 chan->config.flags &= ~(CYGNUM_SERIAL_FLOW_DSRDTR_RX| 435 cyg_uint8 _scfcr;
392 CYGNUM_SERIAL_FLOW_DSRDTR_TX); 436 sh3_scif_info *ser_chan = (sh3_scif_info *)chan->dev_priv;
393 return -EINVAL; 437 cyg_addrword_t base = ser_chan->ctrl_base;
394 } 438 cyg_uint8 *f = (cyg_uint8 *)xbuf;
439
440 HAL_READ_UINT8(base+SCIF_SCFCR, _scfcr);
441 if (*f) // enable RTS/CTS flow control
442 _scfcr |= CYGARC_REG_SCFCR1_MCE;
443 else // disable RTS/CTS flow control
444 _scfcr &= ~CYGARC_REG_SCFCR1_MCE;
445 HAL_WRITE_UINT8(base+SCIF_SCFCR, _scfcr);
446 }
447 // Clear DSR/DTR flag as it's not supported.
448 if (chan->config.flags &
449 (CYGNUM_SERIAL_FLOW_DSRDTR_RX|CYGNUM_SERIAL_FLOW_DSRDTR_TX)) {
450 chan->config.flags &= ~(CYGNUM_SERIAL_FLOW_DSRDTR_RX|
451 CYGNUM_SERIAL_FLOW_DSRDTR_TX);
452 return -EINVAL;
453 }
395 } 454 }
396 break; 455 break;
397 #endif 456 #endif
398 default: 457 default:
399 return -EINVAL; 458 return -EINVAL;
400 } 459 }
401 return ENOERR; 460 return ENOERR;
402 } 461 }
403 462
404 463
464 #if (CYGINT_IO_SERIAL_SH_SCIF_DMA > 0)
465
466 // Must be called with serial interrupts disabled
467 static xmt_req_reply_t
468 sh3_scif_start_dma_xmt(serial_channel *chan)
469 {
470 int chars_avail;
471 unsigned char* chars;
472 xmt_req_reply_t res;
473
474 // We can transfer the full buffer - ask how much to transfer
475 res = (chan->callbacks->data_xmt_req)(chan, chan->out_cbuf.len,
476 &chars_avail, &chars);
477 if (CYG_XMT_OK == res) {
478 sh3_scif_info *sh_chan = (sh3_scif_info *)chan->dev_priv;
479 cyg_uint32 dma_base = sh_chan->dma_xmt_base;
480 cyg_uint32 scr;
481
482 // Save the length so it can be used in the DMA DSR
483 sh_chan->dma_xmt_len = chars_avail;
484
485 // Flush cache for the area
486 HAL_DCACHE_FLUSH((cyg_haladdress)chars, chars_avail);
487
488 // Program DMA
489 HAL_WRITE_UINT32(dma_base+CYGARC_REG_CHCR, 0); // disable and clear
490 HAL_WRITE_UINT32(dma_base+CYGARC_REG_SAR, (cyg_uint32)chars);
491 HAL_WRITE_UINT32(dma_base+CYGARC_REG_DAR,
492 (sh_chan->ctrl_base+SCIF_SCFTDR) & 0x0fffffff);
493 HAL_WRITE_UINT32(dma_base+CYGARC_REG_DMATCR, chars_avail);
494 // Source increments, dest static, byte transfer, enable
495 // interrupt on completion.
496 HAL_WRITE_UINT32(dma_base+CYGARC_REG_CHCR,
497 sh_chan->dma_xmt_cr_flags | CYGARC_REG_CHCR_SM0 \
498 | CYGARC_REG_CHCR_IE | CYGARC_REG_CHCR_DE);
499
500 // Enable serial interrupts
501 HAL_READ_UINT8(sh_chan->ctrl_base+SCIF_SCSCR, scr);
502 scr |= CYGARC_REG_SCSCR2_TIE;
503 HAL_WRITE_UINT8(sh_chan->ctrl_base+SCIF_SCSCR, scr);
504 }
505
506 return res;
507 }
508
509 // must be called with serial interrupts masked
510 static void
511 sh3_scif_stop_dma_xmt(serial_channel *chan)
512 {
513 sh3_scif_info *sh_chan = (sh3_scif_info *)chan->dev_priv;
514 cyg_uint32 dma_base = sh_chan->dma_xmt_base;
515 cyg_uint32 cr;
516
517 // Disable DMA engine and interrupt enable flag. Should be safe
518 // to do since it's triggered by the serial interrupt which has
519 // already been disabled.
520 HAL_READ_UINT32(dma_base+CYGARC_REG_CHCR, cr);
521 cr &= ~(CYGARC_REG_CHCR_IE | CYGARC_REG_CHCR_DE);
522 HAL_WRITE_UINT32(dma_base+CYGARC_REG_CHCR, cr);
523
524 // Did transfer complete?
525 HAL_READ_UINT32(dma_base+CYGARC_REG_CHCR, cr);
526 if (0 == (cr & CYGARC_REG_CHCR_TE)) {
527 // Transfer incomplete. Report actually transferred amount of data
528 // back to the serial driver.
529 int chars_left;
530 HAL_READ_UINT32(dma_base+CYGARC_REG_DMATCR, chars_left);
531 CYG_ASSERT(chars_left > 0, "DMA incomplete, but no data left");
532 CYG_ASSERT(chars_left <= sh_chan->dma_xmt_len,
533 "More data remaining than was attempted transferred");
534
535 (chan->callbacks->data_xmt_done)(chan,
536 sh_chan->dma_xmt_len - chars_left);
537 }
538
539 #ifdef CYGDBG_USE_ASSERTS
540 {
541 cyg_uint32 dmaor;
542 HAL_READ_UINT32(CYGARC_REG_DMAOR, dmaor);
543 CYG_ASSERT(0== (dmaor & (CYGARC_REG_DMAOR_AE | CYGARC_REG_DMAOR_NMIF)),
544 "DMA error");
545 }
546 #endif
547
548 // The DMA engine is free again.
549 sh_chan->dma_xmt_running = false;
550 }
551
552 // Serial xmt DMA completion interrupt handler (ISR)
553 static cyg_uint32
554 sh3_dma_xmt_ISR(cyg_vector_t vector, cyg_addrword_t data)
555 {
556 serial_channel *chan = (serial_channel *)data;
557 sh3_scif_info *sh_chan = (sh3_scif_info *)chan->dev_priv;
558 cyg_uint32 _cr;
559
560 // mask serial interrupt
561 HAL_READ_UINT8(sh_chan->ctrl_base+SCIF_SCSCR, _cr);
562 _cr &= ~CYGARC_REG_SCSCR2_TIE; // Disable xmit interrupt
563 HAL_WRITE_UINT8(sh_chan->ctrl_base+SCIF_SCSCR, _cr);
564
565 // mask DMA interrupt and disable engine
566 HAL_READ_UINT32(sh_chan->dma_xmt_base+CYGARC_REG_CHCR, _cr);
567 _cr &= ~(CYGARC_REG_CHCR_IE | CYGARC_REG_CHCR_DE);
568 HAL_WRITE_UINT32(sh_chan->dma_xmt_base+CYGARC_REG_CHCR, _cr);
569
570 return CYG_ISR_CALL_DSR; // Cause DSR to be run
571 }
572
573 // Serial xmt DMA completion interrupt handler (DSR)
574 static void
575 sh3_dma_xmt_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
576 {
577 serial_channel *chan = (serial_channel *)data;
578 sh3_scif_info *sh_chan = (sh3_scif_info *)chan->dev_priv;
579
580 (chan->callbacks->data_xmt_done)(chan, sh_chan->dma_xmt_len);
581
582 // Try to load the engine again.
583 sh_chan->dma_xmt_running =
584 (CYG_XMT_OK == sh3_scif_start_dma_xmt(chan)) ? true : false;
585 }
586 #endif // CYGINT_IO_SERIAL_SH_SCIF_DMA
587
405 588
406 // Enable the transmitter on the device 589 // Enable the transmitter on the device
407 static void 590 static void
408 sh3_scif_start_xmit(serial_channel *chan) 591 sh3_scif_start_xmit(serial_channel *chan)
409 { 592 {
411 sh3_scif_info *sh_chan = (sh3_scif_info *)chan->dev_priv; 594 sh3_scif_info *sh_chan = (sh3_scif_info *)chan->dev_priv;
412 xmt_req_reply_t _block_status = CYG_XMT_DISABLED; 595 xmt_req_reply_t _block_status = CYG_XMT_DISABLED;
413 596
414 if (sh_chan->tx_enabled) 597 if (sh_chan->tx_enabled)
415 return; 598 return;
599
600 #if (CYGINT_IO_SERIAL_SH_SCIF_DMA > 0)
601 // Check if the engine is already running. If so, return. Note
602 // that there will never be a race on this flag - the caller of
603 // this function is respecting a per-channel lock.
604 if (sh_chan->dma_xmt_running)
605 return;
606 // If the channel uses DMA, try to start a DMA job for this -
607 // but handle the case where the job doesn't start by falling
608 // back to the FIFO/interrupt based code.
609 if (sh_chan->dma_enable) {
610 _block_status = sh3_scif_start_dma_xmt(chan);
611 CYG_ASSERT(_block_status != CYG_XMT_EMPTY,
612 "start_xmit called with empty buffers!");
613 sh_chan->dma_xmt_running =
614 (CYG_XMT_OK == _block_status) ? true : false;
615 }
616 #endif // CYGINT_IO_SERIAL_SH_SCIF_DMA
416 617
417 if (CYG_XMT_DISABLED == _block_status) { 618 if (CYG_XMT_DISABLED == _block_status) {
418 // Mask interrupts while changing the CR since a rx 619 // Mask interrupts while changing the CR since a rx
419 // interrupt or another thread doing the same in the 620 // interrupt or another thread doing the same in the
420 // middle of this would result in a bad CR state. 621 // middle of this would result in a bad CR state.
445 _scr &= ~CYGARC_REG_SCSCR2_TIE; // Disable xmit interrupt 646 _scr &= ~CYGARC_REG_SCSCR2_TIE; // Disable xmit interrupt
446 HAL_WRITE_UINT8(sh_chan->ctrl_base+SCIF_SCSCR, _scr); 647 HAL_WRITE_UINT8(sh_chan->ctrl_base+SCIF_SCSCR, _scr);
447 } 648 }
448 cyg_drv_isr_unlock(); 649 cyg_drv_isr_unlock();
449 650
651 #if (CYGINT_IO_SERIAL_SH_SCIF_DMA > 0)
652 // If the channel uses DMA, stop the DMA engine.
653 if (sh_chan->dma_xmt_running)
654 sh3_scif_stop_dma_xmt(chan);
655 else // dangling else!
656 #endif // CYGINT_IO_SERIAL_SH_SCIF_DMA
450 sh_chan->tx_enabled = false; 657 sh_chan->tx_enabled = false;
451 } 658 }
452 659
453 // Serial I/O - low level tx interrupt handler (ISR) 660 // Serial I/O - low level tx interrupt handler (ISR)
454 static cyg_uint32 661 static cyg_uint32