Add stage1 support for vt8237[RS] to v3.

Signed-off-by: Corey Osgood <corey.osgood@gmail.com>
Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>



git-svn-id: svn://coreboot.org/repository/coreboot-v3@928 f3766cd6-281f-0410-b1cd-43a5c92072e9
This commit is contained in:
Corey Osgood 2008-10-14 18:26:09 +00:00
commit 2dd3477242
3 changed files with 433 additions and 0 deletions

View file

@ -0,0 +1,25 @@
##
## This file is part of the coreboot project.
##
## Copyright (C) 2008 Corey Osgood <corey.osgood@gmail.com>
##
## 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
##
ifeq ($(CONFIG_SOUTHBRIDGE_VIA_VT8237),y)
STAGE2_CHIPSET_SRC +=
endif

View file

@ -0,0 +1,318 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2007-2008 Corey Osgood <corey.osgood@gmail.com>
* Copyright (C) 2007 Rudolf Marek <r.marek@assembler.cz>
*
* 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
*/
#include <types.h>
#include <lib.h>
#include <console.h>
#include <device/pci.h>
#include <io.h>
#include <device/pci_ids.h>
#include <spd.h>
#include "vt8237.h"
/* TODO List:
* * Merge the rest of the functions from v2, except smbus_fixup which doesn't
* seem to be necessary any more (?)
* * Clean up vt8237_early_network_init.
* Comments in code indicate that it's broken?
* * Figure out if the smbus actually needs to be reset after every transaction.
*/
/**
* Print an error, should it occur. If no error, just exit.
*
* @param host_status The data returned on the host status register after
* a transaction is processed.
* @param loops The number of times a transaction was attempted.
*/
static void smbus_print_error(u8 host_status, int loops)
{
/* Check if there actually was an error. */
if ((host_status == 0x00 || host_status == 0x40 ||
host_status == 0x42) && (loops < SMBUS_TIMEOUT))
{
printk(BIOS_SPEW, "SMBus Ready/Completed Successfully\n");
return;
}
if (loops >= SMBUS_TIMEOUT)
printk(BIOS_ERR, "SMBus Timed out\n");
if (host_status & (1 << 4))
printk(BIOS_ERR, "Interrupt/SMI# was Failed Bus Transaction\n");
if (host_status & (1 << 3))
printk(BIOS_ERR, "Bus error\n");
if (host_status & (1 << 2))
printk(BIOS_ERR, "Device error\n");
if (host_status & (1 << 1))
printk(BIOS_SPEW, "Interrupt/SMI# completed successfully\n");
if (host_status & (1 << 0))
printk(BIOS_ERR, "Host busy\n");
}
/**
* Reset and take ownership of the SMBus.
*/
static void smbus_reset(u16 smbus_io_base)
{
outb(HOST_RESET, smbus_io_base + SMBHSTSTAT);
/* Datasheet says we have to read it to take ownership of SMBus. */
smbus_print_error(inb(smbus_io_base + SMBHSTSTAT), 0);
}
/**
* Wait for the SMBus to become ready to process the next transaction.
*/
static void smbus_wait_until_ready(u16 smbus_io_base)
{
int loops;
printk(BIOS_SPEW, "Waiting until SMBus ready\n");
loops = 0;
while ((inb(smbus_io_base + SMBHSTSTAT) & 1) == 1 && loops <= SMBUS_TIMEOUT)
++loops;
smbus_print_error(inb(smbus_io_base + SMBHSTSTAT), loops);
}
/**
* Read a byte from the SMBus.
*
* @param dimm The address location of the DIMM on the SMBus.
* @param offset The offset the data is located at.
*/
u8 smbus_read_byte(u16 dimm, u8 offset, u16 smbus_io_base)
{
u8 val;
printk(BIOS_SPEW, "SMBus Read from DIMM %d at address 0x%x\n",
(int)dimm, offset);
smbus_reset(smbus_io_base);
/* Clear host data port. */
outb(0x00, smbus_io_base + SMBHSTDAT0);
/* Doesn't seem to be necessary...*/
/* udelay(1); */
smbus_wait_until_ready(smbus_io_base);
/* With this, addresses are 0x50, 0x51, etc. Without it,
* addresses would be 0xa1, 0xa3, etc */
dimm = (dimm << 1) | 1;
outb(dimm, smbus_io_base + SMBXMITADD);
outb(offset, smbus_io_base + SMBHSTCMD);
/* Start transaction, byte data read. */
outb(0x48, smbus_io_base + SMBHSTCTL);
/* udelay(1); */
smbus_wait_until_ready(smbus_io_base);
val = inb(smbus_io_base + SMBHSTDAT0);
printk(BIOS_SPEW, "Read: 0x%x\n", val);
/* TODO: Is this necessary? */
smbus_reset(smbus_io_base);
return val;
}
/**
* Enable the smbus on vt8237-based systems
*
* @param smbus_io_base: The SMBus I/O base, usually 0x400
*/
void enable_smbus(u16 smbus_io_base)
{
u32 dev;
/* Power management controller */
pci_conf1_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT8237R_LPC,
&dev);
if (!dev) {
/* Power management controller */
pci_conf1_find_device(PCI_VENDOR_ID_VIA,
PCI_DEVICE_ID_VIA_VT8237S_LPC, &dev);
if (!dev)
{
printk(BIOS_ERR, "Power management controller not "
"found! Using hardcoded default.\n");
dev = PCI_BDF(0, 17, 0);
} else {
printk(BIOS_DEBUG, "VT8237S Power management "
"controller found at 0x%x\n", dev);
}
} else {
printk(BIOS_DEBUG, "VT8237R Power management controller found "
"at 0x%x\n", dev);
}
/* 7 = SMBus Clock from RTC 32.768KHz
* 5 = Internal PLL reset from susp
*/
pci_conf1_write_config8(dev, VT8237R_POWER_WELL, 0xa0);
/* Enable SMBus. */
pci_conf1_write_config16(dev, VT8237R_SMBUS_IO_BASE_REG,
smbus_io_base | 0x1);
/* SMBus Host Configuration, enable. */
pci_conf1_write_config8(dev, VT8237R_SMBUS_HOST_CONF, 0x01);
/* Make it work for I/O. */
pci_conf1_write_config16(dev, PCI_COMMAND, PCI_COMMAND_IO);
/* reset smbus */
smbus_reset(smbus_io_base);
/* Reset the internal pointer. */
inb(smbus_io_base + SMBHSTCTL);
}
/* TODO:
* Magic numbers -> #defines
* fix?
* clean up
*/
/* offset 0x58
* 31:20 reserved
* 19:16 4 bit position in shadow EEPROM
* 15:0 data to write
*
* offset 0x5c
* 31:28 reserved
* 27 ERDBG - enable read from 0x5c
* 26 reserved
* 25 SEELD
* 24 SEEPR - write 1 when done updating, wait until SEELD is set to 1, sticky
* cleared by reset, if it is 1 writing is disabled
* 19:16 4 bit position in shadow EEPROM
* 15:0 data from shadow EEPROM
*
* after PCIRESET SEELD and SEEPR must be 1 and 1
*/
/* 1 = needs PCI reset, 0 don't reset, network initialized */
/* fixme maybe close the debug register after use? */
#define LAN_TIMEOUT 0x7FFFFFFF
int vt8237_early_network_init(struct vt8237_network_rom *rom) {
struct vt8237_network_rom n;
int loops = 0;
u32 dev;
u32 tmp;
u8 status;
u16 *rom_write;
unsigned int checksum;
int i;
/* Network adapter */
pci_conf1_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT8237_LAN,
&dev);
if (!dev) {
printk(BIOS_ERR, "Network is disabled, please enable\n");
return 0;
}
tmp = pci_conf1_read_config32(dev, 0x5c);
/* enable ERDBG */
tmp |= 0x08000000;
pci_conf1_write_config32(dev, 0x5c, tmp);
status = ((pci_conf1_read_config32(dev, 0x5c) >> 24) & 0x3);
if (status == 3) {
/* network controller OK, EEPROM loaded */
return 0;
}
if (rom == NULL) {
printk(BIOS_ERR, "No configuration data specified, using default MAC!\n");
n.mac_address[0] = 0x0;
n.mac_address[1] = 0x0;
n.mac_address[2] = 0xde;
n.mac_address[3] = 0xad;
n.mac_address[4] = 0xbe;
n.mac_address[5] = 0xef;
n.phy_addr = 0x1;
n.res1 = 0x0;
n.sub_sid = 0x102;
n.sub_vid = 0x1106;
n.pid = 0x3065;
n.vid = 0x1106;
n.pmcc = 0x1f;
n.data_sel = 0x10;
n.pmu_data_reg = 0x0;
n.aux_curr = 0x0;
n.reserved = 0x0;
n.min_gnt = 0x3;
n.max_lat = 0x8;
n.bcr0 = 0x9;
n.bcr1 = 0xe;
n.cfg_a = 0x3;
n.cfg_b = 0x0;
n.cfg_c = 0x40;
n.cfg_d = 0x82;
n.checksum = 0x0;
rom = &n;
}
rom_write = (u16 *) rom;
checksum = 0;
/* write all data except checksum and second to last byte */
tmp &= 0xff000000; /* leave reserved bits in */
for (i = 0; i < 15; i++) {
pci_conf1_write_config32(dev, 0x58, tmp | (i << 16) | rom_write[i]);
/* lame code fixme */
checksum += rom_write[i] & 0xff;
//checksum %= 256;
checksum += (rom_write[i] >> 8) & 0xff;
//checksum %= 256;
}
checksum += (rom_write[15] & 0xff);
checksum = ~(checksum & 0xff);
tmp |= (((checksum & 0xff) << 8) | rom_write[15]);
/* write last byte and checksum */
pci_conf1_write_config32(dev, 0x58, (15 << 16) | tmp);
tmp = pci_conf1_read_config32(dev, 0x5c);
pci_conf1_write_config32(dev, 0x5c, tmp | 0x01000000); /* toggle SEEPR */
/* Yes, this is a mess, but it's the easiest way to do it. */
while ( (((pci_conf1_read_config32(dev, 0x5c) >> 25) & 1) == 0)
&& (loops < LAN_TIMEOUT))
++loops;
if (loops >= LAN_TIMEOUT) {
printk(BIOS_ERR, "Timout - LAN controller did not accept configuration\n");
return 0;
}
/* we are done, config will be used after PCIRST# */
return 1;
}

View file

@ -0,0 +1,90 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2007 Rudolf Marek <r.marek@assembler.cz>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License v2 as published by
* the Free Software Foundation.
*
* 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
*/
#ifndef SOUTHBRIDGE_VIA_VT8237_VT8237_H
#define SOUTHBRIDGE_VIA_VT8237_VT8237_H
#include <types.h>
/* Static resources for the VT8237R southbridge */
#define VT8237R_APIC_ID 0x2
#define VT8237R_ACPI_IO_BASE 0x500
/* 0x0 disabled, 0x2 reserved, 0xf = IRQ15 */
#define VT8237R_ACPI_IRQ 0x9
#define VT8237S_SPI_MEM_BASE 0xfed02000ULL
#define VT8237R_HPET_ADDR 0xfed00000ULL
#define VT8237R_APIC_BASE 0xfec00000ULL
/* IDE */
#define IDE_CS 0x40
#define IDE_CONF_I 0x41
#define IDE_CONF_II 0x42
#define IDE_CONF_FIFO 0x43
#define IDE_MISC_I 0x44
#define IDE_MISC_II 0x45
#define IDE_UDMA 0x50
/* SMBus */
#define VT8237R_POWER_WELL 0x94
#define VT8237R_SMBUS_IO_BASE_REG 0xd0
#define VT8237R_SMBUS_HOST_CONF 0xd2
#define SMBHSTSTAT 0x0
#define SMBSLVSTAT 0x1
#define SMBHSTCTL 0x2
#define SMBHSTCMD 0x3
#define SMBXMITADD 0x4
#define SMBHSTDAT0 0x5
#define HOST_RESET 0xff
/* 1 in the 0 bit of SMBHSTADD states to READ. */
#define READ_CMD 0x01
#define SMBUS_TIMEOUT (100 * 1000 * 10)
#define I2C_TRANS_CMD 0x40
#define CLOCK_SLAVE_ADDRESS 0x69
struct vt8237_network_rom {
u8 mac_address[6];
u8 phy_addr;
u8 res1;
u16 sub_sid;
u16 sub_vid;
u16 pid;
u16 vid;
u8 pmcc;
u8 data_sel;
u8 pmu_data_reg;
u8 aux_curr;
u16 reserved;
u8 min_gnt;
u8 max_lat;
u8 bcr0;
u8 bcr1;
u8 cfg_a;
u8 cfg_b;
u8 cfg_c;
u8 cfg_d;
u8 checksum;
} __attribute__ ((packed));
void enable_smbus(u16);
u8 smbus_read_byte(u16, u8, u16);
#endif