summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/southbridge/amd/cs5536/Makefile.inc2
-rw-r--r--src/southbridge/amd/cs5536/cs5536.c20
-rw-r--r--src/southbridge/amd/cs5536/early_smbus.c176
-rw-r--r--src/southbridge/amd/cs5536/smbus.c199
-rw-r--r--src/southbridge/amd/cs5536/smbus.h34
5 files changed, 256 insertions, 175 deletions
diff --git a/src/southbridge/amd/cs5536/Makefile.inc b/src/southbridge/amd/cs5536/Makefile.inc
index 75c6e5c930..3d2613b4ce 100644
--- a/src/southbridge/amd/cs5536/Makefile.inc
+++ b/src/southbridge/amd/cs5536/Makefile.inc
@@ -20,3 +20,5 @@
driver-y += cs5536.c
driver-y += ide.c
driver-y += pirq.c
+driver-y += smbus.c
+romstage-y += smbus.c \ No newline at end of file
diff --git a/src/southbridge/amd/cs5536/cs5536.c b/src/southbridge/amd/cs5536/cs5536.c
index 872de36887..0c0368f217 100644
--- a/src/southbridge/amd/cs5536/cs5536.c
+++ b/src/southbridge/amd/cs5536/cs5536.c
@@ -23,6 +23,7 @@
#include <device/pci.h>
#include <device/pci_ops.h>
#include <device/pci_ids.h>
+#include <device/smbus.h>
#include <console/console.h>
#include <stdint.h>
#include <pc80/isa-dma.h>
@@ -33,6 +34,7 @@
#include <stdlib.h>
#include "chip.h"
#include "cs5536.h"
+#include "smbus.h"
struct msrinit {
u32 msrnum;
@@ -667,6 +669,23 @@ static void southbridge_enable(struct device *dev)
}
+static int lsmbus_read_byte(device_t dev, u8 address)
+{
+ u16 device;
+ struct resource *res;
+ struct bus *pbus;
+
+ device = dev->path.i2c.device;
+ pbus = get_pbus_smbus(dev);
+ res = find_resource(pbus->dev, 0x10);
+
+ return do_smbus_read_byte(res->base, device, address);
+}
+
+static struct smbus_bus_operations lops_smbus_bus = {
+ .read_byte = lsmbus_read_byte,
+};
+
static struct device_operations southbridge_ops = {
.read_resources = cs5536_read_resources,
.set_resources = pci_dev_set_resources,
@@ -674,6 +693,7 @@ static struct device_operations southbridge_ops = {
.init = southbridge_init,
// .enable = southbridge_enable,
.scan_bus = scan_static_bus,
+ .ops_smbus_bus = &lops_smbus_bus,
};
static const struct pci_driver cs5536_pci_driver __pci_driver = {
diff --git a/src/southbridge/amd/cs5536/early_smbus.c b/src/southbridge/amd/cs5536/early_smbus.c
index 814bc5a1fb..c3f681749a 100644
--- a/src/southbridge/amd/cs5536/early_smbus.c
+++ b/src/southbridge/amd/cs5536/early_smbus.c
@@ -18,11 +18,7 @@
*/
#include "cs5536.h"
-
-#define SMBUS_ERROR -1
-#define SMBUS_WAIT_UNTIL_READY_TIMEOUT -2
-#define SMBUS_WAIT_UNTIL_DONE_TIMEOUT -3
-#define SMBUS_TIMEOUT (1000)
+#include "smbus.h"
/* initialization for SMBus Controller */
static void cs5536_enable_smbus(void)
@@ -37,176 +33,6 @@ static void cs5536_enable_smbus(void)
}
-static void smbus_delay(void)
-{
- /* inb(0x80); */
-}
-
-static int smbus_wait(unsigned smbus_io_base)
-{
- unsigned long loops = SMBUS_TIMEOUT;
- unsigned char val;
-
- do {
- smbus_delay();
- val = inb(smbus_io_base + SMB_STS);
- if ((val & SMB_STS_SDAST) != 0)
- break;
- if (val & (SMB_STS_BER | SMB_STS_NEGACK)) {
- /*printk(BIOS_DEBUG, "SMBUS WAIT ERROR %x\n", val); */
- return SMBUS_ERROR;
- }
- } while (--loops);
- return loops ? 0 : SMBUS_WAIT_UNTIL_READY_TIMEOUT;
-}
-
-/* generate a smbus start condition */
-static int smbus_start_condition(unsigned smbus_io_base)
-{
- unsigned char val;
-
- /* issue a START condition */
- val = inb(smbus_io_base + SMB_CTRL1);
- outb(val | SMB_CTRL1_START, smbus_io_base + SMB_CTRL1);
-
- /* check for bus conflict */
- val = inb(smbus_io_base + SMB_STS);
- if ((val & SMB_STS_BER) != 0)
- return SMBUS_ERROR;
-
- return smbus_wait(smbus_io_base);
-}
-
-static int smbus_check_stop_condition(unsigned smbus_io_base)
-{
- unsigned char val;
- unsigned long loops;
- loops = SMBUS_TIMEOUT;
- /* check for SDA status */
- do {
- smbus_delay();
- val = inb(smbus_io_base + SMB_CTRL1);
- if ((val & SMB_CTRL1_STOP) == 0) {
- break;
- }
- outb((0x7F << 1) | SMB_CTRL2_ENABLE, smbus_io_base + SMB_CTRL2);
- } while (--loops);
- return loops ? 0 : SMBUS_WAIT_UNTIL_READY_TIMEOUT;
-}
-
-static int smbus_stop_condition(unsigned smbus_io_base)
-{
- outb(SMB_CTRL1_STOP, smbus_io_base + SMB_CTRL1);
- return smbus_wait(smbus_io_base);
-}
-
-static int smbus_ack(unsigned smbus_io_base, int state)
-{
- unsigned char val = inb(smbus_io_base + SMB_CTRL1);
-
-/* if (state) */
- outb(val | SMB_CTRL1_ACK, smbus_io_base + SMB_CTRL1);
-/* else
- outb(val & ~SMB_CTRL1_ACK, smbus_io_base + SMB_CTRL1);
-*/
- return 0;
-}
-
-static int smbus_send_slave_address(unsigned smbus_io_base,
- unsigned char device)
-{
- unsigned char val;
-
- /* send the slave address */
- outb(device, smbus_io_base + SMB_SDA);
-
- /* check for bus conflict and NACK */
- val = inb(smbus_io_base + SMB_STS);
- if (((val & SMB_STS_BER) != 0) || ((val & SMB_STS_NEGACK) != 0)) {
- /* printk(BIOS_DEBUG, "SEND SLAVE ERROR (%x)\n", val); */
- return SMBUS_ERROR;
- }
- return smbus_wait(smbus_io_base);
-}
-
-static int smbus_send_command(unsigned smbus_io_base, unsigned char command)
-{
- unsigned char val;
-
- /* send the command */
- outb(command, smbus_io_base + SMB_SDA);
-
- /* check for bus conflict and NACK */
- val = inb(smbus_io_base + SMB_STS);
- if (((val & SMB_STS_BER) != 0) || ((val & SMB_STS_NEGACK) != 0))
- return SMBUS_ERROR;
-
- return smbus_wait(smbus_io_base);
-}
-
-static unsigned char smbus_get_result(unsigned smbus_io_base)
-{
- return inb(smbus_io_base + SMB_SDA);
-}
-
-static unsigned char do_smbus_read_byte(unsigned smbus_io_base,
- unsigned char device,
- unsigned char address)
-{
- unsigned char error = 0;
-
- if ((smbus_check_stop_condition(smbus_io_base))) {
- error = 1;
- goto err;
- }
-
- if ((smbus_start_condition(smbus_io_base))) {
- error = 2;
- goto err;
- }
-
- if ((smbus_send_slave_address(smbus_io_base, device << 1))) {
- error = 3;
- goto err;
- }
-
- smbus_ack(smbus_io_base, 1);
-
- if ((smbus_send_command(smbus_io_base, address))) {
- error = 4;
- goto err;
- }
-
- if ((smbus_start_condition(smbus_io_base))) {
- error = 5;
- goto err;
- }
-
- if ((smbus_send_slave_address(smbus_io_base, (device << 1) | 0x01))) {
- error = 6;
- goto err;
- }
-
- if ((smbus_stop_condition(smbus_io_base))) {
- error = 7;
- goto err;
- }
-
- return smbus_get_result(smbus_io_base);
-
-err:
- print_debug("SMBUS READ ERROR:");
- print_debug_hex8(error);
- print_debug(" device:");
- print_debug_hex8(device);
- print_debug("\n");
- /* stop, clean up the error, and leave */
- smbus_stop_condition(smbus_io_base);
- outb(inb(smbus_io_base + SMB_STS), smbus_io_base + SMB_STS);
- outb(0x0, smbus_io_base + SMB_STS);
- return 0xFF;
-}
-
static inline int smbus_read_byte(unsigned device, unsigned address)
{
return do_smbus_read_byte(SMBUS_IO_BASE, device, address);
diff --git a/src/southbridge/amd/cs5536/smbus.c b/src/southbridge/amd/cs5536/smbus.c
new file mode 100644
index 0000000000..3b948c4045
--- /dev/null
+++ b/src/southbridge/amd/cs5536/smbus.c
@@ -0,0 +1,199 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2007 Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <console/console.h>
+#include <arch/io.h>
+#include "cs5536.h"
+#include "smbus.h"
+
+#define SMBUS_ERROR -1
+#define SMBUS_WAIT_UNTIL_READY_TIMEOUT -2
+#define SMBUS_WAIT_UNTIL_DONE_TIMEOUT -3
+#define SMBUS_TIMEOUT (1000)
+
+static void smbus_delay(void)
+{
+ /* inb(0x80); */
+}
+
+static int smbus_wait(unsigned smbus_io_base)
+{
+ unsigned long loops = SMBUS_TIMEOUT;
+ unsigned char val;
+
+ do {
+ smbus_delay();
+ val = inb(smbus_io_base + SMB_STS);
+ if ((val & SMB_STS_SDAST) != 0)
+ break;
+ if (val & (SMB_STS_BER | SMB_STS_NEGACK)) {
+ /*printk(BIOS_DEBUG, "SMBUS WAIT ERROR %x\n", val); */
+ return SMBUS_ERROR;
+ }
+ } while (--loops);
+ return loops ? 0 : SMBUS_WAIT_UNTIL_READY_TIMEOUT;
+}
+
+/* generate a smbus start condition */
+int smbus_start_condition(unsigned smbus_io_base)
+{
+ unsigned char val;
+
+ /* issue a START condition */
+ val = inb(smbus_io_base + SMB_CTRL1);
+ outb(val | SMB_CTRL1_START, smbus_io_base + SMB_CTRL1);
+
+ /* check for bus conflict */
+ val = inb(smbus_io_base + SMB_STS);
+ if ((val & SMB_STS_BER) != 0)
+ return SMBUS_ERROR;
+
+ return smbus_wait(smbus_io_base);
+}
+
+int smbus_check_stop_condition(unsigned smbus_io_base)
+{
+ unsigned char val;
+ unsigned long loops;
+ loops = SMBUS_TIMEOUT;
+ /* check for SDA status */
+ do {
+ smbus_delay();
+ val = inb(smbus_io_base + SMB_CTRL1);
+ if ((val & SMB_CTRL1_STOP) == 0) {
+ break;
+ }
+ outb((0x7F << 1) | SMB_CTRL2_ENABLE, smbus_io_base + SMB_CTRL2);
+ } while (--loops);
+ return loops ? 0 : SMBUS_WAIT_UNTIL_READY_TIMEOUT;
+}
+
+int smbus_stop_condition(unsigned smbus_io_base)
+{
+ outb(SMB_CTRL1_STOP, smbus_io_base + SMB_CTRL1);
+ return smbus_wait(smbus_io_base);
+}
+
+static int smbus_ack(unsigned smbus_io_base, int state)
+{
+ unsigned char val = inb(smbus_io_base + SMB_CTRL1);
+
+/* if (state) */
+ outb(val | SMB_CTRL1_ACK, smbus_io_base + SMB_CTRL1);
+/* else
+ outb(val & ~SMB_CTRL1_ACK, smbus_io_base + SMB_CTRL1);
+*/
+ return 0;
+}
+
+int smbus_send_slave_address(unsigned smbus_io_base,
+ unsigned char device)
+{
+ unsigned char val;
+
+ /* send the slave address */
+ outb(device, smbus_io_base + SMB_SDA);
+
+ /* check for bus conflict and NACK */
+ val = inb(smbus_io_base + SMB_STS);
+ if (((val & SMB_STS_BER) != 0) || ((val & SMB_STS_NEGACK) != 0)) {
+ /* printk(BIOS_DEBUG, "SEND SLAVE ERROR (%x)\n", val); */
+ return SMBUS_ERROR;
+ }
+ return smbus_wait(smbus_io_base);
+}
+
+int smbus_send_command(unsigned smbus_io_base, unsigned char command)
+{
+ unsigned char val;
+
+ /* send the command */
+ outb(command, smbus_io_base + SMB_SDA);
+
+ /* check for bus conflict and NACK */
+ val = inb(smbus_io_base + SMB_STS);
+ if (((val & SMB_STS_BER) != 0) || ((val & SMB_STS_NEGACK) != 0))
+ return SMBUS_ERROR;
+
+ return smbus_wait(smbus_io_base);
+}
+
+static unsigned char smbus_get_result(unsigned smbus_io_base)
+{
+ return inb(smbus_io_base + SMB_SDA);
+}
+
+unsigned char do_smbus_read_byte(unsigned smbus_io_base,
+ unsigned char device,
+ unsigned char address)
+{
+ unsigned char error = 0;
+
+ if ((smbus_check_stop_condition(smbus_io_base))) {
+ error = 1;
+ goto err;
+ }
+
+ if ((smbus_start_condition(smbus_io_base))) {
+ error = 2;
+ goto err;
+ }
+
+ if ((smbus_send_slave_address(smbus_io_base, device << 1))) {
+ error = 3;
+ goto err;
+ }
+
+ smbus_ack(smbus_io_base, 1);
+
+ if ((smbus_send_command(smbus_io_base, address))) {
+ error = 4;
+ goto err;
+ }
+
+ if ((smbus_start_condition(smbus_io_base))) {
+ error = 5;
+ goto err;
+ }
+
+ if ((smbus_send_slave_address(smbus_io_base, (device << 1) | 0x01))) {
+ error = 6;
+ goto err;
+ }
+
+ if ((smbus_stop_condition(smbus_io_base))) {
+ error = 7;
+ goto err;
+ }
+
+ return smbus_get_result(smbus_io_base);
+
+err:
+ print_debug("SMBUS READ ERROR:");
+ print_debug_hex8(error);
+ print_debug(" device:");
+ print_debug_hex8(device);
+ print_debug("\n");
+ /* stop, clean up the error, and leave */
+ smbus_stop_condition(smbus_io_base);
+ outb(inb(smbus_io_base + SMB_STS), smbus_io_base + SMB_STS);
+ outb(0x0, smbus_io_base + SMB_STS);
+ return 0xFF;
+}
+
diff --git a/src/southbridge/amd/cs5536/smbus.h b/src/southbridge/amd/cs5536/smbus.h
new file mode 100644
index 0000000000..318a727de1
--- /dev/null
+++ b/src/southbridge/amd/cs5536/smbus.h
@@ -0,0 +1,34 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2007 Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _CS5536_SMBUS_H
+#define _CS5536_SMBUS_H
+
+int smbus_start_condition(unsigned smbus_io_base);
+int smbus_stop_condition(unsigned smbus_io_base);
+int smbus_check_stop_condition(unsigned smbus_io_base);
+int smbus_send_slave_address(unsigned smbus_io_base,
+ unsigned char device);
+int smbus_send_command(unsigned smbus_io_base, unsigned char command);
+
+unsigned char do_smbus_read_byte(unsigned smbus_io_base,
+ unsigned char device,
+ unsigned char address);
+
+#endif /* _CS5536_SMBUS_H */