source: rtems/c/src/lib/libbsp/sparc/shared/uart/apbuart_cons.c @ 6860ddb

5
Last change on this file since 6860ddb was 6860ddb, checked in by Martin Aberg <maberg@…>, on 03/14/17 at 16:27:57

leon, apbuart: Optimized RX processing in ISR

Limit the number of calls to termios rtems_termios_enqueue_raw_characters() by
reading out the RX FIFO on stack and then call termios only once.

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