added spd scan for piix4e
This commit is contained in:
parent
b101440e7d
commit
cf7729a729
1 changed files with 298 additions and 0 deletions
298
util/scanspd/spd_piix4e.c
Normal file
298
util/scanspd/spd_piix4e.c
Normal file
|
|
@ -0,0 +1,298 @@
|
|||
#ifndef __KERNEL__
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#include <asm/io.h>
|
||||
|
||||
#ifndef __KERNEL__
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned long u32;
|
||||
|
||||
#define CONFIG_CMD(bus,devfn, where) (0x80000000 | (bus << 16) | (devfn << 8) | (where & ~3))
|
||||
|
||||
static int pci_conf1_write_config_byte(unsigned char bus, int devfn, int where, unsigned char value)
|
||||
{
|
||||
outl(CONFIG_CMD(bus,devfn,where), 0xCF8);
|
||||
outb(value, (0xCFC + (where&2)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pci_conf1_write_config_word(unsigned char bus, int devfn, int where, u16 value)
|
||||
{
|
||||
outl(CONFIG_CMD(bus,devfn,where), 0xCF8);
|
||||
outw(value, (0xCFC + (where&2)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pci_conf1_write_config_dword(unsigned char bus, int devfn, int where, u32 value)
|
||||
{
|
||||
outl(CONFIG_CMD(bus,devfn,where), 0xCF8);
|
||||
outl(value, 0xcfc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pci_conf1_read_config_word(unsigned char bus, int devfn, int where, u16 *value)
|
||||
{
|
||||
outl(CONFIG_CMD(bus,devfn,where), 0xCF8);
|
||||
*value = inw(0xCFC + (where&2));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pci_conf1_read_config_dword(unsigned char bus, int devfn, int where, u32 *value)
|
||||
{
|
||||
u32 retval;
|
||||
int i, j;
|
||||
outl(CONFIG_CMD(bus,devfn,where), 0xCF8);
|
||||
retval = inl(0xCFC);
|
||||
*value = retval;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#include <linux/pci.h>
|
||||
|
||||
/* Define register offsets */
|
||||
#define SMBHSTSTS 0x00
|
||||
#define SMBHSTCTL 0x02
|
||||
#define SMBHSTCMD 0x03 // Register tells what data to get
|
||||
#define SMBHSTADD 0x04
|
||||
#define SMBHSTDAT0 0x05
|
||||
#define SMBHSTDAT1 0x06
|
||||
#define SMBBLKDAT 0x07
|
||||
|
||||
/* Define register settings */
|
||||
#define HOST_RESET 0x8e
|
||||
#define DIMM_BASE 0xa0 // 1010000 is base for DIMM in SMBus
|
||||
#define READ_CMD 0x01 // 1 in the 0 bit of SMBHSTADD states to READ
|
||||
|
||||
/* Define SPD Data locations */
|
||||
#define MEM_TYPE 2 // Memory Type - EDO, FPM, SDRAM
|
||||
#define NUM_ROWS 3 // Number of Row Addresses
|
||||
#define NUM_COLS 4 // Number of Column Addresses
|
||||
#define NUM_MOD_ROWS 5 // Number of Module Rows
|
||||
#define CAS_LAT 18 // CAS Latencies Supported
|
||||
#define MOD_ATTR 21 // SDRAM Module Attributes
|
||||
#define BANK_DENSITY 31 // Module Bank Density
|
||||
#define SPD_REV 62 // SPD Revision
|
||||
#define SPEC_FREQ 126 // Specification Frequency - 66, 100, ...
|
||||
|
||||
inline void waitbusy(unsigned short baseaddr);
|
||||
inline int waitstatus(unsigned short baseaddr);
|
||||
int error_check(unsigned short baseaddr);
|
||||
|
||||
int main()
|
||||
{
|
||||
int devfn;
|
||||
unsigned short baseaddr;
|
||||
int dimm;
|
||||
int status;
|
||||
int data;
|
||||
int rows, density; // For RAM size calcs
|
||||
u32 val;
|
||||
int i;
|
||||
|
||||
iopl(3);
|
||||
// Find the PIIX4 Power Management function
|
||||
for (devfn = 0; devfn < 256; devfn++)
|
||||
{
|
||||
pci_conf1_read_config_dword(0, devfn, 0, &val);
|
||||
if (val == 0x71138086)
|
||||
break;
|
||||
}
|
||||
|
||||
if (devfn == 256)
|
||||
return(1);
|
||||
|
||||
// Get SMBus IO Base register
|
||||
pci_conf1_read_config_word(0, devfn, 0x90, &baseaddr);
|
||||
baseaddr &= 0xfff0;
|
||||
|
||||
printf("got devfn 0x%x baseaddr 0x%x\n", devfn, baseaddr);
|
||||
if (!baseaddr) // Still in default
|
||||
return(2);
|
||||
pci_conf1_write_config_word(0, devfn, 0xd2, (4<<1)|1);
|
||||
|
||||
/* Communicate on the SMBus through the SMBus IO Space Registers
|
||||
* See the System Management Bus Specification [1] for general
|
||||
* information about the bus. See the PIIX4 datasheet [2] for
|
||||
* information about the SMBus IO Space Registers (p. 148) */
|
||||
|
||||
waitbusy(baseaddr);
|
||||
|
||||
|
||||
for(i = 0x1; i < 0x100; i += 2) {
|
||||
if (i == 0xd3)
|
||||
continue;
|
||||
outb(HOST_RESET, baseaddr + SMBHSTSTS);
|
||||
outb(i, baseaddr + SMBHSTADD);
|
||||
outb(0x3, baseaddr + SMBHSTCMD);
|
||||
outb(0, baseaddr + SMBHSTDAT0);
|
||||
outb((2<<2)|(1<<6), baseaddr + SMBHSTCTL);
|
||||
|
||||
/* Check DIMM status once */
|
||||
status = waitstatus(baseaddr);
|
||||
printf("status 0x%x ", status);
|
||||
if (status == 4) {printf("no device at 0x%x\n", i);}
|
||||
else printf("device at 0x%x\n", i);
|
||||
}
|
||||
#if 0
|
||||
#endif
|
||||
|
||||
/* Select the DIMM chip to read SPD data (cycle through all of them) */
|
||||
|
||||
for (dimm = 0; dimm < 8; dimm++)
|
||||
{
|
||||
|
||||
/* Reset the controller status before using */
|
||||
outb(HOST_RESET, baseaddr + SMBHSTSTS);
|
||||
printf("DIMM #%d:\n", dimm);
|
||||
|
||||
/* Set up SPD for READ's */
|
||||
outb(DIMM_BASE | (dimm << 1) | READ_CMD, baseaddr + SMBHSTADD);
|
||||
|
||||
|
||||
/* For each piece of Data below, we select the data number in the
|
||||
Command Register (SBDHSTCMD) and tell the Control Register
|
||||
(SMBHSTCTL) we are reading a byte of data. Then grab the data from
|
||||
data register 0 (SMBHSTDAT0).
|
||||
*/
|
||||
|
||||
#if 0
|
||||
/* Specification Revision */
|
||||
outb(SPD_REV, baseaddr + SMBHSTCMD);
|
||||
outb(0x48, baseaddr + SMBHSTCTL);
|
||||
#endif
|
||||
|
||||
outb(0x3, baseaddr + SMBHSTCMD);
|
||||
outb(0, baseaddr + SMBHSTDAT0);
|
||||
outb((2<<2)|(1<<6), baseaddr + SMBHSTCTL);
|
||||
|
||||
/* Check DIMM status once */
|
||||
status = waitstatus(baseaddr);
|
||||
if (status & 0x04)
|
||||
{
|
||||
printf("No SPD present at DIMM\n\n");
|
||||
continue;
|
||||
}
|
||||
else if (error_check(baseaddr)) return (3);
|
||||
|
||||
data = inb(baseaddr + SMBHSTDAT0);
|
||||
printf("SPD Revision: %d.%d\n", (data & 0xf0) >> 4, data & 0x0f);
|
||||
|
||||
/* Memory Type */
|
||||
outb(HOST_RESET, baseaddr + SMBHSTSTS);
|
||||
outb(MEM_TYPE, baseaddr + SMBHSTCMD);
|
||||
outb(0x48, baseaddr + SMBHSTCTL);
|
||||
|
||||
if (error_check(baseaddr)) return(4);
|
||||
|
||||
data = inb(baseaddr + SMBHSTDAT0);
|
||||
switch(data)
|
||||
{
|
||||
case 0x02:
|
||||
{
|
||||
printf("DIMM #%d contains EDO\n", dimm);
|
||||
break;
|
||||
}
|
||||
case 0x04:
|
||||
{
|
||||
printf("DIMM #%d contains SDRAM\n", dimm);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
printf("DIMM %d contains unknown (0x%02X) type\n", dimm, data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Memory Size */
|
||||
|
||||
/* Start w/ number of module rows */
|
||||
outb(HOST_RESET, baseaddr + SMBHSTSTS);
|
||||
outb(NUM_MOD_ROWS, baseaddr + SMBHSTCMD);
|
||||
outb(0x48, baseaddr + SMBHSTCTL);
|
||||
|
||||
if (error_check(baseaddr)) return(5);
|
||||
|
||||
rows = inb(baseaddr + SMBHSTDAT0);
|
||||
if (rows == 0)
|
||||
{
|
||||
printf("Undefined number of rows");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("%d module rows on DIMM\n", rows);
|
||||
}
|
||||
|
||||
/* Now do size of row */
|
||||
outb(HOST_RESET, baseaddr + SMBHSTSTS);
|
||||
outb(BANK_DENSITY, baseaddr + SMBHSTCMD);
|
||||
outb(0x48, baseaddr + SMBHSTCTL);
|
||||
|
||||
if (error_check(baseaddr)) return(6);
|
||||
|
||||
density = inb(baseaddr + SMBHSTDAT0);
|
||||
switch (density)
|
||||
{
|
||||
case 0x01:
|
||||
case 0x02:
|
||||
case 0x04:
|
||||
case 0x08:
|
||||
case 0x10:
|
||||
case 0x20:
|
||||
case 0x40:
|
||||
case 0x80:
|
||||
{
|
||||
printf("DIMM has %dMByte per row.\n", density << 2);
|
||||
printf("DIMM has %dMByte total.\n", (density << 2) * rows);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
printf("DIMM has mixed memory per row.\n");
|
||||
printf("Unknown total memory.\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* Waitbusy... could possibly hang CPU, so insert timeout */
|
||||
inline void waitbusy (unsigned short baseaddr)
|
||||
{
|
||||
while(1)
|
||||
if ( !(inb(baseaddr + SMBHSTSTS) & 0x01) )
|
||||
return;
|
||||
}
|
||||
|
||||
/* waitstatus... could also hang CPU */
|
||||
inline int waitstatus (unsigned short baseaddr)
|
||||
{
|
||||
int status;
|
||||
|
||||
do
|
||||
status = inb(baseaddr + SMBHSTSTS);
|
||||
while ( (status & 0x01) != 0 || status == 0);
|
||||
|
||||
return (status);
|
||||
}
|
||||
|
||||
/* Error check for transaction errors */
|
||||
int error_check (unsigned short baseaddr)
|
||||
{
|
||||
int status;
|
||||
|
||||
status = waitstatus(baseaddr);
|
||||
if ( !(status & 0x02) )
|
||||
{
|
||||
printf("Transaction error 0x%02X\n", status);
|
||||
return(1);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue