uboot移植

目标平台

NANO2410A

目录
CPU S3C2410 (ARM920T)
Nand FLASH K9F1208 (64M*8bit)
SRAM HY57V561620 (4banks*4M+16Bit)

准备工作

我的移植工作是基于1.3.2来进行的,因为在网上看到1.3.3之后的版本Makefile会有点小问题
自己插入的Nand Flash拷贝代码会被放入到前4K以外,导致不能执行
关于这个问题和解决办法请参照这里

下载好uboot源码之后,解压

tar zxvf u-boot-1.3.2.tar.gz

在board下建立自己板子对应的文件,以smdk2410为模板

cp -r smdk2410 xxx2410  

修改Makefile,将smdk2410修改成对应的xxx2410
修改config.mk,因为我们的板子Nand Flash只有32M,所以需要将 TEXT_BASE 设置成0x31F80000
修改lowlevel_init.S,按照我们的需要(这里我参考的是一个工作良好的vivi的配置)修改 SMRDATA
换到uboot的根目录,make一下

原理

Nand Flash和Nor Flash不同,其中Nand Flash不能直接读写,需要通过驱动程序控制
但是在我们的板子上没有Nor Flash,也就是说我们需要把bootloader也放入Nand Flash中。
好在s3c2410在设计时考虑到了这样的问题,提供了这样的机制
uboot移植_第1张图片
在每次CPU上电之后,CPU会通过内置的Nand控制器将Bank0上面的前4K内容映射到一片叫做Steppingstone的buffer中
于是,我们需要将一段代码放在这前4K中,并且在这4K代码中实现将整个uboot载入内存并开始执行。

好在有vivi的代码可以参考,我们不难发现在跳转到C入口之前会先执行copy_myself

#ifdef CONFIG_S3C2410_NAND_BOOT	/* CONFIG_S3C2410_NAND_BOOT=y */
@
@ copy_myself: copy vivi to ram
@
copy_myself:
	mov	r10, lr

	@ reset NAND
	mov	r1, #NAND_CTL_BASE
	ldr	r2, =0xf830		@ initial value
	str	r2, [r1, #oNFCONF]
	ldr	r2, [r1, #oNFCONF]
	bic	r2, r2, #0x800		@ enable chip
	str	r2, [r1, #oNFCONF]
	mov	r2, #0xff		@ RESET command
	strb	r2, [r1, #oNFCMD]
	mov	r3, #0			@ wait 
1:	add	r3, r3, #0x1
	cmp	r3, #0xa
	blt	1b
2:	ldr	r2, [r1, #oNFSTAT]	@ wait ready
	tst	r2, #0x1
	beq	2b
	ldr	r2, [r1, #oNFCONF]
	orr	r2, r2, #0x800		@ disable chip
	str	r2, [r1, #oNFCONF]

	@ get read to call C functions (for nand_read())
	ldr	sp, DW_STACK_START	@ setup stack pointer
	mov	fp, #0			@ no previous frame, so fp=0

	@ copy vivi to RAM
	ldr	r0, =VIVI_RAM_BASE
	mov     r1, #0x0
	mov	r2, #0x20000
	bl	nand_read_ll

	tst	r0, #0x0
	beq	ok_nand_read
#ifdef CONFIG_DEBUG_LL /* is not set */
bad_nand_read: 
	ldr	r0, STR_FAIL
	ldr	r1, SerBase
	bl	PrintWord
1:	b	1b		@ infinite loop 
				@ 我认为应把这条指令放到#ifdef...#endif之外
#endif
	
ok_nand_read:
#ifdef CONFIG_DEBUG_LL	/* is not set */
	ldr	r0, STR_OK
	ldr	r1, SerBase
	bl	PrintWord
#endif

	@ verify
	mov	r0, #0
	ldr	r1, =0x33f00000	@VIVI_RAM_BASE
	mov	r2, #0x400	@ 4 bytes * 1024 = 4K-bytes
go_next:
	ldr	r3, [r0], #4
	ldr	r4, [r1], #4
	teq	r3, r4
	bne	notmatch
	subs	r2, r2, #4
	beq	done_nand_read	
	bne	go_next
notmatch:
#ifdef CONFIG_DEBUG_LL	/* is not set */
	sub	r0, r0, #4
	ldr	r1, SerBase
	bl	PrintHexWord
	ldr	r0, STR_FAIL
	ldr	r1, SerBase
	bl	PrintWord
#endif
1:	b	1b
done_nand_read:

#ifdef CONFIG_DEBUG_LL	/* is not set */
	ldr	r0, STR_OK
	ldr	r1, SerBase
	bl	PrintWord
#endif

	mov	pc, r10

这段程序非常简单,哪怕是完全不会arm汇编也基本能稍微看出一点眉目来

  1. 保存返回地址(参见APCS)
  2. 初始化Nand Flash(需要严格按照对应Nand Flash的datasheet)
  3. 建立C运行环境(建立栈帧)
  4. 跳转到nand_read_ll,其中参数1为vivi在ram中的起始地址,参数2为地址0(Nand Flash所对应的起始地址)
  5. 校验
  6. 如果校验成功,根据已经保存的返回地址返回

移植工作

有了以上原理性的东西,我们实际动手起来就方便多了
修改cpu/arm920t/start.S文件
在setup_stack上面加入(因为后面的代码是建立堆栈,清楚bss,跳转到uboot的C入口)

#ifdef CONFIG_S3C2410_NAND_BOOT
	bl	copy_myself
#endif /* CONFIG_S3C2410_NAND_BOOT */  

我们需要在这之前先将整个uboot载入到内存当中
参照vivi中的代码,我们加入这样一段代码

#ifdef CONFIG_S3C2410_NAND_BOOT

copy_myself:
	mov	r10, lr				@save return address to r10
	ldr	sp, DW_STACK_START 	
	mov	fp, #0 				
	bl	NF_Init 			

	
	ldr	r0, =UBOOT_RAM_BASE 		
	mov	r1, #0x0		
	mov	r2, #0x30000		@192K(size of uboot)
	bl	nand_read_whole		
						 
	tst	r0, #0x0		
	beq	ok_nand_read		
1:	b	1b				

/* Verify */
ok_nand_read:
	mov	r0, #0x00000000 
	ldr	r1, =UBOOT_RAM_BASE
	mov	r2, #0x400	
go_next:
	ldr	r3, [r0], #4
	ldr	r4, [r1], #4
	teq	r3, r4
	bne	notmatch
	subs	r2, r2, #4
	beq	done_nand_read
	bne	go_next
notmatch:
1:	b	1b
done_nand_read:
	mov	pc, r10		
#endif    
	
DW_STACK_START:
	.word	STACK_BASE+STACK_SIZE-4  

代码结构和vivi中的完全一样,只不过我们将Nand Flash初始化部分改成了C语言实现
这段代码中调用了两个外部C函数,NF_Init和nand_read_whole
我们需要在board/xxx2410中加入对应的C实现

#include <common.h>
#include <s3c2410.h>
#include <config.h>

/*s3c2410 datasheet P216*/
#define rNFCONF (*(volatile unsigned int *)0x4e000000)
#define rNFCMD (*(volatile unsigned char *)0x4e000004)
#define rNFADDR (*(volatile unsigned char *)0x4e000008)
#define rNFDATA (*(volatile unsigned char *)0x4e00000c)
#define rNFSTAT (*(volatile unsigned int *)0x4e000010)
#define rNFECC (*(volatile unsigned int *)0x4e000014)
#define rNFECC0 (*(volatile unsigned char *)0x4e000014)
#define rNFECC1 (*(volatile unsigned char *)0x4e000015)
#define rNFECC2 (*(volatile unsigned char *)0x4e000016)

/* Nand Flash ops */
#define NF_CMD(cmd) {rNFCMD=cmd;}
#define NF_ADDR(addr) {rNFADDR=addr;}
#define NF_nFCE_L() {rNFCONF&=~(1<<11);}
#define NF_nFCE_H() {rNFCONF|=(1<<11);}
#define NF_RSTECC() {rNFCONF|=(1<<12);}
#define NF_RDDATA() (rNFDATA)
#define NF_WRDATA(data) {rNFDATA=data;}
#define NF_WAITRB() {while(!(rNFSTAT&(1<<0)));}

static void NF_Reset(void)
{
	int i;
	NF_nFCE_L();		/* Enable */ 
	NF_CMD(0xFF);		/* Reset Command */
	for(i=0;i<10;i++);	/* Delay 100ns */
	NF_WAITRB();		/* wait for busy */
	NF_nFCE_H();		/* Disable */
}

void NF_Init(void)
{
	/*
	 * initial value is 0xf830 
	 * copy form vivi			*/
	rNFCONF=0xF830;
	NF_Reset();
}

int nand_read_whole(unsigned char *buf, unsigned long start_addr, int size)
{
	int i, j;
	/* align with nand block */
	if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) {
		return 1;
	}

	NF_nFCE_L();
	for(i=0; i<10; i++);	/* delay 100ns */
	i = start_addr;
	while(i < start_addr + size) {
		/* Zone A */
		rNFCMD = 0;
		/* Generate 4 cycle address */
		rNFADDR = i & 0xff;
		rNFADDR = (i >> 9) & 0xff;
		rNFADDR = (i >> 17) & 0xff;
		rNFADDR = (i >> 25) & 0xff;
		NF_WAITRB();
		/* Read a whole page */
		for(j=0; j < NAND_SECTOR_SIZE; j++, i++) {
			*buf = (rNFDATA & 0xff);
			buf++;
		}
	}
	NF_nFCE_H();
	return 0;
}

记得将对应的文件加入Makefile的依赖中。

后续

至此便完成了大部分的工作,我们还需要在相应的板卡配置中稍作修改
加入:

#define CONFIG_S3C2410_NAND_BOOT 1
#define STACK_BASE 0x31f00000
#define STACK_SIZE 0x8000
#define UBOOT_RAM_BASE 0x31f80000
#define CONFIG_CMD_NAND
#define CONFIG_CMD_PING
#define CONFIG_CMD_ENV

修改 CFG_PROMET 为"XXX2410: "
修改 PHYS_SDRAM_1_SIZE 为0x02000000 (根据自己板子情况)
在文件的最后加入

#define CFG_ENV_SIZE  0x4000 /* Total Size of Environment Sector */
#define CFG_ENV_OFFSET  (0x80000-0x4000)
#define CONFIG_ARCH_SMDK2410 1
#define CFG_NAND_BASE 0x4E000000  /* Nand Flash控制器在SFR区中起始寄存器地址 */
#define CFG_MAX_NAND_DEVICE 1   /* 支持的最在Nand Flash数据 */
#define SECTORSIZE 512    /* 1页的大小 */
#define NAND_SECTOR_SIZE SECTORSIZE
#define NAND_BLOCK_MASK (NAND_SECTOR_SIZE - 1) /* 页掩码 */
#define ADDR_COLUMN 1    /* 一个字节的Column地址 */
#define ADDR_PAGE 2    /* 3字节的页块地址, A9A25*/
#define ADDR_COLUMN_PAGE 3   /* 总共4字节的页块地址 */
#define NAND_ChipID_UNKNOWN 0x00  /* 未知芯片的ID号 */
#define NAND_MAX_FLOORS 1
#define NAND_MAX_CHIPS 1
/* Nand Flash命令层底层接口函数 */
#define WRITE_NAND_COMMAND(d, adr) do {rNFCMD = d;} while(0)
#define WRITE_NAND_ADDRESS(d, adr) do {rNFADDR = d;} while(0)
#define WRITE_NAND(d, adr) do {rNFDATA = d;} while(0)
#define READ_NAND(adr) (rNFDATA)
#define NAND_WAIT_READY(nand) {while(!(rNFSTAT&(1<<0)));}
#define NAND_DISABLE_CE(nand) {rNFCONF |= (1<<11);}
#define NAND_ENABLE_CE(nand) {rNFCONF &= ~(1<<11);}
/* 下面一组操作对Nand Flash无效 */
#define NAND_CTL_CLRALE(nandptr)
#define NAND_CTL_SETALE(nandptr)
#define NAND_CTL_CLRCLE(nandptr)
#define NAND_CTL_SETCLE(nandptr)

/* 允许Nand Flash写校验 */
#define CONFIG_MTD_NAND_VERIFY_WRITE 1

至此,移植完成

你可能感兴趣的:(工作,cmd,command,Flash,makefile,delay)