Back to home page

LXR

 
 

    


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

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /*
0004  *  COPYRIGHT (c) 1989-1998.
0005  *  On-Line Applications Research Corporation (OAR).
0006  *
0007  *  Modified for LEON3 BSP.
0008  *  COPYRIGHT (c) 2004.
0009  *  Gaisler Research.
0010  *
0011  * Redistribution and use in source and binary forms, with or without
0012  * modification, are permitted provided that the following conditions
0013  * are met:
0014  * 1. Redistributions of source code must retain the above copyright
0015  *    notice, this list of conditions and the following disclaimer.
0016  * 2. Redistributions in binary form must reproduce the above copyright
0017  *    notice, this list of conditions and the following disclaimer in the
0018  *    documentation and/or other materials provided with the distribution.
0019  *
0020  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0021  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0022  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0023  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0024  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0025  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0026  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0027  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0028  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0029  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0030  * POSSIBILITY OF SUCH DAMAGE.
0031  */
0032 
0033 #include <grlib/apbuart_termios.h>
0034 #include <grlib/apbuart.h>
0035 #include <grlib/io.h>
0036 #include <bsp.h>
0037 
0038 static void apbuart_isr(void *arg)
0039 {
0040   rtems_termios_tty *tty = arg;
0041   struct apbuart_context *uart = rtems_termios_get_device_context(tty);
0042   unsigned int status;
0043   char data;
0044 
0045   /* Get all received characters */
0046   while ((status=grlib_load_32(&uart->regs->status)) & APBUART_STATUS_DR) {
0047     /* Data has arrived, get new data */
0048     data = (char)grlib_load_32(&uart->regs->data);
0049 
0050     /* Tell termios layer about new character */
0051     rtems_termios_enqueue_raw_characters(tty, &data, 1);
0052   }
0053 
0054   if (
0055     (status & APBUART_STATUS_TE)
0056       && (grlib_load_32(&uart->regs->ctrl) & APBUART_CTRL_TI) != 0
0057   ) {
0058     /* write_interrupt will get called from this function */
0059     rtems_termios_dequeue_characters(tty, 1);
0060   }
0061 }
0062 
0063 static void apbuart_write_support(
0064   rtems_termios_device_context *base,
0065   const char *buf,
0066   size_t len
0067 )
0068 {
0069   struct apbuart_context *uart = (struct apbuart_context *) base;
0070   int sending;
0071   uint32_t ctrl;
0072 
0073   ctrl = grlib_load_32(&uart->regs->ctrl);
0074 
0075   if (len > 0) {
0076     /* Enable TX interrupt (interrupt is edge-triggered) */
0077     ctrl |= APBUART_CTRL_TI;
0078 
0079     /* start UART TX, this will result in an interrupt when done */
0080     grlib_store_32(&uart->regs->data, (uint8_t)*buf);
0081 
0082     sending = 1;
0083   } else {
0084     /* No more to send, disable TX interrupts */
0085     ctrl &= ~APBUART_CTRL_TI;
0086 
0087     /* Tell close that we sent everything */
0088     sending = 0;
0089   }
0090 
0091   grlib_store_32(&uart->regs->ctrl, ctrl);
0092   uart->sending = sending;
0093 }
0094 
0095 static void apbuart_write_polled(
0096   rtems_termios_device_context *base,
0097   const char *buf,
0098   size_t len
0099 )
0100 {
0101   struct apbuart_context *uart = (struct apbuart_context *) base;
0102   size_t nwrite = 0;
0103 
0104   while (nwrite < len) {
0105     apbuart_outbyte_polled(uart->regs, *buf++);
0106     nwrite++;
0107   }
0108 }
0109 
0110 static int apbuart_poll_read(rtems_termios_device_context *base)
0111 {
0112   struct apbuart_context *uart = (struct apbuart_context *) base;
0113 
0114   return apbuart_inbyte_nonblocking(uart->regs);
0115 }
0116 
0117 static bool apbuart_set_attributes(
0118   rtems_termios_device_context *base,
0119   const struct termios *t
0120 )
0121 {
0122   struct apbuart_context *uart = (struct apbuart_context *) base;
0123   rtems_interrupt_lock_context lock_context;
0124   unsigned int scaler;
0125   unsigned int ctrl;
0126   int baud;
0127 
0128   switch (t->c_cflag & CSIZE) {
0129     default:
0130     case CS5:
0131     case CS6:
0132     case CS7:
0133       /* Hardware doesn't support other than CS8 */
0134       return false;
0135     case CS8:
0136       break;
0137   }
0138 
0139   rtems_termios_device_lock_acquire(base, &lock_context);
0140 
0141   /* Read out current value */
0142   ctrl = grlib_load_32(&uart->regs->ctrl);
0143 
0144   switch (t->c_cflag & (PARENB|PARODD)) {
0145     case (PARENB|PARODD):
0146       /* Odd parity */
0147       ctrl |= APBUART_CTRL_PE|APBUART_CTRL_PS;
0148       break;
0149 
0150     case PARENB:
0151       /* Even parity */
0152       ctrl &= ~APBUART_CTRL_PS;
0153       ctrl |= APBUART_CTRL_PE;
0154       break;
0155 
0156     default:
0157     case 0:
0158     case PARODD:
0159       /* No Parity */
0160       ctrl &= ~(APBUART_CTRL_PS|APBUART_CTRL_PE);
0161   }
0162 
0163   if (!(t->c_cflag & CLOCAL)) {
0164     ctrl |= APBUART_CTRL_FL;
0165   } else {
0166     ctrl &= ~APBUART_CTRL_FL;
0167   }
0168 
0169   /* Update new settings */
0170   grlib_store_32(&uart->regs->ctrl, ctrl);
0171 
0172   rtems_termios_device_lock_release(base, &lock_context);
0173 
0174   /* Baud rate */
0175   baud = rtems_termios_baud_to_number(t->c_ospeed);
0176   if (baud > 0) {
0177     /* Calculate Baud rate generator "scaler" number */
0178     scaler = (((uart->freq_hz * 10) / (baud * 8)) - 5) / 10;
0179 
0180     /* Set new baud rate by setting scaler */
0181     grlib_store_32(&uart->regs->scaler, scaler);
0182   }
0183 
0184   return true;
0185 }
0186 
0187 static void apbuart_set_best_baud(
0188   const struct apbuart_context *uart,
0189   struct termios *term
0190 )
0191 {
0192   uint32_t baud = (uart->freq_hz * 10) /
0193     ((grlib_load_32(&uart->regs->scaler) * 10 + 5) * 8);
0194 
0195   rtems_termios_set_best_baud(term, baud);
0196 }
0197 
0198 static bool apbuart_first_open_polled(
0199   rtems_termios_tty *tty,
0200   rtems_termios_device_context *base,
0201   struct termios *term,
0202   rtems_libio_open_close_args_t *args
0203 )
0204 {
0205   struct apbuart_context *uart = (struct apbuart_context *) base;
0206   uint32_t ctrl;
0207 
0208   apbuart_set_best_baud(uart, term);
0209 
0210   /* Initialize UART on opening */
0211   ctrl = grlib_load_32(&uart->regs->ctrl);
0212   ctrl |= APBUART_CTRL_RE | APBUART_CTRL_TE;
0213   grlib_store_32(&uart->regs->ctrl, ctrl);
0214   grlib_store_32(&uart->regs->status, 0);
0215 
0216   return true;
0217 }
0218 
0219 static bool apbuart_first_open_interrupt(
0220   rtems_termios_tty *tty,
0221   rtems_termios_device_context *base,
0222   struct termios *term,
0223   rtems_libio_open_close_args_t *args
0224 )
0225 {
0226   struct apbuart_context *uart = (struct apbuart_context *) base;
0227   rtems_status_code sc;
0228   uint32_t ctrl;
0229 
0230   apbuart_set_best_baud(uart, term);
0231 
0232   /* Register Interrupt handler */
0233   sc = rtems_interrupt_handler_install(uart->irq, "console",
0234                                        RTEMS_INTERRUPT_SHARED,
0235                                        apbuart_isr,
0236                                        tty);
0237   if (sc != RTEMS_SUCCESSFUL)
0238     return false;
0239 
0240   uart->sending = 0;
0241   /* Enable Receiver and transmitter and Turn on RX interrupts */
0242   ctrl = grlib_load_32(&uart->regs->ctrl);
0243   ctrl |= APBUART_CTRL_RE | APBUART_CTRL_TE | APBUART_CTRL_RI;
0244   grlib_store_32(&uart->regs->ctrl, ctrl);
0245   /* Initialize UART on opening */
0246   ctrl |= APBUART_CTRL_RE | APBUART_CTRL_TE;
0247   grlib_store_32(&uart->regs->ctrl, ctrl);
0248   grlib_store_32(&uart->regs->status, 0);
0249 
0250   return true;
0251 }
0252 
0253 static void apbuart_last_close_interrupt(
0254   rtems_termios_tty *tty,
0255   rtems_termios_device_context *base,
0256   rtems_libio_open_close_args_t *args
0257 )
0258 {
0259   struct apbuart_context *uart = (struct apbuart_context *) base;
0260   rtems_interrupt_lock_context lock_context;
0261   uint32_t ctrl;
0262 
0263   /* Turn off RX interrupts */
0264   rtems_termios_device_lock_acquire(base, &lock_context);
0265   ctrl = grlib_load_32(&uart->regs->ctrl);
0266   ctrl &= ~APBUART_CTRL_RI;
0267   grlib_store_32(&uart->regs->ctrl, ctrl);
0268   rtems_termios_device_lock_release(base, &lock_context);
0269 
0270   /**** Flush device ****/
0271   while (uart->sending) {
0272     /* Wait until all data has been sent */
0273   }
0274 
0275   /* uninstall ISR */
0276   rtems_interrupt_handler_remove(uart->irq, apbuart_isr, tty);
0277 }
0278 
0279 const rtems_termios_device_handler apbuart_handler_interrupt = {
0280   .first_open = apbuart_first_open_interrupt,
0281   .last_close = apbuart_last_close_interrupt,
0282   .write = apbuart_write_support,
0283   .set_attributes = apbuart_set_attributes,
0284   .mode = TERMIOS_IRQ_DRIVEN
0285 };
0286 
0287 const rtems_termios_device_handler apbuart_handler_polled = {
0288   .first_open = apbuart_first_open_polled,
0289   .poll_read = apbuart_poll_read,
0290   .write = apbuart_write_polled,
0291   .set_attributes = apbuart_set_attributes,
0292   .mode = TERMIOS_POLLED
0293 };