sb/intel/*: Use common SMBus functions
All Intel southbridges implement the same SMBus functions. This patch replaces all these similar and mostly identical implementations with a common file. This also makes i2c block read available to all those southbridges. If the northbridge has to read a lot of SPD bytes sequentially, using this function can reduce the time being spent to read SPD five-fold. Change-Id: I93bb186e04e8c32dff04fc1abe4b5ecbc4c9c962 Signed-off-by: Arthur Heymans <arthur@aheymans.xyz> Reviewed-on: https://review.coreboot.org/19258 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Kyösti Mälkki <kyosti.malkki@gmail.com>
This commit is contained in:
parent
12d010306b
commit
16fe79048f
|
@ -5,5 +5,6 @@
|
|||
#define SMBUS_ERROR -1
|
||||
#define SMBUS_WAIT_UNTIL_READY_TIMEOUT -2
|
||||
#define SMBUS_WAIT_UNTIL_DONE_TIMEOUT -3
|
||||
#define SMBUS_WAIT_UNTIL_ACTIVE_TIMEOUT -4
|
||||
|
||||
#endif /* DEVICE_SMBUS_DEF_H */
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
#include <timestamp.h>
|
||||
#include <northbridge/intel/common/mrc_cache.h>
|
||||
#include <southbridge/intel/bd82x6x/me.h>
|
||||
#include <southbridge/intel/bd82x6x/smbus.h>
|
||||
#include <southbridge/intel/common/smbus.h>
|
||||
#include <cpu/x86/msr.h>
|
||||
#include <delay.h>
|
||||
#include <smbios.h>
|
||||
|
|
|
@ -25,6 +25,7 @@ config SOUTH_BRIDGE_OPTIONS # dummy
|
|||
def_bool y
|
||||
select ACPI_INTEL_HARDWARE_SLEEP_VALUES
|
||||
select SOUTHBRIDGE_INTEL_COMMON
|
||||
select SOUTHBRIDGE_INTEL_COMMON_SMBUS
|
||||
select IOAPIC
|
||||
select HAVE_HARD_RESET
|
||||
select HAVE_USBDEBUG_OPTIONS
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
#include <console/console.h>
|
||||
#include <device/pci_ids.h>
|
||||
#include <device/pci_def.h>
|
||||
#include <southbridge/intel/common/smbus.h>
|
||||
#include "pch.h"
|
||||
#include "smbus.h"
|
||||
|
||||
void enable_smbus(void)
|
||||
{
|
||||
|
|
|
@ -265,22 +265,6 @@ early_usb_init (const struct southbridge_usb_port *portmap);
|
|||
#define SMB_SMI_EN (1 << 1)
|
||||
#define HST_EN (1 << 0)
|
||||
|
||||
/* SMBus I/O bits. */
|
||||
#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 SMBUS_TIMEOUT (10 * 1000 * 100)
|
||||
|
||||
|
||||
/* Southbridge IO BARs */
|
||||
|
||||
#define GPIOBASE 0x48
|
||||
|
|
|
@ -22,8 +22,8 @@
|
|||
#include <device/pci_ids.h>
|
||||
#include <device/pci_ops.h>
|
||||
#include <arch/io.h>
|
||||
#include <southbridge/intel/common/smbus.h>
|
||||
#include "pch.h"
|
||||
#include "smbus.h"
|
||||
|
||||
static void pch_smbus_init(device_t dev)
|
||||
{
|
||||
|
@ -54,49 +54,6 @@ static int lsmbus_read_byte(device_t dev, u8 address)
|
|||
return do_smbus_read_byte(res->base, device, address);
|
||||
}
|
||||
|
||||
static int do_smbus_write_byte(unsigned smbus_base, unsigned device, unsigned address, unsigned data)
|
||||
{
|
||||
unsigned char global_status_register;
|
||||
|
||||
if (smbus_wait_until_ready(smbus_base) < 0)
|
||||
return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
|
||||
|
||||
/* Setup transaction */
|
||||
/* Disable interrupts */
|
||||
outb(inb(smbus_base + SMBHSTCTL) & (~1), smbus_base + SMBHSTCTL);
|
||||
/* Set the device I'm talking too */
|
||||
outb(((device & 0x7f) << 1) & ~0x01, smbus_base + SMBXMITADD);
|
||||
/* Set the command/address... */
|
||||
outb(address & 0xff, smbus_base + SMBHSTCMD);
|
||||
/* Set up for a byte data read */
|
||||
outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | (0x2 << 2),
|
||||
(smbus_base + SMBHSTCTL));
|
||||
/* Clear any lingering errors, so the transaction will run */
|
||||
outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
|
||||
|
||||
/* Clear the data byte... */
|
||||
outb(data, smbus_base + SMBHSTDAT0);
|
||||
|
||||
/* Start the command */
|
||||
outb((inb(smbus_base + SMBHSTCTL) | 0x40),
|
||||
smbus_base + SMBHSTCTL);
|
||||
|
||||
/* Poll for transaction completion */
|
||||
if (smbus_wait_until_done(smbus_base) < 0)
|
||||
return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
|
||||
|
||||
global_status_register = inb(smbus_base + SMBHSTSTAT);
|
||||
|
||||
/* Ignore the "In Use" status... */
|
||||
global_status_register &= ~(3 << 5);
|
||||
|
||||
/* Read results of transaction */
|
||||
if (global_status_register != (1 << 1))
|
||||
return SMBUS_ERROR;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lsmbus_write_byte(device_t dev, u8 address, u8 val)
|
||||
{
|
||||
u16 device;
|
||||
|
|
|
@ -1,95 +0,0 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2005 Yinghai Lu <yinghailu@gmail.com>
|
||||
* Copyright (C) 2009 coresystems GmbH
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <device/smbus_def.h>
|
||||
#include "pch.h"
|
||||
|
||||
static void smbus_delay(void)
|
||||
{
|
||||
inb(0x80);
|
||||
}
|
||||
|
||||
static int smbus_wait_until_ready(u16 smbus_base)
|
||||
{
|
||||
unsigned loops = SMBUS_TIMEOUT;
|
||||
unsigned char byte;
|
||||
do {
|
||||
smbus_delay();
|
||||
if (--loops == 0)
|
||||
break;
|
||||
byte = inb(smbus_base + SMBHSTSTAT);
|
||||
} while (byte & 1);
|
||||
return loops ? 0 : -1;
|
||||
}
|
||||
|
||||
static int smbus_wait_until_done(u16 smbus_base)
|
||||
{
|
||||
unsigned loops = SMBUS_TIMEOUT;
|
||||
unsigned char byte;
|
||||
do {
|
||||
smbus_delay();
|
||||
if (--loops == 0)
|
||||
break;
|
||||
byte = inb(smbus_base + SMBHSTSTAT);
|
||||
} while ((byte & 1) || (byte & ~((1 << 6) | (1 << 0))) == 0);
|
||||
return loops ? 0 : -1;
|
||||
}
|
||||
|
||||
static int do_smbus_read_byte(unsigned smbus_base, unsigned device, unsigned address)
|
||||
{
|
||||
unsigned char global_status_register;
|
||||
unsigned char byte;
|
||||
|
||||
if (smbus_wait_until_ready(smbus_base) < 0) {
|
||||
return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
|
||||
}
|
||||
/* Setup transaction */
|
||||
/* Disable interrupts */
|
||||
outb(inb(smbus_base + SMBHSTCTL) & (~1), smbus_base + SMBHSTCTL);
|
||||
/* Set the device I'm talking too */
|
||||
outb(((device & 0x7f) << 1) | 1, smbus_base + SMBXMITADD);
|
||||
/* Set the command/address... */
|
||||
outb(address & 0xff, smbus_base + SMBHSTCMD);
|
||||
/* Set up for a byte data read */
|
||||
outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | (0x2 << 2),
|
||||
(smbus_base + SMBHSTCTL));
|
||||
/* Clear any lingering errors, so the transaction will run */
|
||||
outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
|
||||
|
||||
/* Clear the data byte... */
|
||||
outb(0, smbus_base + SMBHSTDAT0);
|
||||
|
||||
/* Start the command */
|
||||
outb((inb(smbus_base + SMBHSTCTL) | 0x40),
|
||||
smbus_base + SMBHSTCTL);
|
||||
|
||||
/* Poll for transaction completion */
|
||||
if (smbus_wait_until_done(smbus_base) < 0) {
|
||||
return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
|
||||
}
|
||||
|
||||
global_status_register = inb(smbus_base + SMBHSTSTAT);
|
||||
|
||||
/* Ignore the "In Use" status... */
|
||||
global_status_register &= ~(3 << 5);
|
||||
|
||||
/* Read results of transaction */
|
||||
byte = inb(smbus_base + SMBHSTDAT0);
|
||||
if (global_status_register != (1 << 1)) {
|
||||
return SMBUS_ERROR;
|
||||
}
|
||||
return byte;
|
||||
}
|
|
@ -2,3 +2,5 @@ config SOUTHBRIDGE_INTEL_COMMON
|
|||
def_bool n
|
||||
config SOUTHBRIDGE_INTEL_COMMON_GPIO
|
||||
def_bool n
|
||||
config SOUTHBRIDGE_INTEL_COMMON_SMBUS
|
||||
def_bool n
|
||||
|
|
|
@ -24,4 +24,8 @@ ramstage-$(CONFIG_USBDEBUG) += usb_debug.c
|
|||
romstage-$(CONFIG_SOUTHBRIDGE_INTEL_COMMON_GPIO) += gpio.c
|
||||
ramstage-$(CONFIG_SOUTHBRIDGE_INTEL_COMMON_GPIO) += gpio.c
|
||||
smm-$(CONFIG_SOUTHBRIDGE_INTEL_COMMON_GPIO) += gpio.c
|
||||
|
||||
romstage-$(CONFIG_SOUTHBRIDGE_INTEL_COMMON_SMBUS) += smbus.c
|
||||
ramstage-$(CONFIG_SOUTHBRIDGE_INTEL_COMMON_SMBUS) += smbus.c
|
||||
|
||||
endif
|
||||
|
|
|
@ -0,0 +1,365 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2005 Yinghai Lu <yinghailu@gmail.com>
|
||||
* Copyright (C) 2009 coresystems GmbH
|
||||
* Copyright (C) 2013 Vladimir Serbinenko
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <arch/io.h>
|
||||
#include <device/smbus_def.h>
|
||||
#include "smbus.h"
|
||||
|
||||
|
||||
/* I801 command constants */
|
||||
#define I801_QUICK (0 << 2)
|
||||
#define I801_BYTE (1 << 2)
|
||||
#define I801_BYTE_DATA (2 << 2)
|
||||
#define I801_WORD_DATA (3 << 2)
|
||||
#define I801_BLOCK_DATA (5 << 2)
|
||||
#define I801_I2C_BLOCK_DATA (6 << 2) /* ICH5 and later */
|
||||
|
||||
/* I801 Host Control register bits */
|
||||
#define SMBHSTCNT_INTREN (1 << 0)
|
||||
#define SMBHSTCNT_KILL (1 << 1)
|
||||
#define SMBHSTCNT_LAST_BYTE (1 << 5)
|
||||
#define SMBHSTCNT_START (1 << 6)
|
||||
#define SMBHSTCNT_PEC_EN (1 << 7) /* ICH3 and later */
|
||||
|
||||
/* I801 Hosts Status register bits */
|
||||
#define SMBHSTSTS_BYTE_DONE (1 << 7)
|
||||
#define SMBHSTSTS_INUSE_STS (1 << 6)
|
||||
#define SMBHSTSTS_SMBALERT_STS (1 << 5)
|
||||
#define SMBHSTSTS_FAILED (1 << 4)
|
||||
#define SMBHSTSTS_BUS_ERR (1 << 3)
|
||||
#define SMBHSTSTS_DEV_ERR (1 << 2)
|
||||
#define SMBHSTSTS_INTR (1 << 1)
|
||||
#define SMBHSTSTS_HOST_BUSY (1 << 0)
|
||||
|
||||
#define SMBUS_TIMEOUT (10 * 1000 * 100)
|
||||
|
||||
static void smbus_delay(void)
|
||||
{
|
||||
inb(0x80);
|
||||
}
|
||||
|
||||
static int smbus_wait_until_ready(u16 smbus_base)
|
||||
{
|
||||
unsigned int loops = SMBUS_TIMEOUT;
|
||||
unsigned char byte;
|
||||
do {
|
||||
smbus_delay();
|
||||
if (--loops == 0)
|
||||
break;
|
||||
byte = inb(smbus_base + SMBHSTSTAT);
|
||||
} while (byte & SMBHSTSTS_HOST_BUSY);
|
||||
return loops ? 0 : -1;
|
||||
}
|
||||
|
||||
static int smbus_wait_until_done(u16 smbus_base)
|
||||
{
|
||||
unsigned int loops = SMBUS_TIMEOUT;
|
||||
unsigned char byte;
|
||||
do {
|
||||
smbus_delay();
|
||||
if (--loops == 0)
|
||||
break;
|
||||
byte = inb(smbus_base + SMBHSTSTAT);
|
||||
} while ((byte & SMBHSTSTS_HOST_BUSY)
|
||||
|| (byte & ~(SMBHSTSTS_INUSE_STS | SMBHSTSTS_HOST_BUSY)) == 0);
|
||||
return loops ? 0 : -1;
|
||||
}
|
||||
|
||||
static int smbus_wait_until_active(u16 smbus_base)
|
||||
{
|
||||
unsigned long loops;
|
||||
loops = SMBUS_TIMEOUT;
|
||||
do {
|
||||
unsigned char val;
|
||||
smbus_delay();
|
||||
val = inb(smbus_base + SMBHSTSTAT);
|
||||
if ((val & SMBHSTSTS_HOST_BUSY)) {
|
||||
break;
|
||||
}
|
||||
} while (--loops);
|
||||
return loops ? 0 : -1;
|
||||
}
|
||||
|
||||
int do_smbus_read_byte(unsigned int smbus_base, u8 device,
|
||||
unsigned int address)
|
||||
{
|
||||
unsigned char status;
|
||||
unsigned char byte;
|
||||
|
||||
if (smbus_wait_until_ready(smbus_base) < 0)
|
||||
return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
|
||||
/* Set up transaction */
|
||||
/* Disable interrupts */
|
||||
outb(inb(smbus_base + SMBHSTCTL) & ~SMBHSTCNT_INTREN,
|
||||
smbus_base + SMBHSTCTL);
|
||||
/* Set the device I'm talking too */
|
||||
outb(((device & 0x7f) << 1) | 1, smbus_base + SMBXMITADD);
|
||||
/* Set the command/address... */
|
||||
outb(address & 0xff, smbus_base + SMBHSTCMD);
|
||||
/* Set up for a byte data read */
|
||||
outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | I801_BYTE_DATA,
|
||||
(smbus_base + SMBHSTCTL));
|
||||
/* Clear any lingering errors, so the transaction will run */
|
||||
outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
|
||||
|
||||
/* Clear the data byte... */
|
||||
outb(0, smbus_base + SMBHSTDAT0);
|
||||
|
||||
/* Start the command */
|
||||
outb((inb(smbus_base + SMBHSTCTL) | SMBHSTCNT_START),
|
||||
smbus_base + SMBHSTCTL);
|
||||
|
||||
/* poll for it to start */
|
||||
if (smbus_wait_until_active(smbus_base) < 0)
|
||||
return SMBUS_WAIT_UNTIL_ACTIVE_TIMEOUT;
|
||||
|
||||
/* Poll for transaction completion */
|
||||
if (smbus_wait_until_done(smbus_base) < 0)
|
||||
return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
|
||||
|
||||
status = inb(smbus_base + SMBHSTSTAT);
|
||||
|
||||
/* Ignore the "In Use" status... */
|
||||
status &= ~(SMBHSTSTS_SMBALERT_STS | SMBHSTSTS_INUSE_STS);
|
||||
|
||||
/* Read results of transaction */
|
||||
byte = inb(smbus_base + SMBHSTDAT0);
|
||||
if (status != SMBHSTSTS_INTR)
|
||||
return SMBUS_ERROR;
|
||||
return byte;
|
||||
}
|
||||
|
||||
int do_smbus_write_byte(unsigned int smbus_base, u8 device,
|
||||
unsigned int address, unsigned int data)
|
||||
{
|
||||
unsigned char status;
|
||||
|
||||
if (smbus_wait_until_ready(smbus_base) < 0)
|
||||
return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
|
||||
|
||||
/* Set up transaction */
|
||||
/* Disable interrupts */
|
||||
outb(inb(smbus_base + SMBHSTCTL) & ~SMBHSTCNT_INTREN,
|
||||
smbus_base + SMBHSTCTL);
|
||||
/* Set the device I'm talking too */
|
||||
outb(((device & 0x7f) << 1) & ~0x01, smbus_base + SMBXMITADD);
|
||||
/* Set the command/address... */
|
||||
outb(address & 0xff, smbus_base + SMBHSTCMD);
|
||||
/* Set up for a byte data read */
|
||||
outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | I801_BYTE_DATA,
|
||||
(smbus_base + SMBHSTCTL));
|
||||
/* Clear any lingering errors, so the transaction will run */
|
||||
outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
|
||||
|
||||
/* Clear the data byte... */
|
||||
outb(data, smbus_base + SMBHSTDAT0);
|
||||
|
||||
/* Start the command */
|
||||
outb((inb(smbus_base + SMBHSTCTL) | SMBHSTCNT_START),
|
||||
smbus_base + SMBHSTCTL);
|
||||
|
||||
/* poll for it to start */
|
||||
if (smbus_wait_until_active(smbus_base) < 0)
|
||||
return SMBUS_WAIT_UNTIL_ACTIVE_TIMEOUT;
|
||||
|
||||
/* Poll for transaction completion */
|
||||
if (smbus_wait_until_done(smbus_base) < 0)
|
||||
return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
|
||||
|
||||
status = inb(smbus_base + SMBHSTSTAT);
|
||||
|
||||
/* Ignore the "In Use" status... */
|
||||
status &= ~(SMBHSTSTS_SMBALERT_STS | SMBHSTSTS_INUSE_STS);
|
||||
|
||||
/* Read results of transaction */
|
||||
if (status != SMBHSTSTS_INTR)
|
||||
return SMBUS_ERROR;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int do_smbus_block_read(unsigned int smbus_base, u8 device, u8 cmd,
|
||||
unsigned int bytes, u8 *buf)
|
||||
{
|
||||
u8 status;
|
||||
int bytes_read = 0;
|
||||
unsigned int loops = SMBUS_TIMEOUT;
|
||||
if (smbus_wait_until_ready(smbus_base) < 0)
|
||||
return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
|
||||
|
||||
/* Set up transaction */
|
||||
/* Disable interrupts */
|
||||
outb(inb(smbus_base + SMBHSTCTL) & ~SMBHSTCNT_INTREN,
|
||||
smbus_base + SMBHSTCTL);
|
||||
/* Set the device I'm talking too */
|
||||
outb(((device & 0x7f) << 1) | 1, smbus_base + SMBXMITADD);
|
||||
/* Set the command/address... */
|
||||
outb(cmd & 0xff, smbus_base + SMBHSTCMD);
|
||||
/* Set up for a block data read */
|
||||
outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | I801_BLOCK_DATA,
|
||||
(smbus_base + SMBHSTCTL));
|
||||
/* Clear any lingering errors, so the transaction will run */
|
||||
outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
|
||||
|
||||
/* Start the command */
|
||||
outb((inb(smbus_base + SMBHSTCTL) | SMBHSTCNT_START),
|
||||
smbus_base + SMBHSTCTL);
|
||||
|
||||
/* poll for it to start */
|
||||
if (smbus_wait_until_active(smbus_base) < 0)
|
||||
return SMBUS_WAIT_UNTIL_ACTIVE_TIMEOUT;
|
||||
|
||||
/* Poll for transaction completion */
|
||||
do {
|
||||
loops--;
|
||||
status = inb(smbus_base + SMBHSTSTAT);
|
||||
if (status & (SMBHSTSTS_FAILED | /* FAILED */
|
||||
SMBHSTSTS_BUS_ERR | /* BUS ERR */
|
||||
SMBHSTSTS_DEV_ERR)) /* DEV ERR */
|
||||
return SMBUS_ERROR;
|
||||
|
||||
if (status & SMBHSTSTS_BYTE_DONE) { /* Byte done */
|
||||
*buf = inb(smbus_base + SMBBLKDAT);
|
||||
buf++;
|
||||
bytes_read++;
|
||||
if (--bytes == 1) {
|
||||
/* indicate that next byte is the last one */
|
||||
outb(inb(smbus_base + SMBHSTCTL)
|
||||
| SMBHSTCNT_LAST_BYTE,
|
||||
smbus_base + SMBHSTCTL);
|
||||
}
|
||||
outb(status, smbus_base + SMBHSTSTAT);
|
||||
}
|
||||
} while ((status & SMBHSTSTS_HOST_BUSY) && loops);
|
||||
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
int do_smbus_block_write(unsigned int smbus_base, u8 device, u8 cmd,
|
||||
unsigned int bytes, const u8 *buf)
|
||||
{
|
||||
u8 status;
|
||||
unsigned int loops = SMBUS_TIMEOUT;
|
||||
|
||||
if (smbus_wait_until_ready(smbus_base) < 0)
|
||||
return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
|
||||
|
||||
/* Set up transaction */
|
||||
/* Disable interrupts */
|
||||
outb(inb(smbus_base + SMBHSTCTL) & ~SMBHSTCNT_INTREN,
|
||||
smbus_base + SMBHSTCTL);
|
||||
/* Set the device I'm talking too */
|
||||
outb(((device & 0x7f) << 1) & ~0x01, smbus_base + SMBXMITADD);
|
||||
/* Set the command/address... */
|
||||
outb(cmd & 0xff, smbus_base + SMBHSTCMD);
|
||||
/* Set up for a block data write */
|
||||
outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | I801_BLOCK_DATA,
|
||||
(smbus_base + SMBHSTCTL));
|
||||
/* Clear any lingering errors, so the transaction will run */
|
||||
outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
|
||||
|
||||
/* set number of bytes to transfer */
|
||||
outb(bytes, smbus_base + SMBHSTDAT0);
|
||||
|
||||
outb(*buf++, smbus_base + SMBBLKDAT);
|
||||
bytes--;
|
||||
|
||||
/* Start the command */
|
||||
outb((inb(smbus_base + SMBHSTCTL) | SMBHSTCNT_START),
|
||||
smbus_base + SMBHSTCTL);
|
||||
|
||||
/* poll for it to start */
|
||||
if (smbus_wait_until_active(smbus_base) < 0)
|
||||
return SMBUS_WAIT_UNTIL_ACTIVE_TIMEOUT;
|
||||
|
||||
/* Poll for transaction completion */
|
||||
do {
|
||||
loops--;
|
||||
status = inb(smbus_base + SMBHSTSTAT);
|
||||
if (status & (SMBHSTSTS_FAILED | /* FAILED */
|
||||
SMBHSTSTS_BUS_ERR | /* BUS ERR */
|
||||
SMBHSTSTS_DEV_ERR)) /* DEV ERR */
|
||||
return SMBUS_ERROR;
|
||||
|
||||
if (status & SMBHSTSTS_BYTE_DONE) {
|
||||
outb(*buf++, smbus_base + SMBBLKDAT);
|
||||
outb(status, smbus_base + SMBHSTSTAT);
|
||||
}
|
||||
} while ((status & SMBHSTSTS_HOST_BUSY) && loops);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Only since ICH5 */
|
||||
int do_i2c_block_read(unsigned int smbus_base, u8 device,
|
||||
unsigned int offset, u32 bytes, u8 *buf)
|
||||
{
|
||||
u8 status;
|
||||
int bytes_read = 0;
|
||||
unsigned int loops = SMBUS_TIMEOUT;
|
||||
if (smbus_wait_until_ready(smbus_base) < 0)
|
||||
return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
|
||||
|
||||
/* Set upp transaction */
|
||||
/* Disable interrupts */
|
||||
outb(inb(smbus_base + SMBHSTCTL) & SMBHSTCNT_INTREN,
|
||||
smbus_base + SMBHSTCTL);
|
||||
/* Set the device I'm talking to */
|
||||
outb((device & 0x7f) << 1, smbus_base + SMBXMITADD);
|
||||
|
||||
/* device offset */
|
||||
outb(offset, smbus_base + SMBHSTDAT1);
|
||||
|
||||
/* Set up for a i2c block data read */
|
||||
outb((inb(smbus_base + SMBHSTCTL) & 0xc3) | I801_I2C_BLOCK_DATA,
|
||||
(smbus_base + SMBHSTCTL));
|
||||
|
||||
/* Clear any lingering errors, so the transaction will run */
|
||||
outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
|
||||
/* Start the command */
|
||||
outb((inb(smbus_base + SMBHSTCTL) | SMBHSTCNT_START),
|
||||
smbus_base + SMBHSTCTL);
|
||||
|
||||
/* poll for it to start */
|
||||
if (smbus_wait_until_active(smbus_base) < 0)
|
||||
return SMBUS_WAIT_UNTIL_ACTIVE_TIMEOUT;
|
||||
|
||||
/* Poll for transaction completion */
|
||||
do {
|
||||
loops--;
|
||||
status = inb(smbus_base + SMBHSTSTAT);
|
||||
if (status & (SMBHSTSTS_FAILED | /* FAILED */
|
||||
SMBHSTSTS_BUS_ERR | /* BUS ERR */
|
||||
SMBHSTSTS_DEV_ERR)) /* DEV ERR */
|
||||
return SMBUS_ERROR;
|
||||
|
||||
if (status & SMBHSTSTS_BYTE_DONE) {
|
||||
*buf = inb(smbus_base + SMBBLKDAT);
|
||||
buf++;
|
||||
bytes_read++;
|
||||
if (--bytes == 1) {
|
||||
/* indicate that next byte is the last one */
|
||||
outb(inb(smbus_base + SMBHSTCTL)
|
||||
| SMBHSTCNT_LAST_BYTE,
|
||||
smbus_base + SMBHSTCTL);
|
||||
}
|
||||
outb(status, smbus_base + SMBHSTSTAT);
|
||||
}
|
||||
} while ((status & SMBHSTSTS_HOST_BUSY) && loops);
|
||||
|
||||
return bytes_read;
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2005 Yinghai Lu <yinghailu@gmail.com>
|
||||
* Copyright (C) 2009 coresystems GmbH
|
||||
* Copyright (C) 2013 Vladimir Serbinenko
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef INTEL_COMMON_SMBUS_H
|
||||
#define INTEL_COMMON_SMBUS_H
|
||||
|
||||
/* SMBus register offsets. */
|
||||
#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 SMBSLVCMD 0x11
|
||||
|
||||
int do_smbus_read_byte(unsigned int smbus_base, u8 device,
|
||||
unsigned int address);
|
||||
int do_smbus_write_byte(unsigned int smbus_base, u8 device,
|
||||
unsigned int address, unsigned int data);
|
||||
int do_smbus_block_read(unsigned int smbus_base, u8 device,
|
||||
u8 cmd, unsigned int bytes, u8 *buf);
|
||||
int do_smbus_block_write(unsigned int smbus_base, u8 device,
|
||||
u8 cmd, unsigned int bytes, const u8 *buf);
|
||||
/* Only since ICH5 */
|
||||
int do_i2c_block_read(unsigned int smbus_base, u8 device,
|
||||
unsigned int offset, u32 bytes, u8 *buf);
|
||||
#endif
|
|
@ -31,6 +31,8 @@ config SOUTH_BRIDGE_OPTIONS # dummy
|
|||
select SPI_FLASH
|
||||
select COMMON_FADT
|
||||
select HAVE_INTEL_FIRMWARE
|
||||
select SOUTHBRIDGE_INTEL_COMMON
|
||||
select SOUTHBRIDGE_INTEL_COMMON_SMBUS
|
||||
|
||||
config EHCI_BAR
|
||||
hex
|
||||
|
|
|
@ -32,6 +32,8 @@ config SOUTH_BRIDGE_OPTIONS # dummy
|
|||
select COMMON_FADT
|
||||
select HAVE_INTEL_FIRMWARE
|
||||
select NO_EARLY_BOOTBLOCK_POSTCODES
|
||||
select SOUTHBRIDGE_INTEL_COMMON
|
||||
select SOUTHBRIDGE_INTEL_COMMON_SMBUS
|
||||
|
||||
config EHCI_BAR
|
||||
hex
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
#include <console/console.h>
|
||||
#include <device/pci_ids.h>
|
||||
#include <device/pci_def.h>
|
||||
#include <southbridge/intel/common/smbus.h>
|
||||
#include "pch.h"
|
||||
#include "smbus.h"
|
||||
|
||||
void enable_smbus(void)
|
||||
{
|
||||
|
|
|
@ -174,22 +174,6 @@ void early_pch_init(void);
|
|||
#define SMB_SMI_EN (1 << 1)
|
||||
#define HST_EN (1 << 0)
|
||||
|
||||
/* SMBus I/O bits. */
|
||||
#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 SMBUS_TIMEOUT (10 * 1000 * 100)
|
||||
|
||||
|
||||
/* Southbridge IO BARs */
|
||||
|
||||
#define GPIOBASE 0x48
|
||||
|
|
|
@ -1,91 +0,0 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2005 Yinghai Lu <yinghailu@gmail.com>
|
||||
* Copyright (C) 2009 coresystems GmbH
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <device/smbus_def.h>
|
||||
#include "pch.h"
|
||||
#include <delay.h>
|
||||
|
||||
static int smbus_wait_until_ready(u16 smbus_base)
|
||||
{
|
||||
unsigned loops = SMBUS_TIMEOUT;
|
||||
unsigned char byte;
|
||||
do {
|
||||
udelay(1);
|
||||
if (--loops == 0)
|
||||
break;
|
||||
byte = inb(smbus_base + SMBHSTSTAT);
|
||||
} while (byte & 1);
|
||||
return loops ? 0 : -1;
|
||||
}
|
||||
|
||||
static int smbus_wait_until_done(u16 smbus_base)
|
||||
{
|
||||
unsigned loops = SMBUS_TIMEOUT;
|
||||
unsigned char byte;
|
||||
do {
|
||||
udelay(1);
|
||||
if (--loops == 0)
|
||||
break;
|
||||
byte = inb(smbus_base + SMBHSTSTAT);
|
||||
} while ((byte & 1) || (byte & ~((1 << 6) | (1 << 0))) == 0);
|
||||
return loops ? 0 : -1;
|
||||
}
|
||||
|
||||
static int do_smbus_read_byte(unsigned smbus_base, unsigned device, unsigned address)
|
||||
{
|
||||
unsigned char global_status_register;
|
||||
unsigned char byte;
|
||||
|
||||
if (smbus_wait_until_ready(smbus_base) < 0) {
|
||||
return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
|
||||
}
|
||||
/* Setup transaction */
|
||||
/* Disable interrupts */
|
||||
outb(inb(smbus_base + SMBHSTCTL) & (~1), smbus_base + SMBHSTCTL);
|
||||
/* Set the device I'm talking too */
|
||||
outb(((device & 0x7f) << 1) | 1, smbus_base + SMBXMITADD);
|
||||
/* Set the command/address... */
|
||||
outb(address & 0xff, smbus_base + SMBHSTCMD);
|
||||
/* Set up for a byte data read */
|
||||
outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | (0x2 << 2),
|
||||
(smbus_base + SMBHSTCTL));
|
||||
/* Clear any lingering errors, so the transaction will run */
|
||||
outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
|
||||
|
||||
/* Clear the data byte... */
|
||||
outb(0, smbus_base + SMBHSTDAT0);
|
||||
|
||||
/* Start the command */
|
||||
outb((inb(smbus_base + SMBHSTCTL) | 0x40),
|
||||
smbus_base + SMBHSTCTL);
|
||||
|
||||
/* Poll for transaction completion */
|
||||
if (smbus_wait_until_done(smbus_base) < 0) {
|
||||
return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
|
||||
}
|
||||
|
||||
global_status_register = inb(smbus_base + SMBHSTSTAT);
|
||||
|
||||
/* Ignore the "In Use" status... */
|
||||
global_status_register &= ~(3 << 5);
|
||||
|
||||
/* Read results of transaction */
|
||||
byte = inb(smbus_base + SMBHSTDAT0);
|
||||
if (global_status_register != (1 << 1)) {
|
||||
return SMBUS_ERROR;
|
||||
}
|
||||
return byte;
|
||||
}
|
|
@ -30,6 +30,8 @@ config SOUTH_BRIDGE_OPTIONS # dummy
|
|||
select PCIEXP_COMMON_CLOCK
|
||||
select SPI_FLASH
|
||||
select HAVE_INTEL_FIRMWARE
|
||||
select SOUTHBRIDGE_INTEL_COMMON
|
||||
select SOUTHBRIDGE_INTEL_COMMON_SMBUS
|
||||
|
||||
config EHCI_BAR
|
||||
hex
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
#include <console/console.h>
|
||||
#include <device/pci_ids.h>
|
||||
#include <device/pci_def.h>
|
||||
#include <southbridge/intel/common/smbus.h>
|
||||
#include "soc.h"
|
||||
#include "smbus.h"
|
||||
|
||||
void enable_smbus(void)
|
||||
{
|
||||
|
|
|
@ -22,8 +22,8 @@
|
|||
#include <device/pci_ids.h>
|
||||
#include <device/pci_ops.h>
|
||||
#include <arch/io.h>
|
||||
#include <southbridge/intel/common/smbus.h>
|
||||
#include "soc.h"
|
||||
#include "smbus.h"
|
||||
|
||||
static int lsmbus_read_byte(device_t dev, u8 address)
|
||||
{
|
||||
|
|
|
@ -1,95 +0,0 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2005 Yinghai Lu <yinghailu@gmail.com>
|
||||
* Copyright (C) 2009 coresystems GmbH
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <device/smbus_def.h>
|
||||
#include "soc.h"
|
||||
|
||||
static void smbus_delay(void)
|
||||
{
|
||||
inb(0x80);
|
||||
}
|
||||
|
||||
static int smbus_wait_until_ready(u16 smbus_base)
|
||||
{
|
||||
unsigned loops = SMBUS_TIMEOUT;
|
||||
unsigned char byte;
|
||||
do {
|
||||
smbus_delay();
|
||||
if (--loops == 0)
|
||||
break;
|
||||
byte = inb(smbus_base + SMBHSTSTAT);
|
||||
} while (byte & 1);
|
||||
return loops ? 0 : -1;
|
||||
}
|
||||
|
||||
static int smbus_wait_until_done(u16 smbus_base)
|
||||
{
|
||||
unsigned loops = SMBUS_TIMEOUT;
|
||||
unsigned char byte;
|
||||
do {
|
||||
smbus_delay();
|
||||
if (--loops == 0)
|
||||
break;
|
||||
byte = inb(smbus_base + SMBHSTSTAT);
|
||||
} while ((byte & 1) || (byte & ~((1 << 6) | (1 << 0))) == 0);
|
||||
return loops ? 0 : -1;
|
||||
}
|
||||
|
||||
static int do_smbus_read_byte(unsigned smbus_base, unsigned device, unsigned address)
|
||||
{
|
||||
unsigned char global_status_register;
|
||||
unsigned char byte;
|
||||
|
||||
if (smbus_wait_until_ready(smbus_base) < 0) {
|
||||
return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
|
||||
}
|
||||
/* Setup transaction */
|
||||
/* Disable interrupts */
|
||||
outb(inb(smbus_base + SMBHSTCTL) & (~1), smbus_base + SMBHSTCTL);
|
||||
/* Set the device I'm talking too */
|
||||
outb(((device & 0x7f) << 1) | 1, smbus_base + SMBXMITADD);
|
||||
/* Set the command/address... */
|
||||
outb(address & 0xff, smbus_base + SMBHSTCMD);
|
||||
/* Set up for a byte data read */
|
||||
outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | (0x2 << 2),
|
||||
(smbus_base + SMBHSTCTL));
|
||||
/* Clear any lingering errors, so the transaction will run */
|
||||
outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
|
||||
|
||||
/* Clear the data byte... */
|
||||
outb(0, smbus_base + SMBHSTDAT0);
|
||||
|
||||
/* Start the command */
|
||||
outb((inb(smbus_base + SMBHSTCTL) | 0x40),
|
||||
smbus_base + SMBHSTCTL);
|
||||
|
||||
/* Poll for transaction completion */
|
||||
if (smbus_wait_until_done(smbus_base) < 0) {
|
||||
return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
|
||||
}
|
||||
|
||||
global_status_register = inb(smbus_base + SMBHSTSTAT);
|
||||
|
||||
/* Ignore the "In Use" status... */
|
||||
global_status_register &= ~(3 << 5);
|
||||
|
||||
/* Read results of transaction */
|
||||
byte = inb(smbus_base + SMBHSTDAT0);
|
||||
if (global_status_register != (1 << 1)) {
|
||||
return SMBUS_ERROR;
|
||||
}
|
||||
return byte;
|
||||
}
|
|
@ -176,21 +176,6 @@ void rangeley_sb_early_initialization(void);
|
|||
#define SMB_SMI_EN (1 << 1)
|
||||
#define HST_EN (1 << 0)
|
||||
|
||||
/* SMBus I/O bits. */
|
||||
#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 SMBUS_TIMEOUT (10 * 1000 * 100)
|
||||
|
||||
/* Root Complex Register Block */
|
||||
#define RCBA 0xf0
|
||||
#define RCBA_ENABLE 0x01
|
||||
|
|
|
@ -2,6 +2,8 @@ config SOUTHBRIDGE_INTEL_I3100
|
|||
bool
|
||||
select IOAPIC
|
||||
select HAVE_HARD_RESET
|
||||
select SOUTHBRIDGE_INTEL_COMMON
|
||||
select SOUTHBRIDGE_INTEL_COMMON_SMBUS
|
||||
|
||||
if SOUTHBRIDGE_INTEL_I3100
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include "smbus.h"
|
||||
#include <southbridge/intel/common/smbus.h>
|
||||
|
||||
#define SMBUS_IO_BASE 0x0f00
|
||||
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
#include <device/pci_ops.h>
|
||||
#include <device/smbus.h>
|
||||
#include <arch/io.h>
|
||||
#include <southbridge/intel/common/smbus.h>
|
||||
#include "i3100.h"
|
||||
#include "smbus.h"
|
||||
|
||||
static int lsmbus_read_byte(device_t dev, u8 address)
|
||||
{
|
||||
|
|
|
@ -1,151 +0,0 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2008 Arastra, Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* This code is based on src/southbridge/intel/esb6300/esb6300_smbus.h */
|
||||
|
||||
#include <device/smbus_def.h>
|
||||
|
||||
#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 SMBSLVCMD 0x11
|
||||
|
||||
#define SMBUS_TIMEOUT (100*1000*10)
|
||||
|
||||
static void smbus_delay(void)
|
||||
{
|
||||
outb(0x80, 0x80);
|
||||
}
|
||||
|
||||
static int smbus_wait_until_ready(u32 smbus_io_base)
|
||||
{
|
||||
u32 loops = SMBUS_TIMEOUT;
|
||||
u8 byte;
|
||||
do {
|
||||
smbus_delay();
|
||||
if (--loops == 0)
|
||||
break;
|
||||
byte = inb(smbus_io_base + SMBHSTSTAT);
|
||||
} while (byte & 1);
|
||||
return loops ? 0 : -1;
|
||||
}
|
||||
|
||||
static int smbus_wait_until_done(u32 smbus_io_base)
|
||||
{
|
||||
u32 loops = SMBUS_TIMEOUT;
|
||||
u8 byte;
|
||||
do {
|
||||
smbus_delay();
|
||||
if (--loops == 0)
|
||||
break;
|
||||
byte = inb(smbus_io_base + SMBHSTSTAT);
|
||||
} while ((byte & 1) || (byte & ~((1 << 6)|(1 << 0))) == 0);
|
||||
return loops ? 0 : -1;
|
||||
}
|
||||
|
||||
static int do_smbus_read_byte(u32 smbus_io_base, u16 device, u8 address)
|
||||
{
|
||||
u8 global_status_register;
|
||||
u8 byte;
|
||||
|
||||
if (smbus_wait_until_ready(smbus_io_base) < 0) {
|
||||
return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
|
||||
}
|
||||
/* 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 */
|
||||
if (smbus_wait_until_done(smbus_io_base) < 0) {
|
||||
return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
|
||||
}
|
||||
|
||||
global_status_register = inb(smbus_io_base + SMBHSTSTAT);
|
||||
|
||||
/* Ignore the In Use Status... */
|
||||
global_status_register &= ~(3 << 5);
|
||||
|
||||
/* read results of transaction */
|
||||
byte = inb(smbus_io_base + SMBHSTDAT0);
|
||||
if (global_status_register != (1 << 1)) {
|
||||
return SMBUS_ERROR;
|
||||
}
|
||||
return byte;
|
||||
}
|
||||
|
||||
static int do_smbus_write_byte(unsigned smbus_base, unsigned device, unsigned address, unsigned data)
|
||||
{
|
||||
unsigned char global_status_register;
|
||||
|
||||
if (smbus_wait_until_ready(smbus_base) < 0)
|
||||
return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
|
||||
|
||||
/* Setup transaction */
|
||||
/* Disable interrupts */
|
||||
outb(inb(smbus_base + SMBHSTCTL) & (~1), smbus_base + SMBHSTCTL);
|
||||
/* Set the device I'm talking too */
|
||||
outb(((device & 0x7f) << 1) & ~0x01, smbus_base + SMBXMITADD);
|
||||
/* Set the command/address... */
|
||||
outb(address & 0xff, smbus_base + SMBHSTCMD);
|
||||
/* Set up for a byte data read */
|
||||
outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | (0x2 << 2),
|
||||
(smbus_base + SMBHSTCTL));
|
||||
/* Clear any lingering errors, so the transaction will run */
|
||||
outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
|
||||
|
||||
/* Clear the data byte... */
|
||||
outb(data, smbus_base + SMBHSTDAT0);
|
||||
|
||||
/* Start the command */
|
||||
outb((inb(smbus_base + SMBHSTCTL) | 0x40),
|
||||
smbus_base + SMBHSTCTL);
|
||||
|
||||
/* Poll for transaction completion */
|
||||
if (smbus_wait_until_done(smbus_base) < 0)
|
||||
return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
|
||||
|
||||
global_status_register = inb(smbus_base + SMBHSTSTAT);
|
||||
|
||||
/* Ignore the "In Use" status... */
|
||||
global_status_register &= ~(3 << 5);
|
||||
|
||||
/* Read results of transaction */
|
||||
if (global_status_register != (1 << 1))
|
||||
return SMBUS_ERROR;
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,4 +1,6 @@
|
|||
config SOUTHBRIDGE_INTEL_I82371EB
|
||||
select SOUTHBRIDGE_INTEL_COMMON
|
||||
select SOUTHBRIDGE_INTEL_COMMON_SMBUS
|
||||
bool
|
||||
|
||||
config BOOTBLOCK_SOUTHBRIDGE_INIT
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
#include <console/console.h>
|
||||
#include <device/pci_ids.h>
|
||||
#include <device/pci_def.h>
|
||||
#include <southbridge/intel/common/smbus.h>
|
||||
#include "i82371eb.h"
|
||||
#include "smbus.h"
|
||||
|
||||
void enable_smbus(void)
|
||||
{
|
||||
|
@ -46,7 +46,7 @@ void enable_smbus(void)
|
|||
pci_write_config16(dev, PCI_COMMAND, reg16);
|
||||
|
||||
/* Clear any lingering errors, so the transaction will run. */
|
||||
outb(inb(SMBUS_IO_BASE + SMBHST_STATUS), SMBUS_IO_BASE + SMBHST_STATUS);
|
||||
outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT);
|
||||
}
|
||||
|
||||
int smbus_read_byte(u8 device, u8 address)
|
||||
|
|
|
@ -24,8 +24,8 @@
|
|||
#include <device/pci.h>
|
||||
#include <device/pci_ids.h>
|
||||
#include <device/smbus.h>
|
||||
#include <southbridge/intel/common/smbus.h>
|
||||
#include "i82371eb.h"
|
||||
#include "smbus.h"
|
||||
|
||||
static void pwrmgt_enable(struct device *dev)
|
||||
{
|
||||
|
|
|
@ -1,112 +0,0 @@
|
|||
#include <device/smbus_def.h>
|
||||
#include "i82371eb.h"
|
||||
|
||||
#define SMBHST_STATUS 0x0
|
||||
#define SMBHST_CTL 0x2
|
||||
#define SMBHST_CMD 0x3
|
||||
#define SMBHST_ADDR 0x4
|
||||
#define SMBHST_DAT 0x5
|
||||
|
||||
#define SMBUS_TIMEOUT (100*1000*10)
|
||||
#define SMBUS_STATUS_MASK 0x1e
|
||||
#define SMBUS_ERROR_FLAG (1<<2)
|
||||
|
||||
int do_smbus_read_byte(unsigned smbus_io_base, unsigned device, unsigned address);
|
||||
|
||||
static inline void smbus_delay(void)
|
||||
{
|
||||
outb(0x80, 0x80);
|
||||
outb(0x80, 0x80);
|
||||
outb(0x80, 0x80);
|
||||
outb(0x80, 0x80);
|
||||
outb(0x80, 0x80);
|
||||
outb(0x80, 0x80);
|
||||
}
|
||||
|
||||
static int smbus_wait_until_ready(unsigned smbus_io_base)
|
||||
{
|
||||
unsigned long loops;
|
||||
loops = SMBUS_TIMEOUT;
|
||||
do {
|
||||
unsigned char val;
|
||||
smbus_delay();
|
||||
val = inb(smbus_io_base + SMBHST_STATUS);
|
||||
if ((val & 0x1) == 0) {
|
||||
break;
|
||||
}
|
||||
#if 0
|
||||
if (loops == (SMBUS_TIMEOUT / 2)) {
|
||||
outw(inw(smbus_io_base + SMBHST_STATUS),
|
||||
smbus_io_base + SMBHST_STATUS);
|
||||
}
|
||||
#endif
|
||||
} while (--loops);
|
||||
return loops?0:SMBUS_WAIT_UNTIL_READY_TIMEOUT;
|
||||
}
|
||||
|
||||
static int smbus_wait_until_done(unsigned smbus_io_base)
|
||||
{
|
||||
unsigned long loops;
|
||||
loops = SMBUS_TIMEOUT;
|
||||
do {
|
||||
unsigned short val;
|
||||
smbus_delay();
|
||||
|
||||
val = inb(smbus_io_base + SMBHST_STATUS);
|
||||
// Make sure the command is done
|
||||
if ((val & 0x1) != 0) {
|
||||
continue;
|
||||
}
|
||||
// Don't break out until one of the interrupt
|
||||
// flags is set.
|
||||
if (val & 0xfe) {
|
||||
break;
|
||||
}
|
||||
} while (--loops);
|
||||
return loops?0:SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
|
||||
}
|
||||
|
||||
int do_smbus_read_byte(unsigned smbus_io_base, unsigned device, unsigned address)
|
||||
{
|
||||
unsigned status_register;
|
||||
unsigned byte;
|
||||
|
||||
if (smbus_wait_until_ready(smbus_io_base) < 0) {
|
||||
return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
|
||||
}
|
||||
|
||||
/* setup transaction */
|
||||
|
||||
/* clear any lingering errors, so the transaction will run */
|
||||
outb(0x1e, smbus_io_base + SMBHST_STATUS);
|
||||
|
||||
/* set the device I'm talking too */
|
||||
outb(((device & 0x7f) << 1) | 1, smbus_io_base + SMBHST_ADDR);
|
||||
|
||||
/* set the command/address... */
|
||||
outb(address & 0xff, smbus_io_base + SMBHST_CMD);
|
||||
|
||||
/* clear the data word...*/
|
||||
outb(0, smbus_io_base + SMBHST_DAT);
|
||||
|
||||
/* start a byte read with interrupts disabled */
|
||||
outb( (0x02 << 2)|(1<<6), smbus_io_base + SMBHST_CTL);
|
||||
|
||||
/* poll for transaction completion */
|
||||
if (smbus_wait_until_done(smbus_io_base) < 0) {
|
||||
return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
|
||||
}
|
||||
|
||||
status_register = inw(smbus_io_base + SMBHST_STATUS);
|
||||
|
||||
/* read results of transaction */
|
||||
byte = inw(smbus_io_base + SMBHST_DAT) & 0xff;
|
||||
|
||||
if (status_register & 0x04) {
|
||||
#if 0
|
||||
printk(BIOS_DEBUG, "Read fail %04x\n", status_register);
|
||||
#endif
|
||||
return SMBUS_ERROR;
|
||||
}
|
||||
return byte;
|
||||
}
|
|
@ -18,3 +18,5 @@ config SOUTHBRIDGE_INTEL_I82801AX
|
|||
select IOAPIC
|
||||
select HAVE_HARD_RESET
|
||||
select USE_WATCHDOG_ON_BOOT
|
||||
select SOUTHBRIDGE_INTEL_COMMON
|
||||
select SOUTHBRIDGE_INTEL_COMMON_SMBUS
|
||||
|
|
|
@ -20,8 +20,8 @@
|
|||
#include <console/console.h>
|
||||
#include <device/pci_ids.h>
|
||||
#include <device/pci_def.h>
|
||||
#include <southbridge/intel/common/smbus.h>
|
||||
#include "i82801ax.h"
|
||||
#include "smbus.h"
|
||||
|
||||
void enable_smbus(void)
|
||||
{
|
||||
|
|
|
@ -90,15 +90,4 @@ int smbus_read_byte(u8 device, u8 address);
|
|||
#define SMB_SMI_EN (1 << 1)
|
||||
#define HST_EN (1 << 0)
|
||||
|
||||
/* SMBus I/O registers. */
|
||||
#define SMBHSTSTAT 0x0
|
||||
#define SMBHSTCTL 0x2
|
||||
#define SMBHSTCMD 0x3
|
||||
#define SMBXMITADD 0x4
|
||||
#define SMBHSTDAT0 0x5
|
||||
#define SMBHSTDAT1 0x6
|
||||
#define SMBBLKDAT 0x7
|
||||
|
||||
#define SMBUS_TIMEOUT (10 * 1000 * 100)
|
||||
|
||||
#endif
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
#include <device/pci.h>
|
||||
#include <device/pci_ids.h>
|
||||
#include <arch/io.h>
|
||||
#include <southbridge/intel/common/smbus.h>
|
||||
#include "i82801ax.h"
|
||||
#include "smbus.h"
|
||||
|
||||
static int lsmbus_read_byte(device_t dev, u8 address)
|
||||
{
|
||||
|
|
|
@ -1,97 +0,0 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2005 Yinghai Lu <yinghailu@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.
|
||||
*/
|
||||
|
||||
#include <device/smbus_def.h>
|
||||
#include "i82801ax.h"
|
||||
|
||||
int do_smbus_read_byte(u16 smbus_io_base, u8 device, u8 address);
|
||||
|
||||
static void smbus_delay(void)
|
||||
{
|
||||
inb(0x80);
|
||||
}
|
||||
|
||||
static int smbus_wait_until_ready(u16 smbus_io_base)
|
||||
{
|
||||
unsigned loops = SMBUS_TIMEOUT;
|
||||
unsigned char byte;
|
||||
do {
|
||||
smbus_delay();
|
||||
if (--loops == 0)
|
||||
break;
|
||||
byte = inb(smbus_io_base + SMBHSTSTAT);
|
||||
} while (byte & 1);
|
||||
return loops ? 0 : -1;
|
||||
}
|
||||
|
||||
static int smbus_wait_until_done(u16 smbus_io_base)
|
||||
{
|
||||
unsigned loops = SMBUS_TIMEOUT;
|
||||
unsigned char byte;
|
||||
do {
|
||||
smbus_delay();
|
||||
if (--loops == 0)
|
||||
break;
|
||||
byte = inb(smbus_io_base + SMBHSTSTAT);
|
||||
} while ((byte & 1) || (byte & ~((1 << 6) | (1 << 0))) == 0);
|
||||
return loops ? 0 : -1;
|
||||
}
|
||||
|
||||
int do_smbus_read_byte(u16 smbus_io_base, u8 device, u8 address)
|
||||
{
|
||||
unsigned char global_status_register;
|
||||
unsigned char byte;
|
||||
|
||||
if (smbus_wait_until_ready(smbus_io_base) < 0) {
|
||||
return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
|
||||
}
|
||||
/* 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 */
|
||||
if (smbus_wait_until_done(smbus_io_base) < 0) {
|
||||
return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
|
||||
}
|
||||
|
||||
global_status_register = inb(smbus_io_base + SMBHSTSTAT);
|
||||
|
||||
/* Ignore the "In Use" status... */
|
||||
global_status_register &= ~(3 << 5);
|
||||
|
||||
/* Read results of transaction */
|
||||
byte = inb(smbus_io_base + SMBHSTDAT0);
|
||||
if (global_status_register != (1 << 1)) {
|
||||
return SMBUS_ERROR;
|
||||
}
|
||||
return byte;
|
||||
}
|
|
@ -18,3 +18,5 @@ config SOUTHBRIDGE_INTEL_I82801BX
|
|||
select IOAPIC
|
||||
select HAVE_HARD_RESET
|
||||
select USE_WATCHDOG_ON_BOOT
|
||||
select SOUTHBRIDGE_INTEL_COMMON
|
||||
select SOUTHBRIDGE_INTEL_COMMON_SMBUS
|
||||
|
|
|
@ -20,8 +20,8 @@
|
|||
#include <console/console.h>
|
||||
#include <device/pci_ids.h>
|
||||
#include <device/pci_def.h>
|
||||
#include <southbridge/intel/common/smbus.h>
|
||||
#include "i82801bx.h"
|
||||
#include "smbus.h"
|
||||
|
||||
void enable_smbus(void)
|
||||
{
|
||||
|
|
|
@ -99,19 +99,4 @@ int smbus_read_byte(u8 device, u8 address);
|
|||
#define SMB_SMI_EN (1 << 1)
|
||||
#define HST_EN (1 << 0)
|
||||
|
||||
/* SMBus I/O registers. */
|
||||
#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 SMBUS_TIMEOUT (10 * 1000 * 100)
|
||||
|
||||
#endif /* SOUTHBRIDGE_INTEL_I82801BX_I82801BX_H */
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
#include <device/pci.h>
|
||||
#include <device/pci_ids.h>
|
||||
#include <arch/io.h>
|
||||
#include <southbridge/intel/common/smbus.h>
|
||||
#include "i82801bx.h"
|
||||
#include "smbus.h"
|
||||
|
||||
static int lsmbus_read_byte(device_t dev, u8 address)
|
||||
{
|
||||
|
|
|
@ -1,94 +0,0 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2005 Yinghai Lu <yinghailu@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.
|
||||
*/
|
||||
|
||||
#include <device/smbus_def.h>
|
||||
|
||||
static void smbus_delay(void)
|
||||
{
|
||||
inb(0x80);
|
||||
}
|
||||
|
||||
static int smbus_wait_until_ready(u16 smbus_io_base)
|
||||
{
|
||||
unsigned loops = SMBUS_TIMEOUT;
|
||||
unsigned char byte;
|
||||
do {
|
||||
smbus_delay();
|
||||
if (--loops == 0)
|
||||
break;
|
||||
byte = inb(smbus_io_base + SMBHSTSTAT);
|
||||
} while (byte & 1);
|
||||
return loops ? 0 : -1;
|
||||
}
|
||||
|
||||
static int smbus_wait_until_done(u16 smbus_io_base)
|
||||
{
|
||||
unsigned loops = SMBUS_TIMEOUT;
|
||||
unsigned char byte;
|
||||
do {
|
||||
smbus_delay();
|
||||
if (--loops == 0)
|
||||
break;
|
||||
byte = inb(smbus_io_base + SMBHSTSTAT);
|
||||
} while ((byte & 1) || (byte & ~((1 << 6) | (1 << 0))) == 0);
|
||||
return loops ? 0 : -1;
|
||||
}
|
||||
|
||||
static int do_smbus_read_byte(u16 smbus_io_base, u8 device, u8 address)
|
||||
{
|
||||
unsigned char global_status_register;
|
||||
unsigned char byte;
|
||||
|
||||
if (smbus_wait_until_ready(smbus_io_base) < 0) {
|
||||
return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
|
||||
}
|
||||
/* 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 */
|
||||
if (smbus_wait_until_done(smbus_io_base) < 0) {
|
||||
return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
|
||||
}
|
||||
|
||||
global_status_register = inb(smbus_io_base + SMBHSTSTAT);
|
||||
|
||||
/* Ignore the "In Use" status... */
|
||||
global_status_register &= ~(3 << 5);
|
||||
|
||||
/* Read results of transaction */
|
||||
byte = inb(smbus_io_base + SMBHSTDAT0);
|
||||
if (global_status_register != (1 << 1)) {
|
||||
return SMBUS_ERROR;
|
||||
}
|
||||
return byte;
|
||||
}
|
|
@ -22,6 +22,8 @@ config SOUTHBRIDGE_INTEL_I82801DX
|
|||
select HAVE_HARD_RESET
|
||||
select HAVE_SMI_HANDLER
|
||||
select HAVE_USBDEBUG
|
||||
select SOUTHBRIDGE_INTEL_COMMON
|
||||
select SOUTHBRIDGE_INTEL_COMMON_SMBUS
|
||||
|
||||
if SOUTHBRIDGE_INTEL_I82801DX
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <arch/io.h>
|
||||
#include <device/pci_def.h>
|
||||
#include <console/console.h>
|
||||
#include <southbridge/intel/common/smbus.h>
|
||||
|
||||
#include "i82801dx.h"
|
||||
|
||||
|
@ -37,143 +38,7 @@ void enable_smbus(void)
|
|||
outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT);
|
||||
}
|
||||
|
||||
static inline void smbus_delay(void)
|
||||
int smbus_read_byte(unsigned int device, unsigned int address)
|
||||
{
|
||||
outb(0x80, 0x80);
|
||||
return do_smbus_read_byte(SMBUS_IO_BASE, device, address);
|
||||
}
|
||||
|
||||
static int smbus_wait_until_active(void)
|
||||
{
|
||||
unsigned long loops;
|
||||
loops = SMBUS_TIMEOUT;
|
||||
do {
|
||||
unsigned char val;
|
||||
smbus_delay();
|
||||
val = inb(SMBUS_IO_BASE + SMBHSTSTAT);
|
||||
if ((val & 1)) {
|
||||
break;
|
||||
}
|
||||
} while (--loops);
|
||||
return loops ? 0 : -4;
|
||||
}
|
||||
|
||||
static int smbus_wait_until_ready(void)
|
||||
{
|
||||
unsigned long loops;
|
||||
loops = SMBUS_TIMEOUT;
|
||||
do {
|
||||
unsigned char val;
|
||||
smbus_delay();
|
||||
val = inb(SMBUS_IO_BASE + SMBHSTSTAT);
|
||||
if ((val & 1) == 0) {
|
||||
break;
|
||||
}
|
||||
if (loops == (SMBUS_TIMEOUT / 2)) {
|
||||
outb(inb(SMBUS_IO_BASE + SMBHSTSTAT),
|
||||
SMBUS_IO_BASE + SMBHSTSTAT);
|
||||
}
|
||||
} while (--loops);
|
||||
return loops ? 0 : -2;
|
||||
}
|
||||
|
||||
static int smbus_wait_until_done(void)
|
||||
{
|
||||
unsigned long loops;
|
||||
loops = SMBUS_TIMEOUT;
|
||||
do {
|
||||
unsigned char val;
|
||||
smbus_delay();
|
||||
|
||||
val = inb(SMBUS_IO_BASE + SMBHSTSTAT);
|
||||
if ((val & 1) == 0) {
|
||||
break;
|
||||
}
|
||||
if ((val & ~((1 << 6) | (1 << 0))) != 0) {
|
||||
break;
|
||||
}
|
||||
} while (--loops);
|
||||
return loops ? 0 : -3;
|
||||
}
|
||||
|
||||
int smbus_read_byte(unsigned device, unsigned address)
|
||||
{
|
||||
unsigned char global_status_register;
|
||||
unsigned char byte;
|
||||
|
||||
/* printk(BIOS_ERR, "smbus_read_byte\n"); */
|
||||
if (smbus_wait_until_ready() < 0) {
|
||||
printk(BIOS_ERR, "SMBUS not ready (-2)\n");
|
||||
return -2;
|
||||
}
|
||||
|
||||
/* setup transaction */
|
||||
/* disable interrupts */
|
||||
outb(inb(SMBUS_IO_BASE + SMBHSTCTL) & 0xfe, 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 a byte read, with interrupts disabled */
|
||||
outb((inb(SMBUS_IO_BASE + SMBHSTCTL) | 0x40),
|
||||
SMBUS_IO_BASE + SMBHSTCTL);
|
||||
/* poll for it to start */
|
||||
if (smbus_wait_until_active() < 0) {
|
||||
printk(BIOS_ERR, "SMBUS not active (-4)\n");
|
||||
return -4;
|
||||
}
|
||||
|
||||
/* poll for transaction completion */
|
||||
if (smbus_wait_until_done() < 0) {
|
||||
printk(BIOS_ERR, "SMBUS not completed (-3)\n");
|
||||
return -3;
|
||||
}
|
||||
|
||||
global_status_register = inb(SMBUS_IO_BASE + SMBHSTSTAT) & ~(1 << 6); /* Ignore the In Use Status... */
|
||||
|
||||
/* read results of transaction */
|
||||
byte = inb(SMBUS_IO_BASE + SMBHSTDAT0);
|
||||
|
||||
if (global_status_register != 2) {
|
||||
//printk(BIOS_SPEW, "%s: no device (%02x, %02x)\n", __func__, device, address);
|
||||
return -1;
|
||||
}
|
||||
//printk(BIOS_DEBUG, "%s: %02x@%02x = %02x\n", __func__, device, address, byte);
|
||||
return byte;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void smbus_write_byte(unsigned device, unsigned address,
|
||||
unsigned char val)
|
||||
{
|
||||
if (smbus_wait_until_ready() < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* by LYH */
|
||||
outb(0x37, SMBUS_IO_BASE + SMBHSTSTAT);
|
||||
/* set the device I'm talking too */
|
||||
outw(((device & 0x7f) << 1) | 0, SMBUS_IO_BASE + SMBHSTADDR);
|
||||
|
||||
/* data to send */
|
||||
outb(val, SMBUS_IO_BASE + SMBHSTDAT);
|
||||
|
||||
outb(address & 0xFF, SMBUS_IO_BASE + SMBHSTCMD);
|
||||
|
||||
/* start the command */
|
||||
outb(0xa, SMBUS_IO_BASE + SMBHSTCTL);
|
||||
|
||||
/* poll for transaction completion */
|
||||
smbus_wait_until_done();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -116,23 +116,6 @@ int smbus_read_byte(unsigned device, unsigned address);
|
|||
|
||||
#define SMBUS_IO_BASE 0x1000
|
||||
|
||||
#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
|
||||
|
||||
/* Between 1-10 seconds, We should never timeout normally
|
||||
* Longer than this is just painful when a timeout condition occurs.
|
||||
*/
|
||||
#define SMBUS_TIMEOUT (100*1000)
|
||||
|
||||
#define PM1_STS 0x00
|
||||
#define WAK_STS (1 << 15)
|
||||
#define PCIEXPWAK_STS (1 << 14)
|
||||
|
|
|
@ -1,101 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#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;
|
||||
}
|
|
@ -24,6 +24,7 @@ config SOUTHBRIDGE_INTEL_I82801GX
|
|||
select HAVE_SMI_HANDLER
|
||||
select COMMON_FADT
|
||||
select SOUTHBRIDGE_INTEL_COMMON_GPIO
|
||||
select SOUTHBRIDGE_INTEL_COMMON_SMBUS
|
||||
|
||||
if SOUTHBRIDGE_INTEL_I82801GX
|
||||
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
#include <console/console.h>
|
||||
#include <device/pci_ids.h>
|
||||
#include <device/pci_def.h>
|
||||
#include <southbridge/intel/common/smbus.h>
|
||||
#include "i82801gx.h"
|
||||
#include "smbus.h"
|
||||
|
||||
void enable_smbus(void)
|
||||
{
|
||||
|
@ -57,52 +57,5 @@ int smbus_read_byte(unsigned int device, unsigned int address)
|
|||
|
||||
int i2c_block_read(unsigned int device, unsigned int offset, u32 bytes, u8 *buf)
|
||||
{
|
||||
u8 status;
|
||||
int bytes_read = 0;
|
||||
if (smbus_wait_until_ready(SMBUS_IO_BASE) < 0)
|
||||
return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
|
||||
|
||||
/* Setup transaction */
|
||||
/* Disable interrupts */
|
||||
outb(inb(SMBUS_IO_BASE + SMBHSTCTL) & (~1), SMBUS_IO_BASE + SMBHSTCTL);
|
||||
/* Set the device I'm talking to */
|
||||
outb((device & 0x7f) << 1, SMBUS_IO_BASE + SMBXMITADD);
|
||||
|
||||
/* SPD offset */
|
||||
outb(offset, SMBUS_IO_BASE + SMBHSTDAT1);
|
||||
|
||||
/* Set up for a i2c block data read */
|
||||
outb((inb(SMBUS_IO_BASE + SMBHSTCTL) & 0xc3) | (0x6 << 2),
|
||||
(SMBUS_IO_BASE + SMBHSTCTL));
|
||||
|
||||
/* Clear any lingering errors, so the transaction will run */
|
||||
outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT);
|
||||
/* Start the command */
|
||||
outb((inb(SMBUS_IO_BASE + SMBHSTCTL) | 0x40),
|
||||
SMBUS_IO_BASE + SMBHSTCTL);
|
||||
|
||||
while (!(inb(SMBUS_IO_BASE + SMBHSTSTAT) & 1))
|
||||
;
|
||||
/* Poll for transaction completion */
|
||||
do {
|
||||
status = inb(SMBUS_IO_BASE + SMBHSTSTAT);
|
||||
if (status & ((1 << 4) | /* FAILED */
|
||||
(1 << 3) | /* BUS ERR */
|
||||
(1 << 2))) /* DEV ERR */
|
||||
return SMBUS_ERROR;
|
||||
|
||||
if (status & 0x80) { /* Byte done */
|
||||
*buf = inb(SMBUS_IO_BASE + SMBBLKDAT);
|
||||
buf++;
|
||||
bytes_read++;
|
||||
if (--bytes == 1) {
|
||||
/* indicate that next byte is the last one */
|
||||
outb(inb(SMBUS_IO_BASE + SMBHSTCTL) | 0x20,
|
||||
SMBUS_IO_BASE + SMBHSTCTL);
|
||||
}
|
||||
outb(status, SMBUS_IO_BASE + SMBHSTSTAT);
|
||||
}
|
||||
} while (status & 0x01);
|
||||
|
||||
return bytes_read;
|
||||
return do_i2c_block_read(SMBUS_IO_BASE, device, offset, bytes, buf);
|
||||
}
|
||||
|
|
|
@ -177,22 +177,6 @@ int southbridge_detect_s3_resume(void);
|
|||
#define SMB_SMI_EN (1 << 1)
|
||||
#define HST_EN (1 << 0)
|
||||
|
||||
/* SMBus I/O bits. */
|
||||
#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 SMBUS_TIMEOUT (10 * 1000 * 100)
|
||||
|
||||
|
||||
/* Southbridge IO BARs */
|
||||
|
||||
#define GPIOBASE 0x48
|
||||
|
|
|
@ -22,8 +22,8 @@
|
|||
#include <device/pci_ids.h>
|
||||
#include <device/pci_ops.h>
|
||||
#include <arch/io.h>
|
||||
#include <southbridge/intel/common/smbus.h>
|
||||
#include "i82801gx.h"
|
||||
#include "smbus.h"
|
||||
|
||||
static int lsmbus_read_byte(device_t dev, u8 address)
|
||||
{
|
||||
|
@ -38,49 +38,6 @@ static int lsmbus_read_byte(device_t dev, u8 address)
|
|||
return do_smbus_read_byte(res->base, device, address);
|
||||
}
|
||||
|
||||
static int do_smbus_write_byte(unsigned int smbus_base, unsigned int device,
|
||||
unsigned int address, unsigned int data)
|
||||
{
|
||||
unsigned char global_status_register;
|
||||
|
||||
if (smbus_wait_until_ready(smbus_base) < 0)
|
||||
return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
|
||||
|
||||
/* Setup transaction */
|
||||
/* Disable interrupts */
|
||||
outb(inb(smbus_base + SMBHSTCTL) & (~1), smbus_base + SMBHSTCTL);
|
||||
/* Set the device I'm talking too */
|
||||
outb(((device & 0x7f) << 1) & ~0x01, smbus_base + SMBXMITADD);
|
||||
/* Set the command/address... */
|
||||
outb(address & 0xff, smbus_base + SMBHSTCMD);
|
||||
/* Set up for a byte data read */
|
||||
outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | (0x2 << 2),
|
||||
(smbus_base + SMBHSTCTL));
|
||||
/* Clear any lingering errors, so the transaction will run */
|
||||
outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
|
||||
|
||||
/* Clear the data byte... */
|
||||
outb(data, smbus_base + SMBHSTDAT0);
|
||||
|
||||
/* Start the command */
|
||||
outb((inb(smbus_base + SMBHSTCTL) | 0x40),
|
||||
smbus_base + SMBHSTCTL);
|
||||
|
||||
/* Poll for transaction completion */
|
||||
if (smbus_wait_until_done(smbus_base) < 0)
|
||||
return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
|
||||
|
||||
global_status_register = inb(smbus_base + SMBHSTSTAT);
|
||||
|
||||
/* Ignore the "In Use" status... */
|
||||
global_status_register &= ~(3 << 5);
|
||||
|
||||
/* Read results of transaction */
|
||||
if (global_status_register != (1 << 1))
|
||||
return SMBUS_ERROR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lsmbus_write_byte(device_t dev, u8 address, u8 data)
|
||||
{
|
||||
u16 device;
|
||||
|
@ -93,58 +50,6 @@ static int lsmbus_write_byte(device_t dev, u8 address, u8 data)
|
|||
return do_smbus_write_byte(res->base, device, address, data);
|
||||
}
|
||||
|
||||
static int do_smbus_block_write(unsigned int smbus_base, unsigned int device,
|
||||
unsigned int cmd, unsigned int bytes, const u8 *buf)
|
||||
{
|
||||
u8 status;
|
||||
|
||||
if (smbus_wait_until_ready(smbus_base) < 0)
|
||||
return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
|
||||
|
||||
/* Setup transaction */
|
||||
/* Disable interrupts */
|
||||
outb(inb(smbus_base + SMBHSTCTL) & (~1), smbus_base + SMBHSTCTL);
|
||||
/* Set the device I'm talking too */
|
||||
outb(((device & 0x7f) << 1) & ~0x01, smbus_base + SMBXMITADD);
|
||||
/* Set the command/address... */
|
||||
outb(cmd & 0xff, smbus_base + SMBHSTCMD);
|
||||
/* Set up for a block data write */
|
||||
outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | (0x5 << 2),
|
||||
(smbus_base + SMBHSTCTL));
|
||||
/* Clear any lingering errors, so the transaction will run */
|
||||
outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
|
||||
|
||||
/* set number of bytes to transfer */
|
||||
outb(bytes, smbus_base + SMBHSTDAT0);
|
||||
|
||||
outb(*buf++, smbus_base + SMBBLKDAT);
|
||||
bytes--;
|
||||
|
||||
/* Start the command */
|
||||
outb((inb(smbus_base + SMBHSTCTL) | 0x40),
|
||||
smbus_base + SMBHSTCTL);
|
||||
|
||||
while (!(inb(smbus_base + SMBHSTSTAT) & 1))
|
||||
;
|
||||
/* Poll for transaction completion */
|
||||
do {
|
||||
status = inb(smbus_base + SMBHSTSTAT);
|
||||
if (status & ((1 << 4) | /* FAILED */
|
||||
(1 << 3) | /* BUS ERR */
|
||||
(1 << 2))) /* DEV ERR */
|
||||
return SMBUS_ERROR;
|
||||
|
||||
if (status & 0x80) { /* Byte done */
|
||||
outb(*buf++, smbus_base + SMBBLKDAT);
|
||||
outb(status, smbus_base + SMBHSTSTAT);
|
||||
}
|
||||
} while (status & 0x01);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int lsmbus_block_write(device_t dev, u8 cmd, u8 bytes, const u8 *buf)
|
||||
{
|
||||
u16 device;
|
||||
|
@ -157,57 +62,6 @@ static int lsmbus_block_write(device_t dev, u8 cmd, u8 bytes, const u8 *buf)
|
|||
return do_smbus_block_write(res->base, device, cmd, bytes, buf);
|
||||
}
|
||||
|
||||
static int do_smbus_block_read(unsigned int smbus_base, unsigned int device,
|
||||
unsigned int cmd, unsigned int bytes, u8 *buf)
|
||||
{
|
||||
u8 status;
|
||||
int bytes_read = 0;
|
||||
if (smbus_wait_until_ready(smbus_base) < 0)
|
||||
return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
|
||||
|
||||
/* Setup transaction */
|
||||
/* Disable interrupts */
|
||||
outb(inb(smbus_base + SMBHSTCTL) & (~1), smbus_base + SMBHSTCTL);
|
||||
/* Set the device I'm talking too */
|
||||
outb(((device & 0x7f) << 1) | 1, smbus_base + SMBXMITADD);
|
||||
/* Set the command/address... */
|
||||
outb(cmd & 0xff, smbus_base + SMBHSTCMD);
|
||||
/* Set up for a block data read */
|
||||
outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | (0x5 << 2),
|
||||
(smbus_base + SMBHSTCTL));
|
||||
/* Clear any lingering errors, so the transaction will run */
|
||||
outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
|
||||
|
||||
/* Start the command */
|
||||
outb((inb(smbus_base + SMBHSTCTL) | 0x40),
|
||||
smbus_base + SMBHSTCTL);
|
||||
|
||||
while (!(inb(smbus_base + SMBHSTSTAT) & 1))
|
||||
;
|
||||
/* Poll for transaction completion */
|
||||
do {
|
||||
status = inb(smbus_base + SMBHSTSTAT);
|
||||
if (status & ((1 << 4) | /* FAILED */
|
||||
(1 << 3) | /* BUS ERR */
|
||||
(1 << 2))) /* DEV ERR */
|
||||
return SMBUS_ERROR;
|
||||
|
||||
if (status & 0x80) { /* Byte done */
|
||||
*buf = inb(smbus_base + SMBBLKDAT);
|
||||
buf++;
|
||||
bytes_read++;
|
||||
outb(status, smbus_base + SMBHSTSTAT);
|
||||
if (--bytes == 1) {
|
||||
/* indicate that next byte is the last one */
|
||||
outb(inb(smbus_base + SMBHSTCTL) | 0x20,
|
||||
smbus_base + SMBHSTCTL);
|
||||
}
|
||||
}
|
||||
} while (status & 0x01);
|
||||
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
static int lsmbus_block_read(device_t dev, u8 cmd, u8 bytes, u8 *buf)
|
||||
{
|
||||
u16 device;
|
||||
|
|
|
@ -1,92 +0,0 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2005 Yinghai Lu <yinghailu@gmail.com>
|
||||
* Copyright (C) 2009 coresystems GmbH
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <device/smbus_def.h>
|
||||
#include "i82801gx.h"
|
||||
|
||||
static void smbus_delay(void)
|
||||
{
|
||||
inb(0x80);
|
||||
}
|
||||
|
||||
static int smbus_wait_until_ready(u16 smbus_base)
|
||||
{
|
||||
unsigned int loops = SMBUS_TIMEOUT;
|
||||
unsigned char byte;
|
||||
do {
|
||||
smbus_delay();
|
||||
if (--loops == 0)
|
||||
break;
|
||||
byte = inb(smbus_base + SMBHSTSTAT);
|
||||
} while (byte & 1);
|
||||
return loops ? 0 : -1;
|
||||
}
|
||||
|
||||
static int smbus_wait_until_done(u16 smbus_base)
|
||||
{
|
||||
unsigned int loops = SMBUS_TIMEOUT;
|
||||
unsigned char byte;
|
||||
do {
|
||||
smbus_delay();
|
||||
if (--loops == 0)
|
||||
break;
|
||||
byte = inb(smbus_base + SMBHSTSTAT);
|
||||
} while ((byte & 1) || (byte & ~((1 << 6) | (1 << 0))) == 0);
|
||||
return loops ? 0 : -1;
|
||||
}
|
||||
|
||||
static int do_smbus_read_byte(unsigned int smbus_base, unsigned int device, unsigned int address)
|
||||
{
|
||||
unsigned char global_status_register;
|
||||
unsigned char byte;
|
||||
|
||||
if (smbus_wait_until_ready(smbus_base) < 0)
|
||||
return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
|
||||
/* Setup transaction */
|
||||
/* Disable interrupts */
|
||||
outb(inb(smbus_base + SMBHSTCTL) & (~1), smbus_base + SMBHSTCTL);
|
||||
/* Set the device I'm talking too */
|
||||
outb(((device & 0x7f) << 1) | 1, smbus_base + SMBXMITADD);
|
||||
/* Set the command/address... */
|
||||
outb(address & 0xff, smbus_base + SMBHSTCMD);
|
||||
/* Set up for a byte data read */
|
||||
outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | (0x2 << 2),
|
||||
(smbus_base + SMBHSTCTL));
|
||||
/* Clear any lingering errors, so the transaction will run */
|
||||
outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
|
||||
|
||||
/* Clear the data byte... */
|
||||
outb(0, smbus_base + SMBHSTDAT0);
|
||||
|
||||
/* Start the command */
|
||||
outb((inb(smbus_base + SMBHSTCTL) | 0x40),
|
||||
smbus_base + SMBHSTCTL);
|
||||
|
||||
/* Poll for transaction completion */
|
||||
if (smbus_wait_until_done(smbus_base) < 0)
|
||||
return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
|
||||
|
||||
global_status_register = inb(smbus_base + SMBHSTSTAT);
|
||||
|
||||
/* Ignore the "In Use" status... */
|
||||
global_status_register &= ~(3 << 5);
|
||||
|
||||
/* Read results of transaction */
|
||||
byte = inb(smbus_base + SMBHSTDAT0);
|
||||
if (global_status_register != (1 << 1))
|
||||
return SMBUS_ERROR;
|
||||
return byte;
|
||||
}
|
|
@ -17,6 +17,7 @@
|
|||
config SOUTHBRIDGE_INTEL_I82801IX
|
||||
bool
|
||||
select SOUTHBRIDGE_INTEL_COMMON
|
||||
select SOUTHBRIDGE_INTEL_COMMON_SMBUS
|
||||
select IOAPIC
|
||||
select HAVE_USBDEBUG
|
||||
select HAVE_HARD_RESET
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
#include <console/console.h>
|
||||
#include <device/pci_ids.h>
|
||||
#include <device/pci_def.h>
|
||||
#include <southbridge/intel/common/smbus.h>
|
||||
#include "i82801ix.h"
|
||||
#include "smbus.h"
|
||||
|
||||
void enable_smbus(void)
|
||||
{
|
||||
|
|
|
@ -154,22 +154,6 @@
|
|||
#define SMB_SMI_EN (1 << 1)
|
||||
#define HST_EN (1 << 0)
|
||||
|
||||
/* SMBus I/O bits. */
|
||||
#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 SMBUS_TIMEOUT (10 * 1000 * 100)
|
||||
|
||||
|
||||
#define RCBA8(x) *((volatile u8 *)(DEFAULT_RCBA + x))
|
||||
#define RCBA16(x) *((volatile u16 *)(DEFAULT_RCBA + x))
|
||||
#define RCBA32(x) *((volatile u32 *)(DEFAULT_RCBA + x))
|
||||
|
|
|
@ -22,7 +22,8 @@
|
|||
#include <device/pci_ids.h>
|
||||
#include <device/pci_ops.h>
|
||||
#include <arch/io.h>
|
||||
#include "smbus.h"
|
||||
#include <southbridge/intel/common/smbus.h>
|
||||
#include "i82801ix.h"
|
||||
|
||||
static void pch_smbus_init(device_t dev)
|
||||
{
|
||||
|
|
|
@ -1,140 +0,0 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2005 Yinghai Lu <yinghailu@gmail.com>
|
||||
* Copyright (C) 2009 coresystems GmbH
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <device/smbus_def.h>
|
||||
#include "i82801ix.h"
|
||||
|
||||
static void smbus_delay(void)
|
||||
{
|
||||
inb(0x80);
|
||||
}
|
||||
|
||||
static int smbus_wait_until_ready(u16 smbus_base)
|
||||
{
|
||||
unsigned loops = SMBUS_TIMEOUT;
|
||||
unsigned char byte;
|
||||
do {
|
||||
smbus_delay();
|
||||
if (--loops == 0)
|
||||
break;
|
||||
byte = inb(smbus_base + SMBHSTSTAT);
|
||||
} while (byte & 1);
|
||||
return loops ? 0 : -1;
|
||||
}
|
||||
|
||||
static int smbus_wait_until_done(u16 smbus_base)
|
||||
{
|
||||
unsigned loops = SMBUS_TIMEOUT;
|
||||
unsigned char byte;
|
||||
do {
|
||||
smbus_delay();
|
||||
if (--loops == 0)
|
||||
break;
|
||||
byte = inb(smbus_base + SMBHSTSTAT);
|
||||
} while ((byte & 1) || (byte & ~((1 << 6) | (1 << 0))) == 0);
|
||||
return loops ? 0 : -1;
|
||||
}
|
||||
|
||||
static int do_smbus_read_byte(unsigned smbus_base, unsigned device, unsigned address)
|
||||
{
|
||||
unsigned char global_status_register;
|
||||
unsigned char byte;
|
||||
|
||||
if (smbus_wait_until_ready(smbus_base) < 0) {
|
||||
return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
|
||||
}
|
||||
/* Setup transaction */
|
||||
/* Disable interrupts */
|
||||
outb(inb(smbus_base + SMBHSTCTL) & (~1), smbus_base + SMBHSTCTL);
|
||||
/* Set the device I'm talking too */
|
||||
outb(((device & 0x7f) << 1) | 1, smbus_base + SMBXMITADD);
|
||||
/* Set the command/address... */
|
||||
outb(address & 0xff, smbus_base + SMBHSTCMD);
|
||||
/* Set up for a byte data read */
|
||||
outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | (0x2 << 2),
|
||||
(smbus_base + SMBHSTCTL));
|
||||
/* Clear any lingering errors, so the transaction will run */
|
||||
outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
|
||||
|
||||
/* Clear the data byte... */
|
||||
outb(0, smbus_base + SMBHSTDAT0);
|
||||
|
||||
/* Start the command */
|
||||
outb((inb(smbus_base + SMBHSTCTL) | 0x40),
|
||||
smbus_base + SMBHSTCTL);
|
||||
|
||||
/* Poll for transaction completion */
|
||||
if (smbus_wait_until_done(smbus_base) < 0) {
|
||||
return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
|
||||
}
|
||||
|
||||
global_status_register = inb(smbus_base + SMBHSTSTAT);
|
||||
|
||||
/* Ignore the "In Use" status... */
|
||||
global_status_register &= ~(3 << 5);
|
||||
|
||||
/* Read results of transaction */
|
||||
byte = inb(smbus_base + SMBHSTDAT0);
|
||||
if (global_status_register != (1 << 1)) {
|
||||
return SMBUS_ERROR;
|
||||
}
|
||||
return byte;
|
||||
}
|
||||
|
||||
#ifndef __PRE_RAM__
|
||||
static int do_smbus_write_byte(unsigned smbus_base, unsigned device, unsigned address, unsigned data)
|
||||
{
|
||||
unsigned char global_status_register;
|
||||
|
||||
if (smbus_wait_until_ready(smbus_base) < 0)
|
||||
return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
|
||||
|
||||
/* Setup transaction */
|
||||
/* Disable interrupts */
|
||||
outb(inb(smbus_base + SMBHSTCTL) & (~1), smbus_base + SMBHSTCTL);
|
||||
/* Set the device I'm talking too */
|
||||
outb(((device & 0x7f) << 1) & ~0x01, smbus_base + SMBXMITADD);
|
||||
/* Set the command/address... */
|
||||
outb(address & 0xff, smbus_base + SMBHSTCMD);
|
||||
/* Set up for a byte data read */
|
||||
outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | (0x2 << 2),
|
||||
(smbus_base + SMBHSTCTL));
|
||||
/* Clear any lingering errors, so the transaction will run */
|
||||
outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
|
||||
|
||||
/* Clear the data byte... */
|
||||
outb(data, smbus_base + SMBHSTDAT0);
|
||||
|
||||
/* Start the command */
|
||||
outb((inb(smbus_base + SMBHSTCTL) | 0x40),
|
||||
smbus_base + SMBHSTCTL);
|
||||
|
||||
/* Poll for transaction completion */
|
||||
if (smbus_wait_until_done(smbus_base) < 0)
|
||||
return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
|
||||
|
||||
global_status_register = inb(smbus_base + SMBHSTSTAT);
|
||||
|
||||
/* Ignore the "In Use" status... */
|
||||
global_status_register &= ~(3 << 5);
|
||||
|
||||
/* Read results of transaction */
|
||||
if (global_status_register != (1 << 1))
|
||||
return SMBUS_ERROR;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
|
@ -17,6 +17,7 @@
|
|||
config SOUTHBRIDGE_INTEL_I82801JX
|
||||
bool
|
||||
select SOUTHBRIDGE_INTEL_COMMON
|
||||
select SOUTHBRIDGE_INTEL_COMMON_SMBUS
|
||||
select IOAPIC
|
||||
select HAVE_USBDEBUG
|
||||
select HAVE_HARD_RESET
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
#include <console/console.h>
|
||||
#include <device/pci_ids.h>
|
||||
#include <device/pci_def.h>
|
||||
#include <southbridge/intel/common/smbus.h>
|
||||
#include "i82801jx.h"
|
||||
#include "smbus.h"
|
||||
|
||||
void enable_smbus(void)
|
||||
{
|
||||
|
|
|
@ -147,22 +147,6 @@
|
|||
#define SMB_SMI_EN (1 << 1)
|
||||
#define HST_EN (1 << 0)
|
||||
|
||||
/* SMBus I/O bits. */
|
||||
#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 SMBUS_TIMEOUT (10 * 1000 * 100)
|
||||
|
||||
|
||||
#define RCBA8(x) *((volatile u8 *)(DEFAULT_RCBA + x))
|
||||
#define RCBA16(x) *((volatile u16 *)(DEFAULT_RCBA + x))
|
||||
#define RCBA32(x) *((volatile u32 *)(DEFAULT_RCBA + x))
|
||||
|
|
|
@ -22,7 +22,8 @@
|
|||
#include <device/pci_ids.h>
|
||||
#include <device/pci_ops.h>
|
||||
#include <arch/io.h>
|
||||
#include "smbus.h"
|
||||
#include <southbridge/intel/common/smbus.h>
|
||||
#include "i82801jx.h"
|
||||
|
||||
static void pch_smbus_init(device_t dev)
|
||||
{
|
||||
|
|
|
@ -1,140 +0,0 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2005 Yinghai Lu <yinghailu@gmail.com>
|
||||
* Copyright (C) 2009 coresystems GmbH
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <device/smbus_def.h>
|
||||
#include "i82801jx.h"
|
||||
|
||||
static void smbus_delay(void)
|
||||
{
|
||||
inb(0x80);
|
||||
}
|
||||
|
||||
static int smbus_wait_until_ready(u16 smbus_base)
|
||||
{
|
||||
unsigned loops = SMBUS_TIMEOUT;
|
||||
unsigned char byte;
|
||||
do {
|
||||
smbus_delay();
|
||||
if (--loops == 0)
|
||||
break;
|
||||
byte = inb(smbus_base + SMBHSTSTAT);
|
||||
} while (byte & 1);
|
||||
return loops ? 0 : -1;
|
||||
}
|
||||
|
||||
static int smbus_wait_until_done(u16 smbus_base)
|
||||
{
|
||||
unsigned loops = SMBUS_TIMEOUT;
|
||||
unsigned char byte;
|
||||
do {
|
||||
smbus_delay();
|
||||
if (--loops == 0)
|
||||
break;
|
||||
byte = inb(smbus_base + SMBHSTSTAT);
|
||||
} while ((byte & 1) || (byte & ~((1 << 6) | (1 << 0))) == 0);
|
||||
return loops ? 0 : -1;
|
||||
}
|
||||
|
||||
static int do_smbus_read_byte(unsigned smbus_base, unsigned device, unsigned address)
|
||||
{
|
||||
unsigned char global_status_register;
|
||||
unsigned char byte;
|
||||
|
||||
if (smbus_wait_until_ready(smbus_base) < 0) {
|
||||
return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
|
||||
}
|
||||
/* Setup transaction */
|
||||
/* Disable interrupts */
|
||||
outb(inb(smbus_base + SMBHSTCTL) & (~1), smbus_base + SMBHSTCTL);
|
||||
/* Set the device I'm talking too */
|
||||
outb(((device & 0x7f) << 1) | 1, smbus_base + SMBXMITADD);
|
||||
/* Set the command/address... */
|
||||
outb(address & 0xff, smbus_base + SMBHSTCMD);
|
||||
/* Set up for a byte data read */
|
||||
outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | (0x2 << 2),
|
||||
(smbus_base + SMBHSTCTL));
|
||||
/* Clear any lingering errors, so the transaction will run */
|
||||
outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
|
||||
|
||||
/* Clear the data byte... */
|
||||
outb(0, smbus_base + SMBHSTDAT0);
|
||||
|
||||
/* Start the command */
|
||||
outb((inb(smbus_base + SMBHSTCTL) | 0x40),
|
||||
smbus_base + SMBHSTCTL);
|
||||
|
||||
/* Poll for transaction completion */
|
||||
if (smbus_wait_until_done(smbus_base) < 0) {
|
||||
return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
|
||||
}
|
||||
|
||||
global_status_register = inb(smbus_base + SMBHSTSTAT);
|
||||
|
||||
/* Ignore the "In Use" status... */
|
||||
global_status_register &= ~(3 << 5);
|
||||
|
||||
/* Read results of transaction */
|
||||
byte = inb(smbus_base + SMBHSTDAT0);
|
||||
if (global_status_register != (1 << 1)) {
|
||||
return SMBUS_ERROR;
|
||||
}
|
||||
return byte;
|
||||
}
|
||||
|
||||
#ifndef __PRE_RAM__
|
||||
static int do_smbus_write_byte(unsigned smbus_base, unsigned device, unsigned address, unsigned data)
|
||||
{
|
||||
unsigned char global_status_register;
|
||||
|
||||
if (smbus_wait_until_ready(smbus_base) < 0)
|
||||
return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
|
||||
|
||||
/* Setup transaction */
|
||||
/* Disable interrupts */
|
||||
outb(inb(smbus_base + SMBHSTCTL) & (~1), smbus_base + SMBHSTCTL);
|
||||
/* Set the device I'm talking too */
|
||||
outb(((device & 0x7f) << 1) & ~0x01, smbus_base + SMBXMITADD);
|
||||
/* Set the command/address... */
|
||||
outb(address & 0xff, smbus_base + SMBHSTCMD);
|
||||
/* Set up for a byte data read */
|
||||
outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | (0x2 << 2),
|
||||
(smbus_base + SMBHSTCTL));
|
||||
/* Clear any lingering errors, so the transaction will run */
|
||||
outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
|
||||
|
||||
/* Clear the data byte... */
|
||||
outb(data, smbus_base + SMBHSTDAT0);
|
||||
|
||||
/* Start the command */
|
||||
outb((inb(smbus_base + SMBHSTCTL) | 0x40),
|
||||
smbus_base + SMBHSTCTL);
|
||||
|
||||
/* Poll for transaction completion */
|
||||
if (smbus_wait_until_done(smbus_base) < 0)
|
||||
return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
|
||||
|
||||
global_status_register = inb(smbus_base + SMBHSTSTAT);
|
||||
|
||||
/* Ignore the "In Use" status... */
|
||||
global_status_register &= ~(3 << 5);
|
||||
|
||||
/* Read results of transaction */
|
||||
if (global_status_register != (1 << 1))
|
||||
return SMBUS_ERROR;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
|
@ -30,6 +30,7 @@ config SOUTH_BRIDGE_OPTIONS # dummy
|
|||
select PCIEXP_COMMON_CLOCK
|
||||
select SPI_FLASH
|
||||
select SOUTHBRIDGE_INTEL_COMMON
|
||||
select SOUTHBRIDGE_INTEL_COMMON_SMBUS
|
||||
select HAVE_USBDEBUG_OPTIONS
|
||||
select COMMON_FADT
|
||||
select ACPI_SATA_GENERATOR
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
#include <console/console.h>
|
||||
#include <device/pci_ids.h>
|
||||
#include <device/pci_def.h>
|
||||
#include <southbridge/intel/common/smbus.h>
|
||||
#include "pch.h"
|
||||
#include "smbus.h"
|
||||
|
||||
void enable_smbus(void)
|
||||
{
|
||||
|
|
|
@ -233,22 +233,6 @@ void southbridge_configure_default_intmap(void);
|
|||
#define SMB_SMI_EN (1 << 1)
|
||||
#define HST_EN (1 << 0)
|
||||
|
||||
/* SMBus I/O bits. */
|
||||
#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 SMBUS_TIMEOUT (10 * 1000 * 100)
|
||||
|
||||
|
||||
/* Southbridge IO BARs */
|
||||
|
||||
#define GPIOBASE 0x48
|
||||
|
|
|
@ -22,8 +22,8 @@
|
|||
#include <device/pci_ids.h>
|
||||
#include <device/pci_ops.h>
|
||||
#include <arch/io.h>
|
||||
#include <southbridge/intel/common/smbus.h>
|
||||
#include "pch.h"
|
||||
#include "smbus.h"
|
||||
|
||||
static void pch_smbus_init(device_t dev)
|
||||
{
|
||||
|
|
|
@ -1,241 +0,0 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2005 Yinghai Lu <yinghailu@gmail.com>
|
||||
* Copyright (C) 2009 coresystems GmbH
|
||||
* Copyright (C) 2013 Vladimir Serbinenko
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <device/smbus_def.h>
|
||||
#include "pch.h"
|
||||
|
||||
static void smbus_delay(void)
|
||||
{
|
||||
inb(0x80);
|
||||
}
|
||||
|
||||
static int smbus_wait_until_ready(u16 smbus_base)
|
||||
{
|
||||
unsigned loops = SMBUS_TIMEOUT;
|
||||
unsigned char byte;
|
||||
do {
|
||||
smbus_delay();
|
||||
if (--loops == 0)
|
||||
break;
|
||||
byte = inb(smbus_base + SMBHSTSTAT);
|
||||
} while (byte & 1);
|
||||
return loops ? 0 : -1;
|
||||
}
|
||||
|
||||
static int smbus_wait_until_done(u16 smbus_base)
|
||||
{
|
||||
unsigned loops = SMBUS_TIMEOUT;
|
||||
unsigned char byte;
|
||||
do {
|
||||
smbus_delay();
|
||||
if (--loops == 0)
|
||||
break;
|
||||
byte = inb(smbus_base + SMBHSTSTAT);
|
||||
} while ((byte & 1) || (byte & ~((1 << 6) | (1 << 0))) == 0);
|
||||
return loops ? 0 : -1;
|
||||
}
|
||||
|
||||
static int do_smbus_read_byte(unsigned smbus_base, unsigned device, unsigned address)
|
||||
{
|
||||
unsigned char global_status_register;
|
||||
unsigned char byte;
|
||||
|
||||
if (smbus_wait_until_ready(smbus_base) < 0) {
|
||||
return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
|
||||
}
|
||||
/* Setup transaction */
|
||||
/* Disable interrupts */
|
||||
outb(inb(smbus_base + SMBHSTCTL) & (~1), smbus_base + SMBHSTCTL);
|
||||
/* Set the device I'm talking too */
|
||||
outb(((device & 0x7f) << 1) | 1, smbus_base + SMBXMITADD);
|
||||
/* Set the command/address... */
|
||||
outb(address & 0xff, smbus_base + SMBHSTCMD);
|
||||
/* Set up for a byte data read */
|
||||
outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | (0x2 << 2),
|
||||
(smbus_base + SMBHSTCTL));
|
||||
/* Clear any lingering errors, so the transaction will run */
|
||||
outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
|
||||
|
||||
/* Clear the data byte... */
|
||||
outb(0, smbus_base + SMBHSTDAT0);
|
||||
|
||||
/* Start the command */
|
||||
outb((inb(smbus_base + SMBHSTCTL) | 0x40),
|
||||
smbus_base + SMBHSTCTL);
|
||||
|
||||
/* Poll for transaction completion */
|
||||
if (smbus_wait_until_done(smbus_base) < 0) {
|
||||
return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
|
||||
}
|
||||
|
||||
global_status_register = inb(smbus_base + SMBHSTSTAT);
|
||||
|
||||
/* Ignore the "In Use" status... */
|
||||
global_status_register &= ~(3 << 5);
|
||||
|
||||
/* Read results of transaction */
|
||||
byte = inb(smbus_base + SMBHSTDAT0);
|
||||
if (global_status_register != (1 << 1)) {
|
||||
return SMBUS_ERROR;
|
||||
}
|
||||
return byte;
|
||||
}
|
||||
|
||||
static int do_smbus_write_byte(unsigned smbus_base, unsigned device, unsigned address, unsigned data)
|
||||
{
|
||||
unsigned char global_status_register;
|
||||
|
||||
if (smbus_wait_until_ready(smbus_base) < 0)
|
||||
return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
|
||||
|
||||
/* Setup transaction */
|
||||
/* Disable interrupts */
|
||||
outb(inb(smbus_base + SMBHSTCTL) & (~1), smbus_base + SMBHSTCTL);
|
||||
/* Set the device I'm talking too */
|
||||
outb(((device & 0x7f) << 1) & ~0x01, smbus_base + SMBXMITADD);
|
||||
/* Set the command/address... */
|
||||
outb(address & 0xff, smbus_base + SMBHSTCMD);
|
||||
/* Set up for a byte data read */
|
||||
outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | (0x2 << 2),
|
||||
(smbus_base + SMBHSTCTL));
|
||||
/* Clear any lingering errors, so the transaction will run */
|
||||
outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
|
||||
|
||||
/* Clear the data byte... */
|
||||
outb(data, smbus_base + SMBHSTDAT0);
|
||||
|
||||
/* Start the command */
|
||||
outb((inb(smbus_base + SMBHSTCTL) | 0x40),
|
||||
smbus_base + SMBHSTCTL);
|
||||
|
||||
/* Poll for transaction completion */
|
||||
if (smbus_wait_until_done(smbus_base) < 0)
|
||||
return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
|
||||
|
||||
global_status_register = inb(smbus_base + SMBHSTSTAT);
|
||||
|
||||
/* Ignore the "In Use" status... */
|
||||
global_status_register &= ~(3 << 5);
|
||||
|
||||
/* Read results of transaction */
|
||||
if (global_status_register != (1 << 1))
|
||||
return SMBUS_ERROR;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef __PRE_RAM__
|
||||
|
||||
static int do_smbus_block_write(unsigned smbus_base, unsigned device,
|
||||
unsigned cmd, unsigned bytes, const u8 *buf)
|
||||
{
|
||||
u8 status;
|
||||
|
||||
if (smbus_wait_until_ready(smbus_base) < 0)
|
||||
return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
|
||||
|
||||
/* Setup transaction */
|
||||
/* Disable interrupts */
|
||||
outb(inb(smbus_base + SMBHSTCTL) & (~1), smbus_base + SMBHSTCTL);
|
||||
/* Set the device I'm talking too */
|
||||
outb(((device & 0x7f) << 1) & ~0x01, smbus_base + SMBXMITADD);
|
||||
/* Set the command/address... */
|
||||
outb(cmd & 0xff, smbus_base + SMBHSTCMD);
|
||||
/* Set up for a block data write */
|
||||
outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | (0x5 << 2),
|
||||
(smbus_base + SMBHSTCTL));
|
||||
/* Clear any lingering errors, so the transaction will run */
|
||||
outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
|
||||
|
||||
/* set number of bytes to transfer */
|
||||
outb(bytes, smbus_base + SMBHSTDAT0);
|
||||
|
||||
outb(*buf++, smbus_base + SMBBLKDAT);
|
||||
bytes--;
|
||||
|
||||
/* Start the command */
|
||||
outb((inb(smbus_base + SMBHSTCTL) | 0x40),
|
||||
smbus_base + SMBHSTCTL);
|
||||
|
||||
while (!(inb(smbus_base + SMBHSTSTAT) & 1));
|
||||
/* Poll for transaction completion */
|
||||
do {
|
||||
status = inb(smbus_base + SMBHSTSTAT);
|
||||
if (status & ((1 << 4) | /* FAILED */
|
||||
(1 << 3) | /* BUS ERR */
|
||||
(1 << 2))) /* DEV ERR */
|
||||
return SMBUS_ERROR;
|
||||
|
||||
if (status & 0x80) { /* Byte done */
|
||||
outb(*buf++, smbus_base + SMBBLKDAT);
|
||||
outb(status, smbus_base + SMBHSTSTAT);
|
||||
}
|
||||
} while (status & 0x01);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_smbus_block_read(unsigned smbus_base, unsigned device,
|
||||
unsigned cmd, unsigned bytes, u8 *buf)
|
||||
{
|
||||
u8 status;
|
||||
int bytes_read = 0;
|
||||
if (smbus_wait_until_ready(smbus_base) < 0)
|
||||
return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
|
||||
|
||||
/* Setup transaction */
|
||||
/* Disable interrupts */
|
||||
outb(inb(smbus_base + SMBHSTCTL) & (~1), smbus_base + SMBHSTCTL);
|
||||
/* Set the device I'm talking too */
|
||||
outb(((device & 0x7f) << 1) | 1, smbus_base + SMBXMITADD);
|
||||
/* Set the command/address... */
|
||||
outb(cmd & 0xff, smbus_base + SMBHSTCMD);
|
||||
/* Set up for a block data read */
|
||||
outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | (0x5 << 2),
|
||||
(smbus_base + SMBHSTCTL));
|
||||
/* Clear any lingering errors, so the transaction will run */
|
||||
outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
|
||||
|
||||
/* Start the command */
|
||||
outb((inb(smbus_base + SMBHSTCTL) | 0x40),
|
||||
smbus_base + SMBHSTCTL);
|
||||
|
||||
while (!(inb(smbus_base + SMBHSTSTAT) & 1));
|
||||
/* Poll for transaction completion */
|
||||
do {
|
||||
status = inb(smbus_base + SMBHSTSTAT);
|
||||
if (status & ((1 << 4) | /* FAILED */
|
||||
(1 << 3) | /* BUS ERR */
|
||||
(1 << 2))) /* DEV ERR */
|
||||
return SMBUS_ERROR;
|
||||
|
||||
if (status & 0x80) { /* Byte done */
|
||||
*buf = inb(smbus_base + SMBBLKDAT);
|
||||
buf++;
|
||||
bytes_read++;
|
||||
outb(status, smbus_base + SMBHSTSTAT);
|
||||
if (--bytes == 1) {
|
||||
/* indicate that next byte is the last one */
|
||||
outb(inb(smbus_base + SMBHSTCTL) | 0x20,
|
||||
smbus_base + SMBHSTCTL);
|
||||
}
|
||||
}
|
||||
} while (status & 0x01);
|
||||
|
||||
return bytes_read;
|
||||
}
|
||||
#endif
|
|
@ -22,6 +22,7 @@ config SOUTH_BRIDGE_OPTIONS # dummy
|
|||
def_bool y
|
||||
select ACPI_INTEL_HARDWARE_SLEEP_VALUES
|
||||
select SOUTHBRIDGE_INTEL_COMMON
|
||||
select SOUTHBRIDGE_INTEL_COMMON_SMBUS
|
||||
select IOAPIC
|
||||
select HAVE_HARD_RESET
|
||||
select HAVE_USBDEBUG_OPTIONS
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
#include <console/console.h>
|
||||
#include <device/pci_ids.h>
|
||||
#include <device/pci_def.h>
|
||||
#include <southbridge/intel/common/smbus.h>
|
||||
#include "pch.h"
|
||||
#include "smbus.h"
|
||||
|
||||
void enable_smbus(void)
|
||||
{
|
||||
|
|
|
@ -473,22 +473,6 @@ void pch_enable_lpc(void);
|
|||
#define SMB_SMI_EN (1 << 1)
|
||||
#define HST_EN (1 << 0)
|
||||
|
||||
/* SMBus I/O bits. */
|
||||
#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 SMBUS_TIMEOUT (10 * 1000 * 100)
|
||||
|
||||
|
||||
/* Southbridge IO BARs */
|
||||
|
||||
#define GPIOBASE 0x48
|
||||
|
|
|
@ -22,8 +22,8 @@
|
|||
#include <device/pci_ids.h>
|
||||
#include <device/pci_ops.h>
|
||||
#include <arch/io.h>
|
||||
#include <southbridge/intel/common/smbus.h>
|
||||
#include "pch.h"
|
||||
#include "smbus.h"
|
||||
|
||||
static void pch_smbus_init(device_t dev)
|
||||
{
|
||||
|
@ -54,54 +54,6 @@ static int lsmbus_read_byte(device_t dev, u8 address)
|
|||
return do_smbus_read_byte(res->base, device, address);
|
||||
}
|
||||
|
||||
static int do_smbus_write_byte(unsigned smbus_base, unsigned device,
|
||||
unsigned address, unsigned data)
|
||||
{
|
||||
unsigned char global_status_register;
|
||||
|
||||
if (smbus_wait_until_ready(smbus_base) < 0)
|
||||
return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
|
||||
|
||||
/* Setup transaction */
|
||||
/* Disable interrupts */
|
||||
outb(inb(smbus_base + SMBHSTCTL) & (~1), smbus_base + SMBHSTCTL);
|
||||
/* Set the device I'm talking too */
|
||||
outb(((device & 0x7f) << 1) & ~0x01, smbus_base + SMBXMITADD);
|
||||
/* Set the command/address... */
|
||||
outb(address & 0xff, smbus_base + SMBHSTCMD);
|
||||
/* Set up for a byte data read */
|
||||
outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | (0x2 << 2),
|
||||
(smbus_base + SMBHSTCTL));
|
||||
/* Clear any lingering errors, so the transaction will run */
|
||||
outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
|
||||
|
||||
/* Clear the data byte... */
|
||||
outb(data, smbus_base + SMBHSTDAT0);
|
||||
|
||||
/* Start the command */
|
||||
outb((inb(smbus_base + SMBHSTCTL) | 0x40),
|
||||
smbus_base + SMBHSTCTL);
|
||||
|
||||
/* Poll for transaction completion */
|
||||
if (smbus_wait_until_done(smbus_base) < 0) {
|
||||
printk(BIOS_ERR, "SMBUS transaction timeout\n");
|
||||
return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
|
||||
}
|
||||
|
||||
global_status_register = inb(smbus_base + SMBHSTSTAT);
|
||||
|
||||
/* Ignore the "In Use" status... */
|
||||
global_status_register &= ~(3 << 5);
|
||||
|
||||
/* Read results of transaction */
|
||||
if (global_status_register != (1 << 1)) {
|
||||
printk(BIOS_ERR, "SMBUS transaction error\n");
|
||||
return SMBUS_ERROR;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lsmbus_write_byte(device_t dev, u8 address, u8 data)
|
||||
{
|
||||
u16 device;
|
||||
|
|
|
@ -1,95 +0,0 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2005 Yinghai Lu <yinghailu@gmail.com>
|
||||
* Copyright (C) 2009 coresystems GmbH
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <device/smbus_def.h>
|
||||
#include "pch.h"
|
||||
|
||||
static void smbus_delay(void)
|
||||
{
|
||||
inb(0x80);
|
||||
}
|
||||
|
||||
static int smbus_wait_until_ready(u16 smbus_base)
|
||||
{
|
||||
unsigned loops = SMBUS_TIMEOUT;
|
||||
unsigned char byte;
|
||||
do {
|
||||
smbus_delay();
|
||||
if (--loops == 0)
|
||||
break;
|
||||
byte = inb(smbus_base + SMBHSTSTAT);
|
||||
} while (byte & 1);
|
||||
return loops ? 0 : -1;
|
||||
}
|
||||
|
||||
static int smbus_wait_until_done(u16 smbus_base)
|
||||
{
|
||||
unsigned loops = SMBUS_TIMEOUT;
|
||||
unsigned char byte;
|
||||
do {
|
||||
smbus_delay();
|
||||
if (--loops == 0)
|
||||
break;
|
||||
byte = inb(smbus_base + SMBHSTSTAT);
|
||||
} while ((byte & 1) || (byte & ~((1 << 6) | (1 << 0))) == 0);
|
||||
return loops ? 0 : -1;
|
||||
}
|
||||
|
||||
static int do_smbus_read_byte(unsigned smbus_base, unsigned device, unsigned address)
|
||||
{
|
||||
unsigned char global_status_register;
|
||||
unsigned char byte;
|
||||
|
||||
if (smbus_wait_until_ready(smbus_base) < 0) {
|
||||
return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
|
||||
}
|
||||
/* Setup transaction */
|
||||
/* Disable interrupts */
|
||||
outb(inb(smbus_base + SMBHSTCTL) & (~1), smbus_base + SMBHSTCTL);
|
||||
/* Set the device I'm talking too */
|
||||
outb(((device & 0x7f) << 1) | 1, smbus_base + SMBXMITADD);
|
||||
/* Set the command/address... */
|
||||
outb(address & 0xff, smbus_base + SMBHSTCMD);
|
||||
/* Set up for a byte data read */
|
||||
outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | (0x2 << 2),
|
||||
(smbus_base + SMBHSTCTL));
|
||||
/* Clear any lingering errors, so the transaction will run */
|
||||
outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
|
||||
|
||||
/* Clear the data byte... */
|
||||
outb(0, smbus_base + SMBHSTDAT0);
|
||||
|
||||
/* Start the command */
|
||||
outb((inb(smbus_base + SMBHSTCTL) | 0x40),
|
||||
smbus_base + SMBHSTCTL);
|
||||
|
||||
/* Poll for transaction completion */
|
||||
if (smbus_wait_until_done(smbus_base) < 0) {
|
||||
return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
|
||||
}
|
||||
|
||||
global_status_register = inb(smbus_base + SMBHSTSTAT);
|
||||
|
||||
/* Ignore the "In Use" status... */
|
||||
global_status_register &= ~(3 << 5);
|
||||
|
||||
/* Read results of transaction */
|
||||
byte = inb(smbus_base + SMBHSTDAT0);
|
||||
if (global_status_register != (1 << 1)) {
|
||||
return SMBUS_ERROR;
|
||||
}
|
||||
return byte;
|
||||
}
|
Loading…
Reference in New Issue