source: rtems/bsps/m68k/mcf5206elite/dev/mcfuart.c @ d7d66d7

5
Last change on this file since d7d66d7 was 2190bc6, checked in by Sebastian Huber <sebastian.huber@…>, on 03/26/18 at 10:20:45

bsps/mcf5206elite: Move libcpu content to bsps

This patch is a part of the BSP source reorganization.

Update #3285.

  • Property mode set to 100644
File size: 13.2 KB
Line 
1/*
2 * Generic UART Serial driver for Motorola Coldfire processors
3 */
4
5/*
6 * Copyright (C) 2000 OKTET Ltd., St.-Petersburg, Russian Fed.
7 * Author: Victor V. Vengerov <vvv@oktet.ru>
8 *
9 *  COPYRIGHT (c) 1989-2000.
10 *  On-Line Applications Research Corporation (OAR).
11 *
12 *  The license and distribution terms for this file may be
13 *  found in the file LICENSE in this distribution or at
14 *  http://www.rtems.org/license/LICENSE.
15 */
16
17#include <rtems.h>
18#include <termios.h>
19#include <rtems/libio.h>
20#include "mcf5206/mcfuart.h"
21
22/*
23 * int_driven_uart -- mapping between interrupt vector number and
24 * UART descriptor structures
25 */
26static struct {
27  mcfuart *uart;
28  int      vec;
29} int_driven_uart[2];
30
31/* Forward function declarations */
32static rtems_isr
33mcfuart_interrupt_handler(rtems_vector_number vec);
34
35/*
36 * mcfuart_init --
37 *     This function verifies the input parameters and perform initialization
38 *     of the Motorola Coldfire on-chip UART descriptor structure.
39 *
40 * PARAMETERS:
41 *     uart - pointer to the UART channel descriptor structure
42 *     tty - pointer to termios structure
43 *     int_driven - interrupt-driven (1) or polled (0) I/O mode
44 *     chn - channel number (0/1)
45 *     rx_buf - pointer to receive buffer
46 *     rx_buf_len - receive buffer length
47 *
48 * RETURNS:
49 *     RTEMS_SUCCESSFUL if all parameters are valid, or error code
50 */
51rtems_status_code
52mcfuart_init(
53  mcfuart   *uart,
54  void      *tty,
55  uint8_t    intvec,
56  uint32_t   chn
57)
58{
59  if (uart == NULL)
60      return RTEMS_INVALID_ADDRESS;
61
62  if ((chn <= 0) || (chn > MCF5206E_UART_CHANNELS))
63      return RTEMS_INVALID_NUMBER;
64
65  uart->chn = chn;
66  uart->intvec = intvec;
67  uart->tty = tty;
68
69  return RTEMS_SUCCESSFUL;
70}
71
72/* mcfuart_set_baudrate --
73 *     Program the UART timer to specified baudrate
74 *
75 * PARAMETERS:
76 *     uart - pointer to UART descriptor structure
77 *     baud - termios baud rate (B50, B9600, etc...)
78 *
79 * RETURNS:
80 *     none
81 */
82static void
83mcfuart_set_baudrate(mcfuart *uart, speed_t baud)
84{
85  uint32_t   div;
86  uint32_t   rate;
87
88    switch (baud) {
89      case B50:     rate = 50; break;
90      case B75:     rate = 75; break;
91      case B110:    rate = 110; break;
92      case B134:    rate = 134; break;
93      case B150:    rate = 150; break;
94      case B200:    rate = 200; break;
95      case B300:    rate = 300; break;
96      case B600:    rate = 600; break;
97      case B1200:   rate = 1200; break;
98      case B2400:   rate = 2400; break;
99      case B4800:   rate = 4800; break;
100      case B9600:   rate = 9600; break;
101      case B19200:  rate = 19200; break;
102      case B38400:  rate = 38400; break;
103      case B57600:  rate = 57600; break;
104#ifdef B115200
105      case B115200: rate = 115200; break;
106#endif
107#ifdef B230400
108      case B230400: rate = 230400; break;
109#endif
110      default:      rate = 9600; break;
111    }
112
113  div = SYSTEM_CLOCK_FREQUENCY / (rate * 32);
114
115  *MCF5206E_UBG1(MBAR,uart->chn) = (uint8_t)((div >> 8) & 0xff);
116  *MCF5206E_UBG2(MBAR,uart->chn) = (uint8_t)(div & 0xff);
117}
118
119/*
120 * mcfuart_reset --
121 *     This function perform the hardware initialization of Motorola
122 *     Coldfire processor on-chip UART controller using parameters
123 *     filled by the mcfuart_init function.
124 *
125 * PARAMETERS:
126 *     uart - pointer to UART channel descriptor structure
127 *
128 * RETURNS:
129 *     RTEMS_SUCCESSFUL if channel is initialized successfully, error
130 *     code in other case
131 *
132 * ALGORITHM:
133 *     This function in general follows to algorith described in MCF5206e
134 *     User's Manual, 12.5 UART Module Initialization Sequence
135 */
136rtems_status_code mcfuart_reset(mcfuart *uart)
137{
138  register uint32_t   chn;
139  rtems_status_code rc;
140
141  if (uart == NULL)
142    return RTEMS_INVALID_ADDRESS;
143
144  chn = uart->chn;
145
146  /* Reset the receiver and transmitter */
147  *MCF5206E_UCR(MBAR,chn) = MCF5206E_UCR_MISC_RESET_RX;
148  *MCF5206E_UCR(MBAR,chn) = MCF5206E_UCR_MISC_RESET_TX;
149
150  /*
151   * Program the vector number for a UART module interrupt, or
152   * disable UART interrupts if polled I/O. Enable the desired
153   * interrupt sources.
154   */
155  if (uart->intvec != 0) {
156    int_driven_uart[chn - 1].uart = uart;
157    int_driven_uart[chn - 1].vec = uart->intvec;
158    rc = rtems_interrupt_catch(mcfuart_interrupt_handler, uart->intvec,
159                               &uart->old_handler);
160    if (rc != RTEMS_SUCCESSFUL)
161      return rc;
162    *MCF5206E_UIVR(MBAR,chn) = uart->intvec;
163    *MCF5206E_UIMR(MBAR,chn) = MCF5206E_UIMR_FFULL;
164    *MCF5206E_UACR(MBAR,chn) = MCF5206E_UACR_IEC;
165    *MCF5206E_IMR(MBAR) &= ~MCF5206E_INTR_BIT(uart->chn == 1 ?
166                                              MCF5206E_INTR_UART_1 :
167                                              MCF5206E_INTR_UART_2);
168  } else {
169    *MCF5206E_UIMR(MBAR,chn) = 0;
170  }
171
172  /* Select the receiver and transmitter clock. */
173  mcfuart_set_baudrate(uart, B19200); /* dBUG defaults (unfortunately,
174                                         it is differ to termios default */
175  *MCF5206E_UCSR(MBAR,chn) = MCF5206E_UCSR_RCS_TIMER | MCF5206E_UCSR_TCS_TIMER;
176
177  /* Mode Registers 1,2 - set termios defaults (8N1) */
178  *MCF5206E_UCR(MBAR,chn) = MCF5206E_UCR_MISC_RESET_MR;
179  *MCF5206E_UMR(MBAR,chn) =
180/*      MCF5206E_UMR1_RXRTS | */
181      MCF5206E_UMR1_PM_NO_PARITY |
182      MCF5206E_UMR1_BC_8;
183  *MCF5206E_UMR(MBAR,chn) =
184      MCF5206E_UMR2_CM_NORMAL |
185/*      MCF5206E_UMR2_TXCTS | */
186      MCF5206E_UMR2_SB_1;
187
188  /* Enable Receiver and Transmitter */
189  *MCF5206E_UCR(MBAR,chn) = MCF5206E_UCR_MISC_RESET_ERR;
190  *MCF5206E_UCR(MBAR,chn) = MCF5206E_UCR_TC_ENABLE;
191  *MCF5206E_UCR(MBAR,chn) = MCF5206E_UCR_RC_ENABLE;
192
193  return RTEMS_SUCCESSFUL;
194}
195
196/*
197 * mcfuart_disable --
198 *     This function disable the operations on Motorola Coldfire UART
199 *     controller
200 *
201 * PARAMETERS:
202 *     uart - pointer to UART channel descriptor structure
203 *
204 * RETURNS:
205 *     RTEMS_SUCCESSFUL if UART closed successfuly, or error code in
206 *     other case
207 */
208rtems_status_code mcfuart_disable(mcfuart *uart)
209{
210  rtems_status_code rc;
211
212  *MCF5206E_UCR(MBAR,uart->chn) =
213      MCF5206E_UCR_TC_DISABLE |
214      MCF5206E_UCR_RC_DISABLE;
215  if (uart->intvec != 0) {
216      *MCF5206E_IMR(MBAR) |=  MCF5206E_INTR_BIT(uart->chn == 1 ?
217                                                MCF5206E_INTR_UART_1 :
218                                                MCF5206E_INTR_UART_2);
219      rc = rtems_interrupt_catch(uart->old_handler, uart->intvec, NULL);
220      int_driven_uart[uart->chn - 1].uart = NULL;
221      int_driven_uart[uart->chn - 1].vec = 0;
222      if (rc != RTEMS_SUCCESSFUL)
223          return rc;
224  }
225  return RTEMS_SUCCESSFUL;
226}
227
228/*
229 * mcfuart_set_attributes --
230 *     This function parse the termios attributes structure and perform
231 *     the appropriate settings in hardware.
232 *
233 * PARAMETERS:
234 *     uart - pointer to the UART descriptor structure
235 *     t - pointer to termios parameters
236 *
237 * RETURNS:
238 *     RTEMS_SUCCESSFUL
239 */
240int mcfuart_set_attributes(mcfuart *uart, const struct termios *t)
241{
242  int level;
243  speed_t baud;
244  uint8_t   umr1, umr2;
245
246  baud = cfgetospeed(t);
247  umr1 = 0;
248  umr2 = MCF5206E_UMR2_CM_NORMAL;
249
250  /* Set flow control */
251  if ((t->c_cflag & CRTSCTS) != 0) {
252    umr1 |= MCF5206E_UMR1_RXRTS;
253    umr2 |= MCF5206E_UMR2_TXCTS;
254  }
255
256  /* Set character size */
257  switch (t->c_cflag & CSIZE) {
258    case CS5: umr1 |= MCF5206E_UMR1_BC_5; break;
259    case CS6: umr1 |= MCF5206E_UMR1_BC_6; break;
260    case CS7: umr1 |= MCF5206E_UMR1_BC_7; break;
261    case CS8: umr1 |= MCF5206E_UMR1_BC_8; break;
262  }
263
264  /* Set number of stop bits */
265  if ((t->c_cflag & CSTOPB) != 0) {
266    if ((t->c_cflag & CSIZE) == CS5) {
267      umr2 |= MCF5206E_UMR2_SB5_2;
268    } else {
269      umr2 |= MCF5206E_UMR2_SB_2;
270    }
271  } else {
272    if ((t->c_cflag & CSIZE) == CS5) {
273      umr2 |= MCF5206E_UMR2_SB5_1;
274    } else {
275      umr2 |= MCF5206E_UMR2_SB_1;
276    }
277  }
278
279  /* Set parity mode */
280  if ((t->c_cflag & PARENB) != 0) {
281    if ((t->c_cflag & PARODD) != 0) {
282      umr1 |= MCF5206E_UMR1_PM_ODD;
283    } else {
284      umr1 |= MCF5206E_UMR1_PM_EVEN;
285    }
286  } else {
287    umr1 |= MCF5206E_UMR1_PM_NO_PARITY;
288  }
289
290  rtems_interrupt_disable(level);
291  *MCF5206E_UCR(MBAR,uart->chn) =
292      MCF5206E_UCR_TC_DISABLE | MCF5206E_UCR_RC_DISABLE;
293  mcfuart_set_baudrate(uart, baud);
294  *MCF5206E_UCR(MBAR,uart->chn) = MCF5206E_UCR_MISC_RESET_MR;
295  *MCF5206E_UMR(MBAR,uart->chn) = umr1;
296  *MCF5206E_UMR(MBAR,uart->chn) = umr2;
297  if ((t->c_cflag & CREAD) != 0) {
298    *MCF5206E_UCR(MBAR,uart->chn) =
299        MCF5206E_UCR_TC_ENABLE | MCF5206E_UCR_RC_ENABLE;
300  } else {
301    *MCF5206E_UCR(MBAR,uart->chn) = MCF5206E_UCR_TC_ENABLE;
302  }
303  rtems_interrupt_enable(level);
304
305  return RTEMS_SUCCESSFUL;
306}
307
308/*
309 * mcfuart_poll_read --
310 *     This function tried to read character from MCF UART and perform
311 *     error handling. When parity or framing error occured, return
312 *     value dependent on termios input mode flags:
313 *         - received character, if IGNPAR == 1
314 *         - 0, if IGNPAR == 0 and PARMRK == 0
315 *         - 0xff and 0x00 on next poll_read invocation, if IGNPAR == 0 and
316 *           PARMRK == 1
317 *
318 * PARAMETERS:
319 *     uart - pointer to UART descriptor structure
320 *
321 * RETURNS:
322 *     code of received character or -1 if no characters received.
323 */
324int mcfuart_poll_read(mcfuart *uart)
325{
326  uint8_t   usr;
327  int ch;
328
329  if (uart->parerr_mark_flag == true) {
330    uart->parerr_mark_flag = false;
331    return 0;
332  }
333
334  usr = *MCF5206E_USR(MBAR,uart->chn);
335  if ((usr & MCF5206E_USR_RXRDY) != 0) {
336    if (((usr & (MCF5206E_USR_FE | MCF5206E_USR_PE)) != 0) &&
337        !(uart->c_iflag & IGNPAR)) {
338      ch = *MCF5206E_URB(MBAR,uart->chn); /* Clear error bits */
339      if (uart->c_iflag & PARMRK) {
340        uart->parerr_mark_flag = true;
341        ch = 0xff;
342      } else {
343        ch = 0;
344      }
345    } else {
346      ch = *MCF5206E_URB(MBAR,uart->chn);
347    }
348  } else
349    ch = -1;
350  return ch;
351}
352
353/*
354 * mcfuart_poll_write --
355 *     This function transmit buffer byte-by-byte in polling mode.
356 *
357 * PARAMETERS:
358 *     uart - pointer to the UART descriptor structure
359 *     buf - pointer to transmit buffer
360 *     len - transmit buffer length
361 *
362 * RETURNS:
363 *     0
364 */
365ssize_t mcfuart_poll_write(mcfuart *uart, const char *buf, size_t len)
366{
367  size_t retval = len;
368
369  while (len--) {
370    while ((*MCF5206E_USR(MBAR, uart->chn) & MCF5206E_USR_TXRDY) == 0);
371    *MCF5206E_UTB(MBAR, uart->chn) = *buf++;
372  }
373  return retval;
374}
375
376/* mcfuart_interrupt_handler --
377 *     UART interrupt handler routine
378 *
379 * PARAMETERS:
380 *     vec - interrupt vector number
381 *
382 * RETURNS:
383 *     none
384 */
385static rtems_isr mcfuart_interrupt_handler(rtems_vector_number vec)
386{
387  mcfuart *uart;
388  register uint8_t   usr;
389  register uint8_t   uisr;
390  register int chn;
391  register int bp = 0;
392
393  /* Find UART descriptor from vector number */
394  if (int_driven_uart[0].vec == vec)
395    uart = int_driven_uart[0].uart;
396  else if (int_driven_uart[1].vec == vec)
397    uart = int_driven_uart[1].uart;
398  else
399    return;
400
401  chn = uart->chn;
402
403  uisr = *MCF5206E_UISR(MBAR, chn);
404  if (uisr & MCF5206E_UISR_DB) {
405    *MCF5206E_UCR(MBAR, chn) = MCF5206E_UCR_MISC_RESET_BRK;
406  }
407
408  /* Receiving */
409  while (1) {
410    char buf[32];
411    usr = *MCF5206E_USR(MBAR,chn);
412    if ((bp < sizeof(buf) - 1) && ((usr & MCF5206E_USR_RXRDY) != 0)) {
413      /* Receive character and handle frame/parity errors */
414      if (((usr & (MCF5206E_USR_FE | MCF5206E_USR_PE)) != 0) &&
415          !(uart->c_iflag & IGNPAR)) {
416          if (uart->c_iflag & PARMRK) {
417            buf[bp++] = 0xff;
418            buf[bp++] = 0x00;
419          } else {
420            buf[bp++] = 0x00;
421          }
422      } else {
423        buf[bp++] = *MCF5206E_URB(MBAR, chn);
424      }
425
426      /* Reset error condition if any errors has been detected */
427      if (usr & (MCF5206E_USR_RB | MCF5206E_USR_FE |
428                 MCF5206E_USR_PE | MCF5206E_USR_OE)) {
429        *MCF5206E_UCR(MBAR, chn) = MCF5206E_UCR_MISC_RESET_ERR;
430      }
431    } else {
432      if (bp != 0)
433        rtems_termios_enqueue_raw_characters(uart->tty, buf, bp);
434      break;
435    }
436  }
437
438  /* Transmitting */
439  while (1) {
440    if ((*MCF5206E_USR(MBAR, chn) & MCF5206E_USR_TXRDY) == 0)
441      break;
442    if (uart->tx_buf != NULL) {
443      if (uart->tx_ptr >= uart->tx_buf_len) {
444        register int dequeue = uart->tx_buf_len;
445
446        *MCF5206E_UIMR(MBAR, uart->chn) = MCF5206E_UIMR_FFULL;
447        uart->tx_buf = NULL;
448        uart->tx_ptr = uart->tx_buf_len = 0;
449        rtems_termios_dequeue_characters(uart->tty, dequeue);
450      } else {
451        *MCF5206E_UTB(MBAR, chn) = uart->tx_buf[uart->tx_ptr++];
452      }
453    }
454    else
455      break;
456  }
457}
458
459/* mcfuart_interrupt_write --
460 *     This function initiate transmitting of the buffer in interrupt mode.
461 *
462 * PARAMETERS:
463 *     uart - pointer to the UART descriptor structure
464 *     buf - pointer to transmit buffer
465 *     len - transmit buffer length
466 *
467 * RETURNS:
468 *     0
469 */
470ssize_t mcfuart_interrupt_write(
471  mcfuart *uart,
472  const char *buf,
473  size_t len
474)
475{
476  if (len > 0) {
477    uart->tx_buf = buf;
478    uart->tx_buf_len = len;
479    uart->tx_ptr = 0;
480    *MCF5206E_UIMR(MBAR, uart->chn) =
481            MCF5206E_UIMR_FFULL | MCF5206E_UIMR_TXRDY;
482    while (((*MCF5206E_USR(MBAR,uart->chn) & MCF5206E_USR_TXRDY) != 0) &&
483           (uart->tx_ptr < uart->tx_buf_len)) {
484        *MCF5206E_UTB(MBAR,uart->chn) = uart->tx_buf[uart->tx_ptr++];
485    }
486  }
487
488  return 0;
489}
490
491/* mcfuart_stop_remote_tx --
492 *     This function stop data flow from remote device.
493 *
494 * PARAMETERS:
495 *     uart - pointer to the UART descriptor structure
496 *
497 * RETURNS:
498 *     RTEMS_SUCCESSFUL
499 */
500int mcfuart_stop_remote_tx(mcfuart *uart)
501{
502  *MCF5206E_UOP0(MBAR, uart->chn) = 1;
503  return RTEMS_SUCCESSFUL;
504}
505
506/* mcfuart_start_remote_tx --
507 *     This function resume data flow from remote device.
508 *
509 * PARAMETERS:
510 *     uart - pointer to the UART descriptor structure
511 *
512 * RETURNS:
513 *     RTEMS_SUCCESSFUL
514 */
515int mcfuart_start_remote_tx(mcfuart *uart)
516{
517  *MCF5206E_UOP1(MBAR, uart->chn) = 1;
518  return RTEMS_SUCCESSFUL;
519}
Note: See TracBrowser for help on using the repository browser.