summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/sh/gensh2/console/sci.c
diff options
context:
space:
mode:
Diffstat (limited to 'c/src/lib/libbsp/sh/gensh2/console/sci.c')
-rw-r--r--c/src/lib/libbsp/sh/gensh2/console/sci.c554
1 files changed, 554 insertions, 0 deletions
diff --git a/c/src/lib/libbsp/sh/gensh2/console/sci.c b/c/src/lib/libbsp/sh/gensh2/console/sci.c
new file mode 100644
index 0000000000..143fc1bb94
--- /dev/null
+++ b/c/src/lib/libbsp/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;
+}