2 * This file is part of the coreboot project.
4 * Copyright (C) 2004 Ronald G. Minnich
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; version 2 of
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 //#define SMBUS_IO_BASE 0x1000
22 //#define SMBUS_IO_BASE 0x0f00
24 #define SMBHSTSTAT 0x0
27 #define SMBXMITADD 0x4
28 #define SMBHSTDAT0 0x5
29 #define SMBHSTDAT1 0x6
31 #define SMBTRNSADD 0x9
32 #define SMBSLVDATA 0xa
33 #define SMLINK_PIN_CTL 0xe
34 #define SMBUS_PIN_CTL 0xf
36 /* Between 1-10 seconds, We should never timeout normally
37 * Longer than this is just painful when a timeout condition occurs.
39 //#define SMBUS_TIMEOUT (100*1000*10)
41 static void enable_smbus(void)
43 device_t dev = PCI_DEV(0x0, 0x1f, 0x3);
45 print_debug("SMBus controller enabled\n");
46 /* set smbus iobase */
47 pci_write_config32(dev, 0x20, SMBUS_IO_BASE | 1);
48 /* Set smbus enable */
49 pci_write_config8(dev, 0x40, 0x01);
50 /* Set smbus iospace enable */
51 pci_write_config16(dev, 0x4, 0x01);
52 /* Disable interrupt generation */
53 outb(0, SMBUS_IO_BASE + SMBHSTCTL);
54 /* clear any lingering errors, so the transaction will run */
55 outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT);
58 static inline void smbus_delay(void)
63 static int smbus_wait_until_active(void)
66 loops = SMBUS_TIMEOUT;
70 val = inb(SMBUS_IO_BASE + SMBHSTSTAT);
75 return loops ? 0 : -4;
78 static int smbus_wait_until_ready(void)
81 loops = SMBUS_TIMEOUT;
85 val = inb(SMBUS_IO_BASE + SMBHSTSTAT);
89 if (loops == (SMBUS_TIMEOUT / 2)) {
90 outb(inb(SMBUS_IO_BASE + SMBHSTSTAT),
91 SMBUS_IO_BASE + SMBHSTSTAT);
94 return loops ? 0 : -2;
97 static int smbus_wait_until_done(void)
100 loops = SMBUS_TIMEOUT;
105 val = inb(SMBUS_IO_BASE + SMBHSTSTAT);
106 if ((val & 1) == 0) {
109 if ((val & ~((1 << 6) | (1 << 0))) != 0) {
113 return loops ? 0 : -3;
116 static int smbus_read_byte(unsigned device, unsigned address)
118 unsigned char global_control_register;
119 unsigned char global_status_register;
122 /*print_err("smbus_read_byte\n"); */
123 if (smbus_wait_until_ready() < 0) {
128 /* setup transaction */
129 /* disable interrupts */
130 outb(inb(SMBUS_IO_BASE + SMBHSTCTL) & 0xfe, SMBUS_IO_BASE + SMBHSTCTL);
131 /* set the device I'm talking too */
132 outb(((device & 0x7f) << 1) | 1, SMBUS_IO_BASE + SMBXMITADD);
133 /* set the command/address... */
134 outb(address & 0xFF, SMBUS_IO_BASE + SMBHSTCMD);
135 /* set up for a byte data read */
136 outb((inb(SMBUS_IO_BASE + SMBHSTCTL) & 0xe3) | (0x2 << 2),
137 SMBUS_IO_BASE + SMBHSTCTL);
139 /* clear any lingering errors, so the transaction will run */
140 outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT);
142 /* clear the data byte... */
143 outb(0, SMBUS_IO_BASE + SMBHSTDAT0);
145 /* start a byte read, with interrupts disabled */
146 outb((inb(SMBUS_IO_BASE + SMBHSTCTL) | 0x40),
147 SMBUS_IO_BASE + SMBHSTCTL);
148 /* poll for it to start */
149 if (smbus_wait_until_active() < 0) {
154 /* poll for transaction completion */
155 if (smbus_wait_until_done() < 0) {
160 global_status_register = inb(SMBUS_IO_BASE + SMBHSTSTAT) & ~(1 << 6); /* Ignore the In Use Status... */
162 /* read results of transaction */
163 byte = inb(SMBUS_IO_BASE + SMBHSTDAT0);
165 if (global_status_register != 2) {
170 print_err("smbus_read_byte: ");
171 print_err_hex32(device); print_err(" ad "); print_err_hex32(address);
172 print_err("value "); print_err_hex8(byte); print_err("\n");
178 static void smbus_write_byte(unsigned device, unsigned address,
181 if (smbus_wait_until_ready() < 0) {
186 outb(0x37, SMBUS_IO_BASE + SMBHSTSTAT);
187 /* set the device I'm talking too */
188 outw(((device & 0x7f) << 1) | 0, SMBUS_IO_BASE + SMBHSTADDR);
191 outb(val, SMBUS_IO_BASE + SMBHSTDAT);
193 outb(address & 0xFF, SMBUS_IO_BASE + SMBHSTCMD);
195 /* start the command */
196 outb(0xa, SMBUS_IO_BASE + SMBHSTCTL);
198 /* poll for transaction completion */
199 smbus_wait_until_done();