diff options
author | Yinghai Lu <yinghailu@gmail.com> | 2005-07-08 02:49:49 +0000 |
---|---|---|
committer | Yinghai Lu <yinghailu@gmail.com> | 2005-07-08 02:49:49 +0000 |
commit | 13f1c2af8be2cd7f7e99a678f5d428a65b771811 (patch) | |
tree | 27cad5581f1fa150f573149d48e82f70ba1b1d9f /src/northbridge/intel/E7525 | |
parent | 14cde9e96a777f9d75016a13b23fab0480515f58 (diff) |
eric patch
1. x86_setup_mtrr take address bit.
2. generic ht, pcix, pcie beidge...
3. scan bus and reset_bus
4. ht read ctrl to decide if the ht chain
is ready
5. Intel e7520 and e7525 support
6. new ich5r support
7. intel sb 6300 support.
yhlu patch
1. split x86_setup_mtrrs to fixed and var
2. if (resource->flags & IORESOURCE_FIXED ) return; in device.c pick_largest_resource
3. in_conherent.c K8_SCAN_PCI_BUS
git-svn-id: svn://svn.coreboot.org/coreboot/trunk@1982 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
Diffstat (limited to 'src/northbridge/intel/E7525')
-rw-r--r-- | src/northbridge/intel/E7525/Config.lb | 12 | ||||
-rw-r--r-- | src/northbridge/intel/E7525/chip.h | 7 | ||||
-rw-r--r-- | src/northbridge/intel/E7525/e7525.h | 44 | ||||
-rw-r--r-- | src/northbridge/intel/E7525/memory_initialized.c | 9 | ||||
-rw-r--r-- | src/northbridge/intel/E7525/northbridge.c | 270 | ||||
-rw-r--r-- | src/northbridge/intel/E7525/northbridge.h | 8 | ||||
-rw-r--r-- | src/northbridge/intel/E7525/pciexp_porta.c | 41 | ||||
-rw-r--r-- | src/northbridge/intel/E7525/pciexp_porta1.c | 41 | ||||
-rw-r--r-- | src/northbridge/intel/E7525/pciexp_portb.c | 41 | ||||
-rw-r--r-- | src/northbridge/intel/E7525/pciexp_portc.c | 41 | ||||
-rw-r--r-- | src/northbridge/intel/E7525/raminit.c | 1300 | ||||
-rw-r--r-- | src/northbridge/intel/E7525/raminit.h | 12 | ||||
-rw-r--r-- | src/northbridge/intel/E7525/raminit_test.c | 393 |
13 files changed, 2219 insertions, 0 deletions
diff --git a/src/northbridge/intel/E7525/Config.lb b/src/northbridge/intel/E7525/Config.lb new file mode 100644 index 0000000000..919e0f8adf --- /dev/null +++ b/src/northbridge/intel/E7525/Config.lb @@ -0,0 +1,12 @@ +config chip.h +driver northbridge.o +driver pciexp_porta.o +driver pciexp_porta1.o +driver pciexp_portb.o +driver pciexp_portc.o + +makerule raminit_test + depends "$(TOP)/src/northbridge/intel/e7525/raminit_test.c" + depends "$(TOP)/src/northbridge/intel/e7525/raminit.c" + action "$(HOSTCC) $(HOSTCFLAGS) $(CPUFLAGS) -Wno-unused-function -I$(TOP)/src/include -g $< -o $@" +end diff --git a/src/northbridge/intel/E7525/chip.h b/src/northbridge/intel/E7525/chip.h new file mode 100644 index 0000000000..19d8c4e54c --- /dev/null +++ b/src/northbridge/intel/E7525/chip.h @@ -0,0 +1,7 @@ +struct northbridge_intel_E7525_config +{ + /* Interrupt line connect */ + unsigned int intrline; +}; + +extern struct chip_operations northbridge_intel_E7525_ops; diff --git a/src/northbridge/intel/E7525/e7525.h b/src/northbridge/intel/E7525/e7525.h new file mode 100644 index 0000000000..be76303d4f --- /dev/null +++ b/src/northbridge/intel/E7525/e7525.h @@ -0,0 +1,44 @@ +#define VID 0X00 +#define DID 0X02 +#define PCICMD 0X04 +#define PCISTS 0X06 +#define RID 0X08 +#define IURBASE 0X14 +#define MCHCFG0 0X50 +#define MCHSCRB 0X52 +#define FDHC 0X58 +#define PAM 0X59 +#define DRB 0X60 +#define DRA 0X70 +#define DRT 0X78 +#define DRC 0X7C +#define DRM 0X80 +#define DRORC 0X82 +#define ECCDIAG 0X84 +#define SDRC 0X88 +#define CKDIS 0X8C +#define CKEDIS 0X8D +#define DDRCSR 0X9A +#define DEVPRES 0X9C +#define DEVPRES_D0F0 (1 << 0) +#define DEVPRES_D1F0 (1 << 1) +#define DEVPRES_D2F0 (1 << 2) +#define DEVPRES_D3F0 (1 << 3) +#define DEVPRES_D4F0 (1 << 4) +#define DEVPRES_D5F0 (1 << 5) +#define DEVPRES_D6F0 (1 << 6) +#define DEVPRES_D7F0 (1 << 7) +#define ESMRC 0X9D +#define SMRC 0X9E +#define EXSMRC 0X9F +#define DDR2ODTC 0XB0 +#define TOLM 0XC4 +#define REMAPBASE 0XC6 +#define REMAPLIMIT 0XC8 +#define REMAPOFFSET 0XCA +#define TOM 0XCC +#define EXPECBASE 0XCE +#define DEVPRES1 0XF4 +#define DEVPRES1_D0F1 (1 << 5) +#define DEVPRES1_D8F0 (1 << 1) +#define MSCFG 0XF6 diff --git a/src/northbridge/intel/E7525/memory_initialized.c b/src/northbridge/intel/E7525/memory_initialized.c new file mode 100644 index 0000000000..6eb31a8ca3 --- /dev/null +++ b/src/northbridge/intel/E7525/memory_initialized.c @@ -0,0 +1,9 @@ +#include "e7525.h" +#define NB_DEV PCI_DEV(0, 0, 0) + +static inline int memory_initialized(void) +{ + uint32_t drc; + drc = pci_read_config32(NB_DEV, DRC); + return (drc & (1<<29)); +} diff --git a/src/northbridge/intel/E7525/northbridge.c b/src/northbridge/intel/E7525/northbridge.c new file mode 100644 index 0000000000..71f17224df --- /dev/null +++ b/src/northbridge/intel/E7525/northbridge.c @@ -0,0 +1,270 @@ +#include <console/console.h> +#include <arch/io.h> +#include <stdint.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <device/hypertransport.h> +#include <stdlib.h> +#include <string.h> +#include <bitops.h> +#include <cpu/cpu.h> +#include "chip.h" +#include "northbridge.h" +#include "e7525.h" + + +static unsigned int max_bus; + +static void ram_resource(device_t dev, unsigned long index, + unsigned long basek, unsigned long sizek) +{ + struct resource *resource; + + resource = new_resource(dev, index); + resource->base = ((resource_t)basek) << 10; + resource->size = ((resource_t)sizek) << 10; + resource->flags = IORESOURCE_MEM | IORESOURCE_CACHEABLE | \ + IORESOURCE_FIXED | IORESOURCE_STORED | IORESOURCE_ASSIGNED; +} + + +static void pci_domain_read_resources(device_t dev) +{ + struct resource *resource; + + /* Initialize the system wide io space constraints */ + resource = new_resource(dev, IOINDEX_SUBTRACTIVE(0,0)); + resource->base = 0; + resource->size = 0; + resource->align = 0; + resource->gran = 0; + resource->limit = 0xffffUL; + resource->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED; + + /* Initialize the system wide memory resources constraints */ + resource = new_resource(dev, IOINDEX_SUBTRACTIVE(1,0)); + resource->base = 0; + resource->size = 0; + resource->align = 0; + resource->gran = 0; + resource->limit = 0xffffffffUL; + resource->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED; +} + +static void tolm_test(void *gp, struct device *dev, struct resource *new) +{ + struct resource **best_p = gp; + struct resource *best; + best = *best_p; + if (!best || (best->base > new->base)) { + best = new; + } + *best_p = best; +} + +static uint32_t find_pci_tolm(struct bus *bus) +{ + struct resource *min; + uint32_t tolm; + min = 0; + search_bus_resources(bus, IORESOURCE_MEM, IORESOURCE_MEM, tolm_test, &min); + tolm = 0xffffffffUL; + if (min && tolm > min->base) { + tolm = min->base; + } + return tolm; +} + + +static void pci_domain_set_resources(device_t dev) +{ + device_t mc_dev; + uint32_t pci_tolm; + + pci_tolm = find_pci_tolm(&dev->link[0]); + +#if 1 + printk_debug("PCI mem marker = %x\n", pci_tolm); +#endif + /* FIXME Me temporary hack */ + if(pci_tolm > 0xe0000000) + pci_tolm = 0xe0000000; + /* Ensure pci_tolm is 128M aligned */ + pci_tolm &= 0xf8000000; + mc_dev = dev->link[0].children; + if (mc_dev) { + /* Figure out which areas are/should be occupied by RAM. + * This is all computed in kilobytes and converted to/from + * the memory controller right at the edges. + * Having different variables in different units is + * too confusing to get right. Kilobytes are good up to + * 4 Terabytes of RAM... + */ + uint16_t tolm_r, remapbase_r, remaplimit_r, remapoffset_r; + unsigned long tomk, tolmk; + unsigned long remapbasek, remaplimitk, remapoffsetk; + + /* Get the Top of Memory address, units are 128M */ + tomk = ((unsigned long)pci_read_config16(mc_dev, TOM)) << 17; + /* Compute the Top of Low Memory */ + tolmk = (pci_tolm & 0xf8000000) >> 10; + + if (tolmk >= tomk) { + /* The PCI hole does not overlap memory + * we won't use the remap window. + */ + tolmk = tomk; + remapbasek = 0x3ff << 16; + remaplimitk = 0 << 16; + remapoffsetk = 0 << 16; + } + else { + /* The PCI memory hole overlaps memory + * setup the remap window. + */ + /* Find the bottom of the remap window + * is it above 4G? + */ + remapbasek = 4*1024*1024; + if (tomk > remapbasek) { + remapbasek = tomk; + } + /* Find the limit of the remap window */ + remaplimitk = (remapbasek + (4*1024*1024 - tolmk) - (1 << 16)); + /* Find the offset of the remap window from tolm */ + remapoffsetk = remapbasek - tolmk; + } + /* Write the ram configruation registers, + * preserving the reserved bits. + */ + tolm_r = pci_read_config16(mc_dev, 0xc4); + tolm_r = ((tolmk >> 17) << 11) | (tolm_r & 0x7ff); + pci_write_config16(mc_dev, 0xc4, tolm_r); + + remapbase_r = pci_read_config16(mc_dev, 0xc6); + remapbase_r = (remapbasek >> 16) | (remapbase_r & 0xfc00); + pci_write_config16(mc_dev, 0xc6, remapbase_r); + + remaplimit_r = pci_read_config16(mc_dev, 0xc8); + remaplimit_r = (remaplimitk >> 16) | (remaplimit_r & 0xfc00); + pci_write_config16(mc_dev, 0xc8, remaplimit_r); + + remapoffset_r = pci_read_config16(mc_dev, 0xca); + remapoffset_r = (remapoffsetk >> 16) | (remapoffset_r & 0xfc00); + pci_write_config16(mc_dev, 0xca, remapoffset_r); + + /* Report the memory regions */ + ram_resource(dev, 3, 0, 640); + ram_resource(dev, 4, 768, tolmk - 768); + if (tomk > 4*1024*1024) { + ram_resource(dev, 5, 4096*1024, tomk - 4*1024*1024); + } + if (remaplimitk >= remapbasek) { + ram_resource(dev, 6, remapbasek, + (remaplimitk + 64*1024) - remapbasek); + } + } + assign_resources(&dev->link[0]); +} + +static unsigned int pci_domain_scan_bus(device_t dev, unsigned int max) +{ + max = pci_scan_bus(&dev->link[0], 0, 0xff, max); + if (max > max_bus) { + max_bus = max; + } + return max; +} + +static struct device_operations pci_domain_ops = { + .read_resources = pci_domain_read_resources, + .set_resources = pci_domain_set_resources, + .enable_resources = enable_childrens_resources, + .init = 0, + .scan_bus = pci_domain_scan_bus, + .ops_pci_bus = &pci_cf8_conf1, /* Do we want to use the memory mapped space here? */ +}; + +static void mc_read_resources(device_t dev) +{ + struct resource *resource; + + pci_dev_read_resources(dev); + + resource = new_resource(dev, 0xcf); + resource->base = 0xe0000000; + resource->size = max_bus * 4096*256; + resource->flags = IORESOURCE_MEM | IORESOURCE_FIXED | IORESOURCE_STORED | IORESOURCE_ASSIGNED; +} + +static void mc_set_resources(device_t dev) +{ + struct resource *resource, *last; + + last = &dev->resource[dev->resources]; + resource = find_resource(dev, 0xcf); + if (resource) { + report_resource_stored(dev, resource, "<mmconfig>"); + } + pci_dev_set_resources(dev); +} + +static void intel_set_subsystem(device_t dev, unsigned vendor, unsigned device) +{ + pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, + ((device & 0xffff) << 16) | (vendor & 0xffff)); +} + +static struct pci_operations intel_pci_ops = { + .set_subsystem = intel_set_subsystem, +}; + +static struct device_operations mc_ops = { + .read_resources = mc_read_resources, + .set_resources = mc_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = 0, + .scan_bus = 0, + .ops_pci = &intel_pci_ops, +}; + +static struct pci_driver mc_driver __pci_driver = { + .ops = &mc_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = 0x359e, +}; + +static void cpu_bus_init(device_t dev) +{ + initialize_cpus(&dev->link[0]); +} + +static void cpu_bus_noop(device_t dev) +{ +} + +static struct device_operations cpu_bus_ops = { + .read_resources = cpu_bus_noop, + .set_resources = cpu_bus_noop, + .enable_resources = cpu_bus_noop, + .init = cpu_bus_init, + .scan_bus = 0, +}; + + +static void enable_dev(device_t dev) +{ + /* Set the operations if it is a special bus type */ + if (dev->path.type == DEVICE_PATH_PCI_DOMAIN) { + dev->ops = &pci_domain_ops; + } + else if (dev->path.type == DEVICE_PATH_APIC_CLUSTER) { + dev->ops = &cpu_bus_ops; + } +} + +struct chip_operations northbridge_intel_E7525_ops = { + CHIP_NAME("Intel E7525 Northbridge") + .enable_dev = enable_dev, +}; diff --git a/src/northbridge/intel/E7525/northbridge.h b/src/northbridge/intel/E7525/northbridge.h new file mode 100644 index 0000000000..0ee533f011 --- /dev/null +++ b/src/northbridge/intel/E7525/northbridge.h @@ -0,0 +1,8 @@ +#ifndef NORTHBRIDGE_INTEL_E7525_H +#define NORTHBRIDGE_INTEL_E7525_H + +extern unsigned int e7525_scan_root_bus(device_t root, unsigned int max); + + +#endif /* NORTHBRIDGE_INTEL_E7525_H */ + diff --git a/src/northbridge/intel/E7525/pciexp_porta.c b/src/northbridge/intel/E7525/pciexp_porta.c new file mode 100644 index 0000000000..093edec38f --- /dev/null +++ b/src/northbridge/intel/E7525/pciexp_porta.c @@ -0,0 +1,41 @@ +#include <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <device/pci_ops.h> +#include <device/pciexp.h> +#include <arch/io.h> +#include "chip.h" + +typedef struct northbridge_intel_E7525_config config_t; + +static void pcie_init(struct device *dev) +{ + config_t *config; + + /* Get the chip configuration */ + config = dev->chip_info; + + if(config->intrline) { + pci_write_config32(dev, 0x3c, config->intrline); + } + +} + +static struct device_operations pcie_ops = { + .read_resources = pci_bus_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_bus_enable_resources, + .init = pcie_init, + .scan_bus = pciexp_scan_bridge, + .reset_bus = pci_bus_reset, + .ops_pci = 0, +}; + +static struct pci_driver pci_driver __pci_driver = { + .ops = &pcie_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_PCIE_PA, +}; + + diff --git a/src/northbridge/intel/E7525/pciexp_porta1.c b/src/northbridge/intel/E7525/pciexp_porta1.c new file mode 100644 index 0000000000..7118caa72f --- /dev/null +++ b/src/northbridge/intel/E7525/pciexp_porta1.c @@ -0,0 +1,41 @@ +#include <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <device/pci_ops.h> +#include <device/pciexp.h> +#include <arch/io.h> +#include "chip.h" + +typedef struct northbridge_intel_E7525_config config_t; + +static void pcie_init(struct device *dev) +{ + config_t *config; + + /* Get the chip configuration */ + config = dev->chip_info; + + if(config->intrline) { + pci_write_config32(dev, 0x3c, config->intrline); + } + +} + +static struct device_operations pcie_ops = { + .read_resources = pci_bus_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_bus_enable_resources, + .init = pcie_init, + .scan_bus = pciexp_scan_bridge, + .reset_bus = pci_bus_reset, + .ops_pci = 0, +}; + +static struct pci_driver pci_driver __pci_driver = { + .ops = &pcie_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_PCIE_PA1, +}; + + diff --git a/src/northbridge/intel/E7525/pciexp_portb.c b/src/northbridge/intel/E7525/pciexp_portb.c new file mode 100644 index 0000000000..f623a54416 --- /dev/null +++ b/src/northbridge/intel/E7525/pciexp_portb.c @@ -0,0 +1,41 @@ +#include <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <device/pci_ops.h> +#include <device/pciexp.h> +#include <arch/io.h> +#include "chip.h" + +typedef struct northbridge_intel_E7525_config config_t; + +static void pcie_init(struct device *dev) +{ + config_t *config; + + /* Get the chip configuration */ + config = dev->chip_info; + + if(config->intrline) { + pci_write_config32(dev, 0x3c, config->intrline); + } + +} + +static struct device_operations pcie_ops = { + .read_resources = pci_bus_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_bus_enable_resources, + .init = pcie_init, + .scan_bus = pciexp_scan_bridge, + .reset_bus = pci_bus_reset, + .ops_pci = 0, +}; + +static struct pci_driver pci_driver __pci_driver = { + .ops = &pcie_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_PCIE_PB, +}; + + diff --git a/src/northbridge/intel/E7525/pciexp_portc.c b/src/northbridge/intel/E7525/pciexp_portc.c new file mode 100644 index 0000000000..05e0b68863 --- /dev/null +++ b/src/northbridge/intel/E7525/pciexp_portc.c @@ -0,0 +1,41 @@ +#include <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <device/pci_ops.h> +#include <device/pciexp.h> +#include <arch/io.h> +#include "chip.h" + +typedef struct northbridge_intel_E7525_config config_t; + +static void pcie_init(struct device *dev) +{ + config_t *config; + + /* Get the chip configuration */ + config = dev->chip_info; + + if(config->intrline) { + pci_write_config32(dev, 0x3c, config->intrline); + } + +} + +static struct device_operations pcie_ops = { + .read_resources = pci_bus_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_bus_enable_resources, + .init = pcie_init, + .scan_bus = pciexp_scan_bridge, + .reset_bus = pci_bus_reset, + .ops_pci = 0, +}; + +static struct pci_driver pci_driver __pci_driver = { + .ops = &pcie_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_PCIE_PC, +}; + + diff --git a/src/northbridge/intel/E7525/raminit.c b/src/northbridge/intel/E7525/raminit.c new file mode 100644 index 0000000000..c0e6b4291e --- /dev/null +++ b/src/northbridge/intel/E7525/raminit.c @@ -0,0 +1,1300 @@ +#include <cpu/x86/mem.h> +#include <cpu/x86/mtrr.h> +#include <cpu/x86/cache.h> +#include "raminit.h" +#include "e7525.h" + +#define BAR 0x40000000 + +static void sdram_set_registers(const struct mem_controller *ctrl) +{ + static const unsigned int register_values[] = { + + /* CKDIS 0x8c disable clocks */ + PCI_ADDR(0, 0x00, 0, CKDIS), 0xffff0000, 0x0000ffff, + + /* 0x9c Device present and extended RAM control + * DEVPRES is very touchy, hard code the initialization + * of PCI-E ports here. + */ + PCI_ADDR(0, 0x00, 0, DEVPRES), 0x00000000, 0x07020801 | DEVPRES_CONFIG, + + /* 0xc8 Remap RAM base and limit off */ + PCI_ADDR(0, 0x00, 0, REMAPLIMIT), 0x00000000, 0x03df0000, + + /* ??? */ + PCI_ADDR(0, 0x00, 0, 0xd8), 0x00000000, 0xb5930000, + PCI_ADDR(0, 0x00, 0, 0xe8), 0x00000000, 0x00004a2a, + + /* 0x50 scrub */ + PCI_ADDR(0, 0x00, 0, MCHCFG0), 0xfce0ffff, 0x00006000, /* 6000 */ + + /* 0x58 0x5c PAM */ + PCI_ADDR(0, 0x00, 0, PAM-1), 0xcccccc7f, 0x33333000, + PCI_ADDR(0, 0x00, 0, PAM+3), 0xcccccccc, 0x33333333, + + /* 0xf4 */ + PCI_ADDR(0, 0x00, 0, DEVPRES1), 0xffbffff, (1<<22)|(6<<2) | DEVPRES1_CONFIG, + + /* 0x14 */ + PCI_ADDR(0, 0x00, 0, IURBASE), 0x00000fff, BAR |0, + }; + int i; + int max; + + max = sizeof(register_values)/sizeof(register_values[0]); + for(i = 0; i < max; i += 3) { + device_t dev; + unsigned where; + unsigned long reg; + dev = (register_values[i] & ~0xff) - PCI_DEV(0, 0x00, 0) + ctrl->f0; + where = register_values[i] & 0xff; + reg = pci_read_config32(dev, where); + reg &= register_values[i+1]; + reg |= register_values[i+2]; + pci_write_config32(dev, where, reg); + } + print_spew("done.\r\n"); +} + + + +struct dimm_size { + unsigned long side1; + unsigned long side2; +}; + +static struct dimm_size spd_get_dimm_size(unsigned device) +{ + /* Calculate the log base 2 size of a DIMM in bits */ + struct dimm_size sz; + int value, low, ddr2; + sz.side1 = 0; + sz.side2 = 0; + + /* test for ddr2 */ + ddr2=0; + value = spd_read_byte(device, 2); /* type */ + if (value < 0) goto hw_err; + if (value == 8) ddr2 = 1; + + /* Note it might be easier to use byte 31 here, it has the DIMM size as + * a multiple of 4MB. The way we do it now we can size both + * sides of an assymetric dimm. + */ + value = spd_read_byte(device, 3); /* rows */ + if (value < 0) goto hw_err; + if ((value & 0xf) == 0) goto val_err; + sz.side1 += value & 0xf; + + value = spd_read_byte(device, 4); /* columns */ + if (value < 0) goto hw_err; + if ((value & 0xf) == 0) goto val_err; + sz.side1 += value & 0xf; + + value = spd_read_byte(device, 17); /* banks */ + if (value < 0) goto hw_err; + if ((value & 0xff) == 0) goto val_err; + sz.side1 += log2(value & 0xff); + + /* Get the module data width and convert it to a power of two */ + value = spd_read_byte(device, 7); /* (high byte) */ + if (value < 0) goto hw_err; + value &= 0xff; + value <<= 8; + + low = spd_read_byte(device, 6); /* (low byte) */ + if (low < 0) goto hw_err; + value = value | (low & 0xff); + if ((value != 72) && (value != 64)) goto val_err; + sz.side1 += log2(value); + + /* side 2 */ + value = spd_read_byte(device, 5); /* number of physical banks */ + + if (value < 0) goto hw_err; + value &= 7; + if(ddr2) value++; + if (value == 1) goto out; + if (value != 2) goto val_err; + + /* Start with the symmetrical case */ + sz.side2 = sz.side1; + + value = spd_read_byte(device, 3); /* rows */ + if (value < 0) goto hw_err; + if ((value & 0xf0) == 0) goto out; /* If symmetrical we are done */ + sz.side2 -= (value & 0x0f); /* Subtract out rows on side 1 */ + sz.side2 += ((value >> 4) & 0x0f); /* Add in rows on side 2 */ + + value = spd_read_byte(device, 4); /* columns */ + if (value < 0) goto hw_err; + if ((value & 0xff) == 0) goto val_err; + sz.side2 -= (value & 0x0f); /* Subtract out columns on side 1 */ + sz.side2 += ((value >> 4) & 0x0f); /* Add in columsn on side 2 */ + goto out; + + val_err: + die("Bad SPD value\r\n"); + /* If an hw_error occurs report that I have no memory */ +hw_err: + sz.side1 = 0; + sz.side2 = 0; + out: + return sz; + +} + +static long spd_set_ram_size(const struct mem_controller *ctrl, long dimm_mask) +{ + int i; + int cum; + + for(i = cum = 0; i < DIMM_SOCKETS; i++) { + struct dimm_size sz; + if (dimm_mask & (1 << i)) { + sz = spd_get_dimm_size(ctrl->channel0[i]); + if (sz.side1 < 29) { + return -1; /* Report SPD error */ + } + /* convert bits to multiples of 64MB */ + sz.side1 -= 29; + cum += (1 << sz.side1); + /* DRB = 0x60 */ + pci_write_config8(ctrl->f0, DRB + (i*2), cum); + if( sz.side2 > 28) { + sz.side2 -= 29; + cum += (1 << sz.side2); + } + pci_write_config8(ctrl->f0, DRB+1 + (i*2), cum); + } + else { + pci_write_config8(ctrl->f0, DRB + (i*2), cum); + pci_write_config8(ctrl->f0, DRB+1 + (i*2), cum); + } + } + /* set TOM top of memory 0xcc */ + pci_write_config16(ctrl->f0, TOM, cum); + /* set TOLM top of low memory */ + if(cum > 0x18) { + cum = 0x18; + } + cum <<= 11; + /* 0xc4 TOLM */ + pci_write_config16(ctrl->f0, TOLM, cum); + return 0; +} + + +static unsigned int spd_detect_dimms(const struct mem_controller *ctrl) +{ + unsigned dimm_mask; + int i; + dimm_mask = 0; + for(i = 0; i < DIMM_SOCKETS; i++) { + int byte; + unsigned device; + device = ctrl->channel0[i]; + if (device) { + byte = spd_read_byte(device, 2); /* Type */ + if ((byte == 7) || (byte == 8)) { + dimm_mask |= (1 << i); + } + } + device = ctrl->channel1[i]; + if (device) { + byte = spd_read_byte(device, 2); + if ((byte == 7) || (byte == 8)) { + dimm_mask |= (1 << (i + DIMM_SOCKETS)); + } + } + } + return dimm_mask; +} + + +static int spd_set_row_attributes(const struct mem_controller *ctrl, + long dimm_mask) +{ + + int value; + int reg; + int dra; + int cnt; + + dra = 0; + for(cnt=0; cnt < 4; cnt++) { + if (!(dimm_mask & (1 << cnt))) { + continue; + } + reg =0; + value = spd_read_byte(ctrl->channel0[cnt], 3); /* rows */ + if (value < 0) goto hw_err; + if ((value & 0xf) == 0) goto val_err; + reg += value & 0xf; + + value = spd_read_byte(ctrl->channel0[cnt], 4); /* columns */ + if (value < 0) goto hw_err; + if ((value & 0xf) == 0) goto val_err; + reg += value & 0xf; + + value = spd_read_byte(ctrl->channel0[cnt], 17); /* banks */ + if (value < 0) goto hw_err; + if ((value & 0xff) == 0) goto val_err; + reg += log2(value & 0xff); + + /* Get the device width and convert it to a power of two */ + value = spd_read_byte(ctrl->channel0[cnt], 13); + if (value < 0) goto hw_err; + value = log2(value & 0xff); + reg += value; + if(reg < 27) goto hw_err; + reg -= 27; + reg += (value << 2); + + dra += reg << (cnt*8); + value = spd_read_byte(ctrl->channel0[cnt], 5); + if (value & 2) + dra += reg << ((cnt*8)+4); + } + + /* 0x70 DRA */ + pci_write_config32(ctrl->f0, DRA, dra); + goto out; + + val_err: + die("Bad SPD value\r\n"); + /* If an hw_error occurs report that I have no memory */ +hw_err: + dra = 0; + out: + return dra; + +} + + +static int spd_set_drt_attributes(const struct mem_controller *ctrl, + long dimm_mask, uint32_t drc) +{ + int value; + int reg; + uint32_t drt; + int cnt; + int first_dimm; + int cas_latency=0; + int latency; + uint32_t index = 0; + uint32_t index2 = 0; + static const unsigned char cycle_time[3] = {0x75,0x60,0x50}; + static const int latency_indicies[] = { 26, 23, 9 }; + + /* 0x78 DRT */ + drt = pci_read_config32(ctrl->f0, DRT); + drt &= 3; /* save bits 1:0 */ + + for(first_dimm = 0; first_dimm < 4; first_dimm++) { + if (dimm_mask & (1 << first_dimm)) + break; + } + + /* get dimm type */ + value = spd_read_byte(ctrl->channel0[first_dimm], 2); + if(value == 8) { + drt |= (3<<5); /* back to bark write turn around & cycle add */ + } + + drt |= (3<<18); /* Trasmax */ + + for(cnt=0; cnt < 4; cnt++) { + if (!(dimm_mask & (1 << cnt))) { + continue; + } + reg = spd_read_byte(ctrl->channel0[cnt], 18); /* CAS Latency */ + /* Compute the lowest cas latency supported */ + latency = log2(reg) -2; + + /* Loop through and find a fast clock with a low latency */ + for(index = 0; index < 3; index++, latency++) { + if ((latency < 2) || (latency > 4) || + (!(reg & (1 << latency)))) { + continue; + } + value = spd_read_byte(ctrl->channel0[cnt], + latency_indicies[index]); + + if(value <= cycle_time[drc&3]) { + if( latency > cas_latency) { + cas_latency = latency; + } + break; + } + } + } + index = (cas_latency-2); + if((index)==0) cas_latency = 20; + else if((index)==1) cas_latency = 25; + else cas_latency = 30; + + for(cnt=0;cnt<4;cnt++) { + if (!(dimm_mask & (1 << cnt))) { + continue; + } + reg = spd_read_byte(ctrl->channel0[cnt], 27)&0x0ff; + if(((index>>8)&0x0ff)<reg) { + index &= ~(0x0ff << 8); + index |= (reg << 8); + } + reg = spd_read_byte(ctrl->channel0[cnt], 28)&0x0ff; + if(((index>>16)&0x0ff)<reg) { + index &= ~(0x0ff << 16); + index |= (reg<<16); + } + reg = spd_read_byte(ctrl->channel0[cnt], 29)&0x0ff; + if(((index2>>0)&0x0ff)<reg) { + index2 &= ~(0x0ff << 0); + index2 |= (reg<<0); + } + reg = spd_read_byte(ctrl->channel0[cnt], 41)&0x0ff; + if(((index2>>8)&0x0ff)<reg) { + index2 &= ~(0x0ff << 8); + index2 |= (reg<<8); + } + reg = spd_read_byte(ctrl->channel0[cnt], 42)&0x0ff; + if(((index2>>16)&0x0ff)<reg) { + index2 &= ~(0x0ff << 16); + index2 |= (reg<<16); + } + } + + /* get dimm speed */ + value = cycle_time[drc&3]; + if(value <= 0x50) { /* 200 MHz */ + if((index&7) > 2) { + drt |= (2<<2); /* CAS latency 4 */ + cas_latency = 40; + } else { + drt |= (1<<2); /* CAS latency 3 */ + cas_latency = 30; + } + if((index&0x0ff00)<=0x03c00) { + drt |= (1<<8); /* Trp RAS Precharg */ + } else { + drt |= (2<<8); /* Trp RAS Precharg */ + } + + /* Trcd RAS to CAS delay */ + if((index2&0x0ff)<=0x03c) { + drt |= (0<<10); + } else { + drt |= (1<<10); + } + + /* Tdal Write auto precharge recovery delay */ + drt |= (1<<12); + + /* Trc TRS min */ + if((index2&0x0ff00)<=0x03700) + drt |= (0<<14); + else if((index2&0xff00)<=0x03c00) + drt |= (1<<14); + else + drt |= (2<<14); /* spd 41 */ + + drt |= (2<<16); /* Twr not defined for DDR docs say use 2 */ + + /* Trrd Row Delay */ + if((index&0x0ff0000)<=0x0140000) { + drt |= (0<<20); + } else if((index&0x0ff0000)<=0x0280000) { + drt |= (1<<20); + } else if((index&0x0ff0000)<=0x03c0000) { + drt |= (2<<20); + } else { + drt |= (3<<20); + } + + /* Trfc Auto refresh cycle time */ + if((index2&0x0ff0000)<=0x04b0000) { + drt |= (0<<22); + } else if((index2&0x0ff0000)<=0x0690000) { + drt |= (1<<22); + } else { + drt |= (2<<22); + } + /* Docs say use 55 for all 200Mhz */ + drt |= (0x055<<24); + } + else if(value <= 0x60) { /* 167 Mhz */ + /* according to new documentation CAS latency is 00 + * for bits 3:2 for all 167 Mhz + drt |= ((index&3)<<2); */ /* set CAS latency */ + if((index&0x0ff00)<=0x03000) { + drt |= (1<<8); /* Trp RAS Precharg */ + } else { + drt |= (2<<8); /* Trp RAS Precharg */ + } + + /* Trcd RAS to CAS delay */ + if((index2&0x0ff)<=0x030) { + drt |= (0<<10); + } else { + drt |= (1<<10); + } + + /* Tdal Write auto precharge recovery delay */ + drt |= (2<<12); + + /* Trc TRS min */ + drt |= (2<<14); /* spd 41, but only one choice */ + + drt |= (2<<16); /* Twr not defined for DDR docs say 2 */ + + /* Trrd Row Delay */ + if((index&0x0ff0000)<=0x0180000) { + drt |= (0<<20); + } else if((index&0x0ff0000)<=0x0300000) { + drt |= (1<<20); + } else { + drt |= (2<<20); + } + + /* Trfc Auto refresh cycle time */ + if((index2&0x0ff0000)<=0x0480000) { + drt |= (0<<22); + } else if((index2&0x0ff0000)<=0x0780000) { + drt |= (2<<22); + } else { + drt |= (2<<22); + } + /* Docs state to use 99 for all 167 Mhz */ + drt |= (0x099<<24); + } + else if(value <= 0x75) { /* 133 Mhz */ + drt |= ((index&3)<<2); /* set CAS latency */ + if((index&0x0ff00)<=0x03c00) { + drt |= (1<<8); /* Trp RAS Precharg */ + } else { + drt |= (2<<8); /* Trp RAS Precharg */ + } + + /* Trcd RAS to CAS delay */ + if((index2&0x0ff)<=0x03c) { + drt |= (0<<10); + } else { + drt |= (1<<10); + } + + /* Tdal Write auto precharge recovery delay */ + drt |= (1<<12); + + /* Trc TRS min */ + drt |= (2<<14); /* spd 41, but only one choice */ + + drt |= (1<<16); /* Twr not defined for DDR docs say 1 */ + + /* Trrd Row Delay */ + if((index&0x0ff0000)<=0x01e0000) { + drt |= (0<<20); + } else if((index&0x0ff0000)<=0x03c0000) { + drt |= (1<<20); + } else { + drt |= (2<<20); + } + + /* Trfc Auto refresh cycle time */ + if((index2&0x0ff0000)<=0x04b0000) { + drt |= (0<<22); + } else if((index2&0x0ff0000)<=0x0780000) { + drt |= (2<<22); + } else { + drt |= (2<<22); + } + + /* Based on CAS latency */ + if(index&7) + drt |= (0x099<<24); + else + drt |= (0x055<<24); + + } + else { + die("Invalid SPD 9 bus speed.\r\n"); + } + + /* 0x78 DRT */ + pci_write_config32(ctrl->f0, DRT, drt); + + return(cas_latency); +} + +static int spd_set_dram_controller_mode(const struct mem_controller *ctrl, + long dimm_mask) +{ + int value; + int reg; + int drc; + int cnt; + msr_t msr; + unsigned char dram_type = 0xff; + unsigned char ecc = 0xff; + unsigned char rate = 62; + static const unsigned char spd_rates[6] = {15,3,7,7,62,62}; + static const unsigned char drc_rates[5] = {0,15,7,62,3}; + static const unsigned char fsb_conversion[4] = {3,1,3,2}; + + /* 0x7c DRC */ + drc = pci_read_config32(ctrl->f0, DRC); + for(cnt=0; cnt < 4; cnt++) { + if (!(dimm_mask & (1 << cnt))) { + continue; + } + value = spd_read_byte(ctrl->channel0[cnt], 11); /* ECC */ + reg = spd_read_byte(ctrl->channel0[cnt], 2); /* Type */ + if (value == 2) { /* RAM is ECC capable */ + if (reg == 8) { + if ( ecc == 0xff ) { + ecc = 2; + } + else if (ecc == 1) { + die("ERROR - Mixed DDR & DDR2 RAM\r\n"); + } + } + else if ( reg == 7 ) { + if ( ecc == 0xff) { + ecc = 1; + } + else if ( ecc > 1 ) { + die("ERROR - Mixed DDR & DDR2 RAM\r\n"); + } + } + else { + die("ERROR - RAM not DDR\r\n"); + } + } + else { + die("ERROR - Non ECC memory dimm\r\n"); + } + + value = spd_read_byte(ctrl->channel0[cnt], 12); /*refresh rate*/ + value &= 0x0f; /* clip self refresh bit */ + if (value > 5) goto hw_err; + if (rate > spd_rates[value]) + rate = spd_rates[value]; + + value = spd_read_byte(ctrl->channel0[cnt], 9); /* cycle time */ + if (value > 0x75) goto hw_err; + if (value <= 0x50) { + if (dram_type >= 2) { + if (reg == 8) { /*speed is good, is this ddr2?*/ + dram_type = 2; + } else { /* not ddr2 so use ddr333 */ + dram_type = 1; + } + } + } + else if (value <= 0x60) { + if (dram_type >= 1) dram_type = 1; + } + else dram_type = 0; /* ddr266 */ + + } + ecc = 2; + if (read_option(CMOS_VSTART_ECC_memory,CMOS_VLEN_ECC_memory,1) == 0) { + ecc = 0; /* ECC off in CMOS so disable it */ + print_debug("ECC off\r\n"); + } + else { + print_debug("ECC on\r\n"); + } + drc &= ~(3 << 20); /* clear the ecc bits */ + drc |= (ecc << 20); /* or in the calculated ecc bits */ + for ( cnt = 1; cnt < 5; cnt++) + if (drc_rates[cnt] == rate) + break; + if (cnt < 5) { + drc &= ~(7 << 8); /* clear the rate bits */ + drc |= (cnt << 8); + } + + if (reg == 8) { /* independant clocks */ + drc |= (1 << 4); + } + + drc |= (1 << 26); /* set the overlap bit - the factory BIOS does */ + drc |= (1 << 27); /* set DED retry enable - the factory BIOS does */ + /* front side bus */ + msr = rdmsr(0x2c); + value = msr.lo >> 16; + value &= 0x03; + drc &= ~(3 << 2); /* set the front side bus */ + drc |= (fsb_conversion[value] << 2); + drc &= ~(3 << 0); /* set the dram type */ + drc |= (dram_type << 0); + + goto out; + + val_err: + die("Bad SPD value\r\n"); + /* If an hw_error occurs report that I have no memory */ +hw_err: + drc = 0; + out: + return drc; +} + +static void sdram_set_spd_registers(const struct mem_controller *ctrl) +{ + long dimm_mask; + + /* Test if we can read the spd and if ram is ddr or ddr2 */ + dimm_mask = spd_detect_dimms(ctrl); + if (!(dimm_mask & ((1 << DIMM_SOCKETS) - 1))) { + print_err("No memory for this cpu\r\n"); + return; + } + return; +} + +static void do_delay(void) +{ + int i; + unsigned char b; + for(i=0;i<16;i++) + b=inb(0x80); +} + +#define TIMEOUT_LOOPS 300000 + +#define DCALCSR 0x100 +#define DCALADDR 0x104 +#define DCALDATA 0x108 + +static void set_on_dimm_termination_enable(const struct mem_controller *ctrl) +{ + unsigned char c1,c2; + unsigned int dimm,i; + unsigned int data32; + unsigned int t4; + + /* Set up northbridge values */ + /* ODT enable */ + pci_write_config32(ctrl->f0, 0x88, 0xf0000180); + /* Figure out which slots are Empty, Single, or Double sided */ + for(i=0,t4=0,c2=0;i<8;i+=2) { + c1 = pci_read_config8(ctrl->f0, DRB+i); + if(c1 == c2) continue; + c2 = pci_read_config8(ctrl->f0, DRB+1+i); + if(c1 == c2) + t4 |= (1 << (i*4)); + else + t4 |= (2 << (i*4)); + } + for(i=0;i<1;i++) { + if((t4&0x0f) == 1) { + if( ((t4>>8)&0x0f) == 0 ) { + data32 = 0x00000010; /* EEES */ + break; + } + if ( ((t4>>16)&0x0f) == 0 ) { + data32 = 0x00003132; /* EESS */ + break; + } + if ( ((t4>>24)&0x0f) == 0 ) { + data32 = 0x00335566; /* ESSS */ + break; + } + data32 = 0x77bbddee; /* SSSS */ + break; + } + if((t4&0x0f) == 2) { + if( ((t4>>8)&0x0f) == 0 ) { + data32 = 0x00003132; /* EEED */ + break; + } + if ( ((t4>>8)&0x0f) == 2 ) { + data32 = 0xb373ecdc; /* EEDD */ + break; + } + if ( ((t4>>16)&0x0f) == 0 ) { + data32 = 0x00b3a898; /* EESD */ + break; + } + data32 = 0x777becdc; /* ESSD */ + break; + } + die("Error - First dimm slot empty\r\n"); + } + + print_debug("ODT Value = "); + print_debug_hex32(data32); + print_debug("\r\n"); + + pci_write_config32(ctrl->f0, 0xb0, data32); + + for(dimm=0;dimm<8;dimm+=1) { + + write32(BAR+DCALADDR, 0x0b840001); + write32(BAR+DCALCSR, 0x83000003 | (dimm << 20)); + + for(i=0;i<1001;i++) { + data32 = read32(BAR+DCALCSR); + if(!(data32 & (1<<31))) + break; + } + } +} +static void set_receive_enable(const struct mem_controller *ctrl) +{ + unsigned int i; + unsigned int cnt,bit; + uint32_t recena=0; + uint32_t recenb=0; + + { + unsigned int dimm; + unsigned int edge; + int32_t data32; + uint32_t data32_dram; + uint32_t dcal_data32_0; + uint32_t dcal_data32_1; + uint32_t dcal_data32_2; + uint32_t dcal_data32_3; + uint32_t work32l; + uint32_t work32h; + uint32_t data32r; + int32_t recen; + for(dimm=0;dimm<8;dimm+=1) { + + if(!(dimm&1)) { + write32(BAR+DCALDATA+(17*4), 0x04020000); + write32(BAR+DCALCSR, 0x83800004 | (dimm << 20)); + + for(i=0;i<1001;i++) { + data32 = read32(BAR+DCALCSR); + if(!(data32 & (1<<31))) + break; + } + if(i>=1000) + continue; + + dcal_data32_0 = read32(BAR+DCALDATA + 0); + dcal_data32_1 = read32(BAR+DCALDATA + 4); + dcal_data32_2 = read32(BAR+DCALDATA + 8); + dcal_data32_3 = read32(BAR+DCALDATA + 12); + } + else { + dcal_data32_0 = read32(BAR+DCALDATA + 16); + dcal_data32_1 = read32(BAR+DCALDATA + 20); + dcal_data32_2 = read32(BAR+DCALDATA + 24); + dcal_data32_3 = read32(BAR+DCALDATA + 28); + } + + /* check if bank is installed */ + if((dcal_data32_0 == 0) && (dcal_data32_2 == 0)) + continue; + /* Calculate the timing value */ + for(i=0,edge=0,bit=63,cnt=31,data32r=0, + work32l=dcal_data32_1,work32h=dcal_data32_3; + (i<4) && bit; i++) { + for(;;bit--,cnt--) { + if(work32l & (1<<cnt)) + break; + if(!cnt) { + work32l = dcal_data32_0; + work32h = dcal_data32_2; + cnt = 32; + } + if(!bit) break; + } + for(;;bit--,cnt--) { + if(!(work32l & (1<<cnt))) + break; + if(!cnt) { + work32l = dcal_data32_0; + work32h = dcal_data32_2; + cnt = 32; + } + if(!bit) break; + } + if(!bit) { + break; + } + data32 = ((bit%8) << 1); + if(work32h & (1<<cnt)) + data32 += 1; + if(data32 < 4) { + if(!edge) { + edge = 1; + } + else { + if(edge != 1) { + data32 = 0x0f; + } + } + } + if(data32 > 12) { + if(!edge) { + edge = 2; + } + else { + if(edge != 2) { + data32 = 0x00; + } + } + } + data32r += data32; + } + + work32l = dcal_data32_0; + work32h = dcal_data32_2; + recen = data32r; + recen += 3; + recen = recen>>2; + for(cnt=5;cnt<24;) { + for(;;cnt++) + if(!(work32l & (1<<cnt))) + break; + for(;;cnt++) { + if(work32l & (1<<cnt)) + break; + } + data32 = (((cnt-1)%8)<<1); + if(work32h & (1<<(cnt-1))) { + data32++; + } + /* test for frame edge cross overs */ + if((edge == 1) && (data32 > 12) && + (((recen+16)-data32) < 3)) { + data32 = 0; + cnt += 2; + } + if((edge == 2) && (data32 < 4) && + ((recen - data32) > 12)) { + data32 = 0x0f; + cnt -= 2; + } + if(((recen+3) >= data32) && ((recen-3) <= data32)) + break; + } + cnt--; + cnt /= 8; + cnt--; + if(recen&1) + recen+=2; + recen >>= 1; + recen += (cnt*8); + recen+=2; + recen <<= (dimm/2) * 8; + if(!(dimm&1)) { + recena |= recen; + } + else { + recenb |= recen; + } + } + } + /* Check for Eratta problem */ + for(i=cnt=bit=0;i<4;i++) { + if (((recena>>(i*8))&0x0f)>7) { + cnt++; bit++; + } + else { + if((recena>>(i*8))&0x0f) { + cnt++; + } + } + } + if(bit) { + cnt-=bit; + if(cnt>1) { + for(i=0;i<4;i++) { + if(((recena>>(i*8))&0x0f)>7) { + recena &= ~(0x0f<<(i*8)); + recena |= (7<<(i*8)); + } + } + } + else { + for(i=0;i<4;i++) { + if(((recena>>(i*8))&0x0f)<8) { + recena &= ~(0x0f<<(i*8)); + recena |= (8<<(i*8)); + } + } + } + } + for(i=cnt=bit=0;i<4;i++) { + if (((recenb>>(i*8))&0x0f)>7) { + cnt++; bit++; + } + else { + if((recenb>>(i*8))&0x0f) { + cnt++; + } + } + } + if(bit) { + cnt-=bit; + if(cnt>1) { + for(i=0;i<4;i++) { + if(((recenb>>(i*8))&0x0f)>7) { + recenb &= ~(0x0f<<(i*8)); + recenb |= (7<<(i*8)); + } + } + } + else { + for(i=0;i<4;i++) { + if(((recenb>>(i*8))&0x0f)<8) { + recenb &= ~(0x0f<<(i*8)); + recenb |= (8<<(i*8)); + } + } + } + } + +// recena = 0x0000090a; +// recenb = 0x0000090a; + + print_debug("Receive enable A = "); + print_debug_hex32(recena); + print_debug(", Receive enable B = "); + print_debug_hex32(recenb); + print_debug("\r\n"); + + /* clear out the calibration area */ + write32(BAR+DCALDATA+(16*4), 0x00000000); + write32(BAR+DCALDATA+(17*4), 0x00000000); + write32(BAR+DCALDATA+(18*4), 0x00000000); + write32(BAR+DCALDATA+(19*4), 0x00000000); + + /* No command */ + write32(BAR+DCALCSR, 0x0000000f); + + write32(BAR+0x150, recena); + write32(BAR+0x154, recenb); +} + + +static void sdram_enable(int controllers, const struct mem_controller *ctrl) +{ + int i; + int cs; + int cnt; + int cas_latency; + long mask; + uint32_t drc; + uint32_t data32; + uint32_t mode_reg; + uint32_t *iptr; + volatile unsigned long *iptrv; + msr_t msr; + uint32_t scratch; + uint8_t byte; + uint16_t data16; + static const struct { + uint32_t clkgr[4]; + } gearing [] = { + /* FSB 133 DIMM 266 */ + {{ 0x00000001, 0x00000000, 0x00000001, 0x00000000}}, + /* FSB 133 DIMM 333 */ + {{ 0x00000000, 0x00000000, 0x00000000, 0x00000000}}, + /* FSB 133 DIMM 400 */ + {{ 0x00000120, 0x00000000, 0x00000032, 0x00000010}}, + /* FSB 167 DIMM 266 */ + {{ 0x00005432, 0x00001000, 0x00004325, 0x00000000}}, + /* FSB 167 DIMM 333 */ + {{ 0x00000001, 0x00000000, 0x00000001, 0x00000000}}, + /* FSB 167 DIMM 400 */ + {{ 0x00154320, 0x00000000, 0x00065432, 0x00010000}}, + /* FSB 200 DIMM 266 */ + {{ 0x00000032, 0x00000010, 0x00000120, 0x00000000}}, + /* FSB 200 DIMM 333 */ + {{ 0x00065432, 0x00010000, 0x00054326, 0x00000000}}, + /* FSB 200 DIMM 400 */ + {{ 0x00000001, 0x00000000, 0x00000001, 0x00000000}}, + }; + + static const uint32_t dqs_data[] = { + 0xffffffff, 0xffffffff, 0x000000ff, + 0xffffffff, 0xffffffff, 0x000000ff, + 0xffffffff, 0xffffffff, 0x000000ff, + 0xffffffff, 0xffffffff, 0x000000ff, + 0xffffffff, 0xffffffff, 0x000000ff, + 0xffffffff, 0xffffffff, 0x000000ff, + 0xffffffff, 0xffffffff, 0x000000ff, + 0xffffffff, 0xffffffff, 0x000000ff}; + + mask = spd_detect_dimms(ctrl); + print_debug("Starting SDRAM Enable\r\n"); + + /* 0x80 */ +#ifdef DIMM_MAP_LOGICAL + pci_write_config32(ctrl->f0, DRM, + 0x00210000 | DIMM_MAP_LOGICAL); +#else + pci_write_config32(ctrl->f0, DRM, 0x00211248); +#endif + /* set dram type and Front Side Bus freq. */ + drc = spd_set_dram_controller_mode(ctrl, mask); + if( drc == 0) { + die("Error calculating DRC\r\n"); + } + data32 = drc & ~(3 << 20); /* clear ECC mode */ + data32 = data32 & ~(7 << 8); /* clear refresh rates */ + data32 = data32 | (1 << 5); /* temp turn off of ODT */ + /* Set gearing, then dram controller mode */ + /* drc bits 1:0 = DIMM speed, bits 3:2 = FSB speed */ + for(iptr = gearing[(drc&3)+((((drc>>2)&3)-1)*3)].clkgr,cnt=0; + cnt<4;cnt++) { + pci_write_config32(ctrl->f0, 0xa0+(cnt*4), iptr[cnt]); + } + /* 0x7c DRC */ + pci_write_config32(ctrl->f0, DRC, data32); + + /* turn the clocks on */ + /* 0x8c CKDIS */ + pci_write_config16(ctrl->f0, CKDIS, 0x0000); + + /* 0x9a DDRCSR Take subsystem out of idle */ + data16 = pci_read_config16(ctrl->f0, DDRCSR); + data16 &= ~(7 << 12); + data16 |= (3 << 12); /* use dual channel lock step */ + pci_write_config16(ctrl->f0, DDRCSR, data16); + + /* program row size DRB */ + spd_set_ram_size(ctrl, mask); + + /* program page size DRA */ + spd_set_row_attributes(ctrl, mask); + + /* program DRT timing values */ + cas_latency = spd_set_drt_attributes(ctrl, mask, drc); + + for(i=0;i<8;i++) { /* loop throught each dimm to test for row */ + print_debug("DIMM "); + print_debug_hex8(i); + print_debug("\r\n"); + /* Apply NOP */ + do_delay(); + + write32(BAR + 0x100, (0x03000000 | (i<<20))); + + write32(BAR+0x100, (0x83000000 | (i<<20))); + + data32 = read32(BAR+DCALCSR); + while(data32 & 0x80000000) + data32 = read32(BAR+DCALCSR); + + } + + /* Apply NOP */ + do_delay(); + + for(cs=0;cs<8;cs++) { + write32(BAR + DCALCSR, (0x83000000 | (cs<<20))); + data32 = read32(BAR+DCALCSR); + while(data32 & 0x80000000) + data32 = read32(BAR+DCALCSR); + } + + /* Precharg all banks */ + do_delay(); + for(cs=0;cs<8;cs++) { + if ((drc & 3) == 2) /* DDR2 */ + write32(BAR+DCALADDR, 0x04000000); + else /* DDR1 */ + write32(BAR+DCALADDR, 0x00000000); + write32(BAR+DCALCSR, (0x83000002 | (cs<<20))); + data32 = read32(BAR+DCALCSR); + while(data32 & 0x80000000) + data32 = read32(BAR+DCALCSR); + } + + /* EMRS dll's enabled */ + do_delay(); + for(cs=0;cs<8;cs++) { + if ((drc & 3) == 2) /* DDR2 */ + /* fixme hard code AL additive latency */ + write32(BAR+DCALADDR, 0x0b940001); + else /* DDR1 */ + write32(BAR+DCALADDR, 0x00000001); + write32(BAR+DCALCSR, (0x83000003 | (cs<<20))); + data32 = read32(BAR+DCALCSR); + while(data32 & 0x80000000) + data32 = read32(BAR+DCALCSR); + } + /* MRS reset dll's */ + do_delay(); + if ((drc & 3) == 2) { /* DDR2 */ + if(cas_latency == 30) + mode_reg = 0x053a0000; + else + mode_reg = 0x054a0000; + } + else { /* DDR1 */ + if(cas_latency == 20) + mode_reg = 0x012a0000; + else /* CAS Latency 2.5 */ + mode_reg = 0x016a0000; + } + for(cs=0;cs<8;cs++) { + write32(BAR+DCALADDR, mode_reg); + write32(BAR+DCALCSR, (0x83000003 | (cs<<20))); + data32 = read32(BAR+DCALCSR); + while(data32 & 0x80000000) + data32 = read32(BAR+DCALCSR); + } + + /* Precharg all banks */ + do_delay(); + do_delay(); + do_delay(); + for(cs=0;cs<8;cs++) { + if ((drc & 3) == 2) /* DDR2 */ + write32(BAR+DCALADDR, 0x04000000); + else /* DDR1 */ + write32(BAR+DCALADDR, 0x00000000); + write32(BAR+DCALCSR, (0x83000002 | (cs<<20))); + data32 = read32(BAR+DCALCSR); + while(data32 & 0x80000000) + data32 = read32(BAR+DCALCSR); + } + + /* Do 2 refreshes */ + do_delay(); + for(cs=0;cs<8;cs++) { + write32(BAR+DCALCSR, (0x83000001 | (cs<<20))); + data32 = read32(BAR+DCALCSR); + while(data32 & 0x80000000) + data32 = read32(BAR+DCALCSR); + } + do_delay(); + for(cs=0;cs<8;cs++) { + write32(BAR+DCALCSR, (0x83000001 | (cs<<20))); + data32 = read32(BAR+DCALCSR); + while(data32 & 0x80000000) + data32 = read32(BAR+DCALCSR); + } + do_delay(); + /* for good luck do 6 more */ + for(cs=0;cs<8;cs++) { + write32(BAR+DCALCSR, (0x83000001 | (cs<<20))); + } + do_delay(); + for(cs=0;cs<8;cs++) { + write32(BAR+DCALCSR, (0x83000001 | (cs<<20))); + } + do_delay(); + for(cs=0;cs<8;cs++) { + write32(BAR+DCALCSR, (0x83000001 | (cs<<20))); + } + do_delay(); + for(cs=0;cs<8;cs++) { + write32(BAR+DCALCSR, (0x83000001 | (cs<<20))); + } + do_delay(); + for(cs=0;cs<8;cs++) { + write32(BAR+DCALCSR, (0x83000001 | (cs<<20))); + } + do_delay(); + for(cs=0;cs<8;cs++) { + write32(BAR+DCALCSR, (0x83000001 | (cs<<20))); + } + do_delay(); + /* MRS reset dll's normal */ + do_delay(); + for(cs=0;cs<8;cs++) { + write32(BAR+DCALADDR, (mode_reg & ~(1<<24))); + write32(BAR+DCALCSR, (0x83000003 | (cs<<20))); + data32 = read32(BAR+DCALCSR); + while(data32 & 0x80000000) + data32 = read32(BAR+DCALCSR); + } + + /* Do only if DDR2 EMRS dll's enabled */ + if ((drc & 3) == 2) { /* DDR2 */ + do_delay(); + for(cs=0;cs<8;cs++) { + write32(BAR+DCALADDR, (0x0b940001)); + write32(BAR+DCALCSR, (0x83000003 | (cs<<20))); + data32 = read32(BAR+DCALCSR); + while(data32 & 0x80000000) + data32 = read32(BAR+DCALCSR); + } + } + + do_delay(); + /* No command */ + write32(BAR+DCALCSR, 0x0000000f); + + /* DDR1 This is test code to copy some codes in the factory setup */ + + write32(BAR, 0x00100000); + + if ((drc & 3) == 2) { /* DDR2 */ + /* enable on dimm termination */ + set_on_dimm_termination_enable(ctrl); + } + + /* receive enable calibration */ + set_receive_enable(ctrl); + + /* DQS */ + pci_write_config32(ctrl->f0, 0x94, 0x3904a100 ); + for(i = 0, cnt = (BAR+0x200); i < 24; i++, cnt+=4) { + write32(cnt, dqs_data[i]); + } + pci_write_config32(ctrl->f0, 0x94, 0x3904a100 ); + + /* Enable refresh */ + /* 0x7c DRC */ + data32 = drc & ~(3 << 20); /* clear ECC mode */ + pci_write_config32(ctrl->f0, DRC, data32); + write32(BAR+DCALCSR, 0x0008000f); + + /* clear memory and init ECC */ + print_debug("Clearing memory\r\n"); + for(i=0;i<64;i+=4) { + write32(BAR+DCALDATA+i, 0x00000000); + } + + for(cs=0;cs<8;cs++) { + write32(BAR+DCALCSR, (0x830831d8 | (cs<<20))); + data32 = read32(BAR+DCALCSR); + while(data32 & 0x80000000) + data32 = read32(BAR+DCALCSR); + } + + /* Bring memory subsystem on line */ + data32 = pci_read_config32(ctrl->f0, 0x98); + data32 |= (1 << 31); + pci_write_config32(ctrl->f0, 0x98, data32); + /* wait for completion */ + print_debug("Waiting for mem complete\r\n"); + while(1) { + data32 = pci_read_config32(ctrl->f0, 0x98); + if( (data32 & (1<<31)) == 0) + break; + } + print_debug("Done\r\n"); + + /* Set initialization complete */ + /* 0x7c DRC */ + drc |= (1 << 29); + data32 = drc & ~(3 << 20); /* clear ECC mode */ + pci_write_config32(ctrl->f0, DRC, data32); + + /* Set the ecc mode */ + pci_write_config32(ctrl->f0, DRC, drc); + + /* Enable memory scrubbing */ + /* 0x52 MCHSCRB */ + data16 = pci_read_config16(ctrl->f0, MCHSCRB); + data16 &= ~0x0f; + data16 |= ((2 << 2) | (2 << 0)); + pci_write_config16(ctrl->f0, MCHSCRB, data16); + + /* The memory is now setup, use it */ + cache_lbmem(MTRR_TYPE_WRBACK); +} diff --git a/src/northbridge/intel/E7525/raminit.h b/src/northbridge/intel/E7525/raminit.h new file mode 100644 index 0000000000..183ace8385 --- /dev/null +++ b/src/northbridge/intel/E7525/raminit.h @@ -0,0 +1,12 @@ +#ifndef RAMINIT_H +#define RAMINIT_H + +#define DIMM_SOCKETS 4 +struct mem_controller { + unsigned node_id; + device_t f0, f1, f2, f3; + uint16_t channel0[DIMM_SOCKETS]; + uint16_t channel1[DIMM_SOCKETS]; +}; + +#endif /* RAMINIT_H */ diff --git a/src/northbridge/intel/E7525/raminit_test.c b/src/northbridge/intel/E7525/raminit_test.c new file mode 100644 index 0000000000..2d44d25403 --- /dev/null +++ b/src/northbridge/intel/E7525/raminit_test.c @@ -0,0 +1,393 @@ +#include <unistd.h> +#include <limits.h> +#include <stdint.h> +#include <string.h> +#include <setjmp.h> +#include <device/pci_def.h> +#include "e7525.h" + +jmp_buf end_buf; + +static int is_cpu_pre_c0(void) +{ + return 0; +} + +#define PCI_ADDR(BUS, DEV, FN, WHERE) ( \ + (((BUS) & 0xFF) << 16) | \ + (((DEV) & 0x1f) << 11) | \ + (((FN) & 0x07) << 8) | \ + ((WHERE) & 0xFF)) + +#define PCI_DEV(BUS, DEV, FN) ( \ + (((BUS) & 0xFF) << 16) | \ + (((DEV) & 0x1f) << 11) | \ + (((FN) & 0x7) << 8)) + +#define PCI_ID(VENDOR_ID, DEVICE_ID) \ + ((((DEVICE_ID) & 0xFFFF) << 16) | ((VENDOR_ID) & 0xFFFF)) + +typedef unsigned device_t; + +unsigned char pci_register[256*5*3*256]; + +static uint8_t pci_read_config8(device_t dev, unsigned where) +{ + unsigned addr; + addr = dev | where; + return pci_register[addr]; +} + +static uint16_t pci_read_config16(device_t dev, unsigned where) +{ + unsigned addr; + addr = dev | where; + return pci_register[addr] | (pci_register[addr + 1] << 8); +} + +static uint32_t pci_read_config32(device_t dev, unsigned where) +{ + unsigned addr; + uint32_t value; + addr = dev | where; + value = pci_register[addr] | + (pci_register[addr + 1] << 8) | + (pci_register[addr + 2] << 16) | + (pci_register[addr + 3] << 24); + + return value; + +} + +static void pci_write_config8(device_t dev, unsigned where, uint8_t value) +{ + unsigned addr; + addr = dev | where; + pci_register[addr] = value; +} + +static void pci_write_config16(device_t dev, unsigned where, uint16_t value) +{ + unsigned addr; + addr = dev | where; + pci_register[addr] = value & 0xff; + pci_register[addr + 1] = (value >> 8) & 0xff; +} + +static void pci_write_config32(device_t dev, unsigned where, uint32_t value) +{ + unsigned addr; + addr = dev | where; + pci_register[addr] = value & 0xff; + pci_register[addr + 1] = (value >> 8) & 0xff; + pci_register[addr + 2] = (value >> 16) & 0xff; + pci_register[addr + 3] = (value >> 24) & 0xff; +} + +#define PCI_DEV_INVALID (0xffffffffU) +static device_t pci_locate_device(unsigned pci_id, device_t dev) +{ + for(; dev <= PCI_DEV(255, 31, 7); dev += PCI_DEV(0,0,1)) { + unsigned int id; + id = pci_read_config32(dev, 0); + if (id == pci_id) { + return dev; + } + } + return PCI_DEV_INVALID; +} + + + + +static void uart_tx_byte(unsigned char data) +{ + write(STDOUT_FILENO, &data, 1); +} +static void hlt(void) +{ + longjmp(end_buf, 2); +} +#include "../../../arch/i386/lib/console.c" + +unsigned long log2(unsigned long x) +{ + // assume 8 bits per byte. + unsigned long i = 1 << (sizeof(x)*8 - 1); + unsigned long pow = sizeof(x) * 8 - 1; + + if (! x) { + static const char errmsg[] = " called with invalid parameter of 0\n"; + write(STDERR_FILENO, __func__, sizeof(__func__) - 1); + write(STDERR_FILENO, errmsg, sizeof(errmsg) - 1); + hlt(); + } + for(; i > x; i >>= 1, pow--) + ; + + return pow; +} + +typedef struct msr_struct +{ + unsigned lo; + unsigned hi; +} msr_t; + +static inline msr_t rdmsr(unsigned index) +{ + msr_t result; + result.lo = 0; + result.hi = 0; + return result; +} + +static inline void wrmsr(unsigned index, msr_t msr) +{ +} + +#include "raminit.h" + +#define SIO_BASE 0x2e + +static void hard_reset(void) +{ + /* FIXME implement the hard reset case... */ + longjmp(end_buf, 3); +} + +static void memreset_setup(void) +{ + /* Nothing to do */ +} + +static void memreset(int controllers, const struct mem_controller *ctrl) +{ + /* Nothing to do */ +} + +static inline void activate_spd_rom(const struct mem_controller *ctrl) +{ + /* nothing to do */ +} + + +static uint8_t spd_mt4lsdt464a[256] = +{ + 0x80, 0x08, 0x04, 0x0C, 0x08, 0x01, 0x40, 0x00, 0x01, 0x70, + 0x54, 0x00, 0x80, 0x10, 0x00, 0x01, 0x8F, 0x04, 0x06, 0x01, + 0x01, 0x00, 0x0E, 0x75, 0x54, 0x00, 0x00, 0x0F, 0x0E, 0x0F, + + 0x25, 0x08, 0x15, 0x08, 0x15, 0x08, 0x00, 0x12, 0x01, 0x4E, + 0x9C, 0xE4, 0xB7, 0x46, 0x2C, 0xFF, 0x01, 0x02, 0x03, 0x04, + 0x05, 0x06, 0x07, 0x08, 0x09, 0x01, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0x08, 0x09, 0x00, +}; + +static uint8_t spd_micron_512MB_DDR333[256] = +{ + 0x80, 0x08, 0x07, 0x0d, 0x0b, 0x02, 0x48, 0x00, 0x04, 0x60, + 0x70, 0x02, 0x82, 0x04, 0x04, 0x01, 0x0e, 0x04, 0x0c, 0x01, + 0x02, 0x26, 0xc0, 0x75, 0x70, 0x00, 0x00, 0x48, 0x30, 0x48, + 0x2a, 0x80, 0x80, 0x80, 0x45, 0x45, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x3c, 0x48, 0x30, 0x28, 0x50, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x6f, 0x2c, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x01, 0x33, 0x36, 0x56, 0x44, 0x44, 0x46, 0x31, + 0x32, 0x38, 0x37, 0x32, 0x47, 0x2d, 0x33, 0x33, 0x35, 0x43, + 0x33, 0x03, 0x00, 0x03, 0x23, 0x17, 0x07, 0x5a, 0xb2, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}; + +static uint8_t spd_micron_256MB_DDR333[256] = +{ + 0x80, 0x08, 0x07, 0x0d, 0x0b, 0x01, 0x48, 0x00, 0x04, 0x60, + 0x70, 0x02, 0x82, 0x04, 0x04, 0x01, 0x0e, 0x04, 0x0c, 0x01, + 0x02, 0x26, 0xc0, 0x75, 0x70, 0x00, 0x00, 0x48, 0x30, 0x48, + 0x2a, 0x80, 0x80, 0x80, 0x45, 0x45, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x3c, 0x48, 0x30, 0x23, 0x50, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x58, 0x2c, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x01, 0x31, 0x38, 0x56, 0x44, 0x44, 0x46, 0x36, + 0x34, 0x37, 0x32, 0x47, 0x2d, 0x33, 0x33, 0x35, 0x43, 0x31, + 0x20, 0x01, 0x00, 0x03, 0x19, 0x17, 0x05, 0xb2, 0xf4, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +}; + +#define MAX_DIMMS 16 +static uint8_t spd_data[MAX_DIMMS*256]; + +static unsigned spd_count, spd_fail_count; +static int spd_read_byte(unsigned device, unsigned address) +{ + int result; + spd_count++; + if ((device < 0x50) || (device >= (0x50 +MAX_DIMMS))) { + result = -1; + } + else { + device -= 0x50; + + if (address > 256) { + result = -1; + } + else if (spd_data[(device << 8) | 2] != 7) { + result = -1; + } + else { + result = spd_data[(device << 8) | address]; + } + } + if (spd_count >= spd_fail_count) { + result = -1; + } + return result; +} + +#include "raminit.c" +#include "../../../sdram/generic_sdram.c" + +#define FIRST_CPU 1 +#define SECOND_CPU 1 +#define TOTAL_CPUS (FIRST_CPU + SECOND_CPU) +#if 0 +static void raminit_main(void) +{ + /* + * GPIO28 of 8111 will control H0_MEMRESET_L + * GPIO29 of 8111 will control H1_MEMRESET_L + */ + static const struct mem_controller cpu[] = { +#if FIRST_CPU + { + .node_id = 0, + .f0 = PCI_DEV(0, 0x18, 0), + .f1 = PCI_DEV(0, 0x18, 1), + .f2 = PCI_DEV(0, 0x18, 2), + .f3 = PCI_DEV(0, 0x18, 3), + .channel0 = { 0x50+0, 0x50+2, 0x50+4, 0x50+6 }, + .channel1 = { 0x50+1, 0x50+3, 0x50+5, 0x50+7 }, + }, +#endif +#if SECOND_CPU + { + .node_id = 1, + .f0 = PCI_DEV(0, 0x19, 0), + .f1 = PCI_DEV(0, 0x19, 1), + .f2 = PCI_DEV(0, 0x19, 2), + .f3 = PCI_DEV(0, 0x19, 3), + .channel0 = { 0x50+8, 0x50+10, 0x50+12, 0x50+14 }, + .channel1 = { 0x50+9, 0x50+11, 0x50+13, 0x50+15 }, + }, +#endif + }; + console_init(); + memreset_setup(); + sdram_initialize(sizeof(cpu)/sizeof(cpu[0]), cpu); + +} +#endif +static void reset_tests(void) +{ + /* Clear the results of any previous tests */ + memset(pci_register, 0, sizeof(pci_register)); + memset(spd_data, 0, sizeof(spd_data)); + spd_count = 0; + spd_fail_count = UINT_MAX; + + pci_write_config32(PCI_DEV(0, 0x18, 3), NORTHBRIDGE_CAP, + NBCAP_128Bit | + NBCAP_MP| NBCAP_BIG_MP | + /* NBCAP_ECC | NBCAP_CHIPKILL_ECC | */ + (NBCAP_MEMCLK_200MHZ << NBCAP_MEMCLK_SHIFT) | + NBCAP_MEMCTRL); + + pci_write_config32(PCI_DEV(0, 0x19, 3), NORTHBRIDGE_CAP, + NBCAP_128Bit | + NBCAP_MP| NBCAP_BIG_MP | + /* NBCAP_ECC | NBCAP_CHIPKILL_ECC | */ + (NBCAP_MEMCLK_200MHZ << NBCAP_MEMCLK_SHIFT) | + NBCAP_MEMCTRL); +} + +static void test1(void) +{ + reset_tests(); + + memcpy(&spd_data[0*256], spd_micron_512MB_DDR333, 256); + memcpy(&spd_data[1*256], spd_micron_512MB_DDR333, 256); +// raminit_main(); +} + + +static void do_test2(int i) +{ + jmp_buf tmp_buf; + memcpy(&tmp_buf, &end_buf, sizeof(end_buf)); + if (setjmp(end_buf) != 0) { + goto done; + } + reset_tests(); + spd_fail_count = i; + + print_debug("\r\nSPD will fail after: "); + print_debug_hex32(spd_fail_count); + print_debug(" accesses.\r\n"); + + memcpy(&spd_data[0*256], spd_micron_512MB_DDR333, 256); + memcpy(&spd_data[1*256], spd_micron_512MB_DDR333, 256); + +// raminit_main(); + + done: + memcpy(&end_buf, &tmp_buf, sizeof(end_buf)); +} + +static void test2(void) +{ + int i; + for(i = 0; i < 0x48; i++) { + do_test2(i); + } + +} + +int main(int argc, char **argv) +{ + if (setjmp(end_buf) != 0) { + return -1; + } + test1(); + test2(); + return 0; +} |