移植u-boot-2016.11到JZ2440(三:修改源码之实现NOR启动与NAND启动)

目录

3. 修改源码之实现从NOR启动与NAND启动
    3.1 前言
    3.2 实现从NOR启动
        3.2.1 修改设置时钟
            3.2.1.1 CLKDIVN寄存器
            3.2.1.2 总线模式
            3.2.1.3 MPLL寄存器
            3.2.1.4 修改源码
        3.2.2 修改初始化存储控制器参数
        3.2.3 修改串口波特率相关内容
            3.2.3.1 分析串口
            3.2.3.2 修改源码
            3.2.3.3 测试
    3.3 实现从NAND启动
        3.3.1 去掉pie选项与checkarmreloc选项
        3.3.2 添加init.c文件
        3.3.3 修改启动流程
        3.3.4 修改链接地址
        3.3.5 修改重定位地址
        3.3.6 修改链接脚本
        3.3.7 测试NAND Flash启动


3. 修改源码之实现从NOR启动与NAND启动

3.1 前言

    通过移植u-boot-2016.11到JZ2440(二:分析启动流程)uboot启动流程的分析,我们知道源码做了许多工作,回顾一下流程如下:
      1. 设置异常向量表
      2. 设置SVC管理模式、关看门狗、关中断、设置时钟频率
      3. 禁用Cache和MMU、初始化存储控制器
      4. 设置栈
      5. 第一阶段C函数调用
          5.1 调用board_init_f_alloc_reserve函数
          5.2 调用board_init_f_init_reserve函数
          5.3 调用board_init_f函数
      6. 重新设置栈
      7. uboot重定位
      8. 异常向量表重定位
      9. 清bss段、调用第二阶段C函数board_init_r

    修改代码前,首先了解NOR启动与NAND启动的概念:
    NOR启动:上电后NOR Flash被映射到0x00000000地址(就是nGCS0,不需要片内SRAM辅助,片内SRAM的起始地址为0x40000000),然后CPU0x00000000开始运行(在NOR Flash上运行)
    NAND启动:上电后CPU自动将NAND Flash中的前4K代码拷贝到SRAM中,SRAM被映射为0x00000000地址,CPU0x00000000开始运行(在SRAM上运行)
    我们只需修改少量单板相关代码就能将该uboot下载到NOR Flash上启动,这是没有问题的,但是想要在NAND Flash上运行,就会涉及一个严重问题:ubootNAND Flash启动,CPU自动将uboot4K代码拷贝到片内RAM(此时片内RAM的基地址从0开始)中运行,前4步的代码量很小,完全可以存放进这前4K的代码里,但是第4步调用第一阶段C函数时(暂且不考虑位置相关码),这部分的代码基本不在前4K代码以内,执行到这里就会出错NOR Flash上能直接运行代码,完全不用担心该问题)
    所以想要在NAND Flash上启动uboot,就需要在uboot前4K代码里将NAND Flashuboot的代码拷贝到SDRAM中,也就是前4K代码里就要完成重定位(将NAND Flash内的uboot拷贝到SDRAM中)并跳转到SDRAM中去执行剩余代码,而源码重定位的信息又是通过调用第一个C函数board_init_f计算得到的,但是我们又不能先调用board_init_f(不在4K代码内)再重定位为了让uboot能同时在NOR Flash也能在NAND Flash上启动,所以启动流程的后半部分我们基本自己来实现。

3.2 实现从NOR启动

    在移植u-boot-2016.11到JZ2440(二:分析启动流程)中我们已经创建好了单板相关文件,接下来按照启动分析流程进行修改源码实现从NOR Flash启动uboot

3.2.1 修改设置时钟

3.2.1.1 CLKDIVN寄存器

    在arch/arm/cpu/arm920t/start.S文件中,uboot源码只设置了CLKDIVN寄存器,查看S3C2440A芯片手册第七章Clock & Power Management
有如下图说明:
   
    默认FCLK120MHz,则HDIVNPDIVN都不为0,这里我们设置CLKDIVN寄存器的值为5,也就是FCLK:HCLK:PCLK=1:4:8

3.2.1.2 总线模式

    同时手册中还有如下说明:
   
    表示S3C2440不支持同步总线模式,我们必须改为异步模式,那么我们必须在时钟设置上加上那段代母,修改CPU的总线模式。

3.2.1.3 MPLL寄存器

    datesheet中还有如下框图:
   
    我们CPU的启动是在normal mode中,normal mode说明如下:
   
    MPLL为锁相环输出频率 ,用来给MCU提供频率,进而再给CPU的各个模块供应频率。具体可以看看datesheet中的Clock Generator Block Diagram框图。尽管MPLL仅仅只是在一个reset后启动,但是直到软件对MPLLCON寄存器写一个有效的设置之后,MPLL才作为系统时钟的输出。在有效设置之前,从外部晶振源(XTlPll或EXTCLK)获得的时候将直接用于系统时钟。哪怕用户不想要改变MPLLCON寄存器的值,用户都应该写一个相同的值进MPLLCON寄存器。
    而我们的源码中,在时钟设置后,就直接跳到cpu_init_crit去执行,在其中又跳进lowlevel_init中执行SDRAM的初始化,并且注释中HCLK的默认频率为60MHZ,此时的HCLK是依赖于FCLK也就是MPLL,因此我们必须添加上MPLL的设置。如下图datesheet中的说明:
   
   
    这里我们设置MPLL400MHZ,所以MDIV设为0x5cPDIV设为1,SDIV设为1。

3.2.1.4 修改源码

    将以上3点修改到源码,同时再启动ICASHE。下面修改源码,将以下内容(arch/arm/cpu/arm920t/start.S文件中)
   
    改为:

    /* 设置时钟 */
	ldr r0, =0x4c000014
	mov r1, #0x05;			  // FCLK:HCLK:PCLK=1:4:8
	str r1, [r0]

	/* 如果HDIVN非0,CPU的总线模式应该从“fast bus mode”变为“asynchronous bus mode” */
	mrc	p15, 0, r1, c1, c0, 0		/* 读出控制寄存器 */ 
	orr	r1, r1, #0xc0000000			/* 设置为“asynchronous bus mode” */
	mcr	p15, 0, r1, c1, c0, 0		/* 写入控制寄存器 */

#define S3C2440_MPLL_400MHZ     ((0x5c<<12)|(0x01<<4)|(0x01))

	/* MPLLCON = S3C2440_MPLL_400MHZ,FCLK=PLL=400MHZ */
	ldr r0, =0x4c000004
	ldr r1, =S3C2440_MPLL_400MHZ
	str r1, [r0]
    
        /* 启动ICACHE */
	mrc p15, 0, r0, c1, c0, 0	@ read control reg
	orr r0, r0, #(1<<12)
	mcr	p15, 0, r0, c1, c0, 0   @ write it back

    由于后面会调用board_init_f()函数里面调用init_sequence_f数组里的board_early_init_f函数里面又设置了系统时钟,这里已经设置好了,所以屏蔽board_early_init_f()函数里的时钟设置,如下(board/samsung/jz2440/jz2440.c文件中)
   

3.2.2 修改初始化存储控制器参数

    修改内存控制寄存器默认参数,将以下内容(board/samsung/jz2440/lowlevel_init.S文件)

SMRDATA:
    .word (0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(B7_BWSCON<<28))
    .word ((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC))
    .word ((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC))
    .word ((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC))
    .word ((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC))
    .word ((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC))
    .word ((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC))
    .word ((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN))
    .word ((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN))
    .word ((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Trc<<18)+(Tchr<<16)+REFCNT)
    .word 0x32
    .word 0x30
    .word 0x30

    改为:

SMRDATA:
	.long 0x22011110	 //BWSCON
	.long 0x00000700	 //BANKCON0
	.long 0x00000700	 //BANKCON1
	.long 0x00000700	 //BANKCON2
	.long 0x00000700	 //BANKCON3  
	.long 0x00000740	 //BANKCON4
	.long 0x00000700	 //BANKCON5
	.long 0x00018005	 //BANKCON6
	.long 0x00018005	 //BANKCON7
	.long 0x008C04F4	 // REFRESH
	.long 0x000000B1	 //BANKSIZE
	.long 0x00000030	 //MRSRB6
	.long 0x00000030	 //MRSRB7

3.2.3 修改串口波特率相关内容

3.2.3.1 分析串口

    此时如果重新编译烧写ubootNOR Flash运行会输出乱码,是由于串口设置问题,串口是在调用board_init_f()函数里面调用init_sequence_f数组里的serial_init()函数进行串口设置的,serial_init()函数如下(drivers/serial/serial_s3c24x0.c中)
   

    返回get_current()->start()函数,首先看get_current()函数返回什么(drivers/serial/serial_s3c24x0.c中)
   
    ... ...
   
    serial_current未进行设置,所以get_current()函数返回的是default_serial_console函数,该函数代码如下(drivers/serial/serial_s3c24x0.c中)
   
    在include/configs/jz2440.h文件中默认定义了CONFIG_SERIAL1宏,所以最终得到的是serial_device结构体类型的s3c24xx_serial0_device,该结构被INIT_S3C_SERIAL_STRUCTURE赋值,INIT_S3C_SERIAL_STRUCTURE宏定义如下(drivers/serial/serial_s3c24x0.c中)
   
    以上的“##”连接符在编译时被去掉,连接符内的变量被替代,也就是会变成如下:
   
所以最前面get_current()->start()函数实际调用的是s3serial0_init()函数,该函数直接返回serial_init_dev()函数,serial_init_dev()函数代码如下:

static int serial_init_dev(const int dev_index)
{
        /* 得到ULCON0控制寄存器基地址0x50000000 */
	struct s3c24x0_uart *uart = s3c24x0_get_base_uart(dev_index);

	/* 使能FIFO, 清空Tx/Rx的FIFO缓冲区 */
	writel(0x07, &uart->ufcon);
	writel(0x0, &uart->umcon);

	/* Normal,No parity,1 stop,8 bit */
	writel(0x3, &uart->ulcon);
	/*
	 * tx=level,rx=edge,disable timeout int.,enable rx error int.,
	 * normal,interrupt or polling
	 */
	writel(0x245, &uart->ucon);

	_serial_setbrg(dev_index);    /*设置波特率*/

	return (0);
}

    该函数首先得到得到ULCON0控制寄存器基地址0x50000000,然后设置相关寄存器(配置FIFO、停止位、校验位等),最后调用_serial_setbrg()函数,代码如下(drivers/serial/serial_s3c24x0.c中)

void _serial_setbrg(const int dev_index)
{
	struct s3c24x0_uart *uart = s3c24x0_get_base_uart(dev_index);
	unsigned int reg = 0;
	int i;

	/* value is calculated so : (int)(PCLK/16./baudrate) -1 */
	reg = get_PCLK() / (16 * gd->baudrate) - 1;

	writel(reg, &uart->ubrdiv);
	for (i = 0; i < 100; i++)
		/* Delay */ ;
}

    由于串口时钟使用的是PLCK,其中通过get_PCLK()函数获得PLCK时钟,get_PCLK()函数如下:
   
    由于之前设置的CLKDIVN寄存器为5,所以get_PCLK()函数返回get_HCLK()/2,按照前面的CLKDIVN寄存器设置,get_HCLK()返回的应该是get_FCLK()/4,但是CONFIG_S3C2440宏却没有定义,执行的是else的代码,所以需要我们添加CONFIG_S3C2440宏。

3.2.3.2 修改源码

    将以下内容(include/configs/jz2440.h文件中)
   
    改为:
   

3.2.3.3 测试

    为了方便重新编译,我编写了如下脚本(remake.sh)

#!/bin/bash  
echo "Clean Configuration File..." 
make distclean 
echo "Clean Obj..." 
make clean 
echo "Load Configuration File..." 
make jz2440_defconfig 
echo "make..." 
make

    重新编译时在u-boot.2016.11根目录下执行./remake.sh即可(没有权限的话执行sudo chmod +x remake.sh
    烧写试验(使用韦东山老师的旧uboot进行烧写快一点)
      1. 使用韦东山老师的旧u-boot.bin,下载编译后的新u-boot.bin到norflash开发板拨置nor启动,输入q进入命令行;
      2. 输入 usb 1 30000000(使用usb下载到SDRAM上,1表示一直下载,直到完成)
      3. 使用dnw软件下载新u-boot.bin;(传输新的u-boot.bin给usb)
      4. 输入 protect off all(关闭nor的写保护)
      5. 输入 erase 0 8ffff(新u-boot.bin比较大,有522k左右,擦除nor上的 0~8FFFF地址内容,擦除长度8FFF==576kb,要大于u-boot.bin才行)
      6. 输入 cp.b 30000000 0 90000(将SDRAM上的u-boot.bin,拷贝到nor flash 0地址上)

    重启开发板,此时串口输出如下所示:
   
    可以看到正确输出信息并且进入命令行了。
    PS:此时还不能修改include/configs/jz2410.h中的指定链接地址的宏(CONFIG_SYS_TEXT_BASE,默认为0),因为调用C函数board_init_f时调用init_sequence_f全局数组里的函数,这是全局变量,里面保存的是链接地址,而此时代码又没有拷贝到对应链接地址去(也就是重定位),跳到链接地址就会导致错误此时宏CONFIG_SYS_TEXT_BASE=0时链接地址与运行地址才相同)。

3.3 实现从NAND启动

3.3.1 去掉pie选项与checkarmreloc选项

    uboot源码在编译执行arm-linux-ld时加了"-pie"选项,那么程序中的变量就会被抽出来放到代码段后面的"*(.rel*)"段,而这些变量的地址肯定超过了4K,无法再访问了。所以我们要去除这个pie选项,执行grep  "\-pie" * -nR查找如下:
   
    修改arch/arm/config.mk文件去掉pie选项如下:
   
    此时重新编译会有如下错误:
   
    这是一个检查ARM相对位置的选项,因为我们已经去掉了pie选项,所以我们也要把这个选项去掉,执行grep  "checkarmreloc" * -nR如下:
   
    同样是修改arch/arm/config.mk文件去掉checkarmreloc选项如下:
   

3.3.2 添加init.c文件

    添加init.c文件到board/samsung/jz2440目录下,代码如下:

/* NAND FLASH控制器 */
#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 char *)0x4E000020))

void nand_read_ll(unsigned int addr, unsigned char *buf, unsigned int len);
void nand_read0(unsigned int addr, unsigned char *buf, unsigned int len);

int isBootFromNorFlash(void)
{
	volatile int *p = (volatile int *)0;
	int val;

	val = *p;
	*p = 0x12345678;
	if (*p == 0x12345678)
	{
		/* 写成功, 是nand启动 */
		*p = val;
		return 0;
	}
	else
	{
		/* NOR不能像内存一样写 */
		return 1;
	}
}

void copy_code_to_sdram(unsigned char *src, unsigned char *dest, unsigned int len)
{	
	int i = 0;
	
	/* 如果是NOR启动 */
	if (isBootFromNorFlash())
	{
		while (i < len)
		{
			dest[i] = src[i];
			i++;
		}
	}
	else
	{
		nand_read_ll((unsigned int)src, dest, len);
	}
}

/* 清bss段 */
void clear_bss(void)
{
	extern int __bss_start, __bss_end;    //bss段的开始地址与结束地址
	int *p = &__bss_start;
	
	for (; p < &__bss_end; p++)    /* 循环清0 */
		*p = 0;
}

/* 初始化NAND Flash */
void nand_init_ll(void)
{
#define TACLS   0
#define TWRPH0  1
#define TWRPH1  0
	/* 设置时序 */
	NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);
	/* 使能NAND Flash控制器, 初始化ECC, 禁止片选 */
	NFCONT = (1<<4)|(1<<1)|(1<<0);	
}

static void nand_select(void)
{
	NFCONT &= ~(1<<1);	
}

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

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_page(unsigned int page)
{
	volatile int 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_col(unsigned int col)
{
	volatile int i;

	NFADDR = col & 0xff;
	for (i = 0; i < 10; i++);
	NFADDR = (col >> 8) & 0xff;
	for (i = 0; i < 10; i++);
}


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

static unsigned char nand_data(void)
{
	return NFDATA;
}

static int nand_bad(unsigned int addr)
{
	unsigned int col  = 2048;
	unsigned int page = addr / 2048;
	unsigned char val;

	/* 1. 选中 */
	nand_select();
	
	/* 2. 发出读命令00h */
	nand_cmd(0x00);
	
	/* 3. 发出地址(分5步发出) */
	nand_col(col);
	nand_page(page);
	
	/* 4. 发出读命令30h */
	nand_cmd(0x30);
	
	/* 5. 判断状态 */
	nand_wait_ready();

	/* 6. 读数据 */
	val = nand_data();
	
	/* 7. 取消选中 */		
	nand_deselect();

	if (val != 0xff)
		return 1;  /* bad blcok */
	else
		return 0;
}

void nand_read_ll(unsigned int addr, unsigned char *buf, unsigned int len)
{
	int col = addr % 2048;
	int i = 0;
		
	while (i < len)
	{
		if (!(addr & 0x1FFFF) && nand_bad(addr)) /* 一个block只判断一次 */
		{
			addr += (128*1024);  /* 跳过当前block */
			continue;
		}

		/* 1. 选中 */
		nand_select();
		
		/* 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();
	}
}

    该文件函数说明如下:

1. isBootFromNorFlash()函数
    1.1 对于从NAND Flash启动的情况,其开始4KB的代码会被自动复制到CPU内部4K RAM中,这4K RAM被映射为0地址,此时读写0地址就是读写RAM,因此可以直接读写0地址。
    1.2 对于从NOR Flash启动的情况,NOR Flash的开始地址即为0,此时读写0地址就是读写NOR Flash,因此必须通过一定的命令序列才能读写0地址。
    所以可以根据这两点来分辨是从NAND Flash还是NOR Flash启动:向地址0写入一个数据,然后读出来,如果发现写入失败的就是NOR启动,否则就是NAND启动
2. copy_code_to_sdram()函数
     不使用源码的重定位,使用该函数进行重定位,不需要进行修改动态链接地址,比较简单,首先判断uboot启动方式,然后将对应代码拷贝到指定地址去(后面会通过指定相同的链接地址与重定位地址,然后调用该函数将uboot代码拷贝到重定位地址)。
3. clear_bss()函数
    首先定义指针指向bss段的开始地址(链接地址)__bss_start,将该地址到bss段的结束地址(链接地址)__bss_end全部清0。__bss_start__bss_end是在链接文件u-boot.lds中的标号。
4. NAND Flash相关函数
    包含NAND Flash的设置、选中函数、发命令函数、发地址函数、判断状态函数、读函数等。

    再修改board/samsung/jz2440目录下的Makefile,修改如下:
   

3.3.3 修改启动流程

    在3.1 前言里提到,对于NAND启动时不能按照源码的启动流程,在调用C函数之前要先重定位(C函数不在前4k代码内),所以修改arch/arm/lib/crt0.S文件,在如下C函数代码调用之前重定位:
   
    也就是修改成如下(arch/arm/lib/crt0.S文件)

	/* 初始化NAND Flash */
	bl nand_init_ll    /* 跳转到borad/samsung/jz2440/init.c 中执行nand_init_ll函数 */

	/* 重定位 */
	mov r0, #0                      /* uboot源地址 */
	ldr r1, =(CONFIG_SYS_TEXT_BASE)	/* 拷贝uboot到目的地址也就是链接地址CONFIG_SYS_TEXT_BASE上 */
	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 clear_bss                    /* 清除bss, 和下面的清BSS可二选一 */
#endif

	ldr pc, =call_board_init_f      /* 跳到SDRAM中执行剩下的代码 */
	
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

    再在将后面重定位部分去掉,如下:
   

3.3.4 修改链接地址

    由于没有使用源码的动态修改链接地址代码,所以在编译U-Boot前修改链接地址,修改宏CONFIG_SYS_TEXT_BASE即可,修改如下(include/configs/jz2440.h文件中):
   

3.3.5 修改重定位地址

    源码是通过在board_init_f函数中计算得到的重定位地址,我们这里重定位地址必须与链接地址一样,所以修改board_init_f()函数调用init_sequence_f数组里的reserve_uboot函数,将最终重定位地址设为链接地址CONFIG_SYS_TEXT_BASE,修改如下(common/board_f.c文件中)
   

3.3.6 修改链接脚本

    由于NAND启动时只把前4K代码拷贝到片内RAM中,所以我们要保证程序跳到SDRAM之前的代码都要在uboot的前4K代码内,也就是把start.S、init.c(实现重定位、清bss等)、lowlevel_init.S(实现初始化SDRAM)、crt0.S等文件的代码段编译时放在u-boot.bin的最前面,编译时会在board/samsung/jz2440目录下生成一个built-in.o文件,该文件是将jz2440单板目录下的所有*.c、*S文件经过编译后生成的库文件,同理在arch/arm/lib目录下也生成一个built-in.o文件,只需要将这两个库文件的代码段与vectors段、start.o的代码段放在uboot的最前面,添加代码“board/samsung/jz2440/built-in.o (.text*)”与"arch/arm/lib/built-in.o (.text*)"到arch/arm/cpu/u-boot.lds文件(编译后顶层目录的u-boot.lds也会更新),修改如下:
       

    此时重新编译成功。(可以通过objdump -h built-in.o查看对应.o文件的代码段大小,上面所说的代码段加起来都小于4K,built-in.o是同目录下的所有文件的库文件(可能包含前4K代码没有用到的文件),如果built-in.o代码段太大,可以把重要文件单独编译(例如修改arch/arm/lib/Makefile为extra-y += vectors.o crt0.o),再将arch/arm/lib/crt0.o (.text*)  arch/arm/lib/vectors.o (.text*)添加到其他代码段之前即可)

3.3.7 测试NAND Flash启动

    烧写试验(使用韦东山老师的旧uboot进行烧写快一点)
      1. 使用韦东山老师的旧u-boot.bin,下载到norflash开发板拨置nor启动,输入q进入命令行;
      2. 输入 usb 1 30000000(使用usb下载到SDRAM的30000000上,1表示一直下载,直到完成)
      3. 使用dnw软件下载编译好的u-boot.bin;(传输新的uboot.bin给usb)
      4. 输入 nand erase 0 80000(此时的uboot只有400多KB了,擦除NAND Flash的0~80000地址)
      5. 输入 nand write 30000000 0 80000(将SDRAM上的新的uboot.bin,拷贝到NAND Flash 0地址上)

    开发板拨置NAND启动,此时串口输出信息如下所示:
   
    NAND启动成功。

  • 6
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值