Back to home page

LXR

 
 

    


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

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /*
0004  * Termios console serial driver.
0005  */
0006 
0007 /*
0008  * Based on SCI driver by Ralf Corsepius and John M. Mills
0009  *
0010  * Author: Radzislaw Galler <rgaller@et.put.poznan.pl>
0011  *
0012  *  COPYRIGHT (c) 1989-2001.
0013  *  On-Line Applications Research Corporation (OAR).
0014  *
0015  * Redistribution and use in source and binary forms, with or without
0016  * modification, are permitted provided that the following conditions
0017  * are met:
0018  * 1. Redistributions of source code must retain the above copyright
0019  *    notice, this list of conditions and the following disclaimer.
0020  * 2. Redistributions in binary form must reproduce the above copyright
0021  *    notice, this list of conditions and the following disclaimer in the
0022  *    documentation and/or other materials provided with the distribution.
0023  *
0024  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0025  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0026  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0027  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0028  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0029  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0030  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0031  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0032  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0033  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0034  * POSSIBILITY OF SUCH DAMAGE.
0035  *
0036  */
0037 
0038 #include <bsp.h>
0039 #include <stdlib.h>
0040 
0041 #include <libchip/serial.h>
0042 #include <libchip/sersupp.h>
0043 
0044 #include <rtems/libio.h>
0045 #include <rtems/iosupp.h>
0046 
0047 #include <rtems/score/sh_io.h>
0048 #include <rtems/score/ispsh7045.h>
0049 #include <rtems/score/iosh7045.h>
0050 
0051 #include <sh/sh7_sci.h>
0052 #include <sh/sh7_pfc.h>
0053 #include <sh/sci_termios.h>
0054 
0055 
0056 /*
0057  * Some handy macros
0058  */
0059 #define SH_SCI_REG_DATA(_data, _minor, _register) \
0060  (write8(_data, Console_Port_Tbl[_minor]->ulCtrlPort1 + (_register)))
0061 
0062 #define SH_SCI_REG_FLAG(_flag, _minor, _register) \
0063  (write8(read8(Console_Port_Tbl[_minor]->ulCtrlPort1 + (_register)) | (_flag), \
0064          Console_Port_Tbl[_minor]->ulCtrlPort1 + (_register)))
0065 
0066 #define SH_SCI_REG_MASK(_flag, _minor, _register) \
0067  (write8(read8(Console_Port_Tbl[_minor]->ulCtrlPort1 + (_register)) & ~(_flag),\
0068          Console_Port_Tbl[_minor]->ulCtrlPort1 + (_register)))
0069 
0070 /*
0071  * NOTE: Some SH variants have 3 sci devices
0072  */
0073 
0074 #define SCI_MINOR_DEVICES       2
0075 
0076 
0077 /*
0078  * Automatically generated function imported from scitab.rel
0079  */
0080 extern int _sci_get_brparms(
0081   speed_t       spd,
0082   unsigned char *smr,
0083   unsigned char *brr
0084 );
0085 
0086 /*
0087  * Translate termios flags into SCI settings
0088  */
0089 int sh_sci_set_attributes(
0090   int minor,
0091   const struct termios *t
0092 )
0093 {
0094     uint8_t     smr;
0095     uint8_t     brr;
0096     int a;
0097 
0098     tcflag_t c_cflag = t->c_cflag;
0099     speed_t spd = t->c_ospeed;
0100 
0101     if ( spd ) {
0102         if ( _sci_get_brparms( spd, &smr, &brr ) != 0 )
0103             return -1 ;
0104     }
0105 
0106     if ( c_cflag & CSIZE ) {
0107         if ( c_cflag & CS8 )
0108             smr &= ~SCI_SEVEN_BIT_DATA;
0109         else if ( c_cflag & CS7 )
0110             smr |= SCI_SEVEN_BIT_DATA;
0111         else
0112             return -1 ;
0113     }
0114 
0115     if ( c_cflag & CSTOPB )
0116         smr |= SCI_STOP_BITS_2;
0117     else
0118         smr &= ~SCI_STOP_BITS_2;
0119 
0120     if ( c_cflag & PARENB )
0121         smr |= SCI_PARITY_ON ;
0122     else
0123         smr &= ~SCI_PARITY_ON ;
0124 
0125     if ( c_cflag & PARODD )
0126         smr |= SCI_ODD_PARITY ;
0127     else
0128         smr &= ~SCI_ODD_PARITY;
0129 
0130     SH_SCI_REG_MASK((SCI_RE | SCI_TE), minor, SCI_SCR);
0131 
0132     SH_SCI_REG_DATA(smr, minor, SCI_SMR);
0133     SH_SCI_REG_DATA(brr, minor, SCI_BRR);
0134 
0135     for (a=0; a < 10000L; a++) { /* Delay one bit */
0136         __asm__ volatile ("nop");
0137     }
0138 
0139     SH_SCI_REG_FLAG((SCI_RE | SCI_TE), minor, SCI_SCR);
0140 
0141     return 0;
0142 }
0143 
0144 /*
0145  * Receive-data-full ISR
0146  *
0147  * The same routine for all interrupt sources of the same type.
0148  */
0149 static rtems_isr sh_sci_rx_isr(rtems_vector_number vector)
0150 {
0151     int minor;
0152 
0153     for (minor = 0; minor < Console_Port_Count; minor++) {
0154         if (Console_Port_Tbl[minor]->ulIntVector == vector) {
0155             char   temp8;
0156 
0157             /*
0158              * FIXME: error handling should be added
0159              */
0160             temp8 = read8(Console_Port_Tbl[minor]->ulCtrlPort1 + SCI_RDR);
0161 
0162             rtems_termios_enqueue_raw_characters(
0163                 Console_Port_Data[minor].termios_data, &temp8, 1);
0164 
0165             SH_SCI_REG_MASK(SCI_RDRF, minor, SCI_SSR);
0166             break;
0167         }
0168     }
0169 }
0170 
0171 /*
0172  * Transmit-data-empty ISR
0173  *
0174  * The same routine for all interrupt sources of the same type.
0175  */
0176 static rtems_isr sh_sci_tx_isr(rtems_vector_number vector)
0177 {
0178     int minor;
0179 
0180     for (minor = 0; minor < Console_Port_Count; minor++) {
0181         if (Console_Port_Tbl[minor]->ulDataPort == vector) {
0182             /*
0183              * FIXME: Error handling should be added
0184              */
0185 
0186             /*
0187              * Mask end-of-transmission interrupt
0188              */
0189             SH_SCI_REG_MASK(SCI_TIE, minor, SCI_SCR);
0190 
0191             if (rtems_termios_dequeue_characters(
0192                    Console_Port_Data[minor].termios_data, 1)) {
0193                 /*
0194                  * More characters to be received - interrupt must be enabled
0195                  */
0196                 SH_SCI_REG_FLAG(SCI_TIE, minor, SCI_SCR);
0197             }
0198             break;
0199         }
0200     }
0201 }
0202 
0203 
0204 /*
0205  * Initialization of serial port
0206  */
0207 void sh_sci_init(int minor)
0208 {
0209     uint16_t   temp16;
0210 
0211     /*
0212      * set PFC registers to enable I/O pins
0213      */
0214     if ((minor == 0)) {
0215         temp16 = read16(PFC_PACRL2);         /* disable SCK0, DMA, IRQ */
0216         temp16 &= ~(PA2MD1 | PA2MD0);
0217         temp16 |= (PA_TXD0 | PA_RXD0);       /* enable pins for Tx0, Rx0 */
0218         write16(temp16, PFC_PACRL2);
0219 
0220     } else if (minor == 1) {
0221         temp16 = read16(PFC_PACRL2);          /* disable SCK1, DMA, IRQ */
0222         temp16 &= ~(PA5MD1 | PA5MD0);
0223         temp16 |= (PA_TXD1 | PA_RXD1);        /* enable pins for Tx1, Rx1 */
0224         write16(temp16, PFC_PACRL2);
0225     }
0226 
0227     /*
0228      * Non-default hardware setup occurs in sh_sci_first_open
0229      */
0230 }
0231 
0232 /*
0233  * Initialization of interrupts
0234  *
0235  * Interrupts can be started only after opening a device, so interrupt
0236  * flags are set up in sh_sci_first_open function
0237  */
0238 void sh_sci_initialize_interrupts(int minor)
0239 {
0240     rtems_isr_entry old_isr;
0241     rtems_status_code status;
0242 
0243     sh_sci_init(minor);
0244     /*
0245      * Disable IRQ of SCIx
0246      */
0247     status = sh_set_irq_priority( Console_Port_Tbl[minor]->ulIntVector, 0);
0248 
0249     if (status != RTEMS_SUCCESSFUL)
0250         rtems_fatal_error_occurred(status);
0251 
0252     SH_SCI_REG_MASK(SCI_RIE, minor, SCI_SCR);
0253 
0254     /*
0255      * Catch apropriate vectors
0256      */
0257     status = rtems_interrupt_catch(
0258         sh_sci_rx_isr,
0259         Console_Port_Tbl[minor]->ulIntVector,
0260         &old_isr);
0261 
0262     if (status != RTEMS_SUCCESSFUL)
0263         rtems_fatal_error_occurred(status);
0264 
0265     status = rtems_interrupt_catch(
0266         sh_sci_tx_isr,
0267         Console_Port_Tbl[minor]->ulDataPort,
0268         &old_isr);
0269 
0270     if (status != RTEMS_SUCCESSFUL)
0271         rtems_fatal_error_occurred(status);
0272 
0273     /*
0274      * Enable IRQ of SCIx
0275      */
0276     SH_SCI_REG_FLAG(SCI_RIE, minor, SCI_SCR);
0277 
0278     status = sh_set_irq_priority(
0279         Console_Port_Tbl[minor]->ulIntVector,
0280         Console_Port_Tbl[minor]->ulCtrlPort2);
0281 
0282     if (status != RTEMS_SUCCESSFUL)
0283         rtems_fatal_error_occurred(status);
0284 }
0285 
0286 
0287 /*
0288  *  Open entry point
0289  *   Sets up port and pins for selected sci.
0290  */
0291 
0292 int sh_sci_first_open(
0293   int major,
0294   int minor,
0295   void *arg
0296 )
0297 {
0298     char   temp8;
0299     unsigned int a ;
0300 
0301     /*
0302      * check for valid minor number
0303      */
0304     if (( minor > ( SCI_MINOR_DEVICES -1 )) || ( minor < 0 )) {
0305         return RTEMS_INVALID_NUMBER;
0306     }
0307 
0308     /*
0309      * set up SCI registers
0310      */
0311     /* Clear SCR - disable Tx and Rx */
0312     SH_SCI_REG_DATA(0x00, minor, SCI_SCR);
0313 
0314     /* set SMR and BRR - baudrate and format */
0315     sh_sci_set_attributes(minor, Console_Port_Tbl[minor]->pDeviceParams);
0316 
0317     for (a=0; a < 10000L; a++) {                      /* Delay */
0318         __asm__ volatile ("nop");
0319     }
0320 
0321     write8((SCI_RE | SCI_TE),              /* enable async. Tx and Rx */
0322            Console_Port_Tbl[minor]->ulCtrlPort1 + SCI_SCR);
0323 
0324     /*
0325      * clear error flags
0326      */
0327     temp8 = read8(Console_Port_Tbl[minor]->ulCtrlPort1 + SCI_SSR);
0328     while(temp8 & (SCI_RDRF | SCI_ORER | SCI_FER | SCI_PER)) {
0329         /* flush input */
0330         temp8 = read8(Console_Port_Tbl[minor]->ulCtrlPort1 + SCI_RDR);
0331 
0332         /* clear some flags */
0333         SH_SCI_REG_FLAG((SCI_RDRF|SCI_ORER|SCI_FER|SCI_PER), minor, SCI_SSR);
0334 
0335         /* check if everything is OK */
0336         temp8 = read8(Console_Port_Tbl[minor]->ulCtrlPort1 + SCI_SSR);
0337     }
0338 
0339     /* Clear RDRF flag */
0340     SH_SCI_REG_DATA(0x00, minor, SCI_TDR); /* force output */
0341 
0342     /* Clear the TDRE bit */
0343     SH_SCI_REG_FLAG(SCI_TDRE, minor, SCI_SSR);
0344 
0345     /*
0346      * Interrupt setup
0347      */
0348     if (Console_Port_Tbl[minor]->pDeviceFns->deviceOutputUsesInterrupts) {
0349         SH_SCI_REG_FLAG(SCI_RIE, minor, SCI_SCR);
0350     }
0351 
0352     return RTEMS_SUCCESSFUL ;
0353 }
0354 
0355 /*
0356  *  Close entry point
0357  */
0358 
0359 int sh_sci_last_close(
0360   int major,
0361   int minor,
0362   void *arg
0363 )
0364 {
0365     /* FIXME: Incomplete */
0366 
0367     /* Shutdown interrupts if necessary */
0368     if (Console_Port_Tbl[minor]->pDeviceFns->deviceOutputUsesInterrupts)
0369     {
0370         SH_SCI_REG_MASK((SCI_TIE | SCI_RIE), minor, SCI_SCR);
0371     }
0372     return RTEMS_SUCCESSFUL ;
0373 }
0374 
0375 /*
0376  * Interrupt aware write routine
0377  */
0378 ssize_t sh_sci_write_support_int(
0379   int            minor,
0380   const char    *buf,
0381   size_t         len
0382 )
0383 {
0384     if (!len)
0385         return 0;
0386     /*
0387      * Put data into TDR and clear transmission-end-flag
0388      */
0389     SH_SCI_REG_DATA(*buf, minor, SCI_TDR);
0390     SH_SCI_REG_MASK(SCI_TDRE, minor, SCI_SSR);
0391     /*
0392      * Enable interrupt
0393      */
0394     SH_SCI_REG_FLAG(SCI_TIE, minor, SCI_SCR);
0395 
0396     return 1;
0397 }
0398 
0399 /*
0400  * Polled write method
0401  */
0402 ssize_t sh_sci_write_support_polled(
0403   int            minor,
0404   const char    *buf,
0405   size_t         len
0406 )
0407 {
0408     int count = 0;
0409 
0410     while(count < len) {
0411         sh_sci_write_polled(minor, buf[count]);
0412         count++;
0413     }
0414     /*
0415      * Return number of bytes written
0416      */
0417     return count;
0418 }
0419 
0420 /*
0421  * Polled write of one character at a time
0422  */
0423 void sh_sci_write_polled(
0424   int     minor,
0425   char    c
0426 )
0427 {
0428     /*
0429      * Wait for end of previous character
0430      */
0431     while(!(read8(Console_Port_Tbl[minor]->ulCtrlPort1 + SCI_SSR) & SCI_TDRE));
0432     /*
0433      * Send the character
0434      */
0435     SH_SCI_REG_DATA(c, minor, SCI_TDR);
0436 
0437     /*
0438      * Clear TDRE flag
0439      */
0440     SH_SCI_REG_MASK(SCI_TDRE, minor, SCI_SSR);
0441 }
0442 
0443 /*
0444  * Non-blocking read
0445  */
0446 int sh_sci_inbyte_nonblocking_polled(int minor)
0447 {
0448     char   inbyte;
0449 
0450     /*
0451      * Check if input buffer is full
0452      */
0453     if (read8(Console_Port_Tbl[minor]->ulCtrlPort1 + SCI_SSR) & SCI_RDRF) {
0454         inbyte = read8(Console_Port_Tbl[minor]->ulCtrlPort1 + SCI_RDR);
0455         SH_SCI_REG_MASK(SCI_RDRF, minor, SCI_SSR);
0456 
0457         /*
0458          * Check for errors
0459          */
0460         if (read8(Console_Port_Tbl[minor]->ulCtrlPort1 + SCI_SSR) &
0461            (SCI_ORER | SCI_FER | SCI_PER)) {
0462             SH_SCI_REG_MASK((SCI_ORER | SCI_FER | SCI_PER), minor, SCI_SSR);
0463             return -1;
0464         }
0465         return (int)inbyte;
0466     }
0467     return -1;
0468 }