1 /*==========================================================================
5 // HAL misc variant support code for NXP LPC24xx
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
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.
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
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.
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.
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####
42 // Author(s): Uwe Kindler
43 // Contributors: gthomas, jskov, nickg, tkoeller
45 // Purpose: Prozessor support
46 // Description: Implementations of LPC24xx processor support
48 //####DESCRIPTIONEND####
50 //========================================================================*/
53 //===========================================================================
55 //===========================================================================
56 #include <pkgconf/hal.h>
57 #include <pkgconf/hal_arm_lpc24xx.h>
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
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
73 #include <cyg/hal/var_io.h> // platform registers
75 #include <cyg/infra/diag.h> // For diagnostic printing
78 //===========================================================================
79 // Get peripheral clock for a certain peripheral
80 //===========================================================================
81 cyg_uint32 hal_lpc_get_pclk(cyg_uint32 peripheral_id)
83 static const cyg_uint8 divider_tbl[4] =
87 cyg_uint32 pclkselreg;
92 // decide if we need PCLKSEL0 or PCLKSEL1
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))
105 return CYGNUM_HAL_ARM_LPC24XX_CLOCK_SPEED / divider;
109 //===========================================================================
110 // Set peripheral clock
111 //===========================================================================
112 void hal_lpc_set_pclk(cyg_uint32 peripheral_id, cyg_uint8 divider)
114 static const cyg_uint8 clock_tbl[4] =
116 0x01, 0x02, 0x00, 0x03
119 cyg_uint32 pclkselreg;
122 CYG_ASSERT(divider <= 8, "Wrong peripheral clock divider value");
124 // decide if we need PCLKSEL0 or PCLKSEL1
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);
137 //===========================================================================
138 // initialize timer 0 as eCos realtime clock source
139 //===========================================================================
140 void hal_clock_initialize(cyg_uint32 period)
142 CYG_ADDRESS timer = CYGARC_HAL_LPC24XX_REG_TIMER0_BASE;
144 period = period / (CYGNUM_HAL_ARM_LPC24XX_CLOCK_SPEED /
145 hal_lpc_get_pclk(CYNUM_HAL_LPC24XX_PCLK_TIMER0));
148 // Disable and reset counter, set prescale register to 0 and
149 // Set up match register
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);
156 // Reset and generate interrupt on match and Enable counter
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);
165 //===========================================================================
167 //===========================================================================
168 void hal_clock_reset(cyg_uint32 vector, cyg_uint32 period)
170 static cyg_uint32 _period = 0;
171 CYG_ADDRESS timer = CYGARC_HAL_LPC24XX_REG_TIMER0_BASE;
173 HAL_WRITE_UINT32(timer + CYGARC_HAL_LPC24XX_REG_TxIR,
174 CYGARC_HAL_LPC24XX_REG_TxIR_MR0); // Clear interrupt
176 if (period != _period)
178 hal_clock_initialize(period);
184 //===========================================================================
186 //===========================================================================
187 void hal_clock_read(cyg_uint32 *pvalue)
189 CYG_ADDRESS timer = CYGARC_HAL_LPC24XX_REG_TIMER0_BASE;
192 HAL_READ_UINT32(timer + CYGARC_HAL_LPC24XX_REG_TxTC, val);
197 //===========================================================================
198 // Delay for some number of micro-seconds - use TIMER1
199 //===========================================================================
200 void hal_delay_us(cyg_int32 usecs)
202 CYG_ADDRESS timer = CYGARC_HAL_LPC24XX_REG_TIMER1_BASE;
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))) /
213 // Disable and reset counter
214 HAL_WRITE_UINT32(timer+CYGARC_HAL_LPC24XX_REG_TxTCR, 2);
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);
222 //set prescale register to 0
223 HAL_WRITE_UINT32(timer+CYGARC_HAL_LPC24XX_REG_TxPR, 0);
226 HAL_WRITE_UINT32(timer+CYGARC_HAL_LPC24XX_REG_TxTCR, 1);
228 // Wait for the match
230 HAL_READ_UINT32(timer+CYGARC_HAL_LPC24XX_REG_TxTC, stat);
231 } while (stat < ticks);
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)
244 // Setup peripheral clocks here according to configuration
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);
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
255 cyg_uint32 addr = CYGARC_HAL_LPC24XX_REG_VIC_BASE +
256 CYGARC_HAL_LPC24XX_REG_VICVECTADDR0;
257 for (i = 0; i < 32; ++i)
259 HAL_WRITE_UINT32(addr, i);
262 #ifdef HAL_PLF_HARDWARE_INIT
263 // Perform any platform specific initializations
264 HAL_PLF_HARDWARE_INIT();
267 // Set up eCos/ROM interfaces
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)
280 HAL_READ_UINT32(CYGARC_HAL_LPC24XX_REG_VIC_BASE +
281 CYGARC_HAL_LPC24XX_REG_VICVECTADDR, irq_num);
287 //===========================================================================
288 // Block the interrupt associated with the vector
289 //===========================================================================
290 void hal_interrupt_mask(int vector)
292 CYG_ASSERT(vector <= CYGNUM_HAL_ISR_MAX &&
293 vector >= CYGNUM_HAL_ISR_MIN , "Invalid vector");
295 HAL_WRITE_UINT32(CYGARC_HAL_LPC24XX_REG_VIC_BASE +
296 CYGARC_HAL_LPC24XX_REG_VICINTENCLEAR, 1 << vector);
300 //===========================================================================
301 // Unblock the interrupt associated with the vector
302 //===========================================================================
303 void hal_interrupt_unmask(int vector)
305 CYG_ASSERT(vector <= CYGNUM_HAL_ISR_MAX &&
306 vector >= CYGNUM_HAL_ISR_MIN , "Invalid vector");
308 HAL_WRITE_UINT32(CYGARC_HAL_LPC24XX_REG_VIC_BASE +
309 CYGARC_HAL_LPC24XX_REG_VICINTENABLE, 1 << vector);
313 //===========================================================================
314 // Acknowledge the interrupt associated with the vector. This
315 // clears the interrupt but may result in another interrupt being
317 //===========================================================================
318 void hal_interrupt_acknowledge(int vector)
321 // External interrupts have to be cleared from the EXTINT register
322 if (vector >= CYGNUM_HAL_INTERRUPT_EINT0 &&
323 vector <= CYGNUM_HAL_INTERRUPT_EINT3)
325 // Map int vector to corresponding bit (0..3)
326 vector = 1 << (vector - CYGNUM_HAL_INTERRUPT_EINT0);
328 // Clear the external interrupt
329 HAL_WRITE_UINT32(CYGARC_HAL_LPC24XX_REG_SCB_BASE +
330 CYGARC_HAL_LPC24XX_REG_EXTINT, vector);
334 // Write any value to vector address register to
335 // acknowledge the interrupt
337 HAL_WRITE_UINT32(CYGARC_HAL_LPC24XX_REG_VIC_BASE +
338 CYGARC_HAL_LPC24XX_REG_VICVECTADDR, 0xFFFFFFFF);
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)
351 // Only external interrupts are configurable
352 CYG_ASSERT(vector <= CYGNUM_HAL_INTERRUPT_EINT3 &&
353 vector >= CYGNUM_HAL_INTERRUPT_EINT0 , "Invalid vector");
355 // Map int vector to corresponding bit (0..3)
356 vector = 1 << (vector - CYGNUM_HAL_INTERRUPT_EINT0);
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);
369 HAL_WRITE_UINT32(CYGARC_HAL_LPC24XX_REG_SCB_BASE +
370 CYGARC_HAL_LPC24XX_REG_EXTMODE, regval);
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);
384 HAL_WRITE_UINT32(CYGARC_HAL_LPC24XX_REG_SCB_BASE +
385 CYGARC_HAL_LPC24XX_REG_EXTPOLAR, regval);
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);
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)
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");
407 cyg_uint32 prioreg_addr = CYGARC_HAL_LPC24XX_REG_VIC_BASE +
408 CYGARC_HAL_LPC24XX_REG_VICVECTPRIO0 +
410 HAL_WRITE_UINT32(prioreg_addr, level & 0xF);
414 //===========================================================================
415 // Use the watchdog to generate a reset
416 //===========================================================================
417 void hal_lpc_watchdog_reset(void)
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);
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);
439 //--------------------------------------------------------------------------
440 // EOF lpc24xx_misc.c