source: rtems/c/src/lib/libbsp/sparc/shared/uart/apbuart_cons.c @ 9631e5a9

5
Last change on this file since 9631e5a9 was e5e44bdb, checked in by Martin Aberg <maberg@…>, on 03/14/17 at 16:46:12

leon, apbuart: Wait for shift register on close

Do not disable transmitter until shift register is empty when closing device.
It is correct to look at the sending software state when closing the device.
However, the sending state must be cleared only when everything is sent.

  • 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);
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                while (
501                        (uart->regs->ctrl & APBUART_CTRL_TE) &&
502                        !(uart->regs->status & APBUART_STATUS_TS)
503                ) {
504                        /* Wait until all data has left shift register */
505                }
506
507                /* Disable and unregister interrupt handler */
508                drvmgr_interrupt_unregister(uart->dev, 0, apbuart_cons_isr, tty);
509        }
510
511#ifdef LEON3
512        /* Disable TX/RX if not used for DEBUG */
513        if (uart->regs != dbg_uart)
514                uart->regs->ctrl &= ~(APBUART_CTRL_RE | APBUART_CTRL_TE);
515#endif
516}
517
518static int read_polled(rtems_termios_device_context *base)
519{
520        struct apbuart_priv *uart = base_get_priv(base);
521
522        return apbuart_inbyte_nonblocking(uart->regs);
523}
524
525/* This function is called from TERMIOS rxdaemon task without device lock. */
526static int read_task(rtems_termios_device_context *base)
527{
528        rtems_interrupt_lock_context lock_context;
529        struct apbuart_priv *uart = base_get_priv(base);
530        struct apbuart_regs *regs = uart->regs;
531        int cnt;
532        char buf[33];
533        struct rtems_termios_tty *tty;
534        uint32_t ctrl_add;
535
536        ctrl_add = APBUART_CTRL_RI;
537        if (uart->cap & CAP_DI) {
538                ctrl_add |= (APBUART_CTRL_DI | APBUART_CTRL_RF);
539        }
540        tty = uart->tty;
541        do {
542                cnt = 0;
543                while (
544                        (regs->status & APBUART_STATUS_DR) &&
545                        (cnt < sizeof(buf))
546                ) {
547                        buf[cnt] = regs->data;
548                        cnt++;
549                }
550                if (0 < cnt) {
551                        /* Tell termios layer about new characters */
552                        rtems_termios_enqueue_raw_characters(tty, &buf[0], cnt);
553                }
554
555                /*
556                 * Turn on RX interrupts. A new character in FIFO now may not
557                 * cause interrupt so we must check data ready again
558                 * afterwards.
559                 */
560                rtems_termios_device_lock_acquire(base, &lock_context);
561                regs->ctrl |= ctrl_add;
562                rtems_termios_device_lock_release(base, &lock_context);
563        } while (regs->status & APBUART_STATUS_DR);
564
565        return EOF;
566}
567
568
569struct apbuart_baud {
570        unsigned int num;
571        unsigned int baud;
572};
573static struct apbuart_baud apbuart_baud_table[] = {
574        {B50, 50},
575        {B75, 75},
576        {B110, 110},
577        {B134, 134},
578        {B150, 150},
579        {B200, 200},
580        {B300, 300},
581        {B600, 600},
582        {B1200, 1200},
583        {B1800, 1800},
584        {B2400, 2400},
585        {B4800, 4800},
586        {B9600, 9600},
587        {B19200, 19200},
588        {B38400, 38400},
589        {B57600, 57600},
590        {B115200, 115200},
591        {B230400, 230400},
592        {B460800, 460800},
593};
594#define BAUD_NUM (sizeof(apbuart_baud_table)/sizeof(struct apbuart_baud))
595
596static int apbuart_baud_num2baud(unsigned int num)
597{
598        int i;
599
600        for(i=0; i<BAUD_NUM; i++)
601                if (apbuart_baud_table[i].num == num)
602                        return apbuart_baud_table[i].baud;
603        return -1;
604}
605
606static struct apbuart_baud *apbuart_baud_find_closest(unsigned int baud)
607{
608        int i, diff;
609
610        for(i=0; i<BAUD_NUM-1; i++) {
611                diff = apbuart_baud_table[i+1].baud -
612                        apbuart_baud_table[i].baud;
613                if (baud < (apbuart_baud_table[i].baud + diff/2))
614                        return &apbuart_baud_table[i];
615        }
616        return &apbuart_baud_table[BAUD_NUM-1];
617}
618
619int apbuart_get_baud(struct apbuart_priv *uart)
620{
621        unsigned int core_clk_hz;
622        unsigned int scaler;
623
624        /* Get current scaler setting */
625        scaler = uart->regs->scaler;
626
627        /* Get APBUART core frequency */
628        drvmgr_freq_get(uart->dev, DEV_APB_SLV, &core_clk_hz);
629
630        /* Calculate baud rate from generator "scaler" number */
631        return core_clk_hz / ((scaler + 1) * 8);
632}
633
634static struct apbuart_baud *apbuart_get_baud_closest(struct apbuart_priv *uart)
635{
636        return apbuart_baud_find_closest(apbuart_get_baud(uart));
637}
638
639static bool set_attributes(
640        rtems_termios_device_context *base,
641        const struct termios *t
642)
643{
644        unsigned int core_clk_hz;
645        unsigned int scaler;
646        unsigned int ctrl;
647        int baud;
648        struct apbuart_priv *uart = base_get_priv(base);
649        rtems_interrupt_lock_context lock_context;
650
651        switch(t->c_cflag & CSIZE) {
652                default:
653                case CS5:
654                case CS6:
655                case CS7:
656                        /* Hardware doesn't support other than CS8 */
657                        return false;
658                case CS8:
659                        break;
660        }
661
662        rtems_termios_device_lock_acquire(base, &lock_context);
663
664        /* Read out current value */
665        ctrl = uart->regs->ctrl;
666
667        switch(t->c_cflag & (PARENB|PARODD)){
668                case (PARENB|PARODD):
669                        /* Odd parity */
670                        ctrl |= LEON_REG_UART_CTRL_PE|LEON_REG_UART_CTRL_PS;
671                        break;
672
673                case PARENB:
674                        /* Even parity */
675                        ctrl &= ~LEON_REG_UART_CTRL_PS;
676                        ctrl |= LEON_REG_UART_CTRL_PE;
677                        break;
678
679                default:
680                case 0:
681                case PARODD:
682                        /* No Parity */
683                        ctrl &= ~(LEON_REG_UART_CTRL_PS|LEON_REG_UART_CTRL_PE);
684        }
685
686        if (!(t->c_cflag & CLOCAL))
687                ctrl |= LEON_REG_UART_CTRL_FL;
688        else
689                ctrl &= ~LEON_REG_UART_CTRL_FL;
690
691        /* Update new settings */
692        uart->regs->ctrl = ctrl;
693
694        rtems_termios_device_lock_release(base, &lock_context);
695
696        /* Baud rate */
697  baud = apbuart_baud_num2baud(t->c_ospeed);
698        if (baud > 0){
699                /* Get APBUART core frequency */
700                drvmgr_freq_get(uart->dev, DEV_APB_SLV, &core_clk_hz);
701
702                /* Calculate Baud rate generator "scaler" number */
703                scaler = (((core_clk_hz*10)/(baud*8))-5)/10;
704
705                /* Set new baud rate by setting scaler */
706                uart->regs->scaler = scaler;
707        }
708
709        return true;
710}
711
712static void get_attributes(
713        rtems_termios_device_context *base,
714        struct termios *t
715)
716{
717        struct apbuart_priv *uart = base_get_priv(base);
718        unsigned int ctrl;
719        struct apbuart_baud *baud;
720
721  t->c_cflag = t->c_cflag & ~(CSIZE|PARENB|PARODD|CLOCAL);
722
723        /* Hardware support only CS8 */
724        t->c_cflag |= CS8;
725
726        /* Read out current parity */
727        ctrl = uart->regs->ctrl;
728        if (ctrl & LEON_REG_UART_CTRL_PE) {
729                if (ctrl & LEON_REG_UART_CTRL_PS)
730                        t->c_cflag |= PARENB|PARODD; /* Odd parity */
731                else
732                        t->c_cflag |= PARENB; /* Even parity */
733        }
734
735        if ((ctrl & LEON_REG_UART_CTRL_FL) == 0)
736                t->c_cflag |= CLOCAL;
737
738        baud = apbuart_get_baud_closest(uart);
739        t->c_cflag |= baud->num;
740}
741
742static void write_polled(
743        rtems_termios_device_context *base,
744        const char *buf,
745        size_t len
746)
747{
748        struct apbuart_priv *uart = base_get_priv(base);
749        int nwrite = 0;
750
751        while (nwrite < len) {
752                apbuart_outbyte_polled(uart->regs, *buf++, 0, 0);
753                nwrite++;
754        }
755}
756
757static void write_interrupt(
758        rtems_termios_device_context *base,
759        const char *buf,
760        size_t len
761)
762{
763        struct apbuart_priv *uart = base_get_priv(base);
764        struct apbuart_regs *regs = uart->regs;
765        int sending;
766        unsigned int ctrl;
767
768        ctrl = regs->ctrl;
769
770        if (len > 0) {
771                /*
772                 * sending is used to remember how much we have outstanding so
773                 * we can tell termios later.
774                 */
775                /* Enable TX interrupt (interrupt is edge-triggered) */
776                regs->ctrl = ctrl | APBUART_CTRL_TI;
777
778                if (ctrl & APBUART_CTRL_FA) {
779                        /* APBUART with FIFO.. Fill as many as FIFO allows */
780                        sending = 0;
781                        while (
782                                ((regs->status & APBUART_STATUS_TF) == 0) &&
783                                (sending < len)
784                        ) {
785                                regs->data = *buf;
786                                buf++;
787                                sending++;
788                        }
789                } else {
790                        /* start UART TX, this will result in an interrupt when done */
791                        regs->data = *buf;
792
793                        sending = 1;
794                }
795        } else {
796                /* No more to send, disable TX interrupts */
797                regs->ctrl = ctrl & ~APBUART_CTRL_TI;
798
799                /* Tell close that we sent everything */
800                sending = 0;
801        }
802
803        uart->sending = sending;
804}
805
806/* Handle UART interrupts */
807static void apbuart_cons_isr(void *arg)
808{
809        rtems_termios_tty *tty = arg;
810        rtems_termios_device_context *base;
811        struct console_dev *condev = rtems_termios_get_device_context(tty);
812        struct apbuart_priv *uart = condev_get_priv(condev);
813        struct apbuart_regs *regs = uart->regs;
814        unsigned int status;
815        char buf[33];
816        int cnt;
817
818        if (uart->mode == TERMIOS_TASK_DRIVEN) {
819                if ((status = regs->status) & APBUART_STATUS_DR) {
820                        rtems_interrupt_lock_context lock_context;
821
822                        /* Turn off RX interrupts */
823                        base = rtems_termios_get_device_context(tty);
824                        rtems_termios_device_lock_acquire(base, &lock_context);
825                        regs->ctrl &=
826                            ~(APBUART_CTRL_DI | APBUART_CTRL_RI |
827                              APBUART_CTRL_RF);
828                        rtems_termios_device_lock_release(base, &lock_context);
829                        /* Activate termios RX daemon task */
830                        rtems_termios_rxirq_occured(tty);
831                }
832        } else {
833                /*
834                 * Get all new characters from APBUART RX (FIFO) and store them
835                 * on the stack. Then tell termios about the new characters.
836                 * Maximum APBUART RX FIFO size is 32 characters.
837                 */
838                cnt = 0;
839                while (
840                        ((status=regs->status) & APBUART_STATUS_DR) &&
841                        (cnt < sizeof(buf))
842                ) {
843                        buf[cnt] = regs->data;
844                        cnt++;
845                }
846                if (0 < cnt) {
847                        /* Tell termios layer about new characters */
848                        rtems_termios_enqueue_raw_characters(tty, &buf[0], cnt);
849                }
850        }
851
852        if (uart->sending && (status & APBUART_STATUS_TE)) {
853                /* Tell close that we sent everything */
854                cnt = uart->sending;
855
856                /*
857                 * Tell termios how much we have sent. dequeue() may call
858                 * write_interrupt() to refill the transmitter.
859                 * write_interrupt() will eventually be called with 0 len to
860                 * disable TX interrupts.
861                 */
862                rtems_termios_dequeue_characters(tty, cnt);
863        }
864}
865
Note: See TracBrowser for help on using the repository browser.