Peter Stuge wrote:
> On Tue, May 22, 2007 at 12:25:43PM +0100, Marcelo Coelho wrote:
>> So, if you want to pass it into a function you have to define the
>> function with the parameter as being a pointer (and a good practice
>> would be also pass the size of the array).
> 
> On Tue, May 22, 2007 at 07:15:14AM -0400, Corey Osgood wrote:
>> unsigned long row_offsets[DIMM_SOCKETS * 2 - 1];
>> spd_set_dram_size(ctrl, row_offsets);
>>
>> static void spd_set_dram_size(const struct mem_controller *ctrl,
>> unsigned long row_offsets)
> 
> To clarify, change the prototype and function to:
> 
> static void spd_set_dram_size(const struct mem_controller *ctrl,
>  unsigned long *row_offsets)

That's what I figured after Marcelo's post, and something I tried last
night as well. The error:

raminit.c:278.56: auto.c:88.21:
0x81b0e30 adecl      Internal compiler error: adecl remains?
make[1]: *** [auto.inc] Aborted (core dumped)
make[1]: Leaving directory
`/home/amp/linuxbios/p2b/LinuxBIOSv2/targets/asus/mew-vm/mew-vm/normal'
make: *** [normal/linuxbios.rom] Error 1

> If this static function is in the same file as row_offsets[] and the
> array is in file scope then you could just skip the parameter
> completely. This makes sense because you'll need to use another
> global entity (the DIMM_SOCKETS define) in the function anyway. The
> alternative clean way would be to pass DIMM_SOCKETS*2-1 to
> spd_set_dram_size() too, but in this case it could probably be OK to
> just skip both those parameters. Not sure without seeing complete
> code.

raminit.c is attached, I think I'm just very confused.

Thanks,
Corey
/*
 * This file is part of the LinuxBIOS project.
 *
 * Copyright (C) 2007 Uwe Hermann <[EMAIL PROTECTED]>
 * Copyright (C) 2007 Corey Osgood <[EMAIL PROTECTED]>
 *
 * 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 "i810.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

/* DRAMT[7:5] - SDRAM Mode Select (SMS). */
#define RAM_COMMAND_SELF_REFRESH 0x0 /* IE disable refresh */
#define RAM_COMMAND_NORMAL	 0x1 /* Normal refresh, 15.6us/11.7us for 100/133MHz */
#define RAM_COMMAND_NORMAL_FR	 0x2 /* Fast refresh, 7.8us/5.85us for 100/133MHz */
#define RAM_COMMAND_NOP		 0x4
#define RAM_COMMAND_PRECHARGE	 0x5
#define RAM_COMMAND_MRS		 0x6
#define RAM_COMMAND_CBR		 0x7

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

/**
 * Send the specified RAM command to all DIMMs.
 *
 * @param Memory controller
 * @param TODO
 * @param TODO
 */
static void do_ram_command(const struct mem_controller *ctrl, uint32_t command, 
				uint32_t addr_offset, unsigned long *row_offsets)
{
	int i;
	uint8_t reg;

	/* TODO: Support for multiple DIMMs. */

	/* Configure the RAM command. */
	reg = pci_read_config8(ctrl->d0, DRAMT);
	reg &= 0x1f;		/* Clear bits 7-5. */
	reg |= command << 5;
	pci_write_config8(ctrl->d0, DRAMT, 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; */

	PRINT_DEBUG("    Sending RAM command 0x");
	PRINT_DEBUG_HEX8(reg);
	PRINT_DEBUG(" to 0x");
	PRINT_DEBUG_HEX32(0 + addr_offset); // FIXME
	PRINT_DEBUG("\r\n");

	/* Read from (DIMM start address + addr_offset). */
	read32(0 + addr_offset);//first offset is always 0
	for(i = 0; i < (DIMM_SOCKETS * 2 - 1); i++)
	{
		read32(row_offsets[i] + addr_offset);
	}
}

/*-----------------------------------------------------------------------------
DIMM-independant configuration functions.
-----------------------------------------------------------------------------*/
static void spd_set_dram_size(const struct mem_controller *ctrl, unsigned long *row_offsets)
{
	/* drp and dimm_size have to be ints since all the smbus-related functions
	 return ints, and its just easier this way */
	int i, drp, dimm_size;
	drp = 0x00;
	row_offsets[0] = 0;
	
	for(i = 0; i < DIMM_SOCKETS; i++)
	{
		/* First check if a DIMM is actually present */
		if(smbus_read_byte(ctrl->channel0[i], 2) == 4)
		{
			print_debug("Found DIMM in slot ");
			print_debug_hex8(i);
			print_debug("\r\n");
			
			dimm_size = smbus_read_byte(ctrl->channel0[i], 31);			
			
			print_debug("DIMM is 0x");
			print_debug_hex8(dimm_size);
			print_debug(" in units of 4MB\r\n");

			/* The i810 can't handle dimms larger than 128MB per side */
			/* Note: the factory BIOS just dies if it spots this :D */
			if(dimm_size < 32)
			{
				print_err("DIMM row sizes larger than 128MB not 
							supported on i810\r\n");
				print_err("Treating as 128MB DIMM\r\n");
				dimm_size = 32;
			}
			
			/* Set the row offset, in KBytes (should this be Kbits?) */
			/* Note that this offset is the start of the next row */
			if(i == 0) 
			{
				row_offsets[i * 2] = (dimm_size * 4 * 1024);
			}
			else 
			{
				row_offsets[i * 2] = (dimm_size * 4 * 1024) + 
							row_offsets[i * 2 - 1];
			}
			/* If the dimm is dual-sided, set the offset for the second
			   row. This needs to be fixed for asymetrical dimms */
			if((smbus_read_byte(ctrl->channel0[i], 127) | 0xf) == 0xff)
			{
				row_offsets[i * 2 + 1] = (dimm_size * 4 * 1024 
							* 1024) + row_offsets[i * 2];
			}
			
			#if 0 //old way
			/* 8MB */
			if(dimm_size == 0x2) dimm_size = 0x1;
			/* 16MB */
			else if(dimm_size == 0x4) dimm_size = 0x4;
			/* 32MB */
			else if(dimm_size == 0x8) dimm_size = 0x7;
			/* 64 MB */
			else if(dimm_size == 0x10) dimm_size = 0xa;
			/* 128 MB */
			else if(dimm_size == 0x20) dimm_size = 0xd;
			else print_debug("Ram Size not supported\r\n");
			#endif
			
			/* This table is provided in raminit.h, because it got 
			 * extremely messy. The above way is cleaner, but doesn't
			 * support any asymetrical configurations. Nasty either
			 * way, thanks to Intel's stupidity */
			dimm_size = translate_spd_to_i810[dimm_size];
			
			print_debug("After translation, dimm_size is 0x");
			print_debug_hex8(dimm_size);
			print_debug("\r\n");
			
			/* If the dimm is dual-sided, the DRP value is +2 */
			/* TODO: Figure out asymetrical configurations */
			if((smbus_read_byte(ctrl->channel0[i], 127) | 0xf) == 0xff)
			{
				print_debug("DIMM is dual-sided\r\n");
				dimm_size += 2;
			}
		} 
		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 the value to 0 */
			dimm_size = 0x00;
		}	
		
		/* Put in dimm_size to reflect the current dimm */
		drp |= dimm_size << (i * 4);
	}

	print_debug("DRP calculated to 0x");
	print_debug_hex8(drp);
	print_debug("\r\n");

	pci_write_config8(ctrl->d0, DRP, drp);		
}

static void set_spd_timing(const struct mem_controller *ctrl)
{
/* Table 14. Programmable SDRAM Timing Parameters
                         Parameter          DRAMT Bit Values (SCLKs)
            RAS# Precharge (SRP)               0            2,3
            RAS# to CAS# Delay (SRCD)          1            2,3
            CAS# Latency (CL)                  2            2,3
            DRAM Cycle Time (DCT)              4         Tras = 5,6
                                                         Trc = 7,8
*/
}


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

/**
 * TODO.
 *
 * @param Memory controller
 */
static void sdram_set_registers(const struct mem_controller *ctrl)
{
	/* TODO */
	pci_write_config8(ctrl->d0, GMCHCFG, 0x60);
	/* TODO */
	pci_write_config8(ctrl->d0, PAM, 0x00);
	/* TODO */
	pci_write_config8(ctrl->d0, DRAMT, 0x0f);
	/* TODO */
	//pci_write_config8(ctrl->d0, SMRAM, 0x00);
	/* TODO */
	pci_write_config8(ctrl->d0, MISSC2, 0x06);
	
	/* TODO - Undocumented, figure out what they do */
	//pci_write_config8(ctrl->d0, 0x81, 0xf8);
	//pci_write_config8(ctrl->d0, 0x82, 0x1f);
	
	/* TODO: This needs to be set according to the dram tech (x8, x16, or x32) */
	pci_write_config16(ctrl->d0, BUFF_SC, 0x77da);	
}

/**
 * TODO.
 *
 * @param Memory controller
 */
static void sdram_set_spd_registers(const struct mem_controller *ctrl)
{
	/* spd_set_dram_size moved to sdram_enable to prevent having to pass
	   a table between here and there */
	//spd_set_dram_size(ctrl);

	//set_spd_timing(ctrl);
	
	//set_buffer_strength(ctrl);
}

/**
 * Enable SDRAM.
 *
 * @param Number of controllers
 * @param Memory controller
 */
static void sdram_enable(int controllers, const struct mem_controller *ctrl)
{
	int i;
	/* Subtract 1 here because the first row offset will always be 0 */
	unsigned long row_offsets[DIMM_SOCKETS * 2 - 1];
		
	spd_set_dram_size(ctrl, row_offsets); 
	
	/* 1. Apply NOP. */
	PRINT_DEBUG("RAM Enable 1: Apply NOP\r\n");
	do_ram_command(ctrl, RAM_COMMAND_NOP, 0, row_offsets);
	udelay(200);

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

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

	/* 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, row_offsets);
	udelay(200);

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

	PRINT_DEBUG("Northbridge following SDRAM init:\r\n");
	DUMPNORTH();
}
-- 
linuxbios mailing list
[email protected]
http://www.linuxbios.org/mailman/listinfo/linuxbios

Reply via email to