Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:46

0001 /*
0002  * Generic UART Serial driver for Motorola Coldfire processors
0003  */
0004 
0005 /*
0006  * Copyright (C) 2000 OKTET Ltd., St.-Petersburg, Russian Fed.
0007  * Author: Victor V. Vengerov <vvv@oktet.ru>
0008  *
0009  *  COPYRIGHT (c) 1989-2000.
0010  *  On-Line Applications Research Corporation (OAR).
0011  *
0012  *  The license and distribution terms for this file may be
0013  *  found in the file LICENSE in this distribution or at
0014  *  http://www.rtems.org/license/LICENSE.
0015  */
0016 
0017 #include <rtems.h>
0018 #include <termios.h>
0019 #include <rtems/libio.h>
0020 #include "mcf5206/mcfuart.h"
0021 
0022 /*
0023  * int_driven_uart -- mapping between interrupt vector number and
0024  * UART descriptor structures
0025  */
0026 static struct {
0027   mcfuart *uart;
0028   int      vec;
0029 } int_driven_uart[2];
0030 
0031 /* Forward function declarations */
0032 static rtems_isr
0033 mcfuart_interrupt_handler(rtems_vector_number vec);
0034 
0035 /*
0036  * mcfuart_init --
0037  *     This function verifies the input parameters and perform initialization
0038  *     of the Motorola Coldfire on-chip UART descriptor structure.
0039  *
0040  * PARAMETERS:
0041  *     uart - pointer to the UART channel descriptor structure
0042  *     tty - pointer to termios structure
0043  *     int_driven - interrupt-driven (1) or polled (0) I/O mode
0044  *     chn - channel number (0/1)
0045  *     rx_buf - pointer to receive buffer
0046  *     rx_buf_len - receive buffer length
0047  *
0048  * RETURNS:
0049  *     RTEMS_SUCCESSFUL if all parameters are valid, or error code
0050  */
0051 rtems_status_code
0052 mcfuart_init(
0053   mcfuart   *uart,
0054   void      *tty,
0055   uint8_t    intvec,
0056   uint32_t   chn
0057 )
0058 {
0059   if (uart == NULL)
0060       return RTEMS_INVALID_ADDRESS;
0061 
0062   if ((chn <= 0) || (chn > MCF5206E_UART_CHANNELS))
0063       return RTEMS_INVALID_NUMBER;
0064 
0065   uart->chn = chn;
0066   uart->intvec = intvec;
0067   uart->tty = tty;
0068 
0069   return RTEMS_SUCCESSFUL;
0070 }
0071 
0072 /* mcfuart_set_baudrate --
0073  *     Program the UART timer to specified baudrate
0074  *
0075  * PARAMETERS:
0076  *     uart - pointer to UART descriptor structure
0077  *     baud - termios baud rate (B50, B9600, etc...)
0078  *
0079  * RETURNS:
0080  *     none
0081  */
0082 static void
0083 mcfuart_set_baudrate(mcfuart *uart, speed_t baud)
0084 {
0085   uint32_t   div;
0086   uint32_t   rate;
0087 
0088     switch (baud) {
0089       case B50:     rate = 50; break;
0090       case B75:     rate = 75; break;
0091       case B110:    rate = 110; break;
0092       case B134:    rate = 134; break;
0093       case B150:    rate = 150; break;
0094       case B200:    rate = 200; break;
0095       case B300:    rate = 300; break;
0096       case B600:    rate = 600; break;
0097       case B1200:   rate = 1200; break;
0098       case B2400:   rate = 2400; break;
0099       case B4800:   rate = 4800; break;
0100       case B9600:   rate = 9600; break;
0101       case B19200:  rate = 19200; break;
0102       case B38400:  rate = 38400; break;
0103       case B57600:  rate = 57600; break;
0104 #ifdef B115200
0105       case B115200: rate = 115200; break;
0106 #endif
0107 #ifdef B230400
0108       case B230400: rate = 230400; break;
0109 #endif
0110       default:      rate = 9600; break;
0111     }
0112 
0113   div = SYSTEM_CLOCK_FREQUENCY / (rate * 32);
0114 
0115   *MCF5206E_UBG1(MBAR,uart->chn) = (uint8_t)((div >> 8) & 0xff);
0116   *MCF5206E_UBG2(MBAR,uart->chn) = (uint8_t)(div & 0xff);
0117 }
0118 
0119 /*
0120  * mcfuart_reset --
0121  *     This function perform the hardware initialization of Motorola
0122  *     Coldfire processor on-chip UART controller using parameters
0123  *     filled by the mcfuart_init function.
0124  *
0125  * PARAMETERS:
0126  *     uart - pointer to UART channel descriptor structure
0127  *
0128  * RETURNS:
0129  *     RTEMS_SUCCESSFUL if channel is initialized successfully, error
0130  *     code in other case
0131  *
0132  * ALGORITHM:
0133  *     This function in general follows to algorith described in MCF5206e
0134  *     User's Manual, 12.5 UART Module Initialization Sequence
0135  */
0136 rtems_status_code mcfuart_reset(mcfuart *uart)
0137 {
0138   register uint32_t   chn;
0139   rtems_status_code rc;
0140 
0141   if (uart == NULL)
0142     return RTEMS_INVALID_ADDRESS;
0143 
0144   chn = uart->chn;
0145 
0146   /* Reset the receiver and transmitter */
0147   *MCF5206E_UCR(MBAR,chn) = MCF5206E_UCR_MISC_RESET_RX;
0148   *MCF5206E_UCR(MBAR,chn) = MCF5206E_UCR_MISC_RESET_TX;
0149 
0150   /*
0151    * Program the vector number for a UART module interrupt, or
0152    * disable UART interrupts if polled I/O. Enable the desired
0153    * interrupt sources.
0154    */
0155   if (uart->intvec != 0) {
0156     int_driven_uart[chn - 1].uart = uart;
0157     int_driven_uart[chn - 1].vec = uart->intvec;
0158     rc = rtems_interrupt_catch(mcfuart_interrupt_handler, uart->intvec,
0159                    &uart->old_handler);
0160     if (rc != RTEMS_SUCCESSFUL)
0161       return rc;
0162     *MCF5206E_UIVR(MBAR,chn) = uart->intvec;
0163     *MCF5206E_UIMR(MBAR,chn) = MCF5206E_UIMR_FFULL;
0164     *MCF5206E_UACR(MBAR,chn) = MCF5206E_UACR_IEC;
0165     *MCF5206E_IMR(MBAR) &= ~MCF5206E_INTR_BIT(uart->chn == 1 ?
0166                           MCF5206E_INTR_UART_1 :
0167                           MCF5206E_INTR_UART_2);
0168   } else {
0169     *MCF5206E_UIMR(MBAR,chn) = 0;
0170   }
0171 
0172   /* Select the receiver and transmitter clock. */
0173   mcfuart_set_baudrate(uart, B19200); /* dBUG defaults (unfortunately,
0174                      it is differ to termios default */
0175   *MCF5206E_UCSR(MBAR,chn) = MCF5206E_UCSR_RCS_TIMER | MCF5206E_UCSR_TCS_TIMER;
0176 
0177   /* Mode Registers 1,2 - set termios defaults (8N1) */
0178   *MCF5206E_UCR(MBAR,chn) = MCF5206E_UCR_MISC_RESET_MR;
0179   *MCF5206E_UMR(MBAR,chn) =
0180 /*      MCF5206E_UMR1_RXRTS | */
0181       MCF5206E_UMR1_PM_NO_PARITY |
0182       MCF5206E_UMR1_BC_8;
0183   *MCF5206E_UMR(MBAR,chn) =
0184       MCF5206E_UMR2_CM_NORMAL |
0185 /*      MCF5206E_UMR2_TXCTS | */
0186       MCF5206E_UMR2_SB_1;
0187 
0188   /* Enable Receiver and Transmitter */
0189   *MCF5206E_UCR(MBAR,chn) = MCF5206E_UCR_MISC_RESET_ERR;
0190   *MCF5206E_UCR(MBAR,chn) = MCF5206E_UCR_TC_ENABLE;
0191   *MCF5206E_UCR(MBAR,chn) = MCF5206E_UCR_RC_ENABLE;
0192 
0193   return RTEMS_SUCCESSFUL;
0194 }
0195 
0196 /*
0197  * mcfuart_disable --
0198  *     This function disable the operations on Motorola Coldfire UART
0199  *     controller
0200  *
0201  * PARAMETERS:
0202  *     uart - pointer to UART channel descriptor structure
0203  *
0204  * RETURNS:
0205  *     RTEMS_SUCCESSFUL if UART closed successfuly, or error code in
0206  *     other case
0207  */
0208 rtems_status_code mcfuart_disable(mcfuart *uart)
0209 {
0210   rtems_status_code rc;
0211 
0212   *MCF5206E_UCR(MBAR,uart->chn) =
0213       MCF5206E_UCR_TC_DISABLE |
0214       MCF5206E_UCR_RC_DISABLE;
0215   if (uart->intvec != 0) {
0216       *MCF5206E_IMR(MBAR) |=  MCF5206E_INTR_BIT(uart->chn == 1 ?
0217                         MCF5206E_INTR_UART_1 :
0218                         MCF5206E_INTR_UART_2);
0219       rc = rtems_interrupt_catch(uart->old_handler, uart->intvec, NULL);
0220       int_driven_uart[uart->chn - 1].uart = NULL;
0221       int_driven_uart[uart->chn - 1].vec = 0;
0222       if (rc != RTEMS_SUCCESSFUL)
0223       return rc;
0224   }
0225   return RTEMS_SUCCESSFUL;
0226 }
0227 
0228 /*
0229  * mcfuart_set_attributes --
0230  *     This function parse the termios attributes structure and perform
0231  *     the appropriate settings in hardware.
0232  *
0233  * PARAMETERS:
0234  *     uart - pointer to the UART descriptor structure
0235  *     t - pointer to termios parameters
0236  *
0237  * RETURNS:
0238  *     RTEMS_SUCCESSFUL
0239  */
0240 int mcfuart_set_attributes(mcfuart *uart, const struct termios *t)
0241 {
0242   int level;
0243   speed_t baud;
0244   uint8_t   umr1, umr2;
0245 
0246   baud = cfgetospeed(t);
0247   umr1 = 0;
0248   umr2 = MCF5206E_UMR2_CM_NORMAL;
0249 
0250   /* Set flow control */
0251   if ((t->c_cflag & CRTSCTS) != 0) {
0252     umr1 |= MCF5206E_UMR1_RXRTS;
0253     umr2 |= MCF5206E_UMR2_TXCTS;
0254   }
0255 
0256   /* Set character size */
0257   switch (t->c_cflag & CSIZE) {
0258     case CS5: umr1 |= MCF5206E_UMR1_BC_5; break;
0259     case CS6: umr1 |= MCF5206E_UMR1_BC_6; break;
0260     case CS7: umr1 |= MCF5206E_UMR1_BC_7; break;
0261     case CS8: umr1 |= MCF5206E_UMR1_BC_8; break;
0262   }
0263 
0264   /* Set number of stop bits */
0265   if ((t->c_cflag & CSTOPB) != 0) {
0266     if ((t->c_cflag & CSIZE) == CS5) {
0267       umr2 |= MCF5206E_UMR2_SB5_2;
0268     } else {
0269       umr2 |= MCF5206E_UMR2_SB_2;
0270     }
0271   } else {
0272     if ((t->c_cflag & CSIZE) == CS5) {
0273       umr2 |= MCF5206E_UMR2_SB5_1;
0274     } else {
0275       umr2 |= MCF5206E_UMR2_SB_1;
0276     }
0277   }
0278 
0279   /* Set parity mode */
0280   if ((t->c_cflag & PARENB) != 0) {
0281     if ((t->c_cflag & PARODD) != 0) {
0282       umr1 |= MCF5206E_UMR1_PM_ODD;
0283     } else {
0284       umr1 |= MCF5206E_UMR1_PM_EVEN;
0285     }
0286   } else {
0287     umr1 |= MCF5206E_UMR1_PM_NO_PARITY;
0288   }
0289 
0290   rtems_interrupt_disable(level);
0291   *MCF5206E_UCR(MBAR,uart->chn) =
0292       MCF5206E_UCR_TC_DISABLE | MCF5206E_UCR_RC_DISABLE;
0293   mcfuart_set_baudrate(uart, baud);
0294   *MCF5206E_UCR(MBAR,uart->chn) = MCF5206E_UCR_MISC_RESET_MR;
0295   *MCF5206E_UMR(MBAR,uart->chn) = umr1;
0296   *MCF5206E_UMR(MBAR,uart->chn) = umr2;
0297   if ((t->c_cflag & CREAD) != 0) {
0298     *MCF5206E_UCR(MBAR,uart->chn) =
0299     MCF5206E_UCR_TC_ENABLE | MCF5206E_UCR_RC_ENABLE;
0300   } else {
0301     *MCF5206E_UCR(MBAR,uart->chn) = MCF5206E_UCR_TC_ENABLE;
0302   }
0303   rtems_interrupt_enable(level);
0304 
0305   return RTEMS_SUCCESSFUL;
0306 }
0307 
0308 /*
0309  * mcfuart_poll_read --
0310  *     This function tried to read character from MCF UART and perform
0311  *     error handling. When parity or framing error occured, return
0312  *     value dependent on termios input mode flags:
0313  *         - received character, if IGNPAR == 1
0314  *         - 0, if IGNPAR == 0 and PARMRK == 0
0315  *         - 0xff and 0x00 on next poll_read invocation, if IGNPAR == 0 and
0316  *           PARMRK == 1
0317  *
0318  * PARAMETERS:
0319  *     uart - pointer to UART descriptor structure
0320  *
0321  * RETURNS:
0322  *     code of received character or -1 if no characters received.
0323  */
0324 int mcfuart_poll_read(mcfuart *uart)
0325 {
0326   uint8_t   usr;
0327   int ch;
0328 
0329   if (uart->parerr_mark_flag == true) {
0330     uart->parerr_mark_flag = false;
0331     return 0;
0332   }
0333 
0334   usr = *MCF5206E_USR(MBAR,uart->chn);
0335   if ((usr & MCF5206E_USR_RXRDY) != 0) {
0336     if (((usr & (MCF5206E_USR_FE | MCF5206E_USR_PE)) != 0) &&
0337     !(uart->c_iflag & IGNPAR)) {
0338       ch = *MCF5206E_URB(MBAR,uart->chn); /* Clear error bits */
0339       if (uart->c_iflag & PARMRK) {
0340     uart->parerr_mark_flag = true;
0341     ch = 0xff;
0342       } else {
0343     ch = 0;
0344       }
0345     } else {
0346       ch = *MCF5206E_URB(MBAR,uart->chn);
0347     }
0348   } else
0349     ch = -1;
0350   return ch;
0351 }
0352 
0353 /*
0354  * mcfuart_poll_write --
0355  *     This function transmit buffer byte-by-byte in polling mode.
0356  *
0357  * PARAMETERS:
0358  *     uart - pointer to the UART descriptor structure
0359  *     buf - pointer to transmit buffer
0360  *     len - transmit buffer length
0361  *
0362  * RETURNS:
0363  *     0
0364  */
0365 ssize_t mcfuart_poll_write(mcfuart *uart, const char *buf, size_t len)
0366 {
0367   size_t retval = len;
0368 
0369   while (len--) {
0370     while ((*MCF5206E_USR(MBAR, uart->chn) & MCF5206E_USR_TXRDY) == 0);
0371     *MCF5206E_UTB(MBAR, uart->chn) = *buf++;
0372   }
0373   return retval;
0374 }
0375 
0376 /* mcfuart_interrupt_handler --
0377  *     UART interrupt handler routine
0378  *
0379  * PARAMETERS:
0380  *     vec - interrupt vector number
0381  *
0382  * RETURNS:
0383  *     none
0384  */
0385 static rtems_isr mcfuart_interrupt_handler(rtems_vector_number vec)
0386 {
0387   mcfuart *uart;
0388   register uint8_t   usr;
0389   register uint8_t   uisr;
0390   register int chn;
0391   register int bp = 0;
0392 
0393   /* Find UART descriptor from vector number */
0394   if (int_driven_uart[0].vec == vec)
0395     uart = int_driven_uart[0].uart;
0396   else if (int_driven_uart[1].vec == vec)
0397     uart = int_driven_uart[1].uart;
0398   else
0399     return;
0400 
0401   chn = uart->chn;
0402 
0403   uisr = *MCF5206E_UISR(MBAR, chn);
0404   if (uisr & MCF5206E_UISR_DB) {
0405     *MCF5206E_UCR(MBAR, chn) = MCF5206E_UCR_MISC_RESET_BRK;
0406   }
0407 
0408   /* Receiving */
0409   while (1) {
0410     char buf[32];
0411     usr = *MCF5206E_USR(MBAR,chn);
0412     if ((bp < sizeof(buf) - 1) && ((usr & MCF5206E_USR_RXRDY) != 0)) {
0413       /* Receive character and handle frame/parity errors */
0414       if (((usr & (MCF5206E_USR_FE | MCF5206E_USR_PE)) != 0) &&
0415       !(uart->c_iflag & IGNPAR)) {
0416       if (uart->c_iflag & PARMRK) {
0417         buf[bp++] = 0xff;
0418         buf[bp++] = 0x00;
0419       } else {
0420         buf[bp++] = 0x00;
0421       }
0422       } else {
0423     buf[bp++] = *MCF5206E_URB(MBAR, chn);
0424       }
0425 
0426       /* Reset error condition if any errors has been detected */
0427       if (usr & (MCF5206E_USR_RB | MCF5206E_USR_FE |
0428          MCF5206E_USR_PE | MCF5206E_USR_OE)) {
0429     *MCF5206E_UCR(MBAR, chn) = MCF5206E_UCR_MISC_RESET_ERR;
0430       }
0431     } else {
0432       if (bp != 0)
0433     rtems_termios_enqueue_raw_characters(uart->tty, buf, bp);
0434       break;
0435     }
0436   }
0437 
0438   /* Transmitting */
0439   while (1) {
0440     if ((*MCF5206E_USR(MBAR, chn) & MCF5206E_USR_TXRDY) == 0)
0441       break;
0442     if (uart->tx_buf != NULL) {
0443       if (uart->tx_ptr >= uart->tx_buf_len) {
0444     register int dequeue = uart->tx_buf_len;
0445 
0446     *MCF5206E_UIMR(MBAR, uart->chn) = MCF5206E_UIMR_FFULL;
0447     uart->tx_buf = NULL;
0448     uart->tx_ptr = uart->tx_buf_len = 0;
0449     rtems_termios_dequeue_characters(uart->tty, dequeue);
0450       } else {
0451     *MCF5206E_UTB(MBAR, chn) = uart->tx_buf[uart->tx_ptr++];
0452       }
0453     }
0454     else
0455       break;
0456   }
0457 }
0458 
0459 /* mcfuart_interrupt_write --
0460  *     This function initiate transmitting of the buffer in interrupt mode.
0461  *
0462  * PARAMETERS:
0463  *     uart - pointer to the UART descriptor structure
0464  *     buf - pointer to transmit buffer
0465  *     len - transmit buffer length
0466  *
0467  * RETURNS:
0468  *     0
0469  */
0470 ssize_t mcfuart_interrupt_write(
0471   mcfuart *uart,
0472   const char *buf,
0473   size_t len
0474 )
0475 {
0476   if (len > 0) {
0477     uart->tx_buf = buf;
0478     uart->tx_buf_len = len;
0479     uart->tx_ptr = 0;
0480     *MCF5206E_UIMR(MBAR, uart->chn) =
0481         MCF5206E_UIMR_FFULL | MCF5206E_UIMR_TXRDY;
0482     while (((*MCF5206E_USR(MBAR,uart->chn) & MCF5206E_USR_TXRDY) != 0) &&
0483        (uart->tx_ptr < uart->tx_buf_len)) {
0484     *MCF5206E_UTB(MBAR,uart->chn) = uart->tx_buf[uart->tx_ptr++];
0485     }
0486   }
0487 
0488   return 0;
0489 }
0490 
0491 /* mcfuart_stop_remote_tx --
0492  *     This function stop data flow from remote device.
0493  *
0494  * PARAMETERS:
0495  *     uart - pointer to the UART descriptor structure
0496  *
0497  * RETURNS:
0498  *     RTEMS_SUCCESSFUL
0499  */
0500 int mcfuart_stop_remote_tx(mcfuart *uart)
0501 {
0502   *MCF5206E_UOP0(MBAR, uart->chn) = 1;
0503   return RTEMS_SUCCESSFUL;
0504 }
0505 
0506 /* mcfuart_start_remote_tx --
0507  *     This function resume data flow from remote device.
0508  *
0509  * PARAMETERS:
0510  *     uart - pointer to the UART descriptor structure
0511  *
0512  * RETURNS:
0513  *     RTEMS_SUCCESSFUL
0514  */
0515 int mcfuart_start_remote_tx(mcfuart *uart)
0516 {
0517   *MCF5206E_UOP1(MBAR, uart->chn) = 1;
0518   return RTEMS_SUCCESSFUL;
0519 }