| /* 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 |
| * |
| * written in 2003 by Eric Biederman |
| * |
| * - Athlon64 workarounds by Stefan Reinauer |
| * - "reset once" logic by Yinghai Lu |
| */ |
| |
| #include <console/console.h> |
| #include <device/device.h> |
| #include <device/pci.h> |
| #include <device/pci_ids.h> |
| #include <device/pci_ops.h> |
| #include <reset.h> |
| #include <pc80/mc146818rtc.h> |
| #include <bitops.h> |
| #include <cpu/amd/model_fxx_rev.h> |
| |
| #include "amdk8.h" |
| |
| /** |
| * @brief Read resources for AGP aperture |
| * |
| * @param |
| * |
| * There is only one AGP aperture resource needed. The resoruce is added to |
| * the northbridge of BSP. |
| * |
| * The same trick can be used to augment legacy VGA resources which can |
| * be detect by generic pci reousrce allocator for VGA devices. |
| * BAD: it is more tricky than I think, the resource allocation code is |
| * implemented in a way to NOT DOING legacy VGA resource allcation on |
| * purpose :-(. |
| */ |
| static void mcf3_read_resources(device_t dev) |
| { |
| struct resource *resource; |
| unsigned char iommu; |
| /* Read the generic PCI resources */ |
| pci_dev_read_resources(dev); |
| |
| /* If we are not the first processor don't allocate the gart apeture */ |
| if (dev->path.pci.devfn != PCI_DEVFN(0x18, 3)) { |
| return; |
| } |
| |
| iommu = 1; |
| get_option(&iommu, "iommu"); |
| |
| if (iommu) { |
| /* Add a Gart apeture resource */ |
| resource = new_resource(dev, 0x94); |
| resource->size = CONFIG_AGP_APERTURE_SIZE; |
| resource->align = log2(resource->size); |
| resource->gran = log2(resource->size); |
| resource->limit = 0xffffffff; /* 4G */ |
| resource->flags = IORESOURCE_MEM; |
| } |
| } |
| |
| static void set_agp_aperture(device_t dev) |
| { |
| struct resource *resource; |
| |
| resource = probe_resource(dev, 0x94); |
| if (resource) { |
| device_t pdev; |
| uint32_t gart_base, gart_acr; |
| |
| /* Remember this resource has been stored */ |
| resource->flags |= IORESOURCE_STORED; |
| |
| /* Find the size of the GART aperture */ |
| gart_acr = (0<<6)|(0<<5)|(0<<4)|((resource->gran - 25) << 1)|(0<<0); |
| |
| /* Get the base address */ |
| gart_base = ((resource->base) >> 25) & 0x00007fff; |
| |
| /* Update the other northbriges */ |
| pdev = 0; |
| while((pdev = dev_find_device(PCI_VENDOR_ID_AMD, 0x1103, pdev))) { |
| /* Store the GART size but don't enable it */ |
| pci_write_config32(pdev, 0x90, gart_acr); |
| |
| /* Store the GART base address */ |
| pci_write_config32(pdev, 0x94, gart_base); |
| |
| /* Don't set the GART Table base address */ |
| pci_write_config32(pdev, 0x98, 0); |
| |
| /* Report the resource has been stored... */ |
| report_resource_stored(pdev, resource, " <gart>"); |
| } |
| } |
| } |
| |
| static void mcf3_set_resources(device_t dev) |
| { |
| /* Set the gart apeture */ |
| set_agp_aperture(dev); |
| |
| /* Set the generic PCI resources */ |
| pci_dev_set_resources(dev); |
| } |
| |
| static void misc_control_init(struct device *dev) |
| { |
| uint32_t cmd, cmd_ref; |
| int needs_reset; |
| struct device *f0_dev, *f2_dev; |
| |
| printk_debug("NB: Function 3 Misc Control.. "); |
| needs_reset = 0; |
| |
| /* Disable Machine checks from Invalid Locations. |
| * This is needed for PC backwards compatibility. |
| */ |
| cmd = pci_read_config32(dev, 0x44); |
| cmd |= (1<<6) | (1<<25); |
| pci_write_config32(dev, 0x44, cmd ); |
| #if CONFIG_K8_REV_F_SUPPORT == 0 |
| if (is_cpu_pre_c0()) { |
| |
| /* Errata 58 |
| * Disable CPU low power states C2, C1 and throttling |
| */ |
| cmd = pci_read_config32(dev, 0x80); |
| cmd &= ~(1<<0); |
| pci_write_config32(dev, 0x80, cmd ); |
| cmd = pci_read_config32(dev, 0x84); |
| cmd &= ~(1<<24); |
| cmd &= ~(1<<8); |
| pci_write_config32(dev, 0x84, cmd ); |
| |
| /* Errata 66 |
| * Limit the number of downstream posted requests to 1 |
| */ |
| cmd = pci_read_config32(dev, 0x70); |
| if ((cmd & (3 << 0)) != 2) { |
| cmd &= ~(3<<0); |
| cmd |= (2<<0); |
| pci_write_config32(dev, 0x70, cmd ); |
| needs_reset = 1; |
| } |
| cmd = pci_read_config32(dev, 0x7c); |
| if ((cmd & (3 << 4)) != 0) { |
| cmd &= ~(3<<4); |
| cmd |= (0<<4); |
| pci_write_config32(dev, 0x7c, cmd ); |
| needs_reset = 1; |
| } |
| /* Clock Power/Timing Low */ |
| cmd = pci_read_config32(dev, 0xd4); |
| if (cmd != 0x000D0001) { |
| cmd = 0x000D0001; |
| pci_write_config32(dev, 0xd4, cmd); |
| needs_reset = 1; /* Needed? */ |
| } |
| } |
| else if(is_cpu_pre_d0()) { |
| uint32_t dcl; |
| f2_dev = dev_find_slot(0, dev->path.pci.devfn - 3 + 2); |
| /* Errata 98 |
| * Set Clk Ramp Hystersis to 7 |
| * Clock Power/Timing Low |
| */ |
| cmd_ref = 0x04e20707; /* Registered */ |
| dcl = pci_read_config32(f2_dev, DRAM_CONFIG_LOW); |
| if (dcl & DCL_UnBuffDimm) { |
| cmd_ref = 0x000D0701; /* Unbuffered */ |
| } |
| cmd = pci_read_config32(dev, 0xd4); |
| if(cmd != cmd_ref) { |
| pci_write_config32(dev, 0xd4, cmd_ref ); |
| needs_reset = 1; /* Needed? */ |
| } |
| } |
| #endif |
| /* Optimize the Link read pointers */ |
| f0_dev = dev_find_slot(0, dev->path.pci.devfn - 3); |
| if (f0_dev) { |
| int link; |
| cmd_ref = cmd = pci_read_config32(dev, 0xdc); |
| for(link = 0; link < 3; link++) { |
| uint32_t link_type; |
| unsigned reg; |
| /* This works on an Athlon64 because unimplemented links return 0 */ |
| reg = 0x98 + (link * 0x20); |
| link_type = pci_read_config32(f0_dev, reg); |
| /* Only handle coherent link here please */ |
| if ((link_type & (LinkConnected|InitComplete|NonCoherent)) |
| == (LinkConnected|InitComplete)) |
| { |
| cmd &= ~(0xff << (link *8)); |
| /* FIXME this assumes the device on the other side is an AMD device */ |
| cmd |= 0x25 << (link *8); |
| } |
| } |
| if (cmd != cmd_ref) { |
| pci_write_config32(dev, 0xdc, cmd); |
| needs_reset = 1; |
| } |
| } |
| else { |
| printk_err("Missing f0 device!\n"); |
| } |
| if (needs_reset) { |
| printk_debug("resetting cpu\n"); |
| hard_reset(); |
| } |
| printk_debug("done.\n"); |
| } |
| |
| |
| static struct device_operations mcf3_ops = { |
| .read_resources = mcf3_read_resources, |
| .set_resources = mcf3_set_resources, |
| .enable_resources = pci_dev_enable_resources, |
| .init = misc_control_init, |
| .scan_bus = 0, |
| .ops_pci = 0, |
| }; |
| |
| static const struct pci_driver mcf3_driver __pci_driver = { |
| .ops = &mcf3_ops, |
| .vendor = PCI_VENDOR_ID_AMD, |
| .device = 0x1103, |
| }; |