copy_and_run.c is not needed twice, and it is used on non-car too.
[coreboot.git] / src / southbridge / intel / i82801dx / i82801dx_early_smbus.c
1 /*
2  * This file is part of the coreboot project.
3  *
4  * Copyright (C) 2004 Ronald G. Minnich
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; version 2 of
9  * the License.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
19  */
20
21 //#define SMBUS_IO_BASE 0x1000
22 //#define SMBUS_IO_BASE 0x0f00
23
24 #define SMBHSTSTAT 0x0
25 #define SMBHSTCTL  0x2
26 #define SMBHSTCMD  0x3
27 #define SMBXMITADD 0x4
28 #define SMBHSTDAT0 0x5
29 #define SMBHSTDAT1 0x6
30 #define SMBBLKDAT  0x7
31 #define SMBTRNSADD 0x9
32 #define SMBSLVDATA 0xa
33 #define SMLINK_PIN_CTL 0xe
34 #define SMBUS_PIN_CTL  0xf
35
36 /* Between 1-10 seconds, We should never timeout normally 
37  * Longer than this is just painful when a timeout condition occurs.
38  */
39 //#define SMBUS_TIMEOUT (100*1000*10)
40
41 static void enable_smbus(void)
42 {
43         device_t dev = PCI_DEV(0x0, 0x1f, 0x3);
44
45         print_debug("SMBus controller enabled\n");
46         /* set smbus iobase */
47         pci_write_config32(dev, 0x20, SMBUS_IO_BASE | 1);
48         /* Set smbus enable */
49         pci_write_config8(dev, 0x40, 0x01);
50         /* Set smbus iospace enable */
51         pci_write_config16(dev, 0x4, 0x01);
52         /* Disable interrupt generation */
53         outb(0, SMBUS_IO_BASE + SMBHSTCTL);
54         /* clear any lingering errors, so the transaction will run */
55         outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT);
56 }
57
58 static inline void smbus_delay(void)
59 {
60         outb(0x80, 0x80);
61 }
62
63 static int smbus_wait_until_active(void)
64 {
65         unsigned long loops;
66         loops = SMBUS_TIMEOUT;
67         do {
68                 unsigned char val;
69                 smbus_delay();
70                 val = inb(SMBUS_IO_BASE + SMBHSTSTAT);
71                 if ((val & 1)) {
72                         break;
73                 }
74         } while (--loops);
75         return loops ? 0 : -4;
76 }
77
78 static int smbus_wait_until_ready(void)
79 {
80         unsigned long loops;
81         loops = SMBUS_TIMEOUT;
82         do {
83                 unsigned char val;
84                 smbus_delay();
85                 val = inb(SMBUS_IO_BASE + SMBHSTSTAT);
86                 if ((val & 1) == 0) {
87                         break;
88                 }
89                 if (loops == (SMBUS_TIMEOUT / 2)) {
90                         outb(inb(SMBUS_IO_BASE + SMBHSTSTAT),
91                              SMBUS_IO_BASE + SMBHSTSTAT);
92                 }
93         } while (--loops);
94         return loops ? 0 : -2;
95 }
96
97 static int smbus_wait_until_done(void)
98 {
99         unsigned long loops;
100         loops = SMBUS_TIMEOUT;
101         do {
102                 unsigned char val;
103                 smbus_delay();
104
105                 val = inb(SMBUS_IO_BASE + SMBHSTSTAT);
106                 if ((val & 1) == 0) {
107                         break;
108                 }
109                 if ((val & ~((1 << 6) | (1 << 0))) != 0) {
110                         break;
111                 }
112         } while (--loops);
113         return loops ? 0 : -3;
114 }
115
116 static int smbus_read_byte(unsigned device, unsigned address)
117 {
118         unsigned char global_control_register;
119         unsigned char global_status_register;
120         unsigned char byte;
121
122         /*print_err("smbus_read_byte\n"); */
123         if (smbus_wait_until_ready() < 0) {
124                 print_err_hex8(-2);
125                 return -2;
126         }
127
128         /* setup transaction */
129         /* disable interrupts */
130         outb(inb(SMBUS_IO_BASE + SMBHSTCTL) & 0xfe, SMBUS_IO_BASE + SMBHSTCTL);
131         /* set the device I'm talking too */
132         outb(((device & 0x7f) << 1) | 1, SMBUS_IO_BASE + SMBXMITADD);
133         /* set the command/address... */
134         outb(address & 0xFF, SMBUS_IO_BASE + SMBHSTCMD);
135         /* set up for a byte data read */
136         outb((inb(SMBUS_IO_BASE + SMBHSTCTL) & 0xe3) | (0x2 << 2),
137              SMBUS_IO_BASE + SMBHSTCTL);
138
139         /* clear any lingering errors, so the transaction will run */
140         outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT);
141
142         /* clear the data byte... */
143         outb(0, SMBUS_IO_BASE + SMBHSTDAT0);
144
145         /* start a byte read, with interrupts disabled */
146         outb((inb(SMBUS_IO_BASE + SMBHSTCTL) | 0x40),
147              SMBUS_IO_BASE + SMBHSTCTL);
148         /* poll for it to start */
149         if (smbus_wait_until_active() < 0) {
150                 print_err_hex8(-4);
151                 return -4;
152         }
153
154         /* poll for transaction completion */
155         if (smbus_wait_until_done() < 0) {
156                 print_err_hex8(-3);
157                 return -3;
158         }
159
160         global_status_register = inb(SMBUS_IO_BASE + SMBHSTSTAT) & ~(1 << 6);   /* Ignore the In Use Status... */
161
162         /* read results of transaction */
163         byte = inb(SMBUS_IO_BASE + SMBHSTDAT0);
164
165         if (global_status_register != 2) {
166                 print_err_hex8(-1);
167                 return -1;
168         }
169 /*
170         print_err("smbus_read_byte: ");
171         print_err_hex32(device); print_err(" ad "); print_err_hex32(address);
172         print_err("value "); print_err_hex8(byte); print_err("\n");
173  */
174         return byte;
175 }
176
177 #if 0
178 static void smbus_write_byte(unsigned device, unsigned address,
179                              unsigned char val)
180 {
181         if (smbus_wait_until_ready() < 0) {
182                 return;
183         }
184
185         /* by LYH */
186         outb(0x37, SMBUS_IO_BASE + SMBHSTSTAT);
187         /* set the device I'm talking too */
188         outw(((device & 0x7f) << 1) | 0, SMBUS_IO_BASE + SMBHSTADDR);
189
190         /* data to send */
191         outb(val, SMBUS_IO_BASE + SMBHSTDAT);
192
193         outb(address & 0xFF, SMBUS_IO_BASE + SMBHSTCMD);
194
195         /* start the command */
196         outb(0xa, SMBUS_IO_BASE + SMBHSTCTL);
197
198         /* poll for transaction completion */
199         smbus_wait_until_done();
200         return;
201 }
202 #endif