04.移植u-boot

Posted wade_linux

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了04.移植u-boot相关的知识,希望对你有一定的参考价值。


1.读readme获取信息
    1.1 由Building the Software可知,需修改顶层makefile,指定架构和编译器
    ifeq ($(HOSTARCH),$(ARCH))
    CROSS_COMPILE ?= arm-linux-
    endif

    ARCH = arm
    CROSS_COMPILE = arm-linux-
2.新建一个单板
    cd board/samsung/
 cp smdk2410 smdk2440 -rf
  cd ../../include/configs/
 cp smdk2410.h smdk2440.h
3.仿造smdk2410修改文件
    具体做法为
    grep "smdk2410" * -nR建立并修改相应的文件
4.实验并烧写,查看结果    
    make smdk2440_config
    make
5.下载到开发板后没有任何输出,阅读代码发现不足
    在u-boot-2016.11\arch\arm\cpu\arm920t\start.S出了问题没有对MPLL
    进行初始化/设置时钟,而是在board_init_f中board_early_init_f初始化
    的,但是之前是按照64MHz设置的,而现在的2440只工作在12MHz,这样是
    无法正常工作,所以应该把board_early_init_f里对MPLL的设置给注释掉,
    在start.S关闭看门狗后进行时钟的设置。
    5.2处理措施:
    #if 0
    /* FCLK:HCLK:PCLK = 1:2:4 */
    /* default FCLK is 120 MHz ! */
    ldr    r0, =CLKDIVN
    mov    r1, #3
    str    r1, [r0]
 #else
        /* 2. 设置时钟 400MHz */
        ldr r0, =0x4c000014
        //  mov r1, #0x03;            // FCLK:HCLK:PCLK=1:2:4, HDIVN=1,PDIVN=1
        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 */
        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
  #endif

6.
    ①依照上述下载到2440开发板,串口输出乱码,这表示2440工作了,这时候出现
乱码应该是串口方面的问题,在board_init_f函数中调用了init_sequence_f数组
里面有一个串口初始化serial_init,点进去,里面有个get_current函数,再进
里面default_serial_console函数,再进,在这个函数所在的c文件(serial_s3c24x0.c)
中有个_serial_setbrg函数中里面有个get_PCLK函数进去该函数中有这么一句
”#ifdef CONFIG_S3C2440”但是这个宏没有被定义,这个代表定义它就支持了2440,我们就
在include/configs/smdk2440.h中定义一下就可以了.然后再重新编译,编译出来的u-boot_04.bin
下载到2440中我们就可以看到串口打印出信息了
    ②改完后编译,烧写,串口有输出了,但是乱码,估计是波特率的问题。分析代码
board_init_r
    init_sequence_r
        initr_serial
            serial_initialize
                s3c24xx_serial_initialize
                    serial_register(&s3c24xx_serial0_device)
                        s3c24xx_serial0_device
                            INIT_S3C_SERIAL_STRUCTURE
                                s3serial##port##_setbrg
                                    serial_setbrg_dev
                                        _serial_setbrg
                                            get_PCLK
                                                get_HCLK(#ifdef CONFIG_S3C2440)

7.支持NOR FLASH
    board_init_r
        init_sequence_r
            initr_flash
                flash_init
                    if (!flash_detect_legacy(cfi_flash_bank_addr(i), i))
                    flash_get_size(cfi_flash_bank_addr(i), i);    
                            //用老方法检测是否识别出来,否则就用新方法
为什么老方法无法识别出nor flash?
flash_detect_legacy
    jedec_flash_match
        jedec_table//该数组里没有我们需要的nor flash的型号和参数,需要手动输入
        
        {                                                                                 
        .mfr_id     = (u16)MX_MANUFACT,                                               
        .dev_id     = 0x2249,                                                         
        .name       = "MX29LV160D",                                                   
        .uaddr      = {                                                               
            [1] = MTD_UADDR_0x0555_0x02AA /* x16 */  
         },                                                                            
        .DevSize    = SIZE_2MiB,                                                      
        .CmdSet     = P_ID_AMD_STD,                                          
        .NumEraseRegions= 4,                                                          
        .regions    = {                                                               
            ERASEINFO(0x10000, 31),                                                   
            ERASEINFO(0x08000, 1),                                                    
            ERASEINFO(0x02000, 2),                                                    
            ERASEINFO(0x04000, 1),                                                    
        }                                                                             
    },  
测试下norflash能否正确读写,用以下u-boot命令:
cp.b 0 30000000 80
cmp.b 0 30000000 80
发现读norflash没有问题。再用以下几条命令测试写norflash:
mw.b 30000000 12 3
protect off all
erase 0 ffff
cp.b 30000000 0 3
md.b 0 3;
发现也是121212;因此写norflash成功,至此u-boot已经支持JZ2440开发板的nor flash;

8.支持nand flash
    支持了norflash后,发现nandflash未识别出来,启动uboot显示NAND: 0 Byte。在代码
    中搜索"NAND:",定位到common目录中的board_r.c的initr_nand函数:
    nand_init
    nand_init_chip
        board_nand_init
            设置nand_chip结构体, 提供底层的操作函数
        nand_scan
            nand_scan_ident
                nand_set_defaults
                    chip->select_chip = nand_select_chip;
                    chip->cmdfunc = nand_command;
                    chip->read_byte = busw ? nand_read_byte16 : nand_read_byte;
                    
                nand_get_flash_type
                    chip->select_chip
                    chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
                            nand_command()  // 即可以用来发命令,也可以用来发列地址(页内地址)、行地址(哪一页)
                                chip->cmd_ctrl
                                        s3c2440_hwcontrol
                                
                    chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
                    *maf_id = chip->read_byte(mtd);
                    *dev_id = chip->read_byte(mtd);
board_nand_init函数主要与单板有关的初始化,uboot的开发人员已经把与单板无关的一些
    协议设置完成了,而把与单板有关的初始化单独列为一层,我们需要做的仅仅是把单板相关的
这一层移植即可。因此这里主要关注board_nand_init函数。我们的board_nand_init函数在
drivers/mtd/nand/s3c2410_nand.c中定义了。进入其中仔细分析代码,发现对nfconf寄存器
的初始化,2410的设置并不适用于2440,于是修改代码如下:
//cfg = S3C2410_NFCONF_EN;  
cfg |= S3C2410_NFCONF_TACLS(tacls - 1);  
cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);  
cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1);  
writel(cfg, &nand_reg->nfconf);  

#define S3C2410_NFCONF_TACLS(x)    ((x)<<12)  
#define S3C2410_NFCONF_TWRPH0(x)   ((x)<<8)  
#define S3C2410_NFCONF_TWRPH1(x)   ((x)<<4)  
往下看,后面设置了2410的nandflash的底层函数,其中selcet_chip被设置为NULL了,我们在
nand_scan里往下看,nand_scan_ident到nand_set_defaults,如果某个底层函数是空,则会
为其分配一个默认的函数,其中的默认的select_chip函数并不完整,不能用,并且后面的代码
调用到select_chip函数,因此这里需要我们自己写一个select_chip函数。
在s3c2410_nand.c中定义如下:

static void s3c24x0_nandselect(struct mtd_info *mtd, int chipnr)                      
 {                                                                                     
     struct s3c24x0_nand *nand_reg = s3c24x0_get_base_nand();                          
     switch (chipnr) {                                                                 
     case -1:                                                                          
     writel(readl(&nand_reg->nfcont) | (1 << 1),&nand_reg->nfcont);                    
         break;                                                                        
     case 0:                                                                           
     writel(readl(&nand_reg->nfcont) & ~(1 << 1),&nand_reg->nfcont);                   
         break;                                                                        
     default:                                                                          
         BUG();                                                                        
     }                                                                                 
 }  
在board_nand_init函数中设置select_chip函数

nand->select_chip = s3c24x0_nandselect;  
继续往下分析,发现s3c24x0_hwcontrol函数不适用于2440,修改如下:

static void s3c24x0_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)       
{                                                                                     
    struct nand_chip *chip = mtd->priv;                                               
    struct s3c24x0_nand *nand = s3c24x0_get_base_nand();                              
                                                                                     
    debug("hwcontrol(): 0x%02x 0x%02x\n", cmd, ctrl);                                 
                                                                                      
    if (ctrl & NAND_CTRL_CHANGE) {                                                    
        ulong IO_ADDR_W = (ulong)nand;                                                
                                                                                      
        if (!(ctrl & NAND_CLE))                                                       
            IO_ADDR_W |= S3C2410_ADDR_NCLE;//NFADDR                                   
        if (!(ctrl & NAND_ALE))                                                       
            IO_ADDR_W |= S3C2410_ADDR_NALE;//NFCMD                                    
                                                                                      
        chip->IO_ADDR_W = (void *)IO_ADDR_W;                                          
                                                                                      
        if (ctrl & NAND_NCE)                                                          
            writel(readl(&nand->nfcont) & ~(1<<1),                                    
                   &nand->nfcont);//chip select                                       
        else                                                                          
            writel(readl(&nand->nfcont) | (1<<1),                                     
                   &nand->nfcont);//deselcet                                          
    }                                                                                 
                                                                                     
     if (cmd != NAND_CMD_NONE)                                                         
         writeb(cmd, chip->IO_ADDR_W);                                                 
     else //若cmd = NAND_CMD_NONE,写地址要恢复为nfdata   
    chip->IO_ADDR_W = (void *)&nand->nfdata;  
}  
这个s3c24x0_hwcontrol函数可以根据crtl值的不同更改写指针chip->IO_ADDR_W,
从而实现既能写地址,又能写命令,当crtl & NAND_CRTL_CHANGE=1时,chip->ADDR_W
就会被赋一次值。在nand_set_defaults中,chip->cmdfunc = nand_command,这个
函数里会多次调用chip->cmd_crtl(即我们的s3c24x0_hwcontrol函数)来实现发命令
和发地址。由于s3c2410_nand.c中未定义chip->cmdfunc,就会使用默认的nand_command。
这里最好将nand_command改为 nand_command_lp,因为我们的nandflash是大页的,每页数据
有2K+64个字节。仔细阅读nand_command_lp你就会了解s3c24x0_hwcontrol应该实现的功能。
在nand_command_lp中,我们发现每个阶段调用chip->cmd_crtl之后,最后都会调用
chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE)(写地址结束后调用一次,写命令结束后调用一次),
仔细思考你就会想到,chip->IO_ADDR_W在board_nand_init中是被初始化为指向nfdata的,
如果我们调用完s3c24x0_hwcontrol,chip->IO_ADDR_W是指向nfaddr或nfcmd,是否要将其还原呢
,否则下次如果要想写数据不是会出错吗(写数据不用调用chip->cmd_ctrl),
因此chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE)的用意应该是还原
chip->IO_ADDR_W为nfdata,所以上面的s3c24x0_hwcontrol的最后我加上了个else分支。经过实验,
不加这一句,nandflash读写会出错。
另外,S3C2410_ADDR_NCLE和S3C2410_ADDR_NALE两个宏要修改为如下:
#define S3C2410_ADDR_NALE  8  
#define S3C2410_ADDR_NCLE  0xC  

这里使用到了NFCONT寄存器,而2410并无该寄存器,之前未对其进行初始化,因此在
board_nand_init中要对该寄存器进行初始化设置:
/* 初始化ECC,禁止片选,使能NAND Flash控制器 */  
writel((1<<4)|(1<<1)|(1<<0),&nand_reg->nfcont);  
同时,s3c24x0_nand结构体中由于原来定义了CONFIG_S3C2410宏,导致没有NFCONT等寄存器,
因此在smdk2410.h中去掉该宏。编译,烧写到开发板,识别出nandflash为256M。我们再试试
Nandflash的读写。首先试试写nandflash,用以下命令:

nand erase 0 4

mw.l 30000000 12345678

nand write 30000000 0 4

nand dump 0

发现nandflash写入12345678成功。然后再试读nandflash,使用命令:
mw.l 30000000 22222222

md.l 30000000

nand read 30000000 0 4

md.l 30000000

发现成功读出12345678。至此u-boot已经成功支持JZ2440的nandflash。

9.支持DM9000
启动uboot,打印出Net: CS8900-0,而我们的网卡是DM9000,于是在代码中搜索“Net:”,
定位到common/board_r.c的initr_net函数,一路追踪eth_initialize,eth_common_init,
一直到board\samsung\smdk2410\smdk2410.c的board_eth_init函数:
int board_eth_init(bd_t *bis)  
{  
    int rc = 0;  
#ifdef CONFIG_CS8900  
    rc = cs8900_initialize(0, CONFIG_CS8900_BASE);  
#endif  
    return rc;  
}  
这里是对CS8900进行了初始化,我们要对DM9000进行初始化,通过查看
drivers/net/Makefile,发现要包含dm9000x.c的文件,要定义CONFIG_DRIVER_DM9000
这个宏,我们也要注释掉CONFIG_CS8900宏。同时查看dm9000x.c,里面有一个
dm9000_initialize函数,于是仿照cs8900来写dm9000的初始化函数。

int board_eth_init(bd_t *bis)  
{  
    int rc = 0;  
#ifdef CONFIG_CS8900  
    rc = cs8900_initialize(0, CONFIG_CS8900_BASE);  
#endif  
 
#ifdef CONFIG_DRIVER_DM9000  
        rc = dm9000_initialize(bis);    
#endif  
    return rc;  
}  
配置文件smdk2410.h修改如下:

//#define CONFIG_CS8900     /* we have a CS8900 on-board */                           
//#define CONFIG_CS8900_BASE    0x19000300  
//#define CONFIG_CS8900_BUS16   /* the Linux driver does accesses as shorts */        
#define CONFIG_DRIVER_DM9000  
保存,编译,提示一大堆错误,提示dm9000x.c中的‘DM9000_DATA‘ undeclared, ‘DM9000_IO‘ undeclared等等,
结合上面的CS8900的一些宏,看来这些宏需要我们自己在smdk2410.h中定义,在linux中使用grep "DM9000_DATA" * -nR
命令搜索,看看其他板子的配置文件是如何定义这些宏的,可以适当参考下,结合原理图和2440手册,smdk.h中定义如下:

#define CONFIG_DRIVER_DM9000  
#define CONFIG_DM9000_BASE   0x20000000  
#define DM9000_IO        CONFIG_DM9000_BASE  
#define DM9000_DATA      (CONFIG_DM9000_BASE + 4)       
#define CONFIG_DM9000_USE_16BIT        1  
第四行之所以加4是因为DM9000上的CMD引脚接到了LADDR2上。

编译,下载到开发板,提示错误Error: dm9000 address not set.

在代码中搜索“address not set”,有两个函数会打印这句话,分别是net/eth.c里的
eth_post_probe函数和eth_write_hwaddr函数。这个eth_post_probe函数是uboot里网卡
驱动的probe函数,而eth_write_hwaddr会在eth_initialize里被调用,因此这里应该是
eth_write_hwaddr打印出来的。阅读这个函数的代码,发现应该是未设置ethaddr即网卡
的MAC地址导致报错。进入到eth_getenv_enetaddr_by_index(base_name, eth_number, env_enetaddr)里分析:

int eth_getenv_enetaddr_by_index(const char *base_name, int index,  
                 uchar *enetaddr)  
{  
    char enetvar[32];  
    sprintf(enetvar, index ? "%s%daddr" : "%saddr", base_name, index);  
    return eth_getenv_enetaddr(enetvar, enetaddr);  
}  
分析得知,这个函数最终将存放MAC地址的环境变量的值存入env_enetaddr数组中,那么这个
环境变量名称由
sprintf(enetvar, index ? "%s%daddr" : "%saddr", base_name, index)确定。在eth_initialize里eth_write_hwaddr是这样被调用的:
eth_write_hwaddr(dev, "eth", dev->index)。上面的basename应该对应于"eth"。结合上面的sprintf函数,如果index函数存在,则
环境变量名称为eth<index>addr,否则为ethaddr。这里index的值即为eth_write_hwaddr(dev, "eth", dev->index)传入的dev->index,
在eth.c中搜索dev->index,看在哪里设置它的值。结果发现eth_register里会设置:

int eth_register(struct eth_device *dev)  
{  
    struct eth_device *d;  
    static int index;  
 
    assert(strlen(dev->name) < sizeof(dev->name));  
 
    if (!eth_devices) {  
        eth_devices = dev;  
        eth_current = dev;  
        eth_current_changed();  
    } else {  
        for (d = eth_devices; d->next != eth_devices; d = d->next)  
            ;  
        d->next = dev;  
    }  
 
    dev->state = ETH_STATE_INIT;  
    dev->next  = eth_devices;  
    dev->index = index++;  
 
    return 0;  
}  
那么这个函数什么时候会被调用呢,搜索发现每一款网卡的文件里会调用这个函数来注册网卡,我们的DM9000x.c里也有,我们只有一个网卡,
因此只会调用一次,index是静态变量,未赋初始值则默认初始值为0,因此dev->index = index++(注意计算顺序),dec->index = 0,所以
环境变量名称为ethaddr。所以我们需要定义一个名为ethaddr环境变量。在include/env_default.h中有默认环境变量的设置,我们在其中
加入ethaddr环境变量的默认值,这个值我是参照电脑网卡MAC地址随便写的。

#elif defined(DEFAULT_ENV_INSTANCE_STATIC)                                            
static char default_environment[] = {                                                 
#else                                                                                 
const uchar default_environment[] = {                                                 
#endif                                                                                
#ifdef CONFIG_ETHADDR                                                                 
    "ethaddr=" CONFIG_ETHADDR   "\0"                                                  
#endif                                                                                
#ifdef  CONFIG_ENV_CALLBACK_LIST_DEFAULT                                              
    ENV_CALLBACK_VAR "=" CONFIG_ENV_CALLBACK_LIST_DEFAULT "\0"                        
#endif  
在smdk2410.h中设置CONFIG_ETHADDR宏:

#define CONFIG_ETHADDR          "00:0c:29:91:dc:5f"  
保存,编译,烧写,启动Uboot,网卡正常启动。设置一下开发板ip:set ipaddr 192.168.0.2。网线连接开发板和路由器,ping一下主机ip:

ping 192.168.0.100,能够Ping通。再试试能不能用tftp下载文件,

set serverip 192.168.0.100

tftp 30000000 u-boot.bin

使用tftp下载文件也成功,至此,DM9000网卡已经支持。

10.设置nand分区

在下载内核或文件系统时,我们可以直接在命令中写明烧到nandflash
的具体地址,但较麻烦,我们可以给nandflash分区,这样就可直接写
烧到那个分区就行了,较为方便。如何设置呢?首先我们在uboot中输入
mtdparts命令,看看默认的分区,结果提示mtdids not defined, no default present。
搜索"mtdids not defined",定位到common/cmd_mtdparts.c的mtdparts_init函数中,
分析发现是mtdids_default为空。mtdids以及另一个重要的变量mtdparts定义如下:

#if defined(MTDIDS_DEFAULT)  
static const char *const mtdids_default = MTDIDS_DEFAULT;  
#else  
 $ static const char *const mtdids_default = NULL;  
#endif  
 
#if defined(MTDPARTS_DEFAULT)  
static const char *const mtdparts_default = MTDPARTS_DEFAULT;  
#else  
static const char *const mtdparts_default = NULL;  
#endif  
因此,我们需要在smdk2410.h中定义MTDIDS_DEFAULT,MTDPARTS_DEFAULT这两个宏。如何定义这两个宏呢,cmd_mtdparts.c中注释里有例子示范了:

/* Examples:
 *
 * 1 NOR Flash, with 1 single writable partition:
 * mtdids=nor0=edb7312-nor
 * mtdparts=mtdparts=edb7312-nor:-
 *
 * 1 NOR Flash with 2 partitions, 1 NAND with one
 * mtdids=nor0=edb7312-nor,nand0=edb7312-nand
 * mtdparts=mtdparts=edb7312-nor:256k(ARMboot)ro,-(root);edb7312-nand:-(home)
 *
 */  
结合例子和其他开发板的配置文件,我们的定义如下:

#define MTDIDS_DEFAULT          "nand0=s3c2440-nand.0"  
#define MTDPARTS_DEFAULT        "mtdparts=s3c2440-nand.0:256k(bootloader),"\         
                                "128k(params),2m(kernel),"\                          
                                 "-(rootfs)"   
保存,编译,烧写。启动u-boot后执行mtdparts命令,提示mtdparts variable not set, see ‘help mtdparts‘,no partitions defined

那就执行help mtdparts命令看看,发现这么一句:mtdparts default - reset partition table to defaults

可能要执行一下mtdparts default,执行后发现不再提示错误。但总不能每次都要手动执行一次命令吧。于是,我们在代码里执行这么一个命令。
在board_r.c的run_main_loop里修改如下:



static int run_main_loop(void)  
{  
#ifdef CONFIG_SANDBOX  
    sandbox_main_loop_init();  
#endif  
    /* main_loop() can return to retry autoboot, if so just run it again */  
     run_command("mtdparts default",0);//添加这一行代码  
     for (;;)  
        main_loop();  
     return 0;  
编译烧写后,启动u-boot执行mtdparts命令,不再提示错误,直接列出了分区,我们试着往kernel分区里烧写uImage,同时要想启动内核,
必须要设置默认参数bootargs和bootcmd,根据environment.h文件,我们要在smdk2410.h里设置CONFIG_BOOTARGS和CONFIG_BOOTCOMMAND两个宏,如下:

#define CONFIG_BOOTARGS        "noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0"  
#define CONFIG_BOOTCOMMAND    "nand read.jffs2 0x30007FC0 kernel; bootm 0x30007FC0"  
编译烧写,启动u-boot,使用tftp下载uImage到30000000,使用下面的命令

nand erase.chip

nand write.jffs2 30000000 kernel 1c08e8

下载内核到kernel分区成功,并且已经可以启动内核了。

  之前我们设置环境变量,都未执行save命令,因为我们还未设置环境变量保存地址,现在我们想让环境变量保存在我们设置的params分区上。
搜索saveenv函数,发现env_flash.c和env_nand.c都有这个函数,通过查看common/Makefile发现要通过定义CONFIG_ENV_IS_IN_NAND才能包含env_nand.c,
从而将环境变量保存在nandflash上。同时还要设置CMD_SAVEENV,CONFIG_ENV_RANGE,CONFIG_ENV_OFFSET等宏,修改配置文件如下:


#define CONFIG_ETHADDR          "00:0c:29:91:dc:5f"                                  
//#define CONFIG_ENV_ADDR         (CONFIG_SYS_FLASH_BASE + 0x070000)                   
//#define CONFIG_ENV_IS_IN_FLASH                                                       
//#define CONFIG_ENV_SIZE         0x10000     
#define     CMD_SAVEENV  
#define  CONFIG_ENV_IS_IN_NAND  
#define  CONFIG_ENV_SIZE     0x20000  
#define  CONFIG_ENV_OFFSET   0  
编译烧写后,执行命令:

set ipaddr 192.168.0.2

set serverip 192.168.0.100

save

然后reset,发现原来一直提示的一个警告Warning - bad CRC, using default environment已经没了,因为我们自己保存了环境变量。print一下,环境变量和我们设置的一样。


11.

    之前我们的u-boot已经能够启动内核了,现在我们试试能不能挂载文件系统,首先先下载jffs2格式的文件系统到30000000。然后使用命令
nand write.jffs2 30000000 rootfs 59ad78烧写到nandflash的rootfs分区,在bootargs环境变量里添加rootfstype=jffs2,然后重启开发板,
发现内核能够挂载文件系统,证明我们的uboot支持烧写jffs2文件系统。
    再试试yaffs2文件系统,同样下载到30000000,使用nand write.yaffs2 或nand write.yaffs发现都没有这个命令,于是我们进入nand的命令文件common/cmd_nand.c,
在do_nand函数里,有nand read或write的代码,而其中有对jffs2的支持,却并没有对yaffs2的支持。以前的老版本uboot是有对yaffs文件系统烧写的支持的,于是我们参考老版本
的uboot代码,在do_nand函数里的nand write/read部分加上一段代码,如下:

#ifdef CONFIG_CMD_NAND_TRIMFFS  
        } else if (!strcmp(s, ".trimffs")) {  
            if (read) {  
                printf("Unknown nand command suffix ‘%s‘\n", s);  
                 return 1;  
            }  
            ret = nand_write_skip_bad(nand, off, &rwsize, NULL,  
                        maxsize, (u_char *)addr,  
                        WITH_DROP_FFS | WITH_WR_VERIFY);  
#endif  
#ifdef CONFIG_CMD_NAND_YAFFS  
        } else if (!strcmp(s, ".yaffs")) {  
            if (read) {  
                printf("Unknown nand command suffix ‘%s‘.\n", s);  
                return 1;  
            }  
            ret = nand_write_skip_bad(nand, off, &rwsize,NULL,//这里参数和老版比要修改下  
                        maxsize,(u_char *)addr,  
                        WITH_YAFFS_OOB);  
#endif  
在nand_help_text[]里添加nand write.yaffs的帮助信息:

"nand read.raw - addr off|partition [count]\n"  
    "nand write.raw - addr off|partition [count]\n"  
    "    Use read.raw/write.raw to avoid ECC and access the flash as-is.\n"  
#ifdef CONFIG_CMD_NAND_YAFFS  
    "nand write.yaffs - addr off|partition size\n"  
    "    write ‘size‘ bytes starting at offset ‘off‘ with yaffs format\n"  
    "    from memory address ‘addr‘, skipping bad blocks.\n"  
#endif  
nand_write_skip_bad函数内部也要修改:

if (actual)  
        *actual = 0;   
#ifdef CONFIG_CMD_NAND_YAFFS                                                         
     if (flags & WITH_YAFFS_OOB) {                                                    
        if (flags & ~WITH_YAFFS_OOB)                                                 
            return -EINVAL;                                                          
                                                                                     
        int pages;                                                                   
        pages = nand->erasesize / nand->writesize;                                   
        blocksize = (pages * nand->oobsize) + nand->erasesize;                       
        if (*length % (nand->writesize + nand->oobsize)) {                           
            printf ("Attempt to write incomplete page"                               
                " in yaffs mode\n");                                                 
            return -EINVAL;                                                          
        }                                                                            
    } else                                                                           
#endif                                                                               
    {                                                                                
        blocksize = nand->erasesize;                                                 
    }      
 
    ...  
 
if (left_to_write < (blocksize - block_offset))                              
        write_size = left_to_write;                                              
     else                                                                         
        write_size = blocksize - block_offset;                                   
#ifdef CONFIG_CMD_NAND_YAFFS                                                         
    if (flags & WITH_YAFFS_OOB) {                                                
        int page, pages;                                                         
        size_t pagesize = nand->writesize;                                       
        size_t pagesize_oob = pagesize + nand->oobsize;                          
        struct mtd_oob_ops ops;                                                  
                                                                                 
        ops.len = pagesize;                                                      
        ops.ooblen = nand->oobsize;                                              
        ops.mode = MTD_OPS_RAW;       //这里要改为RAW                                           
        ops.ooboffs = 0;                                                         
                                                                                 
        pages = write_size / pagesize_oob;                                       
        for (page = 0; page < pages; page++) {                                   
            WATCHDOG_RESET();                                                    
                                                                                 
        ops.datbuf = p_buffer;                                               
        ops.oobbuf = ops.datbuf + pagesize;                                  
                                                                             
        rval = nand->_write_oob(nand, offset, &ops);                          
        if (rval != 0)   
             break;                                                           
                                                                                
             offset += pagesize;                                                  
             p_buffer += pagesize_oob;                                            
            }                                                                        
        }                                                                            
        else                                                                         
#endif      
     {          //这里要加个左大括号                                                                  
             truncated_write_size = write_size;                                       
#ifdef CONFIG_CMD_NAND_TRIMFFS                                                       
         if (flags & WITH_DROP_FFS)                                                   
             truncated_write_size = drop_ffs(nand, p_buffer,                          
                     &write_size);                                                    
#endif                                                                               
                                                                                      
         rval = nand_write(nand, offset, &truncated_write_size,                       
                 p_buffer);                                                           
                                                                                      
         if ((flags & WITH_WR_VERIFY) && !rval)                                       
             rval = nand_verify(nand, offset,                                         
                 truncated_write_size, p_buffer);                                     
                                                                                      
         offset += write_size;                                                        
         p_buffer += write_size;                                                      
         } //这里要加个右大括号                                                                           
...  
同时,在include/nand.h中添加WITH_YAFFS_OOB宏的定义,

#define WITH_YAFFS_OOB    (1 << 0)  
最后在配置文件里添加CONFIG_CMD_NAND_YAFFS宏定义,编译烧写,成功烧写yaffs2文件系统。启动内核之前,去掉bootargs环境变量里之前添加的rootfstype=jffs2,挂载yaffs2不需要指定rootfstype。启动内核,挂载文件系统成功,此uboot已经支持yaffs2文件系统的烧写。

接下来 我们对uboot进行裁剪以缩小其大小,在配置文件中将一些不需要的功能的宏定义注释掉,然后编译,中间可能会有一些报错,根据提示解决即可。最后制作补丁,先make distclean删除编译内容,再使用如下命令制作补丁:

mv u-boot-2016.16  u-boot-2016.11_jz2440

tar -xjvf u-boot-2016.11.tar.bz2

diff -urN u-boot-2016.11 u-boot-2016.11_jz2440 > u-boot-2016.11_jz2440.patch

这样一个uboot就基本移植成功了。

make distclean;make smdk2440_config;make
usb 1 30000000
protect off all;erase 0 7ffff;cp.b 30000000 0 80000




以上是关于04.移植u-boot的主要内容,如果未能解决你的问题,请参考以下文章

移植u-boot-2012.04.01到JZ2440

04.移植u-boot

可移植类库:推荐替换 [Serializable]

uboot研读笔记 | 04 - 移植uboot 2012.04到JZ2440(支持Nor Flash读写)

MiniGui开发:ubuntu-14.04环境移植MiniGui

ubuntu16.04 ARM平台移植xmlrpc-c