a0d9663318ab16437cd75769e44756e333a098bf
[coreboot.git] / src / southbridge / intel / i82801db / i82801db_early_smbus.c
1 /*
2  * This file is part of the LinuxBIOS project.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
17  */
18
19 #include "i82801db_smbus.h"
20
21 #define SMBUS_IO_BASE 0x0f00
22
23 static void enable_smbus(void)
24 {
25         device_t dev;
26         dev = pci_locate_device(PCI_ID(0x8086, 0x24d3), 0);
27         if (dev == PCI_DEV_INVALID) {
28                 die("SMBUS controller not found\r\n");
29         }
30         print_spew("SMBus controller enabled\r\n");
31         
32         pci_write_config32(dev, 0x20, SMBUS_IO_BASE | 1);
33         /* Set smbus enable */
34         pci_write_config8(dev, 0x40, 1);
35         /* Set smbus iospace enable */
36         pci_write_config8(dev, 0x4, 1);
37         /* SMBALERT_DIS */
38         pci_write_config8(dev, 0x11, 4);
39         
40         /* Disable interrupt generation */
41         outb(0, SMBUS_IO_BASE + SMBHSTCTL);
42
43         /* clear any lingering errors, so the transaction will run */
44         outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT);
45
46 #if 0   // It's unlikely that half the southbridge suddenly vanishes?
47         dev = pci_locate_device(PCI_ID(0x8086, 0x24d0), 0);
48         if (dev == PCI_DEV_INVALID) {
49                 die("ISA bridge not found\r\n");
50         }
51 #endif
52 }
53
54 static int smbus_read_byte(unsigned device, unsigned address)
55 {
56         return do_smbus_read_byte(SMBUS_IO_BASE, device, address);
57 }
58
59 static void smbus_write_byte(unsigned device, unsigned address, unsigned char val)
60 {
61         if (smbus_wait_until_ready(SMBUS_IO_BASE) < 0) {
62                 return;
63         }
64         
65         print_debug("Unimplemented smbus_write_byte() called.\r\n");
66
67 #if 0
68         /* setup transaction */
69         /* disable interrupts */
70         outw(inw(SMBUS_IO_BASE + SMBGCTL) & ~((1<<10)|(1<<9)|(1<<8)|(1<<4)),
71                         SMBUS_IO_BASE + SMBGCTL);
72         /* set the device I'm talking too */
73         outw(((device & 0x7f) << 1) | 1, SMBUS_IO_BASE + SMBHSTADDR);
74         outb(address & 0xFF, SMBUS_IO_BASE + SMBHSTCMD);
75         /* set up for a byte data write */ /* FIXME */
76         outw((inw(SMBUS_IO_BASE + SMBGCTL) & ~7) | (0x1), SMBUS_IO_BASE + SMBGCTL);
77         /* clear any lingering errors, so the transaction will run */
78         /* Do I need to write the bits to a 1 to clear an error? */
79         outw(inw(SMBUS_IO_BASE + SMBGSTATUS), SMBUS_IO_BASE + SMBGSTATUS);
80
81         /* clear the data word...*/
82         outw(val, SMBUS_IO_BASE + SMBHSTDAT);
83
84         /* start the command */
85         outw((inw(SMBUS_IO_BASE + SMBGCTL) | (1 << 3)), SMBUS_IO_BASE + SMBGCTL);
86
87         /* poll for transaction completion */
88         smbus_wait_until_done(SMBUS_IO_BASE);
89 #endif  
90         return;
91 }
92
93 static int smbus_write_block(unsigned device, unsigned length, unsigned cmd, 
94                  unsigned data1, unsigned data2)
95 {
96         unsigned char global_control_register;
97         unsigned char global_status_register;
98         unsigned char byte;
99         unsigned char stat;
100         int i;
101
102         /* chear the PM timeout flags, SECOND_TO_STS */
103         outw(inw(0x0400 + 0x66), 0x0400 + 0x66);
104         
105         if (smbus_wait_until_ready(SMBUS_IO_BASE) < 0) {
106                 return -2;
107         }
108         
109         /* setup transaction */
110         /* Obtain ownership */
111         outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT);
112         for(stat=0;(stat&0x40)==0;) {
113         stat = inb(SMBUS_IO_BASE + SMBHSTSTAT);
114         }
115         /* clear the done bit */
116         outb(0x80, SMBUS_IO_BASE + SMBHSTSTAT);
117         /* disable interrupts */
118         outb(inb(SMBUS_IO_BASE + SMBHSTCTL) & (~1), SMBUS_IO_BASE + SMBHSTCTL);
119         
120         /* set the device I'm talking too */
121         outb(((device & 0x7f) << 1), SMBUS_IO_BASE + SMBXMITADD);
122         
123         /* set the command address */
124         outb(cmd & 0xFF, SMBUS_IO_BASE + SMBHSTCMD);
125         
126         /* set the block length */
127         outb(length & 0xFF, SMBUS_IO_BASE + SMBHSTDAT0);
128         
129         /* try sending out the first byte of data here */
130         byte=(data1>>(0))&0x0ff;
131         outb(byte,SMBUS_IO_BASE + SMBBLKDAT);
132         /* issue a block write command */
133         outb((inb(SMBUS_IO_BASE + SMBHSTCTL) & 0xE3) | (0x5 << 2) | 0x40, 
134                         SMBUS_IO_BASE + SMBHSTCTL);
135
136         for(i=0;i<length;i++) {
137                 
138                 /* poll for transaction completion */
139                 if (smbus_wait_until_blk_done(SMBUS_IO_BASE) < 0) {
140                         return -3;
141                 }
142                 
143                 /* load the next byte */
144                 if(i>3)
145                         byte=(data2>>(i%4))&0x0ff;
146                 else
147                         byte=(data1>>(i))&0x0ff;
148                 outb(byte,SMBUS_IO_BASE + SMBBLKDAT);
149                 
150                 /* clear the done bit */
151                 outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), 
152                                 SMBUS_IO_BASE + SMBHSTSTAT);
153         }
154
155         print_debug("SMBUS Block complete\r\n");
156         return 0;
157 }
158