s3c6410 开发板Linux系统支持 K9GAG08U0E的方法
由于NandFlash硬件升級(jí)比較快,公司去年一直在使用三星的K9GAG08U0D,現(xiàn)在MLC NandFlash 升級(jí)到了第二代,K9GAG08U0D 很快就會(huì)處在停產(chǎn)的狀態(tài),未雨綢繆,公司選型了K9GAG08U0E 來替代原有的NandFlash芯片。起初。本以為把新Nandflash ID信息增加到Uboot 和 Linux內(nèi)核的NandFlash ID 列表文件中即可,也就是Uboot 和Linux源碼中的nand_ids.c 文件中,但是仔細(xì)看了?K9GAG08U0E 的DataSheet,發(fā)現(xiàn)自己的想法錯(cuò)了。
下面記錄了NandFlash更換時(shí)面臨的幾個(gè)問題,及解決方法:
第一個(gè)問題:ID 沖突
??K9GAG08U0E 的 Product ID與?K9GAG08U0D 的Product ID 是相同的,都是 0xd5,而在Uboot 代碼和Linux內(nèi)核代碼中,是根據(jù)ID信息來獲取或者計(jì)算NandFlash的頁(yè)大小和塊大小這些關(guān)鍵信息的。
?現(xiàn)在這兩款的 Flash ID相同,而Page,OOB ,Block大小都是不同的。 K9GAG08U0D ?Page,OOB,Block 關(guān)鍵參數(shù):
?
而K9GAG08U0E 的?Page,OOB,Block ?關(guān)鍵參數(shù):
可見他們是不同的,U0E 每頁(yè)大小是U0D的兩倍。
針對(duì)相同ID的兩款不同F(xiàn)lash是怎樣區(qū)分的呢?仔細(xì)看DataSheet,發(fā)現(xiàn)了可以快速區(qū)分兩種設(shè)備的方法:
U0D Page=4K,U0D Page=8K,我們只需判斷Read第四個(gè)字節(jié)的第0位和第1位即可。
下面列出關(guān)鍵代碼段:
? ? ?//這里必須有下面兩行代碼,因?yàn)閁0E的DataSheet要求系統(tǒng)上電后第一條指令必須是NAND_CMD_RESET,而U0D沒有這要求,如果不發(fā)送這條指令是無法讀取到NandFlash的任何信息的,因?yàn)檫@個(gè)問題查找了很長(zhǎng)時(shí)間,在這里提醒給大家。
? ? ?// K9GAG08U0E must add below codes ? ??
? ? ? ?{
? ? ? ? ? s3c_nand_hwcontrol(0, NAND_CMD_RESET, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
? ? ? ? ? s3c_nand_device_ready(0);
? ? ? ? }
? ? ? ? s3c_nand_hwcontrol(0, NAND_CMD_READID, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
? ? ? ? s3c_nand_hwcontrol(0, 0x00, NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE);
? ? ? ? s3c_nand_hwcontrol(0, 0x00, NAND_NCE | NAND_ALE);
? ? ? ? s3c_nand_hwcontrol(0, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
? ? ? ? s3c_nand_device_ready(0);
? ? ? ?tmp = readb(nand->IO_ADDR_R); /* Maf. ID */
? ? ? // ?printf("Manufactor ID:%x\n",tmp);
? ? ? ?tmp = dev_id = readb(nand->IO_ADDR_R); /* Device ID */
? ? ? ? //printf("dev_id ID:%x \n",dev_id);
? ? ?for (i = 0; nand_flash_ids[i].name != NULL; i++)?
? ? ?{
? ? ? ? if (tmp == nand_flash_ids[i].id) {
? ? ? ? type = &nand_flash_ids[i];
? ? ? ?break;
? ? }
? ? ? nand->cellinfo = readb(nand->IO_ADDR_R);/* 3rd byte */
? ? ?tmp = readb(nand->IO_ADDR_R);/* 4th byte */
? ???int childType=tmp & 0x03; //Page size
? ? ?// ?printf("dev_id=%x,childType=%x \n",dev_id,childType);
? ??if(dev_id == 0xd5 && childType==0x01) //U0D
? ??{ ??
? ? }else ?if(dev_id == 0xd5 && childType==0x02) //U0E
? ?{
? ? }
這樣針對(duì)不同的NandFlash做不同的初始化了,以上代碼來自u(píng)boot1.1.6/cpu/s3c64xx/nand.c 文件中的void board_nand_init(struct nand_chip *nand) 函數(shù)。
在上一篇中我們重點(diǎn)介紹了K9GAG08U0D 和?K9GAG08U0E的區(qū)別,除了這些外還有一個(gè)需要重點(diǎn)關(guān)注的地方,下面我們?cè)敿?xì)講解。
? ? ? ? Uboot從NandFlash啟動(dòng)第一步就是把NandFlash的前8K代碼拷貝到s3c6410內(nèi)部的SRAM中,然后運(yùn)行,這8K的代碼會(huì)從NandFlash中把完整的Uboot代碼拷貝到6410開發(fā)板片外內(nèi)存中,我這里使用的是256M的DDR,Uboot的存放地址為0x5FE00000,虛擬地址為 0xCFE00000.
注意:關(guān)鍵的8K代碼不是在U0D(每頁(yè)4K)的前兩頁(yè)存放,也不是在U0E(每頁(yè)8K)的第一頁(yè)存放,而是在U0E或者U0D的 ? ? ? ? ? ? 前四頁(yè)中存放的,前四頁(yè)分為每頁(yè)2K,總共8K,這是由s3c6410芯片本身所規(guī)定的。這8K字節(jié)外后面的數(shù)據(jù)就是按實(shí) ? ? ? ? ? ? 際的頁(yè)數(shù)存放了,U0D 每頁(yè)存放4K字節(jié),U0E每頁(yè)存放8K字節(jié)。
? ? ? ? ? ? ??s3c6410支持從SD卡啟動(dòng),從SD卡啟動(dòng)后就可以把Uboot.bin文件寫入NandFlash了,可以認(rèn)真的看一下Uboot 里面 的 nand write.uboot 命令是如何把數(shù)據(jù)寫入NandFlash前4頁(yè) 的。寫入成功后就可以從NandFlash啟動(dòng)Uboot。
? ? ? ?nand write.uboot 的關(guān)鍵代碼 位于uboot1.1.6/common/cmd_nand.c文件中:
? ? ? ? ? ? if (!read && s != NULL && (!strcmp(s, ".uboot")) && nand->writesize == 4096)?//U0D?
? ? ? ? ? ?{ ? ?
? ? ? ? ? ? size=4096;
? ? ? ? ? ? nand_write(nand, off, &size, (u_char *)addr);
? ? ? ? ? ? off+=4096;
? ? ? ? ? ? addr+=2048;
? ? ? ? ? ?nand_write(nand, off, &size, (u_char *)addr);
? ? ? ? ? ? off+=4096;
? ? ? ? ? ? addr+=2048;
? ? ? ? ? ?nand_write(nand, off, &size, (u_char *)addr);
? ? ? ? ? ?off+=4096;
? ? ? ? ? ?addr+=2048;
? ? ? ? ? ?nand_write(nand, off, &size, (u_char *)addr);
? ? ? ? ? ?off+=4096;
? ? ? ? ? ?addr+=2048;
? ? ? ? ? ? size=1024*1024-4*4096;
? ? ? ? ? ? ret = nand_write(nand, off, &size, (u_char *)addr);
? ? ? ? ? ? }else if(!read && s != NULL && (!strcmp(s, ".uboot")) && nand->writesize == 8192) //U0E
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? size=8192; ?
? ? ? ? ? ? ? ? ? ? ret=nand_write(nand, off, &size, (u_char *)addr);
? ? ? ? ? ? ? ? ? ? off+=8192;
? ? ? ? ? ? ? ? ? ? addr+=2048;
? ? ? ? ? ? ? ? ? ? ret=nand_write(nand, off, &size, (u_char *)addr);
? ? ? ? ? ? ? ? ? ? off+=8192;
? ? ? ? ? ? ? ? ? ? addr+=2048;
? ? ? ? ? ? ? ? ? ? ret=nand_write(nand, off, &size, (u_char *)addr);
? ? ? ? ? ? ? ? ? ? off+=8192;
? ? ? ? ? ? ? ? ? ? addr+=2048;
? ? ? ? ? ? ? ? ? ? ret=nand_write(nand, off, &size, (u_char *)addr);
? ? ? ? ? ? ? ? ? ? off+=8192;
? ? ? ? ? ? ? ? ? ? addr+=2048;
//寫剩余的頁(yè)面,這里的Uboot占用1M的NandFlash地址空間,在U0E里面占用128個(gè)頁(yè)面(128Page=1M),上面已經(jīng)寫了四個(gè)頁(yè)面了,這里寫剩余的124個(gè)頁(yè),124個(gè)頁(yè)面足夠存放Uboot的有效數(shù)據(jù)了。
? ? ? ? ? ? ? ? ? ? size=1024*1024-4*8192;
? ? ? ? ? ? ? ? ? ? ret = nand_write(nand, off, &size, (u_char *)addr);
? ? ? ? ? ? ? ? }
現(xiàn)在我們重點(diǎn)要看 Uboot代碼,uboot1.1.6/cpu/s3c64xx/nand_cp.c 文件:
?//該函數(shù)在Uboot.bin前8K代碼中,這個(gè)函數(shù)實(shí)現(xiàn)把Uboot從Nandflash拷貝到外部?jī)?nèi)存中,是Uboot從Nandflash啟動(dòng)的關(guān)鍵地方
int copy_uboot_to_ram (void)
{
? ? ? int large_block = 0;
? ? ? int i;
? ? ? vu_char id;
? ? ? ? NAND_ENABLE_CE();
? ? ? ? NFCMD_REG=NAND_CMD_RESET;
? ? ? ? NF_TRANSRnB();
? ? ? ? NFCMD_REG = NAND_CMD_READID;
? ? ? ? NFADDR_REG = ?0x00;
? ? ? ? NF_TRANSRnB();
/* wait for a while */
? ? ? ? for (i=0; i<200; i++);
? ? ? ? int factory = NFDATA8_REG;
? ? ? ? id = NFDATA8_REG;
? ? ? ? int cellinfo=NFDATA8_REG;
? ? ? ? int tmp= NFDATA8_REG;
? ? ? ? int childType=tmp & 0x03; //Page size
? ? ? ? if (id > 0x80)
? ? ? ? {
? ? ? ? ? ? large_block = 1;
? ? ? ? }
? ? ? ? if(id == 0xd5 && childType==0x01 ) //K9GAG08U0D
? ? ? ? {
? ? ? ? ? ? large_block = 2;
? ? ? ? }else if(id == 0xd5 && childType==0x02 ) //K9GAG08U0D
? ? ? ? {
? ? ? ? ? ? large_block = 3;
? ? ? ? }
? ? /* read NAND Block.
? ? * 128KB ->240KB because of U-Boot size increase. by scsuh
? ? * So, read 0x3c000 bytes not 0x20000(128KB).
? ? */
? ?return nandll_read_blocks(CFG_PHY_UBOOT_BASE, 0x3c000, large_block);
}
static int nandll_read_blocks (ulong dst_addr, ulong size, int large_block)
{
? ? ? ?uchar *buf = (uchar *)dst_addr;
? ? ? ?int i;
? ? ? ?uint page_shift = 9;
? ? ? if (large_block==1)
? ? ? ? page_shift = 11;
? ? ? if(large_block==2)
? ? ? ? ? page_shift = 12;
? ? ? if(large_block==3)
? ? ? ? ? ? ? ? page_shift =13;
? ? ? if(large_block == 2) //?K9GAG08U0D
? ? ? ?{
? ? ? ? ? ? ? ? /* Read pages */
? ? ? ? ?for (i = 0; i < 4; i++, buf+=(1<<(page_shift-1)))?
? ? ? ? ? {
? ? ? ? ? ? ? ? ? nandll_read_page(buf, i, large_block);
? ? ? ? ? }
? ? ? ?/* Read pages */
? ? ? for (i = 4; i < (0x3c000>>page_shift); i++, buf+=(1<<page_shift))?
? ? ? {
? ? ? ?nandll_read_page(buf, i, large_block);
? ? ?}
? ? ??}else if(large_block == 3) ?//K9GAG08U0E
? ? ? ? {
? ? ? ? ? ? /* Read pages */
? ? ? ? ? ? for (i = 0; i < 4; i++, buf+=(1<<(page_shift-2)))?
? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? nandll_read_page(buf, i, large_block);
? ? ? ? ? ? }
? ? ? ? ? ? /* Read pages */
? ? ? ? ? ? for (i = 4; i < (0x3c000>>page_shift); i++, buf+=(1<<page_shift))?
? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? nandll_read_page(buf, i, large_block);
? ? ? ? ? ? }
? ? ? ? }
? ? else
? ? ? {
? ? ? ? ? ? for (i = 0; i < (0x3c000>>page_shift); i++, buf+=(1<<page_shift))?
? ? ? ? ? ? ?{
? ? ? ? ? ? ? ? ? ?nandll_read_page(buf, i, large_block);
? ? ? ? ? ? ? ?}
? ? ? ?}
? ? ? ? return 0;
}
static int nandll_read_page (uchar *buf, ulong addr, int large_block)
{
? ? ?int i;
? ? ?int page_size = 512;
? ? ?if (large_block==1)
? ? ? ? ?page_size = 2048;
? ? ?if (large_block==2)
? ? ? ? ?page_size = 4096;
? ? ?if(large_block==3)
? ? ? ? ?page_size = 8192;
? ? ? ?NAND_ENABLE_CE();
? ? ? ?NFCMD_REG = NAND_CMD_READ0;
? ? ? ? /* Write Address */ //5 個(gè)尋址周期,參看下圖
? ? ? ? NFADDR_REG = 0;
? ? ? ? if (large_block)
? ? ? ?NFADDR_REG = 0;
? ? ? ?NFADDR_REG = (addr) & 0xff;
? ? ? ?NFADDR_REG = (addr >> 8) & 0xff;
? ? ? ?NFADDR_REG = (addr >> 16) & 0xff;
? ? ? ? if (large_block)
? ? ? ? ? ?NFCMD_REG = NAND_CMD_READSTART;
? ? ? ? NF_TRANSRnB(); //等待NandFlash 狀態(tài)引腳可讀。
? ? ? ?/* for compatibility(2460). u32 cannot be used. by scsuh */
? ? ? ?for(i=0; i < page_size; i++)?
? ? ? ? {
? ? ? ? ? ? ? ? *buf++ = NFDATA8_REG;
? ? ? ? }
? ? ? ? NAND_DISABLE_CE();
? ? ? ? return 0;
}
尋址周期圖:
具體的說明請(qǐng)參考K9GAG08U0E ?DataSheet 第9頁(yè)。
這里用兩片文章寫了s3c6410支持K9GAG08U0E 的關(guān)鍵地方,當(dāng)然還有一些具體的細(xì)節(jié)了,比如給關(guān)鍵結(jié)構(gòu)體 nand ?chip,?mtd_device 等賦值Page大小,Block大小,OOB大小的操作,硬件ECC 8bit 糾錯(cuò)等功能,當(dāng)然這些不是K9GAG08U0E特有的功能,K9GAG08U0D也需要這樣的操作,這里就不詳細(xì)的介紹了。
希望這兩篇文章對(duì)需要了解NandFlash如何通過軟件工作的朋友有參考價(jià)值。
《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀
總結(jié)
以上是生活随笔為你收集整理的s3c6410 开发板Linux系统支持 K9GAG08U0E的方法的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Nandflash 驱动移植
- 下一篇: Maximum Allowed Erro