]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/hal/arm/edb7xxx/v2_0/src/hal_diag.c
Initial revision
[karo-tx-redboot.git] / packages / hal / arm / edb7xxx / 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/drv_api.h>
68 #include <cyg/hal/hal_edb7xxx.h>         // Hardware definitions
69
70 //-----------------------------------------------------------------------------
71
72 struct edb_serial {
73     volatile cyg_uint32 ctrl;
74     cyg_uint32 pad004_040[16-1];
75     volatile cyg_uint32 stat;
76     cyg_uint32 pad044_37c[208-1];
77     union {
78         volatile cyg_uint8 write;
79         volatile cyg_uint32 read;    // Need to read 32 bits
80     } data;
81     cyg_uint32 pad384_3BC[16-1];
82     volatile cyg_uint32 blcr;
83 };
84
85 //-----------------------------------------------------------------------------
86 typedef struct {
87     volatile struct edb_serial* base;
88     cyg_int32 msec_timeout;
89     int isr_vector;
90     int baud_rate;      
91 } channel_data_t;
92
93 //-----------------------------------------------------------------------------
94
95 static void
96 cyg_hal_plf_serial_init_channel(channel_data_t* __ch_data)
97 {
98     channel_data_t* chan = (channel_data_t*)__ch_data;
99
100     // Enable port
101     chan->base->ctrl |= SYSCON1_UART1EN;
102     // Configure
103     chan->base->blcr = UART_BITRATE(chan->baud_rate) |
104                        UBLCR_FIFOEN | UBLCR_WRDLEN8;
105 }
106
107
108 // Call this delay function when polling for serial access - otherwise
109 // the CPU will keep the memory bus busy and thus prevent DRAM refresh
110 // (and the resulting memory corruption).
111 externC void dram_delay_loop(void);
112
113 void
114 cyg_hal_plf_serial_putc(void *__ch_data, char c)
115 {
116     channel_data_t* chan = (channel_data_t*)__ch_data;
117
118     CYGARC_HAL_SAVE_GP();
119
120     // Wait for Tx FIFO not full
121     while ((chan->base->stat & SYSFLG1_UTXFF1) != 0) ;
122
123     chan->base->data.write = c;
124
125     CYGARC_HAL_RESTORE_GP();
126 }
127
128 static cyg_bool
129 cyg_hal_plf_serial_getc_nonblock(void* __ch_data, cyg_uint8* ch)
130 {
131     channel_data_t* chan = (channel_data_t*)__ch_data;
132
133     if ((chan->base->stat & SYSFLG1_URXFE1) != 0)
134         return false;
135
136     *ch = (cyg_uint8)(chan->base->data.read & 0xFF);
137
138     return true;
139 }
140
141 cyg_uint8
142 cyg_hal_plf_serial_getc(void* __ch_data)
143 {
144     cyg_uint8 ch;
145     int delay_timer = 0;
146
147     CYGARC_HAL_SAVE_GP();
148
149     while(!cyg_hal_plf_serial_getc_nonblock(__ch_data, &ch)) {
150         CYGACC_CALL_IF_DELAY_US(50);  // A reasonable time
151         // Only delay every 10ms or so
152         if (++delay_timer == 10*20) {
153             dram_delay_loop();
154             delay_timer = 0;
155         }
156     }
157
158     CYGARC_HAL_RESTORE_GP();
159     return ch;
160 }
161
162 static channel_data_t edb_ser_channels[2] = {
163     {(volatile struct edb_serial*)SYSCON1, 1000, CYGNUM_HAL_INTERRUPT_URXINT1, CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL_BAUD},
164     {(volatile struct edb_serial*)SYSCON2, 1000, CYGNUM_HAL_INTERRUPT_URXINT2, CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL_BAUD}
165 };
166
167 static void
168 cyg_hal_plf_serial_write(void* __ch_data, const cyg_uint8* __buf, 
169                          cyg_uint32 __len)
170 {
171     CYGARC_HAL_SAVE_GP();
172
173     while(__len-- > 0)
174         cyg_hal_plf_serial_putc(__ch_data, *__buf++);
175
176     CYGARC_HAL_RESTORE_GP();
177 }
178
179 static void
180 cyg_hal_plf_serial_read(void* __ch_data, cyg_uint8* __buf, cyg_uint32 __len)
181 {
182     CYGARC_HAL_SAVE_GP();
183
184     while(__len-- > 0)
185         *__buf++ = cyg_hal_plf_serial_getc(__ch_data);
186
187     CYGARC_HAL_RESTORE_GP();
188 }
189
190 cyg_bool
191 cyg_hal_plf_serial_getc_timeout(void* __ch_data, cyg_uint8* ch)
192 {
193     int delay_count;
194     channel_data_t* chan = (channel_data_t*)__ch_data;
195     cyg_bool res;
196     CYGARC_HAL_SAVE_GP();
197
198     delay_count = chan->msec_timeout * 10; // delay in .1 ms steps
199
200     for(;;) {
201         res = cyg_hal_plf_serial_getc_nonblock(__ch_data, ch);
202         if (res || 0 == delay_count--)
203             break;
204         
205         CYGACC_CALL_IF_DELAY_US(100);
206     }
207
208     CYGARC_HAL_RESTORE_GP();
209     return res;
210 }
211
212 static int
213 cyg_hal_plf_serial_control(void *__ch_data, __comm_control_cmd_t __func, ...)
214 {
215     static int irq_state = 0;
216     channel_data_t* chan = (channel_data_t*)__ch_data;
217     int ret = 0;
218     va_list ap;
219
220     CYGARC_HAL_SAVE_GP();
221     va_start(ap, __func);
222
223     switch (__func) {
224     case __COMMCTL_GETBAUD:
225         ret = chan->baud_rate;
226         break;
227     case __COMMCTL_SETBAUD:
228         chan->baud_rate = va_arg(ap, cyg_int32);
229         // Should we verify this value here?
230         cyg_hal_plf_serial_init_channel(chan);
231         ret = 0;
232         break;
233
234     case __COMMCTL_IRQ_ENABLE:
235         irq_state = 1;
236         HAL_INTERRUPT_UNMASK(chan->isr_vector);
237         break;
238     case __COMMCTL_IRQ_DISABLE:
239         ret = irq_state;
240         irq_state = 0;
241         HAL_INTERRUPT_MASK(chan->isr_vector);
242         break;
243     case __COMMCTL_DBG_ISR_VECTOR:
244         ret = chan->isr_vector;
245         break;
246     case __COMMCTL_SET_TIMEOUT:
247     {
248         va_list ap;
249
250         va_start(ap, __func);
251
252         ret = chan->msec_timeout;
253         chan->msec_timeout = va_arg(ap, cyg_uint32);
254
255         va_end(ap);
256     }        
257     default:
258         break;
259     }
260
261     va_end(ap);
262     CYGARC_HAL_RESTORE_GP();
263     return ret;
264 }
265
266 static int
267 cyg_hal_plf_serial_isr(void *__ch_data, int* __ctrlc, 
268                        CYG_ADDRWORD __vector, CYG_ADDRWORD __data)
269 {
270     int res = 0;
271     channel_data_t* chan = (channel_data_t*)__ch_data;
272     char c;
273     CYGARC_HAL_SAVE_GP();
274
275     cyg_drv_interrupt_acknowledge(chan->isr_vector);
276
277     *__ctrlc = 0;
278     if ((chan->base->stat & SYSFLG1_URXFE1) == 0) {
279         c = (cyg_uint8)(chan->base->data.read & 0xFF);
280         if( cyg_hal_is_break( &c , 1 ) )
281             *__ctrlc = 1;
282
283         res = CYG_ISR_HANDLED;
284     }
285
286     CYGARC_HAL_RESTORE_GP();
287     return res;
288 }
289
290 static void
291 cyg_hal_plf_serial_init(void)
292 {
293     hal_virtual_comm_table_t* comm;
294     int cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
295
296     // Disable interrupts.
297     HAL_INTERRUPT_MASK(edb_ser_channels[0].isr_vector);
298     HAL_INTERRUPT_MASK(edb_ser_channels[1].isr_vector);
299
300     // Init channels
301     cyg_hal_plf_serial_init_channel(&edb_ser_channels[0]);
302     cyg_hal_plf_serial_init_channel(&edb_ser_channels[1]);
303
304     // Setup procs in the vector table
305
306     // Set channel 0
307     CYGACC_CALL_IF_SET_CONSOLE_COMM(0);
308     comm = CYGACC_CALL_IF_CONSOLE_PROCS();
309     CYGACC_COMM_IF_CH_DATA_SET(*comm, &edb_ser_channels[0]);
310     CYGACC_COMM_IF_WRITE_SET(*comm, cyg_hal_plf_serial_write);
311     CYGACC_COMM_IF_READ_SET(*comm, cyg_hal_plf_serial_read);
312     CYGACC_COMM_IF_PUTC_SET(*comm, cyg_hal_plf_serial_putc);
313     CYGACC_COMM_IF_GETC_SET(*comm, cyg_hal_plf_serial_getc);
314     CYGACC_COMM_IF_CONTROL_SET(*comm, cyg_hal_plf_serial_control);
315     CYGACC_COMM_IF_DBG_ISR_SET(*comm, cyg_hal_plf_serial_isr);
316     CYGACC_COMM_IF_GETC_TIMEOUT_SET(*comm, cyg_hal_plf_serial_getc_timeout);
317
318     // Set channel 1
319     CYGACC_CALL_IF_SET_CONSOLE_COMM(1);
320     comm = CYGACC_CALL_IF_CONSOLE_PROCS();
321     CYGACC_COMM_IF_CH_DATA_SET(*comm, &edb_ser_channels[1]);
322     CYGACC_COMM_IF_WRITE_SET(*comm, cyg_hal_plf_serial_write);
323     CYGACC_COMM_IF_READ_SET(*comm, cyg_hal_plf_serial_read);
324     CYGACC_COMM_IF_PUTC_SET(*comm, cyg_hal_plf_serial_putc);
325     CYGACC_COMM_IF_GETC_SET(*comm, cyg_hal_plf_serial_getc);
326     CYGACC_COMM_IF_CONTROL_SET(*comm, cyg_hal_plf_serial_control);
327     CYGACC_COMM_IF_DBG_ISR_SET(*comm, cyg_hal_plf_serial_isr);
328     CYGACC_COMM_IF_GETC_TIMEOUT_SET(*comm, cyg_hal_plf_serial_getc_timeout);
329
330     // Restore original console
331     CYGACC_CALL_IF_SET_CONSOLE_COMM(cur);
332 }
333
334 void
335 cyg_hal_plf_comms_init(void)
336 {
337     static int initialized = 0;
338
339     if (initialized)
340         return;
341
342     initialized = 1;
343
344     cyg_hal_plf_serial_init();
345 }
346
347 //=============================================================================
348 // Compatibility with older stubs
349 //=============================================================================
350
351 #ifndef CYGSEM_HAL_VIRTUAL_VECTOR_DIAG
352
353 #ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
354 #include <cyg/hal/hal_stub.h>           // cyg_hal_gdb_interrupt
355 #endif
356
357 // Assumption: all diagnostic output must be GDB packetized unless this is a ROM (i.e.
358 // totally stand-alone) system.
359
360 #ifdef CYGSEM_HAL_ROM_MONITOR
361 #define CYG_HAL_STARTUP_ROM
362 #undef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
363 #endif
364
365 #if defined(CYG_HAL_STARTUP_ROM) && !defined(CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS)
366 #define HAL_DIAG_USES_HARDWARE
367 #else
368 #if !defined(CYGDBG_HAL_DIAG_TO_DEBUG_CHAN)
369 #define HAL_DIAG_USES_HARDWARE
370 #elif CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL != CYGNUM_HAL_VIRTUAL_VECTOR_DEBUG_CHANNEL
371 #define HAL_DIAG_USES_HARDWARE
372 #endif
373 #endif
374
375 #if CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL == 0
376 # define __BASE ((volatile struct edb_serial*)SYSCON1)
377 # define __IRQ  CYGNUM_HAL_INTERRUPT_URXINT1
378 #else
379 # define __BASE ((volatile struct edb_serial*)SYSCON2)
380 # define __IRQ  CYGNUM_HAL_INTERRUPT_URXINT2
381 #endif
382
383 static channel_data_t edb_ser_channel = {
384     __BASE, 0, 0
385 };
386
387 /*---------------------------------------------------------------------------*/
388 // EDB7XXX Serial Port (UARTx) for Debug
389
390 // Actually send character down the wire
391 static void
392 hal_diag_write_char_serial(char c)
393 {
394     cyg_hal_plf_serial_putc(&edb_ser_channel, c);
395 }
396
397 static bool
398 hal_diag_read_serial(char *c)
399 {
400     long timeout = 1000000000;  // A long time...
401
402     while (! cyg_hal_plf_serial_getc_nonblock(&edb_ser_channel, c) )
403         if (--timeout == 0) return false;
404
405     return true;
406 }
407
408 #ifdef HAL_DIAG_USES_HARDWARE
409
410 void hal_diag_init(void)
411 {
412     static int init = 0;
413 #ifndef CYG_HAL_STARTUP_ROM
414     char *msg = "\n\rRAM EDB7XXX eCos\n\r";
415 #endif
416     if (init++) return;
417
418     cyg_hal_plf_serial_init_channel(&edb_ser_channel);
419
420 #ifndef CYG_HAL_STARTUP_ROM
421     while (*msg) hal_diag_write_char(*msg++);
422 #endif
423 }
424
425 #ifdef DEBUG_DIAG
426 #ifndef CYG_HAL_STARTUP_ROM
427 #define DIAG_BUFSIZE 2048
428 static char diag_buffer[DIAG_BUFSIZE];
429 static int diag_bp = 0;
430 #endif
431 #endif
432
433 void hal_diag_write_char(char c)
434 {
435     hal_diag_init();
436 #ifdef DEBUG_DIAG
437 #ifndef CYG_HAL_STARTUP_ROM
438     diag_buffer[diag_bp++] = c;
439     if (diag_bp == sizeof(diag_buffer)) diag_bp = 0;
440 #endif
441 #endif
442     hal_diag_write_char_serial(c);
443 }
444
445 void hal_diag_read_char(char *c)
446 {
447     while (!hal_diag_read_serial(c)) ;
448 }
449
450 #else // HAL_DIAG relies on GDB
451
452 // Initialize diag port
453 void hal_diag_init(void)
454 {
455     // Assume port is already setup
456     if (0) cyg_hal_plf_serial_init_channel(&edb_ser_channel);
457 }
458
459 void 
460 hal_diag_read_char(char *c)
461 {
462     while (!hal_diag_read_serial(c)) ;
463 }
464
465 void 
466 hal_diag_write_char(char c)
467 {
468     static char line[100];
469     static int pos = 0;
470
471     // No need to send CRs
472     if( c == '\r' ) return;
473
474     line[pos++] = c;
475
476     if( c == '\n' || pos == sizeof(line) )
477     {
478         
479         CYG_INTERRUPT_STATE old;
480
481         // Disable interrupts. This prevents GDB trying to interrupt us
482         // while we are in the middle of sending a packet. The serial
483         // receive interrupt will be seen when we re-enable interrupts
484         // later.
485         
486 #ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
487         CYG_HAL_GDB_ENTER_CRITICAL_IO_REGION(old);
488 #else
489         HAL_DISABLE_INTERRUPTS(old);
490 #endif
491
492         while(1)
493         {
494             static char hex[] = "0123456789ABCDEF";
495             cyg_uint8 csum = 0;
496             int i;
497             char c1;
498         
499             hal_diag_write_char_serial('$');
500             hal_diag_write_char_serial('O');
501             csum += 'O';
502             for( i = 0; i < pos; i++ )
503             {
504                 char ch = line[i];
505                 char h = hex[(ch>>4)&0xF];
506                 char l = hex[ch&0xF];
507                 hal_diag_write_char_serial(h);
508                 hal_diag_write_char_serial(l);
509                 csum += h;
510                 csum += l;
511             }
512             hal_diag_write_char_serial('#');
513             hal_diag_write_char_serial(hex[(csum>>4)&0xF]);
514             hal_diag_write_char_serial(hex[csum&0xF]);
515
516             // Wait for the ACK character '+' from GDB here and handle
517             // receiving a ^C instead.  This is the reason for this clause
518             // being a loop.
519             if (!hal_diag_read_serial(&c1))
520                 continue;   // No response - try sending packet again
521
522             if( c1 == '+' )
523                 break;              // a good acknowledge
524
525 #ifdef CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT
526             cyg_drv_interrupt_acknowledge(__IRQ);
527             if( c1 == 3 ) {
528                 // Ctrl-C: breakpoint.
529                 cyg_hal_gdb_interrupt (__builtin_return_address(0));
530                 break;
531             }
532 #endif
533             // otherwise, loop round again
534         }
535         
536         pos = 0;
537
538         
539         // And re-enable interrupts
540 #ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
541         CYG_HAL_GDB_LEAVE_CRITICAL_IO_REGION(old);
542 #else
543         HAL_RESTORE_INTERRUPTS(old);
544 #endif
545         
546     }
547 }
548 #endif
549
550 #endif // !CYGSEM_HAL_VIRTUAL_VECTOR_DIAG
551
552 /*---------------------------------------------------------------------------*/
553 /* End of hal_diag.c */