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_ERROR -1
|
||||||
#define SMBUS_WAIT_UNTIL_READY_TIMEOUT -2
|
#define SMBUS_WAIT_UNTIL_READY_TIMEOUT -2
|
||||||
#define SMBUS_WAIT_UNTIL_DONE_TIMEOUT -3
|
#define SMBUS_WAIT_UNTIL_DONE_TIMEOUT -3
|
||||||
|
#define SMBUS_WAIT_UNTIL_ACTIVE_TIMEOUT -4
|
||||||
|
|
||||||
#endif /* DEVICE_SMBUS_DEF_H */
|
#endif /* DEVICE_SMBUS_DEF_H */
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
#include <timestamp.h>
|
#include <timestamp.h>
|
||||||
#include <northbridge/intel/common/mrc_cache.h>
|
#include <northbridge/intel/common/mrc_cache.h>
|
||||||
#include <southbridge/intel/bd82x6x/me.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 <cpu/x86/msr.h>
|
||||||
#include <delay.h>
|
#include <delay.h>
|
||||||
#include <smbios.h>
|
#include <smbios.h>
|
||||||
|
|
|
@ -25,6 +25,7 @@ config SOUTH_BRIDGE_OPTIONS # dummy
|
||||||
def_bool y
|
def_bool y
|
||||||
select ACPI_INTEL_HARDWARE_SLEEP_VALUES
|
select ACPI_INTEL_HARDWARE_SLEEP_VALUES
|
||||||
select SOUTHBRIDGE_INTEL_COMMON
|
select SOUTHBRIDGE_INTEL_COMMON
|
||||||
|
select SOUTHBRIDGE_INTEL_COMMON_SMBUS
|
||||||
select IOAPIC
|
select IOAPIC
|
||||||
select HAVE_HARD_RESET
|
select HAVE_HARD_RESET
|
||||||
select HAVE_USBDEBUG_OPTIONS
|
select HAVE_USBDEBUG_OPTIONS
|
||||||
|
|
|
@ -18,8 +18,8 @@
|
||||||
#include <console/console.h>
|
#include <console/console.h>
|
||||||
#include <device/pci_ids.h>
|
#include <device/pci_ids.h>
|
||||||
#include <device/pci_def.h>
|
#include <device/pci_def.h>
|
||||||
|
#include <southbridge/intel/common/smbus.h>
|
||||||
#include "pch.h"
|
#include "pch.h"
|
||||||
#include "smbus.h"
|
|
||||||
|
|
||||||
void enable_smbus(void)
|
void enable_smbus(void)
|
||||||
{
|
{
|
||||||
|
|
|
@ -265,22 +265,6 @@ early_usb_init (const struct southbridge_usb_port *portmap);
|
||||||
#define SMB_SMI_EN (1 << 1)
|
#define SMB_SMI_EN (1 << 1)
|
||||||
#define HST_EN (1 << 0)
|
#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 */
|
/* Southbridge IO BARs */
|
||||||
|
|
||||||
#define GPIOBASE 0x48
|
#define GPIOBASE 0x48
|
||||||
|
|
|
@ -22,8 +22,8 @@
|
||||||
#include <device/pci_ids.h>
|
#include <device/pci_ids.h>
|
||||||
#include <device/pci_ops.h>
|
#include <device/pci_ops.h>
|
||||||
#include <arch/io.h>
|
#include <arch/io.h>
|
||||||
|
#include <southbridge/intel/common/smbus.h>
|
||||||
#include "pch.h"
|
#include "pch.h"
|
||||||
#include "smbus.h"
|
|
||||||
|
|
||||||
static void pch_smbus_init(device_t dev)
|
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);
|
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)
|
static int lsmbus_write_byte(device_t dev, u8 address, u8 val)
|
||||||
{
|
{
|
||||||
u16 device;
|
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
|
def_bool n
|
||||||
config SOUTHBRIDGE_INTEL_COMMON_GPIO
|
config SOUTHBRIDGE_INTEL_COMMON_GPIO
|
||||||
def_bool n
|
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
|
romstage-$(CONFIG_SOUTHBRIDGE_INTEL_COMMON_GPIO) += gpio.c
|
||||||
ramstage-$(CONFIG_SOUTHBRIDGE_INTEL_COMMON_GPIO) += gpio.c
|
ramstage-$(CONFIG_SOUTHBRIDGE_INTEL_COMMON_GPIO) += gpio.c
|
||||||
smm-$(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
|
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 SPI_FLASH
|
||||||
select COMMON_FADT
|
select COMMON_FADT
|
||||||
select HAVE_INTEL_FIRMWARE
|
select HAVE_INTEL_FIRMWARE
|
||||||
|
select SOUTHBRIDGE_INTEL_COMMON
|
||||||
|
select SOUTHBRIDGE_INTEL_COMMON_SMBUS
|
||||||
|
|
||||||
config EHCI_BAR
|
config EHCI_BAR
|
||||||
hex
|
hex
|
||||||
|
|
|
@ -32,6 +32,8 @@ config SOUTH_BRIDGE_OPTIONS # dummy
|
||||||
select COMMON_FADT
|
select COMMON_FADT
|
||||||
select HAVE_INTEL_FIRMWARE
|
select HAVE_INTEL_FIRMWARE
|
||||||
select NO_EARLY_BOOTBLOCK_POSTCODES
|
select NO_EARLY_BOOTBLOCK_POSTCODES
|
||||||
|
select SOUTHBRIDGE_INTEL_COMMON
|
||||||
|
select SOUTHBRIDGE_INTEL_COMMON_SMBUS
|
||||||
|
|
||||||
config EHCI_BAR
|
config EHCI_BAR
|
||||||
hex
|
hex
|
||||||
|
|
|
@ -19,8 +19,8 @@
|
||||||
#include <console/console.h>
|
#include <console/console.h>
|
||||||
#include <device/pci_ids.h>
|
#include <device/pci_ids.h>
|
||||||
#include <device/pci_def.h>
|
#include <device/pci_def.h>
|
||||||
|
#include <southbridge/intel/common/smbus.h>
|
||||||
#include "pch.h"
|
#include "pch.h"
|
||||||
#include "smbus.h"
|
|
||||||
|
|
||||||
void enable_smbus(void)
|
void enable_smbus(void)
|
||||||
{
|
{
|
||||||
|
|
|
@ -174,22 +174,6 @@ void early_pch_init(void);
|
||||||
#define SMB_SMI_EN (1 << 1)
|
#define SMB_SMI_EN (1 << 1)
|
||||||
#define HST_EN (1 << 0)
|
#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 */
|
/* Southbridge IO BARs */
|
||||||
|
|
||||||
#define GPIOBASE 0x48
|
#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 PCIEXP_COMMON_CLOCK
|
||||||
select SPI_FLASH
|
select SPI_FLASH
|
||||||
select HAVE_INTEL_FIRMWARE
|
select HAVE_INTEL_FIRMWARE
|
||||||
|
select SOUTHBRIDGE_INTEL_COMMON
|
||||||
|
select SOUTHBRIDGE_INTEL_COMMON_SMBUS
|
||||||
|
|
||||||
config EHCI_BAR
|
config EHCI_BAR
|
||||||
hex
|
hex
|
||||||
|
|
|
@ -18,8 +18,8 @@
|
||||||
#include <console/console.h>
|
#include <console/console.h>
|
||||||
#include <device/pci_ids.h>
|
#include <device/pci_ids.h>
|
||||||
#include <device/pci_def.h>
|
#include <device/pci_def.h>
|
||||||
|
#include <southbridge/intel/common/smbus.h>
|
||||||
#include "soc.h"
|
#include "soc.h"
|
||||||
#include "smbus.h"
|
|
||||||
|
|
||||||
void enable_smbus(void)
|
void enable_smbus(void)
|
||||||
{
|
{
|
||||||
|
|
|
@ -22,8 +22,8 @@
|
||||||
#include <device/pci_ids.h>
|
#include <device/pci_ids.h>
|
||||||
#include <device/pci_ops.h>
|
#include <device/pci_ops.h>
|
||||||
#include <arch/io.h>
|
#include <arch/io.h>
|
||||||
|
#include <southbridge/intel/common/smbus.h>
|
||||||
#include "soc.h"
|
#include "soc.h"
|
||||||
#include "smbus.h"
|
|
||||||
|
|
||||||
static int lsmbus_read_byte(device_t dev, u8 address)
|
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 SMB_SMI_EN (1 << 1)
|
||||||
#define HST_EN (1 << 0)
|
#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 */
|
/* Root Complex Register Block */
|
||||||
#define RCBA 0xf0
|
#define RCBA 0xf0
|
||||||
#define RCBA_ENABLE 0x01
|
#define RCBA_ENABLE 0x01
|
||||||
|
|
|
@ -2,6 +2,8 @@ config SOUTHBRIDGE_INTEL_I3100
|
||||||
bool
|
bool
|
||||||
select IOAPIC
|
select IOAPIC
|
||||||
select HAVE_HARD_RESET
|
select HAVE_HARD_RESET
|
||||||
|
select SOUTHBRIDGE_INTEL_COMMON
|
||||||
|
select SOUTHBRIDGE_INTEL_COMMON_SMBUS
|
||||||
|
|
||||||
if SOUTHBRIDGE_INTEL_I3100
|
if SOUTHBRIDGE_INTEL_I3100
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "smbus.h"
|
#include <southbridge/intel/common/smbus.h>
|
||||||
|
|
||||||
#define SMBUS_IO_BASE 0x0f00
|
#define SMBUS_IO_BASE 0x0f00
|
||||||
|
|
||||||
|
|
|
@ -21,8 +21,8 @@
|
||||||
#include <device/pci_ops.h>
|
#include <device/pci_ops.h>
|
||||||
#include <device/smbus.h>
|
#include <device/smbus.h>
|
||||||
#include <arch/io.h>
|
#include <arch/io.h>
|
||||||
|
#include <southbridge/intel/common/smbus.h>
|
||||||
#include "i3100.h"
|
#include "i3100.h"
|
||||||
#include "smbus.h"
|
|
||||||
|
|
||||||
static int lsmbus_read_byte(device_t dev, u8 address)
|
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
|
config SOUTHBRIDGE_INTEL_I82371EB
|
||||||
|
select SOUTHBRIDGE_INTEL_COMMON
|
||||||
|
select SOUTHBRIDGE_INTEL_COMMON_SMBUS
|
||||||
bool
|
bool
|
||||||
|
|
||||||
config BOOTBLOCK_SOUTHBRIDGE_INIT
|
config BOOTBLOCK_SOUTHBRIDGE_INIT
|
||||||
|
|
|
@ -19,8 +19,8 @@
|
||||||
#include <console/console.h>
|
#include <console/console.h>
|
||||||
#include <device/pci_ids.h>
|
#include <device/pci_ids.h>
|
||||||
#include <device/pci_def.h>
|
#include <device/pci_def.h>
|
||||||
|
#include <southbridge/intel/common/smbus.h>
|
||||||
#include "i82371eb.h"
|
#include "i82371eb.h"
|
||||||
#include "smbus.h"
|
|
||||||
|
|
||||||
void enable_smbus(void)
|
void enable_smbus(void)
|
||||||
{
|
{
|
||||||
|
@ -46,7 +46,7 @@ void enable_smbus(void)
|
||||||
pci_write_config16(dev, PCI_COMMAND, reg16);
|
pci_write_config16(dev, PCI_COMMAND, reg16);
|
||||||
|
|
||||||
/* Clear any lingering errors, so the transaction will run. */
|
/* 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)
|
int smbus_read_byte(u8 device, u8 address)
|
||||||
|
|
|
@ -24,8 +24,8 @@
|
||||||
#include <device/pci.h>
|
#include <device/pci.h>
|
||||||
#include <device/pci_ids.h>
|
#include <device/pci_ids.h>
|
||||||
#include <device/smbus.h>
|
#include <device/smbus.h>
|
||||||
|
#include <southbridge/intel/common/smbus.h>
|
||||||
#include "i82371eb.h"
|
#include "i82371eb.h"
|
||||||
#include "smbus.h"
|
|
||||||
|
|
||||||
static void pwrmgt_enable(struct device *dev)
|
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 IOAPIC
|
||||||
select HAVE_HARD_RESET
|
select HAVE_HARD_RESET
|
||||||
select USE_WATCHDOG_ON_BOOT
|
select USE_WATCHDOG_ON_BOOT
|
||||||
|
select SOUTHBRIDGE_INTEL_COMMON
|
||||||
|
select SOUTHBRIDGE_INTEL_COMMON_SMBUS
|
||||||
|
|
|
@ -20,8 +20,8 @@
|
||||||
#include <console/console.h>
|
#include <console/console.h>
|
||||||
#include <device/pci_ids.h>
|
#include <device/pci_ids.h>
|
||||||
#include <device/pci_def.h>
|
#include <device/pci_def.h>
|
||||||
|
#include <southbridge/intel/common/smbus.h>
|
||||||
#include "i82801ax.h"
|
#include "i82801ax.h"
|
||||||
#include "smbus.h"
|
|
||||||
|
|
||||||
void enable_smbus(void)
|
void enable_smbus(void)
|
||||||
{
|
{
|
||||||
|
|
|
@ -90,15 +90,4 @@ int smbus_read_byte(u8 device, u8 address);
|
||||||
#define SMB_SMI_EN (1 << 1)
|
#define SMB_SMI_EN (1 << 1)
|
||||||
#define HST_EN (1 << 0)
|
#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
|
#endif
|
||||||
|
|
|
@ -19,8 +19,8 @@
|
||||||
#include <device/pci.h>
|
#include <device/pci.h>
|
||||||
#include <device/pci_ids.h>
|
#include <device/pci_ids.h>
|
||||||
#include <arch/io.h>
|
#include <arch/io.h>
|
||||||
|
#include <southbridge/intel/common/smbus.h>
|
||||||
#include "i82801ax.h"
|
#include "i82801ax.h"
|
||||||
#include "smbus.h"
|
|
||||||
|
|
||||||
static int lsmbus_read_byte(device_t dev, u8 address)
|
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 IOAPIC
|
||||||
select HAVE_HARD_RESET
|
select HAVE_HARD_RESET
|
||||||
select USE_WATCHDOG_ON_BOOT
|
select USE_WATCHDOG_ON_BOOT
|
||||||
|
select SOUTHBRIDGE_INTEL_COMMON
|
||||||
|
select SOUTHBRIDGE_INTEL_COMMON_SMBUS
|
||||||
|
|
|
@ -20,8 +20,8 @@
|
||||||
#include <console/console.h>
|
#include <console/console.h>
|
||||||
#include <device/pci_ids.h>
|
#include <device/pci_ids.h>
|
||||||
#include <device/pci_def.h>
|
#include <device/pci_def.h>
|
||||||
|
#include <southbridge/intel/common/smbus.h>
|
||||||
#include "i82801bx.h"
|
#include "i82801bx.h"
|
||||||
#include "smbus.h"
|
|
||||||
|
|
||||||
void enable_smbus(void)
|
void enable_smbus(void)
|
||||||
{
|
{
|
||||||
|
|
|
@ -99,19 +99,4 @@ int smbus_read_byte(u8 device, u8 address);
|
||||||
#define SMB_SMI_EN (1 << 1)
|
#define SMB_SMI_EN (1 << 1)
|
||||||
#define HST_EN (1 << 0)
|
#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 */
|
#endif /* SOUTHBRIDGE_INTEL_I82801BX_I82801BX_H */
|
||||||
|
|
|
@ -19,8 +19,8 @@
|
||||||
#include <device/pci.h>
|
#include <device/pci.h>
|
||||||
#include <device/pci_ids.h>
|
#include <device/pci_ids.h>
|
||||||
#include <arch/io.h>
|
#include <arch/io.h>
|
||||||
|
#include <southbridge/intel/common/smbus.h>
|
||||||
#include "i82801bx.h"
|
#include "i82801bx.h"
|
||||||
#include "smbus.h"
|
|
||||||
|
|
||||||
static int lsmbus_read_byte(device_t dev, u8 address)
|
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_HARD_RESET
|
||||||
select HAVE_SMI_HANDLER
|
select HAVE_SMI_HANDLER
|
||||||
select HAVE_USBDEBUG
|
select HAVE_USBDEBUG
|
||||||
|
select SOUTHBRIDGE_INTEL_COMMON
|
||||||
|
select SOUTHBRIDGE_INTEL_COMMON_SMBUS
|
||||||
|
|
||||||
if SOUTHBRIDGE_INTEL_I82801DX
|
if SOUTHBRIDGE_INTEL_I82801DX
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include <arch/io.h>
|
#include <arch/io.h>
|
||||||
#include <device/pci_def.h>
|
#include <device/pci_def.h>
|
||||||
#include <console/console.h>
|
#include <console/console.h>
|
||||||
|
#include <southbridge/intel/common/smbus.h>
|
||||||
|
|
||||||
#include "i82801dx.h"
|
#include "i82801dx.h"
|
||||||
|
|
||||||
|
@ -37,143 +38,7 @@ void enable_smbus(void)
|
||||||
outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT);
|
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 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 PM1_STS 0x00
|
||||||
#define WAK_STS (1 << 15)
|
#define WAK_STS (1 << 15)
|
||||||
#define PCIEXPWAK_STS (1 << 14)
|
#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 HAVE_SMI_HANDLER
|
||||||
select COMMON_FADT
|
select COMMON_FADT
|
||||||
select SOUTHBRIDGE_INTEL_COMMON_GPIO
|
select SOUTHBRIDGE_INTEL_COMMON_GPIO
|
||||||
|
select SOUTHBRIDGE_INTEL_COMMON_SMBUS
|
||||||
|
|
||||||
if SOUTHBRIDGE_INTEL_I82801GX
|
if SOUTHBRIDGE_INTEL_I82801GX
|
||||||
|
|
||||||
|
|
|
@ -18,8 +18,8 @@
|
||||||
#include <console/console.h>
|
#include <console/console.h>
|
||||||
#include <device/pci_ids.h>
|
#include <device/pci_ids.h>
|
||||||
#include <device/pci_def.h>
|
#include <device/pci_def.h>
|
||||||
|
#include <southbridge/intel/common/smbus.h>
|
||||||
#include "i82801gx.h"
|
#include "i82801gx.h"
|
||||||
#include "smbus.h"
|
|
||||||
|
|
||||||
void enable_smbus(void)
|
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)
|
int i2c_block_read(unsigned int device, unsigned int offset, u32 bytes, u8 *buf)
|
||||||
{
|
{
|
||||||
u8 status;
|
return do_i2c_block_read(SMBUS_IO_BASE, device, offset, bytes, buf);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -177,22 +177,6 @@ int southbridge_detect_s3_resume(void);
|
||||||
#define SMB_SMI_EN (1 << 1)
|
#define SMB_SMI_EN (1 << 1)
|
||||||
#define HST_EN (1 << 0)
|
#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 */
|
/* Southbridge IO BARs */
|
||||||
|
|
||||||
#define GPIOBASE 0x48
|
#define GPIOBASE 0x48
|
||||||
|
|
|
@ -22,8 +22,8 @@
|
||||||
#include <device/pci_ids.h>
|
#include <device/pci_ids.h>
|
||||||
#include <device/pci_ops.h>
|
#include <device/pci_ops.h>
|
||||||
#include <arch/io.h>
|
#include <arch/io.h>
|
||||||
|
#include <southbridge/intel/common/smbus.h>
|
||||||
#include "i82801gx.h"
|
#include "i82801gx.h"
|
||||||
#include "smbus.h"
|
|
||||||
|
|
||||||
static int lsmbus_read_byte(device_t dev, u8 address)
|
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);
|
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)
|
static int lsmbus_write_byte(device_t dev, u8 address, u8 data)
|
||||||
{
|
{
|
||||||
u16 device;
|
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);
|
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)
|
static int lsmbus_block_write(device_t dev, u8 cmd, u8 bytes, const u8 *buf)
|
||||||
{
|
{
|
||||||
u16 device;
|
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);
|
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)
|
static int lsmbus_block_read(device_t dev, u8 cmd, u8 bytes, u8 *buf)
|
||||||
{
|
{
|
||||||
u16 device;
|
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
|
config SOUTHBRIDGE_INTEL_I82801IX
|
||||||
bool
|
bool
|
||||||
select SOUTHBRIDGE_INTEL_COMMON
|
select SOUTHBRIDGE_INTEL_COMMON
|
||||||
|
select SOUTHBRIDGE_INTEL_COMMON_SMBUS
|
||||||
select IOAPIC
|
select IOAPIC
|
||||||
select HAVE_USBDEBUG
|
select HAVE_USBDEBUG
|
||||||
select HAVE_HARD_RESET
|
select HAVE_HARD_RESET
|
||||||
|
|
|
@ -19,8 +19,8 @@
|
||||||
#include <console/console.h>
|
#include <console/console.h>
|
||||||
#include <device/pci_ids.h>
|
#include <device/pci_ids.h>
|
||||||
#include <device/pci_def.h>
|
#include <device/pci_def.h>
|
||||||
|
#include <southbridge/intel/common/smbus.h>
|
||||||
#include "i82801ix.h"
|
#include "i82801ix.h"
|
||||||
#include "smbus.h"
|
|
||||||
|
|
||||||
void enable_smbus(void)
|
void enable_smbus(void)
|
||||||
{
|
{
|
||||||
|
|
|
@ -154,22 +154,6 @@
|
||||||
#define SMB_SMI_EN (1 << 1)
|
#define SMB_SMI_EN (1 << 1)
|
||||||
#define HST_EN (1 << 0)
|
#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 RCBA8(x) *((volatile u8 *)(DEFAULT_RCBA + x))
|
||||||
#define RCBA16(x) *((volatile u16 *)(DEFAULT_RCBA + x))
|
#define RCBA16(x) *((volatile u16 *)(DEFAULT_RCBA + x))
|
||||||
#define RCBA32(x) *((volatile u32 *)(DEFAULT_RCBA + x))
|
#define RCBA32(x) *((volatile u32 *)(DEFAULT_RCBA + x))
|
||||||
|
|
|
@ -22,7 +22,8 @@
|
||||||
#include <device/pci_ids.h>
|
#include <device/pci_ids.h>
|
||||||
#include <device/pci_ops.h>
|
#include <device/pci_ops.h>
|
||||||
#include <arch/io.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)
|
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
|
config SOUTHBRIDGE_INTEL_I82801JX
|
||||||
bool
|
bool
|
||||||
select SOUTHBRIDGE_INTEL_COMMON
|
select SOUTHBRIDGE_INTEL_COMMON
|
||||||
|
select SOUTHBRIDGE_INTEL_COMMON_SMBUS
|
||||||
select IOAPIC
|
select IOAPIC
|
||||||
select HAVE_USBDEBUG
|
select HAVE_USBDEBUG
|
||||||
select HAVE_HARD_RESET
|
select HAVE_HARD_RESET
|
||||||
|
|
|
@ -19,8 +19,8 @@
|
||||||
#include <console/console.h>
|
#include <console/console.h>
|
||||||
#include <device/pci_ids.h>
|
#include <device/pci_ids.h>
|
||||||
#include <device/pci_def.h>
|
#include <device/pci_def.h>
|
||||||
|
#include <southbridge/intel/common/smbus.h>
|
||||||
#include "i82801jx.h"
|
#include "i82801jx.h"
|
||||||
#include "smbus.h"
|
|
||||||
|
|
||||||
void enable_smbus(void)
|
void enable_smbus(void)
|
||||||
{
|
{
|
||||||
|
|
|
@ -147,22 +147,6 @@
|
||||||
#define SMB_SMI_EN (1 << 1)
|
#define SMB_SMI_EN (1 << 1)
|
||||||
#define HST_EN (1 << 0)
|
#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 RCBA8(x) *((volatile u8 *)(DEFAULT_RCBA + x))
|
||||||
#define RCBA16(x) *((volatile u16 *)(DEFAULT_RCBA + x))
|
#define RCBA16(x) *((volatile u16 *)(DEFAULT_RCBA + x))
|
||||||
#define RCBA32(x) *((volatile u32 *)(DEFAULT_RCBA + x))
|
#define RCBA32(x) *((volatile u32 *)(DEFAULT_RCBA + x))
|
||||||
|
|
|
@ -22,7 +22,8 @@
|
||||||
#include <device/pci_ids.h>
|
#include <device/pci_ids.h>
|
||||||
#include <device/pci_ops.h>
|
#include <device/pci_ops.h>
|
||||||
#include <arch/io.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)
|
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 PCIEXP_COMMON_CLOCK
|
||||||
select SPI_FLASH
|
select SPI_FLASH
|
||||||
select SOUTHBRIDGE_INTEL_COMMON
|
select SOUTHBRIDGE_INTEL_COMMON
|
||||||
|
select SOUTHBRIDGE_INTEL_COMMON_SMBUS
|
||||||
select HAVE_USBDEBUG_OPTIONS
|
select HAVE_USBDEBUG_OPTIONS
|
||||||
select COMMON_FADT
|
select COMMON_FADT
|
||||||
select ACPI_SATA_GENERATOR
|
select ACPI_SATA_GENERATOR
|
||||||
|
|
|
@ -18,8 +18,8 @@
|
||||||
#include <console/console.h>
|
#include <console/console.h>
|
||||||
#include <device/pci_ids.h>
|
#include <device/pci_ids.h>
|
||||||
#include <device/pci_def.h>
|
#include <device/pci_def.h>
|
||||||
|
#include <southbridge/intel/common/smbus.h>
|
||||||
#include "pch.h"
|
#include "pch.h"
|
||||||
#include "smbus.h"
|
|
||||||
|
|
||||||
void enable_smbus(void)
|
void enable_smbus(void)
|
||||||
{
|
{
|
||||||
|
|
|
@ -233,22 +233,6 @@ void southbridge_configure_default_intmap(void);
|
||||||
#define SMB_SMI_EN (1 << 1)
|
#define SMB_SMI_EN (1 << 1)
|
||||||
#define HST_EN (1 << 0)
|
#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 */
|
/* Southbridge IO BARs */
|
||||||
|
|
||||||
#define GPIOBASE 0x48
|
#define GPIOBASE 0x48
|
||||||
|
|
|
@ -22,8 +22,8 @@
|
||||||
#include <device/pci_ids.h>
|
#include <device/pci_ids.h>
|
||||||
#include <device/pci_ops.h>
|
#include <device/pci_ops.h>
|
||||||
#include <arch/io.h>
|
#include <arch/io.h>
|
||||||
|
#include <southbridge/intel/common/smbus.h>
|
||||||
#include "pch.h"
|
#include "pch.h"
|
||||||
#include "smbus.h"
|
|
||||||
|
|
||||||
static void pch_smbus_init(device_t dev)
|
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
|
def_bool y
|
||||||
select ACPI_INTEL_HARDWARE_SLEEP_VALUES
|
select ACPI_INTEL_HARDWARE_SLEEP_VALUES
|
||||||
select SOUTHBRIDGE_INTEL_COMMON
|
select SOUTHBRIDGE_INTEL_COMMON
|
||||||
|
select SOUTHBRIDGE_INTEL_COMMON_SMBUS
|
||||||
select IOAPIC
|
select IOAPIC
|
||||||
select HAVE_HARD_RESET
|
select HAVE_HARD_RESET
|
||||||
select HAVE_USBDEBUG_OPTIONS
|
select HAVE_USBDEBUG_OPTIONS
|
||||||
|
|
|
@ -18,8 +18,8 @@
|
||||||
#include <console/console.h>
|
#include <console/console.h>
|
||||||
#include <device/pci_ids.h>
|
#include <device/pci_ids.h>
|
||||||
#include <device/pci_def.h>
|
#include <device/pci_def.h>
|
||||||
|
#include <southbridge/intel/common/smbus.h>
|
||||||
#include "pch.h"
|
#include "pch.h"
|
||||||
#include "smbus.h"
|
|
||||||
|
|
||||||
void enable_smbus(void)
|
void enable_smbus(void)
|
||||||
{
|
{
|
||||||
|
|
|
@ -473,22 +473,6 @@ void pch_enable_lpc(void);
|
||||||
#define SMB_SMI_EN (1 << 1)
|
#define SMB_SMI_EN (1 << 1)
|
||||||
#define HST_EN (1 << 0)
|
#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 */
|
/* Southbridge IO BARs */
|
||||||
|
|
||||||
#define GPIOBASE 0x48
|
#define GPIOBASE 0x48
|
||||||
|
|
|
@ -22,8 +22,8 @@
|
||||||
#include <device/pci_ids.h>
|
#include <device/pci_ids.h>
|
||||||
#include <device/pci_ops.h>
|
#include <device/pci_ops.h>
|
||||||
#include <arch/io.h>
|
#include <arch/io.h>
|
||||||
|
#include <southbridge/intel/common/smbus.h>
|
||||||
#include "pch.h"
|
#include "pch.h"
|
||||||
#include "smbus.h"
|
|
||||||
|
|
||||||
static void pch_smbus_init(device_t dev)
|
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);
|
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)
|
static int lsmbus_write_byte(device_t dev, u8 address, u8 data)
|
||||||
{
|
{
|
||||||
u16 device;
|
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