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.
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.
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.
17 #include <device/smbus_def.h>
19 #define SMBHSTSTAT 0x1
20 #define SMBHSTPRTCL 0x0
22 #define SMBXMITADD 0x2
23 #define SMBHSTDAT0 0x4
24 #define SMBHSTDAT1 0x5
27 * Between 1-10 seconds, We should never timeout normally.
28 * Longer than this is just painful when a timeout condition occurs.
30 #define SMBUS_TIMEOUT (100 * 1000 * 10)
32 static inline void smbus_delay(void)
38 /* Not needed, upon write to PRTCL, the status will be auto-cleared. */
39 static int smbus_wait_until_ready(unsigned smbus_io_base
)
42 loops
= SMBUS_TIMEOUT
;
46 val
= inb(smbus_io_base
+ SMBHSTSTAT
);
50 outb(val
, smbus_io_base
+ SMBHSTSTAT
);
56 static int smbus_wait_until_done(unsigned smbus_io_base
)
59 loops
= SMBUS_TIMEOUT
;
63 val
= inb(smbus_io_base
+ SMBHSTSTAT
);
64 if ((val
& 0xff) != 0)
71 static int do_smbus_recv_byte(unsigned smbus_io_base
, unsigned device
)
73 unsigned char global_status_register
, byte
;
76 /* Not needed, upon write to PRTCL, the status will be auto-cleared. */
77 if (smbus_wait_until_ready(smbus_io_base
) < 0)
81 /* Set the device I'm talking to. */
82 outb(((device
& 0x7f) << 1) | 1, smbus_io_base
+ SMBXMITADD
);
85 /* Set the command/address. */
86 outb(0, smbus_io_base
+ SMBHSTCMD
);
90 outb(0x05, smbus_io_base
+ SMBHSTPRTCL
);
93 /* Poll for transaction completion. */
94 if (smbus_wait_until_done(smbus_io_base
) < 0)
98 global_status_register
= inb(smbus_io_base
+ SMBHSTSTAT
) & 0x80;
100 /* Read results of transaction. */
101 byte
= inb(smbus_io_base
+ SMBHSTDAT0
);
103 /* Lose check, otherwise it should be 0. */
104 if (global_status_register
!= 0x80)
110 static int do_smbus_send_byte(unsigned smbus_io_base
, unsigned device
,
113 unsigned global_status_register
;
116 /* Not needed, upon write to PRTCL, the status will be auto-cleared. */
117 if (smbus_wait_until_ready(smbus_io_base
) < 0)
121 outb(val
, smbus_io_base
+ SMBHSTDAT0
);
124 /* Set the device I'm talking to. */
125 outb(((device
& 0x7f) << 1) | 0, smbus_io_base
+ SMBXMITADD
);
128 outb(0, smbus_io_base
+ SMBHSTCMD
);
131 /* Set up for a byte data write. */
132 outb(0x04, smbus_io_base
+ SMBHSTPRTCL
);
135 /* Poll for transaction completion. */
136 if (smbus_wait_until_done(smbus_io_base
) < 0)
140 global_status_register
= inb(smbus_io_base
+ SMBHSTSTAT
) & 0x80;
142 if (global_status_register
!= 0x80)
149 static int do_smbus_read_byte(unsigned smbus_io_base
, unsigned device
,
152 unsigned char global_status_register
, byte
;
155 /* Not needed, upon write to PRTCL, the status will be auto-cleared. */
156 if (smbus_wait_until_ready(smbus_io_base
) < 0)
160 /* Set the device I'm talking to. */
161 outb(((device
& 0x7f) << 1) | 1, smbus_io_base
+ SMBXMITADD
);
164 /* Set the command/address. */
165 outb(address
& 0xff, smbus_io_base
+ SMBHSTCMD
);
168 /* Byte data read. */
169 outb(0x07, smbus_io_base
+ SMBHSTPRTCL
);
172 /* Poll for transaction completion. */
173 if (smbus_wait_until_done(smbus_io_base
) < 0)
177 global_status_register
= inb(smbus_io_base
+ SMBHSTSTAT
) & 0x80;
179 /* Read results of transaction. */
180 byte
= inb(smbus_io_base
+ SMBHSTDAT0
);
182 /* Lose check, otherwise it should be 0. */
183 if (global_status_register
!= 0x80)
189 static int do_smbus_write_byte(unsigned smbus_io_base
, unsigned device
,
190 unsigned address
, unsigned char val
)
192 unsigned global_status_register
;
195 /* Not needed, upon write to PRTCL, the status will be auto-cleared. */
196 if (smbus_wait_until_ready(smbus_io_base
) < 0)
200 outb(val
, smbus_io_base
+ SMBHSTDAT0
);
203 /* Set the device I'm talking to. */
204 outb(((device
& 0x7f) << 1) | 0, smbus_io_base
+ SMBXMITADD
);
207 outb(address
& 0xff, smbus_io_base
+ SMBHSTCMD
);
210 /* Set up for a byte data write. */
211 outb(0x06, smbus_io_base
+ SMBHSTPRTCL
);
214 /* Poll for transaction completion. */
215 if (smbus_wait_until_done(smbus_io_base
) < 0)
219 global_status_register
= inb(smbus_io_base
+ SMBHSTSTAT
) & 0x80;
221 if (global_status_register
!= 0x80)