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 )