- 1.1.4
authorEric Biederman <ebiederm@xmission.com>
Tue, 2 Sep 2003 17:16:48 +0000 (17:16 +0000)
committerEric Biederman <ebiederm@xmission.com>
Tue, 2 Sep 2003 17:16:48 +0000 (17:16 +0000)
  Major restructuring of hypertransport handling.
  Major rewerite of superio/NSC/pc87360 as a proof of concept for handling superio resources dynamically
  Updates to hard_reset handling when resetting because of the need to change hypertransport link
    speeds and widths.
    (a) No longer assume the boot is good just because we get to a hard reset point.
    (b) Set a flag to indicate that the BIOS triggered the reset so we don't decrement the
       boot counter.
  Updates to arima/hdama mptable so it tracks the new bus numbers

git-svn-id: svn://svn.coreboot.org/coreboot/trunk@1097 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1

17 files changed:
NEWS
src/config/Options.lb
src/devices/Config.lb
src/devices/hypertransport.c [new file with mode: 0644]
src/devices/pci_device.c
src/include/device/device.h
src/include/device/hypertransport.h [new file with mode: 0644]
src/mainboard/arima/hdama/Config.lb
src/mainboard/arima/hdama/mainboard.c
src/mainboard/arima/hdama/mptable.c
src/northbridge/amd/amdk8/Config.lb
src/northbridge/amd/amdk8/chip.h [new file with mode: 0644]
src/northbridge/amd/amdk8/misc_control.c [new file with mode: 0644]
src/northbridge/amd/amdk8/northbridge.c
src/northbridge/amd/amdk8/northbridge.h [new file with mode: 0644]
src/northbridge/amd/amdk8/reset_test.c
src/superio/NSC/pc87360/superio.c

diff --git a/NEWS b/NEWS
index 07f3326d34dd140aebe292d41a20159612ccd89c..1e2feb71d22285f7314024f0ecae1c1d1c7d9b09 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,12 @@
+- 1.1.4
+  Major restructuring of hypertransport handling.
+  Major rewerite of superio/NSC/pc87360 as a proof of concept for handling superio resources dynamically
+  Updates to hard_reset handling when resetting because of the need to change hypertransport link
+    speeds and widths. 
+    (a) No longer assume the boot is good just because we get to a hard reset point.
+    (b) Set a flag to indicate that the BIOS triggered the reset so we don't decrement the
+        boot counter.
+  Updates to arima/hdama mptable so it tracks the new bus numbers
 - 1.1.3
   Major update of the dyanmic device tree to so it can handle
   * subtractive resources
index 9073ae340b527bc2fc987a9a2a477a430426c837..aae29108ea677a84172c351f9897db310b111f13 100644 (file)
@@ -117,7 +117,7 @@ define OBJCOPY
        comment "Objcopy command"
 end
 define LINUXBIOS_VERSION
-       default "1.1.3"
+       default "1.1.4"
        export always
        comment "LinuxBIOS version"
 end
index 063aa1db92398c4ebff93827d22d5b6cf4760127..6da04ee2e4b3fd82cbcb3a5228d0961a00545950 100644 (file)
@@ -2,4 +2,5 @@ object device.o
 object root_device.o
 object device_util.o
 object pci_device.o
+object hypertransport.o
 object chip.o
diff --git a/src/devices/hypertransport.c b/src/devices/hypertransport.c
new file mode 100644 (file)
index 0000000..26cd237
--- /dev/null
@@ -0,0 +1,319 @@
+#include <bitops.h>
+#include <console/console.h>
+#include <device/device.h>
+#include <device/path.h>
+#include <device/pci.h>
+#include <part/hard_reset.h>
+#include <part/fallback_boot.h>
+
+static device_t ht_scan_get_devs(device_t *old_devices)
+{
+       device_t first, last;
+       first = *old_devices;
+       last = first;
+       while(last && last->sibling && 
+               (last->sibling->path.u.pci.devfn > last->path.u.pci.devfn)) {
+               last = last->sibling;
+       }
+       if (first) {
+               *old_devices = last->sibling;
+               last->sibling = 0;
+       }
+       return first;
+}
+
+
+struct prev_link {
+       struct device *dev;
+       unsigned pos;
+       unsigned char config_off, freq_off, freq_cap_off;
+};
+
+static int ht_setup_link(struct prev_link *prev, device_t dev, unsigned pos)
+{
+       static const uint8_t link_width_to_pow2[]= { 3, 4, 0, 5, 1, 2, 0, 0 };
+       static const uint8_t pow2_to_link_width[] = { 0x7, 4, 5, 0, 1, 3 };
+       unsigned present_width_cap,    upstream_width_cap;
+       unsigned present_freq_cap,     upstream_freq_cap;
+       unsigned ln_present_width_in,  ln_upstream_width_in; 
+       unsigned ln_present_width_out, ln_upstream_width_out;
+       unsigned freq, old_freq;
+       unsigned present_width, upstream_width, old_width;
+       int reset_needed;
+
+       /* Set the hypertransport link width and frequency */
+       reset_needed = 0;
+
+       /* Read the capabilities */
+       present_freq_cap   = pci_read_config16(dev, pos + PCI_HT_CAP_SLAVE_FREQ_CAP0);
+       upstream_freq_cap  = pci_read_config16(prev->dev, prev->pos + prev->freq_cap_off);
+       present_width_cap  = pci_read_config8(dev, pos + PCI_HT_CAP_SLAVE_WIDTH0);
+       upstream_width_cap = pci_read_config8(prev->dev, prev->pos + prev->config_off);
+       
+       /* Calculate the highest useable frequency */
+#if 0
+       freq = log2(present_freq_cap & upstream_freq_cap);
+#else
+       /* Errata for 8131 - freq 5 has hardware problems don't support it */
+       freq = log2(present_freq_cap & upstream_freq_cap & 0x1f);
+#endif
+
+       /* Calculate the highest width */
+       ln_upstream_width_in = link_width_to_pow2[upstream_width_cap & 7];
+       ln_present_width_out = link_width_to_pow2[(present_width_cap >> 4) & 7];
+       if (ln_upstream_width_in > ln_present_width_out) {
+               ln_upstream_width_in = ln_present_width_out;
+       }
+       upstream_width = pow2_to_link_width[ln_upstream_width_in];
+       present_width  = pow2_to_link_width[ln_upstream_width_in] << 4;
+
+       ln_upstream_width_out = link_width_to_pow2[(upstream_width_cap >> 4) & 7];
+       ln_present_width_in   = link_width_to_pow2[present_width_cap & 7];
+       if (ln_upstream_width_out > ln_present_width_in) {
+               ln_upstream_width_out = ln_present_width_in;
+       }
+       upstream_width |= pow2_to_link_width[ln_upstream_width_out] << 4;
+       present_width  |= pow2_to_link_width[ln_upstream_width_out];
+
+       /* Set the current device */
+       old_freq = pci_read_config8(dev, pos + PCI_HT_CAP_SLAVE_FREQ0);
+       if (freq != old_freq) {
+               pci_write_config8(dev, pos + PCI_HT_CAP_SLAVE_FREQ0, freq);
+               reset_needed = 1;
+               printk_spew("HyperT FreqP old %x new %x\n",old_freq,freq);
+       }
+       old_width = pci_read_config8(dev, pos + PCI_HT_CAP_SLAVE_WIDTH0 + 1);
+       if (present_width != old_width) {
+               pci_write_config8(dev, pos + PCI_HT_CAP_SLAVE_WIDTH0 + 1, present_width);
+               reset_needed = 1;
+               printk_spew("HyperT widthP old %x new %x\n",old_width, present_width);
+       }
+
+       /* Set the upstream device */
+       old_freq = pci_read_config8(prev->dev, prev->pos + prev->freq_off);
+       old_freq &= 0x0f;
+       if (freq != old_freq) {
+               pci_write_config8(prev->dev, prev->pos + prev->freq_off, freq);
+               reset_needed = 1;
+               printk_spew("HyperT freqU old %x new %x\n", old_freq, freq);
+       }
+       old_width = pci_read_config8(prev->dev, prev->pos + prev->config_off + 1);
+       if (upstream_width != old_width) {
+               pci_write_config8(prev->dev, prev->pos + prev->config_off + 1, upstream_width);
+               reset_needed = 1;
+               printk_spew("HyperT widthU old %x new %x\n", old_width, upstream_width);
+       }
+       
+       /* Remember the current link as the previous link */
+       prev->dev = dev;
+       prev->pos = pos;
+       prev->config_off   = PCI_HT_CAP_SLAVE_WIDTH1;
+       prev->freq_off     = PCI_HT_CAP_SLAVE_FREQ1;
+       prev->freq_cap_off = PCI_HT_CAP_SLAVE_FREQ_CAP1;
+
+       return reset_needed;
+               
+}
+
+static unsigned ht_lookup_slave_capability(struct device *dev)
+{
+       unsigned pos;
+       pos = 0;
+       switch(dev->hdr_type & 0x7f) {
+       case PCI_HEADER_TYPE_NORMAL:
+       case PCI_HEADER_TYPE_BRIDGE:
+               pos = PCI_CAPABILITY_LIST;
+               break;
+       }
+       if (pos > PCI_CAP_LIST_NEXT) {
+               pos = pci_read_config8(dev, pos);
+       }
+       while(pos != 0) {   /* loop through the linked list */
+               uint8_t cap;
+               cap = pci_read_config8(dev, pos + PCI_CAP_LIST_ID);
+               printk_spew("Capability: 0x%02x @ 0x%02x\n", cap, pos);
+               if (cap == PCI_CAP_ID_HT) {
+                       unsigned flags;
+                       flags = pci_read_config16(dev, pos + PCI_CAP_FLAGS);
+                       printk_spew("flags: 0x%04x\n", (unsigned)flags);
+                       if ((flags >> 13) == 0) {
+                               /* Entry is a Slave secondary, success...*/
+                               break;
+                       }
+               }
+               if(pos) {
+                       pos = pci_read_config8(dev, pos + PCI_CAP_LIST_NEXT);
+               }
+       }
+       return pos;
+}
+
+static void ht_collapse_early_enumeration(struct bus *bus)
+{
+       unsigned int devfn;
+
+       /* Spin through the devices and collapse any early
+        * hypertransport enumeration.
+        */
+       for(devfn = 0; devfn <= 0xff; devfn += 8) {
+               struct device dummy;
+               uint32_t id;
+               unsigned pos, flags;
+               dummy.bus              = bus;
+               dummy.path.type        = DEVICE_PATH_PCI;
+               dummy.path.u.pci.devfn = devfn;
+               id = pci_read_config32(&dummy, PCI_VENDOR_ID);
+               if (id == 0xffffffff || id == 0x00000000 || 
+                       id == 0x0000ffff || id == 0xffff0000) {
+                       continue;
+               }
+               dummy.vendor = id & 0xffff;
+               dummy.device = (id >> 16) & 0xffff;
+               dummy.hdr_type = pci_read_config8(&dummy, PCI_HEADER_TYPE);
+               pos = ht_lookup_slave_capability(&dummy);
+               if (!pos){
+                       continue;
+               }
+
+               /* Clear the unitid */
+               flags = pci_read_config16(&dummy, pos + PCI_CAP_FLAGS);
+               flags &= ~0x1f;
+               pci_write_config16(&dummy, pos + PCI_CAP_FLAGS, flags);
+               printk_spew("Collapsing %s [%04x/%04x]\n", 
+                       dev_path(&dummy), dummy.vendor, dummy.device);
+       }
+}
+
+unsigned int hypertransport_scan_chain(struct bus *bus, unsigned int max)
+{
+       unsigned next_unitid, last_unitid, previous_unitid;
+       uint8_t previous_pos;
+       device_t old_devices, dev, func, *chain_last;
+       unsigned min_unitid = 1;
+       int reset_needed;
+       struct prev_link prev;
+
+       /* Restore the hypertransport chain to it's unitialized state */
+       ht_collapse_early_enumeration(bus);
+
+       /* See which static device nodes I have */
+       old_devices = bus->children;
+       bus->children = 0;
+       chain_last = &bus->children;
+
+       /* Initialize the hypertransport enumeration state */
+       reset_needed = 0;
+       prev.dev = bus->dev;
+       prev.pos = bus->cap;
+       prev.config_off   = PCI_HT_CAP_HOST_WIDTH;
+       prev.freq_off     = PCI_HT_CAP_HOST_FREQ;
+       prev.freq_cap_off = PCI_HT_CAP_HOST_FREQ_CAP;
+       
+       /* If present assign unitid to a hypertransport chain */
+       last_unitid = min_unitid -1;
+       next_unitid = min_unitid;
+       previous_pos = 0;
+       do {
+               uint32_t id, class;
+               uint8_t hdr_type, pos;
+               uint16_t flags;
+               unsigned count, static_count;
+
+               previous_unitid = last_unitid;
+               last_unitid = next_unitid;
+
+               /* Get setup the device_structure */
+               dev = ht_scan_get_devs(&old_devices);
+
+               if (!dev) {
+                       struct device dummy;
+                       dummy.bus              = bus;
+                       dummy.path.type        = DEVICE_PATH_PCI;
+                       dummy.path.u.pci.devfn = 0;
+                       id = pci_read_config32(&dummy, PCI_VENDOR_ID);
+                       /* If the chain is fully enumerated quit */
+                       if (id == 0xffffffff || id == 0x00000000 ||
+                               id == 0x0000ffff || id == 0xffff0000) {
+                               break;
+                       }
+                       dev = alloc_dev(bus, &dummy.path);
+               }
+               else {
+                       /* Add this device to the pci bus chain */
+                       *chain_last = dev;
+                       /* Run the magice enable/disable sequence for the device */
+                       if (dev->ops && dev->ops->enable) {
+                               dev->ops->enable(dev);
+                       }
+                       /* Now read the vendor and device id */
+                       id = pci_read_config32(dev, PCI_VENDOR_ID);
+               }
+               /* Update the device chain tail */
+               for(func = dev; func; func = func->sibling) {
+                       chain_last = &func->sibling;
+               }
+               
+               /* Read the rest of the pci configuration information */
+               hdr_type = pci_read_config8(dev, PCI_HEADER_TYPE);
+               class = pci_read_config32(dev, PCI_CLASS_REVISION);
+               
+               /* Store the interesting information in the device structure */
+               dev->vendor = id & 0xffff;
+               dev->device = (id >> 16) & 0xffff;
+               dev->hdr_type = hdr_type;
+               /* class code, the upper 3 bytes of PCI_CLASS_REVISION */
+               dev->class = class >> 8;
+
+               /* Find the hypertransport link capability */
+               pos = ht_lookup_slave_capability(dev);
+               if (pos == 0) {
+                       printk_err("Hypertransport link capability not found");
+                       break;
+               }
+               
+               /* Update the Unitid of the current device */
+               flags = pci_read_config16(dev, pos + PCI_CAP_FLAGS);
+               flags &= ~0x1f; /* mask out base Unit ID */
+               flags |= next_unitid & 0x1f;
+               pci_write_config16(dev, pos + PCI_CAP_FLAGS, flags);
+
+               /* Update the Unitd id in the device structure */
+               static_count = 1;
+               for(func = dev; func; func = func->sibling) {
+                       func->path.u.pci.devfn += (next_unitid << 3);
+                       static_count = (func->path.u.pci.devfn >> 3) 
+                               - (dev->path.u.pci.devfn >> 3) + 1;
+               }
+
+               /* Compute the number of unitids consumed */
+               count = (flags >> 5) & 0x1f; /* get unit count */
+               printk_spew("%s count: %04x static_count: %04x\n", 
+                       dev_path(dev), count, static_count);
+               if (count < static_count) {
+                       count = static_count;
+               }
+
+               /* Update the Unitid of the next device */
+               next_unitid += count;
+
+               /* Setup the hypetransport link */
+               reset_needed |= ht_setup_link(&prev, dev, pos);
+
+               printk_debug("%s [%04x/%04x] %s next_unitid: %04x\n",
+                       dev_path(dev),
+                       dev->vendor, dev->device, 
+                       (dev->enable? "enabled": "disabled"), next_unitid);
+
+       } while((last_unitid != next_unitid) && (next_unitid <= 0x1f));
+#if HAVE_HARD_RESET == 1
+       if(reset_needed) {
+               printk_info("HyperT reset needed\n");
+               hard_reset();
+       }
+       printk_debug("HyperT reset not needed\n");
+#endif
+       if (next_unitid > 0x1f) {
+               next_unitid = 0x1f;
+       }
+       return pci_scan_bus(bus, 0x00, (next_unitid << 3)|7, max);
+}
index 4db01027459996a53e8502762cf0dd28ac1a57dd..c387f3569fef9688cf250bc0a8501d4b84e5d323 100644 (file)
@@ -496,163 +496,6 @@ static struct device *pci_scan_get_dev(struct device **list, unsigned int devfn)
        return dev;
 }
 
-void assign_id_set_links(device_t dev, uint8_t *pos, 
-               uint8_t *previous_pos, unsigned previous_unitid,
-               unsigned last_unitid, int *reset_needed,
-               struct device *bus, unsigned *next_unitid)
-{
-       static const uint8_t link_width_to_pow2[]= { 3, 4, 0, 5, 1, 2, 0, 0 };
-       static const uint8_t pow2_to_link_width[] = { 0x7, 4, 5, 0, 1, 3 };
-       uint16_t flags;
-       struct bus prev_bus;
-       struct device last, previous;
-       unsigned count;
-       uint8_t present_width_cap;
-       uint16_t present_freq_cap;
-       uint8_t upstream_width_cap;
-       uint16_t upstream_freq_cap;
-       uint8_t ln_upstream_width_in, ln_present_width_in;
-       uint8_t ln_upstream_width_out, ln_present_width_out;
-       uint16_t mask;
-       uint8_t freq;
-       uint8_t old_freq;
-       uint8_t upstream_width, present_width;
-       uint8_t old_width;
-
-       flags = pci_read_config16(dev, (*pos) + PCI_CAP_FLAGS);
-       printk_debug("flags: 0x%04x\n", (unsigned)flags);
-       if ((flags >> 13) != 0)
-                       return; /* Entry is a Host */
-       /* Entry is a Slave secondary */
-       flags &= ~0x1f; /* mask out base unit ID */
-       flags |= *next_unitid & 0x1f; /* assign ID */
-       count = (flags >> 5) & 0x1f; /* get unit count */
-       printk_debug("unitid: 0x%02x, count: 0x%02x\n",
-               *next_unitid, count);
-       pci_write_config16(dev, (*pos) + PCI_CAP_FLAGS, flags);
-       *next_unitid += count;
-       if (previous_unitid == 0) { /* the link is back to the host */
-               prev_bus.secondary = 0;
-               /* calculate the previous pos for the host */
-               *previous_pos = 0x80;
-               previous.bus = &prev_bus;
-               previous.path.type        = DEVICE_PATH_PCI;
-               previous.path.u.pci.devfn = 0x18 << 3;
-       #warning "FIXME we should not hard code this!"
-       } else {
-               previous.bus              = bus;
-               previous.path.type        = DEVICE_PATH_PCI;
-               previous.path.u.pci.devfn = previous_unitid << 3;
-       }
-       last.bus              = bus;
-       last.path.type        = DEVICE_PATH_PCI;
-       last.path.u.pci.devfn = last_unitid << 3;
-       /* Set link width and frequency */
-       present_freq_cap = pci_read_config16(&last, 
-                       (*pos) + PCI_HT_CAP_SLAVE_FREQ_CAP0);
-       present_width_cap = pci_read_config8(&last, 
-                       (*pos) + PCI_HT_CAP_SLAVE_WIDTH0);
-       if(previous_unitid == 0) { /* the link is back to the host */
-               upstream_freq_cap = pci_read_config16(&previous, 
-                           (*previous_pos) + PCI_HT_CAP_HOST_FREQ_CAP);
-               upstream_width_cap = pci_read_config8(&previous, 
-                           (*previous_pos) + PCI_HT_CAP_HOST_WIDTH);
-       }
-       else { /* The link is back up the chain */
-               upstream_freq_cap = pci_read_config16(&previous, 
-                       (*previous_pos) + PCI_HT_CAP_SLAVE_FREQ_CAP1);
-               upstream_width_cap = pci_read_config8(&previous, 
-                       (*previous_pos) + PCI_HT_CAP_SLAVE_WIDTH1);
-       }
-       /* Calculate the highest possible frequency */
-       /* Errata for 8131 - freq 5 has hardware problems don't support it */
-       freq = log2(present_freq_cap & upstream_freq_cap & 0x1f);
-
-       /* Calculate the highest width */
-       ln_upstream_width_in = link_width_to_pow2[upstream_width_cap & 7];
-       ln_present_width_out  = link_width_to_pow2[(present_width_cap >> 4) & 7]; 
-       if (ln_upstream_width_in > ln_present_width_out) {
-               ln_upstream_width_in = ln_present_width_out;
-       }
-       upstream_width = pow2_to_link_width[ln_upstream_width_in];
-       present_width  = pow2_to_link_width[ln_upstream_width_in] << 4;
-
-       ln_upstream_width_out = link_width_to_pow2[(upstream_width_cap >> 4) & 7];
-       ln_present_width_in   = link_width_to_pow2[present_width_cap & 7];
-       if (ln_upstream_width_out > ln_present_width_in) {
-               ln_upstream_width_out = ln_present_width_in;
-       }
-       upstream_width |= pow2_to_link_width[ln_upstream_width_out] << 4;
-       present_width  |= pow2_to_link_width[ln_upstream_width_out];
-       
-       /* set the present device */
-       old_freq = pci_read_config8(&last, (*pos) + PCI_HT_CAP_SLAVE_FREQ0);
-       if(old_freq != freq) {
-               pci_write_config8(&last, 
-                               (*pos) + PCI_HT_CAP_SLAVE_FREQ0, freq);
-               *reset_needed = 1;
-               printk_debug("HyperT FreqP old %x new %x\n",old_freq,freq);
-       }
-       old_width = pci_read_config8(&last, 
-                       (*pos) + PCI_HT_CAP_SLAVE_WIDTH0 + 1);
-       if(present_width != old_width) {
-               pci_write_config8(&last, 
-                       (*pos) + PCI_HT_CAP_SLAVE_WIDTH0 + 1, present_width);
-                *reset_needed = 1;
-               printk_debug("HyperT widthP old %x new %x\n",
-                               old_width, present_width);
-       }
-       /* set the upstream device */
-        if(previous_unitid == 0) { /* the link is back to the host */
-               old_freq = pci_read_config8(&previous, 
-                               (*previous_pos) + PCI_HT_CAP_HOST_FREQ);
-               old_freq &= 0x0f;
-               if(freq != old_freq) {
-                               pci_write_config8(&previous, 
-                           (*previous_pos) + PCI_HT_CAP_HOST_FREQ, freq);
-                       *reset_needed = 1;
-                       printk_debug("HyperT freqUH old %x new %x\n",
-                                       old_freq, freq);
-               }
-               old_width = pci_read_config8(&previous, 
-                           (*previous_pos) + PCI_HT_CAP_HOST_WIDTH + 1);
-               if(upstream_width != old_width) {
-                               pci_write_config8(&previous, 
-                       (*previous_pos) + PCI_HT_CAP_HOST_WIDTH + 1, 
-                                       upstream_width);
-                       *reset_needed = 1;
-                       printk_debug("HyperT widthUH old %x new %x\n",
-                                       old_width, upstream_width);
-               }
-       }
-       else { /* The link is back up the chain */
-                       old_freq = pci_read_config8(&previous, 
-                       (*previous_pos) + PCI_HT_CAP_SLAVE_FREQ1);
-                old_freq &= 0x0f;
-                if(freq != old_freq) {
-                               pci_write_config8(&previous, 
-                           (*previous_pos) + PCI_HT_CAP_SLAVE_FREQ1, 
-                               freq);
-                       *reset_needed = 1;
-                       printk_debug("HyperT freqUL old %x new %x\n",
-                                       old_freq, freq);
-               }
-                old_width = pci_read_config8(&previous, 
-                       (*previous_pos) + PCI_HT_CAP_SLAVE_WIDTH1 + 1);
-                if(upstream_width != old_width) {
-                               pci_write_config8(&previous, 
-                           (*previous_pos) + PCI_HT_CAP_SLAVE_WIDTH1,
-                                       upstream_width);
-                       *reset_needed = 1;
-                       printk_debug("HyperT widthUL old %x new %x\n",
-                                       old_width, upstream_width);
-               }
-               }
-       *previous_pos = *pos;
-       *pos=0;
-}
-
-#define HYPERTRANSPORT_SUPPORT 1
 /** Scan the pci bus devices and bridges.
  * @param bus pointer to the bus structure
  * @param min_devfn minimum devfn to look at in the scan usually 0x00
@@ -668,11 +511,6 @@ unsigned int pci_scan_bus(struct bus *bus,
        device_t dev;
        device_t old_devices;
        device_t child;
-#if HYPERTRANSPORT_SUPPORT
-       unsigned next_unitid, last_unitid, previous_unitid;
-       int reset_needed = 0;
-       uint8_t previous_pos;
-#endif
 
        printk_debug("PCI: pci_scan_bus for bus %d\n", bus->secondary);
 
@@ -682,112 +520,6 @@ unsigned int pci_scan_bus(struct bus *bus,
        post_code(0x24);
        
 
-#if HYPERTRANSPORT_SUPPORT
-       /* Spin through the devices and collapse any early
-        * hypertransport enumeration.
-        */
-       for(devfn = min_devfn; devfn <= max_devfn; devfn += 8) {
-               struct device dummy;
-               uint32_t id;
-               uint8_t hdr_type, pos;
-               dummy.bus              = bus;
-               dummy.path.type        = DEVICE_PATH_PCI;
-               dummy.path.u.pci.devfn = devfn;
-               id = pci_read_config32(&dummy, PCI_VENDOR_ID);
-               if (    (id == 0xffffffff) || (id == 0x00000000) || 
-                       (id == 0x0000ffff) || (id == 0xffff0000)) {
-                       continue;
-               }
-               hdr_type = pci_read_config8(&dummy, PCI_HEADER_TYPE);
-               pos = 0;
-               switch(hdr_type & 0x7f) {
-               case PCI_HEADER_TYPE_NORMAL:
-               case PCI_HEADER_TYPE_BRIDGE:
-                       pos = PCI_CAPABILITY_LIST;
-                       break;
-               }
-               if (pos > PCI_CAP_LIST_NEXT) {
-                       pos = pci_read_config8(&dummy, pos);
-               }
-               while(pos != 0) {
-                       uint8_t cap;
-                       cap = pci_read_config8(&dummy, pos + PCI_CAP_LIST_ID);
-                       printk_debug("Capability: 0x%02x @ 0x%02x\n", cap, pos);
-                       if (cap == PCI_CAP_ID_HT) {
-                               uint16_t flags;
-                               flags = pci_read_config16(&dummy, 
-                                               pos + PCI_CAP_FLAGS);
-                               printk_debug("flags: 0x%04x\n", 
-                                               (unsigned)flags);
-                               if ((flags >> 13) == 0) {
-                                       /* Clear the unitid */
-                                       flags &= ~0x1f;
-                                       pci_write_config16(&dummy, 
-                                               pos + PCI_CAP_FLAGS, flags);
-                                       break;
-                               }
-                       }
-                       pos = pci_read_config8(&dummy, pos + PCI_CAP_LIST_NEXT);
-               }
-       }
-       /* If present assign unitid to a hypertransport chain */
-       last_unitid = 0;
-       next_unitid = 1;
-       previous_pos = 0;
-       do {
-               struct device dummy;
-               uint32_t id;
-               uint8_t hdr_type, pos;
-
-               previous_unitid = last_unitid;
-               last_unitid = next_unitid;
-
-               /* Read the next unassigned device off the stack */
-               dummy.bus              = bus;
-               dummy.path.type        = DEVICE_PATH_PCI;
-               dummy.path.u.pci.devfn = 0;
-               id = pci_read_config32(&dummy, PCI_VENDOR_ID);
-               /* If the chain is enumerated quit */
-               if (id == 0xffffffff || id == 0x00000000 ||
-                       id == 0x0000ffff || id == 0xffff0000) {
-                       break;
-               }
-               hdr_type = pci_read_config8(&dummy, PCI_HEADER_TYPE);
-               pos = 0;
-               switch(hdr_type & 0x7f) {
-               case PCI_HEADER_TYPE_NORMAL:
-               case PCI_HEADER_TYPE_BRIDGE:
-                       pos = PCI_CAPABILITY_LIST;
-                       break;
-               }
-               if (pos > PCI_CAP_LIST_NEXT) {
-                       pos = pci_read_config8(&dummy, pos);
-               }
-               while(pos != 0) {   /* loop through the linked list */
-                       uint8_t cap;
-                       cap = pci_read_config8(&dummy, pos + PCI_CAP_LIST_ID);
-                       printk_debug("Capability: 0x%02x @ 0x%02x\n", cap, pos);
-                       if (cap == PCI_CAP_ID_HT) {
-                               assign_id_set_links(&dummy,&pos,&previous_pos,
-                                               previous_unitid, last_unitid,
-                                               &reset_needed, bus, 
-                                               &next_unitid);
-                       }
-                       if(pos)
-                               pos = pci_read_config8(&dummy, 
-                                               pos + PCI_CAP_LIST_NEXT);
-               }
-       } while((last_unitid != next_unitid) && (next_unitid <= 0x1f));
-#if HAVE_HARD_RESET == 1
-       if(reset_needed) {
-               printk_debug("HyperT reset needed\n");
-               boot_successful();
-               hard_reset();
-       }
-       printk_debug("HyperT reset not needed\n");
-#endif /* HAVE_HARD_RESET */
-#endif /* HYPERTRANSPORT_SUPPORT */
-
        /* probe all devices on this bus with some optimization for non-existance and 
           single funcion devices */
        for (devfn = min_devfn; devfn <= max_devfn; devfn++) {
index 5529abc7f232eb4782ab5320efabc288dabf6c98..e7b0317db3fef87fd18fca1497fa37b0e0588fed 100644 (file)
@@ -110,5 +110,6 @@ extern void root_dev_read_resources(device_t dev);
 extern void root_dev_set_resources(device_t dev);
 extern unsigned int walk_static_devices(device_t bus, unsigned int max);
 extern void enable_childrens_resources(device_t dev);
+extern unsigned int root_dev_scan_pci_bus(device_t root, unsigned int max);
 
 #endif /* DEVICE_H */
diff --git a/src/include/device/hypertransport.h b/src/include/device/hypertransport.h
new file mode 100644 (file)
index 0000000..281f50e
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef DEVICE_HYPERTRANSPORT_H
+#define DEVICE_HYPERTRANSPORT_H
+
+unsigned int hypertransport_scan_chain(struct bus *bus, unsigned min_unitid, unsigned int max);
+
+#define HT_IO_HOST_ALIGN 4096
+#define HT_MEM_HOST_ALIGN (1024*1024)
+
+#endif /* DEVICE_HYPERTRANSPORT_H */
index 80c3bfca1124cda33df65bb80ff8a0cf5230b62f..824e43ff6744266c41feda6ca1dc302f66e309f8 100644 (file)
@@ -222,6 +222,7 @@ mainboardinit cpu/k8/disable_mmx_sse.inc
 ## Include the secondary Configuration files 
 ##
 dir /pc80
+config chip.h
 
 northbridge amd/amdk8 "mc0"
        pci 0:18.0
@@ -263,12 +264,12 @@ northbridge amd/amdk8 "mc0"
 end
 
 northbridge amd/amdk8 "mc1"
-       #pci 0:19.0
-       #pci 0:19.0
-       #pci 0:19.0
-       #pci 0:19.1
-       #pci 0:19.2
-       #pci 0:19.3
+       pci 0:19.0
+       pci 0:19.0
+       pci 0:19.0
+       pci 0:19.1
+       pci 0:19.2
+       pci 0:19.3
 end
 
 cpu k8 "cpu0"
index 4f40e393b2c08339bf2c550637d6e2b67d6b5006..c5812ece3f28ef577ae9d85ef905e6458716e331 100644 (file)
@@ -1,3 +1,4 @@
+
 #include <console/console.h>
 #include <device/device.h>
 #include <device/pci.h>
@@ -6,6 +7,7 @@
 
 #include <arch/io.h>
 #include <device/chip.h>
+#include "../../../northbridge/amd/amdk8/northbridge.h"
 #include "chip.h"
 
 
@@ -14,22 +16,27 @@ unsigned long initial_apicid[CONFIG_MAX_CPUS] =
        0, 1,
 };
 
-static void
-enable(struct chip *chip, enum chip_pass pass)
-{
-
-        struct mainboard_arima_hdama_config *conf =
-                (struct mainboard_arima_hdama_config *)chip->chip_info;
-
-        switch (pass) {
-       default: break;
-       case CONF_PASS_PRE_BOOT:
-               break;
-        }
+static struct device_operations mainboard_operations = {
+       .read_resources   = root_dev_read_resources,
+       .set_resources    = root_dev_set_resources,
+       .enable_resources = enable_childrens_resources,
+       .init             = 0,
+       .scan_bus         = amdk8_scan_root_bus,
+       .enable           = 0,
+};
 
+static void enumerate(struct chip *chip)
+{
+       struct chip *child;
+       dev_root.ops = &mainboard_operations;
+       chip->dev = &dev_root;
+       chip->bus = 0;
+       for(child = chip->children; child; child = child->next) {
+               child->bus = &dev_root.link[0];
+       }
 }
 struct chip_control mainboard_arima_hdama_control = {
-                enable: enable,
-                name:   "Arima HDAMA mainboard "
+       .enumerate = enumerate, 
+       .name      = "Arima HDAMA mainboard ",
 };
 
index 856288590deed43c6e1402a6262ae86927170ebf..94ac7357445815ac9557ae218690d36353e8e796 100644 (file)
@@ -36,40 +36,40 @@ void *smp_write_config_table(void *v, unsigned long * processor_map)
        smp_write_processors(mc, processor_map);
 
        {
-               struct pci_dev *dev;
-               uint32_t base;
+               device_t dev;
+
                /* 8111 */
-               dev = dev_find_slot(0, PCI_DEVFN(0x03,0));
+               dev = dev_find_slot(1, PCI_DEVFN(0x03,0));
                if (dev) {
                        bus_8111_1 = pci_read_config8(dev, PCI_SECONDARY_BUS);
                        bus_isa    = pci_read_config8(dev, PCI_SUBORDINATE_BUS);
                        bus_isa++;
                }
                else {
-                       printk_debug("ERROR - could not find PCI 0:03.0, using defaults\n");
+                       printk_debug("ERROR - could not find PCI 1:03.0, using defaults\n");
 
                        bus_8111_1 = 3;
                        bus_isa = 4;
                }
                /* 8131-1 */
-               dev = dev_find_slot(0, PCI_DEVFN(0x01,0));
+               dev = dev_find_slot(1, PCI_DEVFN(0x01,0));
                if (dev) {
                        bus_8131_1 = pci_read_config8(dev, PCI_SECONDARY_BUS);
 
                }
                else {
-                       printk_debug("ERROR - could not find PCI 0:01.0, using defaults\n");
+                       printk_debug("ERROR - could not find PCI 1:01.0, using defaults\n");
 
                        bus_8131_1 = 1;
                }
                /* 8131-2 */
-               dev = dev_find_slot(0, PCI_DEVFN(0x02,0));
+               dev = dev_find_slot(1, PCI_DEVFN(0x02,0));
                if (dev) {
                        bus_8131_2 = pci_read_config8(dev, PCI_SECONDARY_BUS);
 
                }
                else {
-                       printk_debug("ERROR - could not find PCI 0:02.0, using defaults\n");
+                       printk_debug("ERROR - could not find PCI 1:02.0, using defaults\n");
 
                        bus_8131_2 = 2;
                }
@@ -85,17 +85,17 @@ void *smp_write_config_table(void *v, unsigned long * processor_map)
 
        smp_write_ioapic(mc, 2, 0x11, 0xfec00000);
        {
-               struct pci_dev *dev;
+               device_t dev;
                uint32_t base;
                /* 8131 apic 3 */
-               dev = dev_find_slot(0, PCI_DEVFN(0x01,1));
+               dev = dev_find_slot(1, PCI_DEVFN(0x01,1));
                if (dev) {
                        base = pci_read_config32(dev, PCI_BASE_ADDRESS_0);
                        base &= PCI_BASE_ADDRESS_MEM_MASK;
                        smp_write_ioapic(mc, 0x03, 0x11, base);
                }
                /* 8131 apic 4 */
-               dev = dev_find_slot(0, PCI_DEVFN(0x02,1));
+               dev = dev_find_slot(1, PCI_DEVFN(0x02,1));
                if (dev) {
                        base = pci_read_config32(dev, PCI_BASE_ADDRESS_0);
                        base &= PCI_BASE_ADDRESS_MEM_MASK;
index 1b8902d6bbca857fd33731dd4c3724aa9f06e41e..6112ed18c8ccfec6372dd6c292880fd929fcaf74 100644 (file)
@@ -1,2 +1,3 @@
+config chip.h
 object northbridge.o
-
+driver misc_control.o
diff --git a/src/northbridge/amd/amdk8/chip.h b/src/northbridge/amd/amdk8/chip.h
new file mode 100644 (file)
index 0000000..a6111c9
--- /dev/null
@@ -0,0 +1,5 @@
+struct northbridge_amd_amdk8_config
+{
+};
+
+extern struct chip_control northbridge_amd_amdk8_control;
diff --git a/src/northbridge/amd/amdk8/misc_control.c b/src/northbridge/amd/amdk8/misc_control.c
new file mode 100644 (file)
index 0000000..639e34f
--- /dev/null
@@ -0,0 +1,37 @@
+/* Turn off machine check triggers when reading
+ * pci space where there are no devices.
+ * This is necessary when scaning the bus for
+ * devices which is done by the kernel */
+
+#include <console/console.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/pci_ops.h>
+
+static void misc_control_init(struct device *dev)
+{
+       uint32_t cmd;
+       
+       printk_debug("NB: Function 3 Misc Control.. ");
+       cmd = pci_read_config32(dev, 0x44);
+       cmd |= (1<<6) | (1<<25);
+       pci_write_config32(dev, 0x44, cmd );
+
+       printk_debug("done.\n");
+}
+
+static struct device_operations mcf3_ops  = {
+       .read_resources   = pci_dev_read_resources,
+       .set_resources    = pci_dev_set_resources,
+       .enable_resources = pci_dev_enable_resources,
+       .init             = misc_control_init,
+       .scan_bus         = 0,
+};
+
+static struct pci_driver mcf3_driver __pci_driver = {
+       .ops    = &mcf3_ops,
+       .vendor = PCI_VENDOR_ID_AMD,
+       .device = 0x1103,
+};
+
index 4d1e6987afac058d877a0e64cd832e1d43e41492..2db9bc18c9a55ad91773a6c442abb61742c0fcdb 100644 (file)
@@ -1,10 +1,17 @@
+#include <console/console.h>
 #include <arch/io.h>
 #include <stdint.h>
 #include <mem.h>
 #include <part/sizeram.h>
 #include <device/device.h>
 #include <device/pci.h>
-#include <console/console.h>
+#include <device/hypertransport.h>
+#include <device/chip.h>
+#include <stdlib.h>
+#include <string.h>
+#include <bitops.h>
+#include "chip.h"
+#include "northbridge.h"
 
 struct mem_range *sizeram(void)
 {
@@ -16,6 +23,7 @@ struct mem_range *sizeram(void)
 #warning "FIXME handle interleaved nodes"
        dev = dev_find_slot(0, PCI_DEVFN(0x18, 1));
        if (!dev) {
+               printk_err("Cannot find PCI: 0:18.1\n");
                return 0;
        }
        mmio_basek = (dev_root.resource[1].base >> 10);
@@ -28,14 +36,10 @@ struct mem_range *sizeram(void)
        mmio_basek &= ~((256*1024) - 1);
 #endif
 
-       /* Temporary hack to get mmio handling working */
-       for(i = 0; i < 8; i++) {
-#warning "FIXME handle multiple Hypertransport chains in device.c"
-               device_t node;
-               node = dev_find_slot(0, PCI_DEVFN(0x18 + i, 1));
-               pci_write_config32(node, 0xB8, ((mmio_basek >> 6) << 8) | (1<<1) | (1 << 0));
-               pci_write_config32(node, 0xBC, 0x00ffff00);
-       }
+#if 1
+       printk_debug("mmio_base: %dKB\n", mmio_basek);
+#endif
+
        for(idx = i = 0; i < 8; i++) {
                uint32_t base, limit;
                unsigned basek, limitk, sizek;
@@ -90,3 +94,387 @@ struct mem_range *sizeram(void)
        return mem;
 }
 
+#define F1_DEVS 8
+static device_t __f1_dev[F1_DEVS];
+
+#if 0
+static void debug_f1_devs(void)
+{
+       int 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);
+               }
+       }
+}
+#endif
+
+static void get_f1_devs(void)
+{
+       int i;
+       if (__f1_dev[0]) {
+               return;
+       }
+       for(i = 0; i < F1_DEVS; i++) {
+               __f1_dev[i] = dev_find_slot(0, PCI_DEVFN(0x18 + i, 1));
+       }
+       if (!__f1_dev[0]) {
+               die("Cannot find 0:0x18.1\n");
+       }
+}
+
+static uint32_t f1_read_config32(unsigned reg)
+{
+       get_f1_devs();
+       return pci_read_config32(__f1_dev[0], reg);
+}
+
+static void f1_write_config32(unsigned reg, uint32_t value)
+{
+       int i;
+       get_f1_devs();
+       for(i = 0; i < F1_DEVS; i++) {
+               device_t dev;
+               dev = __f1_dev[i];
+               if (dev) {
+                       pci_write_config32(dev, reg, value);
+               }
+       }
+}
+
+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++) {
+               uint32_t link_type;
+               uint32_t busses, config_busses;
+               unsigned free_reg, config_reg;
+               dev->link[link].cap = 0x80 + (link *0x20);
+               do {
+                       link_type = pci_read_config32(dev, dev->link[link].cap + 0x18);
+               } while(link_type & ConnectionPending);
+               if (!(link_type & LinkConnected)) {
+                       continue;
+               }
+               do {
+                       link_type = pci_read_config32(dev, dev->link[link].cap + 0x18);
+               } while(!(link_type & InitComplete));
+               if (!(link_type & NonCoherent)) {
+                       continue;
+               }
+               /* 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) {
+                       uint32_t config;
+                       config = f1_read_config32(config_reg);
+                       if (!free_reg && ((config & 3) == 0)) {
+                               free_reg = config_reg;
+                               continue;
+                       }
+                       if (((config & 3) == 3) && 
+                               (((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 (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.
+                */
+               dev->link[link].secondary = ++max;
+               dev->link[link].subordinate = 0xff;
+
+               /* Read the existing primary/secondary/subordinate bus
+                * number configuration.
+                */
+               busses = pci_read_config32(dev, dev->link[link].cap + 0x14);
+               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
+                */
+               busses &= 0xff000000;
+               busses |= (((unsigned int)(dev->bus->secondary) << 0) |
+                       ((unsigned int)(dev->link[link].secondary) << 8) |
+                       ((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) |
+                       ((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 */
+               max = hypertransport_scan_chain(&dev->link[link], 1, max);
+
+#if 1
+               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
+                */
+               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);
+               f1_write_config32(config_reg, config_busses);
+#if 1
+               printk_debug("Hypertransport scan link done\n");
+#endif         
+       }
+#if 1
+       printk_debug("amdk8_scan_chains max: %d done\n", max);
+#endif
+       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) {
+               uint32_t base, limit;
+               base  = f1_read_config32(reg);
+               limit = f1_read_config32(reg + 0x4);
+               /* Do I have a free register */
+               if (!free_reg && ((base & 3) == 0)) {
+                       free_reg = reg;
+               }
+               /* Do I have a match for this node and link? */
+               if (((base & 3) == 3) &&
+                       ((limit & 3) == nodeid) &&
+                       (((limit >> 4) & 3) == link)) {
+                       break;
+               }
+       }
+       /* If I didn't find an exact match return a free register */
+       if (reg > 0xd8) {
+               reg = free_reg;
+       }
+       /* Return an available I/O pair or 0 on failure */
+       return reg;
+}
+
+static unsigned amdk8_find_mempair(unsigned nodeid, unsigned link)
+{
+       unsigned free_reg, reg;
+       free_reg = 0;
+       for(reg = 0x80; reg <= 0xb8; reg += 0x8) {
+               uint32_t base, limit;
+               base  = f1_read_config32(reg);
+               limit = f1_read_config32(reg + 0x4);
+               /* Do I have a free register */
+               if (!free_reg && ((base & 3) == 0)) {
+                       free_reg = reg;
+               }
+               /* Do I have a match for this node and link? */
+               if (((base & 3) == 3) &&
+                       ((limit & 3) == nodeid) &&
+                       (((limit >> 4) & 3) == link)) {
+                       break;
+               }
+       }
+       /* If I didn't find an exact match return a free register */
+       if (reg > 0xb8) {
+               reg = free_reg;
+       }
+       /* Return an available I/O pair or 0 on failure */
+       return reg;
+}
+
+static void amdk8_link_read_bases(device_t dev, unsigned nodeid, unsigned link)
+{
+       unsigned int reg = dev->resources;
+       unsigned index;
+       
+       /* Initialize the io space constraints on the current bus */
+       index = amdk8_find_iopair(nodeid, link);
+       if (index) {
+               dev->resource[reg].base  = 0;
+               dev->resource[reg].size  = 0;
+               dev->resource[reg].align = log2(HT_IO_HOST_ALIGN);
+               dev->resource[reg].gran  = log2(HT_IO_HOST_ALIGN);
+               dev->resource[reg].limit = 0xffffUL;
+               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);
+               reg++;
+       }
+
+       /* Initialize the memory constraints on the current bus */
+       index = amdk8_find_mempair(nodeid, link);
+       if (index) {
+               dev->resource[reg].base  = 0;
+               dev->resource[reg].size  = 0;
+               dev->resource[reg].align = log2(HT_MEM_HOST_ALIGN);
+               dev->resource[reg].gran  = log2(HT_MEM_HOST_ALIGN);
+               dev->resource[reg].limit = 0xffffffffUL;
+               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);
+               reg++;
+       }
+       dev->resources = reg;
+}
+
+static void amdk8_read_resources(device_t dev)
+{
+       unsigned nodeid, link;
+       nodeid = amdk8_nodeid(dev);
+       dev->resources = 0;
+       memset(&dev->resource, 0, sizeof(dev->resource));
+       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)
+{
+       unsigned long rbase, rlimit;
+       unsigned reg, link;
+       /* Make certain the resource has actually been set */
+       if (!(resource->flags & IORESOURCE_SET)) {
+               return;
+       }
+       
+       /* Only handle PCI memory and IO resources */
+       if (!(resource->flags & (IORESOURCE_MEM | IORESOURCE_IO)))
+               return;
+
+       /* Get the base address */
+       rbase = resource->base;
+       
+       /* Get the limit (rounded up) */
+       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);
+               base  = f1_read_config32(reg);
+               limit = f1_read_config32(reg + 0x4);
+               base  &= 0xfe000fcc;
+               base  |= rbase  & 0x01fff000;
+               base  |= 3;
+               limit &= 0xfe000fc8;
+               limit |= rlimit & 0x01fff000;
+               limit |= (link & 3) << 4;
+               limit |= (nodeid & 3);
+               f1_write_config32(reg + 0x4, limit);
+               f1_write_config32(reg, base);
+       }
+       else if (resource->flags & IORESOURCE_MEM) {
+               uint32_t base, limit;
+               compute_allocate_resource(&dev->link[link], resource,
+                       IORESOURCE_MEM, IORESOURCE_MEM);
+               base  = f1_read_config32(reg);
+               limit = f1_read_config32(reg + 0x4);
+               base  &= 0x000000f0;
+               base  |= (rbase & 0xffff0000) >> 8;
+               base  |= 3;
+               limit &= 0x00000048;
+               limit |= (rlimit & 0xffff0000) >> 8;
+               limit |= (link & 3) << 4;
+               limit |= (nodeid & 3);
+               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");
+}
+
+static void amdk8_set_resources(device_t dev)
+{
+       unsigned nodeid, link;
+       int i;
+
+       /* Find the nodeid */
+       nodeid = amdk8_nodeid(dev);     
+
+       /* Set each resource we have found */
+       for(i = 0; i < dev->resources; i++) {
+               amdk8_set_resource(dev, &dev->resource[i], nodeid);
+       }
+       
+       for(link = 0; link < dev->links; link++) {
+               struct bus *bus;
+               bus = &dev->link[link];
+               if (bus->children) {
+                       assign_resources(bus);
+               }
+       }
+}
+
+unsigned int amdk8_scan_root_bus(device_t root, unsigned int max)
+{
+       return pci_scan_bus(&root->link[0], PCI_DEVFN(0x18, 0), 0xff, max);
+}
+
+static struct device_operations northbridge_operations = {
+       .read_resources   = amdk8_read_resources,
+       .set_resources    = amdk8_set_resources,
+       .enable_resources = pci_dev_enable_resources,
+       .init             = 0,
+       .scan_bus         = amdk8_scan_chains,
+       .enable           = 0,
+};
+
+
+static void enumerate(struct chip *chip)
+{
+       chip_enumerate(chip);
+       chip->dev->ops = &northbridge_operations;
+}
+
+struct chip_control northbridge_amd_amdk8_control = {
+       .enumerate = enumerate,
+       .name   = "AMD K8 Northbridge",
+};
diff --git a/src/northbridge/amd/amdk8/northbridge.h b/src/northbridge/amd/amdk8/northbridge.h
new file mode 100644 (file)
index 0000000..b39a594
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef NORTHBRIDGE_AMD_AMDK8_H
+#define NORTHBRIDGE_AMD_AMDK8_H
+
+extern unsigned int amdk8_scan_root_bus(device_t root, unsigned int max);
+
+#endif /* NORTHBRIDGE_AMD_AMDK8_H */
index ab48f9830eae05e51b7a195fb416be8e0600b900..9105324f33b5284d88db5021a65103adf2140709 100644 (file)
@@ -9,29 +9,26 @@
 
 static int cpu_init_detected(void)
 {
-       unsigned long dcl;
-       int cpu_init;
+       unsigned long htic;
+       htic = pci_read_config32(PCI_DEV(0, 0x18, 0), HT_INIT_CONTROL);
+
+       return !!(htic & HTIC_INIT_Detect);
+}
 
+static int bios_reset_detected(void)
+{
        unsigned long htic;
+       htic = pci_read_config32(PCI_DEV(0, 0x18, 0), HT_INIT_CONTROL);
+
+       return (htic & HTIC_ColdR_Detect) && !(htic & HTIC_BIOSR_Detect);
+}
 
+static int cold_reset_detected(void)
+{
+       unsigned long htic;
        htic = pci_read_config32(PCI_DEV(0, 0x18, 0), HT_INIT_CONTROL);
-#if 0
-       print_debug("htic: ");
-       print_debug_hex32(htic);
-       print_debug("\r\n");
-
-       if (!(htic & HTIC_ColdR_Detect)) {
-               print_debug("Cold Reset.\r\n");
-       }
-       if ((htic & HTIC_ColdR_Detect) && !(htic & HTIC_BIOSR_Detect)) {
-               print_debug("BIOS generated Reset.\r\n");
-       }
-       if (htic & HTIC_INIT_Detect) {
-               print_debug("Init event.\r\n");
-       }
-#endif
-       cpu_init = (htic & HTIC_INIT_Detect);
-       return cpu_init;
+
+       return !(htic & HTIC_ColdR_Detect);
 }
 
 static void distinguish_cpu_resets(unsigned node_id)
@@ -43,3 +40,11 @@ static void distinguish_cpu_resets(unsigned node_id)
        htic |= HTIC_ColdR_Detect | HTIC_BIOSR_Detect | HTIC_INIT_Detect;
        pci_write_config32(device, HT_INIT_CONTROL, htic);
 }
+
+static void set_bios_reset(void)
+{
+       unsigned long htic;
+       htic = pci_read_config32(PCI_DEV(0, 0x18, 0), HT_INIT_CONTROL);
+       htic &= ~HTIC_BIOSR_Detect;
+       pci_write_config32(PCI_DEV(0, 0x18, 0), HT_INIT_CONTROL, htic);
+}
index 059f5163b03f5500614fde1d5e009054cec8942a..0ec41c3346ccd2ceee8eeb79b795b530282b795c 100644 (file)
@@ -2,7 +2,11 @@
 /* This code is distributed without warranty under the GPL v2 (see COPYING) */
 
 #include <arch/io.h>
+#include <device/device.h>
 #include <device/chip.h>
+#include <console/console.h>
+#include <string.h>
+#include <bitops.h>
 #include "chip.h"
 
 void pnp_output(char address, char data)
@@ -11,7 +15,7 @@ void pnp_output(char address, char data)
        outb(data, PNP_DATA_REG);
 }
 
-void sio_enable(struct chip *chip, enum chip_pass pass)
+static void sio_enable(struct chip *chip, enum chip_pass pass)
 {
 
        struct superio_NSC_pc87360_config *conf = (struct superio_NSC_pc87360_config *)chip->chip_info;
@@ -31,7 +35,281 @@ void sio_enable(struct chip *chip, enum chip_pass pass)
        }
 }
 
+static void pnp_write_config(device_t dev, unsigned char value, unsigned char reg)
+{
+       outb(reg, dev->path.u.pnp.port);
+       outb(value, dev->path.u.pnp.port + 1);
+}
+
+static unsigned char pnp_read_config(device_t dev, unsigned char reg)
+{
+       outb(reg, dev->path.u.pnp.port);
+       return inb(dev->path.u.pnp.port + 1);
+}
+
+static void pnp_set_logical_device(device_t dev)
+{
+       pnp_write_config(dev, dev->path.u.pnp.device, 0x07);
+}
+
+static void pnp_set_enable(device_t dev, int enable)
+{
+       pnp_write_config(dev, enable?0x1:0x0, 0x30);
+}
+
+static int pnp_read_enable(device_t dev)
+{
+       return !!pnp_read_config(dev, 0x30);
+}
+
+#define FLOPPY_DEVICE   0
+#define PARALLEL_DEVICE 1
+#define COM2_DEVICE     2
+#define COM1_DEVICE     3
+#define SWC_DEVICE      4
+#define MOUSE_DEVICE    5
+#define KBC_DEVICE      6
+#define GPIO_DEVICE     7
+#define ACB_DEVICE      8
+#define FSCM_DEVICE     9
+#define WDT_DEVICE     10
+
+struct io_info {
+       unsigned mask, set;
+};
+struct pnp_info {
+       unsigned flags;
+#define PNP_IO0  0x01
+#define PNP_IO1  0x02
+#define PNP_IRQ0 0x04
+#define PNP_IRQ1 0x08
+#define PNP_DRQ0 0x10
+#define PNP_DRQ1 0x20
+       struct io_info io0, io1;
+};
+
+static struct pnp_info pnp_dev_info[] = {
+       [ 0] = { PNP_IO0 | PNP_IRQ0 | PNP_DRQ0, { 0x07fa, 0}, },
+       [ 1] = { PNP_IO0 | PNP_IRQ0 | PNP_DRQ0, { 0x04f8, 0}, },
+       [ 2] = { PNP_IO0 | PNP_IRQ0 | PNP_DRQ0 | PNP_DRQ1, { 0x7f8, 0 }, },
+       [ 3] = { PNP_IO0 | PNP_IRQ0, { 0x7f8, 0 }, },
+       [ 4] = { PNP_IO0 | PNP_IRQ0, { 0xfff0, 0 }, },
+       [ 5] = { PNP_IRQ0 },
+       [ 6] = { PNP_IO0 | PNP_IO1 | PNP_IRQ0, { 0x7f8, 0 }, { 0x7f8, 0x4}, },
+       [ 7] = { PNP_IO0 | PNP_IRQ0, { 0xfff8, 0 } },
+       [ 8] = { PNP_IO0 | PNP_IRQ0, { 0xfff8, 0 } },
+       [ 9] = { PNP_IO0 | PNP_IRQ0, { 0xfff8, 0 } },
+       [10] = { PNP_IO0 | PNP_IRQ0, { 0xfffc, 0 } },
+};
+
+static struct resource *get_resource(device_t dev, unsigned index)
+{
+       struct resource *resource;
+       int i;
+       resource = 0;
+       for(i = 0; i < dev->resources; i++) {
+               resource = &dev->resource[i];
+               if (resource->index == index) {
+                       break;
+               }
+       }
+       if (!resource || (resource->index != index)) {
+               resource = &dev->resource[dev->resources];
+               memset(resource, 0, sizeof(*resource));
+               dev->resources++;
+       }
+       /* Initialize the resource values */
+       if (!(resource->flags & IORESOURCE_FIXED)) {
+               resource->flags = 0;
+               resource->base = 0;
+       }
+       resource->size  = 0;
+       resource->limit = 0;
+       resource->flags = 0;
+       resource->index = index;
+       resource->align = 0;
+       resource->gran  = 0;
+
+       return resource;
+}
+
+static void pnp_read_ioresource(device_t dev, unsigned index, struct io_info *info)
+{
+       struct resource *resource;
+       uint32_t size;
+       resource = get_resource(dev, index);
+       
+       /* Initilize the resource */
+       resource->limit = 0xffff;
+       resource->flags |= IORESOURCE_IO;
+       
+       /* Set the resource size and alignment */
+       size = (0xffff & info->mask);
+       resource->size  = (~(size | 0xfffff800) + 1);
+       resource->align = log2(resource->size);
+       resource->gran  = resource->align;
+}
+
+
+static void pnp_read_resources(device_t dev)
+{
+       struct pnp_info *info;
+       struct resource *resource;
+       pnp_set_logical_device(dev);
+
+       info = &pnp_dev_info[dev->path.u.pnp.device];
+
+       if (info->flags & PNP_IO0) {
+               pnp_read_ioresource(dev, 0x60, &info->io0);
+       }
+       if (info->flags & PNP_IO1) {
+               pnp_read_ioresource(dev, 0x62, &info->io1);
+       }
+       if (info->flags & PNP_IRQ0) {
+               resource = get_resource(dev, 0x70);
+               resource->size = 1;
+               resource->flags |= IORESOURCE_IRQ;
+       }
+       if (info->flags & PNP_IRQ1) {
+               resource = get_resource(dev, 0x72);
+               resource->size = 1;
+               resource->flags |= IORESOURCE_IRQ;
+       }
+       if (info->flags & PNP_DRQ0) {
+               resource = get_resource(dev, 0x74);
+               resource->size = 1;
+               resource->flags |= IORESOURCE_DRQ;
+       }
+       if (info->flags & PNP_DRQ1) {
+               resource = get_resource(dev, 0x75);
+               resource->size = 1;
+               resource->flags |= IORESOURCE_DRQ;
+       }
+}
+
+static void pnp_set_iobase(device_t dev, unsigned iobase, unsigned index)
+{
+       /* Index == 0x60 or 0x62 */
+       pnp_write_config(dev, (iobase >> 8) & 0xff, index);
+       pnp_write_config(dev, iobase & 0xff, index + 1);
+}
+
+static void pnp_set_irq(device_t dev, unsigned irq, unsigned index)
+{
+       /* Index == 0x70 or 0x72 */
+       pnp_write_config(dev, irq, index);
+}
+
+static void pnp_set_drq(device_t dev, unsigned drq, unsigned index)
+{
+       /* Index == 0x74 */
+       pnp_write_config(dev, drq & 0xff, index);
+}
+
+
+static void pnp_set_resource(device_t dev, struct resource *resource)
+{
+       if (!(resource->flags & IORESOURCE_SET)) {
+#if 1
+               printk_err("ERROR: %s %02x not allocated\n",
+                       dev_path(dev), resource->index);
+#endif
+               return;
+       }
+       if (resource->flags & IORESOURCE_IO) {
+               pnp_set_iobase(dev, resource->base, resource->index);
+       }
+       else if (resource->flags & IORESOURCE_DRQ) {
+               pnp_set_drq(dev, resource->base, resource->index);
+       }
+       else if (resource->flags  & IORESOURCE_IRQ) {
+               pnp_set_irq(dev, resource->base, resource->index);
+       }
+       else {
+               printk_err("ERROR: %s %02x unknown resource type\n",
+                       dev_path(dev), resource->index);
+               return;
+       }
+       printk_debug(
+               "%s %02x <- [0x%08lx - 0x%08lx %s\n",
+               dev_path(dev),
+               resource->index,
+               resource->base,  resource->base + resource->size - 1,
+               (resource->flags & IORESOURCE_IO)? "io":
+               (resource->flags & IORESOURCE_DRQ)? "drq":
+               (resource->flags & IORESOURCE_IRQ)? "irq":
+               (resource->flags & IORESOURCE_MEM)? "mem":
+               "???");
+}
+
+static void pnp_set_resources(device_t dev)
+{
+       int i;
+       pnp_set_logical_device(dev);
+       for(i = 0; i < dev->resources; i++) {
+               pnp_set_resource(dev, &dev->resource[i]);
+       }
+
+}
+static void pnp_enable_resources(device_t dev)
+{
+       pnp_set_logical_device(dev);
+       pnp_set_enable(dev, 1);
+
+}
+static void pnp_enable(device_t dev)
+{
+       pnp_set_logical_device(dev);
+       if (!dev->enable) {
+               pnp_set_enable(dev, 0);
+       }
+}
+
+static struct device_operations pnp_ops = {
+       .read_resources   = pnp_read_resources,
+       .set_resources    = pnp_set_resources,
+       .enable_resources = pnp_enable_resources,
+       .enable           = pnp_enable,
+};
+
+#define MAX_FUNCTION 10
+static void enumerate(struct chip *chip)
+{
+       struct superio_NSC_pc87360_config *conf = (struct superio_NSC_pc87360_config *)chip->chip_info;
+       struct resource *resource;
+       struct device_path path;
+       device_t dev;
+       int i;
+
+       chip_enumerate(chip);
+       path.type       = DEVICE_PATH_PNP;
+       path.u.pnp.port = chip->dev->path.u.pnp.port;
+
+       /* Set the ops on the newly allocated devices */
+       for(i = 0; i <= WDT_DEVICE; i++) {
+               path.u.pnp.device = i;
+               dev = alloc_find_dev(chip->bus, &path);
+               dev->ops = &pnp_ops;
+       }
+
+       /* Processes the hard codes for com1 */
+       path.u.pnp.device = COM1_DEVICE;
+       dev = alloc_find_dev(chip->bus, &path);
+       resource = get_resource(dev, 0x60);
+       if (conf->com1.base) {
+               resource->base = conf->com1.base;
+               resource->flags = IORESOURCE_IO | IORESOURCE_FIXED | IORESOURCE_SET;
+       }
+       resource = get_resource(dev, 0x70);
+       if (conf->com1.irq) {
+               resource->base = conf->com1.irq;
+               resource->flags = IORESOURCE_IRQ | IORESOURCE_FIXED | IORESOURCE_SET;
+       }
+               
+}
+
 struct chip_control superio_NSC_pc87360_control = {
-       enable: sio_enable,
-       name:   "NSC 87360"
+       .enable    = sio_enable,
+       .enumerate = enumerate,
+       .name      = "NSC 87360"
 };