blob: 1387525f3bb53617f5834ffff3fa1a66d646713f [file] [log] [blame]
Stefan Reinauer8702ab52010-03-14 17:01:08 +00001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2004 Ronald G. Minnich
5 *
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
9 * the License.
10 *
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.
15 *
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
19 */
Ronald G. Minnich182615d2004-08-24 16:20:46 +000020
Kyösti Mälkki1d89f142012-04-20 17:11:31 +030021#include <arch/io.h>
22#include <arch/romcc_io.h>
23#include <device/pci_def.h>
24#include <console/console.h>
25
Stefan Reinauer4cc5af92010-04-11 20:02:47 +000026#include "i82801dx.h"
Ronald G. Minnich182615d2004-08-24 16:20:46 +000027
Kyösti Mälkki1d89f142012-04-20 17:11:31 +030028void enable_smbus(void)
Ronald G. Minnich182615d2004-08-24 16:20:46 +000029{
Ed Swierkc4e052c2008-04-01 02:36:59 +000030 device_t dev = PCI_DEV(0x0, 0x1f, 0x3);
31
Kyösti Mälkki2588db42011-10-17 17:37:45 +030032 print_debug("SMBus controller enabled\n");
Ronald G. Minnich182615d2004-08-24 16:20:46 +000033 /* set smbus iobase */
34 pci_write_config32(dev, 0x20, SMBUS_IO_BASE | 1);
35 /* Set smbus enable */
36 pci_write_config8(dev, 0x40, 0x01);
Stefan Reinauer8702ab52010-03-14 17:01:08 +000037 /* Set smbus iospace enable */
Ronald G. Minnich182615d2004-08-24 16:20:46 +000038 pci_write_config16(dev, 0x4, 0x01);
Stefan Reinauer8702ab52010-03-14 17:01:08 +000039 /* Disable interrupt generation */
Ronald G. Minnich182615d2004-08-24 16:20:46 +000040 outb(0, SMBUS_IO_BASE + SMBHSTCTL);
41 /* clear any lingering errors, so the transaction will run */
42 outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT);
43}
44
Ronald G. Minnich182615d2004-08-24 16:20:46 +000045static inline void smbus_delay(void)
46{
47 outb(0x80, 0x80);
48}
49
Ronald G. Minnicha4779e82004-09-30 16:37:22 +000050static int smbus_wait_until_active(void)
51{
52 unsigned long loops;
53 loops = SMBUS_TIMEOUT;
54 do {
55 unsigned char val;
56 smbus_delay();
57 val = inb(SMBUS_IO_BASE + SMBHSTSTAT);
58 if ((val & 1)) {
59 break;
60 }
Stefan Reinauer8702ab52010-03-14 17:01:08 +000061 } while (--loops);
62 return loops ? 0 : -4;
Ronald G. Minnicha4779e82004-09-30 16:37:22 +000063}
64
Ronald G. Minnich182615d2004-08-24 16:20:46 +000065static int smbus_wait_until_ready(void)
66{
67 unsigned long loops;
68 loops = SMBUS_TIMEOUT;
69 do {
70 unsigned char val;
71 smbus_delay();
72 val = inb(SMBUS_IO_BASE + SMBHSTSTAT);
73 if ((val & 1) == 0) {
74 break;
75 }
Stefan Reinauer8702ab52010-03-14 17:01:08 +000076 if (loops == (SMBUS_TIMEOUT / 2)) {
77 outb(inb(SMBUS_IO_BASE + SMBHSTSTAT),
78 SMBUS_IO_BASE + SMBHSTSTAT);
Ronald G. Minnich182615d2004-08-24 16:20:46 +000079 }
Stefan Reinauer8702ab52010-03-14 17:01:08 +000080 } while (--loops);
81 return loops ? 0 : -2;
Ronald G. Minnich182615d2004-08-24 16:20:46 +000082}
83
84static int smbus_wait_until_done(void)
85{
86 unsigned long loops;
87 loops = SMBUS_TIMEOUT;
88 do {
89 unsigned char val;
90 smbus_delay();
Stefan Reinauer8702ab52010-03-14 17:01:08 +000091
Ronald G. Minnich182615d2004-08-24 16:20:46 +000092 val = inb(SMBUS_IO_BASE + SMBHSTSTAT);
Stefan Reinauer8702ab52010-03-14 17:01:08 +000093 if ((val & 1) == 0) {
Ronald G. Minnich182615d2004-08-24 16:20:46 +000094 break;
95 }
Stefan Reinauer8702ab52010-03-14 17:01:08 +000096 if ((val & ~((1 << 6) | (1 << 0))) != 0) {
Ronald G. Minnich182615d2004-08-24 16:20:46 +000097 break;
98 }
Stefan Reinauer8702ab52010-03-14 17:01:08 +000099 } while (--loops);
100 return loops ? 0 : -3;
Ronald G. Minnich182615d2004-08-24 16:20:46 +0000101}
102
Kyösti Mälkki1d89f142012-04-20 17:11:31 +0300103int smbus_read_byte(unsigned device, unsigned address)
Ronald G. Minnich182615d2004-08-24 16:20:46 +0000104{
Ronald G. Minnich182615d2004-08-24 16:20:46 +0000105 unsigned char global_status_register;
106 unsigned char byte;
107
Kyösti Mälkki2588db42011-10-17 17:37:45 +0300108 /* print_err("smbus_read_byte\n"); */
Ronald G. Minnich182615d2004-08-24 16:20:46 +0000109 if (smbus_wait_until_ready() < 0) {
Kyösti Mälkki2588db42011-10-17 17:37:45 +0300110 print_err("SMBUS not ready (-2)\n");
Ronald G. Minnich182615d2004-08-24 16:20:46 +0000111 return -2;
112 }
Stefan Reinauer8702ab52010-03-14 17:01:08 +0000113
Ronald G. Minnich182615d2004-08-24 16:20:46 +0000114 /* setup transaction */
115 /* disable interrupts */
116 outb(inb(SMBUS_IO_BASE + SMBHSTCTL) & 0xfe, SMBUS_IO_BASE + SMBHSTCTL);
117 /* set the device I'm talking too */
118 outb(((device & 0x7f) << 1) | 1, SMBUS_IO_BASE + SMBXMITADD);
119 /* set the command/address... */
120 outb(address & 0xFF, SMBUS_IO_BASE + SMBHSTCMD);
121 /* set up for a byte data read */
Stefan Reinauer8702ab52010-03-14 17:01:08 +0000122 outb((inb(SMBUS_IO_BASE + SMBHSTCTL) & 0xe3) | (0x2 << 2),
123 SMBUS_IO_BASE + SMBHSTCTL);
Ronald G. Minnich182615d2004-08-24 16:20:46 +0000124
125 /* clear any lingering errors, so the transaction will run */
126 outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT);
127
Stefan Reinauer8702ab52010-03-14 17:01:08 +0000128 /* clear the data byte... */
Ronald G. Minnich182615d2004-08-24 16:20:46 +0000129 outb(0, SMBUS_IO_BASE + SMBHSTDAT0);
130
131 /* start a byte read, with interrupts disabled */
Stefan Reinauer8702ab52010-03-14 17:01:08 +0000132 outb((inb(SMBUS_IO_BASE + SMBHSTCTL) | 0x40),
133 SMBUS_IO_BASE + SMBHSTCTL);
Ronald G. Minnicha4779e82004-09-30 16:37:22 +0000134 /* poll for it to start */
135 if (smbus_wait_until_active() < 0) {
Kyösti Mälkki2588db42011-10-17 17:37:45 +0300136 print_err("SMBUS not active (-4)\n");
Ronald G. Minnicha4779e82004-09-30 16:37:22 +0000137 return -4;
138 }
Ronald G. Minnich182615d2004-08-24 16:20:46 +0000139
140 /* poll for transaction completion */
141 if (smbus_wait_until_done() < 0) {
Kyösti Mälkki2588db42011-10-17 17:37:45 +0300142 print_err("SMBUS not completed (-3)\n");
Ronald G. Minnich182615d2004-08-24 16:20:46 +0000143 return -3;
144 }
145
Stefan Reinauer8702ab52010-03-14 17:01:08 +0000146 global_status_register = inb(SMBUS_IO_BASE + SMBHSTSTAT) & ~(1 << 6); /* Ignore the In Use Status... */
Ronald G. Minnich182615d2004-08-24 16:20:46 +0000147
148 /* read results of transaction */
149 byte = inb(SMBUS_IO_BASE + SMBHSTDAT0);
150
151 if (global_status_register != 2) {
Kyösti Mälkki2588db42011-10-17 17:37:45 +0300152 //print_spew("%s: no device (%02x, %02x)\n", __func__, device, address);
Ronald G. Minnich182615d2004-08-24 16:20:46 +0000153 return -1;
154 }
Kyösti Mälkki2588db42011-10-17 17:37:45 +0300155 //print_debug("%s: %02x@%02x = %02x\n", __func__, device, address, byte);
Ronald G. Minnich182615d2004-08-24 16:20:46 +0000156 return byte;
157}
Stefan Reinauer8702ab52010-03-14 17:01:08 +0000158
Ronald G. Minnich182615d2004-08-24 16:20:46 +0000159#if 0
Stefan Reinauer8702ab52010-03-14 17:01:08 +0000160static void smbus_write_byte(unsigned device, unsigned address,
161 unsigned char val)
Ronald G. Minnich182615d2004-08-24 16:20:46 +0000162{
163 if (smbus_wait_until_ready() < 0) {
164 return;
165 }
166
167 /* by LYH */
Stefan Reinauer8702ab52010-03-14 17:01:08 +0000168 outb(0x37, SMBUS_IO_BASE + SMBHSTSTAT);
Ronald G. Minnich182615d2004-08-24 16:20:46 +0000169 /* set the device I'm talking too */
170 outw(((device & 0x7f) << 1) | 0, SMBUS_IO_BASE + SMBHSTADDR);
171
172 /* data to send */
173 outb(val, SMBUS_IO_BASE + SMBHSTDAT);
174
175 outb(address & 0xFF, SMBUS_IO_BASE + SMBHSTCMD);
176
177 /* start the command */
178 outb(0xa, SMBUS_IO_BASE + SMBHSTCTL);
179
180 /* poll for transaction completion */
181 smbus_wait_until_done();
182 return;
183}
184#endif