Back to home page

LXR

 
 

    


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

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /*  This file contains the driver for the GRLIB APBUART serial port. The driver
0004  *  is implemented by using the cons.c console layer. Interrupt/Polling/Task
0005  *  driven mode can be configured using driver resources:
0006  *
0007  *  - mode   (0=Polling, 1=Interrupt, 2=Task-Driven-Interrupt Mode)
0008  *  - syscon (0=Force not Ssystem Console, 1=Suggest System Console)
0009  *
0010  *  The BSP define APBUART_INFO_AVAIL in order to add the info routine
0011  *  used for debugging.
0012  *
0013  *  COPYRIGHT (c) 2010.
0014  *  Cobham Gaisler AB.
0015  *
0016  * Redistribution and use in source and binary forms, with or without
0017  * modification, are permitted provided that the following conditions
0018  * are met:
0019  * 1. Redistributions of source code must retain the above copyright
0020  *    notice, this list of conditions and the following disclaimer.
0021  * 2. Redistributions in binary form must reproduce the above copyright
0022  *    notice, this list of conditions and the following disclaimer in the
0023  *    documentation and/or other materials provided with the distribution.
0024  *
0025  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0026  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0027  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0028  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0029  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0030  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0031  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0032  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0033  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0034  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0035  * POSSIBILITY OF SUCH DAMAGE.
0036  */
0037 
0038 /******************* Driver manager interface ***********************/
0039 #include <bsp.h>
0040 #include <stdlib.h>
0041 #include <assert.h>
0042 #include <rtems/bspIo.h>
0043 #include <string.h>
0044 #include <stdio.h>
0045 
0046 #include <drvmgr/drvmgr.h>
0047 #include <grlib/ambapp_bus.h>
0048 #include <grlib/apbuart.h>
0049 #include <grlib/ambapp.h>
0050 #include <grlib/io.h>
0051 #include <grlib/cons.h>
0052 #include <rtems/termiostypes.h>
0053 #include <grlib/apbuart_cons.h>
0054 
0055 #ifdef LEON3
0056 #include <bsp/leon3.h>
0057 #endif
0058 
0059 /*#define DEBUG 1  */
0060 
0061 #ifdef DEBUG
0062 #define DBG(x...) printk(x)
0063 #else
0064 #define DBG(x...)
0065 #endif
0066 
0067 /* Probed hardware capabilities */
0068 enum {
0069     CAP_FIFO = 0x01, /* FIFO available */
0070     CAP_DI   = 0x02, /* RX delayed interrupt available */
0071 };
0072 struct apbuart_priv {
0073     struct console_dev condev;
0074     struct drvmgr_dev *dev;
0075     apbuart *regs;
0076     struct rtems_termios_tty *tty;
0077     char devName[52];
0078     volatile int sending;
0079     int mode;
0080     int cap;
0081 };
0082 
0083 /* Getters for different interfaces. It happens to be just casting which we do
0084  * in one place to avoid getting cast away. */
0085 static struct console_dev *base_get_condev(rtems_termios_device_context *base)
0086 {
0087     return (struct console_dev *) base;
0088 }
0089 
0090 static struct apbuart_priv *condev_get_priv(struct console_dev *condev)
0091 {
0092     return (struct apbuart_priv *) condev;
0093 }
0094 
0095 static struct apbuart_priv *base_get_priv(rtems_termios_device_context *base)
0096 {
0097     return condev_get_priv(base_get_condev(base));
0098 }
0099 
0100 /* TERMIOS Layer Callback functions */
0101 static bool first_open(
0102   rtems_termios_tty *tty,
0103   rtems_termios_device_context *base,
0104   struct termios *term,
0105   rtems_libio_open_close_args_t *args
0106 );
0107 static void last_close(
0108   rtems_termios_tty *tty,
0109   rtems_termios_device_context *base,
0110   rtems_libio_open_close_args_t *args
0111 );
0112 static void write_interrupt(
0113   rtems_termios_device_context *base,
0114   const char *buf,
0115   size_t len
0116 );
0117 static bool set_attributes(
0118     rtems_termios_device_context *base,
0119     const struct termios *t
0120 );
0121 static void get_attributes(
0122     rtems_termios_device_context *base,
0123     struct termios *t
0124 );
0125 static int read_polled(rtems_termios_device_context *base);
0126 static int read_task(rtems_termios_device_context *base);
0127 static void write_polled(
0128   rtems_termios_device_context *base,
0129   const char *buf,
0130   size_t len
0131 );
0132 
0133 static void apbuart_cons_isr(void *arg);
0134 int apbuart_get_baud(struct apbuart_priv *uart);
0135 
0136 int apbuart_init1(struct drvmgr_dev *dev);
0137 #ifdef APBUART_INFO_AVAIL
0138 static int apbuart_info(
0139     struct drvmgr_dev *dev,
0140     void (*print_line)(void *p, char *str),
0141     void *p, int, char *argv[]);
0142 #define APBUART_INFO_FUNC apbuart_info
0143 #else
0144 #define APBUART_INFO_FUNC NULL
0145 #endif
0146 
0147 struct drvmgr_drv_ops apbuart_ops =
0148 {
0149     .init = {apbuart_init1, NULL, NULL, NULL},
0150     .remove = NULL,
0151     .info = APBUART_INFO_FUNC
0152 };
0153 
0154 static struct amba_dev_id apbuart_ids[] =
0155 {
0156     {VENDOR_GAISLER, GAISLER_APBUART},
0157     {0, 0}      /* Mark end of table */
0158 };
0159 
0160 static struct amba_drv_info apbuart_drv_info =
0161 {
0162     {
0163         DRVMGR_OBJ_DRV,             /* Driver */
0164         NULL,                   /* Next driver */
0165         NULL,                   /* Device list */
0166         DRIVER_AMBAPP_GAISLER_APBUART_ID,   /* Driver ID */
0167         "APBUART_DRV",              /* Driver Name */
0168         DRVMGR_BUS_TYPE_AMBAPP,         /* Bus Type */
0169         &apbuart_ops,
0170         NULL,                   /* Funcs */
0171         0,                  /* No devices yet */
0172         sizeof(struct apbuart_priv),        /*DrvMgr alloc private*/
0173     },
0174     &apbuart_ids[0]
0175 };
0176 
0177 void apbuart_cons_register_drv (void)
0178 {
0179     DBG("Registering APBUART Console driver\n");
0180     drvmgr_drv_register(&apbuart_drv_info.general);
0181 }
0182 
0183 static const rtems_termios_device_handler handler_interrupt = {
0184     .first_open     = first_open,
0185     .last_close     = last_close,
0186     .write          = write_interrupt,
0187     .set_attributes = set_attributes,
0188     .mode           = TERMIOS_IRQ_DRIVEN
0189 };
0190 
0191 static const rtems_termios_device_handler handler_task = {
0192     .first_open     = first_open,
0193     .last_close     = last_close,
0194     .poll_read      = read_task,
0195     .write          = write_interrupt,
0196     .set_attributes = set_attributes,
0197     .mode           = TERMIOS_TASK_DRIVEN
0198 };
0199 
0200 static const rtems_termios_device_handler handler_polled = {
0201     .first_open     = first_open,
0202     .last_close     = last_close,
0203     .poll_read      = read_polled,
0204     .write          = write_polled,
0205     .set_attributes = set_attributes,
0206     .mode           = TERMIOS_POLLED
0207 };
0208 
0209 /*
0210  * APBUART hardware instantiation is flexible. Probe features here and driver
0211  * can select appropriate routines for the hardware. probecap() return value
0212  * is a CAP_ bitmask.
0213  */
0214 static int probecap(apbuart *regs)
0215 {
0216     int cap = 0;
0217     uint32_t ctrl;
0218 
0219     /* Probe FIFO */
0220     ctrl = grlib_load_32(&regs->ctrl);
0221     if (ctrl & APBUART_CTRL_FA) {
0222         cap |= CAP_FIFO;
0223 
0224         /* Probe RX delayed interrupt */
0225         ctrl |= APBUART_CTRL_DI;
0226         grlib_store_32(&regs->ctrl, ctrl);
0227         ctrl = grlib_load_32(&regs->ctrl);
0228         if (ctrl & APBUART_CTRL_DI) {
0229             ctrl &= ~APBUART_CTRL_DI;
0230             grlib_store_32(&regs->ctrl, ctrl);
0231             cap |= CAP_DI;
0232         }
0233     }
0234 
0235     return cap;
0236 }
0237 
0238 int apbuart_init1(struct drvmgr_dev *dev)
0239 {
0240     struct apbuart_priv *priv;
0241     struct amba_dev_info *ambadev;
0242     struct ambapp_core *pnpinfo;
0243     union drvmgr_key_value *value;
0244     char prefix[32];
0245     unsigned int db;
0246     static int first_uart = 1;
0247     uint32_t ctrl;
0248 
0249     /* The default operation in AMP is to use APBUART[0] for CPU[0],
0250      * APBUART[1] for CPU[1] and so on. The remaining UARTs is not used
0251      * since we don't know how many CPU-cores there are. Note this only
0252      * affects the on-chip amba bus (the root bus). The user can override
0253      * the default resource sharing by defining driver resources for the
0254      * APBUART devices on each AMP OS instance.
0255      */
0256 #if defined(RTEMS_MULTIPROCESSING) && defined(LEON3)
0257     if (drvmgr_on_rootbus(dev) && dev->minor_drv != LEON3_Cpu_Index &&
0258         drvmgr_keys_get(dev, NULL) != 0) {
0259         /* User hasn't configured on-chip APBUART, leave it untouched */
0260         return DRVMGR_EBUSY;
0261     }
0262 #endif
0263 
0264     DBG("APBUART[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
0265     /* Private data was allocated and zeroed by driver manager */
0266     priv = dev->priv;
0267     if (!priv)
0268         return DRVMGR_NOMEM;
0269     priv->dev = dev;
0270 
0271     /* Get device information from AMBA PnP information */
0272     ambadev = (struct amba_dev_info *)priv->dev->businfo;
0273     if (ambadev == NULL)
0274         return -1;
0275     pnpinfo = &ambadev->info;
0276     priv->regs = (apbuart *)pnpinfo->apb_slv->start;
0277 
0278     /* Clear HW regs, leave baudrate register as it is */
0279     grlib_store_32(&priv->regs->status, 0);
0280 
0281     ctrl = grlib_load_32(&priv->regs->ctrl);
0282 
0283     /* leave Transmitter/receiver if this is the RTEMS debug UART (assume
0284      * it has been setup by boot loader).
0285      */
0286     db = 0;
0287 #ifdef LEON3
0288     if (priv->regs == leon3_debug_uart) {
0289         db = ctrl & (APBUART_CTRL_RE |
0290                  APBUART_CTRL_TE |
0291                  APBUART_CTRL_PE |
0292                  APBUART_CTRL_PS);
0293     }
0294 #endif
0295     /* Let UART debug tunnelling be untouched if Flow-control is set.
0296      *
0297      * With old APBUARTs debug is enabled by setting LB and FL, since LB or
0298      * DB are not reset we can not trust them. However since FL is reset we
0299      * guess that we are debugging if FL is already set, the debugger set
0300      * either LB or DB depending on UART capabilities.
0301      */
0302     if (ctrl & APBUART_CTRL_FL) {
0303         db |= ctrl & (APBUART_CTRL_DB |
0304               APBUART_CTRL_LB | APBUART_CTRL_FL);
0305     }
0306 
0307     grlib_store_32(&priv->regs->ctrl, db);
0308 
0309     priv->cap = probecap(priv->regs);
0310 
0311     /* The system console and Debug console may depend on this device, so
0312      * initialize it straight away.
0313      *
0314      * We default to have System Console on first APBUART, user may override
0315      * this behaviour by setting the syscon option to 0.
0316      */
0317     if (drvmgr_on_rootbus(dev) && first_uart) {
0318         priv->condev.flags = CONSOLE_FLAG_SYSCON;
0319         first_uart = 0;
0320     } else {
0321         priv->condev.flags = 0;
0322     }
0323 
0324     value = drvmgr_dev_key_get(priv->dev, "syscon", DRVMGR_KT_INT);
0325     if (value) {
0326         if (value->i)
0327             priv->condev.flags |= CONSOLE_FLAG_SYSCON;
0328         else
0329             priv->condev.flags &= ~CONSOLE_FLAG_SYSCON;
0330     }
0331 
0332     /* Select 0=Polled, 1=IRQ, 2=Task-Driven UART Mode */
0333     value = drvmgr_dev_key_get(priv->dev, "mode", DRVMGR_KT_INT);
0334     if (value)
0335         priv->mode = value->i;
0336     else
0337         priv->mode = TERMIOS_POLLED;
0338     /* TERMIOS device handlers */
0339     if (priv->mode == TERMIOS_IRQ_DRIVEN) {
0340         priv->condev.handler = &handler_interrupt;
0341     } else if (priv->mode == TERMIOS_TASK_DRIVEN) {
0342         priv->condev.handler = &handler_task;
0343     } else {
0344         priv->condev.handler = &handler_polled;
0345     }
0346 
0347     priv->condev.fsname = NULL;
0348     /* Get Filesystem name prefix */
0349     prefix[0] = '\0';
0350     if (drvmgr_get_dev_prefix(dev, prefix) == DRVMGR_OK) {
0351         /* Got special prefix, this means we have a bus prefix
0352          * And we should use our "bus minor"
0353          */
0354         sprintf(priv->devName, "/dev/%sapbuart%d", prefix, dev->minor_bus);
0355         priv->condev.fsname = priv->devName;
0356     } else {
0357         sprintf(priv->devName, "/dev/apbuart%d", dev->minor_drv);
0358     }
0359 
0360     /* Register it as a console device, the console driver will register
0361      * a termios device as well
0362      */
0363     console_dev_register(&priv->condev);
0364 
0365     return DRVMGR_OK;
0366 }
0367 
0368 #ifdef APBUART_INFO_AVAIL
0369 static int apbuart_info(
0370     struct drvmgr_dev *dev,
0371     void (*print_line)(void *p, char *str),
0372     void *p, int argc, char *argv[])
0373 {
0374     struct apbuart_priv *priv = dev->priv;
0375     char *str1;
0376     char buf[64];
0377 
0378     if (dev->priv == NULL)
0379         return -DRVMGR_EINVAL;
0380 
0381     if (priv->mode == TERMIOS_POLLED)
0382         str1 = "TERMIOS_POLLED";
0383     else if (priv->mode == TERMIOS_IRQ_DRIVEN)
0384         str1 = "TERMIOS_IRQ_DRIVEN";
0385     else if (priv->mode == TERMIOS_TASK_DRIVEN)
0386         str1 = "TERMIOS_TASK_DRIVEN";
0387     else
0388         str1 = "BAD MODE";
0389 
0390     sprintf(buf, "UART Mode:   %s", str1);
0391     print_line(p, buf);
0392     if (priv->condev.fsname) {
0393         sprintf(buf, "FS Name:     %s", priv->condev.fsname);
0394         print_line(p, buf);
0395     }
0396     sprintf(buf, "STATUS REG:  0x%x", grlib_load_32(&priv->regs->status));
0397     print_line(p, buf);
0398     sprintf(buf, "CTRL REG:    0x%x", grlib_load_32(&priv->regs->ctrl));
0399     print_line(p, buf);
0400     sprintf(buf, "SCALER REG:  0x%x  baud rate %d",
0401                 grlib_load_32(&priv->regs->scaler),
0402                 apbuart_get_baud(priv));
0403     print_line(p, buf);
0404 
0405     return DRVMGR_OK;
0406 }
0407 #endif
0408 
0409 static bool first_open(
0410     rtems_termios_tty *tty,
0411     rtems_termios_device_context *base,
0412     struct termios *term,
0413     rtems_libio_open_close_args_t *args
0414 )
0415 {
0416     struct apbuart_priv *uart = base_get_priv(base);
0417     apbuart *regs = uart->regs;
0418     uint32_t ctrl;
0419 
0420     uart->tty = tty;
0421 
0422     /* Inherit UART hardware parameters from bootloader on system console */
0423     if (uart->condev.flags & CONSOLE_FLAG_SYSCON_GRANT) {
0424         get_attributes(base, term);
0425         term->c_oflag |= ONLCR;
0426         set_attributes(base, term);
0427     }
0428 
0429     /* Enable TX/RX */
0430     ctrl = grlib_load_32(&regs->ctrl);
0431     ctrl |= APBUART_CTRL_RE | APBUART_CTRL_TE;
0432 
0433     if (uart->mode != TERMIOS_POLLED) {
0434         int ret;
0435 
0436         /* Register interrupt and enable it */
0437         ret = drvmgr_interrupt_register(
0438             uart->dev, 0, uart->devName, apbuart_cons_isr, tty
0439         );
0440         if (ret) {
0441             return false;
0442         }
0443 
0444         uart->sending = 0;
0445 
0446         /* Turn on RX interrupts */
0447         ctrl |= APBUART_CTRL_RI;
0448         if (uart->cap & CAP_DI) {
0449             /* Use RX FIFO interrupt only if delayed interrupt available. */
0450             ctrl |= (APBUART_CTRL_DI | APBUART_CTRL_RF);
0451         }
0452     }
0453 
0454     grlib_store_32(&regs->ctrl, ctrl);
0455 
0456     return true;
0457 }
0458 
0459 static void last_close(
0460     rtems_termios_tty *tty,
0461     rtems_termios_device_context *base,
0462     rtems_libio_open_close_args_t *args
0463 )
0464 {
0465     struct apbuart_priv *uart = base_get_priv(base);
0466     apbuart *regs = uart->regs;
0467     rtems_interrupt_lock_context lock_context;
0468     uint32_t ctrl;
0469 
0470     if (uart->mode != TERMIOS_POLLED) {
0471         /* Turn off RX interrupts */
0472         rtems_termios_device_lock_acquire(base, &lock_context);
0473         ctrl = grlib_load_32(&regs->ctrl);
0474         ctrl &= ~(APBUART_CTRL_DI | APBUART_CTRL_RI | APBUART_CTRL_RF);
0475         grlib_store_32(&regs->ctrl, ctrl);
0476         rtems_termios_device_lock_release(base, &lock_context);
0477 
0478         /**** Flush device ****/
0479         while (uart->sending) {
0480             /* Wait until all data has been sent */
0481         }
0482         while (
0483             (grlib_load_32(&regs->ctrl) & APBUART_CTRL_TE) &&
0484             !(grlib_load_32(&regs->status) & APBUART_STATUS_TS)
0485         ) {
0486             /* Wait until all data has left shift register */
0487         }
0488 
0489         /* Disable and unregister interrupt handler */
0490         drvmgr_interrupt_unregister(uart->dev, 0, apbuart_cons_isr, tty);
0491     }
0492 
0493 #ifdef LEON3
0494     /* Disable TX/RX if not used for DEBUG */
0495     if (regs != leon3_debug_uart) {
0496         ctrl = grlib_load_32(&regs->ctrl);
0497         ctrl &= ~(APBUART_CTRL_RE | APBUART_CTRL_TE);
0498         grlib_store_32(&regs->ctrl, ctrl);
0499     }
0500 #endif
0501 }
0502 
0503 static int read_polled(rtems_termios_device_context *base)
0504 {
0505     struct apbuart_priv *uart = base_get_priv(base);
0506 
0507     return apbuart_inbyte_nonblocking(uart->regs);
0508 }
0509 
0510 /* This function is called from TERMIOS rxdaemon task without device lock. */
0511 static int read_task(rtems_termios_device_context *base)
0512 {
0513     rtems_interrupt_lock_context lock_context;
0514     struct apbuart_priv *uart = base_get_priv(base);
0515     apbuart *regs = uart->regs;
0516     int cnt;
0517     char buf[33];
0518     struct rtems_termios_tty *tty;
0519     uint32_t ctrl;
0520     uint32_t ctrl_add;
0521 
0522     ctrl_add = APBUART_CTRL_RI;
0523     if (uart->cap & CAP_DI) {
0524         ctrl_add |= (APBUART_CTRL_DI | APBUART_CTRL_RF);
0525     }
0526     tty = uart->tty;
0527     do {
0528         cnt = 0;
0529         while (
0530             (grlib_load_32(&regs->status) & APBUART_STATUS_DR) &&
0531             (cnt < sizeof(buf))
0532         ) {
0533             buf[cnt] = grlib_load_32(&regs->data);
0534             cnt++;
0535         }
0536         if (0 < cnt) {
0537             /* Tell termios layer about new characters */
0538             rtems_termios_enqueue_raw_characters(tty, &buf[0], cnt);
0539         }
0540 
0541         /*
0542          * Turn on RX interrupts. A new character in FIFO now may not
0543          * cause interrupt so we must check data ready again
0544          * afterwards.
0545          */
0546         rtems_termios_device_lock_acquire(base, &lock_context);
0547         ctrl = grlib_load_32(&regs->ctrl);
0548         ctrl |= ctrl_add;
0549         grlib_store_32(&regs->ctrl, ctrl);
0550         rtems_termios_device_lock_release(base, &lock_context);
0551     } while (grlib_load_32(&regs->status) & APBUART_STATUS_DR);
0552 
0553     return EOF;
0554 }
0555 
0556 int apbuart_get_baud(struct apbuart_priv *uart)
0557 {
0558     unsigned int core_clk_hz;
0559     unsigned int scaler;
0560 
0561     /* Get current scaler setting */
0562     scaler = grlib_load_32(&uart->regs->scaler);
0563 
0564     /* Get APBUART core frequency */
0565     drvmgr_freq_get(uart->dev, DEV_APB_SLV, &core_clk_hz);
0566 
0567     /* Calculate baud rate from generator "scaler" number */
0568     return core_clk_hz / ((scaler + 1) * 8);
0569 }
0570 
0571 static bool set_attributes(
0572     rtems_termios_device_context *base,
0573     const struct termios *t
0574 )
0575 {
0576     unsigned int core_clk_hz;
0577     unsigned int scaler;
0578     unsigned int ctrl;
0579     int baud;
0580     struct apbuart_priv *uart = base_get_priv(base);
0581     rtems_interrupt_lock_context lock_context;
0582 
0583     switch(t->c_cflag & CSIZE) {
0584         default:
0585         case CS5:
0586         case CS6:
0587         case CS7:
0588             /* Hardware doesn't support other than CS8 */
0589             return false;
0590         case CS8:
0591             break;
0592     }
0593 
0594     rtems_termios_device_lock_acquire(base, &lock_context);
0595 
0596     /* Read out current value */
0597     ctrl = grlib_load_32(&uart->regs->ctrl);
0598 
0599     switch(t->c_cflag & (PARENB|PARODD)){
0600         case (PARENB|PARODD):
0601             /* Odd parity */
0602             ctrl |= APBUART_CTRL_PE|APBUART_CTRL_PS;
0603             break;
0604 
0605         case PARENB:
0606             /* Even parity */
0607             ctrl &= ~APBUART_CTRL_PS;
0608             ctrl |= APBUART_CTRL_PE;
0609             break;
0610 
0611         default:
0612         case 0:
0613         case PARODD:
0614             /* No Parity */
0615             ctrl &= ~(APBUART_CTRL_PS|APBUART_CTRL_PE);
0616     }
0617 
0618     if (!(t->c_cflag & CLOCAL))
0619         ctrl |= APBUART_CTRL_FL;
0620     else
0621         ctrl &= ~APBUART_CTRL_FL;
0622 
0623     /* Update new settings */
0624     grlib_store_32(&uart->regs->ctrl, ctrl);
0625 
0626     rtems_termios_device_lock_release(base, &lock_context);
0627 
0628     /* Baud rate */
0629     baud = rtems_termios_baud_to_number(t->c_ospeed);
0630     if (baud > 0){
0631         /* Get APBUART core frequency */
0632         drvmgr_freq_get(uart->dev, DEV_APB_SLV, &core_clk_hz);
0633 
0634         /* Calculate Baud rate generator "scaler" number */
0635         scaler = (((core_clk_hz*10)/(baud*8))-5)/10;
0636 
0637         /* Set new baud rate by setting scaler */
0638         grlib_store_32(&uart->regs->scaler, scaler);
0639     }
0640 
0641     return true;
0642 }
0643 
0644 static void get_attributes(
0645     rtems_termios_device_context *base,
0646     struct termios *t
0647 )
0648 {
0649     struct apbuart_priv *uart = base_get_priv(base);
0650     unsigned int ctrl;
0651 
0652     t->c_cflag = t->c_cflag & ~(CSIZE|PARENB|PARODD|CLOCAL);
0653 
0654     /* Hardware support only CS8 */
0655     t->c_cflag |= CS8;
0656 
0657     /* Read out current parity */
0658     ctrl = grlib_load_32(&uart->regs->ctrl);
0659     if (ctrl & APBUART_CTRL_PE) {
0660         if (ctrl & APBUART_CTRL_PS)
0661             t->c_cflag |= PARENB|PARODD; /* Odd parity */
0662         else
0663             t->c_cflag |= PARENB; /* Even parity */
0664     }
0665 
0666     if ((ctrl & APBUART_CTRL_FL) == 0)
0667         t->c_cflag |= CLOCAL;
0668 
0669     rtems_termios_set_best_baud(t, apbuart_get_baud(uart));
0670 }
0671 
0672 static void write_polled(
0673     rtems_termios_device_context *base,
0674     const char *buf,
0675     size_t len
0676 )
0677 {
0678     struct apbuart_priv *uart = base_get_priv(base);
0679     int nwrite = 0;
0680 
0681     while (nwrite < len) {
0682         apbuart_outbyte_polled(uart->regs, *buf++);
0683         nwrite++;
0684     }
0685 }
0686 
0687 static void write_interrupt(
0688     rtems_termios_device_context *base,
0689     const char *buf,
0690     size_t len
0691 )
0692 {
0693     struct apbuart_priv *uart = base_get_priv(base);
0694     apbuart *regs = uart->regs;
0695     int sending;
0696     unsigned int ctrl;
0697 
0698     ctrl = grlib_load_32(&regs->ctrl);
0699 
0700     if (len > 0) {
0701         /*
0702          * sending is used to remember how much we have outstanding so
0703          * we can tell termios later.
0704          */
0705         /* Enable TX interrupt (interrupt is edge-triggered) */
0706         ctrl |= APBUART_CTRL_TI;
0707         grlib_store_32(&regs->ctrl, ctrl);
0708 
0709         if (ctrl & APBUART_CTRL_FA) {
0710             /* APBUART with FIFO.. Fill as many as FIFO allows */
0711             sending = 0;
0712             while (
0713                 ((grlib_load_32(&regs->status) & APBUART_STATUS_TF) == 0) &&
0714                 (sending < len)
0715             ) {
0716                 grlib_store_32(&regs->data, *buf);
0717                 buf++;
0718                 sending++;
0719             }
0720         } else {
0721             /* start UART TX, this will result in an interrupt when done */
0722             grlib_store_32(&regs->data, *buf);
0723 
0724             sending = 1;
0725         }
0726     } else {
0727         /* No more to send, disable TX interrupts */
0728         ctrl &= ~APBUART_CTRL_TI;
0729         grlib_store_32(&regs->ctrl, ctrl);
0730 
0731         /* Tell close that we sent everything */
0732         sending = 0;
0733     }
0734 
0735     uart->sending = sending;
0736 }
0737 
0738 /* Handle UART interrupts */
0739 static void apbuart_cons_isr(void *arg)
0740 {
0741     rtems_termios_tty *tty = arg;
0742     rtems_termios_device_context *base;
0743     struct console_dev *condev = rtems_termios_get_device_context(tty);
0744     struct apbuart_priv *uart = condev_get_priv(condev);
0745     apbuart *regs = uart->regs;
0746     unsigned int status;
0747     char buf[33];
0748     int cnt;
0749 
0750     if (uart->mode == TERMIOS_TASK_DRIVEN) {
0751         if ((status = grlib_load_32(&regs->status)) & APBUART_STATUS_DR) {
0752             rtems_interrupt_lock_context lock_context;
0753             uint32_t ctrl;
0754 
0755             /* Turn off RX interrupts */
0756             base = rtems_termios_get_device_context(tty);
0757             rtems_termios_device_lock_acquire(base, &lock_context);
0758             ctrl = grlib_load_32(&regs->ctrl);
0759             ctrl &=
0760                 ~(APBUART_CTRL_DI | APBUART_CTRL_RI |
0761                   APBUART_CTRL_RF);
0762             grlib_store_32(&regs->ctrl, ctrl);
0763             rtems_termios_device_lock_release(base, &lock_context);
0764             /* Activate termios RX daemon task */
0765             rtems_termios_rxirq_occured(tty);
0766         }
0767     } else {
0768         /*
0769          * Get all new characters from APBUART RX (FIFO) and store them
0770          * on the stack. Then tell termios about the new characters.
0771          * Maximum APBUART RX FIFO size is 32 characters.
0772          */
0773         cnt = 0;
0774         while (
0775             ((status=grlib_load_32(&regs->status)) & APBUART_STATUS_DR) &&
0776             (cnt < sizeof(buf))
0777         ) {
0778             buf[cnt] = grlib_load_32(&regs->data);
0779             cnt++;
0780         }
0781         if (0 < cnt) {
0782             /* Tell termios layer about new characters */
0783             rtems_termios_enqueue_raw_characters(tty, &buf[0], cnt);
0784         }
0785     }
0786 
0787     if (uart->sending && (status & APBUART_STATUS_TE)) {
0788         /* Tell close that we sent everything */
0789         cnt = uart->sending;
0790 
0791         /*
0792          * Tell termios how much we have sent. dequeue() may call
0793          * write_interrupt() to refill the transmitter.
0794          * write_interrupt() will eventually be called with 0 len to
0795          * disable TX interrupts.
0796          */
0797         rtems_termios_dequeue_characters(tty, cnt);
0798     }
0799 }
0800