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