1 //==========================================================================
3 // devs/serial/MCF52xx/MCF5282
5 // MCF5272 UART Serial I/O Interface Module (interrupt driven)
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
36 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37 // at http://sources.redhat.com/ecos/ecos-license/
38 // -------------------------------------------
39 //####ECOSGPLCOPYRIGHTEND####
40 //==========================================================================
42 #include <cyg/io/io.h>
43 #include <cyg/io/devtab.h>
44 #include <cyg/io/serial.h>
45 #include <cyg/infra/diag.h>
46 #include <cyg/hal/hal_intr.h>
47 #include <cyg/hal/hal_memmap.h>
48 #include <cyg/infra/cyg_type.h>
49 #include <cyg/hal/hal_arch.h>
50 #include <cyg/hal/drv_api.h>
51 #include <pkgconf/hal.h>
52 #include <pkgconf/system.h>
53 #include <pkgconf/io_serial.h>
54 #include <pkgconf/io.h>
55 #include <pkgconf/io_serial_mcf5272_uart.h>
56 #include <cyg/io/ser_mcf5272_uart.h>
59 /* The UART priority level */
60 #define MCF5272_UART_PRIORITY_LEVEL 2
64 typedef enum autobaud_states_t
66 AB_IDLE = 0, /* Normal state. Autobaud process hasn't been initiated yet. */
67 AB_BEGIN_BREAK, /* Detected a start of the break */
68 AB_BEGIN, /* Detected the end of the break and has set up the autobaud.*/
72 #define FIELD_OFFSET(type,field) (cyg_uint32)(&(((type*)0)->field))
74 typedef struct MCF5272_uart_info_t
77 volatile mcf5272_sim_uart_t* base; // Base address of the UART registers
78 uint32 uart_vector; // UART interrupt vector number
80 cyg_interrupt serial_interrupt; // Interrupt context
81 cyg_handle_t serial_interrupt_handle; // Interrupt handle
83 volatile uint8 imr_mirror; // Interrupt mask register mirror
85 cyg_serial_info_t config; // The channel configuration
87 autobaud_states_t autobaud_state; // The autobaud state
90 } MCF5272_uart_info_t;
92 /* Function prtoftyps for the MCF5272 UART ISR and DSR. */
93 static cyg_uint32 MCF5272_uart_ISR(cyg_vector_t vector, cyg_addrword_t data);
94 static void MCF5272_uart_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data);
97 /* Function prototypes for the serial functions. */
98 static bool MCF5272_uart_init(struct cyg_devtab_entry * tab);
99 static Cyg_ErrNo MCF5272_uart_lookup(struct cyg_devtab_entry **tab,
100 struct cyg_devtab_entry *sub_tab,
102 static bool MCF5272_uart_putc(serial_channel *chan, unsigned char c);
103 static unsigned char MCF5272_uart_getc(serial_channel *chan);
104 Cyg_ErrNo MCF5272_uart_set_config(serial_channel *chan, cyg_uint32 key,
105 const void *xbuf, cyg_uint32 *len);
106 static void MCF5272_uart_start_xmit(serial_channel *chan);
107 static void MCF5272_uart_stop_xmit(serial_channel * chan);
110 /* Declare the serial functions that are called by the common serial driver layer. */
116 MCF5272_uart_set_config,
117 MCF5272_uart_start_xmit,
118 MCF5272_uart_stop_xmit
122 /* Definition for channel 0 UART configuration. */
123 /************************************************/
124 #ifdef CYGPKG_IO_SERIAL_MCF5272_UART_CHANNEL0
126 /* Data structure contains
129 static MCF5272_uart_info_t MCF5272_uart_channel_info_0;
131 /* If the channel buffer size is zero, do not include interrupt UART processing */
132 #if CYGNUM_IO_SERIAL_MCF5272_UART_CHANNEL0_BUFSIZE > 0
134 /* Allocated receive and transmit buffer. The size of the buffer is */
135 /* configured by the configtool. */
137 static unsigned char MCF5272_uart_out_buf0[CYGNUM_IO_SERIAL_MCF5272_UART_CHANNEL0_BUFSIZE];
138 static unsigned char MCF5272_uart_in_buf0[CYGNUM_IO_SERIAL_MCF5272_UART_CHANNEL0_BUFSIZE];
140 /* Channel function table. We register the UART functions here so */
141 /* that uppper serial drivers can call the serial driver's routines. */
143 static SERIAL_CHANNEL_USING_INTERRUPTS(
144 MCF5272_uart_channel_0,
146 MCF5272_uart_channel_info_0,
147 CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_MCF5272_UART_CHANNEL0_BAUD),
148 CYG_SERIAL_STOP_DEFAULT,
149 CYG_SERIAL_PARITY_DEFAULT,
150 CYG_SERIAL_WORD_LENGTH_DEFAULT,
151 CYG_SERIAL_FLAGS_DEFAULT,
152 MCF5272_uart_out_buf0, sizeof(MCF5272_uart_out_buf0),
153 MCF5272_uart_in_buf0, sizeof(MCF5272_uart_in_buf0)
156 /* Don't use interrupt processing for the UART. */
157 static SERIAL_CHANNEL(
158 MCF5272_uart_channel_0,
160 MCF5272_uart_channel_info_0,
161 CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_MCF5272_UART_CHANNEL0_BAUD),
162 CYG_SERIAL_STOP_DEFAULT,
163 CYG_SERIAL_PARITY_DEFAULT,
164 CYG_SERIAL_WORD_LENGTH_DEFAULT,
165 CYG_SERIAL_FLAGS_DEFAULT
171 CYGDAT_IO_SERIAL_MCF5272_UART_CHANNEL0_NAME,
172 0, // Does not depend on a lower level interface
173 &cyg_io_serial_devio, // The table of I/O functions.
174 MCF5272_uart_init, // UART initialization function.
175 MCF5272_uart_lookup, // The UART lookup function. This function typically sets
176 // up the device for actual use, turing on interrupts, configuring the port, etc.
177 &MCF5272_uart_channel_0
179 #endif // CYGNUM_IO_SERIAL_MCF5272_UART_CHANNEL0
181 /* Definition for channel 1 UART configuration. */
182 /************************************************/
184 #ifdef CYGPKG_IO_SERIAL_MCF5272_UART_CHANNEL1
187 /* Data structure contains
190 static MCF5272_uart_info_t MCF5272_uart_channel_info_1;
192 /* If the channel buffer size is zero, do not include interrupt UART processing */
193 #if CYGNUM_IO_SERIAL_MCF5272_UART_CHANNEL1_BUFSIZE > 0
195 /* Allocated receive and transmit buffer. The size of the buffer is */
196 /* configured by the configtool. */
198 static unsigned char MCF5272_uart_out_buf1[CYGNUM_IO_SERIAL_MCF5272_UART_CHANNEL1_BUFSIZE];
199 static unsigned char MCF5272_uart_in_buf1[CYGNUM_IO_SERIAL_MCF5272_UART_CHANNEL1_BUFSIZE];
201 /* Channel function table. We register the UART functions here so */
202 /* that uppper serial drivers can call the serial driver's routines. */
204 static SERIAL_CHANNEL_USING_INTERRUPTS(
205 MCF5272_uart_channel_1,
207 MCF5272_uart_channel_info_1,
208 CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_MCF5272_UART_CHANNEL1_BAUD),
209 CYG_SERIAL_STOP_DEFAULT,
210 CYG_SERIAL_PARITY_DEFAULT,
211 CYG_SERIAL_WORD_LENGTH_DEFAULT,
212 CYG_SERIAL_FLAGS_DEFAULT,
213 MCF5272_uart_out_buf1, sizeof(MCF5272_uart_out_buf1),
214 MCF5272_uart_in_buf1, sizeof(MCF5272_uart_in_buf1)
218 static SERIAL_CHANNEL(MCF5272_uart_channel_1,
220 MCF5272_uart_channel_info_1,
221 CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_MCF5272_UART_CHANNEL0_BAUD),
222 CYG_SERIAL_STOP_DEFAULT,
223 CYG_SERIAL_PARITY_DEFAULT,
224 CYG_SERIAL_WORD_LENGTH_DEFAULT,
225 CYG_SERIAL_FLAGS_DEFAULT
230 CYGDAT_IO_SERIAL_MCF5272_UART_CHANNEL1_NAME,
231 0, // Does not depend on a lower level interface
232 &cyg_io_serial_devio, // The table of I/O functions.
233 MCF5272_uart_init, // UART initialization function.
234 MCF5272_uart_lookup, // The UART lookup function. This function typically sets
235 // up the device for actual use, turing on interrupts, configuring the port, etc.
236 &MCF5272_uart_channel_1
238 #endif // CYGNUM_IO_SERIAL_MCF5272_UART_CHANNEL1
242 /* Definition of macros that access the UART's SIM registers */
243 /* Read from a register */
245 #define MCF5272_UART_WRITE(_addr_,_value_) \
246 *((volatile CYG_BYTE*)&(_addr_)) = (CYG_BYTE)(_value_)
247 /* Write to a register */
248 #define MCF5272_UART_READ(_addr_) \
249 *(volatile CYG_BYTE*)&(_addr_)
252 /* Function Prototypes */
253 /* =================== */
254 /* Internal function to actually configure the hardware to desired baud rate, etc. */
255 static bool MCF5272_uart_config_port(serial_channel*, cyg_serial_info_t*);
256 static void MCF5272_uart_start_xmit(serial_channel*);
259 /* Baudrate conversion table. */
260 static unsigned long baud_rates_table[]=
263 50, // CYGNUM_SERIAL_BAUD_50 = 1
264 75, // CYGNUM_SERIAL_BAUD_75
265 110, // CYGNUM_SERIAL_BAUD_110
266 134, // CYGNUM_SERIAL_BAUD_134_5
267 150, // CYGNUM_SERIAL_BAUD_150
268 200, // CYGNUM_SERIAL_BAUD_200
269 300, // CYGNUM_SERIAL_BAUD_300
270 600, // CYGNUM_SERIAL_BAUD_600
271 1200, // CYGNUM_SERIAL_BAUD_1200
272 1800, // CYGNUM_SERIAL_BAUD_1800
273 2400, // CYGNUM_SERIAL_BAUD_2400
274 3600, // CYGNUM_SERIAL_BAUD_3600
275 4800, // CYGNUM_SERIAL_BAUD_4800
276 7200, // CYGNUM_SERIAL_BAUD_7200
277 9600, // CYGNUM_SERIAL_BAUD_9600
278 14400, // CYGNUM_SERIAL_BAUD_14400
279 19200, // CYGNUM_SERIAL_BAUD_19200
280 38400, // CYGNUM_SERIAL_BAUD_38400
281 57600, // CYGNUM_SERIAL_BAUD_57600
282 115200, // CYGNUM_SERIAL_BAUD_115200
283 230400 // CYGNUM_SERIAL_BAUD_230400
286 /* The table contains divers to divide the clock to configre a */
287 /* approppriate for the UART. */
289 static unsigned long dividers_table[]=
315 /*******************************************************************************
316 MCF5272_uart_init() - This routine is called during bootstrap to set up the
320 Pointer to the the device table.
323 Returns true if the initialization is successful. Otherwise, it retuns false
325 static bool MCF5272_uart_init(struct cyg_devtab_entry * tab)
327 serial_channel *chan = (serial_channel *)tab->priv;
328 MCF5272_uart_info_t *MCF5272_uart_chan = (MCF5272_uart_info_t *)chan->dev_priv;
330 #ifdef CYGPKG_IO_SERIAL_MCF5272_UART_CHANNEL0
332 /* Instantiation of the UART channel 0 data strucutre. This data */
333 /* structure contains channel information. */
335 if (strcmp(tab->name, CYGDAT_IO_SERIAL_MCF5272_UART_CHANNEL0_NAME) == 0)
338 /* Initiliaze the UART information data to all zeros. */
340 memset(MCF5272_uart_chan, sizeof(MCF5272_uart_info_t), 0);
342 /* Set the base address of the UART registers to differentiate */
343 /* itself from the different regusters for the other UART port. */
345 MCF5272_uart_chan->base = (mcf5272_sim_uart_t*)&MCF5272_SIM->uart[0];
347 /* Set the UART interrupt vector number. */
349 MCF5272_uart_chan->uart_vector = CYGNUM_HAL_VECTOR_UART1;
351 /* Set the autobaud state to idle. */
353 MCF5272_uart_chan->autobaud_state = AB_IDLE;
355 /* Initilize the UART 0 output pins */
357 MCF5272_SIM->gpio.pbcnt = MCF5272_GPIO_PBCNT_URT0_EN |
358 ((MCF5272_SIM->gpio.pbcnt) & ~MCF5272_GPIO_PBCNT_URT0_MSK);
362 #ifdef CYGPKG_IO_SERIAL_MCF5272_UART_CHANNEL1
364 /* Instantiation of the UART channel 1 data strucutre. This data structure contains
367 if (strcmp(tab->name, CYGDAT_IO_SERIAL_MCF5272_UART_CHANNEL1_NAME) == 0)
370 /* Initiliaze the UART information data to all zeros. */
372 memset(MCF5272_uart_chan, sizeof(MCF5272_uart_info_t), 0);
374 /* Set the base address of the UART registers to differentiate */
375 /* itself from the different regusters for the other UART port. */
377 MCF5272_uart_chan->base = (mcf5272_sim_uart_t*)&MCF5272_SIM->uart[1];
379 /* Set the UART interrupt vector number. */
381 MCF5272_uart_chan->uart_vector = CYGNUM_HAL_VECTOR_UART2;
383 /* Set the autobaud state to idle. */
385 MCF5272_uart_chan->autobaud_state = AB_IDLE;
387 /* Initilize the UART 1 output pins */
389 MCF5272_SIM->gpio.pdcnt = MCF5272_GPIO_PDCNT_URT1_EN |
390 ((MCF5272_SIM->gpio.pdcnt) & ~MCF5272_GPIO_PDCNT_URT1_MSK);
396 if (chan->out_cbuf.len > 0) {
398 /* If the the buffer is greater than zero, then the driver will */
399 /* use interrupt driven I/O. Hence, the driver creates an */
400 /* interrupt context for the UART device. */
402 cyg_drv_interrupt_create(MCF5272_uart_chan->uart_vector,
403 MCF5272_UART_PRIORITY_LEVEL, // Priority - Level 2
404 (cyg_addrword_t)chan, // Data item passed to interrupt handler
407 &MCF5272_uart_chan->serial_interrupt_handle,
408 &MCF5272_uart_chan->serial_interrupt);
410 cyg_drv_interrupt_attach(MCF5272_uart_chan->serial_interrupt_handle);
412 (chan->callbacks->serial_init)(chan); // Really only required for interrupt driven devices
415 // Configure Serial device.
416 return(MCF5272_uart_config_port(chan, &chan->config));
419 /******************************************************************************************************
420 MCF5272_uart_config_port() - Configure the UART port.
422 Internal function to actually configure the hardware to desired baud rate, etc.
425 chan - The channel information
426 new_confg - The port configuration which include the desired baud rate, etc.
429 Returns true if the port configuration is successful. Otherwise, it retuns false
432 static bool MCF5272_uart_config_port(serial_channel *chan,
433 cyg_serial_info_t *new_config)
435 MCF5272_uart_info_t * port = (MCF5272_uart_info_t *) chan->dev_priv;
438 unsigned int baud_divisor;
441 /* Get the divisor from the baudrate table which will use to */
442 /* configure the port's baud rate. */
444 baud_divisor = baud_rates_table[new_config->baud];
446 /* If the divisor is zeor, we dont' configure the port. */
448 if (baud_divisor == 0) return false;
450 /* Save the configuration value for later use. */
452 port->config = *new_config;
454 /* We first write the reset values into the device and then configure */
455 /* the device the we way we want to use it. */
457 /* Reset Transmitter */
459 MCF5272_UART_WRITE(port->base->ucr, MCF5272_UART_UCR_RESET_TX);
463 MCF5272_UART_WRITE(port->base->ucr, MCF5272_UART_UCR_RESET_RX);
465 /* Reset Mode Register */
467 MCF5272_UART_WRITE(port->base->ucr, MCF5272_UART_UCR_RESET_MR);
469 /* Translate the parity configuration to UART mode bits. */
471 switch(port->config.parity)
474 case CYGNUM_SERIAL_PARITY_NONE:
475 mode_reg = 0 | MCF5272_UART_UMR1_PM_NONE;
477 case CYGNUM_SERIAL_PARITY_EVEN:
478 mode_reg = 0 | MCF5272_UART_UMR1_PM_EVEN;
480 case CYGNUM_SERIAL_PARITY_ODD:
481 mode_reg = 0 | MCF5272_UART_UMR1_PM_ODD;
483 case CYGNUM_SERIAL_PARITY_MARK:
484 mode_reg = 0 | MCF5272_UART_UMR1_PM_FORCE_HI;
486 case CYGNUM_SERIAL_PARITY_SPACE:
487 mode_reg = 0 | MCF5272_UART_UMR1_PM_FORCE_LO;
491 /* Translate the number of bits per character configuration to UART mode bits. */
493 switch(port->config.word_length)
496 case CYGNUM_SERIAL_WORD_LENGTH_5:
497 mode_reg |= MCF5272_UART_UMR1_BC_5;
499 case CYGNUM_SERIAL_WORD_LENGTH_6:
500 mode_reg |= MCF5272_UART_UMR1_BC_6;
502 case CYGNUM_SERIAL_WORD_LENGTH_7:
503 mode_reg |= MCF5272_UART_UMR1_BC_7;
506 case CYGNUM_SERIAL_WORD_LENGTH_8:
507 mode_reg |= MCF5272_UART_UMR1_BC_8;
511 /* Configure the parity and the bits per character */
513 MCF5272_UART_WRITE(port->base->umr, mode_reg);
515 /* Translate the stop bit length to UART mode bits. */
517 switch(port->config.stop)
520 case CYGNUM_SERIAL_STOP_1:
521 mode_reg = MCF5272_UART_UMR2_STOP_BITS_1;
523 case CYGNUM_SERIAL_STOP_1_5:
524 mode_reg = MCF5272_UART_UMR2_STOP_BITS_15;
526 case CYGNUM_SERIAL_STOP_2:
527 mode_reg = MCF5272_UART_UMR2_STOP_BITS_2;
531 /* No echo or loopback */
533 MCF5272_UART_WRITE(port->base->umr, 0 | MCF5272_UART_UMR2_CM_NORMAL | mode_reg);
535 /* Set Rx and Tx baud by timer */
537 MCF5272_UART_WRITE(port->base->ucr, 0 | MCF5272_UART_UCSR_RCS(0xD) |
538 MCF5272_UART_UCSR_TCS(0xD));
540 /* Mask all USART interrupts */
542 MCF5272_UART_WRITE(port->base->uisr_uimr, 0);
544 /* Calculate baud settings */
546 ubgs = (uint16)((CYGHWR_HAL_SYSTEM_CLOCK_MHZ*1000000)/
547 (baud_divisor * 32));
549 /* Program the baud settings to the device. */
551 MCF5272_UART_WRITE(port->base->udu, (uint8)((ubgs & 0xFF00) >> 8));
552 MCF5272_UART_WRITE(port->base->udl, (uint8)(ubgs & 0x00FF));
554 /* Enable receiver and transmitter */
556 MCF5272_UART_WRITE(port->base->ucr, 0 | MCF5272_UART_UCR_TXRXEN);
558 /* Enable both transmit and receive interrupt. */
560 port->imr_mirror = MCF5272_UART_UIMR_TXRDY | MCF5272_UART_UIMR_FFULL |
561 MCF5272_UART_UIMR_DB;
562 MCF5272_UART_WRITE(port->base->uisr_uimr, port->imr_mirror);
564 return true; /* Returns true to indicate a successful configuration */
568 /*******************************************************************************
569 MCF5272_uart_lookup() - This routine is called when the device is "looked" up
573 tab - pointer to a pointer of the device table
574 sub_tab - Pointer to the sub device table.
575 name - name of the device
581 static Cyg_ErrNo MCF5272_uart_lookup(struct cyg_devtab_entry **tab,
582 struct cyg_devtab_entry *sub_tab,
585 serial_channel *chan = (serial_channel *)(*tab)->priv;
586 (chan->callbacks->serial_init)(chan); // Really only required for interrupt driven devices
590 /*******************************************************************************
591 MCF5272_uart_putc() - Send a character to the device output buffer.
594 chan - pointer to the serial private data.
595 c - the character to output
598 'true' if character is sent to device, return 'false' when we've
599 ran out of buffer space in the device itself.
603 static bool MCF5272_uart_putc(serial_channel *chan, unsigned char c)
605 CYG_INTERRUPT_STATE int_state;
606 MCF5272_uart_info_t *port = (MCF5272_uart_info_t *)chan->dev_priv;
608 /* Make sure the transmitter is not full. If it is full, return false. */
609 if (!(MCF5272_UART_READ(port->base->usr_ucsr) & MCF5272_UART_USR_TXRDY))
612 /* Enable transmit interrupt. */
613 HAL_DISABLE_INTERRUPTS(int_state);
614 port->imr_mirror |= MCF5272_UART_UIMR_TXRDY;
615 MCF5272_UART_WRITE(port->base->uisr_uimr, port->imr_mirror);
616 HAL_RESTORE_INTERRUPTS(int_state);
618 /* Enable the UART transmit. */
619 MCF5272_UART_WRITE(port->base->ucr, MCF5272_UART_UCR_TXRXEN);
621 /* Send the character */
622 MCF5272_UART_WRITE(port->base->urb_utb, c);
628 /******************************************************************************************************
629 MCF5272_uart_getc() - Fetch a character from the device input bufferand return it to the alling
630 routine. Wait until there is a character ready.
633 chan - pointer to the serial private data.
636 the character read from the UART.
639 static unsigned char MCF5272_uart_getc(serial_channel *chan)
641 MCF5272_uart_info_t * port = (MCF5272_uart_info_t *)chan->dev_priv;
643 /* Wait until character has been received */
645 while (!(MCF5272_UART_READ(port->base->usr_ucsr) & MCF5272_UART_USR_RXRDY))
647 diag_printf("ready poll");
650 /* Read the character from the FIFO queue. */
652 return MCF5272_UART_READ(port->base->urf);
657 /*******************************************************************************
658 MCF5272_uart_set_config() - Set up the device characteristics; baud rate, etc.
661 chan - pointer to the serial private data.
662 key - configuration key (command).
663 xbuf - pointer to the configuration buffer
664 len - the length of the configuration buffer
667 NOERR - If the configuration is successful
668 EINVAL - If the argument is invalid
672 Cyg_ErrNo MCF5272_uart_set_config(serial_channel *chan, cyg_uint32 key,
673 const void *xbuf, cyg_uint32 *len)
675 cyg_serial_info_t *config = (cyg_serial_info_t *)xbuf;
676 MCF5272_uart_info_t * port = (MCF5272_uart_info_t *) chan->dev_priv;
680 case CYG_IO_SET_CONFIG_SERIAL_INFO:
682 /* Set serial configuration. */
683 if ( *len < sizeof(cyg_serial_info_t) ) {
686 *len = sizeof(cyg_serial_info_t);
688 if (!MCF5272_uart_config_port(chan, config))
693 case CYG_IO_GET_CONFIG_SERIAL_INFO:
694 // Retrieve UART configuration
695 *config = port->config;
705 /*******************************************************************************
706 MCF5272_uart_start_xmit() - Enable the transmitter on the device.
709 chan - pointer to the serial private data.
712 static void MCF5272_uart_start_xmit(serial_channel *chan)
714 CYG_INTERRUPT_STATE int_state;
715 MCF5272_uart_info_t * port = (MCF5272_uart_info_t *) chan->dev_priv;
717 /* Enable the UART transmit. */
718 MCF5272_UART_WRITE(port->base->ucr, MCF5272_UART_UCR_TXEN);
720 /* Enable transmit interrupt */
721 HAL_DISABLE_INTERRUPTS(int_state);
722 port->imr_mirror |= MCF5272_UART_UIMR_TXRDY;
723 MCF5272_UART_WRITE(port->base->uisr_uimr, port->imr_mirror);
724 HAL_RESTORE_INTERRUPTS(int_state);
730 /******************************************************************************************************
731 MCF5272_uart_stop_xmit() - Disable the transmitter on the device
734 chan - pointer to the serial private data.
737 static void MCF5272_uart_stop_xmit(serial_channel * chan)
739 CYG_INTERRUPT_STATE int_state;
740 MCF5272_uart_info_t * port = (MCF5272_uart_info_t *) chan->dev_priv;
742 /* Disable transmit interrupt */
743 HAL_DISABLE_INTERRUPTS(int_state);
744 port->imr_mirror &= ~MCF5272_UART_UIMR_TXRDY;
745 MCF5272_UART_WRITE(port->base->uisr_uimr, port->imr_mirror);
746 HAL_RESTORE_INTERRUPTS(int_state);
748 /* Disable the UART transmit.
752 If the transmit the disabe
753 the diag_printf routines will poll forever to transmit the
754 a character. Hence, don't ever disable the transmit if
755 we want it to work with diag_printf.
757 //MCF5272_UART_WRITE(port->base->ucr, MCF5272_UART_UCR_TXDE);
763 /******************************************************************************************************
764 MCF5272_uart_ISR() - UART I/O interrupt interrupt service routine (ISR).
767 vector - the interrupt vector number
768 data - user parameter.
772 returns CYG_ISR_CALL_DSR to call the DSR.
775 static cyg_uint32 MCF5272_uart_ISR(cyg_vector_t vector, cyg_addrword_t data)
777 serial_channel *chan = (serial_channel *) data;
778 MCF5272_uart_info_t * port = (MCF5272_uart_info_t *) chan->dev_priv;
781 /* Write the value in the interrupt status register back
782 to the mask register to disable the interrupt temporarily.
785 MCF5272_UART_WRITE(port->base->uisr_uimr, 0);
787 return CYG_ISR_CALL_DSR; // Cause DSR to run
792 /******************************************************************************************************
793 MCF5272_uart_DSR() - Defered Service Routine (DSR) - This routine processes the interrupt
797 vector - The interrupt vector number
798 count - The nunber of DSR requests.
799 data - Device specific information
803 static void MCF5272_uart_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
805 serial_channel *chan = (serial_channel *)data;
806 MCF5272_uart_info_t *port = (MCF5272_uart_info_t *)chan->dev_priv;
810 /* Retrieve the interrupt status bits. We use these status bits to figure out
811 what process shouled we perform: read from the UART or inform of a completion
812 of a data transmission.
815 /* Retrieve the interrupt status register so
816 * the DSR can look it up.
820 while((isr = (MCF5272_UART_READ(port->base->uisr_uimr) & port->imr_mirror)))
822 switch (port->autobaud_state)
826 if (isr & MCF5272_UART_UISR_DB)
828 /* Detected the begin of a break, set the state to AB_BEGIN_BREAK
830 port->autobaud_state = AB_BEGIN_BREAK;
832 /* Reset the Delta Break bit in the UISR */
833 MCF5272_UART_WRITE(port->base->ucr, MCF5272_UART_UCR_RESET_BKCHGINT);
838 if (isr & MCF5272_UART_UISR_DB)
840 /* Detected the end of a break, set the state to AB_BEGIN, and
841 setup autobaud detection.
843 port->autobaud_state = AB_BEGIN;
845 /* Reset the Delta Break bit in the UISR and Enable autobaud */
846 MCF5272_UART_WRITE(port->base->ucr, MCF5272_UART_UCR_RESET_BKCHGINT |
847 MCF5272_UART_UCR_ENAB);
849 /* Enable autobaud completion interrupt */
850 port->imr_mirror |= MCF5272_UART_UIMR_ABC;
851 /* Disable the delta break interrupt so we can't receive
852 anymore break interrupt.
854 port->imr_mirror &= ~MCF5272_UART_UIMR_DB;
860 if (isr & MCF5272_UART_UISR_ABC)
863 // Retrieve the baudrate that we're using now.
864 u16_t divider = (port->base->uabu << 8) + port->base->uabl;
865 // Search in the list to find a match.
866 for (count = sizeof(dividers_table)/sizeof(unsigned long) - 1;
870 if (divider < dividers_table[count]) break;
874 port->config.baud = count;
876 /* Autobaud completion */
877 port->autobaud_state = AB_IDLE;
879 /* Disable autobaud */
880 MCF5272_UART_WRITE(port->base->ucr, MCF5272_UART_UCR_NONE);
882 /* Ignore autobaud completion interrupt. */
883 port->imr_mirror &= ~MCF5272_UART_UIMR_ABC;
885 /* Reenable begin break change and receive interrupt. */
886 port->imr_mirror |= MCF5272_UART_UIMR_DB;
894 /* Receive character interrupt */
895 if ((isr & MCF5272_UART_UISR_RXRDY))
896 /* Ignore all receive interrupt when we're autobauding. */
898 // Read all the characters in the fifo.
899 while ((MCF5272_UART_READ(port->base->uisr_uimr) & MCF5272_UART_UISR_RXRDY))
902 /* Read the character from the UART. */
903 c = MCF5272_UART_READ(port->base->urb_utb);
904 /* Pass the read character to the upper layer. */
905 (chan->callbacks->rcv_char)(chan, c);
909 /* Transmit complete interrupt */
911 if ((isr & MCF5272_UART_UISR_TXRDY))
914 /* Transmit holding register is empty */
915 (chan->callbacks->xmt_char)(chan);
921 /* Unmask all the DUART interrupts that were masked in the ISR, so */
922 /* that we can receive the next interrupt. */
924 MCF5272_UART_WRITE(port->base->uisr_uimr, port->imr_mirror);
928 #ifdef CYGPKG_IO_SERIAL_MCF5272_UART_CHANNEL0
929 unsigned long MCF5272_uart_get_channel_0_baud_rate()
931 /* return the baud rate for the first serial port */
933 return baud_rates_table[MCF5272_uart_channel_info_0.config.baud];
937 #ifdef CYGPKG_IO_SERIAL_MCF5272_UART_CHANNEL1
938 unsigned long MCF5272_uart_get_channel_1_baud_rate()
940 /* return the baud rate for the second serial port */
942 return baud_rates_table[MCF5272_uart_channel_info_1.config.baud];