On Sat, Dec 02, 2006 at 09:30:58AM +0100, Segher Boessenkool wrote: > It looks reasonable. You want to shift by 3 though, not 23, > not 15, so you read from 0x1d0 for writing to the MRS.
OK, a few questions:
* Do I read32() from somewhere for _every_ RAM command or only for MRS?
* The v1 code seems to read from the highest RAM address for each DRB
register. In my case:
Get contents of DRB6 (0x8), shift left by 23 as the DRB registers
store multiples of 8 MB, so I get my 64 MB. Correct?
Now; do I read32() from
* (8 << 23)
* (8 << 23) + 0x1d0
* 0x0 + 0x1d0
* 0x0 + 0x1d0 AND (8 << 23) + 0x1d0
* 0x0
* ???
Do I read from x for most commands but from (x + 0x1d0) for MRS?
Or should I read from (x + 0x1d0) for all commands?
I've tried a lot of variations here, but nothing worked. Maybe some
other parts of the code are still broken?
> It seems the i440 might want the address bits inverted on
> the high banks in some configurations, btw; so if it won't
> work, you can try 0x1d0 ^ 0xff8 or so.
Doesn't seem to work either.
Attached my latest code and a minicom log...
Uwe.
--
http://www.hermann-uwe.de | http://www.holsham-traders.de
http://www.crazy-hacks.org | http://www.unmaintained-free-software.org
#include <spd.h>
#include <sdram_mode.h>
#include "i440bx.h"
/*-----------------------------------------------------------------------------
Definitions.
-----------------------------------------------------------------------------*/
/* Uncomment this to enable local debugging messages. */
#define DEBUG_RAM_CONFIG 1
/* Debugging macros. */
#if defined(DEBUG_RAM_CONFIG)
#define RAM_DEBUG_MESSAGE(x) print_debug(x)
#define RAM_DEBUG_HEX32(x) print_debug_hex32(x)
#define RAM_DEBUG_HEX8(x) print_debug_hex8(x)
#define DUMPNORTH() dump_pci_device(PCI_DEV(0, 0, 0))
#else
#define RAM_DEBUG_MESSAGE(x)
#define RAM_DEBUG_HEX32(x)
#define RAM_DEBUG_HEX8(x)
#define DUMPNORTH()
#endif
/* SDRAMC[7:5] - SDRAM Mode Select (SMS). */
#define RAM_COMMAND_NORMAL 0x0
#define RAM_COMMAND_NOP 0x1
#define RAM_COMMAND_PRECHARGE 0x2
#define RAM_COMMAND_MRS 0x3
#define RAM_COMMAND_CBR 0x4
/* Map the JEDEC SPD refresh rates (array index) to 440BX refresh rates as
* defined in DRAMC[2:0].
*
* [0] == Normal 15.625 us -> 15.6 us
* [1] == Reduced(.25X) 3.9 us -> 7.8 ns
* [2] == Reduced(.5X) 7.8 us -> 7.8 us
* [3] == Extended(2x) 31.3 us -> 31.2 us
* [4] == Extended(4x) 62.5 us -> 62.4 us
* [5] == Extended(8x) 125 us -> 124.8 us
*/
static const uint32_t refresh_rate_map[] = {
1, 5, 5, 2, 3, 4
};
/*-----------------------------------------------------------------------------
Delay functions.
-----------------------------------------------------------------------------*/
#define SLOW_DOWN_IO inb(0x80);
static void do_delay(void)
{
int i;
for (i = 0; i < 16; i++) {
SLOW_DOWN_IO
}
}
#define DO_DELAY do_delay();
#define EXTRA_DELAY DO_DELAY
/*-----------------------------------------------------------------------------
SDRAM configuration functions.
-----------------------------------------------------------------------------*/
static void do_ram_command(const struct mem_controller *ctrl,
uint32_t command, uint16_t jedec_mode_bits)
{
int i;
uint16_t reg;
/* Configure the RAM command. */
reg = pci_read_config16(ctrl->d0, SDRAMC);
reg &= 0xff1f; /* Clear bits 7-5. */
reg |= (uint16_t)(command << 5);
pci_write_config16(ctrl->d0, SDRAMC, reg);
/* RAM_COMMAND_NORMAL affects only the memory controller and
doesn't need to be "sent" to the DIMMs. */
/* if (command == RAM_COMMAND_NORMAL) return; */
/* Note: 2^23 == 8 MB (440BX stores multiples of 8 MB in DRB regs). */
/* We shift 8 by 23 to make a total of 64 MB. */
RAM_DEBUG_MESSAGE(" Sending RAM command to 0x");
RAM_DEBUG_HEX32((0x8 << 23) + jedec_mode_bits);
RAM_DEBUG_MESSAGE("\r\n");
/* read32(0x0 + jedec_mode_bits); */
read32((0x8 << 23) + jedec_mode_bits);
}
/*-----------------------------------------------------------------------------
DIMM-independant configuration functions.
-----------------------------------------------------------------------------*/
static void spd_enable_refresh(const struct mem_controller *ctrl)
{
uint8_t reg;
int i, value;
reg = pci_read_config8(ctrl->d0, DRAMC);
for (i = 0; i < MAX_DIMM_SOCKETS_PER_CHANNEL; i++) {
value = spd_read_byte(ctrl->channel0[i], SPD_REFRESH);
if (value < 0) continue;
reg = (reg & 0xf8) | refresh_rate_map[(value & 0x7f)];
}
pci_write_config8(ctrl->d0, DRAMC, reg);
}
/*-----------------------------------------------------------------------------
Public interface.
-----------------------------------------------------------------------------*/
static void sdram_set_registers(const struct mem_controller *ctrl)
{
RAM_DEBUG_MESSAGE("Northbridge prior to SDRAM init:\r\n");
DUMPNORTH();
pci_write_config8(ctrl->d0, PAM0, 0x10);
pci_write_config8(ctrl->d0, PAM1, 0x11);
pci_write_config8(ctrl->d0, PAM2, 0x01);
pci_write_config8(ctrl->d0, PAM3, 0x00);
pci_write_config8(ctrl->d0, PAM4, 0x00);
pci_write_config8(ctrl->d0, PAM5, 0x00);
pci_write_config8(ctrl->d0, PAM6, 0x00);
pci_write_config8(ctrl->d0, 0x13, 0xd8);
pci_write_config8(ctrl->d0, 0x92, 0x00);
pci_write_config8(ctrl->d0, 0x0d, 0x40);
pci_write_config8(ctrl->d0, 0x13, 0xd8);
pci_write_config8(ctrl->d0, DRAMT, 0x00);
pci_write_config8(ctrl->d0, 0x6d, 0x2a);
pci_write_config8(ctrl->d0, 0x70, 0x20);
pci_write_config8(ctrl->d0, SMRAM, 0x0a);
pci_write_config8(ctrl->d0, 0x80, 0x02);
pci_write_config8(ctrl->d0, 0x90, 0x98);
pci_write_config8(ctrl->d0, 0x91, 0xcc);
pci_write_config8(ctrl->d0, 0xb0, 0x80);
pci_write_config8(ctrl->d0, 0xb1, 0x20);
pci_write_config8(ctrl->d0, 0xb4, 0x30);
pci_write_config8(ctrl->d0, 0xba, 0x45);
pci_write_config8(ctrl->d0, 0xbb, 0x03);
pci_write_config8(ctrl->d0, 0xbc, 0x20);
pci_write_config8(ctrl->d0, 0xbd, 0x10);
pci_write_config8(ctrl->d0, 0xc4, 0xff);
pci_write_config8(ctrl->d0, 0xc5, 0xfd);
pci_write_config8(ctrl->d0, 0xc6, 0xff);
pci_write_config8(ctrl->d0, 0xc7, 0xff);
pci_write_config8(ctrl->d0, 0xc8, 0x18);
pci_write_config8(ctrl->d0, 0xc9, 0x0c);
pci_write_config8(ctrl->d0, 0xca, 0xff);
pci_write_config8(ctrl->d0, 0xcb, 0xff);
pci_write_config8(ctrl->d0, 0xcc, 0x61);
pci_write_config8(ctrl->d0, 0xe0, 0x4c);
pci_write_config8(ctrl->d0, 0xe1, 0xad);
pci_write_config8(ctrl->d0, 0xe2, 0xff);
pci_write_config8(ctrl->d0, 0xe3, 0xbb);
pci_write_config8(ctrl->d0, 0xe4, 0x8a);
pci_write_config8(ctrl->d0, 0xe5, 0x3e);
pci_write_config8(ctrl->d0, 0xe6, 0x00);
/* pci_write_config8(ctrl->d0, 0xe7, 0x80); */
pci_write_config8(ctrl->d0, 0xe8, 0x2c);
pci_write_config8(ctrl->d0, 0xe9, 0xd3);
pci_write_config8(ctrl->d0, 0xea, 0xf7);
pci_write_config8(ctrl->d0, 0xeb, 0xcf);
pci_write_config8(ctrl->d0, 0xec, 0x9d);
pci_write_config8(ctrl->d0, 0xed, 0x3e);
pci_write_config8(ctrl->d0, 0xee, 0x00);
pci_write_config8(ctrl->d0, 0xef, 0x00);
/* Now set bit 7 of 0xe7 (must come last). */
pci_write_config8(ctrl->d0, 0xe7, 0x80);
pci_write_config8(ctrl->d0, 0xf0, 0x40);
pci_write_config8(ctrl->d0, 0xf1, 0x01);
pci_write_config8(ctrl->d0, 0xf7, 0x60);
/* TODO: Do this later? */
pci_write_config8(ctrl->d0, PMCR, 0x10);
}
static void sdram_set_spd_registers(const struct mem_controller *ctrl)
{
pci_write_config8(ctrl->d0, DRB0, 0x00);
pci_write_config8(ctrl->d0, DRB1, 0x00);
pci_write_config8(ctrl->d0, DRB2, 0x00);
pci_write_config8(ctrl->d0, DRB3, 0x00);
pci_write_config8(ctrl->d0, DRB4, 0x00);
pci_write_config8(ctrl->d0, DRB5, 0x00);
pci_write_config8(ctrl->d0, DRB6, 0x08);
pci_write_config8(ctrl->d0, DRB7, 0x08);
/* Don't enable refresh for now. */
pci_write_config8(ctrl->d0, DRAMC, 0x08);
pci_write_config16(ctrl->d0, RPS, 0x1000);
pci_write_config16(ctrl->d0, SDRAMC, 0x0110);
pci_write_config16(ctrl->d0, PGPOL, 0xff23);
pci_write_config32(ctrl->d0, NBXCFG, 0xff008a0c);
}
static void sdram_enable(int controllers, const struct mem_controller *ctrl)
{
/* 1. & 2. Power up and start clocks. */
RAM_DEBUG_MESSAGE("Ram Enable 1: Power up\r\n");
RAM_DEBUG_MESSAGE("Ram Enable 2: Start clocks\r\n");
/* A 200us delay is needed. */
DO_DELAY
EXTRA_DELAY
/* 3. Apply NOP. */
RAM_DEBUG_MESSAGE("Ram Enable 3: Apply NOP\r\n");
do_ram_command(ctrl, RAM_COMMAND_NOP, 0);
EXTRA_DELAY
/* 4. Precharge all. */
RAM_DEBUG_MESSAGE("Ram Enable 4: Precharge all\r\n");
do_ram_command(ctrl, RAM_COMMAND_PRECHARGE, 0);
EXTRA_DELAY
/* 5. Issue EMRS to enable DLL (not needed on 440BX). */
/* 6. Reset DLL (not needed on 440BX). */
/* 7. Precharge all (not needed on 440BX). */
/* 8. Perform eight AUTO REFRESH / CBR cycles. */
RAM_DEBUG_MESSAGE("Ram Enable 8: CBR\r\n");
do_ram_command(ctrl, RAM_COMMAND_CBR, 0);
EXTRA_DELAY
do_ram_command(ctrl, RAM_COMMAND_CBR, 0);
EXTRA_DELAY
do_ram_command(ctrl, RAM_COMMAND_CBR, 0);
EXTRA_DELAY
do_ram_command(ctrl, RAM_COMMAND_CBR, 0);
EXTRA_DELAY
do_ram_command(ctrl, RAM_COMMAND_CBR, 0);
EXTRA_DELAY
do_ram_command(ctrl, RAM_COMMAND_CBR, 0);
EXTRA_DELAY
do_ram_command(ctrl, RAM_COMMAND_CBR, 0);
EXTRA_DELAY
do_ram_command(ctrl, RAM_COMMAND_CBR, 0);
EXTRA_DELAY
/* 9. Mode register set. */
RAM_DEBUG_MESSAGE("Ram Enable 9: Mode register set\r\n");
do_ram_command(ctrl, RAM_COMMAND_MRS, 0x1d0);
/* do_ram_command(ctrl, RAM_COMMAND_MRS, 0x150); */
/* do_ram_command(ctrl, RAM_COMMAND_MRS, 0x1d0 ^ 0xff8); */
EXTRA_DELAY
EXTRA_DELAY
/* 10. DDR Receive FIFO Resync (not needed on 440BX). */
/* 11. Normal operation. */
RAM_DEBUG_MESSAGE("Ram Enable 11: Normal operation\r\n");
do_ram_command(ctrl, RAM_COMMAND_NORMAL, 0);
EXTRA_DELAY
/* Finally enable refresh. */
RAM_DEBUG_MESSAGE("Finally enabling refresh\r\n");
spd_enable_refresh(ctrl);
EXTRA_DELAY
RAM_DEBUG_MESSAGE("Northbridge following SDRAM init:\r\n");
DUMPNORTH();
}
minicom.cap
Description: application/cap
signature.asc
Description: Digital signature
-- linuxbios mailing list [email protected] http://www.openbios.org/mailman/listinfo/linuxbios
