503a385e2974412496ffdf2876f9409c3ee16dc1
[coreboot.git] / src / southbridge / sis / sis966 / sis966_smbus.h
1 /*
2  * This file is part of the LinuxBIOS project.
3  *
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.
8  * Copyright (C) 2007 Silicon Integrated Systems Corp. (SiS)
9  * Written by Morgan Tsai <my_tsai@sis.com> for SiS.
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
24  */
25
26 #include <device/smbus_def.h>
27
28 #define SMBHSTSTAT      0x1
29 #define SMBHSTPRTCL     0x0
30 #define SMBHSTCMD       0x3
31 #define SMBXMITADD      0x2
32 #define SMBHSTDAT0      0x4
33 #define SMBHSTDAT1      0x5
34
35 /* Between 1-10 seconds, We should never timeout normally
36  * Longer than this is just painful when a timeout condition occurs.
37  */
38 #define SMBUS_TIMEOUT   (100*1000*10)
39
40 static inline void smbus_delay(void)
41 {
42         outb(0x80, 0x80);
43 }
44
45 static int smbus_wait_until_ready(unsigned smbus_io_base)
46 {
47         unsigned long loops;
48         loops = SMBUS_TIMEOUT;
49         do {
50                 unsigned char val;
51                 smbus_delay();
52                 val = inb(smbus_io_base + SMBHSTSTAT);
53                 val &= 0x1f;
54                 if (val == 0) {
55                         return 0;
56                 }
57                 outb(val,smbus_io_base + SMBHSTSTAT);
58         } while(--loops);
59         return -2;
60 }
61
62 static int smbus_wait_until_done(unsigned smbus_io_base)
63 {
64         unsigned long loops;
65         loops = SMBUS_TIMEOUT;
66         do {
67                 unsigned char val;
68                 smbus_delay();
69
70                 val = inb(smbus_io_base + 0x00);
71                 if ( (val & 0xff) != 0x02) {
72                         return 0;
73                 }
74         } while(--loops);
75         return -3;
76 }
77 static int do_smbus_recv_byte(unsigned smbus_io_base, unsigned device)
78 {
79         unsigned char global_status_register;
80         unsigned char byte;
81
82         /* set the device I'm talking too */
83         outb(((device & 0x7f) << 1)|1 , smbus_io_base + SMBXMITADD);
84         smbus_delay();
85
86         /* byte data recv */
87         outb(0x05, smbus_io_base + SMBHSTPRTCL);
88         smbus_delay();
89
90         /* poll for transaction completion */
91         if (smbus_wait_until_done(smbus_io_base) < 0) {
92                 return -3;
93         }
94
95         global_status_register = inb(smbus_io_base + SMBHSTSTAT) & 0x80; /* lose check */
96
97         /* read results of transaction */
98         byte = inb(smbus_io_base + SMBHSTCMD);
99
100         if (global_status_register != 0x80) { // lose check, otherwise it should be 0
101                 return -1;
102         }
103         return byte;
104 }
105 static int do_smbus_send_byte(unsigned smbus_io_base, unsigned device, unsigned char val)
106 {
107         unsigned global_status_register;
108
109         outb(val, smbus_io_base + SMBHSTDAT0);
110         smbus_delay();
111
112         /* set the command... */
113         outb(val, smbus_io_base + SMBHSTCMD);
114         smbus_delay();
115
116         /* set the device I'm talking too */
117         outb(((device & 0x7f) << 1) | 0, smbus_io_base + SMBXMITADD);
118         smbus_delay();
119
120         /* set up for a byte data write */
121         outb(0x04, smbus_io_base + SMBHSTPRTCL);
122         smbus_delay();
123
124         /* poll for transaction completion */
125         if (smbus_wait_until_done(smbus_io_base) < 0) {
126                 return -3;
127         }
128         global_status_register = inb(smbus_io_base + SMBHSTSTAT) & 0x80; /* lose check */;
129
130         if (global_status_register != 0x80) {
131                 return -1;
132         }
133         return 0;
134 }
135 static int do_smbus_read_byte(unsigned smbus_io_base, unsigned device, unsigned address)
136 {
137         unsigned char global_status_register;
138         unsigned char byte;
139
140         outb(0xff, smbus_io_base + 0x00);
141         smbus_delay();
142         outb(0x20, smbus_io_base + 0x03);
143         smbus_delay();
144
145         outb(((device & 0x7f) << 1)|1 , smbus_io_base + 0x04);
146         smbus_delay();
147         outb(address & 0xff, smbus_io_base + 0x05);
148         smbus_delay();
149         outb(0x12, smbus_io_base + 0x03);
150         smbus_delay();
151
152 int     i,j;
153 for(i=0;i<0x1000;i++)
154 {
155         if (inb(smbus_io_base + 0x00) != 0x08)
156         {       smbus_delay();
157                 for(j=0;j<0xFFFF;j++);
158         }
159 };
160
161         global_status_register = inb(smbus_io_base + 0x00);
162         byte = inb(smbus_io_base + 0x08);
163
164         if (global_status_register != 0x08) { // lose check, otherwise it should be 0
165                 print_debug("Fail");print_debug("\r\t");
166                         return -1;
167         }
168                 print_debug("Success");print_debug("\r\t");
169         return byte;
170 }
171
172
173 static int do_smbus_write_byte(unsigned smbus_io_base, unsigned device, unsigned address, unsigned char val)
174 {
175         unsigned global_status_register;
176
177         outb(val, smbus_io_base + SMBHSTDAT0);
178         smbus_delay();
179
180         /* set the device I'm talking too */
181         outb(((device & 0x7f) << 1) | 0, smbus_io_base + SMBXMITADD);
182         smbus_delay();
183
184         outb(address & 0xff, smbus_io_base + SMBHSTCMD);
185         smbus_delay();
186
187         /* set up for a byte data write */
188         outb(0x06, smbus_io_base + SMBHSTPRTCL);
189         smbus_delay();
190
191         /* poll for transaction completion */
192         if (smbus_wait_until_done(smbus_io_base) < 0) {
193                 return -3;
194         }
195         global_status_register = inb(smbus_io_base + SMBHSTSTAT) & 0x80; /* lose check */;
196
197         if (global_status_register != 0x80) {
198                 return -1;
199         }
200         return 0;
201 }
202