* Patch by Martin Winistoerfer, 23 Mar 2003

- Add port to MPC555/556 microcontrollers
  - Add support for cmi customer board with
    Intel 28F128J3A, 28F320J3A or 28F640J3A flash.

* Patch by Rick Bronson, 28 Mar 2003:
  - fix common/cmd_nand.c
This commit is contained in:
wdenk
2003-03-31 17:27:09 +00:00
parent 85ec0bcc1b
commit 0db5bca807
38 changed files with 3971 additions and 146 deletions

52
cpu/mpc5xx/Makefile Normal file
View File

@@ -0,0 +1,52 @@
#
# (C) Copyright 2003
# Martin Winistoerfer, martinwinistoerfer@gmx.ch.
#
# See file CREDITS for list of people who contributed to this
# project.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of
# the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
# MA 02111-1307 USA
#
#
# File: cpu/mpc5xx/Makefile
#
# Discription: Makefile to build mpc5xx cpu configuration.
# Will include top config.mk which itselfs
# uses the definitions made in cpu/mpc5xx/config.mk
#
include $(TOPDIR)/config.mk
LIB = lib$(CPU).a
START = start.S
OBJS = serial.o cpu.o cpu_init.o interrupts.o traps.o speed.o status_led.o
all: .depend $(START) $(LIB)
$(LIB): $(OBJS)
$(AR) crv $@ $(OBJS)
#########################################################################
.depend: Makefile $(START:.o=.S) $(OBJS:.o=.c)
$(CC) -M $(CFLAGS) $(START:.o=.S) $(OBJS:.o=.c) > $@
sinclude .depend
#########################################################################

34
cpu/mpc5xx/config.mk Normal file
View File

@@ -0,0 +1,34 @@
#
# (C) Copyright 2003
# Martin Winistoerfer, martinwinistoerfer@gmx.ch.
#
# See file CREDITS for list of people who contributed to this
# project.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of
# the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
# MA 02111-1307 USA
#
#
# File: config.mk
#
# Discription: compiler flags and make definitions
#
PLATFORM_RELFLAGS += -mrelocatable -ffixed-r14 -meabi
PLATFORM_CPPFLAGS += -DCONFIG_5xx -ffixed-r2 -ffixed-r29 -mpowerpc -msoft-float

155
cpu/mpc5xx/cpu.c Normal file
View File

@@ -0,0 +1,155 @@
/*
* (C) Copyright 2003
* Martin Winistoerfer, martinwinistoerfer@gmx.ch.
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation,
*/
/*
* File: cpu.c
*
* Discription: Some cpu specific function for watchdog,
* cpu version test, clock setting ...
*
*/
#include <common.h>
#include <watchdog.h>
#include <command.h>
#include <mpc5xx.h>
#if (defined(CONFIG_MPC555))
# define ID_STR "MPC555/556"
/*
* Check version of cpu with Processor Version Register (PVR)
*/
static int check_cpu_version (long clock, uint pvr, uint immr)
{
char buf[32];
/* The highest 16 bits should be 0x0002 for a MPC555/556 */
if ((pvr >> 16) == 0x0002) {
printf (" " ID_STR " Version %x", (pvr >> 16));
printf (" at %s MHz:", strmhz (buf, clock));
} else {
printf ("Not supported cpu version");
return -1;
}
return 0;
}
#endif /* CONFIG_MPC555 */
/*
* Check version of mpc5xx
*/
int checkcpu (void)
{
DECLARE_GLOBAL_DATA_PTR;
ulong clock = gd->cpu_clk;
uint immr = get_immr (0); /* Return full IMMR contents */
uint pvr = get_pvr (); /* Retrieve PVR register */
puts ("CPU: ");
return check_cpu_version (clock, pvr, immr);
}
/*
* Called by macro WATCHDOG_RESET
*/
#if defined(CONFIG_WATCHDOG)
void watchdog_reset (void)
{
int re_enable = disable_interrupts ();
reset_5xx_watchdog ((immap_t *) CFG_IMMR);
if (re_enable)
enable_interrupts ();
}
/*
* Will clear software reset
*/
void reset_5xx_watchdog (volatile immap_t * immr)
{
/* Use the MPC5xx Internal Watchdog */
immr->im_siu_conf.sc_swsr = 0x556c; /* Prevent SW time-out */
immr->im_siu_conf.sc_swsr = 0xaa39;
}
#endif /* CONFIG_WATCHDOG */
/*
* Get timebase clock frequency
*/
unsigned long get_tbclk (void)
{
DECLARE_GLOBAL_DATA_PTR;
volatile immap_t *immr = (volatile immap_t *) CFG_IMMR;
ulong oscclk, factor;
if (immr->im_clkrst.car_sccr & SCCR_TBS) {
return (gd->cpu_clk / 16);
}
factor = (((CFG_PLPRCR) & PLPRCR_MF_MSK) >> PLPRCR_MF_SHIFT) + 1;
oscclk = gd->cpu_clk / factor;
if ((immr->im_clkrst.car_sccr & SCCR_RTSEL) == 0 || factor > 2) {
return (oscclk / 4);
}
return (oscclk / 16);
}
/*
* Reset board
*/
int do_reset (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
{
ulong addr;
/* Interrupts off, enable reset */
__asm__ volatile (" mtspr 81, %r0 \n\t
mfmsr %r3 \n\t
rlwinm %r31,%r3,0,25,23\n\t
mtmsr %r31 \n\t");
/*
* Trying to execute the next instruction at a non-existing address
* should cause a machine check, resulting in reset
*/
#ifdef CFG_RESET_ADDRESS
addr = CFG_RESET_ADDRESS;
#else
/*
* note: when CFG_MONITOR_BASE points to a RAM address, CFG_MONITOR_BASE * - sizeof (ulong) is usually a valid address. Better pick an address
* known to be invalid on your system and assign it to CFG_RESET_ADDRESS.
* "(ulong)-1" used to be a good choice for many systems...
*/
addr = CFG_MONITOR_BASE - sizeof (ulong);
#endif
((void (*) (void)) addr) ();
return 1;
}

119
cpu/mpc5xx/cpu_init.c Normal file
View File

@@ -0,0 +1,119 @@
/*
* (C) Copyright 2003 Martin Winistoerfer, martinwinistoerfer@gmx.ch.
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation,
*/
/*
* File: cpu_init.c
*
* Discription: Contains initialisation functions to setup
* the cpu properly
*
*/
#include <common.h>
#include <mpc5xx.h>
#include <watchdog.h>
/*
* Setup essential cpu registers to run
*/
void cpu_init_f (volatile immap_t * immr)
{
volatile memctl5xx_t *memctl = &immr->im_memctl;
ulong reg;
/* SYPCR - contains watchdog control. This will enable watchdog */
/* if CONFIG_WATCHDOG is set */
immr->im_siu_conf.sc_sypcr = CFG_SYPCR;
#if defined(CONFIG_WATCHDOG)
reset_5xx_watchdog (immr);
#endif
/* SIUMCR - contains debug pin configuration */
immr->im_siu_conf.sc_siumcr |= CFG_SIUMCR;
/* Initialize timebase. Unlock TBSCRK */
immr->im_sitk.sitk_tbscrk = KAPWR_KEY;
immr->im_sit.sit_tbscr = CFG_TBSCR;
/* Full IMB bus speed */
immr->im_uimb.uimb_umcr = CFG_UMCR;
/* Time base and decrementer will be enables (TBE) */
/* in init_timebase() in time.c called from board_init_f(). */
/* Initialize the PIT. Unlock PISCRK */
immr->im_sitk.sitk_piscrk = KAPWR_KEY;
immr->im_sit.sit_piscr = CFG_PISCR;
/* PLL (CPU clock) settings */
immr->im_clkrstk.cark_plprcrk = KAPWR_KEY;
/* If CFG_PLPRCR (set in the various *_config.h files) tries to
* set the MF field, then just copy CFG_PLPRCR over car_plprcr,
* otherwise OR in CFG_PLPRCR so we do not change the currentMF
* field value.
*/
#if ((CFG_PLPRCR & PLPRCR_MF_MSK) != 0)
reg = CFG_PLPRCR; /* reset control bits */
#else
reg = immr->im_clkrst.car_plprcr;
reg &= PLPRCR_MF_MSK; /* isolate MF field */
reg |= CFG_PLPRCR; /* reset control bits */
#endif
immr->im_clkrst.car_plprcr = reg;
/* System integration timers. CFG_MASK has EBDF configuration */
immr->im_clkrstk.cark_sccrk = KAPWR_KEY;
reg = immr->im_clkrst.car_sccr;
reg &= SCCR_MASK;
reg |= CFG_SCCR;
immr->im_clkrst.car_sccr = reg;
/* Memory Controller */
memctl->memc_br0 = CFG_BR0_PRELIM;
memctl->memc_or0 = CFG_OR0_PRELIM;
#if (defined(CFG_OR1_PRELIM) && defined(CFG_BR1_PRELIM))
memctl->memc_or1 = CFG_OR1_PRELIM;
memctl->memc_br1 = CFG_BR1_PRELIM;
#endif
#if defined(CFG_OR2_PRELIM) && defined(CFG_BR2_PRELIM)
memctl->memc_or2 = CFG_OR2_PRELIM;
memctl->memc_br2 = CFG_BR2_PRELIM;
#endif
#if defined(CFG_OR3_PRELIM) && defined(CFG_BR3_PRELIM)
memctl->memc_or3 = CFG_OR3_PRELIM;
memctl->memc_br3 = CFG_BR3_PRELIM;
#endif
}
/*
* Initialize higher level parts of cpu
*/
int cpu_init_r (void)
{
/* Nothing to do at the moment */
return (0);
}

273
cpu/mpc5xx/interrupts.c Normal file
View File

@@ -0,0 +1,273 @@
/*
* (C) Copyright 2000-2002 Wolfgang Denk, DENX Software Engineering, wd@denx.de.
* (C) Copyright 2003 Martin Winistoerfer, martinwinistoerfer@gmx.ch.
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation,
*/
/*
* File: interrupt.c
*
* Discription: Contains interrupt routines needed by U-Boot
*
*/
#include <common.h>
#include <watchdog.h>
#include <mpc5xx.h>
#include <asm/processor.h>
/************************************************************************/
unsigned decrementer_count; /* count value for 1e6/HZ microseconds */
/************************************************************************/
struct interrupt_action {
interrupt_handler_t *handler;
void *arg;
};
static struct interrupt_action irq_vecs[NR_IRQS];
/*
* Local function prototypes
*/
static __inline__ unsigned long get_msr (void)
{
unsigned long msr;
asm volatile ("mfmsr %0":"=r" (msr):);
return msr;
}
static __inline__ void set_msr (unsigned long msr)
{
asm volatile ("mtmsr %0"::"r" (msr));
}
static __inline__ unsigned long get_dec (void)
{
unsigned long val;
asm volatile ("mfdec %0":"=r" (val):);
return val;
}
static __inline__ void set_dec (unsigned long val)
{
asm volatile ("mtdec %0"::"r" (val));
}
/*
* Enable interrupts
*/
void enable_interrupts (void)
{
set_msr (get_msr () | MSR_EE);
}
/*
* Returns flag if MSR_EE was set before
*/
int disable_interrupts (void)
{
ulong msr = get_msr ();
set_msr (msr & ~MSR_EE);
return ((msr & MSR_EE) != 0);
}
/*
* Initialise interrupts
*/
int interrupt_init (void)
{
volatile immap_t *immr = (immap_t *) CFG_IMMR;
/* Decrementer used here for status led */
decrementer_count = get_tbclk () / CFG_HZ;
/* Disable all interrupts */
immr->im_siu_conf.sc_simask = 0;
set_dec (decrementer_count);
set_msr (get_msr () | MSR_EE);
return (0);
}
/*
* Handle external interrupts
*/
void external_interrupt (struct pt_regs *regs)
{
volatile immap_t *immr = (immap_t *) CFG_IMMR;
int irq;
ulong simask, newmask;
ulong vec, v_bit;
/*
* read the SIVEC register and shift the bits down
* to get the irq number
*/
vec = immr->im_siu_conf.sc_sivec;
irq = vec >> 26;
v_bit = 0x80000000UL >> irq;
/*
* Read Interrupt Mask Register and Mask Interrupts
*/
simask = immr->im_siu_conf.sc_simask;
newmask = simask & (~(0xFFFF0000 >> irq));
immr->im_siu_conf.sc_simask = newmask;
if (!(irq & 0x1)) { /* External Interrupt ? */
ulong siel;
/*
* Read Interrupt Edge/Level Register
*/
siel = immr->im_siu_conf.sc_siel;
if (siel & v_bit) { /* edge triggered interrupt ? */
/*
* Rewrite SIPEND Register to clear interrupt
*/
immr->im_siu_conf.sc_sipend = v_bit;
}
}
if (irq_vecs[irq].handler != NULL) {
irq_vecs[irq].handler (irq_vecs[irq].arg);
} else {
printf ("\nBogus External Interrupt IRQ %d Vector %ld\n",
irq, vec);
/* turn off the bogus interrupt to avoid it from now */
simask &= ~v_bit;
}
/*
* Re-Enable old Interrupt Mask
*/
immr->im_siu_conf.sc_simask = simask;
}
/*
* Install and free an interrupt handler
*/
void irq_install_handler (int vec, interrupt_handler_t * handler,
void *arg)
{
volatile immap_t *immr = (immap_t *) CFG_IMMR;
/* SIU interrupt */
if (irq_vecs[vec].handler != NULL) {
printf ("SIU interrupt %d 0x%x\n",
vec,
(uint) handler);
}
irq_vecs[vec].handler = handler;
irq_vecs[vec].arg = arg;
immr->im_siu_conf.sc_simask |= 1 << (31 - vec);
#if 0
printf ("Install SIU interrupt for vector %d ==> %p\n",
vec, handler);
#endif
}
void irq_free_handler (int vec)
{
volatile immap_t *immr = (immap_t *) CFG_IMMR;
/* SIU interrupt */
#if 0
printf ("Free CPM interrupt for vector %d\n",
vec);
#endif
immr->im_siu_conf.sc_simask &= ~(1 << (31 - vec));
irq_vecs[vec].handler = NULL;
irq_vecs[vec].arg = NULL;
}
volatile ulong timestamp = 0;
/*
* Timer interrupt - gets called when bit 0 of DEC changes from
* 0. Decrementer is enabled with bit TBE in TBSCR.
*/
void timer_interrupt (struct pt_regs *regs)
{
volatile immap_t *immr = (immap_t *) CFG_IMMR;
#ifdef CONFIG_STATUS_LED
extern void status_led_tick (ulong);
#endif
#if 0
printf ("*** Timer Interrupt *** ");
#endif
/* Reset Timer Status Bit and Timers Interrupt Status */
immr->im_clkrstk.cark_plprcrk = KAPWR_KEY;
__asm__ ("nop");
immr->im_clkrst.car_plprcr |= PLPRCR_TEXPS | PLPRCR_TMIST;
/* Restore Decrementer Count */
set_dec (decrementer_count);
timestamp++;
#ifdef CONFIG_STATUS_LED
status_led_tick (timestamp);
#endif /* CONFIG_STATUS_LED */
#if defined(CONFIG_WATCHDOG)
/*
* The shortest watchdog period of all boards
* is approx. 1 sec, thus re-trigger watchdog at least
* every 500 ms = CFG_HZ / 2
*/
if ((timestamp % (CFG_HZ / 2)) == 0) {
reset_5xx_watchdog (immr);
}
#endif /* CONFIG_WATCHDOG */
}
/*
* Reset timer
*/
void reset_timer (void)
{
timestamp = 0;
}
/*
* Get Timer
*/
ulong get_timer (ulong base)
{
return (timestamp - base);
}
/*
* Set timer
*/
void set_timer (ulong t)
{
timestamp = t;
}

171
cpu/mpc5xx/serial.c Normal file
View File

@@ -0,0 +1,171 @@
/*
* (C) Copyright 2003
* Martin Winistoerfer, martinwinistoerfer@gmx.ch.
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation,
*/
/*
* File: serial.c
*
* Discription: Serial interface driver for SCI1 and SCI2.
* Since this code will be called from ROM use
* only non-static local variables.
*
*/
#include <common.h>
#include <watchdog.h>
#include <command.h>
#include <mpc5xx.h>
/*
* Local function prototypes
*/
static int ready_to_send(void);
/*
* Minimal global serial functions needed to use one of the SCI modules.
*/
int serial_init (void)
{
volatile immap_t *immr = (immap_t *)CFG_IMMR;
serial_setbrg();
#if defined(CONFIG_5xx_CONS_SCI1)
/* 10-Bit, 1 start bit, 8 data bit, no parity, 1 stop bit */
immr->im_qsmcm.qsmcm_scc1r1 = SCI_M_10;
immr->im_qsmcm.qsmcm_scc1r1 = SCI_TE | SCI_RE;
#else
immr->im_qsmcm.qsmcm_scc2r1 = SCI_M_10;
immr->im_qsmcm.qsmcm_scc2r1 = SCI_TE | SCI_RE;
#endif
return 0;
}
void serial_putc(const char c)
{
volatile immap_t *immr = (immap_t *)CFG_IMMR;
/* Test for completition */
if(ready_to_send()) {
#if defined(CONFIG_5xx_CONS_SCI1)
immr->im_qsmcm.qsmcm_sc1dr = (short)c;
#else
immr->im_qsmcm.qsmcm_sc2dr = (short)c;
#endif
if(c == '\n') {
if(ready_to_send());
#if defined(CONFIG_5xx_CONS_SCI1)
immr->im_qsmcm.qsmcm_sc1dr = (short)'\r';
#else
immr->im_qsmcm.qsmcm_sc2dr = (short)'\r';
#endif
}
}
}
int serial_getc(void)
{
volatile immap_t *immr = (immap_t *)CFG_IMMR;
volatile short status;
unsigned char tmp;
/* New data ? */
do {
#if defined(CONFIG_5xx_CONS_SCI1)
status = immr->im_qsmcm.qsmcm_sc1sr;
#else
status = immr->im_qsmcm.qsmcm_sc2sr;
#endif
#if defined(CONFIG_WATCHDOG)
reset_5xx_watchdog (immr);
#endif
} while ((status & SCI_RDRF) == 0);
/* Read data */
#if defined(CONFIG_5xx_CONS_SCI1)
tmp = (unsigned char)(immr->im_qsmcm.qsmcm_sc1dr & SCI_SCXDR_MK);
#else
tmp = (unsigned char)( immr->im_qsmcm.qsmcm_sc2dr & SCI_SCXDR_MK);
#endif
return tmp;
}
int serial_tstc()
{
volatile immap_t *immr = (immap_t *)CFG_IMMR;
short status;
/* New data character ? */
#if defined(CONFIG_5xx_CONS_SCI1)
status = immr->im_qsmcm.qsmcm_sc1sr;
#else
status = immr->im_qsmcm.qsmcm_sc2sr;
#endif
return (status & SCI_RDRF);
}
void serial_setbrg (void)
{
DECLARE_GLOBAL_DATA_PTR;
volatile immap_t *immr = (immap_t *)CFG_IMMR;
short scxbr;
/* Set baudrate */
scxbr = (gd->cpu_clk / (32 * gd->baudrate));
#if defined(CONFIG_5xx_CONS_SCI1)
immr->im_qsmcm.qsmcm_scc1r0 = (scxbr & SCI_SCXBR_MK);
#else
immr->im_qsmcm.qsmcm_scc2r0 = (scxbr & SCI_SCXBR_MK);
#endif
}
void serial_puts (const char *s)
{
while (*s) {
serial_putc(*s);
++s;
}
}
int ready_to_send(void)
{
volatile immap_t *immr = (immap_t *)CFG_IMMR;
volatile short status;
do {
#if defined(CONFIG_5xx_CONS_SCI1)
status = immr->im_qsmcm.qsmcm_sc1sr;
#else
status = immr->im_qsmcm.qsmcm_sc2sr;
#endif
#if defined(CONFIG_WATCHDOG)
reset_5xx_watchdog (immr);
#endif
} while ((status & SCI_TDRE) == 0);
return 1;
}

66
cpu/mpc5xx/speed.c Normal file
View File

@@ -0,0 +1,66 @@
/*
* (C) Copyright 2003
* Martin Winistoerfer, martinwinistoerfer@gmx.ch.
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation,
*/
/*
* File: speed.c
*
* Discription: Provides cpu speed calculation
*
*/
#include <common.h>
#include <mpc5xx.h>
#include <asm/processor.h>
/*
* Get cpu and bus clock
*/
int get_clocks (void)
{
DECLARE_GLOBAL_DATA_PTR;
volatile immap_t *immr = (immap_t *) CFG_IMMR;
#ifndef CONFIG_5xx_GCLK_FREQ
uint divf = (immr->im_clkrst.car_plprcr & PLPRCR_DIVF_MSK);
uint mf = ((immr->im_clkrst.car_plprcr & PLPRCR_MF_MSK) >> PLPRCR_MF_SHIFT);
ulong vcoout;
vcoout = (CFG_OSC_CLK / (divf + 1)) * (mf + 1) * 2;
if(immr->im_clkrst.car_plprcr & PLPRCR_CSRC_MSK) {
gd->cpu_clk = vcoout / (2^(((immr->im_clkrst.car_sccr & SCCR_DFNL_MSK) >> SCCR_DFNL_SHIFT) + 1));
} else {
gd->cpu_clk = vcoout / (2^(immr->im_clkrst.car_sccr & SCCR_DFNH_MSK));
}
#else /* CONFIG_5xx_GCLK_FREQ */
gd->bus_clk = CONFIG_5xx_GCLK_FREQ;
#endif /* CONFIG_5xx_GCLK_FREQ */
if ((immr->im_clkrst.car_sccr & SCCR_EBDF11) == 0) {
/* No Bus Divider active */
gd->bus_clk = gd->cpu_clk;
} else {
/* CLKOUT is GCLK / 2 */
gd->bus_clk = gd->cpu_clk / 2;
}
return (0);
}

629
cpu/mpc5xx/start.S Normal file
View File

@@ -0,0 +1,629 @@
/*
* Copyright (C) 1998 Dan Malek <dmalek@jlc.net>
* Copyright (C) 1999 Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se>
* Copyright (C) 2000, 2001, 2002 Wolfgang Denk <wd@denx.de>
* Copyright (C) 2003 Martin Winistoerfer, martinwinistoerfer@gmx.ch.
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
/*
* File: start.S
*
* Discription: startup code
*
*/
#include <config.h>
#include <mpc5xx.h>
#include <version.h>
#define CONFIG_5xx 1 /* needed for Linux kernel header files */
#define _LINUX_CONFIG_H 1 /* avoid reading Linux autoconf.h file */
#include <ppc_asm.tmpl>
#include <ppc_defs.h>
#include <linux/config.h>
#include <asm/processor.h>
#ifndef CONFIG_IDENT_STRING
#define CONFIG_IDENT_STRING ""
#endif
/* We don't have a MMU.
*/
#undef MSR_KERNEL
#define MSR_KERNEL ( MSR_ME | MSR_RI ) /* Machine Check and Recoverable Interr. */
/*
* Set up GOT: Global Offset Table
*
* Use r14 to access the GOT
*/
START_GOT
GOT_ENTRY(_GOT2_TABLE_)
GOT_ENTRY(_FIXUP_TABLE_)
GOT_ENTRY(_start)
GOT_ENTRY(_start_of_vectors)
GOT_ENTRY(_end_of_vectors)
GOT_ENTRY(transfer_to_handler)
GOT_ENTRY(_end)
GOT_ENTRY(.bss)
END_GOT
/*
* r3 - 1st arg to board_init(): IMMP pointer
* r4 - 2nd arg to board_init(): boot flag
*/
.text
.long 0x27051956 /* U-Boot Magic Number */
.globl version_string
version_string:
.ascii U_BOOT_VERSION
.ascii " (", __DATE__, " - ", __TIME__, ")"
.ascii CONFIG_IDENT_STRING, "\0"
. = EXC_OFF_SYS_RESET
.globl _start
_start:
mfspr r3, 638
li r4, CFG_ISB /* Set ISB bit */
or r3, r3, r4
mtspr 638, r3
li r21, BOOTFLAG_COLD /* Normal Power-On: Boot from FLASH */
b boot_cold
. = EXC_OFF_SYS_RESET + 0x20
.globl _start_warm
_start_warm:
li r21, BOOTFLAG_WARM /* Software reboot */
b boot_warm
boot_cold:
boot_warm:
/* Initialize machine status; enable machine check interrupt */
/*----------------------------------------------------------------------*/
li r3, MSR_KERNEL /* Set ME, RI flags */
mtmsr r3
mtspr SRR1, r3 /* Make SRR1 match MSR */
/* Initialize debug port registers */
/*----------------------------------------------------------------------*/
xor r0, r0, r0 /* Clear R0 */
mtspr LCTRL1, r0 /* Initialize debug port regs */
mtspr LCTRL2, r0
mtspr COUNTA, r0
mtspr COUNTB, r0
/*
* Calculate absolute address in FLASH and jump there
*----------------------------------------------------------------------*/
lis r3, CFG_MONITOR_BASE@h
ori r3, r3, CFG_MONITOR_BASE@l
addi r3, r3, in_flash - _start + EXC_OFF_SYS_RESET
mtlr r3
blr
in_flash:
/* Initialize some SPRs that are hard to access from C */
/*----------------------------------------------------------------------*/
lis r3, CFG_IMMR@h /* Pass IMMR as arg1 to C routine */
lis r2, CFG_INIT_SP_ADDR@h
ori r1, r2, CFG_INIT_SP_ADDR@l /* Set up the stack in internal SRAM */
/* Note: R0 is still 0 here */
stwu r0, -4(r1) /* Clear final stack frame so that */
stwu r0, -4(r1) /* stack backtraces terminate cleanly */
/*
* Disable serialized ifetch and show cycles
* (i.e. set processor to normal mode) for maximum
* performance.
*/
li r2, 0x0007
mtspr ICTRL, r2
/* Set up debug mode entry */
lis r2, CFG_DER@h
ori r2, r2, CFG_DER@l
mtspr DER, r2
/* Let the C-code set up the rest */
/* */
/* Be careful to keep code relocatable ! */
/*----------------------------------------------------------------------*/
GET_GOT /* initialize GOT access */
/* r3: IMMR */
bl cpu_init_f /* run low-level CPU init code (from Flash) */
mr r3, r21
/* r3: BOOTFLAG */
bl board_init_f /* run 1st part of board init code (from Flash) */
.globl _start_of_vectors
_start_of_vectors:
/* Machine check */
STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)
/* Data Storage exception. "Never" generated on the 860. */
STD_EXCEPTION(0x300, DataStorage, UnknownException)
/* Instruction Storage exception. "Never" generated on the 860. */
STD_EXCEPTION(0x400, InstStorage, UnknownException)
/* External Interrupt exception. */
STD_EXCEPTION(0x500, ExtInterrupt, external_interrupt)
/* Alignment exception. */
. = 0x600
Alignment:
EXCEPTION_PROLOG
mfspr r4,DAR
stw r4,_DAR(r21)
mfspr r5,DSISR
stw r5,_DSISR(r21)
addi r3,r1,STACK_FRAME_OVERHEAD
li r20,MSR_KERNEL
rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */
lwz r6,GOT(transfer_to_handler)
mtlr r6
blrl
.L_Alignment:
.long AlignmentException - _start + EXC_OFF_SYS_RESET
.long int_return - _start + EXC_OFF_SYS_RESET
/* Program check exception */
. = 0x700
ProgramCheck:
EXCEPTION_PROLOG
addi r3,r1,STACK_FRAME_OVERHEAD
li r20,MSR_KERNEL
rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */
lwz r6,GOT(transfer_to_handler)
mtlr r6
blrl
.L_ProgramCheck:
.long ProgramCheckException - _start + EXC_OFF_SYS_RESET
.long int_return - _start + EXC_OFF_SYS_RESET
/* FPU on MPC5xx available. We will use it later.
*/
STD_EXCEPTION(0x800, FPUnavailable, UnknownException)
/* I guess we could implement decrementer, and may have
* to someday for timekeeping.
*/
STD_EXCEPTION(0x900, Decrementer, timer_interrupt)
STD_EXCEPTION(0xa00, Trap_0a, UnknownException)
STD_EXCEPTION(0xb00, Trap_0b, UnknownException)
. = 0xc00
/*
* r0 - SYSCALL number
* r3-... arguments
*/
SystemCall:
addis r11,r0,0 /* get functions table addr */
ori r11,r11,0 /* Note: this code is patched in trap_init */
addis r12,r0,0 /* get number of functions */
ori r12,r12,0
cmplw 0, r0, r12
bge 1f
rlwinm r0,r0,2,0,31 /* fn_addr = fn_tbl[r0] */
add r11,r11,r0
lwz r11,0(r11)
li r20,0xd00-4 /* Get stack pointer */
lwz r12,0(r20)
subi r12,r12,12 /* Adjust stack pointer */
li r0,0xc00+_end_back-SystemCall
cmplw 0, r0, r12 /* Check stack overflow */
bgt 1f
stw r12,0(r20)
mflr r0
stw r0,0(r12)
mfspr r0,SRR0
stw r0,4(r12)
mfspr r0,SRR1
stw r0,8(r12)
li r12,0xc00+_back-SystemCall
mtlr r12
mtspr SRR0,r11
1: SYNC
rfi
_back:
mfmsr r11 /* Disable interrupts */
li r12,0
ori r12,r12,MSR_EE
andc r11,r11,r12
SYNC /* Some chip revs need this... */
mtmsr r11
SYNC
li r12,0xd00-4 /* restore regs */
lwz r12,0(r12)
lwz r11,0(r12)
mtlr r11
lwz r11,4(r12)
mtspr SRR0,r11
lwz r11,8(r12)
mtspr SRR1,r11
addi r12,r12,12 /* Adjust stack pointer */
li r20,0xd00-4
stw r12,0(r20)
SYNC
rfi
_end_back:
STD_EXCEPTION(0xd00, SingleStep, UnknownException)
STD_EXCEPTION(0xe00, Trap_0e, UnknownException)
STD_EXCEPTION(0xf00, Trap_0f, UnknownException)
/* On the MPC8xx, this is a software emulation interrupt. It occurs
* for all unimplemented and illegal instructions.
*/
STD_EXCEPTION(0x1000, SoftEmu, SoftEmuException)
STD_EXCEPTION(0x1100, InstructionTLBMiss, UnknownException)
STD_EXCEPTION(0x1200, DataTLBMiss, UnknownException)
STD_EXCEPTION(0x1300, InstructionTLBError, UnknownException)
STD_EXCEPTION(0x1400, DataTLBError, UnknownException)
STD_EXCEPTION(0x1500, Reserved5, UnknownException)
STD_EXCEPTION(0x1600, Reserved6, UnknownException)
STD_EXCEPTION(0x1700, Reserved7, UnknownException)
STD_EXCEPTION(0x1800, Reserved8, UnknownException)
STD_EXCEPTION(0x1900, Reserved9, UnknownException)
STD_EXCEPTION(0x1a00, ReservedA, UnknownException)
STD_EXCEPTION(0x1b00, ReservedB, UnknownException)
STD_EXCEPTION(0x1c00, DataBreakpoint, UnknownException)
STD_EXCEPTION(0x1d00, InstructionBreakpoint, DebugException)
STD_EXCEPTION(0x1e00, PeripheralBreakpoint, UnknownException)
STD_EXCEPTION(0x1f00, DevPortBreakpoint, UnknownException)
.globl _end_of_vectors
_end_of_vectors:
. = 0x2000
/*
* This code finishes saving the registers to the exception frame
* and jumps to the appropriate handler for the exception.
* Register r21 is pointer into trap frame, r1 has new stack pointer.
*/
.globl transfer_to_handler
transfer_to_handler:
stw r22,_NIP(r21)
lis r22,MSR_POW@h
andc r23,r23,r22
stw r23,_MSR(r21)
SAVE_GPR(7, r21)
SAVE_4GPRS(8, r21)
SAVE_8GPRS(12, r21)
SAVE_8GPRS(24, r21)
mflr r23
andi. r24,r23,0x3f00 /* get vector offset */
stw r24,TRAP(r21)
li r22,0
stw r22,RESULT(r21)
mtspr SPRG2,r22 /* r1 is now kernel sp */
lwz r24,0(r23) /* virtual address of handler */
lwz r23,4(r23) /* where to go when done */
mtspr SRR0,r24
mtspr SRR1,r20
mtlr r23
SYNC
rfi /* jump to handler, enable MMU */
int_return:
mfmsr r28 /* Disable interrupts */
li r4,0
ori r4,r4,MSR_EE
andc r28,r28,r4
SYNC /* Some chip revs need this... */
mtmsr r28
SYNC
lwz r2,_CTR(r1)
lwz r0,_LINK(r1)
mtctr r2
mtlr r0
lwz r2,_XER(r1)
lwz r0,_CCR(r1)
mtspr XER,r2
mtcrf 0xFF,r0
REST_10GPRS(3, r1)
REST_10GPRS(13, r1)
REST_8GPRS(23, r1)
REST_GPR(31, r1)
lwz r2,_NIP(r1) /* Restore environment */
lwz r0,_MSR(r1)
mtspr SRR0,r2
mtspr SRR1,r0
lwz r0,GPR0(r1)
lwz r2,GPR2(r1)
lwz r1,GPR1(r1)
SYNC
rfi
/*
* unsigned int get_immr (unsigned int mask)
*
* return (mask ? (IMMR & mask) : IMMR);
*/
.globl get_immr
get_immr:
mr r4,r3 /* save mask */
mfspr r3, IMMR /* IMMR */
cmpwi 0,r4,0 /* mask != 0 ? */
beq 4f
and r3,r3,r4 /* IMMR & mask */
4:
blr
.globl get_pvr
get_pvr:
mfspr r3, PVR
blr
/*------------------------------------------------------------------------------*/
/*
* void relocate_code (addr_sp, gd, addr_moni)
*
* This "function" does not return, instead it continues in RAM
* after relocating the monitor code.
*
* r3 = dest
* r4 = src
* r5 = length in bytes
* r6 = cachelinesize
*/
.globl relocate_code
relocate_code:
mr r1, r3 /* Set new stack pointer in SRAM */
mr r9, r4 /* Save copy of global data pointer in SRAM */
mr r10, r5 /* Save copy of monitor destination Address in SRAM */
mr r3, r5 /* Destination Address */
lis r4, CFG_MONITOR_BASE@h /* Source Address */
ori r4, r4, CFG_MONITOR_BASE@l
lis r5, CFG_MONITOR_LEN@h /* Length in Bytes */
ori r5, r5, CFG_MONITOR_LEN@l
/*
* Fix GOT pointer:
*
* New GOT-PTR = (old GOT-PTR - CFG_MONITOR_BASE) + Destination Address
*
* Offset:
*/
sub r15, r10, r4
/* First our own GOT */
add r14, r14, r15
/* the the one used by the C code */
add r30, r30, r15
/*
* Now relocate code
*/
cmplw cr1,r3,r4
addi r0,r5,3
srwi. r0,r0,2
beq cr1,4f /* In place copy is not necessary */
beq 4f /* 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
4: sync
isync
/*
* We are done. Do not return, instead branch to second part of board
* initialization, now running from RAM.
*/
addi r0, r10, in_ram - _start + EXC_OFF_SYS_RESET
mtlr r0
blr
in_ram:
/*
* Relocation Function, r14 point to got2+0x8000
*
* 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 r3,GOT(_GOT2_TABLE_)
lwz r11,GOT(_GOT2_TABLE_)
mtctr r0
sub r11,r3,r11
addi r3,r3,-4
1: lwzu r0,4(r3)
add r0,r0,r11
stw r0,0(r3)
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 r3,GOT(_FIXUP_TABLE_)
cmpwi r0,0
mtctr r0
addi r3,r3,-4
beq 4f
3: lwzu r4,4(r3)
lwzux r0,r4,r11
add r0,r0,r11
stw r10,0(r3)
stw r0,0(r4)
bdnz 3b
4:
clear_bss:
/*
* Now clear BSS segment
*/
lwz r3,GOT(.bss)
lwz r4,GOT(_end)
cmplw 0, r3, r4
beq 6f
li r0, 0
5:
stw r0, 0(r3)
addi r3, r3, 4
cmplw 0, r3, r4
bne 5b
6:
mr r3, r9 /* Global Data pointer */
mr r4, r10 /* Destination Address */
bl board_init_r
/* Problems accessing "end" in C, so do it here */
.globl get_endaddr
get_endaddr:
lwz r3,GOT(_end)
blr
/*
* Copy exception vector code to low memory
*
* r3: dest_addr
* r7: source address, r8: end address, r9: target address
*/
.globl trap_init
trap_init:
lwz r7, GOT(_start)
lwz r8, GOT(_end_of_vectors)
rlwinm r9, r7, 0, 22, 31 /* _start & 0x3FF */
cmplw 0, r7, r8
bgelr /* return if r7>=r8 - just in case */
mflr r4 /* save link register */
1:
lwz r0, 0(r7)
stw r0, 0(r9)
addi r7, r7, 4
addi r9, r9, 4
cmplw 0, r7, r8
bne 1b
/*
* relocate `hdlr' and `int_return' entries
*/
li r7, .L_MachineCheck - _start + EXC_OFF_SYS_RESET
li r8, Alignment - _start + EXC_OFF_SYS_RESET
2:
bl trap_reloc
addi r7, r7, 0x100 /* next exception vector */
cmplw 0, r7, r8
blt 2b
li r7, .L_Alignment - _start + EXC_OFF_SYS_RESET
bl trap_reloc
li r7, .L_ProgramCheck - _start + EXC_OFF_SYS_RESET
bl trap_reloc
li r7, .L_FPUnavailable - _start + EXC_OFF_SYS_RESET
li r8, SystemCall - _start + EXC_OFF_SYS_RESET
3:
bl trap_reloc
addi r7, r7, 0x100 /* next exception vector */
cmplw 0, r7, r8
blt 3b
li r7, .L_SingleStep - _start + EXC_OFF_SYS_RESET
li r8, _end_of_vectors - _start + EXC_OFF_SYS_RESET
4:
bl trap_reloc
addi r7, r7, 0x100 /* next exception vector */
cmplw 0, r7, r8
blt 4b
mtlr r4 /* restore link register */
blr
/*
* Function: relocate entries for one exception vector
*/
trap_reloc:
lwz r0, 0(r7) /* hdlr ... */
add r0, r0, r3 /* ... += dest_addr */
stw r0, 0(r7)
lwz r0, 4(r7) /* int_return ... */
add r0, r0, r3 /* ... += dest_addr */
stw r0, 4(r7)
sync
isync
blr

161
cpu/mpc5xx/status_led.c Normal file
View File

@@ -0,0 +1,161 @@
/*
* (C) Copyright 2000-2002 Wolfgang Denk, DENX Software Engineering, wd@denx.de
* (C) Copyright 2003 Martin Winistoerfer, martinwinistoerfer@gmx.ch.
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
/*
* File: status_led.c
*
* Discription: Blink a board led to show boot progress. Led's
* are connected via the MIOS module.
*/
#include <common.h>
#include <mpc5xx.h>
#include <status_led.h>
#ifdef CONFIG_STATUS_LED
typedef struct {
ulong mask;
int state;
int period;
int cnt;
} led_dev_t;
led_dev_t led_dev[] = {
{ STATUS_LED_BIT,
STATUS_LED_STATE,
STATUS_LED_PERIOD,
0,
},
#if defined(STATUS_LED_BIT1)
{ STATUS_LED_BIT1,
STATUS_LED_STATE1,
STATUS_LED_PERIOD1,
0,
},
#endif
#if defined(STATUS_LED_BIT2)
{ STATUS_LED_BIT2,
STATUS_LED_STATE2,
STATUS_LED_PERIOD2,
0,
},
#endif
#if defined(STATUS_LED_BIT3)
{ STATUS_LED_BIT3,
STATUS_LED_STATE3,
STATUS_LED_PERIOD3,
0,
},
#endif
};
#define MAX_LED_DEV (sizeof(led_dev)/sizeof(led_dev_t))
static int status_led_init_done = 0;
static void status_led_init (void)
{
volatile immap_t *immr = (immap_t *)CFG_IMMR;
int i;
for (i=0; i<MAX_LED_DEV; ++i) {
led_dev_t *ld = &led_dev[i];
immr->STATUS_LED_DIR = STATUS_LED_BIT;
#if (STATUS_LED_ACTIVE == 0)
if (ld->state == STATUS_LED_ON)
immr->STATUS_LED_DAT &= ~(ld->mask);
else
immr->STATUS_LED_DAT |= ld->mask ;
#else
if (ld->state == STATUS_LED_ON)
immr->STATUS_LED_DAT |= ld->mask ;
else
immr->STATUS_LED_DAT &= ~(ld->mask);
#endif
}
status_led_init_done = 1;
}
void status_led_tick (ulong timestamp)
{
volatile immap_t *immr = (immap_t *)CFG_IMMR;
int i;
if (!status_led_init_done)
status_led_init();
for (i=0; i<MAX_LED_DEV; ++i) {
led_dev_t *ld = &led_dev[i];
if (ld->state != STATUS_LED_BLINKING)
continue;
if (++(ld->cnt) >= ld->period) {
immr->STATUS_LED_DAT ^= ld->mask;
ld->cnt -= ld->period;
}
}
}
void status_led_set (int led, int state)
{
volatile immap_t *immr = (immap_t *)CFG_IMMR;
led_dev_t *ld;
if (led < 0 || led >= MAX_LED_DEV)
return;
if (!status_led_init_done)
status_led_init();
ld = &led_dev[led];
switch (state) {
default:
return;
case STATUS_LED_BLINKING:
ld->cnt = 0; /* always start with full period */
/* fall through */ /* always start with LED _ON_ */
case STATUS_LED_ON:
#if (STATUS_LED_ACTIVE == 0)
immr->STATUS_LED_DAT &= ~(ld->mask);
#else
immr->STATUS_LED_DAT |= ld->mask ;
#endif
break;
case STATUS_LED_OFF:
#if (STATUS_LED_ACTIVE == 0)
immr->STATUS_LED_DAT |= ld->mask ;
#else
immr->STATUS_LED_DAT &= ~(ld->mask);
#endif
break;
}
ld->state = state;
}
#endif /* CONFIG_STATUS_LED */

231
cpu/mpc5xx/traps.c Normal file
View File

@@ -0,0 +1,231 @@
/*
* linux/arch/ppc/kernel/traps.c
*
* Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
*
* Modified by Cort Dougan (cort@cs.nmt.edu)
* and Paul Mackerras (paulus@cs.anu.edu.au)
*
* (C) Copyright 2000
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
/*
* This file handles the architecture-dependent parts of hardware exceptions
*/
#include <common.h>
#include <command.h>
#include <asm/processor.h>
#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
int (*debugger_exception_handler)(struct pt_regs *) = 0;
#endif
#if (CONFIG_COMMANDS & CFG_CMD_BEDBUG)
extern void do_bedbug_breakpoint(struct pt_regs *);
#endif
/* Returns 0 if exception not found and fixup otherwise. */
extern unsigned long search_exception_table(unsigned long);
/* THIS NEEDS CHANGING to use the board info structure.
*/
#define END_OF_MEM 0x0001000
/*
* Print stack backtrace
*/
void print_backtrace(unsigned long *sp)
{
int cnt = 0;
unsigned long i;
printf("Call backtrace: ");
while (sp) {
if ((uint)sp > END_OF_MEM)
break;
i = sp[1];
if (cnt++ % 7 == 0)
printf("\n");
printf("%08lX ", i);
if (cnt > 32) break;
sp = (unsigned long *)*sp;
}
printf("\n");
}
/*
* Print current registers
*/
void show_regs(struct pt_regs * regs)
{
int i;
printf("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx DAR: %08lX\n",
regs->nip, regs->xer, regs->link, regs, regs->trap, regs->dar);
printf("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
regs->msr&MSR_IR ? 1 : 0,
regs->msr&MSR_DR ? 1 : 0);
printf("\n");
for (i = 0; i < 32; i++) {
if ((i % 8) == 0)
{
printf("GPR%02d: ", i);
}
printf("%08lX ", regs->gpr[i]);
if ((i % 8) == 7)
{
printf("\n");
}
}
}
/*
* General exception handler routine
*/
void _exception(int signr, struct pt_regs *regs)
{
show_regs(regs);
print_backtrace((unsigned long *)regs->gpr[1]);
panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
}
/*
* Machine check exception handler routine
*/
void MachineCheckException(struct pt_regs *regs)
{
unsigned long fixup;
/* Probing PCI using config cycles cause this exception
* when a device is not present. Catch it and return to
* the PCI exception handler.
*/
if ((fixup = search_exception_table(regs->nip)) != 0) {
regs->nip = fixup;
return;
}
#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
if (debugger_exception_handler && (*debugger_exception_handler)(regs))
return;
#endif
printf("Machine check in kernel mode.\n");
printf("Caused by (from msr): ");
printf("regs %p ",regs);
switch( regs->msr & 0x0000F000)
{
case (1<<12) :
printf("Machine check signal\n");
break;
case (1<<13) :
printf("Transfer error ack signal\n");
break;
case (1<<14) :
printf("Data parity signal\n");
break;
case (1<<15) :
printf("Address parity signal\n");
break;
default:
printf("Unknown values in msr\n");
}
show_regs(regs);
print_backtrace((unsigned long *)regs->gpr[1]);
panic("machine check");
}
/*
* Alignment exception handler routine
*/
void AlignmentException(struct pt_regs *regs)
{
#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
if (debugger_exception_handler && (*debugger_exception_handler)(regs))
return;
#endif
show_regs(regs);
print_backtrace((unsigned long *)regs->gpr[1]);
panic("Alignment Exception");
}
/*
* Program check exception handler routine
*/
void ProgramCheckException(struct pt_regs *regs)
{
#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
if (debugger_exception_handler && (*debugger_exception_handler)(regs))
return;
#endif
show_regs(regs);
print_backtrace((unsigned long *)regs->gpr[1]);
panic("Program Check Exception");
}
/*
* Software emulation exception handler routine
*/
void SoftEmuException(struct pt_regs *regs)
{
#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
if (debugger_exception_handler && (*debugger_exception_handler)(regs))
return;
#endif
show_regs(regs);
print_backtrace((unsigned long *)regs->gpr[1]);
panic("Software Emulation Exception");
}
/*
* Unknown exception handler routine
*/
void UnknownException(struct pt_regs *regs)
{
#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
if (debugger_exception_handler && (*debugger_exception_handler)(regs))
return;
#endif
printf("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
regs->nip, regs->msr, regs->trap);
_exception(0, regs);
}
/*
* Debug exception handler routine
*/
void DebugException(struct pt_regs *regs)
{
printf("Debugger trap at @ %lx\n", regs->nip );
show_regs(regs);
#if (CONFIG_COMMANDS & CFG_CMD_BEDBUG)
do_bedbug_breakpoint( regs );
#endif
}