From 3a5fec8fefe59cd53f0c0e6d260162b1819e92f6 Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Thu, 16 Aug 2001 21:50:01 +0000 Subject: 2001-08-10 Radzislaw Galler * score/cpu_asm.c (sh_set_irq_priority): Changed interrupt vector number range check and handling of interrupt priority regs to conform SH2 specs. * sci/sci_termios.c: New file. * include/sci_termios.h: New file. * include/Makefile.am (EXTRA_DIST): Added sci_termios.h. (include_sh_HEADERS): Added sci_termios.h. * score/ispsh7045.c (isp): Calling an ISR with immediate argument casued negative sign extension for vector numbers of 128 and above. This was fixed. * sci/sci.c: Cleaned initialization of SCI registers; added necessary setup for new TERMIOS console cooperation --- c/src/lib/libcpu/sh/sh7045/include/sci_termios.h | 67 ++++ c/src/lib/libcpu/sh/sh7045/sci/sci_termios.c | 464 +++++++++++++++++++++++ 2 files changed, 531 insertions(+) create mode 100644 c/src/lib/libcpu/sh/sh7045/include/sci_termios.h create mode 100644 c/src/lib/libcpu/sh/sh7045/sci/sci_termios.c (limited to 'c') diff --git a/c/src/lib/libcpu/sh/sh7045/include/sci_termios.h b/c/src/lib/libcpu/sh/sh7045/include/sci_termios.h new file mode 100644 index 0000000000..008e5e0f6f --- /dev/null +++ b/c/src/lib/libcpu/sh/sh7045/include/sci_termios.h @@ -0,0 +1,67 @@ +/* + * COPYRIGHT (c) 1989-2001. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.OARcorp.com/rtems/license.html. + * + * $Id$ + * + */ + +#ifndef _SH_SCI_TERMIOS_H_ +#define _SH_SCI_TERMIOS_H_ + +#ifdef __cplusplus +extern "C"{ +#endif + + +int sh_sci_set_attributes( + int minor, + const struct termios *t +); + +void sh_sci_initialize_interrupts(int minor); + +void sh_sci_init(int minor); + +int sh_sci_write_support_int( + int minor, + const char *buf, + int len +); + +int sh_sci_write_support_polled( + int minor, + const char *buf, + int len +); + +void sh_sci_write_polled( + int minor, + char c +); + +int sh_sci_inbyte_nonblocking_polled(int minor); + + +int sh_sci_first_open( + int major, + int minor, + void *arg +); + +int sh_sci_last_close( + int major, + int minor, + void *arg +); + +#ifdef __cplusplus +} +#endif + + +#endif /* _SH_SCI_TERMIOS_H_ */ diff --git a/c/src/lib/libcpu/sh/sh7045/sci/sci_termios.c b/c/src/lib/libcpu/sh/sh7045/sci/sci_termios.c new file mode 100644 index 0000000000..bb3f540146 --- /dev/null +++ b/c/src/lib/libcpu/sh/sh7045/sci/sci_termios.c @@ -0,0 +1,464 @@ +/* + * Termios console serial driver. + * + * Based on SCI driver by Ralf Corsepius and John M. Mills + * + * Author: Radzislaw Galler + * + * COPYRIGHT (c) 1989-2001. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.OARcorp.com/rtems/license.html. + * + * $Id$ + * + */ + +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include + + +/* + * Some handy macros + */ +#define SH_SCI_REG_DATA(_data, _minor, _register) \ + (write8(_data, Console_Port_Tbl[_minor].ulCtrlPort1 + (_register))) + +#define SH_SCI_REG_FLAG(_flag, _minor, _register) \ + (write8(read8(Console_Port_Tbl[_minor].ulCtrlPort1 + (_register)) | (_flag), \ + Console_Port_Tbl[_minor].ulCtrlPort1 + (_register))) + +#define SH_SCI_REG_MASK(_flag, _minor, _register) \ + (write8(read8(Console_Port_Tbl[_minor].ulCtrlPort1 + (_register)) & ~(_flag), \ + Console_Port_Tbl[_minor].ulCtrlPort1 + (_register))) + +/* + * NOTE: Some SH variants have 3 sci devices + */ + +#define SCI_MINOR_DEVICES 2 + + +/* + * Automatically generated function imported from scitab.rel + */ +extern int _sci_get_brparms( + tcflag_t cflag, + unsigned char *smr, + unsigned char *brr ); + +/* + * Translate termios flags into SCI settings + */ +int sh_sci_set_attributes( + int minor, + const struct termios *t +) +{ + unsigned8 smr ; + unsigned8 brr ; + int a; + + tcflag_t c_cflag = t->c_cflag; + + if ( c_cflag & CBAUD ) + { + if ( _sci_get_brparms( c_cflag, &smr, &brr ) != 0 ) + return -1 ; + } + + if ( c_cflag & CSIZE ) + { + if ( c_cflag & CS8 ) + smr &= ~SCI_SEVEN_BIT_DATA; + else if ( c_cflag & CS7 ) + smr |= SCI_SEVEN_BIT_DATA; + else + return -1 ; + } + + if ( c_cflag & CSTOPB ) + smr |= SCI_STOP_BITS_2; + else + smr &= ~SCI_STOP_BITS_2; + + if ( c_cflag & PARENB ) + smr |= SCI_PARITY_ON ; + else + smr &= ~SCI_PARITY_ON ; + + if ( c_cflag & PARODD ) + smr |= SCI_ODD_PARITY ; + else + smr &= ~SCI_ODD_PARITY; + + SH_SCI_REG_MASK((SCI_RE | SCI_TE), minor, SCI_SCR); + + SH_SCI_REG_DATA(smr, minor, SCI_SMR); + SH_SCI_REG_DATA(brr, minor, SCI_BRR); + + for(a=0; a < 10000L; a++) { /* Delay one bit */ + asm volatile ("nop"); + } + + SH_SCI_REG_FLAG((SCI_RE | SCI_TE), minor, SCI_SCR); + + return 0; +} + +/* + * Receive-data-full ISR + * + * The same routine for all interrupt sources of the same type. + */ +rtems_isr sh_sci_rx_isr(rtems_vector_number vector) +{ + int minor; + + for(minor = 0; minor < Console_Port_Count; minor++) + { + if(Console_Port_Tbl[minor].ulIntVector == vector) + { + unsigned8 temp8; + + /* + * FIXME: error handling should be added + */ + temp8 = read8(Console_Port_Tbl[minor].ulCtrlPort1 + SCI_RDR); + + rtems_termios_enqueue_raw_characters( + Console_Port_Data[minor].termios_data, + (char*)&temp8, 1); + + SH_SCI_REG_MASK(SCI_RDRF, minor, SCI_SSR); + break; + } + } +} + +/* + * Transmit-data-empty ISR + * + * The same routine for all interrupt sources of the same type. + */ +rtems_isr sh_sci_tx_isr(rtems_vector_number vector) +{ + int minor; + + for(minor = 0; minor < Console_Port_Count; minor++) + { + if(Console_Port_Tbl[minor].ulDataPort == vector) + { + /* + * FIXME: Error handling should be added + */ + + /* + * Mask end-of-transmission interrupt + */ + SH_SCI_REG_MASK(SCI_TIE, minor, SCI_SCR); + + if(rtems_termios_dequeue_characters( + Console_Port_Data[minor].termios_data, 1)) + { + /* + * More characters to be received - interrupt must be enabled + */ + SH_SCI_REG_FLAG(SCI_TIE, minor, SCI_SCR); + } + break; + } + } +} + + +/* + * Initialization of serial port + */ +void sh_sci_init(int minor) +{ + unsigned16 temp16; + + /* + * set PFC registers to enable I/O pins + */ + if ((minor == 0)) + { + temp16 = read16(PFC_PACRL2); /* disable SCK0, DMA, IRQ */ + temp16 &= ~(PA2MD1 | PA2MD0); + temp16 |= (PA_TXD0 | PA_RXD0); /* enable pins for Tx0, Rx0 */ + write16(temp16, PFC_PACRL2); + + } + else if (minor == 1) + { + temp16 = read16(PFC_PACRL2); /* disable SCK1, DMA, IRQ */ + temp16 &= ~(PA5MD1 | PA5MD0); + temp16 |= (PA_TXD1 | PA_RXD1); /* enable pins for Tx1, Rx1 */ + write16(temp16, PFC_PACRL2); + } + + /* + * Non-default hardware setup occurs in sh_sci_first_open + */ +} + +/* + * Initialization of interrupts + * + * Interrupts can be started only after opening a device, so interrupt + * flags are set up in sh_sci_first_open function + */ +void sh_sci_initialize_interrupts(int minor) +{ + rtems_isr_entry old_isr; + rtems_status_code status; + + sh_sci_init(minor); + /* + * Disable IRQ of SCIx + */ + status = sh_set_irq_priority( + Console_Port_Tbl[minor].ulIntVector, 0); + + if(status != RTEMS_SUCCESSFUL) + rtems_fatal_error_occurred(status); + + SH_SCI_REG_MASK(SCI_RIE, minor, SCI_SCR); + + /* + * Catch apropriate vectors + */ + status = rtems_interrupt_catch( + sh_sci_rx_isr, + Console_Port_Tbl[minor].ulIntVector, + &old_isr); + + if(status != RTEMS_SUCCESSFUL) + rtems_fatal_error_occurred(status); + + status = rtems_interrupt_catch( + sh_sci_tx_isr, + Console_Port_Tbl[minor].ulDataPort, + &old_isr); + + if(status != RTEMS_SUCCESSFUL) + rtems_fatal_error_occurred(status); + + /* + * Enable IRQ of SCIx + */ + SH_SCI_REG_FLAG(SCI_RIE, minor, SCI_SCR); + + status = sh_set_irq_priority( + Console_Port_Tbl[minor].ulIntVector, + Console_Port_Tbl[minor].ulCtrlPort2); + + if(status != RTEMS_SUCCESSFUL) + rtems_fatal_error_occurred(status); +} + + +/* + * Open entry point + * Sets up port and pins for selected sci. + */ + +int sh_sci_first_open( + int major, + int minor, + void *arg ) +{ + unsigned8 temp8; + unsigned int a ; + + /* + * check for valid minor number + */ + if(( minor > ( SCI_MINOR_DEVICES -1 )) || ( minor < 0 )) + { + return RTEMS_INVALID_NUMBER; + } + + /* + * set up SCI registers + */ + /* Clear SCR - disable Tx and Rx */ + SH_SCI_REG_DATA(0x00, minor, SCI_SCR); + + /* set SMR and BRR - baudrate and format */ + sh_sci_set_attributes(minor, Console_Port_Tbl[minor].pDeviceParams); + + for(a=0; a < 10000L; a++) { /* Delay */ + asm volatile ("nop"); + } + + write8((SCI_RE | SCI_TE), /* enable async. Tx and Rx */ + Console_Port_Tbl[minor].ulCtrlPort1 + SCI_SCR); + + /* + * clear error flags + */ + temp8 = read8(Console_Port_Tbl[minor].ulCtrlPort1 + SCI_SSR); + while(temp8 & (SCI_RDRF | SCI_ORER | SCI_FER | SCI_PER)) + { + /* flush input */ + temp8 = read8(Console_Port_Tbl[minor].ulCtrlPort1 + SCI_RDR); + + /* clear some flags */ + SH_SCI_REG_FLAG((SCI_RDRF | SCI_ORER | SCI_FER | SCI_PER), minor, SCI_SSR); + + /* check if everything is OK */ + temp8 = read8(Console_Port_Tbl[minor].ulCtrlPort1 + SCI_SSR); + } + + /* Clear RDRF flag */ + SH_SCI_REG_DATA(0x00, minor, SCI_TDR); /* force output */ + + /* Clear the TDRE bit */ + SH_SCI_REG_FLAG(SCI_TDRE, minor, SCI_SSR); + + /* + * Interrupt setup + */ + if(Console_Port_Tbl[minor].pDeviceFns->deviceOutputUsesInterrupts) + { + SH_SCI_REG_FLAG(SCI_RIE, minor, SCI_SCR); + } + + return RTEMS_SUCCESSFUL ; +} + +/* + * Close entry point + */ + +int sh_sci_last_close( + int major, + int minor, + void *arg +) +{ + /* FIXME: Incomplete */ + + /* Shutdown interrupts if necessary */ + if(Console_Port_Tbl[minor].pDeviceFns->deviceOutputUsesInterrupts) + { + SH_SCI_REG_MASK((SCI_TIE | SCI_RIE), minor, SCI_SCR); + } + return RTEMS_SUCCESSFUL ; +} + +/* + * Interrupt aware write routine + */ +int sh_sci_write_support_int( + int minor, + const char *buf, + int len +) +{ + if(!len) + return 0; + /* + * Put data into TDR and clear transmission-end-flag + */ + SH_SCI_REG_DATA(*buf, minor, SCI_TDR); + SH_SCI_REG_MASK(SCI_TDRE, minor, SCI_SSR); + /* + * Enable interrupt + */ + SH_SCI_REG_FLAG(SCI_TIE, minor, SCI_SCR); + + return 1; +} + +/* + * Polled write method + */ +int sh_sci_write_support_polled( + int minor, + const char *buf, + int len +) +{ + int count = 0; + + while(count < len) + { + sh_sci_write_polled(minor, buf[count]); + count++; + } + /* + * Return number of bytes written + */ + return count; +} + +/* + * Polled write of one character at a time + */ +void sh_sci_write_polled( + int minor, + char c +) +{ + /* + * Wait for end of previous character + */ + while(!(read8(Console_Port_Tbl[minor].ulCtrlPort1 + SCI_SSR) & SCI_TDRE)); + /* + * Send the character + */ + SH_SCI_REG_DATA(c, minor, SCI_TDR); + + /* + * Clear TDRE flag + */ + SH_SCI_REG_MASK(SCI_TDRE, minor, SCI_SSR); +} + +/* + * Non-blocking read + */ +int sh_sci_inbyte_nonblocking_polled(int minor) +{ + unsigned8 inbyte; + + /* + * Check if input buffer is full + */ + if(read8(Console_Port_Tbl[minor].ulCtrlPort1 + SCI_SSR) & SCI_RDRF) + { + inbyte = read8(Console_Port_Tbl[minor].ulCtrlPort1 + SCI_RDR); + SH_SCI_REG_MASK(SCI_RDRF, minor, SCI_SSR); + + /* + * Check for errors + */ + if(read8(Console_Port_Tbl[minor].ulCtrlPort1 + SCI_SSR) & + (SCI_ORER | SCI_FER | SCI_PER)) + { + SH_SCI_REG_MASK((SCI_ORER | SCI_FER | SCI_PER), minor, SCI_SSR); + return -1; + } + return (int)inbyte; + } + return -1; +} -- cgit v1.2.3