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();
}

Attachment: minicom.cap
Description: application/cap

Attachment: signature.asc
Description: Digital signature

-- 
linuxbios mailing list
linuxbios@linuxbios.org
http://www.openbios.org/mailman/listinfo/linuxbios

Reply via email to