]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/hal/arm/lpc24xx/var/v2_0/src/lpc24xx_misc.c
Initial revision
[karo-tx-redboot.git] / packages / hal / arm / lpc24xx / var / v2_0 / src / lpc24xx_misc.c
1 /*==========================================================================
2 //
3 //      lpc24xx_misc.c
4 //
5 //      HAL misc variant support code for NXP LPC24xx
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) 2003 Nick Garnett <nickg@calivar.com>
13 // Copyright (C) 2004 eCosCentric Limited 
14 //
15 // eCos is free software; you can redistribute it and/or modify it under
16 // the terms of the GNU General Public License as published by the Free
17 // Software Foundation; either version 2 or (at your option) any later version.
18 //
19 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
20 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
21 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
22 // for more details.
23 //
24 // You should have received a copy of the GNU General Public License along
25 // with eCos; if not, write to the Free Software Foundation, Inc.,
26 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
27 //
28 // As a special exception, if other files instantiate templates or use macros
29 // or inline functions from this file, or you compile this file and link it
30 // with other works to produce a work based on this file, this file does not
31 // by itself cause the resulting work to be covered by the GNU General Public
32 // License. However the source code for this file must still be made available
33 // in accordance with section (3) of the GNU General Public License.
34 //
35 // This exception does not invalidate any other reasons why a work based on
36 // this file might be covered by the GNU General Public License.
37 // -------------------------------------------
38 //####ECOSGPLCOPYRIGHTEND####
39 //==========================================================================
40 //#####DESCRIPTIONBEGIN####
41 //
42 // Author(s):    Uwe Kindler 
43 // Contributors: gthomas, jskov, nickg, tkoeller
44 // Date:         2008-07-06
45 // Purpose:      Prozessor support
46 // Description:  Implementations of LPC24xx processor support
47 //
48 //####DESCRIPTIONEND####
49 //
50 //========================================================================*/
51
52
53 //===========================================================================
54 //                                INCLUDES
55 //===========================================================================
56 #include <pkgconf/hal.h>
57 #include <pkgconf/hal_arm_lpc24xx.h>
58
59 #include <cyg/infra/cyg_type.h>         // base types
60 #include <cyg/infra/cyg_trac.h>         // tracing macros
61 #include <cyg/infra/cyg_ass.h>          // assertion macros
62
63 #include <cyg/hal/hal_io.h>             // IO macros
64 #include <cyg/hal/hal_arch.h>           // Register state info
65 #include <cyg/hal/hal_diag.h>
66 #include <cyg/hal/hal_intr.h>           // necessary?
67 #include <cyg/hal/hal_cache.h>
68 #include <cyg/hal/hal_if.h>             // calling interface
69 #include <cyg/hal/hal_misc.h>           // helper functions
70 #ifdef CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT
71 #include <cyg/hal/drv_api.h>            // HAL ISR support
72 #endif
73 #include <cyg/hal/var_io.h>             // platform registers
74
75 #include <cyg/infra/diag.h>     // For diagnostic printing
76
77
78 //===========================================================================
79 // Get peripheral clock for a certain peripheral
80 //===========================================================================
81 cyg_uint32 hal_lpc_get_pclk(cyg_uint32 peripheral_id)
82 {
83     static const cyg_uint8 divider_tbl[4] =
84     {
85         4, 1, 2, 8
86     };
87     cyg_uint32 pclkselreg;
88     cyg_uint32 regval;
89     cyg_uint8  divider;
90
91     //
92     // decide if we need PCLKSEL0 or PCLKSEL1
93     //
94     pclkselreg = ((peripheral_id <= CYNUM_HAL_LPC24XX_PCLK_ACF) ? 
95                    CYGARC_HAL_LPC24XX_REG_PCLKSEL0 : 
96                    CYGARC_HAL_LPC24XX_REG_PCLKSEL1); 
97     HAL_READ_UINT32(CYGARC_HAL_LPC24XX_REG_SCB_BASE + pclkselreg, regval);
98     regval  = (regval >> ((peripheral_id & 0xF) << 1)) & 0x03;
99     divider = divider_tbl[regval];    
100     if ((8 == divider) && (peripheral_id >= CYNUM_HAL_LPC24XX_PCLK_CAN1)
101         && (peripheral_id <= CYNUM_HAL_LPC24XX_PCLK_ACF))
102     {
103         divider = 6;
104     }           
105     return CYGNUM_HAL_ARM_LPC24XX_CLOCK_SPEED / divider;
106 }
107
108
109 //===========================================================================
110 // Set peripheral clock
111 //===========================================================================
112 void hal_lpc_set_pclk(cyg_uint32 peripheral_id, cyg_uint8 divider)
113 {
114     static const cyg_uint8 clock_tbl[4] =
115     {
116         0x01, 0x02, 0x00, 0x03
117     }; 
118     cyg_uint32 clock;
119     cyg_uint32 pclkselreg;
120     cyg_uint32 regval;
121      
122     CYG_ASSERT(divider <= 8, "Wrong peripheral clock divider value"); 
123     //
124     // decide if we need PCLKSEL0 or PCLKSEL1
125     //
126     pclkselreg = (peripheral_id <= CYNUM_HAL_LPC24XX_PCLK_ACF) ? 
127                   CYGARC_HAL_LPC24XX_REG_PCLKSEL0 : 
128                   CYGARC_HAL_LPC24XX_REG_PCLKSEL1;  
129     HAL_READ_UINT32(CYGARC_HAL_LPC24XX_REG_SCB_BASE + pclkselreg, regval);
130     divider = (6 == divider) ? 8 : divider;
131     clock = clock_tbl[divider >> 1];
132     regval |= (clock << ((peripheral_id & 0xF) << 1));   
133     HAL_WRITE_UINT32(CYGARC_HAL_LPC24XX_REG_SCB_BASE + pclkselreg, regval);             
134 }
135
136
137 //===========================================================================
138 // initialize timer 0 as eCos realtime clock source
139 //===========================================================================
140 void hal_clock_initialize(cyg_uint32 period)
141 {
142     CYG_ADDRESS timer = CYGARC_HAL_LPC24XX_REG_TIMER0_BASE;
143
144     period = period / (CYGNUM_HAL_ARM_LPC24XX_CLOCK_SPEED / 
145                        hal_lpc_get_pclk(CYNUM_HAL_LPC24XX_PCLK_TIMER0));
146
147     // 
148     // Disable and reset counter, set prescale register to 0 and
149     // Set up match register 
150     //
151     HAL_WRITE_UINT32(timer + CYGARC_HAL_LPC24XX_REG_TxTCR, 2);
152     HAL_WRITE_UINT32(timer + CYGARC_HAL_LPC24XX_REG_TxPR, 0);
153     HAL_WRITE_UINT32(timer + CYGARC_HAL_LPC24XX_REG_TxMR0, period);
154     
155     //
156     // Reset and generate interrupt on match and Enable counter
157     //
158     HAL_WRITE_UINT32(timer + CYGARC_HAL_LPC24XX_REG_TxMCR, 
159                      CYGARC_HAL_LPC24XX_REG_TxMCR_MR0_INT | 
160                      CYGARC_HAL_LPC24XX_REG_TxMCR_MR0_RESET);
161     HAL_WRITE_UINT32(timer+CYGARC_HAL_LPC24XX_REG_TxTCR, 1);
162 }
163
164
165 //===========================================================================
166 // Reset clock
167 //===========================================================================
168 void hal_clock_reset(cyg_uint32 vector, cyg_uint32 period)
169 {
170     static cyg_uint32 _period = 0;
171     CYG_ADDRESS        timer  = CYGARC_HAL_LPC24XX_REG_TIMER0_BASE;
172
173     HAL_WRITE_UINT32(timer + CYGARC_HAL_LPC24XX_REG_TxIR, 
174                      CYGARC_HAL_LPC24XX_REG_TxIR_MR0);  // Clear interrupt
175
176     if (period != _period) 
177     {
178         hal_clock_initialize(period);
179     }
180     _period = period;
181 }
182
183
184 //===========================================================================
185 // Reset clock value
186 //===========================================================================
187 void hal_clock_read(cyg_uint32 *pvalue)
188 {
189     CYG_ADDRESS timer = CYGARC_HAL_LPC24XX_REG_TIMER0_BASE;
190     cyg_uint32 val;
191
192     HAL_READ_UINT32(timer + CYGARC_HAL_LPC24XX_REG_TxTC, val);
193     *pvalue = val;
194 }
195
196
197 //===========================================================================
198 // Delay for some number of micro-seconds - use TIMER1
199 //===========================================================================
200 void hal_delay_us(cyg_int32 usecs)
201 {
202     CYG_ADDRESS timer = CYGARC_HAL_LPC24XX_REG_TIMER1_BASE;
203     cyg_uint32 stat;
204     cyg_uint64 ticks;
205
206     // Calculate how many timer ticks the required number of
207     // microseconds equate to. We do this calculation in 64 bit
208     // arithmetic to avoid overflow.
209     ticks = (((cyg_uint64)usecs) * 
210              ((cyg_uint64)hal_lpc_get_pclk(CYNUM_HAL_LPC24XX_PCLK_TIMER1))) / 
211                1000000LL;
212     
213     // Disable and reset counter
214     HAL_WRITE_UINT32(timer+CYGARC_HAL_LPC24XX_REG_TxTCR, 2);
215     
216     // Stop on match
217     HAL_WRITE_UINT32(timer+CYGARC_HAL_LPC24XX_REG_TxMR0, ticks);
218     HAL_WRITE_UINT32(timer+CYGARC_HAL_LPC24XX_REG_TxMCR, 
219                      CYGARC_HAL_LPC24XX_REG_TxMCR_MR0_STOP | 
220                      CYGARC_HAL_LPC24XX_REG_TxMCR_MR0_RESET);
221
222     //set prescale register to 0
223     HAL_WRITE_UINT32(timer+CYGARC_HAL_LPC24XX_REG_TxPR, 0);         
224
225     // Enable counter
226     HAL_WRITE_UINT32(timer+CYGARC_HAL_LPC24XX_REG_TxTCR, 1);
227
228     // Wait for the match
229     do {
230         HAL_READ_UINT32(timer+CYGARC_HAL_LPC24XX_REG_TxTC, stat);
231     } while (stat < ticks);
232 }
233
234
235 //===========================================================================
236 // Perform variant setup. This optionally calls into the platform
237 // HAL if it has defined HAL_PLF_HARDWARE_INIT.
238 //===========================================================================
239 void hal_hardware_init(void)
240 {
241     cyg_uint32 i; 
242     
243     //
244     // Setup peripheral clocks here according to configuration
245     // 
246     hal_lpc_set_pclk(CYNUM_HAL_LPC24XX_PCLK_CAN1, CYGNUM_HAL_ARM_LPC24XX_CAN_CLK_DIV);
247     hal_lpc_set_pclk(CYNUM_HAL_LPC24XX_PCLK_CAN2, CYGNUM_HAL_ARM_LPC24XX_CAN_CLK_DIV);
248     hal_lpc_set_pclk(CYNUM_HAL_LPC24XX_PCLK_ACF,  CYGNUM_HAL_ARM_LPC24XX_CAN_CLK_DIV);
249     
250     //
251     // Fill vector address registers with interrupt number. If an interrupt
252     // occurs we can simply read the interrupt number from the vector
253     // address register later
254     //
255     cyg_uint32 addr = CYGARC_HAL_LPC24XX_REG_VIC_BASE + 
256                       CYGARC_HAL_LPC24XX_REG_VICVECTADDR0;    
257     for (i = 0; i < 32; ++i)
258     {
259         HAL_WRITE_UINT32(addr, i);
260         addr += 4;
261     }
262 #ifdef HAL_PLF_HARDWARE_INIT
263     // Perform any platform specific initializations
264     HAL_PLF_HARDWARE_INIT();
265 #endif
266
267     // Set up eCos/ROM interfaces
268     hal_if_init();
269 }
270
271
272 //===========================================================================
273 // This routine is called to respond to a hardware interrupt (IRQ).  It
274 // should interrogate the hardware and return the IRQ vector number.
275 //===========================================================================
276 int hal_IRQ_handler(void)
277 {
278     cyg_uint32 irq_num;
279     
280     HAL_READ_UINT32(CYGARC_HAL_LPC24XX_REG_VIC_BASE + 
281                     CYGARC_HAL_LPC24XX_REG_VICVECTADDR, irq_num);
282        
283     return (irq_num);
284 }
285
286
287 //===========================================================================
288 // Block the interrupt associated with the vector
289 //===========================================================================
290 void hal_interrupt_mask(int vector)
291 {
292     CYG_ASSERT(vector <= CYGNUM_HAL_ISR_MAX &&
293                vector >= CYGNUM_HAL_ISR_MIN , "Invalid vector");
294
295     HAL_WRITE_UINT32(CYGARC_HAL_LPC24XX_REG_VIC_BASE + 
296                      CYGARC_HAL_LPC24XX_REG_VICINTENCLEAR, 1 << vector);
297 }
298
299
300 //===========================================================================
301 // Unblock the interrupt associated with the vector
302 //===========================================================================
303 void hal_interrupt_unmask(int vector)
304 {
305     CYG_ASSERT(vector <= CYGNUM_HAL_ISR_MAX &&
306                vector >= CYGNUM_HAL_ISR_MIN , "Invalid vector");
307
308     HAL_WRITE_UINT32(CYGARC_HAL_LPC24XX_REG_VIC_BASE + 
309                      CYGARC_HAL_LPC24XX_REG_VICINTENABLE, 1 << vector);
310 }
311
312
313 //===========================================================================
314 // Acknowledge the interrupt associated with the vector. This
315 // clears the interrupt but may result in another interrupt being
316 // delivered
317 //===========================================================================
318 void hal_interrupt_acknowledge(int vector)
319 {
320
321     // External interrupts have to be cleared from the EXTINT register
322     if (vector >= CYGNUM_HAL_INTERRUPT_EINT0 &&
323         vector <= CYGNUM_HAL_INTERRUPT_EINT3)
324     {
325         // Map int vector to corresponding bit (0..3)
326         vector = 1 << (vector - CYGNUM_HAL_INTERRUPT_EINT0);
327         
328         // Clear the external interrupt
329         HAL_WRITE_UINT32(CYGARC_HAL_LPC24XX_REG_SCB_BASE + 
330                          CYGARC_HAL_LPC24XX_REG_EXTINT, vector);
331     }
332     
333     // 
334     // Write any value to vector address register to
335     // acknowledge the interrupt
336     //
337     HAL_WRITE_UINT32(CYGARC_HAL_LPC24XX_REG_VIC_BASE + 
338                      CYGARC_HAL_LPC24XX_REG_VICVECTADDR, 0xFFFFFFFF);  
339 }
340
341
342 //===========================================================================
343 // This provides control over how an interrupt signal is detected.
344 // Options are between level or edge sensitive (level) and high/low
345 // level or rising/falling edge triggered (up).
346 //===========================================================================
347 void hal_interrupt_configure(int vector, int level, int up)
348 {
349     cyg_uint32 regval;
350
351     // Only external interrupts are configurable    
352     CYG_ASSERT(vector <= CYGNUM_HAL_INTERRUPT_EINT3 &&
353                vector >= CYGNUM_HAL_INTERRUPT_EINT0 , "Invalid vector");
354
355     // Map int vector to corresponding bit (0..3)
356     vector = 1 << (vector - CYGNUM_HAL_INTERRUPT_EINT0);
357     
358     // Read current mode and update for level (0) or edge detection (1)
359     HAL_READ_UINT32(CYGARC_HAL_LPC24XX_REG_SCB_BASE + 
360                     CYGARC_HAL_LPC24XX_REG_EXTMODE, regval);
361     if (level)
362     {
363       regval &= ~vector;
364     }
365     else
366     {
367       regval |= vector;
368     }
369     HAL_WRITE_UINT32(CYGARC_HAL_LPC24XX_REG_SCB_BASE + 
370                      CYGARC_HAL_LPC24XX_REG_EXTMODE, regval);
371     
372     // Read current polarity and update for trigger level or edge
373     // level: high (1), low (0) edge: rising (1), falling (0)
374     HAL_READ_UINT32(CYGARC_HAL_LPC24XX_REG_SCB_BASE + 
375                     CYGARC_HAL_LPC24XX_REG_EXTPOLAR, regval);
376     if (up)
377     {
378       regval |= vector;
379     }
380     else
381     {
382       regval &= ~vector;
383     }
384     HAL_WRITE_UINT32(CYGARC_HAL_LPC24XX_REG_SCB_BASE + 
385                      CYGARC_HAL_LPC24XX_REG_EXTPOLAR, regval);
386
387     // Clear any spurious interrupt that might have been generated
388     HAL_WRITE_UINT32(CYGARC_HAL_LPC24XX_REG_SCB_BASE + 
389                      CYGARC_HAL_LPC24XX_REG_EXTINT, vector);
390 }
391
392
393 //===========================================================================
394 // These selects select a priority level for the 32 vectored IRQs. 
395 // There are 16 priority levels, corresponding to the values 0 
396 // through 15 decimal, of which 15 is the lowest priority.
397 // The reset value of these registers defaults all interrupt to the 
398 // lowest priority, allowing a single write to elevate the priority 
399 // of an individual interrupt.
400 //===========================================================================
401 void hal_interrupt_set_level(int vector, int level)
402 {
403     CYG_ASSERT(vector <= CYGNUM_HAL_ISR_MAX &&
404                vector >= CYGNUM_HAL_ISR_MIN , "Invalid vector");
405     CYG_ASSERT(level >= 0 && level <= 15, "Invalid level");
406        
407     cyg_uint32 prioreg_addr = CYGARC_HAL_LPC24XX_REG_VIC_BASE + 
408                               CYGARC_HAL_LPC24XX_REG_VICVECTPRIO0 + 
409                               (vector << 2);                   
410     HAL_WRITE_UINT32(prioreg_addr, level & 0xF);
411 }
412
413
414 //===========================================================================
415 // Use the watchdog to generate a reset
416 //===========================================================================
417 void hal_lpc_watchdog_reset(void)
418 {
419     HAL_WRITE_UINT32(CYGARC_HAL_LPC24XX_REG_WD_BASE + 
420                      CYGARC_HAL_LPC24XX_REG_WDTC, 0xFF);
421     HAL_WRITE_UINT32(CYGARC_HAL_LPC24XX_REG_WD_BASE + 
422                      CYGARC_HAL_LPC24XX_REG_WDMOD, 
423                      CYGARC_HAL_LPC24XX_REG_WDMOD_WDEN | 
424                      CYGARC_HAL_LPC24XX_REG_WDMOD_WDRESET);
425
426     // feed WD with the two magic values
427     HAL_WRITE_UINT32(CYGARC_HAL_LPC24XX_REG_WD_BASE + 
428                      CYGARC_HAL_LPC24XX_REG_WDFEED, 
429                      CYGARC_HAL_LPC24XX_REG_WDFEED_MAGIC1); 
430     HAL_WRITE_UINT32(CYGARC_HAL_LPC24XX_REG_WD_BASE + 
431                      CYGARC_HAL_LPC24XX_REG_WDFEED, 
432                      CYGARC_HAL_LPC24XX_REG_WDFEED_MAGIC2);
433     
434     while(1)
435       continue;
436 }
437
438
439 //--------------------------------------------------------------------------
440 // EOF lpc24xx_misc.c