blob: 1f7e47be95680280930671a188373cc0c00cb7b9 [file] [log] [blame]
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2004 Ronald G. Minnich
*
* 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; version 2 of the License.
*
* 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 "i82801dx.h"
#include <smbus.h>
#include <pci.h>
#include <arch/io.h>
#define PM_BUS 0
#define PM_DEVFN PCI_DEVFN(0x1f,3)
void smbus_enable(void)
{
unsigned char byte;
/* iobase addr */
pcibios_write_config_dword(PM_BUS, PM_DEVFN, 0x20, SMBUS_IO_BASE | 1);
/* smbus enable */
pcibios_write_config_byte(PM_BUS, PM_DEVFN, 0x40, 1);
/* iospace enable */
pcibios_write_config_word(PM_BUS, PM_DEVFN, 0x4, 1);
/* Disable interrupt generation */
outb(0, SMBUS_IO_BASE + SMBHSTCTL);
}
void smbus_setup(void)
{
outb(0, SMBUS_IO_BASE + SMBHSTSTAT);
}
static void smbus_wait_until_ready(void)
{
while ((inb(SMBUS_IO_BASE + SMBHSTSTAT) & 1) == 1) {
/* nop */
}
}
static void smbus_wait_until_done(void)
{
unsigned char byte;
do {
byte = inb(SMBUS_IO_BASE + SMBHSTSTAT);
}
while ((byte & 1) == 1);
while ((byte & ~1) == 0) {
byte = inb(SMBUS_IO_BASE + SMBHSTSTAT);
}
}
int smbus_read_byte(unsigned device, unsigned address, unsigned char *result)
{
unsigned char host_status_register;
unsigned char byte;
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 + SMBHSTADD);
/* 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);
/* read results of transaction */
byte = inb(SMBUS_IO_BASE + SMBHSTDAT0);
*result = byte;
return host_status_register != 0x02;
}