--- /dev/null	Thu Jan  6 02:10:11 2011
+++ linux-2.6.36/arch/mips/boot/compressed/invcache.S	Thu Jan  6 01:32:57 2011
@@ -0,0 +1,132 @@
+/*-
+ * written 2011 by Thorsten Glaser <tg@mirbsd.org> based on
+ * code from LZMA-Loader with the following copyright note:
+ * Copyright 2005 Oleg I. Vdovikin <oleg@cs.msu.su>
+ * cache manipulation adapted from Broadcom code
+ * idea taken from original bunzip2 decompressor code
+ * Copyright 2004 Manuel Novoa III <mjn3@codepoet.org>
+ */
+
+/*
+ * This file is supposed to be #include’d where it’s
+ * needed; we will not trash s0, s1, s2, s3.
+ */
+
+#define KSEG0		0x80000000
+
+#define C0_CONFIG	$16
+#define C0_TAGLO	$28
+#define C0_TAGHI	$29
+
+#define CONF1_DA_SHIFT	7			/* D$ associativity */
+#define CONF1_DA_MASK	0x00000380
+#define CONF1_DA_BASE	1
+#define CONF1_DL_SHIFT	10			/* D$ line size */
+#define CONF1_DL_MASK	0x00001c00
+#define CONF1_DL_BASE	2
+#define CONF1_DS_SHIFT	13			/* D$ sets/way */
+#define CONF1_DS_MASK	0x0000e000
+#define CONF1_DS_BASE	64
+#define CONF1_IA_SHIFT	16			/* I$ associativity */
+#define CONF1_IA_MASK	0x00070000
+#define CONF1_IA_BASE	1
+#define CONF1_IL_SHIFT	19			/* I$ line size */
+#define CONF1_IL_MASK	0x00380000
+#define CONF1_IL_BASE	2
+#define CONF1_IS_SHIFT	22			/* Instruction cache sets/way */
+#define CONF1_IS_MASK	0x01c00000
+#define CONF1_IS_BASE	64
+
+#define Index_Invalidate_I	0x00
+#define Index_Writeback_Inv_D	0x01
+
+	/* Get cache sizes */
+	.set	mips32
+	mfc0	s4,C0_CONFIG,1
+	.set	mips0
+
+	li	s5,CONF1_DL_MASK
+	and	s5,s4
+	beq	s5,zero,2f
+	 nop
+
+	srl	s5,CONF1_DL_SHIFT
+	li	t0,CONF1_DL_BASE
+	sll	s5,t0,s5		/* s5 has D$ cache line size */
+
+	li	s6,CONF1_DA_MASK
+	and	s6,s4
+	srl	s6,CONF1_DA_SHIFT
+	addiu	s6,CONF1_DA_BASE	/* s6 now has D$ associativity */
+
+	li	t0,CONF1_DS_MASK
+	and	t0,s4
+	srl	t0,CONF1_DS_SHIFT
+	li	s7,CONF1_DS_BASE
+	sll	s7,s7,t0		/* s7 has D$ sets per way */
+
+	multu	s6,s7			/* sets/way * associativity */
+	mflo	t0			/* total cache lines */
+
+	multu	s5,t0			/* D$ linesize * lines */
+	mflo	s6			/* s6 is now D$ size in bytes */
+
+	/* Initilize the D$: */
+	mtc0	zero,C0_TAGLO
+	mtc0	zero,C0_TAGHI
+
+	li	t0,KSEG0		/* Just an address for the first $ line */
+	addu	t1,t0,s6		/*  + size of cache == end */
+
+	.set	mips3
+1:	cache	Index_Writeback_Inv_D,0(t0)
+	.set	mips0
+	bne	t0,t1,1b
+	 addu	t0,s5
+
+2:
+	/* Now we get to do it all again for the I$ */
+
+	move	s7,zero			/* just in case there is no icache */
+	move	t8,zero
+
+	li	t0,CONF1_IL_MASK
+	and	t0,s4
+	beq	t0,zero,3f
+	 nop
+
+	srl	t0,CONF1_IL_SHIFT
+	li	s7,CONF1_IL_BASE
+	sll	s7,t0			/* s7 has I$ cache line size */
+
+	li	t0,CONF1_IA_MASK
+	and	t0,s4
+	srl	t0,CONF1_IA_SHIFT
+	addiu	t8,t0,CONF1_IA_BASE	/* t8 now has I$ associativity */
+
+	li	t0,CONF1_IS_MASK
+	and	t0,s4
+	srl	t0,CONF1_IS_SHIFT
+	li	t9,CONF1_IS_BASE
+	sll	t9,t0			/* t9 has I$ sets per way */
+
+	multu	t8,t9			/* sets/way * associativity */
+	mflo	t0			/* t8 is now total cache lines */
+
+	multu	s7,t0			/* I$ linesize * lines */
+	mflo	t8			/* t8 is cache size in bytes */
+
+	/* Initilize the I$: */
+	mtc0	zero,C0_TAGLO
+	mtc0	zero,C0_TAGHI
+
+	li	t0,KSEG0		/* Just an address for the first $ line */
+	addu	t1,t0,t8		/*  + size of cache == end */
+
+	.set	mips3
+1:	cache	Index_Invalidate_I,0(t0)
+	.set	mips0
+	bne	t0,t1,1b
+	 addu	t0,s7
+
+3:
--- /dev/null	Thu Jan  6 00:14:18 2011
+++ linux-2.6.36/arch/mips/boot/compressed/selfreloc.lds.S	Wed Jan  5 23:52:43 2011
@@ -0,0 +1,39 @@
+/*-
+ * written 2010 by Thorsten Glaser <tg@debian.org> based on
+ * arch/mips/kernel/vmlinux.lds and arch/mips/boot/compressed/ld.script
+ */
+
+#include <asm/asm-offsets.h>
+#include <asm/page.h>
+#include <asm-generic/vmlinux.lds.h>
+
+#undef mips
+#define mips mips
+OUTPUT_ARCH(mips)
+ENTRY(selfreloc_start)
+PHDRS {
+	text PT_LOAD FLAGS(7);	/* RWX */
+}
+SECTIONS
+{
+	. = VMLINUX_LOAD_ADDRESS;
+	.text : {
+		*(.text)
+		*(.text.*)
+		*(.rodata)
+		*(.rodata.*)
+		*(.data)
+		*(.data.*)
+		*(.bss)
+		*(.bss.*)
+	} :text
+	/DISCARD/ : {
+		*(.MIPS.options)
+		*(.options)
+		*(.pdr)
+		*(.reginfo)
+		*(.comment)
+		*(.note)
+		*(.gnu.attributes)
+	}
+}
--- /dev/null	Thu Jan  6 02:10:14 2011
+++ linux-2.6.36/arch/mips/boot/compressed/selfreloc.S	Thu Jan  6 01:21:44 2011
@@ -0,0 +1,60 @@
+/*-
+ * written 2011 by Thorsten Glaser <tg@freewrt.org> based on
+ * arch/mips/boot/compressed/head.S and code from LZMA-Loader
+ */
+
+#include <asm/asm.h>
+#include <asm/regdef.h>
+
+	.set noreorder
+	.cprestore
+
+	.text
+	LEAF(selfreloc_start)
+selfreloc_start:
+	/* Save boot rom start args */
+	move	s0, a0
+	move	s1, a1
+	move	s2, a2
+	move	s3, a3
+
+	/* Copy code to the correct place */
+	PTR_LI	a0, VMLINUZ_LOAD_ADDRESS
+	PTR_LA	a1, imgbeg
+	PTR_LA	a2, imgend
+1:	lw	t0, 0(a1)
+	sw	t0, 0(a0)
+	add	a1, 4
+	add	a0, 4
+	blt	a1, a2, 1b
+	 nop
+
+	/*
+	 * At this point we need to invalidate dcache and
+	 * icache before jumping to the new code
+	 */
+/* #include "invcache.S" // since this may work only on brcm? */
+
+	/* Restore boot rom start args */
+	move	a0, s0
+	move	a1, s1
+	move	a2, s2
+	move	a3, s3
+
+	/* Jump to the code at its new location */
+	PTR_LI	k0, VMLINUZ_LOAD_ADDRESS
+	jr	k0
+	 nop
+
+	/* Just in case we come back… */
+3:
+	b	3b
+	 nop
+	END(selfreloc_start)
+
+	.globl	imgbeg
+	.p2align 2
+imgbeg:	.incbin	"vmlinuz.bin"
+	.globl	imgend
+	.p2align 2
+imgend:
--- linux-2.6.36/arch/mips/boot/compressed/Makefile~	Wed Jan  5 21:26:40 2011
+++ linux-2.6.36/arch/mips/boot/compressed/Makefile	Wed Jan  5 23:35:58 2011
@@ -62,8 +62,13 @@ $(obj)/piggy.o: $(obj)/dummy.o $(obj)/vm
 # Calculate the load address of the compressed kernel image
 hostprogs-y := calc_vmlinuz_load_addr
 
+ifdef CONFIG_BCM47XX
+# XXX just after CFE, just pray the address is static
+VMLINUZ_LOAD_ADDRESS = 0xffffffff80480000
+else
 VMLINUZ_LOAD_ADDRESS = $(shell $(obj)/calc_vmlinuz_load_addr \
 		$(obj)/vmlinux.bin $(VMLINUX_LOAD_ADDRESS))
+endif
 
 vmlinuzobjs-y += $(obj)/piggy.o
 
@@ -106,4 +107,12 @@ OBJCOPYFLAGS_vmlinuz.srec := $(OBJCOPYFL
 vmlinuz.srec: vmlinuz
 	$(call cmd,objcopy)
 
-clean-files := $(objtree)/vmlinuz $(objtree)/vmlinuz.{32,ecoff,bin,srec}
+AFLAGS_selfreloc.o := -DVMLINUZ_LOAD_ADDRESS=$(VMLINUZ_LOAD_ADDRESS)
+arch/mips/boot/compressed/selfreloc.o: arch/mips/boot/compressed/selfreloc.S vmlinuz.bin arch/mips/boot/compressed/invcache.S
+
+CPPFLAGS_selfreloc.lds := $(KBUILD_CFLAGS)
+
+vmlinub.elf: arch/mips/boot/compressed/selfreloc.o arch/mips/boot/compressed/selfreloc.lds
+	$(LD) $(LDFLAGS) -T arch/mips/boot/compressed/selfreloc.lds arch/mips/boot/compressed/selfreloc.o -o $@
+
+clean-files := $(objtree)/vmlinuz $(objtree)/vmlinuz.{32,ecoff,bin,srec} $(objtree)/vmlinub.elf $(objtree)/arch/mips/boot/compressed/selfreloc.{o,lds}
--- linux-2.6.36/arch/mips/Makefile~	Wed Jan  5 20:26:12 2011
+++ linux-2.6.36/arch/mips/Makefile	Wed Jan  5 22:41:38 2011
@@ -79,6 +79,7 @@ endif
 all-$(CONFIG_BOOT_ELF32)	:= $(vmlinux-32)
 all-$(CONFIG_BOOT_ELF64)	:= $(vmlinux-64)
 all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlinuz
+all-$(CONFIG_BCM47XX)		+= vmlinub.elf
 
 #
 # GCC uses -G 0 -mabicalls -fpic as default.  We don't want PIC in the kernel
@@ -285,7 +286,7 @@ vmlinux.bin vmlinux.ecoff vmlinux.srec: 
 	$(Q)$(MAKE) $(build)=arch/mips/boot VMLINUX=$(vmlinux-32) arch/mips/boot/$@
 
 # boot/compressed
-vmlinuz vmlinuz.bin vmlinuz.ecoff vmlinuz.srec: $(vmlinux-32) FORCE
+vmlinuz vmlinuz.bin vmlinuz.ecoff vmlinuz.srec vmlinub.elf: $(vmlinux-32) FORCE
 	$(Q)$(MAKE) $(build)=arch/mips/boot/compressed \
 	   VMLINUX_LOAD_ADDRESS=$(load-y) 32bit-bfd=$(32bit-bfd) $@
 
@@ -322,6 +323,7 @@ define archhelp
 	echo '  vmlinuz.ecoff        - ECOFF zboot image'
 	echo '  vmlinuz.bin          - Raw binary zboot image'
 	echo '  vmlinuz.srec         - SREC zboot image'
+	echo '  vmlinub.elf          - ELF self-relocating zboot image'
 	echo
 	echo '  These will be default as apropriate for a configured platform.'
 endef
