source: rtems/bsps/arm/csb336/console/uart.c @ a3fe23c

5
Last change on this file since a3fe23c was d7d66d7, checked in by Sebastian Huber <sebastian.huber@…>, on 04/19/18 at 04:28:01

bsps: Move console drivers to bsps

This patch is a part of the BSP source reorganization.

Update #3285.

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