summaryrefslogtreecommitdiff
path: root/src/northbridge/amd/gx1
diff options
context:
space:
mode:
Diffstat (limited to 'src/northbridge/amd/gx1')
-rw-r--r--src/northbridge/amd/gx1/Config.lb2
-rw-r--r--src/northbridge/amd/gx1/chip.h5
-rw-r--r--src/northbridge/amd/gx1/northbridge.c213
-rw-r--r--src/northbridge/amd/gx1/northbridge.h6
-rw-r--r--src/northbridge/amd/gx1/raminit.c354
-rw-r--r--src/northbridge/amd/gx1/raminit.h11
6 files changed, 591 insertions, 0 deletions
diff --git a/src/northbridge/amd/gx1/Config.lb b/src/northbridge/amd/gx1/Config.lb
new file mode 100644
index 0000000000..4a0c2c8658
--- /dev/null
+++ b/src/northbridge/amd/gx1/Config.lb
@@ -0,0 +1,2 @@
+config chip.h
+object northbridge.o
diff --git a/src/northbridge/amd/gx1/chip.h b/src/northbridge/amd/gx1/chip.h
new file mode 100644
index 0000000000..00374568bb
--- /dev/null
+++ b/src/northbridge/amd/gx1/chip.h
@@ -0,0 +1,5 @@
+struct northbridge_amd_gx1_config
+{
+};
+
+extern struct chip_operations northbridge_amd_gx1_ops;
diff --git a/src/northbridge/amd/gx1/northbridge.c b/src/northbridge/amd/gx1/northbridge.c
new file mode 100644
index 0000000000..0966bf83ad
--- /dev/null
+++ b/src/northbridge/amd/gx1/northbridge.c
@@ -0,0 +1,213 @@
+#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 <stdlib.h>
+#include <string.h>
+#include <bitops.h>
+#include "chip.h"
+#include "northbridge.h"
+#include <cpu/amd/gx1def.h>
+
+#define NORTHBRIDGE_FILE "northbridge.c"
+/*
+*/
+
+static void optimize_xbus(device_t dev)
+{
+ /* Optimise X-Bus performance */
+ pci_write_config8(dev, 0x40, 0x1e);
+ pci_write_config8(dev, 0x41, 0x52);
+ pci_write_config8(dev, 0x43, 0xc1);
+ pci_write_config8(dev, 0x44, 0x00);
+}
+
+static void enable_shadow(device_t dev)
+{
+
+}
+
+static void northbridge_init(device_t dev)
+{
+ printk_debug("northbridge: %s()\n", __FUNCTION__);
+
+ optimize_xbus(dev);
+ enable_shadow(dev);
+}
+
+
+static struct device_operations northbridge_operations = {
+ .read_resources = pci_dev_read_resources,
+ .set_resources = pci_dev_set_resources,
+ .enable_resources = pci_dev_enable_resources,
+ .init = northbridge_init,
+ .enable = 0,
+ .ops_pci = 0,
+};
+
+static struct pci_driver northbridge_driver __pci_driver = {
+ .ops = &northbridge_operations,
+ .vendor = PCI_VENDOR_ID_CYRIX,
+ .device = PCI_DEVICE_ID_CYRIX_PCI_MASTER,
+};
+
+
+
+#define BRIDGE_IO_MASK (IORESOURCE_IO | IORESOURCE_MEM)
+
+static void pci_domain_read_resources(device_t dev)
+{
+ struct resource *resource;
+
+ printk_spew("%s:%s()\n", NORTHBRIDGE_FILE, __FUNCTION__);
+
+ /* Initialize the system wide io space constraints */
+ resource = new_resource(dev, IOINDEX_SUBTRACTIVE(0,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->limit = 0xffffffffULL;
+ resource->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED;
+}
+
+static void ram_resource(device_t dev, unsigned long index,
+ unsigned long basek, unsigned long sizek)
+{
+ struct resource *resource;
+
+ if (!sizek) {
+ return;
+ }
+ 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 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;
+}
+
+#define FRAMEBUFFERK 4096
+
+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]);
+ mc_dev = dev->link[0].children;
+ if (mc_dev) {
+ unsigned int tomk, tolmk;
+ unsigned int ramreg = 0;
+ int i, idx;
+ unsigned int *bcdramtop = (unsigned int *)(GX_BASE + BC_DRAM_TOP);
+ unsigned int *mcgbaseadd = (unsigned int *)(GX_BASE + MC_GBASE_ADD);
+
+ for(i=0; i<0x20; i+= 0x10) {
+ unsigned int *mcreg = (unsigned int *)(GX_BASE + MC_BANK_CFG);
+ unsigned int mem_config = *mcreg;
+
+ if (((mem_config & (DIMM_PG_SZ << i)) >> (4 + i)) == 7)
+ continue;
+ ramreg += 1 << (((mem_config & (DIMM_SZ << i)) >> (i + 8)) + 2);
+ }
+
+ tomk = ramreg << 10;
+
+ /* Sort out the framebuffer size */
+ tomk -= FRAMEBUFFERK;
+ *bcdramtop = ((tomk << 10) - 1);
+ *mcgbaseadd = (tomk >> 9);
+
+ printk_debug("BC_DRAM_TOP = 0x%08x\n", *bcdramtop);
+ printk_debug("MC_GBASE_ADD = 0x%08x\n", *mcgbaseadd);
+
+ printk_debug("I would set ram size to %d Mbytes\n", (tomk >> 10));
+
+ /* Compute the top of Low memory */
+ tolmk = pci_tolm >> 10;
+ if (tolmk >= tomk) {
+ /* The PCI hole does does not overlap the memory.
+ */
+ tolmk = tomk;
+ }
+ /* Report the memory regions */
+ idx = 10;
+ ram_resource(dev, idx++, 0, tolmk);
+ }
+ 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], PCI_DEVFN(0, 0), 0xff, 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,
+};
+
+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(struct device *dev)
+{
+ /* Set the operations if it is a special bus type */
+ if (dev->path.type == DEVICE_PATH_PCI_DOMAIN) {
+ dev->ops = &pci_domain_ops;
+ pci_set_method(dev);
+ }
+ else if (dev->path.type == DEVICE_PATH_APIC_CLUSTER) {
+ dev->ops = &cpu_bus_ops;
+ }
+}
+
+struct chip_operations northbridge_amd_gx1_ops = {
+ CHIP_NAME("AMD GX1 Northbridge")
+ .enable_dev = enable_dev,
+};
diff --git a/src/northbridge/amd/gx1/northbridge.h b/src/northbridge/amd/gx1/northbridge.h
new file mode 100644
index 0000000000..3e569bb31b
--- /dev/null
+++ b/src/northbridge/amd/gx1/northbridge.h
@@ -0,0 +1,6 @@
+#ifndef NORTHBRIDGE_INTEL_440BX_H
+#define NORTHBRIDGE_INTEL_440BX_H
+
+extern unsigned int i440bx_scan_root_bus(device_t root, unsigned int max);
+
+#endif /* NORTHBRIDGE_INTEL_440BX_H */
diff --git a/src/northbridge/amd/gx1/raminit.c b/src/northbridge/amd/gx1/raminit.c
new file mode 100644
index 0000000000..c4c29e9d97
--- /dev/null
+++ b/src/northbridge/amd/gx1/raminit.c
@@ -0,0 +1,354 @@
+#include <cpu/amd/gx1def.h>
+
+/*
+This software and ancillary information (herein called SOFTWARE )
+called LinuxBIOS is made available under the terms described
+here. The SOFTWARE has been approved for release with associated
+LA-CC Number 00-34 . Unless otherwise indicated, this SOFTWARE has
+been authored by an employee or employees of the University of
+California, operator of the Los Alamos National Laboratory under
+Contract No. W-7405-ENG-36 with the U.S. Department of Energy. The
+U.S. Government has rights to use, reproduce, and distribute this
+SOFTWARE. The public may copy, distribute, prepare derivative works
+and publicly display this SOFTWARE without charge, provided that this
+Notice and any statement of authorship are reproduced on all copies.
+Neither the Government nor the University makes any warranty, express
+or implied, or assumes any liability or responsibility for the use of
+this SOFTWARE. If SOFTWARE is modified to produce derivative works,
+such modified SOFTWARE should be clearly marked, so as not to confuse
+it with the version available from LANL.
+ */
+/* Copyright 2000, Ron Minnich, Advanced Computing Lab, LANL
+ * rminnich@lanl.gov
+ */
+
+/* SDRAM initialization for GX1 - translated from Christer Weinigel's
+ assembler version into C.
+
+ Hamish Guthrie 10/4/2005 hamish@prodigi.ch
+*/
+
+#define NUM_REFRESH 8
+#define TEST_DATA1 0x05A5A5A5A
+#define TEST_DATA2 0x0DEADBEEF
+
+void setGX1Mem(unsigned int addr, unsigned int data)
+{
+ writel(data, (volatile void *)addr);
+}
+
+unsigned int getGX1Mem(unsigned int addr)
+{
+ return (unsigned int)readl((const volatile void *)addr);
+}
+
+void do_refresh(void)
+{
+unsigned int tval, i;
+
+ post_code(0x71);
+ tval = getGX1Mem(GX_BASE + MC_MEM_CNTRL1);
+ tval |= RFSHTST;
+ for(i=0; i>NUM_REFRESH; i++)
+ setGX1Mem(GX_BASE + MC_MEM_CNTRL1, tval);
+ post_code(0x72);
+}
+
+
+void enable_dimm(void)
+{
+unsigned int tval, i;
+
+ post_code(0x73);
+
+ /* start SDCLCK's */
+ tval = getGX1Mem(GX_BASE + MC_MEM_CNTRL1);
+ tval &= ~SDCLKSTRT;
+ setGX1Mem(GX_BASE + MC_MEM_CNTRL1, tval);
+ tval |= SDCLKSTRT;
+ setGX1Mem(GX_BASE + MC_MEM_CNTRL1, tval);
+
+ /* Unmask SDCLK's */
+ tval = getGX1Mem(GX_BASE + MC_MEM_CNTRL2);
+ tval &= ~(SDCLK_MASK | SDCLKOUT_MASK);
+ setGX1Mem(GX_BASE + MC_MEM_CNTRL2, tval);
+ tval = getGX1Mem(GX_BASE + MC_MEM_CNTRL2);
+
+ /* Wait for clocks to unmask */
+ for(i=0; i<5000; i++)
+ outb(0, 0xed);
+
+ /* Refresh memory */
+ tval = getGX1Mem(GX_BASE + MC_MEM_CNTRL1);
+ tval |= RFSHTST;
+ for(i=0; i<NUM_REFRESH; i++)
+ setGX1Mem(GX_BASE + MC_MEM_CNTRL1, tval);
+ tval &= ~RFSHTST;
+
+ /* Start the SDCLK's */
+ tval &= ~PROGRAM_SDRAM;
+ setGX1Mem(GX_BASE + MC_MEM_CNTRL1, tval);
+ tval |= PROGRAM_SDRAM | 0x00002000; /* Set refresh timing */
+ setGX1Mem(GX_BASE + MC_MEM_CNTRL1, tval);
+ tval &= ~PROGRAM_SDRAM;
+ setGX1Mem(GX_BASE + MC_MEM_CNTRL1, tval);
+
+ /* Refresh memory again */
+ tval = getGX1Mem(GX_BASE + MC_MEM_CNTRL1);
+ tval |= RFSHTST;
+ for(i=0; i>NUM_REFRESH; i++)
+ setGX1Mem(GX_BASE + MC_MEM_CNTRL1, tval);
+
+ for(i=0; i<2000; i++)
+ outb(0, 0xed);
+ post_code(0x74);
+}
+
+static unsigned int size_dimm(int dimm_shift)
+{
+int bank_cfg = 0x700; /* MC_BANK_CFG for 512M */
+unsigned int offset = 0x10000000; /* Offset 256M */
+int failed_flag = 1;
+
+ do {
+ setGX1Mem(0, TEST_DATA1);
+ setGX1Mem(offset, TEST_DATA2);
+ setGX1Mem(0x100, 0); /* Clear the bus */
+ if (getGX1Mem(0) != TEST_DATA1) {
+ setGX1Mem(GX_BASE + MC_BANK_CFG,
+ getGX1Mem(GX_BASE + MC_BANK_CFG) & ~(DIMM_SZ << dimm_shift));
+ bank_cfg -= 0x100;
+ setGX1Mem(GX_BASE + MC_BANK_CFG,
+ getGX1Mem(GX_BASE + MC_BANK_CFG) | (bank_cfg << dimm_shift));
+ do_refresh();
+ offset >>= 1;
+ } else {
+ failed_flag = 0;
+ break;
+ }
+ } while (bank_cfg >= 0);
+
+ if (failed_flag)
+ return (0x0070 << dimm_shift);
+ else
+ return(getGX1Mem(GX_BASE + MC_BANK_CFG) & (DIMM_SZ << dimm_shift));
+
+}
+
+static unsigned int module_banks(int dimm_shift)
+{
+int page_size = 0x800; /* Smallest page = 1K * 2 banks */
+int comp_banks;
+
+#if 0
+ print_debug("MC_BANK_CFG = ");
+ print_debug_hex32(getGX1Mem(GX_BASE + MC_BANK_CFG));
+ print_debug("\r\n");
+#endif
+
+ /* retrieve the page size from the MC register */
+ page_size <<= (((getGX1Mem(GX_BASE + MC_BANK_CFG) & (DIMM_PG_SZ << dimm_shift)) >> dimm_shift) >> 4);
+
+#if 0
+ print_debug(" page_size = ");
+ print_debug_hex32(page_size);
+ print_debug("\r\n");
+#endif
+
+ comp_banks = (((getGX1Mem(GX_BASE + MC_BANK_CFG) & (DIMM_COMP_BNK << dimm_shift)) >> dimm_shift) >> 12);
+ page_size <<= comp_banks;
+
+ setGX1Mem(0, TEST_DATA1);
+ setGX1Mem(page_size, TEST_DATA2);
+ setGX1Mem(0x100, 0); /* Clear the bus */
+ if (getGX1Mem(page_size) != TEST_DATA2) {
+ setGX1Mem(GX_BASE + MC_BANK_CFG,
+ getGX1Mem(GX_BASE + MC_BANK_CFG) & ~(DIMM_MOD_BNK << dimm_shift));
+ do_refresh();
+ }
+#if 0
+ print_debug("MC_BANK_CFG = ");
+ print_debug_hex32(getGX1Mem(GX_BASE + MC_BANK_CFG));
+ print_debug("\r\n");
+#endif
+ return(getGX1Mem(GX_BASE + MC_BANK_CFG) & (DIMM_MOD_BNK << dimm_shift));
+}
+
+static unsigned int component_banks(int dimm_shift)
+{
+int page_size = 0x800; /* Smallest page = 1K * 2 banks */
+
+#if 0
+ print_debug("MC_BANK_CFG = ");
+ print_debug_hex32(getGX1Mem(GX_BASE + MC_BANK_CFG));
+ print_debug("\r\n");
+#endif
+
+ page_size = page_size << (((getGX1Mem(GX_BASE + MC_BANK_CFG) & (DIMM_PG_SZ << dimm_shift)) >> dimm_shift) >> 4);
+
+#if 0
+ print_debug(" page_size = ");
+ print_debug_hex32(page_size);
+ print_debug("\r\n");
+#endif
+
+ setGX1Mem(0, TEST_DATA1);
+ setGX1Mem(page_size, TEST_DATA2);
+ setGX1Mem(0x100, 0); /* Clear the bus */
+ if (getGX1Mem(0) != TEST_DATA1) {
+ setGX1Mem(GX_BASE + MC_BANK_CFG,
+ getGX1Mem(GX_BASE + MC_BANK_CFG) & ~(DIMM_COMP_BNK << dimm_shift));
+ do_refresh();
+ }
+#if 0
+ print_debug("MC_BANK_CFG = ");
+ print_debug_hex32(getGX1Mem(GX_BASE + MC_BANK_CFG));
+ print_debug("\r\n");
+#endif
+ return(getGX1Mem(GX_BASE + MC_BANK_CFG) & (DIMM_COMP_BNK << dimm_shift));
+}
+
+static unsigned int page_size(int dimm_shift)
+{
+unsigned int page_test_offset = 0x2000;
+unsigned int temp;
+int page_size_config = 0x40;
+unsigned int probe_config;
+
+ do {
+ setGX1Mem(0, TEST_DATA1);
+ setGX1Mem(page_test_offset, TEST_DATA2);
+ setGX1Mem(0x100, 0);
+ temp = getGX1Mem(0);
+ setGX1Mem(0, 0);
+ if(temp == TEST_DATA1) {
+#if 0
+ print_debug(" Page size Config = ");
+ print_debug_hex32(page_size_config << dimm_shift);
+ print_debug("\r\n");
+#endif
+ return(page_size_config << dimm_shift);
+ }
+
+ temp = ~(DIMM_PG_SZ << dimm_shift);
+
+ probe_config = getGX1Mem(GX_BASE + MC_BANK_CFG);
+ probe_config &= temp;
+
+ page_size_config -= 0x10;
+ page_size_config <<= dimm_shift;
+
+ probe_config |= page_size_config;
+
+ page_size_config >>= dimm_shift;
+
+ page_test_offset >>= 1;
+
+ setGX1Mem(GX_BASE + MC_BANK_CFG, probe_config);
+ do_refresh();
+ } while (page_size_config >= 0);
+
+ return 0x70;
+}
+
+static int dimm_detect(int dimm_shift)
+{
+unsigned int test;
+
+ print_debug("Probing for DIMM");
+ print_debug_char((dimm_shift >> 4) + 0x30);
+ print_debug("\r\n");
+
+ setGX1Mem(0, TEST_DATA1);
+ setGX1Mem(0x100, 0);
+ test = getGX1Mem(0);
+ setGX1Mem(0, 0);
+
+ if (test != TEST_DATA1)
+ return 0;
+
+ print_debug(" Found DIMM");
+ print_debug_char((dimm_shift >> 4) + 0x30);
+ print_debug("\r\n");
+
+ return 1;
+}
+
+static int size_memory(int dimm_shift, unsigned int mem_config)
+{
+
+ if (!dimm_detect(dimm_shift))
+ return (mem_config);
+
+ mem_config &= (~(DIMM_PG_SZ << dimm_shift));
+ mem_config |= (page_size(dimm_shift));
+
+ print_debug(" Page Size: ");
+ print_debug_hex32(0x400 << ((mem_config & (DIMM_PG_SZ << dimm_shift)) >> (dimm_shift + 4)));
+ print_debug("\r\n");
+
+ /* Now do component banks detection */
+
+ mem_config &= (~(DIMM_COMP_BNK << dimm_shift));
+ mem_config |= (component_banks(dimm_shift));
+
+ print_debug(" Component Banks: ");
+ print_debug_char((((mem_config & (DIMM_COMP_BNK << dimm_shift)) >> (dimm_shift + 12)) ? 4 : 2) + 0x30);
+ print_debug("\r\n");
+
+ /* Now do module banks */
+
+ mem_config &= (~(DIMM_MOD_BNK << dimm_shift));
+ mem_config |= (module_banks(dimm_shift));
+
+ print_debug(" Module Banks: ");
+ print_debug_char((((mem_config & (DIMM_MOD_BNK << dimm_shift)) >> (dimm_shift + 14)) ? 2 : 1) + 0x30);
+ print_debug("\r\n");
+
+ mem_config &= (~(DIMM_SZ << dimm_shift));
+ mem_config |= (size_dimm(dimm_shift));
+
+ print_debug(" DIMM size: ");
+ print_debug_hex32(1 <<
+ ((mem_config & (DIMM_SZ << dimm_shift)) >> (dimm_shift + 8)) + 22);
+ print_debug("\r\n");
+
+ return (mem_config);
+}
+
+static void sdram_init(void)
+{
+unsigned int mem_config = 0x00700070;
+
+ print_debug("Setting up default parameters for memory\r\n");
+ post_code(0x70);
+
+ setGX1Mem(GX_BASE + MC_MEM_CNTRL2, 0x000007d8); /* Disable all CLKS, Shift = 3 */
+ setGX1Mem(GX_BASE + MC_MEM_CNTRL1, 0x92140000); /* MD_DS=2, MA_DS=2, CNTL_DS=2 SDCLKRATE=4 */
+ setGX1Mem(GX_BASE + MC_BANK_CFG, 0x00700070); /* No DIMMS installed */
+ setGX1Mem(GX_BASE + MC_SYNC_TIM1, 0x3a733225); /* LTMODE=3, RC=10, RAS=7, RP=3, RCD=3, RRD=2, DPL=2 */
+ setGX1Mem(GX_BASE + MC_BANK_CFG, 0x57405740); /* Largest DIMM size
+ 0x4000 -- 2 module banks
+ 0x1000 -- 4 component banks
+ 0x0700 -- DIMM size 512MB
+ 0x0040 -- Page Size 16kB */
+
+ enable_dimm();
+
+ print_debug("Sizing memory\r\n");
+
+ setGX1Mem(GX_BASE + MC_BANK_CFG, 0x00705740);
+ do_refresh();
+ mem_config = size_memory(0, mem_config);
+ setGX1Mem(GX_BASE + MC_BANK_CFG, 0x57400070);
+ do_refresh();
+ mem_config = size_memory(16, mem_config);
+
+ print_debug("MC_BANK_CFG = ");
+ print_debug_hex32(mem_config);
+ print_debug("\r\n");
+
+ setGX1Mem(GX_BASE + MC_BANK_CFG, mem_config);
+ enable_dimm();
+ post_code(0x7e);
+}
diff --git a/src/northbridge/amd/gx1/raminit.h b/src/northbridge/amd/gx1/raminit.h
new file mode 100644
index 0000000000..6e40683066
--- /dev/null
+++ b/src/northbridge/amd/gx1/raminit.h
@@ -0,0 +1,11 @@
+#ifndef RAMINIT_H
+#define RAMINIT_H
+
+#define DIMM_SOCKETS 4
+struct mem_controller {
+ device_t d0;
+ uint16_t channel0[DIMM_SOCKETS];
+};
+
+
+#endif /* RAMINIT_H */