1 #define SMBUS_IO_BASE 0xf00
12 #define SMBTRNSADD 0x9
13 #define SMBSLVDATA 0xa
14 #define SMLINK_PIN_CTL 0xe
15 #define SMBUS_PIN_CTL 0xf
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
23 #define SMBUS_TIMEOUT (100*1000*10)
25 #define I2C_TRANS_CMD 0x40
26 #define CLOCK_SLAVE_ADDRESS 0x69
28 static void enable_smbus(void)
33 /* Power management controller */
34 dev = pci_locate_device(PCI_ID(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235), 0);
36 if (dev == PCI_DEV_INVALID) {
37 die("SMBUS controller not found\r\n");
39 pci_write_config8(dev, 0xd2, (0x4 << 1 ));
41 // set IO base address to SMBUS_IO_BASE
42 pci_write_config16(dev, 0xd0, SMBUS_IO_BASE);
45 pci_write_config8(dev, 0xd2, (0x4 << 1)|1);
48 pci_write_config8(dev,0x51,0x04);
50 /* make it work for I/O ...
52 pci_write_config16(dev, 4, 1);
55 /* tell the world we're alive - make power led flash during bios execution */
56 pci_write_config8(dev,0x94,0xb2);
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++)
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);
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);
77 c = inb(SMBUS_IO_BASE+SMBHSTSTAT);
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);
88 c = inb(SMBUS_IO_BASE+SMBHSTSTAT);
95 static inline void smbus_delay(void)
100 static int smbus_wait_until_ready(void)
104 loops = SMBUS_TIMEOUT;
108 c = inb(SMBUS_IO_BASE + SMBHSTSTAT);
109 while((c & 1) == 1) {
110 print_debug("c is ");
113 c = inb(SMBUS_IO_BASE + SMBHSTSTAT);
121 void smbus_reset(void)
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);
128 smbus_wait_until_ready();
129 print_debug("After reset status ");
130 print_debug_hex8( inb(SMBUS_IO_BASE + SMBHSTSTAT));
136 static int smbus_wait_until_done(void)
140 loops = SMBUS_TIMEOUT;
145 byte = inb(SMBUS_IO_BASE + SMBHSTSTAT);
153 static void smbus_print_error(unsigned char host_status_register)
156 print_err("smbus_error: ");
157 print_err_hex8(host_status_register);
159 if (host_status_register & (1 << 4)) {
160 print_err("Interrup/SMI# was Failed Bus Transaction\r\n");
162 if (host_status_register & (1 << 3)) {
163 print_err("Bus Error\r\n");
165 if (host_status_register & (1 << 2)) {
166 print_err("Device Error\r\n");
168 if (host_status_register & (1 << 1)) {
169 print_err("Interrupt/SMI# was Successful Completion\r\n");
171 if (host_status_register & (1 << 0)) {
172 print_err("Host Busy\r\n");
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)
184 unsigned char sts = 0;
186 /* clear host status */
187 outb(0xff, SMBUS_IO_BASE);
189 /* check SMBUS ready */
190 for ( i = 0; i < 0xFFFF; i++ )
191 if ( (inb(SMBUS_IO_BASE) & 0x01) == 0 )
194 /* set host command */
195 outb(bIndex, SMBUS_IO_BASE+3);
197 /* set slave address */
198 outb(devAdr | 0x01, SMBUS_IO_BASE+4);
201 outb(0x48, SMBUS_IO_BASE+2);
203 /* SMBUS Wait Ready */
204 for ( i = 0; i < 0xFFFF; i++ )
205 if ( ((sts = (inb(SMBUS_IO_BASE) & 0x1f)) & 0x01) == 0 )
208 if ((sts & ~3) != 0) {
209 smbus_print_error(sts);
212 bData=inb(SMBUS_IO_BASE+5);
218 /* for reference, here is the fancier version which we will use at some
222 int smbus_read_byte(unsigned device, unsigned address, unsigned char *result)
224 unsigned char host_status_register;
229 smbus_wait_until_ready();
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);
242 /* clear any lingering errors, so the transaction will run */
243 outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT);
245 /* clear the data byte...*/
246 outb(0, SMBUS_IO_BASE + SMBHSTDAT0);
248 /* start the command */
249 outb((inb(SMBUS_IO_BASE + SMBHSTCTL) | 0x40),
250 SMBUS_IO_BASE + SMBHSTCTL);
252 /* poll for transaction completion */
253 smbus_wait_until_done();
255 host_status_register = inb(SMBUS_IO_BASE + SMBHSTSTAT);
257 /* Ignore the In Use Status... */
258 host_status_register &= ~(1 << 6);
260 /* read results of transaction */
261 byte = inb(SMBUS_IO_BASE + SMBHSTDAT0);
262 smbus_print_error(byte);
265 return host_status_register != 0x02;