code refromat, doxidization
[coreboot.git] / src / northbridge / amd / amdk8 / northbridge.c
index aed38557d472815c762b4208ae77273ef70de835..8a252d0054db198c679a5b352aff58c35d277c4c 100644 (file)
@@ -5,6 +5,7 @@
 #include <part/sizeram.h>
 #include <device/device.h>
 #include <device/pci.h>
+#include <device/pci_ids.h>
 #include <device/hypertransport.h>
 #include <device/chip.h>
 #include <stdlib.h>
@@ -12,6 +13,7 @@
 #include <bitops.h>
 #include "chip.h"
 #include "northbridge.h"
+#include "amdk8.h"
 
 struct mem_range *sizeram(void)
 {
@@ -36,11 +38,11 @@ struct mem_range *sizeram(void)
        mmio_basek &= ~((256*1024) - 1);
 #endif
 
-#if 1
+#if 0
        printk_debug("mmio_base: %dKB\n", mmio_basek);
 #endif
 
-       for(idx = i = 0; i < 8; i++) {
+       for (idx = i = 0; i < 8; i++) {
                uint32_t base, limit;
                unsigned basek, limitk, sizek;
                base  = pci_read_config32(dev, 0x40 + (i<<3));
@@ -52,17 +54,27 @@ struct mem_range *sizeram(void)
                limitk = ((limit + 0x00010000) & 0xffff0000) >> 2;
                sizek = limitk - basek;
                if ((idx > 0) &&
-                       ((mem[idx -1].basek + mem[idx - 1].sizek) == basek)) {
+                   ((mem[idx - 1].basek + mem[idx - 1].sizek) == basek)) {
                        mem[idx -1].sizek += sizek;
-               }
-               else {
+               } else {
                        mem[idx].basek = basek;
                        mem[idx].sizek = sizek;
                        idx++;
                }
+       
+               /* see if we need a hole from 0xa0000 to 0xbffff */
+               if ((mem[idx-1].basek < ((8*64)+(8*16))) /* 640 */ && 
+                   (mem[idx-1].sizek > ((8*64)+(16*16))) /* 768 */ ) {
+#warning "FIXME: this left 0xA0000 to 0xBFFFF undefined"
+                       mem[idx].basek = (8*64)+(16*16);
+                       mem[idx].sizek = mem[idx-1].sizek - ((8*64)+(16*16));
+                       mem[idx-1].sizek = ((8*64)+(8*16)) - mem[idx-1].basek;
+                       idx++;
+               }       
+               
                /* See if I need to split the region to accomodate pci memory space */
                if ((mem[idx - 1].basek <= mmio_basek) &&
-                       ((mem[idx - 1].basek + mem[idx - 1].sizek) >  mmio_basek)) {
+                   ((mem[idx - 1].basek + mem[idx - 1].sizek) >  mmio_basek)) {
                        if (mem[idx - 1].basek < mmio_basek) {
                                unsigned pre_sizek;
                                pre_sizek = mmio_basek - mem[idx - 1].basek;
@@ -73,20 +85,19 @@ struct mem_range *sizeram(void)
                        }
                        if ((mem[idx - 1].basek + mem[idx - 1].sizek) <= 4*1024*1024) {
                                idx -= 1;
-                       }
-                       else {
+                       } else {
                                mem[idx - 1].basek = 4*1024*1024;
                                mem[idx - 1].sizek -= (4*1024*1024 - mmio_basek);
                        }
                }
        }
-#if 0
-       for(i = 0; i < idx; i++) {
+#if 1
+       for (i = 0; i < idx; i++) {
                printk_debug("mem[%d].basek = %08x mem[%d].sizek = %08x\n",
-                       i, mem[i].basek, i, mem[i].sizek);
+                            i, mem[i].basek, i, mem[i].sizek);
        }
 #endif
-       while(idx < sizeof(mem)/sizeof(mem[0])) {
+       while (idx < sizeof(mem)/sizeof(mem[0])) {
                mem[idx].basek = 0;
                mem[idx].sizek = 0;
                idx++;
@@ -101,12 +112,12 @@ static device_t __f1_dev[F1_DEVS];
 static void debug_f1_devs(void)
 {
        int i;
-       for(i = 0; i < F1_DEVS; i++) {
+       for (i = 0; i < F1_DEVS; i++) {
                device_t dev;
                dev = __f1_dev[i];
                if (dev) {
                        printk_debug("__f1_dev[%d]: %s bus: %p\n",
-                               i, dev_path(dev), dev->bus);
+                                    i, dev_path(dev), dev->bus);
                }
        }
 }
@@ -118,7 +129,7 @@ static void get_f1_devs(void)
        if (__f1_dev[0]) {
                return;
        }
-       for(i = 0; i < F1_DEVS; i++) {
+       for (i = 0; i < F1_DEVS; i++) {
                __f1_dev[i] = dev_find_slot(0, PCI_DEVFN(0x18 + i, 1));
        }
        if (!__f1_dev[0]) {
@@ -136,7 +147,7 @@ static void f1_write_config32(unsigned reg, uint32_t value)
 {
        int i;
        get_f1_devs();
-       for(i = 0; i < F1_DEVS; i++) {
+       for (i = 0; i < F1_DEVS; i++) {
                device_t dev;
                dev = __f1_dev[i];
                if (dev) {
@@ -150,23 +161,21 @@ static unsigned int amdk8_nodeid(device_t dev)
        return (dev->path.u.pci.devfn >> 3) - 0x18;
 }
 
-
-#define LinkConnected     (1 << 0)
-#define InitComplete      (1 << 1)
-#define NonCoherent       (1 << 2)
-#define ConnectionPending (1 << 4)
 static unsigned int amdk8_scan_chains(device_t dev, unsigned int max)
 {
        unsigned nodeid;
        unsigned link;
+
        nodeid = amdk8_nodeid(dev);
+
 #if 1
        printk_debug("amdk8_scan_chains max: %d starting...\n", max);
 #endif
-       for(link = 0; link < dev->links; link++) {
+
+       for (link = 0; link < dev->links; link++) {
                uint32_t link_type;
                uint32_t busses, config_busses;
-               unsigned free_reg, config_reg, other_reg;
+               unsigned free_reg, config_reg;
                dev->link[link].cap = 0x80 + (link *0x20);
                do {
                        link_type = pci_read_config32(dev, dev->link[link].cap + 0x18);
@@ -180,9 +189,10 @@ static unsigned int amdk8_scan_chains(device_t dev, unsigned int max)
                if (!(link_type & NonCoherent)) {
                        continue;
                }
-               /* See if there is an available configuration space mapping register in function 1. */
+               /* See if there is an available configuration space mapping register
+                * in function 1. */
                free_reg = 0;
-               for(config_reg = 0xe0; config_reg <= 0xec; config_reg += 4) {
+               for (config_reg = 0xe0; config_reg <= 0xec; config_reg += 4) {
                        uint32_t config;
                        config = f1_read_config32(config_reg);
                        if (!free_reg && ((config & 3) == 0)) {
@@ -190,22 +200,23 @@ static unsigned int amdk8_scan_chains(device_t dev, unsigned int max)
                                continue;
                        }
                        if (((config & 3) == 3) && 
-                               (((config >> 4) & 7) == nodeid) &&
-                               (((config >> 8) & 3) == link)) {
+                           (((config >> 4) & 7) == nodeid) &&
+                           (((config >> 8) & 3) == link)) {
                                break;
                        }
                }
                if (free_reg && (config_reg > 0xec)) {
                        config_reg = free_reg;
                }
-               /* If we can't find an available configuration space mapping register skip this bus */
+               /* If we can't find an available configuration space mapping
+                * register skip this bus */
                if (config_reg > 0xec) {
                        continue;
                }
 
-               /* Set up the primary, secondary and subordinate bus numbers.  We have
-                * no idea how many busses are behind this bridge yet, so we set the subordinate
-                * bus number to 0xff for the moment.
+               /* Set up the primary, secondary and subordinate bus numbers.
+                * We have no idea how many busses are behind this bridge yet,
+                * so we set the subordinate bus number to 0xff for the moment.
                 */
                dev->link[link].secondary = ++max;
                dev->link[link].subordinate = 0xff;
@@ -217,8 +228,8 @@ static unsigned int amdk8_scan_chains(device_t dev, unsigned int max)
                config_busses = f1_read_config32(config_reg);
                
                /* Configure the bus numbers for this bridge: the configuration
-                * transactions will not be propagates by the bridge if it is not
-                * correctly configured
+                * transactions will not be propagates by the bridge if it is
+                * not correctly configured
                 */
                busses &= 0xff000000;
                busses |= (((unsigned int)(dev->bus->secondary) << 0) |
@@ -226,30 +237,39 @@ static unsigned int amdk8_scan_chains(device_t dev, unsigned int max)
                        ((unsigned int)(dev->link[link].subordinate) << 16));
                pci_write_config32(dev, dev->link[link].cap + 0x14, busses);
 
-               config_busses &= 0x0000ffff;
-               config_busses |= ((dev->link[link].secondary) << 16) |
+               config_busses &= 0x000fc88;
+               config_busses |= 
+                       (3 << 0) |  /* rw enable, no device compare */
+                       (( nodeid & 7) << 4) | 
+                       (( link & 3 ) << 8) |  
+                       ((dev->link[link].secondary) << 16) |
                        ((dev->link[link].subordinate) << 24);
                f1_write_config32(config_reg, config_busses);
 
 #if 1
-               printk_debug("Hyper transport scan link: %d max: %d\n", link, max);
-#endif         
-               /* Now we can scan all of the subordinate busses i.e. the chain on the hypertranport link */
+               printk_debug("Hyper transport scan link: %d max: %d\n",
+                            link, max);
+#endif
+
+               /* Now we can scan all of the subordinate busses i.e. the
+                * chain on the hypertranport link */
                max = hypertransport_scan_chain(&dev->link[link], max);
 
 #if 1
-               printk_debug("Hyper transport scan link: %d new max: %d\n", link, max);
+               printk_debug("Hyper transport scan link: %d new max: %d\n",
+                            link, max);
 #endif         
 
-               /* We know the number of busses behind this bridge.  Set the subordinate
-                * bus number to it's real value
+               /* We know the number of busses behind this bridge.  Set the
+                * subordinate bus number to it's real value
                 */
                dev->link[link].subordinate = max;
                busses = (busses & 0xff00ffff) |
                        ((unsigned int) (dev->link[link].subordinate) << 16);
                pci_write_config32(dev, dev->link[link].cap + 0x14, busses);
 
-               config_busses = (config_busses & 0x00ffffff) | (dev->link[link].subordinate << 24);
+               config_busses = (config_busses & 0x00ffffff) |
+                       (dev->link[link].subordinate << 24);
                f1_write_config32(config_reg, config_busses);
 #if 1
                printk_debug("Hypertransport scan link done\n");
@@ -261,13 +281,12 @@ static unsigned int amdk8_scan_chains(device_t dev, unsigned int max)
        return max;
 }
 
-
 static unsigned amdk8_find_iopair(unsigned nodeid, unsigned link)
 {
        unsigned free_reg, reg;
 
        free_reg = 0;
-       for(reg = 0xc0; reg <= 0xd8; reg += 0x8) {
+       for (reg = 0xc0; reg <= 0xd8; reg += 0x8) {
                uint32_t base, limit;
                base  = f1_read_config32(reg);
                limit = f1_read_config32(reg + 0x4);
@@ -277,8 +296,8 @@ static unsigned amdk8_find_iopair(unsigned nodeid, unsigned link)
                }
                /* Do I have a match for this node and link? */
                if (((base & 3) == 3) &&
-                       ((limit & 3) == nodeid) &&
-                       (((limit >> 4) & 3) == link)) {
+                   ((limit & 7) == nodeid) &&
+                   (((limit >> 4) & 3) == link)) {
                        break;
                }
        }
@@ -293,8 +312,9 @@ static unsigned amdk8_find_iopair(unsigned nodeid, unsigned link)
 static unsigned amdk8_find_mempair(unsigned nodeid, unsigned link)
 {
        unsigned free_reg, reg;
+
        free_reg = 0;
-       for(reg = 0x80; reg <= 0xb8; reg += 0x8) {
+       for (reg = 0x80; reg <= 0xb8; reg += 0x8) {
                uint32_t base, limit;
                base  = f1_read_config32(reg);
                limit = f1_read_config32(reg + 0x4);
@@ -304,7 +324,7 @@ static unsigned amdk8_find_mempair(unsigned nodeid, unsigned link)
                }
                /* Do I have a match for this node and link? */
                if (((base & 3) == 3) &&
-                       ((limit & 3) == nodeid) &&
+                       ((limit & 7) == nodeid) &&
                        (((limit >> 4) & 3) == link)) {
                        break;
                }
@@ -333,7 +353,7 @@ static void amdk8_link_read_bases(device_t dev, unsigned nodeid, unsigned link)
                dev->resource[reg].flags = IORESOURCE_IO;
                dev->resource[reg].index = index | (link & 0x3);
                compute_allocate_resource(&dev->link[link], &dev->resource[reg], 
-                       IORESOURCE_IO, IORESOURCE_IO);
+                                         IORESOURCE_IO, IORESOURCE_IO);
                reg++;
        }
 
@@ -348,7 +368,7 @@ static void amdk8_link_read_bases(device_t dev, unsigned nodeid, unsigned link)
                dev->resource[reg].flags = IORESOURCE_MEM;
                dev->resource[reg].index = index | (link & 0x3);
                compute_allocate_resource(&dev->link[link], &dev->resource[reg], 
-                       IORESOURCE_MEM, IORESOURCE_MEM);
+                                         IORESOURCE_MEM, IORESOURCE_MEM);
                reg++;
        }
        dev->resources = reg;
@@ -360,19 +380,26 @@ static void amdk8_read_resources(device_t dev)
        nodeid = amdk8_nodeid(dev);
        dev->resources = 0;
        memset(&dev->resource, 0, sizeof(dev->resource));
-       for(link = 0; link < dev->links; link++) {
+       for (link = 0; link < dev->links; link++) {
                if (dev->link[link].children) {
                        amdk8_link_read_bases(dev, nodeid, link);
                }
        }
 }
 
-static void amdk8_set_resource(device_t dev, struct resource *resource, unsigned nodeid)
+static void amdk8_set_resource(device_t dev, struct resource *resource,
+                              unsigned nodeid)
 {
        unsigned long rbase, rlimit;
        unsigned reg, link;
+
        /* Make certain the resource has actually been set */
-       if (!(resource->flags & IORESOURCE_SET)) {
+       if (!(resource->flags & IORESOURCE_ASSIGNED)) {
+               return;
+       }
+
+       /* If I have already stored this resource don't worry about it */
+       if (resource->flags & IORESOURCE_STORED) {
                return;
        }
        
@@ -384,16 +411,17 @@ static void amdk8_set_resource(device_t dev, struct resource *resource, unsigned
        rbase = resource->base;
        
        /* Get the limit (rounded up) */
-       rlimit = rbase + ((resource->size + resource->align - 1UL) & ~(resource->align -1)) - 1UL;
+       rlimit = rbase + ((resource->size + resource->align - 1UL) &
+                         ~(resource->align -1)) - 1UL;
 
        /* Get the register and link */
        reg  = resource->index & ~3;
        link = resource->index & 3;
-       
+
        if (resource->flags & IORESOURCE_IO) {
                uint32_t base, limit;
                compute_allocate_resource(&dev->link[link], resource,
-                       IORESOURCE_IO, IORESOURCE_IO);
+                                         IORESOURCE_IO, IORESOURCE_IO);
                base  = f1_read_config32(reg);
                limit = f1_read_config32(reg + 0x4);
                base  &= 0xfe000fcc;
@@ -402,14 +430,21 @@ static void amdk8_set_resource(device_t dev, struct resource *resource, unsigned
                limit &= 0xfe000fc8;
                limit |= rlimit & 0x01fff000;
                limit |= (link & 3) << 4;
-               limit |= (nodeid & 3);
+               limit |= (nodeid & 7);
+
+               if (dev->link[link].bridge_ctrl & PCI_BRIDGE_CTL_VGA) {
+                       base |= PCI_IO_BASE_VGA_EN;
+               }
+               if (dev->link[link].bridge_ctrl & PCI_BRIDGE_CTL_NO_ISA) {
+                       base |= PCI_IO_BASE_NO_ISA;
+               }
+               
                f1_write_config32(reg + 0x4, limit);
                f1_write_config32(reg, base);
-       }
-       else if (resource->flags & IORESOURCE_MEM) {
+       } else if (resource->flags & IORESOURCE_MEM) {
                uint32_t base, limit;
                compute_allocate_resource(&dev->link[link], resource,
-                       IORESOURCE_MEM, IORESOURCE_MEM);
+                                         IORESOURCE_MEM, IORESOURCE_MEM);
                base  = f1_read_config32(reg);
                limit = f1_read_config32(reg + 0x4);
                base  &= 0x000000f0;
@@ -418,17 +453,14 @@ static void amdk8_set_resource(device_t dev, struct resource *resource, unsigned
                limit &= 0x00000048;
                limit |= (rlimit & 0xffff0000) >> 8;
                limit |= (link & 3) << 4;
-               limit |= (nodeid & 3);
+               limit |= (nodeid & 7);
                f1_write_config32(reg + 0x4, limit);
                f1_write_config32(reg, base);
        }
-       printk_debug(
-               "%s %02x <- [0x%08lx - 0x%08lx] node %d link %d %s\n",
-               dev_path(dev),
-               reg, 
-               rbase, rlimit,
-               nodeid, link,
-               (resource->flags & IORESOURCE_IO)? "io": "mem");
+       resource->flags |= IORESOURCE_STORED;
+       printk_debug("%s %02x <- [0x%08lx - 0x%08lx] node %d link %d %s\n",
+                    dev_path(dev), reg, rbase, rlimit, nodeid, link,
+                    (resource->flags & IORESOURCE_IO)? "io": "mem");
 }
 
 static void amdk8_set_resources(device_t dev)
@@ -440,11 +472,11 @@ static void amdk8_set_resources(device_t dev)
        nodeid = amdk8_nodeid(dev);     
 
        /* Set each resource we have found */
-       for(i = 0; i < dev->resources; i++) {
+       for (i = 0; i < dev->resources; i++) {
                amdk8_set_resource(dev, &dev->resource[i], nodeid);
        }
-       
-       for(link = 0; link < dev->links; link++) {
+
+       for (link = 0; link < dev->links; link++) {
                struct bus *bus;
                bus = &dev->link[link];
                if (bus->children) {
@@ -453,26 +485,113 @@ static void amdk8_set_resources(device_t dev)
        }
 }
 
+/**
+ * @brief Scan root bus for AMD K8 systems
+ *
+ * @param root the root device structure
+ * @max the current bus number scanned so far, usually 0x00
+ *
+ * The root device in a AMD K8 system is not at Bus 0, Device 0, Fun 0
+ * as other PCI based systems. The northbridge is at Bus 0, Device 0x18,
+ * Fun 0. We have to call the pci_scan_bus() with PCI_DEVFN(0x18,0) as
+ * the starting device instead of PCI_DEVFN(0x0, 0) as in the default
+ * root_dev_scan_pci_bus().
+ *
+ * This function is set up as the default scan_bus() method for mainboards'
+ * device_operations for AMD K8 mainboards in mainboard.c
+ *
+ * @see device_operation()
+ * @see root_dev_scan_pci_bus()
+ */
 unsigned int amdk8_scan_root_bus(device_t root, unsigned int max)
 {
        unsigned reg;
-       max = pci_scan_bus(&root->link[0], PCI_DEVFN(0x18, 0), 0xff, max);
-       /* Unmap all of the other pci busses */
-       for(reg = 0xe0; reg <= 0xec; reg += 4) {
+
+       printk_debug("amdk8_scan_root_bus\n");
+
+       /* Unmap all of the HT chains */
+       for (reg = 0xe0; reg <= 0xec; reg += 4) {
                f1_write_config32(reg, 0);
        }
+
+       printk_debug("amdk8_scan_root_bus: start scaning pci bus\n");
+       max = pci_scan_bus(&root->link[0], PCI_DEVFN(0x18, 0), 0xff, max);
+
+       printk_debug("amdk8_scan_root_bus: done\n");
        return max;
 }
 
+static void mcf0_control_init(struct device *dev)
+{
+       uint32_t cmd;
+
+#if 1  
+       printk_debug("NB: Function 0 Misc Control.. ");
+       /* improve latency and bandwith on HT */
+       cmd = pci_read_config32(dev, 0x68);
+       cmd &= 0xffff80ff;
+       cmd |= 0x00004800;
+       pci_write_config32(dev, 0x68, cmd );
+#endif
+
+#if 0  
+       /* over drive the ht port to 1000 Mhz */
+       cmd = pci_read_config32(dev, 0xa8);
+       cmd &= 0xfffff0ff;
+       cmd |= 0x00000600;
+       pci_write_config32(dev, 0xdc, cmd );
+#endif 
+       printk_debug("done.\n");
+}
+
+
+static void amdk8_enable_resources(struct device *dev)
+{
+       uint16_t ctrl;
+       unsigned link;
+       unsigned int vgalink = -1;
+
+       ctrl = pci_read_config16(dev, PCI_BRIDGE_CONTROL);
+       ctrl |= dev->link[0].bridge_ctrl;
+       printk_debug("%s bridge ctrl <- %04x\n", dev_path(dev), ctrl);
+       pci_write_config16(dev, PCI_BRIDGE_CONTROL, ctrl);
+
+#if 0
+       /* let's see what link VGA is on */
+       for (link = 0; link < dev->links; link++) {
+               device_t child;
+               printk_err("Kid %d of k8: bridge ctrl says: 0x%x\n",
+                          link, dev->link[link].bridge_ctrl);
+               if (dev->link[link].bridge_ctrl & PCI_BRIDGE_CTL_VGA)
+                       vgalink = link;
+       }
+
+       if (vgalink != 1) {
+               /* now find the IOPAIR that goes to vgalink and set the vga
+                * enable in the base part (0x30) */
+               /* now allocate an MMIOPAIR and point it to the CPU0,
+                * LINK=vgalink */
+               /* now set IORR1 so it has a hole for the 0xa0000-0xcffff
+                * region */
+       }
+#endif
+       pci_dev_enable_resources(dev);
+}
+
 static struct device_operations northbridge_operations = {
        .read_resources   = amdk8_read_resources,
        .set_resources    = amdk8_set_resources,
        .enable_resources = pci_dev_enable_resources,
-       .init             = 0,
+       .init             = mcf0_control_init,
        .scan_bus         = amdk8_scan_chains,
        .enable           = 0,
 };
 
+static struct pci_driver mcf0_driver __pci_driver = {
+       .ops    = &northbridge_operations,
+       .vendor = PCI_VENDOR_ID_AMD,
+       .device = 0x1100,
+};
 
 static void enumerate(struct chip *chip)
 {