Remove whitespace.
[coreboot.git] / src / southbridge / intel / i82801gx / smbus.c
1 /*
2  * This file is part of the coreboot project.
3  *
4  * Copyright (C) 2008-2009 coresystems GmbH
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 <console/console.h>
22 #include <device/device.h>
23 #include <device/path.h>
24 #include <device/smbus.h>
25 #include <device/pci.h>
26 #include <device/pci_ids.h>
27 #include <device/pci_ops.h>
28 #include <arch/io.h>
29 #include "i82801gx.h"
30 #include "smbus.h"
31
32 static int lsmbus_read_byte(device_t dev, u8 address)
33 {
34         u16 device;
35         struct resource *res;
36         struct bus *pbus;
37
38         device = dev->path.i2c.device;
39         pbus = get_pbus_smbus(dev);
40         res = find_resource(pbus->dev, 0x20);
41
42         return do_smbus_read_byte(res->base, device, address);
43 }
44
45 static int do_smbus_write_byte(unsigned smbus_base, unsigned device, unsigned address, unsigned data)
46 {
47         unsigned char global_status_register;
48
49         if (smbus_wait_until_ready(smbus_base) < 0)
50                 return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
51
52         /* Setup transaction */
53         /* Disable interrupts */
54         outb(inb(smbus_base + SMBHSTCTL) & (~1), smbus_base + SMBHSTCTL);
55         /* Set the device I'm talking too */
56         outb(((device & 0x7f) << 1) & ~0x01, smbus_base + SMBXMITADD);
57         /* Set the command/address... */
58         outb(address & 0xff, smbus_base + SMBHSTCMD);
59         /* Set up for a byte data read */
60         outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | (0x2 << 2),
61              (smbus_base + SMBHSTCTL));
62         /* Clear any lingering errors, so the transaction will run */
63         outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
64
65         /* Clear the data byte... */
66         outb(data, smbus_base + SMBHSTDAT0);
67
68         /* Start the command */
69         outb((inb(smbus_base + SMBHSTCTL) | 0x40),
70              smbus_base + SMBHSTCTL);
71
72         /* Poll for transaction completion */
73         if (smbus_wait_until_done(smbus_base) < 0)
74                 return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
75
76         global_status_register = inb(smbus_base + SMBHSTSTAT);
77
78         /* Ignore the "In Use" status... */
79         global_status_register &= ~(3 << 5);
80
81         /* Read results of transaction */
82         if (global_status_register != (1 << 1))
83                 return SMBUS_ERROR;
84         return 0;
85 }
86
87 static int lsmbus_write_byte(device_t dev, u8 address, u8 data)
88 {
89         u16 device;
90         struct resource *res;
91         struct bus *pbus;
92
93         device = dev->path.i2c.device;
94         pbus = get_pbus_smbus(dev);
95         res = find_resource(pbus->dev, 0x20);
96         return do_smbus_write_byte(res->base, device, address, data);
97 }
98
99 static int do_smbus_block_write(unsigned smbus_base, unsigned device,
100                               unsigned cmd, unsigned bytes, const u8 *buf)
101 {
102         u8 status;
103
104         if (smbus_wait_until_ready(smbus_base) < 0)
105                 return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
106
107         /* Setup transaction */
108         /* Disable interrupts */
109         outb(inb(smbus_base + SMBHSTCTL) & (~1), smbus_base + SMBHSTCTL);
110         /* Set the device I'm talking too */
111         outb(((device & 0x7f) << 1) & ~0x01, smbus_base + SMBXMITADD);
112         /* Set the command/address... */
113         outb(cmd & 0xff, smbus_base + SMBHSTCMD);
114         /* Set up for a block data write */
115         outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | (0x5 << 2),
116              (smbus_base + SMBHSTCTL));
117         /* Clear any lingering errors, so the transaction will run */
118         outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
119
120         /* set number of bytes to transfer */
121         outb(bytes, smbus_base + SMBHSTDAT0);
122
123         outb(*buf++, smbus_base + SMBBLKDAT);
124         bytes--;
125
126         /* Start the command */
127         outb((inb(smbus_base + SMBHSTCTL) | 0x40),
128              smbus_base + SMBHSTCTL);
129
130         while(!(inb(smbus_base + SMBHSTSTAT) & 1));
131         /* Poll for transaction completion */
132         do {
133                 status = inb(smbus_base + SMBHSTSTAT);
134                 if (status & ((1 << 4) | /* FAILED */
135                               (1 << 3) | /* BUS ERR */
136                               (1 << 2))) /* DEV ERR */
137                         return SMBUS_ERROR;
138
139                 if (status & 0x80) { /* Byte done */
140                         outb(*buf++, smbus_base + SMBBLKDAT);
141                         outb(status, smbus_base + SMBHSTSTAT);
142                 }
143         } while(status & 0x01);
144
145         return 0;
146 }
147
148
149
150 static int lsmbus_block_write(device_t dev, u8 cmd, u8 bytes, const u8 *buf)
151 {
152         u16 device;
153         struct resource *res;
154         struct bus *pbus;
155
156         device = dev->path.i2c.device;
157         pbus = get_pbus_smbus(dev);
158         res = find_resource(pbus->dev, 0x20);
159         return do_smbus_block_write(res->base, device, cmd, bytes, buf);
160 }
161
162 static int do_smbus_block_read(unsigned smbus_base, unsigned device,
163                               unsigned cmd, unsigned bytes, u8 *buf)
164 {
165         u8 status;
166         int bytes_read = 0;
167         if (smbus_wait_until_ready(smbus_base) < 0)
168                 return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
169
170         /* Setup transaction */
171         /* Disable interrupts */
172         outb(inb(smbus_base + SMBHSTCTL) & (~1), smbus_base + SMBHSTCTL);
173         /* Set the device I'm talking too */
174         outb(((device & 0x7f) << 1) | 1, smbus_base + SMBXMITADD);
175         /* Set the command/address... */
176         outb(cmd & 0xff, smbus_base + SMBHSTCMD);
177         /* Set up for a block data read */
178         outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | (0x5 << 2),
179              (smbus_base + SMBHSTCTL));
180         /* Clear any lingering errors, so the transaction will run */
181         outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
182
183         /* Start the command */
184         outb((inb(smbus_base + SMBHSTCTL) | 0x40),
185              smbus_base + SMBHSTCTL);
186
187         while(!(inb(smbus_base + SMBHSTSTAT) & 1));
188         /* Poll for transaction completion */
189         do {
190                 status = inb(smbus_base + SMBHSTSTAT);
191                 if (status & ((1 << 4) | /* FAILED */
192                               (1 << 3) | /* BUS ERR */
193                               (1 << 2))) /* DEV ERR */
194                         return SMBUS_ERROR;
195
196                 if (status & 0x80) { /* Byte done */
197                         *buf = inb(smbus_base + SMBBLKDAT);
198                         buf++;
199                         bytes_read++;
200                         outb(status, smbus_base + SMBHSTSTAT);
201                         if (--bytes == 1) {
202                                 /* indicate that next byte is the last one */
203                                 outb(inb(smbus_base + SMBHSTCTL) | 0x20,
204                                          smbus_base + SMBHSTCTL);
205                         }
206                 }
207         } while(status & 0x01);
208
209         return bytes_read;
210 }
211
212 static int lsmbus_block_read(device_t dev, u8 cmd, u8 bytes, u8 *buf)
213 {
214         u16 device;
215         struct resource *res;
216         struct bus *pbus;
217
218         device = dev->path.i2c.device;
219         pbus = get_pbus_smbus(dev);
220         res = find_resource(pbus->dev, 0x20);
221         return do_smbus_block_read(res->base, device, cmd, bytes, buf);
222 }
223
224
225 static struct smbus_bus_operations lops_smbus_bus = {
226         .read_byte      = lsmbus_read_byte,
227         .write_byte     = lsmbus_write_byte,
228         .block_read     = lsmbus_block_read,
229         .block_write    = lsmbus_block_write,
230 };
231
232 static void smbus_set_subsystem(device_t dev, unsigned vendor, unsigned device)
233 {
234         if (!vendor || !device) {
235                 pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID,
236                                 pci_read_config32(dev, PCI_VENDOR_ID));
237         } else {
238                 pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID,
239                                 ((device & 0xffff) << 16) | (vendor & 0xffff));
240         }
241 }
242
243 static struct pci_operations smbus_pci_ops = {
244         .set_subsystem    = smbus_set_subsystem,
245 };
246
247 static void smbus_read_resources(device_t dev)
248 {
249         struct resource *res = new_resource(dev, PCI_BASE_ADDRESS_4);
250         res->base = SMBUS_IO_BASE;
251         res->size = 32;
252         res->limit = res->base + res->size - 1;
253         res->flags = IORESOURCE_IO | IORESOURCE_FIXED | IORESOURCE_RESERVE |
254                      IORESOURCE_STORED | IORESOURCE_ASSIGNED;
255 }
256
257 static struct device_operations smbus_ops = {
258         .read_resources         = smbus_read_resources,
259         .set_resources          = pci_dev_set_resources,
260         .enable_resources       = pci_dev_enable_resources,
261         .scan_bus               = scan_static_bus,
262         .enable                 = i82801gx_enable,
263         .ops_smbus_bus          = &lops_smbus_bus,
264         .ops_pci                = &smbus_pci_ops,
265 };
266
267 /* 82801GB/GR/GDH/GBM/GHM/GU (ICH7/ICH7R/ICH7DH/ICH7-M/ICH7-M DH/ICH7-U) */
268 static const struct pci_driver i82801gx_smbus __pci_driver = {
269         .ops    = &smbus_ops,
270         .vendor = PCI_VENDOR_ID_INTEL,
271         .device = 0x27da,
272 };