Rudolf Marek wrote: > Corey Osgood wrote: >> Corey Osgood wrote: >>> Rudolf Marek wrote: >>>> I'm attaching version which works for me (tm) >>>> // dimm &= 0x0E; >>>> // dimm |= 0xA1; >>> It works without those? Interesting. I'll try it in a few minutes, >>> see if it works here. >> >> Confirmed: this doesn't work with my board, it doesn't find the dimm at >> all, nor read any of the spd data correctly if forced to. Not quite sure >> why, but I'll investigate it further later. It might be this is done by >> the k8 code before it does smbus_read_byte()? > > Yes perhaps. Btw It seems that I need also a bit of warming up the chip > so it works correctly :/ I will investigate. Also It seems I'm stuck > with the PCI-E device mirroring on all addresses. I already programmed > all values to match award values and it still does not work :/ I signed > up for VIA datasheet, so we see what will happen. > > Rudolf > Attached is yet another version. In auto.c, put enable_smbus() before your serial init, then smbus_fixup() after the serial init, so smbus can be figuring itself out while the console is initializing. That should take care of any problems. And yes, I have actually tested this version first ;) You will need a DDR2 stick in slot 0 for it to work correctly, I'll fix it up later to work with regular DDR as well (I'm sure you can see how to fix it if you're using DDR). Again your changes (IO base and commenting that code) will be needed.
-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 */ /* * Datasheet: http://www.via.com.tw/en/downloads/datasheets/chipsets/ * VT8237R_SouthBridge_Revision2.06_Lead-Free.zip */ /* SMBus info: page 125, 137-139 */ #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 #define SMBUS_DELAY() outb(0x80, 0x80) /* 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 /* Internal functions */ 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(SMBHSTSTAT) & 1) == 1 && loops <= SMBUS_TIMEOUT) ++loops; smbus_print_error(inb(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); /* This messes up dump_spd_data() formatting. Very annoying */ //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); /* Rudolf says these aren't necessary. trying */ /* Seem necessary on my board... */ 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) { 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) { /* This won't work if enable_smbus() is before serial init */ 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); } static void smbus_fixup(void) { int c; unsigned int byte = 0x00; /* SMBus reads fail for ~22 reads without some fixup */ /* Read until we get the right data for a known byte */ /* This method has one major flaw: it needs DDR2 in DIMM0 */ PRINT_DEBUG("Waiting until SMBus ready"); for(c = 0; c < SMBUS_TIMEOUT && byte != 0x08; c++) { PRINT_DEBUG("."); byte = get_spd_data(0, 2); } if(c == SMBUS_TIMEOUT) { print_debug("SMBus error!\r\n"); } else { /* Will this cause any problems if DEBUG_SMBUS isn't defined? */ PRINT_DEBUG("Done!\r\n"); } } /* 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
