source: rtems/c/src/lib/libcpu/m68k/mcf5206/console/mcfuart.c @ 00717a3

4.104.114.84.95
Last change on this file since 00717a3 was 00717a3, checked in by Joel Sherrill <joel.sherrill@…>, on 10/26/01 at 19:32:40

2001-10-26 Victor V. Vengerov <vvv@…>

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