First cut at utilities to scan spd.

This commit is contained in:
Ronald G. Minnich 2002-03-25 05:14:21 +00:00
parent 68b925b9a4
commit b101440e7d
4 changed files with 331 additions and 0 deletions

12
util/scanspd/Makefile Normal file
View file

@ -0,0 +1,12 @@
LINUXBIOS=../../
CFLAGS += -O2 -g
LDFLAGS += -g
INCLUDE=
spd_82801: spd_82801.o pcibios.o
spd_82801.o: spd_82801.c
cc -g -I. -O2 -c -o $@ $<
clean:
rm -f *.o spd_82801

3
util/scanspd/README Normal file
View file

@ -0,0 +1,3 @@
In here are programs to scan SPD dram for various chip types.
ron

54
util/scanspd/pcibios.c Normal file
View file

@ -0,0 +1,54 @@
#include <stdio.h>
#include <asm/io.h>
typedef unsigned short u16;
typedef unsigned long u32;
#define CONFIG_CMD(bus,devfn, where) (0x80000000 | (bus << 16) | (devfn << 8) | (where & ~3))
int pcibios_write_config_byte(unsigned char bus, int devfn, int where, unsigned char value)
{
outl(CONFIG_CMD(bus,devfn,where&0xfc), 0xCF8);
outb(value, (0xCFC + (where&2)));
return 0;
}
int pcibios_write_config_word(unsigned char bus, int devfn, int where, u16 value)
{
outl(CONFIG_CMD(bus,devfn,where&0xfc), 0xCF8);
outw(value, (0xCFC + (where&2)));
return 0;
}
int pcibios_write_config_dword(unsigned char bus, int devfn, int where, u32 value)
{
outl(CONFIG_CMD(bus,devfn,where&0xfc), 0xCF8);
outl(value, 0xcfc);
return 0;
}
int pcibios_read_config_byte(unsigned char bus, int devfn, int where, unsigned char *value)
{
outl(CONFIG_CMD(bus,devfn,(where&0xfc)), 0xCF8);
*value = inw(0xCFC + (where&2));
return 0;
}
int pcibios_read_config_word(unsigned char bus, int devfn, int where, u16 *value)
{
outl(CONFIG_CMD(bus,devfn,where&0xfc), 0xCF8);
*value = inw(0xCFC + (where&2));
return 0;
}
int pcibios_read_config_dword(unsigned char bus, int devfn, int where, u32 *value)
{
u32 retval;
int i, j;
outl(CONFIG_CMD(bus,devfn,where&0xfc), 0xCF8);
retval = inl(0xCFC);
*value = retval;
return 0;
}

262
util/scanspd/spd_82801.c Normal file
View file

@ -0,0 +1,262 @@
#include <errno.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/io.h>
#include <unistd.h>
#include <stdio.h>
/* * $Id$*/
/*
* 82801Support code by Eric Beiderman of lnxi.com
*/
#if 0
#include <smbus.h>
#include <arch/io.h>
#include <pci.h>
#include <southbridge/intel/82801.h>
#include "82801.h"
#endif
int smbus_io_base;
int smbus_devfn;
#define SMBUS_BUS 0
#define SMBHSTSTAT 0x0
#define SMBHSTCTL 0x2
#define SMBHSTCMD 0x3
#define SMBXMITADD 0x4
#define SMBHSTDAT0 0x5
#define SMBHSTDAT1 0x6
#define SMBBLKDAT 0x7
#define SMBTRNSADD 0x9
#define SMBSLVDATA 0xa
#define SMLINK_PIN_CTL 0xe
#define SMBUS_PIN_CTL 0xf
/* Define register settings */
#define HOST_RESET 0xfe
#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
void smbus_setup(void)
{
pcibios_read_config_dword(SMBUS_BUS, smbus_devfn, 0x20,
&smbus_io_base);
smbus_io_base &= ~3;
pcibios_write_config_byte(SMBUS_BUS, smbus_devfn, 0x40, 1);
pcibios_write_config_word(SMBUS_BUS, smbus_devfn, 0x4, 1);
}
static void smbus_wait_until_ready(void)
{
volatile unsigned char c;
c = inb(smbus_io_base + SMBHSTSTAT);
while((c & 1) == 1) {
printf("c is 0x%x\n", c);
c = inb(smbus_io_base + SMBHSTSTAT);
/* nop */
}
}
void reset(void)
{
outb(HOST_RESET, smbus_io_base + SMBHSTSTAT);
outb(HOST_RESET, smbus_io_base + SMBHSTSTAT);
outb(HOST_RESET, smbus_io_base + SMBHSTSTAT);
outb(HOST_RESET, smbus_io_base + SMBHSTSTAT);
smbus_wait_until_ready();
printf("After reset status %#x\n", inb(smbus_io_base + SMBHSTSTAT));
}
static void smbus_wait_until_done(void)
{
unsigned char byte;
unsigned long giveup;
do {
byte = inb(smbus_io_base + SMBHSTSTAT);
giveup++;
if (giveup > 1000000)
return;
} while((byte &1) == 1);
while( (byte & ~((1<<6)|(1<<0))) == 0) {
byte = inb(smbus_io_base + SMBHSTSTAT);
}
}
static void smbus_print_error(unsigned char host_status_register)
{
printf("smbus_error: 0x%02x\n", host_status_register);
if (host_status_register & (1 << 7)) {
printf("Byte Done Status\n");
}
if (host_status_register & (1 << 6)) {
printf("In Use Status\n");
}
if (host_status_register & (1 << 5)) {
printf("SMBus Alert Status\n");
}
if (host_status_register & (1 << 4)) {
printf("Interrup/SMI# was Failed Bus Transaction\n");
}
if (host_status_register & (1 << 3)) {
printf("Bus Error\n");
}
if (host_status_register & (1 << 2)) {
printf("Device Error\n");
}
if (host_status_register & (1 << 1)) {
printf("Interrupt/SMI# was Successful Completion\n");
}
if (host_status_register & (1 << 0)) {
printf("Host Busy\n");
}
}
int smbus_read_byte(unsigned device, unsigned address, unsigned char *result)
{
unsigned char host_status_register;
unsigned char byte;
reset();
smbus_wait_until_ready();
/* setup transaction */
/* disable interrupts */
outb(inb(smbus_io_base + SMBHSTCTL) & (~1), smbus_io_base + SMBHSTCTL);
/* set the device I'm talking too */
outb(((device & 0x7f) << 1) | 1, smbus_io_base + SMBXMITADD);
/* set the command/address... */
outb(address & 0xFF, smbus_io_base + SMBHSTCMD);
/* set up for a byte data read */
outb((inb(smbus_io_base + SMBHSTCTL) & 0xE3) | (0x2 << 2),
smbus_io_base + SMBHSTCTL);
/* clear any lingering errors, so the transaction will run */
outb(inb(smbus_io_base + SMBHSTSTAT), smbus_io_base + SMBHSTSTAT);
/* clear the data byte...*/
outb(0, smbus_io_base + SMBHSTDAT0);
/* start the command */
outb((inb(smbus_io_base + SMBHSTCTL) | 0x40),
smbus_io_base + SMBHSTCTL);
/* poll for transaction completion */
smbus_wait_until_done();
host_status_register = inb(smbus_io_base + SMBHSTSTAT);
/* Ignore the In Use Status... */
host_status_register &= ~(1 << 6);
/* read results of transaction */
byte = inb(smbus_io_base + SMBHSTDAT0);
smbus_print_error(byte);
*result = byte;
return host_status_register != 0x02;
}
/*
* Scan SPD bus
*
*
* Derived from ...
* Copyright 2000 Silicon Integrated System Corporation
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*
* Reference:
* 1. SiS 630 Specification
*
*/
unsigned short acpi_base;
unsigned char
read_spd(unsigned char slot, unsigned char index)
{
unsigned char value;
smbus_read_byte(0xA1 + (slot << 1), index, &value);
return value;
}
main()
{
unsigned char b;
unsigned short w;
int slot;
/* get io privilege access PCI configuration space */
if (iopl(3) != 0) {
perror("Can not set io priviliage");
exit(1);
}
// Find the 801
for (smbus_devfn = 0; smbus_devfn < 256; smbus_devfn++)
{
unsigned long val;
pcibios_read_config_dword(0, smbus_devfn, 0, &val);
if (val == 0x24438086)
break;
}
if (smbus_devfn == 256) {
printf("smbus_devfn not found!\n");
return(1);
}
smbus_setup();
reset();
for(slot = 1; slot < 0xff; slot += 2) {
unsigned char val;
if (slot == 0x6a)
continue;
smbus_read_byte(slot, 0, &val);
printf("slot 0x%x val 0x%x\n", slot, val);
}
for(slot = 0; slot < 4; slot++) {
printf("SLOT %d\n", slot);
printf("Number of bytes used by module manufacturer 0x%02x\n",
read_spd(slot, 0x00));
printf("Memory Type 0x%02x\n",
read_spd(slot, 0x02));
printf("Number of Row Address bits 0x%02x\n",
read_spd(slot, 0x03));
printf("Number of Column Address bits 0x%02x\n",
read_spd(slot, 0x04));
printf("Number of Sides 0x%02x\n",
read_spd(slot, 0x05));
printf("Number of Banks 0x%02x\n",
read_spd(slot, 0x11));
}
}