Patchwork [U-Boot,SPEAr,Enhancement,7/9] spear6xx/spear3xx: Add support to boot via NAND device

login
register
mail settings
Submitter Vipin Kumar
Date Nov. 2, 2012, 5:39 p.m.
Message ID <a767bd12f2a8c32bf35ab0c9d1cd59a1dd86f056.1351877331.git.vipin.kumar@st.com>
Download mbox | patch
Permalink /patch/196732/
State New
Delegated to: Vipin Kumar
Headers show

Comments

Vipin Kumar - Nov. 2, 2012, 5:39 p.m.
Add support for nand boot to SPL meant for spear3xx/spear6xx based boards

Signed-off-by: Vipin Kumar <vipin.kumar@st.com>
---
 arch/arm/cpu/arm926ejs/spear/Makefile           |   2 +-
 arch/arm/cpu/arm926ejs/spear/spl_boot.c         |  44 +++++-
 arch/arm/cpu/arm926ejs/spear/spl_nand.c         | 121 ++++++++++++++++
 arch/arm/include/asm/arch-spear/bootrom_table.h |  54 +++++++
 arch/arm/include/asm/arch-spear/spl_nand.h      | 181 ++++++++++++++++++++++++
 include/configs/spear600-evb.h                  |   1 +
 6 files changed, 400 insertions(+), 3 deletions(-)
 create mode 100644 arch/arm/cpu/arm926ejs/spear/spl_nand.c
 create mode 100644 arch/arm/include/asm/arch-spear/bootrom_table.h
 create mode 100644 arch/arm/include/asm/arch-spear/spl_nand.h

Patch

diff --git a/arch/arm/cpu/arm926ejs/spear/Makefile b/arch/arm/cpu/arm926ejs/spear/Makefile
index 2e026ee..5ebdf65 100644
--- a/arch/arm/cpu/arm926ejs/spear/Makefile
+++ b/arch/arm/cpu/arm926ejs/spear/Makefile
@@ -38,7 +38,7 @@  COBJS-$(CONFIG_SOC_SPEAR320) += spear320.o
 COBJS-$(CONFIG_ARCH_SPEAR6XX) += spear6xx.o
 
 ifdef CONFIG_SPL_BUILD
-COBJS-y	+= spl.o spl_boot.o
+COBJS-y	+= spl.o spl_boot.o spl_nand.o
 COBJS-$(CONFIG_SOC_SPEAR600) += spl-spear600.o
 endif
 
diff --git a/arch/arm/cpu/arm926ejs/spear/spl_boot.c b/arch/arm/cpu/arm926ejs/spear/spl_boot.c
index 9742135..497aefc 100644
--- a/arch/arm/cpu/arm926ejs/spear/spl_boot.c
+++ b/arch/arm/cpu/arm926ejs/spear/spl_boot.c
@@ -30,6 +30,7 @@ 
 #include <asm/io.h>
 #include <asm/arch/hardware.h>
 #include <asm/arch/generic.h>
+#include <asm/arch/spl_nand.h>
 
 uint32_t crc32(uint32_t, const unsigned char *, uint);
 
@@ -72,6 +73,35 @@  static int snor_image_load(u8 *load_addr, void (**image_p)(void))
 	return 0;
 }
 
+static int nand_image_load(u32 blkstart, void (**image_p)(void))
+{
+	image_header_t header;
+	int ret = 0, blknum = blkstart;
+	size_t size;
+	ulong load_address;
+
+	do {
+		size = sizeof(image_header_t);
+		ret = nand_read_skip_bad(blknum, 0, &size, (u_char *)&header);
+
+		if ((ret >= 0) && image_check_header(&header)) {
+			size = image_get_data_size(&header);
+			load_address = image_get_load(&header);
+
+			ret = nand_read_skip_bad(blknum,
+						 sizeof(image_header_t),
+						 &size, (void *)load_address);
+			if (image_check_data(&header)) {
+				/* Jump to boot image */
+				*image_p = (void (*)(void))image_get_load(&header);
+				return 1;
+			}
+		}
+	} while (++blknum < blkstart + 4);
+
+	return 0;
+}
+
 static void boot_image(void (*image)(void))
 {
 	void (*funcp)(void) __noreturn = (void *)image;
@@ -124,8 +154,18 @@  u32 spl_boot(void)
 
 	if (NAND_BOOT_SUPPORTED && nand_boot_selected()) {
 		/* NAND booting */
-		/* Not ported from XLoader to SPL yet */
-		return 0;
+		/* NAND-FSMC initialization */
+		spl_nand_init();
+
+		/* NAND booting */
+		if (nand_image_load(CONFIG_SYS_NAND_BOOT_BLK, &image)) {
+			/* Platform related late initialasations */
+			board_lowlevel_late_init();
+
+			/* Jump to boot image */
+			boot_image(image);
+			return 1;
+		}
 	}
 
 	if (PNOR_BOOT_SUPPORTED && pnor_boot_selected()) {
diff --git a/arch/arm/cpu/arm926ejs/spear/spl_nand.c b/arch/arm/cpu/arm926ejs/spear/spl_nand.c
new file mode 100644
index 0000000..e5d5288
--- /dev/null
+++ b/arch/arm/cpu/arm926ejs/spear/spl_nand.c
@@ -0,0 +1,121 @@ 
+/*
+ * (C) Copyright 2012
+ * Vipin Kumar, ST Microelectronics, vipin.kumar@st.com.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <asm/io.h>
+#include <asm/arch/bootrom_table.h>
+#include <asm/arch/generic.h>
+#include <asm/arch/spl_nand.h>
+
+static struct flashtype flashtype;
+static boot_flashdetectandinit_ptr_type boot_flashdetectandinit;
+static boot_flashread_ptr_type boot_flashread;
+static boot_nandsanitycheck_ptr_type boot_nandsanitycheck;
+static struct boot_nand_page *tmp_page_p;
+
+void spl_nand_init(void)
+{
+	struct bootrom_table *romtb_p =
+		(struct bootrom_table *)BOOTROM_TABLE_ADDRESS;
+
+	/* Global function pointers */
+	switch (get_socrev()) {
+	case SOC_SPEAR300:
+		boot_flashdetectandinit =
+			(boot_flashdetectandinit_ptr_type)0xffff1774;
+		boot_flashread = (boot_flashread_ptr_type)0xffff1050;
+		boot_nandsanitycheck =
+			(boot_nandsanitycheck_ptr_type)0xffff193C;
+		tmp_page_p = (struct boot_nand_page *)0x50030CCC;
+		break;
+	case SOC_SPEAR600_BA:
+	case SOC_SPEAR600_BB:
+		/* NAND Boot does not work for Revisions SPEAr600 BA and BB */
+	case SOC_SPEAR600_BC:
+		boot_flashdetectandinit =
+			(boot_flashdetectandinit_ptr_type)0xffff14ec;
+		boot_flashread = (boot_flashread_ptr_type)0xffff0dc4;
+		boot_nandsanitycheck =
+			(boot_nandsanitycheck_ptr_type)0xffff1628;
+		tmp_page_p = (struct boot_nand_page *)0xd2800844;
+		break;
+	case SOC_SPEAR310:
+	case SOC_SPEAR320:
+	case SOC_SPEAR600_BD:
+		boot_flashdetectandinit =
+			(romtb_p->table.table_1_0.boot_flashdetectandinit_ptr);
+		boot_flashread = (romtb_p->table.table_1_0.boot_flashread_ptr);
+		boot_nandsanitycheck =
+			(romtb_p->table.table_1_0.boot_nandsanitycheck_ptr);
+		tmp_page_p = (struct boot_nand_page *)0xd280084C;
+		break;
+	default:
+		break;
+	}
+
+	if (boot_flashdetectandinit)
+		(*boot_flashdetectandinit) (&flashtype, 1, BOTH_8_16,
+				tmp_page_p);
+}
+
+/**
+ * nand_read_skip_bad: Read image from NAND flash. Blocks that are marked bad
+ * are skipped and the next block is read instead as long as the image is short
+ * enough to fit even after skipping the bad blocks.
+ *
+ * @block: block number to start the read
+ * @offset: offset in the block number
+ * @length: buffer length, on return holds remaining bytes to read
+ * @buffer: buffer to write to
+ * @return 0 in case of success
+ */
+int nand_read_skip_bad(u32 block, size_t offset, size_t *length,
+		       u_char *buffer)
+{
+	struct command_set *command = &(flashtype.comm_set);
+	u32 chip_off, readlen;
+
+	if (!boot_nandsanitycheck || !boot_flashread)
+		return -EINVAL;
+
+	while (*length) {
+		if (BOOT_OK == (*boot_nandsanitycheck) (&flashtype, block)) {
+			/* Block is OK */
+			chip_off = command->block_size * block + offset;
+			readlen = min(command->block_size - offset, *length);
+
+			if (BOOT_OK == (*boot_flashread) (&flashtype, chip_off,
+					       buffer, readlen, tmp_page_p)) {
+				offset = 0;
+				*length -= readlen;
+				buffer += readlen;
+			} else
+				return -EINVAL;
+		}
+		/* Block is bad */
+		block++;
+	}
+
+	return 0;
+}
diff --git a/arch/arm/include/asm/arch-spear/bootrom_table.h b/arch/arm/include/asm/arch-spear/bootrom_table.h
new file mode 100644
index 0000000..65bb369
--- /dev/null
+++ b/arch/arm/include/asm/arch-spear/bootrom_table.h
@@ -0,0 +1,54 @@ 
+/*
+ * (C) Copyright 2012
+ * Vipin Kumar, ST Microelectronics, vipin.kumar@st.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef ASM_ARCH_BOOTROM_TABLE_H
+#define ASM_ARCH_BOOTROM_TABLE_H
+
+/*
+ * BootROM Table Structures
+ */
+#define BOOTROM_TABLE_ADDRESS		0xFFFF7F00
+
+#define BOOTROM_TABLE_VERSION_1_0	1
+
+struct bootrom_table_1_0 {
+	const void *boot_flashdetectandinit_ptr;
+	const void *boot_flashread_ptr;
+	const void *boot_nandsanitycheck_ptr;
+	const void *boot_nandreadpage_ptr;
+};
+
+/*
+ * Generic bootrom table structure's union. Contains the table structure for
+ * all versions
+ */
+union bootrom_ver_table {
+	struct bootrom_table_1_0 table_1_0;
+};
+
+struct bootrom_table {
+	const unsigned int table_version;
+	union bootrom_ver_table table;
+};
+
+#endif
diff --git a/arch/arm/include/asm/arch-spear/spl_nand.h b/arch/arm/include/asm/arch-spear/spl_nand.h
new file mode 100644
index 0000000..2773ea8
--- /dev/null
+++ b/arch/arm/include/asm/arch-spear/spl_nand.h
@@ -0,0 +1,181 @@ 
+/*
+ * (C) Copyright 2012
+ * Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef ASM_ARCH_SPEAR_SPL_NAND_H
+#define ASM_ARCH_SPEAR_SPL_NAND_H
+
+extern void spl_nand_init(void);
+extern int nand_read_skip_bad(u32 blk, size_t off, size_t *len, u_char *buff);
+
+/*
+ * The following definitions come from BootROM library.
+ * Please do not change the routine names as the refrences are picked from
+ * BootROM library all the versions of which are also committed along with
+ * SPL sources
+ */
+
+#define BOOT_OK			0
+
+enum {
+	BOTH_8_16		= 0,
+	EIGHT_BITS_ONLY		= 1,
+	SIXTEEN_BITS_ONLY	= 2
+};
+
+typedef enum {
+	NAND			= 0,
+	NOR			= 1,
+	ONE_NAND		= 2
+} t_flash_device;
+
+typedef enum {
+	/* SMALL PAGES */
+	/* 64M */
+	NAND_64MS_1V_8		= 0x39,
+	/* 128M */
+	NAND_128MS_1V_8		= 0x33,
+	NAND_128MS_1V_16	= 0x43,
+	NAND_128MS_3V_8		= 0x73,
+	NAND_128MS_3V_16	= 0x53,
+	/* 256M */
+	NAND_256MS_1V_8		= 0x35,
+	NAND_256MS_1V_16	= 0x45,
+	NAND_256MS_3V_8		= 0x75,
+	NAND_256MS_3V_16	= 0x55,
+	/* 512M */
+	NAND_512MS_1V_8		= 0x36,
+	NAND_512MS_1V_16	= 0x46,
+	NAND_512MS_3V_8		= 0x76,
+	NAND_512MS_3V_16	= 0x56,
+	/* 1G */
+	NAND_1GS_1V_8		= 0x40,
+	NAND_1GS_1V_16		= 0x49,
+	NAND_1GS_3V_8		= 0x79,
+	NAND_1GS_3V_16		= 0x59,
+	NAND_1GS_3V_DDP_16	= 0x74,
+	NAND_1GS_1V_DDP_8	= 0x78,
+	NAND_1GS_1V_DDP_16	= 0x72,
+
+	/* LARGE PAGES */
+	/* 512M */
+	NAND_512ML_1V_8		= 0xA2,
+	NAND_512ML_1V_16	= 0xB2,
+	NAND_512ML_3V_8		= 0xF2,
+	NAND_512ML_3V_16	= 0xC2,
+	/* 1G */
+	NAND_1GL_1V_8		= 0xA1,
+	NAND_1GL_1V_16		= 0xB1,
+	NAND_1GL_3V_8		= 0xF1,
+	NAND_1GL_3V_16		= 0xC1,
+	/* 2G */
+	NAND_2GL_1V_8		= 0xAA,
+	NAND_2GL_3V_8		= 0xDA,
+	NAND_2GL_1V_16		= 0xBA,
+	NAND_2GL_3V_16		= 0xCA,
+	/* 4G */
+	NAND_4GL_1V_8		= 0xAC,
+	NAND_4GL_3V_8		= 0xDC,
+	NAND_4GL_1V_16		= 0xBC,
+	NAND_4GL_3V_16		= 0xCC,
+	/* 8G */
+	NAND_8GL_1V_8		= 0xA3,
+	NAND_8GL_3V_8		= 0xD3,
+	NAND_8GL_1V_16		= 0xB3,
+	NAND_8GL_3V_16		= 0xC3,
+	/* 8G */
+	NAND_16GL_1V_8		= 0xA5,
+	NAND_16GL_3V_8		= 0xD5,
+	NAND_16GL_1V_16		= 0xB5,
+	NAND_16GL_3V_16		= 0xC5,
+	/* NOR */
+	NOR_8			= -1,
+	NOR_16			= -2,
+	/* NAND */
+	ONE_NAND_16		= -4,
+	NO_VALID_ID		= 0,
+	UNKNOWN_ID		= -3
+} t_flash_command_id;
+
+typedef enum {
+	NOR_BANK_0 = 0,
+	NAND_BANK_0 = 1,
+	NAND_BANK_1 = 2,
+	NAND_BANK_2 = 3,
+	LAST_BANK
+} t_flash_FSMC_bank;
+
+struct command_set {
+	u32 pagexblock;
+	u32 page_size;
+	u32 block_size;
+	u32 spare_size;
+	u32 memory_size;
+	u32 ecc_size;
+	u32 data_width;
+	u32 pmem_command;
+	u32 pmem_address[2];
+	u32 patt_command;
+	u32 pmem_read;
+	u32 mem_command;
+	u32 att_command;
+	u32 mem_command_write;
+	u32 att_command_write;
+	u32 spare_command;
+	u8 /* t_flash_FSMC_bank */ memory_bank;
+	u8  padding[3];
+};
+
+/*
+ * There is a hack while defining this structure. The bootROM interface uses the
+ * enum types for a few elements of the structure which it optimizes using the
+ * compiler flag '-fshort-enums'. Since the bootrom is fixed it can be hacked
+ * here and not let the flag apply to all other parts of code */
+struct flashtype {
+	u8 /* t_flash_device */		device;
+	u8				padding;
+	s16 /* t_flash_command_id */	read_id;
+	struct command_set		comm_set;
+};
+
+typedef enum {
+	PAGE_OK,
+	PAGE_KO
+} t_valid_flag;
+
+struct boot_nand_page {
+	u32  page_start_address;
+	u8    page[512];
+	t_valid_flag page_valid;
+	u8    padding[3];
+};
+
+typedef u32 (*boot_flashdetectandinit_ptr_type) (struct flashtype *,
+		u32, u32, struct boot_nand_page *);
+typedef u32 (*boot_flashread_ptr_type) (struct flashtype *, u32,
+		u8 *, u32, struct boot_nand_page *);
+typedef u32 (*boot_nandsanitycheck_ptr_type) (struct flashtype *,
+		u32);
+typedef u32 (*boot_nandreadpage_ptr_type) (u32, struct flashtype *,
+		struct boot_nand_page *);
+
+#endif
diff --git a/include/configs/spear600-evb.h b/include/configs/spear600-evb.h
index e7c5ee3..35761eb 100644
--- a/include/configs/spear600-evb.h
+++ b/include/configs/spear600-evb.h
@@ -85,6 +85,7 @@ 
 #define CONFIG_DDR_MT47H32M16
 #define CONFIG_SPL_TEXT_BASE			0xD2800B00
 #define CONFIG_SYS_SNOR_BOOT_BASE		0xF8010000
+#define CONFIG_SYS_NAND_BOOT_BLK		4
 
 #if defined(CONFIG_ENV_IS_IN_FLASH)
 	/* Environment is in serial NOR flash */