diff options
| -rw-r--r-- | board/cray/L1/L1.c | 302 | ||||
| -rw-r--r-- | board/cray/L1/L1.h | 44 | ||||
| -rw-r--r-- | board/evb64260/local.h | 60 | ||||
| -rw-r--r-- | board/genietv/genietv.h | 25 | ||||
| -rw-r--r-- | board/pn62/pn62.h | 161 | ||||
| -rw-r--r-- | common/cmd_bedbug.c | 424 | ||||
| -rw-r--r-- | common/cmd_bootm.c | 931 | ||||
| -rw-r--r-- | common/console.c | 532 | ||||
| -rw-r--r-- | cpu/74xx_7xx/start.S | 860 | ||||
| -rw-r--r-- | cpu/mpc8260/start.S | 1092 | 
10 files changed, 4431 insertions, 0 deletions
| diff --git a/board/cray/L1/L1.c b/board/cray/L1/L1.c new file mode 100644 index 000000000..f5dfba4aa --- /dev/null +++ b/board/cray/L1/L1.c @@ -0,0 +1,302 @@ +/* + * (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 + */ + +#include <common.h> +#include <asm/processor.h> +#include <405gp_i2c.h> +#include <command.h> +#include <cmd_nvedit.h> +#include <cmd_bootm.h> +#include <rtc.h> +#include <net.h> +#include <malloc.h> + +#define L1_MEMSIZE (32*1024*1024) + +/* the std. DHCP stufff */ +#define DHCP_ROUTER       3 +#define DHCP_NETMASK      1 +#define DHCP_BOOTFILE     67 +#define DHCP_ROOTPATH     17 +#define DHCP_HOSTNAME     12 + +/* some extras used by CRAY + * + * on the server this looks like: + * + * option L1-initrd-image code 224 = string; + * option L1-initrd-image "/opt/craysv2/craymcu/l1/flash/initrd.image" + */ +#define DHCP_L1_INITRD  224 + +/* new, [better?] way via official vendor-extensions, defining an option + * space. + * on the server this looks like: + * + * option space U-Boot; + * option U-Boot.initrd    code 3 = string; + * option U-Boot.bootcmd   code 4 = string; + * option U-Boot.bootflags code 5 = string; + * option U-Boot.rootdev   code 6 = string; + */ +#define DHCP_VENDOR_SPECX   43 +#define DHCP_VX_INITRD       3 +#define DHCP_VX_BOOTCMD      4 +#define DHCP_VX_BOOTFLAGS    5 +#define DHCP_VX_ROOTDEV      6 + +/* Things DHCP server can tellme about.  If there's no flash address, then + * they dont participate in 'update' to flash, and we force their values + * back to '0' every boot to be sure to get them fresh from DHCP.  Yes, I + * know this is a pain... + * + * If I get no bootfile, boot from flash.  If rootpath, use that.  If no + * rootpath use initrd in flash. + */ +typedef struct dhcp_item_s { +	u8 dhcp_option; +	u8 dhcp_vendor_option; +	char *dhcpvalue; +	char *envname; +} dhcp_item_t; +static dhcp_item_t Things[] = { +	{DHCP_ROUTER, 0, NULL, "gateway"}, +	{DHCP_NETMASK, 0, NULL, "netmask"}, +	{DHCP_BOOTFILE, 0, NULL, "bootfile"}, +	{DHCP_ROOTPATH, 0, NULL, "rootpath"}, +	{DHCP_HOSTNAME, 0, NULL, "hostname"}, +	{DHCP_L1_INITRD, 0, NULL, "initrd"}, +/* and the other way.. */ +	{DHCP_VENDOR_SPECX, DHCP_VX_INITRD, NULL, "initrd"}, +	{DHCP_VENDOR_SPECX, DHCP_VX_BOOTCMD, NULL, "bootcmd"}, +	{DHCP_VENDOR_SPECX, DHCP_VX_BOOTFLAGS, NULL, NULL}, +	{DHCP_VENDOR_SPECX, DHCP_VX_ROOTDEV, NULL, NULL}, +}; + +#define N_THINGS ((sizeof(Things))/(sizeof(dhcp_item_t))) + +static void init_ecc_sdram (void); + +/* ------------------------------------------------------------------------- */ +int board_pre_init (void) +{ +	init_ecc_sdram (); +	mtdcr (uicsr, 0xFFFFFFFF);	/* clear all ints */ +	mtdcr (uicer, 0x00000000);	/* disable all ints */ +	mtdcr (uiccr, 0x00000020);	/* set all but FPGA SMI to be non-critical */ +	mtdcr (uicpr, 0xFFFFFFE0);	/* set int polarities */ +	mtdcr (uictr, 0x10000000);	/* set int trigger levels */ +	mtdcr (uicvcr, 0x00000001);	/* set vect base=0,INT0 highest priority */ +	mtdcr (uicsr, 0xFFFFFFFF);	/* clear all ints */ +	return 0; +} + +/* ------------------------------------------------------------------------- */ +int checkboard (void) +{ +	return (0); +} + +/* ------------------------------------------------------------------------- */ +int misc_init_r (void) +{ +	unsigned char *s, *e; +	image_header_t *hdr; +	time_t timestamp; +	struct rtc_time tm; + +	hdr = (image_header_t *) (CFG_MONITOR_BASE - sizeof (image_header_t)); +	timestamp = (time_t) hdr->ih_time; +	to_tm (timestamp, &tm); +	printf ("Welcome to U-Boot on Cray L1. Compiled %4d-%02d-%02d  %2d:%02d:%02d (UTC)\n", tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); + +#define FACTORY_SETTINGS 0xFFFC0000 +	if ((s = getenv ("ethaddr")) == NULL) { +		e = (unsigned char *) (FACTORY_SETTINGS); +		if (*(e + 0) != '0' +			|| *(e + 1) != '0' +			|| *(e + 2) != ':' +			|| *(e + 3) != '4' || *(e + 4) != '0' || *(e + 17) != '\0') { +			printf ("No valid MAC address in flash location 0x3C0000!\n"); +		} else { +			printf ("Factory MAC: %s\n", e); +			setenv ("ethaddr", e); +		} +	} +	return (0); +} + +/* ------------------------------------------------------------------------- */ +long int initdram (int board_type) +{ +	return (L1_MEMSIZE); +} + +/* ------------------------------------------------------------------------- */ +/* stubs so we can print dates w/o any nvram RTC.*/ +void rtc_get (struct rtc_time *tmp) +{ +	return; +} +void rtc_set (struct rtc_time *tmp) +{ +	return; +} +void rtc_reset (void) +{ +	return; +} + +/* ------------------------------------------------------------------------- */ +/*  Do sdram bank init in C so I can read it.. + */ +static void init_ecc_sdram (void) +{ +	unsigned long tmp, *p; + +	/* write SDRAM bank 0 register */ +	mtdcr (memcfga, mem_mb0cf); +	mtdcr (memcfgd, 0x00062001); + +/* Set the SDRAM Timing reg, SDTR1 and the refresh timer reg, RTR.	*/ +/* To set the appropriate timings, we need to know the SDRAM speed.	*/ +/* We can use the PLB speed since the SDRAM speed is the same as	*/ +/* the PLB speed. The PLB speed is the FBK divider times the		*/ +/* 405GP reference clock, which on the L1 is 25Mhz.			*/ +/* Thus, if FBK div is 2, SDRAM is 50Mhz; if FBK div is 3, SDRAM is	*/ +/* 150Mhz; if FBK is 3, SDRAM is 150Mhz.				*/ + +	/* divisor = ((mfdcr(strap)>> 28) & 0x3); */ + +/* write SDRAM timing for 100Mhz. */ +	mtdcr (memcfga, mem_sdtr1); +	mtdcr (memcfgd, 0x0086400D); + +/* write SDRAM refresh interval register */ +	mtdcr (memcfga, mem_rtr); +	mtdcr (memcfgd, 0x05F00000); +	udelay (200); + +/* sdram controller.*/ +	mtdcr (memcfga, mem_mcopt1); +	mtdcr (memcfgd, 0x90800000); +	udelay (200); + +/* disable ECC on all banks */ +	mtdcr (memcfga, mem_ecccf); +	tmp = mfdcr (memcfgd); +	tmp &= 0xff0fffff; +	mtdcr (memcfga, mem_ecccf); +	mtdcr (memcfgd, tmp); + +/* set up SDRAM Controller with ECC enabled */ +	mtdcr (memcfga, mem_mcopt1); +	tmp = (mfdcr (memcfgd) & ~0xFFE00000) | 0x90800000; +	mtdcr (memcfga, mem_mcopt1); +	mtdcr (memcfgd, tmp); +	udelay (600); + +/* fill all the memory */ +	for (p = (unsigned long) 0; ((unsigned long) p < L1_MEMSIZE); +		 *p++ = 0L); +	udelay (400); +	mtdcr (memcfga, mem_ecccf); +	tmp = mfdcr (memcfgd); + +/* enable ECC on bank 0 */ +	tmp |= 0x00800000; +	mtdcr (memcfgd, tmp); +	udelay (400); + +	return; +} + +/* ------------------------------------------------------------------------- */ +static u8 *dhcp_env_update (u8 thing, u8 * pop) +{ +	u8 i, oplen; + +	oplen = *(pop + 1); + +	if ((Things[thing].dhcpvalue = malloc (oplen)) == NULL) { +		printf ("Whoops! failed to malloc space for DHCP thing %s\n", +				Things[thing].envname); +		return NULL; +	} +	for (i = 0; (i < oplen); i++) +		if ((*(Things[thing].dhcpvalue + i) = *(pop + 2 + i)) == ' ') +			break; +	*(Things[thing].dhcpvalue + i) = '\0'; + +/* set env. */ +	if (Things[thing].envname) +		setenv (Things[thing].envname, Things[thing].dhcpvalue); +	return (Things[thing].dhcpvalue); +} + +/* ------------------------------------------------------------------------- */ +u8 *dhcp_vendorex_prep (u8 * e) +{ +	u8 thing; + +/* ask for the things I want. */ +	*e++ = 55;					/* Parameter Request List */ +	*e++ = N_THINGS; +	for (thing = 0; thing < N_THINGS; thing++) +		*e++ = Things[thing].dhcp_option; +	*e++ = 255; + +	return e; +} + +/* ------------------------------------------------------------------------- */ +/* .. return NULL means it wasnt mine, non-null means I got it..*/ +u8 *dhcp_vendorex_proc (u8 * pop) +{ +	u8 oplen, *sub_op, sub_oplen, *retval; +	u8 thing = 0; + +	retval = NULL; +	oplen = *(pop + 1); +/* if pop is vender spec indicator, there are sub-options. */ +	if (*pop == DHCP_VENDOR_SPECX) { +		for (sub_op = pop + 2; +		     oplen && (sub_oplen = *(sub_op + 1)); +		     oplen -= sub_oplen, sub_op += (sub_oplen + 2)) { +			for (thing = 0; thing < N_THINGS; thing++) { +			    if (*sub_op == Things[thing].dhcp_vendor_option) { +				if (!(retval = dhcp_env_update (thing, sub_op))) { +					return NULL; +				} +			    } +			} +		} +	} else { +		for (thing = 0; thing < N_THINGS; thing++) { +			if (*pop == Things[thing].dhcp_option) +				if (!(retval = dhcp_env_update (thing, pop))) +					return NULL; +		} +	} +	return (thing >= N_THINGS ? NULL : pop); +} diff --git a/board/cray/L1/L1.h b/board/cray/L1/L1.h new file mode 100644 index 000000000..1b4182448 --- /dev/null +++ b/board/cray/L1/L1.h @@ -0,0 +1,44 @@ +/* + * (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 + */ + +/**************************************************************************** + * FLASH Memory Map as used by CRAY L1, 4MB AMD29F032B flash chip + * + *                          Start Address    Length + * +++++++++++++++++++++++++ 0xFFC0_0000     Start of Flash ----------------- + * | Failsafe Linux Image  | 	(1M) + * +=======================+ 0xFFD0_0000 + * | (Reserved FlashFiles) |	(1M) + * +=======================+ 0xFFE0_0000 + * | Failsafe RootFS       |	(1M) + * +=======================+ 0xFFF0_0000 + * |                       | + * | U N U S E D           | + * |                       | + * +-----------------------+ 0xFFFD_0000	U-Boot image header (64 bytes) + * | environment settings  | 	(64k) + * +-----------------------+ 0xFFFE_0000	U-Boot image header (64 bytes) + * | U-Boot                | 0xFFFE_0040    _start of U-Boot + * |                       | 0xFFFE_FFFC    reset vector - branch to _start + * +++++++++++++++++++++++++ 0xFFFF_FFFF     End of Flash ----------------- + *****************************************************************************/ diff --git a/board/evb64260/local.h b/board/evb64260/local.h new file mode 100644 index 000000000..6d1fb4cda --- /dev/null +++ b/board/evb64260/local.h @@ -0,0 +1,60 @@ +/* + * include/local.h - local configuration options, board specific + */ + +#ifndef __LOCAL_H +#define __LOCAL_H + +/* + * High Level Configuration Options + * (easy to change) + */ + +/* This tells U-Boot that the config options are compiled in */ +/* #undef ENV_IS_EMBEDDED */ +/* Don't touch this! U-Boot figures this out  based on other + * magic. */ + +/* Uncomment and define any of the below options */ + +/* #define CONFIG_750CX */ /* The 750CX doesn't support as many things in L2CR */ +			/* Note: If you defined CONFIG_EVB64260_750CX this */ +			/* gets defined automatically. */ + +/* These want string arguments */ +/* #define CONFIG_BOOTARGS */ +/* #define CONFIG_BOOTCOMMAND */ +/* #define CONFIG_RAMBOOTCOMMAND */ +/* #define CONFIG_NFSBOOTCOMMAND */ +/* #define CFG_AUTOLOAD */ +/* #define CONFIG_PREBOOT */ + +/* These don't */ + +/* #define CONFIG_BOOTDELAY  */ +/* #define CONFIG_BAUDRATE */ +/* #define CONFIG_LOADS_ECHO */ +/* #define CONFIG_ETHADDR */ +/* #define CONFIG_ETH2ADDR */ +/* #define CONFIG_ETH3ADDR */ +/* #define CONFIG_IPADDR */ +/* #define CONFIG_SERVERIP */ +/* #define CONFIG_ROOTPATH */ +/* #define CONFIG_GATEWAYIP */ +/* #define CONFIG_NETMASK */ +/* #define CONFIG_HOSTNAME */ +/* #define CONFIG_BOOTFILE */ +/* #define CONFIG_LOADADDR */ + +/* these hardware addresses are pretty bogus, please change them to +   suit your needs */ + +/* first ethernet */ +#define CONFIG_ETHADDR          00:11:22:33:44:55 + +/* next two ethernet hwaddrs */ +#define CONFIG_ETH1ADDR		00:11:22:33:44:66 +#define CONFIG_ETH2ADDR		00:11:22:33:44:77 + +#define CONFIG_ENV_OVERWRITE +#endif	/* __CONFIG_H */ diff --git a/board/genietv/genietv.h b/board/genietv/genietv.h new file mode 100644 index 000000000..7c95b566f --- /dev/null +++ b/board/genietv/genietv.h @@ -0,0 +1,25 @@ +/* + * The GENIETV is using the following physical memorymap (copied from + * the FADS configuration): + * + * ff020000 -> ff02ffff : pcmcia + * ff010000 -> ff01ffff : BCSR       connected to CS1, setup by 8xxROM + * ff000000 -> ff00ffff : IMAP       internal in the cpu + * 02800000 -> 0287ffff : flash      connected to CS0 + * 00000000 -> nnnnnnnn : sdram      setup by U-Boot + * + * CS pins are connected as follows: + * + * CS0 -512Kb boot flash + * CS1 - SDRAM #1 + * CS2 - SDRAM #2 + * CS3 - Flash #1 + * CS4 - Flash #2 + * CS5 - LON (if present) + * CS6 - PCMCIA #1 + * CS7 - PCMCIA #2 + * + * Ports are configured as follows: + * + * PA7 - SDRAM banks enable + */ diff --git a/board/pn62/pn62.h b/board/pn62/pn62.h new file mode 100644 index 000000000..7bda0ad9d --- /dev/null +++ b/board/pn62/pn62.h @@ -0,0 +1,161 @@ +/* + * (C) Copyright 2002 Wolfgang Grandegger <wg@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 + */ + +#ifndef _PN62_H_ +#define _PN62_H_ + +/* + * Definitions for the Intel Bridge 21554 or 21555. + */ +#define I2155X_VPD_ADDR 	0xe6 +#define I2155X_VPD_DATA 	0xe8 + +#define I2155X_VPD_START	0x80 +#define I2155X_VPD_SN_START	0x80 +#define I2155X_VPD_SN_SIZE	0x10 +#define I2155X_VPD_MAC0_START	0x90 +#define I2155X_VPD_MAC1_START	0x96 + +#define I2155X_SCRAPAD_ADDR	0xa8 +#define I2155X_SCRAPAD_MAX	8 + +#define I2155X_BAR2_BASE	0x98 +#define I2155X_BAR3_BASE	0x9c +#define I2155X_BAR4_BASE	0xa0 + +#define I2155X_BAR2_SETUP	0xb0 +#define I2155X_BAR3_SETUP	0xb4 +#define I2155X_BAR4_SETUP	0xb8 + +/* + * Interrupt request numbers + */ +#define PN62_IRQ_HOST		0x0 +#define PN62_IRQ_PLX9054	0x1 +#define PN62_IRQ_ETH0		0x2 +#define PN62_IRQ_ETH1		0x3 +#define PN62_IRQ_COM1		0x4 +#define PN62_IRQ_COM2		0x4 + +/* + * Miscellaneous definitons. + */ +#define PN62_SMEM_DEFAULT	0x1f00000 + +/* + * Definitions for boot protocol using Scratchpad registers. + */ +#define BOOT_DONE		0 +#define BOOT_DONE_CLEAR  	  0x00dead00 +#define BOOT_DONE_ERROR  	  0xbad0dead +#define BOOT_DONE_U_BOOT 	  0x12345678 +#define BOOT_DONE_LINUX   	  0x87654321 +#define BOOT_CMD 		1 +#define BOOT_CMD_MOVE   	  0x1 +#define BOOT_CMD_BOOT		  0x2 +#define BOOT_DATA		2 +#define BOOT_PROTO		3 +#define BOOT_PROTO_READY	  0x23456789 +#define BOOT_PROTO_CLEAR	  0x00000000 +#define BOOT_STATUS		4 + +/* + * LED Definitions: + */ +#define PN62_LED_BASE		0xff800300 +#define PN62_LED_MAX		12 + +/* + * LED0 - 7 mounted on top of board, D1 - D8 + * LED8 - 11 upper four LEDs on the front panel of the board. + */ +#define LED_0			0x00	/* OFF */ +#define LED_1			0x01	/* ON */ +#define LED_SLOW_CLOCK		0x02	/* SLOW 1Hz ish */ +#define LED_nSLOW_CLOCK		0x03	/* inverse of above */ +#define LED_WATCHDOG_OUT	0x06	/* Reset Watchdog level */ +#define LED_WATCHDOG_CLOCK	0x07	/* clock to watchdog */ + +/* + * LED's currently setup in AMD79C973 device as the following: + * LED0 100Mbit + * LED1 LNKSE + * LED2 TX Activity + * LED3 RX Activity + */ +#define LED_E0_LED0		0x08	/* Ethernet Port 0 LED 0 */ +#define LED_E0_LED1		0x09	/* Ethernet Port 0 LED 1 */ +#define LED_E0_LED2		0x0A	/* Ethernet Port 0 LED 2 */ +#define LED_E0_LED3		0x0B	/* Ethernet Port 0 LED 3 */ +#define LED_E1_LED0		0x0C	/* Ethernet Port 1 LED 0 */ +#define LED_E1_LED1		0x0D	/* Ethernet Port 1 LED 1 */ +#define LED_E1_LED2		0x0E	/* Ethernet Port 1 LED 2 */ +#define LED_E1_LED3		0x0F	/* Ethernet Port 1 LED 3 */ +#define LED_STROBE0		0x10	/* Processor Strobe 0 */ +#define LED_STROBE1		0x11	/* Processor Strobe 1 */ +#define LED_STROBE2		0x12	/* Processor Strobe 2 */ +#define LED_STROBE3		0x13	/* Processor Strobe 3 */ +#define LED_STROBE4		0x14	/* Processor Strobe 4 */ +#define LED_STROBE5		0x15	/* Processor Strobe 5 */ +#define LED_STROBE6		0x16	/* Processor Strobe 6 */ +#define LED_STROBE7		0x17	/* Processor Strobe 7 */ +#define LED_HOST_STROBE0	0x18	/* Host strobe 0 */ +#define LED_HOST_STROBE1	0x19	/* Host strobe 1 */ +#define LED_HOST_STROBE2	0x1A	/* Host strobe 2 */ +#define LED_HOST_STROBE3	0x1B	/* Host strobe 3 */ +#define LED_HOST_STROBE4	0x1C	/* Host strobe 4 */ +#define LED_HOST_STROBE5	0x1D	/* Host strobe 5 */ +#define LED_HOST_STROBE6	0x1E	/* Host strobe 6 */ +#define LED_HOST_STROBE7	0x1F	/* Host strobe 7 */ +#define LED_MPC_INT0		0x20	/* MPC8240 INT 0 */ +#define LED_MPC_INT1		0x21	/* MPC8240 INT 1 */ +#define	LED_MPC_INT2		0x22	/* MPC8240 INT 2 */ +#define	LED_MPC_INT3		0x23	/* MPC8240 INT 3 */ +#define	LED_MPC_INT4		0x24	/* MPC8240 INT 4 */ +#define	LED_UART0_CS		0x25	/* UART 0 Chip Select */ +#define	LED_UART1_CS		0x26	/* UART 1 Chip Select */ +#define	LED_SRAM_CS		0x27	/* SRAM Chip Select */ +#define	LED_SRAM_WR		0x28	/* SRAM WR Signal */ +#define	LED_SRAM_RD		0x29	/* SRAM RD Signal */ +#define	LED_MPC_RCS0		0x2A	/* MPC8240 RCS0 Signal */ +#define	LED_S_PCI_FRAME		0x2B	/* Secondary PCI Frame Signal */ +#define	LED_MPC_CS0		0x2C	/* MPC8240 CS0 Signal */ +#define	LED_HOST_INT		0x2D	/* MPC8240 to Host Interrupt signal */ +#define LED_LAST_FUNCTION	LED_HOST_INT	/* last function */ + +/* + * Forward declarations + */ +int  i2155x_init         (void); +void i2155x_write_scrapad(int idx, u32 val); +u32  i2155x_read_scrapad (int idx); +void i2155x_set_bar_base (int bar, u32 addr); +int  i2155x_read_vpd     (int offset, int size, unsigned char *data); + +int  am79c95x_init	 (void); + +void set_led             (unsigned int number, unsigned int function); +void fatal_error	 (unsigned int error_code); +void show_startup_phase  (int phase); + + +#endif /* _PN62_H_ */ diff --git a/common/cmd_bedbug.c b/common/cmd_bedbug.c new file mode 100644 index 000000000..75b74d50b --- /dev/null +++ b/common/cmd_bedbug.c @@ -0,0 +1,424 @@ +/* + * BedBug Functions + */ + +#include <common.h> +#include <command.h> +#include <linux/ctype.h> +#include <net.h> + +#include <cmd_bedbug.h> +#include <bedbug/bedbug.h> +#include <bedbug/regs.h> +#include <bedbug/ppc.h> +#include <elf.h> + +#if (CONFIG_COMMANDS & CFG_CMD_BEDBUG) + +#ifndef MAX +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#endif + +extern void show_regs __P((struct pt_regs*)); +extern int  run_command __P((const char*, int)); +extern char console_buffer[]; + +ulong	      dis_last_addr = 0;        /* Last address disassembled   */ +ulong	      dis_last_len = 20;        /* Default disassembler length */ +CPU_DEBUG_CTX bug_ctx;                  /* Bedbug context structure    */ + + +/* ====================================================================== + * U-Boot's puts function does not append a newline, so the bedbug stuff + * will use this for the output of the dis/assembler. + * ====================================================================== */ + +int bedbug_puts(const char *str) +{ +  /* -------------------------------------------------- */ + +  printf( "%s\r\n", str ); +  return 0; +} /* bedbug_puts */ + + + +/* ====================================================================== + * Initialize the bug_ctx structure used by the bedbug debugger.  This is + * specific to the CPU since each has different debug registers and + * settings. + * ====================================================================== */ + +void bedbug_init( void ) +{ +  /* -------------------------------------------------- */ + +#if defined(CONFIG_4xx) +  void bedbug405_init( void ); +  bedbug405_init(); +#elif defined(CONFIG_MPC860) +  void bedbug860_init( void ); +  bedbug860_init(); +#endif + +#if defined(CONFIG_MPC824X) || defined(CONFIG_MPC8260) +  /* Processors that are 603e core based */ +  void bedbug603e_init( void ); + +  bedbug603e_init(); +#endif + +  return; +} /* bedbug_init */ + + + +/* ====================================================================== + * Entry point from the interpreter to the disassembler.  Repeated calls + * will resume from the last disassembled address. + * ====================================================================== */ +int do_bedbug_dis (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ +  ulong	addr;   /* Address to start disassembly from    */ +  ulong	len;    /* # of instructions to disassemble     */ +  /* -------------------------------------------------- */ + +  /* Setup to go from the last address if none is given */ +  addr = dis_last_addr; +  len  = dis_last_len; + +  if (argc < 2) +  { +    printf ("Usage:\n%s\n", cmdtp->usage); +    return 1; +  } + +  if(( flag & CMD_FLAG_REPEAT ) == 0 ) +  { +    /* New command */ +    addr = simple_strtoul( argv[1], NULL, 16 ); + +    /* If an extra param is given then it is the length */ +    if( argc > 2 ) +      len = simple_strtoul( argv[2], NULL, 16 ); +  } + +  /* Run the disassembler */ +  disppc( (unsigned char *)addr, 0, len, bedbug_puts, F_RADHEX ); + +  dis_last_addr = addr + (len * 4); +  dis_last_len = len; +  return 0; +} /* do_bedbug_dis */ + + + +/* ====================================================================== + * Entry point from the interpreter to the assembler.  Assembles + * instructions in consecutive memory locations until a '.' (period) is + * entered on a line by itself. + * ====================================================================== */ +int do_bedbug_asm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ +  long		mem_addr;               /* Address to assemble into     */ +  unsigned long instr;                  /* Machine code for text        */ +  char		prompt[ 15 ];           /* Prompt string for user input */ +  int		asm_err;                /* Error code from the assembler*/ +  /* -------------------------------------------------- */ +   int          rcode = 0; + +  if (argc < 2) +  { +    printf ("Usage:\n%s\n", cmdtp->usage); +    return 1; +  } + +  printf( "\nEnter '.' when done\n" ); +  mem_addr = simple_strtoul( argv[ 1 ], NULL, 16 ); + +  while( 1 ) +  { +    putc( '\n' ); +    disppc( (unsigned char *)mem_addr, 0, 1, bedbug_puts, F_RADHEX ); + +    sprintf( prompt, "%08lx:    ", mem_addr ); +    readline( prompt ); + +    if( console_buffer[ 0 ] && strcmp( console_buffer, "." )) +    { +      if(( instr = asmppc( mem_addr, console_buffer, &asm_err )) != 0 ) +      { +	*(unsigned long *)mem_addr = instr; +	mem_addr += 4; +      } +      else +      { +	printf( "*** Error: %s ***\n", asm_error_str( asm_err )); +        rcode = 1; +      } +    } +    else +    { +      break; +    } +  } +  return rcode; +} /* do_bedbug_asm */ + + + +/* ====================================================================== + * Used to set a break point from the interpreter.  Simply calls into the + * CPU-specific break point set routine. + * ====================================================================== */ + +int do_bedbug_break (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ +  /* -------------------------------------------------- */ +  if( bug_ctx.do_break ) +    (*bug_ctx.do_break)( cmdtp, flag, argc, argv ); +    return 0; + +} /* do_bedbug_break */ + + + +/* ====================================================================== + * Called from the debug interrupt routine.  Simply calls the CPU-specific + * breakpoint handling routine. + * ====================================================================== */ + +void do_bedbug_breakpoint (struct pt_regs *regs) +{ +  /* -------------------------------------------------- */ + +  if( bug_ctx.break_isr ) +    (*bug_ctx.break_isr)( regs ); + +  return; +} /* do_bedbug_breakpoint */ + + + +/* ====================================================================== + * Called from the CPU-specific breakpoint handling routine.  Enter a + * mini main loop until the stopped flag is cleared from the breakpoint + * context. + * + * This handles the parts of the debugger that are common to all CPU's. + * ====================================================================== */ + +void bedbug_main_loop( unsigned long addr, struct pt_regs *regs ) +{ +  int		len;                    /* Length of command line */ +  int           flag;                   /* Command flags          */ +  int           rc = 0;                 /* Result from run_command*/ +  char          prompt_str[ 20 ];       /* Prompt string          */ +  static char   lastcommand[ CFG_CBSIZE ] = {0}; /* previous command */ +  /* -------------------------------------------------- */ + +  if( bug_ctx.clear ) +    (*bug_ctx.clear)( bug_ctx.current_bp ); + +  printf( "Breakpoint %d: ", bug_ctx.current_bp ); +  disppc( (unsigned char *)addr, 0, 1, bedbug_puts, F_RADHEX ); + +  bug_ctx.stopped = 1; +  bug_ctx.regs = regs; + +  sprintf( prompt_str, "BEDBUG.%d =>", bug_ctx.current_bp ); + +  /* A miniature main loop */ +  while( bug_ctx.stopped ) +  { +    len = readline( prompt_str ); + +    flag = 0;	/* assume no special flags for now */ + +    if (len > 0) +      strcpy( lastcommand, console_buffer ); +    else if( len == 0 ) +      flag |= CMD_FLAG_REPEAT; + +    if (len == -1) +      printf ("<INTERRUPT>\n"); +    else +      rc = run_command( lastcommand, flag ); + +    if (rc <= 0) { +      /* invalid command or not repeatable, forget it */ +      lastcommand[0] = 0; +    } +  } + +  bug_ctx.regs = NULL; +  bug_ctx.current_bp = 0; + +  return; +} /* bedbug_main_loop */ + + + +/* ====================================================================== + * Interpreter command to continue from a breakpoint.  Just clears the + * stopped flag in the context so that the breakpoint routine will + * return. + * ====================================================================== */ +int do_bedbug_continue (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) + +{ +  /* -------------------------------------------------- */ + +  if( ! bug_ctx.stopped ) +  { +    printf( "Not at a breakpoint\n" ); +    return 1; +  } + +  bug_ctx.stopped = 0; +  return 0; +} /* do_bedbug_continue */ + + + +/* ====================================================================== + * Interpreter command to continue to the next instruction, stepping into + * subroutines.  Works by calling the find_next_addr() routine to compute + * the address passes control to the CPU-specific set breakpoint routine + * for the current breakpoint number. + * ====================================================================== */ +int do_bedbug_step (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ +  unsigned long addr;   /* Address to stop at */ +  /* -------------------------------------------------- */ + +  if( ! bug_ctx.stopped ) +  { +    printf( "Not at a breakpoint\n" ); +    return 1; +  } + +  if( !find_next_address( (unsigned char *)&addr, FALSE, bug_ctx.regs )) +    return 1; + +  if( bug_ctx.set ) +    (*bug_ctx.set)( bug_ctx.current_bp, addr ); + +  bug_ctx.stopped = 0; +  return 0; +} /* do_bedbug_step */ + + + +/* ====================================================================== + * Interpreter command to continue to the next instruction, stepping over + * subroutines.  Works by calling the find_next_addr() routine to compute + * the address passes control to the CPU-specific set breakpoint routine + * for the current breakpoint number. + * ====================================================================== */ +int do_bedbug_next (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ +  unsigned long addr;   /* Address to stop at */ +  /* -------------------------------------------------- */ + +  if( ! bug_ctx.stopped ) +  { +    printf( "Not at a breakpoint\n" ); +    return 1; +  } + +  if( !find_next_address( (unsigned char *)&addr, TRUE, bug_ctx.regs )) +    return 1; + +  if( bug_ctx.set ) +    (*bug_ctx.set)( bug_ctx.current_bp, addr ); + +  bug_ctx.stopped = 0; +  return 0; +} /* do_bedbug_next */ + + + +/* ====================================================================== + * Interpreter command to print the current stack.  This assumes an EABI + * architecture, so it starts with GPR R1 and works back up the stack. + * ====================================================================== */ +int do_bedbug_stack (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ +	DECLARE_GLOBAL_DATA_PTR; + +  unsigned long sp;             /* Stack pointer                */ +  unsigned long func;           /* LR from stack                */ +  int           depth;          /* Stack iteration level        */ +  int           skip = 1;       /* Flag to skip the first entry */ +  unsigned long top;            /* Top of memory address        */ +  /* -------------------------------------------------- */ + +  if( ! bug_ctx.stopped ) +  { +    printf( "Not at a breakpoint\n" ); +    return 1; +  } + +  top = gd->bd->bi_memstart + gd->bd->bi_memsize; +  depth = 0; + +  printf( "Depth     PC\n" ); +  printf( "-----  --------\n" ); +  printf( "%5d  %08lx\n", depth++, bug_ctx.regs->nip ); + +  sp = bug_ctx.regs->gpr[ 1 ]; +  func = *(unsigned long *)(sp+4); + +  while(( func < top ) && ( sp < top )) +  { +    if( !skip ) +      printf( "%5d  %08lx\n", depth++, func ); +    else +      --skip; + +    sp = *(unsigned long *)sp; +    func = *(unsigned long *)(sp+4); +  } +  return 0; +} /* do_bedbug_stack */ + + + +/* ====================================================================== + * Interpreter command to dump the registers.  Calls the CPU-specific + * show registers routine. + * ====================================================================== */ +int do_bedbug_rdump (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ +  /* -------------------------------------------------- */ + +  if( ! bug_ctx.stopped ) +  { +    printf( "Not at a breakpoint\n" ); +    return 1; +  } + +  show_regs( bug_ctx.regs ); +  return 0; +} /* do_bedbug_rdump */ + + +/* ====================================================================== */ +#endif	/* CFG_CMD_BEDBUG */ + + +/* + * Copyright (c) 2001 William L. Pitts + * All rights reserved. + * + * Redistribution and use in source and binary forms are freely + * permitted provided that the above copyright notice and this + * paragraph and the following disclaimer are duplicated in all + * such forms. + * + * This software is provided "AS IS" and without any express or + * implied warranties, including, without limitation, the implied + * warranties of merchantability and fitness for a particular + * purpose. + */ diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c new file mode 100644 index 000000000..e8ce40d69 --- /dev/null +++ b/common/cmd_bootm.c @@ -0,0 +1,931 @@ +/* + * (C) Copyright 2000-2002 + * 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 + */ + +/* + * Boot support + */ +#include <common.h> +#include <watchdog.h> +#include <command.h> +#include <cmd_boot.h> +#include <image.h> +#include <malloc.h> +#include <zlib.h> +#include <asm/byteorder.h> +#if (CONFIG_COMMANDS & CFG_CMD_DATE) || defined(CONFIG_TIMESTAMP) +#include <rtc.h> +#endif + +#ifdef CFG_HUSH_PARSER +#include <hush.h> +#endif + +#ifdef CONFIG_SHOW_BOOT_PROGRESS +# include <status_led.h> +# define SHOW_BOOT_PROGRESS(arg)	show_boot_progress(arg) +#else +# define SHOW_BOOT_PROGRESS(arg) +#endif + +#ifdef CFG_INIT_RAM_LOCK +#include <asm/cache.h> +#endif + +/* + * Some systems (for example LWMON) have very short watchdog periods; + * we must make sure to split long operations like memmove() or + * crc32() into reasonable chunks. + */ +#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) +# define CHUNKSZ (64 * 1024) +#endif + +int  gunzip (void *, int, unsigned char *, int *); + +static void *zalloc(void *, unsigned, unsigned); +static void zfree(void *, void *, unsigned); + +#if (CONFIG_COMMANDS & CFG_CMD_IMI) +static int image_info (unsigned long addr); +#endif +static void print_type (image_header_t *hdr); + +/* + *  Continue booting an OS image; caller already has: + *  - copied image header to global variable `header' + *  - checked header magic number, checksums (both header & image), + *  - verified image architecture (PPC) and type (KERNEL or MULTI), + *  - loaded (first part of) image to header load address, + *  - disabled interrupts. + */ +typedef void boot_os_Fcn (cmd_tbl_t *cmdtp, int flag, +			  int	argc, char *argv[], +			  ulong	addr,		/* of image to boot */ +			  ulong	*len_ptr,	/* multi-file image length table */ +			  int	verify);	/* getenv("verify")[0] != 'n' */ + +#ifndef CONFIG_ARM +static boot_os_Fcn do_bootm_linux; +#else +extern boot_os_Fcn do_bootm_linux; +#endif +static boot_os_Fcn do_bootm_netbsd; +#if (CONFIG_COMMANDS & CFG_CMD_ELF) +static boot_os_Fcn do_bootm_vxworks; +static boot_os_Fcn do_bootm_qnxelf; +int do_bootvx ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[] ); +int do_bootelf (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[] ); +#endif /* CFG_CMD_ELF */ + +image_header_t header; + +ulong load_addr = CFG_LOAD_ADDR;		/* Default Load Address */ + +int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ +	ulong	iflag; +	ulong	addr; +	ulong	data, len, checksum; +	ulong  *len_ptr; +	int	i, verify; +	char	*name, *s; +	int	(*appl)(cmd_tbl_t *, int, int, char *[]); +	image_header_t *hdr = &header; + +	s = getenv ("verify"); +	verify = (s && (*s == 'n')) ? 0 : 1; + +	if (argc < 2) { +		addr = load_addr; +	} else { +		addr = simple_strtoul(argv[1], NULL, 16); +	} + +	SHOW_BOOT_PROGRESS (1); +	printf ("## Booting image at %08lx ...\n", addr); + +	/* Copy header so we can blank CRC field for re-calculation */ +	memmove (&header, (char *)addr, sizeof(image_header_t)); + +	if (ntohl(hdr->ih_magic) != IH_MAGIC) { +		printf ("Bad Magic Number\n"); +		SHOW_BOOT_PROGRESS (-1); +		return 1; +	} +	SHOW_BOOT_PROGRESS (2); + +	data = (ulong)&header; +	len  = sizeof(image_header_t); + +	checksum = ntohl(hdr->ih_hcrc); +	hdr->ih_hcrc = 0; + +	if (crc32 (0, (char *)data, len) != checksum) { +		printf ("Bad Header Checksum\n"); +		SHOW_BOOT_PROGRESS (-2); +		return 1; +	} +	SHOW_BOOT_PROGRESS (3); + +	/* for multi-file images we need the data part, too */ +	print_image_hdr ((image_header_t *)addr); + +	data = addr + sizeof(image_header_t); +	len  = ntohl(hdr->ih_size); + +	if (verify) { +		printf ("   Verifying Checksum ... "); +		if (crc32 (0, (char *)data, len) != ntohl(hdr->ih_dcrc)) { +			printf ("Bad Data CRC\n"); +			SHOW_BOOT_PROGRESS (-3); +			return 1; +		} +		printf ("OK\n"); +	} +	SHOW_BOOT_PROGRESS (4); + +	len_ptr = (ulong *)data; + +	if (hdr->ih_arch != IH_CPU_PPC && hdr->ih_arch != IH_CPU_ARM) { +		printf ("Unsupported Architecture\n"); +		SHOW_BOOT_PROGRESS (-4); +		return 1; +	} +	SHOW_BOOT_PROGRESS (5); + +	switch (hdr->ih_type) { +	case IH_TYPE_STANDALONE:	name = "Standalone Application"; +					break; +	case IH_TYPE_KERNEL:		name = "Kernel Image"; +					break; +	case IH_TYPE_MULTI:		name = "Multi-File Image"; +					len  = ntohl(len_ptr[0]); +					/* OS kernel is always the first image */ +					data += 8; /* kernel_len + terminator */ +					for (i=1; len_ptr[i]; ++i) +						data += 4; +					break; +	default: printf ("Wrong Image Type for %s command\n", cmdtp->name); +		SHOW_BOOT_PROGRESS (-5); +		return 1; +	} +	SHOW_BOOT_PROGRESS (6); + +	/* +	 * We have reached the point of no return: we are going to +	 * overwrite all exception vector code, so we cannot easily +	 * recover from any failures any more... +	 */ + +	iflag = disable_interrupts(); + +	switch (hdr->ih_comp) { +	case IH_COMP_NONE: +		if(hdr->ih_load == addr) { +			printf ("   XIP %s ... ", name); +		} else { +#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) +			size_t l = len; +			void *to = (void *)ntohl(hdr->ih_load); +			void *from = (void *)data; + +			printf ("   Loading %s ... ", name); + +			while (l > 0) { +				size_t tail = (l > CHUNKSZ) ? CHUNKSZ : l; +				WATCHDOG_RESET(); +				memmove (to, from, tail); +				to += tail; +				from += tail; +				l -= tail; +			} +#else	/* !(CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG) */ +			memmove ((void *) ntohl(hdr->ih_load), (uchar *)data, len); +#endif	/* CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG */ +		} +		break; +	case IH_COMP_GZIP: +		printf ("   Uncompressing %s ... ", name); +		if (gunzip ((void *)ntohl(hdr->ih_load), 0x400000, +			    (uchar *)data, (int *)&len) != 0) { +			printf ("GUNZIP ERROR - must RESET board to recover\n"); +			SHOW_BOOT_PROGRESS (-6); +			do_reset (cmdtp, flag, argc, argv); +		} +		break; +	default: +		if (iflag) +			enable_interrupts(); +		printf ("Unimplemented compression type %d\n", hdr->ih_comp); +		SHOW_BOOT_PROGRESS (-7); +		return 1; +	} +	printf ("OK\n"); +	SHOW_BOOT_PROGRESS (7); + +	switch (hdr->ih_type) { +	case IH_TYPE_STANDALONE: +		appl = (int (*)(cmd_tbl_t *, int, int, char *[]))ntohl(hdr->ih_ep); +		if (iflag) +			enable_interrupts(); + +		(*appl)(cmdtp, flag, argc-1, &argv[1]); +		break; +	case IH_TYPE_KERNEL: +	case IH_TYPE_MULTI: +		/* handled below */ +		break; +	default: +		if (iflag) +			enable_interrupts(); +		printf ("Can't boot image type %d\n", hdr->ih_type); +		SHOW_BOOT_PROGRESS (-8); +		return 1; +	} +	SHOW_BOOT_PROGRESS (8); + +	switch (hdr->ih_os) { +	default:			/* handled by (original) Linux case */ +	case IH_OS_LINUX: +	    do_bootm_linux  (cmdtp, flag, argc, argv, +			     addr, len_ptr, verify); +	    break; +	case IH_OS_NETBSD: +	    do_bootm_netbsd (cmdtp, flag, argc, argv, +			     addr, len_ptr, verify); +	    break; +#if (CONFIG_COMMANDS & CFG_CMD_ELF) +	case IH_OS_VXWORKS: +	    do_bootm_vxworks (cmdtp, flag, argc, argv, +			      addr, len_ptr, verify); +	    break; +	case IH_OS_QNX: +	    do_bootm_qnxelf (cmdtp, flag, argc, argv, +			      addr, len_ptr, verify); +	    break; +#endif /* CFG_CMD_ELF */ +	} + +	SHOW_BOOT_PROGRESS (-9); +#ifdef DEBUG +	printf ("\n## Control returned to monitor - resetting...\n"); +	do_reset (cmdtp, flag, argc, argv); +#endif +	return 1; +} + +#ifndef CONFIG_ARM +static void +do_bootm_linux (cmd_tbl_t *cmdtp, int flag, +		int	argc, char *argv[], +		ulong	addr, +		ulong	*len_ptr, +		int	verify) +{ +	DECLARE_GLOBAL_DATA_PTR; + +	ulong	sp; +	ulong	len, checksum; +	ulong	initrd_start, initrd_end; +	ulong	cmd_start, cmd_end; +	ulong	initrd_high; +	ulong	data; +	char    *cmdline; +	char	*s; +	bd_t	*kbd; +	void	(*kernel)(bd_t *, ulong, ulong, ulong, ulong); +	image_header_t *hdr = &header; + +	if ((s = getenv ("initrd_high")) != NULL) { +		/* a value of "no" or a similar string will act like 0, +		 * turning the "load high" feature off. This is intentional. +		 */ +		initrd_high = simple_strtoul(s, NULL, 16); +	} else {			/* not set, no restrictions to load high */ +		initrd_high = ~0; +	} + +	/* +	 * Booting a (Linux) kernel image +	 * +	 * Allocate space for command line and board info - the +	 * address should be as high as possible within the reach of +	 * the kernel (see CFG_BOOTMAPSZ settings), but in unused +	 * memory, which means far enough below the current stack +	 * pointer. +	 */ + +	asm( "mr %0,1": "=r"(sp) : ); + +#ifdef	DEBUG +	printf ("## Current stack ends at 0x%08lX ", sp); +#endif +	sp -= 2048;		/* just to be sure */ +	if (sp > CFG_BOOTMAPSZ) +		sp = CFG_BOOTMAPSZ; +	sp &= ~0xF; + +#ifdef	DEBUG +	printf ("=> set upper limit to 0x%08lX\n", sp); +#endif +	cmdline = (char *)((sp - CFG_BARGSIZE) & ~0xF); +	kbd = (bd_t *)(((ulong)cmdline - sizeof(bd_t)) & ~0xF); + +	if ((s = getenv("bootargs")) == NULL) +		s = ""; + +	strcpy (cmdline, s); + +	cmd_start    = (ulong)&cmdline[0]; +	cmd_end      = cmd_start + strlen(cmdline); + +	*kbd = *(gd->bd); + +#ifdef	DEBUG +	printf ("## cmdline at 0x%08lX ... 0x%08lX\n", cmd_start, cmd_end); + +	do_bdinfo (NULL, 0, 0, NULL); +#endif + +	if ((s = getenv ("clocks_in_mhz")) != NULL) { +		/* convert all clock information to MHz */ +		kbd->bi_intfreq /= 1000000L; +		kbd->bi_busfreq /= 1000000L; +#if defined(CONFIG_8260) +		kbd->bi_cpmfreq /= 1000000L; +		kbd->bi_brgfreq /= 1000000L; +		kbd->bi_sccfreq /= 1000000L; +		kbd->bi_vco     /= 1000000L; +#endif /* CONFIG_8260 */ +	} + +	kernel = (void (*)(bd_t *, ulong, ulong, ulong, ulong))hdr->ih_ep; + +	/* +	 * Check if there is an initrd image +	 */ +	if (argc >= 3) { +		SHOW_BOOT_PROGRESS (9); + +		addr = simple_strtoul(argv[2], NULL, 16); + +		printf ("## Loading RAMDisk Image at %08lx ...\n", addr); + +		/* Copy header so we can blank CRC field for re-calculation */ +		memmove (&header, (char *)addr, sizeof(image_header_t)); + +		if (hdr->ih_magic  != IH_MAGIC) { +			printf ("Bad Magic Number\n"); +			SHOW_BOOT_PROGRESS (-10); +			do_reset (cmdtp, flag, argc, argv); +		} + +		data = (ulong)&header; +		len  = sizeof(image_header_t); + +		checksum = hdr->ih_hcrc; +		hdr->ih_hcrc = 0; + +		if (crc32 (0, (char *)data, len) != checksum) { +			printf ("Bad Header Checksum\n"); +			SHOW_BOOT_PROGRESS (-11); +			do_reset (cmdtp, flag, argc, argv); +		} + +		SHOW_BOOT_PROGRESS (10); + +		print_image_hdr (hdr); + +		data = addr + sizeof(image_header_t); +		len  = hdr->ih_size; + +		if (verify) { +			ulong csum = 0; +#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) +			ulong cdata = data, edata = cdata + len; +#endif	/* CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG */ + +			printf ("   Verifying Checksum ... "); + +#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) + +			while (cdata < edata) { +				ulong chunk = edata - cdata; + +				if (chunk > CHUNKSZ) +					chunk = CHUNKSZ; +				csum = crc32 (csum, (char *)cdata, chunk); +				cdata += chunk; + +				WATCHDOG_RESET(); +			} +#else	/* !(CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG) */ +			csum = crc32 (0, (char *)data, len); +#endif	/* CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG */ + +			if (csum != hdr->ih_dcrc) { +				printf ("Bad Data CRC\n"); +				SHOW_BOOT_PROGRESS (-12); +				do_reset (cmdtp, flag, argc, argv); +			} +			printf ("OK\n"); +		} + +		SHOW_BOOT_PROGRESS (11); + +		if ((hdr->ih_os   != IH_OS_LINUX)	|| +		    (hdr->ih_arch != IH_CPU_PPC)	|| +		    (hdr->ih_type != IH_TYPE_RAMDISK)	) { +			printf ("No Linux PPC Ramdisk Image\n"); +			SHOW_BOOT_PROGRESS (-13); +			do_reset (cmdtp, flag, argc, argv); +		} + +		/* +		 * Now check if we have a multifile image +		 */ +	} else if ((hdr->ih_type==IH_TYPE_MULTI) && (len_ptr[1])) { +		u_long tail    = ntohl(len_ptr[0]) % 4; +		int i; + +		SHOW_BOOT_PROGRESS (13); + +		/* skip kernel length and terminator */ +		data = (ulong)(&len_ptr[2]); +		/* skip any additional image length fields */ +		for (i=1; len_ptr[i]; ++i) +			data += 4; +		/* add kernel length, and align */ +		data += ntohl(len_ptr[0]); +		if (tail) { +			data += 4 - tail; +		} + +		len   = ntohl(len_ptr[1]); + +	} else { +		/* +		 * no initrd image +		 */ +		SHOW_BOOT_PROGRESS (14); + +		len = data = 0; +	} + +#ifdef	DEBUG +	if (!data) { +		printf ("No initrd\n"); +	} +#endif + +	if (data) { +		initrd_start  = (ulong)kbd - len; +		initrd_start &= ~(4096 - 1);	/* align on page */ + +		if (initrd_high) { +			ulong nsp; + +			/* +			 * the inital ramdisk does not need to be within +			 * CFG_BOOTMAPSZ as it is not accessed until after +			 * the mm system is initialised. +			 * +			 * do the stack bottom calculation again and see if +			 * the initrd will fit just below the monitor stack +			 * bottom without overwriting the area allocated +			 * above for command line args and board info. +			 */ +			asm( "mr %0,1": "=r"(nsp) : ); +			nsp -= 2048;		/* just to be sure */ +			nsp &= ~0xF; +			if (nsp > initrd_high)	/* limit as specified */ +				nsp = initrd_high; +			nsp -= len; +			nsp &= ~(4096 - 1);	/* align on page */ +			if (nsp >= sp) +				initrd_start = nsp; +		} + +		SHOW_BOOT_PROGRESS (12); +#ifdef	DEBUG +		printf ("## initrd at 0x%08lX ... 0x%08lX (len=%ld=0x%lX)\n", +			data, data + len - 1, len, len); +#endif +		initrd_end    = initrd_start + len; +		printf ("   Loading Ramdisk to %08lx, end %08lx ... ", +			initrd_start, initrd_end); +#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) +		{ +			size_t l = len; +			void *to = (void *)initrd_start; +			void *from = (void *)data; + +			while (l > 0) { +				size_t tail = (l > CHUNKSZ) ? CHUNKSZ : l; +				WATCHDOG_RESET(); +				memmove (to, from, tail); +				to += tail; +				from += tail; +				l -= tail; +			} +		} +#else	/* !(CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG) */ +		memmove ((void *)initrd_start, (void *)data, len); +#endif	/* CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG */ +		printf ("OK\n"); +	} else { +		initrd_start = 0; +		initrd_end = 0; +	} + +#ifdef DEBUG +	printf ("## Transferring control to Linux (at address %08lx) ...\n", +		(ulong)kernel); +#endif +	SHOW_BOOT_PROGRESS (15); + +#ifdef CFG_INIT_RAM_LOCK +	unlock_ram_in_cache(); +#endif +	/* +	 * Linux Kernel Parameters: +	 *   r3: ptr to board info data +	 *   r4: initrd_start or 0 if no initrd +	 *   r5: initrd_end - unused if r4 is 0 +	 *   r6: Start of command line string +	 *   r7: End   of command line string +	 */ +	(*kernel) (kbd, initrd_start, initrd_end, cmd_start, cmd_end); +} +#endif /* CONFIG_ARM */ + +static void +do_bootm_netbsd (cmd_tbl_t *cmdtp, int flag, +		int	argc, char *argv[], +		ulong	addr, +		ulong	*len_ptr, +		int	verify) +{ +	DECLARE_GLOBAL_DATA_PTR; + +	image_header_t *hdr = &header; + +	void	(*loader)(bd_t *, image_header_t *, char *, char *); +	image_header_t *img_addr; +	char     *consdev; +	char     *cmdline; + + +	/* +	 * Booting a (NetBSD) kernel image +	 * +	 * This process is pretty similar to a standalone application: +	 * The (first part of an multi-) image must be a stage-2 loader, +	 * which in turn is responsible for loading & invoking the actual +	 * kernel.  The only differences are the parameters being passed: +	 * besides the board info strucure, the loader expects a command +	 * line, the name of the console device, and (optionally) the +	 * address of the original image header. +	 */ + +	img_addr = 0; +	if ((hdr->ih_type==IH_TYPE_MULTI) && (len_ptr[1])) +		img_addr = (image_header_t *) addr; + + +	consdev = ""; +#if   defined (CONFIG_8xx_CONS_SMC1) +	consdev = "smc1"; +#elif defined (CONFIG_8xx_CONS_SMC2) +	consdev = "smc2"; +#elif defined (CONFIG_8xx_CONS_SCC2) +	consdev = "scc2"; +#elif defined (CONFIG_8xx_CONS_SCC3) +	consdev = "scc3"; +#endif + +	if (argc > 2) { +		ulong len; +		int   i; + +		for (i=2, len=0 ; i<argc ; i+=1) +			len += strlen (argv[i]) + 1; +		cmdline = malloc (len); + +		for (i=2, len=0 ; i<argc ; i+=1) { +			if (i > 2) +				cmdline[len++] = ' '; +			strcpy (&cmdline[len], argv[i]); +			len += strlen (argv[i]); +		} +	} else if ((cmdline = getenv("bootargs")) == NULL) { +		cmdline = ""; +	} + +	loader = (void (*)(bd_t *, image_header_t *, char *, char *)) hdr->ih_ep; + +	printf ("## Transferring control to NetBSD stage-2 loader (at address %08lx) ...\n", +		(ulong)loader); + +	SHOW_BOOT_PROGRESS (15); + +	/* +	 * NetBSD Stage-2 Loader Parameters: +	 *   r3: ptr to board info data +	 *   r4: image address +	 *   r5: console device +	 *   r6: boot args string +	 */ +	(*loader) (gd->bd, img_addr, consdev, cmdline); +} + +#if (CONFIG_COMMANDS & CFG_CMD_BOOTD) +int do_bootd (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ +	int rcode = 0; +#ifndef CFG_HUSH_PARSER +	if (run_command (getenv ("bootcmd"), flag) < 0) rcode = 1; +#else +	if (parse_string_outer(getenv("bootcmd"), +		FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP) != 0 ) rcode = 1; +#endif +	return rcode; +} +#endif + +#if (CONFIG_COMMANDS & CFG_CMD_IMI) +int do_iminfo ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ +	int	arg; +	ulong	addr; +	int     rcode=0; + +	if (argc < 2) { +		return image_info (load_addr); +	} + +	for (arg=1; arg <argc; ++arg) { +		addr = simple_strtoul(argv[arg], NULL, 16); +		if (image_info (addr) != 0) rcode = 1; +	} +	return rcode; +} + +static int image_info (ulong addr) +{ +	ulong	data, len, checksum; +	image_header_t *hdr = &header; + +	printf ("\n## Checking Image at %08lx ...\n", addr); + +	/* Copy header so we can blank CRC field for re-calculation */ +	memmove (&header, (char *)addr, sizeof(image_header_t)); + +	if (ntohl(hdr->ih_magic) != IH_MAGIC) { +		printf ("   Bad Magic Number\n"); +		return 1; +	} + +	data = (ulong)&header; +	len  = sizeof(image_header_t); + +	checksum = ntohl(hdr->ih_hcrc); +	hdr->ih_hcrc = 0; + +	if (crc32 (0, (char *)data, len) != checksum) { +		printf ("   Bad Header Checksum\n"); +		return 1; +	} + +	/* for multi-file images we need the data part, too */ +	print_image_hdr ((image_header_t *)addr); + +	data = addr + sizeof(image_header_t); +	len  = ntohl(hdr->ih_size); + +	printf ("   Verifying Checksum ... "); +	if (crc32 (0, (char *)data, len) != ntohl(hdr->ih_dcrc)) { +		printf ("   Bad Data CRC\n"); +		return 1; +	} +	printf ("OK\n"); +	return 0; +} +#endif	/* CFG_CMD_IMI */ + +void +print_image_hdr (image_header_t *hdr) +{ +#if (CONFIG_COMMANDS & CFG_CMD_DATE) || defined(CONFIG_TIMESTAMP) +	time_t timestamp = (time_t)ntohl(hdr->ih_time); +	struct rtc_time tm; +#endif + +	printf ("   Image Name:   %.*s\n", IH_NMLEN, hdr->ih_name); +#if (CONFIG_COMMANDS & CFG_CMD_DATE) || defined(CONFIG_TIMESTAMP) +	to_tm (timestamp, &tm); +	printf ("   Created:      %4d-%02d-%02d  %2d:%02d:%02d UTC\n", +		tm.tm_year, tm.tm_mon, tm.tm_mday, +		tm.tm_hour, tm.tm_min, tm.tm_sec); +#endif	/* CFG_CMD_DATE, CONFIG_TIMESTAMP */ +	printf ("   Image Type:   "); print_type(hdr); printf ("\n"); +	printf ("   Data Size:    %d Bytes = ", ntohl(hdr->ih_size)); +	print_size (ntohl(hdr->ih_size), "\n"); +	printf ("   Load Address: %08x\n", ntohl(hdr->ih_load)); +	printf ("   Entry Point:  %08x\n", ntohl(hdr->ih_ep)); + +	if (hdr->ih_type == IH_TYPE_MULTI) { +		int i; +		ulong len; +		ulong *len_ptr = (ulong *)((ulong)hdr + sizeof(image_header_t)); + +		printf ("   Contents:\n"); +		for (i=0; (len = ntohl(*len_ptr)); ++i, ++len_ptr) { +			printf ("   Image %d: %8ld Bytes = ", i, len); +			print_size (len, "\n"); +		} +	} +} + + +static void +print_type (image_header_t *hdr) +{ +	char *os, *arch, *type, *comp; + +	switch (hdr->ih_os) { +	case IH_OS_INVALID:	os = "Invalid OS";		break; +	case IH_OS_NETBSD:	os = "NetBSD";			break; +	case IH_OS_LINUX:	os = "Linux";			break; +	case IH_OS_VXWORKS:	os = "VxWorks";			break; +	case IH_OS_QNX:		os = "QNX";			break; +	case IH_OS_U_BOOT:	os = "U-Boot";			break; +	default:		os = "Unknown OS";		break; +	} + +	switch (hdr->ih_arch) { +	case IH_CPU_INVALID:	arch = "Invalid CPU";		break; +	case IH_CPU_ALPHA:	arch = "Alpha";			break; +	case IH_CPU_ARM:	arch = "ARM";			break; +	case IH_CPU_I386:	arch = "Intel x86";		break; +	case IH_CPU_IA64:	arch = "IA64";			break; +	case IH_CPU_MIPS:	arch = "MIPS";			break; +	case IH_CPU_MIPS64:	arch = "MIPS 64 Bit";		break; +	case IH_CPU_PPC:	arch = "PowerPC";		break; +	case IH_CPU_S390:	arch = "IBM S390";		break; +	case IH_CPU_SH:		arch = "SuperH";		break; +	case IH_CPU_SPARC:	arch = "SPARC";			break; +	case IH_CPU_SPARC64:	arch = "SPARC 64 Bit";		break; +	default:		arch = "Unknown Architecture";	break; +	} + +	switch (hdr->ih_type) { +	case IH_TYPE_INVALID:	type = "Invalid Image";		break; +	case IH_TYPE_STANDALONE:type = "Standalone Program";	break; +	case IH_TYPE_KERNEL:	type = "Kernel Image";		break; +	case IH_TYPE_RAMDISK:	type = "RAMDisk Image";		break; +	case IH_TYPE_MULTI:	type = "Multi-File Image";	break; +	case IH_TYPE_FIRMWARE:	type = "Firmware";		break; +	case IH_TYPE_SCRIPT:	type = "Script";		break; +	default:		type = "Unknown Image";		break; +	} + +	switch (hdr->ih_comp) { +	case IH_COMP_NONE:	comp = "uncompressed";		break; +	case IH_COMP_GZIP:	comp = "gzip compressed";	break; +	case IH_COMP_BZIP2:	comp = "bzip2 compressed";	break; +	default:		comp = "unknown compression";	break; +	} + +	printf ("%s %s %s (%s)", arch, os, type, comp); +} + +#define	ZALLOC_ALIGNMENT	16 + +static void *zalloc(void *x, unsigned items, unsigned size) +{ +	void *p; + +	size *= items; +	size = (size + ZALLOC_ALIGNMENT - 1) & ~(ZALLOC_ALIGNMENT - 1); + +	p = malloc (size); + +	return (p); +} + +static void zfree(void *x, void *addr, unsigned nb) +{ +	free (addr); +} + +#define HEAD_CRC	2 +#define EXTRA_FIELD	4 +#define ORIG_NAME	8 +#define COMMENT		0x10 +#define RESERVED	0xe0 + +#define DEFLATED	8 + +int gunzip(void *dst, int dstlen, unsigned char *src, int *lenp) +{ +	z_stream s; +	int r, i, flags; + +	/* skip header */ +	i = 10; +	flags = src[3]; +	if (src[2] != DEFLATED || (flags & RESERVED) != 0) { +		printf ("Error: Bad gzipped data\n"); +		return (-1); +	} +	if ((flags & EXTRA_FIELD) != 0) +		i = 12 + src[10] + (src[11] << 8); +	if ((flags & ORIG_NAME) != 0) +		while (src[i++] != 0) +			; +	if ((flags & COMMENT) != 0) +		while (src[i++] != 0) +			; +	if ((flags & HEAD_CRC) != 0) +		i += 2; +	if (i >= *lenp) { +		printf ("Error: gunzip out of data in header\n"); +		return (-1); +	} + +	s.zalloc = zalloc; +	s.zfree = zfree; +#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) +	s.outcb = (cb_func)WATCHDOG_RESET; +#else +	s.outcb = Z_NULL; +#endif	/* CONFIG_HW_WATCHDOG */ + +	r = inflateInit2(&s, -MAX_WBITS); +	if (r != Z_OK) { +		printf ("Error: inflateInit2() returned %d\n", r); +		return (-1); +	} +	s.next_in = src + i; +	s.avail_in = *lenp - i; +	s.next_out = dst; +	s.avail_out = dstlen; +	r = inflate(&s, Z_FINISH); +	if (r != Z_OK && r != Z_STREAM_END) { +		printf ("Error: inflate() returned %d\n", r); +		return (-1); +	} +	*lenp = s.next_out - (unsigned char *) dst; +	inflateEnd(&s); + +	return (0); +} + +#if (CONFIG_COMMANDS & CFG_CMD_ELF) +static void +do_bootm_vxworks (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[], +		  ulong addr, ulong *len_ptr, int verify) +{ +	image_header_t *hdr = &header; +	char str[80]; + +	sprintf(str, "%x", hdr->ih_ep); /* write entry-point into string */ +	setenv("loadaddr", str); +	do_bootvx(cmdtp, 0, 0, NULL); +} + +static void +do_bootm_qnxelf (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[], +		 ulong addr, ulong *len_ptr, int verify) +{ +	image_header_t *hdr = &header; +	char *local_args[2]; +	char str[16]; + +	sprintf(str, "%x", hdr->ih_ep); /* write entry-point into string */ +	local_args[0] = argv[0]; +	local_args[1] = str;	/* and provide it via the arguments */ +	do_bootelf(cmdtp, 0, 2, local_args); +} +#endif /* CFG_CMD_ELF */ diff --git a/common/console.c b/common/console.c new file mode 100644 index 000000000..f99dfcc64 --- /dev/null +++ b/common/console.c @@ -0,0 +1,532 @@ +/* + * (C) Copyright 2000 + * Paolo Scaffardi, AIRVENT SAM s.p.a - RIMINI(ITALY), arsenio@tin.it + * + * 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 + */ + +#include <common.h> +#include <stdarg.h> +#include <malloc.h> +#include <console.h> +#include <syscall.h> + +void **syscall_tbl; + +#ifdef CFG_CONSOLE_IS_IN_ENV +/* + * if overwrite_console returns 1, the stdin, stderr and stdout + * are switched to the serial port, else the settings in the + * environment are used + */ +#ifdef CFG_CONSOLE_OVERWRITE_ROUTINE +extern int overwrite_console (void); +#else +int overwrite_console (void) +{ +	return (0); +} +#endif /* CFG_CONSOLE_OVERWRITE_ROUTINE */ + +#endif /* CFG_CONSOLE_IS_IN_ENV */ + +static int console_setfile (int file, device_t * dev) +{ +	int error = 0; + +	if (dev == NULL) +		return -1; + +	switch (file) { +	case stdin: +	case stdout: +	case stderr: +		/* Start new device */ +		if (dev->start) { +			error = dev->start (); +			/* If it's not started dont use it */ +			if (error < 0) +				break; +		} + +		/* Assign the new device (leaving the existing one started) */ +		stdio_devices[file] = dev; + +		/* +		 * Update monitor functions +		 * (to use the console stuff by other applications) +		 */ +		switch (file) { +		case stdin: +			syscall_tbl[SYSCALL_GETC] = dev->getc; +			syscall_tbl[SYSCALL_TSTC] = dev->tstc; +			break; +		case stdout: +			syscall_tbl[SYSCALL_PUTC] = dev->putc; +			syscall_tbl[SYSCALL_PUTS] = dev->puts; +			syscall_tbl[SYSCALL_PRINTF] = printf; +			break; +		} +		break; + +	default:		/* Invalid file ID */ +		error = -1; +	} +	return error; +} + +/** U-Boot INITIAL CONSOLE-NOT COMPATIBLE FUNCTIONS *************************/ + +void serial_printf (const char *fmt, ...) +{ +	va_list args; +	uint i; +	char printbuffer[CFG_PBSIZE]; + +	va_start (args, fmt); + +	/* For this to work, printbuffer must be larger than +	 * anything we ever want to print. +	 */ +	i = vsprintf (printbuffer, fmt, args); +	va_end (args); + +	serial_puts (printbuffer); +} + +int fgetc (int file) +{ +	if (file < MAX_FILES) +		return stdio_devices[file]->getc (); + +	return -1; +} + +int ftstc (int file) +{ +	if (file < MAX_FILES) +		return stdio_devices[file]->tstc (); + +	return -1; +} + +void fputc (int file, const char c) +{ +	if (file < MAX_FILES) +		stdio_devices[file]->putc (c); +} + +void fputs (int file, const char *s) +{ +	if (file < MAX_FILES) +		stdio_devices[file]->puts (s); +} + +void fprintf (int file, const char *fmt, ...) +{ +	va_list args; +	uint i; +	char printbuffer[CFG_PBSIZE]; + +	va_start (args, fmt); + +	/* For this to work, printbuffer must be larger than +	 * anything we ever want to print. +	 */ +	i = vsprintf (printbuffer, fmt, args); +	va_end (args); + +	/* Send to desired file */ +	fputs (file, printbuffer); +} + +/** U-Boot INITIAL CONSOLE-COMPATIBLE FUNCTION *****************************/ + +int getc (void) +{ +	DECLARE_GLOBAL_DATA_PTR; + +	if (gd->flags & GD_FLG_DEVINIT) { +		/* Get from the standard input */ +		return fgetc (stdin); +	} + +	/* Send directly to the handler */ +	return serial_getc (); +} + +int tstc (void) +{ +	DECLARE_GLOBAL_DATA_PTR; + +	if (gd->flags & GD_FLG_DEVINIT) { +		/* Test the standard input */ +		return ftstc (stdin); +	} + +	/* Send directly to the handler */ +	return serial_tstc (); +} + +void putc (const char c) +{ +	DECLARE_GLOBAL_DATA_PTR; + +	if (gd->flags & GD_FLG_DEVINIT) { +		/* Send to the standard output */ +		fputc (stdout, c); +	} else { +		/* Send directly to the handler */ +		serial_putc (c); +	} +} + +void puts (const char *s) +{ +	DECLARE_GLOBAL_DATA_PTR; + +	if (gd->flags & GD_FLG_DEVINIT) { +		/* Send to the standard output */ +		fputs (stdout, s); +	} else { +		/* Send directly to the handler */ +		serial_puts (s); +	} +} + +void printf (const char *fmt, ...) +{ +	va_list args; +	uint i; +	char printbuffer[CFG_PBSIZE]; + +	va_start (args, fmt); + +	/* For this to work, printbuffer must be larger than +	 * anything we ever want to print. +	 */ +	i = vsprintf (printbuffer, fmt, args); +	va_end (args); + +	/* Print the string */ +	puts (printbuffer); +} + +/* test if ctrl-c was pressed */ +static int ctrlc_disabled = 0;	/* see disable_ctrl() */ +static int ctrlc_was_pressed = 0; +int ctrlc (void) +{ +	DECLARE_GLOBAL_DATA_PTR; + +	if (!ctrlc_disabled && gd->have_console) { +		if (tstc ()) { +			switch (getc ()) { +			case 0x03:		/* ^C - Control C */ +				ctrlc_was_pressed = 1; +				return 1; +			default: +				break; +			} +		} +	} +	return 0; +} + +/* pass 1 to disable ctrlc() checking, 0 to enable. + * returns previous state + */ +int disable_ctrlc (int disable) +{ +	int prev = ctrlc_disabled;	/* save previous state */ + +	ctrlc_disabled = disable; +	return prev; +} + +int had_ctrlc (void) +{ +	return ctrlc_was_pressed; +} + +void clear_ctrlc (void) +{ +	ctrlc_was_pressed = 0; +} + +#ifdef CONFIG_MODEM_SUPPORT_DEBUG +char	screen[1024]; +char *cursor = screen; +int once = 0; +inline void dbg(const char *fmt, ...) +{ +	va_list	args; +	uint	i; +	char	printbuffer[CFG_PBSIZE]; + +	if (!once) { +		memset(screen, 0, sizeof(screen)); +		once++; +	} + +	va_start(args, fmt); + +	/* For this to work, printbuffer must be larger than +	 * anything we ever want to print. +	 */ +	i = vsprintf(printbuffer, fmt, args); +	va_end(args); + +	if ((screen + sizeof(screen) - 1 - cursor) < strlen(printbuffer)+1) { +		memset(screen, 0, sizeof(screen)); +		cursor = screen; +	} +	sprintf(cursor, printbuffer); +	cursor += strlen(printbuffer); + +} +#else +inline void dbg(const char *fmt, ...) +{ +} +#endif + +/** U-Boot INIT FUNCTIONS *************************************************/ + +int console_assign (int file, char *devname) +{ +	int flag, i; + +	/* Check for valid file */ +	switch (file) { +	case stdin: +		flag = DEV_FLAGS_INPUT; +		break; +	case stdout: +	case stderr: +		flag = DEV_FLAGS_OUTPUT; +		break; +	default: +		return -1; +	} + +	/* Check for valid device name */ + +	for (i = 1; i <= ListNumItems (devlist); i++) { +		device_t *dev = ListGetPtrToItem (devlist, i); + +		if (strcmp (devname, dev->name) == 0) { +			if (dev->flags & flag) +				return console_setfile (file, dev); + +			return -1; +		} +	} + +	return -1; +} + +/* Called before relocation - use serial functions */ +int console_init_f (void) +{ +	DECLARE_GLOBAL_DATA_PTR; + +	gd->have_console = 1; +	return (0); +} + +#ifdef CFG_CONSOLE_IS_IN_ENV +/* search a device */ +device_t *search_device (int flags, char *name) +{ +	int i, items; +	device_t *dev = NULL; + +	items = ListNumItems (devlist); +	if (name == NULL) +		return dev; + +	for (i = 1; i <= items; i++) { +		dev = ListGetPtrToItem (devlist, i); +		if ((dev->flags & flags) && (strcmp (name, dev->name) == 0)) { +			break; +		} +	} +	return dev; +} +#endif /* CFG_CONSOLE_IS_IN_ENV */ + +#ifdef CFG_CONSOLE_IS_IN_ENV +/* Called after the relocation - use desired console functions */ +int console_init_r (void) +{ +	char *stdinname, *stdoutname, *stderrname; +	device_t *inputdev = NULL, *outputdev = NULL, *errdev = NULL; + +	/* set default handlers at first */ +	syscall_tbl[SYSCALL_GETC] = serial_getc; +	syscall_tbl[SYSCALL_TSTC] = serial_tstc; +	syscall_tbl[SYSCALL_PUTC] = serial_putc; +	syscall_tbl[SYSCALL_PUTS] = serial_puts; +	syscall_tbl[SYSCALL_PRINTF] = serial_printf; + +	/* stdin stdout and stderr are in environment */ +	/* scan for it */ +	stdinname  = getenv ("stdin"); +	stdoutname = getenv ("stdout"); +	stderrname = getenv ("stderr"); + +	if (overwrite_console () == 0) { /* if not overwritten by config switch */ +		inputdev  = search_device (DEV_FLAGS_INPUT,  stdinname); +		outputdev = search_device (DEV_FLAGS_OUTPUT, stdoutname); +		errdev    = search_device (DEV_FLAGS_OUTPUT, stderrname); +	} +	/* if the devices are overwritten or not found, use default device */ +	if (inputdev == NULL) { +		inputdev  = search_device (DEV_FLAGS_INPUT,  "serial"); +	} +	if (outputdev == NULL) { +		outputdev = search_device (DEV_FLAGS_OUTPUT, "serial"); +	} +	if (errdev == NULL) { +		errdev    = search_device (DEV_FLAGS_OUTPUT, "serial"); +	} +	/* Initializes output console first */ +	if (outputdev != NULL) { +		console_setfile (stdout, outputdev); +	} +	if (errdev != NULL) { +		console_setfile (stderr, errdev); +	} +	if (inputdev != NULL) { +		console_setfile (stdin, inputdev); +	} + +#ifndef CFG_CONSOLE_INFO_QUIET +	/* Print information */ +	printf ("In:    "); +	if (stdio_devices[stdin] == NULL) { +		printf ("No input devices available!\n"); +	} else { +		printf ("%s\n", stdio_devices[stdin]->name); +	} + +	printf ("Out:   "); +	if (stdio_devices[stdout] == NULL) { +		printf ("No output devices available!\n"); +	} else { +		printf ("%s\n", stdio_devices[stdout]->name); +	} + +	printf ("Err:   "); +	if (stdio_devices[stderr] == NULL) { +		printf ("No error devices available!\n"); +	} else { +		printf ("%s\n", stdio_devices[stderr]->name); +	} +#endif /* CFG_CONSOLE_INFO_QUIET */ + +#ifdef CFG_CONSOLE_ENV_OVERWRITE +	/* set the environment variables (will overwrite previous env settings) */ +	for (i = 0; i < 3; i++) { +		setenv (stdio_names[i], stdio_devices[i]->name); +	} +#endif /*  CFG_CONSOLE_ENV_OVERWRITE */ + +#if 0 +	/* If nothing usable installed, use only the initial console */ +	if ((stdio_devices[stdin] == NULL) && (stdio_devices[stdout] == NULL)) +		return (0); +#endif +	return (0); +} + +#else /* CFG_CONSOLE_IS_IN_ENV */ + +/* Called after the relocation - use desired console functions */ +int console_init_r (void) +{ +	device_t *inputdev = NULL, *outputdev = NULL; +	int i, items = ListNumItems (devlist); + +	/* Scan devices looking for input and output devices */ +	for (i = 1; +	     (i <= items) && ((inputdev == NULL) || (outputdev == NULL)); +	     i++ +	    ) { +		device_t *dev = ListGetPtrToItem (devlist, i); + +		if ((dev->flags & DEV_FLAGS_INPUT) && (inputdev == NULL)) { +			inputdev = dev; +		} +		if ((dev->flags & DEV_FLAGS_OUTPUT) && (outputdev == NULL)) { +			outputdev = dev; +		} +	} + +	/* Initializes output console first */ +	if (outputdev != NULL) { +		console_setfile (stdout, outputdev); +		console_setfile (stderr, outputdev); +	} + +	/* Initializes input console */ +	if (inputdev != NULL) { +		console_setfile (stdin, inputdev); +	} + +#ifndef CFG_CONSOLE_INFO_QUIET +	/* Print informations */ +	printf ("In:    "); +	if (stdio_devices[stdin] == NULL) { +		printf ("No input devices available!\n"); +	} else { +		printf ("%s\n", stdio_devices[stdin]->name); +	} + +	printf ("Out:   "); +	if (stdio_devices[stdout] == NULL) { +		printf ("No output devices available!\n"); +	} else { +		printf ("%s\n", stdio_devices[stdout]->name); +	} + +	printf ("Err:   "); +	if (stdio_devices[stderr] == NULL) { +		printf ("No error devices available!\n"); +	} else { +		printf ("%s\n", stdio_devices[stderr]->name); +	} +#endif /* CFG_CONSOLE_INFO_QUIET */ + +	/* Setting environment variables */ +	for (i = 0; i < 3; i++) { +		setenv (stdio_names[i], stdio_devices[i]->name); +	} + +#if 0 +	/* If nothing usable installed, use only the initial console */ +	if ((stdio_devices[stdin] == NULL) && (stdio_devices[stdout] == NULL)) +		return (0); +#endif + +	return (0); +} + +#endif /* CFG_CONSOLE_IS_IN_ENV */ diff --git a/cpu/74xx_7xx/start.S b/cpu/74xx_7xx/start.S new file mode 100644 index 000000000..fe08f8e83 --- /dev/null +++ b/cpu/74xx_7xx/start.S @@ -0,0 +1,860 @@ +/* + *  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) 2001  Josh Huber <huber@mclx.com> + * + * 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 + */ + +/*  U-Boot - Startup Code for PowerPC based Embedded Boards + * + * + *  The processor starts at 0xfff00100 and the code is executed + *  from flash. The code is organized to be at an other address + *  in memory, but as long we don't jump around before relocating. + *  board_init lies at a quite high address and when the cpu has + *  jumped there, everything is ok. + */ +#include <config.h> +#include <74xx_7xx.h> +#include <version.h> + +#include <ppc_asm.tmpl> +#include <ppc_defs.h> + +#include <asm/cache.h> +#include <asm/mmu.h> + +#include <galileo/gt64260R.h> + +#ifndef  CONFIG_IDENT_STRING +#define  CONFIG_IDENT_STRING "" +#endif + +/* We don't want the  MMU yet. +*/ +#undef	MSR_KERNEL +/* Machine Check and Recoverable Interr. */ +#define MSR_KERNEL ( MSR_ME | MSR_RI ) + +/* + * 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: +	li	r21, BOOTFLAG_COLD	/* Normal Power-On: Boot from FLASH */ +	b	boot_cold +	sync + +	. = EXC_OFF_SYS_RESET + 0x10 + +	.globl	_start_warm +_start_warm: +	li	r21, BOOTFLAG_WARM	/* Software reboot		*/ +	b	boot_warm +	sync + +	/* the boot code is located below the exception table */ + +	.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 + +	/* No FPU on MPC8xx.  This exception is not supposed to happen. +	*/ +	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	r12,0xd00-4*3		/* save LR & SRRx */ +	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*3		/* restore regs */ +	lwz	r11,0(r12) +	mtlr	r11 +	lwz	r11,4(r12) +	mtspr	SRR0,r11 +	lwz	r11,8(r12) +	mtspr	SRR1,r11 + +	SYNC +	rfi + +	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, UnknownException) +	STD_EXCEPTION(0x1e00, PeripheralBreakpoint, UnknownException) +	STD_EXCEPTION(0x1f00, DevPortBreakpoint, UnknownException) + +	.globl	_end_of_vectors +_end_of_vectors: + +	. = 0x2000 + +boot_cold: +boot_warm: +	/* disable everything */ +	li	r0, 0 +	mtspr	HID0, r0 +	sync +	mtmsr	0 +	bl	invalidate_bats +	sync + +#ifdef CFG_L2 +	/* init the L2 cache */ +	addis	r3, r0, L2_INIT@h +	ori	r3, r3, L2_INIT@l +	sync +	mtspr	l2cr, r3 +#endif +#if defined(CONFIG_ALTIVEC) && defined(CONFIG_74xx) +	.long	0x7e00066c +		/* +                 * dssall instruction, gas doesn't have it yet +                 * ...for altivec, data stream stop all this probably +                 * isn't needed unless we warm (software) reboot U-Boot +		 */ +#endif + +#ifdef CFG_L2 +	/* invalidate the L2 cache */ +	bl	l2cache_invalidate +	sync +#endif +#ifdef CFG_BOARD_ASM_INIT +	/* do early init */ +	bl	board_asm_init +#endif + +	/* +	 * 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: +	/* let the C-code set up the rest			*/ +	/*							*/ +	/* Be careful to keep code relocatable !		*/ +	/*------------------------------------------------------*/ + +	/* perform low-level init */ +	/* sdram init, galileo init, etc */ +	/* r3:	NHR bit from HID0 */ + +	/* setup the bats */ +	bl	setup_bats +	sync + +	/* +	 * Cache must be enabled here for stack-in-cache trick. +	 * This means we need to enable the BATS. +	 * This means: +         *   1) for the EVB, original gt regs need to be mapped +	 *   2) need to have an IBAT for the 0xf region, +	 *      we are running there! +         * Cache should be turned on after BATs, since by default +         * everything is write-through. +         * The init-mem BAT can be reused after reloc. The old +         * gt-regs BAT can be reused after board_init_f calls +         * board_pre_init (EVB only). +         */ +#if !defined(CONFIG_BAB7xx) && !defined(CONFIG_ELPPC) +	/* enable address translation */ +	bl	enable_addr_trans +	sync + +	/* enable and invalidate the data cache */ +	bl	l1dcache_enable +	sync +#endif +#ifdef CFG_INIT_RAM_LOCK +	bl	lock_ram_in_cache +	sync +#endif + +	/* set up the stack pointer in our newly created +	 * cache-ram (r1) */ +	lis	r1, (CFG_INIT_RAM_ADDR + CFG_GBL_DATA_OFFSET)@h +	ori	r1, r1, (CFG_INIT_RAM_ADDR + CFG_GBL_DATA_OFFSET)@l + +	li	r0, 0		/* Make room for stack frame header and	*/ +	stwu	r0, -4(r1)	/* clear final stack frame so that	*/ +	stwu	r0, -4(r1)	/* stack backtraces terminate cleanly	*/ + +	GET_GOT			/* initialize GOT access	*/ + +	/* run low-level CPU init code     (from Flash)	*/ +	bl	cpu_init_f +	sync + +	mr	r3, r21 + +	/* r3: BOOTFLAG */ +	/* run 1st part of board init code (from Flash)   */ +	bl	board_init_f +	sync + +	/* NOTREACHED */ + +	.globl	invalidate_bats +invalidate_bats: +	/* invalidate BATs */ +	mtspr	IBAT0U, r0 +	mtspr	IBAT1U, r0 +	mtspr	IBAT2U, r0 +	mtspr	IBAT3U, r0 +	isync +	mtspr	DBAT0U, r0 +	mtspr	DBAT1U, r0 +	mtspr	DBAT2U, r0 +	mtspr	DBAT3U, r0 +	isync +	sync +	blr + +	/* setup_bats - set them up to some initial state */ +	.globl	setup_bats +setup_bats: +	addis	r0, r0, 0x0000 + +	/* IBAT 0 */ +	addis	r4, r0, CFG_IBAT0L@h +	ori	r4, r4, CFG_IBAT0L@l +	addis	r3, r0, CFG_IBAT0U@h +	ori	r3, r3, CFG_IBAT0U@l +	mtspr	IBAT0L, r4 +	mtspr	IBAT0U, r3 +	isync + +	/* DBAT 0 */ +	addis	r4, r0, CFG_DBAT0L@h +	ori	r4, r4, CFG_DBAT0L@l +	addis	r3, r0, CFG_DBAT0U@h +	ori	r3, r3, CFG_DBAT0U@l +	mtspr	DBAT0L, r4 +	mtspr	DBAT0U, r3 +	isync + +	/* IBAT 1 */ +	addis	r4, r0, CFG_IBAT1L@h +	ori	r4, r4, CFG_IBAT1L@l +	addis	r3, r0, CFG_IBAT1U@h +	ori	r3, r3, CFG_IBAT1U@l +	mtspr	IBAT1L, r4 +	mtspr	IBAT1U, r3 +	isync + +	/* DBAT 1 */ +	addis	r4, r0, CFG_DBAT1L@h +	ori	r4, r4, CFG_DBAT1L@l +	addis	r3, r0, CFG_DBAT1U@h +	ori	r3, r3, CFG_DBAT1U@l +	mtspr	DBAT1L, r4 +	mtspr	DBAT1U, r3 +	isync + +	/* IBAT 2 */ +	addis	r4, r0, CFG_IBAT2L@h +	ori	r4, r4, CFG_IBAT2L@l +	addis	r3, r0, CFG_IBAT2U@h +	ori	r3, r3, CFG_IBAT2U@l +	mtspr	IBAT2L, r4 +	mtspr	IBAT2U, r3 +	isync + +	/* DBAT 2 */ +	addis	r4, r0, CFG_DBAT2L@h +	ori	r4, r4, CFG_DBAT2L@l +	addis	r3, r0, CFG_DBAT2U@h +	ori	r3, r3, CFG_DBAT2U@l +	mtspr	DBAT2L, r4 +	mtspr	DBAT2U, r3 +	isync + +	/* IBAT 3 */ +	addis	r4, r0, CFG_IBAT3L@h +	ori	r4, r4, CFG_IBAT3L@l +	addis	r3, r0, CFG_IBAT3U@h +	ori	r3, r3, CFG_IBAT3U@l +	mtspr	IBAT3L, r4 +	mtspr	IBAT3U, r3 +	isync + +	/* DBAT 3 */ +	addis	r4, r0, CFG_DBAT3L@h +	ori	r4, r4, CFG_DBAT3L@l +	addis	r3, r0, CFG_DBAT3U@h +	ori	r3, r3, CFG_DBAT3U@l +	mtspr	DBAT3L, r4 +	mtspr	DBAT3U, r3 +	isync + +	/* bats are done, now invalidate the TLBs */ + +	addis	r3, 0, 0x0000 +	addis	r5, 0, 0x4    /* upper bound of 0x00040000 for 7400/750 */ + +	isync + +tlblp: +	tlbie	r3 +	sync +	addi	r3, r3, 0x1000 +	cmp	0, 0, r3, r5 +	blt tlblp + +	blr + +	.globl enable_addr_trans +enable_addr_trans: +	/* enable address translation */ +	mfmsr	r5 +	ori	r5, r5, (MSR_IR | MSR_DR) +	mtmsr	r5 +	isync +	blr + +	.globl disable_addr_trans +disable_addr_trans: +	/* disable address translation */ +	mflr	r4 +	mfmsr	r3 +	andi.	r0, r3, (MSR_IR | MSR_DR) +	beqlr +	andc	r3, r3, r0 +	mtspr	SRR0, r4 +	mtspr	SRR1, r3 +	rfi + +/* + * 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 + +	.globl	dc_read +dc_read: +	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		*/ +	mr	r9,  r4		/* Save copy of Global Data pointer	*/ +	mr	r10, r5		/* Save copy of Destination Address	*/ + +	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 +	li	r6, CFG_CACHELINE_SIZE		/* Cache Line Size	*/ + +	/* +	 * 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 +	/* then the one used by the C code */ +	add	r30, r30, r15 + +	/* +	 * Now relocate code +	 */ +#ifdef CONFIG_ECC +	bl	board_relocate_rom +	sync +	mr	r3, r10				/* 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 +	li	r6, CFG_CACHELINE_SIZE		/* Cache Line Size	*/ +#else +	cmplw	cr1,r3,r4 +	addi	r0,r5,3 +	srwi.	r0,r0,2 +	beq	cr1,4f		/* In place copy is not necessary	*/ +	beq	7f		/* Protect against 0 count		*/ +	mtctr	r0 +	bge	cr1,2f + +	la	r8,-4(r4) +	la	r7,-4(r3) +1:	lwzu	r0,4(r8) +	stwu	r0,4(r7) +	bdnz	1b +	b	4f + +2:	slwi	r0,r0,2 +	add	r8,r4,r0 +	add	r7,r3,r0 +3:	lwzu	r0,-4(r8) +	stwu	r0,-4(r7) +	bdnz	3b +#endif +/* + * Now flush the cache: note that we must start from a cache aligned + * address. Otherwise we might miss one cache line. + */ +4:	cmpwi	r6,0 +	add	r5,r3,r5 +	beq	7f		/* Always flush prefetch queue in any case */ +	subi	r0,r6,1 +	andc	r3,r3,r0 +	mr	r4,r3 +5:	dcbst	0,r4 +	add	r4,r4,r6 +	cmplw	r4,r5 +	blt	5b +	sync			/* Wait for all dcbst to complete on bus */ +	mr	r4,r3 +6:	icbi	0,r4 +	add	r4,r4,r6 +	cmplw	r4,r5 +	blt	6b +7:	sync			/* Wait for all icbi to complete on bus	*/ +	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: +#ifdef CONFIG_ECC +	bl	board_init_ecc +#endif +	/* +	 * 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, r10		/* Destination Address		*/ +	bl	after_reloc + +	/* not reached - end relocate_code */ +/*-----------------------------------------------------------------------*/ + +	/* 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, 18, 31	/* _start & 0x3FFF	*/ + +	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 + +	/* enable execptions from RAM vectors */ +	mfmsr	r7 +	li	r8,MSR_IP +	andc	r7,r7,r8 +	mtmsr	r7 + +	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 + +#ifdef CFG_INIT_RAM_LOCK +lock_ram_in_cache: +	/* Allocate Initial RAM in data cache. +	 */ +	lis	r3, (CFG_INIT_RAM_ADDR & ~31)@h +	ori	r3, r3, (CFG_INIT_RAM_ADDR & ~31)@l +	li	r2, ((CFG_INIT_RAM_END & ~31) + \ +		     (CFG_INIT_RAM_ADDR & 31) + 31) / 32 +	mtctr	r2 +1: +	dcbz	r0, r3 +	addi	r3, r3, 32 +	bdnz	1b + +	/* Lock the data cache */ +	mfspr	r0, HID0 +	ori	r0, r0, 0x1000 +	sync +	mtspr	HID0, r0 +	sync +	blr + +.globl unlock_ram_in_cache +unlock_ram_in_cache: +	/* invalidate the INIT_RAM section */ +	lis	r3, (CFG_INIT_RAM_ADDR & ~31)@h +	ori	r3, r3, (CFG_INIT_RAM_ADDR & ~31)@l +	li	r2, ((CFG_INIT_RAM_END & ~31) + \ +		     (CFG_INIT_RAM_ADDR & 31) + 31) / 32 +	mtctr	r2 +1:	icbi	r0, r3 +	addi	r3, r3, 32 +	bdnz	1b +	sync			/* Wait for all icbi to complete on bus	*/ +	isync + +	/* Unlock the data cache and invalidate it */ +	mfspr   r0, HID0 +	li      r3,0x1000 +	andc    r0,r0,r3 +	li	r3,0x0400 +	or	r0,r0,r3 +	sync +	mtspr   HID0, r0 +	sync +	blr +#endif diff --git a/cpu/mpc8260/start.S b/cpu/mpc8260/start.S new file mode 100644 index 000000000..10a8988ee --- /dev/null +++ b/cpu/mpc8260/start.S @@ -0,0 +1,1092 @@ +/* + *  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> + * + * 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 + */ + +/* + *  U-Boot - Startup Code for MPC8260 PowerPC based Embedded Boards + */ +#include <config.h> +#include <mpc8260.h> +#include <version.h> + +#define CONFIG_8260 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 <asm/cache.h> +#include <asm/mmu.h> + +#ifndef  CONFIG_IDENT_STRING +#define  CONFIG_IDENT_STRING "" +#endif + +/* We don't want the  MMU yet. +*/ +#undef	MSR_KERNEL +/* Floating Point enable, Machine Check and Recoverable Interr. */ +#ifdef DEBUG +#define MSR_KERNEL (MSR_FP|MSR_RI) +#else +#define MSR_KERNEL (MSR_FP|MSR_ME|MSR_RI) +#endif + +/* + * 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) +#if defined(CONFIG_HYMOD) +	GOT_ENTRY(environment) +#endif +	END_GOT + +/* + * Version string - must be in data segment because MPC8260 uses the first + * 256 bytes for the Hard Reset Configuration Word table (see below). + * Similarly, can't have the U-Boot Magic Number as the first thing in + * the image - don't know how this will affect the image tools, but I guess + * I'll find out soon + */ +	.data +	.globl	version_string +version_string: +	.ascii U_BOOT_VERSION +	.ascii " (", __DATE__, " - ", __TIME__, ")" +	.ascii CONFIG_IDENT_STRING, "\0" + +/* + *  Hard Reset Configuration Word (HRCW) table + * + *  The Hard Reset Configuration Word (HRCW) sets a number of useful things + *  such as whether there is an external memory controller, whether the + *  PowerPC core is disabled (i.e. only the communications processor is + *  active, accessed by another CPU on the bus), whether using external + *  arbitration, external bus mode, boot port size, core initial prefix, + *  internal space base, boot memory space, etc. + * + *  These things dictate where the processor begins execution, where the + *  boot ROM appears in memory, the memory controller setup when access + *  boot ROM, etc. The HRCW is *extremely* important. + * + *  The HRCW is read from the bus during reset. One CPU on the bus will + *  be a hard reset configuration master, any others will be hard reset + *  configuration slaves. The master reads eight HRCWs from flash during + *  reset - the first it uses for itself, the other 7 it communicates to + *  up to 7 configuration slaves by some complicated mechanism, which is + *  not really important here. + * + *  The configuration master performs 32 successive reads starting at address + *  0 and incrementing by 8 each read (i.e. on 64 bit boundaries) but only 8 + *  bits is read, and always from byte lane D[0-7] (so that port size of the + *  boot device does not matter). The first four reads form the 32 bit HRCW + *  for the master itself. The second four reads form the HRCW for the first + *  slave, and so on, up to seven slaves. The 32 bit HRCW is formed by + *  concatenating the four bytes, with the first read placed in byte 0 (the + *  most significant byte), and so on with the fourth read placed in byte 3 + *  (the least significant byte). + */ +#define _HRCW_TABLE_ENTRY(w)		\ +	.fill	8,1,(((w)>>24)&0xff);	\ +	.fill	8,1,(((w)>>16)&0xff);	\ +	.fill	8,1,(((w)>> 8)&0xff);	\ +	.fill	8,1,(((w)    )&0xff) +	.text +	.globl	_hrcw_table +_hrcw_table: +	_HRCW_TABLE_ENTRY(CFG_HRCW_MASTER) +	_HRCW_TABLE_ENTRY(CFG_HRCW_SLAVE1) +	_HRCW_TABLE_ENTRY(CFG_HRCW_SLAVE2) +	_HRCW_TABLE_ENTRY(CFG_HRCW_SLAVE3) +	_HRCW_TABLE_ENTRY(CFG_HRCW_SLAVE4) +	_HRCW_TABLE_ENTRY(CFG_HRCW_SLAVE5) +	_HRCW_TABLE_ENTRY(CFG_HRCW_SLAVE6) +	_HRCW_TABLE_ENTRY(CFG_HRCW_SLAVE7) +/* + *  After configuration, a system reset exception is executed using the + *  vector at offset 0x100 relative to the base set by MSR[IP]. If MSR[IP] + *  is 0, the base address is 0x00000000. If MSR[IP] is 1, the base address + *  is 0xfff00000. In the case of a Power On Reset or Hard Reset, the value + *  of MSR[IP] is determined by the CIP field in the HRCW. + * + *  Other bits in the HRCW set up the Base Address and Port Size in BR0. + *  This determines the location of the boot ROM (flash or EPROM) in the + *  processor's address space at boot time. As long as the HRCW is set up + *  so that we eventually end up executing the code below when the processor + *  executes the reset exception, the actual values used should not matter. + * + *  Once we have got here, the address mask in OR0 is cleared so that the + *  bottom 32K of the boot ROM is effectively repeated all throughout the + *  processor's address space, after which we can jump to the absolute + *  address at which the boot ROM was linked at compile time, and proceed + *  to initialise the memory controller without worrying if the rug will be + *  pulled out from under us, so to speak (it will be fine as long as we + *  configure BR0 with the same boot ROM link address). + */ +	. = EXC_OFF_SYS_RESET + +	.globl	_start +_start: +	li	r21, BOOTFLAG_COLD	/* Normal Power-On: Boot from FLASH*/ +	b	boot_cold + +	. = EXC_OFF_SYS_RESET + 0x10 + +	.globl	_start_warm +_start_warm: +	li	r21, BOOTFLAG_WARM	/* Software reboot		*/ +	b	boot_warm + +boot_cold: +boot_warm: +	mfmsr	r5			/* save msr contents		*/ + +#if defined(CONFIG_COGENT) +	/* this is what the cogent EPROM does */ +	li	r0, 0 +	mtmsr	r0 +	isync +	bl	cogent_init_8260 +#endif	/* CONFIG_COGENT */ + +#if defined(CFG_DEFAULT_IMMR) +	lis	r3, CFG_IMMR@h +	ori	r3, r3, CFG_IMMR@l +	lis	r4, CFG_DEFAULT_IMMR@h +	stw	r3, 0x1A8(r4) +#endif /* CFG_DEFAULT_IMMR */ + +	/* Initialise the MPC8260 processor core			*/ +	/*--------------------------------------------------------------*/ + +	bl	init_8260_core + +#ifndef CFG_RAMBOOT +	/* When booting from ROM (Flash or EPROM), clear the		*/ +	/* Address Mask in OR0 so ROM appears everywhere		*/ +	/*--------------------------------------------------------------*/ + +	lis	r3, (CFG_IMMR+IM_REGBASE)@h +	lwz	r4, IM_OR0@l(r3) +	li	r5, 0x7fff +	and	r4, r4, r5 +	stw	r4, IM_OR0@l(r3) + +	/* 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: +#endif	/* CFG_RAMBOOT */ + +	/* initialize some things that are hard to access from C	*/ +	/*--------------------------------------------------------------*/ + +	lis	r3, CFG_IMMR@h		/* set up stack in internal DPRAM */ +	ori	r1, r3, CFG_INIT_SP_OFFSET +	li	r0, 0			/* Make room for stack frame header and	*/ +	stwu	r0, -4(r1)		/* clear final stack frame so that	*/ +	stwu	r0, -4(r1)		/* stack backtraces terminate cleanly	*/ + +	/* 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 (in Flash)*/ + +#ifdef DEBUG +	bl	init_debug	/* set up debugging stuff		*/ +#endif + +	mr	r3, r21 +	/* r3: BOOTFLAG */ +	bl	board_init_f	/* run 1st part of board init code (in Flash)*/ + +/* + * Vector Table + */ + +	.globl	_start_of_vectors +_start_of_vectors: + +/* Machine check */ +	STD_EXCEPTION(0x200, MachineCheck, MachineCheckException) + +/* Data Storage exception. */ +	STD_EXCEPTION(0x300, DataStorage, UnknownException) + +/* Instruction Storage exception. */ +	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 */ +	rlwimi	r20,r23,0,25,25		/* copy IP 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 */ +	rlwimi	r20,r23,0,25,25		/* copy IP 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 + +	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	r12,0xd00-4*3		/* save LR & SRRx */ +	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*3		/* restore regs */ +	lwz	r11,0(r12) +	mtlr	r11 +	lwz	r11,4(r12) +	mtspr	SRR0,r11 +	lwz	r11,8(r12) +	mtspr	SRR1,r11 + +	SYNC +	rfi + +	STD_EXCEPTION(0xd00, SingleStep, UnknownException) + +	STD_EXCEPTION(0xe00, Trap_0e, UnknownException) +	STD_EXCEPTION(0xf00, Trap_0f, UnknownException) + +	STD_EXCEPTION(0x1000, InstructionTLBMiss, UnknownException) +	STD_EXCEPTION(0x1100, DataLoadTLBMiss, UnknownException) +	STD_EXCEPTION(0x1200, DataStoreTLBMiss, UnknownException) +#ifdef DEBUG +	. = 0x1300 +	/* +	 * This exception occurs when the program counter matches the +	 * Instruction Address Breakpoint Register (IABR). +	 * +	 * I want the cpu to halt if this occurs so I can hunt around +	 * with the debugger and look at things. +	 * +	 * When DEBUG is defined, both machine check enable (in the MSR) +	 * and checkstop reset enable (in the reset mode register) are +	 * turned off and so a checkstop condition will result in the cpu +	 * halting. +	 * +	 * I force the cpu into a checkstop condition by putting an illegal +	 * instruction here (at least this is the theory). +	 * +	 * well - that didnt work, so just do an infinite loop! +	 */ +1:	b	1b +#else +	STD_EXCEPTION(0x1300, InstructionBreakpoint, DebugException) +#endif +	STD_EXCEPTION(0x1400, SMI, UnknownException) + +	STD_EXCEPTION(0x1500, Trap_15, UnknownException) +	STD_EXCEPTION(0x1600, Trap_16, UnknownException) +	STD_EXCEPTION(0x1700, Trap_17, UnknownException) +	STD_EXCEPTION(0x1800, Trap_18, UnknownException) +	STD_EXCEPTION(0x1900, Trap_19, UnknownException) +	STD_EXCEPTION(0x1a00, Trap_1a, UnknownException) +	STD_EXCEPTION(0x1b00, Trap_1b, UnknownException) +	STD_EXCEPTION(0x1c00, Trap_1c, UnknownException) +	STD_EXCEPTION(0x1d00, Trap_1d, UnknownException) +	STD_EXCEPTION(0x1e00, Trap_1e, UnknownException) +	STD_EXCEPTION(0x1f00, Trap_1f, UnknownException) +	STD_EXCEPTION(0x2000, Trap_20, UnknownException) +	STD_EXCEPTION(0x2100, Trap_21, UnknownException) +	STD_EXCEPTION(0x2200, Trap_22, UnknownException) +	STD_EXCEPTION(0x2300, Trap_23, UnknownException) +	STD_EXCEPTION(0x2400, Trap_24, UnknownException) +	STD_EXCEPTION(0x2500, Trap_25, UnknownException) +	STD_EXCEPTION(0x2600, Trap_26, UnknownException) +	STD_EXCEPTION(0x2700, Trap_27, UnknownException) +	STD_EXCEPTION(0x2800, Trap_28, UnknownException) +	STD_EXCEPTION(0x2900, Trap_29, UnknownException) +	STD_EXCEPTION(0x2a00, Trap_2a, UnknownException) +	STD_EXCEPTION(0x2b00, Trap_2b, UnknownException) +	STD_EXCEPTION(0x2c00, Trap_2c, UnknownException) +	STD_EXCEPTION(0x2d00, Trap_2d, UnknownException) +	STD_EXCEPTION(0x2e00, Trap_2e, UnknownException) +	STD_EXCEPTION(0x2f00, Trap_2f, UnknownException) + + +	.globl	_end_of_vectors +_end_of_vectors: + +	. = 0x3000 + +/* + * 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) +	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 + +#if defined(CONFIG_COGENT) + +/* + * This code initialises the MPC8260 processor core + * (conforms to PowerPC 603e spec) + */ + +	.globl	cogent_init_8260 +cogent_init_8260: + +	/* Taken from page 14 of CMA282 manual				*/ +	/*--------------------------------------------------------------*/ + +	lis	r4, (CFG_IMMR+IM_REGBASE)@h +	lis	r3, CFG_IMMR@h +	stw	r3, IM_IMMR@l(r4) +	lwz	r3, IM_IMMR@l(r4) +	stw	r3, 0(r0) +	lis	r3, CFG_SYPCR@h +	ori	r3, r3, CFG_SYPCR@l +	stw	r3, IM_SYPCR@l(r4) +	lwz	r3, IM_SYPCR@l(r4) +	stw	r3, 4(r0) +	lis	r3, CFG_SCCR@h +	ori	r3, r3, CFG_SCCR@l +	stw	r3, IM_SCCR@l(r4) +	lwz	r3, IM_SCCR@l(r4) +	stw	r3, 8(r0) + +	/* the rest of this was disassembled from the			*/ +	/* EPROM code that came with my CMA282 CPU module		*/ +	/*--------------------------------------------------------------*/ + +	lis	r1, 0x1234 +	ori	r1, r1, 0x5678 +	stw	r1, 0x20(r0) +	lwz	r1, 0x20(r0) +	stw	r1, 0x24(r0) +	lwz	r1, 0x24(r0) +	lis	r3, 0x0e80 +	ori	r3, r3, 0 +	stw	r1, 4(r3) +	lwz	r1, 4(r3) + +	/* Done!							*/ +	/*--------------------------------------------------------------*/ + +	blr + +#endif	/* CONFIG_COGENT */ + +/* + * This code initialises the MPC8260 processor core + * (conforms to PowerPC 603e spec) + * Note: expects original MSR contents to be in r5. + */ + +	.globl	init_8260_core +init_8260_core: + +	/* Initialize machine status; enable machine check interrupt	*/ +	/*--------------------------------------------------------------*/ + +	li	r3, MSR_KERNEL		/* Set ME and RI flags */ +	rlwimi	r3, r5, 0, 25, 25	/* preserve IP bit set by HRCW */ +#ifdef DEBUG +	rlwimi	r3, r5, 0, 21, 22	/* debugger might set SE & BE bits */ +#endif +	SYNC				/* Some chip revs need this... */ +	mtmsr	r3 +	SYNC +	mtspr	SRR1, r3		/* Make SRR1 match MSR */ + +	/* Initialise the SYPCR early, and reset the watchdog (if req)	*/ +	/*--------------------------------------------------------------*/ + +	lis	r3, (CFG_IMMR+IM_REGBASE)@h +#if !defined(CONFIG_COGENT) +	lis	r4, CFG_SYPCR@h +	ori	r4, r4, CFG_SYPCR@l +	stw	r4, IM_SYPCR@l(r3) +#endif /* !CONFIG_COGENT */ +#if defined(CONFIG_WATCHDOG) +	li	r4, 21868		/* = 0x556c */ +	sth	r4, IM_SWSR@l(r3) +	li	r4, -21959		/* = 0xaa39 */ +	sth	r4, IM_SWSR@l(r3) +#endif /* CONFIG_WATCHDOG */ + +	/* Initialize the Hardware Implementation-dependent Registers	*/ +	/* HID0 also contains cache control				*/ +	/*--------------------------------------------------------------*/ + +	lis	r3, CFG_HID0_INIT@h +	ori	r3, r3, CFG_HID0_INIT@l +	SYNC +	mtspr	HID0, r3 + +	lis	r3, CFG_HID0_FINAL@h +	ori	r3, r3, CFG_HID0_FINAL@l +	SYNC +	mtspr	HID0, r3 + +	lis	r3, CFG_HID2@h +	ori	r3, r3, CFG_HID2@l +	mtspr	HID2, r3 + +	/* clear all BAT's						*/ +	/*--------------------------------------------------------------*/ + +	li	r0, 0 +	mtspr	DBAT0U, r0 +	mtspr	DBAT0L, r0 +	mtspr	DBAT1U, r0 +	mtspr	DBAT1L, r0 +	mtspr	DBAT2U, r0 +	mtspr	DBAT2L, r0 +	mtspr	DBAT3U, r0 +	mtspr	DBAT3L, r0 +	mtspr	IBAT0U, r0 +	mtspr	IBAT0L, r0 +	mtspr	IBAT1U, r0 +	mtspr	IBAT1L, r0 +	mtspr	IBAT2U, r0 +	mtspr	IBAT2L, r0 +	mtspr	IBAT3U, r0 +	mtspr	IBAT3L, r0 +	SYNC + +	/* invalidate all tlb's						*/ +	/*								*/ +	/* From the 603e User Manual: "The 603e provides the ability to	*/ +	/* invalidate a TLB entry. The TLB Invalidate Entry (tlbie)	*/ +	/* instruction invalidates the TLB entry indexed by the EA, and	*/ +	/* operates on both the instruction and data TLBs simultaneously*/ +	/* invalidating four TLB entries (both sets in each TLB). The	*/ +	/* index corresponds to bits 15-19 of the EA. To invalidate all	*/ +	/* entries within both TLBs, 32 tlbie instructions should be	*/ +	/* issued, incrementing this field by one each time."		*/ +	/*								*/ +	/* "Note that the tlbia instruction is not implemented on the	*/ +	/* 603e."							*/ +	/*								*/ +	/* bits 15-19 correspond to addresses 0x00000000 to 0x0001F000	*/ +	/* incrementing by 0x1000 each time. The code below is sort of	*/ +	/* based on code in "flush_tlbs" from arch/ppc/kernel/head.S	*/ +	/*								*/ +	/*--------------------------------------------------------------*/ + +	li	r3, 32 +	mtctr	r3 +	li	r3, 0 +1:	tlbie	r3 +	addi	r3, r3, 0x1000 +	bdnz	1b +	SYNC + +	/* Done!							*/ +	/*--------------------------------------------------------------*/ + +	blr + +#ifdef DEBUG + +/* + * initialise things related to debugging. + * + * must be called after the global offset table (GOT) is initialised + * (GET_GOT) and after cpu_init_f() has executed. + */ + +	.globl	init_debug +init_debug: + +	lis	r3, (CFG_IMMR+IM_REGBASE)@h + +	/* Quick and dirty hack to enable the RAM and copy the		*/ +	/* vectors so that we can take exceptions.			*/ +	/*--------------------------------------------------------------*/ +	/* write Memory Refresh Prescaler */ +	li	r4, CFG_MPTPR +	sth	r4, IM_MPTPR@l(r3) +	/* write 60x Refresh Timer */ +	li	r4, CFG_PSRT +	stb	r4, IM_PSRT@l(r3) +	/* init the 60x SDRAM Mode Register */ +	lis	r4, (CFG_PSDMR|PSDMR_OP_NORM)@h +	ori	r4, r4, (CFG_PSDMR|PSDMR_OP_NORM)@l +	stw	r4, IM_PSDMR@l(r3) +	/* write Precharge All Banks command */ +	lis	r4, (CFG_PSDMR|PSDMR_OP_PREA)@h +	ori	r4, r4, (CFG_PSDMR|PSDMR_OP_PREA)@l +	stw	r4, IM_PSDMR@l(r3) +	stb	r0, 0(0) +	/* write eight CBR Refresh commands */ +	lis	r4, (CFG_PSDMR|PSDMR_OP_CBRR)@h +	ori	r4, r4, (CFG_PSDMR|PSDMR_OP_CBRR)@l +	stw	r4, IM_PSDMR@l(r3) +	stb	r0, 0(0) +	stb	r0, 0(0) +	stb	r0, 0(0) +	stb	r0, 0(0) +	stb	r0, 0(0) +	stb	r0, 0(0) +	stb	r0, 0(0) +	stb	r0, 0(0) +	/* write Mode Register Write command */ +	lis	r4, (CFG_PSDMR|PSDMR_OP_MRW)@h +	ori	r4, r4, (CFG_PSDMR|PSDMR_OP_MRW)@l +	stw	r4, IM_PSDMR@l(r3) +	stb	r0, 0(0) +	/* write Normal Operation command and enable Refresh */ +	lis	r4, (CFG_PSDMR|PSDMR_OP_NORM|PSDMR_RFEN)@h +	ori	r4, r4, (CFG_PSDMR|PSDMR_OP_NORM|PSDMR_RFEN)@l +	stw	r4, IM_PSDMR@l(r3) +	stb	r0, 0(0) +	/* RAM should now be operational */ + +#define VEC_WRD_CNT	((_end_of_vectors - _start + EXC_OFF_SYS_RESET) / 4) + +	lwz	r3, GOT(_end_of_vectors) +	rlwinm	r4, r3, 0, 18, 31	/* _end_of_vectors & 0x3FFF	*/ +	lis	r5, VEC_WRD_CNT@h +	ori	r5, r5, VEC_WRD_CNT@l +	mtctr	r5 +1: +	lwzu	r5, -4(r3) +	stwu	r5, -4(r4) +	bdnz	1b + +	/* Load the Instruction Address Breakpoint Register (IABR).	*/ +	/* 								*/ +	/* The address to load is stored in the first word of dual port	*/ +	/* ram and should be preserved while the power is on, so you	*/ +	/* can plug addresses into that location then reset the cpu and	*/ +	/* this code will load that address into the IABR after the	*/ +	/* reset.							*/ +	/* 								*/ +	/* When the program counter matches the contents of the IABR,	*/ +	/* an exception is generated (before the instruction at that	*/ +	/* location completes). The vector for this exception is 0x1300 */ +	/*--------------------------------------------------------------*/ +	lis	r3, CFG_IMMR@h +	lwz	r3, 0(r3) +	mtspr	IABR, r3 + +	/* Set the entire dual port RAM (where the initial stack	*/ +	/* resides) to a known value - makes it easier to see where	*/ +	/* the stack has been written					*/ +	/*--------------------------------------------------------------*/ +	lis	r3, (CFG_IMMR + CFG_INIT_SP_OFFSET)@h +	ori	r3, r3, (CFG_IMMR + CFG_INIT_SP_OFFSET)@l +	li	r4, ((CFG_INIT_SP_OFFSET - 4) / 4) +	mtctr	r4 +	lis	r4, 0xdeadbeaf@h +	ori	r4, r4, 0xdeadbeaf@l +1: +	stwu	r4, -4(r3) +	bdnz	1b + +	/* Done!							*/ +	/*--------------------------------------------------------------*/ + +	blr +#endif + +/* Cache functions. + * + * Note: requires that all cache bits in + * HID0 are in the low half word. + */ +	.globl	icache_enable +icache_enable: +	mfspr	r3, HID0 +	ori	r3, r3, HID0_ICE +	lis	r4, 0 +	ori	r4, r4, HID0_ILOCK +	andc	r3, r3, r4 +	ori	r4, r3, HID0_ICFI +	isync +	mtspr	HID0, r4	/* sets enable and invalidate, clears lock */ +	isync +	mtspr	HID0, r3	/* clears invalidate */ +	blr + +	.globl	icache_disable +icache_disable: +	mfspr	r3, HID0 +	lis	r4, 0 +	ori	r4, r4, HID0_ICE|HID0_ILOCK +	andc	r3, r3, r4 +	ori	r4, r3, HID0_ICFI +	isync +	mtspr	HID0, r4	/* sets invalidate, clears enable and lock */ +	isync +	mtspr	HID0, r3	/* clears invalidate */ +	blr + +	.globl	icache_status +icache_status: +	mfspr	r3, HID0 +	rlwinm	r3, r3, HID0_ICE_BITPOS + 1, 31, 31 +	blr + +	.globl	dcache_enable +dcache_enable: +	mfspr	r3, HID0 +	ori	r3, r3, HID0_DCE +	lis	r4, 0 +	ori	r4, r4, HID0_DLOCK +	andc	r3, r3, r4 +	ori	r4, r3, HID0_DCI +	sync +	mtspr	HID0, r4	/* sets enable and invalidate, clears lock */ +	sync +	mtspr	HID0, r3	/* clears invalidate */ +	blr + +	.globl	dcache_disable +dcache_disable: +	mfspr	r3, HID0 +	lis	r4, 0 +	ori	r4, r4, HID0_DCE|HID0_DLOCK +	andc	r3, r3, r4 +	ori	r4, r3, HID0_DCI +	sync +	mtspr	HID0, r4	/* sets invalidate, clears enable and lock */ +	sync +	mtspr	HID0, r3	/* clears invalidate */ +	blr + +	.globl	dcache_status +dcache_status: +	mfspr	r3, HID0 +	rlwinm	r3, r3, HID0_DCE_BITPOS + 1, 31, 31 +	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		*/ +	mr	r9,  r4		/* Save copy of Global Data pointer	*/ +	mr	r10, r5		/* Save copy of Destination Address	*/ + +	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 +	li	r6, CFG_CACHELINE_SIZE		/* Cache Line Size	*/ + +	/* +	 * 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 +	/* then 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	7f		/* Protect against 0 count		*/ +	mtctr	r0 +	bge	cr1,2f + +	la	r8,-4(r4) +	la	r7,-4(r3) +1:	lwzu	r0,4(r8) +	stwu	r0,4(r7) +	bdnz	1b +	b	4f + +2:	slwi	r0,r0,2 +	add	r8,r4,r0 +	add	r7,r3,r0 +3:	lwzu	r0,-4(r8) +	stwu	r0,-4(r7) +	bdnz	3b + +/* + * Now flush the cache: note that we must start from a cache aligned + * address. Otherwise we might miss one cache line. + */ +4:	cmpwi	r6,0 +	add	r5,r3,r5 +	beq	7f		/* Always flush prefetch queue in any case */ +	subi	r0,r6,1 +	andc	r3,r3,r0 +	mfspr	r7,HID0		/* don't do dcbst if dcache is disabled */ +	rlwinm	r7,r7,HID0_DCE_BITPOS+1,31,31 +	cmpwi	r7,0 +	beq	9f +	mr	r4,r3 +5:	dcbst	0,r4 +	add	r4,r4,r6 +	cmplw	r4,r5 +	blt	5b +	sync			/* Wait for all dcbst to complete on bus */ +9:	mfspr	r7,HID0		/* don't do icbi if icache is disabled */ +	rlwinm	r7,r7,HID0_ICE_BITPOS+1,31,31 +	cmpwi	r7,0 +	beq	7f +	mr	r4,r3 +6:	icbi	0,r4 +	add	r4,r4,r6 +	cmplw	r4,r5 +	blt	6b +7:	sync			/* Wait for all icbi to complete on bus	*/ +	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) +#if defined(CONFIG_HYMOD) +	/* +	 * For HYMOD - the environment is the very last item in flash. +	 * The real .bss stops just before environment starts, so only +	 * clear up to that point. +	 * +	 * taken from mods for FADS board +	 */ +	lwz	r4,GOT(environment) +#else +	lwz	r4,GOT(_end) +#endif + +	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, 18, 31	/* _start & 0x3FFF	*/ + +	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 + +	mfmsr	r3			/* now that the vectors have	*/ +	lis	r7, MSR_IP@h		/* relocated into low memory	*/ +	ori	r7, r7, MSR_IP@l	/* MSR[IP] can be turned off	*/ +	andc	r3, r3, r7		/* (if it was on)		*/ +	SYNC				/* Some chip revs need this... */ +	mtmsr	r3 +	SYNC + +	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) + +	blr |