jz2440开发板修改UBOOT支持NAND FLASH
很多天沒有看嵌入式的東西了,今天來看一下,繼續之前移植uboot到jz2440開發板。今天我們來實現Uboot支持NAND FLASH。
在之前的文章里(點擊連接查看之前的記錄),我們為了編譯通過把NAND FLASH 給屏蔽掉了,現在把它加回來。
將:include/configs/smdk2440.h: 中的#define CONFIG_CMD_NAND取消注釋,重新編譯,看一下編譯的結果錯誤是什么?錯誤如下:
,遇到錯誤要按照從第一個錯誤開始解決的辦法,因為有時候第一個錯誤解決了,后面的錯誤可能就沒有了。我們這里第一個錯誤是:
s3c2410_nand.c:72: error: dereferencing pointer to incomplete type
顯示大概的意思是不完整的類型,我們去s3c2410_nand.c中72行去尋找,是如下代碼:
調用了一個nand結構體:
struct s3c2410_nand *nand = s3c2410_get_base_nand();結構體如下:
#ifdef CONFIG_S3C2410 /* NAND FLASH (see S3C2410 manual chapter 6) */ struct s3c2410_nand {u32 nfconf;u32 nfcmd;u32 nfaddr;u32 nfdata;u32 nfstat;u32 nfecc; }; #endif我們應該是沒有定義CONFIG_S3C2410,因為之前是我們在smdk2440.h中注釋掉了2410的定義,換成了2440:
//#define CONFIG_S3C2410 /* specifically a SAMSUNG S3C2410 SoC */ #define CONFIG_S3C2440 /* specifically a SAMSUNG S3C2440 SoC */那我們只能修改代碼支持2440的部分了(想要更加了解代碼如何修改,需要了解nand flash的操作,詳細可以去看韋東山視頻第二期的關于nand flash的操作)。
操作步驟:
1.把drivers\mtd\nand\s3c2410_nand.c復制為s3c2440_nand.c
該目錄下的Makefile里面關于2410的配置為:
COBJS-$(CONFIG_NAND_S3C2410) += s3c2410_nand.o
去smdk2440.h中搜索CONFIG_NAND_S3C2410,發現有如下兩行代碼:
將這兩行代碼修改為:
#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修改上面的Makefile:
添加一行:
COBJS-$(CONFIG_NAND_S3C2440) += s3c2440_nand.o
這代表如果配置文件里面定義了CONFIG_NAND_S3C2440,則執行這一行的編譯。
2.首先我們去看一下板級初始化相關函數board.c里面關于nand初始化的函數,在board.c中board_init_r函數中有:
void board_init_r(gd_t *id, ulong dest_addr) { ...... ...... nand_init(); /* go init the NAND */ ...... ...... }跳轉到如下代碼(nand.c中):
void nand_init(void) { #ifdef CONFIG_SYS_NAND_SELF_INIT /* 沒有執行 */board_nand_init(); #else /* 執行這里 */int 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 }先跳轉到nand_init_chip這里執行:
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 = 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 = s3c2410_hwcontrol;nand->dev_ready = s3c2410_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; }將以上的這句話:
struct s3c2410_nand *nand_reg = s3c2410_get_base_nand();
改為:
struct s3c2440_nand *nand_reg = s3c2440_get_base_nand();
然后往下看代碼,看到設置時序的時候,與2440手冊對比發現,發現時序設置不對,它是適用于2410的,并不適用于2440,將以下代碼:
修改為:
/* 設置時序 lyy*/cfg = ((tacls-1)<<12)|((twrph0-1)<<8)|((twrph1-1)<<4);然后我們先來做一件事,把這個程序中的關于ECC的代碼全部刪掉,這一部分太復雜,但是對我們的程序又沒有影響太大。刪掉下面的代碼:
#ifdef CONFIG_S3C2410_NAND_HWECC void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode) {struct s3c2410_nand *nand = s3c2410_get_base_nand();debug("s3c2410_nand_enable_hwecc(%p, %d)\n", mtd, mode);writel(readl(&nand->nfconf) | S3C2410_NFCONF_INITECC, &nand->nfconf); }static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,u_char *ecc_code) {struct s3c2410_nand *nand = s3c2410_get_base_nand();ecc_code[0] = readb(&nand->nfecc);ecc_code[1] = readb(&nand->nfecc + 1);ecc_code[2] = readb(&nand->nfecc + 2);debug("s3c2410_nand_calculate_hwecc(%p,): 0x%02x 0x%02x 0x%02x\n",mtd , ecc_code[0], ecc_code[1], ecc_code[2]);return 0; }static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,u_char *read_ecc, u_char *calc_ecc) {if (read_ecc[0] == calc_ecc[0] &&read_ecc[1] == calc_ecc[1] &&read_ecc[2] == calc_ecc[2])return 0;printf("s3c2410_nand_correct_data: not implemented\n");return -1; } #endif然后我們用source insight里面的替代功能,將s3c2410_hwcontrol,s3c2410_dev_ready,s3c2440_nand,s3c2440_get_base_nand,這幾個函數全部替換成…2440….
再來分析:s3c2440_hwcontrol函數,它最后面有這樣幾行代碼:
if (ctrl & NAND_NCE) /* 使能選中 */writel(readl(&nand->nfconf) & ~S3C2410_NFCONF_nFCE,&nand->nfconf);else /* 取消選中 */writel(readl(&nand->nfconf) | S3C2410_NFCONF_nFCE,&nand->nfconf);這個是控制寄存器的片選的配置,這是2410的配置,我們是2440的配置,需要查看2440手冊查看相關寄存器,我們的2440需要配置的是NFCONT寄存器。查看寄存器配置后,將上面的代碼修改為:
if (ctrl & NAND_NCE) /* 使能選中 */writel(readl(&nand->nfcont) & ~(1<<1),&nand->nfcont);else /* 取消選中 */writel(readl(&nand->nfcont) | (1<<1),&nand->nfcont);突然想到上面有一個地方還行需要設置一下nfcont寄存器,在s3c2440_nand.c中的board_nand_init函數中加入一段話(下面兩行):
/* 設置時序 lyy*/cfg = ((tacls-1)<<12)|((twrph0-1)<<8)|((twrph1-1)<<4);writel(cfg, &nand_reg->nfconf);/* 使能NAND Flash控制器, 初始化ECC, 禁止片選 */ /*加入的*/writel((1<<4)|(1<<1)|(1<<0),&nand_reg->nfcont); /*加入的*/通過分析,發現還需要在s3c2440_nand.c中的board_nand_init函數里加上nand->select_chip = s3c2440_nand_select;這個函數,將以下代碼修改為:nand->select_chip = s3c2440_nand_select;
nand->select_chip = NULL; 修改為: nand->select_chip = s3c2440_nand_select;編寫s3c2440_nand_select函數,放在board_nand_init上面。
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();} }通過分析知道,需要修改s3c2440_hwcontrol函數重新全部修改為下面得函數:
static void s3c2440_hwcontrol(struct mtd_info *mtd, int dat, unsigned int ctrl) {struct nand_chip *chip = mtd->priv;struct s3c2440_nand *nand = s3c2440_get_base_nand();if (ctrl & NAND_CLE){/* 發命令 */ writeb(dat, &nand->nfcmd);}if (ctrl & NAND_ALE){/* 發地址 */writeb(dat, &nand->nfaddr);}}上面的分析過于復雜,對于我來說還是有一定難度,我也無法用文字描述清楚,下面給出函數調用的大致流程,等以后水平高了,再回頭來看年輕的時候做過的記錄。
分析過程:
修改的文件一共涉及三個文件:s3c2440_nand.c,smdk2440.h,Makefile,這三個文件。
重新編譯燒寫到開發板(燒寫步驟會單獨寫一篇文章記錄):
很奇怪,又出現了這個錯誤:
Flash: ERROR: too many flash sectors
記得在之前修改代碼支持NOR FLASH中也出現過一樣的錯誤(點擊查看之前的文章)。我們將CONFIG_SYS_MAX_FLASH_SECT這個值改大一些試一下,改為128(我記得之前改過,怎么又變回去了?奇怪!!!)
然后重新燒寫啟動:
從中可以看出已經識別出了nand:256MiB.那么說明我們的uboot已經支持nand flash。
下面從NAND 啟動看一下,首先我們從NOR直接把uboot拷貝到NAND。輸入以下命令:
nand erase 0 80000
nand write 0 0 80000
然后測試燒寫到NNAD FLASH中的uboot是否正常
nand read 30000000 0 80000
cmp.b 0 30000000 80000 (比較拷貝的代碼是否全部一樣)
然后切換到NAND重啟。顯示:
這樣的話,就說明我們的nand啟動也是正常的!!!!
寫了很久,真的很累也很難,但是我相信付出一定有回報的~
想獲得各種學習資源以及交流學習的加我:
qq:1126137994
微信:liu1126137994
可以共同交流關于嵌入式,操作系統,C++語言,C語言,數據結構等技術問題!
總結
以上是生活随笔為你收集整理的jz2440开发板修改UBOOT支持NAND FLASH的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: cisco 思科三层交换机配置命令
- 下一篇: 互联网日报 | 8月3日 星期二 | 陌