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 0000000000..f5dfba4aac --- /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 0000000000..1b41824483 --- /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 0000000000..6d1fb4cdab --- /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 0000000000..7c95b566f9 --- /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 0000000000..7bda0ad9d0 --- /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 0000000000..75b74d50b0 --- /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 0000000000..e8ce40d69c --- /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 0000000000..f99dfcc64c --- /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 0000000000..fe08f8e837 --- /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 0000000000..10a8988ee8 --- /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 |