bbc6f537161c78b0c1e45c5e0d69a5d1ffe6a35a
[coreboot.git] / src / mainboard / arima / hdama / mainboard.c
1 #include <console/console.h>
2 #include <device/device.h>
3 #include <device/pci.h>
4 #include <device/pci_ids.h>
5 #include <device/pci_ops.h>
6 #include <cpu/p6/msr.h>
7
8 #include <arch/io.h>
9 #include <device/chip.h>
10 #include "../../../northbridge/amd/amdk8/northbridge.h"
11 #include "chip.h"
12
13 #include "pc80/mc146818rtc.h"
14
15
16
17 unsigned long initial_apicid[CONFIG_MAX_CPUS] =
18 {
19         0, 1,
20 };
21
22 #define SMBGSTATUS 0xe0
23 #define SMBGCTL    0xe2
24 #define SMBHSTADDR 0xe4
25 #define SMBHSTDAT  0xe6
26 #define SMBHSTCMD  0xe8
27 #define SMBHSTFIFO 0xe9
28
29 #define SMBUS_TIMEOUT (100*1000*10)
30
31 static inline void smbus_delay(void)
32 {
33         outb(0x80, 0x80);
34 }
35
36 static int smbus_wait_until_ready(unsigned smbus_io_base)
37 {
38         unsigned long loops;
39         loops = SMBUS_TIMEOUT;
40         do {
41                 unsigned short val;
42                 smbus_delay();
43                 val = inw(smbus_io_base + SMBGSTATUS);
44                 if ((val & 0x800) == 0) {
45                         break;
46                 }
47                 if(loops == (SMBUS_TIMEOUT / 2)) {
48                         outw(inw(smbus_io_base + SMBGSTATUS), 
49                                 smbus_io_base + SMBGSTATUS);
50                 }
51         } while(--loops);
52         return loops?0:-2;
53 }
54
55 static int smbus_wait_until_done(unsigned smbus_io_base)
56 {
57         unsigned long loops;
58         loops = SMBUS_TIMEOUT;
59         do {
60                 unsigned short val;
61                 smbus_delay();
62                 
63                 val = inw(smbus_io_base + SMBGSTATUS);
64                 if (((val & 0x8) == 0) | ((val & 0x437) != 0)) {
65                         break;
66                 }
67         } while(--loops);
68         return loops?0:-3;
69 }
70
71 static int smbus_send_byte(unsigned smbus_io_base, unsigned device, unsigned value)
72 {
73         unsigned char global_status_register;
74
75         if (smbus_wait_until_ready(smbus_io_base) < 0) {
76                 return -2;
77         }
78         
79         /* setup transaction */
80         /* disable interrupts */
81         outw(inw(smbus_io_base + SMBGCTL) & ~((1<<10)|(1<<9)|(1<<8)|(1<<4)), smbus_io_base + SMBGCTL);
82         /* set the device I'm talking too */
83         outw(((device & 0x7f) << 1) | 0, smbus_io_base + SMBHSTADDR);
84         /* set the command/address... */
85         outb(0, smbus_io_base + SMBHSTCMD);
86         /* set up for a send byte */
87         outw((inw(smbus_io_base + SMBGCTL) & ~7) | (0x1), smbus_io_base + SMBGCTL);
88
89         /* clear any lingering errors, so the transaction will run */
90         /* Do I need to write the bits to a 1 to clear an error? */
91         outw(inw(smbus_io_base + SMBGSTATUS), smbus_io_base + SMBGSTATUS);
92
93         /* set the data word...*/
94         outw(value, smbus_io_base + SMBHSTDAT);
95
96         /* start the command */
97         outw((inw(smbus_io_base + SMBGCTL) | (1 << 3)), smbus_io_base + SMBGCTL);
98
99
100         /* poll for transaction completion */
101         if (smbus_wait_until_done(smbus_io_base) < 0) {
102                 return -3;
103         }
104         global_status_register = inw(smbus_io_base + SMBGSTATUS);
105
106         if (global_status_register != (1 << 4)) {
107                 return -1;
108         }
109         return 0;
110 }
111
112 static int smbus_recv_byte(unsigned smbus_io_base, unsigned device)
113 {
114         unsigned char global_status_register;
115         unsigned char byte;
116
117         if (smbus_wait_until_ready(smbus_io_base) < 0) {
118                 return -2;
119         }
120         
121         /* setup transaction */
122         /* disable interrupts */
123         outw(inw(smbus_io_base + SMBGCTL) & ~((1<<10)|(1<<9)|(1<<8)|(1<<4)), smbus_io_base + SMBGCTL);
124         /* set the device I'm talking too */
125         outw(((device & 0x7f) << 1) | 1, smbus_io_base + SMBHSTADDR);
126         /* set the command/address... */
127         outb(0, smbus_io_base + SMBHSTCMD);
128         /* set up for a send byte */
129         outw((inw(smbus_io_base + SMBGCTL) & ~7) | (0x1), smbus_io_base + SMBGCTL);
130
131         /* clear any lingering errors, so the transaction will run */
132         /* Do I need to write the bits to a 1 to clear an error? */
133         outw(inw(smbus_io_base + SMBGSTATUS), smbus_io_base + SMBGSTATUS);
134
135         /* set the data word...*/
136         outw(0, smbus_io_base + SMBHSTDAT);
137
138         /* start the command */
139         outw((inw(smbus_io_base + SMBGCTL) | (1 << 3)), smbus_io_base + SMBGCTL);
140
141
142         /* poll for transaction completion */
143         if (smbus_wait_until_done(smbus_io_base) < 0) {
144                 return -3;
145         }
146
147         global_status_register = inw(smbus_io_base + SMBGSTATUS);
148
149         /* read results of transaction */
150         byte = inw(smbus_io_base + SMBHSTDAT) & 0xff;
151
152         if (global_status_register != (1 << 4)) {
153                 return -1;
154         }
155         return byte;
156 }
157
158 #if 0
159 static int smbus_read_byte(unsigned smbus_io_base, unsigned device, unsigned address)
160 {
161         unsigned char global_status_register;
162         unsigned char byte;
163
164         if (smbus_wait_until_ready(smbus_io_base) < 0) {
165                 return -2;
166         }
167         
168         /* setup transaction */
169         /* disable interrupts */
170         outw(inw(smbus_io_base + SMBGCTL) & ~((1<<10)|(1<<9)|(1<<8)|(1<<4)), smbus_io_base + SMBGCTL);
171         /* set the device I'm talking too */
172         outw(((device & 0x7f) << 1) | 1, smbus_io_base + SMBHSTADDR);
173         /* set the command/address... */
174         outb(address & 0xFF, smbus_io_base + SMBHSTCMD);
175         /* set up for a byte data read */
176         outw((inw(smbus_io_base + SMBGCTL) & ~7) | (0x2), smbus_io_base + SMBGCTL);
177
178         /* clear any lingering errors, so the transaction will run */
179         /* Do I need to write the bits to a 1 to clear an error? */
180         outw(inw(smbus_io_base + SMBGSTATUS), smbus_io_base + SMBGSTATUS);
181
182         /* clear the data word...*/
183         outw(0, smbus_io_base + SMBHSTDAT);
184
185         /* start the command */
186         outw((inw(smbus_io_base + SMBGCTL) | (1 << 3)), smbus_io_base + SMBGCTL);
187
188
189         /* poll for transaction completion */
190         if (smbus_wait_until_done(smbus_io_base) < 0) {
191                 return -3;
192         }
193
194         global_status_register = inw(smbus_io_base + SMBGSTATUS);
195
196         /* read results of transaction */
197         byte = inw(smbus_io_base + SMBHSTDAT) & 0xff;
198
199         if (global_status_register != (1 << 4)) {
200                 return -1;
201         }
202         return byte;
203 }
204
205 static int smbus_write_byte(unsigned smbus_io_base, unsigned device, unsigned address, unsigned char val)
206 {
207         if (smbus_wait_until_ready(smbus_io_base) < 0) {
208                 return -2;
209         }
210
211         /* setup transaction */
212         /* disable interrupts */
213         outw(inw(smbus_io_base + SMBGCTL) & ~((1<<10)|(1<<9)|(1<<8)|(1<<4)),
214                         smbus_io_base + SMBGCTL);
215         /* set the device I'm talking too */
216         outw(((device & 0x7f) << 1) | 0, smbus_io_base + SMBHSTADDR);
217         outb(address & 0xFF, smbus_io_base + SMBHSTCMD);
218         /* set up for a byte data write */ /* FIXME */
219         outw((inw(smbus_io_base + SMBGCTL) & ~7) | (0x1), smbus_io_base + SMBGCTL);
220         /* clear any lingering errors, so the transaction will run */
221         /* Do I need to write the bits to a 1 to clear an error? */
222         outw(inw(smbus_io_base + SMBGSTATUS), smbus_io_base + SMBGSTATUS);
223
224         /* clear the data word...*/
225         outw(val, smbus_io_base + SMBHSTDAT);
226
227         /* start the command */
228         outw((inw(smbus_io_base + SMBGCTL) | (1 << 3)), smbus_io_base + SMBGCTL);
229
230         /* poll for transaction completion */
231         if (smbus_wait_until_done(smbus_io_base) < 0) {
232                 return -3;
233         }
234         return 0;
235 }
236 #endif
237
238 #define SMBUS_MUX 0x70
239 static void mainboard_init(device_t dev)
240 {
241         /* Set the mux to see the temperature sensors */
242         dev = dev_find_device(0x1022, 0x746b, 0);
243         if (dev) {
244                 unsigned smbus_io_base;
245                 unsigned device;
246                 int result;
247                 int mux_setting;
248                 device = SMBUS_MUX;
249                 mux_setting = 1;
250                 smbus_io_base = pci_read_config32(dev, 0x58) & ~1;;
251                 result = smbus_send_byte(smbus_io_base, device, mux_setting);
252                 if ((result < 0) || 
253                         (smbus_recv_byte(smbus_io_base, device) != mux_setting)) {
254                         printk_err("SMBUS mux would not set to %d\n", mux_setting);
255                 }
256                 
257         }
258         else {
259                 printk_err("SMBUS_controller not found\n");
260         }
261 }
262
263 static struct device_operations mainboard_operations = {
264         .read_resources   = root_dev_read_resources,
265         .set_resources    = root_dev_set_resources,
266         .enable_resources = enable_childrens_resources,
267         .init             = mainboard_init,
268         .scan_bus         = amdk8_scan_root_bus,
269         .enable           = 0,
270 };
271
272 static void enumerate(struct chip *chip)
273 {
274         struct chip *child;
275         dev_root.ops = &mainboard_operations;
276         chip->dev = &dev_root;
277         chip->bus = 0;
278         for(child = chip->children; child; child = child->next) {
279                 child->bus = &dev_root.link[0];
280         }
281 }
282 struct chip_control mainboard_arima_hdama_control = {
283         .enumerate = enumerate, 
284         .name      = "Arima HDAMA mainboard ",
285 };
286