📄 iq80310_misc.c
字号:
//==========================================================================//// iq80310_misc.c//// HAL misc board support code for XScale IQ80310////==========================================================================//####COPYRIGHTBEGIN####// // ------------------------------------------- // The contents of this file are subject to the Red Hat eCos Public License // Version 1.1 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at // http://www.redhat.com/ // // Software distributed under the License is distributed on an "AS IS" // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the // License for the specific language governing rights and limitations under // the License. // // The Original Code is eCos - Embedded Configurable Operating System, // released September 30, 1998. // // The Initial Developer of the Original Code is Red Hat. // Portions created by Red Hat are // Copyright (C) 1998, 1999, 2000, 2001 Red Hat, Inc. // All Rights Reserved. // ------------------------------------------- // //####COPYRIGHTEND####//==========================================================================//#####DESCRIPTIONBEGIN####//// Author(s): msalter// Contributors: msalter// Date: 2000-10-10// Purpose: HAL board support// Description: Implementations of HAL board interfaces////####DESCRIPTIONEND####////========================================================================*/#include <pkgconf/hal.h>#include <pkgconf/system.h>#include CYGBLD_HAL_PLATFORM_H#include CYGHWR_MEMORY_LAYOUT_H#include <cyg/infra/cyg_type.h> // base types#include <cyg/infra/cyg_trac.h> // tracing macros#include <cyg/infra/cyg_ass.h> // assertion macros#include <cyg/hal/hal_io.h> // IO macros#include <cyg/hal/hal_stub.h> // Stub macros#include <cyg/hal/hal_if.h> // calling interface API#include <cyg/hal/hal_arch.h> // Register state info#include <cyg/hal/hal_diag.h>#include <cyg/hal/hal_intr.h> // Interrupt names#include <cyg/hal/hal_cache.h>#include <cyg/hal/hal_iq80310.h> // Hardware definitions#include <cyg/infra/diag.h> // diag_printf#include <cyg/hal/drv_api.h> // CYG_ISR_HANDLEDstatic cyg_uint32 nfiq_ISR(cyg_vector_t vector, cyg_addrword_t data);static cyg_uint32 nirq_ISR(cyg_vector_t vector, cyg_addrword_t data);static cyg_uint32 nmi_mcu_ISR(cyg_vector_t vector, cyg_addrword_t data);static cyg_uint32 nmi_patu_ISR(cyg_vector_t vector, cyg_addrword_t data);static cyg_uint32 nmi_satu_ISR(cyg_vector_t vector, cyg_addrword_t data);static cyg_uint32 nmi_pb_ISR(cyg_vector_t vector, cyg_addrword_t data);static cyg_uint32 nmi_sb_ISR(cyg_vector_t vector, cyg_addrword_t data);// Some initialization has already been done before we get here.//// Set up the interrupt environment.// Set up the MMU so that we can use caches.// Enable caches.// - All done!void hal_hardware_init(void){ unsigned rtmp = 0; // Route INTA-INTD to IRQ pin // The Yavapai manual is incorrect in that a '1' value // routes to the IRQ line, not a '0' value. *PIRSR_REG = 0x0f; // Disable all interrupt sources: *IIMR_REG = 0x7f; *OIMR_REG = 0x7f; // don't mask INTD which is really xint3 *X3MASK_REG = XINT3_TIMER | XINT3_ETHERNET | XINT3_UART_1 | \ XINT3_UART_2 | XINT3_PCI_INTD; // Let the timer run at a default rate (for delays) hal_clock_initialize(CYGNUM_HAL_RTC_PERIOD); // Set up eCos/ROM interfaces hal_if_init(); // attach some builtin interrupt handlers HAL_INTERRUPT_ATTACH (CYGNUM_HAL_INTERRUPT_NIRQ, &nirq_ISR, CYGNUM_HAL_INTERRUPT_NIRQ, 0); HAL_INTERRUPT_UNMASK (CYGNUM_HAL_INTERRUPT_NIRQ); HAL_INTERRUPT_ATTACH (CYGNUM_HAL_INTERRUPT_NFIQ, &nfiq_ISR, CYGNUM_HAL_INTERRUPT_NFIQ, 0); HAL_INTERRUPT_UNMASK (CYGNUM_HAL_INTERRUPT_NFIQ); HAL_INTERRUPT_ATTACH (CYGNUM_HAL_INTERRUPT_MCU_ERR, &nmi_mcu_ISR, CYGNUM_HAL_INTERRUPT_MCU_ERR, 0); HAL_INTERRUPT_UNMASK (CYGNUM_HAL_INTERRUPT_MCU_ERR); HAL_INTERRUPT_ATTACH (CYGNUM_HAL_INTERRUPT_PATU_ERR, &nmi_patu_ISR, CYGNUM_HAL_INTERRUPT_PATU_ERR, 0); HAL_INTERRUPT_UNMASK (CYGNUM_HAL_INTERRUPT_PATU_ERR); HAL_INTERRUPT_ATTACH (CYGNUM_HAL_INTERRUPT_SATU_ERR, &nmi_satu_ISR, CYGNUM_HAL_INTERRUPT_SATU_ERR, 0); HAL_INTERRUPT_UNMASK (CYGNUM_HAL_INTERRUPT_SATU_ERR); HAL_INTERRUPT_ATTACH (CYGNUM_HAL_INTERRUPT_PBDG_ERR, &nmi_pb_ISR, CYGNUM_HAL_INTERRUPT_PBDG_ERR, 0); HAL_INTERRUPT_UNMASK (CYGNUM_HAL_INTERRUPT_PBDG_ERR); HAL_INTERRUPT_ATTACH (CYGNUM_HAL_INTERRUPT_SBDG_ERR, &nmi_sb_ISR, CYGNUM_HAL_INTERRUPT_SBDG_ERR, 0); HAL_INTERRUPT_UNMASK (CYGNUM_HAL_INTERRUPT_SBDG_ERR); // Enable FIQ#if 0 asm volatile ("mrs %0,cpsr\n" "bic %0,%0,#0x40\n" "msr cpsr,%0\n" : "=r"(rtmp) : );#endif}#include CYGHWR_MEMORY_LAYOUT_Htypedef void code_fun(void);void __attribute__ ((naked)) iq80310_program_new_stack(void *func){ asm volatile ("mov r12,sp\n" "stmdb sp!, {r4, r12, lr, pc}\n" "sub r4,r12, #4\n" "mov r12,#0xa0000000\n" "add sp,r12,#0x1000000\n" "mov lr,pc\n" "mov pc,r0\n" "ldmdb r4, {r4, sp, pc}\n"); return;}// -------------------------------------------------------------------------// Clock can come from the PMU or from an external timer.// The external timer is the preferred choice.#if CYGNUM_HAL_INTERRUPT_RTC == CYGNUM_HAL_INTERRUPT_PMU_CCNT_OVFL// Proper version that uses the clock counter in the PMU to do proper// interrupts that require acknowledgement and all that good stuff.static cyg_uint32 hal_clock_init_period; // The START value, it counts upvoid hal_clock_initialize(cyg_uint32 period){ // event types both zero; clear all 3 interrupts; // disable all 3 counter interrupts; // CCNT counts every processor cycle; reset all counters; // enable PMU. register cyg_uint32 init = 0x00000707; asm volatile ( "mcr p14,0,%0,c0,c0,0;" // write into PMNC : : "r"(init) /*:*/ ); // the CCNT in the PMU counts *up* then interrupts at overflow // ie. at 0x1_0000_0000 as it were. // So init to 0xffffffff - period + 1 to get the right answer. period = (~period) + 1; hal_clock_init_period = period; hal_clock_reset( 0, 0 );}// This routine is called during a clock interrupt.// (before acknowledging the interrupt)void hal_clock_reset(cyg_uint32 vector, cyg_uint32 period){ asm volatile ( "mrc p14,0,r0,c1,c0,0;" // read from CCNT - how long since OVFL "add %0, %0, r0;" // synchronize with previous overflow "mcr p14,0,%0,c1,c0,0;" // write into CCNT : : "r"(hal_clock_init_period) : "r0" );}// Read the current value of the clock, returning the number of hardware// "ticks" that have occurred (i.e. how far away the current value is from// the start)void hal_clock_read(cyg_uint32 *pvalue){ register cyg_uint32 now; asm volatile ( "mrc p14,0,%0,c1,c0,0;" // read from CCNT : "=r"(now) : /*:*/ ); *pvalue = now - hal_clock_init_period;}// Delay for some usecs.void hal_delay_us(cyg_uint32 delay){ int i; // the loop is going to take 3 ticks. At 600 MHz, to give uS, multiply // by 600/3 = 200. No volatile is needed on i; gcc recognizes delay // loops and does NOT elide them. for ( i = 200 * delay; i ; i--) ;}#else // external timerstatic cyg_uint32 _period;void hal_clock_initialize(cyg_uint32 period){ _period = period; // disable timer EXT_TIMER_INT_DISAB(); EXT_TIMER_CNT_DISAB(); *TIMER_LA0_REG_ADDR = period; *TIMER_LA1_REG_ADDR = period >> 8; *TIMER_LA2_REG_ADDR = period >> 16; EXT_TIMER_INT_ENAB(); EXT_TIMER_CNT_ENAB();}// This routine is called during a clock interrupt.void hal_clock_reset(cyg_uint32 vector, cyg_uint32 period){ // to clear the timer interrupt, clear the timer interrupt // enable, then re-set the int. enable bit EXT_TIMER_INT_DISAB(); EXT_TIMER_INT_ENAB();}// Read the current value of the clock, returning the number of hardware// "ticks" that have occurred (i.e. how far away the current value is from// the start)void hal_clock_read(cyg_uint32 *pvalue){ cyg_uint8 cnt0, cnt1, cnt2, cnt3; cyg_uint32 timer_val;; // first read latches the count // Actually, it looks like there is a hardware problem where // invalid counts get latched. This do while loop appears // to get around the problem. do { cnt0 = *TIMER_LA0_REG_ADDR & TIMER_COUNT_MASK; } while (cnt0 == 0); cnt1 = *TIMER_LA1_REG_ADDR & TIMER_COUNT_MASK; cnt2 = *TIMER_LA2_REG_ADDR & TIMER_COUNT_MASK; cnt3 = *TIMER_LA3_REG_ADDR & 0xf; /* only 4 bits in most sig. */ /* now build up the count value */ timer_val = ((cnt0 & 0x40) >> 1) | (cnt0 & 0x1f); timer_val |= (((cnt1 & 0x40) >> 1) | (cnt1 & 0x1f)) << 6; timer_val |= (((cnt2 & 0x40) >> 1) | (cnt2 & 0x1f)) << 12; timer_val |= cnt3 << 18; *pvalue = timer_val;}// Delay for some usecs.void hal_delay_us(cyg_uint32 delay){#define _CNT_MASK 0x3fffff#define _TICKS_PER_USEC (EXT_TIMER_CLK_FREQ / 1000000) cyg_uint32 now, last, diff, ticks; hal_clock_read(&last); diff = ticks = 0; while (delay > ticks) { hal_clock_read(&now); if (now < last) diff += ((_period - last) + now); else diff += (now - last); last = now; if (diff >= _TICKS_PER_USEC) { ticks += (diff / _TICKS_PER_USEC); diff %= _TICKS_PER_USEC; } }}#endif// -------------------------------------------------------------------------typedef cyg_uint32 cyg_ISR(cyg_uint32 vector, CYG_ADDRWORD data);extern void cyg_interrupt_post_dsr( CYG_ADDRWORD intr_obj );static inline cyg_uint32hal_call_isr (cyg_uint32 vector){ cyg_ISR *isr; CYG_ADDRWORD data; cyg_uint32 isr_ret; isr = (cyg_ISR*) hal_interrupt_handlers[vector]; data = hal_interrupt_data[vector]; isr_ret = (*isr) (vector, data);#ifdef CYGFUN_HAL_COMMON_KERNEL_SUPPORT if (isr_ret & CYG_ISR_CALL_DSR) { cyg_interrupt_post_dsr (hal_interrupt_objects[vector]); }#endif return isr_ret & ~CYG_ISR_CALL_DSR;}void _scrub_ecc(unsigned p){ asm volatile ("ldrb r4, [%0]\n" "strb r4, [%0]\n" : : "r"(p) );}static cyg_uint32 nmi_mcu_ISR(cyg_vector_t vector, cyg_addrword_t data){ cyg_uint32 eccr_reg; // Read current state of ECC register eccr_reg = *ECCR_REG; // Turn off all ecc error reporting *ECCR_REG = 0x4; // Check for ECC Error 0 if(*MCISR_REG & 0x1) { #ifdef DEBUG_NMI diag_printf("ELOG0 = 0x%X\n", *ELOG0_REG); diag_printf("ECC Error Detected at Address 0x%X\n",*ECAR0_REG); #endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -