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
openfirmware@openfirmware.info