diff options
Diffstat (limited to 'arch/powerpc/cpu/mpc5xx')
| -rw-r--r-- | arch/powerpc/cpu/mpc5xx/Makefile | 59 | ||||
| -rw-r--r-- | arch/powerpc/cpu/mpc5xx/config.mk | 36 | ||||
| -rw-r--r-- | arch/powerpc/cpu/mpc5xx/cpu.c | 171 | ||||
| -rw-r--r-- | arch/powerpc/cpu/mpc5xx/cpu_init.c | 123 | ||||
| -rw-r--r-- | arch/powerpc/cpu/mpc5xx/interrupts.c | 207 | ||||
| -rw-r--r-- | arch/powerpc/cpu/mpc5xx/serial.c | 170 | ||||
| -rw-r--r-- | arch/powerpc/cpu/mpc5xx/speed.c | 67 | ||||
| -rw-r--r-- | arch/powerpc/cpu/mpc5xx/spi.c | 412 | ||||
| -rw-r--r-- | arch/powerpc/cpu/mpc5xx/start.S | 576 | ||||
| -rw-r--r-- | arch/powerpc/cpu/mpc5xx/traps.c | 227 | ||||
| -rw-r--r-- | arch/powerpc/cpu/mpc5xx/u-boot.lds | 137 | 
11 files changed, 2185 insertions, 0 deletions
| diff --git a/arch/powerpc/cpu/mpc5xx/Makefile b/arch/powerpc/cpu/mpc5xx/Makefile new file mode 100644 index 000000000..80c53203e --- /dev/null +++ b/arch/powerpc/cpu/mpc5xx/Makefile @@ -0,0 +1,59 @@ +# +# (C) Copyright 2006 +# 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:			arch/powerpc/cpu/mpc5xx/Makefile +# +# Discription:		Makefile to build mpc5xx cpu configuration. +#			Will include top config.mk which itselfs +#			uses the definitions made in arch/powerpc/cpu/mpc5xx/config.mk +# + + +include $(TOPDIR)/config.mk + +LIB	= $(obj)lib$(CPU).a + +START	= start.o +COBJS	= serial.o cpu.o cpu_init.o interrupts.o traps.o speed.o spi.o + +SRCS	:= $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c) +OBJS	:= $(addprefix $(obj),$(SOBJS) $(COBJS)) +START	:= $(addprefix $(obj),$(START)) + +all:	$(obj).depend $(START) $(LIB) + +$(LIB):	$(OBJS) +	$(AR) $(ARFLAGS) $@ $(OBJS) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/arch/powerpc/cpu/mpc5xx/config.mk b/arch/powerpc/cpu/mpc5xx/config.mk new file mode 100644 index 000000000..5f9285df4 --- /dev/null +++ b/arch/powerpc/cpu/mpc5xx/config.mk @@ -0,0 +1,36 @@ +# +# (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 +=	-fPIC -meabi + +PLATFORM_CPPFLAGS +=	-DCONFIG_5xx -ffixed-r2 -mpowerpc -msoft-float + +# Use default linker script.  Board port can override in board/*/config.mk +LDSCRIPT := $(SRCTREE)/arch/powerpc/cpu/mpc5xx/u-boot.lds diff --git a/arch/powerpc/cpu/mpc5xx/cpu.c b/arch/powerpc/cpu/mpc5xx/cpu.c new file mode 100644 index 000000000..7fffebcc1 --- /dev/null +++ b/arch/powerpc/cpu/mpc5xx/cpu.c @@ -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:		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> + +DECLARE_GLOBAL_DATA_PTR; + +#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) +{ +	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 *) CONFIG_SYS_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) +{ +	volatile immap_t *immr = (volatile immap_t *) CONFIG_SYS_IMMR; +	ulong oscclk, factor; + +	if (immr->im_clkrst.car_sccr & SCCR_TBS) { +		return (gd->cpu_clk / 16); +	} + +	factor = (((CONFIG_SYS_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); +} + +void dcache_enable (void) +{ +	return; +} + +void dcache_disable (void) +{ +	return; +} + +int dcache_status (void) +{ +	return 0;	/* always off */ +} + +/* + * Reset board + */ +int do_reset (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) +{ +#if defined(CONFIG_PATI) +	volatile ulong *addr = (ulong *) CONFIG_SYS_RESET_ADDRESS; +	*addr = 1; +#else +	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 CONFIG_SYS_RESET_ADDRESS +	addr = CONFIG_SYS_RESET_ADDRESS; +#else +	/* +	 * note: when CONFIG_SYS_MONITOR_BASE points to a RAM address, CONFIG_SYS_MONITOR_BASE         * - sizeof (ulong) is usually a valid address. Better pick an address +	 * known to be invalid on your system and assign it to CONFIG_SYS_RESET_ADDRESS. +	 * "(ulong)-1" used to be a good choice for many systems... +	 */ +	addr = CONFIG_SYS_MONITOR_BASE - sizeof (ulong); +#endif +	((void (*) (void)) addr) (); +#endif  /* #if defined(CONFIG_PATI) */ +	return 1; +} diff --git a/arch/powerpc/cpu/mpc5xx/cpu_init.c b/arch/powerpc/cpu/mpc5xx/cpu_init.c new file mode 100644 index 000000000..cb4bf8473 --- /dev/null +++ b/arch/powerpc/cpu/mpc5xx/cpu_init.c @@ -0,0 +1,123 @@ +/* + * (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 = CONFIG_SYS_SYPCR; + +#if defined(CONFIG_WATCHDOG) +	reset_5xx_watchdog (immr); +#endif + +	/* SIUMCR - contains debug pin configuration */ +	immr->im_siu_conf.sc_siumcr |= CONFIG_SYS_SIUMCR; + +	/* Initialize timebase. Unlock TBSCRK */ +	immr->im_sitk.sitk_tbscrk = KAPWR_KEY; +	immr->im_sit.sit_tbscr = CONFIG_SYS_TBSCR; + +	/* Full IMB bus speed */ +	immr->im_uimb.uimb_umcr = CONFIG_SYS_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 = CONFIG_SYS_PISCR; + +#if !defined(CONFIG_PATI) +	/* PATI sest PLL in start.S */ +	/* PLL (CPU clock) settings */ +	immr->im_clkrstk.cark_plprcrk = KAPWR_KEY; + +	/* If CONFIG_SYS_PLPRCR (set in the various *_config.h files) tries to +	 * set the MF field, then just copy CONFIG_SYS_PLPRCR over car_plprcr, +	 * otherwise OR in CONFIG_SYS_PLPRCR so we do not change the currentMF +	 * field value. +	 */ +#if ((CONFIG_SYS_PLPRCR & PLPRCR_MF_MSK) != 0) +	reg = CONFIG_SYS_PLPRCR;			/* reset control bits   */ +#else +	reg = immr->im_clkrst.car_plprcr; +	reg &= PLPRCR_MF_MSK;			/* isolate MF field */ +	reg |= CONFIG_SYS_PLPRCR;			/* reset control bits   */ +#endif +	immr->im_clkrst.car_plprcr = reg; + +#endif /* !defined(CONFIG_PATI) */ + +	/* System integration timers. CONFIG_SYS_MASK has EBDF configuration */ +	immr->im_clkrstk.cark_sccrk = KAPWR_KEY; +	reg = immr->im_clkrst.car_sccr; +	reg &= SCCR_MASK; +	reg |= CONFIG_SYS_SCCR; +	immr->im_clkrst.car_sccr = reg; + +	/* Memory Controller */ +	memctl->memc_br0 = CONFIG_SYS_BR0_PRELIM; +	memctl->memc_or0 = CONFIG_SYS_OR0_PRELIM; + +#if (defined(CONFIG_SYS_OR1_PRELIM) && defined(CONFIG_SYS_BR1_PRELIM)) +	memctl->memc_or1 = CONFIG_SYS_OR1_PRELIM; +	memctl->memc_br1 = CONFIG_SYS_BR1_PRELIM; +#endif + +#if defined(CONFIG_SYS_OR2_PRELIM) && defined(CONFIG_SYS_BR2_PRELIM) +	memctl->memc_or2 = CONFIG_SYS_OR2_PRELIM; +	memctl->memc_br2 = CONFIG_SYS_BR2_PRELIM; +#endif + +#if defined(CONFIG_SYS_OR3_PRELIM) && defined(CONFIG_SYS_BR3_PRELIM) +	memctl->memc_or3 = CONFIG_SYS_OR3_PRELIM; +	memctl->memc_br3 = CONFIG_SYS_BR3_PRELIM; +#endif + +} + +/* + * Initialize higher level parts of cpu + */ +int cpu_init_r (void) +{ +	/* Nothing to do at the moment */ +	return (0); +} diff --git a/arch/powerpc/cpu/mpc5xx/interrupts.c b/arch/powerpc/cpu/mpc5xx/interrupts.c new file mode 100644 index 000000000..167543fcf --- /dev/null +++ b/arch/powerpc/cpu/mpc5xx/interrupts.c @@ -0,0 +1,207 @@ +/* + * (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 <command.h> +#include <mpc5xx.h> +#include <asm/processor.h> + +#if defined(CONFIG_PATI) +/* PATI uses IRQs for PCI doorbell */ +#undef NR_IRQS +#define NR_IRQS 16 +#endif + +struct interrupt_action { +	interrupt_handler_t *handler; +	void *arg; +	int count; +}; + +static struct interrupt_action irq_vecs[NR_IRQS]; + +/* + * Initialise interrupts + */ + +int interrupt_init_cpu (ulong *decrementer_count) +{ +	volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR; +	int vec; + +	/* Decrementer used here for status led */ +	*decrementer_count = get_tbclk () / CONFIG_SYS_HZ; + +	/* Disable all interrupts */ +	immr->im_siu_conf.sc_simask = 0; +	for (vec=0; vec<NR_IRQS; vec++) { +		irq_vecs[vec].handler = NULL; +		irq_vecs[vec].arg = NULL; +		irq_vecs[vec].count = 0; +	} + +	return (0); +} + +/* + * Handle external interrupts + */ +void external_interrupt (struct pt_regs *regs) +{ +	volatile immap_t *immr = (immap_t *) CONFIG_SYS_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 *) CONFIG_SYS_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 *) CONFIG_SYS_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; +} + +/* + *  Timer interrupt - gets called when  bit 0 of DEC changes from + *  0. Decrementer is enabled with bit TBE in TBSCR. + */ +void timer_interrupt_cpu (struct pt_regs *regs) +{ +	volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR; + +#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; + +	return; +} + +#if defined(CONFIG_CMD_IRQ) +/******************************************************************************* + * + * irqinfo - print information about IRQs + * + */ +int do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ +	int vec; + +	printf ("\nInterrupt-Information:\n"); +	printf ("Nr  Routine   Arg       Count\n"); + +	for (vec=0; vec<NR_IRQS; vec++) { +		if (irq_vecs[vec].handler != NULL) { +			printf ("%02d  %08lx  %08lx  %d\n", +				vec, +				(ulong)irq_vecs[vec].handler, +				(ulong)irq_vecs[vec].arg, +				irq_vecs[vec].count); +		} +	} +	return 0; +} + + +#endif diff --git a/arch/powerpc/cpu/mpc5xx/serial.c b/arch/powerpc/cpu/mpc5xx/serial.c new file mode 100644 index 000000000..88c6db81c --- /dev/null +++ b/arch/powerpc/cpu/mpc5xx/serial.c @@ -0,0 +1,170 @@ +/* + * (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> + +DECLARE_GLOBAL_DATA_PTR; + +/* + * 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 *)CONFIG_SYS_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 *)CONFIG_SYS_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 *)CONFIG_SYS_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 *)CONFIG_SYS_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) +{ +	volatile immap_t *immr = (immap_t *)CONFIG_SYS_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 *)CONFIG_SYS_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; + +} diff --git a/arch/powerpc/cpu/mpc5xx/speed.c b/arch/powerpc/cpu/mpc5xx/speed.c new file mode 100644 index 000000000..ea5c1dead --- /dev/null +++ b/arch/powerpc/cpu/mpc5xx/speed.c @@ -0,0 +1,67 @@ +/* + * (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> + +DECLARE_GLOBAL_DATA_PTR; + +/* + * Get cpu and bus clock + */ +int get_clocks (void) +{ +	volatile immap_t *immr = (immap_t *) CONFIG_SYS_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 = (CONFIG_SYS_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); +} diff --git a/arch/powerpc/cpu/mpc5xx/spi.c b/arch/powerpc/cpu/mpc5xx/spi.c new file mode 100644 index 000000000..3ca15ea83 --- /dev/null +++ b/arch/powerpc/cpu/mpc5xx/spi.c @@ -0,0 +1,412 @@ +/* + * Copyright (c) 2001 Navin Boppuri / Prashant Patel + *	<nboppuri@trinetcommunication.com>, + *	<pmpatel@trinetcommunication.com> + * Copyright (c) 2001 Gerd Mennchen <Gerd.Mennchen@icn.siemens.de> + * Copyright (c) 2001 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 + */ + +/* + * MPC5xx CPM SPI interface. + * + * Parts of this code are probably not portable and/or specific to + * the board which I used for the tests. Please send fixes/complaints + * to wd@denx.de + * + * Ported to MPC5xx + * Copyright (c) 2003 Denis Peter, MPL AG Switzerland, d.petr@mpl.ch. + */ + +#include <common.h> +#include <mpc5xx.h> +#include <asm/5xx_immap.h> +#include <linux/ctype.h> +#include <malloc.h> +#include <post.h> +#include <net.h> + +#if defined(CONFIG_SPI) + +#undef	DEBUG + +#define SPI_EEPROM_WREN		0x06 +#define SPI_EEPROM_RDSR		0x05 +#define SPI_EEPROM_READ		0x03 +#define SPI_EEPROM_WRITE	0x02 + + +#ifdef	DEBUG + +#define	DPRINT(a)	printf a; +/* ----------------------------------------------- + * Helper functions to peek into tx and rx buffers + * ----------------------------------------------- */ +static const char * const hex_digit = "0123456789ABCDEF"; + +static char quickhex (int i) +{ +	return hex_digit[i]; +} + +static void memdump (void *pv, int num) +{ +	int i; +	unsigned char *pc = (unsigned char *) pv; + +	for (i = 0; i < num; i++) +		printf ("%c%c ", quickhex (pc[i] >> 4), quickhex (pc[i] & 0x0f)); +	printf ("\t"); +	for (i = 0; i < num; i++) +		printf ("%c", isprint (pc[i]) ? pc[i] : '.'); +	printf ("\n"); +} +#else	/* !DEBUG */ + +#define	DPRINT(a) + +#endif	/* DEBUG */ + +/* ------------------- + * Function prototypes + * ------------------- */ +void spi_init (void); + +ssize_t spi_read (uchar *, int, uchar *, int); +ssize_t spi_write (uchar *, int, uchar *, int); +ssize_t spi_xfer (size_t); + + +/* ************************************************************************** + * + *  Function:    spi_init_f + * + *  Description: Init SPI-Controller (ROM part) + * + *  return:      --- + * + * *********************************************************************** */ + +void spi_init_f (void) +{ +	int i; + +	volatile immap_t *immr; +	volatile qsmcm5xx_t *qsmcm; + +	immr = (immap_t *)  CONFIG_SYS_IMMR; +	qsmcm = (qsmcm5xx_t *)&immr->im_qsmcm; + +	qsmcm->qsmcm_qsmcr = 0; /* all accesses enabled */ +	qsmcm->qsmcm_qspi_il = 0; /* lowest IRQ */ + +	/* -------------------------------------------- +	 * GPIO or per. Function +	 * PQSPAR[00] = 0 reserved +	 * PQSPAR[01] = 1 [0x4000] -> PERI: (SPICS3) +	 * PQSPAR[02] = 0 [0x0000] -> GPIO +	 * PQSPAR[03] = 0 [0x0000] -> GPIO +	 * PQSPAR[04] = 1 [0x0800] -> PERI: (SPICS0) +	 * PQSPAR[05] = 0 reseved +	 * PQSPAR[06] = 1 [0x0200] -> PERI: (SPIMOSI) +	 * PQSPAR[07] = 1 [0x0100] -> PERI: (SPIMISO) +	 * -------------------------------------------- */ +	qsmcm->qsmcm_pqspar =  0x3 | (CONFIG_SYS_SPI_CS_USED << 3); + +	 /* -------------------------------------------- +	 * DDRQS[00] = 0 reserved +	 * DDRQS[01] = 1 [0x0040] -> SPICS3 Output +	 * DDRQS[02] = 0 [0x0000] -> GPIO Output +	 * DDRQS[03] = 0 [0x0000] -> GPIO Output +	 * DDRQS[04] = 1 [0x0008] -> SPICS0 Output +	 * DDRQS[05] = 1 [0x0004] -> SPICLK Output +	 * DDRQS[06] = 1 [0x0002] -> SPIMOSI Output +	 * DDRQS[07] = 0 [0x0001] -> SPIMISO Input +	 * -------------------------------------------- */ +	qsmcm->qsmcm_ddrqs = 0x7E; +	 /* -------------------------------------------- +	 * Base state for used SPI CS pins, if base = 0 active must be 1 +	 * PORTQS[00] = 0 reserved +	 * PORTQS[01] = 0 reserved +	 * PORTQS[02] = 0 reserved +	 * PORTQS[03] = 0 reserved +	 * PORTQS[04] = 0 [0x0000] RxD2 +	 * PORTQS[05] = 1 [0x0400] TxD2 +	 * PORTQS[06] = 0 [0x0000] RxD1 +	 * PORTQS[07] = 1 [0x0100] TxD1 +	 * PORTQS[08] = 0 reserved +	 * PORTQS[09] = 0 [0x0000] -> SPICS3 Base Output +	 * PORTQS[10] = 0 [0x0000] -> SPICS2 Base Output +	 * PORTQS[11] = 0 [0x0000] -> SPICS1 Base Output +	 * PORTQS[12] = 0 [0x0000] -> SPICS0 Base Output +	 * PORTQS[13] = 0 [0x0004] -> SPICLK Output +	 * PORTQS[14] = 0 [0x0002] -> SPIMOSI Output +	 * PORTQS[15] = 0 [0x0001] -> SPIMISO Input +	 * -------------------------------------------- */ +	qsmcm->qsmcm_portqs |= (CONFIG_SYS_SPI_CS_BASE << 3); +	/* -------------------------------------------- +	 * Controll Register 0 +	 * SPCR0[00] = 1 (0x8000) Master +	 * SPCR0[01] = 0 (0x0000) Wired-Or +	 * SPCR0[2..5] = (0x2000) Bits per transfer (default 8) +	 * SPCR0[06] = 0 (0x0000) Normal polarity +	 * SPCR0[07] = 0 (0x0000) Normal Clock Phase +	 * SPCR0[08..15] = 14 1.4MHz +	 */ +	qsmcm->qsmcm_spcr0=0xA00E; +	/* -------------------------------------------- +	 * Controll Register 1 +	 * SPCR1[00] = 0 (0x0000) QSPI enabled +	 * SPCR1[1..7] =  (0x7F00) Delay before Transfer +	 * SPCR1[8..15] = (0x0000) Delay After transfer (204.8usec@40MHz) +	 */ +	qsmcm->qsmcm_spcr1=0x7F00; +	/* -------------------------------------------- +	 * Controll Register 2 +	 * SPCR2[00] = 0 (0x0000) SPI IRQs Disabeld +	 * SPCR2[01] = 0 (0x0000) No Wrap around +	 * SPCR2[02] = 0 (0x0000) Wrap to 0 +	 * SPCR2[3..7] = (0x0000) End Queue pointer = 0 +	 * SPCR2[8..10] = 0 (0x0000) reserved +	 * SPCR2[11..15] = 0 (0x0000) NewQueue Address = 0 +	 */ +	qsmcm->qsmcm_spcr2=0x0000; +	/* -------------------------------------------- +	 * Controll Register 3 +	 * SPCR3[00..04] = 0 (0x0000) reserved +	 * SPCR3[05] = 0 (0x0000) Feedback disabled +	 * SPCR3[06] = 0 (0x0000) IRQ on HALTA & MODF disabled +	 * SPCR3[07] = 0 (0x0000) Not halted +	 */ +	qsmcm->qsmcm_spcr3=0x00; +	/* -------------------------------------------- +	 * SPSR (Controll Register 3) Read only/ reset Flags 08,09,10 +	 * SPCR3[08] = 1 (0x80) QSPI finished +	 * SPCR3[09] = 1 (0x40) Mode Fault Flag +	 * SPCR3[10] = 1 (0x20) HALTA +	 * SPCR3[11..15] = 0 (0x0000) Last executed command +	 */ +	qsmcm->qsmcm_spsr=0xE0; +	/*------------------------------------------- +	 * Setup RAM +	 */ +	for(i=0;i<32;i++) { +		 qsmcm->qsmcm_recram[i]=0x0000; +		 qsmcm->qsmcm_tranram[i]=0x0000; +		 qsmcm->qsmcm_comdram[i]=0x00; +	} +	return; +} + +/* ************************************************************************** + * + *  Function:    spi_init_r + *  Dummy, all initializations have been done in spi_init_r + * *********************************************************************** */ +void spi_init_r (void) +{ +	return; + +} + +/**************************************************************************** + *  Function:    spi_write + **************************************************************************** */ +ssize_t short_spi_write (uchar *addr, int alen, uchar *buffer, int len) +{ +	int i,dlen; +	volatile immap_t *immr; +	volatile qsmcm5xx_t *qsmcm; + +	immr = (immap_t *)  CONFIG_SYS_IMMR; +	qsmcm = (qsmcm5xx_t *)&immr->im_qsmcm; +	for(i=0;i<32;i++) { +		 qsmcm->qsmcm_recram[i]=0x0000; +		 qsmcm->qsmcm_tranram[i]=0x0000; +		 qsmcm->qsmcm_comdram[i]=0x00; +	} +	qsmcm->qsmcm_tranram[0] =  SPI_EEPROM_WREN; /* write enable */ +	spi_xfer(1); +	i=0; +	qsmcm->qsmcm_tranram[i++] =  SPI_EEPROM_WRITE; /* WRITE memory array */ +	qsmcm->qsmcm_tranram[i++] =  addr[0]; +	qsmcm->qsmcm_tranram[i++] =  addr[1]; + +	for(dlen=0;dlen<len;dlen++) { +		qsmcm->qsmcm_tranram[i+dlen] = buffer[dlen]; /* WRITE memory array */ +	} +	/* transmit it */ +	spi_xfer(i+dlen); +	/* ignore received data	*/ +	for (i = 0; i < 1000; i++) { +		qsmcm->qsmcm_tranram[0] =  SPI_EEPROM_RDSR; /* read status */ +		qsmcm->qsmcm_tranram[1] = 0; +		spi_xfer(2); +		if (!(qsmcm->qsmcm_recram[1] & 1)) { +			break; +		} +		udelay(1000); +	} +	if (i >= 1000) { +		printf ("*** spi_write: Time out while writing!\n"); +	} +	return len; +} + +#define TRANSFER_LEN 16 + +ssize_t spi_write (uchar *addr, int alen, uchar *buffer, int len) +{ +	int index,i,newlen; +	uchar newaddr[2]; +	int curraddr; + +	curraddr=(addr[alen-2]<<8)+addr[alen-1]; +	i=len; +	index=0; +	do { +		newaddr[1]=(curraddr & 0xff); +		newaddr[0]=((curraddr>>8) & 0xff); +		if(i>TRANSFER_LEN) { +			newlen=TRANSFER_LEN; +			i-=TRANSFER_LEN; +		} +		else { +			newlen=i; +			i=0; +		} +		short_spi_write (newaddr, 2, &buffer[index], newlen); +		index+=newlen; +		curraddr+=newlen; +	}while(i); +	return (len); +} + +/**************************************************************************** + *  Function:    spi_read + **************************************************************************** */ +ssize_t short_spi_read (uchar *addr, int alen, uchar *buffer, int len) +{ +	int i; +	volatile immap_t *immr; +	volatile qsmcm5xx_t *qsmcm; + +	immr = (immap_t *)  CONFIG_SYS_IMMR; +	qsmcm = (qsmcm5xx_t *)&immr->im_qsmcm; + +	for(i=0;i<32;i++) { +		 qsmcm->qsmcm_recram[i]=0x0000; +		 qsmcm->qsmcm_tranram[i]=0x0000; +		 qsmcm->qsmcm_comdram[i]=0x00; +	} +	i=0; +	qsmcm->qsmcm_tranram[i++] = (SPI_EEPROM_READ); /* READ memory array */ +	qsmcm->qsmcm_tranram[i++] = addr[0] & 0xff; +	qsmcm->qsmcm_tranram[i++] = addr[1] & 0xff; +	spi_xfer(3 + len); +	for(i=0;i<len;i++) { +		*buffer++=(char)qsmcm->qsmcm_recram[i+3]; +	} +	return len; +} + +ssize_t spi_read (uchar *addr, int alen, uchar *buffer, int len) +{ +	int index,i,newlen; +	uchar newaddr[2]; +	int curraddr; + +	curraddr=(addr[alen-2]<<8)+addr[alen-1]; +	i=len; +	index=0; +	do { +		newaddr[1]=(curraddr & 0xff); +		newaddr[0]=((curraddr>>8) & 0xff); +		if(i>TRANSFER_LEN) { +			newlen=TRANSFER_LEN; +			i-=TRANSFER_LEN; +		} +		else { +			newlen=i; +			i=0; +		} +		short_spi_read (newaddr, 2, &buffer[index], newlen); +		index+=newlen; +		curraddr+=newlen; +	}while(i); +	return (len); +} + +/**************************************************************************** + *  Function:    spi_xfer + **************************************************************************** */ +ssize_t spi_xfer (size_t count) +{ +	volatile immap_t *immr; +	volatile qsmcm5xx_t *qsmcm; +	int i; +	int tm; +	ushort status; +	immr = (immap_t *)  CONFIG_SYS_IMMR; +	qsmcm = (qsmcm5xx_t *)&immr->im_qsmcm; +	DPRINT (("*** spi_xfer entered count %d***\n",count)); + +	/* Set CS for device */ +	for(i=0;i<(count-1);i++) +		qsmcm->qsmcm_comdram[i] = 0x80 | CONFIG_SYS_SPI_CS_ACT;  /* CS3 is connected to the SPI EEPROM */ + +	qsmcm->qsmcm_comdram[i] = CONFIG_SYS_SPI_CS_ACT; /* CS3 is connected to the SPI EEPROM */ +	qsmcm->qsmcm_spcr2=((count-1)&0x1F)<<8; + +	DPRINT (("*** spi_xfer: Bytes to be xferred: %d ***\n", count)); + +	qsmcm->qsmcm_spsr=0xE0; /* clear all flags */ + +	/* start spi transfer */ +	DPRINT (("*** spi_xfer: Performing transfer ...\n")); +	qsmcm->qsmcm_spcr1 |= 0x8000;		/* Start transmit */ + +	/* -------------------------------- +	 * Wait for SPI transmit to get out +	 * or time out (1 second = 1000 ms) +	 * -------------------------------- */ +	for (tm=0; tm<1000; ++tm) { +		status=qsmcm->qsmcm_spcr1; +		if((status & 0x8000)==0) +			break; +		udelay (1000); +	} +	if (tm >= 1000) { +		printf ("*** spi_xfer: Time out while xferring to/from SPI!\n"); +	} +#ifdef	DEBUG +	printf ("\nspi_xfer: txbuf after xfer\n"); +	memdump ((void *) qsmcm->qsmcm_tranram, 32);	/* dump of txbuf before transmit */ +	printf ("spi_xfer: rxbuf after xfer\n"); +	memdump ((void *) qsmcm->qsmcm_recram, 32);	/* dump of rxbuf after transmit */ +	printf ("\nspi_xfer: commbuf after xfer\n"); +	memdump ((void *) qsmcm->qsmcm_comdram, 32);	/* dump of txbuf before transmit */ +	printf ("\n"); +#endif + +	return count; +} + +#endif	/* CONFIG_SPI  */ diff --git a/arch/powerpc/cpu/mpc5xx/start.S b/arch/powerpc/cpu/mpc5xx/start.S new file mode 100644 index 000000000..0af879e39 --- /dev/null +++ b/arch/powerpc/cpu/mpc5xx/start.S @@ -0,0 +1,576 @@ +/* + *  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 <timestamp.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 r12 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(__init_end) +	GOT_ENTRY(_end) +	GOT_ENTRY(__bss_start) +	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 " (", U_BOOT_DATE, " - ", U_BOOT_TIME, ")" +	.ascii CONFIG_IDENT_STRING, "\0" + +	. = EXC_OFF_SYS_RESET +	.globl	_start +_start: +	mfspr	r3, 638 +	li	r4, CONFIG_SYS_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 + +#if defined(CONFIG_PATI) +	/* the external flash access on PATI fails if programming the PLL to 40MHz. +	 * Copy the PLL programming code to the internal RAM and execute it +	 *----------------------------------------------------------------------*/ +	lis	r3, CONFIG_SYS_MONITOR_BASE@h +	ori	r3, r3, CONFIG_SYS_MONITOR_BASE@l +	addi	r3, r3, pll_prog_code_start - _start + EXC_OFF_SYS_RESET + +	lis	r4, CONFIG_SYS_INIT_RAM_ADDR@h +	ori	r4, r4, CONFIG_SYS_INIT_RAM_ADDR@l +	mtlr	r4 +	addis	r5,0,0x0 +	ori	r5,r5,((pll_prog_code_end - pll_prog_code_start) >>2) +	mtctr	r5 +	addi	r3, r3, -4 +	addi	r4, r4, -4 +0: +	lwzu	r0,4(r3) +	stwu	r0,4(r4) +	bdnz	0b                /* copy loop */ +	blrl +#endif + +	/* +	 * Calculate absolute address in FLASH and jump there +	 *----------------------------------------------------------------------*/ + +	lis	r3, CONFIG_SYS_MONITOR_BASE@h +	ori	r3, r3, CONFIG_SYS_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, CONFIG_SYS_IMMR@h			/* Pass IMMR as arg1 to C routine */ +	lis	r2, CONFIG_SYS_INIT_SP_ADDR@h +	ori	r1, r2, CONFIG_SYS_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, CONFIG_SYS_DER@h +	ori	r2, r2, CONFIG_SYS_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(SRR0, SRR1) +	mfspr	r4,DAR +	stw	r4,_DAR(r21) +	mfspr	r5,DSISR +	stw	r5,_DSISR(r21) +	addi	r3,r1,STACK_FRAME_OVERHEAD +	EXC_XFER_TEMPLATE(Alignment, AlignmentException, MSR_KERNEL, COPY_EE) + +/* Program check exception */ +	. = 0x700 +ProgramCheck: +	EXCEPTION_PROLOG(SRR0, SRR1) +	addi	r3,r1,STACK_FRAME_OVERHEAD +	EXC_XFER_TEMPLATE(ProgramCheck, ProgramCheckException, +		MSR_KERNEL, COPY_EE) + +	/* 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) +	STD_EXCEPTION(0xc00, SystemCall, UnknownException) +	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 */ + +	GET_GOT +	mr	r3,  r5				/* Destination Address	*/ +	lis	r4, CONFIG_SYS_MONITOR_BASE@h		/* Source      Address	*/ +	ori	r4, r4, CONFIG_SYS_MONITOR_BASE@l +	lwz	r5, GOT(__init_end) +	sub	r5, r5, r4 + +	/* +	 * Fix GOT pointer: +	 * +	 * New GOT-PTR = (old GOT-PTR - CONFIG_SYS_MONITOR_BASE) + Destination Address +	 * +	 * Offset: +	 */ +	sub	r15, r10, r4 + +	/* First our own GOT */ +	add	r12, r12, 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, r12 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) +	cmpwi	r0,0 +	beq-	2f +	add	r0,r0,r11 +	stw	r0,0(r3) +2:	bdnz	1b + +	/* +	 * Now adjust the fixups and the pointers to the fixups +	 * in case we need to move ourselves again. +	 */ +	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_start) +	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 + +	/* +	 * Copy exception vector code to low memory +	 * +	 * r3: dest_addr +	 * r7: source address, r8: end address, r9: target address +	 */ +	.globl	trap_init +trap_init: +	mflr	r4			/* save link register		*/ +	GET_GOT +	lwz	r7, GOT(_start) +	lwz	r8, GOT(_end_of_vectors) + +	li	r9, 0x100		/* reset vector always at 0x100 */ + +	cmplw	0, r7, r8 +	bgelr				/* return if r7>=r8 - just in case */ +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 + +#if defined(CONFIG_PATI) +/* Program the PLL */ +pll_prog_code_start: +	lis	r4, (CONFIG_SYS_IMMR + 0x002fc384)@h +	ori	r4, r4, (CONFIG_SYS_IMMR + 0x002fc384)@l +	lis	r3, (0x55ccaa33)@h +	ori	r3, r3, (0x55ccaa33)@l +	stw	r3, 0(r4) +	lis	r4, (CONFIG_SYS_IMMR + 0x002fc284)@h +	ori	r4, r4, (CONFIG_SYS_IMMR + 0x002fc284)@l +	lis	r3, CONFIG_SYS_PLPRCR@h +	ori	r3, r3, CONFIG_SYS_PLPRCR@l +	stw	r3, 0(r4) +	addis	r3,0,0x0 +	ori	r3,r3,0xA000 +	mtctr	r3 +..spinlp: +  bdnz    ..spinlp                /* spin loop */ +	blr +pll_prog_code_end: +	nop +	blr +#endif diff --git a/arch/powerpc/cpu/mpc5xx/traps.c b/arch/powerpc/cpu/mpc5xx/traps.c new file mode 100644 index 000000000..e3ce11b2b --- /dev/null +++ b/arch/powerpc/cpu/mpc5xx/traps.c @@ -0,0 +1,227 @@ +/* + * linux/arch/powerpc/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 <kgdb.h> +#include <asm/processor.h> + +#if defined(CONFIG_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 defined(CONFIG_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 & 0x000F0000) { +	case (0x80000000>>12): +		printf("Machine check signal\n"); +		break; +	case (0x80000000>>13): +		printf("Transfer error ack signal\n"); +		break; +	case (0x80000000>>14): +		printf("Data parity signal\n"); +		break; +	case (0x80000000>>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 defined(CONFIG_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 defined(CONFIG_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 defined(CONFIG_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 defined(CONFIG_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 defined(CONFIG_CMD_BEDBUG) +	do_bedbug_breakpoint( regs ); +#endif +} diff --git a/arch/powerpc/cpu/mpc5xx/u-boot.lds b/arch/powerpc/cpu/mpc5xx/u-boot.lds new file mode 100644 index 000000000..d5e5dc178 --- /dev/null +++ b/arch/powerpc/cpu/mpc5xx/u-boot.lds @@ -0,0 +1,137 @@ +/* + * (C) Copyright 2001	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 + */ + +OUTPUT_ARCH(powerpc) +/* Do we need any of these for elf? +   __DYNAMIC = 0;    */ +SECTIONS +{ +  /* Read-only sections, merged into text segment: */ +  . = + SIZEOF_HEADERS; +  .interp : { *(.interp) } +  .hash          : { *(.hash)		} +  .dynsym        : { *(.dynsym)		} +  .dynstr        : { *(.dynstr)		} +  .rel.text      : { *(.rel.text)		} +  .rela.text     : { *(.rela.text)	} +  .rel.data      : { *(.rel.data)		} +  .rela.data     : { *(.rela.data)	} +  .rel.rodata    : { *(.rel.rodata)	} +  .rela.rodata   : { *(.rela.rodata)	} +  .rel.got       : { *(.rel.got)		} +  .rela.got      : { *(.rela.got)		} +  .rel.ctors     : { *(.rel.ctors)	} +  .rela.ctors    : { *(.rela.ctors)	} +  .rel.dtors     : { *(.rel.dtors)	} +  .rela.dtors    : { *(.rela.dtors)	} +  .rel.bss       : { *(.rel.bss)		} +  .rela.bss      : { *(.rela.bss)		} +  .rel.plt       : { *(.rel.plt)		} +  .rela.plt      : { *(.rela.plt)		} +  .init          : { *(.init)	} +  .plt : { *(.plt) } +  .text      : +  { +    /* WARNING - the following is hand-optimized to fit within	*/ +    /* the sector layout of our flash chips!	XXX FIXME XXX	*/ + +    arch/powerpc/cpu/mpc5xx/start.o	(.text) + +    *(.text) +    *(.got1) +  } +  _etext = .; +  PROVIDE (etext = .); +  .rodata    : +  { +    *(.eh_frame) +    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) +  } +  .fini      : { *(.fini)    } =0 +  .ctors     : { *(.ctors)   } +  .dtors     : { *(.dtors)   } + +  /* Read-write section, merged into data segment: */ +  . = (. + 0x00FF) & 0xFFFFFF00; +  _erotext = .; +  PROVIDE (erotext = .); +  .reloc   : +  { +    *(.got) +    _GOT2_TABLE_ = .; +    *(.got2) +    _FIXUP_TABLE_ = .; +    *(.fixup) +  } +  __got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >>2; +  __fixup_entries = (. - _FIXUP_TABLE_)>>2; + +  .data    : +  { +    *(.data) +    *(.data1) +    *(.sdata) +    *(.sdata2) +    *(.dynamic) +    CONSTRUCTORS +  } +  _edata  =  .; +  PROVIDE (edata = .); + +  . = .; +  __u_boot_cmd_start = .; +  .u_boot_cmd : { *(.u_boot_cmd) } +  __u_boot_cmd_end = .; + + +  . = .; +  __start___ex_table = .; +  __ex_table : { *(__ex_table) } +  __stop___ex_table = .; + +  . = ALIGN(256); +  __init_begin = .; +  .text.init : { *(.text.init) } +  .data.init : { *(.data.init) } +  . = ALIGN(256); +  __init_end = .; + +  __bss_start = .; +  .bss (NOLOAD)       : +  { +   *(.sbss) *(.scommon) +   *(.dynbss) +   *(.bss) +   *(COMMON) +   . = ALIGN(4); +  } + +  _end = . ; +  PROVIDE (end = .); +/*   . = env_start; +	.ppcenv	: +	{ +		common/env_embedded.o (.ppcenv) +	} +*/ +} |