日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

移植uboot第六步:支持NANDFlash

發(fā)布時間:2025/10/17 编程问答 55 豆豆
生活随笔 收集整理的這篇文章主要介紹了 移植uboot第六步:支持NANDFlash 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

寫在前面:

我的博客已遷移至自建服務(wù)器:博客傳送門,CSDN博客暫時停止,如有機器學(xué)習(xí)方面的興趣,歡迎來看一看。

此外目前我在gitHub上準(zhǔn)備一些李航的《統(tǒng)計學(xué)習(xí)方法》的實現(xiàn)算法,目標(biāo)將書內(nèi)算法全部手打?qū)崿F(xiàn),歡迎參觀并打星。GitHib傳送門

正文

前面已經(jīng)讓板子能夠支持NORFlash了,還沒有支持NANDFlash。

一. 找到之前第一步注釋掉的NAND相關(guān)的宏定義

//#define CONFIG_S3C2410 /* specifically a SAMSUNG S3C2410 SoC */ #ifdef CONFIG_S3C2410 #define CONFIG_NAND_S3C2410 #define CONFIG_SYS_S3C2410_NAND_HWECC #define CONFIG_SYS_MAX_NAND_DEVICE 1 #define CONFIG_SYS_NAND_BASE 0x4E000000 #endif

為了程序的兼容性,不直接把宏定義取消注釋。在宏定義邊上再宏定義一個

//#define CONFIG_S3C2410 /* specifically a SAMSUNG S3C2410 SoC */ #define CONFIG_S3C2440 /* specifically a SAMSUNG S3C2410 SoC */

然后將NAND的相關(guān)宏定義格式改為

#ifdef CONFIG_S3C2410 #define CONFIG_NAND_S3C2410 #define CONFIG_SYS_S3C2410_NAND_HWECC #else #define CONFIG_NAND_S3C2440 #define CONFIG_SYS_S3C2440_NAND_HWECC #endif #define CONFIG_SYS_MAX_NAND_DEVICE 1 #define CONFIG_SYS_NAND_BASE 0x4E000000 #endif

這樣這個uboot以后對2410還是有很好的支持性的。

編譯,解決錯誤

二. 報錯:s3c2410_nand.c的第72行出現(xiàn)錯誤。(一般出現(xiàn)一堆錯誤的時候,解決第一個錯誤,解決完再重新編譯, 再解決第一個錯誤,直到?jīng)]有錯誤。因為很多錯誤是有連帶性的,一個錯誤解決可能會連帶解決一些錯誤)
找到代碼段,是調(diào)用了一個結(jié)構(gòu)體,結(jié)構(gòu)體的定義是這樣的
struct s3c2410_nand *nand = s3c2410_get_base_nand();
定位到這個結(jié)構(gòu)體的初始化

#ifdef CONFIG_S3C2410 /* NAND FLASH (see S3C2410 manual chapter 6) */ struct s3c2410_nand { u32nfconf; u32nfcmd; u32nfaddr; u32nfdata; u32nfstat; u32nfecc; };#endif #ifdef CONFIG_S3C2440 /* NAND FLASH (see S3C2440 manual chapter 6) */ struct s3c2440_nand {u32 nfconf;u32 nfcont;u32 nfcmd;u32 nfaddr;u32 nfdata;u32 nfeccd0;u32 nfeccd1;u32 nfeccd;u32 nfstat;u32 nfstat0;u32 nfstat1; }; #endif

這里可以明白,我們使用的宏是2440,所以2410這個結(jié)構(gòu)體并沒有,在代碼中把2410改為2440。
我們干脆就重新做一個s3c2440_nand.c文件,找到目錄drivers\mtd\nand里面的s3c2410_nand.c,復(fù)制一份改為s3c2440_nand.c,要將其加入uboot,所以找到該文件目錄里的Makefile,找到里面有一條語句

COBJS-$(CONFIG_NAND_S3C2410) += s3c2410_nand.o

說明原先的2410也是條件編譯進入uboot。在include\configs 目錄內(nèi)找到smdk2440.h。

#ifdef CONFIG_CMD_NAND#ifdef CONFIG_S3C2410 #define CONFIG_NAND_S3C2410 #define CONFIG_SYS_S3C2410_NAND_HWECC #else #define CONFIG_NAND_S3C2440 #define CONFIG_SYS_S3C2440_NAND_HWECC #endif#define CONFIG_SYS_MAX_NAND_DEVICE 1 #define CONFIG_SYS_NAND_BASE 0x4E000000 #endif

宏定義在這里,這段代碼段就是我們剛才修改過的,也就是說s3c2410_nand.c本身就已經(jīng)不參與編譯了,我們再邊上加上一句

COBJS-$(CONFIG_NAND_S3C2410) += s3c2410_nand.o COBJS-$(CONFIG_NAND_S3C2440) += s3c2440_nand.o

如果定義了CONFIG_NAND_S3C2440,那么就編譯s3c2440_nand.c
這樣就可以了。

進入s3c2440_nand.c目錄。將剛才發(fā)現(xiàn)錯誤的地方修改如下

struct s3c2440_nand *nand = s3c2440_get_base_nand();

三.查看nand相關(guān)函數(shù)是否支持2440
在board_init_r中找到

nand_init(); /* go init the NAND */

進入函數(shù)

void nand_init(void) { #ifdef CONFIG_SYS_NAND_SELF_INITboard_nand_init(); #elseint i;for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++)nand_init_chip(i); #endifprintf("%lu MiB\n", total_nand_size / 1024);#ifdef CONFIG_SYS_NAND_SELECT_DEVICE/** Select the chip in the board/cpu specific driver*/board_nand_select_device(nand_info[nand_curr_device].priv, nand_curr_device); #endif }

查看得知CONFIG_SYS_NAND_SELF_INIT這個宏定義是否定義由另一個宏定義決定

#if defined(CONFIG_NAND_FSL_ELBC) #define CONFIG_SYS_NAND_SELF_INIT #endif

而CONFIG_NAND_FSL_ELBC沒有被定義,也就是說程序是執(zhí)行的是#else下面的內(nèi)容,進入nand_init_chip(i);函數(shù)。

#ifndef CONFIG_SYS_NAND_SELF_INIT static void nand_init_chip(int i) {struct mtd_info *mtd = &nand_info[i];struct nand_chip *nand = &nand_chip[i];ulong base_addr = base_address[i];int maxchips = CONFIG_SYS_NAND_MAX_CHIPS;if (maxchips < 1)maxchips = 1;mtd->priv = nand;nand->IO_ADDR_R = nand->IO_ADDR_W = (void __iomem *)base_addr;if (board_nand_init(nand))return;if (nand_scan(mtd, maxchips))return;nand_register(i); } #endif

進入board_nand_init看看

int board_nand_init(struct nand_chip *nand) {u_int32_t cfg;u_int8_t tacls, twrph0, twrph1;struct s3c24x0_clock_power *clk_power = s3c24x0_get_base_clock_power();struct s3c2440_nand *nand_reg = s3c2440_get_base_nand();debug("board_nand_init()\n");writel(readl(&clk_power->clkcon) | (1 << 4), &clk_power->clkcon);/* initialize hardware */ #if defined(CONFIG_S3C24XX_CUSTOM_NAND_TIMING)tacls = CONFIG_S3C24XX_TACLS;twrph0 = CONFIG_S3C24XX_TWRPH0;twrph1 = CONFIG_S3C24XX_TWRPH1; #elsetacls = 4;twrph0 = 8;twrph1 = 8; #endifcfg = 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);/* initialize nand_chip data structure */nand->IO_ADDR_R = (void *)&nand_reg->nfdata;nand->IO_ADDR_W = (void *)&nand_reg->nfdata;nand->select_chip = s3c2440_nand_select;/* read_buf and write_buf are default *//* read_byte and write_byte are default */ #ifdef CONFIG_NAND_SPLnand->read_buf = nand_read_buf; #endif/* hwcontrol always must be implemented */nand->cmd_ctrl = s3c2440_hwcontrol;nand->dev_ready = s3c2440_dev_ready;#ifdef CONFIG_S3C2410_NAND_HWECCnand->ecc.hwctl = s3c2410_nand_enable_hwecc;nand->ecc.calculate = s3c2410_nand_calculate_ecc;nand->ecc.correct = s3c2410_nand_correct_data;nand->ecc.mode = NAND_ECC_HW;nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE;nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES; #elsenand->ecc.mode = NAND_ECC_SOFT; #endif#ifdef CONFIG_S3C2410_NAND_BBTnand->options = NAND_USE_FLASH_BBT; #elsenand->options = 0; #endifdebug("end of nand_init\n");return 0; }

下面這段代碼應(yīng)該是設(shè)置NAND控制器的時間參數(shù)的。我當(dāng)時寫的時候三個時間參數(shù)設(shè)置是

tacls = 0; twrph0 = 1; twrph1 = 0;

但是無所謂,只要它的時間參數(shù)比我的久就行了,久是肯定可以直接用的,比我的時間短那就得看手冊支不支持怎么短的時間了。

tacls = 4; twrph0 = 8; twrph1 = 8; #endifcfg = 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);

查看手冊比對寄存器設(shè)置的時候這些代碼是否是對的,我就不想管這些了,直接粗暴一點,反正之前這塊設(shè)置的代碼還在,我就直接改成了

#elsetacls = 4;twrph0 = 8;twrph1 = 8; #endif#if 0cfg = S3C2410_NFCONF_EN;cfg |= S3C2410_NFCONF_TACLS(tacls - 1);cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1); #else/* 設(shè)置時序 */ cfg = ((twrph1 - 1)<<12)|((twrph0 - 1)<<8)|((tacls - 1)<<4); #endifwritel(cfg, &nand_reg->nfconf);

設(shè)置完時序以后 初始化ECC, 禁止片選還沒有做,我也自己給他在后面加上

/* 使能NAND Flash控制器, 初始化ECC, 禁止片選 */ writel( (1<<4)|(1<<1)|(1<<0), &nand_reg->nfcont);

函數(shù)剩下的部分是結(jié)構(gòu)體參數(shù)的賦值,應(yīng)該是NAND的底層操作函數(shù)在這里上報。

nand->select_chip = NULL;/* read_buf and write_buf are default *//* read_byte and write_byte are default */ #ifdef CONFIG_NAND_SPLnand->read_buf = nand_read_buf; #endif/* hwcontrol always must be implemented */nand->cmd_ctrl = s3c2440_hwcontrol;nand->dev_ready = s3c2440_dev_ready;#ifdef CONFIG_S3C2410_NAND_HWECCnand->ecc.hwctl = s3c2410_nand_enable_hwecc;nand->ecc.calculate = s3c2410_nand_calculate_ecc;nand->ecc.correct = s3c2410_nand_correct_data;nand->ecc.mode = NAND_ECC_HW;nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE;nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES; #elsenand->ecc.mode = NAND_ECC_SOFT; #endif#ifdef CONFIG_S3C2410_NAND_BBTnand->options = NAND_USE_FLASH_BBT; #elsenand->options = 0; #endif

我們要看現(xiàn)在uboot的nand能不能支持2440了,就一個個把這些函數(shù)看下去,看每一個函數(shù)里面的代碼是否和2440匹配。

a.select_chip函數(shù)設(shè)置的是null,就先不管,CONFIG_NAND_SPL沒有宏定義,所以read_buf也先不管,先看nand->cmd_ctrl = s3c2410_hwcontrol;這個函數(shù)
先把名字都從2410改成2440。

static void s3c2440_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) {struct nand_chip *chip = mtd->priv;struct s3c2440_nand *nand = s3c2440_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;if (!(ctrl & NAND_ALE))IO_ADDR_W |= S3C2410_ADDR_NALE;chip->IO_ADDR_W = (void *)IO_ADDR_W;if (ctrl & NAND_NCE)writel(readl(&nand->nfconf) & ~S3C2410_NFCONF_nFCE,&nand->nfconf);elsewritel(readl(&nand->nfconf) | S3C2410_NFCONF_nFCE,&nand->nfconf);}if (cmd != NAND_CMD_NONE)writeb(cmd, chip->IO_ADDR_W); }

這個函數(shù)應(yīng)該是負(fù)責(zé)寫命令或者寫數(shù)據(jù),直接將其修改為我們自己的

static void s3c2440_hwcontrol(struct mtd_info *mtd, int dat, unsigned int ctrl) {struct s3c2440_nand *nand = s3c2440_get_base_nand();if (ctrl & NAND_CLE){/* 發(fā)命令 */writeb(dat, &nand->nfcmd);}else if (ctrl & NAND_ALE){/* 發(fā)數(shù)據(jù) */writeb(dat, &nand->nfaddr);} }

接下來就是比對每一個操作函數(shù)里面的操作寄存器的方式和我們的是否一樣,同時把所有的2440修改為2410。

之前代碼里看到過select_chip 函數(shù)是空,那么怎么選中片子呢?

nand->select_chip = null;

一層層函數(shù)下去找到nand_set_defaults函數(shù),看名字是設(shè)置默認(rèn)值

void board_init_r(gd_t *id, ulong dest_addr) nand_init(); /* go init the NAND */ nand_init_chip(i); nand_scan(mtd, maxchips) nand_scan_ident(mtd, maxchips, NULL); nand_set_defaults(chip, busw);

這個函數(shù)的作用是,查看之前上報用的結(jié)構(gòu)體,如果某項為空,就使用程序自帶的默認(rèn)函數(shù)。

/** Set default functions*/ static void nand_set_defaults(struct nand_chip *chip, int busw) {/* check for proper chip_delay setup, set 20us if not */if (!chip->chip_delay)chip->chip_delay = 20;/* check, if a user supplied command function given */if (chip->cmdfunc == NULL)chip->cmdfunc = nand_command;/* check, if a user supplied wait function given */if (chip->waitfunc == NULL)chip->waitfunc = nand_wait;if (!chip->select_chip)chip->select_chip = nand_select_chip;if (!chip->read_byte)chip->read_byte = busw ? nand_read_byte16 : nand_read_byte;if (!chip->read_word)chip->read_word = nand_read_word;if (!chip->block_bad)chip->block_bad = nand_block_bad;if (!chip->block_markbad)chip->block_markbad = nand_default_block_markbad;if (!chip->write_buf)chip->write_buf = busw ? nand_write_buf16 : nand_write_buf;if (!chip->read_buf)chip->read_buf = busw ? nand_read_buf16 : nand_read_buf;if (!chip->verify_buf)chip->verify_buf = busw ? nand_verify_buf16 : nand_verify_buf;if (!chip->scan_bbt)chip->scan_bbt = nand_default_bbt;if (!chip->controller)chip->controller = &chip->hwcontrol; }

找到它默認(rèn)的選擇片子的函數(shù)

/*** nand_select_chip - [DEFAULT] control CE line* @mtd: MTD device structure* @chipnr: chipnumber to select, -1 for deselect** Default select function for 1 chip devices.*/ static void nand_select_chip(struct mtd_info *mtd, int chipnr) {struct nand_chip *chip = mtd->priv;switch (chipnr) {case -1:chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);break;case 0:break;default:BUG();} }

-1表示取消選中,0表示選中,這里只寫了取消選中,沒寫選中,顯然這個函數(shù)我們是用不了的。自己在s3c2440_nand.c建一個函數(shù)

static void s3c2440_nand_select(struct mtd_info *mtd, int chipnr) {struct s3c2440_nand *nand = s3c2440_get_base_nand();switch (chipnr) {case -1: /* 取消選中 */nand->nfcont |= (1 << 1); break;case 0:nand->nfcont &= ~(1 << 1); break;default:BUG();} }

在結(jié)構(gòu)體上報中修改一下

nand->select_chip = s3c2440_nand_select;

編譯,燒寫,運行。
沒有錯誤且已經(jīng)能識別NAND了,因為燒寫在NAND里,0地址對應(yīng)的是片內(nèi)內(nèi)存,無法去訪問NOR,所以NOR識別出來應(yīng)該是0k。但是NOR啟動的話,兩個都能識別。

U-Boot 2012.04.01 (Aug 12 2016 - 16:02:01)CPUID: 32440001 FCLK: 400 MHz HCLK: 100 MHz PCLK: 50 MHz DRAM: 64 MiB WARNING: Caches not enabled Flash: 0 KB NAND: 256 MiB *** Warning - bad CRC, using default environmentIn: serial Out: serial Err: serial Net: CS8900-0 SMDK2410 #

后記:
boot有四五百K,我使用的是oflash,燒寫速度很慢,提速的方式可以使用先燒寫下的好用的uboot,我使用了韋東山的,兩百多K,然后再使用好用的uboot去驅(qū)動dnw下載。
現(xiàn)在我們寫的boot已經(jīng)能使用串口了,因此可以使用串口下載,速度也還可以。
輸入help查看指令,有l(wèi)oady下載方式

loady - load binary file over serial line (ymodem mode)

我使用的Xshell沒找到loady模式,(load有好幾種模式,loadx,loady,loadz,大多數(shù)都不支持loady)。百度下載了一個XP的超級終端,提供loady。終端中串口連接上,輸入命令。

loady 0x30000000

后面的是燒寫地址。板子就在等待文件,終端中選擇boot路徑,選擇loady模式,點確定就能下載。發(fā)送文件這個步驟手速要快,如果失敗了,就是時間間隔太久了,可以復(fù)制文件路徑,進去直接粘貼點確定,要快一點。
燒寫進去以后是在板子的內(nèi)存里,輸入

nand erase 0 80000 //擦除nand, 從0地址一直到80000 nand write 0 80000 //將內(nèi)存中的boot寫入nand,從0地址到80000 reset //重啟boot

總結(jié)

以上是生活随笔為你收集整理的移植uboot第六步:支持NANDFlash的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。