由于价格的原因,相对于norflash,nandflash对于存储大容量的数据来说更具有优势。但是程序不能直接在nandflash上运行,因此s3c2440提供了一个机制,即系统会自动把nandflash中前4k的内容复制到名为“Steppingstone”的内部SRAM中,利用这段SRAM,程序员需要再把程序复制到其余的SRAM中,然后运行刚刚复制到SRAM中的程序。
本文就介绍如何使u-boot在nandflash中启动,该工作原理类似于u-boot-2011.06自带的smdk6400开发板的nandflash启动过程,即最终生成的烧写文件为u-boot-nand.bin,它是由两个文件组成的:
nand_spl/u-boot-spl-16k.bin+ u-boot.bin = u-boot-nand.bin
u-boot-spl-16k.bin文件的大小正好为4k,系统启动后,这4k的内容自动复制到Steppingstone中。u-boot-spl-16k.bin在完成必要的硬件初始化后,复制u-boot.bin文件到指定的内存中,然后运行已经复制到内存中的u-boot.bin文件。
下面就具体讲解移植的过程:
1、boards.cfg
在该文件内去掉下面语句:
zhaocj2440 arm arm920t - samsung s3c24x0
2、Makefile
在该文件内的第1050行左右添加下面语句:
#########################################################################
## ARM920T Systems
#########################################################################
zhaocj2440_config : unconfig
@mkdir-p $(obj)include $(obj)board/samsung/zhaocj2440
@mkdir-p $(obj)nand_spl/board/samsung/zhaocj2440
@echo"#define CONFIG_NAND_U_BOOT" > $(obj)include/config.h
@echo"CONFIG_NAND_U_BOOT = y" >> $(obj)include/config.mk
@echo"RAM_TEXT = 0x33000000" >>$(obj)board/samsung/zhaocj2440/config.tmp
@$(MKCONFIG)zhaocj2440 arm arm920t - samsung s3c24x0
@echo"CONFIG_NAND_U_BOOT = y" >> $(obj)include/config.mk
3、board/samsung/zhaocj2440/
在该目录下创建config.mk文件,内容为:
sinclude$(OBJTREE)/board/$(BOARDDIR)/config.tmp
ifndef CONFIG_NAND_SPL
CONFIG_SYS_TEXT_BASE =$(RAM_TEXT)
else
CONFIG_SYS_TEXT_BASE = 0
endif
4、nand_spl/board/Samsung/
在该目录下创建zhaocj2440目录,并在zhaocj2440目录下再创建config.mk,Makefile,和u-boot.lds这三个文件,内容分别为:
config.mk文件:
include$(TOPDIR)/board/$(BOARDDIR)/config.mk
# PAD_TO used to generate a 4kByte binaryneeded for the combined image
# -> PAD_TO = CONFIG_SYS_TEXT_BASE +4096
PAD_TO :=$(shell expr $$[$(CONFIG_SYS_TEXT_BASE) + 4096])
ifeq ($(debug),1)
PLATFORM_CPPFLAGS += -DDEBUG
endif
Makefile文件:
CONFIG_NAND_SPL = y
include $(TOPDIR)/config.mk
include$(TOPDIR)/nand_spl/board/$(BOARDDIR)/config.mk
nandobj :=$(OBJTREE)/nand_spl/
LDSCRIPT=$(TOPDIR)/nand_spl/board/$(BOARDDIR)/u-boot.lds
LDFLAGS := -T $(nandobj)u-boot.lds -Ttext$(CONFIG_SYS_TEXT_BASE) $(LDFLAGS) \
$(LDFLAGS_FINAL)
AFLAGS +=-DCONFIG_NAND_SPL
CFLAGS +=-DCONFIG_NAND_SPL
SOBJS =start.o lowlevel_init.o
COBJS =nand_boot.o s3c2440_nand.o
SRCS :=$(addprefix $(obj),$(SOBJS:.o=.S) $(COBJS:.o=.c))
OBJS :=$(addprefix $(obj),$(SOBJS) $(COBJS))
__OBJS :=$(SOBJS) $(COBJS)
LNDIR :=$(nandobj)board/$(BOARDDIR)
ALL =$(nandobj)u-boot-spl $(nandobj)u-boot-spl.bin $(nandobj)u-boot-spl-16k.bin
all: $(obj).depend$(ALL)
$(nandobj)u-boot-spl-16k.bin:$(nandobj)u-boot-spl
$(OBJCOPY)${OBJCFLAGS} --pad-to=$(PAD_TO) -O binary $< $@
$(nandobj)u-boot-spl.bin: $(nandobj)u-boot-spl
$(OBJCOPY)${OBJCFLAGS} -O binary $< $@
$(nandobj)u-boot-spl: $(OBJS) $(nandobj)u-boot.lds
cd$(LNDIR) && $(LD) $(LDFLAGS) $(__OBJS) \
-Map$(nandobj)u-boot-spl.map \
-o$(nandobj)u-boot-spl
$(nandobj)u-boot.lds: $(LDSCRIPT)
$(CPP)$(CPPFLAGS) $(LDPPFLAGS) -ansi -D__ASSEMBLY__ -P - <$^ >$@
# create symbolic links for common files
# from cpu directory
$(obj)start.S:
@rm-f $@
@ln-s $(TOPDIR)/arch/arm/cpu/arm920t/start.S $@
# from board directory
$(obj)lowlevel_init.S:
@rm-f $@
@ln-s $(TOPDIR)/board/samsung/zhaocj2440/lowlevel_init.S $@
# from nand_spl directory
$(obj)nand_boot.c:
@rm-f $@
@ln-s $(TOPDIR)/nand_spl/nand_boot.c $@
$(obj)s3c2440_nand.c:
@rm-f $@
@ln-s $(TOPDIR)/drivers/mtd/nand/s3c2440_nand.c$@
#########################################################################
$(obj)%.o: $(obj)%.S
$(CC)$(AFLAGS) -c -o $@ $<
$(obj)%.o: $(obj)%.c
$(CC)$(CFLAGS) -c -o $@ $<
# defines $(obj).depend target
include $(SRCTREE)/rules.mk
sinclude $(obj).depend
#########################################################################
u-boot.lds文件:
OUTPUT_FORMAT("elf32-littlearm","elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
.= 0x00000000;
.= ALIGN(4);
.text :
{
start.o (.text)
nand_boot.o (.text)
*(.text)
}
.= ALIGN(4);
.rodata: { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
.= ALIGN(4);
.data: { *(.data) }
.= ALIGN(4);
.got: { *(.got) }
__u_boot_cmd_start= .;
.u_boot_cmd: { *(.u_boot_cmd) }
__u_boot_cmd_end= .;
.= ALIGN(4);
.rel.dyn: {
__rel_dyn_start= .;
*(.rel*)
__rel_dyn_end= .;
}
.dynsym: {
__dynsym_start= .;
*(.dynsym)
}
_end= .;
.bss__rel_dyn_start (OVERLAY) : {
__bss_start= .;
*(.bss)
.= ALIGN(4);
__bss_end__= .;
}
}
5、arch/arm/cpu/arm920t/start.s
在该文件内修改下列内容,其中红色标记的代码为需要修改的部分:
.globl _start
_start: b start_code
#ifndef CONFIG_NAND_SPL // by zhaocj
ldr pc, _undefined_instruction
ldr pc, _software_interrupt
ldr pc, _prefetch_abort
ldr pc, _data_abort
ldr pc, _not_used
ldr pc, _irq
ldr pc, _fiq
_undefined_instruction: .word undefined_instruction
_software_interrupt: .word software_interrupt
_prefetch_abort: .word prefetch_abort
_data_abort: .word data_abort
_not_used: .wordnot_used
_irq: .wordirq
_fiq: .wordfiq
_pad: .word 0x12345678 //by zhaocj start
#else
. = _start + 64
#endif //by zhaocj end
.balignl16,0xdeadbeef
…………
/* Set stackpointer in internal RAM to callboard_init_f */
#ifndef CONFIG_NAND_SPL //by zhaocj
call_board_init_f:
ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)
bic sp, sp, #7 /* 8-byte alignment for ABIcompliance */
ldr r0,=0x00000000
bl board_init_f
…………
blcoloured_LED_init
blred_LED_on
#endif
#endif // by zhaocj
/*
* We are done. Do notreturn, instead branch to second part of board
* initialization, nowrunning from RAM.
*/
#ifdef CONFIG_NAND_SPL
ldr sp,=0x33200000 //by zhaocj
ldr r0, _nand_boot_ofs
mov pc, r0
_nand_boot_ofs:
.wordnand_boot
…………
mov lr, ip
mov pc, lr
#endif /* CONFIG_SKIP_LOWLEVEL_INIT */
#ifndef CONFIG_NAND_SPL //by zhaocj
/*
*************************************************************************
*
* Interrupt handling
*
*************************************************************************
*/
@
@ IRQ stack frame.
@
#define S_FRAME_SIZE 72
…………
fiq:
get_bad_stack
bad_save_user_regs
bl do_fiq
#endif
#endif //by zhaocj
6、include/configs/zhaocj2440.h
在该文件内修改下列内容:
注释掉下面语句:
#define CONFIG_SYS_TEXT_BASE 0x0
添加下面语句:
#ifndef CONFIG_NAND_SPL
#define CONFIG_SKIP_LOWLEVEL_INIT
#endif
注释掉下面语句:
#define CONFIG_ENV_ADDR (CONFIG_SYS_FLASH_BASE +0x080000)
#define CONFIG_ENV_IS_IN_FLASH
#define CONFIG_ENV_SIZE 0x10000
添加下面语句:
#define CONFIG_SYS_NAND_U_BOOT_DST 0x33000000 /*NUB load-addr */
#define CONFIG_SYS_NAND_U_BOOT_START CONFIG_SYS_NAND_U_BOOT_DST /* NUB start-addr */
#define CONFIG_SYS_NAND_U_BOOT_OFFS (4 * 1024) /* Offset to RAM U-Boot image */
#define CONFIG_SYS_NAND_U_BOOT_SIZE 0x80000 /*Size of RAM U-Boot image */
/* NAND chip page size */
#define CONFIG_SYS_NAND_PAGE_SIZE 2048
/* NAND chip block size */
#define CONFIG_SYS_NAND_BLOCK_SIZE (128 * 1024)
/* NAND chip page per block count */
#define CONFIG_SYS_NAND_PAGE_COUNT 64
/* Location of the bad-block label */
#define CONFIG_SYS_NAND_BAD_BLOCK_POS 0
/* Extra address cycle for > 128MiB */
#define CONFIG_SYS_NAND_5_ADDR_CYCLE
/* Size of the block protected by one OOB(Spare Area in Samsung terminology) */
#define CONFIG_SYS_NAND_ECCSIZE CONFIG_SYS_NAND_PAGE_SIZE
/* Number of ECC bytes per OOB - S3C6400 calculates 4 bytes ECC in 1-bitmode */
#define CONFIG_SYS_NAND_ECCBYTES 4
/* Number of ECC-blocks per NAND page */
#define CONFIG_SYS_NAND_ECCSTEPS (CONFIG_SYS_NAND_PAGE_SIZE / CONFIG_SYS_NAND_ECCSIZE)
/* Size of a single OOB region */
#define CONFIG_SYS_NAND_OOBSIZE 64
/* Number of ECC bytes per page */
#define CONFIG_SYS_NAND_ECCTOTAL (CONFIG_SYS_NAND_ECCBYTES *CONFIG_SYS_NAND_ECCSTEPS)
/* ECC byte positions */
#define CONFIG_SYS_NAND_ECCPOS {40, 41, 42, 43, 44, 45, 46, 47, \
48, 49, 50, 51, 52, 53, 54, 55, \
56, 57, 58, 59, 60, 61, 62, 63}
/* Put environment copies after the end ofU-Boot owned RAM */
#define CONFIG_NAND_ENV_DST (0x33000000 + 0x80000)
#define CONFIG_ENV_OFFSET 0x80000
#define CONFIG_ENV_IS_IN_NAND
#define CONFIG_ENV_SIZE 0x4000 /* Total Size of Environment Sector */
7、drivers/mtd/cfi_flash.c
在该文件的第2156行(flash_init函数内)把size变量改为:
unsigned long size = 0x200000;
之所以要修改这里,是因为如果nandflash启动,那么系统是无法识别norflash的。为了能够让系统正常运行,修改这个变量是一个简单的办法。
通过以上7个步骤的修改,就完成了nandflash启动的移植,把编译好的u-boot-nand.bin烧写到nandflash中即可运行了。下面再简单描述一下它的工作原理:u-boot-nand.bin文件是由u-boot-spl-16k.bin文件和u-boot.bin文件组成,后两个文件是两个独立的文件,由编译器一次编译完成。之所以能生成两个独立的文件,依靠的是CONFIG_NAND_SPL这个变量。当定义了CONFIG_NAND_SPL时,编译的是u-boot-spl-16k.bin文件;没有定义CONFIG_NAND_SPL时,编译的是u-boot.bin文件。在u-boot-spl-16k.bin文件内,运行了nand_spl/nand_boot.c这个文件,它负责把u-boot.bin文件从nandflash中复制到以0x33000000为起始地址的一段内存中,复制完后,再让系统从0x33000000处开始运行,即运行u-boot.bin的内容。
本文所介绍的方法不同于网络上所能检索到的绝大多数基于vivi的nandflash启动方法,它不需要写任何关于代码复制的内容,而是利用u-boot自带的程序(nand_spl/nand_boot.c)。因此可以说,该方法更能保持u-boot的一致性和完成性。