zoukankan      html  css  js  c++  java
  • 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.11archarmcpuarm920tstart.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 ", 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,
    一直到boardsamsungsmdk2410smdk2410.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   ""                                                  
    #endif                                                                                
    #ifdef  CONFIG_ENV_CALLBACK_LIST_DEFAULT                                              
        ENV_CALLBACK_VAR "=" CONFIG_ENV_CALLBACK_LIST_DEFAULT ""                        
    #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' ", 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'. ", 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] "  
        "nand write.raw - addr off|partition [count] "  
        "    Use read.raw/write.raw to avoid ECC and access the flash as-is. "  
    #ifdef CONFIG_CMD_NAND_YAFFS  
        "nand write.yaffs - addr off|partition size "  
        "    write 'size' bytes starting at offset 'off' with yaffs format "  
        "    from memory address 'addr', skipping bad blocks. "  
    #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 ");                                                 
                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




  • 相关阅读:
    装饰器
    目录和文件操作
    网络通信过程
    epoll并发
    laravel(包含lumen)框架中的跨域函数实例
    windows使用nginx
    nginx反向代理配置 其实很简单
    前端html页面使用marked点亮你的代码
    PHPWAMP开启SSL,PHPWAMP配置ssl证书
    php接收并存储base64位字符串图片
  • 原文地址:https://www.cnblogs.com/Lwd-linux/p/6363564.html
Copyright © 2011-2022 走看看