]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/hal/arm/aeb/v2_0/src/hal_diag.c
Initial revision
[karo-tx-redboot.git] / packages / hal / arm / aeb / 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
55 #include <cyg/infra/cyg_type.h>         // base types
56 #include <cyg/infra/cyg_trac.h>         // tracing macros
57 #include <cyg/infra/cyg_ass.h>          // assertion macros
58
59 #include <cyg/hal/hal_arch.h>           // SAVE/RESTORE GP macros
60 #include <cyg/hal/hal_io.h>             // IO macros
61 #include <cyg/hal/hal_if.h>             // interface API
62 #include <cyg/hal/hal_intr.h>           // HAL_ENABLE/MASK/UNMASK_INTERRUPTS
63 #include <cyg/hal/hal_misc.h>           // Helper functions
64 #include <cyg/hal/drv_api.h>            // CYG_ISR_HANDLED
65
66 /*---------------------------------------------------------------------------*/
67 // AEB Serial Port (UART1) for Debug
68
69 /*---------------------------------------------------------------------------*/
70 /* From serial_16550.h */
71
72 // UART1, 38400  (Using raw 24MHz system clock)
73 #define CYG_DEVICE_SERIAL_RS232_BAUD_MSB        (0)
74 #define CYG_DEVICE_SERIAL_RS232_BAUD_LSB        (13*3)
75 // This is the base address of UART1
76 #define CYG_DEV_UART1_BASE      0xFFFF0400
77
78 // Interrupt Enable Register
79 #define SIO_IER_RCV 0x01
80 #define SIO_IER_XMT 0x02
81 #define SIO_IER_LS  0x04
82 #define SIO_IER_MS  0x08
83
84 // Define the serial registers.
85 #define CYG_DEV_RBR 0x00   // receiver buffer register, read, dlab = 0
86 #define CYG_DEV_THR 0x00   // transmitter holding register, write, dlab = 0
87 #define CYG_DEV_DLL 0x00   // divisor latch (LS), read/write, dlab = 1
88 #define CYG_DEV_IER 0x04   // interrupt enable register, read/write, dlab = 0
89 #define CYG_DEV_DLM 0x04   // divisor latch (MS), read/write, dlab = 1
90 #define CYG_DEV_IIR 0x08   // interrupt identification register, read, dlab = 0
91 #define CYG_DEV_FCR 0x08   // fifo control register, write, dlab = 0
92 #define CYG_DEV_LCR 0x0C   // line control register, read/write
93 #define CYG_DEV_MCR 0x10   // modem control register, read/write
94 #define CYG_DEV_LSR 0x14   // line status register, read
95 #define CYG_DEV_MSR 0x18   // modem status register, read
96
97 // The line status register bits.
98 #define SIO_LSR_DR      0x01            // data ready
99 #define SIO_LSR_OE      0x02            // overrun error
100 #define SIO_LSR_PE      0x04            // parity error
101 #define SIO_LSR_FE      0x08            // framing error
102 #define SIO_LSR_BI      0x10            // break interrupt
103 #define SIO_LSR_THRE    0x20            // transmitter holding register empty
104 #define SIO_LSR_TEMT    0x40            // transmitter register empty
105 #define SIO_LSR_ERR     0x80            // any error condition
106
107 // The modem status register bits.
108 #define SIO_MSR_DCTS  0x01              // delta clear to send
109 #define SIO_MSR_DDSR  0x02              // delta data set ready
110 #define SIO_MSR_TERI  0x04              // trailing edge ring indicator
111 #define SIO_MSR_DDCD  0x08              // delta data carrier detect
112 #define SIO_MSR_CTS   0x10              // clear to send
113 #define SIO_MSR_DSR   0x20              // data set ready
114 #define SIO_MSR_RI    0x40              // ring indicator
115 #define SIO_MSR_DCD   0x80              // data carrier detect
116
117 // The line control register bits.
118 #define SIO_LCR_WLS0   0x01             // word length select bit 0
119 #define SIO_LCR_WLS1   0x02             // word length select bit 1
120 #define SIO_LCR_STB    0x04             // number of stop bits
121 #define SIO_LCR_PEN    0x08             // parity enable
122 #define SIO_LCR_EPS    0x10             // even parity select
123 #define SIO_LCR_SP     0x20             // stick parity
124 #define SIO_LCR_SB     0x40             // set break
125 #define SIO_LCR_DLAB   0x80             // divisor latch access bit
126
127 // Modem Control Register
128 #define SIO_MCR_DTR 0x01
129 #define SIO_MCR_RTS 0x02
130 #define SIO_MCR_INT 0x08   // Enable interrupts
131
132
133 //-----------------------------------------------------------------------------
134 typedef struct {
135     cyg_uint8* base;
136     cyg_int32 msec_timeout;
137     int isr_vector;
138 } channel_data_t;
139
140 //-----------------------------------------------------------------------------
141
142 static void
143 cyg_hal_plf_serial_init_channel(void* __ch_data)
144 {
145     cyg_uint8* base = ((channel_data_t*)__ch_data)->base;
146     cyg_uint8 lcr, dll, dlm;
147
148     // 8-1-no parity.
149     HAL_WRITE_UINT8(base+CYG_DEV_LCR, SIO_LCR_WLS0 | SIO_LCR_WLS1);
150
151     HAL_READ_UINT8(base+CYG_DEV_LCR, lcr);
152     lcr |= SIO_LCR_DLAB;
153     HAL_WRITE_UINT8(base+CYG_DEV_LCR, lcr);
154     HAL_READ_UINT8(base+CYG_DEV_DLL, dll);
155     HAL_READ_UINT8(base+CYG_DEV_DLM, dlm);
156     HAL_WRITE_UINT8 (base+CYG_DEV_DLL, CYG_DEVICE_SERIAL_RS232_BAUD_LSB);
157     HAL_WRITE_UINT8 (base+CYG_DEV_DLM, CYG_DEVICE_SERIAL_RS232_BAUD_MSB);
158     lcr &= ~SIO_LCR_DLAB;
159     HAL_WRITE_UINT8 (base+CYG_DEV_LCR, lcr);
160     HAL_WRITE_UINT8 (base+CYG_DEV_FCR, 0x07);  // Enable & clear FIFO
161 }
162
163 void
164 cyg_hal_plf_serial_putc(void *__ch_data, char c)
165 {
166     cyg_uint8* base = ((channel_data_t*)__ch_data)->base;
167     cyg_uint8 lsr;
168     CYGARC_HAL_SAVE_GP();
169
170     do {
171         HAL_READ_UINT8(base+CYG_DEV_LSR, lsr);
172     } while ((lsr & SIO_LSR_THRE) == 0);
173
174     HAL_WRITE_UINT8(base+CYG_DEV_THR, c);
175
176     CYGARC_HAL_RESTORE_GP();
177 }
178
179 static cyg_bool
180 cyg_hal_plf_serial_getc_nonblock(void* __ch_data, cyg_uint8* ch)
181 {
182     cyg_uint8* base = ((channel_data_t*)__ch_data)->base;
183     cyg_uint8 lsr;
184
185     HAL_READ_UINT8(base+CYG_DEV_LSR, lsr);
186     if ((lsr & SIO_LSR_DR) == 0)
187         return false;
188
189     HAL_READ_UINT8(base+CYG_DEV_RBR, *ch);
190
191     return true;
192 }
193
194 cyg_uint8
195 cyg_hal_plf_serial_getc(void* __ch_data)
196 {
197     cyg_uint8 ch;
198     CYGARC_HAL_SAVE_GP();
199
200     while(!cyg_hal_plf_serial_getc_nonblock(__ch_data, &ch));
201
202     CYGARC_HAL_RESTORE_GP();
203     return ch;
204 }
205
206 static void
207 cyg_hal_plf_serial_write(void* __ch_data, const cyg_uint8* __buf, 
208                          cyg_uint32 __len)
209 {
210     CYGARC_HAL_SAVE_GP();
211
212     while(__len-- > 0)
213         cyg_hal_plf_serial_putc(__ch_data, *__buf++);
214
215     CYGARC_HAL_RESTORE_GP();
216 }
217
218 static void
219 cyg_hal_plf_serial_read(void* __ch_data, cyg_uint8* __buf, cyg_uint32 __len)
220 {
221     CYGARC_HAL_SAVE_GP();
222
223     while(__len-- > 0)
224         *__buf++ = cyg_hal_plf_serial_getc(__ch_data);
225
226     CYGARC_HAL_RESTORE_GP();
227 }
228
229 cyg_bool
230 cyg_hal_plf_serial_getc_timeout(void* __ch_data, cyg_uint8* ch)
231 {
232     int delay_count;
233     channel_data_t* chan = (channel_data_t*)__ch_data;
234     cyg_bool res;
235     CYGARC_HAL_SAVE_GP();
236
237     delay_count = chan->msec_timeout * 10; // delay in .1 ms steps
238
239     for(;;) {
240         res = cyg_hal_plf_serial_getc_nonblock(__ch_data, ch);
241         if (res || 0 == delay_count--)
242             break;
243         
244         CYGACC_CALL_IF_DELAY_US(100);
245     }
246
247     CYGARC_HAL_RESTORE_GP();
248     return res;
249 }
250
251 static int
252 cyg_hal_plf_serial_control(void *__ch_data, __comm_control_cmd_t __func, ...)
253 {
254     static int irq_state = 0;
255     channel_data_t* chan = (channel_data_t*)__ch_data;
256     int ret = 0;
257     CYGARC_HAL_SAVE_GP();
258
259     switch (__func) {
260     case __COMMCTL_IRQ_ENABLE:
261         irq_state = 1;
262
263         HAL_WRITE_UINT8(chan->base+CYG_DEV_IER, SIO_IER_RCV);
264         HAL_WRITE_UINT8(chan->base+CYG_DEV_MCR, SIO_MCR_INT|SIO_MCR_DTR|SIO_MCR_RTS);
265
266         HAL_INTERRUPT_UNMASK(chan->isr_vector);
267         break;
268     case __COMMCTL_IRQ_DISABLE:
269         ret = irq_state;
270         irq_state = 0;
271
272         HAL_WRITE_UINT8(chan->base+CYG_DEV_IER, 0);
273         HAL_WRITE_UINT8(chan->base+CYG_DEV_MCR, SIO_MCR_INT|SIO_MCR_DTR|SIO_MCR_RTS);
274
275         HAL_INTERRUPT_MASK(chan->isr_vector);
276         break;
277     case __COMMCTL_DBG_ISR_VECTOR:
278         ret = chan->isr_vector;
279         break;
280     case __COMMCTL_SET_TIMEOUT:
281     {
282         va_list ap;
283
284         va_start(ap, __func);
285
286         ret = chan->msec_timeout;
287         chan->msec_timeout = va_arg(ap, cyg_uint32);
288
289         va_end(ap);
290     }        
291     default:
292         break;
293     }
294     CYGARC_HAL_RESTORE_GP();
295     return ret;
296 }
297
298 static int
299 cyg_hal_plf_serial_isr(void *__ch_data, int* __ctrlc, 
300                        CYG_ADDRWORD __vector, CYG_ADDRWORD __data)
301 {
302     int res = 0;
303     channel_data_t* chan = (channel_data_t*)__ch_data;
304     char c;
305     cyg_uint8 lsr;
306     CYGARC_HAL_SAVE_GP();
307
308     cyg_drv_interrupt_acknowledge(chan->isr_vector);
309
310
311     *__ctrlc = 0;
312     HAL_READ_UINT8(chan->base+CYG_DEV_LSR, lsr);
313     if ( (lsr & SIO_LSR_DR) != 0 ) {
314
315         HAL_READ_UINT8(chan->base+CYG_DEV_RBR, c);
316         if( cyg_hal_is_break( &c , 1 ) )
317             *__ctrlc = 1;
318
319         res = CYG_ISR_HANDLED;
320     }
321
322     CYGARC_HAL_RESTORE_GP();
323     return res;
324 }
325
326 static channel_data_t aeb_ser_channels[1];
327
328 static void
329 cyg_hal_plf_serial_init(void)
330 {
331     hal_virtual_comm_table_t* comm;
332     int cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
333     channel_data_t* chan;
334
335     chan = &aeb_ser_channels[0];
336     chan->base = (cyg_uint8*)CYG_DEV_UART1_BASE;
337     chan->isr_vector = CYGNUM_HAL_INTERRUPT_UART1;
338     chan->msec_timeout = 1000;
339
340     // Init channel
341     cyg_hal_plf_serial_init_channel(chan);
342
343     // Setup procs in the vector table
344
345     // Set channel 0
346     CYGACC_CALL_IF_SET_CONSOLE_COMM(0);
347     comm = CYGACC_CALL_IF_CONSOLE_PROCS();
348     CYGACC_COMM_IF_CH_DATA_SET(*comm, chan);
349     CYGACC_COMM_IF_WRITE_SET(*comm, cyg_hal_plf_serial_write);
350     CYGACC_COMM_IF_READ_SET(*comm, cyg_hal_plf_serial_read);
351     CYGACC_COMM_IF_PUTC_SET(*comm, cyg_hal_plf_serial_putc);
352     CYGACC_COMM_IF_GETC_SET(*comm, cyg_hal_plf_serial_getc);
353     CYGACC_COMM_IF_CONTROL_SET(*comm, cyg_hal_plf_serial_control);
354     CYGACC_COMM_IF_DBG_ISR_SET(*comm, cyg_hal_plf_serial_isr);
355     CYGACC_COMM_IF_GETC_TIMEOUT_SET(*comm, cyg_hal_plf_serial_getc_timeout);
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 #ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
381 #include <cyg/hal/drv_api.h>
382 #include <cyg/hal/hal_stub.h>           // cyg_hal_gdb_interrupt
383 #endif
384
385 // Assumption: all diagnostic output must be GDB packetized unless this is a ROM (i.e.
386 // totally stand-alone) system.
387
388 #if defined(CYG_HAL_STARTUP_ROM) || !defined(CYGDBG_HAL_DIAG_TO_DEBUG_CHAN)
389 #define HAL_DIAG_USES_HARDWARE
390 #endif
391
392
393 static channel_data_t aeb_ser_channel = {(cyg_uint8*)CYG_DEV_UART1_BASE, 0, 0};
394
395 #ifdef HAL_DIAG_USES_HARDWARE
396
397 void hal_diag_init(void)
398 {
399     static int init = 0;
400     char *msg = "\n\rAEB-1 eCos\n\r";
401
402     if (init++) return;
403
404     cyg_hal_plf_serial_init_channel(&aeb_ser_channel);
405
406     while (*msg) cyg_hal_plf_serial_putc(&aeb_ser_channel, *msg++);
407 }
408
409 #ifdef DEBUG_DIAG
410 #if defined(CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS)
411 #define DIAG_BUFSIZE 32
412 #else
413 #define DIAG_BUFSIZE 2048
414 #endif
415 static char diag_buffer[DIAG_BUFSIZE];
416 static int diag_bp = 0;
417 #endif
418
419 void hal_diag_write_char(char c)
420 {
421     hal_diag_init();
422
423     cyg_hal_plf_serial_putc(&aeb_ser_channel, c);
424
425 #ifdef DEBUG_DIAG
426     diag_buffer[diag_bp++] = c;
427     if (diag_bp == DIAG_BUFSIZE) diag_bp = 0;
428 #endif
429 }
430
431 void hal_diag_read_char(char *c)
432 {
433     *c = cyg_hal_plf_serial_getc(&aeb_ser_channel);
434 }
435
436 #else // HAL_DIAG relies on GDB
437
438 // Initialize diag port - assume GDB channel is already set up
439 void hal_diag_init(void)
440 {
441     if (0) cyg_hal_plf_serial_init_channel(&aeb_ser_channel); // avoid warning
442 }
443
444 // Actually send character down the wire
445 static void
446 hal_diag_write_char_serial(char c)
447 {
448     hal_diag_init();
449
450     cyg_hal_plf_serial_putc(&aeb_ser_channel, c);
451 }
452
453 static bool
454 hal_diag_read_serial(char *c)
455 {
456     long timeout = 1000000000;  // A long time...
457     while (!cyg_hal_plf_serial_getc_nonblock(&aeb_ser_channel, c))
458         if (0 == --timeout) return false;
459
460     return true;
461 }
462
463 void 
464 hal_diag_read_char(char *c)
465 {
466     while (!hal_diag_read_serial(c)) ;
467 }
468
469 void 
470 hal_diag_write_char(char c)
471 {
472     static char line[100];
473     static int pos = 0;
474
475     // No need to send CRs
476     if( c == '\r' ) return;
477
478     line[pos++] = c;
479
480     if( c == '\n' || pos == sizeof(line) )
481     {
482         
483         CYG_INTERRUPT_STATE old;
484
485         // Disable interrupts. This prevents GDB trying to interrupt us
486         // while we are in the middle of sending a packet. The serial
487         // receive interrupt will be seen when we re-enable interrupts
488         // later.
489         
490 #ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
491         CYG_HAL_GDB_ENTER_CRITICAL_IO_REGION(old);
492 #else
493         HAL_DISABLE_INTERRUPTS(old);
494 #endif
495
496         while(1)
497         {
498             static char hex[] = "0123456789ABCDEF";
499             cyg_uint8 csum = 0;
500             int i;
501             char c1;
502         
503             hal_diag_write_char_serial('$');
504             hal_diag_write_char_serial('O');
505             csum += 'O';
506             for( i = 0; i < pos; i++ )
507             {
508                 char ch = line[i];
509                 char h = hex[(ch>>4)&0xF];
510                 char l = hex[ch&0xF];
511                 hal_diag_write_char_serial(h);
512                 hal_diag_write_char_serial(l);
513                 csum += h;
514                 csum += l;
515             }
516             hal_diag_write_char_serial('#');
517             hal_diag_write_char_serial(hex[(csum>>4)&0xF]);
518             hal_diag_write_char_serial(hex[csum&0xF]);
519
520             // Wait for the ACK character '+' from GDB here and handle
521             // receiving a ^C instead.  This is the reason for this clause
522             // being a loop.
523             if (!hal_diag_read_serial(&c1))
524                 continue;   // No response - try sending packet again
525
526             if( c1 == '+' )
527                 break;              // a good acknowledge
528
529 #ifdef CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT
530             cyg_drv_interrupt_acknowledge(CYGNUM_HAL_INTERRUPT_UART1);
531             if( c1 == 3 ) {
532                 // Ctrl-C: breakpoint.
533                 cyg_hal_gdb_interrupt (__builtin_return_address(0));
534                 break;
535             }
536 #endif
537             // otherwise, loop round again
538         }
539         
540         pos = 0;
541
542         
543         // And re-enable interrupts
544 #ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
545         CYG_HAL_GDB_LEAVE_CRITICAL_IO_REGION(old);
546 #else
547         HAL_RESTORE_INTERRUPTS(old);
548 #endif
549         
550     }
551 }
552 #endif
553
554 #endif // CYGSEM_HAL_VIRTUAL_VECTOR_DIAG
555
556
557 /*---------------------------------------------------------------------------*/
558 /* End of hal_diag.c */