Add constants for fast path resume copying
[coreboot.git] / src / southbridge / intel / i82801dx / 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 modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; version 2 of the License.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18  */
19
20 #include "i82801dx.h"
21 #include <smbus.h>
22 #include <pci.h>
23 #include <arch/io.h>
24
25 #define PM_BUS 0
26 #define PM_DEVFN PCI_DEVFN(0x1f,3)
27
28 void smbus_enable(void)
29 {
30         unsigned char byte;
31         /* iobase addr */
32         pcibios_write_config_dword(PM_BUS, PM_DEVFN, 0x20, SMBUS_IO_BASE | 1);
33         /* smbus enable */
34         pcibios_write_config_byte(PM_BUS, PM_DEVFN, 0x40, 1);
35         /* iospace enable */
36         pcibios_write_config_word(PM_BUS, PM_DEVFN, 0x4, 1);
37
38         /* Disable interrupt generation */
39         outb(0, SMBUS_IO_BASE + SMBHSTCTL);
40
41 }
42
43 void smbus_setup(void)
44 {
45         outb(0, SMBUS_IO_BASE + SMBHSTSTAT);
46 }
47
48 static void smbus_wait_until_ready(void)
49 {
50         while ((inb(SMBUS_IO_BASE + SMBHSTSTAT) & 1) == 1) {
51                 /* nop */
52         }
53 }
54
55 static void smbus_wait_until_done(void)
56 {
57         unsigned char byte;
58         do {
59                 byte = inb(SMBUS_IO_BASE + SMBHSTSTAT);
60         }
61         while ((byte & 1) == 1);
62         while ((byte & ~1) == 0) {
63                 byte = inb(SMBUS_IO_BASE + SMBHSTSTAT);
64         }
65 }
66
67 int smbus_read_byte(unsigned device, unsigned address, unsigned char *result)
68 {
69         unsigned char host_status_register;
70         unsigned char byte;
71
72         smbus_wait_until_ready();
73
74         /* setup transaction */
75         /* disable interrupts */
76         outb(inb(SMBUS_IO_BASE + SMBHSTCTL) & (~1), SMBUS_IO_BASE + SMBHSTCTL);
77         /* set the device I'm talking too */
78         outb(((device & 0x7f) << 1) | 1, SMBUS_IO_BASE + SMBHSTADD);
79         /* set the command/address... */
80         outb(address & 0xFF, SMBUS_IO_BASE + SMBHSTCMD);
81         /* set up for a byte data read */
82         outb((inb(SMBUS_IO_BASE + SMBHSTCTL) & 0xE3) | (0x2 << 2),
83              SMBUS_IO_BASE + SMBHSTCTL);
84
85         /* clear any lingering errors, so the transaction will run */
86         outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT);
87
88         /* clear the data byte... */
89         outb(0, SMBUS_IO_BASE + SMBHSTDAT0);
90
91         /* start the command */
92         outb((inb(SMBUS_IO_BASE + SMBHSTCTL) | 0x40),
93              SMBUS_IO_BASE + SMBHSTCTL);
94
95         /* poll for transaction completion */
96         smbus_wait_until_done();
97
98         host_status_register = inb(SMBUS_IO_BASE + SMBHSTSTAT);
99
100         /* read results of transaction */
101         byte = inb(SMBUS_IO_BASE + SMBHSTDAT0);
102
103         *result = byte;
104         return host_status_register != 0x02;
105 }