I know this isn't your main problem, but I noticed that you're getting
error 44's from the smbus. The attached version should fix that, along
with a couple other issues (including the incorrect reports of a
timeout). I've also gotten rid of some of the debugging info, so it
shouldn't be filling up your screen unless there actually is a real
problem, or else if you want it. From what I can see, the
smbus_read_byte I've put in there should work, I'll rename get_spd_data
later, since it's now being used by my very incomplete CN700 code
(waiting on Via for datasheets sucks).
Also, the rest of your southbridge init is bound to be completely
borked, since IIRC that was well before I started seriously working on
the post-ram code, so it's probably still looking for some incorrect
device IDs, let alone setting things up right. If you want my most
recent stuff, let me know, it should actually work right now.
And yes, there will be a patch with this and the rest of the southbridge
code when the whole thing is clean and tested.
-Corey
/*
* This file is part of the LinuxBIOS project.
*
* 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
*/
#define SMBUS_IO_BASE 0x0500 //from award bios
/* With this, is SMBUS_IO_BASE added during compile or runtime? */
#define SMBHSTSTAT SMBUS_IO_BASE + 0x0
#define SMBSLVSTAT SMBUS_IO_BASE + 0x1
#define SMBHSTCTL SMBUS_IO_BASE + 0x2
#define SMBHSTCMD SMBUS_IO_BASE + 0x3
#define SMBXMITADD SMBUS_IO_BASE + 0x4
#define SMBHSTDAT0 SMBUS_IO_BASE + 0x5
/* Rest of these aren't used... */
#define SMBHSTDAT1 SMBUS_IO_BASE + 0x6
#define SMBBLKDAT SMBUS_IO_BASE + 0x7
#define SMBSLVCTL SMBUS_IO_BASE + 0x8
#define SMBTRNSADD SMBUS_IO_BASE + 0x9
#define SMBSLVDATA SMBUS_IO_BASE + 0xa
#define SMLINK_PIN_CTL SMBUS_IO_BASE + 0xe
#define SMBUS_PIN_CTL SMBUS_IO_BASE + 0xf
/* Define register settings */
#define HOST_RESET 0xff
#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 SMBUS_TIMEOUT (100*1000*10)
#define I2C_TRANS_CMD 0x40
#define CLOCK_SLAVE_ADDRESS 0x69
/* Debugging macros. Only necessary if something isn't working right */
//#define DEBUG_SMBUS = 1
#ifdef DEBUG_SMBUS
#define PRINT_DEBUG(x) print_debug(x)
#define PRINT_DEBUG_HEX16(x) print_debug_hex16(x)
#else
#define PRINT_DEBUG(x)
#define PRINT_DEBUG_HEX16(x)
#endif
/* TODO: datasheet link here */
/* See datasheet pages 125 and 137-139 */
/* Internal functions */
/* TODO: make define? */
#define SMBUS_DELAY() outb(0x80, 0x80)
static void smbus_print_error(unsigned char host_status_register, int loops)
{
/* Check if there actually was an error */
if ( host_status_register == 0x00 || host_status_register == 0x40 ||
host_status_register == 0x42) return;
print_err("smbus_error: ");
print_err_hex8(host_status_register);
print_err("\r\n");
if (loops >= SMBUS_TIMEOUT) {
print_err("SMBus Timout\r\n");
}
if (host_status_register & (1 << 4)) {
print_err("Interrup/SMI# was Failed Bus Transaction\r\n");
}
if (host_status_register & (1 << 3)) {
print_err("Bus Error\r\n");
}
if (host_status_register & (1 << 2)) {
print_err("Device Error\r\n");
}
if (host_status_register & (1 << 1)) {
print_err("Interrupt/SMI# was Successful Completion\r\n");
}
if (host_status_register & (1 << 0)) {
print_err("Host Busy\r\n");
}
}
static void smbus_wait_until_ready(void)
{
int loops;
PRINT_DEBUG("Waiting until smbus ready\r\n");
loops = 0;
/* Yes, this is a mess, but it's the easiest way to do it */
while((inb(SMBUS_IO_BASE + SMBHSTSTAT) & 1) == 1 && loops <= SMBUS_TIMEOUT)
++loops;
smbus_print_error(inb(SMBUS_IO_BASE + SMBHSTSTAT), loops);
}
static void smbus_reset(void)
{
/* four resets? a little overboard? or just frustrated? */
outb(HOST_RESET, SMBHSTSTAT);
#if 0
outb(HOST_RESET, SMBHSTSTAT);
outb(HOST_RESET, SMBHSTSTAT);
outb(HOST_RESET, SMBHSTSTAT);
#endif
/* Datasheet says we have to read it to take ownership of SMBus */
inb(SMBHSTSTAT);
PRINT_DEBUG("After reset status: ");
PRINT_DEBUG_HEX16( inb(SMBHSTSTAT));
PRINT_DEBUG("\r\n");
}
/* Public functions */
static unsigned int get_spd_data(unsigned int dimm, unsigned int offset)
{
unsigned int val;
smbus_reset();
/* clear host data port */
outb(0x00, SMBHSTDAT0);
SMBUS_DELAY();
smbus_wait_until_ready();
/* Do some mathmatic magic */
dimm = (dimm << 1);
dimm &= 0x0E;
dimm |= 0xA1;
outb(dimm, SMBXMITADD);
outb(offset, SMBHSTCMD);
outb(0x48, SMBHSTCTL);
SMBUS_DELAY();
smbus_wait_until_ready();
val = inb(SMBHSTDAT0);
smbus_reset(); /* probably don't have to do this, but it can't hurt */
return val; /* can I just "return inb(SMBHSTDAT0)"? */
}
static unsigned int smbus_read_byte(unsigned int dimm, unsigned int offset)
{
unsigned int data;
data = get_spd_data(dimm, offset);
return data;
}
static void enable_smbus(void)
{
int c;
device_t dev;
/* Power management controller */
/* This should work, but there are more important things to work on */
/* dev = PCI_DEV(0, 0x11, 0); */
dev = pci_locate_device(PCI_ID(0x1106, 0x3227), 0);
if (dev == PCI_DEV_INVALID)
{
die("Power Managment Controller not found\r\n");
}
/* Set clock source */
pci_write_config8(dev, 0x94, 0xa0);
/* Write SMBus IO base to 0xd0, and enable SMBus */
pci_write_config16(dev, 0xd0, SMBUS_IO_BASE | 1);
/* Set to Award value */
pci_write_config8(dev, 0xd2, 0x01);
/* make it work for I/O ...*/
pci_write_config16(dev, 0x04, 0x0001);
/* SMBus reads 0 the first 22 offsets. Lets see if this helps */
/* Putting enable_smbus() earlier in auto.c could also help */
/* The original plan was to use one or the other of these. Neither worked
* by itself, but both together seems to work. Play with it more later */
/* We're incurring lots of delay here. Oh well, it's necessary */
for(c = 0; c < 5000; c++)
{
smbus_reset();
SMBUS_DELAY();
}
/* The other, slightly hackish, fixup method */
for(c = 0; c < 30; c++) get_spd_data(0, c);
}
/* Debugging Function */
#ifdef DEBUG_SMBUS
static void dump_spd_data(void)
{
int dimm, offset, regs;
unsigned int val;
for(dimm = 0; dimm < 8; dimm++)
{
print_debug("SPD Data for DIMM ");
print_debug_hex8(dimm);
print_debug("\r\n");
val = get_spd_data(dimm, 0);
if(val == 0xff)
{
regs = 256;
} else if(val == 0x80) {
regs = 128;
} else {
print_debug("No DIMM present\r\n");
regs = 0;
}
for(offset = 0; offset < regs; offset++)
{
print_debug(" Offset ");
print_debug_hex8(offset);
print_debug(" = 0x");
print_debug_hex8(get_spd_data(dimm, offset));
print_debug("\r\n");
}
}
}
#else
#define dump_spd_data()
#endif
--
linuxbios mailing list
[EMAIL PROTECTED]
http://www.linuxbios.org/mailman/listinfo/linuxbios