blob: bb43269b9bfa84f1ef2e1c3e08991648ed79ef64 [file] [log] [blame]
Yinghai Luafd34e62006-02-16 17:22:19 +00001/*
Uwe Hermannc6a10622010-10-17 19:30:58 +00002 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2005 AMD
5 * Written by Yinghai Lu <yinghai.lu@amd.com> for AMD.
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.
Yinghai Luafd34e62006-02-16 17:22:19 +000015 */
Uwe Hermannc6a10622010-10-17 19:30:58 +000016
Yinghai Luafd34e62006-02-16 17:22:19 +000017#include <device/smbus_def.h>
18
19#define SMBHSTSTAT 0x0
20#define SMBSLVSTAT 0x1
21#define SMBHSTCTRL 0x2
22#define SMBHSTCMD 0x3
23#define SMBHSTADDR 0x4
24#define SMBHSTDAT0 0x5
25#define SMBHSTDAT1 0x6
26#define SMBHSTBLKDAT 0x7
27
28#define SMBSLVCTRL 0x8
29#define SMBSLVCMD_SHADOW 0x9
30#define SMBSLVEVT 0xa
31#define SMBSLVDAT 0xc
32
33
Stefan Reinauer14e22772010-04-27 06:56:47 +000034/* Between 1-10 seconds, We should never timeout normally
Yinghai Luafd34e62006-02-16 17:22:19 +000035 * Longer than this is just painful when a timeout condition occurs.
36 */
37#define SMBUS_TIMEOUT (100*1000*10)
38
39static inline void smbus_delay(void)
40{
41 outb(0x80, 0x80);
42}
43
44static int smbus_wait_until_ready(unsigned smbus_io_base)
45{
46 unsigned long loops;
47 loops = SMBUS_TIMEOUT;
48 do {
49 unsigned char val;
50 val = inb(smbus_io_base + SMBHSTSTAT);
Stefan Reinauer14e22772010-04-27 06:56:47 +000051 val &= 0x1f;
Yinghai Luafd34e62006-02-16 17:22:19 +000052 if (val == 0) { // ready now
53 return 0;
54 }
55 outb(val, smbus_io_base + SMBHSTSTAT);
56 } while(--loops);
57 return -2; // time out
58}
59
60static int smbus_wait_until_done(unsigned smbus_io_base)
61{
62 unsigned long loops;
63 loops = SMBUS_TIMEOUT;
64 do {
65 unsigned char val;
Stefan Reinauer14e22772010-04-27 06:56:47 +000066
Yinghai Luafd34e62006-02-16 17:22:19 +000067 val = inb(smbus_io_base + SMBHSTSTAT);
68 val &= 0x1f; // mask off reserved bits
69 if ( val & 0x1c) {
70 return -5; // error
71 }
72 if ( val == 0x02) {
73 outb(val, smbus_io_base + SMBHSTSTAT); // clear status
74 return 0; //
75 }
76 } while(--loops);
77 return -3; // timeout
78}
79
80static int do_smbus_recv_byte(unsigned smbus_io_base, unsigned device)
81{
82 uint8_t byte;
Stefan Reinauer14e22772010-04-27 06:56:47 +000083
Yinghai Luafd34e62006-02-16 17:22:19 +000084 if (smbus_wait_until_ready(smbus_io_base) < 0) {
85 return -2; // not ready
86 }
87
88 /* set the device I'm talking too */
89 outb(((device & 0x7f) << 1)|1 , smbus_io_base + SMBHSTADDR);
90
91 byte = inb(smbus_io_base + SMBHSTCTRL);
92 byte &= 0xe3; // Clear [4:2]
93 byte |= (1<<2) | (1<<6); // Byte data read/write command, start the command
94 outb(byte, smbus_io_base + SMBHSTCTRL);
95
96 /* poll for transaction completion */
97 if (smbus_wait_until_done(smbus_io_base) < 0) {
98 return -3; // timeout or error
99 }
100
101 /* read results of transaction */
102 byte = inb(smbus_io_base + SMBHSTCMD);
103
104 return byte;
Yinghai Luafd34e62006-02-16 17:22:19 +0000105}
Uwe Hermannc6a10622010-10-17 19:30:58 +0000106
Yinghai Luafd34e62006-02-16 17:22:19 +0000107static int do_smbus_send_byte(unsigned smbus_io_base, unsigned device, unsigned char val)
108{
109 uint8_t byte;
110
111 if (smbus_wait_until_ready(smbus_io_base) < 0) {
112 return -2; // not ready
113 }
114
115 /* set the command... */
116 outb(val, smbus_io_base + SMBHSTCMD);
117
118 /* set the device I'm talking too */
119 outb(((device & 0x7f) << 1)|0 , smbus_io_base + SMBHSTADDR);
120
121 byte = inb(smbus_io_base + SMBHSTCTRL);
122 byte &= 0xe3; // Clear [4:2]
123 byte |= (1<<2) | (1<<6); // Byte data read/write command, start the command
124 outb(byte, smbus_io_base + SMBHSTCTRL);
125
126 /* poll for transaction completion */
127 if (smbus_wait_until_done(smbus_io_base) < 0) {
128 return -3; // timeout or error
129 }
130
131 return 0;
Yinghai Luafd34e62006-02-16 17:22:19 +0000132}
133
Yinghai Luafd34e62006-02-16 17:22:19 +0000134static int do_smbus_read_byte(unsigned smbus_io_base, unsigned device, unsigned address)
135{
136 uint8_t byte;
137
138 if (smbus_wait_until_ready(smbus_io_base) < 0) {
139 return -2; // not ready
140 }
Stefan Reinauer14e22772010-04-27 06:56:47 +0000141
Yinghai Luafd34e62006-02-16 17:22:19 +0000142 /* set the command/address... */
143 outb(address & 0xff, smbus_io_base + SMBHSTCMD);
144
145 /* set the device I'm talking too */
146 outb(((device & 0x7f) << 1)|1 , smbus_io_base + SMBHSTADDR);
147
148 byte = inb(smbus_io_base + SMBHSTCTRL);
149 byte &= 0xe3; // Clear [4:2]
150 byte |= (1<<3) | (1<<6); // Byte data read/write command, start the command
151 outb(byte, smbus_io_base + SMBHSTCTRL);
152
153 /* poll for transaction completion */
154 if (smbus_wait_until_done(smbus_io_base) < 0) {
155 return -3; // timeout or error
156 }
157
158 /* read results of transaction */
159 byte = inb(smbus_io_base + SMBHSTDAT0);
160
161 return byte;
162}
Uwe Hermannc6a10622010-10-17 19:30:58 +0000163
Yinghai Luafd34e62006-02-16 17:22:19 +0000164static int do_smbus_write_byte(unsigned smbus_io_base, unsigned device, unsigned address, unsigned char val)
165{
166 uint8_t byte;
167
168 if (smbus_wait_until_ready(smbus_io_base) < 0) {
169 return -2; // not ready
170 }
171
172 /* set the command/address... */
173 outb(address & 0xff, smbus_io_base + SMBHSTCMD);
174
175 /* set the device I'm talking too */
176 outb(((device & 0x7f) << 1)|0 , smbus_io_base + SMBHSTADDR);
177
178 /* output value */
179 outb(val, smbus_io_base + SMBHSTDAT0);
180
181 byte = inb(smbus_io_base + SMBHSTCTRL);
182 byte &= 0xe3; // Clear [4:2]
183 byte |= (1<<3) | (1<<6); // Byte data read/write command, start the command
184 outb(byte, smbus_io_base + SMBHSTCTRL);
185
186 /* poll for transaction completion */
187 if (smbus_wait_until_done(smbus_io_base) < 0) {
188 return -3; // timeout or error
189 }
190
191 return 0;
Yinghai Luafd34e62006-02-16 17:22:19 +0000192}