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