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 <pci.h>
#include <pciconf.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) static unsigned long __sizeram(void)
{ {
unsigned long totalmem; u8 sma_status, sma_size_bits;
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;
struct pci_dev *pcidev; 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)); pcidev = pci_find_slot(0, PCI_DEVFN(0,0));
if (! pcidev) if (! pcidev)
return 0; 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 // Documentation on VT8601 - Pg 51 Rev 1.3 Sept 1999 says
// Device 0 Offset FB - Frame buffer control // Device 0 Offset FB - Frame buffer control
// bit // bit
@ -35,41 +177,31 @@ static unsigned long __sizeram(void)
pci_read_config_byte(pcidev, 0xfb, &sma_status); pci_read_config_byte(pcidev, 0xfb, &sma_status);
sma_size_bits = (sma_status >> 4) & 0x03; sma_size_bits = (sma_status >> 4) & 0x03;
if (sma_size_bits > 0) if (sma_size_bits > 0)
sma_size = 0x01 << sma_size_bits; sma_size = (1024*1024) << sma_size_bits;
else else
sma_size = 0; sma_size = 0;
for(totalmem = mem = prevmem = 0, bank = firstbank; printk_info("Total %dMB + frame buffer %dMB\n",
bank <= lastbank; bank++) { (memtop - sma_size)>>20, sma_size>>20);
// last 2 banks are in regs before first bank so
// wrap round if > 0x5f
unsigned long rbank = (bank > 0x5f) ? bank - 10 : bank;
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, return (memtop - sma_size) >> 10; // return in kilo bytes
// 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;
} }
struct mem_range *sizeram(void) struct mem_range *sizeram(void)
{ {
static struct mem_range mem[3]; static struct mem_range mem[3];
mem[0].basek = 0; mem[0].basek = 0;
mem[0].sizek = 640; mem[0].sizek = 640;
mem[1].basek = 1024; mem[1].basek = 768;
mem[1].sizek = __sizeram(); mem[1].sizek = __sizeram();
mem[2].basek = 0; mem[2].basek = 0;
mem[2].sizek = 0; mem[2].sizek = 0;
@ -77,19 +209,27 @@ struct mem_range *sizeram(void)
mem[1].sizek = 64*1024; mem[1].sizek = 64*1024;
} }
mem[1].sizek -= mem[1].basek; mem[1].sizek -= mem[1].basek;
return &mem; return mem;
} }
#ifdef HAVE_FRAMEBUFFER #ifdef HAVE_FRAMEBUFFER
void framebuffer_on() 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; unsigned long devfn;
u16 command; u16 command;
devfn = PCI_DEVFN(0, 1); devfn = PCI_DEVFN(0, 1);
pcibios_read_config_word(0, devfn, 0x3e, &command); pcibios_read_config_word(0, devfn, 0x3e, &command);
command |= 0x08; //command |= 0x08;
command |= 0x0c;
pcibios_write_config_word(0, devfn, 0x3e, command); 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 #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. * correctly - at least on my VIA epia motherboard. 64MB DIMM in slot 0.
*/ */
#define loop200 $0x5000 /* Added automatic detection of first equipped bank and its MA mapping type.
#define loop100 $0x2500 * (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: raminit:
intel_chip_post_macro(0x35) intel_chip_post_macro(0x35)
/*; new code... pulled from via stuff.*/
/* initialize registers */
// memory clk enable. We are not using ECC // memory clk enable. We are not using ECC
CS_WRITE($0x78, $0x01) CS_WRITE($0x78, $0x01)
// dram control, see the book. // 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. // dram control, see the book.
CS_WRITE($0x6B, $0x0d) CS_WRITE($0x6B, $0x0c)
// 64/128 MB dram // Initial setting, 256MB in each bank, will be rewritten later.
CS_WRITE($0x58, $0x80) CS_WRITE($0x5A, $0x20)
// 64/128 MB dram CS_WRITE($0x5B, $0x40)
CS_WRITE($0x59, $0x00) CS_WRITE($0x5C, $0x60)
// bank 0 ends at 64 MB CS_WRITE($0x5D, $0x80)
CS_WRITE($0x5A, $0x08) CS_WRITE($0x5E, $0xA0)
// bank 1 ends at 64 MB CS_WRITE($0x5F, $0xC0)
CS_WRITE($0x5B, $0x08) // It seems we have to take care of these 2 registers as if
// bank 2 ends at 64 MB // they are bank 6 and 7.
CS_WRITE($0x5C, $0x08) CS_WRITE($0x56, $0xC0)
// bank 2 ends at 64 MB CS_WRITE($0x57, $0xC0)
CS_WRITE($0x5D, $0x08)
// bank 2 ends at 64 MB
CS_WRITE($0x5E, $0x08)
// bank 2 ends at 64 MB
CS_WRITE($0x5F, $0x08)
// SDRAM in all banks // SDRAM in all banks
CS_WRITE($0x60, $0x3F) CS_WRITE($0x60, $0x3F)
// DRAM timing. I'm suspicious of this // DRAM timing. I'm suspicious of this
// This is for all banks, 64 is 0,1. 65 is 2,3. 66 is 4,5. // 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 // ras precharge 4T, RAS pulse 5T
// as per the note below, we change to cas 3 2000/8/31
// cas2 is 0xd6, cas3 is 0xe6 // cas2 is 0xd6, cas3 is 0xe6
// we're also backing off write pulse width to 2T, so result is 0xee // we're also backing off write pulse width to 2T, so result is 0xee
CS_WRITE($0x64, $0xe6) #if DIMM_CL2
CS_WRITE($0x65, $0x95) CS_WRITE($0x64, $0xd4)
CS_WRITE($0x66, $0x95) 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. // dram frequency select.
// no 256 m, enable 4K pages for 64M dram. // enable 4K pages for 64M dram.
CS_WRITE($0x69, $0xac) #if DIMM_PC133
CS_WRITE($0x69, $0x3c)
#else
CS_WRITE($0x69, $0xac)
#endif
// refresh counter, disabled. // refresh counter, disabled.
CS_WRITE($0x6A, $0x00) CS_WRITE($0x6A, $0x00)
// clkenable configuration. kevinh FIXME - add precharge // clkenable configuration. kevinh FIXME - add precharge
@ -80,102 +120,188 @@ raminit:
// As per Cindy Lee, set to 0x37, not 0x57 // As per Cindy Lee, set to 0x37, not 0x57
CS_WRITE($0x6D, $0x7f) CS_WRITE($0x6D, $0x7f)
/* Initialize all banks at once */
/* begin to initialize*/ /* begin to initialize*/
// I forget why we need this, but we do // I forget why we need this, but we do
mov $0xa55a5aa5, %eax mov $0xa55a5aa5, %eax
mov %eax, 0 DIMMS_WRITE(0)
mov %eax, 0x4000000
/* set NOP*/ /* set NOP*/
CS_WRITE($0x6C, $0x01) CS_WRITE($0x6C, $0x01)
/* wait 200us*/ /* wait 200us*/
// You need to do the memory reference. That causes the nop cycle. // You need to do the memory reference. That causes the nop cycle.
mov 0x0, %eax DIMMS_READ(0)
mov 0x4000000, %eax UDELAY(400)
DELAY(loop200)
/* set precharge */ /* set precharge */
CS_WRITE($0x6C, $0x02) CS_WRITE($0x6C, $0x02)
/* dummy reads*/ /* dummy reads*/
mov 0x0, %eax DIMMS_READ(0)
mov 0x4000000, %eax UDELAY(200)
/* set CBR*/ /* set CBR*/
CS_WRITE($0x6C, $0x04) CS_WRITE($0x6C, $0x04)
/* do 8 reads and wait 100us between each - from via*/ /* do 8 reads and wait >100us between each - from via*/
mov 0x0, %eax DIMMS_READ(0)
mov 0x4000000, %eax UDELAY(200)
DELAY(loop100) DIMMS_READ(0)
mov 0x0, %eax UDELAY(200)
mov 0x4000000, %eax DIMMS_READ(0)
DELAY(loop100) UDELAY(200)
mov 0x0, %eax DIMMS_READ(0)
mov 0x4000000, %eax UDELAY(200)
DELAY(loop100) DIMMS_READ(0)
mov 0x0, %eax UDELAY(200)
mov 0x4000000, %eax DIMMS_READ(0)
DELAY(loop100) UDELAY(200)
mov 0x0, %eax DIMMS_READ(0)
mov 0x4000000, %eax UDELAY(200)
DELAY(loop100) DIMMS_READ(0)
mov 0x0, %eax UDELAY(200)
mov 0x4000000, %eax
DELAY(loop100)
mov 0x0, %eax
mov 0x4000000, %eax
DELAY(loop100)
mov 0x0, %eax
mov 0x4000000, %eax
DELAY(loop100)
/* set MRS*/ /* set MRS*/
// 0x150 is cas2. We are now using 0x1d0, which is cas3
CS_WRITE($0x6c, $0x03) CS_WRITE($0x6c, $0x03)
movl $0x1d0, %ecx #if DIMM_CL2
movl (%ecx), %eax DIMMS_READ(0x150)
movl $0x40001d0, %ecx #else // CL=3
movl (%ecx), %eax DIMMS_READ(0x1d0)
#endif
UDELAY(200)
/* set to normal mode */ /* set to normal mode */
CS_WRITE($0x6C, $0x08) CS_WRITE($0x6C, $0x08)
movl $0x55aa55aa, %eax movl $0x55aa55aa, %eax
mov %eax, 0x0 DIMMS_WRITE(0)
mov 0x0, %eax DIMMS_READ(0)
UDELAY(200)
// Set the refresh rate. // Set the refresh rate.
#if DIMM_PC133
CS_WRITE($0x6A, $0x86)
#else
CS_WRITE($0x6A, $0x65) CS_WRITE($0x6A, $0x65)
#endif
// enable multi-page open // enable multi-page open
CS_WRITE($0x6B, $0x01) CS_WRITE($0x6B, $0x0d)
/* Begin auto-detection
/* From Mike Fan: * Find the first bank with DIMM equipped. */
Hi all:
If you are porting PM133, then you have to set DRAM Row Ending Address. /* Maximum possible memory in bank 0, none in other banks.
You did not set Rx56 and Rx57 in intel_pm133ram.S. * Starting from bank 0, we's fill 0 in these registers
That register setting is like Rx5A~Rx5F. * until memory is found. */
Maybe could fix the mem wrapping issue. CS_WRITE($0x5A, $0xff)
(from Ron Minnich) CS_WRITE($0x5B, $0xff)
My manual says these are non-cacheable region registers. CS_WRITE($0x5C, $0xff)
(Turns out the manual is wrong. However, this did not help. CS_WRITE($0x5D, $0xff)
2000/8/31 8:49 am I am setting all dram to cas3, and if that fails, CS_WRITE($0x5E, $0xff)
I'll be trying some of Cindy's other recommendations. CS_WRITE($0x5F, $0xff)
DRAM is currently CAS2. Symptom is an explosion in free_all_bootmem_core, CS_WRITE($0x56, $0xff)
In the loop where it is freeing bootmem alloc pages from low mem. CS_WRITE($0x57, $0xff)
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 movl $0x5A, %ebx // first bank
other recommendations. We also need to see whether we should be setting 1:
Fixed MTRRs, but that seems unlikely. /* Write different values to 0 and 8, then read from 0.
2000/8/31: 5:56 PM. No significant change. We're going to try to use 1 cycle writes * If values of address 0 match, we have something there. */
instead of 2. None of this feels like it is the real problem. Fixed MTRRs movl $0x12345678, %eax
helped a tiny bit. We can get to schedule() before we crash, but only movl %eax, 0
if we set a breakpoint after the first loop in free_all_bootmem_core movl $0x87654321, %edx
*/ movl %edx, 8
CS_WRITE($0x56, $0x10) movl 0, %edx
CS_WRITE($0x57, $0x10) 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) 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