Add support for Intel Panther Point PCH
[coreboot.git] / src / southbridge / intel / bd82x6x / smbus.h
1 /*
2  * This file is part of the coreboot project.
3  *
4  * Copyright (C) 2005 Yinghai Lu <yinghailu@gmail.com>
5  * Copyright (C) 2009 coresystems GmbH
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; version 2 of 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 <device/smbus_def.h>
22 #include "pch.h"
23
24 static void smbus_delay(void)
25 {
26         inb(0x80);
27 }
28
29 static int smbus_wait_until_ready(u16 smbus_base)
30 {
31         unsigned loops = SMBUS_TIMEOUT;
32         unsigned char byte;
33         do {
34                 smbus_delay();
35                 if (--loops == 0)
36                         break;
37                 byte = inb(smbus_base + SMBHSTSTAT);
38         } while (byte & 1);
39         return loops ? 0 : -1;
40 }
41
42 static int smbus_wait_until_done(u16 smbus_base)
43 {
44         unsigned loops = SMBUS_TIMEOUT;
45         unsigned char byte;
46         do {
47                 smbus_delay();
48                 if (--loops == 0)
49                         break;
50                 byte = inb(smbus_base + SMBHSTSTAT);
51         } while ((byte & 1) || (byte & ~((1 << 6) | (1 << 0))) == 0);
52         return loops ? 0 : -1;
53 }
54
55 static int do_smbus_read_byte(unsigned smbus_base, unsigned device, unsigned address)
56 {
57         unsigned char global_status_register;
58         unsigned char byte;
59
60         if (smbus_wait_until_ready(smbus_base) < 0) {
61                 return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
62         }
63         /* Setup transaction */
64         /* Disable interrupts */
65         outb(inb(smbus_base + SMBHSTCTL) & (~1), smbus_base + SMBHSTCTL);
66         /* Set the device I'm talking too */
67         outb(((device & 0x7f) << 1) | 1, smbus_base + SMBXMITADD);
68         /* Set the command/address... */
69         outb(address & 0xff, smbus_base + SMBHSTCMD);
70         /* Set up for a byte data read */
71         outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | (0x2 << 2),
72              (smbus_base + SMBHSTCTL));
73         /* Clear any lingering errors, so the transaction will run */
74         outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
75
76         /* Clear the data byte... */
77         outb(0, smbus_base + SMBHSTDAT0);
78
79         /* Start the command */
80         outb((inb(smbus_base + SMBHSTCTL) | 0x40),
81              smbus_base + SMBHSTCTL);
82
83         /* Poll for transaction completion */
84         if (smbus_wait_until_done(smbus_base) < 0) {
85                 return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
86         }
87
88         global_status_register = inb(smbus_base + SMBHSTSTAT);
89
90         /* Ignore the "In Use" status... */
91         global_status_register &= ~(3 << 5);
92
93         /* Read results of transaction */
94         byte = inb(smbus_base + SMBHSTDAT0);
95         if (global_status_register != (1 << 1)) {
96                 return SMBUS_ERROR;
97         }
98         return byte;
99 }
100