2 * This file is part of the coreboot project.
4 * Copyright (C) 2004 Tyan Computer
5 * Written by Yinghai Lu <yhlu@tyan.com> for Tyan Computer.
6 * Copyright (C) 2006,2007 AMD
7 * Written by Yinghai Lu <yinghai.lu@amd.com> for AMD.
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
20 #include <device/smbus_def.h>
22 #define SMBHSTSTAT 0x1
23 #define SMBHSTPRTCL 0x0
25 #define SMBXMITADD 0x2
26 #define SMBHSTDAT0 0x4
27 #define SMBHSTDAT1 0x5
29 /* Between 1-10 seconds, We should never timeout normally
30 * Longer than this is just painful when a timeout condition occurs.
32 #define SMBUS_TIMEOUT (100*1000*10)
34 static inline void smbus_delay(void)
39 static int smbus_wait_until_done(unsigned smbus_io_base
)
42 loops
= SMBUS_TIMEOUT
;
47 val
= inb(smbus_io_base
+ SMBHSTSTAT
);
48 if ( (val
& 0xff) != 0) {
54 static int do_smbus_recv_byte(unsigned smbus_io_base
, unsigned device
)
56 unsigned char global_status_register
;
59 /* set the device I'm talking too */
60 outb(((device
& 0x7f) << 1)|1 , smbus_io_base
+ SMBXMITADD
);
64 outb(0x05, smbus_io_base
+ SMBHSTPRTCL
);
67 /* poll for transaction completion */
68 if (smbus_wait_until_done(smbus_io_base
) < 0) {
72 global_status_register
= inb(smbus_io_base
+ SMBHSTSTAT
) & 0x80; /* lose check */
74 /* read results of transaction */
75 byte
= inb(smbus_io_base
+ SMBHSTCMD
);
77 if (global_status_register
!= 0x80) { // lose check, otherwise it should be 0
82 static int do_smbus_send_byte(unsigned smbus_io_base
, unsigned device
, unsigned char val
)
84 unsigned global_status_register
;
86 outb(val
, smbus_io_base
+ SMBHSTDAT0
);
89 /* set the command... */
90 outb(val
, smbus_io_base
+ SMBHSTCMD
);
93 /* set the device I'm talking too */
94 outb(((device
& 0x7f) << 1) | 0, smbus_io_base
+ SMBXMITADD
);
97 /* set up for a byte data write */
98 outb(0x04, smbus_io_base
+ SMBHSTPRTCL
);
101 /* poll for transaction completion */
102 if (smbus_wait_until_done(smbus_io_base
) < 0) {
105 global_status_register
= inb(smbus_io_base
+ SMBHSTSTAT
) & 0x80; /* lose check */;
107 if (global_status_register
!= 0x80) {
112 static int do_smbus_read_byte(unsigned smbus_io_base
, unsigned device
, unsigned address
)
114 unsigned char global_status_register
;
117 /* set the device I'm talking too */
118 outb(((device
& 0x7f) << 1)|1 , smbus_io_base
+ SMBXMITADD
);
120 /* set the command/address... */
121 outb(address
& 0xff, smbus_io_base
+ SMBHSTCMD
);
124 outb(0x07, smbus_io_base
+ SMBHSTPRTCL
);
127 /* poll for transaction completion */
128 if (smbus_wait_until_done(smbus_io_base
) < 0) {
132 global_status_register
= inb(smbus_io_base
+ SMBHSTSTAT
) & 0x80; /* lose check */
134 /* read results of transaction */
135 byte
= inb(smbus_io_base
+ SMBHSTDAT0
);
137 if (global_status_register
!= 0x80) { // lose check, otherwise it should be 0
144 static int do_smbus_write_byte(unsigned smbus_io_base
, unsigned device
, unsigned address
, unsigned char val
)
146 unsigned global_status_register
;
148 outb(val
, smbus_io_base
+ SMBHSTDAT0
);
151 /* set the device I'm talking too */
152 outb(((device
& 0x7f) << 1) | 0, smbus_io_base
+ SMBXMITADD
);
155 outb(address
& 0xff, smbus_io_base
+ SMBHSTCMD
);
158 /* set up for a byte data write */
159 outb(0x06, smbus_io_base
+ SMBHSTPRTCL
);
162 /* poll for transaction completion */
163 if (smbus_wait_until_done(smbus_io_base
) < 0) {
166 global_status_register
= inb(smbus_io_base
+ SMBHSTSTAT
) & 0x80; /* lose check */;
168 if (global_status_register
!= 0x80) {