Author: wmb Date: 2008-09-13 00:37:48 +0200 (Sat, 13 Sep 2008) New Revision: 936
Added: dev/olpc/cafenand/lbanand.fth Modified: cpu/x86/pc/olpc/copynand.fth dev/olpc/cafenand/badblock.fth dev/olpc/cafenand/cafenand.bth dev/olpc/cafenand/cafenand.fth dev/olpc/cafenand/methods.fth dev/olpc/cafenand/selftest.fth ofw/fs/fatfs/device.fth ofw/fs/fatfs/fdisk2.fth ofw/fs/fatfs/makefs.fth ofw/fs/jffs2/jffs2.fth Log: OLPC - support LBA-NAND Flash devices.
Modified: cpu/x86/pc/olpc/copynand.fth =================================================================== --- cpu/x86/pc/olpc/copynand.fth 2008-09-12 22:34:01 UTC (rev 935) +++ cpu/x86/pc/olpc/copynand.fth 2008-09-12 22:37:48 UTC (rev 936) @@ -55,7 +55,7 @@ " /nandflash" open-dev to nandih nandih 0= " Can't open NAND FLASH device" ?nand-abort " erase-size" $call-nand to /nand-block - " block-size" $call-nand to /nand-page + " page-size" $call-nand to /nand-page " size" $call-nand /nand-page um/mod nip to #nand-pages /nand-block /nand-page / to nand-pages/block " start-scan" $call-nand @@ -220,6 +220,269 @@ defer show-done ' cr to show-done
+: written? ( adr len -- flag ) h# ffffffff lskip 0<> ; + + +d# 24 d# 24 2value ulhc + +d# 22 constant status-line + +8 constant glyph-w +8 constant glyph-h + +9 constant grid-w +9 constant grid-h + +d# 128 value #cols +: xy+ ( x1 y1 x2 y2 -- x3 y3 ) rot + -rot + swap ; +: xy* ( x y w h -- x*w y*h ) rot * >r * r> ; + +0 value nand-block-limit + +: do-fill ( color x y w h -- ) " fill-rectangle" $call-screen ; + +\ States: 0:erased 1:bad 2:waiting for write 3:written + +: >loc ( eblock# -- x y ) #cols /mod grid-w grid-h xy* ulhc xy+ ; + +: show-state ( eblock# state -- ) swap >loc glyph-w glyph-h do-fill ; + +dev screen : erase-screen erase-screen ; dend + +h# 80 h# 80 h# 80 rgb>565 constant bbt-color \ gray + 0 0 0 rgb>565 constant erased-color \ black +h# ff 0 0 rgb>565 constant bad-color \ red + 0 0 h# ff rgb>565 constant clean-color \ blue +h# ff h# ff 0 rgb>565 constant pending-color \ yellow + 0 h# ff 0 rgb>565 constant written-color \ green + 0 h# ff h# ff rgb>565 constant strange-color \ cyan +h# ff h# ff h# ff rgb>565 constant starting-color \ white + +: gshow-init ( #eblocks -- ) + #nand-pages nand-pages/block / to nand-block-limit + + cursor-off " erase-screen" $call-screen + + " bbt0" $call-nand nand-pages/block / bbt-color show-state + " bbt1" $call-nand nand-pages/block / bbt-color show-state + + starting-color ( #eblocks color ) + swap 0 ?do i over show-state loop + drop + 0 status-line at-xy +; + +: gshow-erasing ( #eblocks -- ) drop ." Erasing " ; + +: gshow-erased ( eblock# -- ) erased-color show-state ; +: gshow-bad ( eblock# -- ) bad-color show-state ; +: gshow-bbt-block ( eblock# -- ) bbt-color show-state ; +: gshow-clean ( eblock# -- ) clean-color show-state ; +: gshow-strange ( eblock# -- ) strange-color show-state ; + +: gshow-cleaning ( -- ) d# 26 status-line at-xy ." Cleanmarkers" cr ; +: gshow-done ( -- ) cursor-on ; + +: gshow-pending ( eblock# -- ) pending-color show-state ; + +: gshow-writing ( #eblocks -- ) + ." Writing " + 0 swap 0 ?do ( eblock# ) + dup nand-pages/block * " block-bad?" $call-nand 0= if ( eblock# ) + dup show-pending ( eblock# ) + 1 ( eblock# increment ) + else ( eblock# ) + 0 ( eblock# increment ) + then ( eblock# increment ) + swap 1+ swap ( eblock#' increment ) + +loop ( eblock#' ) + drop +; + +: show-eblock# ( eblock# -- ) d# 20 status-line at-xy .x ; +: gshow-written ( eblock# -- ) + dup written-color show-state + show-eblock# +; + +: gshow + ['] gshow-init to show-init + ['] gshow-erasing to show-erasing + ['] gshow-erased to show-erased + ['] gshow-bad to show-bad + ['] gshow-bbt-block to show-bbt-block + ['] gshow-clean to show-clean + ['] gshow-cleaning to show-cleaning + ['] gshow-pending to show-pending + ['] gshow-writing to show-writing + ['] gshow-written to show-written + ['] gshow-strange to show-strange + ['] gshow-done to show-done +; + +gshow + +\ 0 - marked bad block : show-bad +\ 1 - unreadable block : show-bad +\ 2 - jffs2 w/ summary: show-written +\ 3 - jffs2 w/o summary: show-pending +\ 4 - clean : show-clean +\ 5 - non-jffs2 data : show-strange +\ 6 - erased : show-erased +\ 7 - primary bad-block-table : show-bbt-block +\ 8 - secondary bad-block-table : show-bbt-block +: show-status ( status eblock# -- ) + swap case + 0 of show-bad endof + 1 of show-bad endof + 2 of show-written endof + 3 of show-pending endof + 4 of show-clean endof + 5 of show-strange endof + 6 of show-erased endof + 7 of show-bbt-block endof + 8 of show-bbt-block endof + endcase +; + +0 value nand-map +0 value working-page +: classify-block ( page# -- status ) + to working-page + + \ Check for block marked bad in bad-block table + working-page " block-bad?" $call-nand if 0 exit then + + \ Try to read the first few bytes + load-base 4 working-page 0 " pio-read" $call-nand + + \ Check for a JFFS2 node at the beginning + load-base w@ h# 1985 = if + \ Look for a summary node + load-base 4 working-page h# 3f + h# 7fc " pio-read" $call-nand + load-base " "(85 18 85 02)" comp if 3 else 2 then + exit + then + + \ Check for non-erased, non-JFFS2 data + load-base l@ h# ffff.ffff <> if 5 exit then + + \ Check for various signatures in the OOB area + working-page " read-oob" $call-nand d# 14 + ( adr ) + + \ .. Cleanmarker + dup " "(85 19 03 20 08 00 00 00)" comp 0= if drop 4 exit then + + \ .. Bad block tables +\ These can't happen because the BBT table blocks are marked "bad" +\ so they get filtered out at the top of this routine. +\ dup " Bbt0" comp 0= if drop 7 exit then +\ dup " 1tbB" comp 0= if drop 8 exit then + drop + + \ See if the whole thing is really completely erased + load-base working-page nand-pages/block ( adr block# #blocks ) + " read-blocks" $call-nand nand-pages/block <> if 1 exit then + + \ Not completely erased + load-base /nand-block written? if 5 exit then + + \ Erased + 6 +; + +0 value current-block +0 value examine-done? + +string-array status-descriptions + ," Marked bad in Bad Block Table" \ 0 + ," Read error" \ 1 + ," JFFS2 data with summary" \ 2 + ," JFFS2 data, no summary" \ 3 + ," Clean (erased with JFFS2 cleanmarker)" \ 4 + ," Dirty, with non-JFFS2 data" \ 5 + ," Erased, no cleanmarker" \ 6 + ," Primary Bad Block Table" \ 7 + ," Secondary Bad Block Table" \ 8 +end-string-array + +: show-block-status ( block# -- ) + dup show-eblock# + nand-map + c@ status-descriptions count type kill-line +; + +: cell-border ( block# color -- ) + swap >loc ( color x y ) + -1 -1 xy+ + 3dup grid-w 1 do-fill ( color x y ) + 3dup grid-w 0 xy+ 1 grid-h do-fill ( color x y ) + 3dup 0 1 xy+ 1 grid-h do-fill ( color x y ) + 1 grid-h xy+ grid-w 1 do-fill +; +: lowlight ( block# -- ) background-rgb rgb>565 cell-border ; +: highlight ( block# -- ) 0 cell-border ; +: point-block ( block# -- ) + current-block lowlight + to current-block + current-block highlight +; +: +block ( offset -- ) + current-block + nand-block-limit mod ( new-block ) + point-block + current-block show-block-status +; + +: process-key ( char -- ) + case + h# 9b of endof + [char] A of #cols negate +block endof \ up + [char] B of #cols +block endof \ down + [char] C of 1 +block endof \ right + [char] D of -1 +block endof \ left + [char] ? of #cols 8 * negate +block endof \ page up + [char] / of #cols 8 * +block endof \ page down + [char] K of 8 +block endof \ page right + [char] H of -8 +block endof \ page left + h# 1b of d# 20 ms key? 0= if true to examine-done? then endof + endcase +; + +: examine-nand ( -- ) + 0 status-line 1- at-xy red-letters ." Arrows, fn Arrows to move, Esc to exit" black-letters cr + 0 to current-block + current-block highlight + false to examine-done? + begin key process-key examine-done? until + current-block lowlight +; + +: (scan-nand) ( -- ) + nand-map 0= if + #nand-pages nand-pages/block / alloc-mem to nand-map + then + + " usable-page-limit" $call-nand + dup nand-pages/block / show-init ( page-limit ) + + 7 " bbt0" $call-nand nand-pages/block / nand-map + c! + 8 " bbt1" $call-nand nand-pages/block / nand-map + c! + + 0 ?do + i classify-block ( status ) + i nand-pages/block / ( status eblock# ) + 2dup nand-map + c! ( status eblock# ) + show-status + nand-pages/block +loop ( ) + + show-done +; + +: scan-nand ( -- ) + open-nand (scan-nand) close-nand-ihs + examine-nand +; + + : >eblock# ( page# -- eblock# ) nand-pages/block / ;
: copy-nand ( "devspec" -- ) @@ -326,13 +589,6 @@ close-nand-ihs ;
- -: written? ( adr len -- flag ) - false -rot bounds ?do ( flag ) - i @ -1 <> if 0= leave then ( flag ) - /n +loop ( flag ) -; - true value dump-oob? : make-new-file ( devspec$ -- fileih ) 2dup ['] $delete catch if 2drop then ( name$ ) @@ -388,42 +644,70 @@ fileih 0= " Can't open output" ?nand-abort ;
-: (dump-nand) ( "devspec" -- ) - open-nand - get-img-filename +: dump-eblock? ( block# -- flag ) + \ Dump JFFS2 w/summary (2), JFFS2 w/o summary (3), non JFFS2 data (5) + nand-map + c@ dup 2 = over 3 = or swap 5 = or +;
- dump-oob? 0= if alloc-crc-buf then - image-name$ open-dump-file +: eblock>file ( -- ) + load-base /nand-block " write" fileih $call-method + /nand-block <> " Write to dump file failed" ?nand-abort + load-base /nand-block $crc #image-eblocks >crc l! + #image-eblocks 1+ to #image-eblocks +;
- 0 to #image-eblocks +: fastdump-nand ( -- ) + \ The stack is empty at the end of each line unless otherwise noted + (scan-nand)
+ cursor-off + d# 20 status-line at-xy ." " + + " usable-page-limit" $call-nand >eblock# 0 do + i dump-eblock? if + i point-block + i show-eblock# + load-base i nand-pages/block * nand-pages/block " read-pages" $call-nand ( #read ) + nand-pages/block <> " Read failed" ?nand-abort + eblock>file + then + loop + show-done +; + +: slowdump-nand ( -- ) \ The stack is empty at the end of each line unless otherwise noted - dump-oob? if #nand-pages else " usable-page-limit" $call-nand then - 0 do + #nand-pages 0 do (cr i >eblock# . - load-base i nand-pages/block " read-blocks" $call-nand + load-base i nand-pages/block " read-pages" $call-nand ( #read ) nand-pages/block = if load-base /nand-block written? if ." w" - load-base /nand-block " write" fileih $call-method - /nand-block <> " Write to dump file failed" ?nand-abort - dump-oob? if - i nand-pages/block bounds ?do - i " read-oob" $call-nand h# 40 ( adr len ) - " write" fileih $call-method drop - h# 40 <> " Write of OOB data failed" ?nand-abort - i pad ! pad 4 " write" fileih $call-method - 4 <> " Write of eblock number failed" ?nand-abort - loop - else - load-base /nand-block $crc #image-eblocks >crc l! - then - #image-eblocks 1+ to #image-eblocks + eblock>file + i nand-pages/block bounds ?do + i " read-oob" $call-nand h# 40 ( adr len ) + " write" fileih $call-method + h# 40 <> " Write of OOB data failed" ?nand-abort + i pad ! pad 4 " write" fileih $call-method + 4 <> " Write of eblock number failed" ?nand-abort + loop else ." s" then then nand-pages/block +loop +; + +: (dump-nand) ( "devspec" -- ) + open-nand + get-img-filename + + alloc-crc-buf + image-name$ open-dump-file + + 0 to #image-eblocks + + dump-oob? if slowdump-nand else fastdump-nand then cr ." Done" cr
close-image-file
Modified: dev/olpc/cafenand/badblock.fth =================================================================== --- dev/olpc/cafenand/badblock.fth 2008-09-12 22:34:01 UTC (rev 935) +++ dev/olpc/cafenand/badblock.fth 2008-09-12 22:37:48 UTC (rev 936) @@ -247,7 +247,7 @@
external \ Assumes that the page range doesn't cross an erase block boundary -: read-blocks ( adr page# #pages -- #read ) +: read-pages ( adr page# #pages -- #read ) over block-bad? if 3drop 0 exit then
rot >r 2dup r> -rot ( page# #pages adr page# #pages ) @@ -261,7 +261,7 @@ drop nip ;
-: write-blocks ( adr page# #pages -- #written ) +: write-pages ( adr page# #pages -- #written ) over block-bad? if 3drop 0 exit then
over >r dup >r ( adr page# #pages r: page# #pages ) @@ -279,12 +279,9 @@ tuck bounds ?do i erase-block pages/eblock +loop ;
-: block-size ( -- n ) /page ; +: page-size ( -- n ) /page ; +: erase-size ( -- n ) /eblock ;
-: erase-size ( -- n ) /eblock ; - -: max-transfer ( -- n ) /eblock ; - : dma-alloc ( len -- adr ) " dma-alloc" $call-parent ;
: dma-free ( adr len -- ) " dma-free" $call-parent ;
Modified: dev/olpc/cafenand/cafenand.bth =================================================================== --- dev/olpc/cafenand/cafenand.bth 2008-09-12 22:34:01 UTC (rev 935) +++ dev/olpc/cafenand/cafenand.bth 2008-09-12 22:37:48 UTC (rev 936) @@ -14,6 +14,8 @@ fload ${BP}/dev/olpc/cafenand/configure.fth fload ${BP}/dev/olpc/cafenand/badblock.fth fload ${BP}/dev/olpc/cafenand/redboot.fth +\ : lba-nand? 0 ; : lba-close ; +fload ${BP}/dev/olpc/cafenand/lbanand.fth fload ${BP}/dev/olpc/cafenand/methods.fth fload ${BP}/dev/olpc/cafenand/selftest.fth
Modified: dev/olpc/cafenand/cafenand.fth =================================================================== --- dev/olpc/cafenand/cafenand.fth 2008-09-12 22:34:01 UTC (rev 935) +++ dev/olpc/cafenand/cafenand.fth 2008-09-12 22:37:48 UTC (rev 936) @@ -61,8 +61,15 @@
: clr-ints ( -- ) h# ffff.ffff h# 10 cl! ;
-\ Wait not busy - XXX need timeout -: ctrl-wait ( -- ) begin h# c cl@ h# 8000.0000 and 0= until ; +: wait-ready ( -- ) + get-msecs d# 1000 + begin ( target-time ) + h# c cl@ h# 4000.0000 and if ( target-time ) + drop exit + then ( target-time ) + dup get-msecs - 0< ( target-time reached? ) + until ( target-time ) + drop +;
\ 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 @@ -211,6 +218,15 @@ 0 instance value dma-buf-pa 0 instance value dma-buf-va defer do-lmove + +: alloc-dma-buf ( -- ) + /dma-buf " dma-alloc" $call-parent to dma-buf-va + dma-buf-va /dma-buf false " dma-map-in" $call-parent to dma-buf-pa +; +: set-lmove ( -- ) + " lmove" $find 0= if ['] move then to do-lmove +; + h# 10 buffer: syndrome-buf : syndrome ( -- adr ) 8 0 do h# 50 i wa+ cw@ i syndrome-buf array! loop @@ -291,10 +307,10 @@
: erase-block ( page# -- ) (erase-block) drop ;
-: read-id ( -- adr ) 8 0 0 h# c420.0090 0 generic-read ; +: read-id ( -- adr ) 8 0 0 h# c400.0090 0 generic-read ;
: send-reset-cmd ( -- ) - ctrl-wait + wait-ready h# 8000.00ff 0 cmd wait-cmd \ NAND Reset command ;
Added: dev/olpc/cafenand/lbanand.fth =================================================================== --- dev/olpc/cafenand/lbanand.fth (rev 0) +++ dev/olpc/cafenand/lbanand.fth 2008-09-12 22:37:48 UTC (rev 936) @@ -0,0 +1,356 @@ +\ dev /nandflash + +: sectors>bytes ( #sectors #bytes -- ) 9 lshift ; + +: lba-get-sectors ( sector# #sectors -- true | adr false ) + tuck set-page ( #sectors ) + sectors>bytes dup h# 18 cl! ( #bytes ) + dma-buf-pa h# 44 cl! ( #bytes ) + 0 h# 48 cl! ( #bytes ) + h# a000.0000 or h# 40 cl! ( ) + read-cmd h# 0000.0130 cmd wait-dma ( ) + + dma-buf-va false +; + +: lba-write-sectors ( adr sector# #sectors -- error? ) \ Size is fixed + write-enable ( adr sector# #sectors) + tuck set-page ( adr #sectors ) + sectors>bytes ( adr #bytes ) + dup false dma-setup ( ) + h# e220.0080 h# 0000.0110 cmd wait-cmd ( ) \ No ECC, write cmd + wait-write-done ( error? ) +\ dma-release +; + +: read57 ( len page# offset -- adr ) read-cmd h# 157 generic-read ; +: dummy57 ( page# offset -- ) set-page dma-off h# e020.0000 h# 157 cmd wait-cmd ; +: dummy-read ( page# offset -- ) set-page dma-off h# e000.0000 h# 120 cmd wait-cmd ; +: pnr>bcm ( -- ) h# fc00 0 dummy-read ; +h# ffff value vfp-password +: set-vfp-password ( new-password -- ) + dup >r ( r: new-password ) + wbsplit vfp-password wbsplit ( npw0 npw1 opw0 opw1 r: new-pw ) + swap >r ( npw0 npw1 opw1 r: new-pw opw0 ) + -rot 0 bljoin h# 21 r> bwjoin ( page offset r: new-pw ) + dummy57 ( r: new-pw + r> to vfp-password +; +: mdp>vfp ( -- ) + vfp-password wbsplit ( pw0 pw1 ) + h# be rot bwjoin ( page=pw1 offset=pw0|be ) + dummy57 +; +: read-lba-id ( -- adr ) 5 0 0 h# c400.0092 0 generic-read ; +: bcm>pnr ( -- ) ( XXX This is a variant of the write command) ; +: 5c@ ( adr -- d ) + >r r@ c@ r@ 1+ c@ r@ 2+ c@ r@ 3 + c@ bljoin r> c@ +; +: le-w@ ( adr -- w ) dup c@ swap 1+ c@ bwjoin ; +: mdp-size ( -- #sectors ) 5 0 h# b0 read57 5c@ ; +: vfp-size ( -- #sectors ) 2 0 h# b5 read57 le-w@ ; +: ex-vfp-sizev ( -- param type ) 2 0 h# 10b8 read57 dup 1+ c@ swap c@ ; +: ex-vfp-size ( -- param type ) 2 0 h# b7 read57 dup 1+ c@ swap c@ ; +: set-vfp-size ( size -- ) + wbsplit swap abort" Bad alignment for VFP size" ( size.hi ) + ?dup if ( size.hi ) + dup invert ( size.hi ~size.hi ) + h# ff swap 0 ( size.hi ~size.lo ~size.hi 0 ) + bljoin h# 22 ( page offset ) + else ( ) + h# dfdf20 h# 2022 ( page offset ) + then ( page offset ) + dummy57 +; +: set-ex-vfp-size ( type param -- ) + over invert ( type param /type ) + swap invert ( type param /type /param ) + 0 bljoin ( type page# ) + h# 24 rot bljoin ( page# offset ) + dummy57 +; + +: set-protocol1 ( param -- ) 0 h# a2 rot bwjoin dummy57 ; +: get-protocol1 ( -- param ) 1 0 h# b2 read57 c@ ; +: 512-byte-transfers ( -- ) 1 set-protocol1 ; +: 2048-byte-transfers ( -- ) 4 set-protocol1 ; +: set-protocol2 ( param -- ) 0 h# a3 rot bwjoin dummy57 ; +: get-protocol2 ( -- param ) 1 0 h# b3 read57 c@ ; +: set-min-busy ( param -- ) 0 h# a4 rot bwjoin dummy57 ; +: get-min-busy ( -- param ) 1 0 h# b4 read57 c@ ; +: get-max-busy ( -- read write flush ) + 6 0 h# b9 read57 >r r@ le-w@ r@ 2+ le-w@ r> 4 + le-w@ +; +: power-down ( -- ) 0 h# ba dummy57 ; +: power-up ( -- ) 0 h# bb dummy57 ; +: fast-writing ( -- ) 0 h# bc dummy57 ; +: slow-writing ( -- ) 0 h# bd dummy57 ; +: start-free-sectors ( -- ) 0 h# 5e dummy57 ; +: free-sectors ( sector# #sectors -- ) + set-page ( ) + h# e020.0080 h# 0000.0110 cmd wait-cmd ( ) \ No ECC, write cmd (no data transfer) +; +: end-free-sectors ( -- ) 0 h# 5f dummy57 ; +: read-attributes ( which -- adr ) + 0 h# 9e dummy57 ( which ) + d# 512 swap 1 read-cmd h# 0000.0130 generic-read ( adr ) + 0 h# 9f dummy57 ( adr ) +; +: unique-id ( -- adr ) 0 read-attributes ; +: firmware-version ( -- adr ) h# 10 read-attributes ; +: hardware-version ( -- adr ) h# 20 read-attributes ; +: cache-flush ( -- ) h# 8020.00f9 0 cmd wait-cmd wait-ready ; +: pnr-mode ( -- ) h# 8020.00fd 0 cmd wait-cmd wait-ready ; +: lba-mode ( -- ) h# 8020.00fc 0 cmd wait-cmd wait-ready ; + +: setup ( -- ) + alloc-dma-buf + set-lmove + + h# 24 cl@ h# ff00 invert and h# 1000 or h# 24 cl! + h# 28 cl@ h# ff000000 invert and h# f0000000 or h# 28 cl! + h# 7fff.ffff to chip-boundary + + lba-mode + 2 set-protocol1 \ 2048-byte max transfer size + h# 200 to /page +; + +\ The deblocker converts a block/record-oriented interface to a byte-oriented +\ interface, using internal buffering. Disk and tape devices are usually +\ block or record oriented, but the OBP external interface is byte-oriented, +\ in order to be independent of particular device block sizes. + +0 instance value deblocker +: init-deblocker ( -- okay? ) + " " " deblocker" $open-package to deblocker + deblocker if + true + else + ." Can't open deblocker package" cr false + then +; + + +\ Label package routines - used for partitions + +0 instance value offset-low \ Offset to start of partition +0 instance value offset-high + +0 instance value label-package +true value report-failure + +\ Sets offset-low and offset-high, reflecting the starting location of the +\ partition specified by the "my-args" string. + +: init-label-package ( -- okay? ) + 0 to offset-high 0 to offset-low + my-args " disk-label" $open-package to label-package + label-package dup if + 0 0 " offset" label-package $call-method to offset-high to offset-low + else + report-failure if + ." Can't open disk label package" cr + then + then +; + +: block-size ( -- n ) h# 200 ; + +: max-transfer ( -- n ) h# 800 ; +\ : max-transfer ( -- n ) h# 200 ; + +: read-blocks ( adr block# #blocks -- #read ) + dup >r lba-get-sectors if ( adr r: #blocks ) + r> 2drop 0 ( #read ) + else ( adr dma-adr r: #blocks ) + swap r@ sectors>bytes do-lmove ( r: #blocks ) + r> ( #read ) + then +; +: write-blocks ( adr block# #blocks -- #written ) + dup >r lba-write-sectors if r> drop 0 else r> then +; + +: #blocks ( -- u ) mdp-size drop ; + +: lba-nand? ( -- false | open-ok? true ) + read-lba-id c@ dup 0= swap h# ff = or if false exit then + + setup + + init-deblocker 0= if false true exit then + + init-label-package 0= if + deblocker close-package false true exit + then + + true true +; + +: lba-close ( -- ) + label-package if label-package close-package then + deblocker if deblocker close-package then + cache-flush +; + +: seek ( offset.low offset.high -- okay? ) + offset-low offset-high d+ " seek" deblocker $call-method +; + +: read ( addr len -- actual-len ) " read" deblocker $call-method ; +: write ( addr len -- actual-len ) " write" deblocker $call-method ; +: load ( addr -- size ) " load" label-package $call-method ; + +: lba-size? ( -- false | d.size true ) + label-package if + " size" label-package $call-method ( d.size ) + true + else + false + then +; + +\ dend + +\ begin-select /nandflash +\ setup + + +[ifdef] notdef + +PNR - Pure NAND Read (raw mode) - first 256 2K pages (512 KiB) - power-on state + +VFP - Vendor Firmware Partition - 8 MBytes + +MDP - Multimedia Data Partition - enter mode with FC command + +BCM - Boot Code Maintenance - used for writing to PNR partition + + + +sequence feature (1) + +00 00 02 00 01 00 30 data data length can be select 512 or 528 (2048 or 2112) OOB data is dummy + +sequence feature (2) + +Type A + +00 00 02 00 01 00 30 <sector data> 00 <dummy address 5 bytes> 30 <sector data> ... + reading command setup + +Type B + +00 00 02 00 01 00 30 <sector data> f8 <sector data> ... + +VFD/MDP mode - OOB is ignored on write, dummy on read +PNR access mode boot area (the first 256 2K pages - 512 KiB) - OOB is read/write + + +Low-level driver init: + +Select transfer mode (whether to send dummy address and command for each data transfer - mode A or mode B) + +Disable ECC + +Select data length - 512 / 528, 2048 / 2112 + + +-- +Device comes up in raw NAND mode + +Mode changes puts it in MDP mode or VFP mode + +VFP mode is for program code +MDP mode is for data + +---- +Commands: +PNR mode: + Boot mode 1: + Page read (sequential) - <00> {00} {00} {page#0} {page#1} {page#2} <30> RDY {page data} ({Dummy page address}) + Page number reset to 0 - <ff> RDY + Boot mode 2: + Page read (sequential) - <00> {AD0} {AD1} {page#0} {page#1} {page#2} <30> RDY {page data} ({Dummy page address}) + Reset (noop) - <ff> RDY + Boot mode 3: + Page read (sequential) - <00> {xx} {xx} {xx} {xx} {xx} <30> {page data} + Reset (noop) - <ff> RDY + + Enter LBA mode - <fc> RDY 0020.00fc 0 0 >cmd + Enter PNR mode - <fd> RDY 0020.00fd 0 0 >cmd + + Enter BCM mode - <00> {xx} {xx} {xx} {FC} {xx} <30> RDY + + +LBA mode: + Sector Read Type A - <00> {cnt0} {cnt1} {sec#0} {sec#1} {sec#2} <30> RDY {data} (repeat all w dummy page address ...) + Retransmit - {prevdata} <31> RDY <00> {dummy 5-byte page address} <30> RDY {data} + Sector Read Type B - <00> {cnt0} {cnt1} {sec#0} {sec#1} {sec#2} <30> RDY {data} (<f8> {data} ...) + Retransmit - {prevdata} <31> RDY {data} + Sector Read Type C - <00> {cnt0} {cnt1} {sec#0} {sec#1} {sec#2} <30> RDY {data} ({data} ...) + Retransmit - {prevdata} RDY <31> RDY {data} + + Sector Write Type A - <80> {cnt0} {cnt1} {sec#0} {sec#1} {sec#2} <10> RDY {data} (repeat all w dummy page address ...) + Sector Write Type B - <80> {cnt0} {cnt1} {sec#0} {sec#1} {sec#2} <10> RDY {data} (<80> {data} <10> RDY ...) + + Switch to PNR partition in BCM mode - <00> {BF} {xx} {xx} {xx} {xx} <57> RDY + + Get MDP size - <00> {B0} {xx} {xx} {xx} {xx} <57> RDY {5 bytes LSB .. MSB} (total #sectors in MDP) + Get VFP size - <00> {B5} {xx} {xx} {xx} {xx} <57> RDY {2 bytes LSB .. MSB} (total #sectors in VFP) + Set VFP size - <00> {22} {SZ0} {SZ1} {/SZ0} {/SZ1} <57> RDY (clears VFP and MDP data) + Get EX_VFP size variation - <00> {B8} {10} {xx} {xx} {xx} <57> RDY {capacity_type, capacity_parameter} + Set EX_VFP size - <00> {24} {type} {param} {/type} {/param} <57> RDY + Get EX_VFP size - <00> {B7} {xx} {xx} {xx} {xx} <57> RDY {model_type, capacity_parameter} + + Set VFP Password - <00> {21} {OldPW1} {OldPW2} {PW1} {PW2} <57> RDY + + Set protocol 1 - <00> {A2} {param} {xx} {xx} {xx} <57> RDY (param is N in (512+16)*N } + Get protocol 1 - <00> {B2} {xx} {xx} {xx} {xx} <57> RDY {param 1 byte} (param is N in (512+16)*N) + + Set protocol 2 - <00> {A3} {param} {xx} {xx} {xx} <57> RDY (param is A,B,C select} + Get protocol 2 - <00> {B3} {xx} {xx} {xx} {xx} <57> RDY {param 1 byte} (param is A,B,C select) + + Set Min busy time - <00> {A4} {param} {xx} {xx} {xx} <57> RDY + Get Min busy time - <00> {B4} {xx} {xx} {xx} {xx} <57> RDY {param 1 byte} + Get Max busy time - <00> {B9} {xx} {xx} {xx} {xx} <57> RDY {read 2 bytes LE} {write 2 bytes LE} {flush 2 bytes LE} + + Power Down - <00> {BA} {xx} {xx} {xx} {xx} <57> RDY + Power Up - <00> {BB} {xx} {xx} {xx} {xx} <57> RDY + + High Speed Write Mode On - <00> {BC} {xx} {xx} {xx} {xx} <57> RDY + High Speed Write Mode Off - <00> {BD} {xx} {xx} {xx} {xx} <57> RDY + + Set Garbage Address Area - <00> {E5} {xx} {xx} {xx} {xx} <57> RDY (<80> {seccnt0, 1 secaddr0, 1, 2} <10> RDY) ... <00> <5f> {xx} {xx} {xx} {xx} <57> RDY + Cache Flush before power down - <F9> RDY + Vendor Option - <00> {8A} {vendor_code 98} {ven_def0} {ven_def1} {ven_def2} <57> RDY {ven_def 3-7} + +BCM Mode: + Read PNP Page - <00> {00} {00} {page#} {00} {00} <30> RDY {2112 bytes} + Write partial PNP Page - <80> {col_adr0} {col_adr1} {page#} {len0} {len1} <30> RDY {up to 2112 bytes} <10> RDY + Cache Flush in BCM mode - <00> {xx} {xx} {xx} {F9} {xx} <30> RDY + Device Reboot in BCM mode - <80> {xx} {xx} {xx} {FD} {xx} <10> RDY (back to PNR read mode) + Set Boot Mode 1 - <00> {xx} {xx} {xx} {11} {xx} <30> RDY + Set Boot Mode 2 - <00> {xx} {xx} {xx} {22} {xx} <30> RDY + Set Boot Mode 3 - <00> {xx} {xx} {xx} {33} {xx} <30> RDY + Set Reboot Mode FD - <00> {xx} {xx} {xx} {AD} {xx} <30> RDY + Set Reboot Mode FD/FF - <00> {xx} {xx} {xx} {AF} {xx} <30> RDY + Get persistent modes - <00> {xx} {xx} {xx} {99} {xx} <30> RDY [boot_mode_value-11/22/33, reboot_mode-AD/AD] + + +All Modes: + Read ID 1 (fake ID) - <90> {00} {5 ID bytes} (emulated SLC 4Gbit ID) + Read ID 2 (real ID) - <92> {00} {5 ID bytes} (LBA-ID + + Switch to MDP partition - <FC> RDY + Switch to VFP partition - <00> {BE} {PW0} {PW1} {xx} {xx} <57> RDY (PW: password - default FF) + + Unique ID - <00> {9E} {xx} {xx} {xx} {xx} <57> RDY <00> {01} {00} {00} {00} {00} <30> RDY {ID data} <00> {9F} {xx} {xx} {xx} {xx} <57> RDY + Firmware version - <00> {9E} {xx} {xx} {xx} {xx} <57> RDY <00> {01} {00} {10} {00} {00} <30> RDY {FW version} <00> {9F} {xx} {xx} {xx} {xx} <57> RDY + Firmware version - <00> {9E} {xx} {xx} {xx} {xx} <57> RDY <00> {01} {00} {20} {00} {00} <30> RDY {FW version} <00> {9F} {xx} {xx} {xx} {xx} <57> RDY + + R/W Terminate - <fb> RDY (must first wait for RDY except for read types A&B) + + Device Reboot to PNR mode - <FD> RDY (<FF> RDY) +[then]
Modified: dev/olpc/cafenand/methods.fth =================================================================== --- dev/olpc/cafenand/methods.fth 2008-09-12 22:34:01 UTC (rev 935) +++ dev/olpc/cafenand/methods.fth 2008-09-12 22:37:48 UTC (rev 936) @@ -41,6 +41,7 @@ : close ( -- ) \ Leave the timing registers set so the OS driver can get the \ right values from them. + lba-close soft-reset timing-configure unmap-regs dma-buf-va ?dup if dma-buf-va dma-buf-pa /dma-buf " dma-map-out" $call-parent @@ -48,7 +49,10 @@ then ;
-: size ( -- d ) partition-size /page um* ; +: size ( -- d ) + lba-size? if exit then + partition-size /page um* +;
: $set-partition ( $ -- error? ) dup 0= if 2drop false exit then ( $ ) @@ -66,15 +70,14 @@ : open ( -- okay? ) map-regs init + lba-nand? if exit then 0 to partition# 0 to partition-start 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 + alloc-dma-buf + set-lmove
- " lmove" $find 0= if ['] move then to do-lmove - get-bbt usable-page-limit to partition-size read-partmap
Modified: dev/olpc/cafenand/selftest.fth =================================================================== --- dev/olpc/cafenand/selftest.fth 2008-09-12 22:34:01 UTC (rev 935) +++ dev/olpc/cafenand/selftest.fth 2008-09-12 22:37:48 UTC (rev 936) @@ -56,7 +56,7 @@ then ; : read-eblock ( adr page# -- error? ) - pages/eblock read-blocks pages/eblock <> + pages/eblock read-pages pages/eblock <> dup if ." SAVE" cr then ; : write-eblock ( adr page# -- error? ) @@ -64,7 +64,7 @@ over /eblock erased? if ( adr page# ) 2drop false else ( adr page# ) - pages/eblock write-blocks pages/eblock <> + pages/eblock write-pages pages/eblock <> dup if ." RESTORE" cr then then ;
Modified: ofw/fs/fatfs/device.fth =================================================================== --- ofw/fs/fatfs/device.fth 2008-09-12 22:34:01 UTC (rev 935) +++ ofw/fs/fatfs/device.fth 2008-09-12 22:37:48 UTC (rev 936) @@ -121,73 +121,78 @@ then ;
-\ This version of read-bpb implements Microsoft's recommended -\ method for determining whether a filesystem is FAT-16 or FAT-32. +\ This BPB parser implements Microsoft's recommended method +\ for determining whether a filesystem is FAT-16 or FAT-32. variable nsects -: ?read-bpb ( -- ) - /sector 0= if \ Read bpb if necessary - init-sector-size - find-bpb
- bp_media c@ media c! - bp_bps lew@ bps w@ <> if - ." WARNING: BPB sector size differs from device sector size" cr - then - bp_bps lew@ bps w! - bp_spc c@ spc c! - bp_spf lew@ ?dup 0= if bp_bspf lel@ then spf l! - bp_nsects lew@ ?dup 0= if bp_xnsects lel@ then nsects l! +: bpb>device ( -- ) + bp_media c@ media c! + bp_bps lew@ bps w! + bp_spc c@ spc c! + bp_spf lew@ ?dup 0= if bp_bspf lel@ then spf l! + bp_nsects lew@ ?dup 0= if bp_xnsects lel@ then nsects l!
- bp_ndirs lew@ /dirent * /sector 1- + /sector / #dir-sectors w! + bp_ndirs lew@ /dirent * /sector 1- + /sector / #dir-sectors w!
- \ nsects is TotSec - \ #dir-sectors is RootDirSectors + \ nsects is TotSec + \ #dir-sectors is RootDirSectors
- \ Sector number where the FAT starts. - \ bp_nhid is the number of sectors before the BPB sector. - \ bp_res is the number of sectors from the BPT sector to the - \ first FAT sector. + \ Sector number where the FAT starts. + \ bp_nhid is the number of sectors before the BPB sector. + \ bp_res is the number of sectors from the BPT sector to the + \ first FAT sector.
- \ If the underlying disk driver handles partition offsets, - \ we don't need to handle bp_nhid here. - bp_res lew@ ( bp_nhid lel@ + ) - dup fat-sector0 w! ( #resv-sectors ) - spf l@ bp_nfats c@ * + ( #early-sectors ) - dup dir-sector0 w! ( #early-sectors ) - #dir-sectors w@ + cl-sector0 l! ( ) + \ If the underlying disk driver handles partition offsets, + \ we don't need to handle bp_nhid here. + bp_res lew@ ( bp_nhid lel@ + ) + dup fat-sector0 w! ( #resv-sectors ) + spf l@ bp_nfats c@ * + ( #early-sectors ) + dup dir-sector0 w! ( #early-sectors ) + #dir-sectors w@ + cl-sector0 l! ( )
- \ cl-sector0 is FirstDataSector + \ cl-sector0 is FirstDataSector
- nsects l@ #dir-sectors w@ - spc c@ / ( #clusters ) - dup d# 65525 >= if ( #clusters ) - drop fat32 fat-type c! - 0 dir-sector0 w! - bp_rdirclus lel@ rdirclus l! - bp_fsinfos lew@ dup read-fsinfo fsinfos w! - else - d# 4085 >= if fat16 else fat12 then fat-type c! - 0 fsinfo ! 0 fssector ! false fsinfos-dirty c! - 0 fsinfos w! 0 rdirclus l! - then + nsects l@ #dir-sectors w@ - spc c@ / ( #clusters ) + dup d# 65525 >= if ( #clusters ) + drop fat32 fat-type c! + 0 dir-sector0 w! + bp_rdirclus lel@ rdirclus l! + bp_fsinfos lew@ dup read-fsinfo fsinfos w! + else + d# 4085 >= if fat16 else fat12 then fat-type c! + 0 fsinfo ! 0 fssector ! false fsinfos-dirty c! + 0 fsinfos w! 0 rdirclus l! + then
- \ The number of clusters is limited both by space for clusters numbers - \ in the FAT and by disk space for storage of the actual clusters. - \ It would be silly to waste disk space by making the FAT too small, - \ but I am paranoid so I check both limits. + \ The number of clusters is limited both by space for clusters numbers + \ in the FAT and by disk space for storage of the actual clusters. + \ It would be silly to waste disk space by making the FAT too small, + \ but I am paranoid so I check both limits.
- \ Calculate the number of clusters the FAT can represent - spf l@ /sector * bytes>cl-entries ( #clusters ) + \ Calculate the number of clusters the FAT can represent + spf l@ /sector * bytes>cl-entries ( #clusters )
- \ Compare it with the number of clusters for which there is disk space - nsects l@ - cl-sector0 l@ - spc c@ / 2 + min 1- - max-cl# l! - free-bpb + \ Compare it with the number of clusters for which there is disk space + nsects l@ + cl-sector0 l@ - spc c@ / 2 + min 1- + max-cl# l! +;
+: ?read-bpb ( -- ) + /sector 0= if \ Read bpb if necessary + init-sector-size + find-bpb + bp_bps lew@ bps w@ <> if + ." WARNING: BPB sector size differs from device sector size" cr + then + bpb>device + + init-fat-cache + \ Start with the root directory as the current working directory rdirclus @ dv_cwd-cl l!
- init-fat-cache + free-bpb then ;
Modified: ofw/fs/fatfs/fdisk2.fth =================================================================== --- ofw/fs/fatfs/fdisk2.fth 2008-09-12 22:34:01 UTC (rev 935) +++ ofw/fs/fatfs/fdisk2.fth 2008-09-12 22:37:48 UTC (rev 936) @@ -143,7 +143,9 @@ ; false value type32? : init-bpb ( #mbytes type name$ -- ) - string2 pack >r " :1,<NoFile>" r@ $cat r> count select-dev + ." Initializing file system ..." cr + + string2 pack >r " :1//fat-file-system:<NoFile>" r@ $cat r> count select-dev fat32? to type32? dup type32? compute-cluster-size swap 2>r ( R: spc #mbytes ) 1 h# 40 h# 20 ( #hid-sec #heads sec/trk ) ( R: spc #mbytes ) @@ -175,7 +177,7 @@ \ We don't bother with the cylinder/head/sector numbers, because they \ rarely matter anymore, and we don't have a good way to find them.
- 1 h# 1c6 +buf le-l! \ Begin the partition at logical block 1 + h# 10 h# 1c6 +buf le-l! \ Begin the partition at logical block 16
dup >r ( #mbytes ) d# 2048 * ( #blocks ) h# 1ca +buf le-l!
Modified: ofw/fs/fatfs/makefs.fth =================================================================== --- ofw/fs/fatfs/makefs.fth 2008-09-12 22:34:01 UTC (rev 935) +++ ofw/fs/fatfs/makefs.fth 2008-09-12 22:37:48 UTC (rev 936) @@ -72,7 +72,9 @@ dup alloc-mem dup bpb ! over erase
r@ if set-params32 else set-params16 then + bpb>device r> r> ( fat32? bps ) + bpb @ over 1- + h# aa over c! 1- h# 55 swap c! 0 1 bpb @ write-sectors ( fat32? bps error? ) rot if \ Write file system info sector @@ -92,6 +94,7 @@ bpb @ rot free-mem if "CaW ". ." sector 0" abort then
+ 0 bps w! \ Force reread ?read-bpb \ Now read back the BIOS parameter block
\ Clear the FATs. (0 means "free cluster")
Modified: ofw/fs/jffs2/jffs2.fth =================================================================== --- ofw/fs/jffs2/jffs2.fth 2008-09-12 22:34:01 UTC (rev 935) +++ ofw/fs/jffs2/jffs2.fth 2008-09-12 22:37:48 UTC (rev 936) @@ -143,7 +143,7 @@ \ Partial reads invalidate the cache dup pages/eblock <> if -1 to have-eblock# then ( page# #pages )
- block-buf -rot " read-blocks" $call-parent ( #read ) + block-buf -rot " read-pages" $call-parent ( #read ) ; : read-pages ( page# #pages -- error? ) tuck (read-pages) <> ; : read-eblock ( eblock# -- ) @@ -1468,7 +1468,7 @@ jffs2-magic over w! \ magic ( pad-adr r: page# ) padding-type over wa1+ w! \ nodetype ( pad-adr r: page# ) dup 8 crc swap 2 j! \ crc ( r: page# ) - block-buf r> 1 " write-blocks" $call-parent ( ) + block-buf r> 1 " write-pages" $call-parent ( ) 1 <> dup if ." JFFS2: write failed" then ( error? ) ;
@@ -1515,7 +1515,7 @@ : set-sizes ( -- ) -1 to file-size
- " block-size" $call-parent to /page + " page-size" $call-parent to /page
" erase-size" ['] $call-parent ( adr len xt ) catch if 2drop h# 20000 then ( n )
openfirmware@openfirmware.info