mirror of
https://github.com/openbios/openfirmware.git
synced 2025-05-09 00:21:49 +08:00

integrate FLASH write drivers into the system. For OLPC, there is no functional difference at the top level, but the internal arrangement of the FLASH device node subtree has changed. It's now possible to compile an OLPC ROM that can save configuration variables in an SPI FLASH block (see config.fth:use-flash-nvram). For the lxdevel build, that option is now chosen by default. git-svn-id: svn://coreboot.org/openfirmware@838 1552c027-8020-0410-b4b5-a757f869b4ce
105 lines
3.8 KiB
Forth
105 lines
3.8 KiB
Forth
0 [if]
|
|
\ Write support is complicated by the need to erase before
|
|
\ writing and the possibly-different erase and write granularity.
|
|
\
|
|
\ For NOR FLASH, where you can write as many times as you want
|
|
\ while turning 1's into 0's, the algorithm is:
|
|
\
|
|
\ Break the entire write range into pieces each contained in one
|
|
\ erase unit. For each piece:
|
|
\
|
|
\ Compare the existing and new contents to see if the unit needs erasing
|
|
\
|
|
\ If no bits need to go from 0 to 1, erase is unnecessary, so just write.
|
|
\ (It's a little more complicated if the write granularity is >1 byte.)
|
|
\
|
|
\ Otherwise, copy the existing contents of the erase unit to a buffer,
|
|
\ merge in the new data, erase, then write back the buffer.
|
|
[then]
|
|
|
|
\ dev /flash
|
|
|
|
[ifndef] flash-write-enable
|
|
also forth definitions
|
|
defer flash-write-enable ( -- )
|
|
defer flash-write-disable ( -- )
|
|
defer flash-erase-block ( offset -- )
|
|
defer flash-write ( adr len offset -- )
|
|
defer flash-read ( adr len offset -- )
|
|
defer flash-verify ( adr len offset -- )
|
|
h# 10.0000 value /flash
|
|
h# 10000 value /flash-block
|
|
previous definitions
|
|
[then]
|
|
|
|
|
|
: left-in-block ( len offset -- #left )
|
|
\ Determine how many bytes are left in the page containing offset
|
|
/flash-block swap /flash-block 1- and - ( len left-in-page )
|
|
min ( #left )
|
|
;
|
|
|
|
: must-erase? ( adr len -- flag )
|
|
device-base seek-ptr + ( adr len dev-adr )
|
|
swap 0 ?do ( adr dev-adr )
|
|
over i + c@ over i + c@ ( adr dev-adr new-byte old-byte )
|
|
\ Must erase if a bit in old-byte is 0 and that bit in new-byte is 1
|
|
invert and if ( adr dev-adr )
|
|
2drop true unloop exit
|
|
then ( adr dev-adr )
|
|
loop ( adr dev-adr )
|
|
2drop false
|
|
;
|
|
|
|
: erase+write ( adr len -- )
|
|
dup /flash-block = if
|
|
\ If we are going to overwrite the entire block, there's no need to
|
|
\ preserve the old data. This can only happen if we are already
|
|
\ aligned on an erase block boundary.
|
|
seek-ptr flash-erase-block ( adr len )
|
|
seek-ptr flash-write ( )
|
|
else
|
|
\ Allocate a buffer to save the old block contents
|
|
/flash-block alloc-mem >r ( adr len )
|
|
|
|
seek-ptr /flash-block round-down ( adr len block-start )
|
|
|
|
\ Copy existing data from FLASH block to the buffer
|
|
dup device-base + r@ /flash-block lmove ( adr len block-start )
|
|
|
|
\ Merge new bytes into the buffer
|
|
-rot ( block-start adr len )
|
|
seek-ptr /flash-block mod ( block-start adr len buf-offset )
|
|
r@ + swap move ( block-start )
|
|
|
|
\ Erase the block and rewrite it from the buffer
|
|
dup flash-erase-block ( block-start )
|
|
r@ /flash-block rot flash-write ( )
|
|
|
|
\ Release the buffer
|
|
r> /flash-block free-mem
|
|
then
|
|
;
|
|
|
|
: handle-block ( adr len -- adr' len' )
|
|
dup seek-ptr left-in-block ( adr len #left )
|
|
>r ( adr len r: #left )
|
|
over r@ must-erase? if ( adr len r: #left )
|
|
over r@ erase+write ( adr len r: #left )
|
|
else ( adr len r: #left )
|
|
over r@ seek-ptr flash-write ( adr len r: #left )
|
|
then ( adr len r: #left )
|
|
seek-ptr r@ + to seek-ptr ( adr len r: #left )
|
|
r> /string ( adr' len' )
|
|
;
|
|
|
|
: write ( adr len -- #written )
|
|
flash-write-enable
|
|
tuck ( len adr len )
|
|
begin dup while handle-block repeat ( len adr' remain' )
|
|
2drop ( len )
|
|
flash-write-disable
|
|
;
|
|
|
|
\ dend
|