
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
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 */