📄 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_HANDLED
static 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_H
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;
}
/*------------------------------------------------------------------------*/
//
// Memory layout
//
externC cyg_uint8 *
hal_arm_mem_real_region_top( cyg_uint8 *regionend )
{
CYG_ASSERT( hal_dram_size > 0, "Didn't detect DRAM size!" );
CYG_ASSERT( hal_dram_size <= 512<<20,
"More than 512MB reported - that can't be right" );
// is it the "normal" end of the DRAM region? If so, it should be
// replaced by the real size
if ( regionend ==
((cyg_uint8 *)CYGMEM_REGION_ram + CYGMEM_REGION_ram_SIZE) ) {
regionend = (cyg_uint8 *)CYGMEM_REGION_ram + hal_dram_size;
}
return regionend;
} // hal_arm_mem_real_region_top()
// -------------------------------------------------------------------------
// 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 up
void 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 timer
static 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_uint32
hal_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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -