Hi,
I am glad to announce the release of the work we did in the last couple of months writing support for a somewhat modern Intel Desktop/Mobile chipset running with the Core Duo/Core 2 Duo: The i945 + ICH7.
The support package has been split in 6 different smaller patches:
1_superio_winbond_w83627thg.diff: Implement support for the Winbond W83627THG. 2_southbridge_intel_i82801gx.diff: Support for the Intel ICH7 southbridge. 3_cpu_core_duo.diff: Support for Intel Core Duo and Core 2 Duo (tm) CPUs. 4_northbridge_intel_i945.diff: Support for the Intel 945 northbridge. 5_device_allocator.diff: Changes required to the device allocator 6_mainboard_kontron_986lcd_m.diff: Support for the Kontron 986LCD-M mainboard series.
At this point I would like to say thank you to Intel Corporation for doing all they could to make this possible.
I also want to cordially thank everyone else helping in the one way or the other to make this happen.
Best regards, Stefan
See patch
Acked-by: Ronald G. Minnich rminnich@gmail.com
See patch
Acked-by: Ronald G. Minnich rminnich@gmail.com
-----Original Message----- From: coreboot-bounces@coreboot.org [mailto:coreboot-bounces@coreboot.org] On Behalf Of Stefan Reinauer Sent: Tuesday, October 28, 2008 7:14 PM To: Coreboot Subject: [coreboot] [PATCH 2/6] Support for the Intel ICH7 southbridge
See patch
The untested and unused function do_smbus_write_block could probably disappear, along with some of the #if 0 code.
Thanks, Myles
See patch
Acked-by: Ronald G. Minnich rminnich@gmail.com
-----Original Message----- From: coreboot-bounces@coreboot.org [mailto:coreboot-bounces@coreboot.org] On Behalf Of Stefan Reinauer Sent: Tuesday, October 28, 2008 7:15 PM To: Coreboot Subject: [coreboot] [PATCH 3/6] Support for Intel Core Duo and Core 2 Duo(tm) CPUs
Is there a time when you want to zero these?
+#if 0 + "xorl %eax, %eax\n" + "xorl %edx, %edx\n" + "movl $MTRRphysBase_MSR(0), %ecx\n" + "wrmsr\n" + "movl $MTRRphysMask_MSR(0), %ecx\n" + "wrmsr\n" + "movl $MTRRphysBase_MSR(1), %ecx\n" + "wrmsr\n" + "movl $MTRRphysMask_MSR(1), %ecx\n" + "wrmsr\n" +#endif
Thanks, Myles
See patch
Acked-by: Ronald G. Minnich rminnich@gmail.com
-----Original Message----- From: coreboot-bounces@coreboot.org [mailto:coreboot-bounces@coreboot.org] On Behalf Of Stefan Reinauer Sent: Tuesday, October 28, 2008 7:16 PM To: Coreboot Subject: [coreboot] [PATCH 4/6] Support for the Intel 945 northbridge
See patch Support for the Intel 945 northbridge.
This currently only supports 2 equal DIMMs (interleaved operation).
Signed-off-by: Stefan Reinauer stepan@coresystems.de
Sorry I'm late. I know it's already in, but I was in the middle of reviewing it. I prefixed my comments with //, I hope that helps you find them faster.
Thanks, Myles
Index: src/northbridge/intel/i945/errata.c
--- src/northbridge/intel/i945/errata.c (revision 0) +++ src/northbridge/intel/i945/errata.c (revision 0) @@ -0,0 +1,30 @@ +/*
- This file is part of the coreboot project.
- Copyright (C) 2007-2008 coresystems GmbH
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; version 2 of the License.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
USA
- */
+int fixup_i945_errata(void) +{
- u32 reg32;
- /* Mobile Intel 945 Express only */
- reg32 = MCHBAR32(FSBPMC3);
- reg32 &= ~((1 << 13) | (1 << 29));
- MCHBAR32(FSBPMC3) = reg32;
- return 0;
+} Index: src/northbridge/intel/i945/early_init.c =================================================================== --- src/northbridge/intel/i945/early_init.c (revision 0) +++ src/northbridge/intel/i945/early_init.c (revision 0) @@ -0,0 +1,567 @@ +/*
- This file is part of the coreboot project.
- Copyright (C) 2007-2008 coresystems GmbH
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; version 2 of the License.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
USA
- */
+#include "i945.h" +#include "pcie_config.c"
+static int i945_silicon_revision(void) +{
- return pci_read_config8(PCI_DEV(0, 0x00, 0), 8);
//could use PCI_CLASS_REVISION here.
+}
+static void i945_detect_chipset(void)
//I would prefer a name that makes it clear that this function only prints information.
+static void i945_setup_bars(void) +{
- u8 reg8;
- /* As of now, we don't have all the A0 workarounds implemented */
- if (i945_silicon_revision() == 0)
printk_info
("Warning: i945 silicon revision A0 might not work
correctly.\r\n");
- /* Setting up Southbridge. In the northbridge code. */
- printk_debug("Setting up static southbridge registers...");
- pci_write_config32(PCI_DEV(0, 0x1f, 0), RCBA, DEFAULT_RCBA | 1);
- pci_write_config32(PCI_DEV(0, 0x1f, 0), PMBASE, DEFAULT_PMBASE | 1);
- pci_write_config8(PCI_DEV(0, 0x1f, 0), 0x44 /* ACPI_CNTL */ , 0x80);
/* Enable ACPI BAR */
- pci_write_config32(PCI_DEV(0, 0x1f, 0), GPIOBASE, DEFAULT_GPIOBASE |
1);
- pci_write_config8(PCI_DEV(0, 0x1f, 0), 0x4c /* GC */ , 0x10); /*
Enable GPIOs */
- setup_ich7_gpios();
- printk_debug(" done.\r\n");
- printk_debug("Disabling Watchdog reboot...");
- RCBA32(GCS) = (RCBA32(0x3410)) | (1 << 5); /* No reset */
- outw((1 << 11), DEFAULT_PMBASE | 0x60 | 0x08); /* halt timer */
- printk_debug(" done.\r\n");
- printk_debug("Setting up static northbridge registers...");
- /* Set up all hardcoded northbridge BARs */
- pci_write_config32(PCI_DEV(0, 0x00, 0), EPBAR, DEFAULT_EPBAR | 1);
- pci_write_config32(PCI_DEV(0, 0x00, 0), MCHBAR, DEFAULT_MCHBAR | 1);
- pci_write_config32(PCI_DEV(0, 0x00, 0), PCIEXBAR, DEFAULT_PCIEXBAR |
5); /* 64MB - busses 0-63 */
- pci_write_config32(PCI_DEV(0, 0x00, 0), DMIBAR, DEFAULT_DMIBAR | 1);
- pci_write_config32(PCI_DEV(0, 0x00, 0), X60BAR, DEFAULT_X60BAR | 1);
- /* Hardware default is 8MB UMA. If someone wants to make this a
* CMOS or compile time option, send a patch.
* pci_write_config16(PCI_DEV(0, 0x00, 0), GGC, 0x30);
*/
- /* Set C0000-FFFFF to access RAM on both reads and writes */
- pci_write_config8(PCI_DEV(0, 0x00, 0), PAM0, 0x30);
- pci_write_config8(PCI_DEV(0, 0x00, 0), PAM1, 0x33);
- pci_write_config8(PCI_DEV(0, 0x00, 0), PAM2, 0x33);
- pci_write_config8(PCI_DEV(0, 0x00, 0), PAM3, 0x33);
- pci_write_config8(PCI_DEV(0, 0x00, 0), PAM4, 0x33);
- pci_write_config8(PCI_DEV(0, 0x00, 0), PAM5, 0x33);
- pci_write_config8(PCI_DEV(0, 0x00, 0), PAM6, 0x33);
- pci_write_config8(PCI_DEV(0, 0x00, 0), TOLUD, 0x40); /* 1G XXX
dynamic! */ //Care to elaborate?
- pci_write_config32(PCI_DEV(0, 0x00, 0), SKPAD, 0xcafebabe);
//definitely better than deadbeef :).
- printk_debug(" done.\r\n");
- /* Wait for MCH BAR to come up */
- printk_debug("Waiting for MCHBAR to come up...");
- if ((pci_read_config8(PCI_DEV(0, 0x0f, 0), 0xe6) & 0x2) == 0x00) {
/* Bit 49 of CAPID0 */
do {
reg8 = *(volatile u8 *)0xfed40000;
} while (!(reg8 & 0x80));
- }
//Consistency with \r\n ...
- printk_debug("ok\r\n");
+}
+static void i945_setup_egress_port(void) +{
- u32 reg32;
- u32 timeout;
//and just \n
- printk_debug("Setting up Egress Port RCRB\n");
- /* Egress Port Virtual Channel 0 Configuration */
- /* map only TC0 to VC0 */
- reg32 = EPBAR32(EPVC0RCTL);
- reg32 &= 0xffffff01;
- EPBAR32(EPVC0RCTL) = reg32;
- reg32 = EPBAR32(EPPVCCAP1);
- reg32 &= ~(7 << 0);
- reg32 |= 1;
- EPBAR32(EPPVCCAP1) = reg32;
- /* Egress Port Virtual Channel 1 Configuration */
- reg32 = EPBAR32(0x2c);
- reg32 &= 0xffffff00;
- if ((MCHBAR32(CLKCFG) & 7) == 1)
reg32 |= 0x0d; /* 533MHz */
- if ((MCHBAR32(CLKCFG) & 7) == 3)
reg32 |= 0x10; /* 667MHz */
- EPBAR32(0x2c) = reg32;
- EPBAR32(EPVC1MTS) = 0x0a0a0a0a;
- reg32 = EPBAR32(EPVC1RCAP);
- reg32 &= ~(0x7f << 16);
- reg32 |= (0x0a << 16);
- EPBAR32(EPVC1RCAP) = reg32;
- if ((MCHBAR32(CLKCFG) & 7) == 1) { /* 533MHz */
EPBAR32(EPVC1IST + 0) = 0x009c009c;
EPBAR32(EPVC1IST + 4) = 0x009c009c;
- }
- if ((MCHBAR32(CLKCFG) & 7) == 3) { /* 667MHz */
EPBAR32(EPVC1IST + 0) = 0x00c000c0;
EPBAR32(EPVC1IST + 4) = 0x00c000c0;
- }
- /* Is internal graphics enabled? */
- if (pci_read_config8(PCI_DEV(0, 0x0, 0), 54) & ((1 << 4) | (1 <<
3))) { /* DEVEN */
MCHBAR32(MMARB1) |= (1 << 17);
- }
- /* Assign Virtual Channel ID 1 to VC1 */
- reg32 = EPBAR32(EPVC1RCTL);
- reg32 &= ~(7 << 24);
- reg32 |= (1 << 24);
- EPBAR32(EPVC1RCTL) = reg32;
- reg32 = EPBAR32(EPVC1RCTL);
- reg32 &= 0xffffff01;
- reg32 |= (1 << 7);
- EPBAR32(EPVC1RCTL) = reg32;
- EPBAR32(PORTARB + 0x00) = 0x01000001;
- EPBAR32(PORTARB + 0x04) = 0x00040000;
- EPBAR32(PORTARB + 0x08) = 0x00001000;
- EPBAR32(PORTARB + 0x0c) = 0x00000040;
- EPBAR32(PORTARB + 0x10) = 0x01000001;
- EPBAR32(PORTARB + 0x14) = 0x00040000;
- EPBAR32(PORTARB + 0x18) = 0x00001000;
- EPBAR32(PORTARB + 0x1c) = 0x00000040;
- EPBAR32(EPVC1RCTL) |= (1 << 16);
- EPBAR32(EPVC1RCTL) |= (1 << 16);
- printk_debug("Loading port arbitration table ...");
- /* Loop until bit 0 becomes 0 */
- timeout = 0x7fffff;
- while ((EPBAR16(EPVC1RSTS) & 1) && --timeout) ;
- if (!timeout)
printk_debug("timeout!\n");
- else
printk_debug("ok\n");
- /* Now enable VC1 */
- EPBAR32(EPVC1RCTL) |= (1 << 31);
- printk_debug("Wait for VC1 negotiation ...");
- /* Wait for VC1 negotiation pending */
- timeout = 0x7fff;
- while ((EPBAR16(EPVC1RSTS) & (1 << 1)) && --timeout) ;
- if (!timeout)
printk_debug("timeout!\n");
- else
printk_debug("ok\n");
+}
+static void ich7_setup_dmi_rcrb(void) +{
- u16 reg16;
- reg16 = RCBA16(LCTL);
- reg16 &= ~(3 << 0);
- reg16 |= 1;
- RCBA16(LCTL) = reg16;
- RCBA32(V0CTL) = 0x80000001;
- RCBA32(V1CAP) = 0x03128010;
- RCBA32(ESD) = 0x00000810;
- RCBA32(RP1D) = 0x01000003;
- RCBA32(RP2D) = 0x02000002;
- RCBA32(RP3D) = 0x03000002;
- RCBA32(RP4D) = 0x04000002;
- RCBA32(HDD) = 0x0f000003;
- RCBA32(RP5D) = 0x05000002;
- RCBA32(RPFN) = 0x00543210;
- pci_write_config16(PCI_DEV(0, 0x1c, 0), 0x42, 0x0141);
- pci_write_config16(PCI_DEV(0, 0x1c, 4), 0x42, 0x0141);
- pci_write_config16(PCI_DEV(0, 0x1c, 5), 0x42, 0x0141);
- pci_write_config32(PCI_DEV(0, 0x1c, 4), 0x54, 0x00480ce0);
- pci_write_config32(PCI_DEV(0, 0x1c, 5), 0x54, 0x00500ce0);
+}
+static void i945_setup_dmi_rcrb(void) +{
- u32 reg32;
- u32 timeout;
- printk_debug("Setting up DMI RCRB\n");
- /* Virtual Channel 0 Configuration */
- reg32 = DMIBAR32(DMIVC0RCTL0);
- reg32 &= 0xffffff01;
- DMIBAR32(DMIVC0RCTL0) = reg32;
- reg32 = DMIBAR32(DMIPVCCAP1);
- reg32 &= ~(7 << 0);
- reg32 |= 1;
- DMIBAR32(DMIPVCCAP1) = reg32;
- reg32 = DMIBAR32(DMIVC1RCTL);
- reg32 &= ~(7 << 24);
- reg32 |= (1 << 24); /* NOTE: This ID must match ICH7 side */
- DMIBAR32(DMIVC1RCTL) = reg32;
- reg32 = DMIBAR32(DMIVC1RCTL);
- reg32 &= 0xffffff01;
- reg32 |= (1 << 7);
- DMIBAR32(DMIVC1RCTL) = reg32;
- /* Now enable VC1 */
- DMIBAR32(DMIVC1RCTL) |= (1 << 31);
- printk_debug("Wait for VC1 negotiation ...");
- /* Wait for VC1 negotiation pending */
- timeout = 0x7ffff;
- while ((DMIBAR16(DMIVC1RSTS) & (1 << 1)) && --timeout) ;
- if (!timeout)
printk_debug("timeout!\n");
- else
printk_debug("done..\n");
//Do we need the #if 1 ?
+#if 1
- /* Enable Active State Power Management (ASPM) L0 state */
- reg32 = DMIBAR32(DMILCAP);
- reg32 &= ~(7 << 12);
- reg32 |= (2 << 12);
- reg32 &= ~(7 << 15);
- reg32 |= (2 << 15);
- DMIBAR32(DMILCAP) = reg32;
- reg32 = DMIBAR32(DMICC);
- reg32 &= 0x00ffffff;
- reg32 &= ~(3 << 0);
- reg32 |= (1 << 0);
- DMIBAR32(DMICC) = reg32;
- if (0) {
DMIBAR32(DMILCTL) |= (3 << 0);
- }
+#endif
- /* Last but not least, some additional steps */
- reg32 = MCHBAR32(FSBSNPCTL);
- reg32 &= ~(0xff << 2);
- reg32 |= (0xaa << 2);
- MCHBAR32(FSBSNPCTL) = reg32;
- DMIBAR32(0x2c) = 0x86000040;
- reg32 = DMIBAR32(0x204);
- reg32 &= ~0x3ff;
//should be #if DMIX == 4?
+#if 1
- reg32 |= 0x13f; /* for x4 DMI only */
+#else
- reg32 |= 0x1e4; /* for x2 DMI only */
+#endif
- DMIBAR32(0x204) = reg32;
- if (pci_read_config8(PCI_DEV(0, 0x0, 0), 54) & ((1 << 4) | (1 <<
3))) { /* DEVEN */
DMIBAR32(0x200) |= (1 << 21);
- } else {
DMIBAR32(0x200) &= ~(1 << 21);
- }
- reg32 = DMIBAR32(0x204);
- reg32 &= ~((1 << 11) | (1 << 10));
- DMIBAR32(0x204) = reg32;
- reg32 = DMIBAR32(0x204);
- reg32 &= ~(0xff << 12);
- reg32 |= (0x0d << 12);
- DMIBAR32(0x204) = reg32;
- DMIBAR32(DMICTL1) |= (3 << 24);
- reg32 = DMIBAR32(0x200);
- reg32 &= ~(0x3 << 26);
- reg32 |= (0x02 << 26);
- DMIBAR32(0x200) = reg32;
- DMIBAR32(DMIDRCCFG) &= ~(1 << 31);
- DMIBAR32(DMICTL2) |= (1 << 31);
- if (i945_silicon_revision() >= 3) {
reg32 = DMIBAR32(0xec0);
reg32 &= 0x0fffffff;
reg32 |= (2 << 28);
DMIBAR32(0xec0) = reg32;
reg32 = DMIBAR32(0xed4);
reg32 &= 0x0fffffff;
reg32 |= (2 << 28);
DMIBAR32(0xed4) = reg32;
reg32 = DMIBAR32(0xee8);
reg32 &= 0x0fffffff;
reg32 |= (2 << 28);
DMIBAR32(0xee8) = reg32;
reg32 = DMIBAR32(0xefc);
reg32 &= 0x0fffffff;
reg32 |= (2 << 28);
DMIBAR32(0xefc) = reg32;
- }
- /* wait for bit toggle to 0 */
- printk_debug("Waiting for DMI hardware...");
- timeout = 0x7fffff;
- while ((DMIBAR8(0x32) & (1 << 1)) && --timeout) ;
- if (!timeout)
printk_debug("timeout!\n");
- else
printk_debug("ok\n");
- DMIBAR32(0x1c4) = 0xffffffff;
- DMIBAR32(0x1d0) = 0xffffffff;
- DMIBAR32(0x228) = 0xffffffff;
- DMIBAR32(0x308) = DMIBAR32(0x308);
- DMIBAR32(0x314) = DMIBAR32(0x314);
- DMIBAR32(0x324) = DMIBAR32(0x324);
- DMIBAR32(0x328) = DMIBAR32(0x328);
- DMIBAR32(0x338) = DMIBAR32(0x334);
- DMIBAR32(0x338) = DMIBAR32(0x338);
- if (i945_silicon_revision() == 1 && ((MCHBAR8(0xe08) & (1 << 5)) ==
1)) {
if ((MCHBAR32(0x214) & 0xf) != 0x3) {
printk_info
("DMI link requires A1 stepping workaround.
Rebooting.\n");
reg32 = MCHBAR32(MMARB1);
reg32 &= 0xfffffff8;
reg32 |= 3;
outb(0x06, 0xcf9);
for (;;) ; /* wait for reset */
}
- }
+}
+static void i945_setup_pci_express_x16(void) +{
- u32 timeout;
- u32 reg32;
- u16 reg16;
- u8 reg8;
- /* For now we just disable the x16 link */
- printk_debug("Disabling PCI Express x16 Link\n");
- MCHBAR16(UPMC1) |= (1 << 5) | (1 << 0);
- reg8 = pcie_read_config8(PCI_DEV(0, 0x01, 0), BCTRL1);
- reg8 |= (1 << 6);
- pcie_write_config8(PCI_DEV(0, 0x01, 0), BCTRL1, reg8);
- reg32 = pcie_read_config32(PCI_DEV(0, 0x01, 0), 0x224);
- reg32 |= (1 << 8);
- pcie_write_config32(PCI_DEV(0, 0x01, 0), 0x224, reg32);
- reg8 = pcie_read_config8(PCI_DEV(0, 0x01, 0), BCTRL1);
- reg8 &= ~(1 << 6);
- pcie_write_config8(PCI_DEV(0, 0x01, 0), BCTRL1, reg8);
- printk_debug("Wait for link to enter detect state... ");
- timeout = 0x7fffff;
- for (reg32 = pcie_read_config32(PCI_DEV(0, 0x01, 0), 0x214);
(reg32 & 0x000f0000) && --timeout;) ;
- if (!timeout)
printk_debug("timeout!\n");
- else
printk_debug("ok\n");
- /* Finally: Disable the PCI config header */
- reg16 = pci_read_config16(PCI_DEV(0, 0x00, 0), DEVEN);
- reg16 &= ~DEVEN_D1F0;
- pci_write_config16(PCI_DEV(0, 0x00, 0), DEVEN, reg16);
+}
+static void i945_setup_root_complex_topology(void) +{
- u32 reg32;
- printk_debug("Setting up Root Complex Topology\n");
- /* Egress Port Root Topology */
- reg32 = EPBAR32(EPESD);
- reg32 &= 0xff00ffff;
- reg32 |= (1 << 16);
- EPBAR32(EPESD) = reg32;
- EPBAR32(EPLE1D) |= (1 << 0);
- EPBAR32(EPLE1A) = DEFAULT_PCIEXBAR + 0x4000;
- EPBAR32(EPLE2D) |= (1 << 0);
- /* DMI Port Root Topology */
- reg32 = DMIBAR32(DMILE1D);
- reg32 &= 0x00ffffff;
- DMIBAR32(DMILE1D) = reg32;
- reg32 = DMIBAR32(DMILE1D);
- reg32 &= 0xff00ffff;
- reg32 |= (2 << 16);
- DMIBAR32(DMILE1D) = reg32;
- DMIBAR32(DMILE1D) |= (1 << 0);
- DMIBAR32(DMILE1A) = DEFAULT_PCIEXBAR + 0x8000;
- DMIBAR32(DMILE2D) |= (1 << 0);
- DMIBAR32(DMILE2A) = DEFAULT_PCIEXBAR + 0x5000;
- /* PCI Express x16 Port Root Topology */
- if (pci_read_config8(PCI_DEV(0, 0x00, 0), DEVEN) & DEVEN_D1F0) {
pcie_write_config32(PCI_DEV(0, 0x01, 0), 0x158,
DEFAULT_PCIEXBAR + 0x5000);
reg32 = pcie_read_config32(PCI_DEV(0, 0x01, 0), 0x150);
reg32 |= (1 << 0);
pcie_write_config32(PCI_DEV(0, 0x01, 0), 0x150, reg32);
- }
+}
+static void ich7_setup_root_complex_topology(void) +{
- RCBA32(0x104) = 0x00000802;
- RCBA32(0x110) = 0x00000001;
- RCBA32(0x114) = 0x00000000;
- RCBA32(0x118) = 0x00000000;
+}
+static void ich7_setup_pci_express(void) +{
- RCBA32(CG) |= (1 << 0);
- pci_write_config32(PCI_DEV(0, 0x1c, 0), 0x54, 0x00000060);
- pci_write_config32(PCI_DEV(0, 0x1c, 0), 0xd8, 0x00110000);
+}
+static void i945_early_initialization(void) +{
- /* Print some chipset specific information */
- i945_detect_chipset();
- /* Setup all BARs required for early PCIe and raminit */
- i945_setup_bars();
- /* Change port80 to LPC */
- RCBA32(GCS) &= (~0x04);
+}
+static void i945_late_initialization(void) +{
- i945_setup_egress_port();
- ich7_setup_root_complex_topology();
- ich7_setup_pci_express();
- ich7_setup_dmi_rcrb();
- i945_setup_dmi_rcrb();
- i945_setup_pci_express_x16();
- i945_setup_root_complex_topology();
+} Index: src/northbridge/intel/i945/i945.h =================================================================== --- src/northbridge/intel/i945/i945.h (revision 0) +++ src/northbridge/intel/i945/i945.h (revision 0) @@ -0,0 +1,330 @@ +/*
- This file is part of the coreboot project.
- Copyright (C) 2007-2008 coresystems GmbH
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; version 2 of the License.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
USA
- */
+#ifndef __NORTHBRIDGE_INTEL_I945_I945_H__ +#define __NORTHBRIDGE_INTEL_I945_I945_H__ 1
+#include "ich7.h"
+/* Device 0:0.0 PCI configuration space (Host Bridge) */
+#define EPBAR 0x40 +#define MCHBAR 0x44 +#define PCIEXBAR 0x48 +#define DMIBAR 0x4c +#define X60BAR 0x60
+/* Northbridge BARs */ +#define DEFAULT_PCIEXBAR 0xf0000000 +#define DEFAULT_X60BAR 0xfed13000 +#define DEFAULT_MCHBAR 0xfed14000 +#define DEFAULT_DMIBAR 0xfed18000 +#define DEFAULT_EPBAR 0xfed19000
+#define GGC 0x52
+#define DEVEN 0x54 +#define DEVEN_D0F0 (1 << 0) +#define DEVEN_D1F0 (1 << 1) +#define DEVEN_D2F0 (1 << 3) +#define DEVEN_D2F1 (1 << 4) +#ifndef BOARD_DEVEN +#define BOARD_DEVEN ( DEVEN_D0F0 | DEVEN_D2F0 | DEVEN_D2F1 ) +#endif
+#define PAM0 0x90 +#define PAM1 0x91 +#define PAM2 0x92 +#define PAM3 0x93 +#define PAM4 0x94 +#define PAM5 0x95 +#define PAM6 0x96
+#define LAC 0x97 /* Legacy Access Control */ +#define TOLUD 0x9c /* Top of Low Used Memory */ +#define SMRAM 0x9d +#define ESMRAM 0x9e
+#define TOM 0xa0
+#define SKPAD 0xdc /* Scratchpad */
+/* Device 0:1.0 PCI configuration space (PCI Express) */
+#define BCTRL1 0x3e /* 8bit */
+/* Device 0:2.0 PCI configuration space (Graphics Device) */
+#define GCFC 0xf0 /* Graphics Clock Frequency and Gating
Control */
+/*
- MCHBAR
- */
+#define MCHBAR8(x) *((volatile u8 *)(DEFAULT_MCHBAR + x)) +#define MCHBAR16(x) *((volatile u16 *)(DEFAULT_MCHBAR + x)) +#define MCHBAR32(x) *((volatile u32 *)(DEFAULT_MCHBAR + x))
+/* Chipset Control Registers */ +#define FSBPMC3 0x40 /* 32bit */ +#define FSBPMC4 0x44 /* 32bit */ +#define FSBSNPCTL 0x48 /* 32bit */ +#define SLPCTL 0x90 /* 32bit */
+#define C0DRB0 0x100 /* 8bit */ +#define C0DRB1 0x101 /* 8bit */ +#define C0DRB2 0x102 /* 8bit */ +#define C0DRB3 0x103 /* 8bit */ +#define C0DRA0 0x108 /* 8bit */ +#define C0DRA2 0x109 /* 8bit */ +#define C0DCLKDIS 0x10c /* 8bit */ +#define C0BNKARC 0x10e /* 16bit */ +#define C0DRT0 0x110 /* 32bit */ +#define C0DRT1 0x114 /* 32bit */ +#define C0DRT2 0x118 /* 32bit */ +#define C0DRT3 0x11c /* 32bit */ +#define C0DRC0 0x120 /* 32bit */ +#define C0DRC1 0x124 /* 32bit */ +#define C0DRC2 0x128 /* 32bit */ +#define C0AIT 0x130 /* 64bit */
//The spacing here looks a little off
+#define C0DCCFT 0x138 /* 64bit */ +#define C0GTEW 0x140 /* 32bit */ +#define C0GTC 0x144 /* 32bit */ +#define C0DTPEW 0x148 /* 64bit */ +#define C0DTAEW 0x150 /* 64bit */ +#define C0DTC 0x158 /* 32bit */ +#define C0DMC 0x164 /* 32bit */ +#define C0ODT 0x168 /* 64bit */
+#define C1DRB0 0x180 /* 8bit */ +#define C1DRB1 0x181 /* 8bit */ +#define C1DRB2 0x182 /* 8bit */ +#define C1DRB3 0x183 /* 8bit */ +#define C1DRA0 0x188 /* 8bit */ +#define C1DCLKDIS 0x18c /* 8bit */ +#define C1BNKARC 0x18e /* 16bit */ +#define C1DRT0 0x190 /* 32bit */ +#define C1DRT1 0x194 /* 32bit */ +#define C1DRT2 0x198 /* 32bit */ +#define C1DRT3 0x19c /* 32bit */ +#define C1DRC0 0x1a0 /* 32bit */ +#define C1DRC1 0x1a4 /* 32bit */ +#define C1DRC2 0x1a8 /* 32bit */ +#define C1AIT 0x1b0 /* 64bit */ +#define C1DCCFT 0x1b8 /* 64bit */ +#define C1GTEW 0x1c0 /* 32bit */ +#define C1GTC 0x1c4 /* 32bit */ +#define C1DTPEW 0x1c8 /* 64bit */ +#define C1DTAEW 0x1d0 /* 64bit */ +#define C1DTC 0x1d8 /* 32bit */ +#define C1DMC 0x1e4 /* 32bit */ +#define C1ODT 0x1e8 /* 64bit */
+#define DCC 0x200 /* 32bit */ +#define CCCFT 0x208 /* 64bit */ +#define WCC 0x218 /* 32bit */ +#define MMARB0 0x220 /* 32bit */ +#define MMARB1 0x224 /* 32bit */ +#define SBTEST 0x230 /* 32bit */ +#define SBOCC 0x238 /* 32bit */ +#define ODTC 0x284 /* 32bit */ +#define SMVREFC 0x2a0 /* 32bit */ +#define DRTST 0x2a8 /* 32bit */ +#define REPC 0x2e0 /* 32bit */ +#define DQSMT 0x2f4 /* 16bit */ +#define RCVENMT 0x2f8 /* 32bit */
+#define C0R0B00DQST 0x300 /* 64bit */
+#define C0WL0REOST 0x340 /* 8bit */ +#define C0WL1REOST 0x341 /* 8bit */ +#define C0WL2REOST 0x342 /* 8bit */ +#define C0WL3REOST 0x343 /* 8bit */ +#define WDLLBYPMODE 0x360 /* 16bit */ +#define C0WDLLCMC 0x36c /* 32bit */ +#define C0HCTC 0x37c /* 8bit */
+#define C1R0B00DQST 0x380 /* 64bit */
+#define C1WL0REOST 0x3c0 /* 8bit */ +#define C1WL1REOST 0x3c1 /* 8bit */ +#define C1WL2REOST 0x3c2 /* 8bit */ +#define C1WL3REOST 0x3c3 /* 8bit */ +#define C1WDLLCMC 0x3ec /* 32bit */ +#define C1HCTC 0x3fc /* 8bit */
+#define GBRCOMPCTL 0x400 /* 32bit */
+#define SMSRCTL 0x408 /* XXX who knows */ +#define C0DRAMW 0x40c /* 16bit */ +#define G1SC 0x410 /* 8bit */ +#define G2SC 0x418 /* 8bit */ +#define G3SC 0x420 /* 8bit */ +#define G4SC 0x428 /* 8bit */ +#define G5SC 0x430 /* 8bit */ +#define G6SC 0x438 /* 8bit */
+#define C1DRAMW 0x48c /* 16bit */ +#define G7SC 0x490 /* 8bit */ +#define G8SC 0x498 /* 8bit */
+#define G1SRPUT 0x500 /* 256bit */ +#define G1SRPDT 0x520 /* 256bit */ +#define G2SRPUT 0x540 /* 256bit */ +#define G2SRPDT 0x560 /* 256bit */ +#define G3SRPUT 0x580 /* 256bit */ +#define G3SRPDT 0x5a0 /* 256bit */ +#define G4SRPUT 0x5c0 /* 256bit */ +#define G4SRPDT 0x5e0 /* 256bit */ +#define G5SRPUT 0x600 /* 256bit */ +#define G5SRPDT 0x620 /* 256bit */ +#define G6SRPUT 0x640 /* 256bit */ +#define G6SRPDT 0x660 /* 256bit */ +#define G7SRPUT 0x680 /* 256bit */ +#define G7SRPDT 0x6a0 /* 256bit */ +#define G8SRPUT 0x6c0 /* 256bit */ +#define G8SRPDT 0x6e0 /* 256bit */
+/* Clock Controls */ +#define CLKCFG 0xc00 /* 32bit */ +#define UPMC1 0xc14 /* 16bit */ +#define CPCTL 0xc16 /* 16bit */ +#define SSKPD 0xc1c /* 16bit (scratchpad) */ +#define UPMC2 0xc20 /* 16bit */ +#define UPMC4 0xc30 /* 32bit */ +#define PLLMON 0xc34 /* 32bit */ +#define HGIPMC2 0xc38 /* 32bit */
+/* Thermal Management Controls */ +#define TSC1 0xc88 /* 8bit */ +#define TSS1 0xc8a /* 8bit */ +#define TR1 0xc8b /* 8bit */ +#define TSTTP1 0xc8c /* 32bit */ +#define TCO1 0xc92 /* 8bit */ +#define THERM1_1 0xc94 /* 8bit */ +#define TCOF1 0xc96 /* 8bit */ +#define TIS1 0xc9a /* 16bit */ +#define TSTTP1_2 0xc9c /* 32bit */ +#define IUB 0xcd0 /* 32bit */ +#define TSC0_1 0xcd8 /* 8bit */ +#define TSS0 0xcda /* 8bit */ +#define TR0 0xcdb /* 8bit */ +#define TSTTP0_1 0xcdc /* 32bit */ +#define TCO0 0xce2 /* 8bit */ +#define THERM0_1 0xce4 /* 8bit */ +#define TCOF0 0xce6 /* 8bit */ +#define TIS0 0xcea /* 16bit */ +#define TSTTP0_2 0xcec /* 32bit */ +#define TERRCMD 0xcf0 /* 8bit */ +#define TSMICMD 0xcf1 /* 8bit */ +#define TSCICMD 0xcf2 /* 8bit */ +#define TINTRCMD 0xcf3 /* 8bit */ +#define EXTTSCS 0xcff /* 8bit */ +#define DFT_STRAP1 0xe08 /* 32bit */
+/* ACPI Power Management Controls */
+#define MIPMC3 0xbd8 /* 32bit */
+#define C2C3TT 0xf00 /* 32bit */ +#define C3C4TT 0xf04 /* 32bit */
+#define MIPMC4 0xf08 /* 16bit */ +#define MIPMC5 0xf0a /* 16bit */ +#define MIPMC6 0xf0c /* 16bit */ +#define MIPMC7 0xf0e /* 16bit */ +#define PMCFG 0xf10 /* 32bit */ +#define SLFRCS 0xf14 /* 32bit */ +#define GIPMC1 0xfb0 /* 32bit */ +#define FSBPMC1 0xfb8 /* 32bit */ +#define UPMC3 0xfc0 /* 32bit */ +#define ECO 0xffc /* 32bit */
+/*
- EPBAR - Egress Port Root Complex Register Block
- */
+#define EPBAR8(x) *((volatile u8 *)(DEFAULT_EPBAR + x)) +#define EPBAR16(x) *((volatile u16 *)(DEFAULT_EPBAR + x)) +#define EPBAR32(x) *((volatile u32 *)(DEFAULT_EPBAR + x))
+#define EPPVCCAP1 0x004 /* 32bit */ +#define EPPVCCAP2 0x008 /* 32bit */
+#define EPVC0RCAP 0x010 /* 32bit */ +#define EPVC0RCTL 0x014 /* 32bit */ +#define EPVC0RSTS 0x01a /* 16bit */
+#define EPVC1RCAP 0x01c /* 32bit */ +#define EPVC1RCTL 0x020 /* 32bit */ +#define EPVC1RSTS 0x026 /* 16bit */
+#define EPVC1MTS 0x028 /* 32bit */ +#define EPVC1IST 0x038 /* 64bit */
+#define EPESD 0x044 /* 32bit */
+#define EPLE1D 0x050 /* 32bit */ +#define EPLE1A 0x058 /* 64bit */ +#define EPLE2D 0x060 /* 32bit */ +#define EPLE2A 0x068 /* 64bit */
+#define PORTARB 0x100 /* 256bit */
+/*
- DMIBAR
- */
+#define DMIBAR8(x) *((volatile u8 *)(DEFAULT_DMIBAR + x)) +#define DMIBAR16(x) *((volatile u16 *)(DEFAULT_DMIBAR + x)) +#define DMIBAR32(x) *((volatile u32 *)(DEFAULT_DMIBAR + x))
+#define DMIVCECH 0x000 /* 32bit */ +#define DMIPVCCAP1 0x004 /* 32bit */ +#define DMIPVCCAP2 0x008 /* 32bit */
+#define DMIPVCCCTL 0x00c /* 16bit */
+#define DMIVC0RCAP 0x010 /* 32bit */ +#define DMIVC0RCTL0 0x014 /* 32bit */ +#define DMIVC0RSTS 0x01a /* 16bit */
+#define DMIVC1RCAP 0x01c /* 32bit */ +#define DMIVC1RCTL 0x020 /* 32bit */ +#define DMIVC1RSTS 0x026 /* 16bit */
+#define DMILE1D 0x050 /* 32bit */ +#define DMILE1A 0x058 /* 64bit */ +#define DMILE2D 0x060 /* 32bit */ +#define DMILE2A 0x068 /* 64bit */
+#define DMILCAP 0x084 /* 32bit */ +#define DMILCTL 0x088 /* 16bit */ +#define DMILSTS 0x08a /* 16bit */
+#define DMICTL1 0x0f0 /* 32bit */ +#define DMICTL2 0x0fc /* 32bit */
+#define DMICC 0x208 /* 32bit */
+#define DMIDRCCFG 0xeb4 /* 32bit */
+#endif Index: src/northbridge/intel/i945/ich7.h =================================================================== --- src/northbridge/intel/i945/ich7.h (revision 0) +++ src/northbridge/intel/i945/ich7.h (revision 0) @@ -0,0 +1,142 @@ +/*
- This file is part of the coreboot project.
- Copyright (C) 2007-2008 coresystems GmbH
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; version 2 of the License.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
USA
- */
+#ifndef __NORTHBRIDGE_INTEL_I945_ICH7_H__ +#define __NORTHBRIDGE_INTEL_I945_ICH7_H__ 1
+/* Southbridge IO BARs */ +/* TODO Make sure these don't get changed by stage2 */ +#define GPIOBASE 0x48 +#define DEFAULT_GPIOBASE 0x480
+#define PMBASE 0x40 +#define DEFAULT_PMBASE 0x500
+/* Root Complex Register Block */ +#define RCBA 0xf0 +#define DEFAULT_RCBA 0xfed1c000
+#define RCBA8(x) *((volatile u8 *)(DEFAULT_RCBA + x)) +#define RCBA16(x) *((volatile u16 *)(DEFAULT_RCBA + x)) +#define RCBA32(x) *((volatile u32 *)(DEFAULT_RCBA + x))
+#define VCH 0x0000 /* 32bit */ +#define VCAP1 0x0004 /* 32bit */ +#define VCAP2 0x0008 /* 32bit */ +#define PVC 0x000c /* 16bit */ +#define PVS 0x000e /* 16bit */
+#define V0CAP 0x0010 /* 32bit */ +#define V0CTL 0x0014 /* 32bit */ +#define V0STS 0x001a /* 16bit */
+#define V1CAP 0x001c /* 32bit */ +#define V1CTL 0x0020 /* 32bit */ +#define V1STS 0x0026 /* 16bit */
+#define RCTCL 0x0100 /* 32bit */ +#define ESD 0x0104 /* 32bit */ +#define ULD 0x0110 /* 32bit */ +#define ULBA 0x0118 /* 64bit */
+#define RP1D 0x0120 /* 32bit */ +#define RP1BA 0x0128 /* 64bit */ +#define RP2D 0x0130 /* 32bit */ +#define RP2BA 0x0138 /* 64bit */ +#define RP3D 0x0140 /* 32bit */ +#define RP3BA 0x0138 /* 64bit */ +#define RP4D 0x0150 /* 32bit */ +#define RP4BA 0x0158 /* 64bit */ +#define HDD 0x0160 /* 32bit */ +#define HDBA 0x0168 /* 64bit */ +#define RP5D 0x0170 /* 32bit */ +#define RP5BA 0x0178 /* 64bit */ +#define RP6D 0x0180 /* 32bit */ +#define RP6BA 0x0188 /* 64bit */
+#define ILCL 0x01a0 /* 32bit */ +#define LCAP 0x01a4 /* 32bit */ +#define LCTL 0x01a8 /* 16bit */ +#define LSTS 0x01aa /* 16bit */
+#define RPC 0x0224 /* 32bit */ +#define RPFN 0x0238 /* 32bit */
+#define TRSR 0x1e00 /* 8bit */ +#define TRCR 0x1e10 /* 64bit */ +#define TWDR 0x1e18 /* 64bit */
+#define IOTR0 0x1e80 /* 64bit */ +#define IOTR1 0x1e88 /* 64bit */ +#define IOTR2 0x1e90 /* 64bit */ +#define IOTR3 0x1e98 /* 64bit */
+#define TCTL 0x3000 /* 8bit */
+#define D31IP 0x3100 /* 32bit */ +#define D30IP 0x3104 /* 32bit */ +#define D29IP 0x3108 /* 32bit */ +#define D28IP 0x310c /* 32bit */ +#define D27IP 0x3110 /* 32bit */ +#define D31IR 0x3140 /* 16bit */ +#define D30IR 0x3142 /* 16bit */ +#define D29IR 0x3144 /* 16bit */ +#define D28IR 0x3146 /* 16bit */ +#define D27IR 0x3148 /* 16bit */ +#define OIC 0x31ff /* 8bit */
+#define RC 0x3400 /* 32bit */ +#define HPTC 0x3404 /* 32bit */ +#define GCS 0x3410 /* 32bit */ +#define BUC 0x3414 /* 32bit */ +#define FD 0x3418 /* 32bit */ +#define CG 0x341c /* 32bit */
+/* Function Disable (FD) register values.
- Setting a bit disables the corresponding
- feature.
- Not all features might be disabled on
- all chipsets. Esp. ICH-7U is picky.
- */
+#define FD_PCIE6 (1 << 21) +#define FD_PCIE5 (1 << 20) +#define FD_PCIE4 (1 << 19) +#define FD_PCIE3 (1 << 18) +#define FD_PCIE2 (1 << 17) +#define FD_PCIE1 (1 << 16) +#define FD_EHCI (1 << 15) +#define FD_LPCB (1 << 14)
+/* UHCI must be disabled from 4 downwards.
- If UHCI controllers get disabled, EHCI
- must know about it, too! */
+#define FD_UHCI4 (1 << 11) +#define FD_UHCI34 (1 << 10) | FD_UHCI4 +#define FD_UHCI234 (1 << 9) | FD_UHCI3 +#define FD_UHCI1234 (1 << 8) | FD_UHCI2
+#define FD_INTLAN (1 << 7) +#define FD_ACMOD (1 << 6) +#define FD_ACAUD (1 << 5) +#define FD_HDAUD (1 << 4) +#define FD_SMBUS (1 << 3) +#define FD_SATA (1 << 2) +#define FD_PATA (1 << 1)
+#endif Index: src/northbridge/intel/i945/Config.lb =================================================================== --- src/northbridge/intel/i945/Config.lb (revision 0) +++ src/northbridge/intel/i945/Config.lb (revision 0) @@ -0,0 +1,21 @@ +# +# This file is part of the coreboot project. +# +# Copyright (C) 2007-2008 coresystems GmbH +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
USA
+#
+config chip.h +driver northbridge.o Index: src/northbridge/intel/i945/reset_test.c =================================================================== --- src/northbridge/intel/i945/reset_test.c (revision 0) +++ src/northbridge/intel/i945/reset_test.c (revision 0) @@ -0,0 +1,28 @@ +/*
- This file is part of the coreboot project.
- Copyright (C) 2007-2008 coresystems GmbH
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; version 2 of the License.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
USA
- */
+static int bios_reset_detected(void) +{
- /* For now ...
* DO NOT, I repeat, DO NOT remove this. If you don't like the
* situation, implement this instead.
*/
- return 0;
+}
Index: src/northbridge/intel/i945/raminit.c
--- src/northbridge/intel/i945/raminit.c (revision 0) +++ src/northbridge/intel/i945/raminit.c (revision 0) @@ -0,0 +1,2779 @@ +/*
- This file is part of the coreboot project.
- Copyright (C) 2007-2008 coresystems GmbH
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; version 2 of the License.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
USA
- */
+#include <cpu/x86/mem.h> +#include <cpu/x86/mtrr.h> +#include <cpu/x86/cache.h> +#include <spd.h> +#include "raminit.h" +#include "i945.h"
+#include "lib/memset.c"
+#define DEBUG_RAM_SETUP
+/* Debugging macros. */ +#if defined(DEBUG_RAM_SETUP) +#define PRINTK_DEBUG(x...) printk_debug(x) +#else +#define PRINTK_DEBUG(x...) +#endif
+#define RAM_INITIALIZATION_COMPLETE (1 << 19)
+#define RAM_COMMAND_SELF_REFRESH (0x0 << 16) +#define RAM_COMMAND_NOP (0x1 << 16) +#define RAM_COMMAND_PRECHARGE (0x2 << 16) +#define RAM_COMMAND_MRS (0x3 << 16) +#define RAM_COMMAND_EMRS (0x4 << 16) +#define RAM_COMMAND_CBR (0x6 << 16) +#define RAM_COMMAND_NORMAL (0x7 << 16)
+#define RAM_EMRS_1 (0x0 << 21) +#define RAM_EMRS_2 (0x1 << 21) +#define RAM_EMRS_3 (0x2 << 21)
+static void do_ram_command(u32 command) +{
- u32 reg32;
- reg32 = MCHBAR32(DCC);
- reg32 &= ~( (3<<21) | (1<<20) | (1<<19) | (7 << 16) );
- reg32 |= command;
- /* Also set Init Complete */
- if (command == RAM_COMMAND_NORMAL)
reg32 |= RAM_INITIALIZATION_COMPLETE;
- PRINTK_DEBUG(" Sending RAM command 0x%08x", reg32);
- MCHBAR32(DCC) = reg32; /* This is the actual magic */
- PRINTK_DEBUG("...done\r\n");
+}
+static void ram_read32(u32 offset) +{
- PRINTK_DEBUG(" ram read: %08x\r\n", offset);
- read32(offset);
+}
+#ifdef DEBUG_RAM_SETUP +static void sdram_dump_mchbar_registers(void) +{
- int i;
- printk_debug("Dumping MCHBAR Registers\r\n");
- for (i=0; i<0xfff; i+=4) {
if (MCHBAR32(i) == 0)
continue;
printk_debug("0x%04x: 0x%08x\r\n", i, MCHBAR32(i));
- }
+} +#endif
+static int sdram_capabilities_max_supported_memory_frequency(void) +{
- u32 reg32;
- reg32 = pci_read_config32(PCI_DEV(0, 0x00, 0), 0xe4);
- reg32 &= (7 << 0);
- switch (reg32) {
- case 4: return 400;
- case 3: return 533;
- case 2: return 667;
- }
- /* Newer revisions of this chipset rather support faster memory
clocks,
* so if it's a reserved value, return the fastest memory clock that
we
* know of and can handle
*/
- return 667;
+}
+/**
- @brief determine whether chipset is capable of dual channel
interleaved mode
- @return 1 if interleaving is supported, 0 otherwise
- */
+static int sdram_capabilities_interleave(void) +{
- u32 reg32;
- reg32 = pci_read_config8(PCI_DEV(0, 0x00,0), 0xe4);
- reg32 >>= 25;
- reg32 &= 1;
- return (!reg32);
+}
+/**
- @brief determine whether chipset is capable of two memory channels
- @return 1 if dual channel operation is supported, 0 otherwise
- */
+static int sdram_capabilities_dual_channel(void) +{
- u32 reg32;
- reg32 = pci_read_config8(PCI_DEV(0, 0x00,0), 0xe4);
- reg32 >>= 24;
- reg32 &= 1;
- return (!reg32);
+}
+static int sdram_capabilities_enhanced_addressing_xor(void) +{
- u8 reg8;
- reg8 = pci_read_config8(PCI_DEV(0, 0x00, 0), 0xe5); /* CAPID0 + 5 */
- reg8 &= (1 << 7);
- return (!reg8);
+}
+static int sdram_capabilities_two_dimms_per_channel(void) +{
- u8 reg8;
- reg8 = pci_read_config8(PCI_DEV(0, 0x00, 0), 0xe8); /* CAPID0 + 8 */
- reg8 &= (1 << 0);
- return (reg8 != 0);
+}
// I think this should be named disabled, since it doesn't disable it.
+static int sdram_capabilities_MEM4G_disable(void) +{
- u8 reg8;
- reg8 = pci_read_config8(PCI_DEV(0, 0x00, 0), 0xe5);
- reg8 &= (1 << 0);
- return (reg8 != 0);
+}
+static void sdram_detect_errors(void) +{
- u8 reg8;
- reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa2);
- if (reg8 & ((1<<7)|(1<<2))) {
if (reg8 & (1<<2)) {
printk_debug("SLP S4# Assertion Width
Violation.\r\n");
pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa2, reg8);
}
if (reg8 & (1<<7)) {
printk_debug("DRAM initialization was
interrupted.\r\n");
reg8 &= ~(1<<7);
pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa2, reg8);
}
/* Set SLP_S3# Assertion Stretch Enable */
reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa4); /*
GEN_PMCON_3 */
reg8 |= (1 << 3);
pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa4, reg8);
printk_debug("Reset required.\r\n");
outb(0x00, 0xcf9);
outb(0x0e, 0xcf9);
for (;;) ; /* Wait for reset! */
- }
- /* Set DRAM initialization bit in ICH7 */
- reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa2);
- reg8 |= (1<<7);
- pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa2, reg8);
+}
+/**
- @brief Get generic DIMM parameters.
- @param sysinfo Central memory controller information structure
- This function gathers several pieces of information for each system
DIMM:
- o DIMM width (x8 / x16)
- o DIMM sides (single sided / dual sided)
- Also, some non-supported scenarios are detected.
- */
+static void sdram_get_dram_configuration(struct sys_info *sysinfo) +{
- u32 dimm_mask = 0;
- int i;
- /**
* i945 supports two DIMMs, in two configurations:
*
* - single channel with two dimms
* - dual channel with one dimm per channel
*
* In practice dual channel mainboards have their spd at 0x50, 0x52
* whereas single channel configurations have their spd at 0x50/x51
*
* The capability register knows a lot about the channel
configuration
* but for now we stick with the information we gather from the SPD
* ROMs
*/
- if (sdram_capabilities_dual_channel()) {
sysinfo->dual_channel = 1;
printk_debug("This mainboard supports Dual Channel
Operation.\n");
- } else {
sysinfo->dual_channel = 0;
printk_debug("This mainboard supports only Single Channel
Operation.\n");
- }
- /**
* Since we only support two DIMMs in total, there is a limited
number // * Since we only support two DIMMs in total, there are a limited number
* of combinations. This function returns the type of DIMMs.
* return value:
* [0:7] lower DIMM population
* [8-15] higher DIMM population
* [16] dual channel?
*
* There are 5 different possible populations for a DIMM socket:
* 1. x16 double sided (X16DS)
* 2. x8 double sided (X8DS)
* 3. x16 single sided (X16SS)
* 4. x8 double stacked (X8DDS)
* 5. not populated (NC)
*
* For the return value we start counting at zero.
*
*/
- for (i=0; i<(2 * DIMM_SOCKETS); i++) {
u8 reg8, device = DIMM_SPD_BASE + i;
/* Initialize the socket information with a sane value */
sysinfo->dimm[i] = SYSINFO_DIMM_NOT_POPULATED;
if (!sdram_capabilities_dual_channel() && (i >> 1))
continue;
if (!sdram_capabilities_two_dimms_per_channel() && (i& 1))
continue;
printk_debug("DDR II Channel %d Socket %d: ", (i >> 1), (i &
1));
if (spd_read_byte(device, SPD_MEMORY_TYPE) !=
SPD_MEMORY_TYPE_SDRAM_DDR2) {
printk_debug("N/A\n");
continue;
}
reg8 = spd_read_byte(device, SPD_DIMM_CONFIG_TYPE);
if (reg8 == ERROR_SCHEME_ECC)
die("Error: ECC memory not supported by this
chipset\r\n");
reg8 = spd_read_byte(device, SPD_MODULE_ATTRIBUTES);
if (reg8 & MODULE_BUFFERED)
die("Error: Buffered memory not supported by this
chipset\r\n");
if (reg8 & MODULE_REGISTERED)
die("Error: Registered memory not supported by this
chipset\r\n");
switch (spd_read_byte(device, SPD_PRIMARY_SDRAM_WIDTH)) {
case 0x08:
switch (spd_read_byte(device, SPD_NUM_DIMM_BANKS) &
0x0f) {
case 1:
printk_debug("x8DDS\r\n");
sysinfo->dimm[i] = SYSINFO_DIMM_X8DDS;
break;
case 0:
printk_debug("x8DS\r\n");
sysinfo->dimm[i] = SYSINFO_DIMM_X8DS;
break;
default:
printk_debug ("Unsupported.\r\n");
}
break;
case 0x10:
switch (spd_read_byte(device, SPD_NUM_DIMM_BANKS) &
0x0f) {
case 1:
printk_debug("x16DS\r\n");
sysinfo->dimm[i] = SYSINFO_DIMM_X16DS;
break;
case 0:
printk_debug("x16SS\r\n");
sysinfo->dimm[i] = SYSINFO_DIMM_X16SS;
break;
default:
printk_debug ("Unsupported.\r\n");
}
break;
default:
die("Unsupported DDR-II memory width.\r\n");
}
dimm_mask |= (1 << i);
- }
- if (!dimm_mask) {
die("No memory installed.\r\n");
- }
- /* The chipset might be able to do this. What the heck, legacy bios
* just beeps when a single DIMM is in the Channel 1 socket. So
let's
* not bother until someone needs this enough to cope with it.
*/
- if (!(dimm_mask & ((1 << DIMM_SOCKETS) - 1))) {
printk_err("Channel 0 has no memory populated. This setup is
not usable. Please move the DIMM.\r\n");
- }
+}
+/**
- @brief determine if any DIMMs are stacked
- @param sysinfo central sysinfo data structure.
- */
+static void sdram_verify_package_type(struct sys_info * sysinfo) +{
- int i;
- /* Assume no stacked DIMMs are available until we find one */
- sysinfo->package = 0;
- for (i=0; i<2*DIMM_SOCKETS; i++) {
if (sysinfo->dimm[i] == SYSINFO_DIMM_NOT_POPULATED)
continue;
/* Is the current DIMM a stacked DIMM? */
if (spd_read_byte(DIMM_SPD_BASE + i, SPD_NUM_DIMM_BANKS) &
(1 << 4))
sysinfo->package = 1;
- }
+}
+static u8 sdram_possible_cas_latencies(struct sys_info * sysinfo) +{
- int i;
- u8 cas_mask;
- /* Setup CAS mask with all supported CAS Latencies */
- cas_mask = SPD_CAS_LATENCY_DDR2_3 |
SPD_CAS_LATENCY_DDR2_4 |
SPD_CAS_LATENCY_DDR2_5;
- for (i=0; i<2*DIMM_SOCKETS; i++) {
if (sysinfo->dimm[i] != SYSINFO_DIMM_NOT_POPULATED)
cas_mask &= spd_read_byte(DIMM_SPD_BASE + i,
SPD_ACCEPTABLE_CAS_LATENCIES);
- }
- if(!cas_mask) {
die("No DDR-II modules with accepted CAS latencies
found.\n");
- }
- return cas_mask;
+}
+static void sdram_detect_cas_latency_and_ram_speed(struct sys_info *
sysinfo, u8 cas_mask)
+{
- int i, j, idx;
- int lowest_common_cas = 0;
- int max_ram_speed;
- const u8 ddr2_speeds_table[] = {
0x50, 0x60, /* DDR2 400: tCLK = 5.0ns tAC = 0.6ns */
0x3d, 0x50, /* DDR2 533: tCLK = 3.75ns tAC = 0.5ns */
0x30, 0x45, /* DDR2 667: tCLK = 3.0ns tAC = 0.45ns */
- };
- const u8 spd_lookup_table[] = {
SPD_MIN_CYCLE_TIME_AT_CAS_MAX, SPD_ACCESS_TIME_FROM_CLOCK,
SPD_SDRAM_CYCLE_TIME_2ND,
SPD_ACCESS_TIME_FROM_CLOCK_2ND,
SPD_SDRAM_CYCLE_TIME_3RD,
SPD_ACCESS_TIME_FROM_CLOCK_3RD
- };
- switch (sdram_capabilities_max_supported_memory_frequency()) {
- case 400: max_ram_speed = 0; break;
- case 533: max_ram_speed = 1; break;
- case 667: max_ram_speed = 2; break;
- }
- sysinfo->memory_frequency = 0;
- sysinfo->cas = 0;
- if (cas_mask & SPD_CAS_LATENCY_DDR2_3) {
lowest_common_cas = 3;
- } else if (cas_mask & SPD_CAS_LATENCY_DDR2_4) {
lowest_common_cas = 4;
- } else if (cas_mask & SPD_CAS_LATENCY_DDR2_5) {
lowest_common_cas = 5;
- }
- PRINTK_DEBUG("lowest common cas = %d\n", lowest_common_cas);
- for (j = max_ram_speed; j>=0; j--) {
int freq_cas_mask = cas_mask;
PRINTK_DEBUG("Probing Speed %d\n", j);
for (i=0; i<2*DIMM_SOCKETS; i++) {
int current_cas_mask;
PRINTK_DEBUG(" DIMM: %d\n", i);
if (sysinfo->dimm[i] == SYSINFO_DIMM_NOT_POPULATED)
{
continue;
}
current_cas_mask = spd_read_byte(DIMM_SPD_BASE + i,
SPD_ACCEPTABLE_CAS_LATENCIES);
while (current_cas_mask) {
int highest_supported_cas = 0, current_cas =
0;
PRINTK_DEBUG(" Current CAS mask: %04x; ",
current_cas_mask);
if (current_cas_mask &
SPD_CAS_LATENCY_DDR2_5) {
highest_supported_cas = 5;
} else if (current_cas_mask &
SPD_CAS_LATENCY_DDR2_4) {
highest_supported_cas = 4;
} else if (current_cas_mask &
SPD_CAS_LATENCY_DDR2_3) {
highest_supported_cas = 3;
}
if (current_cas_mask &
SPD_CAS_LATENCY_DDR2_3) {
current_cas = 3;
} else if (current_cas_mask &
SPD_CAS_LATENCY_DDR2_4) {
current_cas = 4;
} else if (current_cas_mask &
SPD_CAS_LATENCY_DDR2_5) {
current_cas = 5;
}
idx = highest_supported_cas - current_cas;
PRINTK_DEBUG("idx=%d, ", idx);
PRINTK_DEBUG("tCLK=%x, ",
spd_read_byte(DIMM_SPD_BASE + i, spd_lookup_table[2*idx]));
PRINTK_DEBUG("tAC=%x",
spd_read_byte(DIMM_SPD_BASE + i, spd_lookup_table[(2*idx)+1]));
if (spd_read_byte(DIMM_SPD_BASE + i,
spd_lookup_table[2*idx]) <= ddr2_speeds_table[2*j] &&
spd_read_byte(DIMM_SPD_BASE
+ i, spd_lookup_table[(2*idx)+1]) <= ddr2_speeds_table[(2*j)+1]) {
PRINTK_DEBUG(": OK\n");
break;
}
PRINTK_DEBUG(": Not fast enough!\n");
current_cas_mask &= ~(1 << (current_cas));
}
freq_cas_mask &= current_cas_mask;
if (!current_cas_mask) {
PRINTK_DEBUG(" No valid CAS for this
speed on DIMM %d\n", i);
break;
}
}
PRINTK_DEBUG(" freq_cas_mask for speed %d: %04x\n", j,
freq_cas_mask);
if (freq_cas_mask) {
switch (j) {
case 0: sysinfo->memory_frequency = 400; break;
case 1: sysinfo->memory_frequency = 533; break;
case 2: sysinfo->memory_frequency = 667; break;
}
if (freq_cas_mask & SPD_CAS_LATENCY_DDR2_3) {
sysinfo->cas = 3;
} else if (freq_cas_mask & SPD_CAS_LATENCY_DDR2_4) {
sysinfo->cas = 4;
} else if (freq_cas_mask & SPD_CAS_LATENCY_DDR2_5) {
sysinfo->cas = 5;
}
break;
}
- }
- if (sysinfo->memory_frequency && sysinfo->cas) {
printk_debug("Memory will be driven at %dMHz with CAS=%d
clocks\n",
sysinfo->memory_frequency, sysinfo->cas);
- } else {
die("Could not find common memory frequency and CAS\n");
- }
+}
+static void sdram_detect_smallest_tRAS(struct sys_info * sysinfo) +{
- int i;
- int tRAS_time;
- int tRAS_cycles;
- int freq_multiplier = 0;
- switch (sysinfo->memory_frequency) {
- case 400: freq_multiplier = 0x14; break; /* 5ns */
- case 533: freq_multiplier = 0x0f; break; /* 3.75ns */
- case 667: freq_multiplier = 0x0c; break; /* 3ns */
- }
- tRAS_cycles = 4; /* 4 clocks minimum */
- tRAS_time = tRAS_cycles * freq_multiplier;
- for (i=0; i<2*DIMM_SOCKETS; i++) {
u8 reg8;
if (sysinfo->dimm[i] == SYSINFO_DIMM_NOT_POPULATED)
continue;
reg8 = spd_read_byte(DIMM_SPD_BASE + i,
SPD_MIN_ACTIVE_TO_PRECHARGE_DELAY);
if (!reg8) {
die("Invalid tRAS value.\n");
}
while ((tRAS_time >> 2) < reg8) {
tRAS_time += freq_multiplier;
tRAS_cycles++;
}
- }
- if(tRAS_cycles > 0x18) {
die("DDR-II Module does not support this frequency (tRAS
error)\n");
- }
- printk_debug("tRAS = %d cycles\n", tRAS_cycles);
- sysinfo->tras = tRAS_cycles;
+}
+static void sdram_detect_smallest_tRP(struct sys_info * sysinfo) +{
- int i;
- int tRP_time;
- int tRP_cycles;
- int freq_multiplier = 0;
- switch (sysinfo->memory_frequency) {
- case 400: freq_multiplier = 0x14; break; /* 5ns */
- case 533: freq_multiplier = 0x0f; break; /* 3.75ns */
- case 667: freq_multiplier = 0x0c; break; /* 3ns */
- }
- tRP_cycles = 2; /* 2 clocks minimum */
- tRP_time = tRP_cycles * freq_multiplier;
- for (i=0; i<2*DIMM_SOCKETS; i++) {
u8 reg8;
if (sysinfo->dimm[i] == SYSINFO_DIMM_NOT_POPULATED)
continue;
reg8 = spd_read_byte(DIMM_SPD_BASE + i,
SPD_MIN_ROW_PRECHARGE_TIME);
if (!reg8) {
die("Invalid tRP value.\n");
}
while (tRP_time < reg8) {
tRP_time += freq_multiplier;
tRP_cycles++;
}
- }
- if(tRP_cycles > 6) {
die("DDR-II Module does not support this frequency (tRP
error)\n");
- }
- printk_debug("tRP = %d cycles\n", tRP_cycles);
- sysinfo->trp = tRP_cycles;
+}
+static void sdram_detect_smallest_tRCD(struct sys_info * sysinfo) +{
- int i;
- int tRCD_time;
- int tRCD_cycles;
- int freq_multiplier = 0;
- switch (sysinfo->memory_frequency) {
- case 400: freq_multiplier = 0x14; break; /* 5ns */
- case 533: freq_multiplier = 0x0f; break; /* 3.75ns */
- case 667: freq_multiplier = 0x0c; break; /* 3ns */
- }
- tRCD_cycles = 2;
- tRCD_time = tRCD_cycles * freq_multiplier;
- for (i=0; i<2*DIMM_SOCKETS; i++) {
u8 reg8;
if (sysinfo->dimm[i] == SYSINFO_DIMM_NOT_POPULATED)
continue;
reg8 = spd_read_byte(DIMM_SPD_BASE + i,
SPD_MIN_RAS_TO_CAS_DELAY);
if (!reg8) {
die("Invalid tRCD value.\n");
}
while (tRCD_time < reg8) {
tRCD_time += freq_multiplier;
tRCD_cycles++;
}
- }
- if(tRCD_cycles > 6) {
die("DDR-II Module does not support this frequency (tRCD
error)\n");
- }
- printk_debug("tRCD = %d cycles\n", tRCD_cycles);
- sysinfo->trcd = tRCD_cycles;
+}
+static void sdram_detect_smallest_tWR(struct sys_info * sysinfo) +{
- int i;
- int tWR_time;
- int tWR_cycles;
- int freq_multiplier = 0;
- switch (sysinfo->memory_frequency) {
- case 400: freq_multiplier = 0x14; break; /* 5ns */
- case 533: freq_multiplier = 0x0f; break; /* 3.75ns */
- case 667: freq_multiplier = 0x0c; break; /* 3ns */
- }
- tWR_cycles = 2; /* 2 clocks minimum */
- tWR_time = tWR_cycles * freq_multiplier;
- for (i=0; i<2*DIMM_SOCKETS; i++) {
u8 reg8;
if (sysinfo->dimm[i] == SYSINFO_DIMM_NOT_POPULATED)
continue;
reg8 = spd_read_byte(DIMM_SPD_BASE + i,
SPD_WRITE_RECOVERY_TIME);
if (!reg8) {
die("Invalid tWR value.\n");
}
while (tWR_time < reg8) {
tWR_time += freq_multiplier;
tWR_cycles++;
}
- }
- if(tWR_cycles > 5) {
die("DDR-II Module does not support this frequency (tWR
error)\n");
- }
- printk_debug("tWR = %d cycles\n", tWR_cycles);
- sysinfo->twr = tWR_cycles;
+}
+static void sdram_detect_smallest_tRFC(struct sys_info * sysinfo) +{
- int i, index = 0;
- const u8 tRFC_cycles[] = {
/* 75 105 127.5 */
15, 21, 26, /* DDR2-400 */
20, 28, 34, /* DDR2-533 */
25, 35, 43 /* DDR2-667 */
- };
- for (i=0; i<2*DIMM_SOCKETS; i++) {
u8 reg8;
if (sysinfo->dimm[i] == SYSINFO_DIMM_NOT_POPULATED)
continue;
reg8 = sysinfo->banksize[i*2];
switch (reg8) {
case 0x04: reg8 = 0; break;
case 0x08: reg8 = 1; break;
case 0x10: reg8 = 2; break;
case 0x20: reg8 = 3; break;
}
if (sysinfo->dimm[i] == SYSINFO_DIMM_X16DS ||
sysinfo->dimm[i] == SYSINFO_DIMM_X16SS)
reg8++;
if (reg8 > 3) {
/* Can this happen? Go back to 127.5ns just to be
sure
* we don't run out of the array. This may be wrong
*/
printk_debug("DIMM %d is 1Gb x16.. Please
report.\n", i);
reg8 = 3;
}
if (reg8 > index)
index = reg8;
- }
- index--;
- switch (sysinfo->memory_frequency) {
- case 667: index += 3;
- case 533: index += 3;
- case 400: break;
- }
- sysinfo->trfc = tRFC_cycles[index];
- printk_debug("tRFC = %d cycles\n", tRFC_cycles[index]);
+}
+static void sdram_detect_smallest_refresh(struct sys_info * sysinfo) +{
- int i;
- sysinfo->refresh = 0;
- for (i=0; i<2*DIMM_SOCKETS; i++) {
int refresh;
if (sysinfo->dimm[i] == SYSINFO_DIMM_NOT_POPULATED)
continue;
refresh = spd_read_byte(DIMM_SPD_BASE + i, SPD_REFRESH) &
~(1 << 7);
/* 15.6us */
if (!refresh)
continue;
/* Refresh is slower than 15.6us, use 15.6us */
if (refresh > 2)
continue;
if (refresh == 2) {
sysinfo->refresh = 1;
break;
}
// It looks like there is only one unsupported value (1) could say that here // If that value means 3.9 us: // die("DDR-II module has unsupported refresh value (3.9 us)\n");
die("DDR-II module has unsupported refresh value\n");
- }
- printk_debug("Refresh: %s\n", sysinfo->refresh?"7.8us":"15.6us");
+}
+static void sdram_verify_burst_length(struct sys_info * sysinfo) +{
- int i;
- for (i=0; i<2*DIMM_SOCKETS; i++) {
if (sysinfo->dimm[i] == SYSINFO_DIMM_NOT_POPULATED)
continue;
if (!(spd_read_byte(DIMM_SPD_BASE + i,
SPD_SUPPORTED_BURST_LENGTHS) & SPD_BURST_LENGTH_8))
die("Only DDR-II RAM with burst length 8 is
supported by this chipset.\n");
- }
+}
+static void sdram_program_dram_width(struct sys_info * sysinfo) +{
- u16 c0dramw=0, c1dramw=0;
- int idx;
- if (sysinfo->dual_channel)
idx = 2;
- else
idx = 1;
- switch (sysinfo->dimm[0]) {
- case 0: c0dramw = 0x0000; break; /* x16DS */
- case 1: c0dramw = 0x0001; break; /* x8DS */
- case 2: c0dramw = 0x0000; break; /* x16SS */
- case 3: c0dramw = 0x0005; break; /* x8DDS */
- case 4: c0dramw = 0x0000; break; /* NC */
- }
- switch (sysinfo->dimm[idx]) {
- case 0: c1dramw = 0x0000; break; /* x16DS */
- case 1: c1dramw = 0x0010; break; /* x8DS */
- case 2: c1dramw = 0x0000; break; /* x16SS */
- case 3: c1dramw = 0x0050; break; /* x8DDS */
- case 4: c1dramw = 0x0000; break; /* NC */
- }
- if ( !sdram_capabilities_dual_channel() ) {
/* Single Channel */
c0dramw |= c1dramw;
c1dramw = 0;
- }
- MCHBAR16(C0DRAMW) = c0dramw;
- MCHBAR16(C1DRAMW) = c1dramw;
+}
+static void sdram_write_slew_rates(u32 offset, const u32
*slew_rate_table)
+{
- int i;
- for (i=0; i<16; i++)
MCHBAR32(offset+(i*4)) = slew_rate_table[i];
+}
+static void sdram_rcomp_buffer_strength_and_slew(struct sys_info
*sysinfo)
+{
- static const u32 dq2030[] = {
0x08070706, 0x0a090908, 0x0d0c0b0a, 0x12100f0e,
0x1a181614, 0x22201e1c, 0x2a282624, 0x3934302d,
0x0a090908, 0x0c0b0b0a, 0x0e0d0d0c, 0x1211100f,
0x19171513, 0x211f1d1b, 0x2d292623, 0x3f393531
- };
- static const u32 dq2330[] = {
0x08070706, 0x0a090908, 0x0d0c0b0a, 0x12100f0e,
0x1a181614, 0x22201e1c, 0x2a282624, 0x3934302d,
0x0a090908, 0x0c0b0b0a, 0x0e0d0d0c, 0x1211100f,
0x19171513, 0x211f1d1b, 0x2d292623, 0x3f393531
- };
- static const u32 cmd2710[] = {
0x07060605, 0x0f0d0b09, 0x19171411, 0x1f1f1d1b,
0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f,
0x1110100f, 0x0f0d0b09, 0x19171411, 0x1f1f1d1b,
0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f
- };
- static const u32 cmd3210[] = {
0x0f0d0b0a, 0x17151311, 0x1f1d1b19, 0x1f1f1f1f,
0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f,
0x18171615, 0x1f1f1c1a, 0x1f1f1f1f, 0x1f1f1f1f,
0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f
- };
- static const u32 clk2030[] = {
0x0e0d0d0c, 0x100f0f0e, 0x100f0e0d, 0x15131211,
0x1d1b1917, 0x2523211f, 0x2a282927, 0x32302e2c,
0x17161514, 0x1b1a1918, 0x1f1e1d1c, 0x23222120,
0x27262524, 0x2d2b2928, 0x3533312f, 0x3d3b3937
- };
- static const u32 ctl3215[] = {
0x01010000, 0x03020101, 0x07060504, 0x0b0a0908,
0x100f0e0d, 0x14131211, 0x18171615, 0x1c1b1a19,
0x05040403, 0x07060605, 0x0a090807, 0x0f0d0c0b,
0x14131211, 0x18171615, 0x1c1b1a19, 0x201f1e1d
- };
- static const u32 ctl3220[] = {
0x05040403, 0x07060505, 0x0e0c0a08, 0x1a171411,
0x2825221f, 0x35322f2b, 0x3e3e3b38, 0x3e3e3e3e,
0x09080807, 0x0b0a0a09, 0x0f0d0c0b, 0x1b171311,
0x2825221f, 0x35322f2b, 0x3e3e3b38, 0x3e3e3e3e
- };
- static const u32 nc[] = {
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000
- };
- static const u32 const * const dual_channel_slew_group_lookup[] = {
dq2030, cmd3210, ctl3215, ctl3215, clk2030, clk2030, dq2030,
cmd3210,
dq2030, cmd3210, ctl3215, ctl3215, clk2030, clk2030, dq2030,
cmd3210,
dq2030, cmd3210, nc, ctl3215, nc, clk2030, dq2030,
cmd3210,
dq2030, cmd3210, ctl3215, ctl3215, clk2030, clk2030, dq2030,
cmd2710,
dq2030, cmd3210, nc, ctl3215, nc, clk2030, nc,
nc,
dq2030, cmd3210, ctl3215, ctl3215, clk2030, clk2030, dq2030,
cmd3210,
dq2030, cmd3210, ctl3215, nc, clk2030, nc, dq2030,
cmd3210,
dq2030, cmd3210, ctl3215, ctl3215, clk2030, clk2030, dq2030,
cmd3210,
dq2030, cmd3210, ctl3215, nc, clk2030, nc, dq2030,
cmd2710,
dq2030, cmd3210, ctl3215, nc, clk2030, nc, nc,
nc,
dq2030, cmd3210, nc, ctl3215, nc, clk2030, dq2030,
cmd3210,
dq2030, cmd3210, ctl3215, ctl3215, clk2030, clk2030, dq2030,
cmd3210,
dq2030, cmd3210, nc, ctl3215, nc, clk2030, dq2030,
cmd3210,
dq2030, cmd3210, ctl3215, ctl3215, clk2030, clk2030, dq2030,
cmd2710,
dq2030, cmd3210, nc, ctl3215, nc, clk2030, nc,
nc,
dq2030, cmd2710, ctl3215, ctl3215, clk2030, clk2030, dq2030,
cmd3210,
dq2030, cmd2710, ctl3215, nc, clk2030, nc, dq2030,
cmd3210,
dq2030, cmd2710, ctl3215, ctl3215, clk2030, clk2030, dq2030,
cmd3210,
dq2030, cmd2710, ctl3215, nc, clk2030, nc, dq2030,
cmd2710,
dq2030, cmd2710, ctl3215, nc, clk2030, nc, nc,
nc,
nc, nc, nc, ctl3215, nc, clk2030, dq2030,
cmd3210,
nc, nc, ctl3215, nc, clk2030, nc, dq2030,
cmd3210,
nc, nc, nc, ctl3215, nc, clk2030, dq2030,
cmd3210,
nc, nc, ctl3215, nc, clk2030, clk2030, dq2030,
cmd2710
- };
- static const u32 const * const single_channel_slew_group_lookup[] =
{
dq2330, cmd3210, ctl3215, ctl3215, clk2030, clk2030, dq2330,
cmd3210,
dq2330, cmd3210, ctl3215, ctl3215, clk2030, clk2030, dq2330,
cmd3210,
dq2330, cmd3210, nc, ctl3215, nc, clk2030, dq2330,
cmd3210,
dq2330, cmd3210, ctl3215, ctl3215, clk2030, clk2030, dq2330,
cmd3210,
dq2330, cmd3210, nc, ctl3215, nc, clk2030, nc,
nc,
dq2330, cmd3210, ctl3215, ctl3215, clk2030, clk2030, dq2330,
cmd3210,
dq2330, cmd3210, ctl3215, nc, clk2030, nc, dq2330,
cmd3210,
dq2330, cmd3210, ctl3215, ctl3215, clk2030, clk2030, dq2330,
cmd3210,
dq2330, cmd3210, ctl3215, nc, clk2030, nc, dq2330,
cmd3210,
dq2330, cmd3210, ctl3215, nc, clk2030, nc, nc,
nc,
dq2330, cmd3210, nc, ctl3215, nc, clk2030, dq2330,
cmd3210,
dq2330, cmd3210, ctl3215, ctl3215, clk2030, clk2030, dq2330,
cmd3210,
dq2330, cmd3210, nc, ctl3215, nc, clk2030, dq2330,
cmd3210,
dq2330, cmd3210, ctl3215, ctl3215, clk2030, clk2030, dq2330,
cmd3210,
dq2330, cmd3210, nc, ctl3215, nc, clk2030, nc,
nc,
dq2330, cmd3210, ctl3215, ctl3215, clk2030, clk2030, dq2330,
cmd3210,
dq2330, cmd3210, ctl3215, nc, clk2030, nc, dq2330,
cmd3210,
dq2330, cmd3210, ctl3215, ctl3215, clk2030, clk2030, dq2330,
cmd3210,
dq2330, cmd3210, ctl3215, nc, clk2030, nc, dq2330,
cmd3210,
dq2330, cmd3210, ctl3215, nc, clk2030, nc, nc,
nc,
dq2330, nc, nc, ctl3215, nc, clk2030, dq2030,
cmd3210,
dq2330, nc, ctl3215, nc, clk2030, nc, dq2030,
cmd3210,
dq2330, nc, nc, ctl3215, nc, clk2030, dq2030,
cmd3210,
dq2330, nc, ctl3215, nc, clk2030, clk2030, dq2030,
cmd3210
- };
- /* Strength multiplier tables */
- static const u8 dual_channel_strength_multiplier[] = {
0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x22,
0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
0x44, 0x11, 0x11, 0x00, 0x44, 0x00, 0x44, 0x11,
0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
0x44, 0x11, 0x11, 0x00, 0x44, 0x00, 0x44, 0x22,
0x44, 0x11, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x22,
0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
0x44, 0x22, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
0x44, 0x22, 0x11, 0x00, 0x44, 0x00, 0x44, 0x11,
0x44, 0x22, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
0x44, 0x22, 0x11, 0x00, 0x44, 0x00, 0x44, 0x22,
0x44, 0x22, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
0x00, 0x00, 0x11, 0x00, 0x44, 0x00, 0x44, 0x11,
0x00, 0x00, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
0x00, 0x00, 0x11, 0x00, 0x44, 0x44, 0x44, 0x22
- };
- static const u8 single_channel_strength_multiplier[] = {
0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
0x33, 0x00, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
0x33, 0x00, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
0x33, 0x00, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
0x33, 0x00, 0x11, 0x00, 0x44, 0x44, 0x33, 0x11
- };
- const u8 * strength_multiplier;
- const u32* const * slew_group_lookup;
- int idx;
- /* Set Strength Multipliers */
- /* Dual Channel needs different tables. */
- if (sdram_capabilities_dual_channel()) {
printk_debug("Programming Dual Channel RCOMP\r\n");
strength_multiplier = dual_channel_strength_multiplier;
slew_group_lookup = dual_channel_slew_group_lookup;
idx = 5 * sysinfo->dimm[0] + sysinfo->dimm[2];
- } else {
printk_debug("Programming Single Channel RCOMP\r\n");
strength_multiplier = single_channel_strength_multiplier;
slew_group_lookup = single_channel_slew_group_lookup;
idx = 5 * sysinfo->dimm[0] + sysinfo->dimm[1];
- }
- printk_debug("Table Index: %d\r\n", idx);
- MCHBAR8(G1SC) = strength_multiplier[idx * 8 + 0];
- MCHBAR8(G2SC) = strength_multiplier[idx * 8 + 1];
- MCHBAR8(G3SC) = strength_multiplier[idx * 8 + 2];
- MCHBAR8(G4SC) = strength_multiplier[idx * 8 + 3];
- MCHBAR8(G5SC) = strength_multiplier[idx * 8 + 4];
- MCHBAR8(G6SC) = strength_multiplier[idx * 8 + 5];
- MCHBAR8(G7SC) = strength_multiplier[idx * 8 + 6];
- MCHBAR8(G8SC) = strength_multiplier[idx * 8 + 7];
- /* Channel 0 */
- sdram_write_slew_rates(G1SRPUT, slew_group_lookup[idx * 8 + 0]);
- sdram_write_slew_rates(G2SRPUT, slew_group_lookup[idx * 8 + 1]);
- if ((slew_group_lookup[idx * 8 + 2] != nc) && (sysinfo->package ==
SYSINFO_PACKAGE_STACKED)) {
sdram_write_slew_rates(G3SRPUT, ctl3220);
- } else {
sdram_write_slew_rates(G3SRPUT, slew_group_lookup[idx * 8 +
2]);
- }
- sdram_write_slew_rates(G4SRPUT, slew_group_lookup[idx * 8 + 3]);
- sdram_write_slew_rates(G5SRPUT, slew_group_lookup[idx * 8 + 4]);
- sdram_write_slew_rates(G6SRPUT, slew_group_lookup[idx * 8 + 5]);
- /* Channel 1 */
- if (sysinfo->dual_channel) {
sdram_write_slew_rates(G7SRPUT, slew_group_lookup[idx * 8 +
6]);
sdram_write_slew_rates(G8SRPUT, slew_group_lookup[idx * 8 +
7]);
- } else {
sdram_write_slew_rates(G7SRPUT, nc);
sdram_write_slew_rates(G8SRPUT, nc);
- }
+}
+static void sdram_enable_rcomp(void) +{
- u32 reg32;
- udelay(300);
- reg32 = MCHBAR32(GBRCOMPCTL);
- reg32 &= ~(1 << 23);
- MCHBAR32(GBRCOMPCTL) = reg32;
+}
+static void sdram_program_dll_timings(struct sys_info *sysinfo) +{
- u32 chan0dll = 0, chan1dll = 0;
- int i;
- printk_debug ("Programming DLL Timings... \r\n");
- MCHBAR16(DQSMT) &= ~( (3 << 12) | (1 << 10) | ( 0xf << 0) );
- MCHBAR16(DQSMT) |= (1 << 13) | (0xc << 0);
- /* We drive both channels with the same speed */
- switch (sysinfo->memory_frequency) {
- case 400: chan0dll = 0x26262626; chan1dll=0x26262626; break; /*
400MHz */
- case 533: chan0dll = 0x22222222; chan1dll=0x22222222; break; /*
533MHz */
- case 667: chan0dll = 0x11111111; chan1dll=0x11111111; break; /*
667MHz */
- }
- for (i=0; i < 4; i++) {
MCHBAR32(C0R0B00DQST + (i * 0x10) + 0) = chan0dll;
MCHBAR32(C0R0B00DQST + (i * 0x10) + 4) = chan0dll;
MCHBAR32(C1R0B00DQST + (i * 0x10) + 0) = chan1dll;
MCHBAR32(C1R0B00DQST + (i * 0x10) + 4) = chan1dll;
- }
+}
+static void sdram_force_rcomp(void) +{
- u32 reg32;
- u8 reg8;
- reg32 = MCHBAR32(ODTC);
- reg32 |= (1 << 28);
- MCHBAR32(ODTC) = reg32;
- reg32 = MCHBAR32(SMSRCTL);
- reg32 |= (1 << 0);
- MCHBAR32(SMSRCTL) = reg32;
- reg32 = MCHBAR32(GBRCOMPCTL);
- reg32 |= (1 << 8);
- MCHBAR32(GBRCOMPCTL) = reg32;
- reg8 = i945_silicon_revision();
- if ((reg8 == 0 && (MCHBAR32(DCC) & (3 << 0)) == 0) || (reg8 == 1)) {
reg32 = MCHBAR32(GBRCOMPCTL);
reg32 |= (3 << 5);
MCHBAR32(GBRCOMPCTL) = reg32;
- }
+}
+static void sdram_initialize_system_memory_io(struct sys_info *sysinfo) +{
- u8 reg8;
- u32 reg32;
- printk_debug ("Initializing System Memory IO... \r\n");
- reg8 = MCHBAR8(C0HCTC);
- reg8 &= ~0x1f;
- reg8 |= ( 1 << 0);
- MCHBAR8(C0HCTC) = reg8;
- reg8 = MCHBAR8(C1HCTC);
- reg8 &= ~0x1f;
- reg8 |= ( 1 << 0);
- MCHBAR8(C1HCTC) = reg8;
- MCHBAR16(WDLLBYPMODE) &= ~( (1 << 9) | (1 << 6) | (1 << 4) | (1 <<
3) | (1 << 1) );
- MCHBAR16(WDLLBYPMODE) |= (1 << 8) | (1 << 7) | (1 << 5) | (1 << 2) |
(1 << 0);
- MCHBAR8(C0WDLLCMC) = 0;
- MCHBAR8(C1WDLLCMC) = 0;
- sdram_program_dram_width(sysinfo);
- sdram_rcomp_buffer_strength_and_slew(sysinfo);
- reg32 = MCHBAR32(GBRCOMPCTL);
- reg32 &= ~( (1 << 29) | (1 << 26) | (3 << 21) | (3 << 2) );
- reg32 |= (3 << 27) | (3 << 0);
- MCHBAR32(GBRCOMPCTL) = reg32;
- MCHBAR32(GBRCOMPCTL) |= (1 << 10);
- sdram_program_dll_timings(sysinfo);
- sdram_force_rcomp();
+}
+static void sdram_enable_system_memory_io(struct sys_info *sysinfo) +{
- u32 reg32;
- printk_debug ("Enabling System Memory IO... \r\n");
- reg32 = MCHBAR32(RCVENMT);
- reg32 &= ~(0x3f << 6);
- MCHBAR32(RCVENMT) = reg32;
- reg32 |= (1 << 11) | (1 << 9);
- MCHBAR32(RCVENMT) = reg32;
- reg32 = MCHBAR32(DRTST);
- reg32 |= (1 << 3) | (1 << 2);
- MCHBAR32(DRTST) = reg32;
- reg32 = MCHBAR32(DRTST);
- reg32 |= (1 << 6) | (1 << 4);
- MCHBAR32(DRTST) = reg32;
- asm volatile ("nop; nop;");
- reg32 = MCHBAR32(DRTST);
- /* Is channel 0 populated? */
- if (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED ||
sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)
reg32 |= (1 << 7) | (1 << 5);
- else
reg32 |= (1 << 31);
- /* Is channel 1 populated? */
- if (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)
reg32 |= (1 << 9) | (1 << 8);
- else
reg32 |= (1 << 30);
- MCHBAR32(DRTST) = reg32;
- if (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED ||
sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED) {
reg32 = MCHBAR32(C0DRC1);
reg32 |= (1 << 8);
MCHBAR32(C0DRC1) = reg32;
- }
- if (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED) {
reg32 = MCHBAR32(C1DRC1);
reg32 |= (1 << 8);
MCHBAR32(C1DRC1) = reg32;
- }
+}
+struct dimm_size {
- unsigned long side1;
- unsigned long side2;
+};
+static struct dimm_size sdram_get_dimm_size(u16 device) +{
- /* Calculate the log base 2 size of a DIMM in bits */
- struct dimm_size sz;
- int value, low, rows, columns;
- sz.side1 = 0;
- sz.side2 = 0;
- rows = spd_read_byte(device, SPD_NUM_ROWS); /* rows */
- if (rows < 0) goto hw_err;
- if ((rows & 0xf) == 0) goto val_err;
- sz.side1 += rows & 0xf;
- columns = spd_read_byte(device, SPD_NUM_COLUMNS); /* columns
*/
- if (columns < 0) goto hw_err;
- if ((columns & 0xf) == 0) goto val_err;
- sz.side1 += columns & 0xf;
- value = spd_read_byte(device, SPD_NUM_BANKS_PER_SDRAM); /* 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, SPD_MODULE_DATA_WIDTH_MSB); /*
(high byte) */
- if (value < 0) goto hw_err;
- value &= 0xff;
- value <<= 8;
- low = spd_read_byte(device, SPD_MODULE_DATA_WIDTH_LSB); /* (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, SPD_NUM_DIMM_BANKS); /* number of
physical banks */
- if (value < 0) goto hw_err;
- value &= 7;
- value++;
- if (value == 1) goto out;
- if (value != 2) goto val_err;
- /* Start with the symmetrical case */
- sz.side2 = sz.side1;
- if ((rows & 0xf0) == 0) goto out; /* If symmetrical we are
done */
- /* Don't die here, I have not come across any of these to test what
* actually happens.
*/
- printk_err("Assymetric DIMMs are not supported by this chipset\n");
- sz.side2 -= (rows & 0x0f); /* Subtract out rows on side
1 */
- sz.side2 += ((rows >> 4) & 0x0f); /* Add in rows on side 2 */
- sz.side2 -= (columns & 0x0f); /* Subtract out columns on
side 1 */
- sz.side2 += ((columns >> 4) & 0x0f); /* Add in columns on side 2
*/
- goto out;
- val_err:
- die("Bad SPD value\r\n");
- hw_err:
- /* If a hardware error occurs the spd rom probably does not exist.
* In this case report that there is no memory
*/
- sz.side1 = 0;
- sz.side2 = 0;
- out:
- return sz;
+}
+static void sdram_detect_dimm_size(struct sys_info * sysinfo) +{
- int i;
- for(i = 0; i < 2 * DIMM_SOCKETS; i++) {
struct dimm_size sz;
sysinfo->banksize[i * 2] = 0;
sysinfo->banksize[(i * 2) + 1] = 0;
if (sysinfo->dimm[i] == SYSINFO_DIMM_NOT_POPULATED)
continue;
sz = sdram_get_dimm_size(DIMM_SPD_BASE + i);
sysinfo->banks[i] = spd_read_byte(DIMM_SPD_BASE + i,
SPD_NUM_BANKS_PER_SDRAM); /* banks */
if (sz.side1 < 30)
die("DDR-II rank size smaller than 128MB is not
supported.\n");
sysinfo->banksize[i * 2] = sz.side1 - 30;
printk_debug("DIMM %d side 0 = %d MB\n", i, (1 <<
sysinfo->banksize[i * 2]) * 128 );
if (!sz.side2)
continue;
/* If there is a second side, it has to have at least 128M,
too */
if (sz.side2 < 30)
die("DDR-II rank size smaller than 128MB is not
supported.\n");
sysinfo->banksize[(i * 2) + 1] = sz.side2 - 30;
printk_debug("DIMM %d side 1 = %d MB\n", i, (1 <<
sysinfo->banksize[(i * 2) + 1]) * 128);
- }
+}
+static int sdram_program_row_boundaries(struct sys_info *sysinfo) +{
- int i;
- int cum0, cum1, tolud;
- printk_debug ("Setting RAM size... \r\n");
- cum0 = 0;
- for(i = 0; i < 2 * DIMM_SOCKETS; i++) {
cum0 += (sysinfo->banksize[i] << 3);
MCHBAR8(C0DRB0+i) = cum0;
- }
- /* Assume we continue in Channel 1 where we stopped in Channel 0 */
- cum1 = cum0;
- /* Exception: Interleaved starts from the beginning */
- if (sysinfo->interleaved)
cum1 = 0;
- /* Exception: Channel 1 is not populated. C1DRB stays zero */
- if (sysinfo->dimm[2] == SYSINFO_DIMM_NOT_POPULATED &&
sysinfo->dimm[3] == SYSINFO_DIMM_NOT_POPULATED)
cum1 = 0;
- for(i = 0; i < 2 * DIMM_SOCKETS; i++) {
cum1 += (sysinfo->banksize[i + 4] << 3);
MCHBAR8(C1DRB0+i) = cum1;
- }
- /* Set TOLUD Top Of Low Usable DRAM */
- if (sysinfo->interleaved)
tolud = (cum0 + cum1) << 1;
- else
tolud = (cum1 ? cum1 : cum0) << 1;
- pci_write_config16(PCI_DEV(0,0,0), TOLUD, tolud);
- printk_debug("C0DRB = 0x%08x\r\n", MCHBAR32(C0DRB0));
- printk_debug("C1DRB = 0x%08x\r\n", MCHBAR32(C1DRB0));
- printk_debug("TOLUD = 0x%04x\r\n", tolud);
- pci_write_config16(PCI_DEV(0,0,0), TOM, tolud>>3);
- return 0;
+}
+static int sdram_set_row_attributes(struct sys_info *sysinfo) +{
- int i, value;
- u16 dra0=0, dra1=0, dra = 0;
- printk_debug ("Setting row attributes... \r\n");
- for(i=0; i < 2 * DIMM_SOCKETS; i++) {
u16 device;
u8 columnsrows;
if (sysinfo->dimm[i] == SYSINFO_DIMM_NOT_POPULATED) {
continue;
}
device = DIMM_SPD_BASE + i;
columnsrows = 0;
value = spd_read_byte(device, SPD_NUM_ROWS); /* rows */
columnsrows = (value & 0x0f);
value = spd_read_byte(device, SPD_NUM_COLUMNS); /* columns
*/
columnsrows |= (value & 0xf) << 4;
switch (columnsrows) {
case 0x9d: dra = 2; break;
case 0xad: dra = 3; break;
case 0xbd: dra = 4; break;
case 0xae: dra = 3; break;
case 0xbe: dra = 4; break;
default: die("Unsupported Rows/Columns. (DRA)");
}
/* Double Sided DIMMs? */
if (sysinfo->banksize[(2 * i) + 1] != 0) {
dra = (dra << 4) | dra;
}
if (i < DIMM_SOCKETS)
dra0 |= (dra << (i*8));
else
dra1 |= (dra << ((i - DIMM_SOCKETS)*8));
- }
- MCHBAR16(C0DRA0) = dra0;
- MCHBAR16(C1DRA0) = dra1;
- printk_debug("C0DRA = 0x%04x\r\n", dra0);
- printk_debug("C1DRA = 0x%04x\r\n", dra1);
- return 0;
+}
+static void sdram_set_bank_architecture(struct sys_info *sysinfo) +{
- u32 off32;
- int i;
- MCHBAR16(C1BNKARC) &= 0xff00;
- MCHBAR16(C0BNKARC) &= 0xff00;
- off32 = C0BNKARC;
- for (i=0; i < 2 * DIMM_SOCKETS; i++) {
/* Switch to second channel */
if (i == DIMM_SOCKETS)
off32 = C1BNKARC;
if (sysinfo->dimm[i] == SYSINFO_DIMM_NOT_POPULATED)
continue;
if (sysinfo->banks[i] != 8)
continue;
printk_spew("DIMM%d has 8 banks.\n");
if (i & 1)
MCHBAR16(off32) |= 0x50;
else
MCHBAR16(off32) |= 0x05;
- }
+}
+#define REFRESH_7_8US 1 +#define REFRESH_15_6US 0 +static void sdram_program_refresh_rate(struct sys_info *sysinfo) +{
- u32 reg32;
- if (sysinfo->refresh == REFRESH_7_8US) {
reg32 = (2 << 8); /* Refresh enabled at 7.8us */
- } else {
reg32 = (1 << 8); /* Refresh enabled at 15.6us */
- }
- MCHBAR32(C0DRC0) &= ~(7 << 8);
- MCHBAR32(C0DRC0) |= reg32;
- MCHBAR32(C1DRC0) &= ~(7 << 8);
- MCHBAR32(C1DRC0) |= reg32;
+}
+static void sdram_program_cke_tristate(struct sys_info *sysinfo) +{
- u32 reg32;
- int i;
- reg32 = MCHBAR32(C0DRC1);
- for (i=0; i < 4; i++) {
if (sysinfo->banksize[i] == 0) {
reg32 |= (1 << (16 + i));
}
- }
- reg32 |= (1 << 12);
- reg32 |= (1 << 11);
- MCHBAR32(C0DRC1) = reg32;
- /* Do we have to do this if we're in Single Channel Mode? */
- reg32 = MCHBAR32(C1DRC1);
- for (i=4; i < 8; i++) {
if (sysinfo->banksize[i] == 0) {
reg32 |= (1 << (12 + i));
}
- }
- reg32 |= (1 << 12);
- reg32 |= (1 << 11);
- MCHBAR32(C1DRC1) = reg32;
+}
+static void sdram_program_odt_tristate(struct sys_info *sysinfo) +{
- u32 reg32;
- int i;
- reg32 = MCHBAR32(C0DRC2);
- for (i=0; i < 4; i++) {
if (sysinfo->banksize[i] == 0) {
reg32 |= (1 << (24 + i));
}
- }
- MCHBAR32(C0DRC2) = reg32;
- reg32 = MCHBAR32(C1DRC2);
- for (i=4; i < 8; i++) {
if (sysinfo->banksize[i] == 0) {
reg32 |= (1 << (20 + i));
}
- }
- MCHBAR32(C1DRC2) = reg32;
+}
+static void sdram_set_timing_and_control(struct sys_info *sysinfo) +{
- u32 reg32, off32;
- u32 tWTR;
- u32 temp_drt;
- int i, page_size;
- static const u8 const drt0_table[] = {
/* CL 3, 4, 5 */
3, 4, 5, /* FSB533/400, DDR533/400 */
4, 5, 6, /* FSB667, DDR533/400 */
4, 5, 6, /* FSB667, DDR667 */
- };
- static const u8 const cas_table[] = {
2, 1, 0, 3
- };
- reg32 = MCHBAR32(C0DRC0);
- reg32 |= (1 << 2); /* Burst Length 8 */
- reg32 &= ~( (1 << 13) | (1 << 12) );
- MCHBAR32(C0DRC0) = reg32;
- reg32 = MCHBAR32(C1DRC0);
- reg32 |= (1 << 2); /* Burst Length 8 */
- reg32 &= ~( (1 << 13) | (1 << 12) );
- MCHBAR32(C1DRC0) = reg32;
- if (!sysinfo->dual_channel && sysinfo->dimm[1] !=
SYSINFO_DIMM_NOT_POPULATED) {
reg32 = MCHBAR32(C0DRC0);
reg32 |= (1 << 15);
MCHBAR32(C0DRC0) = reg32;
- }
- sdram_program_refresh_rate(sysinfo);
- sdram_program_cke_tristate(sysinfo);
- sdram_program_odt_tristate(sysinfo);
- /* Calculate DRT0 */
- temp_drt = 0;
- /* B2B Write Precharge (same bank) = CL-1 + BL/2 + tWR */
- reg32 = (sysinfo->cas - 1) + (BURSTLENGTH / 2) + sysinfo->twr;
- temp_drt |= (reg32 << 28);
- /* Write Auto Precharge (same bank) = CL-1 + BL/2 + tWR + tRP */
- reg32 += sysinfo->trp;
- temp_drt |= (reg32 << 4);
- if (sysinfo->memory_frequency == 667) {
tWTR = 3; /* 667MHz */
- } else {
tWTR = 2; /* 400 and 533 */
- }
- /* B2B Write to Read Command Spacing */
- reg32 = (sysinfo->cas - 1) + (BURSTLENGTH / 2) + tWTR;
- temp_drt |= (reg32 << 24);
- temp_drt |= ( (1 << 22) | (3 << 20) | (1 << 18) | (0 << 16) );
- /* Program Write Auto Precharge to Activate */
- off32 = 0;
- if (sysinfo->fsb_frequency == 667) { /* 667MHz FSB */
off32 += 3;
- }
- if (sysinfo->memory_frequency == 667) {
off32 += 3;
- }
- off32 += sysinfo->cas - 3;
- reg32 = drt0_table[off32];
- temp_drt |= (reg32 << 11);
- /* Read Auto Precharge to Activate */
- temp_drt |= (8 << 0);
- MCHBAR32(C0DRT0) = temp_drt;
- MCHBAR32(C1DRT0) = temp_drt;
- /* Calculate DRT1 */
- temp_drt = MCHBAR32(C0DRT1) & 0x00020088;
- /* DRAM RASB Precharge */
- temp_drt |= (sysinfo->trp - 2) << 0;
- /* DRAM RASB to CASB Delay */
- temp_drt |= (sysinfo->trcd - 2) << 4;
- /* CASB Latency */
- temp_drt |= (cas_table[sysinfo->cas - 3]) << 8;
- /* Refresh Cycle Time */
- temp_drt |= (sysinfo->trfc) << 10;
- /* Pre-All to Activate Delay */
- temp_drt |= (0 << 16);
- /* Precharge to Precharge Delay stays at 1 clock */
- temp_drt |= (0 << 18);
- /* Activate to Precharge Delay */
- temp_drt |= (sysinfo->tras << 19);
- /* Read to Precharge (tRTP) */
- if (sysinfo->memory_frequency == 667) {
temp_drt |= (1 << 28);
- } else {
temp_drt |= (0 << 28);
- }
- /* Determine page size */
- reg32 = 0;
- page_size = 1; /* Default: 1k pagesize */
- for (i=0; i< 2*DIMM_SOCKETS; i++) {
if (sysinfo->dimm[i] == SYSINFO_DIMM_X16DS ||
sysinfo->dimm[i] == SYSINFO_DIMM_X16SS)
page_size = 2; /* 2k pagesize */
- }
- if (sysinfo->memory_frequency == 533 && page_size == 2) {
reg32 = 1;
- }
- if (sysinfo->memory_frequency == 667) {
reg32 = page_size;
- }
- temp_drt |= (reg32 << 30);
- MCHBAR32(C0DRT1) = temp_drt;
- MCHBAR32(C1DRT1) = temp_drt;
- /* Program DRT2 */
- reg32 = MCHBAR32(C0DRT2);
- reg32 &= ~(1 << 8);
- MCHBAR32(C0DRT2) = reg32;
- reg32 = MCHBAR32(C1DRT2);
- reg32 &= ~(1 << 8);
- MCHBAR32(C1DRT2) = reg32;
- /* Calculate DRT3 */
- temp_drt = MCHBAR32(C0DRT3) & ~0x07ffffff;
- /* Get old tRFC value */
- reg32 = MCHBAR32(C0DRT1) >> 10;
- reg32 &= 0x3f;
- /* 788nS - tRFC */
- switch (sysinfo->memory_frequency) {
- case 400: /* 5nS */
reg32 = ((78800 / 500) - reg32) & 0x1ff;
reg32 |= (0x8c << 16) | (0x0c << 10); /* 1 us */
break;
- case 533: /* 3.75nS */
reg32 = ((78800 / 375) - reg32) & 0x1ff;
reg32 |= (0xba << 16) | (0x10 << 10); /* 1 us */
break;
- case 667: /* 3nS */
reg32 = ((78800 / 300) - reg32) & 0x1ff;
reg32 |= (0xe9 << 16) | (0x14 << 10); /* 1 us */
break;
- }
- temp_drt |= reg32;
- MCHBAR32(C0DRT3) = temp_drt;
- MCHBAR32(C1DRT3) = temp_drt;
+}
+static void sdram_set_channel_mode(struct sys_info *sysinfo) +{
- u32 reg32;
- printk_debug("Setting mode of operation for memory channels...");
- if (sdram_capabilities_interleave() &&
( ( sysinfo->banksize[0] + sysinfo->banksize[1] +
sysinfo->banksize[2] + sysinfo->banksize[3] ) ==
( sysinfo->banksize[4] + sysinfo->banksize[5] +
sysinfo->banksize[6] + sysinfo->banksize[7] ) ) ) {
/* Both channels equipped with DIMMs of the same size */
sysinfo->interleaved = 1;
- } else {
sysinfo->interleaved = 0;
- }
- reg32 = MCHBAR32(DCC);
- reg32 &= ~(7 << 0);
- if(sysinfo->interleaved) {
/* Dual Channel Interleaved */
printk_debug("Dual Channel Interleaved.\n");
reg32 |= (1 << 1);
- } else if (sysinfo->dimm[0] == SYSINFO_DIMM_NOT_POPULATED &&
sysinfo->dimm[1] == SYSINFO_DIMM_NOT_POPULATED) {
/* Channel 1 only */
printk_debug("Single Channel 1 only.\n");
reg32 |= (1 << 2);
- } else if (sdram_capabilities_dual_channel() && sysinfo->dimm[2] !=
SYSINFO_DIMM_NOT_POPULATED) {
/* Dual Channel Assymetric */
printk_debug("Dual Channel Assymetric.\n");
reg32 |= (1 << 0);
- } else {
/* All bits 0 means Single Channel 0 operation */
printk_debug("Single Channel 0 only.\n");
- }
- reg32 |= (1 << 10);
- MCHBAR32(DCC) = reg32;
- PRINTK_DEBUG("DCC=0x%08x\r\n", MCHBAR32(DCC));
+}
+static void sdram_program_pll_settings(void) +{
- volatile u16 reg16;
- volatile u32 reg32;
- const u8 HPLLGPLLPowerDown[] = {
0x90, /* 400MHz */
0x95, /* 533MHz */
0x00, /* --- */
0x8d, /* 667MHz */
- };
- MCHBAR32(PLLMON) = 0x80800000;
- reg32 = MCHBAR32(CLKCFG);
- reg32 &= (7 << 0);
- reg16 = MCHBAR16(CPCTL);
- reg16 &= 0xff00;
- reg16 |= HPLLGPLLPowerDown[reg32];
- MCHBAR16(CPCTL) = reg16;
- reg16 &= ~(1 << 11);
- MCHBAR16(CPCTL) = reg16;
- reg16 = MCHBAR16(CPCTL);
+}
+static void sdram_program_graphics_frequency(struct sys_info *sysinfo) +{
- u8 reg8;
- u16 reg16;
- u8 freq, second_vco;
+#define CRCLK_166MHz 0x00 +#define CRCLK_200MHz 0x01 +#define CRCLK_250MHz 0x03 +#define CRCLK_400MHz 0x05
+#define CDCLK_200MHz 0x00 +#define CDCLK_320MHz 0x40
- printk_debug ("Setting Graphics Frequency... \r\n");
- reg16 = pci_read_config16(PCI_DEV(0,2,0), GCFC);
- reg16 |= (1<<11) | (1<<9);
- pci_write_config16(PCI_DEV(0,2,0), GCFC, reg16);
- /* Program CPCTL according to FSB speed */
- reg16 = MCHBAR16(CPCTL);
- reg16 &= 0xff00;
- switch (MCHBAR32(CLKCFG) & 0x7) {
- case 0: sysinfo->fsb_frequency = 400; break; /* FSB400 */
- case 1: sysinfo->fsb_frequency = 533; break; /* FSB533 */
- case 3: sysinfo->fsb_frequency = 667; break; /* FSB667 */
- default: die("Unsupported FSB speed");
- }
- switch (sysinfo->fsb_frequency) {
- case 533: reg16 |= 0x95; break; /* FSB533 */
- case 667: reg16 |= 0x8d; break; /* FSB667 */
- }
- MCHBAR16(CPCTL) = reg16;
- /* Get graphics frequency capabilities */
- reg8 = (pci_read_config8(PCI_DEV(0, 0x00,0), 0xe5) & 0x0e) >> 1;
- freq = CRCLK_250MHz;
- switch (reg8) {
- case 0:
if (MCHBAR32(DFT_STRAP1) & (1 << 20))
freq = CRCLK_250MHz;
else
freq = CRCLK_400MHz;
break;
- case 2: freq = CRCLK_250MHz; break;
- case 3: freq = CRCLK_200MHz; break;
- case 4: freq = CRCLK_166MHz; break;
- }
- if (freq != CRCLK_400MHz) {
reg8 = (pci_read_config8(PCI_DEV(0, 0x00,0), 0xe7) & 0x70)
4;
if (reg8==2)
freq = CRCLK_166MHz;
- }
- if (i945_silicon_revision() == 0) {
sysinfo->mvco4x = 1;
- } else {
sysinfo->mvco4x = 0;
- }
- second_vco = 0;
- if (MCHBAR32(DFT_STRAP1) & (1 << 20)) {
second_vco = 1;
- } else if ((i945_silicon_revision() > 0) && (freq == CRCLK_250MHz))
{
u16 mem = sysinfo->memory_frequency;
u16 fsb = sysinfo->fsb_frequency;
if ( (fsb == 667 && mem == 533) ||
(fsb == 533 && mem == 533) ||
(fsb == 533 && mem == 400)) {
second_vco = 1;
}
if (fsb == 667 && mem == 533)
sysinfo->mvco4x = 1;
- }
- if (second_vco) {
printk_debug("Programming second TCO\r\n");
sysinfo->clkcfg_bit7=1;
- } else {
sysinfo->clkcfg_bit7=0;
- }
- reg16 = pci_read_config16(PCI_DEV(0,2,0), GCFC);
- reg16 &= ~( (7 << 0) | (1 << 13) );
- reg16 |= freq;
- pci_write_config16(PCI_DEV(0,2,0), GCFC, reg16);
- reg16 = pci_read_config16(PCI_DEV(0,2,0), GCFC);
- reg16 &= ~( (1<<7) | (7<<4) );
- if (MCHBAR32(DFT_STRAP1) & (1 << 20)) {
reg16 |= CDCLK_200MHz;
- } else {
reg16 |= CDCLK_320MHz;
- }
- pci_write_config16(PCI_DEV(0,2,0), GCFC, reg16);
- reg16 = pci_read_config16(PCI_DEV(0,2,0), GCFC);
- reg16 &= ~( (1<<10) | (1<<8) );
- pci_write_config16(PCI_DEV(0,2,0), GCFC, reg16);
- reg16 |= (1<<10) | (1<<8);
- pci_write_config16(PCI_DEV(0,2,0), GCFC, reg16);
- reg16 &= 0xf0ff;
- pci_write_config16(PCI_DEV(0,2,0), GCFC, reg16);
+}
+static void sdram_program_memory_frequency(struct sys_info *sysinfo) +{
- u32 clkcfg;
- u8 reg8;
- printk_debug ("Setting Memory Frequency... ");
- clkcfg = MCHBAR32(CLKCFG);
- printk_debug("CLKCFG=0x%08x, ", clkcfg);
- clkcfg &= ~( (1 << 12) | (1 << 7) | ( 7 << 4) );
- if (sysinfo->mvco4x) {
printk_debug("MVCO 4x, ");
// You just did this - why twice
clkcfg &= ~(1 << 12);
- }
- if (sysinfo->clkcfg_bit7) {
printk_debug("second VCO, ");
clkcfg |= (1 << 7);
- }
- switch (sysinfo->memory_frequency) {
- case 400: clkcfg |= (2 << 4); break;
- case 533: clkcfg |= (3 << 4); break;
- case 667: clkcfg |= (4 << 4); break;
- default: die("Target Memory Frequency Error");
- }
- if (MCHBAR32(CLKCFG) == clkcfg) {
printk_debug ("ok (unchanged)\r\n");
return;
- }
- MCHBAR32(CLKCFG) = clkcfg;
- /* Make sure the following code is in the
* cache before we execute it.
*/
- goto cache_code;
+vco_update:
- reg8 = pci_read_config8(PCI_DEV(0,0x1f,0), 0xa2);
- reg8 &= ~(1 << 7);
- pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa2, reg8);
- clkcfg &= ~(1 << 10);
- MCHBAR32(CLKCFG) = clkcfg;
- clkcfg |= (1 << 10);
- MCHBAR32(CLKCFG) = clkcfg;
- __asm__ __volatile__ (
" movl $0x100, %%ecx\n"
"delay_update:\n"
" nop\n"
" nop\n"
" nop\n"
" nop\n"
" loop delay_update\n"
: /* No outputs */
: /* No inputs */
: "%ecx"
);
- clkcfg &= ~(1 << 10);
- MCHBAR32(CLKCFG) = clkcfg;
- goto out;
+cache_code:
- goto vco_update;
+out:
- printk_debug("CLKCFG=0x%08x, ", MCHBAR32(CLKCFG));
- printk_debug ("ok\r\n");
+}
+static void sdram_program_clock_crossing(void) +{
- u32 reg32;
- int idx = 0;
- /**
* The first two lines of each of these tables are for FSB533,
* the following three lines are for FSB667. We ignore FSB400.
* Thus we add the indices according to our clocks from CLKCFG.
*/
- static const u32 data_clock_crossing[] = {
0x08040120, 0x00000000, /* DDR400 FSB533 */
0x00100401, 0x00000000, /* DDR533 FSB533 */
0x04020120, 0x00000010, /* DDR400 FSB667 */
0x10040280, 0x00000040, /* DDR533 FSB667 */
0x00100401, 0x00000000 /* DDR667 FSB667 */
- };
- static const u32 command_clock_crossing[] = {
0x00060108, 0x00000000, /* DDR400 FSB533 */
0x04020108, 0x00000000, /* DDR533 FSB533 */
0x00040318, 0x00000000, /* DDR400 FSB667 */
0x04020118, 0x00000000, /* DDR533 FSB667 */
0x02010804, 0x00000000 /* DDR667 FSB667 */
- };
- printk_debug("Programming Clock Crossing...");
- reg32 = MCHBAR32(CLKCFG);
- printk_debug("MEM=");
- switch ((reg32 >> 4) & 7) {
- case 2: printk_debug("400"); idx += 0; break;
- case 3: printk_debug("533"); idx += 2; break;
- case 4: printk_debug("667"); idx += 4; break;
- default: printk_debug("RSVD\r\n"); return;
- }
- printk_debug(" FSB=");
- switch (reg32 & 7) {
- case 0: printk_debug("400\r\n"); return;
- case 1: printk_debug("533"); idx += 0; break;
- case 3: printk_debug("667"); idx += 4; break;
- default: printk_debug("RSVD\r\n"); return;
- }
- MCHBAR32(C0DCCFT + 0) = data_clock_crossing[idx];
- MCHBAR32(C0DCCFT + 4) = data_clock_crossing[idx + 1];
- MCHBAR32(C1DCCFT + 0) = data_clock_crossing[idx];
- MCHBAR32(C1DCCFT + 4) = data_clock_crossing[idx + 1];
- MCHBAR32(CCCFT + 0) = command_clock_crossing[idx];
- MCHBAR32(CCCFT + 4) = command_clock_crossing[idx + 1];
- printk_debug("... ok\r\n");
+}
+static void sdram_disable_fast_dispatch(void) +{
- u32 reg32;
- reg32 = MCHBAR32(FSBPMC3);
- reg32 |= (1 << 1);
- MCHBAR32(FSBPMC3) = reg32;
- reg32 = MCHBAR32(SBTEST);
- reg32 |= (3 << 1);
- MCHBAR32(SBTEST) = reg32;
+}
+static void sdram_pre_jedec_initialization(void) +{
- u32 reg32;
- reg32 = MCHBAR32(WCC);
- reg32 &= 0x113ff3ff;
- reg32 |= (4 << 29) | (3 << 25) | (1 << 10);
- MCHBAR32(WCC) = reg32;
- MCHBAR32(SMVREFC) |= (1 << 6);
- MCHBAR32(MMARB0) &= ~(3 << 17);
- MCHBAR32(MMARB0) |= (1 << 21) | (1 << 16);
- MCHBAR32(MMARB1) &= ~(7 << 8);
- MCHBAR32(MMARB1) |= (3 << 8);
- MCHBAR32(C0AIT) = 0x000006c4;
- MCHBAR32(C0AIT+4) = 0x871a066d;
- MCHBAR32(C1AIT) = 0x000006c4;
- MCHBAR32(C1AIT+4) = 0x871a066d;
+}
+#define EA_DUALCHANNEL_XOR_BANK_RANK_MODE (0xd4 << 24) +#define EA_DUALCHANNEL_XOR_BANK_MODE (0xf4 << 24) +#define EA_DUALCHANNEL_BANK_RANK_MODE (0xc2 << 24) +#define EA_DUALCHANNEL_BANK_MODE (0xe2 << 24) +#define EA_SINGLECHANNEL_XOR_BANK_RANK_MODE (0x91 << 24) +#define EA_SINGLECHANNEL_XOR_BANK_MODE (0xb1 << 24) +#define EA_SINGLECHANNEL_BANK_RANK_MODE (0x80 << 24) +#define EA_SINGLECHANNEL_BANK_MODE (0xa0 << 24)
+static void sdram_enhanced_addressing_mode(struct sys_info *sysinfo) +{
- u32 chan0 = 0, chan1 = 0;
- int chan0_dualsided, chan1_dualsided, chan0_populated,
chan1_populated;
- chan0_populated = (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED
||
sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED);
- chan1_populated = (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED ||
sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED);
- chan0_dualsided = (sysinfo->banksize[1] || sysinfo->banksize[3]);
- chan1_dualsided = (sysinfo->banksize[5] || sysinfo->banksize[7]);
- if (sdram_capabilities_enhanced_addressing_xor()) {
if (!sysinfo->interleaved) {
/* Single Channel & Dual Channel Assymetric */
if (chan0_populated) {
if (chan0_dualsided) {
chan0 =
EA_SINGLECHANNEL_XOR_BANK_RANK_MODE;
} else {
chan0 =
EA_SINGLECHANNEL_XOR_BANK_MODE;
}
}
if (chan1_populated) {
if (chan1_dualsided) {
chan1 =
EA_SINGLECHANNEL_XOR_BANK_RANK_MODE;
} else {
chan1 =
EA_SINGLECHANNEL_XOR_BANK_MODE;
}
}
} else {
/* Interleaved has always both channels populated */
if (chan0_dualsided) {
chan0 = EA_DUALCHANNEL_XOR_BANK_RANK_MODE;
} else {
chan0 = EA_DUALCHANNEL_XOR_BANK_MODE;
}
if (chan1_dualsided) {
chan1 = EA_DUALCHANNEL_XOR_BANK_RANK_MODE;
} else {
chan1 = EA_DUALCHANNEL_XOR_BANK_MODE;
}
}
- } else {
if (!sysinfo->interleaved) {
/* Single Channel & Dual Channel Assymetric */
if (chan0_populated) {
if (chan0_dualsided) {
chan0 =
EA_SINGLECHANNEL_BANK_RANK_MODE;
} else {
chan0 = EA_SINGLECHANNEL_BANK_MODE;
}
}
if (chan1_populated) {
if (chan1_dualsided) {
chan1 =
EA_SINGLECHANNEL_BANK_RANK_MODE;
} else {
chan1 = EA_SINGLECHANNEL_BANK_MODE;
}
}
} else {
/* Interleaved has always both channels populated */
if (chan0_dualsided) {
chan0 = EA_DUALCHANNEL_BANK_RANK_MODE;
} else {
chan0 = EA_DUALCHANNEL_BANK_MODE;
}
if (chan1_dualsided) {
chan1 = EA_DUALCHANNEL_BANK_RANK_MODE;
} else {
chan1 = EA_DUALCHANNEL_BANK_MODE;
}
}
- }
- MCHBAR32(C0DRC1) &= 0x00ffffff;
- MCHBAR32(C0DRC1) |= chan0;
- MCHBAR32(C1DRC1) &= 0x00ffffff;
- MCHBAR32(C1DRC1) |= chan1;
+}
+static void sdram_post_jedec_initialization(struct sys_info *sysinfo) +{
- u32 reg32;
- /* Enable Channel XORing for Dual Channel Interleave */
- if (sysinfo->interleaved) {
reg32 = MCHBAR32(DCC);
+#if CHANNEL_XOR_RANDOMIZATION
reg32 &= ~(1 << 10);
+#endif
reg32 &= ~(1 << 9);
MCHBAR32(DCC) = reg32;
- }
- /* DRAM mode optimizations */
- sdram_enhanced_addressing_mode(sysinfo);
- reg32 = MCHBAR32(FSBPMC3);
- reg32 &= ~(1 << 1);
- MCHBAR32(FSBPMC3) = reg32;
- reg32 = MCHBAR32(SBTEST);
- reg32 &= ~(1 << 2);
- MCHBAR32(SBTEST) = reg32;
- reg32 = MCHBAR32(SBOCC);
- reg32 &= 0xffbdb6ff;
- reg32 |= (0xbdb6 << 8) | (1 << 0);
- MCHBAR32(SBOCC) = reg32;
+}
+static void sdram_power_management(struct sys_info *sysinfo) +{
- u8 reg8;
- u16 reg16;
- u32 reg32;
- int integrated_graphics = 1;
- int i;
- reg32 = MCHBAR32(C0DRT2);
- reg32 &= 0xffffff00;
- /* Idle timer = 8 clocks, CKE idle timer = 16 clocks */
- reg32 |= (1 << 5) | (1 << 4);
- MCHBAR32(C0DRT2) = reg32;
- reg32 = MCHBAR32(C1DRT2);
- reg32 &= 0xffffff00;
- /* Idle timer = 8 clocks, CKE idle timer = 16 clocks */
- reg32 |= (1 << 5) | (1 << 4);
- MCHBAR32(C1DRT2) = reg32;
- reg32 = MCHBAR32(C0DRC1);
- reg32 |= (1 << 12) | (1 << 11);
- MCHBAR32(C0DRC1) = reg32;
- reg32 = MCHBAR32(C1DRC1);
- reg32 |= (1 << 12) | (1 << 11);
- MCHBAR32(C1DRC1) = reg32;
- if (i945_silicon_revision()>1) {
MCHBAR16(UPMC1) = 0x1010;
- } else {
/* Rev 0 and 1 */
MCHBAR16(UPMC1) = 0x0010;
- }
- reg16 = MCHBAR16(UPMC2);
- reg16 &= 0xfc00;
- reg16 |= 0x0100;
- MCHBAR16(UPMC2) = reg16;
- MCHBAR32(UPMC3) = 0x000f06ff;
- for (i=0; i<5; i++) {
MCHBAR32(UPMC3) &= ~(1 << 16);
MCHBAR32(UPMC3) |= (1 << 16);
- }
- MCHBAR32(GIPMC1) = 0x8000000c;
- reg16 = MCHBAR16(CPCTL);
- reg16 &= ~(7 << 11);
- if (i945_silicon_revision()>2) {
reg16 |= (6 << 11);
- } else {
reg16 |= (4 << 11);
- }
- MCHBAR16(CPCTL) = reg16;
- if ((MCHBAR32(ECO) & (1 << 16)) != 0) {
switch (sysinfo->fsb_frequency) {
case 667: MCHBAR32(HGIPMC2) = 0x0d590d59; break;
case 533: MCHBAR32(HGIPMC2) = 0x155b155b; break;
}
- } else {
switch (sysinfo->fsb_frequency) {
case 667: MCHBAR32(HGIPMC2) = 0x09c409c4; break;
case 533: MCHBAR32(HGIPMC2) = 0x0fa00fa0; break;
}
- }
- MCHBAR32(FSBPMC1) = 0x8000000c;
- reg32 = MCHBAR32(C2C3TT);
- reg32 &= 0xffff0000;
- switch (sysinfo->fsb_frequency) {
- case 667: reg32 |= 0x0600; break;
- case 533: reg32 |= 0x0480; break;
- }
- MCHBAR32(C2C3TT) = reg32;
- reg32 = MCHBAR32(C3C4TT);
- reg32 &= 0xffff0000;
- switch (sysinfo->fsb_frequency) {
- case 667: reg32 |= 0x0b80; break;
- case 533: reg32 |= 0x0980; break;
- }
- MCHBAR32(C3C4TT) = reg32;
- if (i945_silicon_revision() == 0) {
MCHBAR32(ECO) &= ~(1 << 16);
- } else {
MCHBAR32(ECO) |= (1 << 16);
- }
+#if 0
- if (i945_silicon_revision() == 0) {
MCHBAR32(FSBPMC3) &= ~(1 << 29);
- } else {
MCHBAR32(FSBPMC3) |= (1 << 29);
- }
+#endif
- MCHBAR32(FSBPMC3) &= ~(1 << 29);
- MCHBAR32(FSBPMC3) |= (1 << 21);
- MCHBAR32(FSBPMC3) &= ~(1 << 19);
- MCHBAR32(FSBPMC3) &= ~(1 << 13);
- reg32 = MCHBAR32(FSBPMC4);
- reg32 &= ~(3 << 24);
- reg32 |= ( 2 << 24);
- MCHBAR32(FSBPMC4) = reg32;
- MCHBAR32(FSBPMC4) |= (1 << 21);
- MCHBAR32(FSBPMC4) |= (1 << 5);
- if (i945_silicon_revision() < 2) {
/* stepping 0 and 1 */
MCHBAR32(FSBPMC4) &= ~(1 << 4);
- } else {
MCHBAR32(FSBPMC4) &= ~(1 << 4);
- }
- reg8 = pci_read_config8(PCI_DEV(0,0x0,0), 0xfc);
- reg8 |= (1 << 4);
- pci_write_config8(PCI_DEV(0, 0x0, 0), 0xfc, reg8);
- reg8 = pci_read_config8(PCI_DEV(0,0x2,0), 0xc1);
- reg8 |= (1 << 2);
- pci_write_config8(PCI_DEV(0, 0x2, 0), 0xc1, reg8);
- if (integrated_graphics) {
MCHBAR16(MIPMC4) = 0x0468;
MCHBAR16(MIPMC5) = 0x046c;
MCHBAR16(MIPMC6) = 0x046c;
- } else {
MCHBAR16(MIPMC4) = 0x6468;
MCHBAR16(MIPMC5) = 0x646c;
MCHBAR16(MIPMC6) = 0x646c;
- }
- reg32 = MCHBAR32(PMCFG);
- reg32 &= ~(3 << 17);
- reg32 |= (2 << 17);
- reg32 |= (1 << 4);
- MCHBAR32(PMCFG) = reg32;
- reg32 = MCHBAR32(0xc30);
- reg32 &= 0xffffff00;
- reg32 |= 0x01;
- MCHBAR32(0xc30) = reg32;
- MCHBAR32(0xb18) &= ~(1 << 21);
+}
+static void sdram_thermal_management(void) +{
- /* The Thermal Sensors for DIMMs at 0x50, 0x52 are at I2C addr
* 0x30/0x32.
*/
- /* Explicitly set to 0 */
- MCHBAR8(TCO1) = 0x00;
- MCHBAR8(TCO0) = 0x00;
+}
+#include "rcven.c"
+static void sdram_program_receive_enable(struct sys_info *sysinfo) +{
- MCHBAR32(REPC) |= (1 << 0);
- receive_enable_adjust(sysinfo);
- MCHBAR32(C0DRC1) |= (1 << 6);
- MCHBAR32(C1DRC1) |= (1 << 6);
- MCHBAR32(C0DRC1) &= ~(1 << 6);
- MCHBAR32(C1DRC1) &= ~(1 << 6);
- MCHBAR32(MIPMC3) |= (0x0f << 0);
+}
+/**
- @brief Enable On-Die Termination for DDR2.
- */
+static void sdram_on_die_termination(struct sys_info *sysinfo) +{
- static const u32 odt[] = {
0x00024911, 0xe0010000,
0x00049211, 0xe0020000,
0x0006db11, 0xe0030000,
- };
- u32 reg32;
- int cas;
- reg32 = MCHBAR32(ODTC);
- reg32 &= ~(3 << 16);
- reg32 |= (1 << 14) | (1 << 6) | (2 << 16);
- MCHBAR32(ODTC) = reg32;
- if ( !(sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED &&
sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED) ) {
printk_debug("one dimm per channel config.. \n");
reg32 = MCHBAR32(C0ODT);
reg32 &= ~(7 << 28);
MCHBAR32(C0ODT) = reg32;
reg32 = MCHBAR32(C1ODT);
reg32 &= ~(7 << 28);
MCHBAR32(C1ODT) = reg32;
- }
- cas = sysinfo->cas;
- reg32 = MCHBAR32(C0ODT) & 0xfff00000;
- reg32 |= odt[(cas-3) * 2];
- MCHBAR32(C0ODT) = reg32;
- reg32 = MCHBAR32(C1ODT) & 0xfff00000;
- reg32 |= odt[(cas-3) * 2];
- MCHBAR32(C1ODT) = reg32;
- reg32 = MCHBAR32(C0ODT + 4) & 0x1fc8ffff;
- reg32 |= odt[((cas-3) * 2) + 1];
- MCHBAR32(C0ODT + 4) = reg32;
- reg32 = MCHBAR32(C1ODT + 4) & 0x1fc8ffff;
- reg32 |= odt[((cas-3) * 2) + 1];
- MCHBAR32(C1ODT + 4) = reg32;
+}
+/**
- @brief Enable clocks to populated sockets
- */
+static void sdram_enable_memory_clocks(struct sys_info *sysinfo) +{
- u8 clocks[2] = { 0, 0 };
- if (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED)
clocks[0] |= (1 << 0) | (1 << 1);
- if (sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)
clocks[0] |= (1 << 2) | (1 << 3);
- if (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED)
clocks[1] |= (1 << 0) | (1 << 1);
- if (sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)
clocks[1] |= (1 << 2) | (1 << 3);
+#ifdef OVERRIDE_CLOCK_DISABLE
- clocks[0] = 0xf;
- clocks[1] = 0xf;
+#endif
- MCHBAR8(C0DCLKDIS) = clocks[0];
- MCHBAR8(C1DCLKDIS) = clocks[1];
+}
+#define RTT_ODT_75_OHM (1 << 5) +#define RTT_ODT_150_OHM (1 << 9)
+#define EMRS_OCD_DEFAULT ( (1 << 12) | (1 << 11) | (1 << 10) )
+#define MRS_CAS_3 (3 << 7) +#define MRS_CAS_4 (4 << 7) +#define MRS_CAS_5 (5 << 7)
+#define MRS_TWR_3 (2 << 12) +#define MRS_TWR_4 (3 << 12) +#define MRS_TWR_5 (4 << 12)
+#define MRS_BT (1 << 6)
+#define MRS_BL4 (2 << 3) +#define MRS_BL8 (3 << 3)
+static void sdram_jedec_enable(struct sys_info *sysinfo) +{
- int i, nonzero;
- u32 bankaddr = 0, tmpaddr, mrsaddr = 0;
- for (i = 0, nonzero = -1; i < 8; i++) {
if (sysinfo->banksize[i] == 0) {
continue;
}
printk_debug("jedec enable sequence: bank %d\n", i);
switch (i) {
case 0:
/* Start at address 0 */
bankaddr = 0;
break;
case 4:
if (sysinfo->interleaved) {
bankaddr = 0x40;
break;
}
default:
if (nonzero != -1) {
printk_debug("bankaddr from bank size of
rank %d\n", nonzero);
bankaddr += (1 <<
sysinfo->banksize[nonzero]) << (sysinfo->interleaved?28:27);
break;
}
/* No populated bank hit before. Start at address 0
*/
bankaddr = 0;
}
/* We have a bank with a non-zero size.. Remember it
* for the next offset we have to calculate
*/
nonzero = i;
/* Get CAS latency set up */
switch (sysinfo->cas) {
case 5: mrsaddr = MRS_CAS_5; break;
case 4: mrsaddr = MRS_CAS_4; break;
case 3: mrsaddr = MRS_CAS_3; break;
default: die("Jedec Error (CAS).\n");
}
/* Get tWR set */
switch (sysinfo->twr) {
case 5: mrsaddr |= MRS_TWR_5; break;
case 4: mrsaddr |= MRS_TWR_4; break;
case 3: mrsaddr |= MRS_TWR_3; break;
default: die("Jedec Error (tWR).\n");
}
/* Interleaved */
if (sysinfo->interleaved) {
mrsaddr |= MRS_BT;
mrsaddr = mrsaddr << 1;
}
/* Only burst length 8 supported */
mrsaddr |= MRS_BL8;
/* Apply NOP */
PRINTK_DEBUG("Apply NOP\r\n");
do_ram_command(RAM_COMMAND_NOP);
ram_read32(bankaddr);
/* Precharge all banks */
PRINTK_DEBUG("All Banks Precharge\r\n");
do_ram_command(RAM_COMMAND_PRECHARGE);
ram_read32(bankaddr);
/* Extended Mode Register Set (2) */
PRINTK_DEBUG("Extended Mode Register Set(2)\r\n");
do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_2);
ram_read32(bankaddr);
/* Extended Mode Register Set (3) */
PRINTK_DEBUG("Extended Mode Register Set(3)\r\n");
do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_3);
ram_read32(bankaddr);
/* Extended Mode Register Set */
PRINTK_DEBUG("Extended Mode Register Set\r\n");
do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_1);
tmpaddr = bankaddr;
if (!sdram_capabilities_dual_channel()) {
tmpaddr |= RTT_ODT_75_OHM;
} else if (sysinfo->interleaved) {
tmpaddr |= (RTT_ODT_150_OHM << 1);
} else {
tmpaddr |= RTT_ODT_150_OHM;
}
ram_read32(tmpaddr);
/* Mode Register Set: Reset DLLs */
PRINTK_DEBUG("MRS: Reset DLLs\r\n");
do_ram_command(RAM_COMMAND_MRS);
tmpaddr = bankaddr;
tmpaddr |= mrsaddr;
/* Set DLL reset bit */
if (sysinfo->interleaved)
tmpaddr |= (1 << 12);
else
tmpaddr |= (1 << 11);
ram_read32(tmpaddr);
/* Precharge all banks */
PRINTK_DEBUG("All Banks Precharge\r\n");
do_ram_command(RAM_COMMAND_PRECHARGE);
ram_read32(bankaddr);
/* CAS before RAS Refresh */
PRINTK_DEBUG("CAS before RAS\r\n");
do_ram_command(RAM_COMMAND_CBR);
/* CBR wants two READs */
ram_read32(bankaddr);
ram_read32(bankaddr);
/* Mode Register Set: Enable DLLs */
PRINTK_DEBUG("MRS: Enable DLLs\r\n");
do_ram_command(RAM_COMMAND_MRS);
tmpaddr = bankaddr;
tmpaddr |= mrsaddr;
ram_read32(tmpaddr);
/* Extended Mode Register Set */
PRINTK_DEBUG("Extended Mode Register Set: ODT/OCD\r\n");
do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_1);
tmpaddr = bankaddr;
if (!sdram_capabilities_dual_channel()) {
tmpaddr |= RTT_ODT_75_OHM | EMRS_OCD_DEFAULT;
} else if (sysinfo->interleaved) {
tmpaddr |= ((RTT_ODT_150_OHM | EMRS_OCD_DEFAULT) <<
1);
} else {
tmpaddr |= RTT_ODT_150_OHM | EMRS_OCD_DEFAULT;
}
ram_read32(tmpaddr);
/* Extended Mode Register Set */
PRINTK_DEBUG("Extended Mode Register Set: OCD Exit\r\n");
do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_1);
tmpaddr = bankaddr;
if (!sdram_capabilities_dual_channel()) {
tmpaddr |= RTT_ODT_75_OHM;
} else if (sysinfo->interleaved) {
tmpaddr |= (RTT_ODT_150_OHM << 1);
} else {
tmpaddr |= RTT_ODT_150_OHM;
}
ram_read32(tmpaddr);
- }
+}
+static void sdram_init_complete(void) +{
- PRINTK_DEBUG("Normal Operation\r\n");
- do_ram_command(RAM_COMMAND_NORMAL);
+}
+static void sdram_setup_processor_side(void) +{
- if (i945_silicon_revision() == 0)
MCHBAR32(FSBPMC3) |= (1 << 2);
- MCHBAR8(0xb00) |= 1;
- if (i945_silicon_revision() == 0)
MCHBAR32(SLPCTL) |= (1 << 8);
+}
+#define BOOT_MODE_RESUME 1 +#define BOOT_MODE_NORMAL 0
+/**
- @param boot_mode: 0 = normal, 1 = resume
- */
+void sdram_initialize(int boot_mode) +{
- struct sys_info sysinfo;
- u8 reg8, cas_mask;
- sdram_detect_errors();
- printk_debug ("Setting up RAM controller.\r\n");
- memset(&sysinfo, 0, sizeof(sysinfo));
- /* Look at the type of DIMMs and verify all DIMMs are x8 or x16
width */
- sdram_get_dram_configuration(&sysinfo);
- /* Check whether we have stacked DIMMs */
- sdram_verify_package_type(&sysinfo);
- /* Determine common CAS */
- cas_mask = sdram_possible_cas_latencies(&sysinfo);
- /* Choose Common Frequency */
- sdram_detect_cas_latency_and_ram_speed(&sysinfo, cas_mask);
- /* Determine smallest common tRAS */
- sdram_detect_smallest_tRAS(&sysinfo);
- /* Determine tRP */
- sdram_detect_smallest_tRP(&sysinfo);
- /* Determine tRCD */
- sdram_detect_smallest_tRCD(&sysinfo);
- /* Determine smallest refresh period */
- sdram_detect_smallest_refresh(&sysinfo);
- /* Verify all DIMMs support burst length 8 */
- sdram_verify_burst_length(&sysinfo);
- /* determine tWR */
- sdram_detect_smallest_tWR(&sysinfo);
- /* Determine DIMM size parameters (rows, columns banks) */
- sdram_detect_dimm_size(&sysinfo);
- /* determine tRFC */
- sdram_detect_smallest_tRFC(&sysinfo);
- /* Program PLL settings */
- sdram_program_pll_settings();
- /* Program Graphics Frequency */
- sdram_program_graphics_frequency(&sysinfo);
- /* Program System Memory Frequency */
- sdram_program_memory_frequency(&sysinfo);
- /* Determine Mode of Operation (Interleaved etc) */
- sdram_set_channel_mode(&sysinfo);
- /* Program Clock Crossing values */
- sdram_program_clock_crossing();
- /* Disable fast dispatch */
- sdram_disable_fast_dispatch();
- /* Enable WIODLL Power Down in ACPI states */
- MCHBAR32(C0DMC) |= (1 << 24);
- MCHBAR32(C1DMC) |= (1 << 24);
- /* Program DRAM Row Boundary/Attribute Registers */
- if (boot_mode != BOOT_MODE_RESUME) {
/* program row size DRB and set TOLUD */
sdram_program_row_boundaries(&sysinfo);
/* program page size DRA */
sdram_set_row_attributes(&sysinfo);
- }
- /* Program CxBNKARC */
- sdram_set_bank_architecture(&sysinfo);
- /* Program DRAM Timing and Control registers based on SPD */
- sdram_set_timing_and_control(&sysinfo);
- /* On-Die Termination Adjustment */
- sdram_on_die_termination(&sysinfo);
- /* Pre Jedec Initialization */
- sdram_pre_jedec_initialization();
- /* Perform System Memory IO Initialization */
- sdram_initialize_system_memory_io(&sysinfo);
- /* Perform System Memory IO Buffer Enable */
- sdram_enable_system_memory_io(&sysinfo);
- /* Enable System Memory Clocks */
- sdram_enable_memory_clocks(&sysinfo);
- if (boot_mode != BOOT_MODE_RESUME) {
/* Jedec Initialization sequence */
sdram_jedec_enable(&sysinfo);
- }
- /* Program Power Management Registers */
- sdram_power_management(&sysinfo);
- /* Post Jedec Init */
- sdram_post_jedec_initialization(&sysinfo);
- /* Program DRAM Throttling */
- sdram_thermal_management();
- /* Normal Operations */
- sdram_init_complete();
- /* Program Receive Enable Timings */
- sdram_program_receive_enable(&sysinfo);
- /* Enable Periodic RCOMP */
- sdram_enable_rcomp();
- /* Tell ICH7 that we're done */
- reg8 = pci_read_config8(PCI_DEV(0,0x1f,0), 0xa2);
- reg8 &= ~(1 << 7);
- pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa2, reg8);
- printk_debug("RAM initialization finished.\r\n");
- sdram_setup_processor_side();
+}
//Since this is CPU specific, should it go with the CPU files?
Index: src/northbridge/intel/i945/udelay.c
--- src/northbridge/intel/i945/udelay.c (revision 0) +++ src/northbridge/intel/i945/udelay.c (revision 0) @@ -0,0 +1,70 @@ +/*
- This file is part of the coreboot project.
- Copyright (C) 2007-2008 coresystems GmbH
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; version 2 of the License.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
USA
- */
+#include <cpu/x86/tsc.h> +#include <cpu/x86/msr.h>
+/**
- Intel Core(tm) cpus always run the TSC at the maximum possible CPU
clock
- */
+static void udelay(u32 us) +{
- u32 dword;
- tsc_t tsc, tsc1, tscd;
- msr_t msr;
- u32 fsb = 0, divisor;
- u32 d;
- u32 dn = 0x1000000 / 2;
- msr = rdmsr(0xcd);
- switch (msr.lo & 0x07) {
- case 5:
fsb = 400;
break;
- case 1:
fsb = 533;
break;
- case 3:
fsb = 667;
break;
- }
- msr = rdmsr(0x198);
- divisor = (msr.hi >> 8) & 0x1f;
- d = fsb * divisor;
- tscd.hi = us / dn;
- tscd.lo = (us - tscd.hi * dn) * d;
- tsc1 = rdtsc();
- dword = tsc1.lo + tscd.lo;
- if ((dword < tsc1.lo) || (dword < tscd.lo)) {
tsc1.hi++;
- }
- tsc1.lo = dword;
- tsc1.hi += tscd.hi;
- do {
tsc = rdtsc();
- } while ((tsc.hi > tsc1.hi)
|| ((tsc.hi == tsc1.hi) && (tsc.lo > tsc1.lo)));
+} Index: src/northbridge/intel/i945/pcie_config.c =================================================================== --- src/northbridge/intel/i945/pcie_config.c (revision 0) +++ src/northbridge/intel/i945/pcie_config.c (revision 0) @@ -0,0 +1,68 @@ +/*
- This file is part of the coreboot project.
- Copyright (C) 2007-2008 coresystems GmbH
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; version 2 of the License.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
USA
- */
+#include "i945.h"
+static inline __attribute__ ((always_inline)) +u8 pcie_read_config8(device_t dev, unsigned int where) +{
- unsigned long addr;
- addr = DEFAULT_PCIEXBAR | dev | where;
- return read8(addr);
+}
+static inline __attribute__ ((always_inline)) +u16 pcie_read_config16(device_t dev, unsigned int where) +{
- unsigned long addr;
- addr = DEFAULT_PCIEXBAR | dev | where;
- return read16(addr);
+}
+static inline __attribute__ ((always_inline)) +u32 pcie_read_config32(device_t dev, unsigned int where) +{
- unsigned long addr;
- addr = DEFAULT_PCIEXBAR | dev | where;
- return read32(addr);
+}
+static inline __attribute__ ((always_inline)) +void pcie_write_config8(device_t dev, unsigned int where, u8 value) +{
- unsigned long addr;
- addr = DEFAULT_PCIEXBAR | dev | where;
- write8(addr, value);
+}
+static inline __attribute__ ((always_inline)) +void pcie_write_config16(device_t dev, unsigned int where, u16 value) +{
- unsigned long addr;
- addr = DEFAULT_PCIEXBAR | dev | where;
- write16(addr, value);
+}
+static inline __attribute__ ((always_inline)) +void pcie_write_config32(device_t dev, unsigned int where, u32 value) +{
- unsigned long addr;
- addr = DEFAULT_PCIEXBAR | dev | where;
- write32(addr, value);
+} Index: src/northbridge/intel/i945/northbridge.c =================================================================== --- src/northbridge/intel/i945/northbridge.c (revision 0) +++ src/northbridge/intel/i945/northbridge.c (revision 0) @@ -0,0 +1,283 @@ +/*
- This file is part of the coreboot project.
- Copyright (C) 2007-2008 coresystems GmbH
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; version 2 of the License.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
USA
- */
+#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 "i945.h"
+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) +{
- uint32_t pci_tolm;
- uint8_t tolud, reg8;
- uint16_t reg16;
- unsigned long long tomk, tolmk;
- pci_tolm = find_pci_tolm(&dev->link[0]);
- printk_spew("Base of stolen memory: 0x%08x\n",
pci_read_config32(dev_find_slot(0, PCI_DEVFN(2, 0)),
0x5c));
- tolud = pci_read_config8(dev_find_slot(0, PCI_DEVFN(0, 0)), 0x9c);
- printk_spew("Top of Low Used DRAM: 0x%08x\n", tolud << 24);
- tomk = tolud << 14;
- /* Note: subtract IGD device and TSEG */
- reg8 = pci_read_config8(dev_find_slot(0, PCI_DEVFN(0, 0)), 0x9e);
- if (reg8 & 1) {
int tseg_size = 0;
printk_debug("TSEG decoded, subtracting ");
reg8 >>= 1;
reg8 &= 3;
switch (reg8) {
case 0:
tseg_size = 1024;
break;
case 1:
tseg_size = 2048;
break;
case 2:
tseg_size = 8192;
break;
}
printk_debug("%dM\n", tseg_size >> 10);
tomk -= tseg_size;
- }
- reg16 = pci_read_config16(dev_find_slot(0, PCI_DEVFN(0, 0)), GGC);
- if (!(reg16 & 2)) {
int uma_size = 0;
printk_debug("IGD decoded, subtracting ");
reg16 >>= 4;
reg16 &= 7;
switch (reg16) {
case 1:
uma_size = 1024;
break;
case 3:
uma_size = 8192;
break;
}
printk_debug("%dM UMA\n", uma_size >> 10);
tomk -= uma_size;
- }
- /* The following needs to be 2 lines, otherwise the second
* number is always 0
*/
// Did you try since tomk is unsigned long? // printk_info("Available memory: %ldK (%ldM)\n", tomk, (tomk >> 10));
- printk_info("Available memory: %dK", tomk);
- printk_info(" (%dM)\n", (tomk >> 10));
- tolmk = tomk;
- /* 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);
- }
- 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);
- /* TODO We could determine how many PCIe busses we need in
* the bar. For now that number is hardcoded to a max of 64.
*/
- 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);
- /* So, this is one of the big mysteries in the coreboot resource
* allocator. This resource should make sure that the address space
* of the PCIe memory mapped config space bar. But it does not.
*/
- /* We use 0xcf as an unused index for our PCIe bar so that we find
it again */
- resource = new_resource(dev, 0xcf);
- resource->base = DEFAULT_PCIEXBAR;
- resource->size = 64 * 1024 * 1024; /* 64MB hard coded PCIe
config space */
- resource->flags =
IORESOURCE_MEM | IORESOURCE_FIXED | IORESOURCE_STORED |
IORESOURCE_ASSIGNED;
- printk_debug("Adding PCIe enhanced config space BAR
0x%08x-0x%08x.\n",
resource->base, (resource->base + resource->size));
+}
+static void mc_set_resources(device_t dev) +{
- struct resource *resource, *last;
- /* Report the PCIe BAR */
- last = &dev->resource[dev->resources];
- resource = find_resource(dev, 0xcf);
- if (resource) {
report_resource_stored(dev, resource, "<mmconfig>");
- }
- /* And call the normal set_resources */
- 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 const struct pci_driver mc_driver __pci_driver = {
- .ops = &mc_ops,
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = 0x27a0,
+};
+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_i945_ops = {
- CHIP_NAME("Intel i945 Northbridge")
- .enable_dev = enable_dev,
+}; Index: src/northbridge/intel/i945/chip.h =================================================================== --- src/northbridge/intel/i945/chip.h (revision 0) +++ src/northbridge/intel/i945/chip.h (revision 0) @@ -0,0 +1,23 @@ +/*
- This file is part of the coreboot project.
- Copyright (C) 2007-2008 coresystems GmbH
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; version 2 of the License.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
USA
- */
+struct northbridge_intel_i945_config { +};
+extern struct chip_operations northbridge_intel_i945_ops; Index: src/northbridge/intel/i945/raminit.h =================================================================== --- src/northbridge/intel/i945/raminit.h (revision 0) +++ src/northbridge/intel/i945/raminit.h (revision 0) @@ -0,0 +1,67 @@ +/*
- This file is part of the coreboot project.
- Copyright (C) 2007-2008 coresystems GmbH
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; version 2 of the License
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
USA
- */
+#ifndef RAMINIT_H +#define RAMINIT_H
+#define DIMM_SOCKETS 2
+#define DIMM_SPD_BASE 0x50 +#define DIMM_TCO_BASE 0x30
+/* Burst length is always 8 */ +#define BURSTLENGTH 8
+struct sys_info {
- u16 memory_frequency; /* 400, 533 or 667 */
- u16 fsb_frequency; /* 400, 533 or 667 */
- u8 trp; /* calculated by sdram_detect_smallest_tRP()
*/
- u8 trcd; /* calculated by
sdram_detect_smallest_tRCD() */
- u8 tras; /* calculated by
sdram_detect_smallest_tRAS() */
- u8 trfc; /* calculated by
sdram_detect_smallest_tRFC() */
- u8 twr; /* calculated by sdram_detect_smallest_tWR()
*/
- u8 cas; /* 3, 4 or 5 */
- u8 refresh; /* 0 = 15.6us, 1 = 7.8us */
- u8 dual_channel; /* 0 or 1 */
- u8 interleaved;
- u8 mvco4x; /* 0 (8x) or 1 (4x) */
- u8 clkcfg_bit7;
- u8 boot_path;
- u8 package; /* 0 = planar, 1 = stacked */
+#define SYSINFO_PACKAGE_PLANAR 0x00 +#define SYSINFO_PACKAGE_STACKED 0x01
- u8 dimm[2 * DIMM_SOCKETS];
+#define SYSINFO_DIMM_X16DS 0x00 +#define SYSINFO_DIMM_X8DS 0x01 +#define SYSINFO_DIMM_X16SS 0x02 +#define SYSINFO_DIMM_X8DDS 0x03 +#define SYSINFO_DIMM_NOT_POPULATED 0x04
- u8 banks[2 * DIMM_SOCKETS];
- u8 banksize[2 * 2 * DIMM_SOCKETS];
+} __attribute__ ((packed));
+#endif /* RAMINIT_H */ Index: src/northbridge/intel/i945/rcven.c =================================================================== --- src/northbridge/intel/i945/rcven.c (revision 0) +++ src/northbridge/intel/i945/rcven.c (revision 0) @@ -0,0 +1,338 @@ +/*
- This file is part of the coreboot project.
- Copyright (C) 2007-2008 coresystems GmbH
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; version 2 of the License.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
USA
- */
+#include "raminit.h"
+/**
- sample the strobes signal
- */
+static u32 sample_strobes(int channel_offset, struct sys_info *sysinfo) +{
- u32 reg32, addr;
- int i;
- MCHBAR32(C0DRC1 + channel_offset) |= (1 << 6);
- MCHBAR32(C0DRC1 + channel_offset) &= ~(1 << 6);
- addr = 0;
- if (channel_offset != 0) { /* must be dual channel */
if (sysinfo->interleaved == 1) {
addr |= (1 << 6);
} else {
addr = ((u32)MCHBAR8(C0DRB3)) << 25;
}
- }
- for (i = 0; i < 28; i++) {
read32(addr);
read32(addr + 0x80);
- }
- reg32 = MCHBAR32(RCVENMT);
- if (channel_offset == 0) {
reg32 = reg32 << 2;
- }
- /**
* [19] = 1: all bits are high
* [18] = 1: all bits are low
* [19:18] = 00: bits are mixed high, low
*/
- return reg32;
+}
+/**
- This function sets receive enable coarse and medium timing parameters
- */
+static void set_receive_enable(int channel_offset, u8 medium, u8 coarse) +{
- u32 reg32;
- printk_spew(" set_receive_enable() medium=0x%x, coarse=0x%x\r\n",
medium, coarse);
- reg32 = MCHBAR32(C0DRT1 + channel_offset);
- reg32 &= 0xf0ffffff;
- reg32 |= ((u32)coarse & 0x0f) << 24;
- MCHBAR32(C0DRT1 + channel_offset) = reg32;
- if (coarse > 0x0f)
printk_debug("set_receive_enable: coarse overflow:
0x%02x.\n", coarse);
- /* medium control
*
* 00 - 1/4 clock
* 01 - 1/2 clock
* 10 - 3/4 clock
* 11 - 1 clock
*/
- reg32 = MCHBAR32(RCVENMT);
- if (!channel_offset) {
reg32 &= ~(3 << 2);
reg32 |= medium << 2;
- } else {
reg32 &= ~(3 << 0);
reg32 |= medium;
- }
- MCHBAR32(RCVENMT) = reg32;
+}
+static int normalize(int channel_offset, u8 * mediumcoarse, u8 * fine) +{
- printk_spew(" normalize()\r\n");
- if (*fine < 0x80)
return 0;
- *fine -= 0x80;
- *mediumcoarse += 1;
- if (*mediumcoarse >= 0x40) {
printk_debug("Normalize Error\r\n");
return -1;
- }
- set_receive_enable(channel_offset, *mediumcoarse & 3,
*mediumcoarse >> 2);
- MCHBAR8(C0WL0REOST + channel_offset) = *fine;
- return 0;
+}
+static int find_preamble(int channel_offset, u8 * mediumcoarse,
struct sys_info *sysinfo)
+{
- /* find start of the data phase */
- u32 reg32;
- printk_spew(" find_preamble()\r\n");
- do {
if (*mediumcoarse < 4) {
printk_debug("No Preamble found.\r\n");
return -1;
}
*mediumcoarse -= 4;
set_receive_enable(channel_offset, *mediumcoarse & 3,
*mediumcoarse >> 2);
reg32 = sample_strobes(channel_offset, sysinfo);
- } while (reg32 & (1 << 19));
- if (!(reg32 & (1 << 18))) {
printk_debug("No Preamble found (neither high nor
low).\r\n");
return -1;
- }
- return 0;
+}
+/**
- add a quarter clock to the current receive enable settings
- */
+static int add_quarter_clock(int channel_offset, u8 * mediumcoarse, u8 *
fine)
+{
- printk_spew(" add_quarter_clock() mediumcoarse=%02x fine=%02x\r\n",
*mediumcoarse, *fine);
- if (*fine >= 0x80) {
*fine -= 0x80;
*mediumcoarse += 2;
if (*mediumcoarse >= 0x40) {
printk_debug("clocks at max.\r\n");
return -1;
}
set_receive_enable(channel_offset, *mediumcoarse & 3,
*mediumcoarse >> 2);
- } else {
*fine += 0x80;
- }
- MCHBAR8(C0WL0REOST + channel_offset) = *fine;
- return 0;
+}
+static int find_strobes_low(int channel_offset, u8 * mediumcoarse, u8 *
fine,
struct sys_info *sysinfo)
+{
- u32 rcvenmt;
- printk_spew(" find_strobes_low()\r\n");
- for (;;) {
MCHBAR8(C0WL0REOST + channel_offset) = *fine;
set_receive_enable(channel_offset, *mediumcoarse & 3,
*mediumcoarse >> 2);
rcvenmt = sample_strobes(channel_offset, sysinfo);
if (((rcvenmt & (1 << 18)) != 0))
return 0;
*fine -= 0x80;
if (*fine == 0)
continue;
*mediumcoarse -= 2;
if (*mediumcoarse < 0xfe)
continue;
break;
- }
- printk_debug("Could not find low strobe\r\n");
- return 0;
+}
+static int find_strobes_edge(int channel_offset, u8 * mediumcoarse, u8 *
fine,
struct sys_info *sysinfo)
+{
- int counter;
- u32 rcvenmt;
- printk_spew(" find_strobes_edge()\r\n");
- counter = 8;
- set_receive_enable(channel_offset, *mediumcoarse & 3,
*mediumcoarse >> 2);
- for (;;) {
MCHBAR8(C0WL0REOST + channel_offset) = *fine;
rcvenmt = sample_strobes(channel_offset, sysinfo);
if ((rcvenmt & (1 << 19)) == 0) {
counter = 8;
} else {
counter--;
if (!counter)
break;
}
*fine = *fine + 1;
if (*fine < 0xf8) {
if (*fine & (1 << 3)) {
*fine &= ~(1 << 3);
*fine += 0x10;
}
continue;
}
*fine = 0;
*mediumcoarse += 2;
if (*mediumcoarse <= 0x40) {
set_receive_enable(channel_offset, *mediumcoarse &
3,
*mediumcoarse >> 2);
continue;
}
printk_debug("could not find rising edge.\r\n");
return -1;
- }
- *fine -= 7;
- if (*fine >= 0xf9) {
*mediumcoarse -= 2;
set_receive_enable(channel_offset, *mediumcoarse & 3,
*mediumcoarse >> 2);
- }
- *fine &= ~(1 << 3);
- MCHBAR8(C0WL0REOST + channel_offset) = *fine;
- return 0;
+}
+/**
- Here we use a trick. The RCVEN channel 0 registers are all at an
- offset of 0x80 to the channel 0 registers. We don't want to waste
- a lot of if()s so let's just pass 0 or 0x80 for the channel offset.
- */
+static int receive_enable_autoconfig(int channel_offset,
struct sys_info *sysinfo)
+{
- u8 mediumcoarse;
- u8 fine;
- printk_spew("receive_enable_autoconfig() for channel %d\r\n",
channel_offset ? 1 : 0);
- /* Set initial values */
- mediumcoarse = (sysinfo->cas << 2) | 3;
- fine = 0;
- if (find_strobes_low(channel_offset, &mediumcoarse, &fine, sysinfo))
return -1;
- if (find_strobes_edge(channel_offset, &mediumcoarse, &fine,
sysinfo))
return -1;
- if (add_quarter_clock(channel_offset, &mediumcoarse, &fine))
return -1;
- if (find_preamble(channel_offset, &mediumcoarse, sysinfo))
return -1;
- if (add_quarter_clock(channel_offset, &mediumcoarse, &fine))
return -1;
- if (normalize(channel_offset, &mediumcoarse, &fine))
return -1;
- /* This is a debug check to see if the rcven code is fully working.
* It can be removed when the output message is not printed anymore
*/
- if (MCHBAR8(C0WL0REOST + channel_offset) == 0) {
printk_debug("Weird. No C%sWL0REOST\n",
channel_offset?"1":"0");
- }
- return 0;
+}
+void receive_enable_adjust(struct sys_info *sysinfo) +{
- /* Is channel 0 populated? */
- if (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED
|| sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)
if (receive_enable_autoconfig(0, sysinfo))
return;
- /* Is channel 1 populated? */
- if (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED
|| sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)
if (receive_enable_autoconfig(0x80, sysinfo))
return;
+}
Myles Watson wrote:
Support for the Intel 945 northbridge.
Sorry I'm late. I know it's already in, but I was in the middle of reviewing it. I prefixed my comments with //, I hope that helps you find them faster.
Ok, trying to address the issues:
Index: src/northbridge/intel/i945/early_init.c
--- src/northbridge/intel/i945/early_init.c (revision 0) +++ src/northbridge/intel/i945/early_init.c (revision 0)
+static int i945_silicon_revision(void) +{
- return pci_read_config8(PCI_DEV(0, 0x00, 0), 8);
//could use PCI_CLASS_REVISION here.
ok.
+}
+static void i945_detect_chipset(void)
//I would prefer a name that makes it clear that this function only prints information.
- /* Set C0000-FFFFF to access RAM on both reads and writes */
- pci_write_config8(PCI_DEV(0, 0x00, 0), PAM0, 0x30);
- pci_write_config8(PCI_DEV(0, 0x00, 0), PAM1, 0x33);
- pci_write_config8(PCI_DEV(0, 0x00, 0), PAM2, 0x33);
- pci_write_config8(PCI_DEV(0, 0x00, 0), PAM3, 0x33);
- pci_write_config8(PCI_DEV(0, 0x00, 0), PAM4, 0x33);
- pci_write_config8(PCI_DEV(0, 0x00, 0), PAM5, 0x33);
- pci_write_config8(PCI_DEV(0, 0x00, 0), PAM6, 0x33);
- pci_write_config8(PCI_DEV(0, 0x00, 0), TOLUD, 0x40); /* 1G XXX
dynamic! */ //Care to elaborate?
I think that's a bug. I'll give it a go and try removing it.
- printk_debug(" done.\r\n");
- /* Wait for MCH BAR to come up */
- printk_debug("Waiting for MCHBAR to come up...");
- if ((pci_read_config8(PCI_DEV(0, 0x0f, 0), 0xe6) & 0x2) == 0x00) {
/* Bit 49 of CAPID0 */
do {
reg8 = *(volatile u8 *)0xfed40000;
} while (!(reg8 & 0x80));
- }
//Consistency with \r\n ...
- printk_debug("ok\r\n");
+}
+static void i945_setup_egress_port(void) +{
- u32 reg32;
- u32 timeout;
//and just \n
Which one is the right one to use these days?
- printk_debug("Wait for VC1 negotiation ...");
- /* Wait for VC1 negotiation pending */
- timeout = 0x7ffff;
- while ((DMIBAR16(DMIVC1RSTS) & (1 << 1)) && --timeout) ;
- if (!timeout)
printk_debug("timeout!\n");
- else
printk_debug("done..\n");
//Do we need the #if 1 ?
Good question. I am not sure when ASPM should be enabled and when it should not. At some point this should be a better #if or if.
+#if 1
- /* Enable Active State Power Management (ASPM) L0 state */
- reg32 = DMIBAR32(DMILCAP);
- reg32 &= ~(7 << 12);
- reg32 |= (2 << 12);
- reg32 &= ~(7 << 15);
- reg32 |= (2 << 15);
- DMIBAR32(DMILCAP) = reg32;
- reg32 = DMIBAR32(DMICC);
- reg32 &= 0x00ffffff;
- reg32 &= ~(3 << 0);
- reg32 |= (1 << 0);
- DMIBAR32(DMICC) = reg32;
- if (0) {
DMIBAR32(DMILCTL) |= (3 << 0);
- }
+#endif
- /* Last but not least, some additional steps */
- reg32 = MCHBAR32(FSBSNPCTL);
- reg32 &= ~(0xff << 2);
- reg32 |= (0xaa << 2);
- MCHBAR32(FSBSNPCTL) = reg32;
- DMIBAR32(0x2c) = 0x86000040;
- reg32 = DMIBAR32(0x204);
- reg32 &= ~0x3ff;
//should be #if DMIX == 4?
+#if 1
- reg32 |= 0x13f; /* for x4 DMI only */
+#else
- reg32 |= 0x1e4; /* for x2 DMI only */
+#endif
- DMIBAR32(0x204) = reg32;
Not sure. And set this in auto.c?
// I think this should be named disabled, since it doesn't disable it.
+static int sdram_capabilities_MEM4G_disable(void) +{
- u8 reg8;
- reg8 = pci_read_config8(PCI_DEV(0, 0x00, 0), 0xe5);
- reg8 &= (1 << 0);
- return (reg8 != 0);
+}
agreed
+static void sdram_detect_smallest_refresh(struct sys_info * sysinfo) +{
- int i;
- sysinfo->refresh = 0;
- for (i=0; i<2*DIMM_SOCKETS; i++) {
int refresh;
if (sysinfo->dimm[i] == SYSINFO_DIMM_NOT_POPULATED)
continue;
refresh = spd_read_byte(DIMM_SPD_BASE + i, SPD_REFRESH) &
~(1 << 7);
/* 15.6us */
if (!refresh)
continue;
/* Refresh is slower than 15.6us, use 15.6us */
if (refresh > 2)
continue;
if (refresh == 2) {
sysinfo->refresh = 1;
break;
}
// It looks like there is only one unsupported value (1) could say that here // If that value means 3.9 us: // die("DDR-II module has unsupported refresh value (3.9 us)\n");
die("DDR-II module has unsupported refresh value\n");
I never got any of those 3.9us modules, so I can't tell for sure that assumption is true. Even if it is, I doubt knowing it's 3.9 is of much value.
+static void sdram_program_memory_frequency(struct sys_info *sysinfo) +{
- u32 clkcfg;
- u8 reg8;
- printk_debug ("Setting Memory Frequency... ");
- clkcfg = MCHBAR32(CLKCFG);
- printk_debug("CLKCFG=0x%08x, ", clkcfg);
- clkcfg &= ~( (1 << 12) | (1 << 7) | ( 7 << 4) );
- if (sysinfo->mvco4x) {
printk_debug("MVCO 4x, ");
// You just did this - why twice
clkcfg &= ~(1 << 12);
- }
Good catch. Let me check.
- printk_debug("RAM initialization finished.\r\n");
- sdram_setup_processor_side();
+}
//Since this is CPU specific, should it go with the CPU files?
While the name is misleading, it really sets up stuff in the chipset, not in the CPU. It's not CPU specific, it just sets up parts of the northbridge that cope with the CPU.
printk_debug("%dM UMA\n", uma_size >> 10);
tomk -= uma_size;
- }
- /* The following needs to be 2 lines, otherwise the second
* number is always 0
*/
// Did you try since tomk is unsigned long? // printk_info("Available memory: %ldK (%ldM)\n", tomk, (tomk >> 10));
I tried lots of stuff, but I am not sure I tried that. Will retry.
- printk_info("Available memory: %dK", tomk);
- printk_info(" (%dM)\n", (tomk >> 10));
- tolmk = tomk;
- /* 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);
- }
- assign_resources(&dev->link[0]);
+}
Stefan
Myles Watson wrote:
Support for the Intel 945 northbridge.
Sorry I'm late. I know it's already in, but I was in the middle of reviewing it. I prefixed my comments with //, I hope that helps you
find
them faster.
Ok, trying to address the issues:
Thanks. It makes it more motivating to do future reviews.
//Consistency with \r\n ...
- printk_debug("ok\r\n");
+}
+static void i945_setup_egress_port(void) +{
- u32 reg32;
- u32 timeout;
//and just \n
Which one is the right one to use these days?
I think the consensus was just \n. That's what v3 uses all the way through.
Thanks, Myles
On 07.11.2008, at 19:09, "Myles Watson" mylesgw@gmail.com wrote:
Ok, trying to address the issues:
Thanks. It makes it more motivating to do future reviews.
Sorry I didn't reply earlier. Your input is much appreciated. Don't be demoticated by the delay. Stuff like this won't be lost.
//Consistency with \r\n ...
- printk_debug("ok\r\n");
+}
+static void i945_setup_egress_port(void) +{
- u32 reg32;
- u32 timeout;
//and just \n
Which one is the right one to use these days?
I think the consensus was just \n. That's what v3 uses all the way through.
In v3 we use the same printk all over the place, while in v2 we have a mess... I think print_debug wanted \r while printk_debug does the right thing and attaches it automatically. So I need to fix \r\n to. \n in a lot of places.
Thanks, Stefan
See patch
Changes required to the device allocator:
- leave a hole for mmapped PCIe config space if
CONFIG_PCIE_CONFIGSPACE_HOLE
is set.
- Mask moving bits to 32bit when resources are not supposed above 4G.
Linux
does not like this, even though the resource is disabled.
Signed-off-by: Stefan Reinauer stepan@coresystems.de
Looks good. would it be better to set the resource to 0 instead of to moving bits? Then there would not be a need for the special case. It also makes it easier to read the config space.
Acked-by: Myles Watson mylesgw@gmail.com
Thanks, Myles
Myles Watson wrote:
Changes required to the device allocator:
- leave a hole for mmapped PCIe config space if
CONFIG_PCIE_CONFIGSPACE_HOLE
is set.
- Mask moving bits to 32bit when resources are not supposed above 4G.
Linux
does not like this, even though the resource is disabled.
Signed-off-by: Stefan Reinauer stepan@coresystems.de
Looks good. would it be better to set the resource to 0 instead of to moving bits? Then there would not be a need for the special case. It also makes it easier to read the config space.
Acked-by: Myles Watson mylesgw@gmail.com
Thanks! r3699.
According to Ron and Eric, setting the resource to 0 will not work on some devices. I know factory bios has done it on at least the bridges I've seen so I am not sure what the right behavior would be. Setting them to 0 would seem the right thing.
Stefan
-----Original Message----- From: Stefan Reinauer [mailto:stepan@coresystems.de] Sent: Tuesday, October 28, 2008 9:16 PM To: Myles Watson Cc: 'Coreboot' Subject: Re: [coreboot] [PATCH 5/6] Changes required to the device allocator
Myles Watson wrote:
Changes required to the device allocator:
- leave a hole for mmapped PCIe config space if
CONFIG_PCIE_CONFIGSPACE_HOLE
is set.
- Mask moving bits to 32bit when resources are not supposed above 4G.
Linux
does not like this, even though the resource is disabled.
Signed-off-by: Stefan Reinauer stepan@coresystems.de
Looks good. would it be better to set the resource to 0 instead of to moving bits? Then there would not be a need for the special case. It
also
makes it easier to read the config space.
Acked-by: Myles Watson mylesgw@gmail.com
Thanks! r3699.
According to Ron and Eric, setting the resource to 0 will not work on some devices. I know factory bios has done it on at least the bridges I've seen so I am not sure what the right behavior would be. Setting them to 0 would seem the right thing.
Should we consider fix-ups for broken boards, then? How common is it?
Thanks, Myles
Myles Watson wrote:
-----Original Message----- From: Stefan Reinauer [mailto:stepan@coresystems.de] Sent: Tuesday, October 28, 2008 9:16 PM To: Myles Watson Cc: 'Coreboot' Subject: Re: [coreboot] [PATCH 5/6] Changes required to the device allocator
Myles Watson wrote:
Changes required to the device allocator:
- leave a hole for mmapped PCIe config space if
CONFIG_PCIE_CONFIGSPACE_HOLE
is set.
- Mask moving bits to 32bit when resources are not supposed above 4G.
Linux
does not like this, even though the resource is disabled.
Signed-off-by: Stefan Reinauer stepan@coresystems.de
Looks good. would it be better to set the resource to 0 instead of to moving bits? Then there would not be a need for the special case. It
also
makes it easier to read the config space.
Acked-by: Myles Watson mylesgw@gmail.com
Thanks! r3699.
According to Ron and Eric, setting the resource to 0 will not work on some devices. I know factory bios has done it on at least the bridges I've seen so I am not sure what the right behavior would be. Setting them to 0 would seem the right thing.
Should we consider fix-ups for broken boards, then? How common is it?
Yes, that's what I've been thinking too.
See patch
Acked-by: Ronald G. Minnich rminnich@gmail.com
-----Original Message----- From: coreboot-bounces@coreboot.org [mailto:coreboot-bounces@coreboot.org] On Behalf Of Stefan Reinauer Sent: Tuesday, October 28, 2008 7:18 PM To: Coreboot Subject: [coreboot] [PATCH 6/6] Support for the Kontron 986LCD-M mainboardseries
See patch
It would be nice to have a comment for why the code was kept for this #if 0 and a couple of the others.
+unsigned long acpi_fill_mcfg(unsigned long current) +{ +#if 0
Thanks, Myles
Hi Stefan,
On 29.10.2008 02:09, Stefan Reinauer wrote:
I am glad to announce the release of the work we did in the last couple of months writing support for a somewhat modern Intel Desktop/Mobile chipset running with the Core Duo/Core 2 Duo: The i945 + ICH7.
This is awesome! Really awesome. I'll look into porting some of the early init stuff to v3 ASAP.
The support package has been split in 6 different smaller patches:
1_superio_winbond_w83627thg.diff: Implement support for the Winbond W83627THG. 2_southbridge_intel_i82801gx.diff: Support for the Intel ICH7 southbridge. 3_cpu_core_duo.diff: Support for Intel Core Duo and Core 2 Duo (tm) CPUs. 4_northbridge_intel_i945.diff: Support for the Intel 945 northbridge. 5_device_allocator.diff: Changes required to the device allocator 6_mainboard_kontron_986lcd_m.diff: Support for the Kontron 986LCD-M mainboard series.
I hope to find time to review this soon.
Regards, Carl-Daniel