forked from Imagelibrary/rtems
Merged of mcp750 and mvme2307 BSP by Eric Valette <valette@crf.canon.fr>.
As part of this effort, the mpc750 libcpu code is now shared with the ppc6xx.
This commit is contained in:
@@ -20,10 +20,10 @@ INSTALL_CHANGE = @INSTALL_CHANGE@
|
|||||||
|
|
||||||
SHARED_LIB = shared
|
SHARED_LIB = shared
|
||||||
|
|
||||||
ifeq ($(RTEMS_CPU_MODEL),mpc750)
|
ifeq ($(RTEMS_PPC_EXCEPTION_PROCESSING_MODEL),new)
|
||||||
CPUDIR = mpc750
|
CPUDIR = new_exception_processing
|
||||||
else
|
else
|
||||||
CPUDIR = other_cpu
|
CPUDIR = old_exception_processing
|
||||||
endif
|
endif
|
||||||
|
|
||||||
SUBDIRS = $(CPUDIR) $(SHARED_LIB)
|
SUBDIRS = $(CPUDIR) $(SHARED_LIB)
|
||||||
|
|||||||
@@ -0,0 +1,90 @@
|
|||||||
|
#
|
||||||
|
# $Id$
|
||||||
|
#
|
||||||
|
|
||||||
|
@SET_MAKE@
|
||||||
|
srcdir = @srcdir@
|
||||||
|
top_srcdir = @top_srcdir@
|
||||||
|
top_builddir = ../..
|
||||||
|
subdir = powerpc/new_exception_processing
|
||||||
|
|
||||||
|
RTEMS_ROOT = @RTEMS_ROOT@
|
||||||
|
PROJECT_ROOT = @PROJECT_ROOT@
|
||||||
|
|
||||||
|
VPATH = @srcdir@
|
||||||
|
|
||||||
|
RELS = ../$(ARCH)/rtems-cpu.rel
|
||||||
|
|
||||||
|
# C source names, if any, go here -- minus the .c
|
||||||
|
C_PIECES = cpu
|
||||||
|
C_FILES = $(C_PIECES:%=%.c)
|
||||||
|
C_O_FILES = $(C_PIECES:%=${ARCH}/%.o)
|
||||||
|
|
||||||
|
ROOT_H_PIECES =
|
||||||
|
ROOT_H_FILES = $(ROOT_H_PIECES:%=$(srcdir)/%)
|
||||||
|
RTEMS_SCORE_H_PIECES = cpu.h
|
||||||
|
RTEMS_SCORE_H_FILES = $(RTEMS_SCORE_H_PIECES:%=$(srcdir)/%)
|
||||||
|
H_PIECES = $(ROOT_H_PIECES) $(RTEMS_SCORE_H_PIECES)
|
||||||
|
H_FILES = $(H_PIECES%=$(srcdir)/%)
|
||||||
|
I_PIECES = c_isr
|
||||||
|
I_FILES = $(I_PIECES:%=$(srcdir)/%.inl)
|
||||||
|
|
||||||
|
# Assembly source names, if any, go here -- minus the .S
|
||||||
|
S_PIECES = cpu_asm
|
||||||
|
S_FILES = $(S_PIECES:%=%.S)
|
||||||
|
S_O_FILES = $(S_FILES:%.S=${ARCH}/%.o)
|
||||||
|
|
||||||
|
SRCS = $(C_FILES) $(CC_FILES) $(H_FILES) $(S_FILES) $(EXTERNAL_H_FILES) \
|
||||||
|
$(I_FILES)
|
||||||
|
OBJS = $(C_O_FILES) $(CC_O_FILES) $(S_O_FILES)
|
||||||
|
|
||||||
|
include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
|
||||||
|
include $(RTEMS_ROOT)/make/leaf.cfg
|
||||||
|
|
||||||
|
INSTALL_CHANGE = @INSTALL_CHANGE@
|
||||||
|
mkinstalldirs = $(SHELL) $(top_srcdir)/@RTEMS_TOPdir@/mkinstalldirs
|
||||||
|
|
||||||
|
INSTALLDIRS = $(PROJECT_INCLUDE)/rtems/score $(PROJECT_INCLUDE)
|
||||||
|
|
||||||
|
$(INSTALLDIRS):
|
||||||
|
@$(mkinstalldirs) $(INSTALLDIRS)
|
||||||
|
|
||||||
|
#
|
||||||
|
# (OPTIONAL) Add local stuff here using +=
|
||||||
|
#
|
||||||
|
|
||||||
|
DEFINES +=
|
||||||
|
CPPFLAGS +=
|
||||||
|
CFLAGS += $(CFLAGS_OS_V)
|
||||||
|
|
||||||
|
LD_PATHS +=
|
||||||
|
LD_LIBS +=
|
||||||
|
LDFLAGS +=
|
||||||
|
|
||||||
|
#
|
||||||
|
# Add your list of files to delete here. The config files
|
||||||
|
# already know how to delete some stuff, so you may want
|
||||||
|
# to just run 'make clean' first to see what gets missed.
|
||||||
|
# 'make clobber' already includes 'make clean'
|
||||||
|
#
|
||||||
|
|
||||||
|
CLEAN_ADDITIONS +=
|
||||||
|
CLOBBER_ADDITIONS +=
|
||||||
|
|
||||||
|
../$(ARCH)/rtems-cpu.rel: $(OBJS)
|
||||||
|
test -d ../$(ARCH) || mkdir ../$(ARCH)
|
||||||
|
$(make-rel)
|
||||||
|
|
||||||
|
all: ${ARCH} $(SRCS) preinstall $(OBJS) $(RELS)
|
||||||
|
|
||||||
|
# Install the program(s), appending _g or _p as appropriate.
|
||||||
|
# for include files, just use $(INSTALL_CHANGE)
|
||||||
|
install: all
|
||||||
|
|
||||||
|
preinstall: ${ARCH}
|
||||||
|
@$(INSTALL_CHANGE) -m 644 $(RTEMS_SCORE_H_FILES) $(I_FILES) $(PROJECT_INCLUDE)/rtems/score
|
||||||
|
@$(INSTALL_CHANGE) -m 644 $(ROOT_H_FILES) $(PROJECT_INCLUDE)
|
||||||
|
|
||||||
|
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||||
|
cd $(top_builddir) \
|
||||||
|
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
RTEMS_INLINE_ROUTINE boolean _ISR_Is_in_progress( void )
|
||||||
|
{
|
||||||
|
register unsigned int isr_nesting_level;
|
||||||
|
/*
|
||||||
|
* Move from special purpose register 0 (mfspr SPRG0, r3)
|
||||||
|
*/
|
||||||
|
asm volatile ("mfspr %0, 272" : "=r" (isr_nesting_level));
|
||||||
|
return isr_nesting_level;
|
||||||
|
}
|
||||||
116
c/src/exec/score/cpu/powerpc/new_exception_processing/cpu.c
Normal file
116
c/src/exec/score/cpu/powerpc/new_exception_processing/cpu.c
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
/*
|
||||||
|
* PowerPC CPU Dependent Source
|
||||||
|
*
|
||||||
|
* Author: Andrew Bray <andy@i-cubed.co.uk>
|
||||||
|
*
|
||||||
|
* COPYRIGHT (c) 1995 by i-cubed ltd.
|
||||||
|
*
|
||||||
|
* To anyone who acknowledges that this file is provided "AS IS"
|
||||||
|
* without any express or implied warranty:
|
||||||
|
* permission to use, copy, modify, and distribute this file
|
||||||
|
* for any purpose is hereby granted without fee, provided that
|
||||||
|
* the above copyright notice and this notice appears in all
|
||||||
|
* copies, and that the name of i-cubed limited not be used in
|
||||||
|
* advertising or publicity pertaining to distribution of the
|
||||||
|
* software without specific, written prior permission.
|
||||||
|
* i-cubed limited makes no representations about the suitability
|
||||||
|
* of this software for any purpose.
|
||||||
|
*
|
||||||
|
* Derived from c/src/exec/cpu/no_cpu/cpu.c:
|
||||||
|
*
|
||||||
|
* COPYRIGHT (c) 1989-1997.
|
||||||
|
* On-Line Applications Research Corporation (OAR).
|
||||||
|
* Copyright assigned to U.S. Government, 1994.
|
||||||
|
*
|
||||||
|
* The license and distribution terms for this file may be found in
|
||||||
|
* the file LICENSE in this distribution or at
|
||||||
|
* http://www.OARcorp.com/rtems/license.html.
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <rtems/system.h>
|
||||||
|
#include <rtems/score/isr.h>
|
||||||
|
#include <rtems/score/context.h>
|
||||||
|
#include <rtems/score/thread.h>
|
||||||
|
#include <rtems/score/interr.h>
|
||||||
|
|
||||||
|
|
||||||
|
/* _CPU_Initialize
|
||||||
|
*
|
||||||
|
* This routine performs processor dependent initialization.
|
||||||
|
*
|
||||||
|
* INPUT PARAMETERS:
|
||||||
|
* cpu_table - CPU table to initialize
|
||||||
|
* thread_dispatch - address of disptaching routine
|
||||||
|
*/
|
||||||
|
|
||||||
|
void _CPU_Initialize(
|
||||||
|
rtems_cpu_table *cpu_table,
|
||||||
|
void (*thread_dispatch) /* ignored on this CPU */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
_CPU_Table = *cpu_table;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*PAGE
|
||||||
|
*
|
||||||
|
* _CPU_Context_Initialize
|
||||||
|
*/
|
||||||
|
|
||||||
|
void _CPU_Context_Initialize(
|
||||||
|
Context_Control *the_context,
|
||||||
|
unsigned32 *stack_base,
|
||||||
|
unsigned32 size,
|
||||||
|
unsigned32 new_level,
|
||||||
|
void *entry_point,
|
||||||
|
boolean is_fp
|
||||||
|
)
|
||||||
|
{
|
||||||
|
unsigned32 msr_value;
|
||||||
|
unsigned32 sp;
|
||||||
|
|
||||||
|
sp = (unsigned32)stack_base + size - CPU_MINIMUM_STACK_FRAME_SIZE;
|
||||||
|
*((unsigned32 *)sp) = 0;
|
||||||
|
the_context->gpr1 = sp;
|
||||||
|
|
||||||
|
_CPU_MSR_GET( msr_value );
|
||||||
|
|
||||||
|
if (!(new_level & CPU_MODES_INTERRUPT_MASK)) {
|
||||||
|
msr_value |= MSR_EE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
msr_value &= ~MSR_EE;
|
||||||
|
}
|
||||||
|
|
||||||
|
the_context->msr = msr_value;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The FP bit of the MSR should only be enabled if this is a floating
|
||||||
|
* point task. Unfortunately, the vfprintf_r routine in newlib
|
||||||
|
* ends up pushing a floating point register regardless of whether or
|
||||||
|
* not a floating point number is being printed. Serious restructuring
|
||||||
|
* of vfprintf.c will be required to avoid this behavior. At this
|
||||||
|
* time (7 July 1997), this restructuring is not being done.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*if ( is_fp ) */
|
||||||
|
the_context->msr |= PPC_MSR_FP;
|
||||||
|
|
||||||
|
the_context->pc = (unsigned32)entry_point;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*PAGE
|
||||||
|
*
|
||||||
|
* _CPU_Install_interrupt_stack
|
||||||
|
*/
|
||||||
|
|
||||||
|
void _CPU_Install_interrupt_stack( void )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
979
c/src/exec/score/cpu/powerpc/new_exception_processing/cpu.h
Normal file
979
c/src/exec/score/cpu/powerpc/new_exception_processing/cpu.h
Normal file
@@ -0,0 +1,979 @@
|
|||||||
|
/* cpu.h
|
||||||
|
*
|
||||||
|
* This include file contains information pertaining to the PowerPC
|
||||||
|
* processor.
|
||||||
|
*
|
||||||
|
* Author: Andrew Bray <andy@i-cubed.co.uk>
|
||||||
|
*
|
||||||
|
* COPYRIGHT (c) 1995 by i-cubed ltd.
|
||||||
|
*
|
||||||
|
* To anyone who acknowledges that this file is provided "AS IS"
|
||||||
|
* without any express or implied warranty:
|
||||||
|
* permission to use, copy, modify, and distribute this file
|
||||||
|
* for any purpose is hereby granted without fee, provided that
|
||||||
|
* the above copyright notice and this notice appears in all
|
||||||
|
* copies, and that the name of i-cubed limited not be used in
|
||||||
|
* advertising or publicity pertaining to distribution of the
|
||||||
|
* software without specific, written prior permission.
|
||||||
|
* i-cubed limited makes no representations about the suitability
|
||||||
|
* of this software for any purpose.
|
||||||
|
*
|
||||||
|
* Derived from c/src/exec/cpu/no_cpu/cpu.h:
|
||||||
|
*
|
||||||
|
* COPYRIGHT (c) 1989-1997.
|
||||||
|
* On-Line Applications Research Corporation (OAR).
|
||||||
|
* Copyright assigned to U.S. Government, 1994.
|
||||||
|
*
|
||||||
|
* The license and distribution terms for this file may be found in
|
||||||
|
* the file LICENSE in this distribution or at
|
||||||
|
* http://www.OARcorp.com/rtems/license.html.
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __CPU_h
|
||||||
|
#define __CPU_h
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <rtems/score/ppc.h> /* pick up machine definitions */
|
||||||
|
#include <libcpu/cpu.h>
|
||||||
|
|
||||||
|
#ifndef ASM
|
||||||
|
#include <rtems/score/ppctypes.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* conditional compilation parameters */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Should the calls to _Thread_Enable_dispatch be inlined?
|
||||||
|
*
|
||||||
|
* If TRUE, then they are inlined.
|
||||||
|
* If FALSE, then a subroutine call is made.
|
||||||
|
*
|
||||||
|
* Basically this is an example of the classic trade-off of size
|
||||||
|
* versus speed. Inlining the call (TRUE) typically increases the
|
||||||
|
* size of RTEMS while speeding up the enabling of dispatching.
|
||||||
|
* [NOTE: In general, the _Thread_Dispatch_disable_level will
|
||||||
|
* only be 0 or 1 unless you are in an interrupt handler and that
|
||||||
|
* interrupt handler invokes the executive.] When not inlined
|
||||||
|
* something calls _Thread_Enable_dispatch which in turns calls
|
||||||
|
* _Thread_Dispatch. If the enable dispatch is inlined, then
|
||||||
|
* one subroutine call is avoided entirely.]
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define CPU_INLINE_ENABLE_DISPATCH FALSE
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Should the body of the search loops in _Thread_queue_Enqueue_priority
|
||||||
|
* be unrolled one time? In unrolled each iteration of the loop examines
|
||||||
|
* two "nodes" on the chain being searched. Otherwise, only one node
|
||||||
|
* is examined per iteration.
|
||||||
|
*
|
||||||
|
* If TRUE, then the loops are unrolled.
|
||||||
|
* If FALSE, then the loops are not unrolled.
|
||||||
|
*
|
||||||
|
* The primary factor in making this decision is the cost of disabling
|
||||||
|
* and enabling interrupts (_ISR_Flash) versus the cost of rest of the
|
||||||
|
* body of the loop. On some CPUs, the flash is more expensive than
|
||||||
|
* one iteration of the loop body. In this case, it might be desirable
|
||||||
|
* to unroll the loop. It is important to note that on some CPUs, this
|
||||||
|
* code is the longest interrupt disable period in RTEMS. So it is
|
||||||
|
* necessary to strike a balance when setting this parameter.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define CPU_UNROLL_ENQUEUE_PRIORITY FALSE
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Does RTEMS manage a dedicated interrupt stack in software?
|
||||||
|
*
|
||||||
|
* If TRUE, then a stack is allocated in _Interrupt_Manager_initialization.
|
||||||
|
* If FALSE, nothing is done.
|
||||||
|
*
|
||||||
|
* If the CPU supports a dedicated interrupt stack in hardware,
|
||||||
|
* then it is generally the responsibility of the BSP to allocate it
|
||||||
|
* and set it up.
|
||||||
|
*
|
||||||
|
* If the CPU does not support a dedicated interrupt stack, then
|
||||||
|
* the porter has two options: (1) execute interrupts on the
|
||||||
|
* stack of the interrupted task, and (2) have RTEMS manage a dedicated
|
||||||
|
* interrupt stack.
|
||||||
|
*
|
||||||
|
* If this is TRUE, CPU_ALLOCATE_INTERRUPT_STACK should also be TRUE.
|
||||||
|
*
|
||||||
|
* Only one of CPU_HAS_SOFTWARE_INTERRUPT_STACK and
|
||||||
|
* CPU_HAS_HARDWARE_INTERRUPT_STACK should be set to TRUE. It is
|
||||||
|
* possible that both are FALSE for a particular CPU. Although it
|
||||||
|
* is unclear what that would imply about the interrupt processing
|
||||||
|
* procedure on that CPU.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define CPU_HAS_SOFTWARE_INTERRUPT_STACK TRUE
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Does this CPU have hardware support for a dedicated interrupt stack?
|
||||||
|
*
|
||||||
|
* If TRUE, then it must be installed during initialization.
|
||||||
|
* If FALSE, then no installation is performed.
|
||||||
|
*
|
||||||
|
* If this is TRUE, CPU_ALLOCATE_INTERRUPT_STACK should also be TRUE.
|
||||||
|
*
|
||||||
|
* Only one of CPU_HAS_SOFTWARE_INTERRUPT_STACK and
|
||||||
|
* CPU_HAS_HARDWARE_INTERRUPT_STACK should be set to TRUE. It is
|
||||||
|
* possible that both are FALSE for a particular CPU. Although it
|
||||||
|
* is unclear what that would imply about the interrupt processing
|
||||||
|
* procedure on that CPU.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define CPU_HAS_HARDWARE_INTERRUPT_STACK FALSE
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Does RTEMS allocate a dedicated interrupt stack in the Interrupt Manager?
|
||||||
|
*
|
||||||
|
* If TRUE, then the memory is allocated during initialization.
|
||||||
|
* If FALSE, then the memory is allocated during initialization.
|
||||||
|
*
|
||||||
|
* This should be TRUE is CPU_HAS_SOFTWARE_INTERRUPT_STACK is TRUE
|
||||||
|
* or CPU_INSTALL_HARDWARE_INTERRUPT_STACK is TRUE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define CPU_ALLOCATE_INTERRUPT_STACK FALSE
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Does the RTEMS invoke the user's ISR with the vector number and
|
||||||
|
* a pointer to the saved interrupt frame (1) or just the vector
|
||||||
|
* number (0)?
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define CPU_ISR_PASSES_FRAME_POINTER 0
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Does the CPU have hardware floating point?
|
||||||
|
*
|
||||||
|
* If TRUE, then the RTEMS_FLOATING_POINT task attribute is supported.
|
||||||
|
* If FALSE, then the RTEMS_FLOATING_POINT task attribute is ignored.
|
||||||
|
*
|
||||||
|
* If there is a FP coprocessor such as the i387 or mc68881, then
|
||||||
|
* the answer is TRUE.
|
||||||
|
*
|
||||||
|
* The macro name "PPC_HAS_FPU" should be made CPU specific.
|
||||||
|
* It indicates whether or not this CPU model has FP support. For
|
||||||
|
* example, it would be possible to have an i386_nofp CPU model
|
||||||
|
* which set this to false to indicate that you have an i386 without
|
||||||
|
* an i387 and wish to leave floating point support out of RTEMS.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if ( PPC_HAS_FPU == 1 )
|
||||||
|
#define CPU_HARDWARE_FP TRUE
|
||||||
|
#else
|
||||||
|
#define CPU_HARDWARE_FP FALSE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Are all tasks RTEMS_FLOATING_POINT tasks implicitly?
|
||||||
|
*
|
||||||
|
* If TRUE, then the RTEMS_FLOATING_POINT task attribute is assumed.
|
||||||
|
* If FALSE, then the RTEMS_FLOATING_POINT task attribute is followed.
|
||||||
|
*
|
||||||
|
* So far, the only CPU in which this option has been used is the
|
||||||
|
* HP PA-RISC. The HP C compiler and gcc both implicitly use the
|
||||||
|
* floating point registers to perform integer multiplies. If
|
||||||
|
* a function which you would not think utilize the FP unit DOES,
|
||||||
|
* then one can not easily predict which tasks will use the FP hardware.
|
||||||
|
* In this case, this option should be TRUE.
|
||||||
|
*
|
||||||
|
* If CPU_HARDWARE_FP is FALSE, then this should be FALSE as well.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define CPU_ALL_TASKS_ARE_FP FALSE
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Should the IDLE task have a floating point context?
|
||||||
|
*
|
||||||
|
* If TRUE, then the IDLE task is created as a RTEMS_FLOATING_POINT task
|
||||||
|
* and it has a floating point context which is switched in and out.
|
||||||
|
* If FALSE, then the IDLE task does not have a floating point context.
|
||||||
|
*
|
||||||
|
* Setting this to TRUE negatively impacts the time required to preempt
|
||||||
|
* the IDLE task from an interrupt because the floating point context
|
||||||
|
* must be saved as part of the preemption.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define CPU_IDLE_TASK_IS_FP FALSE
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Should the saving of the floating point registers be deferred
|
||||||
|
* until a context switch is made to another different floating point
|
||||||
|
* task?
|
||||||
|
*
|
||||||
|
* If TRUE, then the floating point context will not be stored until
|
||||||
|
* necessary. It will remain in the floating point registers and not
|
||||||
|
* disturned until another floating point task is switched to.
|
||||||
|
*
|
||||||
|
* If FALSE, then the floating point context is saved when a floating
|
||||||
|
* point task is switched out and restored when the next floating point
|
||||||
|
* task is restored. The state of the floating point registers between
|
||||||
|
* those two operations is not specified.
|
||||||
|
*
|
||||||
|
* If the floating point context does NOT have to be saved as part of
|
||||||
|
* interrupt dispatching, then it should be safe to set this to TRUE.
|
||||||
|
*
|
||||||
|
* Setting this flag to TRUE results in using a different algorithm
|
||||||
|
* for deciding when to save and restore the floating point context.
|
||||||
|
* The deferred FP switch algorithm minimizes the number of times
|
||||||
|
* the FP context is saved and restored. The FP context is not saved
|
||||||
|
* until a context switch is made to another, different FP task.
|
||||||
|
* Thus in a system with only one FP task, the FP context will never
|
||||||
|
* be saved or restored.
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* ACB Note: This could make debugging tricky..
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define CPU_USE_DEFERRED_FP_SWITCH TRUE
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Does this port provide a CPU dependent IDLE task implementation?
|
||||||
|
*
|
||||||
|
* If TRUE, then the routine _CPU_Thread_Idle_body
|
||||||
|
* must be provided and is the default IDLE thread body instead of
|
||||||
|
* _CPU_Thread_Idle_body.
|
||||||
|
*
|
||||||
|
* If FALSE, then use the generic IDLE thread body if the BSP does
|
||||||
|
* not provide one.
|
||||||
|
*
|
||||||
|
* This is intended to allow for supporting processors which have
|
||||||
|
* a low power or idle mode. When the IDLE thread is executed, then
|
||||||
|
* the CPU can be powered down.
|
||||||
|
*
|
||||||
|
* The order of precedence for selecting the IDLE thread body is:
|
||||||
|
*
|
||||||
|
* 1. BSP provided
|
||||||
|
* 2. CPU dependent (if provided)
|
||||||
|
* 3. generic (if no BSP and no CPU dependent)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define CPU_PROVIDES_IDLE_THREAD_BODY FALSE
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Does the stack grow up (toward higher addresses) or down
|
||||||
|
* (toward lower addresses)?
|
||||||
|
*
|
||||||
|
* If TRUE, then the grows upward.
|
||||||
|
* If FALSE, then the grows toward smaller addresses.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define CPU_STACK_GROWS_UP FALSE
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The following is the variable attribute used to force alignment
|
||||||
|
* of critical RTEMS structures. On some processors it may make
|
||||||
|
* sense to have these aligned on tighter boundaries than
|
||||||
|
* the minimum requirements of the compiler in order to have as
|
||||||
|
* much of the critical data area as possible in a cache line.
|
||||||
|
*
|
||||||
|
* The placement of this macro in the declaration of the variables
|
||||||
|
* is based on the syntactically requirements of the GNU C
|
||||||
|
* "__attribute__" extension. For example with GNU C, use
|
||||||
|
* the following to force a structures to a 32 byte boundary.
|
||||||
|
*
|
||||||
|
* __attribute__ ((aligned (32)))
|
||||||
|
*
|
||||||
|
* NOTE: Currently only the Priority Bit Map table uses this feature.
|
||||||
|
* To benefit from using this, the data must be heavily
|
||||||
|
* used so it will stay in the cache and used frequently enough
|
||||||
|
* in the executive to justify turning this on.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define CPU_STRUCTURE_ALIGNMENT \
|
||||||
|
__attribute__ ((aligned (PPC_CACHE_ALIGNMENT)))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Define what is required to specify how the network to host conversion
|
||||||
|
* routines are handled.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define CPU_HAS_OWN_HOST_TO_NETWORK_ROUTINES FALSE
|
||||||
|
#define CPU_BIG_ENDIAN TRUE
|
||||||
|
#define CPU_LITTLE_ENDIAN FALSE
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Processor defined structures
|
||||||
|
*
|
||||||
|
* Examples structures include the descriptor tables from the i386
|
||||||
|
* and the processor control structure on the i960ca.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* may need to put some structures here. */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Contexts
|
||||||
|
*
|
||||||
|
* Generally there are 2 types of context to save.
|
||||||
|
* 1. Interrupt registers to save
|
||||||
|
* 2. Task level registers to save
|
||||||
|
*
|
||||||
|
* This means we have the following 3 context items:
|
||||||
|
* 1. task level context stuff:: Context_Control
|
||||||
|
* 2. floating point task stuff:: Context_Control_fp
|
||||||
|
* 3. special interrupt level context :: Context_Control_interrupt
|
||||||
|
*
|
||||||
|
* On some processors, it is cost-effective to save only the callee
|
||||||
|
* preserved registers during a task context switch. This means
|
||||||
|
* that the ISR code needs to save those registers which do not
|
||||||
|
* persist across function calls. It is not mandatory to make this
|
||||||
|
* distinctions between the caller/callee saves registers for the
|
||||||
|
* purpose of minimizing context saved during task switch and on interrupts.
|
||||||
|
* If the cost of saving extra registers is minimal, simplicity is the
|
||||||
|
* choice. Save the same context on interrupt entry as for tasks in
|
||||||
|
* this case.
|
||||||
|
*
|
||||||
|
* Additionally, if gdb is to be made aware of RTEMS tasks for this CPU, then
|
||||||
|
* care should be used in designing the context area.
|
||||||
|
*
|
||||||
|
* On some CPUs with hardware floating point support, the Context_Control_fp
|
||||||
|
* structure will not be used or it simply consist of an array of a
|
||||||
|
* fixed number of bytes. This is done when the floating point context
|
||||||
|
* is dumped by a "FP save context" type instruction and the format
|
||||||
|
* is not really defined by the CPU. In this case, there is no need
|
||||||
|
* to figure out the exact format -- only the size. Of course, although
|
||||||
|
* this is enough information for RTEMS, it is probably not enough for
|
||||||
|
* a debugger such as gdb. But that is another problem.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ASM
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned32 gpr1; /* Stack pointer for all */
|
||||||
|
unsigned32 gpr2; /* TOC in PowerOpen, reserved SVR4, section ptr EABI + */
|
||||||
|
unsigned32 gpr13; /* First non volatile PowerOpen, section ptr SVR4/EABI */
|
||||||
|
unsigned32 gpr14; /* Non volatile for all */
|
||||||
|
unsigned32 gpr15; /* Non volatile for all */
|
||||||
|
unsigned32 gpr16; /* Non volatile for all */
|
||||||
|
unsigned32 gpr17; /* Non volatile for all */
|
||||||
|
unsigned32 gpr18; /* Non volatile for all */
|
||||||
|
unsigned32 gpr19; /* Non volatile for all */
|
||||||
|
unsigned32 gpr20; /* Non volatile for all */
|
||||||
|
unsigned32 gpr21; /* Non volatile for all */
|
||||||
|
unsigned32 gpr22; /* Non volatile for all */
|
||||||
|
unsigned32 gpr23; /* Non volatile for all */
|
||||||
|
unsigned32 gpr24; /* Non volatile for all */
|
||||||
|
unsigned32 gpr25; /* Non volatile for all */
|
||||||
|
unsigned32 gpr26; /* Non volatile for all */
|
||||||
|
unsigned32 gpr27; /* Non volatile for all */
|
||||||
|
unsigned32 gpr28; /* Non volatile for all */
|
||||||
|
unsigned32 gpr29; /* Non volatile for all */
|
||||||
|
unsigned32 gpr30; /* Non volatile for all */
|
||||||
|
unsigned32 gpr31; /* Non volatile for all */
|
||||||
|
unsigned32 cr; /* PART of the CR is non volatile for all */
|
||||||
|
unsigned32 pc; /* Program counter/Link register */
|
||||||
|
unsigned32 msr; /* Initial interrupt level */
|
||||||
|
} Context_Control;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
/* The ABIs (PowerOpen/SVR4/EABI) only require saving f14-f31 over
|
||||||
|
* procedure calls. However, this would mean that the interrupt
|
||||||
|
* frame had to hold f0-f13, and the fpscr. And as the majority
|
||||||
|
* of tasks will not have an FP context, we will save the whole
|
||||||
|
* context here.
|
||||||
|
*/
|
||||||
|
#if (PPC_HAS_DOUBLE == 1)
|
||||||
|
double f[32];
|
||||||
|
double fpscr;
|
||||||
|
#else
|
||||||
|
float f[32];
|
||||||
|
float fpscr;
|
||||||
|
#endif
|
||||||
|
} Context_Control_fp;
|
||||||
|
|
||||||
|
typedef struct CPU_Interrupt_frame {
|
||||||
|
unsigned32 stacklink; /* Ensure this is a real frame (also reg1 save) */
|
||||||
|
unsigned32 calleeLr; /* link register used by callees: SVR4/EABI */
|
||||||
|
/* This is what is left out of the primary contexts */
|
||||||
|
unsigned32 gpr0;
|
||||||
|
unsigned32 gpr2; /* play safe */
|
||||||
|
unsigned32 gpr3;
|
||||||
|
unsigned32 gpr4;
|
||||||
|
unsigned32 gpr5;
|
||||||
|
unsigned32 gpr6;
|
||||||
|
unsigned32 gpr7;
|
||||||
|
unsigned32 gpr8;
|
||||||
|
unsigned32 gpr9;
|
||||||
|
unsigned32 gpr10;
|
||||||
|
unsigned32 gpr11;
|
||||||
|
unsigned32 gpr12;
|
||||||
|
unsigned32 gpr13; /* Play safe */
|
||||||
|
unsigned32 gpr28; /* For internal use by the IRQ handler */
|
||||||
|
unsigned32 gpr29; /* For internal use by the IRQ handler */
|
||||||
|
unsigned32 gpr30; /* For internal use by the IRQ handler */
|
||||||
|
unsigned32 gpr31; /* For internal use by the IRQ handler */
|
||||||
|
unsigned32 cr; /* Bits of this are volatile, so no-one may save */
|
||||||
|
unsigned32 ctr;
|
||||||
|
unsigned32 xer;
|
||||||
|
unsigned32 lr;
|
||||||
|
unsigned32 pc;
|
||||||
|
unsigned32 msr;
|
||||||
|
unsigned32 pad[3];
|
||||||
|
} CPU_Interrupt_frame;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The following table contains the information required to configure
|
||||||
|
* the PowerPC processor specific parameters.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
void (*pretasking_hook)( void );
|
||||||
|
void (*predriver_hook)( void );
|
||||||
|
void (*postdriver_hook)( void );
|
||||||
|
void (*idle_task)( void );
|
||||||
|
boolean do_zero_of_workspace;
|
||||||
|
unsigned32 idle_task_stack_size;
|
||||||
|
unsigned32 interrupt_stack_size;
|
||||||
|
unsigned32 extra_mpci_receive_server_stack;
|
||||||
|
void * (*stack_allocate_hook)( unsigned32 );
|
||||||
|
void (*stack_free_hook)( void* );
|
||||||
|
/* end of fields required on all CPUs */
|
||||||
|
|
||||||
|
unsigned32 clicks_per_usec; /* Timer clicks per microsecond */
|
||||||
|
boolean exceptions_in_RAM; /* TRUE if in RAM */
|
||||||
|
|
||||||
|
} rtems_cpu_table;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Macros to access required entires in the CPU Table are in
|
||||||
|
* the file rtems/system.h.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Macros to access PowerPC MPC750 specific additions to the CPU Table
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define rtems_cpu_configuration_get_clicks_per_usec() \
|
||||||
|
(_CPU_Table.clicks_per_usec)
|
||||||
|
|
||||||
|
#define rtems_cpu_configuration_get_exceptions_in_ram() \
|
||||||
|
(_CPU_Table.exceptions_in_RAM)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This variable is optional. It is used on CPUs on which it is difficult
|
||||||
|
* to generate an "uninitialized" FP context. It is filled in by
|
||||||
|
* _CPU_Initialize and copied into the task's FP context area during
|
||||||
|
* _CPU_Context_Initialize.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* EXTERN Context_Control_fp _CPU_Null_fp_context; */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* On some CPUs, RTEMS supports a software managed interrupt stack.
|
||||||
|
* This stack is allocated by the Interrupt Manager and the switch
|
||||||
|
* is performed in _ISR_Handler. These variables contain pointers
|
||||||
|
* to the lowest and highest addresses in the chunk of memory allocated
|
||||||
|
* for the interrupt stack. Since it is unknown whether the stack
|
||||||
|
* grows up or down (in general), this give the CPU dependent
|
||||||
|
* code the option of picking the version it wants to use.
|
||||||
|
*
|
||||||
|
* NOTE: These two variables are required if the macro
|
||||||
|
* CPU_HAS_SOFTWARE_INTERRUPT_STACK is defined as TRUE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
SCORE_EXTERN void *_CPU_Interrupt_stack_low;
|
||||||
|
SCORE_EXTERN void *_CPU_Interrupt_stack_high;
|
||||||
|
|
||||||
|
#endif /* ndef ASM */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This defines the number of levels and the mask used to pick those
|
||||||
|
* bits out of a thread mode.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define CPU_MODES_INTERRUPT_LEVEL 0x00000001 /* interrupt level in mode */
|
||||||
|
#define CPU_MODES_INTERRUPT_MASK 0x00000001 /* interrupt level in mode */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* With some compilation systems, it is difficult if not impossible to
|
||||||
|
* call a high-level language routine from assembly language. This
|
||||||
|
* is especially true of commercial Ada compilers and name mangling
|
||||||
|
* C++ ones. This variable can be optionally defined by the CPU porter
|
||||||
|
* and contains the address of the routine _Thread_Dispatch. This
|
||||||
|
* can make it easier to invoke that routine at the end of the interrupt
|
||||||
|
* sequence (if a dispatch is necessary).
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* EXTERN void (*_CPU_Thread_dispatch_pointer)(); */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Nothing prevents the porter from declaring more CPU specific variables.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ASM
|
||||||
|
|
||||||
|
SCORE_EXTERN struct {
|
||||||
|
unsigned32 *Disable_level;
|
||||||
|
void *Stack;
|
||||||
|
volatile boolean *Switch_necessary;
|
||||||
|
boolean *Signal;
|
||||||
|
|
||||||
|
} _CPU_IRQ_info CPU_STRUCTURE_ALIGNMENT;
|
||||||
|
|
||||||
|
#endif /* ndef ASM */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The size of the floating point context area. On some CPUs this
|
||||||
|
* will not be a "sizeof" because the format of the floating point
|
||||||
|
* area is not defined -- only the size is. This is usually on
|
||||||
|
* CPUs with a "floating point save context" instruction.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define CPU_CONTEXT_FP_SIZE sizeof( Context_Control_fp )
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (Optional) # of bytes for libmisc/stackchk to check
|
||||||
|
* If not specifed, then it defaults to something reasonable
|
||||||
|
* for most architectures.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define CPU_STACK_CHECK_SIZE (128)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Amount of extra stack (above minimum stack size) required by
|
||||||
|
* MPCI receive server thread. Remember that in a multiprocessor
|
||||||
|
* system this thread must exist and be able to process all directives.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define CPU_MPCI_RECEIVE_SERVER_EXTRA_STACK 0
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This defines the number of entries in the ISR_Vector_table managed
|
||||||
|
* by RTEMS.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define CPU_INTERRUPT_NUMBER_OF_VECTORS (PPC_INTERRUPT_MAX)
|
||||||
|
#define CPU_INTERRUPT_MAXIMUM_VECTOR_NUMBER (PPC_INTERRUPT_MAX - 1)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Should be large enough to run all RTEMS tests. This insures
|
||||||
|
* that a "reasonable" small application should not have any problems.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define CPU_STACK_MINIMUM_SIZE (1024*8)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CPU's worst alignment requirement for data types on a byte boundary. This
|
||||||
|
* alignment does not take into account the requirements for the stack.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define CPU_ALIGNMENT (PPC_ALIGNMENT)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This number corresponds to the byte alignment requirement for the
|
||||||
|
* heap handler. This alignment requirement may be stricter than that
|
||||||
|
* for the data types alignment specified by CPU_ALIGNMENT. It is
|
||||||
|
* common for the heap to follow the same alignment requirement as
|
||||||
|
* CPU_ALIGNMENT. If the CPU_ALIGNMENT is strict enough for the heap,
|
||||||
|
* then this should be set to CPU_ALIGNMENT.
|
||||||
|
*
|
||||||
|
* NOTE: This does not have to be a power of 2. It does have to
|
||||||
|
* be greater or equal to than CPU_ALIGNMENT.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define CPU_HEAP_ALIGNMENT (PPC_ALIGNMENT)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This number corresponds to the byte alignment requirement for memory
|
||||||
|
* buffers allocated by the partition manager. This alignment requirement
|
||||||
|
* may be stricter than that for the data types alignment specified by
|
||||||
|
* CPU_ALIGNMENT. It is common for the partition to follow the same
|
||||||
|
* alignment requirement as CPU_ALIGNMENT. If the CPU_ALIGNMENT is strict
|
||||||
|
* enough for the partition, then this should be set to CPU_ALIGNMENT.
|
||||||
|
*
|
||||||
|
* NOTE: This does not have to be a power of 2. It does have to
|
||||||
|
* be greater or equal to than CPU_ALIGNMENT.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define CPU_PARTITION_ALIGNMENT (PPC_ALIGNMENT)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This number corresponds to the byte alignment requirement for the
|
||||||
|
* stack. This alignment requirement may be stricter than that for the
|
||||||
|
* data types alignment specified by CPU_ALIGNMENT. If the CPU_ALIGNMENT
|
||||||
|
* is strict enough for the stack, then this should be set to 0.
|
||||||
|
*
|
||||||
|
* NOTE: This must be a power of 2 either 0 or greater than CPU_ALIGNMENT.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define CPU_STACK_ALIGNMENT (PPC_STACK_ALIGNMENT)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Needed for Interrupt stack
|
||||||
|
*/
|
||||||
|
#define CPU_MINIMUM_STACK_FRAME_SIZE 8
|
||||||
|
|
||||||
|
|
||||||
|
/* ISR handler macros */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Disable all interrupts for an RTEMS critical section. The previous
|
||||||
|
* level is returned in _isr_cookie.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define loc_string(a,b) a " (" #b ")\n"
|
||||||
|
|
||||||
|
#ifndef ASM
|
||||||
|
|
||||||
|
static inline unsigned32 _CPU_ISR_Get_level( void )
|
||||||
|
{
|
||||||
|
register unsigned int msr;
|
||||||
|
_CPU_MSR_GET(msr);
|
||||||
|
if (msr & MSR_EE) return 0;
|
||||||
|
else return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void _CPU_ISR_Set_level( unsigned32 level )
|
||||||
|
{
|
||||||
|
register unsigned int msr;
|
||||||
|
_CPU_MSR_GET(msr);
|
||||||
|
if (!(level & CPU_MODES_INTERRUPT_MASK)) {
|
||||||
|
msr |= MSR_EE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
msr &= ~MSR_EE;
|
||||||
|
}
|
||||||
|
_CPU_MSR_SET(msr);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define _CPU_ISR_install_vector(irq, new, old) {BSP_panic("_CPU_ISR_install_vector called\n");}
|
||||||
|
|
||||||
|
/* Context handler macros */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize the context to a state suitable for starting a
|
||||||
|
* task after a context restore operation. Generally, this
|
||||||
|
* involves:
|
||||||
|
*
|
||||||
|
* - setting a starting address
|
||||||
|
* - preparing the stack
|
||||||
|
* - preparing the stack and frame pointers
|
||||||
|
* - setting the proper interrupt level in the context
|
||||||
|
* - initializing the floating point context
|
||||||
|
*
|
||||||
|
* This routine generally does not set any unnecessary register
|
||||||
|
* in the context. The state of the "general data" registers is
|
||||||
|
* undefined at task start time.
|
||||||
|
*
|
||||||
|
* NOTE: Implemented as a subroutine for the SPARC port.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void _CPU_Context_Initialize(
|
||||||
|
Context_Control *the_context,
|
||||||
|
unsigned32 *stack_base,
|
||||||
|
unsigned32 size,
|
||||||
|
unsigned32 new_level,
|
||||||
|
void *entry_point,
|
||||||
|
boolean is_fp
|
||||||
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This routine is responsible for somehow restarting the currently
|
||||||
|
* executing task. If you are lucky, then all that is necessary
|
||||||
|
* is restoring the context. Otherwise, there will need to be
|
||||||
|
* a special assembly routine which does something special in this
|
||||||
|
* case. Context_Restore should work most of the time. It will
|
||||||
|
* not work if restarting self conflicts with the stack frame
|
||||||
|
* assumptions of restoring a context.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _CPU_Context_Restart_self( _the_context ) \
|
||||||
|
_CPU_Context_restore( (_the_context) );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The purpose of this macro is to allow the initial pointer into
|
||||||
|
* a floating point context area (used to save the floating point
|
||||||
|
* context) to be at an arbitrary place in the floating point
|
||||||
|
* context area.
|
||||||
|
*
|
||||||
|
* This is necessary because some FP units are designed to have
|
||||||
|
* their context saved as a stack which grows into lower addresses.
|
||||||
|
* Other FP units can be saved by simply moving registers into offsets
|
||||||
|
* from the base of the context area. Finally some FP units provide
|
||||||
|
* a "dump context" instruction which could fill in from high to low
|
||||||
|
* or low to high based on the whim of the CPU designers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _CPU_Context_Fp_start( _base, _offset ) \
|
||||||
|
( (void *) _Addresses_Add_offset( (_base), (_offset) ) )
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This routine initializes the FP context area passed to it to.
|
||||||
|
* There are a few standard ways in which to initialize the
|
||||||
|
* floating point context. The code included for this macro assumes
|
||||||
|
* that this is a CPU in which a "initial" FP context was saved into
|
||||||
|
* _CPU_Null_fp_context and it simply copies it to the destination
|
||||||
|
* context passed to it.
|
||||||
|
*
|
||||||
|
* Other models include (1) not doing anything, and (2) putting
|
||||||
|
* a "null FP status word" in the correct place in the FP context.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _CPU_Context_Initialize_fp( _destination ) \
|
||||||
|
{ \
|
||||||
|
((Context_Control_fp *) *((void **) _destination))->fpscr = PPC_INIT_FPSCR; \
|
||||||
|
}
|
||||||
|
|
||||||
|
/* end of Context handler macros */
|
||||||
|
|
||||||
|
/* Fatal Error manager macros */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This routine copies _error into a known place -- typically a stack
|
||||||
|
* location or a register, optionally disables interrupts, and
|
||||||
|
* halts/stops the CPU.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _CPU_Fatal_halt( _error ) \
|
||||||
|
_BSP_Fatal_error(_error)
|
||||||
|
|
||||||
|
/* end of Fatal Error manager macros */
|
||||||
|
|
||||||
|
/* Bitfield handler macros */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This routine sets _output to the bit number of the first bit
|
||||||
|
* set in _value. _value is of CPU dependent type Priority_Bit_map_control.
|
||||||
|
* This type may be either 16 or 32 bits wide although only the 16
|
||||||
|
* least significant bits will be used.
|
||||||
|
*
|
||||||
|
* There are a number of variables in using a "find first bit" type
|
||||||
|
* instruction.
|
||||||
|
*
|
||||||
|
* (1) What happens when run on a value of zero?
|
||||||
|
* (2) Bits may be numbered from MSB to LSB or vice-versa.
|
||||||
|
* (3) The numbering may be zero or one based.
|
||||||
|
* (4) The "find first bit" instruction may search from MSB or LSB.
|
||||||
|
*
|
||||||
|
* RTEMS guarantees that (1) will never happen so it is not a concern.
|
||||||
|
* (2),(3), (4) are handled by the macros _CPU_Priority_mask() and
|
||||||
|
* _CPU_Priority_Bits_index(). These three form a set of routines
|
||||||
|
* which must logically operate together. Bits in the _value are
|
||||||
|
* set and cleared based on masks built by _CPU_Priority_mask().
|
||||||
|
* The basic major and minor values calculated by _Priority_Major()
|
||||||
|
* and _Priority_Minor() are "massaged" by _CPU_Priority_Bits_index()
|
||||||
|
* to properly range between the values returned by the "find first bit"
|
||||||
|
* instruction. This makes it possible for _Priority_Get_highest() to
|
||||||
|
* calculate the major and directly index into the minor table.
|
||||||
|
* This mapping is necessary to ensure that 0 (a high priority major/minor)
|
||||||
|
* is the first bit found.
|
||||||
|
*
|
||||||
|
* This entire "find first bit" and mapping process depends heavily
|
||||||
|
* on the manner in which a priority is broken into a major and minor
|
||||||
|
* components with the major being the 4 MSB of a priority and minor
|
||||||
|
* the 4 LSB. Thus (0 << 4) + 0 corresponds to priority 0 -- the highest
|
||||||
|
* priority. And (15 << 4) + 14 corresponds to priority 254 -- the next
|
||||||
|
* to the lowest priority.
|
||||||
|
*
|
||||||
|
* If your CPU does not have a "find first bit" instruction, then
|
||||||
|
* there are ways to make do without it. Here are a handful of ways
|
||||||
|
* to implement this in software:
|
||||||
|
*
|
||||||
|
* - a series of 16 bit test instructions
|
||||||
|
* - a "binary search using if's"
|
||||||
|
* - _number = 0
|
||||||
|
* if _value > 0x00ff
|
||||||
|
* _value >>=8
|
||||||
|
* _number = 8;
|
||||||
|
*
|
||||||
|
* if _value > 0x0000f
|
||||||
|
* _value >=8
|
||||||
|
* _number += 4
|
||||||
|
*
|
||||||
|
* _number += bit_set_table[ _value ]
|
||||||
|
*
|
||||||
|
* where bit_set_table[ 16 ] has values which indicate the first
|
||||||
|
* bit set
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _CPU_Bitfield_Find_first_bit( _value, _output ) \
|
||||||
|
{ \
|
||||||
|
asm volatile ("cntlzw %0, %1" : "=r" ((_output)), "=r" ((_value)) : \
|
||||||
|
"1" ((_value))); \
|
||||||
|
}
|
||||||
|
|
||||||
|
/* end of Bitfield handler macros */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This routine builds the mask which corresponds to the bit fields
|
||||||
|
* as searched by _CPU_Bitfield_Find_first_bit(). See the discussion
|
||||||
|
* for that routine.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _CPU_Priority_Mask( _bit_number ) \
|
||||||
|
( 0x80000000 >> (_bit_number) )
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This routine translates the bit numbers returned by
|
||||||
|
* _CPU_Bitfield_Find_first_bit() into something suitable for use as
|
||||||
|
* a major or minor component of a priority. See the discussion
|
||||||
|
* for that routine.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _CPU_Priority_bits_index( _priority ) \
|
||||||
|
(_priority)
|
||||||
|
|
||||||
|
/* end of Priority handler macros */
|
||||||
|
|
||||||
|
/* variables */
|
||||||
|
|
||||||
|
extern const unsigned32 _CPU_msrs[4];
|
||||||
|
|
||||||
|
/* functions */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* _CPU_Initialize
|
||||||
|
*
|
||||||
|
* This routine performs CPU dependent initialization.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void _CPU_Initialize(
|
||||||
|
rtems_cpu_table *cpu_table,
|
||||||
|
void (*thread_dispatch)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* _CPU_Install_interrupt_stack
|
||||||
|
*
|
||||||
|
* This routine installs the hardware interrupt stack pointer.
|
||||||
|
*
|
||||||
|
* NOTE: It need only be provided if CPU_HAS_HARDWARE_INTERRUPT_STACK
|
||||||
|
* is TRUE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void _CPU_Install_interrupt_stack( void );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* _CPU_Context_switch
|
||||||
|
*
|
||||||
|
* This routine switches from the run context to the heir context.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void _CPU_Context_switch(
|
||||||
|
Context_Control *run,
|
||||||
|
Context_Control *heir
|
||||||
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* _CPU_Context_restore
|
||||||
|
*
|
||||||
|
* This routine is generallu used only to restart self in an
|
||||||
|
* efficient manner. It may simply be a label in _CPU_Context_switch.
|
||||||
|
*
|
||||||
|
* NOTE: May be unnecessary to reload some registers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void _CPU_Context_restore(
|
||||||
|
Context_Control *new_context
|
||||||
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* _CPU_Context_save_fp
|
||||||
|
*
|
||||||
|
* This routine saves the floating point context passed to it.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void _CPU_Context_save_fp(
|
||||||
|
void **fp_context_ptr
|
||||||
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* _CPU_Context_restore_fp
|
||||||
|
*
|
||||||
|
* This routine restores the floating point context passed to it.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void _CPU_Context_restore_fp(
|
||||||
|
void **fp_context_ptr
|
||||||
|
);
|
||||||
|
|
||||||
|
void _CPU_Fatal_error(
|
||||||
|
unsigned32 _error
|
||||||
|
);
|
||||||
|
|
||||||
|
/* The following routine swaps the endian format of an unsigned int.
|
||||||
|
* It must be static because it is referenced indirectly.
|
||||||
|
*
|
||||||
|
* This version will work on any processor, but if there is a better
|
||||||
|
* way for your CPU PLEASE use it. The most common way to do this is to:
|
||||||
|
*
|
||||||
|
* swap least significant two bytes with 16-bit rotate
|
||||||
|
* swap upper and lower 16-bits
|
||||||
|
* swap most significant two bytes with 16-bit rotate
|
||||||
|
*
|
||||||
|
* Some CPUs have special instructions which swap a 32-bit quantity in
|
||||||
|
* a single instruction (e.g. i486). It is probably best to avoid
|
||||||
|
* an "endian swapping control bit" in the CPU. One good reason is
|
||||||
|
* that interrupts would probably have to be disabled to insure that
|
||||||
|
* an interrupt does not try to access the same "chunk" with the wrong
|
||||||
|
* endian. Another good reason is that on some CPUs, the endian bit
|
||||||
|
* endianness for ALL fetches -- both code and data -- so the code
|
||||||
|
* will be fetched incorrectly.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static inline unsigned int CPU_swap_u32(
|
||||||
|
unsigned int value
|
||||||
|
)
|
||||||
|
{
|
||||||
|
unsigned32 swapped;
|
||||||
|
|
||||||
|
asm volatile("rlwimi %0,%1,8,24,31;"
|
||||||
|
"rlwimi %0,%1,24,16,23;"
|
||||||
|
"rlwimi %0,%1,8,8,15;"
|
||||||
|
"rlwimi %0,%1,24,0,7;" :
|
||||||
|
"=&r" ((swapped)) : "r" ((value)));
|
||||||
|
|
||||||
|
return( swapped );
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CPU_swap_u16( value ) \
|
||||||
|
(((value&0xff) << 8) | ((value >> 8)&0xff))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Routines to access the decrementer register
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define PPC_Set_decrementer( _clicks ) \
|
||||||
|
do { \
|
||||||
|
asm volatile( "mtdec %0" : "=r" ((_clicks)) : "r" ((_clicks)) ); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Routines to access the time base register
|
||||||
|
*/
|
||||||
|
|
||||||
|
static inline unsigned64 PPC_Get_timebase_register( void )
|
||||||
|
{
|
||||||
|
unsigned32 tbr_low;
|
||||||
|
unsigned32 tbr_high;
|
||||||
|
unsigned32 tbr_high_old;
|
||||||
|
unsigned64 tbr;
|
||||||
|
|
||||||
|
do {
|
||||||
|
asm volatile( "mftbu %0" : "=r" (tbr_high_old));
|
||||||
|
asm volatile( "mftb %0" : "=r" (tbr_low));
|
||||||
|
asm volatile( "mftbu %0" : "=r" (tbr_high));
|
||||||
|
} while ( tbr_high_old != tbr_high );
|
||||||
|
|
||||||
|
tbr = tbr_high;
|
||||||
|
tbr <<= 32;
|
||||||
|
tbr |= tbr_low;
|
||||||
|
return tbr;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* ndef ASM */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
396
c/src/exec/score/cpu/powerpc/new_exception_processing/cpu_asm.S
Normal file
396
c/src/exec/score/cpu/powerpc/new_exception_processing/cpu_asm.S
Normal file
@@ -0,0 +1,396 @@
|
|||||||
|
|
||||||
|
/* cpu_asm.s 1.1 - 95/12/04
|
||||||
|
*
|
||||||
|
* This file contains the assembly code for the PowerPC implementation
|
||||||
|
* of RTEMS.
|
||||||
|
*
|
||||||
|
* Author: Andrew Bray <andy@i-cubed.co.uk>
|
||||||
|
*
|
||||||
|
* COPYRIGHT (c) 1995 by i-cubed ltd.
|
||||||
|
*
|
||||||
|
* To anyone who acknowledges that this file is provided "AS IS"
|
||||||
|
* without any express or implied warranty:
|
||||||
|
* permission to use, copy, modify, and distribute this file
|
||||||
|
* for any purpose is hereby granted without fee, provided that
|
||||||
|
* the above copyright notice and this notice appears in all
|
||||||
|
* copies, and that the name of i-cubed limited not be used in
|
||||||
|
* advertising or publicity pertaining to distribution of the
|
||||||
|
* software without specific, written prior permission.
|
||||||
|
* i-cubed limited makes no representations about the suitability
|
||||||
|
* of this software for any purpose.
|
||||||
|
*
|
||||||
|
* Derived from c/src/exec/cpu/no_cpu/cpu_asm.c:
|
||||||
|
*
|
||||||
|
* COPYRIGHT (c) 1989-1997.
|
||||||
|
* On-Line Applications Research Corporation (OAR).
|
||||||
|
* Copyright assigned to U.S. Government, 1994.
|
||||||
|
*
|
||||||
|
* The license and distribution terms for this file may in
|
||||||
|
* the file LICENSE in this distribution or at
|
||||||
|
* http://www.OARcorp.com/rtems/license.html.
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <asm.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Offsets for various Contexts
|
||||||
|
*/
|
||||||
|
.set GP_1, 0
|
||||||
|
.set GP_2, (GP_1 + 4)
|
||||||
|
.set GP_13, (GP_2 + 4)
|
||||||
|
.set GP_14, (GP_13 + 4)
|
||||||
|
|
||||||
|
.set GP_15, (GP_14 + 4)
|
||||||
|
.set GP_16, (GP_15 + 4)
|
||||||
|
.set GP_17, (GP_16 + 4)
|
||||||
|
.set GP_18, (GP_17 + 4)
|
||||||
|
|
||||||
|
.set GP_19, (GP_18 + 4)
|
||||||
|
.set GP_20, (GP_19 + 4)
|
||||||
|
.set GP_21, (GP_20 + 4)
|
||||||
|
.set GP_22, (GP_21 + 4)
|
||||||
|
|
||||||
|
.set GP_23, (GP_22 + 4)
|
||||||
|
.set GP_24, (GP_23 + 4)
|
||||||
|
.set GP_25, (GP_24 + 4)
|
||||||
|
.set GP_26, (GP_25 + 4)
|
||||||
|
|
||||||
|
.set GP_27, (GP_26 + 4)
|
||||||
|
.set GP_28, (GP_27 + 4)
|
||||||
|
.set GP_29, (GP_28 + 4)
|
||||||
|
.set GP_30, (GP_29 + 4)
|
||||||
|
|
||||||
|
.set GP_31, (GP_30 + 4)
|
||||||
|
.set GP_CR, (GP_31 + 4)
|
||||||
|
.set GP_PC, (GP_CR + 4)
|
||||||
|
.set GP_MSR, (GP_PC + 4)
|
||||||
|
|
||||||
|
.set FP_0, 0
|
||||||
|
.set FP_1, (FP_0 + 4)
|
||||||
|
.set FP_2, (FP_1 + 4)
|
||||||
|
.set FP_3, (FP_2 + 4)
|
||||||
|
.set FP_4, (FP_3 + 4)
|
||||||
|
.set FP_5, (FP_4 + 4)
|
||||||
|
.set FP_6, (FP_5 + 4)
|
||||||
|
.set FP_7, (FP_6 + 4)
|
||||||
|
.set FP_8, (FP_7 + 4)
|
||||||
|
.set FP_9, (FP_8 + 4)
|
||||||
|
.set FP_10, (FP_9 + 4)
|
||||||
|
.set FP_11, (FP_10 + 4)
|
||||||
|
.set FP_12, (FP_11 + 4)
|
||||||
|
.set FP_13, (FP_12 + 4)
|
||||||
|
.set FP_14, (FP_13 + 4)
|
||||||
|
.set FP_15, (FP_14 + 4)
|
||||||
|
.set FP_16, (FP_15 + 4)
|
||||||
|
.set FP_17, (FP_16 + 4)
|
||||||
|
.set FP_18, (FP_17 + 4)
|
||||||
|
.set FP_19, (FP_18 + 4)
|
||||||
|
.set FP_20, (FP_19 + 4)
|
||||||
|
.set FP_21, (FP_20 + 4)
|
||||||
|
.set FP_22, (FP_21 + 4)
|
||||||
|
.set FP_23, (FP_22 + 4)
|
||||||
|
.set FP_24, (FP_23 + 4)
|
||||||
|
.set FP_25, (FP_24 + 4)
|
||||||
|
.set FP_26, (FP_25 + 4)
|
||||||
|
.set FP_27, (FP_26 + 4)
|
||||||
|
.set FP_28, (FP_27 + 4)
|
||||||
|
.set FP_29, (FP_28 + 4)
|
||||||
|
.set FP_30, (FP_29 + 4)
|
||||||
|
.set FP_31, (FP_30 + 4)
|
||||||
|
.set FP_FPSCR, (FP_31 + 4)
|
||||||
|
|
||||||
|
.set IP_LINK, 0
|
||||||
|
.set IP_0, (IP_LINK + 8)
|
||||||
|
.set IP_2, (IP_0 + 4)
|
||||||
|
|
||||||
|
.set IP_3, (IP_2 + 4)
|
||||||
|
.set IP_4, (IP_3 + 4)
|
||||||
|
.set IP_5, (IP_4 + 4)
|
||||||
|
.set IP_6, (IP_5 + 4)
|
||||||
|
|
||||||
|
.set IP_7, (IP_6 + 4)
|
||||||
|
.set IP_8, (IP_7 + 4)
|
||||||
|
.set IP_9, (IP_8 + 4)
|
||||||
|
.set IP_10, (IP_9 + 4)
|
||||||
|
|
||||||
|
.set IP_11, (IP_10 + 4)
|
||||||
|
.set IP_12, (IP_11 + 4)
|
||||||
|
.set IP_13, (IP_12 + 4)
|
||||||
|
.set IP_28, (IP_13 + 4)
|
||||||
|
|
||||||
|
.set IP_29, (IP_28 + 4)
|
||||||
|
.set IP_30, (IP_29 + 4)
|
||||||
|
.set IP_31, (IP_30 + 4)
|
||||||
|
.set IP_CR, (IP_31 + 4)
|
||||||
|
|
||||||
|
.set IP_CTR, (IP_CR + 4)
|
||||||
|
.set IP_XER, (IP_CTR + 4)
|
||||||
|
.set IP_LR, (IP_XER + 4)
|
||||||
|
.set IP_PC, (IP_LR + 4)
|
||||||
|
|
||||||
|
.set IP_MSR, (IP_PC + 4)
|
||||||
|
.set IP_END, (IP_MSR + 16)
|
||||||
|
|
||||||
|
BEGIN_CODE
|
||||||
|
/*
|
||||||
|
* _CPU_Context_save_fp_context
|
||||||
|
*
|
||||||
|
* This routine is responsible for saving the FP context
|
||||||
|
* at *fp_context_ptr. If the point to load the FP context
|
||||||
|
* from is changed then the pointer is modified by this routine.
|
||||||
|
*
|
||||||
|
* Sometimes a macro implementation of this is in cpu.h which dereferences
|
||||||
|
* the ** and a similarly named routine in this file is passed something
|
||||||
|
* like a (Context_Control_fp *). The general rule on making this decision
|
||||||
|
* is to avoid writing assembly language.
|
||||||
|
*/
|
||||||
|
|
||||||
|
ALIGN (PPC_CACHE_ALIGNMENT, PPC_CACHE_ALIGN_POWER)
|
||||||
|
PUBLIC_PROC (_CPU_Context_save_fp)
|
||||||
|
PROC (_CPU_Context_save_fp):
|
||||||
|
#if (PPC_HAS_FPU == 1)
|
||||||
|
lwz r3, 0(r3)
|
||||||
|
stfs f0, FP_0(r3)
|
||||||
|
stfs f1, FP_1(r3)
|
||||||
|
stfs f2, FP_2(r3)
|
||||||
|
stfs f3, FP_3(r3)
|
||||||
|
stfs f4, FP_4(r3)
|
||||||
|
stfs f5, FP_5(r3)
|
||||||
|
stfs f6, FP_6(r3)
|
||||||
|
stfs f7, FP_7(r3)
|
||||||
|
stfs f8, FP_8(r3)
|
||||||
|
stfs f9, FP_9(r3)
|
||||||
|
stfs f10, FP_10(r3)
|
||||||
|
stfs f11, FP_11(r3)
|
||||||
|
stfs f12, FP_12(r3)
|
||||||
|
stfs f13, FP_13(r3)
|
||||||
|
stfs f14, FP_14(r3)
|
||||||
|
stfs f15, FP_15(r3)
|
||||||
|
stfs f16, FP_16(r3)
|
||||||
|
stfs f17, FP_17(r3)
|
||||||
|
stfs f18, FP_18(r3)
|
||||||
|
stfs f19, FP_19(r3)
|
||||||
|
stfs f20, FP_20(r3)
|
||||||
|
stfs f21, FP_21(r3)
|
||||||
|
stfs f22, FP_22(r3)
|
||||||
|
stfs f23, FP_23(r3)
|
||||||
|
stfs f24, FP_24(r3)
|
||||||
|
stfs f25, FP_25(r3)
|
||||||
|
stfs f26, FP_26(r3)
|
||||||
|
stfs f27, FP_27(r3)
|
||||||
|
stfs f28, FP_28(r3)
|
||||||
|
stfs f29, FP_29(r3)
|
||||||
|
stfs f30, FP_30(r3)
|
||||||
|
stfs f31, FP_31(r3)
|
||||||
|
mffs f2
|
||||||
|
stfs f2, FP_FPSCR(r3)
|
||||||
|
#endif
|
||||||
|
blr
|
||||||
|
|
||||||
|
/*
|
||||||
|
* _CPU_Context_restore_fp_context
|
||||||
|
*
|
||||||
|
* This routine is responsible for restoring the FP context
|
||||||
|
* at *fp_context_ptr. If the point to load the FP context
|
||||||
|
* from is changed then the pointer is modified by this routine.
|
||||||
|
*
|
||||||
|
* Sometimes a macro implementation of this is in cpu.h which dereferences
|
||||||
|
* the ** and a similarly named routine in this file is passed something
|
||||||
|
* like a (Context_Control_fp *). The general rule on making this decision
|
||||||
|
* is to avoid writing assembly language.
|
||||||
|
*/
|
||||||
|
|
||||||
|
ALIGN (PPC_CACHE_ALIGNMENT, PPC_CACHE_ALIGN_POWER)
|
||||||
|
PUBLIC_PROC (_CPU_Context_restore_fp)
|
||||||
|
PROC (_CPU_Context_restore_fp):
|
||||||
|
#if (PPC_HAS_FPU == 1)
|
||||||
|
lwz r3, 0(r3)
|
||||||
|
lfs f2, FP_FPSCR(r3)
|
||||||
|
mtfsf 255, f2
|
||||||
|
lfs f0, FP_0(r3)
|
||||||
|
lfs f1, FP_1(r3)
|
||||||
|
lfs f2, FP_2(r3)
|
||||||
|
lfs f3, FP_3(r3)
|
||||||
|
lfs f4, FP_4(r3)
|
||||||
|
lfs f5, FP_5(r3)
|
||||||
|
lfs f6, FP_6(r3)
|
||||||
|
lfs f7, FP_7(r3)
|
||||||
|
lfs f8, FP_8(r3)
|
||||||
|
lfs f9, FP_9(r3)
|
||||||
|
lfs f10, FP_10(r3)
|
||||||
|
lfs f11, FP_11(r3)
|
||||||
|
lfs f12, FP_12(r3)
|
||||||
|
lfs f13, FP_13(r3)
|
||||||
|
lfs f14, FP_14(r3)
|
||||||
|
lfs f15, FP_15(r3)
|
||||||
|
lfs f16, FP_16(r3)
|
||||||
|
lfs f17, FP_17(r3)
|
||||||
|
lfs f18, FP_18(r3)
|
||||||
|
lfs f19, FP_19(r3)
|
||||||
|
lfs f20, FP_20(r3)
|
||||||
|
lfs f21, FP_21(r3)
|
||||||
|
lfs f22, FP_22(r3)
|
||||||
|
lfs f23, FP_23(r3)
|
||||||
|
lfs f24, FP_24(r3)
|
||||||
|
lfs f25, FP_25(r3)
|
||||||
|
lfs f26, FP_26(r3)
|
||||||
|
lfs f27, FP_27(r3)
|
||||||
|
lfs f28, FP_28(r3)
|
||||||
|
lfs f29, FP_29(r3)
|
||||||
|
lfs f30, FP_30(r3)
|
||||||
|
lfs f31, FP_31(r3)
|
||||||
|
#endif
|
||||||
|
blr
|
||||||
|
|
||||||
|
|
||||||
|
/* _CPU_Context_switch
|
||||||
|
*
|
||||||
|
* This routine performs a normal non-FP context switch.
|
||||||
|
*/
|
||||||
|
ALIGN (PPC_CACHE_ALIGNMENT, PPC_CACHE_ALIGN_POWER)
|
||||||
|
PUBLIC_PROC (_CPU_Context_switch)
|
||||||
|
PROC (_CPU_Context_switch):
|
||||||
|
sync
|
||||||
|
isync
|
||||||
|
/* This assumes that all the registers are in the given order */
|
||||||
|
li r5, 32
|
||||||
|
addi r3,r3,-4
|
||||||
|
#if ( PPC_USE_DATA_CACHE )
|
||||||
|
dcbz r5, r3
|
||||||
|
#endif
|
||||||
|
stw r1, GP_1+4(r3)
|
||||||
|
stw r2, GP_2+4(r3)
|
||||||
|
#if (PPC_USE_MULTIPLE == 1)
|
||||||
|
addi r3, r3, GP_18+4
|
||||||
|
#if ( PPC_USE_DATA_CACHE )
|
||||||
|
dcbz r5, r3
|
||||||
|
#endif
|
||||||
|
stmw r13, GP_13-GP_18(r3)
|
||||||
|
#else
|
||||||
|
stw r13, GP_13+4(r3)
|
||||||
|
stw r14, GP_14+4(r3)
|
||||||
|
stw r15, GP_15+4(r3)
|
||||||
|
stw r16, GP_16+4(r3)
|
||||||
|
stw r17, GP_17+4(r3)
|
||||||
|
stwu r18, GP_18+4(r3)
|
||||||
|
#if ( PPC_USE_DATA_CACHE )
|
||||||
|
dcbz r5, r3
|
||||||
|
#endif
|
||||||
|
stw r19, GP_19-GP_18(r3)
|
||||||
|
stw r20, GP_20-GP_18(r3)
|
||||||
|
stw r21, GP_21-GP_18(r3)
|
||||||
|
stw r22, GP_22-GP_18(r3)
|
||||||
|
stw r23, GP_23-GP_18(r3)
|
||||||
|
stw r24, GP_24-GP_18(r3)
|
||||||
|
stw r25, GP_25-GP_18(r3)
|
||||||
|
stw r26, GP_26-GP_18(r3)
|
||||||
|
stw r27, GP_27-GP_18(r3)
|
||||||
|
stw r28, GP_28-GP_18(r3)
|
||||||
|
stw r29, GP_29-GP_18(r3)
|
||||||
|
stw r30, GP_30-GP_18(r3)
|
||||||
|
stw r31, GP_31-GP_18(r3)
|
||||||
|
#endif
|
||||||
|
#if ( PPC_USE_DATA_CACHE )
|
||||||
|
dcbt r0, r4
|
||||||
|
#endif
|
||||||
|
mfcr r6
|
||||||
|
stw r6, GP_CR-GP_18(r3)
|
||||||
|
mflr r7
|
||||||
|
stw r7, GP_PC-GP_18(r3)
|
||||||
|
mfmsr r8
|
||||||
|
stw r8, GP_MSR-GP_18(r3)
|
||||||
|
|
||||||
|
#if ( PPC_USE_DATA_CACHE )
|
||||||
|
dcbt r5, r4
|
||||||
|
#endif
|
||||||
|
lwz r1, GP_1(r4)
|
||||||
|
lwz r2, GP_2(r4)
|
||||||
|
#if (PPC_USE_MULTIPLE == 1)
|
||||||
|
addi r4, r4, GP_19
|
||||||
|
#if ( PPC_USE_DATA_CACHE )
|
||||||
|
dcbt r5, r4
|
||||||
|
#endif
|
||||||
|
lmw r13, GP_13-GP_19(r4)
|
||||||
|
#else
|
||||||
|
lwz r13, GP_13(r4)
|
||||||
|
lwz r14, GP_14(r4)
|
||||||
|
lwz r15, GP_15(r4)
|
||||||
|
lwz r16, GP_16(r4)
|
||||||
|
lwz r17, GP_17(r4)
|
||||||
|
lwz r18, GP_18(r4)
|
||||||
|
lwzu r19, GP_19(r4)
|
||||||
|
#if ( PPC_USE_DATA_CACHE )
|
||||||
|
dcbt r5, r4
|
||||||
|
#endif
|
||||||
|
lwz r20, GP_20-GP_19(r4)
|
||||||
|
lwz r21, GP_21-GP_19(r4)
|
||||||
|
lwz r22, GP_22-GP_19(r4)
|
||||||
|
lwz r23, GP_23-GP_19(r4)
|
||||||
|
lwz r24, GP_24-GP_19(r4)
|
||||||
|
lwz r25, GP_25-GP_19(r4)
|
||||||
|
lwz r26, GP_26-GP_19(r4)
|
||||||
|
lwz r27, GP_27-GP_19(r4)
|
||||||
|
lwz r28, GP_28-GP_19(r4)
|
||||||
|
lwz r29, GP_29-GP_19(r4)
|
||||||
|
lwz r30, GP_30-GP_19(r4)
|
||||||
|
lwz r31, GP_31-GP_19(r4)
|
||||||
|
#endif
|
||||||
|
lwz r6, GP_CR-GP_19(r4)
|
||||||
|
lwz r7, GP_PC-GP_19(r4)
|
||||||
|
lwz r8, GP_MSR-GP_19(r4)
|
||||||
|
mtcrf 255, r6
|
||||||
|
mtlr r7
|
||||||
|
mtmsr r8
|
||||||
|
|
||||||
|
blr
|
||||||
|
|
||||||
|
/*
|
||||||
|
* _CPU_Context_restore
|
||||||
|
*
|
||||||
|
* This routine is generallu used only to restart self in an
|
||||||
|
* efficient manner. It may simply be a label in _CPU_Context_switch.
|
||||||
|
*
|
||||||
|
* NOTE: May be unnecessary to reload some registers.
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* ACB: Don't worry about cache optimisation here - this is not THAT critical.
|
||||||
|
*/
|
||||||
|
ALIGN (PPC_CACHE_ALIGNMENT, PPC_CACHE_ALIGN_POWER)
|
||||||
|
PUBLIC_PROC (_CPU_Context_restore)
|
||||||
|
PROC (_CPU_Context_restore):
|
||||||
|
lwz r5, GP_CR(r3)
|
||||||
|
lwz r6, GP_PC(r3)
|
||||||
|
lwz r7, GP_MSR(r3)
|
||||||
|
mtcrf 255, r5
|
||||||
|
mtlr r6
|
||||||
|
mtmsr r7
|
||||||
|
lwz r1, GP_1(r3)
|
||||||
|
lwz r2, GP_2(r3)
|
||||||
|
#if (PPC_USE_MULTIPLE == 1)
|
||||||
|
lmw r13, GP_13(r3)
|
||||||
|
#else
|
||||||
|
lwz r13, GP_13(r3)
|
||||||
|
lwz r14, GP_14(r3)
|
||||||
|
lwz r15, GP_15(r3)
|
||||||
|
lwz r16, GP_16(r3)
|
||||||
|
lwz r17, GP_17(r3)
|
||||||
|
lwz r18, GP_18(r3)
|
||||||
|
lwz r19, GP_19(r3)
|
||||||
|
lwz r20, GP_20(r3)
|
||||||
|
lwz r21, GP_21(r3)
|
||||||
|
lwz r22, GP_22(r3)
|
||||||
|
lwz r23, GP_23(r3)
|
||||||
|
lwz r24, GP_24(r3)
|
||||||
|
lwz r25, GP_25(r3)
|
||||||
|
lwz r26, GP_26(r3)
|
||||||
|
lwz r27, GP_27(r3)
|
||||||
|
lwz r28, GP_28(r3)
|
||||||
|
lwz r29, GP_29(r3)
|
||||||
|
lwz r30, GP_30(r3)
|
||||||
|
lwz r31, GP_31(r3)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
blr
|
||||||
|
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
#
|
||||||
|
# $Id$
|
||||||
|
#
|
||||||
|
|
||||||
|
@SET_MAKE@
|
||||||
|
srcdir = @srcdir@
|
||||||
|
top_srcdir = @top_srcdir@
|
||||||
|
top_builddir = ../..
|
||||||
|
subdir = powerpc/old_exception_processing
|
||||||
|
|
||||||
|
RTEMS_ROOT = @RTEMS_ROOT@
|
||||||
|
PROJECT_ROOT = @PROJECT_ROOT@
|
||||||
|
|
||||||
|
VPATH = @srcdir@
|
||||||
|
|
||||||
|
RELS = ../$(ARCH)/rtems-cpu.rel
|
||||||
|
|
||||||
|
# C source names, if any, go here -- minus the .c
|
||||||
|
C_PIECES = cpu ppccache
|
||||||
|
C_FILES = $(C_PIECES:%=%.c)
|
||||||
|
C_O_FILES = $(C_PIECES:%=${ARCH}/%.o)
|
||||||
|
|
||||||
|
ROOT_H_PIECES =
|
||||||
|
ROOT_H_FILES = $(ROOT_H_PIECES:%=$(srcdir)/%)
|
||||||
|
RTEMS_SCORE_H_PIECES = cpu.h
|
||||||
|
RTEMS_SCORE_H_FILES = $(RTEMS_SCORE_H_PIECES:%=$(srcdir)/%)
|
||||||
|
H_PIECES = $(ROOT_H_PIECES) $(RTEMS_SCORE_H_PIECES)
|
||||||
|
H_FILES = $(H_PIECES%=$(srcdir)/%)
|
||||||
|
I_PIECES = c_isr
|
||||||
|
I_FILES = $(I_PIECES:%=$(srcdir)/%.inl)
|
||||||
|
|
||||||
|
# Assembly source names, if any, go here -- minus the .S
|
||||||
|
S_PIECES = cpu_asm rtems # irq_stub
|
||||||
|
S_FILES = $(S_PIECES:%=%.S)
|
||||||
|
S_O_FILES = $(S_FILES:%.S=${ARCH}/%.o)
|
||||||
|
|
||||||
|
SRCS = $(C_FILES) $(CC_FILES) $(H_FILES) $(S_FILES) $(EXTERNAL_H_FILES) \
|
||||||
|
$(I_FILES)
|
||||||
|
OBJS = $(C_O_FILES) $(CC_O_FILES) $(S_O_FILES)
|
||||||
|
|
||||||
|
include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
|
||||||
|
include $(RTEMS_ROOT)/make/leaf.cfg
|
||||||
|
|
||||||
|
INSTALL_CHANGE = @INSTALL_CHANGE@
|
||||||
|
mkinstalldirs = $(SHELL) $(top_srcdir)/@RTEMS_TOPdir@/mkinstalldirs
|
||||||
|
|
||||||
|
INSTALLDIRS = $(PROJECT_INCLUDE)/rtems/score $(PROJECT_INCLUDE)
|
||||||
|
|
||||||
|
$(INSTALLDIRS):
|
||||||
|
@$(mkinstalldirs) $(INSTALLDIRS)
|
||||||
|
|
||||||
|
#
|
||||||
|
# (OPTIONAL) Add local stuff here using +=
|
||||||
|
#
|
||||||
|
|
||||||
|
DEFINES +=
|
||||||
|
CPPFLAGS +=
|
||||||
|
CFLAGS += $(CFLAGS_OS_V)
|
||||||
|
|
||||||
|
LD_PATHS +=
|
||||||
|
LD_LIBS +=
|
||||||
|
LDFLAGS +=
|
||||||
|
|
||||||
|
#
|
||||||
|
# Add your list of files to delete here. The config files
|
||||||
|
# already know how to delete some stuff, so you may want
|
||||||
|
# to just run 'make clean' first to see what gets missed.
|
||||||
|
# 'make clobber' already includes 'make clean'
|
||||||
|
#
|
||||||
|
|
||||||
|
CLEAN_ADDITIONS +=
|
||||||
|
CLOBBER_ADDITIONS +=
|
||||||
|
|
||||||
|
../$(ARCH)/rtems-cpu.rel: $(OBJS)
|
||||||
|
test -d ../$(ARCH) || mkdir ../$(ARCH)
|
||||||
|
$(make-rel)
|
||||||
|
|
||||||
|
all: ${ARCH} $(SRCS) preinstall $(OBJS) $(RELS)
|
||||||
|
|
||||||
|
# Install the program(s), appending _g or _p as appropriate.
|
||||||
|
# for include files, just use $(INSTALL_CHANGE)
|
||||||
|
install: all
|
||||||
|
|
||||||
|
preinstall: ${ARCH}
|
||||||
|
@$(INSTALL_CHANGE) -m 644 $(RTEMS_SCORE_H_FILES) $(I_FILES) $(PROJECT_INCLUDE)/rtems/score
|
||||||
|
@$(INSTALL_CHANGE) -m 644 $(ROOT_H_FILES) $(PROJECT_INCLUDE)
|
||||||
|
|
||||||
|
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||||
|
cd $(top_builddir) \
|
||||||
|
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
|
||||||
80
c/src/exec/score/cpu/powerpc/old_exception_processing/README
Normal file
80
c/src/exec/score/cpu/powerpc/old_exception_processing/README
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
#
|
||||||
|
# $Id$
|
||||||
|
#
|
||||||
|
|
||||||
|
There are various issues regarding this port:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
1) Legal
|
||||||
|
|
||||||
|
This port is written by Andrew Bray <andy@i-cubed.co.uk>, and
|
||||||
|
is copyright 1995 i-cubed ltd.
|
||||||
|
|
||||||
|
This port was later updated by Joel Sherrill <joel@OARcorp.com>
|
||||||
|
to test the support for the PPC603, PPC603e, and MPC604. This
|
||||||
|
was tested on the PowerPC simulator PSIM and a VMEbus single board
|
||||||
|
computer.
|
||||||
|
|
||||||
|
2) CPU support.
|
||||||
|
|
||||||
|
This release fully supports the PPC403GA, PPC403GB, PPC603, PPC603e,
|
||||||
|
MPC604, MPC750, and numerous MPC8xx processors. A good faith attempt
|
||||||
|
has been made to include support other models based upon available
|
||||||
|
documentation including the MPC5xx. There are two interrupt structures
|
||||||
|
supported by the PowerPC port. The newer structure is supported by
|
||||||
|
all the MPC750 and MPC604 BSPs. This structure is required to use
|
||||||
|
the RDBG remote debugging support.
|
||||||
|
|
||||||
|
This port was originally written and tested on the PPC403GA (using
|
||||||
|
software floating point). Current ports are tested primarily on
|
||||||
|
60x CPUs using the PowerPC simulator PSIM.
|
||||||
|
|
||||||
|
Andrew Bray received assistance during the initial porting effort
|
||||||
|
from IBM and Blue Micro and we would like to gratefully acknowledge
|
||||||
|
that help.
|
||||||
|
|
||||||
|
The support for the PPC602 processor is incomplete as only sketchy
|
||||||
|
data is currently available. Perhaps this model has been dropped.
|
||||||
|
|
||||||
|
3) Application Binary Interface
|
||||||
|
|
||||||
|
In the context of RTEMS, the ABI is of interest for the following
|
||||||
|
aspects:
|
||||||
|
|
||||||
|
a) Register usage. Which registers are used to provide static variable
|
||||||
|
linkage, stack pointer etc.
|
||||||
|
|
||||||
|
b) Function calling convention. How parameters are passed, how function
|
||||||
|
variables should be invoked, how values are returned, etc.
|
||||||
|
|
||||||
|
c) Stack frame layout.
|
||||||
|
|
||||||
|
I am aware of a number of ABIs for the PowerPC:
|
||||||
|
|
||||||
|
a) The PowerOpen ABI. This is the original Power ABI used on the RS/6000.
|
||||||
|
This is the only ABI supported by versions of GCC before 2.7.0.
|
||||||
|
|
||||||
|
b) The SVR4 ABI. This is the ABI defined by SunSoft for the Solaris port
|
||||||
|
to the PowerPC.
|
||||||
|
|
||||||
|
c) The Embedded ABI. This is an embedded ABI for PowerPC use, which has no
|
||||||
|
operating system interface defined. It is promoted by SunSoft, Motorola,
|
||||||
|
and Cygnus Support. Cygnus are porting the GNU toolchain to this ABI.
|
||||||
|
|
||||||
|
d) GCC 2.7.0. This compiler is partway along the road to supporting the EABI,
|
||||||
|
but is currently halfway in between.
|
||||||
|
|
||||||
|
This port was built and tested using the PowerOpen ABI, with the following
|
||||||
|
caveat: we used an ELF assembler and linker. So some attention may be
|
||||||
|
required on the assembler files to get them through a traditional (XCOFF)
|
||||||
|
PowerOpen assembler.
|
||||||
|
|
||||||
|
This port contains support for the other ABIs, but this may prove to be
|
||||||
|
incomplete as it is untested.
|
||||||
|
|
||||||
|
The RTEMS PowerPC port supports EABI as the primary ABI. The powerpc-rtems
|
||||||
|
GNU toolset configuration is EABI.
|
||||||
|
|
||||||
|
Andrew Bray, 4 December 1995
|
||||||
|
Joel Sherrill, 16 July 1997
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
# $Id$
|
||||||
|
#
|
||||||
|
|
||||||
|
Todo list:
|
||||||
|
|
||||||
|
Maybe decode external interrupts like the HPPA does.
|
||||||
|
See c/src/lib/libcpu/powerpc/ppc403/ictrl/* for implementation on ppc403
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
RTEMS_INLINE_ROUTINE boolean _ISR_Is_in_progress( void )
|
||||||
|
{
|
||||||
|
return (_ISR_Nest_level != 0);
|
||||||
|
}
|
||||||
853
c/src/exec/score/cpu/powerpc/old_exception_processing/cpu.c
Normal file
853
c/src/exec/score/cpu/powerpc/old_exception_processing/cpu.c
Normal file
@@ -0,0 +1,853 @@
|
|||||||
|
/*
|
||||||
|
* PowerPC CPU Dependent Source
|
||||||
|
*
|
||||||
|
* Author: Andrew Bray <andy@i-cubed.co.uk>
|
||||||
|
*
|
||||||
|
* COPYRIGHT (c) 1995 by i-cubed ltd.
|
||||||
|
*
|
||||||
|
* To anyone who acknowledges that this file is provided "AS IS"
|
||||||
|
* without any express or implied warranty:
|
||||||
|
* permission to use, copy, modify, and distribute this file
|
||||||
|
* for any purpose is hereby granted without fee, provided that
|
||||||
|
* the above copyright notice and this notice appears in all
|
||||||
|
* copies, and that the name of i-cubed limited not be used in
|
||||||
|
* advertising or publicity pertaining to distribution of the
|
||||||
|
* software without specific, written prior permission.
|
||||||
|
* i-cubed limited makes no representations about the suitability
|
||||||
|
* of this software for any purpose.
|
||||||
|
*
|
||||||
|
* Derived from c/src/exec/cpu/no_cpu/cpu.c:
|
||||||
|
*
|
||||||
|
* COPYRIGHT (c) 1989-1997.
|
||||||
|
* On-Line Applications Research Corporation (OAR).
|
||||||
|
* Copyright assigned to U.S. Government, 1994.
|
||||||
|
*
|
||||||
|
* The license and distribution terms for this file may be found in
|
||||||
|
* the file LICENSE in this distribution or at
|
||||||
|
* http://www.OARcorp.com/rtems/license.html.
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <rtems/system.h>
|
||||||
|
#include <rtems/score/isr.h>
|
||||||
|
#include <rtems/score/context.h>
|
||||||
|
#include <rtems/score/thread.h>
|
||||||
|
#include <rtems/score/interr.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* These are for testing purposes.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* _CPU_Initialize
|
||||||
|
*
|
||||||
|
* This routine performs processor dependent initialization.
|
||||||
|
*
|
||||||
|
* INPUT PARAMETERS:
|
||||||
|
* cpu_table - CPU table to initialize
|
||||||
|
* thread_dispatch - address of disptaching routine
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void ppc_spurious(int, CPU_Interrupt_frame *);
|
||||||
|
|
||||||
|
void _CPU_Initialize(
|
||||||
|
rtems_cpu_table *cpu_table,
|
||||||
|
void (*thread_dispatch) /* ignored on this CPU */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
proc_ptr handler = (proc_ptr)ppc_spurious;
|
||||||
|
int i;
|
||||||
|
#if (PPC_ABI != PPC_ABI_POWEROPEN)
|
||||||
|
register unsigned32 r2 = 0;
|
||||||
|
#if (PPC_ABI != PPC_ABI_GCC27)
|
||||||
|
register unsigned32 r13 = 0;
|
||||||
|
|
||||||
|
asm ("mr %0,13" : "=r" ((r13)) : "0" ((r13)));
|
||||||
|
_CPU_IRQ_info.Default_r13 = r13;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
asm ("mr %0,2" : "=r" ((r2)) : "0" ((r2)));
|
||||||
|
_CPU_IRQ_info.Default_r2 = r2;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
_CPU_IRQ_info.Nest_level = &_ISR_Nest_level;
|
||||||
|
_CPU_IRQ_info.Disable_level = &_Thread_Dispatch_disable_level;
|
||||||
|
_CPU_IRQ_info.Vector_table = _ISR_Vector_table;
|
||||||
|
#if (PPC_ABI == PPC_ABI_POWEROPEN)
|
||||||
|
_CPU_IRQ_info.Dispatch_r2 = ((unsigned32 *)_Thread_Dispatch)[1];
|
||||||
|
#endif
|
||||||
|
_CPU_IRQ_info.Switch_necessary = &_Context_Switch_necessary;
|
||||||
|
_CPU_IRQ_info.Signal = &_ISR_Signals_to_thread_executing;
|
||||||
|
|
||||||
|
#if (PPC_USE_SPRG)
|
||||||
|
i = (int)&_CPU_IRQ_info;
|
||||||
|
asm volatile("mtspr 0x113, %0" : "=r" (i) : "0" (i)); /* SPRG 3 */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Store Msr Value in the IRQ info structure.
|
||||||
|
*/
|
||||||
|
_CPU_MSR_Value(_CPU_IRQ_info.msr_initial);
|
||||||
|
|
||||||
|
#if (PPC_USE_SPRG)
|
||||||
|
i = _CPU_IRQ_info.msr_initial;
|
||||||
|
asm volatile("mtspr 0x112, %0" : "=r" (i) : "0" (i)); /* SPRG 2 */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if ( cpu_table->spurious_handler )
|
||||||
|
handler = (proc_ptr)cpu_table->spurious_handler;
|
||||||
|
|
||||||
|
for (i = 0; i < PPC_INTERRUPT_MAX; i++)
|
||||||
|
_ISR_Vector_table[i] = handler;
|
||||||
|
|
||||||
|
_CPU_Table = *cpu_table;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*PAGE
|
||||||
|
*
|
||||||
|
* _CPU_ISR_Calculate_level
|
||||||
|
*
|
||||||
|
* The PowerPC puts its interrupt enable status in the MSR register
|
||||||
|
* which also contains things like endianness control. To be more
|
||||||
|
* awkward, the layout varies from processor to processor. This
|
||||||
|
* is why it was necessary to adopt a scheme which allowed the user
|
||||||
|
* to specify specifically which interrupt sources were enabled.
|
||||||
|
*/
|
||||||
|
|
||||||
|
unsigned32 _CPU_ISR_Calculate_level(
|
||||||
|
unsigned32 new_level
|
||||||
|
)
|
||||||
|
{
|
||||||
|
register unsigned32 new_msr = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the critical interrupt enable bit
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if (PPC_HAS_RFCI)
|
||||||
|
if ( !(new_level & PPC_INTERRUPT_LEVEL_CE) )
|
||||||
|
new_msr |= PPC_MSR_CE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if ( !(new_level & PPC_INTERRUPT_LEVEL_ME) )
|
||||||
|
new_msr |= PPC_MSR_ME;
|
||||||
|
|
||||||
|
if ( !(new_level & PPC_INTERRUPT_LEVEL_EE) )
|
||||||
|
new_msr |= PPC_MSR_EE;
|
||||||
|
|
||||||
|
return new_msr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*PAGE
|
||||||
|
*
|
||||||
|
* _CPU_ISR_Set_level
|
||||||
|
*
|
||||||
|
* This routine sets the requested level in the MSR.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void _CPU_ISR_Set_level(
|
||||||
|
unsigned32 new_level
|
||||||
|
)
|
||||||
|
{
|
||||||
|
register unsigned32 tmp = 0;
|
||||||
|
register unsigned32 new_msr;
|
||||||
|
|
||||||
|
new_msr = _CPU_ISR_Calculate_level( new_level );
|
||||||
|
|
||||||
|
asm volatile (
|
||||||
|
"mfmsr %0; andc %0,%0,%1; and %2, %2, %1; or %0, %0, %2; mtmsr %0" :
|
||||||
|
"=&r" ((tmp)) :
|
||||||
|
"r" ((PPC_MSR_DISABLE_MASK)), "r" ((new_msr)), "0" ((tmp))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*PAGE
|
||||||
|
*
|
||||||
|
* _CPU_ISR_Get_level
|
||||||
|
*
|
||||||
|
* This routine gets the current interrupt level from the MSR and
|
||||||
|
* converts it to an RTEMS interrupt level.
|
||||||
|
*/
|
||||||
|
|
||||||
|
unsigned32 _CPU_ISR_Get_level( void )
|
||||||
|
{
|
||||||
|
unsigned32 level = 0;
|
||||||
|
unsigned32 msr;
|
||||||
|
|
||||||
|
asm volatile("mfmsr %0" : "=r" ((msr)));
|
||||||
|
|
||||||
|
msr &= PPC_MSR_DISABLE_MASK;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the critical interrupt enable bit
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if (PPC_HAS_RFCI)
|
||||||
|
if ( !(msr & PPC_MSR_CE) )
|
||||||
|
level |= PPC_INTERRUPT_LEVEL_CE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if ( !(msr & PPC_MSR_ME) )
|
||||||
|
level |= PPC_INTERRUPT_LEVEL_ME;
|
||||||
|
|
||||||
|
if ( !(msr & PPC_MSR_EE) )
|
||||||
|
level |= PPC_INTERRUPT_LEVEL_EE;
|
||||||
|
|
||||||
|
return level;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*PAGE
|
||||||
|
*
|
||||||
|
* _CPU_Context_Initialize
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if (PPC_ABI == PPC_ABI_POWEROPEN)
|
||||||
|
#define CPU_MINIMUM_STACK_FRAME_SIZE 56
|
||||||
|
#else /* PPC_ABI_SVR4 or PPC_ABI_EABI */
|
||||||
|
#define CPU_MINIMUM_STACK_FRAME_SIZE 8
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void _CPU_Context_Initialize(
|
||||||
|
Context_Control *the_context,
|
||||||
|
unsigned32 *stack_base,
|
||||||
|
unsigned32 size,
|
||||||
|
unsigned32 new_level,
|
||||||
|
void *entry_point,
|
||||||
|
boolean is_fp
|
||||||
|
)
|
||||||
|
{
|
||||||
|
unsigned32 msr_value;
|
||||||
|
unsigned32 sp;
|
||||||
|
|
||||||
|
sp = (unsigned32)stack_base + size - CPU_MINIMUM_STACK_FRAME_SIZE;
|
||||||
|
*((unsigned32 *)sp) = 0;
|
||||||
|
the_context->gpr1 = sp;
|
||||||
|
|
||||||
|
the_context->msr = _CPU_ISR_Calculate_level( new_level );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The FP bit of the MSR should only be enabled if this is a floating
|
||||||
|
* point task. Unfortunately, the vfprintf_r routine in newlib
|
||||||
|
* ends up pushing a floating point register regardless of whether or
|
||||||
|
* not a floating point number is being printed. Serious restructuring
|
||||||
|
* of vfprintf.c will be required to avoid this behavior. At this
|
||||||
|
* time (7 July 1997), this restructuring is not being done.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*if ( is_fp ) */
|
||||||
|
the_context->msr |= PPC_MSR_FP;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calculate the task's MSR value:
|
||||||
|
*
|
||||||
|
* + Set the exception prefix bit to point to the exception table
|
||||||
|
* + Force the RI bit
|
||||||
|
* + Use the DR and IR bits
|
||||||
|
*/
|
||||||
|
_CPU_MSR_Value( msr_value );
|
||||||
|
the_context->msr |= (msr_value & PPC_MSR_EP);
|
||||||
|
the_context->msr |= PPC_MSR_RI;
|
||||||
|
the_context->msr |= msr_value & (PPC_MSR_DR|PPC_MSR_IR);
|
||||||
|
|
||||||
|
#if (PPC_ABI == PPC_ABI_POWEROPEN)
|
||||||
|
{ unsigned32 *desc = (unsigned32 *)entry_point;
|
||||||
|
|
||||||
|
the_context->pc = desc[0];
|
||||||
|
the_context->gpr2 = desc[1];
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (PPC_ABI == PPC_ABI_SVR4)
|
||||||
|
{ unsigned r13 = 0;
|
||||||
|
asm volatile ("mr %0, 13" : "=r" ((r13)));
|
||||||
|
|
||||||
|
the_context->pc = (unsigned32)entry_point;
|
||||||
|
the_context->gpr13 = r13;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (PPC_ABI == PPC_ABI_EABI)
|
||||||
|
{ unsigned32 r2 = 0;
|
||||||
|
unsigned r13 = 0;
|
||||||
|
asm volatile ("mr %0,2; mr %1,13" : "=r" ((r2)), "=r" ((r13)));
|
||||||
|
|
||||||
|
the_context->pc = (unsigned32)entry_point;
|
||||||
|
the_context->gpr2 = r2;
|
||||||
|
the_context->gpr13 = r13;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* _CPU_ISR_install_vector
|
||||||
|
*
|
||||||
|
* This kernel routine installs the RTEMS handler for the
|
||||||
|
* specified vector.
|
||||||
|
*
|
||||||
|
* Input parameters:
|
||||||
|
* vector - interrupt vector number
|
||||||
|
* old_handler - former ISR for this vector number
|
||||||
|
* new_handler - replacement ISR for this vector number
|
||||||
|
*
|
||||||
|
* Output parameters: NONE
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void _CPU_ISR_install_vector(
|
||||||
|
unsigned32 vector,
|
||||||
|
proc_ptr new_handler,
|
||||||
|
proc_ptr *old_handler
|
||||||
|
)
|
||||||
|
{
|
||||||
|
proc_ptr ignored;
|
||||||
|
*old_handler = _ISR_Vector_table[ vector ];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the interrupt vector table is a table of pointer to isr entry
|
||||||
|
* points, then we need to install the appropriate RTEMS interrupt
|
||||||
|
* handler for this vector number.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Install the wrapper so this ISR can be invoked properly.
|
||||||
|
*/
|
||||||
|
if (_CPU_Table.exceptions_in_RAM)
|
||||||
|
_CPU_ISR_install_raw_handler( vector, _ISR_Handler, &ignored );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We put the actual user ISR address in '_ISR_vector_table'. This will
|
||||||
|
* be used by the _ISR_Handler so the user gets control.
|
||||||
|
*/
|
||||||
|
|
||||||
|
_ISR_Vector_table[ vector ] = new_handler ? (ISR_Handler_entry)new_handler :
|
||||||
|
_CPU_Table.spurious_handler ?
|
||||||
|
(ISR_Handler_entry)_CPU_Table.spurious_handler :
|
||||||
|
(ISR_Handler_entry)ppc_spurious;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*PAGE
|
||||||
|
*
|
||||||
|
* _CPU_Install_interrupt_stack
|
||||||
|
*/
|
||||||
|
|
||||||
|
void _CPU_Install_interrupt_stack( void )
|
||||||
|
{
|
||||||
|
#if (PPC_ABI == PPC_ABI_POWEROPEN || PPC_ABI == PPC_ABI_GCC27)
|
||||||
|
_CPU_IRQ_info.Stack = _CPU_Interrupt_stack_high - 56;
|
||||||
|
#else
|
||||||
|
_CPU_IRQ_info.Stack = _CPU_Interrupt_stack_high - 8;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle a spurious interrupt */
|
||||||
|
static void ppc_spurious(int v, CPU_Interrupt_frame *i)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
printf("Spurious interrupt on vector %d from %08.8x\n",
|
||||||
|
v, i->pc);
|
||||||
|
#endif
|
||||||
|
#ifdef ppc403
|
||||||
|
if (v == PPC_IRQ_EXTERNAL)
|
||||||
|
{
|
||||||
|
register int r = 0;
|
||||||
|
|
||||||
|
asm volatile("mtdcr 0x42, %0" :
|
||||||
|
"=&r" ((r)) : "0" ((r))); /* EXIER */
|
||||||
|
}
|
||||||
|
else if (v == PPC_IRQ_PIT)
|
||||||
|
{
|
||||||
|
register int r = 0x08000000;
|
||||||
|
|
||||||
|
asm volatile("mtspr 0x3d8, %0" :
|
||||||
|
"=&r" ((r)) : "0" ((r))); /* TSR */
|
||||||
|
}
|
||||||
|
else if (v == PPC_IRQ_FIT)
|
||||||
|
{
|
||||||
|
register int r = 0x04000000;
|
||||||
|
|
||||||
|
asm volatile("mtspr 0x3d8, %0" :
|
||||||
|
"=&r" ((r)) : "0" ((r))); /* TSR */
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void _CPU_Fatal_error(unsigned32 _error)
|
||||||
|
{
|
||||||
|
asm volatile ("mr 3, %0" : : "r" ((_error)));
|
||||||
|
asm volatile ("tweq 5,5");
|
||||||
|
asm volatile ("li 0,0; mtmsr 0");
|
||||||
|
while (1) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define PPC_SYNCHRONOUS_TRAP_BIT_MASK 0x100
|
||||||
|
#define PPC_ASYNCHRONOUS_TRAP( _trap ) (_trap)
|
||||||
|
#define PPC_SYNCHRONOUS_TRAP ( _trap ) ((_trap)+PPC_SYNCHRONOUS_TRAP_BIT_MASK)
|
||||||
|
#define PPC_REAL_TRAP_NUMBER ( _trap ) ((_trap)%PPC_SYNCHRONOUS_TRAP_BIT_MASK)
|
||||||
|
|
||||||
|
|
||||||
|
const CPU_Trap_table_entry _CPU_Trap_slot_template = {
|
||||||
|
|
||||||
|
#if (PPC_ABI == PPC_ABI_POWEROPEN || PPC_ABI == PPC_ABI_GCC27)
|
||||||
|
#error " Vector install not tested."
|
||||||
|
#if (PPC_HAS_FPU)
|
||||||
|
#error " Vector install not tested."
|
||||||
|
0x9421feb0, /* stwu r1, -(20*4 + 18*8 + IP_END)(r1) */
|
||||||
|
#else
|
||||||
|
#error " Vector install not tested."
|
||||||
|
0x9421ff40, /* stwu r1, -(20*4 + IP_END)(r1) */
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
0x9421ff90, /* stwu r1, -(IP_END)(r1) */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
0x90010008, /* stw %r0, IP_0(%r1) */
|
||||||
|
0x38000000, /* li %r0, PPC_IRQ */
|
||||||
|
0x48000002 /* ba PROC (_ISR_Handler) */
|
||||||
|
};
|
||||||
|
|
||||||
|
#if defined(mpc860) || defined(mpc821)
|
||||||
|
const CPU_Trap_table_entry _CPU_Trap_slot_template_m860 = {
|
||||||
|
0x7c0803ac, /* mtlr %r0 */
|
||||||
|
0x81210028, /* lwz %r9, IP_9(%r1) */
|
||||||
|
0x38000000, /* li %r0, PPC_IRQ */
|
||||||
|
0x48000002 /* b PROC (_ISR_Handler) */
|
||||||
|
};
|
||||||
|
#endif /* mpc860 */
|
||||||
|
|
||||||
|
unsigned32 ppc_exception_vector_addr(
|
||||||
|
unsigned32 vector
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
/*PAGE
|
||||||
|
*
|
||||||
|
* _CPU_ISR_install_raw_handler
|
||||||
|
*
|
||||||
|
* This routine installs the specified handler as a "raw" non-executive
|
||||||
|
* supported trap handler (a.k.a. interrupt service routine).
|
||||||
|
*
|
||||||
|
* Input Parameters:
|
||||||
|
* vector - trap table entry number plus synchronous
|
||||||
|
* vs. asynchronous information
|
||||||
|
* new_handler - address of the handler to be installed
|
||||||
|
* old_handler - pointer to an address of the handler previously installed
|
||||||
|
*
|
||||||
|
* Output Parameters: NONE
|
||||||
|
* *new_handler - address of the handler previously installed
|
||||||
|
*
|
||||||
|
* NOTE:
|
||||||
|
*
|
||||||
|
* This routine is based on the SPARC routine _CPU_ISR_install_raw_handler.
|
||||||
|
* Install a software trap handler as an executive interrupt handler
|
||||||
|
* (which is desirable since RTEMS takes care of window and register issues),
|
||||||
|
* then the executive needs to know that the return address is to the trap
|
||||||
|
* rather than the instruction following the trap.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void _CPU_ISR_install_raw_handler(
|
||||||
|
unsigned32 vector,
|
||||||
|
proc_ptr new_handler,
|
||||||
|
proc_ptr *old_handler
|
||||||
|
)
|
||||||
|
{
|
||||||
|
unsigned32 real_vector;
|
||||||
|
CPU_Trap_table_entry *slot;
|
||||||
|
unsigned32 u32_handler=0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the "real" trap number for this vector ignoring the synchronous
|
||||||
|
* versus asynchronous indicator included with our vector numbers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
real_vector = vector;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the current base address of the trap table and calculate a pointer
|
||||||
|
* to the slot we are interested in.
|
||||||
|
*/
|
||||||
|
slot = (CPU_Trap_table_entry *)ppc_exception_vector_addr( real_vector );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the address of the old_handler from the trap table.
|
||||||
|
*
|
||||||
|
* NOTE: The old_handler returned will be bogus if it does not follow
|
||||||
|
* the RTEMS model.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define HIGH_BITS_MASK 0xFFFFFC00
|
||||||
|
#define HIGH_BITS_SHIFT 10
|
||||||
|
#define LOW_BITS_MASK 0x000003FF
|
||||||
|
|
||||||
|
if (slot->stwu_r1 == _CPU_Trap_slot_template.stwu_r1) {
|
||||||
|
/*
|
||||||
|
* Set u32_handler = to target address
|
||||||
|
*/
|
||||||
|
u32_handler = slot->b_Handler & 0x03fffffc;
|
||||||
|
|
||||||
|
/* IMD FIX: sign extend address fragment... */
|
||||||
|
if (u32_handler & 0x02000000) {
|
||||||
|
u32_handler |= 0xfc000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
*old_handler = (proc_ptr) u32_handler;
|
||||||
|
} else
|
||||||
|
/* There are two kinds of handlers for the MPC860. One is the 'standard'
|
||||||
|
* one like above. The other is for the cascaded interrupts from the SIU
|
||||||
|
* and CPM. Therefore we must check for the alternate one if the standard
|
||||||
|
* one is not present
|
||||||
|
*/
|
||||||
|
#if defined(mpc860) || defined(mpc821)
|
||||||
|
if (slot->stwu_r1 == _CPU_Trap_slot_template_m860.stwu_r1) {
|
||||||
|
/*
|
||||||
|
* Set u32_handler = to target address
|
||||||
|
*/
|
||||||
|
u32_handler = slot->b_Handler & 0x03fffffc;
|
||||||
|
*old_handler = (proc_ptr) u32_handler;
|
||||||
|
} else
|
||||||
|
#endif /* mpc860 */
|
||||||
|
|
||||||
|
*old_handler = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copy the template to the slot and then fix it.
|
||||||
|
*/
|
||||||
|
#if defined(mpc860) || defined(mpc821)
|
||||||
|
if (vector >= PPC_IRQ_IRQ0)
|
||||||
|
*slot = _CPU_Trap_slot_template_m860;
|
||||||
|
else
|
||||||
|
#endif /* mpc860 */
|
||||||
|
*slot = _CPU_Trap_slot_template;
|
||||||
|
|
||||||
|
u32_handler = (unsigned32) new_handler;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IMD FIX: insert address fragment only (bits 6..29)
|
||||||
|
* therefore check for proper address range
|
||||||
|
* and remove unwanted bits
|
||||||
|
*/
|
||||||
|
if ((u32_handler & 0xfc000000) == 0xfc000000) {
|
||||||
|
u32_handler &= ~0xfc000000;
|
||||||
|
}
|
||||||
|
else if ((u32_handler & 0xfc000000) != 0x00000000) {
|
||||||
|
_Internal_error_Occurred(INTERNAL_ERROR_CORE,
|
||||||
|
TRUE,
|
||||||
|
u32_handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
slot->b_Handler |= u32_handler;
|
||||||
|
|
||||||
|
slot->li_r0_IRQ |= vector;
|
||||||
|
|
||||||
|
_CPU_Data_Cache_Block_Flush( slot );
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned32 ppc_exception_vector_addr(
|
||||||
|
unsigned32 vector
|
||||||
|
)
|
||||||
|
{
|
||||||
|
#if (!PPC_HAS_EVPR)
|
||||||
|
unsigned32 Msr;
|
||||||
|
#endif
|
||||||
|
unsigned32 Top = 0;
|
||||||
|
unsigned32 Offset = 0x000;
|
||||||
|
|
||||||
|
#if (PPC_HAS_EXCEPTION_PREFIX)
|
||||||
|
_CPU_MSR_Value ( Msr );
|
||||||
|
if ( ( Msr & PPC_MSR_EP) != 0 ) /* Vectors at FFFx_xxxx */
|
||||||
|
Top = 0xfff00000;
|
||||||
|
#elif (PPC_HAS_EVPR)
|
||||||
|
asm volatile( "mfspr %0,0x3d6" : "=r" (Top)); /* EVPR */
|
||||||
|
Top = Top & 0xffff0000;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
switch ( vector ) {
|
||||||
|
case PPC_IRQ_SYSTEM_RESET: /* on 40x aka PPC_IRQ_CRIT */
|
||||||
|
Offset = 0x00100;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_MCHECK:
|
||||||
|
Offset = 0x00200;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_PROTECT:
|
||||||
|
Offset = 0x00300;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_ISI:
|
||||||
|
Offset = 0x00400;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_EXTERNAL:
|
||||||
|
Offset = 0x00500;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_ALIGNMENT:
|
||||||
|
Offset = 0x00600;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_PROGRAM:
|
||||||
|
Offset = 0x00700;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_NOFP:
|
||||||
|
Offset = 0x00800;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_DECREMENTER:
|
||||||
|
Offset = 0x00900;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_RESERVED_A:
|
||||||
|
Offset = 0x00a00;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_RESERVED_B:
|
||||||
|
Offset = 0x00b00;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_SCALL:
|
||||||
|
Offset = 0x00c00;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_TRACE:
|
||||||
|
Offset = 0x00d00;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_FP_ASST:
|
||||||
|
Offset = 0x00e00;
|
||||||
|
break;
|
||||||
|
|
||||||
|
#if defined(ppc403)
|
||||||
|
|
||||||
|
/* PPC_IRQ_CRIT is the same vector as PPC_IRQ_RESET
|
||||||
|
case PPC_IRQ_CRIT:
|
||||||
|
Offset = 0x00100;
|
||||||
|
break;
|
||||||
|
*/
|
||||||
|
case PPC_IRQ_PIT:
|
||||||
|
Offset = 0x01000;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_FIT:
|
||||||
|
Offset = 0x01010;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_WATCHDOG:
|
||||||
|
Offset = 0x01020;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_DEBUG:
|
||||||
|
Offset = 0x02000;
|
||||||
|
break;
|
||||||
|
|
||||||
|
#elif defined(ppc601)
|
||||||
|
case PPC_IRQ_TRACE:
|
||||||
|
Offset = 0x02000;
|
||||||
|
break;
|
||||||
|
|
||||||
|
#elif defined(ppc603)
|
||||||
|
case PPC_IRQ_TRANS_MISS:
|
||||||
|
Offset = 0x1000;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_DATA_LOAD:
|
||||||
|
Offset = 0x1100;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_DATA_STORE:
|
||||||
|
Offset = 0x1200;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_ADDR_BRK:
|
||||||
|
Offset = 0x1300;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_SYS_MGT:
|
||||||
|
Offset = 0x1400;
|
||||||
|
break;
|
||||||
|
|
||||||
|
#elif defined(ppc603e)
|
||||||
|
case PPC_TLB_INST_MISS:
|
||||||
|
Offset = 0x1000;
|
||||||
|
break;
|
||||||
|
case PPC_TLB_LOAD_MISS:
|
||||||
|
Offset = 0x1100;
|
||||||
|
break;
|
||||||
|
case PPC_TLB_STORE_MISS:
|
||||||
|
Offset = 0x1200;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_ADDRBRK:
|
||||||
|
Offset = 0x1300;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_SYS_MGT:
|
||||||
|
Offset = 0x1400;
|
||||||
|
break;
|
||||||
|
|
||||||
|
#elif defined(mpc604)
|
||||||
|
case PPC_IRQ_ADDR_BRK:
|
||||||
|
Offset = 0x1300;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_SYS_MGT:
|
||||||
|
Offset = 0x1400;
|
||||||
|
break;
|
||||||
|
|
||||||
|
#elif defined(mpc860) || defined(mpc821)
|
||||||
|
case PPC_IRQ_EMULATE:
|
||||||
|
Offset = 0x1000;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_INST_MISS:
|
||||||
|
Offset = 0x1100;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_DATA_MISS:
|
||||||
|
Offset = 0x1200;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_INST_ERR:
|
||||||
|
Offset = 0x1300;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_DATA_ERR:
|
||||||
|
Offset = 0x1400;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_DATA_BPNT:
|
||||||
|
Offset = 0x1c00;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_INST_BPNT:
|
||||||
|
Offset = 0x1d00;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_IO_BPNT:
|
||||||
|
Offset = 0x1e00;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_DEV_PORT:
|
||||||
|
Offset = 0x1f00;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_IRQ0:
|
||||||
|
Offset = 0x2000;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_LVL0:
|
||||||
|
Offset = 0x2040;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_IRQ1:
|
||||||
|
Offset = 0x2080;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_LVL1:
|
||||||
|
Offset = 0x20c0;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_IRQ2:
|
||||||
|
Offset = 0x2100;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_LVL2:
|
||||||
|
Offset = 0x2140;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_IRQ3:
|
||||||
|
Offset = 0x2180;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_LVL3:
|
||||||
|
Offset = 0x21c0;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_IRQ4:
|
||||||
|
Offset = 0x2200;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_LVL4:
|
||||||
|
Offset = 0x2240;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_IRQ5:
|
||||||
|
Offset = 0x2280;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_LVL5:
|
||||||
|
Offset = 0x22c0;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_IRQ6:
|
||||||
|
Offset = 0x2300;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_LVL6:
|
||||||
|
Offset = 0x2340;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_IRQ7:
|
||||||
|
Offset = 0x2380;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_LVL7:
|
||||||
|
Offset = 0x23c0;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_CPM_RESERVED_0:
|
||||||
|
Offset = 0x2400;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_CPM_PC4:
|
||||||
|
Offset = 0x2410;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_CPM_PC5:
|
||||||
|
Offset = 0x2420;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_CPM_SMC2:
|
||||||
|
Offset = 0x2430;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_CPM_SMC1:
|
||||||
|
Offset = 0x2440;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_CPM_SPI:
|
||||||
|
Offset = 0x2450;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_CPM_PC6:
|
||||||
|
Offset = 0x2460;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_CPM_TIMER4:
|
||||||
|
Offset = 0x2470;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_CPM_RESERVED_8:
|
||||||
|
Offset = 0x2480;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_CPM_PC7:
|
||||||
|
Offset = 0x2490;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_CPM_PC8:
|
||||||
|
Offset = 0x24a0;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_CPM_PC9:
|
||||||
|
Offset = 0x24b0;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_CPM_TIMER3:
|
||||||
|
Offset = 0x24c0;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_CPM_RESERVED_D:
|
||||||
|
Offset = 0x24d0;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_CPM_PC10:
|
||||||
|
Offset = 0x24e0;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_CPM_PC11:
|
||||||
|
Offset = 0x24f0;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_CPM_I2C:
|
||||||
|
Offset = 0x2500;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_CPM_RISC_TIMER:
|
||||||
|
Offset = 0x2510;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_CPM_TIMER2:
|
||||||
|
Offset = 0x2520;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_CPM_RESERVED_13:
|
||||||
|
Offset = 0x2530;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_CPM_IDMA2:
|
||||||
|
Offset = 0x2540;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_CPM_IDMA1:
|
||||||
|
Offset = 0x2550;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_CPM_SDMA_ERROR:
|
||||||
|
Offset = 0x2560;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_CPM_PC12:
|
||||||
|
Offset = 0x2570;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_CPM_PC13:
|
||||||
|
Offset = 0x2580;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_CPM_TIMER1:
|
||||||
|
Offset = 0x2590;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_CPM_PC14:
|
||||||
|
Offset = 0x25a0;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_CPM_SCC4:
|
||||||
|
Offset = 0x25b0;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_CPM_SCC3:
|
||||||
|
Offset = 0x25c0;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_CPM_SCC2:
|
||||||
|
Offset = 0x25d0;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_CPM_SCC1:
|
||||||
|
Offset = 0x25e0;
|
||||||
|
break;
|
||||||
|
case PPC_IRQ_CPM_PC15:
|
||||||
|
Offset = 0x25f0;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
Top += Offset;
|
||||||
|
return Top;
|
||||||
|
}
|
||||||
|
|
||||||
1200
c/src/exec/score/cpu/powerpc/old_exception_processing/cpu.h
Normal file
1200
c/src/exec/score/cpu/powerpc/old_exception_processing/cpu.h
Normal file
File diff suppressed because it is too large
Load Diff
809
c/src/exec/score/cpu/powerpc/old_exception_processing/cpu_asm.S
Normal file
809
c/src/exec/score/cpu/powerpc/old_exception_processing/cpu_asm.S
Normal file
@@ -0,0 +1,809 @@
|
|||||||
|
|
||||||
|
/* cpu_asm.s 1.1 - 95/12/04
|
||||||
|
*
|
||||||
|
* This file contains the assembly code for the PowerPC implementation
|
||||||
|
* of RTEMS.
|
||||||
|
*
|
||||||
|
* Author: Andrew Bray <andy@i-cubed.co.uk>
|
||||||
|
*
|
||||||
|
* COPYRIGHT (c) 1995 by i-cubed ltd.
|
||||||
|
*
|
||||||
|
* To anyone who acknowledges that this file is provided "AS IS"
|
||||||
|
* without any express or implied warranty:
|
||||||
|
* permission to use, copy, modify, and distribute this file
|
||||||
|
* for any purpose is hereby granted without fee, provided that
|
||||||
|
* the above copyright notice and this notice appears in all
|
||||||
|
* copies, and that the name of i-cubed limited not be used in
|
||||||
|
* advertising or publicity pertaining to distribution of the
|
||||||
|
* software without specific, written prior permission.
|
||||||
|
* i-cubed limited makes no representations about the suitability
|
||||||
|
* of this software for any purpose.
|
||||||
|
*
|
||||||
|
* Derived from c/src/exec/cpu/no_cpu/cpu_asm.c:
|
||||||
|
*
|
||||||
|
* COPYRIGHT (c) 1989-1997.
|
||||||
|
* On-Line Applications Research Corporation (OAR).
|
||||||
|
* Copyright assigned to U.S. Government, 1994.
|
||||||
|
*
|
||||||
|
* The license and distribution terms for this file may in
|
||||||
|
* the file LICENSE in this distribution or at
|
||||||
|
* http://www.OARcorp.com/rtems/license.html.
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <asm.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Offsets for various Contexts
|
||||||
|
*/
|
||||||
|
.set GP_1, 0
|
||||||
|
.set GP_2, (GP_1 + 4)
|
||||||
|
.set GP_13, (GP_2 + 4)
|
||||||
|
.set GP_14, (GP_13 + 4)
|
||||||
|
|
||||||
|
.set GP_15, (GP_14 + 4)
|
||||||
|
.set GP_16, (GP_15 + 4)
|
||||||
|
.set GP_17, (GP_16 + 4)
|
||||||
|
.set GP_18, (GP_17 + 4)
|
||||||
|
|
||||||
|
.set GP_19, (GP_18 + 4)
|
||||||
|
.set GP_20, (GP_19 + 4)
|
||||||
|
.set GP_21, (GP_20 + 4)
|
||||||
|
.set GP_22, (GP_21 + 4)
|
||||||
|
|
||||||
|
.set GP_23, (GP_22 + 4)
|
||||||
|
.set GP_24, (GP_23 + 4)
|
||||||
|
.set GP_25, (GP_24 + 4)
|
||||||
|
.set GP_26, (GP_25 + 4)
|
||||||
|
|
||||||
|
.set GP_27, (GP_26 + 4)
|
||||||
|
.set GP_28, (GP_27 + 4)
|
||||||
|
.set GP_29, (GP_28 + 4)
|
||||||
|
.set GP_30, (GP_29 + 4)
|
||||||
|
|
||||||
|
.set GP_31, (GP_30 + 4)
|
||||||
|
.set GP_CR, (GP_31 + 4)
|
||||||
|
.set GP_PC, (GP_CR + 4)
|
||||||
|
.set GP_MSR, (GP_PC + 4)
|
||||||
|
|
||||||
|
#if (PPC_HAS_DOUBLE == 1)
|
||||||
|
.set FP_0, 0
|
||||||
|
.set FP_1, (FP_0 + 8)
|
||||||
|
.set FP_2, (FP_1 + 8)
|
||||||
|
.set FP_3, (FP_2 + 8)
|
||||||
|
.set FP_4, (FP_3 + 8)
|
||||||
|
.set FP_5, (FP_4 + 8)
|
||||||
|
.set FP_6, (FP_5 + 8)
|
||||||
|
.set FP_7, (FP_6 + 8)
|
||||||
|
.set FP_8, (FP_7 + 8)
|
||||||
|
.set FP_9, (FP_8 + 8)
|
||||||
|
.set FP_10, (FP_9 + 8)
|
||||||
|
.set FP_11, (FP_10 + 8)
|
||||||
|
.set FP_12, (FP_11 + 8)
|
||||||
|
.set FP_13, (FP_12 + 8)
|
||||||
|
.set FP_14, (FP_13 + 8)
|
||||||
|
.set FP_15, (FP_14 + 8)
|
||||||
|
.set FP_16, (FP_15 + 8)
|
||||||
|
.set FP_17, (FP_16 + 8)
|
||||||
|
.set FP_18, (FP_17 + 8)
|
||||||
|
.set FP_19, (FP_18 + 8)
|
||||||
|
.set FP_20, (FP_19 + 8)
|
||||||
|
.set FP_21, (FP_20 + 8)
|
||||||
|
.set FP_22, (FP_21 + 8)
|
||||||
|
.set FP_23, (FP_22 + 8)
|
||||||
|
.set FP_24, (FP_23 + 8)
|
||||||
|
.set FP_25, (FP_24 + 8)
|
||||||
|
.set FP_26, (FP_25 + 8)
|
||||||
|
.set FP_27, (FP_26 + 8)
|
||||||
|
.set FP_28, (FP_27 + 8)
|
||||||
|
.set FP_29, (FP_28 + 8)
|
||||||
|
.set FP_30, (FP_29 + 8)
|
||||||
|
.set FP_31, (FP_30 + 8)
|
||||||
|
.set FP_FPSCR, (FP_31 + 8)
|
||||||
|
#else
|
||||||
|
.set FP_0, 0
|
||||||
|
.set FP_1, (FP_0 + 4)
|
||||||
|
.set FP_2, (FP_1 + 4)
|
||||||
|
.set FP_3, (FP_2 + 4)
|
||||||
|
.set FP_4, (FP_3 + 4)
|
||||||
|
.set FP_5, (FP_4 + 4)
|
||||||
|
.set FP_6, (FP_5 + 4)
|
||||||
|
.set FP_7, (FP_6 + 4)
|
||||||
|
.set FP_8, (FP_7 + 4)
|
||||||
|
.set FP_9, (FP_8 + 4)
|
||||||
|
.set FP_10, (FP_9 + 4)
|
||||||
|
.set FP_11, (FP_10 + 4)
|
||||||
|
.set FP_12, (FP_11 + 4)
|
||||||
|
.set FP_13, (FP_12 + 4)
|
||||||
|
.set FP_14, (FP_13 + 4)
|
||||||
|
.set FP_15, (FP_14 + 4)
|
||||||
|
.set FP_16, (FP_15 + 4)
|
||||||
|
.set FP_17, (FP_16 + 4)
|
||||||
|
.set FP_18, (FP_17 + 4)
|
||||||
|
.set FP_19, (FP_18 + 4)
|
||||||
|
.set FP_20, (FP_19 + 4)
|
||||||
|
.set FP_21, (FP_20 + 4)
|
||||||
|
.set FP_22, (FP_21 + 4)
|
||||||
|
.set FP_23, (FP_22 + 4)
|
||||||
|
.set FP_24, (FP_23 + 4)
|
||||||
|
.set FP_25, (FP_24 + 4)
|
||||||
|
.set FP_26, (FP_25 + 4)
|
||||||
|
.set FP_27, (FP_26 + 4)
|
||||||
|
.set FP_28, (FP_27 + 4)
|
||||||
|
.set FP_29, (FP_28 + 4)
|
||||||
|
.set FP_30, (FP_29 + 4)
|
||||||
|
.set FP_31, (FP_30 + 4)
|
||||||
|
.set FP_FPSCR, (FP_31 + 4)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
.set IP_LINK, 0
|
||||||
|
#if (PPC_ABI == PPC_ABI_POWEROPEN || PPC_ABI == PPC_ABI_GCC27)
|
||||||
|
.set IP_0, (IP_LINK + 56)
|
||||||
|
#else
|
||||||
|
.set IP_0, (IP_LINK + 8)
|
||||||
|
#endif
|
||||||
|
.set IP_2, (IP_0 + 4)
|
||||||
|
|
||||||
|
.set IP_3, (IP_2 + 4)
|
||||||
|
.set IP_4, (IP_3 + 4)
|
||||||
|
.set IP_5, (IP_4 + 4)
|
||||||
|
.set IP_6, (IP_5 + 4)
|
||||||
|
|
||||||
|
.set IP_7, (IP_6 + 4)
|
||||||
|
.set IP_8, (IP_7 + 4)
|
||||||
|
.set IP_9, (IP_8 + 4)
|
||||||
|
.set IP_10, (IP_9 + 4)
|
||||||
|
|
||||||
|
.set IP_11, (IP_10 + 4)
|
||||||
|
.set IP_12, (IP_11 + 4)
|
||||||
|
.set IP_13, (IP_12 + 4)
|
||||||
|
.set IP_28, (IP_13 + 4)
|
||||||
|
|
||||||
|
.set IP_29, (IP_28 + 4)
|
||||||
|
.set IP_30, (IP_29 + 4)
|
||||||
|
.set IP_31, (IP_30 + 4)
|
||||||
|
.set IP_CR, (IP_31 + 4)
|
||||||
|
|
||||||
|
.set IP_CTR, (IP_CR + 4)
|
||||||
|
.set IP_XER, (IP_CTR + 4)
|
||||||
|
.set IP_LR, (IP_XER + 4)
|
||||||
|
.set IP_PC, (IP_LR + 4)
|
||||||
|
|
||||||
|
.set IP_MSR, (IP_PC + 4)
|
||||||
|
.set IP_END, (IP_MSR + 16)
|
||||||
|
|
||||||
|
/* _CPU_IRQ_info offsets */
|
||||||
|
|
||||||
|
/* These must be in this order */
|
||||||
|
.set Nest_level, 0
|
||||||
|
.set Disable_level, 4
|
||||||
|
.set Vector_table, 8
|
||||||
|
.set Stack, 12
|
||||||
|
#if (PPC_ABI == PPC_ABI_POWEROPEN)
|
||||||
|
.set Dispatch_r2, 16
|
||||||
|
.set Switch_necessary, 20
|
||||||
|
#else
|
||||||
|
.set Default_r2, 16
|
||||||
|
#if (PPC_ABI != PPC_ABI_GCC27)
|
||||||
|
.set Default_r13, 20
|
||||||
|
.set Switch_necessary, 24
|
||||||
|
#else
|
||||||
|
.set Switch_necessary, 20
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
.set Signal, Switch_necessary + 4
|
||||||
|
.set msr_initial, Signal + 4
|
||||||
|
|
||||||
|
BEGIN_CODE
|
||||||
|
/*
|
||||||
|
* _CPU_Context_save_fp_context
|
||||||
|
*
|
||||||
|
* This routine is responsible for saving the FP context
|
||||||
|
* at *fp_context_ptr. If the point to load the FP context
|
||||||
|
* from is changed then the pointer is modified by this routine.
|
||||||
|
*
|
||||||
|
* Sometimes a macro implementation of this is in cpu.h which dereferences
|
||||||
|
* the ** and a similarly named routine in this file is passed something
|
||||||
|
* like a (Context_Control_fp *). The general rule on making this decision
|
||||||
|
* is to avoid writing assembly language.
|
||||||
|
*/
|
||||||
|
|
||||||
|
ALIGN (PPC_CACHE_ALIGNMENT, PPC_CACHE_ALIGN_POWER)
|
||||||
|
PUBLIC_PROC (_CPU_Context_save_fp)
|
||||||
|
PROC (_CPU_Context_save_fp):
|
||||||
|
#if (PPC_HAS_FPU == 1)
|
||||||
|
lwz r3, 0(r3)
|
||||||
|
#if (PPC_HAS_DOUBLE == 1)
|
||||||
|
stfd f0, FP_0(r3)
|
||||||
|
stfd f1, FP_1(r3)
|
||||||
|
stfd f2, FP_2(r3)
|
||||||
|
stfd f3, FP_3(r3)
|
||||||
|
stfd f4, FP_4(r3)
|
||||||
|
stfd f5, FP_5(r3)
|
||||||
|
stfd f6, FP_6(r3)
|
||||||
|
stfd f7, FP_7(r3)
|
||||||
|
stfd f8, FP_8(r3)
|
||||||
|
stfd f9, FP_9(r3)
|
||||||
|
stfd f10, FP_10(r3)
|
||||||
|
stfd f11, FP_11(r3)
|
||||||
|
stfd f12, FP_12(r3)
|
||||||
|
stfd f13, FP_13(r3)
|
||||||
|
stfd f14, FP_14(r3)
|
||||||
|
stfd f15, FP_15(r3)
|
||||||
|
stfd f16, FP_16(r3)
|
||||||
|
stfd f17, FP_17(r3)
|
||||||
|
stfd f18, FP_18(r3)
|
||||||
|
stfd f19, FP_19(r3)
|
||||||
|
stfd f20, FP_20(r3)
|
||||||
|
stfd f21, FP_21(r3)
|
||||||
|
stfd f22, FP_22(r3)
|
||||||
|
stfd f23, FP_23(r3)
|
||||||
|
stfd f24, FP_24(r3)
|
||||||
|
stfd f25, FP_25(r3)
|
||||||
|
stfd f26, FP_26(r3)
|
||||||
|
stfd f27, FP_27(r3)
|
||||||
|
stfd f28, FP_28(r3)
|
||||||
|
stfd f29, FP_29(r3)
|
||||||
|
stfd f30, FP_30(r3)
|
||||||
|
stfd f31, FP_31(r3)
|
||||||
|
mffs f2
|
||||||
|
stfd f2, FP_FPSCR(r3)
|
||||||
|
#else
|
||||||
|
stfs f0, FP_0(r3)
|
||||||
|
stfs f1, FP_1(r3)
|
||||||
|
stfs f2, FP_2(r3)
|
||||||
|
stfs f3, FP_3(r3)
|
||||||
|
stfs f4, FP_4(r3)
|
||||||
|
stfs f5, FP_5(r3)
|
||||||
|
stfs f6, FP_6(r3)
|
||||||
|
stfs f7, FP_7(r3)
|
||||||
|
stfs f8, FP_8(r3)
|
||||||
|
stfs f9, FP_9(r3)
|
||||||
|
stfs f10, FP_10(r3)
|
||||||
|
stfs f11, FP_11(r3)
|
||||||
|
stfs f12, FP_12(r3)
|
||||||
|
stfs f13, FP_13(r3)
|
||||||
|
stfs f14, FP_14(r3)
|
||||||
|
stfs f15, FP_15(r3)
|
||||||
|
stfs f16, FP_16(r3)
|
||||||
|
stfs f17, FP_17(r3)
|
||||||
|
stfs f18, FP_18(r3)
|
||||||
|
stfs f19, FP_19(r3)
|
||||||
|
stfs f20, FP_20(r3)
|
||||||
|
stfs f21, FP_21(r3)
|
||||||
|
stfs f22, FP_22(r3)
|
||||||
|
stfs f23, FP_23(r3)
|
||||||
|
stfs f24, FP_24(r3)
|
||||||
|
stfs f25, FP_25(r3)
|
||||||
|
stfs f26, FP_26(r3)
|
||||||
|
stfs f27, FP_27(r3)
|
||||||
|
stfs f28, FP_28(r3)
|
||||||
|
stfs f29, FP_29(r3)
|
||||||
|
stfs f30, FP_30(r3)
|
||||||
|
stfs f31, FP_31(r3)
|
||||||
|
mffs f2
|
||||||
|
stfs f2, FP_FPSCR(r3)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
blr
|
||||||
|
|
||||||
|
/*
|
||||||
|
* _CPU_Context_restore_fp_context
|
||||||
|
*
|
||||||
|
* This routine is responsible for restoring the FP context
|
||||||
|
* at *fp_context_ptr. If the point to load the FP context
|
||||||
|
* from is changed then the pointer is modified by this routine.
|
||||||
|
*
|
||||||
|
* Sometimes a macro implementation of this is in cpu.h which dereferences
|
||||||
|
* the ** and a similarly named routine in this file is passed something
|
||||||
|
* like a (Context_Control_fp *). The general rule on making this decision
|
||||||
|
* is to avoid writing assembly language.
|
||||||
|
*/
|
||||||
|
|
||||||
|
ALIGN (PPC_CACHE_ALIGNMENT, PPC_CACHE_ALIGN_POWER)
|
||||||
|
PUBLIC_PROC (_CPU_Context_restore_fp)
|
||||||
|
PROC (_CPU_Context_restore_fp):
|
||||||
|
#if (PPC_HAS_FPU == 1)
|
||||||
|
lwz r3, 0(r3)
|
||||||
|
#if (PPC_HAS_DOUBLE == 1)
|
||||||
|
lfd f2, FP_FPSCR(r3)
|
||||||
|
mtfsf 255, f2
|
||||||
|
lfd f0, FP_0(r3)
|
||||||
|
lfd f1, FP_1(r3)
|
||||||
|
lfd f2, FP_2(r3)
|
||||||
|
lfd f3, FP_3(r3)
|
||||||
|
lfd f4, FP_4(r3)
|
||||||
|
lfd f5, FP_5(r3)
|
||||||
|
lfd f6, FP_6(r3)
|
||||||
|
lfd f7, FP_7(r3)
|
||||||
|
lfd f8, FP_8(r3)
|
||||||
|
lfd f9, FP_9(r3)
|
||||||
|
lfd f10, FP_10(r3)
|
||||||
|
lfd f11, FP_11(r3)
|
||||||
|
lfd f12, FP_12(r3)
|
||||||
|
lfd f13, FP_13(r3)
|
||||||
|
lfd f14, FP_14(r3)
|
||||||
|
lfd f15, FP_15(r3)
|
||||||
|
lfd f16, FP_16(r3)
|
||||||
|
lfd f17, FP_17(r3)
|
||||||
|
lfd f18, FP_18(r3)
|
||||||
|
lfd f19, FP_19(r3)
|
||||||
|
lfd f20, FP_20(r3)
|
||||||
|
lfd f21, FP_21(r3)
|
||||||
|
lfd f22, FP_22(r3)
|
||||||
|
lfd f23, FP_23(r3)
|
||||||
|
lfd f24, FP_24(r3)
|
||||||
|
lfd f25, FP_25(r3)
|
||||||
|
lfd f26, FP_26(r3)
|
||||||
|
lfd f27, FP_27(r3)
|
||||||
|
lfd f28, FP_28(r3)
|
||||||
|
lfd f29, FP_29(r3)
|
||||||
|
lfd f30, FP_30(r3)
|
||||||
|
lfd f31, FP_31(r3)
|
||||||
|
#else
|
||||||
|
lfs f2, FP_FPSCR(r3)
|
||||||
|
mtfsf 255, f2
|
||||||
|
lfs f0, FP_0(r3)
|
||||||
|
lfs f1, FP_1(r3)
|
||||||
|
lfs f2, FP_2(r3)
|
||||||
|
lfs f3, FP_3(r3)
|
||||||
|
lfs f4, FP_4(r3)
|
||||||
|
lfs f5, FP_5(r3)
|
||||||
|
lfs f6, FP_6(r3)
|
||||||
|
lfs f7, FP_7(r3)
|
||||||
|
lfs f8, FP_8(r3)
|
||||||
|
lfs f9, FP_9(r3)
|
||||||
|
lfs f10, FP_10(r3)
|
||||||
|
lfs f11, FP_11(r3)
|
||||||
|
lfs f12, FP_12(r3)
|
||||||
|
lfs f13, FP_13(r3)
|
||||||
|
lfs f14, FP_14(r3)
|
||||||
|
lfs f15, FP_15(r3)
|
||||||
|
lfs f16, FP_16(r3)
|
||||||
|
lfs f17, FP_17(r3)
|
||||||
|
lfs f18, FP_18(r3)
|
||||||
|
lfs f19, FP_19(r3)
|
||||||
|
lfs f20, FP_20(r3)
|
||||||
|
lfs f21, FP_21(r3)
|
||||||
|
lfs f22, FP_22(r3)
|
||||||
|
lfs f23, FP_23(r3)
|
||||||
|
lfs f24, FP_24(r3)
|
||||||
|
lfs f25, FP_25(r3)
|
||||||
|
lfs f26, FP_26(r3)
|
||||||
|
lfs f27, FP_27(r3)
|
||||||
|
lfs f28, FP_28(r3)
|
||||||
|
lfs f29, FP_29(r3)
|
||||||
|
lfs f30, FP_30(r3)
|
||||||
|
lfs f31, FP_31(r3)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
blr
|
||||||
|
|
||||||
|
|
||||||
|
/* _CPU_Context_switch
|
||||||
|
*
|
||||||
|
* This routine performs a normal non-FP context switch.
|
||||||
|
*/
|
||||||
|
ALIGN (PPC_CACHE_ALIGNMENT, PPC_CACHE_ALIGN_POWER)
|
||||||
|
PUBLIC_PROC (_CPU_Context_switch)
|
||||||
|
PROC (_CPU_Context_switch):
|
||||||
|
sync
|
||||||
|
isync
|
||||||
|
#if (PPC_CACHE_ALIGNMENT == 4) /* No cache */
|
||||||
|
stw r1, GP_1(r3)
|
||||||
|
lwz r1, GP_1(r4)
|
||||||
|
stw r2, GP_2(r3)
|
||||||
|
lwz r2, GP_2(r4)
|
||||||
|
#if (PPC_USE_MULTIPLE == 1)
|
||||||
|
stmw r13, GP_13(r3)
|
||||||
|
lmw r13, GP_13(r4)
|
||||||
|
#else
|
||||||
|
stw r13, GP_13(r3)
|
||||||
|
lwz r13, GP_13(r4)
|
||||||
|
stw r14, GP_14(r3)
|
||||||
|
lwz r14, GP_14(r4)
|
||||||
|
stw r15, GP_15(r3)
|
||||||
|
lwz r15, GP_15(r4)
|
||||||
|
stw r16, GP_16(r3)
|
||||||
|
lwz r16, GP_16(r4)
|
||||||
|
stw r17, GP_17(r3)
|
||||||
|
lwz r17, GP_17(r4)
|
||||||
|
stw r18, GP_18(r3)
|
||||||
|
lwz r18, GP_18(r4)
|
||||||
|
stw r19, GP_19(r3)
|
||||||
|
lwz r19, GP_19(r4)
|
||||||
|
stw r20, GP_20(r3)
|
||||||
|
lwz r20, GP_20(r4)
|
||||||
|
stw r21, GP_21(r3)
|
||||||
|
lwz r21, GP_21(r4)
|
||||||
|
stw r22, GP_22(r3)
|
||||||
|
lwz r22, GP_22(r4)
|
||||||
|
stw r23, GP_23(r3)
|
||||||
|
lwz r23, GP_23(r4)
|
||||||
|
stw r24, GP_24(r3)
|
||||||
|
lwz r24, GP_24(r4)
|
||||||
|
stw r25, GP_25(r3)
|
||||||
|
lwz r25, GP_25(r4)
|
||||||
|
stw r26, GP_26(r3)
|
||||||
|
lwz r26, GP_26(r4)
|
||||||
|
stw r27, GP_27(r3)
|
||||||
|
lwz r27, GP_27(r4)
|
||||||
|
stw r28, GP_28(r3)
|
||||||
|
lwz r28, GP_28(r4)
|
||||||
|
stw r29, GP_29(r3)
|
||||||
|
lwz r29, GP_29(r4)
|
||||||
|
stw r30, GP_30(r3)
|
||||||
|
lwz r30, GP_30(r4)
|
||||||
|
stw r31, GP_31(r3)
|
||||||
|
lwz r31, GP_31(r4)
|
||||||
|
#endif
|
||||||
|
mfcr r5
|
||||||
|
stw r5, GP_CR(r3)
|
||||||
|
lwz r5, GP_CR(r4)
|
||||||
|
mflr r6
|
||||||
|
mtcrf 255, r5
|
||||||
|
stw r6, GP_PC(r3)
|
||||||
|
lwz r6, GP_PC(r4)
|
||||||
|
mfmsr r7
|
||||||
|
mtlr r6
|
||||||
|
stw r7, GP_MSR(r3)
|
||||||
|
lwz r7, GP_MSR(r4)
|
||||||
|
mtmsr r7
|
||||||
|
#endif
|
||||||
|
#if (PPC_CACHE_ALIGNMENT == 16)
|
||||||
|
/* This assumes that all the registers are in the given order */
|
||||||
|
li r5, 16
|
||||||
|
addi r3,r3,-4
|
||||||
|
#if ( PPC_USE_DATA_CACHE )
|
||||||
|
dcbz r5, r3
|
||||||
|
#endif
|
||||||
|
stw r1, GP_1+4(r3)
|
||||||
|
stw r2, GP_2+4(r3)
|
||||||
|
#if (PPC_USE_MULTIPLE == 1)
|
||||||
|
addi r3, r3, GP_14+4
|
||||||
|
#if ( PPC_USE_DATA_CACHE )
|
||||||
|
dcbz r5, r3
|
||||||
|
#endif
|
||||||
|
|
||||||
|
addi r3, r3, GP_18-GP_14
|
||||||
|
#if ( PPC_USE_DATA_CACHE )
|
||||||
|
dcbz r5, r3
|
||||||
|
#endif
|
||||||
|
addi r3, r3, GP_22-GP_18
|
||||||
|
#if ( PPC_USE_DATA_CACHE )
|
||||||
|
dcbz r5, r3
|
||||||
|
#endif
|
||||||
|
addi r3, r3, GP_26-GP_22
|
||||||
|
#if ( PPC_USE_DATA_CACHE )
|
||||||
|
dcbz r5, r3
|
||||||
|
#endif
|
||||||
|
stmw r13, GP_13-GP_26(r3)
|
||||||
|
#else
|
||||||
|
stw r13, GP_13+4(r3)
|
||||||
|
stwu r14, GP_14+4(r3)
|
||||||
|
#if ( PPC_USE_DATA_CACHE )
|
||||||
|
dcbz r5, r3
|
||||||
|
#endif
|
||||||
|
stw r15, GP_15-GP_14(r3)
|
||||||
|
stw r16, GP_16-GP_14(r3)
|
||||||
|
stw r17, GP_17-GP_14(r3)
|
||||||
|
stwu r18, GP_18-GP_14(r3)
|
||||||
|
#if ( PPC_USE_DATA_CACHE )
|
||||||
|
dcbz r5, r3
|
||||||
|
#endif
|
||||||
|
stw r19, GP_19-GP_18(r3)
|
||||||
|
stw r20, GP_20-GP_18(r3)
|
||||||
|
stw r21, GP_21-GP_18(r3)
|
||||||
|
stwu r22, GP_22-GP_18(r3)
|
||||||
|
#if ( PPC_USE_DATA_CACHE )
|
||||||
|
dcbz r5, r3
|
||||||
|
#endif
|
||||||
|
stw r23, GP_23-GP_22(r3)
|
||||||
|
stw r24, GP_24-GP_22(r3)
|
||||||
|
stw r25, GP_25-GP_22(r3)
|
||||||
|
stwu r26, GP_26-GP_22(r3)
|
||||||
|
#if ( PPC_USE_DATA_CACHE )
|
||||||
|
dcbz r5, r3
|
||||||
|
#endif
|
||||||
|
stw r27, GP_27-GP_26(r3)
|
||||||
|
stw r28, GP_28-GP_26(r3)
|
||||||
|
stw r29, GP_29-GP_26(r3)
|
||||||
|
stw r30, GP_30-GP_26(r3)
|
||||||
|
stw r31, GP_31-GP_26(r3)
|
||||||
|
#endif
|
||||||
|
#if ( PPC_USE_DATA_CACHE )
|
||||||
|
dcbt r0, r4
|
||||||
|
#endif
|
||||||
|
mfcr r6
|
||||||
|
stw r6, GP_CR-GP_26(r3)
|
||||||
|
mflr r7
|
||||||
|
stw r7, GP_PC-GP_26(r3)
|
||||||
|
mfmsr r8
|
||||||
|
stw r8, GP_MSR-GP_26(r3)
|
||||||
|
|
||||||
|
#if ( PPC_USE_DATA_CACHE )
|
||||||
|
dcbt r5, r4
|
||||||
|
#endif
|
||||||
|
lwz r1, GP_1(r4)
|
||||||
|
lwz r2, GP_2(r4)
|
||||||
|
#if (PPC_USE_MULTIPLE == 1)
|
||||||
|
addi r4, r4, GP_15
|
||||||
|
#if ( PPC_USE_DATA_CACHE )
|
||||||
|
dcbt r5, r4
|
||||||
|
#endif
|
||||||
|
addi r4, r4, GP_19-GP_15
|
||||||
|
#if ( PPC_USE_DATA_CACHE )
|
||||||
|
dcbt r5, r4
|
||||||
|
#endif
|
||||||
|
addi r4, r4, GP_23-GP_19
|
||||||
|
#if ( PPC_USE_DATA_CACHE )
|
||||||
|
dcbt r5, r4
|
||||||
|
#endif
|
||||||
|
addi r4, r4, GP_27-GP_23
|
||||||
|
#if ( PPC_USE_DATA_CACHE )
|
||||||
|
dcbt r5, r4
|
||||||
|
#endif
|
||||||
|
lmw r13, GP_13-GP_27(r4)
|
||||||
|
#else
|
||||||
|
lwz r13, GP_13(r4)
|
||||||
|
lwz r14, GP_14(r4)
|
||||||
|
lwzu r15, GP_15(r4)
|
||||||
|
#if ( PPC_USE_DATA_CACHE )
|
||||||
|
dcbt r5, r4
|
||||||
|
#endif
|
||||||
|
lwz r16, GP_16-GP_15(r4)
|
||||||
|
lwz r17, GP_17-GP_15(r4)
|
||||||
|
lwz r18, GP_18-GP_15(r4)
|
||||||
|
lwzu r19, GP_19-GP_15(r4)
|
||||||
|
#if ( PPC_USE_DATA_CACHE )
|
||||||
|
dcbt r5, r4
|
||||||
|
#endif
|
||||||
|
lwz r20, GP_20-GP_19(r4)
|
||||||
|
lwz r21, GP_21-GP_19(r4)
|
||||||
|
lwz r22, GP_22-GP_19(r4)
|
||||||
|
lwzu r23, GP_23-GP_19(r4)
|
||||||
|
#if ( PPC_USE_DATA_CACHE )
|
||||||
|
dcbt r5, r4
|
||||||
|
#endif
|
||||||
|
lwz r24, GP_24-GP_23(r4)
|
||||||
|
lwz r25, GP_25-GP_23(r4)
|
||||||
|
lwz r26, GP_26-GP_23(r4)
|
||||||
|
lwzu r27, GP_27-GP_23(r4)
|
||||||
|
#if ( PPC_USE_DATA_CACHE )
|
||||||
|
dcbt r5, r4
|
||||||
|
#endif
|
||||||
|
lwz r28, GP_28-GP_27(r4)
|
||||||
|
lwz r29, GP_29-GP_27(r4)
|
||||||
|
lwz r30, GP_30-GP_27(r4)
|
||||||
|
lwz r31, GP_31-GP_27(r4)
|
||||||
|
#endif
|
||||||
|
lwz r6, GP_CR-GP_27(r4)
|
||||||
|
lwz r7, GP_PC-GP_27(r4)
|
||||||
|
lwz r8, GP_MSR-GP_27(r4)
|
||||||
|
mtcrf 255, r6
|
||||||
|
mtlr r7
|
||||||
|
mtmsr r8
|
||||||
|
#endif
|
||||||
|
#if (PPC_CACHE_ALIGNMENT == 32)
|
||||||
|
/* This assumes that all the registers are in the given order */
|
||||||
|
li r5, 32
|
||||||
|
addi r3,r3,-4
|
||||||
|
#if ( PPC_USE_DATA_CACHE )
|
||||||
|
dcbz r5, r3
|
||||||
|
#endif
|
||||||
|
stw r1, GP_1+4(r3)
|
||||||
|
stw r2, GP_2+4(r3)
|
||||||
|
#if (PPC_USE_MULTIPLE == 1)
|
||||||
|
addi r3, r3, GP_18+4
|
||||||
|
#if ( PPC_USE_DATA_CACHE )
|
||||||
|
dcbz r5, r3
|
||||||
|
#endif
|
||||||
|
stmw r13, GP_13-GP_18(r3)
|
||||||
|
#else
|
||||||
|
stw r13, GP_13+4(r3)
|
||||||
|
stw r14, GP_14+4(r3)
|
||||||
|
stw r15, GP_15+4(r3)
|
||||||
|
stw r16, GP_16+4(r3)
|
||||||
|
stw r17, GP_17+4(r3)
|
||||||
|
stwu r18, GP_18+4(r3)
|
||||||
|
#if ( PPC_USE_DATA_CACHE )
|
||||||
|
dcbz r5, r3
|
||||||
|
#endif
|
||||||
|
stw r19, GP_19-GP_18(r3)
|
||||||
|
stw r20, GP_20-GP_18(r3)
|
||||||
|
stw r21, GP_21-GP_18(r3)
|
||||||
|
stw r22, GP_22-GP_18(r3)
|
||||||
|
stw r23, GP_23-GP_18(r3)
|
||||||
|
stw r24, GP_24-GP_18(r3)
|
||||||
|
stw r25, GP_25-GP_18(r3)
|
||||||
|
stw r26, GP_26-GP_18(r3)
|
||||||
|
stw r27, GP_27-GP_18(r3)
|
||||||
|
stw r28, GP_28-GP_18(r3)
|
||||||
|
stw r29, GP_29-GP_18(r3)
|
||||||
|
stw r30, GP_30-GP_18(r3)
|
||||||
|
stw r31, GP_31-GP_18(r3)
|
||||||
|
#endif
|
||||||
|
#if ( PPC_USE_DATA_CACHE )
|
||||||
|
dcbt r0, r4
|
||||||
|
#endif
|
||||||
|
mfcr r6
|
||||||
|
stw r6, GP_CR-GP_18(r3)
|
||||||
|
mflr r7
|
||||||
|
stw r7, GP_PC-GP_18(r3)
|
||||||
|
mfmsr r8
|
||||||
|
stw r8, GP_MSR-GP_18(r3)
|
||||||
|
|
||||||
|
#if ( PPC_USE_DATA_CACHE )
|
||||||
|
dcbt r5, r4
|
||||||
|
#endif
|
||||||
|
lwz r1, GP_1(r4)
|
||||||
|
lwz r2, GP_2(r4)
|
||||||
|
#if (PPC_USE_MULTIPLE == 1)
|
||||||
|
addi r4, r4, GP_19
|
||||||
|
#if ( PPC_USE_DATA_CACHE )
|
||||||
|
dcbt r5, r4
|
||||||
|
#endif
|
||||||
|
lmw r13, GP_13-GP_19(r4)
|
||||||
|
#else
|
||||||
|
lwz r13, GP_13(r4)
|
||||||
|
lwz r14, GP_14(r4)
|
||||||
|
lwz r15, GP_15(r4)
|
||||||
|
lwz r16, GP_16(r4)
|
||||||
|
lwz r17, GP_17(r4)
|
||||||
|
lwz r18, GP_18(r4)
|
||||||
|
lwzu r19, GP_19(r4)
|
||||||
|
#if ( PPC_USE_DATA_CACHE )
|
||||||
|
dcbt r5, r4
|
||||||
|
#endif
|
||||||
|
lwz r20, GP_20-GP_19(r4)
|
||||||
|
lwz r21, GP_21-GP_19(r4)
|
||||||
|
lwz r22, GP_22-GP_19(r4)
|
||||||
|
lwz r23, GP_23-GP_19(r4)
|
||||||
|
lwz r24, GP_24-GP_19(r4)
|
||||||
|
lwz r25, GP_25-GP_19(r4)
|
||||||
|
lwz r26, GP_26-GP_19(r4)
|
||||||
|
lwz r27, GP_27-GP_19(r4)
|
||||||
|
lwz r28, GP_28-GP_19(r4)
|
||||||
|
lwz r29, GP_29-GP_19(r4)
|
||||||
|
lwz r30, GP_30-GP_19(r4)
|
||||||
|
lwz r31, GP_31-GP_19(r4)
|
||||||
|
#endif
|
||||||
|
lwz r6, GP_CR-GP_19(r4)
|
||||||
|
lwz r7, GP_PC-GP_19(r4)
|
||||||
|
lwz r8, GP_MSR-GP_19(r4)
|
||||||
|
mtcrf 255, r6
|
||||||
|
mtlr r7
|
||||||
|
mtmsr r8
|
||||||
|
#endif
|
||||||
|
blr
|
||||||
|
|
||||||
|
/*
|
||||||
|
* _CPU_Context_restore
|
||||||
|
*
|
||||||
|
* This routine is generallu used only to restart self in an
|
||||||
|
* efficient manner. It may simply be a label in _CPU_Context_switch.
|
||||||
|
*
|
||||||
|
* NOTE: May be unnecessary to reload some registers.
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* ACB: Don't worry about cache optimisation here - this is not THAT critical.
|
||||||
|
*/
|
||||||
|
ALIGN (PPC_CACHE_ALIGNMENT, PPC_CACHE_ALIGN_POWER)
|
||||||
|
PUBLIC_PROC (_CPU_Context_restore)
|
||||||
|
PROC (_CPU_Context_restore):
|
||||||
|
lwz r5, GP_CR(r3)
|
||||||
|
lwz r6, GP_PC(r3)
|
||||||
|
lwz r7, GP_MSR(r3)
|
||||||
|
mtcrf 255, r5
|
||||||
|
mtlr r6
|
||||||
|
mtmsr r7
|
||||||
|
lwz r1, GP_1(r3)
|
||||||
|
lwz r2, GP_2(r3)
|
||||||
|
#if (PPC_USE_MULTIPLE == 1)
|
||||||
|
lmw r13, GP_13(r3)
|
||||||
|
#else
|
||||||
|
lwz r13, GP_13(r3)
|
||||||
|
lwz r14, GP_14(r3)
|
||||||
|
lwz r15, GP_15(r3)
|
||||||
|
lwz r16, GP_16(r3)
|
||||||
|
lwz r17, GP_17(r3)
|
||||||
|
lwz r18, GP_18(r3)
|
||||||
|
lwz r19, GP_19(r3)
|
||||||
|
lwz r20, GP_20(r3)
|
||||||
|
lwz r21, GP_21(r3)
|
||||||
|
lwz r22, GP_22(r3)
|
||||||
|
lwz r23, GP_23(r3)
|
||||||
|
lwz r24, GP_24(r3)
|
||||||
|
lwz r25, GP_25(r3)
|
||||||
|
lwz r26, GP_26(r3)
|
||||||
|
lwz r27, GP_27(r3)
|
||||||
|
lwz r28, GP_28(r3)
|
||||||
|
lwz r29, GP_29(r3)
|
||||||
|
lwz r30, GP_30(r3)
|
||||||
|
lwz r31, GP_31(r3)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
blr
|
||||||
|
|
||||||
|
/* Individual interrupt prologues look like this:
|
||||||
|
* #if (PPC_ABI == PPC_ABI_POWEROPEN || PPC_ABI == PPC_ABI_GCC27)
|
||||||
|
* #if (PPC_HAS_FPU)
|
||||||
|
* stwu r1, -(20*4 + 18*8 + IP_END)(r1)
|
||||||
|
* #else
|
||||||
|
* stwu r1, -(20*4 + IP_END)(r1)
|
||||||
|
* #endif
|
||||||
|
* #else
|
||||||
|
* stwu r1, -(IP_END)(r1)
|
||||||
|
* #endif
|
||||||
|
* stw r0, IP_0(r1)
|
||||||
|
*
|
||||||
|
* li r0, vectornum
|
||||||
|
* b PROC (_ISR_Handler{,C})
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* void __ISR_Handler()
|
||||||
|
*
|
||||||
|
* This routine provides the RTEMS interrupt management.
|
||||||
|
* The vector number is in r0. R0 has already been stacked.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
ALIGN (PPC_CACHE_ALIGNMENT, PPC_CACHE_ALIGN_POWER)
|
||||||
|
PUBLIC_PROC (_ISR_Handler)
|
||||||
|
PROC (_ISR_Handler):
|
||||||
|
#define LABEL(x) x
|
||||||
|
/* XXX ??
|
||||||
|
#define MTSAVE(x) mtspr sprg0, x
|
||||||
|
#define MFSAVE(x) mfspr x, sprg0
|
||||||
|
*/
|
||||||
|
#define MTPC(x) mtspr srr0, x
|
||||||
|
#define MFPC(x) mfspr x, srr0
|
||||||
|
#define MTMSR(x) mtspr srr1, x
|
||||||
|
#define MFMSR(x) mfspr x, srr1
|
||||||
|
|
||||||
|
#include "irq_stub.S"
|
||||||
|
rfi
|
||||||
|
|
||||||
|
#if (PPC_HAS_RFCI == 1)
|
||||||
|
/* void __ISR_HandlerC()
|
||||||
|
*
|
||||||
|
* This routine provides the RTEMS interrupt management.
|
||||||
|
* For critical interrupts
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
ALIGN (PPC_CACHE_ALIGNMENT, PPC_CACHE_ALIGN_POWER)
|
||||||
|
PUBLIC_PROC (_ISR_HandlerC)
|
||||||
|
PROC (_ISR_HandlerC):
|
||||||
|
#undef LABEL
|
||||||
|
#undef MTSAVE
|
||||||
|
#undef MFSAVE
|
||||||
|
#undef MTPC
|
||||||
|
#undef MFPC
|
||||||
|
#undef MTMSR
|
||||||
|
#undef MFMSR
|
||||||
|
#define LABEL(x) x##_C
|
||||||
|
/* XXX??
|
||||||
|
#define MTSAVE(x) mtspr sprg1, x
|
||||||
|
#define MFSAVE(x) mfspr x, sprg1
|
||||||
|
*/
|
||||||
|
#define MTPC(x) mtspr srr2, x
|
||||||
|
#define MFPC(x) mfspr x, srr2
|
||||||
|
#define MTMSR(x) mtspr srr3, x
|
||||||
|
#define MFMSR(x) mfspr x, srr3
|
||||||
|
#include "irq_stub.S"
|
||||||
|
rfci
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* PowerOpen descriptors for indirect function calls.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if (PPC_ABI == PPC_ABI_POWEROPEN)
|
||||||
|
DESCRIPTOR (_CPU_Context_save_fp)
|
||||||
|
DESCRIPTOR (_CPU_Context_restore_fp)
|
||||||
|
DESCRIPTOR (_CPU_Context_switch)
|
||||||
|
DESCRIPTOR (_CPU_Context_restore)
|
||||||
|
DESCRIPTOR (_ISR_Handler)
|
||||||
|
#if (PPC_HAS_RFCI == 1)
|
||||||
|
DESCRIPTOR (_ISR_HandlerC)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
268
c/src/exec/score/cpu/powerpc/old_exception_processing/irq_stub.S
Normal file
268
c/src/exec/score/cpu/powerpc/old_exception_processing/irq_stub.S
Normal file
@@ -0,0 +1,268 @@
|
|||||||
|
/*
|
||||||
|
* This file contains the interrupt handler assembly code for the PowerPC
|
||||||
|
* implementation of RTEMS. It is #included from cpu_asm.s.
|
||||||
|
*
|
||||||
|
* Author: Andrew Bray <andy@i-cubed.co.uk>
|
||||||
|
*
|
||||||
|
* COPYRIGHT (c) 1995 by i-cubed ltd.
|
||||||
|
*
|
||||||
|
* To anyone who acknowledges that this file is provided "AS IS"
|
||||||
|
* without any express or implied warranty:
|
||||||
|
* permission to use, copy, modify, and distribute this file
|
||||||
|
* for any purpose is hereby granted without fee, provided that
|
||||||
|
* the above copyright notice and this notice appears in all
|
||||||
|
* copies, and that the name of i-cubed limited not be used in
|
||||||
|
* advertising or publicity pertaining to distribution of the
|
||||||
|
* software without specific, written prior permission.
|
||||||
|
* i-cubed limited makes no representations about the suitability
|
||||||
|
* of this software for any purpose.
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* void __ISR_Handler()
|
||||||
|
*
|
||||||
|
* This routine provides the RTEMS interrupt management.
|
||||||
|
* The vector number is in r0. R0 has already been stacked.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
PUBLIC_VAR (_CPU_IRQ_info )
|
||||||
|
|
||||||
|
/* Finish off the interrupt frame */
|
||||||
|
stw r2, IP_2(r1)
|
||||||
|
stw r3, IP_3(r1)
|
||||||
|
stw r4, IP_4(r1)
|
||||||
|
stw r5, IP_5(r1)
|
||||||
|
stw r6, IP_6(r1)
|
||||||
|
stw r7, IP_7(r1)
|
||||||
|
stw r8, IP_8(r1)
|
||||||
|
stw r9, IP_9(r1)
|
||||||
|
stw r10, IP_10(r1)
|
||||||
|
stw r11, IP_11(r1)
|
||||||
|
stw r12, IP_12(r1)
|
||||||
|
stw r13, IP_13(r1)
|
||||||
|
stmw r28, IP_28(r1)
|
||||||
|
mfcr r5
|
||||||
|
mfctr r6
|
||||||
|
mfxer r7
|
||||||
|
mflr r8
|
||||||
|
MFPC (r9)
|
||||||
|
MFMSR (r10)
|
||||||
|
/* Establish addressing */
|
||||||
|
#if (PPC_USE_SPRG)
|
||||||
|
mfspr r11, sprg3
|
||||||
|
#else
|
||||||
|
lis r11,_CPU_IRQ_info@ha
|
||||||
|
addi r11,r11,_CPU_IRQ_info@l
|
||||||
|
#endif
|
||||||
|
dcbt r0, r11
|
||||||
|
stw r5, IP_CR(r1)
|
||||||
|
stw r6, IP_CTR(r1)
|
||||||
|
stw r7, IP_XER(r1)
|
||||||
|
stw r8, IP_LR(r1)
|
||||||
|
stw r9, IP_PC(r1)
|
||||||
|
stw r10, IP_MSR(r1)
|
||||||
|
|
||||||
|
lwz r30, Vector_table(r11)
|
||||||
|
slwi r4,r0,2
|
||||||
|
lwz r28, Nest_level(r11)
|
||||||
|
add r4, r4, r30
|
||||||
|
|
||||||
|
lwz r30, 0(r28)
|
||||||
|
mr r3, r0
|
||||||
|
lwz r31, Stack(r11)
|
||||||
|
/*
|
||||||
|
* #if ( CPU_HAS_SOFTWARE_INTERRUPT_STACK == TRUE )
|
||||||
|
* if ( _ISR_Nest_level == 0 )
|
||||||
|
* switch to software interrupt stack
|
||||||
|
* #endif
|
||||||
|
*/
|
||||||
|
/* Switch stacks, here we must prevent ALL interrupts */
|
||||||
|
#if (PPC_USE_SPRG)
|
||||||
|
mfmsr r5
|
||||||
|
mfspr r6, sprg2
|
||||||
|
#else
|
||||||
|
lwz r6,msr_initial(r11)
|
||||||
|
lis r5,~PPC_MSR_DISABLE_MASK@ha
|
||||||
|
ori r5,r5,~PPC_MSR_DISABLE_MASK@l
|
||||||
|
and r6,r6,r5
|
||||||
|
mfmsr r5
|
||||||
|
#endif
|
||||||
|
mtmsr r6
|
||||||
|
cmpwi r30, 0
|
||||||
|
lwz r29, Disable_level(r11)
|
||||||
|
subf r31,r1,r31
|
||||||
|
bne LABEL (nested)
|
||||||
|
stwux r1,r1,r31
|
||||||
|
LABEL (nested):
|
||||||
|
/*
|
||||||
|
* _ISR_Nest_level++;
|
||||||
|
*/
|
||||||
|
lwz r31, 0(r29)
|
||||||
|
addi r30,r30,1
|
||||||
|
stw r30,0(r28)
|
||||||
|
/* From here on out, interrupts can be re-enabled. RTEMS
|
||||||
|
* convention says not.
|
||||||
|
*/
|
||||||
|
lwz r4,0(r4)
|
||||||
|
/*
|
||||||
|
* _Thread_Dispatch_disable_level++;
|
||||||
|
*/
|
||||||
|
addi r31,r31,1
|
||||||
|
stw r31, 0(r29)
|
||||||
|
/* SCE 980217
|
||||||
|
*
|
||||||
|
* We need address translation ON when we call our ISR routine
|
||||||
|
|
||||||
|
mtmsr r5
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (*_ISR_Vector_table[ vector ])( vector );
|
||||||
|
*/
|
||||||
|
#if (PPC_ABI == PPC_ABI_POWEROPEN)
|
||||||
|
lwz r6,0(r4)
|
||||||
|
lwz r2,4(r4)
|
||||||
|
mtlr r6
|
||||||
|
lwz r11,8(r4)
|
||||||
|
#endif
|
||||||
|
#if (PPC_ABI == PPC_ABI_GCC27)
|
||||||
|
lwz r2, Default_r2(r11)
|
||||||
|
mtlr r4
|
||||||
|
#lwz r2, 0(r2)
|
||||||
|
#endif
|
||||||
|
#if (PPC_ABI == PPC_ABI_SVR4 || PPC_ABI == PPC_ABI_EABI)
|
||||||
|
mtlr r4
|
||||||
|
lwz r2, Default_r2(r11)
|
||||||
|
lwz r13, Default_r13(r11)
|
||||||
|
#lwz r2, 0(r2)
|
||||||
|
#lwz r13, 0(r13)
|
||||||
|
#endif
|
||||||
|
mr r4,r1
|
||||||
|
blrl
|
||||||
|
/* NOP marker for debuggers */
|
||||||
|
or r6,r6,r6
|
||||||
|
|
||||||
|
/* We must re-disable the interrupts */
|
||||||
|
#if (PPC_USE_SPRG)
|
||||||
|
mfspr r11, sprg3
|
||||||
|
mfspr r0, sprg2
|
||||||
|
#else
|
||||||
|
lis r11,_CPU_IRQ_info@ha
|
||||||
|
addi r11,r11,_CPU_IRQ_info@l
|
||||||
|
lwz r0,msr_initial(r11)
|
||||||
|
lis r30,~PPC_MSR_DISABLE_MASK@ha
|
||||||
|
ori r30,r30,~PPC_MSR_DISABLE_MASK@l
|
||||||
|
and r0,r0,r30
|
||||||
|
#endif
|
||||||
|
mtmsr r0
|
||||||
|
lwz r30, 0(r28)
|
||||||
|
lwz r31, 0(r29)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* if (--Thread_Dispatch_disable,--_ISR_Nest_level)
|
||||||
|
* goto easy_exit;
|
||||||
|
*/
|
||||||
|
addi r30, r30, -1
|
||||||
|
cmpwi r30, 0
|
||||||
|
addi r31, r31, -1
|
||||||
|
stw r30, 0(r28)
|
||||||
|
stw r31, 0(r29)
|
||||||
|
bne LABEL (easy_exit)
|
||||||
|
cmpwi r31, 0
|
||||||
|
|
||||||
|
lwz r30, Switch_necessary(r11)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* #if ( CPU_HAS_SOFTWARE_INTERRUPT_STACK == TRUE )
|
||||||
|
* restore stack
|
||||||
|
* #endif
|
||||||
|
*/
|
||||||
|
lwz r1,0(r1)
|
||||||
|
bne LABEL (easy_exit)
|
||||||
|
lwz r30, 0(r30)
|
||||||
|
lwz r31, Signal(r11)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* if ( _Context_Switch_necessary )
|
||||||
|
* goto switch
|
||||||
|
*/
|
||||||
|
cmpwi r30, 0
|
||||||
|
lwz r28, 0(r31)
|
||||||
|
li r6,0
|
||||||
|
bne LABEL (switch)
|
||||||
|
/*
|
||||||
|
* if ( !_ISR_Signals_to_thread_executing )
|
||||||
|
* goto easy_exit
|
||||||
|
* _ISR_Signals_to_thread_executing = 0;
|
||||||
|
*/
|
||||||
|
cmpwi r28, 0
|
||||||
|
beq LABEL (easy_exit)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* switch:
|
||||||
|
* call _Thread_Dispatch() or prepare to return to _ISR_Dispatch
|
||||||
|
*/
|
||||||
|
LABEL (switch):
|
||||||
|
stw r6, 0(r31)
|
||||||
|
/* Re-enable interrupts */
|
||||||
|
lwz r0, IP_MSR(r1)
|
||||||
|
#if (PPC_ABI == PPC_ABI_POWEROPEN)
|
||||||
|
lwz r2, Dispatch_r2(r11)
|
||||||
|
#else
|
||||||
|
/* R2 and R13 still hold their values from the last call */
|
||||||
|
#endif
|
||||||
|
mtmsr r0
|
||||||
|
bl SYM (_Thread_Dispatch)
|
||||||
|
/* NOP marker for debuggers */
|
||||||
|
or r6,r6,r6
|
||||||
|
/*
|
||||||
|
* prepare to get out of interrupt
|
||||||
|
*/
|
||||||
|
/* Re-disable IRQs */
|
||||||
|
#if (PPC_USE_SPRG)
|
||||||
|
mfspr r0, sprg2
|
||||||
|
#else
|
||||||
|
lis r11,_CPU_IRQ_info@ha
|
||||||
|
addi r11,r11,_CPU_IRQ_info@l
|
||||||
|
lwz r0,msr_initial(r11)
|
||||||
|
lis r5,~PPC_MSR_DISABLE_MASK@ha
|
||||||
|
ori r5,r5,~PPC_MSR_DISABLE_MASK@l
|
||||||
|
and r0,r0,r5
|
||||||
|
#endif
|
||||||
|
mtmsr r0
|
||||||
|
|
||||||
|
/*
|
||||||
|
* easy_exit:
|
||||||
|
* prepare to get out of interrupt
|
||||||
|
* return from interrupt
|
||||||
|
*/
|
||||||
|
LABEL (easy_exit):
|
||||||
|
lwz r5, IP_CR(r1)
|
||||||
|
lwz r6, IP_CTR(r1)
|
||||||
|
lwz r7, IP_XER(r1)
|
||||||
|
lwz r8, IP_LR(r1)
|
||||||
|
lwz r9, IP_PC(r1)
|
||||||
|
lwz r10, IP_MSR(r1)
|
||||||
|
mtcrf 255,r5
|
||||||
|
mtctr r6
|
||||||
|
mtxer r7
|
||||||
|
mtlr r8
|
||||||
|
MTPC (r9)
|
||||||
|
MTMSR (r10)
|
||||||
|
lwz r0, IP_0(r1)
|
||||||
|
lwz r2, IP_2(r1)
|
||||||
|
lwz r3, IP_3(r1)
|
||||||
|
lwz r4, IP_4(r1)
|
||||||
|
lwz r5, IP_5(r1)
|
||||||
|
lwz r6, IP_6(r1)
|
||||||
|
lwz r7, IP_7(r1)
|
||||||
|
lwz r8, IP_8(r1)
|
||||||
|
lwz r9, IP_9(r1)
|
||||||
|
lwz r10, IP_10(r1)
|
||||||
|
lwz r11, IP_11(r1)
|
||||||
|
lwz r12, IP_12(r1)
|
||||||
|
lwz r13, IP_13(r1)
|
||||||
|
lmw r28, IP_28(r1)
|
||||||
|
lwz r1, 0(r1)
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* PowerPC Cache enable routines
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <rtems/system.h>
|
||||||
|
|
||||||
|
#define PPC_Get_HID0( _value ) \
|
||||||
|
do { \
|
||||||
|
_value = 0; /* to avoid warnings */ \
|
||||||
|
asm volatile( \
|
||||||
|
"mfspr %0, 0x3f0;" /* get HID0 */ \
|
||||||
|
"isync" \
|
||||||
|
: "=r" (_value) \
|
||||||
|
: "0" (_value) \
|
||||||
|
); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define PPC_Set_HID0( _value ) \
|
||||||
|
do { \
|
||||||
|
asm volatile( \
|
||||||
|
"isync;" \
|
||||||
|
"mtspr 0x3f0, %0;" /* load HID0 */ \
|
||||||
|
"isync" \
|
||||||
|
: "=r" (_value) \
|
||||||
|
: "0" (_value) \
|
||||||
|
); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
|
void powerpc_instruction_cache_enable ()
|
||||||
|
{
|
||||||
|
unsigned32 value;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enable the instruction cache
|
||||||
|
*/
|
||||||
|
|
||||||
|
PPC_Get_HID0( value );
|
||||||
|
|
||||||
|
value |= 0x00008000; /* Set ICE bit */
|
||||||
|
|
||||||
|
PPC_Set_HID0( value );
|
||||||
|
}
|
||||||
|
|
||||||
|
void powerpc_data_cache_enable ()
|
||||||
|
{
|
||||||
|
unsigned32 value;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* enable data cache
|
||||||
|
*/
|
||||||
|
|
||||||
|
PPC_Get_HID0( value );
|
||||||
|
|
||||||
|
value |= 0x00004000; /* set DCE bit */
|
||||||
|
|
||||||
|
PPC_Set_HID0( value );
|
||||||
|
}
|
||||||
|
|
||||||
132
c/src/exec/score/cpu/powerpc/old_exception_processing/rtems.S
Normal file
132
c/src/exec/score/cpu/powerpc/old_exception_processing/rtems.S
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
/* rtems.s
|
||||||
|
*
|
||||||
|
* This file contains the single entry point code for
|
||||||
|
* the PowerPC implementation of RTEMS.
|
||||||
|
*
|
||||||
|
* Author: Andrew Bray <andy@i-cubed.co.uk>
|
||||||
|
*
|
||||||
|
* COPYRIGHT (c) 1995 by i-cubed ltd.
|
||||||
|
*
|
||||||
|
* To anyone who acknowledges that this file is provided "AS IS"
|
||||||
|
* without any express or implied warranty:
|
||||||
|
* permission to use, copy, modify, and distribute this file
|
||||||
|
* for any purpose is hereby granted without fee, provided that
|
||||||
|
* the above copyright notice and this notice appears in all
|
||||||
|
* copies, and that the name of i-cubed limited not be used in
|
||||||
|
* advertising or publicity pertaining to distribution of the
|
||||||
|
* software without specific, written prior permission.
|
||||||
|
* i-cubed limited makes no representations about the suitability
|
||||||
|
* of this software for any purpose.
|
||||||
|
*
|
||||||
|
* Derived from c/src/exec/cpu/no_cpu/rtems.c:
|
||||||
|
*
|
||||||
|
* COPYRIGHT (c) 1989-1997.
|
||||||
|
* On-Line Applications Research Corporation (OAR).
|
||||||
|
* Copyright assigned to U.S. Government, 1994.
|
||||||
|
*
|
||||||
|
* The license and distribution terms for this file may in
|
||||||
|
* the file LICENSE in this distribution or at
|
||||||
|
* http://www.OARcorp.com/rtems/license.html.
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <asm.h>
|
||||||
|
|
||||||
|
BEGIN_CODE
|
||||||
|
/*
|
||||||
|
* RTEMS
|
||||||
|
*
|
||||||
|
* This routine jumps to the directive indicated in r11.
|
||||||
|
* This routine is used when RTEMS is linked by itself and placed
|
||||||
|
* in ROM. This routine is the first address in the ROM space for
|
||||||
|
* RTEMS. The user "calls" this address with the directive arguments
|
||||||
|
* in the normal place.
|
||||||
|
* This routine then jumps indirectly to the correct directive
|
||||||
|
* preserving the arguments. The directive should not realize
|
||||||
|
* it has been "wrapped" in this way. The table "_Entry_points"
|
||||||
|
* is used to look up the directive.
|
||||||
|
*/
|
||||||
|
|
||||||
|
ALIGN (4, 2)
|
||||||
|
PUBLIC_PROC (RTEMS)
|
||||||
|
PROC (RTEMS):
|
||||||
|
#if (PPC_ABI == PPC_ABI_POWEROPEN)
|
||||||
|
mflr r0
|
||||||
|
stw r0, 8(r1)
|
||||||
|
stwu r1, -64(r1)
|
||||||
|
|
||||||
|
/* Establish addressing */
|
||||||
|
bl base
|
||||||
|
base:
|
||||||
|
mflr r12
|
||||||
|
addi r12, r12, tabaddr - base
|
||||||
|
|
||||||
|
lwz r12, Entry_points-abase(r12)
|
||||||
|
slwi r11, r11, 2
|
||||||
|
lwzx r12, r12, r11
|
||||||
|
|
||||||
|
stw r2, 56(r1)
|
||||||
|
lwz r0, 0(r12)
|
||||||
|
mtlr r0
|
||||||
|
lwz r2, 4(r12)
|
||||||
|
lwz r11, 8(r12)
|
||||||
|
blrl
|
||||||
|
lwz r2, 56(r1)
|
||||||
|
addi r1, r1, 64
|
||||||
|
lwz r0, 8(r1)
|
||||||
|
mtlr r0
|
||||||
|
#else
|
||||||
|
mflr r0
|
||||||
|
stw r0, 4(r1)
|
||||||
|
stwu r1, -16(r1)
|
||||||
|
|
||||||
|
/* Establish addressing */
|
||||||
|
bl base
|
||||||
|
base:
|
||||||
|
mflr r12
|
||||||
|
addi r12, r12, tabaddr - base
|
||||||
|
|
||||||
|
lwz r12, Entry_points-abase(r12)
|
||||||
|
slwi r11, r11, 2
|
||||||
|
lwzx r11, r12, r11
|
||||||
|
|
||||||
|
stw r2, 8(r1)
|
||||||
|
#if (PPC_ABI != PPC_ABI_GCC27)
|
||||||
|
stw r13, 12(r1)
|
||||||
|
#endif
|
||||||
|
mtlr r11
|
||||||
|
lwz r11, irqinfo-abase(r12)
|
||||||
|
lwz r2, 0(r11)
|
||||||
|
#if (PPC_ABI != PPC_ABI_GCC27)
|
||||||
|
lwz r13, 4(r11)
|
||||||
|
#endif
|
||||||
|
blrl
|
||||||
|
lwz r2, 8(r1)
|
||||||
|
#if (PPC_ABI != PPC_ABI_GCC27)
|
||||||
|
lwz r13, 12(r1)
|
||||||
|
#endif
|
||||||
|
addi r1, r1, 16
|
||||||
|
lwz r0, 4(r1)
|
||||||
|
mtlr r0
|
||||||
|
#endif
|
||||||
|
blr
|
||||||
|
|
||||||
|
|
||||||
|
/* Addressability stuff */
|
||||||
|
tabaddr:
|
||||||
|
abase:
|
||||||
|
EXTERN_VAR (_Entry_points)
|
||||||
|
Entry_points:
|
||||||
|
EXT_SYM_REF (_Entry_points)
|
||||||
|
#if (PPC_ABI != PPC_ABI_POWEROPEN)
|
||||||
|
EXTERN_VAR (_CPU_IRQ_info)
|
||||||
|
irqinfo:
|
||||||
|
EXT_SYM_REF (_CPU_IRQ_info)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (PPC_ABI == PPC_ABI_POWEROPEN)
|
||||||
|
DESCRIPTOR (RTEMS)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@@ -185,7 +185,7 @@ extern "C" {
|
|||||||
|
|
||||||
#define PPC_LOW_POWER_MODE PPC_LOW_POWER_MODE_STANDARD
|
#define PPC_LOW_POWER_MODE PPC_LOW_POWER_MODE_STANDARD
|
||||||
|
|
||||||
#elif defined(ppc604)
|
#elif defined(mpc604)
|
||||||
/*
|
/*
|
||||||
* Submitted with original port -- book checked only.
|
* Submitted with original port -- book checked only.
|
||||||
*/
|
*/
|
||||||
@@ -475,7 +475,7 @@ extern "C" {
|
|||||||
#define PPC_IRQ_LAST PPC_IRQ_SYS_MGT
|
#define PPC_IRQ_LAST PPC_IRQ_SYS_MGT
|
||||||
|
|
||||||
|
|
||||||
#elif defined(ppc604)
|
#elif defined(mpc604)
|
||||||
#define PPC_IRQ_ADDR_BRK (PPC_STD_IRQ_LAST+1) /*0x1300- Inst. addr break */
|
#define PPC_IRQ_ADDR_BRK (PPC_STD_IRQ_LAST+1) /*0x1300- Inst. addr break */
|
||||||
#define PPC_IRQ_SYS_MGT (PPC_STD_IRQ_LAST+2) /*0x1400- System Management */
|
#define PPC_IRQ_SYS_MGT (PPC_STD_IRQ_LAST+2) /*0x1400- System Management */
|
||||||
#define PPC_IRQ_LAST PPC_IRQ_SYS_MGT
|
#define PPC_IRQ_LAST PPC_IRQ_SYS_MGT
|
||||||
|
|||||||
@@ -185,7 +185,7 @@ extern "C" {
|
|||||||
|
|
||||||
#define PPC_LOW_POWER_MODE PPC_LOW_POWER_MODE_STANDARD
|
#define PPC_LOW_POWER_MODE PPC_LOW_POWER_MODE_STANDARD
|
||||||
|
|
||||||
#elif defined(ppc604)
|
#elif defined(mpc604)
|
||||||
/*
|
/*
|
||||||
* Submitted with original port -- book checked only.
|
* Submitted with original port -- book checked only.
|
||||||
*/
|
*/
|
||||||
@@ -475,7 +475,7 @@ extern "C" {
|
|||||||
#define PPC_IRQ_LAST PPC_IRQ_SYS_MGT
|
#define PPC_IRQ_LAST PPC_IRQ_SYS_MGT
|
||||||
|
|
||||||
|
|
||||||
#elif defined(ppc604)
|
#elif defined(mpc604)
|
||||||
#define PPC_IRQ_ADDR_BRK (PPC_STD_IRQ_LAST+1) /*0x1300- Inst. addr break */
|
#define PPC_IRQ_ADDR_BRK (PPC_STD_IRQ_LAST+1) /*0x1300- Inst. addr break */
|
||||||
#define PPC_IRQ_SYS_MGT (PPC_STD_IRQ_LAST+2) /*0x1400- System Management */
|
#define PPC_IRQ_SYS_MGT (PPC_STD_IRQ_LAST+2) /*0x1400- System Management */
|
||||||
#define PPC_IRQ_LAST PPC_IRQ_SYS_MGT
|
#define PPC_IRQ_LAST PPC_IRQ_SYS_MGT
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ VPATH = @srcdir@/..
|
|||||||
RELS = ../$(ARCH)/rtems-cpu.rel
|
RELS = ../$(ARCH)/rtems-cpu.rel
|
||||||
|
|
||||||
# C source names, if any, go here -- minus the .c
|
# C source names, if any, go here -- minus the .c
|
||||||
C_PIECES = cpu ppccache
|
C_PIECES =
|
||||||
C_FILES = $(C_PIECES:%=%.c)
|
C_FILES = $(C_PIECES:%=%.c)
|
||||||
C_O_FILES = $(C_PIECES:%=${ARCH}/%.o)
|
C_O_FILES = $(C_PIECES:%=${ARCH}/%.o)
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ NETWORK = $(NETWORK_$(HAS_NETWORKING)_V)
|
|||||||
# wrapup is the one that actually builds and installs the library
|
# wrapup is the one that actually builds and installs the library
|
||||||
# from the individual .rel files built in other directories
|
# from the individual .rel files built in other directories
|
||||||
SUBDIRS = clock console include pci residual openpic irq vectors start \
|
SUBDIRS = clock console include pci residual openpic irq vectors start \
|
||||||
startup bootloader $(NETWORK) wrapup
|
startup bootloader $(NETWORK) motorola wrapup
|
||||||
|
|
||||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||||
cd $(top_builddir) \
|
cd $(top_builddir) \
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ subdir = powerpc/mcp750/bootloader
|
|||||||
RTEMS_ROOT = @RTEMS_ROOT@
|
RTEMS_ROOT = @RTEMS_ROOT@
|
||||||
PROJECT_ROOT = @PROJECT_ROOT@
|
PROJECT_ROOT = @PROJECT_ROOT@
|
||||||
|
|
||||||
VPATH = @srcdir@:@srcdir@/../../../shared:@srcdir@/../console
|
VPATH = @srcdir@:@srcdir@/../../../shared:@srcdir@/../../shared/console:@srcdir@/../../shared/bootloader
|
||||||
|
|
||||||
# C source names, if any, go here -- minus the .c
|
# C source names, if any, go here -- minus the .c
|
||||||
C_PIECES = misc pci zlib mm em86 polled_io lib
|
C_PIECES = misc pci zlib mm em86 polled_io lib
|
||||||
@@ -77,7 +77,7 @@ CLOBBER_ADDITIONS += $(IMAGES)
|
|||||||
#
|
#
|
||||||
bootloader : ${OBJS} $(IMAGES) $(BINARY_LOADED) ppcboot.lds
|
bootloader : ${OBJS} $(IMAGES) $(BINARY_LOADED) ppcboot.lds
|
||||||
$(LD) -o bootloader $(OBJS) --just-symbols=$(BINARY_LOADED) \
|
$(LD) -o bootloader $(OBJS) --just-symbols=$(BINARY_LOADED) \
|
||||||
-b binary $(IMAGES) -T @srcdir@/ppcboot.lds \
|
-b binary $(IMAGES) -T @srcdir@/../../shared/bootloader/ppcboot.lds \
|
||||||
-Map bootloader.map
|
-Map bootloader.map
|
||||||
|
|
||||||
check_unresolved : ${OBJS}
|
check_unresolved : ${OBJS}
|
||||||
|
|||||||
@@ -11,9 +11,7 @@ subdir = powerpc/mcp750/clock
|
|||||||
RTEMS_ROOT = @RTEMS_ROOT@
|
RTEMS_ROOT = @RTEMS_ROOT@
|
||||||
PROJECT_ROOT = @PROJECT_ROOT@
|
PROJECT_ROOT = @PROJECT_ROOT@
|
||||||
|
|
||||||
VPATH = @srcdir@
|
VPATH = @srcdir@:@srcdir@/../../shared/clock
|
||||||
|
|
||||||
PGM = ${ARCH}/clock.rel
|
|
||||||
|
|
||||||
# C source names, if any, go here -- minus the .c
|
# C source names, if any, go here -- minus the .c
|
||||||
C_PIECES = p_clock
|
C_PIECES = p_clock
|
||||||
@@ -58,10 +56,7 @@ LDFLAGS +=
|
|||||||
CLEAN_ADDITIONS +=
|
CLEAN_ADDITIONS +=
|
||||||
CLOBBER_ADDITIONS +=
|
CLOBBER_ADDITIONS +=
|
||||||
|
|
||||||
$(PGM): ${OBJS}
|
all: ${ARCH} $(SRCS) $(OBJS)
|
||||||
$(make-rel)
|
|
||||||
|
|
||||||
all: ${ARCH} $(SRCS) $(PGM)
|
|
||||||
|
|
||||||
# the .rel file built here will be put into libbsp.a by ../wrapup/Makefile
|
# the .rel file built here will be put into libbsp.a by ../wrapup/Makefile
|
||||||
install: all
|
install: all
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# $Id:
|
# $Id$
|
||||||
#
|
#
|
||||||
|
|
||||||
@SET_MAKE@
|
@SET_MAKE@
|
||||||
@@ -11,14 +11,14 @@ subdir = powerpc/mcp750/console
|
|||||||
RTEMS_ROOT = @RTEMS_ROOT@
|
RTEMS_ROOT = @RTEMS_ROOT@
|
||||||
PROJECT_ROOT = @PROJECT_ROOT@
|
PROJECT_ROOT = @PROJECT_ROOT@
|
||||||
|
|
||||||
VPATH = @srcdir@:@srcdir@/../../../shared
|
VPATH = @srcdir@:@srcdir@/../../shared/console:@srcdir@/../../../shared
|
||||||
|
|
||||||
# C source names, if any, go here -- minus the .c
|
# C source names, if any, go here -- minus the .c
|
||||||
C_PIECES = polled_io uart console inch console_reserve_resources
|
C_PIECES = polled_io uart console inch
|
||||||
C_FILES = $(C_PIECES:%=%.c)
|
C_FILES = $(C_PIECES:%=%.c)
|
||||||
C_O_FILES = $(C_PIECES:%=${ARCH}/%.o)
|
C_O_FILES = $(C_PIECES:%=${ARCH}/%.o)
|
||||||
|
|
||||||
H_FILES = $(srcdir)/consoleIo.h $(srcdir)/keyboard.h $(srcdir)/uart.h
|
H_FILES = $(srcdir)/../../shared/console/consoleIo.h $(srcdir)/../../shared/console/keyboard.h $(srcdir)/../../shared/console/uart.h
|
||||||
|
|
||||||
# Assembly source names, if any, go here -- minus the .s
|
# Assembly source names, if any, go here -- minus the .s
|
||||||
S_PIECES =
|
S_PIECES =
|
||||||
@@ -48,6 +48,7 @@ CC_O_FILES = $(CC_PIECES:%=${ARCH}/%.o)
|
|||||||
#
|
#
|
||||||
|
|
||||||
CPPFLAGS += -DSTATIC_LOG_ALLOC
|
CPPFLAGS += -DSTATIC_LOG_ALLOC
|
||||||
|
CFLAGS +=
|
||||||
#
|
#
|
||||||
# Add your list of files to delete here. The config files
|
# Add your list of files to delete here. The config files
|
||||||
# already know how to delete some stuff, so you may want
|
# already know how to delete some stuff, so you may want
|
||||||
@@ -56,11 +57,7 @@ CPPFLAGS += -DSTATIC_LOG_ALLOC
|
|||||||
# 'make clobber' already includes 'make clean'
|
# 'make clobber' already includes 'make clean'
|
||||||
#
|
#
|
||||||
|
|
||||||
preinstall:
|
all: ${ARCH} $(SRCS) ${OBJS}
|
||||||
@$(mkinstalldirs) $(PROJECT_INCLUDE)/bsp
|
|
||||||
@$(INSTALL_CHANGE) -m 644 $(H_FILES) $(PROJECT_INCLUDE)/bsp
|
|
||||||
|
|
||||||
all: ${ARCH} $(SRCS) preinstall ${OBJS}
|
|
||||||
|
|
||||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||||
cd $(top_builddir) \
|
cd $(top_builddir) \
|
||||||
|
|||||||
@@ -1,61 +0,0 @@
|
|||||||
/*
|
|
||||||
* console.c -- console I/O package
|
|
||||||
*
|
|
||||||
* Copyright (C) 1999 Eric Valette. valette@crf.canon.fr
|
|
||||||
*
|
|
||||||
* This code is based on the pc386 BSP console.c so the following
|
|
||||||
* copyright also applies :
|
|
||||||
*
|
|
||||||
* (C) Copyright 1997 -
|
|
||||||
* - NavIST Group - Real-Time Distributed Systems and Industrial Automation
|
|
||||||
*
|
|
||||||
* http://pandora.ist.utl.pt
|
|
||||||
*
|
|
||||||
* Instituto Superior Tecnico * Lisboa * PORTUGAL
|
|
||||||
* The license and distribution terms for this file may be
|
|
||||||
* found in found in the file LICENSE in this distribution or at
|
|
||||||
* http://www.OARcorp.com/rtems/license.html.
|
|
||||||
*
|
|
||||||
* $Id$
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <assert.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#undef __assert
|
|
||||||
void __assert (const char *file, int line, const char *msg);
|
|
||||||
extern int close(int fd);
|
|
||||||
|
|
||||||
#include <bsp.h>
|
|
||||||
#include <bsp/irq.h>
|
|
||||||
#include <rtems/libio.h>
|
|
||||||
#include <termios.h>
|
|
||||||
#include <bsp/uart.h>
|
|
||||||
#include <bsp/consoleIo.h>
|
|
||||||
|
|
||||||
/* Definitions for BSPConsolePort */
|
|
||||||
#define BSP_CONSOLE_PORT_CONSOLE (-1)
|
|
||||||
#define BSP_CONSOLE_PORT_COM1 (BSP_UART_COM1)
|
|
||||||
#define BSP_CONSOLE_PORT_COM2 (BSP_UART_COM2)
|
|
||||||
/*
|
|
||||||
* Possible value for console input/output :
|
|
||||||
* BSP_CONSOLE_PORT_CONSOLE
|
|
||||||
* BSP_UART_COM1
|
|
||||||
* BSP_UART_COM2
|
|
||||||
*/
|
|
||||||
|
|
||||||
int BSPConsolePort = BSP_UART_COM1;
|
|
||||||
|
|
||||||
/* int BSPConsolePort = BSP_UART_COM2; */
|
|
||||||
int BSPBaseBaud = 115200;
|
|
||||||
|
|
||||||
void console_reserve_resources(rtems_configuration_table *conf)
|
|
||||||
{
|
|
||||||
if(BSPConsolePort != BSP_CONSOLE_PORT_CONSOLE)
|
|
||||||
{
|
|
||||||
rtems_termios_reserve_resources(conf, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
@@ -13,7 +13,13 @@ PROJECT_ROOT = @PROJECT_ROOT@
|
|||||||
|
|
||||||
VPATH = @srcdir@
|
VPATH = @srcdir@
|
||||||
|
|
||||||
H_FILES = $(srcdir)/nvram.h $(srcdir)/bsp.h
|
H_FILES = $(srcdir)/../../shared/include/nvram.h \
|
||||||
|
$(srcdir)/../../shared/include/bsp.h
|
||||||
|
|
||||||
|
BSP_H_FILES = $(srcdir)/../../shared/console/consoleIo.h \
|
||||||
|
$(srcdir)/../../shared/console/uart.h \
|
||||||
|
$(srcdir)/../../shared/irq/irq.h \
|
||||||
|
$(srcdir)/../../shared/motorola/motorola.h
|
||||||
|
|
||||||
#
|
#
|
||||||
# Equate files are for including from assembly preprocessed by
|
# Equate files are for including from assembly preprocessed by
|
||||||
@@ -43,7 +49,9 @@ CLOBBER_ADDITIONS +=
|
|||||||
|
|
||||||
preinstall:
|
preinstall:
|
||||||
$(mkinstalldirs) $(PROJECT_INCLUDE)
|
$(mkinstalldirs) $(PROJECT_INCLUDE)
|
||||||
|
$(mkinstalldirs) $(PROJECT_INCLUDE)/bsp
|
||||||
@$(INSTALL_CHANGE) -m 644 $(H_FILES) $(PROJECT_INCLUDE)
|
@$(INSTALL_CHANGE) -m 644 $(H_FILES) $(PROJECT_INCLUDE)
|
||||||
|
@$(INSTALL_CHANGE) -m 644 $(BSP_H_FILES) $(PROJECT_INCLUDE)/bsp
|
||||||
|
|
||||||
all: $(SRCS) preinstall
|
all: $(SRCS) preinstall
|
||||||
|
|
||||||
|
|||||||
@@ -11,14 +11,14 @@ subdir = powerpc/mcp750/irq
|
|||||||
RTEMS_ROOT = @RTEMS_ROOT@
|
RTEMS_ROOT = @RTEMS_ROOT@
|
||||||
PROJECT_ROOT = @PROJECT_ROOT@
|
PROJECT_ROOT = @PROJECT_ROOT@
|
||||||
|
|
||||||
VPATH = @srcdir@
|
VPATH = @srcdir@:@srcdir@/../../shared/irq
|
||||||
|
|
||||||
# C source names, if any, go here -- minus the .c
|
# C source names, if any, go here -- minus the .c
|
||||||
C_PIECES = irq_init i8259 irq
|
C_PIECES = irq_init i8259 irq
|
||||||
C_FILES = $(C_PIECES:%=%.c)
|
C_FILES = $(C_PIECES:%=%.c)
|
||||||
C_O_FILES = $(C_PIECES:%=${ARCH}/%.o)
|
C_O_FILES = $(C_PIECES:%=${ARCH}/%.o)
|
||||||
|
|
||||||
H_FILES = $(srcdir)/irq.h
|
H_FILES = $(srcdir)/../../shared/irq/irq.h
|
||||||
|
|
||||||
# Assembly source names, if any, go here -- minus the .s
|
# Assembly source names, if any, go here -- minus the .s
|
||||||
S_PIECES = irq_asm
|
S_PIECES = irq_asm
|
||||||
@@ -61,11 +61,7 @@ LDFLAGS +=
|
|||||||
CLEAN_ADDITIONS +=
|
CLEAN_ADDITIONS +=
|
||||||
CLOBBER_ADDITIONS +=
|
CLOBBER_ADDITIONS +=
|
||||||
|
|
||||||
preinstall:
|
all: ${ARCH} $(SRCS) ${OBJS}
|
||||||
@$(mkinstalldirs) $(PROJECT_INCLUDE)/bsp
|
|
||||||
@$(INSTALL_CHANGE) -m 644 $(H_FILES) $(PROJECT_INCLUDE)/bsp
|
|
||||||
|
|
||||||
all: ${ARCH} $(SRCS) preinstall ${OBJS}
|
|
||||||
|
|
||||||
install: all
|
install: all
|
||||||
|
|
||||||
|
|||||||
@@ -11,16 +11,14 @@ subdir = powerpc/mcp750/openpic
|
|||||||
RTEMS_ROOT = @RTEMS_ROOT@
|
RTEMS_ROOT = @RTEMS_ROOT@
|
||||||
PROJECT_ROOT = @PROJECT_ROOT@
|
PROJECT_ROOT = @PROJECT_ROOT@
|
||||||
|
|
||||||
VPATH = @srcdir@
|
VPATH = @srcdir@:@srcdir@/../../shared/openpic
|
||||||
|
|
||||||
PGM = ${ARCH}/openpic.rel
|
|
||||||
|
|
||||||
# C source names, if any, go here -- minus the .c
|
# C source names, if any, go here -- minus the .c
|
||||||
C_PIECES = $(OPENPIC_C_PIECES)
|
C_PIECES = $(OPENPIC_C_PIECES)
|
||||||
C_FILES = $(C_PIECES:%=%.c)
|
C_FILES = $(C_PIECES:%=%.c)
|
||||||
C_O_FILES = $(C_PIECES:%=${ARCH}/%.o)
|
C_O_FILES = $(C_PIECES:%=${ARCH}/%.o)
|
||||||
|
|
||||||
H_FILES = $(srcdir)/openpic.h
|
H_FILES = $(srcdir)/../../shared/openpic/openpic.h
|
||||||
|
|
||||||
SRCS = $(C_FILES) $(H_FILES)
|
SRCS = $(C_FILES) $(H_FILES)
|
||||||
OBJS = $(C_O_FILES)
|
OBJS = $(C_O_FILES)
|
||||||
@@ -60,14 +58,11 @@ LDFLAGS +=
|
|||||||
CLEAN_ADDITIONS +=
|
CLEAN_ADDITIONS +=
|
||||||
CLOBBER_ADDITIONS +=
|
CLOBBER_ADDITIONS +=
|
||||||
|
|
||||||
$(PGM): ${OBJS}
|
|
||||||
$(make-rel)
|
|
||||||
|
|
||||||
preinstall:
|
preinstall:
|
||||||
@$(mkinstalldirs) $(PROJECT_INCLUDE)/bsp
|
@$(mkinstalldirs) $(PROJECT_INCLUDE)/bsp
|
||||||
@$(INSTALL_CHANGE) -m 644 $(H_FILES) $(PROJECT_INCLUDE)/bsp
|
@$(INSTALL_CHANGE) -m 644 $(H_FILES) $(PROJECT_INCLUDE)/bsp
|
||||||
|
|
||||||
all: ${ARCH} $(SRCS) preinstall $(PGM)
|
all: ${ARCH} $(SRCS) preinstall $(OBJS)
|
||||||
|
|
||||||
# the .rel file built here will be put into libbsp.a by ../wrapup/Makefile
|
# the .rel file built here will be put into libbsp.a by ../wrapup/Makefile
|
||||||
install: all
|
install: all
|
||||||
|
|||||||
@@ -11,16 +11,14 @@ subdir = powerpc/mcp750/pci
|
|||||||
RTEMS_ROOT = @RTEMS_ROOT@
|
RTEMS_ROOT = @RTEMS_ROOT@
|
||||||
PROJECT_ROOT = @PROJECT_ROOT@
|
PROJECT_ROOT = @PROJECT_ROOT@
|
||||||
|
|
||||||
VPATH = @srcdir@
|
VPATH = @srcdir@:@srcdir@/../../shared/pci
|
||||||
|
|
||||||
PGM = ${ARCH}/pci.rel
|
|
||||||
|
|
||||||
# C source names, if any, go here -- minus the .c
|
# C source names, if any, go here -- minus the .c
|
||||||
C_PIECES = $(PCI_C_PIECES)
|
C_PIECES = pci
|
||||||
C_FILES = $(C_PIECES:%=%.c)
|
C_FILES = $(C_PIECES:%=%.c)
|
||||||
C_O_FILES = $(C_PIECES:%=${ARCH}/%.o)
|
C_O_FILES = $(C_PIECES:%=${ARCH}/%.o)
|
||||||
|
|
||||||
H_FILES = $(srcdir)/pci.h
|
H_FILES = $(srcdir)/../../shared/pci/pci.h
|
||||||
|
|
||||||
SRCS = $(C_FILES) $(H_FILES)
|
SRCS = $(C_FILES) $(H_FILES)
|
||||||
OBJS = $(C_O_FILES)
|
OBJS = $(C_O_FILES)
|
||||||
@@ -36,8 +34,6 @@ INSTALLDIRS = $(PROJECT_INCLUDE)/bsp
|
|||||||
$(INSTALLDIRS):
|
$(INSTALLDIRS):
|
||||||
@$(mkinstalldirs) $(INSTALLDIRS)
|
@$(mkinstalldirs) $(INSTALLDIRS)
|
||||||
|
|
||||||
PCI_C_PIECES = pci
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# (OPTIONAL) Add local stuff here using +=
|
# (OPTIONAL) Add local stuff here using +=
|
||||||
#
|
#
|
||||||
@@ -60,14 +56,11 @@ LDFLAGS +=
|
|||||||
CLEAN_ADDITIONS +=
|
CLEAN_ADDITIONS +=
|
||||||
CLOBBER_ADDITIONS +=
|
CLOBBER_ADDITIONS +=
|
||||||
|
|
||||||
$(PGM): ${OBJS}
|
|
||||||
$(make-rel)
|
|
||||||
|
|
||||||
preinstall:
|
preinstall:
|
||||||
@$(mkinstalldirs) $(PROJECT_INCLUDE)/bsp
|
@$(mkinstalldirs) $(PROJECT_INCLUDE)/bsp
|
||||||
@$(INSTALL_CHANGE) -m 644 $(H_FILES) $(PROJECT_INCLUDE)/bsp
|
@$(INSTALL_CHANGE) -m 644 $(H_FILES) $(PROJECT_INCLUDE)/bsp
|
||||||
|
|
||||||
all: ${ARCH} $(SRCS) preinstall $(PGM)
|
all: ${ARCH} $(SRCS) preinstall $(OBJS)
|
||||||
|
|
||||||
# the .rel file built here will be put into libbsp.a by ../wrapup/Makefile
|
# the .rel file built here will be put into libbsp.a by ../wrapup/Makefile
|
||||||
install: all
|
install: all
|
||||||
|
|||||||
@@ -11,16 +11,14 @@ subdir = powerpc/mcp750/residual
|
|||||||
RTEMS_ROOT = @RTEMS_ROOT@
|
RTEMS_ROOT = @RTEMS_ROOT@
|
||||||
PROJECT_ROOT = @PROJECT_ROOT@
|
PROJECT_ROOT = @PROJECT_ROOT@
|
||||||
|
|
||||||
VPATH = @srcdir@
|
VPATH = @srcdir@:@srcdir@/../../shared/residual
|
||||||
|
|
||||||
PGM = ${ARCH}/residual.rel
|
|
||||||
|
|
||||||
# C source names, if any, go here -- minus the .c
|
# C source names, if any, go here -- minus the .c
|
||||||
C_PIECES = $(RESIDUAL_C_PIECES)
|
C_PIECES = $(RESIDUAL_C_PIECES)
|
||||||
C_FILES = $(C_PIECES:%=%.c)
|
C_FILES = $(C_PIECES:%=%.c)
|
||||||
C_O_FILES = $(C_PIECES:%=${ARCH}/%.o)
|
C_O_FILES = $(C_PIECES:%=${ARCH}/%.o)
|
||||||
|
|
||||||
H_FILES = $(srcdir)/pnp.h $(srcdir)/residual.h
|
H_FILES = $(srcdir)/../../shared/residual/pnp.h $(srcdir)/../../shared/residual/residual.h
|
||||||
|
|
||||||
SRCS = $(C_FILES) $(H_FILES)
|
SRCS = $(C_FILES) $(H_FILES)
|
||||||
OBJS = $(C_O_FILES)
|
OBJS = $(C_O_FILES)
|
||||||
@@ -64,10 +62,7 @@ preinstall:
|
|||||||
@$(mkinstalldirs) $(PROJECT_INCLUDE)/bsp
|
@$(mkinstalldirs) $(PROJECT_INCLUDE)/bsp
|
||||||
@$(INSTALL_CHANGE) -m 644 $(H_FILES) $(PROJECT_INCLUDE)/bsp
|
@$(INSTALL_CHANGE) -m 644 $(H_FILES) $(PROJECT_INCLUDE)/bsp
|
||||||
|
|
||||||
$(PGM): ${OBJS}
|
all: ${ARCH} $(SRCS) preinstall $(OBJS)
|
||||||
$(make-rel)
|
|
||||||
|
|
||||||
all: ${ARCH} $(SRCS) preinstall $(PGM)
|
|
||||||
|
|
||||||
# the .rel file built here will be put into libbsp.a by ../wrapup/Makefile
|
# the .rel file built here will be put into libbsp.a by ../wrapup/Makefile
|
||||||
install: all
|
install: all
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ subdir = powerpc/mcp750/start
|
|||||||
RTEMS_ROOT = @RTEMS_ROOT@
|
RTEMS_ROOT = @RTEMS_ROOT@
|
||||||
PROJECT_ROOT = @PROJECT_ROOT@
|
PROJECT_ROOT = @PROJECT_ROOT@
|
||||||
|
|
||||||
VPATH = @srcdir@
|
VPATH = @srcdir@:@srcdir@/../../shared/start
|
||||||
|
|
||||||
PGM = ${ARCH}/start.o
|
PGM = ${ARCH}/start.o
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ subdir = powerpc/mcp750/startup
|
|||||||
RTEMS_ROOT = @RTEMS_ROOT@
|
RTEMS_ROOT = @RTEMS_ROOT@
|
||||||
PROJECT_ROOT = @PROJECT_ROOT@
|
PROJECT_ROOT = @PROJECT_ROOT@
|
||||||
|
|
||||||
VPATH = @srcdir@:@srcdir@/../console:@srcdir@/../../../shared
|
VPATH = @srcdir@:@srcdir@/../console:@srcdir@/../../../shared:@srcdir@/../../shared/startup
|
||||||
|
|
||||||
# C source names, if any, go here -- minus the .c
|
# C source names, if any, go here -- minus the .c
|
||||||
C_PIECES = bootcard main bspstart bsppost bsplibc sbrk bspclean \
|
C_PIECES = bootcard main bspstart bsppost bsplibc sbrk bspclean \
|
||||||
|
|||||||
@@ -11,16 +11,14 @@ subdir = powerpc/mcp750/vectors
|
|||||||
RTEMS_ROOT = @RTEMS_ROOT@
|
RTEMS_ROOT = @RTEMS_ROOT@
|
||||||
PROJECT_ROOT = @PROJECT_ROOT@
|
PROJECT_ROOT = @PROJECT_ROOT@
|
||||||
|
|
||||||
VPATH = @srcdir@:@srcdir@/../console:
|
VPATH = @srcdir@:@srcdir@/../console:@srcdir@/../../shared/vectors
|
||||||
|
|
||||||
PGM = ${ARCH}/vectors.rel
|
|
||||||
|
|
||||||
# C source names, if any, go here -- minus the .c
|
# C source names, if any, go here -- minus the .c
|
||||||
C_PIECES = vectors_init
|
C_PIECES = vectors_init
|
||||||
C_FILES = $(C_PIECES:%=%.c)
|
C_FILES = $(C_PIECES:%=%.c)
|
||||||
C_O_FILES = $(C_PIECES:%=${ARCH}/%.o)
|
C_O_FILES = $(C_PIECES:%=${ARCH}/%.o)
|
||||||
|
|
||||||
H_FILES = $(srcdir)/vectors.h
|
H_FILES = $(srcdir)/../../shared/vectors/vectors.h
|
||||||
|
|
||||||
# Assembly source names, if any, go here -- minus the .s
|
# Assembly source names, if any, go here -- minus the .s
|
||||||
S_PIECES = vectors
|
S_PIECES = vectors
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ NETWORK_yes_V = dec21140
|
|||||||
NETWORK = $(NETWORK_$(HAS_NETWORKING)_V)
|
NETWORK = $(NETWORK_$(HAS_NETWORKING)_V)
|
||||||
|
|
||||||
BSP_PIECES = clock console irq openpic pci residual startup $(NETWORK) \
|
BSP_PIECES = clock console irq openpic pci residual startup $(NETWORK) \
|
||||||
vectors
|
vectors motorola
|
||||||
GENERIC_PIECES =
|
GENERIC_PIECES =
|
||||||
|
|
||||||
# bummer; have to use $foreach since % pattern subst rules only replace 1x
|
# bummer; have to use $foreach since % pattern subst rules only replace 1x
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ NETWORK = $(NETWORK_$(HAS_NETWORKING)_V)
|
|||||||
# wrapup is the one that actually builds and installs the library
|
# wrapup is the one that actually builds and installs the library
|
||||||
# from the individual .rel files built in other directories
|
# from the individual .rel files built in other directories
|
||||||
SUBDIRS = clock console include pci residual openpic irq vectors start \
|
SUBDIRS = clock console include pci residual openpic irq vectors start \
|
||||||
startup bootloader $(NETWORK) wrapup
|
startup bootloader $(NETWORK) motorola wrapup
|
||||||
|
|
||||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||||
cd $(top_builddir) \
|
cd $(top_builddir) \
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ subdir = powerpc/mcp750/bootloader
|
|||||||
RTEMS_ROOT = @RTEMS_ROOT@
|
RTEMS_ROOT = @RTEMS_ROOT@
|
||||||
PROJECT_ROOT = @PROJECT_ROOT@
|
PROJECT_ROOT = @PROJECT_ROOT@
|
||||||
|
|
||||||
VPATH = @srcdir@:@srcdir@/../../../shared:@srcdir@/../console
|
VPATH = @srcdir@:@srcdir@/../../../shared:@srcdir@/../../shared/console:@srcdir@/../../shared/bootloader
|
||||||
|
|
||||||
# C source names, if any, go here -- minus the .c
|
# C source names, if any, go here -- minus the .c
|
||||||
C_PIECES = misc pci zlib mm em86 polled_io lib
|
C_PIECES = misc pci zlib mm em86 polled_io lib
|
||||||
@@ -77,7 +77,7 @@ CLOBBER_ADDITIONS += $(IMAGES)
|
|||||||
#
|
#
|
||||||
bootloader : ${OBJS} $(IMAGES) $(BINARY_LOADED) ppcboot.lds
|
bootloader : ${OBJS} $(IMAGES) $(BINARY_LOADED) ppcboot.lds
|
||||||
$(LD) -o bootloader $(OBJS) --just-symbols=$(BINARY_LOADED) \
|
$(LD) -o bootloader $(OBJS) --just-symbols=$(BINARY_LOADED) \
|
||||||
-b binary $(IMAGES) -T @srcdir@/ppcboot.lds \
|
-b binary $(IMAGES) -T @srcdir@/../../shared/bootloader/ppcboot.lds \
|
||||||
-Map bootloader.map
|
-Map bootloader.map
|
||||||
|
|
||||||
check_unresolved : ${OBJS}
|
check_unresolved : ${OBJS}
|
||||||
|
|||||||
@@ -11,9 +11,7 @@ subdir = powerpc/mcp750/clock
|
|||||||
RTEMS_ROOT = @RTEMS_ROOT@
|
RTEMS_ROOT = @RTEMS_ROOT@
|
||||||
PROJECT_ROOT = @PROJECT_ROOT@
|
PROJECT_ROOT = @PROJECT_ROOT@
|
||||||
|
|
||||||
VPATH = @srcdir@
|
VPATH = @srcdir@:@srcdir@/../../shared/clock
|
||||||
|
|
||||||
PGM = ${ARCH}/clock.rel
|
|
||||||
|
|
||||||
# C source names, if any, go here -- minus the .c
|
# C source names, if any, go here -- minus the .c
|
||||||
C_PIECES = p_clock
|
C_PIECES = p_clock
|
||||||
@@ -58,10 +56,7 @@ LDFLAGS +=
|
|||||||
CLEAN_ADDITIONS +=
|
CLEAN_ADDITIONS +=
|
||||||
CLOBBER_ADDITIONS +=
|
CLOBBER_ADDITIONS +=
|
||||||
|
|
||||||
$(PGM): ${OBJS}
|
all: ${ARCH} $(SRCS) $(OBJS)
|
||||||
$(make-rel)
|
|
||||||
|
|
||||||
all: ${ARCH} $(SRCS) $(PGM)
|
|
||||||
|
|
||||||
# the .rel file built here will be put into libbsp.a by ../wrapup/Makefile
|
# the .rel file built here will be put into libbsp.a by ../wrapup/Makefile
|
||||||
install: all
|
install: all
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# $Id:
|
# $Id$
|
||||||
#
|
#
|
||||||
|
|
||||||
@SET_MAKE@
|
@SET_MAKE@
|
||||||
@@ -11,14 +11,14 @@ subdir = powerpc/mcp750/console
|
|||||||
RTEMS_ROOT = @RTEMS_ROOT@
|
RTEMS_ROOT = @RTEMS_ROOT@
|
||||||
PROJECT_ROOT = @PROJECT_ROOT@
|
PROJECT_ROOT = @PROJECT_ROOT@
|
||||||
|
|
||||||
VPATH = @srcdir@:@srcdir@/../../../shared
|
VPATH = @srcdir@:@srcdir@/../../shared/console:@srcdir@/../../../shared
|
||||||
|
|
||||||
# C source names, if any, go here -- minus the .c
|
# C source names, if any, go here -- minus the .c
|
||||||
C_PIECES = polled_io uart console inch console_reserve_resources
|
C_PIECES = polled_io uart console inch
|
||||||
C_FILES = $(C_PIECES:%=%.c)
|
C_FILES = $(C_PIECES:%=%.c)
|
||||||
C_O_FILES = $(C_PIECES:%=${ARCH}/%.o)
|
C_O_FILES = $(C_PIECES:%=${ARCH}/%.o)
|
||||||
|
|
||||||
H_FILES = $(srcdir)/consoleIo.h $(srcdir)/keyboard.h $(srcdir)/uart.h
|
H_FILES = $(srcdir)/../../shared/console/consoleIo.h $(srcdir)/../../shared/console/keyboard.h $(srcdir)/../../shared/console/uart.h
|
||||||
|
|
||||||
# Assembly source names, if any, go here -- minus the .s
|
# Assembly source names, if any, go here -- minus the .s
|
||||||
S_PIECES =
|
S_PIECES =
|
||||||
@@ -48,6 +48,7 @@ CC_O_FILES = $(CC_PIECES:%=${ARCH}/%.o)
|
|||||||
#
|
#
|
||||||
|
|
||||||
CPPFLAGS += -DSTATIC_LOG_ALLOC
|
CPPFLAGS += -DSTATIC_LOG_ALLOC
|
||||||
|
CFLAGS +=
|
||||||
#
|
#
|
||||||
# Add your list of files to delete here. The config files
|
# Add your list of files to delete here. The config files
|
||||||
# already know how to delete some stuff, so you may want
|
# already know how to delete some stuff, so you may want
|
||||||
@@ -56,11 +57,7 @@ CPPFLAGS += -DSTATIC_LOG_ALLOC
|
|||||||
# 'make clobber' already includes 'make clean'
|
# 'make clobber' already includes 'make clean'
|
||||||
#
|
#
|
||||||
|
|
||||||
preinstall:
|
all: ${ARCH} $(SRCS) ${OBJS}
|
||||||
@$(mkinstalldirs) $(PROJECT_INCLUDE)/bsp
|
|
||||||
@$(INSTALL_CHANGE) -m 644 $(H_FILES) $(PROJECT_INCLUDE)/bsp
|
|
||||||
|
|
||||||
all: ${ARCH} $(SRCS) preinstall ${OBJS}
|
|
||||||
|
|
||||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||||
cd $(top_builddir) \
|
cd $(top_builddir) \
|
||||||
|
|||||||
@@ -1,382 +0,0 @@
|
|||||||
/*
|
|
||||||
* console.c -- console I/O package
|
|
||||||
*
|
|
||||||
* Copyright (C) 1999 Eric Valette. valette@crf.canon.fr
|
|
||||||
*
|
|
||||||
* This code is based on the pc386 BSP console.c so the following
|
|
||||||
* copyright also applies :
|
|
||||||
*
|
|
||||||
* (C) Copyright 1997 -
|
|
||||||
* - NavIST Group - Real-Time Distributed Systems and Industrial Automation
|
|
||||||
*
|
|
||||||
* http://pandora.ist.utl.pt
|
|
||||||
*
|
|
||||||
* Instituto Superior Tecnico * Lisboa * PORTUGAL
|
|
||||||
* The license and distribution terms for this file may be
|
|
||||||
* found in found in the file LICENSE in this distribution or at
|
|
||||||
* http://www.OARcorp.com/rtems/license.html.
|
|
||||||
*
|
|
||||||
* $Id$
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <assert.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#undef __assert
|
|
||||||
void __assert (const char *file, int line, const char *msg);
|
|
||||||
extern int close(int fd);
|
|
||||||
|
|
||||||
#include <bsp.h>
|
|
||||||
#include <bsp/irq.h>
|
|
||||||
#include <rtems/libio.h>
|
|
||||||
#include <termios.h>
|
|
||||||
#include <bsp/uart.h>
|
|
||||||
#include <bsp/consoleIo.h>
|
|
||||||
|
|
||||||
/* Definitions for BSPConsolePort */
|
|
||||||
#define BSP_CONSOLE_PORT_CONSOLE (-1)
|
|
||||||
#define BSP_CONSOLE_PORT_COM1 (BSP_UART_COM1)
|
|
||||||
#define BSP_CONSOLE_PORT_COM2 (BSP_UART_COM2)
|
|
||||||
/*
|
|
||||||
* Possible value for console input/output :
|
|
||||||
* BSP_CONSOLE_PORT_CONSOLE
|
|
||||||
* BSP_UART_COM1
|
|
||||||
* BSP_UART_COM2
|
|
||||||
*/
|
|
||||||
|
|
||||||
extern int BSPConsolePort;
|
|
||||||
|
|
||||||
/* int BSPConsolePort = BSP_UART_COM2; */
|
|
||||||
extern int BSPBaseBaud;
|
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------+
|
|
||||||
| External Prototypes
|
|
||||||
+--------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
static int conSetAttr(int minor, const struct termios *);
|
|
||||||
static void isr_on(const rtems_irq_connect_data *);
|
|
||||||
static void isr_off(const rtems_irq_connect_data *);
|
|
||||||
static int isr_is_on(const rtems_irq_connect_data *);
|
|
||||||
|
|
||||||
|
|
||||||
static rtems_irq_connect_data console_isr_data = {BSP_ISA_UART_COM1_IRQ,
|
|
||||||
BSP_uart_termios_isr_com1,
|
|
||||||
isr_on,
|
|
||||||
isr_off,
|
|
||||||
isr_is_on};
|
|
||||||
|
|
||||||
static void
|
|
||||||
isr_on(const rtems_irq_connect_data *unused)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
isr_off(const rtems_irq_connect_data *unused)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
isr_is_on(const rtems_irq_connect_data *irq)
|
|
||||||
{
|
|
||||||
return BSP_irq_enabled_at_i8259s(irq->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
void console_reserve_resources(rtems_configuration_table *conf)
|
|
||||||
{
|
|
||||||
if(BSPConsolePort != BSP_CONSOLE_PORT_CONSOLE)
|
|
||||||
{
|
|
||||||
rtems_termios_reserve_resources(conf, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
void __assert (const char *file, int line, const char *msg)
|
|
||||||
{
|
|
||||||
static char exit_msg[] = "EXECUTIVE SHUTDOWN! Any key to reboot...";
|
|
||||||
unsigned char ch;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Note we cannot call exit or printf from here,
|
|
||||||
* assert can fail inside ISR too
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Close console
|
|
||||||
*/
|
|
||||||
close(2);
|
|
||||||
close(1);
|
|
||||||
close(0);
|
|
||||||
|
|
||||||
printk("\nassert failed: %s: ", file);
|
|
||||||
printk("%d: ", line);
|
|
||||||
printk("%s\n\n", msg);
|
|
||||||
printk(exit_msg);
|
|
||||||
ch = debug_getc();
|
|
||||||
printk("\n\n");
|
|
||||||
rtemsReboot();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------+
|
|
||||||
| Console device driver INITIALIZE entry point.
|
|
||||||
+--------------------------------------------------------------------------+
|
|
||||||
| Initilizes the I/O console (keyboard + VGA display) driver.
|
|
||||||
+--------------------------------------------------------------------------*/
|
|
||||||
rtems_device_driver
|
|
||||||
console_initialize(rtems_device_major_number major,
|
|
||||||
rtems_device_minor_number minor,
|
|
||||||
void *arg)
|
|
||||||
{
|
|
||||||
rtems_status_code status;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The video was initialized in the start.s code and does not need
|
|
||||||
* to be reinitialized.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Set up TERMIOS
|
|
||||||
*/
|
|
||||||
rtems_termios_initialize ();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Do device-specific initialization
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* 9600-8-N-1 */
|
|
||||||
BSP_uart_init(BSPConsolePort, 9600, 0);
|
|
||||||
|
|
||||||
|
|
||||||
/* Set interrupt handler */
|
|
||||||
if(BSPConsolePort == BSP_UART_COM1)
|
|
||||||
{
|
|
||||||
console_isr_data.name = BSP_ISA_UART_COM1_IRQ;
|
|
||||||
console_isr_data.hdl = BSP_uart_termios_isr_com1;
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
assert(BSPConsolePort == BSP_UART_COM2);
|
|
||||||
console_isr_data.name = BSP_ISA_UART_COM2_IRQ;
|
|
||||||
console_isr_data.hdl = BSP_uart_termios_isr_com2;
|
|
||||||
}
|
|
||||||
|
|
||||||
status = BSP_install_rtems_irq_handler(&console_isr_data);
|
|
||||||
|
|
||||||
if (!status){
|
|
||||||
printk("Error installing serial console interrupt handler!\n");
|
|
||||||
rtems_fatal_error_occurred(status);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Register the device
|
|
||||||
*/
|
|
||||||
status = rtems_io_register_name ("/dev/console", major, 0);
|
|
||||||
if (status != RTEMS_SUCCESSFUL)
|
|
||||||
{
|
|
||||||
printk("Error registering console device!\n");
|
|
||||||
rtems_fatal_error_occurred (status);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(BSPConsolePort == BSP_UART_COM1)
|
|
||||||
{
|
|
||||||
printk("Initialized console on port COM1 9600-8-N-1\n\n");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printk("Initialized console on port COM2 9600-8-N-1\n\n");
|
|
||||||
}
|
|
||||||
return RTEMS_SUCCESSFUL;
|
|
||||||
} /* console_initialize */
|
|
||||||
|
|
||||||
|
|
||||||
static int console_last_close(int major, int minor, void *arg)
|
|
||||||
{
|
|
||||||
BSP_remove_rtems_irq_handler (&console_isr_data);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------+
|
|
||||||
| Console device driver OPEN entry point
|
|
||||||
+--------------------------------------------------------------------------*/
|
|
||||||
rtems_device_driver
|
|
||||||
console_open(rtems_device_major_number major,
|
|
||||||
rtems_device_minor_number minor,
|
|
||||||
void *arg)
|
|
||||||
{
|
|
||||||
rtems_status_code status;
|
|
||||||
static rtems_termios_callbacks cb =
|
|
||||||
{
|
|
||||||
NULL, /* firstOpen */
|
|
||||||
console_last_close, /* lastClose */
|
|
||||||
NULL, /* pollRead */
|
|
||||||
BSP_uart_termios_write_com1, /* write */
|
|
||||||
conSetAttr, /* setAttributes */
|
|
||||||
NULL, /* stopRemoteTx */
|
|
||||||
NULL, /* startRemoteTx */
|
|
||||||
1 /* outputUsesInterrupts */
|
|
||||||
};
|
|
||||||
|
|
||||||
if(BSPConsolePort == BSP_UART_COM2)
|
|
||||||
{
|
|
||||||
cb.write = BSP_uart_termios_write_com2;
|
|
||||||
}
|
|
||||||
|
|
||||||
status = rtems_termios_open (major, minor, arg, &cb);
|
|
||||||
|
|
||||||
if(status != RTEMS_SUCCESSFUL)
|
|
||||||
{
|
|
||||||
printk("Error openning console device\n");
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Pass data area info down to driver
|
|
||||||
*/
|
|
||||||
BSP_uart_termios_set(BSPConsolePort,
|
|
||||||
((rtems_libio_open_close_args_t *)arg)->iop->data1);
|
|
||||||
/* Enable interrupts on channel */
|
|
||||||
BSP_uart_intr_ctrl(BSPConsolePort, BSP_UART_INTR_CTRL_TERMIOS);
|
|
||||||
|
|
||||||
return RTEMS_SUCCESSFUL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------+
|
|
||||||
| Console device driver CLOSE entry point
|
|
||||||
+--------------------------------------------------------------------------*/
|
|
||||||
rtems_device_driver
|
|
||||||
console_close(rtems_device_major_number major,
|
|
||||||
rtems_device_minor_number minor,
|
|
||||||
void *arg)
|
|
||||||
{
|
|
||||||
rtems_device_driver res = RTEMS_SUCCESSFUL;
|
|
||||||
|
|
||||||
res = rtems_termios_close (arg);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
} /* console_close */
|
|
||||||
|
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------+
|
|
||||||
| Console device driver READ entry point.
|
|
||||||
+--------------------------------------------------------------------------+
|
|
||||||
| Read characters from the I/O console. We only have stdin.
|
|
||||||
+--------------------------------------------------------------------------*/
|
|
||||||
rtems_device_driver
|
|
||||||
console_read(rtems_device_major_number major,
|
|
||||||
rtems_device_minor_number minor,
|
|
||||||
void *arg)
|
|
||||||
{
|
|
||||||
|
|
||||||
return rtems_termios_read (arg);
|
|
||||||
} /* console_read */
|
|
||||||
|
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------+
|
|
||||||
| Console device driver WRITE entry point.
|
|
||||||
+--------------------------------------------------------------------------+
|
|
||||||
| Write characters to the I/O console. Stderr and stdout are the same.
|
|
||||||
+--------------------------------------------------------------------------*/
|
|
||||||
rtems_device_driver
|
|
||||||
console_write(rtems_device_major_number major,
|
|
||||||
rtems_device_minor_number minor,
|
|
||||||
void * arg)
|
|
||||||
{
|
|
||||||
|
|
||||||
return rtems_termios_write (arg);
|
|
||||||
|
|
||||||
} /* console_write */
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Handle ioctl request.
|
|
||||||
*/
|
|
||||||
rtems_device_driver
|
|
||||||
console_control(rtems_device_major_number major,
|
|
||||||
rtems_device_minor_number minor,
|
|
||||||
void * arg
|
|
||||||
)
|
|
||||||
{
|
|
||||||
return rtems_termios_ioctl (arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
conSetAttr(int minor, const struct termios *t)
|
|
||||||
{
|
|
||||||
int baud;
|
|
||||||
|
|
||||||
switch (t->c_cflag & CBAUD)
|
|
||||||
{
|
|
||||||
case B50:
|
|
||||||
baud = 50;
|
|
||||||
break;
|
|
||||||
case B75:
|
|
||||||
baud = 75;
|
|
||||||
break;
|
|
||||||
case B110:
|
|
||||||
baud = 110;
|
|
||||||
break;
|
|
||||||
case B134:
|
|
||||||
baud = 134;
|
|
||||||
break;
|
|
||||||
case B150:
|
|
||||||
baud = 150;
|
|
||||||
break;
|
|
||||||
case B200:
|
|
||||||
baud = 200;
|
|
||||||
break;
|
|
||||||
case B300:
|
|
||||||
baud = 300;
|
|
||||||
break;
|
|
||||||
case B600:
|
|
||||||
baud = 600;
|
|
||||||
break;
|
|
||||||
case B1200:
|
|
||||||
baud = 1200;
|
|
||||||
break;
|
|
||||||
case B1800:
|
|
||||||
baud = 1800;
|
|
||||||
break;
|
|
||||||
case B2400:
|
|
||||||
baud = 2400;
|
|
||||||
break;
|
|
||||||
case B4800:
|
|
||||||
baud = 4800;
|
|
||||||
break;
|
|
||||||
case B9600:
|
|
||||||
baud = 9600;
|
|
||||||
break;
|
|
||||||
case B19200:
|
|
||||||
baud = 19200;
|
|
||||||
break;
|
|
||||||
case B38400:
|
|
||||||
baud = 38400;
|
|
||||||
break;
|
|
||||||
case B57600:
|
|
||||||
baud = 57600;
|
|
||||||
break;
|
|
||||||
case B115200:
|
|
||||||
baud = 115200;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
baud = 0;
|
|
||||||
rtems_fatal_error_occurred (RTEMS_INTERNAL_ERROR);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
BSP_uart_set_baud(BSPConsolePort, baud);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
/*
|
|
||||||
* console.c -- console I/O package
|
|
||||||
*
|
|
||||||
* Copyright (C) 1999 Eric Valette. valette@crf.canon.fr
|
|
||||||
*
|
|
||||||
* This code is based on the pc386 BSP console.c so the following
|
|
||||||
* copyright also applies :
|
|
||||||
*
|
|
||||||
* (C) Copyright 1997 -
|
|
||||||
* - NavIST Group - Real-Time Distributed Systems and Industrial Automation
|
|
||||||
*
|
|
||||||
* http://pandora.ist.utl.pt
|
|
||||||
*
|
|
||||||
* Instituto Superior Tecnico * Lisboa * PORTUGAL
|
|
||||||
* The license and distribution terms for this file may be
|
|
||||||
* found in found in the file LICENSE in this distribution or at
|
|
||||||
* http://www.OARcorp.com/rtems/license.html.
|
|
||||||
*
|
|
||||||
* $Id$
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <assert.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#undef __assert
|
|
||||||
void __assert (const char *file, int line, const char *msg);
|
|
||||||
extern int close(int fd);
|
|
||||||
|
|
||||||
#include <bsp.h>
|
|
||||||
#include <bsp/irq.h>
|
|
||||||
#include <rtems/libio.h>
|
|
||||||
#include <termios.h>
|
|
||||||
#include <bsp/uart.h>
|
|
||||||
#include <bsp/consoleIo.h>
|
|
||||||
|
|
||||||
/* Definitions for BSPConsolePort */
|
|
||||||
#define BSP_CONSOLE_PORT_CONSOLE (-1)
|
|
||||||
#define BSP_CONSOLE_PORT_COM1 (BSP_UART_COM1)
|
|
||||||
#define BSP_CONSOLE_PORT_COM2 (BSP_UART_COM2)
|
|
||||||
/*
|
|
||||||
* Possible value for console input/output :
|
|
||||||
* BSP_CONSOLE_PORT_CONSOLE
|
|
||||||
* BSP_UART_COM1
|
|
||||||
* BSP_UART_COM2
|
|
||||||
*/
|
|
||||||
|
|
||||||
int BSPConsolePort = BSP_UART_COM1;
|
|
||||||
|
|
||||||
/* int BSPConsolePort = BSP_UART_COM2; */
|
|
||||||
int BSPBaseBaud = 115200;
|
|
||||||
|
|
||||||
void console_reserve_resources(rtems_configuration_table *conf)
|
|
||||||
{
|
|
||||||
if(BSPConsolePort != BSP_CONSOLE_PORT_CONSOLE)
|
|
||||||
{
|
|
||||||
rtems_termios_reserve_resources(conf, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
@@ -13,7 +13,13 @@ PROJECT_ROOT = @PROJECT_ROOT@
|
|||||||
|
|
||||||
VPATH = @srcdir@
|
VPATH = @srcdir@
|
||||||
|
|
||||||
H_FILES = $(srcdir)/nvram.h $(srcdir)/bsp.h
|
H_FILES = $(srcdir)/../../shared/include/nvram.h \
|
||||||
|
$(srcdir)/../../shared/include/bsp.h
|
||||||
|
|
||||||
|
BSP_H_FILES = $(srcdir)/../../shared/console/consoleIo.h \
|
||||||
|
$(srcdir)/../../shared/console/uart.h \
|
||||||
|
$(srcdir)/../../shared/irq/irq.h \
|
||||||
|
$(srcdir)/../../shared/motorola/motorola.h
|
||||||
|
|
||||||
#
|
#
|
||||||
# Equate files are for including from assembly preprocessed by
|
# Equate files are for including from assembly preprocessed by
|
||||||
@@ -43,7 +49,9 @@ CLOBBER_ADDITIONS +=
|
|||||||
|
|
||||||
preinstall:
|
preinstall:
|
||||||
$(mkinstalldirs) $(PROJECT_INCLUDE)
|
$(mkinstalldirs) $(PROJECT_INCLUDE)
|
||||||
|
$(mkinstalldirs) $(PROJECT_INCLUDE)/bsp
|
||||||
@$(INSTALL_CHANGE) -m 644 $(H_FILES) $(PROJECT_INCLUDE)
|
@$(INSTALL_CHANGE) -m 644 $(H_FILES) $(PROJECT_INCLUDE)
|
||||||
|
@$(INSTALL_CHANGE) -m 644 $(BSP_H_FILES) $(PROJECT_INCLUDE)/bsp
|
||||||
|
|
||||||
all: $(SRCS) preinstall
|
all: $(SRCS) preinstall
|
||||||
|
|
||||||
|
|||||||
@@ -11,14 +11,14 @@ subdir = powerpc/mcp750/irq
|
|||||||
RTEMS_ROOT = @RTEMS_ROOT@
|
RTEMS_ROOT = @RTEMS_ROOT@
|
||||||
PROJECT_ROOT = @PROJECT_ROOT@
|
PROJECT_ROOT = @PROJECT_ROOT@
|
||||||
|
|
||||||
VPATH = @srcdir@
|
VPATH = @srcdir@:@srcdir@/../../shared/irq
|
||||||
|
|
||||||
# C source names, if any, go here -- minus the .c
|
# C source names, if any, go here -- minus the .c
|
||||||
C_PIECES = irq_init i8259 irq
|
C_PIECES = irq_init i8259 irq
|
||||||
C_FILES = $(C_PIECES:%=%.c)
|
C_FILES = $(C_PIECES:%=%.c)
|
||||||
C_O_FILES = $(C_PIECES:%=${ARCH}/%.o)
|
C_O_FILES = $(C_PIECES:%=${ARCH}/%.o)
|
||||||
|
|
||||||
H_FILES = $(srcdir)/irq.h
|
H_FILES = $(srcdir)/../../shared/irq/irq.h
|
||||||
|
|
||||||
# Assembly source names, if any, go here -- minus the .s
|
# Assembly source names, if any, go here -- minus the .s
|
||||||
S_PIECES = irq_asm
|
S_PIECES = irq_asm
|
||||||
@@ -61,11 +61,7 @@ LDFLAGS +=
|
|||||||
CLEAN_ADDITIONS +=
|
CLEAN_ADDITIONS +=
|
||||||
CLOBBER_ADDITIONS +=
|
CLOBBER_ADDITIONS +=
|
||||||
|
|
||||||
preinstall:
|
all: ${ARCH} $(SRCS) ${OBJS}
|
||||||
@$(mkinstalldirs) $(PROJECT_INCLUDE)/bsp
|
|
||||||
@$(INSTALL_CHANGE) -m 644 $(H_FILES) $(PROJECT_INCLUDE)/bsp
|
|
||||||
|
|
||||||
all: ${ARCH} $(SRCS) preinstall ${OBJS}
|
|
||||||
|
|
||||||
install: all
|
install: all
|
||||||
|
|
||||||
|
|||||||
@@ -11,16 +11,14 @@ subdir = powerpc/mcp750/openpic
|
|||||||
RTEMS_ROOT = @RTEMS_ROOT@
|
RTEMS_ROOT = @RTEMS_ROOT@
|
||||||
PROJECT_ROOT = @PROJECT_ROOT@
|
PROJECT_ROOT = @PROJECT_ROOT@
|
||||||
|
|
||||||
VPATH = @srcdir@
|
VPATH = @srcdir@:@srcdir@/../../shared/openpic
|
||||||
|
|
||||||
PGM = ${ARCH}/openpic.rel
|
|
||||||
|
|
||||||
# C source names, if any, go here -- minus the .c
|
# C source names, if any, go here -- minus the .c
|
||||||
C_PIECES = $(OPENPIC_C_PIECES)
|
C_PIECES = $(OPENPIC_C_PIECES)
|
||||||
C_FILES = $(C_PIECES:%=%.c)
|
C_FILES = $(C_PIECES:%=%.c)
|
||||||
C_O_FILES = $(C_PIECES:%=${ARCH}/%.o)
|
C_O_FILES = $(C_PIECES:%=${ARCH}/%.o)
|
||||||
|
|
||||||
H_FILES = $(srcdir)/openpic.h
|
H_FILES = $(srcdir)/../../shared/openpic/openpic.h
|
||||||
|
|
||||||
SRCS = $(C_FILES) $(H_FILES)
|
SRCS = $(C_FILES) $(H_FILES)
|
||||||
OBJS = $(C_O_FILES)
|
OBJS = $(C_O_FILES)
|
||||||
@@ -60,14 +58,11 @@ LDFLAGS +=
|
|||||||
CLEAN_ADDITIONS +=
|
CLEAN_ADDITIONS +=
|
||||||
CLOBBER_ADDITIONS +=
|
CLOBBER_ADDITIONS +=
|
||||||
|
|
||||||
$(PGM): ${OBJS}
|
|
||||||
$(make-rel)
|
|
||||||
|
|
||||||
preinstall:
|
preinstall:
|
||||||
@$(mkinstalldirs) $(PROJECT_INCLUDE)/bsp
|
@$(mkinstalldirs) $(PROJECT_INCLUDE)/bsp
|
||||||
@$(INSTALL_CHANGE) -m 644 $(H_FILES) $(PROJECT_INCLUDE)/bsp
|
@$(INSTALL_CHANGE) -m 644 $(H_FILES) $(PROJECT_INCLUDE)/bsp
|
||||||
|
|
||||||
all: ${ARCH} $(SRCS) preinstall $(PGM)
|
all: ${ARCH} $(SRCS) preinstall $(OBJS)
|
||||||
|
|
||||||
# the .rel file built here will be put into libbsp.a by ../wrapup/Makefile
|
# the .rel file built here will be put into libbsp.a by ../wrapup/Makefile
|
||||||
install: all
|
install: all
|
||||||
|
|||||||
@@ -11,16 +11,14 @@ subdir = powerpc/mcp750/pci
|
|||||||
RTEMS_ROOT = @RTEMS_ROOT@
|
RTEMS_ROOT = @RTEMS_ROOT@
|
||||||
PROJECT_ROOT = @PROJECT_ROOT@
|
PROJECT_ROOT = @PROJECT_ROOT@
|
||||||
|
|
||||||
VPATH = @srcdir@
|
VPATH = @srcdir@:@srcdir@/../../shared/pci
|
||||||
|
|
||||||
PGM = ${ARCH}/pci.rel
|
|
||||||
|
|
||||||
# C source names, if any, go here -- minus the .c
|
# C source names, if any, go here -- minus the .c
|
||||||
C_PIECES = $(PCI_C_PIECES)
|
C_PIECES = pci
|
||||||
C_FILES = $(C_PIECES:%=%.c)
|
C_FILES = $(C_PIECES:%=%.c)
|
||||||
C_O_FILES = $(C_PIECES:%=${ARCH}/%.o)
|
C_O_FILES = $(C_PIECES:%=${ARCH}/%.o)
|
||||||
|
|
||||||
H_FILES = $(srcdir)/pci.h
|
H_FILES = $(srcdir)/../../shared/pci/pci.h
|
||||||
|
|
||||||
SRCS = $(C_FILES) $(H_FILES)
|
SRCS = $(C_FILES) $(H_FILES)
|
||||||
OBJS = $(C_O_FILES)
|
OBJS = $(C_O_FILES)
|
||||||
@@ -36,8 +34,6 @@ INSTALLDIRS = $(PROJECT_INCLUDE)/bsp
|
|||||||
$(INSTALLDIRS):
|
$(INSTALLDIRS):
|
||||||
@$(mkinstalldirs) $(INSTALLDIRS)
|
@$(mkinstalldirs) $(INSTALLDIRS)
|
||||||
|
|
||||||
PCI_C_PIECES = pci
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# (OPTIONAL) Add local stuff here using +=
|
# (OPTIONAL) Add local stuff here using +=
|
||||||
#
|
#
|
||||||
@@ -60,14 +56,11 @@ LDFLAGS +=
|
|||||||
CLEAN_ADDITIONS +=
|
CLEAN_ADDITIONS +=
|
||||||
CLOBBER_ADDITIONS +=
|
CLOBBER_ADDITIONS +=
|
||||||
|
|
||||||
$(PGM): ${OBJS}
|
|
||||||
$(make-rel)
|
|
||||||
|
|
||||||
preinstall:
|
preinstall:
|
||||||
@$(mkinstalldirs) $(PROJECT_INCLUDE)/bsp
|
@$(mkinstalldirs) $(PROJECT_INCLUDE)/bsp
|
||||||
@$(INSTALL_CHANGE) -m 644 $(H_FILES) $(PROJECT_INCLUDE)/bsp
|
@$(INSTALL_CHANGE) -m 644 $(H_FILES) $(PROJECT_INCLUDE)/bsp
|
||||||
|
|
||||||
all: ${ARCH} $(SRCS) preinstall $(PGM)
|
all: ${ARCH} $(SRCS) preinstall $(OBJS)
|
||||||
|
|
||||||
# the .rel file built here will be put into libbsp.a by ../wrapup/Makefile
|
# the .rel file built here will be put into libbsp.a by ../wrapup/Makefile
|
||||||
install: all
|
install: all
|
||||||
|
|||||||
@@ -11,16 +11,14 @@ subdir = powerpc/mcp750/residual
|
|||||||
RTEMS_ROOT = @RTEMS_ROOT@
|
RTEMS_ROOT = @RTEMS_ROOT@
|
||||||
PROJECT_ROOT = @PROJECT_ROOT@
|
PROJECT_ROOT = @PROJECT_ROOT@
|
||||||
|
|
||||||
VPATH = @srcdir@
|
VPATH = @srcdir@:@srcdir@/../../shared/residual
|
||||||
|
|
||||||
PGM = ${ARCH}/residual.rel
|
|
||||||
|
|
||||||
# C source names, if any, go here -- minus the .c
|
# C source names, if any, go here -- minus the .c
|
||||||
C_PIECES = $(RESIDUAL_C_PIECES)
|
C_PIECES = $(RESIDUAL_C_PIECES)
|
||||||
C_FILES = $(C_PIECES:%=%.c)
|
C_FILES = $(C_PIECES:%=%.c)
|
||||||
C_O_FILES = $(C_PIECES:%=${ARCH}/%.o)
|
C_O_FILES = $(C_PIECES:%=${ARCH}/%.o)
|
||||||
|
|
||||||
H_FILES = $(srcdir)/pnp.h $(srcdir)/residual.h
|
H_FILES = $(srcdir)/../../shared/residual/pnp.h $(srcdir)/../../shared/residual/residual.h
|
||||||
|
|
||||||
SRCS = $(C_FILES) $(H_FILES)
|
SRCS = $(C_FILES) $(H_FILES)
|
||||||
OBJS = $(C_O_FILES)
|
OBJS = $(C_O_FILES)
|
||||||
@@ -64,10 +62,7 @@ preinstall:
|
|||||||
@$(mkinstalldirs) $(PROJECT_INCLUDE)/bsp
|
@$(mkinstalldirs) $(PROJECT_INCLUDE)/bsp
|
||||||
@$(INSTALL_CHANGE) -m 644 $(H_FILES) $(PROJECT_INCLUDE)/bsp
|
@$(INSTALL_CHANGE) -m 644 $(H_FILES) $(PROJECT_INCLUDE)/bsp
|
||||||
|
|
||||||
$(PGM): ${OBJS}
|
all: ${ARCH} $(SRCS) preinstall $(OBJS)
|
||||||
$(make-rel)
|
|
||||||
|
|
||||||
all: ${ARCH} $(SRCS) preinstall $(PGM)
|
|
||||||
|
|
||||||
# the .rel file built here will be put into libbsp.a by ../wrapup/Makefile
|
# the .rel file built here will be put into libbsp.a by ../wrapup/Makefile
|
||||||
install: all
|
install: all
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ subdir = powerpc/mcp750/start
|
|||||||
RTEMS_ROOT = @RTEMS_ROOT@
|
RTEMS_ROOT = @RTEMS_ROOT@
|
||||||
PROJECT_ROOT = @PROJECT_ROOT@
|
PROJECT_ROOT = @PROJECT_ROOT@
|
||||||
|
|
||||||
VPATH = @srcdir@
|
VPATH = @srcdir@:@srcdir@/../../shared/start
|
||||||
|
|
||||||
PGM = ${ARCH}/start.o
|
PGM = ${ARCH}/start.o
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ subdir = powerpc/mcp750/startup
|
|||||||
RTEMS_ROOT = @RTEMS_ROOT@
|
RTEMS_ROOT = @RTEMS_ROOT@
|
||||||
PROJECT_ROOT = @PROJECT_ROOT@
|
PROJECT_ROOT = @PROJECT_ROOT@
|
||||||
|
|
||||||
VPATH = @srcdir@:@srcdir@/../console:@srcdir@/../../../shared
|
VPATH = @srcdir@:@srcdir@/../console:@srcdir@/../../../shared:@srcdir@/../../shared/startup
|
||||||
|
|
||||||
# C source names, if any, go here -- minus the .c
|
# C source names, if any, go here -- minus the .c
|
||||||
C_PIECES = bootcard main bspstart bsppost bsplibc sbrk bspclean \
|
C_PIECES = bootcard main bspstart bsppost bsplibc sbrk bspclean \
|
||||||
|
|||||||
@@ -11,16 +11,14 @@ subdir = powerpc/mcp750/vectors
|
|||||||
RTEMS_ROOT = @RTEMS_ROOT@
|
RTEMS_ROOT = @RTEMS_ROOT@
|
||||||
PROJECT_ROOT = @PROJECT_ROOT@
|
PROJECT_ROOT = @PROJECT_ROOT@
|
||||||
|
|
||||||
VPATH = @srcdir@:@srcdir@/../console:
|
VPATH = @srcdir@:@srcdir@/../console:@srcdir@/../../shared/vectors
|
||||||
|
|
||||||
PGM = ${ARCH}/vectors.rel
|
|
||||||
|
|
||||||
# C source names, if any, go here -- minus the .c
|
# C source names, if any, go here -- minus the .c
|
||||||
C_PIECES = vectors_init
|
C_PIECES = vectors_init
|
||||||
C_FILES = $(C_PIECES:%=%.c)
|
C_FILES = $(C_PIECES:%=%.c)
|
||||||
C_O_FILES = $(C_PIECES:%=${ARCH}/%.o)
|
C_O_FILES = $(C_PIECES:%=${ARCH}/%.o)
|
||||||
|
|
||||||
H_FILES = $(srcdir)/vectors.h
|
H_FILES = $(srcdir)/../../shared/vectors/vectors.h
|
||||||
|
|
||||||
# Assembly source names, if any, go here -- minus the .s
|
# Assembly source names, if any, go here -- minus the .s
|
||||||
S_PIECES = vectors
|
S_PIECES = vectors
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ NETWORK_yes_V = dec21140
|
|||||||
NETWORK = $(NETWORK_$(HAS_NETWORKING)_V)
|
NETWORK = $(NETWORK_$(HAS_NETWORKING)_V)
|
||||||
|
|
||||||
BSP_PIECES = clock console irq openpic pci residual startup $(NETWORK) \
|
BSP_PIECES = clock console irq openpic pci residual startup $(NETWORK) \
|
||||||
vectors
|
vectors motorola
|
||||||
GENERIC_PIECES =
|
GENERIC_PIECES =
|
||||||
|
|
||||||
# bummer; have to use $foreach since % pattern subst rules only replace 1x
|
# bummer; have to use $foreach since % pattern subst rules only replace 1x
|
||||||
|
|||||||
36
c/src/lib/libbsp/powerpc/shared/Makefile.in
Normal file
36
c/src/lib/libbsp/powerpc/shared/Makefile.in
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
#
|
||||||
|
# $Id$
|
||||||
|
#
|
||||||
|
|
||||||
|
@SET_MAKE@
|
||||||
|
srcdir = @srcdir@
|
||||||
|
top_srcdir = @top_srcdir@
|
||||||
|
top_builddir = ../..
|
||||||
|
subdir = powerpc/shared
|
||||||
|
|
||||||
|
RTEMS_ROOT = @RTEMS_ROOT@
|
||||||
|
PROJECT_ROOT = @PROJECT_ROOT@
|
||||||
|
|
||||||
|
VPATH = @srcdir@
|
||||||
|
|
||||||
|
include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
|
||||||
|
include $(RTEMS_ROOT)/make/directory.cfg
|
||||||
|
|
||||||
|
INSTALL_CHANGE = @INSTALL_CHANGE@
|
||||||
|
|
||||||
|
SRCS =
|
||||||
|
|
||||||
|
all: $(SRCS)
|
||||||
|
|
||||||
|
# We only build the Network library if HAS_NETWORKING was defined
|
||||||
|
NETWORK_yes_V = dec21140
|
||||||
|
NETWORK = $(NETWORK_$(HAS_NETWORKING)_V)
|
||||||
|
|
||||||
|
# wrapup is the one that actually builds and installs the library
|
||||||
|
# from the individual .rel files built in other directories
|
||||||
|
SUB_DIRS = clock console include pci residual openpic irq vectors \
|
||||||
|
start startup motorola bootloader $(NETWORK)
|
||||||
|
|
||||||
|
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||||
|
cd $(top_builddir) \
|
||||||
|
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
|
||||||
44
c/src/lib/libbsp/powerpc/shared/bootloader/Makefile.in
Normal file
44
c/src/lib/libbsp/powerpc/shared/bootloader/Makefile.in
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
#
|
||||||
|
# $Id$
|
||||||
|
#
|
||||||
|
|
||||||
|
@SET_MAKE@
|
||||||
|
srcdir = @srcdir@
|
||||||
|
top_srcdir = @top_srcdir@
|
||||||
|
top_builddir = ../../..
|
||||||
|
subdir = powerpc/shared/bootloader
|
||||||
|
|
||||||
|
RTEMS_ROOT = @RTEMS_ROOT@
|
||||||
|
PROJECT_ROOT = @PROJECT_ROOT@
|
||||||
|
|
||||||
|
VPATH = @srcdir@:@srcdir@/../../../shared:@srcdir@/../console
|
||||||
|
|
||||||
|
# C source names, if any, go here -- minus the .c
|
||||||
|
C_PIECES =
|
||||||
|
C_FILES = $(C_PIECES:%=%.c)
|
||||||
|
C_O_FILES = $(C_PIECES:%=${ARCH}/%.o)
|
||||||
|
|
||||||
|
H_FILES = @srcdir@/bootldr.h @srcdir@/zlib.h @srcdir@/pci.h
|
||||||
|
|
||||||
|
# Assembly source names, if any, go here -- minus the .s
|
||||||
|
S_PIECES =
|
||||||
|
S_FILES = $(S_PIECES:%=%.S)
|
||||||
|
S_O_FILES = $(S_FILES:%.S=${ARCH}/%.o)
|
||||||
|
|
||||||
|
SRCS = $(C_FILES) $(CC_FILES) $(H_FILES) $(S_FILES)
|
||||||
|
OBJS = $(S_O_FILES) $(C_O_FILES)
|
||||||
|
|
||||||
|
include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
|
||||||
|
include $(RTEMS_ROOT)/make/leaf.cfg
|
||||||
|
|
||||||
|
INSTALL_CHANGE = @INSTALL_CHANGE@
|
||||||
|
|
||||||
|
CC_PIECES =
|
||||||
|
CC_FILES = $(CC_PIECES:%=%.cc)
|
||||||
|
CC_O_FILES = $(CC_PIECES:%=${ARCH}/%.o)
|
||||||
|
|
||||||
|
all: ${ARCH} $(SRCS) ${OBJ}
|
||||||
|
|
||||||
|
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||||
|
cd $(top_builddir) \
|
||||||
|
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
|
||||||
41
c/src/lib/libbsp/powerpc/shared/bootloader/README
Normal file
41
c/src/lib/libbsp/powerpc/shared/bootloader/README
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
#
|
||||||
|
# $Id$
|
||||||
|
#
|
||||||
|
|
||||||
|
The code in this directory has been taken WITH PERMISSION from
|
||||||
|
Gabriel Paubert, paubert@iram.es. The main reason for having
|
||||||
|
a separate bootloader for PreP compliant firmware is that the
|
||||||
|
initial code is relocated by firmware at an unknow address
|
||||||
|
(actually 0x5000 on motorola MCP750) and that as Gabriel I
|
||||||
|
think having a relocatable bootloder code is a must.
|
||||||
|
|
||||||
|
So the way of building a binary executable that can be booted via
|
||||||
|
hard disk or network boot goes like this :
|
||||||
|
|
||||||
|
- make a RTEMS executable,
|
||||||
|
- put is as data section in the bootloder binary,
|
||||||
|
- relink the loader (see make-exe macros for details),
|
||||||
|
|
||||||
|
I would like to thank Gabriel for his support and his code.
|
||||||
|
The original code can be found in form of a patch to official linux
|
||||||
|
kernel at (I insist not vger ppc kernel or Imac ppc kernels!!) :
|
||||||
|
|
||||||
|
<ftp://vlab1.iram.es/pub/linux-2.2/>
|
||||||
|
|
||||||
|
After applying the patch, the code is located in a new directory
|
||||||
|
called prepboot.
|
||||||
|
|
||||||
|
(NB : note use ftp not netscape...)
|
||||||
|
|
||||||
|
Note that the actual code differs a lot since Gabriel choose to use
|
||||||
|
a CHRP compliant mapping instead of a Prep Mapping to save
|
||||||
|
BATs. I had no time to upgrade the code to its new one allthough
|
||||||
|
I agree it should be done...
|
||||||
|
|
||||||
|
I have also splitted the original code to have a more modular
|
||||||
|
design enabling to reuse code between the loader and RTEMS
|
||||||
|
initialization (e.g printk, ...).
|
||||||
|
|
||||||
|
Eric Valette (valette@crf.canon.fr)
|
||||||
|
|
||||||
|
|
||||||
258
c/src/lib/libbsp/powerpc/shared/bootloader/bootldr.h
Normal file
258
c/src/lib/libbsp/powerpc/shared/bootloader/bootldr.h
Normal file
@@ -0,0 +1,258 @@
|
|||||||
|
/*
|
||||||
|
* bootldr.h -- Include file for bootloader.
|
||||||
|
*
|
||||||
|
* Copyright (C) 1998, 1999 Gabriel Paubert, paubert@iram.es
|
||||||
|
*
|
||||||
|
* Modified to compile in RTEMS development environment
|
||||||
|
* by Eric Valette
|
||||||
|
*
|
||||||
|
* Copyright (C) 1999 Eric Valette. valette@crf.canon.fr
|
||||||
|
*
|
||||||
|
* The license and distribution terms for this file may be
|
||||||
|
* found in found in the file LICENSE in this distribution or at
|
||||||
|
* http://www.OARcorp.com/rtems/license.html.
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _PPC_BOOTLDR_H
|
||||||
|
#define _PPC_BOOTLDR_H
|
||||||
|
|
||||||
|
#ifndef ASM
|
||||||
|
#include <bsp/residual.h>
|
||||||
|
#include <bsp/consoleIo.h>
|
||||||
|
#include "pci.h"
|
||||||
|
|
||||||
|
#define abs __builtin_abs
|
||||||
|
|
||||||
|
#define PTE_REFD 0x100
|
||||||
|
#define PTE_CHNG (0x80|PTE_REFD) /* Modified implies referenced */
|
||||||
|
#define PTE_WTHR 0x040
|
||||||
|
#define PTE_CINH 0x020
|
||||||
|
#define PTE_COHER 0x010
|
||||||
|
#define PTE_GUAR 0x008
|
||||||
|
#define PTE_RO 0x003
|
||||||
|
#define PTE_RW 0x002
|
||||||
|
|
||||||
|
#define PTE_RAM (PTE_CHNG|PTE_COHER|PTE_RW)
|
||||||
|
#define PTE_ROM (PTE_REFD|PTE_RO)
|
||||||
|
#define PTE_IO (PTE_CHNG|PTE_CINH|PTE_GUAR|PTE_RW)
|
||||||
|
|
||||||
|
typedef struct {}opaque;
|
||||||
|
|
||||||
|
/* The context passed during MMU interrupts. */
|
||||||
|
typedef struct _ctxt {
|
||||||
|
u_long lr, ctr;
|
||||||
|
u_int cr, xer;
|
||||||
|
u_long nip, msr;
|
||||||
|
u_long regs[32];
|
||||||
|
} ctxt;
|
||||||
|
|
||||||
|
/* The main structure which is pointed to permanently by r13. Things
|
||||||
|
* are not separated very well between parts because it would cause
|
||||||
|
* too much code bloat for such a simple program like the bootloader.
|
||||||
|
* The code is designed to be compiled with the -m relocatable option and
|
||||||
|
* tries to minimize the number of relocations/fixups and the number of
|
||||||
|
* functions who have to access the .got2 sections (this increases the
|
||||||
|
* size of the prologue in every function).
|
||||||
|
*/
|
||||||
|
typedef struct _boot_data {
|
||||||
|
RESIDUAL *residual;
|
||||||
|
void *load_address;
|
||||||
|
void *of_entry;
|
||||||
|
void *r6, *r7, *r8, *r9, *r10;
|
||||||
|
u_long cache_lsize;
|
||||||
|
void *image; /* Where to copy ourselves */
|
||||||
|
void *stack;
|
||||||
|
void *mover; /* where to copy codemove to avoid overlays */
|
||||||
|
u_long o_msr, o_hid0, o_r31;
|
||||||
|
opaque * mm_private;
|
||||||
|
const struct pci_config_access_functions * pci_functions;
|
||||||
|
opaque * pci_private;
|
||||||
|
struct pci_dev * pci_devices;
|
||||||
|
opaque * v86_private;
|
||||||
|
char cmd_line[256];
|
||||||
|
} boot_data;
|
||||||
|
|
||||||
|
register boot_data *bd __asm__("r13");
|
||||||
|
|
||||||
|
extern inline int
|
||||||
|
pcibios_read_config_byte(u_char bus, u_char dev_fn,
|
||||||
|
u_char where, u_char * val) {
|
||||||
|
return bd->pci_functions->read_config_byte(bus, dev_fn, where, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern inline int
|
||||||
|
pcibios_read_config_word(u_char bus, u_char dev_fn,
|
||||||
|
u_char where, u_short * val) {
|
||||||
|
return bd->pci_functions->read_config_word(bus, dev_fn, where, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern inline int
|
||||||
|
pcibios_read_config_dword(u_char bus, u_char dev_fn,
|
||||||
|
u_char where, u_int * val) {
|
||||||
|
return bd->pci_functions->read_config_dword(bus, dev_fn, where, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern inline int
|
||||||
|
pcibios_write_config_byte(u_char bus, u_char dev_fn,
|
||||||
|
u_char where, u_char val) {
|
||||||
|
return bd->pci_functions->write_config_byte(bus, dev_fn, where, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern inline int
|
||||||
|
pcibios_write_config_word(u_char bus, u_char dev_fn,
|
||||||
|
u_char where, u_short val) {
|
||||||
|
return bd->pci_functions->write_config_word(bus, dev_fn, where, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern inline int
|
||||||
|
pcibios_write_config_dword(u_char bus, u_char dev_fn,
|
||||||
|
u_char where, u_int val) {
|
||||||
|
return bd->pci_functions->write_config_dword(bus, dev_fn, where, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern inline int
|
||||||
|
pci_read_config_byte(struct pci_dev *dev, u_char where, u_char * val) {
|
||||||
|
return bd->pci_functions->read_config_byte(dev->bus->number,
|
||||||
|
dev->devfn,
|
||||||
|
where, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern inline int
|
||||||
|
pci_read_config_word(struct pci_dev *dev, u_char where, u_short * val) {
|
||||||
|
return bd->pci_functions->read_config_word(dev->bus->number,
|
||||||
|
dev->devfn,
|
||||||
|
where, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern inline int
|
||||||
|
pci_read_config_dword(struct pci_dev *dev, u_char where, u_int * val) {
|
||||||
|
return bd->pci_functions->read_config_dword(dev->bus->number,
|
||||||
|
dev->devfn,
|
||||||
|
where, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern inline int
|
||||||
|
pci_write_config_byte(struct pci_dev *dev, u_char where, u_char val) {
|
||||||
|
return bd->pci_functions->write_config_byte(dev->bus->number,
|
||||||
|
dev->devfn,
|
||||||
|
where, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern inline int
|
||||||
|
pci_write_config_word(struct pci_dev *dev, u_char where, u_short val) {
|
||||||
|
return bd->pci_functions->write_config_word(dev->bus->number,
|
||||||
|
dev->devfn,
|
||||||
|
where, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern inline int
|
||||||
|
pci_write_config_dword(struct pci_dev *dev, u_char where, u_int val) {
|
||||||
|
return bd->pci_functions->write_config_dword(dev->bus->number,
|
||||||
|
dev->devfn,
|
||||||
|
where, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* codemove is like memmove, but it also gets the cache line size
|
||||||
|
* as 4th parameter to synchronize them. If this last parameter is
|
||||||
|
* zero, it performs more or less like memmove. No copy is performed if
|
||||||
|
* source and destination addresses are equal. However the caches
|
||||||
|
* are synchronized. Note that the size is always rounded up to the
|
||||||
|
* next mutiple of 4.
|
||||||
|
*/
|
||||||
|
extern void * codemove(void *, const void *, size_t, unsigned long);
|
||||||
|
|
||||||
|
/* The physical memory allocator allows to align memory by
|
||||||
|
* powers of 2 given by the lower order bits of flags.
|
||||||
|
* By default it allocates from higher addresses towrds lower ones,
|
||||||
|
* setting PA_LOW reverses this behaviour.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define palloc(size) __palloc(size,0)
|
||||||
|
|
||||||
|
#define isa_io_base (bd->io_base)
|
||||||
|
|
||||||
|
|
||||||
|
void * __palloc(u_long, int);
|
||||||
|
void pfree(void *);
|
||||||
|
|
||||||
|
#define PA_LOW 0x100
|
||||||
|
#define PA_PERM 0x200 /* Not freeable by pfree */
|
||||||
|
#define PA_SUBALLOC 0x400 /* Allocate for suballocation by salloc */
|
||||||
|
#define PA_ALIGN_MASK 0x1f
|
||||||
|
|
||||||
|
void * valloc(u_long size);
|
||||||
|
void vfree(void *);
|
||||||
|
|
||||||
|
int vmap(void *, u_long, u_long);
|
||||||
|
void vunmap(void *);
|
||||||
|
|
||||||
|
void * salloc(u_long size);
|
||||||
|
void sfree(void *);
|
||||||
|
|
||||||
|
void pci_init(void);
|
||||||
|
|
||||||
|
void * memset(void *p, int c, size_t n);
|
||||||
|
|
||||||
|
void gunzip(void *, int, unsigned char *, int *);
|
||||||
|
|
||||||
|
void print_all_maps(const char *);
|
||||||
|
void print_hash_table(void);
|
||||||
|
void MMUon(void);
|
||||||
|
void MMUoff(void);
|
||||||
|
void hang(const char *, u_long, ctxt *) __attribute__((noreturn));
|
||||||
|
|
||||||
|
int init_v86(void);
|
||||||
|
void cleanup_v86_mess(void);
|
||||||
|
void em86_main(struct pci_dev *);
|
||||||
|
int find_max_mem(struct pci_dev *);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ASM
|
||||||
|
/* These definitions simplify the ugly declarations necessary for
|
||||||
|
* GOT definitions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define GOT_ENTRY(NAME) .L_ ## NAME = . - .LCTOC1 ; .long NAME
|
||||||
|
#define GOT(NAME) .L_ ## NAME (r30)
|
||||||
|
|
||||||
|
#define START_GOT \
|
||||||
|
.section ".got2","aw"; \
|
||||||
|
.LCTOC1 = .+ 0x8000
|
||||||
|
|
||||||
|
#define END_GOT \
|
||||||
|
.text
|
||||||
|
|
||||||
|
#define GET_GOT \
|
||||||
|
bl 1f; \
|
||||||
|
.text 2; \
|
||||||
|
0: .long .LCTOC1-1f; \
|
||||||
|
.text ; \
|
||||||
|
1: mflr r30; \
|
||||||
|
lwz r0,0b-1b(r30); \
|
||||||
|
add r30,r0,r30
|
||||||
|
|
||||||
|
#define bd r13
|
||||||
|
#define cache_lsize 32 /* Offset into bd area */
|
||||||
|
#define image 36
|
||||||
|
#define stack 40
|
||||||
|
#define mover 44
|
||||||
|
#define o_msr 48
|
||||||
|
#define o_hid0 52
|
||||||
|
#define o_r31 56
|
||||||
|
/* Stack offsets for saved registers on exceptions */
|
||||||
|
#define save_lr 8(r1)
|
||||||
|
#define save_ctr 12(r1)
|
||||||
|
#define save_cr 16(r1)
|
||||||
|
#define save_xer 20(r1)
|
||||||
|
#define save_nip 24(r1)
|
||||||
|
#define save_msr 28(r1)
|
||||||
|
#define save_r(n) 32+4*n(r1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
580
c/src/lib/libbsp/powerpc/shared/bootloader/em86.c
Normal file
580
c/src/lib/libbsp/powerpc/shared/bootloader/em86.c
Normal file
@@ -0,0 +1,580 @@
|
|||||||
|
/*
|
||||||
|
* em86.c -- Include file for bootloader.
|
||||||
|
*
|
||||||
|
* Copyright (C) 1998, 1999 Gabriel Paubert, paubert@iram.es
|
||||||
|
*
|
||||||
|
* Modified to compile in RTEMS development environment
|
||||||
|
* by Eric Valette
|
||||||
|
*
|
||||||
|
* Copyright (C) 1999 Eric Valette. valette@crf.canon.fr
|
||||||
|
*
|
||||||
|
* The license and distribution terms for this file may be
|
||||||
|
* found in found in the file LICENSE in this distribution or at
|
||||||
|
* http://www.OARcorp.com/rtems/license.html.
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
*
|
||||||
|
* Code to interpret Video BIOS ROM routines.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/* These include are for the development version only */
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include "pci.h"
|
||||||
|
#include <libcpu/byteorder.h>
|
||||||
|
#ifdef __BOOT__
|
||||||
|
#include "bootldr.h"
|
||||||
|
#include <limits.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Code options, put them on the compiler command line */
|
||||||
|
/* #define EIP_STATS */ /* EIP based profiling */
|
||||||
|
/* #undef EIP_STATS */
|
||||||
|
|
||||||
|
typedef union _reg_type1 {
|
||||||
|
unsigned e;
|
||||||
|
unsigned short x;
|
||||||
|
struct {
|
||||||
|
unsigned char l, h;
|
||||||
|
} lh;
|
||||||
|
} reg_type1;
|
||||||
|
|
||||||
|
typedef union _reg_type2 {
|
||||||
|
unsigned e;
|
||||||
|
unsigned short x;
|
||||||
|
} reg_type2;
|
||||||
|
|
||||||
|
typedef struct _x86 {
|
||||||
|
reg_type1
|
||||||
|
_eax, _ecx, _edx, _ebx;
|
||||||
|
reg_type2
|
||||||
|
_esp, _ebp, _esi, _edi;
|
||||||
|
unsigned
|
||||||
|
es, cs, ss, ds, fs, gs, eip, eflags;
|
||||||
|
unsigned char
|
||||||
|
*esbase, *csbase, *ssbase, *dsbase, *fsbase, *gsbase;
|
||||||
|
volatile unsigned char *iobase;
|
||||||
|
unsigned char *ioperm;
|
||||||
|
unsigned
|
||||||
|
reason, nexteip, parm1, parm2, opcode, base;
|
||||||
|
unsigned *optable, opreg; /* no more used! */
|
||||||
|
unsigned char* vbase;
|
||||||
|
unsigned instructions;
|
||||||
|
#ifdef __BOOT__
|
||||||
|
u_char * ram;
|
||||||
|
u_char * rom;
|
||||||
|
struct pci_dev * dev;
|
||||||
|
#else
|
||||||
|
unsigned filler[14]; /* Skip to next 64 byte boundary */
|
||||||
|
unsigned eipstats[32768][2];
|
||||||
|
#endif
|
||||||
|
} x86;
|
||||||
|
|
||||||
|
x86 v86_private __attribute__((aligned(32)));
|
||||||
|
|
||||||
|
|
||||||
|
/* Emulator is in another source file */
|
||||||
|
extern
|
||||||
|
void em86_enter(x86 * p);
|
||||||
|
|
||||||
|
#define EAX (p->_eax.e)
|
||||||
|
#define ECX (p->_ecx.e)
|
||||||
|
#define EDX (p->_edx.e)
|
||||||
|
#define EBX (p->_ebx.e)
|
||||||
|
#define ESP (p->_esp.e)
|
||||||
|
#define EBP (p->_ebp.e)
|
||||||
|
#define ESI (p->_esi.e)
|
||||||
|
#define EDI (p->_edi.e)
|
||||||
|
#define AX (p->_eax.x)
|
||||||
|
#define CX (p->_ecx.x)
|
||||||
|
#define DX (p->_edx.x)
|
||||||
|
#define BX (p->_ebx.x)
|
||||||
|
#define SP (p->_esp.x)
|
||||||
|
#define BP (p->_ebp.x)
|
||||||
|
#define SI (p->_esi.x)
|
||||||
|
#define DI (p->_edi.x)
|
||||||
|
#define AL (p->_eax.lh.l)
|
||||||
|
#define CL (p->_ecx.lh.l)
|
||||||
|
#define DL (p->_edx.lh.l)
|
||||||
|
#define BL (p->_ebx.lh.l)
|
||||||
|
#define AH (p->_eax.lh.h)
|
||||||
|
#define CH (p->_ecx.lh.h)
|
||||||
|
#define DH (p->_edx.lh.h)
|
||||||
|
#define BH (p->_ebx.lh.h)
|
||||||
|
|
||||||
|
/* Function used to debug */
|
||||||
|
#ifdef __BOOT__
|
||||||
|
#define printf printk
|
||||||
|
#endif
|
||||||
|
#ifdef DEBUG
|
||||||
|
static void dump86(x86 * p){
|
||||||
|
unsigned char *s = p->csbase + p->eip;
|
||||||
|
printf("cs:eip=%04x:%08x, eax=%08x, ecx=%08x, edx=%08x, ebx=%08x\n",
|
||||||
|
p->cs, p->eip, ld_le32(&EAX),
|
||||||
|
ld_le32(&ECX), ld_le32(&EDX), ld_le32(&EBX));
|
||||||
|
printf("ss:esp=%04x:%08x, ebp=%08x, esi=%08x, edi=%08x, efl=%08x\n",
|
||||||
|
p->ss, ld_le32(&ESP), ld_le32(&EBP),
|
||||||
|
ld_le32(&ESI), ld_le32(&EDI), p->eflags);
|
||||||
|
printf("nip=%08x, ds=%04x, es=%04x, fs=%04x, gs=%04x, total=%d\n",
|
||||||
|
p->nexteip, p->ds, p->es, p->fs, p->gs, p->instructions);
|
||||||
|
printf("code: %02x %02x %02x %02x %02x %02x "
|
||||||
|
"%02x %02x %02x %02x %02x %02x\n",
|
||||||
|
s[0], s[1], s[2], s[3], s[4], s[5],
|
||||||
|
s[6], s[7], s[8], s[9], s[10], s[11]);
|
||||||
|
#ifndef __BOOT__
|
||||||
|
printf("op1=%08x, op2=%08x, result=%08x, flags=%08x\n",
|
||||||
|
p->filler[11], p->filler[12], p->filler[13], p->filler[14]);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define dump86(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int bios86pci(x86 * p) {
|
||||||
|
unsigned reg=ld_le16(&DI);
|
||||||
|
reg_type2 tmp;
|
||||||
|
|
||||||
|
if (AL>=8 && AL<=13 && reg>0xff) {
|
||||||
|
AH = PCIBIOS_BAD_REGISTER_NUMBER;
|
||||||
|
} else {
|
||||||
|
switch(AL) {
|
||||||
|
case 2: /* find_device */
|
||||||
|
/* Should be improved for BIOS able to handle
|
||||||
|
* multiple devices. We simply suppose the BIOS
|
||||||
|
* inits a single device, and return an error
|
||||||
|
* if it tries to find more...
|
||||||
|
*/
|
||||||
|
if (SI) {
|
||||||
|
AH=PCIBIOS_DEVICE_NOT_FOUND;
|
||||||
|
} else {
|
||||||
|
BH = p->dev->bus->number;
|
||||||
|
BL = p->dev->devfn;
|
||||||
|
AH = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
/*
|
||||||
|
case 3: find_class not implemented for now.
|
||||||
|
*/
|
||||||
|
case 8: /* read_config_byte */
|
||||||
|
AH=pcibios_read_config_byte(BH, BL, reg, &CL);
|
||||||
|
break;
|
||||||
|
case 9: /* read_config_word */
|
||||||
|
AH=pcibios_read_config_word(BH, BL, reg, &tmp.x);
|
||||||
|
CX=ld_le16(&tmp.x);
|
||||||
|
break;
|
||||||
|
case 10: /* read_config_dword */
|
||||||
|
AH=pcibios_read_config_dword(BH, BL, reg, &tmp.e);
|
||||||
|
ECX=ld_le32(&tmp.e);
|
||||||
|
break;
|
||||||
|
case 11: /* write_config_byte */
|
||||||
|
AH=pcibios_write_config_byte(BH, BL, reg, CL);
|
||||||
|
break;
|
||||||
|
case 12: /* write_config_word */
|
||||||
|
AH=pcibios_write_config_word(BH, BL, reg, ld_le16(&CX));
|
||||||
|
break;
|
||||||
|
case 13: /* write_config_dword */
|
||||||
|
AH=pcibios_write_config_dword(BH, BL, reg, ld_le32(&ECX));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("Unimplemented or illegal PCI service call #%d!\n",
|
||||||
|
AL);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p->eip = p->nexteip;
|
||||||
|
/* Set/clear carry according to result */
|
||||||
|
if (AH) p->eflags |= 1; else p->eflags &=~1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void push2(x86 *p, unsigned value) {
|
||||||
|
unsigned char * sbase= p->ssbase;
|
||||||
|
unsigned newsp = (ld_le16(&SP)-2)&0xffff;
|
||||||
|
st_le16(&SP,newsp);
|
||||||
|
st_le16((unsigned short *)(sbase+newsp), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned pop2(x86 *p) {
|
||||||
|
unsigned char * sbase=p->ssbase;
|
||||||
|
unsigned oldsp = ld_le16(&SP);
|
||||||
|
st_le16(&SP,oldsp+2);
|
||||||
|
return ld_le16((unsigned short *)(sbase+oldsp));
|
||||||
|
}
|
||||||
|
|
||||||
|
int int10h(x86 * p) { /* Process BIOS video interrupt */
|
||||||
|
unsigned vector;
|
||||||
|
vector=ld_le32((unsigned *)p->vbase+0x10);
|
||||||
|
if (((vector&0xffff0000)>>16)==0xc000) {
|
||||||
|
push2(p, p->eflags);
|
||||||
|
push2(p, p->cs);
|
||||||
|
push2(p, p->nexteip);
|
||||||
|
p->cs=vector>>16;
|
||||||
|
p->csbase=p->vbase + (p->cs<<4);
|
||||||
|
p->eip=vector&0xffff;
|
||||||
|
#if 1
|
||||||
|
p->eflags&=0xfcff; /* Clear AC/TF/IF */
|
||||||
|
#else
|
||||||
|
p->eflags = (p->eflags&0xfcff)|0x100; /* Set TF for debugging */
|
||||||
|
#endif
|
||||||
|
/* p->eflags|=0x100; uncomment to force a trap */
|
||||||
|
return(0);
|
||||||
|
} else {
|
||||||
|
switch(AH) {
|
||||||
|
case 0x12:
|
||||||
|
switch(BL){
|
||||||
|
case 0x32:
|
||||||
|
p->eip=p->nexteip;
|
||||||
|
return(0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
printf("unhandled soft interrupt 0x10: vector=%x\n", vector);
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int process_softint(x86 * p) {
|
||||||
|
#if 0
|
||||||
|
if (p->parm1!=0x10 || AH!=0x0e) {
|
||||||
|
printf("Soft interrupt\n");
|
||||||
|
dump86(p);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
switch(p->parm1) {
|
||||||
|
case 0x10: /* BIOS video interrupt */
|
||||||
|
return int10h(p);
|
||||||
|
case 0x1a:
|
||||||
|
if(AH==0xb1) return bios86pci(p);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
dump86(p);
|
||||||
|
printf("Unhandled soft interrupt number 0x%04x, AX=0x%04x\n",
|
||||||
|
p->parm1, ld_le16(&AX));
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The only function called back by the emulator is em86_trap, all
|
||||||
|
instructions may that change the code segment are trapped here.
|
||||||
|
p->reason is one of the following codes. */
|
||||||
|
#define code_zerdiv 0
|
||||||
|
#define code_trap 1
|
||||||
|
#define code_int3 3
|
||||||
|
#define code_into 4
|
||||||
|
#define code_bound 5
|
||||||
|
#define code_ud 6
|
||||||
|
#define code_dna 7
|
||||||
|
|
||||||
|
#define code_iretw 256
|
||||||
|
#define code_iretl 257
|
||||||
|
#define code_lcallw 258
|
||||||
|
#define code_lcalll 259
|
||||||
|
#define code_ljmpw 260
|
||||||
|
#define code_ljmpl 261
|
||||||
|
#define code_lretw 262
|
||||||
|
#define code_lretl 263
|
||||||
|
#define code_softint 264
|
||||||
|
#define code_lock 265 /* Lock prefix */
|
||||||
|
/* Codes 1024 to 2047 are used for I/O port access instructions:
|
||||||
|
- The three LSB define the port size (1, 2 or 4)
|
||||||
|
- bit of weight 512 means out if set, in if clear
|
||||||
|
- bit of weight 256 means ins/outs if set, in/out if clear
|
||||||
|
- bit of weight 128 means use esi/edi if set, si/di if clear
|
||||||
|
(only used for ins/outs instructions, always clear for in/out)
|
||||||
|
*/
|
||||||
|
#define code_inb 1024+1
|
||||||
|
#define code_inw 1024+2
|
||||||
|
#define code_inl 1024+4
|
||||||
|
#define code_outb 1024+512+1
|
||||||
|
#define code_outw 1024+512+2
|
||||||
|
#define code_outl 1024+512+4
|
||||||
|
#define code_insb_a16 1024+256+1
|
||||||
|
#define code_insw_a16 1024+256+2
|
||||||
|
#define code_insl_a16 1024+256+4
|
||||||
|
#define code_outsb_a16 1024+512+256+1
|
||||||
|
#define code_outsw_a16 1024+512+256+2
|
||||||
|
#define code_outsl_a16 1024+512+256+4
|
||||||
|
#define code_insb_a32 1024+256+128+1
|
||||||
|
#define code_insw_a32 1024+256+128+2
|
||||||
|
#define code_insl_a32 1024+256+128+4
|
||||||
|
#define code_outsb_a32 1024+512+256+128+1
|
||||||
|
#define code_outsw_a32 1024+512+256+128+2
|
||||||
|
#define code_outsl_a32 1024+512+256+128+4
|
||||||
|
|
||||||
|
int em86_trap(x86 *p) {
|
||||||
|
#ifndef __BOOT__
|
||||||
|
int i;
|
||||||
|
unsigned char command[80];
|
||||||
|
unsigned char *verb, *t;
|
||||||
|
unsigned short *fp;
|
||||||
|
static unsigned char def=0;
|
||||||
|
static unsigned char * bptaddr=NULL; /* Breakpoint address */
|
||||||
|
static unsigned char bptopc; /* Replaced breakpoint opcode */
|
||||||
|
unsigned char cmd;
|
||||||
|
unsigned tmp;
|
||||||
|
#endif
|
||||||
|
switch(p->reason) {
|
||||||
|
case code_int3:
|
||||||
|
#ifndef __BOOT__
|
||||||
|
if(p->csbase+p->eip == bptaddr) {
|
||||||
|
*bptaddr=bptopc;
|
||||||
|
bptaddr=NULL;
|
||||||
|
}
|
||||||
|
else printf("Unexpected ");
|
||||||
|
#endif
|
||||||
|
printf("Breakpoint Interrupt !\n");
|
||||||
|
/* Note that this fallthrough (no break;) is on purpose */
|
||||||
|
#ifdef __BOOT__
|
||||||
|
return 0;
|
||||||
|
#else
|
||||||
|
case code_trap:
|
||||||
|
dump86(p);
|
||||||
|
for(;;) {
|
||||||
|
printf("b(reakpoint, g(o, q(uit, s(tack, t(race ? [%c] ", def);
|
||||||
|
fgets(command,sizeof(command),stdin);
|
||||||
|
verb = strtok(command," \n");
|
||||||
|
if(verb) cmd=*verb; else cmd=def;
|
||||||
|
def=0;
|
||||||
|
switch(cmd) {
|
||||||
|
case 'b':
|
||||||
|
case 'B':
|
||||||
|
if(bptaddr) *bptaddr=bptopc;
|
||||||
|
t=strtok(0," \n");
|
||||||
|
i=sscanf(t,"%x",&tmp);
|
||||||
|
if(i==1) {
|
||||||
|
bptaddr=p->vbase + tmp;
|
||||||
|
bptopc=*bptaddr;
|
||||||
|
*bptaddr=0xcc;
|
||||||
|
} else bptaddr=NULL;
|
||||||
|
break;
|
||||||
|
case 'q':
|
||||||
|
case 'Q':
|
||||||
|
return 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'g':
|
||||||
|
case 'G':
|
||||||
|
p->eflags &= ~0x100;
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 's':
|
||||||
|
case 'S': /* Print the 8 stack top words */
|
||||||
|
fp = (unsigned short *)(p->ssbase+ld_le16(&SP));
|
||||||
|
printf("Stack [%04x:%04x]: %04x %04x %04x %04x %04x %04x %04x %04x\n",
|
||||||
|
p->ss, ld_le16(&SP),
|
||||||
|
ld_le16(fp+0), ld_le16(fp+1), ld_le16(fp+2), ld_le16(fp+3),
|
||||||
|
ld_le16(fp+4), ld_le16(fp+5), ld_le16(fp+6), ld_le16(fp+7));
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
case 'T':
|
||||||
|
p->eflags |= 0x10100; /* Set the resume and trap flags */
|
||||||
|
def='t';
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
/* Should add some code to edit registers */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case code_ud:
|
||||||
|
printf("Attempt to execute an unimplemented"
|
||||||
|
"or undefined opcode!\n");
|
||||||
|
dump86(p);
|
||||||
|
return(1); /* exit interpreter */
|
||||||
|
break;
|
||||||
|
case code_dna:
|
||||||
|
printf("Attempt to execute a floating point instruction!\n");
|
||||||
|
dump86(p);
|
||||||
|
return(1);
|
||||||
|
break;
|
||||||
|
case code_softint:
|
||||||
|
return process_softint(p);
|
||||||
|
break;
|
||||||
|
case code_iretw:
|
||||||
|
p->eip=pop2(p);
|
||||||
|
p->cs=pop2(p);
|
||||||
|
p->csbase=p->vbase + (p->cs<<4);
|
||||||
|
p->eflags= (p->eflags&0xfffe0000)|pop2(p);
|
||||||
|
/* p->eflags|= 0x100; */ /* Uncomment to trap after iretws */
|
||||||
|
return(0);
|
||||||
|
break;
|
||||||
|
#ifndef __BOOT__
|
||||||
|
case code_inb:
|
||||||
|
case code_inw:
|
||||||
|
case code_inl:
|
||||||
|
case code_insb_a16:
|
||||||
|
case code_insw_a16:
|
||||||
|
case code_insl_a16:
|
||||||
|
case code_insb_a32:
|
||||||
|
case code_insw_a32:
|
||||||
|
case code_insl_a32:
|
||||||
|
case code_outb:
|
||||||
|
case code_outw:
|
||||||
|
case code_outl:
|
||||||
|
case code_outsb_a16:
|
||||||
|
case code_outsw_a16:
|
||||||
|
case code_outsl_a16:
|
||||||
|
case code_outsb_a32:
|
||||||
|
case code_outsw_a32:
|
||||||
|
case code_outsl_a32:
|
||||||
|
/* For now we simply enable I/O to the ports and continue */
|
||||||
|
for(i=p->parm1; i<p->parm1+(p->reason&7); i++) {
|
||||||
|
p->ioperm[i/8] &= ~(1<<i%8);
|
||||||
|
}
|
||||||
|
printf("Access to ports %04x-%04x enabled.\n",
|
||||||
|
p->parm1, p->parm1+(p->reason&7)-1);
|
||||||
|
return(0);
|
||||||
|
#endif
|
||||||
|
case code_lretw:
|
||||||
|
/* Check for the exit eyecatcher */
|
||||||
|
if ( *(u_int *)(p->ssbase+ld_le16(&SP)) == UINT_MAX) return 1;
|
||||||
|
/* No break on purpose */
|
||||||
|
default:
|
||||||
|
dump86(p);
|
||||||
|
printf("em86_trap called with unhandled reason code !\n");
|
||||||
|
return(1);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cleanup_v86_mess(void) {
|
||||||
|
x86 *p = (x86 *) bd->v86_private;
|
||||||
|
|
||||||
|
/* This automatically removes the mappings ! */
|
||||||
|
vfree(p->vbase);
|
||||||
|
p->vbase = 0;
|
||||||
|
pfree(p->ram);
|
||||||
|
p->ram = 0;
|
||||||
|
sfree(p->ioperm);
|
||||||
|
p->ioperm=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int init_v86(void) {
|
||||||
|
x86 *p = (x86 *) bd->v86_private;
|
||||||
|
|
||||||
|
/* p->vbase is non null when the v86 is properly set-up */
|
||||||
|
if (p->vbase) return 0;
|
||||||
|
|
||||||
|
/* Set everything to 0 */
|
||||||
|
memset(p, 0, sizeof(*p));
|
||||||
|
p->ioperm = salloc(65536/8+1);
|
||||||
|
p->ram = palloc(0xa0000);
|
||||||
|
p->iobase = ptr_mem_map->io_base;
|
||||||
|
|
||||||
|
if (!p->ram || !p->ioperm) return 1;
|
||||||
|
|
||||||
|
/* The ioperm array must have an additional byte at the end ! */
|
||||||
|
p->ioperm[65536/8] = 0xff;
|
||||||
|
|
||||||
|
p->vbase = valloc(0x110000);
|
||||||
|
if (!p->vbase) return 1;
|
||||||
|
|
||||||
|
/* These calls should never fail. */
|
||||||
|
vmap(p->vbase, (u_long)p->ram|PTE_RAM, 0xa0000);
|
||||||
|
vmap(p->vbase+0x100000, (u_long)p->ram|PTE_RAM, 0x10000);
|
||||||
|
vmap(p->vbase+0xa0000,
|
||||||
|
((u_long)ptr_mem_map->isa_mem_base+0xa0000)|PTE_IO, 0x20000);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void em86_main(struct pci_dev *dev){
|
||||||
|
x86 *p = (x86 *) bd->v86_private;
|
||||||
|
u_short signature;
|
||||||
|
u_char length;
|
||||||
|
volatile u_int *src;
|
||||||
|
u_int *dst, left, saved_rom;
|
||||||
|
#if defined(MONITOR_IO) && !defined(__BOOT__)
|
||||||
|
#define IOMASK 0xff
|
||||||
|
#else
|
||||||
|
#define IOMASK 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __BOOT__
|
||||||
|
int i;
|
||||||
|
/* Allow or disable access to all ports */
|
||||||
|
for(i=0; i<65536/8; i++) p->ioperm[i]=IOMASK;
|
||||||
|
p->ioperm[i] = 0xff; /* Last unused byte must have this value */
|
||||||
|
#endif
|
||||||
|
p->dev = dev;
|
||||||
|
memset(p->vbase, 0, 0xa0000);
|
||||||
|
/* Set up a few registers */
|
||||||
|
p->cs = 0xc000; p->csbase = p->vbase + 0xc0000;
|
||||||
|
p->ss = 0x1000; p->ssbase = p->vbase + 0x10000;
|
||||||
|
p->eflags=0x200;
|
||||||
|
st_le16(&SP,0xfffc); p->eip=3;
|
||||||
|
|
||||||
|
p->dsbase = p->esbase = p->fsbase = p->gsbase = p->vbase;
|
||||||
|
|
||||||
|
/* Follow the PCI BIOS specification */
|
||||||
|
AH=dev->bus->number;
|
||||||
|
AL=dev->devfn;
|
||||||
|
|
||||||
|
/* All other registers are irrelevant except ES:DI which
|
||||||
|
* should point to a PnP installation check block. This
|
||||||
|
* is not yet implemented due to lack of references. */
|
||||||
|
|
||||||
|
/* Store a return address of 0xffff:0xffff as eyecatcher */
|
||||||
|
*(u_int *)(p->ssbase+ld_le16(&SP)) = UINT_MAX;
|
||||||
|
|
||||||
|
/* Interrupt for BIOS EGA services is 0xf000:0xf065 (int 0x10) */
|
||||||
|
st_le32((u_int *)p->vbase + 0x10, 0xf000f065);
|
||||||
|
|
||||||
|
/* Enable the ROM, read it and disable it immediately */
|
||||||
|
pci_read_config_dword(dev, PCI_ROM_ADDRESS, &saved_rom);
|
||||||
|
pci_write_config_dword(dev, PCI_ROM_ADDRESS, 0x000c0001);
|
||||||
|
|
||||||
|
/* Check that there is an Intel ROM. Should we also check that
|
||||||
|
* the first instruction is a jump (0xe9 or 0xeb) ?
|
||||||
|
*/
|
||||||
|
signature = *(u_short *)(ptr_mem_map->isa_mem_base+0xc0000);
|
||||||
|
if (signature!=0x55aa) {
|
||||||
|
printf("bad signature: %04x.\n", signature);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* Allocate memory and copy the video rom to vbase+0xc0000; */
|
||||||
|
length = ptr_mem_map->isa_mem_base[0xc0002];
|
||||||
|
p->rom = palloc(length*512);
|
||||||
|
if (!p->rom) return;
|
||||||
|
|
||||||
|
|
||||||
|
for(dst=(u_int *) p->rom,
|
||||||
|
src=(volatile u_int *)(ptr_mem_map->isa_mem_base+0xc0000),
|
||||||
|
left = length*512/sizeof(u_int);
|
||||||
|
left--;
|
||||||
|
*dst++=*src++);
|
||||||
|
|
||||||
|
/* Disable the ROM and map the copy in virtual address space, note
|
||||||
|
* that the ROM has to be mapped as RAM since some BIOSes (at least
|
||||||
|
* Cirrus) perform write accesses to their own ROM. The reason seems
|
||||||
|
* to be that they check that they must execute from shadow RAM
|
||||||
|
* because accessing the ROM prevents accessing the video RAM
|
||||||
|
* according to comments in linux/arch/alpha/kernel/bios32.c.
|
||||||
|
*/
|
||||||
|
|
||||||
|
pci_write_config_dword(dev, PCI_ROM_ADDRESS, saved_rom);
|
||||||
|
vmap(p->vbase+0xc0000, (u_long)p->rom|PTE_RAM, length*512);
|
||||||
|
|
||||||
|
/* Now actually emulate the ROM init routine */
|
||||||
|
em86_enter(p);
|
||||||
|
|
||||||
|
/* Free the acquired resources */
|
||||||
|
vunmap(p->vbase+0xc0000);
|
||||||
|
pfree(p->rom);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
4561
c/src/lib/libbsp/powerpc/shared/bootloader/em86real.S
Normal file
4561
c/src/lib/libbsp/powerpc/shared/bootloader/em86real.S
Normal file
File diff suppressed because it is too large
Load Diff
473
c/src/lib/libbsp/powerpc/shared/bootloader/exception.S
Normal file
473
c/src/lib/libbsp/powerpc/shared/bootloader/exception.S
Normal file
@@ -0,0 +1,473 @@
|
|||||||
|
/*
|
||||||
|
* exception.S -- Exception handlers for early boot.
|
||||||
|
*
|
||||||
|
* Copyright (C) 1998, 1999 Gabriel Paubert, paubert@iram.es
|
||||||
|
*
|
||||||
|
* Modified to compile in RTEMS development environment
|
||||||
|
* by Eric Valette
|
||||||
|
*
|
||||||
|
* Copyright (C) 1999 Eric Valette. valette@crf.canon.fr
|
||||||
|
*
|
||||||
|
* The license and distribution terms for this file may be
|
||||||
|
* found in found in the file LICENSE in this distribution or at
|
||||||
|
* http://www.OARcorp.com/rtems/license.html.
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* This is an improved version of the TLB interrupt handling code from
|
||||||
|
* the 603e users manual (603eUM.pdf) downloaded from the WWW. All the
|
||||||
|
* visible bugs have been removed. Note that many have survived in the errata
|
||||||
|
* to the 603 user manual (603UMer.pdf).
|
||||||
|
*
|
||||||
|
* This code also pays particular attention to optimization, takes into
|
||||||
|
* account the differences between 603 and 603e, single/multiple processor
|
||||||
|
* systems and tries to order instructions for dual dispatch in many places.
|
||||||
|
*
|
||||||
|
* The optimization has been performed along two lines:
|
||||||
|
* 1) to minimize the number of instruction cache lines needed for the most
|
||||||
|
* common execution paths (the ones that do not result in an exception).
|
||||||
|
* 2) then to order the code to maximize the number of dual issue and
|
||||||
|
* completion opportunities without increasing the number of cache lines
|
||||||
|
* used in the same cases.
|
||||||
|
*
|
||||||
|
* The last goal of this code is to fit inside the address range
|
||||||
|
* assigned to the interrupt vectors: 192 instructions with fixed
|
||||||
|
* entry points every 64 instructions.
|
||||||
|
*
|
||||||
|
* Some typos have also been corrected and the Power l (lowercase L)
|
||||||
|
* instructions replaced by lwz without comment.
|
||||||
|
*
|
||||||
|
* I have attempted to describe the reasons of the order and of the choice
|
||||||
|
* of the instructions but the comments may be hard to understand without
|
||||||
|
* the processor manual.
|
||||||
|
*
|
||||||
|
* Note that the fact that the TLB are reloaded by software in theory
|
||||||
|
* allows tremendous flexibility, for example we could avoid setting the
|
||||||
|
* reference bit of the PTE which will could actually not be accessed because
|
||||||
|
* of protection violation by changing a few lines of code. However,
|
||||||
|
* this would significantly slow down most TLB reload operations, and
|
||||||
|
* this is the reason for which we try never to make checks which would be
|
||||||
|
* redundant with hardware and usually indicate a bug in a program.
|
||||||
|
*
|
||||||
|
* There are some inconsistencies in the documentation concerning the
|
||||||
|
* settings of SRR1 bit 15. All recent documentations say now that it is set
|
||||||
|
* for stores and cleared for loads. Anyway this handler never uses this bit.
|
||||||
|
*
|
||||||
|
* A final remark, the rfi instruction seems to implicitly clear the
|
||||||
|
* MSR<14> (tgpr)bit. The documentation claims that this bit is restored
|
||||||
|
* from SRR1 by rfi, but the corresponding bit in SRR1 is the LRU way bit.
|
||||||
|
* Anyway, the only exception which can occur while TGPR is set is a machine
|
||||||
|
* check which would indicate an unrecoverable problem. Recent documentation
|
||||||
|
* now says in some place that rfi clears MSR<14>.
|
||||||
|
*
|
||||||
|
* TLB software load for 602/603/603e/603ev:
|
||||||
|
* Specific Instructions:
|
||||||
|
* tlbld - write the dtlb with the pte in rpa reg
|
||||||
|
* tlbli - write the itlb with the pte in rpa reg
|
||||||
|
* Specific SPRs:
|
||||||
|
* dmiss - address of dstream miss
|
||||||
|
* imiss - address of istream miss
|
||||||
|
* hash1 - address primary hash PTEG address
|
||||||
|
* hash2 - returns secondary hash PTEG address
|
||||||
|
* iCmp - returns the primary istream compare value
|
||||||
|
* dCmp - returns the primary dstream compare value
|
||||||
|
* rpa - the second word of pte used by tlblx
|
||||||
|
* Other specific resources:
|
||||||
|
* cr0 saved in 4 high order bits of SRR1,
|
||||||
|
* SRR1 bit 14 [WAY] selects TLB set to load from LRU algorithm
|
||||||
|
* gprs r0..r3 shadowed by the setting of MSR bit 14 [TGPR]
|
||||||
|
* other bits in SRR1 (unused by this handler but see earlier comments)
|
||||||
|
*
|
||||||
|
* There are three basic flows corresponding to three vectors:
|
||||||
|
* 0x1000: Instruction TLB miss,
|
||||||
|
* 0x1100: Data TLB miss on load,
|
||||||
|
* 0x1200: Data TLB miss on store or not dirty page
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* define the following if code does not have to run on basic 603 */
|
||||||
|
/* #define USE_KEY_BIT */
|
||||||
|
|
||||||
|
/* define the following for safe multiprocessing */
|
||||||
|
/* #define MULTIPROCESSING */
|
||||||
|
|
||||||
|
/* define the following for mixed endian */
|
||||||
|
/* #define CHECK_MIXED_ENDIAN */
|
||||||
|
|
||||||
|
/* define the following if entries always have the reference bit set */
|
||||||
|
#define ASSUME_REF_SET
|
||||||
|
|
||||||
|
/* Some OS kernels may want to keep a single copy of the dirty bit in a per
|
||||||
|
* page table. In this case writable pages are always write-protected as long
|
||||||
|
* as they are clean, and the dirty bit set actually means that the page
|
||||||
|
* is writable.
|
||||||
|
*/
|
||||||
|
#define DIRTY_MEANS_WRITABLE
|
||||||
|
|
||||||
|
#include <libcpu/cpu.h>
|
||||||
|
#include "asm.h"
|
||||||
|
#include "bootldr.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Instruction TLB miss flow
|
||||||
|
* Entry at 0x1000 with the following:
|
||||||
|
* srr0 -> address of instruction that missed
|
||||||
|
* srr1 -> 0:3=cr0, 13=1 (instruction), 14=lru way, 16:31=saved MSR
|
||||||
|
* msr<tgpr> -> 1
|
||||||
|
* iMiss -> ea that missed
|
||||||
|
* iCmp -> the compare value for the va that missed
|
||||||
|
* hash1 -> pointer to first hash pteg
|
||||||
|
* hash2 -> pointer to second hash pteg
|
||||||
|
*
|
||||||
|
* Register usage:
|
||||||
|
* r0 is limit address during search / scratch after
|
||||||
|
* r1 is pte data / error code for ISI exception when search fails
|
||||||
|
* r2 is pointer to pte
|
||||||
|
* r3 is compare value during search / scratch after
|
||||||
|
*/
|
||||||
|
/* Binutils or assembler bug ? Declaring the section executable and writable
|
||||||
|
* generates an error message on the @fixup entries.
|
||||||
|
*/
|
||||||
|
.section .exception,"aw"
|
||||||
|
# .org 0x1000 # instruction TLB miss entry point
|
||||||
|
.globl tlb_handlers
|
||||||
|
tlb_handlers:
|
||||||
|
.type tlb_handlers,@function
|
||||||
|
#define ISIVec tlb_handlers-0x1000+0x400
|
||||||
|
#define DSIVec tlb_handlers-0x1000+0x300
|
||||||
|
mfspr r2,HASH1
|
||||||
|
lwz r1,0(r2) # Start memory access as soon as possible
|
||||||
|
mfspr r3,ICMP # to load the cache.
|
||||||
|
0: la r0,48(r2) # Use explicit loop to avoid using ctr
|
||||||
|
1: cmpw r1,r3 # In theory the loop is somewhat slower
|
||||||
|
beq- 2f # than documentation example
|
||||||
|
cmpw r0,r2 # but we gain from starting cache load
|
||||||
|
lwzu r1,8(r2) # earlier and using slots between load
|
||||||
|
bne+ 1b # and comparison for other purposes.
|
||||||
|
cmpw r1,r3
|
||||||
|
bne- 4f # Secondary hash check
|
||||||
|
2: lwz r1,4(r2) # Found: load second word of PTE
|
||||||
|
mfspr r0,IMISS # get miss address during load delay
|
||||||
|
#ifdef ASSUME_REF_SET
|
||||||
|
andi. r3,r1,8 # check for guarded memory
|
||||||
|
bne- 5f
|
||||||
|
mtspr RPA,r1
|
||||||
|
mfsrr1 r3
|
||||||
|
tlbli r0
|
||||||
|
#else
|
||||||
|
/* This is basically the original code from the manual. */
|
||||||
|
# andi. r3,r1,8 # check for guarded memory
|
||||||
|
# bne- 5f
|
||||||
|
# andi. r3,r1,0x100 # check R bit ahead to help folding
|
||||||
|
/* However there is a better solution: these last three instructions can be
|
||||||
|
replaced by the following which should cause less pipeline stalls because
|
||||||
|
both tests are combined and there is a single CR rename buffer */
|
||||||
|
extlwi r3,r1,6,23 # Keep only RCWIMG in 6 most significant bits.
|
||||||
|
rlwinm. r3,r3,5,0,27 # Keep only G (in sign) and R and test.
|
||||||
|
blt- 5f # Negative means guarded, zero R not set.
|
||||||
|
mfsrr1 r3 # get saved cr0 bits now to dual issue
|
||||||
|
ori r1,r1,0x100
|
||||||
|
mtspr RPA,r1
|
||||||
|
tlbli r0
|
||||||
|
/* Do not update PTE if R bit already set, this will save one cache line
|
||||||
|
writeback at a later time, and avoid even more bus traffic in
|
||||||
|
multiprocessing systems, when several processors access the same PTEGs.
|
||||||
|
We also hope that the reference bit will be already set. */
|
||||||
|
bne+ 3f
|
||||||
|
#ifdef MULTIPROCESSING
|
||||||
|
srwi r1,r1,8 # get byte 7 of pte
|
||||||
|
stb r1,+6(r2) # update page table
|
||||||
|
#else
|
||||||
|
sth r1,+6(r2) # update page table
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
3: mtcrf 0x80,r3 # restore CR0
|
||||||
|
rfi # return to executing program
|
||||||
|
|
||||||
|
/* The preceding code is 20 to 25 instructions long, which occupies
|
||||||
|
3 or 4 cache lines. */
|
||||||
|
4: andi. r0,r3,0x0040 # see if we have done second hash
|
||||||
|
lis r1,0x4000 # set up error code in case next branch taken
|
||||||
|
bne- 6f # speculatively issue the following
|
||||||
|
mfspr r2,HASH2 # get the second pointer
|
||||||
|
ori r3,r3,0x0040 # change the compare value
|
||||||
|
lwz r1,0(r2) # load first entry
|
||||||
|
b 0b # and go back to main loop
|
||||||
|
/* We are now at 27 to 32 instructions, using 3 or 4 cache lines for all
|
||||||
|
cases in which the TLB is successfully loaded. */
|
||||||
|
|
||||||
|
/* Guarded memory protection violation: synthesize an ISI exception. */
|
||||||
|
5: lis r1,0x1000 # set srr1<3>=1 to flag guard violation
|
||||||
|
/* Entry Not Found branches here with r1 correctly set. */
|
||||||
|
6: mfsrr1 r3
|
||||||
|
mfmsr r0
|
||||||
|
insrwi r1,r3,16,16 # build srr1 for ISI exception
|
||||||
|
mtsrr1 r1 # set srr1
|
||||||
|
/* It seems few people have realized rlwinm can be used to clear a bit or
|
||||||
|
a field of contiguous bits in a register by setting mask_begin>mask_end. */
|
||||||
|
rlwinm r0,r0,0,15,13 # clear the msr<tgpr> bit
|
||||||
|
mtcrf 0x80, r3 # restore CR0
|
||||||
|
mtmsr r0 # flip back to the native gprs
|
||||||
|
isync # Required from 602 doc!
|
||||||
|
b ISIVec # go to instruction access exception
|
||||||
|
/* Up to now there are 37 to 42 instructions so at least 20 could be
|
||||||
|
inserted for complex cases or for statistics recording. */
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Data TLB miss on load flow
|
||||||
|
Entry at 0x1100 with the following:
|
||||||
|
srr0 -> address of instruction that caused the miss
|
||||||
|
srr1 -> 0:3=cr0, 13=0 (data), 14=lru way, 15=0, 16:31=saved MSR
|
||||||
|
msr<tgpr> -> 1
|
||||||
|
dMiss -> ea that missed
|
||||||
|
dCmp -> the compare value for the va that missed
|
||||||
|
hash1 -> pointer to first hash pteg
|
||||||
|
hash2 -> pointer to second hash pteg
|
||||||
|
|
||||||
|
Register usage:
|
||||||
|
r0 is limit address during search / scratch after
|
||||||
|
r1 is pte data / error code for DSI exception when search fails
|
||||||
|
r2 is pointer to pte
|
||||||
|
r3 is compare value during search / scratch after
|
||||||
|
*/
|
||||||
|
.org tlb_handlers+0x100
|
||||||
|
mfspr r2,HASH1
|
||||||
|
lwz r1,0(r2) # Start memory access as soon as possible
|
||||||
|
mfspr r3,DCMP # to load the cache.
|
||||||
|
0: la r0,48(r2) # Use explicit loop to avoid using ctr
|
||||||
|
1: cmpw r1,r3 # In theory the loop is somewhat slower
|
||||||
|
beq- 2f # than documentation example
|
||||||
|
cmpw r0,r2 # but we gain from starting cache load
|
||||||
|
lwzu r1,8(r2) # earlier and using slots between load
|
||||||
|
bne+ 1b # and comparison for other purposes.
|
||||||
|
cmpw r1,r3
|
||||||
|
bne- 4f # Secondary hash check
|
||||||
|
2: lwz r1,4(r2) # Found: load second word of PTE
|
||||||
|
mfspr r0,DMISS # get miss address during load delay
|
||||||
|
#ifdef ASSUME_REF_SET
|
||||||
|
mtspr RPA,r1
|
||||||
|
mfsrr1 r3
|
||||||
|
tlbld r0
|
||||||
|
#else
|
||||||
|
andi. r3,r1,0x100 # check R bit ahead to help folding
|
||||||
|
mfsrr1 r3 # get saved cr0 bits now to dual issue
|
||||||
|
ori r1,r1,0x100
|
||||||
|
mtspr RPA,r1
|
||||||
|
tlbld r0
|
||||||
|
/* Do not update PTE if R bit already set, this will save one cache line
|
||||||
|
writeback at a later time, and avoid even more bus traffic in
|
||||||
|
multiprocessing systems, when several processors access the same PTEGs.
|
||||||
|
We also hope that the reference bit will be already set. */
|
||||||
|
bne+ 3f
|
||||||
|
#ifdef MULTIPROCESSING
|
||||||
|
srwi r1,r1,8 # get byte 7 of pte
|
||||||
|
stb r1,+6(r2) # update page table
|
||||||
|
#else
|
||||||
|
sth r1,+6(r2) # update page table
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
3: mtcrf 0x80,r3 # restore CR0
|
||||||
|
rfi # return to executing program
|
||||||
|
|
||||||
|
/* The preceding code is 18 to 23 instructions long, which occupies
|
||||||
|
3 cache lines. */
|
||||||
|
4: andi. r0,r3,0x0040 # see if we have done second hash
|
||||||
|
lis r1,0x4000 # set up error code in case next branch taken
|
||||||
|
bne- 9f # speculatively issue the following
|
||||||
|
mfspr r2,HASH2 # get the second pointer
|
||||||
|
ori r3,r3,0x0040 # change the compare value
|
||||||
|
lwz r1,0(r2) # load first entry asap
|
||||||
|
b 0b # and go back to main loop
|
||||||
|
/* We are now at 25 to 30 instructions, using 3 or 4 cache lines for all
|
||||||
|
cases in which the TLB is successfully loaded. */
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Data TLB miss on store or not dirty page flow
|
||||||
|
Entry at 0x1200 with the following:
|
||||||
|
srr0 -> address of instruction that caused the miss
|
||||||
|
srr1 -> 0:3=cr0, 13=0 (data), 14=lru way, 15=1, 16:31=saved MSR
|
||||||
|
msr<tgpr> -> 1
|
||||||
|
dMiss -> ea that missed
|
||||||
|
dCmp -> the compare value for the va that missed
|
||||||
|
hash1 -> pointer to first hash pteg
|
||||||
|
hash2 -> pointer to second hash pteg
|
||||||
|
|
||||||
|
Register usage:
|
||||||
|
r0 is limit address during search / scratch after
|
||||||
|
r1 is pte data / error code for DSI exception when search fails
|
||||||
|
r2 is pointer to pte
|
||||||
|
r3 is compare value during search / scratch after
|
||||||
|
*/
|
||||||
|
.org tlb_handlers+0x200
|
||||||
|
mfspr r2,HASH1
|
||||||
|
lwz r1,0(r2) # Start memory access as soon as possible
|
||||||
|
mfspr r3,DCMP # to load the cache.
|
||||||
|
0: la r0,48(r2) # Use explicit loop to avoid using ctr
|
||||||
|
1: cmpw r1,r3 # In theory the loop is somewhat slower
|
||||||
|
beq- 2f # than documentation example
|
||||||
|
cmpw r0,r2 # but we gain from starting cache load
|
||||||
|
lwzu r1,8(r2) # earlier and using slots between load
|
||||||
|
bne+ 1b # and comparison for other purposes.
|
||||||
|
cmpw r1,r3
|
||||||
|
bne- 4f # Secondary hash check
|
||||||
|
2: lwz r1,4(r2) # Found: load second word of PTE
|
||||||
|
mfspr r0,DMISS # get miss address during load delay
|
||||||
|
/* We could simply set the C bit and then rely on hardware to flag protection
|
||||||
|
violations. This raises the problem that a page which actually has not been
|
||||||
|
modified may be marked as dirty and violates the OEA model for guaranteed
|
||||||
|
bit settings (table 5-8 of 603eUM.pdf). This can have harmful consequences
|
||||||
|
on operating system memory management routines, and play havoc with copy on
|
||||||
|
write schemes. So the protection check is ABSOLUTELY necessary. */
|
||||||
|
andi. r3,r1,0x80 # check C bit
|
||||||
|
beq- 5f # if (C==0) go to check protection
|
||||||
|
3: mfsrr1 r3 # get the saved cr0 bits
|
||||||
|
mtspr RPA,r1 # set the pte
|
||||||
|
tlbld r0 # load the dtlb
|
||||||
|
mtcrf 0x80,r3 # restore CR0
|
||||||
|
rfi # return to executing program
|
||||||
|
/* The preceding code is 20 instructions long, which occupy
|
||||||
|
3 cache lines. */
|
||||||
|
4: andi. r0,r3,0x0040 # see if we have done second hash
|
||||||
|
lis r1,0x4200 # set up error code in case next branch taken
|
||||||
|
bne- 9f # speculatively issue the following
|
||||||
|
mfspr r2,HASH2 # get the second pointer
|
||||||
|
ori r3,r3,0x0040 # change the compare value
|
||||||
|
lwz r1,0(r2) # load first entry asap
|
||||||
|
b 0b # and go back to main loop
|
||||||
|
/* We are now at 27 instructions, using 3 or 4 cache lines for all
|
||||||
|
cases in which the TLB C bit is already set. */
|
||||||
|
|
||||||
|
#ifdef DIRTY_MEANS_WRITABLE
|
||||||
|
5: lis r1,0x0A00 # protection violation on store
|
||||||
|
#else
|
||||||
|
/*
|
||||||
|
Entry found and C==0: check protection before setting C:
|
||||||
|
Register usage:
|
||||||
|
r0 is dMiss register
|
||||||
|
r1 is PTE entry (to be copied to RPA if success)
|
||||||
|
r2 is pointer to pte
|
||||||
|
r3 is trashed
|
||||||
|
|
||||||
|
For the 603e, the key bit in SRR1 helps to decide whether there is a
|
||||||
|
protection violation. However the way the check is done in the manual is
|
||||||
|
not very efficient. The code shown here works as well for 603 and 603e and
|
||||||
|
is much more efficient for the 603 and comparable to the manual example
|
||||||
|
for 603e. This code however has quite a bad structure due to the fact it
|
||||||
|
has been reordered to speed up the most common cases.
|
||||||
|
*/
|
||||||
|
/* The first of the following two instructions could be replaced by
|
||||||
|
andi. r3,r1,3 but it would compete with cmplwi for cr0 resource. */
|
||||||
|
5: clrlwi r3,r1,30 # Extract two low order bits
|
||||||
|
cmplwi r3,2 # Test for PP=10
|
||||||
|
bne- 7f # assume fallthrough is more frequent
|
||||||
|
6: ori r1,r1,0x180 # set referenced and changed bit
|
||||||
|
sth r1,6(r2) # update page table
|
||||||
|
b 3b # and finish loading TLB
|
||||||
|
/* We are now at 33 instructions, using 5 cache lines. */
|
||||||
|
7: bgt- 8f # if PP=11 then DSI protection exception
|
||||||
|
/* This code only works if key bit is present (602/603e/603ev) */
|
||||||
|
#ifdef USE_KEY_BIT
|
||||||
|
mfsrr1 r3 # get the KEY bit and test it
|
||||||
|
andis. r3,r3,0x0008
|
||||||
|
beq 6b # default prediction taken, truly better ?
|
||||||
|
#else
|
||||||
|
/* This code is for all 602 and 603 family models: */
|
||||||
|
mfsrr1 r3 # Here the trick is to use the MSR PR bit as a
|
||||||
|
mfsrin r0,r0 # shift count for an rlwnm. instruction which
|
||||||
|
extrwi r3,r3,1,17 # extracts and tests the correct key bit from
|
||||||
|
rlwnm. r3,r0,r3,1,1 # the segment register. RISC they said...
|
||||||
|
mfspr r0,DMISS # Restore fault address to r0
|
||||||
|
beq 6b # if 0 load tlb else protection fault
|
||||||
|
#endif
|
||||||
|
/* We are now at 40 instructions, (37 if using key bit), using 5 cache
|
||||||
|
lines in all cases in which the C bit is successfully set */
|
||||||
|
8: lis r1,0x0A00 # protection violation on store
|
||||||
|
#endif /* DIRTY_IS_WRITABLE */
|
||||||
|
/* PTE entry not found branch here with DSISR code in r1 */
|
||||||
|
9: mfsrr1 r3
|
||||||
|
mtdsisr r1
|
||||||
|
clrlwi r2,r3,16 # set up srr1 for DSI exception
|
||||||
|
mfmsr r0
|
||||||
|
/* I have some doubts about the usefulness of the xori instruction in
|
||||||
|
mixed or pure little-endian environment. The address is in the same
|
||||||
|
doubleword, hence in the same protection domain and performing an exclusive
|
||||||
|
or with 7 is only valid for byte accesses. */
|
||||||
|
#ifdef CHECK_MIXED_ENDIAN
|
||||||
|
andi. r1,r2,1 # test LE bit ahead to help folding
|
||||||
|
#endif
|
||||||
|
mtsrr1 r2
|
||||||
|
rlwinm r0,r0,0,15,13 # clear the msr<tgpr> bit
|
||||||
|
mfspr r1,DMISS # get miss address
|
||||||
|
#ifdef CHECK_MIXED_ENDIAN
|
||||||
|
beq 1f # if little endian then:
|
||||||
|
xori r1,r1,0x07 # de-mung the data address
|
||||||
|
1:
|
||||||
|
#endif
|
||||||
|
mtdar r1 # put in dar
|
||||||
|
mtcrf 0x80,r3 # restore CR0
|
||||||
|
mtmsr r0 # flip back to the native gprs
|
||||||
|
isync # required from 602 manual
|
||||||
|
b DSIVec # branch to DSI exception
|
||||||
|
/* We are now between 50 and 56 instructions. Close to the limit
|
||||||
|
but should be sufficient in case bugs are found. */
|
||||||
|
/* Altogether the three handlers occupy 128 instructions in the worst
|
||||||
|
case, 64 instructions could still be added (non contiguously). */
|
||||||
|
.org tlb_handlers+0x300
|
||||||
|
.globl _handler_glue
|
||||||
|
_handler_glue:
|
||||||
|
/* Entry code for exceptions: DSI (0x300), ISI(0x400), alignment(0x600) and
|
||||||
|
* traps(0x700). In theory it is not necessary to save and restore r13 and all
|
||||||
|
* higher numbered registers, but it is done because it allowed to call the
|
||||||
|
* firmware (PPCBug) for debugging in the very first stages when writing the
|
||||||
|
* bootloader.
|
||||||
|
*/
|
||||||
|
stwu r1,-160(r1)
|
||||||
|
stw r0,save_r(0)
|
||||||
|
mflr r0
|
||||||
|
stmw r2,save_r(2)
|
||||||
|
bl 0f
|
||||||
|
0: mfctr r4
|
||||||
|
stw r0,save_lr
|
||||||
|
mflr r9 /* Interrupt vector + few instructions */
|
||||||
|
la r10,160(r1)
|
||||||
|
stw r4,save_ctr
|
||||||
|
mfcr r5
|
||||||
|
lwz r8,2f-0b(r9)
|
||||||
|
mfxer r6
|
||||||
|
stw r5,save_cr
|
||||||
|
mtctr r8
|
||||||
|
stw r6,save_xer
|
||||||
|
mfsrr0 r7
|
||||||
|
stw r10,save_r(1)
|
||||||
|
mfsrr1 r8
|
||||||
|
stw r7,save_nip
|
||||||
|
la r4,8(r1)
|
||||||
|
lwz r13,1f-0b(r9)
|
||||||
|
rlwinm r3,r9,24,0x3f /* Interrupt vector >> 8 */
|
||||||
|
stw r8,save_msr
|
||||||
|
bctrl
|
||||||
|
|
||||||
|
lwz r7,save_msr
|
||||||
|
lwz r6,save_nip
|
||||||
|
mtsrr1 r7
|
||||||
|
lwz r5,save_xer
|
||||||
|
mtsrr0 r6
|
||||||
|
lwz r4,save_ctr
|
||||||
|
mtxer r5
|
||||||
|
lwz r3,save_lr
|
||||||
|
mtctr r4
|
||||||
|
lwz r0,save_cr
|
||||||
|
mtlr r3
|
||||||
|
lmw r2,save_r(2)
|
||||||
|
mtcr r0
|
||||||
|
lwz r0,save_r(0)
|
||||||
|
la r1,160(r1)
|
||||||
|
rfi
|
||||||
|
1: .long (__bd)@fixup
|
||||||
|
2: .long (_handler)@fixup
|
||||||
|
.section .fixup,"aw"
|
||||||
|
.align 2
|
||||||
|
.long 1b, 2b
|
||||||
|
.previous
|
||||||
381
c/src/lib/libbsp/powerpc/shared/bootloader/head.S
Normal file
381
c/src/lib/libbsp/powerpc/shared/bootloader/head.S
Normal file
@@ -0,0 +1,381 @@
|
|||||||
|
/*
|
||||||
|
* head.S -- Bootloader Entry point
|
||||||
|
*
|
||||||
|
* Copyright (C) 1998, 1999 Gabriel Paubert, paubert@iram.es
|
||||||
|
*
|
||||||
|
* Modified to compile in RTEMS development environment
|
||||||
|
* by Eric Valette
|
||||||
|
*
|
||||||
|
* Copyright (C) 1999 Eric Valette. valette@crf.canon.fr
|
||||||
|
*
|
||||||
|
* The license and distribution terms for this file may be
|
||||||
|
* found in found in the file LICENSE in this distribution or at
|
||||||
|
* http://www.OARcorp.com/rtems/license.html.
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "bootldr.h"
|
||||||
|
#include <libcpu/cpu.h>
|
||||||
|
#include <rtems/score/targopts.h>
|
||||||
|
#include "asm.h"
|
||||||
|
|
||||||
|
#undef TEST_PPCBUG_CALLS
|
||||||
|
#define FRAME_SIZE 32
|
||||||
|
#define LOCK_CACHES (HID0_DLOCK|HID0_ILOCK)
|
||||||
|
#define INVL_CACHES (HID0_DCI|HID0_ICFI)
|
||||||
|
#define ENBL_CACHES (HID0_DCE|HID0_ICE)
|
||||||
|
|
||||||
|
#define USE_PPCBUG
|
||||||
|
#undef USE_PPCBUG
|
||||||
|
|
||||||
|
#define MONITOR_ENTER \
|
||||||
|
mfmsr r10 ; \
|
||||||
|
ori r10,r10,MSR_IP ; \
|
||||||
|
mtmsr r10 ; \
|
||||||
|
li r10,0x63 ; \
|
||||||
|
sc
|
||||||
|
|
||||||
|
START_GOT
|
||||||
|
GOT_ENTRY(_GOT2_TABLE_)
|
||||||
|
GOT_ENTRY(_FIXUP_TABLE_)
|
||||||
|
GOT_ENTRY(.bss)
|
||||||
|
GOT_ENTRY(codemove)
|
||||||
|
GOT_ENTRY(0)
|
||||||
|
GOT_ENTRY(__bd)
|
||||||
|
GOT_ENTRY(moved)
|
||||||
|
GOT_ENTRY(_binary_rtems_gz_start)
|
||||||
|
GOT_ENTRY(_binary_initrd_gz_start)
|
||||||
|
GOT_ENTRY(_binary_initrd_gz_end)
|
||||||
|
#ifdef TEST_PPCBUG_CALLS
|
||||||
|
GOT_ENTRY(banner_start)
|
||||||
|
GOT_ENTRY(banner_end)
|
||||||
|
#endif
|
||||||
|
END_GOT
|
||||||
|
.globl start
|
||||||
|
.type start,@function
|
||||||
|
/* Point the stack into the PreP partition header in the x86 reserved
|
||||||
|
* code area, so that simple C routines can be called.
|
||||||
|
*/
|
||||||
|
start:
|
||||||
|
#ifdef USE_PPCBUG
|
||||||
|
MONITOR_ENTER
|
||||||
|
#endif
|
||||||
|
bl 1f
|
||||||
|
1: mflr r1
|
||||||
|
li r0,0
|
||||||
|
stwu r0,start-1b-0x400+0x1b0-FRAME_SIZE(r1)
|
||||||
|
stmw r26,FRAME_SIZE-24(r1)
|
||||||
|
GET_GOT
|
||||||
|
mfmsr r28 /* Turn off interrupts */
|
||||||
|
ori r0,r28,MSR_EE
|
||||||
|
xori r0,r0,MSR_EE
|
||||||
|
mtmsr r0
|
||||||
|
|
||||||
|
/* Enable the caches, from now on cr2.eq set means processor is 601 */
|
||||||
|
mfpvr r0
|
||||||
|
mfspr r29,HID0
|
||||||
|
srwi r0,r0,16
|
||||||
|
cmplwi cr2,r0,1
|
||||||
|
beq 2,2f
|
||||||
|
#ifndef USE_PPCBUG
|
||||||
|
ori r0,r29,ENBL_CACHES|INVL_CACHES|LOCK_CACHES
|
||||||
|
xori r0,r0,INVL_CACHES|LOCK_CACHES
|
||||||
|
sync
|
||||||
|
isync
|
||||||
|
mtspr HID0,r0
|
||||||
|
#endif
|
||||||
|
2: bl reloc
|
||||||
|
|
||||||
|
/* save all the parameters and the orginal msr/hid0/r31 */
|
||||||
|
lwz bd,GOT(__bd)
|
||||||
|
stw r3,0(bd)
|
||||||
|
stw r4,4(bd)
|
||||||
|
stw r5,8(bd)
|
||||||
|
stw r6,12(bd)
|
||||||
|
lis r3,__size@sectoff@ha
|
||||||
|
stw r7,16(bd)
|
||||||
|
stw r8,20(bd)
|
||||||
|
addi r3,r3,__size@sectoff@l
|
||||||
|
stw r9,24(bd)
|
||||||
|
stw r10,28(bd)
|
||||||
|
stw r28,o_msr(bd)
|
||||||
|
stw r29,o_hid0(bd)
|
||||||
|
stw r31,o_r31(bd)
|
||||||
|
|
||||||
|
/* Call the routine to fill boot_data structure from residual data.
|
||||||
|
* And to find where the code has to be moved.
|
||||||
|
*/
|
||||||
|
bl early_setup
|
||||||
|
|
||||||
|
/* Now we need to relocate ourselves, where we are told to. First put a
|
||||||
|
* copy of the codemove routine to some place in memory.
|
||||||
|
* (which may be where the 0x41 partition was loaded, so size is critical).
|
||||||
|
*/
|
||||||
|
lwz r4,GOT(codemove)
|
||||||
|
li r5,_size_codemove
|
||||||
|
lwz r3,mover(bd)
|
||||||
|
lwz r6,cache_lsize(bd)
|
||||||
|
bl codemove
|
||||||
|
mtctr r3 # Where the temporary codemove is.
|
||||||
|
lwz r3,image(bd)
|
||||||
|
lis r5,_edata@sectoff@ha
|
||||||
|
lwz r4,GOT(0) # Our own address
|
||||||
|
addi r5,r5,_edata@sectoff@l
|
||||||
|
lwz r6,cache_lsize(bd)
|
||||||
|
lwz r8,GOT(moved)
|
||||||
|
sub r7,r3,r4 # Difference to adjust pointers.
|
||||||
|
add r8,r8,r7
|
||||||
|
add r30,r30,r7
|
||||||
|
add bd,bd,r7
|
||||||
|
/* Call the copy routine but return to the new area. */
|
||||||
|
mtlr r8 # for the return address
|
||||||
|
bctr # returns to the moved instruction
|
||||||
|
/* Establish the new top stack frame. */
|
||||||
|
moved: lwz r1,stack(bd)
|
||||||
|
li r0,0
|
||||||
|
stwu r0,-16(r1)
|
||||||
|
|
||||||
|
/* relocate again */
|
||||||
|
bl reloc
|
||||||
|
/* Clear all of BSS */
|
||||||
|
lwz r10,GOT(.bss)
|
||||||
|
li r0,__bss_words@sectoff@l
|
||||||
|
subi r10,r10,4
|
||||||
|
cmpwi r0,0
|
||||||
|
mtctr r0
|
||||||
|
li r0,0
|
||||||
|
beq 4f
|
||||||
|
3: stwu r0,4(r10)
|
||||||
|
bdnz 3b
|
||||||
|
|
||||||
|
/* Final memory initialization. First switch to unmapped mode
|
||||||
|
* in case the FW had set the MMU on, and flush the TLB to avoid
|
||||||
|
* stale entries from interfering. No I/O access is allowed
|
||||||
|
* during this time!
|
||||||
|
*/
|
||||||
|
#ifndef USE_PPCBUG
|
||||||
|
4: bl MMUoff
|
||||||
|
#endif
|
||||||
|
bl flush_tlb
|
||||||
|
/* Some firmware versions leave stale values in the BATs, it's time
|
||||||
|
* to invalidate them to avoid interferences with our own mappings.
|
||||||
|
* But the 601 valid bit is in the BATL (IBAT only) and others are in
|
||||||
|
* the [ID]BATU. Bloat, bloat.. fortunately thrown away later.
|
||||||
|
*/
|
||||||
|
li r3,0
|
||||||
|
beq cr2,5f
|
||||||
|
mtdbatu 0,r3
|
||||||
|
mtdbatu 1,r3
|
||||||
|
mtdbatu 2,r3
|
||||||
|
mtdbatu 3,r3
|
||||||
|
5: mtibatu 0,r3
|
||||||
|
mtibatl 0,r3
|
||||||
|
mtibatu 1,r3
|
||||||
|
mtibatl 1,r3
|
||||||
|
mtibatu 2,r3
|
||||||
|
mtibatl 2,r3
|
||||||
|
mtibatu 3,r3
|
||||||
|
mtibatl 3,r3
|
||||||
|
lis r3,__size@sectoff@ha
|
||||||
|
addi r3,r3,__size@sectoff@l
|
||||||
|
sync # We are going to touch SDR1 !
|
||||||
|
bl mm_init
|
||||||
|
bl MMUon
|
||||||
|
|
||||||
|
/* Now we are mapped and can perform I/O if we want */
|
||||||
|
#ifdef TEST_PPCBUG_CALLS
|
||||||
|
/* Experience seems to show that PPCBug can only be called with the
|
||||||
|
* data cache disabled and with MMU disabled. Bummer.
|
||||||
|
*/
|
||||||
|
li r10,0x22 # .OUTLN
|
||||||
|
lwz r3,GOT(banner_start)
|
||||||
|
lwz r4,GOT(banner_end)
|
||||||
|
sc
|
||||||
|
#endif
|
||||||
|
bl setup_hw
|
||||||
|
lwz r4,GOT(_binary_rtems_gz_start)
|
||||||
|
lis r5,_rtems_gz_size@sectoff@ha
|
||||||
|
lwz r6,GOT(_binary_initrd_gz_start)
|
||||||
|
lis r3,_rtems_size@sectoff@ha
|
||||||
|
lwz r7,GOT(_binary_initrd_gz_end)
|
||||||
|
addi r5,r5,_rtems_gz_size@sectoff@l
|
||||||
|
addi r3,r3,_rtems_size@sectoff@l
|
||||||
|
sub r7,r7,r6
|
||||||
|
bl decompress_kernel
|
||||||
|
|
||||||
|
/* Back here we are unmapped and we start the kernel, passing up to eight
|
||||||
|
* parameters just in case, only r3 to r7 used for now. Flush the tlb so
|
||||||
|
* that the loaded image starts in a clean state.
|
||||||
|
*/
|
||||||
|
bl flush_tlb
|
||||||
|
lwz r3,0(bd)
|
||||||
|
lwz r4,4(bd)
|
||||||
|
lwz r5,8(bd)
|
||||||
|
lwz r6,12(bd)
|
||||||
|
lwz r7,16(bd)
|
||||||
|
lwz r8,20(bd)
|
||||||
|
lwz r9,24(bd)
|
||||||
|
lwz r10,28(bd)
|
||||||
|
|
||||||
|
lwz r30,0(0)
|
||||||
|
mtctr r30
|
||||||
|
/*
|
||||||
|
* Linux code again
|
||||||
|
lis r30,0xdeadc0de@ha
|
||||||
|
addi r30,r30,0xdeadc0de@l
|
||||||
|
stw r30,0(0)
|
||||||
|
li r30,0
|
||||||
|
*/
|
||||||
|
dcbst 0,r30 /* Make sure it's in memory ! */
|
||||||
|
/* We just flash invalidate and disable the dcache, unless it's a 601,
|
||||||
|
* critical areas have been flushed and we don't care about the stack
|
||||||
|
* and other scratch areas.
|
||||||
|
*/
|
||||||
|
beq cr2,1f
|
||||||
|
mfspr r0,HID0
|
||||||
|
ori r0,r0,HID0_DCI|HID0_DCE
|
||||||
|
sync
|
||||||
|
mtspr HID0,r0
|
||||||
|
xori r0,r0,HID0_DCI|HID0_DCE
|
||||||
|
mtspr HID0,r0
|
||||||
|
/* Provisional return to FW, works for PPCBug */
|
||||||
|
#if 0
|
||||||
|
MONITOR_ENTER
|
||||||
|
#else
|
||||||
|
1: bctr
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* relocation function, r30 must point to got2+0x8000 */
|
||||||
|
reloc:
|
||||||
|
/* Adjust got2 pointers, no need to check for 0, this code already puts
|
||||||
|
* a few entries in the table.
|
||||||
|
*/
|
||||||
|
li r0,__got2_entries@sectoff@l
|
||||||
|
la r12,GOT(_GOT2_TABLE_)
|
||||||
|
lwz r11,GOT(_GOT2_TABLE_)
|
||||||
|
mtctr r0
|
||||||
|
sub r11,r12,r11
|
||||||
|
addi r12,r12,-4
|
||||||
|
1: lwzu r0,4(r12)
|
||||||
|
add r0,r0,r11
|
||||||
|
stw r0,0(r12)
|
||||||
|
bdnz 1b
|
||||||
|
|
||||||
|
/* Now adjust the fixups and the pointers to the fixups in case we need
|
||||||
|
* to move ourselves again.
|
||||||
|
*/
|
||||||
|
2: li r0,__fixup_entries@sectoff@l
|
||||||
|
lwz r12,GOT(_FIXUP_TABLE_)
|
||||||
|
cmpwi r0,0
|
||||||
|
mtctr r0
|
||||||
|
addi r12,r12,-4
|
||||||
|
beqlr
|
||||||
|
3: lwzu r10,4(r12)
|
||||||
|
lwzux r0,r10,r11
|
||||||
|
add r0,r0,r11
|
||||||
|
stw r10,0(r12)
|
||||||
|
stw r0,0(r10)
|
||||||
|
bdnz 3b
|
||||||
|
blr
|
||||||
|
|
||||||
|
/* Set the MMU on and off: code is always mapped 1:1 and does not need MMU,
|
||||||
|
* but it does not cost so much to map it also and it catches calls through
|
||||||
|
* NULL function pointers.
|
||||||
|
*/
|
||||||
|
.globl MMUon
|
||||||
|
.type MMUon,@function
|
||||||
|
MMUon: mfmsr r0
|
||||||
|
ori r0,r0,MSR_IR|MSR_DR|MSR_IP
|
||||||
|
mflr r11
|
||||||
|
xori r0,r0,MSR_IP
|
||||||
|
mtsrr0 r11
|
||||||
|
mtsrr1 r0
|
||||||
|
rfi
|
||||||
|
.globl MMUoff
|
||||||
|
.type MMUoff,@function
|
||||||
|
MMUoff: mfmsr r0
|
||||||
|
ori r0,r0,MSR_IR|MSR_DR|MSR_IP
|
||||||
|
mflr r11
|
||||||
|
xori r0,r0,MSR_IR|MSR_DR
|
||||||
|
mtsrr0 r11
|
||||||
|
mtsrr1 r0
|
||||||
|
rfi
|
||||||
|
|
||||||
|
/* Due to the PPC architecture (and according to the specifications), a
|
||||||
|
* series of tlbie which goes through a whole 256 MB segment always flushes
|
||||||
|
* the whole TLB. This is obviously overkill and slow, but who cares ?
|
||||||
|
* It takes about 1 ms on a 200 MHz 603e and works even if residual data
|
||||||
|
* get the number of TLB entries wrong.
|
||||||
|
*/
|
||||||
|
flush_tlb:
|
||||||
|
lis r11,0x1000
|
||||||
|
1: addic. r11,r11,-0x1000
|
||||||
|
tlbie r11
|
||||||
|
bnl 1b
|
||||||
|
/* tlbsync is not implemented on 601, so use sync which seems to be a superset
|
||||||
|
* of tlbsync in all cases and do not bother with CPU dependant code
|
||||||
|
*/
|
||||||
|
sync
|
||||||
|
blr
|
||||||
|
|
||||||
|
.globl codemove
|
||||||
|
codemove:
|
||||||
|
.type codemove,@function
|
||||||
|
/* r3 dest, r4 src, r5 length in bytes, r6 cachelinesize */
|
||||||
|
cmplw cr1,r3,r4
|
||||||
|
addi r0,r5,3
|
||||||
|
srwi. r0,r0,2
|
||||||
|
beq cr1,4f /* In place copy is not necessary */
|
||||||
|
beq 7f /* Protect against 0 count */
|
||||||
|
mtctr r0
|
||||||
|
bge cr1,2f
|
||||||
|
|
||||||
|
la r8,-4(r4)
|
||||||
|
la r7,-4(r3)
|
||||||
|
1: lwzu r0,4(r8)
|
||||||
|
stwu r0,4(r7)
|
||||||
|
bdnz 1b
|
||||||
|
b 4f
|
||||||
|
|
||||||
|
2: slwi r0,r0,2
|
||||||
|
add r8,r4,r0
|
||||||
|
add r7,r3,r0
|
||||||
|
3: lwzu r0,-4(r8)
|
||||||
|
stwu r0,-4(r7)
|
||||||
|
bdnz 3b
|
||||||
|
|
||||||
|
/* Now flush the cache: note that we must start from a cache aligned
|
||||||
|
* address. Otherwise we might miss one cache line.
|
||||||
|
*/
|
||||||
|
4: cmpwi r6,0
|
||||||
|
add r5,r3,r5
|
||||||
|
beq 7f /* Always flush prefetch queue in any case */
|
||||||
|
subi r0,r6,1
|
||||||
|
andc r3,r3,r0
|
||||||
|
mr r4,r3
|
||||||
|
5: cmplw r4,r5
|
||||||
|
dcbst 0,r4
|
||||||
|
add r4,r4,r6
|
||||||
|
blt 5b
|
||||||
|
sync /* Wait for all dcbst to complete on bus */
|
||||||
|
mr r4,r3
|
||||||
|
6: cmplw r4,r5
|
||||||
|
icbi 0,r4
|
||||||
|
add r4,r4,r6
|
||||||
|
blt 6b
|
||||||
|
7: sync /* Wait for all icbi to complete on bus */
|
||||||
|
isync
|
||||||
|
blr
|
||||||
|
.size codemove,.-codemove
|
||||||
|
_size_codemove=.-codemove
|
||||||
|
|
||||||
|
.section ".data" # .rodata
|
||||||
|
.align 2
|
||||||
|
#ifdef TEST_PPCBUG_CALLS
|
||||||
|
banner_start:
|
||||||
|
.ascii "This message was printed by PPCBug with MMU enabled"
|
||||||
|
banner_end:
|
||||||
|
#endif
|
||||||
53
c/src/lib/libbsp/powerpc/shared/bootloader/lib.c
Normal file
53
c/src/lib/libbsp/powerpc/shared/bootloader/lib.c
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
/* lib.c
|
||||||
|
*
|
||||||
|
* This file contains the implementation of functions that are unresolved
|
||||||
|
* in the bootloader. Unfortunately it shall not use any object code
|
||||||
|
* from newlib or rtems because they are not compiled with the right option!!!
|
||||||
|
*
|
||||||
|
* You've been warned!!!.
|
||||||
|
*
|
||||||
|
* CopyRight (C) 1998, 1999 valette@crf.canon.fr
|
||||||
|
*
|
||||||
|
* The license and distribution terms for this file may be
|
||||||
|
* found in found in the file LICENSE in this distribution or at
|
||||||
|
* http://www.OARcorp.com/rtems/license.html.
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
void* memset(void *p, int c, unsigned int n)
|
||||||
|
{
|
||||||
|
char *q =p;
|
||||||
|
for(; n>0; --n) *q++=c;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* memcpy(void *dst, const void * src, unsigned int n)
|
||||||
|
{
|
||||||
|
unsigned char *d=dst;
|
||||||
|
const unsigned char *s=src;
|
||||||
|
|
||||||
|
while(n-- > 0) *d++=*s++;
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* strcat(char * dest, const char * src)
|
||||||
|
{
|
||||||
|
char *tmp = dest;
|
||||||
|
|
||||||
|
while (*dest)
|
||||||
|
dest++;
|
||||||
|
while ((*dest++ = *src++) != '\0')
|
||||||
|
;
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
int strlen(const char* string)
|
||||||
|
{
|
||||||
|
register int i = 0;
|
||||||
|
|
||||||
|
while (string[i] != '\0')
|
||||||
|
++i;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
528
c/src/lib/libbsp/powerpc/shared/bootloader/misc.c
Normal file
528
c/src/lib/libbsp/powerpc/shared/bootloader/misc.c
Normal file
@@ -0,0 +1,528 @@
|
|||||||
|
/*
|
||||||
|
* head.S -- Bootloader Entry point
|
||||||
|
*
|
||||||
|
* Copyright (C) 1998, 1999 Gabriel Paubert, paubert@iram.es
|
||||||
|
*
|
||||||
|
* Modified to compile in RTEMS development environment
|
||||||
|
* by Eric Valette
|
||||||
|
*
|
||||||
|
* Copyright (C) 1999 Eric Valette. valette@crf.canon.fr
|
||||||
|
*
|
||||||
|
* The license and distribution terms for this file may be
|
||||||
|
* found in found in the file LICENSE in this distribution or at
|
||||||
|
* http://www.OARcorp.com/rtems/license.html.
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <libcpu/cpu.h>
|
||||||
|
#include "bootldr.h"
|
||||||
|
#include <libcpu/spr.h>
|
||||||
|
#include "zlib.h"
|
||||||
|
#include <libcpu/page.h>
|
||||||
|
#include <libcpu/byteorder.h>
|
||||||
|
|
||||||
|
SPR_RW(DEC)
|
||||||
|
SPR_RO(PVR)
|
||||||
|
|
||||||
|
struct inode;
|
||||||
|
struct wait_queue;
|
||||||
|
struct buffer_head;
|
||||||
|
typedef struct { int counter; } atomic_t;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct page {
|
||||||
|
/* these must be first (free area handling) */
|
||||||
|
struct page *next;
|
||||||
|
struct page *prev;
|
||||||
|
struct inode *inode;
|
||||||
|
unsigned long offset;
|
||||||
|
struct page *next_hash;
|
||||||
|
atomic_t count;
|
||||||
|
unsigned long flags; /* atomic flags, some possibly updated asynchronously */
|
||||||
|
struct wait_queue *wait;
|
||||||
|
struct page **pprev_hash;
|
||||||
|
struct buffer_head * buffers;
|
||||||
|
} mem_map_t;
|
||||||
|
|
||||||
|
|
||||||
|
extern opaque mm_private, pci_private, v86_private, console_private;
|
||||||
|
|
||||||
|
#define CONSOLE_ON_SERIAL "console=ttyS0"
|
||||||
|
|
||||||
|
extern struct console_io vacuum_console_functions;
|
||||||
|
extern opaque log_console_setup, serial_console_setup, vga_console_setup;
|
||||||
|
|
||||||
|
boot_data __bd = {0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
32, 0, 0, 0, 0, 0, 0,
|
||||||
|
&mm_private,
|
||||||
|
NULL,
|
||||||
|
&pci_private,
|
||||||
|
NULL,
|
||||||
|
&v86_private,
|
||||||
|
"root=/dev/hdc1"
|
||||||
|
};
|
||||||
|
|
||||||
|
static void exit(void) __attribute__((noreturn));
|
||||||
|
|
||||||
|
static void exit(void) {
|
||||||
|
printk("\nOnly way out is to press the reset button!\n");
|
||||||
|
asm volatile("": : :"memory");
|
||||||
|
while(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void hang(const char *s, u_long x, ctxt *p) {
|
||||||
|
u_long *r1;
|
||||||
|
#ifdef DEBUG
|
||||||
|
print_all_maps("\nMemory mappings at exception time:\n");
|
||||||
|
#endif
|
||||||
|
printk("%s %lx NIP: %p LR: %p\n"
|
||||||
|
"Callback trace (stack:return address)\n",
|
||||||
|
s, x, (void *) p->nip, (void *) p->lr);
|
||||||
|
asm volatile("lwz %0,0(1); lwz %0,0(%0); lwz %0,0(%0)": "=b" (r1));
|
||||||
|
while(r1) {
|
||||||
|
printk(" %p:%p\n", r1, (void *) r1[1]);
|
||||||
|
r1 = (u_long *) *r1;
|
||||||
|
}
|
||||||
|
exit();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void *zalloc(void *x, unsigned items, unsigned size)
|
||||||
|
{
|
||||||
|
void *p = salloc(items*size);
|
||||||
|
|
||||||
|
if (!p) {
|
||||||
|
printk("oops... not enough memory for gunzip\n");
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void zfree(void *x, void *addr, unsigned nb)
|
||||||
|
{
|
||||||
|
sfree(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define HEAD_CRC 2
|
||||||
|
#define EXTRA_FIELD 4
|
||||||
|
#define ORIG_NAME 8
|
||||||
|
#define COMMENT 0x10
|
||||||
|
#define RESERVED 0xe0
|
||||||
|
|
||||||
|
#define DEFLATED 8
|
||||||
|
|
||||||
|
|
||||||
|
void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
|
||||||
|
{
|
||||||
|
z_stream s;
|
||||||
|
int r, i, flags;
|
||||||
|
|
||||||
|
/* skip header */
|
||||||
|
i = 10;
|
||||||
|
flags = src[3];
|
||||||
|
if (src[2] != DEFLATED || (flags & RESERVED) != 0) {
|
||||||
|
printk("bad gzipped data\n");
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
if ((flags & EXTRA_FIELD) != 0)
|
||||||
|
i = 12 + src[10] + (src[11] << 8);
|
||||||
|
if ((flags & ORIG_NAME) != 0)
|
||||||
|
while (src[i++] != 0)
|
||||||
|
;
|
||||||
|
if ((flags & COMMENT) != 0)
|
||||||
|
while (src[i++] != 0)
|
||||||
|
;
|
||||||
|
if ((flags & HEAD_CRC) != 0)
|
||||||
|
i += 2;
|
||||||
|
if (i >= *lenp) {
|
||||||
|
printk("gunzip: ran out of data in header\n");
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
s.zalloc = zalloc;
|
||||||
|
s.zfree = zfree;
|
||||||
|
r = inflateInit2(&s, -MAX_WBITS);
|
||||||
|
if (r != Z_OK) {
|
||||||
|
printk("inflateInit2 returned %d\n", r);
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
s.next_in = src + i;
|
||||||
|
s.avail_in = *lenp - i;
|
||||||
|
s.next_out = dst;
|
||||||
|
s.avail_out = dstlen;
|
||||||
|
r = inflate(&s, Z_FINISH);
|
||||||
|
if (r != Z_OK && r != Z_STREAM_END) {
|
||||||
|
printk("inflate returned %d\n", r);
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
*lenp = s.next_out - (unsigned char *) dst;
|
||||||
|
inflateEnd(&s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void decompress_kernel(int kernel_size, void * zimage_start, int len,
|
||||||
|
void * initrd_start, int initrd_len ) {
|
||||||
|
u_char *parea;
|
||||||
|
RESIDUAL* rescopy;
|
||||||
|
int zimage_size= len;
|
||||||
|
|
||||||
|
/* That's a mess, we have to copy the residual data twice just in
|
||||||
|
* case it happens to be in the low memory area where the kernel
|
||||||
|
* is going to be unpacked. Later we have to copy it back to
|
||||||
|
* lower addresses because only the lowest part of memory is mapped
|
||||||
|
* during boot.
|
||||||
|
*/
|
||||||
|
parea=__palloc(kernel_size, PA_LOW);
|
||||||
|
if(!parea) {
|
||||||
|
printk("Not enough memory to uncompress the kernel.");
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
/* Note that this clears the bss as a side effect, so some code
|
||||||
|
* with ugly special case for SMP could be removed from the kernel!
|
||||||
|
*/
|
||||||
|
memset(parea, 0, kernel_size);
|
||||||
|
printk("\nUncompressing the kernel...\n");
|
||||||
|
rescopy=salloc(sizeof(RESIDUAL));
|
||||||
|
/* Let us hope that residual data is aligned on word boundary */
|
||||||
|
*rescopy = *bd->residual;
|
||||||
|
bd->residual = (void *)PAGE_ALIGN(kernel_size);
|
||||||
|
|
||||||
|
gunzip(parea, kernel_size, zimage_start, &zimage_size);
|
||||||
|
|
||||||
|
bd->of_entry = 0;
|
||||||
|
bd->load_address = 0;
|
||||||
|
bd->r6 = (char *)bd->residual+PAGE_ALIGN(sizeof(RESIDUAL));
|
||||||
|
bd->r7 = bd->r6+strlen(bd->cmd_line);
|
||||||
|
if ( initrd_len ) {
|
||||||
|
/* We have to leave some room for the hash table and for the
|
||||||
|
* whole array of struct page. The hash table would be better
|
||||||
|
* located at the end of memory if possible. With some bridges
|
||||||
|
* DMA from the last pages of memory is slower because
|
||||||
|
* prefetching from PCI has to be disabled to avoid accessing
|
||||||
|
* non existing memory. So it is the ideal place to put the
|
||||||
|
* hash table.
|
||||||
|
*/
|
||||||
|
unsigned tmp = rescopy->TotalMemory;
|
||||||
|
/* It's equivalent to tmp & (-tmp), but using the negation
|
||||||
|
* operator on unsigned variables looks so ugly.
|
||||||
|
*/
|
||||||
|
if ((tmp & (~tmp+1)) != tmp) tmp <<= 1; /* Next power of 2 */
|
||||||
|
tmp /= 256; /* Size of hash table */
|
||||||
|
if (tmp> (2<<20)) tmp=2<<20;
|
||||||
|
tmp = tmp*2 + 0x40000; /* Alignment can double size + 256 kB */
|
||||||
|
tmp += (rescopy->TotalMemory / PAGE_SIZE)
|
||||||
|
* sizeof(struct page);
|
||||||
|
bd->load_address = (void *)PAGE_ALIGN((int)bd->r7 + tmp);
|
||||||
|
bd->of_entry = (char *)bd->load_address+initrd_len;
|
||||||
|
}
|
||||||
|
#ifdef DEBUG
|
||||||
|
printk("Kernel at 0x%p, size=0x%x\n", NULL, kernel_size);
|
||||||
|
printk("Initrd at 0x%p, size=0x%x\n",bd->load_address, initrd_len);
|
||||||
|
printk("Residual data at 0x%p\n", bd->residual);
|
||||||
|
printk("Command line at 0x%p\n",bd->r6);
|
||||||
|
#endif
|
||||||
|
printk("done\nNow booting...\n");
|
||||||
|
MMUoff(); /* We need to access address 0 ! */
|
||||||
|
codemove(0, parea, kernel_size, bd->cache_lsize);
|
||||||
|
codemove(bd->residual, rescopy, sizeof(RESIDUAL), bd->cache_lsize);
|
||||||
|
codemove(bd->r6, bd->cmd_line, sizeof(bd->cmd_line), bd->cache_lsize);
|
||||||
|
/* codemove checks for 0 length */
|
||||||
|
codemove(bd->load_address, initrd_start, initrd_len, bd->cache_lsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
setup_hw(void)
|
||||||
|
{
|
||||||
|
char *cp, ch;
|
||||||
|
register RESIDUAL * res;
|
||||||
|
/* PPC_DEVICE * nvram; */
|
||||||
|
struct pci_dev *p, *default_vga;
|
||||||
|
int timer, err;
|
||||||
|
u_short default_vga_cmd;
|
||||||
|
static unsigned int indic;
|
||||||
|
|
||||||
|
indic = 0;
|
||||||
|
|
||||||
|
res=bd->residual;
|
||||||
|
default_vga=NULL;
|
||||||
|
default_vga_cmd = 0;
|
||||||
|
|
||||||
|
#define vpd res->VitalProductData
|
||||||
|
if (_read_PVR()>>16 != 1) {
|
||||||
|
if ( res && vpd.ProcessorBusHz ) {
|
||||||
|
ticks_per_ms = vpd.ProcessorBusHz/
|
||||||
|
(vpd.TimeBaseDivisor ? vpd.TimeBaseDivisor : 4000);
|
||||||
|
} else {
|
||||||
|
ticks_per_ms = 16500; /* assume 66 MHz on bus */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
select_console(CONSOLE_LOG);
|
||||||
|
|
||||||
|
/* We check that the keyboard is present and immediately
|
||||||
|
* select the serial console if not.
|
||||||
|
*/
|
||||||
|
err = kbdreset();
|
||||||
|
if (err) select_console(CONSOLE_SERIAL);
|
||||||
|
|
||||||
|
printk("\nModel: %s\nSerial: %s\n"
|
||||||
|
"Processor/Bus frequencies (Hz): %ld/%ld\n"
|
||||||
|
"Time Base Divisor: %ld\n"
|
||||||
|
"Memory Size: %x\n",
|
||||||
|
vpd.PrintableModel,
|
||||||
|
vpd.Serial,
|
||||||
|
vpd.ProcessorHz,
|
||||||
|
vpd.ProcessorBusHz,
|
||||||
|
(vpd.TimeBaseDivisor ? vpd.TimeBaseDivisor : 4000),
|
||||||
|
res->TotalMemory);
|
||||||
|
printk("Original MSR: %lx\nOriginal HID0: %lx\nOriginal R31: %lx\n",
|
||||||
|
bd->o_msr, bd->o_hid0, bd->o_r31);
|
||||||
|
|
||||||
|
/* This reconfigures all the PCI subsystem */
|
||||||
|
pci_init();
|
||||||
|
|
||||||
|
/* The Motorola NT firmware does not set the correct mem size */
|
||||||
|
if ( vpd.FirmwareSupplier == 0x10000 ) {
|
||||||
|
int memsize;
|
||||||
|
memsize = find_max_mem(bd->pci_devices);
|
||||||
|
if ( memsize != res->TotalMemory ) {
|
||||||
|
printk("Changed Memory size from %lx to %x\n",
|
||||||
|
res->TotalMemory, memsize);
|
||||||
|
res->TotalMemory = memsize;
|
||||||
|
res->GoodMemory = memsize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#define ENABLE_VGA_USAGE
|
||||||
|
#undef ENABLE_VGA_USAGE
|
||||||
|
#ifdef ENABLE_VGA_USAGE
|
||||||
|
/* Find the primary VGA device, chosing the first one found
|
||||||
|
* if none is enabled. The basic loop structure has been copied
|
||||||
|
* from linux/drivers/char/bttv.c by Alan Cox.
|
||||||
|
*/
|
||||||
|
for (p = bd->pci_devices; p; p = p->next) {
|
||||||
|
u_short cmd;
|
||||||
|
if (p->class != PCI_CLASS_NOT_DEFINED_VGA &&
|
||||||
|
((p->class) >> 16 != PCI_BASE_CLASS_DISPLAY))
|
||||||
|
continue;
|
||||||
|
if (p->bus->number != 0) {
|
||||||
|
printk("VGA device not on bus 0 not initialized!\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* Only one can be active in text mode, which for now will
|
||||||
|
* be assumed as equivalent to having I/O response enabled.
|
||||||
|
*/
|
||||||
|
pci_read_config_word(p, PCI_COMMAND, &cmd);
|
||||||
|
if(cmd & PCI_COMMAND_IO || !default_vga) {
|
||||||
|
default_vga=p;
|
||||||
|
default_vga_cmd=cmd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Disable the enabled VGA device, if any. */
|
||||||
|
if (default_vga)
|
||||||
|
pci_write_config_word(default_vga, PCI_COMMAND,
|
||||||
|
default_vga_cmd&
|
||||||
|
~(PCI_COMMAND_IO|PCI_COMMAND_MEMORY));
|
||||||
|
init_v86();
|
||||||
|
/* Same loop copied from bttv.c, this time doing the serious work */
|
||||||
|
for (p = bd->pci_devices; p; p = p->next) {
|
||||||
|
u_short cmd;
|
||||||
|
if (p->class != PCI_CLASS_NOT_DEFINED_VGA &&
|
||||||
|
((p->class) >> 16 != PCI_BASE_CLASS_DISPLAY))
|
||||||
|
continue;
|
||||||
|
if (p->bus->number != 0) continue;
|
||||||
|
pci_read_config_word(p, PCI_COMMAND, &cmd);
|
||||||
|
pci_write_config_word(p, PCI_COMMAND,
|
||||||
|
cmd|PCI_COMMAND_IO|PCI_COMMAND_MEMORY);
|
||||||
|
printk("Calling the emulator.\n");
|
||||||
|
em86_main(p);
|
||||||
|
pci_write_config_word(p, PCI_COMMAND, cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup_v86_mess();
|
||||||
|
#endif
|
||||||
|
/* Reenable the primary VGA device */
|
||||||
|
if (default_vga) {
|
||||||
|
pci_write_config_word(default_vga, PCI_COMMAND,
|
||||||
|
default_vga_cmd|
|
||||||
|
(PCI_COMMAND_IO|PCI_COMMAND_MEMORY));
|
||||||
|
if (err) {
|
||||||
|
printk("Keyboard error %d, using serial console!\n",
|
||||||
|
err);
|
||||||
|
} else {
|
||||||
|
select_console(CONSOLE_VGA);
|
||||||
|
}
|
||||||
|
} else if (!err) {
|
||||||
|
select_console(CONSOLE_SERIAL);
|
||||||
|
if (bd->cmd_line[0] == '\0') {
|
||||||
|
strcat(&bd->cmd_line[0], CONSOLE_ON_SERIAL);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int s = strlen (bd->cmd_line);
|
||||||
|
bd->cmd_line[s + 1] = ' ';
|
||||||
|
bd->cmd_line[s + 2] = '\0';
|
||||||
|
strcat(&bd->cmd_line[0], CONSOLE_ON_SERIAL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if 0
|
||||||
|
/* In the future we may use the NVRAM to store default
|
||||||
|
* kernel parameters.
|
||||||
|
*/
|
||||||
|
nvram=residual_find_device(~0UL, NULL, SystemPeripheral, NVRAM,
|
||||||
|
~0UL, 0);
|
||||||
|
if (nvram) {
|
||||||
|
PnP_TAG_PACKET * pkt;
|
||||||
|
switch (nvram->DevId.Interface) {
|
||||||
|
case IndirectNVRAM:
|
||||||
|
pkt=PnP_find_packet(res->DevicePnpHeap
|
||||||
|
+nvram->AllocatedOffset,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
printk("\nRTEMS 4.x/PPC load: ");
|
||||||
|
timer = 0;
|
||||||
|
cp = bd->cmd_line+strlen(bd->cmd_line);
|
||||||
|
while (timer++ < 5*1000) {
|
||||||
|
if (debug_tstc()) {
|
||||||
|
while ((ch = debug_getc()) != '\n' && ch != '\r') {
|
||||||
|
if (ch == '\b' || ch == 0177) {
|
||||||
|
if (cp != bd->cmd_line) {
|
||||||
|
cp--;
|
||||||
|
printk("\b \b");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
*cp++ = ch;
|
||||||
|
debug_putc(ch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break; /* Exit 'timer' loop */
|
||||||
|
}
|
||||||
|
udelay(1000); /* 1 msec */
|
||||||
|
}
|
||||||
|
*cp = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Functions to deal with the residual data */
|
||||||
|
static int same_DevID(unsigned short vendor,
|
||||||
|
unsigned short Number,
|
||||||
|
char * str)
|
||||||
|
{
|
||||||
|
static unsigned const char hexdigit[]="0123456789ABCDEF";
|
||||||
|
if (strlen(str)!=7) return 0;
|
||||||
|
if ( ( ((vendor>>10)&0x1f)+'A'-1 == str[0]) &&
|
||||||
|
( ((vendor>>5)&0x1f)+'A'-1 == str[1]) &&
|
||||||
|
( (vendor&0x1f)+'A'-1 == str[2]) &&
|
||||||
|
(hexdigit[(Number>>12)&0x0f] == str[3]) &&
|
||||||
|
(hexdigit[(Number>>8)&0x0f] == str[4]) &&
|
||||||
|
(hexdigit[(Number>>4)&0x0f] == str[5]) &&
|
||||||
|
(hexdigit[Number&0x0f] == str[6]) ) return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
PPC_DEVICE *residual_find_device(unsigned long BusMask,
|
||||||
|
unsigned char * DevID,
|
||||||
|
int BaseType,
|
||||||
|
int SubType,
|
||||||
|
int Interface,
|
||||||
|
int n)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
RESIDUAL *res = bd->residual;
|
||||||
|
if ( !res || !res->ResidualLength ) return NULL;
|
||||||
|
for (i=0; i<res->ActualNumDevices; i++) {
|
||||||
|
#define Dev res->Devices[i].DeviceId
|
||||||
|
if ( (Dev.BusId&BusMask) &&
|
||||||
|
(BaseType==-1 || Dev.BaseType==BaseType) &&
|
||||||
|
(SubType==-1 || Dev.SubType==SubType) &&
|
||||||
|
(Interface==-1 || Dev.Interface==Interface) &&
|
||||||
|
(DevID==NULL || same_DevID((Dev.DevId>>16)&0xffff,
|
||||||
|
Dev.DevId&0xffff, DevID)) &&
|
||||||
|
!(n--) ) return res->Devices+i;
|
||||||
|
#undef Dev
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
PnP_TAG_PACKET *PnP_find_packet(unsigned char *p,
|
||||||
|
unsigned packet_tag,
|
||||||
|
int n)
|
||||||
|
{
|
||||||
|
unsigned mask, masked_tag, size;
|
||||||
|
if(!p) return 0;
|
||||||
|
if (tag_type(packet_tag)) mask=0xff; else mask=0xF8;
|
||||||
|
masked_tag = packet_tag&mask;
|
||||||
|
for(; *p != END_TAG; p+=size) {
|
||||||
|
if ((*p & mask) == masked_tag && !(n--))
|
||||||
|
return (PnP_TAG_PACKET *) p;
|
||||||
|
if (tag_type(*p))
|
||||||
|
size=ld_le16((unsigned short *)(p+1))+3;
|
||||||
|
else
|
||||||
|
size=tag_small_count(*p)+1;
|
||||||
|
}
|
||||||
|
return 0; /* not found */
|
||||||
|
}
|
||||||
|
|
||||||
|
PnP_TAG_PACKET *PnP_find_small_vendor_packet(unsigned char *p,
|
||||||
|
unsigned packet_type,
|
||||||
|
int n)
|
||||||
|
{
|
||||||
|
int next=0;
|
||||||
|
while (p) {
|
||||||
|
p = (unsigned char *) PnP_find_packet(p, 0x70, next);
|
||||||
|
if (p && p[1]==packet_type && !(n--))
|
||||||
|
return (PnP_TAG_PACKET *) p;
|
||||||
|
next = 1;
|
||||||
|
};
|
||||||
|
return 0; /* not found */
|
||||||
|
}
|
||||||
|
|
||||||
|
PnP_TAG_PACKET *PnP_find_large_vendor_packet(unsigned char *p,
|
||||||
|
unsigned packet_type,
|
||||||
|
int n)
|
||||||
|
{
|
||||||
|
int next=0;
|
||||||
|
while (p) {
|
||||||
|
p = (unsigned char *) PnP_find_packet(p, 0x84, next);
|
||||||
|
if (p && p[3]==packet_type && !(n--))
|
||||||
|
return (PnP_TAG_PACKET *) p;
|
||||||
|
next = 1;
|
||||||
|
};
|
||||||
|
return 0; /* not found */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find out the amount of installed memory. For MPC105 and IBM 660 this
|
||||||
|
* can be done by finding the bank with the highest memory ending address
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
find_max_mem( struct pci_dev *dev )
|
||||||
|
{
|
||||||
|
u_char banks,tmp;
|
||||||
|
int i, top, max;
|
||||||
|
|
||||||
|
max = 0;
|
||||||
|
for ( ; dev; dev = dev->next) {
|
||||||
|
if ( ((dev->vendor == PCI_VENDOR_ID_MOTOROLA) &&
|
||||||
|
(dev->device == PCI_DEVICE_ID_MOTOROLA_MPC105)) ||
|
||||||
|
((dev->vendor == PCI_VENDOR_ID_IBM) &&
|
||||||
|
(dev->device == 0x0037/*IBM 660 Bridge*/)) ) {
|
||||||
|
pci_read_config_byte(dev, 0xa0, &banks);
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
if ( banks & (1<<i) ) {
|
||||||
|
pci_read_config_byte(dev, 0x90+i, &tmp);
|
||||||
|
top = tmp;
|
||||||
|
pci_read_config_byte(dev, 0x98+i, &tmp);
|
||||||
|
top |= (tmp&3)<<8;
|
||||||
|
if ( top > max ) max = top;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( max ) return ((max+1)<<20);
|
||||||
|
else return(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
982
c/src/lib/libbsp/powerpc/shared/bootloader/mm.c
Normal file
982
c/src/lib/libbsp/powerpc/shared/bootloader/mm.c
Normal file
@@ -0,0 +1,982 @@
|
|||||||
|
/*
|
||||||
|
* mm.c -- Crude memory management for early boot.
|
||||||
|
*
|
||||||
|
* Copyright (C) 1998, 1999 Gabriel Paubert, paubert@iram.es
|
||||||
|
*
|
||||||
|
* Modified to compile in RTEMS development environment
|
||||||
|
* by Eric Valette
|
||||||
|
*
|
||||||
|
* Copyright (C) 1999 Eric Valette. valette@crf.canon.fr
|
||||||
|
*
|
||||||
|
* The license and distribution terms for this file may be
|
||||||
|
* found in found in the file LICENSE in this distribution or at
|
||||||
|
* http://www.OARcorp.com/rtems/license.html.
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* This code is a crude memory manager for early boot for LinuxPPC.
|
||||||
|
* As such, it does not try to perform many optimiztions depending
|
||||||
|
* on the processor, it only uses features which are common to
|
||||||
|
* all processors (no BATs...).
|
||||||
|
*
|
||||||
|
* On PreP platorms (the only ones on which it works for now),
|
||||||
|
* it maps 1:1 all RAM/ROM and I/O space as claimed by the
|
||||||
|
* residual data. The holes between these areas can be virtually
|
||||||
|
* remapped to any of these, since for some functions it is very handy
|
||||||
|
* to have virtually contiguous but physically discontiguous memory.
|
||||||
|
*
|
||||||
|
* Physical memory allocation is also very crude, since it's only
|
||||||
|
* designed to manage a small number of large chunks. For valloc/vfree
|
||||||
|
* and palloc/pfree, the unit of allocation is the 4kB page.
|
||||||
|
*
|
||||||
|
* The salloc/sfree has been added after tracing gunzip and seeing
|
||||||
|
* how it performed a very large number of small allocations.
|
||||||
|
* For these the unit of allocation is 8 bytes (the s stands for
|
||||||
|
* small or subpage). This memory is cleared when allocated.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <libcpu/spr.h>
|
||||||
|
#include "bootldr.h"
|
||||||
|
#include <libcpu/mmu.h>
|
||||||
|
#include <libcpu/page.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
/* We use our own kind of simple memory areas for the loader, but
|
||||||
|
* we want to avoid potential clashes with kernel includes.
|
||||||
|
* Here a map maps contiguous areas from base to end,
|
||||||
|
* the firstpte entry corresponds to physical address and has the low
|
||||||
|
* order bits set for caching and permission.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct _map {
|
||||||
|
struct _map *next;
|
||||||
|
u_long base;
|
||||||
|
u_long end;
|
||||||
|
u_long firstpte;
|
||||||
|
} map;
|
||||||
|
|
||||||
|
/* The LSB of the firstpte entries on map lists other than mappings
|
||||||
|
* are constants which can be checked for debugging. All these constants
|
||||||
|
* have bit of weight 4 set, this bit is zero in the mappings list entries.
|
||||||
|
* Actually firstpte&7 value is:
|
||||||
|
* - 0 or 1 should not happen
|
||||||
|
* - 2 for RW actual virtual->physical mappings
|
||||||
|
* - 3 for RO actual virtual->physical mappings
|
||||||
|
* - 6 for free areas to be suballocated by salloc
|
||||||
|
* - 7 for salloc'ated areas
|
||||||
|
* - 4 or 5 for all others, in this case firtpte & 63 is
|
||||||
|
* - 4 for unused maps (on the free list)
|
||||||
|
* - 12 for free physical memory
|
||||||
|
* - 13 for physical memory in use
|
||||||
|
* - 20 for free virtual address space
|
||||||
|
* - 21 for allocated virtual address space
|
||||||
|
* - 28 for physical memory space suballocated by salloc
|
||||||
|
* - 29 for physical memory that can't be freed
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MAP_FREE_SUBS 6
|
||||||
|
#define MAP_USED_SUBS 7
|
||||||
|
|
||||||
|
#define MAP_FREE 4
|
||||||
|
#define MAP_FREE_PHYS 12
|
||||||
|
#define MAP_USED_PHYS 13
|
||||||
|
#define MAP_FREE_VIRT 20
|
||||||
|
#define MAP_USED_VIRT 21
|
||||||
|
#define MAP_SUBS_PHYS 28
|
||||||
|
#define MAP_PERM_PHYS 29
|
||||||
|
|
||||||
|
SPR_RW(SDR1);
|
||||||
|
SPR_RO(DSISR);
|
||||||
|
SPR_RO(DAR);
|
||||||
|
|
||||||
|
/* We need a few statically allocated free maps to bootstrap the
|
||||||
|
* memory managment */
|
||||||
|
static map free_maps[4] = {{free_maps+1, 0, 0, MAP_FREE},
|
||||||
|
{free_maps+2, 0, 0, MAP_FREE},
|
||||||
|
{free_maps+3, 0, 0, MAP_FREE},
|
||||||
|
{NULL, 0, 0, MAP_FREE}};
|
||||||
|
struct _mm_private {
|
||||||
|
void *sdr1;
|
||||||
|
u_long hashmask;
|
||||||
|
map *freemaps; /* Pool of unused map structs */
|
||||||
|
map *mappings; /* Sorted list of virtual->physical mappings */
|
||||||
|
map *physavail; /* Unallocated physical address space */
|
||||||
|
map *physused; /* Allocated physical address space */
|
||||||
|
map *physperm; /* Permanently allocated physical space */
|
||||||
|
map *virtavail; /* Unallocated virtual address space */
|
||||||
|
map *virtused; /* Allocated virtual address space */
|
||||||
|
map *sallocfree; /* Free maps for salloc */
|
||||||
|
map *sallocused; /* Used maps for salloc */
|
||||||
|
map *sallocphys; /* Physical areas used by salloc */
|
||||||
|
u_int hashcnt; /* Used to cycle in PTEG when they overflow */
|
||||||
|
} mm_private = {hashmask: 0xffc0,
|
||||||
|
freemaps: free_maps+0};
|
||||||
|
|
||||||
|
/* A simplified hash table entry declaration */
|
||||||
|
typedef struct _hash_entry {
|
||||||
|
int key;
|
||||||
|
u_long rpn;
|
||||||
|
} hash_entry;
|
||||||
|
|
||||||
|
void print_maps(map *, const char *);
|
||||||
|
|
||||||
|
/* The handler used for all exceptions although for now it is only
|
||||||
|
* designed to properly handle MMU interrupts to fill the hash table.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
void _handler(int vec, ctxt *p) {
|
||||||
|
map *area;
|
||||||
|
struct _mm_private *mm = (struct _mm_private *) bd->mm_private;
|
||||||
|
u_long vaddr, cause;
|
||||||
|
if (vec==4 || vec==7) { /* ISI exceptions are different */
|
||||||
|
vaddr = p->nip;
|
||||||
|
cause = p->msr;
|
||||||
|
} else { /* Valid for DSI and alignment exceptions */
|
||||||
|
vaddr = _read_DAR();
|
||||||
|
cause = _read_DSISR();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vec==3 || vec==4) {
|
||||||
|
/* Panic if the fault is not PTE not found. */
|
||||||
|
if (!(cause & 0x40000000)) {
|
||||||
|
MMUon();
|
||||||
|
printk("\nPanic: vector=%x, cause=%lx\n", vec, cause);
|
||||||
|
hang("Memory protection violation at ", vaddr, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(area=mm->mappings; area; area=area->next) {
|
||||||
|
if(area->base<=vaddr && vaddr<=area->end) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (area) {
|
||||||
|
u_long hash, vsid, rpn;
|
||||||
|
hash_entry volatile *hte, *_hte1;
|
||||||
|
u_int i, alt=0, flushva;
|
||||||
|
|
||||||
|
vsid = _read_SR((void *)vaddr);
|
||||||
|
rpn = (vaddr&PAGE_MASK)-area->base+area->firstpte;
|
||||||
|
hash = vsid<<6;
|
||||||
|
hash ^= (vaddr>>(PAGE_SHIFT-6))&0x3fffc0;
|
||||||
|
hash &= mm->hashmask;
|
||||||
|
/* Find an empty entry in the PTEG, else
|
||||||
|
* replace a random one.
|
||||||
|
*/
|
||||||
|
hte = (hash_entry *) ((u_long)(mm->sdr1)+hash);
|
||||||
|
for (i=0; i<8; i++) {
|
||||||
|
if (hte[i].key>=0) goto found;
|
||||||
|
}
|
||||||
|
hash ^= mm->hashmask;
|
||||||
|
alt = 0x40; _hte1 = hte;
|
||||||
|
hte = (hash_entry *) ((u_long)(mm->sdr1)+hash);
|
||||||
|
|
||||||
|
for (i=0; i<8; i++) {
|
||||||
|
if (hte[i].key>=0) goto found;
|
||||||
|
}
|
||||||
|
alt = 0;
|
||||||
|
hte = _hte1;
|
||||||
|
/* Chose a victim entry and replace it. There might be
|
||||||
|
* better policies to choose the victim, but in a boot
|
||||||
|
* loader we want simplicity as long as it works.
|
||||||
|
*
|
||||||
|
* We would not need to invalidate the TLB entry since
|
||||||
|
* the mapping is still valid. But this would be a mess
|
||||||
|
* when unmapping so we make sure that the TLB is a
|
||||||
|
* subset of the hash table under all circumstances.
|
||||||
|
*/
|
||||||
|
i = mm->hashcnt;
|
||||||
|
mm->hashcnt = (mm->hashcnt+1)%8;
|
||||||
|
/* Note that the hash is already complemented here ! */
|
||||||
|
flushva = (~(hash<<9)^((hte[i].key)<<5)) &0x3ff000;
|
||||||
|
if (hte[i].key&0x40) flushva^=0x3ff000;
|
||||||
|
flushva |= ((hte[i].key<<21)&0xf0000000)
|
||||||
|
| ((hte[i].key<<22)&0x0fc00000);
|
||||||
|
hte[i].key=0;
|
||||||
|
asm volatile("sync; tlbie %0; sync" : : "r" (flushva));
|
||||||
|
found:
|
||||||
|
hte[i].rpn = rpn;
|
||||||
|
asm volatile("eieio": : );
|
||||||
|
hte[i].key = 0x80000000|(vsid<<7)|alt|
|
||||||
|
((vaddr>>22)&0x3f);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
MMUon();
|
||||||
|
printk("\nPanic: vector=%x, cause=%lx\n", vec, cause);
|
||||||
|
hang("\nInvalid memory access attempt at ", vaddr, p);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
MMUon();
|
||||||
|
printk("\nPanic: vector=%x, dsisr=%lx, faultaddr =%lx, msr=%lx opcode=%lx\n", vec,
|
||||||
|
cause, p->nip, p->msr, * ((unsigned int*) p->nip) );
|
||||||
|
if (vec == 7) {
|
||||||
|
unsigned int* ptr = ((unsigned int*) p->nip) - 4 * 10;
|
||||||
|
for (; ptr <= (((unsigned int*) p->nip) + 4 * 10); ptr ++)
|
||||||
|
printk("Hexdecimal code at address %x = %x\n", ptr, *ptr);
|
||||||
|
}
|
||||||
|
hang("Program or alignment exception at ", vaddr, p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generic routines for map handling.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static inline
|
||||||
|
void free_map(map *p) {
|
||||||
|
struct _mm_private *mm = (struct _mm_private *) bd->mm_private;
|
||||||
|
if (!p) return;
|
||||||
|
p->next=mm->freemaps;
|
||||||
|
mm->freemaps=p;
|
||||||
|
p->firstpte=MAP_FREE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sorted insertion in linked list */
|
||||||
|
static
|
||||||
|
int insert_map(map **head, map *p) {
|
||||||
|
map *q = *head;
|
||||||
|
if (!p) return 0;
|
||||||
|
if (q && (q->base < p->base)) {
|
||||||
|
for(;q->next && q->next->base<p->base; q = q->next);
|
||||||
|
if ((q->end >= p->base) ||
|
||||||
|
(q->next && p->end>=q->next->base)) {
|
||||||
|
free_map(p);
|
||||||
|
printk("Overlapping areas!\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
p->next = q->next;
|
||||||
|
q->next = p;
|
||||||
|
} else { /* Insert at head */
|
||||||
|
if (q && (p->end >= q->base)) {
|
||||||
|
free_map(p);
|
||||||
|
printk("Overlapping areas!\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
p->next = q;
|
||||||
|
*head = p;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Removal from linked list */
|
||||||
|
|
||||||
|
static
|
||||||
|
map *remove_map(map **head, map *p) {
|
||||||
|
map *q = *head;
|
||||||
|
|
||||||
|
if (!p || !q) return NULL;
|
||||||
|
if (q==p) {
|
||||||
|
*head = q->next;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
for(;q && q->next!=p; q=q->next);
|
||||||
|
if (q) {
|
||||||
|
q->next=p->next;
|
||||||
|
return p;
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
map *remove_map_at(map **head, void * vaddr) {
|
||||||
|
map *p, *q = *head;
|
||||||
|
|
||||||
|
if (!vaddr || !q) return NULL;
|
||||||
|
if (q->base==(u_long)vaddr) {
|
||||||
|
*head = q->next;
|
||||||
|
return q;
|
||||||
|
}
|
||||||
|
while (q->next && q->next->base != (u_long)vaddr) q=q->next;
|
||||||
|
p=q->next;
|
||||||
|
if (p) q->next=p->next;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
map * alloc_map_page(void) {
|
||||||
|
map *from, *p;
|
||||||
|
struct _mm_private *mm = (struct _mm_private *) bd->mm_private;
|
||||||
|
|
||||||
|
/* printk("Allocating new map page !"); */
|
||||||
|
/* Get the highest page */
|
||||||
|
for (from=mm->physavail; from && from->next; from=from->next);
|
||||||
|
if (!from) return NULL;
|
||||||
|
|
||||||
|
from->end -= PAGE_SIZE;
|
||||||
|
|
||||||
|
mm->freemaps = (map *) (from->end+1);
|
||||||
|
|
||||||
|
for(p=mm->freemaps; p<mm->freemaps+PAGE_SIZE/sizeof(map)-1; p++) {
|
||||||
|
p->next = p+1;
|
||||||
|
p->firstpte = MAP_FREE;
|
||||||
|
}
|
||||||
|
(p-1)->next=0;
|
||||||
|
|
||||||
|
/* Take the last one as pointer to self and insert
|
||||||
|
* the map into the permanent map list.
|
||||||
|
*/
|
||||||
|
|
||||||
|
p->firstpte = MAP_PERM_PHYS;
|
||||||
|
p->base=(u_long) mm->freemaps;
|
||||||
|
p->end = p->base+PAGE_SIZE-1;
|
||||||
|
|
||||||
|
insert_map(&mm->physperm, p);
|
||||||
|
|
||||||
|
if (from->end+1 == from->base)
|
||||||
|
free_map(remove_map(&mm->physavail, from));
|
||||||
|
|
||||||
|
return mm->freemaps;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
map * alloc_map(void) {
|
||||||
|
map *p;
|
||||||
|
struct _mm_private * mm = (struct _mm_private *) bd->mm_private;
|
||||||
|
|
||||||
|
p = mm->freemaps;
|
||||||
|
if (!p) {
|
||||||
|
p=alloc_map_page();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(p) mm->freemaps=p->next;
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void coalesce_maps(map *p) {
|
||||||
|
while(p) {
|
||||||
|
if (p->next && (p->end+1 == p->next->base)) {
|
||||||
|
map *q=p->next;
|
||||||
|
p->end=q->end;
|
||||||
|
p->next=q->next;
|
||||||
|
free_map(q);
|
||||||
|
} else {
|
||||||
|
p = p->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* These routines are used to find the free memory zones to avoid
|
||||||
|
* overlapping destructive copies when initializing.
|
||||||
|
* They work from the top because of the way we want to boot.
|
||||||
|
* In the following the term zone refers to the memory described
|
||||||
|
* by one or several contiguous so called segments in the
|
||||||
|
* residual data.
|
||||||
|
*/
|
||||||
|
#define STACK_PAGES 2
|
||||||
|
static inline u_long
|
||||||
|
find_next_zone(RESIDUAL *res, u_long lowpage, u_long flags) {
|
||||||
|
u_long i, newmin=0, size=0;
|
||||||
|
for(i=0; i<res->ActualNumMemSegs; i++) {
|
||||||
|
if (res->Segs[i].Usage & flags
|
||||||
|
&& res->Segs[i].BasePage<lowpage
|
||||||
|
&& res->Segs[i].BasePage>newmin) {
|
||||||
|
newmin=res->Segs[i].BasePage;
|
||||||
|
size=res->Segs[i].PageCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newmin+size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline u_long
|
||||||
|
find_zone_start(RESIDUAL *res, u_long highpage, u_long flags) {
|
||||||
|
u_long i;
|
||||||
|
int progress;
|
||||||
|
do {
|
||||||
|
progress=0;
|
||||||
|
for (i=0; i<res->ActualNumMemSegs; i++) {
|
||||||
|
if ( (res->Segs[i].BasePage+res->Segs[i].PageCount
|
||||||
|
== highpage)
|
||||||
|
&& res->Segs[i].Usage & flags) {
|
||||||
|
highpage=res->Segs[i].BasePage;
|
||||||
|
progress=1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while(progress);
|
||||||
|
return highpage;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The Motorola NT firmware does not provide any setting in the residual
|
||||||
|
* data about memory segment usage. The following table provides enough
|
||||||
|
* info so that this bootloader can work.
|
||||||
|
*/
|
||||||
|
MEM_MAP seg_fix[] = {
|
||||||
|
{ 0x2000, 0xFFF00, 0x00100 },
|
||||||
|
{ 0x0020, 0x02000, 0x7E000 },
|
||||||
|
{ 0x0008, 0x00800, 0x00168 },
|
||||||
|
{ 0x0004, 0x00000, 0x00005 },
|
||||||
|
{ 0x0001, 0x006F1, 0x0010F },
|
||||||
|
{ 0x0002, 0x006AD, 0x00044 },
|
||||||
|
{ 0x0010, 0x00005, 0x006A8 },
|
||||||
|
{ 0x0010, 0x00968, 0x00698 },
|
||||||
|
{ 0x0800, 0xC0000, 0x3F000 },
|
||||||
|
{ 0x0600, 0xBF800, 0x00800 },
|
||||||
|
{ 0x0500, 0x81000, 0x3E800 },
|
||||||
|
{ 0x0480, 0x80800, 0x00800 },
|
||||||
|
{ 0x0440, 0x80000, 0x00800 } };
|
||||||
|
|
||||||
|
|
||||||
|
/* The Motorola NT firmware does not set up all required info in the residual
|
||||||
|
* data. This routine changes some things in a way that the bootloader and
|
||||||
|
* linux are happy.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
fix_residual( RESIDUAL *res )
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
PPC_DEVICE *hostbridge;
|
||||||
|
#endif
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Missing memory segment information */
|
||||||
|
res->ActualNumMemSegs = sizeof(seg_fix)/sizeof(MEM_MAP);
|
||||||
|
for (i=0; i<res->ActualNumMemSegs; i++) {
|
||||||
|
res->Segs[i].Usage = seg_fix[i].Usage;
|
||||||
|
res->Segs[i].BasePage = seg_fix[i].BasePage;
|
||||||
|
res->Segs[i].PageCount = seg_fix[i].PageCount;
|
||||||
|
}
|
||||||
|
/* The following should be fixed in the current version of the
|
||||||
|
* kernel and of the bootloader.
|
||||||
|
*/
|
||||||
|
#if 0
|
||||||
|
/* PPCBug has this zero */
|
||||||
|
res->VitalProductData.CacheLineSize = 0;
|
||||||
|
/* Motorola NT firmware sets TimeBaseDivisor to 0 */
|
||||||
|
if ( res->VitalProductData.TimeBaseDivisor == 0 ) {
|
||||||
|
res->VitalProductData.TimeBaseDivisor = 4000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Motorola NT firmware records the PCIBridge as a "PCIDEVICE" and
|
||||||
|
* sets "PCIBridgeDirect". This bootloader and linux works better if
|
||||||
|
* BusId = "PROCESSORDEVICE" and Interface = "PCIBridgeIndirect".
|
||||||
|
*/
|
||||||
|
hostbridge=residual_find_device(PCIDEVICE, NULL,
|
||||||
|
BridgeController,
|
||||||
|
PCIBridge, -1, 0);
|
||||||
|
if (hostbridge) {
|
||||||
|
hostbridge->DeviceId.BusId = PROCESSORDEVICE;
|
||||||
|
hostbridge->DeviceId.Interface = PCIBridgeIndirect;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This routine is the first C code called with very little stack space!
|
||||||
|
* Its goal is to find where the boot image can be moved. This will
|
||||||
|
* be the highest address with enough room.
|
||||||
|
*/
|
||||||
|
int early_setup(u_long image_size) {
|
||||||
|
register RESIDUAL *res = bd->residual;
|
||||||
|
u_long minpages = PAGE_ALIGN(image_size)>>PAGE_SHIFT;
|
||||||
|
|
||||||
|
/* Fix residual if we are loaded by Motorola NT firmware */
|
||||||
|
if ( res && res->VitalProductData.FirmwareSupplier == 0x10000 )
|
||||||
|
fix_residual( res );
|
||||||
|
|
||||||
|
/* FIXME: if OF we should do something different */
|
||||||
|
if( !bd->of_entry && res &&
|
||||||
|
res->ResidualLength <= sizeof(RESIDUAL) && res->Version == 0 ) {
|
||||||
|
u_long lowpage=ULONG_MAX, highpage;
|
||||||
|
u_long imghigh=0, stkhigh=0;
|
||||||
|
/* Find the highest and large enough contiguous zone
|
||||||
|
consisting of free and BootImage sections. */
|
||||||
|
/* Find 3 free areas of memory, one for the main image, one
|
||||||
|
* for the stack (STACK_PAGES), and page one to put the map
|
||||||
|
* structures. They are allocated from the top of memory.
|
||||||
|
* In most cases the stack will be put just below the image.
|
||||||
|
*/
|
||||||
|
while((highpage =
|
||||||
|
find_next_zone(res, lowpage, BootImage|Free))) {
|
||||||
|
lowpage=find_zone_start(res, highpage, BootImage|Free);
|
||||||
|
if ((highpage-lowpage)>minpages &&
|
||||||
|
highpage>imghigh) {
|
||||||
|
imghigh=highpage;
|
||||||
|
highpage -=minpages;
|
||||||
|
}
|
||||||
|
if ((highpage-lowpage)>STACK_PAGES &&
|
||||||
|
highpage>stkhigh) {
|
||||||
|
stkhigh=highpage;
|
||||||
|
highpage-=STACK_PAGES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bd->image = (void *)((imghigh-minpages)<<PAGE_SHIFT);
|
||||||
|
bd->stack=(void *) (stkhigh<<PAGE_SHIFT);
|
||||||
|
|
||||||
|
/* The code mover is put at the lowest possible place
|
||||||
|
* of free memory. If this corresponds to the loaded boot
|
||||||
|
* partition image it does not matter because it overrides
|
||||||
|
* the unused part of it (x86 code).
|
||||||
|
*/
|
||||||
|
bd->mover=(void *) (lowpage<<PAGE_SHIFT);
|
||||||
|
|
||||||
|
/* Let us flush the caches in all cases. After all it should
|
||||||
|
* not harm even on 601 and we don't care about performance.
|
||||||
|
* Right now it's easy since all processors have a line size
|
||||||
|
* of 32 bytes. Once again residual data has proved unreliable.
|
||||||
|
*/
|
||||||
|
bd->cache_lsize = 32;
|
||||||
|
}
|
||||||
|
/* For now we always assume that it's succesful, we should
|
||||||
|
* handle better the case of insufficient memory.
|
||||||
|
*/
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void * valloc(u_long size) {
|
||||||
|
map *p, *q;
|
||||||
|
struct _mm_private * mm = (struct _mm_private *) bd->mm_private;
|
||||||
|
|
||||||
|
if (size==0) return NULL;
|
||||||
|
size=PAGE_ALIGN(size)-1;
|
||||||
|
for (p=mm->virtavail; p; p=p->next) {
|
||||||
|
if (p->base+size <= p->end) break;
|
||||||
|
}
|
||||||
|
if(!p) return NULL;
|
||||||
|
q=alloc_map();
|
||||||
|
q->base=p->base;
|
||||||
|
q->end=q->base+size;
|
||||||
|
q->firstpte=MAP_USED_VIRT;
|
||||||
|
insert_map(&mm->virtused, q);
|
||||||
|
if (q->end==p->end) free_map(remove_map(&mm->virtavail, p));
|
||||||
|
else p->base += size+1;
|
||||||
|
return (void *)q->base;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void vflush(map *virtmap) {
|
||||||
|
struct _mm_private * mm = (struct _mm_private *) bd->mm_private;
|
||||||
|
u_long i, limit=(mm->hashmask>>3)+8;
|
||||||
|
hash_entry volatile *p=(hash_entry *) mm->sdr1;
|
||||||
|
|
||||||
|
/* PTE handling is simple since the processor never update
|
||||||
|
* the entries. Writable pages always have the C bit set and
|
||||||
|
* all valid entries have the R bit set. From the processor
|
||||||
|
* point of view the hash table is read only.
|
||||||
|
*/
|
||||||
|
for (i=0; i<limit; i++) {
|
||||||
|
if (p[i].key<0) {
|
||||||
|
u_long va;
|
||||||
|
va = ((i<<9)^((p[i].key)<<5)) &0x3ff000;
|
||||||
|
if (p[i].key&0x40) va^=0x3ff000;
|
||||||
|
va |= ((p[i].key<<21)&0xf0000000)
|
||||||
|
| ((p[i].key<<22)&0x0fc00000);
|
||||||
|
if (va>=virtmap->base && va<=virtmap->end) {
|
||||||
|
p[i].key=0;
|
||||||
|
asm volatile("sync; tlbie %0; sync" : :
|
||||||
|
"r" (va));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void vfree(void *vaddr) {
|
||||||
|
map *physmap, *virtmap; /* Actual mappings pertaining to this vm */
|
||||||
|
struct _mm_private * mm = (struct _mm_private *) bd->mm_private;
|
||||||
|
|
||||||
|
/* Flush memory queues */
|
||||||
|
asm volatile("sync": : : "memory");
|
||||||
|
|
||||||
|
virtmap = remove_map_at(&mm->virtused, vaddr);
|
||||||
|
if (!virtmap) return;
|
||||||
|
|
||||||
|
/* Remove mappings corresponding to virtmap */
|
||||||
|
for (physmap=mm->mappings; physmap; ) {
|
||||||
|
map *nextmap=physmap->next;
|
||||||
|
if (physmap->base>=virtmap->base
|
||||||
|
&& physmap->base<virtmap->end) {
|
||||||
|
free_map(remove_map(&mm->mappings, physmap));
|
||||||
|
}
|
||||||
|
physmap=nextmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
vflush(virtmap);
|
||||||
|
|
||||||
|
virtmap->firstpte= MAP_FREE_VIRT;
|
||||||
|
insert_map(&mm->virtavail, virtmap);
|
||||||
|
coalesce_maps(mm->virtavail);
|
||||||
|
}
|
||||||
|
|
||||||
|
void vunmap(void *vaddr) {
|
||||||
|
map *physmap, *virtmap; /* Actual mappings pertaining to this vm */
|
||||||
|
struct _mm_private *mm = (struct _mm_private *) bd->mm_private;
|
||||||
|
|
||||||
|
/* Flush memory queues */
|
||||||
|
asm volatile("sync": : : "memory");
|
||||||
|
|
||||||
|
/* vaddr must be within one of the vm areas in use and
|
||||||
|
* then must correspond to one of the physical areas
|
||||||
|
*/
|
||||||
|
for (virtmap=mm->virtused; virtmap; virtmap=virtmap->next) {
|
||||||
|
if (virtmap->base<=(u_long)vaddr &&
|
||||||
|
virtmap->end>=(u_long)vaddr) break;
|
||||||
|
}
|
||||||
|
if (!virtmap) return;
|
||||||
|
|
||||||
|
physmap = remove_map_at(&mm->mappings, vaddr);
|
||||||
|
if(!physmap) return;
|
||||||
|
vflush(physmap);
|
||||||
|
free_map(physmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
int vmap(void *vaddr, u_long p, u_long size) {
|
||||||
|
map *q;
|
||||||
|
struct _mm_private *mm = (struct _mm_private *) bd->mm_private;
|
||||||
|
|
||||||
|
size=PAGE_ALIGN(size);
|
||||||
|
if(!size) return 1;
|
||||||
|
/* Check that the requested area fits in one vm image */
|
||||||
|
for (q=mm->virtused; q; q=q->next) {
|
||||||
|
if ((q->base <= (u_long)vaddr) &&
|
||||||
|
(q->end>=(u_long)vaddr+size -1)) break;
|
||||||
|
}
|
||||||
|
if (!q) return 1;
|
||||||
|
q= alloc_map();
|
||||||
|
if (!q) return 1;
|
||||||
|
q->base = (u_long)vaddr;
|
||||||
|
q->end = (u_long)vaddr+size-1;
|
||||||
|
q->firstpte = p;
|
||||||
|
return insert_map(&mm->mappings, q);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void create_identity_mappings(int type, int attr) {
|
||||||
|
u_long lowpage=ULONG_MAX, highpage;
|
||||||
|
struct _mm_private *mm = (struct _mm_private *) bd->mm_private;
|
||||||
|
RESIDUAL * res=bd->residual;
|
||||||
|
|
||||||
|
while((highpage = find_next_zone(res, lowpage, type))) {
|
||||||
|
map *p;
|
||||||
|
lowpage=find_zone_start(res, highpage, type);
|
||||||
|
p=alloc_map();
|
||||||
|
/* Do not map page 0 to catch null pointers */
|
||||||
|
lowpage = lowpage ? lowpage : 1;
|
||||||
|
p->base=lowpage<<PAGE_SHIFT;
|
||||||
|
p->end=(highpage<<PAGE_SHIFT)-1;
|
||||||
|
p->firstpte = (lowpage<<PAGE_SHIFT)|attr;
|
||||||
|
insert_map(&mm->mappings, p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
void add_free_map(u_long base, u_long end) {
|
||||||
|
map *q=NULL;
|
||||||
|
struct _mm_private *mm = (struct _mm_private *) bd->mm_private;
|
||||||
|
|
||||||
|
if (base<end) q=alloc_map();
|
||||||
|
if (!q) return;
|
||||||
|
q->base=base;
|
||||||
|
q->end=end-1;
|
||||||
|
q->firstpte=MAP_FREE_VIRT;
|
||||||
|
insert_map(&mm->virtavail, q);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
void create_free_vm(void) {
|
||||||
|
map *p;
|
||||||
|
struct _mm_private *mm = (struct _mm_private *) bd->mm_private;
|
||||||
|
|
||||||
|
u_long vaddr=PAGE_SIZE; /* Never map vaddr 0 */
|
||||||
|
for(p=mm->mappings; p; p=p->next) {
|
||||||
|
add_free_map(vaddr, p->base);
|
||||||
|
vaddr=p->end+1;
|
||||||
|
}
|
||||||
|
/* Special end of memory case */
|
||||||
|
if (vaddr) add_free_map(vaddr,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Memory management initialization.
|
||||||
|
* Set up the mapping lists.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static inline
|
||||||
|
void add_perm_map(u_long start, u_long size) {
|
||||||
|
struct _mm_private *mm = (struct _mm_private *) bd->mm_private;
|
||||||
|
map *p=alloc_map();
|
||||||
|
p->base = start;
|
||||||
|
p->end = start + size - 1;
|
||||||
|
p->firstpte = MAP_PERM_PHYS;
|
||||||
|
insert_map(& mm->physperm , p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mm_init(u_long image_size)
|
||||||
|
{
|
||||||
|
u_long lowpage=ULONG_MAX, highpage;
|
||||||
|
struct _mm_private *mm = (struct _mm_private *) bd->mm_private;
|
||||||
|
RESIDUAL * res=bd->residual;
|
||||||
|
extern void (tlb_handlers)(void);
|
||||||
|
extern void (_handler_glue)(void);
|
||||||
|
int i;
|
||||||
|
map *p;
|
||||||
|
|
||||||
|
/* The checks are simplified by the fact that the image
|
||||||
|
* and stack area are always allocated at the upper end
|
||||||
|
* of a free block.
|
||||||
|
*/
|
||||||
|
while((highpage = find_next_zone(res, lowpage, BootImage|Free))) {
|
||||||
|
lowpage=find_zone_start(res, highpage, BootImage|Free);
|
||||||
|
if ( ( ((u_long)bd->image+PAGE_ALIGN(image_size))>>PAGE_SHIFT)
|
||||||
|
== highpage) {
|
||||||
|
highpage=(u_long)(bd->image)>>PAGE_SHIFT;
|
||||||
|
add_perm_map((u_long)bd->image, image_size);
|
||||||
|
}
|
||||||
|
if ( (( u_long)bd->stack>>PAGE_SHIFT) == highpage) {
|
||||||
|
highpage -= STACK_PAGES;
|
||||||
|
add_perm_map(highpage<<PAGE_SHIFT,
|
||||||
|
STACK_PAGES*PAGE_SIZE);
|
||||||
|
}
|
||||||
|
/* Protect the interrupt handlers that we need ! */
|
||||||
|
if (lowpage<2) lowpage=2;
|
||||||
|
/* Check for the special case of full area! */
|
||||||
|
if (highpage>lowpage) {
|
||||||
|
p = alloc_map();
|
||||||
|
p->base = lowpage<<PAGE_SHIFT;
|
||||||
|
p->end = (highpage<<PAGE_SHIFT)-1;
|
||||||
|
p->firstpte=MAP_FREE_PHYS;
|
||||||
|
insert_map(&mm->physavail, p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate the hash table */
|
||||||
|
mm->sdr1=__palloc(0x10000, PA_PERM|16);
|
||||||
|
_write_SDR1((u_long)mm->sdr1);
|
||||||
|
memset(mm->sdr1, 0, 0x10000);
|
||||||
|
mm->hashmask = 0xffc0;
|
||||||
|
|
||||||
|
/* Setup the segment registers as we want them */
|
||||||
|
for (i=0; i<16; i++) _write_SR(i, (void *)(i<<28));
|
||||||
|
/* Create the maps for the physical memory, firwmarecode does not
|
||||||
|
* seem to be necessary. ROM is mapped read-only to reduce the risk
|
||||||
|
* of reprogramming it because it's often Flash and some are
|
||||||
|
* amazingly easy to overwrite.
|
||||||
|
*/
|
||||||
|
create_identity_mappings(BootImage|Free|FirmwareCode|FirmwareHeap|
|
||||||
|
FirmwareStack, PTE_RAM);
|
||||||
|
create_identity_mappings(SystemROM, PTE_ROM);
|
||||||
|
create_identity_mappings(IOMemory|SystemIO|SystemRegs|
|
||||||
|
PCIAddr|PCIConfig|ISAAddr, PTE_IO);
|
||||||
|
|
||||||
|
create_free_vm();
|
||||||
|
|
||||||
|
/* Install our own MMU and trap handlers. */
|
||||||
|
codemove((void *) 0x300, _handler_glue, 0x100, bd->cache_lsize);
|
||||||
|
codemove((void *) 0x400, _handler_glue, 0x100, bd->cache_lsize);
|
||||||
|
codemove((void *) 0x600, _handler_glue, 0x100, bd->cache_lsize);
|
||||||
|
codemove((void *) 0x700, _handler_glue, 0x100, bd->cache_lsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void * salloc(u_long size) {
|
||||||
|
map *p, *q;
|
||||||
|
struct _mm_private *mm = (struct _mm_private *) bd->mm_private;
|
||||||
|
|
||||||
|
if (size==0) return NULL;
|
||||||
|
|
||||||
|
size = (size+7)&~7;
|
||||||
|
|
||||||
|
for (p=mm->sallocfree; p; p=p->next) {
|
||||||
|
if (p->base+size <= p->end) break;
|
||||||
|
}
|
||||||
|
if(!p) {
|
||||||
|
void *m;
|
||||||
|
m = __palloc(size, PA_SUBALLOC);
|
||||||
|
p = alloc_map();
|
||||||
|
if (!m && !p) return NULL;
|
||||||
|
p->base = (u_long) m;
|
||||||
|
p->firstpte = MAP_FREE_SUBS;
|
||||||
|
p->end = (u_long)m+PAGE_ALIGN(size)-1;
|
||||||
|
insert_map(&mm->sallocfree, p);
|
||||||
|
coalesce_maps(mm->sallocfree);
|
||||||
|
coalesce_maps(mm->sallocphys);
|
||||||
|
};
|
||||||
|
q=alloc_map();
|
||||||
|
q->base=p->base;
|
||||||
|
q->end=q->base+size-1;
|
||||||
|
q->firstpte=MAP_USED_SUBS;
|
||||||
|
insert_map(&mm->sallocused, q);
|
||||||
|
if (q->end==p->end) free_map(remove_map(&mm->sallocfree, p));
|
||||||
|
else p->base += size;
|
||||||
|
memset((void *)q->base, 0, size);
|
||||||
|
return (void *)q->base;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sfree(void *p) {
|
||||||
|
map *q;
|
||||||
|
struct _mm_private *mm = (struct _mm_private *) bd->mm_private;
|
||||||
|
|
||||||
|
q=remove_map_at(&mm->sallocused, p);
|
||||||
|
if (!q) return;
|
||||||
|
q->firstpte=MAP_FREE_SUBS;
|
||||||
|
insert_map(&mm->sallocfree, q);
|
||||||
|
coalesce_maps(mm->sallocfree);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* first/last area fit, flags is a power of 2 indicating the required
|
||||||
|
* alignment. The algorithms are stupid because we expect very little
|
||||||
|
* fragmentation of the areas, if any. The unit of allocation is the page.
|
||||||
|
* The allocation is by default performed from higher addresses down,
|
||||||
|
* unless flags&PA_LOW is true.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void * __palloc(u_long size, int flags)
|
||||||
|
{
|
||||||
|
u_long mask = ((1<<(flags&PA_ALIGN_MASK))-1);
|
||||||
|
map *newmap, *frommap, *p, *splitmap=0;
|
||||||
|
map **queue;
|
||||||
|
u_long qflags;
|
||||||
|
struct _mm_private *mm = (struct _mm_private *) bd->mm_private;
|
||||||
|
|
||||||
|
/* Asking for a size which is not a multiple of the alignment
|
||||||
|
is likely to be an error. */
|
||||||
|
|
||||||
|
if (size & mask) return NULL;
|
||||||
|
size = PAGE_ALIGN(size);
|
||||||
|
if(!size) return NULL;
|
||||||
|
|
||||||
|
if (flags&PA_SUBALLOC) {
|
||||||
|
queue = &mm->sallocphys;
|
||||||
|
qflags = MAP_SUBS_PHYS;
|
||||||
|
} else if (flags&PA_PERM) {
|
||||||
|
queue = &mm->physperm;
|
||||||
|
qflags = MAP_PERM_PHYS;
|
||||||
|
} else {
|
||||||
|
queue = &mm->physused;
|
||||||
|
qflags = MAP_USED_PHYS;
|
||||||
|
}
|
||||||
|
/* We need to allocate that one now so no two allocations may attempt
|
||||||
|
* to take the same memory simultaneously. Alloc_map_page does
|
||||||
|
* not call back here to avoid infinite recursion in alloc_map.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (mask&PAGE_MASK) {
|
||||||
|
splitmap=alloc_map();
|
||||||
|
if (!splitmap) return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (p=mm->physavail, frommap=NULL; p; p=p->next) {
|
||||||
|
u_long high = p->end;
|
||||||
|
u_long limit = ((p->base+mask)&~mask) + size-1;
|
||||||
|
if (high>=limit && ((p->base+mask)&~mask)+size>p->base) {
|
||||||
|
frommap = p;
|
||||||
|
if (flags&PA_LOW) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!frommap) {
|
||||||
|
if (splitmap) free_map(splitmap);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
newmap=alloc_map();
|
||||||
|
|
||||||
|
if (flags&PA_LOW) {
|
||||||
|
newmap->base = (frommap->base+mask)&~mask;
|
||||||
|
} else {
|
||||||
|
newmap->base = (frommap->end +1 - size) & ~mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
newmap->end = newmap->base+size-1;
|
||||||
|
newmap->firstpte = qflags;
|
||||||
|
|
||||||
|
/* Add a fragment if we don't allocate until the end. */
|
||||||
|
|
||||||
|
if (splitmap) {
|
||||||
|
splitmap->base=newmap->base+size;
|
||||||
|
splitmap->end=frommap->end;
|
||||||
|
splitmap->firstpte= MAP_FREE_PHYS;
|
||||||
|
frommap->end=newmap->base-1;
|
||||||
|
} else if (flags & PA_LOW) {
|
||||||
|
frommap->base=newmap->base+size;
|
||||||
|
} else {
|
||||||
|
frommap->end=newmap->base-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove a fragment if it becomes empty. */
|
||||||
|
if (frommap->base == frommap->end+1) {
|
||||||
|
free_map(remove_map(&mm->physavail, frommap));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (splitmap) {
|
||||||
|
if (splitmap->base == splitmap->end+1) {
|
||||||
|
free_map(remove_map(&mm->physavail, splitmap));
|
||||||
|
} else {
|
||||||
|
insert_map(&mm->physavail, splitmap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
insert_map(queue, newmap);
|
||||||
|
return (void *) newmap->base;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void pfree(void * p) {
|
||||||
|
map *q;
|
||||||
|
struct _mm_private *mm = (struct _mm_private *) bd->mm_private;
|
||||||
|
q=remove_map_at(&mm->physused, p);
|
||||||
|
if (!q) return;
|
||||||
|
q->firstpte=MAP_FREE_PHYS;
|
||||||
|
insert_map(&mm->physavail, q);
|
||||||
|
coalesce_maps(mm->physavail);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
/* Debugging functions */
|
||||||
|
void print_maps(map *chain, const char *s) {
|
||||||
|
map *p;
|
||||||
|
printk("%s",s);
|
||||||
|
for(p=chain; p; p=p->next) {
|
||||||
|
printk(" %08lx-%08lx: %08lx\n",
|
||||||
|
p->base, p->end, p->firstpte);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_all_maps(const char * s) {
|
||||||
|
u_long freemaps;
|
||||||
|
struct _mm_private *mm = (struct _mm_private *) bd->mm_private;
|
||||||
|
map *free;
|
||||||
|
printk("%s",s);
|
||||||
|
print_maps(mm->mappings, " Currently defined mappings:\n");
|
||||||
|
print_maps(mm->physavail, " Currently available physical areas:\n");
|
||||||
|
print_maps(mm->physused, " Currently used physical areas:\n");
|
||||||
|
print_maps(mm->virtavail, " Currently available virtual areas:\n");
|
||||||
|
print_maps(mm->virtused, " Currently used virtual areas:\n");
|
||||||
|
print_maps(mm->physperm, " Permanently used physical areas:\n");
|
||||||
|
print_maps(mm->sallocphys, " Physical memory used for salloc:\n");
|
||||||
|
print_maps(mm->sallocfree, " Memory available for salloc:\n");
|
||||||
|
print_maps(mm->sallocused, " Memory allocated through salloc:\n");
|
||||||
|
for (freemaps=0, free=mm->freemaps; free; freemaps++, free=free->next);
|
||||||
|
printk(" %ld free maps.\n", freemaps);
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_hash_table(void) {
|
||||||
|
struct _mm_private *mm = (struct _mm_private *) bd->mm_private;
|
||||||
|
hash_entry *p=(hash_entry *) mm->sdr1;
|
||||||
|
u_int i, valid=0;
|
||||||
|
for (i=0; i<((mm->hashmask)>>3)+8; i++) {
|
||||||
|
if (p[i].key<0) valid++;
|
||||||
|
}
|
||||||
|
printk("%u valid hash entries on pass 1.\n", valid);
|
||||||
|
valid = 0;
|
||||||
|
for (i=0; i<((mm->hashmask)>>3)+8; i++) {
|
||||||
|
if (p[i].key<0) valid++;
|
||||||
|
}
|
||||||
|
printk("%u valid hash entries on pass 2.\n"
|
||||||
|
" vpn:rpn_attr, p/s, pteg.i\n", valid);
|
||||||
|
for (i=0; i<((mm->hashmask)>>3)+8; i++) {
|
||||||
|
if (p[i].key<0) {
|
||||||
|
u_int pteg=(i>>3);
|
||||||
|
u_long vpn;
|
||||||
|
vpn = (pteg^((p[i].key)>>7)) &0x3ff;
|
||||||
|
if (p[i].key&0x40) vpn^=0x3ff;
|
||||||
|
vpn |= ((p[i].key<<9)&0xffff0000)
|
||||||
|
| ((p[i].key<<10)&0xfc00);
|
||||||
|
printk("%08lx:%08lx, %s, %5d.%d\n",
|
||||||
|
vpn, p[i].rpn, p[i].key&0x40 ? "sec" : "pri",
|
||||||
|
pteg, i%8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
931
c/src/lib/libbsp/powerpc/shared/bootloader/pci.c
Normal file
931
c/src/lib/libbsp/powerpc/shared/bootloader/pci.c
Normal file
@@ -0,0 +1,931 @@
|
|||||||
|
/*
|
||||||
|
* pci.c -- Crude pci handling for early boot.
|
||||||
|
*
|
||||||
|
* Copyright (C) 1998, 1999 Gabriel Paubert, paubert@iram.es
|
||||||
|
*
|
||||||
|
* Modified to compile in RTEMS development environment
|
||||||
|
* by Eric Valette
|
||||||
|
*
|
||||||
|
* Copyright (C) 1999 Eric Valette. valette@crf.canon.fr
|
||||||
|
*
|
||||||
|
* The license and distribution terms for this file may be
|
||||||
|
* found in found in the file LICENSE in this distribution or at
|
||||||
|
* http://www.OARcorp.com/rtems/license.html.
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <libcpu/spr.h>
|
||||||
|
#include "bootldr.h"
|
||||||
|
#include "pci.h"
|
||||||
|
#include <libcpu/io.h>
|
||||||
|
#include <bsp/consoleIo.h>
|
||||||
|
|
||||||
|
typedef unsigned int u32;
|
||||||
|
|
||||||
|
/*#define DEBUG*/
|
||||||
|
/* Used to reorganize PCI space on stupid machines which spread resources
|
||||||
|
* across a wide address space. This is bad when P2P bridges are present
|
||||||
|
* or when it limits the mappings that a resource hog like a PCI<->VME
|
||||||
|
* bridge can use.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct _pci_resource {
|
||||||
|
struct _pci_resource *next;
|
||||||
|
struct pci_dev *dev;
|
||||||
|
u_long base; /* will be 64 bits on 64 bits machines */
|
||||||
|
u_long size;
|
||||||
|
u_char type; /* 1 is I/O else low order 4 bits of the memory type */
|
||||||
|
u_char reg; /* Register # in conf space header */
|
||||||
|
u_short cmd; /* Original cmd byte */
|
||||||
|
} pci_resource;
|
||||||
|
|
||||||
|
typedef struct _pci_area {
|
||||||
|
struct _pci_area *next;
|
||||||
|
u_long start;
|
||||||
|
u_long end;
|
||||||
|
struct pci_bus *bus;
|
||||||
|
u_int flags;
|
||||||
|
} pci_area;
|
||||||
|
|
||||||
|
typedef struct _pci_area_head {
|
||||||
|
pci_area *head;
|
||||||
|
u_long mask;
|
||||||
|
int high; /* To allocate from top */
|
||||||
|
} pci_area_head;
|
||||||
|
|
||||||
|
#define PCI_AREA_PREFETCHABLE 0
|
||||||
|
#define PCI_AREA_MEMORY 1
|
||||||
|
#define PCI_AREA_IO 2
|
||||||
|
|
||||||
|
struct _pci_private {
|
||||||
|
volatile u_int * config_addr;
|
||||||
|
volatile u_char * config_data;
|
||||||
|
struct pci_dev **last_dev_p;
|
||||||
|
struct pci_bus pci_root;
|
||||||
|
pci_resource *resources;
|
||||||
|
pci_area_head io, mem;
|
||||||
|
|
||||||
|
} pci_private = {
|
||||||
|
config_addr: NULL,
|
||||||
|
config_data: (volatile u_char *) 0x80800000,
|
||||||
|
last_dev_p: NULL,
|
||||||
|
resources: NULL,
|
||||||
|
io: {NULL, 0xfff, 0},
|
||||||
|
mem: {NULL, 0xfffff, 0}
|
||||||
|
};
|
||||||
|
|
||||||
|
#define pci ((struct _pci_private *)(bd->pci_private))
|
||||||
|
#define pci_root pci->pci_root
|
||||||
|
|
||||||
|
#if !defined(DEBUG)
|
||||||
|
#undef PCI_DEBUG
|
||||||
|
/*
|
||||||
|
#else
|
||||||
|
#define PCI_DEBUG
|
||||||
|
*/
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(PCI_DEBUG)
|
||||||
|
static void
|
||||||
|
print_pci_resources(const char *s) {
|
||||||
|
pci_resource *p;
|
||||||
|
printk("%s", s);
|
||||||
|
for (p=pci->resources; p; p=p->next) {
|
||||||
|
printk(" %p:%p %06x %08lx %08lx %d\n",
|
||||||
|
p, p->next,
|
||||||
|
(p->dev->devfn<<8)+(p->dev->bus->number<<16)
|
||||||
|
+0x10+p->reg*4,
|
||||||
|
p->base,
|
||||||
|
p->size,
|
||||||
|
p->type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_pci_area(pci_area *p) {
|
||||||
|
for (; p; p=p->next) {
|
||||||
|
printk(" %p:%p %p %08lx %08lx\n",
|
||||||
|
p, p->next, p->bus, p->start, p->end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_pci_areas(const char *s) {
|
||||||
|
printk("%s PCI I/O areas:\n",s);
|
||||||
|
print_pci_area(pci->io.head);
|
||||||
|
printk(" PCI memory areas:\n");
|
||||||
|
print_pci_area(pci->mem.head);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define print_pci_areas(x)
|
||||||
|
#define print_pci_resources(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Maybe there are some devices who use a size different
|
||||||
|
* from the alignment. For now we assume both are the same.
|
||||||
|
* The blacklist might be used for other weird things in the future too,
|
||||||
|
* since weird non PCI complying devices seem to proliferate these days.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct blacklist_entry {
|
||||||
|
u_short vendor, device;
|
||||||
|
u_char reg;
|
||||||
|
u_long actual_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define BLACKLIST(vid, did, breg, actual_size) \
|
||||||
|
{PCI_VENDOR_ID_##vid, PCI_DEVICE_ID_##vid##_##did, breg, actual_size}
|
||||||
|
|
||||||
|
static struct blacklist_entry blacklist[] = {
|
||||||
|
BLACKLIST(S3, TRIO, 0, 0x04000000),
|
||||||
|
{0xffff, 0, 0, 0}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* This function filters resources and then inserts them into a list of
|
||||||
|
* configurable pci resources.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#define AREA(r) \
|
||||||
|
(((r->type&PCI_BASE_ADDRESS_SPACE)==PCI_BASE_ADDRESS_SPACE_IO) ? PCI_AREA_IO :\
|
||||||
|
((r->type&PCI_BASE_ADDRESS_MEM_PREFETCH) ? PCI_AREA_PREFETCHABLE :\
|
||||||
|
PCI_AREA_MEMORY))
|
||||||
|
|
||||||
|
static int insert_before(pci_resource *e, pci_resource *t) {
|
||||||
|
if (e->dev->bus->number != t->dev->bus->number)
|
||||||
|
return e->dev->bus->number > t->dev->bus->number;
|
||||||
|
if (AREA(e) != AREA(t)) return AREA(e)<AREA(t);
|
||||||
|
return (e->size > t->size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void insert_resource(pci_resource *r) {
|
||||||
|
struct blacklist_entry *b;
|
||||||
|
pci_resource *p;
|
||||||
|
if (!r) return;
|
||||||
|
|
||||||
|
/* First fixup in case we have a blacklist entry. Note that this
|
||||||
|
* may temporarily leave a resource in an inconsistent state: with
|
||||||
|
* (base & (size-1)) !=0. This is harmless.
|
||||||
|
*/
|
||||||
|
for (b=blacklist; b->vendor!=0xffff; b++) {
|
||||||
|
if ((r->dev->vendor==b->vendor) &&
|
||||||
|
(r->dev->device==b->device) &&
|
||||||
|
(r->reg==b->reg)) {
|
||||||
|
r->size=b->actual_size;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Motorola NT firmware does not configure pci devices which are not
|
||||||
|
* required for booting, others do. For now:
|
||||||
|
* - allocated devices in the ISA range (64kB I/O, 16Mb memory)
|
||||||
|
* but non zero base registers are left as is.
|
||||||
|
* - all other registers, whether already allocated or not, are
|
||||||
|
* reallocated unless they require an inordinate amount of
|
||||||
|
* resources (>256 Mb for memory >64kB for I/O). These
|
||||||
|
* devices with too large mapping requirements are simply ignored
|
||||||
|
* and their bases are set to 0. This should disable the
|
||||||
|
* corresponding decoders according to the PCI specification.
|
||||||
|
* Many devices are buggy in this respect, however, but the
|
||||||
|
* limits have hopefully been set high enough to avoid problems.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ((r->type==PCI_BASE_ADDRESS_SPACE_IO)
|
||||||
|
? (r->base && r->base <0x10000)
|
||||||
|
: (r->base && r->base <0x1000000)) {
|
||||||
|
sfree(r);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((r->type==PCI_BASE_ADDRESS_SPACE_IO)
|
||||||
|
? (r->size >= 0x10000)
|
||||||
|
: (r->size >= 0x10000000)) {
|
||||||
|
r->size = 0;
|
||||||
|
r->base = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now insert into the list sorting by
|
||||||
|
* 1) decreasing bus number
|
||||||
|
* 2) space: prefetchable memory, non-prefetchable and finally I/O
|
||||||
|
* 3) decreasing size
|
||||||
|
*/
|
||||||
|
if (!pci->resources || insert_before(r, pci->resources)) {
|
||||||
|
r->next = pci->resources;
|
||||||
|
pci->resources=r;
|
||||||
|
} else {
|
||||||
|
for (p=pci->resources; p->next; p=p->next) {
|
||||||
|
if (insert_before(r, p->next)) break;
|
||||||
|
}
|
||||||
|
r->next=p->next;
|
||||||
|
p->next=r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This version only works for bus 0. I don't have any P2P bridges to test
|
||||||
|
* a more sophisticated version which has therefore not been implemented.
|
||||||
|
* Prefetchable memory is not yet handled correctly either.
|
||||||
|
* And several levels of PCI bridges much less even since there must be
|
||||||
|
* allocated together to be able to setup correctly the top bridge.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static u_long find_range(u_char bus, u_char type,
|
||||||
|
pci_resource **first,
|
||||||
|
pci_resource **past, u_int *flags) {
|
||||||
|
pci_resource *p;
|
||||||
|
u_long total=0;
|
||||||
|
u_int fl=0;
|
||||||
|
|
||||||
|
for (p=pci->resources; p; p=p->next) {
|
||||||
|
if ((p->dev->bus->number == bus) &&
|
||||||
|
AREA(p)==type) break;
|
||||||
|
}
|
||||||
|
*first = p;
|
||||||
|
for (; p; p=p->next) {
|
||||||
|
if ((p->dev->bus->number != bus) ||
|
||||||
|
AREA(p)!=type || p->size == 0) break;
|
||||||
|
total = total+p->size;
|
||||||
|
fl |= 1<<p->type;
|
||||||
|
}
|
||||||
|
*past = p;
|
||||||
|
/* This will be used later to tell whether there are any 32 bit
|
||||||
|
* devices in an area which could be mapped higher than 4Gb
|
||||||
|
* on 64 bits architectures
|
||||||
|
*/
|
||||||
|
*flags = fl;
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void init_free_area(pci_area_head *h, u_long start,
|
||||||
|
u_long end, u_int mask, int high) {
|
||||||
|
pci_area *p;
|
||||||
|
p = salloc(sizeof(pci_area));
|
||||||
|
if (!p) return;
|
||||||
|
h->head = p;
|
||||||
|
p->next = NULL;
|
||||||
|
p->start = (start+mask)&~mask;
|
||||||
|
p->end = (end-mask)|mask;
|
||||||
|
p->bus = NULL;
|
||||||
|
h->mask = mask;
|
||||||
|
h->high = high;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void insert_area(pci_area_head *h, pci_area *p) {
|
||||||
|
pci_area *q = h->head;
|
||||||
|
if (!p) return;
|
||||||
|
if (q && (q->start< p->start)) {
|
||||||
|
for(;q->next && q->next->start<p->start; q = q->next);
|
||||||
|
if ((q->end >= p->start) ||
|
||||||
|
(q->next && p->end>=q->next->start)) {
|
||||||
|
sfree(p);
|
||||||
|
printk("Overlapping pci areas!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
p->next = q->next;
|
||||||
|
q->next = p;
|
||||||
|
} else { /* Insert at head */
|
||||||
|
if (q && (p->end >= q->start)) {
|
||||||
|
sfree(p);
|
||||||
|
printk("Overlapping pci areas!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
p->next = q;
|
||||||
|
h->head = p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void remove_area(pci_area_head *h, pci_area *p) {
|
||||||
|
pci_area *q = h->head;
|
||||||
|
|
||||||
|
if (!p || !q) return;
|
||||||
|
if (q==p) {
|
||||||
|
h->head = q->next;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for(;q && q->next!=p; q=q->next);
|
||||||
|
if (q) q->next=p->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
static pci_area * alloc_area(pci_area_head *h, struct pci_bus *bus,
|
||||||
|
u_long required, u_long mask, u_int flags) {
|
||||||
|
pci_area *p;
|
||||||
|
pci_area *from, *split, *new;
|
||||||
|
|
||||||
|
required = (required+h->mask) & ~h->mask;
|
||||||
|
for (p=h->head, from=NULL; p; p=p->next) {
|
||||||
|
u_long l1 = ((p->start+required+mask)&~mask)-1;
|
||||||
|
u_long l2 = ((p->start+mask)&~mask)+required-1;
|
||||||
|
/* Allocated areas point to the bus to which they pertain */
|
||||||
|
if (p->bus) continue;
|
||||||
|
if ((p->end)>=l1 || (p->end)>=l2) from=p;
|
||||||
|
if (from && !h->high) break;
|
||||||
|
}
|
||||||
|
if (!from) return NULL;
|
||||||
|
|
||||||
|
split = salloc(sizeof(pci_area));
|
||||||
|
new = salloc(sizeof(pci_area));
|
||||||
|
/* If allocation of new succeeds then allocation of split has
|
||||||
|
* also been successful (given the current mm algorithms) !
|
||||||
|
*/
|
||||||
|
if (!new) {
|
||||||
|
sfree(split);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
new->bus = bus;
|
||||||
|
new->flags = flags;
|
||||||
|
/* Now allocate pci_space taking alignment into account ! */
|
||||||
|
if (h->high) {
|
||||||
|
u_long l1 = ((from->end+1)&~mask)-required;
|
||||||
|
u_long l2 = (from->end+1-required)&~mask;
|
||||||
|
new->start = (l1>l2) ? l1 : l2;
|
||||||
|
split->end = from->end;
|
||||||
|
from->end = new->start-1;
|
||||||
|
split->start = new->start+required;
|
||||||
|
new->end = new->start+required-1;
|
||||||
|
} else {
|
||||||
|
u_long l1 = ((from->start+mask)&~mask)+required-1;
|
||||||
|
u_long l2 = ((from->start+required+mask)&~mask)-1;
|
||||||
|
new->end = (l1<l2) ? l1 : l2;
|
||||||
|
split->start = from->start;
|
||||||
|
from->start = new->end+1;
|
||||||
|
new->start = new->end+1-required;
|
||||||
|
split->end = new->start-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (from->end+1 == from->start) remove_area(h, from);
|
||||||
|
if (split->end+1 != split->start) {
|
||||||
|
split->bus = NULL;
|
||||||
|
insert_area(h, split);
|
||||||
|
} else {
|
||||||
|
sfree(split);
|
||||||
|
}
|
||||||
|
insert_area(h, new);
|
||||||
|
print_pci_areas("alloc_area called:\n");
|
||||||
|
return new;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
void alloc_space(pci_area *p, pci_resource *r) {
|
||||||
|
if (p->start & (r->size-1)) {
|
||||||
|
r->base = p->end+1-r->size;
|
||||||
|
p->end -= r->size;
|
||||||
|
} else {
|
||||||
|
r->base = p->start;
|
||||||
|
p->start += r->size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void reconfigure_bus_space(u_char bus, u_char type, pci_area_head *h) {
|
||||||
|
pci_resource *first, *past, *r;
|
||||||
|
pci_area *area, tmp;
|
||||||
|
u_int flags;
|
||||||
|
u_int required = find_range(bus, type, &first, &past, &flags);
|
||||||
|
|
||||||
|
if (required==0) return;
|
||||||
|
area = alloc_area(h, first->dev->bus, required, first->size-1, flags);
|
||||||
|
if (!area) return;
|
||||||
|
tmp = *area;
|
||||||
|
for (r=first; r!=past; r=r->next) {
|
||||||
|
alloc_space(&tmp, r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void reconfigure_pci(void) {
|
||||||
|
pci_resource *r;
|
||||||
|
struct pci_dev *dev;
|
||||||
|
/* FIXME: for now memory is relocated from low, it's better
|
||||||
|
* to start from higher addresses.
|
||||||
|
*/
|
||||||
|
init_free_area(&pci->io, 0x10000, 0x7fffff, 0xfff, 0);
|
||||||
|
init_free_area(&pci->mem, 0x1000000, 0x3cffffff, 0xfffff, 0);
|
||||||
|
|
||||||
|
/* First reconfigure the I/O space, this will be more
|
||||||
|
* complex when there is more than 1 bus. And 64 bits
|
||||||
|
* devices are another kind of problems.
|
||||||
|
*/
|
||||||
|
reconfigure_bus_space(0, PCI_AREA_IO, &pci->io);
|
||||||
|
reconfigure_bus_space(0, PCI_AREA_MEMORY, &pci->mem);
|
||||||
|
reconfigure_bus_space(0, PCI_AREA_PREFETCHABLE, &pci->mem);
|
||||||
|
|
||||||
|
/* Now we have to touch the configuration space of all
|
||||||
|
* the devices to remap them better than they are right now.
|
||||||
|
* This is done in 3 steps:
|
||||||
|
* 1) first disable I/O and memory response of all devices
|
||||||
|
* 2) modify the base registers
|
||||||
|
* 3) restore the original PCI_COMMAND register.
|
||||||
|
*/
|
||||||
|
for (r=pci->resources; r; r= r->next) {
|
||||||
|
if (!r->dev->sysdata) {
|
||||||
|
r->dev->sysdata=r;
|
||||||
|
pci_read_config_word(r->dev, PCI_COMMAND, &r->cmd);
|
||||||
|
pci_write_config_word(r->dev, PCI_COMMAND,
|
||||||
|
r->cmd & ~(PCI_COMMAND_IO|
|
||||||
|
PCI_COMMAND_MEMORY));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (r=pci->resources; r; r= r->next) {
|
||||||
|
pci_write_config_dword(r->dev,
|
||||||
|
PCI_BASE_ADDRESS_0+(r->reg<<2),
|
||||||
|
r->base);
|
||||||
|
if ((r->type&
|
||||||
|
(PCI_BASE_ADDRESS_SPACE|
|
||||||
|
PCI_BASE_ADDRESS_MEM_TYPE_MASK)) ==
|
||||||
|
(PCI_BASE_ADDRESS_SPACE_MEMORY|
|
||||||
|
PCI_BASE_ADDRESS_MEM_TYPE_64)) {
|
||||||
|
pci_write_config_dword(r->dev,
|
||||||
|
PCI_BASE_ADDRESS_1+
|
||||||
|
(r->reg<<2),
|
||||||
|
0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (dev=bd->pci_devices; dev; dev= dev->next) {
|
||||||
|
if (dev->sysdata) {
|
||||||
|
pci_write_config_word(dev, PCI_COMMAND,
|
||||||
|
((pci_resource *)dev->sysdata)
|
||||||
|
->cmd);
|
||||||
|
dev->sysdata=NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
indirect_pci_read_config_byte(unsigned char bus, unsigned char dev_fn,
|
||||||
|
unsigned char offset, unsigned char *val) {
|
||||||
|
out_be32(pci->config_addr,
|
||||||
|
0x80|(bus<<8)|(dev_fn<<16)|((offset&~3)<<24));
|
||||||
|
*val=in_8(pci->config_data + (offset&3));
|
||||||
|
return PCIBIOS_SUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
indirect_pci_read_config_word(unsigned char bus, unsigned char dev_fn,
|
||||||
|
unsigned char offset, unsigned short *val) {
|
||||||
|
*val = 0xffff;
|
||||||
|
if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
|
||||||
|
out_be32(pci->config_addr,
|
||||||
|
0x80|(bus<<8)|(dev_fn<<16)|((offset&~3)<<24));
|
||||||
|
*val=in_le16((volatile u_short *)(pci->config_data + (offset&3)));
|
||||||
|
return PCIBIOS_SUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
indirect_pci_read_config_dword(unsigned char bus, unsigned char dev_fn,
|
||||||
|
unsigned char offset, unsigned int *val) {
|
||||||
|
*val = 0xffffffff;
|
||||||
|
if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
|
||||||
|
out_be32(pci->config_addr,
|
||||||
|
0x80|(bus<<8)|(dev_fn<<16)|(offset<<24));
|
||||||
|
*val=in_le32((volatile u_int *)pci->config_data);
|
||||||
|
return PCIBIOS_SUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
indirect_pci_write_config_byte(unsigned char bus, unsigned char dev_fn,
|
||||||
|
unsigned char offset, unsigned char val) {
|
||||||
|
out_be32(pci->config_addr,
|
||||||
|
0x80|(bus<<8)|(dev_fn<<16)|((offset&~3)<<24));
|
||||||
|
out_8(pci->config_data + (offset&3), val);
|
||||||
|
return PCIBIOS_SUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
indirect_pci_write_config_word(unsigned char bus, unsigned char dev_fn,
|
||||||
|
unsigned char offset, unsigned short val) {
|
||||||
|
if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
|
||||||
|
out_be32(pci->config_addr,
|
||||||
|
0x80|(bus<<8)|(dev_fn<<16)|((offset&~3)<<24));
|
||||||
|
out_le16((volatile u_short *)(pci->config_data + (offset&3)), val);
|
||||||
|
return PCIBIOS_SUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
indirect_pci_write_config_dword(unsigned char bus, unsigned char dev_fn,
|
||||||
|
unsigned char offset, unsigned int val) {
|
||||||
|
if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
|
||||||
|
out_be32(pci->config_addr,
|
||||||
|
0x80|(bus<<8)|(dev_fn<<16)|(offset<<24));
|
||||||
|
out_le32((volatile u_int *)pci->config_data, val);
|
||||||
|
return PCIBIOS_SUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct pci_config_access_functions indirect_functions = {
|
||||||
|
indirect_pci_read_config_byte,
|
||||||
|
indirect_pci_read_config_word,
|
||||||
|
indirect_pci_read_config_dword,
|
||||||
|
indirect_pci_write_config_byte,
|
||||||
|
indirect_pci_write_config_word,
|
||||||
|
indirect_pci_write_config_dword
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
direct_pci_read_config_byte(unsigned char bus, unsigned char dev_fn,
|
||||||
|
unsigned char offset, unsigned char *val) {
|
||||||
|
if (bus != 0 || (1<<PCI_SLOT(dev_fn) & 0xff8007fe)) {
|
||||||
|
*val=0xff;
|
||||||
|
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||||
|
}
|
||||||
|
*val=in_8(pci->config_data + ((1<<PCI_SLOT(dev_fn))&~1)
|
||||||
|
+ (PCI_FUNC(dev_fn)<<8) + offset);
|
||||||
|
return PCIBIOS_SUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
direct_pci_read_config_word(unsigned char bus, unsigned char dev_fn,
|
||||||
|
unsigned char offset, unsigned short *val) {
|
||||||
|
*val = 0xffff;
|
||||||
|
if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
|
||||||
|
if (bus != 0 || (1<<PCI_SLOT(dev_fn) & 0xff8007fe)) {
|
||||||
|
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||||
|
}
|
||||||
|
*val=in_le16((volatile u_short *)
|
||||||
|
(pci->config_data + ((1<<PCI_SLOT(dev_fn))&~1)
|
||||||
|
+ (PCI_FUNC(dev_fn)<<8) + offset));
|
||||||
|
return PCIBIOS_SUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
direct_pci_read_config_dword(unsigned char bus, unsigned char dev_fn,
|
||||||
|
unsigned char offset, unsigned int *val) {
|
||||||
|
*val = 0xffffffff;
|
||||||
|
if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
|
||||||
|
if (bus != 0 || (1<<PCI_SLOT(dev_fn) & 0xff8007fe)) {
|
||||||
|
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||||
|
}
|
||||||
|
*val=in_le32((volatile u_int *)
|
||||||
|
(pci->config_data + ((1<<PCI_SLOT(dev_fn))&~1)
|
||||||
|
+ (PCI_FUNC(dev_fn)<<8) + offset));
|
||||||
|
return PCIBIOS_SUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
direct_pci_write_config_byte(unsigned char bus, unsigned char dev_fn,
|
||||||
|
unsigned char offset, unsigned char val) {
|
||||||
|
if (bus != 0 || (1<<PCI_SLOT(dev_fn) & 0xff8007fe)) {
|
||||||
|
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||||
|
}
|
||||||
|
out_8(pci->config_data + ((1<<PCI_SLOT(dev_fn))&~1)
|
||||||
|
+ (PCI_FUNC(dev_fn)<<8) + offset,
|
||||||
|
val);
|
||||||
|
return PCIBIOS_SUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
direct_pci_write_config_word(unsigned char bus, unsigned char dev_fn,
|
||||||
|
unsigned char offset, unsigned short val) {
|
||||||
|
if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
|
||||||
|
if (bus != 0 || (1<<PCI_SLOT(dev_fn) & 0xff8007fe)) {
|
||||||
|
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||||
|
}
|
||||||
|
out_le16((volatile u_short *)
|
||||||
|
(pci->config_data + ((1<<PCI_SLOT(dev_fn))&~1)
|
||||||
|
+ (PCI_FUNC(dev_fn)<<8) + offset),
|
||||||
|
val);
|
||||||
|
return PCIBIOS_SUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
direct_pci_write_config_dword(unsigned char bus, unsigned char dev_fn,
|
||||||
|
unsigned char offset, unsigned int val) {
|
||||||
|
if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
|
||||||
|
if (bus != 0 || (1<<PCI_SLOT(dev_fn) & 0xff8007fe)) {
|
||||||
|
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||||
|
}
|
||||||
|
out_le32((volatile u_int *)
|
||||||
|
(pci->config_data + ((1<<PCI_SLOT(dev_fn))&~1)
|
||||||
|
+ (PCI_FUNC(dev_fn)<<8) + offset),
|
||||||
|
val);
|
||||||
|
return PCIBIOS_SUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct pci_config_access_functions direct_functions = {
|
||||||
|
direct_pci_read_config_byte,
|
||||||
|
direct_pci_read_config_word,
|
||||||
|
direct_pci_read_config_dword,
|
||||||
|
direct_pci_write_config_byte,
|
||||||
|
direct_pci_write_config_word,
|
||||||
|
direct_pci_write_config_dword
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void pci_read_bases(struct pci_dev *dev, unsigned int howmany)
|
||||||
|
{
|
||||||
|
unsigned int reg, nextreg;
|
||||||
|
#define REG (PCI_BASE_ADDRESS_0 + (reg<<2))
|
||||||
|
u_short cmd;
|
||||||
|
u32 l, ml;
|
||||||
|
pci_read_config_word(dev, PCI_COMMAND, &cmd);
|
||||||
|
|
||||||
|
for(reg=0; reg<howmany; reg=nextreg) {
|
||||||
|
pci_resource *r;
|
||||||
|
nextreg=reg+1;
|
||||||
|
pci_read_config_dword(dev, REG, &l);
|
||||||
|
#if 0
|
||||||
|
if (l == 0xffffffff /*AJF || !l*/) continue;
|
||||||
|
#endif
|
||||||
|
/* Note that disabling the memory response of a host bridge
|
||||||
|
* would lose data if a DMA transfer were in progress. In a
|
||||||
|
* bootloader we don't care however. Also we can't print any
|
||||||
|
* message for a while since we might just disable the console.
|
||||||
|
*/
|
||||||
|
pci_write_config_word(dev, PCI_COMMAND, cmd &
|
||||||
|
~(PCI_COMMAND_IO|PCI_COMMAND_MEMORY));
|
||||||
|
pci_write_config_dword(dev, REG, ~0);
|
||||||
|
pci_read_config_dword(dev, REG, &ml);
|
||||||
|
pci_write_config_dword(dev, REG, l);
|
||||||
|
|
||||||
|
/* Reenable the device now that we've played with
|
||||||
|
* base registers.
|
||||||
|
*/
|
||||||
|
pci_write_config_word(dev, PCI_COMMAND, cmd);
|
||||||
|
|
||||||
|
/* seems to be an unused entry skip it */
|
||||||
|
if ( ml == 0 || ml == 0xffffffff ) continue;
|
||||||
|
|
||||||
|
if ((l &
|
||||||
|
(PCI_BASE_ADDRESS_SPACE|PCI_BASE_ADDRESS_MEM_TYPE_MASK))
|
||||||
|
== (PCI_BASE_ADDRESS_MEM_TYPE_64
|
||||||
|
|PCI_BASE_ADDRESS_SPACE_MEMORY)) {
|
||||||
|
nextreg=reg+2;
|
||||||
|
}
|
||||||
|
dev->base_address[reg] = l;
|
||||||
|
r = salloc(sizeof(pci_resource));
|
||||||
|
if (!r) {
|
||||||
|
printk("Error allocating pci_resource struct.\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
r->dev = dev;
|
||||||
|
r->reg = reg;
|
||||||
|
if ((l&PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) {
|
||||||
|
r->type = l&~PCI_BASE_ADDRESS_IO_MASK;
|
||||||
|
r->base = l&PCI_BASE_ADDRESS_IO_MASK;
|
||||||
|
r->size = ~(ml&PCI_BASE_ADDRESS_IO_MASK)+1;
|
||||||
|
} else {
|
||||||
|
r->type = l&~PCI_BASE_ADDRESS_MEM_MASK;
|
||||||
|
r->base = l&PCI_BASE_ADDRESS_MEM_MASK;
|
||||||
|
r->size = ~(ml&PCI_BASE_ADDRESS_MEM_MASK)+1;
|
||||||
|
}
|
||||||
|
/* Check for the blacklisted entries */
|
||||||
|
insert_resource(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
u_int pci_scan_bus(struct pci_bus *bus)
|
||||||
|
{
|
||||||
|
unsigned int devfn, l, max, class;
|
||||||
|
unsigned char irq, hdr_type, is_multi = 0;
|
||||||
|
struct pci_dev *dev, **bus_last;
|
||||||
|
struct pci_bus *child;
|
||||||
|
|
||||||
|
bus_last = &bus->devices;
|
||||||
|
max = bus->secondary;
|
||||||
|
for (devfn = 0; devfn < 0xff; ++devfn) {
|
||||||
|
if (PCI_FUNC(devfn) && !is_multi) {
|
||||||
|
/* not a multi-function device */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (pcibios_read_config_byte(bus->number, devfn, PCI_HEADER_TYPE, &hdr_type))
|
||||||
|
continue;
|
||||||
|
if (!PCI_FUNC(devfn))
|
||||||
|
is_multi = hdr_type & 0x80;
|
||||||
|
|
||||||
|
if (pcibios_read_config_dword(bus->number, devfn, PCI_VENDOR_ID, &l) ||
|
||||||
|
/* some broken boards return 0 if a slot is empty: */
|
||||||
|
l == 0xffffffff || l == 0x00000000 || l == 0x0000ffff || l == 0xffff0000) {
|
||||||
|
is_multi = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev = salloc(sizeof(*dev));
|
||||||
|
dev->bus = bus;
|
||||||
|
dev->devfn = devfn;
|
||||||
|
dev->vendor = l & 0xffff;
|
||||||
|
dev->device = (l >> 16) & 0xffff;
|
||||||
|
|
||||||
|
pcibios_read_config_dword(bus->number, devfn,
|
||||||
|
PCI_CLASS_REVISION, &class);
|
||||||
|
class >>= 8; /* upper 3 bytes */
|
||||||
|
dev->class = class;
|
||||||
|
class >>= 8;
|
||||||
|
dev->hdr_type = hdr_type;
|
||||||
|
|
||||||
|
switch (hdr_type & 0x7f) { /* header type */
|
||||||
|
case PCI_HEADER_TYPE_NORMAL: /* standard header */
|
||||||
|
if (class == PCI_CLASS_BRIDGE_PCI)
|
||||||
|
goto bad;
|
||||||
|
/*
|
||||||
|
* If the card generates interrupts, read IRQ number
|
||||||
|
* (some architectures change it during pcibios_fixup())
|
||||||
|
*/
|
||||||
|
pcibios_read_config_byte(bus->number, dev->devfn, PCI_INTERRUPT_PIN, &irq);
|
||||||
|
if (irq)
|
||||||
|
pcibios_read_config_byte(bus->number, dev->devfn, PCI_INTERRUPT_LINE, &irq);
|
||||||
|
dev->irq = irq;
|
||||||
|
/*
|
||||||
|
* read base address registers, again pcibios_fixup() can
|
||||||
|
* tweak these
|
||||||
|
*/
|
||||||
|
pci_read_bases(dev, 6);
|
||||||
|
pcibios_read_config_dword(bus->number, devfn, PCI_ROM_ADDRESS, &l);
|
||||||
|
dev->rom_address = (l == 0xffffffff) ? 0 : l;
|
||||||
|
break;
|
||||||
|
case PCI_HEADER_TYPE_BRIDGE: /* bridge header */
|
||||||
|
if (class != PCI_CLASS_BRIDGE_PCI)
|
||||||
|
goto bad;
|
||||||
|
pci_read_bases(dev, 2);
|
||||||
|
pcibios_read_config_dword(bus->number, devfn, PCI_ROM_ADDRESS1, &l);
|
||||||
|
dev->rom_address = (l == 0xffffffff) ? 0 : l;
|
||||||
|
break;
|
||||||
|
case PCI_HEADER_TYPE_CARDBUS: /* CardBus bridge header */
|
||||||
|
if (class != PCI_CLASS_BRIDGE_CARDBUS)
|
||||||
|
goto bad;
|
||||||
|
pci_read_bases(dev, 1);
|
||||||
|
break;
|
||||||
|
default: /* unknown header */
|
||||||
|
bad:
|
||||||
|
printk("PCI device with unknown "
|
||||||
|
"header type %d ignored.\n",
|
||||||
|
hdr_type&0x7f);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Put it into the global PCI device chain. It's used to
|
||||||
|
* find devices once everything is set up.
|
||||||
|
*/
|
||||||
|
*pci->last_dev_p = dev;
|
||||||
|
pci->last_dev_p = &dev->next;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now insert it into the list of devices held
|
||||||
|
* by the parent bus.
|
||||||
|
*/
|
||||||
|
*bus_last = dev;
|
||||||
|
bus_last = &dev->sibling;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* After performing arch-dependent fixup of the bus, look behind
|
||||||
|
* all PCI-to-PCI bridges on this bus.
|
||||||
|
*/
|
||||||
|
for(dev=bus->devices; dev; dev=dev->sibling)
|
||||||
|
/*
|
||||||
|
* If it's a bridge, scan the bus behind it.
|
||||||
|
*/
|
||||||
|
if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
|
||||||
|
unsigned int buses;
|
||||||
|
unsigned int devfn = dev->devfn;
|
||||||
|
unsigned short cr;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Insert it into the tree of buses.
|
||||||
|
*/
|
||||||
|
child = salloc(sizeof(*child));
|
||||||
|
child->next = bus->children;
|
||||||
|
bus->children = child;
|
||||||
|
child->self = dev;
|
||||||
|
child->parent = bus;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set up the primary, secondary and subordinate
|
||||||
|
* bus numbers.
|
||||||
|
*/
|
||||||
|
child->number = child->secondary = ++max;
|
||||||
|
child->primary = bus->secondary;
|
||||||
|
child->subordinate = 0xff;
|
||||||
|
/*
|
||||||
|
* Clear all status bits and turn off memory,
|
||||||
|
* I/O and master enables.
|
||||||
|
*/
|
||||||
|
pcibios_read_config_word(bus->number, devfn, PCI_COMMAND, &cr);
|
||||||
|
pcibios_write_config_word(bus->number, devfn, PCI_COMMAND, 0x0000);
|
||||||
|
pcibios_write_config_word(bus->number, devfn, PCI_STATUS, 0xffff);
|
||||||
|
/*
|
||||||
|
* Read the existing primary/secondary/subordinate bus
|
||||||
|
* number configuration to determine if the PCI bridge
|
||||||
|
* has already been configured by the system. If so,
|
||||||
|
* do not modify the configuration, merely note it.
|
||||||
|
*/
|
||||||
|
pcibios_read_config_dword(bus->number, devfn, PCI_PRIMARY_BUS, &buses);
|
||||||
|
if ((buses & 0xFFFFFF) != 0)
|
||||||
|
{
|
||||||
|
unsigned int cmax;
|
||||||
|
|
||||||
|
child->primary = buses & 0xFF;
|
||||||
|
child->secondary = (buses >> 8) & 0xFF;
|
||||||
|
child->subordinate = (buses >> 16) & 0xFF;
|
||||||
|
child->number = child->secondary;
|
||||||
|
cmax = pci_scan_bus(child);
|
||||||
|
if (cmax > max) max = cmax;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Configure the bus numbers for this bridge:
|
||||||
|
*/
|
||||||
|
buses &= 0xff000000;
|
||||||
|
buses |=
|
||||||
|
(((unsigned int)(child->primary) << 0) |
|
||||||
|
((unsigned int)(child->secondary) << 8) |
|
||||||
|
((unsigned int)(child->subordinate) << 16));
|
||||||
|
pcibios_write_config_dword(bus->number, devfn, PCI_PRIMARY_BUS, buses);
|
||||||
|
/*
|
||||||
|
* Now we can scan all subordinate buses:
|
||||||
|
*/
|
||||||
|
max = pci_scan_bus(child);
|
||||||
|
/*
|
||||||
|
* Set the subordinate bus number to its real
|
||||||
|
* value:
|
||||||
|
*/
|
||||||
|
child->subordinate = max;
|
||||||
|
buses = (buses & 0xff00ffff)
|
||||||
|
| ((unsigned int)(child->subordinate) << 16);
|
||||||
|
pcibios_write_config_dword(bus->number, devfn, PCI_PRIMARY_BUS, buses);
|
||||||
|
}
|
||||||
|
pcibios_write_config_word(bus->number, devfn, PCI_COMMAND, cr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We've scanned the bus and so we know all about what's on
|
||||||
|
* the other side of any bridges that may be on this bus plus
|
||||||
|
* any devices.
|
||||||
|
*
|
||||||
|
* Return how far we've got finding sub-buses.
|
||||||
|
*/
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pci_fixup(void) {
|
||||||
|
struct pci_dev *p;
|
||||||
|
struct pci_bus *bus;
|
||||||
|
for (bus = &pci_root; bus; bus=bus->next) {
|
||||||
|
|
||||||
|
for (p=bus->devices; p; p=p->sibling) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void pci_init(void) {
|
||||||
|
PPC_DEVICE *hostbridge;
|
||||||
|
|
||||||
|
if (pci->last_dev_p) {
|
||||||
|
printk("Two or more calls to pci_init!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pci->last_dev_p = &(bd->pci_devices);
|
||||||
|
hostbridge=residual_find_device(PROCESSORDEVICE, NULL,
|
||||||
|
BridgeController,
|
||||||
|
PCIBridge, -1, 0);
|
||||||
|
if (hostbridge) {
|
||||||
|
if (hostbridge->DeviceId.Interface==PCIBridgeIndirect) {
|
||||||
|
bd->pci_functions=&indirect_functions;
|
||||||
|
/* Should be extracted from residual data,
|
||||||
|
* indeed MPC106 in CHRP mode is different,
|
||||||
|
* but we should not use residual data in
|
||||||
|
* this case anyway.
|
||||||
|
*/
|
||||||
|
pci->config_addr = ((volatile u_int *)
|
||||||
|
(ptr_mem_map->io_base+0xcf8));
|
||||||
|
pci->config_data = ptr_mem_map->io_base+0xcfc;
|
||||||
|
} else if(hostbridge->DeviceId.Interface==PCIBridgeDirect) {
|
||||||
|
bd->pci_functions=&direct_functions;
|
||||||
|
pci->config_data=(u_char *) 0x80800000;
|
||||||
|
} else {
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Let us try by experimentation at our own risk! */
|
||||||
|
u_int id0;
|
||||||
|
bd->pci_functions = &direct_functions;
|
||||||
|
/* On all direct bridges I know the host bridge itself
|
||||||
|
* appears as device 0 function 0.
|
||||||
|
*/
|
||||||
|
pcibios_read_config_dword(0, 0, PCI_VENDOR_ID, &id0);
|
||||||
|
if (id0==~0U) {
|
||||||
|
bd->pci_functions = &indirect_functions;
|
||||||
|
pci->config_addr = ((volatile u_int *)
|
||||||
|
(ptr_mem_map->io_base+0xcf8));
|
||||||
|
pci->config_data = ptr_mem_map->io_base+0xcfc;
|
||||||
|
}
|
||||||
|
/* Here we should check that the host bridge is actually
|
||||||
|
* present, but if it not, we are in such a desperate
|
||||||
|
* situation, that we probably can't even tell it.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
/* Now build a small database of all found PCI devices */
|
||||||
|
printk("\nPCI: Probing PCI hardware\n");
|
||||||
|
pci_root.subordinate=pci_scan_bus(&pci_root);
|
||||||
|
print_pci_resources("Configurable PCI resources:\n");
|
||||||
|
reconfigure_pci();
|
||||||
|
print_pci_resources("Allocated PCI resources:\n");
|
||||||
|
}
|
||||||
|
|
||||||
1159
c/src/lib/libbsp/powerpc/shared/bootloader/pci.h
Normal file
1159
c/src/lib/libbsp/powerpc/shared/bootloader/pci.h
Normal file
File diff suppressed because it is too large
Load Diff
94
c/src/lib/libbsp/powerpc/shared/bootloader/ppcboot.lds
Normal file
94
c/src/lib/libbsp/powerpc/shared/bootloader/ppcboot.lds
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
OUTPUT_ARCH(powerpc)
|
||||||
|
OUTPUT_FORMAT(ppcboot)
|
||||||
|
/* Do we need any of these for elf?
|
||||||
|
__DYNAMIC = 0; */
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
.text :
|
||||||
|
{
|
||||||
|
/* We have to build the header by hand, painful since ppcboot
|
||||||
|
format support is very poor in binutils.
|
||||||
|
objdump -b ppcboot zImage --all-headers can be used to check. */
|
||||||
|
/* The following line can be added as a branch to use the same image
|
||||||
|
* for netboot as for prepboots, the only problem is that objdump
|
||||||
|
* did not in this case recognize the format since it insisted
|
||||||
|
* in checking the x86 code area held only zeroes.
|
||||||
|
*/
|
||||||
|
LONG(0x48000000+start);
|
||||||
|
. = 0x1be; BYTE(0x80); BYTE(0)
|
||||||
|
BYTE(2); BYTE(0); BYTE(0x41); BYTE(1);
|
||||||
|
BYTE(0x12); BYTE(0x4f); LONG(0);
|
||||||
|
BYTE(((_edata + 0x1ff)>>9)&0xff);
|
||||||
|
BYTE(((_edata + 0x1ff)>>17)&0xff);
|
||||||
|
BYTE(((_edata + 0x1ff)>>25)&0xff);
|
||||||
|
. = 0x1fe;
|
||||||
|
BYTE(0x55);
|
||||||
|
BYTE(0xaa);
|
||||||
|
BYTE(start&0xff);
|
||||||
|
BYTE((start>>8)&0xff);
|
||||||
|
BYTE((start>>16)&0xff);
|
||||||
|
BYTE((start>>24)&0xff);
|
||||||
|
BYTE(_edata&0xff);
|
||||||
|
BYTE((_edata>>8)&0xff);
|
||||||
|
BYTE((_edata>>16)&0xff);
|
||||||
|
BYTE((_edata>>24)&0xff);
|
||||||
|
BYTE(0); /* flags */
|
||||||
|
BYTE(0); /* os_id */
|
||||||
|
BYTE(0x4C); BYTE(0x69); BYTE(0x6e);
|
||||||
|
BYTE(0x75); BYTE(0x78); /* Partition name */
|
||||||
|
. = 0x400;
|
||||||
|
*(.text)
|
||||||
|
*(.sdata2)
|
||||||
|
*(.rodata)
|
||||||
|
}
|
||||||
|
/* . = ALIGN(16); */
|
||||||
|
.image :
|
||||||
|
{
|
||||||
|
rtems.gz(*)
|
||||||
|
. = ALIGN(4);
|
||||||
|
*.gz(*)
|
||||||
|
}
|
||||||
|
/* Read-write section, merged into data segment: */
|
||||||
|
/* . = ALIGN(4096); */
|
||||||
|
.reloc :
|
||||||
|
{
|
||||||
|
*(.got)
|
||||||
|
_GOT2_TABLE_ = .;
|
||||||
|
*(.got2)
|
||||||
|
_FIXUP_TABLE_ = .;
|
||||||
|
*(.fixup)
|
||||||
|
}
|
||||||
|
|
||||||
|
__got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >>2;
|
||||||
|
__fixup_entries = (. - _FIXUP_TABLE_)>>2;
|
||||||
|
|
||||||
|
.handlers :
|
||||||
|
{
|
||||||
|
*(.exception)
|
||||||
|
}
|
||||||
|
|
||||||
|
.data :
|
||||||
|
{
|
||||||
|
*(.data)
|
||||||
|
*(.sdata)
|
||||||
|
. = ALIGN(4);
|
||||||
|
_edata = .;
|
||||||
|
}
|
||||||
|
PROVIDE(_binary_initrd_gz_start = 0);
|
||||||
|
PROVIDE(_binary_initrd_gz_end = 0);
|
||||||
|
_rtems_gz_size = _binary_rtems_gz_end - _binary_rtems_gz_start;
|
||||||
|
_rtems_size = __rtems_end - __rtems_start;
|
||||||
|
.bss :
|
||||||
|
{
|
||||||
|
*(.sbss)
|
||||||
|
*(.bss)
|
||||||
|
. = ALIGN(4);
|
||||||
|
}
|
||||||
|
__bss_words = SIZEOF(.bss)>>2;
|
||||||
|
__size = . ;
|
||||||
|
/DISCARD/ :
|
||||||
|
{
|
||||||
|
*(.comment)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
2143
c/src/lib/libbsp/powerpc/shared/bootloader/zlib.c
Normal file
2143
c/src/lib/libbsp/powerpc/shared/bootloader/zlib.c
Normal file
File diff suppressed because it is too large
Load Diff
438
c/src/lib/libbsp/powerpc/shared/bootloader/zlib.h
Normal file
438
c/src/lib/libbsp/powerpc/shared/bootloader/zlib.h
Normal file
@@ -0,0 +1,438 @@
|
|||||||
|
/* $Id$ */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is derived from zlib.h and zconf.h from the zlib-0.95
|
||||||
|
* distribution by Jean-loup Gailly and Mark Adler, with some additions
|
||||||
|
* by Paul Mackerras to aid in implementing Deflate compression and
|
||||||
|
* decompression for PPP packets.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ==FILEVERSION 960122==
|
||||||
|
*
|
||||||
|
* This marker is used by the Linux installation script to determine
|
||||||
|
* whether an up-to-date version of this file is already installed.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* zlib.h -- interface of the 'zlib' general purpose compression library
|
||||||
|
version 0.95, Aug 16th, 1995.
|
||||||
|
|
||||||
|
Copyright (C) 1995 Jean-loup Gailly and Mark Adler
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
|
||||||
|
Jean-loup Gailly Mark Adler
|
||||||
|
gzip@prep.ai.mit.edu madler@alumni.caltech.edu
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _ZLIB_H
|
||||||
|
#define _ZLIB_H
|
||||||
|
|
||||||
|
#define local
|
||||||
|
#ifdef DEBUG_ZLIB
|
||||||
|
#include <bsp/consoleIo.h>
|
||||||
|
#define fprintf printk
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* #include "zconf.h" */ /* included directly here */
|
||||||
|
|
||||||
|
/* zconf.h -- configuration of the zlib compression library
|
||||||
|
* Copyright (C) 1995 Jean-loup Gailly.
|
||||||
|
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* From: zconf.h,v 1.12 1995/05/03 17:27:12 jloup Exp */
|
||||||
|
|
||||||
|
/*
|
||||||
|
The library does not install any signal handler. It is recommended to
|
||||||
|
add at least a handler for SIGSEGV when decompressing; the library checks
|
||||||
|
the consistency of the input data whenever possible but may go nuts
|
||||||
|
for some forms of corrupted input.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compile with -DMAXSEG_64K if the alloc function cannot allocate more
|
||||||
|
* than 64k bytes at a time (needed on systems with 16-bit int).
|
||||||
|
* Compile with -DUNALIGNED_OK if it is OK to access shorts or ints
|
||||||
|
* at addresses which are not a multiple of their size.
|
||||||
|
* Under DOS, -DFAR=far or -DFAR=__far may be needed.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STDC
|
||||||
|
# if defined(MSDOS) || defined(__STDC__) || defined(__cplusplus)
|
||||||
|
# define STDC
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __MWERKS__ /* Metrowerks CodeWarrior declares fileno() in unix.h */
|
||||||
|
# include <unix.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Maximum value for memLevel in deflateInit2 */
|
||||||
|
#ifndef MAX_MEM_LEVEL
|
||||||
|
# ifdef MAXSEG_64K
|
||||||
|
# define MAX_MEM_LEVEL 8
|
||||||
|
# else
|
||||||
|
# define MAX_MEM_LEVEL 9
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef FAR
|
||||||
|
# define FAR
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Maximum value for windowBits in deflateInit2 and inflateInit2 */
|
||||||
|
#ifndef MAX_WBITS
|
||||||
|
# define MAX_WBITS 15 /* 32K LZ77 window */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* The memory requirements for deflate are (in bytes):
|
||||||
|
1 << (windowBits+2) + 1 << (memLevel+9)
|
||||||
|
that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values)
|
||||||
|
plus a few kilobytes for small objects. For example, if you want to reduce
|
||||||
|
the default memory requirements from 256K to 128K, compile with
|
||||||
|
make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
|
||||||
|
Of course this will generally degrade compression (there's no free lunch).
|
||||||
|
|
||||||
|
The memory requirements for inflate are (in bytes) 1 << windowBits
|
||||||
|
that is, 32K for windowBits=15 (default value) plus a few kilobytes
|
||||||
|
for small objects.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Type declarations */
|
||||||
|
|
||||||
|
#ifndef OF /* function prototypes */
|
||||||
|
# ifdef STDC
|
||||||
|
# define OF(args) args
|
||||||
|
# else
|
||||||
|
# define OF(args) ()
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef unsigned char Byte; /* 8 bits */
|
||||||
|
typedef unsigned int uInt; /* 16 bits or more */
|
||||||
|
typedef unsigned long uLong; /* 32 bits or more */
|
||||||
|
|
||||||
|
typedef Byte FAR Bytef;
|
||||||
|
typedef char FAR charf;
|
||||||
|
typedef int FAR intf;
|
||||||
|
typedef uInt FAR uIntf;
|
||||||
|
typedef uLong FAR uLongf;
|
||||||
|
|
||||||
|
#ifdef STDC
|
||||||
|
typedef void FAR *voidpf;
|
||||||
|
typedef void *voidp;
|
||||||
|
#else
|
||||||
|
typedef Byte FAR *voidpf;
|
||||||
|
typedef Byte *voidp;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* end of original zconf.h */
|
||||||
|
|
||||||
|
#define ZLIB_VERSION "0.95P"
|
||||||
|
|
||||||
|
/*
|
||||||
|
The 'zlib' compression library provides in-memory compression and
|
||||||
|
decompression functions, including integrity checks of the uncompressed
|
||||||
|
data. This version of the library supports only one compression method
|
||||||
|
(deflation) but other algorithms may be added later and will have the same
|
||||||
|
stream interface.
|
||||||
|
|
||||||
|
For compression the application must provide the output buffer and
|
||||||
|
may optionally provide the input buffer for optimization. For decompression,
|
||||||
|
the application must provide the input buffer and may optionally provide
|
||||||
|
the output buffer for optimization.
|
||||||
|
|
||||||
|
Compression can be done in a single step if the buffers are large
|
||||||
|
enough (for example if an input file is mmap'ed), or can be done by
|
||||||
|
repeated calls of the compression function. In the latter case, the
|
||||||
|
application must provide more input and/or consume the output
|
||||||
|
(providing more output space) before each call.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
|
||||||
|
typedef void (*free_func) OF((voidpf opaque, voidpf address, uInt nbytes));
|
||||||
|
|
||||||
|
struct internal_state;
|
||||||
|
|
||||||
|
typedef struct z_stream_s {
|
||||||
|
Bytef *next_in; /* next input byte */
|
||||||
|
uInt avail_in; /* number of bytes available at next_in */
|
||||||
|
uLong total_in; /* total nb of input bytes read so far */
|
||||||
|
|
||||||
|
Bytef *next_out; /* next output byte should be put there */
|
||||||
|
uInt avail_out; /* remaining free space at next_out */
|
||||||
|
uLong total_out; /* total nb of bytes output so far */
|
||||||
|
|
||||||
|
char *msg; /* last error message, NULL if no error */
|
||||||
|
struct internal_state FAR *state; /* not visible by applications */
|
||||||
|
|
||||||
|
alloc_func zalloc; /* used to allocate the internal state */
|
||||||
|
free_func zfree; /* used to free the internal state */
|
||||||
|
voidp opaque; /* private data object passed to zalloc and zfree */
|
||||||
|
|
||||||
|
Byte data_type; /* best guess about the data type: ascii or binary */
|
||||||
|
|
||||||
|
} z_stream;
|
||||||
|
|
||||||
|
/*
|
||||||
|
The application must update next_in and avail_in when avail_in has
|
||||||
|
dropped to zero. It must update next_out and avail_out when avail_out
|
||||||
|
has dropped to zero. The application must initialize zalloc, zfree and
|
||||||
|
opaque before calling the init function. All other fields are set by the
|
||||||
|
compression library and must not be updated by the application.
|
||||||
|
|
||||||
|
The opaque value provided by the application will be passed as the first
|
||||||
|
parameter for calls of zalloc and zfree. This can be useful for custom
|
||||||
|
memory management. The compression library attaches no meaning to the
|
||||||
|
opaque value.
|
||||||
|
|
||||||
|
zalloc must return Z_NULL if there is not enough memory for the object.
|
||||||
|
On 16-bit systems, the functions zalloc and zfree must be able to allocate
|
||||||
|
exactly 65536 bytes, but will not be required to allocate more than this
|
||||||
|
if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
|
||||||
|
pointers returned by zalloc for objects of exactly 65536 bytes *must*
|
||||||
|
have their offset normalized to zero. The default allocation function
|
||||||
|
provided by this library ensures this (see zutil.c). To reduce memory
|
||||||
|
requirements and avoid any allocation of 64K objects, at the expense of
|
||||||
|
compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
|
||||||
|
|
||||||
|
The fields total_in and total_out can be used for statistics or
|
||||||
|
progress reports. After compression, total_in holds the total size of
|
||||||
|
the uncompressed data and may be saved for use in the decompressor
|
||||||
|
(particularly if the decompressor wants to decompress everything in
|
||||||
|
a single step).
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* constants */
|
||||||
|
|
||||||
|
#define Z_NO_FLUSH 0
|
||||||
|
#define Z_PARTIAL_FLUSH 1
|
||||||
|
#define Z_FULL_FLUSH 2
|
||||||
|
#define Z_SYNC_FLUSH 3 /* experimental: partial_flush + byte align */
|
||||||
|
#define Z_FINISH 4
|
||||||
|
#define Z_PACKET_FLUSH 5
|
||||||
|
/* See deflate() below for the usage of these constants */
|
||||||
|
|
||||||
|
#define Z_OK 0
|
||||||
|
#define Z_STREAM_END 1
|
||||||
|
#define Z_ERRNO (-1)
|
||||||
|
#define Z_STREAM_ERROR (-2)
|
||||||
|
#define Z_DATA_ERROR (-3)
|
||||||
|
#define Z_MEM_ERROR (-4)
|
||||||
|
#define Z_BUF_ERROR (-5)
|
||||||
|
/* error codes for the compression/decompression functions */
|
||||||
|
|
||||||
|
#define Z_BEST_SPEED 1
|
||||||
|
#define Z_BEST_COMPRESSION 9
|
||||||
|
#define Z_DEFAULT_COMPRESSION (-1)
|
||||||
|
/* compression levels */
|
||||||
|
|
||||||
|
#define Z_FILTERED 1
|
||||||
|
#define Z_HUFFMAN_ONLY 2
|
||||||
|
#define Z_DEFAULT_STRATEGY 0
|
||||||
|
|
||||||
|
#define Z_BINARY 0
|
||||||
|
#define Z_ASCII 1
|
||||||
|
#define Z_UNKNOWN 2
|
||||||
|
/* Used to set the data_type field */
|
||||||
|
|
||||||
|
#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */
|
||||||
|
|
||||||
|
extern char *zlib_version;
|
||||||
|
/* The application can compare zlib_version and ZLIB_VERSION for consistency.
|
||||||
|
If the first character differs, the library code actually used is
|
||||||
|
not compatible with the zlib.h header file used by the application.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* basic functions */
|
||||||
|
|
||||||
|
extern int inflateInit OF((z_stream *strm));
|
||||||
|
/*
|
||||||
|
Initializes the internal stream state for decompression. The fields
|
||||||
|
zalloc and zfree must be initialized before by the caller. If zalloc and
|
||||||
|
zfree are set to Z_NULL, inflateInit updates them to use default allocation
|
||||||
|
functions.
|
||||||
|
|
||||||
|
inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
|
||||||
|
enough memory. msg is set to null if there is no error message.
|
||||||
|
inflateInit does not perform any decompression: this will be done by
|
||||||
|
inflate().
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
extern int inflate OF((z_stream *strm, int flush));
|
||||||
|
/*
|
||||||
|
Performs one or both of the following actions:
|
||||||
|
|
||||||
|
- Decompress more input starting at next_in and update next_in and avail_in
|
||||||
|
accordingly. If not all input can be processed (because there is not
|
||||||
|
enough room in the output buffer), next_in is updated and processing
|
||||||
|
will resume at this point for the next call of inflate().
|
||||||
|
|
||||||
|
- Provide more output starting at next_out and update next_out and avail_out
|
||||||
|
accordingly. inflate() always provides as much output as possible
|
||||||
|
(until there is no more input data or no more space in the output buffer).
|
||||||
|
|
||||||
|
Before the call of inflate(), the application should ensure that at least
|
||||||
|
one of the actions is possible, by providing more input and/or consuming
|
||||||
|
more output, and updating the next_* and avail_* values accordingly.
|
||||||
|
The application can consume the uncompressed output when it wants, for
|
||||||
|
example when the output buffer is full (avail_out == 0), or after each
|
||||||
|
call of inflate().
|
||||||
|
|
||||||
|
If the parameter flush is set to Z_PARTIAL_FLUSH or Z_PACKET_FLUSH,
|
||||||
|
inflate flushes as much output as possible to the output buffer. The
|
||||||
|
flushing behavior of inflate is not specified for values of the flush
|
||||||
|
parameter other than Z_PARTIAL_FLUSH, Z_PACKET_FLUSH or Z_FINISH, but the
|
||||||
|
current implementation actually flushes as much output as possible
|
||||||
|
anyway. For Z_PACKET_FLUSH, inflate checks that once all the input data
|
||||||
|
has been consumed, it is expecting to see the length field of a stored
|
||||||
|
block; if not, it returns Z_DATA_ERROR.
|
||||||
|
|
||||||
|
inflate() should normally be called until it returns Z_STREAM_END or an
|
||||||
|
error. However if all decompression is to be performed in a single step
|
||||||
|
(a single call of inflate), the parameter flush should be set to
|
||||||
|
Z_FINISH. In this case all pending input is processed and all pending
|
||||||
|
output is flushed; avail_out must be large enough to hold all the
|
||||||
|
uncompressed data. (The size of the uncompressed data may have been saved
|
||||||
|
by the compressor for this purpose.) The next operation on this stream must
|
||||||
|
be inflateEnd to deallocate the decompression state. The use of Z_FINISH
|
||||||
|
is never required, but can be used to inform inflate that a faster routine
|
||||||
|
may be used for the single inflate() call.
|
||||||
|
|
||||||
|
inflate() returns Z_OK if some progress has been made (more input
|
||||||
|
processed or more output produced), Z_STREAM_END if the end of the
|
||||||
|
compressed data has been reached and all uncompressed output has been
|
||||||
|
produced, Z_DATA_ERROR if the input data was corrupted, Z_STREAM_ERROR if
|
||||||
|
the stream structure was inconsistent (for example if next_in or next_out
|
||||||
|
was NULL), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if no
|
||||||
|
progress is possible or if there was not enough room in the output buffer
|
||||||
|
when Z_FINISH is used. In the Z_DATA_ERROR case, the application may then
|
||||||
|
call inflateSync to look for a good compression block. */
|
||||||
|
|
||||||
|
|
||||||
|
extern int inflateEnd OF((z_stream *strm));
|
||||||
|
/*
|
||||||
|
All dynamically allocated data structures for this stream are freed.
|
||||||
|
This function discards any unprocessed input and does not flush any
|
||||||
|
pending output.
|
||||||
|
|
||||||
|
inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
|
||||||
|
was inconsistent. In the error case, msg may be set but then points to a
|
||||||
|
static string (which must not be deallocated).
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* advanced functions */
|
||||||
|
|
||||||
|
extern int inflateInit2 OF((z_stream *strm,
|
||||||
|
int windowBits));
|
||||||
|
/*
|
||||||
|
This is another version of inflateInit with more compression options. The
|
||||||
|
fields next_out, zalloc and zfree must be initialized before by the caller.
|
||||||
|
|
||||||
|
The windowBits parameter is the base two logarithm of the maximum window
|
||||||
|
size (the size of the history buffer). It should be in the range 8..15 for
|
||||||
|
this version of the library (the value 16 will be allowed soon). The
|
||||||
|
default value is 15 if inflateInit is used instead. If a compressed stream
|
||||||
|
with a larger window size is given as input, inflate() will return with
|
||||||
|
the error code Z_DATA_ERROR instead of trying to allocate a larger window.
|
||||||
|
|
||||||
|
If next_out is not null, the library will use this buffer for the history
|
||||||
|
buffer; the buffer must either be large enough to hold the entire output
|
||||||
|
data, or have at least 1<<windowBits bytes. If next_out is null, the
|
||||||
|
library will allocate its own buffer (and leave next_out null). next_in
|
||||||
|
need not be provided here but must be provided by the application for the
|
||||||
|
next call of inflate().
|
||||||
|
|
||||||
|
If the history buffer is provided by the application, next_out must
|
||||||
|
never be changed by the application since the decompressor maintains
|
||||||
|
history information inside this buffer from call to call; the application
|
||||||
|
can only reset next_out to the beginning of the history buffer when
|
||||||
|
avail_out is zero and all output has been consumed.
|
||||||
|
|
||||||
|
inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was
|
||||||
|
not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as
|
||||||
|
windowBits < 8). msg is set to null if there is no error message.
|
||||||
|
inflateInit2 does not perform any decompression: this will be done by
|
||||||
|
inflate().
|
||||||
|
*/
|
||||||
|
|
||||||
|
extern int inflateSync OF((z_stream *strm));
|
||||||
|
/*
|
||||||
|
Skips invalid compressed data until the special marker (see deflate()
|
||||||
|
above) can be found, or until all available input is skipped. No output
|
||||||
|
is provided.
|
||||||
|
|
||||||
|
inflateSync returns Z_OK if the special marker has been found, Z_BUF_ERROR
|
||||||
|
if no more input was provided, Z_DATA_ERROR if no marker has been found,
|
||||||
|
or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
|
||||||
|
case, the application may save the current current value of total_in which
|
||||||
|
indicates where valid compressed data was found. In the error case, the
|
||||||
|
application may repeatedly call inflateSync, providing more input each time,
|
||||||
|
until success or end of the input data.
|
||||||
|
*/
|
||||||
|
|
||||||
|
extern int inflateReset OF((z_stream *strm));
|
||||||
|
/*
|
||||||
|
This function is equivalent to inflateEnd followed by inflateInit,
|
||||||
|
but does not free and reallocate all the internal decompression state.
|
||||||
|
The stream will keep attributes that may have been set by inflateInit2.
|
||||||
|
|
||||||
|
inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
|
||||||
|
stream state was inconsistent (such as zalloc or state being NULL).
|
||||||
|
*/
|
||||||
|
|
||||||
|
extern int inflateIncomp OF((z_stream *strm));
|
||||||
|
/*
|
||||||
|
This function adds the data at next_in (avail_in bytes) to the output
|
||||||
|
history without performing any output. There must be no pending output,
|
||||||
|
and the decompressor must be expecting to see the start of a block.
|
||||||
|
Calling this function is equivalent to decompressing a stored block
|
||||||
|
containing the data at next_in (except that the data is not output).
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* checksum functions */
|
||||||
|
|
||||||
|
/*
|
||||||
|
This function is not related to compression but is exported
|
||||||
|
anyway because it might be useful in applications using the
|
||||||
|
compression library.
|
||||||
|
*/
|
||||||
|
|
||||||
|
extern uLong adler32 OF((uLong adler, Bytef *buf, uInt len));
|
||||||
|
|
||||||
|
/*
|
||||||
|
Update a running Adler-32 checksum with the bytes buf[0..len-1] and
|
||||||
|
return the updated checksum. If buf is NULL, this function returns
|
||||||
|
the required initial value for the checksum.
|
||||||
|
An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
|
||||||
|
much faster. Usage example:
|
||||||
|
|
||||||
|
uLong adler = adler32(0L, Z_NULL, 0);
|
||||||
|
|
||||||
|
while (read_buffer(buffer, length) != EOF) {
|
||||||
|
adler = adler32(adler, buffer, length);
|
||||||
|
}
|
||||||
|
if (adler != original_adler) error();
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _Z_UTIL_H
|
||||||
|
struct internal_state {int dummy;}; /* hack for buggy compilers */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _ZLIB_H */
|
||||||
38
c/src/lib/libbsp/powerpc/shared/clock/Makefile.in
Normal file
38
c/src/lib/libbsp/powerpc/shared/clock/Makefile.in
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
#
|
||||||
|
# $Id$
|
||||||
|
#
|
||||||
|
|
||||||
|
@SET_MAKE@
|
||||||
|
srcdir = @srcdir@
|
||||||
|
top_srcdir = @top_srcdir@
|
||||||
|
top_builddir = ../../..
|
||||||
|
subdir = powerpc/shared/clock
|
||||||
|
|
||||||
|
RTEMS_ROOT = @RTEMS_ROOT@
|
||||||
|
PROJECT_ROOT = @PROJECT_ROOT@
|
||||||
|
|
||||||
|
VPATH = @srcdir@
|
||||||
|
|
||||||
|
H_FILES =
|
||||||
|
|
||||||
|
SRCS = $(C_FILES) $(H_FILES)
|
||||||
|
|
||||||
|
include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
|
||||||
|
include $(RTEMS_ROOT)/make/leaf.cfg
|
||||||
|
|
||||||
|
INSTALL_CHANGE = @INSTALL_CHANGE@
|
||||||
|
mkinstalldirs = $(SHELL) $(top_srcdir)/@RTEMS_TOPdir@/mkinstalldirs
|
||||||
|
|
||||||
|
INSTALLDIRS = $(PROJECT_INCLUDE)/bsp
|
||||||
|
|
||||||
|
$(INSTALLDIRS):
|
||||||
|
@$(mkinstalldirs) $(INSTALLDIRS)
|
||||||
|
|
||||||
|
all: ${ARCH} $(SRCS)
|
||||||
|
|
||||||
|
# the .rel file built here will be put into libbsp.a by ../wrapup/Makefile
|
||||||
|
install: all
|
||||||
|
|
||||||
|
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||||
|
cd $(top_builddir) \
|
||||||
|
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
|
||||||
37
c/src/lib/libbsp/powerpc/shared/clock/p_clock.c
Normal file
37
c/src/lib/libbsp/powerpc/shared/clock/p_clock.c
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* Clock Tick interrupt conexion code.
|
||||||
|
*
|
||||||
|
* COPYRIGHT (c) 1989-1997.
|
||||||
|
* On-Line Applications Research Corporation (OAR).
|
||||||
|
* Copyright assigned to U.S. Government, 1994.
|
||||||
|
*
|
||||||
|
* The license and distribution terms for this file may in
|
||||||
|
* the file LICENSE in this distribution or at
|
||||||
|
* http://www.OARcorp.com/rtems/license.html.
|
||||||
|
*
|
||||||
|
* Modified to support the MPC750.
|
||||||
|
* Modifications Copyright (c) 1999 Eric Valette valette@crf.canon.fr
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <bsp.h>
|
||||||
|
#include <bsp/irq.h>
|
||||||
|
#include <libcpu/c_clock.h>
|
||||||
|
|
||||||
|
static rtems_irq_connect_data clockIrqData = {BSP_DECREMENTER,
|
||||||
|
clockIsr,
|
||||||
|
(rtems_irq_enable)clockOn,
|
||||||
|
(rtems_irq_disable)clockOff,
|
||||||
|
(rtems_irq_is_enabled) clockIsOn};
|
||||||
|
|
||||||
|
|
||||||
|
int BSP_disconnect_clock_handler (void)
|
||||||
|
{
|
||||||
|
return BSP_remove_rtems_irq_handler (&clockIrqData);
|
||||||
|
}
|
||||||
|
|
||||||
|
int BSP_connect_clock_handler (void)
|
||||||
|
{
|
||||||
|
return BSP_install_rtems_irq_handler (&clockIrqData);
|
||||||
|
}
|
||||||
48
c/src/lib/libbsp/powerpc/shared/console/Makefile.in
Normal file
48
c/src/lib/libbsp/powerpc/shared/console/Makefile.in
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
#
|
||||||
|
# $Id:
|
||||||
|
#
|
||||||
|
|
||||||
|
@SET_MAKE@
|
||||||
|
srcdir = @srcdir@
|
||||||
|
top_srcdir = @top_srcdir@
|
||||||
|
top_builddir = ../../..
|
||||||
|
subdir = powerpc/shared/console
|
||||||
|
|
||||||
|
RTEMS_ROOT = @RTEMS_ROOT@
|
||||||
|
PROJECT_ROOT = @PROJECT_ROOT@
|
||||||
|
|
||||||
|
VPATH = @srcdir@:@srcdir@/../../../shared
|
||||||
|
|
||||||
|
# C source names, if any, go here -- minus the .c
|
||||||
|
H_FILES = $(srcdir)/consoleIo.h $(srcdir)/keyboard.h $(srcdir)/uart.h
|
||||||
|
|
||||||
|
SRCS = $(C_FILES) $(CC_FILES) $(H_FILES) $(S_FILES)
|
||||||
|
|
||||||
|
include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
|
||||||
|
include $(RTEMS_ROOT)/make/leaf.cfg
|
||||||
|
|
||||||
|
INSTALL_CHANGE = @INSTALL_CHANGE@
|
||||||
|
mkinstalldirs = $(SHELL) $(top_srcdir)/@RTEMS_TOPdir@/mkinstalldirs
|
||||||
|
|
||||||
|
INSTALLDIRS = $(PROJECT_INCLUDE)/bsp
|
||||||
|
|
||||||
|
$(INSTALLDIRS):
|
||||||
|
@$(mkinstalldirs) $(INSTALLDIRS)
|
||||||
|
|
||||||
|
#
|
||||||
|
# Add your list of files to delete here. The config files
|
||||||
|
# already know how to delete some stuff, so you may want
|
||||||
|
|
||||||
|
# to just run 'make clean' first to see what gets missed.
|
||||||
|
# 'make clobber' already includes 'make clean'
|
||||||
|
#
|
||||||
|
|
||||||
|
preinstall:
|
||||||
|
@$(mkinstalldirs) $(PROJECT_INCLUDE)/bsp
|
||||||
|
@$(INSTALL_CHANGE) -m 644 $(H_FILES) $(PROJECT_INCLUDE)/bsp
|
||||||
|
|
||||||
|
all: ${ARCH} $(SRCS) preinstall
|
||||||
|
|
||||||
|
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||||
|
cd $(top_builddir) \
|
||||||
|
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
|
||||||
@@ -45,10 +45,10 @@ extern int close(int fd);
|
|||||||
* BSP_UART_COM2
|
* BSP_UART_COM2
|
||||||
*/
|
*/
|
||||||
|
|
||||||
extern int BSPConsolePort;
|
int BSPConsolePort = BSP_UART_COM1;
|
||||||
|
|
||||||
/* int BSPConsolePort = BSP_UART_COM2; */
|
/* int BSPConsolePort = BSP_UART_COM2; */
|
||||||
extern int BSPBaseBaud;
|
int BSPBaseBaud = 115200;
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------+
|
/*-------------------------------------------------------------------------+
|
||||||
| External Prototypes
|
| External Prototypes
|
||||||
@@ -84,7 +84,6 @@ isr_is_on(const rtems_irq_connect_data *irq)
|
|||||||
return BSP_irq_enabled_at_i8259s(irq->name);
|
return BSP_irq_enabled_at_i8259s(irq->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
void console_reserve_resources(rtems_configuration_table *conf)
|
void console_reserve_resources(rtems_configuration_table *conf)
|
||||||
{
|
{
|
||||||
if(BSPConsolePort != BSP_CONSOLE_PORT_CONSOLE)
|
if(BSPConsolePort != BSP_CONSOLE_PORT_CONSOLE)
|
||||||
@@ -94,7 +93,6 @@ void console_reserve_resources(rtems_configuration_table *conf)
|
|||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
void __assert (const char *file, int line, const char *msg)
|
void __assert (const char *file, int line, const char *msg)
|
||||||
{
|
{
|
||||||
45
c/src/lib/libbsp/powerpc/shared/console/consoleIo.h
Normal file
45
c/src/lib/libbsp/powerpc/shared/console/consoleIo.h
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* consoleIo.h -- console I/O package interface
|
||||||
|
*
|
||||||
|
* Copyright (C) 1999 Eric Valette. valette@crf.canon.fr
|
||||||
|
*
|
||||||
|
* The license and distribution terms for this file may be
|
||||||
|
* found in found in the file LICENSE in this distribution or at
|
||||||
|
* http://www.OARcorp.com/rtems/license.html.
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __CONSOLE_IO_H
|
||||||
|
#define __CONSOLE_IO_H
|
||||||
|
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
CONSOLE_LOG = 1,
|
||||||
|
CONSOLE_SERIAL = 2,
|
||||||
|
CONSOLE_VGA = 3,
|
||||||
|
CONSOLE_VACUUM = 4
|
||||||
|
}ioType;
|
||||||
|
|
||||||
|
typedef volatile unsigned char * __io_ptr;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
__io_ptr io_base;
|
||||||
|
__io_ptr isa_mem_base;
|
||||||
|
__io_ptr pci_mmio_base;
|
||||||
|
__io_ptr pci_dma_offset;
|
||||||
|
} board_memory_map;
|
||||||
|
|
||||||
|
extern board_memory_map *ptr_mem_map;
|
||||||
|
extern unsigned long ticks_per_ms;
|
||||||
|
|
||||||
|
extern int select_console(ioType t);
|
||||||
|
extern int printk(const char *, ...) __attribute__((format(printf, 1, 2)));
|
||||||
|
extern void udelay(int);
|
||||||
|
extern void debug_putc(const unsigned char c);
|
||||||
|
extern int debug_getc(void);
|
||||||
|
extern int debug_tstc(void);
|
||||||
|
int kbdreset(void);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
318
c/src/lib/libbsp/powerpc/shared/console/inch.c
Normal file
318
c/src/lib/libbsp/powerpc/shared/console/inch.c
Normal file
@@ -0,0 +1,318 @@
|
|||||||
|
/*
|
||||||
|
* inch.c -- keyboard minimal driver
|
||||||
|
*
|
||||||
|
* Copyright (C) 1999 Eric Valette. valette@crf.canon.fr
|
||||||
|
*
|
||||||
|
* This code is based on the pc386 BSP inch.c so the following
|
||||||
|
* copyright also applies :
|
||||||
|
*
|
||||||
|
* (C) Copyright 1997 -
|
||||||
|
* - NavIST Group - Real-Time Distributed Systems and Industrial Automation
|
||||||
|
*
|
||||||
|
* http://pandora.ist.utl.pt
|
||||||
|
*
|
||||||
|
* Instituto Superior Tecnico * Lisboa * PORTUGAL
|
||||||
|
* The license and distribution terms for this file may be
|
||||||
|
* found in found in the file LICENSE in this distribution or at
|
||||||
|
* http://www.OARcorp.com/rtems/license.html.
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <bsp.h>
|
||||||
|
#include <bsp/irq.h>
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------+
|
||||||
|
| Constants
|
||||||
|
+--------------------------------------------------------------------------*/
|
||||||
|
#define KBD_CTL 0x61 /* -------------------------------- */
|
||||||
|
#define KBD_DATA 0x60 /* Ports for PC keyboard controller */
|
||||||
|
#define KBD_STATUS 0x64 /* -------------------------------- */
|
||||||
|
|
||||||
|
#define KBD_BUF_SIZE 256
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------+
|
||||||
|
| Global Variables
|
||||||
|
+--------------------------------------------------------------------------*/
|
||||||
|
static char key_map[] =
|
||||||
|
{
|
||||||
|
0,033,'1','2','3','4','5','6','7','8','9','0','-','=','\b','\t',
|
||||||
|
'q','w','e','r','t','y','u','i','o','p','[',']',015,0x80,
|
||||||
|
'a','s','d','f','g','h','j','k','l',';',047,0140,0x80,
|
||||||
|
0134,'z','x','c','v','b','n','m',',','.','/',0x80,
|
||||||
|
'*',0x80,' ',0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
|
||||||
|
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
|
||||||
|
0x80,0x80,0x80,'0',0177
|
||||||
|
}; /* Keyboard scancode -> character map with no modifiers. */
|
||||||
|
|
||||||
|
static char shift_map[] =
|
||||||
|
{
|
||||||
|
0,033,'!','@','#','$','%','^','&','*','(',')','_','+','\b','\t',
|
||||||
|
'Q','W','E','R','T','Y','U','I','O','P','{','}',015,0x80,
|
||||||
|
'A','S','D','F','G','H','J','K','L',':',042,'~',0x80,
|
||||||
|
'|','Z','X','C','V','B','N','M','<','>','?',0x80,
|
||||||
|
'*',0x80,' ',0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
|
||||||
|
0x80,0x80,0x80,0x80,'7','8','9',0x80,'4','5','6',0x80,
|
||||||
|
'1','2','3','0',177
|
||||||
|
}; /* Keyboard scancode -> character map with SHIFT key modifier. */
|
||||||
|
|
||||||
|
static char kbd_buffer[KBD_BUF_SIZE];
|
||||||
|
static rtems_unsigned16 kbd_first = 0;
|
||||||
|
static rtems_unsigned16 kbd_last = 0;
|
||||||
|
static rtems_unsigned16 kbd_end = KBD_BUF_SIZE - 1;
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------+
|
||||||
|
| Function: rtemsReboot
|
||||||
|
| Description: Reboot the PC.
|
||||||
|
| Global Variables: None.
|
||||||
|
| Arguments: None.
|
||||||
|
| Returns: Nothing.
|
||||||
|
+--------------------------------------------------------------------------*/
|
||||||
|
void rtemsReboot(void)
|
||||||
|
{
|
||||||
|
/* shutdown and reboot */
|
||||||
|
outport_byte(0x64, 0xFE); /* use keyboard controler to do the job... */
|
||||||
|
} /* rtemsReboot */
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------+
|
||||||
|
| Function: _IBMPC_scankey
|
||||||
|
| Description: This function can be called during a poll for input, or by
|
||||||
|
| an ISR. Basically any time you want to process a keypress.
|
||||||
|
| Global Variables: key_map, shift_map.
|
||||||
|
| Arguments: outChar - character read in case of a valid reading,
|
||||||
|
| otherwise unchanged.
|
||||||
|
| Returns: TRUE in case a valid character has been read,
|
||||||
|
| FALSE otherwise.
|
||||||
|
+--------------------------------------------------------------------------*/
|
||||||
|
rtems_boolean
|
||||||
|
_IBMPC_scankey(char *outChar)
|
||||||
|
{
|
||||||
|
unsigned char inChar;
|
||||||
|
static int alt_pressed = 0;
|
||||||
|
static int ctrl_pressed = 0;
|
||||||
|
static int shift_pressed = 0;
|
||||||
|
static int caps_pressed = 0;
|
||||||
|
static int extended = 0;
|
||||||
|
|
||||||
|
*outChar = NULL; /* default value if we return FALSE */
|
||||||
|
|
||||||
|
/* Read keyboard controller, toggle enable */
|
||||||
|
inport_byte(KBD_CTL, inChar);
|
||||||
|
outport_byte(KBD_CTL, inChar & ~0x80);
|
||||||
|
outport_byte(KBD_CTL, inChar | 0x80);
|
||||||
|
outport_byte(KBD_CTL, inChar & ~0x80);
|
||||||
|
|
||||||
|
/* See if it has data */
|
||||||
|
inport_byte(KBD_STATUS, inChar);
|
||||||
|
if ((inChar & 0x01) == 0)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* Read the data. Handle nonsense with shift, control, etc. */
|
||||||
|
inport_byte(KBD_DATA, inChar);
|
||||||
|
|
||||||
|
if (extended)
|
||||||
|
extended--;
|
||||||
|
|
||||||
|
switch (inChar)
|
||||||
|
{
|
||||||
|
case 0xe0:
|
||||||
|
extended = 2;
|
||||||
|
return FALSE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x38:
|
||||||
|
alt_pressed = 1;
|
||||||
|
return FALSE;
|
||||||
|
break;
|
||||||
|
case 0xb8:
|
||||||
|
alt_pressed = 0;
|
||||||
|
return FALSE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x1d:
|
||||||
|
ctrl_pressed = 1;
|
||||||
|
return FALSE;
|
||||||
|
break;
|
||||||
|
case 0x9d:
|
||||||
|
ctrl_pressed = 0;
|
||||||
|
return FALSE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x2a:
|
||||||
|
if (extended)
|
||||||
|
return FALSE;
|
||||||
|
case 0x36:
|
||||||
|
shift_pressed = 1;
|
||||||
|
return FALSE;
|
||||||
|
break;
|
||||||
|
case 0xaa:
|
||||||
|
if (extended)
|
||||||
|
return FALSE;
|
||||||
|
case 0xb6:
|
||||||
|
shift_pressed = 0;
|
||||||
|
return FALSE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x3a:
|
||||||
|
caps_pressed = 1;
|
||||||
|
return FALSE;
|
||||||
|
break;
|
||||||
|
case 0xba:
|
||||||
|
caps_pressed = 0;
|
||||||
|
return FALSE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x53:
|
||||||
|
if (ctrl_pressed && alt_pressed)
|
||||||
|
rtemsReboot(); /* ctrl+alt+del -> reboot */
|
||||||
|
break;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ignore unrecognized keys--usually arrow and such
|
||||||
|
*/
|
||||||
|
default:
|
||||||
|
if ((inChar & 0x80) || (inChar > 0x39))
|
||||||
|
/* High-bit on means key is being released, not pressed */
|
||||||
|
return FALSE;
|
||||||
|
break;
|
||||||
|
} /* switch */
|
||||||
|
|
||||||
|
/* Strip high bit, look up in our map */
|
||||||
|
inChar &= 0x7f;
|
||||||
|
if (ctrl_pressed)
|
||||||
|
{
|
||||||
|
*outChar = key_map[inChar];
|
||||||
|
*outChar &= 037;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*outChar = shift_pressed ? shift_map[inChar] : key_map[inChar];
|
||||||
|
if (caps_pressed)
|
||||||
|
{
|
||||||
|
if (*outChar >= 'A' && *outChar <= 'Z')
|
||||||
|
*outChar += 'a' - 'A';
|
||||||
|
else if (*outChar >= 'a' && *outChar <= 'z')
|
||||||
|
*outChar -= 'a' - 'A';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
} /* _IBMPC_scankey */
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------+
|
||||||
|
| Function: _IBMPC_keyboard_isr
|
||||||
|
| Description: Interrupt Service Routine for keyboard (0x01) IRQ.
|
||||||
|
| Global Variables: kbd_buffer, kbd_first, kbd_last.
|
||||||
|
| Arguments: vector - standard RTEMS argument - see documentation.
|
||||||
|
| Returns: standard return value - see documentation.
|
||||||
|
+--------------------------------------------------------------------------*/
|
||||||
|
void _IBMPC_keyboard_isr()
|
||||||
|
{
|
||||||
|
if (_IBMPC_scankey(&kbd_buffer[kbd_last]))
|
||||||
|
{
|
||||||
|
/* Got one; save it if there is enough room in buffer. */
|
||||||
|
unsigned int next = (kbd_last == kbd_end) ? 0 : kbd_last + 1;
|
||||||
|
|
||||||
|
if (next != kbd_first)
|
||||||
|
{
|
||||||
|
kbd_last = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} /* _IBMPC_keyboard_isr */
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------+
|
||||||
|
| Function: _IBMPC_chrdy
|
||||||
|
| Description: Check keyboard ISR buffer and return character if not empty.
|
||||||
|
| Global Variables: kbd_buffer, kbd_first, kbd_last.
|
||||||
|
| Arguments: c - character read if keyboard buffer not empty, otherwise
|
||||||
|
| unchanged.
|
||||||
|
| Returns: TRUE if keyboard buffer not empty, FALSE otherwise.
|
||||||
|
+--------------------------------------------------------------------------*/
|
||||||
|
rtems_boolean
|
||||||
|
_IBMPC_chrdy(char *c)
|
||||||
|
{
|
||||||
|
/* Check buffer our ISR builds */
|
||||||
|
if (kbd_first != kbd_last)
|
||||||
|
{
|
||||||
|
*c = kbd_buffer[kbd_first];
|
||||||
|
|
||||||
|
kbd_first = (kbd_first + 1) % KBD_BUF_SIZE;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return FALSE;
|
||||||
|
} /* _IBMPC_chrdy */
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------+
|
||||||
|
| Function: _IBMPC_inch
|
||||||
|
| Description: Poll keyboard until a character is ready and return it.
|
||||||
|
| Global Variables: None.
|
||||||
|
| Arguments: None.
|
||||||
|
| Returns: character read from keyboard.
|
||||||
|
+--------------------------------------------------------------------------*/
|
||||||
|
char
|
||||||
|
_IBMPC_inch(void)
|
||||||
|
{
|
||||||
|
char c;
|
||||||
|
while (!_IBMPC_chrdy(&c))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
return c;
|
||||||
|
} /* _IBMPC_inch */
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Routine that can be used before interrupt management is initialized.
|
||||||
|
*/
|
||||||
|
|
||||||
|
char
|
||||||
|
BSP_wait_polled_input(void)
|
||||||
|
{
|
||||||
|
char c;
|
||||||
|
while (!_IBMPC_scankey(&c))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------+
|
||||||
|
| Function: _IBMPC_inch_sleep
|
||||||
|
| Description: If charcter is ready return it, otherwise sleep until
|
||||||
|
| it is ready
|
||||||
|
| Global Variables: None.
|
||||||
|
| Arguments: None.
|
||||||
|
| Returns: character read from keyboard.
|
||||||
|
+--------------------------------------------------------------------------*/
|
||||||
|
char
|
||||||
|
_IBMPC_inch_sleep(void)
|
||||||
|
{
|
||||||
|
char c;
|
||||||
|
rtems_interval ticks_per_second;
|
||||||
|
|
||||||
|
ticks_per_second = 0;
|
||||||
|
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
if(_IBMPC_chrdy(&c))
|
||||||
|
{
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ticks_per_second == 0)
|
||||||
|
{
|
||||||
|
rtems_clock_get(RTEMS_CLOCK_GET_TICKS_PER_SECOND,
|
||||||
|
&ticks_per_second);
|
||||||
|
}
|
||||||
|
rtems_task_wake_after((ticks_per_second+24)/25);
|
||||||
|
}
|
||||||
|
|
||||||
|
return c;
|
||||||
|
} /* _IBMPC_inch */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
433
c/src/lib/libbsp/powerpc/shared/console/keyboard.h
Normal file
433
c/src/lib/libbsp/powerpc/shared/console/keyboard.h
Normal file
@@ -0,0 +1,433 @@
|
|||||||
|
/*
|
||||||
|
* keyboard.h -- keyboard definitions.
|
||||||
|
*
|
||||||
|
* Copyright (C) 1999 Eric Valette. valette@crf.canon.fr
|
||||||
|
*
|
||||||
|
* The license and distribution terms for this file may be
|
||||||
|
* found in found in the file LICENSE in this distribution or at
|
||||||
|
* http://www.OARcorp.com/rtems/license.html.
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LINUX_KEYBOARD_H
|
||||||
|
#define __LINUX_KEYBOARD_H
|
||||||
|
|
||||||
|
#define KG_SHIFT 0
|
||||||
|
#define KG_CTRL 2
|
||||||
|
#define KG_ALT 3
|
||||||
|
#define KG_ALTGR 1
|
||||||
|
#define KG_SHIFTL 4
|
||||||
|
#define KG_SHIFTR 5
|
||||||
|
#define KG_CTRLL 6
|
||||||
|
#define KG_CTRLR 7
|
||||||
|
#define KG_CAPSSHIFT 8
|
||||||
|
|
||||||
|
#define NR_SHIFT 9
|
||||||
|
|
||||||
|
#define NR_KEYS 128
|
||||||
|
#define MAX_NR_KEYMAPS 256
|
||||||
|
/* This means 64Kb if all keymaps are allocated. Only the superuser
|
||||||
|
may increase the number of keymaps beyond MAX_NR_OF_USER_KEYMAPS. */
|
||||||
|
#define MAX_NR_OF_USER_KEYMAPS 256 /* should be at least 7 */
|
||||||
|
|
||||||
|
#define MAX_NR_FUNC 256 /* max nr of strings assigned to keys */
|
||||||
|
|
||||||
|
#define KT_LATIN 0 /* we depend on this being zero */
|
||||||
|
#define KT_LETTER 11 /* symbol that can be acted upon by CapsLock */
|
||||||
|
#define KT_FN 1
|
||||||
|
#define KT_SPEC 2
|
||||||
|
#define KT_PAD 3
|
||||||
|
#define KT_DEAD 4
|
||||||
|
#define KT_CONS 5
|
||||||
|
#define KT_CUR 6
|
||||||
|
#define KT_SHIFT 7
|
||||||
|
#define KT_META 8
|
||||||
|
#define KT_ASCII 9
|
||||||
|
#define KT_LOCK 10
|
||||||
|
#define KT_SLOCK 12
|
||||||
|
|
||||||
|
#define K(t,v) (((t)<<8)|(v))
|
||||||
|
#define KTYP(x) ((x) >> 8)
|
||||||
|
#define KVAL(x) ((x) & 0xff)
|
||||||
|
|
||||||
|
#define K_F1 K(KT_FN,0)
|
||||||
|
#define K_F2 K(KT_FN,1)
|
||||||
|
#define K_F3 K(KT_FN,2)
|
||||||
|
#define K_F4 K(KT_FN,3)
|
||||||
|
#define K_F5 K(KT_FN,4)
|
||||||
|
#define K_F6 K(KT_FN,5)
|
||||||
|
#define K_F7 K(KT_FN,6)
|
||||||
|
#define K_F8 K(KT_FN,7)
|
||||||
|
#define K_F9 K(KT_FN,8)
|
||||||
|
#define K_F10 K(KT_FN,9)
|
||||||
|
#define K_F11 K(KT_FN,10)
|
||||||
|
#define K_F12 K(KT_FN,11)
|
||||||
|
#define K_F13 K(KT_FN,12)
|
||||||
|
#define K_F14 K(KT_FN,13)
|
||||||
|
#define K_F15 K(KT_FN,14)
|
||||||
|
#define K_F16 K(KT_FN,15)
|
||||||
|
#define K_F17 K(KT_FN,16)
|
||||||
|
#define K_F18 K(KT_FN,17)
|
||||||
|
#define K_F19 K(KT_FN,18)
|
||||||
|
#define K_F20 K(KT_FN,19)
|
||||||
|
#define K_FIND K(KT_FN,20)
|
||||||
|
#define K_INSERT K(KT_FN,21)
|
||||||
|
#define K_REMOVE K(KT_FN,22)
|
||||||
|
#define K_SELECT K(KT_FN,23)
|
||||||
|
#define K_PGUP K(KT_FN,24) /* PGUP is a synonym for PRIOR */
|
||||||
|
#define K_PGDN K(KT_FN,25) /* PGDN is a synonym for NEXT */
|
||||||
|
#define K_MACRO K(KT_FN,26)
|
||||||
|
#define K_HELP K(KT_FN,27)
|
||||||
|
#define K_DO K(KT_FN,28)
|
||||||
|
#define K_PAUSE K(KT_FN,29)
|
||||||
|
#define K_F21 K(KT_FN,30)
|
||||||
|
#define K_F22 K(KT_FN,31)
|
||||||
|
#define K_F23 K(KT_FN,32)
|
||||||
|
#define K_F24 K(KT_FN,33)
|
||||||
|
#define K_F25 K(KT_FN,34)
|
||||||
|
#define K_F26 K(KT_FN,35)
|
||||||
|
#define K_F27 K(KT_FN,36)
|
||||||
|
#define K_F28 K(KT_FN,37)
|
||||||
|
#define K_F29 K(KT_FN,38)
|
||||||
|
#define K_F30 K(KT_FN,39)
|
||||||
|
#define K_F31 K(KT_FN,40)
|
||||||
|
#define K_F32 K(KT_FN,41)
|
||||||
|
#define K_F33 K(KT_FN,42)
|
||||||
|
#define K_F34 K(KT_FN,43)
|
||||||
|
#define K_F35 K(KT_FN,44)
|
||||||
|
#define K_F36 K(KT_FN,45)
|
||||||
|
#define K_F37 K(KT_FN,46)
|
||||||
|
#define K_F38 K(KT_FN,47)
|
||||||
|
#define K_F39 K(KT_FN,48)
|
||||||
|
#define K_F40 K(KT_FN,49)
|
||||||
|
#define K_F41 K(KT_FN,50)
|
||||||
|
#define K_F42 K(KT_FN,51)
|
||||||
|
#define K_F43 K(KT_FN,52)
|
||||||
|
#define K_F44 K(KT_FN,53)
|
||||||
|
#define K_F45 K(KT_FN,54)
|
||||||
|
#define K_F46 K(KT_FN,55)
|
||||||
|
#define K_F47 K(KT_FN,56)
|
||||||
|
#define K_F48 K(KT_FN,57)
|
||||||
|
#define K_F49 K(KT_FN,58)
|
||||||
|
#define K_F50 K(KT_FN,59)
|
||||||
|
#define K_F51 K(KT_FN,60)
|
||||||
|
#define K_F52 K(KT_FN,61)
|
||||||
|
#define K_F53 K(KT_FN,62)
|
||||||
|
#define K_F54 K(KT_FN,63)
|
||||||
|
#define K_F55 K(KT_FN,64)
|
||||||
|
#define K_F56 K(KT_FN,65)
|
||||||
|
#define K_F57 K(KT_FN,66)
|
||||||
|
#define K_F58 K(KT_FN,67)
|
||||||
|
#define K_F59 K(KT_FN,68)
|
||||||
|
#define K_F60 K(KT_FN,69)
|
||||||
|
#define K_F61 K(KT_FN,70)
|
||||||
|
#define K_F62 K(KT_FN,71)
|
||||||
|
#define K_F63 K(KT_FN,72)
|
||||||
|
#define K_F64 K(KT_FN,73)
|
||||||
|
#define K_F65 K(KT_FN,74)
|
||||||
|
#define K_F66 K(KT_FN,75)
|
||||||
|
#define K_F67 K(KT_FN,76)
|
||||||
|
#define K_F68 K(KT_FN,77)
|
||||||
|
#define K_F69 K(KT_FN,78)
|
||||||
|
#define K_F70 K(KT_FN,79)
|
||||||
|
#define K_F71 K(KT_FN,80)
|
||||||
|
#define K_F72 K(KT_FN,81)
|
||||||
|
#define K_F73 K(KT_FN,82)
|
||||||
|
#define K_F74 K(KT_FN,83)
|
||||||
|
#define K_F75 K(KT_FN,84)
|
||||||
|
#define K_F76 K(KT_FN,85)
|
||||||
|
#define K_F77 K(KT_FN,86)
|
||||||
|
#define K_F78 K(KT_FN,87)
|
||||||
|
#define K_F79 K(KT_FN,88)
|
||||||
|
#define K_F80 K(KT_FN,89)
|
||||||
|
#define K_F81 K(KT_FN,90)
|
||||||
|
#define K_F82 K(KT_FN,91)
|
||||||
|
#define K_F83 K(KT_FN,92)
|
||||||
|
#define K_F84 K(KT_FN,93)
|
||||||
|
#define K_F85 K(KT_FN,94)
|
||||||
|
#define K_F86 K(KT_FN,95)
|
||||||
|
#define K_F87 K(KT_FN,96)
|
||||||
|
#define K_F88 K(KT_FN,97)
|
||||||
|
#define K_F89 K(KT_FN,98)
|
||||||
|
#define K_F90 K(KT_FN,99)
|
||||||
|
#define K_F91 K(KT_FN,100)
|
||||||
|
#define K_F92 K(KT_FN,101)
|
||||||
|
#define K_F93 K(KT_FN,102)
|
||||||
|
#define K_F94 K(KT_FN,103)
|
||||||
|
#define K_F95 K(KT_FN,104)
|
||||||
|
#define K_F96 K(KT_FN,105)
|
||||||
|
#define K_F97 K(KT_FN,106)
|
||||||
|
#define K_F98 K(KT_FN,107)
|
||||||
|
#define K_F99 K(KT_FN,108)
|
||||||
|
#define K_F100 K(KT_FN,109)
|
||||||
|
#define K_F101 K(KT_FN,110)
|
||||||
|
#define K_F102 K(KT_FN,111)
|
||||||
|
#define K_F103 K(KT_FN,112)
|
||||||
|
#define K_F104 K(KT_FN,113)
|
||||||
|
#define K_F105 K(KT_FN,114)
|
||||||
|
#define K_F106 K(KT_FN,115)
|
||||||
|
#define K_F107 K(KT_FN,116)
|
||||||
|
#define K_F108 K(KT_FN,117)
|
||||||
|
#define K_F109 K(KT_FN,118)
|
||||||
|
#define K_F110 K(KT_FN,119)
|
||||||
|
#define K_F111 K(KT_FN,120)
|
||||||
|
#define K_F112 K(KT_FN,121)
|
||||||
|
#define K_F113 K(KT_FN,122)
|
||||||
|
#define K_F114 K(KT_FN,123)
|
||||||
|
#define K_F115 K(KT_FN,124)
|
||||||
|
#define K_F116 K(KT_FN,125)
|
||||||
|
#define K_F117 K(KT_FN,126)
|
||||||
|
#define K_F118 K(KT_FN,127)
|
||||||
|
#define K_F119 K(KT_FN,128)
|
||||||
|
#define K_F120 K(KT_FN,129)
|
||||||
|
#define K_F121 K(KT_FN,130)
|
||||||
|
#define K_F122 K(KT_FN,131)
|
||||||
|
#define K_F123 K(KT_FN,132)
|
||||||
|
#define K_F124 K(KT_FN,133)
|
||||||
|
#define K_F125 K(KT_FN,134)
|
||||||
|
#define K_F126 K(KT_FN,135)
|
||||||
|
#define K_F127 K(KT_FN,136)
|
||||||
|
#define K_F128 K(KT_FN,137)
|
||||||
|
#define K_F129 K(KT_FN,138)
|
||||||
|
#define K_F130 K(KT_FN,139)
|
||||||
|
#define K_F131 K(KT_FN,140)
|
||||||
|
#define K_F132 K(KT_FN,141)
|
||||||
|
#define K_F133 K(KT_FN,142)
|
||||||
|
#define K_F134 K(KT_FN,143)
|
||||||
|
#define K_F135 K(KT_FN,144)
|
||||||
|
#define K_F136 K(KT_FN,145)
|
||||||
|
#define K_F137 K(KT_FN,146)
|
||||||
|
#define K_F138 K(KT_FN,147)
|
||||||
|
#define K_F139 K(KT_FN,148)
|
||||||
|
#define K_F140 K(KT_FN,149)
|
||||||
|
#define K_F141 K(KT_FN,150)
|
||||||
|
#define K_F142 K(KT_FN,151)
|
||||||
|
#define K_F143 K(KT_FN,152)
|
||||||
|
#define K_F144 K(KT_FN,153)
|
||||||
|
#define K_F145 K(KT_FN,154)
|
||||||
|
#define K_F146 K(KT_FN,155)
|
||||||
|
#define K_F147 K(KT_FN,156)
|
||||||
|
#define K_F148 K(KT_FN,157)
|
||||||
|
#define K_F149 K(KT_FN,158)
|
||||||
|
#define K_F150 K(KT_FN,159)
|
||||||
|
#define K_F151 K(KT_FN,160)
|
||||||
|
#define K_F152 K(KT_FN,161)
|
||||||
|
#define K_F153 K(KT_FN,162)
|
||||||
|
#define K_F154 K(KT_FN,163)
|
||||||
|
#define K_F155 K(KT_FN,164)
|
||||||
|
#define K_F156 K(KT_FN,165)
|
||||||
|
#define K_F157 K(KT_FN,166)
|
||||||
|
#define K_F158 K(KT_FN,167)
|
||||||
|
#define K_F159 K(KT_FN,168)
|
||||||
|
#define K_F160 K(KT_FN,169)
|
||||||
|
#define K_F161 K(KT_FN,170)
|
||||||
|
#define K_F162 K(KT_FN,171)
|
||||||
|
#define K_F163 K(KT_FN,172)
|
||||||
|
#define K_F164 K(KT_FN,173)
|
||||||
|
#define K_F165 K(KT_FN,174)
|
||||||
|
#define K_F166 K(KT_FN,175)
|
||||||
|
#define K_F167 K(KT_FN,176)
|
||||||
|
#define K_F168 K(KT_FN,177)
|
||||||
|
#define K_F169 K(KT_FN,178)
|
||||||
|
#define K_F170 K(KT_FN,179)
|
||||||
|
#define K_F171 K(KT_FN,180)
|
||||||
|
#define K_F172 K(KT_FN,181)
|
||||||
|
#define K_F173 K(KT_FN,182)
|
||||||
|
#define K_F174 K(KT_FN,183)
|
||||||
|
#define K_F175 K(KT_FN,184)
|
||||||
|
#define K_F176 K(KT_FN,185)
|
||||||
|
#define K_F177 K(KT_FN,186)
|
||||||
|
#define K_F178 K(KT_FN,187)
|
||||||
|
#define K_F179 K(KT_FN,188)
|
||||||
|
#define K_F180 K(KT_FN,189)
|
||||||
|
#define K_F181 K(KT_FN,190)
|
||||||
|
#define K_F182 K(KT_FN,191)
|
||||||
|
#define K_F183 K(KT_FN,192)
|
||||||
|
#define K_F184 K(KT_FN,193)
|
||||||
|
#define K_F185 K(KT_FN,194)
|
||||||
|
#define K_F186 K(KT_FN,195)
|
||||||
|
#define K_F187 K(KT_FN,196)
|
||||||
|
#define K_F188 K(KT_FN,197)
|
||||||
|
#define K_F189 K(KT_FN,198)
|
||||||
|
#define K_F190 K(KT_FN,199)
|
||||||
|
#define K_F191 K(KT_FN,200)
|
||||||
|
#define K_F192 K(KT_FN,201)
|
||||||
|
#define K_F193 K(KT_FN,202)
|
||||||
|
#define K_F194 K(KT_FN,203)
|
||||||
|
#define K_F195 K(KT_FN,204)
|
||||||
|
#define K_F196 K(KT_FN,205)
|
||||||
|
#define K_F197 K(KT_FN,206)
|
||||||
|
#define K_F198 K(KT_FN,207)
|
||||||
|
#define K_F199 K(KT_FN,208)
|
||||||
|
#define K_F200 K(KT_FN,209)
|
||||||
|
#define K_F201 K(KT_FN,210)
|
||||||
|
#define K_F202 K(KT_FN,211)
|
||||||
|
#define K_F203 K(KT_FN,212)
|
||||||
|
#define K_F204 K(KT_FN,213)
|
||||||
|
#define K_F205 K(KT_FN,214)
|
||||||
|
#define K_F206 K(KT_FN,215)
|
||||||
|
#define K_F207 K(KT_FN,216)
|
||||||
|
#define K_F208 K(KT_FN,217)
|
||||||
|
#define K_F209 K(KT_FN,218)
|
||||||
|
#define K_F210 K(KT_FN,219)
|
||||||
|
#define K_F211 K(KT_FN,220)
|
||||||
|
#define K_F212 K(KT_FN,221)
|
||||||
|
#define K_F213 K(KT_FN,222)
|
||||||
|
#define K_F214 K(KT_FN,223)
|
||||||
|
#define K_F215 K(KT_FN,224)
|
||||||
|
#define K_F216 K(KT_FN,225)
|
||||||
|
#define K_F217 K(KT_FN,226)
|
||||||
|
#define K_F218 K(KT_FN,227)
|
||||||
|
#define K_F219 K(KT_FN,228)
|
||||||
|
#define K_F220 K(KT_FN,229)
|
||||||
|
#define K_F221 K(KT_FN,230)
|
||||||
|
#define K_F222 K(KT_FN,231)
|
||||||
|
#define K_F223 K(KT_FN,232)
|
||||||
|
#define K_F224 K(KT_FN,233)
|
||||||
|
#define K_F225 K(KT_FN,234)
|
||||||
|
#define K_F226 K(KT_FN,235)
|
||||||
|
#define K_F227 K(KT_FN,236)
|
||||||
|
#define K_F228 K(KT_FN,237)
|
||||||
|
#define K_F229 K(KT_FN,238)
|
||||||
|
#define K_F230 K(KT_FN,239)
|
||||||
|
#define K_F231 K(KT_FN,240)
|
||||||
|
#define K_F232 K(KT_FN,241)
|
||||||
|
#define K_F233 K(KT_FN,242)
|
||||||
|
#define K_F234 K(KT_FN,243)
|
||||||
|
#define K_F235 K(KT_FN,244)
|
||||||
|
#define K_F236 K(KT_FN,245)
|
||||||
|
#define K_F237 K(KT_FN,246)
|
||||||
|
#define K_F238 K(KT_FN,247)
|
||||||
|
#define K_F239 K(KT_FN,248)
|
||||||
|
#define K_F240 K(KT_FN,249)
|
||||||
|
#define K_F241 K(KT_FN,250)
|
||||||
|
#define K_F242 K(KT_FN,251)
|
||||||
|
#define K_F243 K(KT_FN,252)
|
||||||
|
#define K_F244 K(KT_FN,253)
|
||||||
|
#define K_F245 K(KT_FN,254)
|
||||||
|
#define K_UNDO K(KT_FN,255)
|
||||||
|
|
||||||
|
|
||||||
|
#define K_HOLE K(KT_SPEC,0)
|
||||||
|
#define K_ENTER K(KT_SPEC,1)
|
||||||
|
#define K_SH_REGS K(KT_SPEC,2)
|
||||||
|
#define K_SH_MEM K(KT_SPEC,3)
|
||||||
|
#define K_SH_STAT K(KT_SPEC,4)
|
||||||
|
#define K_BREAK K(KT_SPEC,5)
|
||||||
|
#define K_CONS K(KT_SPEC,6)
|
||||||
|
#define K_CAPS K(KT_SPEC,7)
|
||||||
|
#define K_NUM K(KT_SPEC,8)
|
||||||
|
#define K_HOLD K(KT_SPEC,9)
|
||||||
|
#define K_SCROLLFORW K(KT_SPEC,10)
|
||||||
|
#define K_SCROLLBACK K(KT_SPEC,11)
|
||||||
|
#define K_BOOT K(KT_SPEC,12)
|
||||||
|
#define K_CAPSON K(KT_SPEC,13)
|
||||||
|
#define K_COMPOSE K(KT_SPEC,14)
|
||||||
|
#define K_SAK K(KT_SPEC,15)
|
||||||
|
#define K_DECRCONSOLE K(KT_SPEC,16)
|
||||||
|
#define K_INCRCONSOLE K(KT_SPEC,17)
|
||||||
|
#define K_SPAWNCONSOLE K(KT_SPEC,18)
|
||||||
|
#define K_BARENUMLOCK K(KT_SPEC,19)
|
||||||
|
|
||||||
|
#define K_ALLOCATED K(KT_SPEC,126) /* dynamically allocated keymap */
|
||||||
|
#define K_NOSUCHMAP K(KT_SPEC,127) /* returned by KDGKBENT */
|
||||||
|
|
||||||
|
#define K_P0 K(KT_PAD,0)
|
||||||
|
#define K_P1 K(KT_PAD,1)
|
||||||
|
#define K_P2 K(KT_PAD,2)
|
||||||
|
#define K_P3 K(KT_PAD,3)
|
||||||
|
#define K_P4 K(KT_PAD,4)
|
||||||
|
#define K_P5 K(KT_PAD,5)
|
||||||
|
#define K_P6 K(KT_PAD,6)
|
||||||
|
#define K_P7 K(KT_PAD,7)
|
||||||
|
#define K_P8 K(KT_PAD,8)
|
||||||
|
#define K_P9 K(KT_PAD,9)
|
||||||
|
#define K_PPLUS K(KT_PAD,10) /* key-pad plus */
|
||||||
|
#define K_PMINUS K(KT_PAD,11) /* key-pad minus */
|
||||||
|
#define K_PSTAR K(KT_PAD,12) /* key-pad asterisk (star) */
|
||||||
|
#define K_PSLASH K(KT_PAD,13) /* key-pad slash */
|
||||||
|
#define K_PENTER K(KT_PAD,14) /* key-pad enter */
|
||||||
|
#define K_PCOMMA K(KT_PAD,15) /* key-pad comma: kludge... */
|
||||||
|
#define K_PDOT K(KT_PAD,16) /* key-pad dot (period): kludge... */
|
||||||
|
#define K_PPLUSMINUS K(KT_PAD,17) /* key-pad plus/minus */
|
||||||
|
#define K_PPARENL K(KT_PAD,18) /* key-pad left parenthesis */
|
||||||
|
#define K_PPARENR K(KT_PAD,19) /* key-pad right parenthesis */
|
||||||
|
|
||||||
|
#define NR_PAD 20
|
||||||
|
|
||||||
|
#define K_DGRAVE K(KT_DEAD,0)
|
||||||
|
#define K_DACUTE K(KT_DEAD,1)
|
||||||
|
#define K_DCIRCM K(KT_DEAD,2)
|
||||||
|
#define K_DTILDE K(KT_DEAD,3)
|
||||||
|
#define K_DDIERE K(KT_DEAD,4)
|
||||||
|
#define K_DCEDIL K(KT_DEAD,5)
|
||||||
|
|
||||||
|
#define NR_DEAD 6
|
||||||
|
|
||||||
|
#define K_DOWN K(KT_CUR,0)
|
||||||
|
#define K_LEFT K(KT_CUR,1)
|
||||||
|
#define K_RIGHT K(KT_CUR,2)
|
||||||
|
#define K_UP K(KT_CUR,3)
|
||||||
|
|
||||||
|
#define K_SHIFT K(KT_SHIFT,KG_SHIFT)
|
||||||
|
#define K_CTRL K(KT_SHIFT,KG_CTRL)
|
||||||
|
#define K_ALT K(KT_SHIFT,KG_ALT)
|
||||||
|
#define K_ALTGR K(KT_SHIFT,KG_ALTGR)
|
||||||
|
#define K_SHIFTL K(KT_SHIFT,KG_SHIFTL)
|
||||||
|
#define K_SHIFTR K(KT_SHIFT,KG_SHIFTR)
|
||||||
|
#define K_CTRLL K(KT_SHIFT,KG_CTRLL)
|
||||||
|
#define K_CTRLR K(KT_SHIFT,KG_CTRLR)
|
||||||
|
#define K_CAPSSHIFT K(KT_SHIFT,KG_CAPSSHIFT)
|
||||||
|
|
||||||
|
#define K_ASC0 K(KT_ASCII,0)
|
||||||
|
#define K_ASC1 K(KT_ASCII,1)
|
||||||
|
#define K_ASC2 K(KT_ASCII,2)
|
||||||
|
#define K_ASC3 K(KT_ASCII,3)
|
||||||
|
#define K_ASC4 K(KT_ASCII,4)
|
||||||
|
#define K_ASC5 K(KT_ASCII,5)
|
||||||
|
#define K_ASC6 K(KT_ASCII,6)
|
||||||
|
#define K_ASC7 K(KT_ASCII,7)
|
||||||
|
#define K_ASC8 K(KT_ASCII,8)
|
||||||
|
#define K_ASC9 K(KT_ASCII,9)
|
||||||
|
#define K_HEX0 K(KT_ASCII,10)
|
||||||
|
#define K_HEX1 K(KT_ASCII,11)
|
||||||
|
#define K_HEX2 K(KT_ASCII,12)
|
||||||
|
#define K_HEX3 K(KT_ASCII,13)
|
||||||
|
#define K_HEX4 K(KT_ASCII,14)
|
||||||
|
#define K_HEX5 K(KT_ASCII,15)
|
||||||
|
#define K_HEX6 K(KT_ASCII,16)
|
||||||
|
#define K_HEX7 K(KT_ASCII,17)
|
||||||
|
#define K_HEX8 K(KT_ASCII,18)
|
||||||
|
#define K_HEX9 K(KT_ASCII,19)
|
||||||
|
#define K_HEXa K(KT_ASCII,20)
|
||||||
|
#define K_HEXb K(KT_ASCII,21)
|
||||||
|
#define K_HEXc K(KT_ASCII,22)
|
||||||
|
#define K_HEXd K(KT_ASCII,23)
|
||||||
|
#define K_HEXe K(KT_ASCII,24)
|
||||||
|
#define K_HEXf K(KT_ASCII,25)
|
||||||
|
|
||||||
|
#define NR_ASCII 26
|
||||||
|
|
||||||
|
#define K_SHIFTLOCK K(KT_LOCK,KG_SHIFT)
|
||||||
|
#define K_CTRLLOCK K(KT_LOCK,KG_CTRL)
|
||||||
|
#define K_ALTLOCK K(KT_LOCK,KG_ALT)
|
||||||
|
#define K_ALTGRLOCK K(KT_LOCK,KG_ALTGR)
|
||||||
|
#define K_SHIFTLLOCK K(KT_LOCK,KG_SHIFTL)
|
||||||
|
#define K_SHIFTRLOCK K(KT_LOCK,KG_SHIFTR)
|
||||||
|
#define K_CTRLLLOCK K(KT_LOCK,KG_CTRLL)
|
||||||
|
#define K_CTRLRLOCK K(KT_LOCK,KG_CTRLR)
|
||||||
|
|
||||||
|
#define K_SHIFT_SLOCK K(KT_SLOCK,KG_SHIFT)
|
||||||
|
#define K_CTRL_SLOCK K(KT_SLOCK,KG_CTRL)
|
||||||
|
#define K_ALT_SLOCK K(KT_SLOCK,KG_ALT)
|
||||||
|
#define K_ALTGR_SLOCK K(KT_SLOCK,KG_ALTGR)
|
||||||
|
#define K_SHIFTL_SLOCK K(KT_SLOCK,KG_SHIFTL)
|
||||||
|
#define K_SHIFTR_SLOCK K(KT_SLOCK,KG_SHIFTR)
|
||||||
|
#define K_CTRLL_SLOCK K(KT_SLOCK,KG_CTRLL)
|
||||||
|
#define K_CTRLR_SLOCK K(KT_SLOCK,KG_CTRLR)
|
||||||
|
|
||||||
|
#define NR_LOCK 8
|
||||||
|
|
||||||
|
#define MAX_DIACR 256
|
||||||
|
#endif
|
||||||
1080
c/src/lib/libbsp/powerpc/shared/console/polled_io.c
Normal file
1080
c/src/lib/libbsp/powerpc/shared/console/polled_io.c
Normal file
File diff suppressed because it is too large
Load Diff
778
c/src/lib/libbsp/powerpc/shared/console/uart.c
Normal file
778
c/src/lib/libbsp/powerpc/shared/console/uart.c
Normal file
@@ -0,0 +1,778 @@
|
|||||||
|
/*
|
||||||
|
* This software is Copyright (C) 1998 by T.sqware - all rights limited
|
||||||
|
* It is provided in to the public domain "as is", can be freely modified
|
||||||
|
* as far as this copyight notice is kept unchanged, but does not imply
|
||||||
|
* an endorsement by T.sqware of the product in which it is included.
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <bsp.h>
|
||||||
|
#include <bsp/irq.h>
|
||||||
|
#include <bsp/uart.h>
|
||||||
|
#include <rtems/libio.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Basic 16552 driver
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct uart_data
|
||||||
|
{
|
||||||
|
int hwFlow;
|
||||||
|
int baud;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct uart_data uart_data[2];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Macros to read/wirte register of uart, if configuration is
|
||||||
|
* different just rewrite these macros
|
||||||
|
*/
|
||||||
|
|
||||||
|
static inline unsigned char
|
||||||
|
uread(int uart, unsigned int reg)
|
||||||
|
{
|
||||||
|
register unsigned char val;
|
||||||
|
|
||||||
|
if(uart == 0)
|
||||||
|
{
|
||||||
|
inport_byte(COM1_BASE_IO+reg, val);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
inport_byte(COM2_BASE_IO+reg, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
uwrite(int uart, int reg, unsigned int val)
|
||||||
|
{
|
||||||
|
if(uart == 0)
|
||||||
|
{
|
||||||
|
outport_byte(COM1_BASE_IO+reg, val);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
outport_byte(COM2_BASE_IO+reg, val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef UARTDEBUG
|
||||||
|
static void
|
||||||
|
uartError(int uart)
|
||||||
|
{
|
||||||
|
unsigned char uartStatus, dummy;
|
||||||
|
|
||||||
|
uartStatus = uread(uart, LSR);
|
||||||
|
dummy = uread(uart, RBR);
|
||||||
|
|
||||||
|
if (uartStatus & OE)
|
||||||
|
printk("********* Over run Error **********\n");
|
||||||
|
if (uartStatus & PE)
|
||||||
|
printk("********* Parity Error **********\n");
|
||||||
|
if (uartStatus & FE)
|
||||||
|
printk("********* Framing Error **********\n");
|
||||||
|
if (uartStatus & BI)
|
||||||
|
printk("********* Parity Error **********\n");
|
||||||
|
if (uartStatus & ERFIFO)
|
||||||
|
printk("********* Error receive Fifo **********\n");
|
||||||
|
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
inline void uartError(int uart)
|
||||||
|
{
|
||||||
|
unsigned char uartStatus;
|
||||||
|
|
||||||
|
uartStatus = uread(uart, LSR);
|
||||||
|
uartStatus = uread(uart, RBR);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Uart initialization, it is hardcoded to 8 bit, no parity,
|
||||||
|
* one stop bit, FIFO, things to be changed
|
||||||
|
* are baud rate and nad hw flow control,
|
||||||
|
* and longest rx fifo setting
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
BSP_uart_init(int uart, int baud, int hwFlow)
|
||||||
|
{
|
||||||
|
unsigned char tmp;
|
||||||
|
|
||||||
|
/* Sanity check */
|
||||||
|
assert(uart == BSP_UART_COM1 || uart == BSP_UART_COM2);
|
||||||
|
|
||||||
|
switch(baud)
|
||||||
|
{
|
||||||
|
case 50:
|
||||||
|
case 75:
|
||||||
|
case 110:
|
||||||
|
case 134:
|
||||||
|
case 300:
|
||||||
|
case 600:
|
||||||
|
case 1200:
|
||||||
|
case 2400:
|
||||||
|
case 9600:
|
||||||
|
case 19200:
|
||||||
|
case 38400:
|
||||||
|
case 57600:
|
||||||
|
case 115200:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set DLAB bit to 1 */
|
||||||
|
uwrite(uart, LCR, DLAB);
|
||||||
|
|
||||||
|
/* Set baud rate */
|
||||||
|
uwrite(uart, DLL, (BSPBaseBaud/baud) & 0xff);
|
||||||
|
uwrite(uart, DLM, ((BSPBaseBaud/baud) >> 8) & 0xff);
|
||||||
|
|
||||||
|
/* 8-bit, no parity , 1 stop */
|
||||||
|
uwrite(uart, LCR, CHR_8_BITS);
|
||||||
|
|
||||||
|
|
||||||
|
/* Set DTR, RTS and OUT2 high */
|
||||||
|
uwrite(uart, MCR, DTR | RTS | OUT_2);
|
||||||
|
|
||||||
|
/* Enable FIFO */
|
||||||
|
uwrite(uart, FCR, FIFO_EN | XMIT_RESET | RCV_RESET | RECEIVE_FIFO_TRIGGER12);
|
||||||
|
|
||||||
|
/* Disable Interrupts */
|
||||||
|
uwrite(uart, IER, 0);
|
||||||
|
|
||||||
|
/* Read status to clear them */
|
||||||
|
tmp = uread(uart, LSR);
|
||||||
|
tmp = uread(uart, RBR);
|
||||||
|
tmp = uread(uart, MSR);
|
||||||
|
|
||||||
|
/* Remember state */
|
||||||
|
uart_data[uart].hwFlow = hwFlow;
|
||||||
|
uart_data[uart].baud = baud;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set baud
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
BSP_uart_set_baud(int uart, int baud)
|
||||||
|
{
|
||||||
|
unsigned char mcr, ier;
|
||||||
|
|
||||||
|
/* Sanity check */
|
||||||
|
assert(uart == BSP_UART_COM1 || uart == BSP_UART_COM2);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function may be called whenever TERMIOS parameters
|
||||||
|
* are changed, so we have to make sire that baud change is
|
||||||
|
* indeed required
|
||||||
|
*/
|
||||||
|
|
||||||
|
if(baud == uart_data[uart].baud)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mcr = uread(uart, MCR);
|
||||||
|
ier = uread(uart, IER);
|
||||||
|
|
||||||
|
BSP_uart_init(uart, baud, uart_data[uart].hwFlow);
|
||||||
|
|
||||||
|
uwrite(uart, MCR, mcr);
|
||||||
|
uwrite(uart, IER, ier);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enable/disable interrupts
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
BSP_uart_intr_ctrl(int uart, int cmd)
|
||||||
|
{
|
||||||
|
|
||||||
|
assert(uart == BSP_UART_COM1 || uart == BSP_UART_COM2);
|
||||||
|
|
||||||
|
switch(cmd)
|
||||||
|
{
|
||||||
|
case BSP_UART_INTR_CTRL_DISABLE:
|
||||||
|
uwrite(uart, IER, INTERRUPT_DISABLE);
|
||||||
|
break;
|
||||||
|
case BSP_UART_INTR_CTRL_ENABLE:
|
||||||
|
if(uart_data[uart].hwFlow)
|
||||||
|
{
|
||||||
|
uwrite(uart, IER,
|
||||||
|
(RECEIVE_ENABLE |
|
||||||
|
TRANSMIT_ENABLE |
|
||||||
|
RECEIVER_LINE_ST_ENABLE |
|
||||||
|
MODEM_ENABLE
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uwrite(uart, IER,
|
||||||
|
(RECEIVE_ENABLE |
|
||||||
|
TRANSMIT_ENABLE |
|
||||||
|
RECEIVER_LINE_ST_ENABLE
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BSP_UART_INTR_CTRL_TERMIOS:
|
||||||
|
if(uart_data[uart].hwFlow)
|
||||||
|
{
|
||||||
|
uwrite(uart, IER,
|
||||||
|
(RECEIVE_ENABLE |
|
||||||
|
RECEIVER_LINE_ST_ENABLE |
|
||||||
|
MODEM_ENABLE
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uwrite(uart, IER,
|
||||||
|
(RECEIVE_ENABLE |
|
||||||
|
RECEIVER_LINE_ST_ENABLE
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BSP_UART_INTR_CTRL_GDB:
|
||||||
|
uwrite(uart, IER, RECEIVE_ENABLE);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
BSP_uart_throttle(int uart)
|
||||||
|
{
|
||||||
|
unsigned int mcr;
|
||||||
|
|
||||||
|
assert(uart == BSP_UART_COM1 || uart == BSP_UART_COM2);
|
||||||
|
|
||||||
|
if(!uart_data[uart].hwFlow)
|
||||||
|
{
|
||||||
|
/* Should not happen */
|
||||||
|
assert(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mcr = uread (uart, MCR);
|
||||||
|
/* RTS down */
|
||||||
|
mcr &= ~RTS;
|
||||||
|
uwrite(uart, MCR, mcr);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
BSP_uart_unthrottle(int uart)
|
||||||
|
{
|
||||||
|
unsigned int mcr;
|
||||||
|
|
||||||
|
assert(uart == BSP_UART_COM1 || uart == BSP_UART_COM2);
|
||||||
|
|
||||||
|
if(!uart_data[uart].hwFlow)
|
||||||
|
{
|
||||||
|
/* Should not happen */
|
||||||
|
assert(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mcr = uread (uart, MCR);
|
||||||
|
/* RTS up */
|
||||||
|
mcr |= RTS;
|
||||||
|
uwrite(uart, MCR, mcr);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Status function, -1 if error
|
||||||
|
* detected, 0 if no received chars available,
|
||||||
|
* 1 if received char available, 2 if break
|
||||||
|
* is detected, it will eat break and error
|
||||||
|
* chars. It ignores overruns - we cannot do
|
||||||
|
* anything about - it execpt count statistics
|
||||||
|
* and we are not counting it.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
BSP_uart_polled_status(int uart)
|
||||||
|
{
|
||||||
|
unsigned char val;
|
||||||
|
|
||||||
|
assert(uart == BSP_UART_COM1 || uart == BSP_UART_COM2);
|
||||||
|
|
||||||
|
val = uread(uart, LSR);
|
||||||
|
|
||||||
|
if(val & BI)
|
||||||
|
{
|
||||||
|
/* BREAK found, eat character */
|
||||||
|
uread(uart, RBR);
|
||||||
|
return BSP_UART_STATUS_BREAK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((val & (DR | OE | FE)) == 1)
|
||||||
|
{
|
||||||
|
/* No error, character present */
|
||||||
|
return BSP_UART_STATUS_CHAR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((val & (DR | OE | FE)) == 0)
|
||||||
|
{
|
||||||
|
/* Nothing */
|
||||||
|
return BSP_UART_STATUS_NOCHAR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Framing or parity error
|
||||||
|
* eat character
|
||||||
|
*/
|
||||||
|
uread(uart, RBR);
|
||||||
|
|
||||||
|
return BSP_UART_STATUS_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Polled mode write function
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
BSP_uart_polled_write(int uart, int val)
|
||||||
|
{
|
||||||
|
unsigned char val1;
|
||||||
|
|
||||||
|
/* Sanity check */
|
||||||
|
assert(uart == BSP_UART_COM1 || uart == BSP_UART_COM2);
|
||||||
|
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
if((val1=uread(uart, LSR)) & THRE)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(uart_data[uart].hwFlow)
|
||||||
|
{
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
if(uread(uart, MSR) & CTS)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uwrite(uart, THR, val & 0xff);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
BSP_output_char_via_serial(int val)
|
||||||
|
{
|
||||||
|
BSP_uart_polled_write(BSPConsolePort, val);
|
||||||
|
if (val == '\n') BSP_uart_polled_write(BSPConsolePort,'\r');
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Polled mode read function
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
BSP_uart_polled_read(int uart)
|
||||||
|
{
|
||||||
|
unsigned char val;
|
||||||
|
|
||||||
|
assert(uart == BSP_UART_COM1 || uart == BSP_UART_COM2);
|
||||||
|
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
if(uread(uart, LSR) & DR)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val = uread(uart, RBR);
|
||||||
|
|
||||||
|
return (int)(val & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned
|
||||||
|
BSP_poll_char_via_serial()
|
||||||
|
{
|
||||||
|
return BSP_uart_polled_read(BSPConsolePort);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ================ Termios support =================*/
|
||||||
|
|
||||||
|
static volatile int termios_stopped_com1 = 0;
|
||||||
|
static volatile int termios_tx_active_com1 = 0;
|
||||||
|
static void* termios_ttyp_com1 = NULL;
|
||||||
|
static char termios_tx_hold_com1 = 0;
|
||||||
|
static volatile char termios_tx_hold_valid_com1 = 0;
|
||||||
|
|
||||||
|
static volatile int termios_stopped_com2 = 0;
|
||||||
|
static volatile int termios_tx_active_com2 = 0;
|
||||||
|
static void* termios_ttyp_com2 = NULL;
|
||||||
|
static char termios_tx_hold_com2 = 0;
|
||||||
|
static volatile char termios_tx_hold_valid_com2 = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set channel parameters
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
BSP_uart_termios_set(int uart, void *ttyp)
|
||||||
|
{
|
||||||
|
unsigned char val;
|
||||||
|
assert(uart == BSP_UART_COM1 || uart == BSP_UART_COM2);
|
||||||
|
|
||||||
|
if(uart == BSP_UART_COM1)
|
||||||
|
{
|
||||||
|
if(uart_data[uart].hwFlow)
|
||||||
|
{
|
||||||
|
val = uread(uart, MSR);
|
||||||
|
|
||||||
|
termios_stopped_com1 = (val & CTS) ? 0 : 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
termios_stopped_com1 = 0;
|
||||||
|
}
|
||||||
|
termios_tx_active_com1 = 0;
|
||||||
|
termios_ttyp_com1 = ttyp;
|
||||||
|
termios_tx_hold_com1 = 0;
|
||||||
|
termios_tx_hold_valid_com1 = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(uart_data[uart].hwFlow)
|
||||||
|
{
|
||||||
|
val = uread(uart, MSR);
|
||||||
|
|
||||||
|
termios_stopped_com2 = (val & CTS) ? 0 : 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
termios_stopped_com2 = 0;
|
||||||
|
}
|
||||||
|
termios_tx_active_com2 = 0;
|
||||||
|
termios_ttyp_com2 = ttyp;
|
||||||
|
termios_tx_hold_com2 = 0;
|
||||||
|
termios_tx_hold_valid_com2 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
BSP_uart_termios_write_com1(int minor, const char *buf, int len)
|
||||||
|
{
|
||||||
|
assert(buf != NULL);
|
||||||
|
|
||||||
|
if(len <= 0)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If there TX buffer is busy - something is royally screwed up */
|
||||||
|
/* assert((uread(BSP_UART_COM1, LSR) & THRE) != 0); */
|
||||||
|
|
||||||
|
|
||||||
|
if(termios_stopped_com1)
|
||||||
|
{
|
||||||
|
/* CTS low */
|
||||||
|
termios_tx_hold_com1 = *buf;
|
||||||
|
termios_tx_hold_valid_com1 = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write character */
|
||||||
|
uwrite(BSP_UART_COM1, THR, *buf & 0xff);
|
||||||
|
|
||||||
|
/* Enable interrupts if necessary */
|
||||||
|
if(!termios_tx_active_com1 && uart_data[BSP_UART_COM1].hwFlow)
|
||||||
|
{
|
||||||
|
termios_tx_active_com1 = 1;
|
||||||
|
uwrite(BSP_UART_COM1, IER,
|
||||||
|
(RECEIVE_ENABLE |
|
||||||
|
TRANSMIT_ENABLE |
|
||||||
|
RECEIVER_LINE_ST_ENABLE |
|
||||||
|
MODEM_ENABLE
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if(!termios_tx_active_com1)
|
||||||
|
{
|
||||||
|
termios_tx_active_com1 = 1;
|
||||||
|
uwrite(BSP_UART_COM1, IER,
|
||||||
|
(RECEIVE_ENABLE |
|
||||||
|
TRANSMIT_ENABLE |
|
||||||
|
RECEIVER_LINE_ST_ENABLE
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
BSP_uart_termios_write_com2(int minor, const char *buf, int len)
|
||||||
|
{
|
||||||
|
assert(buf != NULL);
|
||||||
|
|
||||||
|
if(len <= 0)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* If there TX buffer is busy - something is royally screwed up */
|
||||||
|
assert((uread(BSP_UART_COM2, LSR) & THRE) != 0);
|
||||||
|
|
||||||
|
if(termios_stopped_com2)
|
||||||
|
{
|
||||||
|
/* CTS low */
|
||||||
|
termios_tx_hold_com2 = *buf;
|
||||||
|
termios_tx_hold_valid_com2 = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write character */
|
||||||
|
|
||||||
|
uwrite(BSP_UART_COM2, THR, *buf & 0xff);
|
||||||
|
|
||||||
|
/* Enable interrupts if necessary */
|
||||||
|
if(!termios_tx_active_com2 && uart_data[BSP_UART_COM2].hwFlow)
|
||||||
|
{
|
||||||
|
termios_tx_active_com2 = 1;
|
||||||
|
uwrite(BSP_UART_COM2, IER,
|
||||||
|
(RECEIVE_ENABLE |
|
||||||
|
TRANSMIT_ENABLE |
|
||||||
|
RECEIVER_LINE_ST_ENABLE |
|
||||||
|
MODEM_ENABLE
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if(!termios_tx_active_com2)
|
||||||
|
{
|
||||||
|
termios_tx_active_com2 = 1;
|
||||||
|
uwrite(BSP_UART_COM2, IER,
|
||||||
|
(RECEIVE_ENABLE |
|
||||||
|
TRANSMIT_ENABLE |
|
||||||
|
RECEIVER_LINE_ST_ENABLE
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BSP_uart_termios_isr_com1(void)
|
||||||
|
{
|
||||||
|
unsigned char buf[40];
|
||||||
|
unsigned char val;
|
||||||
|
int off, ret, vect;
|
||||||
|
|
||||||
|
off = 0;
|
||||||
|
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
vect = uread(BSP_UART_COM1, IIR) & 0xf;
|
||||||
|
|
||||||
|
switch(vect)
|
||||||
|
{
|
||||||
|
case MODEM_STATUS :
|
||||||
|
val = uread(BSP_UART_COM1, MSR);
|
||||||
|
if(uart_data[BSP_UART_COM1].hwFlow)
|
||||||
|
{
|
||||||
|
if(val & CTS)
|
||||||
|
{
|
||||||
|
/* CTS high */
|
||||||
|
termios_stopped_com1 = 0;
|
||||||
|
if(termios_tx_hold_valid_com1)
|
||||||
|
{
|
||||||
|
termios_tx_hold_valid_com1 = 0;
|
||||||
|
BSP_uart_termios_write_com1(0, &termios_tx_hold_com1,
|
||||||
|
1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* CTS low */
|
||||||
|
termios_stopped_com1 = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NO_MORE_INTR :
|
||||||
|
/* No more interrupts */
|
||||||
|
if(off != 0)
|
||||||
|
{
|
||||||
|
/* Update rx buffer */
|
||||||
|
rtems_termios_enqueue_raw_characters(termios_ttyp_com1,
|
||||||
|
(char *)buf,
|
||||||
|
off);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
case TRANSMITTER_HODING_REGISTER_EMPTY :
|
||||||
|
/*
|
||||||
|
* TX holding empty: we have to disable these interrupts
|
||||||
|
* if there is nothing more to send.
|
||||||
|
*/
|
||||||
|
|
||||||
|
ret = rtems_termios_dequeue_characters(termios_ttyp_com1, 1);
|
||||||
|
|
||||||
|
/* If nothing else to send disable interrupts */
|
||||||
|
if(ret == 0 && uart_data[BSP_UART_COM1].hwFlow)
|
||||||
|
{
|
||||||
|
uwrite(BSP_UART_COM1, IER,
|
||||||
|
(RECEIVE_ENABLE |
|
||||||
|
RECEIVER_LINE_ST_ENABLE |
|
||||||
|
MODEM_ENABLE
|
||||||
|
)
|
||||||
|
);
|
||||||
|
termios_tx_active_com1 = 0;
|
||||||
|
}
|
||||||
|
else if(ret == 0)
|
||||||
|
{
|
||||||
|
uwrite(BSP_UART_COM1, IER,
|
||||||
|
(RECEIVE_ENABLE |
|
||||||
|
RECEIVER_LINE_ST_ENABLE
|
||||||
|
)
|
||||||
|
);
|
||||||
|
termios_tx_active_com1 = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RECEIVER_DATA_AVAIL :
|
||||||
|
case CHARACTER_TIMEOUT_INDICATION:
|
||||||
|
/* RX data ready */
|
||||||
|
assert(off < sizeof(buf));
|
||||||
|
buf[off++] = uread(BSP_UART_COM1, RBR);
|
||||||
|
break;
|
||||||
|
case RECEIVER_ERROR:
|
||||||
|
/* RX error: eat character */
|
||||||
|
uartError(BSP_UART_COM1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* Should not happen */
|
||||||
|
assert(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
BSP_uart_termios_isr_com2()
|
||||||
|
{
|
||||||
|
unsigned char buf[40];
|
||||||
|
unsigned char val;
|
||||||
|
int off, ret, vect;
|
||||||
|
|
||||||
|
off = 0;
|
||||||
|
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
vect = uread(BSP_UART_COM2, IIR) & 0xf;
|
||||||
|
|
||||||
|
switch(vect)
|
||||||
|
{
|
||||||
|
case MODEM_STATUS :
|
||||||
|
val = uread(BSP_UART_COM2, MSR);
|
||||||
|
if(uart_data[BSP_UART_COM2].hwFlow)
|
||||||
|
{
|
||||||
|
if(val & CTS)
|
||||||
|
{
|
||||||
|
/* CTS high */
|
||||||
|
termios_stopped_com2 = 0;
|
||||||
|
if(termios_tx_hold_valid_com2)
|
||||||
|
{
|
||||||
|
termios_tx_hold_valid_com2 = 0;
|
||||||
|
BSP_uart_termios_write_com2(0, &termios_tx_hold_com2,
|
||||||
|
1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* CTS low */
|
||||||
|
termios_stopped_com2 = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NO_MORE_INTR :
|
||||||
|
/* No more interrupts */
|
||||||
|
if(off != 0)
|
||||||
|
{
|
||||||
|
/* Update rx buffer */
|
||||||
|
rtems_termios_enqueue_raw_characters(termios_ttyp_com2,
|
||||||
|
(char *)buf,
|
||||||
|
off);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
case TRANSMITTER_HODING_REGISTER_EMPTY :
|
||||||
|
/*
|
||||||
|
* TX holding empty: we have to disable these interrupts
|
||||||
|
* if there is nothing more to send.
|
||||||
|
*/
|
||||||
|
|
||||||
|
ret = rtems_termios_dequeue_characters(termios_ttyp_com2, 1);
|
||||||
|
|
||||||
|
/* If nothing else to send disable interrupts */
|
||||||
|
if(ret == 0 && uart_data[BSP_UART_COM2].hwFlow)
|
||||||
|
{
|
||||||
|
uwrite(BSP_UART_COM2, IER,
|
||||||
|
(RECEIVE_ENABLE |
|
||||||
|
RECEIVER_LINE_ST_ENABLE |
|
||||||
|
MODEM_ENABLE
|
||||||
|
)
|
||||||
|
);
|
||||||
|
termios_tx_active_com2 = 0;
|
||||||
|
}
|
||||||
|
else if(ret == 0)
|
||||||
|
{
|
||||||
|
uwrite(BSP_UART_COM2, IER,
|
||||||
|
(RECEIVE_ENABLE |
|
||||||
|
RECEIVER_LINE_ST_ENABLE
|
||||||
|
)
|
||||||
|
);
|
||||||
|
termios_tx_active_com2 = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RECEIVER_DATA_AVAIL :
|
||||||
|
case CHARACTER_TIMEOUT_INDICATION:
|
||||||
|
/* RX data ready */
|
||||||
|
assert(off < sizeof(buf));
|
||||||
|
buf[off++] = uread(BSP_UART_COM2, RBR);
|
||||||
|
break;
|
||||||
|
case RECEIVER_ERROR:
|
||||||
|
/* RX error: eat character */
|
||||||
|
uartError(BSP_UART_COM2);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* Should not happen */
|
||||||
|
assert(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
169
c/src/lib/libbsp/powerpc/shared/console/uart.h
Normal file
169
c/src/lib/libbsp/powerpc/shared/console/uart.h
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This software is Copyright (C) 1998 by T.sqware - all rights limited
|
||||||
|
* It is provided in to the public domain "as is", can be freely modified
|
||||||
|
* as far as this copyight notice is kept unchanged, but does not imply
|
||||||
|
* an endorsement by T.sqware of the product in which it is included.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _BSPUART_H
|
||||||
|
#define _BSPUART_H
|
||||||
|
|
||||||
|
void BSP_uart_init(int uart, int baud, int hwFlow);
|
||||||
|
void BSP_uart_set_baud(int aurt, int baud);
|
||||||
|
void BSP_uart_intr_ctrl(int uart, int cmd);
|
||||||
|
void BSP_uart_throttle(int uart);
|
||||||
|
void BSP_uart_unthrottle(int uart);
|
||||||
|
int BSP_uart_polled_status(int uart);
|
||||||
|
void BSP_uart_polled_write(int uart, int val);
|
||||||
|
int BSP_uart_polled_read(int uart);
|
||||||
|
void BSP_uart_termios_set(int uart, void *ttyp);
|
||||||
|
int BSP_uart_termios_write_com1(int minor, const char *buf, int len);
|
||||||
|
int BSP_uart_termios_write_com2(int minor, const char *buf, int len);
|
||||||
|
void BSP_uart_termios_isr_com1();
|
||||||
|
void BSP_uart_termios_isr_com2();
|
||||||
|
void BSP_uart_dbgisr_com1(void);
|
||||||
|
void BSP_uart_dbgisr_com2(void);
|
||||||
|
extern unsigned BSP_poll_char_via_serial(void);
|
||||||
|
extern void BSP_output_char_via_serial(int val);
|
||||||
|
extern int BSPConsolePort;
|
||||||
|
extern int BSPBaseBaud;
|
||||||
|
/*
|
||||||
|
* Command values for BSP_uart_intr_ctrl(),
|
||||||
|
* values are strange in order to catch errors
|
||||||
|
* with assert
|
||||||
|
*/
|
||||||
|
#define BSP_UART_INTR_CTRL_DISABLE (0)
|
||||||
|
#define BSP_UART_INTR_CTRL_GDB (0xaa) /* RX only */
|
||||||
|
#define BSP_UART_INTR_CTRL_ENABLE (0xbb) /* Normal operations */
|
||||||
|
#define BSP_UART_INTR_CTRL_TERMIOS (0xcc) /* RX & line status */
|
||||||
|
|
||||||
|
/* Return values for uart_polled_status() */
|
||||||
|
#define BSP_UART_STATUS_ERROR (-1) /* No character */
|
||||||
|
#define BSP_UART_STATUS_NOCHAR (0) /* No character */
|
||||||
|
#define BSP_UART_STATUS_CHAR (1) /* Character present */
|
||||||
|
#define BSP_UART_STATUS_BREAK (2) /* Break point is detected */
|
||||||
|
|
||||||
|
/* PC UART definitions */
|
||||||
|
#define BSP_UART_COM1 (0)
|
||||||
|
#define BSP_UART_COM2 (1)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Base IO for UART
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define COM1_BASE_IO 0x3F8
|
||||||
|
#define COM2_BASE_IO 0x2F8
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Offsets from base
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* DLAB 0 */
|
||||||
|
#define RBR (0) /* Rx Buffer Register (read) */
|
||||||
|
#define THR (0) /* Tx Buffer Register (write) */
|
||||||
|
#define IER (1) /* Interrupt Enable Register */
|
||||||
|
|
||||||
|
/* DLAB X */
|
||||||
|
#define IIR (2) /* Interrupt Ident Register (read) */
|
||||||
|
#define FCR (2) /* FIFO Control Register (write) */
|
||||||
|
#define LCR (3) /* Line Control Register */
|
||||||
|
#define MCR (4) /* Modem Control Register */
|
||||||
|
#define LSR (5) /* Line Status Register */
|
||||||
|
#define MSR (6) /* Modem Status Register */
|
||||||
|
#define SCR (7) /* Scratch register */
|
||||||
|
|
||||||
|
/* DLAB 1 */
|
||||||
|
#define DLL (0) /* Divisor Latch, LSB */
|
||||||
|
#define DLM (1) /* Divisor Latch, MSB */
|
||||||
|
#define AFR (2) /* Alternate Function register */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Interrupt source definition via IIR
|
||||||
|
*/
|
||||||
|
#define MODEM_STATUS 0
|
||||||
|
#define NO_MORE_INTR 1
|
||||||
|
#define TRANSMITTER_HODING_REGISTER_EMPTY 2
|
||||||
|
#define RECEIVER_DATA_AVAIL 4
|
||||||
|
#define RECEIVER_ERROR 6
|
||||||
|
#define CHARACTER_TIMEOUT_INDICATION 12
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Bits definition of IER
|
||||||
|
*/
|
||||||
|
#define RECEIVE_ENABLE 0x1
|
||||||
|
#define TRANSMIT_ENABLE 0x2
|
||||||
|
#define RECEIVER_LINE_ST_ENABLE 0x4
|
||||||
|
#define MODEM_ENABLE 0x8
|
||||||
|
#define INTERRUPT_DISABLE 0x0
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Bits definition of the Line Status Register (LSR)
|
||||||
|
*/
|
||||||
|
#define DR 0x01 /* Data Ready */
|
||||||
|
#define OE 0x02 /* Overrun Error */
|
||||||
|
#define PE 0x04 /* Parity Error */
|
||||||
|
#define FE 0x08 /* Framing Error */
|
||||||
|
#define BI 0x10 /* Break Interrupt */
|
||||||
|
#define THRE 0x20 /* Transmitter Holding Register Empty */
|
||||||
|
#define TEMT 0x40 /* Transmitter Empty */
|
||||||
|
#define ERFIFO 0x80 /* Error receive Fifo */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Bits definition of the MODEM Control Register (MCR)
|
||||||
|
*/
|
||||||
|
#define DTR 0x01 /* Data Terminal Ready */
|
||||||
|
#define RTS 0x02 /* Request To Send */
|
||||||
|
#define OUT_1 0x04 /* Output 1, (reserved on COMPAQ I/O Board) */
|
||||||
|
#define OUT_2 0x08 /* Output 2, Enable Asynchronous Port Interrupts */
|
||||||
|
#define LB 0x10 /* Enable Internal Loop Back */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Bits definition of the Line Control Register (LCR)
|
||||||
|
*/
|
||||||
|
#define CHR_5_BITS 0
|
||||||
|
#define CHR_6_BITS 1
|
||||||
|
#define CHR_7_BITS 2
|
||||||
|
#define CHR_8_BITS 3
|
||||||
|
|
||||||
|
#define WL 0x03 /* Word length mask */
|
||||||
|
#define STB 0x04 /* 1 Stop Bit, otherwise 2 Stop Bits */
|
||||||
|
#define PEN 0x08 /* Parity Enabled */
|
||||||
|
#define EPS 0x10 /* Even Parity Select, otherwise Odd */
|
||||||
|
#define SP 0x20 /* Stick Parity */
|
||||||
|
#define BCB 0x40 /* Break Control Bit */
|
||||||
|
#define DLAB 0x80 /* Enable Divisor Latch Access */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Bits definition of the MODEM Status Register (MSR)
|
||||||
|
*/
|
||||||
|
#define DCTS 0x01 /* Delta Clear To Send */
|
||||||
|
#define DDSR 0x02 /* Delta Data Set Ready */
|
||||||
|
#define TERI 0x04 /* Trailing Edge Ring Indicator */
|
||||||
|
#define DDCD 0x08 /* Delta Carrier Detect Indicator */
|
||||||
|
#define CTS 0x10 /* Clear To Send (when loop back is active) */
|
||||||
|
#define DSR 0x20 /* Data Set Ready (when loop back is active) */
|
||||||
|
#define RI 0x40 /* Ring Indicator (when loop back is active) */
|
||||||
|
#define DCD 0x80 /* Data Carrier Detect (when loop back is active) */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Bits definition of the FIFO Control Register : WD16C552 or NS16550
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define FIFO_CTRL 0x01 /* Set to 1 permit access to other bits */
|
||||||
|
#define FIFO_EN 0x01 /* Enable the FIFO */
|
||||||
|
#define XMIT_RESET 0x02 /* Transmit FIFO Reset */
|
||||||
|
#define RCV_RESET 0x04 /* Receive FIFO Reset */
|
||||||
|
#define FCR3 0x08 /* do not understand manual! */
|
||||||
|
|
||||||
|
#define RECEIVE_FIFO_TRIGGER1 0x0 /* trigger recieve interrupt after 1 byte */
|
||||||
|
#define RECEIVE_FIFO_TRIGGER4 0x40 /* trigger recieve interrupt after 4 byte */
|
||||||
|
#define RECEIVE_FIFO_TRIGGER8 0x80 /* trigger recieve interrupt after 8 byte */
|
||||||
|
#define RECEIVE_FIFO_TRIGGER12 0xc0 /* trigger recieve interrupt after 12 byte */
|
||||||
|
#define TRIG_LEVEL 0xc0 /* Mask for the trigger level */
|
||||||
|
|
||||||
|
#endif /* _BSPUART_H */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
32
c/src/lib/libbsp/powerpc/shared/dec21140/Makefile.in
Normal file
32
c/src/lib/libbsp/powerpc/shared/dec21140/Makefile.in
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
#
|
||||||
|
# $Id$
|
||||||
|
#
|
||||||
|
|
||||||
|
@SET_MAKE@
|
||||||
|
srcdir = @srcdir@
|
||||||
|
top_srcdir = @top_srcdir@
|
||||||
|
top_builddir = ../../..
|
||||||
|
subdir = powerpc/shared/dec21140
|
||||||
|
|
||||||
|
RTEMS_ROOT = @RTEMS_ROOT@
|
||||||
|
PROJECT_ROOT = @PROJECT_ROOT@
|
||||||
|
|
||||||
|
VPATH = @srcdir@
|
||||||
|
|
||||||
|
H_FILES =
|
||||||
|
|
||||||
|
SRCS = $(C_FILES) $(H_FILES)
|
||||||
|
|
||||||
|
include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
|
||||||
|
include $(RTEMS_ROOT)/make/leaf.cfg
|
||||||
|
|
||||||
|
INSTALL_CHANGE = @INSTALL_CHANGE@
|
||||||
|
|
||||||
|
all: ${ARCH} $(SRCS)
|
||||||
|
|
||||||
|
# the .rel file built here will be put into libbsp.a by ../wrapup/Makefile
|
||||||
|
install: all
|
||||||
|
|
||||||
|
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||||
|
cd $(top_builddir) \
|
||||||
|
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
|
||||||
905
c/src/lib/libbsp/powerpc/shared/dec21140/dec21140.c
Normal file
905
c/src/lib/libbsp/powerpc/shared/dec21140/dec21140.c
Normal file
@@ -0,0 +1,905 @@
|
|||||||
|
/*
|
||||||
|
* RTEMS driver for TULIP based Ethernet Controller
|
||||||
|
*
|
||||||
|
* Copyright (C) 1999 Emmanuel Raguet. raguet@crf.canon.fr
|
||||||
|
*
|
||||||
|
* The license and distribution terms for this file may be
|
||||||
|
* found in found in the file LICENSE in this distribution or at
|
||||||
|
* http://www.OARcorp.com/rtems/license.html.
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <bsp.h>
|
||||||
|
#include <bsp/pci.h>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <rtems/error.h>
|
||||||
|
#include <rtems/rtems_bsdnet.h>
|
||||||
|
|
||||||
|
#include <libcpu/cpu.h>
|
||||||
|
#include <libcpu/io.h>
|
||||||
|
#include <libcpu/byteorder.h>
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/mbuf.h>
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/sockio.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netinet/if_ether.h>
|
||||||
|
|
||||||
|
#include <bsp/irq.h>
|
||||||
|
|
||||||
|
#ifdef malloc
|
||||||
|
#undef malloc
|
||||||
|
#endif
|
||||||
|
#ifdef free
|
||||||
|
#undef free
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define DEC_DEBUG
|
||||||
|
|
||||||
|
#define PCI_INVALID_VENDORDEVICEID 0xffffffff
|
||||||
|
#define PCI_VENDOR_ID_DEC 0x1011
|
||||||
|
#define PCI_DEVICE_ID_DEC_TULIP_FAST 0x0009
|
||||||
|
|
||||||
|
#define IO_MASK 0x3
|
||||||
|
#define MEM_MASK 0xF
|
||||||
|
#define MASK_OFFSET 0xF
|
||||||
|
|
||||||
|
/* command and status registers, 32-bit access, only if IO-ACCESS */
|
||||||
|
#define ioCSR0 0x00 /* bus mode register */
|
||||||
|
#define ioCSR1 0x08 /* transmit poll demand */
|
||||||
|
#define ioCSR2 0x10 /* receive poll demand */
|
||||||
|
#define ioCSR3 0x18 /* receive list base address */
|
||||||
|
#define ioCSR4 0x20 /* transmit list base address */
|
||||||
|
#define ioCSR5 0x28 /* status register */
|
||||||
|
#define ioCSR6 0x30 /* operation mode register */
|
||||||
|
#define ioCSR7 0x38 /* interrupt mask register */
|
||||||
|
#define ioCSR8 0x40 /* missed frame counter */
|
||||||
|
#define ioCSR9 0x48 /* Ethernet ROM register */
|
||||||
|
#define ioCSR10 0x50 /* reserved */
|
||||||
|
#define ioCSR11 0x58 /* full-duplex register */
|
||||||
|
#define ioCSR12 0x60 /* SIA status register */
|
||||||
|
#define ioCSR13 0x68
|
||||||
|
#define ioCSR14 0x70
|
||||||
|
#define ioCSR15 0x78 /* SIA general register */
|
||||||
|
|
||||||
|
/* command and status registers, 32-bit access, only if MEMORY-ACCESS */
|
||||||
|
#define memCSR0 0x00 /* bus mode register */
|
||||||
|
#define memCSR1 0x02 /* transmit poll demand */
|
||||||
|
#define memCSR2 0x04 /* receive poll demand */
|
||||||
|
#define memCSR3 0x06 /* receive list base address */
|
||||||
|
#define memCSR4 0x08 /* transmit list base address */
|
||||||
|
#define memCSR5 0x0A /* status register */
|
||||||
|
#define memCSR6 0x0C /* operation mode register */
|
||||||
|
#define memCSR7 0x0E /* interrupt mask register */
|
||||||
|
#define memCSR8 0x10 /* missed frame counter */
|
||||||
|
#define memCSR9 0x12 /* Ethernet ROM register */
|
||||||
|
#define memCSR10 0x14 /* reserved */
|
||||||
|
#define memCSR11 0x16 /* full-duplex register */
|
||||||
|
#define memCSR12 0x18 /* SIA status register */
|
||||||
|
#define memCSR13 0x1A
|
||||||
|
#define memCSR14 0x1C
|
||||||
|
#define memCSR15 0x1E /* SIA general register */
|
||||||
|
|
||||||
|
#define DEC_REGISTER_SIZE 0x100 /* to reserve virtual memory */
|
||||||
|
|
||||||
|
#define RESET_CHIP 0x00000001
|
||||||
|
#define CSR0_MODE 0x01b08000 /* 01a08000 */
|
||||||
|
#define ROM_ADDRESS 0x00004800
|
||||||
|
#define CSR6_INIT 0x020c0000 /* 020c0000 */
|
||||||
|
#define CSR6_TX 0x00002000
|
||||||
|
#define CSR6_TXRX 0x00002002
|
||||||
|
#define IT_SETUP 0x00010040 /* 0001ebef */
|
||||||
|
#define CLEAR_IT 0xFFFFFFFF
|
||||||
|
#define NO_IT 0x00000000
|
||||||
|
|
||||||
|
#define NRXBUFS 7 /* number of receive buffers */
|
||||||
|
#define NTXBUFS 1 /* number of transmit buffers */
|
||||||
|
|
||||||
|
/* message descriptor entry */
|
||||||
|
struct MD {
|
||||||
|
volatile unsigned long status;
|
||||||
|
volatile unsigned long counts;
|
||||||
|
volatile unsigned char *buf1, *buf2;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Number of WDs supported by this driver
|
||||||
|
*/
|
||||||
|
#define NDECDRIVER 1
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Receive buffer size -- Allow for a full ethernet packet including CRC
|
||||||
|
*/
|
||||||
|
#define RBUF_SIZE 1536
|
||||||
|
|
||||||
|
#define ET_MINLEN 60 /* minimum message length */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* RTEMS event used by interrupt handler to signal driver tasks.
|
||||||
|
* This must not be any of the events used by the network task synchronization.
|
||||||
|
*/
|
||||||
|
#define INTERRUPT_EVENT RTEMS_EVENT_1
|
||||||
|
|
||||||
|
/*
|
||||||
|
* RTEMS event used to start transmit daemon.
|
||||||
|
* This must not be the same as INTERRUPT_EVENT.
|
||||||
|
*/
|
||||||
|
#define START_TRANSMIT_EVENT RTEMS_EVENT_2
|
||||||
|
|
||||||
|
#if (MCLBYTES < RBUF_SIZE)
|
||||||
|
# error "Driver must have MCLBYTES > RBUF_SIZE"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Per-device data
|
||||||
|
*/
|
||||||
|
struct dec21140_softc {
|
||||||
|
struct arpcom arpcom;
|
||||||
|
rtems_irq_connect_data irqInfo;
|
||||||
|
volatile struct MD *MDbase;
|
||||||
|
volatile unsigned char *bufferBase;
|
||||||
|
int acceptBroadcast;
|
||||||
|
int rxBdCount;
|
||||||
|
int txBdCount;
|
||||||
|
rtems_id rxDaemonTid;
|
||||||
|
rtems_id txDaemonTid;
|
||||||
|
|
||||||
|
unsigned int port;
|
||||||
|
volatile unsigned int *base;
|
||||||
|
unsigned long bpar;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Statistics
|
||||||
|
*/
|
||||||
|
unsigned long rxInterrupts;
|
||||||
|
unsigned long rxNotFirst;
|
||||||
|
unsigned long rxNotLast;
|
||||||
|
unsigned long rxGiant;
|
||||||
|
unsigned long rxNonOctet;
|
||||||
|
unsigned long rxRunt;
|
||||||
|
unsigned long rxBadCRC;
|
||||||
|
unsigned long rxOverrun;
|
||||||
|
unsigned long rxCollision;
|
||||||
|
|
||||||
|
unsigned long txInterrupts;
|
||||||
|
unsigned long txDeferred;
|
||||||
|
unsigned long txHeartbeat;
|
||||||
|
unsigned long txLateCollision;
|
||||||
|
unsigned long txRetryLimit;
|
||||||
|
unsigned long txUnderrun;
|
||||||
|
unsigned long txLostCarrier;
|
||||||
|
unsigned long txRawWait;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct dec21140_softc dec21140_softc[NDECDRIVER];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* DEC21140 interrupt handler
|
||||||
|
*/
|
||||||
|
static rtems_isr
|
||||||
|
dec21140Enet_interrupt_handler (rtems_vector_number v)
|
||||||
|
{
|
||||||
|
volatile unsigned int *tbase;
|
||||||
|
unsigned long status;
|
||||||
|
|
||||||
|
unsigned int sc;
|
||||||
|
|
||||||
|
tbase = dec21140_softc[0].base ;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read status
|
||||||
|
*/
|
||||||
|
st_le32((tbase+memCSR7), NO_IT);
|
||||||
|
status = ld_le32(tbase+memCSR5);
|
||||||
|
st_le32((tbase+memCSR5), CLEAR_IT);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Frame received?
|
||||||
|
*/
|
||||||
|
if (status & 0x00000040){
|
||||||
|
dec21140_softc[0].rxInterrupts++;
|
||||||
|
sc = rtems_event_send (dec21140_softc[0].rxDaemonTid, INTERRUPT_EVENT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nopOn(const rtems_irq_connect_data* notUsed)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* code should be moved from dec21140Enet_initialize_hardware
|
||||||
|
* to this location
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dec21140IsOn(const rtems_irq_connect_data* irq)
|
||||||
|
{
|
||||||
|
return BSP_irq_enabled_at_i8259s (irq->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read and write the MII registers using software-generated serial
|
||||||
|
* MDIO protocol.
|
||||||
|
*/
|
||||||
|
#define MDIO_SHIFT_CLK 0x10000
|
||||||
|
#define MDIO_DATA_WRITE0 0x00000
|
||||||
|
#define MDIO_DATA_WRITE1 0x20000
|
||||||
|
#define MDIO_ENB 0x00000
|
||||||
|
#define MDIO_ENB_IN 0x40000
|
||||||
|
#define MDIO_DATA_READ 0x80000
|
||||||
|
|
||||||
|
static int mdio_read(volatile unsigned int *ioaddr, int phy_id, int location)
|
||||||
|
{
|
||||||
|
int i, i3;
|
||||||
|
int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
|
||||||
|
unsigned short retval = 0;
|
||||||
|
|
||||||
|
/* Establish sync by sending at least 32 logic ones. */
|
||||||
|
for (i = 32; i >= 0; i--) {
|
||||||
|
st_le32(ioaddr, MDIO_ENB | MDIO_DATA_WRITE1);
|
||||||
|
for(i3=0; i3<1000; i3++);
|
||||||
|
st_le32(ioaddr, MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK);
|
||||||
|
for(i3=0; i3<1000; i3++);
|
||||||
|
}
|
||||||
|
/* Shift the read command bits out. */
|
||||||
|
for (i = 17; i >= 0; i--) {
|
||||||
|
int dataval = (read_cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0;
|
||||||
|
st_le32(ioaddr, dataval);
|
||||||
|
for(i3=0; i3<1000; i3++);
|
||||||
|
st_le32(ioaddr, dataval | MDIO_SHIFT_CLK);
|
||||||
|
for(i3=0; i3<1000; i3++);
|
||||||
|
st_le32(ioaddr, dataval);
|
||||||
|
for(i3=0; i3<1000; i3++);
|
||||||
|
}
|
||||||
|
st_le32(ioaddr, MDIO_ENB_IN | MDIO_SHIFT_CLK);
|
||||||
|
for(i3=0; i3<1000; i3++);
|
||||||
|
st_le32(ioaddr, MDIO_ENB_IN);
|
||||||
|
|
||||||
|
for (i = 16; i > 0; i--) {
|
||||||
|
st_le32(ioaddr, MDIO_ENB_IN | MDIO_SHIFT_CLK);
|
||||||
|
for(i3=0; i3<1000; i3++);
|
||||||
|
retval = (retval << 1) | ((ld_le32(ioaddr) & MDIO_DATA_READ) ? 1 : 0);
|
||||||
|
st_le32(ioaddr, MDIO_ENB_IN);
|
||||||
|
for(i3=0; i3<1000; i3++);
|
||||||
|
}
|
||||||
|
/* Clear out extra bits. */
|
||||||
|
for (i = 16; i > 0; i--) {
|
||||||
|
st_le32(ioaddr, MDIO_ENB_IN | MDIO_SHIFT_CLK);
|
||||||
|
for(i3=0; i3<1000; i3++);
|
||||||
|
st_le32(ioaddr, MDIO_ENB_IN);
|
||||||
|
for(i3=0; i3<1000; i3++);
|
||||||
|
}
|
||||||
|
return ( ((retval<<8)&0xff00) | ((retval>>8)&0xff) );
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mdio_write(volatile unsigned int *ioaddr, int phy_id, int location, int value)
|
||||||
|
{
|
||||||
|
int i, i3;
|
||||||
|
int cmd = (0x5002 << 16) | (phy_id << 23) | (location << 18) | value;
|
||||||
|
|
||||||
|
/* Establish sync by sending at least 32 logic ones. */
|
||||||
|
for (i = 32; i >= 0; i--) {
|
||||||
|
st_le32(ioaddr, MDIO_ENB | MDIO_DATA_WRITE1);
|
||||||
|
for(i3=0; i3<1000; i3++);
|
||||||
|
st_le32(ioaddr, MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK);
|
||||||
|
for(i3=0; i3<1000; i3++);
|
||||||
|
}
|
||||||
|
/* Shift the read command bits out. */
|
||||||
|
for (i = 31; i >= 0; i--) {
|
||||||
|
int dataval = (cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0;
|
||||||
|
st_le32(ioaddr, dataval);
|
||||||
|
for(i3=0; i3<1000; i3++);
|
||||||
|
st_le32(ioaddr, dataval | MDIO_SHIFT_CLK);
|
||||||
|
for(i3=0; i3<1000; i3++);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clear out extra bits. */
|
||||||
|
for (i = 2; i > 0; i--) {
|
||||||
|
st_le32(ioaddr, MDIO_ENB_IN);
|
||||||
|
for(i3=0; i3<1000; i3++);
|
||||||
|
st_le32(ioaddr, MDIO_ENB_IN | MDIO_SHIFT_CLK);
|
||||||
|
for(i3=0; i3<1000; i3++);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This routine reads a word (16 bits) from the serial EEPROM.
|
||||||
|
*/
|
||||||
|
/* EEPROM_Ctrl bits. */
|
||||||
|
#define EE_SHIFT_CLK 0x02 /* EEPROM shift clock. */
|
||||||
|
#define EE_CS 0x01 /* EEPROM chip select. */
|
||||||
|
#define EE_DATA_WRITE 0x04 /* EEPROM chip data in. */
|
||||||
|
#define EE_WRITE_0 0x01
|
||||||
|
#define EE_WRITE_1 0x05
|
||||||
|
#define EE_DATA_READ 0x08 /* EEPROM chip data out. */
|
||||||
|
#define EE_ENB (0x4800 | EE_CS)
|
||||||
|
|
||||||
|
/* The EEPROM commands include the alway-set leading bit. */
|
||||||
|
#define EE_WRITE_CMD (5 << 6)
|
||||||
|
#define EE_READ_CMD (6 << 6)
|
||||||
|
#define EE_ERASE_CMD (7 << 6)
|
||||||
|
|
||||||
|
static int eeget16(volatile unsigned int *ioaddr, int location)
|
||||||
|
{
|
||||||
|
int i, i3;
|
||||||
|
unsigned short retval = 0;
|
||||||
|
int read_cmd = location | EE_READ_CMD;
|
||||||
|
|
||||||
|
st_le32(ioaddr, EE_ENB & ~EE_CS);
|
||||||
|
st_le32(ioaddr, EE_ENB);
|
||||||
|
|
||||||
|
/* Shift the read command bits out. */
|
||||||
|
for (i = 10; i >= 0; i--) {
|
||||||
|
short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
|
||||||
|
st_le32(ioaddr, EE_ENB | dataval);
|
||||||
|
for (i3=0; i3<1000; i3++) ;
|
||||||
|
st_le32(ioaddr, EE_ENB | dataval | EE_SHIFT_CLK);
|
||||||
|
for (i3=0; i3<1000; i3++) ;
|
||||||
|
st_le32(ioaddr, EE_ENB | dataval); /* Finish EEPROM a clock tick. */
|
||||||
|
for (i3=0; i3<1000; i3++) ;
|
||||||
|
}
|
||||||
|
st_le32(ioaddr, EE_ENB);
|
||||||
|
|
||||||
|
for (i = 16; i > 0; i--) {
|
||||||
|
st_le32(ioaddr, EE_ENB | EE_SHIFT_CLK);
|
||||||
|
for (i3=0; i3<1000; i3++) ;
|
||||||
|
retval = (retval << 1) | ((ld_le32(ioaddr) & EE_DATA_READ) ? 1 : 0);
|
||||||
|
st_le32(ioaddr, EE_ENB);
|
||||||
|
for (i3=0; i3<1000; i3++) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Terminate the EEPROM access. */
|
||||||
|
st_le32(ioaddr, EE_ENB & ~EE_CS);
|
||||||
|
return ( ((retval<<8)&0xff00) | ((retval>>8)&0xff) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize the ethernet hardware
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
dec21140Enet_initialize_hardware (struct dec21140_softc *sc)
|
||||||
|
{
|
||||||
|
rtems_status_code st;
|
||||||
|
volatile unsigned int *tbase;
|
||||||
|
union {char c[64]; unsigned short s[32];} rombuf;
|
||||||
|
int i, i2, i3;
|
||||||
|
volatile unsigned char *cp, direction, *setup_frm, *eaddrs;
|
||||||
|
unsigned long csr12_val, mii_reg0;
|
||||||
|
volatile unsigned char *buffer;
|
||||||
|
volatile struct MD *rmd;
|
||||||
|
|
||||||
|
|
||||||
|
tbase = sc->base;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* WARNING : First write in CSR6
|
||||||
|
* Then Reset the chip ( 1 in CSR0)
|
||||||
|
*/
|
||||||
|
|
||||||
|
st_le32( (tbase+memCSR6), CSR6_INIT);
|
||||||
|
st_le32( (tbase+memCSR0), RESET_CHIP);
|
||||||
|
for(i3=0; i3<1000; i3++);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Init CSR0
|
||||||
|
*/
|
||||||
|
st_le32( (tbase+memCSR0), CSR0_MODE);
|
||||||
|
|
||||||
|
csr12_val = ld_le32( (tbase+memCSR8) );
|
||||||
|
|
||||||
|
for (i=0; i<32; i++){
|
||||||
|
rombuf.s[i] = eeget16(tbase+memCSR9, i);
|
||||||
|
}
|
||||||
|
memcpy (sc->arpcom.ac_enaddr, rombuf.c+20, ETHER_ADDR_LEN);
|
||||||
|
|
||||||
|
mii_reg0 = mdio_read(tbase+memCSR9, 0, 0);
|
||||||
|
mdio_write(tbase+memCSR9, 0, 0, mii_reg0 | 0x1000);
|
||||||
|
|
||||||
|
#ifdef DEC_DEBUG
|
||||||
|
printk("DC21140 %x:%x:%x:%x:%x:%x IRQ %d IO %x M %x .........\n",
|
||||||
|
sc->arpcom.ac_enaddr[0], sc->arpcom.ac_enaddr[1],
|
||||||
|
sc->arpcom.ac_enaddr[2], sc->arpcom.ac_enaddr[3],
|
||||||
|
sc->arpcom.ac_enaddr[4], sc->arpcom.ac_enaddr[5],
|
||||||
|
sc->irqInfo.name, sc->port, (unsigned) sc->base);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Init RX ring
|
||||||
|
*/
|
||||||
|
sc->rxBdCount = 0;
|
||||||
|
cp = (volatile unsigned char *)malloc((NRXBUFS+NTXBUFS)*(sizeof(struct MD)+ RBUF_SIZE) + PPC_CACHE_ALIGNMENT);
|
||||||
|
sc->bufferBase = cp;
|
||||||
|
if ((unsigned int)cp & (PPC_CACHE_ALIGNMENT-1))
|
||||||
|
cp = (volatile unsigned char *) (((unsigned int)cp + PPC_CACHE_ALIGNMENT) & ~(PPC_CACHE_ALIGNMENT-1));
|
||||||
|
#ifdef PCI_BRIDGE_DOES_NOT_ENSURE_CACHE_COHERENCY_FOR_DMA
|
||||||
|
if (_CPU_is_paging_enabled())
|
||||||
|
_CPU_change_memory_mapping_attribute
|
||||||
|
(NULL, cp,
|
||||||
|
(NRXBUFS+NTXBUFS)*(sizeof(struct MD)+ RBUF_SIZE),
|
||||||
|
PTE_CACHE_DISABLE | PTE_WRITABLE);
|
||||||
|
#endif
|
||||||
|
rmd = (volatile struct MD*)cp;
|
||||||
|
sc->MDbase = rmd;
|
||||||
|
buffer = cp + ((NRXBUFS+NTXBUFS)*sizeof(struct MD));
|
||||||
|
st_le32( (tbase+memCSR3), (long)((long)(sc->MDbase) + PREP_PCI_DRAM_OFFSET));
|
||||||
|
for (i=0 ; i<NRXBUFS; i++){
|
||||||
|
rmd->buf2 = (volatile unsigned char *) 0;
|
||||||
|
rmd->buf1 = (buffer + (i*RBUF_SIZE) + PREP_PCI_DRAM_OFFSET);
|
||||||
|
rmd->counts = 0xfcc00000 | (RBUF_SIZE);
|
||||||
|
rmd->status = 0x80000000;
|
||||||
|
rmd++;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* mark last RX buffer.
|
||||||
|
*/
|
||||||
|
sc->MDbase [NRXBUFS-1].counts = 0xfec00000 | (RBUF_SIZE);
|
||||||
|
/*
|
||||||
|
* Init TX ring
|
||||||
|
*/
|
||||||
|
sc->txBdCount = 0;
|
||||||
|
st_le32( (tbase+memCSR4), (long)(((long)(rmd)) + PREP_PCI_DRAM_OFFSET));
|
||||||
|
rmd->buf2 = (volatile unsigned char *) 0;
|
||||||
|
rmd->buf1 = buffer + (NRXBUFS*RBUF_SIZE) + PREP_PCI_DRAM_OFFSET;
|
||||||
|
rmd->counts = 0x62000000;
|
||||||
|
rmd->status = 0x0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set up interrupts
|
||||||
|
*/
|
||||||
|
st_le32( (tbase+memCSR5), IT_SETUP);
|
||||||
|
st_le32( (tbase+memCSR7), IT_SETUP);
|
||||||
|
|
||||||
|
sc->irqInfo.hdl = (rtems_irq_hdl)dec21140Enet_interrupt_handler;
|
||||||
|
sc->irqInfo.on = nopOn;
|
||||||
|
sc->irqInfo.off = nopOn;
|
||||||
|
sc->irqInfo.isOn = dec21140IsOn;
|
||||||
|
st = BSP_install_rtems_irq_handler (&sc->irqInfo);
|
||||||
|
if (!st)
|
||||||
|
rtems_panic ("Can't attach DEC21140 interrupt handler for irq %d\n",
|
||||||
|
sc->irqInfo.name);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Start TX for setup frame
|
||||||
|
*/
|
||||||
|
st_le32( (tbase+memCSR6), CSR6_INIT | CSR6_TX);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Build setup frame
|
||||||
|
*/
|
||||||
|
setup_frm = rmd->buf1 - PREP_PCI_DRAM_OFFSET;
|
||||||
|
eaddrs = (char *)(sc->arpcom.ac_enaddr);
|
||||||
|
/* Fill the buffer with our physical address. */
|
||||||
|
for (i = 1; i < 16; i++) {
|
||||||
|
*setup_frm++ = eaddrs[0];
|
||||||
|
*setup_frm++ = eaddrs[1];
|
||||||
|
*setup_frm++ = eaddrs[0];
|
||||||
|
*setup_frm++ = eaddrs[1];
|
||||||
|
*setup_frm++ = eaddrs[2];
|
||||||
|
*setup_frm++ = eaddrs[3];
|
||||||
|
*setup_frm++ = eaddrs[2];
|
||||||
|
*setup_frm++ = eaddrs[3];
|
||||||
|
*setup_frm++ = eaddrs[4];
|
||||||
|
*setup_frm++ = eaddrs[5];
|
||||||
|
*setup_frm++ = eaddrs[4];
|
||||||
|
*setup_frm++ = eaddrs[5];
|
||||||
|
}
|
||||||
|
/* Add the broadcast address when doing perfect filtering */
|
||||||
|
memset((void*) setup_frm, 0xff, 12);
|
||||||
|
rmd->counts = 0x0a000000 | 192 ;
|
||||||
|
rmd->status = 0x80000000;
|
||||||
|
st_le32( (tbase+memCSR1), 1);
|
||||||
|
while (rmd->status != 0x7fffffff);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enable RX and TX
|
||||||
|
*/
|
||||||
|
st_le32( (unsigned int*)(tbase+memCSR6), CSR6_INIT | CSR6_TXRX);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set up PHY
|
||||||
|
*/
|
||||||
|
|
||||||
|
i = rombuf.c[27];
|
||||||
|
i+=2;
|
||||||
|
direction = rombuf.c[i];
|
||||||
|
i +=4;
|
||||||
|
st_le32( (tbase+memCSR12), direction | 0x100);
|
||||||
|
for (i2 = 0; i2 < rombuf.c[(i+2) + rombuf.c[i+1]]; i2++){
|
||||||
|
st_le32( (tbase + memCSR12), rombuf.c[(i+3) + rombuf.c[i+1] + i2]);
|
||||||
|
}
|
||||||
|
for (i2 = 0; i2 < rombuf.c[i+1]; i2++){
|
||||||
|
st_le32( (tbase + memCSR12), rombuf.c[(i+2) + i2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dec21140_rxDaemon (void *arg)
|
||||||
|
{
|
||||||
|
volatile unsigned int *tbase;
|
||||||
|
struct ether_header *eh;
|
||||||
|
struct dec21140_softc *dp = (struct dec21140_softc *)&dec21140_softc[0];
|
||||||
|
struct ifnet *ifp = &dp->arpcom.ac_if;
|
||||||
|
struct mbuf *m;
|
||||||
|
volatile struct MD *rmd;
|
||||||
|
unsigned int len;
|
||||||
|
char *temp;
|
||||||
|
rtems_event_set events;
|
||||||
|
int nbMD;
|
||||||
|
|
||||||
|
tbase = dec21140_softc[0].base ;
|
||||||
|
|
||||||
|
for (;;){
|
||||||
|
|
||||||
|
rtems_bsdnet_event_receive (INTERRUPT_EVENT,
|
||||||
|
RTEMS_WAIT|RTEMS_EVENT_ANY,
|
||||||
|
RTEMS_NO_TIMEOUT,
|
||||||
|
&events);
|
||||||
|
rmd = dec21140_softc[0].MDbase;
|
||||||
|
nbMD = 0;
|
||||||
|
|
||||||
|
while (nbMD < NRXBUFS){
|
||||||
|
if ( (rmd->status & 0x80000000) == 0){
|
||||||
|
len = (rmd->status >> 16) & 0x7ff;
|
||||||
|
MGETHDR (m, M_WAIT, MT_DATA);
|
||||||
|
MCLGET (m, M_WAIT);
|
||||||
|
m->m_pkthdr.rcvif = ifp;
|
||||||
|
temp = m->m_data;
|
||||||
|
m->m_len = m->m_pkthdr.len = len - sizeof(struct ether_header);
|
||||||
|
memcpy(temp, (void*) (rmd->buf1-PREP_PCI_DRAM_OFFSET), len);
|
||||||
|
rmd->status = 0x80000000;
|
||||||
|
eh = mtod (m, struct ether_header *);
|
||||||
|
m->m_data += sizeof(struct ether_header);
|
||||||
|
ether_input (ifp, eh, m);
|
||||||
|
}
|
||||||
|
rmd++;
|
||||||
|
nbMD++;
|
||||||
|
}
|
||||||
|
st_le32( (tbase+memCSR7), IT_SETUP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sendpacket (struct ifnet *ifp, struct mbuf *m)
|
||||||
|
{
|
||||||
|
struct dec21140_softc *dp = ifp->if_softc;
|
||||||
|
volatile struct MD *tmd;
|
||||||
|
volatile unsigned char *temp;
|
||||||
|
struct mbuf *n;
|
||||||
|
unsigned int len;
|
||||||
|
volatile unsigned int *tbase;
|
||||||
|
|
||||||
|
tbase = dp->base;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Waiting for Transmitter ready
|
||||||
|
*/
|
||||||
|
tmd = dec21140_softc[0].MDbase + NRXBUFS;
|
||||||
|
while ( (tmd->status & 0x80000000) != 0 );
|
||||||
|
len = 0;
|
||||||
|
n = m;
|
||||||
|
temp = tmd->buf1-PREP_PCI_DRAM_OFFSET;
|
||||||
|
|
||||||
|
for (;;){
|
||||||
|
len += m->m_len;
|
||||||
|
memcpy((void*) temp, (char *)m->m_data, m->m_len);
|
||||||
|
temp += m->m_len ;
|
||||||
|
if ((m = m->m_next) == NULL)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len < ET_MINLEN) len = ET_MINLEN;
|
||||||
|
tmd->counts = 0xe2000000 | len;
|
||||||
|
tmd->status = 0x80000000;
|
||||||
|
|
||||||
|
st_le32( (tbase+memCSR1), 0x1);
|
||||||
|
|
||||||
|
m_freem(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Driver transmit daemon
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
dec21140_txDaemon (void *arg)
|
||||||
|
{
|
||||||
|
struct dec21140_softc *sc = (struct dec21140_softc *)arg;
|
||||||
|
struct ifnet *ifp = &sc->arpcom.ac_if;
|
||||||
|
struct mbuf *m;
|
||||||
|
rtems_event_set events;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
/*
|
||||||
|
* Wait for packet
|
||||||
|
*/
|
||||||
|
|
||||||
|
rtems_bsdnet_event_receive (START_TRANSMIT_EVENT, RTEMS_EVENT_ANY | RTEMS_WAIT, RTEMS_NO_TIMEOUT, &events);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Send packets till queue is empty
|
||||||
|
*/
|
||||||
|
for (;;) {
|
||||||
|
/*
|
||||||
|
* Get the next mbuf chain to transmit.
|
||||||
|
*/
|
||||||
|
IF_DEQUEUE(&ifp->if_snd, m);
|
||||||
|
if (!m)
|
||||||
|
break;
|
||||||
|
sendpacket (ifp, m);
|
||||||
|
}
|
||||||
|
ifp->if_flags &= ~IFF_OACTIVE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
dec21140_start (struct ifnet *ifp)
|
||||||
|
{
|
||||||
|
struct dec21140_softc *sc = ifp->if_softc;
|
||||||
|
|
||||||
|
rtems_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT);
|
||||||
|
ifp->if_flags |= IFF_OACTIVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize and start the device
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
dec21140_init (void *arg)
|
||||||
|
{
|
||||||
|
struct dec21140_softc *sc = arg;
|
||||||
|
struct ifnet *ifp = &sc->arpcom.ac_if;
|
||||||
|
|
||||||
|
if (sc->txDaemonTid == 0) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set up DEC21140 hardware
|
||||||
|
*/
|
||||||
|
dec21140Enet_initialize_hardware (sc);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Start driver tasks
|
||||||
|
*/
|
||||||
|
sc->rxDaemonTid = rtems_bsdnet_newproc ("DCrx", 4096,
|
||||||
|
dec21140_rxDaemon, sc);
|
||||||
|
sc->txDaemonTid = rtems_bsdnet_newproc ("DCtx", 4096,
|
||||||
|
dec21140_txDaemon, sc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Tell the world that we're running.
|
||||||
|
*/
|
||||||
|
ifp->if_flags |= IFF_RUNNING;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Stop the device
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
dec21140_stop (struct dec21140_softc *sc)
|
||||||
|
{
|
||||||
|
volatile unsigned int *tbase;
|
||||||
|
struct ifnet *ifp = &sc->arpcom.ac_if;
|
||||||
|
|
||||||
|
ifp->if_flags &= ~IFF_RUNNING;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Stop the transmitter
|
||||||
|
*/
|
||||||
|
tbase=dec21140_softc[0].base ;
|
||||||
|
st_le32( (tbase+memCSR7), NO_IT);
|
||||||
|
st_le32( (tbase+memCSR6), CSR6_INIT);
|
||||||
|
free((void*)sc->bufferBase);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Show interface statistics
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
dec21140_stats (struct dec21140_softc *sc)
|
||||||
|
{
|
||||||
|
printf (" Rx Interrupts:%-8lu", sc->rxInterrupts);
|
||||||
|
printf (" Not First:%-8lu", sc->rxNotFirst);
|
||||||
|
printf (" Not Last:%-8lu\n", sc->rxNotLast);
|
||||||
|
printf (" Giant:%-8lu", sc->rxGiant);
|
||||||
|
printf (" Runt:%-8lu", sc->rxRunt);
|
||||||
|
printf (" Non-octet:%-8lu\n", sc->rxNonOctet);
|
||||||
|
printf (" Bad CRC:%-8lu", sc->rxBadCRC);
|
||||||
|
printf (" Overrun:%-8lu", sc->rxOverrun);
|
||||||
|
printf (" Collision:%-8lu\n", sc->rxCollision);
|
||||||
|
|
||||||
|
printf (" Tx Interrupts:%-8lu", sc->txInterrupts);
|
||||||
|
printf (" Deferred:%-8lu", sc->txDeferred);
|
||||||
|
printf (" Missed Hearbeat:%-8lu\n", sc->txHeartbeat);
|
||||||
|
printf (" No Carrier:%-8lu", sc->txLostCarrier);
|
||||||
|
printf ("Retransmit Limit:%-8lu", sc->txRetryLimit);
|
||||||
|
printf (" Late Collision:%-8lu\n", sc->txLateCollision);
|
||||||
|
printf (" Underrun:%-8lu", sc->txUnderrun);
|
||||||
|
printf (" Raw output wait:%-8lu\n", sc->txRawWait);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Driver ioctl handler
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
dec21140_ioctl (struct ifnet *ifp, int command, caddr_t data)
|
||||||
|
{
|
||||||
|
struct dec21140_softc *sc = ifp->if_softc;
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
switch (command) {
|
||||||
|
case SIOCGIFADDR:
|
||||||
|
case SIOCSIFADDR:
|
||||||
|
ether_ioctl (ifp, command, data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SIOCSIFFLAGS:
|
||||||
|
switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
|
||||||
|
case IFF_RUNNING:
|
||||||
|
dec21140_stop (sc);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IFF_UP:
|
||||||
|
dec21140_init (sc);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IFF_UP | IFF_RUNNING:
|
||||||
|
dec21140_stop (sc);
|
||||||
|
dec21140_init (sc);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SIO_RTEMS_SHOW_STATS:
|
||||||
|
dec21140_stats (sc);
|
||||||
|
break;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FIXME: All sorts of multicast commands need to be added here!
|
||||||
|
*/
|
||||||
|
default:
|
||||||
|
error = EINVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Attach an DEC21140 driver to the system
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
rtems_dec21140_driver_attach (struct rtems_bsdnet_ifconfig *config)
|
||||||
|
{
|
||||||
|
struct dec21140_softc *sc;
|
||||||
|
struct ifnet *ifp;
|
||||||
|
int mtu;
|
||||||
|
int i;
|
||||||
|
unsigned char ucSlotNumber, ucFnNumber;
|
||||||
|
unsigned int ulDeviceID, lvalue, tmp;
|
||||||
|
unsigned char cvalue;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* First, find a DEC board
|
||||||
|
*/
|
||||||
|
for(ucSlotNumber=0;ucSlotNumber<PCI_MAX_DEVICES;ucSlotNumber++) {
|
||||||
|
for(ucFnNumber=0;ucFnNumber<PCI_MAX_FUNCTIONS;ucFnNumber++) {
|
||||||
|
(void)pci_read_config_dword(0,
|
||||||
|
ucSlotNumber,
|
||||||
|
ucFnNumber,
|
||||||
|
PCI_VENDOR_ID,
|
||||||
|
&ulDeviceID);
|
||||||
|
if(ulDeviceID==PCI_INVALID_VENDORDEVICEID) {
|
||||||
|
/*
|
||||||
|
* This slot is empty
|
||||||
|
*/
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (ulDeviceID == ((PCI_DEVICE_ID_DEC_TULIP_FAST<<16) + PCI_VENDOR_ID_DEC))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ulDeviceID == ((PCI_DEVICE_ID_DEC_TULIP_FAST<<16) + PCI_VENDOR_ID_DEC)){
|
||||||
|
printk("DEC Adapter found !!\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ulDeviceID==PCI_INVALID_VENDORDEVICEID)
|
||||||
|
rtems_panic("DEC PCI board not found !!\n");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find a free driver
|
||||||
|
*/
|
||||||
|
for (i = 0 ; i < NDECDRIVER ; i++) {
|
||||||
|
sc = &dec21140_softc[i];
|
||||||
|
ifp = &sc->arpcom.ac_if;
|
||||||
|
if (ifp->if_softc == NULL)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (i >= NDECDRIVER) {
|
||||||
|
printk ("Too many DEC drivers.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Process options
|
||||||
|
*/
|
||||||
|
|
||||||
|
(void)pci_read_config_dword(0,
|
||||||
|
ucSlotNumber,
|
||||||
|
ucFnNumber,
|
||||||
|
PCI_BASE_ADDRESS_0,
|
||||||
|
&lvalue);
|
||||||
|
|
||||||
|
sc->port = lvalue & (unsigned int)(~IO_MASK);
|
||||||
|
|
||||||
|
(void)pci_read_config_dword(0,
|
||||||
|
ucSlotNumber,
|
||||||
|
ucFnNumber,
|
||||||
|
PCI_BASE_ADDRESS_1 ,
|
||||||
|
&lvalue);
|
||||||
|
|
||||||
|
|
||||||
|
tmp = (unsigned int)(lvalue & (unsigned int)(~MEM_MASK))
|
||||||
|
+ (unsigned int)PREP_ISA_MEM_BASE;
|
||||||
|
sc->base = (unsigned int *)(tmp);
|
||||||
|
|
||||||
|
(void)pci_read_config_byte(0,
|
||||||
|
ucSlotNumber,
|
||||||
|
ucFnNumber,
|
||||||
|
PCI_INTERRUPT_LINE,
|
||||||
|
&cvalue);
|
||||||
|
sc->irqInfo.name = (rtems_irq_symbolic_name)cvalue;
|
||||||
|
|
||||||
|
if (config->hardware_address) {
|
||||||
|
memcpy (sc->arpcom.ac_enaddr, config->hardware_address,
|
||||||
|
ETHER_ADDR_LEN);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
memset (sc->arpcom.ac_enaddr, 0x08,ETHER_ADDR_LEN);
|
||||||
|
}
|
||||||
|
if (config->mtu)
|
||||||
|
mtu = config->mtu;
|
||||||
|
else
|
||||||
|
mtu = ETHERMTU;
|
||||||
|
|
||||||
|
sc->acceptBroadcast = !config->ignore_broadcast;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set up network interface values
|
||||||
|
*/
|
||||||
|
ifp->if_softc = sc;
|
||||||
|
ifp->if_unit = i + 1;
|
||||||
|
ifp->if_name = "dc";
|
||||||
|
ifp->if_mtu = mtu;
|
||||||
|
ifp->if_init = dec21140_init;
|
||||||
|
ifp->if_ioctl = dec21140_ioctl;
|
||||||
|
ifp->if_start = dec21140_start;
|
||||||
|
ifp->if_output = ether_output;
|
||||||
|
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
|
||||||
|
if (ifp->if_snd.ifq_maxlen == 0)
|
||||||
|
ifp->if_snd.ifq_maxlen = ifqmaxlen;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Attach the interface
|
||||||
|
*/
|
||||||
|
if_attach (ifp);
|
||||||
|
ether_ifattach (ifp);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
};
|
||||||
|
|
||||||
48
c/src/lib/libbsp/powerpc/shared/include/Makefile.in
Normal file
48
c/src/lib/libbsp/powerpc/shared/include/Makefile.in
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
#
|
||||||
|
# $Id$
|
||||||
|
#
|
||||||
|
|
||||||
|
@SET_MAKE@
|
||||||
|
srcdir = @srcdir@
|
||||||
|
top_srcdir = @top_srcdir@
|
||||||
|
top_builddir = ../../..
|
||||||
|
subdir = powerpc/shared/include
|
||||||
|
|
||||||
|
RTEMS_ROOT = @RTEMS_ROOT@
|
||||||
|
PROJECT_ROOT = @PROJECT_ROOT@
|
||||||
|
|
||||||
|
VPATH = @srcdir@
|
||||||
|
|
||||||
|
H_FILES = $(srcdir)/nvram.h $(srcdir)/bsp.h
|
||||||
|
|
||||||
|
#
|
||||||
|
# Equate files are for including from assembly preprocessed by
|
||||||
|
# gm4 or gasp. No examples are provided except for those for
|
||||||
|
# other CPUs. The best way to generate them would be to
|
||||||
|
# provide a program which generates the constants used based
|
||||||
|
# on the C equivalents.
|
||||||
|
#
|
||||||
|
|
||||||
|
EQ_FILES =
|
||||||
|
|
||||||
|
SRCS = $(H_FILES) $(EQ_FILES)
|
||||||
|
|
||||||
|
include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
|
||||||
|
include $(RTEMS_ROOT)/make/leaf.cfg
|
||||||
|
|
||||||
|
INSTALL_CHANGE = @INSTALL_CHANGE@
|
||||||
|
mkinstalldirs = $(SHELL) $(top_srcdir)/@RTEMS_TOPdir@/mkinstalldirs
|
||||||
|
|
||||||
|
INSTALLDIRS = $(PROJECT_INCLUDE)
|
||||||
|
|
||||||
|
$(INSTALLDIRS):
|
||||||
|
@$(mkinstalldirs) $(INSTALLDIRS)
|
||||||
|
|
||||||
|
CLEAN_ADDITIONS +=
|
||||||
|
CLOBBER_ADDITIONS +=
|
||||||
|
|
||||||
|
all: $(SRCS)
|
||||||
|
|
||||||
|
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||||
|
cd $(top_builddir) \
|
||||||
|
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
|
||||||
57
c/src/lib/libbsp/powerpc/shared/include/bsp.h
Normal file
57
c/src/lib/libbsp/powerpc/shared/include/bsp.h
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* bsp.h -- contain BSP API definition.
|
||||||
|
*
|
||||||
|
* Copyright (C) 1999 Eric Valette. valette@crf.canon.fr
|
||||||
|
*
|
||||||
|
* The license and distribution terms for this file may be
|
||||||
|
* found in found in the file LICENSE in this distribution or at
|
||||||
|
* http://www.OARcorp.com/rtems/license.html.
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*/
|
||||||
|
#ifndef LIBBSP_POWERPC_MCP750_BSP_H
|
||||||
|
#define LIBBSP_POWERPC_MCP750_BSP_H
|
||||||
|
|
||||||
|
#include <rtems.h>
|
||||||
|
#include <console.h>
|
||||||
|
#include <libcpu/io.h>
|
||||||
|
#include <clockdrv.h>
|
||||||
|
#include <bsp/vectors.h>
|
||||||
|
|
||||||
|
#ifndef ASM
|
||||||
|
#define outport_byte(port,value) outb(value,port)
|
||||||
|
#define outport_word(port,value) outw(value,port)
|
||||||
|
#define outport_long(port,value) outl(value,port)
|
||||||
|
|
||||||
|
#define inport_byte(port,value) (value = inb(port))
|
||||||
|
#define inport_word(port,value) (value = inw(port))
|
||||||
|
#define inport_long(port,value) (value = inl(port))
|
||||||
|
/*
|
||||||
|
* Vital Board data Start using DATA RESIDUAL
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* Total memory using RESIDUAL DATA
|
||||||
|
*/
|
||||||
|
unsigned int BSP_mem_size;
|
||||||
|
/*
|
||||||
|
* PCI Bus Frequency
|
||||||
|
*/
|
||||||
|
unsigned int BSP_bus_frequency;
|
||||||
|
/*
|
||||||
|
* processor clock frequency
|
||||||
|
*/
|
||||||
|
unsigned int BSP_processor_frequency;
|
||||||
|
/*
|
||||||
|
* Time base divisior (how many tick for 1 second).
|
||||||
|
*/
|
||||||
|
unsigned int BSP_time_base_divisor;
|
||||||
|
|
||||||
|
extern rtems_configuration_table BSP_Configuration;
|
||||||
|
extern void BSP_panic(char *s);
|
||||||
|
extern void rtemsReboot(void);
|
||||||
|
extern int printk(const char *, ...) __attribute__((format(printf, 1, 2)));
|
||||||
|
extern int BSP_disconnect_clock_handler (void);
|
||||||
|
extern int BSP_connect_clock_handler (void);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
170
c/src/lib/libbsp/powerpc/shared/include/nvram.h
Normal file
170
c/src/lib/libbsp/powerpc/shared/include/nvram.h
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
/*
|
||||||
|
* PreP compliant NVRAM access
|
||||||
|
*
|
||||||
|
* This file can be found in motorla or IBP PPC site.
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _PPC_NVRAM_H
|
||||||
|
#define _PPC_NVRAM_H
|
||||||
|
|
||||||
|
#define NVRAM_AS0 0x74
|
||||||
|
#define NVRAM_AS1 0x75
|
||||||
|
#define NVRAM_DATA 0x77
|
||||||
|
|
||||||
|
|
||||||
|
/* RTC Offsets */
|
||||||
|
|
||||||
|
#define MOTO_RTC_SECONDS 0x1FF9
|
||||||
|
#define MOTO_RTC_MINUTES 0x1FFA
|
||||||
|
#define MOTO_RTC_HOURS 0x1FFB
|
||||||
|
#define MOTO_RTC_DAY_OF_WEEK 0x1FFC
|
||||||
|
#define MOTO_RTC_DAY_OF_MONTH 0x1FFD
|
||||||
|
#define MOTO_RTC_MONTH 0x1FFE
|
||||||
|
#define MOTO_RTC_YEAR 0x1FFF
|
||||||
|
#define MOTO_RTC_CONTROLA 0x1FF8
|
||||||
|
#define MOTO_RTC_CONTROLB 0x1FF9
|
||||||
|
|
||||||
|
#ifndef BCD_TO_BIN
|
||||||
|
#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef BIN_TO_BCD
|
||||||
|
#define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Structure map for NVRAM on PowerPC Reference Platform */
|
||||||
|
/* All fields are either character/byte strings which are valid either
|
||||||
|
endian or they are big-endian numbers.
|
||||||
|
|
||||||
|
There are a number of Date and Time fields which are in RTC format,
|
||||||
|
big-endian. These are stored in UT (GMT).
|
||||||
|
|
||||||
|
For enum's: if given in hex then they are bit significant, i.e. only
|
||||||
|
one bit is on for each enum.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define NVSIZE 4096 /* size of NVRAM */
|
||||||
|
#define OSAREASIZE 512 /* size of OSArea space */
|
||||||
|
#define CONFSIZE 1024 /* guess at size of Configuration space */
|
||||||
|
|
||||||
|
#ifndef ASM
|
||||||
|
|
||||||
|
typedef struct _SECURITY {
|
||||||
|
unsigned long BootErrCnt; /* Count of boot password errors */
|
||||||
|
unsigned long ConfigErrCnt; /* Count of config password errors */
|
||||||
|
unsigned long BootErrorDT[2]; /* Date&Time from RTC of last error in pw */
|
||||||
|
unsigned long ConfigErrorDT[2]; /* Date&Time from RTC of last error in pw */
|
||||||
|
unsigned long BootCorrectDT[2]; /* Date&Time from RTC of last correct pw */
|
||||||
|
unsigned long ConfigCorrectDT[2]; /* Date&Time from RTC of last correct pw */
|
||||||
|
unsigned long BootSetDT[2]; /* Date&Time from RTC of last set of pw */
|
||||||
|
unsigned long ConfigSetDT[2]; /* Date&Time from RTC of last set of pw */
|
||||||
|
unsigned char Serial[16]; /* Box serial number */
|
||||||
|
} SECURITY;
|
||||||
|
|
||||||
|
typedef enum _OS_ID {
|
||||||
|
Unknown = 0,
|
||||||
|
Firmware = 1,
|
||||||
|
AIX = 2,
|
||||||
|
NT = 3,
|
||||||
|
MKOS2 = 4,
|
||||||
|
MKAIX = 5,
|
||||||
|
Taligent = 6,
|
||||||
|
Solaris = 7,
|
||||||
|
MK = 12
|
||||||
|
} OS_ID;
|
||||||
|
|
||||||
|
typedef struct _ERROR_LOG {
|
||||||
|
unsigned char ErrorLogEntry[40]; /* To be architected */
|
||||||
|
} ERROR_LOG;
|
||||||
|
|
||||||
|
typedef enum _BOOT_STATUS {
|
||||||
|
BootStarted = 0x01,
|
||||||
|
BootFinished = 0x02,
|
||||||
|
RestartStarted = 0x04,
|
||||||
|
RestartFinished = 0x08,
|
||||||
|
PowerFailStarted = 0x10,
|
||||||
|
PowerFailFinished = 0x20,
|
||||||
|
ProcessorReady = 0x40,
|
||||||
|
ProcessorRunning = 0x80,
|
||||||
|
ProcessorStart = 0x0100
|
||||||
|
} BOOT_STATUS;
|
||||||
|
|
||||||
|
typedef struct _RESTART_BLOCK {
|
||||||
|
unsigned short Version;
|
||||||
|
unsigned short Revision;
|
||||||
|
unsigned long ResumeReserve1[2];
|
||||||
|
volatile unsigned long BootStatus;
|
||||||
|
unsigned long CheckSum; /* Checksum of RESTART_BLOCK */
|
||||||
|
void* RestartAddress;
|
||||||
|
void* SaveAreaAddr;
|
||||||
|
unsigned long SaveAreaLength;
|
||||||
|
} RESTART_BLOCK;
|
||||||
|
|
||||||
|
typedef enum _OSAREA_USAGE {
|
||||||
|
Empty = 0,
|
||||||
|
Used = 1
|
||||||
|
} OSAREA_USAGE;
|
||||||
|
|
||||||
|
typedef enum _PM_MODE {
|
||||||
|
Suspend = 0x80, /* Part of state is in memory */
|
||||||
|
Normal = 0x00 /* No power management in effect */
|
||||||
|
} PMMode;
|
||||||
|
|
||||||
|
typedef struct _HEADER {
|
||||||
|
unsigned short Size; /* NVRAM size in K(1024) */
|
||||||
|
unsigned char Version; /* Structure map different */
|
||||||
|
unsigned char Revision; /* Structure map the same -may
|
||||||
|
be new values in old fields
|
||||||
|
in other words old code still works */
|
||||||
|
unsigned short Crc1; /* check sum from beginning of nvram to OSArea */
|
||||||
|
unsigned short Crc2; /* check sum of config */
|
||||||
|
unsigned char LastOS; /* OS_ID */
|
||||||
|
unsigned char Endian; /* B if big endian, L if little endian */
|
||||||
|
unsigned char OSAreaUsage;/* OSAREA_USAGE */
|
||||||
|
unsigned char PMMode; /* Shutdown mode */
|
||||||
|
RESTART_BLOCK RestartBlock;
|
||||||
|
SECURITY Security;
|
||||||
|
ERROR_LOG ErrorLog[2];
|
||||||
|
|
||||||
|
/* Global Environment information */
|
||||||
|
void* GEAddress;
|
||||||
|
unsigned long GELength;
|
||||||
|
|
||||||
|
/* Date&Time from RTC of last change to Global Environment */
|
||||||
|
unsigned long GELastWriteDT[2];
|
||||||
|
|
||||||
|
/* Configuration information */
|
||||||
|
void* ConfigAddress;
|
||||||
|
unsigned long ConfigLength;
|
||||||
|
|
||||||
|
/* Date&Time from RTC of last change to Configuration */
|
||||||
|
unsigned long ConfigLastWriteDT[2];
|
||||||
|
unsigned long ConfigCount; /* Count of entries in Configuration */
|
||||||
|
|
||||||
|
/* OS dependent temp area */
|
||||||
|
void* OSAreaAddress;
|
||||||
|
unsigned long OSAreaLength;
|
||||||
|
|
||||||
|
/* Date&Time from RTC of last change to OSAreaArea */
|
||||||
|
unsigned long OSAreaLastWriteDT[2];
|
||||||
|
} HEADER;
|
||||||
|
|
||||||
|
/* Here is the whole map of the NVRAM */
|
||||||
|
typedef struct _NVRAM_MAP {
|
||||||
|
HEADER Header;
|
||||||
|
unsigned char GEArea[NVSIZE-CONFSIZE-OSAREASIZE-sizeof(HEADER)];
|
||||||
|
unsigned char OSArea[OSAREASIZE];
|
||||||
|
unsigned char ConfigArea[CONFSIZE];
|
||||||
|
} NVRAM_MAP;
|
||||||
|
|
||||||
|
/* Routines to manipulate the NVRAM */
|
||||||
|
void init_prep_nvram(void);
|
||||||
|
char *prep_nvram_get_var(const char *name);
|
||||||
|
char *prep_nvram_first_var(void);
|
||||||
|
char *prep_nvram_next_var(char *name);
|
||||||
|
|
||||||
|
#endif /* ASM */
|
||||||
|
|
||||||
|
#endif /* _PPC_NVRAM_H */
|
||||||
41
c/src/lib/libbsp/powerpc/shared/irq/Makefile.in
Normal file
41
c/src/lib/libbsp/powerpc/shared/irq/Makefile.in
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
#
|
||||||
|
# $Id$
|
||||||
|
#
|
||||||
|
|
||||||
|
@SET_MAKE@
|
||||||
|
srcdir = @srcdir@
|
||||||
|
top_srcdir = @top_srcdir@
|
||||||
|
top_builddir = ../../..
|
||||||
|
subdir = powerpc/shared/irq
|
||||||
|
|
||||||
|
RTEMS_ROOT = @RTEMS_ROOT@
|
||||||
|
PROJECT_ROOT = @PROJECT_ROOT@
|
||||||
|
|
||||||
|
VPATH = @srcdir@
|
||||||
|
|
||||||
|
H_FILES = $(srcdir)/irq.h
|
||||||
|
|
||||||
|
SRCS = $(C_FILES) $(CC_FILES) $(H_FILES) $(S_FILES)
|
||||||
|
|
||||||
|
include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
|
||||||
|
include $(RTEMS_ROOT)/make/leaf.cfg
|
||||||
|
|
||||||
|
INSTALL_CHANGE = @INSTALL_CHANGE@
|
||||||
|
mkinstalldirs = $(SHELL) $(top_srcdir)/@RTEMS_TOPdir@/mkinstalldirs
|
||||||
|
|
||||||
|
INSTALLDIRS = $(PROJECT_INCLUDE)/bsp
|
||||||
|
|
||||||
|
$(INSTALLDIRS):
|
||||||
|
@$(mkinstalldirs) $(INSTALLDIRS)
|
||||||
|
|
||||||
|
preinstall:
|
||||||
|
@$(mkinstalldirs) $(PROJECT_INCLUDE)/bsp
|
||||||
|
@$(INSTALL_CHANGE) -m 644 $(H_FILES) $(PROJECT_INCLUDE)/bsp
|
||||||
|
|
||||||
|
all: ${ARCH} $(SRCS) preinstall
|
||||||
|
|
||||||
|
install: all
|
||||||
|
|
||||||
|
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||||
|
cd $(top_builddir) \
|
||||||
|
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
|
||||||
152
c/src/lib/libbsp/powerpc/shared/irq/i8259.c
Normal file
152
c/src/lib/libbsp/powerpc/shared/irq/i8259.c
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
* This file contains the implementation of the function described in irq.h
|
||||||
|
* related to Intel 8259 Programmable Interrupt controller.
|
||||||
|
*
|
||||||
|
* Copyright (C) 1998, 1999 valette@crf.canon.fr
|
||||||
|
*
|
||||||
|
* The license and distribution terms for this file may be
|
||||||
|
* found in found in the file LICENSE in this distribution or at
|
||||||
|
* http://www.OARcorp.com/rtems/license.html.
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <bsp.h>
|
||||||
|
#include <bsp/irq.h>
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------+
|
||||||
|
| Cache for 1st and 2nd PIC IRQ line's status (enabled or disabled) register.
|
||||||
|
+--------------------------------------------------------------------------*/
|
||||||
|
/*
|
||||||
|
* lower byte is interrupt mask on the master PIC.
|
||||||
|
* while upper bits are interrupt on the slave PIC.
|
||||||
|
*/
|
||||||
|
volatile rtems_i8259_masks i8259s_cache = 0xfffb;
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------+
|
||||||
|
| Function: BSP_irq_disable_at_i8259s
|
||||||
|
| Description: Mask IRQ line in appropriate PIC chip.
|
||||||
|
| Global Variables: i8259s_cache
|
||||||
|
| Arguments: vector_offset - number of IRQ line to mask.
|
||||||
|
| Returns: Nothing.
|
||||||
|
+--------------------------------------------------------------------------*/
|
||||||
|
int BSP_irq_disable_at_i8259s (const rtems_irq_symbolic_name irqLine)
|
||||||
|
{
|
||||||
|
unsigned short mask;
|
||||||
|
unsigned int level;
|
||||||
|
|
||||||
|
if ( ((int)irqLine < BSP_ISA_IRQ_LOWEST_OFFSET) ||
|
||||||
|
((int)irqLine > BSP_ISA_IRQ_MAX_OFFSET)
|
||||||
|
)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
_CPU_ISR_Disable(level);
|
||||||
|
|
||||||
|
mask = 1 << irqLine;
|
||||||
|
i8259s_cache |= mask;
|
||||||
|
|
||||||
|
if (irqLine < 8)
|
||||||
|
{
|
||||||
|
outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) >> 8));
|
||||||
|
}
|
||||||
|
_CPU_ISR_Enable (level);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------+
|
||||||
|
| Function: BSP_irq_enable_at_i8259s
|
||||||
|
| Description: Unmask IRQ line in appropriate PIC chip.
|
||||||
|
| Global Variables: i8259s_cache
|
||||||
|
| Arguments: irqLine - number of IRQ line to mask.
|
||||||
|
| Returns: Nothing.
|
||||||
|
+--------------------------------------------------------------------------*/
|
||||||
|
int BSP_irq_enable_at_i8259s (const rtems_irq_symbolic_name irqLine)
|
||||||
|
{
|
||||||
|
unsigned short mask;
|
||||||
|
unsigned int level;
|
||||||
|
|
||||||
|
if ( ((int)irqLine < BSP_ISA_IRQ_LOWEST_OFFSET) ||
|
||||||
|
((int)irqLine > BSP_ISA_IRQ_MAX_OFFSET )
|
||||||
|
)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
_CPU_ISR_Disable(level);
|
||||||
|
|
||||||
|
mask = ~(1 << irqLine);
|
||||||
|
i8259s_cache &= mask;
|
||||||
|
|
||||||
|
if (irqLine < 8)
|
||||||
|
{
|
||||||
|
outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) >> 8));
|
||||||
|
}
|
||||||
|
_CPU_ISR_Enable (level);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
} /* mask_irq */
|
||||||
|
|
||||||
|
int BSP_irq_enabled_at_i8259s (const rtems_irq_symbolic_name irqLine)
|
||||||
|
{
|
||||||
|
unsigned short mask;
|
||||||
|
|
||||||
|
if ( ((int)irqLine < BSP_ISA_IRQ_LOWEST_OFFSET) ||
|
||||||
|
((int)irqLine > BSP_ISA_IRQ_MAX_OFFSET)
|
||||||
|
)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
mask = (1 << irqLine);
|
||||||
|
return (~(i8259s_cache & mask));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------+
|
||||||
|
| Function: BSP_irq_ack_at_i8259s
|
||||||
|
| Description: Signal generic End Of Interrupt (EOI) to appropriate PIC.
|
||||||
|
| Global Variables: None.
|
||||||
|
| Arguments: irqLine - number of IRQ line to acknowledge.
|
||||||
|
| Returns: Nothing.
|
||||||
|
+--------------------------------------------------------------------------*/
|
||||||
|
int BSP_irq_ack_at_i8259s (const rtems_irq_symbolic_name irqLine)
|
||||||
|
{
|
||||||
|
if (irqLine >= 8) {
|
||||||
|
outport_byte(PIC_MASTER_COMMAND_IO_PORT, SLAVE_PIC_EOSI);
|
||||||
|
outport_byte(PIC_SLAVE_COMMAND_IO_PORT, (PIC_EOSI | (irqLine - 8)));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
outport_byte(PIC_MASTER_COMMAND_IO_PORT, (PIC_EOSI | irqLine));
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
} /* ackIRQ */
|
||||||
|
|
||||||
|
void BSP_i8259s_init(void)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* init master 8259 interrupt controller
|
||||||
|
*/
|
||||||
|
outport_byte(PIC_MASTER_COMMAND_IO_PORT, 0x11); /* Start init sequence */
|
||||||
|
outport_byte(PIC_MASTER_IMR_IO_PORT, 0x00);/* Vector base = 0 */
|
||||||
|
outport_byte(PIC_MASTER_IMR_IO_PORT, 0x04);/* edge tiggered, Cascade (slave) on IRQ2 */
|
||||||
|
outport_byte(PIC_MASTER_IMR_IO_PORT, 0x01);/* Select 8086 mode */
|
||||||
|
outport_byte(PIC_MASTER_IMR_IO_PORT, 0xFB); /* Mask all except cascade */
|
||||||
|
/*
|
||||||
|
* init slave interrupt controller
|
||||||
|
*/
|
||||||
|
outport_byte(PIC_SLAVE_COMMAND_IO_PORT, 0x11); /* Start init sequence */
|
||||||
|
outport_byte(PIC_SLAVE_IMR_IO_PORT, 0x08);/* Vector base = 8 */
|
||||||
|
outport_byte(PIC_SLAVE_IMR_IO_PORT, 0x02);/* edge triggered, Cascade (slave) on IRQ2 */
|
||||||
|
outport_byte(PIC_SLAVE_IMR_IO_PORT, 0x01); /* Select 8086 mode */
|
||||||
|
outport_byte(PIC_SLAVE_IMR_IO_PORT, 0xFF); /* Mask all */
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
398
c/src/lib/libbsp/powerpc/shared/irq/irq.c
Normal file
398
c/src/lib/libbsp/powerpc/shared/irq/irq.c
Normal file
@@ -0,0 +1,398 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* This file contains the implementation of the function described in irq.h
|
||||||
|
*
|
||||||
|
* Copyright (C) 1998, 1999 valette@crf.canon.fr
|
||||||
|
*
|
||||||
|
* The license and distribution terms for this file may be
|
||||||
|
* found in found in the file LICENSE in this distribution or at
|
||||||
|
* http://www.OARcorp.com/rtems/license.html.
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <bsp.h>
|
||||||
|
#include <bsp/irq.h>
|
||||||
|
#include <bsp/openpic.h>
|
||||||
|
#include <rtems/score/thread.h>
|
||||||
|
#include <rtems/score/apiext.h>
|
||||||
|
#include <libcpu/raw_exception.h>
|
||||||
|
#include <bsp/vectors.h>
|
||||||
|
#include <libcpu/cpu.h>
|
||||||
|
|
||||||
|
#define RAVEN_INTR_ACK_REG 0xfeff0030
|
||||||
|
|
||||||
|
/*
|
||||||
|
* pointer to the mask representing the additionnal irq vectors
|
||||||
|
* that must be disabled when a particular entry is activated.
|
||||||
|
* They will be dynamically computed from teh prioruty table given
|
||||||
|
* in BSP_rtems_irq_mngt_set();
|
||||||
|
* CAUTION : this table is accessed directly by interrupt routine
|
||||||
|
* prologue.
|
||||||
|
*/
|
||||||
|
rtems_i8259_masks irq_mask_or_tbl[BSP_IRQ_NUMBER];
|
||||||
|
/*
|
||||||
|
* default handler connected on each irq after bsp initialization
|
||||||
|
*/
|
||||||
|
static rtems_irq_connect_data default_rtems_entry;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* location used to store initial tables used for interrupt
|
||||||
|
* management.
|
||||||
|
*/
|
||||||
|
static rtems_irq_global_settings* internal_config;
|
||||||
|
static rtems_irq_connect_data* rtems_hdl_tbl;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if IRQ is an ISA IRQ
|
||||||
|
*/
|
||||||
|
static inline int is_isa_irq(const rtems_irq_symbolic_name irqLine)
|
||||||
|
{
|
||||||
|
return (((int) irqLine <= BSP_ISA_IRQ_MAX_OFFSET) &
|
||||||
|
((int) irqLine >= BSP_ISA_IRQ_LOWEST_OFFSET)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if IRQ is an OPENPIC IRQ
|
||||||
|
*/
|
||||||
|
static inline int is_pci_irq(const rtems_irq_symbolic_name irqLine)
|
||||||
|
{
|
||||||
|
return (((int) irqLine <= BSP_PCI_IRQ_MAX_OFFSET) &
|
||||||
|
((int) irqLine >= BSP_PCI_IRQ_LOWEST_OFFSET)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if IRQ is a Porcessor IRQ
|
||||||
|
*/
|
||||||
|
static inline int is_processor_irq(const rtems_irq_symbolic_name irqLine)
|
||||||
|
{
|
||||||
|
return (((int) irqLine <= BSP_PROCESSOR_IRQ_MAX_OFFSET) &
|
||||||
|
((int) irqLine >= BSP_PROCESSOR_IRQ_LOWEST_OFFSET)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ------------------------ RTEMS Irq helper functions ----------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Caution : this function assumes the variable "internal_config"
|
||||||
|
* is already set and that the tables it contains are still valid
|
||||||
|
* and accessible.
|
||||||
|
*/
|
||||||
|
static void compute_i8259_masks_from_prio ()
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
unsigned int j;
|
||||||
|
/*
|
||||||
|
* Always mask at least current interrupt to prevent re-entrance
|
||||||
|
*/
|
||||||
|
for (i=BSP_ISA_IRQ_LOWEST_OFFSET; i < BSP_ISA_IRQ_NUMBER; i++) {
|
||||||
|
* ((unsigned short*) &irq_mask_or_tbl[i]) = (1 << i);
|
||||||
|
for (j = BSP_ISA_IRQ_LOWEST_OFFSET; j < BSP_ISA_IRQ_NUMBER; j++) {
|
||||||
|
/*
|
||||||
|
* Mask interrupts at i8259 level that have a lower priority
|
||||||
|
*/
|
||||||
|
if (internal_config->irqPrioTbl [i] > internal_config->irqPrioTbl [j]) {
|
||||||
|
* ((unsigned short*) &irq_mask_or_tbl[i]) |= (1 << j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function check that the value given for the irq line
|
||||||
|
* is valid.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int isValidInterrupt(int irq)
|
||||||
|
{
|
||||||
|
if ( (irq < BSP_LOWEST_OFFSET) || (irq > BSP_MAX_OFFSET))
|
||||||
|
return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ------------------------ RTEMS Single Irq Handler Mngt Routines ----------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
int BSP_install_rtems_irq_handler (const rtems_irq_connect_data* irq)
|
||||||
|
{
|
||||||
|
unsigned int level;
|
||||||
|
|
||||||
|
if (!isValidInterrupt(irq->name)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Check if default handler is actually connected. If not issue an error.
|
||||||
|
* You must first get the current handler via i386_get_current_idt_entry
|
||||||
|
* and then disconnect it using i386_delete_idt_entry.
|
||||||
|
* RATIONALE : to always have the same transition by forcing the user
|
||||||
|
* to get the previous handler before accepting to disconnect.
|
||||||
|
*/
|
||||||
|
if (rtems_hdl_tbl[irq->name].hdl != default_rtems_entry.hdl) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
_CPU_ISR_Disable(level);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* store the data provided by user
|
||||||
|
*/
|
||||||
|
rtems_hdl_tbl[irq->name] = *irq;
|
||||||
|
|
||||||
|
if (is_isa_irq(irq->name)) {
|
||||||
|
/*
|
||||||
|
* Enable interrupt at PIC level
|
||||||
|
*/
|
||||||
|
BSP_irq_enable_at_i8259s (irq->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_pci_irq(irq->name)) {
|
||||||
|
/*
|
||||||
|
* Enable interrupt at OPENPIC level
|
||||||
|
*/
|
||||||
|
openpic_enable_irq ((int) irq->name - BSP_PCI_IRQ_LOWEST_OFFSET);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_processor_irq(irq->name)) {
|
||||||
|
/*
|
||||||
|
* Enable exception at processor level
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Enable interrupt on device
|
||||||
|
*/
|
||||||
|
irq->on(irq);
|
||||||
|
|
||||||
|
_CPU_ISR_Enable(level);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int BSP_get_current_rtems_irq_handler (rtems_irq_connect_data* irq)
|
||||||
|
{
|
||||||
|
if (!isValidInterrupt(irq->name)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
*irq = rtems_hdl_tbl[irq->name];
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int BSP_remove_rtems_irq_handler (const rtems_irq_connect_data* irq)
|
||||||
|
{
|
||||||
|
unsigned int level;
|
||||||
|
|
||||||
|
if (!isValidInterrupt(irq->name)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Check if default handler is actually connected. If not issue an error.
|
||||||
|
* You must first get the current handler via i386_get_current_idt_entry
|
||||||
|
* and then disconnect it using i386_delete_idt_entry.
|
||||||
|
* RATIONALE : to always have the same transition by forcing the user
|
||||||
|
* to get the previous handler before accepting to disconnect.
|
||||||
|
*/
|
||||||
|
if (rtems_hdl_tbl[irq->name].hdl != irq->hdl) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
_CPU_ISR_Disable(level);
|
||||||
|
|
||||||
|
if (is_isa_irq(irq->name)) {
|
||||||
|
/*
|
||||||
|
* disable interrupt at PIC level
|
||||||
|
*/
|
||||||
|
BSP_irq_disable_at_i8259s (irq->name);
|
||||||
|
}
|
||||||
|
if (is_pci_irq(irq->name)) {
|
||||||
|
/*
|
||||||
|
* disable interrupt at OPENPIC level
|
||||||
|
*/
|
||||||
|
openpic_disable_irq ((int) irq->name - BSP_PCI_IRQ_LOWEST_OFFSET);
|
||||||
|
}
|
||||||
|
if (is_processor_irq(irq->name)) {
|
||||||
|
/*
|
||||||
|
* disable exception at processor level
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Disable interrupt on device
|
||||||
|
*/
|
||||||
|
irq->off(irq);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* restore the default irq value
|
||||||
|
*/
|
||||||
|
rtems_hdl_tbl[irq->name] = default_rtems_entry;
|
||||||
|
|
||||||
|
_CPU_ISR_Enable(level);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ------------------------ RTEMS Global Irq Handler Mngt Routines ----------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
int BSP_rtems_irq_mngt_set(rtems_irq_global_settings* config)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
unsigned int level;
|
||||||
|
/*
|
||||||
|
* Store various code accelerators
|
||||||
|
*/
|
||||||
|
internal_config = config;
|
||||||
|
default_rtems_entry = config->defaultEntry;
|
||||||
|
rtems_hdl_tbl = config->irqHdlTbl;
|
||||||
|
|
||||||
|
_CPU_ISR_Disable(level);
|
||||||
|
/*
|
||||||
|
* set up internal tables used by rtems interrupt prologue
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* start with ISA IRQ
|
||||||
|
*/
|
||||||
|
compute_i8259_masks_from_prio ();
|
||||||
|
|
||||||
|
for (i=BSP_ISA_IRQ_LOWEST_OFFSET; i < BSP_ISA_IRQ_NUMBER; i++) {
|
||||||
|
if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) {
|
||||||
|
BSP_irq_enable_at_i8259s (i);
|
||||||
|
rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]);
|
||||||
|
BSP_irq_disable_at_i8259s (i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* must enable slave pic anyway
|
||||||
|
*/
|
||||||
|
BSP_irq_enable_at_i8259s (2);
|
||||||
|
/*
|
||||||
|
* continue with PCI IRQ
|
||||||
|
*/
|
||||||
|
for (i=BSP_PCI_IRQ_LOWEST_OFFSET; i < BSP_PCI_IRQ_LOWEST_OFFSET + BSP_PCI_IRQ_NUMBER ; i++) {
|
||||||
|
openpic_set_priority(0, internal_config->irqPrioTbl [i]);
|
||||||
|
if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) {
|
||||||
|
openpic_enable_irq ((int) i - BSP_PCI_IRQ_LOWEST_OFFSET);
|
||||||
|
rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]);
|
||||||
|
openpic_disable_irq ((int) i - BSP_PCI_IRQ_LOWEST_OFFSET);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Must enable PCI/ISA bridge IRQ
|
||||||
|
*/
|
||||||
|
openpic_enable_irq (0);
|
||||||
|
/*
|
||||||
|
* finish with Processor exceptions handled like IRQ
|
||||||
|
*/
|
||||||
|
for (i=BSP_PROCESSOR_IRQ_LOWEST_OFFSET; i < BSP_PROCESSOR_IRQ_LOWEST_OFFSET + BSP_PROCESSOR_IRQ_NUMBER; i++) {
|
||||||
|
if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) {
|
||||||
|
rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_CPU_ISR_Enable(level);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int BSP_rtems_irq_mngt_get(rtems_irq_global_settings** config)
|
||||||
|
{
|
||||||
|
*config = internal_config;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned spuriousIntr = 0;
|
||||||
|
/*
|
||||||
|
* High level IRQ handler called from shared_raw_irq_code_entry
|
||||||
|
*/
|
||||||
|
void C_dispatch_irq_handler (CPU_Interrupt_frame *frame, unsigned int excNum)
|
||||||
|
{
|
||||||
|
register unsigned int irq;
|
||||||
|
register unsigned isaIntr; /* boolean */
|
||||||
|
register unsigned oldMask; /* old isa pic masks */
|
||||||
|
register unsigned newMask; /* new isa pic masks */
|
||||||
|
register unsigned msr;
|
||||||
|
register unsigned new_msr;
|
||||||
|
|
||||||
|
|
||||||
|
if (excNum == ASM_DEC_VECTOR) {
|
||||||
|
_CPU_MSR_GET(msr);
|
||||||
|
new_msr = msr | MSR_EE;
|
||||||
|
_CPU_MSR_SET(new_msr);
|
||||||
|
|
||||||
|
rtems_hdl_tbl[BSP_DECREMENTER].hdl();
|
||||||
|
|
||||||
|
_CPU_MSR_SET(msr);
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
irq = openpic_irq(0);
|
||||||
|
if (irq == OPENPIC_VEC_SPURIOUS) {
|
||||||
|
++spuriousIntr;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
isaIntr = (irq == BSP_PCI_ISA_BRIDGE_IRQ);
|
||||||
|
if (isaIntr) {
|
||||||
|
/*
|
||||||
|
* Acknowledge and read 8259 vector
|
||||||
|
*/
|
||||||
|
irq = (unsigned int) (*(unsigned char *) RAVEN_INTR_ACK_REG);
|
||||||
|
/*
|
||||||
|
* store current PIC mask
|
||||||
|
*/
|
||||||
|
oldMask = i8259s_cache;
|
||||||
|
newMask = oldMask | irq_mask_or_tbl [irq];
|
||||||
|
i8259s_cache = newMask;
|
||||||
|
outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff);
|
||||||
|
outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) >> 8));
|
||||||
|
BSP_irq_ack_at_i8259s (irq);
|
||||||
|
openpic_eoi(0);
|
||||||
|
}
|
||||||
|
_CPU_MSR_GET(msr);
|
||||||
|
new_msr = msr | MSR_EE;
|
||||||
|
_CPU_MSR_SET(new_msr);
|
||||||
|
|
||||||
|
rtems_hdl_tbl[irq].hdl();
|
||||||
|
|
||||||
|
_CPU_MSR_SET(msr);
|
||||||
|
|
||||||
|
if (isaIntr) {
|
||||||
|
i8259s_cache = oldMask;
|
||||||
|
outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff);
|
||||||
|
outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) >> 8));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
openpic_eoi(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void _ThreadProcessSignalsFromIrq (BSP_Exception_frame* ctx)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Process pending signals that have not already been
|
||||||
|
* processed by _Thread_Displatch. This happens quite
|
||||||
|
* unfrequently : the ISR must have posted an action
|
||||||
|
* to the current running thread.
|
||||||
|
*/
|
||||||
|
if ( _Thread_Do_post_task_switch_extension ||
|
||||||
|
_Thread_Executing->do_post_task_switch_extension ) {
|
||||||
|
_Thread_Executing->do_post_task_switch_extension = FALSE;
|
||||||
|
_API_extensions_Run_postswitch();
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* I plan to process other thread related events here.
|
||||||
|
* This will include DEBUG session requested from keyboard...
|
||||||
|
*/
|
||||||
|
}
|
||||||
319
c/src/lib/libbsp/powerpc/shared/irq/irq.h
Normal file
319
c/src/lib/libbsp/powerpc/shared/irq/irq.h
Normal file
@@ -0,0 +1,319 @@
|
|||||||
|
/* irq.h
|
||||||
|
*
|
||||||
|
* This include file describe the data structure and the functions implemented
|
||||||
|
* by rtems to write interrupt handlers.
|
||||||
|
*
|
||||||
|
* CopyRight (C) 1999 valette@crf.canon.fr
|
||||||
|
*
|
||||||
|
* This code is heavilly inspired by the public specification of STREAM V2
|
||||||
|
* that can be found at :
|
||||||
|
*
|
||||||
|
* <http://www.chorus.com/Documentation/index.html> by following
|
||||||
|
* the STREAM API Specification Document link.
|
||||||
|
*
|
||||||
|
* The license and distribution terms for this file may be
|
||||||
|
* found in found in the file LICENSE in this distribution or at
|
||||||
|
* http://www.OARcorp.com/rtems/license.html.
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LIBBSP_POWERPC_MCP750_IRQ_IRQ_H
|
||||||
|
#define LIBBSP_POWERPC_MCP750_IRQ_IRQ_H
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 8259 edge/level control definitions at VIA
|
||||||
|
*/
|
||||||
|
#define ISA8259_M_ELCR 0x4d0
|
||||||
|
#define ISA8259_S_ELCR 0x4d1
|
||||||
|
|
||||||
|
#define ELCRS_INT15_LVL 0x80
|
||||||
|
#define ELCRS_INT14_LVL 0x40
|
||||||
|
#define ELCRS_INT13_LVL 0x20
|
||||||
|
#define ELCRS_INT12_LVL 0x10
|
||||||
|
#define ELCRS_INT11_LVL 0x08
|
||||||
|
#define ELCRS_INT10_LVL 0x04
|
||||||
|
#define ELCRS_INT9_LVL 0x02
|
||||||
|
#define ELCRS_INT8_LVL 0x01
|
||||||
|
#define ELCRM_INT7_LVL 0x80
|
||||||
|
#define ELCRM_INT6_LVL 0x40
|
||||||
|
#define ELCRM_INT5_LVL 0x20
|
||||||
|
#define ELCRM_INT4_LVL 0x10
|
||||||
|
#define ELCRM_INT3_LVL 0x8
|
||||||
|
#define ELCRM_INT2_LVL 0x4
|
||||||
|
#define ELCRM_INT1_LVL 0x2
|
||||||
|
#define ELCRM_INT0_LVL 0x1
|
||||||
|
|
||||||
|
#define BSP_ASM_IRQ_VECTOR_BASE 0x0
|
||||||
|
/* PIC's command and mask registers */
|
||||||
|
#define PIC_MASTER_COMMAND_IO_PORT 0x20 /* Master PIC command register */
|
||||||
|
#define PIC_SLAVE_COMMAND_IO_PORT 0xa0 /* Slave PIC command register */
|
||||||
|
#define PIC_MASTER_IMR_IO_PORT 0x21 /* Master PIC Interrupt Mask Register */
|
||||||
|
#define PIC_SLAVE_IMR_IO_PORT 0xa1 /* Slave PIC Interrupt Mask Register */
|
||||||
|
|
||||||
|
/* Command for specific EOI (End Of Interrupt): Interrupt acknowledge */
|
||||||
|
#define PIC_EOSI 0x60 /* End of Specific Interrupt (EOSI) */
|
||||||
|
#define SLAVE_PIC_EOSI 0x62 /* End of Specific Interrupt (EOSI) for cascade */
|
||||||
|
#define PIC_EOI 0x20 /* Generic End of Interrupt (EOI) */
|
||||||
|
|
||||||
|
#ifndef ASM
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Symblolic IRQ names and related definitions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
/* Base vector for our ISA IRQ handlers. */
|
||||||
|
BSP_ISA_IRQ_VECTOR_BASE = BSP_ASM_IRQ_VECTOR_BASE,
|
||||||
|
/*
|
||||||
|
* ISA IRQ handler related definitions
|
||||||
|
*/
|
||||||
|
BSP_ISA_IRQ_NUMBER = 16,
|
||||||
|
BSP_ISA_IRQ_LOWEST_OFFSET = 0,
|
||||||
|
BSP_ISA_IRQ_MAX_OFFSET = BSP_ISA_IRQ_LOWEST_OFFSET + BSP_ISA_IRQ_NUMBER - 1,
|
||||||
|
/*
|
||||||
|
* PCI IRQ handlers related definitions
|
||||||
|
* CAUTION : BSP_PCI_IRQ_LOWEST_OFFSET should be equal to OPENPIC_VEC_SOURCE
|
||||||
|
*/
|
||||||
|
BSP_PCI_IRQ_NUMBER = 16,
|
||||||
|
BSP_PCI_IRQ_LOWEST_OFFSET = BSP_ISA_IRQ_NUMBER,
|
||||||
|
BSP_PCI_IRQ_MAX_OFFSET = BSP_PCI_IRQ_LOWEST_OFFSET + BSP_PCI_IRQ_NUMBER - 1,
|
||||||
|
/*
|
||||||
|
* PowerPc exceptions handled as interrupt where a rtems managed interrupt
|
||||||
|
* handler might be connected
|
||||||
|
*/
|
||||||
|
BSP_PROCESSOR_IRQ_NUMBER = 1,
|
||||||
|
BSP_PROCESSOR_IRQ_LOWEST_OFFSET = BSP_PCI_IRQ_MAX_OFFSET + 1,
|
||||||
|
BSP_PROCESSOR_IRQ_MAX_OFFSET = BSP_PROCESSOR_IRQ_LOWEST_OFFSET + BSP_PROCESSOR_IRQ_NUMBER - 1,
|
||||||
|
/*
|
||||||
|
* Summary
|
||||||
|
*/
|
||||||
|
BSP_IRQ_NUMBER = BSP_PROCESSOR_IRQ_MAX_OFFSET + 1,
|
||||||
|
BSP_LOWEST_OFFSET = BSP_ISA_IRQ_LOWEST_OFFSET,
|
||||||
|
BSP_MAX_OFFSET = BSP_PROCESSOR_IRQ_MAX_OFFSET,
|
||||||
|
/*
|
||||||
|
* Some ISA IRQ symbolic name definition
|
||||||
|
*/
|
||||||
|
BSP_ISA_PERIODIC_TIMER = 0,
|
||||||
|
|
||||||
|
BSP_ISA_KEYBOARD = 1,
|
||||||
|
|
||||||
|
BSP_ISA_UART_COM2_IRQ = 3,
|
||||||
|
|
||||||
|
BSP_ISA_UART_COM1_IRQ = 4,
|
||||||
|
|
||||||
|
BSP_ISA_RT_TIMER1 = 8,
|
||||||
|
|
||||||
|
BSP_ISA_RT_TIMER3 = 10,
|
||||||
|
/*
|
||||||
|
* Some PCI IRQ symbolic name definition
|
||||||
|
*/
|
||||||
|
BSP_PCI_IRQ0 = BSP_PCI_IRQ_LOWEST_OFFSET,
|
||||||
|
BSP_PCI_ISA_BRIDGE_IRQ = BSP_PCI_IRQ0,
|
||||||
|
/*
|
||||||
|
* Some Processor execption handled as rtems IRQ symbolic name definition
|
||||||
|
*/
|
||||||
|
BSP_DECREMENTER = BSP_PROCESSOR_IRQ_LOWEST_OFFSET
|
||||||
|
|
||||||
|
}rtems_irq_symbolic_name;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Type definition for RTEMS managed interrupts
|
||||||
|
*/
|
||||||
|
typedef unsigned char rtems_irq_prio;
|
||||||
|
typedef unsigned short rtems_i8259_masks;
|
||||||
|
|
||||||
|
extern volatile rtems_i8259_masks i8259s_cache;
|
||||||
|
|
||||||
|
struct __rtems_irq_connect_data__; /* forward declaratiuon */
|
||||||
|
|
||||||
|
typedef void (*rtems_irq_hdl) (void);
|
||||||
|
typedef void (*rtems_irq_enable) (const struct __rtems_irq_connect_data__*);
|
||||||
|
typedef void (*rtems_irq_disable) (const struct __rtems_irq_connect_data__*);
|
||||||
|
typedef int (*rtems_irq_is_enabled) (const struct __rtems_irq_connect_data__*);
|
||||||
|
|
||||||
|
typedef struct __rtems_irq_connect_data__ {
|
||||||
|
/*
|
||||||
|
* IRQ line
|
||||||
|
*/
|
||||||
|
rtems_irq_symbolic_name name;
|
||||||
|
/*
|
||||||
|
* handler. See comment on handler properties below in function prototype.
|
||||||
|
*/
|
||||||
|
rtems_irq_hdl hdl;
|
||||||
|
/*
|
||||||
|
* function for enabling interrupts at device level (ONLY!).
|
||||||
|
* The BSP code will automatically enable it at i8259s level and openpic level.
|
||||||
|
* RATIONALE : anyway such code has to exist in current driver code.
|
||||||
|
* It is usually called immediately AFTER connecting the interrupt handler.
|
||||||
|
* RTEMS may well need such a function when restoring normal interrupt
|
||||||
|
* processing after a debug session.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
rtems_irq_enable on;
|
||||||
|
/*
|
||||||
|
* function for disabling interrupts at device level (ONLY!).
|
||||||
|
* The code will disable it at i8259s level. RATIONALE : anyway
|
||||||
|
* such code has to exist for clean shutdown. It is usually called
|
||||||
|
* BEFORE disconnecting the interrupt. RTEMS may well need such
|
||||||
|
* a function when disabling normal interrupt processing for
|
||||||
|
* a debug session. May well be a NOP function.
|
||||||
|
*/
|
||||||
|
rtems_irq_disable off;
|
||||||
|
/*
|
||||||
|
* function enabling to know what interrupt may currently occur
|
||||||
|
* if someone manipulates the i8259s interrupt mask without care...
|
||||||
|
*/
|
||||||
|
rtems_irq_is_enabled isOn;
|
||||||
|
}rtems_irq_connect_data;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
/*
|
||||||
|
* size of all the table fields (*Tbl) described below.
|
||||||
|
*/
|
||||||
|
unsigned int irqNb;
|
||||||
|
/*
|
||||||
|
* Default handler used when disconnecting interrupts.
|
||||||
|
*/
|
||||||
|
rtems_irq_connect_data defaultEntry;
|
||||||
|
/*
|
||||||
|
* Table containing initials/current value.
|
||||||
|
*/
|
||||||
|
rtems_irq_connect_data* irqHdlTbl;
|
||||||
|
/*
|
||||||
|
* actual value of BSP_ISA_IRQ_VECTOR_BASE...
|
||||||
|
*/
|
||||||
|
rtems_irq_symbolic_name irqBase;
|
||||||
|
/*
|
||||||
|
* software priorities associated with interrupts.
|
||||||
|
* if irqPrio [i] > intrPrio [j] it means that
|
||||||
|
* interrupt handler hdl connected for interrupt name i
|
||||||
|
* will not be interrupted by the handler connected for interrupt j
|
||||||
|
* The interrupt source will be physically masked at i8259 level.
|
||||||
|
*/
|
||||||
|
rtems_irq_prio* irqPrioTbl;
|
||||||
|
}rtems_irq_global_settings;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------+
|
||||||
|
| Function Prototypes.
|
||||||
|
+--------------------------------------------------------------------------*/
|
||||||
|
/*
|
||||||
|
* ------------------------ Intel 8259 (or emulation) Mngt Routines -------
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* function to disable a particular irq at 8259 level. After calling
|
||||||
|
* this function, even if the device asserts the interrupt line it will
|
||||||
|
* not be propagated further to the processor
|
||||||
|
*/
|
||||||
|
int BSP_irq_disable_at_i8259s (const rtems_irq_symbolic_name irqLine);
|
||||||
|
/*
|
||||||
|
* function to enable a particular irq at 8259 level. After calling
|
||||||
|
* this function, if the device asserts the interrupt line it will
|
||||||
|
* be propagated further to the processor
|
||||||
|
*/
|
||||||
|
int BSP_irq_enable_at_i8259s (const rtems_irq_symbolic_name irqLine);
|
||||||
|
/*
|
||||||
|
* function to acknoledge a particular irq at 8259 level. After calling
|
||||||
|
* this function, if a device asserts an enabled interrupt line it will
|
||||||
|
* be propagated further to the processor. Mainly usefull for people
|
||||||
|
* writting raw handlers as this is automagically done for rtems managed
|
||||||
|
* handlers.
|
||||||
|
*/
|
||||||
|
int BSP_irq_ack_at_i8259s (const rtems_irq_symbolic_name irqLine);
|
||||||
|
/*
|
||||||
|
* function to check if a particular irq is enabled at 8259 level. After calling
|
||||||
|
*/
|
||||||
|
int BSP_irq_enabled_at_i8259s (const rtems_irq_symbolic_name irqLine);
|
||||||
|
/*
|
||||||
|
* ------------------------ RTEMS Single Irq Handler Mngt Routines ----------------
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* function to connect a particular irq handler. This hanlder will NOT be called
|
||||||
|
* directly as the result of the corresponding interrupt. Instead, a RTEMS
|
||||||
|
* irq prologue will be called that will :
|
||||||
|
*
|
||||||
|
* 1) save the C scratch registers,
|
||||||
|
* 2) switch to a interrupt stack if the interrupt is not nested,
|
||||||
|
* 3) store the current i8259s' interrupt masks
|
||||||
|
* 4) modify them to disable the current interrupt at 8259 level (and may
|
||||||
|
* be others depending on software priorities)
|
||||||
|
* 5) aknowledge the i8259s',
|
||||||
|
* 6) demask the processor,
|
||||||
|
* 7) call the application handler
|
||||||
|
*
|
||||||
|
* As a result the hdl function provided
|
||||||
|
*
|
||||||
|
* a) can perfectly be written is C,
|
||||||
|
* b) may also well directly call the part of the RTEMS API that can be used
|
||||||
|
* from interrupt level,
|
||||||
|
* c) It only responsible for handling the jobs that need to be done at
|
||||||
|
* the device level including (aknowledging/re-enabling the interrupt at device,
|
||||||
|
* level, getting the data,...)
|
||||||
|
*
|
||||||
|
* When returning from the function, the following will be performed by
|
||||||
|
* the RTEMS irq epilogue :
|
||||||
|
*
|
||||||
|
* 1) masks the interrupts again,
|
||||||
|
* 2) restore the original i8259s' interrupt masks
|
||||||
|
* 3) switch back on the orinal stack if needed,
|
||||||
|
* 4) perform rescheduling when necessary,
|
||||||
|
* 5) restore the C scratch registers...
|
||||||
|
* 6) restore initial execution flow
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int BSP_install_rtems_irq_handler (const rtems_irq_connect_data*);
|
||||||
|
/*
|
||||||
|
* function to get the current RTEMS irq handler for ptr->name. It enables to
|
||||||
|
* define hanlder chain...
|
||||||
|
*/
|
||||||
|
int BSP_get_current_rtems_irq_handler (rtems_irq_connect_data* ptr);
|
||||||
|
/*
|
||||||
|
* function to get disconnect the RTEMS irq handler for ptr->name.
|
||||||
|
* This function checks that the value given is the current one for safety reason.
|
||||||
|
* The user can use the previous function to get it.
|
||||||
|
*/
|
||||||
|
int BSP_remove_rtems_irq_handler (const rtems_irq_connect_data*);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ------------------------ RTEMS Global Irq Handler Mngt Routines ----------------
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* (Re) Initialize the RTEMS interrupt management.
|
||||||
|
*
|
||||||
|
* The result of calling this function will be the same as if each individual
|
||||||
|
* handler (config->irqHdlTbl[i].hdl) different from "config->defaultEntry.hdl"
|
||||||
|
* has been individualy connected via
|
||||||
|
* BSP_install_rtems_irq_handler(&config->irqHdlTbl[i])
|
||||||
|
* And each handler currently equal to config->defaultEntry.hdl
|
||||||
|
* has been previously disconnected via
|
||||||
|
* BSP_remove_rtems_irq_handler (&config->irqHdlTbl[i])
|
||||||
|
*
|
||||||
|
* This is to say that all information given will be used and not just
|
||||||
|
* only the space.
|
||||||
|
*
|
||||||
|
* CAUTION : the various table address contained in config will be used
|
||||||
|
* directly by the interrupt mangement code in order to save
|
||||||
|
* data size so they must stay valid after the call => they should
|
||||||
|
* not be modified or declared on a stack.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int BSP_rtems_irq_mngt_set(rtems_irq_global_settings* config);
|
||||||
|
/*
|
||||||
|
* (Re) get info on current RTEMS interrupt management.
|
||||||
|
*/
|
||||||
|
int BSP_rtems_irq_mngt_get(rtems_irq_global_settings**);
|
||||||
|
|
||||||
|
extern void BSP_rtems_irq_mng_init(unsigned cpuId);
|
||||||
|
extern void BSP_i8259s_init(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
322
c/src/lib/libbsp/powerpc/shared/irq/irq_asm.S
Normal file
322
c/src/lib/libbsp/powerpc/shared/irq/irq_asm.S
Normal file
@@ -0,0 +1,322 @@
|
|||||||
|
/*
|
||||||
|
* This file contains the assembly code for the PowerPC
|
||||||
|
* IRQ veneers for RTEMS.
|
||||||
|
*
|
||||||
|
* The license and distribution terms for this file may be
|
||||||
|
* found in found in the file LICENSE in this distribution or at
|
||||||
|
* http://www.OARcorp.com/rtems/license.html.
|
||||||
|
*
|
||||||
|
* Modified to support the MCP750.
|
||||||
|
* Modifications Copyright (C) 1999 Eric Valette. valette@crf.canon.fr
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <bsp/vectors.h>
|
||||||
|
#include <libcpu/cpu.h>
|
||||||
|
#include <libcpu/raw_exception.h>
|
||||||
|
#include <rtems/score/targopts.h>
|
||||||
|
#include "asm.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define SYNC \
|
||||||
|
sync; \
|
||||||
|
isync
|
||||||
|
|
||||||
|
.text
|
||||||
|
.p2align 5
|
||||||
|
|
||||||
|
PUBLIC_VAR(decrementer_exception_vector_prolog_code)
|
||||||
|
|
||||||
|
SYM (decrementer_exception_vector_prolog_code):
|
||||||
|
/*
|
||||||
|
* let room for exception frame
|
||||||
|
*/
|
||||||
|
stwu r1, - (EXCEPTION_FRAME_END)(r1)
|
||||||
|
stw r4, GPR4_OFFSET(r1)
|
||||||
|
li r4, ASM_DEC_VECTOR
|
||||||
|
ba shared_raw_irq_code_entry
|
||||||
|
|
||||||
|
PUBLIC_VAR (decrementer_exception_vector_prolog_code_size)
|
||||||
|
|
||||||
|
decrementer_exception_vector_prolog_code_size = . - decrementer_exception_vector_prolog_code
|
||||||
|
|
||||||
|
PUBLIC_VAR(external_exception_vector_prolog_code)
|
||||||
|
|
||||||
|
SYM (external_exception_vector_prolog_code):
|
||||||
|
/*
|
||||||
|
* let room for exception frame
|
||||||
|
*/
|
||||||
|
stwu r1, - (EXCEPTION_FRAME_END)(r1)
|
||||||
|
stw r4, GPR4_OFFSET(r1)
|
||||||
|
li r4, ASM_EXT_VECTOR
|
||||||
|
ba shared_raw_irq_code_entry
|
||||||
|
|
||||||
|
PUBLIC_VAR (external_exception_vector_prolog_code_size)
|
||||||
|
|
||||||
|
external_exception_vector_prolog_code_size = . - external_exception_vector_prolog_code
|
||||||
|
|
||||||
|
PUBLIC_VAR(shared_raw_irq_code_entry)
|
||||||
|
PUBLIC_VAR(C_dispatch_irq_handler)
|
||||||
|
|
||||||
|
.p2align 5
|
||||||
|
SYM (shared_raw_irq_code_entry):
|
||||||
|
/*
|
||||||
|
* Entry conditions :
|
||||||
|
* Registers already saved : R1, R4
|
||||||
|
* R1 : points to a location with enough room for the
|
||||||
|
* interrupt frame
|
||||||
|
* R4 : vector number
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* Save SRR0/SRR1 As soon As possible as it is the minimal needed
|
||||||
|
* to reenable exception processing
|
||||||
|
*/
|
||||||
|
stw r0, GPR0_OFFSET(r1)
|
||||||
|
stw r2, GPR2_OFFSET(r1)
|
||||||
|
stw r3, GPR3_OFFSET(r1)
|
||||||
|
|
||||||
|
mfsrr0 r0
|
||||||
|
mfsrr1 r2
|
||||||
|
mfmsr r3
|
||||||
|
|
||||||
|
stw r0, SRR0_FRAME_OFFSET(r1)
|
||||||
|
stw r2, SRR1_FRAME_OFFSET(r1)
|
||||||
|
/*
|
||||||
|
* Enable data and instruction address translation, exception recovery
|
||||||
|
*/
|
||||||
|
ori r3, r3, MSR_RI | MSR_IR | MSR_DR
|
||||||
|
mtmsr r3
|
||||||
|
SYNC
|
||||||
|
/*
|
||||||
|
* Push C scratch registers on the current stack. It may
|
||||||
|
* actually be the thread stack or the interrupt stack.
|
||||||
|
* Anyway we have to make it in order to be able to call C/C++
|
||||||
|
* functions. Depending on the nesting interrupt level, we will
|
||||||
|
* switch to the right stack later.
|
||||||
|
*/
|
||||||
|
stw r5, GPR5_OFFSET(r1)
|
||||||
|
stw r6, GPR6_OFFSET(r1)
|
||||||
|
stw r7, GPR7_OFFSET(r1)
|
||||||
|
stw r8, GPR8_OFFSET(r1)
|
||||||
|
stw r9, GPR9_OFFSET(r1)
|
||||||
|
stw r10, GPR10_OFFSET(r1)
|
||||||
|
stw r11, GPR11_OFFSET(r1)
|
||||||
|
stw r12, GPR12_OFFSET(r1)
|
||||||
|
stw r13, GPR13_OFFSET(r1)
|
||||||
|
|
||||||
|
mfcr r5
|
||||||
|
mfctr r6
|
||||||
|
mfxer r7
|
||||||
|
mflr r8
|
||||||
|
|
||||||
|
stw r5, EXC_CR_OFFSET(r1)
|
||||||
|
stw r6, EXC_CTR_OFFSET(r1)
|
||||||
|
stw r7, EXC_XER_OFFSET(r1)
|
||||||
|
stw r8, EXC_LR_OFFSET(r1)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add some non volatile registers to store information
|
||||||
|
* that will be used when returning from C handler
|
||||||
|
*/
|
||||||
|
stw r14, GPR14_OFFSET(r1)
|
||||||
|
stw r15, GPR15_OFFSET(r1)
|
||||||
|
/*
|
||||||
|
* save current stack pointer location in R14
|
||||||
|
*/
|
||||||
|
addi r14, r1, 0
|
||||||
|
/*
|
||||||
|
* store part of _Thread_Dispatch_disable_level address in R15
|
||||||
|
*/
|
||||||
|
addis r15,0, _Thread_Dispatch_disable_level@ha
|
||||||
|
/*
|
||||||
|
* Get current nesting level in R2
|
||||||
|
*/
|
||||||
|
mfspr r2, SPRG0
|
||||||
|
/*
|
||||||
|
* Check if stack switch is necessary
|
||||||
|
*/
|
||||||
|
cmpwi r2,0
|
||||||
|
bne nested
|
||||||
|
mfspr r1, SPRG1
|
||||||
|
|
||||||
|
nested:
|
||||||
|
/*
|
||||||
|
* Start Incrementing nesting level in R2
|
||||||
|
*/
|
||||||
|
addi r2,r2,1
|
||||||
|
/*
|
||||||
|
* Start Incrementing _Thread_Dispatch_disable_level R4 = _Thread_Dispatch_disable_level
|
||||||
|
*/
|
||||||
|
lwz r6,_Thread_Dispatch_disable_level@l(r15)
|
||||||
|
/*
|
||||||
|
* store new nesting level in SPRG0
|
||||||
|
*/
|
||||||
|
mtspr SPRG0, r2
|
||||||
|
|
||||||
|
addi r6, r6, 1
|
||||||
|
mfmsr r5
|
||||||
|
/*
|
||||||
|
* store new _Thread_Dispatch_disable_level value
|
||||||
|
*/
|
||||||
|
stw r6, _Thread_Dispatch_disable_level@l(r15)
|
||||||
|
/*
|
||||||
|
* We are now running on the interrupt stack. External and decrementer
|
||||||
|
* exceptions are still disabled. I see no purpose trying to optimize
|
||||||
|
* further assembler code.
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* Call C exception handler for decrementer Interrupt frame is passed just
|
||||||
|
* in case...
|
||||||
|
*/
|
||||||
|
addi r3, r14, 0x8
|
||||||
|
bl C_dispatch_irq_handler /* C_dispatch_irq_handler(cpu_interrupt_frame* r3, vector r4) */
|
||||||
|
/*
|
||||||
|
* start decrementing nesting level. Note : do not test result against 0
|
||||||
|
* value as an easy exit condition because if interrupt nesting level > 1
|
||||||
|
* then _Thread_Dispatch_disable_level > 1
|
||||||
|
*/
|
||||||
|
mfspr r2, SPRG0
|
||||||
|
/*
|
||||||
|
* start decrementing _Thread_Dispatch_disable_level
|
||||||
|
*/
|
||||||
|
lwz r3,_Thread_Dispatch_disable_level@l(r15)
|
||||||
|
addi r2, r2, -1 /* Continue decrementing nesting level */
|
||||||
|
addi r3, r3, -1 /* Continue decrementing _Thread_Dispatch_disable_level */
|
||||||
|
mtspr SPRG0, r2 /* End decrementing nesting level */
|
||||||
|
stw r3,_Thread_Dispatch_disable_level@l(r15) /* End decrementing _Thread_Dispatch_disable_level */
|
||||||
|
cmpwi r3, 0
|
||||||
|
/*
|
||||||
|
* switch back to original stack (done here just optimize registers
|
||||||
|
* contention. Could have been done before...)
|
||||||
|
*/
|
||||||
|
addi r1, r14, 0
|
||||||
|
bne easy_exit /* if (_Thread_Dispatch_disable_level != 0) goto easy_exit */
|
||||||
|
/*
|
||||||
|
* Here we are running again on the thread system stack.
|
||||||
|
* We have interrupt nesting level = _Thread_Dispatch_disable_level = 0.
|
||||||
|
* Interrupt are still disabled. Time to check if scheduler request to
|
||||||
|
* do something with the current thread...
|
||||||
|
*/
|
||||||
|
addis r4, 0, _Context_Switch_necessary@ha
|
||||||
|
lwz r5, _Context_Switch_necessary@l(r4)
|
||||||
|
cmpwi r5, 0
|
||||||
|
bne switch
|
||||||
|
|
||||||
|
addis r6, 0, _ISR_Signals_to_thread_executing@ha
|
||||||
|
lwz r7, _ISR_Signals_to_thread_executing@l(r6)
|
||||||
|
cmpwi r7, 0
|
||||||
|
li r8, 0
|
||||||
|
beq easy_exit
|
||||||
|
stw r8, _ISR_Signals_to_thread_executing@l(r6)
|
||||||
|
/*
|
||||||
|
* going to call _ThreadProcessSignalsFromIrq
|
||||||
|
* Push a complete exception like frame...
|
||||||
|
*/
|
||||||
|
stmw r16, GPR16_OFFSET(r1)
|
||||||
|
addi r3, r1, 0x8
|
||||||
|
/*
|
||||||
|
* compute SP at exception entry
|
||||||
|
*/
|
||||||
|
addi r2, r1, EXCEPTION_FRAME_END
|
||||||
|
/*
|
||||||
|
* store it at the right place
|
||||||
|
*/
|
||||||
|
stw r2, GPR1_OFFSET(r1)
|
||||||
|
/*
|
||||||
|
* Call High Level signal handling code
|
||||||
|
*/
|
||||||
|
bl _ISR_Signals_to_thread_executing
|
||||||
|
/*
|
||||||
|
* start restoring exception like frame
|
||||||
|
*/
|
||||||
|
lwz r31, EXC_CTR_OFFSET(r1)
|
||||||
|
lwz r30, EXC_XER_OFFSET(r1)
|
||||||
|
lwz r29, EXC_CR_OFFSET(r1)
|
||||||
|
lwz r28, EXC_LR_OFFSET(r1)
|
||||||
|
|
||||||
|
mtctr r31
|
||||||
|
mtxer r30
|
||||||
|
mtcr r29
|
||||||
|
mtlr r28
|
||||||
|
|
||||||
|
lmw r4, GPR4_OFFSET(r1)
|
||||||
|
lwz r2, GPR2_OFFSET(r1)
|
||||||
|
lwz r0, GPR0_OFFSET(r1)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Disable data and instruction translation. Make path non recoverable...
|
||||||
|
*/
|
||||||
|
mfmsr r3
|
||||||
|
xori r3, r3, MSR_RI | MSR_IR | MSR_DR
|
||||||
|
mtmsr r3
|
||||||
|
SYNC
|
||||||
|
/*
|
||||||
|
* Restore rfi related settings
|
||||||
|
*/
|
||||||
|
|
||||||
|
lwz r3, SRR1_FRAME_OFFSET(r1)
|
||||||
|
mtsrr1 r3
|
||||||
|
lwz r3, SRR0_FRAME_OFFSET(r1)
|
||||||
|
mtsrr0 r3
|
||||||
|
|
||||||
|
lwz r3, GPR3_OFFSET(r1)
|
||||||
|
addi r1,r1, EXCEPTION_FRAME_END
|
||||||
|
SYNC
|
||||||
|
rfi
|
||||||
|
|
||||||
|
switch:
|
||||||
|
bl SYM (_Thread_Dispatch)
|
||||||
|
|
||||||
|
easy_exit:
|
||||||
|
/*
|
||||||
|
* start restoring interrupt frame
|
||||||
|
*/
|
||||||
|
lwz r3, EXC_CTR_OFFSET(r1)
|
||||||
|
lwz r4, EXC_XER_OFFSET(r1)
|
||||||
|
lwz r5, EXC_CR_OFFSET(r1)
|
||||||
|
lwz r6, EXC_LR_OFFSET(r1)
|
||||||
|
|
||||||
|
mtctr r3
|
||||||
|
mtxer r4
|
||||||
|
mtcr r5
|
||||||
|
mtlr r6
|
||||||
|
|
||||||
|
lwz r15, GPR15_OFFSET(r1)
|
||||||
|
lwz r14, GPR14_OFFSET(r1)
|
||||||
|
lwz r13, GPR13_OFFSET(r1)
|
||||||
|
lwz r12, GPR12_OFFSET(r1)
|
||||||
|
lwz r11, GPR11_OFFSET(r1)
|
||||||
|
lwz r10, GPR10_OFFSET(r1)
|
||||||
|
lwz r9, GPR9_OFFSET(r1)
|
||||||
|
lwz r8, GPR8_OFFSET(r1)
|
||||||
|
lwz r7, GPR7_OFFSET(r1)
|
||||||
|
lwz r6, GPR6_OFFSET(r1)
|
||||||
|
lwz r5, GPR5_OFFSET(r1)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Disable nested exception processing, data and instruction
|
||||||
|
* translation.
|
||||||
|
*/
|
||||||
|
mfmsr r3
|
||||||
|
xori r3, r3, MSR_RI | MSR_IR | MSR_DR
|
||||||
|
mtmsr r3
|
||||||
|
SYNC
|
||||||
|
/*
|
||||||
|
* Restore rfi related settings
|
||||||
|
*/
|
||||||
|
|
||||||
|
lwz r4, SRR1_FRAME_OFFSET(r1)
|
||||||
|
lwz r2, SRR0_FRAME_OFFSET(r1)
|
||||||
|
lwz r3, GPR3_OFFSET(r1)
|
||||||
|
lwz r0, GPR0_OFFSET(r1)
|
||||||
|
|
||||||
|
mtsrr1 r4
|
||||||
|
mtsrr0 r2
|
||||||
|
lwz r4, GPR4_OFFSET(r1)
|
||||||
|
lwz r2, GPR2_OFFSET(r1)
|
||||||
|
addi r1,r1, EXCEPTION_FRAME_END
|
||||||
|
SYNC
|
||||||
|
rfi
|
||||||
|
|
||||||
315
c/src/lib/libbsp/powerpc/shared/irq/irq_init.c
Normal file
315
c/src/lib/libbsp/powerpc/shared/irq/irq_init.c
Normal file
@@ -0,0 +1,315 @@
|
|||||||
|
/* irq_init.c
|
||||||
|
*
|
||||||
|
* This file contains the implementation of rtems initialization
|
||||||
|
* related to interrupt handling.
|
||||||
|
*
|
||||||
|
* CopyRight (C) 1999 valette@crf.canon.fr
|
||||||
|
*
|
||||||
|
* The license and distribution terms for this file may be
|
||||||
|
* found in the file LICENSE in this distribution or at
|
||||||
|
* http://www.OARcorp.com/rtems/license.html.
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*/
|
||||||
|
#include <bsp/consoleIo.h>
|
||||||
|
#include <libcpu/io.h>
|
||||||
|
#include <libcpu/spr.h>
|
||||||
|
#include <bsp/pci.h>
|
||||||
|
#include <bsp/residual.h>
|
||||||
|
#include <bsp/openpic.h>
|
||||||
|
#include <bsp/irq.h>
|
||||||
|
#include <bsp.h>
|
||||||
|
#include <libcpu/raw_exception.h>
|
||||||
|
#include <bsp/motorola.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned char bus; /* few chance the PCI/ISA bridge is not on first bus but ... */
|
||||||
|
unsigned char device;
|
||||||
|
unsigned char function;
|
||||||
|
} pci_isa_bridge_device;
|
||||||
|
|
||||||
|
pci_isa_bridge_device* via_82c586 = 0;
|
||||||
|
static pci_isa_bridge_device bridge;
|
||||||
|
|
||||||
|
extern unsigned int external_exception_vector_prolog_code_size;
|
||||||
|
extern void external_exception_vector_prolog_code();
|
||||||
|
extern unsigned int decrementer_exception_vector_prolog_code_size;
|
||||||
|
extern void decrementer_exception_vector_prolog_code();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* default on/off function
|
||||||
|
*/
|
||||||
|
static void nop_func(){}
|
||||||
|
/*
|
||||||
|
* default isOn function
|
||||||
|
*/
|
||||||
|
static int not_connected() {return 0;}
|
||||||
|
/*
|
||||||
|
* default possible isOn function
|
||||||
|
*/
|
||||||
|
static int connected() {return 1;}
|
||||||
|
|
||||||
|
static rtems_irq_connect_data rtemsIrq[BSP_IRQ_NUMBER];
|
||||||
|
static rtems_irq_global_settings initial_config;
|
||||||
|
static rtems_irq_connect_data defaultIrq = {
|
||||||
|
/* vectorIdex, hdl , on , off , isOn */
|
||||||
|
0, nop_func , nop_func , nop_func , not_connected
|
||||||
|
};
|
||||||
|
static rtems_irq_prio irqPrioTable[BSP_IRQ_NUMBER]={
|
||||||
|
/*
|
||||||
|
* actual rpiorities for interrupt :
|
||||||
|
* 0 means that only current interrupt is masked
|
||||||
|
* 255 means all other interrupts are masked
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* ISA interrupts.
|
||||||
|
* The second entry has a priority of 255 because
|
||||||
|
* it is the slave pic entry and is should always remain
|
||||||
|
* unmasked.
|
||||||
|
*/
|
||||||
|
0,0,
|
||||||
|
255,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
/*
|
||||||
|
* PCI Interrupts
|
||||||
|
*/
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* for raven prio 0 means unactive... */
|
||||||
|
/*
|
||||||
|
* Processor exceptions handled as interrupts
|
||||||
|
*/
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
static unsigned char mcp750_openpic_initsenses[] = {
|
||||||
|
1, /* MCP750_INT_PCB(8259) */
|
||||||
|
0, /* MCP750_INT_FALCON_ECC_ERR */
|
||||||
|
1, /* MCP750_INT_PCI_ETHERNET */
|
||||||
|
1, /* MCP750_INT_PCI_PMC */
|
||||||
|
1, /* MCP750_INT_PCI_WATCHDOG_TIMER1 */
|
||||||
|
1, /* MCP750_INT_PCI_PRST_SIGNAL */
|
||||||
|
1, /* MCP750_INT_PCI_FALL_SIGNAL */
|
||||||
|
1, /* MCP750_INT_PCI_DEG_SIGNAL */
|
||||||
|
1, /* MCP750_INT_PCI_BUS1_INTA */
|
||||||
|
1, /* MCP750_INT_PCI_BUS1_INTB */
|
||||||
|
1, /* MCP750_INT_PCI_BUS1_INTC */
|
||||||
|
1, /* MCP750_INT_PCI_BUS1_INTD */
|
||||||
|
1, /* MCP750_INT_PCI_BUS2_INTA */
|
||||||
|
1, /* MCP750_INT_PCI_BUS2_INTB */
|
||||||
|
1, /* MCP750_INT_PCI_BUS2_INTC */
|
||||||
|
1, /* MCP750_INT_PCI_BUS2_INTD */
|
||||||
|
};
|
||||||
|
|
||||||
|
void VIA_isa_bridge_interrupts_setup(void)
|
||||||
|
{
|
||||||
|
pci_isa_bridge_device pci_dev;
|
||||||
|
unsigned int temp;
|
||||||
|
unsigned char tmp;
|
||||||
|
unsigned char maxBus;
|
||||||
|
unsigned found = 0;
|
||||||
|
|
||||||
|
maxBus = BusCountPCI();
|
||||||
|
pci_dev.function = 0; /* Assumes the bidge is the first function */
|
||||||
|
|
||||||
|
for (pci_dev.bus = 0; pci_dev.bus < maxBus; pci_dev.bus++) {
|
||||||
|
#ifdef SCAN_PCI_PRINT
|
||||||
|
printk("isa_bridge_interrupts_setup: Scanning bus %d\n", pci_dev.bus);
|
||||||
|
#endif
|
||||||
|
for (pci_dev.device = 0; pci_dev.device < PCI_MAX_DEVICES; pci_dev.device++) {
|
||||||
|
#ifdef SCAN_PCI_PRINT
|
||||||
|
printk("isa_bridge_interrupts_setup: Scanning device %d\n", pci_dev.device);
|
||||||
|
#endif
|
||||||
|
pci_read_config_dword(pci_dev.bus, pci_dev.device, pci_dev.function,
|
||||||
|
PCI_VENDOR_ID, &temp);
|
||||||
|
#ifdef SCAN_PCI_PRINT
|
||||||
|
printk("Vendor/device = %x\n", temp);
|
||||||
|
#endif
|
||||||
|
if ( (temp == (((unsigned short) PCI_VENDOR_ID_VIA) | (PCI_DEVICE_ID_VIA_82C586_1 << 16)))
|
||||||
|
||
|
||||||
|
(temp == (((unsigned short) PCI_VENDOR_ID_VIA) | (PCI_DEVICE_ID_VIA_82C586_0 << 16)))
|
||||||
|
) {
|
||||||
|
bridge = pci_dev;
|
||||||
|
via_82c586 = &bridge;
|
||||||
|
#ifdef SHOW_ISA_PCI_BRIDGE_SETTINGS
|
||||||
|
/*
|
||||||
|
* Should print : bus = 0, device = 11, function = 0 on a MCP750.
|
||||||
|
*/
|
||||||
|
printk("Via PCI/ISA bridge found at bus = %d, device = %d, function = %d\n",
|
||||||
|
via_82c586->bus,
|
||||||
|
via_82c586->device,
|
||||||
|
via_82c586->function);
|
||||||
|
#endif
|
||||||
|
found = 1;
|
||||||
|
goto loop_exit;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loop_exit:
|
||||||
|
if (!found) BSP_panic("VIA_82C586 PCI/ISA bridge not found!n");
|
||||||
|
|
||||||
|
tmp = inb(0x810);
|
||||||
|
if ( !(tmp & 0x2)) {
|
||||||
|
#ifdef SHOW_ISA_PCI_BRIDGE_SETTINGS
|
||||||
|
printk("This is a second generation MCP750 board\n");
|
||||||
|
printk("We must reprogram the PCI/ISA bridge...\n");
|
||||||
|
#endif
|
||||||
|
pci_read_config_byte(via_82c586->bus, via_82c586->device, via_82c586->function,
|
||||||
|
0x47, &tmp);
|
||||||
|
#ifdef SHOW_ISA_PCI_BRIDGE_SETTINGS
|
||||||
|
printk(" PCI ISA bridge control2 = %x\n", (unsigned) tmp);
|
||||||
|
#endif
|
||||||
|
/*
|
||||||
|
* Enable 4D0/4D1 ISA interrupt level/edge config registers
|
||||||
|
*/
|
||||||
|
tmp |= 0x20;
|
||||||
|
pci_write_config_byte(via_82c586->bus, via_82c586->device, via_82c586->function,
|
||||||
|
0x47, tmp);
|
||||||
|
/*
|
||||||
|
* Now program the ISA interrupt edge/level
|
||||||
|
*/
|
||||||
|
tmp = ELCRS_INT9_LVL | ELCRS_INT10_LVL | ELCRS_INT11_LVL;
|
||||||
|
outb(tmp, ISA8259_S_ELCR);
|
||||||
|
tmp = ELCRM_INT5_LVL;
|
||||||
|
outb(tmp, ISA8259_M_ELCR);;
|
||||||
|
/*
|
||||||
|
* Set the Interrupt inputs to non-inverting level interrupt
|
||||||
|
*/
|
||||||
|
pci_read_config_byte(via_82c586->bus, via_82c586->device, via_82c586->function,
|
||||||
|
0x54, &tmp);
|
||||||
|
#ifdef SHOW_ISA_PCI_BRIDGE_SETTINGS
|
||||||
|
printk(" PCI ISA bridge PCI/IRQ Edge/Level Select = %x\n", (unsigned) tmp);
|
||||||
|
#endif
|
||||||
|
tmp = 0;
|
||||||
|
pci_write_config_byte(via_82c586->bus, via_82c586->device, via_82c586->function,
|
||||||
|
0x54, tmp);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
#ifdef SHOW_ISA_PCI_BRIDGE_SETTINGS
|
||||||
|
printk("This is a first generation MCP750 board\n");
|
||||||
|
printk("We just show the actual value used by PCI/ISA bridge\n");
|
||||||
|
#endif
|
||||||
|
pci_read_config_byte(via_82c586->bus, via_82c586->device, via_82c586->function,
|
||||||
|
0x47, &tmp);
|
||||||
|
#ifdef SHOW_ISA_PCI_BRIDGE_SETTINGS
|
||||||
|
printk(" PCI ISA bridge control2 = %x\n", (unsigned) tmp);
|
||||||
|
#endif
|
||||||
|
/*
|
||||||
|
* Enable 4D0/4D1 ISA interrupt level/edge config registers
|
||||||
|
*/
|
||||||
|
tmp |= 0x20;
|
||||||
|
pci_write_config_byte(via_82c586->bus, via_82c586->device, via_82c586->function,
|
||||||
|
0x47, tmp);
|
||||||
|
#ifdef SHOW_ISA_PCI_BRIDGE_SETTINGS
|
||||||
|
tmp = inb(ISA8259_S_ELCR);
|
||||||
|
printk(" PCI ISA bridge slave edge/level control bit = %x\n", (unsigned) tmp);
|
||||||
|
tmp = inb(ISA8259_M_ELCR);;
|
||||||
|
printk(" PCI ISA bridge master edge/level control bit = %x\n", (unsigned) tmp);
|
||||||
|
#endif
|
||||||
|
/*
|
||||||
|
* Must disable the 4D0/4D1 ISA interrupt level/edge config registers
|
||||||
|
* or the card will die a soon as we we will enable external interrupts
|
||||||
|
*/
|
||||||
|
pci_read_config_byte(via_82c586->bus, via_82c586->device, via_82c586->function,
|
||||||
|
0x47, &tmp);
|
||||||
|
tmp &= ~(0x20);
|
||||||
|
pci_write_config_byte(via_82c586->bus, via_82c586->device, via_82c586->function,
|
||||||
|
0x47, tmp);
|
||||||
|
/*
|
||||||
|
* Show the Interrupt inputs inverting/non-inverting level status
|
||||||
|
*/
|
||||||
|
pci_read_config_byte(via_82c586->bus, via_82c586->device, via_82c586->function,
|
||||||
|
0x54, &tmp);
|
||||||
|
#ifdef SHOW_ISA_PCI_BRIDGE_SETTINGS
|
||||||
|
printk(" PCI ISA bridge PCI/IRQ Edge/Level Select = %x\n", (unsigned) tmp);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This code assumes the exceptions management setup has already
|
||||||
|
* been done. We just need to replace the exceptions that will
|
||||||
|
* be handled like interrupt. On mcp750/mpc750 and many PPC processors
|
||||||
|
* this means the decrementer exception and the external exception.
|
||||||
|
*/
|
||||||
|
void BSP_rtems_irq_mng_init(unsigned cpuId)
|
||||||
|
{
|
||||||
|
rtems_raw_except_connect_data vectorDesc;
|
||||||
|
int known_cpi_isa_bridge = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* First initialize the Interrupt management hardware
|
||||||
|
*/
|
||||||
|
OpenPIC_InitSenses = mcp750_openpic_initsenses;
|
||||||
|
OpenPIC_NumInitSenses = sizeof(mcp750_openpic_initsenses) / sizeof(char);
|
||||||
|
#ifdef TRACE_IRQ_INIT
|
||||||
|
printk("Going to initialize raven interrupt controller (openpic compliant)\n");
|
||||||
|
#endif
|
||||||
|
openpic_init(1);
|
||||||
|
#ifdef TRACE_IRQ_INIT
|
||||||
|
printk("Going to initialize the PCI/ISA bridge IRQ related setting (VIA 82C586)\n");
|
||||||
|
#endif
|
||||||
|
if ( (currentBoard == MESQUITE) ) {
|
||||||
|
VIA_isa_bridge_interrupts_setup();
|
||||||
|
known_cpi_isa_bridge = 1;
|
||||||
|
}
|
||||||
|
if (!known_cpi_isa_bridge) {
|
||||||
|
printk("Please add code for PCI/ISA bridge init to libbsp/shared/irq/irq_init.c\n");
|
||||||
|
printk("If your card works correctly please add a test and set known_cpi_isa_bridge to true\n");
|
||||||
|
}
|
||||||
|
#ifdef TRACE_IRQ_INIT
|
||||||
|
printk("Going to initialize the ISA PC legacy IRQ management hardware\n");
|
||||||
|
#endif
|
||||||
|
BSP_i8259s_init();
|
||||||
|
/*
|
||||||
|
* Initialize Rtems management interrupt table
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* re-init the rtemsIrq table
|
||||||
|
*/
|
||||||
|
for (i = 0; i < BSP_IRQ_NUMBER; i++) {
|
||||||
|
rtemsIrq[i] = defaultIrq;
|
||||||
|
rtemsIrq[i].name = i;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Init initial Interrupt management config
|
||||||
|
*/
|
||||||
|
initial_config.irqNb = BSP_IRQ_NUMBER;
|
||||||
|
initial_config.defaultEntry = defaultIrq;
|
||||||
|
initial_config.irqHdlTbl = rtemsIrq;
|
||||||
|
initial_config.irqBase = BSP_ASM_IRQ_VECTOR_BASE;
|
||||||
|
initial_config.irqPrioTbl = irqPrioTable;
|
||||||
|
|
||||||
|
if (!BSP_rtems_irq_mngt_set(&initial_config)) {
|
||||||
|
/*
|
||||||
|
* put something here that will show the failure...
|
||||||
|
*/
|
||||||
|
BSP_panic("Unable to initialize RTEMS interrupt Management!!! System locked\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We must connect the raw irq handler for the two
|
||||||
|
* expected interrupt sources : decrementer and external interrupts.
|
||||||
|
*/
|
||||||
|
vectorDesc.exceptIndex = ASM_DEC_VECTOR;
|
||||||
|
vectorDesc.hdl.vector = ASM_DEC_VECTOR;
|
||||||
|
vectorDesc.hdl.raw_hdl = decrementer_exception_vector_prolog_code;
|
||||||
|
vectorDesc.hdl.raw_hdl_size = (unsigned) &decrementer_exception_vector_prolog_code_size;
|
||||||
|
vectorDesc.on = nop_func;
|
||||||
|
vectorDesc.off = nop_func;
|
||||||
|
vectorDesc.isOn = connected;
|
||||||
|
if (!mpc60x_set_exception (&vectorDesc)) {
|
||||||
|
BSP_panic("Unable to initialize RTEMS decrementer raw exception\n");
|
||||||
|
}
|
||||||
|
vectorDesc.exceptIndex = ASM_EXT_VECTOR;
|
||||||
|
vectorDesc.hdl.vector = ASM_EXT_VECTOR;
|
||||||
|
vectorDesc.hdl.raw_hdl = external_exception_vector_prolog_code;
|
||||||
|
vectorDesc.hdl.raw_hdl_size = (unsigned) &external_exception_vector_prolog_code_size;
|
||||||
|
if (!mpc60x_set_exception (&vectorDesc)) {
|
||||||
|
BSP_panic("Unable to initialize RTEMS external raw exception\n");
|
||||||
|
}
|
||||||
|
#ifdef TRACE_IRQ_INIT
|
||||||
|
printk("RTEMS IRQ management is now operationnal\n");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
41
c/src/lib/libbsp/powerpc/shared/motorola/Makefile.in
Normal file
41
c/src/lib/libbsp/powerpc/shared/motorola/Makefile.in
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
#
|
||||||
|
# $Id$
|
||||||
|
#
|
||||||
|
|
||||||
|
@SET_MAKE@
|
||||||
|
srcdir = @srcdir@
|
||||||
|
top_srcdir = @top_srcdir@
|
||||||
|
top_builddir = ../../..
|
||||||
|
subdir = powerpc/shared/motorola
|
||||||
|
|
||||||
|
RTEMS_ROOT = @RTEMS_ROOT@
|
||||||
|
PROJECT_ROOT = @PROJECT_ROOT@
|
||||||
|
|
||||||
|
VPATH = @srcdir@
|
||||||
|
|
||||||
|
H_FILES = $(srcdir)/motorola.h
|
||||||
|
|
||||||
|
SRCS = $(C_FILES) $(H_FILES)
|
||||||
|
|
||||||
|
include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
|
||||||
|
include $(RTEMS_ROOT)/make/leaf.cfg
|
||||||
|
|
||||||
|
INSTALL_CHANGE = @INSTALL_CHANGE@
|
||||||
|
mkinstalldirs = $(SHELL) $(top_srcdir)/@RTEMS_TOPdir@/mkinstalldirs
|
||||||
|
|
||||||
|
INSTALLDIRS = $(PROJECT_INCLUDE)/bsp
|
||||||
|
|
||||||
|
$(INSTALLDIRS):
|
||||||
|
@$(mkinstalldirs) $(INSTALLDIRS)
|
||||||
|
|
||||||
|
preinstall:
|
||||||
|
@$(mkinstalldirs) $(PROJECT_INCLUDE)/bsp
|
||||||
|
@$(INSTALL_CHANGE) -m 644 $(H_FILES) $(PROJECT_INCLUDE)/bsp
|
||||||
|
|
||||||
|
all: ${ARCH} $(SRCS) preinstall
|
||||||
|
|
||||||
|
install: all
|
||||||
|
|
||||||
|
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||||
|
cd $(top_builddir) \
|
||||||
|
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
|
||||||
120
c/src/lib/libbsp/powerpc/shared/motorola/motorola.c
Normal file
120
c/src/lib/libbsp/powerpc/shared/motorola/motorola.c
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
/* motorola.h
|
||||||
|
*
|
||||||
|
* This include file describe the data structure and the functions implemented
|
||||||
|
* by rtems to identify motorola boards.
|
||||||
|
*
|
||||||
|
* CopyRight (C) 1999 valette@crf.canon.fr
|
||||||
|
*
|
||||||
|
* The license and distribution terms for this file may be
|
||||||
|
* found in found in the file LICENSE in this distribution or at
|
||||||
|
* http://www.OARcorp.com/rtems/license.html.
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <bsp/motorola.h>
|
||||||
|
#include <libcpu/io.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
/*
|
||||||
|
* 0x100 mask assumes for Raven and Hawk boards
|
||||||
|
* that the level/edge are set.
|
||||||
|
* 0x200 if this board has a Hawk chip.
|
||||||
|
*/
|
||||||
|
int cpu_type;
|
||||||
|
int base_type;
|
||||||
|
const char *name;
|
||||||
|
} mot_info_t;
|
||||||
|
|
||||||
|
|
||||||
|
static const mot_info_t mot_boards[] = {
|
||||||
|
{0x300, 0x00, "MVME 2400"},
|
||||||
|
{0x010, 0x00, "Genesis"},
|
||||||
|
{0x020, 0x00, "Powerstack (Series E)"},
|
||||||
|
{0x040, 0x00, "Blackhawk (Powerstack)"},
|
||||||
|
{0x050, 0x00, "Omaha (PowerStack II Pro3000)"},
|
||||||
|
{0x060, 0x00, "Utah (Powerstack II Pro4000)"},
|
||||||
|
{0x0A0, 0x00, "Powerstack (Series EX)"},
|
||||||
|
{0x1E0, 0xE0, "Mesquite cPCI (MCP750)"},
|
||||||
|
{0x1E0, 0xE1, "Sitka cPCI (MCPN750)"},
|
||||||
|
{0x1E0, 0xE2, "Mesquite cPCI (MCP750) w/ HAC"},
|
||||||
|
{0x1E0, 0xF6, "MTX Plus"},
|
||||||
|
{0x1E0, 0xF7, "MTX wo/ Parallel Port"},
|
||||||
|
{0x1E0, 0xF8, "MTX w/ Parallel Port"},
|
||||||
|
{0x1E0, 0xF9, "MVME 2300"},
|
||||||
|
{0x1E0, 0xFA, "MVME 2300SC/2600"},
|
||||||
|
{0x1E0, 0xFB, "MVME 2600 with MVME712M"},
|
||||||
|
{0x1E0, 0xFC, "MVME 2600/2700 with MVME761"},
|
||||||
|
{0x1E0, 0xFD, "MVME 3600 with MVME712M"},
|
||||||
|
{0x1E0, 0xFE, "MVME 3600 with MVME761"},
|
||||||
|
{0x1E0, 0xFF, "MVME 1600-001 or 1600-011"},
|
||||||
|
{0x000, 0x00, ""}
|
||||||
|
};
|
||||||
|
|
||||||
|
prep_t currentPrepType;
|
||||||
|
motorolaBoard currentBoard;
|
||||||
|
prep_t checkPrepBoardType(RESIDUAL *res)
|
||||||
|
{
|
||||||
|
prep_t PREP_type;
|
||||||
|
/* figure out what kind of prep workstation we are */
|
||||||
|
if ( res->ResidualLength != 0 ) {
|
||||||
|
if ( !strncmp(res->VitalProductData.PrintableModel,"IBM",3) )
|
||||||
|
PREP_type = PREP_IBM;
|
||||||
|
else if (!strncmp(res->VitalProductData.PrintableModel,
|
||||||
|
"Radstone",8)){
|
||||||
|
PREP_type = PREP_Radstone;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
PREP_type = PREP_Motorola;
|
||||||
|
}
|
||||||
|
else /* assume motorola if no residual (netboot?) */ {
|
||||||
|
PREP_type = PREP_Motorola;
|
||||||
|
}
|
||||||
|
currentPrepType = PREP_type;
|
||||||
|
return PREP_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
motorolaBoard getMotorolaBoard()
|
||||||
|
{
|
||||||
|
unsigned char cpu_type;
|
||||||
|
unsigned char base_mod;
|
||||||
|
int entry;
|
||||||
|
int mot_entry = -1;
|
||||||
|
|
||||||
|
cpu_type = inb(MOTOROLA_CPUTYPE_REG) & 0xF0;
|
||||||
|
base_mod = inb(MOTOROLA_BASETYPE_REG);
|
||||||
|
|
||||||
|
for (entry = 0; mot_boards[entry].cpu_type != 0; entry++) {
|
||||||
|
if ((mot_boards[entry].cpu_type & 0xff) != cpu_type)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (mot_boards[entry].base_type == 0) {
|
||||||
|
mot_entry = entry;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mot_boards[entry].base_type != base_mod)
|
||||||
|
continue;
|
||||||
|
else{
|
||||||
|
mot_entry = entry;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mot_entry == -1) {
|
||||||
|
printk("Unkwon motorola board Please update libbsp/powerpc/shared/motorola/motorola.c\n");
|
||||||
|
printk("cpu_type = %x\n", (unsigned) cpu_type);
|
||||||
|
printk("base_mod = %x\n", (unsigned) base_mod);
|
||||||
|
currentBoard = MOTOROLA_UNKNOWN;
|
||||||
|
return currentBoard;
|
||||||
|
}
|
||||||
|
currentBoard = (motorolaBoard) mot_entry;
|
||||||
|
return currentBoard;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* motorolaBoardToString(motorolaBoard board)
|
||||||
|
{
|
||||||
|
if (board == MOTOROLA_UNKNOWN) return "Unknown motorola board";
|
||||||
|
return (mot_boards[board].name);
|
||||||
|
}
|
||||||
|
|
||||||
67
c/src/lib/libbsp/powerpc/shared/motorola/motorola.h
Normal file
67
c/src/lib/libbsp/powerpc/shared/motorola/motorola.h
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
/* motorola.h
|
||||||
|
*
|
||||||
|
* This include file describe the data structure and the functions implemented
|
||||||
|
* by rtems to identify motorola boards.
|
||||||
|
*
|
||||||
|
* CopyRight (C) 1999 valette@crf.canon.fr
|
||||||
|
*
|
||||||
|
* The license and distribution terms for this file may be
|
||||||
|
* found in found in the file LICENSE in this distribution or at
|
||||||
|
* http://www.OARcorp.com/rtems/license.html.
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LIBBSP_POWERPC_SHARED_MOTOROLA_MOTOROLA_H
|
||||||
|
#define LIBBSP_POWERPC_SHARED_MOTOROLA_MOTOROLA_H
|
||||||
|
|
||||||
|
#include <bsp/residual.h>
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
PREP_IBM = 0,
|
||||||
|
PREP_Radstone = 1,
|
||||||
|
PREP_Motorola = 2
|
||||||
|
}prep_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
MVME_2400 = 0,
|
||||||
|
GENESIS = 1,
|
||||||
|
POWERSTACK_E = 2,
|
||||||
|
BLACKAWK = 3,
|
||||||
|
OMAHA = 4,
|
||||||
|
UTAH = 5,
|
||||||
|
POWERSTACK_EX = 6,
|
||||||
|
MESQUITE = 7,
|
||||||
|
SITKA = 8,
|
||||||
|
MESQUITE_W_HAC = 9,
|
||||||
|
MTX_PLUS = 10,
|
||||||
|
MTX_WO_PP = 11,
|
||||||
|
MTX_W_PP = 12,
|
||||||
|
MVME_2300 = 13,
|
||||||
|
MVME_2300SC_2600 = 14,
|
||||||
|
MVME_2600_W_MVME712M = 15,
|
||||||
|
MVME_2600_2700_W_MVME761 = 16,
|
||||||
|
MVME_3600_W_MVME712M = 17,
|
||||||
|
MVME_3600_W_MVME761 = 18,
|
||||||
|
MVME_1600 = 19,
|
||||||
|
MOTOROLA_UNKNOWN = 255
|
||||||
|
} motorolaBoard;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
HOST_BRIDGE_RAVEN = 0,
|
||||||
|
HOST_BRIDGE_HAWK = 1,
|
||||||
|
HOST_BRIDGE_UNKNOWN = 255
|
||||||
|
}motorolaHostBridge;
|
||||||
|
|
||||||
|
#define MOTOROLA_CPUTYPE_REG 0x800
|
||||||
|
#define MOTOROLA_BASETYPE_REG 0x803
|
||||||
|
|
||||||
|
extern prep_t checkPrepBoardType(RESIDUAL *res);
|
||||||
|
extern prep_t currentPrepType;
|
||||||
|
extern motorolaBoard getMotorolaBoard();
|
||||||
|
extern motorolaBoard currentBoard;
|
||||||
|
extern const char* motorolaBoardToString(motorolaBoard);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* LIBBSP_POWERPC_SHARED_MOTOROLA_MOTOROLA_H */
|
||||||
|
|
||||||
42
c/src/lib/libbsp/powerpc/shared/openpic/Makefile.in
Normal file
42
c/src/lib/libbsp/powerpc/shared/openpic/Makefile.in
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
#
|
||||||
|
# $Id$
|
||||||
|
#
|
||||||
|
|
||||||
|
@SET_MAKE@
|
||||||
|
srcdir = @srcdir@
|
||||||
|
top_srcdir = @top_srcdir@
|
||||||
|
top_builddir = ../../..
|
||||||
|
subdir = powerpc/shared/openpic
|
||||||
|
|
||||||
|
RTEMS_ROOT = @RTEMS_ROOT@
|
||||||
|
PROJECT_ROOT = @PROJECT_ROOT@
|
||||||
|
|
||||||
|
VPATH = @srcdir@
|
||||||
|
|
||||||
|
H_FILES = $(srcdir)/openpic.h
|
||||||
|
|
||||||
|
SRCS = $(C_FILES) $(H_FILES)
|
||||||
|
|
||||||
|
include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
|
||||||
|
include $(RTEMS_ROOT)/make/leaf.cfg
|
||||||
|
|
||||||
|
INSTALL_CHANGE = @INSTALL_CHANGE@
|
||||||
|
mkinstalldirs = $(SHELL) $(top_srcdir)/@RTEMS_TOPdir@/mkinstalldirs
|
||||||
|
|
||||||
|
INSTALLDIRS = $(PROJECT_INCLUDE)/bsp
|
||||||
|
|
||||||
|
$(INSTALLDIRS):
|
||||||
|
@$(mkinstalldirs) $(INSTALLDIRS)
|
||||||
|
|
||||||
|
preinstall:
|
||||||
|
@$(mkinstalldirs) $(PROJECT_INCLUDE)/bsp
|
||||||
|
@$(INSTALL_CHANGE) -m 644 $(H_FILES) $(PROJECT_INCLUDE)/bsp
|
||||||
|
|
||||||
|
all: ${ARCH} $(SRCS) preinstall
|
||||||
|
|
||||||
|
# the .rel file built here will be put into libbsp.a by ../wrapup/Makefile
|
||||||
|
install: all
|
||||||
|
|
||||||
|
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||||
|
cd $(top_builddir) \
|
||||||
|
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
|
||||||
509
c/src/lib/libbsp/powerpc/shared/openpic/openpic.c
Normal file
509
c/src/lib/libbsp/powerpc/shared/openpic/openpic.c
Normal file
@@ -0,0 +1,509 @@
|
|||||||
|
/*
|
||||||
|
* openpic.c -- OpenPIC Interrupt Handling
|
||||||
|
*
|
||||||
|
* Copyright (C) 1997 Geert Uytterhoeven
|
||||||
|
*
|
||||||
|
* Modified to compile in RTEMS development environment
|
||||||
|
* by Eric Valette
|
||||||
|
*
|
||||||
|
* Copyright (C) 1999 Eric Valette. valette@crf.canon.fr
|
||||||
|
*
|
||||||
|
* The license and distribution terms for this file may be
|
||||||
|
* found in found in the file LICENSE in this distribution or at
|
||||||
|
* http://www.OARcorp.com/rtems/license.html.
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note: Interprocessor Interrupt (IPI) and Timer support is incomplete
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <bsp/openpic.h>
|
||||||
|
#include <bsp/pci.h>
|
||||||
|
#include <bsp/consoleIo.h>
|
||||||
|
#include <libcpu/io.h>
|
||||||
|
#include <libcpu/byteorder.h>
|
||||||
|
#include <bsp.h>
|
||||||
|
|
||||||
|
#define NULL 0
|
||||||
|
#define REGISTER_DEBUG
|
||||||
|
#undef REGISTER_DEBUG
|
||||||
|
|
||||||
|
|
||||||
|
volatile struct OpenPIC *OpenPIC = NULL;
|
||||||
|
unsigned int OpenPIC_NumInitSenses = 0;
|
||||||
|
unsigned char *OpenPIC_InitSenses = NULL;
|
||||||
|
|
||||||
|
static unsigned int NumProcessors;
|
||||||
|
static unsigned int NumSources;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Accesses to the current processor's registers
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define THIS_CPU Processor[cpu]
|
||||||
|
#define CHECK_THIS_CPU check_arg_cpu(cpu)
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sanity checks
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
#define check_arg_ipi(ipi) \
|
||||||
|
if (ipi < 0 || ipi >= OPENPIC_NUM_IPI) \
|
||||||
|
printk("openpic.c:%d: illegal ipi %d\n", __LINE__, ipi);
|
||||||
|
#define check_arg_timer(timer) \
|
||||||
|
if (timer < 0 || timer >= OPENPIC_NUM_TIMERS) \
|
||||||
|
printk("openpic.c:%d: illegal timer %d\n", __LINE__, timer);
|
||||||
|
#define check_arg_vec(vec) \
|
||||||
|
if (vec < 0 || vec >= OPENPIC_NUM_VECTORS) \
|
||||||
|
printk("openpic.c:%d: illegal vector %d\n", __LINE__, vec);
|
||||||
|
#define check_arg_pri(pri) \
|
||||||
|
if (pri < 0 || pri >= OPENPIC_NUM_PRI) \
|
||||||
|
printk("openpic.c:%d: illegal priority %d\n", __LINE__, pri);
|
||||||
|
#define check_arg_irq(irq) \
|
||||||
|
if (irq < 0 || irq >= NumSources) \
|
||||||
|
printk("openpic.c:%d: illegal irq %d from %p,[%p],[[%p]]\n", \
|
||||||
|
__LINE__, irq, __builtin_return_address(0), \
|
||||||
|
__builtin_return_address(1), __builtin_return_address(2) \
|
||||||
|
);
|
||||||
|
#define check_arg_cpu(cpu) \
|
||||||
|
if (cpu < 0 || cpu >= NumProcessors) \
|
||||||
|
printk("openpic.c:%d: illegal cpu %d\n", __LINE__, cpu);
|
||||||
|
#else
|
||||||
|
#define check_arg_ipi(ipi) do {} while (0)
|
||||||
|
#define check_arg_timer(timer) do {} while (0)
|
||||||
|
#define check_arg_vec(vec) do {} while (0)
|
||||||
|
#define check_arg_pri(pri) do {} while (0)
|
||||||
|
#define check_arg_irq(irq) do {} while (0)
|
||||||
|
#define check_arg_cpu(cpu) do {} while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* I/O functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
static inline unsigned int openpic_read(volatile unsigned int *addr)
|
||||||
|
{
|
||||||
|
unsigned int val;
|
||||||
|
|
||||||
|
val = ld_le32(addr);
|
||||||
|
#ifdef REGISTER_DEBUG
|
||||||
|
printk("openpic_read(0x%08x) = 0x%08x\n", (unsigned int)addr, val);
|
||||||
|
#endif
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void openpic_write(volatile unsigned int *addr, unsigned int val)
|
||||||
|
{
|
||||||
|
#ifdef REGISTER_DEBUG
|
||||||
|
printk("openpic_write(0x%08x, 0x%08x)\n", (unsigned int)addr, val);
|
||||||
|
#endif
|
||||||
|
out_le32(addr, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline unsigned int openpic_readfield(volatile unsigned int *addr, unsigned int mask)
|
||||||
|
{
|
||||||
|
unsigned int val = openpic_read(addr);
|
||||||
|
return val & mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void openpic_writefield(volatile unsigned int *addr, unsigned int mask,
|
||||||
|
unsigned int field)
|
||||||
|
{
|
||||||
|
unsigned int val = openpic_read(addr);
|
||||||
|
openpic_write(addr, (val & ~mask) | (field & mask));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void openpic_clearfield(volatile unsigned int *addr, unsigned int mask)
|
||||||
|
{
|
||||||
|
openpic_writefield(addr, mask, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void openpic_setfield(volatile unsigned int *addr, unsigned int mask)
|
||||||
|
{
|
||||||
|
openpic_writefield(addr, mask, mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Update a Vector/Priority register in a safe manner. The interrupt will
|
||||||
|
* be disabled.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void openpic_safe_writefield(volatile unsigned int *addr, unsigned int mask,
|
||||||
|
unsigned int field)
|
||||||
|
{
|
||||||
|
openpic_setfield(addr, OPENPIC_MASK);
|
||||||
|
/* wait until it's not in use */
|
||||||
|
while (openpic_read(addr) & OPENPIC_ACTIVITY);
|
||||||
|
openpic_writefield(addr, mask | OPENPIC_MASK, field | OPENPIC_MASK);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -------- Global Operations ---------------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize the OpenPIC
|
||||||
|
*
|
||||||
|
* Add some kludge to use the Motorola Raven OpenPIC which does not
|
||||||
|
* report vendor and device id, and gets the wrong number of interrupts.
|
||||||
|
* (Motorola did a great job on that one!)
|
||||||
|
*/
|
||||||
|
|
||||||
|
void openpic_init(int main_pic)
|
||||||
|
{
|
||||||
|
unsigned int t, i;
|
||||||
|
unsigned int vendorid, devid, stepping, timerfreq;
|
||||||
|
const char *version, *vendor, *device;
|
||||||
|
|
||||||
|
if (!OpenPIC)
|
||||||
|
BSP_panic("No OpenPIC found");
|
||||||
|
|
||||||
|
t = openpic_read(&OpenPIC->Global.Feature_Reporting0);
|
||||||
|
switch (t & OPENPIC_FEATURE_VERSION_MASK) {
|
||||||
|
case 1:
|
||||||
|
version = "1.0";
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
version = "1.2";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
version = "?";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
NumProcessors = ((t & OPENPIC_FEATURE_LAST_PROCESSOR_MASK) >>
|
||||||
|
OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT) + 1;
|
||||||
|
NumSources = ((t & OPENPIC_FEATURE_LAST_SOURCE_MASK) >>
|
||||||
|
OPENPIC_FEATURE_LAST_SOURCE_SHIFT) + 1;
|
||||||
|
t = openpic_read(&OpenPIC->Global.Vendor_Identification);
|
||||||
|
|
||||||
|
vendorid = t & OPENPIC_VENDOR_ID_VENDOR_ID_MASK;
|
||||||
|
devid = (t & OPENPIC_VENDOR_ID_DEVICE_ID_MASK) >>
|
||||||
|
OPENPIC_VENDOR_ID_DEVICE_ID_SHIFT;
|
||||||
|
stepping = (t & OPENPIC_VENDOR_ID_STEPPING_MASK) >>
|
||||||
|
OPENPIC_VENDOR_ID_STEPPING_SHIFT;
|
||||||
|
|
||||||
|
/* Kludge for the Raven */
|
||||||
|
pci_read_config_dword(0, 0, 0, 0, &t);
|
||||||
|
if (t == PCI_VENDOR_ID_MOTOROLA + (PCI_DEVICE_ID_MOTOROLA_RAVEN<<16)) {
|
||||||
|
vendor = "Motorola";
|
||||||
|
device = "Raven";
|
||||||
|
NumSources += 1;
|
||||||
|
} else {
|
||||||
|
switch (vendorid) {
|
||||||
|
case OPENPIC_VENDOR_ID_APPLE:
|
||||||
|
vendor = "Apple";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
vendor = "Unknown";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
switch (devid) {
|
||||||
|
case OPENPIC_DEVICE_ID_APPLE_HYDRA:
|
||||||
|
device = "Hydra";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
device = "Unknown";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printk("OpenPIC Version %s (%d CPUs and %d IRQ sources) at %p\n", version,
|
||||||
|
NumProcessors, NumSources, OpenPIC);
|
||||||
|
|
||||||
|
printk("OpenPIC Vendor %d (%s), Device %d (%s), Stepping %d\n", vendorid,
|
||||||
|
vendor, devid, device, stepping);
|
||||||
|
|
||||||
|
timerfreq = openpic_read(&OpenPIC->Global.Timer_Frequency);
|
||||||
|
printk("OpenPIC timer frequency is ");
|
||||||
|
if (timerfreq)
|
||||||
|
printk("%d Hz\n", timerfreq);
|
||||||
|
else
|
||||||
|
printk("not set\n");
|
||||||
|
|
||||||
|
if ( main_pic )
|
||||||
|
{
|
||||||
|
/* Initialize timer interrupts */
|
||||||
|
for (i = 0; i < OPENPIC_NUM_TIMERS; i++) {
|
||||||
|
/* Disabled, Priority 0 */
|
||||||
|
openpic_inittimer(i, 0, OPENPIC_VEC_TIMER+i);
|
||||||
|
/* No processor */
|
||||||
|
openpic_maptimer(i, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize IPI interrupts */
|
||||||
|
for (i = 0; i < OPENPIC_NUM_IPI; i++) {
|
||||||
|
/* Disabled, Priority 0 */
|
||||||
|
openpic_initipi(i, 0, OPENPIC_VEC_IPI+i);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize external interrupts */
|
||||||
|
/* SIOint (8259 cascade) is special */
|
||||||
|
openpic_initirq(0, 8, OPENPIC_VEC_SOURCE, 1, 1);
|
||||||
|
/* Processor 0 */
|
||||||
|
openpic_mapirq(0, 1<<0);
|
||||||
|
for (i = 1; i < NumSources; i++) {
|
||||||
|
/* Enabled, Priority 8 */
|
||||||
|
openpic_initirq(i, 8, OPENPIC_VEC_SOURCE+i, 0,
|
||||||
|
i < OpenPIC_NumInitSenses ? OpenPIC_InitSenses[i] : 1);
|
||||||
|
/* Processor 0 */
|
||||||
|
openpic_mapirq(i, 1<<0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize the spurious interrupt */
|
||||||
|
openpic_set_spurious(OPENPIC_VEC_SPURIOUS);
|
||||||
|
#if 0
|
||||||
|
if (request_irq(IRQ_8259_CASCADE, no_action, SA_INTERRUPT,
|
||||||
|
"82c59 cascade", NULL))
|
||||||
|
printk("Unable to get OpenPIC IRQ 0 for cascade\n");
|
||||||
|
#endif
|
||||||
|
openpic_set_priority(0, 0);
|
||||||
|
openpic_disable_8259_pass_through();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reset the OpenPIC
|
||||||
|
*/
|
||||||
|
|
||||||
|
void openpic_reset(void)
|
||||||
|
{
|
||||||
|
openpic_setfield(&OpenPIC->Global.Global_Configuration0,
|
||||||
|
OPENPIC_CONFIG_RESET);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enable/disable 8259 Pass Through Mode
|
||||||
|
*/
|
||||||
|
|
||||||
|
void openpic_enable_8259_pass_through(void)
|
||||||
|
{
|
||||||
|
openpic_clearfield(&OpenPIC->Global.Global_Configuration0,
|
||||||
|
OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void openpic_disable_8259_pass_through(void)
|
||||||
|
{
|
||||||
|
openpic_setfield(&OpenPIC->Global.Global_Configuration0,
|
||||||
|
OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find out the current interrupt
|
||||||
|
*/
|
||||||
|
|
||||||
|
unsigned int openpic_irq(unsigned int cpu)
|
||||||
|
{
|
||||||
|
unsigned int vec;
|
||||||
|
|
||||||
|
check_arg_cpu(cpu);
|
||||||
|
vec = openpic_readfield(&OpenPIC->THIS_CPU.Interrupt_Acknowledge,
|
||||||
|
OPENPIC_VECTOR_MASK);
|
||||||
|
return vec;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Signal end of interrupt (EOI) processing
|
||||||
|
*/
|
||||||
|
|
||||||
|
void openpic_eoi(unsigned int cpu)
|
||||||
|
{
|
||||||
|
check_arg_cpu(cpu);
|
||||||
|
openpic_write(&OpenPIC->THIS_CPU.EOI, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get/set the current task priority
|
||||||
|
*/
|
||||||
|
|
||||||
|
unsigned int openpic_get_priority(unsigned int cpu)
|
||||||
|
{
|
||||||
|
CHECK_THIS_CPU;
|
||||||
|
return openpic_readfield(&OpenPIC->THIS_CPU.Current_Task_Priority,
|
||||||
|
OPENPIC_CURRENT_TASK_PRIORITY_MASK);
|
||||||
|
}
|
||||||
|
|
||||||
|
void openpic_set_priority(unsigned int cpu, unsigned int pri)
|
||||||
|
{
|
||||||
|
CHECK_THIS_CPU;
|
||||||
|
check_arg_pri(pri);
|
||||||
|
openpic_writefield(&OpenPIC->THIS_CPU.Current_Task_Priority,
|
||||||
|
OPENPIC_CURRENT_TASK_PRIORITY_MASK, pri);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get/set the spurious vector
|
||||||
|
*/
|
||||||
|
|
||||||
|
unsigned int openpic_get_spurious(void)
|
||||||
|
{
|
||||||
|
return openpic_readfield(&OpenPIC->Global.Spurious_Vector,
|
||||||
|
OPENPIC_VECTOR_MASK);
|
||||||
|
}
|
||||||
|
|
||||||
|
void openpic_set_spurious(unsigned int vec)
|
||||||
|
{
|
||||||
|
check_arg_vec(vec);
|
||||||
|
openpic_writefield(&OpenPIC->Global.Spurious_Vector, OPENPIC_VECTOR_MASK,
|
||||||
|
vec);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize one or more CPUs
|
||||||
|
*/
|
||||||
|
|
||||||
|
void openpic_init_processor(unsigned int cpumask)
|
||||||
|
{
|
||||||
|
openpic_write(&OpenPIC->Global.Processor_Initialization, cpumask);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -------- Interprocessor Interrupts -------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize an interprocessor interrupt (and disable it)
|
||||||
|
*
|
||||||
|
* ipi: OpenPIC interprocessor interrupt number
|
||||||
|
* pri: interrupt source priority
|
||||||
|
* vec: the vector it will produce
|
||||||
|
*/
|
||||||
|
|
||||||
|
void openpic_initipi(unsigned int ipi, unsigned int pri, unsigned int vec)
|
||||||
|
{
|
||||||
|
check_arg_timer(ipi);
|
||||||
|
check_arg_pri(pri);
|
||||||
|
check_arg_vec(vec);
|
||||||
|
openpic_safe_writefield(&OpenPIC->Global.IPI_Vector_Priority(ipi),
|
||||||
|
OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK,
|
||||||
|
(pri << OPENPIC_PRIORITY_SHIFT) | vec);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Send an IPI to one or more CPUs
|
||||||
|
*/
|
||||||
|
|
||||||
|
void openpic_cause_IPI(unsigned int cpu, unsigned int ipi, unsigned int cpumask)
|
||||||
|
{
|
||||||
|
CHECK_THIS_CPU;
|
||||||
|
check_arg_ipi(ipi);
|
||||||
|
openpic_write(&OpenPIC->THIS_CPU.IPI_Dispatch(ipi), cpumask);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -------- Timer Interrupts ----------------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize a timer interrupt (and disable it)
|
||||||
|
*
|
||||||
|
* timer: OpenPIC timer number
|
||||||
|
* pri: interrupt source priority
|
||||||
|
* vec: the vector it will produce
|
||||||
|
*/
|
||||||
|
|
||||||
|
void openpic_inittimer(unsigned int timer, unsigned int pri, unsigned int vec)
|
||||||
|
{
|
||||||
|
check_arg_timer(timer);
|
||||||
|
check_arg_pri(pri);
|
||||||
|
check_arg_vec(vec);
|
||||||
|
openpic_safe_writefield(&OpenPIC->Global.Timer[timer].Vector_Priority,
|
||||||
|
OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK,
|
||||||
|
(pri << OPENPIC_PRIORITY_SHIFT) | vec);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Map a timer interrupt to one or more CPUs
|
||||||
|
*/
|
||||||
|
|
||||||
|
void openpic_maptimer(unsigned int timer, unsigned int cpumask)
|
||||||
|
{
|
||||||
|
check_arg_timer(timer);
|
||||||
|
openpic_write(&OpenPIC->Global.Timer[timer].Destination, cpumask);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -------- Interrupt Sources ---------------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enable/disable an interrupt source
|
||||||
|
*/
|
||||||
|
|
||||||
|
void openpic_enable_irq(unsigned int irq)
|
||||||
|
{
|
||||||
|
check_arg_irq(irq);
|
||||||
|
openpic_clearfield(&OpenPIC->Source[irq].Vector_Priority, OPENPIC_MASK);
|
||||||
|
}
|
||||||
|
|
||||||
|
void openpic_disable_irq(unsigned int irq)
|
||||||
|
{
|
||||||
|
check_arg_irq(irq);
|
||||||
|
openpic_setfield(&OpenPIC->Source[irq].Vector_Priority, OPENPIC_MASK);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize an interrupt source (and disable it!)
|
||||||
|
*
|
||||||
|
* irq: OpenPIC interrupt number
|
||||||
|
* pri: interrupt source priority
|
||||||
|
* vec: the vector it will produce
|
||||||
|
* pol: polarity (1 for positive, 0 for negative)
|
||||||
|
* sense: 1 for level, 0 for edge
|
||||||
|
*/
|
||||||
|
|
||||||
|
void openpic_initirq(unsigned int irq, unsigned int pri, unsigned int vec, int pol, int sense)
|
||||||
|
{
|
||||||
|
check_arg_irq(irq);
|
||||||
|
check_arg_pri(pri);
|
||||||
|
check_arg_vec(vec);
|
||||||
|
openpic_safe_writefield(&OpenPIC->Source[irq].Vector_Priority,
|
||||||
|
OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK |
|
||||||
|
OPENPIC_SENSE_POLARITY | OPENPIC_SENSE_LEVEL,
|
||||||
|
(pri << OPENPIC_PRIORITY_SHIFT) | vec |
|
||||||
|
(pol ? OPENPIC_SENSE_POLARITY : 0) |
|
||||||
|
(sense ? OPENPIC_SENSE_LEVEL : 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Map an interrupt source to one or more CPUs
|
||||||
|
*/
|
||||||
|
|
||||||
|
void openpic_mapirq(unsigned int irq, unsigned int cpumask)
|
||||||
|
{
|
||||||
|
check_arg_irq(irq);
|
||||||
|
openpic_write(&OpenPIC->Source[irq].Destination, cpumask);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the sense for an interrupt source (and disable it!)
|
||||||
|
*
|
||||||
|
* sense: 1 for level, 0 for edge
|
||||||
|
*/
|
||||||
|
|
||||||
|
void openpic_set_sense(unsigned int irq, int sense)
|
||||||
|
{
|
||||||
|
check_arg_irq(irq);
|
||||||
|
openpic_safe_writefield(&OpenPIC->Source[irq].Vector_Priority,
|
||||||
|
OPENPIC_SENSE_LEVEL,
|
||||||
|
(sense ? OPENPIC_SENSE_LEVEL : 0));
|
||||||
|
}
|
||||||
340
c/src/lib/libbsp/powerpc/shared/openpic/openpic.h
Normal file
340
c/src/lib/libbsp/powerpc/shared/openpic/openpic.h
Normal file
@@ -0,0 +1,340 @@
|
|||||||
|
/*
|
||||||
|
* openpic.h -- OpenPIC definitions
|
||||||
|
*
|
||||||
|
* Copyright (C) 1997 Geert Uytterhoeven
|
||||||
|
*
|
||||||
|
* This file is based on the following documentation:
|
||||||
|
*
|
||||||
|
* The Open Programmable Interrupt Controller (PIC)
|
||||||
|
* Register Interface Specification Revision 1.2
|
||||||
|
*
|
||||||
|
* Issue Date: October 1995
|
||||||
|
*
|
||||||
|
* Issued jointly by Advanced Micro Devices and Cyrix Corporation
|
||||||
|
*
|
||||||
|
* AMD is a registered trademark of Advanced Micro Devices, Inc.
|
||||||
|
* Copyright (C) 1995, Advanced Micro Devices, Inc. and Cyrix, Inc.
|
||||||
|
* All Rights Reserved.
|
||||||
|
*
|
||||||
|
* To receive a copy of this documentation, send an email to openpic@amd.com.
|
||||||
|
*
|
||||||
|
* This file is subject to the terms and conditions of the GNU General Public
|
||||||
|
* License. See the file COPYING in the main directory of this archive
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* Modified to compile in RTEMS development environment
|
||||||
|
* by Eric Valette
|
||||||
|
*
|
||||||
|
* Copyright (C) 1999 Eric Valette. valette@crf.canon.fr
|
||||||
|
*
|
||||||
|
* The license and distribution terms for this file may be
|
||||||
|
* found in found in the file LICENSE in this distribution or at
|
||||||
|
* http://www.OARcorp.com/rtems/license.html.
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _RTEMS_OPENPIC_H
|
||||||
|
#define _RTEMS_OPENPIC_H
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* OpenPIC supports up to 2048 interrupt sources and up to 32 processors
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define OPENPIC_MAX_SOURCES 2048
|
||||||
|
#define OPENPIC_MAX_PROCESSORS 32
|
||||||
|
|
||||||
|
#define OPENPIC_NUM_TIMERS 4
|
||||||
|
#define OPENPIC_NUM_IPI 4
|
||||||
|
#define OPENPIC_NUM_PRI 16
|
||||||
|
#define OPENPIC_NUM_VECTORS 256
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Vector numbers
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define OPENPIC_VEC_SOURCE 0x10 /* and up */
|
||||||
|
#define OPENPIC_VEC_TIMER 0x40 /* and up */
|
||||||
|
#define OPENPIC_VEC_IPI 0x50 /* and up */
|
||||||
|
#define OPENPIC_VEC_SPURIOUS 99
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* OpenPIC Registers are 32 bits and aligned on 128 bit boundaries
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct _OpenPIC_Reg {
|
||||||
|
unsigned int Reg; /* Little endian! */
|
||||||
|
char Pad[0xc];
|
||||||
|
} OpenPIC_Reg;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Per Processor Registers
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct _OpenPIC_Processor {
|
||||||
|
/*
|
||||||
|
* Private Shadow Registers (for SLiC backwards compatibility)
|
||||||
|
*/
|
||||||
|
unsigned int IPI0_Dispatch_Shadow; /* Write Only */
|
||||||
|
char Pad1[0x4];
|
||||||
|
unsigned int IPI0_Vector_Priority_Shadow; /* Read/Write */
|
||||||
|
char Pad2[0x34];
|
||||||
|
/*
|
||||||
|
* Interprocessor Interrupt Command Ports
|
||||||
|
*/
|
||||||
|
OpenPIC_Reg _IPI_Dispatch[OPENPIC_NUM_IPI]; /* Write Only */
|
||||||
|
/*
|
||||||
|
* Current Task Priority Register
|
||||||
|
*/
|
||||||
|
OpenPIC_Reg _Current_Task_Priority; /* Read/Write */
|
||||||
|
char Pad3[0x10];
|
||||||
|
/*
|
||||||
|
* Interrupt Acknowledge Register
|
||||||
|
*/
|
||||||
|
OpenPIC_Reg _Interrupt_Acknowledge; /* Read Only */
|
||||||
|
/*
|
||||||
|
* End of Interrupt (EOI) Register
|
||||||
|
*/
|
||||||
|
OpenPIC_Reg _EOI; /* Read/Write */
|
||||||
|
char Pad5[0xf40];
|
||||||
|
} OpenPIC_Processor;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Timer Registers
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct _OpenPIC_Timer {
|
||||||
|
OpenPIC_Reg _Current_Count; /* Read Only */
|
||||||
|
OpenPIC_Reg _Base_Count; /* Read/Write */
|
||||||
|
OpenPIC_Reg _Vector_Priority; /* Read/Write */
|
||||||
|
OpenPIC_Reg _Destination; /* Read/Write */
|
||||||
|
} OpenPIC_Timer;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Global Registers
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct _OpenPIC_Global {
|
||||||
|
/*
|
||||||
|
* Feature Reporting Registers
|
||||||
|
*/
|
||||||
|
OpenPIC_Reg _Feature_Reporting0; /* Read Only */
|
||||||
|
OpenPIC_Reg _Feature_Reporting1; /* Future Expansion */
|
||||||
|
/*
|
||||||
|
* Global Configuration Registers
|
||||||
|
*/
|
||||||
|
OpenPIC_Reg _Global_Configuration0; /* Read/Write */
|
||||||
|
OpenPIC_Reg _Global_Configuration1; /* Future Expansion */
|
||||||
|
/*
|
||||||
|
* Vendor Specific Registers
|
||||||
|
*/
|
||||||
|
OpenPIC_Reg _Vendor_Specific[4];
|
||||||
|
/*
|
||||||
|
* Vendor Identification Register
|
||||||
|
*/
|
||||||
|
OpenPIC_Reg _Vendor_Identification; /* Read Only */
|
||||||
|
/*
|
||||||
|
* Processor Initialization Register
|
||||||
|
*/
|
||||||
|
OpenPIC_Reg _Processor_Initialization; /* Read/Write */
|
||||||
|
/*
|
||||||
|
* IPI Vector/Priority Registers
|
||||||
|
*/
|
||||||
|
OpenPIC_Reg _IPI_Vector_Priority[OPENPIC_NUM_IPI]; /* Read/Write */
|
||||||
|
/*
|
||||||
|
* Spurious Vector Register
|
||||||
|
*/
|
||||||
|
OpenPIC_Reg _Spurious_Vector; /* Read/Write */
|
||||||
|
/*
|
||||||
|
* Global Timer Registers
|
||||||
|
*/
|
||||||
|
OpenPIC_Reg _Timer_Frequency; /* Read/Write */
|
||||||
|
OpenPIC_Timer Timer[OPENPIC_NUM_TIMERS];
|
||||||
|
char Pad1[0xee00];
|
||||||
|
} OpenPIC_Global;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Interrupt Source Registers
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct _OpenPIC_Source {
|
||||||
|
OpenPIC_Reg _Vector_Priority; /* Read/Write */
|
||||||
|
OpenPIC_Reg _Destination; /* Read/Write */
|
||||||
|
} OpenPIC_Source;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* OpenPIC Register Map
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct OpenPIC {
|
||||||
|
char Pad1[0x1000];
|
||||||
|
/*
|
||||||
|
* Global Registers
|
||||||
|
*/
|
||||||
|
OpenPIC_Global Global;
|
||||||
|
/*
|
||||||
|
* Interrupt Source Configuration Registers
|
||||||
|
*/
|
||||||
|
OpenPIC_Source Source[OPENPIC_MAX_SOURCES];
|
||||||
|
/*
|
||||||
|
* Per Processor Registers
|
||||||
|
*/
|
||||||
|
OpenPIC_Processor Processor[OPENPIC_MAX_PROCESSORS];
|
||||||
|
};
|
||||||
|
|
||||||
|
extern volatile struct OpenPIC *OpenPIC;
|
||||||
|
extern unsigned int OpenPIC_NumInitSenses;
|
||||||
|
extern unsigned char *OpenPIC_InitSenses;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Current Task Priority Register
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define OPENPIC_CURRENT_TASK_PRIORITY_MASK 0x0000000f
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Who Am I Register
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define OPENPIC_WHO_AM_I_ID_MASK 0x0000001f
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Feature Reporting Register 0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define OPENPIC_FEATURE_LAST_SOURCE_MASK 0x07ff0000
|
||||||
|
#define OPENPIC_FEATURE_LAST_SOURCE_SHIFT 16
|
||||||
|
#define OPENPIC_FEATURE_LAST_PROCESSOR_MASK 0x00001f00
|
||||||
|
#define OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT 8
|
||||||
|
#define OPENPIC_FEATURE_VERSION_MASK 0x000000ff
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Global Configuration Register 0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define OPENPIC_CONFIG_RESET 0x80000000
|
||||||
|
#define OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE 0x20000000
|
||||||
|
#define OPENPIC_CONFIG_BASE_MASK 0x000fffff
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Vendor Identification Register
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define OPENPIC_VENDOR_ID_STEPPING_MASK 0x00ff0000
|
||||||
|
#define OPENPIC_VENDOR_ID_STEPPING_SHIFT 16
|
||||||
|
#define OPENPIC_VENDOR_ID_DEVICE_ID_MASK 0x0000ff00
|
||||||
|
#define OPENPIC_VENDOR_ID_DEVICE_ID_SHIFT 8
|
||||||
|
#define OPENPIC_VENDOR_ID_VENDOR_ID_MASK 0x000000ff
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Vector/Priority Registers
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define OPENPIC_MASK 0x80000000
|
||||||
|
#define OPENPIC_ACTIVITY 0x40000000 /* Read Only */
|
||||||
|
#define OPENPIC_PRIORITY_MASK 0x000f0000
|
||||||
|
#define OPENPIC_PRIORITY_SHIFT 16
|
||||||
|
#define OPENPIC_VECTOR_MASK 0x000000ff
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Interrupt Source Registers
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define OPENPIC_SENSE_POLARITY 0x00800000 /* Undoc'd */
|
||||||
|
#define OPENPIC_SENSE_LEVEL 0x00400000
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Timer Registers
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define OPENPIC_COUNT_MASK 0x7fffffff
|
||||||
|
#define OPENPIC_TIMER_TOGGLE 0x80000000
|
||||||
|
#define OPENPIC_TIMER_COUNT_INHIBIT 0x80000000
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Aliases to make life simpler
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Per Processor Registers */
|
||||||
|
#define IPI_Dispatch(i) _IPI_Dispatch[i].Reg
|
||||||
|
#define Current_Task_Priority _Current_Task_Priority.Reg
|
||||||
|
#define Interrupt_Acknowledge _Interrupt_Acknowledge.Reg
|
||||||
|
#define EOI _EOI.Reg
|
||||||
|
|
||||||
|
/* Global Registers */
|
||||||
|
#define Feature_Reporting0 _Feature_Reporting0.Reg
|
||||||
|
#define Feature_Reporting1 _Feature_Reporting1.Reg
|
||||||
|
#define Global_Configuration0 _Global_Configuration0.Reg
|
||||||
|
#define Global_Configuration1 _Global_Configuration1.Reg
|
||||||
|
#define Vendor_Specific(i) _Vendor_Specific[i].Reg
|
||||||
|
#define Vendor_Identification _Vendor_Identification.Reg
|
||||||
|
#define Processor_Initialization _Processor_Initialization.Reg
|
||||||
|
#define IPI_Vector_Priority(i) _IPI_Vector_Priority[i].Reg
|
||||||
|
#define Spurious_Vector _Spurious_Vector.Reg
|
||||||
|
#define Timer_Frequency _Timer_Frequency.Reg
|
||||||
|
|
||||||
|
/* Timer Registers */
|
||||||
|
#define Current_Count _Current_Count.Reg
|
||||||
|
#define Base_Count _Base_Count.Reg
|
||||||
|
#define Vector_Priority _Vector_Priority.Reg
|
||||||
|
#define Destination _Destination.Reg
|
||||||
|
|
||||||
|
/* Interrupt Source Registers */
|
||||||
|
#define Vector_Priority _Vector_Priority.Reg
|
||||||
|
#define Destination _Destination.Reg
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Vendor and Device IDs
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define OPENPIC_VENDOR_ID_APPLE 0x14
|
||||||
|
#define OPENPIC_DEVICE_ID_APPLE_HYDRA 0x46
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* OpenPIC Operations
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Global Operations */
|
||||||
|
extern void openpic_init(int);
|
||||||
|
extern void openpic_reset(void);
|
||||||
|
extern void openpic_enable_8259_pass_through(void);
|
||||||
|
extern void openpic_disable_8259_pass_through(void);
|
||||||
|
extern unsigned int openpic_irq(unsigned int cpu);
|
||||||
|
extern void openpic_eoi(unsigned int cpu);
|
||||||
|
extern unsigned int openpic_get_priority(unsigned int cpu);
|
||||||
|
extern void openpic_set_priority(unsigned int cpu, unsigned int pri);
|
||||||
|
extern unsigned int openpic_get_spurious(void);
|
||||||
|
extern void openpic_set_spurious(unsigned int vector);
|
||||||
|
extern void openpic_init_processor(unsigned int cpumask);
|
||||||
|
|
||||||
|
/* Interprocessor Interrupts */
|
||||||
|
extern void openpic_initipi(unsigned int ipi, unsigned int pri, unsigned int vector);
|
||||||
|
extern void openpic_cause_IPI(unsigned int cpu, unsigned int ipi, unsigned int cpumask);
|
||||||
|
|
||||||
|
/* Timer Interrupts */
|
||||||
|
extern void openpic_inittimer(unsigned int timer, unsigned int pri, unsigned int vector);
|
||||||
|
extern void openpic_maptimer(unsigned int timer, unsigned int cpumask);
|
||||||
|
|
||||||
|
/* Interrupt Sources */
|
||||||
|
extern void openpic_enable_irq(unsigned int irq);
|
||||||
|
extern void openpic_disable_irq(unsigned int irq);
|
||||||
|
extern void openpic_initirq(unsigned int irq, unsigned int pri, unsigned int vector, int polarity,
|
||||||
|
int is_level);
|
||||||
|
extern void openpic_mapirq(unsigned int irq, unsigned int cpumask);
|
||||||
|
extern void openpic_set_sense(unsigned int irq, int sense);
|
||||||
|
|
||||||
|
#endif /* RTEMS_OPENPIC_H */
|
||||||
42
c/src/lib/libbsp/powerpc/shared/pci/Makefile.in
Normal file
42
c/src/lib/libbsp/powerpc/shared/pci/Makefile.in
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
#
|
||||||
|
# $Id$
|
||||||
|
#
|
||||||
|
|
||||||
|
@SET_MAKE@
|
||||||
|
srcdir = @srcdir@
|
||||||
|
top_srcdir = @top_srcdir@
|
||||||
|
top_builddir = ../../..
|
||||||
|
subdir = powerpc/shared/pci
|
||||||
|
|
||||||
|
RTEMS_ROOT = @RTEMS_ROOT@
|
||||||
|
PROJECT_ROOT = @PROJECT_ROOT@
|
||||||
|
|
||||||
|
VPATH = @srcdir@
|
||||||
|
|
||||||
|
H_FILES = $(srcdir)/pci.h
|
||||||
|
|
||||||
|
SRCS = $(C_FILES) $(H_FILES)
|
||||||
|
|
||||||
|
include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
|
||||||
|
include $(RTEMS_ROOT)/make/leaf.cfg
|
||||||
|
|
||||||
|
INSTALL_CHANGE = @INSTALL_CHANGE@
|
||||||
|
mkinstalldirs = $(SHELL) $(top_srcdir)/@RTEMS_TOPdir@/mkinstalldirs
|
||||||
|
|
||||||
|
INSTALLDIRS = $(PROJECT_INCLUDE)/bsp
|
||||||
|
|
||||||
|
$(INSTALLDIRS):
|
||||||
|
@$(mkinstalldirs) $(INSTALLDIRS)
|
||||||
|
|
||||||
|
preinstall:
|
||||||
|
@$(mkinstalldirs) $(PROJECT_INCLUDE)/bsp
|
||||||
|
@$(INSTALL_CHANGE) -m 644 $(H_FILES) $(PROJECT_INCLUDE)/bsp
|
||||||
|
|
||||||
|
all: ${ARCH} $(SRCS) preinstall
|
||||||
|
|
||||||
|
# the .rel file built here will be put into libbsp.a by ../wrapup/Makefile
|
||||||
|
install: all
|
||||||
|
|
||||||
|
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||||
|
cd $(top_builddir) \
|
||||||
|
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
|
||||||
388
c/src/lib/libbsp/powerpc/shared/pci/pci.c
Normal file
388
c/src/lib/libbsp/powerpc/shared/pci/pci.c
Normal file
@@ -0,0 +1,388 @@
|
|||||||
|
/*
|
||||||
|
* pci.c : this file contains basic PCI Io functions.
|
||||||
|
*
|
||||||
|
* CopyRight (C) 1999 valette@crf.canon.fr
|
||||||
|
*
|
||||||
|
* This code is heavilly inspired by the public specification of STREAM V2
|
||||||
|
* that can be found at :
|
||||||
|
*
|
||||||
|
* <http://www.chorus.com/Documentation/index.html> by following
|
||||||
|
* the STREAM API Specification Document link.
|
||||||
|
*
|
||||||
|
* The license and distribution terms for this file may be
|
||||||
|
* found in found in the file LICENSE in this distribution or at
|
||||||
|
* http://www.OARcorp.com/rtems/license.html.
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <bsp/consoleIo.h>
|
||||||
|
#include <libcpu/io.h>
|
||||||
|
#include <bsp/pci.h>
|
||||||
|
#include <bsp/residual.h>
|
||||||
|
#include <bsp/openpic.h>
|
||||||
|
#include <bsp.h>
|
||||||
|
|
||||||
|
#define PCI_CONFIG_ADDR 0xcf8
|
||||||
|
#define PCI_CONFIG_DATA 0xcfc
|
||||||
|
#define PCI_INVALID_VENDORDEVICEID 0xffffffff
|
||||||
|
#define PCI_MULTI_FUNCTION 0x80
|
||||||
|
#define RAVEN_MPIC_IOSPACE_ENABLE 0x1
|
||||||
|
#define RAVEN_MPIC_MEMSPACE_ENABLE 0x2
|
||||||
|
#define RAVEN_MASTER_ENABLE 0x4
|
||||||
|
#define RAVEN_PARITY_CHECK_ENABLE 0x40
|
||||||
|
#define RAVEN_SYSTEM_ERROR_ENABLE 0x100
|
||||||
|
#define RAVEN_CLEAR_EVENTS_MASK 0xf9000000
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Bit encode for PCI_CONFIG_HEADER_TYPE register
|
||||||
|
*/
|
||||||
|
unsigned char ucMaxPCIBus;
|
||||||
|
|
||||||
|
static int
|
||||||
|
indirect_pci_read_config_byte(unsigned char bus, unsigned char slot,
|
||||||
|
unsigned char function,
|
||||||
|
unsigned char offset, unsigned char *val) {
|
||||||
|
out_be32((unsigned int*) pci.pci_config_addr,
|
||||||
|
0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|((offset&~3)<<24));
|
||||||
|
*val = in_8(pci.pci_config_data + (offset&3));
|
||||||
|
return PCIBIOS_SUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
indirect_pci_read_config_word(unsigned char bus, unsigned char slot,
|
||||||
|
unsigned char function,
|
||||||
|
unsigned char offset, unsigned short *val) {
|
||||||
|
*val = 0xffff;
|
||||||
|
if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
|
||||||
|
out_be32((unsigned int*) pci.pci_config_addr,
|
||||||
|
0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|((offset&~3)<<24));
|
||||||
|
*val = in_le16((volatile unsigned short *)(pci.pci_config_data + (offset&3)));
|
||||||
|
return PCIBIOS_SUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
indirect_pci_read_config_dword(unsigned char bus, unsigned char slot,
|
||||||
|
unsigned char function,
|
||||||
|
unsigned char offset, unsigned int *val) {
|
||||||
|
*val = 0xffffffff;
|
||||||
|
if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
|
||||||
|
out_be32((unsigned int*) pci.pci_config_addr,
|
||||||
|
0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|(offset<<24));
|
||||||
|
*val = in_le32((volatile unsigned int *)pci.pci_config_data);
|
||||||
|
return PCIBIOS_SUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
indirect_pci_write_config_byte(unsigned char bus, unsigned char slot,
|
||||||
|
unsigned char function,
|
||||||
|
unsigned char offset, unsigned char val) {
|
||||||
|
out_be32((unsigned int*) pci.pci_config_addr,
|
||||||
|
0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|((offset&~3)<<24));
|
||||||
|
out_8(pci.pci_config_data + (offset&3), val);
|
||||||
|
return PCIBIOS_SUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
indirect_pci_write_config_word(unsigned char bus, unsigned char slot,
|
||||||
|
unsigned char function,
|
||||||
|
unsigned char offset, unsigned short val) {
|
||||||
|
if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
|
||||||
|
out_be32((unsigned int*) pci.pci_config_addr,
|
||||||
|
0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|((offset&~3)<<24));
|
||||||
|
out_le16((volatile unsigned short *)(pci.pci_config_data + (offset&3)), val);
|
||||||
|
return PCIBIOS_SUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
indirect_pci_write_config_dword(unsigned char bus, unsigned char slot,
|
||||||
|
unsigned char function,
|
||||||
|
unsigned char offset, unsigned int val) {
|
||||||
|
if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
|
||||||
|
out_be32((unsigned int*) pci.pci_config_addr,
|
||||||
|
0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|(offset<<24));
|
||||||
|
out_le32((volatile unsigned int *)pci.pci_config_data, val);
|
||||||
|
return PCIBIOS_SUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const pci_config_access_functions indirect_functions = {
|
||||||
|
indirect_pci_read_config_byte,
|
||||||
|
indirect_pci_read_config_word,
|
||||||
|
indirect_pci_read_config_dword,
|
||||||
|
indirect_pci_write_config_byte,
|
||||||
|
indirect_pci_write_config_word,
|
||||||
|
indirect_pci_write_config_dword
|
||||||
|
};
|
||||||
|
|
||||||
|
pci_config pci = {(volatile unsigned char*)PCI_CONFIG_ADDR,
|
||||||
|
(volatile unsigned char*)PCI_CONFIG_DATA,
|
||||||
|
&indirect_functions};
|
||||||
|
|
||||||
|
static int
|
||||||
|
direct_pci_read_config_byte(unsigned char bus, unsigned char slot,
|
||||||
|
unsigned char function,
|
||||||
|
unsigned char offset, unsigned char *val) {
|
||||||
|
if (bus != 0 || (1<<slot & 0xff8007fe)) {
|
||||||
|
*val=0xff;
|
||||||
|
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||||
|
}
|
||||||
|
*val=in_8(pci.pci_config_data + ((1<<slot)&~1)
|
||||||
|
+ (function<<8) + offset);
|
||||||
|
return PCIBIOS_SUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
direct_pci_read_config_word(unsigned char bus, unsigned char slot,
|
||||||
|
unsigned char function,
|
||||||
|
unsigned char offset, unsigned short *val) {
|
||||||
|
*val = 0xffff;
|
||||||
|
if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
|
||||||
|
if (bus != 0 || (1<<slot & 0xff8007fe)) {
|
||||||
|
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||||
|
}
|
||||||
|
*val=in_le16((volatile unsigned short *)
|
||||||
|
(pci.pci_config_data + ((1<<slot)&~1)
|
||||||
|
+ (function<<8) + offset));
|
||||||
|
return PCIBIOS_SUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
direct_pci_read_config_dword(unsigned char bus, unsigned char slot,
|
||||||
|
unsigned char function,
|
||||||
|
unsigned char offset, unsigned int *val) {
|
||||||
|
*val = 0xffffffff;
|
||||||
|
if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
|
||||||
|
if (bus != 0 || (1<<slot & 0xff8007fe)) {
|
||||||
|
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||||
|
}
|
||||||
|
*val=in_le32((volatile unsigned int *)
|
||||||
|
(pci.pci_config_data + ((1<<slot)&~1)
|
||||||
|
+ (function<<8) + offset));
|
||||||
|
return PCIBIOS_SUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
direct_pci_write_config_byte(unsigned char bus, unsigned char slot,
|
||||||
|
unsigned char function,
|
||||||
|
unsigned char offset, unsigned char val) {
|
||||||
|
if (bus != 0 || (1<<slot & 0xff8007fe)) {
|
||||||
|
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||||
|
}
|
||||||
|
out_8(pci.pci_config_data + ((1<<slot)&~1)
|
||||||
|
+ (function<<8) + offset,
|
||||||
|
val);
|
||||||
|
return PCIBIOS_SUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
direct_pci_write_config_word(unsigned char bus, unsigned char slot,
|
||||||
|
unsigned char function,
|
||||||
|
unsigned char offset, unsigned short val) {
|
||||||
|
if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
|
||||||
|
if (bus != 0 || (1<<slot & 0xff8007fe)) {
|
||||||
|
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||||
|
}
|
||||||
|
out_le16((volatile unsigned short *)
|
||||||
|
(pci.pci_config_data + ((1<<slot)&~1)
|
||||||
|
+ (function<<8) + offset),
|
||||||
|
val);
|
||||||
|
return PCIBIOS_SUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
direct_pci_write_config_dword(unsigned char bus, unsigned char slot,
|
||||||
|
unsigned char function,
|
||||||
|
unsigned char offset, unsigned int val) {
|
||||||
|
if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
|
||||||
|
if (bus != 0 || (1<<slot & 0xff8007fe)) {
|
||||||
|
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||||
|
}
|
||||||
|
out_le32((volatile unsigned int *)
|
||||||
|
(pci.pci_config_data + ((1<<slot)&~1)
|
||||||
|
+ (function<<8) + offset),
|
||||||
|
val);
|
||||||
|
return PCIBIOS_SUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const pci_config_access_functions direct_functions = {
|
||||||
|
direct_pci_read_config_byte,
|
||||||
|
direct_pci_read_config_word,
|
||||||
|
direct_pci_read_config_dword,
|
||||||
|
direct_pci_write_config_byte,
|
||||||
|
direct_pci_write_config_word,
|
||||||
|
direct_pci_write_config_dword
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void detect_host_bridge()
|
||||||
|
{
|
||||||
|
PPC_DEVICE *hostbridge;
|
||||||
|
unsigned int id0;
|
||||||
|
unsigned int tmp;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This code assumes that the host bridge is located at
|
||||||
|
* bus 0, dev 0, func 0 AND that the old pre PCI 2.1
|
||||||
|
* standart devices detection mecahnism that was used on PC
|
||||||
|
* (still used in BSD source code) works.
|
||||||
|
*/
|
||||||
|
hostbridge=residual_find_device(&residualCopy, PROCESSORDEVICE, NULL,
|
||||||
|
BridgeController,
|
||||||
|
PCIBridge, -1, 0);
|
||||||
|
if (hostbridge) {
|
||||||
|
if (hostbridge->DeviceId.Interface==PCIBridgeIndirect) {
|
||||||
|
pci.pci_functions=&indirect_functions;
|
||||||
|
/* Should be extracted from residual data,
|
||||||
|
* indeed MPC106 in CHRP mode is different,
|
||||||
|
* but we should not use residual data in
|
||||||
|
* this case anyway.
|
||||||
|
*/
|
||||||
|
pci.pci_config_addr = ((volatile unsigned char *)
|
||||||
|
(ptr_mem_map->io_base+0xcf8));
|
||||||
|
pci.pci_config_data = ptr_mem_map->io_base+0xcfc;
|
||||||
|
} else if(hostbridge->DeviceId.Interface==PCIBridgeDirect) {
|
||||||
|
pci.pci_functions=&direct_functions;
|
||||||
|
pci.pci_config_data=(unsigned char *) 0x80800000;
|
||||||
|
} else {
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Let us try by experimentation at our own risk! */
|
||||||
|
pci.pci_functions = &direct_functions;
|
||||||
|
/* On all direct bridges I know the host bridge itself
|
||||||
|
* appears as device 0 function 0.
|
||||||
|
*/
|
||||||
|
pci_read_config_dword(0, 0, 0, PCI_VENDOR_ID, &id0);
|
||||||
|
if (id0==~0U) {
|
||||||
|
pci.pci_functions = &indirect_functions;
|
||||||
|
pci.pci_config_addr = ((volatile unsigned char*)
|
||||||
|
(ptr_mem_map->io_base+0xcf8));
|
||||||
|
pci.pci_config_data = ((volatile unsigned char*)ptr_mem_map->io_base+0xcfc);
|
||||||
|
}
|
||||||
|
/* Here we should check that the host bridge is actually
|
||||||
|
* present, but if it not, we are in such a desperate
|
||||||
|
* situation, that we probably can't even tell it.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
pci_read_config_dword(0, 0, 0, 0, &id0);
|
||||||
|
if(id0 == PCI_VENDOR_ID_MOTOROLA +
|
||||||
|
(PCI_DEVICE_ID_MOTOROLA_RAVEN<<16)) {
|
||||||
|
/*
|
||||||
|
* We have a Raven bridge. We will get information about its settings
|
||||||
|
*/
|
||||||
|
pci_read_config_dword(0, 0, 0, PCI_COMMAND, &id0);
|
||||||
|
#ifdef SHOW_RAVEN_SETTING
|
||||||
|
printk("RAVEN PCI command register = %x\n",id0);
|
||||||
|
#endif
|
||||||
|
id0 |= RAVEN_CLEAR_EVENTS_MASK;
|
||||||
|
pci_write_config_dword(0, 0, 0, PCI_COMMAND, id0);
|
||||||
|
pci_read_config_dword(0, 0, 0, PCI_COMMAND, &id0);
|
||||||
|
#ifdef SHOW_RAVEN_SETTING
|
||||||
|
printk("After error clearing RAVEN PCI command register = %x\n",id0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (id0 & RAVEN_MPIC_IOSPACE_ENABLE) {
|
||||||
|
pci_read_config_dword(0, 0, 0,PCI_BASE_ADDRESS_0, &tmp);
|
||||||
|
#ifdef SHOW_RAVEN_SETTING
|
||||||
|
printk("Raven MPIC is accessed via IO Space Access at address : %x\n",(tmp & ~0x1));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
if (id0 & RAVEN_MPIC_MEMSPACE_ENABLE) {
|
||||||
|
pci_read_config_dword(0, 0, 0,PCI_BASE_ADDRESS_1, &tmp);
|
||||||
|
#ifdef SHOW_RAVEN_SETTING
|
||||||
|
printk("Raven MPIC is accessed via memory Space Access at address : %x\n", tmp);
|
||||||
|
#endif
|
||||||
|
OpenPIC=(volatile struct OpenPIC *) (tmp + PREP_ISA_MEM_BASE);
|
||||||
|
printk("OpenPIC found at %p.\n",
|
||||||
|
OpenPIC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (OpenPIC == (volatile struct OpenPIC *)0) {
|
||||||
|
BSP_panic("OpenPic Not found\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This routine determines the maximum bus number in the system
|
||||||
|
*/
|
||||||
|
void InitializePCI()
|
||||||
|
{
|
||||||
|
unsigned char ucSlotNumber, ucFnNumber, ucNumFuncs;
|
||||||
|
unsigned char ucHeader;
|
||||||
|
unsigned char ucMaxSubordinate;
|
||||||
|
unsigned int ulClass, ulDeviceID;
|
||||||
|
|
||||||
|
detect_host_bridge();
|
||||||
|
/*
|
||||||
|
* Scan PCI bus 0 looking for PCI-PCI bridges
|
||||||
|
*/
|
||||||
|
for(ucSlotNumber=0;ucSlotNumber<PCI_MAX_DEVICES;ucSlotNumber++) {
|
||||||
|
(void)pci_read_config_dword(0,
|
||||||
|
ucSlotNumber,
|
||||||
|
0,
|
||||||
|
PCI_VENDOR_ID,
|
||||||
|
&ulDeviceID);
|
||||||
|
if(ulDeviceID==PCI_INVALID_VENDORDEVICEID) {
|
||||||
|
/*
|
||||||
|
* This slot is empty
|
||||||
|
*/
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
(void)pci_read_config_byte(0,
|
||||||
|
ucSlotNumber,
|
||||||
|
0,
|
||||||
|
PCI_HEADER_TYPE,
|
||||||
|
&ucHeader);
|
||||||
|
if(ucHeader&PCI_MULTI_FUNCTION) {
|
||||||
|
ucNumFuncs=PCI_MAX_FUNCTIONS;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ucNumFuncs=1;
|
||||||
|
}
|
||||||
|
for(ucFnNumber=0;ucFnNumber<ucNumFuncs;ucFnNumber++) {
|
||||||
|
(void)pci_read_config_dword(0,
|
||||||
|
ucSlotNumber,
|
||||||
|
ucFnNumber,
|
||||||
|
PCI_VENDOR_ID,
|
||||||
|
&ulDeviceID);
|
||||||
|
if(ulDeviceID==PCI_INVALID_VENDORDEVICEID) {
|
||||||
|
/*
|
||||||
|
* This slot/function is empty
|
||||||
|
*/
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This slot/function has a device fitted.
|
||||||
|
*/
|
||||||
|
(void)pci_read_config_dword(0,
|
||||||
|
ucSlotNumber,
|
||||||
|
ucFnNumber,
|
||||||
|
PCI_CLASS_REVISION,
|
||||||
|
&ulClass);
|
||||||
|
ulClass >>= 16;
|
||||||
|
if (ulClass == PCI_CLASS_BRIDGE_PCI) {
|
||||||
|
/*
|
||||||
|
* We have found a PCI-PCI bridge
|
||||||
|
*/
|
||||||
|
(void)pci_read_config_byte(0,
|
||||||
|
ucSlotNumber,
|
||||||
|
ucFnNumber,
|
||||||
|
PCI_SUBORDINATE_BUS,
|
||||||
|
&ucMaxSubordinate);
|
||||||
|
if(ucMaxSubordinate>ucMaxPCIBus) {
|
||||||
|
ucMaxPCIBus=ucMaxSubordinate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return the number of PCI busses in the system
|
||||||
|
*/
|
||||||
|
unsigned char BusCountPCI()
|
||||||
|
{
|
||||||
|
return(ucMaxPCIBus+1);
|
||||||
|
}
|
||||||
1153
c/src/lib/libbsp/powerpc/shared/pci/pci.h
Normal file
1153
c/src/lib/libbsp/powerpc/shared/pci/pci.h
Normal file
File diff suppressed because it is too large
Load Diff
50
c/src/lib/libbsp/powerpc/shared/residual/Makefile.in
Normal file
50
c/src/lib/libbsp/powerpc/shared/residual/Makefile.in
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
#
|
||||||
|
# $Id$
|
||||||
|
#
|
||||||
|
|
||||||
|
@SET_MAKE@
|
||||||
|
srcdir = @srcdir@
|
||||||
|
top_srcdir = @top_srcdir@
|
||||||
|
top_builddir = ../../..
|
||||||
|
subdir = powerpc/shared/residual
|
||||||
|
|
||||||
|
RTEMS_ROOT = @RTEMS_ROOT@
|
||||||
|
PROJECT_ROOT = @PROJECT_ROOT@
|
||||||
|
|
||||||
|
VPATH = @srcdir@
|
||||||
|
|
||||||
|
PGM = ${ARCH}/residual.rel
|
||||||
|
|
||||||
|
# C source names, if any, go here -- minus the .c
|
||||||
|
C_PIECES = $(RESIDUAL_C_PIECES)
|
||||||
|
C_FILES = $(C_PIECES:%=%.c)
|
||||||
|
C_O_FILES = $(C_PIECES:%=${ARCH}/%.o)
|
||||||
|
|
||||||
|
H_FILES = $(srcdir)/pnp.h $(srcdir)/residual.h
|
||||||
|
|
||||||
|
SRCS = $(C_FILES) $(H_FILES)
|
||||||
|
OBJS = $(C_O_FILES)
|
||||||
|
|
||||||
|
include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
|
||||||
|
include $(RTEMS_ROOT)/make/leaf.cfg
|
||||||
|
|
||||||
|
INSTALL_CHANGE = @INSTALL_CHANGE@
|
||||||
|
mkinstalldirs = $(SHELL) $(top_srcdir)/@RTEMS_TOPdir@/mkinstalldirs
|
||||||
|
|
||||||
|
INSTALLDIRS = $(PROJECT_INCLUDE)/bsp
|
||||||
|
|
||||||
|
$(INSTALLDIRS):
|
||||||
|
@$(mkinstalldirs) $(INSTALLDIRS)
|
||||||
|
|
||||||
|
preinstall:
|
||||||
|
@$(mkinstalldirs) $(PROJECT_INCLUDE)/bsp
|
||||||
|
@$(INSTALL_CHANGE) -m 644 $(H_FILES) $(PROJECT_INCLUDE)/bsp
|
||||||
|
|
||||||
|
all: ${ARCH} $(SRCS) preinstall
|
||||||
|
|
||||||
|
# the .rel file built here will be put into libbsp.a by ../wrapup/Makefile
|
||||||
|
install: all
|
||||||
|
|
||||||
|
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||||
|
cd $(top_builddir) \
|
||||||
|
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
|
||||||
647
c/src/lib/libbsp/powerpc/shared/residual/pnp.h
Normal file
647
c/src/lib/libbsp/powerpc/shared/residual/pnp.h
Normal file
@@ -0,0 +1,647 @@
|
|||||||
|
/* 11/02/95 */
|
||||||
|
/*----------------------------------------------------------------------------*/
|
||||||
|
/* Plug and Play header definitions */
|
||||||
|
/*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Structure map for PnP on PowerPC Reference Platform */
|
||||||
|
/* See Plug and Play ISA Specification, Version 1.0, May 28, 1993. It */
|
||||||
|
/* (or later versions) is available on Compuserve in the PLUGPLAY area. */
|
||||||
|
/* This code has extensions to that specification, namely new short and */
|
||||||
|
/* long tag types for platform dependent information */
|
||||||
|
|
||||||
|
/* Warning: LE notation used throughout this file */
|
||||||
|
|
||||||
|
/* For enum's: if given in hex then they are bit significant, i.e. */
|
||||||
|
/* only one bit is on for each enum */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _PNP_
|
||||||
|
#define _PNP_
|
||||||
|
|
||||||
|
#ifndef ASM
|
||||||
|
#define MAX_MEM_REGISTERS 9
|
||||||
|
#define MAX_IO_PORTS 20
|
||||||
|
#define MAX_IRQS 7
|
||||||
|
/*#define MAX_DMA_CHANNELS 7*/
|
||||||
|
|
||||||
|
/* Interrupt controllers */
|
||||||
|
|
||||||
|
#define PNPinterrupt0 "PNP0000" /* AT Interrupt Controller */
|
||||||
|
#define PNPinterrupt1 "PNP0001" /* EISA Interrupt Controller */
|
||||||
|
#define PNPinterrupt2 "PNP0002" /* MCA Interrupt Controller */
|
||||||
|
#define PNPinterrupt3 "PNP0003" /* APIC */
|
||||||
|
#define PNPExtInt "IBM000D" /* PowerPC Extended Interrupt Controller */
|
||||||
|
|
||||||
|
/* Timers */
|
||||||
|
|
||||||
|
#define PNPtimer0 "PNP0100" /* AT Timer */
|
||||||
|
#define PNPtimer1 "PNP0101" /* EISA Timer */
|
||||||
|
#define PNPtimer2 "PNP0102" /* MCA Timer */
|
||||||
|
|
||||||
|
/* DMA controllers */
|
||||||
|
|
||||||
|
#define PNPdma0 "PNP0200" /* AT DMA Controller */
|
||||||
|
#define PNPdma1 "PNP0201" /* EISA DMA Controller */
|
||||||
|
#define PNPdma2 "PNP0202" /* MCA DMA Controller */
|
||||||
|
|
||||||
|
/* start of August 15, 1994 additions */
|
||||||
|
/* CMOS */
|
||||||
|
#define PNPCMOS "IBM0009" /* CMOS */
|
||||||
|
|
||||||
|
/* L2 Cache */
|
||||||
|
#define PNPL2 "IBM0007" /* L2 Cache */
|
||||||
|
|
||||||
|
/* NVRAM */
|
||||||
|
#define PNPNVRAM "IBM0008" /* NVRAM */
|
||||||
|
|
||||||
|
/* Power Management */
|
||||||
|
#define PNPPM "IBM0005" /* Power Management */
|
||||||
|
/* end of August 15, 1994 additions */
|
||||||
|
|
||||||
|
/* Keyboards */
|
||||||
|
|
||||||
|
#define PNPkeyboard0 "PNP0300" /* IBM PC/XT KB Cntlr (83 key, no mouse) */
|
||||||
|
#define PNPkeyboard1 "PNP0301" /* Olivetti ICO (102 key) */
|
||||||
|
#define PNPkeyboard2 "PNP0302" /* IBM PC/AT KB Cntlr (84 key) */
|
||||||
|
#define PNPkeyboard3 "PNP0303" /* IBM Enhanced (101/2 key, PS/2 mouse) */
|
||||||
|
#define PNPkeyboard4 "PNP0304" /* Nokia 1050 KB Cntlr */
|
||||||
|
#define PNPkeyboard5 "PNP0305" /* Nokia 9140 KB Cntlr */
|
||||||
|
#define PNPkeyboard6 "PNP0306" /* Standard Japanese KB Cntlr */
|
||||||
|
#define PNPkeyboard7 "PNP0307" /* Microsoft Windows (R) KB Cntlr */
|
||||||
|
|
||||||
|
/* Parallel port controllers */
|
||||||
|
|
||||||
|
#define PNPparallel0 "PNP0400" /* Standard LPT Parallel Port */
|
||||||
|
#define PNPparallel1 "PNP0401" /* ECP Parallel Port */
|
||||||
|
#define PNPepp "IBM001C" /* EPP Parallel Port */
|
||||||
|
|
||||||
|
/* Serial port controllers */
|
||||||
|
|
||||||
|
#define PNPserial0 "PNP0500" /* Standard PC Serial port */
|
||||||
|
#define PNPSerial1 "PNP0501" /* 16550A Compatible Serial port */
|
||||||
|
|
||||||
|
/* Disk controllers */
|
||||||
|
|
||||||
|
#define PNPdisk0 "PNP0600" /* Generic ESDI/IDE/ATA Compat HD Cntlr */
|
||||||
|
#define PNPdisk1 "PNP0601" /* Plus Hardcard II */
|
||||||
|
#define PNPdisk2 "PNP0602" /* Plus Hardcard IIXL/EZ */
|
||||||
|
|
||||||
|
/* Diskette controllers */
|
||||||
|
|
||||||
|
#define PNPdiskette0 "PNP0700" /* PC Standard Floppy Disk Controller */
|
||||||
|
|
||||||
|
/* Display controllers */
|
||||||
|
|
||||||
|
#define PNPdisplay0 "PNP0900" /* VGA Compatible */
|
||||||
|
#define PNPdisplay1 "PNP0901" /* Video Seven VGA */
|
||||||
|
#define PNPdisplay2 "PNP0902" /* 8514/A Compatible */
|
||||||
|
#define PNPdisplay3 "PNP0903" /* Trident VGA */
|
||||||
|
#define PNPdisplay4 "PNP0904" /* Cirrus Logic Laptop VGA */
|
||||||
|
#define PNPdisplay5 "PNP0905" /* Cirrus Logic VGA */
|
||||||
|
#define PNPdisplay6 "PNP0906" /* Tseng ET4000 or ET4000/W32 */
|
||||||
|
#define PNPdisplay7 "PNP0907" /* Western Digital VGA */
|
||||||
|
#define PNPdisplay8 "PNP0908" /* Western Digital Laptop VGA */
|
||||||
|
#define PNPdisplay9 "PNP0909" /* S3 */
|
||||||
|
#define PNPdisplayA "PNP090A" /* ATI Ultra Pro/Plus (Mach 32) */
|
||||||
|
#define PNPdisplayB "PNP090B" /* ATI Ultra (Mach 8) */
|
||||||
|
#define PNPdisplayC "PNP090C" /* XGA Compatible */
|
||||||
|
#define PNPdisplayD "PNP090D" /* ATI VGA Wonder */
|
||||||
|
#define PNPdisplayE "PNP090E" /* Weitek P9000 Graphics Adapter */
|
||||||
|
#define PNPdisplayF "PNP090F" /* Oak Technology VGA */
|
||||||
|
|
||||||
|
/* Peripheral busses */
|
||||||
|
|
||||||
|
#define PNPbuses0 "PNP0A00" /* ISA Bus */
|
||||||
|
#define PNPbuses1 "PNP0A01" /* EISA Bus */
|
||||||
|
#define PNPbuses2 "PNP0A02" /* MCA Bus */
|
||||||
|
#define PNPbuses3 "PNP0A03" /* PCI Bus */
|
||||||
|
#define PNPbuses4 "PNP0A04" /* VESA/VL Bus */
|
||||||
|
|
||||||
|
/* RTC, BIOS, planar devices */
|
||||||
|
|
||||||
|
#define PNPspeaker0 "PNP0800" /* AT Style Speaker Sound */
|
||||||
|
#define PNPrtc0 "PNP0B00" /* AT RTC */
|
||||||
|
#define PNPpnpbios0 "PNP0C00" /* PNP BIOS (only created by root enum) */
|
||||||
|
#define PNPpnpbios1 "PNP0C01" /* System Board Memory Device */
|
||||||
|
#define PNPpnpbios2 "PNP0C02" /* Math Coprocessor */
|
||||||
|
#define PNPpnpbios3 "PNP0C03" /* PNP BIOS Event Notification Interrupt */
|
||||||
|
|
||||||
|
/* PCMCIA controller */
|
||||||
|
|
||||||
|
#define PNPpcmcia0 "PNP0E00" /* Intel 82365 Compatible PCMCIA Cntlr */
|
||||||
|
|
||||||
|
/* Mice */
|
||||||
|
|
||||||
|
#define PNPmouse0 "PNP0F00" /* Microsoft Bus Mouse */
|
||||||
|
#define PNPmouse1 "PNP0F01" /* Microsoft Serial Mouse */
|
||||||
|
#define PNPmouse2 "PNP0F02" /* Microsoft Inport Mouse */
|
||||||
|
#define PNPmouse3 "PNP0F03" /* Microsoft PS/2 Mouse */
|
||||||
|
#define PNPmouse4 "PNP0F04" /* Mousesystems Mouse */
|
||||||
|
#define PNPmouse5 "PNP0F05" /* Mousesystems 3 Button Mouse - COM2 */
|
||||||
|
#define PNPmouse6 "PNP0F06" /* Genius Mouse - COM1 */
|
||||||
|
#define PNPmouse7 "PNP0F07" /* Genius Mouse - COM2 */
|
||||||
|
#define PNPmouse8 "PNP0F08" /* Logitech Serial Mouse */
|
||||||
|
#define PNPmouse9 "PNP0F09" /* Microsoft Ballpoint Serial Mouse */
|
||||||
|
#define PNPmouseA "PNP0F0A" /* Microsoft PNP Mouse */
|
||||||
|
#define PNPmouseB "PNP0F0B" /* Microsoft PNP Ballpoint Mouse */
|
||||||
|
|
||||||
|
/* Modems */
|
||||||
|
|
||||||
|
#define PNPmodem0 "PNP9000" /* Specific IDs TBD */
|
||||||
|
|
||||||
|
/* Network controllers */
|
||||||
|
|
||||||
|
#define PNPnetworkC9 "PNP80C9" /* IBM Token Ring */
|
||||||
|
#define PNPnetworkCA "PNP80CA" /* IBM Token Ring II */
|
||||||
|
#define PNPnetworkCB "PNP80CB" /* IBM Token Ring II/Short */
|
||||||
|
#define PNPnetworkCC "PNP80CC" /* IBM Token Ring 4/16Mbs */
|
||||||
|
#define PNPnetwork27 "PNP8327" /* IBM Token Ring (All types) */
|
||||||
|
#define PNPnetworket "IBM0010" /* IBM Ethernet used by Power PC */
|
||||||
|
#define PNPneteisaet "IBM2001" /* IBM Ethernet EISA adapter */
|
||||||
|
#define PNPAMD79C970 "IBM0016" /* AMD 79C970 (PCI Ethernet) */
|
||||||
|
|
||||||
|
/* SCSI controllers */
|
||||||
|
|
||||||
|
#define PNPscsi0 "PNPA000" /* Adaptec 154x Compatible SCSI Cntlr */
|
||||||
|
#define PNPscsi1 "PNPA001" /* Adaptec 174x Compatible SCSI Cntlr */
|
||||||
|
#define PNPscsi2 "PNPA002" /* Future Domain 16-700 Compat SCSI Cntlr*/
|
||||||
|
#define PNPscsi3 "PNPA003" /* Panasonic CDROM Adapter (SBPro/SB16) */
|
||||||
|
#define PNPscsiF "IBM000F" /* NCR 810 SCSI Controller */
|
||||||
|
#define PNPscsi825 "IBM001B" /* NCR 825 SCSI Controller */
|
||||||
|
#define PNPscsi875 "IBM0018" /* NCR 875 SCSI Controller */
|
||||||
|
|
||||||
|
/* Sound/Video, Multimedia */
|
||||||
|
|
||||||
|
#define PNPmm0 "PNPB000" /* Sound Blaster Compatible Sound Device */
|
||||||
|
#define PNPmm1 "PNPB001" /* MS Windows Sound System Compat Device */
|
||||||
|
#define PNPmmF "IBM000E" /* Crystal CS4231 Audio Device */
|
||||||
|
#define PNPv7310 "IBM0015" /* ASCII V7310 Video Capture Device */
|
||||||
|
#define PNPmm4232 "IBM0017" /* Crystal CS4232 Audio Device */
|
||||||
|
#define PNPpmsyn "IBM001D" /* YMF 289B chip (Yamaha) */
|
||||||
|
#define PNPgp4232 "IBM0012" /* Crystal CS4232 Game Port */
|
||||||
|
#define PNPmidi4232 "IBM0013" /* Crystal CS4232 MIDI */
|
||||||
|
|
||||||
|
/* Operator Panel */
|
||||||
|
#define PNPopctl "IBM000B" /* Operator's panel */
|
||||||
|
|
||||||
|
/* Service Processor */
|
||||||
|
#define PNPsp "IBM0011" /* IBM Service Processor */
|
||||||
|
#define PNPLTsp "IBM001E" /* Lightning/Terlingua Support Processor */
|
||||||
|
#define PNPLTmsp "IBM001F" /* Lightning/Terlingua Mini-SP */
|
||||||
|
|
||||||
|
/* Memory Controller */
|
||||||
|
#define PNPmemctl "IBM000A" /* Memory controller */
|
||||||
|
|
||||||
|
/* Graphics Assist */
|
||||||
|
#define PNPg_assist "IBM0014" /* Graphics Assist */
|
||||||
|
|
||||||
|
/* Miscellaneous Device Controllers */
|
||||||
|
#define PNPtablet "IBM0019" /* IBM Tablet Controller */
|
||||||
|
|
||||||
|
/* PNP Packet Handles */
|
||||||
|
|
||||||
|
#define S1_Packet 0x0A /* Version resource */
|
||||||
|
#define S2_Packet 0x15 /* Logical DEVID (without flags) */
|
||||||
|
#define S2_Packet_flags 0x16 /* Logical DEVID (with flags) */
|
||||||
|
#define S3_Packet 0x1C /* Compatible device ID */
|
||||||
|
#define S4_Packet 0x22 /* IRQ resource (without flags) */
|
||||||
|
#define S4_Packet_flags 0x23 /* IRQ resource (with flags) */
|
||||||
|
#define S5_Packet 0x2A /* DMA resource */
|
||||||
|
#define S6_Packet 0x30 /* Depend funct start (w/o priority) */
|
||||||
|
#define S6_Packet_priority 0x31 /* Depend funct start (w/ priority) */
|
||||||
|
#define S7_Packet 0x38 /* Depend funct end */
|
||||||
|
#define S8_Packet 0x47 /* I/O port resource (w/o fixed loc) */
|
||||||
|
#define S9_Packet_fixed 0x4B /* I/O port resource (w/ fixed loc) */
|
||||||
|
#define S14_Packet 0x71 /* Vendor defined */
|
||||||
|
#define S15_Packet 0x78 /* End of resource (w/o checksum) */
|
||||||
|
#define S15_Packet_checksum 0x79 /* End of resource (w/ checksum) */
|
||||||
|
#define L1_Packet 0x81 /* Memory range */
|
||||||
|
#define L1_Shadow 0x20 /* Memory is shadowable */
|
||||||
|
#define L1_32bit_mem 0x18 /* 32-bit memory only */
|
||||||
|
#define L1_8_16bit_mem 0x10 /* 8- and 16-bit supported */
|
||||||
|
#define L1_Decode_Hi 0x04 /* decode supports high address */
|
||||||
|
#define L1_Cache 0x02 /* read cacheable, write-through */
|
||||||
|
#define L1_Writeable 0x01 /* Memory is writeable */
|
||||||
|
#define L2_Packet 0x82 /* ANSI ID string */
|
||||||
|
#define L3_Packet 0x83 /* Unicode ID string */
|
||||||
|
#define L4_Packet 0x84 /* Vendor defined */
|
||||||
|
#define L5_Packet 0x85 /* Large I/O */
|
||||||
|
#define L6_Packet 0x86 /* 32-bit Fixed Loc Mem Range Desc */
|
||||||
|
#define END_TAG 0x78 /* End of resource */
|
||||||
|
#define DF_START_TAG 0x30 /* Dependent function start */
|
||||||
|
#define DF_START_TAG_priority 0x31 /* Dependent function start */
|
||||||
|
#define DF_END_TAG 0x38 /* Dependent function end */
|
||||||
|
#define SUBOPTIMAL_CONFIGURATION 0x2 /* Priority byte sub optimal config */
|
||||||
|
|
||||||
|
/* Device Base Type Codes */
|
||||||
|
|
||||||
|
typedef enum _PnP_BASE_TYPE {
|
||||||
|
Reserved = 0,
|
||||||
|
MassStorageDevice = 1,
|
||||||
|
NetworkInterfaceController = 2,
|
||||||
|
DisplayController = 3,
|
||||||
|
MultimediaController = 4,
|
||||||
|
MemoryController = 5,
|
||||||
|
BridgeController = 6,
|
||||||
|
CommunicationsDevice = 7,
|
||||||
|
SystemPeripheral = 8,
|
||||||
|
InputDevice = 9,
|
||||||
|
ServiceProcessor = 0x0A, /* 11/2/95 */
|
||||||
|
} PnP_BASE_TYPE;
|
||||||
|
|
||||||
|
/* Device Sub Type Codes */
|
||||||
|
|
||||||
|
typedef enum _PnP_SUB_TYPE {
|
||||||
|
SCSIController = 0,
|
||||||
|
IDEController = 1,
|
||||||
|
FloppyController = 2,
|
||||||
|
IPIController = 3,
|
||||||
|
OtherMassStorageController = 0x80,
|
||||||
|
|
||||||
|
EthernetController = 0,
|
||||||
|
TokenRingController = 1,
|
||||||
|
FDDIController = 2,
|
||||||
|
OtherNetworkController = 0x80,
|
||||||
|
|
||||||
|
VGAController= 0,
|
||||||
|
SVGAController= 1,
|
||||||
|
XGAController= 2,
|
||||||
|
OtherDisplayController = 0x80,
|
||||||
|
|
||||||
|
VideoController = 0,
|
||||||
|
AudioController = 1,
|
||||||
|
OtherMultimediaController = 0x80,
|
||||||
|
|
||||||
|
RAM = 0,
|
||||||
|
FLASH = 1,
|
||||||
|
OtherMemoryDevice = 0x80,
|
||||||
|
|
||||||
|
HostProcessorBridge = 0,
|
||||||
|
ISABridge = 1,
|
||||||
|
EISABridge = 2,
|
||||||
|
MicroChannelBridge = 3,
|
||||||
|
PCIBridge = 4,
|
||||||
|
PCMCIABridge = 5,
|
||||||
|
VMEBridge = 6,
|
||||||
|
OtherBridgeDevice = 0x80,
|
||||||
|
|
||||||
|
RS232Device = 0,
|
||||||
|
ATCompatibleParallelPort = 1,
|
||||||
|
OtherCommunicationsDevice = 0x80,
|
||||||
|
|
||||||
|
ProgrammableInterruptController = 0,
|
||||||
|
DMAController = 1,
|
||||||
|
SystemTimer = 2,
|
||||||
|
RealTimeClock = 3,
|
||||||
|
L2Cache = 4,
|
||||||
|
NVRAM = 5,
|
||||||
|
PowerManagement = 6,
|
||||||
|
CMOS = 7,
|
||||||
|
OperatorPanel = 8,
|
||||||
|
ServiceProcessorClass1 = 9,
|
||||||
|
ServiceProcessorClass2 = 0xA,
|
||||||
|
ServiceProcessorClass3 = 0xB,
|
||||||
|
GraphicAssist = 0xC,
|
||||||
|
SystemPlanar = 0xF, /* 10/5/95 */
|
||||||
|
OtherSystemPeripheral = 0x80,
|
||||||
|
|
||||||
|
KeyboardController = 0,
|
||||||
|
Digitizer = 1,
|
||||||
|
MouseController = 2,
|
||||||
|
TabletController = 3, /* 10/27/95 */
|
||||||
|
OtherInputController = 0x80,
|
||||||
|
|
||||||
|
GeneralMemoryController = 0,
|
||||||
|
} PnP_SUB_TYPE;
|
||||||
|
|
||||||
|
/* Device Interface Type Codes */
|
||||||
|
|
||||||
|
typedef enum _PnP_INTERFACE {
|
||||||
|
General = 0,
|
||||||
|
GeneralSCSI = 0,
|
||||||
|
GeneralIDE = 0,
|
||||||
|
ATACompatible = 1,
|
||||||
|
|
||||||
|
GeneralFloppy = 0,
|
||||||
|
Compatible765 = 1,
|
||||||
|
NS398_Floppy = 2, /* NS Super I/O wired to use index
|
||||||
|
register at port 398 and data
|
||||||
|
register at port 399 */
|
||||||
|
NS26E_Floppy = 3, /* Ports 26E and 26F */
|
||||||
|
NS15C_Floppy = 4, /* Ports 15C and 15D */
|
||||||
|
NS2E_Floppy = 5, /* Ports 2E and 2F */
|
||||||
|
CHRP_Floppy = 6, /* CHRP Floppy in PR*P system */
|
||||||
|
|
||||||
|
GeneralIPI = 0,
|
||||||
|
|
||||||
|
GeneralEther = 0,
|
||||||
|
GeneralToken = 0,
|
||||||
|
GeneralFDDI = 0,
|
||||||
|
|
||||||
|
GeneralVGA = 0,
|
||||||
|
GeneralSVGA = 0,
|
||||||
|
GeneralXGA = 0,
|
||||||
|
|
||||||
|
GeneralVideo = 0,
|
||||||
|
GeneralAudio = 0,
|
||||||
|
CS4232Audio = 1, /* CS 4232 Plug 'n Play Configured */
|
||||||
|
|
||||||
|
GeneralRAM = 0,
|
||||||
|
GeneralFLASH = 0,
|
||||||
|
PCIMemoryController = 0, /* PCI Config Method */
|
||||||
|
RS6KMemoryController = 1, /* RS6K Config Method */
|
||||||
|
|
||||||
|
GeneralHostBridge = 0,
|
||||||
|
GeneralISABridge = 0,
|
||||||
|
GeneralEISABridge = 0,
|
||||||
|
GeneralMCABridge = 0,
|
||||||
|
GeneralPCIBridge = 0,
|
||||||
|
PCIBridgeDirect = 0,
|
||||||
|
PCIBridgeIndirect = 1,
|
||||||
|
PCIBridgeRS6K = 2,
|
||||||
|
GeneralPCMCIABridge = 0,
|
||||||
|
GeneralVMEBridge = 0,
|
||||||
|
|
||||||
|
GeneralRS232 = 0,
|
||||||
|
COMx = 1,
|
||||||
|
Compatible16450 = 2,
|
||||||
|
Compatible16550 = 3,
|
||||||
|
NS398SerPort = 4, /* NS Super I/O wired to use index
|
||||||
|
register at port 398 and data
|
||||||
|
register at port 399 */
|
||||||
|
NS26ESerPort = 5, /* Ports 26E and 26F */
|
||||||
|
NS15CSerPort = 6, /* Ports 15C and 15D */
|
||||||
|
NS2ESerPort = 7, /* Ports 2E and 2F */
|
||||||
|
|
||||||
|
GeneralParPort = 0,
|
||||||
|
LPTx = 1,
|
||||||
|
NS398ParPort = 2, /* NS Super I/O wired to use index
|
||||||
|
register at port 398 and data
|
||||||
|
register at port 399 */
|
||||||
|
NS26EParPort = 3, /* Ports 26E and 26F */
|
||||||
|
NS15CParPort = 4, /* Ports 15C and 15D */
|
||||||
|
NS2EParPort = 5, /* Ports 2E and 2F */
|
||||||
|
|
||||||
|
GeneralPIC = 0,
|
||||||
|
ISA_PIC = 1,
|
||||||
|
EISA_PIC = 2,
|
||||||
|
MPIC = 3,
|
||||||
|
RS6K_PIC = 4,
|
||||||
|
|
||||||
|
GeneralDMA = 0,
|
||||||
|
ISA_DMA = 1,
|
||||||
|
EISA_DMA = 2,
|
||||||
|
|
||||||
|
GeneralTimer = 0,
|
||||||
|
ISA_Timer = 1,
|
||||||
|
EISA_Timer = 2,
|
||||||
|
GeneralRTC = 0,
|
||||||
|
ISA_RTC = 1,
|
||||||
|
|
||||||
|
StoreThruOnly = 1,
|
||||||
|
StoreInEnabled = 2,
|
||||||
|
RS6KL2Cache = 3,
|
||||||
|
|
||||||
|
IndirectNVRAM = 0, /* Indirectly addressed */
|
||||||
|
DirectNVRAM = 1, /* Memory Mapped */
|
||||||
|
IndirectNVRAM24 = 2, /* Indirectly addressed - 24 bit */
|
||||||
|
|
||||||
|
GeneralPowerManagement = 0,
|
||||||
|
EPOWPowerManagement = 1,
|
||||||
|
PowerControl = 2, /* d1378 */
|
||||||
|
|
||||||
|
GeneralCMOS = 0,
|
||||||
|
|
||||||
|
GeneralOPPanel = 0,
|
||||||
|
HarddiskLight = 1,
|
||||||
|
CDROMLight = 2,
|
||||||
|
PowerLight = 3,
|
||||||
|
KeyLock = 4,
|
||||||
|
ANDisplay = 5, /* AlphaNumeric Display */
|
||||||
|
SystemStatusLED = 6, /* 3 digit 7 segment LED */
|
||||||
|
CHRP_SystemStatusLED = 7, /* CHRP LEDs in PR*P system */
|
||||||
|
|
||||||
|
GeneralServiceProcessor = 0,
|
||||||
|
|
||||||
|
TransferData = 1,
|
||||||
|
IGMC32 = 2,
|
||||||
|
IGMC64 = 3,
|
||||||
|
|
||||||
|
GeneralSystemPlanar = 0, /* 10/5/95 */
|
||||||
|
|
||||||
|
} PnP_INTERFACE;
|
||||||
|
|
||||||
|
/* PnP resources */
|
||||||
|
|
||||||
|
/* Compressed ASCII is 5 bits per char; 00001=A ... 11010=Z */
|
||||||
|
|
||||||
|
typedef struct _SERIAL_ID {
|
||||||
|
unsigned char VendorID0; /* Bit(7)=0 */
|
||||||
|
/* Bits(6:2)=1st character in */
|
||||||
|
/* compressed ASCII */
|
||||||
|
/* Bits(1:0)=2nd character in */
|
||||||
|
/* compressed ASCII bits(4:3) */
|
||||||
|
unsigned char VendorID1; /* Bits(7:5)=2nd character in */
|
||||||
|
/* compressed ASCII bits(2:0) */
|
||||||
|
/* Bits(4:0)=3rd character in */
|
||||||
|
/* compressed ASCII */
|
||||||
|
unsigned char VendorID2; /* Product number - vendor assigned */
|
||||||
|
unsigned char VendorID3; /* Product number - vendor assigned */
|
||||||
|
|
||||||
|
/* Serial number is to provide uniqueness if more than one board of same */
|
||||||
|
/* type is in system. Must be "FFFFFFFF" if feature not supported. */
|
||||||
|
|
||||||
|
unsigned char Serial0; /* Unique serial number bits (7:0) */
|
||||||
|
unsigned char Serial1; /* Unique serial number bits (15:8) */
|
||||||
|
unsigned char Serial2; /* Unique serial number bits (23:16) */
|
||||||
|
unsigned char Serial3; /* Unique serial number bits (31:24) */
|
||||||
|
unsigned char Checksum;
|
||||||
|
} SERIAL_ID;
|
||||||
|
|
||||||
|
typedef enum _PnPItemName {
|
||||||
|
Unused = 0,
|
||||||
|
PnPVersion = 1,
|
||||||
|
LogicalDevice = 2,
|
||||||
|
CompatibleDevice = 3,
|
||||||
|
IRQFormat = 4,
|
||||||
|
DMAFormat = 5,
|
||||||
|
StartDepFunc = 6,
|
||||||
|
EndDepFunc = 7,
|
||||||
|
IOPort = 8,
|
||||||
|
FixedIOPort = 9,
|
||||||
|
Res1 = 10,
|
||||||
|
Res2 = 11,
|
||||||
|
Res3 = 12,
|
||||||
|
SmallVendorItem = 14,
|
||||||
|
EndTag = 15,
|
||||||
|
MemoryRange = 1,
|
||||||
|
ANSIIdentifier = 2,
|
||||||
|
UnicodeIdentifier = 3,
|
||||||
|
LargeVendorItem = 4,
|
||||||
|
MemoryRange32 = 5,
|
||||||
|
MemoryRangeFixed32 = 6,
|
||||||
|
} PnPItemName;
|
||||||
|
|
||||||
|
/* Define a bunch of access functions for the bits in the tag field */
|
||||||
|
|
||||||
|
/* Tag type - 0 = small; 1 = large */
|
||||||
|
#define tag_type(t) (((t) & 0x80)>>7)
|
||||||
|
#define set_tag_type(t,v) (t = (t & 0x7f) | ((v)<<7))
|
||||||
|
|
||||||
|
/* Small item name is 4 bits - one of PnPItemName enum above */
|
||||||
|
#define tag_small_item_name(t) (((t) & 0x78)>>3)
|
||||||
|
#define set_tag_small_item_name(t,v) (t = (t & 0x07) | ((v)<<3))
|
||||||
|
|
||||||
|
/* Small item count is 3 bits - count of further bytes in packet */
|
||||||
|
#define tag_small_count(t) ((t) & 0x07)
|
||||||
|
#define set_tag_count(t,v) (t = (t & 0x78) | (v))
|
||||||
|
|
||||||
|
/* Large item name is 7 bits - one of PnPItemName enum above */
|
||||||
|
#define tag_large_item_name(t) ((t) & 0x7f)
|
||||||
|
#define set_tag_large_item_name(t,v) (t = (t | 0x80) | (v))
|
||||||
|
|
||||||
|
/* a PnP resource is a bunch of contiguous TAG packets ending with an end tag */
|
||||||
|
|
||||||
|
typedef union _PnP_TAG_PACKET {
|
||||||
|
struct _S1_Pack{ /* VERSION PACKET */
|
||||||
|
unsigned char Tag; /* small tag = 0x0a */
|
||||||
|
unsigned char Version[2]; /* PnP version, Vendor version */
|
||||||
|
} S1_Pack;
|
||||||
|
|
||||||
|
struct _S2_Pack{ /* LOGICAL DEVICE ID PACKET */
|
||||||
|
unsigned char Tag; /* small tag = 0x15 or 0x16 */
|
||||||
|
unsigned char DevId[4]; /* Logical device id */
|
||||||
|
unsigned char Flags[2]; /* bit(0) boot device; */
|
||||||
|
/* bit(7:1) cmd in range x31-x37 */
|
||||||
|
/* bit(7:0) cmd in range x28-x3f (opt)*/
|
||||||
|
} S2_Pack;
|
||||||
|
|
||||||
|
struct _S3_Pack{ /* COMPATIBLE DEVICE ID PACKET */
|
||||||
|
unsigned char Tag; /* small tag = 0x1c */
|
||||||
|
unsigned char CompatId[4]; /* Compatible device id */
|
||||||
|
} S3_Pack;
|
||||||
|
|
||||||
|
struct _S4_Pack{ /* IRQ PACKET */
|
||||||
|
unsigned char Tag; /* small tag = 0x22 or 0x23 */
|
||||||
|
unsigned char IRQMask[2]; /* bit(0) is IRQ0, ...; */
|
||||||
|
/* bit(0) is IRQ8 ... */
|
||||||
|
unsigned char IRQInfo; /* optional; assume bit(0)=1; else */
|
||||||
|
/* bit(0) - high true edge sensitive */
|
||||||
|
/* bit(1) - low true edge sensitive */
|
||||||
|
/* bit(2) - high true level sensitive*/
|
||||||
|
/* bit(3) - low true level sensitive */
|
||||||
|
/* bit(7:4) - must be 0 */
|
||||||
|
} S4_Pack;
|
||||||
|
|
||||||
|
struct _S5_Pack{ /* DMA PACKET */
|
||||||
|
unsigned char Tag; /* small tag = 0x2a */
|
||||||
|
unsigned char DMAMask; /* bit(0) is channel 0 ... */
|
||||||
|
unsigned char DMAInfo;
|
||||||
|
} S5_Pack;
|
||||||
|
|
||||||
|
struct _S6_Pack{ /* START DEPENDENT FUNCTION PACKET */
|
||||||
|
unsigned char Tag; /* small tag = 0x30 or 0x31 */
|
||||||
|
unsigned char Priority; /* Optional; if missing then x01; else*/
|
||||||
|
/* x00 = best possible */
|
||||||
|
/* x01 = acceptible */
|
||||||
|
/* x02 = sub-optimal but functional */
|
||||||
|
} S6_Pack;
|
||||||
|
|
||||||
|
struct _S7_Pack{ /* END DEPENDENT FUNCTION PACKET */
|
||||||
|
unsigned char Tag; /* small tag = 0x38 */
|
||||||
|
} S7_Pack;
|
||||||
|
|
||||||
|
struct _S8_Pack{ /* VARIABLE I/O PORT PACKET */
|
||||||
|
unsigned char Tag; /* small tag x47 */
|
||||||
|
unsigned char IOInfo; /* x0 = decode only bits(9:0); */
|
||||||
|
#define ISAAddr16bit 0x01 /* x01 = decode bits(15:0) */
|
||||||
|
unsigned char RangeMin[2]; /* Min base address */
|
||||||
|
unsigned char RangeMax[2]; /* Max base address */
|
||||||
|
unsigned char IOAlign; /* base alignmt, incr in 1B blocks */
|
||||||
|
unsigned char IONum; /* number of contiguous I/O ports */
|
||||||
|
} S8_Pack;
|
||||||
|
|
||||||
|
struct _S9_Pack{ /* FIXED I/O PORT PACKET */
|
||||||
|
unsigned char Tag; /* small tag = 0x4b */
|
||||||
|
unsigned char Range[2]; /* base address 10 bits */
|
||||||
|
unsigned char IONum; /* number of contiguous I/O ports */
|
||||||
|
} S9_Pack;
|
||||||
|
|
||||||
|
struct _S14_Pack{ /* VENDOR DEFINED PACKET */
|
||||||
|
unsigned char Tag; /* small tag = 0x7m m = 1-7 */
|
||||||
|
union _S14_Data{
|
||||||
|
unsigned char Data[7]; /* Vendor defined */
|
||||||
|
struct _S14_PPCPack{ /* Pr*p s14 pack */
|
||||||
|
unsigned char Type; /* 00=non-IBM */
|
||||||
|
unsigned char PPCData[6]; /* Vendor defined */
|
||||||
|
} S14_PPCPack;
|
||||||
|
} S14_Data;
|
||||||
|
} S14_Pack;
|
||||||
|
|
||||||
|
struct _S15_Pack{ /* END PACKET */
|
||||||
|
unsigned char Tag; /* small tag = 0x78 or 0x79 */
|
||||||
|
unsigned char Check; /* optional - checksum */
|
||||||
|
} S15_Pack;
|
||||||
|
|
||||||
|
struct _L1_Pack{ /* MEMORY RANGE PACKET */
|
||||||
|
unsigned char Tag; /* large tag = 0x81 */
|
||||||
|
unsigned char Count0; /* x09 */
|
||||||
|
unsigned char Count1; /* x00 */
|
||||||
|
unsigned char Data[9]; /* a variable array of bytes, */
|
||||||
|
/* count in tag */
|
||||||
|
} L1_Pack;
|
||||||
|
|
||||||
|
struct _L2_Pack{ /* ANSI ID STRING PACKET */
|
||||||
|
unsigned char Tag; /* large tag = 0x82 */
|
||||||
|
unsigned char Count0; /* Length of string */
|
||||||
|
unsigned char Count1;
|
||||||
|
unsigned char Identifier[1]; /* a variable array of bytes, */
|
||||||
|
/* count in tag */
|
||||||
|
} L2_Pack;
|
||||||
|
|
||||||
|
struct _L3_Pack{ /* UNICODE ID STRING PACKET */
|
||||||
|
unsigned char Tag; /* large tag = 0x83 */
|
||||||
|
unsigned char Count0; /* Length + 2 of string */
|
||||||
|
unsigned char Count1;
|
||||||
|
unsigned char Country0; /* TBD */
|
||||||
|
unsigned char Country1; /* TBD */
|
||||||
|
unsigned char Identifier[1]; /* a variable array of bytes, */
|
||||||
|
/* count in tag */
|
||||||
|
} L3_Pack;
|
||||||
|
|
||||||
|
struct _L4_Pack{ /* VENDOR DEFINED PACKET */
|
||||||
|
unsigned char Tag; /* large tag = 0x84 */
|
||||||
|
unsigned char Count0;
|
||||||
|
unsigned char Count1;
|
||||||
|
union _L4_Data{
|
||||||
|
unsigned char Data[1]; /* a variable array of bytes, */
|
||||||
|
/* count in tag */
|
||||||
|
struct _L4_PPCPack{ /* Pr*p L4 packet */
|
||||||
|
unsigned char Type; /* 00=non-IBM */
|
||||||
|
unsigned char PPCData[1]; /* a variable array of bytes, */
|
||||||
|
/* count in tag */
|
||||||
|
} L4_PPCPack;
|
||||||
|
} L4_Data;
|
||||||
|
} L4_Pack;
|
||||||
|
|
||||||
|
struct _L5_Pack{
|
||||||
|
unsigned char Tag; /* large tag = 0x85 */
|
||||||
|
unsigned char Count0; /* Count = 17 */
|
||||||
|
unsigned char Count1;
|
||||||
|
unsigned char Data[17];
|
||||||
|
} L5_Pack;
|
||||||
|
|
||||||
|
struct _L6_Pack{
|
||||||
|
unsigned char Tag; /* large tag = 0x86 */
|
||||||
|
unsigned char Count0; /* Count = 9 */
|
||||||
|
unsigned char Count1;
|
||||||
|
unsigned char Data[9];
|
||||||
|
} L6_Pack;
|
||||||
|
|
||||||
|
} PnP_TAG_PACKET;
|
||||||
|
|
||||||
|
#endif /* ASM */
|
||||||
|
#endif /* ndef _PNP_ */
|
||||||
106
c/src/lib/libbsp/powerpc/shared/residual/residual.c
Normal file
106
c/src/lib/libbsp/powerpc/shared/residual/residual.c
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
/*
|
||||||
|
* residual.c : function used to parse residual data.
|
||||||
|
*
|
||||||
|
* CopyRight (C) 1999 valette@crf.canon.fr
|
||||||
|
*
|
||||||
|
* This code is heavilly inspired by the public specification of STREAM V2
|
||||||
|
* that can be found at :
|
||||||
|
*
|
||||||
|
* The license and distribution terms for this file may be
|
||||||
|
* found in found in the file LICENSE in this distribution or at
|
||||||
|
* http://www.OARcorp.com/rtems/license.html.
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <bsp/residual.h>
|
||||||
|
#include <libcpu/io.h>
|
||||||
|
#include <libcpu/byteorder.h>
|
||||||
|
|
||||||
|
|
||||||
|
static int same_DevID(unsigned short vendor,
|
||||||
|
unsigned short Number,
|
||||||
|
char * str)
|
||||||
|
{
|
||||||
|
static unsigned const char hexdigit[]="0123456789ABCDEF";
|
||||||
|
if (strlen(str)!=7) return 0;
|
||||||
|
if ( ( ((vendor>>10)&0x1f)+'A'-1 == str[0]) &&
|
||||||
|
( ((vendor>>5)&0x1f)+'A'-1 == str[1]) &&
|
||||||
|
( (vendor&0x1f)+'A'-1 == str[2]) &&
|
||||||
|
(hexdigit[(Number>>12)&0x0f] == str[3]) &&
|
||||||
|
(hexdigit[(Number>>8)&0x0f] == str[4]) &&
|
||||||
|
(hexdigit[(Number>>4)&0x0f] == str[5]) &&
|
||||||
|
(hexdigit[Number&0x0f] == str[6]) ) return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
PPC_DEVICE *residual_find_device(RESIDUAL *res,unsigned long BusMask,
|
||||||
|
unsigned char * DevID,
|
||||||
|
int BaseType,
|
||||||
|
int SubType,
|
||||||
|
int Interface,
|
||||||
|
int n)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
if ( !res || !res->ResidualLength ) return NULL;
|
||||||
|
for (i=0; i<res->ActualNumDevices; i++) {
|
||||||
|
#define Dev res->Devices[i].DeviceId
|
||||||
|
if ( (Dev.BusId&BusMask) &&
|
||||||
|
(BaseType==-1 || Dev.BaseType==BaseType) &&
|
||||||
|
(SubType==-1 || Dev.SubType==SubType) &&
|
||||||
|
(Interface==-1 || Dev.Interface==Interface) &&
|
||||||
|
(DevID==NULL || same_DevID((Dev.DevId>>16)&0xffff,
|
||||||
|
Dev.DevId&0xffff, DevID)) &&
|
||||||
|
!(n--) ) return res->Devices+i;
|
||||||
|
#undef Dev
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
PnP_TAG_PACKET *PnP_find_packet(unsigned char *p,
|
||||||
|
unsigned packet_tag,
|
||||||
|
int n)
|
||||||
|
{
|
||||||
|
unsigned mask, masked_tag, size;
|
||||||
|
if(!p) return 0;
|
||||||
|
if (tag_type(packet_tag)) mask=0xff; else mask=0xF8;
|
||||||
|
masked_tag = packet_tag&mask;
|
||||||
|
for(; *p != END_TAG; p+=size) {
|
||||||
|
if ((*p & mask) == masked_tag && !(n--))
|
||||||
|
return (PnP_TAG_PACKET *) p;
|
||||||
|
if (tag_type(*p))
|
||||||
|
size=ld_le16((unsigned short *)(p+1))+3;
|
||||||
|
else
|
||||||
|
size=tag_small_count(*p)+1;
|
||||||
|
}
|
||||||
|
return 0; /* not found */
|
||||||
|
}
|
||||||
|
|
||||||
|
PnP_TAG_PACKET *PnP_find_small_vendor_packet(unsigned char *p,
|
||||||
|
unsigned packet_type,
|
||||||
|
int n)
|
||||||
|
{
|
||||||
|
int next=0;
|
||||||
|
while (p) {
|
||||||
|
p = (unsigned char *) PnP_find_packet(p, 0x70, next);
|
||||||
|
if (p && p[1]==packet_type && !(n--))
|
||||||
|
return (PnP_TAG_PACKET *) p;
|
||||||
|
next = 1;
|
||||||
|
};
|
||||||
|
return 0; /* not found */
|
||||||
|
}
|
||||||
|
|
||||||
|
PnP_TAG_PACKET *PnP_find_large_vendor_packet(unsigned char *p,
|
||||||
|
unsigned packet_type,
|
||||||
|
int n)
|
||||||
|
{
|
||||||
|
int next=0;
|
||||||
|
while (p) {
|
||||||
|
p = (unsigned char *) PnP_find_packet(p, 0x84, next);
|
||||||
|
if (p && p[3]==packet_type && !(n--))
|
||||||
|
return (PnP_TAG_PACKET *) p;
|
||||||
|
next = 1;
|
||||||
|
};
|
||||||
|
return 0; /* not found */
|
||||||
|
}
|
||||||
|
|
||||||
346
c/src/lib/libbsp/powerpc/shared/residual/residual.h
Normal file
346
c/src/lib/libbsp/powerpc/shared/residual/residual.h
Normal file
@@ -0,0 +1,346 @@
|
|||||||
|
/* 7/18/95 */
|
||||||
|
/*----------------------------------------------------------------------------*/
|
||||||
|
/* Residual Data header definitions and prototypes */
|
||||||
|
/*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Structure map for RESIDUAL on PowerPC Reference Platform */
|
||||||
|
/* residual.h - Residual data structure passed in r3. */
|
||||||
|
/* Load point passed in r4 to boot image. */
|
||||||
|
/* For enum's: if given in hex then they are bit significant, */
|
||||||
|
/* i.e. only one bit is on for each enum */
|
||||||
|
/* Reserved fields must be filled with zeros. */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _RESIDUAL_
|
||||||
|
#define _RESIDUAL_
|
||||||
|
|
||||||
|
#ifndef ASM
|
||||||
|
|
||||||
|
#define MAX_CPUS 32 /* These should be set to the maximum */
|
||||||
|
#define MAX_MEMS 64 /* number possible for this system. */
|
||||||
|
#define MAX_DEVICES 256 /* Changing these will change the */
|
||||||
|
#define AVE_PNP_SIZE 32 /* structure, hence the version of */
|
||||||
|
#define MAX_MEM_SEGS 64 /* this header file. */
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------*/
|
||||||
|
/* Public structures... */
|
||||||
|
/*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include <bsp/pnp.h>
|
||||||
|
|
||||||
|
typedef enum _L1CACHE_TYPE {
|
||||||
|
NoneCAC = 0,
|
||||||
|
SplitCAC = 1,
|
||||||
|
CombinedCAC = 2
|
||||||
|
} L1CACHE_TYPE;
|
||||||
|
|
||||||
|
typedef enum _TLB_TYPE {
|
||||||
|
NoneTLB = 0,
|
||||||
|
SplitTLB = 1,
|
||||||
|
CombinedTLB = 2
|
||||||
|
} TLB_TYPE;
|
||||||
|
|
||||||
|
typedef enum _FIRMWARE_SUPPORT {
|
||||||
|
Conventional = 0x01,
|
||||||
|
OpenFirmware = 0x02,
|
||||||
|
Diagnostics = 0x04,
|
||||||
|
LowDebug = 0x08,
|
||||||
|
Multiboot = 0x10,
|
||||||
|
LowClient = 0x20,
|
||||||
|
Hex41 = 0x40,
|
||||||
|
FAT = 0x80,
|
||||||
|
ISO9660 = 0x0100,
|
||||||
|
SCSI_InitiatorID_Override = 0x0200,
|
||||||
|
Tape_Boot = 0x0400,
|
||||||
|
FW_Boot_Path = 0x0800
|
||||||
|
} FIRMWARE_SUPPORT;
|
||||||
|
|
||||||
|
typedef enum _FIRMWARE_SUPPLIERS {
|
||||||
|
IBMFirmware = 0x00,
|
||||||
|
MotoFirmware = 0x01, /* 7/18/95 */
|
||||||
|
FirmWorks = 0x02, /* 10/5/95 */
|
||||||
|
Bull = 0x03, /* 04/03/96 */
|
||||||
|
} FIRMWARE_SUPPLIERS;
|
||||||
|
|
||||||
|
typedef enum _ENDIAN_SWITCH_METHODS {
|
||||||
|
UsePort92 = 0x01,
|
||||||
|
UsePCIConfigA8 = 0x02,
|
||||||
|
UseFF001030 = 0x03,
|
||||||
|
} ENDIAN_SWITCH_METHODS;
|
||||||
|
|
||||||
|
typedef enum _SPREAD_IO_METHODS {
|
||||||
|
UsePort850 = 0x00,
|
||||||
|
/*UsePCIConfigA8 = 0x02,*/
|
||||||
|
} SPREAD_IO_METHODS;
|
||||||
|
|
||||||
|
typedef struct _VPD {
|
||||||
|
|
||||||
|
/* Box dependent stuff */
|
||||||
|
unsigned char PrintableModel[32]; /* Null terminated string.
|
||||||
|
Must be of the form:
|
||||||
|
vvv,<20h>,<model designation>,<0x0>
|
||||||
|
where vvv is the vendor ID
|
||||||
|
e.g. IBM PPS MODEL 6015<0x0> */
|
||||||
|
unsigned char Serial[16]; /* 12/94:
|
||||||
|
Serial Number; must be of the form:
|
||||||
|
vvv<serial number> where vvv is the
|
||||||
|
vendor ID.
|
||||||
|
e.g. IBM60151234567<20h><20h> */
|
||||||
|
unsigned char Reserved[48];
|
||||||
|
unsigned long FirmwareSupplier; /* See FirmwareSuppliers enum */
|
||||||
|
unsigned long FirmwareSupports; /* See FirmwareSupport enum */
|
||||||
|
unsigned long NvramSize; /* Size of nvram in bytes */
|
||||||
|
unsigned long NumSIMMSlots;
|
||||||
|
unsigned short EndianSwitchMethod; /* See EndianSwitchMethods enum */
|
||||||
|
unsigned short SpreadIOMethod; /* See SpreadIOMethods enum */
|
||||||
|
unsigned long SmpIar;
|
||||||
|
unsigned long RAMErrLogOffset; /* Heap offset to error log */
|
||||||
|
unsigned long Reserved5;
|
||||||
|
unsigned long Reserved6;
|
||||||
|
unsigned long ProcessorHz; /* Processor clock frequency in Hertz */
|
||||||
|
unsigned long ProcessorBusHz; /* Processor bus clock frequency */
|
||||||
|
unsigned long Reserved7;
|
||||||
|
unsigned long TimeBaseDivisor; /* (Bus clocks per timebase tic)*1000 */
|
||||||
|
unsigned long WordWidth; /* Word width in bits */
|
||||||
|
unsigned long PageSize; /* Page size in bytes */
|
||||||
|
unsigned long CoherenceBlockSize; /* Unit of transfer in/out of cache
|
||||||
|
for which coherency is maintained;
|
||||||
|
normally <= CacheLineSize. */
|
||||||
|
unsigned long GranuleSize; /* Unit of lock allocation to avoid */
|
||||||
|
/* false sharing of locks. */
|
||||||
|
|
||||||
|
/* L1 Cache variables */
|
||||||
|
unsigned long CacheSize; /* L1 Cache size in KB. This is the */
|
||||||
|
/* total size of the L1, whether */
|
||||||
|
/* combined or split */
|
||||||
|
unsigned long CacheAttrib; /* L1CACHE_TYPE */
|
||||||
|
unsigned long CacheAssoc; /* L1 Cache associativity. Use this
|
||||||
|
for combined cache. If split, put
|
||||||
|
zeros here. */
|
||||||
|
unsigned long CacheLineSize; /* L1 Cache line size in bytes. Use
|
||||||
|
for combined cache. If split, put
|
||||||
|
zeros here. */
|
||||||
|
/* For split L1 Cache: (= combined if combined cache) */
|
||||||
|
unsigned long I_CacheSize;
|
||||||
|
unsigned long I_CacheAssoc;
|
||||||
|
unsigned long I_CacheLineSize;
|
||||||
|
unsigned long D_CacheSize;
|
||||||
|
unsigned long D_CacheAssoc;
|
||||||
|
unsigned long D_CacheLineSize;
|
||||||
|
|
||||||
|
/* Translation Lookaside Buffer variables */
|
||||||
|
unsigned long TLBSize; /* Total number of TLBs on the system */
|
||||||
|
unsigned long TLBAttrib; /* Combined I+D or split TLB */
|
||||||
|
unsigned long TLBAssoc; /* TLB Associativity. Use this for
|
||||||
|
combined TLB. If split, put zeros
|
||||||
|
here. */
|
||||||
|
/* For split TLB: (= combined if combined TLB) */
|
||||||
|
unsigned long I_TLBSize;
|
||||||
|
unsigned long I_TLBAssoc;
|
||||||
|
unsigned long D_TLBSize;
|
||||||
|
unsigned long D_TLBAssoc;
|
||||||
|
|
||||||
|
unsigned long ExtendedVPD; /* Offset to extended VPD area;
|
||||||
|
null if unused */
|
||||||
|
} VPD;
|
||||||
|
|
||||||
|
typedef enum _DEVICE_FLAGS {
|
||||||
|
Enabled = 0x4000, /* 1 - PCI device is enabled */
|
||||||
|
Integrated = 0x2000,
|
||||||
|
Failed = 0x1000, /* 1 - device failed POST code tests */
|
||||||
|
Static = 0x0800, /* 0 - dynamically configurable
|
||||||
|
1 - static */
|
||||||
|
Dock = 0x0400, /* 0 - not a docking station device
|
||||||
|
1 - is a docking station device */
|
||||||
|
Boot = 0x0200, /* 0 - device cannot be used for BOOT
|
||||||
|
1 - can be a BOOT device */
|
||||||
|
Configurable = 0x0100, /* 1 - device is configurable */
|
||||||
|
Disableable = 0x80, /* 1 - device can be disabled */
|
||||||
|
PowerManaged = 0x40, /* 0 - not managed; 1 - managed */
|
||||||
|
ReadOnly = 0x20, /* 1 - device is read only */
|
||||||
|
Removable = 0x10, /* 1 - device is removable */
|
||||||
|
ConsoleIn = 0x08,
|
||||||
|
ConsoleOut = 0x04,
|
||||||
|
Input = 0x02,
|
||||||
|
Output = 0x01
|
||||||
|
} DEVICE_FLAGS;
|
||||||
|
|
||||||
|
typedef enum _BUS_ID {
|
||||||
|
ISADEVICE = 0x01,
|
||||||
|
EISADEVICE = 0x02,
|
||||||
|
PCIDEVICE = 0x04,
|
||||||
|
PCMCIADEVICE = 0x08,
|
||||||
|
PNPISADEVICE = 0x10,
|
||||||
|
MCADEVICE = 0x20,
|
||||||
|
MXDEVICE = 0x40, /* Devices on mezzanine bus */
|
||||||
|
PROCESSORDEVICE = 0x80, /* Devices on processor bus */
|
||||||
|
VMEDEVICE = 0x100,
|
||||||
|
} BUS_ID;
|
||||||
|
|
||||||
|
typedef struct _DEVICE_ID {
|
||||||
|
unsigned long BusId; /* See BUS_ID enum above */
|
||||||
|
unsigned long DevId; /* Big Endian format */
|
||||||
|
unsigned long SerialNum; /* For multiple usage of a single
|
||||||
|
DevId */
|
||||||
|
unsigned long Flags; /* See DEVICE_FLAGS enum above */
|
||||||
|
unsigned char BaseType; /* See pnp.h for bit definitions */
|
||||||
|
unsigned char SubType; /* See pnp.h for bit definitions */
|
||||||
|
unsigned char Interface; /* See pnp.h for bit definitions */
|
||||||
|
unsigned char Spare;
|
||||||
|
} DEVICE_ID;
|
||||||
|
|
||||||
|
typedef union _BUS_ACCESS {
|
||||||
|
struct _PnPAccess{
|
||||||
|
unsigned char CSN;
|
||||||
|
unsigned char LogicalDevNumber;
|
||||||
|
unsigned short ReadDataPort;
|
||||||
|
} PnPAccess;
|
||||||
|
struct _ISAAccess{
|
||||||
|
unsigned char SlotNumber; /* ISA Slot Number generally not
|
||||||
|
available; 0 if unknown */
|
||||||
|
unsigned char LogicalDevNumber;
|
||||||
|
unsigned short ISAReserved;
|
||||||
|
} ISAAccess;
|
||||||
|
struct _MCAAccess{
|
||||||
|
unsigned char SlotNumber;
|
||||||
|
unsigned char LogicalDevNumber;
|
||||||
|
unsigned short MCAReserved;
|
||||||
|
} MCAAccess;
|
||||||
|
struct _PCMCIAAccess{
|
||||||
|
unsigned char SlotNumber;
|
||||||
|
unsigned char LogicalDevNumber;
|
||||||
|
unsigned short PCMCIAReserved;
|
||||||
|
} PCMCIAAccess;
|
||||||
|
struct _EISAAccess{
|
||||||
|
unsigned char SlotNumber;
|
||||||
|
unsigned char FunctionNumber;
|
||||||
|
unsigned short EISAReserved;
|
||||||
|
} EISAAccess;
|
||||||
|
struct _PCIAccess{
|
||||||
|
unsigned char BusNumber;
|
||||||
|
unsigned char DevFuncNumber;
|
||||||
|
unsigned short PCIReserved;
|
||||||
|
} PCIAccess;
|
||||||
|
struct _ProcBusAccess{
|
||||||
|
unsigned char BusNumber;
|
||||||
|
unsigned char BUID;
|
||||||
|
unsigned short ProcBusReserved;
|
||||||
|
} ProcBusAccess;
|
||||||
|
} BUS_ACCESS;
|
||||||
|
|
||||||
|
/* Per logical device information */
|
||||||
|
typedef struct _PPC_DEVICE {
|
||||||
|
DEVICE_ID DeviceId;
|
||||||
|
BUS_ACCESS BusAccess;
|
||||||
|
|
||||||
|
/* The following three are offsets into the DevicePnPHeap */
|
||||||
|
/* All are in PnP compressed format */
|
||||||
|
unsigned long AllocatedOffset; /* Allocated resource description */
|
||||||
|
unsigned long PossibleOffset; /* Possible resource description */
|
||||||
|
unsigned long CompatibleOffset; /* Compatible device identifiers */
|
||||||
|
} PPC_DEVICE;
|
||||||
|
|
||||||
|
typedef enum _CPU_STATE {
|
||||||
|
CPU_GOOD = 0, /* CPU is present, and active */
|
||||||
|
CPU_GOOD_FW = 1, /* CPU is present, and in firmware */
|
||||||
|
CPU_OFF = 2, /* CPU is present, but inactive */
|
||||||
|
CPU_FAILED = 3, /* CPU is present, but failed POST */
|
||||||
|
CPU_NOT_PRESENT = 255 /* CPU not present */
|
||||||
|
} CPU_STATE;
|
||||||
|
|
||||||
|
typedef struct _PPC_CPU {
|
||||||
|
unsigned long CpuType; /* Result of mfspr from Processor
|
||||||
|
Version Register (PVR).
|
||||||
|
PVR(0-15) = Version (e.g. 601)
|
||||||
|
PVR(16-31 = EC Level */
|
||||||
|
unsigned char CpuNumber; /* CPU Number for this processor */
|
||||||
|
unsigned char CpuState; /* CPU State, see CPU_STATE enum */
|
||||||
|
unsigned short Reserved;
|
||||||
|
} PPC_CPU;
|
||||||
|
|
||||||
|
typedef struct _PPC_MEM {
|
||||||
|
unsigned long SIMMSize; /* 0 - absent or bad
|
||||||
|
8M, 32M (in MB) */
|
||||||
|
} PPC_MEM;
|
||||||
|
|
||||||
|
typedef enum _MEM_USAGE {
|
||||||
|
Other = 0x8000,
|
||||||
|
ResumeBlock = 0x4000, /* for use by power management */
|
||||||
|
SystemROM = 0x2000, /* Flash memory (populated) */
|
||||||
|
UnPopSystemROM = 0x1000, /* Unpopulated part of SystemROM area */
|
||||||
|
IOMemory = 0x0800,
|
||||||
|
SystemIO = 0x0400,
|
||||||
|
SystemRegs = 0x0200,
|
||||||
|
PCIAddr = 0x0100,
|
||||||
|
PCIConfig = 0x80,
|
||||||
|
ISAAddr = 0x40,
|
||||||
|
Unpopulated = 0x20, /* Unpopulated part of System Memory */
|
||||||
|
Free = 0x10, /* Free part of System Memory */
|
||||||
|
BootImage = 0x08, /* BootImage part of System Memory */
|
||||||
|
FirmwareCode = 0x04, /* FirmwareCode part of System Memory */
|
||||||
|
FirmwareHeap = 0x02, /* FirmwareHeap part of System Memory */
|
||||||
|
FirmwareStack = 0x01 /* FirmwareStack part of System Memory*/
|
||||||
|
} MEM_USAGE;
|
||||||
|
|
||||||
|
typedef struct _MEM_MAP {
|
||||||
|
unsigned long Usage; /* See MEM_USAGE above */
|
||||||
|
unsigned long BasePage; /* Page number measured in 4KB pages */
|
||||||
|
unsigned long PageCount; /* Page count measured in 4KB pages */
|
||||||
|
} MEM_MAP;
|
||||||
|
|
||||||
|
typedef struct _RESIDUAL {
|
||||||
|
unsigned long ResidualLength; /* Length of Residual */
|
||||||
|
unsigned char Version; /* of this data structure */
|
||||||
|
unsigned char Revision; /* of this data structure */
|
||||||
|
unsigned short EC; /* of this data structure */
|
||||||
|
/* VPD */
|
||||||
|
VPD VitalProductData;
|
||||||
|
/* CPU */
|
||||||
|
unsigned short MaxNumCpus; /* Max CPUs in this system */
|
||||||
|
unsigned short ActualNumCpus; /* ActualNumCpus < MaxNumCpus means */
|
||||||
|
/* that there are unpopulated or */
|
||||||
|
/* otherwise unusable cpu locations */
|
||||||
|
PPC_CPU Cpus[MAX_CPUS];
|
||||||
|
/* Memory */
|
||||||
|
unsigned long TotalMemory; /* Total amount of memory installed */
|
||||||
|
unsigned long GoodMemory; /* Total amount of good memory */
|
||||||
|
unsigned long ActualNumMemSegs;
|
||||||
|
MEM_MAP Segs[MAX_MEM_SEGS];
|
||||||
|
unsigned long ActualNumMemories;
|
||||||
|
PPC_MEM Memories[MAX_MEMS];
|
||||||
|
/* Devices */
|
||||||
|
unsigned long ActualNumDevices;
|
||||||
|
PPC_DEVICE Devices[MAX_DEVICES];
|
||||||
|
unsigned char DevicePnPHeap[2*MAX_DEVICES*AVE_PNP_SIZE];
|
||||||
|
} RESIDUAL;
|
||||||
|
|
||||||
|
#ifndef NULL
|
||||||
|
#define NULL 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern RESIDUAL residualCopy;
|
||||||
|
|
||||||
|
extern void print_residual_device_info(void);
|
||||||
|
#ifndef __BOOT__
|
||||||
|
extern PPC_DEVICE *residual_find_device(RESIDUAL *res, unsigned long BusMask,
|
||||||
|
unsigned char * DevID, int BaseType,
|
||||||
|
int SubType, int Interface, int n);
|
||||||
|
#else
|
||||||
|
extern PPC_DEVICE *residual_find_device(unsigned long BusMask,
|
||||||
|
unsigned char * DevID, int BaseType,
|
||||||
|
int SubType, int Interface, int n);
|
||||||
|
#endif
|
||||||
|
extern PnP_TAG_PACKET *PnP_find_packet(unsigned char *p, unsigned packet_tag,
|
||||||
|
int n);
|
||||||
|
extern PnP_TAG_PACKET *PnP_find_small_vendor_packet(unsigned char *p,
|
||||||
|
unsigned packet_type,
|
||||||
|
int n);
|
||||||
|
extern PnP_TAG_PACKET *PnP_find_large_vendor_packet(unsigned char *p,
|
||||||
|
unsigned packet_type,
|
||||||
|
int n);
|
||||||
|
#endif /* ASM */
|
||||||
|
#endif /* ndef _RESIDUAL_ */
|
||||||
|
|
||||||
29
c/src/lib/libbsp/powerpc/shared/start/Makefile.in
Normal file
29
c/src/lib/libbsp/powerpc/shared/start/Makefile.in
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
#
|
||||||
|
# $Id$
|
||||||
|
#
|
||||||
|
|
||||||
|
@SET_MAKE@
|
||||||
|
srcdir = @srcdir@
|
||||||
|
top_srcdir = @top_srcdir@
|
||||||
|
top_builddir = ../../..
|
||||||
|
subdir = powerpc/mcp750/start
|
||||||
|
|
||||||
|
RTEMS_ROOT = @RTEMS_ROOT@
|
||||||
|
PROJECT_ROOT = @PROJECT_ROOT@
|
||||||
|
|
||||||
|
VPATH = @srcdir@
|
||||||
|
|
||||||
|
H_FILES =
|
||||||
|
|
||||||
|
SRCS = $(C_FILES) $(CC_FILES) $(H_FILES) $(S_FILES)
|
||||||
|
|
||||||
|
include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
|
||||||
|
include $(RTEMS_ROOT)/make/leaf.cfg
|
||||||
|
|
||||||
|
INSTALL_CHANGE = @INSTALL_CHANGE@
|
||||||
|
|
||||||
|
all: ${ARCH} $(SRCS)
|
||||||
|
|
||||||
|
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||||
|
cd $(top_builddir) \
|
||||||
|
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
|
||||||
131
c/src/lib/libbsp/powerpc/shared/start/start.S
Normal file
131
c/src/lib/libbsp/powerpc/shared/start/start.S
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
/*
|
||||||
|
* start.S : RTEMS entry point
|
||||||
|
*
|
||||||
|
* Copyright (C) 1999 Eric Valette. valette@crf.canon.fr
|
||||||
|
*
|
||||||
|
* The license and distribution terms for this file may be
|
||||||
|
* found in found in the file LICENSE in this distribution or at
|
||||||
|
* http://www.OARcorp.com/rtems/license.html.
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <libcpu/cpu.h>
|
||||||
|
#include <libcpu/io.h>
|
||||||
|
#include <rtems/score/targopts.h>
|
||||||
|
#include <rtems/score/cpu.h>
|
||||||
|
#include "asm.h"
|
||||||
|
|
||||||
|
#define SYNC \
|
||||||
|
sync; \
|
||||||
|
isync
|
||||||
|
|
||||||
|
#define KERNELBASE 0x0
|
||||||
|
|
||||||
|
#define MONITOR_ENTER \
|
||||||
|
mfmsr r10 ; \
|
||||||
|
ori r10,r10,MSR_IP ; \
|
||||||
|
mtmsr r10 ; \
|
||||||
|
li r10,0x63 ; \
|
||||||
|
sc
|
||||||
|
|
||||||
|
.text
|
||||||
|
.globl __rtems_entry_point
|
||||||
|
.type __rtems_entry_point,@function
|
||||||
|
__rtems_entry_point:
|
||||||
|
#ifdef DEBUG_EARLY_START
|
||||||
|
MONITOR_ENTER
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PREP
|
||||||
|
* This is jumped to on prep systems right after the kernel is relocated
|
||||||
|
* to its proper place in memory by the boot loader. The expected layout
|
||||||
|
* of the regs is:
|
||||||
|
* r3: ptr to residual data
|
||||||
|
* r4: initrd_start or if no initrd then 0
|
||||||
|
* r5: initrd_end - unused if r4 is 0
|
||||||
|
* r6: Start of command line string
|
||||||
|
* r7: End of command line string
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
mr r31,r3 /* save parameters */
|
||||||
|
mr r30,r4
|
||||||
|
mr r29,r5
|
||||||
|
mr r28,r6
|
||||||
|
mr r27,r7
|
||||||
|
/*
|
||||||
|
* Use the first pair of BAT registers to map the 1st 64MB
|
||||||
|
* of RAM to KERNELBASE.
|
||||||
|
*/
|
||||||
|
lis r11,KERNELBASE@h
|
||||||
|
ori r11,r11,0x7fe /* set up BAT registers for 604 */
|
||||||
|
li r8,2 /* R/W access */
|
||||||
|
mtspr DBAT0L,r8 /* N.B. 6xx (not 601) have valid */
|
||||||
|
mtspr DBAT0U,r11 /* bit in upper BAT register */
|
||||||
|
mtspr IBAT0L,r8
|
||||||
|
mtspr IBAT0U,r11
|
||||||
|
isync
|
||||||
|
|
||||||
|
/*
|
||||||
|
* we now have the 1st 64M of ram mapped with the bats.
|
||||||
|
*/
|
||||||
|
|
||||||
|
enter_C_code:
|
||||||
|
bl MMUon
|
||||||
|
/*
|
||||||
|
* stack = &__rtems_end + 4096
|
||||||
|
*/
|
||||||
|
addis r9,r0, __rtems_end+(4096-CPU_MINIMUM_STACK_FRAME_SIZE)@ha
|
||||||
|
addi r9,r9, __rtems_end+(4096-CPU_MINIMUM_STACK_FRAME_SIZE)@l
|
||||||
|
mr r1, r9
|
||||||
|
bl zero_bss
|
||||||
|
/*
|
||||||
|
* restore prep boot params
|
||||||
|
*/
|
||||||
|
mr r3,r31
|
||||||
|
mr r4,r30
|
||||||
|
mr r5,r29
|
||||||
|
mr r6,r28
|
||||||
|
mr r7,r27
|
||||||
|
bl save_boot_params
|
||||||
|
bl boot_card
|
||||||
|
bl _return_to_ppcbug
|
||||||
|
|
||||||
|
.globl MMUon
|
||||||
|
.type MMUon,@function
|
||||||
|
MMUon:
|
||||||
|
mfmsr r0
|
||||||
|
ori r0,r0, MSR_IP | MSR_RI | MSR_IR | MSR_DR | MSR_EE | MSR_FE0 | MSR_FE1
|
||||||
|
xori r0, r0, MSR_EE | MSR_IP | MSR_FP
|
||||||
|
mflr r11
|
||||||
|
mtsrr0 r11
|
||||||
|
mtsrr1 r0
|
||||||
|
SYNC
|
||||||
|
rfi
|
||||||
|
|
||||||
|
.globl MMUoff
|
||||||
|
.type MMUoff,@function
|
||||||
|
MMUoff:
|
||||||
|
mfmsr r0
|
||||||
|
ori r0,r0,MSR_IR| MSR_DR | MSR_IP
|
||||||
|
mflr r11
|
||||||
|
xori r0,r0,MSR_IR|MSR_DR
|
||||||
|
mtsrr0 r11
|
||||||
|
mtsrr1 r0
|
||||||
|
SYNC
|
||||||
|
rfi
|
||||||
|
|
||||||
|
.globl _return_to_ppcbug
|
||||||
|
.type _return_to_ppcbug,@function
|
||||||
|
|
||||||
|
|
||||||
|
_return_to_ppcbug:
|
||||||
|
mflr r30
|
||||||
|
bl MMUoff
|
||||||
|
MONITOR_ENTER
|
||||||
|
bl MMUon
|
||||||
|
mtctr r30
|
||||||
|
bctr
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user