blob: 7bf1267b75979e16184c58c0b3048ff1b965d6cf [file] [log] [blame]
Ronald G. Minnichc8179262003-09-26 04:45:52 +00001#define SMBUS_IO_BASE 0x5000
2
Ronald G. Minnich320c6a02003-10-01 01:45:43 +00003#define SMBHSTSTAT 0x0
4#define SMBSLVSTAT 0x1
5#define SMBHSTCTL 0x2
6#define SMBHSTCMD 0x3
7#define SMBXMITADD 0x4
8#define SMBHSTDAT0 0x5
9#define SMBHSTDAT1 0x6
10#define SMBBLKDAT 0x7
11#define SMBSLVCTL 0x8
12#define SMBTRNSADD 0x9
13#define SMBSLVDATA 0xa
14#define SMLINK_PIN_CTL 0xe
arch import user (historical)80e3d962005-07-06 18:17:33 +000015#define SMBUS_PIN_CTL 0xf
Ronald G. Minnich320c6a02003-10-01 01:45:43 +000016
17/* Define register settings */
18#define HOST_RESET 0xff
arch import user (historical)80e3d962005-07-06 18:17:33 +000019#define READ_CMD 0x01 // 1 in the 0 bit of SMBHSTADD states to READ
Ronald G. Minnich320c6a02003-10-01 01:45:43 +000020
Ronald G. Minnichc8179262003-09-26 04:45:52 +000021
22#define SMBUS_TIMEOUT (100*1000*10)
23
24static void enable_smbus(void)
25{
Eric Biederman83b991a2003-10-11 06:20:25 +000026 device_t dev;
27 unsigned char c;
28 /* Power management controller */
arch import user (historical)80e3d962005-07-06 18:17:33 +000029 dev = pci_locate_device(PCI_ID(0x1106, 0x8235), 0);
30
Eric Biederman83b991a2003-10-11 06:20:25 +000031 if (dev == PCI_DEV_INVALID) {
Stefan Reinauer64ed2b72010-03-31 14:47:43 +000032 die("SMBUS controller not found\n");
Eric Biederman83b991a2003-10-11 06:20:25 +000033 }
Eric Biederman83b991a2003-10-11 06:20:25 +000034 // set IO base address to SMBUS_IO_BASE
arch import user (historical)80e3d962005-07-06 18:17:33 +000035 pci_write_config32(dev, 0x90, SMBUS_IO_BASE | 1);
36
Stefan Reinauer14e22772010-04-27 06:56:47 +000037 // Enable SMBus
Eric Biederman83b991a2003-10-11 06:20:25 +000038 c = pci_read_config8(dev, 0xd2);
39 c |= 5;
40 pci_write_config8(dev, 0xd2, c);
arch import user (historical)80e3d962005-07-06 18:17:33 +000041
Eric Biederman83b991a2003-10-11 06:20:25 +000042 /* make it work for I/O ...
43 */
arch import user (historical)80e3d962005-07-06 18:17:33 +000044 dev = pci_locate_device(PCI_ID(0x1106, 0x8231), 0);
Eric Biederman83b991a2003-10-11 06:20:25 +000045 c = pci_read_config8(dev, 4);
46 c |= 1;
47 pci_write_config8(dev, 4, c);
Ronald G. Minnich88fbae22003-10-22 21:54:19 +000048 print_debug_hex8(c);
Stefan Reinauer64ed2b72010-03-31 14:47:43 +000049 print_debug(" is the comm register\n");
arch import user (historical)80e3d962005-07-06 18:17:33 +000050
Stefan Reinauer64ed2b72010-03-31 14:47:43 +000051 print_debug("SMBus controller enabled\n");
Ronald G. Minnichc8179262003-09-26 04:45:52 +000052}
53
54
55static inline void smbus_delay(void)
56{
Eric Biederman83b991a2003-10-11 06:20:25 +000057 outb(0x80, 0x80);
Ronald G. Minnichc8179262003-09-26 04:45:52 +000058}
59
Mark Wilkinsone1bc97b2004-12-01 16:57:37 +000060static int smbus_wait_until_active(void)
61{
arch import user (historical)80e3d962005-07-06 18:17:33 +000062 unsigned long loops;
63 loops = SMBUS_TIMEOUT;
64 do {
65 unsigned char val;
66 smbus_delay();
67 val = inb(SMBUS_IO_BASE + SMBHSTSTAT);
68 if ((val & 1)) {
69 break;
70 }
71 } while (--loops);
72 return loops ? 0 : -4;
Mark Wilkinsone1bc97b2004-12-01 16:57:37 +000073}
74
Ronald G. Minnichc8179262003-09-26 04:45:52 +000075static int smbus_wait_until_ready(void)
76{
arch import user (historical)80e3d962005-07-06 18:17:33 +000077 unsigned long loops;
78 loops = SMBUS_TIMEOUT;
79 do {
80 unsigned char val;
81 smbus_delay();
82 val = inb(SMBUS_IO_BASE + SMBHSTSTAT);
83 if ((val & 1) == 0) {
84 break;
85 }
86 if (loops == (SMBUS_TIMEOUT / 2)) {
87 outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT);
88 }
89 } while (--loops);
90 return loops ? 0 : -2;
Mark Wilkinsone1bc97b2004-12-01 16:57:37 +000091}
Ronald G. Minnich320c6a02003-10-01 01:45:43 +000092
Mark Wilkinsone1bc97b2004-12-01 16:57:37 +000093static int smbus_wait_until_done(void)
94{
arch import user (historical)80e3d962005-07-06 18:17:33 +000095 unsigned long loops;
96 loops = SMBUS_TIMEOUT;
97 do {
98 unsigned char val;
99 smbus_delay();
Mark Wilkinsone1bc97b2004-12-01 16:57:37 +0000100
arch import user (historical)80e3d962005-07-06 18:17:33 +0000101 val = inb(SMBUS_IO_BASE + SMBHSTSTAT);
102 if ((val & 1) == 0) {
103 break;
104 }
105 } while (--loops);
106 return loops ? 0 : -3;
Ronald G. Minnichc8179262003-09-26 04:45:52 +0000107}
108
Stefan Reinauer8a9268452010-04-07 03:40:37 +0000109#if 0
Ronald G. Minnich320c6a02003-10-01 01:45:43 +0000110void smbus_reset(void)
111{
Eric Biederman83b991a2003-10-11 06:20:25 +0000112 outb(HOST_RESET, SMBUS_IO_BASE + SMBHSTSTAT);
113 outb(HOST_RESET, SMBUS_IO_BASE + SMBHSTSTAT);
114 outb(HOST_RESET, SMBUS_IO_BASE + SMBHSTSTAT);
115 outb(HOST_RESET, SMBUS_IO_BASE + SMBHSTSTAT);
arch import user (historical)80e3d962005-07-06 18:17:33 +0000116
Eric Biederman83b991a2003-10-11 06:20:25 +0000117 smbus_wait_until_ready();
Ronald G. Minnich88fbae22003-10-22 21:54:19 +0000118 print_debug("After reset status ");
arch import user (historical)80e3d962005-07-06 18:17:33 +0000119 print_debug_hex8(inb(SMBUS_IO_BASE + SMBHSTSTAT));
Stefan Reinauer64ed2b72010-03-31 14:47:43 +0000120 print_debug("\n");
Ronald G. Minnich320c6a02003-10-01 01:45:43 +0000121}
Stefan Reinauer8a9268452010-04-07 03:40:37 +0000122#endif
arch import user (historical)80e3d962005-07-06 18:17:33 +0000123
Stefan Reinauer8a9268452010-04-07 03:40:37 +0000124#if CONFIG_DEBUG_SMBUS
Ronald G. Minnich320c6a02003-10-01 01:45:43 +0000125static void smbus_print_error(unsigned char host_status_register)
Ronald G. Minnichc8179262003-09-26 04:45:52 +0000126{
Ronald G. Minnichc8179262003-09-26 04:45:52 +0000127
Eric Biederman83b991a2003-10-11 06:20:25 +0000128 print_err("smbus_error: ");
129 print_err_hex8(host_status_register);
Stefan Reinauer64ed2b72010-03-31 14:47:43 +0000130 print_err("\n");
Eric Biederman83b991a2003-10-11 06:20:25 +0000131 if (host_status_register & (1 << 4)) {
Stefan Reinauer64ed2b72010-03-31 14:47:43 +0000132 print_err("Interrup/SMI# was Failed Bus Transaction\n");
Eric Biederman83b991a2003-10-11 06:20:25 +0000133 }
134 if (host_status_register & (1 << 3)) {
Stefan Reinauer64ed2b72010-03-31 14:47:43 +0000135 print_err("Bus Error\n");
Eric Biederman83b991a2003-10-11 06:20:25 +0000136 }
137 if (host_status_register & (1 << 2)) {
Stefan Reinauer64ed2b72010-03-31 14:47:43 +0000138 print_err("Device Error\n");
Eric Biederman83b991a2003-10-11 06:20:25 +0000139 }
140 if (host_status_register & (1 << 1)) {
Stefan Reinauer64ed2b72010-03-31 14:47:43 +0000141 print_err("Interrupt/SMI# was Successful Completion\n");
Eric Biederman83b991a2003-10-11 06:20:25 +0000142 }
143 if (host_status_register & (1 << 0)) {
Stefan Reinauer64ed2b72010-03-31 14:47:43 +0000144 print_err("Host Busy\n");
Eric Biederman83b991a2003-10-11 06:20:25 +0000145 }
Ronald G. Minnichc8179262003-09-26 04:45:52 +0000146}
Stefan Reinauer8a9268452010-04-07 03:40:37 +0000147#endif
Ronald G. Minnich320c6a02003-10-01 01:45:43 +0000148
Mark Wilkinsone1bc97b2004-12-01 16:57:37 +0000149/*
150 * Copied from intel/i82801dbm early smbus code - suggested by rgm.
151 * Modifications/check against i2c-viapro driver code from linux-2.4.22
152 * and VT8231 Reference Docs - mw.
153 */
154static int smbus_read_byte(unsigned device, unsigned address)
155{
arch import user (historical)80e3d962005-07-06 18:17:33 +0000156 unsigned char global_status_register;
157 unsigned char byte;
Ronald G. Minnich320c6a02003-10-01 01:45:43 +0000158
arch import user (historical)80e3d962005-07-06 18:17:33 +0000159 if (smbus_wait_until_ready() < 0) {
160 outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT);
161 if (smbus_wait_until_ready() < 0) {
162 return -2;
163 }
164 }
Mark Wilkinsone1bc97b2004-12-01 16:57:37 +0000165
arch import user (historical)80e3d962005-07-06 18:17:33 +0000166 /* setup transaction */
167 /* disable interrupts */
168 outb(inb(SMBUS_IO_BASE + SMBHSTCTL) & 0xfe, SMBUS_IO_BASE + SMBHSTCTL);
169 /* set the device I'm talking too */
170 outb(((device & 0x7f) << 1) | 1, SMBUS_IO_BASE + SMBXMITADD);
171 /* set the command/address... */
172 outb(address & 0xFF, SMBUS_IO_BASE + SMBHSTCMD);
173 /* set up for a byte data read */
174 outb((inb(SMBUS_IO_BASE + SMBHSTCTL) & 0xe3) | (0x2 << 2), SMBUS_IO_BASE + SMBHSTCTL);
Mark Wilkinsone1bc97b2004-12-01 16:57:37 +0000175
arch import user (historical)80e3d962005-07-06 18:17:33 +0000176 /* clear any lingering errors, so the transaction will run */
177 outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT);
Mark Wilkinsone1bc97b2004-12-01 16:57:37 +0000178
arch import user (historical)80e3d962005-07-06 18:17:33 +0000179 /* clear the data byte... */
180 outb(0, SMBUS_IO_BASE + SMBHSTDAT0);
Mark Wilkinsone1bc97b2004-12-01 16:57:37 +0000181
arch import user (historical)80e3d962005-07-06 18:17:33 +0000182 /* start a byte read, with interrupts disabled */
183 outb((inb(SMBUS_IO_BASE + SMBHSTCTL) | 0x40), SMBUS_IO_BASE + SMBHSTCTL);
184 /* poll for it to start */
185 if (smbus_wait_until_active() < 0) {
186 return -4;
187 }
Mark Wilkinsone1bc97b2004-12-01 16:57:37 +0000188
arch import user (historical)80e3d962005-07-06 18:17:33 +0000189 /* poll for transaction completion */
190 if (smbus_wait_until_done() < 0) {
191 return -3;
192 }
Mark Wilkinsone1bc97b2004-12-01 16:57:37 +0000193
194 /* Ignore the Host Busy & Command Complete ? */
arch import user (historical)80e3d962005-07-06 18:17:33 +0000195 global_status_register = inb(SMBUS_IO_BASE + SMBHSTSTAT) & ~((1 << 1) | (1 << 0));
Mark Wilkinsone1bc97b2004-12-01 16:57:37 +0000196
arch import user (historical)80e3d962005-07-06 18:17:33 +0000197 /* read results of transaction */
198 byte = inb(SMBUS_IO_BASE + SMBHSTDAT0);
Mark Wilkinsone1bc97b2004-12-01 16:57:37 +0000199
arch import user (historical)80e3d962005-07-06 18:17:33 +0000200 if (global_status_register != 0) {
201 return -1;
202 }
203 return byte;
Mark Wilkinsone1bc97b2004-12-01 16:57:37 +0000204}
205
206#if 0
Ronald G. Minnich320c6a02003-10-01 01:45:43 +0000207/* SMBus routines borrowed from VIA's Trident Driver */
208/* this works, so I am not going to touch it for now -- rgm */
arch import user (historical)80e3d962005-07-06 18:17:33 +0000209static unsigned char smbus_read_byte(unsigned char devAdr, unsigned char bIndex)
Ronald G. Minnich320c6a02003-10-01 01:45:43 +0000210{
Mark Wilkinsone1bc97b2004-12-01 16:57:37 +0000211 unsigned int i;
arch import user (historical)80e3d962005-07-06 18:17:33 +0000212 unsigned char bData;
213 unsigned char sts = 0;
214
Eric Biederman83b991a2003-10-11 06:20:25 +0000215 /* clear host status */
216 outb(0xff, SMBUS_IO_BASE);
arch import user (historical)80e3d962005-07-06 18:17:33 +0000217
Eric Biederman83b991a2003-10-11 06:20:25 +0000218 /* check SMBUS ready */
arch import user (historical)80e3d962005-07-06 18:17:33 +0000219 for (i = 0; i < SMBUS_TIMEOUT; i++)
220 if ((inb(SMBUS_IO_BASE) & 0x01) == 0)
Eric Biederman83b991a2003-10-11 06:20:25 +0000221 break;
Mark Wilkinsone1bc97b2004-12-01 16:57:37 +0000222
Eric Biederman83b991a2003-10-11 06:20:25 +0000223 /* set host command */
arch import user (historical)80e3d962005-07-06 18:17:33 +0000224 outb(bIndex, SMBUS_IO_BASE + 3);
225
Eric Biederman83b991a2003-10-11 06:20:25 +0000226 /* set slave address */
arch import user (historical)80e3d962005-07-06 18:17:33 +0000227 outb(devAdr | 0x01, SMBUS_IO_BASE + 4);
228
Eric Biederman83b991a2003-10-11 06:20:25 +0000229 /* start */
arch import user (historical)80e3d962005-07-06 18:17:33 +0000230 outb(0x48, SMBUS_IO_BASE + 2);
231
Eric Biederman83b991a2003-10-11 06:20:25 +0000232 /* SMBUS Wait Ready */
arch import user (historical)80e3d962005-07-06 18:17:33 +0000233 for (i = 0; i < SMBUS_TIMEOUT; i++)
234 if (((sts = inb(SMBUS_IO_BASE)) & 0x01) == 0)
Eric Biederman83b991a2003-10-11 06:20:25 +0000235 break;
236 if ((sts & ~3) != 0) {
237 smbus_print_error(sts);
238 return 0;
239 }
arch import user (historical)80e3d962005-07-06 18:17:33 +0000240 bData = inb(SMBUS_IO_BASE + 5);
241
Eric Biederman83b991a2003-10-11 06:20:25 +0000242 return bData;
arch import user (historical)80e3d962005-07-06 18:17:33 +0000243
Ronald G. Minnich320c6a02003-10-01 01:45:43 +0000244}
Mark Wilkinsone1bc97b2004-12-01 16:57:37 +0000245#endif
Stefan Reinauer14e22772010-04-27 06:56:47 +0000246/* for reference, here is the fancier version which we will use at some
Ronald G. Minnich320c6a02003-10-01 01:45:43 +0000247 * point
248 */
249# if 0
250int smbus_read_byte(unsigned device, unsigned address, unsigned char *result)
251{
Eric Biederman83b991a2003-10-11 06:20:25 +0000252 unsigned char host_status_register;
253 unsigned char byte;
arch import user (historical)80e3d962005-07-06 18:17:33 +0000254
Eric Biederman83b991a2003-10-11 06:20:25 +0000255 reset();
arch import user (historical)80e3d962005-07-06 18:17:33 +0000256
Eric Biederman83b991a2003-10-11 06:20:25 +0000257 smbus_wait_until_ready();
arch import user (historical)80e3d962005-07-06 18:17:33 +0000258
Eric Biederman83b991a2003-10-11 06:20:25 +0000259 /* setup transaction */
260 /* disable interrupts */
261 outb(inb(SMBUS_IO_BASE + SMBHSTCTL) & (~1), SMBUS_IO_BASE + SMBHSTCTL);
262 /* set the device I'm talking too */
263 outb(((device & 0x7f) << 1) | 1, SMBUS_IO_BASE + SMBXMITADD);
264 /* set the command/address... */
265 outb(address & 0xFF, SMBUS_IO_BASE + SMBHSTCMD);
266 /* set up for a byte data read */
arch import user (historical)80e3d962005-07-06 18:17:33 +0000267 outb((inb(SMBUS_IO_BASE + SMBHSTCTL) & 0xE3) | (0x2 << 2), SMBUS_IO_BASE + SMBHSTCTL);
268
Eric Biederman83b991a2003-10-11 06:20:25 +0000269 /* clear any lingering errors, so the transaction will run */
270 outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT);
arch import user (historical)80e3d962005-07-06 18:17:33 +0000271
272 /* clear the data byte... */
Eric Biederman83b991a2003-10-11 06:20:25 +0000273 outb(0, SMBUS_IO_BASE + SMBHSTDAT0);
arch import user (historical)80e3d962005-07-06 18:17:33 +0000274
Eric Biederman83b991a2003-10-11 06:20:25 +0000275 /* start the command */
arch import user (historical)80e3d962005-07-06 18:17:33 +0000276 outb((inb(SMBUS_IO_BASE + SMBHSTCTL) | 0x40), SMBUS_IO_BASE + SMBHSTCTL);
277
Eric Biederman83b991a2003-10-11 06:20:25 +0000278 /* poll for transaction completion */
279 smbus_wait_until_done();
arch import user (historical)80e3d962005-07-06 18:17:33 +0000280
Eric Biederman83b991a2003-10-11 06:20:25 +0000281 host_status_register = inb(SMBUS_IO_BASE + SMBHSTSTAT);
arch import user (historical)80e3d962005-07-06 18:17:33 +0000282
Eric Biederman83b991a2003-10-11 06:20:25 +0000283 /* Ignore the In Use Status... */
284 host_status_register &= ~(1 << 6);
arch import user (historical)80e3d962005-07-06 18:17:33 +0000285
Eric Biederman83b991a2003-10-11 06:20:25 +0000286 /* read results of transaction */
287 byte = inb(SMBUS_IO_BASE + SMBHSTDAT0);
288 smbus_print_error(byte);
arch import user (historical)80e3d962005-07-06 18:17:33 +0000289
Eric Biederman83b991a2003-10-11 06:20:25 +0000290 *result = byte;
291 return host_status_register != 0x02;
Ronald G. Minnich320c6a02003-10-01 01:45:43 +0000292}
293
294
295#endif