nandflash驱动详解
生活随笔
收集整理的這篇文章主要介紹了
nandflash驱动详解
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
對nandflash存儲原理不了解的請先閱讀《flash memory技術》
架構圖
+ ----------- +系統總線+ ------------------- + CLE,io [8:0] + ----- -------------- + ?| cpu |←------------→| nand控制器| ←--------------→| nand flash | + ----------- + + ------------------- + + --------------- ---- +
cpu通過系統總線訪問nand控制器寄存器,設置讀寫flash的命令和相應的地址,當完成操作時nand controler發出中斷,也可以通過查詢nand controler的狀態寄存器來獲取操作狀態,nand controler將相應的命令狀態為nand flash能夠理解的時序
nand flash引腳
如果支持直接訪問模式,可以將nandflash直接映射到物理地址空間,通過XOR可以映射到不同的物理空間,這樣就可以直接從nandflash執行程序了(注意不能寫,因為寫之前必須要先擦除)
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 數據:flash_cache 128字節= 128 * 4 = 512字節
1.BCHP_NAND_CS_NAND_SELECT: [0:0]? EBI_CS_0_SEL【0-7】每位對一個銀行 指示EBI_CS0b是否使用直接尋址機制,并將Nand Flash映射到MIPS物理地址空間,并使用EBI_CS_BASE_0寄存器指定的基址和大小。(EBI_CS_CONFIG_0將被忽略。)
(注意:建議軟件使用寄存器陣列尋址,除了初始引導讀取之外的所有Nand Flash訪問,無論此位是否設置,都可以使用寄存器陣列尋址。
1 =允許直接尋址EBI_CS0b。 0 =僅使用EBI_CS0b的寄存器陣列尋址。當芯片從NAND閃存啟動時,該位被初始化。
[8:8] EBI_CS_0_USES_NAND 【8-15】每位對?? 一個銀行 指示EBI_CS0b是否連接到Nand Flash設備。該位不被硬件使用,但可由軟件用于指示哪些EBI_CS連接到Nand Flash器件。當芯片從NAND閃存啟動時,該位被初始化。
保留 [27:16]
WR_PROTECT_BLK0 [28:28] RW? 該位將保護連接到EBI_CS0b的Nand Flash的塊0的內容。該位置1時,控制器將忽略目標地址位于EBI_CS0b塊0中的閃存修改操作(PAGE_PROGRAM,ERASE等)。(塊大小由NAND_CONFIG_CS [n]寄存器的BLOCK_SIZE字段決定。)
1 =塊寫入EBI_CS0b塊0。 0 =允許寫入EBI_CS0b塊0。
復位值:0x0
NAND_WP [29:29] RW? 該位控制NAND_WPb引腳(通過反相器)以保護閃存器件。只要SW希望擦除或編程閃存,該位應由SW清零。
(請注意,內部電壓監視器檢測VDD,并且當VDD超出容許范圍時,NAND_WPb被驅動為低電平,無論此位的狀態如何。)
1 = NAND_WPb引腳為低電平。Flash受到寫保護。 0 = NAND_WPb引腳為高電平。Flash可以被擦除或編程。
重置值:0x1
AUTO_DEVICE_ID_CONFIG [30:30] RW? 如果設置了該位,則Nand Flash控制器將在任何其他Nand Flash訪問之前自動執行FLASH_RESET,然后執行Read Device ID命令。從Nand Flash器件返回的值將被硬件用于基于內部維護的已知Nand Flash器件的數據庫來初始化NAND_CONFIG_CS [n]寄存器。 當strap_nand_flash = 1時,該位??將被置1,并且讀取器件ID命令和NAND_CONFIG_CS [n]寄存器的初始化將在上電時發生。 如果軟件沒有設置該位,并且strap_nand_flash = 0,軟件應該在使用Nand Flash控制器之前(在寫入CMD_START之前)執行FLASH_RESET命令并初始化NAND_CONFIG_CS [n]寄存器。
1 =執行FLASH_RESET和Device ID讀取,NAND_CONFIG_CS [n]寄存器自動初始化。 0 =不要執行設備ID讀取或NAND_CONFIG_CS [n]初始化。
當芯片從NAND閃存啟動時,該位被初始化。
CS_LOCK [31:31] RW? 當該位設置為1時,該寄存器變為只讀寄存器,防止進一步寫入該寄存器。一旦設置,該位只能通過復位清零。
復位值:0x0
2.BCHP_NAND_CS_NAND_XOR EBI_CS_0_ADDR_XOR [0:0] RW?? 【0-7】每位對一個銀行 指示為EBI_CS0b指定的地址是否與0xE000_0000異或。 1 =與E000_0000到EBI_CS0b的XOR地址。 0 =直接將地址傳遞給EBI_CS0b(無XOR)。當芯片從NAND閃存啟動時,該位被初始化。
保留 [30:8] RWX???
ONLY_BLOCK_0_XOR [31:31] RW? 僅對塊0打開地址XOR。CS0中的所有其他塊地址不會異或。 該位僅影響CS0,因為塊0被定義為CS0器件的第一個塊。要使用該位,EBI_CS_0_ADDR_XOR也必須設置為1。 當控制器空閑時,軟件應該改變這個位。 1 =僅對塊0使用E000_0000的XOR地址。 0 =所有塊的EOR_0000異或地址。
復位值:0x0
INTFC_STATUS - Nand Flash接口狀態 CTLR_READY [31:31] R表示EBI內部Nand Flash接口控制器狀態機邏輯已完成此接口的所有命令。
FLASH_READY [30:30] R反映外部Nand Flash器件的R / B(就緒/忙碌)引腳的即時狀態。(0 =忙碌)
CACHE_VALID [29:29] R指示512字節的FlashCache緩沖區是否包含位于FLASH_READ_ADDR寄存器指示的地址處的有效數據。
SPARE_AREA_VALID [28:28] R指示16字節備用區域讀取寄存器是否包含位于FLASH_READ_ADDR寄存器指示的地址處的有效數據。
ERASED [27:27] R指示最近的PAGE_READ命令是否導致數據和備用區域的所有字節均為FFh。
PLANE_READY [26:26] R僅適用于多平面設備。 指示EBI內部Nand Flash接口控制器狀態機邏輯已在當前平面上完成PROGRAM_PAGE_MULTI命令。
保留[25:8] RX???
FLASH_STATUS [7:0] R在每次程序頁面,塊擦除或復制命令操作后,使用來自閃存設備的狀態讀取命令更新此字節值。 復位值:0x0
每個銀行的配置寄存器: Brcm nandflash控制器最多支持7個銀行
BCHP_NAND_ACC_CONTROL_CS0? ? ? ? ? ? ? ?Nand Flash訪問控制?
RD_ECC_EN [31:31] RW為PAGE_READ操作啟用ECC校正。 重置值:0x1
WR_ECC_EN [30:30] RW為任何塊啟用對PROGRAM_PAGE或PROGRAM_SPARE_AREA操作的ECC校驗位生成。當該位置位時,ECC字節將被忽略。 選擇漢明碼時的ECC字節位置是SPARE_AREA_WRITE_OFS_4和SPARE_AREA_WRITE_OFS_8寄存器的BYTE_OFS_6,BYTE_OFS_7和BYTE_OFS_8的3個字節。選擇BCH碼時的ECC字節位置是備用區域的最后字節位置。例如,如果SPARE_AREA_SIZE = 16且ECC_LEVEL = 4(7個ECC字節),則ECC字節位置是BYTE_OFS_9到BYTE_OFS_15中的16個字節中的最后7個。 當此位設置為PROGRAM_PAGE操作時,ECC字節將由H / W生成的ECC校驗字節替代; 對于PROGRAM_SPARE_AREA操作,ECC字節將被FFh替換。 重置值:0x1
CE_CARE [29:29] RW此字段僅適用于CE護理設備。 當設置為1時,EBI_CS [n]將在NAND_RBb低電平期間保持置位狀態(器件忙)。在此期間,其他芯片選擇中的器件無法訪問。 默認設置為0以獲得更好的性能。 復位值:0x0
保留 [28:28] RWX???
RD_ERASED_ECC_EN [27:27] RW確定擦除頁面中的PAGE_READ操作是否會生成不可糾正的ECC錯誤。(一個Erased Page被定義為全部512個數據字節,所有3個ECC字節都包含0xFF,剩余的Spare Area字節未被考慮)。無論該位的狀態如何,如果ECC被RD_ECC_EN = 0或RD_ECC_BLK0_EN = 0禁用,將不會生成錯誤。 1 =從擦除頁讀取生成ECC錯誤。 0 =從擦除頁讀取不會產生ECC錯誤。 復位值:0x0
PARTIAL_PAGE_EN [26:26] RW啟用部分頁面編程。建議清除此位以提高性能并防止部分頁面編程,這是許多nand閃存設備所禁止的。??當該位置位且軟件啟動PROGRAM_PAGE操作時,硬件將數據直接寫入閃存單元。當該位清零并且軟件啟動PROGRAM_PAGE操作時,硬件將數據移入NAND Flash設備緩存并返回空閑狀態。只有當NAND_CMD_ADDRESS指向頁面的最后512字節扇區時,硬件才會將數據編程到閃存單元中。 小頁面設備會忽略該位。 復位值:0x0
WR_PREEMPT_EN [25:25] RW使能其他EBI或PCI周期的寫突發操作的搶占。當另一個請求者試圖使用總線時,這允許將來自Flash外部總線的長512字節突發分成16次傳輸的多個突發。 重置值:0x1
PAGE_HIT_EN [24:24] RW啟用Flash頁面檢測檢測,作為頁面大小大于512B的頁面內512字節讀取的優化。該位僅為大頁面設備提供性能優化。如果設置,并且硬件發現讀取未命中,但是從已經讀入FlashCache的相同頁面,它將簡單地使用閃存的隨機讀取操作來節省時間。 重置值:0x1
PREFETCH_EN [23:23] RW硬件自動讀取當前頁面讀取命令地址的下一個512B或1KB數據,扇區大小取決于SECTOR_SIZE_1K位。啟用此位可提高讀取連續地址的性能。 預取對軟件是透明的。CTLR_READY位始終指示當前地址讀取完成。注:建議將此位設置為長連續讀取,例如DMA傳輸。如果讀取地址不連續,則由于后臺預取,軟件可能會看到更長的繁忙時間和性能下降。 注:僅當ECC_type為BCH時才支持預取。 復位值:0x0
CACHE_MODE_EN [22:22] RW啟用程序頁面或頁面讀取緩存模式。 如果置位,并且發出頁面讀取命令,硬件將啟動具有緩存模式操作碼31h的頁面讀操作。 如果置位,并且發出程序頁命令,則硬件以高速緩存模式操作碼15h結束程序頁操作。 緩存模式通過連續頁面訪問跳過閃存設備繁忙時間來提高性能。例如:第n,n + 1,n + 2,n + 3,n + 4 ... n + m的DMA傳輸 注:硬件不檢測頁面地址的連貫性。軟件需要管理設置這一點。要恢復正常的頁面讀取和程序頁面命令,請取消設置此位。 復位值:0x0
保留 [21:21] RWX???
ECC_LEVEL [20:16] RW設置每512個數據字節可以糾正的編碼類型和位數。 定義T:=每扇區可修正的位數。 當SECTOR_SIZE_1K = 0時,則T = ECC_LEVEL 當SECTOR_SIZE_1K = 1時,則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碼字大小,也稱為扇區大小。注意:當使用1k字節扇區大小時,ECC_LEVEL字段指定T值的一半,漢明碼不可用。 請參閱ECC_LEVEL說明中顯示的表。 注意:當使用1k字節扇區大小時,必須清除PARTIAL_PAGE_EN位,并且閃存頁面大小必須大于512。 0 512字節 1個1k字節
當strap_nand_flash = 1時,該字段將根據選定的ECC級別綁定在strap_nand_ecc_level [n:0]上進行初始化。 復位值:0x0
SPARE_AREA_SIZE [6:0] RW表示每512個數據字節包含在閃存設備中的備用區字節數。有效設置是16到64(含)。對于16位寬的NAND閃存器件,此字段必須包含偶數。 對于大頁面設備(頁面大小為2kB或更大),每頁的備用區域除以每頁的扇區數量。??例如,(2kB + 64B)頁面大小和512B扇區大小每頁有4個扇區,每頁全部64字節備用區域將被分成4個相等的部分,每個16字節; 并且這些部分中的每一個都將被不同的部門使用。 選擇漢明碼時的ECC字節位置是SPARE_AREA_WRITE_OFS_4和SPARE_AREA_WRITE_OFS_8寄存器的BYTE_OFS_6,BYTE_OFS_7和BYTE_OFS_8的3個字節。 選擇BCH碼時的ECC字節位置是該特定扇區的備用區的最后一個字節位置。??例如,如果SPARE_AREA_SIZE = 16且ECC_LEVEL = 4(7個ECC字節),則ECC字節位置是BYTE_OFS_9到BYTE_OFS_15中的16個字節中的最后7個。 當SECTOR_SIZE_1K = 1時,該字段仍指定每512個備用字節。
當strap_nand_flash = 1時,該字段將根據選定的ECC級別綁定在strap_nand_ecc_level [n:0]上進行初始化。 重置值:0x10
因為ECC校驗是由控制器自動完成的,那么就必須讓控制器知道該bank上的nandflash使用的ECC LEVEL和SPARE_AREA_SIZE,這樣控制器就能知道ECC字節在SPARE_AREA_READ_OFS_0中的位置.ECC字節在nandflash中的位置理論上來說跟nandflash沒有多大關系,因為nandflash對ECC字節是無知的,它由控制器來使用,nandflash會根據本身工藝推薦ECC LEVEL,理論上大于這個值都是可行的。
BCHP_NAND_CONFIG_EXT_CS0?????????? Nand Flash配置擴展? 閃存設備接口參數。根據NAND_CMD_EXT_ADDRESS寄存器中的CS_SEL值,硬件會根據剛剛復位后從外部Nand Flash器件讀取的DeviceID或ONFI參數值將缺省值裝入此寄存器。
保留[31:12] RWX???
BLOCK_SIZE [11:4] RW塊大小(以字節為單位)。(注意:該字段僅用于確定目標地址是否位于閃存的塊0中,以便在WR_PROTECT_BLK0位置位時知道是否應用寫保護,或者當RD_ECC_BLK0_EN位為是時是否執行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頁面大小(以字節為單位)。 值名稱說明 0 PG_SIZE_512 512字節。 1 PG_SIZE_1KB 1k字節。 2 PG_SIZE_2KB 2k字節。 3 PG_SIZE_4KB 4k字節。 4 PG_SIZE_8KB 8k字節。 5 PG_SIZE_16KB 16k字節。
BCHP_NAND_CONFIG_CS0????????????????? Nand Flash配置 閃存設備接口參數。根據NAND_CMD_EXT_ADDRESS寄存器中的CS_SEL值,硬件會根據剛剛復位后從外部Nand Flash器件讀取的DeviceID或ONFI參數值將缺省值裝入此寄存器。
CONFIG_LOCK [31:31] RW當該位設置為1時,該寄存器和CONFIG_EXT寄存器變為只讀寄存器,防止進一步寫入該寄存器和CONFIG_EXT寄存器。一旦設置,該位只能通過復位清零。 復位值:0x0
保留[30:28] RWX???
DEVICE_SIZE [27:24] RW設備大小(以字節為單位)。 值名稱 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設備I / O數據總線寬度(以位為單位)。 值名稱 0 DVC_WIDTH_8 1 DVC_WIDTH_16
保留[22:19] RWX???
FUL_ADR_BYTES [18:16] RW在設備內發送到Flash的完整地址的地址字節數。 當PAGE_SIZE> 512B時,FUL_ADR_BYTES = COL_ADR_BYTES + BLK_ADR_BYTES。 當PAGE_SIZE = 512B時,FUL_ADR_BYTES = 1 + BLK_ADR_BYTES。 該字段通過綁定或AUTO_DEVICE_ID_CONFIG初始化。
保留[15:15] RWX???
COL_ADR_BYTES [14:12] RW發送到Flash以指定頁面內隨機數據訪問的列地址的地址字節數。該字段僅用于頁面大小大于512B的頁面,用于頁面內的隨機尋址,以尋址PROGRAM_PAGE和PAGE_READ命令的備用區域。 2為512B <=頁面大小<= 32KB 該字段通過綁定或AUTO_DEVICE_ID_CONFIG初始化。
保留[11:11] RWX???
BLK_ADR_BYTES [10:8] RW發送到Flash以指定行和塊的地址字節數。該字段相當于NAND閃存數據表中的頁面地址+塊地址。 該字段僅用于BLOCK_ERASE和BLOCKS_UNLOCK命令。 該字段通過綁定或AUTO_DEVICE_ID_CONFIG初始化。
保留[7:0] RWX???
BCHP_NAND_TIMING_1_CS0???????????????? ?Nand Flash時序參數1? 閃存設備接口時序參數。時序以內部108 MHz時鐘(9.26 ns)或內部216 MHz時鐘(4.63 ns)為單位指定,具體取決于TIMING_2.CLK_SELECT的值。 任何時間字段中的最小值是2(2個時鐘)。
tWP [31:28] RW時鐘數WE低脈沖寬度。
重置值:0x6 tWH [27:24] RW片段數WE高脈沖寬度。(除了ALE較高時,在這種情況下,tALH控制WE高脈沖寬度而不是tWH。)
重置值:0x5 tRP [23:20] RW時鐘數RE低脈沖寬度。
重置值:0x7 tREH [19:16] RW時鐘數RE高脈沖寬度。
重置值:0x4 tCS [15:12] RW從CE低到第一個WE低的時鐘數。注意:當CLK_SELECT = CLK_108時,該寄存器字段中的值將被硬件加倍,當CLK_SELECT = CLK_216時,該值將被硬件加倍。
重置值:0x8 tCLH [11:8] RW從WE高到CLE低的塊數。
重置值:0x4 tALH [7:4] RW從WE高到ALE低的時針數量。而且,當ALE高時,屏幕的數量WE高脈沖寬度。該位應該被設置為來自閃存制造商數據表的tWH和tALH之間的較大值。
重置值:0x5 tADL [3:0] RW從最后一個addr到第一次數據寫入的時鐘片數。注意:當CLK_SELECT = CLK_108時,該寄存器字段中的值將被硬件加倍,當CLK_SELECT = CLK_216時,該值將被硬件加倍。
復位值:0xB
BCHP_NAND_TIMING_2_CS0?????????????????? ?Nand Flash時序參數2? 閃存設備接口時序參數。時序以內部108 MHz時鐘(9.26 ns)或內部216 MHz時鐘(4.63 ns)為單位指定,具體取決于TIMING_2.CLK_SELECT的值。 任何時間字段中的最小值是2(2個時鐘)。
CLK_SELECT [31:31] RW確定NAND_TIMING_1和NAND_TIMING_2中的參數用于nand閃存定時狀態機的時鐘。 值名稱說明 0 CLK_108內部108 MHz時鐘。 1 CLK_216內部216 MHz時鐘。
重置值:CLK_108 保留[30:20] RWX??? tCCS [19:16] RW更改列命令設置時間。 注:當CLK_SELECT = CLK_108時,硬件將該寄存器字段中的值翻兩倍,并且當CLK_SELECT = CLK_216時,該值將由硬件八倍。
重置值:0x9 保留[15:13] RWX??? tWB [12:9] RW在硬件開始采樣R / B引腳之前,CE的高電平時鐘數。注意:當CLK_SELECT = CLK_108時,該寄存器字段中的值將被硬件加倍,當CLK_SELECT = CLK_216時,該值將被硬件加倍。
復位值:0xF tWHR [8:4] RW從WE高到RE低的時鐘片數。此參數僅用于狀態讀取和設備ID讀取操作。注意:當CLK_SELECT = CLK_108時,該寄存器字段中的值將被硬件加倍,當CLK_SELECT = CLK_216時,該值將被硬件加倍。
重置值:0x9 tREAD [3:0] RW RE低后采樣讀取數據之前等待的時鐘數。
為獲得最佳性能,應通過將nns閃存器件的RE存取時間(tREA)加上17ns,然后將總和除以CLK_SELECT所選的時鐘周期,然后將其四舍五入至下一較大整數來計算此參數。例如,如果器件tREA = 20ns并且CLK_SELECT = 1(216MHz => 4.63ns): tREAD =(20ns + 17ns)/4.63ns=7.99(四舍五入)=> 8。
tREAD的最大值是(tRP + tREH)。
重置值:0x6
操作時序 在編程操作中,要被編程的數據在WE#的上升沿被同步到數據寄存器中。 數據以類似的方式通過讀使能(RE#)信號從數據寄存器輸出,該信號負責輸出當前數據并遞增到下一個位置。WE#和RE#時鐘每次傳輸可以運行25ns。當RE#或芯片使能(CE#)未置為低電平時,輸出緩沖器為三態。CE#和RE#的這種組合激活了輸出緩沖器,使NAND Flash能夠與其他類型的存儲器(如NOR閃存,SRAM或DRAM)共享數據總線。這個功能有時被稱為“芯片使能不關心”。 在RE#為低時,讀使能,輸出緩沖器直接放置在io上,可跟著變化。 所有的NAND Flash操作都是通過發出一個命令周期來啟動的。這是通過將命令放在I / O [7:0]上,驅動CE#為低電平并且為高電平,然后發出WE#時鐘來完成的。命令,地址和數據在WE#的上升沿時鐘輸入NAND閃存器件, 大多數命令需要多個地址周期,然后是第二個命令周期。除RESET和READ STATUS命令外,當設備忙時不應發出新命令。 支持的命令:
2Gb NAND Flash器件的尋址方案如表6所示。第一個和第二個地址周期(或字節)指定了列地址,它指定了頁面內的起始字節。最后一列的位置是2112,因此最后一個位置的地址是第二個字節中的08h,第一個字節中是3Fh。PA [5:0]指定塊內的頁面地址,BA [16:6]指定塊地址。盡管大多數PROGRAM和READ操作需要完整的5字節地址,但對于在頁面內隨機訪問數據的操作,只需要第一個和第二個字節(或循環)。BLOCK ERASE操作只需要三個最重要的字節(第三,第四和第五)來選擇該塊。
當CA11 = 1時表示訪問oob數據,一般列地址都為0,表示從頁面內偏移0開始訪問整個頁面。
復位操作 RESET是NAND Flash器件繁忙時可以發出的兩個命令之一。如果設備正忙于處理先前的命令,則發出RESET命令會中止前一個操作。如果之前的操作是ERASE或PROGRAM命令,則發出RESET命令會過早地中止該命令,并且所需的操作不會完成。ERASE和PROGRAM可以是耗時的操作; 發出RESET命令可以中止或稍后重新發出命令。
CE先拉低選中芯片,在io [8:0]上放置FFh,然后CLE拉高,將io [8:0]與命令鎖存器相連,然后將WE拉低,接著拉高,在上升沿完成命令的寫操作,延時TWB后查詢R / B腳的狀態,當為1時表示RESET完成。
READ ID操作 READ ID(90h)命令需要一個虛擬地址周期(00h),但不需要第二個命令周期。在發出命令和虛擬地址后,通過保持CLE和ALE為低電平并讀取ID的每個字節的RE#信號,可以讀出ID數據。
CE先拉低選中chip,在io [8:0]上放置90h,然后CLE拉高,將io [8:0]與命令鎖存器相連,然后將WE拉低,接著拉高,在上升沿完成命令的寫操作,然后拉低CLE,拉高ALE,將io [8:0]與地址鎖存器相連,在io [8:0]上放置00h,然后將WE拉低,然后拉高WE ,在上升沿完成addrees的寫操作,接著拉低ALE,適當的延時后拉低RE,(CLE和ALE都為低時,IO [8:0]與數據鎖存器相連,CLE和ALE都為高時為非法),chip將數據放置在io [8:0]上,nand controler從io [8:0]上讀取數據,讀完后RE拉高,然后拉低讀取下一個字節。
READ STATUS操作 讀取狀態(70h)是NAND Flash器件忙時可以發出的第二個命令。該命令不需要地址或第二個命令周期。通過在READ STATUS命令之后發出RE#時鐘信號,可以監控NAND閃存器件的狀態。如果使用READ STATUS命令監視器件的就緒狀態,則該命令只能發出一次,并且可以通過重新發出RE#時鐘來重新讀取狀態。或者,RE#信號可以保持低電平,在繼續之前等待接收適當的狀態位。READ STATUS還會報告寫保護信號的狀態以及之前PROGRAM或ERASE操作的通過/失敗狀態。在PROGRAM或ERASE操作中必須達到合格狀態以確保數據完整性。
擦除操作 BLOCK ERASE(60h)操作會擦除整個64頁的頁面,總共128KB。要發出BLOCK ERASE操作,使用WE#信號在CLE置位時在ERASE(60h)命令中計時。接下來,在三個地址周期中的時鐘,保持每個字節地址的ALE有效。(這三個地址周期是最重要的地址周期,包括塊地址和頁地址,如第9頁的表6所示。)頁地址部分(第三個地址周期的六個低位)被忽略,并且只使用三個最高有效字節的塊地址部分。地址完全輸入后,發出D0h的第二個命令(命令周期2),當CLE置位時,它由WE#提供時鐘。這確認了ERASE操作,并且設備忙了大約500μs。當設備完成此操作時,它已準備好執行另一個命令。READ STATUS命令可以隨時發出,即使在ERASE操作過程中設備處于繁忙狀態。微處理器或控制器可以通過READ STATUS命令監視設備
提交70H命令查詢狀態后,RE一直為低,監控IO [5]引腳上的值,為0時表示擦除完成
程序操作 PROGRAM操作只能將位編程為0,并假定用戶以先前擦除的塊開始。如果用戶不想編程一個位(或一組位),則通過將該特定位/組設置為1,可以將位保持在擦除狀態。當接收到編程頁(80h)命令時,輸入寄存器被重置(內部)到全1。這支持只輸入要用0位編程的數據字節。PROGRAM操作從80h命令開始(CLE置位 - 見圖8)。接下來,取消斷言CLE并斷言ALE輸入完整的五個地址周期。輸入命令和地址后,數據輸入到寄存器。當所有的數據都被輸入時,發出10h命令來確認前一個命令并開始編程操作。PROGRAM操作通常需要220μs,雖然它可能需要多達600μs。用戶必須閱讀狀態并檢查操作是否成功。如果操作不成功,則該塊應該記錄為壞塊并且將來不會使用。所有的數據應該移到一個好的塊。
可以編程1-2112個字節,根據col add,如果頁內偏移為0,即編程整個頁,則2112個字節
READ操作 READ操作從00h命令開始,隨后是5個地址周期,然后是30h命令以確認命令序列。經過大約25μs的讀取傳輸時間(t R)后,數據被加載到寄存器并準備輸出。置位RE#使NAND Flash器件能夠輸出與地址中指定的列地址相對應的數據的第一個字節。隨后的RE#從連續的列位置轉換輸出數據。當RE#信號為高(未置位)時,I / O線為三態。讀取設備末尾(字節2112或字1056)會導致無效數據。
READ PAGE CACHE SEQUENTIAL操作 至此只討論了NAND??閃存器件中的一個寄存器。NAND Flash器件實際上有兩個寄存器,一個數據寄存器和一個高速緩存寄存器,如圖12所示。這兩個寄存器的屬性在各種NAND Flash緩存模式中起著重要的作用。PAGE READ CACHE MODE命令使用戶能夠在輸出先前訪問的數據的同時從數組中流水線化下一個順序訪問。這種雙緩沖技術可以隱藏讀取傳輸時間(t R)。數據最初從NAND閃存陣列傳輸到數據寄存器。如果高速緩存寄存器可用(不忙),數據將很快從數據寄存器移至高速緩存寄存器。數據傳輸到高速緩存寄存器后,數據寄存器可用,并且可以開始加載NAND閃存陣列中的下一個連續頁面。與8位I / O設備上的傳統PAGE READ命令相比,使用PAGE READ CACHE MODE命令可提高33%的性能,吞吐量可達31 MB / s。在16位I / O設備上,吞吐量可以提高到37 MB / s,與普通的PAGE READ操作相比,性能提高40%。 www.micron.com/products/nand/technotes上的技術說明提供了有關緩存模式的更多詳細信息以及如何使用它們來提高性能。PAGE READ CACHE MODE在系統啟動時特別有用,當大量數據通常從NAND閃存設備中讀取并且啟動時間非常關鍵時。
PROGRAM PAGE CACHE操作 PROGRAM PAGE CACHE MODE提供比正常PROGRAM PAGE操作更高的性能(見圖14和15)。PROGRAM PAGE CACHE MODE是一種雙緩沖技術,它使控制器能夠將數據直接輸入到高速緩存寄存器,并使用數據寄存器作為存儲區來提供用于編程陣列的數據。這將釋放高速緩存寄存器,以便可以并行加載下一個順序頁面操作。在許多應用中,編程時間(t PROG)可以完全隱藏。與PAGE READ CACHE MODE命令一樣,數據寄存器用于在整個編程周期內保持數據吞吐量。這將釋放緩存寄存器以接收來自控制器的下一頁數據。
存儲方法 圖10顯示了將數據和備用信息存儲在同一頁面的兩種常用方法。第一種方法顯示512字節的數據區加上與其直接相鄰的16字節備用區; 組合區域為528字節。一個2112字節的頁面可以包含這些528字節元素中的四個。第二個實施涉及單獨存儲數據和備用信息。四個512字節的數據區首先被存儲,并且它們對應的16字節備用區按順序依次位于頁面的末尾。
至于具體采用哪種存儲方式,由控制器決定,在NANDFLASH看來,數據和OOB并沒有什么區別.BRCM控制器采用的第二種方式。
部分頁面編程 與NAND接口一致,NAND中的基本編程單元是一個頁面; 然而,通過利用部分頁面編程,可以將頁面編程成更小的部分。為了便于部分頁面編程,每個頁面被進一步分成八個段(數據區域四個,備用區域四個)。 頁面中的每個段都充當獨立的可編程單元; 它們可以單獨編程或以任何組合段編程。每個片段允許的最大連續部分頁面程序數量為1。也就是說,頁面中的每個段可以被編程一次,并且在需要塊擦除之前頁面可以被編程多達八次。 部分頁面編程通過發出一個輸入命令(80h),然后是多段編程的隨機數據輸入命令(85h)序列完成。加載最后一個數據后,程序確認命令(10h)啟動編程操作并將數據寫入到所需位置的緩沖區中。寫狀態位(I / O0)可以通過命令(70h)進行驗證,以驗證編程是否成功。
部分頁面讀取 部分頁面讀取是通過發出一個讀取命令(00h),然后是一個隨機數據讀取命令(05h)序列來完成多段讀取。?
讀取內部數據移動操作 READ FOR INTERNAL DATA MOVE(00h-35h)命令也被稱為“復制”。它提供了將數據從一個頁面內部移動到另一個頁面的能力 - 數據永遠不會離開NAND Flash設備。READ FOR INTERNAL DATA MOVE操作將從NAND閃存陣列讀取的數據傳輸到高速緩存寄存器。數據可以被編程到設備的另一個頁面中。這在控制器在擦除塊之前需要將數據從塊中移出的情況下非常有用。在PROGRAM操作開始之前,也可以修改讀取的數據。如果用戶想在編程之前更改數據,這很有用。此功能可在NAND Flash設備內移動數據,而無需占用處理器或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:超時等待命令(%#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比較智能,我們只需要設置要進行的操作和地址,控制器會自動解釋發出芯片能夠理解的命令和地址。
Linux的內核中關于NANDFLASH的代碼: include / mtd / mtd-abi.h中定義的nand_ecclayout 結構指定OOB備用區域的布局:? struct nand_ecclayout { uint 32_t eccbytes; uint32_t eccpos [64]; uint32_t oobavail; struct nand_oobfree oobfree [MTD_MAX_OOBFREE_ENTRIES]; };
在此結構中,eccbytes 保存存儲ECC數據的OOB字節的數量,eccpos 是包含ECC數據的OOB區域的偏移量數組。oobfree 將可用于閃存文件系統的OOB區域中未使用的字節記錄為用于存儲標志的標志,例如清除標志,表示擦除操作成功完成。 各個NAND程序驅動根據芯片的屬性初始化它們的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; ????整個行業; ????int sas; ????int idx1,idx2;
????layout = kzalloc(sizeof(* layout),GFP_KERNEL); ????if(!layout){ ????????pr_err(“%s:無法分配內存\ 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 ++){ ????????????/ *每個頁面的第一個扇區可能有BBI * / ????????????if(i == 0){ ????????????????layout-> oobfree [idx2] .offset = i * sas + 1; ????????????????/ *小頁面NAND使用字節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;? ? ? //對于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;? ? ? // 根據ECC LEVEL得到需要的ECC byte數 ????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;? ? ? ? //對于BCH,ECC byte放在每個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; }
對于大頁nand flash,一個page含義多個sector,每個sector 512byte或者1024byte,一個block含有多個頁。
通常,NAND控制器通過對OOB區域中的ECC字段進行操作來在硬件中執行糾錯和檢測。但是,如果您的NAND控制器不支持錯誤管理,則需要通過軟件讓MTD為您完成。MTD?nand_ecc驅動程序(drivers / mtd / nand / nand_ecc.c)實現軟件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;
包含壞塊標記的OOB存儲器字節。這些標記用于標記有故障的閃存塊,并且通常出現在屬于每個塊的第一頁的OOB區域中。標記在OOB區域內的位置取決于芯片的屬性。壞塊標記可以在生產過程中在工廠設置,也可以在軟件中檢測到塊中的磨損。MTD在drivers / mtd / nand / nand_bbt.c中實現壞塊管理。 # # 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 所以絕大多數都是block的前兩個頁的OFS0用來標記壞塊,非0xFF則表示壞塊。
解析的過程可以參考boot代碼中的nand_get_page_status()函數
工具: 你必須使用nanddump和nandwrite等NAND感知工具而不是更常見的dd工具來創建或恢復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
+ ----------- +系統總線+ ------------------- + CLE,io [8:0] + ----- -------------- + ?| cpu |←------------→| nand控制器| ←--------------→| nand flash | + ----------- + + ------------------- + + --------------- ---- +
cpu通過系統總線訪問nand控制器寄存器,設置讀寫flash的命令和相應的地址,當完成操作時nand controler發出中斷,也可以通過查詢nand controler的狀態寄存器來獲取操作狀態,nand controler將相應的命令狀態為nand flash能夠理解的時序
nand flash引腳
如果支持直接訪問模式,可以將nandflash直接映射到物理地址空間,通過XOR可以映射到不同的物理空間,這樣就可以直接從nandflash執行程序了(注意不能寫,因為寫之前必須要先擦除)
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 數據:flash_cache 128字節= 128 * 4 = 512字節
1.BCHP_NAND_CS_NAND_SELECT: [0:0]? EBI_CS_0_SEL【0-7】每位對一個銀行 指示EBI_CS0b是否使用直接尋址機制,并將Nand Flash映射到MIPS物理地址空間,并使用EBI_CS_BASE_0寄存器指定的基址和大小。(EBI_CS_CONFIG_0將被忽略。)
(注意:建議軟件使用寄存器陣列尋址,除了初始引導讀取之外的所有Nand Flash訪問,無論此位是否設置,都可以使用寄存器陣列尋址。
1 =允許直接尋址EBI_CS0b。 0 =僅使用EBI_CS0b的寄存器陣列尋址。當芯片從NAND閃存啟動時,該位被初始化。
[8:8] EBI_CS_0_USES_NAND 【8-15】每位對?? 一個銀行 指示EBI_CS0b是否連接到Nand Flash設備。該位不被硬件使用,但可由軟件用于指示哪些EBI_CS連接到Nand Flash器件。當芯片從NAND閃存啟動時,該位被初始化。
保留 [27:16]
WR_PROTECT_BLK0 [28:28] RW? 該位將保護連接到EBI_CS0b的Nand Flash的塊0的內容。該位置1時,控制器將忽略目標地址位于EBI_CS0b塊0中的閃存修改操作(PAGE_PROGRAM,ERASE等)。(塊大小由NAND_CONFIG_CS [n]寄存器的BLOCK_SIZE字段決定。)
1 =塊寫入EBI_CS0b塊0。 0 =允許寫入EBI_CS0b塊0。
復位值:0x0
NAND_WP [29:29] RW? 該位控制NAND_WPb引腳(通過反相器)以保護閃存器件。只要SW希望擦除或編程閃存,該位應由SW清零。
(請注意,內部電壓監視器檢測VDD,并且當VDD超出容許范圍時,NAND_WPb被驅動為低電平,無論此位的狀態如何。)
1 = NAND_WPb引腳為低電平。Flash受到寫保護。 0 = NAND_WPb引腳為高電平。Flash可以被擦除或編程。
重置值:0x1
AUTO_DEVICE_ID_CONFIG [30:30] RW? 如果設置了該位,則Nand Flash控制器將在任何其他Nand Flash訪問之前自動執行FLASH_RESET,然后執行Read Device ID命令。從Nand Flash器件返回的值將被硬件用于基于內部維護的已知Nand Flash器件的數據庫來初始化NAND_CONFIG_CS [n]寄存器。 當strap_nand_flash = 1時,該位??將被置1,并且讀取器件ID命令和NAND_CONFIG_CS [n]寄存器的初始化將在上電時發生。 如果軟件沒有設置該位,并且strap_nand_flash = 0,軟件應該在使用Nand Flash控制器之前(在寫入CMD_START之前)執行FLASH_RESET命令并初始化NAND_CONFIG_CS [n]寄存器。
1 =執行FLASH_RESET和Device ID讀取,NAND_CONFIG_CS [n]寄存器自動初始化。 0 =不要執行設備ID讀取或NAND_CONFIG_CS [n]初始化。
當芯片從NAND閃存啟動時,該位被初始化。
CS_LOCK [31:31] RW? 當該位設置為1時,該寄存器變為只讀寄存器,防止進一步寫入該寄存器。一旦設置,該位只能通過復位清零。
復位值:0x0
2.BCHP_NAND_CS_NAND_XOR EBI_CS_0_ADDR_XOR [0:0] RW?? 【0-7】每位對一個銀行 指示為EBI_CS0b指定的地址是否與0xE000_0000異或。 1 =與E000_0000到EBI_CS0b的XOR地址。 0 =直接將地址傳遞給EBI_CS0b(無XOR)。當芯片從NAND閃存啟動時,該位被初始化。
保留 [30:8] RWX???
ONLY_BLOCK_0_XOR [31:31] RW? 僅對塊0打開地址XOR。CS0中的所有其他塊地址不會異或。 該位僅影響CS0,因為塊0被定義為CS0器件的第一個塊。要使用該位,EBI_CS_0_ADDR_XOR也必須設置為1。 當控制器空閑時,軟件應該改變這個位。 1 =僅對塊0使用E000_0000的XOR地址。 0 =所有塊的EOR_0000異或地址。
復位值:0x0
INTFC_STATUS - Nand Flash接口狀態 CTLR_READY [31:31] R表示EBI內部Nand Flash接口控制器狀態機邏輯已完成此接口的所有命令。
FLASH_READY [30:30] R反映外部Nand Flash器件的R / B(就緒/忙碌)引腳的即時狀態。(0 =忙碌)
CACHE_VALID [29:29] R指示512字節的FlashCache緩沖區是否包含位于FLASH_READ_ADDR寄存器指示的地址處的有效數據。
SPARE_AREA_VALID [28:28] R指示16字節備用區域讀取寄存器是否包含位于FLASH_READ_ADDR寄存器指示的地址處的有效數據。
ERASED [27:27] R指示最近的PAGE_READ命令是否導致數據和備用區域的所有字節均為FFh。
PLANE_READY [26:26] R僅適用于多平面設備。 指示EBI內部Nand Flash接口控制器狀態機邏輯已在當前平面上完成PROGRAM_PAGE_MULTI命令。
保留[25:8] RX???
FLASH_STATUS [7:0] R在每次程序頁面,塊擦除或復制命令操作后,使用來自閃存設備的狀態讀取命令更新此字節值。 復位值:0x0
每個銀行的配置寄存器: Brcm nandflash控制器最多支持7個銀行
BCHP_NAND_ACC_CONTROL_CS0? ? ? ? ? ? ? ?Nand Flash訪問控制?
RD_ECC_EN [31:31] RW為PAGE_READ操作啟用ECC校正。 重置值:0x1
WR_ECC_EN [30:30] RW為任何塊啟用對PROGRAM_PAGE或PROGRAM_SPARE_AREA操作的ECC校驗位生成。當該位置位時,ECC字節將被忽略。 選擇漢明碼時的ECC字節位置是SPARE_AREA_WRITE_OFS_4和SPARE_AREA_WRITE_OFS_8寄存器的BYTE_OFS_6,BYTE_OFS_7和BYTE_OFS_8的3個字節。選擇BCH碼時的ECC字節位置是備用區域的最后字節位置。例如,如果SPARE_AREA_SIZE = 16且ECC_LEVEL = 4(7個ECC字節),則ECC字節位置是BYTE_OFS_9到BYTE_OFS_15中的16個字節中的最后7個。 當此位設置為PROGRAM_PAGE操作時,ECC字節將由H / W生成的ECC校驗字節替代; 對于PROGRAM_SPARE_AREA操作,ECC字節將被FFh替換。 重置值:0x1
CE_CARE [29:29] RW此字段僅適用于CE護理設備。 當設置為1時,EBI_CS [n]將在NAND_RBb低電平期間保持置位狀態(器件忙)。在此期間,其他芯片選擇中的器件無法訪問。 默認設置為0以獲得更好的性能。 復位值:0x0
保留 [28:28] RWX???
RD_ERASED_ECC_EN [27:27] RW確定擦除頁面中的PAGE_READ操作是否會生成不可糾正的ECC錯誤。(一個Erased Page被定義為全部512個數據字節,所有3個ECC字節都包含0xFF,剩余的Spare Area字節未被考慮)。無論該位的狀態如何,如果ECC被RD_ECC_EN = 0或RD_ECC_BLK0_EN = 0禁用,將不會生成錯誤。 1 =從擦除頁讀取生成ECC錯誤。 0 =從擦除頁讀取不會產生ECC錯誤。 復位值:0x0
PARTIAL_PAGE_EN [26:26] RW啟用部分頁面編程。建議清除此位以提高性能并防止部分頁面編程,這是許多nand閃存設備所禁止的。??當該位置位且軟件啟動PROGRAM_PAGE操作時,硬件將數據直接寫入閃存單元。當該位清零并且軟件啟動PROGRAM_PAGE操作時,硬件將數據移入NAND Flash設備緩存并返回空閑狀態。只有當NAND_CMD_ADDRESS指向頁面的最后512字節扇區時,硬件才會將數據編程到閃存單元中。 小頁面設備會忽略該位。 復位值:0x0
WR_PREEMPT_EN [25:25] RW使能其他EBI或PCI周期的寫突發操作的搶占。當另一個請求者試圖使用總線時,這允許將來自Flash外部總線的長512字節突發分成16次傳輸的多個突發。 重置值:0x1
PAGE_HIT_EN [24:24] RW啟用Flash頁面檢測檢測,作為頁面大小大于512B的頁面內512字節讀取的優化。該位僅為大頁面設備提供性能優化。如果設置,并且硬件發現讀取未命中,但是從已經讀入FlashCache的相同頁面,它將簡單地使用閃存的隨機讀取操作來節省時間。 重置值:0x1
PREFETCH_EN [23:23] RW硬件自動讀取當前頁面讀取命令地址的下一個512B或1KB數據,扇區大小取決于SECTOR_SIZE_1K位。啟用此位可提高讀取連續地址的性能。 預取對軟件是透明的。CTLR_READY位始終指示當前地址讀取完成。注:建議將此位設置為長連續讀取,例如DMA傳輸。如果讀取地址不連續,則由于后臺預取,軟件可能會看到更長的繁忙時間和性能下降。 注:僅當ECC_type為BCH時才支持預取。 復位值:0x0
CACHE_MODE_EN [22:22] RW啟用程序頁面或頁面讀取緩存模式。 如果置位,并且發出頁面讀取命令,硬件將啟動具有緩存模式操作碼31h的頁面讀操作。 如果置位,并且發出程序頁命令,則硬件以高速緩存模式操作碼15h結束程序頁操作。 緩存模式通過連續頁面訪問跳過閃存設備繁忙時間來提高性能。例如:第n,n + 1,n + 2,n + 3,n + 4 ... n + m的DMA傳輸 注:硬件不檢測頁面地址的連貫性。軟件需要管理設置這一點。要恢復正常的頁面讀取和程序頁面命令,請取消設置此位。 復位值:0x0
保留 [21:21] RWX???
ECC_LEVEL [20:16] RW設置每512個數據字節可以糾正的編碼類型和位數。 定義T:=每扇區可修正的位數。 當SECTOR_SIZE_1K = 0時,則T = ECC_LEVEL 當SECTOR_SIZE_1K = 1時,則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碼字大小,也稱為扇區大小。注意:當使用1k字節扇區大小時,ECC_LEVEL字段指定T值的一半,漢明碼不可用。 請參閱ECC_LEVEL說明中顯示的表。 注意:當使用1k字節扇區大小時,必須清除PARTIAL_PAGE_EN位,并且閃存頁面大小必須大于512。 0 512字節 1個1k字節
當strap_nand_flash = 1時,該字段將根據選定的ECC級別綁定在strap_nand_ecc_level [n:0]上進行初始化。 復位值:0x0
SPARE_AREA_SIZE [6:0] RW表示每512個數據字節包含在閃存設備中的備用區字節數。有效設置是16到64(含)。對于16位寬的NAND閃存器件,此字段必須包含偶數。 對于大頁面設備(頁面大小為2kB或更大),每頁的備用區域除以每頁的扇區數量。??例如,(2kB + 64B)頁面大小和512B扇區大小每頁有4個扇區,每頁全部64字節備用區域將被分成4個相等的部分,每個16字節; 并且這些部分中的每一個都將被不同的部門使用。 選擇漢明碼時的ECC字節位置是SPARE_AREA_WRITE_OFS_4和SPARE_AREA_WRITE_OFS_8寄存器的BYTE_OFS_6,BYTE_OFS_7和BYTE_OFS_8的3個字節。 選擇BCH碼時的ECC字節位置是該特定扇區的備用區的最后一個字節位置。??例如,如果SPARE_AREA_SIZE = 16且ECC_LEVEL = 4(7個ECC字節),則ECC字節位置是BYTE_OFS_9到BYTE_OFS_15中的16個字節中的最后7個。 當SECTOR_SIZE_1K = 1時,該字段仍指定每512個備用字節。
當strap_nand_flash = 1時,該字段將根據選定的ECC級別綁定在strap_nand_ecc_level [n:0]上進行初始化。 重置值:0x10
因為ECC校驗是由控制器自動完成的,那么就必須讓控制器知道該bank上的nandflash使用的ECC LEVEL和SPARE_AREA_SIZE,這樣控制器就能知道ECC字節在SPARE_AREA_READ_OFS_0中的位置.ECC字節在nandflash中的位置理論上來說跟nandflash沒有多大關系,因為nandflash對ECC字節是無知的,它由控制器來使用,nandflash會根據本身工藝推薦ECC LEVEL,理論上大于這個值都是可行的。
BCHP_NAND_CONFIG_EXT_CS0?????????? Nand Flash配置擴展? 閃存設備接口參數。根據NAND_CMD_EXT_ADDRESS寄存器中的CS_SEL值,硬件會根據剛剛復位后從外部Nand Flash器件讀取的DeviceID或ONFI參數值將缺省值裝入此寄存器。
保留[31:12] RWX???
BLOCK_SIZE [11:4] RW塊大小(以字節為單位)。(注意:該字段僅用于確定目標地址是否位于閃存的塊0中,以便在WR_PROTECT_BLK0位置位時知道是否應用寫保護,或者當RD_ECC_BLK0_EN位為是時是否執行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頁面大小(以字節為單位)。 值名稱說明 0 PG_SIZE_512 512字節。 1 PG_SIZE_1KB 1k字節。 2 PG_SIZE_2KB 2k字節。 3 PG_SIZE_4KB 4k字節。 4 PG_SIZE_8KB 8k字節。 5 PG_SIZE_16KB 16k字節。
BCHP_NAND_CONFIG_CS0????????????????? Nand Flash配置 閃存設備接口參數。根據NAND_CMD_EXT_ADDRESS寄存器中的CS_SEL值,硬件會根據剛剛復位后從外部Nand Flash器件讀取的DeviceID或ONFI參數值將缺省值裝入此寄存器。
CONFIG_LOCK [31:31] RW當該位設置為1時,該寄存器和CONFIG_EXT寄存器變為只讀寄存器,防止進一步寫入該寄存器和CONFIG_EXT寄存器。一旦設置,該位只能通過復位清零。 復位值:0x0
保留[30:28] RWX???
DEVICE_SIZE [27:24] RW設備大小(以字節為單位)。 值名稱 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設備I / O數據總線寬度(以位為單位)。 值名稱 0 DVC_WIDTH_8 1 DVC_WIDTH_16
保留[22:19] RWX???
FUL_ADR_BYTES [18:16] RW在設備內發送到Flash的完整地址的地址字節數。 當PAGE_SIZE> 512B時,FUL_ADR_BYTES = COL_ADR_BYTES + BLK_ADR_BYTES。 當PAGE_SIZE = 512B時,FUL_ADR_BYTES = 1 + BLK_ADR_BYTES。 該字段通過綁定或AUTO_DEVICE_ID_CONFIG初始化。
保留[15:15] RWX???
COL_ADR_BYTES [14:12] RW發送到Flash以指定頁面內隨機數據訪問的列地址的地址字節數。該字段僅用于頁面大小大于512B的頁面,用于頁面內的隨機尋址,以尋址PROGRAM_PAGE和PAGE_READ命令的備用區域。 2為512B <=頁面大小<= 32KB 該字段通過綁定或AUTO_DEVICE_ID_CONFIG初始化。
保留[11:11] RWX???
BLK_ADR_BYTES [10:8] RW發送到Flash以指定行和塊的地址字節數。該字段相當于NAND閃存數據表中的頁面地址+塊地址。 該字段僅用于BLOCK_ERASE和BLOCKS_UNLOCK命令。 該字段通過綁定或AUTO_DEVICE_ID_CONFIG初始化。
保留[7:0] RWX???
BCHP_NAND_TIMING_1_CS0???????????????? ?Nand Flash時序參數1? 閃存設備接口時序參數。時序以內部108 MHz時鐘(9.26 ns)或內部216 MHz時鐘(4.63 ns)為單位指定,具體取決于TIMING_2.CLK_SELECT的值。 任何時間字段中的最小值是2(2個時鐘)。
tWP [31:28] RW時鐘數WE低脈沖寬度。
重置值:0x6 tWH [27:24] RW片段數WE高脈沖寬度。(除了ALE較高時,在這種情況下,tALH控制WE高脈沖寬度而不是tWH。)
重置值:0x5 tRP [23:20] RW時鐘數RE低脈沖寬度。
重置值:0x7 tREH [19:16] RW時鐘數RE高脈沖寬度。
重置值:0x4 tCS [15:12] RW從CE低到第一個WE低的時鐘數。注意:當CLK_SELECT = CLK_108時,該寄存器字段中的值將被硬件加倍,當CLK_SELECT = CLK_216時,該值將被硬件加倍。
重置值:0x8 tCLH [11:8] RW從WE高到CLE低的塊數。
重置值:0x4 tALH [7:4] RW從WE高到ALE低的時針數量。而且,當ALE高時,屏幕的數量WE高脈沖寬度。該位應該被設置為來自閃存制造商數據表的tWH和tALH之間的較大值。
重置值:0x5 tADL [3:0] RW從最后一個addr到第一次數據寫入的時鐘片數。注意:當CLK_SELECT = CLK_108時,該寄存器字段中的值將被硬件加倍,當CLK_SELECT = CLK_216時,該值將被硬件加倍。
復位值:0xB
BCHP_NAND_TIMING_2_CS0?????????????????? ?Nand Flash時序參數2? 閃存設備接口時序參數。時序以內部108 MHz時鐘(9.26 ns)或內部216 MHz時鐘(4.63 ns)為單位指定,具體取決于TIMING_2.CLK_SELECT的值。 任何時間字段中的最小值是2(2個時鐘)。
CLK_SELECT [31:31] RW確定NAND_TIMING_1和NAND_TIMING_2中的參數用于nand閃存定時狀態機的時鐘。 值名稱說明 0 CLK_108內部108 MHz時鐘。 1 CLK_216內部216 MHz時鐘。
重置值:CLK_108 保留[30:20] RWX??? tCCS [19:16] RW更改列命令設置時間。 注:當CLK_SELECT = CLK_108時,硬件將該寄存器字段中的值翻兩倍,并且當CLK_SELECT = CLK_216時,該值將由硬件八倍。
重置值:0x9 保留[15:13] RWX??? tWB [12:9] RW在硬件開始采樣R / B引腳之前,CE的高電平時鐘數。注意:當CLK_SELECT = CLK_108時,該寄存器字段中的值將被硬件加倍,當CLK_SELECT = CLK_216時,該值將被硬件加倍。
復位值:0xF tWHR [8:4] RW從WE高到RE低的時鐘片數。此參數僅用于狀態讀取和設備ID讀取操作。注意:當CLK_SELECT = CLK_108時,該寄存器字段中的值將被硬件加倍,當CLK_SELECT = CLK_216時,該值將被硬件加倍。
重置值:0x9 tREAD [3:0] RW RE低后采樣讀取數據之前等待的時鐘數。
為獲得最佳性能,應通過將nns閃存器件的RE存取時間(tREA)加上17ns,然后將總和除以CLK_SELECT所選的時鐘周期,然后將其四舍五入至下一較大整數來計算此參數。例如,如果器件tREA = 20ns并且CLK_SELECT = 1(216MHz => 4.63ns): tREAD =(20ns + 17ns)/4.63ns=7.99(四舍五入)=> 8。
tREAD的最大值是(tRP + tREH)。
重置值:0x6
操作時序 在編程操作中,要被編程的數據在WE#的上升沿被同步到數據寄存器中。 數據以類似的方式通過讀使能(RE#)信號從數據寄存器輸出,該信號負責輸出當前數據并遞增到下一個位置。WE#和RE#時鐘每次傳輸可以運行25ns。當RE#或芯片使能(CE#)未置為低電平時,輸出緩沖器為三態。CE#和RE#的這種組合激活了輸出緩沖器,使NAND Flash能夠與其他類型的存儲器(如NOR閃存,SRAM或DRAM)共享數據總線。這個功能有時被稱為“芯片使能不關心”。 在RE#為低時,讀使能,輸出緩沖器直接放置在io上,可跟著變化。 所有的NAND Flash操作都是通過發出一個命令周期來啟動的。這是通過將命令放在I / O [7:0]上,驅動CE#為低電平并且為高電平,然后發出WE#時鐘來完成的。命令,地址和數據在WE#的上升沿時鐘輸入NAND閃存器件, 大多數命令需要多個地址周期,然后是第二個命令周期。除RESET和READ STATUS命令外,當設備忙時不應發出新命令。 支持的命令:
2Gb NAND Flash器件的尋址方案如表6所示。第一個和第二個地址周期(或字節)指定了列地址,它指定了頁面內的起始字節。最后一列的位置是2112,因此最后一個位置的地址是第二個字節中的08h,第一個字節中是3Fh。PA [5:0]指定塊內的頁面地址,BA [16:6]指定塊地址。盡管大多數PROGRAM和READ操作需要完整的5字節地址,但對于在頁面內隨機訪問數據的操作,只需要第一個和第二個字節(或循環)。BLOCK ERASE操作只需要三個最重要的字節(第三,第四和第五)來選擇該塊。
當CA11 = 1時表示訪問oob數據,一般列地址都為0,表示從頁面內偏移0開始訪問整個頁面。
復位操作 RESET是NAND Flash器件繁忙時可以發出的兩個命令之一。如果設備正忙于處理先前的命令,則發出RESET命令會中止前一個操作。如果之前的操作是ERASE或PROGRAM命令,則發出RESET命令會過早地中止該命令,并且所需的操作不會完成。ERASE和PROGRAM可以是耗時的操作; 發出RESET命令可以中止或稍后重新發出命令。
CE先拉低選中芯片,在io [8:0]上放置FFh,然后CLE拉高,將io [8:0]與命令鎖存器相連,然后將WE拉低,接著拉高,在上升沿完成命令的寫操作,延時TWB后查詢R / B腳的狀態,當為1時表示RESET完成。
READ ID操作 READ ID(90h)命令需要一個虛擬地址周期(00h),但不需要第二個命令周期。在發出命令和虛擬地址后,通過保持CLE和ALE為低電平并讀取ID的每個字節的RE#信號,可以讀出ID數據。
CE先拉低選中chip,在io [8:0]上放置90h,然后CLE拉高,將io [8:0]與命令鎖存器相連,然后將WE拉低,接著拉高,在上升沿完成命令的寫操作,然后拉低CLE,拉高ALE,將io [8:0]與地址鎖存器相連,在io [8:0]上放置00h,然后將WE拉低,然后拉高WE ,在上升沿完成addrees的寫操作,接著拉低ALE,適當的延時后拉低RE,(CLE和ALE都為低時,IO [8:0]與數據鎖存器相連,CLE和ALE都為高時為非法),chip將數據放置在io [8:0]上,nand controler從io [8:0]上讀取數據,讀完后RE拉高,然后拉低讀取下一個字節。
READ STATUS操作 讀取狀態(70h)是NAND Flash器件忙時可以發出的第二個命令。該命令不需要地址或第二個命令周期。通過在READ STATUS命令之后發出RE#時鐘信號,可以監控NAND閃存器件的狀態。如果使用READ STATUS命令監視器件的就緒狀態,則該命令只能發出一次,并且可以通過重新發出RE#時鐘來重新讀取狀態。或者,RE#信號可以保持低電平,在繼續之前等待接收適當的狀態位。READ STATUS還會報告寫保護信號的狀態以及之前PROGRAM或ERASE操作的通過/失敗狀態。在PROGRAM或ERASE操作中必須達到合格狀態以確保數據完整性。
擦除操作 BLOCK ERASE(60h)操作會擦除整個64頁的頁面,總共128KB。要發出BLOCK ERASE操作,使用WE#信號在CLE置位時在ERASE(60h)命令中計時。接下來,在三個地址周期中的時鐘,保持每個字節地址的ALE有效。(這三個地址周期是最重要的地址周期,包括塊地址和頁地址,如第9頁的表6所示。)頁地址部分(第三個地址周期的六個低位)被忽略,并且只使用三個最高有效字節的塊地址部分。地址完全輸入后,發出D0h的第二個命令(命令周期2),當CLE置位時,它由WE#提供時鐘。這確認了ERASE操作,并且設備忙了大約500μs。當設備完成此操作時,它已準備好執行另一個命令。READ STATUS命令可以隨時發出,即使在ERASE操作過程中設備處于繁忙狀態。微處理器或控制器可以通過READ STATUS命令監視設備
提交70H命令查詢狀態后,RE一直為低,監控IO [5]引腳上的值,為0時表示擦除完成
程序操作 PROGRAM操作只能將位編程為0,并假定用戶以先前擦除的塊開始。如果用戶不想編程一個位(或一組位),則通過將該特定位/組設置為1,可以將位保持在擦除狀態。當接收到編程頁(80h)命令時,輸入寄存器被重置(內部)到全1。這支持只輸入要用0位編程的數據字節。PROGRAM操作從80h命令開始(CLE置位 - 見圖8)。接下來,取消斷言CLE并斷言ALE輸入完整的五個地址周期。輸入命令和地址后,數據輸入到寄存器。當所有的數據都被輸入時,發出10h命令來確認前一個命令并開始編程操作。PROGRAM操作通常需要220μs,雖然它可能需要多達600μs。用戶必須閱讀狀態并檢查操作是否成功。如果操作不成功,則該塊應該記錄為壞塊并且將來不會使用。所有的數據應該移到一個好的塊。
可以編程1-2112個字節,根據col add,如果頁內偏移為0,即編程整個頁,則2112個字節
READ操作 READ操作從00h命令開始,隨后是5個地址周期,然后是30h命令以確認命令序列。經過大約25μs的讀取傳輸時間(t R)后,數據被加載到寄存器并準備輸出。置位RE#使NAND Flash器件能夠輸出與地址中指定的列地址相對應的數據的第一個字節。隨后的RE#從連續的列位置轉換輸出數據。當RE#信號為高(未置位)時,I / O線為三態。讀取設備末尾(字節2112或字1056)會導致無效數據。
READ PAGE CACHE SEQUENTIAL操作 至此只討論了NAND??閃存器件中的一個寄存器。NAND Flash器件實際上有兩個寄存器,一個數據寄存器和一個高速緩存寄存器,如圖12所示。這兩個寄存器的屬性在各種NAND Flash緩存模式中起著重要的作用。PAGE READ CACHE MODE命令使用戶能夠在輸出先前訪問的數據的同時從數組中流水線化下一個順序訪問。這種雙緩沖技術可以隱藏讀取傳輸時間(t R)。數據最初從NAND閃存陣列傳輸到數據寄存器。如果高速緩存寄存器可用(不忙),數據將很快從數據寄存器移至高速緩存寄存器。數據傳輸到高速緩存寄存器后,數據寄存器可用,并且可以開始加載NAND閃存陣列中的下一個連續頁面。與8位I / O設備上的傳統PAGE READ命令相比,使用PAGE READ CACHE MODE命令可提高33%的性能,吞吐量可達31 MB / s。在16位I / O設備上,吞吐量可以提高到37 MB / s,與普通的PAGE READ操作相比,性能提高40%。 www.micron.com/products/nand/technotes上的技術說明提供了有關緩存模式的更多詳細信息以及如何使用它們來提高性能。PAGE READ CACHE MODE在系統啟動時特別有用,當大量數據通常從NAND閃存設備中讀取并且啟動時間非常關鍵時。
PROGRAM PAGE CACHE操作 PROGRAM PAGE CACHE MODE提供比正常PROGRAM PAGE操作更高的性能(見圖14和15)。PROGRAM PAGE CACHE MODE是一種雙緩沖技術,它使控制器能夠將數據直接輸入到高速緩存寄存器,并使用數據寄存器作為存儲區來提供用于編程陣列的數據。這將釋放高速緩存寄存器,以便可以并行加載下一個順序頁面操作。在許多應用中,編程時間(t PROG)可以完全隱藏。與PAGE READ CACHE MODE命令一樣,數據寄存器用于在整個編程周期內保持數據吞吐量。這將釋放緩存寄存器以接收來自控制器的下一頁數據。
存儲方法 圖10顯示了將數據和備用信息存儲在同一頁面的兩種常用方法。第一種方法顯示512字節的數據區加上與其直接相鄰的16字節備用區; 組合區域為528字節。一個2112字節的頁面可以包含這些528字節元素中的四個。第二個實施涉及單獨存儲數據和備用信息。四個512字節的數據區首先被存儲,并且它們對應的16字節備用區按順序依次位于頁面的末尾。
至于具體采用哪種存儲方式,由控制器決定,在NANDFLASH看來,數據和OOB并沒有什么區別.BRCM控制器采用的第二種方式。
部分頁面編程 與NAND接口一致,NAND中的基本編程單元是一個頁面; 然而,通過利用部分頁面編程,可以將頁面編程成更小的部分。為了便于部分頁面編程,每個頁面被進一步分成八個段(數據區域四個,備用區域四個)。 頁面中的每個段都充當獨立的可編程單元; 它們可以單獨編程或以任何組合段編程。每個片段允許的最大連續部分頁面程序數量為1。也就是說,頁面中的每個段可以被編程一次,并且在需要塊擦除之前頁面可以被編程多達八次。 部分頁面編程通過發出一個輸入命令(80h),然后是多段編程的隨機數據輸入命令(85h)序列完成。加載最后一個數據后,程序確認命令(10h)啟動編程操作并將數據寫入到所需位置的緩沖區中。寫狀態位(I / O0)可以通過命令(70h)進行驗證,以驗證編程是否成功。
部分頁面讀取 部分頁面讀取是通過發出一個讀取命令(00h),然后是一個隨機數據讀取命令(05h)序列來完成多段讀取。?
讀取內部數據移動操作 READ FOR INTERNAL DATA MOVE(00h-35h)命令也被稱為“復制”。它提供了將數據從一個頁面內部移動到另一個頁面的能力 - 數據永遠不會離開NAND Flash設備。READ FOR INTERNAL DATA MOVE操作將從NAND閃存陣列讀取的數據傳輸到高速緩存寄存器。數據可以被編程到設備的另一個頁面中。這在控制器在擦除塊之前需要將數據從塊中移出的情況下非常有用。在PROGRAM操作開始之前,也可以修改讀取的數據。如果用戶想在編程之前更改數據,這很有用。此功能可在NAND Flash設備內移動數據,而無需占用處理器或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:超時等待命令(%#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比較智能,我們只需要設置要進行的操作和地址,控制器會自動解釋發出芯片能夠理解的命令和地址。
Linux的內核中關于NANDFLASH的代碼: include / mtd / mtd-abi.h中定義的nand_ecclayout 結構指定OOB備用區域的布局:? struct nand_ecclayout { uint 32_t eccbytes; uint32_t eccpos [64]; uint32_t oobavail; struct nand_oobfree oobfree [MTD_MAX_OOBFREE_ENTRIES]; };
在此結構中,eccbytes 保存存儲ECC數據的OOB字節的數量,eccpos 是包含ECC數據的OOB區域的偏移量數組。oobfree 將可用于閃存文件系統的OOB區域中未使用的字節記錄為用于存儲標志的標志,例如清除標志,表示擦除操作成功完成。 各個NAND程序驅動根據芯片的屬性初始化它們的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; ????整個行業; ????int sas; ????int idx1,idx2;
????layout = kzalloc(sizeof(* layout),GFP_KERNEL); ????if(!layout){ ????????pr_err(“%s:無法分配內存\ 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 ++){ ????????????/ *每個頁面的第一個扇區可能有BBI * / ????????????if(i == 0){ ????????????????layout-> oobfree [idx2] .offset = i * sas + 1; ????????????????/ *小頁面NAND使用字節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;? ? ? //對于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;? ? ? // 根據ECC LEVEL得到需要的ECC byte數 ????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;? ? ? ? //對于BCH,ECC byte放在每個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; }
對于大頁nand flash,一個page含義多個sector,每個sector 512byte或者1024byte,一個block含有多個頁。
通常,NAND控制器通過對OOB區域中的ECC字段進行操作來在硬件中執行糾錯和檢測。但是,如果您的NAND控制器不支持錯誤管理,則需要通過軟件讓MTD為您完成。MTD?nand_ecc驅動程序(drivers / mtd / nand / nand_ecc.c)實現軟件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;
包含壞塊標記的OOB存儲器字節。這些標記用于標記有故障的閃存塊,并且通常出現在屬于每個塊的第一頁的OOB區域中。標記在OOB區域內的位置取決于芯片的屬性。壞塊標記可以在生產過程中在工廠設置,也可以在軟件中檢測到塊中的磨損。MTD在drivers / mtd / nand / nand_bbt.c中實現壞塊管理。 # # 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 所以絕大多數都是block的前兩個頁的OFS0用來標記壞塊,非0xFF則表示壞塊。
解析的過程可以參考boot代碼中的nand_get_page_status()函數
工具: 你必須使用nanddump和nandwrite等NAND感知工具而不是更常見的dd工具來創建或恢復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
總結
以上是生活随笔為你收集整理的nandflash驱动详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SAP ABAP开发视频学习(视频教程)
- 下一篇: Ubuntu常用软件安装