1 Index: rtems/c/src/lib/libbsp/arm/csb336/console/uart.c
2 ===================================================================
3 --- rtems.orig/c/src/lib/libbsp/arm/csb336/console/uart.c
4 +++ rtems/c/src/lib/libbsp/arm/csb336/console/uart.c
7 - * console driver for MC9328XML UARTs
8 + * Console driver for MC9328XML UARTs.
10 - * This driver uses the shared console driver in
11 - * ...../libbsp/shared/console.c
12 + * Written Jay Monkman <jtm@lopingdog.com>
13 + * Copyright (c) 2005 by Loping Dog Embedded Systems
15 - * If you want the driver to be interrupt driven, you
16 - * need to write the ISR, and in the ISR insert the
17 - * chars into termios's queue.
18 + * The license and distribution terms for this file may be
19 + * found in the file LICENSE in this distribution or at
20 + * http://www.rtems.com/license
22 - * Copyright (c) 2004 Cogent Computer Systems
23 - * Written by Jay Monkman <jtm@lopingdog.com>
25 - * The license and distribution terms for this file may be
26 - * found in the file LICENSE in this distribution or at
28 - * http://www.OARcorp.com/rtems/license.html.
31 - * $Id: uart.c,v 1.1 2004/07/15 06:12:05 jtm Exp $
33 -#include <bsp.h> /* Must be before libio.h */
37 #include <rtems/libio.h>
39 +#include <libchip/sersupp.h>
40 +#include <rtems/error.h>
41 #include <rtems/bspIo.h>
43 -/* Put the CPU (or UART) specific header file #include here */
46 #include <mc9328mxl.h>
47 -#include <libchip/serial.h>
48 -#include <libchip/sersupp.h>
51 +/* Define this to use interrupt driver UART driver */
52 +#define USE_INTERRUPTS 1
54 /* How many serial ports? */
56 +#define poll_write(c) imx_uart_poll_write_char(0, c)
57 +#define poll_read() imx_uart_poll_read_char(0)
59 -int uart_poll_read(int minor);
60 +static int imx_uart_first_open(int, int, void *);
61 +static int imx_uart_last_close(int, int, void *);
62 +static int imx_uart_poll_read(int);
63 +static int imx_uart_set_attrs(int, const struct termios *);
64 +static void imx_uart_init(int minor);
65 +static void imx_uart_set_baud(int, int);
66 +static int imx_uart_poll_write(int, const char *, int);
68 +#if defined(USE_INTERRUPTS)
69 +static void imx_uart_tx_isr(rtems_irq_hdl_param);
70 +static void imx_uart_rx_isr(rtems_irq_hdl_param);
71 +static void imx_uart_isr_on(const rtems_irq_connect_data *irq);
72 +static void imx_uart_isr_off(const rtems_irq_connect_data *irq);
73 +static int imx_uart_isr_is_on(const rtems_irq_connect_data *irq);
74 +static int imx_uart_intr_write(int, const char *, int);
79 -/* static function prototypes */
80 -static int uart_first_open(int major, int minor, void *arg);
81 -static int uart_last_close(int major, int minor, void *arg);
82 -static int uart_read(int minor);
83 -static int uart_write(int minor, const char *buf, int len);
84 -static void uart_init(int minor);
85 -static void uart_write_polled(int minor, char c);
86 -static int uart_set_attributes(int minor, const struct termios *t);
88 -/* These are used by code in console.c */
89 -unsigned long Console_Port_Count = NUM_DEVS;
90 -console_data Console_Port_Data[NUM_DEVS];
92 -/* rtems console uses the following minor number */
93 -rtems_device_minor_number Console_Port_Minor = 0;
95 -/* Pointers to functions for handling the UART. */
96 -console_fns uart_fns =
98 - libchip_serial_default_probe,
104 - uart_write_polled, /* not used in this driver */
105 - uart_set_attributes,
106 - FALSE /* TRUE if interrupt driven, FALSE if not. */
108 +/* TERMIOS callbacks */
109 +#if defined(USE_INTERRUPTS)
110 +rtems_termios_callbacks imx_uart_cbacks = {
111 + .firstOpen = imx_uart_first_open,
112 + .lastClose = imx_uart_last_close,
114 + .write = imx_uart_intr_write,
115 + .setAttributes = imx_uart_set_attrs,
116 + .stopRemoteTx = NULL,
117 + .startRemoteTx = NULL,
118 + .outputUsesInterrupts = 1,
121 +rtems_termios_callbacks imx_uart_cbacks = {
122 + .firstOpen = imx_uart_first_open,
123 + .lastClose = imx_uart_last_close,
124 + .pollRead = imx_uart_poll_read,
125 + .write = imx_uart_poll_write,
126 + .setAttributes = imx_uart_set_attrs,
127 + .stopRemoteTx = NULL,
128 + .startRemoteTx = NULL,
129 + .outputUsesInterrupts = 0,
134 - * There's one item in array for each UART.
136 - * Some of these fields are marked "NOT USED". They are not used
137 - * by console.c, but may be used by drivers in libchip
140 -console_tbl Console_Port_Tbl[] = {
142 - "/dev/com0", /* sDeviceName */
143 - SERIAL_CUSTOM, /* deviceType */
144 - &uart_fns, /* pDeviceFns */
145 - NULL, /* deviceProbe */
146 - NULL, /* pDeviceFlow */
147 - 0, /* ulMargin - NOT USED */
148 - 0, /* ulHysteresis - NOT USED */
149 - NULL, /* pDeviceParams */
150 - 0, /* ulCtrlPort1 - NOT USED */
151 - 0, /* ulCtrlPort2 - NOT USED */
152 - 0, /* ulDataPort - NOT USED */
153 - NULL, /* getRegister - NOT USED */
154 - NULL, /* setRegister - NOT USED */
155 - NULL, /* getData - NOT USED */
156 - NULL, /* setData - NOT USED */
157 - 0, /* ulClock - NOT USED */
158 - 0 /* ulIntVector - NOT USED */
161 - "/dev/com1", /* sDeviceName */
162 - SERIAL_CUSTOM, /* deviceType */
163 - &uart_fns, /* pDeviceFns */
164 - NULL, /* deviceProbe */
165 - NULL, /* pDeviceFlow */
166 - 0, /* ulMargin - NOT USED */
167 - 0, /* ulHysteresis - NOT USED */
168 - NULL, /* pDeviceParams */
169 - 0, /* ulCtrlPort1 - NOT USED */
170 - 0, /* ulCtrlPort2 - NOT USED */
171 - 0, /* ulDataPort - NOT USED */
172 - NULL, /* getRegister - NOT USED */
173 - NULL, /* setRegister - NOT USED */
174 - NULL, /* getData - NOT USED */
175 - NULL, /* setData - NOT USED */
176 - 0, /* ulClock - NOT USED */
177 - 0 /* ulIntVector - NOT USED */
178 +#if defined(USE_INTERRUPTS)
179 +static rtems_irq_connect_data imx_uart_tx_isr_data[NUM_DEVS];
180 +static rtems_irq_connect_data imx_uart_rx_isr_data[NUM_DEVS];
185 + mc9328mxl_uart_regs_t * regs;
186 + volatile const char *buf;
192 +static imx_uart_data_t imx_uart_data[NUM_DEVS];
194 +rtems_device_driver console_initialize(
195 + rtems_device_major_number major,
196 + rtems_device_minor_number minor,
200 + rtems_status_code status;
203 + for (i = 0; i < NUM_DEVS; i++) {
208 -/*********************************************************************/
209 -/* Functions called via termios callbacks (i.e. the ones in uart_fns */
210 -/*********************************************************************/
213 - * This is called the first time each device is opened. If the driver
214 - * is interrupt driven, you should enable interrupts here. Otherwise,
215 - * it's probably safe to do nothing.
217 - * Since micromonitor already set up the UART, we do nothing.
219 -static int uart_first_open(int major, int minor, void *arg)
220 + rtems_termios_initialize();
222 + /* /dev/console and /dev/tty0 are the same */
223 + status = rtems_io_register_name("/dev/console", major, 0);
224 + if (status != RTEMS_SUCCESSFUL) {
225 + rtems_panic("%s:%d Error registering /dev/console :: %d\n",
226 + __FUNCTION__, __LINE__, status);
229 + status = rtems_io_register_name("/dev/tty0", major, 0);
230 + if (status != RTEMS_SUCCESSFUL) {
231 + rtems_panic("%s:%d Error registering /dev/tty0 :: %d\n",
232 + __FUNCTION__, __LINE__, status);
235 + status = rtems_io_register_name("/dev/tty1", major, 1);
236 + if (status != RTEMS_SUCCESSFUL) {
237 + rtems_panic("%s:%d Error registering /dev/tty1 :: %d\n",
238 + __FUNCTION__, __LINE__, status);
240 + return RTEMS_SUCCESSFUL;
243 +rtems_device_driver console_open(
244 + rtems_device_major_number major,
245 + rtems_device_minor_number minor,
250 + rtems_status_code rc;
252 + if (minor > (NUM_DEVS - 1)) {
253 + return RTEMS_INVALID_NUMBER;
256 + rc = rtems_termios_open(major, minor, arg, &imx_uart_cbacks);
261 +rtems_device_driver console_close(
262 + rtems_device_major_number major,
263 + rtems_device_minor_number minor,
267 + return rtems_termios_close(arg);
271 - * This is called the last time each device is closed. If the driver
272 - * is interrupt driven, you should disable interrupts here. Otherwise,
273 - * it's probably safe to do nothing.
275 -static int uart_last_close(int major, int minor, void *arg)
276 +rtems_device_driver console_read(
277 + rtems_device_major_number major,
278 + rtems_device_minor_number minor,
283 + return rtems_termios_read(arg);
286 +rtems_device_driver console_write(
287 + rtems_device_major_number major,
288 + rtems_device_minor_number minor,
292 + return rtems_termios_write(arg);
296 - * Read one character from UART.
298 - * Return -1 if there's no data, otherwise return
299 - * the character in lowest 8 bits of returned int.
301 -static int uart_read(int minor)
302 +rtems_device_driver console_control(
303 + rtems_device_major_number major,
304 + rtems_device_minor_number minor,
309 + return rtems_termios_ioctl(arg);
312 +static void imx_uart_init(int minor)
314 + imx_uart_data[minor].minor = minor;
315 + imx_uart_data[minor].buf = NULL;
316 + imx_uart_data[minor].len = 0;
317 + imx_uart_data[minor].idx = 0;
320 - if (MC9328MXL_UART1_SR2 & MC9328MXL_UART_SR2_RDR) {
321 - c = MC9328MXL_UART1_RXD & MC9328MXL_UART_RXD_CHARMASK;
326 +#if defined(USE_INTERRUPTS)
327 + imx_uart_tx_isr_data[minor].name = BSP_INT_UART1_TX;
328 + imx_uart_rx_isr_data[minor].name = BSP_INT_UART1_RX;
330 + imx_uart_data[minor].regs =
331 + (mc9328mxl_uart_regs_t *) MC9328MXL_UART1_BASE;
332 } else if (minor == 1) {
333 - if (MC9328MXL_UART2_SR2 & MC9328MXL_UART_SR2_RDR) {
334 - c = MC9328MXL_UART2_RXD & MC9328MXL_UART_RXD_CHARMASK;
339 +#if defined(USE_INTERRUPTS)
340 + imx_uart_tx_isr_data[minor].name = BSP_INT_UART2_TX;
341 + imx_uart_rx_isr_data[minor].name = BSP_INT_UART2_RX;
343 + imx_uart_data[minor].regs =
344 + (mc9328mxl_uart_regs_t *) MC9328MXL_UART2_BASE;
346 - printk("Unknown console minor number: %d\n", minor);
348 + rtems_panic("%s:%d Unknown UART minor number %d\n",
349 + __FUNCTION__, __LINE__, minor);
352 +#if defined(USE_INTERRUPTS)
353 + imx_uart_tx_isr_data[minor].hdl = imx_uart_tx_isr;
354 + imx_uart_tx_isr_data[minor].handle = &imx_uart_data[minor];
355 + imx_uart_tx_isr_data[minor].on = imx_uart_isr_on;
356 + imx_uart_tx_isr_data[minor].off = imx_uart_isr_off;
357 + imx_uart_tx_isr_data[minor].isOn = imx_uart_isr_is_on;
359 + imx_uart_rx_isr_data[minor].hdl = imx_uart_rx_isr;
360 + imx_uart_rx_isr_data[minor].handle = &imx_uart_data[minor];
361 + imx_uart_rx_isr_data[minor].on = imx_uart_isr_on;
362 + imx_uart_rx_isr_data[minor].off = imx_uart_isr_off;
363 + imx_uart_rx_isr_data[minor].isOn = imx_uart_isr_is_on;
366 + imx_uart_data[minor].regs->cr1 = (
367 + MC9328MXL_UART_CR1_UARTCLKEN |
368 + MC9328MXL_UART_CR1_UARTEN);
370 + imx_uart_data[minor].regs->cr2 = (
371 + MC9328MXL_UART_CR2_IRTS |
372 + MC9328MXL_UART_CR2_WS |
373 + MC9328MXL_UART_CR2_TXEN |
374 + MC9328MXL_UART_CR2_RXEN |
375 + MC9328MXL_UART_CR2_SRST);
377 + imx_uart_data[minor].regs->cr3 = 0;
379 + imx_uart_data[minor].regs->cr4 = 0;
381 + imx_uart_data[minor].regs->fcr = (
382 + MC9328MXL_UART_FCR_TXTL(32) |
383 + MC9328MXL_UART_FCR_RFDIV_1 |
384 + MC9328MXL_UART_FCR_RXTL(1));
386 + imx_uart_set_baud(minor, 38400);
390 +static int imx_uart_first_open(int major, int minor, void *arg)
392 + rtems_libio_open_close_args_t *args = arg;
395 - * Write buffer to UART
397 - * return 1 on success, -1 on error
399 -static int uart_write(int minor, const char *buf, int len)
400 + imx_uart_data[minor].tty = args->iop->data1;
402 +#if defined(USE_INTERRUPTS)
403 + BSP_install_rtems_irq_handler(&imx_uart_tx_isr_data[minor]);
404 + BSP_install_rtems_irq_handler(&imx_uart_rx_isr_data[minor]);
406 + imx_uart_data[minor].regs->cr1 |= MC9328MXL_UART_CR1_RRDYEN;
412 +static int imx_uart_last_close(int major, int minor, void *arg)
415 +#if defined(USE_INTERRUPTS)
416 + BSP_remove_rtems_irq_handler(&imx_uart_tx_isr_data[minor]);
417 + BSP_remove_rtems_irq_handler(&imx_uart_rx_isr_data[minor]);
421 - for (i = 0; i < len; i++) {
422 - /* Wait for fifo to have room */
423 - while(!(MC9328MXL_UART1_SR2 & MC9328MXL_UART_SR2_TXDC)) {
427 - MC9328MXL_UART1_TXD = (char) buf[i];
429 - } else if (minor == 1) {
430 - for (i = 0; i < len; i++) {
431 - /* Wait for fifo to have room */
432 - while(!(MC9328MXL_UART2_SR2 & MC9328MXL_UART_SR2_TXDC)) {
436 - MC9328MXL_UART2_TXD = (char) buf[i];
441 +static int imx_uart_poll_read(int minor)
443 + if (imx_uart_data[minor].regs->sr2 & MC9328MXL_UART_SR2_RDR) {
444 + return imx_uart_data[minor].regs->rxd & 0xff;
446 - printk("Unknown console minor number: %d\n", minor);
454 -/* Set up the UART. */
455 -static void uart_init(int minor)
456 +static int imx_uart_poll_write(int minor, const char *buf, int len)
458 - /* leave the debug sio port as setup by umon */
460 + for (i = 0; i < len; i++) {
461 + /* Wait for there to be room in the fifo */
462 + while (!(imx_uart_data[minor].regs->sr2 & MC9328MXL_UART_SR2_TXDC)) {
466 + imx_uart_data[minor].regs->txd = buf[i];
472 -/* I'm not sure this is needed for the shared console driver. */
473 -static void uart_write_polled(int minor, char c)
474 +#if defined(USE_INTERRUPTS)
475 +static int imx_uart_intr_write(int minor, const char *buf, int len)
477 - uart_write(minor, &c, 1);
478 + imx_uart_data[minor].buf = buf;
479 + imx_uart_data[minor].len = len;
480 + imx_uart_data[minor].idx = 0;
482 + imx_uart_data[minor].regs->cr1 |= MC9328MXL_UART_CR1_TXMPTYEN;
489 /* This is for setting baud rate, bits, etc. */
490 -static int uart_set_attributes(int minor, const struct termios *t)
491 +static int imx_uart_set_attrs(int minor, const struct termios *t)
495 + baud = termios_baud_to_number(t->c_cflag & CBAUD);
496 + imx_uart_set_baud(minor, baud);
501 -/***********************************************************************/
502 +#if defined(USE_INTERRUPTS)
503 +static void imx_uart_isr_on(const rtems_irq_connect_data *irq)
505 + MC9328MXL_AITC_INTENNUM = irq->name;
507 +static void imx_uart_isr_off(const rtems_irq_connect_data *irq)
509 + MC9328MXL_AITC_INTDISNUM = irq->name;
511 +static int imx_uart_isr_is_on(const rtems_irq_connect_data *irq)
513 + int irq_num = (int)irq->name;
514 + if (irq_num < 32) {
515 + return MC9328MXL_AITC_INTENABLEL & (1 << irq_num);
517 + return MC9328MXL_AITC_INTENABLEH & (1 << (irq_num - 32));
521 +static void imx_uart_rx_isr(rtems_irq_hdl_param param)
523 + imx_uart_data_t *uart_data = param;
527 + while (uart_data->regs->sr2 & MC9328MXL_UART_SR2_RDR) {
528 + buf[i] = uart_data->regs->rxd & 0xff;
532 + rtems_termios_enqueue_raw_characters(uart_data->tty, buf, i);
535 +static void imx_uart_tx_isr(rtems_irq_hdl_param param)
537 + imx_uart_data_t *uart_data = param;
539 + int minor = uart_data->minor;
542 + if (uart_data->idx < uart_data->len) {
543 + while ( (uart_data->regs->sr1 & MC9328MXL_UART_SR1_TRDY) &&
544 + (uart_data->idx < uart_data->len)) {
545 + uart_data->regs->txd = uart_data->buf[uart_data->idx];
549 + len = uart_data->len;
550 + uart_data->len = 0;
551 + imx_uart_data[minor].regs->cr1 &= ~MC9328MXL_UART_CR1_TXMPTYEN;
552 + rtems_termios_dequeue_characters(uart_data->tty, len);
558 - * The following functions are not used by TERMIOS, but other RTEMS
559 - * functions use them instead.
560 + * Set the UART's baud rate. The calculation is:
561 + * (baud * 16) / ref_freq = num/demom
563 + * ref_freq = perclk1 / RFDIV[2:0]
567 + * Setting 'num' to 16 yields this equation:
568 + * demom = ref_freq / baud
570 -/***********************************************************************/
572 - * Read from UART. This is used in the exit code, and can't
573 - * rely on interrupts.
575 -int uart_poll_read(int minor)
576 +static void imx_uart_set_baud(int minor, int baud)
578 - return uart_read(minor);
579 + unsigned int perclk1;
580 + unsigned int denom;
581 + unsigned int ref_freq = 0;
584 + perclk1 = get_perclk1_freq();
585 + fcr = imx_uart_data[minor].regs->fcr;
587 + switch(fcr & MC9328MXL_UART_FCR_RFDIV_MASK) {
588 + case MC9328MXL_UART_FCR_RFDIV_1: ref_freq = perclk1/1; break;
589 + case MC9328MXL_UART_FCR_RFDIV_2: ref_freq = perclk1/2; break;
590 + case MC9328MXL_UART_FCR_RFDIV_3: ref_freq = perclk1/3; break;
591 + case MC9328MXL_UART_FCR_RFDIV_4: ref_freq = perclk1/4; break;
592 + case MC9328MXL_UART_FCR_RFDIV_5: ref_freq = perclk1/5; break;
593 + case MC9328MXL_UART_FCR_RFDIV_6: ref_freq = perclk1/6; break;
594 + case MC9328MXL_UART_FCR_RFDIV_7: ref_freq = perclk1/7; break;
596 + rtems_panic("%s:%d Unknown RFDIV: 0x%x",
597 + __FUNCTION__, __LINE__,
598 + fcr & MC9328MXL_UART_FCR_RFDIV_MASK);
602 + denom = ref_freq / baud;
604 + imx_uart_data[minor].regs->bir = 0xf;
605 + imx_uart_data[minor].regs->bmr = denom;
610 - * Write a character to the console. This is used by printk() and
611 - * maybe other low level functions. It should not use interrupts or any
612 - * RTEMS system calls. It needs to be very simple
613 + * Polled, non-blocking read from UART
615 +int imx_uart_poll_read_char(int minor)
617 + return imx_uart_poll_read(minor);
621 + * Polled, blocking write from UART
623 -static void _BSP_put_char( char c ) {
624 - uart_write_polled(0, c);
625 +void imx_uart_poll_write_char(int minor, char c)
627 + imx_uart_poll_write(minor, &c, 1);
631 + * Functions for printk() and friends.
633 +void _BSP_output_char(char c)
637 - uart_write_polled(0, '\r');
641 +BSP_output_char_function_type BSP_output_char = _BSP_output_char;
643 -BSP_output_char_function_type BSP_output_char = _BSP_put_char;
645 +char _BSP_poll_char()
647 + return poll_read();
649 +BSP_polling_getchar_function_type BSP_poll_char = _BSP_poll_char;
652 Index: rtems/c/src/lib/libbsp/arm/csb336/Makefile.am
653 ===================================================================
654 --- rtems.orig/c/src/lib/libbsp/arm/csb336/Makefile.am
655 +++ rtems/c/src/lib/libbsp/arm/csb336/Makefile.am
656 @@ -35,7 +35,7 @@ startup_rel_CPPFLAGS = $(AM_CPPFLAGS)
657 startup_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
659 noinst_PROGRAMS += console.rel
660 -console_rel_SOURCES = console/uart.c ../../shared/console.c
661 +console_rel_SOURCES = console/uart.c
662 console_rel_CPPFLAGS = $(AM_CPPFLAGS)
663 console_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)