Author: wmb
Date: 2008-08-29 11:22:06 +0200 (Fri, 29 Aug 2008)
New Revision: 906
Modified:
cpu/x86/pc/neptune/addrs.fth
cpu/x86/pc/neptune/config.fth
cpu/x86/pc/neptune/romreset.bth
Log:
Neptune - memory autoconfiguration.
Modified: cpu/x86/pc/neptune/addrs.fth
===================================================================
--- cpu/x86/pc/neptune/addrs.fth 2008-08-29 09:21:31 UTC (rev 905)
+++ cpu/x86/pc/neptune/addrs.fth 2008-08-29 09:22:06 UTC (rev 906)
@@ -38,6 +38,8 @@
h# f.0008 constant resume-entry
h# f.0800 constant resume-data
+h# 80.0000 constant fb-size
+
\ If you change these, also change {g/l}xmsrs.fth and {g/l}xearly.fth
h# fd00.0000 constant fw-map-base
h# ffc0.0000 constant fw-map-limit
Modified: cpu/x86/pc/neptune/config.fth
===================================================================
--- cpu/x86/pc/neptune/config.fth 2008-08-29 09:21:31 UTC (rev 905)
+++ cpu/x86/pc/neptune/config.fth 2008-08-29 09:22:06 UTC (rev 906)
@@ -34,6 +34,7 @@
create use-elf
create lx-pll-autoconfig \ enable pll autoconfiguration from bootstrap pin
+create mem-autoconfig \ autoconfigure different memory sizes
create use-memtest86
\ create use-timestamp-counter \ Use CPU's timestamp counter for timing ...
Modified: cpu/x86/pc/neptune/romreset.bth
===================================================================
--- cpu/x86/pc/neptune/romreset.bth 2008-08-29 09:21:31 UTC (rev 905)
+++ cpu/x86/pc/neptune/romreset.bth 2008-08-29 09:22:06 UTC (rev 906)
@@ -46,7 +46,79 @@
fload ${BP}/cpu/x86/pc/romfind.fth \ find-dropin
+label dramtry
+ char b 3f8 port-wb begin 3fd port-rb 40 bitand 0<> until
+ h# 12 # al mov al h# 80 # out
+
+ \ Unmask CKE1 and CKE0
+ 1000. 2000001d set-msr \ MC_CFCLK_DBG Clear 300 bits, don't tristate in IDLE
+
+ \ Reset memory controller
+ 20000018 rmsr \ MC_CF07_DATA
+ 2 bitset 20000018 wmsr
+ 2 bitclr 20000018 wmsr
+
+ \ Enable DLL, load Extended Mode Register by set and clear PROG_DRAM
+ 10000001 bitset 20000018 wmsr
+ 10000001 bitclr 20000018 wmsr
+
+ \ Reset DLL (bit 27 is undocumented in GX datasheet, but is in the LX one)
+ 08000001 bitset 20000018 wmsr
+ 08000001 bitclr 20000018 wmsr
+
+ \ Here we are supposed to wait 200 SDCLK cycles to let the DLL settle.
+ \ That is approximately 2 uS. The ROM instruction access is so slow that
+ \ anything we do will take quite a bit longer than that, so we just let the
+ \ "rmsr, bitset" sequence take care of the time delay for us.
+
+ \ In the following sequence of writes the 2000.0018 MSR, we
+ \ take advantage of the fact that the existing value stays
+ \ in EAX/EDX, so we don't have to re-read the value.
+
+ \ Generate 2 refresh requests. The refresh queue is 8 deep, and we
+ \ need to make sure 2 refreshes hit the chips, so we have to issue
+ \ 10 requests to the queue. According to the GX datasheet, we don't
+ \ have to clear the REF_TST bit (8) explicitly between writes
+ 20000018 rmsr 8 bitset
+ wrmsr wrmsr wrmsr wrmsr wrmsr wrmsr wrmsr wrmsr wrmsr wrmsr
+ 8 bitclr
+
+ \ Load Mode Register
+ 1 bitset 20000018 wmsr
+ 1 bitclr 20000018 wmsr
+
+ \ Earlier code has set up an MSR so the fxxxx address range hits memory
+
+ \ The RAM DLL needs a write to lock on
+ ax h# ffff0 #) mov
+
+ \ The following simple test determines how much memory is present.
+
+ \ Set locations just below power-of-two boundaries to the boundary value
+ h# 4000.0000 # si mov \ Start address
+ h# 400.0000 # di mov \ End address
+ si ax mov
+ begin
+ ax -4 [ax] mov \ Set e.g. loc 3ffffffc to 40000000
+ 1 # ax shr \ Step down to the next power of two
+ di ax cmp \ Stop at 64 MiB; can't buy RAMs that small
+ <= until
+
+ \ Look for a location that contains the expected data
+ si ax mov
+ begin
+ -4 [ax] bx mov
+ bx ax cmp = if esp jmp then \ Exit if found
+ 1 # ax shr
+ di ax cmp
+ <= until
+
+ \ Not found, return 0
+ ax ax xor
+ esp jmp
+
label startup
+ long-offsets on
h# 10 # al mov al h# 80 # out
\ The next few MSRs allow us to access the 5536
@@ -102,6 +174,208 @@
\ sdram_initialize,generic_sdram.c
\ sdram_set_spdregisters(),auto.c
+[ifdef] mem-autoconfig
+ 20000000.000fff00. 10000020 set-msr \ memory - 0..fffff
+
+ \ We start with address map settings for the largest possible memory configuration,
+ \ probe and test the memory, then reduce the values as necessary
+ \ We'll deal with DMA and the frame buffer after memory has been sized.
+
+ 25ffe002.14000000. 1808 set-msr \ 2M ROM at ffe0.0000, system RAM limit at 4000.0000
+ 2000003f.fff00100. 10000028 set-msr \ Top of memory at 3fff.ffff
+
+ 00000000.2814d352. 00001981 set-msr \ Memory delay values
+ 00000000.1068334d. 00001982 set-msr \ Memory delay values
+ 00000106.83104104. 00001983 set-msr \ Memory delay values
+ 00000000.00000001. 00001980 set-msr \ Enable memory delays
+
+ \ Init the SDRAMs
+ \ sdram_enable,src/northbridge/amd/gx2/raminit.c
+
+ \ Clock gating for PMode
+ \ Clocks always on in mode 1, hardware gating in mode 0
+\ 20002004 rmsr 4 bitclr 1 bitset 20002004 wmsr \ GX p 199
+ 1. 20002004 set-msr \ GX p 199
+
+ 00000200.00000000. 20000020 set-msr \ Power mode entry and exit delays
+
+[ifdef] support-1g-drams
+ \ Try 1-Gbit chip, 1 GiB total config
+
+ 1300. 2000001d set-msr \ Mask CKE1,0 while setting new config
+ 10078113.00005040. 20000018 set-msr \ DIMM1 off, DIMM0 1024 MB, 2 module banks, 8K pages
+ 18000100.364221a3. 20000019 set-msr
+ 140dd101. 2000001a set-msr \ MC_CF1017_DATA LX p 231
+
+ here d# 10 + asm-base - ResetBase + # esp mov \ Return address (no stack)
+ dramtry #) jmp h# 4000.0000 # ax cmp 1 F: je
+
+ \ Try 1-Gbit chip, 512 MiB total config
+
+ 1300. 2000001d set-msr \ Mask CKE1,0 while setting new config
+ 10077013.00005040. 20000018 set-msr \ DIMM1 off, DIMM0 512 MB, 1 module bank, 8K pages
+ 18000100.364221a3. 20000019 set-msr
+ 140dd101. 2000001a set-msr \ MC_CF1017_DATA LX p 231
+
+ here d# 10 + asm-base - ResetBase + # esp mov \ Return address (no stack)
+ dramtry #) jmp h# 2000.0000 # ax cmp 1 F: je
+[then]
+
+ \ Try 512-Mbit chip, 512 MiB total config
+
+ 1300. 2000001d set-msr \ Mask CKE1,0 while setting new config
+ 10077113.00005040. 20000018 set-msr \ DIMM1 off, DIMM0 512 MB, 2 module banks, 8K pages
+ 18000100.364221a3. 20000019 set-msr
+ 140dd101. 2000001a set-msr \ MC_CF1017_DATA LX p 231
+ here d# 10 + asm-base - ResetBase + # esp mov \ Return address (no stack)
+ dramtry #) jmp h# 2000.0000 # ax cmp 1 F: je
+
+
+ \ Try 512-Mbit chip, 256 MiB total config
+ 1300. 2000001d set-msr \ Mask CKE1,0 while setting new config
+ 10076013.00005040. 20000018 set-msr \ DIMM1 off, DIMM0 256 MB, 1 module bank, 8K pages
+ 18000100.364221a3. 20000019 set-msr
+ 140dd101. 2000001a set-msr \ MC_CF1017_DATA LX p 231
+
+ here d# 10 + asm-base - ResetBase + # esp mov \ Return address (no stack)
+ dramtry #) jmp h# 1000.0000 # ax cmp 1 F: je
+
+
+ \ Can't find a working RAM configuration - emit a message and POST code
+ char * 3f8 port-wb begin 3fd port-rb 40 bitand 0<> until
+ char R 3f8 port-wb begin 3fd port-rb 40 bitand 0<> until
+ char A 3f8 port-wb begin 3fd port-rb 40 bitand 0<> until
+ char M 3f8 port-wb begin 3fd port-rb 40 bitand 0<> until
+ char * 3f8 port-wb begin 3fd port-rb 40 bitand 0<> until
+ h# 1e # al mov al h# 80 # out
+ begin hlt again
+
+1 L: \ DRAM is okay; size in EAX
+ ax bp mov \ Move DRAM size to EBP so we can use EAX for MSR ops
+ fb-size # bp sub \ Subtract off frame buffer size
+
+ \ Shrink system RAM limit in RCONF_DEFAULT MSR
+ 00001808 rmsr
+ bp ax mov 4 # ax shr \ Move DRAM size to SYSTOP field
+ h# 1000.0000 # ax or \ Set DEVRP (high nibble) and SYSRP (low byte)
+ 00001808 wmsr
+
+ \ Map frame buffer (see page 83 of LX manual)
+ \ This is tricky because we have to compute several field values and distribute
+ \ them across two registers.
+
+ bp dx mov \ EDX: Frame buffer address in RAM array
+ fb-pci-base # bx mov \ EBX: Frame buffer address in CPU address space
+ bx dx sub \ EDX: Offset from FB CPU address to RAM array address
+ d# 4 # dx shr \ Move offset to OFFSET field of P2D_RO high word
+ h# 2000.0000 # dx or \ Merge in PDID1 field
+
+ bx ax mov \ EAX: Frame buffer CPU address
+ fb-size # ax add \ EAX: Frame buffer limit
+ h# 1000 # ax sub \ EAX: Frame buffer top page
+ ax si mov \ Save a copy in ESI
+ d# 24 # ax shr \ Top 8 bits of frame buffer top page to PMAX field
+ ax dx or \ EDX: completed high word of MSR value EAX: dead
+
+ bx ax mov \ EAX: Frame buffer CPU address
+ d# 12 # ax shr \ Move to PMIN field
+ d# 8 # si shl \ Move low bits of frame buffer limit to PMAX low
+ si ax add \ EAX: completed high word of MSR value ESI: dead EBX: dead
+ 10000029 wmsr \ P2D_RO0 - Frame buffer at PA fd00.0000 maps to RAM at 0f80.0000
+
+ \ The remaining fields use the top page instead of the limit
+ h# 1000 # bp sub \ EBP: RAM top page address
+
+ \ Set above-1M memory address map - P2D_R descriptors
+ bp dx mov d# 24 # dx shr \ Top 8 bits to PMAX field in high word
+ bp ax mov d# 8 # ax shl \ Low bits to PMAX field in low word
+ h# 2000.0000 # dx or \ Merge in PDID1 field
+ h# 0000.0100 # ax or \ Merge in PMIN field (1 MiB)
+ 10000028 wmsr \ Write P2D_R descriptor for GLIU0 (outgoing)
+ 4000002c wmsr \ Write P2D_R descriptor for GLIU1 (incoming)
+
+ \ Set PCI DMA to memory descriptor to map incoming DMA from 1M to RAM limit
+ bp dx mov \ TOP field in high word
+ h# 00100130 # ax mov \ BASE field (1 MiB), EN (100), PF(20), WC(10)
+ 50002019 wmsr \ Write GLPCI_R1 MSR
+
+\ This is the tail of ${BP}/dev/geode/draminit.fth
+
+ h# 19 # al mov al h# 80 # out
+ h# 1430 # dx mov dx ax in h# 9999 # ax cmp = if
+ h# 34 # al mov al h# 70 # out \ Write to CMOS 0x34
+ h# 19 # al mov al h# 71 # out \ Write value 01
+ then
+
+ \ Turn on the cache
+ cr0 ax mov
+ 6000.0000 bitclr \ Cache-disable off, coherent
+ ax cr0 mov
+ invd
+
+ h# 1a # al mov al h# 80 # out
+ h# 1430 # dx mov dx ax in h# 9999 # ax cmp = if
+ h# 34 # al mov al h# 70 # out \ Write to CMOS 0x34
+ h# 1a # al mov al h# 71 # out \ Write value 01
+ then
+
+ 0000f001.00001400. 5140000f set-msr \ PMS BAR
+
+ \ It is tempting to test bit 0 of PM register 5c, but a 5536 erratum
+ \ prevents that bit from working. Bit 1 works, but LX errata 34
+ \ sometimes requires that we reset the system to fix the memory DLL,
+ \ which destroys all the bits of PM register 5c. So we put a breadcrumb
+ \ in a PM register that we don't otherwise use.
+ 1430 port-rl h# 9999 # ax cmp = if \ Wakeup event flag
+ 0 1430 port-wl
+ h# 1b # al mov al h# 80 # out
+ h# 34 # al mov al h# 70 # out \ Write to CMOS 0x34
+ h# 1b # al mov al h# 71 # out \ Write value 01
+
+ char r 3f8 port-wb begin 3fd port-rb 40 bitand 0<> until
+
+ resume-data # sp mov
+ resume-entry # ax mov ax call \ This might return if checksumming fails
+ char x 3f8 port-wb begin 3fd port-rb 40 bitand 0<> until
+ then
+
+ h# 1c # al mov al h# 80 # out
+ h# 1808 rmsr \ Default region configuration properties MSR
+ h# 0fffff00 # ax and \ Top of System Memory field
+ 4 # ax shl \ Shift into place
+ ax mem-info-pa 4 + #) mov \ Put it where resetend.fth can find it
+
+ \ char D 3f8 port-wb begin 3fd port-rb 40 bitand 0<> until
+
+ \ Memory is now on
+ h# 8.0000 # sp mov \ Setup a stack pointer for later code
+
+ h# 1d # al mov al h# 80 # out
+\ Some optional debugging stuff ...
+[ifdef] debug-startup
+init-com1
+
+carret report
+linefeed report
+ascii F report
+ascii o report
+ascii r report
+[then]
+
+\ fload ${BP}/cpu/x86/pc/ramtest.fth
+
+0 [if]
+ax ax xor
+h# 12345678 # bx mov
+bx 0 [ax] mov
+h# 5555aaaa # 4 [ax] mov
+0 [ax] dx mov
+dx bx cmp <> if ascii B report ascii A report ascii D report begin again then
+[then]
+
+[else]
+ \ This is the single-configuration DRAM startup code
+
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
@@ -150,6 +424,7 @@
fload ${BP}/dev/geode/draminit.fth
+[then]
\ Last-minute check for LX erratum 34 - reset if the DLL didn't start correctly
h# 4c000017 rmsr h# 10 bitand 0<> if \ LX branch
h# 4c00000f rmsr h# 7ff bitclr h# 4 bitset h# 4c00000f wmsr \ Set DLL_OV