- O2, enums, and switch statements work in romcc
[coreboot.git] / src / southbridge / via / vt8231 / vt8231.c
1
2 #include <arch/io.h>
3 #include <device/device.h>
4 #include <device/pci.h>
5 #include <device/pci_ops.h>
6 #include <device/pci_ids.h>
7 #include <device/chip.h>
8 #include <console/console.h>
9 #include "vt8231.h"
10 #include "chip.h"
11
12 void pc_keyboard_init(void);
13
14 void hard_reset(void) 
15 {
16         printk_err("NO HARD RESET ON VT8231! FIX ME!\n");
17 }
18
19 static void usb_on(int enable)
20 {
21         unsigned char regval;
22
23         /* Base 8231 controller */
24         device_t dev0 = dev_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231, 0);
25         /* USB controller 1 */
26         device_t dev2 = dev_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_2, 0);
27         /* USB controller 2 */
28         device_t dev3 = dev_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_2, dev2);
29         
30         /* enable USB1 */
31         if(dev2) {
32                 if (enable) {
33                         pci_write_config8(dev2, 0x3c, 0x05);
34                         pci_write_config8(dev2, 0x04, 0x07);
35                 } else {
36                         pci_write_config8(dev2, 0x3c, 0x00);
37                         pci_write_config8(dev2, 0x04, 0x00);
38                 }
39         }
40         
41         if(dev0) {
42                 regval = pci_read_config8(dev0, 0x50);
43                 if (enable) 
44                         regval &= ~(0x10);    
45                 else
46                         regval |= 0x10;               
47                 pci_write_config8(dev0, 0x50, regval);
48         }
49         
50         /* enable USB2 */
51         if(dev3) {
52                 if (enable) {
53                         pci_write_config8(dev3, 0x3c, 0x05);
54                         pci_write_config8(dev3, 0x04, 0x07);
55                 } else {
56                         pci_write_config8(dev3, 0x3c, 0x00);
57                         pci_write_config8(dev3, 0x04, 0x00);
58                 }
59         }
60         
61         if(dev0) {
62                 regval = pci_read_config8(dev0, 0x50);
63                 if (enable) 
64                         regval &= ~(0x20);    
65                 else
66                         regval |= 0x20;    
67                 pci_write_config8(dev0, 0x50, regval);
68         }
69 }
70
71 static void keyboard_on(void)
72 {
73         unsigned char regval;
74         
75         /* Base 8231 controller */
76         device_t dev0 = dev_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231, 0);
77         
78         /* kevinh/Ispiri - update entire function to use 
79            new pci_write_config8 */
80
81         if (dev0) {
82                 regval = pci_read_config8(dev0, 0x51);
83                 regval |= 0x0f; 
84                 pci_write_config8(dev0, 0x51, regval);
85         }
86         pc_keyboard_init();
87 }
88
89 static void nvram_on(void)
90 {
91         /*
92          * the VIA 8231 South has a very different nvram setup than the 
93          * piix4e ...
94          * turn on ProMedia nvram.
95          * TO DO: use the PciWriteByte function here.
96          */
97         
98         /*
99          * kevinh/Ispiri - I don't think this is the correct address/value
100          * intel_conf_writeb(0x80008841, 0xFF);
101          */
102 }
103
104
105 /*
106  * Enable the ethernet device and turn off stepping (because it is integrated 
107  * inside the southbridge)
108  */
109 static void ethernet_fixup()
110 {
111         device_t        edev;
112         uint8_t         byte;
113
114         printk_info("Ethernet fixup\n");
115
116         edev = dev_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8233_7, 0);
117         if (edev) {
118                 printk_debug("Configuring VIA LAN\n");
119                 
120                 /* We don't need stepping - though the device supports it */
121                 byte = pci_read_config8(edev, PCI_COMMAND);
122                 byte &= ~PCI_COMMAND_WAIT;
123                 pci_write_config8(edev, PCI_COMMAND, byte);
124         } else {
125                 printk_debug("VIA LAN not found\n");
126         }
127 }
128
129
130 /* we need to do things in this function so that PCI scan will find 
131  * them.  One problem here is that we can't use ANY of the new device 
132  * stuff. This work here precedes all that.      
133  * Fundamental problem with linuxbios V2 architecture.
134  * You can't do pci control in the C code without having done a PCI scan.
135  * But in some cases you need to to pci control in the c code before doing
136  * a PCI scan. But you can't use arch/romcc_io.h (the code you need) because
137  * that has functions with the same name but different type signatures
138  * (e.g. device_t). This needs to get fixed. We need low-level pci scans
139  * in the C code. 
140  */
141 static void vt8231_pci_enable(struct southbridge_via_vt8231_config *conf) 
142 {
143         /*
144           unsigned long busdevfn = 0x8000;
145           if (conf->enable_ide) {
146           printk_debug("%s: enabling IDE function\n", __FUNCTION__);
147           }
148         */
149 }
150
151 /* PIRQ init
152  */
153 void pci_assign_irqs(unsigned bus, unsigned slot, const unsigned char pIntAtoD[4]);
154
155
156 static const unsigned char southbridgeIrqs[4] = { 11, 5, 10, 12 };
157 static const unsigned char enetIrqs[4] = { 11, 5, 10, 12 };
158 static const unsigned char slotIrqs[4] = { 5, 10, 12, 11 };
159
160 /*
161         Our IDSEL mappings are as follows
162         PCI slot is AD31          (device 15) (00:14.0)
163         Southbridge is AD28       (device 12) (00:11.0)
164 */
165 static void pci_routing_fixup(void)
166 {
167         device_t dev;
168
169         dev = dev_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231, 0);
170         printk_info("%s: dev is %p\n", __FUNCTION__, dev);
171         if (dev) {
172                 /* initialize PCI interupts - these assignments depend
173                    on the PCB routing of PINTA-D 
174
175                    PINTA = IRQ11
176                    PINTB = IRQ5
177                    PINTC = IRQ10
178                    PINTD = IRQ12
179                 */
180                 pci_write_config8(dev, 0x55, 0xb0);
181                 pci_write_config8(dev, 0x56, 0xa5);
182                 pci_write_config8(dev, 0x57, 0xc0);
183         }
184
185         // Standard southbridge components
186         printk_info("setting southbridge\n");
187         pci_assign_irqs(0, 0x11, southbridgeIrqs);
188
189         // Ethernet built into southbridge
190         printk_info("setting ethernet\n");
191         pci_assign_irqs(0, 0x12, enetIrqs);
192
193         // PCI slot
194         printk_info("setting pci slot\n");
195         pci_assign_irqs(0, 0x14, slotIrqs);
196         printk_info("%s: DONE\n", __FUNCTION__);
197 }
198
199
200 void
201 dump_south(void)
202 {
203         device_t dev0;
204         dev0 = dev_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231, 0);
205         int i,j;
206         
207         for(i = 0; i < 256; i += 16) {
208                 printk_debug("0x%x: ", i);
209                 for(j = 0; j < 16; j++) {
210                         printk_debug("%02x ", pci_read_config8(dev0, i+j));
211                 }
212                 printk_debug("\n");
213         }
214 }
215
216 static void vt8231_init(struct southbridge_via_vt8231_config *conf)
217 {
218         unsigned char enables;
219         device_t dev0;
220         device_t dev1;
221         device_t devpwr;
222         
223         // to do: use the pcibios_find function here, instead of 
224         // hard coding the devfn. 
225         // done - kevinh/Ispiri
226         printk_debug("vt8231 init\n");
227         /* Base 8231 controller */
228         dev0 = dev_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231, 0);
229         /* IDE controller */
230         dev1 = dev_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1, 0);
231         /* Power management controller */
232         devpwr = dev_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231_4, 0);
233
234         // enable the internal I/O decode
235         enables = pci_read_config8(dev0, 0x6C);
236         enables |= 0x80;
237         pci_write_config8(dev0, 0x6C, enables);
238         
239         // Map 4MB of FLASH into the address space
240         pci_write_config8(dev0, 0x41, 0x7f);
241         
242         // Set bit 6 of 0x40, because Award does it (IO recovery time)
243         // IMPORTANT FIX - EISA 0x4d0 decoding must be on so that PCI 
244         // interrupts can be properly marked as level triggered.
245         enables = pci_read_config8(dev0, 0x40);
246         pci_write_config8(dev0, 0x40, enables);
247         
248         // Set 0x42 to 0xf0 to match Award bios
249         enables = pci_read_config8(dev0, 0x42);
250         enables |= 0xf0;
251         pci_write_config8(dev0, 0x42, enables);
252         
253         // Set bit 3 of 0x4a, to match award (dummy pci request)
254         enables = pci_read_config8(dev0, 0x4a);
255         enables |= 0x08;
256         pci_write_config8(dev0, 0x4a, enables);
257         
258         // Set bit 3 of 0x4f to match award (use INIT# as cpu reset)
259         enables = pci_read_config8(dev0, 0x4f);
260         enables |= 0x08;
261         pci_write_config8(dev0, 0x4f, enables);
262         
263         // Set 0x58 to 0x03 to match Award
264         pci_write_config8(dev0, 0x58, 0x03);
265         
266         // enable the ethernet/RTC
267         if(dev0) {
268                 enables = pci_read_config8(dev0, 0x51);
269                 enables |= 0x18; 
270                 pci_write_config8(dev0, 0x51, enables);
271         }
272         
273         
274         // enable com1 and com2. 
275         if (conf->enable_com_ports) {
276                 enables = pci_read_config8(dev0, 0x6e);
277                 
278                 /* 0x80 is enable com port b, 0x10 is to make it com2, 0x8
279                  * is enable com port a as com1 kevinh/Ispiri - Old code
280                  * thought 0x01 would make it com1, that was wrong enables =
281                  * 0x80 | 0x10 | 0x8 ; pci_write_config8(dev0, 0x6e,
282                  * enables); // note: this is also a redo of some port of
283                  * assembly, but we want everything up.
284                  */
285                 
286                 /* set com1 to 115 kbaud not clear how to do this yet.
287                  * forget it; done in assembly.
288                  */
289
290         }
291         // enable IDE, since Linux won't do it.
292         // First do some more things to devfn (17,0)
293         // note: this should already be cleared, according to the book. 
294         enables = pci_read_config8(dev0, 0x50);
295         printk_debug("IDE enable in reg. 50 is 0x%x\n", enables);
296         enables &= ~8; // need manifest constant here!
297         printk_debug("set IDE reg. 50 to 0x%x\n", enables);
298         pci_write_config8(dev0, 0x50, enables);
299         
300         // set default interrupt values (IDE)
301         enables = pci_read_config8(dev0, 0x4c);
302         printk_debug("IRQs in reg. 4c are 0x%x\n", enables & 0xf);
303         // clear out whatever was there. 
304         enables &= ~0xf;
305         enables |= 4;
306         printk_debug("setting reg. 4c to 0x%x\n", enables);
307         pci_write_config8(dev0, 0x4c, enables);
308         
309         // set up the serial port interrupts. 
310         // com2 to 3, com1 to 4
311         pci_write_config8(dev0, 0x46, 0x04);
312         pci_write_config8(dev0, 0x47, 0x03);
313         pci_write_config8(dev0, 0x6e, 0x98);
314         //
315         // Power management setup
316         //
317         // Set ACPI base address to IO 0x4000
318         pci_write_config32(devpwr, 0x48, 0x4001);
319         
320         // Enable ACPI access (and setup like award)
321         pci_write_config8(devpwr, 0x41, 0x84);
322         
323         // Set hardware monitor base address to IO 0x6000
324         pci_write_config32(devpwr, 0x70, 0x6001);
325         
326         // Enable hardware monitor (and setup like award)
327         pci_write_config8(devpwr, 0x74, 0x01);
328         
329         // set IO base address to 0x5000
330         pci_write_config32(devpwr, 0x90, 0x5001);
331         
332         // Enable SMBus 
333         pci_write_config8(devpwr, 0xd2, 0x01);
334         
335         //
336         // IDE setup
337         //
338         if (conf->enable_native_ide) {
339                 // Run the IDE controller in 'compatiblity mode - i.e. don't use PCI
340                 // interrupts.  Using PCI ints confuses linux for some reason.
341                 
342                 printk_info("%s: enabling native IDE addresses\n", __FUNCTION__);
343                 enables = pci_read_config8(dev1, 0x42);
344                 printk_debug("enables in reg 0x42 0x%x\n", enables);
345                 enables &= ~0xc0;               // compatability mode
346                 pci_write_config8(dev1, 0x42, enables);
347                 enables = pci_read_config8(dev1, 0x42);
348                 printk_debug("enables in reg 0x42 read back as 0x%x\n", enables);
349         }
350         
351         enables = pci_read_config8(dev1, 0x40);
352         printk_debug("enables in reg 0x40 0x%x\n", enables);
353         enables |= 3;
354         pci_write_config8(dev1, 0x40, enables);
355         enables = pci_read_config8(dev1, 0x40);
356         printk_debug("enables in reg 0x40 read back as 0x%x\n", enables);
357         
358         // Enable prefetch buffers
359         enables = pci_read_config8(dev1, 0x41);
360         enables |= 0xf0;
361         pci_write_config8(dev1, 0x41, enables);
362         
363         // Lower thresholds (cause award does it)
364         enables = pci_read_config8(dev1, 0x43);
365         enables &= ~0x0f;
366         enables |=  0x05;
367         pci_write_config8(dev1, 0x43, enables);
368         
369         // PIO read prefetch counter (cause award does it)
370         pci_write_config8(dev1, 0x44, 0x18);
371         
372         // Use memory read multiple
373         pci_write_config8(dev1, 0x45, 0x1c);
374         
375         // address decoding. 
376         // we want "flexible", i.e. 1f0-1f7 etc. or native PCI
377         // kevinh@ispiri.com - the standard linux drivers seem ass slow when 
378         // used in native mode - I've changed back to classic
379         enables = pci_read_config8(dev1, 0x9);
380         printk_debug("enables in reg 0x9 0x%x\n", enables);
381         // by the book, set the low-order nibble to 0xa. 
382         if (conf->enable_native_ide) {
383                 enables &= ~0xf;
384                 // cf/cg silicon needs an 'f' here. 
385                 enables |= 0xf;
386         } else {
387                 enables &= ~0x5;
388         }
389         
390         pci_write_config8(dev1, 0x9, enables);
391         enables = pci_read_config8(dev1, 0x9);
392         printk_debug("enables in reg 0x9 read back as 0x%x\n", enables);
393         
394         // standard bios sets master bit. 
395         enables = pci_read_config8(dev1, 0x4);
396         printk_debug("command in reg 0x4 0x%x\n", enables);
397         enables |= 7;
398         
399         // No need for stepping - kevinh@ispiri.com
400         enables &= ~0x80;
401         
402         pci_write_config8(dev1, 0x4, enables);
403         enables = pci_read_config8(dev1, 0x4);
404         printk_debug("command in reg 0x4 reads back as 0x%x\n", enables);
405         
406         if (! conf->enable_native_ide) {
407                 // Use compatability mode - per award bios
408                 pci_write_config32(dev1, 0x10, 0x0);
409                 pci_write_config32(dev1, 0x14, 0x0);
410                 pci_write_config32(dev1, 0x18, 0x0);
411                 pci_write_config32(dev1, 0x1c, 0x0);
412                 
413                 // Force interrupts to use compat mode - just like Award bios
414                 pci_write_config8(dev1, 0x3d, 00);
415                 pci_write_config8(dev1, 0x3c, 0xff);
416         }
417         
418         
419         /* set up isa bus -- i/o recovery time, rom write enable, extend-ale */
420         pci_write_config8(dev0, 0x40, 0x54);
421         ethernet_fixup();
422         
423         // Start the rtc
424         rtc_init(0);
425 }
426
427 static void southbridge_init(struct chip *chip, enum chip_pass pass)
428 {
429
430         struct southbridge_via_vt8231_config *conf = 
431                 (struct southbridge_via_vt8231_config *)chip->chip_info;
432
433         switch (pass) {
434         case CONF_PASS_PRE_PCI:
435                 vt8231_pci_enable(conf);
436                 break;
437                 
438         case CONF_PASS_POST_PCI:
439                 vt8231_init(conf);
440                 printk_err("FUCK! ROUTING FIXUP!\n");
441                 pci_routing_fixup();
442                 
443                 break;
444         case CONF_PASS_PRE_BOOT:
445                 pci_routing_fixup();
446                 dump_south();
447                 break;
448                 
449         default:
450                 /* nothing yet */
451                 break;
452         }
453 }
454
455 static void enumerate(struct chip *chip)
456 {
457         extern struct device_operations default_pci_ops_bus;
458         chip_enumerate(chip);
459         chip->dev->ops = &default_pci_ops_bus;
460 }
461
462 struct chip_control southbridge_via_vt8231_control = {
463         .enumerate = enumerate,
464         .enable    = southbridge_init,
465         .name      = "VIA vt8231"
466 };