diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2018-04-19 06:28:01 +0200 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2018-04-20 13:08:32 +0200 |
commit | d7d66d7d4523b904c8ccc6aea3709dc0d5aa5bdc (patch) | |
tree | caa54b4229e86a68c84ab5961af34e087dce5302 /bsps/sh | |
parent | bsps/powerpc: Move shared btimer support (diff) | |
download | rtems-d7d66d7d4523b904c8ccc6aea3709dc0d5aa5bdc.tar.bz2 |
bsps: Move console drivers to bsps
This patch is a part of the BSP source reorganization.
Update #3285.
Diffstat (limited to 'bsps/sh')
-rw-r--r-- | bsps/sh/gensh1/console/sci.c | 358 | ||||
-rw-r--r-- | bsps/sh/gensh2/console/config.c | 130 | ||||
-rw-r--r-- | bsps/sh/gensh2/console/sci.c | 554 | ||||
-rw-r--r-- | bsps/sh/gensh2/console/sci_termios.c | 449 | ||||
-rw-r--r-- | bsps/sh/gensh4/console/console.c | 469 | ||||
-rw-r--r-- | bsps/sh/gensh4/console/sh4uart.c | 910 | ||||
-rw-r--r-- | bsps/sh/shsim/console/console-debugio.c | 33 | ||||
-rw-r--r-- | bsps/sh/shsim/console/console-io.c | 57 | ||||
-rw-r--r-- | bsps/sh/shsim/console/console-support.S | 18 |
9 files changed, 2978 insertions, 0 deletions
diff --git a/bsps/sh/gensh1/console/sci.c b/bsps/sh/gensh1/console/sci.c new file mode 100644 index 0000000000..04d9ca5c70 --- /dev/null +++ b/bsps/sh/gensh1/console/sci.c @@ -0,0 +1,358 @@ +/* + * /dev/sci[0|1] for Hitachi SH 703X + * + * Author: Ralf Corsepius (corsepiu@faw.uni-ulm.de) + * + * COPYRIGHT (c) 1997-1999, Ralf Corsepius, Ulm, Germany + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * + * COPYRIGHT (c) 1998. + * 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.rtems.org/license/LICENSE. + */ + +#include <rtems.h> + +#include <stdlib.h> + +#include <rtems/libio.h> +#include <rtems/iosupp.h> +#include <rtems/score/sh_io.h> +#include <rtems/score/ispsh7032.h> +#include <rtems/score/iosh7032.h> +#include <sh/sh7_sci.h> +#include <sh/sh7_pfc.h> +#include <sh/sci.h> + +/* + * NOTE: Some SH variants have 3 sci devices + */ + +#define SCI_MINOR_DEVICES 2 + +#define SH_SCI_BASE_0 SCI0_SMR +#define SH_SCI_BASE_1 SCI1_SMR + +struct scidev_t { + char * name ; + uint32_t addr ; + rtems_device_minor_number minor ; + unsigned short opened ; + tcflag_t cflags ; + speed_t spd ; +} sci_device[SCI_MINOR_DEVICES] = +{ + { "/dev/sci0", SH_SCI_BASE_0, 0, 0, CS8, B9600 }, + { "/dev/sci1", SH_SCI_BASE_1, 1, 0, CS8, B9600 } +} ; + +/* imported from scitab.rel */ +extern int _sci_get_brparms( + speed_t spd, + unsigned char *smr, + unsigned char *brr ); + +/* Translate termios' tcflag_t into sci settings */ +static int _sci_set_cflags( + struct scidev_t *sci_dev, + tcflag_t c_cflag, + speed_t spd ) +{ + uint8_t smr ; + uint8_t brr ; + + if ( spd ) + { + if ( _sci_get_brparms( spd, &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; + + write8( smr, sci_dev->addr + SCI_SMR ); + write8( brr, sci_dev->addr + SCI_BRR ); + + return 0 ; +} + +static void _sci_init( + rtems_device_minor_number minor ) +{ + uint16_t temp16 ; + + /* Pin function controller initialisation for asynchronous mode */ + if( minor == 0) + { + temp16 = read16( PFC_PBCR1); + temp16 &= ~( PB8MD | PB9MD ); + temp16 |= (PB_TXD0 | PB_RXD0); + write16( temp16, PFC_PBCR1); + } + else + { + temp16 = read16( PFC_PBCR1); + temp16 &= ~( PB10MD | PB11MD); + temp16 |= (PB_TXD1 | PB_RXD1); + write16( temp16, PFC_PBCR1); + } + + /* disable sck-pin */ + if( minor == 0) + { + temp16 = read16( PFC_PBCR1); + temp16 &= ~(PB12MD); + write16( temp16, PFC_PBCR1); + } + else + { + temp16 = read16( PFC_PBCR1); + temp16 &= ~(PB13MD); + write16( temp16, PFC_PBCR1); + } +} + +static void _sci_tx_polled( + int minor, + const char buf ) +{ + struct scidev_t *scidev = &sci_device[minor] ; + int8_t ssr ; + + while ( !inb((scidev->addr + SCI_SSR) & SCI_TDRE )) + ; + write8(buf,scidev->addr+SCI_TDR); + + ssr = inb(scidev->addr+SCI_SSR); + ssr &= ~SCI_TDRE ; + write8(ssr,scidev->addr+SCI_SSR); +} + +static int _sci_rx_polled ( + int minor) +{ + struct scidev_t *scidev = &sci_device[minor] ; + + unsigned char c; + char ssr ; + ssr = read8(scidev->addr + SCI_SSR) ; + + if (ssr & (SCI_PER | SCI_FER | SCI_ORER)) + write8(ssr & ~(SCI_PER | SCI_FER | SCI_ORER), scidev->addr+SCI_SSR); + + if ( !(ssr & SCI_RDRF) ) + return -1; + + c = read8(scidev->addr + SCI_RDR) ; + + write8(ssr & ~SCI_RDRF,scidev->addr + SCI_SSR); + return c; +} + +/* + * sci_initialize + */ + +rtems_device_driver sh_sci_initialize( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg ) +{ + rtems_device_driver status ; + rtems_device_minor_number i; + + /* + * register all possible devices. + * the initialization of the hardware is done by sci_open + */ + + for ( i = 0 ; i < SCI_MINOR_DEVICES ; i++ ) + { + status = rtems_io_register_name( + sci_device[i].name, + major, + sci_device[i].minor ); + if (status != RTEMS_SUCCESSFUL) + rtems_fatal_error_occurred(status); + } + + /* default hardware setup */ + + return RTEMS_SUCCESSFUL; +} + + +/* + * Open entry point + */ + +rtems_device_driver sh_sci_open( + rtems_device_major_number major, + rtems_device_minor_number minor, + void * arg ) +{ + uint8_t temp8; + + /* check for valid minor number */ + if(( minor > ( SCI_MINOR_DEVICES -1 )) || ( minor < 0 )) + { + return RTEMS_INVALID_NUMBER; + } + + /* device already opened */ + if ( sci_device[minor].opened > 0 ) + { + sci_device[minor].opened++ ; + return RTEMS_SUCCESSFUL ; + } + + _sci_init( minor ); + + if (minor == 0) { + temp8 = read8(sci_device[minor].addr + SCI_SCR); + temp8 &= ~(SCI_TE | SCI_RE) ; + write8(temp8, sci_device[minor].addr + SCI_SCR); /* Clear SCR */ + _sci_set_cflags( &sci_device[minor], sci_device[minor].cflags, sci_device[minor].spd ); + +/* FIXME: Should be one bit delay */ + CPU_delay(50000); /* microseconds */ + + temp8 |= SCI_RE | SCI_TE; + write8(temp8, sci_device[minor].addr + SCI_SCR); /* Enable clock output */ + } else { + temp8 = read8(sci_device[minor].addr + SCI_SCR); + temp8 &= ~(SCI_TE | SCI_RE) ; + write8(temp8, sci_device[minor].addr + SCI_SCR); /* Clear SCR */ + _sci_set_cflags( &sci_device[minor], sci_device[minor].cflags, sci_device[minor].spd ); + +/* FIXME: Should be one bit delay */ + CPU_delay(50000); /* microseconds */ + + temp8 |= SCI_RE | SCI_TE; + write8(temp8, sci_device[minor].addr + SCI_SCR); /* Enable clock output */ + } + + sci_device[minor].opened++ ; + + return RTEMS_SUCCESSFUL ; +} + +/* + * Close entry point + */ + +rtems_device_driver sh_sci_close( + rtems_device_major_number major, + rtems_device_minor_number minor, + void * arg +) +{ + if( sci_device[minor].opened == 0 ) + { + return RTEMS_INVALID_NUMBER; + } + + sci_device[minor].opened-- ; + + return RTEMS_SUCCESSFUL ; +} + +/* + * read bytes from the serial port. + */ + +rtems_device_driver sh_sci_read( + rtems_device_major_number major, + rtems_device_minor_number minor, + void * arg +) +{ + int count = 0; + + rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t *) arg; + char * buffer = rw_args->buffer; + int maximum = rw_args->count; + + for (count = 0; count < maximum; count++) { + buffer[ count ] = _sci_rx_polled(minor); + if (buffer[ count ] == '\n' || buffer[ count ] == '\r') { + buffer[ count++ ] = '\n'; + break; + } + } + + rw_args->bytes_moved = count; + return (count >= 0) ? RTEMS_SUCCESSFUL : RTEMS_UNSATISFIED; +} + +/* + * write bytes to the serial port. + */ + +rtems_device_driver sh_sci_write( + rtems_device_major_number major, + rtems_device_minor_number minor, + void * arg +) +{ + int count; + + rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t *) arg; + char *buffer = rw_args->buffer; + int maximum = rw_args->count; + + for (count = 0; count < maximum; count++) { +#if 0 + if ( buffer[ count ] == '\n') { + outbyte(minor, '\r'); + } +#endif + _sci_tx_polled( minor, buffer[ count ] ); + } + + rw_args->bytes_moved = maximum; + return 0; +} + +/* + * IO Control entry point + */ + +rtems_device_driver sh_sci_control( + rtems_device_major_number major, + rtems_device_minor_number minor, + void * arg +) +{ + /* Not yet supported */ + return RTEMS_SUCCESSFUL ; +} diff --git a/bsps/sh/gensh2/console/config.c b/bsps/sh/gensh2/console/config.c new file mode 100644 index 0000000000..a2f25742dd --- /dev/null +++ b/bsps/sh/gensh2/console/config.c @@ -0,0 +1,130 @@ +/* + * This file contains the TTY driver table. The implementation is + * based on libchip/serial drivers, but it uses internal SHx SCI so + * the implementation of the driver is placed in + * lib/libcpu/sh/sh7045/sci instead of libchip/serial. + * + * 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.rtems.org/license/LICENSE. + * + */ + +#include <bsp.h> +#include <libchip/serial.h> +#include <libchip/sersupp.h> +#include <sh/sci_termios.h> +#include <rtems/score/sh_io.h> +#include <rtems/score/ispsh7045.h> +#include <rtems/score/iosh7045.h> +#include <rtems/termiostypes.h> + +/* + * Function set for interrupt enabled termios console + */ +const console_fns sh_sci_fns = +{ + libchip_serial_default_probe, /* deviceProbe */ + sh_sci_first_open, /* deviceFirstOpen */ + NULL, /* deviceLastClose */ + NULL, /* deviceRead */ + sh_sci_write_support_int, /* deviceWrite */ + sh_sci_initialize_interrupts, /* deviceInitialize */ + sh_sci_write_polled, /* deviceWritePolled */ + sh_sci_set_attributes, /* deviceSetAttributes */ + TERMIOS_IRQ_DRIVEN /* deviceOutputUsesInterrupts */ +}; + +/* + * Function set for polled termios console + */ +const console_fns sh_sci_fns_polled = +{ + libchip_serial_default_probe, /* deviceProbe */ + sh_sci_first_open, /* deviceFirstOpen */ + sh_sci_last_close, /* deviceLastClose */ + sh_sci_inbyte_nonblocking_polled, /* deviceRead */ + sh_sci_write_support_polled, /* deviceWrite */ + sh_sci_init, /* deviceInitialize */ + sh_sci_write_polled, /* deviceWritePolled */ + sh_sci_set_attributes, /* deviceSetAttributes */ + TERMIOS_POLLED /* deviceOutputUsesInterrupts */ +}; + +#if 1 /* (CONSOLE_USE_INTERRUPTS) */ +#define SCI_FUNCTIONS &sh_sci_fns +#else +#define SCI_FUNCTIONS &sh_sci_fns_polled +#endif + +static const struct termios term1 = { + 0, + 0, + 0, + 0, + {0}, + B9600 | CS8, + B9600 | CS8 +}; + +static const struct termios term2 = { + 0, + 0, + 0, + 0, + {0}, + B115200 | CS8, + B115200 | CS8 +}; + +console_tbl Console_Configuration_Ports[] = { + { + "/dev/sci0", /* sDeviceName */ + SERIAL_CUSTOM, /* deviceType */ + SCI_FUNCTIONS, /* pDeviceFns */ + NULL, /* deviceProbe */ + NULL, /* pDeviceFlow */ + 16, /* ulMargin */ + 8, /* ulHysteresis */ + (void *)&term1, /* baud rate */ /* pDeviceParams */ + SCI_SMR0, /* ulCtrlPort1 */ + 3, /* ulCtrlPort2 as IRQ priority level*/ + TXI0_ISP_V, /* ulDataPort as TX end vector number*/ + NULL, /* unused */ /* getRegister */ + NULL, /* unused */ /* setRegister */ + NULL, /* unused */ /* getData */ + NULL, /* unused */ /* setData */ + 0, /* ulClock */ + RXI0_ISP_V, /* ulIntVector as RX end vector number*/ + }, + { + "/dev/sci1", /* sDeviceName */ + SERIAL_CUSTOM, /* deviceType */ + SCI_FUNCTIONS, /* pDeviceFns */ + NULL, /* deviceProbe */ + NULL, /* pDeviceFlow */ + 16, /* ulMargin */ + 8, /* ulHysteresis */ + (void *)&term2, /* baud rate */ /* pDeviceParams */ + SCI_SMR1, /* ulCtrlPort1 */ + 3, /* ulCtrlPort2 as IRQ priority level*/ + TXI1_ISP_V, /* ulDataPort as TX end vector number*/ + NULL, /* unused */ /* getRegister */ + NULL, /* unused */ /* setRegister */ + NULL, /* unused */ /* getData */ + NULL, /* unused */ /* setData */ + 0, /* ulClock */ + RXI1_ISP_V, /* ulIntVector as RX end vector number*/ + } +}; + +/* + * Declare some information used by the console driver + */ + +#define NUM_CONSOLE_PORTS (sizeof(Console_Configuration_Ports)/sizeof(console_tbl)) + +unsigned long Console_Configuration_Count = NUM_CONSOLE_PORTS; diff --git a/bsps/sh/gensh2/console/sci.c b/bsps/sh/gensh2/console/sci.c new file mode 100644 index 0000000000..143fc1bb94 --- /dev/null +++ b/bsps/sh/gensh2/console/sci.c @@ -0,0 +1,554 @@ +/* + * /dev/sci[0|1] for Hitachi SH 704X + * + * The SH doesn't have a designated console device. Therefore we "alias" + * another device as /dev/console and revector all calls to /dev/console + * to this device. + * + * This approach is similar to installing a sym-link from one device to + * another device. If rtems once will support sym-links for devices files, + * this implementation could be dropped. + */ + +/* + * Author: Ralf Corsepius (corsepiu@faw.uni-ulm.de) + * + * COPYRIGHT (c) 1997-1998, FAW Ulm, Germany + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * + * COPYRIGHT (c) 1998. + * 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.rtems.org/license/LICENSE. + * + * Modified to reflect sh7045 processor: + * John M. Mills (jmills@tga.com) + * TGA Technologies, Inc. + * 100 Pinnacle Way, Suite 140 + * Norcross, GA 30071 U.S.A. + * + * This modified file may be copied and distributed in accordance + * the above-referenced license. It is provided for critique and + * developmental purposes without any warranty nor representation + * by the authors or by TGA Technologies. + */ + +#include <bsp.h> + + +#include <stdlib.h> + +#include <rtems/libio.h> +#include <rtems/iosupp.h> +#include <rtems/score/sh_io.h> +#include <rtems/score/ispsh7045.h> +#include <rtems/score/iosh7045.h> +#include <sh/sh7_sci.h> +#include <sh/sh7_pfc.h> + +#include <sh/sci.h> + +#ifndef STANDALONE_EVB +#define STANDALONE_EVB 0 +#endif + +/* + * NOTE: Some SH variants have 3 sci devices + */ + +#define SCI_MINOR_DEVICES 2 + +/* + * FIXME: sh7045 register names match Hitachi data book, + * but conflict with RTEMS sh7032 usage. + */ + +#define SH_SCI_BASE_0 SCI_SMR0 +#define SH_SCI_BASE_1 SCI_SMR1 + +#define SH_SCI_DEF_COMM_0 CS8, B9600 +#define SH_SCI_DEF_COMM_1 CS8, B38400 +/* #define SH_SCI_DEF_COMM_1 CS8, B9600 */ + +struct scidev_t { + char * name; + uint32_t addr; + rtems_device_minor_number minor; + unsigned short opened; + tcflag_t cflags; + speed_t spd; +} sci_device[SCI_MINOR_DEVICES] = +{ + { "/dev/sci0", SH_SCI_BASE_0, 0, 0, SH_SCI_DEF_COMM_0 }, + { "/dev/sci1", SH_SCI_BASE_1, 1, 0, SH_SCI_DEF_COMM_1 } +}; + +/* local data structures maintain hardware configuration */ +#if UNUSED +static sci_setup_t sio_param[2]; +#endif + +/* Translate termios' tcflag_t into sci settings */ +static int _sci_set_cflags( + struct scidev_t *sci_dev, + tcflag_t c_cflag, + speed_t spd +) +{ + uint8_t smr; + uint8_t brr; + + if ( spd ) + { + if ( _sci_get_brparms( spd, &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; + + write8( smr, sci_dev->addr + SCI_SMR ); + write8( brr, sci_dev->addr + SCI_BRR ); + + return 0; +} + +/* + * local functions operate SCI ports 0 and 1 + * called from polling routines or ISRs + */ +static bool wrtSCI0(unsigned char ch) +{ + uint8_t temp; + bool result = false; + + if ((read8(SCI_SSR0) & SCI_TDRE) != 0x00) { + /* Write the character to the TDR */ + write8(ch, SCI_TDR0); + /* Clear the TDRE bit */ + temp = read8(SCI_SSR0) & ~SCI_TDRE; + write8(temp, SCI_SSR0); + result = true; + } + return result; +} /* wrtSCI0 */ + +static bool wrtSCI1(unsigned char ch) +{ + uint8_t temp; + bool result = false; + + if ((read8(SCI_SSR1) & SCI_TDRE) != 0x00) { + /* Write the character to the TDR */ + write8(ch, SCI_TDR1); + /* Clear the TDRE bit */ + temp = read8(SCI_SSR1) & ~SCI_TDRE; + write8(temp, SCI_SSR1); + result = true; + } + return result; +} /* wrtSCI1 */ + +/* polled output steers byte to selected port */ +static void sh_sci_outbyte_polled( + rtems_device_minor_number minor, + char ch ) +{ + if (minor == 0) /* blocks until port ready */ + while (wrtSCI0(ch) != true); /* SCI0*/ + else + while (wrtSCI1(ch) != true); /* SCI1*/ +} /* sh_sci_outbyte_polled */ + +/* + * Initial version calls polled output driver and blocks + */ +static void outbyte( + rtems_device_minor_number minor, + char ch) +{ + sh_sci_outbyte_polled(minor, (unsigned char)ch); +} /* outbyte */ + +static bool rdSCI0(unsigned char *ch) +{ + uint8_t temp; + bool result = false; + + if ((read8(SCI_SSR0) & SCI_RDRF) != 0x00) { + /* read input */ + *ch = read8(SCI_RDR0); + /* Clear RDRF flag */ + temp = read8(SCI_SSR0) & ~SCI_RDRF; + write8(temp, SCI_SSR0); + /* Check for transmission errors */ + if (temp & (SCI_ORER | SCI_FER | SCI_PER)) { + /* TODO: report to RTEMS transmission error */ + + /* clear error flags*/ + temp &= ~(SCI_ORER | SCI_FER | SCI_PER); + write8(temp, SCI_SSR0); + } + result = true; + } + return result; +} /* rdSCI0 */ + +static bool rdSCI1(unsigned char *ch) +{ + uint8_t temp; + bool result = false; + + if ((read8(SCI_SSR1) & SCI_RDRF) != 0x00) { + /* read input */ + *ch = read8(SCI_RDR1); + /* Clear RDRF flag */ + temp= read8(SCI_SSR1) & ~SCI_RDRF; + write8(temp, SCI_SSR1); + /* Check for transmission errors */ + if (temp & (SCI_ORER | SCI_FER | SCI_PER)) { + /* TODO: report to RTEMS transmission error */ + + /* clear error flags*/ + temp &= ~(SCI_ORER | SCI_FER | SCI_PER); + write8(temp, SCI_SSR1); + } + result = true; + } + return result; +} /* rdSCI1 */ + +/* initial version pulls byte from selected port */ +static char sh_sci_inbyte_polled( rtems_device_minor_number minor ) +{ + uint8_t ch = 0; + + if (minor == 0) /* blocks until char.ready */ + while (rdSCI0(&ch) != true); /* SCI0 */ + else + while (rdSCI1(&ch) != true); /* SCI1 */ + return ch; +} /* sh_sci_inbyte_polled */ + +/* Initial version calls polled input driver */ +static char inbyte( rtems_device_minor_number minor ) +{ + char ch; + + ch = sh_sci_inbyte_polled(minor); + return ch; +} /* inbyte */ + +/* sh_sci_initialize + * + * This routine initializes (registers) the sh_sci IO drivers. + * + * Input parameters: ignored + * + * Output parameters: NONE + * + * Return values: RTEMS_SUCCESSFUL + * if all sci[...] register, else calls + * rtems_fatal_error_occurred(status) + */ +rtems_device_driver sh_sci_initialize( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg ) +{ + rtems_device_driver status; + rtems_device_minor_number i; + + /* + * register all possible devices. + * the initialization of the hardware is done by sci_open + * + * One of devices could be previously registered by console + * initialization therefore we check it everytime + */ + for ( i = 0 ; i < SCI_MINOR_DEVICES ; i++ ) { + /* OK. We assume it is not registered yet. */ + status = rtems_io_register_name( + sci_device[i].name, + major, + sci_device[i].minor + ); + if (status != RTEMS_SUCCESSFUL) + rtems_fatal_error_occurred(status); + } + + /* non-default hardware setup occurs in sh_sci_open() */ + return RTEMS_SUCCESSFUL; +} + +/* + * Open entry point + * Sets up port and pins for selected sci. + */ +rtems_device_driver sh_sci_open( + rtems_device_major_number major, + rtems_device_minor_number minor, + void * arg ) +{ + uint8_t temp8; + uint16_t temp16; + + unsigned a; + + /* check for valid minor number */ + if (( minor > ( SCI_MINOR_DEVICES -1 )) || ( minor < 0 )) { + return RTEMS_INVALID_NUMBER; + } + + /* device already opened */ + if ( sci_device[minor].opened > 0 ) { + sci_device[minor].opened++; + return RTEMS_SUCCESSFUL; + } + + /* 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); + + } /* add other devices and pins as req'd. */ + + /* set up SCI registers */ + write8(0x00, sci_device[minor].addr + SCI_SCR); /* Clear SCR */ + /* set SMR and BRR */ + _sci_set_cflags( &sci_device[minor], sci_device[minor].cflags, sci_device[minor].spd ); + + for (a=0; a < 10000L; a++) { /* Delay */ + __asm__ volatile ("nop"); + } + + write8((SCI_RE | SCI_TE), /* enable async. Tx and Rx */ + sci_device[minor].addr + SCI_SCR); + + /* clear error flags */ + temp8 = read8(sci_device[minor].addr + SCI_SSR); + while (temp8 & (SCI_RDRF | SCI_ORER | SCI_FER | SCI_PER)) { + temp8 = read8(sci_device[minor].addr + SCI_RDR); /* flush input */ + temp8 = read8(sci_device[minor].addr + SCI_SSR); /* clear some flags */ + write8(temp8 & ~(SCI_RDRF | SCI_ORER | SCI_FER | SCI_PER), + sci_device[minor].addr + SCI_SSR); + temp8 = read8(sci_device[minor].addr + SCI_SSR); /* check if everything is OK */ + } + /* Clear RDRF flag */ + write8(0x00, sci_device[minor].addr + SCI_TDR); /* force output */ + /* Clear the TDRE bit */ + temp8 = read8(sci_device[minor].addr + SCI_SSR) & ~SCI_TDRE; + write8(temp8, sci_device[minor].addr + SCI_SSR); + + /* add interrupt setup if required */ + + + sci_device[minor].opened++; + + return RTEMS_SUCCESSFUL; +} + +/* + * Close entry point + */ +rtems_device_driver sh_sci_close( + rtems_device_major_number major, + rtems_device_minor_number minor, + void * arg +) +{ + /* FIXME: Incomplete */ + if ( sci_device[minor].opened > 0 ) + sci_device[minor].opened--; + else + return RTEMS_INVALID_NUMBER; + + return RTEMS_SUCCESSFUL; +} + +/* + * read bytes from the serial port. We only have stdin. + */ +rtems_device_driver sh_sci_read( + rtems_device_major_number major, + rtems_device_minor_number minor, + void * arg +) +{ + rtems_libio_rw_args_t *rw_args; + char *buffer; + int maximum; + int count = 0; + + rw_args = (rtems_libio_rw_args_t *) arg; + + buffer = rw_args->buffer; + maximum = rw_args->count; + + for (count = 0; count < maximum; count++) { + buffer[ count ] = inbyte(minor); + if (buffer[ count ] == '\n' || buffer[ count ] == '\r') { + buffer[ count++ ] = '\n'; + break; + } + } + + rw_args->bytes_moved = count; + return (count >= 0) ? RTEMS_SUCCESSFUL : RTEMS_UNSATISFIED; +} + +/* + * write bytes to the serial port. Stdout and stderr are the same. + */ +rtems_device_driver sh_sci_write( + rtems_device_major_number major, + rtems_device_minor_number minor, + void * arg +) +{ + int count; + int maximum; + rtems_libio_rw_args_t *rw_args; + char *buffer; + + rw_args = (rtems_libio_rw_args_t *) arg; + + buffer = rw_args->buffer; + maximum = rw_args->count; + + for (count = 0; count < maximum; count++) { + if ( buffer[ count ] == '\n') { + outbyte(minor, '\r'); + } + outbyte( minor, buffer[ count ] ); + } + + rw_args->bytes_moved = maximum; + return 0; +} + +/* + * IO Control entry point + */ +rtems_device_driver sh_sci_control( + rtems_device_major_number major, + rtems_device_minor_number minor, + void * arg +) +{ + /* Not yet supported */ + return RTEMS_SUCCESSFUL; +} + +/* + * Termios polled first open + */ +static int _sh_sci_poll_first_open(int major, int minor, void *arg) +{ + return sh_sci_open(major, minor, arg); +} + +/* + * Termios general last close + */ +static int _sh_sci_last_close(int major, int minor, void *arg) +{ + return sh_sci_close(major, minor, arg); +} + +/* + * Termios polled read + */ +static int _sh_sci_poll_read(int minor) +{ + int value = -1; + uint8_t ch = 0; + + if ( minor == 0 ) { + if ( rdSCI0( &ch ) ) + value = (int) ch; + } else if ( minor == 1 ) { + if ( rdSCI1( &ch ) ) + value = (int) ch; + } + return value; +} + +/* + * Termios polled write + */ +static ssize_t _sh_sci_poll_write(int minor, const char *buf, size_t len) +{ + size_t count; + + for (count = 0; count < len; count++) + outbyte( minor, buf[count] ); + return count; +} + +/* + * Termios set attributes + */ +static int _sh_sci_set_attributes( int minor, const struct termios *t) +{ + return _sci_set_cflags( &sci_device[ minor ], t->c_cflag, t->c_ospeed); +} + + +const rtems_termios_callbacks sci_poll_callbacks = { + _sh_sci_poll_first_open, /* FirstOpen*/ + _sh_sci_last_close, /* LastClose*/ + _sh_sci_poll_read, /* PollRead */ + _sh_sci_poll_write, /* Write */ + _sh_sci_set_attributes, /* setAttributes */ + NULL, /* stopRemoteTX */ + NULL, /* StartRemoteTX */ + 0 /* outputUsesInterrupts */ +}; + +/* FIXME: not yet supported */ +const rtems_termios_callbacks sci_interrupt_callbacks; + +const rtems_termios_callbacks* sh_sci_get_termios_handlers( bool poll ) +{ + return poll ? + &sci_poll_callbacks : + &sci_interrupt_callbacks; +} diff --git a/bsps/sh/gensh2/console/sci_termios.c b/bsps/sh/gensh2/console/sci_termios.c new file mode 100644 index 0000000000..5d588065af --- /dev/null +++ b/bsps/sh/gensh2/console/sci_termios.c @@ -0,0 +1,449 @@ +/* + * Termios console serial driver. + */ + +/* + * Based on SCI driver by Ralf Corsepius and John M. Mills + * + * Author: Radzislaw Galler <rgaller@et.put.poznan.pl> + * + * 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.rtems.org/license/LICENSE. + * + */ + +#include <bsp.h> +#include <stdlib.h> + +#include <libchip/serial.h> +#include <libchip/sersupp.h> + +#include <rtems/libio.h> +#include <rtems/iosupp.h> + +#include <rtems/score/sh_io.h> +#include <rtems/score/ispsh7045.h> +#include <rtems/score/iosh7045.h> + +#include <sh/sh7_sci.h> +#include <sh/sh7_pfc.h> +#include <sh/sci_termios.h> + + +/* + * 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( + speed_t spd, + unsigned char *smr, + unsigned char *brr +); + +/* + * Translate termios flags into SCI settings + */ +int sh_sci_set_attributes( + int minor, + const struct termios *t +) +{ + uint8_t smr; + uint8_t brr; + int a; + + tcflag_t c_cflag = t->c_cflag; + speed_t spd = t->c_ospeed; + + if ( spd ) { + if ( _sci_get_brparms( spd, &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. + */ +static 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) { + char 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, &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. + */ +static 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) +{ + uint16_t 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 +) +{ + char 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 + */ +ssize_t sh_sci_write_support_int( + int minor, + const char *buf, + size_t 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 + */ +ssize_t sh_sci_write_support_polled( + int minor, + const char *buf, + size_t 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) +{ + char 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; +} diff --git a/bsps/sh/gensh4/console/console.c b/bsps/sh/gensh4/console/console.c new file mode 100644 index 0000000000..917556df4e --- /dev/null +++ b/bsps/sh/gensh4/console/console.c @@ -0,0 +1,469 @@ +/* + * Console driver for SH-4 UART modules + * + * Copyright (C) 2000 OKTET Ltd., St.-Petersburg, Russia + * Author: Alexandra Kossovsky <sasha@oktet.ru> + * + * COPYRIGHT (c) 1989-1998. + * 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.rtems.org/license/LICENSE. + */ + +#include <termios.h> + +#include <rtems/console.h> +#include <rtems/libio.h> +#include <bsp.h> + +#include "sh/sh4uart.h" + +/* Descriptor structures for two on-chip UART channels */ +sh4uart sh4_uarts[2]; + +/* Console operations mode: + * 0 - raw (non-termios) polled input/output + * 1 - termios-based polled input/output + * 2 - termios-based interrupt-driven input/output + * 3 - non-termios over gdb stub + */ +int console_mode = 3; +#define CONSOLE_MODE_RAW (0) +#define CONSOLE_MODE_POLL (1) +#define CONSOLE_MODE_INT (2) +#define CONSOLE_MODE_IPL (3) + +/* Wrapper functions for SH-4 UART generic driver */ + +/* console_poll_read -- + * wrapper for poll read function + * + * PARAMETERS: + * minor - minor device number + * + * RETURNS: + * character code readed from UART, or -1 if there is no characters + * available + */ +static int +console_poll_read(int minor) +{ + return sh4uart_poll_read(&sh4_uarts[minor]); +} + +/* console_interrupt_write -- + * wrapper for interrupt write function + * + * PARAMETERS: + * minor - minor device number + * buf - output buffer + * len - output buffer length + * + * RETURNS: + * result code + */ +static ssize_t +console_interrupt_write(int minor, const char *buf, size_t len) +{ + return sh4uart_interrupt_write(&sh4_uarts[minor], buf, len); +} + +/* console_poll_write -- + * wrapper for polling mode write function + * + * PARAMETERS: + * minor - minor device number + * buf - output buffer + * len - output buffer length + * + * RETURNS: + * result code + */ +static ssize_t +console_poll_write(int minor, const char *buf, size_t len) +{ + return sh4uart_poll_write(&sh4_uarts[minor], buf, len); +} + +/* console_set_attributes -- + * wrapper for hardware-dependent termios attributes setting + * + * PARAMETERS: + * minor - minor device number + * t - pointer to the termios structure + * + * RETURNS: + * result code + */ +static int +console_set_attributes(int minor, const struct termios *t) +{ + return sh4uart_set_attributes(&sh4_uarts[minor], t); +} + +/* console_stop_remote_tx -- + * wrapper for stopping data flow from remote party. + * + * PARAMETERS: + * minor - minor device number + * + * RETURNS: + * result code + */ +static int +console_stop_remote_tx(int minor) +{ + if (minor < sizeof(sh4_uarts)/sizeof(sh4_uarts[0])) + return sh4uart_stop_remote_tx(&sh4_uarts[minor]); + else + return RTEMS_INVALID_NUMBER; +} + +/* console_start_remote_tx -- + * wrapper for resuming data flow from remote party. + * + * PARAMETERS: + * minor - minor device number + * + */ +static int +console_start_remote_tx(int minor) +{ + if (minor < sizeof(sh4_uarts)/sizeof(sh4_uarts[0])) + return sh4uart_start_remote_tx(&sh4_uarts[minor]); + else + return RTEMS_INVALID_NUMBER; +} + +/* console_first_open -- + * wrapper for UART controller initialization functions + * + * PARAMETERS: + * major - major device number + * minor - minor device number + * arg - libio device open argument + * + * RETURNS: + * error code + */ +static int +console_first_open(int major, int minor, void *arg) +{ + rtems_libio_open_close_args_t *args = arg; + rtems_status_code sc; + + sc = sh4uart_init(&sh4_uarts[minor], /* uart */ + args->iop->data1, /* tty */ + minor+1, /* channel */ + (console_mode == CONSOLE_MODE_INT)); + + if (sc == RTEMS_SUCCESSFUL) + sc = sh4uart_reset(&sh4_uarts[minor]); + + return sc; +} + +/* console_last_close -- + * wrapper for UART controller close function + * + * PARAMETERS: + * major - major device number + * minor - minor device number + * arg - libio device close argument + * + * RETURNS: + * error code + */ +static int +console_last_close(int major, int minor, void *arg) +{ + if (console_mode != CONSOLE_MODE_IPL) + /* working from gdb we should not disable port operations */ + return sh4uart_disable(&sh4_uarts[minor], + !(boot_mode == SH4_BOOT_MODE_IPL)); + else + return RTEMS_SUCCESSFUL; +} + +/* console_initialize -- + * This routine initializes the console IO drivers and register devices + * in RTEMS I/O system. + * + * PARAMETERS: + * major - major console device number + * minor - minor console device number (not used) + * arg - device initialize argument + * + * RETURNS: + * RTEMS error code (RTEMS_SUCCESSFUL if device initialized successfuly) + */ +rtems_device_driver +console_initialize(rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg) +{ + rtems_status_code status; + +#ifdef SH4_WITH_IPL + /* booting from flash we cannot have IPL console */ + if (boot_mode != SH4_BOOT_MODE_IPL && console_mode == CONSOLE_MODE_IPL) + console_mode = CONSOLE_MODE_INT; + + /* break out from gdb if neccessary */ + if (boot_mode == SH4_BOOT_MODE_IPL && console_mode != CONSOLE_MODE_IPL) + ipl_finish(); +#endif + + /* + * Set up TERMIOS + */ + if ((console_mode != CONSOLE_MODE_RAW) && + (console_mode != CONSOLE_MODE_IPL)) + rtems_termios_initialize (); + + /* + * Register the devices + */ + status = rtems_io_register_name ("/dev/console", major, 0); + if (status != RTEMS_SUCCESSFUL) + rtems_fatal_error_occurred (status); + + status = rtems_io_register_name ("/dev/aux", major, 1); + if (status != RTEMS_SUCCESSFUL) + rtems_fatal_error_occurred (status); + + if (console_mode == CONSOLE_MODE_RAW) + { + rtems_status_code sc; + sc = sh4uart_init(&sh4_uarts[0], /* uart */ + NULL, /* tty */ + 1, /* UART channel number */ + 0); /* Poll-mode */ + + if (sc == RTEMS_SUCCESSFUL) + sc = sh4uart_reset(&sh4_uarts[0]); + + sc = sh4uart_init(&sh4_uarts[1], /* uart */ + NULL, /* tty */ + 2, /* UART channel number */ + 0); /* Poll-mode */ + + if (sc == RTEMS_SUCCESSFUL) + sc = sh4uart_reset(&sh4_uarts[1]); + + return sc; + } + + return RTEMS_SUCCESSFUL; +} + +/* console_open -- + * Open console device driver. Pass appropriate termios callback + * functions to termios library. + * + * PARAMETERS: + * major - major device number for console devices + * minor - minor device number for console + * arg - device opening argument + * + * RETURNS: + * RTEMS error code + */ +rtems_device_driver +console_open(rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg) +{ + static const rtems_termios_callbacks intr_callbacks = { + console_first_open, /* firstOpen */ + console_last_close, /* lastClose */ + NULL, /* pollRead */ + console_interrupt_write, /* write */ + console_set_attributes, /* setAttributes */ + console_stop_remote_tx, /* stopRemoteTx */ + console_start_remote_tx, /* startRemoteTx */ + 1 /* outputUsesInterrupts */ + }; + static const rtems_termios_callbacks poll_callbacks = { + console_first_open, /* firstOpen */ + console_last_close, /* lastClose */ + console_poll_read, /* pollRead */ + console_poll_write, /* write */ + console_set_attributes, /* setAttributes */ + console_stop_remote_tx, /* stopRemoteTx */ + console_start_remote_tx, /* startRemoteTx */ + 0 /* outputUsesInterrupts */ + }; + + switch (console_mode) + { + case CONSOLE_MODE_RAW: + case CONSOLE_MODE_IPL: + return RTEMS_SUCCESSFUL; + + case CONSOLE_MODE_INT: + return rtems_termios_open(major, minor, arg, &intr_callbacks); + + case CONSOLE_MODE_POLL: + return rtems_termios_open(major, minor, arg, &poll_callbacks); + + default: + rtems_fatal_error_occurred(0xC07A1310); + } + + return RTEMS_INTERNAL_ERROR; +} + +/* console_close -- + * Close console device. + * + * PARAMETERS: + * major - major device number for console devices + * minor - minor device number for console + * arg - device close argument + * + * RETURNS: + * RTEMS error code + */ +rtems_device_driver +console_close(rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg) +{ + if ((console_mode != CONSOLE_MODE_RAW) && + (console_mode != CONSOLE_MODE_IPL)) + return rtems_termios_close (arg); + else + return RTEMS_SUCCESSFUL; +} + +/* console_read -- + * Read from the console device + * + * PARAMETERS: + * major - major device number for console devices + * minor - minor device number for console + * arg - device read argument + * + * RETURNS: + * RTEMS error code + */ +rtems_device_driver +console_read(rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg) +{ + if ((console_mode != CONSOLE_MODE_RAW) && + (console_mode != CONSOLE_MODE_IPL)) + { + return rtems_termios_read (arg); + } + else + { + rtems_libio_rw_args_t *argp = arg; + char *buf = argp->buffer; + int count = argp->count; + int n = 0; + int c; + while (n < count) + { + do { + c = (console_mode == CONSOLE_MODE_RAW) ? + sh4uart_poll_read(&sh4_uarts[minor]) : + ipl_console_poll_read(minor); + } while (c == -1); + if (c == '\r') + c = '\n'; + *(buf++) = c; + n++; + if (c == '\n') + break; + } + argp->bytes_moved = n; + return RTEMS_SUCCESSFUL; + } +} + +/* console_write -- + * Write to the console device + * + * PARAMETERS: + * major - major device number for console devices + * minor - minor device number for console + * arg - device write argument + * + * RETURNS: + * RTEMS error code + */ +rtems_device_driver +console_write(rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg) +{ + switch (console_mode) + { + case CONSOLE_MODE_POLL: + case CONSOLE_MODE_INT: + return rtems_termios_write (arg); + case CONSOLE_MODE_RAW: + { + rtems_libio_rw_args_t *argp = arg; + char cr = '\r'; + char *buf = argp->buffer; + int count = argp->count; + int i; + + for (i = 0; i < count; i++) + { + if (*buf == '\n') + sh4uart_poll_write(&sh4_uarts[minor], &cr, 1); + sh4uart_poll_write(&sh4_uarts[minor], buf, 1); + buf++; + } + argp->bytes_moved = count; + return RTEMS_SUCCESSFUL; + } +#ifdef SH4_WITH_IPL + case CONSOLE_MODE_IPL: + { + rtems_libio_rw_args_t *argp = arg; + char *buf = argp->buffer; + int count = argp->count; + ipl_console_poll_write(minor, buf, count); + argp->bytes_moved = count; + return RTEMS_SUCCESSFUL; + } +#endif + default: /* Unreachable */ + return RTEMS_NOT_DEFINED; + } +} + +/* console_control -- + * Handle console device I/O control (IOCTL) + * + * PARAMETERS: + * major - major device number for console devices + * minor - minor device number for console + * arg - device ioctl argument + * + * RETURNS: + * RTEMS error code + */ +rtems_device_driver +console_control(rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg) +{ + if ((console_mode != CONSOLE_MODE_RAW) && + (console_mode != CONSOLE_MODE_IPL)) + { + return rtems_termios_ioctl (arg); + } + else + { + return RTEMS_SUCCESSFUL; + } +} diff --git a/bsps/sh/gensh4/console/sh4uart.c b/bsps/sh/gensh4/console/sh4uart.c new file mode 100644 index 0000000000..7acc1de337 --- /dev/null +++ b/bsps/sh/gensh4/console/sh4uart.c @@ -0,0 +1,910 @@ +/* + * Generic UART Serial driver for SH-4 processors + * + * Copyright (C) 2000 OKTET Ltd., St.-Petersburg, Russian Fed. + * Author: Alexandra Kossovsky <sasha@oktet.ru> + * + * COPYRIGHT (c) 1989-2000. + * 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.rtems.org/license/LICENSE. + * + */ + +#include <rtems.h> +#include <termios.h> +#include <rtems/libio.h> +#include <bsp.h> +#include "sh/sh4uart.h" + +#ifndef SH4_UART_INTERRUPT_LEVEL +#define SH4_UART_INTERRUPT_LEVEL 4 +#endif + +/* Forward function declarations */ +static rtems_isr +sh4uart1_interrupt_transmit(rtems_vector_number vec); +static rtems_isr +sh4uart1_interrupt_receive(rtems_vector_number vec); +static rtems_isr +sh4uart2_interrupt_transmit(rtems_vector_number vec); +static rtems_isr +sh4uart2_interrupt_receive(rtems_vector_number vec); + +/* + * sh4uart_init -- + * This function verifies the input parameters and perform initialization + * of the SH-4 on-chip UART descriptor structure. + * + * PARAMETERS: + * uart - pointer to the UART channel descriptor structure + * tty - pointer to termios structure + * chn - channel number (SH4_SCI/SH4_SCIF -- 1/2) + * int_driven - interrupt-driven (1) or polled (0) I/O mode + * + * RETURNS: + * RTEMS_SUCCESSFUL if all parameters are valid, or error code + */ +rtems_status_code +sh4uart_init(sh4uart *uart, void *tty, int chn, int int_driven) +{ + if (uart == NULL) + return RTEMS_INVALID_ADDRESS; + + if ((chn != SH4_SCI) && (chn != SH4_SCIF)) + return RTEMS_INVALID_NUMBER; + + uart->chn = chn; + uart->tty = tty; + uart->int_driven = int_driven; + +#if 0 + sh4uart_poll_write(uart, "init", 4); +#endif + return RTEMS_SUCCESSFUL; +} + +/* + * sh4uart_get_Pph -- + * Get current peripheral module clock. + * + * PARAMETERS: none; + * Cpu clock is get from CPU_CLOCK_RATE_HZ marco + * (defined in bspopts.h, included from bsp.h) + * + * RETURNS: + * peripheral module clock in Hz. + */ +static uint32_t +sh4uart_get_Pph(void) +{ + uint16_t frqcr = *(volatile uint16_t*)SH7750_FRQCR; + uint32_t Pph = CPU_CLOCK_RATE_HZ; + + switch (frqcr & SH7750_FRQCR_IFC) { + case SH7750_FRQCR_IFCDIV1: break; + case SH7750_FRQCR_IFCDIV2: Pph *= 2; break; + case SH7750_FRQCR_IFCDIV3: Pph *= 3; break; + case SH7750_FRQCR_IFCDIV4: Pph *= 4; break; + case SH7750_FRQCR_IFCDIV6: Pph *= 6; break; + case SH7750_FRQCR_IFCDIV8: Pph *= 8; break; + default: /* unreachable */ + break; + } + + switch (frqcr & SH7750_FRQCR_PFC) { + case SH7750_FRQCR_PFCDIV2: Pph /= 2; break; + case SH7750_FRQCR_PFCDIV3: Pph /= 3; break; + case SH7750_FRQCR_PFCDIV4: Pph /= 4; break; + case SH7750_FRQCR_PFCDIV6: Pph /= 6; break; + case SH7750_FRQCR_PFCDIV8: Pph /= 8; break; + default: /* unreachable */ + break; + } + + return Pph; +} + +/* + * sh4uart_set_baudrate -- + * Program the UART timer to specified baudrate + * + * PARAMETERS: + * uart - pointer to UART descriptor structure + * baud - termios baud rate (B50, B9600, etc...) + * + * ALGORITHM: + * see SH7750 Hardware Manual. + * + * RETURNS: + * none + */ +static void +sh4uart_set_baudrate(sh4uart *uart, speed_t baud) +{ + uint32_t rate; + int16_t div; + int n; + uint32_t Pph = sh4uart_get_Pph(); + + switch (baud) { + case B50: rate = 50; break; + case B75: rate = 75; break; + case B110: rate = 110; break; + case B134: rate = 134; break; + case B150: rate = 150; break; + case B200: rate = 200; break; + case B300: rate = 300; break; + case B600: rate = 600; break; + case B1200: rate = 1200; break; + case B2400: rate = 2400; break; + case B4800: rate = 4800; break; + case B9600: rate = 9600; break; + case B19200: rate = 19200; break; + case B38400: rate = 38400; break; + case B57600: rate = 57600; break; +#ifdef B115200 + case B115200: rate = 115200; break; +#endif +#ifdef B230400 + case B230400: rate = 230400; break; +#endif + default: rate = 9600; break; + } + + for (n = 0; n < 4; n++) { + div = Pph / (32 * (1 << (2 * n)) * rate) - 1; + if (div < 0x100) + break; + } + + /* Set default baudrate if specified baudrate is impossible */ + if (n >= 4) + sh4uart_set_baudrate(uart, B9600); + + if ( uart->chn == 1 ) { + volatile uint8_t *smr1 = (volatile uint8_t *)SH7750_SCSMR1; + *smr1 &= ~SH7750_SCSMR_CKS; + *smr1 |= n << SH7750_SCSMR_CKS_S; + } else { + volatile uint16_t *smr2 = (volatile uint16_t *)SH7750_SCSMR2; + *smr2 &= ~SH7750_SCSMR_CKS; + *smr2 |= n << SH7750_SCSMR_CKS_S; + } + + SCBRR(uart->chn) = div; + /* Wait at least 1 bit interwal */ + rtems_task_wake_after(RTEMS_MILLISECONDS_TO_TICKS(1000 / rate)); +} + +/* + * sh4uart_reset -- + * This function perform the hardware initialization of SH-4 + * on-chip UART controller using parameters + * filled by the sh4uart_init function. + * + * PARAMETERS: + * uart - pointer to UART channel descriptor structure + * + * RETURNS: + * RTEMS_SUCCESSFUL if channel is initialized successfully, error + * code in other case + */ +rtems_status_code +sh4uart_reset(sh4uart *uart) +{ + register int chn; + register int int_driven; + rtems_status_code rc; + uint16_t tmp; + + if (uart == NULL) + return RTEMS_INVALID_ADDRESS; + + chn = uart->chn; + int_driven = uart->int_driven; + + if ( chn == 1 ) { + volatile uint8_t *scr1 = (volatile uint8_t *)SH7750_SCSCR1; + volatile uint8_t *smr1 = (volatile uint8_t *)SH7750_SCSMR1; + *scr1 = 0x0; /* Is set properly at the end of this function */ + *smr1 = 0x0; /* 8-bit, non-parity, 1 stop bit, pf/1 clock */ + } else { + volatile uint16_t *scr2 = (volatile uint16_t *)SH7750_SCSCR2; + volatile uint16_t *smr2 = (volatile uint16_t *)SH7750_SCSMR2; + *scr2 = 0x0; /* Is set properly at the end of this function */ + *smr2 = 0x0; /* 8-bit, non-parity, 1 stop bit, pf/1 clock */ + } + + if (chn == SH4_SCIF) + SCFCR2 = SH7750_SCFCR2_TFRST | SH7750_SCFCR2_RFRST | + SH7750_SCFCR2_RTRG_1 | SH7750_SCFCR2_TTRG_4; + + if (chn == SH4_SCI) + SCSPTR1 = int_driven ? 0x0 : SH7750_SCSPTR1_EIO; + else + SCSPTR2 = SH7750_SCSPTR2_RTSDT; + + if (int_driven) { + uint16_t ipr; + + if (chn == SH4_SCI) { + ipr = IPRB; + ipr &= ~SH7750_IPRB_SCI1; + ipr |= SH4_UART_INTERRUPT_LEVEL << SH7750_IPRB_SCI1_S; + IPRB = ipr; + + rc = rtems_interrupt_catch(sh4uart1_interrupt_transmit, + SH7750_EVT_TO_NUM(SH7750_EVT_SCI_TXI), + &uart->old_handler_transmit); + if (rc != RTEMS_SUCCESSFUL) + return rc; + + rc = rtems_interrupt_catch(sh4uart1_interrupt_receive, + SH7750_EVT_TO_NUM(SH7750_EVT_SCI_RXI), + &uart->old_handler_receive); + if (rc != RTEMS_SUCCESSFUL) + return rc; + } else { + ipr = IPRC; + ipr &= ~SH7750_IPRC_SCIF; + ipr |= SH4_UART_INTERRUPT_LEVEL << SH7750_IPRC_SCIF_S; + IPRC = ipr; + + rc = rtems_interrupt_catch(sh4uart2_interrupt_transmit, + SH7750_EVT_TO_NUM(SH7750_EVT_SCIF_TXI), + &uart->old_handler_transmit); + if (rc != RTEMS_SUCCESSFUL) + return rc; + rc = rtems_interrupt_catch(sh4uart2_interrupt_receive, + SH7750_EVT_TO_NUM(SH7750_EVT_SCIF_RXI), + &uart->old_handler_receive); + if (rc != RTEMS_SUCCESSFUL) + return rc; + } + uart->tx_buf = NULL; + uart->tx_ptr = uart->tx_buf_len = 0; + } + + sh4uart_set_baudrate(uart, B38400); /* debug defaults (unfortunately, + it is differ to termios default */ + + tmp = SH7750_SCSCR_TE | SH7750_SCSCR_RE | + (chn == SH4_SCI ? 0x0 : SH7750_SCSCR2_REIE) | + (int_driven ? (SH7750_SCSCR_RIE | SH7750_SCSCR_TIE) : 0x0); + + if ( chn == 1 ) { + volatile uint8_t *scr = (volatile uint8_t *)SH7750_SCSCR1; + *scr = tmp; + } else { + volatile uint16_t *scr = (volatile uint16_t *)SH7750_SCSCR2; + *scr = tmp; + } + + return RTEMS_SUCCESSFUL; +} + +/* + * sh4uart_disable -- + * This function disable the operations on SH-4 UART controller + * + * PARAMETERS: + * uart - pointer to UART channel descriptor structure + * disable_port - disable receive and transmit on the port + * + * RETURNS: + * RTEMS_SUCCESSFUL if UART closed successfuly, or error code in + * other case + */ +rtems_status_code +sh4uart_disable(sh4uart *uart, int disable_port) +{ + rtems_status_code rc; + + if (disable_port) { + if ( uart->chn == 1 ) { + volatile uint8_t *scr = (volatile uint8_t *)SH7750_SCSCR1; + *scr &= ~(SH7750_SCSCR_TE | SH7750_SCSCR_RE); + } else { + volatile uint16_t *scr = (volatile uint16_t *)SH7750_SCSCR2; + *scr &= ~(SH7750_SCSCR_TE | SH7750_SCSCR_RE); + } + } + + if (uart->int_driven) { + rc = rtems_interrupt_catch(uart->old_handler_transmit, + uart->chn == SH4_SCI ? SH7750_EVT_SCI_TXI : SH7750_EVT_SCIF_TXI, + NULL); + if (rc != RTEMS_SUCCESSFUL) + return rc; + rc = rtems_interrupt_catch(uart->old_handler_receive, + uart->chn == SH4_SCI ? SH7750_EVT_SCI_RXI : SH7750_EVT_SCIF_RXI, + NULL); + if (rc != RTEMS_SUCCESSFUL) + return rc; + } + + return RTEMS_SUCCESSFUL; +} + +/* + * sh4uart_set_attributes -- + * This function parse the termios attributes structure and perform + * the appropriate settings in hardware. + * + * PARAMETERS: + * uart - pointer to the UART descriptor structure + * t - pointer to termios parameters + * + * RETURNS: + * RTEMS_SUCCESSFUL + */ +rtems_status_code +sh4uart_set_attributes(sh4uart *uart, const struct termios *t) +{ + int level; + speed_t baud; + uint16_t smr; + + smr = (uint16_t)(*(uint8_t*)SH7750_SCSMR(uart->chn)); + + baud = cfgetospeed(t); + + /* Set flow control XXX*/ + if ((t->c_cflag & CRTSCTS) != 0) { + } + + /* Set character size -- only 7 or 8 bit */ + switch (t->c_cflag & CSIZE) { + case CS5: + case CS6: + case CS7: smr |= SH7750_SCSMR_CHR_7; break; + case CS8: smr &= ~SH7750_SCSMR_CHR_7; break; + } + + /* Set number of stop bits */ + if ((t->c_cflag & CSTOPB) != 0) + smr |= SH7750_SCSMR_STOP_2; + else + smr &= ~SH7750_SCSMR_STOP_2; + + /* Set parity mode */ + if ((t->c_cflag & PARENB) != 0) { + smr |= SH7750_SCSMR_PE; + if ((t->c_cflag & PARODD) != 0) + smr |= SH7750_SCSMR_PM_ODD; + else + smr &= ~SH7750_SCSMR_PM_ODD; + } else + smr &= ~SH7750_SCSMR_PE; + + rtems_interrupt_disable(level); + /* wait untill all data is transmitted */ + /* XXX JOEL says this is broken -- interrupts are OFF so NO ticks */ + rtems_task_wake_after(RTEMS_MILLISECONDS_TO_TICKS(100)); + + if ( uart->chn == 1 ) { + volatile uint8_t *scrP = (volatile uint8_t *)SH7750_SCSCR1; + volatile uint8_t *smrP = (volatile uint8_t *)SH7750_SCSMR1; + + *scrP &= ~(SH7750_SCSCR_TE | SH7750_SCSCR_RE); /* disable operations */ + sh4uart_set_baudrate(uart, baud); + *smrP = (uint8_t)smr; + *scrP |= SH7750_SCSCR_TE | SH7750_SCSCR_RE; /* enable operations */ + } else { + volatile uint16_t *scrP = (volatile uint16_t *)SH7750_SCSCR2; + volatile uint16_t *smrP = (volatile uint16_t *)SH7750_SCSMR2; + + *scrP &= ~(SH7750_SCSCR_TE | SH7750_SCSCR_RE); /* disable operations */ + sh4uart_set_baudrate(uart, baud); + *smrP = (uint8_t)smr; + *scrP |= SH7750_SCSCR_TE | SH7750_SCSCR_RE; /* enable operations */ + } + + rtems_interrupt_enable(level); + + return RTEMS_SUCCESSFUL; +} + +/* + * sh4uart_handle_error -- + * Perfoms error (Overrun, Framing & Parity) handling + * + * PARAMETERS: + * uart - pointer to UART descriptor structure + * + * RETURNS: + * nothing + */ +static void +sh4uart_handle_error(sh4uart *uart) +{ + if (uart->chn == SH4_SCI) { + volatile uint8_t *scr = (volatile uint8_t *)SH7750_SCSCR1; + *scr &= ~(SH7750_SCSSR1_ORER | SH7750_SCSSR1_FER | SH7750_SCSSR1_PER); + } else { + volatile uint16_t *scr = (volatile uint16_t *)SH7750_SCSCR2; + *scr &= ~(SH7750_SCSSR2_ER | SH7750_SCSSR2_BRK | SH7750_SCSSR2_FER); + *scr &= ~(SH7750_SCLSR2_ORER); + } +} + +/* + * sh4uart_poll_read -- + * This function tried to read character from SH-4 UART and perform + * error handling. When parity or framing error occured, return + * value dependent on termios input mode flags: + * - received character, if IGNPAR == 1 + * - 0, if IGNPAR == 0 and PARMRK == 0 + * - 0xff and 0x00 on next poll_read invocation, if IGNPAR == 0 and + * PARMRK == 1 + * + * PARAMETERS: + * uart - pointer to UART descriptor structure + * + * RETURNS: + * code of received character or -1 if no characters received. + */ +int +sh4uart_poll_read(sh4uart *uart) +{ + int chn = uart->chn; + int parity_error = 0; + int break_occured = 0; + int ch; + + if (uart->parerr_mark_flag == true) { + uart->parerr_mark_flag = false; + return 0; + } + + if (chn == SH4_SCI) { + if ((SCSSR1 & (SH7750_SCSSR1_PER | SH7750_SCSSR1_FER | + SH7750_SCSSR1_ORER)) != 0) { + if (SCSSR1 & (SH7750_SCSSR1_PER | SH7750_SCSSR1_FER)) + parity_error = 1; + sh4uart_handle_error(uart); + } + if ((SCSSR1 & SH7750_SCSSR1_RDRF) == 0) + return -1; + } else { + if ((SCSSR2 & (SH7750_SCSSR2_ER | SH7750_SCSSR2_DR | + SH7750_SCSSR2_BRK)) != 0 || + (SCLSR2 & SH7750_SCLSR2_ORER) != 0) { + if (SCSSR2 & (SH7750_SCSSR1_PER | SH7750_SCSSR1_FER)) + parity_error = 1; + if (SCSSR2 & SH7750_SCSSR2_BRK) + break_occured = 1; + sh4uart_handle_error(uart); + } + if ((SCSSR2 & SH7750_SCSSR2_RDF) == 0) + return -1; + } + + if (parity_error && !(uart->c_iflag & IGNPAR)) { + if (uart->c_iflag & PARMRK) { + uart->parerr_mark_flag = true; + return 0xff; + } else + return 0; + } + + if (break_occured && !(uart->c_iflag & BRKINT)) { + if (uart->c_iflag & IGNBRK) + return 0; + else + return 0; /* XXX -- SIGINT */ + } + + ch = SCRDR(chn); + + if (uart->chn == SH4_SCI) { + volatile uint8_t *scr = (volatile uint8_t *)SH7750_SCSCR1; + *scr &= ~SH7750_SCSSR1_RDRF; + } else { + volatile uint16_t *scr = (volatile uint16_t *)SH7750_SCSCR2; + *scr &= ~SH7750_SCSSR2_RDF; + } + + return ch; +} + +/* + * sh4uart_poll_write -- + * This function transmit buffer byte-by-byte in polling mode. + * + * PARAMETERS: + * uart - pointer to the UART descriptor structure + * buf - pointer to transmit buffer + * len - transmit buffer length + * + * RETURNS: + * 0 + */ +int +sh4uart_poll_write(sh4uart *uart, const char *buf, int len) +{ + volatile uint8_t *ssr1 = (volatile uint8_t *)SH7750_SCSSR1; + volatile uint16_t *ssr2 = (volatile uint16_t *)SH7750_SCSSR2; + + while (len) { + if (uart->chn == SH4_SCI) { + while ((SCSSR1 & SH7750_SCSSR1_TDRE) != 0) { + SCTDR1 = *buf++; + len--; + *ssr1 &= ~SH7750_SCSSR1_TDRE; + } + } else { + while ((SCSSR2 & SH7750_SCSSR2_TDFE) != 0) { + int i; + for (i = 0; + i < 16 - TRANSMIT_TRIGGER_VALUE(SCFCR2 & + SH7750_SCFCR2_TTRG); + i++) { + SCTDR2 = *buf++; + len--; + } + while ((SCSSR2 & SH7750_SCSSR2_TDFE) == 0 || + (SCSSR2 & SH7750_SCSSR2_TEND) == 0); + *ssr2 &= ~(SH7750_SCSSR1_TDRE | SH7750_SCSSR2_TEND); + } + } + } + return 0; +} + +/********************************** + * Functions to handle interrupts * + **********************************/ +/* sh4uart1_interrupt_receive -- + * UART interrupt handler routine -- SCI + * Receiving data + * + * PARAMETERS: + * vec - interrupt vector number + * + * RETURNS: + * none + */ +static rtems_isr +sh4uart1_interrupt_receive(rtems_vector_number vec) +{ + register int bp = 0; + char buf[32]; + volatile uint8_t *ssr1 = (volatile uint8_t *)SH7750_SCSSR1; + + + /* Find UART descriptor from vector number */ + sh4uart *uart = &sh4_uarts[0]; + + while (1) { + if ((bp < sizeof(buf) - 1) && ((SCSSR1 & SH7750_SCSSR1_RDRF) != 0)) { + /* Receive character and handle frame/parity errors */ + if ((SCSSR1 & (SH7750_SCSSR1_PER | SH7750_SCSSR1_FER | + SH7750_SCSSR1_ORER)) != 0) { + if (SCSSR1 & (SH7750_SCSSR1_PER | SH7750_SCSSR1_FER)) { + if (!(uart->c_iflag & IGNPAR)) { + if (uart->c_iflag & PARMRK) { + buf[bp++] = 0xff; + buf[bp++] = 0x00; + } else + buf[bp++] = 0x00; + } else + buf[bp++] = SCRDR1; + } + sh4uart_handle_error(uart); + } else + buf[bp++] = SCRDR1; + *ssr1 &= ~SH7750_SCSSR1_RDRF; + } else { + if (bp != 0) + rtems_termios_enqueue_raw_characters(uart->tty, buf, bp); + break; + } + } +} + +/* sh4uart2_interrupt_receive -- + * UART interrupt handler routine -- SCIF + * Receiving data + * + * PARAMETERS: + * vec - interrupt vector number + * + * RETURNS: + * none + */ +static rtems_isr +sh4uart2_interrupt_receive(rtems_vector_number vec) +{ + register int bp = 0; + char buf[32]; + volatile uint16_t *ssr2 = (volatile uint16_t *)SH7750_SCSSR2; + + + /* Find UART descriptor from vector number */ + sh4uart *uart = &sh4_uarts[1]; + + while (1) { + if ((bp < sizeof(buf) - 1) && ((SCSSR2 & SH7750_SCSSR2_RDF) != 0)) { + if ((SCSSR2 & (SH7750_SCSSR2_ER | SH7750_SCSSR2_DR | + SH7750_SCSSR2_BRK)) != 0 || + (SH7750_SCLSR2 & SH7750_SCLSR2_ORER) != 0) { + if (SCSSR2 & SH7750_SCSSR2_ER) { + if (!(uart->c_iflag & IGNPAR)) { + if (uart->c_iflag & PARMRK) { + buf[bp++] = 0xff; + buf[bp++] = 0x00; + } else + buf[bp++] = 0x00; + } else + buf[bp++] = SCRDR1; + } + + if (SCSSR2 & SH7750_SCSSR2_BRK) { + if (uart->c_iflag & IGNBRK) + buf[bp++] = 0x00; + else + buf[bp++] = 0x00; /* XXX -- SIGINT */ + } + + sh4uart_handle_error(uart); + } else + buf[bp++] = SCRDR1; + *ssr2 &= ~SH7750_SCSSR2_RDF; + } else { + if (bp != 0) + rtems_termios_enqueue_raw_characters(uart->tty, buf, bp); + break; + } + } +} + + +/* sh4uart1_interrupt_transmit -- + * UART interrupt handler routine -- SCI + * It continues transmit data when old part of data is transmitted + * + * PARAMETERS: + * vec - interrupt vector number + * + * RETURNS: + * none + */ +static rtems_isr +sh4uart1_interrupt_transmit(rtems_vector_number vec) +{ + volatile uint8_t *scr1 = (volatile uint8_t *)SH7750_SCSCR1; + volatile uint8_t *ssr1 = (volatile uint8_t *)SH7750_SCSSR1; + + /* Find UART descriptor from vector number */ + sh4uart *uart = &sh4_uarts[0]; + + if (uart->tx_buf != NULL && uart->tx_ptr < uart->tx_buf_len) { + while ((SCSSR1 & SH7750_SCSSR1_TDRE) != 0 && + uart->tx_ptr < uart->tx_buf_len) { + SCTDR1 = uart->tx_buf[uart->tx_ptr++]; + *ssr1 &= ~SH7750_SCSSR1_TDRE; + } + } else { + register int dequeue = uart->tx_buf_len; + + uart->tx_buf = NULL; + uart->tx_ptr = uart->tx_buf_len = 0; + + /* Disable interrupts while we do not have any data to transmit */ + *scr1 &= ~SH7750_SCSCR_TIE; + + rtems_termios_dequeue_characters(uart->tty, dequeue); + } +} + +/* sh4uart2_interrupt_transmit -- + * UART interrupt handler routine -- SCI + * It continues transmit data when old part of data is transmitted + * + * PARAMETERS: + * vec - interrupt vector number + * + * RETURNS: + * none + */ +static rtems_isr +sh4uart2_interrupt_transmit(rtems_vector_number vec) +{ + volatile uint8_t *ssr1 = (volatile uint8_t *)SH7750_SCSSR1; + volatile uint16_t *scr2 = (volatile uint16_t *)SH7750_SCSCR2; + + /* Find UART descriptor from vector number */ + sh4uart *uart = &sh4_uarts[1]; + + if (uart->tx_buf != NULL && uart->tx_ptr < uart->tx_buf_len) { + while ((SCSSR2 & SH7750_SCSSR2_TDFE) != 0) { + int i; + for (i = 0; + i < 16 - TRANSMIT_TRIGGER_VALUE(SCFCR2 & SH7750_SCFCR2_TTRG); + i++) + SCTDR2 = uart->tx_buf[uart->tx_ptr++]; + while ((SCSSR1 & SH7750_SCSSR1_TDRE) == 0 || + (SCSSR1 & SH7750_SCSSR1_TEND) == 0); + *ssr1 &= ~(SH7750_SCSSR1_TDRE | SH7750_SCSSR2_TEND); + } + } else { + register int dequeue = uart->tx_buf_len; + + uart->tx_buf = NULL; + uart->tx_ptr = uart->tx_buf_len = 0; + + /* Disable interrupts while we do not have any data to transmit */ + *scr2 &= ~SH7750_SCSCR_TIE; + + rtems_termios_dequeue_characters(uart->tty, dequeue); + } +} + +/* sh4uart_interrupt_write -- + * This function initiate transmitting of the buffer in interrupt mode. + * + * PARAMETERS: + * uart - pointer to the UART descriptor structure + * buf - pointer to transmit buffer + * len - transmit buffer length + * + * RETURNS: + * 0 + */ +rtems_status_code +sh4uart_interrupt_write(sh4uart *uart, const char *buf, int len) +{ + if (len > 0) { + volatile uint8_t *scr1 = (volatile uint8_t *)SH7750_SCSCR1; + volatile uint16_t *scr2 = (volatile uint16_t *)SH7750_SCSCR2; + + while ((SCSSR1 & SH7750_SCSSR1_TEND) == 0); + + uart->tx_buf = buf; + uart->tx_buf_len = len; + uart->tx_ptr = 0; + + if (uart->chn == SH4_SCI) + *scr1 |= SH7750_SCSCR_TIE; + else + *scr2 |= SH7750_SCSCR_TIE; + } + + return RTEMS_SUCCESSFUL; +} + +/* sh4uart_stop_remote_tx -- + * This function stop data flow from remote device. + * + * PARAMETERS: + * uart - pointer to the UART descriptor structure + * + * RETURNS: + * RTEMS_SUCCESSFUL + */ +rtems_status_code +sh4uart_stop_remote_tx(sh4uart *uart) +{ + if ( uart->chn == 1 ) { + volatile uint8_t *scr = (volatile uint8_t *)SH7750_SCSCR1; + *scr &= ~(SH7750_SCSCR_RIE | SH7750_SCSCR_RE); + } else { + volatile uint16_t *scr = (volatile uint16_t *)SH7750_SCSCR2; + *scr &= ~(SH7750_SCSCR_RIE | SH7750_SCSCR_RE); + } + + return RTEMS_SUCCESSFUL; +} + +/* sh4uart_start_remote_tx -- + * This function resume data flow from remote device. + * + * PARAMETERS: + * uart - pointer to the UART descriptor structure + * + * RETURNS: + * RTEMS_SUCCESSFUL + */ +rtems_status_code +sh4uart_start_remote_tx(sh4uart *uart) +{ + if ( uart->chn == 1 ) { + volatile uint8_t *scr = (volatile uint8_t *)SH7750_SCSCR1; + *scr |= SH7750_SCSCR_RIE | SH7750_SCSCR_RE; + } else { + volatile uint16_t *scr = (volatile uint16_t *)SH7750_SCSCR2; + *scr |= SH7750_SCSCR_RIE | SH7750_SCSCR_RE; + } + + return RTEMS_SUCCESSFUL; +} + +#ifdef SH4_WITH_IPL +/********************************* + * Functions for SH-IPL gdb stub * + *********************************/ + +/* + * ipl_finish -- + * Says gdb that program finished to get out from it. + */ +extern void ipl_finish(void); +__asm__ ( +" .global _ipl_finish\n" +"_ipl_finish:\n" +" mov.l __ipl_finish_value, r0\n" +" trapa #0x3f\n" +" nop\n" +" rts\n" +" nop\n" +" .align 4\n" +"__ipl_finish_value:\n" +" .long 255" +); + +extern int ipl_serial_input(int poll_count); +__asm__ ( +" .global _ipl_serial_input\n" +"_ipl_serial_input:\n" +" mov #1,r0\n" +" trapa #0x3f\n" +" nop\n" +" rts\n" +" nop\n"); + +extern void ipl_serial_output(const char *buf, int len); +__asm__ ( +" .global _ipl_serial_output\n" +"_ipl_serial_output:\n" +" mov #0,r0\n" +" trapa #0x3f\n" +" nop\n" +" rts\n" +" nop\n"); + +/* ipl_console_poll_read -- + * poll read operation for simulator console through ipl mechanism. + * + * PARAMETERS: + * minor - minor device number + * + * RETURNS: + * character code red from UART, or -1 if there is no characters + * available + */ +int +ipl_console_poll_read(int minor) +{ + unsigned char buf; + buf = ipl_serial_input(0x100000); + return buf; +} + +/* ipl_console_poll_write -- + * wrapper for polling mode write function + * + * PARAMETERS: + * minor - minor device number + * buf - output buffer + * len - output buffer length + * + * RETURNS: + * result code (0) + */ +int +ipl_console_poll_write(int minor, const char *buf, int len) +{ + int c; + while (len > 0) { + c = (len < 64 ? len : 64); + ipl_serial_output(buf, c); + len -= c; + buf += c; + } + return 0; +} +#endif diff --git a/bsps/sh/shsim/console/console-debugio.c b/bsps/sh/shsim/console/console-debugio.c new file mode 100644 index 0000000000..0a81dbe45b --- /dev/null +++ b/bsps/sh/shsim/console/console-debugio.c @@ -0,0 +1,33 @@ +/** + * @file + * @brief Stub printk() support + */ + +/* + * COPYRIGHT (c) 1989-2014. + * 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.rtems.org/license/LICENSE. + */ + +/* + * To support printk + */ + +#include <rtems.h> +#include <rtems/bspIo.h> + +void console_outbyte_polled( + int port, + char ch +); + +static void BSP_output_char_f(char c) +{ + console_outbyte_polled( 0, c ); +} + +BSP_output_char_function_type BSP_output_char = BSP_output_char_f; +BSP_polling_getchar_function_type BSP_poll_char = NULL; diff --git a/bsps/sh/shsim/console/console-io.c b/bsps/sh/shsim/console/console-io.c new file mode 100644 index 0000000000..71b089fdf7 --- /dev/null +++ b/bsps/sh/shsim/console/console-io.c @@ -0,0 +1,57 @@ +/* + * This file contains the hardware specific portions of the TTY driver + * for the simulators stdin/out. + */ + +/* + * COPYRIGHT (c) 1989-2011. + * 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.rtems.org/license/LICENSE. + */ + +#include <bsp.h> +#include <bsp/console-polled.h> +#include <rtems/libio.h> +#include <stdlib.h> +#include <assert.h> + +#include <bsp/syscall.h> + +/* + * console_initialize_hardware + * + * This routine initializes the console hardware. + */ +void console_initialize_hardware(void) +{ +} + +/* + * console_outbyte_polled + * + * This routine transmits a character using polling. + */ +void console_outbyte_polled( + int port, + char ch +) +{ + __trap34 (SYS_write, 1, &ch, 1); +} + +/* + * console_inbyte_nonblocking + * + * This routine polls for a character. + */ +int console_inbyte_nonblocking( + int port +) +{ + unsigned char c; + + return __trap34 (SYS_read, 0, &c, 1); +} diff --git a/bsps/sh/shsim/console/console-support.S b/bsps/sh/shsim/console/console-support.S new file mode 100644 index 0000000000..63f72f794b --- /dev/null +++ b/bsps/sh/shsim/console/console-support.S @@ -0,0 +1,18 @@ +/* + * newlib-1.8.2/newlib/libc/sys/sh/trap.S + */ + .text + .global ___trap34 +___trap34: + trapa #34 + tst r1,r1 ! r1 is errno + bt ret + mov.l perrno,r2 + mov.l r1,@r2 +ret: + rts + nop + + .align 2 +perrno: + .long _errno |