unified MX27, MX25, MX37 trees
[karo-tx-redboot.git] / packages / hal / arm / lpc2xxx / 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 // Copyright (C) 2004 eCosCentric Limited 
13 //
14 // eCos is free software; you can redistribute it and/or modify it under
15 // the terms of the GNU General Public License as published by the Free
16 // Software Foundation; either version 2 or (at your option) any later version.
17 //
18 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
19 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
21 // for more details.
22 //
23 // You should have received a copy of the GNU General Public License along
24 // with eCos; if not, write to the Free Software Foundation, Inc.,
25 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 //
27 // As a special exception, if other files instantiate templates or use macros
28 // or inline functions from this file, or you compile this file and link it
29 // with other works to produce a work based on this file, this file does not
30 // by itself cause the resulting work to be covered by the GNU General Public
31 // License. However the source code for this file must still be made available
32 // in accordance with section (3) of the GNU General Public License.
33 //
34 // This exception does not invalidate any other reasons why a work based on
35 // this file might be covered by the GNU General Public License.
36 // -------------------------------------------
37 //####ECOSGPLCOPYRIGHTEND####
38 //=============================================================================
39 //#####DESCRIPTIONBEGIN####
40 //
41 // Author(s):   jani
42 // Contributors:jskov, gthomas
43 // Date:        2001-07-12
44 // Purpose:     HAL diagnostic output
45 // Description: Implementations of HAL diagnostic output support.
46 //
47 //####DESCRIPTIONEND####
48 //
49 //===========================================================================*/
50
51 #include <pkgconf/hal.h>
52 #include CYGBLD_HAL_PLATFORM_H
53
54 #include <cyg/infra/cyg_type.h>         // base types
55
56 #include <cyg/hal/hal_arch.h>           // SAVE/RESTORE GP macros
57 #include <cyg/hal/hal_io.h>             // IO macros
58 #include <cyg/hal/hal_if.h>             // interface API
59 #include <cyg/hal/hal_intr.h>           // HAL_ENABLE/MASK/UNMASK_INTERRUPTS
60 #include <cyg/hal/hal_misc.h>           // Helper functions
61 #include <cyg/hal/drv_api.h>            // CYG_ISR_HANDLED
62 #include <cyg/hal/hal_diag.h>
63
64 #include <cyg/hal/var_io.h>             // USART registers
65
66 //-----------------------------------------------------------------------------
67 typedef struct {
68     cyg_uint8* base;
69     cyg_int32 msec_timeout;
70     int isr_vector;
71     int baud_rate;
72 } channel_data_t;
73
74 //-----------------------------------------------------------------------------
75 static void
76 cyg_hal_plf_serial_init_channel(void* __ch_data)
77 {
78     channel_data_t* chan = (channel_data_t*)__ch_data;
79     cyg_uint8* base = chan->base;
80     cyg_uint16 divider = CYG_HAL_ARM_LPC2XXX_BAUD_GENERATOR(chan->baud_rate);
81     // Set baudrate
82     HAL_WRITE_UINT32(base+CYGARC_HAL_LPC2XXX_REG_UxLCR, 
83                      CYGARC_HAL_LPC2XXX_REG_UxLCR_DLAB);
84     HAL_WRITE_UINT32(base+CYGARC_HAL_LPC2XXX_REG_UxDLM, divider >> 8);
85     HAL_WRITE_UINT32(base+CYGARC_HAL_LPC2XXX_REG_UxDLL, divider & 0xFF);
86
87     // 8-1-no parity.
88     HAL_WRITE_UINT32(base+CYGARC_HAL_LPC2XXX_REG_UxLCR, 
89                      CYGARC_HAL_LPC2XXX_REG_UxLCR_WORD_LENGTH_8 |
90                      CYGARC_HAL_LPC2XXX_REG_UxLCR_STOP_1);
91
92     // Reset and enable FIFO
93     HAL_WRITE_UINT32(base+CYGARC_HAL_LPC2XXX_REG_UxFCR, 
94                      CYGARC_HAL_LPC2XXX_REG_UxFCR_FIFO_ENA |
95                      CYGARC_HAL_LPC2XXX_REG_UxFCR_RX_FIFO_RESET | 
96                      CYGARC_HAL_LPC2XXX_REG_UxFCR_TX_FIFO_RESET);
97 }
98
99 void
100 cyg_hal_plf_serial_putc(void *__ch_data, char c)
101 {
102     cyg_uint8* base = ((channel_data_t*)__ch_data)->base;
103     cyg_uint8 stat;
104     CYGARC_HAL_SAVE_GP();
105
106     do {
107         HAL_READ_UINT32(base+CYGARC_HAL_LPC2XXX_REG_UxLSR, stat);
108     } while ((stat & CYGARC_HAL_LPC2XXX_REG_UxLSR_THRE) == 0);
109
110     HAL_WRITE_UINT32(base+CYGARC_HAL_LPC2XXX_REG_UxTHR, c);
111
112     CYGARC_HAL_RESTORE_GP();
113 }
114
115 static cyg_bool
116 cyg_hal_plf_serial_getc_nonblock(void* __ch_data, cyg_uint8* ch)
117 {
118     channel_data_t* chan = (channel_data_t*)__ch_data;
119     cyg_uint8* base = chan->base;
120     cyg_uint8 stat;
121
122     HAL_READ_UINT32(base+CYGARC_HAL_LPC2XXX_REG_UxLSR, stat);
123     if ((stat & CYGARC_HAL_LPC2XXX_REG_UxLSR_RDR) == 0)
124         return false;
125
126     HAL_READ_UINT32(base+CYGARC_HAL_LPC2XXX_REG_UxRBR, *ch);
127
128     return true;
129 }
130
131 cyg_uint8
132 cyg_hal_plf_serial_getc(void* __ch_data)
133 {
134     cyg_uint8 ch;
135     CYGARC_HAL_SAVE_GP();
136
137     while(!cyg_hal_plf_serial_getc_nonblock(__ch_data, &ch));
138
139     CYGARC_HAL_RESTORE_GP();
140     return ch;
141 }
142
143 static void
144 cyg_hal_plf_serial_write(void* __ch_data, const cyg_uint8* __buf, 
145                          cyg_uint32 __len)
146 {
147     CYGARC_HAL_SAVE_GP();
148
149     while(__len-- > 0)
150         cyg_hal_plf_serial_putc(__ch_data, *__buf++);
151
152     CYGARC_HAL_RESTORE_GP();
153 }
154
155 static void
156 cyg_hal_plf_serial_read(void* __ch_data, cyg_uint8* __buf, cyg_uint32 __len)
157 {
158     CYGARC_HAL_SAVE_GP();
159
160     while(__len-- > 0)
161         *__buf++ = cyg_hal_plf_serial_getc(__ch_data);
162
163     CYGARC_HAL_RESTORE_GP();
164 }
165
166 cyg_bool
167 cyg_hal_plf_serial_getc_timeout(void* __ch_data, cyg_uint8* ch)
168 {
169     int delay_count;
170     channel_data_t* chan = (channel_data_t*)__ch_data;
171     cyg_bool res;
172     CYGARC_HAL_SAVE_GP();
173
174     delay_count = chan->msec_timeout * 10; // delay in .1 ms steps
175
176     for(;;) {
177         res = cyg_hal_plf_serial_getc_nonblock(__ch_data, ch);
178         if (res || 0 == delay_count--)
179             break;
180         
181         CYGACC_CALL_IF_DELAY_US(100);
182     }
183
184     CYGARC_HAL_RESTORE_GP();
185     return res;
186 }
187
188 static int
189 cyg_hal_plf_serial_control(void *__ch_data, __comm_control_cmd_t __func, ...)
190 {
191     static int irq_state = 0;
192     channel_data_t* chan = (channel_data_t*)__ch_data;
193     cyg_uint8* base = ((channel_data_t*)__ch_data)->base;
194     int ret = 0;
195     va_list ap;
196
197     CYGARC_HAL_SAVE_GP();
198     va_start(ap, __func);
199
200     switch (__func) {
201     case __COMMCTL_GETBAUD:
202         ret = chan->baud_rate;
203         break;
204     case __COMMCTL_SETBAUD:
205         chan->baud_rate = va_arg(ap, cyg_int32);
206         // Should we verify this value here?
207         cyg_hal_plf_serial_init_channel(chan);
208         ret = 0;
209         break;
210     case __COMMCTL_IRQ_ENABLE:
211         irq_state = 1;
212         HAL_INTERRUPT_ACKNOWLEDGE(chan->isr_vector);
213         HAL_INTERRUPT_UNMASK(chan->isr_vector);
214         HAL_WRITE_UINT32(base+CYGARC_HAL_LPC2XXX_REG_UxIER, 
215                          CYGARC_HAL_LPC2XXX_REG_UxIER_RXDATA_INT);
216         break;
217     case __COMMCTL_IRQ_DISABLE:
218         ret = irq_state;
219         irq_state = 0;
220         HAL_INTERRUPT_MASK(chan->isr_vector);
221         HAL_WRITE_UINT32(base+CYGARC_HAL_LPC2XXX_REG_UxIER, 0);
222         break;
223     case __COMMCTL_DBG_ISR_VECTOR:
224         ret = chan->isr_vector;
225         break;
226     case __COMMCTL_SET_TIMEOUT:
227         ret = chan->msec_timeout;
228         chan->msec_timeout = va_arg(ap, cyg_uint32);
229     default:
230         break;
231     }
232
233     va_end(ap);
234     CYGARC_HAL_RESTORE_GP();
235     return ret;
236 }
237
238 static int
239 cyg_hal_plf_serial_isr(void *__ch_data, int* __ctrlc, 
240                        CYG_ADDRWORD __vector, CYG_ADDRWORD __data)
241 {
242     int res = 0;
243     channel_data_t* chan = (channel_data_t*)__ch_data;
244     cyg_uint8 c;
245     cyg_uint8 iir;
246     
247     CYGARC_HAL_SAVE_GP();
248
249     *__ctrlc = 0;
250
251         HAL_READ_UINT32(chan->base + CYGARC_HAL_LPC2XXX_REG_UxIIR, iir);
252         
253         if((iir & (CYGARC_HAL_LPC2XXX_REG_UxIIR_IIR0 | CYGARC_HAL_LPC2XXX_REG_UxIIR_IIR1 | 
254                 CYGARC_HAL_LPC2XXX_REG_UxIIR_IIR2)) == CYGARC_HAL_LPC2XXX_REG_UxIIR_IIR2)
255         {
256                 // Rx data available or character timeout
257                 // Read data in order to clear interrupt
258         HAL_READ_UINT32(chan->base+CYGARC_HAL_LPC2XXX_REG_UxRBR, c);
259         if( cyg_hal_is_break( &c , 1 ) ) *__ctrlc = 1;
260
261         res = CYG_ISR_HANDLED;
262     }
263
264     HAL_INTERRUPT_ACKNOWLEDGE(chan->isr_vector);
265
266     CYGARC_HAL_RESTORE_GP();
267     return res;
268 }
269
270 static channel_data_t lpc2xxx_ser_channels[2] = {
271     { (cyg_uint8*)CYGARC_HAL_LPC2XXX_REG_UART0_BASE, 1000, 
272       CYGNUM_HAL_INTERRUPT_UART0, 
273       CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL_BAUD},
274     { (cyg_uint8*)CYGARC_HAL_LPC2XXX_REG_UART1_BASE, 1000, 
275       CYGNUM_HAL_INTERRUPT_UART1, 
276       CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL_BAUD}
277 };
278
279 void
280 cyg_hal_plf_serial_init(void)
281 {
282     hal_virtual_comm_table_t* comm;
283     int cur;
284
285     cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
286
287     // Init channels
288     cyg_hal_plf_serial_init_channel(&lpc2xxx_ser_channels[0]);
289 #if CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS > 1
290     cyg_hal_plf_serial_init_channel(&lpc2xxx_ser_channels[1]);
291 #endif
292
293     // Setup procs in the vector table
294
295     // Set channel 0
296     CYGACC_CALL_IF_SET_CONSOLE_COMM(0);
297     comm = CYGACC_CALL_IF_CONSOLE_PROCS();
298     CYGACC_COMM_IF_CH_DATA_SET(*comm, &lpc2xxx_ser_channels[0]);
299     CYGACC_COMM_IF_WRITE_SET(*comm, cyg_hal_plf_serial_write);
300     CYGACC_COMM_IF_READ_SET(*comm, cyg_hal_plf_serial_read);
301     CYGACC_COMM_IF_PUTC_SET(*comm, cyg_hal_plf_serial_putc);
302     CYGACC_COMM_IF_GETC_SET(*comm, cyg_hal_plf_serial_getc);
303     CYGACC_COMM_IF_CONTROL_SET(*comm, cyg_hal_plf_serial_control);
304     CYGACC_COMM_IF_DBG_ISR_SET(*comm, cyg_hal_plf_serial_isr);
305     CYGACC_COMM_IF_GETC_TIMEOUT_SET(*comm, cyg_hal_plf_serial_getc_timeout);
306
307 #if CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS > 1
308     // Set channel 1
309     CYGACC_CALL_IF_SET_CONSOLE_COMM(1);
310     comm = CYGACC_CALL_IF_CONSOLE_PROCS();
311     CYGACC_COMM_IF_CH_DATA_SET(*comm, &lpc2xxx_ser_channels[1]);
312     CYGACC_COMM_IF_WRITE_SET(*comm, cyg_hal_plf_serial_write);
313     CYGACC_COMM_IF_READ_SET(*comm, cyg_hal_plf_serial_read);
314     CYGACC_COMM_IF_PUTC_SET(*comm, cyg_hal_plf_serial_putc);
315     CYGACC_COMM_IF_GETC_SET(*comm, cyg_hal_plf_serial_getc);
316     CYGACC_COMM_IF_CONTROL_SET(*comm, cyg_hal_plf_serial_control);
317     CYGACC_COMM_IF_DBG_ISR_SET(*comm, cyg_hal_plf_serial_isr);
318     CYGACC_COMM_IF_GETC_TIMEOUT_SET(*comm, cyg_hal_plf_serial_getc_timeout);
319 #endif
320
321     // Restore original console
322     CYGACC_CALL_IF_SET_CONSOLE_COMM(cur);
323 }
324
325 void
326 hal_diag_led(int mask)
327 {
328     hal_lpc2xxx_set_leds(mask);
329 }
330
331 //-----------------------------------------------------------------------------
332 // End of hal_diag.c