source: rtems/c/src/lib/libbsp/arm/csb336/console/uart.c @ 1c6926c1

Last change on this file since 1c6926c1 was 1c6926c1, checked in by Kevin Kirspel <kevin-kirspel@…>, on Mar 21, 2017 at 7:39:48 PM

termios: Synchronize with latest FreeBSD headers

Adding modified FreeBSD headers to synchronize RTEMS termios with
FreeBSD. Modify termios to support dedicated input and output baud for
termios structure. Updated BSPs to use dedicated input and output baud
in termios structure. Updated tools to use dedicated input and output
baud in termios structure. Updated termios testsuites to use dedicated
input and output baud in termios structure.

Close #2897.

  • Property mode set to 100644
File size: 11.9 KB
Line 
1/*
2 * Console driver for MC9328XML UARTs.
3 *
4 * Written Jay Monkman <jtm@lopingdog.com>
5 * Copyright (c) 2005 by Loping Dog Embedded Systems
6 *
7 * The license and distribution terms for this file may be
8 * found in the file LICENSE in this distribution or at
9 *    http://www.rtems.org/license
10 */
11#include <bsp.h>
12#include <rtems/libio.h>
13#include <libchip/sersupp.h>
14#include <rtems/error.h>
15#include <rtems/bspIo.h>
16#include <assert.h>
17#include <termios.h>
18#include <rtems/irq.h>
19#include <bsp/irq.h>
20#include <mc9328mxl.h>
21#include <rtems/console.h>
22
23/* Define this to use interrupt driver UART driver */
24#define USE_INTERRUPTS 1
25
26/* How many serial ports? */
27#define NUM_DEVS       2
28#define poll_write(c)  imx_uart_poll_write_char(0, c)
29#define poll_read()  imx_uart_poll_read_char(0)
30
31static int imx_uart_first_open(int, int, void *);
32static int imx_uart_last_close(int, int, void *);
33static int imx_uart_poll_read(int);
34static int imx_uart_set_attrs(int, const struct termios *);
35static void imx_uart_init(int minor);
36static void imx_uart_set_baud(int, int);
37static ssize_t imx_uart_poll_write(int, const char *, size_t);
38static int imx_uart_poll_read_char(int minor);
39static void imx_uart_poll_write_char(int minor, char c);
40static void _BSP_output_char(char c);
41static int _BSP_poll_char(void);
42
43#if USE_INTERRUPTS
44static void imx_uart_tx_isr(void *);
45static void imx_uart_rx_isr(void *);
46static void imx_uart_isr_on(rtems_vector_number);
47static void imx_uart_isr_off(rtems_vector_number);
48static ssize_t imx_uart_intr_write(int, const char *, size_t);
49static rtems_vector_number imx_uart_name_transmit(int minor);
50static rtems_vector_number imx_uart_name_receive(int minor);
51#endif
52
53/* TERMIOS callbacks */
54#if USE_INTERRUPTS
55rtems_termios_callbacks imx_uart_cbacks = {
56    .firstOpen            = imx_uart_first_open,
57    .lastClose            = imx_uart_last_close,
58    .pollRead             = NULL,
59    .write                = imx_uart_intr_write,
60    .setAttributes        = imx_uart_set_attrs,
61    .stopRemoteTx         = NULL,
62    .startRemoteTx        = NULL,
63    .outputUsesInterrupts = 1,
64};
65#else
66rtems_termios_callbacks imx_uart_cbacks = {
67    .firstOpen            = imx_uart_first_open,
68    .lastClose            = imx_uart_last_close,
69    .pollRead             = imx_uart_poll_read,
70    .write                = imx_uart_poll_write,
71    .setAttributes        = imx_uart_set_attrs,
72    .stopRemoteTx         = NULL,
73    .startRemoteTx        = NULL,
74    .outputUsesInterrupts = 0,
75};
76#endif
77
78typedef struct {
79    int minor;
80    mc9328mxl_uart_regs_t * regs;
81    volatile const char *buf;
82    volatile int len;
83    volatile int idx;
84    void *tty;
85} imx_uart_data_t;
86
87static imx_uart_data_t imx_uart_data[NUM_DEVS];
88
89rtems_device_driver console_initialize(
90    rtems_device_major_number  major,
91    rtems_device_minor_number  minor,
92    void                      *arg
93)
94{
95    rtems_status_code status;
96    int i;
97
98    for (i = 0; i < NUM_DEVS; i++) {
99        imx_uart_init(i);
100    }
101
102    rtems_termios_initialize();
103
104    /* /dev/console and /dev/tty0 are the same */
105    status = rtems_io_register_name("/dev/console", major, 0);
106    if (status != RTEMS_SUCCESSFUL) {
107        rtems_panic("%s:%d Error registering /dev/console :: %d\n",
108                    __FUNCTION__, __LINE__, status);
109    }
110
111    status = rtems_io_register_name("/dev/tty0", major, 0);
112    if (status != RTEMS_SUCCESSFUL) {
113        rtems_panic("%s:%d Error registering /dev/tty0 :: %d\n",
114                    __FUNCTION__, __LINE__, status);
115    }
116
117    status = rtems_io_register_name("/dev/tty1", major, 1);
118    if (status != RTEMS_SUCCESSFUL) {
119        rtems_panic("%s:%d Error registering /dev/tty1 :: %d\n",
120                    __FUNCTION__, __LINE__, status);
121    }
122    return RTEMS_SUCCESSFUL;
123}
124
125rtems_device_driver console_open(
126    rtems_device_major_number major,
127    rtems_device_minor_number minor,
128    void                    * arg
129)
130{
131    rtems_status_code rc;
132
133    if (minor > (NUM_DEVS - 1)) {
134        return RTEMS_INVALID_NUMBER;
135    }
136
137    rc = rtems_termios_open(major, minor, arg, &imx_uart_cbacks);
138
139    return rc;
140}
141
142rtems_device_driver console_close(
143    rtems_device_major_number major,
144    rtems_device_minor_number minor,
145    void                    * arg
146)
147{
148    return rtems_termios_close(arg);
149}
150
151rtems_device_driver console_read(
152    rtems_device_major_number major,
153    rtems_device_minor_number minor,
154    void                    * arg
155)
156{
157  return rtems_termios_read(arg);
158}
159
160rtems_device_driver console_write(
161    rtems_device_major_number major,
162    rtems_device_minor_number minor,
163    void                    * arg
164)
165{
166  return rtems_termios_write(arg);
167}
168
169rtems_device_driver console_control(
170    rtems_device_major_number major,
171    rtems_device_minor_number minor,
172    void                    * arg
173)
174{
175  return rtems_termios_ioctl(arg);
176}
177
178static void imx_uart_init(int minor)
179{
180    imx_uart_data[minor].minor = minor;
181    imx_uart_data[minor].buf   = NULL;
182    imx_uart_data[minor].len   = 0;
183    imx_uart_data[minor].idx   = 0;
184
185    if (minor == 0) {
186        imx_uart_data[minor].regs =
187            (mc9328mxl_uart_regs_t *) MC9328MXL_UART1_BASE;
188    } else if (minor == 1) {
189        imx_uart_data[minor].regs =
190            (mc9328mxl_uart_regs_t *) MC9328MXL_UART2_BASE;
191    } else {
192        rtems_panic("%s:%d Unknown UART minor number %d\n",
193                    __FUNCTION__, __LINE__, minor);
194    }
195
196    imx_uart_data[minor].regs->cr1 = (
197        MC9328MXL_UART_CR1_UARTCLKEN |
198        MC9328MXL_UART_CR1_UARTEN);
199
200    imx_uart_data[minor].regs->cr2 = (
201        MC9328MXL_UART_CR2_IRTS |
202        MC9328MXL_UART_CR2_WS   |
203        MC9328MXL_UART_CR2_TXEN |
204        MC9328MXL_UART_CR2_RXEN |
205        MC9328MXL_UART_CR2_SRST);
206
207    imx_uart_data[minor].regs->cr3 = 0;
208
209    imx_uart_data[minor].regs->cr4 = 0;
210
211    imx_uart_data[minor].regs->fcr = (
212        MC9328MXL_UART_FCR_TXTL(32) |
213        MC9328MXL_UART_FCR_RFDIV_1 |
214        MC9328MXL_UART_FCR_RXTL(1));
215
216    imx_uart_set_baud(minor, 38400);
217
218}
219
220static int imx_uart_first_open(int major, int minor, void *arg)
221{
222    rtems_libio_open_close_args_t *args = arg;
223    rtems_status_code status = RTEMS_SUCCESSFUL;
224
225    imx_uart_data[minor].tty   = args->iop->data1;
226
227#if USE_INTERRUPTS
228    status = rtems_interrupt_handler_install(
229        imx_uart_name_transmit(minor),
230        "UART",
231        RTEMS_INTERRUPT_UNIQUE,
232        imx_uart_tx_isr,
233        &imx_uart_data[minor]
234    );
235    assert(status == RTEMS_SUCCESSFUL);
236    imx_uart_isr_on(imx_uart_name_transmit(minor));
237
238    status = rtems_interrupt_handler_install(
239        imx_uart_name_receive(minor),
240        "UART",
241        RTEMS_INTERRUPT_UNIQUE,
242        imx_uart_rx_isr,
243        &imx_uart_data[minor]
244    );
245    assert(status == RTEMS_SUCCESSFUL);
246    imx_uart_isr_on(imx_uart_name_receive(minor));
247
248    imx_uart_data[minor].regs->cr1 |= MC9328MXL_UART_CR1_RRDYEN;
249#endif
250
251    return 0;
252}
253
254static int imx_uart_last_close(int major, int minor, void *arg)
255{
256#if USE_INTERRUPTS
257    rtems_status_code status = RTEMS_SUCCESSFUL;
258
259    imx_uart_isr_off(imx_uart_name_transmit(minor));
260    status = rtems_interrupt_handler_remove(
261        imx_uart_name_transmit(minor),
262        imx_uart_tx_isr,
263        &imx_uart_data[minor]
264    );
265    assert(status == RTEMS_SUCCESSFUL);
266
267    imx_uart_isr_off(imx_uart_name_receive(minor));
268    status = rtems_interrupt_handler_remove(
269        imx_uart_name_receive(minor),
270        imx_uart_rx_isr,
271        &imx_uart_data[minor]
272    );
273    assert(status == RTEMS_SUCCESSFUL);
274#endif
275
276    return 0;
277}
278
279static int imx_uart_poll_read(int minor)
280{
281    if (imx_uart_data[minor].regs->sr2 & MC9328MXL_UART_SR2_RDR) {
282        return imx_uart_data[minor].regs->rxd & 0xff;
283    } else {
284        return -1;
285    }
286}
287
288
289static ssize_t imx_uart_poll_write(int minor, const char *buf, size_t len)
290{
291    int i;
292    for (i = 0; i < len; i++) {
293        /* Wait for there to be room in the fifo */
294        while (!(imx_uart_data[minor].regs->sr2 & MC9328MXL_UART_SR2_TXDC)) {
295            continue;
296        }
297
298        imx_uart_data[minor].regs->txd = buf[i];
299    }
300    return 1;
301
302}
303
304#if USE_INTERRUPTS
305static ssize_t imx_uart_intr_write(int minor, const char *buf, size_t len)
306{
307    if (len > 0) {
308        imx_uart_data[minor].buf = buf;
309        imx_uart_data[minor].len = len;
310        imx_uart_data[minor].idx = 0;
311
312        imx_uart_data[minor].regs->cr1 |= MC9328MXL_UART_CR1_TXMPTYEN;
313    }
314
315    return 1;
316}
317#endif
318
319
320/* This is for setting baud rate, bits, etc. */
321static int imx_uart_set_attrs(int minor, const struct termios *t)
322{
323    int baud;
324
325    baud = rtems_termios_baud_to_number(t->c_ospeed);
326    imx_uart_set_baud(minor, baud);
327
328    return 0;
329}
330
331#if USE_INTERRUPTS
332static void imx_uart_isr_on(rtems_vector_number name)
333{
334    MC9328MXL_AITC_INTENNUM = name;
335}
336static void imx_uart_isr_off(rtems_vector_number name)
337{
338    MC9328MXL_AITC_INTDISNUM = name;
339}
340
341static void imx_uart_rx_isr(void * param)
342{
343    imx_uart_data_t *uart_data = param;
344    char buf[32];
345    int i=0;
346
347    while (uart_data->regs->sr2 & MC9328MXL_UART_SR2_RDR) {
348        buf[i] = uart_data->regs->rxd & 0xff;
349        i++;
350    }
351
352    rtems_termios_enqueue_raw_characters(uart_data->tty, buf, i);
353}
354
355static void imx_uart_tx_isr(void * param)
356{
357    imx_uart_data_t *uart_data = param;
358    int len;
359    int minor = uart_data->minor;
360
361
362    if (uart_data->idx < uart_data->len) {
363        while ( (uart_data->regs->sr1 & MC9328MXL_UART_SR1_TRDY) &&
364                (uart_data->idx < uart_data->len)) {
365            uart_data->regs->txd = uart_data->buf[uart_data->idx];
366            uart_data->idx++;
367        }
368    } else {
369        len = uart_data->len;
370        uart_data->len = 0;
371        imx_uart_data[minor].regs->cr1 &= ~MC9328MXL_UART_CR1_TXMPTYEN;
372        rtems_termios_dequeue_characters(uart_data->tty, len);
373    }
374}
375
376static rtems_vector_number imx_uart_name_transmit(int minor)
377{
378    if (minor == 0) {
379        return BSP_INT_UART1_TX;
380    } else if (minor == 1) {
381        return BSP_INT_UART2_TX;
382    }
383
384    assert(0);
385}
386
387static rtems_vector_number imx_uart_name_receive(int minor)
388{
389    if (minor == 0) {
390        return BSP_INT_UART1_RX;
391    } else if (minor == 1) {
392        return BSP_INT_UART2_RX;
393    }
394
395    assert(0);
396}
397#endif
398
399/*
400 * Set the UART's baud rate. The calculation is:
401 *   (baud * 16) / ref_freq  = num/demom
402 *
403 *   ref_freq = perclk1 / RFDIV[2:0]
404 *   BIR = num - 1
405 *   BMR = demom - 1
406 *
407 * Setting 'num' to 16 yields this equation:
408 *    demom = ref_freq / baud
409 */
410static void imx_uart_set_baud(int minor, int baud)
411{
412    unsigned int perclk1;
413    unsigned int denom;
414    unsigned int ref_freq = 0;
415    uint32_t fcr;
416
417    perclk1 = get_perclk1_freq();
418    fcr = imx_uart_data[minor].regs->fcr;
419
420    switch(fcr & MC9328MXL_UART_FCR_RFDIV_MASK) {
421    case MC9328MXL_UART_FCR_RFDIV_1:  ref_freq = perclk1/1; break;
422    case MC9328MXL_UART_FCR_RFDIV_2:  ref_freq = perclk1/2; break;
423    case MC9328MXL_UART_FCR_RFDIV_3:  ref_freq = perclk1/3; break;
424    case MC9328MXL_UART_FCR_RFDIV_4:  ref_freq = perclk1/4; break;
425    case MC9328MXL_UART_FCR_RFDIV_5:  ref_freq = perclk1/5; break;
426    case MC9328MXL_UART_FCR_RFDIV_6:  ref_freq = perclk1/6; break;
427    case MC9328MXL_UART_FCR_RFDIV_7:  ref_freq = perclk1/7; break;
428    default:
429        rtems_panic("%s:%d Unknown RFDIV: 0x%x",
430                    __FUNCTION__, __LINE__,
431                    fcr & MC9328MXL_UART_FCR_RFDIV_MASK);
432        break;
433    }
434
435    denom = ref_freq / baud;
436
437    imx_uart_data[minor].regs->bir = 0xf;
438    imx_uart_data[minor].regs->bmr = denom;
439}
440
441
442/*
443 * Polled, non-blocking read from UART
444 */
445static int imx_uart_poll_read_char(int minor)
446{
447    return imx_uart_poll_read(minor);
448}
449
450/*
451 * Polled, blocking write from UART
452 */
453static void  imx_uart_poll_write_char(int minor, char c)
454{
455    imx_uart_poll_write(minor, &c, 1);
456}
457
458/*
459 * Functions for printk() and friends.
460 */
461static void _BSP_output_char(char c)
462{
463    poll_write(c);
464    if (c == '\n') {
465        poll_write('\r');
466    }
467}
468
469BSP_output_char_function_type BSP_output_char = _BSP_output_char;
470
471static int _BSP_poll_char(void)
472{
473    return poll_read();
474}
475
476BSP_polling_getchar_function_type BSP_poll_char = _BSP_poll_char;
477
478
Note: See TracBrowser for help on using the repository browser.