]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/hal/arm/ebsa285/v2_0/src/hal_diag.c
Initial revision
[karo-tx-redboot.git] / packages / hal / arm / ebsa285 / 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):   nickg, gthomas
44 // Contributors:nickg, gthomas
45 // Date:        1998-03-02
46 // Purpose:     HAL diagnostic output
47 // Description: Implementations of HAL diagnostic output support.
48 //
49 //####DESCRIPTIONEND####
50 //
51 //===========================================================================*/
52
53 #include <pkgconf/hal.h>
54 #include <pkgconf/system.h>
55 #include CYGBLD_HAL_PLATFORM_H
56
57 #include <cyg/infra/cyg_type.h>         // base types
58 #include <cyg/infra/cyg_trac.h>         // tracing macros
59 #include <cyg/infra/cyg_ass.h>          // assertion macros
60
61 #include <cyg/hal/hal_arch.h>           // basic machine info
62 #include <cyg/hal/hal_intr.h>           // interrupt macros
63 #include <cyg/hal/hal_io.h>             // IO macros
64 #include <cyg/hal/hal_if.h>             // calling interface API
65 #include <cyg/hal/hal_misc.h>           // helper functions
66 #include <cyg/hal/hal_diag.h>
67 #include <cyg/hal/hal_ebsa285.h>        // Hardware definitions
68 #include <cyg/hal/drv_api.h>            // cyg_drv_interrupt_acknowledge
69
70 /*---------------------------------------------------------------------------*/
71
72 struct ebsa_serial {
73   volatile cyg_uint32 data_register;
74   volatile cyg_uint32 rxstat;
75   volatile cyg_uint32 h_baud_control;
76   volatile cyg_uint32 m_baud_control;
77   volatile cyg_uint32 l_baud_control;
78   volatile cyg_uint32 control_register;
79   volatile cyg_uint32 flag_register;
80 };
81
82 /*---------------------------------------------------------------------------*/
83
84 static void
85 init_channel(void* __ch_data)
86 {
87     volatile struct ebsa_serial* base = (struct ebsa_serial*)__ch_data;
88
89     int dummy;
90     /*
91      * Make sure everything is off
92      */
93     base->control_register = SA110_UART_DISABLED | SA110_SIR_DISABLED;
94     
95     /*
96      * Read the RXStat to drain the fifo
97      */
98     dummy = base->rxstat;
99
100     /*
101      * Set the baud rate - this also turns the uart on.
102      *
103      * Note that the ordering of these writes is critical,
104      * and the writes to the H_BAUD_CONTROL and CONTROL_REGISTER
105      * are necessary to force the UART to update its register
106      * contents.
107      */
108     base->l_baud_control   = 0x13; // bp->divisor_low;
109     base->m_baud_control   = 0x00; // bp->divisor_high;
110     base->h_baud_control = SA110_UART_BREAK_DISABLED    |
111         SA110_UART_PARITY_DISABLED   |
112         SA110_UART_STOP_BITS_ONE     |
113         SA110_UART_FIFO_ENABLED      |
114         SA110_UART_DATA_LENGTH_8_BITS;
115     base->control_register = SA110_UART_ENABLED | SA110_SIR_DISABLED;
116     // All done
117 }
118
119 void
120 cyg_hal_plf_serial_putc(void *__ch_data, char c)
121 {
122     volatile struct ebsa_serial* base = (struct ebsa_serial*)__ch_data;
123     CYGARC_HAL_SAVE_GP();
124
125     // Wait for Tx FIFO not full
126     while ((base->flag_register & SA110_TX_FIFO_STATUS_MASK) == SA110_TX_FIFO_BUSY)
127         ;
128     base->data_register = c;
129
130     CYGARC_HAL_RESTORE_GP();
131 }
132
133
134 static cyg_bool
135 cyg_hal_plf_serial_getc_nonblock(void* __ch_data, cyg_uint8* ch)
136 {
137     volatile struct ebsa_serial* base = (struct ebsa_serial*)__ch_data;
138
139
140     if ((base->flag_register & SA110_RX_FIFO_STATUS_MASK) == SA110_RX_FIFO_EMPTY)
141         return false;
142
143     *ch = (char)(base->data_register & 0xFF);
144
145     return true;
146 }
147
148
149 cyg_uint8
150 cyg_hal_plf_serial_getc(void* __ch_data)
151 {
152     cyg_uint8 ch;
153     CYGARC_HAL_SAVE_GP();
154
155     while(!cyg_hal_plf_serial_getc_nonblock(__ch_data, &ch));
156
157     CYGARC_HAL_RESTORE_GP();
158     return ch;
159 }
160
161 static cyg_int32 msec_timeout;
162
163 static void
164 cyg_hal_plf_serial_write(void* __ch_data, const cyg_uint8* __buf, 
165                          cyg_uint32 __len)
166 {
167     CYGARC_HAL_SAVE_GP();
168
169     while(__len-- > 0)
170         cyg_hal_plf_serial_putc(__ch_data, *__buf++);
171
172     CYGARC_HAL_RESTORE_GP();
173 }
174
175 static void
176 cyg_hal_plf_serial_read(void* __ch_data, cyg_uint8* __buf, cyg_uint32 __len)
177 {
178     CYGARC_HAL_SAVE_GP();
179
180     while(__len-- > 0)
181         *__buf++ = cyg_hal_plf_serial_getc(__ch_data);
182
183     CYGARC_HAL_RESTORE_GP();
184 }
185
186 cyg_bool
187 cyg_hal_plf_serial_getc_timeout(void* __ch_data, cyg_uint8* ch)
188 {
189     int delay_count;
190     cyg_bool res;
191     CYGARC_HAL_SAVE_GP();
192
193     delay_count = msec_timeout * 10; // delay in .1 ms steps
194
195     for(;;) {
196         res = cyg_hal_plf_serial_getc_nonblock(__ch_data, ch);
197         if (res || 0 == delay_count--)
198             break;
199         
200         CYGACC_CALL_IF_DELAY_US(100);
201     }
202
203     CYGARC_HAL_RESTORE_GP();
204     return res;
205 }
206
207 static int
208 cyg_hal_plf_serial_control(void *__ch_data, __comm_control_cmd_t __func, ...)
209 {
210     static int irq_state = 0;
211     int ret = 0;
212     CYGARC_HAL_SAVE_GP();
213
214     switch (__func) {
215     case __COMMCTL_IRQ_ENABLE:
216         irq_state = 1;
217
218         HAL_INTERRUPT_UNMASK(CYGNUM_HAL_INTERRUPT_SERIAL_RX);
219         break;
220     case __COMMCTL_IRQ_DISABLE:
221         ret = irq_state;
222         irq_state = 0;
223
224         HAL_INTERRUPT_MASK(CYGNUM_HAL_INTERRUPT_SERIAL_RX);
225         break;
226     case __COMMCTL_DBG_ISR_VECTOR:
227         ret = CYGNUM_HAL_INTERRUPT_SERIAL_RX;
228         break;
229     case __COMMCTL_SET_TIMEOUT:
230     {
231         va_list ap;
232
233         va_start(ap, __func);
234
235         ret = msec_timeout;
236         msec_timeout = va_arg(ap, cyg_uint32);
237
238         va_end(ap);
239     }        
240     default:
241         break;
242     }
243     CYGARC_HAL_RESTORE_GP();
244     return ret;
245 }
246
247 static int
248 cyg_hal_plf_serial_isr(void *__ch_data, int* __ctrlc, 
249                        CYG_ADDRWORD __vector, CYG_ADDRWORD __data)
250 {
251     int reg, res = 0;
252     volatile struct ebsa_serial* base = (struct ebsa_serial*)__ch_data;
253     char c;
254     CYGARC_HAL_SAVE_GP();
255
256     if ( CYGNUM_HAL_INTERRUPT_SERIAL_RX == __vector ) {
257         reg = base->flag_register;
258         // read it anyway just in case - no harm done and we might
259         // prevent an interrup loop
260         c = (char)(base->data_register & 0xFF);
261
262         cyg_drv_interrupt_acknowledge(CYGNUM_HAL_INTERRUPT_SERIAL_RX);
263         *__ctrlc = 0;
264         if ( (reg & SA110_RX_FIFO_STATUS_MASK) != SA110_RX_FIFO_EMPTY ) {
265             if( cyg_hal_is_break( &c , 1 ) )
266                 *__ctrlc = 1;
267             
268         }
269         res = CYG_ISR_HANDLED;
270     }
271
272     CYGARC_HAL_RESTORE_GP();
273     return res;
274 }
275
276 static void
277 cyg_hal_plf_serial_init(void)
278 {
279     hal_virtual_comm_table_t* comm;
280     int cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
281
282     // Init channels
283     init_channel((void*)UART_BASE_0);
284
285     // Setup procs in the vector table
286
287     // Set channel 0
288     CYGACC_CALL_IF_SET_CONSOLE_COMM(0);
289     comm = CYGACC_CALL_IF_CONSOLE_PROCS();
290     CYGACC_COMM_IF_CH_DATA_SET(*comm, UART_BASE_0);
291     CYGACC_COMM_IF_WRITE_SET(*comm, cyg_hal_plf_serial_write);
292     CYGACC_COMM_IF_READ_SET(*comm, cyg_hal_plf_serial_read);
293     CYGACC_COMM_IF_PUTC_SET(*comm, cyg_hal_plf_serial_putc);
294     CYGACC_COMM_IF_GETC_SET(*comm, cyg_hal_plf_serial_getc);
295     CYGACC_COMM_IF_CONTROL_SET(*comm, cyg_hal_plf_serial_control);
296     CYGACC_COMM_IF_DBG_ISR_SET(*comm, cyg_hal_plf_serial_isr);
297     CYGACC_COMM_IF_GETC_TIMEOUT_SET(*comm, cyg_hal_plf_serial_getc_timeout);
298
299     // Restore original console
300     CYGACC_CALL_IF_SET_CONSOLE_COMM(cur);
301 }
302
303 void
304 cyg_hal_plf_comms_init(void)
305 {
306     static int initialized = 0;
307
308     if (initialized)
309         return;
310
311     initialized = 1;
312
313     cyg_hal_plf_serial_init();
314 }
315
316
317 //=============================================================================
318 // Compatibility with older stubs
319 //=============================================================================
320
321 #ifndef CYGSEM_HAL_VIRTUAL_VECTOR_DIAG
322
323 #ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
324 #include <cyg/hal/hal_stub.h>           // cyg_hal_gdb_interrupt
325 #endif
326
327 #ifdef CYGSEM_HAL_ROM_MONITOR
328 #define CYG_HAL_STARTUP_ROM
329 #undef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
330 #endif
331
332 #if defined(CYG_HAL_STARTUP_ROM) || !defined(CYGDBG_HAL_DIAG_TO_DEBUG_CHAN)
333 #define HAL_DIAG_USES_HARDWARE
334 #endif
335
336 /*---------------------------------------------------------------------------*/
337 // EBSA285 Serial Port (UARTx) for Debug
338
339 void hal_diag_init(void)
340 {
341   init_channel((void*)UART_BASE_0);
342 }
343
344
345 // Actually send character down the wire
346 static void
347 hal_diag_write_char_serial(char c)
348 {
349     cyg_hal_plf_serial_putc((void*)UART_BASE_0, c);
350 }
351
352 static bool
353 hal_diag_read_serial(char *c)
354 {
355     long timeout = 1000000000;  // A long time...
356     while (! cyg_hal_plf_serial_getc_nonblock((void*)UART_BASE_0, c) )
357         if ( --timeout == 0 ) return false;
358
359     return true;
360 }
361
362 /*
363  * Baud rate selection stuff
364  */
365 #if 0
366 struct _baud {
367     int baud;
368     unsigned short divisor_high, divisor_low;
369 };
370
371 const static struct _baud bauds[] = {
372 #if (FCLK_MHZ == 50)
373     {   300, 0xA, 0x2B},                  /* 2603  = 0x0A2B */
374     {   600, 0x5, 0x15},                  /* 1301  = 0x0515 */
375     {  1200, 0x2, 0x8A},                  /* 650   = 0x028A */
376     {  2400, 0x1, 0x45},                  /* 325   = 0x0145 */
377     {  4800, 0x0, 0xA2},                  /* 162   = 0x00A2 */
378     {  9600, 0x0, 0x50},                  /* 80    = 0x0050 */
379     { 19200, 0x0, 0x28},                  /* 40    = 0x0028 */
380     { 38400, 0x0, 0x13},                  /* 19    = 0x0013 */
381 #elif (FCLK_MHZ == 60)
382     {   300, 0xC, 0x34},                  /* 2603  = 0x0A2B */
383     {   600, 0x6, 0x19},                  /* 1301  = 0x0515 */
384     {  1200, 0x3, 0x0C},                  /* 650   = 0x028A */
385     {  2400, 0x1, 0x86},                  /* 325   = 0x0145 */
386     {  4800, 0x0, 0xC2},                  /* 162   = 0x00A2 */
387     {  9600, 0x0, 0x61},                  /* 80    = 0x0050 */
388     { 19200, 0x0, 0x30},                  /* 40    = 0x0028 */
389     { 38400, 0x0, 0x17},                  /* 19    = 0x0013 */
390 #endif
391 };
392 #endif
393
394 #ifdef HAL_DIAG_USES_HARDWARE
395
396 #ifdef DEBUG_DIAG
397 #ifndef CYG_HAL_STARTUP_ROM
398 #define DIAG_BUFSIZE 2048
399 static char diag_buffer[DIAG_BUFSIZE];
400 static int diag_bp = 0;
401 #endif
402 #endif
403
404 void hal_diag_read_char(char *c)
405 {
406     while (!hal_diag_read_serial(c)) ;
407 }
408
409 void hal_diag_write_char(char c)
410 {
411 #ifdef DEBUG_DIAG
412 #ifndef CYG_HAL_STARTUP_ROM
413     diag_buffer[diag_bp++] = c;
414     if (diag_bp == sizeof(diag_buffer)) diag_bp = 0;
415 #endif
416 #endif
417     hal_diag_write_char_serial(c);
418 }
419
420 #else // not HAL_DIAG_USES_HARDWARE - it uses GDB protocol
421
422 void 
423 hal_diag_read_char(char *c)
424 {
425     while (!hal_diag_read_serial(c)) ;
426 }
427
428 void 
429 hal_diag_write_char(char c)
430 {
431     static char line[100];
432     static int pos = 0;
433
434 #if 0
435     // Do not unconditionally poke the XBUS LED location - XBUS may not be
436     // available if external arbiter is in use.  This fragment may still be
437     // useful for debugging in the future, so left thus:
438     {
439 //        int i;
440         *(cyg_uint32 *)0x40012000 = 7 & (cyg_uint32)c; // LED XBUS location
441 //        for ( i = 0x1000000; i > 0; i-- ) ;
442     }
443 #endif
444
445     // No need to send CRs
446     if( c == '\r' ) return;
447
448     line[pos++] = c;
449
450     if( c == '\n' || pos == sizeof(line) )
451     {
452         
453         CYG_INTERRUPT_STATE old;
454
455         // Disable interrupts. This prevents GDB trying to interrupt us
456         // while we are in the middle of sending a packet. The serial
457         // receive interrupt will be seen when we re-enable interrupts
458         // later.
459         
460 #ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
461         CYG_HAL_GDB_ENTER_CRITICAL_IO_REGION(old);
462 #else
463         HAL_DISABLE_INTERRUPTS(old);
464 #endif
465
466         while(1)
467         {
468             static char hex[] = "0123456789ABCDEF";
469             cyg_uint8 csum = 0;
470             int i;
471 #ifndef CYGDBG_HAL_DEBUG_GDB_CTRLC_SUPPORT
472             char c1;
473 #endif        
474             hal_diag_write_char_serial('$');
475             hal_diag_write_char_serial('O');
476             csum += 'O';
477             for( i = 0; i < pos; i++ )
478             {
479                 char ch = line[i];
480                 char h = hex[(ch>>4)&0xF];
481                 char l = hex[ch&0xF];
482                 hal_diag_write_char_serial(h);
483                 hal_diag_write_char_serial(l);
484                 csum += h;
485                 csum += l;
486             }
487             hal_diag_write_char_serial('#');
488             hal_diag_write_char_serial(hex[(csum>>4)&0xF]);
489             hal_diag_write_char_serial(hex[csum&0xF]);
490
491 #ifdef CYGDBG_HAL_DEBUG_GDB_CTRLC_SUPPORT
492
493             break; // regardless
494
495 #else // not CYGDBG_HAL_DEBUG_GDB_CTRLC_SUPPORT Ie. usually...
496
497             // Wait for the ACK character '+' from GDB here and handle
498             // receiving a ^C instead.  This is the reason for this clause
499             // being a loop.
500             if (!hal_diag_read_serial(&c1))
501                 continue;   // No response - try sending packet again
502
503             if( c1 == '+' )
504                 break;              // a good acknowledge
505
506 #ifdef CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT
507             cyg_drv_interrupt_acknowledge(CYGNUM_HAL_INTERRUPT_SERIAL_RX);
508             if( c1 == 3 ) {
509                 // Ctrl-C: breakpoint.
510                 cyg_hal_gdb_interrupt(
511                     (target_register_t)__builtin_return_address(0) );
512                 break;
513             }
514 #endif // CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT
515
516 #endif // ! CYGDBG_HAL_DEBUG_GDB_CTRLC_SUPPORT
517             // otherwise, loop round again
518         }
519         
520         pos = 0;
521
522         
523         // And re-enable interrupts
524 #ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
525         CYG_HAL_GDB_LEAVE_CRITICAL_IO_REGION(old);
526 #else
527         HAL_RESTORE_INTERRUPTS(old);
528 #endif
529         
530     }
531 }
532 #endif
533
534 #endif // !CYGSEM_HAL_VIRTUAL_VECTOR_DIAG
535
536 /*---------------------------------------------------------------------------*/
537 /* End of hal_diag.c */