coreboot-kgpe-d16/util/romcc/tests/linux_test5.c
Eric Biederman 9008960339 - Upgrade to romcc version 0.63
This includes more test cases
  Lots of small bug fixes
  A built in C preprocessor
  Initial support for not inlining everything
  __attribute__((noinline)) works
  Better command line options and help
  Constants arrays can be read at compile time
  Asm statements that are not volatile will now be removed when their outputs go unused
  Loads and stores that are not volatile will be removed when their values go unused
  The number of FIXMES in the code is finally starting to go down.


git-svn-id: svn://svn.coreboot.org/coreboot/trunk@1582 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
2004-05-28 14:11:54 +00:00

359 lines
11 KiB
C

#include "linux_syscall.h"
#include "linux_console.h"
inline int log2(int value)
{
/* __builtin_bsr is a exactly equivalent to the x86 machine
* instruction with the exception that it returns -1
* when the value presented to it is zero.
* Otherwise __builtin_bsr returns the zero based index of
* the highest bit set.
*/
return __builtin_bsr(value);
}
static int smbus_read_byte(unsigned device, unsigned address)
{
static const unsigned char dimm[] = {
0x80, 0x08, 0x07, 0x0d, 0x0a, 0x02, 0x48, 0x00, 0x04, 0x60, 0x70, 0x02, 0x82, 0x08, 0x08, 0x01,
0x0e, 0x04, 0x0c, 0x01, 0x02, 0x20, 0x00, 0x75, 0x70, 0x00, 0x00, 0x48, 0x30, 0x48, 0x2a, 0x40,
0x80, 0x80, 0x45, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x80, 0x08, 0x07, 0x0d, 0x0a, 0x02, 0x48, 0x00, 0x04, 0x60, 0x70, 0x02, 0x82, 0x08, 0x08, 0x01,
0x0e, 0x04, 0x0c, 0x01, 0x02, 0x20, 0x00, 0x75, 0x70, 0x00, 0x00, 0x48, 0x30, 0x48, 0x2a, 0x40,
0x80, 0x80, 0x45, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
};
return dimm[(device << 8) + address];
}
#define SMBUS_MEM_DEVICE_START 0x00
#define SMBUS_MEM_DEVICE_END 0x01
#define SMBUS_MEM_DEVICE_INC 1
/* Function 2 */
#define DRAM_CONFIG_HIGH 0x94
#define DCH_MEMCLK_SHIFT 20
#define DCH_MEMCLK_MASK 7
#define DCH_MEMCLK_100MHZ 0
#define DCH_MEMCLK_133MHZ 2
#define DCH_MEMCLK_166MHZ 5
#define DCH_MEMCLK_200MHZ 7
/* Function 3 */
#define NORTHBRIDGE_CAP 0xE8
#define NBCAP_128Bit 0x0001
#define NBCAP_MP 0x0002
#define NBCAP_BIG_MP 0x0004
#define NBCAP_ECC 0x0004
#define NBCAP_CHIPKILL_ECC 0x0010
#define NBCAP_MEMCLK_SHIFT 5
#define NBCAP_MEMCLK_MASK 3
#define NBCAP_MEMCLK_100MHZ 3
#define NBCAP_MEMCLK_133MHZ 2
#define NBCAP_MEMCLK_166MHZ 1
#define NBCAP_MEMCLK_200MHZ 0
#define NBCAP_MEMCTRL 0x0100
typedef unsigned char uint8_t;
typedef unsigned int uint32_t;
static unsigned spd_to_dimm(unsigned device)
{
return (device - SMBUS_MEM_DEVICE_START);
}
static void disable_dimm(unsigned index)
{
print_debug("disabling dimm");
print_debug_hex8(index);
print_debug("\r\n");
#if 0
pci_write_config32(PCI_DEV(0, 0x18, 2), DRAM_CSBASE + (((index << 1)+0)<<2), 0);
pci_write_config32(PCI_DEV(0, 0x18, 2), DRAM_CSBASE + (((index << 1)+1)<<2), 0);
#endif
}
struct mem_param {
uint8_t cycle_time;
uint32_t dch_memclk;
};
static const struct mem_param *get_mem_param(unsigned min_cycle_time)
{
static const struct mem_param speed[] = {
{
.cycle_time = 0xa0,
.dch_memclk = DCH_MEMCLK_100MHZ << DCH_MEMCLK_SHIFT,
},
{
.cycle_time = 0x75,
.dch_memclk = DCH_MEMCLK_133MHZ << DCH_MEMCLK_SHIFT,
},
{
.cycle_time = 0x60,
.dch_memclk = DCH_MEMCLK_166MHZ << DCH_MEMCLK_SHIFT,
},
{
.cycle_time = 0x50,
.dch_memclk = DCH_MEMCLK_200MHZ << DCH_MEMCLK_SHIFT,
},
{
.cycle_time = 0x00,
},
};
const struct mem_param *param;
for(param = &speed[0]; param->cycle_time ; param++) {
if (min_cycle_time > (param+1)->cycle_time) {
break;
}
}
if (!param->cycle_time) {
die("min_cycle_time to low");
}
return param;
}
#if 1
static void debug(int c)
{
print_debug_char(c);
print_debug_char('\r');
print_debug_char('\n');
}
#endif
static const struct mem_param *spd_set_memclk(void)
{
/* Compute the minimum cycle time for these dimms */
const struct mem_param *param;
unsigned min_cycle_time, min_latency;
unsigned device;
uint32_t value;
static const int latency_indicies[] = { 26, 23, 9 };
static const unsigned char min_cycle_times[] = {
[NBCAP_MEMCLK_200MHZ] = 0x50, /* 5ns */
[NBCAP_MEMCLK_166MHZ] = 0x60, /* 6ns */
[NBCAP_MEMCLK_133MHZ] = 0x75, /* 7.5ns */
[NBCAP_MEMCLK_100MHZ] = 0xa0, /* 10ns */
};
#if 0
value = pci_read_config32(PCI_DEV(0, 0x18, 3), NORTHBRIDGE_CAP);
#else
value = 0x50;
#endif
min_cycle_time = min_cycle_times[(value >> NBCAP_MEMCLK_SHIFT) & NBCAP_MEMCLK_MASK];
min_latency = 2;
#if 1
print_debug("min_cycle_time: ");
print_debug_hex8(min_cycle_time);
print_debug(" min_latency: ");
print_debug_hex8(min_latency);
print_debug("\r\n");
#endif
/* Compute the least latency with the fastest clock supported
* by both the memory controller and the dimms.
*/
for(device = SMBUS_MEM_DEVICE_START;
device <= SMBUS_MEM_DEVICE_END;
device += SMBUS_MEM_DEVICE_INC)
{
int new_cycle_time, new_latency;
int index;
int latencies;
int latency;
debug('A');
/* First find the supported CAS latencies
* Byte 18 for DDR SDRAM is interpreted:
* bit 0 == CAS Latency = 1.0
* bit 1 == CAS Latency = 1.5
* bit 2 == CAS Latency = 2.0
* bit 3 == CAS Latency = 2.5
* bit 4 == CAS Latency = 3.0
* bit 5 == CAS Latency = 3.5
* bit 6 == TBD
* bit 7 == TBD
*/
new_cycle_time = 0xa0;
new_latency = 5;
latencies = smbus_read_byte(device, 18);
if (latencies <= 0) continue;
debug('B');
/* Compute the lowest cas latency supported */
latency = log2(latencies) -2;
/* Loop through and find a fast clock with a low latency */
for(index = 0; index < 3; index++, latency++) {
int value;
debug('C');
if ((latency < 2) || (latency > 4) ||
(!(latencies & (1 << latency)))) {
continue;
}
debug('D');
value = smbus_read_byte(device, latency_indicies[index]);
if (value < 0) continue;
debug('E');
/* Only increase the latency if we decreas the clock */
if ((value >= min_cycle_time) && (value < new_cycle_time)) {
new_cycle_time = value;
new_latency = latency;
#if 1
print_debug("device: ");
print_debug_hex8(device);
print_debug(" new_cycle_time: ");
print_debug_hex8(new_cycle_time);
print_debug(" new_latency: ");
print_debug_hex8(new_latency);
print_debug("\r\n");
#endif
}
debug('G');
}
debug('H');
#if 1
print_debug("device: ");
print_debug_hex8(device);
print_debug(" new_cycle_time: ");
print_debug_hex8(new_cycle_time);
print_debug(" new_latency: ");
print_debug_hex8(new_latency);
print_debug("\r\n");
#endif
if (new_latency > 4){
continue;
}
debug('I');
/* Does min_latency need to be increased? */
if (new_cycle_time > min_cycle_time) {
min_cycle_time = new_cycle_time;
}
/* Does min_cycle_time need to be increased? */
if (new_latency > min_latency) {
min_latency = new_latency;
}
#if 1
print_debug("device: ");
print_debug_hex8(device);
print_debug(" min_cycle_time: ");
print_debug_hex8(min_cycle_time);
print_debug(" min_latency: ");
print_debug_hex8(min_latency);
print_debug("\r\n");
#endif
}
/* Make a second pass through the dimms and disable
* any that cannot support the selected memclk and cas latency.
*/
for(device = SMBUS_MEM_DEVICE_START;
device <= SMBUS_MEM_DEVICE_END;
device += SMBUS_MEM_DEVICE_INC)
{
int latencies;
int latency;
int index;
int value;
int dimm;
latencies = smbus_read_byte(device, 18);
if (latencies <= 0) {
goto dimm_err;
}
/* Compute the lowest cas latency supported */
latency = log2(latencies) -2;
/* Walk through searching for the selected latency */
for(index = 0; index < 3; index++, latency++) {
if (!(latencies & (1 << latency))) {
continue;
}
if (latency == min_latency)
break;
}
/* If I can't find the latency or my index is bad error */
if ((latency != min_latency) || (index >= 3)) {
goto dimm_err;
}
/* Read the min_cycle_time for this latency */
value = smbus_read_byte(device, latency_indicies[index]);
/* All is good if the selected clock speed
* is what I need or slower.
*/
if (value <= min_cycle_time) {
continue;
}
/* Otherwise I have an error, disable the dimm */
dimm_err:
disable_dimm(spd_to_dimm(device));
}
#if 1
print_debug("min_cycle_time: ");
print_debug_hex8(min_cycle_time);
print_debug(" min_latency: ");
print_debug_hex8(min_latency);
print_debug("\r\n");
#endif
/* Now that I know the minimum cycle time lookup the memory parameters */
param = get_mem_param(min_cycle_time);
#if 0
/* Update DRAM Config High with our selected memory speed */
value = pci_read_config32(PCI_DEV(0, 0x18, 2), DRAM_CONFIG_HIGH);
value &= ~(DCH_MEMCLK_MASK << DCH_MEMCLK_SHIFT);
value |= param->dch_memclk;
pci_write_config32(PCI_DEV(0, 0x18, 2), DRAM_CONFIG_HIGH, value);
static const unsigned latencies[] = { 1, 5, 2 };
/* Update DRAM Timing Low wiht our selected cas latency */
value = pci_read_config32(PCI_DEV(0, 0x18, 2), DRAM_CONFIG_LOW);
value &= ~7;
value |= latencies[min_latency - 2];
pci_write_config32(PCI_DEV(0, 0x18, 2), DRAM_CONFIG_LOW, value);
#endif
return param;
}
static void main(void)
{
const struct mem_param *param;
param = spd_set_memclk();
_exit(0);
}