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




linux

相關文章
相關標籤/搜索