Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:22:48

0001 /*
0002  * Console driver for MC9328XML UARTs.
0003  *
0004  * Written Jay Monkman <jtm@lopingdog.com>
0005  * Copyright (c) 2005 by Loping Dog Embedded Systems
0006  *
0007  * The license and distribution terms for this file may be
0008  * found in the file LICENSE in this distribution or at
0009  *    http://www.rtems.org/license
0010  */
0011 #include <bsp.h>
0012 #include <rtems/libio.h>
0013 #include <libchip/sersupp.h>
0014 #include <rtems/error.h>
0015 #include <rtems/bspIo.h>
0016 #include <assert.h>
0017 #include <termios.h>
0018 #include <rtems/irq.h>
0019 #include <bsp/irq.h>
0020 #include <mc9328mxl.h>
0021 #include <rtems/console.h>
0022 #include <inttypes.h>
0023 
0024 /* Define this to use interrupt driver UART driver */
0025 #define USE_INTERRUPTS 1
0026 
0027 /* How many serial ports? */
0028 #define NUM_DEVS       2
0029 #define poll_write(c)  imx_uart_poll_write_char(0, c)
0030 #define poll_read()  imx_uart_poll_read_char(0)
0031 
0032 static int imx_uart_first_open(int, int, void *);
0033 static int imx_uart_last_close(int, int, void *);
0034 static int imx_uart_poll_read(int);
0035 static int imx_uart_set_attrs(int, const struct termios *);
0036 static void imx_uart_init(int minor);
0037 static void imx_uart_set_baud(int, int);
0038 static ssize_t imx_uart_poll_write(int, const char *, size_t);
0039 static int imx_uart_poll_read_char(int minor);
0040 static void imx_uart_poll_write_char(int minor, char c);
0041 static void _BSP_output_char(char c);
0042 static int _BSP_poll_char(void);
0043 
0044 #if USE_INTERRUPTS
0045 static void imx_uart_tx_isr(void *);
0046 static void imx_uart_rx_isr(void *);
0047 static void imx_uart_isr_on(rtems_vector_number);
0048 static void imx_uart_isr_off(rtems_vector_number);
0049 static ssize_t imx_uart_intr_write(int, const char *, size_t);
0050 static rtems_vector_number imx_uart_name_transmit(int minor);
0051 static rtems_vector_number imx_uart_name_receive(int minor);
0052 #endif
0053 
0054 /* TERMIOS callbacks */
0055 #if USE_INTERRUPTS
0056 rtems_termios_callbacks imx_uart_cbacks = {
0057     .firstOpen            = imx_uart_first_open,
0058     .lastClose            = imx_uart_last_close,
0059     .pollRead             = NULL,
0060     .write                = imx_uart_intr_write,
0061     .setAttributes        = imx_uart_set_attrs,
0062     .stopRemoteTx         = NULL,
0063     .startRemoteTx        = NULL,
0064     .outputUsesInterrupts = TERMIOS_IRQ_DRIVEN,
0065 };
0066 #else
0067 rtems_termios_callbacks imx_uart_cbacks = {
0068     .firstOpen            = imx_uart_first_open,
0069     .lastClose            = imx_uart_last_close,
0070     .pollRead             = imx_uart_poll_read,
0071     .write                = imx_uart_poll_write,
0072     .setAttributes        = imx_uart_set_attrs,
0073     .stopRemoteTx         = NULL,
0074     .startRemoteTx        = NULL,
0075     .outputUsesInterrupts = TERMIOS_POLLED,
0076 };
0077 #endif
0078 
0079 typedef struct {
0080     int minor;
0081     mc9328mxl_uart_regs_t * regs;
0082     volatile const char *buf;
0083     volatile int len;
0084     volatile int idx;
0085     void *tty;
0086 } imx_uart_data_t;
0087 
0088 static imx_uart_data_t imx_uart_data[NUM_DEVS];
0089 
0090 rtems_device_driver console_initialize(
0091     rtems_device_major_number  major,
0092     rtems_device_minor_number  minor,
0093     void                      *arg
0094 )
0095 {
0096     rtems_status_code status;
0097     int i;
0098 
0099     for (i = 0; i < NUM_DEVS; i++) {
0100         imx_uart_init(i);
0101     }
0102 
0103     rtems_termios_initialize();
0104 
0105     /* /dev/console and /dev/tty0 are the same */
0106     status = rtems_io_register_name("/dev/console", major, 0);
0107     if (status != RTEMS_SUCCESSFUL) {
0108         rtems_panic("%s:%d Error registering /dev/console :: %d\n",
0109                     __FUNCTION__, __LINE__, status);
0110     }
0111 
0112     status = rtems_io_register_name("/dev/tty0", major, 0);
0113     if (status != RTEMS_SUCCESSFUL) {
0114         rtems_panic("%s:%d Error registering /dev/tty0 :: %d\n",
0115                     __FUNCTION__, __LINE__, status);
0116     }
0117 
0118     status = rtems_io_register_name("/dev/tty1", major, 1);
0119     if (status != RTEMS_SUCCESSFUL) {
0120         rtems_panic("%s:%d Error registering /dev/tty1 :: %d\n",
0121                     __FUNCTION__, __LINE__, status);
0122     }
0123     return RTEMS_SUCCESSFUL;
0124 }
0125 
0126 rtems_device_driver console_open(
0127     rtems_device_major_number major,
0128     rtems_device_minor_number minor,
0129     void                    * arg
0130 )
0131 {
0132     rtems_status_code rc;
0133 
0134     if (minor > (NUM_DEVS - 1)) {
0135         return RTEMS_INVALID_NUMBER;
0136     }
0137 
0138     rc = rtems_termios_open(major, minor, arg, &imx_uart_cbacks);
0139 
0140     return rc;
0141 }
0142 
0143 rtems_device_driver console_close(
0144     rtems_device_major_number major,
0145     rtems_device_minor_number minor,
0146     void                    * arg
0147 )
0148 {
0149     return rtems_termios_close(arg);
0150 }
0151 
0152 rtems_device_driver console_read(
0153     rtems_device_major_number major,
0154     rtems_device_minor_number minor,
0155     void                    * arg
0156 )
0157 {
0158   return rtems_termios_read(arg);
0159 }
0160 
0161 rtems_device_driver console_write(
0162     rtems_device_major_number major,
0163     rtems_device_minor_number minor,
0164     void                    * arg
0165 )
0166 {
0167   return rtems_termios_write(arg);
0168 }
0169 
0170 rtems_device_driver console_control(
0171     rtems_device_major_number major,
0172     rtems_device_minor_number minor,
0173     void                    * arg
0174 )
0175 {
0176   return rtems_termios_ioctl(arg);
0177 }
0178 
0179 static void imx_uart_init(int minor)
0180 {
0181     imx_uart_data[minor].minor = minor;
0182     imx_uart_data[minor].buf   = NULL;
0183     imx_uart_data[minor].len   = 0;
0184     imx_uart_data[minor].idx   = 0;
0185 
0186     if (minor == 0) {
0187         imx_uart_data[minor].regs =
0188             (mc9328mxl_uart_regs_t *) MC9328MXL_UART1_BASE;
0189     } else if (minor == 1) {
0190         imx_uart_data[minor].regs =
0191             (mc9328mxl_uart_regs_t *) MC9328MXL_UART2_BASE;
0192     } else {
0193         rtems_panic("%s:%d Unknown UART minor number %d\n",
0194                     __FUNCTION__, __LINE__, minor);
0195     }
0196 
0197     imx_uart_data[minor].regs->cr1 = (
0198         MC9328MXL_UART_CR1_UARTCLKEN |
0199         MC9328MXL_UART_CR1_UARTEN);
0200 
0201     imx_uart_data[minor].regs->cr2 = (
0202         MC9328MXL_UART_CR2_IRTS |
0203         MC9328MXL_UART_CR2_WS   |
0204         MC9328MXL_UART_CR2_TXEN |
0205         MC9328MXL_UART_CR2_RXEN |
0206         MC9328MXL_UART_CR2_SRST);
0207 
0208     imx_uart_data[minor].regs->cr3 = 0;
0209 
0210     imx_uart_data[minor].regs->cr4 = 0;
0211 
0212     imx_uart_data[minor].regs->fcr = (
0213         MC9328MXL_UART_FCR_TXTL(32) |
0214         MC9328MXL_UART_FCR_RFDIV_1 |
0215         MC9328MXL_UART_FCR_RXTL(1));
0216 
0217     imx_uart_set_baud(minor, 38400);
0218 
0219 }
0220 
0221 static int imx_uart_first_open(int major, int minor, void *arg)
0222 {
0223     rtems_libio_open_close_args_t *args = arg;
0224     rtems_status_code status = RTEMS_SUCCESSFUL;
0225 
0226     imx_uart_data[minor].tty   = args->iop->data1;
0227 
0228 #if USE_INTERRUPTS
0229     status = rtems_interrupt_handler_install(
0230         imx_uart_name_transmit(minor),
0231         "UART",
0232         RTEMS_INTERRUPT_UNIQUE,
0233         imx_uart_tx_isr,
0234         &imx_uart_data[minor]
0235     );
0236     assert(status == RTEMS_SUCCESSFUL);
0237     imx_uart_isr_on(imx_uart_name_transmit(minor));
0238 
0239     status = rtems_interrupt_handler_install(
0240         imx_uart_name_receive(minor),
0241         "UART",
0242         RTEMS_INTERRUPT_UNIQUE,
0243         imx_uart_rx_isr,
0244         &imx_uart_data[minor]
0245     );
0246     assert(status == RTEMS_SUCCESSFUL);
0247     imx_uart_isr_on(imx_uart_name_receive(minor));
0248 
0249     imx_uart_data[minor].regs->cr1 |= MC9328MXL_UART_CR1_RRDYEN;
0250 #endif
0251 
0252     return 0;
0253 }
0254 
0255 static int imx_uart_last_close(int major, int minor, void *arg)
0256 {
0257 #if USE_INTERRUPTS
0258     rtems_status_code status = RTEMS_SUCCESSFUL;
0259 
0260     imx_uart_isr_off(imx_uart_name_transmit(minor));
0261     status = rtems_interrupt_handler_remove(
0262         imx_uart_name_transmit(minor),
0263         imx_uart_tx_isr,
0264         &imx_uart_data[minor]
0265     );
0266     assert(status == RTEMS_SUCCESSFUL);
0267 
0268     imx_uart_isr_off(imx_uart_name_receive(minor));
0269     status = rtems_interrupt_handler_remove(
0270         imx_uart_name_receive(minor),
0271         imx_uart_rx_isr,
0272         &imx_uart_data[minor]
0273     );
0274     assert(status == RTEMS_SUCCESSFUL);
0275 #endif
0276 
0277     return 0;
0278 }
0279 
0280 static int imx_uart_poll_read(int minor)
0281 {
0282     if (imx_uart_data[minor].regs->sr2 & MC9328MXL_UART_SR2_RDR) {
0283         return imx_uart_data[minor].regs->rxd & 0xff;
0284     } else {
0285         return -1;
0286     }
0287 }
0288 
0289 
0290 static ssize_t imx_uart_poll_write(int minor, const char *buf, size_t len)
0291 {
0292     int i;
0293     for (i = 0; i < len; i++) {
0294         /* Wait for there to be room in the fifo */
0295         while (!(imx_uart_data[minor].regs->sr2 & MC9328MXL_UART_SR2_TXDC)) {
0296             continue;
0297         }
0298 
0299         imx_uart_data[minor].regs->txd = buf[i];
0300     }
0301     return 1;
0302 
0303 }
0304 
0305 #if USE_INTERRUPTS
0306 static ssize_t imx_uart_intr_write(int minor, const char *buf, size_t len)
0307 {
0308     if (len > 0) {
0309         imx_uart_data[minor].buf = buf;
0310         imx_uart_data[minor].len = len;
0311         imx_uart_data[minor].idx = 0;
0312 
0313         imx_uart_data[minor].regs->cr1 |= MC9328MXL_UART_CR1_TXMPTYEN;
0314     }
0315 
0316     return 1;
0317 }
0318 #endif
0319 
0320 
0321 /* This is for setting baud rate, bits, etc. */
0322 static int imx_uart_set_attrs(int minor, const struct termios *t)
0323 {
0324     int baud;
0325 
0326     baud = rtems_termios_baud_to_number(t->c_ospeed);
0327     imx_uart_set_baud(minor, baud);
0328 
0329     return 0;
0330 }
0331 
0332 #if USE_INTERRUPTS
0333 static void imx_uart_isr_on(rtems_vector_number name)
0334 {
0335     MC9328MXL_AITC_INTENNUM = name;
0336 }
0337 static void imx_uart_isr_off(rtems_vector_number name)
0338 {
0339     MC9328MXL_AITC_INTDISNUM = name;
0340 }
0341 
0342 static void imx_uart_rx_isr(void * param)
0343 {
0344     imx_uart_data_t *uart_data = param;
0345     char buf[32];
0346     int i=0;
0347 
0348     while (uart_data->regs->sr2 & MC9328MXL_UART_SR2_RDR) {
0349         buf[i] = uart_data->regs->rxd & 0xff;
0350         i++;
0351     }
0352 
0353     rtems_termios_enqueue_raw_characters(uart_data->tty, buf, i);
0354 }
0355 
0356 static void imx_uart_tx_isr(void * param)
0357 {
0358     imx_uart_data_t *uart_data = param;
0359     int len;
0360     int minor = uart_data->minor;
0361 
0362 
0363     if (uart_data->idx < uart_data->len) {
0364         while ( (uart_data->regs->sr1 & MC9328MXL_UART_SR1_TRDY) &&
0365                 (uart_data->idx < uart_data->len)) {
0366             uart_data->regs->txd = uart_data->buf[uart_data->idx];
0367             uart_data->idx++;
0368         }
0369     } else {
0370         len = uart_data->len;
0371         uart_data->len = 0;
0372         imx_uart_data[minor].regs->cr1 &= ~MC9328MXL_UART_CR1_TXMPTYEN;
0373         rtems_termios_dequeue_characters(uart_data->tty, len);
0374     }
0375 }
0376 
0377 static rtems_vector_number imx_uart_name_transmit(int minor)
0378 {
0379     if (minor == 0) {
0380         return BSP_INT_UART1_TX;
0381     } else if (minor == 1) {
0382         return BSP_INT_UART2_TX;
0383     }
0384 
0385     assert(0);
0386 }
0387 
0388 static rtems_vector_number imx_uart_name_receive(int minor)
0389 {
0390     if (minor == 0) {
0391         return BSP_INT_UART1_RX;
0392     } else if (minor == 1) {
0393         return BSP_INT_UART2_RX;
0394     }
0395 
0396     assert(0);
0397 }
0398 #endif
0399 
0400 /*
0401  * Set the UART's baud rate. The calculation is:
0402  *   (baud * 16) / ref_freq  = num/demom
0403  *
0404  *   ref_freq = perclk1 / RFDIV[2:0]
0405  *   BIR = num - 1
0406  *   BMR = demom - 1
0407  *
0408  * Setting 'num' to 16 yields this equation:
0409  *    demom = ref_freq / baud
0410  */
0411 static void imx_uart_set_baud(int minor, int baud)
0412 {
0413     unsigned int perclk1;
0414     unsigned int denom;
0415     unsigned int ref_freq = 0;
0416     uint32_t fcr;
0417 
0418     perclk1 = get_perclk1_freq();
0419     fcr = imx_uart_data[minor].regs->fcr;
0420 
0421     switch(fcr & MC9328MXL_UART_FCR_RFDIV_MASK) {
0422     case MC9328MXL_UART_FCR_RFDIV_1:  ref_freq = perclk1/1; break;
0423     case MC9328MXL_UART_FCR_RFDIV_2:  ref_freq = perclk1/2; break;
0424     case MC9328MXL_UART_FCR_RFDIV_3:  ref_freq = perclk1/3; break;
0425     case MC9328MXL_UART_FCR_RFDIV_4:  ref_freq = perclk1/4; break;
0426     case MC9328MXL_UART_FCR_RFDIV_5:  ref_freq = perclk1/5; break;
0427     case MC9328MXL_UART_FCR_RFDIV_6:  ref_freq = perclk1/6; break;
0428     case MC9328MXL_UART_FCR_RFDIV_7:  ref_freq = perclk1/7; break;
0429     default:
0430         rtems_panic("%s:%d Unknown RFDIV: 0x%" PRIx32,
0431                     __FUNCTION__, __LINE__,
0432                     fcr & MC9328MXL_UART_FCR_RFDIV_MASK);
0433         break;
0434     }
0435 
0436     denom = ref_freq / baud;
0437 
0438     imx_uart_data[minor].regs->bir = 0xf;
0439     imx_uart_data[minor].regs->bmr = denom;
0440 }
0441 
0442 
0443 /*
0444  * Polled, non-blocking read from UART
0445  */
0446 static int imx_uart_poll_read_char(int minor)
0447 {
0448     return imx_uart_poll_read(minor);
0449 }
0450 
0451 /*
0452  * Polled, blocking write from UART
0453  */
0454 static void  imx_uart_poll_write_char(int minor, char c)
0455 {
0456     imx_uart_poll_write(minor, &c, 1);
0457 }
0458 
0459 /*
0460  * Functions for printk() and friends.
0461  */
0462 static void _BSP_output_char(char c)
0463 {
0464     poll_write(c);
0465 }
0466 
0467 BSP_output_char_function_type BSP_output_char = _BSP_output_char;
0468 
0469 static int _BSP_poll_char(void)
0470 {
0471     return poll_read();
0472 }
0473 
0474 BSP_polling_getchar_function_type BSP_poll_char = _BSP_poll_char;
0475 
0476