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