nandflash驱动详解
生活随笔
收集整理的這篇文章主要介紹了
nandflash驱动详解
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
對(duì)nandflash存儲(chǔ)原理不了解的請(qǐng)先閱讀《flash memory技術(shù)》
架構(gòu)圖
+ ----------- +系統(tǒng)總線+ ------------------- + CLE,io [8:0] + ----- -------------- + ?| cpu |←------------→| nand控制器| ←--------------→| nand flash | + ----------- + + ------------------- + + --------------- ---- +
cpu通過系統(tǒng)總線訪問nand控制器寄存器,設(shè)置讀寫flash的命令和相應(yīng)的地址,當(dāng)完成操作時(shí)nand controler發(fā)出中斷,也可以通過查詢nand controler的狀態(tài)寄存器來獲取操作狀態(tài),nand controler將相應(yīng)的命令狀態(tài)為nand flash能夠理解的時(shí)序
nand flash引腳
如果支持直接訪問模式,可以將nandflash直接映射到物理地址空間,通過XOR可以映射到不同的物理空間,這樣就可以直接從nandflash執(zhí)行程序了(注意不能寫,因?yàn)閷懼氨仨氁炔脸?#xff09;
NAND直接存取模式?
/ *禁止所有NAND CS的直接尋址+ XOR * / ????BDEV_UNSET(BCHP_NAND_CS_NAND_SELECT,0xff); ????BDEV_UNSET(BCHP_NAND_CS_NAND_XOR,0xff);
nandflash控制器全局寄存器
oob:spare_area 0x40 = 64byte 數(shù)據(jù):flash_cache 128字節(jié)= 128 * 4 = 512字節(jié)
1.BCHP_NAND_CS_NAND_SELECT: [0:0]? EBI_CS_0_SEL【0-7】每位對(duì)一個(gè)銀行 指示EBI_CS0b是否使用直接尋址機(jī)制,并將Nand Flash映射到MIPS物理地址空間,并使用EBI_CS_BASE_0寄存器指定的基址和大小。(EBI_CS_CONFIG_0將被忽略。)
(注意:建議軟件使用寄存器陣列尋址,除了初始引導(dǎo)讀取之外的所有Nand Flash訪問,無論此位是否設(shè)置,都可以使用寄存器陣列尋址。
1 =允許直接尋址EBI_CS0b。 0 =僅使用EBI_CS0b的寄存器陣列尋址。當(dāng)芯片從NAND閃存啟動(dòng)時(shí),該位被初始化。
[8:8] EBI_CS_0_USES_NAND 【8-15】每位對(duì)?? 一個(gè)銀行 指示EBI_CS0b是否連接到Nand Flash設(shè)備。該位不被硬件使用,但可由軟件用于指示哪些EBI_CS連接到Nand Flash器件。當(dāng)芯片從NAND閃存啟動(dòng)時(shí),該位被初始化。
保留 [27:16]
WR_PROTECT_BLK0 [28:28] RW? 該位將保護(hù)連接到EBI_CS0b的Nand Flash的塊0的內(nèi)容。該位置1時(shí),控制器將忽略目標(biāo)地址位于EBI_CS0b塊0中的閃存修改操作(PAGE_PROGRAM,ERASE等)。(塊大小由NAND_CONFIG_CS [n]寄存器的BLOCK_SIZE字段決定。)
1 =塊寫入EBI_CS0b塊0。 0 =允許寫入EBI_CS0b塊0。
復(fù)位值:0x0
NAND_WP [29:29] RW? 該位控制NAND_WPb引腳(通過反相器)以保護(hù)閃存器件。只要SW希望擦除或編程閃存,該位應(yīng)由SW清零。
(請(qǐng)注意,內(nèi)部電壓監(jiān)視器檢測VDD,并且當(dāng)VDD超出容許范圍時(shí),NAND_WPb被驅(qū)動(dòng)為低電平,無論此位的狀態(tài)如何。)
1 = NAND_WPb引腳為低電平。Flash受到寫保護(hù)。 0 = NAND_WPb引腳為高電平。Flash可以被擦除或編程。
重置值:0x1
AUTO_DEVICE_ID_CONFIG [30:30] RW? 如果設(shè)置了該位,則Nand Flash控制器將在任何其他Nand Flash訪問之前自動(dòng)執(zhí)行FLASH_RESET,然后執(zhí)行Read Device ID命令。從Nand Flash器件返回的值將被硬件用于基于內(nèi)部維護(hù)的已知Nand Flash器件的數(shù)據(jù)庫來初始化NAND_CONFIG_CS [n]寄存器。 當(dāng)strap_nand_flash = 1時(shí),該位??將被置1,并且讀取器件ID命令和NAND_CONFIG_CS [n]寄存器的初始化將在上電時(shí)發(fā)生。 如果軟件沒有設(shè)置該位,并且strap_nand_flash = 0,軟件應(yīng)該在使用Nand Flash控制器之前(在寫入CMD_START之前)執(zhí)行FLASH_RESET命令并初始化NAND_CONFIG_CS [n]寄存器。
1 =執(zhí)行FLASH_RESET和Device ID讀取,NAND_CONFIG_CS [n]寄存器自動(dòng)初始化。 0 =不要執(zhí)行設(shè)備ID讀取或NAND_CONFIG_CS [n]初始化。
當(dāng)芯片從NAND閃存啟動(dòng)時(shí),該位被初始化。
CS_LOCK [31:31] RW? 當(dāng)該位設(shè)置為1時(shí),該寄存器變?yōu)橹蛔x寄存器,防止進(jìn)一步寫入該寄存器。一旦設(shè)置,該位只能通過復(fù)位清零。
復(fù)位值:0x0
2.BCHP_NAND_CS_NAND_XOR EBI_CS_0_ADDR_XOR [0:0] RW?? 【0-7】每位對(duì)一個(gè)銀行 指示為EBI_CS0b指定的地址是否與0xE000_0000異或。 1 =與E000_0000到EBI_CS0b的XOR地址。 0 =直接將地址傳遞給EBI_CS0b(無XOR)。當(dāng)芯片從NAND閃存啟動(dòng)時(shí),該位被初始化。
保留 [30:8] RWX???
ONLY_BLOCK_0_XOR [31:31] RW? 僅對(duì)塊0打開地址XOR。CS0中的所有其他塊地址不會(huì)異或。 該位僅影響CS0,因?yàn)閴K0被定義為CS0器件的第一個(gè)塊。要使用該位,EBI_CS_0_ADDR_XOR也必須設(shè)置為1。 當(dāng)控制器空閑時(shí),軟件應(yīng)該改變這個(gè)位。 1 =僅對(duì)塊0使用E000_0000的XOR地址。 0 =所有塊的EOR_0000異或地址。
復(fù)位值:0x0
INTFC_STATUS - Nand Flash接口狀態(tài) CTLR_READY [31:31] R表示EBI內(nèi)部Nand Flash接口控制器狀態(tài)機(jī)邏輯已完成此接口的所有命令。
FLASH_READY [30:30] R反映外部Nand Flash器件的R / B(就緒/忙碌)引腳的即時(shí)狀態(tài)。(0 =忙碌)
CACHE_VALID [29:29] R指示512字節(jié)的FlashCache緩沖區(qū)是否包含位于FLASH_READ_ADDR寄存器指示的地址處的有效數(shù)據(jù)。
SPARE_AREA_VALID [28:28] R指示16字節(jié)備用區(qū)域讀取寄存器是否包含位于FLASH_READ_ADDR寄存器指示的地址處的有效數(shù)據(jù)。
ERASED [27:27] R指示最近的PAGE_READ命令是否導(dǎo)致數(shù)據(jù)和備用區(qū)域的所有字節(jié)均為FFh。
PLANE_READY [26:26] R僅適用于多平面設(shè)備。 指示EBI內(nèi)部Nand Flash接口控制器狀態(tài)機(jī)邏輯已在當(dāng)前平面上完成PROGRAM_PAGE_MULTI命令。
保留[25:8] RX???
FLASH_STATUS [7:0] R在每次程序頁面,塊擦除或復(fù)制命令操作后,使用來自閃存設(shè)備的狀態(tài)讀取命令更新此字節(jié)值。 復(fù)位值:0x0
每個(gè)銀行的配置寄存器: Brcm nandflash控制器最多支持7個(gè)銀行
BCHP_NAND_ACC_CONTROL_CS0? ? ? ? ? ? ? ?Nand Flash訪問控制?
RD_ECC_EN [31:31] RW為PAGE_READ操作啟用ECC校正。 重置值:0x1
WR_ECC_EN [30:30] RW為任何塊啟用對(duì)PROGRAM_PAGE或PROGRAM_SPARE_AREA操作的ECC校驗(yàn)位生成。當(dāng)該位置位時(shí),ECC字節(jié)將被忽略。 選擇漢明碼時(shí)的ECC字節(jié)位置是SPARE_AREA_WRITE_OFS_4和SPARE_AREA_WRITE_OFS_8寄存器的BYTE_OFS_6,BYTE_OFS_7和BYTE_OFS_8的3個(gè)字節(jié)。選擇BCH碼時(shí)的ECC字節(jié)位置是備用區(qū)域的最后字節(jié)位置。例如,如果SPARE_AREA_SIZE = 16且ECC_LEVEL = 4(7個(gè)ECC字節(jié)),則ECC字節(jié)位置是BYTE_OFS_9到BYTE_OFS_15中的16個(gè)字節(jié)中的最后7個(gè)。 當(dāng)此位設(shè)置為PROGRAM_PAGE操作時(shí),ECC字節(jié)將由H / W生成的ECC校驗(yàn)字節(jié)替代; 對(duì)于PROGRAM_SPARE_AREA操作,ECC字節(jié)將被FFh替換。 重置值:0x1
CE_CARE [29:29] RW此字段僅適用于CE護(hù)理設(shè)備。 當(dāng)設(shè)置為1時(shí),EBI_CS [n]將在NAND_RBb低電平期間保持置位狀態(tài)(器件忙)。在此期間,其他芯片選擇中的器件無法訪問。 默認(rèn)設(shè)置為0以獲得更好的性能。 復(fù)位值:0x0
保留 [28:28] RWX???
RD_ERASED_ECC_EN [27:27] RW確定擦除頁面中的PAGE_READ操作是否會(huì)生成不可糾正的ECC錯(cuò)誤。(一個(gè)Erased Page被定義為全部512個(gè)數(shù)據(jù)字節(jié),所有3個(gè)ECC字節(jié)都包含0xFF,剩余的Spare Area字節(jié)未被考慮)。無論該位的狀態(tài)如何,如果ECC被RD_ECC_EN = 0或RD_ECC_BLK0_EN = 0禁用,將不會(huì)生成錯(cuò)誤。 1 =從擦除頁讀取生成ECC錯(cuò)誤。 0 =從擦除頁讀取不會(huì)產(chǎn)生ECC錯(cuò)誤。 復(fù)位值:0x0
PARTIAL_PAGE_EN [26:26] RW啟用部分頁面編程。建議清除此位以提高性能并防止部分頁面編程,這是許多nand閃存設(shè)備所禁止的。??當(dāng)該位置位且軟件啟動(dòng)PROGRAM_PAGE操作時(shí),硬件將數(shù)據(jù)直接寫入閃存單元。當(dāng)該位清零并且軟件啟動(dòng)PROGRAM_PAGE操作時(shí),硬件將數(shù)據(jù)移入NAND Flash設(shè)備緩存并返回空閑狀態(tài)。只有當(dāng)NAND_CMD_ADDRESS指向頁面的最后512字節(jié)扇區(qū)時(shí),硬件才會(huì)將數(shù)據(jù)編程到閃存單元中。 小頁面設(shè)備會(huì)忽略該位。 復(fù)位值:0x0
WR_PREEMPT_EN [25:25] RW使能其他EBI或PCI周期的寫突發(fā)操作的搶占。當(dāng)另一個(gè)請(qǐng)求者試圖使用總線時(shí),這允許將來自Flash外部總線的長512字節(jié)突發(fā)分成16次傳輸?shù)亩鄠€(gè)突發(fā)。 重置值:0x1
PAGE_HIT_EN [24:24] RW啟用Flash頁面檢測檢測,作為頁面大小大于512B的頁面內(nèi)512字節(jié)讀取的優(yōu)化。該位僅為大頁面設(shè)備提供性能優(yōu)化。如果設(shè)置,并且硬件發(fā)現(xiàn)讀取未命中,但是從已經(jīng)讀入FlashCache的相同頁面,它將簡單地使用閃存的隨機(jī)讀取操作來節(jié)省時(shí)間。 重置值:0x1
PREFETCH_EN [23:23] RW硬件自動(dòng)讀取當(dāng)前頁面讀取命令地址的下一個(gè)512B或1KB數(shù)據(jù),扇區(qū)大小取決于SECTOR_SIZE_1K位。啟用此位可提高讀取連續(xù)地址的性能。 預(yù)取對(duì)軟件是透明的。CTLR_READY位始終指示當(dāng)前地址讀取完成。注:建議將此位設(shè)置為長連續(xù)讀取,例如DMA傳輸。如果讀取地址不連續(xù),則由于后臺(tái)預(yù)取,軟件可能會(huì)看到更長的繁忙時(shí)間和性能下降。 注:僅當(dāng)ECC_type為BCH時(shí)才支持預(yù)取。 復(fù)位值:0x0
CACHE_MODE_EN [22:22] RW啟用程序頁面或頁面讀取緩存模式。 如果置位,并且發(fā)出頁面讀取命令,硬件將啟動(dòng)具有緩存模式操作碼31h的頁面讀操作。 如果置位,并且發(fā)出程序頁命令,則硬件以高速緩存模式操作碼15h結(jié)束程序頁操作。 緩存模式通過連續(xù)頁面訪問跳過閃存設(shè)備繁忙時(shí)間來提高性能。例如:第n,n + 1,n + 2,n + 3,n + 4 ... n + m的DMA傳輸 注:硬件不檢測頁面地址的連貫性。軟件需要管理設(shè)置這一點(diǎn)。要恢復(fù)正常的頁面讀取和程序頁面命令,請(qǐng)取消設(shè)置此位。 復(fù)位值:0x0
保留 [21:21] RWX???
ECC_LEVEL [20:16] RW設(shè)置每512個(gè)數(shù)據(jù)字節(jié)可以糾正的編碼類型和位數(shù)。 定義T:=每扇區(qū)可修正的位數(shù)。 當(dāng)SECTOR_SIZE_1K = 0時(shí),則T = ECC_LEVEL 當(dāng)SECTOR_SIZE_1K = 1時(shí),則T = ECC_LEVEL * 2 異常是SECTOR_SIZE_1K = 0,SPARE_AREA_SIZE = 16,ECC_LEVEL = 15,則T = 1(海明模式)
保留 [15:8] RWX???
SECTOR_SIZE_1K [7:7] RW定義ECC碼字大小,也稱為扇區(qū)大小。注意:當(dāng)使用1k字節(jié)扇區(qū)大小時(shí),ECC_LEVEL字段指定T值的一半,漢明碼不可用。 請(qǐng)參閱ECC_LEVEL說明中顯示的表。 注意:當(dāng)使用1k字節(jié)扇區(qū)大小時(shí),必須清除PARTIAL_PAGE_EN位,并且閃存頁面大小必須大于512。 0 512字節(jié) 1個(gè)1k字節(jié)
當(dāng)strap_nand_flash = 1時(shí),該字段將根據(jù)選定的ECC級(jí)別綁定在strap_nand_ecc_level [n:0]上進(jìn)行初始化。 復(fù)位值:0x0
SPARE_AREA_SIZE [6:0] RW表示每512個(gè)數(shù)據(jù)字節(jié)包含在閃存設(shè)備中的備用區(qū)字節(jié)數(shù)。有效設(shè)置是16到64(含)。對(duì)于16位寬的NAND閃存器件,此字段必須包含偶數(shù)。 對(duì)于大頁面設(shè)備(頁面大小為2kB或更大),每頁的備用區(qū)域除以每頁的扇區(qū)數(shù)量。??例如,(2kB + 64B)頁面大小和512B扇區(qū)大小每頁有4個(gè)扇區(qū),每頁全部64字節(jié)備用區(qū)域?qū)⒈环殖?個(gè)相等的部分,每個(gè)16字節(jié); 并且這些部分中的每一個(gè)都將被不同的部門使用。 選擇漢明碼時(shí)的ECC字節(jié)位置是SPARE_AREA_WRITE_OFS_4和SPARE_AREA_WRITE_OFS_8寄存器的BYTE_OFS_6,BYTE_OFS_7和BYTE_OFS_8的3個(gè)字節(jié)。 選擇BCH碼時(shí)的ECC字節(jié)位置是該特定扇區(qū)的備用區(qū)的最后一個(gè)字節(jié)位置。??例如,如果SPARE_AREA_SIZE = 16且ECC_LEVEL = 4(7個(gè)ECC字節(jié)),則ECC字節(jié)位置是BYTE_OFS_9到BYTE_OFS_15中的16個(gè)字節(jié)中的最后7個(gè)。 當(dāng)SECTOR_SIZE_1K = 1時(shí),該字段仍指定每512個(gè)備用字節(jié)。
當(dāng)strap_nand_flash = 1時(shí),該字段將根據(jù)選定的ECC級(jí)別綁定在strap_nand_ecc_level [n:0]上進(jìn)行初始化。 重置值:0x10
因?yàn)镋CC校驗(yàn)是由控制器自動(dòng)完成的,那么就必須讓控制器知道該bank上的nandflash使用的ECC LEVEL和SPARE_AREA_SIZE,這樣控制器就能知道ECC字節(jié)在SPARE_AREA_READ_OFS_0中的位置.ECC字節(jié)在nandflash中的位置理論上來說跟nandflash沒有多大關(guān)系,因?yàn)閚andflash對(duì)ECC字節(jié)是無知的,它由控制器來使用,nandflash會(huì)根據(jù)本身工藝推薦ECC LEVEL,理論上大于這個(gè)值都是可行的。
BCHP_NAND_CONFIG_EXT_CS0?????????? Nand Flash配置擴(kuò)展? 閃存設(shè)備接口參數(shù)。根據(jù)NAND_CMD_EXT_ADDRESS寄存器中的CS_SEL值,硬件會(huì)根據(jù)剛剛復(fù)位后從外部Nand Flash器件讀取的DeviceID或ONFI參數(shù)值將缺省值裝入此寄存器。
保留[31:12] RWX???
BLOCK_SIZE [11:4] RW塊大小(以字節(jié)為單位)。(注意:該字段僅用于確定目標(biāo)地址是否位于閃存的塊0中,以便在WR_PROTECT_BLK0位置位時(shí)知道是否應(yīng)用寫保護(hù),或者當(dāng)RD_ECC_BLK0_EN位為是時(shí)是否執(zhí)行ECC糾正組。) 值名稱 0 BK_SIZE_8KB 1 BK_SIZE_16KB 2 BK_SIZE_32KB 3 BK_SIZE_64KB 4 BK_SIZE_128KB 5 BK_SIZE_256KB 6 BK_SIZE_512KB 7 BK_SIZE_1024KB 8 BK_SIZE_2048KB 9 BK_SIZE_4096KB 10 BK_SIZE_8192KB
PAGE_SIZE [3:0] RW頁面大小(以字節(jié)為單位)。 值名稱說明 0 PG_SIZE_512 512字節(jié)。 1 PG_SIZE_1KB 1k字節(jié)。 2 PG_SIZE_2KB 2k字節(jié)。 3 PG_SIZE_4KB 4k字節(jié)。 4 PG_SIZE_8KB 8k字節(jié)。 5 PG_SIZE_16KB 16k字節(jié)。
BCHP_NAND_CONFIG_CS0????????????????? Nand Flash配置 閃存設(shè)備接口參數(shù)。根據(jù)NAND_CMD_EXT_ADDRESS寄存器中的CS_SEL值,硬件會(huì)根據(jù)剛剛復(fù)位后從外部Nand Flash器件讀取的DeviceID或ONFI參數(shù)值將缺省值裝入此寄存器。
CONFIG_LOCK [31:31] RW當(dāng)該位設(shè)置為1時(shí),該寄存器和CONFIG_EXT寄存器變?yōu)橹蛔x寄存器,防止進(jìn)一步寫入該寄存器和CONFIG_EXT寄存器。一旦設(shè)置,該位只能通過復(fù)位清零。 復(fù)位值:0x0
保留[30:28] RWX???
DEVICE_SIZE [27:24] RW設(shè)備大小(以字節(jié)為單位)。 值名稱 0 DVC_SIZE_4MB 1 DVC_SIZE_8MB 2 DVC_SIZE_16MB 3 DVC_SIZE_32MB 4 DVC_SIZE_64MB 5 DVC_SIZE_128MB 6 DVC_SIZE_256MB 7 DVC_SIZE_512MB 8 DVC_SIZE_1GB 9 DVC_SIZE_2GB 10 DVC_SIZE_4GB 11 DVC_SIZE_8GB 12 DVC_SIZE_16GB 13 DVC_SIZE_32GB 14 DVC_SIZE_64GB 15 DVC_SIZE_128GB
DEVICE_WIDTH [23:23] RW設(shè)備I / O數(shù)據(jù)總線寬度(以位為單位)。 值名稱 0 DVC_WIDTH_8 1 DVC_WIDTH_16
保留[22:19] RWX???
FUL_ADR_BYTES [18:16] RW在設(shè)備內(nèi)發(fā)送到Flash的完整地址的地址字節(jié)數(shù)。 當(dāng)PAGE_SIZE> 512B時(shí),FUL_ADR_BYTES = COL_ADR_BYTES + BLK_ADR_BYTES。 當(dāng)PAGE_SIZE = 512B時(shí),FUL_ADR_BYTES = 1 + BLK_ADR_BYTES。 該字段通過綁定或AUTO_DEVICE_ID_CONFIG初始化。
保留[15:15] RWX???
COL_ADR_BYTES [14:12] RW發(fā)送到Flash以指定頁面內(nèi)隨機(jī)數(shù)據(jù)訪問的列地址的地址字節(jié)數(shù)。該字段僅用于頁面大小大于512B的頁面,用于頁面內(nèi)的隨機(jī)尋址,以尋址PROGRAM_PAGE和PAGE_READ命令的備用區(qū)域。 2為512B <=頁面大小<= 32KB 該字段通過綁定或AUTO_DEVICE_ID_CONFIG初始化。
保留[11:11] RWX???
BLK_ADR_BYTES [10:8] RW發(fā)送到Flash以指定行和塊的地址字節(jié)數(shù)。該字段相當(dāng)于NAND閃存數(shù)據(jù)表中的頁面地址+塊地址。 該字段僅用于BLOCK_ERASE和BLOCKS_UNLOCK命令。 該字段通過綁定或AUTO_DEVICE_ID_CONFIG初始化。
保留[7:0] RWX???
BCHP_NAND_TIMING_1_CS0???????????????? ?Nand Flash時(shí)序參數(shù)1? 閃存設(shè)備接口時(shí)序參數(shù)。時(shí)序以內(nèi)部108 MHz時(shí)鐘(9.26 ns)或內(nèi)部216 MHz時(shí)鐘(4.63 ns)為單位指定,具體取決于TIMING_2.CLK_SELECT的值。 任何時(shí)間字段中的最小值是2(2個(gè)時(shí)鐘)。
tWP [31:28] RW時(shí)鐘數(shù)WE低脈沖寬度。
重置值:0x6 tWH [27:24] RW片段數(shù)WE高脈沖寬度。(除了ALE較高時(shí),在這種情況下,tALH控制WE高脈沖寬度而不是tWH。)
重置值:0x5 tRP [23:20] RW時(shí)鐘數(shù)RE低脈沖寬度。
重置值:0x7 tREH [19:16] RW時(shí)鐘數(shù)RE高脈沖寬度。
重置值:0x4 tCS [15:12] RW從CE低到第一個(gè)WE低的時(shí)鐘數(shù)。注意:當(dāng)CLK_SELECT = CLK_108時(shí),該寄存器字段中的值將被硬件加倍,當(dāng)CLK_SELECT = CLK_216時(shí),該值將被硬件加倍。
重置值:0x8 tCLH [11:8] RW從WE高到CLE低的塊數(shù)。
重置值:0x4 tALH [7:4] RW從WE高到ALE低的時(shí)針數(shù)量。而且,當(dāng)ALE高時(shí),屏幕的數(shù)量WE高脈沖寬度。該位應(yīng)該被設(shè)置為來自閃存制造商數(shù)據(jù)表的tWH和tALH之間的較大值。
重置值:0x5 tADL [3:0] RW從最后一個(gè)addr到第一次數(shù)據(jù)寫入的時(shí)鐘片數(shù)。注意:當(dāng)CLK_SELECT = CLK_108時(shí),該寄存器字段中的值將被硬件加倍,當(dāng)CLK_SELECT = CLK_216時(shí),該值將被硬件加倍。
復(fù)位值:0xB
BCHP_NAND_TIMING_2_CS0?????????????????? ?Nand Flash時(shí)序參數(shù)2? 閃存設(shè)備接口時(shí)序參數(shù)。時(shí)序以內(nèi)部108 MHz時(shí)鐘(9.26 ns)或內(nèi)部216 MHz時(shí)鐘(4.63 ns)為單位指定,具體取決于TIMING_2.CLK_SELECT的值。 任何時(shí)間字段中的最小值是2(2個(gè)時(shí)鐘)。
CLK_SELECT [31:31] RW確定NAND_TIMING_1和NAND_TIMING_2中的參數(shù)用于nand閃存定時(shí)狀態(tài)機(jī)的時(shí)鐘。 值名稱說明 0 CLK_108內(nèi)部108 MHz時(shí)鐘。 1 CLK_216內(nèi)部216 MHz時(shí)鐘。
重置值:CLK_108 保留[30:20] RWX??? tCCS [19:16] RW更改列命令設(shè)置時(shí)間。 注:當(dāng)CLK_SELECT = CLK_108時(shí),硬件將該寄存器字段中的值翻兩倍,并且當(dāng)CLK_SELECT = CLK_216時(shí),該值將由硬件八倍。
重置值:0x9 保留[15:13] RWX??? tWB [12:9] RW在硬件開始采樣R / B引腳之前,CE的高電平時(shí)鐘數(shù)。注意:當(dāng)CLK_SELECT = CLK_108時(shí),該寄存器字段中的值將被硬件加倍,當(dāng)CLK_SELECT = CLK_216時(shí),該值將被硬件加倍。
復(fù)位值:0xF tWHR [8:4] RW從WE高到RE低的時(shí)鐘片數(shù)。此參數(shù)僅用于狀態(tài)讀取和設(shè)備ID讀取操作。注意:當(dāng)CLK_SELECT = CLK_108時(shí),該寄存器字段中的值將被硬件加倍,當(dāng)CLK_SELECT = CLK_216時(shí),該值將被硬件加倍。
重置值:0x9 tREAD [3:0] RW RE低后采樣讀取數(shù)據(jù)之前等待的時(shí)鐘數(shù)。
為獲得最佳性能,應(yīng)通過將nns閃存器件的RE存取時(shí)間(tREA)加上17ns,然后將總和除以CLK_SELECT所選的時(shí)鐘周期,然后將其四舍五入至下一較大整數(shù)來計(jì)算此參數(shù)。例如,如果器件tREA = 20ns并且CLK_SELECT = 1(216MHz => 4.63ns): tREAD =(20ns + 17ns)/4.63ns=7.99(四舍五入)=> 8。
tREAD的最大值是(tRP + tREH)。
重置值:0x6
操作時(shí)序 在編程操作中,要被編程的數(shù)據(jù)在WE#的上升沿被同步到數(shù)據(jù)寄存器中。 數(shù)據(jù)以類似的方式通過讀使能(RE#)信號(hào)從數(shù)據(jù)寄存器輸出,該信號(hào)負(fù)責(zé)輸出當(dāng)前數(shù)據(jù)并遞增到下一個(gè)位置。WE#和RE#時(shí)鐘每次傳輸可以運(yùn)行25ns。當(dāng)RE#或芯片使能(CE#)未置為低電平時(shí),輸出緩沖器為三態(tài)。CE#和RE#的這種組合激活了輸出緩沖器,使NAND Flash能夠與其他類型的存儲(chǔ)器(如NOR閃存,SRAM或DRAM)共享數(shù)據(jù)總線。這個(gè)功能有時(shí)被稱為“芯片使能不關(guān)心”。 在RE#為低時(shí),讀使能,輸出緩沖器直接放置在io上,可跟著變化。 所有的NAND Flash操作都是通過發(fā)出一個(gè)命令周期來啟動(dòng)的。這是通過將命令放在I / O [7:0]上,驅(qū)動(dòng)CE#為低電平并且為高電平,然后發(fā)出WE#時(shí)鐘來完成的。命令,地址和數(shù)據(jù)在WE#的上升沿時(shí)鐘輸入NAND閃存器件, 大多數(shù)命令需要多個(gè)地址周期,然后是第二個(gè)命令周期。除RESET和READ STATUS命令外,當(dāng)設(shè)備忙時(shí)不應(yīng)發(fā)出新命令。 支持的命令:
2Gb NAND Flash器件的尋址方案如表6所示。第一個(gè)和第二個(gè)地址周期(或字節(jié))指定了列地址,它指定了頁面內(nèi)的起始字節(jié)。最后一列的位置是2112,因此最后一個(gè)位置的地址是第二個(gè)字節(jié)中的08h,第一個(gè)字節(jié)中是3Fh。PA [5:0]指定塊內(nèi)的頁面地址,BA [16:6]指定塊地址。盡管大多數(shù)PROGRAM和READ操作需要完整的5字節(jié)地址,但對(duì)于在頁面內(nèi)隨機(jī)訪問數(shù)據(jù)的操作,只需要第一個(gè)和第二個(gè)字節(jié)(或循環(huán))。BLOCK ERASE操作只需要三個(gè)最重要的字節(jié)(第三,第四和第五)來選擇該塊。
當(dāng)CA11 = 1時(shí)表示訪問oob數(shù)據(jù),一般列地址都為0,表示從頁面內(nèi)偏移0開始訪問整個(gè)頁面。
復(fù)位操作 RESET是NAND Flash器件繁忙時(shí)可以發(fā)出的兩個(gè)命令之一。如果設(shè)備正忙于處理先前的命令,則發(fā)出RESET命令會(huì)中止前一個(gè)操作。如果之前的操作是ERASE或PROGRAM命令,則發(fā)出RESET命令會(huì)過早地中止該命令,并且所需的操作不會(huì)完成。ERASE和PROGRAM可以是耗時(shí)的操作; 發(fā)出RESET命令可以中止或稍后重新發(fā)出命令。
CE先拉低選中芯片,在io [8:0]上放置FFh,然后CLE拉高,將io [8:0]與命令鎖存器相連,然后將WE拉低,接著拉高,在上升沿完成命令的寫操作,延時(shí)TWB后查詢R / B腳的狀態(tài),當(dāng)為1時(shí)表示RESET完成。
READ ID操作 READ ID(90h)命令需要一個(gè)虛擬地址周期(00h),但不需要第二個(gè)命令周期。在發(fā)出命令和虛擬地址后,通過保持CLE和ALE為低電平并讀取ID的每個(gè)字節(jié)的RE#信號(hào),可以讀出ID數(shù)據(jù)。
CE先拉低選中chip,在io [8:0]上放置90h,然后CLE拉高,將io [8:0]與命令鎖存器相連,然后將WE拉低,接著拉高,在上升沿完成命令的寫操作,然后拉低CLE,拉高ALE,將io [8:0]與地址鎖存器相連,在io [8:0]上放置00h,然后將WE拉低,然后拉高WE ,在上升沿完成addrees的寫操作,接著拉低ALE,適當(dāng)?shù)难訒r(shí)后拉低RE,(CLE和ALE都為低時(shí),IO [8:0]與數(shù)據(jù)鎖存器相連,CLE和ALE都為高時(shí)為非法),chip將數(shù)據(jù)放置在io [8:0]上,nand controler從io [8:0]上讀取數(shù)據(jù),讀完后RE拉高,然后拉低讀取下一個(gè)字節(jié)。
READ STATUS操作 讀取狀態(tài)(70h)是NAND Flash器件忙時(shí)可以發(fā)出的第二個(gè)命令。該命令不需要地址或第二個(gè)命令周期。通過在READ STATUS命令之后發(fā)出RE#時(shí)鐘信號(hào),可以監(jiān)控NAND閃存器件的狀態(tài)。如果使用READ STATUS命令監(jiān)視器件的就緒狀態(tài),則該命令只能發(fā)出一次,并且可以通過重新發(fā)出RE#時(shí)鐘來重新讀取狀態(tài)。或者,RE#信號(hào)可以保持低電平,在繼續(xù)之前等待接收適當(dāng)?shù)臓顟B(tài)位。READ STATUS還會(huì)報(bào)告寫保護(hù)信號(hào)的狀態(tài)以及之前PROGRAM或ERASE操作的通過/失敗狀態(tài)。在PROGRAM或ERASE操作中必須達(dá)到合格狀態(tài)以確保數(shù)據(jù)完整性。
擦除操作 BLOCK ERASE(60h)操作會(huì)擦除整個(gè)64頁的頁面,總共128KB。要發(fā)出BLOCK ERASE操作,使用WE#信號(hào)在CLE置位時(shí)在ERASE(60h)命令中計(jì)時(shí)。接下來,在三個(gè)地址周期中的時(shí)鐘,保持每個(gè)字節(jié)地址的ALE有效。(這三個(gè)地址周期是最重要的地址周期,包括塊地址和頁地址,如第9頁的表6所示。)頁地址部分(第三個(gè)地址周期的六個(gè)低位)被忽略,并且只使用三個(gè)最高有效字節(jié)的塊地址部分。地址完全輸入后,發(fā)出D0h的第二個(gè)命令(命令周期2),當(dāng)CLE置位時(shí),它由WE#提供時(shí)鐘。這確認(rèn)了ERASE操作,并且設(shè)備忙了大約500μs。當(dāng)設(shè)備完成此操作時(shí),它已準(zhǔn)備好執(zhí)行另一個(gè)命令。READ STATUS命令可以隨時(shí)發(fā)出,即使在ERASE操作過程中設(shè)備處于繁忙狀態(tài)。微處理器或控制器可以通過READ STATUS命令監(jiān)視設(shè)備
提交70H命令查詢狀態(tài)后,RE一直為低,監(jiān)控IO [5]引腳上的值,為0時(shí)表示擦除完成
程序操作 PROGRAM操作只能將位編程為0,并假定用戶以先前擦除的塊開始。如果用戶不想編程一個(gè)位(或一組位),則通過將該特定位/組設(shè)置為1,可以將位保持在擦除狀態(tài)。當(dāng)接收到編程頁(80h)命令時(shí),輸入寄存器被重置(內(nèi)部)到全1。這支持只輸入要用0位編程的數(shù)據(jù)字節(jié)。PROGRAM操作從80h命令開始(CLE置位 - 見圖8)。接下來,取消斷言CLE并斷言ALE輸入完整的五個(gè)地址周期。輸入命令和地址后,數(shù)據(jù)輸入到寄存器。當(dāng)所有的數(shù)據(jù)都被輸入時(shí),發(fā)出10h命令來確認(rèn)前一個(gè)命令并開始編程操作。PROGRAM操作通常需要220μs,雖然它可能需要多達(dá)600μs。用戶必須閱讀狀態(tài)并檢查操作是否成功。如果操作不成功,則該塊應(yīng)該記錄為壞塊并且將來不會(huì)使用。所有的數(shù)據(jù)應(yīng)該移到一個(gè)好的塊。
可以編程1-2112個(gè)字節(jié),根據(jù)col add,如果頁內(nèi)偏移為0,即編程整個(gè)頁,則2112個(gè)字節(jié)
READ操作 READ操作從00h命令開始,隨后是5個(gè)地址周期,然后是30h命令以確認(rèn)命令序列。經(jīng)過大約25μs的讀取傳輸時(shí)間(t R)后,數(shù)據(jù)被加載到寄存器并準(zhǔn)備輸出。置位RE#使NAND Flash器件能夠輸出與地址中指定的列地址相對(duì)應(yīng)的數(shù)據(jù)的第一個(gè)字節(jié)。隨后的RE#從連續(xù)的列位置轉(zhuǎn)換輸出數(shù)據(jù)。當(dāng)RE#信號(hào)為高(未置位)時(shí),I / O線為三態(tài)。讀取設(shè)備末尾(字節(jié)2112或字1056)會(huì)導(dǎo)致無效數(shù)據(jù)。
READ PAGE CACHE SEQUENTIAL操作 至此只討論了NAND??閃存器件中的一個(gè)寄存器。NAND Flash器件實(shí)際上有兩個(gè)寄存器,一個(gè)數(shù)據(jù)寄存器和一個(gè)高速緩存寄存器,如圖12所示。這兩個(gè)寄存器的屬性在各種NAND Flash緩存模式中起著重要的作用。PAGE READ CACHE MODE命令使用戶能夠在輸出先前訪問的數(shù)據(jù)的同時(shí)從數(shù)組中流水線化下一個(gè)順序訪問。這種雙緩沖技術(shù)可以隱藏讀取傳輸時(shí)間(t R)。數(shù)據(jù)最初從NAND閃存陣列傳輸?shù)綌?shù)據(jù)寄存器。如果高速緩存寄存器可用(不忙),數(shù)據(jù)將很快從數(shù)據(jù)寄存器移至高速緩存寄存器。數(shù)據(jù)傳輸?shù)礁咚倬彺婕拇嫫骱?#xff0c;數(shù)據(jù)寄存器可用,并且可以開始加載NAND閃存陣列中的下一個(gè)連續(xù)頁面。與8位I / O設(shè)備上的傳統(tǒng)PAGE READ命令相比,使用PAGE READ CACHE MODE命令可提高33%的性能,吞吐量可達(dá)31 MB / s。在16位I / O設(shè)備上,吞吐量可以提高到37 MB / s,與普通的PAGE READ操作相比,性能提高40%。 www.micron.com/products/nand/technotes上的技術(shù)說明提供了有關(guān)緩存模式的更多詳細(xì)信息以及如何使用它們來提高性能。PAGE READ CACHE MODE在系統(tǒng)啟動(dòng)時(shí)特別有用,當(dāng)大量數(shù)據(jù)通常從NAND閃存設(shè)備中讀取并且啟動(dòng)時(shí)間非常關(guān)鍵時(shí)。
PROGRAM PAGE CACHE操作 PROGRAM PAGE CACHE MODE提供比正常PROGRAM PAGE操作更高的性能(見圖14和15)。PROGRAM PAGE CACHE MODE是一種雙緩沖技術(shù),它使控制器能夠?qū)?shù)據(jù)直接輸入到高速緩存寄存器,并使用數(shù)據(jù)寄存器作為存儲(chǔ)區(qū)來提供用于編程陣列的數(shù)據(jù)。這將釋放高速緩存寄存器,以便可以并行加載下一個(gè)順序頁面操作。在許多應(yīng)用中,編程時(shí)間(t PROG)可以完全隱藏。與PAGE READ CACHE MODE命令一樣,數(shù)據(jù)寄存器用于在整個(gè)編程周期內(nèi)保持?jǐn)?shù)據(jù)吞吐量。這將釋放緩存寄存器以接收來自控制器的下一頁數(shù)據(jù)。
存儲(chǔ)方法 圖10顯示了將數(shù)據(jù)和備用信息存儲(chǔ)在同一頁面的兩種常用方法。第一種方法顯示512字節(jié)的數(shù)據(jù)區(qū)加上與其直接相鄰的16字節(jié)備用區(qū); 組合區(qū)域?yàn)?28字節(jié)。一個(gè)2112字節(jié)的頁面可以包含這些528字節(jié)元素中的四個(gè)。第二個(gè)實(shí)施涉及單獨(dú)存儲(chǔ)數(shù)據(jù)和備用信息。四個(gè)512字節(jié)的數(shù)據(jù)區(qū)首先被存儲(chǔ),并且它們對(duì)應(yīng)的16字節(jié)備用區(qū)按順序依次位于頁面的末尾。
至于具體采用哪種存儲(chǔ)方式,由控制器決定,在NANDFLASH看來,數(shù)據(jù)和OOB并沒有什么區(qū)別.BRCM控制器采用的第二種方式。
部分頁面編程 與NAND接口一致,NAND中的基本編程單元是一個(gè)頁面; 然而,通過利用部分頁面編程,可以將頁面編程成更小的部分。為了便于部分頁面編程,每個(gè)頁面被進(jìn)一步分成八個(gè)段(數(shù)據(jù)區(qū)域四個(gè),備用區(qū)域四個(gè))。 頁面中的每個(gè)段都充當(dāng)獨(dú)立的可編程單元; 它們可以單獨(dú)編程或以任何組合段編程。每個(gè)片段允許的最大連續(xù)部分頁面程序數(shù)量為1。也就是說,頁面中的每個(gè)段可以被編程一次,并且在需要塊擦除之前頁面可以被編程多達(dá)八次。 部分頁面編程通過發(fā)出一個(gè)輸入命令(80h),然后是多段編程的隨機(jī)數(shù)據(jù)輸入命令(85h)序列完成。加載最后一個(gè)數(shù)據(jù)后,程序確認(rèn)命令(10h)啟動(dòng)編程操作并將數(shù)據(jù)寫入到所需位置的緩沖區(qū)中。寫狀態(tài)位(I / O0)可以通過命令(70h)進(jìn)行驗(yàn)證,以驗(yàn)證編程是否成功。
部分頁面讀取 部分頁面讀取是通過發(fā)出一個(gè)讀取命令(00h),然后是一個(gè)隨機(jī)數(shù)據(jù)讀取命令(05h)序列來完成多段讀取。?
讀取內(nèi)部數(shù)據(jù)移動(dòng)操作 READ FOR INTERNAL DATA MOVE(00h-35h)命令也被稱為“復(fù)制”。它提供了將數(shù)據(jù)從一個(gè)頁面內(nèi)部移動(dòng)到另一個(gè)頁面的能力 - 數(shù)據(jù)永遠(yuǎn)不會(huì)離開NAND Flash設(shè)備。READ FOR INTERNAL DATA MOVE操作將從NAND閃存陣列讀取的數(shù)據(jù)傳輸?shù)礁咚倬彺婕拇嫫鳌?/span>數(shù)據(jù)可以被編程到設(shè)備的另一個(gè)頁面中。這在控制器在擦除塊之前需要將數(shù)據(jù)從塊中移出的情況下非常有用。在PROGRAM操作開始之前,也可以修改讀取的數(shù)據(jù)。如果用戶想在編程之前更改數(shù)據(jù),這很有用。此功能可在NAND Flash設(shè)備內(nèi)移動(dòng)數(shù)據(jù),而無需占用處理器或I / O總線。
代碼分析 static uint32_t do_nand_cmd(struct nand_probe_info * info,uint32_t cmd, ????????uint64_t addr) { ????int t = 100 * 1000; / * 100ms * /
????BDEV_WR(BCHP_NAND_CMD_EXT_ADDRESS, ????????????(info-> cs << 16)| ((addr >> 32)&0xffff)); ????BDEV_WR(BCHP_NAND_CMD_ADDRESS,addr&0xffffffff); ????BDEV_WR_F(NAND_CMD_START,操作碼,cmd);
????while(!BDEV_RD_F(NAND_INTFC_STATUS,CTLR_READY)){ ????????如果(t <= 0) ????????????打破; ????????bolt_usleep(1);
????????t - = 1; ????}
???如果(!BDEV_RD_F(NAND_INTFC_STATUS,CTLR_READY)) ???????????err_msg(“NAND:超時(shí)等待命令(%#04x @%llx)[%d,%d]”, ????????????????cmd,addr, ????????????????BDEV_RD_F(NAND_INTFC_STATUS,CTLR_READY), ????????????????BDEV_RD_F(NAND_INTFC_STATUS,FLASH_READY));
????返回BDEV_RD(BCHP_NAND_INTFC_STATUS)&NAND_STATUS_FAIL; } BRCM的nand controler比較智能,我們只需要設(shè)置要進(jìn)行的操作和地址,控制器會(huì)自動(dòng)解釋發(fā)出芯片能夠理解的命令和地址。
Linux的內(nèi)核中關(guān)于NANDFLASH的代碼: include / mtd / mtd-abi.h中定義的nand_ecclayout 結(jié)構(gòu)指定OOB備用區(qū)域的布局:? struct nand_ecclayout { uint 32_t eccbytes; uint32_t eccpos [64]; uint32_t oobavail; struct nand_oobfree oobfree [MTD_MAX_OOBFREE_ENTRIES]; };
在此結(jié)構(gòu)中,eccbytes 保存存儲(chǔ)ECC數(shù)據(jù)的OOB字節(jié)的數(shù)量,eccpos 是包含ECC數(shù)據(jù)的OOB區(qū)域的偏移量數(shù)組。oobfree 將可用于閃存文件系統(tǒng)的OOB區(qū)域中未使用的字節(jié)記錄為用于存儲(chǔ)標(biāo)志的標(biāo)志,例如清除標(biāo)志,表示擦除操作成功完成。 各個(gè)NAND程序驅(qū)動(dòng)根據(jù)芯片的屬性初始化它們的nand_ecclayout static struct nand_ecclayout * brcmstb_nand_create_layout(int ecc_level, ????????struct brcmstb_nand_cfg * cfg) { ????int i,j; ????struct nand_ecclayout * layout; ????int req; ????整個(gè)行業(yè); ????int sas; ????int idx1,idx2;
????layout = kzalloc(sizeof(* layout),GFP_KERNEL); ????if(!layout){ ????????pr_err(“%s:無法分配內(nèi)存\ n”,__func__); ????????返回NULL; ????}
????sector = cfg-> page_size /(512 << cfg-> sector_size_1k); ????sas = cfg-> spare_area_size << cfg-> sector_size_1k;
????/ *漢明* / ????if(is_hamming_ecc(cfg)){ ????????for(i = 0,idx1 = 0,idx2 = 0; i <sectors; i ++){ ????????????/ *每個(gè)頁面的第一個(gè)扇區(qū)可能有BBI * / ????????????if(i == 0){ ????????????????layout-> oobfree [idx2] .offset = i * sas + 1; ????????????????/ *小頁面NAND使用字節(jié)6用于BBI * / ????????????????if(cfg-> page_size == 512) ????????????????????布局 - > oobfree [IDX2] .offset--; ????????????????layout-> oobfree [idx2] .length = 5; ????????????} else { ????????????????layout-> oobfree [idx2] .offset = i * sas; ????????????????layout-> oobfree [idx2] .length = 6; ????????????} ????????????IDX2 ++; ????????????layout->eccpos[idx1++] = i * sas + 6; ????????????layout->eccpos[idx1++] = i * sas + 7; ????????????layout->eccpos[idx1++] = i * sas + 8;? ? ? //對(duì)于Hamming, 6,7,8 byte為Hamming ECC ????????????layout->oobfree[idx2].offset = i * sas + 9; ????????????layout->oobfree[idx2].length = 7; ????????????idx2++; ????????????/* Leave zero-terminated entry for OOBFREE */ ????????????if (idx1 >= MTD_MAX_ECCPOS_ENTRIES_LARGE || ????????????????????idx2 >= MTD_MAX_OOBFREE_ENTRIES_LARGE - 1) ????????????????break; ????????} ????????goto out; ????}
????/* ???? * CONTROLLER_VERSION: ???? *???< v5.0: ECC_REQ = ceil(BCH_T * 13/8) ???? *??>= v5.0: ECC_REQ = ceil(BCH_T * 14/8)??[see SWLINUX-2038] ???? * But we will just be conservative. ???? */ ????req = (ecc_level * 14 + 7) / 8;? ? ? // 根據(jù)ECC LEVEL得到需要的ECC byte數(shù) ????if (req >= sas) { ????????pr_info("%s: ECC too large for OOB, using dummy layout\n", ????????????__func__); ????????memcpy(layout, &brcmstb_nand_dummy_layout, sizeof(*layout)); ????????return layout; ????}
????DBG("OOBLAYOUT: sas=%d??req=%d??sectors=%d\n", sas, req, sectors);
????layout->eccbytes = req * sectors; ????for (i = 0, idx1 = 0, idx2 = 0; i < sectors; i++) { ????????for (j = sas - req; j < sas && idx1 < ????????????????MTD_MAX_ECCPOS_ENTRIES_LARGE; j++, idx1++) ????????????layout->eccpos[idx1] = i * sas + j;? ? ? ? //對(duì)于BCH,ECC byte放在每個(gè)oob的最后面
????????/* First sector of each page may have BBI */ ????????if (i == 0) { ????????????if (cfg->page_size == 512 && (sas - req >= 6)) {? ?//小頁使用byte 6指示壞塊,一般page size都是2k ????????????????/* Small-page NAND use byte 6 for BBI */ ????????????????layout->oobfree[idx2].offset = 0; ????????????????layout->oobfree[idx2].length = 5; ????????????????idx2++; ????????????????if (sas - req > 6) { ????????????????????layout->oobfree[idx2].offset = 6; ????????????????????layout->oobfree[idx2].length = ????????????????????????sas - req - 6; ????????????????????idx2++; ????????????????} ????????????} else if (sas > req + 1) { ????????????????layout->oobfree[idx2].offset = i * sas + 1;? ? ?//使用byte 0?指示壞塊 ????????????????layout->oobfree[idx2].length = sas - req - 1; ????????????????idx2++; ????????????} ????????} else if (sas > req) { ????????????layout->oobfree[idx2].offset = i * sas; ????????????layout->oobfree[idx2].length = sas - req; ????????????idx2++; ????????} ????????/* Leave zero-terminated entry for OOBFREE */ ????????if (idx1 >= MTD_MAX_ECCPOS_ENTRIES_LARGE || ????????????????idx2 >= MTD_MAX_OOBFREE_ENTRIES_LARGE - 1) ????????????break; ????} out: ????/* Sum available OOB */ ????for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES_LARGE; i++) ????????layout->oobavail += layout->oobfree[i].length; ????return layout; }
對(duì)于大頁nand flash,一個(gè)page含義多個(gè)sector,每個(gè)sector 512byte或者1024byte,一個(gè)block含有多個(gè)頁。
通常,NAND控制器通過對(duì)OOB區(qū)域中的ECC字段進(jìn)行操作來在硬件中執(zhí)行糾錯(cuò)和檢測。但是,如果您的NAND控制器不支持錯(cuò)誤管理,則需要通過軟件讓MTD為您完成。MTD?nand_ecc驅(qū)動(dòng)程序(drivers / mtd / nand / nand_ecc.c)實(shí)現(xiàn)軟件ECC。 ????case NAND_ECC_SOFT: ????????chip->ecc.calculate = nand_calculate_ecc; ????????chip->ecc.correct = nand_correct_data; ????????chip->ecc.read_page = nand_read_page_swecc; ????????chip->ecc.read_subpage = nand_read_subpage; ????????chip->ecc.write_page = nand_write_page_swecc; ????????chip->ecc.read_page_raw = nand_read_page_raw; ????????chip->ecc.write_page_raw = nand_write_page_raw; ????????chip->ecc.read_oob = nand_read_oob_std; ????????chip->ecc.write_oob = nand_write_oob_std; ????????if (!chip->ecc.size) ????????????chip->ecc.size = 256; ????????chip->ecc.bytes = 3;
包含壞塊標(biāo)記的OOB存儲(chǔ)器字節(jié)。這些標(biāo)記用于標(biāo)記有故障的閃存塊,并且通常出現(xiàn)在屬于每個(gè)塊的第一頁的OOB區(qū)域中。標(biāo)記在OOB區(qū)域內(nèi)的位置取決于芯片的屬性。壞塊標(biāo)記可以在生產(chǎn)過程中在工廠設(shè)置,也可以在軟件中檢測到塊中的磨損。MTD在drivers / mtd / nand / nand_bbt.c中實(shí)現(xiàn)壞塊管理。 # # The NAND_BAD_BLOCK_INDICATOR_MAP has the following format: # #????????bit[15:8]???- Flags indicating which pages, offset from start of block, #??????????????????????are used as bad block indicators.??Bit8 = first page. #??????????????????????Bit15 = 8th page. # #????????bit[7:0]????- Flags indicating which OFS bytes are used as bad block #??????????????????????indicators for pages specified by bits[15:8].??Bit0 = OFS0. #??????????????????????Bit7 = OFS7. # #????????bit[31:24]??- Flags indicating which pages, offset from end of block, #??????????????????????are used as bad block indicators.??Bit24 = last page. #??????????????????????bit31 = 8th to the last page. # #????????bit[23:16]??- Flags indicating which OFS bytes are used as bad block #??????????????????????indicators for pages specified by bits[31:24].??Bit16 = OFS0. #??????????????????????Bit23 = OFS7. # # ifndef NAND_BAD_BLOCK_INDICATOR_MAP
ifeq ($(strip ${NAND_MEM_TYPE}),0) ????NAND_BAD_BLOCK_INDICATOR_MAP=0x00000301??#first 2 pages, OFS0 endif
ifeq ($(strip ${NAND_MEM_TYPE}),1) ????NAND_BAD_BLOCK_INDICATOR_MAP=0x00000301??#first 2 pages, OFS0 endif
ifeq ($(strip ${NAND_MEM_TYPE}),2) ????NAND_BAD_BLOCK_INDICATOR_MAP=0x03010000??#last 2 pages, OFS0 endif
ifeq ($(strip ${NAND_MEM_TYPE}),3) ????NAND_BAD_BLOCK_INDICATOR_MAP=0x03010000??#last 2 pages, OFS0 endif
endif 所以絕大多數(shù)都是block的前兩個(gè)頁的OFS0用來標(biāo)記壞塊,非0xFF則表示壞塊。
解析的過程可以參考boot代碼中的nand_get_page_status()函數(shù)
工具: 你必須使用nanddump和nandwrite等NAND感知工具而不是更常見的dd工具來創(chuàng)建或恢復(fù)NAND
nanddump -f /tmp/dump2.bin -l 131072 -s 131072??-o??/dev/mtd3
nandwrite -o??/dev/mtd3??/mnt/usb/dump1.bin
參考文檔: https://www.ece.umd.edu/~blj/CS-590.26/micron-tn2919.pdf https://www.ece.umd.edu/~blj/CS-590.26/nand-presentation-2010.pdf
+ ----------- +系統(tǒng)總線+ ------------------- + CLE,io [8:0] + ----- -------------- + ?| cpu |←------------→| nand控制器| ←--------------→| nand flash | + ----------- + + ------------------- + + --------------- ---- +
cpu通過系統(tǒng)總線訪問nand控制器寄存器,設(shè)置讀寫flash的命令和相應(yīng)的地址,當(dāng)完成操作時(shí)nand controler發(fā)出中斷,也可以通過查詢nand controler的狀態(tài)寄存器來獲取操作狀態(tài),nand controler將相應(yīng)的命令狀態(tài)為nand flash能夠理解的時(shí)序
nand flash引腳
如果支持直接訪問模式,可以將nandflash直接映射到物理地址空間,通過XOR可以映射到不同的物理空間,這樣就可以直接從nandflash執(zhí)行程序了(注意不能寫,因?yàn)閷懼氨仨氁炔脸?#xff09;
NAND直接存取模式?
/ *禁止所有NAND CS的直接尋址+ XOR * / ????BDEV_UNSET(BCHP_NAND_CS_NAND_SELECT,0xff); ????BDEV_UNSET(BCHP_NAND_CS_NAND_XOR,0xff);
nandflash控制器全局寄存器
oob:spare_area 0x40 = 64byte 數(shù)據(jù):flash_cache 128字節(jié)= 128 * 4 = 512字節(jié)
1.BCHP_NAND_CS_NAND_SELECT: [0:0]? EBI_CS_0_SEL【0-7】每位對(duì)一個(gè)銀行 指示EBI_CS0b是否使用直接尋址機(jī)制,并將Nand Flash映射到MIPS物理地址空間,并使用EBI_CS_BASE_0寄存器指定的基址和大小。(EBI_CS_CONFIG_0將被忽略。)
(注意:建議軟件使用寄存器陣列尋址,除了初始引導(dǎo)讀取之外的所有Nand Flash訪問,無論此位是否設(shè)置,都可以使用寄存器陣列尋址。
1 =允許直接尋址EBI_CS0b。 0 =僅使用EBI_CS0b的寄存器陣列尋址。當(dāng)芯片從NAND閃存啟動(dòng)時(shí),該位被初始化。
[8:8] EBI_CS_0_USES_NAND 【8-15】每位對(duì)?? 一個(gè)銀行 指示EBI_CS0b是否連接到Nand Flash設(shè)備。該位不被硬件使用,但可由軟件用于指示哪些EBI_CS連接到Nand Flash器件。當(dāng)芯片從NAND閃存啟動(dòng)時(shí),該位被初始化。
保留 [27:16]
WR_PROTECT_BLK0 [28:28] RW? 該位將保護(hù)連接到EBI_CS0b的Nand Flash的塊0的內(nèi)容。該位置1時(shí),控制器將忽略目標(biāo)地址位于EBI_CS0b塊0中的閃存修改操作(PAGE_PROGRAM,ERASE等)。(塊大小由NAND_CONFIG_CS [n]寄存器的BLOCK_SIZE字段決定。)
1 =塊寫入EBI_CS0b塊0。 0 =允許寫入EBI_CS0b塊0。
復(fù)位值:0x0
NAND_WP [29:29] RW? 該位控制NAND_WPb引腳(通過反相器)以保護(hù)閃存器件。只要SW希望擦除或編程閃存,該位應(yīng)由SW清零。
(請(qǐng)注意,內(nèi)部電壓監(jiān)視器檢測VDD,并且當(dāng)VDD超出容許范圍時(shí),NAND_WPb被驅(qū)動(dòng)為低電平,無論此位的狀態(tài)如何。)
1 = NAND_WPb引腳為低電平。Flash受到寫保護(hù)。 0 = NAND_WPb引腳為高電平。Flash可以被擦除或編程。
重置值:0x1
AUTO_DEVICE_ID_CONFIG [30:30] RW? 如果設(shè)置了該位,則Nand Flash控制器將在任何其他Nand Flash訪問之前自動(dòng)執(zhí)行FLASH_RESET,然后執(zhí)行Read Device ID命令。從Nand Flash器件返回的值將被硬件用于基于內(nèi)部維護(hù)的已知Nand Flash器件的數(shù)據(jù)庫來初始化NAND_CONFIG_CS [n]寄存器。 當(dāng)strap_nand_flash = 1時(shí),該位??將被置1,并且讀取器件ID命令和NAND_CONFIG_CS [n]寄存器的初始化將在上電時(shí)發(fā)生。 如果軟件沒有設(shè)置該位,并且strap_nand_flash = 0,軟件應(yīng)該在使用Nand Flash控制器之前(在寫入CMD_START之前)執(zhí)行FLASH_RESET命令并初始化NAND_CONFIG_CS [n]寄存器。
1 =執(zhí)行FLASH_RESET和Device ID讀取,NAND_CONFIG_CS [n]寄存器自動(dòng)初始化。 0 =不要執(zhí)行設(shè)備ID讀取或NAND_CONFIG_CS [n]初始化。
當(dāng)芯片從NAND閃存啟動(dòng)時(shí),該位被初始化。
CS_LOCK [31:31] RW? 當(dāng)該位設(shè)置為1時(shí),該寄存器變?yōu)橹蛔x寄存器,防止進(jìn)一步寫入該寄存器。一旦設(shè)置,該位只能通過復(fù)位清零。
復(fù)位值:0x0
2.BCHP_NAND_CS_NAND_XOR EBI_CS_0_ADDR_XOR [0:0] RW?? 【0-7】每位對(duì)一個(gè)銀行 指示為EBI_CS0b指定的地址是否與0xE000_0000異或。 1 =與E000_0000到EBI_CS0b的XOR地址。 0 =直接將地址傳遞給EBI_CS0b(無XOR)。當(dāng)芯片從NAND閃存啟動(dòng)時(shí),該位被初始化。
保留 [30:8] RWX???
ONLY_BLOCK_0_XOR [31:31] RW? 僅對(duì)塊0打開地址XOR。CS0中的所有其他塊地址不會(huì)異或。 該位僅影響CS0,因?yàn)閴K0被定義為CS0器件的第一個(gè)塊。要使用該位,EBI_CS_0_ADDR_XOR也必須設(shè)置為1。 當(dāng)控制器空閑時(shí),軟件應(yīng)該改變這個(gè)位。 1 =僅對(duì)塊0使用E000_0000的XOR地址。 0 =所有塊的EOR_0000異或地址。
復(fù)位值:0x0
INTFC_STATUS - Nand Flash接口狀態(tài) CTLR_READY [31:31] R表示EBI內(nèi)部Nand Flash接口控制器狀態(tài)機(jī)邏輯已完成此接口的所有命令。
FLASH_READY [30:30] R反映外部Nand Flash器件的R / B(就緒/忙碌)引腳的即時(shí)狀態(tài)。(0 =忙碌)
CACHE_VALID [29:29] R指示512字節(jié)的FlashCache緩沖區(qū)是否包含位于FLASH_READ_ADDR寄存器指示的地址處的有效數(shù)據(jù)。
SPARE_AREA_VALID [28:28] R指示16字節(jié)備用區(qū)域讀取寄存器是否包含位于FLASH_READ_ADDR寄存器指示的地址處的有效數(shù)據(jù)。
ERASED [27:27] R指示最近的PAGE_READ命令是否導(dǎo)致數(shù)據(jù)和備用區(qū)域的所有字節(jié)均為FFh。
PLANE_READY [26:26] R僅適用于多平面設(shè)備。 指示EBI內(nèi)部Nand Flash接口控制器狀態(tài)機(jī)邏輯已在當(dāng)前平面上完成PROGRAM_PAGE_MULTI命令。
保留[25:8] RX???
FLASH_STATUS [7:0] R在每次程序頁面,塊擦除或復(fù)制命令操作后,使用來自閃存設(shè)備的狀態(tài)讀取命令更新此字節(jié)值。 復(fù)位值:0x0
每個(gè)銀行的配置寄存器: Brcm nandflash控制器最多支持7個(gè)銀行
BCHP_NAND_ACC_CONTROL_CS0? ? ? ? ? ? ? ?Nand Flash訪問控制?
RD_ECC_EN [31:31] RW為PAGE_READ操作啟用ECC校正。 重置值:0x1
WR_ECC_EN [30:30] RW為任何塊啟用對(duì)PROGRAM_PAGE或PROGRAM_SPARE_AREA操作的ECC校驗(yàn)位生成。當(dāng)該位置位時(shí),ECC字節(jié)將被忽略。 選擇漢明碼時(shí)的ECC字節(jié)位置是SPARE_AREA_WRITE_OFS_4和SPARE_AREA_WRITE_OFS_8寄存器的BYTE_OFS_6,BYTE_OFS_7和BYTE_OFS_8的3個(gè)字節(jié)。選擇BCH碼時(shí)的ECC字節(jié)位置是備用區(qū)域的最后字節(jié)位置。例如,如果SPARE_AREA_SIZE = 16且ECC_LEVEL = 4(7個(gè)ECC字節(jié)),則ECC字節(jié)位置是BYTE_OFS_9到BYTE_OFS_15中的16個(gè)字節(jié)中的最后7個(gè)。 當(dāng)此位設(shè)置為PROGRAM_PAGE操作時(shí),ECC字節(jié)將由H / W生成的ECC校驗(yàn)字節(jié)替代; 對(duì)于PROGRAM_SPARE_AREA操作,ECC字節(jié)將被FFh替換。 重置值:0x1
CE_CARE [29:29] RW此字段僅適用于CE護(hù)理設(shè)備。 當(dāng)設(shè)置為1時(shí),EBI_CS [n]將在NAND_RBb低電平期間保持置位狀態(tài)(器件忙)。在此期間,其他芯片選擇中的器件無法訪問。 默認(rèn)設(shè)置為0以獲得更好的性能。 復(fù)位值:0x0
保留 [28:28] RWX???
RD_ERASED_ECC_EN [27:27] RW確定擦除頁面中的PAGE_READ操作是否會(huì)生成不可糾正的ECC錯(cuò)誤。(一個(gè)Erased Page被定義為全部512個(gè)數(shù)據(jù)字節(jié),所有3個(gè)ECC字節(jié)都包含0xFF,剩余的Spare Area字節(jié)未被考慮)。無論該位的狀態(tài)如何,如果ECC被RD_ECC_EN = 0或RD_ECC_BLK0_EN = 0禁用,將不會(huì)生成錯(cuò)誤。 1 =從擦除頁讀取生成ECC錯(cuò)誤。 0 =從擦除頁讀取不會(huì)產(chǎn)生ECC錯(cuò)誤。 復(fù)位值:0x0
PARTIAL_PAGE_EN [26:26] RW啟用部分頁面編程。建議清除此位以提高性能并防止部分頁面編程,這是許多nand閃存設(shè)備所禁止的。??當(dāng)該位置位且軟件啟動(dòng)PROGRAM_PAGE操作時(shí),硬件將數(shù)據(jù)直接寫入閃存單元。當(dāng)該位清零并且軟件啟動(dòng)PROGRAM_PAGE操作時(shí),硬件將數(shù)據(jù)移入NAND Flash設(shè)備緩存并返回空閑狀態(tài)。只有當(dāng)NAND_CMD_ADDRESS指向頁面的最后512字節(jié)扇區(qū)時(shí),硬件才會(huì)將數(shù)據(jù)編程到閃存單元中。 小頁面設(shè)備會(huì)忽略該位。 復(fù)位值:0x0
WR_PREEMPT_EN [25:25] RW使能其他EBI或PCI周期的寫突發(fā)操作的搶占。當(dāng)另一個(gè)請(qǐng)求者試圖使用總線時(shí),這允許將來自Flash外部總線的長512字節(jié)突發(fā)分成16次傳輸?shù)亩鄠€(gè)突發(fā)。 重置值:0x1
PAGE_HIT_EN [24:24] RW啟用Flash頁面檢測檢測,作為頁面大小大于512B的頁面內(nèi)512字節(jié)讀取的優(yōu)化。該位僅為大頁面設(shè)備提供性能優(yōu)化。如果設(shè)置,并且硬件發(fā)現(xiàn)讀取未命中,但是從已經(jīng)讀入FlashCache的相同頁面,它將簡單地使用閃存的隨機(jī)讀取操作來節(jié)省時(shí)間。 重置值:0x1
PREFETCH_EN [23:23] RW硬件自動(dòng)讀取當(dāng)前頁面讀取命令地址的下一個(gè)512B或1KB數(shù)據(jù),扇區(qū)大小取決于SECTOR_SIZE_1K位。啟用此位可提高讀取連續(xù)地址的性能。 預(yù)取對(duì)軟件是透明的。CTLR_READY位始終指示當(dāng)前地址讀取完成。注:建議將此位設(shè)置為長連續(xù)讀取,例如DMA傳輸。如果讀取地址不連續(xù),則由于后臺(tái)預(yù)取,軟件可能會(huì)看到更長的繁忙時(shí)間和性能下降。 注:僅當(dāng)ECC_type為BCH時(shí)才支持預(yù)取。 復(fù)位值:0x0
CACHE_MODE_EN [22:22] RW啟用程序頁面或頁面讀取緩存模式。 如果置位,并且發(fā)出頁面讀取命令,硬件將啟動(dòng)具有緩存模式操作碼31h的頁面讀操作。 如果置位,并且發(fā)出程序頁命令,則硬件以高速緩存模式操作碼15h結(jié)束程序頁操作。 緩存模式通過連續(xù)頁面訪問跳過閃存設(shè)備繁忙時(shí)間來提高性能。例如:第n,n + 1,n + 2,n + 3,n + 4 ... n + m的DMA傳輸 注:硬件不檢測頁面地址的連貫性。軟件需要管理設(shè)置這一點(diǎn)。要恢復(fù)正常的頁面讀取和程序頁面命令,請(qǐng)取消設(shè)置此位。 復(fù)位值:0x0
保留 [21:21] RWX???
ECC_LEVEL [20:16] RW設(shè)置每512個(gè)數(shù)據(jù)字節(jié)可以糾正的編碼類型和位數(shù)。 定義T:=每扇區(qū)可修正的位數(shù)。 當(dāng)SECTOR_SIZE_1K = 0時(shí),則T = ECC_LEVEL 當(dāng)SECTOR_SIZE_1K = 1時(shí),則T = ECC_LEVEL * 2 異常是SECTOR_SIZE_1K = 0,SPARE_AREA_SIZE = 16,ECC_LEVEL = 15,則T = 1(海明模式)
保留 [15:8] RWX???
SECTOR_SIZE_1K [7:7] RW定義ECC碼字大小,也稱為扇區(qū)大小。注意:當(dāng)使用1k字節(jié)扇區(qū)大小時(shí),ECC_LEVEL字段指定T值的一半,漢明碼不可用。 請(qǐng)參閱ECC_LEVEL說明中顯示的表。 注意:當(dāng)使用1k字節(jié)扇區(qū)大小時(shí),必須清除PARTIAL_PAGE_EN位,并且閃存頁面大小必須大于512。 0 512字節(jié) 1個(gè)1k字節(jié)
當(dāng)strap_nand_flash = 1時(shí),該字段將根據(jù)選定的ECC級(jí)別綁定在strap_nand_ecc_level [n:0]上進(jìn)行初始化。 復(fù)位值:0x0
SPARE_AREA_SIZE [6:0] RW表示每512個(gè)數(shù)據(jù)字節(jié)包含在閃存設(shè)備中的備用區(qū)字節(jié)數(shù)。有效設(shè)置是16到64(含)。對(duì)于16位寬的NAND閃存器件,此字段必須包含偶數(shù)。 對(duì)于大頁面設(shè)備(頁面大小為2kB或更大),每頁的備用區(qū)域除以每頁的扇區(qū)數(shù)量。??例如,(2kB + 64B)頁面大小和512B扇區(qū)大小每頁有4個(gè)扇區(qū),每頁全部64字節(jié)備用區(qū)域?qū)⒈环殖?個(gè)相等的部分,每個(gè)16字節(jié); 并且這些部分中的每一個(gè)都將被不同的部門使用。 選擇漢明碼時(shí)的ECC字節(jié)位置是SPARE_AREA_WRITE_OFS_4和SPARE_AREA_WRITE_OFS_8寄存器的BYTE_OFS_6,BYTE_OFS_7和BYTE_OFS_8的3個(gè)字節(jié)。 選擇BCH碼時(shí)的ECC字節(jié)位置是該特定扇區(qū)的備用區(qū)的最后一個(gè)字節(jié)位置。??例如,如果SPARE_AREA_SIZE = 16且ECC_LEVEL = 4(7個(gè)ECC字節(jié)),則ECC字節(jié)位置是BYTE_OFS_9到BYTE_OFS_15中的16個(gè)字節(jié)中的最后7個(gè)。 當(dāng)SECTOR_SIZE_1K = 1時(shí),該字段仍指定每512個(gè)備用字節(jié)。
當(dāng)strap_nand_flash = 1時(shí),該字段將根據(jù)選定的ECC級(jí)別綁定在strap_nand_ecc_level [n:0]上進(jìn)行初始化。 重置值:0x10
因?yàn)镋CC校驗(yàn)是由控制器自動(dòng)完成的,那么就必須讓控制器知道該bank上的nandflash使用的ECC LEVEL和SPARE_AREA_SIZE,這樣控制器就能知道ECC字節(jié)在SPARE_AREA_READ_OFS_0中的位置.ECC字節(jié)在nandflash中的位置理論上來說跟nandflash沒有多大關(guān)系,因?yàn)閚andflash對(duì)ECC字節(jié)是無知的,它由控制器來使用,nandflash會(huì)根據(jù)本身工藝推薦ECC LEVEL,理論上大于這個(gè)值都是可行的。
BCHP_NAND_CONFIG_EXT_CS0?????????? Nand Flash配置擴(kuò)展? 閃存設(shè)備接口參數(shù)。根據(jù)NAND_CMD_EXT_ADDRESS寄存器中的CS_SEL值,硬件會(huì)根據(jù)剛剛復(fù)位后從外部Nand Flash器件讀取的DeviceID或ONFI參數(shù)值將缺省值裝入此寄存器。
保留[31:12] RWX???
BLOCK_SIZE [11:4] RW塊大小(以字節(jié)為單位)。(注意:該字段僅用于確定目標(biāo)地址是否位于閃存的塊0中,以便在WR_PROTECT_BLK0位置位時(shí)知道是否應(yīng)用寫保護(hù),或者當(dāng)RD_ECC_BLK0_EN位為是時(shí)是否執(zhí)行ECC糾正組。) 值名稱 0 BK_SIZE_8KB 1 BK_SIZE_16KB 2 BK_SIZE_32KB 3 BK_SIZE_64KB 4 BK_SIZE_128KB 5 BK_SIZE_256KB 6 BK_SIZE_512KB 7 BK_SIZE_1024KB 8 BK_SIZE_2048KB 9 BK_SIZE_4096KB 10 BK_SIZE_8192KB
PAGE_SIZE [3:0] RW頁面大小(以字節(jié)為單位)。 值名稱說明 0 PG_SIZE_512 512字節(jié)。 1 PG_SIZE_1KB 1k字節(jié)。 2 PG_SIZE_2KB 2k字節(jié)。 3 PG_SIZE_4KB 4k字節(jié)。 4 PG_SIZE_8KB 8k字節(jié)。 5 PG_SIZE_16KB 16k字節(jié)。
BCHP_NAND_CONFIG_CS0????????????????? Nand Flash配置 閃存設(shè)備接口參數(shù)。根據(jù)NAND_CMD_EXT_ADDRESS寄存器中的CS_SEL值,硬件會(huì)根據(jù)剛剛復(fù)位后從外部Nand Flash器件讀取的DeviceID或ONFI參數(shù)值將缺省值裝入此寄存器。
CONFIG_LOCK [31:31] RW當(dāng)該位設(shè)置為1時(shí),該寄存器和CONFIG_EXT寄存器變?yōu)橹蛔x寄存器,防止進(jìn)一步寫入該寄存器和CONFIG_EXT寄存器。一旦設(shè)置,該位只能通過復(fù)位清零。 復(fù)位值:0x0
保留[30:28] RWX???
DEVICE_SIZE [27:24] RW設(shè)備大小(以字節(jié)為單位)。 值名稱 0 DVC_SIZE_4MB 1 DVC_SIZE_8MB 2 DVC_SIZE_16MB 3 DVC_SIZE_32MB 4 DVC_SIZE_64MB 5 DVC_SIZE_128MB 6 DVC_SIZE_256MB 7 DVC_SIZE_512MB 8 DVC_SIZE_1GB 9 DVC_SIZE_2GB 10 DVC_SIZE_4GB 11 DVC_SIZE_8GB 12 DVC_SIZE_16GB 13 DVC_SIZE_32GB 14 DVC_SIZE_64GB 15 DVC_SIZE_128GB
DEVICE_WIDTH [23:23] RW設(shè)備I / O數(shù)據(jù)總線寬度(以位為單位)。 值名稱 0 DVC_WIDTH_8 1 DVC_WIDTH_16
保留[22:19] RWX???
FUL_ADR_BYTES [18:16] RW在設(shè)備內(nèi)發(fā)送到Flash的完整地址的地址字節(jié)數(shù)。 當(dāng)PAGE_SIZE> 512B時(shí),FUL_ADR_BYTES = COL_ADR_BYTES + BLK_ADR_BYTES。 當(dāng)PAGE_SIZE = 512B時(shí),FUL_ADR_BYTES = 1 + BLK_ADR_BYTES。 該字段通過綁定或AUTO_DEVICE_ID_CONFIG初始化。
保留[15:15] RWX???
COL_ADR_BYTES [14:12] RW發(fā)送到Flash以指定頁面內(nèi)隨機(jī)數(shù)據(jù)訪問的列地址的地址字節(jié)數(shù)。該字段僅用于頁面大小大于512B的頁面,用于頁面內(nèi)的隨機(jī)尋址,以尋址PROGRAM_PAGE和PAGE_READ命令的備用區(qū)域。 2為512B <=頁面大小<= 32KB 該字段通過綁定或AUTO_DEVICE_ID_CONFIG初始化。
保留[11:11] RWX???
BLK_ADR_BYTES [10:8] RW發(fā)送到Flash以指定行和塊的地址字節(jié)數(shù)。該字段相當(dāng)于NAND閃存數(shù)據(jù)表中的頁面地址+塊地址。 該字段僅用于BLOCK_ERASE和BLOCKS_UNLOCK命令。 該字段通過綁定或AUTO_DEVICE_ID_CONFIG初始化。
保留[7:0] RWX???
BCHP_NAND_TIMING_1_CS0???????????????? ?Nand Flash時(shí)序參數(shù)1? 閃存設(shè)備接口時(shí)序參數(shù)。時(shí)序以內(nèi)部108 MHz時(shí)鐘(9.26 ns)或內(nèi)部216 MHz時(shí)鐘(4.63 ns)為單位指定,具體取決于TIMING_2.CLK_SELECT的值。 任何時(shí)間字段中的最小值是2(2個(gè)時(shí)鐘)。
tWP [31:28] RW時(shí)鐘數(shù)WE低脈沖寬度。
重置值:0x6 tWH [27:24] RW片段數(shù)WE高脈沖寬度。(除了ALE較高時(shí),在這種情況下,tALH控制WE高脈沖寬度而不是tWH。)
重置值:0x5 tRP [23:20] RW時(shí)鐘數(shù)RE低脈沖寬度。
重置值:0x7 tREH [19:16] RW時(shí)鐘數(shù)RE高脈沖寬度。
重置值:0x4 tCS [15:12] RW從CE低到第一個(gè)WE低的時(shí)鐘數(shù)。注意:當(dāng)CLK_SELECT = CLK_108時(shí),該寄存器字段中的值將被硬件加倍,當(dāng)CLK_SELECT = CLK_216時(shí),該值將被硬件加倍。
重置值:0x8 tCLH [11:8] RW從WE高到CLE低的塊數(shù)。
重置值:0x4 tALH [7:4] RW從WE高到ALE低的時(shí)針數(shù)量。而且,當(dāng)ALE高時(shí),屏幕的數(shù)量WE高脈沖寬度。該位應(yīng)該被設(shè)置為來自閃存制造商數(shù)據(jù)表的tWH和tALH之間的較大值。
重置值:0x5 tADL [3:0] RW從最后一個(gè)addr到第一次數(shù)據(jù)寫入的時(shí)鐘片數(shù)。注意:當(dāng)CLK_SELECT = CLK_108時(shí),該寄存器字段中的值將被硬件加倍,當(dāng)CLK_SELECT = CLK_216時(shí),該值將被硬件加倍。
復(fù)位值:0xB
BCHP_NAND_TIMING_2_CS0?????????????????? ?Nand Flash時(shí)序參數(shù)2? 閃存設(shè)備接口時(shí)序參數(shù)。時(shí)序以內(nèi)部108 MHz時(shí)鐘(9.26 ns)或內(nèi)部216 MHz時(shí)鐘(4.63 ns)為單位指定,具體取決于TIMING_2.CLK_SELECT的值。 任何時(shí)間字段中的最小值是2(2個(gè)時(shí)鐘)。
CLK_SELECT [31:31] RW確定NAND_TIMING_1和NAND_TIMING_2中的參數(shù)用于nand閃存定時(shí)狀態(tài)機(jī)的時(shí)鐘。 值名稱說明 0 CLK_108內(nèi)部108 MHz時(shí)鐘。 1 CLK_216內(nèi)部216 MHz時(shí)鐘。
重置值:CLK_108 保留[30:20] RWX??? tCCS [19:16] RW更改列命令設(shè)置時(shí)間。 注:當(dāng)CLK_SELECT = CLK_108時(shí),硬件將該寄存器字段中的值翻兩倍,并且當(dāng)CLK_SELECT = CLK_216時(shí),該值將由硬件八倍。
重置值:0x9 保留[15:13] RWX??? tWB [12:9] RW在硬件開始采樣R / B引腳之前,CE的高電平時(shí)鐘數(shù)。注意:當(dāng)CLK_SELECT = CLK_108時(shí),該寄存器字段中的值將被硬件加倍,當(dāng)CLK_SELECT = CLK_216時(shí),該值將被硬件加倍。
復(fù)位值:0xF tWHR [8:4] RW從WE高到RE低的時(shí)鐘片數(shù)。此參數(shù)僅用于狀態(tài)讀取和設(shè)備ID讀取操作。注意:當(dāng)CLK_SELECT = CLK_108時(shí),該寄存器字段中的值將被硬件加倍,當(dāng)CLK_SELECT = CLK_216時(shí),該值將被硬件加倍。
重置值:0x9 tREAD [3:0] RW RE低后采樣讀取數(shù)據(jù)之前等待的時(shí)鐘數(shù)。
為獲得最佳性能,應(yīng)通過將nns閃存器件的RE存取時(shí)間(tREA)加上17ns,然后將總和除以CLK_SELECT所選的時(shí)鐘周期,然后將其四舍五入至下一較大整數(shù)來計(jì)算此參數(shù)。例如,如果器件tREA = 20ns并且CLK_SELECT = 1(216MHz => 4.63ns): tREAD =(20ns + 17ns)/4.63ns=7.99(四舍五入)=> 8。
tREAD的最大值是(tRP + tREH)。
重置值:0x6
操作時(shí)序 在編程操作中,要被編程的數(shù)據(jù)在WE#的上升沿被同步到數(shù)據(jù)寄存器中。 數(shù)據(jù)以類似的方式通過讀使能(RE#)信號(hào)從數(shù)據(jù)寄存器輸出,該信號(hào)負(fù)責(zé)輸出當(dāng)前數(shù)據(jù)并遞增到下一個(gè)位置。WE#和RE#時(shí)鐘每次傳輸可以運(yùn)行25ns。當(dāng)RE#或芯片使能(CE#)未置為低電平時(shí),輸出緩沖器為三態(tài)。CE#和RE#的這種組合激活了輸出緩沖器,使NAND Flash能夠與其他類型的存儲(chǔ)器(如NOR閃存,SRAM或DRAM)共享數(shù)據(jù)總線。這個(gè)功能有時(shí)被稱為“芯片使能不關(guān)心”。 在RE#為低時(shí),讀使能,輸出緩沖器直接放置在io上,可跟著變化。 所有的NAND Flash操作都是通過發(fā)出一個(gè)命令周期來啟動(dòng)的。這是通過將命令放在I / O [7:0]上,驅(qū)動(dòng)CE#為低電平并且為高電平,然后發(fā)出WE#時(shí)鐘來完成的。命令,地址和數(shù)據(jù)在WE#的上升沿時(shí)鐘輸入NAND閃存器件, 大多數(shù)命令需要多個(gè)地址周期,然后是第二個(gè)命令周期。除RESET和READ STATUS命令外,當(dāng)設(shè)備忙時(shí)不應(yīng)發(fā)出新命令。 支持的命令:
2Gb NAND Flash器件的尋址方案如表6所示。第一個(gè)和第二個(gè)地址周期(或字節(jié))指定了列地址,它指定了頁面內(nèi)的起始字節(jié)。最后一列的位置是2112,因此最后一個(gè)位置的地址是第二個(gè)字節(jié)中的08h,第一個(gè)字節(jié)中是3Fh。PA [5:0]指定塊內(nèi)的頁面地址,BA [16:6]指定塊地址。盡管大多數(shù)PROGRAM和READ操作需要完整的5字節(jié)地址,但對(duì)于在頁面內(nèi)隨機(jī)訪問數(shù)據(jù)的操作,只需要第一個(gè)和第二個(gè)字節(jié)(或循環(huán))。BLOCK ERASE操作只需要三個(gè)最重要的字節(jié)(第三,第四和第五)來選擇該塊。
當(dāng)CA11 = 1時(shí)表示訪問oob數(shù)據(jù),一般列地址都為0,表示從頁面內(nèi)偏移0開始訪問整個(gè)頁面。
復(fù)位操作 RESET是NAND Flash器件繁忙時(shí)可以發(fā)出的兩個(gè)命令之一。如果設(shè)備正忙于處理先前的命令,則發(fā)出RESET命令會(huì)中止前一個(gè)操作。如果之前的操作是ERASE或PROGRAM命令,則發(fā)出RESET命令會(huì)過早地中止該命令,并且所需的操作不會(huì)完成。ERASE和PROGRAM可以是耗時(shí)的操作; 發(fā)出RESET命令可以中止或稍后重新發(fā)出命令。
CE先拉低選中芯片,在io [8:0]上放置FFh,然后CLE拉高,將io [8:0]與命令鎖存器相連,然后將WE拉低,接著拉高,在上升沿完成命令的寫操作,延時(shí)TWB后查詢R / B腳的狀態(tài),當(dāng)為1時(shí)表示RESET完成。
READ ID操作 READ ID(90h)命令需要一個(gè)虛擬地址周期(00h),但不需要第二個(gè)命令周期。在發(fā)出命令和虛擬地址后,通過保持CLE和ALE為低電平并讀取ID的每個(gè)字節(jié)的RE#信號(hào),可以讀出ID數(shù)據(jù)。
CE先拉低選中chip,在io [8:0]上放置90h,然后CLE拉高,將io [8:0]與命令鎖存器相連,然后將WE拉低,接著拉高,在上升沿完成命令的寫操作,然后拉低CLE,拉高ALE,將io [8:0]與地址鎖存器相連,在io [8:0]上放置00h,然后將WE拉低,然后拉高WE ,在上升沿完成addrees的寫操作,接著拉低ALE,適當(dāng)?shù)难訒r(shí)后拉低RE,(CLE和ALE都為低時(shí),IO [8:0]與數(shù)據(jù)鎖存器相連,CLE和ALE都為高時(shí)為非法),chip將數(shù)據(jù)放置在io [8:0]上,nand controler從io [8:0]上讀取數(shù)據(jù),讀完后RE拉高,然后拉低讀取下一個(gè)字節(jié)。
READ STATUS操作 讀取狀態(tài)(70h)是NAND Flash器件忙時(shí)可以發(fā)出的第二個(gè)命令。該命令不需要地址或第二個(gè)命令周期。通過在READ STATUS命令之后發(fā)出RE#時(shí)鐘信號(hào),可以監(jiān)控NAND閃存器件的狀態(tài)。如果使用READ STATUS命令監(jiān)視器件的就緒狀態(tài),則該命令只能發(fā)出一次,并且可以通過重新發(fā)出RE#時(shí)鐘來重新讀取狀態(tài)。或者,RE#信號(hào)可以保持低電平,在繼續(xù)之前等待接收適當(dāng)?shù)臓顟B(tài)位。READ STATUS還會(huì)報(bào)告寫保護(hù)信號(hào)的狀態(tài)以及之前PROGRAM或ERASE操作的通過/失敗狀態(tài)。在PROGRAM或ERASE操作中必須達(dá)到合格狀態(tài)以確保數(shù)據(jù)完整性。
擦除操作 BLOCK ERASE(60h)操作會(huì)擦除整個(gè)64頁的頁面,總共128KB。要發(fā)出BLOCK ERASE操作,使用WE#信號(hào)在CLE置位時(shí)在ERASE(60h)命令中計(jì)時(shí)。接下來,在三個(gè)地址周期中的時(shí)鐘,保持每個(gè)字節(jié)地址的ALE有效。(這三個(gè)地址周期是最重要的地址周期,包括塊地址和頁地址,如第9頁的表6所示。)頁地址部分(第三個(gè)地址周期的六個(gè)低位)被忽略,并且只使用三個(gè)最高有效字節(jié)的塊地址部分。地址完全輸入后,發(fā)出D0h的第二個(gè)命令(命令周期2),當(dāng)CLE置位時(shí),它由WE#提供時(shí)鐘。這確認(rèn)了ERASE操作,并且設(shè)備忙了大約500μs。當(dāng)設(shè)備完成此操作時(shí),它已準(zhǔn)備好執(zhí)行另一個(gè)命令。READ STATUS命令可以隨時(shí)發(fā)出,即使在ERASE操作過程中設(shè)備處于繁忙狀態(tài)。微處理器或控制器可以通過READ STATUS命令監(jiān)視設(shè)備
提交70H命令查詢狀態(tài)后,RE一直為低,監(jiān)控IO [5]引腳上的值,為0時(shí)表示擦除完成
程序操作 PROGRAM操作只能將位編程為0,并假定用戶以先前擦除的塊開始。如果用戶不想編程一個(gè)位(或一組位),則通過將該特定位/組設(shè)置為1,可以將位保持在擦除狀態(tài)。當(dāng)接收到編程頁(80h)命令時(shí),輸入寄存器被重置(內(nèi)部)到全1。這支持只輸入要用0位編程的數(shù)據(jù)字節(jié)。PROGRAM操作從80h命令開始(CLE置位 - 見圖8)。接下來,取消斷言CLE并斷言ALE輸入完整的五個(gè)地址周期。輸入命令和地址后,數(shù)據(jù)輸入到寄存器。當(dāng)所有的數(shù)據(jù)都被輸入時(shí),發(fā)出10h命令來確認(rèn)前一個(gè)命令并開始編程操作。PROGRAM操作通常需要220μs,雖然它可能需要多達(dá)600μs。用戶必須閱讀狀態(tài)并檢查操作是否成功。如果操作不成功,則該塊應(yīng)該記錄為壞塊并且將來不會(huì)使用。所有的數(shù)據(jù)應(yīng)該移到一個(gè)好的塊。
可以編程1-2112個(gè)字節(jié),根據(jù)col add,如果頁內(nèi)偏移為0,即編程整個(gè)頁,則2112個(gè)字節(jié)
READ操作 READ操作從00h命令開始,隨后是5個(gè)地址周期,然后是30h命令以確認(rèn)命令序列。經(jīng)過大約25μs的讀取傳輸時(shí)間(t R)后,數(shù)據(jù)被加載到寄存器并準(zhǔn)備輸出。置位RE#使NAND Flash器件能夠輸出與地址中指定的列地址相對(duì)應(yīng)的數(shù)據(jù)的第一個(gè)字節(jié)。隨后的RE#從連續(xù)的列位置轉(zhuǎn)換輸出數(shù)據(jù)。當(dāng)RE#信號(hào)為高(未置位)時(shí),I / O線為三態(tài)。讀取設(shè)備末尾(字節(jié)2112或字1056)會(huì)導(dǎo)致無效數(shù)據(jù)。
READ PAGE CACHE SEQUENTIAL操作 至此只討論了NAND??閃存器件中的一個(gè)寄存器。NAND Flash器件實(shí)際上有兩個(gè)寄存器,一個(gè)數(shù)據(jù)寄存器和一個(gè)高速緩存寄存器,如圖12所示。這兩個(gè)寄存器的屬性在各種NAND Flash緩存模式中起著重要的作用。PAGE READ CACHE MODE命令使用戶能夠在輸出先前訪問的數(shù)據(jù)的同時(shí)從數(shù)組中流水線化下一個(gè)順序訪問。這種雙緩沖技術(shù)可以隱藏讀取傳輸時(shí)間(t R)。數(shù)據(jù)最初從NAND閃存陣列傳輸?shù)綌?shù)據(jù)寄存器。如果高速緩存寄存器可用(不忙),數(shù)據(jù)將很快從數(shù)據(jù)寄存器移至高速緩存寄存器。數(shù)據(jù)傳輸?shù)礁咚倬彺婕拇嫫骱?#xff0c;數(shù)據(jù)寄存器可用,并且可以開始加載NAND閃存陣列中的下一個(gè)連續(xù)頁面。與8位I / O設(shè)備上的傳統(tǒng)PAGE READ命令相比,使用PAGE READ CACHE MODE命令可提高33%的性能,吞吐量可達(dá)31 MB / s。在16位I / O設(shè)備上,吞吐量可以提高到37 MB / s,與普通的PAGE READ操作相比,性能提高40%。 www.micron.com/products/nand/technotes上的技術(shù)說明提供了有關(guān)緩存模式的更多詳細(xì)信息以及如何使用它們來提高性能。PAGE READ CACHE MODE在系統(tǒng)啟動(dòng)時(shí)特別有用,當(dāng)大量數(shù)據(jù)通常從NAND閃存設(shè)備中讀取并且啟動(dòng)時(shí)間非常關(guān)鍵時(shí)。
PROGRAM PAGE CACHE操作 PROGRAM PAGE CACHE MODE提供比正常PROGRAM PAGE操作更高的性能(見圖14和15)。PROGRAM PAGE CACHE MODE是一種雙緩沖技術(shù),它使控制器能夠?qū)?shù)據(jù)直接輸入到高速緩存寄存器,并使用數(shù)據(jù)寄存器作為存儲(chǔ)區(qū)來提供用于編程陣列的數(shù)據(jù)。這將釋放高速緩存寄存器,以便可以并行加載下一個(gè)順序頁面操作。在許多應(yīng)用中,編程時(shí)間(t PROG)可以完全隱藏。與PAGE READ CACHE MODE命令一樣,數(shù)據(jù)寄存器用于在整個(gè)編程周期內(nèi)保持?jǐn)?shù)據(jù)吞吐量。這將釋放緩存寄存器以接收來自控制器的下一頁數(shù)據(jù)。
存儲(chǔ)方法 圖10顯示了將數(shù)據(jù)和備用信息存儲(chǔ)在同一頁面的兩種常用方法。第一種方法顯示512字節(jié)的數(shù)據(jù)區(qū)加上與其直接相鄰的16字節(jié)備用區(qū); 組合區(qū)域?yàn)?28字節(jié)。一個(gè)2112字節(jié)的頁面可以包含這些528字節(jié)元素中的四個(gè)。第二個(gè)實(shí)施涉及單獨(dú)存儲(chǔ)數(shù)據(jù)和備用信息。四個(gè)512字節(jié)的數(shù)據(jù)區(qū)首先被存儲(chǔ),并且它們對(duì)應(yīng)的16字節(jié)備用區(qū)按順序依次位于頁面的末尾。
至于具體采用哪種存儲(chǔ)方式,由控制器決定,在NANDFLASH看來,數(shù)據(jù)和OOB并沒有什么區(qū)別.BRCM控制器采用的第二種方式。
部分頁面編程 與NAND接口一致,NAND中的基本編程單元是一個(gè)頁面; 然而,通過利用部分頁面編程,可以將頁面編程成更小的部分。為了便于部分頁面編程,每個(gè)頁面被進(jìn)一步分成八個(gè)段(數(shù)據(jù)區(qū)域四個(gè),備用區(qū)域四個(gè))。 頁面中的每個(gè)段都充當(dāng)獨(dú)立的可編程單元; 它們可以單獨(dú)編程或以任何組合段編程。每個(gè)片段允許的最大連續(xù)部分頁面程序數(shù)量為1。也就是說,頁面中的每個(gè)段可以被編程一次,并且在需要塊擦除之前頁面可以被編程多達(dá)八次。 部分頁面編程通過發(fā)出一個(gè)輸入命令(80h),然后是多段編程的隨機(jī)數(shù)據(jù)輸入命令(85h)序列完成。加載最后一個(gè)數(shù)據(jù)后,程序確認(rèn)命令(10h)啟動(dòng)編程操作并將數(shù)據(jù)寫入到所需位置的緩沖區(qū)中。寫狀態(tài)位(I / O0)可以通過命令(70h)進(jìn)行驗(yàn)證,以驗(yàn)證編程是否成功。
部分頁面讀取 部分頁面讀取是通過發(fā)出一個(gè)讀取命令(00h),然后是一個(gè)隨機(jī)數(shù)據(jù)讀取命令(05h)序列來完成多段讀取。?
讀取內(nèi)部數(shù)據(jù)移動(dòng)操作 READ FOR INTERNAL DATA MOVE(00h-35h)命令也被稱為“復(fù)制”。它提供了將數(shù)據(jù)從一個(gè)頁面內(nèi)部移動(dòng)到另一個(gè)頁面的能力 - 數(shù)據(jù)永遠(yuǎn)不會(huì)離開NAND Flash設(shè)備。READ FOR INTERNAL DATA MOVE操作將從NAND閃存陣列讀取的數(shù)據(jù)傳輸?shù)礁咚倬彺婕拇嫫鳌?/span>數(shù)據(jù)可以被編程到設(shè)備的另一個(gè)頁面中。這在控制器在擦除塊之前需要將數(shù)據(jù)從塊中移出的情況下非常有用。在PROGRAM操作開始之前,也可以修改讀取的數(shù)據(jù)。如果用戶想在編程之前更改數(shù)據(jù),這很有用。此功能可在NAND Flash設(shè)備內(nèi)移動(dòng)數(shù)據(jù),而無需占用處理器或I / O總線。
代碼分析 static uint32_t do_nand_cmd(struct nand_probe_info * info,uint32_t cmd, ????????uint64_t addr) { ????int t = 100 * 1000; / * 100ms * /
????BDEV_WR(BCHP_NAND_CMD_EXT_ADDRESS, ????????????(info-> cs << 16)| ((addr >> 32)&0xffff)); ????BDEV_WR(BCHP_NAND_CMD_ADDRESS,addr&0xffffffff); ????BDEV_WR_F(NAND_CMD_START,操作碼,cmd);
????while(!BDEV_RD_F(NAND_INTFC_STATUS,CTLR_READY)){ ????????如果(t <= 0) ????????????打破; ????????bolt_usleep(1);
????????t - = 1; ????}
???如果(!BDEV_RD_F(NAND_INTFC_STATUS,CTLR_READY)) ???????????err_msg(“NAND:超時(shí)等待命令(%#04x @%llx)[%d,%d]”, ????????????????cmd,addr, ????????????????BDEV_RD_F(NAND_INTFC_STATUS,CTLR_READY), ????????????????BDEV_RD_F(NAND_INTFC_STATUS,FLASH_READY));
????返回BDEV_RD(BCHP_NAND_INTFC_STATUS)&NAND_STATUS_FAIL; } BRCM的nand controler比較智能,我們只需要設(shè)置要進(jìn)行的操作和地址,控制器會(huì)自動(dòng)解釋發(fā)出芯片能夠理解的命令和地址。
Linux的內(nèi)核中關(guān)于NANDFLASH的代碼: include / mtd / mtd-abi.h中定義的nand_ecclayout 結(jié)構(gòu)指定OOB備用區(qū)域的布局:? struct nand_ecclayout { uint 32_t eccbytes; uint32_t eccpos [64]; uint32_t oobavail; struct nand_oobfree oobfree [MTD_MAX_OOBFREE_ENTRIES]; };
在此結(jié)構(gòu)中,eccbytes 保存存儲(chǔ)ECC數(shù)據(jù)的OOB字節(jié)的數(shù)量,eccpos 是包含ECC數(shù)據(jù)的OOB區(qū)域的偏移量數(shù)組。oobfree 將可用于閃存文件系統(tǒng)的OOB區(qū)域中未使用的字節(jié)記錄為用于存儲(chǔ)標(biāo)志的標(biāo)志,例如清除標(biāo)志,表示擦除操作成功完成。 各個(gè)NAND程序驅(qū)動(dòng)根據(jù)芯片的屬性初始化它們的nand_ecclayout static struct nand_ecclayout * brcmstb_nand_create_layout(int ecc_level, ????????struct brcmstb_nand_cfg * cfg) { ????int i,j; ????struct nand_ecclayout * layout; ????int req; ????整個(gè)行業(yè); ????int sas; ????int idx1,idx2;
????layout = kzalloc(sizeof(* layout),GFP_KERNEL); ????if(!layout){ ????????pr_err(“%s:無法分配內(nèi)存\ n”,__func__); ????????返回NULL; ????}
????sector = cfg-> page_size /(512 << cfg-> sector_size_1k); ????sas = cfg-> spare_area_size << cfg-> sector_size_1k;
????/ *漢明* / ????if(is_hamming_ecc(cfg)){ ????????for(i = 0,idx1 = 0,idx2 = 0; i <sectors; i ++){ ????????????/ *每個(gè)頁面的第一個(gè)扇區(qū)可能有BBI * / ????????????if(i == 0){ ????????????????layout-> oobfree [idx2] .offset = i * sas + 1; ????????????????/ *小頁面NAND使用字節(jié)6用于BBI * / ????????????????if(cfg-> page_size == 512) ????????????????????布局 - > oobfree [IDX2] .offset--; ????????????????layout-> oobfree [idx2] .length = 5; ????????????} else { ????????????????layout-> oobfree [idx2] .offset = i * sas; ????????????????layout-> oobfree [idx2] .length = 6; ????????????} ????????????IDX2 ++; ????????????layout->eccpos[idx1++] = i * sas + 6; ????????????layout->eccpos[idx1++] = i * sas + 7; ????????????layout->eccpos[idx1++] = i * sas + 8;? ? ? //對(duì)于Hamming, 6,7,8 byte為Hamming ECC ????????????layout->oobfree[idx2].offset = i * sas + 9; ????????????layout->oobfree[idx2].length = 7; ????????????idx2++; ????????????/* Leave zero-terminated entry for OOBFREE */ ????????????if (idx1 >= MTD_MAX_ECCPOS_ENTRIES_LARGE || ????????????????????idx2 >= MTD_MAX_OOBFREE_ENTRIES_LARGE - 1) ????????????????break; ????????} ????????goto out; ????}
????/* ???? * CONTROLLER_VERSION: ???? *???< v5.0: ECC_REQ = ceil(BCH_T * 13/8) ???? *??>= v5.0: ECC_REQ = ceil(BCH_T * 14/8)??[see SWLINUX-2038] ???? * But we will just be conservative. ???? */ ????req = (ecc_level * 14 + 7) / 8;? ? ? // 根據(jù)ECC LEVEL得到需要的ECC byte數(shù) ????if (req >= sas) { ????????pr_info("%s: ECC too large for OOB, using dummy layout\n", ????????????__func__); ????????memcpy(layout, &brcmstb_nand_dummy_layout, sizeof(*layout)); ????????return layout; ????}
????DBG("OOBLAYOUT: sas=%d??req=%d??sectors=%d\n", sas, req, sectors);
????layout->eccbytes = req * sectors; ????for (i = 0, idx1 = 0, idx2 = 0; i < sectors; i++) { ????????for (j = sas - req; j < sas && idx1 < ????????????????MTD_MAX_ECCPOS_ENTRIES_LARGE; j++, idx1++) ????????????layout->eccpos[idx1] = i * sas + j;? ? ? ? //對(duì)于BCH,ECC byte放在每個(gè)oob的最后面
????????/* First sector of each page may have BBI */ ????????if (i == 0) { ????????????if (cfg->page_size == 512 && (sas - req >= 6)) {? ?//小頁使用byte 6指示壞塊,一般page size都是2k ????????????????/* Small-page NAND use byte 6 for BBI */ ????????????????layout->oobfree[idx2].offset = 0; ????????????????layout->oobfree[idx2].length = 5; ????????????????idx2++; ????????????????if (sas - req > 6) { ????????????????????layout->oobfree[idx2].offset = 6; ????????????????????layout->oobfree[idx2].length = ????????????????????????sas - req - 6; ????????????????????idx2++; ????????????????} ????????????} else if (sas > req + 1) { ????????????????layout->oobfree[idx2].offset = i * sas + 1;? ? ?//使用byte 0?指示壞塊 ????????????????layout->oobfree[idx2].length = sas - req - 1; ????????????????idx2++; ????????????} ????????} else if (sas > req) { ????????????layout->oobfree[idx2].offset = i * sas; ????????????layout->oobfree[idx2].length = sas - req; ????????????idx2++; ????????} ????????/* Leave zero-terminated entry for OOBFREE */ ????????if (idx1 >= MTD_MAX_ECCPOS_ENTRIES_LARGE || ????????????????idx2 >= MTD_MAX_OOBFREE_ENTRIES_LARGE - 1) ????????????break; ????} out: ????/* Sum available OOB */ ????for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES_LARGE; i++) ????????layout->oobavail += layout->oobfree[i].length; ????return layout; }
對(duì)于大頁nand flash,一個(gè)page含義多個(gè)sector,每個(gè)sector 512byte或者1024byte,一個(gè)block含有多個(gè)頁。
通常,NAND控制器通過對(duì)OOB區(qū)域中的ECC字段進(jìn)行操作來在硬件中執(zhí)行糾錯(cuò)和檢測。但是,如果您的NAND控制器不支持錯(cuò)誤管理,則需要通過軟件讓MTD為您完成。MTD?nand_ecc驅(qū)動(dòng)程序(drivers / mtd / nand / nand_ecc.c)實(shí)現(xiàn)軟件ECC。 ????case NAND_ECC_SOFT: ????????chip->ecc.calculate = nand_calculate_ecc; ????????chip->ecc.correct = nand_correct_data; ????????chip->ecc.read_page = nand_read_page_swecc; ????????chip->ecc.read_subpage = nand_read_subpage; ????????chip->ecc.write_page = nand_write_page_swecc; ????????chip->ecc.read_page_raw = nand_read_page_raw; ????????chip->ecc.write_page_raw = nand_write_page_raw; ????????chip->ecc.read_oob = nand_read_oob_std; ????????chip->ecc.write_oob = nand_write_oob_std; ????????if (!chip->ecc.size) ????????????chip->ecc.size = 256; ????????chip->ecc.bytes = 3;
包含壞塊標(biāo)記的OOB存儲(chǔ)器字節(jié)。這些標(biāo)記用于標(biāo)記有故障的閃存塊,并且通常出現(xiàn)在屬于每個(gè)塊的第一頁的OOB區(qū)域中。標(biāo)記在OOB區(qū)域內(nèi)的位置取決于芯片的屬性。壞塊標(biāo)記可以在生產(chǎn)過程中在工廠設(shè)置,也可以在軟件中檢測到塊中的磨損。MTD在drivers / mtd / nand / nand_bbt.c中實(shí)現(xiàn)壞塊管理。 # # The NAND_BAD_BLOCK_INDICATOR_MAP has the following format: # #????????bit[15:8]???- Flags indicating which pages, offset from start of block, #??????????????????????are used as bad block indicators.??Bit8 = first page. #??????????????????????Bit15 = 8th page. # #????????bit[7:0]????- Flags indicating which OFS bytes are used as bad block #??????????????????????indicators for pages specified by bits[15:8].??Bit0 = OFS0. #??????????????????????Bit7 = OFS7. # #????????bit[31:24]??- Flags indicating which pages, offset from end of block, #??????????????????????are used as bad block indicators.??Bit24 = last page. #??????????????????????bit31 = 8th to the last page. # #????????bit[23:16]??- Flags indicating which OFS bytes are used as bad block #??????????????????????indicators for pages specified by bits[31:24].??Bit16 = OFS0. #??????????????????????Bit23 = OFS7. # # ifndef NAND_BAD_BLOCK_INDICATOR_MAP
ifeq ($(strip ${NAND_MEM_TYPE}),0) ????NAND_BAD_BLOCK_INDICATOR_MAP=0x00000301??#first 2 pages, OFS0 endif
ifeq ($(strip ${NAND_MEM_TYPE}),1) ????NAND_BAD_BLOCK_INDICATOR_MAP=0x00000301??#first 2 pages, OFS0 endif
ifeq ($(strip ${NAND_MEM_TYPE}),2) ????NAND_BAD_BLOCK_INDICATOR_MAP=0x03010000??#last 2 pages, OFS0 endif
ifeq ($(strip ${NAND_MEM_TYPE}),3) ????NAND_BAD_BLOCK_INDICATOR_MAP=0x03010000??#last 2 pages, OFS0 endif
endif 所以絕大多數(shù)都是block的前兩個(gè)頁的OFS0用來標(biāo)記壞塊,非0xFF則表示壞塊。
解析的過程可以參考boot代碼中的nand_get_page_status()函數(shù)
工具: 你必須使用nanddump和nandwrite等NAND感知工具而不是更常見的dd工具來創(chuàng)建或恢復(fù)NAND
nanddump -f /tmp/dump2.bin -l 131072 -s 131072??-o??/dev/mtd3
nandwrite -o??/dev/mtd3??/mnt/usb/dump1.bin
參考文檔: https://www.ece.umd.edu/~blj/CS-590.26/micron-tn2919.pdf https://www.ece.umd.edu/~blj/CS-590.26/nand-presentation-2010.pdf
總結(jié)
以上是生活随笔為你收集整理的nandflash驱动详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SAP ABAP开发视频学习(视频教程)
- 下一篇: 2023重庆邮电大学计算机考研信息汇总