Since some people disapprove of white space cleanups mixed in regular commits
[coreboot.git] / src / southbridge / intel / i82801dx / i82801dx_early_smbus.c
1 /*
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  */
20
21 #include "i82801dx.h"
22
23 #define SMBHSTSTAT 0x0
24 #define SMBHSTCTL  0x2
25 #define SMBHSTCMD  0x3
26 #define SMBXMITADD 0x4
27 #define SMBHSTDAT0 0x5
28 #define SMBHSTDAT1 0x6
29 #define SMBBLKDAT  0x7
30 #define SMBTRNSADD 0x9
31 #define SMBSLVDATA 0xa
32 #define SMLINK_PIN_CTL 0xe
33 #define SMBUS_PIN_CTL  0xf
34
35 /* Between 1-10 seconds, We should never timeout normally
36  * Longer than this is just painful when a timeout condition occurs.
37  */
38 //#define SMBUS_TIMEOUT (100*1000*10)
39
40 static void enable_smbus(void)
41 {
42         device_t dev = PCI_DEV(0x0, 0x1f, 0x3);
43
44         printk(BIOS_DEBUG, "SMBus controller enabled\n");
45         /* set smbus iobase */
46         pci_write_config32(dev, 0x20, SMBUS_IO_BASE | 1);
47         /* Set smbus enable */
48         pci_write_config8(dev, 0x40, 0x01);
49         /* Set smbus iospace enable */
50         pci_write_config16(dev, 0x4, 0x01);
51         /* Disable interrupt generation */
52         outb(0, SMBUS_IO_BASE + SMBHSTCTL);
53         /* clear any lingering errors, so the transaction will run */
54         outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT);
55 }
56
57 static inline void smbus_delay(void)
58 {
59         outb(0x80, 0x80);
60 }
61
62 static int smbus_wait_until_active(void)
63 {
64         unsigned long loops;
65         loops = SMBUS_TIMEOUT;
66         do {
67                 unsigned char val;
68                 smbus_delay();
69                 val = inb(SMBUS_IO_BASE + SMBHSTSTAT);
70                 if ((val & 1)) {
71                         break;
72                 }
73         } while (--loops);
74         return loops ? 0 : -4;
75 }
76
77 static int smbus_wait_until_ready(void)
78 {
79         unsigned long loops;
80         loops = SMBUS_TIMEOUT;
81         do {
82                 unsigned char val;
83                 smbus_delay();
84                 val = inb(SMBUS_IO_BASE + SMBHSTSTAT);
85                 if ((val & 1) == 0) {
86                         break;
87                 }
88                 if (loops == (SMBUS_TIMEOUT / 2)) {
89                         outb(inb(SMBUS_IO_BASE + SMBHSTSTAT),
90                              SMBUS_IO_BASE + SMBHSTSTAT);
91                 }
92         } while (--loops);
93         return loops ? 0 : -2;
94 }
95
96 static int smbus_wait_until_done(void)
97 {
98         unsigned long loops;
99         loops = SMBUS_TIMEOUT;
100         do {
101                 unsigned char val;
102                 smbus_delay();
103
104                 val = inb(SMBUS_IO_BASE + SMBHSTSTAT);
105                 if ((val & 1) == 0) {
106                         break;
107                 }
108                 if ((val & ~((1 << 6) | (1 << 0))) != 0) {
109                         break;
110                 }
111         } while (--loops);
112         return loops ? 0 : -3;
113 }
114
115 static int smbus_read_byte(unsigned device, unsigned address)
116 {
117         unsigned char global_status_register;
118         unsigned char byte;
119
120         /* printk(BIOS_ERR, "smbus_read_byte\n"); */
121         if (smbus_wait_until_ready() < 0) {
122                 printk(BIOS_ERR, "SMBUS not ready (%02x)\n", -2);
123                 return -2;
124         }
125
126         /* setup transaction */
127         /* disable interrupts */
128         outb(inb(SMBUS_IO_BASE + SMBHSTCTL) & 0xfe, SMBUS_IO_BASE + SMBHSTCTL);
129         /* set the device I'm talking too */
130         outb(((device & 0x7f) << 1) | 1, SMBUS_IO_BASE + SMBXMITADD);
131         /* set the command/address... */
132         outb(address & 0xFF, SMBUS_IO_BASE + SMBHSTCMD);
133         /* set up for a byte data read */
134         outb((inb(SMBUS_IO_BASE + SMBHSTCTL) & 0xe3) | (0x2 << 2),
135              SMBUS_IO_BASE + SMBHSTCTL);
136
137         /* clear any lingering errors, so the transaction will run */
138         outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT);
139
140         /* clear the data byte... */
141         outb(0, SMBUS_IO_BASE + SMBHSTDAT0);
142
143         /* start a byte read, with interrupts disabled */
144         outb((inb(SMBUS_IO_BASE + SMBHSTCTL) | 0x40),
145              SMBUS_IO_BASE + SMBHSTCTL);
146         /* poll for it to start */
147         if (smbus_wait_until_active() < 0) {
148                 printk(BIOS_ERR, "SMBUS not active (%02x)\n", -4);
149                 return -4;
150         }
151
152         /* poll for transaction completion */
153         if (smbus_wait_until_done() < 0) {
154                 printk(BIOS_ERR, "SMBUS not completed (%02x)\n", -3);
155                 return -3;
156         }
157
158         global_status_register = inb(SMBUS_IO_BASE + SMBHSTSTAT) & ~(1 << 6);   /* Ignore the In Use Status... */
159
160         /* read results of transaction */
161         byte = inb(SMBUS_IO_BASE + SMBHSTDAT0);
162
163         if (global_status_register != 2) {
164                 //printk(BIOS_SPEW, "%s: no device (%02x, %02x)\n", __func__, device, address);
165                 return -1;
166         }
167         //printk(BIOS_DEBUG, "%s: %02x@%02x = %02x\n", __func__, device, address, byte);
168         return byte;
169 }
170
171 #if 0
172 static void smbus_write_byte(unsigned device, unsigned address,
173                              unsigned char val)
174 {
175         if (smbus_wait_until_ready() < 0) {
176                 return;
177         }
178
179         /* by LYH */
180         outb(0x37, SMBUS_IO_BASE + SMBHSTSTAT);
181         /* set the device I'm talking too */
182         outw(((device & 0x7f) << 1) | 0, SMBUS_IO_BASE + SMBHSTADDR);
183
184         /* data to send */
185         outb(val, SMBUS_IO_BASE + SMBHSTDAT);
186
187         outb(address & 0xFF, SMBUS_IO_BASE + SMBHSTCMD);
188
189         /* start the command */
190         outb(0xa, SMBUS_IO_BASE + SMBHSTCTL);
191
192         /* poll for transaction completion */
193         smbus_wait_until_done();
194         return;
195 }
196 #endif