source: rtems/c/src/lib/libbsp/arm/csb336/console/uart.c @ 748efe9

5
Last change on this file since 748efe9 was 2fb6d161, checked in by Joel Sherrill <joel@…>, on 03/29/16 at 18:10:49

arm/csb336: Remove include of <rtems/console.h> from <bsp.h> and fix warnings

  • 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_cflag & CBAUD);
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.