Author: wmb Date: 2008-08-13 23:37:36 +0200 (Wed, 13 Aug 2008) New Revision: 881
Modified: cpu/x86/pc/neptune/addrs.fth cpu/x86/pc/neptune/config.fth cpu/x86/pc/neptune/devices.fth cpu/x86/pc/neptune/fw.bth cpu/x86/pc/neptune/romreset.bth dev/flashui.fth dev/flashwritepkg.fth dev/lpcflash.fth Log: Neptune - FLASH reprogramming user interface and enabled configuration variable saving.
Modified: cpu/x86/pc/neptune/addrs.fth =================================================================== --- cpu/x86/pc/neptune/addrs.fth 2008-08-13 10:13:36 UTC (rev 880) +++ cpu/x86/pc/neptune/addrs.fth 2008-08-13 21:37:36 UTC (rev 881) @@ -4,12 +4,18 @@ h# fff0.0000 constant rom-pa \ Physical address of boot ROM h# 10.0000 constant /rom \ Size of boot ROM
+h# 0.0000 constant config-vars-offset h# 8.0000 constant dropin-offset rom-pa dropin-offset + constant dropin-base h# 8.0000 constant dropin-size
dropin-base h# 20 + constant ResetBase \ Location of "reset" dropin in ROM
+\ Firmware reflash parameters +h# 8.0000 constant fw-offset \ Where to start reflashing +h# 8.0000 constant /fw-reflash \ Expected size of a reflash image +h# -30 constant fw-crc-offset \ Location of firmware CRC (- is from end) + h# 1c0.0000 constant fw-pa h# 20.0000 constant /fw-ram
Modified: cpu/x86/pc/neptune/config.fth =================================================================== --- cpu/x86/pc/neptune/config.fth 2008-08-13 10:13:36 UTC (rev 880) +++ cpu/x86/pc/neptune/config.fth 2008-08-13 21:37:36 UTC (rev 881) @@ -51,8 +51,8 @@ \ create use-ega \ create save-msrs
-create use-null-nvram \ Don't store configuration variables -\ create use-flash-nvram \ Store configuration variables in firmware FLASH +\ create use-null-nvram \ Don't store configuration variables +create use-flash-nvram \ Store configuration variables in firmware FLASH
fload ${BP}/cpu/x86/pc/neptune/addrs.fth
Modified: cpu/x86/pc/neptune/devices.fth =================================================================== --- cpu/x86/pc/neptune/devices.fth 2008-08-13 10:13:36 UTC (rev 880) +++ cpu/x86/pc/neptune/devices.fth 2008-08-13 21:37:36 UTC (rev 881) @@ -79,16 +79,50 @@ ; warning !
+\ Create the secondary FLASH node. This device exists only when an external +\ card is attached to the board. It is used for initial programming of +\ the primary FLASH, by swapping the ID selects for the internal and external +\ FLASH chips. The external FLASH appears as the primary boot FLASH (fff00000) +\ and the internal one as the secondary (ffe00000). In normal operation, +\ the internal FLASH is primary (fff00000) and the secondary doesn't exist. + +\ We define the secondary node first so that "/flash" will refer to the primary +\ (pathname matching finds the most recent match first). + +0 0 " ffe00000" " /" begin-package + " flash" device-name + + h# 10.0000 constant /device + h# 1.0000 constant /block + h# 1000 constant /sector + my-address my-space /device reg + + h# 40.0000 negate constant regs-offset + + : write-enable ( -- ) + h# 1808 rdmsr h# ff.ffff and h# 2100.0000 or h# 1808 wrmsr + ; + : write-disable ( -- ) + h# 1808 rdmsr h# ff.ffff and h# 2500.0000 or h# 1808 wrmsr + ; + + fload ${BP}/dev/flashpkg.fth + fload ${BP}/dev/lpcflash.fth + fload ${BP}/dev/flashwritepkg.fth +end-package + \ Create the top-level device node to access the entire boot FLASH device 0 0 " fff00000" " /" begin-package " flash" device-name
h# 10.0000 value /device + my-address my-space /device reg + h# 10.0000 constant /device-phys - my-address my-space /device-phys reg + h# 1.0000 constant /block + h# 1000 constant /sector
h# 40.0000 negate constant regs-offset - h# 1.0000 value block-size
: write-enable ( -- ) h# 1808 rdmsr h# ff.ffff and h# 2100.0000 or h# 1808 wrmsr @@ -106,7 +140,7 @@
\ Create a node below the top-level FLASH node to accessing the portion \ containing the dropin modules -0 0 dropin-offset <# u#s u#> " /flash" begin-package +0 0 dropin-offset <# u#s u#> " flash" begin-package " dropins" device-name
dropin-size constant /device @@ -121,29 +155,6 @@ \ This devalias lets us say, for example, "dir rom:" devalias rom /dropin-fs
-\ Create the top-level device node to access the entire boot FLASH device -0 0 " ffe00000" " /" begin-package - " flash" device-name - - h# 10.0000 value /device - h# 10.0000 constant /device-phys - my-address my-space /device-phys reg - h# 1.0000 value block-size - - h# 40.0000 negate constant regs-offset - - : write-enable ( -- ) - h# 1808 rdmsr h# ff.ffff and h# 2100.0000 or h# 1808 wrmsr - ; - : write-disable ( -- ) - h# 1808 rdmsr h# ff.ffff and h# 2500.0000 or h# 1808 wrmsr - ; - - fload ${BP}/dev/flashpkg.fth - fload ${BP}/dev/lpcflash.fth - fload ${BP}/dev/flashwritepkg.fth -end-package - fload ${BP}/cpu/x86/forthint.fth \ Low-level interrupt handling code fload ${BP}/dev/isa/irq.fth \ ISA interrupt dispatcher fload ${BP}/cpu/x86/pc/isatick.fth \ Use ISA timer as the alarm tick timer @@ -218,10 +229,10 @@
\ Create a node below the top-level FLASH node to access the portion \ containing the configuration variables. -0 0 " d0000" " /flash" begin-package +0 0 config-vars-offset <# u#s u#> " flash" begin-package " nvram" device-name
- h# 10000 constant /device + h# 1000 constant /device \ 4K - SST49LF080A sector size fload ${BP}/dev/subrange.fth end-package
Modified: cpu/x86/pc/neptune/fw.bth =================================================================== --- cpu/x86/pc/neptune/fw.bth 2008-08-13 10:13:36 UTC (rev 880) +++ cpu/x86/pc/neptune/fw.bth 2008-08-13 21:37:36 UTC (rev 881) @@ -422,6 +422,28 @@
fload ${BP}/dev/flashui.fth
+\ Copies internal flash to external - everything, including config vars +: clone-flash ( -- ) + " /flash@fff00000" open-dev >r + load-base /rom " read" r@ $call-method drop + r> close-dev + + " devalias flash /flash@ffe00000" evaluate + load-base /rom 0 ($reflash) + " devalias flash /flash@fff00000" evaluate +; + +: clone-firmware ( -- ) + " /flash@fff00000" open-dev >r + fw-offset u>d " seek" r@ $call-method drop + load-base /fw-reflash " read" r@ $call-method drop + r> close-dev + + " devalias flash /flash@ffe00000" evaluate + load-base /fw-reflash $reflash + " devalias flash /flash@fff00000" evaluate +; + : vme ( -- ) ." Running Lattice programmer " com1 io
Modified: cpu/x86/pc/neptune/romreset.bth =================================================================== --- cpu/x86/pc/neptune/romreset.bth 2008-08-13 10:13:36 UTC (rev 880) +++ cpu/x86/pc/neptune/romreset.bth 2008-08-13 21:37:36 UTC (rev 881) @@ -97,8 +97,7 @@ \ sdram_initialize,generic_sdram.c \ sdram_set_spdregisters(),auto.c
- \ The LX devel board has only 512M ROM, but assigning 1M of address space is harmless - 25fff002.10f80000. 1808 set-msr \ 1M ROM at fff0.0000, system RAM limit at 0f80.0000 + 25ffe002.10f80000. 1808 set-msr \ 2M ROM at ffe0.0000, system RAM limit at 0f80.0000 20000000.000fff00. 10000020 set-msr \ memory - 0..fffff 2000000f.7ff00100. 10000028 set-msr \ Top of memory at 0f7f.ffff 212800fd.7fffd000. 10000029 set-msr \ Range Offset - Frame buffer at PA fd00.0000 maps to RAM at 0f80.0000
Modified: dev/flashui.fth =================================================================== --- dev/flashui.fth 2008-08-13 10:13:36 UTC (rev 880) +++ dev/flashui.fth 2008-08-13 21:37:36 UTC (rev 881) @@ -1,38 +1,29 @@ purpose: Simple FLASH write user interface, calling flash node methods \ See license at end of file.
-[ifndef] reflash -0 value flash-buf -0 value /flash -0 value /flash-block - -\ Simple UI for reflashing, assuming that you want to overwrite -\ the entire FLASH contents. That's not always a good assumption; +\ Simple UI for reflashing. That's not always a good assumption; \ some systems use certain FLASH blocks for persistent data like \ configuration variables or manufacturing data ("Vital Product Data").
-0 value file-loaded? - -: ?image-valid ( len -- ) - /flash <> abort" Image file is the wrong length" -; - 0 value flash-ih +0 value /flash-block
: $call-flash ( ??? -- ??? ) flash-ih $call-method ; : close-flash ( -- ) flash-ih if flash-ih close-dev 0 to flash-ih - flash-buf /flash free-mem then ;
-: ?open-flash ( -- ) +: open-flash ( -- ) flash-ih if exit then
" flash" open-dev to flash-ih - flash-ih 0= abort" Can't open FLASH device" + flash-ih 0= if + close-flash + true abort" Can't open FLASH device" + then
" writable?" $call-flash 0= if close-flash @@ -40,56 +31,88 @@ then
" block-size" $call-flash to /flash-block - " size" $call-flash drop to /flash - /flash alloc-mem to flash-buf ;
-: $get-flash-file ( "filename" -- ) - $read-open - flash-buf /flash ifd @ fgets ( len ) - ifd @ fclose +: crc ( adr len -- crc ) 0 crctab 2swap ($crc) ;
- ?image-valid +: ?crc ( adr len -- ) + fw-crc-offset -1 = if 2drop exit then \ -1 means don't check
- true to file-loaded? + ." Checking integrity ..." cr + + \ Negative offsets are from the end + fw-crc-offset 0< if 2dup + else over then ( adr len crc-base ) + fw-crc-offset + ( crc-adr ) + + dup l@ >r ( adr len crc-adr r: crc ) + -1 over l! ( adr len crc-adr r: crc ) + + -rot crc ( crc-adr calc-crc r: crc ) + r@ rot l! ( calc-crc r: crc ) + r> <> if + true abort" Firmware image has bad internal CRC" + then ;
-: ?file ( -- ) - file-loaded? 0= if - ." You must first load a valid FLASH image file with" cr - ." get-file filename" cr - abort +: ?image-valid ( adr len -- ) + dup /fw-reflash <> if + true abort" Firmware image length is wrong" then + ?crc ;
-: reflash ( -- ) \ Flash from data already in memory - ?open-flash - ?file +\ No error checking so you can override the standard parameters +: ($reflash) ( adr len offset -- ) + open-flash ( adr len offset )
- ." Writing" cr + tuck u>d " seek" $call-flash drop ( adr offset len )
- /flash 0 ?do - (cr i . - flash-buf i + /flash-block i " flash-write" $call-flash ( ) - /flash-block +loop + ." Writing" cr ( adr offset len )
+ 0 ?do ( adr offset ) + (cr dup i + .x ( adr offset ) + over i + /flash-block ( adr offset adr' len ) + " write" $call-flash drop ( adr offset ) + /flash-block +loop ( adr offset ) + 2drop ( ) + close-flash ;
-\ Set this defer word to return a string naming the default -\ filename for firmware updates -defer fw-filename$ ' null$ to fw-filename$ +: $reflash ( adr len -- ) \ Flash from data already in memory + 2dup ?image-valid + fw-offset ($reflash) +;
-: get-flash-file ( ["filename"] -- ) - ?open-flash - parse-word ( adr len ) - dup 0= if 2drop fw-filename$ then ( adr len ) - ." Reading " 2dup type cr ( adr len ) - $get-flash-file +0 value flash-buf + +: get-flash-file ( "filename" -- adr len ) + safe-parse-word ( filename$ ) + ." Reading " 2dup type cr ( filename$ ) + $read-open ( ) + ifd @ fsize /fw-reflash <> if ( ) + ifd @ fclose + true abort" Firmware image file size is wrong" + then ( ) + + /fw-reflash alloc-mem to flash-buf ( ) + + flash-buf /fw-reflash ifd @ fgets ( len ) + ifd @ fclose ( ) + /fw-reflash <> if + flash-buf /fw-reflash free-mem + true abort" Firmware image read failure" + then + + flash-buf /fw-reflash ( adr len ) ;
-: flash ( ["filename"] -- ) get-flash-file reflash ; -[then] +: flash ( "filename" -- ) + get-flash-file ( adr len ) + ['] $reflash catch ( false | x x throw-code ) + flash-buf /fw-reflash free-mem ( false | x x throw-code ) + throw +;
\ LICENSE_BEGIN
Modified: dev/flashwritepkg.fth =================================================================== --- dev/flashwritepkg.fth 2008-08-13 10:13:36 UTC (rev 880) +++ dev/flashwritepkg.fth 2008-08-13 21:37:36 UTC (rev 881) @@ -23,9 +23,27 @@ \ Otherwise, copy the existing contents of the erase unit to a buffer, \ merge in the new data, erase, then write back the buffer.
-: left-in-block ( len offset -- #left ) +0 instance value /chunk + +: set-chunk-size ( len -- ) + dup /device = if ( len ) + seek-ptr 0= if to /chunk exit then ( len ) + then ( len ) + /block >= if /block else /sector then to /chunk +; + +: erase-chunk ( offset -- ) + /chunk case ( offset ) + /sector of erase-sector endof + /block of erase-block endof + /device of drop erase-chip endof + true abort" flashwritepkg: Internal error - bad value for /chunk" + endcase +; + +: left-in-chunk ( len offset -- #left ) \ Determine how many bytes are left in the page containing offset - block-size swap block-size 1- and - ( len left-in-page ) + /chunk swap /chunk 1- and - ( len left-in-page ) min ( #left ) ;
@@ -42,37 +60,37 @@ ;
: erase+write ( adr len -- ) - dup block-size = if + dup /chunk = if ( adr len ) \ 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 erase-block ( adr len ) - seek-ptr flash-write ( ) + seek-ptr erase-chunk ( adr len ) + seek-ptr flash-write ( ) else \ Allocate a buffer to save the old block contents - block-size alloc-mem >r ( adr len ) + /chunk alloc-mem >r ( adr len )
- seek-ptr block-size round-down ( adr len block-start ) + seek-ptr /chunk round-down ( adr len block-start )
\ Copy existing data from FLASH block to the buffer - dup device-base + r@ block-size lmove ( adr len block-start ) + dup device-base + r@ /chunk lmove ( adr len block-start )
\ Merge new bytes into the buffer - -rot ( block-start adr len ) - seek-ptr block-size mod ( block-start adr len buf-offset ) - r@ + swap move ( block-start ) + -rot ( block-start adr len ) + seek-ptr /chunk mod ( block-start adr len buf-offset ) + r@ + swap move ( block-start )
\ Erase the block and rewrite it from the buffer - dup erase-block ( block-start ) - r@ block-size rot flash-write ( ) + dup erase-chunk ( block-start ) + r@ /chunk rot flash-write ( )
\ Release the buffer - r> block-size free-mem + r> /chunk free-mem then ;
: handle-block ( adr len -- adr' len' ) - dup seek-ptr left-in-block ( adr len #left ) + dup seek-ptr left-in-chunk ( 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 ) @@ -85,6 +103,7 @@
: write ( adr len -- #written ) writable? 0= if 2drop 0 exit then + dup set-chunk-size ( adr len ) tuck ( len adr len ) begin dup while handle-block repeat ( len adr' remain' ) 2drop ( len )
Modified: dev/lpcflash.fth =================================================================== --- dev/lpcflash.fth 2008-08-13 10:13:36 UTC (rev 880) +++ dev/lpcflash.fth 2008-08-13 21:37:36 UTC (rev 881) @@ -1,11 +1,20 @@ purpose: LPC/FWH FLASH low-level write words for use inside a device node \ See license at end of file.
-\ write-enable and write-disable need to be defined externally -\ Typically you load flashpkg.fth before and flashwritepkg.fth after this +\ Typically this file is loaded between flashpkg.fth and flashwritepkg.fth
0 instance value regs-adr
+\ The "register space" for an LPC FLASH device is a different address bank, +\ typically differing by the value of A22. In some devices there are only +\ two registers (chip ID and GPIO), while other devices have write lock +\ registers scattered throughout a large (e.g. 1 MB) address space. + +: map-regs ( -- ) + regs-adr if exit then + my-address my-space regs-offset + /device " map-in" $call-parent to regs-adr +; + : unmap-regs ( -- ) regs-adr if regs-adr /device " map-out" $call-parent @@ -14,13 +23,45 @@ then ;
+\ This tests for the presence of an LPC/FWH FLASH device by trying to +\ read its ID register. You can't tell by reading the FLASH data because +\ an erased device is indistinguishable from a device that's not there. +\ ROM emulators that can't be written via the LPC bus will show up as +\ "not present" (unless they emulate the ID register). + +: (present?) ( -- flag ) + regs-adr h# c.0000 + c@ ( id0 ) + + dup 0<> swap h# ff <> and ( id-present? ) +; + +\ Test for device presence, leaving register space in the same state +\ (mapped or not) as before. This is intended for use as an "early +\ probe" to see if the device is there. + +: present? ( -- flag ) + regs-adr if + (present?) + else + map-regs (present?) unmap-regs + then +; + +\ Test for device presence (and thus the ability to write), leaving +\ register space mapped and the device write-enabled if the device is +\ indeed present. This intended for use in preparation for a sequence +\ of write operations. When the sequence is finished, closing the +\ device instance will unmap the registers and write-disable . + : writable? ( -- flag ) + \ This is an optimization so writable? can be called multiple times + \ quickly. Theres is no point in leaving register space mapped if + \ there are no registers. regs-adr if true exit then
- my-address my-space regs-offset + /device " map-in" $call-parent to regs-adr - regs-adr h# c.0000 + c@ ( id0 ) + map-regs
- dup 0<> swap h# ff <> and ( writable? ) + (present?)
dup if write-enable else unmap-regs then ; @@ -32,7 +73,11 @@ : >lpc-adr ( offset -- ) device-base + ; : jedec! ( byte -- ) h# 5555 >lpc-adr c! ;
-\ The write enable for the block at fffx.0000 is at ffbx.0002 +\ Some, but not all, devices have block-granularity software locking via +\ register-space addresses. For example, SST49LF008A (FWH version) has +\ software locking, while SST47LF080A (LPC version) does not. Writing +\ the lock register addresses is innocuous on the ones without locking. + : write-enable-block ( offset -- ) h# ffff invert and 2 or ( we-offset ) regs-adr + 0 swap c! @@ -53,10 +98,21 @@ begin device-base c@ tuck = until ( value ) drop ; +: erase-sector ( offset -- ) + dup write-enable-block + write-setup h# 80 jedec! + write-setup h# 30 swap >lpc-adr c! + wait-toggle +; : erase-block ( offset -- ) dup write-enable-block write-setup h# 80 jedec! write-setup h# 50 swap >lpc-adr c! + wait-toggle +; +: erase-chip ( -- ) + write-setup h# 80 jedec! + write-setup h# 10 jedec! wait-toggle ;
@@ -78,6 +134,7 @@ dup erase-block ( adr len offset ) flash-write ; +: block-size ( -- u ) /block ;
\ LICENSE_BEGIN \ Copyright (c) 2008 FirmWorks