1 /*=============================================================================
5 // HAL diagnostic output code
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.
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.
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
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.
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.
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.
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####
44 // Contributors:nickg, gthomas, dmoseley
45 // Travis C. Furrer <furrer@mit.edu>
47 // Purpose: HAL diagnostic output
48 // Description: Implementations of HAL diagnostic output support.
50 //####DESCRIPTIONEND####
52 //===========================================================================*/
54 #include <pkgconf/hal.h>
55 #include <pkgconf/system.h>
56 #include CYGBLD_HAL_PLATFORM_H
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
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
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;
83 //-----------------------------------------------------------------------------
85 volatile struct sa11x0_serial* base;
86 cyg_int32 msec_timeout;
91 /*---------------------------------------------------------------------------*/
92 // SA11x0 Serial Port (UARTx) for Debug
95 init_channel(channel_data_t* __ch_data)
97 volatile struct sa11x0_serial* base = __ch_data->base;
100 // Disable Receiver and Transmitter (clears FIFOs)
101 base->utcr3 = SA11X0_UART_RX_DISABLED | SA11X0_UART_TX_DISABLED;
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;
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;
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);
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));
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);
122 // Pin reassignment for serial port 1.
123 HAL_WRITE_UINT32(SA11X0_PPC_PIN_ASSIGNMENT, par | SA11X0_PPC_UART_PIN_REASSIGNMENT_MASK);
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;
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;
136 // Enable the receiver and the transmitter.
137 base->utcr3 = SA11X0_UART_RX_ENABLED | SA11X0_UART_TX_ENABLED;
143 cyg_hal_plf_serial_putc(void *__ch_data, char c)
145 volatile struct sa11x0_serial* base = ((channel_data_t*)__ch_data)->base;
146 CYGARC_HAL_SAVE_GP();
148 // Wait for Tx FIFO not full
149 while ((base->utsr1 & SA11X0_UART_TX_FIFO_NOT_FULL) == 0)
153 CYGARC_HAL_RESTORE_GP();
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.
161 cyg_hal_plf_serial_getc_nonblock(void* __ch_data, cyg_uint8* ch)
163 volatile struct sa11x0_serial* base = ((channel_data_t*)__ch_data)->base;
165 // If receive fifo is empty, return false
166 if ((base->utsr1 & SA11X0_UART_RX_FIFO_NOT_EMPTY) == 0)
169 *ch = (char)base->utdr;
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;
179 cyg_hal_plf_serial_getc(void* __ch_data)
182 CYGARC_HAL_SAVE_GP();
184 while(!cyg_hal_plf_serial_getc_nonblock(__ch_data, &ch));
186 CYGARC_HAL_RESTORE_GP();
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 },
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 },
202 cyg_hal_plf_serial_write(void* __ch_data, const cyg_uint8* __buf,
205 CYGARC_HAL_SAVE_GP();
208 cyg_hal_plf_serial_putc(__ch_data, *__buf++);
210 CYGARC_HAL_RESTORE_GP();
214 cyg_hal_plf_serial_read(void* __ch_data, cyg_uint8* __buf, cyg_uint32 __len)
216 CYGARC_HAL_SAVE_GP();
219 *__buf++ = cyg_hal_plf_serial_getc(__ch_data);
221 CYGARC_HAL_RESTORE_GP();
225 cyg_hal_plf_serial_getc_timeout(void* __ch_data, cyg_uint8* ch)
228 channel_data_t* chan = (channel_data_t*)__ch_data;
230 CYGARC_HAL_SAVE_GP();
232 delay_count = chan->msec_timeout * 10; // delay in .1 ms steps
235 res = cyg_hal_plf_serial_getc_nonblock(__ch_data, ch);
236 if (res || 0 == delay_count--)
239 CYGACC_CALL_IF_DELAY_US(100);
242 CYGARC_HAL_RESTORE_GP();
247 cyg_hal_plf_serial_control(void *__ch_data, __comm_control_cmd_t __func, ...)
249 static int irq_state = 0;
250 channel_data_t* chan = (channel_data_t*)__ch_data;
254 CYGARC_HAL_SAVE_GP();
255 va_start(ap, __func);
258 case __COMMCTL_GETBAUD:
259 ret = chan->baud_rate;
261 case __COMMCTL_SETBAUD:
262 chan->baud_rate = va_arg(ap, cyg_int32);
263 // Should we verify this value here?
267 case __COMMCTL_IRQ_ENABLE:
270 chan->base->utcr3 |= SA11X0_UART_RX_FIFO_INT_ENABLED;
272 HAL_INTERRUPT_UNMASK(chan->isr_vector);
274 case __COMMCTL_IRQ_DISABLE:
278 chan->base->utcr3 &= ~SA11X0_UART_RX_FIFO_INT_ENABLED;
280 HAL_INTERRUPT_MASK(chan->isr_vector);
282 case __COMMCTL_DBG_ISR_VECTOR:
283 ret = chan->isr_vector;
285 case __COMMCTL_SET_TIMEOUT:
286 ret = chan->msec_timeout;
287 chan->msec_timeout = va_arg(ap, cyg_uint32);
293 CYGARC_HAL_RESTORE_GP();
298 cyg_hal_plf_serial_isr(void *__ch_data, int* __ctrlc,
299 CYG_ADDRWORD __vector, CYG_ADDRWORD __data)
302 channel_data_t* chan = (channel_data_t*)__ch_data;
305 CYGARC_HAL_SAVE_GP();
307 reg = chan->base->utsr1;
309 // read it anyway just in case - no harm done and we might prevent an
311 c = (char)chan->base->utdr;
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 );
320 cyg_drv_interrupt_acknowledge(chan->isr_vector);
323 if ( (reg & SA11X0_UART_RX_FIFO_NOT_EMPTY) != 0 ) {
324 if( cyg_hal_is_break( &c , 1 ) )
327 res = CYG_ISR_HANDLED;
330 CYGARC_HAL_RESTORE_GP();
335 cyg_hal_plf_serial_init(void)
337 hal_virtual_comm_table_t* comm;
338 int cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
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);
357 // Restore original console
358 CYGACC_CALL_IF_SET_CONSOLE_COMM(cur);
362 cyg_hal_plf_comms_init(void)
364 static int initialized = 0;
371 cyg_hal_plf_serial_init();
374 //=============================================================================
375 // Compatibility with older stubs
376 //=============================================================================
378 #ifndef CYGSEM_HAL_VIRTUAL_VECTOR_DIAG
380 #include <cyg/hal/hal_stub.h> // cyg_hal_gdb_interrupt
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
386 # define __BASE ((void*)SA11X0_UART3_BASE)
387 # define CYGHWR_HAL_GDB_PORT_VECTOR CYGNUM_HAL_INTERRUPT_UART3
390 #ifdef CYGSEM_HAL_ROM_MONITOR
391 #define CYG_HAL_STARTUP_ROM
392 #undef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
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
403 static channel_data_t ser_channel = {
404 (volatile struct sa11x0_serial*)__BASE, 0, CYGHWR_HAL_GDB_PORT_VECTOR
410 // Init serial device
411 init_channel(&ser_channel);
414 #ifdef HAL_DIAG_USES_HARDWARE
417 #ifndef CYG_HAL_STARTUP_ROM
418 #define DIAG_BUFSIZE 2048
419 static char diag_buffer[DIAG_BUFSIZE];
420 static int diag_bp = 0;
424 void hal_diag_read_char(char *c)
426 *c = cyg_hal_plf_serial_getc(&ser_channel);
429 void hal_diag_write_char(char c)
432 #ifndef CYG_HAL_STARTUP_ROM
433 diag_buffer[diag_bp++] = c;
434 if (diag_bp == sizeof(diag_buffer)) diag_bp = 0;
437 cyg_hal_plf_serial_putc(&ser_channel, c);
440 #else // not HAL_DIAG_USES_HARDWARE - it uses GDB protocol
443 hal_diag_read_char(char *c)
445 *c = cyg_hal_plf_serial_getc(&ser_channel);
449 hal_diag_write_char(char c)
451 static char line[100];
454 // FIXME: Some LED blinking might be nice right here.
456 // No need to send CRs
457 if( c == '\r' ) return;
461 if( c == '\n' || pos == sizeof(line) )
464 CYG_INTERRUPT_STATE old;
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
471 #ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
472 CYG_HAL_GDB_ENTER_CRITICAL_IO_REGION(old);
474 HAL_DISABLE_INTERRUPTS(old);
479 static char hex[] = "0123456789ABCDEF";
482 #ifndef CYGDBG_HAL_DEBUG_GDB_CTRLC_SUPPORT
485 cyg_hal_plf_serial_putc(&ser_channel, '$');
486 cyg_hal_plf_serial_putc(&ser_channel, 'O');
488 for( i = 0; i < pos; 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);
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]);
502 #ifdef CYGDBG_HAL_DEBUG_GDB_CTRLC_SUPPORT
506 #else // not CYGDBG_HAL_DEBUG_GDB_CTRLC_SUPPORT Ie. usually...
508 // Wait for the ACK character '+' from GDB here and handle
509 // receiving a ^C instead. This is the reason for this clause
511 c1 = cyg_hal_plf_serial_getc(&ser_channel);
514 break; // a good acknowledge
516 #ifdef CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT
517 cyg_drv_interrupt_acknowledge(CYGHWR_HAL_GDB_PORT_VECTOR);
519 // Ctrl-C: breakpoint.
520 cyg_hal_gdb_interrupt(
521 (target_register_t)__builtin_return_address(0) );
524 #endif // CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT
526 #endif // ! CYGDBG_HAL_DEBUG_GDB_CTRLC_SUPPORT
527 // otherwise, loop round again
533 // And re-enable interrupts
534 #ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
535 CYG_HAL_GDB_LEAVE_CRITICAL_IO_REGION(old);
537 HAL_RESTORE_INTERRUPTS(old);
544 #endif // !CYGSEM_HAL_VIRTUAL_VECTOR_DIAG
547 /*---------------------------------------------------------------------------*/
548 /* End of hal_diag.c */