]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/hal/arm/sa11x0/var/v2_0/src/hal_diag.c
Initial revision
[karo-tx-redboot.git] / packages / hal / arm / sa11x0 / var / v2_0 / src / hal_diag.c
1 /*=============================================================================
2 //
3 //      hal_diag.c
4 //
5 //      HAL diagnostic output code
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 //
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.
16 //
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
20 // for more details.
21 //
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.
25 //
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.
32 //
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.
35 //
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 //=============================================================================
41 //#####DESCRIPTIONBEGIN####
42 //
43 // Author(s):   gthomas
44 // Contributors:nickg, gthomas, dmoseley
45 //              Travis C. Furrer <furrer@mit.edu>
46 // Date:        2000-05-08
47 // Purpose:     HAL diagnostic output
48 // Description: Implementations of HAL diagnostic output support.
49 //
50 //####DESCRIPTIONEND####
51 //
52 //===========================================================================*/
53
54 #include <pkgconf/hal.h>
55 #include <pkgconf/system.h>
56 #include CYGBLD_HAL_PLATFORM_H
57
58 #include <cyg/infra/cyg_type.h>         // base types
59 #include <cyg/infra/cyg_trac.h>         // tracing macros
60 #include <cyg/infra/cyg_ass.h>          // assertion macros
61
62 #include <cyg/hal/hal_arch.h>           // basic machine info
63 #include <cyg/hal/hal_intr.h>           // interrupt macros
64 #include <cyg/hal/hal_io.h>             // IO macros
65 #include <cyg/hal/hal_if.h>             // Calling interface definitions
66 #include <cyg/hal/hal_diag.h>
67 #include <cyg/hal/drv_api.h>            // cyg_drv_interrupt_acknowledge
68 #include <cyg/hal/hal_misc.h>           // Helper functions
69 #include <cyg/hal/hal_sa11x0.h>         // Hardware definitions
70
71 struct sa11x0_serial {
72   volatile cyg_uint32 utcr0;
73   volatile cyg_uint32 utcr1;
74   volatile cyg_uint32 utcr2;
75   volatile cyg_uint32 utcr3;
76   volatile cyg_uint32 pad0010;
77   volatile cyg_uint32 utdr;
78   volatile cyg_uint32 pad0018;
79   volatile cyg_uint32 utsr0;
80   volatile cyg_uint32 utsr1;
81 };
82
83 //-----------------------------------------------------------------------------
84 typedef struct {
85     volatile struct sa11x0_serial* base;
86     cyg_int32 msec_timeout;
87     int isr_vector;
88     int baud_rate;
89 } channel_data_t;
90
91 /*---------------------------------------------------------------------------*/
92 // SA11x0 Serial Port (UARTx) for Debug
93
94 static void
95 init_channel(channel_data_t* __ch_data)
96 {
97     volatile struct sa11x0_serial* base = __ch_data->base;
98     cyg_uint32 brd;
99
100     // Disable Receiver and Transmitter (clears FIFOs)
101     base->utcr3 = SA11X0_UART_RX_DISABLED | SA11X0_UART_TX_DISABLED;
102
103     // Clear sticky (writable) status bits.
104     base->utsr0 = SA11X0_UART_RX_IDLE | SA11X0_UART_RX_BEGIN_OF_BREAK |
105                   SA11X0_UART_RX_END_OF_BREAK;
106
107 #if defined(CYGPKG_HAL_ARM_SA11X0_SA1100MM) || defined(CYGPKG_HAL_ARM_SA11X0_BRUTUS)
108    // This setup is specific to only a few boards.
109    if (SA11X0_UART1_BASE == (volatile unsigned long *)base) {
110         cyg_uint32 pdr, afr, par;
111
112         HAL_READ_UINT32(SA11X0_GPIO_PIN_DIRECTION, pdr);
113         HAL_READ_UINT32(SA11X0_GPIO_ALTERNATE_FUNCTION, afr);
114         HAL_READ_UINT32(SA11X0_PPC_PIN_ASSIGNMENT, par);
115
116         //Set pin 14 as an output (Tx) and pin 15 as in input (Rx).
117         HAL_WRITE_UINT32(SA11X0_GPIO_PIN_DIRECTION, ((pdr | SA11X0_GPIO_PIN_14) & ~SA11X0_GPIO_PIN_15));
118
119         // Use GPIO 14 & 15 pins for serial port 1.
120         HAL_WRITE_UINT32(SA11X0_GPIO_ALTERNATE_FUNCTION, afr | SA11X0_GPIO_PIN_14 | SA11X0_GPIO_PIN_15);
121
122         // Pin reassignment for serial port 1.
123         HAL_WRITE_UINT32(SA11X0_PPC_PIN_ASSIGNMENT, par | SA11X0_PPC_UART_PIN_REASSIGNMENT_MASK);
124     }
125 #endif
126
127     // Set UART to 8N1 (8 data bits, no partity, 1 stop bit)
128     base->utcr0 = SA11X0_UART_PARITY_DISABLED | SA11X0_UART_STOP_BITS_1 |
129                   SA11X0_UART_DATA_BITS_8;
130
131     // Set the desired baud rate.
132     brd = SA11X0_UART_BAUD_RATE_DIVISOR(__ch_data->baud_rate);
133     base->utcr1 = (brd >> 8) & SA11X0_UART_H_BAUD_RATE_DIVISOR_MASK;
134     base->utcr2 = brd & SA11X0_UART_L_BAUD_RATE_DIVISOR_MASK;
135
136     // Enable the receiver and the transmitter.
137     base->utcr3 = SA11X0_UART_RX_ENABLED | SA11X0_UART_TX_ENABLED;
138
139     // All done
140 }
141
142 void
143 cyg_hal_plf_serial_putc(void *__ch_data, char c)
144 {
145     volatile struct sa11x0_serial* base = ((channel_data_t*)__ch_data)->base;
146     CYGARC_HAL_SAVE_GP();
147
148     // Wait for Tx FIFO not full
149     while ((base->utsr1 & SA11X0_UART_TX_FIFO_NOT_FULL) == 0)
150         ;
151     base->utdr = c;
152
153     CYGARC_HAL_RESTORE_GP();
154 }
155
156 // FIXME: shouldn't we check for PARITY_ERROR, FRAMING_ERROR, or
157 // RECEIVE_FIFO_OVERRUN_ERROR in the received data?  This
158 // means check the appropriate bits in UTSR1.
159
160 static cyg_bool
161 cyg_hal_plf_serial_getc_nonblock(void* __ch_data, cyg_uint8* ch)
162 {
163     volatile struct sa11x0_serial* base = ((channel_data_t*)__ch_data)->base;
164
165     // If receive fifo is empty, return false
166     if ((base->utsr1 & SA11X0_UART_RX_FIFO_NOT_EMPTY) == 0)
167         return false;
168
169     *ch = (char)base->utdr;
170
171     // Clear receiver idle status bit, to allow another interrupt to
172     // occur in the case where the receive fifo is almost empty.
173     base->utsr0 = SA11X0_UART_RX_IDLE;
174
175     return true;
176 }
177
178 cyg_uint8
179 cyg_hal_plf_serial_getc(void* __ch_data)
180 {
181     cyg_uint8 ch;
182     CYGARC_HAL_SAVE_GP();
183
184     while(!cyg_hal_plf_serial_getc_nonblock(__ch_data, &ch));
185
186     CYGARC_HAL_RESTORE_GP();
187     return ch;
188 }
189
190 static channel_data_t ser_channels[] = {
191 #if CYGHWR_HAL_ARM_SA11X0_UART1 != 0
192     { (volatile struct sa11x0_serial*)SA11X0_UART1_BASE, 1000, 
193       CYGNUM_HAL_INTERRUPT_UART1, CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL_BAUD },
194 #endif
195 #if CYGHWR_HAL_ARM_SA11X0_UART3 != 0
196     { (volatile struct sa11x0_serial*)SA11X0_UART3_BASE, 1000, 
197       CYGNUM_HAL_INTERRUPT_UART3, CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL_BAUD },
198 #endif
199 };
200
201 static void
202 cyg_hal_plf_serial_write(void* __ch_data, const cyg_uint8* __buf, 
203                          cyg_uint32 __len)
204 {
205     CYGARC_HAL_SAVE_GP();
206
207     while(__len-- > 0)
208         cyg_hal_plf_serial_putc(__ch_data, *__buf++);
209
210     CYGARC_HAL_RESTORE_GP();
211 }
212
213 static void
214 cyg_hal_plf_serial_read(void* __ch_data, cyg_uint8* __buf, cyg_uint32 __len)
215 {
216     CYGARC_HAL_SAVE_GP();
217
218     while(__len-- > 0)
219         *__buf++ = cyg_hal_plf_serial_getc(__ch_data);
220
221     CYGARC_HAL_RESTORE_GP();
222 }
223
224 cyg_bool
225 cyg_hal_plf_serial_getc_timeout(void* __ch_data, cyg_uint8* ch)
226 {
227     int delay_count;
228     channel_data_t* chan = (channel_data_t*)__ch_data;
229     cyg_bool res;
230     CYGARC_HAL_SAVE_GP();
231
232     delay_count = chan->msec_timeout * 10; // delay in .1 ms steps
233
234     for(;;) {
235         res = cyg_hal_plf_serial_getc_nonblock(__ch_data, ch);
236         if (res || 0 == delay_count--)
237             break;
238         
239         CYGACC_CALL_IF_DELAY_US(100);
240     }
241
242     CYGARC_HAL_RESTORE_GP();
243     return res;
244 }
245
246 static int
247 cyg_hal_plf_serial_control(void *__ch_data, __comm_control_cmd_t __func, ...)
248 {
249     static int irq_state = 0;
250     channel_data_t* chan = (channel_data_t*)__ch_data;
251     int ret = -1;
252     va_list ap;
253
254     CYGARC_HAL_SAVE_GP();
255     va_start(ap, __func);
256
257     switch (__func) {
258     case __COMMCTL_GETBAUD:
259         ret = chan->baud_rate;
260         break;
261     case __COMMCTL_SETBAUD:
262         chan->baud_rate = va_arg(ap, cyg_int32);
263         // Should we verify this value here?
264         init_channel(chan);
265         ret = 0;
266         break;
267     case __COMMCTL_IRQ_ENABLE:
268         irq_state = 1;
269
270         chan->base->utcr3 |= SA11X0_UART_RX_FIFO_INT_ENABLED;
271
272         HAL_INTERRUPT_UNMASK(chan->isr_vector);
273         break;
274     case __COMMCTL_IRQ_DISABLE:
275         ret = irq_state;
276         irq_state = 0;
277
278         chan->base->utcr3 &= ~SA11X0_UART_RX_FIFO_INT_ENABLED;
279
280         HAL_INTERRUPT_MASK(chan->isr_vector);
281         break;
282     case __COMMCTL_DBG_ISR_VECTOR:
283         ret = chan->isr_vector;
284         break;
285     case __COMMCTL_SET_TIMEOUT:
286         ret = chan->msec_timeout;
287         chan->msec_timeout = va_arg(ap, cyg_uint32);
288         break;
289     default:
290         break;
291     }
292     va_end(ap);
293     CYGARC_HAL_RESTORE_GP();
294     return ret;
295 }
296
297 static int
298 cyg_hal_plf_serial_isr(void *__ch_data, int* __ctrlc, 
299                        CYG_ADDRWORD __vector, CYG_ADDRWORD __data)
300 {
301     int res = 0;
302     channel_data_t* chan = (channel_data_t*)__ch_data;
303     char c;
304     int reg;
305     CYGARC_HAL_SAVE_GP();
306
307     reg = chan->base->utsr1;
308
309     // read it anyway just in case - no harm done and we might prevent an
310     // interrupt loop
311     c = (char)chan->base->utdr;
312
313     // Clear receiver idle status bit, to allow another interrupt to
314     // occur in the case where the receive fifo is almost empty.
315     // Also for a break interrupt; these are sticky and nonmaskable.
316     chan->base->utsr0 = (SA11X0_UART_RX_IDLE |
317                          SA11X0_UART_RX_BEGIN_OF_BREAK |
318                          SA11X0_UART_RX_END_OF_BREAK      );
319
320     cyg_drv_interrupt_acknowledge(chan->isr_vector);
321
322     *__ctrlc = 0;
323     if ( (reg & SA11X0_UART_RX_FIFO_NOT_EMPTY) != 0 ) {
324         if( cyg_hal_is_break( &c , 1 ) )
325             *__ctrlc = 1;
326
327         res = CYG_ISR_HANDLED;
328     }
329
330     CYGARC_HAL_RESTORE_GP();
331     return res;
332 }
333
334 static void
335 cyg_hal_plf_serial_init(void)
336 {
337     hal_virtual_comm_table_t* comm;
338     int cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
339     int i;
340
341     // Init channels
342 #define NUMOF(x) (sizeof(x)/sizeof(x[0]))
343     for (i = 0;  i < NUMOF(ser_channels);  i++) {
344         init_channel(&ser_channels[i]);
345         CYGACC_CALL_IF_SET_CONSOLE_COMM(i);
346         comm = CYGACC_CALL_IF_CONSOLE_PROCS();
347         CYGACC_COMM_IF_CH_DATA_SET(*comm, &ser_channels[i]);
348         CYGACC_COMM_IF_WRITE_SET(*comm, cyg_hal_plf_serial_write);
349         CYGACC_COMM_IF_READ_SET(*comm, cyg_hal_plf_serial_read);
350         CYGACC_COMM_IF_PUTC_SET(*comm, cyg_hal_plf_serial_putc);
351         CYGACC_COMM_IF_GETC_SET(*comm, cyg_hal_plf_serial_getc);
352         CYGACC_COMM_IF_CONTROL_SET(*comm, cyg_hal_plf_serial_control);
353         CYGACC_COMM_IF_DBG_ISR_SET(*comm, cyg_hal_plf_serial_isr);
354         CYGACC_COMM_IF_GETC_TIMEOUT_SET(*comm, cyg_hal_plf_serial_getc_timeout);
355     }
356      
357     // Restore original console
358     CYGACC_CALL_IF_SET_CONSOLE_COMM(cur);
359 }
360
361 void
362 cyg_hal_plf_comms_init(void)
363 {
364     static int initialized = 0;
365
366     if (initialized)
367         return;
368
369     initialized = 1;
370
371     cyg_hal_plf_serial_init();
372 }
373
374 //=============================================================================
375 // Compatibility with older stubs
376 //=============================================================================
377
378 #ifndef CYGSEM_HAL_VIRTUAL_VECTOR_DIAG
379
380 #include <cyg/hal/hal_stub.h>           // cyg_hal_gdb_interrupt
381
382 #if (CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL == 0)
383 # define __BASE ((void*)SA11X0_UART1_BASE)
384 # define CYGHWR_HAL_GDB_PORT_VECTOR CYGNUM_HAL_INTERRUPT_UART1
385 #else
386 # define __BASE ((void*)SA11X0_UART3_BASE)
387 # define CYGHWR_HAL_GDB_PORT_VECTOR CYGNUM_HAL_INTERRUPT_UART3
388 #endif
389
390 #ifdef CYGSEM_HAL_ROM_MONITOR
391 #define CYG_HAL_STARTUP_ROM
392 #undef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
393 #endif
394
395 #if defined(CYG_HAL_STARTUP_ROM) && !defined(CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS)
396 #define HAL_DIAG_USES_HARDWARE
397 #elif !defined(CYGDBG_HAL_DIAG_TO_DEBUG_CHAN)
398 #define HAL_DIAG_USES_HARDWARE
399 #elif CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL != CYGNUM_HAL_VIRTUAL_VECTOR_DEBUG_CHANNEL
400 #define HAL_DIAG_USES_HARDWARE
401 #endif
402
403 static channel_data_t ser_channel = {
404     (volatile struct sa11x0_serial*)__BASE, 0, CYGHWR_HAL_GDB_PORT_VECTOR
405 };
406
407 void 
408 hal_diag_init(void)
409 {
410     // Init serial device
411     init_channel(&ser_channel);
412 }
413
414 #ifdef HAL_DIAG_USES_HARDWARE
415
416 #ifdef DEBUG_DIAG
417 #ifndef CYG_HAL_STARTUP_ROM
418 #define DIAG_BUFSIZE 2048
419 static char diag_buffer[DIAG_BUFSIZE];
420 static int diag_bp = 0;
421 #endif
422 #endif
423
424 void hal_diag_read_char(char *c)
425 {
426     *c = cyg_hal_plf_serial_getc(&ser_channel);
427 }
428
429 void hal_diag_write_char(char c)
430 {
431 #ifdef DEBUG_DIAG
432 #ifndef CYG_HAL_STARTUP_ROM
433     diag_buffer[diag_bp++] = c;
434     if (diag_bp == sizeof(diag_buffer)) diag_bp = 0;
435 #endif
436 #endif
437     cyg_hal_plf_serial_putc(&ser_channel, c);
438 }
439
440 #else // not HAL_DIAG_USES_HARDWARE - it uses GDB protocol
441
442 void 
443 hal_diag_read_char(char *c)
444 {
445     *c = cyg_hal_plf_serial_getc(&ser_channel);
446 }
447
448 void 
449 hal_diag_write_char(char c)
450 {
451     static char line[100];
452     static int pos = 0;
453
454     // FIXME: Some LED blinking might be nice right here.
455
456     // No need to send CRs
457     if( c == '\r' ) return;
458
459     line[pos++] = c;
460
461     if( c == '\n' || pos == sizeof(line) )
462     {
463         
464         CYG_INTERRUPT_STATE old;
465
466         // Disable interrupts. This prevents GDB trying to interrupt us
467         // while we are in the middle of sending a packet. The serial
468         // receive interrupt will be seen when we re-enable interrupts
469         // later.
470         
471 #ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
472         CYG_HAL_GDB_ENTER_CRITICAL_IO_REGION(old);
473 #else
474         HAL_DISABLE_INTERRUPTS(old);
475 #endif
476
477         while(1)
478         {
479             static char hex[] = "0123456789ABCDEF";
480             cyg_uint8 csum = 0;
481             int i;
482 #ifndef CYGDBG_HAL_DEBUG_GDB_CTRLC_SUPPORT
483             char c1;
484 #endif        
485             cyg_hal_plf_serial_putc(&ser_channel, '$');
486             cyg_hal_plf_serial_putc(&ser_channel, 'O');
487             csum += 'O';
488             for( i = 0; i < pos; i++ )
489             {
490                 char ch = line[i];
491                 char h = hex[(ch>>4)&0xF];
492                 char l = hex[ch&0xF];
493                 cyg_hal_plf_serial_putc(&ser_channel, h);
494                 cyg_hal_plf_serial_putc(&ser_channel, l);
495                 csum += h;
496                 csum += l;
497             }
498             cyg_hal_plf_serial_putc(&ser_channel, '#');
499             cyg_hal_plf_serial_putc(&ser_channel, hex[(csum>>4)&0xF]);
500             cyg_hal_plf_serial_putc(&ser_channel, hex[csum&0xF]);
501
502 #ifdef CYGDBG_HAL_DEBUG_GDB_CTRLC_SUPPORT
503
504             break; // regardless
505
506 #else // not CYGDBG_HAL_DEBUG_GDB_CTRLC_SUPPORT Ie. usually...
507
508             // Wait for the ACK character '+' from GDB here and handle
509             // receiving a ^C instead.  This is the reason for this clause
510             // being a loop.
511             c1 = cyg_hal_plf_serial_getc(&ser_channel);
512
513             if( c1 == '+' )
514                 break;              // a good acknowledge
515
516 #ifdef CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT
517             cyg_drv_interrupt_acknowledge(CYGHWR_HAL_GDB_PORT_VECTOR);
518             if( c1 == 3 ) {
519                 // Ctrl-C: breakpoint.
520                 cyg_hal_gdb_interrupt(
521                     (target_register_t)__builtin_return_address(0) );
522                 break;
523             }
524 #endif // CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT
525
526 #endif // ! CYGDBG_HAL_DEBUG_GDB_CTRLC_SUPPORT
527             // otherwise, loop round again
528         }
529         
530         pos = 0;
531
532         
533         // And re-enable interrupts
534 #ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
535         CYG_HAL_GDB_LEAVE_CRITICAL_IO_REGION(old);
536 #else
537         HAL_RESTORE_INTERRUPTS(old);
538 #endif
539         
540     }
541 }
542 #endif
543
544 #endif // !CYGSEM_HAL_VIRTUAL_VECTOR_DIAG
545
546
547 /*---------------------------------------------------------------------------*/
548 /* End of hal_diag.c */