[LinuxBIOS] Problems with Filo booting - HELP

joe at smittys.pointclark.net joe at smittys.pointclark.net
Fri Oct 5 04:45:57 CEST 2007


Quoting joe at smittys.pointclark.net:

> Quoting Stefan Reinauer <stepan at coresystems.de>:
>
>> * joe at smittys.pointclark.net <joe at smittys.pointclark.net> [071004 06:26]:
>>
>>> Here is my ram_check from 1-128MB. It appears to fill the ram ok. But
>>> only returns a value of 0xffffffff. Does this mean the ram is WO
>>> (write only) for some reason? Thanks again for your help.
>>
>> Do you have several banks? Do you send your ram init commands to all
>> these banks, or just the first?
>>
>>
> There is only one bank of onboard memory. I am starting to wonder if
> the memory isn't initializing correctly. But why would only part
> (0-640KB) of the memory initialize and not the rest??
>
>
So I changed around my do_ram_command() in raminit.c a bit and set it  
up so it will send the ram commands to any/all dimms found. I think  
this will work alot better. I will report back after I test it. I have  
attached it if you would like to check it out.


Thanks - Joe
-------------- next part --------------
/*
 * This file is part of the LinuxBIOS project.
 *
 * Copyright (C) 2007 Joseph Smith <joe at smittys.pointclark.net>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
 *
 */

#include <spd.h>
#include <sdram_mode.h>
#include <delay.h>
#include "i82830.h"

/*-----------------------------------------------------------------------------
Macros and definitions.
-----------------------------------------------------------------------------*/

/* Uncomment this to enable debugging output. */
#define DEBUG_RAM_SETUP 1

/* Debugging macros. */
#if defined(DEBUG_RAM_SETUP)
#define PRINT_DEBUG(x)		print_debug(x)
#define PRINT_DEBUG_HEX8(x)	print_debug_hex8(x)
#define PRINT_DEBUG_HEX16(x)	print_debug_hex16(x)
#define PRINT_DEBUG_HEX32(x)	print_debug_hex32(x)
#define DUMPNORTH()		dump_pci_device(PCI_DEV(0, 0, 0))
#else
#define PRINT_DEBUG(x)
#define PRINT_DEBUG_HEX8(x)
#define PRINT_DEBUG_HEX16(x)
#define PRINT_DEBUG_HEX32(x)
#define DUMPNORTH()
#endif

/* DRC[10:8] - Refresh Mode Select (RMS).
 * 0x0 for Refresh Disabled (Self Refresh)
 * 0x1 for Refresh interval 15.6 us for 133MHz
 * 0x2 for Refresh interval 7.8 us for 133MHz
 * 0x7 /* Refresh interval 128 Clocks. (Fast Refresh Mode)
 */
#define RAM_COMMAND_REFRESH      0x2

/* DRC[6:4] - SDRAM Mode Select (SMS). */
#define RAM_COMMAND_SELF_REFRESH 0x0
#define RAM_COMMAND_NOP		   0x1
#define RAM_COMMAND_PRECHARGE	   0x2
#define RAM_COMMAND_MRS		   0x3
#define RAM_COMMAND_CBR		   0x6
#define RAM_COMMAND_NORMAL	   0x7

/* DRC[29] - Initialization Complete (IC). */
#define RAM_COMMAND_IC           0x1

/*-----------------------------------------------------------------------------
SDRAM configuration functions.
-----------------------------------------------------------------------------*/

/* Send the specified RAM command to all DIMMs. */

static void do_ram_command(const struct mem_controller *ctrl, uint32_t command, uint32_t addr_offset)
{
	uint32_t reg;
	uint32_t dimm_start;
	uint32_t dimm_end;

	/* Configure the RAM command. */
	reg = pci_read_config32(ctrl->d0, DRC);
	/* Clear bits 6-4. */
	reg &= 0xffffff8f;
	reg |= command << 4;
	pci_write_config32(ctrl->d0, DRC, reg);

      /* If RAM_COMMAND_NORMAL set the refresh mode and IC bit. */
	if (command == RAM_COMMAND_NORMAL) {
		reg |= (RAM_COMMAND_REFRESH << 8);
		pci_write_config32(ctrl->d0, DRC, reg);
		udelay(1);
		reg |= (RAM_COMMAND_IC << 29);
		pci_write_config32(ctrl->d0, DRC, reg);
		PRINT_DEBUG("    Sending RAM command 0x");
		PRINT_DEBUG_HEX32(reg);
		PRINT_DEBUG(" to Memory Controller");
		PRINT_DEBUG("\r\n");
      } else {
	/* RAM_COMMAND_NORMAL affects only the memory controller 
	 * and doesn't need to be "sent" to the DIMMs.
	 */
		dimm_start = 0;

		for (i = 0; i < DIMM_SOCKETS; i++) {

			/* DRB is in Ticks of 32MB so we need to get total Bytes
			 * of each DIMM. NOTE: 2^25 == 32MB
			 */
			if (i == 0) {
				dim_end = (pci_read_config8(ctrl->d0, DRB + 1)) << 25;
			} else if (i == 1) {
				dim_end = (pci_read_config8(ctrl->d0, DRB + 3)) << 25;
			}

			if (dimm_end > dimm_start) {
				PRINT_DEBUG("    Sending RAM command 0x");
				PRINT_DEBUG_HEX32(reg);
				PRINT_DEBUG(" to 0x");
				PRINT_DEBUG_HEX32(dimm_start + addr_offset);
				PRINT_DEBUG("\r\n");
				read32(dimm_start + addr_offset);

				/* Set the start of the next DIMM. */
				dimm_start = dimm_end;
			}
		}
	}
}

/*-----------------------------------------------------------------------------
DIMM-independant configuration functions.
-----------------------------------------------------------------------------*/

struct dimm_size {
	unsigned long side1;
	unsigned long side2;
};

static struct dimm_size spd_get_dimm_size(unsigned device)
{
	struct dimm_size sz;
	int i, module_density, dimm_banks;
	sz.side1 = 0;
	module_density = spd_read_byte(device, 31);
	dimm_banks = spd_read_byte(device, 5);

	/* Find the size of side1 */
	/* Find the larger value. The larger value is always side1 */	
	for (i = 512; i >= 0; i >>= 1) {
		if ((module_density & i) == i) {
			sz.side1 = i;
			break;
		}
	}

	/* Set to 0 in case it's single sided */
	sz.side2 = 0;

	/* Test if it's a dual-sided dimm */
	if (dimm_banks > 1) {

		/* Test to see if there's a second value, if so it's asymmetrical */
		if (module_density != i) {

		/* Find the second value, picking up where we left off */
		/* i >>= 1 done initially to make sure we don't get the same value again */
			for (i >>= 1; i >= 0; i >>= 1) {
				if (module_density == (sz.side1 | i)) {
					sz.side2 = i;
					break;
				}
			}

		/* If not, it's symmetrical */
		} else {
		sz.side2 = sz.side1;
		}
	}
	/* SPD byte 31 is the memory size divided by 4 so we
	 * need to muliply by 4 to get the total size.
	 */
	sz.side1 <<= 2;
	sz.side2 <<= 2;
	return sz;
}

static void spd_set_dram_size(const struct mem_controller *ctrl)
{
	int i, value, drb1, drb2;

	for (i = 0; i < DIMM_SOCKETS; i++) {
		struct dimm_size sz;
		unsigned device;
		device = ctrl->channel0[i];
		drb1 = 0;
		drb2 = 0;

		/* First check if a DIMM is actually present. */
		if (spd_read_byte(device, 2) == 0x4) {
			print_debug("Found DIMM in slot ");
			print_debug_hex8(i);
			print_debug("\r\n");

			sz = spd_get_dimm_size(device);

			/* WISHLIST: would be nice to display it as decimal? */
			print_debug("DIMM is 0x");
			print_debug_hex16(sz.side1);
			print_debug(" on side 1\r\n");
			print_debug("DIMM is 0x");
			print_debug_hex16(sz.side2);
			print_debug(" on side 2\r\n");

			/* Test for PC133 (i82830 only supports PC133) */
			/* PC133 SPD9 - cycle time is always 75 */
			if (spd_read_byte(device, 9) != 0x75) {
				print_err("SPD9 DIMM Is Not PC133 Compatable\r\n");
				die("HALT\r\n");
			}
			/* PC133 SPD10 - access time is always 54 */
			if (spd_read_byte(device, 10) != 0x54) {
				print_err("SPD10 DIMM Is Not PC133 Compatable\r\n");
				die("HALT\r\n");
			}

			/* The i82830 can't handle DIMMs smaller than 32MB per
			 * side or larger than 256MB per side. It also can
			 * only support a symmetrical dual-sided dimm.
			 */
			if ((sz.side1 < 32)) {
				print_err("DIMMs smaller than 32MB per side\r\n");
				print_err("are not supported on this board\r\n");
				die("HALT\r\n");
			}

			if ((sz.side2 != 0) && (sz.side2 < 32)) {
				print_err("DIMMs smaller than 32MB per side\r\n");
				print_err("are not supported on this board\r\n");
				die("HALT\r\n");
			}

			if ((sz.side1 > 256) || (sz.side2 > 256)) {
				print_err("DIMMs larger than 256MB per side\r\n");
				print_err("are not supported on this board\r\n");
				die("HALT\r\n");
			}

			if ((sz.side2 != 0) && (sz.side1 != sz.side2)) {
				print_err("This board only supports\r\n");
				print_err("symmetrical dual-sided DIMMs\r\n");
				die("HALT\r\n");
			}

			/* We need to divide size by 32 to set up the
			 * DRB registers.
			*/
			if (sz.side1 > 0) {
				drb1 = sz.side1 >> 5;
			}
			if (sz.side2 > 0) {
				drb2 = sz.side2 >> 5;
			}
		} else {
			PRINT_DEBUG("No DIMM found in slot ");
			PRINT_DEBUG_HEX8(i);
			PRINT_DEBUG("\r\n");

			/* If there's no DIMM in the slot, set value to 0. */
			drb1 = 0;
			drb2 = 0;
		}
      	/* Set the value for DRAM Row Boundary Registers */
		if (i == 0) {
			pci_write_config8(ctrl->d0, DRB, drb1);
			pci_write_config8(ctrl->d0, DRB + 1, drb1 + drb2);
			PRINT_DEBUG("DRB 0x");
			PRINT_DEBUG_HEX8(DRB);
			PRINT_DEBUG(" has been set to 0x");
			PRINT_DEBUG_HEX8(drb1);
			PRINT_DEBUG("\r\n");
			PRINT_DEBUG("DRB1 0x");
			PRINT_DEBUG_HEX8(DRB + 1);
			PRINT_DEBUG(" has been set to 0x");
			PRINT_DEBUG_HEX8(drb1 + drb2);
			PRINT_DEBUG("\r\n");
		} else if (i == 1) {
			value = pci_read_config8(ctrl->d0, DRB + 1);
			pci_write_config8(ctrl->d0, DRB + 2, value + drb1);
			pci_write_config8(ctrl->d0, DRB + 3, value + drb1 + drb2);
			PRINT_DEBUG("DRB2 0x");
			PRINT_DEBUG_HEX8(DRB + 2);
			PRINT_DEBUG(" has been set to 0x");
			PRINT_DEBUG_HEX8(value + drb1);
			PRINT_DEBUG("\r\n");
			PRINT_DEBUG("DRB3 0x");
			PRINT_DEBUG_HEX8(DRB + 3);
			PRINT_DEBUG(" has been set to 0x");
			PRINT_DEBUG_HEX8(value + drb1 + drb2);
			PRINT_DEBUG("\r\n");
		}
	}
}

static void set_dram_row_attributes(const struct mem_controller *ctrl)
{
	int i, dra, col, width, value;

	for (i = 0; i < DIMM_SOCKETS; i++) {
		unsigned device;
		device = ctrl->channel0[i];

		/* First check if a DIMM is actually present. */
		if (spd_read_byte(device, 2) == 0x4) {
			print_debug("Found DIMM in slot ");
			print_debug_hex8(i);
			print_debug(", setting DRA...\r\n");

			dra = 0x00;

			/* columns */
			col = spd_read_byte(device, 4);

			/* data width */
			width = spd_read_byte(device, 6);

			/* calculate page size in bits */
			value = ((1 << col) * width);

			/* convert to Kilobytes */
			dra = ((value / 8) >> 10);

			/* # of banks of DIMM (single or double sided) */
			value = spd_read_byte(device, 5);

			if (value == 1) {
				switch(dra) {
					/* 2KB */
					case 2:
						dra = 0xF0;
						break;
					/* 4KB */
					case 4:
						dra = 0xF1;
						break;
					/* 8KB */
					case 8:
						dra = 0xF2;
						break;
					/* 16KB */
					case 16:
						dra = 0xF3;
						break;
					default:
						print_err("Page size not supported\r\n");
						die("HALT\r\n");
				}
			} else if (value == 2) {
				switch(dra) {
					/* 2KB */
					case 2:
						dra = 0x00;
						break;
					/* 4KB */
					case 4:
						dra = 0x11;
						break;
					/* 8KB */
					case 8:
						dra = 0x22;
						break;
					/* 16KB */
					case 16:
						dra = 0x33;
						break;
					default:
						print_err("Page size not supported\r\n");
						die("HALT\r\n");
				}
			}else {
				print_err("# of banks of DIMM not supported\r\n");
				die("HALT\r\n");
			}

		} else {
			PRINT_DEBUG("No DIMM found in slot ");
			PRINT_DEBUG_HEX8(i);
			PRINT_DEBUG(", setting DRA to 0xFF\r\n");

			/* If there's no DIMM in the slot, set dra value to 0xFF. */
			dra = 0xFF;
		}

		/* Set the value for DRAM Row Attribute Registers */
      	pci_write_config8(ctrl->d0, DRA + i, dra);
		PRINT_DEBUG("DRA 0x");
		PRINT_DEBUG_HEX8(DRA + i);
		PRINT_DEBUG(" has been set to 0x");
		PRINT_DEBUG_HEX8(dra);
		PRINT_DEBUG("\r\n");
	}
}

static void set_dram_timing(const struct mem_controller *ctrl)
{
	/* Set the value for DRAM Timing Register */
	pci_write_config32(ctrl->d0, DRT, 0x00000010);
}

static void set_dram_buffer_strength(const struct mem_controller *ctrl)
{
	/* TODO: This needs to be set according to the DRAM tech
	 * (x8, x16, or x32). Argh, Intel provides no docs on this!
	 * Currently, it needs to be pulled from the output of
	 * lspci -xxx Rx92
	*/

	/* Set the value for System Memory Buffer Strength Control Registers */
	pci_write_config32(ctrl->d0, BUFF_SC, 0xFC9FC909);
}

/*-----------------------------------------------------------------------------
Public interface.
-----------------------------------------------------------------------------*/

static void sdram_set_registers(const struct mem_controller *ctrl)
{
	unsigned value;
	value = 0;

	PRINT_DEBUG("Setting initial registers....\r\n");

      /* Set the value for GMCH Control Register #0 */
      pci_write_config16(ctrl->d0, GCC0, 0xA072);

	/* Set the value for GMCH Control Register #1
	 * Only set bits 6-0, bits 15-7 are reserved.
	 */
	value = pci_read_config16(ctrl->d0, GCC1);
	value |= 0x20;
	pci_write_config16(ctrl->d0, GCC1, value);

	/* Set the value for Fixed DRAM Hole Control Register */
	pci_write_config8(ctrl->d0, FDHC, 0x00);

	/* Set the value for Aperture Base Configuration Register  */
	pci_write_config32(ctrl->d0, APBASE, 0x00000008);

	/* Set the value for Register Range Base Address Register */
	pci_write_config32(ctrl->d0, RRBAR, 0x00000000);

	/* Set the value for Programable Attribute Map Registers
	 * Ideally, this should be R/W for as many ranges as possible.
	 */
	pci_write_config8(ctrl->d0, PAM0, 0x30);
	pci_write_config8(ctrl->d0, PAM1, 0x33);
	pci_write_config8(ctrl->d0, PAM2, 0x33);
	pci_write_config8(ctrl->d0, PAM3, 0x33);
	pci_write_config8(ctrl->d0, PAM4, 0x33);
	pci_write_config8(ctrl->d0, PAM5, 0x33);
	pci_write_config8(ctrl->d0, PAM6, 0x33);

	/* Set the value for DRAM Throttling Control Register */
	pci_write_config32(ctrl->d0, DTC, 0x00000000);

	/* Set the value for System Management RAM Control Register */
	pci_write_config8(ctrl->d0, SMRAM, 0x02);

	/* Set the value for Extended System Management RAM Control Register */
	pci_write_config8(ctrl->d0, ESMRAMC, 0x38);

	PRINT_DEBUG("Initial registers have been set.\r\n");
}

static void sdram_set_spd_registers(const struct mem_controller *ctrl)
{
	spd_set_dram_size(ctrl);

	set_dram_row_attributes(ctrl);

	set_dram_timing(ctrl);

	set_dram_buffer_strength(ctrl);
}

static void sdram_enable(int controllers, const struct mem_controller *ctrl)
{
	int i;

	/* 0. Wait until power/voltages and clocks are stable (200us). */
	udelay(200);

	/* 1. Apply NOP. */
	PRINT_DEBUG("RAM Enable 1: Apply NOP\r\n");
	do_ram_command(ctrl, RAM_COMMAND_NOP, 0);
	udelay(200);

	/* 2. Precharge all. Wait tRP. */
	PRINT_DEBUG("RAM Enable 2: Precharge all\r\n");
	do_ram_command(ctrl, RAM_COMMAND_PRECHARGE, 0);
	udelay(1);

	/* 3. Perform 8 refresh cycles. Wait tRC each time. */
	PRINT_DEBUG("RAM Enable 3: CBR\r\n");
	for (i = 0; i < 8; i++) {
		do_ram_command(ctrl, RAM_COMMAND_CBR, 0);
		udelay(1);
	}

	/* 4. Mode register set. Wait two memory cycles. */
	PRINT_DEBUG("RAM Enable 4: Mode register set\r\n");
	do_ram_command(ctrl, RAM_COMMAND_MRS, 0x1d0);
	udelay(2);

	/* 5. Normal operation (enables refresh) */
	PRINT_DEBUG("RAM Enable 5: Normal operation\r\n");
	do_ram_command(ctrl, RAM_COMMAND_NORMAL, 0);
	udelay(1);

	PRINT_DEBUG("Northbridge following SDRAM init:\r\n");
	DUMPNORTH();
}


More information about the coreboot mailing list