1 //==========================================================================
5 // HAL diagnostic I/O support routines for the MCF5272
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.
12 // Copyright (C) 2006 eCosCentric Ltd.
14 // eCos is free software; you can redistribute it and/or modify it under
15 // the terms of the GNU General Public License as published by the Free
16 // Software Foundation; either version 2 or (at your option) any later version.
18 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
19 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23 // You should have received a copy of the GNU General Public License along
24 // with eCos; if not, write to the Free Software Foundation, Inc.,
25 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
27 // As a special exception, if other files instantiate templates or use macros
28 // or inline functions from this file, or you compile this file and link it
29 // with other works to produce a work based on this file, this file does not
30 // by itself cause the resulting work to be covered by the GNU General Public
31 // License. However the source code for this file must still be made available
32 // in accordance with section (3) of the GNU General Public License.
34 // This exception does not invalidate any other reasons why a work based on
35 // this file might be covered by the GNU General Public License.
36 // -------------------------------------------
37 //####ECOSGPLCOPYRIGHTEND####
38 //==========================================================================
39 //#####DESCRIPTIONBEGIN####
41 // Author(s): Enrico Piria
44 // Purpose: Code to manage the serial ports for diagnostic output.
47 //####DESCRIPTIONEND####
48 //==========================================================================
51 #include <pkgconf/hal.h>
52 #include <cyg/infra/cyg_type.h>
53 #include <cyg/hal/hal_intr.h> // CYGNUM_HAL_INTERRUPT_UART1
54 #include <cyg/hal/hal_if.h> // __comm_control_cmd_t
55 #include <cyg/hal/hal_io.h> // HAL I/O macros
56 #include <cyg/hal/hal_misc.h> // cyg_hal_is_break
57 #include <cyg/hal/drv_api.h> // CYG_ISR_HANDLED
59 #include <cyg/hal/plf_serial.h>
63 CYG_ADDRWORD base; // [Pointer] to Port base address
64 unsigned int vector; // UART interrupt vector
65 CYG_WORD msec_timeout; // Timeout in msec
68 static channel_data_t ports[] = {
70 (CYG_ADDRWORD) (&((mcf5272_devs_t *) 0)->uart[0]),
71 CYGNUM_HAL_INTERRUPT_UART1,
76 (CYG_ADDRWORD) (&((mcf5272_devs_t *) 0)->uart[1]),
77 CYGNUM_HAL_INTERRUPT_UART2,
84 cyg_hal_plf_serial_getc(void* __ch_data);
87 cyg_hal_plf_serial_putc(void* __ch_data, cyg_uint8 ch);
90 cyg_hal_plf_serial_init_channel(channel_data_t *port);
93 cyg_hal_plf_serial_getc_nonblock(void* __ch_data, cyg_uint8* ch);
96 cyg_hal_plf_serial_getc_timeout(void* __ch_data, cyg_uint8* ch);
99 cyg_hal_plf_serial_write(void* __ch_data, const cyg_uint8* __buf,
102 cyg_hal_plf_serial_read(void* __ch_data, cyg_uint8* __buf, cyg_uint32 __len);
105 cyg_hal_plf_serial_isr(void *__ch_data, int* __ctrlc,
106 CYG_ADDRWORD __vector, CYG_ADDRWORD __data);
108 cyg_hal_plf_serial_control(void *__ch_data, __comm_control_cmd_t __func, ...);
111 // ----------------------------------------------------------------------------
112 // Early initialization of comm. channels.
114 cyg_hal_plf_comms_init(void)
116 hal_virtual_comm_table_t* comm;
117 int cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
119 static int initialized = 0;
125 #if (defined(CYGNUM_HAL_VIRTUAL_VECTOR_DEBUG_CHANNEL) && \
126 CYGNUM_HAL_VIRTUAL_VECTOR_DEBUG_CHANNEL == 0) || \
127 (defined(CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL) && \
128 CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL == 0)
130 // UART0 pins are multplexed with GPIO port B. Enable them in
131 // port B control register.
132 HAL_READ_UINT32(&MCF5272_DEVS->gpio.pbcnt, portcnt);
133 HAL_WRITE_UINT32(&MCF5272_DEVS->gpio.pbcnt, ((portcnt &
134 ~(MCF5272_GPIO_PBCNT_URT0_MSK)) |
135 (MCF5272_GPIO_PBCNT_URT0_EN)));
138 cyg_hal_plf_serial_init_channel(&ports[0]);
140 // Setup procs in the vector table for channel 0
141 CYGACC_CALL_IF_SET_CONSOLE_COMM(0);
142 comm = CYGACC_CALL_IF_CONSOLE_PROCS();
143 CYGACC_COMM_IF_CH_DATA_SET(*comm, &ports[0]);
144 CYGACC_COMM_IF_WRITE_SET(*comm, cyg_hal_plf_serial_write);
145 CYGACC_COMM_IF_READ_SET(*comm, cyg_hal_plf_serial_read);
146 CYGACC_COMM_IF_PUTC_SET(*comm, cyg_hal_plf_serial_putc);
147 CYGACC_COMM_IF_GETC_SET(*comm, cyg_hal_plf_serial_getc);
148 CYGACC_COMM_IF_CONTROL_SET(*comm, cyg_hal_plf_serial_control);
149 CYGACC_COMM_IF_DBG_ISR_SET(*comm, cyg_hal_plf_serial_isr);
150 CYGACC_COMM_IF_GETC_TIMEOUT_SET(*comm, cyg_hal_plf_serial_getc_timeout);
153 #if (defined(CYGNUM_HAL_VIRTUAL_VECTOR_DEBUG_CHANNEL) && \
154 CYGNUM_HAL_VIRTUAL_VECTOR_DEBUG_CHANNEL == 1) || \
155 (defined(CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL) && \
156 CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL == 1)
158 // UART1 pins need to be enabled in port D control register.
159 HAL_READ_UINT32(&MCF5272_DEVS->gpio.pdcnt, portcnt);
160 HAL_WRITE_UINT32(&MCF5272_DEVS->gpio.pdcnt, ((portcnt &
161 ~(MCF5272_GPIO_PDCNT_URT1_MSK)) |
162 (MCF5272_GPIO_PDCNT_URT1_EN)));
165 cyg_hal_plf_serial_init_channel(&ports[1]);
167 // Setup procs in the vector table for channel 0
168 CYGACC_CALL_IF_SET_CONSOLE_COMM(1);
169 comm = CYGACC_CALL_IF_CONSOLE_PROCS();
170 CYGACC_COMM_IF_CH_DATA_SET(*comm, &ports[1]);
171 CYGACC_COMM_IF_WRITE_SET(*comm, cyg_hal_plf_serial_write);
172 CYGACC_COMM_IF_READ_SET(*comm, cyg_hal_plf_serial_read);
173 CYGACC_COMM_IF_PUTC_SET(*comm, cyg_hal_plf_serial_putc);
174 CYGACC_COMM_IF_GETC_SET(*comm, cyg_hal_plf_serial_getc);
175 CYGACC_COMM_IF_CONTROL_SET(*comm, cyg_hal_plf_serial_control);
176 CYGACC_COMM_IF_DBG_ISR_SET(*comm, cyg_hal_plf_serial_isr);
177 CYGACC_COMM_IF_GETC_TIMEOUT_SET(*comm, cyg_hal_plf_serial_getc_timeout);
180 // Restore original console
181 CYGACC_CALL_IF_SET_CONSOLE_COMM(cur);
185 void cyg_hal_plf_serial_init_channel(channel_data_t *port)
188 volatile mcf5272_uart_t *base =
189 (volatile mcf5272_uart_t *)((char *)MCF5272_DEVS + port->base);
190 // Initialize variable to prevent compiler warnings
191 unsigned int baud_rate = 1200;
194 #ifdef CYGPRI_HAL_VIRTUAL_VECTOR_DEBUG_CHANNEL_CONFIGURABLE
195 if( (port-&ports[0]) == CYGNUM_HAL_VIRTUAL_VECTOR_DEBUG_CHANNEL )
196 baud_rate = CYGNUM_HAL_VIRTUAL_VECTOR_DEBUG_CHANNEL_BAUD;
198 #ifdef CYGPRI_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL_CONFIGURABLE
199 if( (port-&ports[0]) == CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL )
200 baud_rate = CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL_BAUD;
203 // Before we do anything else, make sure we have enabled RTS in case
204 // the device we are using relies on hardware flow control.
205 // Note that this step is our only attempt at hardware flow control.
206 HAL_WRITE_UINT8(&base->uop1, MCF5272_UART_UOP1_RTS);
211 HAL_WRITE_UINT8(&base->ucr, MCF5272_UART_UCR_RTX);
214 HAL_WRITE_UINT8(&base->ucr, MCF5272_UART_UCR_RRX);
216 // Reset Mode Register
217 HAL_WRITE_UINT8(&base->ucr, MCF5272_UART_UCR_RMR);
219 HAL_WRITE_UINT8(&base->ucr, MCF5272_UART_UCR_RES);
220 HAL_WRITE_UINT8(&base->ucr, MCF5272_UART_UCR_RBC);
222 // Mode register 1 sets the UART to 8 data bits with no parity, and
223 // mode register 2 forces 1 stop bit. Also, interrupt generation
224 // on RxRDY signal is enabled by default.
225 // Reading or write to the mode register switches it from umr1 to umr2.
226 // To set it to umr1, we must write a reset mode register command to the
228 HAL_WRITE_UINT8(&base->umr, MCF5272_UART_UMR_8BNP);
229 HAL_WRITE_UINT8(&base->umr, MCF5272_UART_UMR_1S);
231 // Select a prescaled (by 1/16) CLKIN for the clock source
232 HAL_WRITE_UINT8(&base->usr_ucsr, MCF5272_UART_UCSR_CLKIN);
234 // Calculate baud settings
235 clk_div = (CYG_WORD16)
236 ((CYGHWR_HAL_SYSTEM_CLOCK_MHZ*1000000)/
238 HAL_WRITE_UINT8(&base->udu, clk_div >> 8);
239 HAL_WRITE_UINT8(&base->udl, clk_div & 0x00ff);
241 // Enable the transmitter and receiver
242 HAL_WRITE_UINT8(&base->ucr, MCF5272_UART_UCR_TXRXEN);
244 // Set interrupt priority to highest maskable level
245 HAL_INTERRUPT_SET_LEVEL(port->vector, 6);
249 cyg_uint8 cyg_hal_plf_serial_getc(void* __ch_data)
254 while(!cyg_hal_plf_serial_getc_nonblock(__ch_data, &ch));
260 void cyg_hal_plf_serial_putc(void *__ch_data, cyg_uint8 ch)
262 channel_data_t *port = (channel_data_t *) __ch_data;
263 volatile mcf5272_uart_t *base =
264 (volatile mcf5272_uart_t *)((char *)MCF5272_DEVS + port->base);
265 cyg_uint8 usr_ucsr, utf;
268 // Loop until the transmit data holding register is empty
271 HAL_READ_UINT8(&base->usr_ucsr, usr_ucsr);
272 } while (!(usr_ucsr & MCF5272_UART_USR_TXRDY));
274 // Write the character to the transmit buffer
275 HAL_WRITE_UINT8(&base->urb_utb, ch);
277 // Loop until the transmit data FIFO and the shift register are empty
280 HAL_READ_UINT8(&base->utf, utf);
281 HAL_READ_UINT8(&base->usr_ucsr, usr_ucsr);
282 } while ((utf & MCF5272_UART_UTF_TXB) ||
283 (!(usr_ucsr & MCF5272_UART_USR_TXEMP)));
286 static void cyg_hal_plf_serial_write(void* __ch_data, const cyg_uint8* __buf,
290 cyg_hal_plf_serial_putc(__ch_data, *__buf++);
294 static void cyg_hal_plf_serial_read(void* __ch_data, cyg_uint8* __buf,
298 *__buf++ = cyg_hal_plf_serial_getc(__ch_data);
302 static cyg_bool cyg_hal_plf_serial_getc_nonblock(void* __ch_data, cyg_uint8* ch)
304 channel_data_t *port = (channel_data_t *) __ch_data;
305 volatile mcf5272_uart_t *base =
306 (volatile mcf5272_uart_t *)((char *)MCF5272_DEVS + port->base);
311 HAL_READ_UINT8(&base->usr_ucsr, usr_ucsr);
313 // Check if a character is present
314 if (usr_ucsr & MCF5272_UART_USR_RRDY)
317 HAL_READ_UINT8(&base->urb_utb, *ch);
325 static cyg_bool cyg_hal_plf_serial_getc_timeout(void* __ch_data, cyg_uint8* ch)
331 delay_count = ((channel_data_t *)__ch_data)->msec_timeout;
334 res = cyg_hal_plf_serial_getc_nonblock(__ch_data, ch);
335 if (res || 0 == delay_count--)
338 CYGACC_CALL_IF_DELAY_US(100);
345 static int cyg_hal_plf_serial_control(void *__ch_data,
346 __comm_control_cmd_t __func, ...)
348 static int irq_state = 0;
349 channel_data_t *port = (channel_data_t *) __ch_data;
350 volatile mcf5272_uart_t *base =
351 (volatile mcf5272_uart_t *)((char *)MCF5272_DEVS + port->base);
356 case __COMMCTL_IRQ_ENABLE:
359 HAL_WRITE_UINT8(&base->uisr_uimr, MCF5272_UART_UIMR_FFULL);
360 HAL_INTERRUPT_UNMASK(port->vector);
362 case __COMMCTL_IRQ_DISABLE:
366 HAL_INTERRUPT_MASK(port->vector);
367 HAL_WRITE_UINT8(&base->uisr_uimr, 0);
369 case __COMMCTL_DBG_ISR_VECTOR:
372 case __COMMCTL_SET_TIMEOUT:
376 va_start(ap, __func);
378 ret = port->msec_timeout;
379 port->msec_timeout = va_arg(ap, cyg_uint32);
391 static int cyg_hal_plf_serial_isr(void *__ch_data, int* __ctrlc,
392 CYG_ADDRWORD __vector, CYG_ADDRWORD __data)
394 channel_data_t *port = (channel_data_t *) __ch_data;
395 volatile mcf5272_uart_t *base =
396 (volatile mcf5272_uart_t *)((char *)MCF5272_DEVS + port->base);
400 // Disable the interrupt temporarily
401 HAL_WRITE_UINT8(&base->uisr_uimr, 0);
406 HAL_READ_UINT8(&base->urb_utb, c);
407 if( cyg_hal_is_break( &c , 1 ) )
412 // Re-enable RxRDY interrupt
413 HAL_WRITE_UINT8(&base->uisr_uimr, MCF5272_UART_UIMR_FFULL);
415 return CYG_ISR_HANDLED;