diff options
Diffstat (limited to 'lib_i386')
| -rw-r--r-- | lib_i386/Makefile | 45 | ||||
| -rw-r--r-- | lib_i386/bios.S | 443 | ||||
| -rw-r--r-- | lib_i386/bios_setup.c | 178 | ||||
| -rw-r--r-- | lib_i386/board.c | 448 | ||||
| -rw-r--r-- | lib_i386/i386_linux.c | 174 | ||||
| -rw-r--r-- | lib_i386/ic/ali512x.c | 442 | ||||
| -rw-r--r-- | lib_i386/ic/sc520.c | 348 | ||||
| -rw-r--r-- | lib_i386/ic/sc520_asm.S | 530 | ||||
| -rw-r--r-- | lib_i386/pci_type1.c | 57 | ||||
| -rw-r--r-- | lib_i386/realmode.c | 69 | ||||
| -rw-r--r-- | lib_i386/realmode_switch.S | 223 | ||||
| -rw-r--r-- | lib_i386/zimage.c | 276 | 
12 files changed, 3233 insertions, 0 deletions
| diff --git a/lib_i386/Makefile b/lib_i386/Makefile new file mode 100644 index 000000000..34994e544 --- /dev/null +++ b/lib_i386/Makefile @@ -0,0 +1,45 @@ +# +# (C) Copyright 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 +# + +include $(TOPDIR)/config.mk + +LIB	= lib$(ARCH).a + +AOBJS	= bios.o realmode_switch.o ic/sc520_asm.o + +COBJS	= board.o bios_setup.o i386_linux.o zimage.o realmode.o \ +	  pci_type1.o ic/sc520.o ic/ali512x.o + +OBJS	= $(AOBJS) $(COBJS) + +$(LIB):	.depend $(OBJS) +	$(AR) crv $@ $(OBJS) + +######################################################################### + +.depend:	Makefile $(AOBJS:.o=.S) $(COBJS:.o=.c) +		$(CC) -M $(CFLAGS) $(AOBJS:.o=.S) $(COBJS:.o=.c) > $@ + +sinclude .depend + +######################################################################### diff --git a/lib_i386/bios.S b/lib_i386/bios.S new file mode 100644 index 000000000..2f5ea8cda --- /dev/null +++ b/lib_i386/bios.S @@ -0,0 +1,443 @@ +/* + * (C) Copyright 2002 + * Daniel Engström, Omicron Ceti AB, daniel@omicron.se + *  + * 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 + */ + +/* + * Based on msbios.c from rolo 1.6: + *---------------------------------------------------------------------- + * (C) Copyright 2000 + * Sysgo Real-Time Solutions GmbH + * Klein-Winternheim, Germany + *---------------------------------------------------------------------- + */ + +/* + * During it's initialization phase, before switching to protected + * mode, the Linux Kernel makes a few BIOS calls. This won't work + * if the board does not have a BIOS. + * + * This is a very minimalisic BIOS that supplies just enough + * functionality to keep the Linux Kernel happy. It is NOT + * a general purpose replacement for a real BIOS !! + */ + +#define OFFS_ES      0 +#define OFFS_GS      2 +#define OFFS_DS      4 +#define OFFS_DI      6 +#define OFFS_SI      8 +#define OFFS_BP      10 +#define OFFS_SP      12 +#define OFFS_BX      14 +#define OFFS_DX      16 +#define OFFS_CX      18 +#define OFFS_AX      20 +#define OFFS_VECTOR  22 +#define OFFS_IP      24 +#define OFFS_CS      26 +#define OFFS_FLAGS   28 + +#define SEGMENT      0x40 +#define STACK	     0x800  			/* stack at 0x40:0x800 -> 0x800 */ + +.section .bios, "ax" +.code16 +.org 0 + +.globl rm_int00 +rm_int00: +	pushw	$0 +	jmp	any_interrupt16 +.globl rm_int01 +rm_int01: +	pushw	$1 +	jmp	any_interrupt16 +.globl rm_int02 +rm_int02: +	pushw	$2 +	jmp	any_interrupt16 +.globl rm_int03 +rm_int03: +	pushw	$3 +	jmp	any_interrupt16 +.globl rm_int04 +rm_int04: +	pushw	$4 +	jmp	any_interrupt16 +.globl rm_int05 +rm_int05: +	pushw	$5 +	jmp	any_interrupt16 +.globl rm_int06 +rm_int06: +	pushw	$6 +	jmp	any_interrupt16 +.globl rm_int07 +rm_int07: +	pushw	$7 +	jmp	any_interrupt16 +.globl rm_int08 +rm_int08: +	pushw	$8 +	jmp	any_interrupt16 +.globl rm_int09 +rm_int09: +	pushw	$9 +	jmp	any_interrupt16 +.globl rm_int0a +rm_int0a: +	pushw	$10 +	jmp	any_interrupt16 +.globl rm_int0b +rm_int0b: +	pushw	$11 +	jmp	any_interrupt16 +.globl rm_int0c +rm_int0c: +	pushw	$12 +	jmp	any_interrupt16 +.globl rm_int0d +rm_int0d: +	pushw	$13 +	jmp	any_interrupt16 +.globl rm_int0e +rm_int0e: +	pushw	$14 +	jmp	any_interrupt16 +.globl rm_int0f +rm_int0f: +	pushw	$15 +	jmp	any_interrupt16 +.globl rm_int10 +rm_int10: +	pushw	$16 +	jmp	any_interrupt16 +.globl rm_int11 +rm_int11: +	pushw	$17 +	jmp	any_interrupt16 +.globl rm_int12 +rm_int12: +	pushw	$18 +	jmp	any_interrupt16 +.globl rm_int13 +rm_int13: +	pushw	$19 +	jmp	any_interrupt16 +.globl rm_int14 +rm_int14: +	pushw	$20 +	jmp	any_interrupt16 +.globl rm_int15 +rm_int15: +	pushw	$21 +	jmp	any_interrupt16 +.globl rm_int16 +rm_int16: +	pushw	$22 +	jmp	any_interrupt16 +.globl rm_int17 +rm_int17: +	pushw	$23 +	jmp	any_interrupt16 +.globl rm_int18 +rm_int18: +	pushw	$24 +	jmp	any_interrupt16 +.globl rm_int19 +rm_int19: +	pushw	$25 +	jmp	any_interrupt16 +.globl rm_int1a +rm_int1a: +	pushw	$26 +	jmp	any_interrupt16 +.globl rm_int1b +rm_int1b: +	pushw	$27 +	jmp	any_interrupt16 +.globl rm_int1c +rm_int1c: +	pushw	$28 +	jmp	any_interrupt16 +.globl rm_int1d +rm_int1d: +	pushw	$29 +	jmp	any_interrupt16 +.globl rm_int1e +rm_int1e: +	pushw	$30 +	jmp	any_interrupt16 +.globl rm_int1f +rm_int1f: +	pushw	$31 +	jmp	any_interrupt16 +.globl rm_def_int +rm_def_int: +	iret + +  +	/* +	 * All interrupt jumptable entries jump to here +	 * after pushing the interrupt vector number onto the +	 * stack. +	 */ +any_interrupt16: +	pusha					/* save general registers */ +	pushw	%ds				/* save some segments     */ +	pushw	%gs +	pushw	%es +	pushw	%ss				/* save callers stack segment .. */ +	popw	%gs				/* ... in gs */ +	movw	$SEGMENT,%ax			/* setup my segments */ +	movw	%ax,%ds +	movw	%ax,%es +	movw	%ax,%ss +	movw	%sp,%bp +	movw	$STACK,%sp			/* setup BIOS stackpointer */ + +gs	movw	OFFS_VECTOR(%bp), %ax +	cmpw	$0x10, %ax +	je	Lint_10h          +	cmpw	$0x11, %ax +	je	Lint_11h +	cmpw	$0x13, %ax +	je	Lint_13h +	cmpw	$0x15, %ax +	je	Lint_15h +	cmpw	$0x16, %ax +	je	Lint_16h +	movw	$0xffff, %ax +	jmp	Lout +Lint_10h:					/* VGA BIOS services */ +	call	bios_10h +	jmp	Lout +Lint_11h:	 +	call	bios_11h +	jmp	Lout +Lint_13h:					/* BIOS disk services */ +	call	bios_13h +	jmp	Lout +Lint_15h:					/* Misc. BIOS services */ +	call	bios_15h +	jmp	Lout +Lint_16h:					/* keyboard services */ +	call	bios_16h +	jmp	Lout +Lout:	 +	cmpw	$0, %ax +	je	Lhandeled +	 +	/* Insert code for unhandeled INTs here. +	 * +	 * ROLO prints a message to the console  +	 * (we could do that but then we're in 16bit mode +	 * so we'll have to get back into 32bit mode +	 * to use the console I/O routines (if we do this +	 * we shuls make int 0x10 and int 0x16 work as well)) +	 */ +Lhandeled: + +	pushw	%gs				/* restore callers stack segment */ +	popw	%ss +	movw	%bp,%sp				/* restore stackpointer */ + +	popw	%es				/* restore segment selectors */ +	popw	%gs +	popw	%ds +	 +	popa					/* restore GP registers */ +	addw	$2,%sp				/* dump vector number */ +	iret					/* return from interrupt */ + + +/* + ************************************************************ + * BIOS 	interrupt 10h -- VGA services + ************************************************************ + */ +bios_10h: +gs	movw	OFFS_AX(%bp), %ax +	shrw	$8, %ax +	cmpw	$0x3, %ax +	je	Lcur_pos +	cmpw	$0xf, %ax +	je	Lvid_state +	cmpw	$0x12, %ax +	je	Lvid_cfg +	movw	$0xffff, %ax +	ret +Lcur_pos:					/* Read Cursor Position and Size */ +gs	movw	$0, OFFS_CX(%bp) +gs	movw	$0, OFFS_DX(%bp) +	xorw	%ax, %ax +	ret +Lvid_state:					/* Get Video State */ +gs	movw	$(80 << 8|0x03), OFFS_AX(%bp)	/* 80 columns, 80x25, 16 colors */ +gs	movw	$0, OFFS_BX(%bp) +	xorw	%ax, %ax +	ret +Lvid_cfg:	/* Video Subsystem Configuration (EGA/VGA) */ +gs	movw	$0x10, OFFS_BX(%bp)		/* indicate CGA/MDA/HGA */ +	xorw	%ax, %ax +	ret + + +/* + ************************************************************ + * BIOS interrupt 11h -- Equipment determination + ************************************************************ + */ + +bios_11h: +	movw	bios_equipment, %ax +gs	movw	%ax, OFFS_AX(%bp)   +	xorw	%ax, %ax +	ret + + +/* + ************************************************************ + * BIOS interrupt 13h -- Disk services + ************************************************************ + */ +bios_13h: +gs	movw	OFFS_AX(%bp), %ax +	shrw	$8, %ax +	cmpw	$0x15, %ax +	je	Lfunc_15h +	movw	$0xffff, %ax +	ret +Lfunc_15h:	 +gs	movw	OFFS_AX(%bp), %ax +	andw	$0xff, %ax			/* return AH=0->drive not present */ +gs	movw	%ax, OFFS_AX(%bp) +	xorw	%ax, %ax +	ret +	 +	 + +/* + *********************************************************** + * BIOS interrupt 15h -- Miscellaneous services + *********************************************************** + */ +bios_15h: +gs	movw	OFFS_AX(%bp), %ax +	shrw	$8, %ax +	cmpw	$0xc0, %ax +	je	Lfunc_c0h +	cmpw	$0xe8, %ax +	je	Lfunc_e8h +	cmpw	$0x88, %ax +	je	Lfunc_88h +	movw	$0xffff, %ax +	ret + +Lfunc_c0h: 					/* Return System Configuration Parameters (PS2 only) */ +gs	movw	OFFS_FLAGS(%bp), %ax +	orw	$1, %ax				/* return carry -- function not supported */ +gs	movw	%ax, OFFS_FLAGS(%bp) +	xorw	%ax, %ax +	ret +	 +Lfunc_e8h: +gs	movw	OFFS_AX(%bp), %ax +	andw	$0xff, %ax +	cmpw	$1, %ax +	je	Lfunc_e801h +gs	movw	OFFS_FLAGS(%bp), %ax +	orw	$1, %ax				/* return carry -- function not supported */ +gs	movw	%ax, OFFS_FLAGS(%bp) +	xorw	%ax, %ax +	ret +	 +Lfunc_e801h:					/* Get memory size for >64M Configurations */ +	movw	$ram_in_64kb_chunks, %ax +	cmpw	$256, %ax +	ja	Lmore_than_16mb +	shlw	$6, %ax				/* multiply by 64 */	 +gs	movw	%ax, OFFS_AX(%bp)   		/* return memory size in 1kb chunks in AX and CX */ +gs	movw	%ax, OFFS_CX(%bp) +	xorw	%ax, %ax +gs	movw	%ax, OFFS_BX(%bp)		/* set BX and DX to 0*/ +gs	movw	%ax, OFFS_DX(%bp)	 +gs	movw	OFFS_FLAGS(%bp), %ax +	andw	$0xfffe, %ax			/* clear carry -- function succeeded */ +gs	movw	%ax, OFFS_FLAGS(%bp) +	xorw	%ax, %ax +	ret +	 +Lmore_than_16mb: +	subw	$0x100, %ax			/* subtract 16MB */	 +	 +gs	movw	$0x3c00, OFFS_AX(%bp)		/* return 0x3c00 (16MB-384k) in AX and CX */ +gs	movw	$0x3c00, OFFS_CX(%bp) +gs	movw	%ax, OFFS_BX(%bp)		/* set BX and DX to number of 64kb chunks - 256 */ +gs	movw	%ax, OFFS_DX(%bp)	 + +gs	movw	OFFS_FLAGS(%bp), %ax +	andw	$0xfffe, %ax			/* clear carry -- function succeeded */ +gs	movw	%ax, OFFS_FLAGS(%bp) +	xorw	%ax, %ax +	ret + +Lfunc_88h: +	movw	ram_in_64kb_chunks, %ax +	subw	$16, %ax +	shlw	$6, %ax +	 +gs	movw	%ax, OFFS_AX(%bp)		/* return number of kilobytes in ax */ + +gs	movw	OFFS_FLAGS(%bp), %ax +	andw	$0xfffe, %ax			/* clear carry -- function succeeded */ +gs	movw	%ax, OFFS_FLAGS(%bp) + +	xorw	%ax, %ax +	ret + + +/* + ************************************************************ + * BIOS interrupt 16h -- keyboard services + ************************************************************ + */ +bios_16h: +gs	movw	OFFS_AX(%bp), %ax +	shrw	$8, %ax +	cmpw	$0x03, %ax +	je	Lfunc_03h +	movw	$0xffff, %ax +	ret +Lfunc_03h: +	xorw	%ax, %ax			/* do nothing -- function not supported */ +	ret + + +.globl ram_in_64kb_chunks +ram_in_64kb_chunks: +	.word 	0 + +.globl bios_equipment +bios_equipment: +	.word 	0 + diff --git a/lib_i386/bios_setup.c b/lib_i386/bios_setup.c new file mode 100644 index 000000000..94319afc5 --- /dev/null +++ b/lib_i386/bios_setup.c @@ -0,0 +1,178 @@ +/* + * (C) Copyright 2002 + * Daniel Engström, Omicron Ceti AB, daniel@omicron.se + *  + * 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 + */ + + +/* + * Partly based on msbios.c from rolo 1.6: + *---------------------------------------------------------------------- + * (C) Copyright 2000 + * Sysgo Real-Time Solutions GmbH + * Klein-Winternheim, Germany + *---------------------------------------------------------------------- + */ + +#include <common.h> +#include <asm/realmode.h> +#include <asm/io.h> + +#define NUMVECTS	256 + +#define BIOS_DATA        ((char*)0x400) +#define BIOS_DATA_SIZE   256 +#define BIOS_BASE        ((char*)0xf0000) +#define BIOS_CS          0xf000 + +extern u16 ram_in_64kb_chunks; +extern u16 bios_equipment; +extern void *rm_int00; +extern void *rm_int01; +extern void *rm_int02; +extern void *rm_int03; +extern void *rm_int04; +extern void *rm_int05; +extern void *rm_int06; +extern void *rm_int07; +extern void *rm_int08; +extern void *rm_int09; +extern void *rm_int0a; +extern void *rm_int0b; +extern void *rm_int0c; +extern void *rm_int0d; +extern void *rm_int0e; +extern void *rm_int0f; +extern void *rm_int10; +extern void *rm_int11; +extern void *rm_int12; +extern void *rm_int13; +extern void *rm_int14; +extern void *rm_int15; +extern void *rm_int16; +extern void *rm_int17; +extern void *rm_int18; +extern void *rm_int19; +extern void *rm_int1a; +extern void *rm_int1b; +extern void *rm_int1c; +extern void *rm_int1d; +extern void *rm_int1e; +extern void *rm_int1f; +extern void *rm_def_int; + +/* + ************************************************************ + * Install an interrupt vector + ************************************************************ + */ + +static void setvector(int vector, u16 segment, void *handler) +{ +	u16 *ptr = (u16*)(vector*4); +	ptr[0] = ((u32)handler - (segment << 4))&0xffff; +	ptr[1] = segment; +	 +#if 0	 +	printf("setvector: int%02x -> %04x:%04x\n", +	       vector, ptr[1], ptr[0]); +#endif	 +} + +int bios_setup(void) +{ +	DECLARE_GLOBAL_DATA_PTR; +	static int done=0;	 +	int vector; +	 +	if (done) { +		return 0; +	} +	done = 1; +	 +	if (i386boot_bios_size > 65536) { +		printf("BIOS too large (%ld bytes, max is 65536)\n",  +		       i386boot_bios_size); +		return -1; +	} +	 +	memcpy(BIOS_BASE, (void*)i386boot_bios, i386boot_bios_size); + +	/* clear bda */ +	memset(BIOS_DATA, 0, BIOS_DATA_SIZE); +	 +	/* enter some values to the bda */ +	writew(0x3f8, BIOS_DATA);   /* com1 addr */ +	writew(0x2f8, BIOS_DATA+2); /* com2 addr */ +	writew(0x3e8, BIOS_DATA+4); /* com3 addr */ +	writew(0x2e8, BIOS_DATA+6); /* com4 addr */ +	writew(0x278, BIOS_DATA+8); /* lpt1 addr */ +	/* +	 * The kernel wants to read the base memory size +	 * from 40:13. Put a zero there to avoid an error message +	 */ +	writew(0, BIOS_DATA+0x13);  /* base memory size */ + +	 +	/* setup realmode interrupt vectors */	 +	for (vector = 0; vector < NUMVECTS; vector++) { +		setvector(vector, BIOS_CS, &rm_def_int); +	} +	 +	setvector(0x00, BIOS_CS, &rm_int00); +	setvector(0x01, BIOS_CS, &rm_int01); +	setvector(0x02, BIOS_CS, &rm_int02); +	setvector(0x03, BIOS_CS, &rm_int03); +	setvector(0x04, BIOS_CS, &rm_int04); +	setvector(0x05, BIOS_CS, &rm_int05); +	setvector(0x06, BIOS_CS, &rm_int06); +	setvector(0x07, BIOS_CS, &rm_int07); +	setvector(0x08, BIOS_CS, &rm_int08); +	setvector(0x09, BIOS_CS, &rm_int09); +	setvector(0x0a, BIOS_CS, &rm_int0a); +	setvector(0x0b, BIOS_CS, &rm_int0b); +	setvector(0x0c, BIOS_CS, &rm_int0c); +	setvector(0x0d, BIOS_CS, &rm_int0d); +	setvector(0x0e, BIOS_CS, &rm_int0e); +	setvector(0x0f, BIOS_CS, &rm_int0f); +	setvector(0x10, BIOS_CS, &rm_int10); +	setvector(0x11, BIOS_CS, &rm_int11); +	setvector(0x12, BIOS_CS, &rm_int12); +	setvector(0x13, BIOS_CS, &rm_int13); +	setvector(0x14, BIOS_CS, &rm_int14); +	setvector(0x15, BIOS_CS, &rm_int15); +	setvector(0x16, BIOS_CS, &rm_int16); +	setvector(0x17, BIOS_CS, &rm_int17); +	setvector(0x18, BIOS_CS, &rm_int18); +	setvector(0x19, BIOS_CS, &rm_int19); +	setvector(0x1a, BIOS_CS, &rm_int1a); +	setvector(0x1b, BIOS_CS, &rm_int1b); +	setvector(0x1c, BIOS_CS, &rm_int1c); +	setvector(0x1d, BIOS_CS, &rm_int1d); +	setvector(0x1e, BIOS_CS, &rm_int1e); +	setvector(0x1f, BIOS_CS, &rm_int1f); + +	/* fill in data area */ +	ram_in_64kb_chunks = gd->ram_size >> 16; +	bios_equipment = 0; /* FixMe */ +	 +	return 0; +} + diff --git a/lib_i386/board.c b/lib_i386/board.c new file mode 100644 index 000000000..193860a87 --- /dev/null +++ b/lib_i386/board.c @@ -0,0 +1,448 @@ +/* + * (C) Copyright 2002 + * Daniel Engström, Omicron Ceti AB, daniel@omicron.se + *  + * (C) Copyright 2002 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + *  + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Marius Groeger <mgroeger@sysgo.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 <watchdog.h> +#include <command.h> +#include <devices.h> +#include <version.h> +#include <malloc.h> +#include <syscall.h> +#include <net.h> +#include <ide.h> + +extern long _i386boot_start;	     +extern long _i386boot_end;	     +extern long _i386boot_romdata_start; +extern long _i386boot_romdata_dest;  +extern long _i386boot_romdata_size;  +extern long _i386boot_bss_start;    +extern long _i386boot_bss_size;     + +extern long _i386boot_realmode;     +extern long _i386boot_realmode_size; +extern long _i386boot_bios;          +extern long _i386boot_bios_size;     + +/* The symbols defined by the linker script becomes pointers + * which is somewhat inconveient ... */ +ulong i386boot_start         = (ulong)&_i386boot_start;         /* code start (in flash) defined in start.S */ +ulong i386boot_end           = (ulong)&_i386boot_end;	        /* code end (in flash) */ +ulong i386boot_romdata_start = (ulong)&_i386boot_romdata_start; /* datasegment in flash (also code+rodata end) */ +ulong i386boot_romdata_dest  = (ulong)&_i386boot_romdata_dest;  /* data location segment in ram */ +ulong i386boot_romdata_size  = (ulong)&_i386boot_romdata_size;  /* size of data segment */ +ulong i386boot_bss_start     = (ulong)&_i386boot_bss_start;     /* bss start */ +ulong i386boot_bss_size      = (ulong)&_i386boot_bss_size;      /* bss size */ + +ulong i386boot_realmode      = (ulong)&_i386boot_realmode;      /* start of realmode entry code */ +ulong i386boot_realmode_size = (ulong)&_i386boot_realmode_size; /* size of realmode entry code */ +ulong i386boot_bios          = (ulong)&_i386boot_bios;          /* start of BIOS emulation code */ +ulong i386boot_bios_size     = (ulong)&_i386boot_bios_size;     /* size of BIOS emulation code */ + + +const char version_string[] = +	U_BOOT_VERSION" (" __DATE__ " - " __TIME__ ")"; + + +/* + * Begin and End of memory area for malloc(), and current "brk" + */ +static ulong mem_malloc_start = 0; +static ulong mem_malloc_end = 0; +static ulong mem_malloc_brk = 0; + +static int mem_malloc_init(void) +{ +	DECLARE_GLOBAL_DATA_PTR; +         +#if 1	 +	/* start malloc area right after the stack */ +	mem_malloc_start = i386boot_bss_start +  +		i386boot_bss_size + CFG_STACK_SIZE; +	mem_malloc_start = (mem_malloc_start+3)&~3; +#else +	mem_malloc_start = 0x400000; +#endif	 +#if 1 +	/* Use all available RAM for malloc() */ +	mem_malloc_end = gd->ram_size; +#else	 +	/* Use only  CONFIG_MALLOC_SIZE bytes of RAM for malloc() */ +	mem_malloc_end = mem_malloc_start + CONFIG_MALLOC_SIZE; +#endif	 +	mem_malloc_brk = mem_malloc_start; + +	return 0; +} + +void *sbrk (ptrdiff_t increment) +{ +	ulong old = mem_malloc_brk; +	ulong new = old + increment; + +	if ((new < mem_malloc_start) || (new > mem_malloc_end)) { +		return (NULL); +	} +	mem_malloc_brk = new; + +	return ((void *) old); +} + +char *strmhz (char *buf, long hz) +{ +	long l, n; +	long m; + +	n = hz / 1000000L; +	l = sprintf (buf, "%ld", n); +	m = (hz % 1000000L) / 1000L; +	if (m != 0) +		sprintf (buf + l, ".%03ld", m); +	return (buf); +} + +/************************************************************************ + * Init Utilities							* + ************************************************************************ + * Some of this code should be moved into the core functions, + * or dropped completely, + * but let's get it working (again) first... + */ +static void syscalls_init (void) +{ +	syscall_tbl[SYSCALL_MALLOC] = (void *) malloc; +	syscall_tbl[SYSCALL_FREE] = (void *) free; + +	syscall_tbl[SYSCALL_INSTALL_HDLR] = (void *) irq_install_handler; +	syscall_tbl[SYSCALL_FREE_HDLR] = (void *) irq_free_handler; + +} + +static int init_baudrate (void) +{ +	DECLARE_GLOBAL_DATA_PTR; + +	uchar tmp[64];	/* long enough for environment variables */ +	int i = getenv_r ("baudrate", tmp, sizeof (tmp)); + +	gd->baudrate = (i > 0) +			? (int) simple_strtoul (tmp, NULL, 10) +			: CONFIG_BAUDRATE; + +	return (0); +} + +static int display_banner (void) +{ + +	printf ("\n\n%s\n\n", version_string); +	printf ("U-Boot code: %08lX -> %08lX  data: %08lX -> %08lX\n" +		"        BSS: %08lX -> %08lX stack: %08lX -> %08lX\n", +		i386boot_start, i386boot_romdata_start-1, +		i386boot_romdata_dest, i386boot_romdata_dest+i386boot_romdata_size-1, +		i386boot_bss_start, i386boot_bss_start+i386boot_bss_size-1, +		i386boot_bss_start+i386boot_bss_size,  +		i386boot_bss_start+i386boot_bss_size+CFG_STACK_SIZE-1); +	 + +	return (0); +} + +/* + * WARNING: this code looks "cleaner" than the PowerPC version, but + * has the disadvantage that you either get nothing, or everything. + * On PowerPC, you might see "DRAM: " before the system hangs - which + * gives a simple yet clear indication which part of the + * initialization if failing. + */ +static int display_dram_config (void) +{ +	DECLARE_GLOBAL_DATA_PTR; +	int i; + +	puts ("DRAM Configuration:\n"); + +	for (i=0; i<CONFIG_NR_DRAM_BANKS; i++) { +		printf ("Bank #%d: %08lx ", i, gd->bd->bi_dram[i].start); +		print_size (gd->bd->bi_dram[i].size, "\n"); +	} +	 +	return (0); +} + +static void display_flash_config (ulong size) +{ +	puts ("Flash: "); +	print_size (size, "\n"); +} + + + +/* + * Breath some life into the board... + * + * Initialize an SMC for serial comms, and carry out some hardware + * tests. + * + * The first part of initialization is running from Flash memory; + * its main purpose is to initialize the RAM so that we + * can relocate the monitor code to RAM. + */ + +/* + * All attempts to come up with a "common" initialization sequence + * that works for all boards and architectures failed: some of the + * requirements are just _too_ different. To get rid of the resulting + * mess of board dependend #ifdef'ed code we now make the whole + * initialization sequence configurable to the user. + * + * The requirements for any new initalization function is simple: it + * receives a pointer to the "global data" structure as it's only + * argument, and returns an integer return code, where 0 means + * "continue" and != 0 means "fatal error, hang the system". + */ +typedef int (init_fnc_t) (void); + +init_fnc_t *init_sequence[] = { +	cpu_init,		/* basic cpu dependent setup */ +	board_init,		/* basic board dependent setup */ +	dram_init,		/* configure available RAM banks */ +	mem_malloc_init,        /* dependant on dram_init */ +	interrupt_init,		/* set up exceptions */ +	timer_init,	 +	env_init,		/* initialize environment */ +	init_baudrate,		/* initialze baudrate settings */ +	serial_init,		/* serial communications setup */ +	display_banner, +	display_dram_config, + +	NULL, +}; + +gd_t *global_data; + +void start_i386boot (void) +{ +	DECLARE_GLOBAL_DATA_PTR; +	char *s; +	int i; +	ulong size; +	static gd_t gd_data; +	static bd_t bd_data; +	init_fnc_t **init_fnc_ptr; +	 +	show_boot_progress(0x21); + +	gd = global_data = &gd_data; +	 +	memset (gd, 0, sizeof (gd_t)); +	gd->bd = &bd_data; +	memset (gd->bd, 0, sizeof (bd_t)); +	show_boot_progress(0x22); + +	 +	for (init_fnc_ptr = init_sequence, i=0; *init_fnc_ptr; ++init_fnc_ptr, i++) { +		show_boot_progress(0xa130|i); + +		if ((*init_fnc_ptr)() != 0) { +			hang (); +		} +	} +	show_boot_progress(0x23); + +	/* configure available FLASH banks */ +	size = flash_init(); +	display_flash_config(size); +	show_boot_progress(0x24); + +	show_boot_progress(0x25); + +	/* initialize environment */ +	env_relocate (); +	show_boot_progress(0x26); + + +	/* IP Address */ +	bd_data.bi_ip_addr = getenv_IPaddr ("ipaddr"); + +	/* MAC Address */ +	{ +		int i; +		ulong reg; +		char *s, *e; +		uchar tmp[64]; + +		i = getenv_r ("ethaddr", tmp, sizeof (tmp)); +		s = (i > 0) ? tmp : NULL; + +		for (reg = 0; reg < 6; ++reg) { +			bd_data.bi_enetaddr[reg] = s ? simple_strtoul (s, &e, 16) : 0; +			if (s) +				s = (*e) ? e + 1 : e; +		} +	} + +#if defined(CONFIG_PCI) +	/* +	 * Do pci configuration +	 */ +	pci_init(); +#endif + +	show_boot_progress(0x27); + + +	devices_init (); + +	/* allocate syscalls table (console_init_r will fill it in */ +	syscall_tbl = (void **) malloc (NR_SYSCALLS * sizeof (void *)); + +	/* Initialize the console (after the relocation and devices init) */ +	console_init_r(); +	syscalls_init(); + +#ifdef CONFIG_MISC_INIT_R +	/* miscellaneous platform dependent initialisations */ +	misc_init_r(); +#endif + + +#if (CONFIG_COMMANDS & CFG_CMD_NET) && (0) +	WATCHDOG_RESET(); +# ifdef DEBUG +	puts ("Reset Ethernet PHY\n"); +# endif +	reset_phy(); +#endif + +#if (CONFIG_COMMANDS & CFG_CMD_PCMCIA) && !(CONFIG_COMMANDS & CFG_CMD_IDE) +	WATCHDOG_RESET(); +	puts ("PCMCIA:"); +	pcmcia_init(); +#endif + +#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +	WATCHDOG_RESET(); +	puts("KGDB:  "); +	kgdb_init(); +#endif + +	/* enable exceptions */ +	enable_interrupts (); +	show_boot_progress(0x28); + +	/* Must happen after interrupts are initialized since +	 * an irq handler gets installed +	 */ +#ifdef CONFIG_SERIAL_SOFTWARE_FIFO +	serial_buffered_init(); +#endif +     +#ifdef CONFIG_STATUS_LED +	status_led_set (STATUS_LED_BOOT, STATUS_LED_BLINKING); +#endif + +	udelay (20); + +	set_timer (0); + +	/* Initialize from environment */ +	if ((s = getenv ("loadaddr")) != NULL) { +		load_addr = simple_strtoul (s, NULL, 16); +	} +#if (CONFIG_COMMANDS & CFG_CMD_NET) +	if ((s = getenv ("bootfile")) != NULL) { +		copy_filename (BootFile, s, sizeof (BootFile)); +	} +#endif /* CFG_CMD_NET */ + +	WATCHDOG_RESET(); + +#if (CONFIG_COMMANDS & CFG_CMD_IDE) +	WATCHDOG_RESET(); +	puts("IDE:   "); +	ide_init(); +#endif /* CFG_CMD_IDE */ + +#if (CONFIG_COMMANDS & CFG_CMD_SCSI) +	WATCHDOG_RESET(); +	puts("SCSI:  "); +	scsi_init(); +#endif + +#if (CONFIG_COMMANDS & CFG_CMD_DOC) +	WATCHDOG_RESET(); +	puts ("DOC:   "); +	doc_init(); +#endif + +#if (CONFIG_COMMANDS & CFG_CMD_NET) && defined(CONFIG_NET_MULTI) +	WATCHDOG_RESET(); +	puts("Net:   "); +	eth_initialize(gd->bd); +#endif + +#ifdef CONFIG_LAST_STAGE_INIT +	WATCHDOG_RESET(); +	/* +	 * Some parts can be only initialized if all others (like +	 * Interrupts) are up and running (i.e. the PC-style ISA +	 * keyboard). +	 */ +	last_stage_init(); +#endif + + + +#ifdef CONFIG_POST +	post_run (NULL, POST_RAM | post_bootmode_get(0)); +	if (post_bootmode_get(0) & POST_POWERFAIL) { +		post_bootmode_clear(); +		board_poweroff(); +	} +#endif + +	show_boot_progress(0x29); +	 +	/* main_loop() can return to retry autoboot, if so just run it again. */ +	for (;;) { +		main_loop (); +	} + +	/* NOTREACHED - no way out of command loop except booting */ +} + +void hang (void) +{ +	puts ("### ERROR ### Please RESET the board ###\n"); +	for (;;); +} + + diff --git a/lib_i386/i386_linux.c b/lib_i386/i386_linux.c new file mode 100644 index 000000000..c37a0d8ee --- /dev/null +++ b/lib_i386/i386_linux.c @@ -0,0 +1,174 @@ +/* + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Marius Groeger <mgroeger@sysgo.de> + * + * Copyright (C) 2001  Erik Mouw (J.A.K.Mouw@its.tudelft.nl) + * + * 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 <command.h> +#include <cmd_boot.h> +#include <image.h> +#include <zlib.h> +#include <asm/byteorder.h> +#include <asm/zimage.h> + + +extern image_header_t header;           /* from cmd_bootm.c */ + + +image_header_t *fake_header(image_header_t *hdr, void *ptr, int size) +{ +	/* try each supported image type in order */ +	if (NULL != fake_zimage_header(hdr, ptr, size)) { +		return hdr; +	} +	 +	return NULL; +} + + +void do_bootm_linux(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[], +		ulong addr, ulong *len_ptr, int   verify) +{ +	ulong base_ptr; +	 +	ulong len = 0, checksum; +	ulong initrd_start, initrd_end; +	ulong data; +	image_header_t *hdr = &header; +	 +	/* +	 * Check if there is an initrd image +	 */ +	if (argc >= 3) { +		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 */ +		memcpy (&header, (char *)addr, sizeof(image_header_t)); +		 +		if (ntohl(hdr->ih_magic) != IH_MAGIC) { +			printf ("Bad Magic Number\n"); +			do_reset (cmdtp, flag, argc, argv); +		} +		 +		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"); +			do_reset (cmdtp, flag, argc, argv); +		} +		 +		print_image_hdr (hdr); +		 +		data = addr + sizeof(image_header_t); +		len  = ntohl(hdr->ih_size); +		 +		if (verify) { +			ulong csum = 0; +			 +			printf ("   Verifying Checksum ... "); +			csum = crc32 (0, (char *)data, len); +			if (csum != ntohl(hdr->ih_dcrc)) { +				printf ("Bad Data CRC\n"); +				do_reset (cmdtp, flag, argc, argv); +			} +			printf ("OK\n"); +		} +		 +		if ((hdr->ih_os   != IH_OS_LINUX)	|| +		    (hdr->ih_arch != IH_CPU_I386)	|| +		    (hdr->ih_type != IH_TYPE_RAMDISK)	) { +			printf ("No Linux i386 Ramdisk Image\n"); +			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])) { +		ulong tail    = ntohl(len_ptr[0]) % 4; +		int i; +		 +		/* 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 +		 */ +		data = 0; +	} +	 +#ifdef	DEBUG +	if (!data) { +		printf ("No initrd\n"); +	} +#endif +	 +	if (data) { +		initrd_start = data; +		initrd_end   = initrd_start + len; +		printf ("   Loading Ramdisk to %08lx, end %08lx ... ", +			initrd_start, initrd_end); +		memmove ((void *)initrd_start, (void *)data, len); +		printf ("OK\n"); +	} else { +		initrd_start = 0; +		initrd_end = 0; +	} +	 +	base_ptr = load_zimage(addr + sizeof(image_header_t), ntohl(hdr->ih_size),  +			       initrd_start, initrd_end-initrd_start, 0); + +	if (NULL == base_ptr) { +		printf ("## Kernel loading failed ...\n"); +		do_reset(cmdtp, flag, argc, argv); +		 +	} +		 +#ifdef DEBUG +	printf ("## Transferring control to Linux (at address %08x) ...\n", +		(u32)base_ptr); +#endif +		 +	/* we assume that the kernel is in place */ +	printf("\nStarting kernel ...\n\n"); +		 +	boot_zimage(base_ptr); +	 +} + + diff --git a/lib_i386/ic/ali512x.c b/lib_i386/ic/ali512x.c new file mode 100644 index 000000000..4537095db --- /dev/null +++ b/lib_i386/ic/ali512x.c @@ -0,0 +1,442 @@ +/* + * (C) Copyright 2002 + * Daniel Engström, Omicron Ceti AB <daniel@omicron.se>. + * + * 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 + */ + +/* + * Based on sc520cdp.c from rolo 1.6: + *---------------------------------------------------------------------- + * (C) Copyright 2000 + * Sysgo Real-Time Solutions GmbH + * Klein-Winternheim, Germany + *---------------------------------------------------------------------- + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/ic/ali512x.h> + + +/* ALI M5123 Logical device numbers: + * 0 FDC + * 1 unused? + * 2 unused? + * 3 lpt + * 4 UART1 + * 5 UART2 + * 6 RTC + * 7 mouse/kbd + * 8 CIO + */ + +/* + ************************************************************ + *  Some access primitives for the ALi chip:                * + ************************************************************ + */ + +static void ali_write(u8 index, u8 value) +{	 +	/* write an arbirary register */ +	outb(index, ALI_INDEX); +	outb(value, ALI_DATA); +} + +static int ali_read(u8 index) +{ +	outb(index, ALI_INDEX); +	return inb(ALI_DATA); +} + +#define ALI_OPEN() \ +	outb(0x51, ALI_DATA); \ +	outb(0x23, ALI_DATA)	 + + +#define ALI_CLOSE() \ +	outb(0xbb, ALI_DATA) + +/* Select a logical device */ +#define ALI_SELDEV(dev)	\ +	ali_write(0x07, dev)	 + + +void ali512x_init(void) +{ +	ALI_OPEN(); + +	ali_write(0x02, 0x01);	/* soft reset */ +	ali_write(0x03, 0x03);	/* disable access to CIOs */ +	ali_write(0x22, 0x00);	/* disable direct powerdown */ +	ali_write(0x23, 0x00);	/* disable auto powerdown */ +	ali_write(0x24, 0x00);	/* IR 8 is active hi, pin26 is PDIR */ + +	ALI_CLOSE(); +} + +void ali512x_set_fdc(int enabled, u16 io, u8 irq, u8 dma_channel) +{ +	ALI_OPEN(); +	ALI_SELDEV(0); +	 +	ali_write(0x30, enabled?1:0); +	if (enabled) { +		ali_write(0x60, io >> 8); +		ali_write(0x61, io & 0xff); +		ali_write(0x70, irq); +		ali_write(0x74, dma_channel); +		 +		/* AT mode, no drive swap */ +		ali_write(0xf0, 0x08); +		ali_write(0xf1, 0x00); +		ali_write(0xf2, 0xff); +		ali_write(0xf4, 0x00); +	} +	ALI_CLOSE(); +} + + +void ali512x_set_pp(int enabled, u16 io, u8 irq, u8 dma_channel) +{ +	ALI_OPEN(); +	ALI_SELDEV(3); +	 +	ali_write(0x30, enabled?1:0); +	if (enabled) { +		ali_write(0x60, io >> 8); +		ali_write(0x61, io & 0xff); +		ali_write(0x70, irq); +		ali_write(0x74, dma_channel); +		 +		/* mode: EPP 1.9, ECP FIFO threshold = 7, IRQ active low */ +		ali_write(0xf0, 0xbc); +		/* 12 MHz, Burst DMA in ECP */ +		ali_write(0xf1, 0x05); +	} +	ALI_CLOSE(); + +} + +void ali512x_set_uart(int enabled, int index, u16 io, u8 irq) +{ +	ALI_OPEN(); +	ALI_SELDEV(index?5:4); +	 +	ali_write(0x30, enabled?1:0); +	if (enabled) { +		ali_write(0x60, io >> 8); +		ali_write(0x61, io & 0xff); +		ali_write(0x70, irq); +		 +		ali_write(0xf0, 0x00); +		ali_write(0xf1, 0x00); +		 +		/* huh? write 0xf2 twice - a typo in rolo +		 * or some secret ali errata? Who knows?  +		 */ +		if (index) { +			ali_write(0xf2, 0x00); +		} +		ali_write(0xf2, 0x0c); +	} +	ALI_CLOSE(); + +} + +void ali512x_set_uart2_irda(int enabled) +{ +	ALI_OPEN(); +	ALI_SELDEV(5); +	 +	ali_write(0xf1, enabled?0x48:0x00); /* fullduplex IrDa */ +	ALI_CLOSE(); + +} + +void ali512x_set_rtc(int enabled, u16 io, u8 irq) +{ +	ALI_OPEN(); +	ALI_SELDEV(6); +	 +	ali_write(0x30, enabled?1:0); +	if (enabled) { +		ali_write(0x60, io >> 8); +		ali_write(0x61, io & 0xff); +		ali_write(0x70, irq); + +		ali_write(0xf0, 0x00); +	} +	ALI_CLOSE(); +} + +void ali512x_set_kbc(int enabled, u8 kbc_irq, u8 mouse_irq) +{ +	ALI_OPEN(); +	ALI_SELDEV(7); +	 +	ali_write(0x30, enabled?1:0); +	if (enabled) { +		ali_write(0x70, kbc_irq); +		ali_write(0x72, mouse_irq);		 +		 +		ali_write(0xf0, 0x00); +	} +	ALI_CLOSE(); +} + + +/* Common I/O + *  + * (This descripotsion is base on several incompete sources + *  since I have not been able to obtain any datasheet for the device + *  there may be some mis-understandings burried in here.  + *  -- Daniel daniel@omicron.se) + *  + * There are 22 CIO pins numbered + * 10-17 + * 20-25 + * 30-37 + *  + * 20-24 are dedicated CIO pins, the other 17 are muliplexed with + * other functions. + *  + *           Secondary  + * CIO Pin   Function    Decription + * ======================================================= + * CIO10     IRQIN1      Interrupt input 1? + * CIO11     IRQIN2      Interrupt input 2? + * CIO12     IRRX        IrDa Receive + * CIO13     IRTX        IrDa Transmit + * CIO14     P21         KBC P21 fucntion + * CIO15     P20         KBC P21 fucntion + * CIO16     I2C_CLK     I2C Clock + * CIO17     I2C_DAT     I2C Data + *  + * CIO20     - + * CIO21     - + * CIO22     - + * CIO23     - + * CIO24     - + * CIO25     LOCK        Keylock + *  + * CIO30     KBC_CLK     Keybaord Clock + * CIO31     CS0J        General Chip Select decoder CS0J + * CIO32     CS1J        General Chip Select decoder CS1J + * CIO33     ALT_KCLK    Alternative Keyboard Clock + * CIO34     ALT_KDAT    Alternative Keyboard Data + * CIO35     ALT_MCLK    Alternative Mouse Clock + * CIO36     ALT_MDAT    Alternative Mouse Data + * CIO37     ALT_KBC     Alternative KBC select + * + * The CIO use a double indirect address scheme.  + *  + * Reigster 3 in the SIO is used to selectg where the CIO  + * I/O registers show up under function 8. Note that these + * registers clash with the CIO function select regsters, + * below. + *  + * SIO reigster 3 (CIO Address Selection) bit definitions: + * bit 7   CIO data register enabled + * bit 1-0 CIO indirect registers select + *     	 0  index = 0xE0 data = 0xE1 + *       1  index = 0xE2 data = 0xE3 + *       2  index = 0xE4 data = 0xE5 + *       3  index = 0xEA data = 0xEB + *  + * There are three CIO I/O register accessed via CIO index and CIO data + * 0x01     CIO 10-17 data + * 0x02     CIO 20-25 data (bits 7-6 unused) + * 0x03     CIO 30-37 data + *  + *  + * The pin function is accessed through normal  + * SIO registers, each register have the same format: + *  + * Bit   Function                     Value + * 0     Input/output                 1=input  + * 1     Polarity of signal           1=inverted + * 2     Unused                       ?? + * 3     Function (normal or special) 1=special + * 7-4   Unused + *  + * SIO REG + * 0xe0     CIO 10 Config + * 0xe1     CIO 11 Config + * 0xe2     CIO 12 Config + * 0xe3     CIO 13 Config + * 0xe4     CIO 14 Config + * 0xe5     CIO 15 Config + * 0xe6     CIO 16 Config + * 0xe7     CIO 16 Config + * + * 0xe8     CIO 20 Config + * 0xe9     CIO 21 Config + * 0xea     CIO 22 Config + * 0xeb     CIO 23 Config + * 0xec     CIO 24 Config + * 0xed     CIO 25 Config + * + * 0xf5     CIO 30 Config + * 0xf6     CIO 31 Config + * 0xf7     CIO 32 Config + * 0xf8     CIO 33 Config + * 0xf9     CIO 34 Config + * 0xfa     CIO 35 Config + * 0xfb     CIO 36 Config + * 0xfc     CIO 37 Config + *  + */ + +void ali512x_set_cio(int enabled) +{ +	int i; +	 +	ALI_OPEN(); +	ali_write(0x3, 3);    /* Disable CIO data register */ +	 +	ALI_SELDEV(8); +	ali_write(0x30, enabled?1:0); +	 +	/* set all pins to input to start with */ +	for (i=0xe0;i<0xee;i++) { +		ali_write(i, 1); +	} +	for (i=0xf5;i<0xfe;i++) { +		ali_write(i, 1); +	} +			 +	ALI_CLOSE(); +} + +void ali512x_cio_function(int pin, int special, int inv, int input) +{ +	u8 data; +	u8 addr; +	 +	 +	/* valid pins are 10-17, 20-25 and 30-37 */ +	if (pin >= 10 && pin <= 17) {  +		addr = 0xe0+(pin-10); +	} else if (pin >= 20 && pin <= 25) { +		addr = 0xe8+(pin-20); +	} else if (pin >= 30 && pin <= 37) {  +		addr = 0xf5+(pin-30); +	} else { +		return; +	} +	 +	ALI_OPEN(); +	ALI_SELDEV(8); +	 +	ali_write(0x03, 0x03);    /* Disable CIO data register */ +	 +	data=0; +	if (special) { +		data |= 0x08; +	} else { +		if (inv) { +			data |= 0x02; +		} +		if (input) { +			data |= 0x01; +		} +	} +	 +	ali_write(addr, data); +	 +	ALI_CLOSE(); +} + +void ali512x_cio_out(int pin, int value)  +{ +	u8 reg; +	u8 data; +	u8 bit; +	 +	/* valid pins are 10-17, 20-25 and 30-37 */ +	if (pin >= 10 && pin <= 17) {  +		reg = 1; +		pin -= 10; +	} else if (pin >= 20 && pin <= 25) { +		reg = 2; +		pin -= 20; +	} else if (pin >= 30 && pin <= 37) {  +		reg = 3; +		pin -= 30; +	} else { +		return; +	} +	bit = 1 << pin; +	 +	ALI_OPEN(); +	ALI_SELDEV(8); +	 +	ali_write(0x03, 0x83);    /* Enable CIO data register, use data port at 0xea */ +	 +	ali_write(0xea, reg);     /* select I/O register */ +	data = ali_read(0xeb); +	if (value) { +		data |= bit; +	} else { +		data &= ~bit; +	} +	ali_write(0xeb, data); +	ali_write(0xea, 0);       /* select register 0 */ +	ali_write(0x03, 0x03);    /* Disable CIO data register */ +	ALI_CLOSE(); +} + +int ali512x_cio_in(int pin) +{ +	u8 reg; +	u8 data; +	u8 bit; +	 +	/* valid pins are 10-17, 20-25 and 30-37 */ +	if (pin >= 10 && pin <= 17) {  +		reg = 1; +		pin -= 10; +	} else if (pin >= 20 && pin <= 25) { +		reg = 2; +		pin -= 20; +	} else if (pin >= 30 && pin <= 37) {  +		reg = 3; +		pin -= 30; +	} else { +		return -1;  +	} +	bit = 1 << pin; +	 +	ALI_OPEN(); +	ALI_SELDEV(8); +	 +	ali_write(0x03, 0x83);    /* Enable CIO data register, use data port at 0xea */ +	 +	ali_write(0xea, reg);     /* select I/O register */ +	data = ali_read(0xeb); +	ali_write(0xea, 0);       /* select register 0 */ +	ali_write(0x03, 0x03);    /* Disable CIO data register */ +	ALI_CLOSE(); +	 +	return data & bit;  +} + +  diff --git a/lib_i386/ic/sc520.c b/lib_i386/ic/sc520.c new file mode 100644 index 000000000..d202625bb --- /dev/null +++ b/lib_i386/ic/sc520.c @@ -0,0 +1,348 @@ +/* + * (C) Copyright 2002 + * Daniel Engström, Omicron Ceti AB <daniel@omicron.se>. + * + * 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 + */ + +/* stuff specific for the sc520, + * but idependent of implementation */ + + +#include <common.h> +#include <config.h> +#include <pci.h> +#include <asm/io.h> +#include <asm/pci.h> +#include <asm/ic/sc520.h> + +/*  + * utility functions for boards based on the AMD sc520  + *  + * void write_mmcr_byte(u16 mmcr, u8 data) + * void write_mmcr_word(u16 mmcr, u16 data) + * void write_mmcr_long(u16 mmcr, u32 data) + *  + * u8   read_mmcr_byte(u16 mmcr) + * u16  read_mmcr_word(u16 mmcr) + * u32  read_mmcr_long(u16 mmcr) + *  + * void init_sc520(void) + * unsigned long init_sc520_dram(void) + * void pci_sc520_init(struct pci_controller *hose) + *  + * void reset_timer(void) + * ulong get_timer(ulong base) + * void set_timer(ulong t) + * void udelay(unsigned long usec) + *  + */ + +static u32 mmcr_base= 0xfffef000; + +void write_mmcr_byte(u16 mmcr, u8 data) +{ +	writeb(data, mmcr+mmcr_base); +} + +void write_mmcr_word(u16 mmcr, u16 data) +{ +	writew(data, mmcr+mmcr_base);	 +} + +void write_mmcr_long(u16 mmcr, u32 data) +{ +	writel(data, mmcr+mmcr_base); +} + +u8 read_mmcr_byte(u16 mmcr) +{ +	return readb(mmcr+mmcr_base); +} + +u16 read_mmcr_word(u16 mmcr) +{ +	return readw(mmcr+mmcr_base);	 +} + +u32 read_mmcr_long(u16 mmcr) +{ +	return readl(mmcr+mmcr_base); +} + + +void init_sc520(void) +{ +	DECLARE_GLOBAL_DATA_PTR; +	 +	/* Set the UARTxCTL register at it's slower, +	 * baud clock giving us a 1.8432 MHz reference  +	 */ +	write_mmcr_byte(SC520_UART1CTL, 7); +	write_mmcr_byte(SC520_UART2CTL, 7); +	 +	/* first set the timer pin mapping */ +	write_mmcr_byte(SC520_CLKSEL, 0x72);	/* no clock frequency selected, use 1.1892MHz */ +	 +	/* enable PCI bus arbitrer */ +	write_mmcr_byte(SC520_SYSARBCTL,0x02);  /* enable concurrent mode */ +	 +	write_mmcr_word(SC520_SYSARBMENB,0x1f); /* enable external grants */ +	write_mmcr_word(SC520_HBCTL,0x04);      /* enable posted-writes */ + + +	if (CFG_SC520_HIGH_SPEED) { +		write_mmcr_byte(SC520_CPUCTL, 0x2);	/* set it to 133 MHz and write back */ +		gd->cpu_clk = 133000000; +		printf("## CPU Speed set to 133MHz\n"); +	} else { +		write_mmcr_byte(SC520_CPUCTL, 1);	/* set CPU to 100 MHz and write back cache */ +		printf("## CPU Speed set to 100MHz\n"); +		gd->cpu_clk = 100000000; +	} +	 + +	/* wait at least one millisecond */ +        asm("movl	$0x2000,%%ecx\n" +	    "wait_loop:	pushl %%ecx\n" +	    "popl	%%ecx\n" +	    "loop wait_loop\n": : : "ecx"); + +	/* turn on the SDRAM write buffer */ +	write_mmcr_byte(SC520_DBCTL, 0x11); + +	/* turn on the cache and disable write through */ +	asm("movl	%%cr0, %%eax\n" +	    "andl	$0x9fffffff, %%eax\n" +	    "movl	%%eax, %%cr0\n"  : : : "eax"); +} + +unsigned long init_sc520_dram(void) +{ +	DECLARE_GLOBAL_DATA_PTR; +	bd_t *bd = gd->bd; +	 +	u32 dram_present=0; +	u32 dram_ctrl; + +	int val; +	 +	int cas_precharge_delay = CFG_SDRAM_PRECHARGE_DELAY;	 +	int refresh_rate        = CFG_SDRAM_REFRESH_RATE;	 +	int ras_cas_delay       = CFG_SDRAM_RAS_CAS_DELAY; +	 +	/* set SDRAM speed here */ +	 +	refresh_rate/=78;	 +	if (refresh_rate<=1) { +		val = 0;  /* 7.8us */ +	} else if (refresh_rate==2) { +		val = 1;  /* 15.6us */ +	} else if (refresh_rate==3 || refresh_rate==4) { +		val = 2;  /* 31.2us */ +	} else { +		val = 3;  /* 62.4us */ +	} +	write_mmcr_byte(SC520_DRCCTL, (read_mmcr_byte(SC520_DRCCTL) & 0xcf) | (val<<4)); +	 +	val = read_mmcr_byte(SC520_DRCTMCTL); +	val &= 0xf0; +	 +	if (cas_precharge_delay==3) {		 +		val |= 0x04;   /* 3T */ +	} else if (cas_precharge_delay==4) {		 +		val |= 0x08;   /* 4T */ +	} else if (cas_precharge_delay>4) {		 +		val |= 0x0c; +	}  +	 +	if (ras_cas_delay > 3) { +		val |= 2;  +	} else { +		val |= 1;  +	} +	write_mmcr_byte(SC520_DRCTMCTL, val); + + +	/* We read-back the configuration of the dram +	 * controller that the assembly code wrote */ +	dram_ctrl = read_mmcr_long(SC520_DRCBENDADR); +	 + +	bd->bi_dram[0].start = 0; +	if (dram_ctrl & 0x80) { +		/* bank 0 enabled */ +		dram_present = bd->bi_dram[1].start = (dram_ctrl & 0x7f) << 22; +		bd->bi_dram[0].size = bd->bi_dram[1].start;  + +	} else { +		bd->bi_dram[0].size = 0; +		bd->bi_dram[1].start = bd->bi_dram[0].start; +	} +	 +	if (dram_ctrl & 0x8000) { +		/* bank 1 enabled */ +		dram_present = bd->bi_dram[2].start = (dram_ctrl & 0x7f00) << 14; +		bd->bi_dram[1].size = bd->bi_dram[2].start -  bd->bi_dram[1].start;  +	} else { +		bd->bi_dram[1].size = 0; +		bd->bi_dram[2].start = bd->bi_dram[1].start; +	} +	 +	if (dram_ctrl & 0x800000) { +		/* bank 2 enabled */ +		dram_present = bd->bi_dram[3].start = (dram_ctrl & 0x7f0000) << 6; +		bd->bi_dram[2].size = bd->bi_dram[3].start -  bd->bi_dram[2].start;  +	} else { +		bd->bi_dram[2].size = 0; +		bd->bi_dram[3].start = bd->bi_dram[2].start; +	}  +	 +	if (dram_ctrl & 0x80000000) { +		/* bank 3 enabled */ +		dram_present  = (dram_ctrl & 0x7f000000) >> 2; +		bd->bi_dram[3].size = dram_present -  bd->bi_dram[3].start; +	} else { +		bd->bi_dram[3].size = 0; +	} + +	 +#if 0	 +	printf("Configured %d bytes of dram\n", dram_present); +#endif	 +	gd->ram_size = dram_present; +	 +	return dram_present; +} + + +#ifdef CONFIG_PCI + + + +void pci_sc520_init(struct pci_controller *hose) +{ +	hose->first_busno = 0; +	hose->last_busno = 0xff; + +	/* System memory space */ +	pci_set_region(hose->regions + 0,  +		       SC520_PCI_MEMORY_BUS, +		       SC520_PCI_MEMORY_PHYS, +		       SC520_PCI_MEMORY_SIZE, +		       PCI_REGION_MEM | PCI_REGION_MEMORY); + +	/* PCI memory space */ +	pci_set_region(hose->regions + 1,  +		       SC520_PCI_MEM_BUS, +		       SC520_PCI_MEM_PHYS, +		       SC520_PCI_MEM_SIZE, +		       PCI_REGION_MEM); + +	/* ISA/PCI memory space */ +	pci_set_region(hose->regions + 2,  +		       SC520_ISA_MEM_BUS, +		       SC520_ISA_MEM_PHYS, +		       SC520_ISA_MEM_SIZE, +		       PCI_REGION_MEM); + +	/* PCI I/O space */ +	pci_set_region(hose->regions + 3,  +		       SC520_PCI_IO_BUS, +		       SC520_PCI_IO_PHYS, +		       SC520_PCI_IO_SIZE, +		       PCI_REGION_IO); + +	/* ISA/PCI I/O space */ +	pci_set_region(hose->regions + 4,  +		       SC520_ISA_IO_BUS, +		       SC520_ISA_IO_PHYS, +		       SC520_ISA_IO_SIZE, +		       PCI_REGION_IO); + +	hose->region_count = 5; + +	pci_setup_type1(hose, +			SC520_REG_ADDR, +			SC520_REG_DATA); + +	pci_register_hose(hose); + +	hose->last_busno = pci_hose_scan(hose); +	 +	/* enable target memory acceses on host brige */ +	pci_write_config_word(0, PCI_COMMAND,  +			      PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); + +} + + +#endif + +#ifdef CFG_TIMER_SC520 + + +void reset_timer(void) +{ +	write_mmcr_word(SC520_GPTMR0CNT, 0); +	write_mmcr_word(SC520_GPTMR0CTL, 0x6001); +	 +} + +ulong get_timer(ulong base) +{ +	/* fixme: 30 or 33 */ +	return 	read_mmcr_word(SC520_GPTMR0CNT) / 33; +} + +void set_timer(ulong t) +{ +	/* FixMe: use two cascade coupled timers */ +	write_mmcr_word(SC520_GPTMR0CTL, 0x4001); +	write_mmcr_word(SC520_GPTMR0CNT, t*33); +	write_mmcr_word(SC520_GPTMR0CTL, 0x6001); +} + + +void udelay(unsigned long usec) +{ +	int m=0; +	long u; +	 +	read_mmcr_word(SC520_SWTMRMILLI); +	read_mmcr_word(SC520_SWTMRMICRO); +	      +#if 0 +	/* do not enable this line, udelay is used in the serial driver -> recursion */ +	printf("udelay: %ld m.u %d.%d  tm.tu %d.%d\n", usec, m, u, tm, tu); +#endif	 +	while (1) { +		 +		m += read_mmcr_word(SC520_SWTMRMILLI); +		u = read_mmcr_word(SC520_SWTMRMICRO) + (m * 1000); +		 +		if (usec <= u) { +			break; +		} +	} +} + +#endif + + diff --git a/lib_i386/ic/sc520_asm.S b/lib_i386/ic/sc520_asm.S new file mode 100644 index 000000000..72110c4a0 --- /dev/null +++ b/lib_i386/ic/sc520_asm.S @@ -0,0 +1,530 @@ +/* + * (C) Copyright 2002 + * Daniel Engström, Omicron Ceti AB <daniel@omicron.se>. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* This file is largely based on code obtned from AMD. AMD's original + * copyright is included below  + */ + +/* + *  ============================================================================= + *                                                                               + *   Copyright 1999 Advanced Micro Devices, Inc.                                 + *                                                                               + *  This software is the property of Advanced Micro Devices, Inc  (AMD)  which  + *  specifically grants the user the right to modify, use and distribute this  + *  software provided this COPYRIGHT NOTICE is not removed or altered.  All  + *  other rights are reserved by AMD.                                                        + *                                                                              + *  THE MATERIALS ARE PROVIDED "AS IS" WITHOUT ANY EXPRESS OR IMPLIED WARRANTY  + *  OF ANY KIND INCLUDING WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT OF  + *  THIRD-PARTY INTELLECTUAL PROPERTY, OR FITNESS FOR ANY PARTICULAR PURPOSE. + *  IN NO EVENT SHALL AMD OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER + *  (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, BUSINESS + *  INTERRUPTION, LOSS OF INFORMAITON) ARISING OUT OF THE USE OF OR INABILITY + *  TO USE THE MATERIALS, EVEN IF AMD HAS BEEN ADVISED OF THE POSSIBILITY OF + *  SUCH DAMAGES.  BECAUSE SOME JURSIDICTIONS PROHIBIT THE EXCLUSION OR + *  LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES, THE ABOVE + *  LIMITATION MAY NOT APPLY TO YOU. + *  + *  AMD does not assume any responsibility for any errors that may appear in + *  the Materials nor any responsibility to support or update the Materials. + *  AMD retains the right to make changes to its test specifications at any + *  time, without notice. + *  + *  So that all may benefit from your experience, please report  any  problems  + *  or suggestions about this software back to AMD.  Please include your name,  + *  company,  telephone number,  AMD product requiring support and question or  + *  problem encountered.                                                        + *                                                                              + *  Advanced Micro Devices, Inc.         Worldwide support and contact            + *  Embedded Processor Division            information available at:                + *  Systems Engineering                       epd.support@amd.com + *  5204 E. Ben White Blvd.                          -or- + *  Austin, TX 78741                http://www.amd.com/html/support/techsup.html + *  ============================================================================ + */ + + +/******************************************************************************* + *	 AUTHOR      : Buddy Fey - Original.  + ******************************************************************************* + */ + + +/******************************************************************************* + *       FUNCTIONAL DESCRIPTION: + * This routine is called to autodetect the geometry of the DRAM. + * + * This routine is called to determine the number of column bits for the DRAM + * devices in this external bank. This routine assumes that the external bank + * has been configured for an 11-bit column and for 4 internal banks. This gives + * us the maximum address reach in memory. By writing a test value to the max + * address and locating where it aliases to, we can determine the number of valid + * column bits. + * + * This routine is called to determine the number of internal banks each DRAM + * device has. The external bank (under test) is configured for maximum reach + * with 11-bit columns and 4 internal banks. This routine will write to a max + * address (BA1 and BA0 = 1) and then read from an address with BA1=0 to see if + * that column is a "don't care". If BA1 does not affect write/read of data, + * then this device has only 2 internal banks. + * + * This routine is called to determine the ending address for this external + * bank of SDRAM. We write to a max address with a data value and then disable + * row address bits looking for "don't care" locations. Each "don't care" bit + * represents a dividing of the maximum density (128M) by 2. By dividing the + * maximum of 32 4M chunks in an external bank down by all the "don't care" bits + * determined during sizing, we set the proper density. + * + * WARNINGS. + * bp must be preserved because it is used for return linkage. + * + * EXIT + * nothing returned - but the memory subsystem is enabled + ******************************************************************************* + */ + +.section .text +.equ            DRCCTL,     0x0fffef010   /* DRAM control register */ +.equ            DRCTMCTL,   0x0fffef012   /* DRAM timing control register */ +.equ            DRCCFG,     0x0fffef014   /* DRAM bank configuration register */ +.equ            DRCBENDADR, 0x0fffef018   /* DRAM bank ending address register */ +.equ            ECCCTL,     0x0fffef020   /* DRAM ECC control register */ +.equ            DBCTL,      0x0fffef040   /* DRAM buffer control register */ + +.equ            CACHELINESZ, 0x00000010   /* size of our cache line (read buffer) */ +.equ            COL11_ADR,  0x0e001e00    /* 11 col addrs */ +.equ            COL10_ADR,  0x0e000e00    /* 10 col addrs */ +.equ            COL09_ADR,  0x0e000600    /*  9 col addrs */ +.equ            COL08_ADR,  0x0e000200    /*  8 col addrs */ +.equ            ROW14_ADR,  0x0f000000    /* 14 row addrs */ +.equ            ROW13_ADR,  0x07000000    /* 13 row addrs */ +.equ            ROW12_ADR,  0x03000000    /* 12 row addrs */ +.equ            ROW11_ADR,  0x01000000    /* 11 row addrs/also bank switch */ +.equ            ROW10_ADR,  0x00000000    /* 10 row addrs/also bank switch */ +.equ            COL11_DATA, 0x0b0b0b0b    /* 11 col addrs */ +.equ            COL10_DATA, 0x0a0a0a0a    /* 10 col data */ +.equ            COL09_DATA, 0x09090909    /*  9 col data */ +.equ            COL08_DATA, 0x08080808    /*  8 col data */ +.equ            ROW14_DATA, 0x3f3f3f3f    /* 14 row data (MASK) */ +.equ            ROW13_DATA, 0x1f1f1f1f    /* 13 row data (MASK) */ +.equ            ROW12_DATA, 0x0f0f0f0f    /* 12 row data (MASK) */ +.equ            ROW11_DATA, 0x07070707    /* 11 row data/also bank switch (MASK) */ +.equ            ROW10_DATA, 0xaaaaaaaa    /* 10 row data/also bank switch (MASK) */ + + + /* +  * initialize dram controller registers +  */ +.globl mem_init +mem_init:  +        xorw    %ax,%ax +        movl    $DBCTL, %edi              +fs	movb     %al, (%edi)             /* disable write buffer */ + +        movl    $ECCCTL, %edi             +fs	movb     %al, (%edi)             /* disable ECC */ + +        movl    $DRCTMCTL, %edi            +        movb    $0x1E,%al                /* Set SDRAM timing for slowest */ +fs	movb     %al, (%edi) + + /* +  * setup loop to do 4 external banks starting with bank 3 +  */ +        movl    $0xff000000,%eax         /* enable last bank and setup */ +        movl    $DRCBENDADR, %edi        /* ending address register */ +fs	movl     %eax, (%edi) + +        movl    $DRCCFG, %edi            /* setup */ +        movw    $0xbbbb,%ax              /* dram config register for  */ +fs	movw    %ax, (%edi) + + /* +  * issue a NOP to all DRAMs +  */ +        movl    $DRCCTL, %edi            /* setup DRAM control register with */ +        movb    $0x1,%al                 /* Disable refresh,disable write buffer */  +fs	movb     %al, (%edi) +        movl    $CACHELINESZ, %esi       /* just a dummy address to write for */  +fs	movw     %ax, (%esi) + /* +  * delay for 100 usec? 200? +  * ******this is a cludge for now ************* +  */ +        movw    $100,%cx +sizdelay:  +        loop    sizdelay                 /* we need 100 usec here */ + /***********************************************/ + + /* +  * issue all banks precharge +  */ +        movb    $0x2,%al                 /* All banks precharge */ +fs	movb     %al, (%edi) +fs	movw     %ax, (%esi) + + /* +  * issue 2 auto refreshes to all banks  +  */ +        movb    $0x4,%al                 /* Auto refresh cmd */ +fs	movb     %al, (%edi) +        movw    $2,%cx +refresh1:  +fs	movw     %ax, (%esi) +        loop    refresh1 + + /* +  * issue LOAD MODE REGISTER command +  */ +        movb    $0x3,%al                 /* Load mode register cmd */ +fs	movb     %al, (%edi) +fs	movw     %ax, (%esi) + + /* +  * issue 8 more auto refreshes to all banks  +  */  +        movb    $0x4,%al                 /* Auto refresh cmd */ +fs	movb     %al, (%edi) +        movw    $8,%cx +refresh2:  +fs	movw     %ax, (%esi) +        loop    refresh2 + + /* +  * set control register to NORMAL mode  +  */ +        movb    $0x0,%al                 /* Normal mode value */ +fs	movb     %al, (%edi) + + /* +  * size dram starting with external bank 3 moving to external bank 0 +  */ +        movl    $0x3,%ecx                /* start with external bank 3 */ + +nextbank:  + + /* +  * write col 11 wrap adr +  */ +        movl    $COL11_ADR, %esi         /* set address to max col (11) wrap addr */ +        movl    $COL11_DATA, %eax        /* pattern for max supported columns(11) */ +fs      movl    %eax, (%esi)             /* write max col pattern at max col adr */ +fs      movl    (%esi), %ebx             /* optional read */ +        cmpl    %ebx,%eax                /* to verify write */ +        jnz     bad_ram                  /* this ram is bad */ + /* +  * write col 10 wrap adr +  */ + +        movl    $COL10_ADR, %esi         /* set address to 10 col wrap address */ +        movl    $COL10_DATA, %eax        /* pattern for 10 col wrap */ +fs      movl    %eax, (%esi)             /* write 10 col pattern @ 10 col wrap adr */ +fs      movl    (%esi), %ebx             /* optional read */ +        cmpl    %ebx,%eax                /* to verify write */ +        jnz     bad_ram                  /* this ram is bad */ + /* +  * write col 9 wrap adr +  */ +        movl    $COL09_ADR, %esi         /* set address to 9 col wrap address */ +        movl    $COL09_DATA, %eax        /* pattern for 9 col wrap */ +fs      movl    %eax, (%esi)             /* write 9 col pattern @ 9 col wrap adr */ +fs      movl    (%esi), %ebx             /* optional read */ +        cmpl    %ebx,%eax                /* to verify write */ +        jnz     bad_ram                  /* this ram is bad */ + /* +  * write col 8 wrap adr +  */ +        movl    $COL08_ADR, %esi         /* set address to min(8) col wrap address */ +        movl    $COL08_DATA, %eax        /* pattern for min (8) col wrap */ +fs      movl    %eax, (%esi)             /* write min col pattern @ min col adr */ +fs      movl    (%esi), %ebx             /* optional read */ +        cmpl    %ebx,%eax                /* to verify write */ +        jnz     bad_ram                  /* this ram is bad */ + /* +  * write row 14 wrap adr +  */ +        movl    $ROW14_ADR, %esi         /* set address to max row (14) wrap addr */ +        movl    $ROW14_DATA, %eax        /* pattern for max supported rows(14) */ +fs      movl    %eax, (%esi)             /* write max row pattern at max row adr */ +fs      movl    (%esi), %ebx             /* optional read */ +        cmpl    %ebx,%eax                /* to verify write */ +        jnz     bad_ram                  /* this ram is bad */ + /* +  * write row 13 wrap adr +  */ +        movl    $ROW13_ADR, %esi         /* set address to 13 row wrap address */ +        movl    $ROW13_DATA, %eax        /* pattern for 13 row wrap */ +fs      movl    %eax, (%esi)             /* write 13 row pattern @ 13 row wrap adr */ +fs      movl    (%esi), %ebx             /* optional read */ +        cmpl    %ebx,%eax                /* to verify write */ +        jnz     bad_ram                  /* this ram is bad */ + /* +  * write row 12 wrap adr +  */ +        movl    $ROW12_ADR, %esi         /* set address to 12 row wrap address */ +        movl    $ROW12_DATA, %eax        /* pattern for 12 row wrap */ +fs      movl    %eax, (%esi)             /* write 12 row pattern @ 12 row wrap adr */ +fs      movl    (%esi), %ebx             /* optional read */ +        cmpl    %ebx,%eax                /* to verify write */ +        jnz     bad_ram                  /* this ram is bad */ + /* +  * write row 11 wrap adr +  */ +        movl    $ROW11_ADR, %edi         /* set address to 11 row wrap address */ +        movl    $ROW11_DATA, %eax        /* pattern for 11 row wrap */ +fs      movl    %eax, (%edi)             /* write 11 row pattern @ 11 row wrap adr */ +fs      movl    (%edi), %ebx             /* optional read */ +        cmpl    %ebx,%eax                /* to verify write */ +        jnz     bad_ram                  /* this ram is bad */ + /* +  * write row 10 wrap adr --- this write is really to determine number of banks +  */ +        movl    $ROW10_ADR, %edi         /* set address to 10 row wrap address */ +        movl    $ROW10_DATA, %eax        /* pattern for 10 row wrap (AA) */ +fs      movl    %eax, (%edi)             /* write 10 row pattern @ 10 row wrap adr */ +fs      movl    (%edi), %ebx             /* optional read */ +        cmpl    %ebx,%eax                /* to verify write */ +        jnz     bad_ram                  /* this ram is bad */ + /* +  * read data @ row 12 wrap adr to determine  * banks,  +  * and read data @ row 14 wrap adr to determine  * rows. +  * if data @ row 12 wrap adr is not AA, 11 or 12 we have bad RAM. +  * if data @ row 12 wrap == AA, we only have 2 banks, NOT 4  +  * if data @ row 12 wrap == 11 or 12, we have 4 banks, +  */ +        xorw    %di,%di                  /* value for 2 banks in DI */ +fs      movl    (%esi), %ebx             /* read from 12 row wrap to check banks  +                                          * (esi is setup from the write to row 12 wrap) */ +        cmpl    %ebx,%eax                /* check for AA pattern  (eax holds the aa pattern) */ +        jz      only2                    /* if pattern == AA, we only have 2 banks */ + +	/* 4 banks */ +	 +        movw    $8,%di                   /* value for 4 banks in DI (BNK_CNT bit) */ +        cmpl    $ROW11_DATA, %ebx        /* only other legitimate values are 11 */ +        jz      only2 +        cmpl    $ROW12_DATA, %ebx        /* and 12 */ +        jnz     bad_ram                  /* its bad if not 11 or 12! */ +	 +	/* fall through */ +only2:  + /* +  * validate row mask +  */ +        movl    $ROW14_ADR, %esi         /* set address back to max row wrap addr */ +fs      movl    (%esi), %eax             /* read actual number of rows @ row14 adr */ + +        cmpl    $ROW11_DATA, %eax        /* row must be greater than 11 pattern */ +        jb      bad_ram + +        cmpl    $ROW14_DATA, %eax        /* and row must be less than 14 pattern */ +        ja      bad_ram + +        cmpb    %ah,%al                  /* verify all 4 bytes of dword same */ +        jnz     bad_ram +        movl    %eax,%ebx +        shrl    $16,%ebx +        cmpw    %bx,%ax +        jnz     bad_ram + /* +  * read col 11 wrap adr for real column data value +  */ +        movl    $COL11_ADR, %esi         /* set address to max col (11) wrap addr */ +fs      movl    (%esi), %eax             /* read real col number at max col adr */ + /* +  * validate column data +  */ +        cmpl    $COL08_DATA, %eax        /* col must be greater than 8 pattern */ +        jb      bad_ram + +        cmpl    $COL11_DATA, %eax        /* and row must be less than 11 pattern */ +        ja      bad_ram + +        subl    $COL08_DATA, %eax        /* normalize column data to zero */ +        jc      bad_ram +        cmpb    %ah,%al                  /* verify all 4 bytes of dword equal */ +        jnz     bad_ram +        movl    %eax,%edx +        shrl    $16,%edx +        cmpw    %dx,%ax +        jnz     bad_ram + /* +  * merge bank and col data together +  */ +        addw    %di,%dx                  /* merge of bank and col info in dl */ + /* +  * fix ending addr mask based upon col info +  */ +        movb    $3,%al +        subb    %dh,%al                  /* dh contains the overflow from the bank/col merge  */ +        movb    %bl,%dh                  /* bl contains the row mask (aa, 07, 0f, 1f or 3f) */ +        xchgw   %cx,%ax                  /* cx = ax = 3 or 2 depending on 2 or 4 bank device */ +        shrb    %cl,%dh	                 /*  */ +        incb    %dh                      /* ending addr is 1 greater than real end */ +        xchgw   %cx,%ax                  /* cx is bank number again */ + /* +  * issue all banks precharge +  */ +bad_reint:  +        movl    $DRCCTL, %esi            /* setup DRAM control register with */ +        movb    $0x2,%al                 /* All banks precharge */ +fs	movb     %al, (%esi) +        movl    $CACHELINESZ, %esi       /* address to init read buffer */ +fs	movw     %ax, (%esi) + + /* +  * update ENDING ADDRESS REGISTER +  */ +        movl    $DRCBENDADR, %edi        /* DRAM ending address register */ +        movl    %ecx,%ebx +	addl	%ebx, %edi +fs	movb    %dh, (%edi) + /* +  * update CONFIG REGISTER +  */ +        xorb    %dh,%dh +        movw    $0x00f,%bx +        movw    %cx,%ax +        shlw    $2,%ax +        xchgw   %cx,%ax +        shlw    %cl,%dx +        shlw    %cl,%bx +        notw    %bx +        xchgw   %cx,%ax +        movl    $DRCCFG, %edi +fs	mov     (%edi), %ax +        andw    %bx,%ax +        orw     %dx,%ax +fs      movw    %ax, (%edi) +        jcxz    cleanup + +        decw    %cx +        movl    %ecx,%ebx +        movl    $DRCBENDADR, %edi        /* DRAM ending address register */ +        movb    $0xff,%al +	addl	%ebx, %edi +fs	movb    %al, (%edi) + /* +  * set control register to NORMAL mode  +  */ +        movl    $DRCCTL, %esi            /* setup DRAM control register with */ +        movb    $0x0,%al                 /* Normal mode value */ +fs	movb    %al, (%esi) +        movl    $CACHELINESZ, %esi       /* address to init read buffer */ +fs	movw    %ax, (%esi) +        jmp     nextbank + +cleanup:  +        movl    $DRCBENDADR, %edi        /* DRAM ending address register  */ +        movw    $4,%cx +        xorw    %ax,%ax +cleanuplp:  +fs	movb   (%edi), %al +        orb     %al,%al +        jz      emptybank + +        addb    %ah,%al +        jns     nottoomuch + +        movb    $0x7f,%al +nottoomuch:  +        movb    %al,%ah +        orb     $0x80,%al +fs	movb    %al, (%edi) +emptybank:  +        incl    %edi +        loop    cleanuplp + +#if defined(CFG_SDRAM_CAS_LATENCY_2T) || defined(CFG_SDRAM_CAS_LATENCY_3T) +	/* set the CAS latency now since it is hard to do +	 * when we run from the RAM */ +	movl    $DRCTMCTL, %edi          /* DRAM timing register */ +	movb    (%edi), %al	 +#ifdef CFG_SDRAM_CAS_LATENCY_2T +	andb    $0xef, %al +#endif +#ifdef CFG_SDRAM_CAS_LATENCY_3T +	orb     $0x10, %al +#endif	  +	movb    %al, (%edi) +#endif +        movl    $DRCCTL, %edi            /* DRAM Control register */ +        movb    $0x3,%al                 /* Load mode register cmd */ +fs	movb     %al, (%edi) +fs	movw     %ax, (%esi) + + +        movl    $DRCCTL, %edi            /* DRAM Control register */ +        movb    $0x18,%al                /*  Enable refresh and NORMAL mode */ +fs	movb    %al, (%edi) + +        jmp     dram_done + +bad_ram:  +        xorl    %edx,%edx +        xorl    %edi,%edi +        jmp     bad_reint + +dram_done:  +	 +	/* readback DRCBENDADR and return the number +	 * of available ram bytes in %eax */  + +        movl    $DRCBENDADR, %edi        /* DRAM ending address register  */ +	 +	movl	(%edi), %eax +	movl	%eax, %ecx +	andl	$0x80000000, %ecx +	jz	bank2 +	andl	$0x7f000000, %eax +	shrl	$2, %eax  +	movl	%eax, %ebx + +bank2: 	movl	(%edi), %eax +	movl	%eax, %ecx +	andl	$0x00800000, %ecx +	jz	bank1 +	andl	$0x007f0000, %eax +	shll	$6, %eax  +	movl	%eax, %ebx + +bank1: 	movl	(%edi), %eax +	movl	%eax, %ecx +	andl	$0x00008000, %ecx +	jz	bank0 +	andl	$0x00007f00, %eax +	shll	$14, %eax  +	movl	%eax, %ebx + +bank0: 	movl	(%edi), %eax +	movl	%eax, %ecx +	andl	$0x00000080, %ecx +	jz	done +	andl	$0x0000007f, %eax +	shll	$22, %eax  +	movl	%eax, %ebx + +done:	movl	%ebx, %eax + +	jmp	*%ebp diff --git a/lib_i386/pci_type1.c b/lib_i386/pci_type1.c new file mode 100644 index 000000000..e5577e820 --- /dev/null +++ b/lib_i386/pci_type1.c @@ -0,0 +1,57 @@ +/* + * Support for type PCI configuration cycles. + * based on pci_indirect.c + * + * Copyright (C) 2002 Daniel Engström, Omicron Ceti AB, daniel@omicron.se. + * + * 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. + */ + +#include <common.h> + +#ifdef CONFIG_PCI + +#include <asm/processor.h> +#include <asm/io.h> +#include <pci.h> + +#define cfg_read(val, addr, type, op)	*val = op((type)(addr)) +#define cfg_write(val, addr, type, op)	op((val), (type *)(addr)) + +#define TYPE1_PCI_OP(rw, size, type, op, mask)			 \ +static int								 \ +type1_##rw##_config_##size(struct pci_controller *hose, 		 \ +			      pci_dev_t dev, int offset, type val)	 \ +{									 \ +	outl(dev | (offset & 0xfc) | 0x80000000, hose->cfg_addr); 	 \ +	cfg_##rw(val, hose->cfg_data + (offset & mask), type, op);	 \ +	return 0;    					 		 \ +} + + +TYPE1_PCI_OP(read, byte, u8 *, inb, 3) +TYPE1_PCI_OP(read, word, u16 *, inw, 2) +TYPE1_PCI_OP(read, dword, u32 *, inl, 0) + +TYPE1_PCI_OP(write, byte, u8, outb, 3) +TYPE1_PCI_OP(write, word, u16, outw, 2) +TYPE1_PCI_OP(write, dword, u32, outl, 0) + +void pci_setup_type1(struct pci_controller* hose, u32 cfg_addr, u32 cfg_data) +{ +	pci_set_ops(hose, +		    type1_read_config_byte, +		    type1_read_config_word, +		    type1_read_config_dword, +		    type1_write_config_byte, +		    type1_write_config_word, +		    type1_write_config_dword); + +	hose->cfg_addr = (unsigned int *) cfg_addr; +	hose->cfg_data = (unsigned char *) cfg_data; +} + +#endif diff --git a/lib_i386/realmode.c b/lib_i386/realmode.c new file mode 100644 index 000000000..372147cf2 --- /dev/null +++ b/lib_i386/realmode.c @@ -0,0 +1,69 @@ +/* + * (C) Copyright 2002 + * Daniel Engström, Omicron Ceti AB, daniel@omicron.se + *  + * 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/io.h> +#include <asm/ptrace.h> + + +#define REALMODE_BASE    ((char*)0x7c0) +#define REALMODE_MAILBOX ((char*)0xe00) + + +extern char realmode_enter; + + +int enter_realmode(u16 seg, u16 off, struct pt_regs *in, struct pt_regs *out) +{ +	 +	/* setup out thin bios emulation */ +	if (bios_setup()) { +		return -1; +	} +		 +	/* copy the realmode switch code */ +	if (i386boot_realmode_size > (REALMODE_MAILBOX-REALMODE_BASE)) { +		printf("realmode switch too large (%ld bytes, max is %d)\n",  +		       i386boot_realmode_size, (REALMODE_MAILBOX-REALMODE_BASE)); +		return -1; +	} +	 +	memcpy(REALMODE_BASE, i386boot_realmode, i386boot_realmode_size); +		 +	 +	in->eip = off; +	in->xcs = seg; +	if (3>in->esp & 0xffff) { +		printf("Warning: entering realmode with sp < 4 will fail\n"); +	} +	 +	memcpy(REALMODE_MAILBOX, in, sizeof(struct pt_regs)); +	 +	__asm__ volatile (  +		 "lcall $0x20,%0\n"  : :  "i" (&realmode_enter) ); + +	memcpy(out, REALMODE_MAILBOX, sizeof(struct pt_regs)); + +	return out->eax; +} + diff --git a/lib_i386/realmode_switch.S b/lib_i386/realmode_switch.S new file mode 100644 index 000000000..9f212c2e8 --- /dev/null +++ b/lib_i386/realmode_switch.S @@ -0,0 +1,223 @@ +/* + * (C) Copyright 2002 + * Daniel Engström, Omicron Ceti AB, daniel@omicron.se + *  + * 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 + */ + + +/* 32bit -> 16bit -> 32bit mode switch code */ + +/* + * Stack frame at 0xe00 + *      e00 ebx; + *	e04 ecx; + *	e08 edx; + *	e0c esi; + *	e10 edi; + *	e14 ebp;  + *	e18 eax; + *	e1c ds;   + *	e20 es; + *	e24 fs;   + *	e28 gs; + *	e2c orig_eax; + *	e30 eip; + *	e34 cs; + *	e38 eflags; + *	e3c esp; + *	e40 ss; + */ + +#define a32		.byte 0x67;		/* address size prefix 32 */ +#define o32		.byte 0x66;		/* operand size prefix 32 */  + +.section .realmode, "ax" +.code16 + +						/* 16bit protected mode code here */ +.globl realmode_enter +realmode_enter: +o32	pusha +o32	pushf +	cli +        sidt   	saved_idt +        sgdt    saved_gdt +        movl    %esp, %eax +        movl    %eax, saved_protected_mode_esp +	 +	movl	$0x10, %eax +	movl    %eax, %esp +	movw	$0x28, %ax +	movw	%ax, %ds +	movw	%ax, %es +	movw	%ax, %fs +	movw	%ax, %gs + +	lidt	realmode_idt_ptr +	movl	%cr0, %eax                	/* Go back into real mode by */ +	andl	$0x7ffffffe, %eax         	/* clearing PE to 0 */ +	movl	%eax, %cr0 +	ljmp	$0x0,$do_realmode             	/* switch to real mode */ +						 +do_realmode:					/* realmode code from here */  +	movw	%cs,%ax +	movw	%ax,%ds +	movw	%ax,%es +	movw	%ax,%fs +	movw	%ax,%gs +	 +						/* create a temporary stack */ +	                                +	movw	$0xc0, %ax              +	movw	%ax, %ss                 +	movw	$0x200, %ax            +	movw	%ax, %sp  +	 +	popl	%ebx +	popl	%ecx +	popl	%edx +	popl	%esi +	popl	%edi +	popl	%ebp +	popl	%eax +	movl	%eax, temp_eax +	popl	%eax +	movw	%ax, %ds +	popl	%eax +	movw	%ax, %es +	popl	%eax +	movw	%ax, %fs +	popl	%eax +	movw	%ax, %gs +	popl	%eax				/* orig_eax */ +	popl	%eax +cs	movw	%ax, temp_ip +	popl	%eax +cs	movw	%ax, temp_cs +o32	popf +	popl	%eax +	popw	%ss +	movl	%eax, %esp +cs	movl	temp_eax, %eax +	wbinvd                                  /* self-modifying code, +						 * better flush the cache */ +	 +	.byte	0x9a				/* lcall */ +temp_ip: +	.word	0	     			/* new ip */ +temp_cs:	 +	.word   0				/* new cs */ +realmode_ret: +						/* save eax, esp and ss */ +cs	movl	%eax, saved_eax +	movl	%esp, %eax +cs	movl	%eax, saved_esp +	movw    %ss, %ax +cs	movw	%ax, saved_ss +	 +	/* restore the stack, note that we set sp to 0x244; +	 * pt_regs is 0x44 bytes long and we push the structure +	 * backwards on to the stack, bottom first */ +	  +	movw	$0xc0, %ax              +	movw	%ax, %ss                 +	movw	$0x244, %ax            +	movw	%ax, %sp  +	 +	xorl	%eax,%eax +cs	movw	saved_ss, %ax +	pushl	%eax +cs	movl	saved_esp, %eax +	pushl	%eax +o32	pushf +	xorl	%eax,%eax +cs	movw	temp_cs, %ax +	pushl	%eax +cs	movw	temp_ip, %ax +	pushl	%eax +	pushl	$0 +	movw	%gs, %ax +	pushl	%eax +	movw	%fs, %ax +	pushl	%eax +	movw	%es, %ax +	pushl	%eax +	movw	%ds, %ax +	pushl	%eax +	movl	saved_eax, %eax +	pushl	%eax +	pushl	%ebp +	pushl	%edi +	pushl	%esi +	pushl	%edx +	pushl	%ecx +	pushl	%ebx + +o32 cs	lidt	saved_idt +o32 cs	lgdt    saved_gdt			/* Set GDTR */ + +        movl    %cr0, %eax              	/* Go back into protected mode */ +        orl     $1,%eax                 	/* reset PE to 1 */ +        movl    %eax, %cr0                +        jmp     next_line               	/* flush prefetch queue */ +next_line:     +        movw	$return_ptr, %ax           +        movw    %ax,%bp +o32 cs	ljmp	*(%bp) + +.code32 +protected_mode: +        movl    $0x18,%eax         		/* reload GDT[3] */ +        movw    %ax,%fs                 	/* reset FS */ +	movw	%ax,%ds                		/* reset DS */ +        movw    %ax,%gs                 	/* reset GS */ +        movw    %ax,%es                 	/* reset ES */ +        movw    %ax,%ss                 	/* reset SS */ +        movl    saved_protected_mode_esp, %eax +	movl	%eax, %esp +	popf +	popa +        ret + +temp_eax: +	.long	0 + +saved_ss: +	.word   0 +saved_esp: +	.long	0 +saved_eax: +	.long	0 +	 +realmode_idt_ptr: +	.word	0x400			        +	.word	0x0, 0x0		 +	 +saved_gdt:   +  	.word 	0, 0, 0, 0 +saved_idt: +  	.word 	0, 0, 0, 0 + +saved_protected_mode_esp: +	.long 	0 +	 +return_ptr: +	.long	protected_mode +	.word	0x10 diff --git a/lib_i386/zimage.c b/lib_i386/zimage.c new file mode 100644 index 000000000..190d46ef7 --- /dev/null +++ b/lib_i386/zimage.c @@ -0,0 +1,276 @@ +/* + * (C) Copyright 2002 + * Daniel Engström, Omicron Ceti AB, daniel@omicron.se + *  + * 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 + */ + +/*  + * Linux i386 zImage and bzImage loading + *  + * based on the procdure described in  + * linux/Documentation/i386/boot.txt + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/ptrace.h> +#include <asm/zimage.h> +#include <asm/realmode.h> +#include <asm/byteorder.h> + +/* + * Memory lay-out: + *  + * relative to setup_base (which is 0x90000 currently) + *  + *	0x0000-0x7FFF	Real mode kernel    + *	0x8000-0x8FFF	Stack and heap + *	0x9000-0x90FF	Kernel command line + */ +#define DEFAULT_SETUP_BASE  0x90000 +#define COMMAND_LINE_OFFSET 0x9000 +#define HEAP_END_OFFSET     0x8e00 + +#define COMMAND_LINE_SIZE   2048 + +static void build_command_line(char *command_line, int auto_boot) +{ +	char *env_command_line; +	 +	command_line[0] = '\0'; +	 +	env_command_line =  getenv("bootargs"); +	 +	/* set console= argument if we use a serial console */ +	if (NULL == strstr(env_command_line, "console=")) { +		if (0==strcmp(getenv("stdout"), "serial")) { +			 +			/* We seem to use serial console */ +			sprintf(command_line, "console=ttyS0,%s ",  +				 getenv("baudrate")); +		} +	} +	 +	if (auto_boot) { +		strcat(command_line, "auto "); +	} +		 +	if (NULL != env_command_line) { +		strcat(command_line, env_command_line); +	}  +	 +	 +	printf("Kernel command line: \"%s\"\n", command_line); +} + +void *load_zimage(char *image, unsigned long kernel_size,  +		  unsigned long initrd_addr, unsigned long initrd_size, +		  int auto_boot) +{ +        void *setup_base; +	int setup_size; +	int bootproto; +	int big_image; +	void *load_address; +	 +	 +	setup_base = (void*)DEFAULT_SETUP_BASE;	/* base address for real-mode segment */ +	 + 	if (KERNEL_MAGIC != *(u16*)(image + BOOT_FLAG_OFF)) { +		printf("Error: Invalid kernel magic (found 0x%04x, expected 0xaa55)\n", +		       *(u16*)(image + BOOT_FLAG_OFF)); +		return 0; +	} +	 +	 +	/* determine boot protocol version */ +	if (KERNEL_V2_MAGIC == *(u32*)(image+HEADER_OFF)) { +		bootproto = *(u16*)(image+VERSION_OFF); +	} else { +		/* Very old kernel */ +		bootproto = 0x0100; +	} +	 +	/* determine size of setup */ +	if (0 == *(u8*)(image + SETUP_SECTS_OFF)) { +		setup_size = 5 * 512; +	} else { +		setup_size = (*(u8*)(image + SETUP_SECTS_OFF) + 1) * 512; +	} +	 +	if (setup_size > SETUP_MAX_SIZE) { +		printf("Error: Setup is too large (%d bytes)\n", setup_size); +	} +	 +	/* Determine image type */ +  	big_image = (bootproto >= 0x0200) && (*(u8*)(image + LOADFLAGS_OFF) & BIG_KERNEL_FLAG); +	 +	/* Derermine load address */ +	load_address = (void*)(big_image ? BZIMAGE_LOAD_ADDR:ZIMAGE_LOAD_ADDR); +			 +	/* load setup */ +	memmove(setup_base, image, setup_size); +	 +	printf("Using boot protocol version %x.%02x\n",  +	       (bootproto & 0xff00) >> 8, bootproto & 0xff); +	 +	 +	if (bootproto == 0x0100) {		 +	 +		*(u16*)(setup_base + CMD_LINE_MAGIC_OFF) = COMMAND_LINE_MAGIC; +		*(u16*)(setup_base + CMD_LINE_OFFSET_OFF) = COMMAND_LINE_OFFSET;  +		 +		/* A very old kernel MUST have its real-mode code +		 * loaded at 0x90000 */ +		 +		if ((u32)setup_base != 0x90000) { +			/* Copy the real-mode kernel */ +			memmove((void*)0x90000, setup_base, setup_size); +			/* Copy the command line */ +			memmove((void*)0x99000, setup_base+COMMAND_LINE_OFFSET,  +			       COMMAND_LINE_SIZE); +			 +			setup_base = (void*)0x90000;		 /* Relocated */ +		} +		 +		/* It is recommended to clear memory up to the 32K mark */ +		memset((void*)0x90000 + setup_size, 0, SETUP_MAX_SIZE-setup_size); +	} +	 +	if (bootproto >= 0x0200) { +		*(u8*)(setup_base + TYPE_OF_LOADER_OFF) = 0xff; +		printf("Linux kernel version %s\n",  +		       (char*)(setup_base + SETUP_START_OFFSET +  +			       *(u16*)(setup_base + START_SYS_OFF + 2))); +		 +		if (initrd_addr) { +			printf("Initial RAM disk at linear address 0x%08lx, size %ld bytes\n", +			       initrd_addr, initrd_size); +			 +			*(u32*)(setup_base + RAMDISK_IMAGE_OFF) = initrd_addr; +			*(u32*)(setup_base + RAMDISK_SIZE_OFF)=initrd_size; +		} +	} +	 +	if (bootproto >= 0x0201) { +		*(u16*)(setup_base + HEAP_END_PTR_OFF) = HEAP_END_OFFSET; +		 +		/* CAN_USE_HEAP */ +		*(u8*)(setup_base + LOADFLAGS_OFF) =  +			*(u8*)(setup_base + LOADFLAGS_OFF) | HEAP_FLAG; +	} +	 +	if (bootproto >= 0x0202) { +		*(u32*)(setup_base + CMD_LINE_PTR_OFF) = (u32)setup_base + COMMAND_LINE_OFFSET; +	} else if (bootproto >= 0x0200) { +		*(u16*)(setup_base + CMD_LINE_MAGIC_OFF) = COMMAND_LINE_MAGIC; +		*(u16*)(setup_base + CMD_LINE_OFFSET_OFF) = COMMAND_LINE_OFFSET;  +		*(u16*)(setup_base + SETUP_MOVE_SIZE_OFF) = 0x9100; +	} +	 + +	 +	if (big_image) { +		if ((kernel_size - setup_size) > BZIMAGE_MAX_SIZE) {  +			printf("Error: bzImage kernel too big! (size: %ld, max: %d)\n", +			       kernel_size - setup_size, BZIMAGE_MAX_SIZE); +			return 0; +		} +		 +	} else if ((kernel_size - setup_size) > ZIMAGE_MAX_SIZE) { +		printf("Error: zImage kernel too big! (size: %ld, max: %d)\n", +		       kernel_size - setup_size, ZIMAGE_MAX_SIZE); +		return 0; +	} +	 +	/* build command line at COMMAND_LINE_OFFSET */ +	build_command_line(setup_base + COMMAND_LINE_OFFSET, auto_boot); +	 +        printf("Loading %czImage at address 0x%08x (%ld bytes)\n", big_image ? 'b' : ' ',  +	       (u32)load_address, kernel_size - setup_size); + +	        +	memmove(load_address, image + setup_size, kernel_size - setup_size); +	 +	/* ready for booting */ +	return setup_base; +} + + +void boot_zimage(void *setup_base) +{ +	struct pt_regs regs; +	 +	memset(®s, 0, sizeof(struct pt_regs)); +	regs.xds = (u32)setup_base >> 4; +	regs.xss = 0x8e00; +	regs.esp = 0x200; +	regs.eflags = 0; +	enter_realmode(((u32)setup_base+SETUP_START_OFFSET)>>4, 0, ®s, ®s); +} + + +image_header_t *fake_zimage_header(image_header_t *hdr, void *ptr, int size) +{	 +	/* There is no way to know the size of a zImage ... * +	 * so we assume that 2MB will be enough for now */ +#define ZIMAGE_SIZE 0x200000 +	 +	/* load a 1MB, the loaded will have to be moved to its final +	 * position again later... */ +#define ZIMAGE_LOAD 0x100000 +	 +	ulong checksum; +	 + 	if (KERNEL_MAGIC != *(u16*)(ptr + BOOT_FLAG_OFF)) { +		/* not a zImage or bzImage */ +		return NULL; +	} + +	if (-1 == size) { +		size = ZIMAGE_SIZE; +	} +#if 0	 +	checksum = crc32 (0, ptr, size); +#else +	checksum = 0; +#endif		 +	memset(hdr, 0, sizeof(image_header_t)); +	 +	/* Build new header */ +	hdr->ih_magic = htonl(IH_MAGIC); +	hdr->ih_time  = 0; +	hdr->ih_size  = htonl(size); +	hdr->ih_load  = htonl(ZIMAGE_LOAD); +	hdr->ih_ep    = 0; +	hdr->ih_dcrc  = htonl(checksum); +	hdr->ih_os    = IH_OS_LINUX; +	hdr->ih_arch  = IH_CPU_I386; +	hdr->ih_type  = IH_TYPE_KERNEL; +	hdr->ih_comp  = IH_COMP_NONE; + +	strncpy((char *)hdr->ih_name, "(none)", IH_NMLEN); + +	checksum = crc32(0,(const char *)hdr,sizeof(image_header_t)); + +	hdr->ih_hcrc = htonl(checksum); +	 +	return hdr; +} |