source: rtems/c/src/lib/libbsp/arm/csb336/console/uart.c @ 09d053e8

4.104.115
Last change on this file since 09d053e8 was 09d053e8, checked in by Joel Sherrill <joel.sherrill@…>, on 04/07/10 at 21:48:14

2010-04-07 Joel Sherrill <joel.sherrill@…>

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