四、移植u-boot-2016.03到Jz2440之修改代码支持NAND启动

4. 移植u-boot-2016.03之修改代码支持NAND启动

    对于Jz2440开发板,它不仅支持NOR Flash启动,还支持从NAND Flash启动。那么NOR Flash启动与NAND Flash启动有什么区别呢?NOR 启动,上电后NOR Flash被映射到0x00000000地址,然后CPU从0x00000000开始运行;NAND启动,上电后CPU自动将NAND Flash中的前4K代码拷贝到SRAM,SRAM被映射为0x00000000地址,CPU从0x00000000开始运行。uboot的大小远远大于4k,因此需要在代码的前4k中完成代码的重定位,即把NAND Flash的代码拷贝到SDRAM中。关于代码的重定位知识,可以看韦东山老师的博客S3c2440代码重定位详解

4.1 去"-pie"、"checkarmreloc"选项

    原来的代码在链接时加了”-pie”选项,使得u-boot.bin里多了*(.rel*)段,程序非常大,不利于从NAND启动(重定位之前的启动代码应该少于4K),因此我们需要去掉**"-pie"**选项。
(1) 在u-boot 的顶层目录中搜索"pie":grep "\-pie" * -nR,搜索结果如下:
在这里插入图片描述
从上图可以发现,"pie"选项在arch/arm/config.mk的第83行,那么我们进去把它注释掉,如下图所示:
在这里插入图片描述
然后执行如下命令重新编译:

make distclean
make jz2440_defconfig
make

最后发现如下错误:
在这里插入图片描述
checkarmreloc正如其名,它是检查arm相对位置的选项,可能是没找到arm,所以出错,对程序整体没有影响,注释掉就不检查了,编译能通过;在uboot顶层目录搜索checkarmrelocgrep "checkarmreloc" * -nR,搜索结果如下:
在这里插入图片描述
从上图可以发现,"checkarmreloc"选项在arch/arm/config.mk的第105行,那么我们进去把它注释掉,如下图所示:
在这里插入图片描述
然后重新编译就成功编译通过了。

4.2 添加init.c程序

(1) 把之前编写好的init.c文件放到board/samsung/jz2440目录,init.c文件的代码如下:

/*那么如何判断是NOR启动还是NAND启动呢? 可以利用NOR的特点:
 *1.NOR可以像内存一样读,但不可以像内存一样写;
 *2.可以通过向0地址写数据已区分是NAND启动还是NOR启动;
 *(因为NAND启动时,0地址是RAM,可读可写;但NOR启动时,0地址是NOR FLASH,可读不可写)
 *返回值:1:Nor启动; 0:NAND启动
 */
#define NFCONF  (*((volatile unsigned long *)0x4E000000))
#define NFCONT  (*((volatile unsigned long *)0x4E000004))
#define NFCMMD  (*((volatile unsigned char *)0x4E000008))
#define NFADDR  (*((volatile unsigned char *)0x4E00000c))
#define NFDATA  (*((volatile unsigned char *)0x4E000010))
#define NFSTAT  (*((volatile unsigned long *)0x4E000020))

/* GPIO */
#define GPHCON              (*(volatile unsigned long *)0x56000070)
#define GPHUP               (*(volatile unsigned long *)0x56000078)

/* UART registers*/
#define ULCON0              (*(volatile unsigned long *)0x50000000)
#define UCON0               (*(volatile unsigned long *)0x50000004)
#define UFCON0              (*(volatile unsigned long *)0x50000008)
#define UMCON0              (*(volatile unsigned long *)0x5000000c)
#define UTRSTAT0            (*(volatile unsigned long *)0x50000010)
#define UTXH0               (*(volatile unsigned char *)0x50000020)
#define URXH0               (*(volatile unsigned char *)0x50000024)
#define UBRDIV0             (*(volatile unsigned long *)0x50000028)

#define TXD0READY   (1<<2)


/* NAND flash 设置时序(需要对比s3c2440与NAND手册的NAND时序)
 *
 */
void nand_init_ll(void)
{
    
    
	/*设置NANDFlash时序*/
#define TACLS 0
#define TWRPH0 1
#define TWRPH1 0
    NFCONF &= ~((3<<12)|(7<<8)|(7<<4));
	NFCONF |= (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);

	/*使能NANDflash 控制器,
	 *禁止片选(开发板没正式使用片选,避免错误的操作)
	 *初始化 ECC 编码器/译码器*/
	NFCONT = (1<<0)|(1<<1)|(1<<4);
}

static void nand_cmd(unsigned char cmd)
{
    
    
    volatile int i;
    NFCMMD = cmd;
    for(i = 0; i < 10; i++);/*等待*/
}

static void nand_addr(unsigned int addr)
{
    
    
    unsigned int col = addr % 2048;
    unsigned int page = addr / 2048;
    volatile int i;
    
    NFADDR = col & 0xff;
    for(i = 0; i < 10; i++);/*等待*/
    NFADDR = (col >> 8) & 0xff;
    for(i = 0; i < 10; i++);/*等待*/
    NFADDR = page & 0xff;
    for(i = 0; i < 10; i++);/*等待*/
    NFADDR = (page >> 8) & 0xff;
    for(i = 0; i < 10; i++);/*等待*/
    NFADDR = (page >> 16) & 0xff;
    for(i = 0; i < 10; i++);/*等待*/
}

static void nand_wait_ready(void)
{
    
    
    while(!(NFSTAT & 0x01));
}

static unsigned char nand_data(void)
{
    
    
    return NFDATA;
}
static void nand_select(void)
{
    
    
    NFCONT &= ~(1<<1);
}

static void nand_deselect(void)
{
    
    
    NFCONT |= (1<<1);
}

void nand_read_ll(unsigned int addr, unsigned char *buf,unsigned int len)
{
    
    
    int col = addr % 2048;
    int i = 0;
     /*1.片选*/
    nand_select();
    while(i < len)
    {
    
    
        /*2.发出读命令00h*/
        nand_cmd(0x00);
        /*3.发出地址(分5个地址周期)*/
        nand_addr(addr);
        /*4.发出读命令30h*/
        nand_cmd(0x30);
        /*5.等待就绪(判断状态)*/
        nand_wait_ready();
        /*6.读数据*/
        for(; (col < 2048) && (i < len); col++)
        {
    
    
            buf[i] = nand_data();
            i++;
            addr++;
        }
        col = 0;
    }
        
    /*7.取消选中*/
    nand_deselect();
}

static int isBootFromNorFlash(void)
{
    
    
    volatile unsigned int *p = (volatile unsigned int*)0;
    unsigned int val;
    
    val = *p;
    *p  = 0x12345678;
    if(*p == val) /*写前写后值一样,证明无法向0地址写数据,是NOR启动*/
    {
    
    
        return 1;
    }else  /*否则是NAND启动*/
    {
    
    
        *p = val;  /*恢复数据*/
        return 0;
    }
        
}

void copy_code_to_sdram(unsigned char *src, unsigned char *dest,unsigned int len)
{
    
    
    unsigned int i=0;
    /*如果是NOR启动*/
    if(isBootFromNorFlash()) /*那么如何判断是NOR启动还是NAND启动呢? */ 
    {
    
                
        while(i < len)
        {
    
    
            dest[i] = src[i];
            i++;
        }
    }else /*否则是NAND启动*/
    {
    
    
        nand_init_ll();/*初始化NAND*/
        nand_read_ll((unsigned int )src,dest,len);
    }
}
/*c语言如何引用连接脚本的 __bss_start、__bss_end等变量呢?
 * extern int __bss_start,__bss_end;
 * int *p = &__bss_start;
 *
 */
void clean_bss(void)
{
    
    
    extern int __bss_start,__bss_end;
    int *p = &__bss_start;
    
    for(;p < &__bss_end;p++)
    {
    
    
        *p = 0;
    }
}

(2) 改board/samsung/jz2440目录下的Makefile,把init.c 文件编译进uboot:
在这里插入图片描述

4.3 修改uboot启动流程

(1) 从前面的u-boot-2012.04.01 移植笔记的第七节修改代码支持NAND启动可知,添加重定位函数是在调用board_init_f函数进行第一阶段初始化之前,并且在执行重定位函数之前要设置栈,如下图所示:
在这里插入图片描述
所以,参照上图,为u-boot-2016.03支持NAND启动添加重定位代码,所以修改arch/arm/lib/crt0.S文件,在调用board_init_f之前重定位,修改成如下:

ENTRY(_main)

/*
 * Set up initial C runtime environment and call board_init_f(0).
 */

#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)
    ldr sp, =(CONFIG_SPL_STACK)
#else
    ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)
#endif
#if defined(CONFIG_CPU_V7M) /* v7M forbids using SP as BIC destination */
    mov r3, sp
    bic r3, r3, #7
    mov sp, r3
#else
    bic sp, sp, #7  /* 8-byte alignment for ABI compliance */
#endif
	bl nand_init_ll  /*初始化NAND Flash*/
	mov r0,#0        /*uboot的源地址*/
	ldr r1, =(CONFIG_SYS_TEXT_BASE)  /*目的地址,即uboot的重定位地址*/
	ldr r2, =_start			/* 得到uboot的开始地址(链接地址) */
	ldr r3, =__bss_start		/* 得到bss段开始地址(链接地址) */
	sub r2, r3, r2		        /* 得到uboot大小 */
	bl copy_code_to_sdram           /* 拷贝代码到SDRAM,参数1:uboot源地址,参数2:目的地址,参数3:uboot大小 */
#if 0
	bl clean_bss   /*注释掉,使用原代码清空bss段*/
#endif   
	ldr pc,=call_board_init_f
	
/* Set stackpointer in internal RAM to call board_init_f */
call_board_init_f:
    mov r0, sp
    bl  board_init_f_alloc_reserve
    mov sp, r0
    /* set up gd here, outside any C code */
    mov r9, r0
    bl  board_init_f_init_reserve

    mov r0, #0
    bl  board_init_f

(2) 注释掉u-boot自身的重定位代码,如下图所示:
在这里插入图片描述

4.4 修改链接地址CONFIG_SYS_TEXT_BASE为0x33f00000

在前面的u-boot重定位函数copy_code_to_sdram中,使用到CONFIG_SYS_TEXT_BASE作为copy_code_to_sdram函数的目的地址,那么它在哪里被定义呢?它在include/configs/jz2440.h中被定义,如下图所示:
在这里插入图片描述
CONFIG_SYS_TEXT_BASE0x33f00000如下图所示:
在这里插入图片描述

4.5 修改uboot重定位地址

从之前的u-boot-2016.03启动过程分析可知, 源码是通过在reserve_uboot函数中计算得到的重定位地址,这里的链接地址和重定位地址必须一样。所以需要修改reserve_uboot函数的代码,,修改后的代码如下图图所示:
在这里插入图片描述

4.6 修改链接脚本: 把start.S, init.c, lowlevel.S等文件放在最前面

链接脚本为:arch/arm/cpu/u-boot.lds 最前面有下面一段代码:
在这里插入图片描述
修改为:
在这里插入图片描述
然后make重新编译,把u-boot.bin烧写到Jz2440开发板的NAND Flash,并设置NAND Flash启动,串口打印的信息如下:
在这里插入图片描述
从上图可知,u-boot-2016.03从NAND Flash启动成功。

猜你喜欢

转载自blog.csdn.net/qq_35031421/article/details/104436021
今日推荐