* Patch by Daniel Engström, 13 Nov 2002:
  Add support for i386 architecture and AMD SC520 board

* Patch by Pierre Aubert, 12 Nov 2002:
  Add support for DOS filesystem and booting from DOS floppy disk
diff --git a/lib_i386/Makefile b/lib_i386/Makefile
new file mode 100644
index 0000000..34994e5
--- /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 0000000..2f5ea8c
--- /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 0000000..94319af
--- /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 0000000..193860a
--- /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 0000000..c37a0d8
--- /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 0000000..4537095
--- /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 0000000..d202625
--- /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 0000000..72110c4
--- /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 0000000..e5577e8
--- /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 0000000..372147c
--- /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 0000000..9f212c2
--- /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 0000000..190d46e
--- /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(&regs, 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, &regs, &regs);
+}
+
+
+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;
+}