]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/hal/coldfire/mcf5272/v2_0/src/hal_diag.c
Initial revision
[karo-tx-redboot.git] / packages / hal / coldfire / mcf5272 / v2_0 / src / hal_diag.c
1 //==========================================================================
2 //
3 //      hal_diag.c
4 //
5 //      HAL diagnostic I/O support routines for the MCF5272
6 //
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.
13 //
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.
17 //
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
21 // for more details.
22 //
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.
26 //
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.
33 //
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####
40 //
41 // Author(s):    Enrico Piria
42 // Contributors:
43 // Date:         2005-25-06
44 // Purpose:      Code to manage the serial ports for diagnostic output.
45 // Description:
46 //
47 //####DESCRIPTIONEND####
48 //==========================================================================
49
50
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
58
59 #include <cyg/hal/plf_serial.h>
60
61
62 typedef struct {
63     CYG_ADDRWORD                base;           // [Pointer] to Port base address
64     unsigned int                vector;         // UART interrupt vector
65     CYG_WORD                    msec_timeout;   // Timeout in msec
66 } channel_data_t;
67
68 static channel_data_t ports[] = {
69     {
70         (CYG_ADDRWORD) (&((mcf5272_devs_t *) 0)->uart[0]),
71         CYGNUM_HAL_INTERRUPT_UART1,
72         1000
73     },
74
75     {
76         (CYG_ADDRWORD) (&((mcf5272_devs_t *) 0)->uart[1]),
77         CYGNUM_HAL_INTERRUPT_UART2,
78         1000
79     }
80 };
81
82
83 static cyg_uint8
84 cyg_hal_plf_serial_getc(void* __ch_data);
85
86 static void
87 cyg_hal_plf_serial_putc(void* __ch_data, cyg_uint8 ch);
88
89 static void
90 cyg_hal_plf_serial_init_channel(channel_data_t *port);
91
92 static cyg_bool
93 cyg_hal_plf_serial_getc_nonblock(void* __ch_data, cyg_uint8* ch);
94
95 static cyg_bool
96 cyg_hal_plf_serial_getc_timeout(void* __ch_data, cyg_uint8* ch);
97
98 static void
99 cyg_hal_plf_serial_write(void* __ch_data, const cyg_uint8* __buf, 
100                          cyg_uint32 __len);
101 static void
102 cyg_hal_plf_serial_read(void* __ch_data, cyg_uint8* __buf, cyg_uint32 __len);
103
104 static int
105 cyg_hal_plf_serial_isr(void *__ch_data, int* __ctrlc, 
106                        CYG_ADDRWORD __vector, CYG_ADDRWORD __data);
107 static int
108 cyg_hal_plf_serial_control(void *__ch_data, __comm_control_cmd_t __func, ...);
109
110
111 // ----------------------------------------------------------------------------
112 // Early initialization of comm. channels.
113 void
114 cyg_hal_plf_comms_init(void)
115 {
116     hal_virtual_comm_table_t* comm;
117     int cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
118     cyg_uint32 portcnt;
119     static int initialized = 0;
120
121     if (initialized)
122         return;
123     initialized = 1;
124
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)
129     
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)));
136
137     // Init channel 0
138     cyg_hal_plf_serial_init_channel(&ports[0]);
139
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);
151 #endif
152
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)
157
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)));
163
164     // Init channel 1
165     cyg_hal_plf_serial_init_channel(&ports[1]);
166
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);
178 #endif
179
180     // Restore original console
181     CYGACC_CALL_IF_SET_CONSOLE_COMM(cur);
182 }
183
184
185 void cyg_hal_plf_serial_init_channel(channel_data_t *port)
186 {
187     CYG_WORD16 clk_div;
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;
192
193
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;
197 #endif    
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;
201 #endif
202
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);
207
208     // Initialize UART
209     
210     // Reset Transmitter
211     HAL_WRITE_UINT8(&base->ucr, MCF5272_UART_UCR_RTX);
212
213     // Reset Receiver
214     HAL_WRITE_UINT8(&base->ucr, MCF5272_UART_UCR_RRX);
215
216     // Reset Mode Register
217     HAL_WRITE_UINT8(&base->ucr, MCF5272_UART_UCR_RMR);
218
219     HAL_WRITE_UINT8(&base->ucr, MCF5272_UART_UCR_RES);
220     HAL_WRITE_UINT8(&base->ucr, MCF5272_UART_UCR_RBC);
221
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
227     // command register.
228     HAL_WRITE_UINT8(&base->umr, MCF5272_UART_UMR_8BNP);
229     HAL_WRITE_UINT8(&base->umr, MCF5272_UART_UMR_1S);
230
231     // Select a prescaled (by 1/16) CLKIN for the clock source
232     HAL_WRITE_UINT8(&base->usr_ucsr, MCF5272_UART_UCSR_CLKIN);
233
234     // Calculate baud settings
235     clk_div = (CYG_WORD16)
236               ((CYGHWR_HAL_SYSTEM_CLOCK_MHZ*1000000)/
237                (baud_rate * 32));
238     HAL_WRITE_UINT8(&base->udu, clk_div >> 8);
239     HAL_WRITE_UINT8(&base->udl, clk_div & 0x00ff);
240
241     // Enable the transmitter and receiver
242     HAL_WRITE_UINT8(&base->ucr, MCF5272_UART_UCR_TXRXEN);
243
244     // Set interrupt priority to highest maskable level
245     HAL_INTERRUPT_SET_LEVEL(port->vector, 6);
246 }
247
248
249 cyg_uint8 cyg_hal_plf_serial_getc(void* __ch_data)
250 {
251     cyg_uint8 ch;
252
253
254     while(!cyg_hal_plf_serial_getc_nonblock(__ch_data, &ch));
255
256     return ch;
257 }
258
259
260 void cyg_hal_plf_serial_putc(void *__ch_data, cyg_uint8 ch)
261 {
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;
266
267
268     // Loop until the transmit data holding register is empty
269     do
270     {
271         HAL_READ_UINT8(&base->usr_ucsr, usr_ucsr);
272     } while (!(usr_ucsr & MCF5272_UART_USR_TXRDY));
273
274     // Write the character to the transmit buffer
275     HAL_WRITE_UINT8(&base->urb_utb, ch);
276
277     // Loop until the transmit data FIFO and the shift register are empty
278     do
279     {
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)));
284 }
285
286 static void cyg_hal_plf_serial_write(void* __ch_data, const cyg_uint8* __buf, 
287                                      cyg_uint32 __len)
288 {
289     while(__len-- > 0)
290         cyg_hal_plf_serial_putc(__ch_data, *__buf++);
291 }
292
293
294 static void cyg_hal_plf_serial_read(void* __ch_data, cyg_uint8* __buf,
295                                     cyg_uint32 __len)
296 {
297     while(__len-- > 0)
298         *__buf++ = cyg_hal_plf_serial_getc(__ch_data);
299 }
300
301
302 static cyg_bool cyg_hal_plf_serial_getc_nonblock(void* __ch_data, cyg_uint8* ch)
303 {
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);
307     cyg_uint8 usr_ucsr;
308
309
310     // Read status
311     HAL_READ_UINT8(&base->usr_ucsr, usr_ucsr);
312
313     // Check if a character is present
314     if (usr_ucsr & MCF5272_UART_USR_RRDY)
315     {
316         // Read character
317         HAL_READ_UINT8(&base->urb_utb, *ch);
318         return true;
319     }
320
321     return false;
322 }
323
324
325 static cyg_bool cyg_hal_plf_serial_getc_timeout(void* __ch_data, cyg_uint8* ch)
326 {
327     int delay_count;
328     cyg_bool res;
329
330
331     delay_count = ((channel_data_t *)__ch_data)->msec_timeout;
332
333     for(;;) {
334         res = cyg_hal_plf_serial_getc_nonblock(__ch_data, ch);
335         if (res || 0 == delay_count--)
336             break;
337         
338         CYGACC_CALL_IF_DELAY_US(100);
339     }
340
341     return res;
342 }
343
344
345 static int cyg_hal_plf_serial_control(void *__ch_data,
346                                       __comm_control_cmd_t __func, ...)
347 {
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);
352     int ret = 0;
353
354
355     switch (__func) {
356     case __COMMCTL_IRQ_ENABLE:
357         irq_state = 1;
358
359         HAL_WRITE_UINT8(&base->uisr_uimr, MCF5272_UART_UIMR_FFULL);
360         HAL_INTERRUPT_UNMASK(port->vector);
361         break;
362     case __COMMCTL_IRQ_DISABLE:
363         ret = irq_state;
364         irq_state = 0;
365
366         HAL_INTERRUPT_MASK(port->vector);
367         HAL_WRITE_UINT8(&base->uisr_uimr, 0);
368         break;
369     case __COMMCTL_DBG_ISR_VECTOR:
370         ret = port->vector;
371         break;
372     case __COMMCTL_SET_TIMEOUT:
373     {
374         va_list ap;
375
376         va_start(ap, __func);
377
378         ret = port->msec_timeout;
379         port->msec_timeout = va_arg(ap, cyg_uint32);
380
381         va_end(ap);
382     }        
383     default:
384         break;
385     }
386
387     return ret;
388 }
389
390
391 static int cyg_hal_plf_serial_isr(void *__ch_data, int* __ctrlc, 
392                                   CYG_ADDRWORD __vector, CYG_ADDRWORD __data)
393 {
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);
397     char c;
398
399
400     // Disable the interrupt temporarily
401     HAL_WRITE_UINT8(&base->uisr_uimr, 0);
402
403     *__ctrlc = 0;
404
405     // Read character
406     HAL_READ_UINT8(&base->urb_utb, c);
407     if( cyg_hal_is_break( &c , 1 ) )
408     {
409         *__ctrlc = 1;
410     }
411
412     // Re-enable RxRDY interrupt
413     HAL_WRITE_UINT8(&base->uisr_uimr, MCF5272_UART_UIMR_FFULL);
414     
415     return CYG_ISR_HANDLED;
416 }