604f34ccfde90a78e9f9b2fa23c23494f5b6bd54
[coreboot.git] / src / mainboard / olpc / rev_a / 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 <arch/io.h>
7 #include <pc80/mc146818rtc.h>
8 #include "chip.h"
9 #include "../southbridge/amd/cs5536/cs5536_smbus2.h"
10
11 /* Borrowed from mc146818rtc.c */
12
13 #define CMOS_READ(addr) ({ \
14                 outb((addr),RTC_PORT(0)); \
15                 inb(RTC_PORT(1)); \
16                 })
17
18 #define CMOS_WRITE(val, addr) ({ \
19                 outb((addr),RTC_PORT(0)); \
20                 outb((val),RTC_PORT(1)); \
21                 })
22
23 static void write_bit(unsigned char val) {
24
25         unsigned char byte = CMOS_READ(440 / 8);
26
27         /* Don't change it if its already set */
28
29         if ((byte & 1) == (val & 1))
30                 return;
31
32         byte &= ~1;
33         byte |= val & 1;
34         CMOS_WRITE(val, 440/8);
35 }
36
37 static unsigned short _getsmbusbase(void) {
38         unsigned devfn = PCI_DEVFN(0xf, 0);
39         device_t dev = dev_find_slot(0x0, devfn);
40         unsigned long addr = pci_read_config32(dev, PCI_BASE_ADDRESS_0);
41
42         return (unsigned short) (addr & ~1);
43 }
44
45 static void init_dcon(void) {
46
47   int ret = 1;
48   unsigned short rev = 0;
49   unsigned short iobase = _getsmbusbase();
50
51   printk_debug("CHECKING FOR DCON (%x)\n", iobase);
52
53   /* Get the IO base for the SMBUS */
54
55   rev = do_smbus_read_word(iobase, 0x0D << 1, 0x00);
56
57   if (rev & 0xDC00) {
58         printk_debug("DCON FOUND - REV %x\n", rev);
59
60         /* Enable the DCON */
61         ret = do_smbus_write_word(iobase, 0x0D << 1, 0x01, 0x0069);
62         if (ret != 0)
63                 printk_debug("DCON ENABLE FAILED\n", ret);
64   }
65   else
66           printk_debug("DCON NOT FOUND (%x)\n", rev);
67
68   write_bit(rev > 0 ? 1 : 0);
69 }
70
71 static void init(struct device *dev) {
72 /*
73         unsigned bus = 0;
74         unsigned devfn = PCI_DEVFN(0xf, 4);
75         device_t usb = NULL;
76         unsigned char usbirq = 0xa;
77 */
78
79         printk_debug("OLPC REVA ENTER %s\n", __func__);
80
81 #if 0
82         /* I can't think of any reason NOT to just set this. If it turns out we want this to be
83           * conditional we can make it a config variable later.
84           */
85
86         printk_debug("%s (%x,%x)SET USB PCI interrupt line to %d\n", 
87                 __func__, bus, devfn, usbirq);
88         usb = dev_find_slot(bus, devfn);
89         if (! usb){
90                 printk_err("Could not find USB\n");
91         } else {
92                 pci_write_config8(usb, PCI_INTERRUPT_LINE, usbirq);
93         }
94 #endif
95
96         init_dcon();
97         printk_debug("OLPC REVA EXIT %s\n", __func__);
98 }
99
100 static void enable_dev(struct device *dev)
101 {
102         dev->ops->init = init;
103 }
104
105 struct chip_operations mainboard_ops = {
106         CHIP_NAME("OLPC rev_a Mainboard")
107         .enable_dev = enable_dev,
108 };