Author: wmb Date: 2007-04-29 21:32:48 +0200 (Sun, 29 Apr 2007) New Revision: 336
Modified: dev/olpc/cafenand/badblock.fth dev/olpc/cafenand/cafenand.fth dev/olpc/cafenand/configure.fth dev/olpc/cafenand/methods.fth dev/olpc/cafenand/test.fth Log: OLPC CaFe NAND driver - added support for two-NAND-chip packages. trac #1374
Modified: dev/olpc/cafenand/badblock.fth =================================================================== --- dev/olpc/cafenand/badblock.fth 2007-04-27 22:25:44 UTC (rev 335) +++ dev/olpc/cafenand/badblock.fth 2007-04-29 19:32:48 UTC (rev 336) @@ -8,7 +8,7 @@ : round-up ( n boundary -- n' ) over 1- + over / * ;
: /bbt ( -- bytes ) \ Bytes per bad block table - pages/chip pages/eblock / 3 + 4 / ( bytes ) + total-pages pages/eblock / 3 + 4 / ( bytes ) /page round-up ;
@@ -70,8 +70,8 @@ \ Page range to search for a bad block table : bbtbounds ( low-page high-page -- ) 0 to bbt0 0 to bbt1 - pages/chip #bbtsearch pages/eblock * - - pages/chip pages/eblock - + total-pages #bbtsearch pages/eblock * - + total-pages pages/eblock - ;
\ Look for existing bad block tables, setting bbt0 and bbt1 if found @@ -118,7 +118,7 @@
\ Scan the device and record the factory bad-block info in a table : initial-badblock-scan ( -- ) - pages/chip 0 do + total-pages 0 do i initial-block-bad? if i .bad else @@ -214,7 +214,7 @@ exit then bbt1 if bbt1 exit then - pages/chip + total-pages ;
: map-resblock ( page# #pages -- page#' #pages ) @@ -275,7 +275,7 @@ \ This is fairly severe, not recommended except in exceptional situations : scrub ( -- ) release-bbt - pages/chip 0 ?do + total-pages 0 ?do (cr i . i erase-block pages/eblock +loop @@ -301,7 +301,7 @@ ; : show-bbt ( -- ) get-bbt - pages/chip 0 ?do + total-pages 0 ?do i block-reserved? if ." Reserved " i .page-byte cr else i block-bad? if ." Bad block" i .page-byte cr then then
Modified: dev/olpc/cafenand/cafenand.fth =================================================================== --- dev/olpc/cafenand/cafenand.fth 2007-04-27 22:25:44 UTC (rev 335) +++ dev/olpc/cafenand/cafenand.fth 2007-04-29 19:32:48 UTC (rev 336) @@ -15,7 +15,6 @@
" reg" property
- : my-w@ ( offset -- w ) my-space + " config-w@" $call-parent ; : my-w! ( w offset -- ) my-space + " config-w!" $call-parent ;
@@ -64,12 +63,29 @@ \ Wait not busy - XXX need timeout : ctrl-wait ( -- ) begin h# c cl@ h# 8000.0000 and 0= until ;
-\ Think of col as the offset within a disk block, and row as the block# -: set-address ( row col -- ) h# 1c cl! h# 20 cl! ; +\ Bit 19 in the command (0) register is reserved according to the +\ version of the CaFe chip spec that we have, but Jerry Zheng says +\ that it chooses the chip select - 0 for CS0, 1 for CS1.
+1 instance value chip-boundary \ Boundary between chip 0 and chip 1 +0 instance value cs-mask \ Chip-select bit for command 0 register +: chip0 ( -- ) 0 to cs-mask ; +: chip1 ( -- ) h# 80000 to cs-mask ; + +: set-chip ( page# -- page#' ) + dup chip-boundary >= if chip-boundary - chip1 else chip0 then +; + +\ For erase-block, the address that is sent to the chip is formatted +\ differently than for reads and writes. +: set-erase-page ( page# -- ) set-chip lwsplit h# 20 cl! h# 1c cl! ; + +: set-page ( page# offset -- ) h# 1c cl! set-chip h# 20 cl! ; + : >cmd ( cmd# #nonmem #address-bytes -- cmdval ) dup if 1- d# 27 lshift h# 4000.0000 or then ( cmd# #nm adr-field ) - swap 7 and d# 22 lshift or ( cmd# nm,adr ) + over 1 and d# 20 lshift or \ #nm[0] ( cmd# #nm adr+nm0 ) + swap e and d# 21 lshift or \ #nm[3:1] ( cmd# adr+nm ) or h# 8000.0000 or ;
@@ -80,29 +96,26 @@ h# 0420.0000 0 5 >cmd constant read-cmd h# 0220.0080 0 5 >cmd constant write-cmd
-: wait-dma-done ( -- ) - begin - h# 10 cl@ h# 1000.0000 and - until - h# 1000.0000 h# 10 cl! \ Clear DMA done +: wait-mask ( bitmask -- ) + begin dup h# 10 cl@ and until ( bitmask ) + h# 10 cl! \ Clear status bit ; +: wait-dma ( -- ) h# 1000.0000 wait-mask ; +: wait-cmd ( -- ) h# 8000.0000 wait-mask ;
-: wait-done ( -- ) - begin - h# 10 cl@ h# 8000.0000 and - until - h# 8000.0000 h# 10 cl! \ Clear done -; - \ Control3 - no reset, no BAR write protect : write-disable ( -- ) 0 8 cl! ; : write-enable ( -- ) h# 4000.0000 8 cl! ;
-: cmd ( n -- ) 0 cl! wait-done ; -: cmd2 ( n -- ) 4 cl! ; +: cmd ( cmd cmd2 -- ) + /page d# 10 rshift 3 and d# 28 lshift or 4 cl! ( cmd ) + cs-mask or 0 cl! ( ) +; + : datalen ( n -- ) h# 18 cl! ; -: read-status ( -- b ) read-status-cmd cmd h# 30 cl@ h# ff and ; -\ : read-id ( -- ) 0 0 set-address read-id-cmd cmd h# 30 cl@ ; + +: read-status ( -- b ) read-status-cmd 0 cmd wait-cmd h# 30 cl@ h# ff and ; +\ : read-id ( -- ) 0 0 set-page read-id-cmd 0 cmd wait-cmd h# 30 cl@ ; : dma-off ( -- ) 0 h# 40 cl! ;
: wait-write-done ( -- ) @@ -118,10 +131,10 @@
\ Assumes that the range doesn't straddle a page boundary : generic-read ( len page# offset cmd cmd2 -- chip-adr ) - cmd2 >r ( len page# offset r: cmd ) - set-address dma-off ( len r: cmd ) - datalen ( r: cmd ) - r> cmd ( ) + >r >r ( len page# offset r: cmd cmd2 ) + set-page dma-off ( len r: cmd cmd2 ) + datalen ( r: cmd cmd2 ) + r> r> cmd wait-cmd ( ) chip h# 1000 + ( adr ) ; : pio-read ( adr len page# offset -- ) @@ -132,19 +145,19 @@
: pio-write-raw ( adr len page# offset -- ) write-enable - dma-off set-address dup datalen ( adr len ) - chip h# 2000 + swap move ( ) - h# 2000.0110 cmd2 write-cmd cmd ( ) \ 2000. 2K page, (No Auto ECC) + dma-off set-page dup datalen ( adr len ) + chip h# 2000 + swap move ( ) + write-cmd h# 0000.0110 cmd wait-cmd ( ) No Auto ECC wait-write-done write-disable ;
: pio-write-page ( adr page# -- ) - write-enable dma-off ( adr page# ) - 0 set-address ( adr ) - /page h# e + dup datalen ( adr len ) - chip h# 2000 + swap move ( ) - h# 6800.0110 cmd2 write-cmd cmd ( ) \ 4000. Auto ECC, 2000. 2K page, 0800 R/S ECC + write-enable dma-off ( adr page# ) + 0 set-page ( adr ) + /page h# e + dup datalen ( adr len ) + chip h# 2000 + swap move ( ) + write-cmd h# 4800.0110 cmd wait-cmd ( ) \ 4000. Auto ECC, 0800. R/S ECC wait-write-done write-disable ; @@ -153,7 +166,7 @@ /oob swap h# 800 read-cmd h# 130 generic-read ;
-: read-rst ( -- ) h# 8000.0000 h# c cl! ; +: read-rst ( -- ) h# 8000.0000 h# c cl! ;
0 instance value dma-vadr 0 instance value dma-padr @@ -176,13 +189,10 @@ ;
: slow-dma-read ( adr len page# offset -- ) - set-address - dup true dma-setup ( ) - h# 130 cmd2 read-cmd 0 cl! ( adr chip-adr r: len ) - \ XXX put a 90 us delay here so we don't start hitting the register - \ until almost done. - wait-dma-done \ For DMA reads we wait for DMA completion instead of cmd - dma-release ( ) + set-page + dup true dma-setup ( ) + read-cmd h# 0800.0130 cmd wait-dma ( adr chip-adr r: len ) + dma-release ( ) ;
: /dma-buf ( -- n ) /page /oob + ; @@ -192,34 +202,33 @@
\ XXX should check ECC : read-page ( adr page# -- ) - h# 20 cl! 0 h# 1c cl! + 0 set-page ( adr ) /page ( /oob + ) h# 18 cl! ( adr ) dma-buf-pa h# 44 cl! ( adr ) 0 h# 48 cl! ( adr ) /page h# a000.0000 or h# 40 cl! ( adr ) - h# 130 4 cl! read-cmd 0 cl! ( adr ) - wait-dma-done \ For DMA reads we wait for DMA completion instead of cmd + read-cmd h# 0800.0130 cmd wait-dma ( adr ) dma-buf-va swap /page do-lmove ( ) ;
: dma-write-raw ( adr len page# offset -- ) - write-enable ( adr len page# offset ) - set-address ( adr len ) - dup false dma-setup ( ) - h# 2000.0110 cmd2 write-cmd cmd ( ) - wait-write-done - dma-release - write-disable + write-enable ( adr len page# offset ) + set-page ( adr len ) + dup false dma-setup ( ) + write-cmd h# 110 cmd wait-cmd ( ) + wait-write-done ( ) + dma-release ( ) + write-disable ( ) ;
: dma-write-page ( adr page# -- ) \ Size is fixed write-enable ( adr page# ) - 0 set-address ( adr ) + 0 set-page ( adr ) h# 800 h# 80e false dma-setup ( ) - h# 6800.0110 cmd2 write-cmd cmd ( ) \ Auto-ECC, 2KB, RS, write cmd - wait-write-done + write-cmd h# 4800.0110 cmd wait-cmd ( ) \ Auto-ECC, RS, write cmd + wait-write-done ( ) \ dma-release - write-disable + write-disable ( ) ;
\ : read-page ( adr page# -- ) dma-read-page ; @@ -229,9 +238,8 @@ 3 value #erase-adr-bytes \ Chip dependent : erase-block ( page# -- ) write-enable - lwsplit swap set-address \ Fiddle the block number - h# 1d0 cmd2 - h# 20.0060 0 #erase-adr-bytes >cmd cmd + set-erase-page + h# 20.0060 0 #erase-adr-bytes >cmd h# 1d0 cmd wait-write-done write-disable ; @@ -240,12 +248,10 @@
: send-reset-cmd ( -- ) ctrl-wait - h# 8000.00ff cmd \ NAND Reset command + h# 8000.00ff 0 cmd wait-cmd \ NAND Reset command ;
: init ( -- ) - 0 0 cl! \ Clear command register - h# 2000.0000 4 cl! \ Page 2KB write-disable
send-reset-cmd
Modified: dev/olpc/cafenand/configure.fth =================================================================== --- dev/olpc/cafenand/configure.fth 2007-04-27 22:25:44 UTC (rev 335) +++ dev/olpc/cafenand/configure.fth 2007-04-29 19:32:48 UTC (rev 336) @@ -1,8 +1,9 @@ \ See license at end of file purpose: Common code for NAND FLASH access
-h# 4.0000 instance value pages/chip -h# 40 instance value pages/eblock +h# 0 instance value total-pages \ Start with 0 and add chips +h# 0 instance value pages/chip +h# 40 instance value pages/eblock
\ This uses byte 4 to work out the plane parameters \ The Samsung part has this byte, but the Hynix part doesn't @@ -10,7 +11,7 @@ dup 4 + c@ ( adr plane-data ) h# 1000 over 4 rshift 7 and lshift ( adr plane-data pages/plane ) 1 rot 2 rshift 3 and lshift ( adr kbytes/plane #planes ) - * to pages/chip ( adr ) + * to pages/chip ( adr ) ;
\ This uses byte 3 to work out the page and erase block sizes @@ -55,6 +56,7 @@ : configure ( -- okay? ) read-id ( adr ) ['] configure-auto catch 0= nip + pages/chip total-pages + to total-pages ;
\ LICENSE_BEGIN
Modified: dev/olpc/cafenand/methods.fth =================================================================== --- dev/olpc/cafenand/methods.fth 2007-04-27 22:25:44 UTC (rev 335) +++ dev/olpc/cafenand/methods.fth 2007-04-29 19:32:48 UTC (rev 336) @@ -6,6 +6,24 @@ comp 0= ;
+: configure-all ( -- error? ) + 0 to total-pages + + \ Set boundary to 0 to look for chip on CE1# + \ If one is found, the number of pages will be added to total-pages + 0 to chip-boundary configure drop + + \ Set boundary to 1 to look for chip on CE0# (configure uses page# 0) + 1 to chip-boundary configure if + pages/chip \ Chip present at CE0#, set boundary above it + else + 0 \ No chip at CE0, set boundary at 0 to use CE1# chip + then + to chip-boundary + + total-pages 0= \ Error if there are no chips +; + external
: dma-alloc ( len -- adr ) " dma-alloc" $call-parent ; @@ -27,7 +45,7 @@ resmap if #reserved-eblocks /eblock else - pages/chip /page + total-pages /page then um* ; @@ -35,7 +53,7 @@ : open ( -- okay? ) map-regs init - configure 0= if false exit then + configure-all if false exit then
/dma-buf dma-alloc to dma-buf-va dma-buf-va /dma-buf false " dma-map-in" $call-parent to dma-buf-pa
Modified: dev/olpc/cafenand/test.fth =================================================================== --- dev/olpc/cafenand/test.fth 2007-04-27 22:25:44 UTC (rev 335) +++ dev/olpc/cafenand/test.fth 2007-04-29 19:32:48 UTC (rev 336) @@ -59,7 +59,7 @@ ;
: test-all ( -- ) - pages/chip 0 do + total-pages 0 do (cr i . i test-eb key? ?leave @@ -68,7 +68,7 @@
\ XXX skip mfg bad blocks : erase-all ( -- ) - pages/chip 0 do + total-pages 0 do (cr i . i erase-block key? ?leave @@ -84,7 +84,7 @@
: scan-all cr - pages/chip 0 do + total-pages 0 do i ?. ib /full-page i 0 pio-read mismatch? if i . .where then @@ -104,7 +104,7 @@ ; : .bad ( page# -- ) .x ." bad" cr ; : initial-badblock-scan ( -- ) - pages/chip 0 do + total-pages 0 do i block-bad? if i .bad else @@ -147,11 +147,12 @@ [then]
: scan-bad ( -- ) - pages/chip 0 do + total-pages 0 do bbbuf 4 i h# 800 pio-read i .bad bbbuf 4 i 1+ h# 800 pio-read i 1+ .bad pages/eblock +loop ; + \ LICENSE_BEGIN \ Copyright (c) 2006 FirmWorks \