40ef656c0091c5342f751f6853686d7957e88974
[coreboot.git] / src / southbridge / via / vt8231 / vt8231_early_smbus.c
1 #define SMBUS_IO_BASE 0x5000
2
3 #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
15 #define SMBUS_PIN_CTL  0xf
16
17 /* Define register settings */
18 #define HOST_RESET 0xff
19 #define DIMM_BASE 0xa0          // 1010000 is base for DIMM in SMBus
20 #define READ_CMD  0x01          // 1 in the 0 bit of SMBHSTADD states to READ
21
22
23 #define SMBUS_TIMEOUT (100*1000*10)
24
25 static void enable_smbus(void)
26 {
27         device_t dev;
28         unsigned char c;
29         /* Power management controller */
30         dev = pci_locate_device(PCI_ID(0x1106, 0x8235), 0);
31
32         if (dev == PCI_DEV_INVALID) {
33                 die("SMBUS controller not found\n");
34         }
35         // set IO base address to SMBUS_IO_BASE
36         pci_write_config32(dev, 0x90, SMBUS_IO_BASE | 1);
37
38         // Enable SMBus 
39         c = pci_read_config8(dev, 0xd2);
40         c |= 5;
41         pci_write_config8(dev, 0xd2, c);
42
43         /* make it work for I/O ...
44          */
45         dev = pci_locate_device(PCI_ID(0x1106, 0x8231), 0);
46         c = pci_read_config8(dev, 4);
47         c |= 1;
48         pci_write_config8(dev, 4, c);
49         print_debug_hex8(c);
50         print_debug(" is the comm register\n");
51
52         print_debug("SMBus controller enabled\n");
53 }
54
55
56 static inline void smbus_delay(void)
57 {
58         outb(0x80, 0x80);
59 }
60
61 static int smbus_wait_until_active(void)
62 {
63         unsigned long loops;
64         loops = SMBUS_TIMEOUT;
65         do {
66                 unsigned char val;
67                 smbus_delay();
68                 val = inb(SMBUS_IO_BASE + SMBHSTSTAT);
69                 if ((val & 1)) {
70                         break;
71                 }
72         } while (--loops);
73         return loops ? 0 : -4;
74 }
75
76 static int smbus_wait_until_ready(void)
77 {
78         unsigned long loops;
79         loops = SMBUS_TIMEOUT;
80         do {
81                 unsigned char val;
82                 smbus_delay();
83                 val = inb(SMBUS_IO_BASE + SMBHSTSTAT);
84                 if ((val & 1) == 0) {
85                         break;
86                 }
87                 if (loops == (SMBUS_TIMEOUT / 2)) {
88                         outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT);
89                 }
90         } while (--loops);
91         return loops ? 0 : -2;
92 }
93
94 static int smbus_wait_until_done(void)
95 {
96         unsigned long loops;
97         loops = SMBUS_TIMEOUT;
98         do {
99                 unsigned char val;
100                 smbus_delay();
101
102                 val = inb(SMBUS_IO_BASE + SMBHSTSTAT);
103                 if ((val & 1) == 0) {
104                         break;
105                 }
106         } while (--loops);
107         return loops ? 0 : -3;
108 }
109
110 #if 0
111 void smbus_reset(void)
112 {
113         outb(HOST_RESET, SMBUS_IO_BASE + SMBHSTSTAT);
114         outb(HOST_RESET, SMBUS_IO_BASE + SMBHSTSTAT);
115         outb(HOST_RESET, SMBUS_IO_BASE + SMBHSTSTAT);
116         outb(HOST_RESET, SMBUS_IO_BASE + SMBHSTSTAT);
117
118         smbus_wait_until_ready();
119         print_debug("After reset status ");
120         print_debug_hex8(inb(SMBUS_IO_BASE + SMBHSTSTAT));
121         print_debug("\n");
122 }
123 #endif
124
125 #if CONFIG_DEBUG_SMBUS
126 static void smbus_print_error(unsigned char host_status_register)
127 {
128
129         print_err("smbus_error: ");
130         print_err_hex8(host_status_register);
131         print_err("\n");
132         if (host_status_register & (1 << 4)) {
133                 print_err("Interrup/SMI# was Failed Bus Transaction\n");
134         }
135         if (host_status_register & (1 << 3)) {
136                 print_err("Bus Error\n");
137         }
138         if (host_status_register & (1 << 2)) {
139                 print_err("Device Error\n");
140         }
141         if (host_status_register & (1 << 1)) {
142                 print_err("Interrupt/SMI# was Successful Completion\n");
143         }
144         if (host_status_register & (1 << 0)) {
145                 print_err("Host Busy\n");
146         }
147 }
148 #endif
149
150 /*
151  * Copied from intel/i82801dbm early smbus code - suggested by rgm.
152  * Modifications/check against i2c-viapro driver code from linux-2.4.22
153  * and VT8231 Reference Docs - mw.
154  */
155 static int smbus_read_byte(unsigned device, unsigned address)
156 {
157         unsigned char global_status_register;
158         unsigned char byte;
159
160         if (smbus_wait_until_ready() < 0) {
161                 outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT);
162                 if (smbus_wait_until_ready() < 0) {
163                         return -2;
164                 }
165         }
166
167         /* setup transaction */
168         /* disable interrupts */
169         outb(inb(SMBUS_IO_BASE + SMBHSTCTL) & 0xfe, SMBUS_IO_BASE + SMBHSTCTL);
170         /* set the device I'm talking too */
171         outb(((device & 0x7f) << 1) | 1, SMBUS_IO_BASE + SMBXMITADD);
172         /* set the command/address... */
173         outb(address & 0xFF, SMBUS_IO_BASE + SMBHSTCMD);
174         /* set up for a byte data read */
175         outb((inb(SMBUS_IO_BASE + SMBHSTCTL) & 0xe3) | (0x2 << 2), SMBUS_IO_BASE + SMBHSTCTL);
176
177         /* clear any lingering errors, so the transaction will run */
178         outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT);
179
180         /* clear the data byte... */
181         outb(0, SMBUS_IO_BASE + SMBHSTDAT0);
182
183         /* start a byte read, with interrupts disabled */
184         outb((inb(SMBUS_IO_BASE + SMBHSTCTL) | 0x40), SMBUS_IO_BASE + SMBHSTCTL);
185         /* poll for it to start */
186         if (smbus_wait_until_active() < 0) {
187                 return -4;
188         }
189
190         /* poll for transaction completion */
191         if (smbus_wait_until_done() < 0) {
192                 return -3;
193         }
194
195         /* Ignore the Host Busy & Command Complete ? */
196         global_status_register = inb(SMBUS_IO_BASE + SMBHSTSTAT) & ~((1 << 1) | (1 << 0));
197
198         /* read results of transaction */
199         byte = inb(SMBUS_IO_BASE + SMBHSTDAT0);
200
201         if (global_status_register != 0) {
202                 return -1;
203         }
204         return byte;
205 }
206
207 #if 0
208 /* SMBus routines borrowed from VIA's Trident Driver */
209 /* this works, so I am not going to touch it for now -- rgm */
210 static unsigned char smbus_read_byte(unsigned char devAdr, unsigned char bIndex)
211 {
212         unsigned int i;
213         unsigned char bData;
214         unsigned char sts = 0;
215
216         /* clear host status */
217         outb(0xff, SMBUS_IO_BASE);
218
219         /* check SMBUS ready */
220         for (i = 0; i < SMBUS_TIMEOUT; i++)
221                 if ((inb(SMBUS_IO_BASE) & 0x01) == 0)
222                         break;
223
224         /* set host command */
225         outb(bIndex, SMBUS_IO_BASE + 3);
226
227         /* set slave address */
228         outb(devAdr | 0x01, SMBUS_IO_BASE + 4);
229
230         /* start */
231         outb(0x48, SMBUS_IO_BASE + 2);
232
233         /* SMBUS Wait Ready */
234         for (i = 0; i < SMBUS_TIMEOUT; i++)
235                 if (((sts = inb(SMBUS_IO_BASE)) & 0x01) == 0)
236                         break;
237         if ((sts & ~3) != 0) {
238                 smbus_print_error(sts);
239                 return 0;
240         }
241         bData = inb(SMBUS_IO_BASE + 5);
242
243         return bData;
244
245 }
246 #endif
247 /* for reference, here is the fancier version which we will use at some 
248  * point
249  */
250 # if 0
251 int smbus_read_byte(unsigned device, unsigned address, unsigned char *result)
252 {
253         unsigned char host_status_register;
254         unsigned char byte;
255
256         reset();
257
258         smbus_wait_until_ready();
259
260         /* setup transaction */
261         /* disable interrupts */
262         outb(inb(SMBUS_IO_BASE + SMBHSTCTL) & (~1), SMBUS_IO_BASE + SMBHSTCTL);
263         /* set the device I'm talking too */
264         outb(((device & 0x7f) << 1) | 1, SMBUS_IO_BASE + SMBXMITADD);
265         /* set the command/address... */
266         outb(address & 0xFF, SMBUS_IO_BASE + SMBHSTCMD);
267         /* set up for a byte data read */
268         outb((inb(SMBUS_IO_BASE + SMBHSTCTL) & 0xE3) | (0x2 << 2), SMBUS_IO_BASE + SMBHSTCTL);
269
270         /* clear any lingering errors, so the transaction will run */
271         outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT);
272
273         /* clear the data byte... */
274         outb(0, SMBUS_IO_BASE + SMBHSTDAT0);
275
276         /* start the command */
277         outb((inb(SMBUS_IO_BASE + SMBHSTCTL) | 0x40), SMBUS_IO_BASE + SMBHSTCTL);
278
279         /* poll for transaction completion */
280         smbus_wait_until_done();
281
282         host_status_register = inb(SMBUS_IO_BASE + SMBHSTSTAT);
283
284         /* Ignore the In Use Status... */
285         host_status_register &= ~(1 << 6);
286
287         /* read results of transaction */
288         byte = inb(SMBUS_IO_BASE + SMBHSTDAT0);
289         smbus_print_error(byte);
290
291         *result = byte;
292         return host_status_register != 0x02;
293 }
294
295
296 #endif