Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:01

0001 /*
0002  * /dev/sci[0|1] for Hitachi SH 704X
0003  *
0004  * The SH doesn't have a designated console device. Therefore we "alias"
0005  * another device as /dev/console and revector all calls to /dev/console
0006  * to this device.
0007  *
0008  * This approach is similar to installing a sym-link from one device to
0009  * another device. If rtems once will support sym-links for devices files,
0010  * this implementation could be dropped.
0011  */
0012 
0013 /*
0014  *  Author: Ralf Corsepius (corsepiu@faw.uni-ulm.de)
0015  *
0016  *  COPYRIGHT (c) 1997-1998, FAW Ulm, Germany
0017  *
0018  *  This program is distributed in the hope that it will be useful,
0019  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
0020  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
0021  *
0022  *
0023  *  COPYRIGHT (c) 1998.
0024  *  On-Line Applications Research Corporation (OAR).
0025  *
0026  *  The license and distribution terms for this file may be
0027  *  found in the file LICENSE in this distribution or at
0028  *  http://www.rtems.org/license/LICENSE.
0029  *
0030  *  Modified to reflect sh7045 processor:
0031  *  John M. Mills (jmills@tga.com)
0032  *  TGA Technologies, Inc.
0033  *  100 Pinnacle Way, Suite 140
0034  *  Norcross, GA 30071 U.S.A.
0035  *
0036  *  This modified file may be copied and distributed in accordance
0037  *  the above-referenced license. It is provided for critique and
0038  *  developmental purposes without any warranty nor representation
0039  *  by the authors or by TGA Technologies.
0040  */
0041 
0042 #include <bsp.h>
0043 
0044 
0045 #include <stdlib.h>
0046 
0047 #include <rtems/libio.h>
0048 #include <rtems/iosupp.h>
0049 #include <rtems/score/sh_io.h>
0050 #include <rtems/score/ispsh7045.h>
0051 #include <rtems/score/iosh7045.h>
0052 #include <sh/sh7_sci.h>
0053 #include <sh/sh7_pfc.h>
0054 
0055 #include <sh/sci.h>
0056 
0057 #ifndef STANDALONE_EVB
0058 #define STANDALONE_EVB 0
0059 #endif
0060 
0061 /*
0062  * NOTE: Some SH variants have 3 sci devices
0063  */
0064 
0065 #define SCI_MINOR_DEVICES       2
0066 
0067 /*
0068  * FIXME: sh7045 register names match Hitachi data book,
0069  *  but conflict with RTEMS sh7032 usage.
0070  */
0071 
0072 #define SH_SCI_BASE_0   SCI_SMR0
0073 #define SH_SCI_BASE_1   SCI_SMR1
0074 
0075 #define SH_SCI_DEF_COMM_0   CS8, B9600
0076 #define SH_SCI_DEF_COMM_1   CS8, B9600
0077 
0078 struct scidev_t {
0079   char *                     name;
0080   uint32_t                   addr;
0081   rtems_device_minor_number  minor;
0082   unsigned short             opened;
0083   tcflag_t                   cflags;
0084   speed_t                    spd;
0085 } sci_device[SCI_MINOR_DEVICES] =
0086 {
0087   { "/dev/sci0", SH_SCI_BASE_0, 0, 0, SH_SCI_DEF_COMM_0 },
0088   { "/dev/sci1", SH_SCI_BASE_1, 1, 0, SH_SCI_DEF_COMM_1 }
0089 };
0090 
0091 /*  local data structures maintain hardware configuration */
0092 #if UNUSED
0093 static sci_setup_t sio_param[2];
0094 #endif
0095 
0096 /* Translate termios' tcflag_t into sci settings */
0097 static int _sci_set_cflags(
0098   struct scidev_t  *sci_dev,
0099   tcflag_t          c_cflag,
0100   speed_t           spd
0101 )
0102 {
0103   uint8_t  smr;
0104   uint8_t  brr;
0105 
0106   if ( spd )
0107   {
0108     if ( _sci_get_brparms( spd, &smr, &brr ) != 0 )
0109       return -1;
0110   }
0111 
0112   if ( c_cflag & CSIZE )
0113   {
0114     if ( c_cflag & CS8 )
0115       smr &= ~SCI_SEVEN_BIT_DATA;
0116     else if ( c_cflag & CS7 )
0117       smr |= SCI_SEVEN_BIT_DATA;
0118     else
0119       return -1;
0120   }
0121 
0122   if ( c_cflag & CSTOPB )
0123     smr |= SCI_STOP_BITS_2;
0124   else
0125     smr &= ~SCI_STOP_BITS_2;
0126 
0127   if ( c_cflag & PARENB )
0128     smr |= SCI_PARITY_ON;
0129   else
0130     smr &= ~SCI_PARITY_ON;
0131 
0132   if ( c_cflag & PARODD )
0133     smr |= SCI_ODD_PARITY;
0134   else
0135     smr &= ~SCI_ODD_PARITY;
0136 
0137   write8( smr, sci_dev->addr + SCI_SMR );
0138   write8( brr, sci_dev->addr + SCI_BRR );
0139 
0140   return 0;
0141 }
0142 
0143 /*
0144  * local functions operate SCI ports 0 and 1
0145  * called from polling routines or ISRs
0146  */
0147 static bool wrtSCI0(unsigned char ch)
0148 {
0149   uint8_t   temp;
0150   bool result = false;
0151 
0152   if ((read8(SCI_SSR0) & SCI_TDRE) != 0x00) {
0153     /* Write the character to the TDR */
0154     write8(ch, SCI_TDR0);
0155     /* Clear the TDRE bit */
0156     temp = read8(SCI_SSR0) & ~SCI_TDRE;
0157     write8(temp, SCI_SSR0);
0158     result = true;
0159   }
0160   return result;
0161 } /* wrtSCI0 */
0162 
0163 static bool wrtSCI1(unsigned char ch)
0164 {
0165   uint8_t   temp;
0166   bool result = false;
0167 
0168   if ((read8(SCI_SSR1) & SCI_TDRE) != 0x00) {
0169      /* Write the character to the TDR */
0170      write8(ch, SCI_TDR1);
0171      /* Clear the TDRE bit */
0172      temp = read8(SCI_SSR1) & ~SCI_TDRE;
0173      write8(temp, SCI_SSR1);
0174      result = true;
0175   }
0176   return result;
0177 } /* wrtSCI1 */
0178 
0179 /* polled output steers byte to selected port */
0180 static void sh_sci_outbyte_polled(
0181   rtems_device_minor_number  minor,
0182   char ch )
0183 {
0184   if (minor == 0) /* blocks until port ready */
0185     while (wrtSCI0(ch) != true); /* SCI0*/
0186   else
0187     while (wrtSCI1(ch) != true); /* SCI1*/
0188 } /* sh_sci_outbyte_polled */
0189 
0190 /*
0191  * Initial version calls polled output driver and blocks
0192  */
0193 static void outbyte(
0194   rtems_device_minor_number  minor,
0195   char ch)
0196 {
0197   sh_sci_outbyte_polled(minor, (unsigned char)ch);
0198 } /* outbyte */
0199 
0200 static bool rdSCI0(unsigned char *ch)
0201 {
0202   uint8_t   temp;
0203   bool result = false;
0204 
0205   if ((read8(SCI_SSR0) & SCI_RDRF) != 0x00) {
0206     /* read input */
0207     *ch = read8(SCI_RDR0);
0208     /* Clear RDRF flag */
0209     temp = read8(SCI_SSR0) & ~SCI_RDRF;
0210     write8(temp, SCI_SSR0);
0211     /* Check for transmission errors */
0212     if (temp & (SCI_ORER | SCI_FER | SCI_PER)) {
0213         /* TODO: report to RTEMS transmission error */
0214 
0215         /* clear error flags*/
0216         temp &= ~(SCI_ORER | SCI_FER | SCI_PER);
0217         write8(temp, SCI_SSR0);
0218     }
0219     result = true;
0220   }
0221   return result;
0222 } /* rdSCI0 */
0223 
0224 static bool rdSCI1(unsigned char *ch)
0225 {
0226   uint8_t   temp;
0227   bool result = false;
0228 
0229   if ((read8(SCI_SSR1) & SCI_RDRF) != 0x00) {
0230     /* read input */
0231     *ch = read8(SCI_RDR1);
0232     /* Clear RDRF flag */
0233     temp= read8(SCI_SSR1) & ~SCI_RDRF;
0234     write8(temp, SCI_SSR1);
0235     /* Check for transmission errors */
0236     if (temp & (SCI_ORER | SCI_FER | SCI_PER)) {
0237         /* TODO: report to RTEMS transmission error */
0238 
0239         /* clear error flags*/
0240         temp &= ~(SCI_ORER | SCI_FER | SCI_PER);
0241         write8(temp, SCI_SSR1);
0242     }
0243     result = true;
0244   }
0245   return result;
0246 } /* rdSCI1 */
0247 
0248 /* initial version pulls byte from selected port */
0249 static char sh_sci_inbyte_polled( rtems_device_minor_number  minor )
0250 {
0251   uint8_t ch = 0;
0252 
0253   if (minor == 0) /* blocks until char.ready */
0254     while (rdSCI0(&ch) != true); /* SCI0 */
0255   else
0256     while (rdSCI1(&ch) != true); /* SCI1 */
0257   return ch;
0258 } /* sh_sci_inbyte_polled */
0259 
0260 /* Initial version calls polled input driver */
0261 static char inbyte( rtems_device_minor_number  minor )
0262 {
0263   char ch;
0264 
0265   ch = sh_sci_inbyte_polled(minor);
0266   return ch;
0267 } /* inbyte */
0268 
0269 /*  sh_sci_initialize
0270  *
0271  *  This routine initializes (registers) the sh_sci IO drivers.
0272  *
0273  *  Input parameters: ignored
0274  *
0275  *  Output parameters:  NONE
0276  *
0277  *  Return values: RTEMS_SUCCESSFUL
0278  *   if all sci[...] register, else calls
0279  *   rtems_fatal_error_occurred(status)
0280  */
0281 rtems_device_driver sh_sci_initialize(
0282   rtems_device_major_number  major,
0283   rtems_device_minor_number  minor,
0284   void                      *arg )
0285 {
0286   rtems_device_driver status;
0287   rtems_device_minor_number i;
0288 
0289   /*
0290    * register all possible devices.
0291    * the initialization of the hardware is done by sci_open
0292    *
0293    * One of devices could be previously registered by console
0294    * initialization therefore we check it everytime
0295    */
0296   for ( i = 0 ; i < SCI_MINOR_DEVICES ; i++ ) {
0297     /* OK. We assume it is not registered yet. */
0298     status = rtems_io_register_name(
0299       sci_device[i].name,
0300       major,
0301       sci_device[i].minor
0302     );
0303     if (status != RTEMS_SUCCESSFUL)
0304       rtems_fatal_error_occurred(status);
0305   }
0306 
0307   /* non-default hardware setup occurs in sh_sci_open() */
0308   return RTEMS_SUCCESSFUL;
0309 }
0310 
0311 /*
0312  *  Open entry point
0313  *   Sets up port and pins for selected sci.
0314  */
0315 rtems_device_driver sh_sci_open(
0316   rtems_device_major_number major,
0317   rtems_device_minor_number minor,
0318   void                    * arg )
0319 {
0320   uint8_t    temp8;
0321   uint16_t   temp16;
0322 
0323   unsigned   a;
0324 
0325  /* check for valid minor number */
0326  if (( minor > ( SCI_MINOR_DEVICES -1 )) || ( minor < 0 )) {
0327    return RTEMS_INVALID_NUMBER;
0328  }
0329 
0330   /* device already opened */
0331   if ( sci_device[minor].opened > 0 ) {
0332     sci_device[minor].opened++;
0333     return RTEMS_SUCCESSFUL;
0334   }
0335 
0336   /* set PFC registers to enable I/O pins */
0337 
0338   if ((minor == 0)) {
0339     temp16 = read16(PFC_PACRL2);         /* disable SCK0, DMA, IRQ */
0340     temp16 &= ~(PA2MD1 | PA2MD0);
0341     temp16 |= (PA_TXD0 | PA_RXD0);       /* enable pins for Tx0, Rx0 */
0342     write16(temp16, PFC_PACRL2);
0343 
0344   } else if (minor == 1) {
0345     temp16 = read16(PFC_PACRL2);          /* disable SCK1, DMA, IRQ */
0346     temp16 &= ~(PA5MD1 | PA5MD0);
0347     temp16 |= (PA_TXD1 | PA_RXD1);        /* enable pins for Tx1, Rx1 */
0348     write16(temp16, PFC_PACRL2);
0349 
0350   } /* add other devices and pins as req'd. */
0351 
0352   /* set up SCI registers */
0353       write8(0x00, sci_device[minor].addr + SCI_SCR);   /* Clear SCR */
0354                                                    /* set SMR and BRR */
0355     _sci_set_cflags( &sci_device[minor], sci_device[minor].cflags, sci_device[minor].spd );
0356 
0357     for (a=0; a < 10000L; a++) {                      /* Delay */
0358       __asm__ volatile ("nop");
0359     }
0360 
0361     write8((SCI_RE | SCI_TE),              /* enable async. Tx and Rx */
0362      sci_device[minor].addr + SCI_SCR);
0363 
0364     /* clear error flags */
0365     temp8 = read8(sci_device[minor].addr + SCI_SSR);
0366     while (temp8 & (SCI_RDRF | SCI_ORER | SCI_FER | SCI_PER)) {
0367         temp8 = read8(sci_device[minor].addr + SCI_RDR);   /* flush input */
0368         temp8 = read8(sci_device[minor].addr + SCI_SSR); /* clear some flags */
0369         write8(temp8 & ~(SCI_RDRF | SCI_ORER | SCI_FER | SCI_PER),
0370                sci_device[minor].addr + SCI_SSR);
0371         temp8 = read8(sci_device[minor].addr + SCI_SSR); /* check if everything is OK */
0372     }
0373     /* Clear RDRF flag */
0374     write8(0x00, sci_device[minor].addr + SCI_TDR);    /* force output */
0375      /* Clear the TDRE bit */
0376      temp8 = read8(sci_device[minor].addr + SCI_SSR) & ~SCI_TDRE;
0377      write8(temp8, sci_device[minor].addr + SCI_SSR);
0378 
0379     /* add interrupt setup if required */
0380 
0381 
0382   sci_device[minor].opened++;
0383 
0384   return RTEMS_SUCCESSFUL;
0385 }
0386 
0387 /*
0388  *  Close entry point
0389  */
0390 rtems_device_driver sh_sci_close(
0391   rtems_device_major_number major,
0392   rtems_device_minor_number minor,
0393   void                    * arg
0394 )
0395 {
0396   /* FIXME: Incomplete */
0397   if ( sci_device[minor].opened > 0 )
0398     sci_device[minor].opened--;
0399   else
0400     return RTEMS_INVALID_NUMBER;
0401 
0402   return RTEMS_SUCCESSFUL;
0403 }
0404 
0405 /*
0406  * read bytes from the serial port. We only have stdin.
0407  */
0408 rtems_device_driver sh_sci_read(
0409   rtems_device_major_number major,
0410   rtems_device_minor_number minor,
0411   void                    * arg
0412 )
0413 {
0414   rtems_libio_rw_args_t *rw_args;
0415   char *buffer;
0416   int maximum;
0417   int count = 0;
0418 
0419   rw_args = (rtems_libio_rw_args_t *) arg;
0420 
0421   buffer = rw_args->buffer;
0422   maximum = rw_args->count;
0423 
0424   for (count = 0; count < maximum; count++) {
0425     buffer[ count ] = inbyte(minor);
0426     if (buffer[ count ] == '\n' || buffer[ count ] == '\r') {
0427       buffer[ count++ ]  = '\n';
0428       break;
0429     }
0430   }
0431 
0432   rw_args->bytes_moved = count;
0433   return (count >= 0) ? RTEMS_SUCCESSFUL : RTEMS_UNSATISFIED;
0434 }
0435 
0436 /*
0437  * write bytes to the serial port. Stdout and stderr are the same.
0438  */
0439 rtems_device_driver sh_sci_write(
0440   rtems_device_major_number major,
0441   rtems_device_minor_number minor,
0442   void                    * arg
0443 )
0444 {
0445   int count;
0446   int maximum;
0447   rtems_libio_rw_args_t *rw_args;
0448   char *buffer;
0449 
0450   rw_args = (rtems_libio_rw_args_t *) arg;
0451 
0452   buffer = rw_args->buffer;
0453   maximum = rw_args->count;
0454 
0455   for (count = 0; count < maximum; count++) {
0456     if ( buffer[ count ] == '\n') {
0457       outbyte(minor, '\r');
0458     }
0459     outbyte( minor, buffer[ count ] );
0460   }
0461 
0462   rw_args->bytes_moved = maximum;
0463   return 0;
0464 }
0465 
0466 /*
0467  *  IO Control entry point
0468  */
0469 rtems_device_driver sh_sci_control(
0470   rtems_device_major_number major,
0471   rtems_device_minor_number minor,
0472   void                    * arg
0473 )
0474 {
0475   /* Not yet supported */
0476   return RTEMS_SUCCESSFUL;
0477 }
0478 
0479 /*
0480  * Termios polled first open
0481  */
0482 static int _sh_sci_poll_first_open(int major, int minor, void *arg)
0483 {
0484     return sh_sci_open(major, minor, arg);
0485 }
0486 
0487 /*
0488  * Termios general last close
0489  */
0490 static int _sh_sci_last_close(int major, int minor, void *arg)
0491 {
0492     return sh_sci_close(major, minor, arg);
0493 }
0494 
0495 /*
0496  * Termios polled read
0497  */
0498 static int _sh_sci_poll_read(int minor)
0499 {
0500   int value = -1;
0501   uint8_t ch = 0;
0502 
0503   if ( minor == 0 ) {
0504     if ( rdSCI0( &ch ) )
0505       value = (int) ch;
0506   } else if ( minor == 1 ) {
0507     if ( rdSCI1( &ch ) )
0508       value = (int) ch;
0509   }
0510   return value;
0511 }
0512 
0513 /*
0514  * Termios polled write
0515  */
0516 static ssize_t _sh_sci_poll_write(int minor, const char *buf, size_t len)
0517 {
0518     size_t count;
0519 
0520     for (count = 0; count < len; count++)
0521         outbyte( minor, buf[count] );
0522     return count;
0523 }
0524 
0525 /*
0526  * Termios set attributes
0527  */
0528 static int _sh_sci_set_attributes( int minor, const struct termios *t)
0529 {
0530     return _sci_set_cflags( &sci_device[ minor ], t->c_cflag, t->c_ospeed);
0531 }
0532 
0533 
0534 const rtems_termios_callbacks sci_poll_callbacks = {
0535     _sh_sci_poll_first_open,    /* FirstOpen*/
0536     _sh_sci_last_close,         /* LastClose*/
0537     _sh_sci_poll_read,          /* PollRead  */
0538     _sh_sci_poll_write,         /* Write */
0539     _sh_sci_set_attributes,     /* setAttributes */
0540     NULL,                       /* stopRemoteTX */
0541     NULL,                       /* StartRemoteTX */
0542     TERMIOS_POLLED              /* outputUsesInterrupts */
0543 };
0544 
0545 /* FIXME: not yet supported */
0546 const rtems_termios_callbacks sci_interrupt_callbacks;
0547 
0548 const rtems_termios_callbacks* sh_sci_get_termios_handlers( bool poll )
0549 {
0550   return poll ?
0551       &sci_poll_callbacks :
0552       &sci_interrupt_callbacks;
0553 }