microblaze: Add SPL support

Add support for U-BOOT SPL. NOR and RAM mode are supported.
There are 3 images in NOR flash. u-boot.img, dtb and kernel.

Signed-off-by: Michal Simek <michal.simek@xilinx.com>
diff --git a/arch/microblaze/cpu/Makefile b/arch/microblaze/cpu/Makefile
index 6e201f2..4955e81 100644
--- a/arch/microblaze/cpu/Makefile
+++ b/arch/microblaze/cpu/Makefile
@@ -8,3 +8,4 @@
 extra-y	= start.o
 obj-y	= irq.o
 obj-y	+= cpu.o interrupts.o cache.o exception.o timer.o
+obj-$(CONFIG_SPL_BUILD)	+= spl.o
diff --git a/arch/microblaze/cpu/spl.c b/arch/microblaze/cpu/spl.c
new file mode 100644
index 0000000..0912261
--- /dev/null
+++ b/arch/microblaze/cpu/spl.c
@@ -0,0 +1,55 @@
+/*
+ * (C) Copyright 2013 - 2014 Xilinx, Inc
+ *
+ * Michal Simek <michal.simek@xilinx.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <image.h>
+#include <spl.h>
+#include <version.h>
+#include <asm/io.h>
+#include <asm/u-boot.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+bool boot_linux;
+
+u32 spl_boot_device(void)
+{
+	return BOOT_DEVICE_NOR;
+}
+
+/* Board initialization after bss clearance */
+void spl_board_init(void)
+{
+	gd = (gd_t *)CONFIG_SPL_STACK_ADDR;
+
+	/* enable console uart printing */
+	preloader_console_init();
+}
+
+#ifdef CONFIG_SPL_OS_BOOT
+void __noreturn jump_to_image_linux(void *arg)
+{
+	debug("Entering kernel arg pointer: 0x%p\n", arg);
+	typedef void (*image_entry_arg_t)(char *, ulong, ulong)
+		__attribute__ ((noreturn));
+	image_entry_arg_t image_entry =
+		(image_entry_arg_t)spl_image.entry_point;
+
+	image_entry(NULL, 0, (ulong)arg);
+}
+#endif /* CONFIG_SPL_OS_BOOT */
+
+int spl_start_uboot(void)
+{
+#ifdef CONFIG_SPL_OS_BOOT
+	if (boot_linux)
+		return 0;
+#endif
+
+	return 1;
+}
diff --git a/arch/microblaze/cpu/start.S b/arch/microblaze/cpu/start.S
index 8928024..1757bbf 100644
--- a/arch/microblaze/cpu/start.S
+++ b/arch/microblaze/cpu/start.S
@@ -22,6 +22,11 @@
 	 */
 
 	mts	rmsr, r0	/* disable cache */
+
+#if defined(CONFIG_SPL_BUILD)
+	addi	r1, r0, CONFIG_SPL_STACK_ADDR
+	addi	r1, r1, -4	/* Decrement SP to top of memory */
+#else
 	addi	r1, r0, CONFIG_SYS_INIT_SP_OFFSET
 	addi	r1, r1, -4	/* Decrement SP to top of memory */
 
@@ -115,6 +120,7 @@
 	sh	r7, r0, r8
 	rsubi	r8, r10, 0x26
 	sh	r6, r0, r8
+#endif /* BUILD_SPL */
 
 	/* Flush cache before enable cache */
 	addik	r5, r0, 0
@@ -139,9 +145,14 @@
 	cmp     r6, r5, r4 /* check if we have reach the end */
 	bnei    r6, 2b
 3:	/* jumping to board_init */
+#ifndef CONFIG_SPL_BUILD
 	brai	board_init_f
+#else
+	brai	board_init_r
+#endif
 1:	bri	1b
 
+#ifndef CONFIG_SPL_BUILD
 /*
  * Read 16bit little endian
  */
@@ -174,3 +185,4 @@
 	rtsd	r15, 8
 	or	r0, r0, r0
 	.end	out16
+#endif
diff --git a/arch/microblaze/cpu/timer.c b/arch/microblaze/cpu/timer.c
index 69ae6d4..3960bbb 100644
--- a/arch/microblaze/cpu/timer.c
+++ b/arch/microblaze/cpu/timer.c
@@ -34,6 +34,7 @@
 	}
 }
 
+#ifndef CONFIG_SPL_BUILD
 static void timer_isr(void *arg)
 {
 	timestamp++;
@@ -62,10 +63,15 @@
 		if (ret)
 			tmr = NULL;
 	}
-
 	/* No problem if timer is not found/initialized */
 	return 0;
 }
+#else
+int timer_init(void)
+{
+	return 0;
+}
+#endif
 
 /*
  * This function is derived from PowerPC code (read timebase as long long).
diff --git a/arch/microblaze/cpu/u-boot-spl.lds b/arch/microblaze/cpu/u-boot-spl.lds
new file mode 100644
index 0000000..96353cd
--- /dev/null
+++ b/arch/microblaze/cpu/u-boot-spl.lds
@@ -0,0 +1,57 @@
+/*
+ * (C) Copyright 2013 - 2014 Xilinx, Inc
+ *
+ * Michal Simek <michal.simek@xilinx.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <asm-offsets.h>
+
+OUTPUT_ARCH(microblaze)
+ENTRY(_start)
+
+SECTIONS
+{
+	.text ALIGN(0x4):
+	{
+		__text_start = .;
+		arch/microblaze/cpu/start.o (.text)
+		*(.text)
+		*(.text.*)
+		__text_end = .;
+	}
+
+	.rodata ALIGN(0x4):
+	{
+		__rodata_start = .;
+		*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
+		__rodata_end = .;
+	}
+
+	.data ALIGN(0x4):
+	{
+		__data_start = .;
+		*(.data)
+		*(.data.*)
+		__data_end = .;
+	}
+
+	.bss ALIGN(0x4):
+	{
+		__bss_start = .;
+		*(.sbss)
+		*(.scommon)
+		*(.bss)
+		*(.bss.*)
+		*(COMMON)
+		. = ALIGN(4);
+		__bss_end = .;
+	}
+	__end = . ;
+}
+
+#if defined(CONFIG_SPL_MAX_FOOTPRINT)
+ASSERT(__end - _start < (CONFIG_SPL_MAX_FOOTPRINT), \
+        "SPL image plus BSS too big");
+#endif
diff --git a/arch/microblaze/include/asm/spl.h b/arch/microblaze/include/asm/spl.h
new file mode 100644
index 0000000..c1cae6c
--- /dev/null
+++ b/arch/microblaze/include/asm/spl.h
@@ -0,0 +1,16 @@
+/*
+ * (C) Copyright 2013 - 2014 Xilinx, Inc
+ *
+ * Michal Simek <michal.simek@xilinx.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _ASM_MICROBLAZE_SPL_H_
+#define _ASM_MICROBLAZE_SPL_H_
+
+#define BOOT_DEVICE_RAM		1
+#define BOOT_DEVICE_NOR		2
+#define BOOT_DEVICE_SPI		3
+
+#endif
diff --git a/arch/microblaze/include/asm/u-boot.h b/arch/microblaze/include/asm/u-boot.h
index 31b014c..ab3f232 100644
--- a/arch/microblaze/include/asm/u-boot.h
+++ b/arch/microblaze/include/asm/u-boot.h
@@ -25,6 +25,7 @@
 	unsigned long	bi_sramstart;	/* start of SRAM memory */
 	unsigned long	bi_sramsize;	/* size	 of SRAM memory */
 	unsigned int	bi_baudrate;	/* Console Baudrate */
+	ulong		bi_boot_params; /* where this board expects params */
 } bd_t;
 
 /* For image.h:image_check_target_arch() */
diff --git a/arch/microblaze/lib/board.c b/arch/microblaze/lib/board.c
index d22aa85..59956a8 100644
--- a/arch/microblaze/lib/board.c
+++ b/arch/microblaze/lib/board.c
@@ -50,10 +50,14 @@
 	fdtdec_check_fdt,
 #endif
 	serial_init,
+#ifndef CONFIG_SPL_BUILD
 	console_init_f,
+#endif
 	display_banner,
+#ifndef CONFIG_SPL_BUILD
 	interrupts_init,
 	timer_init,
+#endif
 	NULL,
 };
 
@@ -66,7 +70,7 @@
 	gd = (gd_t *)(CONFIG_SYS_SDRAM_BASE + CONFIG_SYS_GBL_DATA_OFFSET);
 	bd = (bd_t *)(CONFIG_SYS_SDRAM_BASE + CONFIG_SYS_GBL_DATA_OFFSET
 						- GENERATED_BD_INFO_SIZE);
-#if defined(CONFIG_CMD_FLASH)
+#if defined(CONFIG_CMD_FLASH) && !defined(CONFIG_SPL_BUILD)
 	ulong flash_size = 0;
 #endif
 	asm ("nop");	/* FIXME gd is not initialize - wait */
@@ -88,9 +92,12 @@
 	/* FDT is at end of image */
 	gd->fdt_blob = (void *)__end;
 #endif
+
+#ifndef CONFIG_SPL_BUILD
 	/* Allow the early environment to override the fdt address */
 	gd->fdt_blob = (void *)getenv_ulong("fdtcontroladdr", 16,
 						(uintptr_t)gd->fdt_blob);
+#endif
 
 	/*
 	 * The Malloc area is immediately below the monitor copy in DRAM
@@ -110,6 +117,7 @@
 			hang();
 	}
 
+#ifndef CONFIG_SPL_BUILD
 #ifdef CONFIG_OF_CONTROL
 	/* For now, put this check after the console is ready */
 	if (fdtdec_prepare_fdt())
@@ -190,4 +198,5 @@
 		WATCHDOG_RESET();
 		main_loop();
 	}
+#endif /* CONFIG_SPL_BUILD */
 }
diff --git a/include/configs/microblaze-generic.h b/include/configs/microblaze-generic.h
index 35e5a4a..486787e 100644
--- a/include/configs/microblaze-generic.h
+++ b/include/configs/microblaze-generic.h
@@ -447,4 +447,64 @@
 # undef CONFIG_PHYLIB
 #endif
 
+/* SPL part */
+#define CONFIG_SPL
+#define CONFIG_CMD_SPL
+#define CONFIG_SPL_FRAMEWORK
+#define CONFIG_SPL_LIBCOMMON_SUPPORT
+#define CONFIG_SPL_LIBGENERIC_SUPPORT
+#define CONFIG_SPL_SERIAL_SUPPORT
+#define CONFIG_SPL_BOARD_INIT
+
+#define CONFIG_SPL_LDSCRIPT	"arch/microblaze/cpu/u-boot-spl.lds"
+
+#define CONFIG_SPL_RAM_DEVICE
+#define CONFIG_SPL_NOR_SUPPORT
+
+/* for booting directly linux */
+#define CONFIG_SPL_OS_BOOT
+
+#define CONFIG_SYS_OS_BASE		(CONFIG_SYS_FLASH_BASE + \
+					 0x60000)
+#define CONFIG_SYS_FDT_BASE		(CONFIG_SYS_FLASH_BASE + \
+					 0x40000)
+#define CONFIG_SYS_SPL_ARGS_ADDR	(CONFIG_SYS_TEXT_BASE + \
+					 0x1000000)
+
+/* SP location before relocation, must use scratch RAM */
+/* BRAM start */
+#define CONFIG_SYS_INIT_RAM_ADDR	0x0
+/* BRAM size - will be generated */
+#define CONFIG_SYS_INIT_RAM_SIZE	0x10000
+/* Stack pointer prior relocation, must situated at on-chip RAM */
+#define CONFIG_SYS_SPL_MALLOC_END	(CONFIG_SYS_INIT_RAM_ADDR + \
+					 CONFIG_SYS_INIT_RAM_SIZE - \
+					 GENERATED_GBL_DATA_SIZE)
+
+#define CONFIG_SYS_SPL_MALLOC_SIZE	0x100
+
+/*
+ * The main reason to do it in this way is that MALLOC_START
+ * can't be defined - common/spl/spl.c
+ */
+#if (CONFIG_SYS_SPL_MALLOC_SIZE != 0)
+# define CONFIG_SYS_SPL_MALLOC_START	(CONFIG_SYS_SPL_MALLOC_END - \
+					 CONFIG_SYS_SPL_MALLOC_SIZE)
+# define CONFIG_SPL_STACK_ADDR		CONFIG_SYS_SPL_MALLOC_START
+#else
+# define CONFIG_SPL_STACK_ADDR		CONFIG_SYS_SPL_MALLOC_END
+#endif
+
+/* Just for sure that there is a space for stack */
+#define CONFIG_SPL_STACK_SIZE		0x100
+
+#define CONFIG_SYS_UBOOT_BASE		CONFIG_SYS_FLASH_BASE
+#define CONFIG_SYS_UBOOT_START		CONFIG_SYS_TEXT_BASE
+
+#define CONFIG_SPL_MAX_FOOTPRINT	(CONFIG_SYS_INIT_RAM_SIZE - \
+					 CONFIG_SYS_INIT_RAM_ADDR - \
+					 GENERATED_GBL_DATA_SIZE - \
+					 CONFIG_SYS_SPL_MALLOC_SIZE - \
+					 CONFIG_SPL_STACK_SIZE)
+
 #endif	/* __CONFIG_H */