Tidy + compile fixup VT8235 southbridge support.
[coreboot.git] / src / southbridge / via / vt8235 / vt8235_early_smbus.c
1 #define SMBUS_IO_BASE 0xf00
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 #define  I2C_TRANS_CMD          0x40
26 #define  CLOCK_SLAVE_ADDRESS    0x69
27
28 static void enable_smbus(void)
29 {
30         device_t dev;
31         unsigned char c;
32         int i;
33         /* Power management controller */
34                 dev = pci_locate_device(PCI_ID(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235), 0);
35         
36         if (dev == PCI_DEV_INVALID) {
37                 die("SMBUS controller not found\r\n");
38         }               
39         pci_write_config8(dev, 0xd2, (0x4 << 1 ));
40
41         // set IO base address to SMBUS_IO_BASE
42         pci_write_config16(dev, 0xd0, SMBUS_IO_BASE);
43         
44         // Enable SMBus 
45         pci_write_config8(dev, 0xd2, (0x4 << 1)|1);
46         
47         // Enable RTC
48         pci_write_config8(dev,0x51,0x04);
49
50         /* make it work for I/O ...
51          */
52         pci_write_config16(dev, 4, 1);
53         
54
55         /* tell the world we're alive - make power led flash during bios execution */
56         pci_write_config8(dev,0x94,0xb2);
57
58
59         /* FIX for half baud rate problem */
60         /* let clocks and the like settle */
61         /* as yet arbitrary count - 1000 is too little 5000 works */
62         for(i = 0 ; i < 5000 ; i++)
63                 outb(0x80,0x80);
64
65         /* southbridge doesn't seem to like to do much untill after this delay, so set up 
66          * the flashing power LED again */
67         pci_write_config8(dev,0x94,0xb2);
68
69 /* The VT1211 serial port needs 48 mhz clock, on power up it is getting
70    only 24 mhz, there is some mysterious device on the smbus that can
71    fix this...this code below does it. */
72         outb(0xff, SMBUS_IO_BASE+SMBHSTSTAT); 
73         outb(0xff, SMBUS_IO_BASE+SMBHSTSTAT);
74         outb(0xff, SMBUS_IO_BASE+SMBHSTSTAT);
75         outb(0xff, SMBUS_IO_BASE+SMBHSTSTAT);
76         for( ;;) {
77                 c = inb(SMBUS_IO_BASE+SMBHSTSTAT);
78                 if ((c & 1) == 0)
79                         break;
80         }
81         outb(0x7f, SMBUS_IO_BASE+SMBHSTDAT0); 
82         outb(0x83, SMBUS_IO_BASE+SMBHSTCMD);
83         outb(CLOCK_SLAVE_ADDRESS<<1 , SMBUS_IO_BASE+SMBXMITADD);
84         outb(8 | I2C_TRANS_CMD, SMBUS_IO_BASE+SMBHSTCTL);
85
86                 
87         for (;;) {
88                 c = inb(SMBUS_IO_BASE+SMBHSTSTAT);
89                 if ((c & 1) == 0)
90                         break;
91         }
92 }
93
94
95 static inline void smbus_delay(void)
96 {
97         outb(0x80, 0x80);
98 }
99
100 static int smbus_wait_until_ready(void)
101 {
102         unsigned char c;
103         unsigned long loops;
104         loops = SMBUS_TIMEOUT;
105         do {
106                 unsigned char val;
107                 smbus_delay();
108                 c = inb(SMBUS_IO_BASE + SMBHSTSTAT);
109                 while((c & 1) == 1) {
110                         print_debug("c is ");
111                         print_debug_hex8(c);
112                         print_debug("\r\n");
113                         c = inb(SMBUS_IO_BASE + SMBHSTSTAT);
114                         /* nop */ 
115                 }
116
117         } while(--loops);
118         return loops?0:-1;
119 }
120
121 void smbus_reset(void)
122 {
123         outb(HOST_RESET, SMBUS_IO_BASE + SMBHSTSTAT);
124         outb(HOST_RESET, SMBUS_IO_BASE + SMBHSTSTAT);
125         outb(HOST_RESET, SMBUS_IO_BASE + SMBHSTSTAT);
126         outb(HOST_RESET, SMBUS_IO_BASE + SMBHSTSTAT);
127         
128         smbus_wait_until_ready();
129         print_debug("After reset status ");
130         print_debug_hex8( inb(SMBUS_IO_BASE + SMBHSTSTAT));
131         print_debug("\r\n");
132 }
133   
134
135
136 static int smbus_wait_until_done(void)
137 {
138         unsigned long loops;
139         unsigned char byte;
140         loops = SMBUS_TIMEOUT;
141         do {
142                 unsigned char val;
143                 smbus_delay();
144                 
145                 byte = inb(SMBUS_IO_BASE + SMBHSTSTAT);
146                 if (byte & 1)
147                         break;
148                 
149         } while(--loops);
150         return loops?0:-1;
151 }
152
153 static void smbus_print_error(unsigned char host_status_register)
154 {
155
156         print_err("smbus_error: ");
157         print_err_hex8(host_status_register);
158         print_err("\r\n");
159         if (host_status_register & (1 << 4)) {
160                 print_err("Interrup/SMI# was Failed Bus Transaction\r\n");
161         }
162         if (host_status_register & (1 << 3)) {
163                 print_err("Bus Error\r\n");
164         }
165         if (host_status_register & (1 << 2)) {
166                 print_err("Device Error\r\n");
167         }
168         if (host_status_register & (1 << 1)) {
169                 print_err("Interrupt/SMI# was Successful Completion\r\n");
170         }
171         if (host_status_register & (1 << 0)) {
172                 print_err("Host Busy\r\n");
173         }
174 }
175
176
177 /* SMBus routines borrowed from VIA's Trident Driver */
178 /* this works, so I am not going to touch it for now -- rgm */
179 static unsigned char smbus_read_byte(unsigned char devAdr, 
180                                 unsigned char bIndex) 
181 {
182         unsigned short i;
183         unsigned char  bData;
184         unsigned char  sts = 0;
185         
186         /* clear host status */
187         outb(0xff, SMBUS_IO_BASE);
188         
189         /* check SMBUS ready */
190         for ( i = 0; i < 0xFFFF; i++ )
191                 if ( (inb(SMBUS_IO_BASE) & 0x01) == 0 )
192                         break;
193         
194         /* set host command */
195         outb(bIndex, SMBUS_IO_BASE+3);
196         
197         /* set slave address */
198         outb(devAdr | 0x01, SMBUS_IO_BASE+4);
199         
200         /* start */
201         outb(0x48, SMBUS_IO_BASE+2);
202         
203         /* SMBUS Wait Ready */
204         for ( i = 0; i < 0xFFFF; i++ )
205                 if ( ((sts = (inb(SMBUS_IO_BASE) & 0x1f)) & 0x01) == 0 )
206                         break;
207         
208         if ((sts & ~3) != 0) {
209                 smbus_print_error(sts);
210                 return 0;
211         }
212         bData=inb(SMBUS_IO_BASE+5);
213         
214         return bData;
215         
216 }
217
218 /* for reference, here is the fancier version which we will use at some 
219  * point
220  */
221 # if 0
222 int smbus_read_byte(unsigned device, unsigned address, unsigned char *result)
223 {
224         unsigned char host_status_register;
225         unsigned char byte;
226         
227         reset();
228         
229         smbus_wait_until_ready();
230         
231         /* setup transaction */
232         /* disable interrupts */
233         outb(inb(SMBUS_IO_BASE + SMBHSTCTL) & (~1), SMBUS_IO_BASE + SMBHSTCTL);
234         /* set the device I'm talking too */
235         outb(((device & 0x7f) << 1) | 1, SMBUS_IO_BASE + SMBXMITADD);
236         /* set the command/address... */
237         outb(address & 0xFF, SMBUS_IO_BASE + SMBHSTCMD);
238         /* set up for a byte data read */
239         outb((inb(SMBUS_IO_BASE + SMBHSTCTL) & 0xE3) | (0x2 << 2),
240                 SMBUS_IO_BASE + SMBHSTCTL);
241         
242         /* clear any lingering errors, so the transaction will run */
243         outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT);
244         
245         /* clear the data byte...*/
246         outb(0, SMBUS_IO_BASE + SMBHSTDAT0);
247         
248         /* start the command */
249         outb((inb(SMBUS_IO_BASE + SMBHSTCTL) | 0x40),
250                 SMBUS_IO_BASE + SMBHSTCTL);
251         
252         /* poll for transaction completion */
253         smbus_wait_until_done();
254         
255         host_status_register = inb(SMBUS_IO_BASE + SMBHSTSTAT);
256         
257         /* Ignore the In Use Status... */
258         host_status_register &= ~(1 << 6);
259         
260         /* read results of transaction */
261         byte = inb(SMBUS_IO_BASE + SMBHSTDAT0);
262         smbus_print_error(byte);
263         
264         *result = byte;
265         return host_status_register != 0x02;
266 }
267
268
269 #endif
270