FIXED! It only took 3 years ....

This commit is contained in:
Ronald G. Minnich 2003-05-19 13:53:07 +00:00
parent 4ddbdc1f98
commit 6280975dbf
2 changed files with 395 additions and 129 deletions

View file

@ -4,22 +4,164 @@
#include <pci.h>
#include <pciconf.h>
/*
* Automatic memory configuration by SONE Takeshi <ts1@tsn.or.jp>, 05/19/03
*/
static unsigned long find_size(unsigned long addr, unsigned long minimum)
{
unsigned long i;
unsigned long maximum;
volatile long *p;
/* First, see if there is any RAM. */
p = (long *) (addr + minimum);
*p = 0x12345678;
p = (long *) (addr + minimum + 8);
*p = 0x87654321;
p = (long *) (addr + minimum);
if (*p != 0x12345678)
return 0; /* No memory */
maximum = (0xffUL << 23) - addr;
/* Write to addresses with only one address bit on,
* in increasing order, from address 8 (assuming 64-bit bus),
* then read address zero to see if it gets wrap-around.
* This way we can detect missing address bit due to incorrect
* MA mapping, or the size of bank when MA mapping is correct. */
for (i = 8; i < maximum; i <<= 1) {
if (i < minimum)
continue;
p = (long *) (addr + i);
*p = 0x89abcdef;
p = (long *) addr;
if (*p == 0x89abcdef)
return i;
}
return maximum;
}
static void set_ma_mapping(struct pci_dev *pcidev, int bank, int type)
{
unsigned char reg, val;
int shift;
reg = 0x58 + bank/4;
if (bank%4 >= 2)
shift = 0;
else
shift = 4;
pci_read_config_byte(pcidev, reg, &val);
val &= ~(0xf << shift);
val |= type << shift;
pci_write_config_byte(pcidev, reg, val);
}
static int get_ma_mapping(struct pci_dev *pcidev, int bank)
{
unsigned char reg, val;
int shift;
reg = 0x58 + bank/4;
if (bank%4 >= 2)
shift = 0;
else
shift = 4;
pci_read_config_byte(pcidev, reg, &val);
return (val >> shift) & 0xf;
}
static unsigned long __sizeram(void)
{
unsigned long totalmem;
unsigned char bank, mem, prevmem;
u8 sma_status, sma_size, sma_size_bits;
// fixed so tha banks 56 & 57 are looked at as well.
unsigned long firstbank = 0x5a, lastbank = 0x61;
u8 sma_status, sma_size_bits;
struct pci_dev *pcidev;
unsigned long memtop, highest, size, sma_size;
int bank, i;
static const unsigned char ma_table[] = {0, 8, 0xe};
unsigned char ma_tmp, val;
extern void cache_enable(void), cache_disable(void);
pcidev = pci_find_slot(0, PCI_DEVFN(0,0));
if (! pcidev)
return 0;
/* In assembly part, we have initialized all RAM chips,
* brought the first equipped RAM bank to address zero,
* and set correct MA mapping type of that bank.
* Now, we have to detect the size of the first bank,
* then configure rest of banks. */
/* Cache must be disabled to detect the RAM. */
cache_disable();
/* Find the first bank configured by assembly part. */
for (bank = 0; bank < 6; bank++) {
pci_read_config_byte(pcidev, 0x5a + bank, &val);
if (val != 0)
break;
}
memtop = find_size(0, 1024*1024);
memtop &= ~0x7fffff; /* Unit of 8MB */
printk_info("Bank%d %dMB (MA type 0x%x)\n", bank,
memtop>>20, get_ma_mapping(pcidev, bank));
pci_write_config_byte(pcidev, 0x5a + bank, memtop>>23);
for (bank++; bank < 6; bank++) {
if (bank & 1) {
/* We don't change MA mapping of this bank
* since it is shared with the previous bank.
* Most possibly this is the other side of a
* double-sided DIMM. */
size = find_size(memtop, 0);
size &= ~0x7fffff;
if (size) {
printk_info("Bank%d %dMB\n", bank, size>>20);
memtop += size;
}
} else {
/* Try MA mapping types and find the one which gives
* highest address without wrap-around.
* It should be the correct mapping for the DIMM,
* and the returned address is the size of the DIMM. */
highest = 0;
ma_tmp = 0;
for (i = 0; i < sizeof(ma_table)/sizeof(ma_table[0]); i++) {
set_ma_mapping(pcidev, bank, ma_table[i]);
size = find_size(memtop, 0);
printk_debug("bank %d MA 0x%x: %d bytes\n",
bank, ma_table[i], size);
if (size > highest) {
highest = size;
ma_tmp = ma_table[i];
}
}
highest &= ~0x7fffff;
if (highest) {
printk_info("Bank%d %dMB (MA type 0x%x)\n",
bank, highest>>20, ma_tmp);
memtop += highest;
}
set_ma_mapping(pcidev, bank, ma_tmp);
}
pci_write_config_byte(pcidev, 0x5a + bank, memtop>>23);
}
/* As well as 6 bank registers above, it seems we have to fill
* these 2 registers. */
pci_write_config_byte(pcidev, 0x56, memtop>>23);
pci_write_config_byte(pcidev, 0x57, memtop>>23);
cache_enable();
/* Frame buffer size */
// Documentation on VT8601 - Pg 51 Rev 1.3 Sept 1999 says
// Device 0 Offset FB - Frame buffer control
// bit
@ -35,41 +177,31 @@ static unsigned long __sizeram(void)
pci_read_config_byte(pcidev, 0xfb, &sma_status);
sma_size_bits = (sma_status >> 4) & 0x03;
if (sma_size_bits > 0)
sma_size = 0x01 << sma_size_bits;
sma_size = (1024*1024) << sma_size_bits;
else
sma_size = 0;
for(totalmem = mem = prevmem = 0, bank = firstbank;
bank <= lastbank; bank++) {
// last 2 banks are in regs before first bank so
// wrap round if > 0x5f
unsigned long rbank = (bank > 0x5f) ? bank - 10 : bank;
printk_info("Total %dMB + frame buffer %dMB\n",
(memtop - sma_size)>>20, sma_size>>20);
pci_read_config_byte(pcidev, rbank, &mem);
/* Turn on shadow DRAM at 0xC0000-0xFFFFF so we can write
* PIRQ table, VGA BIOS, Bochs BIOS, etc. */
printk_debug("Enabling shadow DRAM at 0xC0000-0xFFFFF: ");
pci_write_config_byte(pcidev, 0x61, 0xff);
pci_write_config_byte(pcidev, 0x62, 0xff);
pci_write_config_byte(pcidev, 0x63, 0xf0);
printk_debug("done\n");
// sanity check. If the mem value is < prevmem,
// that is an error, so skip this step.
if (mem < prevmem) {
printk_err("ERROR: bank 0x%x, mem 0x%x TOO SMALL\n",
rbank, prevmem);
printk_err("Should be >= 0x%x\n", prevmem);
} else
totalmem += (mem - prevmem) * 8;
prevmem = mem;
}
totalmem -= sma_size;
totalmem *= 1024;
return totalmem;
return (memtop - sma_size) >> 10; // return in kilo bytes
}
struct mem_range *sizeram(void)
{
static struct mem_range mem[3];
mem[0].basek = 0;
mem[0].sizek = 640;
mem[1].basek = 1024;
mem[1].basek = 768;
mem[1].sizek = __sizeram();
mem[2].basek = 0;
mem[2].sizek = 0;
@ -77,19 +209,27 @@ struct mem_range *sizeram(void)
mem[1].sizek = 64*1024;
}
mem[1].sizek -= mem[1].basek;
return &mem;
return mem;
}
#ifdef HAVE_FRAMEBUFFER
void framebuffer_on()
{
#if 0 /* This code has not been working (always reads 0xffff)
* and I still can bring up VGA (with original VGA BIOS under ADLO)
* after disabling this. -- ts1 */
unsigned long devfn;
u16 command;
devfn = PCI_DEVFN(0, 1);
pcibios_read_config_word(0, devfn, 0x3e, &command);
command |= 0x08;
//command |= 0x08;
command |= 0x0c;
pcibios_write_config_word(0, devfn, 0x3e, command);
printk_debug("wrote %02x\n", command);
pcibios_read_config_word(0, devfn, 0x3e, &command);
printk_debug("readback %02x\n", command);
#endif
}
#endif

View file

@ -25,52 +25,92 @@ it with the version available from LANL.
* correctly - at least on my VIA epia motherboard. 64MB DIMM in slot 0.
*/
#define loop200 $0x5000
#define loop100 $0x2500
/* Added automatic detection of first equipped bank and its MA mapping type.
* (Rest of configuration is done in C)
* 5/19/03 by SONE Takeshi <ts1@tsn.or.jp>
*/
// Set to 1 if your DIMMs are PC133
// Note that I'm assuming CPU's FSB frequency is 133MHz. If your CPU runs
// at another bus speed, you might need to change some of register values.
#ifndef DIMM_PC133
#define DIMM_PC133 0
#endif
// Set to 1 if your DIMMs are CL=2
#ifndef DIMM_CL2
#define DIMM_CL2 0
#endif
/* Stable ~1 usec delay by hitting unused ISA port. */
#define UDELAY(x) movl $x,%ecx; 9: outb %al,$0x81; loop 9b
#define DIMMS_READ(x) \
movl 0x00000000+x, %eax; \
movl 0x10000000+x, %eax; \
movl 0x20000000+x, %eax; \
movl 0x30000000+x, %eax; \
movl 0x40000000+x, %eax; \
movl 0x50000000+x, %eax
#define DIMMS_WRITE(x) \
movl %eax, 0x00000000+x; \
movl %eax, 0x10000000+x; \
movl %eax, 0x20000000+x; \
movl %eax, 0x30000000+x; \
movl %eax, 0x40000000+x; \
movl %eax, 0x50000000+x
raminit:
intel_chip_post_macro(0x35)
/*; new code... pulled from via stuff.*/
/* initialize registers */
// memory clk enable. We are not using ECC
CS_WRITE($0x78, $0x01)
// dram control, see the book.
CS_WRITE($0x68, $0x42)
#if DIMM_PC133
CS_WRITE($0x68, $0x52)
#else
CS_WRITE($0x68, $0x42)
#endif
// dram control, see the book.
CS_WRITE($0x6B, $0x0d)
// 64/128 MB dram
CS_WRITE($0x58, $0x80)
// 64/128 MB dram
CS_WRITE($0x59, $0x00)
// bank 0 ends at 64 MB
CS_WRITE($0x5A, $0x08)
// bank 1 ends at 64 MB
CS_WRITE($0x5B, $0x08)
// bank 2 ends at 64 MB
CS_WRITE($0x5C, $0x08)
// bank 2 ends at 64 MB
CS_WRITE($0x5D, $0x08)
// bank 2 ends at 64 MB
CS_WRITE($0x5E, $0x08)
// bank 2 ends at 64 MB
CS_WRITE($0x5F, $0x08)
CS_WRITE($0x6B, $0x0c)
// Initial setting, 256MB in each bank, will be rewritten later.
CS_WRITE($0x5A, $0x20)
CS_WRITE($0x5B, $0x40)
CS_WRITE($0x5C, $0x60)
CS_WRITE($0x5D, $0x80)
CS_WRITE($0x5E, $0xA0)
CS_WRITE($0x5F, $0xC0)
// It seems we have to take care of these 2 registers as if
// they are bank 6 and 7.
CS_WRITE($0x56, $0xC0)
CS_WRITE($0x57, $0xC0)
// SDRAM in all banks
CS_WRITE($0x60, $0x3F)
// DRAM timing. I'm suspicious of this
// This is for all banks, 64 is 0,1. 65 is 2,3. 66 is 4,5.
// ras precharge 4T, RAS pulse 5T, CAS 2T
// as per the note below, we change to cas 3 2000/8/31
// ras precharge 4T, RAS pulse 5T
// cas2 is 0xd6, cas3 is 0xe6
// we're also backing off write pulse width to 2T, so result is 0xee
CS_WRITE($0x64, $0xe6)
CS_WRITE($0x65, $0x95)
CS_WRITE($0x66, $0x95)
#if DIMM_CL2
CS_WRITE($0x64, $0xd4)
CS_WRITE($0x65, $0xd4)
CS_WRITE($0x66, $0xd4)
#else // CL=3
CS_WRITE($0x64, $0xe4)
CS_WRITE($0x65, $0xe4)
CS_WRITE($0x66, $0xe4)
#endif
// dram frequency select. We set 66/66.
// no 256 m, enable 4K pages for 64M dram.
CS_WRITE($0x69, $0xac)
// dram frequency select.
// enable 4K pages for 64M dram.
#if DIMM_PC133
CS_WRITE($0x69, $0x3c)
#else
CS_WRITE($0x69, $0xac)
#endif
// refresh counter, disabled.
CS_WRITE($0x6A, $0x00)
// clkenable configuration. kevinh FIXME - add precharge
@ -80,102 +120,188 @@ raminit:
// As per Cindy Lee, set to 0x37, not 0x57
CS_WRITE($0x6D, $0x7f)
/* Initialize all banks at once */
/* begin to initialize*/
// I forget why we need this, but we do
mov $0xa55a5aa5, %eax
mov %eax, 0
mov %eax, 0x4000000
DIMMS_WRITE(0)
/* set NOP*/
CS_WRITE($0x6C, $0x01)
/* wait 200us*/
// You need to do the memory reference. That causes the nop cycle.
mov 0x0, %eax
mov 0x4000000, %eax
DELAY(loop200)
DIMMS_READ(0)
UDELAY(400)
/* set precharge */
CS_WRITE($0x6C, $0x02)
/* dummy reads*/
mov 0x0, %eax
mov 0x4000000, %eax
DIMMS_READ(0)
UDELAY(200)
/* set CBR*/
CS_WRITE($0x6C, $0x04)
/* do 8 reads and wait 100us between each - from via*/
mov 0x0, %eax
mov 0x4000000, %eax
DELAY(loop100)
mov 0x0, %eax
mov 0x4000000, %eax
DELAY(loop100)
mov 0x0, %eax
mov 0x4000000, %eax
DELAY(loop100)
mov 0x0, %eax
mov 0x4000000, %eax
DELAY(loop100)
mov 0x0, %eax
mov 0x4000000, %eax
DELAY(loop100)
mov 0x0, %eax
mov 0x4000000, %eax
DELAY(loop100)
mov 0x0, %eax
mov 0x4000000, %eax
DELAY(loop100)
mov 0x0, %eax
mov 0x4000000, %eax
DELAY(loop100)
/* do 8 reads and wait >100us between each - from via*/
DIMMS_READ(0)
UDELAY(200)
DIMMS_READ(0)
UDELAY(200)
DIMMS_READ(0)
UDELAY(200)
DIMMS_READ(0)
UDELAY(200)
DIMMS_READ(0)
UDELAY(200)
DIMMS_READ(0)
UDELAY(200)
DIMMS_READ(0)
UDELAY(200)
DIMMS_READ(0)
UDELAY(200)
/* set MRS*/
// 0x150 is cas2. We are now using 0x1d0, which is cas3
CS_WRITE($0x6c, $0x03)
movl $0x1d0, %ecx
movl (%ecx), %eax
movl $0x40001d0, %ecx
movl (%ecx), %eax
#if DIMM_CL2
DIMMS_READ(0x150)
#else // CL=3
DIMMS_READ(0x1d0)
#endif
UDELAY(200)
/* set to normal mode */
CS_WRITE($0x6C, $0x08)
movl $0x55aa55aa, %eax
mov %eax, 0x0
mov 0x0, %eax
DIMMS_WRITE(0)
DIMMS_READ(0)
UDELAY(200)
// Set the refresh rate.
#if DIMM_PC133
CS_WRITE($0x6A, $0x86)
#else
CS_WRITE($0x6A, $0x65)
#endif
// enable multi-page open
CS_WRITE($0x6B, $0x01)
CS_WRITE($0x6B, $0x0d)
/* From Mike Fan:
Hi all:
If you are porting PM133, then you have to set DRAM Row Ending Address.
You did not set Rx56 and Rx57 in intel_pm133ram.S.
That register setting is like Rx5A~Rx5F.
Maybe could fix the mem wrapping issue.
(from Ron Minnich)
My manual says these are non-cacheable region registers.
(Turns out the manual is wrong. However, this did not help.
2000/8/31 8:49 am I am setting all dram to cas3, and if that fails,
I'll be trying some of Cindy's other recommendations.
DRAM is currently CAS2. Symptom is an explosion in free_all_bootmem_core,
In the loop where it is freeing bootmem alloc pages from low mem.
2000/8/31: 10:57 No change, Linux still crashes. We'll try Cindy Lee's recommendation
RE Register 0x6d, set it to 0x37. All our other settings conform to her
other recommendations. We also need to see whether we should be setting
Fixed MTRRs, but that seems unlikely.
2000/8/31: 5:56 PM. No significant change. We're going to try to use 1 cycle writes
instead of 2. None of this feels like it is the real problem. Fixed MTRRs
helped a tiny bit. We can get to schedule() before we crash, but only
if we set a breakpoint after the first loop in free_all_bootmem_core
*/
CS_WRITE($0x56, $0x10)
CS_WRITE($0x57, $0x10)
/* Begin auto-detection
* Find the first bank with DIMM equipped. */
/* Maximum possible memory in bank 0, none in other banks.
* Starting from bank 0, we's fill 0 in these registers
* until memory is found. */
CS_WRITE($0x5A, $0xff)
CS_WRITE($0x5B, $0xff)
CS_WRITE($0x5C, $0xff)
CS_WRITE($0x5D, $0xff)
CS_WRITE($0x5E, $0xff)
CS_WRITE($0x5F, $0xff)
CS_WRITE($0x56, $0xff)
CS_WRITE($0x57, $0xff)
movl $0x5A, %ebx // first bank
1:
/* Write different values to 0 and 8, then read from 0.
* If values of address 0 match, we have something there. */
movl $0x12345678, %eax
movl %eax, 0
movl $0x87654321, %edx
movl %edx, 8
movl 0, %edx
cmpl %eax, %edx
je 2f
/* No memory in this bank. Tell it to the bridge. */
movl %ebx, %eax
xorl %edx, %edx
PCI_WRITE_CONFIG_BYTE
incl %ebx
cmpl $0x60, %ebx
jne 1b
/* No memory at all! */
CONSOLE_EMERG_TX_STRING($msg_nomem)
1:
hlt
jmp 1b
2:
/* Detect MA mapping type of the first bank. */
jmp raminit_ma
raminit_ma_reg_table:
/* Values for MA type register to try */
.word 0x0000, 0x8088, 0xe0ee
.word 0xffff // end mark
raminit_ma:
xorl %esi, %esi // highest address
movl $raminit_ma_reg_table, %ebx
1:
movw (%ebx), %cx
cmpw $0xffff, %cx
je raminit_ma_done
movl $0x58, %eax
PCI_WRITE_CONFIG_WORD
xorl %eax, %eax
movl %eax, (%eax)
// Write to addresses with only one address bit on,
// from 0x80000000 to 0x00000008 (lower 3 bits are ignored, assuming
// 64-bit bus).
// Then what is read at address 0 is the value written to the lowest
// address where it gets wrap-around. That address is either the size
// of the bank, or a missing bit due to incorrect MA mapping.
movl $0x80000000, %eax
2:
movl %eax, (%eax)
shrl $1, %eax
cmpl $4, %eax
jne 2b
movl 0, %eax
cmpl %eax, %esi
jnc 3f
// This is the current best MA mapping.
// Save the address and its MA mapping value.
movl %eax, %esi
movl %ecx, %edi
3:
incl %ebx
incl %ebx
jmp 1b
raminit_ma_done:
// Set the best (hopefully correct) MA mapping type.
movl $0x58, %eax
movl %edi, %ecx
PCI_WRITE_CONFIG_WORD
CONSOLE_DEBUG_TX_STRING($msg_enabled)
CONSOLE_DEBUG_TX_HEX32(%esi)
CONSOLE_DEBUG_TX_STRING($msg_bytes)
/*
* We have the size of first bank in %esi, but throwing it away.
* Sizing will again be done in C, because we'll configure the rest
* of banks in there anyway.
*/
//CALLSP(dumpnorth)
intel_chip_post_macro(0x36)
.section ".rom.data"
msg_nomem:
.asciz "No memory\r\n"
msg_enabled:
.asciz "Enabled first bank of RAM: 0x"
msg_bytes:
.asciz " bytes\r\n"
.previous