1 /*==========================================================================
5 // HAL misc variant support code for Philips LPC2xxx
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####
43 // Contributors: gthomas, jskov, nickg, tkoeller
45 // Purpose: HAL board support
46 // Description: Implementations of HAL board interfaces
48 //####DESCRIPTIONEND####
50 //========================================================================*/
52 #include <pkgconf/hal.h>
53 #include <pkgconf/hal_arm_lpc2xxx.h>
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
59 #include <cyg/hal/hal_io.h> // IO macros
60 #include <cyg/hal/hal_arch.h> // Register state info
61 #include <cyg/hal/hal_diag.h>
62 #include <cyg/hal/hal_intr.h> // necessary?
63 #include <cyg/hal/hal_cache.h>
64 #include <cyg/hal/hal_if.h> // calling interface
65 #include <cyg/hal/hal_misc.h> // helper functions
66 #ifdef CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT
67 #include <cyg/hal/drv_api.h> // HAL ISR support
69 #include <cyg/hal/var_io.h> // platform registers
71 #include <cyg/infra/diag.h> // For diagnostic printing
74 // -------------------------------------------------------------------------
77 static cyg_uint32 _period;
79 void hal_clock_initialize(cyg_uint32 period)
81 CYG_ADDRESS timer = CYGARC_HAL_LPC2XXX_REG_TIMER0_BASE;
83 period = period / (CYGNUM_HAL_ARM_LPC2XXX_CLOCK_SPEED / CYGNUM_HAL_ARM_LPC2XXX_PCLK);
85 // Disable and reset counter
86 HAL_WRITE_UINT32(timer+CYGARC_HAL_LPC2XXX_REG_TxTCR, 2);
88 // set prescale register to 0
89 HAL_WRITE_UINT32(timer+CYGARC_HAL_LPC2XXX_REG_TxPR, 0);
91 // Set up match register
92 HAL_WRITE_UINT32(timer+CYGARC_HAL_LPC2XXX_REG_TxMR0, period);
94 // Reset and generate interrupt on match
95 HAL_WRITE_UINT32(timer+CYGARC_HAL_LPC2XXX_REG_TxMCR,
96 CYGARC_HAL_LPC2XXX_REG_TxMCR_MR0_INT |
97 CYGARC_HAL_LPC2XXX_REG_TxMCR_MR0_RESET);
100 HAL_WRITE_UINT32(timer+CYGARC_HAL_LPC2XXX_REG_TxTCR, 1);
103 void hal_clock_reset(cyg_uint32 vector, cyg_uint32 period)
105 CYG_ADDRESS timer = CYGARC_HAL_LPC2XXX_REG_TIMER0_BASE;
107 HAL_WRITE_UINT32(timer+CYGARC_HAL_LPC2XXX_REG_TxIR,
108 CYGARC_HAL_LPC2XXX_REG_TxIR_MR0); // Clear interrupt
110 if (period != _period) {
111 hal_clock_initialize(period);
117 void hal_clock_read(cyg_uint32 *pvalue)
119 CYG_ADDRESS timer = CYGARC_HAL_LPC2XXX_REG_TIMER0_BASE;
122 HAL_READ_UINT32(timer+CYGARC_HAL_LPC2XXX_REG_TxTC, val);
126 // -------------------------------------------------------------------------
128 // Delay for some number of micro-seconds
131 void hal_delay_us(cyg_int32 usecs)
133 CYG_ADDRESS timer = CYGARC_HAL_LPC2XXX_REG_TIMER1_BASE;
137 // Calculate how many timer ticks the required number of
138 // microseconds equate to. We do this calculation in 64 bit
139 // arithmetic to avoid overflow.
140 ticks = CYGNUM_HAL_ARM_LPC2XXX_PCLK;
141 ticks = (((cyg_uint64)usecs) * (ticks))/1000000LL;
143 // Disable and reset counter
144 HAL_WRITE_UINT32(timer+CYGARC_HAL_LPC2XXX_REG_TxTCR, 2);
147 HAL_WRITE_UINT32(timer+CYGARC_HAL_LPC2XXX_REG_TxMR0, ticks);
148 HAL_WRITE_UINT32(timer+CYGARC_HAL_LPC2XXX_REG_TxMCR,
149 CYGARC_HAL_LPC2XXX_REG_TxMCR_MR0_STOP |
150 CYGARC_HAL_LPC2XXX_REG_TxMCR_MR0_RESET);
152 //set prescale register to 0
153 HAL_WRITE_UINT32(timer+CYGARC_HAL_LPC2XXX_REG_TxPR, 0);
156 HAL_WRITE_UINT32(timer+CYGARC_HAL_LPC2XXX_REG_TxTCR, 1);
158 // Wait for the match
160 HAL_READ_UINT32(timer+CYGARC_HAL_LPC2XXX_REG_TxTC, stat);
161 } while (stat < ticks);
164 // -------------------------------------------------------------------------
167 // Return value of VPBDIV register. According to errata doc
168 // we need to read twice consecutively to get correct value
169 cyg_uint32 lpc_get_vpbdiv(void)
171 cyg_uint32 vpbdiv_reg;
173 HAL_READ_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE +
174 CYGARC_HAL_LPC2XXX_REG_VPBDIV, vpbdiv_reg);
175 HAL_READ_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE +
176 CYGARC_HAL_LPC2XXX_REG_VPBDIV, vpbdiv_reg);
181 // Set the VPBDIV register. The vpb bits are 1:0 and the xclk bits are 5:4. The
182 // mapping of values passed to this routine to field values is:
183 // 4 = divide by 4 (register bits 00)
184 // 2 = divide by 2 (register bits 10)
185 // 1 = divide by 1 (register bits 01)
186 // This routine assumes that only these values can occur. As they are
187 // generated in the CDL hopefully this should be the case. Fortunately
188 // writing 11 merely causes the previous value to be retained.
189 void lpc_set_vpbdiv(int vpbdiv, int xclkdiv)
191 CYG_ASSERT(((vpbdiv & 0x3) != 3) && ((xclkdiv & 0x3) != 3),
192 "illegal VPBDIV register value");
194 // Update VPBDIV register
195 #ifdef CYGHWR_HAL_ARM_LPC2XXX_FAMILY_LPC22XX
196 HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE +
197 CYGARC_HAL_LPC2XXX_REG_VPBDIV,
198 ((xclkdiv & 0x3) << 4) | (vpbdiv & 0x3));
200 HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE +
201 CYGARC_HAL_LPC2XXX_REG_VPBDIV, vpbdiv & 0x3);
205 // Perform variant setup. This optionally calls into the platform
206 // HAL if it has defined HAL_PLF_HARDWARE_INIT.
207 void hal_hardware_init(void)
209 #ifdef CYGHWR_HAL_ARM_LPC2XXX_FAMILY_LPC22XX
210 lpc_set_vpbdiv(CYGNUM_HAL_ARM_LPC2XXX_VPBDIV,
211 CYGNUM_HAL_ARM_LPC2XXX_XCLKDIV);
213 lpc_set_vpbdiv(CYGNUM_HAL_ARM_LPC2XXX_VPBDIV, 1);
217 // 0xFFFFFFFF indicates that this is a non vectored ISR
218 // This is the default setting for all interrupts
220 HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_VIC_BASE +
221 CYGARC_HAL_LPC2XXX_REG_VICDEFVECTADDR, 0xFFFFFFFF);
223 #ifdef HAL_PLF_HARDWARE_INIT
224 // Perform any platform specific initializations
225 HAL_PLF_HARDWARE_INIT();
228 // Set up eCos/ROM interfaces
232 // -------------------------------------------------------------------------
233 // This routine is called to respond to a hardware interrupt (IRQ). It
234 // should interrogate the hardware and return the IRQ vector number.
235 int hal_IRQ_handler(void)
239 HAL_READ_UINT32(CYGARC_HAL_LPC2XXX_REG_VIC_BASE +
240 CYGARC_HAL_LPC2XXX_REG_VICVECTADDR, irq_num);
242 // if this is a non vectored ISR then we need to find out which interrupt
245 if (0xFFFFFFFF == irq_num)
249 // Find out which interrupt caused the IRQ. This picks the lowest
250 // if there are more than 1.
251 HAL_READ_UINT32(CYGARC_HAL_LPC2XXX_REG_VIC_BASE +
252 CYGARC_HAL_LPC2XXX_REG_VICIRQSTAT, irq_stat);
254 while (!(irq_stat & 0x01))
260 // If not a valid interrrupt source, treat as spurious interrupt
261 if (irq_num < CYGNUM_HAL_ISR_MIN || irq_num > CYGNUM_HAL_ISR_MAX)
263 irq_num = CYGNUM_HAL_INTERRUPT_NONE;
265 } // if (0xFFFFFFFF == irq_num)
270 // -------------------------------------------------------------------------
274 // Block the the interrupt associated with the vector
275 void hal_interrupt_mask(int vector)
277 CYG_ASSERT(vector <= CYGNUM_HAL_ISR_MAX &&
278 vector >= CYGNUM_HAL_ISR_MIN , "Invalid vector");
280 HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_VIC_BASE +
281 CYGARC_HAL_LPC2XXX_REG_VICINTENCLEAR, 1 << vector);
284 // Unblock the the interrupt associated with the vector
285 void hal_interrupt_unmask(int vector)
287 CYG_ASSERT(vector <= CYGNUM_HAL_ISR_MAX &&
288 vector >= CYGNUM_HAL_ISR_MIN , "Invalid vector");
290 HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_VIC_BASE +
291 CYGARC_HAL_LPC2XXX_REG_VICINTENABLE, 1 << vector);
294 // Acknowledge the the interrupt associated with the vector. This
295 // clears the interrupt but may result in another interrupt being
297 void hal_interrupt_acknowledge(int vector)
300 // External interrupts have to be cleared from the EXTINT register
301 if (vector >= CYGNUM_HAL_INTERRUPT_EINT0 &&
302 vector <= CYGNUM_HAL_INTERRUPT_EINT3)
304 // Map int vector to corresponding bit (0..3)
305 vector = 1 << (vector - CYGNUM_HAL_INTERRUPT_EINT0);
307 // Clear the external interrupt
308 HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE +
309 CYGARC_HAL_LPC2XXX_REG_EXTINT, vector);
312 // Acknowledge interrupt in the VIC
313 HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_VIC_BASE +
314 CYGARC_HAL_LPC2XXX_REG_VICVECTADDR, 0);
317 // This provides control over how an interrupt signal is detected.
318 // Options are between level or edge sensitive (level) and high/low
319 // level or rising/falling edge triggered (up).
321 // This should be simple, but unfortunately on some processor revisions,
322 // it trips up on two errata issues (for the LPC2294 Rev.A these are
323 // EXTINT.1 and VPBDIV.1) and so on these devices a somewhat convoluted
324 // sequence in order to work properly. There is nothing in the errata
325 // sequence that won't work on a processor without these issues.
326 void hal_interrupt_configure(int vector, int level, int up)
328 cyg_uint32 regval, saved_vpbdiv;
330 // Only external interrupts are configurable
331 CYG_ASSERT(vector <= CYGNUM_HAL_INTERRUPT_EINT3 &&
332 vector >= CYGNUM_HAL_INTERRUPT_EINT0 , "Invalid vector");
334 // Map int vector to corresponding bit (0..3)
335 vector = 1 << (vector - CYGNUM_HAL_INTERRUPT_EINT0);
337 #ifdef CYGHWR_HAL_ARM_LPC2XXX_EXTINT_ERRATA
338 // From discussions with the Philips applications engineers on the
339 // Yahoo LPC2000 forum, it appears that in order up change both
340 // EXTMODE and EXTPOLAR, the operations have to be performed in
341 // two passes as follows:
343 // VPBDIV=0, EXTMODE=n, VPBDIV=n, VPBDIV=0, EXTPOLAR=y, VPBDIV=y
346 // Save current VPBDIV register settings
347 saved_vpbdiv = lpc_get_vpbdiv();
349 // Clear VPBDIV register
350 HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE +
351 CYGARC_HAL_LPC2XXX_REG_VPBDIV, 0);
353 // Read current mode and update for level (0) or edge detection (1)
354 HAL_READ_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE +
355 CYGARC_HAL_LPC2XXX_REG_EXTMODE, regval);
360 HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE +
361 CYGARC_HAL_LPC2XXX_REG_EXTMODE, regval);
363 // Set VPBDIV register to same value as mode
364 HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE +
365 CYGARC_HAL_LPC2XXX_REG_VPBDIV, regval);
367 // Clear VPBDIV register
368 HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE +
369 CYGARC_HAL_LPC2XXX_REG_VPBDIV, 0);
371 // Read current polarity and update for trigger level or edge
372 // level: high (1), low (0) edge: rising (1), falling (0)
373 HAL_READ_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE +
374 CYGARC_HAL_LPC2XXX_REG_EXTPOLAR, regval);
379 HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE +
380 CYGARC_HAL_LPC2XXX_REG_EXTPOLAR, regval);
382 // Set VPBDIV register to same value as mode
383 HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE +
384 CYGARC_HAL_LPC2XXX_REG_VPBDIV, regval);
386 // Restore saved VPBDIV register
387 HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE +
388 CYGARC_HAL_LPC2XXX_REG_VPBDIV, saved_vpbdiv);
390 // Read current mode and update for level (0) or edge detection (1)
391 HAL_READ_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE +
392 CYGARC_HAL_LPC2XXX_REG_EXTMODE, regval);
397 HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE +
398 CYGARC_HAL_LPC2XXX_REG_EXTMODE, regval);
400 // Read current polarity and update for trigger level or edge
401 // level: high (1), low (0) edge: rising (1), falling (0)
402 HAL_READ_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE +
403 CYGARC_HAL_LPC2XXX_REG_EXTPOLAR, regval);
408 HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE +
409 CYGARC_HAL_LPC2XXX_REG_EXTPOLAR, regval);
411 // Clear any spurious interrupt that might have been generated
412 HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE +
413 CYGARC_HAL_LPC2XXX_REG_EXTINT, vector);
417 // We support up to 17 interrupt levels
418 // Interrupts 0 - 15 are vectored interrupt requests. Vectored IRQs have
419 // the higher priority then non vectored IRQs, but only 16 of the 32 requests
420 // can be assigned to this category. Any of the 32 requests can be assigned
421 // to any of the 16 vectored IRQ slots, among which slot 0 has the highest
422 // priority and slot 15 has the lowest. Priority 16 indicates a non vectored
425 void hal_interrupt_set_level(int vector, int level)
427 CYG_ASSERT(vector <= CYGNUM_HAL_ISR_MAX &&
428 vector >= CYGNUM_HAL_ISR_MIN , "Invalid vector");
429 CYG_ASSERT(level >= 0 && level <= 16, "Invalid level");
432 // If level is < 16 then this is a vectored ISR and we try to write
433 // the vector number of this ISR in the right slot of the vectored
434 // interrupt controller
438 cyg_uint32 addr_offset = level << 2;
441 HAL_READ_UINT32(CYGARC_HAL_LPC2XXX_REG_VIC_BASE +
442 CYGARC_HAL_LPC2XXX_REG_VICVECTCNTL0 +
443 addr_offset, reg_val);
444 CYG_ASSERT((reg_val == 0) || (reg_val == (vector | 0x20)),
445 "Priority already used by another vector");
446 HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_VIC_BASE +
447 CYGARC_HAL_LPC2XXX_REG_VICVECTCNTL0 +
448 addr_offset, vector | 0x20);
450 // We do not store the adress of the ISR here but we store the
451 // vector number The hal_IRQ_handler then can faster determine
452 // the right vector number
454 HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_VIC_BASE +
455 CYGARC_HAL_LPC2XXX_REG_VICVECTADDR0 +
456 addr_offset, vector);
460 // Use the watchdog to generate a reset
461 void hal_lpc_watchdog_reset(void)
463 HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_WD_BASE +
464 CYGARC_HAL_LPC2XXX_REG_WDTC, 0xFF);
465 HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_WD_BASE +
466 CYGARC_HAL_LPC2XXX_REG_WDMOD,
467 CYGARC_HAL_LPC2XXX_REG_WDMOD_WDEN |
468 CYGARC_HAL_LPC2XXX_REG_WDMOD_WDRESET);
470 // feed WD with the two magic values
471 HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_WD_BASE +
472 CYGARC_HAL_LPC2XXX_REG_WDFEED,
473 CYGARC_HAL_LPC2XXX_REG_WDFEED_MAGIC1);
474 HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_WD_BASE +
475 CYGARC_HAL_LPC2XXX_REG_WDFEED,
476 CYGARC_HAL_LPC2XXX_REG_WDFEED_MAGIC2);
482 #ifdef CYGPKG_DEVS_CAN_LPC2XXX
483 //===========================================================================
484 // Do varianat specific CAN initialisation
485 //===========================================================================
486 void hal_lpc_can_init(cyg_uint8 can_chan_no)
494 static const canpincfg canpincfg_tbl[] =
496 {0x00040000L, CYGARC_HAL_LPC2XXX_REG_PINSEL1},
497 {0x00014000L, CYGARC_HAL_LPC2XXX_REG_PINSEL1},
498 {0x00001800L, CYGARC_HAL_LPC2XXX_REG_PINSEL1},
499 {0x0F000000L, CYGARC_HAL_LPC2XXX_REG_PINSEL0},
502 CYG_ASSERT(can_chan_no < 4, "CAN channel number out of bounds");
503 canpincfg *pincfg = (canpincfg *)&canpincfg_tbl[can_chan_no];
506 HAL_READ_UINT32(CYGARC_HAL_LPC2XXX_REG_PIN_BASE + pincfg->reg, regval);
507 regval |= pincfg->pin_mask;
508 HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_PIN_BASE + pincfg->reg, regval);
510 #endif // CYGPKG_DEVS_CAN_LPC2XXX
512 //--------------------------------------------------------------------------