source: rtems/c/src/lib/libbsp/sparc/shared/uart/apbuart_cons.c @ 229c4249

5
Last change on this file since 229c4249 was 229c4249, checked in by Martin Aberg <maberg@…>, on 04/27/17 at 11:14:53

bsp/leon3: Cleaner namespace for LEON3 debug UART

Prefix BSP specific symbols with BSP name:
dbg_uart -> leon3_debug_uart
debug_uart_index -> leon3_debug_uart_index

  • Property mode set to 100644
File size: 21.2 KB
Line 
1/*  This file contains the driver for the GRLIB APBUART serial port. The driver
2 *  is implemented by using the cons.c console layer. Interrupt/Polling/Task
3 *  driven mode can be configured using driver resources:
4 *
5 *  - mode   (0=Polling, 1=Interrupt, 2=Task-Driven-Interrupt Mode)
6 *  - syscon (0=Force not Ssystem Console, 1=Suggest System Console)
7 *
8 *  The BSP define APBUART_INFO_AVAIL in order to add the info routine
9 *  used for debugging.
10 *
11 *  COPYRIGHT (c) 2010.
12 *  Cobham Gaisler AB.
13 *
14 *  The license and distribution terms for this file may be
15 *  found in the file LICENSE in this distribution or at
16 *  http://www.rtems.org/license/LICENSE.
17 */
18
19/******************* Driver manager interface ***********************/
20#include <bsp.h>
21#include <stdlib.h>
22#include <assert.h>
23#include <rtems/bspIo.h>
24#include <string.h>
25#include <stdio.h>
26
27#include <drvmgr/drvmgr.h>
28#include <drvmgr/ambapp_bus.h>
29#include <bsp/apbuart.h>
30#include <ambapp.h>
31#include <grlib.h>
32#include <bsp/cons.h>
33#include <rtems/termiostypes.h>
34#include <bsp/apbuart_cons.h>
35
36/*#define DEBUG 1  */
37
38#ifdef DEBUG
39#define DBG(x...) printk(x)
40#else
41#define DBG(x...)
42#endif
43
44/* LEON3 Low level transmit/receive functions provided by debug-uart code */
45extern void apbuart_outbyte_polled(
46  struct apbuart_regs *regs,
47  unsigned char ch,
48  int do_cr_on_newline,
49  int wait_sent);
50extern int apbuart_inbyte_nonblocking(struct apbuart_regs *regs);
51#ifdef LEON3
52extern struct apbuart_regs *leon3_debug_uart; /* The debug UART */
53#endif
54
55/* Probed hardware capabilities */
56enum {
57        CAP_FIFO = 0x01, /* FIFO available */
58        CAP_DI   = 0x02, /* RX delayed interrupt available */
59};
60struct apbuart_priv {
61        struct console_dev condev;
62        struct drvmgr_dev *dev;
63        struct apbuart_regs *regs;
64        struct rtems_termios_tty *tty;
65        char devName[32];
66        volatile int sending;
67        int mode;
68        int cap;
69};
70
71/* Getters for different interfaces. It happens to be just casting which we do
72 * in one place to avoid getting cast away. */
73static struct console_dev *base_get_condev(rtems_termios_device_context *base)
74{
75        return (struct console_dev *) base;
76}
77
78static struct apbuart_priv *condev_get_priv(struct console_dev *condev)
79{
80        return (struct apbuart_priv *) condev;
81}
82
83static struct apbuart_priv *base_get_priv(rtems_termios_device_context *base)
84{
85        return condev_get_priv(base_get_condev(base));
86}
87
88/* TERMIOS Layer Callback functions */
89static bool first_open(
90  rtems_termios_tty *tty,
91  rtems_termios_device_context *base,
92  struct termios *term,
93  rtems_libio_open_close_args_t *args
94);
95static void last_close(
96  rtems_termios_tty *tty,
97  rtems_termios_device_context *base,
98  rtems_libio_open_close_args_t *args
99);
100static void write_interrupt(
101  rtems_termios_device_context *base,
102  const char *buf,
103  size_t len
104);
105static bool set_attributes(
106        rtems_termios_device_context *base,
107        const struct termios *t
108);
109static void get_attributes(
110        rtems_termios_device_context *base,
111        struct termios *t
112);
113static int read_polled(rtems_termios_device_context *base);
114static int read_task(rtems_termios_device_context *base);
115static void write_polled(
116  rtems_termios_device_context *base,
117  const char *buf,
118  size_t len
119);
120
121static void apbuart_cons_isr(void *arg);
122int apbuart_get_baud(struct apbuart_priv *uart);
123
124int apbuart_init1(struct drvmgr_dev *dev);
125#ifdef APBUART_INFO_AVAIL
126static int apbuart_info(
127        struct drvmgr_dev *dev,
128        void (*print_line)(void *p, char *str),
129        void *p, int, char *argv[]);
130#define APBUART_INFO_FUNC apbuart_info
131#else
132#define APBUART_INFO_FUNC NULL
133#endif
134
135struct drvmgr_drv_ops apbuart_ops =
136{
137        .init = {apbuart_init1, NULL, NULL, NULL},
138        .remove = NULL,
139        .info = APBUART_INFO_FUNC
140};
141
142static struct amba_dev_id apbuart_ids[] =
143{
144        {VENDOR_GAISLER, GAISLER_APBUART},
145        {0, 0}          /* Mark end of table */
146};
147
148static struct amba_drv_info apbuart_drv_info =
149{
150        {
151                DRVMGR_OBJ_DRV,                         /* Driver */
152                NULL,                                   /* Next driver */
153                NULL,                                   /* Device list */
154                DRIVER_AMBAPP_GAISLER_APBUART_ID,       /* Driver ID */
155                "APBUART_DRV",                          /* Driver Name */
156                DRVMGR_BUS_TYPE_AMBAPP,                 /* Bus Type */
157                &apbuart_ops,
158                NULL,                                   /* Funcs */
159                0,                                      /* No devices yet */
160                sizeof(struct apbuart_priv),            /*DrvMgr alloc private*/
161        },
162        &apbuart_ids[0]
163};
164
165void apbuart_cons_register_drv (void)
166{
167        DBG("Registering APBUART Console driver\n");
168        drvmgr_drv_register(&apbuart_drv_info.general);
169}
170
171static const rtems_termios_device_handler handler_interrupt = {
172        .first_open     = first_open,
173        .last_close     = last_close,
174        .write          = write_interrupt,
175        .set_attributes = set_attributes,
176        .mode           = TERMIOS_IRQ_DRIVEN
177};
178
179static const rtems_termios_device_handler handler_task = {
180        .first_open     = first_open,
181        .last_close     = last_close,
182        .poll_read      = read_task,
183        .write          = write_interrupt,
184        .set_attributes = set_attributes,
185        .mode           = TERMIOS_TASK_DRIVEN
186};
187
188static const rtems_termios_device_handler handler_polled = {
189        .first_open     = first_open,
190        .last_close     = last_close,
191        .poll_read      = read_polled,
192        .write          = write_polled,
193        .set_attributes = set_attributes,
194        .mode           = TERMIOS_POLLED
195};
196
197/*
198 * APBUART hardware instantiation is flexible. Probe features here and driver
199 * can select appropriate routines for the hardware. probecap() return value
200 * is a CAP_ bitmask.
201 */
202static int probecap(struct apbuart_regs *regs)
203{
204        int cap = 0;
205
206        /* Probe FIFO */
207        if (regs->ctrl & APBUART_CTRL_FA) {
208                cap |= CAP_FIFO;
209
210                /* Probe RX delayed interrupt */
211                regs->ctrl |= APBUART_CTRL_DI;
212                if (regs->ctrl & APBUART_CTRL_DI) {
213                        regs->ctrl &= ~APBUART_CTRL_DI;
214                        cap |= CAP_DI;
215                }
216        }
217
218        return cap;
219}
220
221int apbuart_init1(struct drvmgr_dev *dev)
222{
223        struct apbuart_priv *priv;
224        struct amba_dev_info *ambadev;
225        struct ambapp_core *pnpinfo;
226        union drvmgr_key_value *value;
227        char prefix[32];
228        unsigned int db;
229        static int first_uart = 1;
230
231        /* The default operation in AMP is to use APBUART[0] for CPU[0],
232         * APBUART[1] for CPU[1] and so on. The remaining UARTs is not used
233         * since we don't know how many CPU-cores there are. Note this only
234         * affects the on-chip amba bus (the root bus). The user can override
235         * the default resource sharing by defining driver resources for the
236         * APBUART devices on each AMP OS instance.
237         */
238#if defined(RTEMS_MULTIPROCESSING) && defined(LEON3)
239        if (drvmgr_on_rootbus(dev) && dev->minor_drv != LEON3_Cpu_Index &&
240            drvmgr_keys_get(dev, NULL) != 0) {
241                /* User hasn't configured on-chip APBUART, leave it untouched */
242                return DRVMGR_EBUSY;
243        }
244#endif
245
246        DBG("APBUART[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
247        /* Private data was allocated and zeroed by driver manager */
248        priv = dev->priv;
249        if (!priv)
250                return DRVMGR_NOMEM;
251        priv->dev = dev;
252
253        /* Get device information from AMBA PnP information */
254        ambadev = (struct amba_dev_info *)priv->dev->businfo;
255        if (ambadev == NULL)
256                return -1;
257        pnpinfo = &ambadev->info;
258        priv->regs = (struct apbuart_regs *)pnpinfo->apb_slv->start;
259
260        /* Clear HW regs, leave baudrate register as it is */
261        priv->regs->status = 0;
262
263        /* leave Transmitter/receiver if this is the RTEMS debug UART (assume
264         * it has been setup by boot loader).
265         */
266        db = 0;
267#ifdef LEON3
268        if (priv->regs == leon3_debug_uart) {
269                db = priv->regs->ctrl & (LEON_REG_UART_CTRL_RE |
270                                        LEON_REG_UART_CTRL_TE |
271                                        LEON_REG_UART_CTRL_PE |
272                                        LEON_REG_UART_CTRL_PS);
273        }
274#endif
275        /* Let UART debug tunnelling be untouched if Flow-control is set.
276         *
277         * With old APBUARTs debug is enabled by setting LB and FL, since LB or
278         * DB are not reset we can not trust them. However since FL is reset we
279         * guess that we are debugging if FL is already set, the debugger set
280         * either LB or DB depending on UART capabilities.
281         */
282        if (priv->regs->ctrl & LEON_REG_UART_CTRL_FL) {
283                db |= priv->regs->ctrl & (LEON_REG_UART_CTRL_DB |
284                      LEON_REG_UART_CTRL_LB | LEON_REG_UART_CTRL_FL);
285        }
286
287        priv->regs->ctrl = db;
288
289        priv->cap = probecap(priv->regs);
290
291        /* The system console and Debug console may depend on this device, so
292         * initialize it straight away.
293         *
294         * We default to have System Console on first APBUART, user may override
295         * this behaviour by setting the syscon option to 0.
296         */
297        if (drvmgr_on_rootbus(dev) && first_uart) {
298                priv->condev.flags = CONSOLE_FLAG_SYSCON;
299                first_uart = 0;
300        } else {
301                priv->condev.flags = 0;
302        }
303
304        value = drvmgr_dev_key_get(priv->dev, "syscon", DRVMGR_KT_INT);
305        if (value) {
306                if (value->i)
307                        priv->condev.flags |= CONSOLE_FLAG_SYSCON;
308                else
309                        priv->condev.flags &= ~CONSOLE_FLAG_SYSCON;
310        }
311
312        /* Select 0=Polled, 1=IRQ, 2=Task-Driven UART Mode */
313        value = drvmgr_dev_key_get(priv->dev, "mode", DRVMGR_KT_INT);
314        if (value)
315                priv->mode = value->i;
316        else
317                priv->mode = TERMIOS_POLLED;
318        /* TERMIOS device handlers */
319        if (priv->mode == TERMIOS_IRQ_DRIVEN) {
320                priv->condev.handler = &handler_interrupt;
321        } else if (priv->mode == TERMIOS_TASK_DRIVEN) {
322                priv->condev.handler = &handler_task;
323        } else {
324                priv->condev.handler = &handler_polled;
325        }
326
327        priv->condev.fsname = NULL;
328        /* Get Filesystem name prefix */
329        prefix[0] = '\0';
330        if (drvmgr_get_dev_prefix(dev, prefix)) {
331                /* Got special prefix, this means we have a bus prefix
332                 * And we should use our "bus minor"
333                 */
334                sprintf(priv->devName, "/dev/%sapbuart%d", prefix, dev->minor_bus);
335                priv->condev.fsname = priv->devName;
336        } else {
337                sprintf(priv->devName, "/dev/apbuart%d", dev->minor_drv);
338        }
339
340        /* Register it as a console device, the console driver will register
341         * a termios device as well
342         */
343        console_dev_register(&priv->condev);
344
345        return DRVMGR_OK;
346}
347
348#ifdef APBUART_INFO_AVAIL
349static int apbuart_info(
350        struct drvmgr_dev *dev,
351        void (*print_line)(void *p, char *str),
352        void *p, int argc, char *argv[])
353{
354        struct apbuart_priv *priv = dev->priv;
355        char *str1;
356        char buf[64];
357
358        if (dev->priv == NULL)
359                return -DRVMGR_EINVAL;
360
361        if (priv->mode == TERMIOS_POLLED)
362                str1 = "TERMIOS_POLLED";
363        else if (priv->mode == TERMIOS_IRQ_DRIVEN)
364                str1 = "TERMIOS_IRQ_DRIVEN";
365        else if (priv->mode == TERMIOS_TASK_DRIVEN)
366                str1 = "TERMIOS_TASK_DRIVEN";
367        else
368                str1 = "BAD MODE";
369
370        sprintf(buf, "UART Mode:   %s", str1);
371        print_line(p, buf);
372        if (priv->condev.fsname) {
373                sprintf(buf, "FS Name:     %s", priv->condev.fsname);
374                print_line(p, buf);
375        }
376        sprintf(buf, "STATUS REG:  0x%x", priv->regs->status);
377        print_line(p, buf);
378        sprintf(buf, "CTRL REG:    0x%x", priv->regs->ctrl);
379        print_line(p, buf);
380        sprintf(buf, "SCALER REG:  0x%x  baud rate %d",
381                                priv->regs->scaler, apbuart_get_baud(priv));
382        print_line(p, buf);
383
384        return DRVMGR_OK;
385}
386#endif
387
388#ifndef LEON3
389/* This routine transmits a character, it will busy-wait until on character
390 * fits in the APBUART Transmit FIFO
391 */
392void apbuart_outbyte_polled(
393  struct apbuart_regs *regs,
394  unsigned char ch,
395  int do_cr_on_newline,
396  int wait_sent)
397{
398send:
399        while ((regs->status & LEON_REG_UART_STATUS_THE) == 0) {
400                /* Lower bus utilization while waiting for UART */
401                asm volatile ("nop"::); asm volatile ("nop"::);
402                asm volatile ("nop"::); asm volatile ("nop"::);
403                asm volatile ("nop"::); asm volatile ("nop"::);
404                asm volatile ("nop"::); asm volatile ("nop"::);
405        }
406        regs->data = (unsigned int) ch;
407
408        if ((ch == '\n') && do_cr_on_newline) {
409                ch = '\r';
410                goto send;
411        }
412
413        /* Wait until the character has been sent? */
414        if (wait_sent) {
415                while ((regs->status & LEON_REG_UART_STATUS_THE) == 0)
416                        ;
417        }
418}
419
420/* This routine polls for one character, return EOF if no character is available */
421int apbuart_inbyte_nonblocking(struct apbuart_regs *regs)
422{
423        if (regs->status & LEON_REG_UART_STATUS_ERR) {
424                regs->status = ~LEON_REG_UART_STATUS_ERR;
425        }
426
427        if ((regs->status & LEON_REG_UART_STATUS_DR) == 0)
428                return EOF;
429
430        return (int)regs->data;
431}
432#endif
433
434static bool first_open(
435        rtems_termios_tty *tty,
436        rtems_termios_device_context *base,
437        struct termios *term,
438        rtems_libio_open_close_args_t *args
439)
440{
441        struct apbuart_priv *uart = base_get_priv(base);
442
443        uart->tty = tty;
444
445        /* Inherit UART hardware parameters from bootloader on system console */
446        if (uart->condev.flags & CONSOLE_FLAG_SYSCON_GRANT) {
447                get_attributes(base, term);
448                term->c_oflag |= ONLCR;
449                set_attributes(base, term);
450        }
451
452        /* Enable TX/RX */
453        uart->regs->ctrl |= APBUART_CTRL_RE | APBUART_CTRL_TE;
454
455        if (uart->mode != TERMIOS_POLLED) {
456                int ret;
457                uint32_t ctrl;
458
459                /* Register interrupt and enable it */
460                ret = drvmgr_interrupt_register(
461                        uart->dev, 0, uart->devName, apbuart_cons_isr, tty
462                );
463                if (ret) {
464                        return false;
465                }
466
467                uart->sending = 0;
468
469                /* Turn on RX interrupts */
470                ctrl = uart->regs->ctrl;
471                ctrl |= APBUART_CTRL_RI;
472                if (uart->cap & CAP_DI) {
473                        /* Use RX FIFO interrupt only if delayed interrupt available. */
474                        ctrl |= (APBUART_CTRL_DI | APBUART_CTRL_RF);
475                }
476                uart->regs->ctrl = ctrl;
477        }
478
479        return true;
480}
481
482static void last_close(
483        rtems_termios_tty *tty,
484        rtems_termios_device_context *base,
485        rtems_libio_open_close_args_t *args
486)
487{
488        struct apbuart_priv *uart = base_get_priv(base);
489        rtems_interrupt_lock_context lock_context;
490
491        if (uart->mode != TERMIOS_POLLED) {
492                /* Turn off RX interrupts */
493                rtems_termios_device_lock_acquire(base, &lock_context);
494                uart->regs->ctrl &=
495                        ~(APBUART_CTRL_DI | APBUART_CTRL_RI | APBUART_CTRL_RF);
496                rtems_termios_device_lock_release(base, &lock_context);
497
498                /**** Flush device ****/
499                while (uart->sending) {
500                        /* Wait until all data has been sent */
501                }
502                while (
503                        (uart->regs->ctrl & APBUART_CTRL_TE) &&
504                        !(uart->regs->status & APBUART_STATUS_TS)
505                ) {
506                        /* Wait until all data has left shift register */
507                }
508
509                /* Disable and unregister interrupt handler */
510                drvmgr_interrupt_unregister(uart->dev, 0, apbuart_cons_isr, tty);
511        }
512
513#ifdef LEON3
514        /* Disable TX/RX if not used for DEBUG */
515        if (uart->regs != leon3_debug_uart)
516                uart->regs->ctrl &= ~(APBUART_CTRL_RE | APBUART_CTRL_TE);
517#endif
518}
519
520static int read_polled(rtems_termios_device_context *base)
521{
522        struct apbuart_priv *uart = base_get_priv(base);
523
524        return apbuart_inbyte_nonblocking(uart->regs);
525}
526
527/* This function is called from TERMIOS rxdaemon task without device lock. */
528static int read_task(rtems_termios_device_context *base)
529{
530        rtems_interrupt_lock_context lock_context;
531        struct apbuart_priv *uart = base_get_priv(base);
532        struct apbuart_regs *regs = uart->regs;
533        int cnt;
534        char buf[33];
535        struct rtems_termios_tty *tty;
536        uint32_t ctrl_add;
537
538        ctrl_add = APBUART_CTRL_RI;
539        if (uart->cap & CAP_DI) {
540                ctrl_add |= (APBUART_CTRL_DI | APBUART_CTRL_RF);
541        }
542        tty = uart->tty;
543        do {
544                cnt = 0;
545                while (
546                        (regs->status & APBUART_STATUS_DR) &&
547                        (cnt < sizeof(buf))
548                ) {
549                        buf[cnt] = regs->data;
550                        cnt++;
551                }
552                if (0 < cnt) {
553                        /* Tell termios layer about new characters */
554                        rtems_termios_enqueue_raw_characters(tty, &buf[0], cnt);
555                }
556
557                /*
558                 * Turn on RX interrupts. A new character in FIFO now may not
559                 * cause interrupt so we must check data ready again
560                 * afterwards.
561                 */
562                rtems_termios_device_lock_acquire(base, &lock_context);
563                regs->ctrl |= ctrl_add;
564                rtems_termios_device_lock_release(base, &lock_context);
565        } while (regs->status & APBUART_STATUS_DR);
566
567        return EOF;
568}
569
570
571struct apbuart_baud {
572        unsigned int num;
573        unsigned int baud;
574};
575static struct apbuart_baud apbuart_baud_table[] = {
576        {B50, 50},
577        {B75, 75},
578        {B110, 110},
579        {B134, 134},
580        {B150, 150},
581        {B200, 200},
582        {B300, 300},
583        {B600, 600},
584        {B1200, 1200},
585        {B1800, 1800},
586        {B2400, 2400},
587        {B4800, 4800},
588        {B9600, 9600},
589        {B19200, 19200},
590        {B38400, 38400},
591        {B57600, 57600},
592        {B115200, 115200},
593        {B230400, 230400},
594        {B460800, 460800},
595};
596#define BAUD_NUM (sizeof(apbuart_baud_table)/sizeof(struct apbuart_baud))
597
598static int apbuart_baud_num2baud(unsigned int num)
599{
600        int i;
601
602        for(i=0; i<BAUD_NUM; i++)
603                if (apbuart_baud_table[i].num == num)
604                        return apbuart_baud_table[i].baud;
605        return -1;
606}
607
608static struct apbuart_baud *apbuart_baud_find_closest(unsigned int baud)
609{
610        int i, diff;
611
612        for(i=0; i<BAUD_NUM-1; i++) {
613                diff = apbuart_baud_table[i+1].baud -
614                        apbuart_baud_table[i].baud;
615                if (baud < (apbuart_baud_table[i].baud + diff/2))
616                        return &apbuart_baud_table[i];
617        }
618        return &apbuart_baud_table[BAUD_NUM-1];
619}
620
621int apbuart_get_baud(struct apbuart_priv *uart)
622{
623        unsigned int core_clk_hz;
624        unsigned int scaler;
625
626        /* Get current scaler setting */
627        scaler = uart->regs->scaler;
628
629        /* Get APBUART core frequency */
630        drvmgr_freq_get(uart->dev, DEV_APB_SLV, &core_clk_hz);
631
632        /* Calculate baud rate from generator "scaler" number */
633        return core_clk_hz / ((scaler + 1) * 8);
634}
635
636static struct apbuart_baud *apbuart_get_baud_closest(struct apbuart_priv *uart)
637{
638        return apbuart_baud_find_closest(apbuart_get_baud(uart));
639}
640
641static bool set_attributes(
642        rtems_termios_device_context *base,
643        const struct termios *t
644)
645{
646        unsigned int core_clk_hz;
647        unsigned int scaler;
648        unsigned int ctrl;
649        int baud;
650        struct apbuart_priv *uart = base_get_priv(base);
651        rtems_interrupt_lock_context lock_context;
652
653        switch(t->c_cflag & CSIZE) {
654                default:
655                case CS5:
656                case CS6:
657                case CS7:
658                        /* Hardware doesn't support other than CS8 */
659                        return false;
660                case CS8:
661                        break;
662        }
663
664        rtems_termios_device_lock_acquire(base, &lock_context);
665
666        /* Read out current value */
667        ctrl = uart->regs->ctrl;
668
669        switch(t->c_cflag & (PARENB|PARODD)){
670                case (PARENB|PARODD):
671                        /* Odd parity */
672                        ctrl |= LEON_REG_UART_CTRL_PE|LEON_REG_UART_CTRL_PS;
673                        break;
674
675                case PARENB:
676                        /* Even parity */
677                        ctrl &= ~LEON_REG_UART_CTRL_PS;
678                        ctrl |= LEON_REG_UART_CTRL_PE;
679                        break;
680
681                default:
682                case 0:
683                case PARODD:
684                        /* No Parity */
685                        ctrl &= ~(LEON_REG_UART_CTRL_PS|LEON_REG_UART_CTRL_PE);
686        }
687
688        if (!(t->c_cflag & CLOCAL))
689                ctrl |= LEON_REG_UART_CTRL_FL;
690        else
691                ctrl &= ~LEON_REG_UART_CTRL_FL;
692
693        /* Update new settings */
694        uart->regs->ctrl = ctrl;
695
696        rtems_termios_device_lock_release(base, &lock_context);
697
698        /* Baud rate */
699  baud = apbuart_baud_num2baud(t->c_ospeed);
700        if (baud > 0){
701                /* Get APBUART core frequency */
702                drvmgr_freq_get(uart->dev, DEV_APB_SLV, &core_clk_hz);
703
704                /* Calculate Baud rate generator "scaler" number */
705                scaler = (((core_clk_hz*10)/(baud*8))-5)/10;
706
707                /* Set new baud rate by setting scaler */
708                uart->regs->scaler = scaler;
709        }
710
711        return true;
712}
713
714static void get_attributes(
715        rtems_termios_device_context *base,
716        struct termios *t
717)
718{
719        struct apbuart_priv *uart = base_get_priv(base);
720        unsigned int ctrl;
721        struct apbuart_baud *baud;
722
723  t->c_cflag = t->c_cflag & ~(CSIZE|PARENB|PARODD|CLOCAL);
724
725        /* Hardware support only CS8 */
726        t->c_cflag |= CS8;
727
728        /* Read out current parity */
729        ctrl = uart->regs->ctrl;
730        if (ctrl & LEON_REG_UART_CTRL_PE) {
731                if (ctrl & LEON_REG_UART_CTRL_PS)
732                        t->c_cflag |= PARENB|PARODD; /* Odd parity */
733                else
734                        t->c_cflag |= PARENB; /* Even parity */
735        }
736
737        if ((ctrl & LEON_REG_UART_CTRL_FL) == 0)
738                t->c_cflag |= CLOCAL;
739
740        baud = apbuart_get_baud_closest(uart);
741        t->c_cflag |= baud->num;
742}
743
744static void write_polled(
745        rtems_termios_device_context *base,
746        const char *buf,
747        size_t len
748)
749{
750        struct apbuart_priv *uart = base_get_priv(base);
751        int nwrite = 0;
752
753        while (nwrite < len) {
754                apbuart_outbyte_polled(uart->regs, *buf++, 0, 0);
755                nwrite++;
756        }
757}
758
759static void write_interrupt(
760        rtems_termios_device_context *base,
761        const char *buf,
762        size_t len
763)
764{
765        struct apbuart_priv *uart = base_get_priv(base);
766        struct apbuart_regs *regs = uart->regs;
767        int sending;
768        unsigned int ctrl;
769
770        ctrl = regs->ctrl;
771
772        if (len > 0) {
773                /*
774                 * sending is used to remember how much we have outstanding so
775                 * we can tell termios later.
776                 */
777                /* Enable TX interrupt (interrupt is edge-triggered) */
778                regs->ctrl = ctrl | APBUART_CTRL_TI;
779
780                if (ctrl & APBUART_CTRL_FA) {
781                        /* APBUART with FIFO.. Fill as many as FIFO allows */
782                        sending = 0;
783                        while (
784                                ((regs->status & APBUART_STATUS_TF) == 0) &&
785                                (sending < len)
786                        ) {
787                                regs->data = *buf;
788                                buf++;
789                                sending++;
790                        }
791                } else {
792                        /* start UART TX, this will result in an interrupt when done */
793                        regs->data = *buf;
794
795                        sending = 1;
796                }
797        } else {
798                /* No more to send, disable TX interrupts */
799                regs->ctrl = ctrl & ~APBUART_CTRL_TI;
800
801                /* Tell close that we sent everything */
802                sending = 0;
803        }
804
805        uart->sending = sending;
806}
807
808/* Handle UART interrupts */
809static void apbuart_cons_isr(void *arg)
810{
811        rtems_termios_tty *tty = arg;
812        rtems_termios_device_context *base;
813        struct console_dev *condev = rtems_termios_get_device_context(tty);
814        struct apbuart_priv *uart = condev_get_priv(condev);
815        struct apbuart_regs *regs = uart->regs;
816        unsigned int status;
817        char buf[33];
818        int cnt;
819
820        if (uart->mode == TERMIOS_TASK_DRIVEN) {
821                if ((status = regs->status) & APBUART_STATUS_DR) {
822                        rtems_interrupt_lock_context lock_context;
823
824                        /* Turn off RX interrupts */
825                        base = rtems_termios_get_device_context(tty);
826                        rtems_termios_device_lock_acquire(base, &lock_context);
827                        regs->ctrl &=
828                            ~(APBUART_CTRL_DI | APBUART_CTRL_RI |
829                              APBUART_CTRL_RF);
830                        rtems_termios_device_lock_release(base, &lock_context);
831                        /* Activate termios RX daemon task */
832                        rtems_termios_rxirq_occured(tty);
833                }
834        } else {
835                /*
836                 * Get all new characters from APBUART RX (FIFO) and store them
837                 * on the stack. Then tell termios about the new characters.
838                 * Maximum APBUART RX FIFO size is 32 characters.
839                 */
840                cnt = 0;
841                while (
842                        ((status=regs->status) & APBUART_STATUS_DR) &&
843                        (cnt < sizeof(buf))
844                ) {
845                        buf[cnt] = regs->data;
846                        cnt++;
847                }
848                if (0 < cnt) {
849                        /* Tell termios layer about new characters */
850                        rtems_termios_enqueue_raw_characters(tty, &buf[0], cnt);
851                }
852        }
853
854        if (uart->sending && (status & APBUART_STATUS_TE)) {
855                /* Tell close that we sent everything */
856                cnt = uart->sending;
857
858                /*
859                 * Tell termios how much we have sent. dequeue() may call
860                 * write_interrupt() to refill the transmitter.
861                 * write_interrupt() will eventually be called with 0 len to
862                 * disable TX interrupts.
863                 */
864                rtems_termios_dequeue_characters(tty, cnt);
865        }
866}
867
Note: See TracBrowser for help on using the repository browser.