summaryrefslogtreecommitdiff
path: root/src/northbridge/amd
diff options
context:
space:
mode:
authorTimothy Pearson <tpearson@raptorengineeringinc.com>2015-10-16 13:51:51 -0500
committerMartin Roth <martinroth@google.com>2015-11-02 23:45:19 +0100
commit730a043fb6cb4dd3cb5af8f8640365727b598648 (patch)
tree59afe45caca1a8e1682939c7e44e95344104533e /src/northbridge/amd
parentd150006c4a4584bc9933c2d8ff580a54c4f0cc2a (diff)
cpu/amd: Add initial AMD Family 15h support
TEST: Booted ASUS KGPE-D16 with single Opteron 6380 * Unbuffered DDR3 DIMMs tested and working * Suspend to RAM (S3) tested and working Change-Id: Idffd2ce36ce183fbfa087e5ba69a9148f084b45e Signed-off-by: Timothy Pearson <tpearson@raptorengineeringinc.com> Reviewed-on: http://review.coreboot.org/11966 Tested-by: build bot (Jenkins) Reviewed-by: Martin Roth <martinroth@google.com>
Diffstat (limited to 'src/northbridge/amd')
-rw-r--r--src/northbridge/amd/amdfam10/Kconfig2
-rw-r--r--src/northbridge/amd/amdfam10/Makefile.inc2
-rw-r--r--src/northbridge/amd/amdfam10/amdfam10.h6
-rw-r--r--src/northbridge/amd/amdfam10/amdfam10_util.c13
-rw-r--r--src/northbridge/amd/amdfam10/link_control.c86
-rw-r--r--src/northbridge/amd/amdfam10/misc_control.c7
-rw-r--r--src/northbridge/amd/amdfam10/nb_control.c85
-rw-r--r--src/northbridge/amd/amdfam10/northbridge.c233
-rw-r--r--src/northbridge/amd/amdfam10/raminit_amdmct.c304
-rw-r--r--src/northbridge/amd/amdht/h3ncmn.c171
-rw-r--r--src/northbridge/amd/amdht/ht_wrapper.c43
-rw-r--r--src/northbridge/amd/amdmct/amddefs.h78
-rw-r--r--src/northbridge/amd/amdmct/mct/mct_d.c4
-rw-r--r--src/northbridge/amd/amdmct/mct/mct_d.h20
-rw-r--r--src/northbridge/amd/amdmct/mct/mctpro_d.c21
-rw-r--r--src/northbridge/amd/amdmct/mct_ddr3/mct_d.c3187
-rw-r--r--src/northbridge/amd/amdmct/mct_ddr3/mct_d.h124
-rw-r--r--src/northbridge/amd/amdmct/mct_ddr3/mct_d_gcc.h9
-rw-r--r--src/northbridge/amd/amdmct/mct_ddr3/mctardk5.c21
-rw-r--r--src/northbridge/amd/amdmct/mct_ddr3/mctcsi_d.c27
-rw-r--r--src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c1087
-rw-r--r--src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c55
-rw-r--r--src/northbridge/amd/amdmct/mct_ddr3/mcthdi.c7
-rw-r--r--src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c105
-rw-r--r--src/northbridge/amd/amdmct/mct_ddr3/mctproc.c2
-rw-r--r--src/northbridge/amd/amdmct/mct_ddr3/mctrci.c24
-rw-r--r--src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c585
-rw-r--r--src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c1342
-rw-r--r--src/northbridge/amd/amdmct/mct_ddr3/mctsrc1p.c10
-rw-r--r--src/northbridge/amd/amdmct/mct_ddr3/mcttmrl.c20
-rw-r--r--src/northbridge/amd/amdmct/mct_ddr3/mctwl.c255
-rw-r--r--src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c1007
-rw-r--r--src/northbridge/amd/amdmct/mct_ddr3/mutilc_d.c69
-rw-r--r--src/northbridge/amd/amdmct/mct_ddr3/mwlc_d.h46
-rw-r--r--src/northbridge/amd/amdmct/mct_ddr3/s3utils.c652
-rw-r--r--src/northbridge/amd/amdmct/wrappers/mcti.h14
-rw-r--r--src/northbridge/amd/amdmct/wrappers/mcti_d.c43
37 files changed, 8092 insertions, 1674 deletions
diff --git a/src/northbridge/amd/amdfam10/Kconfig b/src/northbridge/amd/amdfam10/Kconfig
index 17968b4b90..cc22365e4d 100644
--- a/src/northbridge/amd/amdfam10/Kconfig
+++ b/src/northbridge/amd/amdfam10/Kconfig
@@ -95,7 +95,7 @@ endif
config S3_DATA_SIZE
int
- default 16384
+ default 32768
depends on (HAVE_ACPI_RESUME)
config S3_DATA_POS
diff --git a/src/northbridge/amd/amdfam10/Makefile.inc b/src/northbridge/amd/amdfam10/Makefile.inc
index f083f31c87..c2b015b955 100644
--- a/src/northbridge/amd/amdfam10/Makefile.inc
+++ b/src/northbridge/amd/amdfam10/Makefile.inc
@@ -2,6 +2,8 @@ ifeq ($(CONFIG_NORTHBRIDGE_AMD_AMDFAM10),y)
ramstage-y += northbridge.c
ramstage-y += misc_control.c
+ramstage-y += link_control.c
+ramstage-y += nb_control.c
romstage-y += amdfam10_util.c
ramstage-y += amdfam10_util.c
diff --git a/src/northbridge/amd/amdfam10/amdfam10.h b/src/northbridge/amd/amdfam10/amdfam10.h
index a8500c70e1..c0bfc5a5d5 100644
--- a/src/northbridge/amd/amdfam10/amdfam10.h
+++ b/src/northbridge/amd/amdfam10/amdfam10.h
@@ -958,9 +958,12 @@ that are corresponding to 0x01, 0x02, 0x03, 0x05, 0x06, 0x07
#define LAPIC_MSG_REG 0x380
#define F10_APSTATE_STARTED 0x13 // start of AP execution
-#define F10_APSTATE_STOPPED 0x14 // allow AP to stop
+#define F10_APSTATE_ASLEEP 0x14 // AP sleeping
+#define F10_APSTATE_STOPPED 0x15 // allow AP to stop
#define F10_APSTATE_RESET 0x01 // waiting for warm reset
+#define MAX_CORES_SUPPORTED 128
+
#include "nums.h"
#ifdef __PRE_RAM__
@@ -1034,7 +1037,6 @@ struct sys_info {
struct MCTStatStruc MCTstat;
struct DCTStatStruc DCTstatA[NODE_NUMS];
-
} __attribute__((packed));
#ifdef __PRE_RAM__
diff --git a/src/northbridge/amd/amdfam10/amdfam10_util.c b/src/northbridge/amd/amdfam10/amdfam10_util.c
index 12452a599a..0ef6c92b49 100644
--- a/src/northbridge/amd/amdfam10/amdfam10_util.c
+++ b/src/northbridge/amd/amdfam10/amdfam10_util.c
@@ -30,14 +30,14 @@ u32 Get_NB32(u32 dev, u32 reg)
}
#endif
-u32 mctGetLogicalCPUID(u32 Node)
+uint64_t mctGetLogicalCPUID(u32 Node)
{
/* Converts the CPUID to a logical ID MASK that is used to check
CPU version support versions */
u32 dev;
u32 val, valx;
u32 family, model, stepping;
- u32 ret;
+ uint64_t ret;
if (Node == 0xFF) { /* current node */
val = cpuid_eax(0x80000001);
@@ -96,9 +96,16 @@ u32 mctGetLogicalCPUID(u32 Node)
case 0x100a0:
ret = AMD_PH_E0;
break;
+ case 0x15012:
+ case 0x1501f:
+ ret = AMD_OR_B2;
+ break;
+ case 0x15020:
+ ret = AMD_OR_C0;
+ break;
default:
/* FIXME: mabe we should die() here. */
- printk(BIOS_ERR, "FIXME! CPU Version unknown or not supported! \n");
+ printk(BIOS_ERR, "FIXME! CPU Version unknown or not supported! %08x\n", valx);
ret = 0;
}
diff --git a/src/northbridge/amd/amdfam10/link_control.c b/src/northbridge/amd/amdfam10/link_control.c
new file mode 100644
index 0000000000..1091ef4f2e
--- /dev/null
+++ b/src/northbridge/amd/amdfam10/link_control.c
@@ -0,0 +1,86 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering
+ *
+ * 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
+ */
+
+/* Configure various power control registers, including processor
+ * boost support.
+ */
+
+#include <console/console.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/pci_ops.h>
+#include <pc80/mc146818rtc.h>
+#include <lib.h>
+#include <cpu/amd/model_10xxx_rev.h>
+
+#include "amdfam10.h"
+
+static inline uint8_t is_fam15h(void)
+{
+ uint8_t fam15h = 0;
+ uint32_t family;
+
+ family = cpuid_eax(0x80000001);
+ family = ((family & 0xf00000) >> 16) | ((family & 0xf00) >> 8);
+
+ if (family >= 0x6f)
+ /* Family 15h or later */
+ fam15h = 1;
+
+ return fam15h;
+}
+
+static void nb_control_init(struct device *dev)
+{
+ uint32_t dword;
+
+ printk(BIOS_DEBUG, "NB: Function 4 Link Control.. ");
+
+ if (is_fam15h()) {
+ /* Enable APM */
+ dword = pci_read_config32(dev, 0x15c);
+ dword |= (0x1 << 7); /* ApmMasterEn = 1 */
+ pci_write_config32(dev, 0x15c, dword);
+ }
+
+ printk(BIOS_DEBUG, "done.\n");
+}
+
+
+static struct device_operations mcf4_ops = {
+ .read_resources = pci_dev_read_resources,
+ .set_resources = pci_dev_set_resources,
+ .enable_resources = pci_dev_enable_resources,
+ .init = nb_control_init,
+ .scan_bus = 0,
+ .ops_pci = 0,
+};
+
+static const struct pci_driver mcf4_driver_fam10 __pci_driver = {
+ .ops = &mcf4_ops,
+ .vendor = PCI_VENDOR_ID_AMD,
+ .device = 0x1204,
+};
+
+static const struct pci_driver mcf4_driver_fam15 __pci_driver = {
+ .ops = &mcf4_ops,
+ .vendor = PCI_VENDOR_ID_AMD,
+ .device = 0x1604,
+}; \ No newline at end of file
diff --git a/src/northbridge/amd/amdfam10/misc_control.c b/src/northbridge/amd/amdfam10/misc_control.c
index 808f587920..24c422d67e 100644
--- a/src/northbridge/amd/amdfam10/misc_control.c
+++ b/src/northbridge/amd/amdfam10/misc_control.c
@@ -4,6 +4,7 @@
* Copyright (C) 2003 by Eric Biederman
* Copyright (C) Stefan Reinauer
* Copyright (C) 2007 Advanced Micro Devices, Inc.
+ * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering
*
* 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
@@ -148,3 +149,9 @@ static const struct pci_driver mcf3_driver __pci_driver = {
.vendor = PCI_VENDOR_ID_AMD,
.device = 0x1203,
};
+
+static const struct pci_driver mcf3_driver_fam15 __pci_driver = {
+ .ops = &mcf3_ops,
+ .vendor = PCI_VENDOR_ID_AMD,
+ .device = 0x1603,
+};
diff --git a/src/northbridge/amd/amdfam10/nb_control.c b/src/northbridge/amd/amdfam10/nb_control.c
new file mode 100644
index 0000000000..f95b6f80ae
--- /dev/null
+++ b/src/northbridge/amd/amdfam10/nb_control.c
@@ -0,0 +1,85 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering
+ *
+ * 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
+ */
+
+/* Configure various power control registers, including processor boost
+ * and TDP monitoring support.
+ */
+
+#include <console/console.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/pci_ops.h>
+#include <pc80/mc146818rtc.h>
+#include <lib.h>
+#include <cpu/amd/model_10xxx_rev.h>
+
+#include "amdfam10.h"
+
+static void nb_control_init(struct device *dev)
+{
+ uint32_t dword;
+ uint32_t f5x80;
+ uint8_t cu_enabled;
+ uint8_t compute_unit_count = 0;
+
+ printk(BIOS_DEBUG, "NB: Function 5 Northbridge Control.. ");
+
+ /* Determine the number of active compute units on this node */
+ f5x80 = pci_read_config32(dev, 0x80);
+ cu_enabled = f5x80 & 0xf;
+ if (cu_enabled == 0x1)
+ compute_unit_count = 1;
+ if (cu_enabled == 0x3)
+ compute_unit_count = 2;
+ if (cu_enabled == 0x7)
+ compute_unit_count = 3;
+ if (cu_enabled == 0xf)
+ compute_unit_count = 4;
+
+ /* Configure Processor TDP Running Average */
+ dword = pci_read_config32(dev, 0xe0);
+ dword &= ~0xf; /* RunAvgRange = 0x9 */
+ dword |= 0x9;
+ pci_write_config32(dev, 0xe0, dword);
+
+ /* Configure northbridge P-states */
+ dword = pci_read_config32(dev, 0xe0);
+ dword &= ~(0x7 << 9); /* NbPstateThreshold = compute_unit_count */
+ dword |= (compute_unit_count & 0x7) << 9;
+ pci_write_config32(dev, 0xe0, dword);
+
+ printk(BIOS_DEBUG, "done.\n");
+}
+
+
+static struct device_operations mcf5_ops = {
+ .read_resources = pci_dev_read_resources,
+ .set_resources = pci_dev_set_resources,
+ .enable_resources = pci_dev_enable_resources,
+ .init = nb_control_init,
+ .scan_bus = 0,
+ .ops_pci = 0,
+};
+
+static const struct pci_driver mcf5_driver_fam15 __pci_driver = {
+ .ops = &mcf5_ops,
+ .vendor = PCI_VENDOR_ID_AMD,
+ .device = 0x1605,
+}; \ No newline at end of file
diff --git a/src/northbridge/amd/amdfam10/northbridge.c b/src/northbridge/amd/amdfam10/northbridge.c
index a5f4140bbb..d1803ae667 100644
--- a/src/northbridge/amd/amdfam10/northbridge.c
+++ b/src/northbridge/amd/amdfam10/northbridge.c
@@ -77,6 +77,21 @@ device_t get_node_pci(u32 nodeid, u32 fn)
#endif
}
+static inline uint8_t is_fam15h(void)
+{
+ uint8_t fam15h = 0;
+ uint32_t family;
+
+ family = cpuid_eax(0x80000001);
+ family = ((family & 0xf00000) >> 16) | ((family & 0xf00) >> 8);
+
+ if (family >= 0x6f)
+ /* Family 15h or later */
+ fam15h = 1;
+
+ return fam15h;
+}
+
static void get_fx_devs(void)
{
int i;
@@ -198,7 +213,7 @@ static void amd_g34_fixup(struct bus *link, device_t dev)
/* Revision D or later */
rev_gte_d = 1;
- if (rev_gte_d) {
+ if (rev_gte_d || is_fam15h()) {
f3xe8 = pci_read_config32(get_node_pci(0, 3), 0xe8);
/* Check for dual node capability */
@@ -211,6 +226,15 @@ static void amd_g34_fixup(struct bus *link, device_t dev)
*/
f3xe8 = pci_read_config32(get_node_pci(nodeid, 3), 0xe8);
uint8_t internal_node_number = ((f3xe8 & 0xc0000000) >> 30);
+ uint8_t defective_link_number_1;
+ uint8_t defective_link_number_2;
+ if (is_fam15h()) {
+ defective_link_number_1 = 4; /* Link 0 Sublink 1 */
+ defective_link_number_2 = 7; /* Link 3 Sublink 1 */
+ } else {
+ defective_link_number_1 = 6; /* Link 2 Sublink 1 */
+ defective_link_number_2 = 5; /* Link 1 Sublink 1 */
+ }
if (internal_node_number == 0) {
/* Node 0 */
if (link->link_num == 6) /* Link 2 Sublink 1 */
@@ -310,6 +334,46 @@ static void amdfam10_scan_chains(device_t dev)
{
struct bus *link;
+#if CONFIG_CPU_AMD_SOCKET_G34_NON_AGESA
+ if (is_fam15h()) {
+ uint8_t current_link_number = 0;
+
+ for (link = dev->link_list; link; link = link->next) {
+ /* The following links have changed position in Fam15h G34 processors:
+ * Fam10 Fam15
+ * Node 0
+ * L3 --> L1
+ * L0 --> L3
+ * L1 --> L2
+ * L2 --> L0
+ * Node 1
+ * L0 --> L0
+ * L1 --> L3
+ * L2 --> L1
+ * L3 --> L2
+ */
+ if (link->link_num == 0)
+ link->link_num = 3;
+ else if (link->link_num == 1)
+ link->link_num = 2;
+ else if (link->link_num == 2)
+ link->link_num = 0;
+ else if (link->link_num == 3)
+ link->link_num = 1;
+ else if (link->link_num == 5)
+ link->link_num = 7;
+ else if (link->link_num == 6)
+ link->link_num = 5;
+ else if (link->link_num == 7)
+ link->link_num = 6;
+
+ current_link_number++;
+ if (current_link_number > 3)
+ current_link_number = 0;
+ }
+ }
+#endif
+
/* Do sb ht chain at first, in case s2885 put sb chain (8131/8111) on link2, but put 8151 on link0 */
trim_ht_chain(dev);
@@ -616,13 +680,21 @@ static const struct pci_driver mcf0_driver __pci_driver = {
.device = 0x1200,
};
+
static void amdfam10_nb_init(void *chip_info)
{
relocate_sb_ht_chain();
}
+static const struct pci_driver mcf0_driver_fam15 __pci_driver = {
+ .ops = &northbridge_operations,
+ .vendor = PCI_VENDOR_ID_AMD,
+ .device = 0x1600,
+};
+
+
struct chip_operations northbridge_amd_amdfam10_ops = {
- CHIP_NAME("AMD FAM10 Northbridge")
+ CHIP_NAME("AMD Family 10h/15h Northbridge")
.enable_dev = 0,
.init = amdfam10_nb_init,
};
@@ -946,38 +1018,61 @@ static int amdfam10_get_smbios_data16(int* count, int handle, unsigned long *cur
static uint16_t amdmct_mct_speed_enum_to_mhz(uint8_t speed)
{
- if (IS_ENABLED(CONFIG_DIMM_DDR2)) {
- switch (speed) {
- case 1:
- return 200;
- case 2:
- return 266;
- case 3:
- return 333;
- case 4:
- return 400;
- case 5:
- return 533;
- default:
- return 0;
- }
- } else if (IS_ENABLED(CONFIG_DIMM_DDR3)) {
- switch (speed) {
- case 3:
- return 333;
- case 4:
- return 400;
- case 5:
- return 533;
- case 6:
- return 667;
- case 7:
- return 800;
- default:
- return 0;
+ if (is_fam15h()) {
+ if (IS_ENABLED(CONFIG_DIMM_DDR3)) {
+ switch (speed) {
+ case 0x4:
+ return 333;
+ case 0x6:
+ return 400;
+ case 0xa:
+ return 533;
+ case 0xe:
+ return 667;
+ case 0x12:
+ return 800;
+ case 0x16:
+ return 933;
+ default:
+ return 0;
+ }
+ } else {
+ return 0;
}
} else {
- return 0;
+ if (IS_ENABLED(CONFIG_DIMM_DDR2)) {
+ switch (speed) {
+ case 1:
+ return 200;
+ case 2:
+ return 266;
+ case 3:
+ return 333;
+ case 4:
+ return 400;
+ case 5:
+ return 533;
+ default:
+ return 0;
+ }
+ } else if (IS_ENABLED(CONFIG_DIMM_DDR3)) {
+ switch (speed) {
+ case 3:
+ return 333;
+ case 4:
+ return 400;
+ case 5:
+ return 533;
+ case 6:
+ return 667;
+ case 7:
+ return 800;
+ default:
+ return 0;
+ }
+ } else {
+ return 0;
+ }
}
}
@@ -1072,6 +1167,8 @@ static int amdfam10_get_smbios_data17(int* count, int handle, int parent_handle,
#if IS_ENABLED(CONFIG_DIMM_DDR3)
/* Find the maximum and minimum supported voltages */
uint8_t supported_voltages = mem_info->dct_stat[node].DimmSupportedVoltages[slot];
+ uint8_t configured_voltage = mem_info->dct_stat[node].DimmConfiguredVoltage[slot];
+
if (supported_voltages & 0x8)
t->minimum_voltage = 1150;
else if (supported_voltages & 0x4)
@@ -1090,7 +1187,14 @@ static int amdfam10_get_smbios_data17(int* count, int handle, int parent_handle,
else if (supported_voltages & 0x8)
t->maximum_voltage = 1150;
- t->configured_voltage = mem_info->dct_stat[node].DimmConfiguredVoltage[slot];
+ if (configured_voltage & 0x8)
+ t->configured_voltage = 1150;
+ else if (configured_voltage & 0x4)
+ t->configured_voltage = 1250;
+ else if (configured_voltage & 0x2)
+ t->configured_voltage = 1350;
+ else if (configured_voltage & 0x1)
+ t->configured_voltage = 1500;
#endif
}
t->memory_error_information_handle = 0xFFFE; /* no error information handle available */
@@ -1229,12 +1333,14 @@ static void cpu_bus_scan(device_t dev)
#if CONFIG_CBB
device_t pci_domain;
#endif
+ int nvram = 0;
int i,j;
int nodes;
unsigned nb_cfg_54;
unsigned siblings;
int cores_found;
int disable_siblings;
+ uint8_t disable_cu_siblings = 0;
unsigned ApicIdCoreIdSize;
nb_cfg_54 = 0;
@@ -1321,14 +1427,23 @@ static void cpu_bus_scan(device_t dev)
/* Always use the devicetree node with lapic_id 0 for BSP. */
remap_bsp_lapic(cpu_bus);
+ if (get_option(&nvram, "compute_unit_siblings") == CB_SUCCESS)
+ disable_cu_siblings = !!nvram;
+
+ if (disable_cu_siblings)
+ printk(BIOS_DEBUG, "Disabling siblings on each compute unit as requested\n");
+
for(i = 0; i < nodes; i++) {
device_t cdb_dev;
unsigned busn, devn;
struct bus *pbus;
+ uint8_t fam15h = 0;
uint8_t rev_gte_d = 0;
uint8_t dual_node = 0;
uint32_t f3xe8;
+ uint32_t family;
+ uint32_t model;
busn = CONFIG_CBB;
devn = CONFIG_CDB+i;
@@ -1368,7 +1483,16 @@ static void cpu_bus_scan(device_t dev)
f3xe8 = pci_read_config32(get_node_pci(0, 3), 0xe8);
- if (cpuid_eax(0x80000001) >= 0x8)
+ family = model = cpuid_eax(0x80000001);
+ model = ((model & 0xf0000) >> 12) | ((model & 0xf0) >> 4);
+
+ if (is_fam15h()) {
+ /* Family 15h or later */
+ fam15h = 1;
+ nb_cfg_54 = 1;
+ }
+
+ if ((model >= 0x8) || fam15h)
/* Revision D or later */
rev_gte_d = 1;
@@ -1378,13 +1502,20 @@ static void cpu_bus_scan(device_t dev)
dual_node = 1;
cores_found = 0; // one core
- cdb_dev = dev_find_slot(busn, PCI_DEVFN(devn, 3));
+ if (fam15h)
+ cdb_dev = dev_find_slot(busn, PCI_DEVFN(devn, 5));
+ else
+ cdb_dev = dev_find_slot(busn, PCI_DEVFN(devn, 3));
int enable_node = cdb_dev && cdb_dev->enabled;
if (enable_node) {
- j = pci_read_config32(cdb_dev, 0xe8);
- cores_found = (j >> 12) & 3; // dev is func 3
- if (siblings > 3)
- cores_found |= (j >> 13) & 4;
+ if (fam15h) {
+ cores_found = pci_read_config32(cdb_dev, 0x84) & 0xff;
+ } else {
+ j = pci_read_config32(cdb_dev, 0xe8);
+ cores_found = (j >> 12) & 3; // dev is func 3
+ if (siblings > 3)
+ cores_found |= (j >> 13) & 4;
+ }
printk(BIOS_DEBUG, " %s siblings=%d\n", dev_path(cdb_dev), cores_found);
}
@@ -1404,15 +1535,24 @@ static void cpu_bus_scan(device_t dev)
if (dual_node) {
apic_id = 0;
- if (nb_cfg_54) {
- apic_id |= ((i >> 1) & 0x3) << 4; /* Node ID */
+ if (fam15h) {
+ apic_id |= ((i >> 1) & 0x3) << 5; /* Node ID */
apic_id |= ((i & 0x1) * (siblings + 1)) + j; /* Core ID */
} else {
- apic_id |= i & 0x3; /* Node ID */
- apic_id |= (((i & 0x1) * (siblings + 1)) + j) << 4; /* Core ID */
+ if (nb_cfg_54) {
+ apic_id |= ((i >> 1) & 0x3) << 4; /* Node ID */
+ apic_id |= ((i & 0x1) * (siblings + 1)) + j; /* Core ID */
+ } else {
+ apic_id |= i & 0x3; /* Node ID */
+ apic_id |= (((i & 0x1) * (siblings + 1)) + j) << 4; /* Core ID */
+ }
}
} else {
- apic_id = i * (nb_cfg_54?(siblings+1):1) + j * (nb_cfg_54?1:64); // ?
+ if (fam15h) {
+ apic_id = (i * (siblings + 1)) + j;
+ } else {
+ apic_id = i * (nb_cfg_54?(siblings+1):1) + j * (nb_cfg_54?1:64); // ?
+ }
}
#if CONFIG_ENABLE_APIC_EXT_ID && (CONFIG_APIC_ID_OFFSET>0)
@@ -1422,6 +1562,9 @@ static void cpu_bus_scan(device_t dev)
}
}
#endif
+ if (disable_cu_siblings && (j & 0x1))
+ continue;
+
device_t cpu = add_cpu_device(cpu_bus, apic_id, enable_node);
if (cpu)
amd_cpu_topology(cpu, i, j);
@@ -1480,6 +1623,6 @@ static void root_complex_enable_dev(struct device *dev)
}
struct chip_operations northbridge_amd_amdfam10_root_complex_ops = {
- CHIP_NAME("AMD FAM10 Root Complex")
+ CHIP_NAME("AMD Family 10h/15h Root Complex")
.enable_dev = root_complex_enable_dev,
};
diff --git a/src/northbridge/amd/amdfam10/raminit_amdmct.c b/src/northbridge/amd/amdfam10/raminit_amdmct.c
index 30b5e8aa7a..d8023f808c 100644
--- a/src/northbridge/amd/amdfam10/raminit_amdmct.c
+++ b/src/northbridge/amd/amdfam10/raminit_amdmct.c
@@ -38,8 +38,120 @@ static void print_tf(const char *func, const char *strval)
#endif
}
-static uint16_t mct_MaxLoadFreq(uint8_t count, uint8_t registered, uint16_t freq)
+static inline void fam15h_switch_dct(uint32_t dev, uint8_t dct)
{
+ uint32_t dword;
+
+ dword = Get_NB32(dev, 0x10c);
+ dword &= ~0x1;
+ dword |= (dct & 0x1);
+ Set_NB32(dev, 0x10c, dword);
+}
+
+static inline void fam15h_switch_nb_pstate_config_reg(uint32_t dev, uint8_t nb_pstate)
+{
+ uint32_t dword;
+
+ dword = Get_NB32(dev, 0x10c);
+ dword &= ~(0x3 << 4);
+ dword |= (nb_pstate & 0x3) << 4;
+ Set_NB32(dev, 0x10c, dword);
+}
+
+static inline uint32_t Get_NB32_DCT(uint32_t dev, uint8_t dct, uint32_t reg)
+{
+ if (is_fam15h()) {
+ /* Obtain address of function 0x1 */
+ uint32_t dev_map = (dev & (~(0x7 << 12))) | (0x1 << 12);
+ fam15h_switch_dct(dev_map, dct);
+ return Get_NB32(dev, reg);
+ } else {
+ return Get_NB32(dev, (0x100 * dct) + reg);
+ }
+}
+
+static inline void Set_NB32_DCT(uint32_t dev, uint8_t dct, uint32_t reg, uint32_t val)
+{
+ if (is_fam15h()) {
+ /* Obtain address of function 0x1 */
+ uint32_t dev_map = (dev & (~(0x7 << 12))) | (0x1 << 12);
+ fam15h_switch_dct(dev_map, dct);
+ Set_NB32(dev, reg, val);
+ } else {
+ Set_NB32(dev, (0x100 * dct) + reg, val);
+ }
+}
+
+static inline uint32_t Get_NB32_DCT_NBPstate(uint32_t dev, uint8_t dct, uint8_t nb_pstate, uint32_t reg)
+{
+ if (is_fam15h()) {
+ /* Obtain address of function 0x1 */
+ uint32_t dev_map = (dev & (~(0x7 << 12))) | (0x1 << 12);
+ fam15h_switch_dct(dev_map, dct);
+ fam15h_switch_nb_pstate_config_reg(dev_map, nb_pstate);
+ return Get_NB32(dev, reg);
+ } else {
+ return Get_NB32(dev, (0x100 * dct) + reg);
+ }
+}
+
+static inline void Set_NB32_DCT_NBPstate(uint32_t dev, uint8_t dct, uint8_t nb_pstate, uint32_t reg, uint32_t val)
+{
+ if (is_fam15h()) {
+ /* Obtain address of function 0x1 */
+ uint32_t dev_map = (dev & (~(0x7 << 12))) | (0x1 << 12);
+ fam15h_switch_dct(dev_map, dct);
+ fam15h_switch_nb_pstate_config_reg(dev_map, nb_pstate);
+ Set_NB32(dev, reg, val);
+ } else {
+ Set_NB32(dev, (0x100 * dct) + reg, val);
+ }
+}
+
+static inline uint32_t Get_NB32_index_wait_DCT(uint32_t dev, uint8_t dct, uint32_t index_reg, uint32_t index)
+{
+ if (is_fam15h()) {
+ /* Obtain address of function 0x1 */
+ uint32_t dev_map = (dev & (~(0x7 << 12))) | (0x1 << 12);
+ fam15h_switch_dct(dev_map, dct);
+ return Get_NB32_index_wait(dev, index_reg, index);
+ } else {
+ return Get_NB32_index_wait(dev, (0x100 * dct) + index_reg, index);
+ }
+}
+
+static inline void Set_NB32_index_wait_DCT(uint32_t dev, uint8_t dct, uint32_t index_reg, uint32_t index, uint32_t data)
+{
+ if (is_fam15h()) {
+ /* Obtain address of function 0x1 */
+ uint32_t dev_map = (dev & (~(0x7 << 12))) | (0x1 << 12);
+ fam15h_switch_dct(dev_map, dct);
+ Set_NB32_index_wait(dev, index_reg, index, data);
+ } else {
+ Set_NB32_index_wait(dev, (0x100 * dct) + index_reg, index, data);
+ }
+}
+
+static uint16_t voltage_index_to_mv(uint8_t index)
+{
+ if (index & 0x8)
+ return 1150;
+ if (index & 0x4)
+ return 1250;
+ else if (index & 0x2)
+ return 1350;
+ else
+ return 1500;
+}
+
+static uint16_t mct_MaxLoadFreq(uint8_t count, uint8_t highest_rank_count, uint8_t registered, uint8_t voltage, uint16_t freq)
+{
+ /* FIXME
+ * Mainboards need to be able to specify the maximum number of DIMMs installable per channel
+ * For now assume a maximum of 2 DIMMs per channel can be installed
+ */
+ uint8_t MaxDimmsInstallable = 2;
+
/* Return limited maximum RAM frequency */
if (IS_ENABLED(CONFIG_DIMM_DDR2)) {
if (IS_ENABLED(CONFIG_DIMM_REGISTERED) && registered) {
@@ -62,34 +174,178 @@ static uint16_t mct_MaxLoadFreq(uint8_t count, uint8_t registered, uint16_t freq
}
}
} else if (IS_ENABLED(CONFIG_DIMM_DDR3)) {
- if (IS_ENABLED(CONFIG_DIMM_REGISTERED) && registered) {
- /* K10 BKDG Rev. 3.62 Table 34 */
- if (count > 2) {
- /* Limit to DDR3-800 */
- if (freq > 400) {
- freq = 400;
- print_tf(__func__, ": More than 2 registered DIMMs on channel; limiting to DDR3-800\n");
+ if (voltage == 0) {
+ printk(BIOS_DEBUG, "%s: WARNING: Mainboard DDR3 voltage unknown, assuming 1.5V!\n", __func__);
+ voltage = 0x1;
+ }
+
+ if (is_fam15h()) {
+ if (IS_ENABLED(CONFIG_DIMM_REGISTERED) && registered) {
+ /* Fam15h BKDG Rev. 3.14 Table 27 */
+ if (voltage & 0x4) {
+ /* 1.25V */
+ if (count > 1) {
+ if (highest_rank_count > 1) {
+ /* Limit to DDR3-1066 */
+ if (freq > 533) {
+ freq = 533;
+ printk(BIOS_DEBUG, "%s: More than 1 registered DIMM on %dmV channel; limiting to DDR3-1066\n", __func__, voltage_index_to_mv(voltage));
+ }
+ } else {
+ /* Limit to DDR3-1333 */
+ if (freq > 666) {
+ freq = 666;
+ printk(BIOS_DEBUG, "%s: More than 1 registered DIMM on %dmV channel; limiting to DDR3-1333\n", __func__, voltage_index_to_mv(voltage));
+ }
+ }
+ } else {
+ /* Limit to DDR3-1333 */
+ if (freq > 666) {
+ freq = 666;
+ printk(BIOS_DEBUG, "%s: 1 registered DIMM on %dmV channel; limiting to DDR3-1333\n", __func__, voltage_index_to_mv(voltage));
+ }
+ }
+ } else if (voltage & 0x2) {
+ /* 1.35V */
+ if (count > 1) {
+ /* Limit to DDR3-1333 */
+ if (freq > 666) {
+ freq = 666;
+ printk(BIOS_DEBUG, "%s: More than 1 registered DIMM on %dmV channel; limiting to DDR3-1333\n", __func__, voltage_index_to_mv(voltage));
+ }
+ } else {
+ /* Limit to DDR3-1600 */
+ if (freq > 800) {
+ freq = 800;
+ printk(BIOS_DEBUG, "%s: 1 registered DIMM on %dmV channel; limiting to DDR3-1600\n", __func__, voltage_index_to_mv(voltage));
+ }
+ }
+ } else if (voltage & 0x1) {
+ /* 1.50V */
+ if (count > 1) {
+ /* Limit to DDR3-1600 */
+ if (freq > 800) {
+ freq = 800;
+ printk(BIOS_DEBUG, "%s: More than 1 registered DIMM on %dmV channel; limiting to DDR3-1600\n", __func__, voltage_index_to_mv(voltage));
+ }
+ } else {
+ /* Limit to DDR3-1866 */
+ if (freq > 933) {
+ freq = 933;
+ printk(BIOS_DEBUG, "%s: 1 registered DIMM on %dmV channel; limiting to DDR3-1866\n", __func__, voltage_index_to_mv(voltage));
+ }
+ }
+ }
+ } else {
+ /* Fam15h BKDG Rev. 3.14 Table 26 */
+ if (voltage & 0x4) {
+ /* 1.25V */
+ if (count > 1) {
+ if (highest_rank_count > 1) {
+ /* Limit to DDR3-1066 */
+ if (freq > 533) {
+ freq = 533;
+ printk(BIOS_DEBUG, "%s: More than 1 unbuffered DIMM on %dmV channel; limiting to DDR3-1066\n", __func__, voltage_index_to_mv(voltage));
+ }
+ } else {
+ /* Limit to DDR3-1333 */
+ if (freq > 666) {
+ freq = 666;
+ printk(BIOS_DEBUG, "%s: More than 1 unbuffered DIMM on %dmV channel; limiting to DDR3-1333\n", __func__, voltage_index_to_mv(voltage));
+ }
+ }
+ } else {
+ /* Limit to DDR3-1333 */
+ if (freq > 666) {
+ freq = 666;
+ printk(BIOS_DEBUG, "%s: 1 unbuffered DIMM on %dmV channel; limiting to DDR3-1333\n", __func__, voltage_index_to_mv(voltage));
+ }
+ }
+ } else if (voltage & 0x2) {
+ /* 1.35V */
+ if (MaxDimmsInstallable > 1) {
+ /* Limit to DDR3-1333 */
+ if (freq > 666) {
+ freq = 666;
+ printk(BIOS_DEBUG, "%s: More than 1 unbuffered DIMM on %dmV channel; limiting to DDR3-1333\n", __func__, voltage_index_to_mv(voltage));
+ }
+ } else {
+ /* Limit to DDR3-1600 */
+ if (freq > 800) {
+ freq = 800;
+ printk(BIOS_DEBUG, "%s: 1 unbuffered DIMM on %dmV channel; limiting to DDR3-1600\n", __func__, voltage_index_to_mv(voltage));
+ }
+ }
+ } else if (voltage & 0x1) {
+ if (MaxDimmsInstallable == 1) {
+ if (count > 1) {
+ /* Limit to DDR3-1600 */
+ if (freq > 800) {
+ freq = 800;
+ printk(BIOS_DEBUG, "%s: More than 1 unbuffered DIMM on %dmV channel; limiting to DDR3-1600\n", __func__, voltage_index_to_mv(voltage));
+ }
+ } else {
+ /* Limit to DDR3-1866 */
+ if (freq > 933) {
+ freq = 933;
+ printk(BIOS_DEBUG, "%s: 1 unbuffered DIMM on %dmV channel; limiting to DDR3-1866\n", __func__, voltage_index_to_mv(voltage));
+ }
+ }
+ } else {
+ if (count > 1) {
+ if (highest_rank_count > 1) {
+ /* Limit to DDR3-1333 */
+ if (freq > 666) {
+ freq = 666;
+ printk(BIOS_DEBUG, "%s: More than 1 unbuffered DIMM on %dmV channel; limiting to DDR3-1333\n", __func__, voltage_index_to_mv(voltage));
+ }
+ } else {
+ /* Limit to DDR3-1600 */
+ if (freq > 800) {
+ freq = 800;
+ printk(BIOS_DEBUG, "%s: More than 1 unbuffered DIMM on %dmV channel; limiting to DDR3-1600\n", __func__, voltage_index_to_mv(voltage));
+ }
+ }
+ } else {
+ /* Limit to DDR3-1600 */
+ if (freq > 800) {
+ freq = 800;
+ printk(BIOS_DEBUG, "%s: 1 unbuffered DIMM on %dmV channel; limiting to DDR3-1600\n", __func__, voltage_index_to_mv(voltage));
+ }
+ }
+ }
}
- } else if (count == 2) {
- /* Limit to DDR3-1066 */
- if (freq > 533) {
- freq = 533;
- print_tf(__func__, ": 2 registered DIMMs on channel; limiting to DDR3-1066\n");
+ }
+ } else {
+ if (IS_ENABLED(CONFIG_DIMM_REGISTERED) && registered) {
+ /* K10 BKDG Rev. 3.62 Table 34 */
+ if (count > 2) {
+ /* Limit to DDR3-800 */
+ if (freq > 400) {
+ freq = 400;
+ printk(BIOS_DEBUG, "%s: More than 2 registered DIMMs on %dmV channel; limiting to DDR3-800\n", __func__, voltage_index_to_mv(voltage));
+ }
+ } else if (count == 2) {
+ /* Limit to DDR3-1066 */
+ if (freq > 533) {
+ freq = 533;
+ printk(BIOS_DEBUG, "%s: 2 registered DIMMs on %dmV channel; limiting to DDR3-1066\n", __func__, voltage_index_to_mv(voltage));
+ }
+ } else {
+ /* Limit to DDR3-1333 */
+ if (freq > 666) {
+ freq = 666;
+ printk(BIOS_DEBUG, "%s: 1 registered DIMM on %dmV channel; limiting to DDR3-1333\n", __func__, voltage_index_to_mv(voltage));
+ }
}
} else {
+ /* K10 BKDG Rev. 3.62 Table 33 */
/* Limit to DDR3-1333 */
if (freq > 666) {
freq = 666;
- print_tf(__func__, ": 1 registered DIMM on channel; limiting to DDR3-1333\n");
+ printk(BIOS_DEBUG, "%s: unbuffered DIMMs on %dmV channel; limiting to DDR3-1333\n", __func__, voltage_index_to_mv(voltage));
}
}
- } else {
- /* K10 BKDG Rev. 3.62 Table 33 */
- /* Limit to DDR3-1333 */
- if (freq > 666) {
- freq = 666;
- print_tf(__func__, ": unbuffered DIMMs on channel; limiting to DDR3-1333\n");
- }
}
}
@@ -219,11 +475,13 @@ void mctGet_DIMMAddr(struct DCTStatStruc *pDCTstat, u32 node)
}
+#if IS_ENABLED(CONFIG_SET_FIDVID)
static u8 mctGetProcessorPackageType(void) {
/* FIXME: I guess this belongs wherever mctGetLogicalCPUID ends up ? */
- u32 BrandId = cpuid_ebx(0x80000001);
- return (u8)((BrandId >> 28) & 0x0F);
+ u32 BrandId = cpuid_ebx(0x80000001);
+ return (u8)((BrandId >> 28) & 0x0F);
}
+#endif
static void raminit_amdmct(struct sys_info *sysinfo)
{
diff --git a/src/northbridge/amd/amdht/h3ncmn.c b/src/northbridge/amd/amdht/h3ncmn.c
index 95246e857e..ac7d393b24 100644
--- a/src/northbridge/amd/amdht/h3ncmn.c
+++ b/src/northbridge/amd/amdht/h3ncmn.c
@@ -39,6 +39,7 @@
#define CPU_HTNB_FUNC_04 4
#define CPU_ADDR_FUNC_01 1
#define CPU_NB_FUNC_03 3
+#define CPU_NB_FUNC_05 5
/* Function 0 registers */
#define REG_ROUTE0_0X40 0x40
@@ -66,6 +67,7 @@
#define REG_NB_CPUID_3XFC 0xFC
#define REG_NB_LINK_XCS_TOKEN0_3X148 0x148
#define REG_NB_DOWNCORE_3X190 0x190
+#define REG_NB_CAPABILITY_5X84 0x84
/* Function 4 registers */
@@ -551,9 +553,10 @@ static u8 fam10GetNumCoresOnNode(u8 node, cNorthBridge *nb)
15, 12, &temp);
/* bits[15,13,12] specify the cores */
- /* Support Downcoring */
temp = ((temp & 8) >> 1) + (temp & 3);
cores = temp + 1;
+
+ /* Support Downcoring */
AmdPCIReadBits (MAKE_SBDFO(makePCISegmentFromNode(node),
makePCIBusFromNode(node),
makePCIDeviceFromNode(node),
@@ -572,6 +575,56 @@ static u8 fam10GetNumCoresOnNode(u8 node, cNorthBridge *nb)
/***************************************************************************//**
*
+ * static u8
+ * fam15GetNumCoresOnNode(u8 node, cNorthBridge *nb)
+ *
+ * Description:
+ * Return the number of cores (1 based count) on node.
+ *
+ * Parameters:
+ * @param[in] node = the node that will be examined
+ * @param[in] *nb = this northbridge
+ * @return = the number of cores
+ *
+ *
+ */
+static u8 fam15GetNumCoresOnNode(u8 node, cNorthBridge *nb)
+{
+ u32 temp, leveling, cores;
+ u8 i;
+
+ ASSERT((node < nb->maxNodes));
+ /* Read CmpCap [7:0] */
+ AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node),
+ makePCIBusFromNode(node),
+ makePCIDeviceFromNode(node),
+ CPU_NB_FUNC_05,
+ REG_NB_CAPABILITY_5X84),
+ 7, 0, &temp);
+
+ /* bits[7:0] specify the cores */
+ temp = temp & 0xff;
+ cores = temp + 1;
+
+ /* Support Downcoring */
+ AmdPCIReadBits (MAKE_SBDFO(makePCISegmentFromNode(node),
+ makePCIBusFromNode(node),
+ makePCIDeviceFromNode(node),
+ CPU_NB_FUNC_03,
+ REG_NB_DOWNCORE_3X190),
+ 31, 0, &leveling);
+ for (i=0; i<cores; i++)
+ {
+ if (leveling & ((u32) 1 << i))
+ {
+ temp--;
+ }
+ }
+ return (u8)(temp+1);
+}
+
+/***************************************************************************//**
+ *
* static void
* setTotalNodesAndCores(u8 node, u8 totalNodes, u8 totalCores, cNorthBridge *nb)
*
@@ -850,6 +903,69 @@ static BOOL fam10IsCapable(u8 node, sMainData *pDat, cNorthBridge *nb)
/***************************************************************************//**
*
+ * static BOOL
+ * fam15IsCapable(u8 node, sMainData *pDat, cNorthBridge *nb)
+ *
+ * Description:
+ * Get node capability and update the minimum supported system capability.
+ * Return whether the current configuration exceeds the capability.
+ *
+ * Parameters:
+ * @param[in] node = the node
+ * @param[in,out] *pDat = sysMpCap (updated) and NodesDiscovered
+ * @param[in] *nb = this northbridge
+ * @return true: system is capable of current config.
+ * false: system is not capable of current config.
+ *
+ * ---------------------------------------------------------------------------------------
+ */
+static BOOL fam15IsCapable(u8 node, sMainData *pDat, cNorthBridge *nb)
+{
+#ifndef HT_BUILD_NC_ONLY
+ u32 temp;
+ u8 maxNodes;
+
+ ASSERT(node < nb->maxNodes);
+
+ AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node),
+ makePCIBusFromNode(node),
+ makePCIDeviceFromNode(node),
+ CPU_NB_FUNC_03,
+ REG_NB_CAPABILITY_3XE8),
+ 18, 16, &temp);
+
+ if (temp != 0)
+ {
+ maxNodes = (1 << (~temp & 0x3)); /* That is, 1, 2, 4, or 8 */
+ }
+ else
+ {
+ /* Check if CPU package is dual node */
+ AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node),
+ makePCIBusFromNode(node),
+ makePCIDeviceFromNode(node),
+ CPU_NB_FUNC_03,
+ REG_NB_CAPABILITY_3XE8),
+ 29, 29, &temp);
+ if (temp)
+ maxNodes = 4;
+ else
+ maxNodes = 8;
+ }
+
+ if (pDat->sysMpCap > maxNodes)
+ {
+ pDat->sysMpCap = maxNodes;
+ }
+ /* Note since sysMpCap is one based and NodesDiscovered is zero based, equal is false */
+ return (pDat->sysMpCap > pDat->NodesDiscovered);
+#else
+ return 1;
+#endif
+}
+
+/***************************************************************************//**
+ *
* static void
* fam0fStopLink(u8 currentNode, u8 currentLink, cNorthBridge *nb)
*
@@ -2064,6 +2180,49 @@ void newNorthBridge(u8 node, cNorthBridge *nb)
u32 match;
u32 extFam, baseFam, model;
+ cNorthBridge fam15 =
+ {
+#ifdef HT_BUILD_NC_ONLY
+ 8,
+ 1,
+ 12,
+#else
+ 8,
+ 8,
+ 64,
+#endif /* HT_BUILD_NC_ONLY*/
+ writeRoutingTable,
+ writeNodeID,
+ readDefLnk,
+ enableRoutingTables,
+ verifyLinkIsCoherent,
+ readTrueLinkFailStatus,
+ readToken,
+ writeToken,
+ fam15GetNumCoresOnNode,
+ setTotalNodesAndCores,
+ limitNodes,
+ writeFullRoutingTable,
+ isCompatible,
+ fam15IsCapable,
+ (void (*)(u8, u8, cNorthBridge*))commonVoid,
+ (BOOL (*)(u8, u8, sMainData*, cNorthBridge*))commonReturnFalse,
+ readSbLink,
+ verifyLinkIsNonCoherent,
+ ht3SetCFGAddrMap,
+ convertBitsToWidth,
+ convertWidthToBits,
+ fam10NorthBridgeFreqMask,
+ gatherLinkData,
+ setLinkData,
+ ht3WriteTrafficDistribution,
+ fam10BufferOptimizations,
+ 0x00000001,
+ 0x00000200,
+ 18,
+ 0x00000f06
+ };
+
cNorthBridge fam10 =
{
#ifdef HT_BUILD_NC_ONLY
@@ -2171,8 +2330,14 @@ void newNorthBridge(u8 node, cNorthBridge *nb)
7, 4, &model);
match = (u32)((baseFam << 8) | extFam);
- /* Test each in turn looking for a match. Init the struct if found */
- if (match == fam10.compatibleKey)
+ /* Test each in turn looking for a match.
+ * Initialize the struct if found.
+ */
+ if (match == fam15.compatibleKey)
+ {
+ Amdmemcpy((void *)nb, (const void *)&fam15, (u32) sizeof(cNorthBridge));
+ }
+ else if (match == fam10.compatibleKey)
{
Amdmemcpy((void *)nb, (const void *)&fam10, (u32) sizeof(cNorthBridge));
}
diff --git a/src/northbridge/amd/amdht/ht_wrapper.c b/src/northbridge/amd/amdht/ht_wrapper.c
index 3bc236ed49..1f38b0c032 100644
--- a/src/northbridge/amd/amdht/ht_wrapper.c
+++ b/src/northbridge/amd/amdht/ht_wrapper.c
@@ -170,16 +170,22 @@ void amd_ht_fixup(struct sys_info *sysinfo) {
printk(BIOS_DEBUG, "amd_ht_fixup()\n");
if (IS_ENABLED(CONFIG_CPU_AMD_MODEL_10XXX)) {
uint8_t rev_gte_d = 0;
+ uint8_t fam15h = 0;
uint8_t dual_node = 0;
uint32_t f3xe8;
uint32_t family;
uint32_t model;
family = model = cpuid_eax(0x80000001);
- model = ((model & 0xf0000) >> 16) | ((model & 0xf0) >> 4);
+ model = ((model & 0xf0000) >> 12) | ((model & 0xf0) >> 4);
+ family = ((family & 0xf00000) >> 16) | ((family & 0xf00) >> 8);
- if (model >= 0x8)
- /* Revision D or later */
+ if (family >= 0x6f)
+ /* Family 15h or later */
+ fam15h = 1;
+
+ if ((model >= 0x8) || fam15h)
+ /* Family 10h Revision D or later */
rev_gte_d = 1;
if (rev_gte_d) {
@@ -191,7 +197,8 @@ void amd_ht_fixup(struct sys_info *sysinfo) {
if (dual_node) {
/* Each G34 processor contains a defective HT link.
- * See the BKDG Rev 3.62 section 2.7.1.5 for details.
+ * See the Family 10h BKDG Rev 3.62 section 2.7.1.5 for details
+ * For Family 15h see the BKDG Rev. 3.14 section 2.12.1.5 for details.
*/
uint8_t node;
uint8_t node_count = get_nodes();
@@ -201,46 +208,46 @@ void amd_ht_fixup(struct sys_info *sysinfo) {
uint8_t internal_node_number = ((f3xe8 & 0xc0000000) >> 30);
printk(BIOS_DEBUG, "amd_ht_fixup(): node %d (internal node ID %d): disabling defective HT link\n", node, internal_node_number);
if (internal_node_number == 0) {
- uint8_t package_link_3_connected = pci_read_config32(NODE_PCI(node, 0), 0xd8) & 0x1;
+ uint8_t package_link_3_connected = pci_read_config32(NODE_PCI(node, 0), (fam15h)?0x98:0xd8) & 0x1;
if (package_link_3_connected) {
/* Set WidthIn and WidthOut to 0 */
- dword = pci_read_config32(NODE_PCI(node, 0), 0xc4);
+ dword = pci_read_config32(NODE_PCI(node, 0), (fam15h)?0x84:0xc4);
dword &= ~0x77000000;
- pci_write_config32(NODE_PCI(node, 0), 0xc4, dword);
+ pci_write_config32(NODE_PCI(node, 0), (fam15h)?0x84:0xc4, dword);
/* Set Ganged to 1 */
- dword = pci_read_config32(NODE_PCI(node, 0), 0x178);
+ dword = pci_read_config32(NODE_PCI(node, 0), (fam15h)?0x170:0x178);
dword |= 0x00000001;
- pci_write_config32(NODE_PCI(node, 0), 0x178, dword);
+ pci_write_config32(NODE_PCI(node, 0), (fam15h)?0x170:0x178, dword);
} else {
/* Set ConnDly to 1 */
dword = pci_read_config32(NODE_PCI(node, 0), 0x16c);
dword |= 0x00000100;
pci_write_config32(NODE_PCI(node, 0), 0x16c, dword);
/* Set TransOff and EndOfChain to 1 */
- dword = pci_read_config32(NODE_PCI(node, 4), 0xc4);
+ dword = pci_read_config32(NODE_PCI(node, 4), (fam15h)?0x84:0xc4);
dword |= 0x000000c0;
- pci_write_config32(NODE_PCI(node, 4), 0xc4, dword);
+ pci_write_config32(NODE_PCI(node, 4), (fam15h)?0x84:0xc4, dword);
}
} else if (internal_node_number == 1) {
- uint8_t package_link_3_connected = pci_read_config32(NODE_PCI(node, 0), 0xb8) & 0x1;
+ uint8_t package_link_3_connected = pci_read_config32(NODE_PCI(node, 0), (fam15h)?0xf8:0xb8) & 0x1;
if (package_link_3_connected) {
/* Set WidthIn and WidthOut to 0 */
- dword = pci_read_config32(NODE_PCI(node, 0), 0xa4);
+ dword = pci_read_config32(NODE_PCI(node, 0), (fam15h)?0xe4:0xa4);
dword &= ~0x77000000;
- pci_write_config32(NODE_PCI(node, 0), 0xa4, dword);
+ pci_write_config32(NODE_PCI(node, 0), (fam15h)?0xe4:0xa4, dword);
/* Set Ganged to 1 */
- dword = pci_read_config32(NODE_PCI(node, 0), 0x174);
+ dword = pci_read_config32(NODE_PCI(node, 0), (fam15h)?0x18c:0x174);
dword |= 0x00000001;
- pci_write_config32(NODE_PCI(node, 0), 0x174, dword);
+ pci_write_config32(NODE_PCI(node, 0), (fam15h)?0x18c:0x174, dword);
} else {
/* Set ConnDly to 1 */
dword = pci_read_config32(NODE_PCI(node, 0), 0x16c);
dword |= 0x00000100;
pci_write_config32(NODE_PCI(node, 0), 0x16c, dword);
/* Set TransOff and EndOfChain to 1 */
- dword = pci_read_config32(NODE_PCI(node, 4), 0xa4);
+ dword = pci_read_config32(NODE_PCI(node, 4), (fam15h)?0xe4:0xa4);
dword |= 0x000000c0;
- pci_write_config32(NODE_PCI(node, 4), 0xa4, dword);
+ pci_write_config32(NODE_PCI(node, 4), (fam15h)?0xe4:0xa4, dword);
}
}
}
diff --git a/src/northbridge/amd/amdmct/amddefs.h b/src/northbridge/amd/amdmct/amddefs.h
index 8b235f7fe3..42ad32b1e2 100644
--- a/src/northbridge/amd/amdmct/amddefs.h
+++ b/src/northbridge/amd/amdmct/amddefs.h
@@ -16,33 +16,35 @@
/* FIXME: this file should be moved to include/cpu/amd/amddefs.h */
/* Public Revisions - USE THESE VERSIONS TO MAKE COMPARE WITH CPULOGICALID RETURN VALUE*/
-#define AMD_SAFEMODE 0x80000000 /* Unknown future revision - SAFE MODE */
-#define AMD_NPT_F0 0x00000001 /* F0 stepping */
-#define AMD_NPT_F1 0x00000002 /* F1 stepping */
-#define AMD_NPT_F2C 0x00000004
-#define AMD_NPT_F2D 0x00000008
-#define AMD_NPT_F2E 0x00000010 /* F2 stepping E */
-#define AMD_NPT_F2G 0x00000020 /* F2 stepping G */
-#define AMD_NPT_F2J 0x00000040
-#define AMD_NPT_F2K 0x00000080
-#define AMD_NPT_F3L 0x00000100 /* F3 Stepping */
-#define AMD_NPT_G0A 0x00000200 /* G0 stepping */
-#define AMD_NPT_G1B 0x00000400 /* G1 stepping */
-#define AMD_DR_A0A 0x00010000 /* Barcelona A0 */
-#define AMD_DR_A1B 0x00020000 /* Barcelona A1 */
-#define AMD_DR_A2 0x00040000 /* Barcelona A2 */
-#define AMD_DR_B0 0x00080000 /* Barcelona B0 */
-#define AMD_DR_B1 0x00100000 /* Barcelona B1 */
-#define AMD_DR_B2 0x00200000 /* Barcelona B2 */
-#define AMD_DR_BA 0x00400000 /* Barcelona BA */
-#define AMD_DR_B3 0x00800000 /* Barcelona B3 */
-#define AMD_RB_C2 0x01000000 /* Shanghai C2 */
-#define AMD_DA_C2 0x02000000 /* XXXX C2 */
-#define AMD_HY_D0 0x04000000 /* Istanbul D0 */
-#define AMD_RB_C3 0x08000000 /* ??? C3 */
-#define AMD_DA_C3 0x10000000 /* XXXX C3 */
-#define AMD_HY_D1 0x20000000 /* Istanbul D1 */
-#define AMD_PH_E0 0x40000000 /* Phenom II X4 X6 */
+#define AMD_SAFEMODE 0x8000000000000000 /* Unknown future revision - SAFE MODE */
+#define AMD_NPT_F0 0x0000000000000001 /* F0 stepping */
+#define AMD_NPT_F1 0x0000000000000002 /* F1 stepping */
+#define AMD_NPT_F2C 0x0000000000000004
+#define AMD_NPT_F2D 0x0000000000000008
+#define AMD_NPT_F2E 0x0000000000000010 /* F2 stepping E */
+#define AMD_NPT_F2G 0x0000000000000020 /* F2 stepping G */
+#define AMD_NPT_F2J 0x0000000000000040
+#define AMD_NPT_F2K 0x0000000000000080
+#define AMD_NPT_F3L 0x0000000000000100 /* F3 Stepping */
+#define AMD_NPT_G0A 0x0000000000000200 /* G0 stepping */
+#define AMD_NPT_G1B 0x0000000000000400 /* G1 stepping */
+#define AMD_DR_A0A 0x0000000000010000 /* Barcelona A0 */
+#define AMD_DR_A1B 0x0000000000020000 /* Barcelona A1 */
+#define AMD_DR_A2 0x0000000000040000 /* Barcelona A2 */
+#define AMD_DR_B0 0x0000000000080000 /* Barcelona B0 */
+#define AMD_DR_B1 0x0000000000100000 /* Barcelona B1 */
+#define AMD_DR_B2 0x0000000000200000 /* Barcelona B2 */
+#define AMD_DR_BA 0x0000000000400000 /* Barcelona BA */
+#define AMD_DR_B3 0x0000000000800000 /* Barcelona B3 */
+#define AMD_RB_C2 0x0000000001000000 /* Shanghai C2 */
+#define AMD_DA_C2 0x0000000002000000 /* XXXX C2 */
+#define AMD_HY_D0 0x0000000004000000 /* Istanbul D0 */
+#define AMD_RB_C3 0x0000000008000000 /* ??? C3 */
+#define AMD_DA_C3 0x0000000010000000 /* XXXX C3 */
+#define AMD_HY_D1 0x0000000020000000 /* Istanbul D1 */
+#define AMD_PH_E0 0x0000000040000000 /* Phenom II X4 X6 */
+#define AMD_OR_B2 0x0000000080000000 /* Interlagos */
+#define AMD_OR_C0 0x0000000100000000 /* Abu Dhabi */
/*
* Groups - Create as many as you wish, from the above public values
@@ -72,6 +74,7 @@
#define AMD_DRBH_Cx (AMD_DR_Cx | AMD_HY_D0 )
#define AMD_DRBA23_RBC2 (AMD_DR_BA | AMD_DR_B2 | AMD_DR_B3 | AMD_RB_C2 )
#define AMD_DR_DAC2_OR_C3 (AMD_DA_C2 | AMD_DA_C3 | AMD_RB_C3)
+#define AMD_FAM15_ALL (AMD_OR_B2 | AMD_OR_C0)
/*
* Public Platforms - USE THESE VERSIONS TO MAKE COMPARE WITH CPUPLATFORMTYPE RETURN VALUE
@@ -118,23 +121,34 @@
*/
#define CPUID_EXT_PM 0x80000007
#define CPUID_MODEL 1
-#define MCG_CAP 0x00000179
+#define MCG_CAP 0x00000179
#define MCG_CTL_P 8
-#define MC0_CTL 0x00000400
-#define MC0_STA MC0_CTL + 1
-#define FS_Base 0xC0000100
+#define MC0_CTL 0x00000400
+#define MC0_STA (MC0_CTL + 1)
+#define MC4_MISC0 0x00000413
+#define MC4_MISC1 0xC0000408
+#define MC4_MISC2 0xC0000409
+#define FS_Base 0xC0000100
#define SYSCFG 0xC0010010
#define HWCR 0xC0010015
#define NB_CFG 0xC001001F
#define FidVidStatus 0xC0010042
+#define MC1_CTL_MASK 0xC0010045
#define MC4_CTL_MASK 0xC0010048
#define OSVW_ID_Length 0xC0010140
#define OSVW_Status 0xC0010141
#define CPUIDFEATURES 0xC0011004
#define LS_CFG 0xC0011020
+#define IC_CFG 0xC0011021
#define DC_CFG 0xC0011022
#define BU_CFG 0xC0011023
-#define BU_CFG2 0xC001102A
+#define FP_CFG 0xC0011028
+#define DE_CFG 0xC0011029
+#define BU_CFG2 0xC001102A
+#define BU_CFG3 0xC001102B
+#define EX_CFG 0xC001102C
+#define LS_CFG2 0xC001102D
+#define IBS_OP_DATA3 0xC0011037
/*
* Processor package types
diff --git a/src/northbridge/amd/amdmct/mct/mct_d.c b/src/northbridge/amd/amdmct/mct/mct_d.c
index c9c74342d1..91d929a8bb 100644
--- a/src/northbridge/amd/amdmct/mct/mct_d.c
+++ b/src/northbridge/amd/amdmct/mct/mct_d.c
@@ -2185,6 +2185,7 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
pDCTstat->DimmManufacturerID[i] |= ((uint64_t)mctRead_SPD(smbaddr, SPD_MANID_START + k)) << (k * 8);
for (k = 0; k < SPD_PARTN_LENGTH; k++)
pDCTstat->DimmPartNumber[i][k] = mctRead_SPD(smbaddr, SPD_PARTN_START + k);
+ pDCTstat->DimmPartNumber[i][SPD_PARTN_LENGTH] = 0;
pDCTstat->DimmRevisionNumber[i] = 0;
for (k = 0; k < 2; k++)
pDCTstat->DimmRevisionNumber[i] |= ((uint16_t)mctRead_SPD(smbaddr, SPD_REVNO_START + k)) << (k * 8);
@@ -2202,8 +2203,7 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
if (byte & JED_REGADCMSK) {
RegDIMMPresent |= 1 << i;
pDCTstat->DimmRegistered[i] = 1;
- }
- else {
+ } else {
pDCTstat->DimmRegistered[i] = 0;
}
/* Check ECC capable */
diff --git a/src/northbridge/amd/amdmct/mct/mct_d.h b/src/northbridge/amd/amdmct/mct/mct_d.h
index 64697a875f..3845a87058 100644
--- a/src/northbridge/amd/amdmct/mct/mct_d.h
+++ b/src/northbridge/amd/amdmct/mct/mct_d.h
@@ -430,7 +430,7 @@ struct DCTStatStruc { /* A per Node structure*/
/* CH A byte lane 0 - 7 maximum filtered window passing DQS delay value*/
/* CH B byte lane 0 - 7 minimum filtered window passing DQS delay value*/
/* CH B byte lane 0 - 7 maximum filtered window passing DQS delay value*/
- u32 LogicalCPUID; /* The logical CPUID of the node*/
+ uint64_t LogicalCPUID; /* The logical CPUID of the node*/
u16 HostBiosSrvc1; /* Word sized general purpose field for use by host BIOS. Scratch space.*/
u32 HostBiosSrvc2; /* Dword sized general purpose field for use by host BIOS. Scratch space.*/
u16 DimmQRPresent; /* QuadRank DIMM present?*/
@@ -525,7 +525,7 @@ struct DCTStatStruc { /* A per Node structure*/
uint8_t DimmRegistered[MAX_DIMMS_SUPPORTED];
uint64_t DimmManufacturerID[MAX_DIMMS_SUPPORTED];
- char DimmPartNumber[MAX_DIMMS_SUPPORTED][SPD_PARTN_LENGTH];
+ char DimmPartNumber[MAX_DIMMS_SUPPORTED][SPD_PARTN_LENGTH+1];
uint16_t DimmRevisionNumber[MAX_DIMMS_SUPPORTED];
uint32_t DimmSerialNumber[MAX_DIMMS_SUPPORTED];
} __attribute__((packed));
@@ -594,17 +594,18 @@ struct DCTStatStruc { /* A per Node structure*/
266=266MHz (DDR533)
333=333MHz (DDR667)
400=400MHz (DDR800)*/
-#define NV_ECC_CAP 4 /* Bus ECC capable (1-bits)
+#define NV_MIN_MEMCLK 4 /* Minimum platform demonstrated Memclock (10-bits) */
+#define NV_ECC_CAP 5 /* Bus ECC capable (1-bits)
0=Platform not capable
1=Platform is capable*/
-#define NV_4RANKType 5 /* Quad Rank DIMM slot type (2-bits)
+#define NV_4RANKType 6 /* Quad Rank DIMM slot type (2-bits)
0=Normal
1=R4 (4-Rank Registered DIMMs in AMD server configuration)
2=S4 (Unbuffered SO-DIMMs)*/
-#define NV_BYPMAX 6 /* Value to set DcqBypassMax field (See Function 2, Offset 94h, [27:24] of BKDG for field definition).
+#define NV_BYPMAX 7 /* Value to set DcqBypassMax field (See Function 2, Offset 94h, [27:24] of BKDG for field definition).
4=4 times bypass (normal for non-UMA systems)
7=7 times bypass (normal for UMA systems)*/
-#define NV_RDWRQBYP 7 /* Value to set RdWrQByp field (See Function 2, Offset A0h, [3:2] of BKDG for field definition).
+#define NV_RDWRQBYP 8 /* Value to set RdWrQByp field (See Function 2, Offset A0h, [3:2] of BKDG for field definition).
2=8 times (normal for non-UMA systems)
3=16 times (normal for UMA systems)*/
@@ -667,8 +668,9 @@ struct DCTStatStruc { /* A per Node structure*/
#define NV_ECCRedir 54 /* Dram ECC Redirection enable*/
#define NV_DramBKScrub 55 /* Dram ECC Background Scrubber CTL*/
#define NV_L2BKScrub 56 /* L2 ECC Background Scrubber CTL*/
-#define NV_DCBKScrub 57 /* DCache ECC Background Scrubber CTL*/
-#define NV_CS_SpareCTL 58 /* Chip Select Spare Control bit 0:
+#define NV_L3BKScrub 57 /* L3 ECC Background Scrubber CTL*/
+#define NV_DCBKScrub 58 /* DCache ECC Background Scrubber CTL*/
+#define NV_CS_SpareCTL 59 /* Chip Select Spare Control bit 0:
0=disable Spare
1=enable Spare */
/* Chip Select Spare Control bit 1-4:
@@ -708,7 +710,7 @@ u8 mct_Get_Start_RcvrEnDly_1Pass(u8 Pass);
u8 mct_Average_RcvrEnDly_Pass(struct DCTStatStruc *pDCTstat, u8 RcvrEnDly, u8 RcvrEnDlyLimit, u8 Channel, u8 Receiver, u8 Pass);
void CPUMemTyping_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA);
void UMAMemTyping_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA);
-u32 mctGetLogicalCPUID(u32 Node);
+uint64_t mctGetLogicalCPUID(u32 Node);
u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA);
void TrainReceiverEn_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA, u8 Pass);
void mct_TrainDQSPos_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA);
diff --git a/src/northbridge/amd/amdmct/mct/mctpro_d.c b/src/northbridge/amd/amdmct/mct/mctpro_d.c
index bdfff046f4..a6d6bad164 100644
--- a/src/northbridge/amd/amdmct/mct/mctpro_d.c
+++ b/src/northbridge/amd/amdmct/mct/mctpro_d.c
@@ -2,6 +2,7 @@
* This file is part of the coreboot project.
*
* Copyright (C) 2007 Advanced Micro Devices, Inc.
+ * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering
*
* 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
@@ -19,7 +20,7 @@ void EarlySampleSupport_D(void)
u32 procOdtWorkaround(struct DCTStatStruc *pDCTstat, u32 dct, u32 val)
{
- u32 tmp;
+ uint64_t tmp;
tmp = pDCTstat->LogicalCPUID;
if ((tmp == AMD_DR_A0A) || (tmp == AMD_DR_A1B) || (tmp == AMD_DR_A2)) {
val &= 0x0FFFFFFF;
@@ -38,7 +39,7 @@ u32 OtherTiming_A_D(struct DCTStatStruc *pDCTstat, u32 val)
* ( F2x[1, 0]8C[1:0] > 00b). Silicon Status: Fixed in Rev B
* FIXME: check if this is still required.
*/
- u32 tmp;
+ uint64_t tmp;
tmp = pDCTstat->LogicalCPUID;
if ((tmp == AMD_DR_A0A) || (tmp == AMD_DR_A1B) || (tmp == AMD_DR_A2)) {
if(!(val & (3<<12) ))
@@ -50,7 +51,7 @@ u32 OtherTiming_A_D(struct DCTStatStruc *pDCTstat, u32 val)
void mct_ForceAutoPrecharge_D(struct DCTStatStruc *pDCTstat, u32 dct)
{
- u32 tmp;
+ uint64_t tmp;
u32 reg;
u32 reg_off;
u32 dev;
@@ -92,7 +93,7 @@ void mct_EndDQSTraining_D(struct MCTStatStruc *pMCTstat,
* FIXME: check this.
*/
- u32 tmp;
+ uint64_t tmp;
u32 dev;
u32 reg;
u32 val;
@@ -139,10 +140,9 @@ void mct_BeforeDQSTrain_Samp_D(struct MCTStatStruc *pMCTstat,
u32 index;
u32 reg;
u32 val;
- u32 tmp;
+ uint64_t tmp;
u32 Channel;
-
tmp = pDCTstat->LogicalCPUID;
if ((tmp == AMD_DR_A0A) || (tmp == AMD_DR_A1B) || (tmp == AMD_DR_A2)) {
@@ -202,7 +202,7 @@ u32 Modify_D3CMP(struct DCTStatStruc *pDCTstat, u32 dct, u32 value)
u32 index_reg;
u32 index;
u32 val;
- u32 tmp;
+ uint64_t tmp;
tmp = pDCTstat->LogicalCPUID;
if ((tmp == AMD_DR_A0A) || (tmp == AMD_DR_A1B) || (tmp == AMD_DR_A2)) {
@@ -233,7 +233,7 @@ void SyncSetting(struct DCTStatStruc *pDCTstat)
* Silicon Status: Fix TBD
*/
- u32 tmp;
+ uint64_t tmp;
tmp = pDCTstat->LogicalCPUID;
if ((tmp == AMD_DR_A0A) || (tmp == AMD_DR_A1B) || (tmp == AMD_DR_A2)) {
pDCTstat->CH_ODC_CTL[1] = pDCTstat->CH_ODC_CTL[0];
@@ -274,7 +274,7 @@ u32 CheckNBCOFAutoPrechg(struct DCTStatStruc *pDCTstat, u32 dct)
void mct_BeforeDramInit_D(struct DCTStatStruc *pDCTstat, u32 dct)
{
- u32 tmp;
+ uint64_t tmp;
u32 Speed;
u32 ch, ch_start, ch_end;
u32 index_reg;
@@ -282,7 +282,6 @@ void mct_BeforeDramInit_D(struct DCTStatStruc *pDCTstat, u32 dct)
u32 dev;
u32 val;
-
tmp = pDCTstat->LogicalCPUID;
if ((tmp == AMD_DR_A0A) || (tmp == AMD_DR_A1B) || (tmp == AMD_DR_A2)) {
Speed = pDCTstat->Speed;
@@ -327,7 +326,7 @@ static u8 mct_checkFenceHoleAdjust_D(struct MCTStatStruc *pMCTstat,
u8 ChipSel, u8 *result)
{
u8 ByteLane;
- u32 tmp;
+ uint64_t tmp;
tmp = pDCTstat->LogicalCPUID;
if ((tmp == AMD_DR_A0A) || (tmp == AMD_DR_A1B) || (tmp == AMD_DR_A2)) {
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
index ca68900758..80a85ff604 100644
--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
@@ -71,6 +71,8 @@ static void StitchMemory_D(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat, u8 dct);
static u16 Get_Fk_D(u8 k);
static u8 Get_DIMMAddress_D(struct DCTStatStruc *pDCTstat, u8 i);
+static void mct_preInitDCT(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat);
static void mct_initDCT(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat);
static void mct_DramInit(struct MCTStatStruc *pMCTstat,
@@ -101,11 +103,11 @@ static void Get_TrwtTO(struct MCTStatStruc *pMCTstat,
static void Get_TrwtWB(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat);
static void Get_DqsRcvEnGross_Diff(struct DCTStatStruc *pDCTstat,
- u32 dev, u32 index_reg);
+ u32 dev, uint8_t dct, u32 index_reg);
static void Get_WrDatGross_Diff(struct DCTStatStruc *pDCTstat, u8 dct,
u32 dev, u32 index_reg);
static u16 Get_DqsRcvEnGross_MaxMin(struct DCTStatStruc *pDCTstat,
- u32 dev, u32 index_reg, u32 index);
+ u32 dev, uint8_t dct, u32 index_reg, u32 index);
static void mct_FinalMCT_D(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat);
static u16 Get_WrDatGross_MaxMin(struct DCTStatStruc *pDCTstat, u8 dct,
@@ -124,6 +126,8 @@ static void SetCKETriState(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat, u8 dct);
static void SetODTTriState(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat, u8 dct);
+static void InitDDRPhy(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct);
static void InitPhyCompensation(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat, u8 dct);
static u32 mct_NodePresent_D(void);
@@ -134,7 +138,9 @@ static void mct_ResetDataStruct_D(struct MCTStatStruc *pMCTstat,
static void mct_EarlyArbEn_D(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat, u8 dct);
static void mct_BeforeDramInit_Prod_D(struct MCTStatStruc *pMCTstat,
- struct DCTStatStruc *pDCTstat);
+ struct DCTStatStruc *pDCTstat, u8 dct);
+static void mct_ProgramODT_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct);
void mct_ClrClToNB_D(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat);
static u8 CheckNBCOFEarlyArbEn(struct MCTStatStruc *pMCTstat,
@@ -154,6 +160,10 @@ static u32 mct_DisDllShutdownSR(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat, u32 DramConfigLo, u8 dct);
static void mct_EnDllShutdownSR(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat, u8 dct);
+static void ChangeMemClk(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat);
+void SetTargetFreq(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat);
static u32 mct_MR1Odt_RDimm(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat, u8 dct, u32 MrsChipSel);
@@ -161,7 +171,8 @@ static u32 mct_DramTermDyn_RDimm(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat, u8 dimm);
static u32 mct_SetDramConfigMisc2(struct DCTStatStruc *pDCTstat, u8 dct, u32 misc2);
static void mct_BeforeDQSTrainSamp(struct DCTStatStruc *pDCTstat);
-static void mct_WriteLevelization_HW(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA);
+static void mct_WriteLevelization_HW(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstatA, uint8_t Pass);
static u8 Get_Latency_Diff(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat, u8 dct);
static void SyncSetting(struct DCTStatStruc *pDCTstat);
@@ -169,6 +180,12 @@ static u8 crcCheck(u8 smbaddr);
static void mct_ExtMCTConfig_Bx(struct DCTStatStruc *pDCTstat);
static void mct_ExtMCTConfig_Cx(struct DCTStatStruc *pDCTstat);
+static void read_dqs_receiver_enable_control_registers(uint16_t* current_total_delay,
+ uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t index_reg);
+
+static void read_dqs_write_timing_control_registers(uint16_t* current_total_delay,
+ uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t index_reg);
+
/*See mctAutoInitMCT header for index relationships to CL and T*/
static const u16 Table_F_k[] = {00,200,266,333,400,533 };
static const u8 Tab_BankAddr[] = {0x3F,0x01,0x09,0x3F,0x3F,0x11,0x0A,0x19,0x12,0x1A,0x21,0x22,0x23};
@@ -229,6 +246,936 @@ static const u8 Table_Comp_Rise_Slew_15x[] = {7, 7, 3, 2, 0xFF};
static const u8 Table_Comp_Fall_Slew_20x[] = {7, 5, 3, 2, 0xFF};
static const u8 Table_Comp_Fall_Slew_15x[] = {7, 7, 5, 3, 0xFF};
+static uint8_t dct_ddr_voltage_index(struct DCTStatStruc *pDCTstat, uint8_t dct)
+{
+ uint8_t dimm;
+ uint8_t ddr_voltage_index = 0;
+
+ /* Find current DDR supply voltage for this DCT */
+ for (dimm = 0; dimm < MAX_DIMMS_SUPPORTED; dimm++) {
+ if (pDCTstat->DIMMValidDCT[dct] & (1 << dimm))
+ ddr_voltage_index |= pDCTstat->DimmConfiguredVoltage[dimm];
+ }
+ if (ddr_voltage_index > 0x7) {
+ printk(BIOS_DEBUG, "%s: Insufficient DDR supply voltage indicated! Configuring processor for 1.25V operation, but this attempt may fail...\n", __func__);
+ ddr_voltage_index = 0x4;
+ }
+ if (ddr_voltage_index == 0x0) {
+ printk(BIOS_DEBUG, "%s: No DDR supply voltage indicated! Configuring processor for 1.5V operation, but this attempt may fail...\n", __func__);
+ ddr_voltage_index = 0x1;
+ }
+
+ return ddr_voltage_index;
+}
+
+static uint16_t fam15h_mhz_to_memclk_config(uint16_t freq)
+{
+ uint16_t fam15h_freq_tab[] = {0, 0, 0, 0, 333, 0, 400, 0, 0, 0, 533, 0, 0, 0, 667, 0, 0, 0, 800, 0, 0, 0, 933};
+ uint16_t iter;
+
+ /* Compute the index value for the given frequency */
+ for (iter = 0; iter <= 0x16; iter++) {
+ if (fam15h_freq_tab[iter] == freq)
+ break;
+ }
+ if (fam15h_freq_tab[iter] == freq)
+ freq = iter;
+ if (freq == 0)
+ freq = 0x4;
+
+ return freq;
+}
+
+static uint16_t fam10h_mhz_to_memclk_config(uint16_t freq)
+{
+ uint16_t fam10h_freq_tab[] = {0, 0, 0, 400, 533, 667, 800};
+ uint16_t iter;
+
+ /* Compute the index value for the given frequency */
+ for (iter = 0; iter <= 0x6; iter++) {
+ if (fam10h_freq_tab[iter] == freq)
+ break;
+ }
+ if (fam10h_freq_tab[iter] == freq)
+ freq = iter;
+ if (freq == 0)
+ freq = 0x3;
+
+ return freq;
+}
+
+static uint16_t mhz_to_memclk_config(uint16_t freq)
+{
+ if (is_fam15h())
+ return fam15h_mhz_to_memclk_config(freq);
+ else
+ return fam10h_mhz_to_memclk_config(freq) + 1;
+}
+
+static uint32_t fam15h_phy_predriver_calibration_code(struct DCTStatStruc *pDCTstat, uint8_t dct, uint8_t drive_strength)
+{
+ uint8_t lrdimm = 0;
+ uint8_t package_type;
+ uint8_t ddr_voltage_index;
+ uint32_t calibration_code = 0;
+ uint16_t MemClkFreq = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 0x1f;
+
+ ddr_voltage_index = dct_ddr_voltage_index(pDCTstat, dct);
+ package_type = mctGet_NVbits(NV_PACK_TYPE);
+
+ if (!lrdimm) {
+ /* Not an LRDIMM */
+ if ((package_type == PT_M2) || (package_type == PT_GR)) {
+ /* Socket AM3 or G34 */
+ if (ddr_voltage_index & 0x4) {
+ /* 1.25V */
+ /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 43 */
+ if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) {
+ /* DDR3-667 - DDR3-800 */
+ if (drive_strength == 0x0)
+ calibration_code = 0xfff;
+ else if (drive_strength == 0x1)
+ calibration_code = 0xb6d;
+ else if (drive_strength == 0x2)
+ calibration_code = 0x924;
+ else if (drive_strength == 0x3)
+ calibration_code = 0x6db;
+ } else if ((MemClkFreq == 0xa) || (MemClkFreq == 0xe)) {
+ /* DDR3-1066 - DDR3-1333 */
+ if (drive_strength == 0x0)
+ calibration_code = 0xfff;
+ else if (drive_strength == 0x1)
+ calibration_code = 0xfff;
+ else if (drive_strength == 0x2)
+ calibration_code = 0xdb6;
+ else if (drive_strength == 0x3)
+ calibration_code = 0x924;
+ } else if ((MemClkFreq == 0x12) || (MemClkFreq == 0x16)) {
+ /* DDR3-1600 - DDR3-1866 */
+ if (drive_strength == 0x0)
+ calibration_code = 0xfff;
+ else if (drive_strength == 0x1)
+ calibration_code = 0xfff;
+ else if (drive_strength == 0x2)
+ calibration_code = 0xfff;
+ else if (drive_strength == 0x3)
+ calibration_code = 0xfff;
+ }
+ }
+ else if (ddr_voltage_index & 0x2) {
+ /* 1.35V */
+ /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 42 */
+ if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) {
+ /* DDR3-667 - DDR3-800 */
+ if (drive_strength == 0x0)
+ calibration_code = 0xfff;
+ else if (drive_strength == 0x1)
+ calibration_code = 0x924;
+ else if (drive_strength == 0x2)
+ calibration_code = 0x6db;
+ else if (drive_strength == 0x3)
+ calibration_code = 0x492;
+ } else if ((MemClkFreq == 0xa) || (MemClkFreq == 0xe)) {
+ /* DDR3-1066 - DDR3-1333 */
+ if (drive_strength == 0x0)
+ calibration_code = 0xfff;
+ else if (drive_strength == 0x1)
+ calibration_code = 0xdb6;
+ else if (drive_strength == 0x2)
+ calibration_code = 0xbd6;
+ else if (drive_strength == 0x3)
+ calibration_code = 0x6db;
+ } else if ((MemClkFreq == 0x12) || (MemClkFreq == 0x16)) {
+ /* DDR3-1600 - DDR3-1866 */
+ if (drive_strength == 0x0)
+ calibration_code = 0xfff;
+ else if (drive_strength == 0x1)
+ calibration_code = 0xfff;
+ else if (drive_strength == 0x2)
+ calibration_code = 0xfff;
+ else if (drive_strength == 0x3)
+ calibration_code = 0xdb6;
+ }
+ }
+ else if (ddr_voltage_index & 0x1) {
+ /* 1.5V */
+ /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 41 */
+ if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) {
+ /* DDR3-667 - DDR3-800 */
+ if (drive_strength == 0x0)
+ calibration_code = 0xb6d;
+ else if (drive_strength == 0x1)
+ calibration_code = 0x6db;
+ else if (drive_strength == 0x2)
+ calibration_code = 0x492;
+ else if (drive_strength == 0x3)
+ calibration_code = 0x492;
+ } else if ((MemClkFreq == 0xa) || (MemClkFreq == 0xe)) {
+ /* DDR3-1066 - DDR3-1333 */
+ if (drive_strength == 0x0)
+ calibration_code = 0xfff;
+ else if (drive_strength == 0x1)
+ calibration_code = 0x924;
+ else if (drive_strength == 0x2)
+ calibration_code = 0x6db;
+ else if (drive_strength == 0x3)
+ calibration_code = 0x6db;
+ } else if ((MemClkFreq == 0x12) || (MemClkFreq == 0x16)) {
+ /* DDR3-1600 - DDR3-1866 */
+ if (drive_strength == 0x0)
+ calibration_code = 0xfff;
+ else if (drive_strength == 0x1)
+ calibration_code = 0xfff;
+ else if (drive_strength == 0x2)
+ calibration_code = 0xfff;
+ else if (drive_strength == 0x3)
+ calibration_code = 0xb6d;
+ }
+ }
+ }
+ else if (package_type == PT_C3) {
+ /* Socket C32 */
+ if (ddr_voltage_index & 0x4) {
+ /* 1.25V */
+ /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 46 */
+ if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) {
+ /* DDR3-667 - DDR3-800 */
+ if (drive_strength == 0x0)
+ calibration_code = 0xfff;
+ else if (drive_strength == 0x1)
+ calibration_code = 0xb6d;
+ else if (drive_strength == 0x2)
+ calibration_code = 0x924;
+ else if (drive_strength == 0x3)
+ calibration_code = 0x6db;
+ } else if (MemClkFreq == 0xa) {
+ /* DDR3-1066 */
+ if (drive_strength == 0x0)
+ calibration_code = 0xfff;
+ else if (drive_strength == 0x1)
+ calibration_code = 0xfff;
+ else if (drive_strength == 0x2)
+ calibration_code = 0xdb6;
+ else if (drive_strength == 0x3)
+ calibration_code = 0x924;
+ } else if (MemClkFreq == 0xe) {
+ /* DDR3-1333 */
+ if (drive_strength == 0x0)
+ calibration_code = 0xb6d;
+ else if (drive_strength == 0x1)
+ calibration_code = 0x6db;
+ else if (drive_strength == 0x2)
+ calibration_code = 0x492;
+ else if (drive_strength == 0x3)
+ calibration_code = 0x492;
+ } else if ((MemClkFreq == 0x12) || (MemClkFreq == 0x16)) {
+ /* DDR3-1600 - DDR3-1866 */
+ if (drive_strength == 0x0)
+ calibration_code = 0xfff;
+ else if (drive_strength == 0x1)
+ calibration_code = 0xfff;
+ else if (drive_strength == 0x2)
+ calibration_code = 0xfff;
+ else if (drive_strength == 0x3)
+ calibration_code = 0xfff;
+ }
+ }
+ else if (ddr_voltage_index & 0x2) {
+ /* 1.35V */
+ /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 45 */
+ if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) {
+ /* DDR3-667 - DDR3-800 */
+ if (drive_strength == 0x0)
+ calibration_code = 0xfff;
+ else if (drive_strength == 0x1)
+ calibration_code = 0x924;
+ else if (drive_strength == 0x2)
+ calibration_code = 0x6db;
+ else if (drive_strength == 0x3)
+ calibration_code = 0x492;
+ } else if (MemClkFreq == 0xa) {
+ /* DDR3-1066 */
+ if (drive_strength == 0x0)
+ calibration_code = 0xfff;
+ else if (drive_strength == 0x1)
+ calibration_code = 0xdb6;
+ else if (drive_strength == 0x2)
+ calibration_code = 0xb6d;
+ else if (drive_strength == 0x3)
+ calibration_code = 0x6db;
+ } else if (MemClkFreq == 0xe) {
+ /* DDR3-1333 */
+ if (drive_strength == 0x0)
+ calibration_code = 0xfff;
+ else if (drive_strength == 0x1)
+ calibration_code = 0x924;
+ else if (drive_strength == 0x2)
+ calibration_code = 0x6db;
+ else if (drive_strength == 0x3)
+ calibration_code = 0x492;
+ } else if ((MemClkFreq == 0x12) || (MemClkFreq == 0x16)) {
+ /* DDR3-1600 - DDR3-1866 */
+ if (drive_strength == 0x0)
+ calibration_code = 0xfff;
+ else if (drive_strength == 0x1)
+ calibration_code = 0xfff;
+ else if (drive_strength == 0x2)
+ calibration_code = 0xfff;
+ else if (drive_strength == 0x3)
+ calibration_code = 0xdb6;
+ }
+ }
+ else if (ddr_voltage_index & 0x1) {
+ /* 1.5V */
+ /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 44 */
+ if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) {
+ /* DDR3-667 - DDR3-800 */
+ if (drive_strength == 0x0)
+ calibration_code = 0xb6d;
+ else if (drive_strength == 0x1)
+ calibration_code = 0x6db;
+ else if (drive_strength == 0x2)
+ calibration_code = 0x492;
+ else if (drive_strength == 0x3)
+ calibration_code = 0x492;
+ } else if (MemClkFreq == 0xa) {
+ /* DDR3-1066 */
+ if (drive_strength == 0x0)
+ calibration_code = 0xfff;
+ else if (drive_strength == 0x1)
+ calibration_code = 0x924;
+ else if (drive_strength == 0x2)
+ calibration_code = 0x6db;
+ else if (drive_strength == 0x3)
+ calibration_code = 0x6db;
+ } else if (MemClkFreq == 0xe) {
+ /* DDR3-1333 */
+ if (drive_strength == 0x0)
+ calibration_code = 0xb6d;
+ else if (drive_strength == 0x1)
+ calibration_code = 0x6db;
+ else if (drive_strength == 0x2)
+ calibration_code = 0x492;
+ else if (drive_strength == 0x3)
+ calibration_code = 0x492;
+ } else if ((MemClkFreq == 0x12) || (MemClkFreq == 0x16)) {
+ /* DDR3-1600 - DDR3-1866 */
+ if (drive_strength == 0x0)
+ calibration_code = 0xfff;
+ else if (drive_strength == 0x1)
+ calibration_code = 0xfff;
+ else if (drive_strength == 0x2)
+ calibration_code = 0xfff;
+ else if (drive_strength == 0x3)
+ calibration_code = 0xb6d;
+ }
+ }
+ }
+ } else {
+ /* LRDIMM */
+
+ /* TODO
+ * Implement LRDIMM support
+ * See Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Tables 47 - 49
+ */
+ }
+
+ return calibration_code;
+}
+
+static uint32_t fam15h_phy_predriver_cmd_addr_calibration_code(struct DCTStatStruc *pDCTstat, uint8_t dct, uint8_t drive_strength)
+{
+ uint8_t ddr_voltage_index;
+ uint32_t calibration_code = 0;
+ uint16_t MemClkFreq = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 0x1f;
+
+ ddr_voltage_index = dct_ddr_voltage_index(pDCTstat, dct);
+
+ if (ddr_voltage_index & 0x4) {
+ /* 1.25V */
+ /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 52 */
+ if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) {
+ /* DDR3-667 - DDR3-800 */
+ if (drive_strength == 0x0)
+ calibration_code = 0x492;
+ else if (drive_strength == 0x1)
+ calibration_code = 0x492;
+ else if (drive_strength == 0x2)
+ calibration_code = 0x492;
+ else if (drive_strength == 0x3)
+ calibration_code = 0x492;
+ } else if ((MemClkFreq == 0xa) || (MemClkFreq == 0xe)) {
+ /* DDR3-1066 - DDR3-1333 */
+ if (drive_strength == 0x0)
+ calibration_code = 0xdad;
+ else if (drive_strength == 0x1)
+ calibration_code = 0x924;
+ else if (drive_strength == 0x2)
+ calibration_code = 0x6db;
+ else if (drive_strength == 0x3)
+ calibration_code = 0x492;
+ } else if ((MemClkFreq == 0x12) || (MemClkFreq == 0x16)) {
+ /* DDR3-1600 - DDR3-1866 */
+ if (drive_strength == 0x0)
+ calibration_code = 0xff6;
+ else if (drive_strength == 0x1)
+ calibration_code = 0xdad;
+ else if (drive_strength == 0x2)
+ calibration_code = 0xb64;
+ else if (drive_strength == 0x3)
+ calibration_code = 0xb64;
+ }
+ }
+ else if (ddr_voltage_index & 0x2) {
+ /* 1.35V */
+ /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 51 */
+ if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) {
+ /* DDR3-667 - DDR3-800 */
+ if (drive_strength == 0x0)
+ calibration_code = 0x492;
+ else if (drive_strength == 0x1)
+ calibration_code = 0x492;
+ else if (drive_strength == 0x2)
+ calibration_code = 0x492;
+ else if (drive_strength == 0x3)
+ calibration_code = 0x492;
+ } else if ((MemClkFreq == 0xa) || (MemClkFreq == 0xe)) {
+ /* DDR3-1066 - DDR3-1333 */
+ if (drive_strength == 0x0)
+ calibration_code = 0x924;
+ else if (drive_strength == 0x1)
+ calibration_code = 0x6db;
+ else if (drive_strength == 0x2)
+ calibration_code = 0x6db;
+ else if (drive_strength == 0x3)
+ calibration_code = 0x6db;
+ } else if ((MemClkFreq == 0x12) || (MemClkFreq == 0x16)) {
+ /* DDR3-1600 - DDR3-1866 */
+ if (drive_strength == 0x0)
+ calibration_code = 0xb6d;
+ else if (drive_strength == 0x1)
+ calibration_code = 0xb6d;
+ else if (drive_strength == 0x2)
+ calibration_code = 0x924;
+ else if (drive_strength == 0x3)
+ calibration_code = 0x924;
+ }
+ }
+ else if (ddr_voltage_index & 0x1) {
+ /* 1.5V */
+ /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 50 */
+ if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) {
+ /* DDR3-667 - DDR3-800 */
+ if (drive_strength == 0x0)
+ calibration_code = 0x492;
+ else if (drive_strength == 0x1)
+ calibration_code = 0x492;
+ else if (drive_strength == 0x2)
+ calibration_code = 0x492;
+ else if (drive_strength == 0x3)
+ calibration_code = 0x492;
+ } else if ((MemClkFreq == 0xa) || (MemClkFreq == 0xe)) {
+ /* DDR3-1066 - DDR3-1333 */
+ if (drive_strength == 0x0)
+ calibration_code = 0x6db;
+ else if (drive_strength == 0x1)
+ calibration_code = 0x6db;
+ else if (drive_strength == 0x2)
+ calibration_code = 0x6db;
+ else if (drive_strength == 0x3)
+ calibration_code = 0x6db;
+ } else if ((MemClkFreq == 0x12) || (MemClkFreq == 0x16)) {
+ /* DDR3-1600 - DDR3-1866 */
+ if (drive_strength == 0x0)
+ calibration_code = 0xb6d;
+ else if (drive_strength == 0x1)
+ calibration_code = 0xb6d;
+ else if (drive_strength == 0x2)
+ calibration_code = 0xb6d;
+ else if (drive_strength == 0x3)
+ calibration_code = 0xb6d;
+ }
+ }
+
+ return calibration_code;
+}
+
+static uint32_t fam15h_phy_predriver_clk_calibration_code(struct DCTStatStruc *pDCTstat, uint8_t dct, uint8_t drive_strength)
+{
+ uint8_t ddr_voltage_index;
+ uint32_t calibration_code = 0;
+ uint16_t MemClkFreq = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 0x1f;
+
+ ddr_voltage_index = dct_ddr_voltage_index(pDCTstat, dct);
+
+ if (ddr_voltage_index & 0x4) {
+ /* 1.25V */
+ /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 55 */
+ if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) {
+ /* DDR3-667 - DDR3-800 */
+ if (drive_strength == 0x0)
+ calibration_code = 0xdad;
+ else if (drive_strength == 0x1)
+ calibration_code = 0xdad;
+ else if (drive_strength == 0x2)
+ calibration_code = 0x924;
+ else if (drive_strength == 0x3)
+ calibration_code = 0x924;
+ } else if ((MemClkFreq == 0xa) || (MemClkFreq == 0xe)) {
+ /* DDR3-1066 - DDR3-1333 */
+ if (drive_strength == 0x0)
+ calibration_code = 0xff6;
+ else if (drive_strength == 0x1)
+ calibration_code = 0xff6;
+ else if (drive_strength == 0x2)
+ calibration_code = 0xff6;
+ else if (drive_strength == 0x3)
+ calibration_code = 0xff6;
+ } else if ((MemClkFreq == 0x12) || (MemClkFreq == 0x16)) {
+ /* DDR3-1600 - DDR3-1866 */
+ if (drive_strength == 0x0)
+ calibration_code = 0xff6;
+ else if (drive_strength == 0x1)
+ calibration_code = 0xff6;
+ else if (drive_strength == 0x2)
+ calibration_code = 0xff6;
+ else if (drive_strength == 0x3)
+ calibration_code = 0xff6;
+ }
+ }
+ else if (ddr_voltage_index & 0x2) {
+ /* 1.35V */
+ /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 54 */
+ if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) {
+ /* DDR3-667 - DDR3-800 */
+ if (drive_strength == 0x0)
+ calibration_code = 0xdad;
+ else if (drive_strength == 0x1)
+ calibration_code = 0xdad;
+ else if (drive_strength == 0x2)
+ calibration_code = 0x924;
+ else if (drive_strength == 0x3)
+ calibration_code = 0x924;
+ } else if ((MemClkFreq == 0xa) || (MemClkFreq == 0xe)) {
+ /* DDR3-1066 - DDR3-1333 */
+ if (drive_strength == 0x0)
+ calibration_code = 0xff6;
+ else if (drive_strength == 0x1)
+ calibration_code = 0xff6;
+ else if (drive_strength == 0x2)
+ calibration_code = 0xff6;
+ else if (drive_strength == 0x3)
+ calibration_code = 0xdad;
+ } else if ((MemClkFreq == 0x12) || (MemClkFreq == 0x16)) {
+ /* DDR3-1600 - DDR3-1866 */
+ if (drive_strength == 0x0)
+ calibration_code = 0xff6;
+ else if (drive_strength == 0x1)
+ calibration_code = 0xff6;
+ else if (drive_strength == 0x2)
+ calibration_code = 0xff6;
+ else if (drive_strength == 0x3)
+ calibration_code = 0xdad;
+ }
+ }
+ else if (ddr_voltage_index & 0x1) {
+ /* 1.5V */
+ /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 53 */
+ if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) {
+ /* DDR3-667 - DDR3-800 */
+ if (drive_strength == 0x0)
+ calibration_code = 0x924;
+ else if (drive_strength == 0x1)
+ calibration_code = 0x924;
+ else if (drive_strength == 0x2)
+ calibration_code = 0x924;
+ else if (drive_strength == 0x3)
+ calibration_code = 0x924;
+ } else if ((MemClkFreq == 0xa) || (MemClkFreq == 0xe)) {
+ /* DDR3-1066 - DDR3-1333 */
+ if (drive_strength == 0x0)
+ calibration_code = 0xff6;
+ else if (drive_strength == 0x1)
+ calibration_code = 0xff6;
+ else if (drive_strength == 0x2)
+ calibration_code = 0xff6;
+ else if (drive_strength == 0x3)
+ calibration_code = 0xb6d;
+ } else if ((MemClkFreq == 0x12) || (MemClkFreq == 0x16)) {
+ /* DDR3-1600 - DDR3-1866 */
+ if (drive_strength == 0x0)
+ calibration_code = 0xff6;
+ else if (drive_strength == 0x1)
+ calibration_code = 0xff6;
+ else if (drive_strength == 0x2)
+ calibration_code = 0xff6;
+ else if (drive_strength == 0x3)
+ calibration_code = 0xff6;
+ }
+ }
+
+ return calibration_code;
+}
+
+static uint32_t fam15h_output_driver_compensation_code(struct DCTStatStruc *pDCTstat, uint8_t dct)
+{
+ /* FIXME
+ * Mainboards need to be able to specify the maximum number of DIMMs installable per channel
+ * For now assume a maximum of 2 DIMMs per channel can be installed
+ */
+ uint8_t MaxDimmsInstallable = 2;
+
+ uint8_t package_type;
+ uint32_t calibration_code = 0;
+
+ package_type = mctGet_NVbits(NV_PACK_TYPE);
+ uint16_t MemClkFreq = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 0x1f;
+
+ /* Obtain number of DIMMs on channel */
+ uint8_t dimm_count = pDCTstat->MAdimms[dct];
+ uint8_t rank_count_dimm0;
+ uint8_t rank_count_dimm1;
+
+ if (package_type == PT_GR) {
+ /* Socket G34 */
+ /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 73 */
+ if (MaxDimmsInstallable == 1) {
+ if (MemClkFreq == 0x4) {
+ /* DDR3-667 */
+ calibration_code = 0x00112222;
+ }
+ else if (MemClkFreq == 0x6) {
+ /* DDR3-800 */
+ calibration_code = 0x10112222;
+ }
+ else if (MemClkFreq == 0xa) {
+ /* DDR3-1066 */
+ calibration_code = 0x20112222;
+ }
+ else if ((MemClkFreq == 0xe) || (MemClkFreq == 0x12)) {
+ /* DDR3-1333 - DDR3-1600 */
+ calibration_code = 0x30112222;
+ }
+ else if (MemClkFreq == 0x16) {
+ /* DDR3-1866 */
+ calibration_code = 0x30332222;
+ }
+ } else if (MaxDimmsInstallable == 2) {
+ if (dimm_count == 1) {
+ /* 1 DIMM detected */
+ if (MemClkFreq == 0x4) {
+ /* DDR3-667 */
+ calibration_code = 0x00112222;
+ }
+ else if (MemClkFreq == 0x6) {
+ /* DDR3-800 */
+ calibration_code = 0x10112222;
+ }
+ else if (MemClkFreq == 0xa) {
+ /* DDR3-1066 */
+ calibration_code = 0x20112222;
+ }
+ else if ((MemClkFreq == 0xe) || (MemClkFreq == 0x12)) {
+ /* DDR3-1333 - DDR3-1600 */
+ calibration_code = 0x30112222;
+ }
+ } else if (dimm_count == 2) {
+ /* 2 DIMMs detected */
+ rank_count_dimm0 = pDCTstat->C_DCTPtr[dct]->DimmRanks[0];
+ rank_count_dimm1 = pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
+
+ if (MemClkFreq == 0x4) {
+ /* DDR3-667 */
+ calibration_code = 0x10222222;
+ }
+ else if (MemClkFreq == 0x6) {
+ /* DDR3-800 */
+ calibration_code = 0x20222222;
+ }
+ else if (MemClkFreq == 0xa) {
+ /* DDR3-1066 */
+ calibration_code = 0x30222222;
+ }
+ else if (MemClkFreq == 0xe) {
+ /* DDR3-1333 */
+ calibration_code = 0x30222222;
+ }
+ else if (MemClkFreq == 0x12) {
+ /* DDR3-1600 */
+ if ((rank_count_dimm0 == 1) && (rank_count_dimm1 == 1))
+ calibration_code = 0x30222222;
+ else
+ calibration_code = 0x30112222;
+ }
+ }
+ } else if (MaxDimmsInstallable == 3) {
+ /* TODO
+ * 3 DIMM/channel support unimplemented
+ */
+ }
+ } else {
+ /* TODO
+ * Other socket support unimplemented
+ */
+ }
+
+ return calibration_code;
+}
+
+static uint32_t fam15h_address_timing_compensation_code(struct DCTStatStruc *pDCTstat, uint8_t dct)
+{
+ /* FIXME
+ * Mainboards need to be able to specify the maximum number of DIMMs installable per channel
+ * For now assume a maximum of 2 DIMMs per channel can be installed
+ */
+ uint8_t MaxDimmsInstallable = 2;
+
+ uint8_t package_type;
+ uint32_t calibration_code = 0;
+
+ package_type = mctGet_NVbits(NV_PACK_TYPE);
+ uint16_t MemClkFreq = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 0x1f;
+
+ /* Obtain number of DIMMs on channel */
+ uint8_t dimm_count = pDCTstat->MAdimms[dct];
+ uint8_t rank_count_dimm0;
+ uint8_t rank_count_dimm1;
+
+ if (package_type == PT_GR) {
+ /* Socket G34 */
+ /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 73 */
+ if (MaxDimmsInstallable == 1) {
+ rank_count_dimm0 = pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
+
+ if (MemClkFreq == 0x4) {
+ /* DDR3-667 */
+ if (rank_count_dimm0 == 1)
+ calibration_code = 0x00000000;
+ else
+ calibration_code = 0x003b0000;
+ } else if (MemClkFreq == 0x6) {
+ /* DDR3-800 */
+ if (rank_count_dimm0 == 1)
+ calibration_code = 0x00000000;
+ else
+ calibration_code = 0x003b0000;
+ } else if (MemClkFreq == 0xa) {
+ /* DDR3-1066 */
+ calibration_code = 0x00383837;
+ } else if (MemClkFreq == 0xe) {
+ /* DDR3-1333 */
+ calibration_code = 0x00363635;
+ } else if (MemClkFreq == 0x12) {
+ /* DDR3-1600 */
+ if (rank_count_dimm0 == 1)
+ calibration_code = 0x00353533;
+ else
+ calibration_code = 0x00003533;
+ } else if (MemClkFreq == 0x16) {
+ /* DDR3-1866 */
+ calibration_code = 0x00333330;
+ }
+ } else if (MaxDimmsInstallable == 2) {
+ if (dimm_count == 1) {
+ /* 1 DIMM detected */
+ rank_count_dimm0 = pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
+
+ if (MemClkFreq == 0x4) {
+ /* DDR3-667 */
+ if (rank_count_dimm0 == 1)
+ calibration_code = 0x00000000;
+ else
+ calibration_code = 0x003b0000;
+ } else if (MemClkFreq == 0x6) {
+ /* DDR3-800 */
+ if (rank_count_dimm0 == 1)
+ calibration_code = 0x00000000;
+ else
+ calibration_code = 0x003b0000;
+ } else if (MemClkFreq == 0xa) {
+ /* DDR3-1066 */
+ calibration_code = 0x00383837;
+ } else if (MemClkFreq == 0xe) {
+ /* DDR3-1333 */
+ calibration_code = 0x00363635;
+ } else if (MemClkFreq == 0x12) {
+ /* DDR3-1600 */
+ if (rank_count_dimm0 == 1)
+ calibration_code = 0x00353533;
+ else
+ calibration_code = 0x00003533;
+ }
+ } else if (dimm_count == 2) {
+ /* 2 DIMMs detected */
+ rank_count_dimm0 = pDCTstat->C_DCTPtr[dct]->DimmRanks[0];
+ rank_count_dimm1 = pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
+
+ if (MemClkFreq == 0x4) {
+ /* DDR3-667 */
+ calibration_code = 0x00390039;
+ } else if (MemClkFreq == 0x6) {
+ /* DDR3-800 */
+ calibration_code = 0x00390039;
+ } else if (MemClkFreq == 0xa) {
+ /* DDR3-1066 */
+ calibration_code = 0x003a3a3a;
+ } else if (MemClkFreq == 0xe) {
+ /* DDR3-1333 */
+ calibration_code = 0x00003939;
+ } else if (MemClkFreq == 0x12) {
+ /* DDR3-1600 */
+ if ((rank_count_dimm0 == 1) && (rank_count_dimm1 == 1))
+ calibration_code = 0x00003738;
+ }
+ }
+ } else if (MaxDimmsInstallable == 3) {
+ /* TODO
+ * 3 DIMM/channel support unimplemented
+ */
+ }
+ } else {
+ /* TODO
+ * Other socket support unimplemented
+ */
+ }
+
+ return calibration_code;
+}
+
+static uint8_t fam15h_slow_access_mode(struct DCTStatStruc *pDCTstat, uint8_t dct)
+{
+ /* FIXME
+ * Mainboards need to be able to specify the maximum number of DIMMs installable per channel
+ * For now assume a maximum of 2 DIMMs per channel can be installed
+ */
+ uint8_t MaxDimmsInstallable = 2;
+
+ uint8_t package_type;
+ uint32_t slow_access = 0;
+
+ package_type = mctGet_NVbits(NV_PACK_TYPE);
+ uint16_t MemClkFreq = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 0x1f;
+
+ /* Obtain number of DIMMs on channel */
+ uint8_t dimm_count = pDCTstat->MAdimms[dct];
+ uint8_t rank_count_dimm0;
+ uint8_t rank_count_dimm1;
+
+ if (package_type == PT_GR) {
+ /* Socket G34 */
+ /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 73 */
+ if (MaxDimmsInstallable == 1) {
+ rank_count_dimm0 = pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
+
+ if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)
+ || (MemClkFreq == 0xa) | (MemClkFreq == 0xe)) {
+ /* DDR3-667 - DDR3-1333 */
+ slow_access = 0;
+ } else if ((MemClkFreq == 0x12) || (MemClkFreq == 0x16)) {
+ /* DDR3-1600 - DDR3-1866 */
+ if (rank_count_dimm0 == 1)
+ slow_access = 0;
+ else
+ slow_access = 1;
+ }
+ } else if (MaxDimmsInstallable == 2) {
+ if (dimm_count == 1) {
+ /* 1 DIMM detected */
+ rank_count_dimm0 = pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
+
+ if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)
+ || (MemClkFreq == 0xa) | (MemClkFreq == 0xe)) {
+ /* DDR3-667 - DDR3-1333 */
+ slow_access = 0;
+ }
+ else if (MemClkFreq == 0x12) {
+ /* DDR3-1600 */
+ if (rank_count_dimm0 == 1)
+ slow_access = 0;
+ else
+ slow_access = 1;
+ }
+ } else if (dimm_count == 2) {
+ /* 2 DIMMs detected */
+ rank_count_dimm0 = pDCTstat->C_DCTPtr[dct]->DimmRanks[0];
+ rank_count_dimm1 = pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
+
+ if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)
+ || (MemClkFreq == 0xa)) {
+ /* DDR3-667 - DDR3-1066 */
+ slow_access = 0;
+ }
+ else if ((MemClkFreq == 0xe) || (MemClkFreq == 0x12)) {
+ /* DDR3-1333 - DDR3-1600 */
+ slow_access = 1;
+ }
+ }
+ } else if (MaxDimmsInstallable == 3) {
+ /* TODO
+ * 3 DIMM/channel support unimplemented
+ */
+ }
+ } else {
+ /* TODO
+ * Other socket support unimplemented
+ */
+ }
+
+ return slow_access;
+}
+
+static void set_2t_configuration(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct)
+{
+ uint32_t dev;
+ uint32_t reg;
+ uint32_t dword;
+
+ uint8_t enable_slow_access_mode = 0;
+ dev = pDCTstat->dev_dct;
+
+ if (is_fam15h()) {
+ if (pDCTstat->_2Tmode)
+ enable_slow_access_mode = 1;
+ } else {
+ if (pDCTstat->_2Tmode == 2)
+ enable_slow_access_mode = 1;
+ }
+
+ reg = 0x94; /* DRAM Configuration High */
+ dword = Get_NB32_DCT(dev, dct, reg);
+ if (enable_slow_access_mode)
+ dword |= (0x1 << 20); /* Set 2T CMD mode */
+ else
+ dword &= ~(0x1 << 20); /* Clear 2T CMD mode */
+ Set_NB32_DCT(dev, dct, reg, dword);
+}
+
+static void precise_ndelay_fam15(struct MCTStatStruc *pMCTstat, uint32_t nanoseconds) {
+ msr_t tsc_msr;
+ uint64_t cycle_count = (((uint64_t)pMCTstat->TSCFreq) * nanoseconds) / 1000;
+ uint64_t start_timestamp;
+ uint64_t current_timestamp;
+
+ tsc_msr = rdmsr(0x00000010);
+ start_timestamp = (((uint64_t)tsc_msr.hi) << 32) | tsc_msr.lo;
+ do {
+ tsc_msr = rdmsr(0x00000010);
+ current_timestamp = (((uint64_t)tsc_msr.hi) << 32) | tsc_msr.lo;
+ } while ((current_timestamp - start_timestamp) < cycle_count);
+}
+
+static void precise_memclk_delay_fam15(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, uint8_t dct, uint32_t clocks) {
+ uint16_t memclk_freq;
+ uint32_t delay_ns;
+ uint16_t fam15h_freq_tab[] = {0, 0, 0, 0, 333, 0, 400, 0, 0, 0, 533, 0, 0, 0, 667, 0, 0, 0, 800, 0, 0, 0, 933};
+
+ memclk_freq = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 0x1f;
+
+ delay_ns = (((uint64_t)clocks * 1000) / fam15h_freq_tab[memclk_freq]);
+ precise_ndelay_fam15(pMCTstat, delay_ns);
+}
+
static void mctAutoInitMCT_D(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstatA)
{
@@ -283,10 +1230,26 @@ static void mctAutoInitMCT_D(struct MCTStatStruc *pMCTstat,
restartinit:
mctInitMemGPIOs_A_D(); /* Set any required GPIOs*/
if (s3resume) {
+ printk(BIOS_DEBUG, "mctAutoInitMCT_D: mct_ForceNBPState0_En_Fam15\n");
+ for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+ struct DCTStatStruc *pDCTstat;
+ pDCTstat = pDCTstatA + Node;
+
+ mct_ForceNBPState0_En_Fam15(pMCTstat, pDCTstat);
+ }
+
#if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME)
printk(BIOS_DEBUG, "mctAutoInitMCT_D: Restoring DCT configuration from NVRAM\n");
restore_mct_information_from_nvram();
#endif
+
+ printk(BIOS_DEBUG, "mctAutoInitMCT_D: mct_ForceNBPState0_Dis_Fam15\n");
+ for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+ struct DCTStatStruc *pDCTstat;
+ pDCTstat = pDCTstatA + Node;
+
+ mct_ForceNBPState0_Dis_Fam15(pMCTstat, pDCTstat);
+ }
} else {
NodesWmem = 0;
node_sys_base = 0;
@@ -303,15 +1266,15 @@ restartinit:
pDCTstat->dev_map = PA_MAP(Node);
pDCTstat->dev_dct = PA_DCT(Node);
pDCTstat->dev_nbmisc = PA_NBMISC(Node);
+ pDCTstat->dev_link = PA_LINK(Node);
+ pDCTstat->dev_nbctl = PA_NBCTL(Node);
pDCTstat->NodeSysBase = node_sys_base;
printk(BIOS_DEBUG, "%s: mct_init Node %d\n", __func__, Node);
mct_init(pMCTstat, pDCTstat);
mctNodeIDDebugPort_D();
pDCTstat->NodePresent = NodePresent_D(Node);
- if (pDCTstat->NodePresent) { /* See if Node is there*/
- printk(BIOS_DEBUG, "%s: clear_legacy_Mode\n", __func__);
- clear_legacy_Mode(pMCTstat, pDCTstat);
+ if (pDCTstat->NodePresent) {
pDCTstat->LogicalCPUID = mctGetLogicalCPUID_D(Node);
printk(BIOS_DEBUG, "%s: mct_InitialMCT_D\n", __func__);
@@ -320,6 +1283,26 @@ restartinit:
printk(BIOS_DEBUG, "%s: mctSMBhub_Init\n", __func__);
mctSMBhub_Init(Node); /* Switch SMBUS crossbar to proper node*/
+ printk(BIOS_DEBUG, "%s: mct_preInitDCT\n", __func__);
+ mct_preInitDCT(pMCTstat, pDCTstat);
+ }
+ node_sys_base = pDCTstat->NodeSysBase;
+ node_sys_base += (pDCTstat->NodeSysLimit + 2) & ~0x0F;
+ }
+
+#if IS_ENABLED(DIMM_VOLTAGE_SET_SUPPORT)
+ printk(BIOS_DEBUG, "%s: DIMMSetVoltage\n", __func__);
+ DIMMSetVoltages(pMCTstat, pDCTstatA); /* Set the DIMM voltages (mainboard specific) */
+#endif
+
+ for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+ struct DCTStatStruc *pDCTstat;
+ pDCTstat = pDCTstatA + Node;
+
+ if (pDCTstat->NodePresent) {
+ printk(BIOS_DEBUG, "%s: mctSMBhub_Init\n", __func__);
+ mctSMBhub_Init(Node); /* Switch SMBUS crossbar to proper node*/
+
printk(BIOS_DEBUG, "%s: mct_initDCT\n", __func__);
mct_initDCT(pMCTstat, pDCTstat);
if (pDCTstat->ErrCode == SC_FatalErr) {
@@ -327,20 +1310,13 @@ restartinit:
} else if (pDCTstat->ErrCode < SC_StopError) {
NodesWmem++;
}
- } /* if Node present */
- node_sys_base = pDCTstat->NodeSysBase;
- node_sys_base += (pDCTstat->NodeSysLimit + 2) & ~0x0F;
+ }
}
if (NodesWmem == 0) {
printk(BIOS_DEBUG, "No Nodes?!\n");
goto fatalexit;
}
-#if IS_ENABLED(DIMM_VOLTAGE_SET_SUPPORT)
- printk(BIOS_DEBUG, "mctAutoInitMCT_D: DIMMSetVoltage\n");
- DIMMSetVoltages(pMCTstat, pDCTstatA); /* Set the DIMM voltages (mainboard specific) */
-#endif
-
printk(BIOS_DEBUG, "mctAutoInitMCT_D: SyncDCTsReady_D\n");
SyncDCTsReady_D(pMCTstat, pDCTstatA); /* Make sure DCTs are ready for accesses.*/
@@ -361,7 +1337,6 @@ restartinit:
printk(BIOS_DEBUG, "mctAutoInitMCT_D: :OtherTiming\n");
mct_OtherTiming(pMCTstat, pDCTstatA);
-
if (ReconfigureDIMMspare_D(pMCTstat, pDCTstatA)) { /* RESET# if 1st pass of DIMM spare enabled*/
goto restartinit;
}
@@ -375,6 +1350,14 @@ restartinit:
MCTMemClr_D(pMCTstat,pDCTstatA);
}
+ printk(BIOS_DEBUG, "mctAutoInitMCT_D: mct_ForceNBPState0_Dis_Fam15\n");
+ for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+ struct DCTStatStruc *pDCTstat;
+ pDCTstat = pDCTstatA + Node;
+
+ mct_ForceNBPState0_Dis_Fam15(pMCTstat, pDCTstat);
+ }
+
mct_FinalMCT_D(pMCTstat, pDCTstatA);
printk(BIOS_DEBUG, "mctAutoInitMCT_D Done: Global Status: %x\n", pMCTstat->GStatus);
}
@@ -414,6 +1397,425 @@ static u8 ReconfigureDIMMspare_D(struct MCTStatStruc *pMCTstat,
return ret;
}
+/* Enable or disable phy-assisted training mode
+ * Phy-assisted training mode applies to the follow DRAM training procedures:
+ * Write Levelization Training (2.10.5.8.1)
+ * DQS Receiver Enable Training (2.10.5.8.2)
+ */
+static void fam15EnableTrainingMode(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, uint8_t dct, uint8_t enable)
+{
+ uint8_t index;
+ uint32_t dword;
+ uint32_t index_reg = 0x98;
+ uint32_t dev = pDCTstat->dev_dct;
+
+ if (enable) {
+ /* Enable training mode */
+ dword = Get_NB32_DCT(dev, dct, 0x78); /* DRAM Control */
+ dword &= ~(0x1 << 17); /* AddrCmdTriEn = 0 */
+ Set_NB32_DCT(dev, dct, 0x78, dword); /* DRAM Control */
+
+ dword = Get_NB32_DCT(dev, dct, 0x8c); /* DRAM Timing High */
+ dword |= (0x1 << 18); /* DisAutoRefresh = 1 */
+ Set_NB32_DCT(dev, dct, 0x8c, dword); /* DRAM Timing High */
+
+ dword = Get_NB32_DCT(dev, dct, 0x94); /* DRAM Configuration High */
+ dword &= ~(0xf << 24); /* DcqBypassMax = 0 */
+ dword &= ~(0x1 << 22); /* BankSwizzleMode = 0 */
+ dword &= ~(0x1 << 15); /* PowerDownEn = 0 */
+ dword &= ~(0x3 << 10); /* ZqcsInterval = 0 */
+ Set_NB32_DCT(dev, dct, 0x94, dword); /* DRAM Configuration High */
+
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000d);
+ dword &= ~(0xf << 16); /* RxMaxDurDllNoLock = 0 */
+ dword &= ~(0xf); /* TxMaxDurDllNoLock = 0 */
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000d, dword);
+
+ for (index = 0; index < 0x9; index++) {
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f0010 | (index << 8));
+ dword &= ~(0x1 << 12); /* EnRxPadStandby = 0 */
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f0010 | (index << 8), dword);
+ }
+
+ dword = Get_NB32_DCT(dev, dct, 0xa4); /* DRAM Controller Temperature Throttle */
+ dword &= ~(0x1 << 11); /* BwCapEn = 0 */
+ dword &= ~(0x1 << 8); /* ODTSEn = 0 */
+ Set_NB32_DCT(dev, dct, 0xa4, dword); /* DRAM Controller Temperature Throttle */
+
+ dword = Get_NB32_DCT(dev, dct, 0x110); /* DRAM Controller Select Low */
+ dword &= ~(0x1 << 2); /* DctSelIntLvEn = 0 */
+ Set_NB32_DCT(dev, dct, 0x110, dword); /* DRAM Controller Select Low */
+
+ dword = Get_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x58); /* Scrub Rate Control */
+ dword &= ~(0x1f << 24); /* L3Scrub = 0 */
+ dword &= ~(0x1f); /* DramScrub = 0 */
+ Set_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x58, dword); /* Scrub Rate Control */
+
+ dword = Get_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x5c); /* DRAM Scrub Address Low */
+ dword &= ~(0x1); /* ScrubReDirEn = 0 */
+ Set_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x5c, dword); /* DRAM Scrub Address Low */
+
+ dword = Get_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x1b8); /* L3 Control 1 */
+ dword |= (0x1 << 4); /* L3ScrbRedirDis = 1 */
+ Set_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x1b8, dword); /* L3 Control 1 */
+
+ /* Fam15h BKDG section 2.10.5.5.1 */
+ dword = Get_NB32_DCT(dev, dct, 0x218); /* DRAM Timing 5 */
+ dword &= ~(0xf << 24); /* TrdrdSdSc = 0xb */
+ dword |= (0xb << 24);
+ dword &= ~(0xf << 16); /* TrdrdSdDc = 0xb */
+ dword |= (0xb << 16);
+ dword &= ~(0xf); /* TrdrdDd = 0xb */
+ dword |= 0xb;
+ Set_NB32_DCT(dev, dct, 0x218, dword); /* DRAM Timing 5 */
+
+ /* Fam15h BKDG section 2.10.5.5.2 */
+ dword = Get_NB32_DCT(dev, dct, 0x214); /* DRAM Timing 4 */
+ dword &= ~(0xf << 16); /* TwrwrSdSc = 0xb */
+ dword |= (0xb << 16);
+ dword &= ~(0xf << 8); /* TwrwrSdDc = 0xb */
+ dword |= (0xb << 8);
+ dword &= ~(0xf); /* TwrwrDd = 0xb */
+ dword |= 0xb;
+ Set_NB32_DCT(dev, dct, 0x214, dword); /* DRAM Timing 4 */
+
+ /* Fam15h BKDG section 2.10.5.5.3 */
+ dword = Get_NB32_DCT(dev, dct, 0x218); /* DRAM Timing 5 */
+ dword &= ~(0xf << 8); /* Twrrd = 0xb */
+ dword |= (0xb << 8);
+ Set_NB32_DCT(dev, dct, 0x218, dword); /* DRAM Timing 5 */
+
+ /* Fam15h BKDG section 2.10.5.5.4 */
+ dword = Get_NB32_DCT(dev, dct, 0x21c); /* DRAM Timing 6 */
+ dword &= ~(0x1f << 8); /* TrwtTO = 0x16 */
+ dword |= (0x16 << 8);
+ dword &= ~(0x1f << 16); /* TrwtWB = TrwtTO + 1 */
+ dword |= ((((dword >> 8) & 0x1f) + 1) << 16);
+ Set_NB32_DCT(dev, dct, 0x21c, dword); /* DRAM Timing 6 */
+ } else {
+ /* Disable training mode */
+ uint8_t lane;
+ uint8_t dimm;
+ uint8_t receiver;
+ uint8_t max_lane;
+ uint8_t ecc_enabled;
+ uint8_t x4_present = 0;
+ uint8_t x8_present = 0;
+ uint8_t memclk_index;
+ uint8_t interleave_channels = 0;
+ uint8_t redirect_ecc_scrub = 0;
+ uint16_t trdrdsddc;
+ uint16_t trdrddd;
+ uint16_t cdd_trdrddd;
+ uint16_t twrwrsddc;
+ uint16_t twrwrdd;
+ uint16_t cdd_twrwrdd;
+ uint16_t twrrd;
+ uint16_t trwtto;
+ uint8_t first_dimm;
+ uint16_t delay;
+ uint16_t delay2;
+ uint8_t read_odt_delay;
+ uint8_t write_odt_delay;
+ uint16_t difference;
+ uint16_t current_total_delay_1[MAX_BYTE_LANES];
+ uint16_t current_total_delay_2[MAX_BYTE_LANES];
+
+ /* FIXME
+ * This should be platform configurable
+ */
+ uint8_t dimm_event_l_pin_support = 0;
+
+ ecc_enabled = !!(pMCTstat->GStatus & 1 << GSB_ECCDIMMs);
+ if (ecc_enabled)
+ max_lane = 9;
+ else
+ max_lane = 8;
+
+ if (pDCTstat->Dimmx4Present & ((dct)?0xaa:0x55))
+ x4_present = 1;
+ if (pDCTstat->Dimmx8Present & ((dct)?0xaa:0x55))
+ x8_present = 1;
+ memclk_index = Get_NB32_DCT(dev, dct, 0x94) & 0x1f;
+
+ if (pDCTstat->DIMMValidDCT[0] && pDCTstat->DIMMValidDCT[1] && mctGet_NVbits(NV_Unganged))
+ interleave_channels = 1;
+
+ if ((pMCTstat->GStatus & 1 << GSB_ECCDIMMs) && mctGet_NVbits(NV_ECCRedir))
+ redirect_ecc_scrub = 1;
+
+ dword = (Get_NB32_DCT(dev, dct, 0x240) >> 4) & 0xf;
+ if (dword > 6)
+ read_odt_delay = dword - 6;
+ else
+ read_odt_delay = 0;
+
+ dword = Get_NB32_DCT(dev, dct, 0x240);
+ delay = (dword >> 4) & 0xf;
+ if (delay > 6)
+ read_odt_delay = delay - 6;
+ else
+ read_odt_delay = 0;
+ delay = (dword >> 12) & 0x7;
+ if (delay > 6)
+ write_odt_delay = delay - 6;
+ else
+ write_odt_delay = 0;
+
+ /* TODO:
+ * Adjust trdrdsddc if four-rank DIMMs are installed per
+ * section 2.10.5.5.1 of the Family 15h BKDG.
+ * cdd_trdrdsddc will also need to be calculated in that process.
+ */
+ trdrdsddc = 3;
+
+ /* Calculate the Critical Delay Difference for TrdrdDd */
+ cdd_trdrddd = 0;
+ first_dimm = 1;
+ for (receiver = 0; receiver < 8; receiver += 2) {
+ dimm = (receiver >> 1);
+
+ if (!mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, dct, receiver))
+ continue;
+
+ read_dqs_receiver_enable_control_registers(current_total_delay_2, dev, dct, dimm, index_reg);
+
+ if (first_dimm) {
+ memcpy(current_total_delay_1, current_total_delay_2, sizeof(current_total_delay_1));
+ first_dimm = 0;
+ }
+
+ for (lane = 0; lane < max_lane; lane++) {
+ if (current_total_delay_1[lane] > current_total_delay_2[lane])
+ difference = current_total_delay_1[lane] - current_total_delay_2[lane];
+ else
+ difference = current_total_delay_2[lane] - current_total_delay_1[lane];
+
+ if (difference > cdd_trdrddd)
+ cdd_trdrddd = difference;
+ }
+ }
+
+ /* Convert the difference to MEMCLKs */
+ cdd_trdrddd = (((cdd_trdrddd >> 5) & 0x1f) + 1) / 2;
+
+ /* Calculate Trdrddd */
+ delay = (read_odt_delay + 3) * 2;
+ delay2 = cdd_trdrddd + 7;
+ if (delay2 > delay)
+ delay = delay2;
+ trdrddd = (delay + 1) / 2; /* + 1 is equivalent to ceiling function here */
+ if (trdrdsddc > trdrddd)
+ trdrddd = trdrdsddc;
+
+ /* TODO:
+ * Adjust twrwrsddc if four-rank DIMMs are installed per
+ * section 2.10.5.5.1 of the Family 15h BKDG.
+ * cdd_twrwrsddc will also need to be calculated in that process.
+ */
+ twrwrsddc = 4;
+
+ /* Calculate the Critical Delay Difference for TwrwrDd */
+ cdd_twrwrdd = 0;
+ first_dimm = 1;
+ for (receiver = 0; receiver < 8; receiver += 2) {
+ dimm = (receiver >> 1);
+
+ if (!mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, dct, receiver))
+ continue;
+
+ read_dqs_write_timing_control_registers(current_total_delay_2, dev, dct, dimm, index_reg);
+
+ if (first_dimm) {
+ memcpy(current_total_delay_1, current_total_delay_2, sizeof(current_total_delay_1));
+ first_dimm = 0;
+ }
+
+ for (lane = 0; lane < max_lane; lane++) {
+ if (current_total_delay_1[lane] > current_total_delay_2[lane])
+ difference = current_total_delay_1[lane] - current_total_delay_2[lane];
+ else
+ difference = current_total_delay_2[lane] - current_total_delay_1[lane];
+
+ if (difference > cdd_twrwrdd)
+ cdd_twrwrdd = difference;
+ }
+ }
+
+ /* Convert the difference to MEMCLKs */
+ cdd_twrwrdd = (((cdd_twrwrdd >> 5) & 0x1f) + 1) / 2;
+
+ /* Calculate Twrwrdd */
+ delay = (write_odt_delay + 3) * 2;
+ delay2 = cdd_twrwrdd + 7;
+ if (delay2 > delay)
+ delay = delay2;
+ twrwrdd = (delay + 1) / 2; /* + 1 is equivalent to ceiling function here */
+ if (twrwrsddc > twrwrdd)
+ twrwrdd = twrwrsddc;
+
+ dword = Get_NB32_DCT(dev, dct, 0x78); /* DRAM Control */
+ dword |= (0x1 << 17); /* AddrCmdTriEn = 1 */
+ Set_NB32_DCT(dev, dct, 0x78, dword); /* DRAM Control */
+
+ dword = Get_NB32_DCT(dev, dct, 0x8c); /* DRAM Timing High */
+ dword &= ~(0x1 << 18); /* DisAutoRefresh = 0 */
+ Set_NB32_DCT(dev, dct, 0x8c, dword); /* DRAM Timing High */
+
+ dword = Get_NB32_DCT(dev, dct, 0x94); /* DRAM Configuration High */
+ dword |= (0xf << 24); /* DcqBypassMax = 0xf */
+ dword |= (0x1 << 22); /* BankSwizzleMode = 1 */
+ dword |= (0x1 << 15); /* PowerDownEn = 1 */
+ dword &= ~(0x3 << 10); /* ZqcsInterval = 0x2 */
+ dword |= (0x2 << 10);
+ Set_NB32_DCT(dev, dct, 0x94, dword); /* DRAM Configuration High */
+
+ if (x4_present && x8_present) {
+ /* Mixed channel of 4x and 8x DIMMs */
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000d);
+ dword &= ~(0x3 << 24); /* RxDLLWakeupTime = 0 */
+ dword &= ~(0x7 << 20); /* RxCPUpdPeriod = 0 */
+ dword &= ~(0xf << 16); /* RxMaxDurDllNoLock = 0 */
+ dword &= ~(0x3 << 8); /* TxDLLWakeupTime = 0 */
+ dword &= ~(0x7 << 4); /* TxCPUpdPeriod = 0 */
+ dword &= ~(0xf); /* TxMaxDurDllNoLock = 0 */
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000d, dword);
+ } else {
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000d);
+ dword &= ~(0x3 << 24); /* RxDLLWakeupTime = 3 */
+ dword |= (0x3 << 24);
+ dword &= ~(0x7 << 20); /* RxCPUpdPeriod = 3 */
+ dword |= (0x3 << 20);
+ dword &= ~(0xf << 16); /* RxMaxDurDllNoLock = 7 */
+ dword |= (0x7 << 16);
+ dword &= ~(0x3 << 8); /* TxDLLWakeupTime = 3 */
+ dword |= (0x3 << 8);
+ dword &= ~(0x7 << 4); /* TxCPUpdPeriod = 3 */
+ dword |= (0x3 << 4);
+ dword &= ~(0xf); /* TxMaxDurDllNoLock = 7 */
+ dword |= 0x7;
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000d, dword);
+ }
+
+ if ((memclk_index <= 0x12) && (x4_present != x8_present)) {
+ /* MemClkFreq <= 800MHz
+ * Not a mixed channel of x4 and x8 DIMMs
+ */
+ for (index = 0; index < 0x9; index++) {
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f0010 | (index << 8));
+ dword |= (0x1 << 12); /* EnRxPadStandby = 1 */
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f0010 | (index << 8), dword);
+ }
+ } else {
+ for (index = 0; index < 0x9; index++) {
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f0010 | (index << 8));
+ dword &= ~(0x1 << 12); /* EnRxPadStandby = 0 */
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f0010 | (index << 8), dword);
+ }
+ }
+
+ /* TODO
+ * Calculate Twrrd per section 2.10.5.5.3 of the Family 15h BKDG
+ */
+ twrrd = 0xb;
+
+ /* TODO
+ * Calculate TrwtTO per section 2.10.5.5.4 of the Family 15h BKDG
+ */
+ trwtto = 0x16;
+
+ dword = Get_NB32_DCT(dev, dct, 0xa4); /* DRAM Controller Temperature Throttle */
+ dword &= ~(0x1 << 11); /* BwCapEn = 0 */
+ dword &= ~(0x1 << 8); /* ODTSEn = dimm_event_l_pin_support */
+ dword |= (dimm_event_l_pin_support & 0x1) << 8;
+ Set_NB32_DCT(dev, dct, 0xa4, dword); /* DRAM Controller Temperature Throttle */
+
+ dword = Get_NB32_DCT(dev, dct, 0x110); /* DRAM Controller Select Low */
+ dword &= ~(0x1 << 2); /* DctSelIntLvEn = interleave_channels */
+ dword |= (interleave_channels & 0x1) << 2;
+ Set_NB32_DCT(dev, dct, 0x110, dword); /* DRAM Controller Select Low */
+
+ dword = Get_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x58); /* Scrub Rate Control */
+ dword &= ~(0x1f << 24); /* L3Scrub = NV_L3BKScrub */
+ dword |= (mctGet_NVbits(NV_L3BKScrub) & 0x1f) << 24;
+ dword &= ~(0x1f); /* DramScrub = NV_DramBKScrub */
+ dword |= mctGet_NVbits(NV_DramBKScrub) & 0x1f;
+ Set_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x58, dword); /* Scrub Rate Control */
+
+ dword = Get_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x5c); /* DRAM Scrub Address Low */
+ dword &= ~(0x1); /* ScrubReDirEn = redirect_ecc_scrub */
+ dword |= redirect_ecc_scrub & 0x1;
+ Set_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x5c, dword); /* DRAM Scrub Address Low */
+
+ dword = Get_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x1b8); /* L3 Control 1 */
+ dword &= ~(0x1 << 4); /* L3ScrbRedirDis = 0 */
+ Set_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x1b8, dword); /* L3 Control 1 */
+
+ /* FIXME
+ * The BKDG-recommended settings cause memory corruption on the ASUS KGPE-D16.
+ * Investigate and fix...
+ */
+#if 0
+ /* Fam15h BKDG section 2.10.5.5.1 */
+ dword = Get_NB32_DCT(dev, dct, 0x218); /* DRAM Timing 5 */
+ dword &= ~(0xf << 24); /* TrdrdSdSc = 0x1 */
+ dword |= (0x1 << 24);
+ dword &= ~(0xf << 16); /* TrdrdSdDc = trdrdsddc */
+ dword |= ((trdrdsddc & 0xf) << 16);
+ dword &= ~(0xf); /* TrdrdDd = trdrddd */
+ dword |= (trdrddd & 0xf);
+ Set_NB32_DCT(dev, dct, 0x218, dword); /* DRAM Timing 5 */
+#endif
+
+ /* Fam15h BKDG section 2.10.5.5.2 */
+ dword = Get_NB32_DCT(dev, dct, 0x214); /* DRAM Timing 4 */
+ dword &= ~(0xf << 16); /* TwrwrSdSc = 0x1 */
+ dword |= (0x1 << 16);
+ dword &= ~(0xf << 8); /* TwrwrSdDc = twrwrsddc */
+ dword |= ((twrwrsddc & 0xf) << 8);
+ dword &= ~(0xf); /* TwrwrDd = twrwrdd */
+ dword |= (twrwrdd & 0xf);
+ Set_NB32_DCT(dev, dct, 0x214, dword); /* DRAM Timing 4 */
+
+ /* Fam15h BKDG section 2.10.5.5.3 */
+ dword = Get_NB32_DCT(dev, dct, 0x218); /* DRAM Timing 5 */
+ dword &= ~(0xf << 8); /* Twrrd = twrrd */
+ dword |= ((twrrd & 0xf) << 8);
+ Set_NB32_DCT(dev, dct, 0x218, dword); /* DRAM Timing 5 */
+
+ /* Fam15h BKDG section 2.10.5.5.4 */
+ dword = Get_NB32_DCT(dev, dct, 0x21c); /* DRAM Timing 6 */
+ dword &= ~(0x1f << 8); /* TrwtTO = trwtto */
+ dword |= ((trwtto & 0x1f) << 8);
+ dword &= ~(0x1f << 16); /* TrwtWB = TrwtTO + 1 */
+ dword |= ((((dword >> 8) & 0x1f) + 1) << 16);
+ Set_NB32_DCT(dev, dct, 0x21c, dword); /* DRAM Timing 6 */
+
+ /* Enable prefetchers */
+ dword = Get_NB32_DCT(dev, dct, 0x110); /* Memory Controller Configuration High */
+ dword &= ~(0x1 << 13); /* PrefIoDis = 0 */
+ dword &= ~(0x1 << 12); /* PrefCpuDis = 0 */
+ Set_NB32_DCT(dev, dct, 0x110, dword); /* Memory Controller Configuration High */
+ }
+}
+
+static void exit_training_mode_fam15(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstatA)
+{
+ uint8_t node;
+ uint8_t dct;
+
+ for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
+ struct DCTStatStruc *pDCTstat;
+ pDCTstat = pDCTstatA + node;
+
+ if (pDCTstat->NodePresent)
+ for (dct = 0; dct < 2; dct++)
+ fam15EnableTrainingMode(pMCTstat, pDCTstat, dct, 0);
+ }
+}
+
static void DQSTiming_D(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstatA)
{
@@ -430,6 +1832,20 @@ static void DQSTiming_D(struct MCTStatStruc *pMCTstat,
mct_BeforeDQSTrain_D(pMCTstat, pDCTstatA);
phyAssistedMemFnceTraining(pMCTstat, pDCTstatA);
+ if (is_fam15h()) {
+ uint8_t Node;
+ struct DCTStatStruc *pDCTstat;
+ for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+ pDCTstat = pDCTstatA + Node;
+ if (pDCTstat->NodePresent) {
+ if (pDCTstat->DIMMValidDCT[0])
+ InitPhyCompensation(pMCTstat, pDCTstat, 0);
+ if (pDCTstat->DIMMValidDCT[1])
+ InitPhyCompensation(pMCTstat, pDCTstat, 1);
+ }
+ }
+ }
+
if (nv_DQSTrainCTL) {
mctHookBeforeAnyTraining(pMCTstat, pDCTstatA);
/* TODO: should be in mctHookBeforeAnyTraining */
@@ -437,16 +1853,35 @@ static void DQSTiming_D(struct MCTStatStruc *pMCTstat,
_WRMSR(0x26D, 0x04040404, 0x04040404);
_WRMSR(0x26E, 0x04040404, 0x04040404);
_WRMSR(0x26F, 0x04040404, 0x04040404);
- mct_WriteLevelization_HW(pMCTstat, pDCTstatA);
+ mct_WriteLevelization_HW(pMCTstat, pDCTstatA, FirstPass);
- TrainReceiverEn_D(pMCTstat, pDCTstatA, FirstPass);
+ if (is_fam15h()) {
+ /* Receiver Enable Training Pass 1 */
+ TrainReceiverEn_D(pMCTstat, pDCTstatA, FirstPass);
+ }
- mct_TrainDQSPos_D(pMCTstat, pDCTstatA);
+ mct_WriteLevelization_HW(pMCTstat, pDCTstatA, SecondPass);
- /* Second Pass never used for Barcelona! */
- /* TrainReceiverEn_D(pMCTstat, pDCTstatA, SecondPass); */
+ if (is_fam15h()) {
+ /* Receiver Enable Training Pass 2 */
+ // TrainReceiverEn_D(pMCTstat, pDCTstatA, SecondPass);
+
+ /* TODO:
+ * Determine why running TrainReceiverEn_D in SecondPass
+ * mode yields less stable training values than when run
+ * in FirstPass mode as in the HACK below.
+ */
+ TrainReceiverEn_D(pMCTstat, pDCTstatA, FirstPass);
+ } else {
+ TrainReceiverEn_D(pMCTstat, pDCTstatA, FirstPass);
+ }
+
+ mct_TrainDQSPos_D(pMCTstat, pDCTstatA);
- mctSetEccDQSRcvrEn_D(pMCTstat, pDCTstatA);
+ if (is_fam15h())
+ exit_training_mode_fam15(pMCTstat, pDCTstatA);
+ else
+ mctSetEccDQSRcvrEn_D(pMCTstat, pDCTstatA);
/* FIXME - currently uses calculated value TrainMaxReadLatency_D(pMCTstat, pDCTstatA); */
mctHookAfterAnyTraining();
@@ -482,7 +1917,7 @@ static void LoadDQSSigTmgRegs_D(struct MCTStatStruc *pMCTstat,
for (Channel = 0;Channel < 2; Channel++) {
/* there are four receiver pairs,
loosely associated with chipselects.*/
- index_reg = 0x98 + Channel * 0x100;
+ index_reg = 0x98;
for (Receiver = 0; Receiver < 8; Receiver += 2) {
/* Set Receiver Enable Values */
mct_SetRcvrEnDly_D(pDCTstat,
@@ -498,7 +1933,7 @@ static void LoadDQSSigTmgRegs_D(struct MCTStatStruc *pMCTstat,
txdqs = pDCTstat->CH_D_B_TxDqs[Channel][Receiver >> 1][ByteLane];
index = Table_DQSRcvEn_Offset[ByteLane >> 1];
index += (Receiver >> 1) * 3 + 0x10 + 0x20; /* Addl_Index */
- val = Get_NB32_index_wait(dev, 0x98 + 0x100*Channel, index);
+ val = Get_NB32_index_wait_DCT(dev, Channel, 0x98, index);
if (ByteLane & 1) { /* odd byte lane */
val &= ~(0xFF << 16);
val |= txdqs << 16;
@@ -506,7 +1941,7 @@ static void LoadDQSSigTmgRegs_D(struct MCTStatStruc *pMCTstat,
val &= ~0xFF;
val |= txdqs;
}
- Set_NB32_index_wait(dev, 0x98 + 0x100*Channel, index, val);
+ Set_NB32_index_wait_DCT(dev, Channel, 0x98, index, val);
}
}
}
@@ -516,7 +1951,7 @@ static void LoadDQSSigTmgRegs_D(struct MCTStatStruc *pMCTstat,
for (Channel = 0; Channel < 2; Channel++) {
u8 *p;
- index_reg = 0x98 + Channel * 0x100;
+ index_reg = 0x98;
/* NOTE:
* when 400, 533, 667, it will support dimm0/1/2/3,
@@ -531,7 +1966,7 @@ static void LoadDQSSigTmgRegs_D(struct MCTStatStruc *pMCTstat,
if (DIMM == 0) {
index = 0; /* CHA Write Data Timing Low */
} else {
- if (pDCTstat->Speed >= 4) {
+ if (pDCTstat->Speed >= mhz_to_memclk_config(mctGet_NVbits(NV_MIN_MEMCLK))) {
index = 0x100 * DIMM;
} else {
break;
@@ -540,23 +1975,23 @@ static void LoadDQSSigTmgRegs_D(struct MCTStatStruc *pMCTstat,
for (Dir = 0; Dir < 2; Dir++) {/* RD/WR */
p = pDCTstat->CH_D_DIR_B_DQS[Channel][DIMM][Dir];
val = stream_to_int(p); /* CHA Read Data Timing High */
- Set_NB32_index_wait(dev, index_reg, index+1, val);
+ Set_NB32_index_wait_DCT(dev, Channel, index_reg, index+1, val);
val = stream_to_int(p+4); /* CHA Write Data Timing High */
- Set_NB32_index_wait(dev, index_reg, index+2, val);
+ Set_NB32_index_wait_DCT(dev, Channel, index_reg, index+2, val);
val = *(p+8); /* CHA Write ECC Timing */
- Set_NB32_index_wait(dev, index_reg, index+3, val);
+ Set_NB32_index_wait_DCT(dev, Channel, index_reg, index+3, val);
index += 4;
}
}
}
for (Channel = 0; Channel<2; Channel++) {
- reg = 0x78 + Channel * 0x100;
- val = Get_NB32(dev, reg);
+ reg = 0x78;
+ val = Get_NB32_DCT(dev, Channel, reg);
val &= ~(0x3ff<<22);
val |= ((u32) pDCTstat->CH_MaxRdLat[Channel] << 22);
val &= ~(1<<DqsRcvEnTrain);
- Set_NB32(dev, reg, val); /* program MaxRdLatency to correspond with current delay*/
+ Set_NB32_DCT(dev, Channel, reg, val); /* program MaxRdLatency to correspond with current delay*/
}
}
}
@@ -818,49 +2253,70 @@ finish:
return ret;
}
-static void DCTInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u8 dct)
+static void DCTPreInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u8 dct)
{
/*
- * Initialize DRAM on single Athlon 64/Opteron Node.
+ * Run DCT pre-initialization tasks
*/
- u8 stopDCTflag;
- u32 val;
+ uint32_t dword;
+ /* Reset DCT registers */
ClearDCT_D(pMCTstat, pDCTstat, dct);
- stopDCTflag = 1; /*preload flag with 'disable' */
- /* enable DDR3 support */
- val = Get_NB32(pDCTstat->dev_dct, 0x94 + dct * 0x100);
- val |= 1 << Ddr3Mode;
- Set_NB32(pDCTstat->dev_dct, 0x94 + dct * 0x100, val);
+ pDCTstat->stopDCT = 1; /*preload flag with 'disable' */
+
+ if (!is_fam15h()) {
+ /* Enable DDR3 support */
+ dword = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94);
+ dword |= 1 << Ddr3Mode;
+ Set_NB32_DCT(pDCTstat->dev_dct, dct, 0x94, dword);
+ }
+
+ /* Read the SPD information into the data structures */
if (mct_DIMMPresence(pMCTstat, pDCTstat, dct) < SC_StopError) {
printk(BIOS_DEBUG, "\t\tDCTInit_D: mct_DIMMPresence Done\n");
- if (mct_SPDCalcWidth(pMCTstat, pDCTstat, dct) < SC_StopError) {
- printk(BIOS_DEBUG, "\t\tDCTInit_D: mct_SPDCalcWidth Done\n");
- if (AutoCycTiming_D(pMCTstat, pDCTstat, dct) < SC_StopError) {
- printk(BIOS_DEBUG, "\t\tDCTInit_D: AutoCycTiming_D Done\n");
- if (AutoConfig_D(pMCTstat, pDCTstat, dct) < SC_StopError) {
- printk(BIOS_DEBUG, "\t\tDCTInit_D: AutoConfig_D Done\n");
- if (PlatformSpec_D(pMCTstat, pDCTstat, dct) < SC_StopError) {
- printk(BIOS_DEBUG, "\t\tDCTInit_D: PlatformSpec_D Done\n");
- stopDCTflag = 0;
- if (!(pMCTstat->GStatus & (1 << GSB_EnDIMMSpareNW))) {
- printk(BIOS_DEBUG, "\t\tDCTInit_D: StartupDCT_D\n");
- StartupDCT_D(pMCTstat, pDCTstat, dct); /*yeaahhh! */
- }
+ }
+}
+
+static void DCTInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u8 dct)
+{
+ /*
+ * Initialize DRAM on single Athlon 64/Opteron Node.
+ */
+ uint32_t dword;
+
+ if (!is_fam15h()) {
+ /* (Re)-enable DDR3 support */
+ dword = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94);
+ dword |= 1 << Ddr3Mode;
+ Set_NB32_DCT(pDCTstat->dev_dct, dct, 0x94, dword);
+ }
+
+ if (mct_SPDCalcWidth(pMCTstat, pDCTstat, dct) < SC_StopError) {
+ printk(BIOS_DEBUG, "\t\tDCTInit_D: mct_SPDCalcWidth Done\n");
+ if (AutoCycTiming_D(pMCTstat, pDCTstat, dct) < SC_StopError) {
+ printk(BIOS_DEBUG, "\t\tDCTInit_D: AutoCycTiming_D Done\n");
+ if (AutoConfig_D(pMCTstat, pDCTstat, dct) < SC_StopError) {
+ printk(BIOS_DEBUG, "\t\tDCTInit_D: AutoConfig_D Done\n");
+ if (PlatformSpec_D(pMCTstat, pDCTstat, dct) < SC_StopError) {
+ printk(BIOS_DEBUG, "\t\tDCTInit_D: PlatformSpec_D Done\n");
+ pDCTstat->stopDCT = 0;
+ if (!(pMCTstat->GStatus & (1 << GSB_EnDIMMSpareNW))) {
+ printk(BIOS_DEBUG, "\t\tDCTInit_D: StartupDCT_D\n");
+ StartupDCT_D(pMCTstat, pDCTstat, dct); /*yeaahhh! */
}
}
}
}
}
- if (stopDCTflag) {
- u32 reg_off = dct * 0x100;
- val = 1<<DisDramInterface;
- Set_NB32(pDCTstat->dev_dct, reg_off+0x94, val);
- /*To maximize power savings when DisDramInterface=1b,
- all of the MemClkDis bits should also be set.*/
- val = 0xFF000000;
- Set_NB32(pDCTstat->dev_dct, reg_off+0x88, val);
+ if (pDCTstat->stopDCT) {
+ dword = 1 << DisDramInterface;
+ Set_NB32_DCT(pDCTstat->dev_dct, dct, 0x94, dword);
+
+ /* To maximize power savings when DisDramInterface=1b,
+ * all of the MemClkDis bits should also be set.
+ */
+ Set_NB32_DCT(pDCTstat->dev_dct, dct, 0x88, 0xff000000);
} else {
mct_EnDllShutdownSR(pMCTstat, pDCTstat, dct);
}
@@ -882,20 +2338,24 @@ static void SyncDCTsReady_D(struct MCTStatStruc *pMCTstat,
pDCTstat = pDCTstatA + Node;
mct_SyncDCTsReady(pDCTstat);
}
- /* v6.1.3 */
- /* re-enable phy compensation engine when dram init is completed on all nodes. */
- for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
- struct DCTStatStruc *pDCTstat;
- pDCTstat = pDCTstatA + Node;
- if (pDCTstat->NodePresent) {
- if (pDCTstat->DIMMValidDCT[0] > 0 || pDCTstat->DIMMValidDCT[1] > 0) {
- /* re-enable phy compensation engine when dram init on both DCTs is completed. */
- val = Get_NB32_index_wait(pDCTstat->dev_dct, 0x98, 0x8);
- val &= ~(1 << DisAutoComp);
- Set_NB32_index_wait(pDCTstat->dev_dct, 0x98, 0x8, val);
+
+ if (!is_fam15h()) {
+ /* v6.1.3 */
+ /* re-enable phy compensation engine when dram init is completed on all nodes. */
+ for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+ struct DCTStatStruc *pDCTstat;
+ pDCTstat = pDCTstatA + Node;
+ if (pDCTstat->NodePresent) {
+ if (pDCTstat->DIMMValidDCT[0] > 0 || pDCTstat->DIMMValidDCT[1] > 0) {
+ /* re-enable phy compensation engine when dram init on both DCTs is completed. */
+ val = Get_NB32_index_wait(pDCTstat->dev_dct, 0x98, 0x8);
+ val &= ~(1 << DisAutoComp);
+ Set_NB32_index_wait(pDCTstat->dev_dct, 0x98, 0x8, val);
+ }
}
}
}
+
/* wait 750us before any memory access can be made. */
mct_Wait(15000);
}
@@ -917,10 +2377,9 @@ static void StartupDCT_D(struct MCTStatStruc *pMCTstat,
*/
u32 val;
u32 dev;
- u32 reg_off = dct * 0x100;
dev = pDCTstat->dev_dct;
- val = Get_NB32(dev, 0x94 + reg_off);
+ val = Get_NB32_DCT(dev, dct, 0x94);
if (val & (1<<MemClkFreqVal)) {
mctHookBeforeDramInit(); /* generalized Hook */
if (!(pMCTstat->GStatus & (1 << GSB_EnDIMMSpareNW)))
@@ -935,23 +2394,23 @@ static void ClearDCT_D(struct MCTStatStruc *pMCTstat,
{
u32 reg_end;
u32 dev = pDCTstat->dev_dct;
- u32 reg = 0x40 + 0x100 * dct;
+ u32 reg = 0x40;
u32 val = 0;
if (pMCTstat->GStatus & (1 << GSB_EnDIMMSpareNW)) {
- reg_end = 0x78 + 0x100 * dct;
+ reg_end = 0x78;
} else {
- reg_end = 0xA4 + 0x100 * dct;
+ reg_end = 0xA4;
}
while(reg < reg_end) {
if ((reg & 0xFF) == 0x90) {
if (pDCTstat->LogicalCPUID & AMD_DR_Dx) {
- val = Get_NB32(dev, reg); /* get DRAMConfigLow */
+ val = Get_NB32_DCT(dev, dct, reg); /* get DRAMConfigLow */
val |= 0x08000000; /* preserve value of DisDllShutdownSR for only Rev.D */
}
}
- Set_NB32(dev, reg, val);
+ Set_NB32_DCT(dev, dct, reg, val);
val = 0;
reg += 4;
}
@@ -970,6 +2429,7 @@ static void SPD2ndTiming(struct MCTStatStruc *pMCTstat,
u16 Trp, Trrd, Trcd, Tras, Trc;
u8 Trfc[4];
u16 Tfaw;
+ u16 Tcwl; /* Fam15h only */
u32 DramTimingLo, DramTimingHi;
u8 tCK16x;
u16 Twtr;
@@ -978,10 +2438,11 @@ static void SPD2ndTiming(struct MCTStatStruc *pMCTstat,
u8 byte;
u32 dword;
u32 dev;
- u32 reg_off;
u32 val;
u16 smbaddr;
+ printk(BIOS_DEBUG, "%s: Start\n", __func__);
+
/* Gather all DIMM mini-max values for cycle timing data */
Trp = 0;
Trrd = 0;
@@ -1194,88 +2655,164 @@ static void SPD2ndTiming(struct MCTStatStruc *pMCTstat,
mctAdjustAutoCycTmg_D();
+ if (is_fam15h()) {
+ /* Compute Tcwl (Fam15h BKDG v3.14 Table 203) */
+ if (pDCTstat->Speed <= 0x6)
+ Tcwl = 0x5;
+ else if (pDCTstat->Speed == 0xa)
+ Tcwl = 0x6;
+ else if (pDCTstat->Speed == 0xe)
+ Tcwl = 0x7;
+ else if (pDCTstat->Speed == 0x12)
+ Tcwl = 0x8;
+ else if (pDCTstat->Speed == 0x16)
+ Tcwl = 0x9;
+ else
+ Tcwl = 0x5; /* Power-on default */
+ }
+
/* Program DRAM Timing values */
- DramTimingLo = 0; /* Dram Timing Low init */
- val = pDCTstat->CASL - 4; /* pDCTstat.CASL to reg. definition */
- DramTimingLo |= val;
+ if (is_fam15h()) {
+ dev = pDCTstat->dev_dct;
- val = pDCTstat->Trcd - Bias_TrcdT;
- DramTimingLo |= val<<4;
+ dword = Get_NB32_DCT(dev, dct, 0x8c); /* DRAM Timing High */
+ val = 2; /* Tref = 7.8us */
+ dword &= ~(0x3 << 16);
+ dword |= (val & 0x3) << 16;
+ Set_NB32_DCT(dev, dct, 0x8c, dword); /* DRAM Timing High */
+
+ dword = Get_NB32_DCT(dev, dct, 0x200); /* DRAM Timing 0 */
+ dword &= ~(0x3f1f1f1f);
+ dword |= ((pDCTstat->Tras + 0xf) & 0x3f) << 24; /* Tras */
+ dword |= ((pDCTstat->Trp + 0x5) & 0x1f) << 16; /* Trp */
+ dword |= ((pDCTstat->Trcd + 0x5) & 0x1f) << 8; /* Trcd */
+ dword |= (pDCTstat->CASL & 0x1f); /* Tcl */
+ Set_NB32_DCT(dev, dct, 0x200, dword); /* DRAM Timing 0 */
+
+ dword = Get_NB32_DCT(dev, dct, 0x204); /* DRAM Timing 1 */
+ dword &= ~(0x0f3f0f3f);
+ dword |= ((pDCTstat->Trtp + 0x4) & 0xf) << 24; /* Trtp */
+ if (pDCTstat->Tfaw != 0)
+ dword |= ((((pDCTstat->Tfaw - 0x1) * 2) + 0x10) & 0x3f) << 16; /* FourActWindow */
+ dword |= ((pDCTstat->Trrd + 0x4) & 0xf) << 8; /* Trrd */
+ dword |= ((pDCTstat->Trc + 0xb) & 0x3f); /* Trc */
+ Set_NB32_DCT(dev, dct, 0x204, dword); /* DRAM Timing 1 */
+
+ dword = Get_NB32_DCT(dev, dct, 0x208); /* DRAM Timing 2 */
+ dword &= ~(0x07070707);
+ dword |= (pDCTstat->Trfc[3] & 0x7) << 24; /* Trfc3 */
+ dword |= (pDCTstat->Trfc[2] & 0x7) << 16; /* Trfc2 */
+ dword |= (pDCTstat->Trfc[1] & 0x7) << 8; /* Trfc1 */
+ dword |= (pDCTstat->Trfc[0] & 0x7); /* Trfc0 */
+ Set_NB32_DCT(dev, dct, 0x208, dword); /* DRAM Timing 2 */
+
+ dword = Get_NB32_DCT(dev, dct, 0x20c); /* DRAM Timing 3 */
+ dword &= ~(0x00000f00);
+ dword |= ((pDCTstat->Twtr + 0x4) & 0xf) << 8; /* Twtr */
+ dword &= ~(0x0000001f);
+ dword |= (Tcwl & 0x1f); /* Tcwl */
+ Set_NB32_DCT(dev, dct, 0x20c, dword); /* DRAM Timing 3 */
+
+ dword = Get_NB32_DCT(dev, dct, 0x22c); /* DRAM Timing 10 */
+ dword &= ~(0x0000001f);
+ dword |= ((pDCTstat->Twr + 0x4) & 0x1f); /* Twr */
+ Set_NB32_DCT(dev, dct, 0x22c, dword); /* DRAM Timing 10 */
+
+ if (pDCTstat->Speed > mhz_to_memclk_config(mctGet_NVbits(NV_MIN_MEMCLK))) {
+ /* Enable phy-assisted training mode */
+ fam15EnableTrainingMode(pMCTstat, pDCTstat, dct, 1);
+ }
- val = pDCTstat->Trp - Bias_TrpT;
- val = mct_AdjustSPDTimings(pMCTstat, pDCTstat, val);
- DramTimingLo |= val<<7;
+ /* Other setup (not training specific) */
+ dword = Get_NB32_DCT(dev, dct, 0x90); /* DRAM Configuration Low */
+ dword &= ~(0x1 << 23); /* ForceAutoPchg = 0 */
+ dword &= ~(0x1 << 20); /* DynPageCloseEn = 0 */
+ Set_NB32_DCT(dev, dct, 0x90, dword); /* DRAM Configuration Low */
- val = pDCTstat->Trtp - Bias_TrtpT;
- DramTimingLo |= val<<10;
+ Set_NB32_DCT(dev, dct, 0x228, 0x14141414); /* DRAM Timing 9 */
+ } else {
+ DramTimingLo = 0; /* Dram Timing Low init */
+ val = pDCTstat->CASL - 4; /* pDCTstat.CASL to reg. definition */
+ DramTimingLo |= val;
- val = pDCTstat->Tras - Bias_TrasT;
- DramTimingLo |= val<<12;
+ val = pDCTstat->Trcd - Bias_TrcdT;
+ DramTimingLo |= val<<4;
- val = pDCTstat->Trc - Bias_TrcT;
- DramTimingLo |= val<<16;
+ val = pDCTstat->Trp - Bias_TrpT;
+ val = mct_AdjustSPDTimings(pMCTstat, pDCTstat, val);
+ DramTimingLo |= val<<7;
- val = pDCTstat->Trrd - Bias_TrrdT;
- DramTimingLo |= val<<22;
+ val = pDCTstat->Trtp - Bias_TrtpT;
+ DramTimingLo |= val<<10;
- DramTimingHi = 0; /* Dram Timing High init */
- val = pDCTstat->Twtr - Bias_TwtrT;
- DramTimingHi |= val<<8;
+ val = pDCTstat->Tras - Bias_TrasT;
+ DramTimingLo |= val<<12;
- val = 2;
- DramTimingHi |= val<<16;
+ val = pDCTstat->Trc - Bias_TrcT;
+ DramTimingLo |= val<<16;
- val = 0;
- for (i=4;i>0;i--) {
- val <<= 3;
- val |= Trfc[i-1];
- }
- DramTimingHi |= val << 20;
+ val = pDCTstat->Trrd - Bias_TrrdT;
+ DramTimingLo |= val<<22;
- dev = pDCTstat->dev_dct;
- reg_off = 0x100 * dct;
- /* Twr */
- val = pDCTstat->Twr;
- if (val == 10)
- val = 9;
- else if (val == 12)
- val = 10;
- val = mct_AdjustSPDTimings(pMCTstat, pDCTstat, val);
- val -= Bias_TwrT;
- val <<= 4;
- dword = Get_NB32(dev, 0x84 + reg_off);
- dword &= ~0x70;
- dword |= val;
- Set_NB32(dev, 0x84 + reg_off, dword);
+ DramTimingHi = 0; /* Dram Timing High init */
+ val = pDCTstat->Twtr - Bias_TwtrT;
+ DramTimingHi |= val<<8;
- /* Tfaw */
- val = pDCTstat->Tfaw;
- val = mct_AdjustSPDTimings(pMCTstat, pDCTstat, val);
- val -= Bias_TfawT;
- val >>= 1;
- val <<= 28;
- dword = Get_NB32(dev, 0x94 + reg_off);
- dword &= ~0xf0000000;
- dword |= val;
- Set_NB32(dev, 0x94 + reg_off, dword);
-
- /* dev = pDCTstat->dev_dct; */
- /* reg_off = 0x100 * dct; */
-
- if (pDCTstat->Speed > 4) {
- val = Get_NB32(dev, 0x88 + reg_off);
- val &= 0xFF000000;
- DramTimingLo |= val;
- }
- Set_NB32(dev, 0x88 + reg_off, DramTimingLo); /*DCT Timing Low*/
+ val = 2; /* Tref = 7.8us */
+ DramTimingHi |= val<<16;
+
+ val = 0;
+ for (i=4;i>0;i--) {
+ val <<= 3;
+ val |= Trfc[i-1];
+ }
+ DramTimingHi |= val << 20;
- if (pDCTstat->Speed > 4) {
- DramTimingHi |= 1 << DisAutoRefresh;
+ dev = pDCTstat->dev_dct;
+ /* Twr */
+ val = pDCTstat->Twr;
+ if (val == 10)
+ val = 9;
+ else if (val == 12)
+ val = 10;
+ val = mct_AdjustSPDTimings(pMCTstat, pDCTstat, val);
+ val -= Bias_TwrT;
+ val <<= 4;
+ dword = Get_NB32_DCT(dev, dct, 0x84);
+ dword &= ~0x70;
+ dword |= val;
+ Set_NB32_DCT(dev, dct, 0x84, dword);
+
+ /* Tfaw */
+ val = pDCTstat->Tfaw;
+ val = mct_AdjustSPDTimings(pMCTstat, pDCTstat, val);
+ val -= Bias_TfawT;
+ val >>= 1;
+ val <<= 28;
+ dword = Get_NB32_DCT(dev, dct, 0x94);
+ dword &= ~0xf0000000;
+ dword |= val;
+ Set_NB32_DCT(dev, dct, 0x94, dword);
+
+ /* dev = pDCTstat->dev_dct; */
+
+ if (pDCTstat->Speed > mhz_to_memclk_config(mctGet_NVbits(NV_MIN_MEMCLK))) {
+ val = Get_NB32_DCT(dev, dct, 0x88);
+ val &= 0xFF000000;
+ DramTimingLo |= val;
+ }
+ Set_NB32_DCT(dev, dct, 0x88, DramTimingLo); /*DCT Timing Low*/
+
+ if (pDCTstat->Speed > mhz_to_memclk_config(mctGet_NVbits(NV_MIN_MEMCLK))) {
+ DramTimingHi |= 1 << DisAutoRefresh;
+ }
+ DramTimingHi |= 0x000018FF;
+ Set_NB32_DCT(dev, dct, 0x8c, DramTimingHi); /*DCT Timing Hi*/
}
- DramTimingHi |= 0x000018FF;
- Set_NB32(dev, 0x8c + reg_off, DramTimingHi); /*DCT Timing Hi*/
/* dump_pci_device(PCI_DEV(0, 0x18+pDCTstat->Node_ID, 2)); */
+
+ printk(BIOS_DEBUG, "%s: Done\n", __func__);
}
static u8 AutoCycTiming_D(struct MCTStatStruc *pMCTstat,
@@ -1309,6 +2846,8 @@ static u8 AutoCycTiming_D(struct MCTStatStruc *pMCTstat,
* timing mode is 'Auto'.
*/
+ printk(BIOS_DEBUG, "%s: Start\n", __func__);
+
/* Get primary timing (CAS Latency and Cycle Time) */
if (pDCTstat->Speed == 0) {
mctGet_MaxLoadFreq(pDCTstat);
@@ -1318,6 +2857,7 @@ static u8 AutoCycTiming_D(struct MCTStatStruc *pMCTstat,
/* Go get best T and CL as specified by DIMM mfgs. and OEM */
SPDGetTCL_D(pMCTstat, pDCTstat, dct);
+
/* skip callback mctForce800to1067_D */
pDCTstat->Speed = pDCTstat->DIMMAutoSpeed;
pDCTstat->CASL = pDCTstat->DIMMCASL;
@@ -1350,7 +2890,10 @@ static void GetPresetmaxF_D(struct MCTStatStruc *pMCTstat,
u16 word;
/* Get CPU Si Revision defined limit (NPT) */
- proposedFreq = 800; /* Rev F0 programmable max memclock is */
+ if (is_fam15h())
+ proposedFreq = 933;
+ else
+ proposedFreq = 800; /* Rev F0 programmable max memclock is */
/*Get User defined limit if "limit" mode */
if ( mctGet_NVbits(NV_MCTUSRTMGMODE) == 1) {
@@ -1387,6 +2930,7 @@ static void SPDGetTCL_D(struct MCTStatStruc *pMCTstat,
u16 tCKmin16x;
u16 tCKproposed16x;
u8 CLactual, CLdesired, CLT_Fail;
+ uint16_t min_frequency_tck16x;
u8 smbaddr, byte = 0, bytex = 0;
@@ -1396,6 +2940,17 @@ static void SPDGetTCL_D(struct MCTStatStruc *pMCTstat,
tCKmin16x = 0;
CLT_Fail = 0;
+ printk(BIOS_DEBUG, "%s: Start\n", __func__);
+
+ if (is_fam15h()) {
+ uint16_t minimum_frequency_mhz = mctGet_NVbits(NV_MIN_MEMCLK);
+ if (minimum_frequency_mhz == 0)
+ minimum_frequency_mhz = 333;
+ min_frequency_tck16x = 16000 / minimum_frequency_mhz;
+ } else {
+ min_frequency_tck16x = 40;
+ }
+
for (i = 0; i < MAX_DIMMS_SUPPORTED; i++) {
if (pDCTstat->DIMMValid & (1 << i)) {
smbaddr = Get_DIMMAddress_D(pDCTstat, (dct + i));
@@ -1425,27 +2980,44 @@ static void SPDGetTCL_D(struct MCTStatStruc *pMCTstat,
tCKmin16x = byte * MTB16x;
}
}
- /* calculate tCKproposed16x */
+ /* calculate tCKproposed16x (proposed clock period in ns * 16) */
tCKproposed16x = 16000 / pDCTstat->PresetmaxFreq;
if (tCKmin16x > tCKproposed16x)
tCKproposed16x = tCKmin16x;
- /* mctHookTwo1333DimmOverride(); */
- /* For UDIMM, if there are two DDR3-1333 on the same channel,
- downgrade DDR speed to 1066. */
-
/* TODO: get user manual tCK16x(Freq.) and overwrite current tCKproposed16x if manual. */
- if (tCKproposed16x == 20)
- pDCTstat->TargetFreq = 7;
- else if (tCKproposed16x <= 24) {
- pDCTstat->TargetFreq = 6;
- tCKproposed16x = 24;
- } else if (tCKproposed16x <= 30) {
- pDCTstat->TargetFreq = 5;
- tCKproposed16x = 30;
+ if (is_fam15h()) {
+ if (tCKproposed16x == 17)
+ pDCTstat->TargetFreq = 0x16;
+ else if (tCKproposed16x <= 20) {
+ pDCTstat->TargetFreq = 0x12;
+ tCKproposed16x = 20;
+ } else if (tCKproposed16x <= 24) {
+ pDCTstat->TargetFreq = 0xe;
+ tCKproposed16x = 24;
+ } else if (tCKproposed16x <= 30) {
+ pDCTstat->TargetFreq = 0xa;
+ tCKproposed16x = 30;
+ } else if (tCKproposed16x <= 40) {
+ pDCTstat->TargetFreq = 0x6;
+ tCKproposed16x = 40;
+ } else {
+ pDCTstat->TargetFreq = 0x4;
+ tCKproposed16x = 48;
+ }
} else {
- pDCTstat->TargetFreq = 4;
- tCKproposed16x = 40;
+ if (tCKproposed16x == 20)
+ pDCTstat->TargetFreq = 7;
+ else if (tCKproposed16x <= 24) {
+ pDCTstat->TargetFreq = 6;
+ tCKproposed16x = 24;
+ } else if (tCKproposed16x <= 30) {
+ pDCTstat->TargetFreq = 5;
+ tCKproposed16x = 30;
+ } else {
+ pDCTstat->TargetFreq = 4;
+ tCKproposed16x = 40;
+ }
}
/* Running through this loop twice:
- First time find tCL at target frequency
@@ -1484,27 +3056,42 @@ static void SPDGetTCL_D(struct MCTStatStruc *pMCTstat,
/* get CL and T */
if (!CLT_Fail) {
bytex = CLactual;
- if (tCKproposed16x == 20)
- byte = 7;
- else if (tCKproposed16x == 24)
- byte = 6;
- else if (tCKproposed16x == 30)
- byte = 5;
- else
- byte = 4;
+ if (is_fam15h()) {
+ if (tCKproposed16x == 17)
+ byte = 0x16;
+ else if (tCKproposed16x == 20)
+ byte = 0x12;
+ else if (tCKproposed16x == 24)
+ byte = 0xe;
+ else if (tCKproposed16x == 30)
+ byte = 0xa;
+ else if (tCKproposed16x == 40)
+ byte = 0x6;
+ else
+ byte = 0x4;
+ } else {
+ if (tCKproposed16x == 20)
+ byte = 7;
+ else if (tCKproposed16x == 24)
+ byte = 6;
+ else if (tCKproposed16x == 30)
+ byte = 5;
+ else
+ byte = 4;
+ }
} else {
/* mctHookManualCLOverride */
/* TODO: */
}
- if (tCKproposed16x != 40) {
+ if (tCKproposed16x != min_frequency_tck16x) {
if (pMCTstat->GStatus & (1 << GSB_EnDIMMSpareNW)) {
pDCTstat->DIMMAutoSpeed = byte;
pDCTstat->DIMMCASL = bytex;
break;
} else {
pDCTstat->TargetCASL = bytex;
- tCKproposed16x = 40;
+ tCKproposed16x = min_frequency_tck16x;
}
} else {
pDCTstat->DIMMAutoSpeed = byte;
@@ -1525,29 +3112,21 @@ static void SPDGetTCL_D(struct MCTStatStruc *pMCTstat,
static u8 PlatformSpec_D(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat, u8 dct)
{
- u32 dev;
- u32 reg;
- u32 val;
+ if (!is_fam15h()) {
+ mctGet_PS_Cfg_D(pMCTstat, pDCTstat, dct);
- mctGet_PS_Cfg_D(pMCTstat, pDCTstat, dct);
+ if (pDCTstat->GangedMode == 1) {
+ mctGet_PS_Cfg_D(pMCTstat, pDCTstat, 1);
+ mct_BeforePlatformSpec(pMCTstat, pDCTstat, 1);
+ }
- if (pDCTstat->GangedMode == 1) {
- mctGet_PS_Cfg_D(pMCTstat, pDCTstat, 1);
- mct_BeforePlatformSpec(pMCTstat, pDCTstat, 1);
- }
+ set_2t_configuration(pMCTstat, pDCTstat, dct);
- if ( pDCTstat->_2Tmode == 2) {
- dev = pDCTstat->dev_dct;
- reg = 0x94 + 0x100 * dct; /* Dram Configuration Hi */
- val = Get_NB32(dev, reg);
- val |= 1 << 20; /* 2T CMD mode */
- Set_NB32(dev, reg, val);
+ mct_BeforePlatformSpec(pMCTstat, pDCTstat, dct);
+ mct_PlatformSpec(pMCTstat, pDCTstat, dct);
+ if (pDCTstat->DIMMAutoSpeed == mhz_to_memclk_config(mctGet_NVbits(NV_MIN_MEMCLK)))
+ InitPhyCompensation(pMCTstat, pDCTstat, dct);
}
-
- mct_BeforePlatformSpec(pMCTstat, pDCTstat, dct);
- mct_PlatformSpec(pMCTstat, pDCTstat, dct);
- if (pDCTstat->DIMMAutoSpeed == 4)
- InitPhyCompensation(pMCTstat, pDCTstat, dct);
mctHookAfterPSCfg();
return pDCTstat->ErrCode;
@@ -1559,11 +3138,11 @@ static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat,
u32 DramControl, DramTimingLo, Status;
u32 DramConfigLo, DramConfigHi, DramConfigMisc, DramConfigMisc2;
u32 val;
- u32 reg_off;
u32 dev;
u16 word;
u32 dword;
u8 byte;
+ uint32_t offset;
DramConfigLo = 0;
DramConfigHi = 0;
@@ -1583,12 +3162,10 @@ static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat,
Status = pDCTstat->Status;
dev = pDCTstat->dev_dct;
- reg_off = 0x100 * dct;
-
/* Build Dram Control Register Value */
- DramConfigMisc2 = Get_NB32 (dev, 0xA8 + reg_off); /* Dram Control*/
- DramControl = Get_NB32 (dev, 0x78 + reg_off); /* Dram Control*/
+ DramConfigMisc2 = Get_NB32_DCT(dev, dct, 0xA8); /* Dram Control*/
+ DramControl = Get_NB32_DCT(dev, dct, 0x78); /* Dram Control*/
/* FIXME: Skip mct_checkForDxSupport */
/* REV_CALL mct_DoRdPtrInit if not Dx */
@@ -1630,8 +3207,12 @@ static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat,
DramConfigLo = mct_DisDllShutdownSR(pMCTstat, pDCTstat, DramConfigLo, dct);
/* Build Dram Config Hi Register Value */
+ if (is_fam15h())
+ offset = 0x0;
+ else
+ offset = 0x1;
dword = pDCTstat->Speed;
- DramConfigHi |= dword - 1; /* get MemClk encoding */
+ DramConfigHi |= dword - offset; /* get MemClk encoding */
DramConfigHi |= 1 << MemClkFreqVal;
if (Status & (1 << SB_Registered))
@@ -1664,7 +3245,7 @@ static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat,
val = 0x0f; /* recommended setting (default) */
DramConfigHi |= val << 24;
- if (pDCTstat->LogicalCPUID & (AMD_DR_Dx | AMD_DR_Cx | AMD_DR_Bx))
+ if (pDCTstat->LogicalCPUID & (AMD_DR_Dx | AMD_DR_Cx | AMD_DR_Bx | AMD_FAM15_ALL))
DramConfigHi |= 1 << DcqArbBypassEn;
/* Build MemClkDis Value from Dram Timing Lo and
@@ -1675,7 +3256,7 @@ static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat,
NV_AllMemClks <>0 AND SB_DiagClks ==0 */
/* Dram Timing Low (owns Clock Enable bits) */
- DramTimingLo = Get_NB32(dev, 0x88 + reg_off);
+ DramTimingLo = Get_NB32_DCT(dev, dct, 0x88);
if (mctGet_NVbits(NV_AllMemClks) == 0) {
/* Special Jedec SPD diagnostic bit - "enable all clocks" */
if (!(pDCTstat->Status & (1<<SB_DiagClks))) {
@@ -1706,28 +3287,34 @@ static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat,
}
dword++ ;
}
+ DramTimingLo &= ~(0xff << 24);
DramTimingLo |= byte << 24;
}
}
- printk(BIOS_DEBUG, "AutoConfig_D: DramControl: %x\n", DramControl);
- printk(BIOS_DEBUG, "AutoConfig_D: DramTimingLo: %x\n", DramTimingLo);
- printk(BIOS_DEBUG, "AutoConfig_D: DramConfigMisc: %x\n", DramConfigMisc);
- printk(BIOS_DEBUG, "AutoConfig_D: DramConfigMisc2: %x\n", DramConfigMisc2);
- printk(BIOS_DEBUG, "AutoConfig_D: DramConfigLo: %x\n", DramConfigLo);
- printk(BIOS_DEBUG, "AutoConfig_D: DramConfigHi: %x\n", DramConfigHi);
+ printk(BIOS_DEBUG, "AutoConfig_D: DramControl: %08x\n", DramControl);
+ printk(BIOS_DEBUG, "AutoConfig_D: DramTimingLo: %08x\n", DramTimingLo);
+ printk(BIOS_DEBUG, "AutoConfig_D: DramConfigMisc: %08x\n", DramConfigMisc);
+ printk(BIOS_DEBUG, "AutoConfig_D: DramConfigMisc2: %08x\n", DramConfigMisc2);
+ printk(BIOS_DEBUG, "AutoConfig_D: DramConfigLo: %08x\n", DramConfigLo);
+ printk(BIOS_DEBUG, "AutoConfig_D: DramConfigHi: %08x\n", DramConfigHi);
/* Write Values to the registers */
- Set_NB32(dev, 0x78 + reg_off, DramControl);
- Set_NB32(dev, 0x88 + reg_off, DramTimingLo);
- Set_NB32(dev, 0xA0 + reg_off, DramConfigMisc);
+ Set_NB32_DCT(dev, dct, 0x78, DramControl);
+ Set_NB32_DCT(dev, dct, 0x88, DramTimingLo);
+ Set_NB32_DCT(dev, dct, 0xa0, DramConfigMisc);
DramConfigMisc2 = mct_SetDramConfigMisc2(pDCTstat, dct, DramConfigMisc2);
- Set_NB32(dev, 0xA8 + reg_off, DramConfigMisc2);
- Set_NB32(dev, 0x90 + reg_off, DramConfigLo);
+ Set_NB32_DCT(dev, dct, 0xa8, DramConfigMisc2);
+ Set_NB32_DCT(dev, dct, 0x90, DramConfigLo);
ProgDramMRSReg_D(pMCTstat, pDCTstat, dct);
- dword = Get_NB32(dev, 0x94 + reg_off);
+
+ if (is_fam15h())
+ InitDDRPhy(pMCTstat, pDCTstat, dct);
+
+ /* Write the DRAM Configuration High register, including memory frequency change */
+ dword = Get_NB32_DCT(dev, dct, 0x94);
DramConfigHi |= dword;
- mct_SetDramConfigHi_D(pDCTstat, dct, DramConfigHi);
+ mct_SetDramConfigHi_D(pMCTstat, pDCTstat, dct, DramConfigHi);
mct_EarlyArbEn_D(pMCTstat, pDCTstat, dct);
mctHookAfterAutoCfg();
@@ -1737,6 +3324,7 @@ static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat,
printk(BIOS_DEBUG, "AutoConfig: ErrStatus %x\n", pDCTstat->ErrStatus);
printk(BIOS_DEBUG, "AutoConfig: ErrCode %x\n", pDCTstat->ErrCode);
printk(BIOS_DEBUG, "AutoConfig: Done\n\n");
+
AutoConfig_exit:
return pDCTstat->ErrCode;
}
@@ -1754,14 +3342,12 @@ static void SPDSetBanks_D(struct MCTStatStruc *pMCTstat,
u32 val;
u32 reg;
u32 dev;
- u32 reg_off;
u8 byte;
u16 word;
u32 dword;
u16 smbaddr;
dev = pDCTstat->dev_dct;
- reg_off = 0x100 * dct;
BankAddrReg = 0;
for (ChipSel = 0; ChipSel < MAX_CS_SUPPORTED; ChipSel+=2) {
@@ -1826,10 +3412,10 @@ static void SPDSetBanks_D(struct MCTStatStruc *pMCTstat,
/*set ChipSelect population indicator odd bits*/
pDCTstat->CSPresent |= 1 << (ChipSel + 1);
- reg = 0x60+(ChipSel<<1) + reg_off; /*Dram CS Mask Register */
+ reg = 0x60+(ChipSel<<1); /*Dram CS Mask Register */
val = csMask;
val &= 0x1FF83FE0; /* Mask out reserved bits.*/
- Set_NB32(dev, reg, val);
+ Set_NB32_DCT(dev, dct, reg, val);
} else {
if (pDCTstat->DIMMSPDCSE & (1<<ChipSel))
pDCTstat->CSTestFail |= (1<<ChipSel);
@@ -1853,8 +3439,8 @@ static void SPDSetBanks_D(struct MCTStatStruc *pMCTstat,
if (!pDCTstat->CSPresent)
pDCTstat->ErrCode = SC_StopError;
- reg = 0x80 + reg_off; /* Bank Addressing Register */
- Set_NB32(dev, reg, BankAddrReg);
+ reg = 0x80; /* Bank Addressing Register */
+ Set_NB32_DCT(dev, dct, reg, BankAddrReg);
pDCTstat->CSPresent_DCT[dct] = pDCTstat->CSPresent;
/* dump_pci_device(PCI_DEV(0, 0x18+pDCTstat->Node_ID, 2)); */
@@ -1939,11 +3525,9 @@ static void StitchMemory_D(struct MCTStatStruc *pMCTstat,
u16 word;
u32 dev;
u32 reg;
- u32 reg_off;
u32 val;
dev = pDCTstat->dev_dct;
- reg_off = 0x100 * dct;
_DSpareEn = 0;
@@ -1980,11 +3564,11 @@ static void StitchMemory_D(struct MCTStatStruc *pMCTstat,
BiggestBank = 0;
for (q = 0; q < MAX_CS_SUPPORTED; q++) { /* from DIMMS to CS */
if (pDCTstat->CSPresent & (1 << q)) { /* bank present? */
- reg = 0x40 + (q << 2) + reg_off; /* Base[q] reg.*/
- val = Get_NB32(dev, reg);
+ reg = 0x40 + (q << 2); /* Base[q] reg.*/
+ val = Get_NB32_DCT(dev, dct, reg);
if (!(val & 3)) { /* (CSEnable|Spare==1)bank is enabled already? */
- reg = 0x60 + (q << 1) + reg_off; /*Mask[q] reg.*/
- val = Get_NB32(dev, reg);
+ reg = 0x60 + (q << 1); /*Mask[q] reg.*/
+ val = Get_NB32_DCT(dev, dct, reg);
val >>= 19;
val++;
val <<= 19;
@@ -2000,7 +3584,7 @@ static void StitchMemory_D(struct MCTStatStruc *pMCTstat,
if (BiggestBank !=0) {
curcsBase = nxtcsBase; /* curcsBase=nxtcsBase*/
/* DRAM CS Base b Address Register offset */
- reg = 0x40 + (b << 2) + reg_off;
+ reg = 0x40 + (b << 2);
if (_DSpareEn) {
BiggestBank = 0;
val = 1 << Spare; /* Spare Enable*/
@@ -2019,7 +3603,7 @@ static void StitchMemory_D(struct MCTStatStruc *pMCTstat,
}
}
}
- Set_NB32(dev, reg, val);
+ Set_NB32_DCT(dev, dct, reg, val);
if (_DSpareEn)
_DSpareEn = 0;
else
@@ -2030,9 +3614,9 @@ static void StitchMemory_D(struct MCTStatStruc *pMCTstat,
/* bank present but disabled?*/
if ( pDCTstat->CSTestFail & (1 << p)) {
/* DRAM CS Base b Address Register offset */
- reg = (p << 2) + 0x40 + reg_off;
+ reg = (p << 2) + 0x40;
val = 1 << TestFail;
- Set_NB32(dev, reg, val);
+ Set_NB32_DCT(dev, dct, reg, val);
}
}
@@ -2070,7 +3654,7 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
u16 i, j, k;
u8 smbaddr;
u8 SPDCtrl;
- u16 RegDIMMPresent, MaxDimms;
+ u16 RegDIMMPresent, LRDIMMPresent, MaxDimms;
u8 devwidth;
u16 DimmSlots;
u8 byte = 0, bytex;
@@ -2083,6 +3667,7 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
SPDCtrl = mctGet_NVbits(NV_SPDCHK_RESTRT);
RegDIMMPresent = 0;
+ LRDIMMPresent = 0;
pDCTstat->DimmQRPresent = 0;
for (i = 0; i < MAX_DIMMS_SUPPORTED; i++) {
@@ -2121,6 +3706,7 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
pDCTstat->DimmManufacturerID[i] |= ((uint64_t)mctRead_SPD(smbaddr, SPD_MANID_START + k)) << (k * 8);
for (k = 0; k < SPD_PARTN_LENGTH; k++)
pDCTstat->DimmPartNumber[i][k] = mctRead_SPD(smbaddr, SPD_PARTN_START + k);
+ pDCTstat->DimmPartNumber[i][SPD_PARTN_LENGTH] = 0;
pDCTstat->DimmRevisionNumber[i] = 0;
for (k = 0; k < 2; k++)
pDCTstat->DimmRevisionNumber[i] |= ((uint16_t)mctRead_SPD(smbaddr, SPD_REVNO_START + k)) << (k * 8);
@@ -2144,6 +3730,12 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
} else {
pDCTstat->DimmRegistered[i] = 0;
}
+ if (byte == JED_LRDIMM) {
+ LRDIMMPresent |= 1 << i;
+ pDCTstat->DimmLoadReduced[i] = 1;
+ } else {
+ pDCTstat->DimmLoadReduced[i] = 0;
+ }
/* Check ECC capable */
byte = mctRead_SPD(smbaddr, SPD_BusWidth);
if (byte & JED_ECC) {
@@ -2227,6 +3819,7 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
printk(BIOS_DEBUG, "\t DIMMPresence: DIMMValid=%x\n", pDCTstat->DIMMValid);
printk(BIOS_DEBUG, "\t DIMMPresence: DIMMPresent=%x\n", pDCTstat->DIMMPresent);
printk(BIOS_DEBUG, "\t DIMMPresence: RegDIMMPresent=%x\n", RegDIMMPresent);
+ printk(BIOS_DEBUG, "\t DIMMPresence: LRDIMMPresent=%x\n", LRDIMMPresent);
printk(BIOS_DEBUG, "\t DIMMPresence: DimmECCPresent=%x\n", pDCTstat->DimmECCPresent);
printk(BIOS_DEBUG, "\t DIMMPresence: DimmPARPresent=%x\n", pDCTstat->DimmPARPresent);
printk(BIOS_DEBUG, "\t DIMMPresence: Dimmx4Present=%x\n", pDCTstat->Dimmx4Present);
@@ -2253,6 +3846,16 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
pDCTstat->Status |= 1<<SB_Registered;
}
}
+ if (LRDIMMPresent != 0) {
+ if ((LRDIMMPresent ^ pDCTstat->DIMMValid) !=0) {
+ /* module type DIMM mismatch (reg'ed, unbuffered) */
+ pDCTstat->ErrStatus |= 1<<SB_DimmMismatchM;
+ pDCTstat->ErrCode = SC_StopError;
+ } else{
+ /* all DIMMs are registered */
+ pDCTstat->Status |= 1<<SB_LoadReduced;
+ }
+ }
if (pDCTstat->DimmECCPresent != 0) {
if ((pDCTstat->DimmECCPresent ^ pDCTstat->DIMMValid )== 0) {
/* all DIMMs are ECC capable */
@@ -2290,6 +3893,26 @@ static u8 Get_DIMMAddress_D(struct DCTStatStruc *pDCTstat, u8 i)
return p[i];
}
+static void mct_preInitDCT(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat)
+{
+ u8 err_code;
+
+ /* Preconfigure DCT0 */
+ DCTPreInit_D(pMCTstat, pDCTstat, 0);
+
+ /* Configure DCT1 if unganged and enabled*/
+ if (!pDCTstat->GangedMode) {
+ if (pDCTstat->DIMMValidDCT[1] > 0) {
+ err_code = pDCTstat->ErrCode; /* save DCT0 errors */
+ pDCTstat->ErrCode = 0;
+ DCTPreInit_D(pMCTstat, pDCTstat, 1);
+ if (pDCTstat->ErrCode == 2) /* DCT1 is not Running */
+ pDCTstat->ErrCode = err_code; /* Using DCT0 Error code to update pDCTstat.ErrCode */
+ }
+ }
+}
+
static void mct_initDCT(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat)
{
@@ -2301,7 +3924,7 @@ static void mct_initDCT(struct MCTStatStruc *pMCTstat,
if (pDCTstat->ErrCode == SC_FatalErr) {
/* Do nothing goto exitDCTInit; any fatal errors? */
} else {
- /* Configure DCT1 if unganged and enabled*/
+ /* Configure DCT1 if unganged and enabled */
if (!pDCTstat->GangedMode) {
if (pDCTstat->DIMMValidDCT[1] > 0) {
err_code = pDCTstat->ErrCode; /* save DCT0 errors */
@@ -2311,17 +3934,21 @@ static void mct_initDCT(struct MCTStatStruc *pMCTstat,
pDCTstat->ErrCode = err_code; /* Using DCT0 Error code to update pDCTstat.ErrCode */
} else {
val = 1 << DisDramInterface;
- Set_NB32(pDCTstat->dev_dct, 0x100 + 0x94, val);
+ Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x94, val);
+
+ /* To maximize power savings when DisDramInterface=1b,
+ * all of the MemClkDis bits should also be set.
+ */
+ Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x88, 0xff000000);
}
}
}
-/* exitDCTInit: */
}
static void mct_DramInit(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat, u8 dct)
{
- mct_BeforeDramInit_Prod_D(pMCTstat, pDCTstat);
+ mct_BeforeDramInit_Prod_D(pMCTstat, pDCTstat, dct);
mct_DramInit_Sw_D(pMCTstat, pDCTstat, dct);
/* mct_DramInit_Hw_D(pMCTstat, pDCTstat, dct); */
}
@@ -2349,7 +3976,8 @@ static u8 mct_setMode(struct MCTStatStruc *pMCTstat,
if (byte)
pDCTstat->ErrStatus |= (1 << SB_DimmMismatchO); /* Set temp. to avoid setting of ganged mode */
- if (!(pDCTstat->ErrStatus & (1 << SB_DimmMismatchO))) {
+ if ((!(pDCTstat->ErrStatus & (1 << SB_DimmMismatchO))) && (pDCTstat->LogicalCPUID & AMD_FAM10_ALL)) {
+ /* Ganged channel mode not supported on Family 15h or higher */
pDCTstat->GangedMode = 1;
/* valid 128-bit mode population. */
pDCTstat->Status |= 1 << SB_128bitmode;
@@ -2393,10 +4021,8 @@ void Set_NB32_index(u32 dev, u32 index_reg, u32 index, u32 data)
u32 Get_NB32_index_wait(u32 dev, u32 index_reg, u32 index)
{
-
u32 dword;
-
index &= ~(1 << DctAccessWrite);
Set_NB32(dev, index_reg, index);
do {
@@ -2411,7 +4037,6 @@ void Set_NB32_index_wait(u32 dev, u32 index_reg, u32 index, u32 data)
{
u32 dword;
-
Set_NB32(dev, index_reg + 0x4, data);
index |= (1 << DctAccessWrite);
Set_NB32(dev, index_reg, index);
@@ -2426,16 +4051,17 @@ static u8 mct_BeforePlatformSpec(struct MCTStatStruc *pMCTstat,
{
/* mct_checkForCxDxSupport_D */
if (pDCTstat->LogicalCPUID & AMD_DR_GT_Bx) {
+ /* Family 10h Errata 322: Address and Command Fine Delay Values May Be Incorrect */
/* 1. Write 00000000h to F2x[1,0]9C_xD08E000 */
- Set_NB32_index_wait(pDCTstat->dev_dct, 0x98 + dct * 0x100, 0x0D08E000, 0);
+ Set_NB32_index_wait_DCT(pDCTstat->dev_dct, dct, 0x98, 0x0D08E000, 0);
/* 2. If DRAM Configuration Register[MemClkFreq] (F2x[1,0]94[2:0]) is
greater than or equal to 011b (DDR-800 and higher),
then write 00000080h to F2x[1,0]9C_xD02E001,
else write 00000090h to F2x[1,0]9C_xD02E001. */
- if (pDCTstat->Speed >= 4)
- Set_NB32_index_wait(pDCTstat->dev_dct, 0x98 + dct * 0x100, 0xD02E001, 0x80);
+ if (pDCTstat->Speed >= mhz_to_memclk_config(mctGet_NVbits(NV_MIN_MEMCLK)))
+ Set_NB32_index_wait_DCT(pDCTstat->dev_dct, dct, 0x98, 0x0D02E001, 0x80);
else
- Set_NB32_index_wait(pDCTstat->dev_dct, 0x98 + dct * 0x100, 0xD02E001, 0x90);
+ Set_NB32_index_wait_DCT(pDCTstat->dev_dct, dct, 0x98, 0x0D02E001, 0x90);
}
return pDCTstat->ErrCode;
}
@@ -2461,9 +4087,9 @@ static u8 mct_PlatformSpec(struct MCTStatStruc *pMCTstat,
i_end = dct + 1;
}
for (i=i_start; i<i_end; i++) {
- index_reg = 0x98 + (i * 0x100);
- Set_NB32_index_wait(dev, index_reg, 0x00, pDCTstat->CH_ODC_CTL[i]); /* Channel A Output Driver Compensation Control */
- Set_NB32_index_wait(dev, index_reg, 0x04, pDCTstat->CH_ADDR_TMG[i]); /* Channel A Output Driver Compensation Control */
+ index_reg = 0x98;
+ Set_NB32_index_wait_DCT(dev, i, index_reg, 0x00, pDCTstat->CH_ODC_CTL[i]); /* Channel A Output Driver Compensation Control */
+ Set_NB32_index_wait_DCT(dev, i, index_reg, 0x04, pDCTstat->CH_ADDR_TMG[i]); /* Channel A Output Driver Compensation Control */
}
return pDCTstat->ErrCode;
@@ -2517,14 +4143,14 @@ static u8 mct_SPDCalcWidth(struct MCTStatStruc *pMCTstat,
}
if (pDCTstat->DIMMValidDCT[0] == 0) {
- val = Get_NB32(pDCTstat->dev_dct, 0x94);
+ val = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x94);
val |= 1 << DisDramInterface;
- Set_NB32(pDCTstat->dev_dct, 0x94, val);
+ Set_NB32_DCT(pDCTstat->dev_dct, 0, 0x94, val);
}
if (pDCTstat->DIMMValidDCT[1] == 0) {
- val = Get_NB32(pDCTstat->dev_dct, 0x94 + 0x100);
+ val = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x94);
val |= 1 << DisDramInterface;
- Set_NB32(pDCTstat->dev_dct, 0x94 + 0x100, val);
+ Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x94, val);
}
printk(BIOS_DEBUG, "SPDCalcWidth: Status %x\n", pDCTstat->Status);
@@ -2654,21 +4280,20 @@ static void Set_OtherTiming(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat, u8 dct)
{
u32 reg;
- u32 reg_off = 0x100 * dct;
u32 val;
u32 dword;
u32 dev = pDCTstat->dev_dct;
- Get_DqsRcvEnGross_Diff(pDCTstat, dev, 0x98 + reg_off);
- Get_WrDatGross_Diff(pDCTstat, dct, dev, 0x98 + reg_off);
+ Get_DqsRcvEnGross_Diff(pDCTstat, dev, dct, 0x98);
+ Get_WrDatGross_Diff(pDCTstat, dct, dev, 0x98);
Get_Trdrd(pMCTstat, pDCTstat, dct);
Get_Twrwr(pMCTstat, pDCTstat, dct);
Get_Twrrd(pMCTstat, pDCTstat, dct);
Get_TrwtTO(pMCTstat, pDCTstat, dct);
Get_TrwtWB(pMCTstat, pDCTstat);
- reg = 0x8C + reg_off; /* Dram Timing Hi */
- val = Get_NB32(dev, reg);
+ reg = 0x8C; /* Dram Timing Hi */
+ val = Get_NB32_DCT(dev, dct, reg);
val &= 0xffff0300;
dword = pDCTstat->TrwtTO;
val |= dword << 4;
@@ -2680,10 +4305,10 @@ static void Set_OtherTiming(struct MCTStatStruc *pMCTstat,
val |= dword << 14;
dword = pDCTstat->TrwtWB;
val |= dword;
- Set_NB32(dev, reg, val);
+ Set_NB32_DCT(dev, dct, reg, val);
- reg = 0x78 + reg_off;
- val = Get_NB32(dev, reg);
+ reg = 0x78;
+ val = Get_NB32_DCT(dev, dct, reg);
val &= 0xFFFFC0FF;
dword = pDCTstat->Twrrd >> 2;
val |= dword << 8;
@@ -2691,7 +4316,7 @@ static void Set_OtherTiming(struct MCTStatStruc *pMCTstat,
val |= dword << 10;
dword = pDCTstat->Trdrd >> 2;
val |= dword << 12;
- Set_NB32(dev, reg, val);
+ Set_NB32_DCT(dev, dct, reg, val);
}
static void Get_Trdrd(struct MCTStatStruc *pMCTstat,
@@ -2761,18 +4386,17 @@ static void Get_TrwtWB(struct MCTStatStruc *pMCTstat,
static u8 Get_Latency_Diff(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat, u8 dct)
{
- u32 reg_off = 0x100 * dct;
u32 dev = pDCTstat->dev_dct;
u32 val1, val2;
- val1 = Get_NB32(dev, reg_off + 0x88) & 0xF;
- val2 = (Get_NB32(dev, reg_off + 0x84) >> 20) & 7;
+ val1 = Get_NB32_DCT(dev, dct, 0x88) & 0xF;
+ val2 = (Get_NB32_DCT(dev, dct, 0x84) >> 20) & 7;
return val1 - val2;
}
static void Get_DqsRcvEnGross_Diff(struct DCTStatStruc *pDCTstat,
- u32 dev, u32 index_reg)
+ u32 dev, uint8_t dct, u32 index_reg)
{
u8 Smallest, Largest;
u32 val;
@@ -2782,12 +4406,12 @@ static void Get_DqsRcvEnGross_Diff(struct DCTStatStruc *pDCTstat,
DqsRcvEnGrossDelay of any other DIMM is equal to the Critical
Gross Delay Difference (CGDD) */
/* DqsRcvEn byte 1,0 */
- val = Get_DqsRcvEnGross_MaxMin(pDCTstat, dev, index_reg, 0x10);
+ val = Get_DqsRcvEnGross_MaxMin(pDCTstat, dev, dct, index_reg, 0x10);
Largest = val & 0xFF;
Smallest = (val >> 8) & 0xFF;
/* DqsRcvEn byte 3,2 */
- val = Get_DqsRcvEnGross_MaxMin(pDCTstat, dev, index_reg, 0x11);
+ val = Get_DqsRcvEnGross_MaxMin(pDCTstat, dev, dct, index_reg, 0x11);
byte = val & 0xFF;
bytex = (val >> 8) & 0xFF;
if (bytex < Smallest)
@@ -2796,7 +4420,7 @@ static void Get_DqsRcvEnGross_Diff(struct DCTStatStruc *pDCTstat,
Largest = byte;
/* DqsRcvEn byte 5,4 */
- val = Get_DqsRcvEnGross_MaxMin(pDCTstat, dev, index_reg, 0x20);
+ val = Get_DqsRcvEnGross_MaxMin(pDCTstat, dev, dct, index_reg, 0x20);
byte = val & 0xFF;
bytex = (val >> 8) & 0xFF;
if (bytex < Smallest)
@@ -2805,7 +4429,7 @@ static void Get_DqsRcvEnGross_Diff(struct DCTStatStruc *pDCTstat,
Largest = byte;
/* DqsRcvEn byte 7,6 */
- val = Get_DqsRcvEnGross_MaxMin(pDCTstat, dev, index_reg, 0x21);
+ val = Get_DqsRcvEnGross_MaxMin(pDCTstat, dev, dct, index_reg, 0x21);
byte = val & 0xFF;
bytex = (val >> 8) & 0xFF;
if (bytex < Smallest)
@@ -2815,7 +4439,7 @@ static void Get_DqsRcvEnGross_Diff(struct DCTStatStruc *pDCTstat,
if (pDCTstat->DimmECCPresent> 0) {
/*DqsRcvEn Ecc */
- val = Get_DqsRcvEnGross_MaxMin(pDCTstat, dev, index_reg, 0x12);
+ val = Get_DqsRcvEnGross_MaxMin(pDCTstat, dev, dct, index_reg, 0x12);
byte = val & 0xFF;
bytex = (val >> 8) & 0xFF;
if (bytex < Smallest)
@@ -2879,7 +4503,7 @@ static void Get_WrDatGross_Diff(struct DCTStatStruc *pDCTstat,
}
static u16 Get_DqsRcvEnGross_MaxMin(struct DCTStatStruc *pDCTstat,
- u32 dev, u32 index_reg,
+ u32 dev, uint8_t dct, u32 index_reg,
u32 index)
{
u8 Smallest, Largest;
@@ -2897,7 +4521,7 @@ static u16 Get_DqsRcvEnGross_MaxMin(struct DCTStatStruc *pDCTstat,
for (i=0; i < 8; i+=2) {
if ( pDCTstat->DIMMValid & (1 << i)) {
- val = Get_NB32_index_wait(dev, index_reg, index);
+ val = Get_NB32_index_wait_DCT(dev, dct, index_reg, index);
val &= 0x00E000E0;
byte = (val >> 5) & 0xFF;
if (byte < Smallest)
@@ -2935,7 +4559,7 @@ static u16 Get_WrDatGross_MaxMin(struct DCTStatStruc *pDCTstat,
Smallest = 3;
Largest = 0;
for (i=0; i < 2; i++) {
- val = Get_NB32_index_wait(dev, index_reg, index);
+ val = Get_NB32_index_wait_DCT(dev, dct, index_reg, index);
val &= 0x60606060;
val >>= 5;
for (j=0; j < 4; j++) {
@@ -2951,7 +4575,7 @@ static u16 Get_WrDatGross_MaxMin(struct DCTStatStruc *pDCTstat,
if (pDCTstat->DimmECCPresent > 0) {
index++;
- val = Get_NB32_index_wait(dev, index_reg, index);
+ val = Get_NB32_index_wait_DCT(dev, dct, index_reg, index);
val &= 0x00000060;
val >>= 5;
byte = val & 0xFF;
@@ -2971,25 +4595,30 @@ static u16 Get_WrDatGross_MaxMin(struct DCTStatStruc *pDCTstat,
static void mct_PhyController_Config(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat, u8 dct)
{
- u32 index_reg = 0x98 + 0x100 * dct;
+ uint8_t index;
+ uint32_t dword;
+ u32 index_reg = 0x98;
u32 dev = pDCTstat->dev_dct;
- u32 val;
- if (pDCTstat->LogicalCPUID & (AMD_DR_DAC2_OR_C3 | AMD_RB_C3)) {
+ if (pDCTstat->LogicalCPUID & (AMD_DR_DAC2_OR_C3 | AMD_RB_C3 | AMD_FAM15_ALL)) {
if (pDCTstat->Dimmx4Present == 0) {
- /* Set bit7 RxDqsUDllPowerDown to register F2x[1, 0]98_x0D0F0F13 for power saving */
- val = Get_NB32_index_wait(dev, index_reg, 0x0D0F0F13); /* Agesa v3 v6 might be wrong here. */
- val |= 1 << 7; /* BIOS should set this bit when x4 DIMMs are not present */
- Set_NB32_index_wait(dev, index_reg, 0x0D0F0F13, val);
+ /* Set bit7 RxDqsUDllPowerDown to register F2x[1, 0]98_x0D0F0F13 for
+ * additional power saving when x4 DIMMs are not present.
+ */
+ for (index = 0; index < 0x9; index++) {
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f0013 | (index << 8));
+ dword |= (0x1 << 7); /* RxDqsUDllPowerDown = 1 */
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f0013 | (index << 8), dword);
+ }
}
}
- if (pDCTstat->LogicalCPUID & AMD_DR_DAC2_OR_C3) {
+ if (pDCTstat->LogicalCPUID & (AMD_DR_DAC2_OR_C3 | AMD_FAM15_ALL)) {
if (pDCTstat->DimmECCPresent == 0) {
/* Set bit4 PwrDn to register F2x[1, 0]98_x0D0F0830 for power saving */
- val = Get_NB32_index_wait(dev, index_reg, 0x0D0F0830);
- val |= 1 << 4; /* BIOS should set this bit if ECC DIMMs are not present */
- Set_NB32_index_wait(dev, index_reg, 0x0D0F0830, val);
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f0830);
+ dword |= 1 << 4; /* BIOS should set this bit if ECC DIMMs are not present */
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f0830, dword);
}
}
@@ -3030,21 +4659,61 @@ static void mct_FinalMCT_D(struct MCTStatStruc *pMCTstat,
val &= ~(1 << 12);
val &= 0x0FFFFFFF;
- switch (pDCTstat->Speed) {
- case 4:
- val |= 0x50000000; /* 5 for DDR800 */
- break;
- case 5:
- val |= 0x60000000; /* 6 for DDR1066 */
- break;
- case 6:
- val |= 0x80000000; /* 8 for DDR800 */
- break;
- default:
- val |= 0x90000000; /* 9 for DDR1600 */
- break;
+ if (!is_fam15h()) {
+ switch (pDCTstat->Speed) {
+ case 4:
+ val |= 0x50000000; /* 5 for DDR800 */
+ break;
+ case 5:
+ val |= 0x60000000; /* 6 for DDR1066 */
+ break;
+ case 6:
+ val |= 0x80000000; /* 8 for DDR800 */
+ break;
+ default:
+ val |= 0x90000000; /* 9 for DDR1600 */
+ break;
+ }
}
Set_NB32(pDCTstat->dev_dct, 0x1B0, val);
+
+ if (is_fam15h()) {
+ uint8_t wm1;
+ uint8_t wm2;
+
+ switch (pDCTstat->Speed) {
+ case 0x4:
+ wm1 = 0x3;
+ wm2 = 0x4;
+ break;
+ case 0x6:
+ wm1 = 0x3;
+ wm2 = 0x5;
+ break;
+ case 0xa:
+ wm1 = 0x4;
+ wm2 = 0x6;
+ break;
+ case 0xe:
+ wm1 = 0x5;
+ wm2 = 0x8;
+ break;
+ case 0x12:
+ wm1 = 0x6;
+ wm2 = 0x9;
+ break;
+ default:
+ wm1 = 0x7;
+ wm2 = 0xa;
+ break;
+ }
+
+ val = Get_NB32(pDCTstat->dev_dct, 0x1B4);
+ val &= ~(0x3ff);
+ val |= ((wm2 & 0x1f) << 5);
+ val |= (wm1 & 0x1f);
+ Set_NB32(pDCTstat->dev_dct, 0x1B4, val);
+ }
}
}
@@ -3061,16 +4730,103 @@ static void mct_FinalMCT_D(struct MCTStatStruc *pMCTstat,
}
}
+void mct_ForceNBPState0_En_Fam15(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat)
+{
+ /* Force the NB P-state to P0 */
+ uint32_t dword;
+ uint32_t dword2;
+
+ dword = Get_NB32(pDCTstat->dev_nbctl, 0x174);
+ if (!(dword & 0x1)) {
+ dword = Get_NB32(pDCTstat->dev_nbctl, 0x170);
+ pDCTstat->SwNbPstateLoDis = (dword >> 14) & 0x1;
+ pDCTstat->NbPstateDisOnP0 = (dword >> 13) & 0x1;
+ pDCTstat->NbPstateThreshold = (dword >> 9) & 0x7;
+ pDCTstat->NbPstateHi = (dword >> 6) & 0x3;
+ dword &= ~(0x1 << 14); /* SwNbPstateLoDis = 0 */
+ dword &= ~(0x1 << 13); /* NbPstateDisOnP0 = 0 */
+ dword &= ~(0x7 << 9); /* NbPstateThreshold = 0 */
+ dword &= ~(0x3 << 3); /* NbPstateLo = NbPstateMaxVal */
+ dword |= ((dword & 0x3) << 3);
+ Set_NB32(pDCTstat->dev_nbctl, 0x170, dword);
+
+ /* Wait until CurNbPState == NbPstateLo */
+ do {
+ dword2 = Get_NB32(pDCTstat->dev_nbctl, 0x174);
+ } while (((dword2 << 19) & 0x7) != (dword & 0x3));
+
+ dword = Get_NB32(pDCTstat->dev_nbctl, 0x170);
+ dword &= ~(0x3 << 6); /* NbPstateHi = 0 */
+ dword |= (0x3 << 14); /* SwNbPstateLoDis = 1 */
+ Set_NB32(pDCTstat->dev_nbctl, 0x170, dword);
+
+ /* Wait until CurNbPState == 0 */
+ do {
+ dword2 = Get_NB32(pDCTstat->dev_nbctl, 0x174);
+ } while (((dword2 << 19) & 0x7) != 0);
+ }
+}
+
+void mct_ForceNBPState0_Dis_Fam15(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat)
+{
+ /* Restore normal NB P-state functionailty */
+ uint32_t dword;
+
+ dword = Get_NB32(pDCTstat->dev_nbctl, 0x174);
+ if (!(dword & 0x1)) {
+ dword = Get_NB32(pDCTstat->dev_nbctl, 0x170);
+ dword &= ~(0x1 << 14); /* SwNbPstateLoDis*/
+ dword |= ((pDCTstat->SwNbPstateLoDis & 0x1) << 14);
+ dword &= ~(0x1 << 13); /* NbPstateDisOnP0 */
+ dword |= ((pDCTstat->NbPstateDisOnP0 & 0x1) << 13);
+ dword &= ~(0x7 << 9); /* NbPstateThreshold */
+ dword |= ((pDCTstat->NbPstateThreshold & 0x7) << 9);
+ dword &= ~(0x3 << 6); /* NbPstateHi */
+ dword |= ((pDCTstat->NbPstateHi & 0x3) << 3);
+ Set_NB32(pDCTstat->dev_nbctl, 0x170, dword);
+ }
+}
+
static void mct_InitialMCT_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat)
{
- mct_SetClToNB_D(pMCTstat, pDCTstat);
- mct_SetWbEnhWsbDis_D(pMCTstat, pDCTstat);
+ if (is_fam15h()) {
+ msr_t p0_state_msr;
+ uint8_t cpu_fid;
+ uint8_t cpu_did;
+ uint32_t cpu_divisor;
+ uint8_t boost_states;
+
+ /* Retrieve the number of boost states */
+ boost_states = (Get_NB32(pDCTstat->dev_link, 0x15c) >> 2) & 0x7;
+
+ /* Retrieve and store the TSC frequency (P0 COF) */
+ p0_state_msr = rdmsr(0xc0010064 + boost_states);
+ cpu_fid = p0_state_msr.lo & 0x3f;
+ cpu_did = (p0_state_msr.lo >> 6) & 0x7;
+ cpu_divisor = (0x1 << cpu_did);
+ pMCTstat->TSCFreq = (100 * (cpu_fid + 0x10)) / cpu_divisor;
+
+ mct_ForceNBPState0_En_Fam15(pMCTstat, pDCTstat);
+ } else {
+ /* K10 BKDG v3.62 section 2.8.9.2 */
+ printk(BIOS_DEBUG, "mct_InitialMCT_D: clear_legacy_Mode\n");
+ clear_legacy_Mode(pMCTstat, pDCTstat);
+
+ /* Northbridge configuration */
+ mct_SetClToNB_D(pMCTstat, pDCTstat);
+ mct_SetWbEnhWsbDis_D(pMCTstat, pDCTstat);
+ }
}
static u32 mct_NodePresent_D(void)
{
u32 val;
- val = 0x12001022;
+ if (is_fam15h())
+ val = 0x16001022;
+ else
+ val = 0x12001022;
return val;
}
@@ -3103,14 +4859,13 @@ static void clear_legacy_Mode(struct MCTStatStruc *pMCTstat,
/* Clear Legacy BIOS Mode bit */
reg = 0x94;
- val = Get_NB32(dev, reg);
+ val = Get_NB32_DCT(dev, 0, reg);
val &= ~(1<<LegacyBiosMode);
- Set_NB32(dev, reg, val);
+ Set_NB32_DCT(dev, 0, reg, val);
- reg = 0x94 + 0x100;
- val = Get_NB32(dev, reg);
+ val = Get_NB32_DCT(dev, 1, reg);
val &= ~(1<<LegacyBiosMode);
- Set_NB32(dev, reg, val);
+ Set_NB32_DCT(dev, 1, reg, val);
}
static void mct_HTMemMapExt(struct MCTStatStruc *pMCTstat,
@@ -3177,7 +4932,7 @@ static void SetCSTriState(struct MCTStatStruc *pMCTstat,
{
u32 val;
u32 dev = pDCTstat->dev_dct;
- u32 index_reg = 0x98 + 0x100 * dct;
+ u32 index_reg = 0x98;
u32 index;
u16 word;
@@ -3192,9 +4947,9 @@ static void SetCSTriState(struct MCTStatStruc *pMCTstat,
}
word = (~word) & 0xFF;
index = 0x0c;
- val = Get_NB32_index_wait(dev, index_reg, index);
+ val = Get_NB32_index_wait_DCT(dev, dct, index_reg, index);
val |= word;
- Set_NB32_index_wait(dev, index_reg, index, val);
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, index, val);
}
static void SetCKETriState(struct MCTStatStruc *pMCTstat,
@@ -3202,7 +4957,7 @@ static void SetCKETriState(struct MCTStatStruc *pMCTstat,
{
u32 val;
u32 dev;
- u32 index_reg = 0x98 + 0x100 * dct;
+ u32 index_reg = 0x98;
u32 index;
u16 word;
@@ -3214,14 +4969,14 @@ static void SetCKETriState(struct MCTStatStruc *pMCTstat,
word = pDCTstat->CSPresent;
index = 0x0c;
- val = Get_NB32_index_wait(dev, index_reg, index);
+ val = Get_NB32_index_wait_DCT(dev, dct, index_reg, index);
if ((word & 0x55) == 0)
val |= 1 << 12;
if ((word & 0xAA) == 0)
val |= 1 << 13;
- Set_NB32_index_wait(dev, index_reg, index, val);
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, index, val);
}
static void SetODTTriState(struct MCTStatStruc *pMCTstat,
@@ -3229,7 +4984,7 @@ static void SetODTTriState(struct MCTStatStruc *pMCTstat,
{
u32 val;
u32 dev;
- u32 index_reg = 0x98 + 0x100 * dct;
+ u32 index_reg = 0x98;
u8 cs;
u32 index;
u8 odt;
@@ -3263,86 +5018,281 @@ static void SetODTTriState(struct MCTStatStruc *pMCTstat,
}
index = 0x0C;
- val = Get_NB32_index_wait(dev, index_reg, index);
+ val = Get_NB32_index_wait_DCT(dev, dct, index_reg, index);
val |= ((odt & 0xFF) << 8); /* set bits 11:8 ODTTriState[3:0] */
- Set_NB32_index_wait(dev, index_reg, index, val);
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, index, val);
+
+}
+
+/* Family 15h */
+static void InitDDRPhy(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct)
+{
+ uint8_t index;
+ uint32_t dword;
+ uint8_t ddr_voltage_index;
+ uint8_t amd_voltage_level_index = 0;
+ uint32_t index_reg = 0x98;
+ uint32_t dev = pDCTstat->dev_dct;
+
+ printk(BIOS_DEBUG, "%s: Start\n", __func__);
+
+ /* Find current DDR supply voltage for this DCT */
+ ddr_voltage_index = dct_ddr_voltage_index(pDCTstat, dct);
+
+ /* Fam15h BKDG v3.14 section 2.10.5.3
+ * The remainder of the Phy Initialization algorithm picks up in phyAssistedMemFnceTraining
+ */
+ for (dct = 0; dct < 2; dct++) {
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000b, 0x80000000);
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fe013, 0x00000118);
+
+ /* Program desired VDDIO level */
+ if (ddr_voltage_index & 0x4) {
+ /* 1.25V */
+ amd_voltage_level_index = 0x2;
+ } else if (ddr_voltage_index & 0x2) {
+ /* 1.35V */
+ amd_voltage_level_index = 0x1;
+ } else if (ddr_voltage_index & 0x1) {
+ /* 1.50V */
+ amd_voltage_level_index = 0x0;
+ }
+
+ /* D18F2x9C_x0D0F_0[F,8:0]1F_dct[1:0][RxVioLvl] */
+ for (index = 0; index < 0x9; index++) {
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f001f | (index << 8));
+ dword &= ~(0x3 << 3);
+ dword |= (amd_voltage_level_index << 3);
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f001f | (index << 8), dword);
+ }
+ /* D18F2x9C_x0D0F_[C,8,2][2:0]1F_dct[1:0][RxVioLvl] */
+ for (index = 0; index < 0x3; index++) {
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f201f | (index << 8));
+ dword &= ~(0x3 << 3);
+ dword |= (amd_voltage_level_index << 3);
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f201f | (index << 8), dword);
+ }
+ for (index = 0; index < 0x2; index++) {
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f801f | (index << 8));
+ dword &= ~(0x3 << 3);
+ dword |= (amd_voltage_level_index << 3);
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f801f | (index << 8), dword);
+ }
+ for (index = 0; index < 0x1; index++) {
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fc01f | (index << 8));
+ dword &= ~(0x3 << 3);
+ dword |= (amd_voltage_level_index << 3);
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fc01f | (index << 8), dword);
+ }
+
+ /* D18F2x9C_x0D0F_4009_dct[1:0][CmpVioLvl, ComparatorAdjust] */
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f4009);
+ dword &= ~(0x0000c00c);
+ dword |= (amd_voltage_level_index << 14);
+ dword |= (amd_voltage_level_index << 2);
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f4009, dword);
+ }
+
+ printk(BIOS_DEBUG, "%s: Done\n", __func__);
}
static void InitPhyCompensation(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat, u8 dct)
{
u8 i;
- u32 index_reg = 0x98 + 0x100 * dct;
+ u32 index_reg = 0x98;
u32 dev = pDCTstat->dev_dct;
- u32 val;
u32 valx = 0;
- u32 dword;
+ uint8_t index;
+ uint32_t dword;
const u8 *p;
- val = Get_NB32_index_wait(dev, index_reg, 0x00);
- dword = 0;
- for (i=0; i < 6; i++) {
- switch (i) {
- case 0:
- case 4:
- p = Table_Comp_Rise_Slew_15x;
- valx = p[(val >> 16) & 3];
- break;
- case 1:
- case 5:
- p = Table_Comp_Fall_Slew_15x;
- valx = p[(val >> 16) & 3];
- break;
- case 2:
- p = Table_Comp_Rise_Slew_20x;
- valx = p[(val >> 8) & 3];
- break;
- case 3:
- p = Table_Comp_Fall_Slew_20x;
- valx = p[(val >> 8) & 3];
- break;
+ printk(BIOS_DEBUG, "%s: Start\n", __func__);
+
+ if (is_fam15h()) {
+ /* Algorithm detailed in the Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 */
+ uint32_t tx_pre;
+ uint32_t drive_strength;
+
+ /* Program D18F2x9C_x0D0F_E003_dct[1:0][DisAutoComp, DisablePredriverCal] */
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fe003);
+ dword |= (0x3 << 13);
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fe003, dword);
+
+ /* Determine TxPreP/TxPreN for data lanes (Stage 1) */
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x00000000);
+ drive_strength = (dword >> 20) & 0x7; /* DqsDrvStren */
+ tx_pre = fam15h_phy_predriver_calibration_code(pDCTstat, dct, drive_strength);
+
+ /* Program TxPreP/TxPreN for data lanes (Stage 1) */
+ for (index = 0; index < 0x9; index++) {
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f0006 | (index << 8));
+ dword &= ~(0xfff);
+ dword |= tx_pre;
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f0006 | (index << 8), dword);
+ }
+ /* Determine TxPreP/TxPreN for data lanes (Stage 2) */
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x00000000);
+ drive_strength = (dword >> 16) & 0x7; /* DataDrvStren */
+ tx_pre = fam15h_phy_predriver_calibration_code(pDCTstat, dct, drive_strength);
+
+ /* Program TxPreP/TxPreN for data lanes (Stage 2) */
+ for (index = 0; index < 0x9; index++) {
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f000a | (index << 8));
+ dword &= ~(0xfff);
+ dword |= tx_pre;
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f000a | (index << 8), dword);
+ }
+ for (index = 0; index < 0x9; index++) {
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f0002 | (index << 8));
+ dword &= ~(0xfff);
+ dword |= (0x8000 | tx_pre);
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f0002 | (index << 8), dword);
}
- dword |= valx << (5 * i);
- }
- /* Override/Exception */
- if (!pDCTstat->GangedMode) {
- i = 0; /* use i for the dct setting required */
- if (pDCTstat->MAdimms[0] < 4)
- i = 1;
- if (((pDCTstat->Speed == 2) || (pDCTstat->Speed == 3)) && (pDCTstat->MAdimms[i] == 4)) {
- dword &= 0xF18FFF18;
- index_reg = 0x98; /* force dct = 0 */
+ /* Determine TxPreP/TxPreN for command/address lines (Stage 1) */
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x00000000);
+ drive_strength = (dword >> 4) & 0x7; /* CsOdtDrvStren */
+ tx_pre = fam15h_phy_predriver_cmd_addr_calibration_code(pDCTstat, dct, drive_strength);
+
+ /* Program TxPreP/TxPreN for command/address lines (Stage 1) */
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f8006);
+ dword &= ~(0xfff);
+ dword |= tx_pre;
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f8006, dword);
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f800a);
+ dword &= ~(0xfff);
+ dword |= tx_pre;
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f800a, dword);
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f8002);
+ dword &= ~(0xfff);
+ dword |= (0x8000 | tx_pre);
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f8002, dword);
+
+ /* Determine TxPreP/TxPreN for command/address lines (Stage 2) */
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x00000000);
+ drive_strength = (dword >> 8) & 0x7; /* AddrCmdDrvStren */
+ tx_pre = fam15h_phy_predriver_cmd_addr_calibration_code(pDCTstat, dct, drive_strength);
+
+ /* Program TxPreP/TxPreN for command/address lines (Stage 2) */
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f8106);
+ dword &= ~(0xfff);
+ dword |= tx_pre;
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f8106, dword);
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f810a);
+ dword &= ~(0xfff);
+ dword |= tx_pre;
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f810a, dword);
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fc006);
+ dword &= ~(0xfff);
+ dword |= tx_pre;
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fc006, dword);
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fc00a);
+ dword &= ~(0xfff);
+ dword |= tx_pre;
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fc00a, dword);
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fc00e);
+ dword &= ~(0xfff);
+ dword |= tx_pre;
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fc00e, dword);
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fc012);
+ dword &= ~(0xfff);
+ dword |= tx_pre;
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fc012, dword);
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f8102);
+ dword &= ~(0xfff);
+ dword |= (0x8000 | tx_pre);
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f8102, dword);
+
+ /* Determine TxPreP/TxPreN for command/address lines (Stage 3) */
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x00000000);
+ drive_strength = (dword >> 0) & 0x7; /* CkeDrvStren */
+ tx_pre = fam15h_phy_predriver_cmd_addr_calibration_code(pDCTstat, dct, drive_strength);
+
+ /* Program TxPreP/TxPreN for command/address lines (Stage 3) */
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fc002);
+ dword &= ~(0xfff);
+ dword |= (0x8000 | tx_pre);
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fc002, dword);
+
+ /* Determine TxPreP/TxPreN for clock lines */
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x00000000);
+ drive_strength = (dword >> 12) & 0x7; /* ClkDrvStren */
+ tx_pre = fam15h_phy_predriver_clk_calibration_code(pDCTstat, dct, drive_strength);
+
+ /* Program TxPreP/TxPreN for clock lines */
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f2002);
+ dword &= ~(0xfff);
+ dword |= (0x8000 | tx_pre);
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f2002, dword);
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f2102);
+ dword &= ~(0xfff);
+ dword |= (0x8000 | tx_pre);
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f2102, dword);
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f2202);
+ dword &= ~(0xfff);
+ dword |= (0x8000 | tx_pre);
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f2202, dword);
+ } else {
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x00);
+ dword = 0;
+ for (i=0; i < 6; i++) {
+ switch (i) {
+ case 0:
+ case 4:
+ p = Table_Comp_Rise_Slew_15x;
+ valx = p[(dword >> 16) & 3];
+ break;
+ case 1:
+ case 5:
+ p = Table_Comp_Fall_Slew_15x;
+ valx = p[(dword >> 16) & 3];
+ break;
+ case 2:
+ p = Table_Comp_Rise_Slew_20x;
+ valx = p[(dword >> 8) & 3];
+ break;
+ case 3:
+ p = Table_Comp_Fall_Slew_20x;
+ valx = p[(dword >> 8) & 3];
+ break;
+ }
+ dword |= valx << (5 * i);
}
+
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0a, dword);
}
- Set_NB32_index_wait(dev, index_reg, 0x0a, dword);
+ printk(BIOS_DEBUG, "%s: Done\n", __func__);
}
static void mct_EarlyArbEn_D(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat, u8 dct)
{
- u32 reg;
- u32 val;
- u32 dev = pDCTstat->dev_dct;
-
- /* GhEnhancement #18429 modified by askar: For low NB CLK :
- * Memclk ratio, the DCT may need to arbitrate early to avoid
- * unnecessary bubbles.
- * bit 19 of F2x[1,0]78 Dram Control Register, set this bit only when
- * NB CLK : Memclk ratio is between 3:1 (inclusive) to 4:5 (inclusive)
- */
- reg = 0x78 + 0x100 * dct;
- val = Get_NB32(dev, reg);
-
- if (pDCTstat->LogicalCPUID & (AMD_DR_Cx | AMD_DR_Dx))
- val |= (1 << EarlyArbEn);
- else if (CheckNBCOFEarlyArbEn(pMCTstat, pDCTstat))
- val |= (1 << EarlyArbEn);
-
- Set_NB32(dev, reg, val);
+ if (!is_fam15h()) {
+ u32 reg;
+ u32 val;
+ u32 dev = pDCTstat->dev_dct;
+
+ /* GhEnhancement #18429 modified by askar: For low NB CLK :
+ * Memclk ratio, the DCT may need to arbitrate early to avoid
+ * unnecessary bubbles.
+ * bit 19 of F2x[1,0]78 Dram Control Register, set this bit only when
+ * NB CLK : Memclk ratio is between 3:1 (inclusive) to 4:5 (inclusive)
+ */
+ reg = 0x78;
+ val = Get_NB32_DCT(dev, dct, reg);
+
+ if (pDCTstat->LogicalCPUID & (AMD_DR_Cx | AMD_DR_Dx))
+ val |= (1 << EarlyArbEn);
+ else if (CheckNBCOFEarlyArbEn(pMCTstat, pDCTstat))
+ val |= (1 << EarlyArbEn);
+
+ Set_NB32_DCT(dev, dct, reg, val);
+ }
}
static u8 CheckNBCOFEarlyArbEn(struct MCTStatStruc *pMCTstat,
@@ -3365,9 +5315,9 @@ static u8 CheckNBCOFEarlyArbEn(struct MCTStatStruc *pMCTstat,
NbDid |= 1;
reg = 0x94;
- val = Get_NB32(dev, reg);
+ val = Get_NB32_DCT(dev, 0, reg);
if (!(val & (1 << MemClkFreqVal)))
- val = Get_NB32(dev, reg + 0x100); /* get the DCT1 value */
+ val = Get_NB32_DCT(dev, 1, reg); /* get the DCT1 value */
val &= 0x07;
val += 3;
@@ -3436,28 +5386,204 @@ static void mct_ResetDataStruct_D(struct MCTStatStruc *pMCTstat,
}
static void mct_BeforeDramInit_Prod_D(struct MCTStatStruc *pMCTstat,
- struct DCTStatStruc *pDCTstat)
+ struct DCTStatStruc *pDCTstat, u8 dct)
+{
+ mct_ProgramODT_D(pMCTstat, pDCTstat, dct);
+}
+
+static void mct_ProgramODT_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct)
{
u8 i;
- u32 reg_off, dword;
+ u32 dword;
u32 dev = pDCTstat->dev_dct;
- if (pDCTstat->LogicalCPUID & AMD_DR_Dx) {
+ /* FIXME
+ * Mainboards need to be able to specify the maximum number of DIMMs installable per channel
+ * For now assume a maximum of 2 DIMMs per channel can be installed
+ */
+ uint8_t MaxDimmsInstallable = 2;
+
+ if (is_fam15h()) {
+ /* Obtain number of DIMMs on channel */
+ uint8_t dimm_count = pDCTstat->MAdimms[dct];
+ uint8_t rank_count_dimm0;
+ uint8_t rank_count_dimm1;
+ uint32_t odt_pattern_0;
+ uint32_t odt_pattern_1;
+ uint32_t odt_pattern_2;
+ uint32_t odt_pattern_3;
+ uint8_t write_odt_duration;
+ uint8_t read_odt_duration;
+ uint8_t write_odt_delay;
+ uint8_t read_odt_delay;
+
+ /* Select appropriate ODT pattern for installed DIMMs
+ * Refer to the Fam15h BKDG Rev. 3.14, page 149 onwards
+ */
+ if (pDCTstat->C_DCTPtr[dct]->Status[DCT_STATUS_REGISTERED]) {
+ if (MaxDimmsInstallable == 2) {
+ if (dimm_count == 1) {
+ /* 1 DIMM detected */
+ rank_count_dimm1 = pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
+ if (rank_count_dimm1 == 1) {
+ odt_pattern_0 = 0x00000000;
+ odt_pattern_1 = 0x00000000;
+ odt_pattern_2 = 0x00000000;
+ odt_pattern_3 = 0x00020000;
+ } else if (rank_count_dimm1 == 2) {
+ odt_pattern_0 = 0x00000000;
+ odt_pattern_1 = 0x00000000;
+ odt_pattern_2 = 0x00000000;
+ odt_pattern_3 = 0x08020000;
+ } else if (rank_count_dimm1 == 4) {
+ odt_pattern_0 = 0x00000000;
+ odt_pattern_1 = 0x00000000;
+ odt_pattern_2 = 0x020a0000;
+ odt_pattern_3 = 0x080a0000;
+ } else {
+ /* Fallback */
+ odt_pattern_0 = 0x00000000;
+ odt_pattern_1 = 0x00000000;
+ odt_pattern_2 = 0x00000000;
+ odt_pattern_3 = 0x08020000;
+ }
+ } else {
+ /* 2 DIMMs detected */
+ rank_count_dimm0 = pDCTstat->C_DCTPtr[dct]->DimmRanks[0];
+ rank_count_dimm1 = pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
+ if ((rank_count_dimm0 < 4) && (rank_count_dimm1 < 4)) {
+ odt_pattern_0 = 0x00000000;
+ odt_pattern_1 = 0x01010202;
+ odt_pattern_2 = 0x00000000;
+ odt_pattern_3 = 0x09030603;
+ } else if ((rank_count_dimm0 < 4) && (rank_count_dimm1 == 4)) {
+ odt_pattern_0 = 0x01010000;
+ odt_pattern_1 = 0x01010a0a;
+ odt_pattern_2 = 0x01090000;
+ odt_pattern_3 = 0x01030e0b;
+ } else if ((rank_count_dimm0 == 4) && (rank_count_dimm1 < 4)) {
+ odt_pattern_0 = 0x00000202;
+ odt_pattern_1 = 0x05050202;
+ odt_pattern_2 = 0x00000206;
+ odt_pattern_3 = 0x0d070203;
+ } else if ((rank_count_dimm0 == 4) && (rank_count_dimm1 == 4)) {
+ odt_pattern_0 = 0x05050a0a;
+ odt_pattern_1 = 0x05050a0a;
+ odt_pattern_2 = 0x050d0a0e;
+ odt_pattern_3 = 0x05070a0b;
+ } else {
+ /* Fallback */
+ odt_pattern_0 = 0x00000000;
+ odt_pattern_1 = 0x00000000;
+ odt_pattern_2 = 0x00000000;
+ odt_pattern_3 = 0x00000000;
+ }
+ }
+ } else {
+ /* FIXME
+ * 3 DIMMs per channel UNIMPLEMENTED
+ */
+ odt_pattern_0 = 0x00000000;
+ odt_pattern_1 = 0x00000000;
+ odt_pattern_2 = 0x00000000;
+ odt_pattern_3 = 0x00000000;
+ }
+ } else if (pDCTstat->C_DCTPtr[dct]->Status[DCT_STATUS_LOAD_REDUCED]) {
+ /* TODO
+ * Load reduced dimms UNIMPLEMENTED
+ */
+ odt_pattern_0 = 0x00000000;
+ odt_pattern_1 = 0x00000000;
+ odt_pattern_2 = 0x00000000;
+ odt_pattern_3 = 0x00000000;
+ } else {
+ if (MaxDimmsInstallable == 2) {
+ if (dimm_count == 1) {
+ /* 1 DIMM detected */
+ rank_count_dimm1 = pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
+ if (rank_count_dimm1 == 1) {
+ odt_pattern_0 = 0x00000000;
+ odt_pattern_1 = 0x00000000;
+ odt_pattern_2 = 0x00000000;
+ odt_pattern_3 = 0x00020000;
+ } else if (rank_count_dimm1 == 2) {
+ odt_pattern_0 = 0x00000000;
+ odt_pattern_1 = 0x00000000;
+ odt_pattern_2 = 0x00000000;
+ odt_pattern_3 = 0x08020000;
+ } else {
+ /* Fallback */
+ odt_pattern_0 = 0x00000000;
+ odt_pattern_1 = 0x00000000;
+ odt_pattern_2 = 0x00000000;
+ odt_pattern_3 = 0x08020000;
+ }
+ } else {
+ /* 2 DIMMs detected */
+ odt_pattern_0 = 0x00000000;
+ odt_pattern_1 = 0x01010202;
+ odt_pattern_2 = 0x00000000;
+ odt_pattern_3 = 0x09030603;
+ }
+ } else {
+ /* FIXME
+ * 3 DIMMs per channel UNIMPLEMENTED
+ */
+ odt_pattern_0 = 0x00000000;
+ odt_pattern_1 = 0x00000000;
+ odt_pattern_2 = 0x00000000;
+ odt_pattern_3 = 0x00000000;
+ }
+ }
+
+ if (pDCTstat->C_DCTPtr[dct]->Status[DCT_STATUS_LOAD_REDUCED]) {
+ /* TODO
+ * Load reduced dimms UNIMPLEMENTED
+ */
+ write_odt_duration = 0x0;
+ read_odt_duration = 0x0;
+ write_odt_delay = 0x0;
+ read_odt_delay = 0x0;
+ } else {
+ uint8_t tcl;
+ uint8_t tcwl;
+ tcl = Get_NB32_DCT(dev, dct, 0x200) & 0x1f;
+ tcwl = Get_NB32_DCT(dev, dct, 0x20c) & 0x1f;
+
+ write_odt_duration = 0x6;
+ read_odt_duration = 0x6;
+ write_odt_delay = 0x0;
+ if (tcl > tcwl)
+ read_odt_delay = tcl - tcwl;
+ else
+ read_odt_delay = 0x0;
+ }
+
+ /* Program ODT pattern */
+ Set_NB32_DCT(dev, dct, 0x230, odt_pattern_1);
+ Set_NB32_DCT(dev, dct, 0x234, odt_pattern_0);
+ Set_NB32_DCT(dev, dct, 0x238, odt_pattern_3);
+ Set_NB32_DCT(dev, dct, 0x23c, odt_pattern_2);
+ dword = Get_NB32_DCT(dev, dct, 0x240);
+ dword &= ~(0x7 << 12); /* WrOdtOnDuration = write_odt_duration */
+ dword |= (write_odt_duration & 0x7) << 12;
+ dword &= ~(0x7 << 8); /* WrOdtTrnOnDly = write_odt_delay */
+ dword |= (write_odt_delay & 0x7) << 8;
+ dword &= ~(0xf << 4); /* RdOdtOnDuration = read_odt_duration */
+ dword |= (read_odt_duration & 0xf) << 4;
+ dword &= ~(0xf); /* RdOdtTrnOnDly = read_odt_delay */
+ dword |= (read_odt_delay & 0xf);
+ Set_NB32_DCT(dev, dct, 0x240, dword);
+ } else if (pDCTstat->LogicalCPUID & AMD_DR_Dx) {
if (pDCTstat->Speed == 3)
dword = 0x00000800;
else
dword = 0x00000000;
for (i=0; i < 2; i++) {
- reg_off = 0x100 * i;
- Set_NB32(dev, 0x98 + reg_off, 0x0D000030);
- Set_NB32(dev, 0x9C + reg_off, dword);
- Set_NB32(dev, 0x98 + reg_off, 0x4D040F30);
-
- /* FIXME
- * Mainboards need to be able to specify the maximum number of DIMMs installable per channel
- * For now assume a maximum of 2 DIMMs per channel can be installed
- */
- uint8_t MaxDimmsInstallable = 2;
+ Set_NB32_DCT(dev, i, 0x98, 0x0D000030);
+ Set_NB32_DCT(dev, i, 0x9C, dword);
+ Set_NB32_DCT(dev, i, 0x98, 0x4D040F30);
/* Obtain number of DIMMs on channel */
uint8_t dimm_count = pDCTstat->MAdimms[i];
@@ -3469,7 +5595,7 @@ static void mct_BeforeDramInit_Prod_D(struct MCTStatStruc *pMCTstat,
uint32_t odt_pattern_3;
/* Select appropriate ODT pattern for installed DIMMs
- * Refer to the BKDG Rev. 3.62, page 120 onwards
+ * Refer to the Fam10h BKDG Rev. 3.62, page 120 onwards
*/
if (pDCTstat->C_DCTPtr[i]->Status[DCT_STATUS_REGISTERED]) {
if (MaxDimmsInstallable == 2) {
@@ -3580,10 +5706,10 @@ static void mct_BeforeDramInit_Prod_D(struct MCTStatStruc *pMCTstat,
}
/* Program ODT pattern */
- Set_NB32_index_wait(dev, 0xf0 + reg_off, 0x180, odt_pattern_1);
- Set_NB32_index_wait(dev, 0xf0 + reg_off, 0x181, odt_pattern_0);
- Set_NB32_index_wait(dev, 0xf0 + reg_off, 0x182, odt_pattern_3);
- Set_NB32_index_wait(dev, 0xf0 + reg_off, 0x183, odt_pattern_2);
+ Set_NB32_index_wait_DCT(dev, i, 0xf0, 0x180, odt_pattern_1);
+ Set_NB32_index_wait_DCT(dev, i, 0xf0, 0x181, odt_pattern_0);
+ Set_NB32_index_wait_DCT(dev, i, 0xf0, 0x182, odt_pattern_3);
+ Set_NB32_index_wait_DCT(dev, i, 0xf0, 0x183, odt_pattern_2);
}
}
}
@@ -3591,34 +5717,32 @@ static void mct_BeforeDramInit_Prod_D(struct MCTStatStruc *pMCTstat,
static void mct_EnDllShutdownSR(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat, u8 dct)
{
- u32 reg_off = 0x100 * dct;
u32 dev = pDCTstat->dev_dct, val;
/* Write 0000_07D0h to register F2x[1, 0]98_x4D0FE006 */
if (pDCTstat->LogicalCPUID & (AMD_DR_DAC2_OR_C3)) {
- Set_NB32(dev, 0x9C + reg_off, 0x1C);
- Set_NB32(dev, 0x98 + reg_off, 0x4D0FE006);
- Set_NB32(dev, 0x9C + reg_off, 0x13D);
- Set_NB32(dev, 0x98 + reg_off, 0x4D0FE007);
+ Set_NB32_DCT(dev, dct, 0x9C, 0x1C);
+ Set_NB32_DCT(dev, dct, 0x98, 0x4D0FE006);
+ Set_NB32_DCT(dev, dct, 0x9C, 0x13D);
+ Set_NB32_DCT(dev, dct, 0x98, 0x4D0FE007);
- val = Get_NB32(dev, 0x90 + reg_off);
+ val = Get_NB32_DCT(dev, dct, 0x90);
val &= ~(1 << 27/* DisDllShutdownSR */);
- Set_NB32(dev, 0x90 + reg_off, val);
+ Set_NB32_DCT(dev, dct, 0x90, val);
}
}
static u32 mct_DisDllShutdownSR(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat, u32 DramConfigLo, u8 dct)
{
- u32 reg_off = 0x100 * dct;
u32 dev = pDCTstat->dev_dct;
/* Write 0000_07D0h to register F2x[1, 0]98_x4D0FE006 */
if (pDCTstat->LogicalCPUID & (AMD_DR_DAC2_OR_C3)) {
- Set_NB32(dev, 0x9C + reg_off, 0x7D0);
- Set_NB32(dev, 0x98 + reg_off, 0x4D0FE006);
- Set_NB32(dev, 0x9C + reg_off, 0x190);
- Set_NB32(dev, 0x98 + reg_off, 0x4D0FE007);
+ Set_NB32_DCT(dev, dct, 0x9C, 0x7D0);
+ Set_NB32_DCT(dev, dct, 0x98, 0x4D0FE006);
+ Set_NB32_DCT(dev, dct, 0x9C, 0x190);
+ Set_NB32_DCT(dev, dct, 0x98, 0x4D0FE007);
DramConfigLo |= /* DisDllShutdownSR */ 1 << 27;
}
@@ -3710,52 +5834,61 @@ void ProgDramMRSReg_D(struct MCTStatStruc *pMCTstat,
DramMRS |= 1 << 23;
}
}
- /*
- DRAM MRS Register
- DrvImpCtrl: drive impedance control.01b(34 ohm driver; Ron34 = Rzq/7)
- */
- DramMRS |= 1 << 2;
- /* Dram nominal termination: */
- byte = pDCTstat->MAdimms[dct];
- if (!(pDCTstat->Status & (1 << SB_Registered))) {
- DramMRS |= 1 << 7; /* 60 ohms */
- if (byte & 2) {
- if (pDCTstat->Speed < 6)
- DramMRS |= 1 << 8; /* 40 ohms */
- else
- DramMRS |= 1 << 9; /* 30 ohms */
+
+ if (is_fam15h()) {
+ DramMRS |= (0x1 << 23); /* PchgPDModeSel = 1 */
+ } else {
+ /*
+ DRAM MRS Register
+ DrvImpCtrl: drive impedance control.01b(34 ohm driver; Ron34 = Rzq/7)
+ */
+ DramMRS |= 1 << 2;
+ /* Dram nominal termination: */
+ byte = pDCTstat->MAdimms[dct];
+ if (!(pDCTstat->Status & (1 << SB_Registered))) {
+ DramMRS |= 1 << 7; /* 60 ohms */
+ if (byte & 2) {
+ if (pDCTstat->Speed < 6)
+ DramMRS |= 1 << 8; /* 40 ohms */
+ else
+ DramMRS |= 1 << 9; /* 30 ohms */
+ }
}
- }
- /* Dram dynamic termination: Disable(1DIMM), 120ohm(>=2DIMM) */
- if (!(pDCTstat->Status & (1 << SB_Registered))) {
- if (byte >= 2) {
- if (pDCTstat->Speed == 7)
- DramMRS |= 1 << 10;
- else
- DramMRS |= 1 << 11;
+ /* Dram dynamic termination: Disable(1DIMM), 120ohm(>=2DIMM) */
+ if (!(pDCTstat->Status & (1 << SB_Registered))) {
+ if (byte >= 2) {
+ if (pDCTstat->Speed == 7)
+ DramMRS |= 1 << 10;
+ else
+ DramMRS |= 1 << 11;
+ }
+ } else {
+ DramMRS |= mct_DramTermDyn_RDimm(pMCTstat, pDCTstat, byte);
}
- } else {
- DramMRS |= mct_DramTermDyn_RDimm(pMCTstat, pDCTstat, byte);
+
+ /* Qoff=0, output buffers enabled */
+ /* Tcwl */
+ DramMRS |= (pDCTstat->Speed - 4) << 20;
+ /* ASR=1, auto self refresh */
+ /* SRT=0 */
+ DramMRS |= 1 << 18;
}
/* burst length control */
if (pDCTstat->Status & (1 << SB_128bitmode))
DramMRS |= 1 << 1;
- /* Qoff=0, output buffers enabled */
- /* Tcwl */
- DramMRS |= (pDCTstat->Speed - 4) << 20;
- /* ASR=1, auto self refresh */
- /* SRT=0 */
- DramMRS |= 1 << 18;
-
- dword = Get_NB32(pDCTstat->dev_dct, 0x100 * dct + 0x84);
- dword &= ~0x00FC2F8F;
+
+ dword = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x84);
+ if (is_fam15h())
+ dword &= ~0x00800003;
+ else
+ dword &= ~0x00fc2f8f;
dword |= DramMRS;
- Set_NB32(pDCTstat->dev_dct, 0x100 * dct + 0x84, dword);
+ Set_NB32_DCT(pDCTstat->dev_dct, dct, 0x84, dword);
}
-void mct_SetDramConfigHi_D(struct DCTStatStruc *pDCTstat, u32 dct,
- u32 DramConfigHi)
+void mct_SetDramConfigHi_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u32 dct, u32 DramConfigHi)
{
/* Bug#15114: Comp. update interrupted by Freq. change can cause
* subsequent update to be invalid during any MemClk frequency change:
@@ -3784,45 +5917,86 @@ void mct_SetDramConfigHi_D(struct DCTStatStruc *pDCTstat, u32 dct,
*/
u32 dev = pDCTstat->dev_dct;
- u32 index_reg = 0x98 + 0x100 * dct;
+ u32 index_reg = 0x98;
u32 index;
- u32 val;
+ uint32_t dword;
+
+ if (is_fam15h()) {
+ /* Initial setup for frequency change
+ * 9C_x0000_0004 must be configured before MemClkFreqVal is set
+ */
+
+ /* Program D18F2x9C_x0D0F_E006_dct[1:0][PllLockTime] = 0x190 */
+ dword = Get_NB32_index_wait_DCT(pDCTstat->dev_dct, dct, index_reg, 0x0d0fe006);
+ dword &= ~(0x0000ffff);
+ dword |= 0x00000190;
+ Set_NB32_index_wait_DCT(pDCTstat->dev_dct, dct, index_reg, 0x0d0fe006, dword);
+
+ dword = Get_NB32_DCT(dev, dct, 0x94);
+ dword &= ~(1 << MemClkFreqVal);
+ Set_NB32_DCT(dev, dct, 0x94, dword);
+
+ dword = DramConfigHi;
+ dword &= ~(1 << MemClkFreqVal);
+ Set_NB32_DCT(dev, dct, 0x94, dword);
+
+ mctGet_PS_Cfg_D(pMCTstat, pDCTstat, dct);
+ set_2t_configuration(pMCTstat, pDCTstat, dct);
+ mct_BeforePlatformSpec(pMCTstat, pDCTstat, dct);
+ mct_PlatformSpec(pMCTstat, pDCTstat, dct);
+ } else {
+ index = 0x08;
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, index);
+ if (!(dword & (1 << DisAutoComp)))
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, index, dword | (1 << DisAutoComp));
- index = 0x08;
- val = Get_NB32_index_wait(dev, index_reg, index);
- if (!(val & (1 << DisAutoComp)))
- Set_NB32_index_wait(dev, index_reg, index, val | (1 << DisAutoComp));
+ mct_Wait(100);
+ }
- mct_Wait(100);
+ /* Program the DRAM Configuration High register */
+ Set_NB32_DCT(dev, dct, 0x94, DramConfigHi);
- Set_NB32(dev, 0x94 + 0x100 * dct, DramConfigHi);
+ if (is_fam15h()) {
+ /* Wait until F2x[1, 0]94[FreqChgInProg]=0. */
+ do {
+ dword = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94);
+ } while (dword & (1 << FreqChgInProg));
+
+ /* Program D18F2x9C_x0D0F_E006_dct[1:0][PllLockTime] = 0xf */
+ dword = Get_NB32_index_wait_DCT(pDCTstat->dev_dct, dct, index_reg, 0x0d0fe006);
+ dword &= ~(0x0000ffff);
+ dword |= 0x0000000f;
+ Set_NB32_index_wait_DCT(pDCTstat->dev_dct, dct, index_reg, 0x0d0fe006, dword);
+ }
}
static void mct_BeforeDQSTrain_D(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstatA)
{
- u8 Node;
- struct DCTStatStruc *pDCTstat;
+ if (!is_fam15h()) {
+ u8 Node;
+ struct DCTStatStruc *pDCTstat;
- /* Errata 178
- *
- * Bug#15115: Uncertainty In The Sync Chain Leads To Setup Violations
- * In TX FIFO
- * Solution: BIOS should program DRAM Control Register[RdPtrInit] =
- * 5h, (F2x[1, 0]78[3:0] = 5h).
- * Silicon Status: Fixed In Rev B0
- *
- * Bug#15880: Determine validity of reset settings for DDR PHY timing.
- * Solution: At least, set WrDqs fine delay to be 0 for DDR3 training.
- */
- for (Node = 0; Node < 8; Node++) {
- pDCTstat = pDCTstatA + Node;
+ /* Errata 178
+ *
+ * Bug#15115: Uncertainty In The Sync Chain Leads To Setup Violations
+ * In TX FIFO
+ * Solution: BIOS should program DRAM Control Register[RdPtrInit] =
+ * 5h, (F2x[1, 0]78[3:0] = 5h).
+ * Silicon Status: Fixed In Rev B0
+ *
+ * Bug#15880: Determine validity of reset settings for DDR PHY timing.
+ * Solution: At least, set WrDqs fine delay to be 0 for DDR3 training.
+ */
+ for (Node = 0; Node < 8; Node++) {
+ pDCTstat = pDCTstatA + Node;
- if (pDCTstat->NodePresent) {
- mct_BeforeDQSTrainSamp(pDCTstat); /* only Bx */
- mct_ResetDLL_D(pMCTstat, pDCTstat, 0);
- mct_ResetDLL_D(pMCTstat, pDCTstat, 1);
+ if (pDCTstat->NodePresent) {
+ mct_BeforeDQSTrainSamp(pDCTstat); /* only Bx */
+ mct_ResetDLL_D(pMCTstat, pDCTstat, 0);
+ mct_ResetDLL_D(pMCTstat, pDCTstat, 1);
+ }
}
}
}
@@ -3833,7 +6007,6 @@ static void mct_ResetDLL_D(struct MCTStatStruc *pMCTstat,
{
u8 Receiver;
u32 dev = pDCTstat->dev_dct;
- u32 reg_off = 0x100 * dct;
u32 addr;
u32 lo, hi;
u8 wrap32dis = 0;
@@ -3844,6 +6017,11 @@ static void mct_ResetDLL_D(struct MCTStatStruc *pMCTstat,
return;
}
+ /* Skip reset DLL for Family 15h */
+ if (is_fam15h()) {
+ return;
+ }
+
addr = HWCR;
_RDMSR(addr, &lo, &hi);
if(lo & (1<<17)) { /* save the old value */
@@ -3863,11 +6041,11 @@ static void mct_ResetDLL_D(struct MCTStatStruc *pMCTstat,
mct_Read1LTestPattern_D(pMCTstat, pDCTstat, addr); /* cache fills */
/* Write 0000_8000h to register F2x[1,0]9C_xD080F0C */
- Set_NB32_index_wait(dev, 0x98 + reg_off, 0xD080F0C, 0x00008000);
+ Set_NB32_index_wait_DCT(dev, dct, 0x98, 0xD080F0C, 0x00008000);
mct_Wait(80); /* wait >= 300ns */
/* Write 0000_0000h to register F2x[1,0]9C_xD080F0C */
- Set_NB32_index_wait(dev, 0x98 + reg_off, 0xD080F0C, 0x00000000);
+ Set_NB32_index_wait_DCT(dev, dct, 0x98, 0xD080F0C, 0x00000000);
mct_Wait(800); /* wait >= 2us */
break;
}
@@ -3907,39 +6085,39 @@ static void mct_EnableDatIntlv_D(struct MCTStatStruc *pMCTstat,
static void SetDllSpeedUp_D(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat, u8 dct)
{
- u32 val;
- u32 dev = pDCTstat->dev_dct;
- u32 reg_off = 0x100 * dct;
-
- if (pDCTstat->Speed >= 7) { /* DDR1600 and above */
- /* Set bit13 PowerDown to register F2x[1, 0]98_x0D080F10 */
- Set_NB32(dev, reg_off + 0x98, 0x0D080F10);
- val = Get_NB32(dev, reg_off + 0x9C);
- val |= 1 < 13;
- Set_NB32(dev, reg_off + 0x9C, val);
- Set_NB32(dev, reg_off + 0x98, 0x4D080F10);
-
- /* Set bit13 PowerDown to register F2x[1, 0]98_x0D080F11 */
- Set_NB32(dev, reg_off + 0x98, 0x0D080F11);
- val = Get_NB32(dev, reg_off + 0x9C);
- val |= 1 < 13;
- Set_NB32(dev, reg_off + 0x9C, val);
- Set_NB32(dev, reg_off + 0x98, 0x4D080F11);
-
- /* Set bit13 PowerDown to register F2x[1, 0]98_x0D088F30 */
- Set_NB32(dev, reg_off + 0x98, 0x0D088F30);
- val = Get_NB32(dev, reg_off + 0x9C);
- val |= 1 < 13;
- Set_NB32(dev, reg_off + 0x9C, val);
- Set_NB32(dev, reg_off + 0x98, 0x4D088F30);
-
- /* Set bit13 PowerDown to register F2x[1, 0]98_x0D08CF30 */
- Set_NB32(dev, reg_off + 0x98, 0x0D08CF30);
- val = Get_NB32(dev, reg_off + 0x9C);
- val |= 1 < 13;
- Set_NB32(dev, reg_off + 0x9C, val);
- Set_NB32(dev, reg_off + 0x98, 0x4D08CF30);
-
+ if (!is_fam15h()) {
+ u32 val;
+ u32 dev = pDCTstat->dev_dct;
+
+ if (pDCTstat->Speed >= mhz_to_memclk_config(800)) { /* DDR1600 and above */
+ /* Set bit13 PowerDown to register F2x[1, 0]98_x0D080F10 */
+ Set_NB32_DCT(dev, dct, 0x98, 0x0D080F10);
+ val = Get_NB32_DCT(dev, dct, 0x9C);
+ val |= 1 < 13;
+ Set_NB32_DCT(dev, dct, 0x9C, val);
+ Set_NB32_DCT(dev, dct, 0x98, 0x4D080F10);
+
+ /* Set bit13 PowerDown to register F2x[1, 0]98_x0D080F11 */
+ Set_NB32_DCT(dev, dct, 0x98, 0x0D080F11);
+ val = Get_NB32_DCT(dev, dct, 0x9C);
+ val |= 1 < 13;
+ Set_NB32_DCT(dev, dct, 0x9C, val);
+ Set_NB32_DCT(dev, dct, 0x98, 0x4D080F11);
+
+ /* Set bit13 PowerDown to register F2x[1, 0]98_x0D088F30 */
+ Set_NB32_DCT(dev, dct, 0x98, 0x0D088F30);
+ val = Get_NB32_DCT(dev, dct, 0x9C);
+ val |= 1 < 13;
+ Set_NB32_DCT(dev, dct, 0x9C, val);
+ Set_NB32_DCT(dev, dct, 0x98, 0x4D088F30);
+
+ /* Set bit13 PowerDown to register F2x[1, 0]98_x0D08CF30 */
+ Set_NB32_DCT(dev, dct, 0x98, 0x0D08CF30);
+ val = Get_NB32_DCT(dev, dct, 0x9C);
+ val |= 1 < 13;
+ Set_NB32_DCT(dev, dct, 0x9C, val);
+ Set_NB32_DCT(dev, dct, 0x98, 0x4D08CF30);
+ }
}
}
@@ -3967,7 +6145,6 @@ static void SyncSetting(struct DCTStatStruc *pDCTstat)
static void AfterDramInit_D(struct DCTStatStruc *pDCTstat, u8 dct) {
u32 val;
- u32 reg_off = 0x100 * dct;
u32 dev = pDCTstat->dev_dct;
if (pDCTstat->LogicalCPUID & (AMD_DR_B2 | AMD_DR_B3)) {
@@ -3975,16 +6152,16 @@ static void AfterDramInit_D(struct DCTStatStruc *pDCTstat, u8 dct) {
val = Get_NB32(dev, 0x110);
if (!(val & (1 << DramEnabled))) {
/* If 50 us expires while DramEnable =0 then do the following */
- val = Get_NB32(dev, 0x90 + reg_off);
+ val = Get_NB32_DCT(dev, dct, 0x90);
val &= ~(1 << Width128); /* Program Width128 = 0 */
- Set_NB32(dev, 0x90 + reg_off, val);
+ Set_NB32_DCT(dev, dct, 0x90, val);
- val = Get_NB32_index_wait(dev, 0x98 + reg_off, 0x05); /* Perform dummy CSR read to F2x09C_x05 */
+ val = Get_NB32_index_wait_DCT(dev, dct, 0x98, 0x05); /* Perform dummy CSR read to F2x09C_x05 */
if (pDCTstat->GangedMode) {
- val = Get_NB32(dev, 0x90 + reg_off);
+ val = Get_NB32_DCT(dev, dct, 0x90);
val |= 1 << Width128; /* Program Width128 = 0 */
- Set_NB32(dev, 0x90 + reg_off, val);
+ Set_NB32_DCT(dev, dct, 0x90, val);
}
}
}
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
index 146e699a56..3aeb7eca2e 100644
--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
@@ -72,6 +72,8 @@
/* #define PA_EXT_DCTADDL (((00 << 3)+5) << 8) */ /*Node x DCT function, Additional Registers PCI Address bits [15:0]*/
#define PA_NBMISC(Node) ((((0x18+Node) << 3)+3) << 12) /*Node 0 Misc PCI Address bits [15:0]*/
+#define PA_LINK(Node) ((((0x18+Node) << 3)+4) << 12) /*Node 0 Link Control bits [15:0]*/
+#define PA_NBCTL(Node) ((((0x18+Node) << 3)+5) << 12) /*Node 0 NB Control PCI Address bits [15:0]*/
/* #define PA_NBDEVOP (((00 << 3)+3) << 8) */ /*Node 0 Misc PCI Address bits [15:0]*/
#define DCC_EN 1 /* X:2:0x94[19]*/
@@ -125,7 +127,7 @@
#define X4Dimm 12 /* func 2, offset 90h, bit 12*/
#define UnBuffDimm 16 /* func 2, offset 90h, bit 16*/
#define DimmEcEn 19 /* func 2, offset 90h, bit 19*/
-#define MemClkFreqVal 3 /* func 2, offset 94h, bit 3*/
+#define MemClkFreqVal ((is_fam15h())?7:3) /* func 2, offset 94h, bit 3 or 7*/
#define RDqsEn 12 /* func 2, offset 94h, bit 12*/
#define DisDramInterface 14 /* func 2, offset 94h, bit 14*/
#define PowerDownEn 15 /* func 2, offset 94h, bit 15*/
@@ -200,6 +202,7 @@
#define JED_PROBEMSK 0x40 /*Analysis Probe installed*/
#define JED_RDIMM 0x1 /* RDIMM */
#define JED_MiniRDIMM 0x5 /* Mini-RDIMM */
+ #define JED_LRDIMM 0xb /* Load-reduced DIMM */
#define SPD_Density 4 /* Bank address bits,SDRAM capacity */
#define SPD_Addressing 5 /* Row/Column address bits */
#define SPD_Voltage 6 /* Supported voltage bitfield */
@@ -293,6 +296,7 @@ struct MCTStatStruc {
of sub 4GB dram hole for HW remapping.*/
u32 Sub4GCacheTop; /* If not zero, the 32-bit top of cacheable memory.*/
u32 SysLimit; /* LIMIT[39:8] (system address)*/
+ uint32_t TSCFreq;
} __attribute__((packed));
/*=============================================================================
@@ -316,7 +320,8 @@ struct MCTStatStruc {
struct DCTStatStruc { /* A per Node structure*/
/* DCTStatStruct_F - start */
- u8 Node_ID; /* Node ID of current controller*/
+ u8 Node_ID; /* Node ID of current controller */
+ uint8_t stopDCT; /* Set if the DCT will be stopped */
u8 ErrCode; /* Current error condition of Node
0= no error
1= Variance Error, DCT is running but not in an optimal configuration.
@@ -460,7 +465,7 @@ struct DCTStatStruc { /* A per Node structure*/
/* CH A byte lane 0 - 7 maximum filtered window passing DQS delay value*/
/* CH B byte lane 0 - 7 minimum filtered window passing DQS delay value*/
/* CH B byte lane 0 - 7 maximum filtered window passing DQS delay value*/
- u32 LogicalCPUID; /* The logical CPUID of the node*/
+ uint64_t LogicalCPUID; /* The logical CPUID of the node*/
u16 HostBiosSrvc1; /* Word sized general purpose field for use by host BIOS. Scratch space.*/
u32 HostBiosSrvc2; /* Dword sized general purpose field for use by host BIOS. Scratch space.*/
u16 DimmQRPresent; /* QuadRank DIMM present?*/
@@ -554,12 +559,20 @@ struct DCTStatStruc { /* A per Node structure*/
u8 ClToNB_flag; /* is used to restore ClLinesToNbDis bit after memory */
u32 NodeSysBase; /* for channel interleave usage */
+ /* Fam15h specific backup variables */
+ uint8_t SwNbPstateLoDis;
+ uint8_t NbPstateDisOnP0;
+ uint8_t NbPstateThreshold;
+ uint8_t NbPstateHi;
+
/* New for LB Support */
u8 NodePresent;
u32 dev_host;
u32 dev_map;
u32 dev_dct;
u32 dev_nbmisc;
+ u32 dev_link;
+ u32 dev_nbctl;
u8 TargetFreq;
u8 TargetCASL;
u8 CtrlWrd3;
@@ -592,9 +605,10 @@ struct DCTStatStruc { /* A per Node structure*/
uint8_t DimmBanks[MAX_DIMMS_SUPPORTED];
uint8_t DimmWidth[MAX_DIMMS_SUPPORTED];
uint8_t DimmRegistered[MAX_DIMMS_SUPPORTED];
+ uint8_t DimmLoadReduced[MAX_DIMMS_SUPPORTED];
uint64_t DimmManufacturerID[MAX_DIMMS_SUPPORTED];
- char DimmPartNumber[MAX_DIMMS_SUPPORTED][SPD_PARTN_LENGTH];
+ char DimmPartNumber[MAX_DIMMS_SUPPORTED][SPD_PARTN_LENGTH+1];
uint16_t DimmRevisionNumber[MAX_DIMMS_SUPPORTED];
uint32_t DimmSerialNumber[MAX_DIMMS_SUPPORTED];
} __attribute__((packed));
@@ -697,7 +711,64 @@ struct amd_s3_persistent_mct_channel_data {
/* Other (1 dword) */
uint32_t f3x58;
- /* TOTAL: 250 dwords */
+ /* Family 15h-specific registers (90 dwords) */
+ uint32_t f2x200;
+ uint32_t f2x204;
+ uint32_t f2x208;
+ uint32_t f2x20c;
+ uint32_t f2x210[4]; /* [nb pstate] */
+ uint32_t f2x214;
+ uint32_t f2x218;
+ uint32_t f2x21c;
+ uint32_t f2x22c;
+ uint32_t f2x230;
+ uint32_t f2x234;
+ uint32_t f2x238;
+ uint32_t f2x23c;
+ uint32_t f2x240;
+ uint32_t f2x9cx0d0fe003;
+ uint32_t f2x9cx0d0fe013;
+ uint32_t f2x9cx0d0f0_8_0_1f[9]; /* [lane]*/
+ uint32_t f2x9cx0d0f201f;
+ uint32_t f2x9cx0d0f211f;
+ uint32_t f2x9cx0d0f221f;
+ uint32_t f2x9cx0d0f801f;
+ uint32_t f2x9cx0d0f811f;
+ uint32_t f2x9cx0d0f821f;
+ uint32_t f2x9cx0d0fc01f;
+ uint32_t f2x9cx0d0fc11f;
+ uint32_t f2x9cx0d0fc21f;
+ uint32_t f2x9cx0d0f4009;
+ uint32_t f2x9cx0d0f0_8_0_02[9]; /* [lane]*/
+ uint32_t f2x9cx0d0f0_8_0_06[9]; /* [lane]*/
+ uint32_t f2x9cx0d0f0_8_0_0a[9]; /* [lane]*/
+ uint32_t f2x9cx0d0f2002;
+ uint32_t f2x9cx0d0f2102;
+ uint32_t f2x9cx0d0f2202;
+ uint32_t f2x9cx0d0f8002;
+ uint32_t f2x9cx0d0f8006;
+ uint32_t f2x9cx0d0f800a;
+ uint32_t f2x9cx0d0f8102;
+ uint32_t f2x9cx0d0f8106;
+ uint32_t f2x9cx0d0f810a;
+ uint32_t f2x9cx0d0fc002;
+ uint32_t f2x9cx0d0fc006;
+ uint32_t f2x9cx0d0fc00a;
+ uint32_t f2x9cx0d0fc00e;
+ uint32_t f2x9cx0d0fc012;
+ uint32_t f2x9cx0d0f2031;
+ uint32_t f2x9cx0d0f2131;
+ uint32_t f2x9cx0d0f2231;
+ uint32_t f2x9cx0d0f8031;
+ uint32_t f2x9cx0d0f8131;
+ uint32_t f2x9cx0d0f8231;
+ uint32_t f2x9cx0d0fc031;
+ uint32_t f2x9cx0d0fc131;
+ uint32_t f2x9cx0d0fc231;
+ uint32_t f2x9cx0d0f0_0_f_31[9]; /* [lane] */
+ uint32_t f2x9cx0d0f8021;
+
+ /* TOTAL: 340 dwords */
} __attribute__((packed));
struct amd_s3_persistent_node_data {
@@ -742,18 +813,19 @@ struct amd_s3_persistent_data {
Local Configuration Status (DCTStatStruc.Status[31:0])
===============================================================================*/
#define SB_Registered 0 /* All DIMMs are Registered*/
-#define SB_ECCDIMMs 1 /* All banks ECC capable*/
-#define SB_PARDIMMs 2 /* All banks Addr/CMD Parity capable*/
-#define SB_DiagClks 3 /* Jedec ALL slots clock enable diag mode*/
-#define SB_128bitmode 4 /* DCT in 128-bit mode operation*/
-#define SB_64MuxedMode 5 /* DCT in 64-bit mux'ed mode.*/
-#define SB_2TMode 6 /* 2T CMD timing mode is enabled.*/
-#define SB_SWNodeHole 7 /* Remapping of Node Base on this Node to create a gap.*/
-#define SB_HWHole 8 /* Memory Hole created on this Node using HW remapping.*/
-#define SB_Over400MHz 9 /* DCT freq >= 400MHz flag*/
-#define SB_DQSPos_Pass2 10 /* Using for TrainDQSPos DIMM0/1, when freq>=400MHz*/
-#define SB_DQSRcvLimit 11 /* Using for DQSRcvEnTrain to know we have reached to upper bound.*/
-#define SB_ExtConfig 12 /* Indicator the default setting for extend PCI configuration support*/
+#define SB_LoadReduced 1 /* All DIMMs are Load-Reduced*/
+#define SB_ECCDIMMs 2 /* All banks ECC capable*/
+#define SB_PARDIMMs 3 /* All banks Addr/CMD Parity capable*/
+#define SB_DiagClks 4 /* Jedec ALL slots clock enable diag mode*/
+#define SB_128bitmode 5 /* DCT in 128-bit mode operation*/
+#define SB_64MuxedMode 6 /* DCT in 64-bit mux'ed mode.*/
+#define SB_2TMode 7 /* 2T CMD timing mode is enabled.*/
+#define SB_SWNodeHole 8 /* Remapping of Node Base on this Node to create a gap.*/
+#define SB_HWHole 9 /* Memory Hole created on this Node using HW remapping.*/
+#define SB_Over400MHz 10 /* DCT freq >= 400MHz flag*/
+#define SB_DQSPos_Pass2 11 /* Using for TrainDQSPos DIMM0/1, when freq>=400MHz*/
+#define SB_DQSRcvLimit 12 /* Using for DQSRcvEnTrain to know we have reached to upper bound.*/
+#define SB_ExtConfig 13 /* Indicator the default setting for extend PCI configuration support*/
/*===============================================================================
@@ -771,17 +843,18 @@ struct amd_s3_persistent_data {
266=266MHz (DDR533)
333=333MHz (DDR667)
400=400MHz (DDR800)*/
-#define NV_ECC_CAP 4 /* Bus ECC capable (1-bits)
+#define NV_MIN_MEMCLK 4 /* Minimum platform demonstrated Memclock (10-bits) */
+#define NV_ECC_CAP 5 /* Bus ECC capable (1-bits)
0=Platform not capable
1=Platform is capable*/
-#define NV_4RANKType 5 /* Quad Rank DIMM slot type (2-bits)
+#define NV_4RANKType 6 /* Quad Rank DIMM slot type (2-bits)
0=Normal
1=R4 (4-Rank Registered DIMMs in AMD server configuration)
2=S4 (Unbuffered SO-DIMMs)*/
-#define NV_BYPMAX 6 /* Value to set DcqBypassMax field (See Function 2, Offset 94h, [27:24] of BKDG for field definition).
+#define NV_BYPMAX 7 /* Value to set DcqBypassMax field (See Function 2, Offset 94h, [27:24] of BKDG for field definition).
4=4 times bypass (normal for non-UMA systems)
7=7 times bypass (normal for UMA systems)*/
-#define NV_RDWRQBYP 7 /* Value to set RdWrQByp field (See Function 2, Offset A0h, [3:2] of BKDG for field definition).
+#define NV_RDWRQBYP 8 /* Value to set RdWrQByp field (See Function 2, Offset A0h, [3:2] of BKDG for field definition).
2=8 times (normal for non-UMA systems)
3=16 times (normal for UMA systems)*/
@@ -844,8 +917,9 @@ struct amd_s3_persistent_data {
#define NV_ECCRedir 54 /* Dram ECC Redirection enable*/
#define NV_DramBKScrub 55 /* Dram ECC Background Scrubber CTL*/
#define NV_L2BKScrub 56 /* L2 ECC Background Scrubber CTL*/
-#define NV_DCBKScrub 57 /* DCache ECC Background Scrubber CTL*/
-#define NV_CS_SpareCTL 58 /* Chip Select Spare Control bit 0:
+#define NV_L3BKScrub 57 /* L3 ECC Background Scrubber CTL*/
+#define NV_DCBKScrub 58 /* DCache ECC Background Scrubber CTL*/
+#define NV_CS_SpareCTL 59 /* Chip Select Spare Control bit 0:
0=disable Spare
1=enable Spare */
/* Chip Select Spare Control bit 1-4:
@@ -896,10 +970,12 @@ void mct_SetRcvrEnDly_D(struct DCTStatStruc *pDCTstat, u16 RcvrEnDly, u8 FinalVa
void SetEccDQSRcvrEn_D(struct DCTStatStruc *pDCTstat, u8 Channel);
void mctGet_PS_Cfg_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u32 dct);
void InterleaveBanks_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u8 dct);
-void mct_SetDramConfigHi_D(struct DCTStatStruc *pDCTstat, u32 dct, u32 DramConfigHi);
+void mct_SetDramConfigHi_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u32 dct, u32 DramConfigHi);
void mct_DramInit_Hw_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u8 dct);
void mct_SetClToNB_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat);
void mct_SetWbEnhWsbDis_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat);
+void mct_ForceNBPState0_En_Fam15(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat);
+void mct_ForceNBPState0_Dis_Fam15(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat);
void mct_TrainRcvrEn_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u8 Pass);
void mct_EnableDimmEccEn_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u8 _DisableDramECC);
u32 procOdtWorkaround(struct DCTStatStruc *pDCTstat, u32 dct, u32 val);
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d_gcc.h b/src/northbridge/amd/amdmct/mct_ddr3/mct_d_gcc.h
index 3534f58d84..c4bfd3fe64 100644
--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d_gcc.h
+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d_gcc.h
@@ -94,6 +94,15 @@ static u32 bsf(u32 x)
u32 SetUpperFSbase(u32 addr_hi);
+static void proc_MFENCE(void)
+{
+ __asm__ volatile (
+ "outb %%al, $0xed\n\t" /* _EXECFENCE */
+ "mfence\n\t"
+ :::"memory"
+ );
+}
+
static void proc_CLFLUSH(u32 addr_hi)
{
SetUpperFSbase(addr_hi);
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctardk5.c b/src/northbridge/amd/amdmct/mct_ddr3/mctardk5.c
index 1700cf76b5..93d2800b00 100644
--- a/src/northbridge/amd/amdmct/mct_ddr3/mctardk5.c
+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctardk5.c
@@ -2,6 +2,7 @@
* This file is part of the coreboot project.
*
* Copyright (C) 2010 Advanced Micro Devices, Inc.
+ * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering
*
* 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
@@ -13,6 +14,8 @@
* GNU General Public License for more details.
*/
+/* AM3/ASB2/C32/G34 DDR3 */
+
static void Get_ChannelPS_Cfg0_D(u8 MAAdimms, u8 Speed, u8 MAAload,
u32 *AddrTmgCTL, u32 *ODC_CTL,
u8 *CMDmode);
@@ -20,17 +23,23 @@ static void Get_ChannelPS_Cfg0_D(u8 MAAdimms, u8 Speed, u8 MAAload,
void mctGet_PS_Cfg_D(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat, u32 dct)
{
- Get_ChannelPS_Cfg0_D(pDCTstat->MAdimms[dct], pDCTstat->Speed,
- pDCTstat->MAload[dct],
- &(pDCTstat->CH_ADDR_TMG[dct]), &(pDCTstat->CH_ODC_CTL[dct]),
- &pDCTstat->_2Tmode);
+ if (is_fam15h()) {
+ pDCTstat->CH_ADDR_TMG[dct] = fam15h_address_timing_compensation_code(pDCTstat, dct);
+ pDCTstat->CH_ODC_CTL[dct] = fam15h_output_driver_compensation_code(pDCTstat, dct);
+ pDCTstat->_2Tmode = fam15h_slow_access_mode(pDCTstat, dct);
+ } else {
+ Get_ChannelPS_Cfg0_D(pDCTstat->MAdimms[dct], pDCTstat->Speed,
+ pDCTstat->MAload[dct],
+ &(pDCTstat->CH_ADDR_TMG[dct]), &(pDCTstat->CH_ODC_CTL[dct]),
+ &pDCTstat->_2Tmode);
+
+ pDCTstat->CH_ODC_CTL[dct] |= 0x20000000; /* 60ohms */
+ }
pDCTstat->CH_EccDQSLike[0] = 0x0403;
pDCTstat->CH_EccDQSScale[0] = 0x70;
pDCTstat->CH_EccDQSLike[1] = 0x0403;
pDCTstat->CH_EccDQSScale[1] = 0x70;
-
- pDCTstat->CH_ODC_CTL[dct] |= 0x20000000; /* 60ohms */
}
/*
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctcsi_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mctcsi_d.c
index 94f7716758..253a89fbc0 100644
--- a/src/northbridge/amd/amdmct/mct_ddr3/mctcsi_d.c
+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctcsi_d.c
@@ -2,6 +2,7 @@
* This file is part of the coreboot project.
*
* Copyright (C) 2010 Advanced Micro Devices, Inc.
+ * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering
*
* 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
@@ -31,7 +32,6 @@ void InterleaveBanks_D(struct MCTStatStruc *pMCTstat,
u32 dev;
u32 reg;
- u32 reg_off;
u32 val;
u32 val_lo, val_hi;
@@ -40,16 +40,15 @@ void InterleaveBanks_D(struct MCTStatStruc *pMCTstat,
EnChipSels = 0;
dev = pDCTstat->dev_dct;
- reg_off = 0x100 * dct;
ChipSel = 0; /* Find out if current configuration is capable */
while (DoIntlv && (ChipSel < MAX_CS_SUPPORTED)) {
- reg = 0x40+(ChipSel<<2) + reg_off; /* Dram CS Base 0 */
- val = Get_NB32(dev, reg);
+ reg = 0x40+(ChipSel<<2); /* Dram CS Base 0 */
+ val = Get_NB32_DCT(dev, dct, reg);
if ( val & (1<<CSEnable)) {
EnChipSels++;
- reg = 0x60+((ChipSel>>1)<<2)+reg_off; /*Dram CS Mask 0 */
- val = Get_NB32(dev, reg);
+ reg = 0x60+((ChipSel>>1)<<2); /*Dram CS Mask 0 */
+ val = Get_NB32_DCT(dev, dct, reg);
val >>= 19;
val &= 0x3ff;
val++;
@@ -59,8 +58,8 @@ void InterleaveBanks_D(struct MCTStatStruc *pMCTstat,
/*If mask sizes not same then skip */
if (val != MemSize)
break;
- reg = 0x80 + reg_off; /*Dram Bank Addressing */
- val = Get_NB32(dev, reg);
+ reg = 0x80; /*Dram Bank Addressing */
+ val = Get_NB32_DCT(dev, dct, reg);
val >>= (ChipSel>>1)<<2;
val &= 0x0f;
if(EnChipSels == 1)
@@ -99,8 +98,8 @@ void InterleaveBanks_D(struct MCTStatStruc *pMCTstat,
BitDelta = bsf(AddrHiMask) - bsf(AddrLoMask);
for (ChipSel = 0; ChipSel < MAX_CS_SUPPORTED; ChipSel++) {
- reg = 0x40+(ChipSel<<2) + reg_off; /*Dram CS Base 0 */
- val = Get_NB32(dev, reg);
+ reg = 0x40+(ChipSel<<2); /*Dram CS Base 0 */
+ val = Get_NB32_DCT(dev, dct, reg);
if (val & 3) {
val_lo = val & AddrLoMask;
val_hi = val & AddrHiMask;
@@ -110,13 +109,13 @@ void InterleaveBanks_D(struct MCTStatStruc *pMCTstat,
val_hi >>= BitDelta;
val |= val_lo;
val |= val_hi;
- Set_NB32(dev, reg, val);
+ Set_NB32_DCT(dev, dct, reg, val);
if(ChipSel & 1)
continue;
- reg = 0x60 + ((ChipSel>>1)<<2) + reg_off; /*Dram CS Mask 0 */
- val = Get_NB32(dev, reg);
+ reg = 0x60 + ((ChipSel>>1)<<2); /*Dram CS Mask 0 */
+ val = Get_NB32_DCT(dev, dct, reg);
val_lo = val & AddrLoMask;
val_hi = val & AddrHiMask;
val &= AddrLoMaskN;
@@ -125,7 +124,7 @@ void InterleaveBanks_D(struct MCTStatStruc *pMCTstat,
val_hi >>= BitDelta;
val |= val_lo;
val |= val_hi;
- Set_NB32(dev, reg, val);
+ Set_NB32_DCT(dev, dct, reg, val);
}
}
} /* DoIntlv */
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
index e77a4ddaf1..537c616a73 100644
--- a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
@@ -14,6 +14,12 @@
* GNU General Public License for more details.
*/
+static void write_dqs_receiver_enable_control_registers(uint16_t* current_total_delay,
+ uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t index_reg);
+
+static void read_read_dqs_timing_control_registers(uint16_t* current_total_delay,
+ uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t index_reg);
+
static void CalcEccDQSPos_D(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat, u16 like,
u8 scale, u8 ChipSel);
@@ -33,7 +39,7 @@ static void FlushDQSTestPattern_D(struct DCTStatStruc *pDCTstat,
u32 addr_lo);
static void SetTargetWTIO_D(u32 TestAddr);
static void ResetTargetWTIO_D(void);
-void ResetDCTWrPtr_D(u32 dev, u32 index_reg, u32 index);
+void ResetDCTWrPtr_D(u32 dev, uint8_t dct, u32 index_reg, u32 index);
u8 mct_DisableDimmEccEn_D(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat);
static void mct_SetDQSDelayCSR_D(struct MCTStatStruc *pMCTstat,
@@ -50,6 +56,7 @@ static void proc_IOCLFLUSH_D(u32 addr_hi);
static void StoreDQSDatStrucVal_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u8 ChipSel);
#define DQS_TRAIN_DEBUG 0
+// #define PRINT_PASS_FAIL_BITMAPS 1
static void print_debug_dqs(const char *str, u32 val, u8 level)
{
@@ -194,18 +201,20 @@ void TrainReceiverEn_D(struct MCTStatStruc *pMCTstat,
pDCTstat = pDCTstatA + Node;
if (pDCTstat->DCTSysLimit) {
- val = Get_NB32(pDCTstat->dev_dct, 0x78);
- val |= 1 <<DqsRcvEnTrain;
- Set_NB32(pDCTstat->dev_dct, 0x78, val);
- val = Get_NB32(pDCTstat->dev_dct, 0x78 + 0x100);
- val |= 1 <<DqsRcvEnTrain;
- Set_NB32(pDCTstat->dev_dct, 0x78 + 0x100, val);
+ if (!is_fam15h()) {
+ val = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x78);
+ val |= 1 <<DqsRcvEnTrain;
+ Set_NB32_DCT(pDCTstat->dev_dct, 0, 0x78, val);
+ val = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x78);
+ val |= 1 <<DqsRcvEnTrain;
+ Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x78, val);
+ }
mct_TrainRcvrEn_D(pMCTstat, pDCTstat, Pass);
}
}
}
-static void SetEccDQSRdWrPos_D(struct MCTStatStruc *pMCTstat,
+static void SetEccDQSRdWrPos_D_Fam10(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat, u8 ChipSel)
{
u8 channel;
@@ -264,68 +273,150 @@ static void CalcEccDQSPos_D(struct MCTStatStruc *pMCTstat,
pDCTstat->DQSDelay = (u8)DQSDelay;
}
-static void write_dqs_write_data_timing_registers(uint16_t* delay, uint32_t dev, uint8_t dimm, uint32_t index_reg)
+static void read_dqs_write_data_timing_registers(uint16_t* delay, uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t index_reg)
+{
+ uint32_t dword;
+ uint32_t mask;
+
+ if (is_fam15h())
+ mask = 0xff;
+ else
+ mask = 0x7f;
+
+ /* Lanes 0 - 3 */
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x1 | (dimm << 8));
+ delay[3] = (dword >> 24) & mask;
+ delay[2] = (dword >> 16) & mask;
+ delay[1] = (dword >> 8) & mask;
+ delay[0] = dword & mask;
+
+ /* Lanes 4 - 7 */
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x2 | (dimm << 8));
+ delay[7] = (dword >> 24) & mask;
+ delay[6] = (dword >> 16) & mask;
+ delay[5] = (dword >> 8) & mask;
+ delay[4] = dword & mask;
+
+ /* Lane 8 (ECC) */
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x3 | (dimm << 8));
+ delay[8] = dword & mask;
+}
+
+static void write_dqs_write_data_timing_registers(uint16_t* delay, uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t index_reg)
{
uint32_t dword;
+ uint32_t mask;
+
+ if (is_fam15h())
+ mask = 0xff;
+ else
+ mask = 0x7f;
/* Lanes 0 - 3 */
- dword = Get_NB32_index_wait(dev, index_reg, 0x1 | (dimm << 8));
- dword &= ~0x7f7f7f7f;
- dword |= (delay[3] & 0x7f) << 24;
- dword |= (delay[2] & 0x7f) << 16;
- dword |= (delay[1] & 0x7f) << 8;
- dword |= delay[0] & 0x7f;
- Set_NB32_index_wait(dev, index_reg, 0x1 | (dimm << 8), dword);
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x1 | (dimm << 8));
+ dword &= ~(mask << 24);
+ dword &= ~(mask << 16);
+ dword &= ~(mask << 8);
+ dword &= ~mask;
+ dword |= (delay[3] & mask) << 24;
+ dword |= (delay[2] & mask) << 16;
+ dword |= (delay[1] & mask) << 8;
+ dword |= delay[0] & mask;
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x1 | (dimm << 8), dword);
/* Lanes 4 - 7 */
- dword = Get_NB32_index_wait(dev, index_reg, 0x2 | (dimm << 8));
- dword &= ~0x7f7f7f7f;
- dword |= (delay[7] & 0x7f) << 24;
- dword |= (delay[6] & 0x7f) << 16;
- dword |= (delay[5] & 0x7f) << 8;
- dword |= delay[4] & 0x7f;
- Set_NB32_index_wait(dev, index_reg, 0x2 | (dimm << 8), dword);
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x2 | (dimm << 8));
+ dword &= ~(mask << 24);
+ dword &= ~(mask << 16);
+ dword &= ~(mask << 8);
+ dword &= ~mask;
+ dword |= (delay[7] & mask) << 24;
+ dword |= (delay[6] & mask) << 16;
+ dword |= (delay[5] & mask) << 8;
+ dword |= delay[4] & mask;
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x2 | (dimm << 8), dword);
/* Lane 8 (ECC) */
- dword = Get_NB32_index_wait(dev, index_reg, 0x3 | (dimm << 8));
- dword &= ~0x0000007f;
- dword |= delay[8] & 0x7f;
- Set_NB32_index_wait(dev, index_reg, 0x3 | (dimm << 8), dword);
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x3 | (dimm << 8));
+ dword &= ~mask;
+ dword |= delay[8] & mask;
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x3 | (dimm << 8), dword);
}
-static void write_dqs_read_data_timing_registers(uint16_t* delay, uint32_t dev, uint8_t dimm, uint32_t index_reg)
+static void read_dqs_read_data_timing_registers(uint16_t* delay, uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t index_reg)
{
uint32_t dword;
+ uint32_t mask;
+
+ if (is_fam15h())
+ mask = 0x3e;
+ else
+ mask = 0x3f;
/* Lanes 0 - 3 */
- dword = Get_NB32_index_wait(dev, index_reg, 0x5 | (dimm << 8));
- dword &= ~0x3f3f3f3f;
- dword |= (delay[3] & 0x3f) << 24;
- dword |= (delay[2] & 0x3f) << 16;
- dword |= (delay[1] & 0x3f) << 8;
- dword |= delay[0] & 0x3f;
- Set_NB32_index_wait(dev, index_reg, 0x5 | (dimm << 8), dword);
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x5 | (dimm << 8));
+ delay[3] = (dword >> 24) & mask;
+ delay[2] = (dword >> 16) & mask;
+ delay[1] = (dword >> 8) & mask;
+ delay[0] = dword & mask;
/* Lanes 4 - 7 */
- dword = Get_NB32_index_wait(dev, index_reg, 0x6 | (dimm << 8));
- dword &= ~0x3f3f3f3f;
- dword |= (delay[7] & 0x3f) << 24;
- dword |= (delay[6] & 0x3f) << 16;
- dword |= (delay[5] & 0x3f) << 8;
- dword |= delay[4] & 0x3f;
- Set_NB32_index_wait(dev, index_reg, 0x6 | (dimm << 8), dword);
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x6 | (dimm << 8));
+ delay[7] = (dword >> 24) & mask;
+ delay[6] = (dword >> 16) & mask;
+ delay[5] = (dword >> 8) & mask;
+ delay[4] = dword & mask;
/* Lane 8 (ECC) */
- dword = Get_NB32_index_wait(dev, index_reg, 0x7 | (dimm << 8));
- dword &= ~0x0000003f;
- dword |= delay[8] & 0x3f;
- Set_NB32_index_wait(dev, index_reg, 0x7 | (dimm << 8), dword);
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x7 | (dimm << 8));
+ delay[8] = dword & mask;
+}
+
+static void write_dqs_read_data_timing_registers(uint16_t* delay, uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t index_reg)
+{
+ uint32_t dword;
+ uint32_t mask;
+
+ if (is_fam15h())
+ mask = 0x3e;
+ else
+ mask = 0x3f;
+
+ /* Lanes 0 - 3 */
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x5 | (dimm << 8));
+ dword &= ~(mask << 24);
+ dword &= ~(mask << 16);
+ dword &= ~(mask << 8);
+ dword &= ~mask;
+ dword |= (delay[3] & mask) << 24;
+ dword |= (delay[2] & mask) << 16;
+ dword |= (delay[1] & mask) << 8;
+ dword |= delay[0] & mask;
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x5 | (dimm << 8), dword);
+
+ /* Lanes 4 - 7 */
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x6 | (dimm << 8));
+ dword &= ~(mask << 24);
+ dword &= ~(mask << 16);
+ dword &= ~(mask << 8);
+ dword &= ~mask;
+ dword |= (delay[7] & mask) << 24;
+ dword |= (delay[6] & mask) << 16;
+ dword |= (delay[5] & mask) << 8;
+ dword |= delay[4] & mask;
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x6 | (dimm << 8), dword);
+
+ /* Lane 8 (ECC) */
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x7 | (dimm << 8));
+ dword &= ~mask;
+ dword |= delay[8] & mask;
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x7 | (dimm << 8), dword);
}
/* DQS Position Training
* Algorithm detailed in the Fam10h BKDG Rev. 3.62 section 2.8.9.9.3
*/
-static void TrainDQSRdWrPos_D(struct MCTStatStruc *pMCTstat,
+static void TrainDQSRdWrPos_D_Fam10(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat)
{
u32 Errors;
@@ -402,7 +493,7 @@ static void TrainDQSRdWrPos_D(struct MCTStatStruc *pMCTstat,
if (pDCTstat->DIMMValidDCT[Channel] == 0) /* mct_BeforeTrainDQSRdWrPos_D */
continue;
- index_reg = 0x98 + 0x100 * Channel;
+ index_reg = 0x98;
dual_rank = 0;
Receiver = mct_InitReceiver_D(pDCTstat, Channel);
@@ -458,7 +549,7 @@ static void TrainDQSRdWrPos_D(struct MCTStatStruc *pMCTstat,
break;
/* Commit the current Write Data Timing settings to the hardware registers */
- write_dqs_write_data_timing_registers(current_write_dqs_delay, dev, (Receiver >> 1), index_reg);
+ write_dqs_write_data_timing_registers(current_write_dqs_delay, dev, Channel, (Receiver >> 1), index_reg);
/* Write the DRAM training pattern to the base test address */
WriteDQSTestPattern_D(pMCTstat, pDCTstat, TestAddr << 8);
@@ -475,7 +566,7 @@ static void TrainDQSRdWrPos_D(struct MCTStatStruc *pMCTstat,
current_read_dqs_delay[lane] = test_read_dqs_delay;
/* Commit the current Read DQS Timing Control settings to the hardware registers */
- write_dqs_read_data_timing_registers(current_read_dqs_delay, dev, (Receiver >> 1), index_reg);
+ write_dqs_read_data_timing_registers(current_read_dqs_delay, dev, Channel, (Receiver >> 1), index_reg);
/* Initialize test result variable */
bytelane_test_results = 0xff;
@@ -541,7 +632,7 @@ static void TrainDQSRdWrPos_D(struct MCTStatStruc *pMCTstat,
passing_dqs_delay_found[lane] = 1;
/* Commit the current Read DQS Timing Control settings to the hardware registers */
- write_dqs_read_data_timing_registers(current_read_dqs_delay, dev, (Receiver >> 1), index_reg);
+ write_dqs_read_data_timing_registers(current_read_dqs_delay, dev, Channel, (Receiver >> 1), index_reg);
/* Exit the DRAM Write Data Timing Loop */
write_dqs_delay_stepping_done[lane] = 1;
@@ -575,7 +666,7 @@ static void TrainDQSRdWrPos_D(struct MCTStatStruc *pMCTstat,
current_write_dqs_delay[lane] = test_write_dqs_delay;
/* Commit the current Write Data Timing settings to the hardware registers */
- write_dqs_write_data_timing_registers(current_write_dqs_delay, dev, (Receiver >> 1), index_reg);
+ write_dqs_write_data_timing_registers(current_write_dqs_delay, dev, Channel, (Receiver >> 1), index_reg);
/* Write the DRAM training pattern to the base test address */
WriteDQSTestPattern_D(pMCTstat, pDCTstat, TestAddr << 8);
@@ -670,7 +761,7 @@ static void TrainDQSRdWrPos_D(struct MCTStatStruc *pMCTstat,
current_read_dqs_delay[lane] = (best_pos + (best_count / 2));
/* Commit the current Read DQS Timing Control settings to the hardware registers */
- write_dqs_read_data_timing_registers(current_read_dqs_delay, dev, (Receiver >> 1), index_reg);
+ write_dqs_read_data_timing_registers(current_read_dqs_delay, dev, Channel, (Receiver >> 1), index_reg);
/* Save the final Read DQS Timing Control settings for later use */
pDCTstat->CH_D_DIR_B_DQS[Channel][Receiver >> 1][DQS_READDIR][lane] = current_read_dqs_delay[lane];
@@ -713,7 +804,7 @@ static void TrainDQSRdWrPos_D(struct MCTStatStruc *pMCTstat,
current_write_dqs_delay[lane] = (best_pos + (best_count / 2));
/* Commit the current Write Data Timing settings to the hardware registers */
- write_dqs_write_data_timing_registers(current_write_dqs_delay, dev, (Receiver >> 1), index_reg);
+ write_dqs_write_data_timing_registers(current_write_dqs_delay, dev, Channel, (Receiver >> 1), index_reg);
/* Save the final Write Data Timing settings for later use */
pDCTstat->CH_D_DIR_B_DQS[Channel][Receiver >> 1][DQS_WRITEDIR][lane] = current_write_dqs_delay[lane];
@@ -783,6 +874,831 @@ static void TrainDQSRdWrPos_D(struct MCTStatStruc *pMCTstat,
printk(BIOS_DEBUG, "TrainDQSRdWrPos: Done\n\n");
}
+/* Calcuate and set MaxRdLatency
+ * Algorithm detailed in the Fam15h BKDG Rev. 3.14 section 2.10.5.8.5
+ */
+static void Calc_SetMaxRdLatency_D_Fam15(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, uint8_t dct)
+{
+ uint8_t dimm;
+ uint8_t lane;
+ uint32_t dword;
+ uint32_t dword2;
+ uint32_t max_delay;
+ uint8_t mem_clk = 0;
+ uint8_t nb_pstate;
+ uint32_t nb_clk;
+ uint32_t p = 0;
+ uint32_t n = 0;
+ uint32_t t = 0;
+ uint16_t current_phy_phase_delay[MAX_BYTE_LANES];
+ uint16_t current_read_dqs_delay[MAX_BYTE_LANES];
+
+ uint32_t index_reg = 0x98;
+ uint32_t dev = pDCTstat->dev_dct;
+ uint16_t fam15h_freq_tab[] = {0, 0, 0, 0, 333, 0, 400, 0, 0, 0, 533, 0, 0, 0, 667, 0, 0, 0, 800, 0, 0, 0, 933};
+
+ /* P is specified in PhyCLKs (1/2 MEMCLKs) */
+ for (nb_pstate = 0; nb_pstate < 2; nb_pstate++) {
+ /* 2.10.5.8.5 (2) */
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x00000004);
+ if ((!(dword & (0x1 << 21))) && (!(dword & (0x1 << 13))) && (!(dword & (0x1 << 5))))
+ p += 1;
+ else
+ p += 2;
+
+ /* 2.10.5.8.5 (3) */
+ dword = Get_NB32_DCT_NBPstate(dev, dct, nb_pstate, 0x210) & 0xf; /* Retrieve RdPtrInit */
+ p += (9 - dword);
+
+ /* 2.10.5.8.5 (4) */
+ p += 5;
+
+ /* 2.10.5.8.5 (5) */
+ dword = Get_NB32_DCT(dev, dct, 0xa8);
+ dword2 = Get_NB32_DCT(dev, dct, 0x90);
+ if ((!(dword & (0x1 << 5))) && (!(dword2 & (0x1 << 16))))
+ p += 2;
+
+ /* 2.10.5.8.5 (6) */
+ dword = Get_NB32_DCT(dev, dct, 0x200) & 0x1f; /* Retrieve Tcl */
+ p += (2 * (dword - 1));
+
+ /* 2.10.5.8.5 (7) */
+ max_delay = 0;
+ for (dimm = 0; dimm < 4; dimm++) {
+ if (!mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, dct, dimm * 2))
+ continue;
+
+ read_dqs_receiver_enable_control_registers(current_phy_phase_delay, dev, dct, dimm, index_reg);
+ read_read_dqs_timing_control_registers(current_read_dqs_delay, dev, dct, dimm, index_reg);
+ for (lane = 0; lane < MAX_BYTE_LANES; lane++)
+ if ((current_phy_phase_delay[lane] + current_read_dqs_delay[lane]) > max_delay)
+ max_delay = (current_phy_phase_delay[lane] + current_read_dqs_delay[lane]);
+ }
+ p += (max_delay >> 5);
+
+ /* 2.10.5.8.5 (8) */
+ p += 5;
+
+ /* 2.10.5.8.5 (9) */
+ t += 800;
+
+ /* 2.10.5.8.5 (10) */
+ mem_clk = Get_NB32_DCT(dev, dct, 0x94) & 0x1f;
+ dword = Get_NB32(pDCTstat->dev_nbctl, (0x160 + (nb_pstate * 4))); /* Retrieve NbDid, NbFid */
+ nb_clk = (200 * (((dword >> 1) & 0x1f) + 0x4)) / (((dword >> 7) & 0x1)?2:1);
+ n = (((((uint64_t)p * 1000000000000ULL)/(((uint64_t)fam15h_freq_tab[mem_clk] * 1000000ULL) * 2)) + ((uint64_t)t)) * ((uint64_t)nb_clk * 1000)) / 1000000000ULL;
+
+ /* 2.10.5.8.5 (11) */
+ n -= 1;
+
+ /* 2.10.5.8.5 (12) */
+ dword = Get_NB32_DCT_NBPstate(dev, dct, nb_pstate, 0x210);
+ dword &= ~(0x3ff << 22);
+ dword |= (((n - 1) & 0x3ff) << 22);
+ Set_NB32_DCT_NBPstate(dev, dct, nb_pstate, 0x210, dword);
+
+ /* Save result for later use */
+ pDCTstat->CH_MaxRdLat[dct] = n;
+ }
+}
+
+static void start_dram_dqs_training_pattern_fam15(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, uint8_t dct, uint8_t Receiver)
+{
+ uint32_t dword;
+ uint32_t dev = pDCTstat->dev_dct;
+
+ /* 2.10.5.7.1.1
+ * It appears that the DCT only supports 8-beat burst length mode,
+ * so do nothing here...
+ */
+
+ /* Wait for CmdSendInProg == 0 */
+ do {
+ dword = Get_NB32_DCT(dev, dct, 0x250);
+ } while (dword & (0x1 << 12));
+
+ /* Set CmdTestEnable = 1 */
+ dword = Get_NB32_DCT(dev, dct, 0x250);
+ dword |= (0x1 << 2);
+ Set_NB32_DCT(dev, dct, 0x250, dword);
+
+ /* 2.10.5.8.6.1.1 Send Activate Command (Target A) */
+ dword = Get_NB32_DCT(dev, dct, 0x28c);
+ dword &= ~(0xff << 22); /* CmdChipSelect = Receiver */
+ dword |= ((0x1 << Receiver) << 22);
+ dword &= ~(0x7 << 19); /* CmdBank = 0 */
+ dword &= ~(0x3ffff); /* CmdAddress = 0 */
+ dword |= (0x1 << 31); /* SendActCmd = 1 */
+ Set_NB32_DCT(dev, dct, 0x28c, dword);
+
+ /* Wait for SendActCmd == 0 */
+ do {
+ dword = Get_NB32_DCT(dev, dct, 0x28c);
+ } while (dword & (0x1 << 31));
+
+ /* Wait 75 MEMCLKs. */
+ precise_memclk_delay_fam15(pMCTstat, pDCTstat, dct, 75);
+
+ /* 2.10.5.8.6.1.1 Send Activate Command (Target B) */
+ dword = Get_NB32_DCT(dev, dct, 0x28c);
+ dword &= ~(0xff << 22); /* CmdChipSelect = Receiver */
+ dword |= ((0x1 << Receiver) << 22);
+ dword &= ~(0x7 << 19); /* CmdBank = 1 */
+ dword |= (0x1 << 19);
+ dword &= ~(0x3ffff); /* CmdAddress = 0 */
+ dword |= (0x1 << 31); /* SendActCmd = 1 */
+ Set_NB32_DCT(dev, dct, 0x28c, dword);
+
+ /* Wait for SendActCmd == 0 */
+ do {
+ dword = Get_NB32_DCT(dev, dct, 0x28c);
+ } while (dword & (0x1 << 31));
+
+ /* Wait 75 MEMCLKs. */
+ precise_memclk_delay_fam15(pMCTstat, pDCTstat, dct, 75);
+}
+
+static void stop_dram_dqs_training_pattern_fam15(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, uint8_t dct, uint8_t Receiver)
+{
+ uint32_t dword;
+ uint32_t dev = pDCTstat->dev_dct;
+
+ /* 2.10.5.8.6.1.1 Send Precharge Command */
+ /* Wait 25 MEMCLKs. */
+ precise_memclk_delay_fam15(pMCTstat, pDCTstat, dct, 25);
+
+ dword = Get_NB32_DCT(dev, dct, 0x28c);
+ dword &= ~(0xff << 22); /* CmdChipSelect = Receiver */
+ dword |= ((0x1 << Receiver) << 22);
+ dword &= ~(0x7 << 19); /* CmdBank = 0 */
+ dword &= ~(0x3ffff); /* CmdAddress = 0x400 */
+ dword |= 0x400;
+ dword |= (0x1 << 30); /* SendPchgCmd = 1 */
+ Set_NB32_DCT(dev, dct, 0x28c, dword);
+
+ /* Wait for SendPchgCmd == 0 */
+ do {
+ dword = Get_NB32_DCT(dev, dct, 0x28c);
+ } while (dword & (0x1 << 30));
+
+ /* Wait 25 MEMCLKs. */
+ precise_memclk_delay_fam15(pMCTstat, pDCTstat, dct, 25);
+
+ /* Set CmdTestEnable = 0 */
+ dword = Get_NB32_DCT(dev, dct, 0x250);
+ dword &= ~(0x1 << 2);
+ Set_NB32_DCT(dev, dct, 0x250, dword);
+}
+
+static void read_dram_dqs_training_pattern_fam15(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, uint8_t dct, uint8_t Receiver, uint8_t lane)
+{
+ uint32_t dword;
+ uint32_t dev = pDCTstat->dev_dct;
+
+ start_dram_dqs_training_pattern_fam15(pMCTstat, pDCTstat, dct, Receiver);
+
+ /* 2.10.5.8.6.1.2 */
+ /* Configure DQMask */
+ if (lane < 4) {
+ Set_NB32_DCT(dev, dct, 0x274, ~(0xff << (lane * 8)));
+ Set_NB32_DCT(dev, dct, 0x278, ~0x0);
+ } else if (lane < 8) {
+ Set_NB32_DCT(dev, dct, 0x274, ~0x0);
+ Set_NB32_DCT(dev, dct, 0x278, ~(0xff << (lane * 8)));
+ } else {
+ Set_NB32_DCT(dev, dct, 0x274, ~0x0);
+ Set_NB32_DCT(dev, dct, 0x278, ~0x0);
+ }
+
+ dword = Get_NB32_DCT(dev, dct, 0x27c);
+ dword &= ~(0xff); /* EccMask = 0 */
+ if ((lane != 8) || (pDCTstat->DimmECCPresent == 0))
+ dword |= 0xff; /* EccMask = 0xff */
+ Set_NB32_DCT(dev, dct, 0x27c, dword);
+
+ dword = Get_NB32_DCT(dev, dct, 0x270);
+ dword &= ~(0x7ffff); /* DataPrbsSeed = 55555 */
+// dword |= (0x55555);
+ dword |= (0x44443); /* Use AGESA seed */
+ Set_NB32_DCT(dev, dct, 0x270, dword);
+
+ /* 2.10.5.8.4 */
+ dword = Get_NB32_DCT(dev, dct, 0x260);
+ dword &= ~(0x1fffff); /* CmdCount = 256 */
+ dword |= 256;
+ Set_NB32_DCT(dev, dct, 0x260, dword);
+
+ /* Configure Target A */
+ dword = Get_NB32_DCT(dev, dct, 0x254);
+ dword &= ~(0x7 << 24); /* TgtChipSelect = Receiver */
+ dword |= (Receiver & 0x7) << 24;
+ dword &= ~(0x7 << 21); /* TgtBank = 0 */
+ dword &= ~(0x3ff); /* TgtAddress = 0 */
+ Set_NB32_DCT(dev, dct, 0x254, dword);
+
+ /* Configure Target B */
+ dword = Get_NB32_DCT(dev, dct, 0x258);
+ dword &= ~(0x7 << 24); /* TgtChipSelect = Receiver */
+ dword |= (Receiver & 0x7) << 24;
+ dword &= ~(0x7 << 21); /* TgtBank = 1 */
+ dword |= (0x1 << 21);
+ dword &= ~(0x3ff); /* TgtAddress = 0 */
+ Set_NB32_DCT(dev, dct, 0x258, dword);
+
+ dword = Get_NB32_DCT(dev, dct, 0x250);
+ dword |= (0x1 << 3); /* ResetAllErr = 1 */
+ dword &= ~(0x1 << 4); /* StopOnErr = 0 */
+ dword &= ~(0x3 << 8); /* CmdTgt = 1 (Alternate between Target A and Target B) */
+ dword |= (0x1 << 8);
+ dword &= ~(0x7 << 5); /* CmdType = 0 (Read) */
+ dword |= (0x1 << 11); /* SendCmd = 1 */
+ Set_NB32_DCT(dev, dct, 0x250, dword);
+
+ /* 2.10.5.8.6.1.2 Wait for TestStatus == 1 and CmdSendInProg == 0 */
+ do {
+ dword = Get_NB32_DCT(dev, dct, 0x250);
+ } while ((dword & (0x1 << 12)) || (!(dword & (0x1 << 10))));
+
+ dword = Get_NB32_DCT(dev, dct, 0x250);
+ dword &= ~(0x1 << 11); /* SendCmd = 0 */
+ Set_NB32_DCT(dev, dct, 0x250, dword);
+
+ stop_dram_dqs_training_pattern_fam15(pMCTstat, pDCTstat, dct, Receiver);
+}
+
+static void write_dram_dqs_training_pattern_fam15(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, uint8_t dct, uint8_t Receiver, uint8_t lane)
+{
+ uint32_t dword;
+ uint32_t dev = pDCTstat->dev_dct;
+
+ start_dram_dqs_training_pattern_fam15(pMCTstat, pDCTstat, dct, Receiver);
+
+ /* 2.10.5.8.6.1.2 */
+ /* Configure DQMask */
+ if (lane < 4) {
+ Set_NB32_DCT(dev, dct, 0x274, ~(0xff << (lane * 8)));
+ Set_NB32_DCT(dev, dct, 0x278, ~0x0);
+ } else if (lane < 8) {
+ Set_NB32_DCT(dev, dct, 0x274, ~0x0);
+ Set_NB32_DCT(dev, dct, 0x278, ~(0xff << (lane * 8)));
+ } else {
+ Set_NB32_DCT(dev, dct, 0x274, ~0x0);
+ Set_NB32_DCT(dev, dct, 0x278, ~0x0);
+ }
+
+ dword = Get_NB32_DCT(dev, dct, 0x27c);
+ dword &= ~(0xff); /* EccMask = 0 */
+ if ((lane != 8) || (pDCTstat->DimmECCPresent == 0))
+ dword |= 0xff; /* EccMask = 0xff */
+ Set_NB32_DCT(dev, dct, 0x27c, dword);
+
+ dword = Get_NB32_DCT(dev, dct, 0x270);
+ dword &= ~(0x7ffff); /* DataPrbsSeed = 55555 */
+// dword |= (0x55555);
+ dword |= (0x44443); /* Use AGESA seed */
+ Set_NB32_DCT(dev, dct, 0x270, dword);
+
+ /* 2.10.5.8.4 */
+ dword = Get_NB32_DCT(dev, dct, 0x260);
+ dword &= ~(0x1fffff); /* CmdCount = 256 */
+ dword |= 256;
+ Set_NB32_DCT(dev, dct, 0x260, dword);
+
+ /* Configure Target A */
+ dword = Get_NB32_DCT(dev, dct, 0x254);
+ dword &= ~(0x7 << 24); /* TgtChipSelect = Receiver */
+ dword |= (Receiver & 0x7) << 24;
+ dword &= ~(0x7 << 21); /* TgtBank = 0 */
+ dword &= ~(0x3ff); /* TgtAddress = 0 */
+ Set_NB32_DCT(dev, dct, 0x254, dword);
+
+ /* Configure Target B */
+ dword = Get_NB32_DCT(dev, dct, 0x258);
+ dword &= ~(0x7 << 24); /* TgtChipSelect = Receiver */
+ dword |= (Receiver & 0x7) << 24;
+ dword &= ~(0x7 << 21); /* TgtBank = 1 */
+ dword |= (0x1 << 21);
+ dword &= ~(0x3ff); /* TgtAddress = 0 */
+ Set_NB32_DCT(dev, dct, 0x258, dword);
+
+ dword = Get_NB32_DCT(dev, dct, 0x250);
+ dword |= (0x1 << 3); /* ResetAllErr = 1 */
+ dword &= ~(0x1 << 4); /* StopOnErr = 0 */
+ dword &= ~(0x3 << 8); /* CmdTgt = 1 (Alternate between Target A and Target B) */
+ dword |= (0x1 << 8);
+ dword &= ~(0x7 << 5); /* CmdType = 1 (Write) */
+ dword |= (0x1 << 5);
+ dword |= (0x1 << 11); /* SendCmd = 1 */
+ Set_NB32_DCT(dev, dct, 0x250, dword);
+
+ /* 2.10.5.8.6.1.2 Wait for TestStatus == 1 and CmdSendInProg == 0 */
+ do {
+ dword = Get_NB32_DCT(dev, dct, 0x250);
+ } while ((dword & (0x1 << 12)) || (!(dword & (0x1 << 10))));
+
+ dword = Get_NB32_DCT(dev, dct, 0x250);
+ dword &= ~(0x1 << 11); /* SendCmd = 0 */
+ Set_NB32_DCT(dev, dct, 0x250, dword);
+
+ stop_dram_dqs_training_pattern_fam15(pMCTstat, pDCTstat, dct, Receiver);
+}
+
+/* DQS Position Training
+ * Algorithm detailed in the Fam15h BKDG Rev. 3.14 section 2.10.5.8.4
+ */
+static uint8_t TrainDQSRdWrPos_D_Fam15(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, uint8_t dct, uint8_t receiver_start, uint8_t receiver_end, uint8_t lane_start, uint8_t lane_end)
+{
+ uint8_t dimm;
+ uint8_t lane;
+ uint32_t dword;
+ uint32_t Errors;
+ uint8_t Receiver;
+ uint8_t dual_rank;
+ uint8_t write_iter;
+ uint8_t read_iter;
+ uint16_t initial_write_dqs_delay[MAX_BYTE_LANES];
+ uint16_t initial_read_dqs_delay[MAX_BYTE_LANES];
+ uint16_t initial_write_data_timing[MAX_BYTE_LANES];
+ uint16_t current_write_data_delay[MAX_BYTE_LANES];
+ uint16_t current_read_dqs_delay[MAX_BYTE_LANES];
+ uint16_t current_write_dqs_delay[MAX_BYTE_LANES];
+ uint8_t passing_dqs_delay_found[MAX_BYTE_LANES];
+ uint8_t dqs_results_array[2][(lane_end - lane_start)][32][32]; /* [rank][lane][write step][read step] */
+
+ uint8_t last_pos = 0;
+ uint8_t cur_count = 0;
+ uint8_t best_pos = 0;
+ uint8_t best_count = 0;
+
+ uint32_t index_reg = 0x98;
+ uint32_t dev = pDCTstat->dev_dct;
+
+ /* Calculate and program MaxRdLatency */
+ Calc_SetMaxRdLatency_D_Fam15(pMCTstat, pDCTstat, dct);
+
+ Errors = 0;
+ dual_rank = 0;
+ Receiver = mct_InitReceiver_D(pDCTstat, dct);
+ if (receiver_start > Receiver)
+ Receiver = receiver_start;
+
+ /* There are four receiver pairs, loosely associated with chipselects.
+ * This is essentially looping over each DIMM.
+ */
+ for (; Receiver < receiver_end; Receiver += 2) {
+ dimm = (Receiver >> 1);
+ if ((Receiver & 0x1) == 0) {
+ /* Even rank of DIMM */
+ if(mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, dct, Receiver+1))
+ dual_rank = 1;
+ else
+ dual_rank = 0;
+ }
+
+ if (!mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, dct, Receiver)) {
+ continue;
+ }
+
+ /* Initialize variables */
+ for (lane = lane_start; lane < lane_end; lane++) {
+ passing_dqs_delay_found[lane] = 0;
+ }
+ memset(dqs_results_array, 0, sizeof(dqs_results_array));
+
+ /* Read initial read / write DQS delays */
+ read_dqs_write_timing_control_registers(initial_write_dqs_delay, dev, dct, dimm, index_reg);
+ read_dqs_read_data_timing_registers(initial_read_dqs_delay, dev, dct, dimm, index_reg);
+
+ /* Read current settings of other (previously trained) lanes */
+ read_dqs_write_data_timing_registers(initial_write_data_timing, dev, dct, dimm, index_reg);
+ memcpy(current_write_data_delay, initial_write_data_timing, sizeof(current_write_data_delay));
+
+ for (lane = lane_start; lane < lane_end; lane++) {
+ /* 2.10.5.8.4 (2)
+ * For each Write Data Delay value from Write DQS Delay to Write DQS Delay + 1 UI
+ */
+ for (current_write_data_delay[lane] = initial_write_dqs_delay[lane]; current_write_data_delay[lane] < (initial_write_dqs_delay[lane] + 0x20); current_write_data_delay[lane]++) {
+ print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 16 current_write_data_delay[lane] ", current_write_data_delay[lane], 6);
+
+ /* 2.10.5.8.4 (2 A)
+ * Commit the current Write Data Timing settings to the hardware registers
+ */
+ write_dqs_write_data_timing_registers(current_write_data_delay, dev, dct, dimm, index_reg);
+
+ /* 2.10.5.8.4 (2 B)
+ * Write the DRAM training pattern to the test address
+ */
+ write_dram_dqs_training_pattern_fam15(pMCTstat, pDCTstat, dct, Receiver, lane);
+
+ /* Read current settings of other (previously trained) lanes */
+ read_dqs_read_data_timing_registers(current_read_dqs_delay, dev, dct, dimm, index_reg);
+
+ /* 2.10.5.8.4 (2 C)
+ * For each Read DQS Delay value from 0 to 1 UI
+ */
+ for (current_read_dqs_delay[lane] = 0; current_read_dqs_delay[lane] < 0x40; current_read_dqs_delay[lane] += 2) {
+ print_debug_dqs("\t\t\t\t\tTrainDQSRdWrPos: 161 current_read_dqs_delay[lane] ", current_read_dqs_delay[lane], 6);
+
+ /* 2.10.5.8.4 (2 A i)
+ * Commit the current Read DQS Timing Control settings to the hardware registers
+ */
+ write_dqs_read_data_timing_registers(current_read_dqs_delay, dev, dct, dimm, index_reg);
+
+ /* 2.10.5.8.4 (2 A ii)
+ * Read the DRAM training pattern from the test address
+ */
+ read_dram_dqs_training_pattern_fam15(pMCTstat, pDCTstat, dct, Receiver, lane);
+
+ /* 2.10.5.8.4 (2 A iii)
+ * Record pass / fail status
+ */
+ dword = Get_NB32_DCT(dev, dct, 0x268) & 0x3ffff;
+ if (dword & (0x3 << (lane * 2)))
+ dqs_results_array[Receiver & 0x1][lane - lane_start][current_write_data_delay[lane] - initial_write_dqs_delay[lane]][current_read_dqs_delay[lane] >> 1] = 0; /* Fail */
+ else
+ dqs_results_array[Receiver & 0x1][lane - lane_start][current_write_data_delay[lane] - initial_write_dqs_delay[lane]][current_read_dqs_delay[lane] >> 1] = 1; /* Pass */
+ }
+ }
+
+ if (dual_rank && (Receiver & 0x1)) {
+ /* Overlay the previous rank test results with the current rank */
+ for (write_iter = 0; write_iter < 32; write_iter++) {
+ for (read_iter = 0; read_iter < 32; read_iter++) {
+ if ((dqs_results_array[0][lane - lane_start][write_iter][read_iter])
+ && (dqs_results_array[1][lane - lane_start][write_iter][read_iter]))
+ dqs_results_array[1][lane - lane_start][write_iter][read_iter] = 1;
+ else
+ dqs_results_array[1][lane - lane_start][write_iter][read_iter] = 0;
+ }
+ }
+ }
+
+ /* Determine location and length of longest consecutive string of read passing values
+ * Output is stored in best_pos and best_count
+ */
+ last_pos = 0;
+ cur_count = 0;
+ best_pos = 0;
+ best_count = 0;
+ for (write_iter = 0; write_iter < 32; write_iter++) {
+ for (read_iter = 0; read_iter < 32; read_iter++) {
+ if ((dqs_results_array[Receiver & 0x1][lane - lane_start][write_iter][read_iter]) && (read_iter < 31)) {
+ /* Pass */
+ cur_count++;
+ } else {
+ /* Failure or end of loop */
+ if (cur_count > best_count) {
+ best_count = cur_count;
+ best_pos = last_pos;
+ }
+ cur_count = 0;
+ last_pos = read_iter;
+ }
+ }
+ last_pos = 0;
+ }
+
+ if (best_count > 2) {
+ /* Restore current settings of other (previously trained) lanes to the active array */
+ memcpy(current_read_dqs_delay, initial_read_dqs_delay, sizeof(current_read_dqs_delay));
+
+ /* Program the Read DQS Timing Control register with the center of the passing window */
+ current_read_dqs_delay[lane] = ((best_pos << 1) + ((best_count << 1) / 2));
+ passing_dqs_delay_found[lane] = 1;
+
+ /* Commit the current Read DQS Timing Control settings to the hardware registers */
+ write_dqs_read_data_timing_registers(current_read_dqs_delay, dev, dct, dimm, index_reg);
+
+ /* Save the final Read DQS Timing Control settings for later use */
+ pDCTstat->CH_D_DIR_B_DQS[dct][Receiver >> 1][DQS_READDIR][lane] = current_read_dqs_delay[lane];
+
+ print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 142 largest read passing region ", best_count, 4);
+ print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 143 largest read passing region start ", best_pos, 4);
+ } else {
+ /* Reprogram the Read DQS Timing Control register with the original settings */
+ write_dqs_read_data_timing_registers(initial_read_dqs_delay, dev, dct, dimm, index_reg);
+ }
+
+ /* Determine location and length of longest consecutive string of write passing values
+ * Output is stored in best_pos and best_count
+ */
+ last_pos = 0;
+ cur_count = 0;
+ best_pos = 0;
+ best_count = 0;
+ for (read_iter = 0; read_iter < 32; read_iter++) {
+ for (write_iter = 0; write_iter < 32; write_iter++) {
+ if ((dqs_results_array[Receiver & 0x1][lane - lane_start][write_iter][read_iter]) && (write_iter < 31)) {
+ /* Pass */
+ cur_count++;
+ } else {
+ /* Failure or end of loop */
+ if (cur_count > best_count) {
+ best_count = cur_count;
+ best_pos = last_pos;
+ }
+ cur_count = 0;
+ last_pos = write_iter;
+ }
+ }
+ last_pos = 0;
+ }
+
+ if (best_count > 2) {
+ /* Restore current settings of other (previously trained) lanes to the active array */
+ memcpy(current_write_dqs_delay, initial_write_data_timing, sizeof(current_write_data_delay));
+
+ /* Program the Write DQS Timing Control register with the optimal region within the passing window */
+ if (pDCTstat->Status & (1 << SB_LoadReduced))
+ current_write_dqs_delay[lane] = ((best_pos + initial_write_dqs_delay[lane]) + (best_count / 3));
+ else
+ current_write_dqs_delay[lane] = ((best_pos + initial_write_dqs_delay[lane]) + (best_count / 2));
+ passing_dqs_delay_found[lane] = 1;
+
+ /* Commit the current Write DQS Timing Control settings to the hardware registers */
+ write_dqs_write_data_timing_registers(current_write_dqs_delay, dev, dct, dimm, index_reg);
+
+ /* Save the final Write Data Timing settings for later use */
+ pDCTstat->CH_D_DIR_B_DQS[dct][Receiver >> 1][DQS_WRITEDIR][lane] = current_write_dqs_delay[lane];
+
+ print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 144 largest write passing region ", best_count, 4);
+ print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 145 largest write passing region start ", best_pos, 4);
+ } else {
+ /* Reprogram the Write DQS Timing Control register with the original settings */
+ write_dqs_write_data_timing_registers(current_write_dqs_delay, dev, dct, dimm, index_reg);
+ }
+ }
+
+#ifdef PRINT_PASS_FAIL_BITMAPS
+ for (lane = lane_start; lane < lane_end; lane++) {
+ for (read_iter = 0; read_iter < 32; read_iter++) {
+ for (write_iter = 0; write_iter < 32; write_iter++) {
+ if (dqs_results_array[Receiver & 0x1][lane - lane_start][write_iter][read_iter])
+ printk(BIOS_DEBUG, "+");
+ else
+ printk(BIOS_DEBUG, ".");
+ }
+ printk(BIOS_DEBUG, "\n");
+ }
+ printk(BIOS_DEBUG, "\n\n");
+ }
+#endif
+
+ /* Flag failure(s) if present */
+ for (lane = lane_start; lane < lane_end; lane++) {
+ if (!passing_dqs_delay_found[lane]) {
+ print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 121 Unable to find passing region for lane ", lane, 2);
+
+ /* Flag absence of passing window */
+ Errors |= 1 << SB_NODQSPOS;
+ }
+ }
+
+ pDCTstat->TrainErrors |= Errors;
+ pDCTstat->ErrStatus |= Errors;
+
+#if DQS_TRAIN_DEBUG > 0
+ {
+ u8 val;
+ u8 i;
+ u8 ChannelDTD, ReceiverDTD, Dir;
+ u8 *p;
+
+ for (Dir = 0; Dir < 2; Dir++) {
+ if (Dir == 1) {
+ printk(BIOS_DEBUG, "TrainDQSRdWrPos: CH_D_DIR_B_DQS WR:\n");
+ } else {
+ printk(BIOS_DEBUG, "TrainDQSRdWrPos: CH_D_DIR_B_DQS RD:\n");
+ }
+ for (ChannelDTD = 0; ChannelDTD < 2; ChannelDTD++) {
+ printk(BIOS_DEBUG, "Channel: %02x\n", ChannelDTD);
+ for (ReceiverDTD = 0; ReceiverDTD < MAX_CS_SUPPORTED; ReceiverDTD += 2) {
+ printk(BIOS_DEBUG, "\t\tReceiver: %02x:", ReceiverDTD);
+ p = pDCTstat->CH_D_DIR_B_DQS[ChannelDTD][ReceiverDTD >> 1][Dir];
+ for (i=0;i<8; i++) {
+ val = p[i];
+ printk(BIOS_DEBUG, " %02x", val);
+ }
+ printk(BIOS_DEBUG, "\n");
+ }
+ }
+ }
+
+ }
+#endif
+ }
+
+ /* Return 1 on success, 0 on failure */
+ return !Errors;
+}
+
+/* DQS Receiver Enable Cycle Training
+ * Algorithm detailed in the Fam15h BKDG Rev. 3.14 section 2.10.5.8.3
+ */
+static void TrainDQSReceiverEnCyc_D_Fam15(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat)
+{
+ u32 Errors;
+ u8 Receiver;
+ u8 _DisableDramECC = 0;
+ u8 _Wrap32Dis = 0, _SSE2 = 0;
+
+ u32 addr;
+ u32 cr4;
+ u32 lo, hi;
+
+ uint8_t dct;
+ uint8_t prev;
+ uint8_t dimm;
+ uint8_t lane;
+ uint32_t dword;
+ uint32_t rx_en_offset;
+ uint16_t initial_phy_phase_delay[MAX_BYTE_LANES];
+ uint16_t current_phy_phase_delay[MAX_BYTE_LANES];
+ uint8_t dqs_results_array[1024];
+
+ uint16_t ren_step = 0x40;
+ uint32_t index_reg = 0x98;
+ uint32_t dev = pDCTstat->dev_dct;
+
+ print_debug_dqs("\nTrainDQSReceiverEnCyc: Node_ID ", pDCTstat->Node_ID, 0);
+ cr4 = read_cr4();
+ if (cr4 & (1<<9)) {
+ _SSE2 = 1;
+ }
+ cr4 |= (1<<9); /* OSFXSR enable SSE2 */
+ write_cr4(cr4);
+
+ addr = HWCR;
+ _RDMSR(addr, &lo, &hi);
+ if (lo & (1<<17)) {
+ _Wrap32Dis = 1;
+ }
+ lo |= (1<<17); /* HWCR.wrap32dis */
+ _WRMSR(addr, lo, hi); /* allow 64-bit memory references in real mode */
+
+ /* Disable ECC correction of reads on the dram bus. */
+ _DisableDramECC = mct_DisableDimmEccEn_D(pMCTstat, pDCTstat);
+
+ Errors = 0;
+
+ for (dct = 0; dct < 2; dct++) {
+ /* Program D18F2x9C_x0D0F_E003_dct[1:0][DisAutoComp, DisablePredriverCal] */
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fe003);
+ dword &= ~(0x3 << 13);
+ dword |= (0x1 << 13);
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fe003, dword);
+ }
+
+ for (dct = 0; dct < 2; dct++) {
+ /* 2.10.5.6 */
+ fam15EnableTrainingMode(pMCTstat, pDCTstat, dct, 1);
+
+ /* 2.10.5.8.3 */
+ Receiver = mct_InitReceiver_D(pDCTstat, dct);
+
+ /* There are four receiver pairs, loosely associated with chipselects.
+ * This is essentially looping over each DIMM.
+ */
+ for (; Receiver < 8; Receiver += 2) {
+ dimm = (Receiver >> 1);
+
+ if (!mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, dct, Receiver)) {
+ continue;
+ }
+
+ /* 2.10.5.8.3 (2) */
+ read_dqs_receiver_enable_control_registers(initial_phy_phase_delay, dev, dct, dimm, index_reg);
+
+ for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
+ /* Initialize variables */
+ memset(dqs_results_array, 0, sizeof(dqs_results_array));
+
+ /* 2.10.5.8.3 (1) */
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f0030 | (lane << 8));
+ dword |= (0x1 << 8); /* BlockRxDqsLock = 1 */
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f0030 | (lane << 8), dword);
+
+ /* 2.10.5.8.3 (3) */
+ rx_en_offset = (initial_phy_phase_delay[lane] + 0x10) % 0x40;
+
+ /* 2.10.5.8.3 (4) */
+ for (current_phy_phase_delay[lane] = rx_en_offset; current_phy_phase_delay[lane] < 0x3ff; current_phy_phase_delay[lane] += ren_step) {
+ /* 2.10.5.8.3 (4 A) */
+ write_dqs_receiver_enable_control_registers(current_phy_phase_delay, dev, dct, dimm, index_reg);
+
+ /* Calculate and program MaxRdLatency */
+ Calc_SetMaxRdLatency_D_Fam15(pMCTstat, pDCTstat, dct);
+
+ /* 2.10.5.8.3 (4 B) */
+ dqs_results_array[current_phy_phase_delay[lane]] = TrainDQSRdWrPos_D_Fam15(pMCTstat, pDCTstat, dct, Receiver, Receiver + 2, lane, lane + 1);
+ }
+
+#ifdef PRINT_PASS_FAIL_BITMAPS
+ uint16_t iter;
+ for (iter = 0; iter < 0x3ff; iter++) {
+ if (dqs_results_array[iter])
+ printk(BIOS_DEBUG, "+");
+ else
+ printk(BIOS_DEBUG, ".");
+ }
+ printk(BIOS_DEBUG, "\n");
+#endif
+
+ /* 2.10.5.8.3 (5) */
+ prev = 0;
+ for (current_phy_phase_delay[lane] = rx_en_offset; current_phy_phase_delay[lane] < 0x3ff; current_phy_phase_delay[lane] += ren_step) {
+ if ((dqs_results_array[current_phy_phase_delay[lane]] == 0) && (prev == 1)) {
+ /* Restore last known good delay */
+ current_phy_phase_delay[lane] -= ren_step;
+
+ /* 2.10.5.8.3 (5 A B) */
+ current_phy_phase_delay[lane] -= 0x10;
+
+ /* Update hardware registers with final values */
+ write_dqs_receiver_enable_control_registers(current_phy_phase_delay, dev, dct, dimm, index_reg);
+ break;
+ }
+ prev = dqs_results_array[current_phy_phase_delay[lane]];
+ }
+
+ /* 2.10.5.8.3 (6) */
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f0030 | (lane << 8));
+ dword &= ~(0x1 << 8); /* BlockRxDqsLock = 0 */
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f0030 | (lane << 8), dword);
+ }
+
+#if DQS_TRAIN_DEBUG > 0
+ printk(BIOS_DEBUG, "TrainDQSReceiverEnCyc_D_Fam15 DQS receiver enable timing: ");
+ for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
+ printk(BIOS_DEBUG, " %03x", current_phy_phase_delay[lane]);
+ }
+ printk(BIOS_DEBUG, "\n");
+#endif
+ }
+ }
+
+ pDCTstat->TrainErrors |= Errors;
+ pDCTstat->ErrStatus |= Errors;
+
+#if DQS_TRAIN_DEBUG > 0
+ {
+ u8 val;
+ u8 i;
+ u8 ChannelDTD, ReceiverDTD, Dir;
+ u8 *p;
+
+ for (Dir = 0; Dir < 2; Dir++) {
+ if (Dir == 1) {
+ printk(BIOS_DEBUG, "TrainDQSRdWrPos: CH_D_DIR_B_DQS WR:\n");
+ } else {
+ printk(BIOS_DEBUG, "TrainDQSRdWrPos: CH_D_DIR_B_DQS RD:\n");
+ }
+ for (ChannelDTD = 0; ChannelDTD < 2; ChannelDTD++) {
+ printk(BIOS_DEBUG, "Channel: %02x\n", ChannelDTD);
+ for (ReceiverDTD = 0; ReceiverDTD < MAX_CS_SUPPORTED; ReceiverDTD += 2) {
+ printk(BIOS_DEBUG, "\t\tReceiver: %02x:", ReceiverDTD);
+ p = pDCTstat->CH_D_DIR_B_DQS[ChannelDTD][ReceiverDTD >> 1][Dir];
+ for (i=0;i<8; i++) {
+ val = p[i];
+ printk(BIOS_DEBUG, " %02x", val);
+ }
+ printk(BIOS_DEBUG, "\n");
+ }
+ }
+ }
+
+ }
+#endif
+ if (_DisableDramECC) {
+ mct_EnableDimmEccEn_D(pMCTstat, pDCTstat, _DisableDramECC);
+ }
+ if (!_Wrap32Dis) {
+ addr = HWCR;
+ _RDMSR(addr, &lo, &hi);
+ lo &= ~(1<<17); /* restore HWCR.wrap32dis */
+ _WRMSR(addr, lo, hi);
+ }
+ if (!_SSE2){
+ cr4 = read_cr4();
+ cr4 &= ~(1<<9); /* restore cr4.OSFXSR */
+ write_cr4(cr4);
+ }
+
+ printk(BIOS_DEBUG, "TrainDQSReceiverEnCyc: Status %x\n", pDCTstat->Status);
+ printk(BIOS_DEBUG, "TrainDQSReceiverEnCyc: TrainErrors %x\n", pDCTstat->TrainErrors);
+ printk(BIOS_DEBUG, "TrainDQSReceiverEnCyc: ErrStatus %x\n", pDCTstat->ErrStatus);
+ printk(BIOS_DEBUG, "TrainDQSReceiverEnCyc: ErrCode %x\n", pDCTstat->ErrCode);
+ printk(BIOS_DEBUG, "TrainDQSReceiverEnCyc: Done\n\n");
+}
+
static void SetupDqsPattern_D(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat, u32 *buffer)
{
@@ -865,18 +1781,17 @@ static u8 ChipSelPresent_D(struct MCTStatStruc *pMCTstat,
u32 val;
u32 reg;
u32 dev = pDCTstat->dev_dct;
- u32 reg_off;
+ uint8_t dct = 0;
u8 ret = 0;
- if (!pDCTstat->GangedMode) {
- reg_off = 0x100 * Channel;
- } else {
- reg_off = 0;
- }
+ if (!pDCTstat->GangedMode)
+ dct = Channel;
+ else
+ dct = 0;
if (ChipSel < MAX_CS_SUPPORTED){
- reg = 0x40 + (ChipSel << 2) + reg_off;
- val = Get_NB32(dev, reg);
+ reg = 0x40 + (ChipSel << 2);
+ val = Get_NB32_DCT(dev, dct, reg);
if (val & ( 1 << 0))
ret = 1;
}
@@ -1081,12 +1996,12 @@ u32 SetUpperFSbase(u32 addr_hi)
return addr_hi << 8;
}
-void ResetDCTWrPtr_D(u32 dev, u32 index_reg, u32 index)
+void ResetDCTWrPtr_D(u32 dev, uint8_t dct, u32 index_reg, u32 index)
{
u32 val;
- val = Get_NB32_index_wait(dev, index_reg, index);
- Set_NB32_index_wait(dev, index_reg, index, val);
+ val = Get_NB32_index_wait_DCT(dev, dct, index_reg, index);
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, index, val);
}
void mct_TrainDQSPos_D(struct MCTStatStruc *pMCTstat,
@@ -1099,9 +2014,13 @@ void mct_TrainDQSPos_D(struct MCTStatStruc *pMCTstat,
for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
pDCTstat = pDCTstatA + Node;
if (pDCTstat->DCTSysLimit) {
- TrainDQSRdWrPos_D(pMCTstat, pDCTstat);
- for (ChipSel = 0; ChipSel < MAX_CS_SUPPORTED; ChipSel += 2) {
- SetEccDQSRdWrPos_D(pMCTstat, pDCTstat, ChipSel);
+ if (is_fam15h()) {
+ TrainDQSReceiverEnCyc_D_Fam15(pMCTstat, pDCTstat);
+ } else {
+ TrainDQSRdWrPos_D_Fam10(pMCTstat, pDCTstat);
+ for (ChipSel = 0; ChipSel < MAX_CS_SUPPORTED; ChipSel += 2) {
+ SetEccDQSRdWrPos_D_Fam10(pMCTstat, pDCTstat, ChipSel);
+ }
}
}
}
@@ -1122,19 +2041,18 @@ u8 mct_DisableDimmEccEn_D(struct MCTStatStruc *pMCTstat,
dev = pDCTstat->dev_dct;
reg = 0x90;
- val = Get_NB32(dev, reg);
+ val = Get_NB32_DCT(dev, 0, reg);
if (val & (1<<DimmEcEn)) {
_DisableDramECC |= 0x01;
val &= ~(1<<DimmEcEn);
- Set_NB32(dev, reg, val);
+ Set_NB32_DCT(dev, 0, reg, val);
}
if (!pDCTstat->GangedMode) {
- reg = 0x190;
- val = Get_NB32(dev, reg);
+ val = Get_NB32_DCT(dev, 1, reg);
if (val & (1<<DimmEcEn)) {
_DisableDramECC |= 0x02;
val &= ~(1<<DimmEcEn);
- Set_NB32(dev, reg, val);
+ Set_NB32_DCT(dev, 1, reg, val);
}
}
return _DisableDramECC;
@@ -1153,15 +2071,14 @@ void mct_EnableDimmEccEn_D(struct MCTStatStruc *pMCTstat,
if ((_DisableDramECC & 0x01) == 0x01) {
reg = 0x90;
- val = Get_NB32(dev, reg);
+ val = Get_NB32_DCT(dev, 0, reg);
val |= (1<<DimmEcEn);
- Set_NB32(dev, reg, val);
+ Set_NB32_DCT(dev, 0, reg, val);
}
if ((_DisableDramECC & 0x02) == 0x02) {
- reg = 0x190;
- val = Get_NB32(dev, reg);
+ val = Get_NB32_DCT(dev, 1, reg);
val |= (1<<DimmEcEn);
- Set_NB32(dev, reg, val);
+ Set_NB32_DCT(dev, 1, reg, val);
}
}
@@ -1173,7 +2090,7 @@ static void mct_SetDQSDelayCSR_D(struct MCTStatStruc *pMCTstat,
{
u8 ByteLane;
u32 val;
- u32 index_reg = 0x98 + 0x100 * pDCTstat->Channel;
+ u32 index_reg = 0x98;
u8 shift;
u32 dqs_delay = (u32)pDCTstat->DQSDelay;
u32 dev = pDCTstat->dev_dct;
@@ -1201,7 +2118,7 @@ static void mct_SetDQSDelayCSR_D(struct MCTStatStruc *pMCTstat,
index += (ChipSel>>1) << 8;
- val = Get_NB32_index_wait(dev, index_reg, index);
+ val = Get_NB32_index_wait_DCT(dev, pDCTstat->Channel, index_reg, index);
if (ByteLane < 8) {
if (pDCTstat->Direction == DQS_WRITEDIR) {
dqs_delay += pDCTstat->CH_D_B_TxDqs[pDCTstat->Channel][ChipSel>>1][ByteLane];
@@ -1211,7 +2128,7 @@ static void mct_SetDQSDelayCSR_D(struct MCTStatStruc *pMCTstat,
}
val &= ~(0x7f << shift);
val |= (dqs_delay << shift);
- Set_NB32_index_wait(dev, index_reg, index, val);
+ Set_NB32_index_wait_DCT(dev, pDCTstat->Channel, index_reg, index, val);
}
}
@@ -1237,7 +2154,7 @@ u32 mct_GetMCTSysAddr_D(struct MCTStatStruc *pMCTstat,
u8 Channel, u8 receiver, u8 *valid)
{
u32 val;
- u32 reg_off = 0;
+ uint8_t dct = 0;
u32 reg;
u32 dword;
u32 dev = pDCTstat->dev_dct;
@@ -1246,12 +2163,12 @@ u32 mct_GetMCTSysAddr_D(struct MCTStatStruc *pMCTstat,
if (!pDCTstat->GangedMode) {
- reg_off = 0x100 * Channel;
+ dct = Channel;
}
/* get the local base addr of the chipselect */
- reg = 0x40 + (receiver << 2) + reg_off;
- val = Get_NB32(dev, reg);
+ reg = 0x40 + (receiver << 2);
+ val = Get_NB32_DCT(dev, dct, reg);
val &= ~0xe007c01f;
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c
index 625fe7ddc4..0a51b1a228 100644
--- a/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c
+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c
@@ -2,6 +2,7 @@
* This file is part of the coreboot project.
*
* Copyright (C) 2010 Advanced Micro Devices, Inc.
+ * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering
*
* 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
@@ -87,19 +88,21 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA)
/* Construct these booleans, based on setup options, for easy handling
later in this procedure */
- OB_NBECC = mctGet_NVbits(NV_NBECC); /* MCA ECC (MCE) enable bit */
+ OB_NBECC = mctGet_NVbits(NV_NBECC); /* MCA ECC (MCE) enable bit */
- OB_ECCRedir = mctGet_NVbits(NV_ECCRedir); /* ECC Redirection */
+ OB_ECCRedir = mctGet_NVbits(NV_ECCRedir); /* ECC Redirection */
- OB_ChipKill = mctGet_NVbits(NV_ChipKill); /* ECC Chip-kill mode */
+ OB_ChipKill = mctGet_NVbits(NV_ChipKill); /* ECC Chip-kill mode */
+ OF_ScrubCTL = 0; /* Scrub CTL for Dcache, L2, and dram */
- OF_ScrubCTL = 0; /* Scrub CTL for Dcache, L2, and dram */
- nvbits = mctGet_NVbits(NV_DCBKScrub);
- /* mct_AdjustScrub_D(pDCTstatA, &nvbits); */ /* Need not adjust */
- OF_ScrubCTL |= (u32) nvbits << 16;
+ if (!is_fam15h()) {
+ nvbits = mctGet_NVbits(NV_DCBKScrub);
+ /* mct_AdjustScrub_D(pDCTstatA, &nvbits); */ /* Need not adjust */
+ OF_ScrubCTL |= (u32) nvbits << 16;
- nvbits = mctGet_NVbits(NV_L2BKScrub);
- OF_ScrubCTL |= (u32) nvbits << 8;
+ nvbits = mctGet_NVbits(NV_L2BKScrub);
+ OF_ScrubCTL |= (u32) nvbits << 8;
+ }
nvbits = mctGet_NVbits(NV_DramBKScrub);
OF_ScrubCTL |= nvbits;
@@ -127,7 +130,7 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA)
pDCTstat->ErrStatus |= (1 << SB_DramECCDis);
}
AllECC = 0;
- LDramECC =0;
+ LDramECC = 0;
}
} else {
AllECC = 0;
@@ -136,7 +139,7 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA)
if (OB_NBECC) {
mct_EnableDatIntlv_D(pMCTstat, pDCTstat);
dev = pDCTstat->dev_nbmisc;
- reg =0x44; /* MCA NB Configuration */
+ reg = 0x44; /* MCA NB Configuration */
val = Get_NB32(dev, reg);
val |= 1 << 22; /* EccEn */
Set_NB32(dev, reg, val);
@@ -173,6 +176,10 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA)
/*WE/RE is checked because memory config may have been */
if((val & 3)==3) { /* Node has dram populated */
if (isDramECCEn_D(pDCTstat)) { /* if ECC is enabled on this dram */
+ if (is_fam15h()) {
+ /* Erratum 505 */
+ fam15h_switch_dct(pDCTstat->dev_map, 0);
+ }
dev = pDCTstat->dev_nbmisc;
val = curBase << 8;
if(OB_ECCRedir) {
@@ -183,16 +190,18 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA)
Set_NB32(dev, 0x60, val); /* Dram Scrub Addr High */
Set_NB32(dev, 0x58, OF_ScrubCTL); /*Scrub Control */
- /* Divisor should not be set deeper than
- * divide by 16 when Dcache scrubber or
- * L2 scrubber is enabled.
- */
- if ((OF_ScrubCTL & (0x1F << 16)) || (OF_ScrubCTL & (0x1F << 8))) {
- val = Get_NB32(dev, 0x84);
- if ((val & 0xE0000000) > 0x80000000) { /* Get F3x84h[31:29]ClkDivisor for C1 */
- val &= 0x1FFFFFFF; /* If ClkDivisor is deeper than divide-by-16 */
- val |= 0x80000000; /* set it to divide-by-16 */
- Set_NB32(dev, 0x84, val);
+ if (!is_fam15h()) {
+ /* Divisor should not be set deeper than
+ * divide by 16 when Dcache scrubber or
+ * L2 scrubber is enabled.
+ */
+ if ((OF_ScrubCTL & (0x1F << 16)) || (OF_ScrubCTL & (0x1F << 8))) {
+ val = Get_NB32(dev, 0x84);
+ if ((val & 0xE0000000) > 0x80000000) { /* Get F3x84h[31:29]ClkDivisor for C1 */
+ val &= 0x1FFFFFFF; /* If ClkDivisor is deeper than divide-by-16 */
+ val |= 0x80000000; /* set it to divide-by-16 */
+ Set_NB32(dev, 0x84, val);
+ }
}
}
} /* this node has ECC enabled dram */
@@ -263,8 +272,8 @@ static u8 isDramECCEn_D(struct DCTStatStruc *pDCTstat)
}
for(i=0; i<ch_end; i++) {
if(pDCTstat->DIMMValidDCT[i] > 0){
- reg = 0x90 + i * 0x100; /* Dram Config Low */
- val = Get_NB32(dev, reg);
+ reg = 0x90; /* Dram Config Low */
+ val = Get_NB32_DCT(dev, i, reg);
if(val & (1<<DimmEcEn)) {
/* set local flag 'dram ecc capable' */
isDimmECCEn = 1;
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mcthdi.c b/src/northbridge/amd/amdmct/mct_ddr3/mcthdi.c
index f55ef901c0..10e9e44a6b 100644
--- a/src/northbridge/amd/amdmct/mct_ddr3/mcthdi.c
+++ b/src/northbridge/amd/amdmct/mct_ddr3/mcthdi.c
@@ -2,6 +2,7 @@
* This file is part of the coreboot project.
*
* Copyright (C) 2010 Advanced Micro Devices, Inc.
+ * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering
*
* 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
@@ -21,8 +22,8 @@ void mct_DramInit_Hw_D(struct MCTStatStruc *pMCTstat,
u32 dev = pDCTstat->dev_dct;
/*flag for selecting HW/SW DRAM Init HW DRAM Init */
- reg = 0x90 + 0x100 * dct; /*DRAM Configuration Low */
- val = Get_NB32(dev, reg);
+ reg = 0x90; /*DRAM Configuration Low */
+ val = Get_NB32_DCT(dev, dct, reg);
val |= (1<<InitDram);
- Set_NB32(dev, reg, val);
+ Set_NB32_DCT(dev, dct, reg, val);
}
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c b/src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c
index 87a6e7aea3..5107fee63d 100644
--- a/src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c
+++ b/src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c
@@ -14,10 +14,12 @@
* GNU General Public License for more details.
*/
-static void SetTargetFreq(struct MCTStatStruc *pMCTstat,
- struct DCTStatStruc *pDCTstat);
-static void AgesaHwWlPhase1(sMCTStruct *pMCTData,
- sDCTStruct *pDCTData, u8 dimm, u8 pass);
+static void AgesaHwWlPhase1(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct, u8 dimm, u8 pass);
+static void AgesaHwWlPhase2(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct, u8 dimm, u8 pass);
+static void AgesaHwWlPhase3(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct, u8 dimm, u8 pass);
static void EnableZQcalibration(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat);
static void DisableZQcalibration(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat);
static void PrepareC_MCT(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat);
@@ -52,7 +54,7 @@ static void SetEccWrDQS_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pD
Addl_Index = 0x32;
Addl_Index += DimmNum * 3;
- val = Get_NB32_index_wait(pDCTstat->dev_dct, Channel * 0x100 + 0x98, Addl_Index);
+ val = Get_NB32_index_wait_DCT(pDCTstat->dev_dct, Channel, 0x98, Addl_Index);
if (OddByte)
val >>= 16;
/* Save WrDqs to stack for later usage */
@@ -70,13 +72,13 @@ static void EnableAutoRefresh_D(struct MCTStatStruc *pMCTstat, struct DCTStatStr
{
u32 val;
- val = Get_NB32(pDCTstat->dev_dct, 0x8C);
+ val = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x8C);
val &= ~(1 << DisAutoRefresh);
- Set_NB32(pDCTstat->dev_dct, 0x8C, val);
+ Set_NB32_DCT(pDCTstat->dev_dct, 0, 0x8C, val);
- val = Get_NB32(pDCTstat->dev_dct, 0x8C + 0x100);
+ val = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x8C);
val &= ~(1 << DisAutoRefresh);
- Set_NB32(pDCTstat->dev_dct, 0x8C + 0x100, val);
+ Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x8C, val);
}
static void DisableAutoRefresh_D(struct MCTStatStruc *pMCTstat,
@@ -84,13 +86,13 @@ static void DisableAutoRefresh_D(struct MCTStatStruc *pMCTstat,
{
u32 val;
- val = Get_NB32(pDCTstat->dev_dct, 0x8C);
+ val = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x8C);
val |= 1 << DisAutoRefresh;
- Set_NB32(pDCTstat->dev_dct, 0x8C, val);
+ Set_NB32_DCT(pDCTstat->dev_dct, 0, 0x8C, val);
- val = Get_NB32(pDCTstat->dev_dct, 0x8C + 0x100);
+ val = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x8C);
val |= 1 << DisAutoRefresh;
- Set_NB32(pDCTstat->dev_dct, 0x8C + 0x100, val);
+ Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x8C, val);
}
@@ -114,8 +116,11 @@ static void PhyWLPass1(struct MCTStatStruc *pMCTstat,
DIMMValid = pDCTstat->DIMMValid;
PrepareC_DCT(pMCTstat, pDCTstat, dct);
for (dimm = 0; dimm < MAX_DIMMS_SUPPORTED; dimm ++) {
- if (DIMMValid & (1 << (dimm << 1)))
- AgesaHwWlPhase1(pDCTstat->C_MCTPtr, DCTPtr, dimm, FirstPass);
+ if (DIMMValid & (1 << (dimm << 1))) {
+ AgesaHwWlPhase1(pMCTstat, pDCTstat, dct, dimm, FirstPass);
+ AgesaHwWlPhase2(pMCTstat, pDCTstat, dct, dimm, FirstPass);
+ AgesaHwWlPhase3(pMCTstat, pDCTstat, dct, dimm, FirstPass);
+ }
}
}
}
@@ -142,27 +147,40 @@ static void PhyWLPass2(struct MCTStatStruc *pMCTstat,
pDCTstat->Speed = pDCTstat->DIMMAutoSpeed = pDCTstat->TargetFreq;
pDCTstat->CASL = pDCTstat->DIMMCASL = pDCTstat->TargetCASL;
SPD2ndTiming(pMCTstat, pDCTstat, dct);
- ProgDramMRSReg_D(pMCTstat, pDCTstat, dct);
- PlatformSpec_D(pMCTstat, pDCTstat, dct);
- fenceDynTraining_D(pMCTstat, pDCTstat, dct);
+ if (!is_fam15h()) {
+ ProgDramMRSReg_D(pMCTstat, pDCTstat, dct);
+ PlatformSpec_D(pMCTstat, pDCTstat, dct);
+ fenceDynTraining_D(pMCTstat, pDCTstat, dct);
+ }
Restore_OnDimmMirror(pMCTstat, pDCTstat);
StartupDCT_D(pMCTstat, pDCTstat, dct);
Clear_OnDimmMirror(pMCTstat, pDCTstat);
SetDllSpeedUp_D(pMCTstat, pDCTstat, dct);
DisableAutoRefresh_D(pMCTstat, pDCTstat);
for (dimm = 0; dimm < MAX_DIMMS_SUPPORTED; dimm ++) {
- if (DIMMValid & (1 << (dimm << 1)))
- AgesaHwWlPhase1(pDCTstat->C_MCTPtr, pDCTstat->C_DCTPtr[dct], dimm, SecondPass);
+ if (DIMMValid & (1 << (dimm << 1))) {
+ AgesaHwWlPhase1(pMCTstat, pDCTstat, dct, dimm, SecondPass);
+ AgesaHwWlPhase2(pMCTstat, pDCTstat, dct, dimm, SecondPass);
+ AgesaHwWlPhase3(pMCTstat, pDCTstat, dct, dimm, SecondPass);
+ }
}
}
}
+static uint16_t fam15h_next_highest_memclk_freq(uint16_t memclk_freq)
+{
+ uint16_t fam15h_next_highest_freq_tab[] = {0, 0, 0, 0, 0x6, 0, 0xa, 0, 0, 0, 0xe, 0, 0, 0, 0x12, 0, 0, 0, 0x16, 0, 0, 0, 0x16};
+ return fam15h_next_highest_freq_tab[memclk_freq];
+}
+
/* Write Levelization Training
* Algorithm detailed in the Fam10h BKDG Rev. 3.62 section 2.8.9.9.1
*/
static void WriteLevelization_HW(struct MCTStatStruc *pMCTstat,
- struct DCTStatStruc *pDCTstat)
+ struct DCTStatStruc *pDCTstat, uint8_t Pass)
{
+ uint16_t final_target_freq;
+
pDCTstat->C_MCTPtr = &(pDCTstat->s_C_MCTPtr);
pDCTstat->C_DCTPtr[0] = &(pDCTstat->s_C_DCTPtr[0]);
pDCTstat->C_DCTPtr[1] = &(pDCTstat->s_C_DCTPtr[1]);
@@ -178,16 +196,39 @@ static void WriteLevelization_HW(struct MCTStatStruc *pMCTstat,
pDCTstat->DIMMValidDCT[1] = pDCTstat->DIMMValidDCT[0];
}
- PhyWLPass1(pMCTstat, pDCTstat, 0);
- PhyWLPass1(pMCTstat, pDCTstat, 1);
+ if (Pass == FirstPass) {
+ PhyWLPass1(pMCTstat, pDCTstat, 0);
+ PhyWLPass1(pMCTstat, pDCTstat, 1);
+ }
+
+ if (Pass == SecondPass) {
+ if (pDCTstat->TargetFreq > mhz_to_memclk_config(mctGet_NVbits(NV_MIN_MEMCLK))) {
+ /* 8.Prepare the memory subsystem for the target MEMCLK frequency.
+ * NOTE: BIOS must program both DCTs to the same frequency.
+ * NOTE: Fam15h steps the frequency, Fam10h slams the frequency.
+ */
+ final_target_freq = pDCTstat->TargetFreq;
+
+ while (pDCTstat->Speed != final_target_freq) {
+ if (is_fam15h())
+ pDCTstat->TargetFreq = fam15h_next_highest_memclk_freq(pDCTstat->Speed);
+ else
+ pDCTstat->TargetFreq = final_target_freq;
+ SetTargetFreq(pMCTstat, pDCTstat);
+ PhyWLPass2(pMCTstat, pDCTstat, 0);
+ PhyWLPass2(pMCTstat, pDCTstat, 1);
+ }
- if (pDCTstat->TargetFreq > 4) {
- /* 8.Prepare the memory subsystem for the target MEMCLK frequency.
- * Note: BIOS must program both DCTs to the same frequency.
- */
- SetTargetFreq(pMCTstat, pDCTstat);
- PhyWLPass2(pMCTstat, pDCTstat, 0);
- PhyWLPass2(pMCTstat, pDCTstat, 1);
+ pDCTstat->TargetFreq = final_target_freq;
+
+ uint8_t dct;
+ for (dct = 0; dct < 2; dct++) {
+ sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
+ memcpy(pDCTData->WLGrossDelayFinalPass, pDCTData->WLGrossDelayPrevPass, sizeof(pDCTData->WLGrossDelayPrevPass));
+ memcpy(pDCTData->WLFineDelayFinalPass, pDCTData->WLFineDelayPrevPass, sizeof(pDCTData->WLFineDelayPrevPass));
+ pDCTData->WLCriticalGrossDelayFinalPass = pDCTData->WLCriticalGrossDelayPrevPass;
+ }
+ }
}
SetEccWrDQS_D(pMCTstat, pDCTstat);
@@ -196,7 +237,7 @@ static void WriteLevelization_HW(struct MCTStatStruc *pMCTstat,
}
void mct_WriteLevelization_HW(struct MCTStatStruc *pMCTstat,
- struct DCTStatStruc *pDCTstatA)
+ struct DCTStatStruc *pDCTstatA, uint8_t Pass)
{
u8 Node;
@@ -207,7 +248,7 @@ void mct_WriteLevelization_HW(struct MCTStatStruc *pMCTstat,
if (pDCTstat->NodePresent) {
mctSMBhub_Init(Node);
Clear_OnDimmMirror(pMCTstat, pDCTstat);
- WriteLevelization_HW(pMCTstat, pDCTstat);
+ WriteLevelization_HW(pMCTstat, pDCTstat, Pass);
Restore_OnDimmMirror(pMCTstat, pDCTstat);
}
}
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c b/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c
index 4502a0b80d..a86c319a88 100644
--- a/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c
+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c
@@ -30,7 +30,7 @@ u32 mct_SetDramConfigMisc2(struct DCTStatStruc *pDCTstat, u8 dct, u32 misc2)
if (pDCTstat->LogicalCPUID & AMD_DR_Cx)
misc2 |= 1 << OdtSwizzle;
- val = Get_NB32(pDCTstat->dev_dct, dct * 0x100 + 0x78);
+ val = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x78);
val &= 7;
val = ((~val) & 0xff) + 1;
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c b/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c
index 53d51f1b9a..d7bd3a7cdc 100644
--- a/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c
+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c
@@ -2,6 +2,7 @@
* This file is part of the coreboot project.
*
* Copyright (C) 2010 Advanced Micro Devices, Inc.
+ * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering
*
* 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
@@ -19,7 +20,6 @@ static u32 mct_ControlRC(struct MCTStatStruc *pMCTstat,
u8 Dimms, DimmNum, MaxDimm, Speed;
u32 val;
u32 dct = 0;
- u32 reg_off = 0;
DimmNum = (MrsChipSel >> 20) & 0xFE;
@@ -37,7 +37,6 @@ static u32 mct_ControlRC(struct MCTStatStruc *pMCTstat,
dct = 1;
DimmNum ++;
}
- reg_off = 0x100 * dct;
Dimms = pDCTstat->MAdimms[dct];
val = 0;
@@ -91,21 +90,21 @@ static u32 mct_ControlRC(struct MCTStatStruc *pMCTstat,
static void mct_SendCtrlWrd(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat, u32 val)
{
- u32 reg_off = 0;
+ uint8_t dct = 0;
u32 dev = pDCTstat->dev_dct;
if (pDCTstat->CSPresent_DCT[0] > 0) {
- reg_off = 0;
+ dct = 0;
} else if (pDCTstat->CSPresent_DCT[1] > 0 ){
- reg_off = 0x100;
+ dct = 1;
}
- val |= Get_NB32(dev, reg_off + 0x7C) & ~0xFFFFFF;
+ val |= Get_NB32_DCT(dev, dct, 0x7C) & ~0xFFFFFF;
val |= 1 << SendControlWord;
- Set_NB32(dev, reg_off + 0x7C, val);
+ Set_NB32_DCT(dev, dct, 0x7C, val);
do {
- val = Get_NB32(dev, reg_off + 0x7C);
+ val = Get_NB32_DCT(dev, dct, 0x7C);
} while (val & (1 << SendControlWord));
}
@@ -115,7 +114,6 @@ void mct_DramControlReg_Init_D(struct MCTStatStruc *pMCTstat,
u8 MrsChipSel;
u32 dev = pDCTstat->dev_dct;
u32 val, cw;
- u32 reg_off = 0x100 * dct;
mct_Wait(1600);
@@ -123,7 +121,7 @@ void mct_DramControlReg_Init_D(struct MCTStatStruc *pMCTstat,
for (MrsChipSel = 0; MrsChipSel < 8; MrsChipSel ++, MrsChipSel ++) {
if (pDCTstat->CSPresent & (1 << MrsChipSel)) {
- val = Get_NB32(dev, reg_off + 0xA8);
+ val = Get_NB32_DCT(dev, dct, 0xa8);
val &= ~(0xF << 8);
switch (MrsChipSel) {
@@ -140,7 +138,7 @@ void mct_DramControlReg_Init_D(struct MCTStatStruc *pMCTstat,
case 7:
val |= (3 << 6) << 8;
}
- Set_NB32(dev, reg_off + 0xA8 , val);
+ Set_NB32_DCT(dev, dct, 0xa8, val);
for (cw=0; cw <=15; cw ++) {
mct_Wait(1600);
@@ -167,10 +165,10 @@ void FreqChgCtrlWrd(struct MCTStatStruc *pMCTstat,
for (MrsChipSel=0; MrsChipSel < 8; MrsChipSel++, MrsChipSel++) {
if (pDCTstat->CSPresent & (1 << MrsChipSel)) {
/* 2. Program F2x[1, 0]A8[CtrlWordCS]=bit mask for target chip selects. */
- val = Get_NB32(dev, 0xA8); /* TODO: dct * 0x100 + 0xA8 */
+ val = Get_NB32_DCT(dev, 0, 0xA8); /* TODO: dct 0 / 1 select */
val &= ~(0xFF << 8);
val |= (0x3 << (MrsChipSel & 0xFE)) << 8;
- Set_NB32(dev, 0xA8, val); /* TODO: dct * 0x100 + 0xA8 */
+ Set_NB32_DCT(dev, 0, 0xA8, val); /* TODO: dct 0 / 1 select */
/* Resend control word 10 */
mct_Wait(1600);
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c b/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
index a71bcbb56b..46a068414b 100644
--- a/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
@@ -14,17 +14,182 @@
* GNU General Public License for more details.
*/
+static uint8_t fam15_dimm_dic(struct DCTStatStruc *pDCTstat, uint8_t dct, uint8_t dimm, uint8_t rank, uint8_t package_type)
+{
+ uint8_t dic;
+
+ /* Calculate DIC based on recommendations in MR1_dct[1:0] */
+ if (pDCTstat->Status & (1 << SB_LoadReduced)) {
+ /* TODO
+ * LRDIMM unimplemented
+ */
+ dic = 0x0;
+ } else {
+ dic = 0x1;
+ }
+
+ return dic;
+}
+
+static uint8_t fam15_rttwr(struct DCTStatStruc *pDCTstat, uint8_t dct, uint8_t dimm, uint8_t rank, uint8_t package_type)
+{
+ uint8_t term = 0;
+ sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
+ uint8_t number_of_dimms = pDCTData->MaxDimmsInstalled;
+ uint8_t frequency_index;
+ uint8_t rank_count = pDCTData->DimmRanks[dimm];
+
+ if (is_fam15h())
+ frequency_index = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 0x1f;
+ else
+ frequency_index = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 0x7;
+
+ /* FIXME
+ * Mainboards need to be able to specify the maximum number of DIMMs installable per channel
+ * For now assume a maximum of 2 DIMMs per channel can be installed
+ */
+ uint8_t MaxDimmsInstallable = 2;
+
+ if (is_fam15h()) {
+ if (pDCTstat->Status & (1 << SB_Registered)) {
+ /* TODO
+ * RDIMM unimplemented
+ */
+ } else {
+ if (package_type == PT_GR) {
+ /* Socket G34: Fam15h BKDG v3.14 Table 56 */
+ if (MaxDimmsInstallable == 1) {
+ term = 0x0;
+ } else if (MaxDimmsInstallable == 2) {
+ if ((number_of_dimms == 2) && (frequency_index == 0x12)) {
+ term = 0x1;
+ } else if (number_of_dimms == 1) {
+ term = 0x0;
+ } else {
+ term = 0x2;
+ }
+ } else if (MaxDimmsInstallable == 3) {
+ if (number_of_dimms == 1) {
+ if (frequency_index <= 0xa) {
+ term = 0x2;
+ } else {
+ if (rank_count < 3) {
+ term = 0x1;
+ } else {
+ term = 0x2;
+ }
+ }
+ } else if (number_of_dimms == 2) {
+ term = 0x2;
+ }
+ }
+ } else {
+ /* TODO
+ * Other sockets unimplemented
+ */
+ }
+ }
+ }
+
+ return term;
+}
+
+static uint8_t fam15_rttnom(struct DCTStatStruc *pDCTstat, uint8_t dct, uint8_t dimm, uint8_t rank, uint8_t package_type)
+{
+ uint8_t term = 0;
+ sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
+ uint8_t number_of_dimms = pDCTData->MaxDimmsInstalled;
+ uint8_t frequency_index;
+
+ if (is_fam15h())
+ frequency_index = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 0x1f;
+ else
+ frequency_index = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 0x7;
+
+ /* FIXME
+ * Mainboards need to be able to specify the maximum number of DIMMs installable per channel
+ * For now assume a maximum of 2 DIMMs per channel can be installed
+ */
+ uint8_t MaxDimmsInstallable = 2;
+
+ if (is_fam15h()) {
+ if (pDCTstat->Status & (1 << SB_LoadReduced)) {
+ /* TODO
+ * LRDIMM unimplemented
+ */
+ } else if (pDCTstat->Status & (1 << SB_Registered)) {
+ /* TODO
+ * RDIMM unimplemented
+ */
+ } else {
+ if (package_type == PT_GR) {
+ /* Socket G34: Fam15h BKDG v3.14 Table 56 */
+ if (MaxDimmsInstallable == 1) {
+ if ((frequency_index == 0x4) || (frequency_index == 0x6))
+ term = 0x2;
+ else if ((frequency_index == 0xa) || (frequency_index == 0xe))
+ term = 0x1;
+ else
+ term = 0x3;
+ }
+ if (MaxDimmsInstallable == 2) {
+ if (number_of_dimms == 1) {
+ if (frequency_index <= 0x6) {
+ term = 0x2;
+ } else if (frequency_index <= 0xe) {
+ term = 0x1;
+ } else {
+ term = 0x3;
+ }
+ } else {
+ if (frequency_index <= 0xa) {
+ term = 0x3;
+ } else if (frequency_index <= 0xe) {
+ term = 0x5;
+ } else {
+ term = 0x4;
+ }
+ }
+ } else if (MaxDimmsInstallable == 3) {
+ if (number_of_dimms == 1) {
+ term = 0x0;
+ } else if (number_of_dimms == 2) {
+ if (frequency_index <= 0xa) {
+ if (rank == 1) {
+ term = 0x0;
+ } else {
+ term = 0x3;
+ }
+ } else if (frequency_index <= 0xe) {
+ if (rank == 1) {
+ term = 0x0;
+ } else {
+ term = 0x5;
+ }
+ }
+ }
+ }
+ } else {
+ /* TODO
+ * Other sockets unimplemented
+ */
+ }
+ }
+ }
+
+ return term;
+}
+
static void mct_DramControlReg_Init_D(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat, u8 dct);
static void mct_DCTAccessDone(struct DCTStatStruc *pDCTstat, u8 dct)
{
- u32 reg_off = 0x100 * dct;
u32 dev = pDCTstat->dev_dct;
u32 val;
do {
- val = Get_NB32(dev, reg_off + 0x98);
+ val = Get_NB32_DCT(dev, dct, 0x98);
} while (!(val & (1 << DctAccessDone)));
}
@@ -50,9 +215,15 @@ static u32 swapAddrBits(struct DCTStatStruc *pDCTstat, u32 MR_register_setting,
if (MR_register_setting & (1 << 6)) ret |= 1 << 5;
if (MR_register_setting & (1 << 7)) ret |= 1 << 8;
if (MR_register_setting & (1 << 8)) ret |= 1 << 7;
- if (MR_register_setting & (1 << 16)) ret |= 1 << 17;
- if (MR_register_setting & (1 << 17)) ret |= 1 << 16;
- MR_register_setting &= ~0x301f8;
+ if (is_fam15h()) {
+ if (MR_register_setting & (1 << 18)) ret |= 1 << 19;
+ if (MR_register_setting & (1 << 19)) ret |= 1 << 18;
+ MR_register_setting &= ~0x000c01f8;
+ } else {
+ if (MR_register_setting & (1 << 16)) ret |= 1 << 17;
+ if (MR_register_setting & (1 << 17)) ret |= 1 << 16;
+ MR_register_setting &= ~0x000301f8;
+ }
MR_register_setting |= ret;
}
}
@@ -61,47 +232,76 @@ static u32 swapAddrBits(struct DCTStatStruc *pDCTstat, u32 MR_register_setting,
static void mct_SendMrsCmd(struct DCTStatStruc *pDCTstat, u8 dct, u32 EMRS)
{
- u32 reg_off = 0x100 * dct;
u32 dev = pDCTstat->dev_dct;
u32 val;
- val = Get_NB32(dev, reg_off + 0x7C);
- val &= ~0xFFFFFF;
+ val = Get_NB32_DCT(dev, dct, 0x7c);
+ val &= ~0x00ffffff;
val |= EMRS;
val |= 1 << SendMrsCmd;
- Set_NB32(dev, reg_off + 0x7C, val);
+ Set_NB32_DCT(dev, dct, 0x7c, val);
do {
- val = Get_NB32(dev, reg_off + 0x7C);
+ val = Get_NB32_DCT(dev, dct, 0x7c);
} while (val & (1 << SendMrsCmd));
}
static u32 mct_MR2(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat, u8 dct, u32 MrsChipSel)
{
- u32 reg_off = 0x100 * dct;
u32 dev = pDCTstat->dev_dct;
u32 dword, ret;
- ret = 0x20000;
- ret |= MrsChipSel;
+ if (is_fam15h()) {
+ uint8_t package_type = mctGet_NVbits(NV_PACK_TYPE);
+
+ /* The formula for chip select number is: CS = dimm*2+rank */
+ uint8_t dimm = MrsChipSel / 2;
+ uint8_t rank = MrsChipSel % 2;
- /* program MrsAddress[5:3]=CAS write latency (CWL):
- * based on F2x[1,0]84[Tcwl] */
- dword = Get_NB32(dev, reg_off + 0x84);
- dword = mct_AdjustSPDTimings(pMCTstat, pDCTstat, dword);
+ /* FIXME: These parameters should be configurable
+ * For now, err on the side of caution and enable automatic 2x refresh
+ * when the DDR temperature rises above the internal limits
+ */
+ uint8_t force_2x_self_refresh = 0; /* ASR */
+ uint8_t auto_2x_self_refresh = 1; /* SRT */
- ret |= ((dword >> 20) & 7) << 3;
+ ret = 0x80000;
+ ret |= (MrsChipSel << 21);
- /* program MrsAddress[6]=auto self refresh method (ASR):
- based on F2x[1,0]84[ASR]
- program MrsAddress[7]=self refresh temperature range (SRT):
- based on F2x[1,0]84[ASR and SRT] */
- ret |= ((dword >> 18) & 3) << 6;
+ /* Set self refresh parameters */
+ ret |= (force_2x_self_refresh << 6);
+ ret |= (auto_2x_self_refresh << 7);
- /* program MrsAddress[10:9]=dynamic termination during writes (RTT_WR)
- based on F2x[1,0]84[DramTermDyn] */
- ret |= ((dword >> 10) & 3) << 9;
+ /* Obtain Tcwl, adjust, and set CWL with the adjusted value */
+ dword = Get_NB32_DCT(dev, dct, 0x20c) & 0x1f;
+ ret |= ((dword - 5) << 3);
+
+ /* Obtain and set RttWr */
+ ret |= (fam15_rttwr(pDCTstat, dct, dimm, rank, package_type) << 9);
+ } else {
+ ret = 0x20000;
+ ret |= (MrsChipSel << 20);
+
+ /* program MrsAddress[5:3]=CAS write latency (CWL):
+ * based on F2x[1,0]84[Tcwl] */
+ dword = Get_NB32_DCT(dev, dct, 0x84);
+ dword = mct_AdjustSPDTimings(pMCTstat, pDCTstat, dword);
+
+ ret |= ((dword >> 20) & 7) << 3;
+
+ /* program MrsAddress[6]=auto self refresh method (ASR):
+ * based on F2x[1,0]84[ASR]
+ * program MrsAddress[7]=self refresh temperature range (SRT):
+ * based on F2x[1,0]84[ASR and SRT]
+ */
+ ret |= ((dword >> 18) & 3) << 6;
+
+ /* program MrsAddress[10:9]=dynamic termination during writes (RTT_WR)
+ * based on F2x[1,0]84[DramTermDyn]
+ */
+ ret |= ((dword >> 10) & 3) << 9;
+ }
return ret;
}
@@ -109,20 +309,28 @@ static u32 mct_MR2(struct MCTStatStruc *pMCTstat,
static u32 mct_MR3(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat, u8 dct, u32 MrsChipSel)
{
- u32 reg_off = 0x100 * dct;
u32 dev = pDCTstat->dev_dct;
u32 dword, ret;
- ret = 0x30000;
- ret |= MrsChipSel;
+ if (is_fam15h()) {
+ ret = 0xc0000;
+ ret |= (MrsChipSel << 21);
- /* program MrsAddress[1:0]=multi purpose register address location
- (MPR Location):based on F2x[1,0]84[MprLoc]
- program MrsAddress[2]=multi purpose register
- (MPR):based on F2x[1,0]84[MprEn]
- */
- dword = Get_NB32(dev, reg_off + 0x84);
- ret |= (dword >> 24) & 7;
+ /* Program MPR and MPRLoc to 0 */
+ // ret |= 0x0; /* MPR */
+ // ret |= (0x0 << 2); /* MPRLoc */
+ } else {
+ ret = 0x30000;
+ ret |= (MrsChipSel << 20);
+
+ /* program MrsAddress[1:0]=multi purpose register address location
+ * (MPR Location):based on F2x[1,0]84[MprLoc]
+ * program MrsAddress[2]=multi purpose register
+ * (MPR):based on F2x[1,0]84[MprEn]
+ */
+ dword = Get_NB32_DCT(dev, dct, 0x84);
+ ret |= (dword >> 24) & 7;
+ }
return ret;
}
@@ -130,48 +338,93 @@ static u32 mct_MR3(struct MCTStatStruc *pMCTstat,
static u32 mct_MR1(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat, u8 dct, u32 MrsChipSel)
{
- u32 reg_off = 0x100 * dct;
u32 dev = pDCTstat->dev_dct;
u32 dword, ret;
- ret = 0x10000;
- ret |= MrsChipSel;
-
- /* program MrsAddress[5,1]=output driver impedance control (DIC):
- * based on F2x[1,0]84[DrvImpCtrl] */
- dword = Get_NB32(dev, reg_off + 0x84);
- if (dword & (1 << 3))
- ret |= 1 << 5;
- if (dword & (1 << 2))
- ret |= 1 << 1;
-
- /* program MrsAddress[9,6,2]=nominal termination resistance of ODT (RTT):
- based on F2x[1,0]84[DramTerm] */
- if (!(pDCTstat->Status & (1 << SB_Registered))) {
- if (dword & (1 << 9))
- ret |= 1 << 9;
- if (dword & (1 << 8))
- ret |= 1 << 6;
- if (dword & (1 << 7))
- ret |= 1 << 2;
+ if (is_fam15h()) {
+ uint8_t package_type = mctGet_NVbits(NV_PACK_TYPE);
+
+ /* Set defaults */
+ uint8_t qoff = 0; /* Enable output buffers */
+ uint8_t wrlvl = 0; /* Disable write levelling */
+ uint8_t tqds = 0;
+ uint8_t rttnom = 0;
+ uint8_t dic = 0;
+ uint8_t additive_latency = 0;
+ uint8_t dll_enable = 0;
+
+ ret = 0x40000;
+ ret |= (MrsChipSel << 21);
+
+ /* The formula for chip select number is: CS = dimm*2+rank */
+ uint8_t dimm = MrsChipSel / 2;
+ uint8_t rank = MrsChipSel % 2;
+
+ /* Determine if TQDS should be set */
+ if ((pDCTstat->Dimmx8Present & (1 << dimm))
+ && (((dimm & 0x1)?(pDCTstat->Dimmx4Present&0x55):(pDCTstat->Dimmx4Present&0xaa)) != 0x0)
+ && (pDCTstat->Status & (1 << SB_LoadReduced)))
+ tqds = 1;
+
+ /* Obtain RttNom */
+ rttnom = fam15_rttnom(pDCTstat, dct, dimm, rank, package_type);
+
+ /* Obtain DIC */
+ dic = fam15_dimm_dic(pDCTstat, dct, dimm, rank, package_type);
+
+ /* Load data into MRS word */
+ ret |= (qoff & 0x1) << 12;
+ ret |= (tqds & 0x1) << 11;
+ ret |= ((rttnom & 0x4) >> 2) << 9;
+ ret |= ((rttnom & 0x2) >> 1) << 6;
+ ret |= ((rttnom & 0x1) >> 0) << 2;
+ ret |= (wrlvl & 0x1) << 7;
+ ret |= ((dic & 0x2) >> 1) << 5;
+ ret |= ((dic & 0x1) >> 0) << 1;
+ ret |= (additive_latency & 0x3) << 3;
+ ret |= (dll_enable & 0x1);
} else {
- ret |= mct_MR1Odt_RDimm(pMCTstat, pDCTstat, dct, MrsChipSel);
- }
+ ret = 0x10000;
+ ret |= (MrsChipSel << 20);
+
+ /* program MrsAddress[5,1]=output driver impedance control (DIC):
+ * based on F2x[1,0]84[DrvImpCtrl]
+ */
+ dword = Get_NB32_DCT(dev, dct, 0x84);
+ if (dword & (1 << 3))
+ ret |= 1 << 5;
+ if (dword & (1 << 2))
+ ret |= 1 << 1;
+
+ /* program MrsAddress[9,6,2]=nominal termination resistance of ODT (RTT):
+ * based on F2x[1,0]84[DramTerm]
+ */
+ if (!(pDCTstat->Status & (1 << SB_Registered))) {
+ if (dword & (1 << 9))
+ ret |= 1 << 9;
+ if (dword & (1 << 8))
+ ret |= 1 << 6;
+ if (dword & (1 << 7))
+ ret |= 1 << 2;
+ } else {
+ ret |= mct_MR1Odt_RDimm(pMCTstat, pDCTstat, dct, MrsChipSel);
+ }
- /* program MrsAddress[11]=TDQS: based on F2x[1,0]94[RDqsEn] */
- if (Get_NB32(dev, reg_off + 0x94) & (1 << RDqsEn)) {
- u8 bit;
- /* Set TDQS=1b for x8 DIMM, TDQS=0b for x4 DIMM, when mixed x8 & x4 */
- bit = (ret >> 21) << 1;
- if ((dct & 1) != 0)
- bit ++;
- if (pDCTstat->Dimmx8Present & (1 << bit))
- ret |= 1 << 11;
- }
+ /* program MrsAddress[11]=TDQS: based on F2x[1,0]94[RDqsEn] */
+ if (Get_NB32_DCT(dev, dct, 0x94) & (1 << RDqsEn)) {
+ u8 bit;
+ /* Set TDQS=1b for x8 DIMM, TDQS=0b for x4 DIMM, when mixed x8 & x4 */
+ bit = (ret >> 21) << 1;
+ if ((dct & 1) != 0)
+ bit ++;
+ if (pDCTstat->Dimmx8Present & (1 << bit))
+ ret |= 1 << 11;
+ }
- /* program MrsAddress[12]=QOFF: based on F2x[1,0]84[Qoff] */
- if (dword & (1 << 13))
- ret |= 1 << 12;
+ /* program MrsAddress[12]=QOFF: based on F2x[1,0]84[Qoff] */
+ if (dword & (1 << 13))
+ ret |= 1 << 12;
+ }
return ret;
}
@@ -179,60 +432,139 @@ static u32 mct_MR1(struct MCTStatStruc *pMCTstat,
static u32 mct_MR0(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat, u8 dct, u32 MrsChipSel)
{
- u32 reg_off = 0x100 * dct;
u32 dev = pDCTstat->dev_dct;
u32 dword, ret, dword2;
- ret = 0x00000;
- ret |= MrsChipSel;
-
- /* program MrsAddress[1:0]=burst length and control method
- (BL):based on F2x[1,0]84[BurstCtrl] */
- dword = Get_NB32(dev, reg_off + 0x84);
- ret |= dword & 3;
-
- /* program MrsAddress[3]=1 (BT):interleaved */
- ret |= 1 << 3;
-
- /* program MrsAddress[6:4,2]=read CAS latency
- (CL):based on F2x[1,0]88[Tcl] */
- dword2 = Get_NB32(dev, reg_off + 0x88);
- ret |= (dword2 & 0x7) << 4; /* F2x88[2:0] to MrsAddress[6:4] */
- ret |= ((dword2 & 0x8) >> 3) << 2; /* F2x88[3] to MrsAddress[2] */
-
- /* program MrsAddress[12]=0 (PPD):slow exit */
- if (dword & (1 << 23))
- ret |= 1 << 12;
-
- /* program MrsAddress[11:9]=write recovery for auto-precharge
- (WR):based on F2x[1,0]84[Twr] */
- ret |= ((dword >> 4) & 7) << 9;
-
- /* program MrsAddress[8]=1 (DLL):DLL reset
- just issue DLL reset at first time */
- ret |= 1 << 8;
+ if (is_fam15h()) {
+ ret = 0x00000;
+ ret |= (MrsChipSel << 21);
+
+ /* Set defaults */
+ uint8_t ppd = 0;
+ uint8_t wr_ap = 0;
+ uint8_t dll_reset = 1;
+ uint8_t test_mode = 0;
+ uint8_t cas_latency = 0;
+ uint8_t read_burst_type = 1;
+ uint8_t burst_length = 0;
+
+ /* Obtain PchgPDModeSel */
+ dword = Get_NB32_DCT(dev, dct, 0x84);
+ ppd = (dword >> 23) & 0x1;
+
+ /* Obtain Twr */
+ dword = Get_NB32_DCT(dev, dct, 0x22c) & 0x1f;
+
+ /* Calculate wr_ap (Fam15h BKDG v3.14 Table 82) */
+ if (dword == 0x10)
+ wr_ap = 0x0;
+ else if (dword == 0x5)
+ wr_ap = 0x1;
+ else if (dword == 0x6)
+ wr_ap = 0x2;
+ else if (dword == 0x7)
+ wr_ap = 0x3;
+ else if (dword == 0x8)
+ wr_ap = 0x4;
+ else if (dword == 0xa)
+ wr_ap = 0x5;
+ else if (dword == 0xc)
+ wr_ap = 0x6;
+ else if (dword == 0xe)
+ wr_ap = 0x7;
+
+ /* Obtain Tcl */
+ dword = Get_NB32_DCT(dev, dct, 0x200) & 0x1f;
+
+ /* Calculate cas_latency (Fam15h BKDG v3.14 Table 83) */
+ if (dword == 0x5)
+ cas_latency = 0x2;
+ else if (dword == 0x6)
+ cas_latency = 0x4;
+ else if (dword == 0x7)
+ cas_latency = 0x6;
+ else if (dword == 0x8)
+ cas_latency = 0x8;
+ else if (dword == 0x9)
+ cas_latency = 0xa;
+ else if (dword == 0xa)
+ cas_latency = 0xc;
+ else if (dword == 0xb)
+ cas_latency = 0xe;
+ else if (dword == 0xc)
+ cas_latency = 0x1;
+ else if (dword == 0xd)
+ cas_latency = 0x3;
+ else if (dword == 0xe)
+ cas_latency = 0x5;
+ else if (dword == 0xf)
+ cas_latency = 0x7;
+ else if (dword == 0x10)
+ cas_latency = 0x9;
+
+ /* Obtain BurstCtrl */
+ burst_length = Get_NB32_DCT(dev, dct, 0x84) & 0x3;
+
+ /* Load data into MRS word */
+ ret |= (ppd & 0x1) << 12;
+ ret |= (wr_ap & 0x3) << 9;
+ ret |= (dll_reset & 0x1) << 8;
+ ret |= (test_mode & 0x1) << 7;
+ ret |= ((cas_latency & 0xe) >> 1) << 4;
+ ret |= ((cas_latency & 0x1) >> 0) << 2;
+ ret |= (read_burst_type & 0x1) << 3;
+ ret |= (burst_length & 0x3);
+ } else {
+ ret = 0x00000;
+ ret |= (MrsChipSel << 20);
+
+ /* program MrsAddress[1:0]=burst length and control method
+ (BL):based on F2x[1,0]84[BurstCtrl] */
+ dword = Get_NB32_DCT(dev, dct, 0x84);
+ ret |= dword & 3;
+
+ /* program MrsAddress[3]=1 (BT):interleaved */
+ ret |= 1 << 3;
+
+ /* program MrsAddress[6:4,2]=read CAS latency
+ (CL):based on F2x[1,0]88[Tcl] */
+ dword2 = Get_NB32_DCT(dev, dct, 0x88);
+ ret |= (dword2 & 0x7) << 4; /* F2x88[2:0] to MrsAddress[6:4] */
+ ret |= ((dword2 & 0x8) >> 3) << 2; /* F2x88[3] to MrsAddress[2] */
+
+ /* program MrsAddress[12]=0 (PPD):slow exit */
+ if (dword & (1 << 23))
+ ret |= 1 << 12;
+
+ /* program MrsAddress[11:9]=write recovery for auto-precharge
+ (WR):based on F2x[1,0]84[Twr] */
+ ret |= ((dword >> 4) & 7) << 9;
+
+ /* program MrsAddress[8]=1 (DLL):DLL reset
+ just issue DLL reset at first time */
+ ret |= 1 << 8;
+ }
return ret;
}
static void mct_SendZQCmd(struct DCTStatStruc *pDCTstat, u8 dct)
{
- u32 reg_off = 0x100 * dct;
u32 dev = pDCTstat->dev_dct;
u32 dword;
/*1.Program MrsAddress[10]=1
2.Set SendZQCmd=1
*/
- dword = Get_NB32(dev, reg_off + 0x7C);
+ dword = Get_NB32_DCT(dev, dct, 0x7C);
dword &= ~0xFFFFFF;
dword |= 1 << 10;
dword |= 1 << SendZQCmd;
- Set_NB32(dev, reg_off + 0x7C, dword);
+ Set_NB32_DCT(dev, dct, 0x7C, dword);
/* Wait for SendZQCmd=0 */
do {
- dword = Get_NB32(dev, reg_off + 0x7C);
+ dword = Get_NB32_DCT(dev, dct, 0x7C);
} while (dword & (1 << SendZQCmd));
/* 4.Wait 512 MEMCLKs */
@@ -244,31 +576,30 @@ void mct_DramInit_Sw_D(struct MCTStatStruc *pMCTstat,
{
u8 MrsChipSel;
u32 dword;
- u32 reg_off = 0x100 * dct;
u32 dev = pDCTstat->dev_dct;
- if (pDCTstat->DIMMAutoSpeed == 4) {
+ if (pDCTstat->DIMMAutoSpeed == mhz_to_memclk_config(mctGet_NVbits(NV_MIN_MEMCLK))) {
/* 3.Program F2x[1,0]7C[EnDramInit]=1 */
- dword = Get_NB32(dev, reg_off + 0x7C);
+ dword = Get_NB32_DCT(dev, dct, 0x7c);
dword |= 1 << EnDramInit;
- Set_NB32(dev, reg_off + 0x7C, dword);
+ Set_NB32_DCT(dev, dct, 0x7c, dword);
mct_DCTAccessDone(pDCTstat, dct);
/* 4.wait 200us */
mct_Wait(40000);
- /* 5.On revision C processors, program F2x[1, 0]7C[DeassertMemRstX] = 1. */
- dword = Get_NB32(dev, reg_off + 0x7C);
+ /* 5.Program F2x[1, 0]7C[DeassertMemRstX] = 1. */
+ dword = Get_NB32_DCT(dev, dct, 0x7c);
dword |= 1 << DeassertMemRstX;
- Set_NB32(dev, reg_off + 0x7C, dword);
+ Set_NB32_DCT(dev, dct, 0x7c, dword);
/* 6.wait 500us */
mct_Wait(200000);
/* 7.Program F2x[1,0]7C[AssertCke]=1 */
- dword = Get_NB32(dev, reg_off + 0x7C);
+ dword = Get_NB32_DCT(dev, dct, 0x7c);
dword |= 1 << AssertCke;
- Set_NB32(dev, reg_off + 0x7C, dword);
+ Set_NB32_DCT(dev, dct, 0x7c, dword);
/* 8.wait 360ns */
mct_Wait(80);
@@ -277,6 +608,13 @@ void mct_DramInit_Sw_D(struct MCTStatStruc *pMCTstat,
* must be done for each chip select pair */
if (pDCTstat->Status & (1 << SB_Registered))
mct_DramControlReg_Init_D(pMCTstat, pDCTstat, dct);
+
+ /* The following steps are performed with load reduced DIMMs only and
+ * must be done for each DIMM */
+ // if (pDCTstat->Status & (1 << SB_LoadReduced))
+ /* TODO
+ * Implement LRDIMM configuration
+ */
}
/* The following steps are performed once for unbuffered DIMMs and once for each
@@ -285,23 +623,23 @@ void mct_DramInit_Sw_D(struct MCTStatStruc *pMCTstat,
if (pDCTstat->CSPresent & (1 << MrsChipSel)) {
u32 EMRS;
/* 13.Send EMRS(2) */
- EMRS = mct_MR2(pMCTstat, pDCTstat, dct, MrsChipSel << 20);
+ EMRS = mct_MR2(pMCTstat, pDCTstat, dct, MrsChipSel);
EMRS = swapAddrBits(pDCTstat, EMRS, MrsChipSel, dct);
mct_SendMrsCmd(pDCTstat, dct, EMRS);
/* 14.Send EMRS(3). Ordinarily at this time, MrsAddress[2:0]=000b */
- EMRS= mct_MR3(pMCTstat, pDCTstat, dct, MrsChipSel << 20);
+ EMRS= mct_MR3(pMCTstat, pDCTstat, dct, MrsChipSel);
EMRS = swapAddrBits(pDCTstat, EMRS, MrsChipSel, dct);
mct_SendMrsCmd(pDCTstat, dct, EMRS);
/* 15.Send EMRS(1) */
- EMRS= mct_MR1(pMCTstat, pDCTstat, dct, MrsChipSel << 20);
+ EMRS= mct_MR1(pMCTstat, pDCTstat, dct, MrsChipSel);
EMRS = swapAddrBits(pDCTstat, EMRS, MrsChipSel, dct);
mct_SendMrsCmd(pDCTstat, dct, EMRS);
/* 16.Send MRS with MrsAddress[8]=1(reset the DLL) */
- EMRS= mct_MR0(pMCTstat, pDCTstat, dct, MrsChipSel << 20);
+ EMRS= mct_MR0(pMCTstat, pDCTstat, dct, MrsChipSel);
EMRS = swapAddrBits(pDCTstat, EMRS, MrsChipSel, dct);
mct_SendMrsCmd(pDCTstat, dct, EMRS);
- if (pDCTstat->DIMMAutoSpeed == 4)
+ if (pDCTstat->DIMMAutoSpeed == mhz_to_memclk_config(mctGet_NVbits(NV_MIN_MEMCLK)))
if (!(pDCTstat->Status & (1 << SB_Registered)))
break; /* For UDIMM, only send MR commands once per channel */
}
@@ -310,16 +648,15 @@ void mct_DramInit_Sw_D(struct MCTStatStruc *pMCTstat,
MrsChipSel ++;
}
- mct_Wait(100000);
-
- if (pDCTstat->DIMMAutoSpeed == 4) {
+ if (pDCTstat->DIMMAutoSpeed == mhz_to_memclk_config(mctGet_NVbits(NV_MIN_MEMCLK))) {
/* 17.Send two ZQCL commands */
mct_SendZQCmd(pDCTstat, dct);
mct_SendZQCmd(pDCTstat, dct);
+
/* 18.Program F2x[1,0]7C[EnDramInit]=0 */
- dword = Get_NB32(dev, reg_off + 0x7C);
+ dword = Get_NB32_DCT(dev, dct, 0x7C);
dword &= ~(1 << EnDramInit);
- Set_NB32(dev, reg_off + 0x7C, dword);
+ Set_NB32_DCT(dev, dct, 0x7C, dword);
mct_DCTAccessDone(pDCTstat, dct);
}
}
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
index d2a82ce995..4397ebaccb 100644
--- a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
@@ -19,7 +19,10 @@
Description: Receiver En and DQS Timing Training feature for DDR 3 MCT
******************************************************************************/
-static void dqsTrainRcvrEn_SW(struct MCTStatStruc *pMCTstat,
+static int32_t abs(int32_t val);
+static void dqsTrainRcvrEn_SW_Fam10(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 Pass);
+static void dqsTrainRcvrEn_SW_Fam15(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat, u8 Pass);
static void mct_InitDQSPos4RcvrEn_D(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat);
@@ -28,7 +31,7 @@ static void InitDQSPos4RcvrEn_D(struct MCTStatStruc *pMCTstat,
static void CalcEccDQSRcvrEn_D(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat, u8 Channel);
static void mct_SetMaxLatency_D(struct DCTStatStruc *pDCTstat, u8 Channel, u16 DQSRcvEnDly);
-static void fenceDynTraining_D(struct MCTStatStruc *pMCTstat,
+static uint32_t fenceDynTraining_D(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat, u8 dct);
static void mct_DisableDQSRcvEn_D(struct DCTStatStruc *pDCTstat);
@@ -85,11 +88,154 @@ static void SetupRcvrPattern(struct MCTStatStruc *pMCTstat,
void mct_TrainRcvrEn_D(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat, u8 Pass)
{
- if(mct_checkNumberOfDqsRcvEn_1Pass(Pass))
- dqsTrainRcvrEn_SW(pMCTstat, pDCTstat, Pass);
+ if(mct_checkNumberOfDqsRcvEn_1Pass(Pass)) {
+ if (is_fam15h())
+ dqsTrainRcvrEn_SW_Fam15(pMCTstat, pDCTstat, Pass);
+ else
+ dqsTrainRcvrEn_SW_Fam10(pMCTstat, pDCTstat, Pass);
+ }
}
-static void read_dqs_write_timing_control_registers(uint16_t* current_total_delay, uint32_t dev, uint8_t dimm, uint32_t index_reg)
+static uint16_t fam15_receiver_enable_training_seed(struct DCTStatStruc *pDCTstat, uint8_t dct, uint8_t dimm, uint8_t rank, uint8_t package_type)
+{
+ uint32_t dword;
+ uint16_t seed = 0;
+
+ /* FIXME
+ * Mainboards need to be able to specify the maximum number of DIMMs installable per channel
+ * For now assume a maximum of 2 DIMMs per channel can be installed
+ */
+ uint8_t MaxDimmsInstallable = 2;
+
+ uint8_t channel = dct;
+ if (package_type == PT_GR) {
+ /* Get the internal node number */
+ dword = Get_NB32(pDCTstat->dev_nbmisc, 0xe8);
+ dword = (dword >> 30) & 0x3;
+ if (dword == 1) {
+ channel += 2;
+ }
+ }
+
+ if (pDCTstat->Status & (1 << SB_Registered)) {
+ if (package_type == PT_GR) {
+ /* Socket G34: Fam15h BKDG v3.14 Table 99 */
+ if (MaxDimmsInstallable == 1) {
+ if (channel == 0)
+ seed = 0x43;
+ else if (channel == 1)
+ seed = 0x3f;
+ else if (channel == 2)
+ seed = 0x3a;
+ else if (channel == 3)
+ seed = 0x35;
+ } else if (MaxDimmsInstallable == 2) {
+ if (channel == 0)
+ seed = 0x54;
+ else if (channel == 1)
+ seed = 0x4d;
+ else if (channel == 2)
+ seed = 0x45;
+ else if (channel == 3)
+ seed = 0x40;
+ } else if (MaxDimmsInstallable == 3) {
+ if (channel == 0)
+ seed = 0x6b;
+ else if (channel == 1)
+ seed = 0x5e;
+ else if (channel == 2)
+ seed = 0x4b;
+ else if (channel == 3)
+ seed = 0x3d;
+ }
+ } else if (package_type == PT_C3) {
+ /* Socket C32: Fam15h BKDG v3.14 Table 100 */
+ if ((MaxDimmsInstallable == 1) || (MaxDimmsInstallable == 2)) {
+ if (channel == 0)
+ seed = 0x3f;
+ else if (channel == 1)
+ seed = 0x3e;
+ } else if (MaxDimmsInstallable == 3) {
+ if (channel == 0)
+ seed = 0x47;
+ else if (channel == 1)
+ seed = 0x38;
+ }
+ }
+ } else if (pDCTstat->Status & (1 << SB_LoadReduced)) {
+ if (package_type == PT_GR) {
+ /* Socket G34: Fam15h BKDG v3.14 Table 99 */
+ if (MaxDimmsInstallable == 1) {
+ if (channel == 0)
+ seed = 0x123;
+ else if (channel == 1)
+ seed = 0x122;
+ else if (channel == 2)
+ seed = 0x112;
+ else if (channel == 3)
+ seed = 0x102;
+ }
+ } else if (package_type == PT_C3) {
+ /* Socket C32: Fam15h BKDG v3.14 Table 100 */
+ if (channel == 0)
+ seed = 0x132;
+ else if (channel == 1)
+ seed = 0x122;
+ }
+ } else {
+ if (package_type == PT_GR) {
+ /* Socket G34: Fam15h BKDG v3.14 Table 99 */
+ if (MaxDimmsInstallable == 1) {
+ if (channel == 0)
+ seed = 0x3e;
+ else if (channel == 1)
+ seed = 0x38;
+ else if (channel == 2)
+ seed = 0x37;
+ else if (channel == 3)
+ seed = 0x31;
+ } else if (MaxDimmsInstallable == 2) {
+ if (channel == 0)
+ seed = 0x51;
+ else if (channel == 1)
+ seed = 0x4a;
+ else if (channel == 2)
+ seed = 0x46;
+ else if (channel == 3)
+ seed = 0x3f;
+ } else if (MaxDimmsInstallable == 3) {
+ if (channel == 0)
+ seed = 0x5e;
+ else if (channel == 1)
+ seed = 0x52;
+ else if (channel == 2)
+ seed = 0x48;
+ else if (channel == 3)
+ seed = 0x3c;
+ }
+ } else if (package_type == PT_C3) {
+ /* Socket C32: Fam15h BKDG v3.14 Table 100 */
+ if ((MaxDimmsInstallable == 1) || (MaxDimmsInstallable == 2)) {
+ if (channel == 0)
+ seed = 0x39;
+ else if (channel == 1)
+ seed = 0x32;
+ } else if (MaxDimmsInstallable == 3) {
+ if (channel == 0)
+ seed = 0x45;
+ else if (channel == 1)
+ seed = 0x37;
+ }
+ } else if (package_type == PT_M2) {
+ /* Socket AM3: Fam15h BKDG v3.14 Table 101 */
+ seed = 0x3a;
+ }
+ }
+
+ return seed;
+}
+
+static void read_dqs_write_timing_control_registers(uint16_t* current_total_delay, uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t index_reg)
{
uint8_t lane;
uint32_t dword;
@@ -107,7 +253,7 @@ static void read_dqs_write_timing_control_registers(uint16_t* current_total_dela
if (lane == 8)
wdt_reg = 0x32;
wdt_reg += dimm * 3;
- dword = Get_NB32_index_wait(dev, index_reg, wdt_reg);
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, wdt_reg);
if ((lane == 7) || (lane == 5) || (lane == 3) || (lane == 1))
current_total_delay[lane] = (dword & 0x00ff0000) >> 16;
if ((lane == 8) || (lane == 6) || (lane == 4) || (lane == 2) || (lane == 0))
@@ -115,12 +261,124 @@ static void read_dqs_write_timing_control_registers(uint16_t* current_total_dela
}
}
-static void write_dqs_receiver_enable_control_registers(uint16_t* current_total_delay, uint32_t dev, uint8_t dimm, uint32_t index_reg)
+#ifdef UNUSED_CODE
+static void write_dqs_write_timing_control_registers(uint16_t* current_total_delay, uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t index_reg)
+{
+ uint8_t lane;
+ uint32_t dword;
+
+ for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
+ uint32_t ret_reg;
+ if ((lane == 0) || (lane == 1))
+ ret_reg = 0x30;
+ if ((lane == 2) || (lane == 3))
+ ret_reg = 0x31;
+ if ((lane == 4) || (lane == 5))
+ ret_reg = 0x40;
+ if ((lane == 6) || (lane == 7))
+ ret_reg = 0x41;
+ if (lane == 8)
+ ret_reg = 0x32;
+ ret_reg += dimm * 3;
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, ret_reg);
+ if ((lane == 7) || (lane == 5) || (lane == 3) || (lane == 1)) {
+ dword &= ~(0xff << 16);
+ dword |= (current_total_delay[lane] & 0xff) << 16;
+ }
+ if ((lane == 8) || (lane == 6) || (lane == 4) || (lane == 2) || (lane == 0)) {
+ dword &= ~0xff;
+ dword |= current_total_delay[lane] & 0xff;
+ }
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, ret_reg, dword);
+ }
+}
+#endif
+
+static void write_write_data_timing_control_registers(uint16_t* current_total_delay, uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t index_reg)
+{
+ uint8_t lane;
+ uint32_t dword;
+
+ for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
+ uint32_t wdt_reg;
+
+ /* Calculate Write Data Timing register location */
+ if ((lane == 0) || (lane == 1) || (lane == 2) || (lane == 3))
+ wdt_reg = 0x1;
+ if ((lane == 4) || (lane == 5) || (lane == 6) || (lane == 7))
+ wdt_reg = 0x2;
+ if (lane == 8)
+ wdt_reg = 0x3;
+ wdt_reg |= (dimm << 8);
+
+ /* Set Write Data Timing register values */
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, wdt_reg);
+ if ((lane == 7) || (lane == 3)) {
+ dword &= ~(0x7f << 24);
+ dword |= (current_total_delay[lane] & 0x7f) << 24;
+ }
+ if ((lane == 6) || (lane == 2)) {
+ dword &= ~(0x7f << 16);
+ dword |= (current_total_delay[lane] & 0x7f) << 16;
+ }
+ if ((lane == 5) || (lane == 1)) {
+ dword &= ~(0x7f << 8);
+ dword |= (current_total_delay[lane] & 0x7f) << 8;
+ }
+ if ((lane == 8) || (lane == 4) || (lane == 0)) {
+ dword &= ~0x7f;
+ dword |= current_total_delay[lane] & 0x7f;
+ }
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, wdt_reg, dword);
+ }
+}
+
+static void read_dqs_receiver_enable_control_registers(uint16_t* current_total_delay, uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t index_reg)
+{
+ uint8_t lane;
+ uint32_t mask;
+ uint32_t dword;
+
+ if (is_fam15h())
+ mask = 0x3ff;
+ else
+ mask = 0x1ff;
+
+ for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
+ uint32_t ret_reg;
+ if ((lane == 0) || (lane == 1))
+ ret_reg = 0x10;
+ if ((lane == 2) || (lane == 3))
+ ret_reg = 0x11;
+ if ((lane == 4) || (lane == 5))
+ ret_reg = 0x20;
+ if ((lane == 6) || (lane == 7))
+ ret_reg = 0x21;
+ if (lane == 8)
+ ret_reg = 0x12;
+ ret_reg += dimm * 3;
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, ret_reg);
+ if ((lane == 7) || (lane == 5) || (lane == 3) || (lane == 1)) {
+ current_total_delay[lane] = (dword & (mask << 16)) >> 16;
+ }
+ if ((lane == 8) || (lane == 6) || (lane == 4) || (lane == 2) || (lane == 0)) {
+ current_total_delay[lane] = dword & mask;
+ }
+ }
+}
+
+static void write_dqs_receiver_enable_control_registers(uint16_t* current_total_delay, uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t index_reg)
{
uint8_t lane;
+ uint32_t mask;
uint32_t dword;
- for (lane = 0; lane < 8; lane++) {
+ if (is_fam15h())
+ mask = 0x3ff;
+ else
+ mask = 0x1ff;
+
+ for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
uint32_t ret_reg;
if ((lane == 0) || (lane == 1))
ret_reg = 0x10;
@@ -130,17 +388,125 @@ static void write_dqs_receiver_enable_control_registers(uint16_t* current_total_
ret_reg = 0x20;
if ((lane == 6) || (lane == 7))
ret_reg = 0x21;
+ if (lane == 8)
+ ret_reg = 0x12;
ret_reg += dimm * 3;
- dword = Get_NB32_index_wait(dev, index_reg, ret_reg);
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, ret_reg);
if ((lane == 7) || (lane == 5) || (lane == 3) || (lane == 1)) {
- dword &= ~(0x1ff << 16);
- dword |= (current_total_delay[lane] & 0x1ff) << 16;
+ dword &= ~(mask << 16);
+ dword |= (current_total_delay[lane] & mask) << 16;
}
- if ((lane == 6) || (lane == 4) || (lane == 2) || (lane == 0)) {
- dword &= ~0x1ff;
- dword |= current_total_delay[lane] & 0x1ff;
+ if ((lane == 8) || (lane == 6) || (lane == 4) || (lane == 2) || (lane == 0)) {
+ dword &= ~mask;
+ dword |= current_total_delay[lane] & mask;
}
- Set_NB32_index_wait(dev, index_reg, ret_reg, dword);
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, ret_reg, dword);
+ }
+}
+
+static void read_dram_phase_recovery_control_registers(uint16_t* current_total_delay, uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t index_reg)
+{
+ uint8_t lane;
+ uint32_t dword;
+
+ for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
+ uint32_t prc_reg;
+
+ /* Calculate DRAM Phase Recovery Control register location */
+ if ((lane == 0) || (lane == 1) || (lane == 2) || (lane == 3))
+ prc_reg = 0x50;
+ if ((lane == 4) || (lane == 5) || (lane == 6) || (lane == 7))
+ prc_reg = 0x51;
+ if (lane == 8)
+ prc_reg = 0x52;
+
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, prc_reg);
+ if ((lane == 7) || (lane == 3)) {
+ current_total_delay[lane] = (dword >> 24) & 0x7f;
+ }
+ if ((lane == 6) || (lane == 2)) {
+ current_total_delay[lane] = (dword >> 16) & 0x7f;
+ }
+ if ((lane == 5) || (lane == 1)) {
+ current_total_delay[lane] = (dword >> 8) & 0x7f;
+ }
+ if ((lane == 8) || (lane == 4) || (lane == 0)) {
+ current_total_delay[lane] = dword & 0x7f;
+ }
+ }
+}
+
+static void write_dram_phase_recovery_control_registers(uint16_t* current_total_delay, uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t index_reg)
+{
+ uint8_t lane;
+ uint32_t dword;
+
+ for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
+ uint32_t prc_reg;
+
+ /* Calculate DRAM Phase Recovery Control register location */
+ if ((lane == 0) || (lane == 1) || (lane == 2) || (lane == 3))
+ prc_reg = 0x50;
+ if ((lane == 4) || (lane == 5) || (lane == 6) || (lane == 7))
+ prc_reg = 0x51;
+ if (lane == 8)
+ prc_reg = 0x52;
+
+ /* Set DRAM Phase Recovery Control register values */
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, prc_reg);
+ if ((lane == 7) || (lane == 3)) {
+ dword &= ~(0x7f << 24);
+ dword |= (current_total_delay[lane] & 0x7f) << 24;
+ }
+ if ((lane == 6) || (lane == 2)) {
+ dword &= ~(0x7f << 16);
+ dword |= (current_total_delay[lane] & 0x7f) << 16;
+ }
+ if ((lane == 5) || (lane == 1)) {
+ dword &= ~(0x7f << 8);
+ dword |= (current_total_delay[lane] & 0x7f) << 8;
+ }
+ if ((lane == 8) || (lane == 4) || (lane == 0)) {
+ dword &= ~0x7f;
+ dword |= current_total_delay[lane] & 0x7f;
+ }
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, prc_reg, dword);
+ }
+}
+
+static void read_read_dqs_timing_control_registers(uint16_t* current_total_delay, uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t index_reg)
+{
+ uint8_t lane;
+ uint32_t dword;
+
+ for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
+ uint32_t rdt_reg;
+
+ /* Calculate DRAM Read DQS Timing register location */
+ if ((lane == 0) || (lane == 1) || (lane == 2) || (lane == 3))
+ rdt_reg = 0x5;
+ if ((lane == 4) || (lane == 5) || (lane == 6) || (lane == 7))
+ rdt_reg = 0x6;
+ if (lane == 8)
+ rdt_reg = 0x7;
+ rdt_reg |= (dimm << 8);
+
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, rdt_reg);
+ if ((lane == 7) || (lane == 3)) {
+ current_total_delay[lane] = (dword >> 24) & 0x3f;
+ }
+ if ((lane == 6) || (lane == 2)) {
+ current_total_delay[lane] = (dword >> 16) & 0x3f;
+ }
+ if ((lane == 5) || (lane == 1)) {
+ current_total_delay[lane] = (dword >> 8) & 0x3f;
+ }
+ if ((lane == 8) || (lane == 4) || (lane == 0)) {
+ current_total_delay[lane] = dword & 0x3f;
+ }
+
+ if (is_fam15h())
+ current_total_delay[lane] >>= 1;
}
}
@@ -156,10 +522,11 @@ static uint32_t convert_testaddr_and_channel_to_address(struct DCTStatStruc *pDC
return testaddr;
}
-/* DQS Receiver Enable Training
- * Algorithm detailed in the Fam10h BKDG Rev. 3.62 section 2.8.9.9.2
+/* DQS Receiver Enable Training (Family 10h)
+ * Algorithm detailed in:
+ * The Fam10h BKDG Rev. 3.62 section 2.8.9.9.2
*/
-static void dqsTrainRcvrEn_SW(struct MCTStatStruc *pMCTstat,
+static void dqsTrainRcvrEn_SW_Fam10(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat, u8 Pass)
{
u8 Channel;
@@ -167,7 +534,6 @@ static void dqsTrainRcvrEn_SW(struct MCTStatStruc *pMCTstat,
u8 Addl_Index = 0;
u8 Receiver;
u8 _DisableDramECC = 0, _Wrap32Dis = 0, _SSE2 = 0;
- u8 Final_Value;
u16 CTLRMaxDelay;
u16 MaxDelay_CH[2];
u32 TestAddr0, TestAddr1, TestAddr0B, TestAddr1B;
@@ -184,6 +550,7 @@ static void dqsTrainRcvrEn_SW(struct MCTStatStruc *pMCTstat,
u32 lo, hi;
uint32_t dword;
+ uint8_t dimm;
uint8_t rank;
uint8_t lane;
uint16_t current_total_delay[MAX_BYTE_LANES];
@@ -210,14 +577,13 @@ static void dqsTrainRcvrEn_SW(struct MCTStatStruc *pMCTstat,
}
for (ch = ch_start; ch < ch_end; ch++) {
- reg = 0x78 + (0x100 * ch);
- val = Get_NB32(dev, reg);
+ reg = 0x78;
+ val = Get_NB32_DCT(dev, ch, reg);
val &= ~(0x3ff << 22);
- val |= (0x0c8 << 22); /* Max Rd Lat */
- Set_NB32(dev, reg, val);
+ val |= (0x0c8 << 22); /* MaxRdLatency = 0xc8 */
+ Set_NB32_DCT(dev, ch, reg, val);
}
- Final_Value = 1;
if (Pass == FirstPass) {
mct_InitDQSPos4RcvrEn_D(pMCTstat, pDCTstat);
} else {
@@ -256,7 +622,7 @@ static void dqsTrainRcvrEn_SW(struct MCTStatStruc *pMCTstat,
CTLRMaxDelay = 0;
MaxDelay_CH[Channel] = 0;
- index_reg = 0x98 + 0x100 * Channel;
+ index_reg = 0x98;
Receiver = mct_InitReceiver_D(pDCTstat, Channel);
/* There are four receiver pairs, loosely associated with chipselects.
@@ -264,6 +630,7 @@ static void dqsTrainRcvrEn_SW(struct MCTStatStruc *pMCTstat,
*/
for (; Receiver < 8; Receiver += 2) {
Addl_Index = (Receiver >> 1) * 3 + 0x10;
+ dimm = (Receiver >> 1);
print_debug_dqs("\t\tTrainRcvEnd52: index ", Addl_Index, 2);
@@ -280,45 +647,14 @@ static void dqsTrainRcvrEn_SW(struct MCTStatStruc *pMCTstat,
/* 2.8.9.9.2 (1, 6)
* Retrieve gross and fine timing fields from write DQS registers
*/
- read_dqs_write_timing_control_registers(current_total_delay, dev, (Receiver >> 1), index_reg);
+ read_dqs_write_timing_control_registers(current_total_delay, dev, Channel, dimm, index_reg);
/* 2.8.9.9.2 (1)
* Program the Write Data Timing and Write ECC Timing register to
* the values stored in the DQS Write Timing Control register
* for each lane
*/
- for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
- uint32_t wdt_reg;
-
- /* Calculate Write Data Timing register location */
- if ((lane == 0) || (lane == 1) || (lane == 2) || (lane == 3))
- wdt_reg = 0x1;
- if ((lane == 4) || (lane == 5) || (lane == 6) || (lane == 7))
- wdt_reg = 0x2;
- if (lane == 8)
- wdt_reg = 0x3;
- wdt_reg |= ((Receiver / 2) << 8);
-
- /* Set Write Data Timing register values */
- dword = Get_NB32_index_wait(dev, index_reg, wdt_reg);
- if ((lane == 7) || (lane == 3)) {
- dword &= ~(0x7f << 24);
- dword |= (current_total_delay[lane] & 0x7f) << 24;
- }
- if ((lane == 6) || (lane == 2)) {
- dword &= ~(0x7f << 16);
- dword |= (current_total_delay[lane] & 0x7f) << 16;
- }
- if ((lane == 5) || (lane == 1)) {
- dword &= ~(0x7f << 8);
- dword |= (current_total_delay[lane] & 0x7f) << 8;
- }
- if ((lane == 8) || (lane == 4) || (lane == 0)) {
- dword &= ~0x7f;
- dword |= current_total_delay[lane] & 0x7f;
- }
- Set_NB32_index_wait(dev, index_reg, wdt_reg, dword);
- }
+ write_write_data_timing_control_registers(current_total_delay, dev, Channel, dimm, index_reg);
/* 2.8.9.9.2 (2)
* Program the Read DQS Timing Control and the Read DQS ECC Timing Control registers
@@ -332,12 +668,12 @@ static void dqsTrainRcvrEn_SW(struct MCTStatStruc *pMCTstat,
rdt_reg = 0x6;
if (lane == 8)
rdt_reg = 0x7;
- rdt_reg |= ((Receiver / 2) << 8);
+ rdt_reg |= (dimm << 8);
if (lane == 8)
dword = 0x0000003f;
else
dword = 0x3f3f3f3f;
- Set_NB32_index_wait(dev, index_reg, rdt_reg, dword);
+ Set_NB32_index_wait_DCT(dev, Channel, index_reg, rdt_reg, dword);
}
/* 2.8.9.9.2 (3)
@@ -367,7 +703,7 @@ static void dqsTrainRcvrEn_SW(struct MCTStatStruc *pMCTstat,
print_debug_dqs("\t\tTrainRcvEn53: TestAddr1B ", TestAddr1B, 2);
/* 2.8.9.9.2 (4, 5)
- * Write 1 cache line of the appropriate test pattern to each test addresse
+ * Write 1 cache line of the appropriate test pattern to each test address
*/
mct_Write1LTestPattern_D(pMCTstat, pDCTstat, TestAddr0, 0); /* rank 0 of DIMM, testpattern 0 */
mct_Write1LTestPattern_D(pMCTstat, pDCTstat, TestAddr0B, 1); /* rank 0 of DIMM, testpattern 1 */
@@ -386,7 +722,7 @@ static void dqsTrainRcvrEn_SW(struct MCTStatStruc *pMCTstat,
/* 2.8.9.9.2 (6)
* Write gross and fine timing fields to read DQS registers
*/
- write_dqs_receiver_enable_control_registers(current_total_delay, dev, (Receiver >> 1), index_reg);
+ write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, dimm, index_reg);
/* 2.8.9.9.2 (7)
* Loop over all delay values up to 1 MEMCLK (0x40 delay steps) from the initial delay values
@@ -413,8 +749,8 @@ static void dqsTrainRcvrEn_SW(struct MCTStatStruc *pMCTstat,
break;
/* 2.8.9.9.2 (7 A)
- * Loop over all ranks
- */
+ * Loop over all ranks
+ */
for (rank = 0; rank < (_2Ranks + 1); rank++) {
/* 2.8.9.9.2 (7 A a-d)
* Read the first test address of the current rank
@@ -430,17 +766,17 @@ static void dqsTrainRcvrEn_SW(struct MCTStatStruc *pMCTstat,
*/
proc_IOCLFLUSH_D((rank == 0)?TestAddr0B:TestAddr1B);
result_qword2 = read64_fs(convert_testaddr_and_channel_to_address(pDCTstat, (rank == 0)?TestAddr0B:TestAddr1B, Channel));
- write_dqs_receiver_enable_control_registers(current_total_delay, dev, (Receiver >> 1), index_reg);
+ write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, dimm, index_reg);
proc_IOCLFLUSH_D((rank == 0)?TestAddr0:TestAddr1);
result_qword1 = read64_fs(convert_testaddr_and_channel_to_address(pDCTstat, (rank == 0)?TestAddr0:TestAddr1, Channel));
- write_dqs_receiver_enable_control_registers(current_total_delay, dev, (Receiver >> 1), index_reg);
+ write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, dimm, index_reg);
} else {
proc_IOCLFLUSH_D((rank == 0)?TestAddr0:TestAddr1);
result_qword1 = read64_fs(convert_testaddr_and_channel_to_address(pDCTstat, (rank == 0)?TestAddr0:TestAddr1, Channel));
- write_dqs_receiver_enable_control_registers(current_total_delay, dev, (Receiver >> 1), index_reg);
+ write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, dimm, index_reg);
proc_IOCLFLUSH_D((rank == 0)?TestAddr0B:TestAddr1B);
result_qword2 = read64_fs(convert_testaddr_and_channel_to_address(pDCTstat, (rank == 0)?TestAddr0B:TestAddr1B, Channel));
- write_dqs_receiver_enable_control_registers(current_total_delay, dev, (Receiver >> 1), index_reg);
+ write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, dimm, index_reg);
}
/* 2.8.9.9.2 (7 A e)
* Compare both read patterns and flag passing ranks/lanes
@@ -529,7 +865,7 @@ static void dqsTrainRcvrEn_SW(struct MCTStatStruc *pMCTstat,
}
/* Update delays in hardware */
- write_dqs_receiver_enable_control_registers(current_total_delay, dev, (Receiver >> 1), index_reg);
+ write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, dimm, index_reg);
/* Save previous results for comparison in the next iteration */
for (lane = 0; lane < 8; lane++)
@@ -583,7 +919,483 @@ static void dqsTrainRcvrEn_SW(struct MCTStatStruc *pMCTstat,
mct_SetMaxLatency_D(pDCTstat, Channel, CTLRMaxDelay); /* program Ch A/B MaxAsyncLat to correspond with max delay */
}
- ResetDCTWrPtr_D(dev, index_reg, Addl_Index);
+ for (Channel = 0; Channel < 2; Channel++) {
+ ResetDCTWrPtr_D(dev, Channel, index_reg, Addl_Index);
+ }
+
+ if(_DisableDramECC) {
+ mct_EnableDimmEccEn_D(pMCTstat, pDCTstat, _DisableDramECC);
+ }
+
+ if (Pass == FirstPass) {
+ /*Disable DQSRcvrEn training mode */
+ mct_DisableDQSRcvEn_D(pDCTstat);
+ }
+
+ if(!_Wrap32Dis) {
+ msr = HWCR;
+ _RDMSR(msr, &lo, &hi);
+ lo &= ~(1<<17); /* restore HWCR.wrap32dis */
+ _WRMSR(msr, lo, hi);
+ }
+ if(!_SSE2){
+ cr4 = read_cr4();
+ cr4 &= ~(1<<9); /* restore cr4.OSFXSR */
+ write_cr4(cr4);
+ }
+
+#if DQS_TRAIN_DEBUG > 0
+ {
+ u8 ChannelDTD;
+ printk(BIOS_DEBUG, "TrainRcvrEn: CH_MaxRdLat:\n");
+ for(ChannelDTD = 0; ChannelDTD<2; ChannelDTD++) {
+ printk(BIOS_DEBUG, "Channel:%x: %x\n",
+ ChannelDTD, pDCTstat->CH_MaxRdLat[ChannelDTD]);
+ }
+ }
+#endif
+
+#if DQS_TRAIN_DEBUG > 0
+ {
+ u16 valDTD;
+ u8 ChannelDTD, ReceiverDTD;
+ u8 i;
+ u16 *p;
+
+ printk(BIOS_DEBUG, "TrainRcvrEn: CH_D_B_RCVRDLY:\n");
+ for(ChannelDTD = 0; ChannelDTD < 2; ChannelDTD++) {
+ printk(BIOS_DEBUG, "Channel:%x\n", ChannelDTD);
+ for(ReceiverDTD = 0; ReceiverDTD<8; ReceiverDTD+=2) {
+ printk(BIOS_DEBUG, "\t\tReceiver:%x:", ReceiverDTD);
+ p = pDCTstat->CH_D_B_RCVRDLY[ChannelDTD][ReceiverDTD>>1];
+ for (i=0;i<8; i++) {
+ valDTD = p[i];
+ printk(BIOS_DEBUG, " %03x", valDTD);
+ }
+ printk(BIOS_DEBUG, "\n");
+ }
+ }
+ }
+#endif
+
+ printk(BIOS_DEBUG, "TrainRcvrEn: Status %x\n", pDCTstat->Status);
+ printk(BIOS_DEBUG, "TrainRcvrEn: ErrStatus %x\n", pDCTstat->ErrStatus);
+ printk(BIOS_DEBUG, "TrainRcvrEn: ErrCode %x\n", pDCTstat->ErrCode);
+ printk(BIOS_DEBUG, "TrainRcvrEn: Done\n\n");
+}
+
+/* DQS Receiver Enable Training Pattern Generation (Family 15h)
+ * Algorithm detailed in:
+ * The Fam15h BKDG Rev. 3.14 section 2.10.5.8.2 (4)
+ */
+static void generate_dram_receiver_enable_training_pattern_fam15(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, uint8_t dct, uint8_t Receiver)
+{
+ uint32_t dword;
+ uint32_t dev = pDCTstat->dev_dct;
+
+ /* 2.10.5.7.1.1
+ * It appears that the DCT only supports 8-beat burst length mode,
+ * so do nothing here...
+ */
+
+ /* Wait for CmdSendInProg == 0 */
+ do {
+ dword = Get_NB32_DCT(dev, dct, 0x250);
+ } while (dword & (0x1 << 12));
+
+ /* Set CmdTestEnable = 1 */
+ dword = Get_NB32_DCT(dev, dct, 0x250);
+ dword |= (0x1 << 2);
+ Set_NB32_DCT(dev, dct, 0x250, dword);
+
+ /* 2.10.5.8.6.1.1 Send Activate Command */
+ dword = Get_NB32_DCT(dev, dct, 0x28c);
+ dword &= ~(0xff << 22); /* CmdChipSelect = Receiver */
+ dword |= ((0x1 << Receiver) << 22);
+ dword &= ~(0x7 << 19); /* CmdBank = 0 */
+ dword &= ~(0x3ffff); /* CmdAddress = 0 */
+ dword |= (0x1 << 31); /* SendActCmd = 1 */
+ Set_NB32_DCT(dev, dct, 0x28c, dword);
+
+ /* Wait for SendActCmd == 0 */
+ do {
+ dword = Get_NB32_DCT(dev, dct, 0x28c);
+ } while (dword & (0x1 << 31));
+
+ /* Wait 75 MEMCLKs. */
+ precise_memclk_delay_fam15(pMCTstat, pDCTstat, dct, 75);
+
+ /* 2.10.5.8.6.1.2 */
+ Set_NB32_DCT(dev, dct, 0x274, 0x0); /* DQMask = 0 */
+ Set_NB32_DCT(dev, dct, 0x278, 0x0);
+
+ dword = Get_NB32_DCT(dev, dct, 0x27c);
+ dword &= ~(0xff); /* EccMask = 0 */
+ if (pDCTstat->DimmECCPresent == 0)
+ dword |= 0xff; /* EccMask = 0xff */
+ Set_NB32_DCT(dev, dct, 0x27c, dword);
+
+ /* 2.10.5.8.6.1.2 */
+ dword = Get_NB32_DCT(dev, dct, 0x270);
+ dword &= ~(0x7ffff); /* DataPrbsSeed = 55555 */
+// dword |= (0x55555);
+ dword |= (0x44443); /* Use AGESA seed */
+ Set_NB32_DCT(dev, dct, 0x270, dword);
+
+ /* 2.10.5.8.2 (4) */
+ dword = Get_NB32_DCT(dev, dct, 0x260);
+ dword &= ~(0x1fffff); /* CmdCount = 192 */
+ dword |= 192;
+ Set_NB32_DCT(dev, dct, 0x260, dword);
+
+#if 0
+ /* TODO: This applies to Fam15h model 10h and above only */
+ /* Program Bubble Count and CmdStreamLen */
+ dword = Get_NB32_DCT(dev, dct, 0x25c);
+ dword &= ~(0x3ff << 12); /* BubbleCnt = 0 */
+ dword &= ~(0x3ff << 22); /* BubbleCnt2 = 0 */
+ dword &= ~(0xff); /* CmdStreamLen = 1 */
+ dword |= 0x1;
+ Set_NB32_DCT(dev, dct, 0x25c, dword);
+#endif
+
+ /* Configure Target A */
+ dword = Get_NB32_DCT(dev, dct, 0x254);
+ dword &= ~(0x7 << 24); /* TgtChipSelect = Receiver */
+ dword |= (Receiver & 0x7) << 24;
+ dword &= ~(0x7 << 21); /* TgtBank = 0 */
+ dword &= ~(0x3ff); /* TgtAddress = 0 */
+ Set_NB32_DCT(dev, dct, 0x254, dword);
+
+ dword = Get_NB32_DCT(dev, dct, 0x250);
+ dword |= (0x1 << 3); /* ResetAllErr = 1 */
+ dword &= ~(0x1 << 4); /* StopOnErr = 0 */
+ dword &= ~(0x3 << 8); /* CmdTgt = 0 (Target A) */
+ dword &= ~(0x7 << 5); /* CmdType = 0 (Read) */
+ dword |= (0x1 << 11); /* SendCmd = 1 */
+ Set_NB32_DCT(dev, dct, 0x250, dword);
+
+ /* 2.10.5.8.6.1.2 Wait for TestStatus == 1 and CmdSendInProg == 0 */
+ do {
+ dword = Get_NB32_DCT(dev, dct, 0x250);
+ } while ((dword & (0x1 << 12)) || (!(dword & (0x1 << 10))));
+
+ dword = Get_NB32_DCT(dev, dct, 0x250);
+ dword &= ~(0x1 << 11); /* SendCmd = 0 */
+ Set_NB32_DCT(dev, dct, 0x250, dword);
+
+ /* 2.10.5.8.6.1.1 Send Precharge Command */
+ /* Wait 25 MEMCLKs. */
+ precise_memclk_delay_fam15(pMCTstat, pDCTstat, dct, 25);
+
+ dword = Get_NB32_DCT(dev, dct, 0x28c);
+ dword &= ~(0xff << 22); /* CmdChipSelect = Receiver */
+ dword |= ((0x1 << Receiver) << 22);
+ dword &= ~(0x7 << 19); /* CmdBank = 0 */
+ dword &= ~(0x3ffff); /* CmdAddress = 0x400 */
+ dword |= 0x400;
+ dword |= (0x1 << 30); /* SendPchgCmd = 1 */
+ Set_NB32_DCT(dev, dct, 0x28c, dword);
+
+ /* Wait for SendPchgCmd == 0 */
+ do {
+ dword = Get_NB32_DCT(dev, dct, 0x28c);
+ } while (dword & (0x1 << 30));
+
+ /* Wait 25 MEMCLKs. */
+ precise_memclk_delay_fam15(pMCTstat, pDCTstat, dct, 25);
+
+ /* Set CmdTestEnable = 0 */
+ dword = Get_NB32_DCT(dev, dct, 0x250);
+ dword &= ~(0x1 << 2);
+ Set_NB32_DCT(dev, dct, 0x250, dword);
+}
+
+/* DQS Receiver Enable Training (Family 15h)
+ * Algorithm detailed in:
+ * The Fam15h BKDG Rev. 3.14 section 2.10.5.8.2
+ * This algorithm runs once at the lowest supported MEMCLK,
+ * then once again at the highest supported MEMCLK.
+ */
+static void dqsTrainRcvrEn_SW_Fam15(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 Pass)
+{
+ u8 Channel;
+ u8 _2Ranks;
+ u8 Addl_Index = 0;
+ u8 Receiver;
+ u8 _DisableDramECC = 0, _Wrap32Dis = 0, _SSE2 = 0;
+ u32 Errors;
+
+ u32 val;
+ u32 dev;
+ u32 index_reg;
+ u32 ch_start, ch_end, ch;
+ u32 msr;
+ u32 cr4;
+ u32 lo, hi;
+
+ uint32_t dword;
+ uint8_t dimm;
+ uint8_t rank;
+ uint8_t lane;
+ uint8_t mem_clk;
+ uint16_t initial_seed;
+ uint16_t current_total_delay[MAX_BYTE_LANES];
+ uint16_t dqs_ret_pass1_total_delay[MAX_BYTE_LANES];
+ uint16_t rank0_current_total_delay[MAX_BYTE_LANES];
+ uint16_t phase_recovery_delays[MAX_BYTE_LANES];
+ uint16_t seed[MAX_BYTE_LANES];
+ uint16_t seed_gross[MAX_BYTE_LANES];
+ uint16_t seed_fine[MAX_BYTE_LANES];
+ uint16_t seed_pre_gross[MAX_BYTE_LANES];
+
+ uint8_t package_type = mctGet_NVbits(NV_PACK_TYPE);
+ uint16_t fam15h_freq_tab[] = {0, 0, 0, 0, 333, 0, 400, 0, 0, 0, 533, 0, 0, 0, 667, 0, 0, 0, 800, 0, 0, 0, 933};
+
+ print_debug_dqs("\nTrainRcvEn: Node", pDCTstat->Node_ID, 0);
+ print_debug_dqs("TrainRcvEn: Pass", Pass, 0);
+
+ dev = pDCTstat->dev_dct;
+ index_reg = 0x98;
+ ch_start = 0;
+ ch_end = 2;
+
+ for (ch = ch_start; ch < ch_end; ch++) {
+ uint8_t max_rd_latency = 0x55;
+ uint8_t p_state;
+
+ /* 2.10.5.6 */
+ fam15EnableTrainingMode(pMCTstat, pDCTstat, ch, 1);
+
+ /* 2.10.5.2 */
+ for (p_state = 0; p_state < 3; p_state++) {
+ val = Get_NB32_DCT_NBPstate(dev, ch, p_state, 0x210);
+ val &= ~(0x3ff << 22); /* MaxRdLatency = max_rd_latency */
+ val |= (max_rd_latency & 0x3ff) << 22;
+ Set_NB32_DCT_NBPstate(dev, ch, p_state, 0x210, val);
+ }
+ }
+
+ if (Pass != FirstPass) {
+ pDCTstat->DimmTrainFail = 0;
+ pDCTstat->CSTrainFail = ~pDCTstat->CSPresent;
+ }
+
+ cr4 = read_cr4();
+ if(cr4 & ( 1 << 9)) { /* save the old value */
+ _SSE2 = 1;
+ }
+ cr4 |= (1 << 9); /* OSFXSR enable SSE2 */
+ write_cr4(cr4);
+
+ msr = HWCR;
+ _RDMSR(msr, &lo, &hi);
+ /* FIXME: Why use SSEDIS */
+ if(lo & (1 << 17)) { /* save the old value */
+ _Wrap32Dis = 1;
+ }
+ lo |= (1 << 17); /* HWCR.wrap32dis */
+ lo &= ~(1 << 15); /* SSEDIS */
+ _WRMSR(msr, lo, hi); /* Setting wrap32dis allows 64-bit memory references in real mode */
+
+ _DisableDramECC = mct_DisableDimmEccEn_D(pMCTstat, pDCTstat);
+
+ Errors = 0;
+ dev = pDCTstat->dev_dct;
+
+ for (Channel = 0; Channel < 2; Channel++) {
+ print_debug_dqs("\tTrainRcvEn51: Node ", pDCTstat->Node_ID, 1);
+ print_debug_dqs("\tTrainRcvEn51: Channel ", Channel, 1);
+ pDCTstat->Channel = Channel;
+
+ mem_clk = Get_NB32_DCT(dev, Channel, 0x94) & 0x1f;
+
+ Receiver = mct_InitReceiver_D(pDCTstat, Channel);
+ /* There are four receiver pairs, loosely associated with chipselects.
+ * This is essentially looping over each DIMM.
+ */
+ for (; Receiver < 8; Receiver += 2) {
+ Addl_Index = (Receiver >> 1) * 3 + 0x10;
+ dimm = (Receiver >> 1);
+
+ print_debug_dqs("\t\tTrainRcvEnd52: index ", Addl_Index, 2);
+
+ if (!mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, Channel, Receiver)) {
+ continue;
+ }
+
+ /* Retrieve the total delay values from pass 1 of DQS receiver enable training */
+ if (Pass != FirstPass) {
+ read_dqs_receiver_enable_control_registers(dqs_ret_pass1_total_delay, dev, Channel, dimm, index_reg);
+ }
+
+ /* 2.10.5.8.2
+ * Loop over all ranks
+ */
+ if (mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, Channel, Receiver+1))
+ _2Ranks = 1;
+ else
+ _2Ranks = 0;
+ for (rank = 0; rank < (_2Ranks + 1); rank++) {
+ /* 2.10.5.8.2 (1)
+ * Specify the target DIMM to be trained
+ * Set TrNibbleSel = 0
+ *
+ * TODO: Add support for x4 DIMMs
+ */
+ dword = Get_NB32_index_wait_DCT(dev, Channel, index_reg, 0x00000008);
+ dword &= ~(0x3 << 4); /* TrDimmSel */
+ dword |= ((dimm & 0x3) << 4);
+ dword &= ~(0x1 << 2); /* TrNibbleSel */
+ Set_NB32_index_wait_DCT(dev, Channel, index_reg, 0x00000008, dword);
+
+ /* 2.10.5.8.2 (2)
+ * Retrieve gross and fine timing fields from write DQS registers
+ */
+ read_dqs_write_timing_control_registers(current_total_delay, dev, Channel, dimm, index_reg);
+
+ /* 2.10.5.8.2.1
+ * Generate the DQS Receiver Enable Training Seed Values
+ */
+ if (Pass == FirstPass) {
+ initial_seed = fam15_receiver_enable_training_seed(pDCTstat, Channel, dimm, rank, package_type);
+
+ /* Adjust seed for the minimum platform supported frequency */
+ initial_seed = (uint16_t) (((((uint64_t) initial_seed) *
+ fam15h_freq_tab[mem_clk] * 100) / (mctGet_NVbits(NV_MIN_MEMCLK) * 100)));
+
+ for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
+ uint16_t wl_pass1_delay;
+ wl_pass1_delay = current_total_delay[lane];
+
+ seed[lane] = initial_seed + wl_pass1_delay;
+ }
+ } else {
+ uint8_t addr_prelaunch = 0; /* TODO: Fetch the correct value from RC2[0] */
+ uint16_t register_delay;
+ int16_t seed_prescaling;
+
+ memcpy(current_total_delay, dqs_ret_pass1_total_delay, sizeof(current_total_delay));
+ if ((pDCTstat->Status & (1 << SB_Registered))) {
+ if (addr_prelaunch)
+ register_delay = 0x30;
+ else
+ register_delay = 0x20;
+ } else if ((pDCTstat->Status & (1 << SB_LoadReduced))) {
+ /* TODO
+ * Load reduced DIMM support unimplemented
+ */
+ register_delay = 0x0;
+ } else {
+ register_delay = 0x0;
+ }
+
+ for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
+ seed_prescaling = current_total_delay[lane] - register_delay - 0x20;
+ seed[lane] = (uint16_t) (register_delay + ((((uint64_t) seed_prescaling) * fam15h_freq_tab[mem_clk] * 100) / (mctGet_NVbits(NV_MIN_MEMCLK) * 100)));
+ }
+ }
+
+ for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
+ seed_gross[lane] = (seed[lane] >> 5) & 0x1f;
+ seed_fine[lane] = seed[lane] & 0x1f;
+
+ /*if (seed_gross[lane] == 0)
+ seed_pre_gross[lane] = 0;
+ else */if (seed_gross[lane] & 0x1)
+ seed_pre_gross[lane] = 1;
+ else
+ seed_pre_gross[lane] = 2;
+
+ /* Calculate phase recovery delays */
+ phase_recovery_delays[lane] = ((seed_pre_gross[lane] & 0x1f) << 5) | (seed_fine[lane] & 0x1f);
+
+ /* Set the gross delay.
+ * NOTE: While the BKDG states to only program DqsRcvEnGrossDelay, this appears
+ * to have been a misprint as DqsRcvEnFineDelay should be set to zero as well.
+ */
+ current_total_delay[lane] = ((seed_gross[lane] & 0x1f) << 5);
+ }
+
+ /* 2.10.5.8.2 (2) / 2.10.5.8.2.1 (5 6)
+ * Program PhRecFineDly and PhRecGrossDly
+ */
+ write_dram_phase_recovery_control_registers(phase_recovery_delays, dev, Channel, dimm, index_reg);
+
+ /* 2.10.5.8.2 (2) / 2.10.5.8.2.1 (7)
+ * Program the DQS Receiver Enable delay values for each lane
+ */
+ write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, dimm, index_reg);
+
+ /* 2.10.5.8.2 (3)
+ * Program DqsRcvTrEn = 1
+ */
+ dword = Get_NB32_index_wait_DCT(dev, Channel, index_reg, 0x00000008);
+ dword |= (0x1 << 13);
+ Set_NB32_index_wait_DCT(dev, Channel, index_reg, 0x00000008, dword);
+
+ /* 2.10.5.8.2 (4)
+ * Issue 192 read requests to the target rank
+ */
+ generate_dram_receiver_enable_training_pattern_fam15(pMCTstat, pDCTstat, Channel, Receiver + (rank & 0x1));
+
+ /* 2.10.5.8.2 (5)
+ * Program DqsRcvTrEn = 0
+ */
+ dword = Get_NB32_index_wait_DCT(dev, Channel, index_reg, 0x00000008);
+ dword &= ~(0x1 << 13);
+ Set_NB32_index_wait_DCT(dev, Channel, index_reg, 0x00000008, dword);
+
+ /* 2.10.5.8.2 (6)
+ * Read PhRecGrossDly, PhRecFineDly
+ */
+ read_dram_phase_recovery_control_registers(phase_recovery_delays, dev, Channel, dimm, index_reg);
+
+ /* 2.10.5.8.2 (7)
+ * Calculate and program the DQS Receiver Enable delay values
+ */
+ for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
+ current_total_delay[lane] = (phase_recovery_delays[lane] & 0x1f);
+ current_total_delay[lane] |= ((seed_gross[lane] + ((phase_recovery_delays[lane] >> 5) & 0x1f) - seed_pre_gross[lane] + 1) << 5);
+ if (lane == 8)
+ pDCTstat->CH_D_BC_RCVRDLY[Channel][dimm] = current_total_delay[lane];
+ else
+ pDCTstat->CH_D_B_RCVRDLY[Channel][dimm][lane] = current_total_delay[lane];
+ }
+ write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, dimm, index_reg);
+
+ if (rank == 0) {
+ /* Back up the Rank 0 delays for later use */
+ memcpy(rank0_current_total_delay, current_total_delay, sizeof(current_total_delay));
+ }
+
+ if (rank == 1) {
+ /* 2.10.5.8.2 (8)
+ * Compute the average delay across both ranks and program the result into
+ * the DQS Receiver Enable delay registers
+ */
+ for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
+ current_total_delay[lane] = (rank0_current_total_delay[lane] + current_total_delay[lane]) / 2;
+ if (lane == 8)
+ pDCTstat->CH_D_BC_RCVRDLY[Channel][dimm] = current_total_delay[lane];
+ else
+ pDCTstat->CH_D_B_RCVRDLY[Channel][dimm][lane] = current_total_delay[lane];
+ }
+ write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, dimm, index_reg);
+ }
+ }
+
+#if DQS_TRAIN_DEBUG > 0
+ for (lane = 0; lane < 8; lane++)
+ print_debug_dqs_pair("\t\tTrainRcvEn55: Lane ", lane, " current_total_delay ", current_total_delay[lane], 2);
+#endif
+ }
+ }
+
+ /* Calculate and program MaxRdLatency */
+ Calc_SetMaxRdLatency_D_Fam15(pMCTstat, pDCTstat, Channel);
if(_DisableDramECC) {
mct_EnableDimmEccEn_D(pMCTstat, pDCTstat, _DisableDramECC);
@@ -670,10 +1482,10 @@ static void mct_DisableDQSRcvEn_D(struct DCTStatStruc *pDCTstat)
}
for (ch=0; ch<ch_end; ch++) {
- reg = 0x78 + 0x100 * ch;
- val = Get_NB32(dev, reg);
+ reg = 0x78;
+ val = Get_NB32_DCT(dev, ch, reg);
val &= ~(1 << DqsRcvEnTrain);
- Set_NB32(dev, reg, val);
+ Set_NB32_DCT(dev, ch, reg, val);
}
}
@@ -714,7 +1526,7 @@ void mct_SetRcvrEnDly_D(struct DCTStatStruc *pDCTstat, u16 RcvrEnDly,
/* get the register index from table */
index = Table_DQSRcvEn_Offset[i >> 1];
index += Addl_Index; /* DIMMx DqsRcvEn byte0 */
- val = Get_NB32_index_wait(dev, index_reg, index);
+ val = Get_NB32_index_wait_DCT(dev, Channel, index_reg, index);
if(i & 1) {
/* odd byte lane */
val &= ~(0x1ff << 16);
@@ -724,7 +1536,7 @@ void mct_SetRcvrEnDly_D(struct DCTStatStruc *pDCTstat, u16 RcvrEnDly,
val &= ~0x1ff;
val |= (RcvrEnDly & 0x1ff);
}
- Set_NB32_index_wait(dev, index_reg, index, val);
+ Set_NB32_index_wait_DCT(dev, Channel, index_reg, index, val);
}
}
@@ -738,7 +1550,6 @@ static void mct_SetMaxLatency_D(struct DCTStatStruc *pDCTstat, u8 Channel, u16 D
u32 reg;
u32 SubTotal;
u32 index_reg;
- u32 reg_off;
u32 val;
uint8_t cpu_val_n;
@@ -773,17 +1584,16 @@ static void mct_SetMaxLatency_D(struct DCTStatStruc *pDCTstat, u8 Channel, u16 D
Channel = 0;
dev = pDCTstat->dev_dct;
- reg_off = 0x100 * Channel;
- index_reg = 0x98 + reg_off;
+ index_reg = 0x98;
/* Multiply the CAS Latency by two to get a number of 1/2 MEMCLKs units.*/
- val = Get_NB32(dev, 0x88 + reg_off);
+ val = Get_NB32_DCT(dev, Channel, 0x88);
SubTotal = ((val & 0x0f) + 4) << 1; /* SubTotal is 1/2 Memclk unit */
/* If registered DIMMs are being used then
* add 1 MEMCLK to the sub-total.
*/
- val = Get_NB32(dev, 0x90 + reg_off);
+ val = Get_NB32_DCT(dev, Channel, 0x90);
if(!(val & (1 << UnBuffDimm)))
SubTotal += 2;
@@ -791,7 +1601,7 @@ static void mct_SetMaxLatency_D(struct DCTStatStruc *pDCTstat, u8 Channel, u16 D
* add 1, else add 2 to the sub-total.
* if (AddrCmdSetup || CsOdtSetup || CkeSetup) then K := K + 2;
*/
- val = Get_NB32_index_wait(dev, index_reg, 0x04);
+ val = Get_NB32_index_wait_DCT(dev, Channel, index_reg, 0x04);
if(!(val & 0x00202020))
SubTotal += 1;
else
@@ -799,7 +1609,7 @@ static void mct_SetMaxLatency_D(struct DCTStatStruc *pDCTstat, u8 Channel, u16 D
/* If the F2x[1, 0]78[RdPtrInit] field is 4, 5, 6 or 7 MEMCLKs,
* then add 4, 3, 2, or 1 MEMCLKs, respectively to the sub-total. */
- val = Get_NB32(dev, 0x78 + reg_off);
+ val = Get_NB32_DCT(dev, Channel, 0x78);
SubTotal += 8 - (val & 0x0f);
/* Convert bits 7-5 (also referred to as the coarse delay) of
@@ -820,7 +1630,7 @@ static void mct_SetMaxLatency_D(struct DCTStatStruc *pDCTstat, u8 Channel, u16 D
* clocks (NCLKs)
*/
SubTotal *= 200 * ((Get_NB32(pDCTstat->dev_nbmisc, 0xd4) & 0x1f) + 4);
- SubTotal /= freq_tab[((Get_NB32(pDCTstat->dev_dct, 0x94 + reg_off) & 0x7) - 3)];
+ SubTotal /= freq_tab[((Get_NB32_DCT(pDCTstat->dev_dct, Channel, 0x94) & 0x7) - 3)];
SubTotal = (SubTotal + (2 - 1)) / 2; /* Round up */
/* Add "N" NCLKs to the sub-total. "N" represents part of the
@@ -837,13 +1647,13 @@ static void mct_SetMaxLatency_D(struct DCTStatStruc *pDCTstat, u8 Channel, u16 D
/* Program the F2x[1, 0]78[MaxRdLatency] register with
* the total delay value (in NCLKs).
*/
- reg = 0x78 + reg_off;
- val = Get_NB32(dev, reg);
+ reg = 0x78;
+ val = Get_NB32_DCT(dev, Channel, reg);
val &= ~(0x3ff << 22);
val |= (SubTotal & 0x3ff) << 22;
/* program MaxRdLatency to correspond with current delay */
- Set_NB32(dev, reg, val);
+ Set_NB32_DCT(dev, Channel, reg, val);
}
static void mct_InitDQSPos4RcvrEn_D(struct MCTStatStruc *pMCTstat,
@@ -873,7 +1683,7 @@ static void InitDQSPos4RcvrEn_D(struct MCTStatStruc *pMCTstat,
u32 dword;
u8 dn = 4; /* TODO: Rev C could be 4 */
u32 dev = pDCTstat->dev_dct;
- u32 index_reg = 0x98 + 0x100 * Channel;
+ u32 index_reg = 0x98;
/* FIXME: add Cx support */
dword = 0x00000000;
@@ -881,7 +1691,7 @@ static void InitDQSPos4RcvrEn_D(struct MCTStatStruc *pMCTstat,
for(j=0; j<dn; j++)
/* DIMM0 Write Data Timing Low */
/* DIMM0 Write ECC Timing */
- Set_NB32_index_wait(dev, index_reg, i + 0x100 * j, dword);
+ Set_NB32_index_wait_DCT(dev, Channel, index_reg, i + 0x100 * j, dword);
}
/* errata #180 */
@@ -889,13 +1699,13 @@ static void InitDQSPos4RcvrEn_D(struct MCTStatStruc *pMCTstat,
for(i=5; i<=6; i++) {
for(j=0; j<dn; j++)
/* DIMM0 Read DQS Timing Control Low */
- Set_NB32_index_wait(dev, index_reg, i + 0x100 * j, dword);
+ Set_NB32_index_wait_DCT(dev, Channel, index_reg, i + 0x100 * j, dword);
}
dword = 0x0000002f;
for(j=0; j<dn; j++)
/* DIMM0 Read DQS ECC Timing Control */
- Set_NB32_index_wait(dev, index_reg, 7 + 0x100 * j, dword);
+ Set_NB32_index_wait_DCT(dev, Channel, index_reg, 7 + 0x100 * j, dword);
}
void SetEccDQSRcvrEn_D(struct DCTStatStruc *pDCTstat, u8 Channel)
@@ -908,13 +1718,13 @@ void SetEccDQSRcvrEn_D(struct DCTStatStruc *pDCTstat, u8 Channel)
u32 val;
dev = pDCTstat->dev_dct;
- index_reg = 0x98 + Channel * 0x100;
+ index_reg = 0x98;
index = 0x12;
p = pDCTstat->CH_D_BC_RCVRDLY[Channel];
print_debug_dqs("\t\tSetEccDQSRcvrPos: Channel ", Channel, 2);
for(ChipSel = 0; ChipSel < MAX_CS_SUPPORTED; ChipSel += 2) {
val = p[ChipSel>>1];
- Set_NB32_index_wait(dev, index_reg, index, val);
+ Set_NB32_index_wait_DCT(dev, Channel, index_reg, index, val);
print_debug_dqs_pair("\t\tSetEccDQSRcvrPos: ChipSel ",
ChipSel, " rcvr_delay ", val, 2);
index += 3;
@@ -998,95 +1808,305 @@ void phyAssistedMemFnceTraining(struct MCTStatStruc *pMCTstat,
u8 Node = 0;
struct DCTStatStruc *pDCTstat;
+ printk(BIOS_DEBUG, "%s: Start\n", __func__);
+
/* FIXME: skip for Ax */
- while (Node < MAX_NODES_SUPPORTED) {
+ for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
pDCTstat = pDCTstatA + Node;
+ if (!pDCTstat->NodePresent)
+ continue;
+
+ if (pDCTstat->DCTSysLimit) {
+ if (is_fam15h()) {
+ /* Fam15h BKDG v3.14 section 2.10.5.3.3
+ * This picks up where InitDDRPhy left off
+ */
+ uint8_t dct;
+ uint8_t index;
+ uint32_t dword;
+ uint32_t datc_backup;
+ uint32_t training_dword;
+ uint32_t fence2_config_dword;
+ uint32_t fence_tx_pad_config_dword;
+ uint32_t index_reg = 0x98;
+ uint32_t dev = pDCTstat->dev_dct;
+
+ for (dct = 0; dct < 2; dct++) {
+ if (!pDCTstat->DIMMValidDCT[dct])
+ continue;
+
+ /* Back up D18F2x9C_x0000_0004_dct[1:0] */
+ datc_backup = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x00000004);
+
+ /* FenceTrSel = 0x2 */
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x00000008);
+ dword &= ~(0x3 << 6);
+ dword |= (0x2 << 6);
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x00000008, dword);
+
+ /* Set phase recovery seed values */
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x00000050, 0x13131313);
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x00000051, 0x13131313);
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x00000052, 0x00000013);
+
+ training_dword = fenceDynTraining_D(pMCTstat, pDCTstat, dct);
+
+ /* Save calculated fence value to the TX DLL */
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000c);
+ dword &= ~(0x1f << 26);
+ dword |= ((training_dword & 0x1f) << 26);
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000c, dword);
+
+ /* D18F2x9C_x0D0F_0[F,8:0]0F_dct[1:0][AlwaysEnDllClks]=0x1 */
+ for (index = 0; index < 0x9; index++) {
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f000f | (index << 8));
+ dword &= ~(0x7 << 12);
+ dword |= (0x1 << 12);
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f000f | (index << 8), dword);
+ }
+
+ /* FenceTrSel = 0x1 */
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x00000008);
+ dword &= ~(0x3 << 6);
+ dword |= (0x1 << 6);
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x00000008, dword);
+
+ /* Set phase recovery seed values */
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x00000050, 0x13131313);
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x00000051, 0x13131313);
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x00000052, 0x00000013);
+
+ training_dword = fenceDynTraining_D(pMCTstat, pDCTstat, dct);
+
+ /* Save calculated fence value to the RX DLL */
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000c);
+ dword &= ~(0x1f << 21);
+ dword |= ((training_dword & 0x1f) << 21);
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000c, dword);
+
+ /* D18F2x9C_x0D0F_0[F,8:0]0F_dct[1:0][AlwaysEnDllClks]=0x0 */
+ for (index = 0; index < 0x9; index++) {
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f000f | (index << 8));
+ dword &= ~(0x7 << 12);
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f000f | (index << 8), dword);
+ }
+
+ /* FenceTrSel = 0x3 */
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x00000008);
+ dword &= ~(0x3 << 6);
+ dword |= (0x3 << 6);
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x00000008, dword);
+
+ /* Set phase recovery seed values */
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x00000050, 0x13131313);
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x00000051, 0x13131313);
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x00000052, 0x00000013);
+
+ fence_tx_pad_config_dword = fenceDynTraining_D(pMCTstat, pDCTstat, dct);
+
+ /* Save calculated fence value to the TX Pad */
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000c);
+ dword &= ~(0x1f << 16);
+ dword |= ((fence_tx_pad_config_dword & 0x1f) << 16);
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000c, dword);
+
+ /* Program D18F2x9C_x0D0F_[C,8,2][2:0]31_dct[1:0] */
+ training_dword = fence_tx_pad_config_dword;
+ if (fence_tx_pad_config_dword < 16)
+ training_dword |= (0x1 << 4);
+ else
+ training_dword = 0;
+ for (index = 0; index < 0x3; index++) {
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f2031 | (index << 8));
+ dword &= ~(0x1f);
+ dword |= (training_dword & 0x1f);
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f2031 | (index << 8), dword);
+ }
+ for (index = 0; index < 0x3; index++) {
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f8031 | (index << 8));
+ dword &= ~(0x1f);
+ dword |= (training_dword & 0x1f);
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f8031 | (index << 8), dword);
+ }
+ for (index = 0; index < 0x3; index++) {
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fc031 | (index << 8));
+ dword &= ~(0x1f);
+ dword |= (training_dword & 0x1f);
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fc031 | (index << 8), dword);
+ }
+
+ /* Assemble Fence2 configuration word (Fam15h BKDG v3.14 page 331) */
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000c);
+ fence2_config_dword = 0;
+
+ /* TxPad */
+ training_dword = (dword >> 16) & 0x1f;
+ if (training_dword < 16)
+ training_dword |= 0x10;
+ else
+ training_dword = 0;
+ fence2_config_dword |= training_dword;
+
+ /* RxDll */
+ training_dword = (dword >> 21) & 0x1f;
+ if (training_dword < 16)
+ training_dword |= 0x10;
+ else
+ training_dword = 0;
+ fence2_config_dword |= (training_dword << 10);
+
+ /* TxDll */
+ training_dword = (dword >> 26) & 0x1f;
+ if (training_dword < 16)
+ training_dword |= 0x10;
+ else
+ training_dword = 0;
+ fence2_config_dword |= (training_dword << 5);
+
+ /* Program D18F2x9C_x0D0F_0[F,8:0]31_dct[1:0] */
+ for (index = 0; index < 0x9; index++) {
+ dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f0031 | (index << 8));
+ dword &= ~(0x7fff);
+ dword |= fence2_config_dword;
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f0031 | (index << 8), dword);
+ }
- if(pDCTstat->DCTSysLimit) {
- fenceDynTraining_D(pMCTstat, pDCTstat, 0);
- fenceDynTraining_D(pMCTstat, pDCTstat, 1);
+ /* Restore D18F2x9C_x0000_0004_dct[1:0] */
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x00000004, datc_backup);
+ }
+ } else {
+ fenceDynTraining_D(pMCTstat, pDCTstat, 0);
+ fenceDynTraining_D(pMCTstat, pDCTstat, 1);
+ }
}
- Node++;
}
+
+ printk(BIOS_DEBUG, "%s: Done\n", __func__);
}
-static void fenceDynTraining_D(struct MCTStatStruc *pMCTstat,
+static uint32_t fenceDynTraining_D(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat, u8 dct)
{
u16 avRecValue;
u32 val;
u32 dev;
- u32 index_reg = 0x98 + 0x100 * dct;
+ u32 index_reg = 0x98;
u32 index;
- /* BIOS first programs a seed value to the phase recovery engine
- * (recommended 19) registers.
- * Dram Phase Recovery Control Register (F2x[1,0]9C_x[51:50] and
- * F2x[1,0]9C_x52.) .
- */
dev = pDCTstat->dev_dct;
- for (index = 0x50; index <= 0x52; index ++) {
- val = (FenceTrnFinDlySeed & 0x1F);
- if (index != 0x52) {
- val |= val << 8 | val << 16 | val << 24;
+
+ if (is_fam15h()) {
+ /* Set F2x[1,0]9C_x08[PhyFenceTrEn] */
+ val = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x08);
+ val |= 1 << PhyFenceTrEn;
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x08, val);
+
+ /* Wait 2000 MEMCLKs */
+ precise_memclk_delay_fam15(pMCTstat, pDCTstat, dct, 2000);
+
+ /* Clear F2x[1,0]9C_x08[PhyFenceTrEn] */
+ val = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x08);
+ val &= ~(1 << PhyFenceTrEn);
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x08, val);
+
+ /* BIOS reads the phase recovery engine registers
+ * F2x[1,0]9C_x[51:50] and F2x[1,0]9C_x52.
+ * Average the fine delay components only.
+ */
+ avRecValue = 0;
+ for (index = 0x50; index <= 0x52; index++) {
+ val = Get_NB32_index_wait_DCT(dev, dct, index_reg, index);
+ avRecValue += val & 0x1f;
+ if (index != 0x52) {
+ avRecValue += (val >> 8) & 0x1f;
+ avRecValue += (val >> 16) & 0x1f;
+ avRecValue += (val >> 24) & 0x1f;
+ }
}
- Set_NB32_index_wait(dev, index_reg, index, val);
- }
- /* Set F2x[1,0]9C_x08[PhyFenceTrEn]=1. */
- val = Get_NB32_index_wait(dev, index_reg, 0x08);
- val |= 1 << PhyFenceTrEn;
- Set_NB32_index_wait(dev, index_reg, 0x08, val);
-
- /* Wait 200 MEMCLKs. */
- mct_Wait(50000); /* wait 200us */
-
- /* Clear F2x[1,0]9C_x08[PhyFenceTrEn]=0. */
- val = Get_NB32_index_wait(dev, index_reg, 0x08);
- val &= ~(1 << PhyFenceTrEn);
- Set_NB32_index_wait(dev, index_reg, 0x08, val);
-
- /* BIOS reads the phase recovery engine registers
- * F2x[1,0]9C_x[51:50] and F2x[1,0]9C_x52. */
- avRecValue = 0;
- for (index = 0x50; index <= 0x52; index ++) {
- val = Get_NB32_index_wait(dev, index_reg, index);
- avRecValue += val & 0x7F;
- if (index != 0x52) {
- avRecValue += (val >> 8) & 0x7F;
- avRecValue += (val >> 16) & 0x7F;
- avRecValue += (val >> 24) & 0x7F;
+ val = avRecValue / 9;
+ if (avRecValue % 9)
+ val++;
+ avRecValue = val;
+
+ if (avRecValue < 6)
+ avRecValue = 0;
+ else
+ avRecValue -= 6;
+
+ return avRecValue;
+ } else {
+ /* BIOS first programs a seed value to the phase recovery engine
+ * (recommended 19) registers.
+ * Dram Phase Recovery Control Register (F2x[1,0]9C_x[51:50] and
+ * F2x[1,0]9C_x52.) .
+ */
+ for (index = 0x50; index <= 0x52; index ++) {
+ val = (FenceTrnFinDlySeed & 0x1F);
+ if (index != 0x52) {
+ val |= val << 8 | val << 16 | val << 24;
+ }
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, index, val);
}
- }
- val = avRecValue / 9;
- if (avRecValue % 9)
- val++;
- avRecValue = val;
+ /* Set F2x[1,0]9C_x08[PhyFenceTrEn]=1. */
+ val = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x08);
+ val |= 1 << PhyFenceTrEn;
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x08, val);
+
+ /* Wait 200 MEMCLKs. */
+ mct_Wait(50000); /* wait 200us */
+
+ /* Clear F2x[1,0]9C_x08[PhyFenceTrEn]=0. */
+ val = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x08);
+ val &= ~(1 << PhyFenceTrEn);
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x08, val);
+
+ /* BIOS reads the phase recovery engine registers
+ * F2x[1,0]9C_x[51:50] and F2x[1,0]9C_x52. */
+ avRecValue = 0;
+ for (index = 0x50; index <= 0x52; index ++) {
+ val = Get_NB32_index_wait_DCT(dev, dct, index_reg, index);
+ avRecValue += val & 0x7F;
+ if (index != 0x52) {
+ avRecValue += (val >> 8) & 0x7F;
+ avRecValue += (val >> 16) & 0x7F;
+ avRecValue += (val >> 24) & 0x7F;
+ }
+ }
- /* Write the (averaged value -8) to F2x[1,0]9C_x0C[PhyFence]. */
- /* inlined mct_AdjustFenceValue() */
- /* TODO: The RBC0 is not supported. */
- /* if (pDCTstat->LogicalCPUID & AMD_RB_C0)
- avRecValue -= 3;
- else
- */
- if (pDCTstat->LogicalCPUID & AMD_DR_Dx)
- avRecValue -= 8;
- else if (pDCTstat->LogicalCPUID & AMD_DR_Cx)
- avRecValue -= 8;
- else if (pDCTstat->LogicalCPUID & AMD_DR_Bx)
- avRecValue -= 8;
-
- val = Get_NB32_index_wait(dev, index_reg, 0x0C);
- val &= ~(0x1F << 16);
- val |= (avRecValue & 0x1F) << 16;
- Set_NB32_index_wait(dev, index_reg, 0x0C, val);
-
- /* Rewrite F2x[1,0]9C_x04-DRAM Address/Command Timing Control Register
- * delays (both channels). */
- val = Get_NB32_index_wait(dev, index_reg, 0x04);
- Set_NB32_index_wait(dev, index_reg, 0x04, val);
+ val = avRecValue / 9;
+ if (avRecValue % 9)
+ val++;
+ avRecValue = val;
+
+ /* Write the (averaged value -8) to F2x[1,0]9C_x0C[PhyFence]. */
+ /* inlined mct_AdjustFenceValue() */
+ /* TODO: The RBC0 is not supported. */
+ /* if (pDCTstat->LogicalCPUID & AMD_RB_C0)
+ avRecValue -= 3;
+ else
+ */
+ if (pDCTstat->LogicalCPUID & AMD_DR_Dx)
+ avRecValue -= 8;
+ else if (pDCTstat->LogicalCPUID & AMD_DR_Cx)
+ avRecValue -= 8;
+ else if (pDCTstat->LogicalCPUID & AMD_DR_Bx)
+ avRecValue -= 8;
+
+ val = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0C);
+ val &= ~(0x1F << 16);
+ val |= (avRecValue & 0x1F) << 16;
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0C, val);
+
+ /* Rewrite F2x[1,0]9C_x04-DRAM Address/Command Timing Control Register
+ * delays (both channels).
+ */
+ val = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x04);
+ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x04, val);
+
+ return avRecValue;
+ }
}
void mct_Wait(u32 cycles)
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc1p.c b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc1p.c
index 89385e74f2..15e66c934c 100644
--- a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc1p.c
+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc1p.c
@@ -17,8 +17,14 @@
u8 mct_checkNumberOfDqsRcvEn_1Pass(u8 pass)
{
u8 ret = 1;
- if (pass == SecondPass)
- ret = 0;
+
+ if (is_fam15h()) {
+ /* Fam15h needs two passes */
+ ret = 1;
+ } else {
+ if (pass == SecondPass)
+ ret = 0;
+ }
return ret;
}
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mcttmrl.c b/src/northbridge/amd/amdmct/mct_ddr3/mcttmrl.c
index 559b5f1266..1b18efa259 100644
--- a/src/northbridge/amd/amdmct/mct_ddr3/mcttmrl.c
+++ b/src/northbridge/amd/amdmct/mct_ddr3/mcttmrl.c
@@ -214,12 +214,12 @@ static void mct_setMaxRdLatTrnVal_D(struct DCTStatStruc *pDCTstat,
}
dev = pDCTstat->dev_dct;
- reg = 0x78 + Channel * 0x100;
- val = Get_NB32(dev, reg);
+ reg = 0x78;
+ val = Get_NB32_DCT(dev, Channel, reg);
val &= ~(0x3ff<<22);
val |= MaxRdLatVal<<22;
/* program MaxRdLatency to correspond with current delay */
- Set_NB32(dev, reg, val);
+ Set_NB32_DCT(dev, Channel, reg, val);
}
static u8 CompareMaxRdLatTestPattern_D(u32 pattern_buf, u32 addr)
@@ -316,30 +316,28 @@ u8 mct_GetStartMaxRdLat_D(struct MCTStatStruc *pMCTstat,
u32 valx;
u32 valxx;
u32 index_reg;
- u32 reg_off;
u32 dev;
if(pDCTstat->GangedMode)
Channel = 0;
- index_reg = 0x98 + 0x100 * Channel;
+ index_reg = 0x98;
- reg_off = 0x100 * Channel;
dev = pDCTstat->dev_dct;
/* Multiply the CAS Latency by two to get a number of 1/2 MEMCLKs units.*/
- val = Get_NB32(dev, 0x88 + reg_off);
+ val = Get_NB32_DCT(dev, Channel, 0x88);
SubTotal = ((val & 0x0f) + 1) << 1; /* SubTotal is 1/2 Memclk unit */
/* If registered DIMMs are being used then add 1 MEMCLK to the sub-total*/
- val = Get_NB32(dev, 0x90 + reg_off);
+ val = Get_NB32_DCT(dev, Channel, 0x90);
if(!(val & (1 << UnBuffDimm)))
SubTotal += 2;
/*If the address prelaunch is setup for 1/2 MEMCLKs then add 1,
* else add 2 to the sub-total. if (AddrCmdSetup || CsOdtSetup
* || CkeSetup) then K := K + 2; */
- val = Get_NB32_index_wait(dev, index_reg, 0x04);
+ val = Get_NB32_index_wait_DCT(dev, Channel, index_reg, 0x04);
if(!(val & 0x00202020))
SubTotal += 1;
else
@@ -347,7 +345,7 @@ u8 mct_GetStartMaxRdLat_D(struct MCTStatStruc *pMCTstat,
/* If the F2x[1, 0]78[RdPtrInit] field is 4, 5, 6 or 7 MEMCLKs,
* then add 4, 3, 2, or 1 MEMCLKs, respectively to the sub-total. */
- val = Get_NB32(dev, 0x78 + reg_off);
+ val = Get_NB32_DCT(dev, Channel, 0x78);
SubTotal += 8 - (val & 0x0f);
/* Convert bits 7-5 (also referred to as the course delay) of the current
@@ -363,7 +361,7 @@ u8 mct_GetStartMaxRdLat_D(struct MCTStatStruc *pMCTstat,
/*New formula:
SubTotal *= 3*(Fn2xD4[NBFid]+4)/(3+Fn2x94[MemClkFreq])/2 */
- val = Get_NB32(dev, 0x94 + reg_off);
+ val = Get_NB32_DCT(dev, Channel, 0x94);
/* SubTotal div 4 to scale 1/4 MemClk back to MemClk */
val &= 7;
if (val >= 3) {
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctwl.c b/src/northbridge/amd/amdmct/mct_ddr3/mctwl.c
index 5a10e4c30d..fe0653e04e 100644
--- a/src/northbridge/amd/amdmct/mct_ddr3/mctwl.c
+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctwl.c
@@ -79,6 +79,12 @@ void PrepareC_DCT(struct MCTStatStruc *pMCTstat,
pDCTstat->C_DCTPtr[dct]->Status[DCT_STATUS_REGISTERED] = 0;
}
+ if (pDCTstat->Status & (1 << SB_LoadReduced)) {
+ pDCTstat->C_DCTPtr[dct]->Status[DCT_STATUS_LOAD_REDUCED] = 1;
+ } else {
+ pDCTstat->C_DCTPtr[dct]->Status[DCT_STATUS_LOAD_REDUCED] = 0;
+ }
+
pDCTstat->C_DCTPtr[dct]->RegMan1Present = pDCTstat->RegMan1Present;
for (dimm = 0; dimm < MAX_TOTAL_DIMMS; dimm++) {
@@ -99,13 +105,13 @@ void EnableZQcalibration(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDC
{
u32 val;
- val = Get_NB32(pDCTstat->dev_dct, 0x94);
+ val = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x94);
val |= 1 << 11;
- Set_NB32(pDCTstat->dev_dct, 0x94, val);
+ Set_NB32_DCT(pDCTstat->dev_dct, 0, 0x94, val);
- val = Get_NB32(pDCTstat->dev_dct, 0x94 + 0x100);
+ val = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x94);
val |= 1 << 11;
- Set_NB32(pDCTstat->dev_dct, 0x94 + 0x100, val);
+ Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x94, val);
}
void DisableZQcalibration(struct MCTStatStruc *pMCTstat,
@@ -113,15 +119,15 @@ void DisableZQcalibration(struct MCTStatStruc *pMCTstat,
{
u32 val;
- val = Get_NB32(pDCTstat->dev_dct, 0x94);
+ val = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x94);
val &= ~(1 << 11);
val &= ~(1 << 10);
- Set_NB32(pDCTstat->dev_dct, 0x94, val);
+ Set_NB32_DCT(pDCTstat->dev_dct, 0, 0x94, val);
- val = Get_NB32(pDCTstat->dev_dct, 0x94 + 0x100);
+ val = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x94);
val &= ~(1 << 11);
val &= ~(1 << 10);
- Set_NB32(pDCTstat->dev_dct, 0x94 + 0x100, val);
+ Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x94, val);
}
static void EnterSelfRefresh(struct MCTStatStruc *pMCTstat,
@@ -138,23 +144,23 @@ static void EnterSelfRefresh(struct MCTStatStruc *pMCTstat,
/* Program F2x[1, 0]90[EnterSelfRefresh]=1. */
if (DCT0Present) {
- val = Get_NB32(pDCTstat->dev_dct, 0x90);
+ val = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x90);
val |= 1 << EnterSelfRef;
- Set_NB32(pDCTstat->dev_dct, 0x90, val);
+ Set_NB32_DCT(pDCTstat->dev_dct, 0, 0x90, val);
}
if (DCT1Present) {
- val = Get_NB32(pDCTstat->dev_dct, 0x90 + 0x100);
+ val = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x90);
val |= 1 << EnterSelfRef;
- Set_NB32(pDCTstat->dev_dct, 0x90 + 0x100, val);
+ Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x90, val);
}
/* Wait until the hardware resets F2x[1, 0]90[EnterSelfRefresh]=0. */
if (DCT0Present)
do {
- val = Get_NB32(pDCTstat->dev_dct, 0x90);
+ val = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x90);
} while (val & (1 <<EnterSelfRef));
if (DCT1Present)
do {
- val = Get_NB32(pDCTstat->dev_dct, 0x90 + 0x100);
+ val = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x90);
} while (val & (1 <<EnterSelfRef));
}
@@ -164,8 +170,11 @@ static void EnterSelfRefresh(struct MCTStatStruc *pMCTstat,
static void ChangeMemClk(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat)
{
- u8 DCT0Present, DCT1Present;
- u32 val;
+ uint8_t DCT0Present;
+ uint8_t DCT1Present;
+ uint32_t dword;
+ uint32_t mask;
+ uint32_t offset;
DCT0Present = pDCTstat->DIMMValidDCT[0];
if (pDCTstat->GangedMode)
@@ -173,76 +182,134 @@ static void ChangeMemClk(struct MCTStatStruc *pMCTstat,
else
DCT1Present = pDCTstat->DIMMValidDCT[1];
- /* Program F2x[1, 0]90[EnterSelfRefresh]=1. */
- if (DCT0Present) {
- val = Get_NB32_index_wait(pDCTstat->dev_dct, 0x98, 8);
- val |= 1 << DisAutoComp;
- Set_NB32_index_wait(pDCTstat->dev_dct, 0x98, 8, val);
- }
- if (DCT1Present) {
- val = Get_NB32_index_wait(pDCTstat->dev_dct, 0x98 + 0x100, 8);
- val |= 1 << DisAutoComp;
- Set_NB32_index_wait(pDCTstat->dev_dct, 0x98 + 0x100, 8, val);
+ if (is_fam15h()) {
+ /* Program D18F2x9C_x0D0F_E006_dct[1:0][PllLockTime] = 0x190 */
+ if (DCT0Present) {
+ dword = Get_NB32_index_wait_DCT(pDCTstat->dev_dct, 0, 0x98, 0x0d0fe006);
+ dword &= ~(0x0000ffff);
+ dword |= 0x00000190;
+ Set_NB32_index_wait_DCT(pDCTstat->dev_dct, 0, 0x98, 0x0d0fe006, dword);
+ }
+ if (DCT1Present) {
+ dword = Get_NB32_index_wait_DCT(pDCTstat->dev_dct, 1, 0x98, 0x0d0fe006);
+ dword &= ~(0x0000ffff);
+ dword |= 0x00000190;
+ Set_NB32_index_wait_DCT(pDCTstat->dev_dct, 1, 0x98, 0x0d0fe006, dword);
+ }
+ } else {
+ /* Program F2x[1, 0]9C[DisAutoComp]=1. */
+ if (DCT0Present) {
+ dword = Get_NB32_index_wait_DCT(pDCTstat->dev_dct, 0, 0x98, 8);
+ dword |= 1 << DisAutoComp;
+ Set_NB32_index_wait_DCT(pDCTstat->dev_dct, 0, 0x98, 8, dword);
+ mct_Wait(100); /* Wait for 5us */
+ }
+ if (DCT1Present) {
+ dword = Get_NB32_index_wait_DCT(pDCTstat->dev_dct, 1, 0x98, 8);
+ dword |= 1 << DisAutoComp;
+ Set_NB32_index_wait_DCT(pDCTstat->dev_dct, 1, 0x98, 8, dword);
+ mct_Wait(100); /* Wait for 5us */
+ }
}
/* Program F2x[1, 0]94[MemClkFreqVal] = 0. */
if (DCT0Present) {
- val = Get_NB32(pDCTstat->dev_dct, 0x94);
- val &= ~(1 << MemClkFreqVal);
- Set_NB32(pDCTstat->dev_dct, 0x94, val);
+ dword = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x94);
+ dword &= ~(1 << MemClkFreqVal);
+ Set_NB32_DCT(pDCTstat->dev_dct, 0, 0x94, dword);
}
if (DCT1Present) {
- val = Get_NB32(pDCTstat->dev_dct, 0x94 + 0x100);
- val &= ~(1 << MemClkFreqVal);
- Set_NB32(pDCTstat->dev_dct, 0x94 + 0x100, val);
+ dword = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x94);
+ dword &= ~(1 << MemClkFreqVal);
+ Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x94, dword);
}
/* Program F2x[1, 0]94[MemClkFreq] to specify the target MEMCLK frequency. */
+ if (is_fam15h()) {
+ offset = 0x0;
+ mask = 0x1f;
+ } else {
+ offset = 0x1;
+ mask = 0x7;
+ }
if (DCT0Present) {
- val = Get_NB32(pDCTstat->dev_dct, 0x94);
- val &= 0xFFFFFFF8;
- val |= pDCTstat->TargetFreq - 1;
- Set_NB32(pDCTstat->dev_dct, 0x94, val);
+ dword = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x94);
+ dword &= ~mask;
+ dword |= (pDCTstat->TargetFreq - offset) & mask;
+ Set_NB32_DCT(pDCTstat->dev_dct, 0, 0x94, dword);
}
if (DCT1Present) {
- val = Get_NB32(pDCTstat->dev_dct, 0x94 + 0x100);
- val &= 0xFFFFFFF8;
- val |= pDCTstat->TargetFreq - 1;
- Set_NB32(pDCTstat->dev_dct, 0x94 + 0x100, val);
+ dword = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x94);
+ dword &= ~mask;
+ dword |= (pDCTstat->TargetFreq - offset) & mask;
+ Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x94, dword);
+ }
+
+ if (is_fam15h()) {
+ if (DCT0Present) {
+ mctGet_PS_Cfg_D(pMCTstat, pDCTstat, 0);
+ set_2t_configuration(pMCTstat, pDCTstat, 0);
+ mct_BeforePlatformSpec(pMCTstat, pDCTstat, 0);
+ mct_PlatformSpec(pMCTstat, pDCTstat, 0);
+ }
+ if (DCT1Present) {
+ mctGet_PS_Cfg_D(pMCTstat, pDCTstat, 1);
+ set_2t_configuration(pMCTstat, pDCTstat, 1);
+ mct_BeforePlatformSpec(pMCTstat, pDCTstat, 1);
+ mct_PlatformSpec(pMCTstat, pDCTstat, 1);
+ }
}
/* Program F2x[1, 0]94[MemClkFreqVal] = 1. */
if (DCT0Present) {
- val = Get_NB32(pDCTstat->dev_dct, 0x94);
- val |= 1 << MemClkFreqVal;
- Set_NB32(pDCTstat->dev_dct, 0x94, val);
+ dword = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x94);
+ dword |= 1 << MemClkFreqVal;
+ Set_NB32_DCT(pDCTstat->dev_dct, 0, 0x94, dword);
}
if (DCT1Present) {
- val = Get_NB32(pDCTstat->dev_dct, 0x94 + 0x100);
- val |= 1 << MemClkFreqVal;
- Set_NB32(pDCTstat->dev_dct, 0x94 + 0x100, val);
+ dword = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x94);
+ dword |= 1 << MemClkFreqVal;
+ Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x94, dword);
}
/* Wait until F2x[1, 0]94[FreqChgInProg]=0. */
if (DCT0Present)
do {
- val = Get_NB32(pDCTstat->dev_dct, 0x94);
- } while (val & (1 << FreqChgInProg));
+ dword = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x94);
+ } while (dword & (1 << FreqChgInProg));
if (DCT1Present)
do {
- val = Get_NB32(pDCTstat->dev_dct, 0x94 + 0x100);
- } while (val & (1 << FreqChgInProg));
-
- /* Program F2x[1, 0]94[MemClkFreqVal] = 0. */
- if (DCT0Present) {
- val = Get_NB32_index_wait(pDCTstat->dev_dct, 0x98, 8);
- val &= ~(1 << DisAutoComp);
- Set_NB32_index_wait(pDCTstat->dev_dct, 0x98, 8, val);
- }
- if (DCT1Present) {
- val = Get_NB32_index_wait(pDCTstat->dev_dct, 0x98 + 0x100, 8);
- val &= ~(1 << DisAutoComp);
- Set_NB32_index_wait(pDCTstat->dev_dct, 0x98 + 0x100, 8, val);
+ dword = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x94);
+ } while (dword & (1 << FreqChgInProg));
+
+ if (is_fam15h()) {
+ /* Program D18F2x9C_x0D0F_E006_dct[1:0][PllLockTime] = 0xf */
+ if (DCT0Present) {
+ dword = Get_NB32_index_wait_DCT(pDCTstat->dev_dct, 0, 0x98, 0x0d0fe006);
+ dword &= ~(0x0000ffff);
+ dword |= 0x0000000f;
+ Set_NB32_index_wait_DCT(pDCTstat->dev_dct, 0, 0x98, 0x0d0fe006, dword);
+ }
+ if (DCT1Present) {
+ dword = Get_NB32_index_wait_DCT(pDCTstat->dev_dct, 1, 0x98, 0x0d0fe006);
+ dword &= ~(0x0000ffff);
+ dword |= 0x0000000f;
+ Set_NB32_index_wait_DCT(pDCTstat->dev_dct, 1, 0x98, 0x0d0fe006, dword);
+ }
+ } else {
+ /* Program F2x[1, 0]9C[DisAutoComp] = 0. */
+ if (DCT0Present) {
+ dword = Get_NB32_index_wait_DCT(pDCTstat->dev_dct, 0, 0x98, 8);
+ dword &= ~(1 << DisAutoComp);
+ Set_NB32_index_wait_DCT(pDCTstat->dev_dct, 0, 0x98, 8, dword);
+ mct_Wait(15000); /* Wait for 750us */
+ }
+ if (DCT1Present) {
+ dword = Get_NB32_index_wait_DCT(pDCTstat->dev_dct, 1, 0x98, 8);
+ dword &= ~(1 << DisAutoComp);
+ Set_NB32_index_wait_DCT(pDCTstat->dev_dct, 1, 0x98, 8, dword);
+ mct_Wait(15000); /* Wait for 750us */
+ }
}
}
@@ -263,29 +330,46 @@ static void ExitSelfRefresh(struct MCTStatStruc *pMCTstat,
/* Program F2x[1, 0]90[ExitSelfRef]=1 for both DCTs. */
if (DCT0Present) {
- val = Get_NB32(pDCTstat->dev_dct, 0x90);
+ val = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x90);
val |= 1 << ExitSelfRef;
- Set_NB32(pDCTstat->dev_dct, 0x90, val);
+ Set_NB32_DCT(pDCTstat->dev_dct, 0, 0x90, val);
}
if (DCT1Present) {
- val = Get_NB32(pDCTstat->dev_dct, 0x90 + 0x100);
+ val = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x90);
val |= 1 << ExitSelfRef;
- Set_NB32(pDCTstat->dev_dct, 0x90 + 0x100, val);
+ Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x90, val);
}
/* Wait until the hardware resets F2x[1, 0]90[ExitSelfRef]=0. */
if (DCT0Present)
do {
- val = Get_NB32(pDCTstat->dev_dct, 0x90);
+ val = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x90);
} while (val & (1 << ExitSelfRef));
if (DCT1Present)
do {
- val = Get_NB32(pDCTstat->dev_dct, 0x90 + 0x100);
+ val = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x90);
} while (val & (1 << ExitSelfRef));
}
void SetTargetFreq(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat)
{
+ uint32_t dword;
+ uint8_t package_type = mctGet_NVbits(NV_PACK_TYPE);
+
+ if (is_fam15h()) {
+ /* Program F2x[1, 0]90[DisDllShutDownSR]=1. */
+ if (pDCTstat->DIMMValidDCT[0]) {
+ dword = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x90);
+ dword |= (0x1 << 27);
+ Set_NB32_DCT(pDCTstat->dev_dct, 0, 0x90, dword);
+ }
+ if (pDCTstat->DIMMValidDCT[1]) {
+ dword = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x90);
+ dword |= (0x1 << 27);
+ Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x90, dword);
+ }
+ }
+
/* Program F2x[1,0]90[EnterSelfRefresh]=1.
* Wait until the hardware resets F2x[1,0]90[EnterSelfRefresh]=0.
*/
@@ -301,11 +385,38 @@ void SetTargetFreq(struct MCTStatStruc *pMCTstat,
*/
ChangeMemClk(pMCTstat, pDCTstat);
+ if (is_fam15h()) {
+ uint8_t dct;
+ for (dct = 0; dct < 2; dct++) {
+ if (pDCTstat->DIMMValidDCT[dct]) {
+ phyAssistedMemFnceTraining(pMCTstat, pDCTstat);
+ InitPhyCompensation(pMCTstat, pDCTstat, dct);
+ }
+ }
+ }
+
/* Program F2x[1,0]90[ExitSelfRef]=1 for both DCTs.
* Wait until the hardware resets F2x[1, 0]90[ExitSelfRef]=0.
*/
ExitSelfRefresh(pMCTstat, pDCTstat);
+ if (is_fam15h()) {
+ if ((package_type == PT_C3) || (package_type == PT_GR)) {
+ /* Socket C32 or G34 */
+ /* Program F2x[1, 0]90[DisDllShutDownSR]=0. */
+ if (pDCTstat->DIMMValidDCT[0]) {
+ dword = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x90);
+ dword &= ~(0x1 << 27);
+ Set_NB32_DCT(pDCTstat->dev_dct, 0, 0x90, dword);
+ }
+ if (pDCTstat->DIMMValidDCT[1]) {
+ dword = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x90);
+ dword &= ~(0x1 << 27);
+ Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x90, dword);
+ }
+ }
+ }
+
/* wait for 500 MCLKs after ExitSelfRef, 500*2.5ns=1250ns */
mct_Wait(250);
@@ -332,13 +443,13 @@ void SetTargetFreq(struct MCTStatStruc *pMCTstat,
static void Modify_OnDimmMirror(struct DCTStatStruc *pDCTstat, u8 dct, u8 set)
{
u32 val;
- u32 reg_off = dct * 0x100 + 0x44;
- while (reg_off < (dct * 0x100 + 0x60)) {
- val = Get_NB32(pDCTstat->dev_dct, reg_off);
+ u32 reg = 0x44;
+ while (reg < 0x60) {
+ val = Get_NB32_DCT(pDCTstat->dev_dct, dct, reg);
if (val & (1 << CSEnable))
set ? (val |= 1 << onDimmMirror) : (val &= ~(1<<onDimmMirror));
- Set_NB32(pDCTstat->dev_dct, reg_off, val);
- reg_off += 8;
+ Set_NB32_DCT(pDCTstat->dev_dct, dct, reg, val);
+ reg += 8;
}
}
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
index 9ea854f186..f3915a2438 100644
--- a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
+++ b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
@@ -26,13 +26,22 @@
*
*----------------------------------------------------------------------------
*/
-u32 swapAddrBits_wl(sDCTStruct *pDCTData, u32 MRSValue);
-u32 swapBankBits(sDCTStruct *pDCTData, u32 MRSValue);
-void prepareDimms(sMCTStruct *pMCTData, sDCTStruct *pDCTData, u8 dimm, BOOL wl);
-void programODT(sMCTStruct *pMCTData, sDCTStruct *pDCTData, u8 dimm);
-void procConifg(sMCTStruct *pMCTData,sDCTStruct *pDCTData, u8 dimm, u8 pass);
-void setWLByteDelay(sDCTStruct *pDCTData, u8 ByteLane, u8 dimm, u8 targetAddr);
-void getWLByteDelay(sDCTStruct *pDCTData, u8 ByteLane, u8 dimm);
+u32 swapAddrBits_wl(struct DCTStatStruc *pDCTstat, uint8_t dct, uint32_t MRSValue);
+u32 swapBankBits(struct DCTStatStruc *pDCTstat, uint8_t dct, uint32_t MRSValue);
+void prepareDimms(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat,
+ u8 dct, u8 dimm, BOOL wl);
+void programODT(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, uint8_t dct, u8 dimm);
+void procConfig(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, uint8_t dct, u8 dimm, u8 pass);
+void setWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, u8 dimm, u8 targetAddr, uint8_t pass);
+void getWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, u8 dimm, uint8_t pass);
+
+static int32_t abs(int32_t val) {
+ if (val < 0)
+ val *= -1;
+
+ return val;
+}
+
/*
*-----------------------------------------------------------------------------
* EXPORTED FUNCTIONS
@@ -58,34 +67,55 @@ void getWLByteDelay(sDCTStruct *pDCTData, u8 ByteLane, u8 dimm);
* OUT
*-----------------------------------------------------------------------------
*/
-void AgesaHwWlPhase1(sMCTStruct *pMCTData, sDCTStruct *pDCTData,
- u8 dimm, u8 pass)
+void AgesaHwWlPhase1(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat,
+ u8 dct, u8 dimm, u8 pass)
{
u8 ByteLane;
u32 Value, Addr;
u16 Addl_Data_Offset, Addl_Data_Port;
+ sMCTStruct *pMCTData = pDCTstat->C_MCTPtr;
+ sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
pDCTData->WLPass = pass;
/* 1. Specify the target DIMM that is to be trained by programming
* F2x[1, 0]9C_x08[TrDimmSel].
*/
- set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId, FUN_DCT,
+ set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
DRAM_ADD_DCT_PHY_CONTROL_REG, TrDimmSelStart,
- TrDimmSelEnd,(u32)dimm);
+ TrDimmSelEnd, (u32)dimm);
+
+ if (is_fam15h()) {
+ /* Set TrNibbleSel = 0
+ *
+ * TODO: Add support for x4 DIMMs
+ */
+ set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
+ DRAM_ADD_DCT_PHY_CONTROL_REG, 2,
+ 2, (u32)0);
+ }
+
/* 2. Prepare the DIMMs for write levelization using DDR3-defined
* MR commands. */
- prepareDimms(pMCTData, pDCTData,dimm, TRUE);
+ prepareDimms(pMCTstat, pDCTstat, dct, dimm, TRUE);
+
/* 3. After the DIMMs are configured, BIOS waits 40 MEMCLKs to
* satisfy DDR3-defined internal DRAM timing.
*/
- pMCTData->AgesaDelay(40);
+ if (is_fam15h())
+ precise_memclk_delay_fam15(pMCTstat, pDCTstat, dct, 40);
+ else
+ pMCTData->AgesaDelay(40);
+
/* 4. Configure the processor's DDR phy for write levelization training: */
- procConifg(pMCTData,pDCTData, dimm, pass);
+ procConfig(pMCTstat, pDCTstat, dct, dimm, pass);
+
/* 5. Begin write levelization training:
- * Program F2x[1, 0]9C_x08[WrtLevelTrEn]=1. */
- if (pDCTData->LogicalCPUID & (AMD_DR_Cx | AMD_DR_Dx))
- set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId, FUN_DCT,
+ * Program F2x[1, 0]9C_x08[WrtLvTrEn]=1. */
+ if (pDCTData->LogicalCPUID & (AMD_DR_Cx | AMD_DR_Dx | AMD_FAM15_ALL))
+ {
+ set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
DRAM_ADD_DCT_PHY_CONTROL_REG, WrtLvTrEn, WrtLvTrEn, 1);
+ }
else
{
/* Broadcast write to all D3Dbyte chipset register offset 0xc
@@ -94,7 +124,7 @@ void AgesaHwWlPhase1(sMCTStruct *pMCTData, sDCTStruct *pDCTData,
* retain value of 3:2 (Trdimmsel)
* reset bit 5 (FrzPR)
*/
- if (pDCTData->DctTrain)
+ if (dct)
{
Addl_Data_Offset=0x198;
Addl_Data_Port=0x19C;
@@ -119,29 +149,127 @@ void AgesaHwWlPhase1(sMCTStruct *pMCTData, sDCTStruct *pDCTData,
DctAccessDone, DctAccessDone)) == 0);
}
+ if (is_fam15h())
+ proc_MFENCE();
+
/* Wait 200 MEMCLKs. If executing pass 2, wait 32 MEMCLKs. */
- pMCTData->AgesaDelay(140);
+ if (is_fam15h())
+ precise_memclk_delay_fam15(pMCTstat, pDCTstat, dct, 200);
+ else
+ pMCTData->AgesaDelay(140);
+
/* Program F2x[1, 0]9C_x08[WrtLevelTrEn]=0. */
- set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId, FUN_DCT,
+ set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
DRAM_ADD_DCT_PHY_CONTROL_REG, WrtLvTrEn, WrtLvTrEn, 0);
+
/* Read from registers F2x[1, 0]9C_x[51:50] and F2x[1, 0]9C_x52
* to get the gross and fine delay settings
* for the target DIMM and save these values. */
- ByteLane = 0;
- while (ByteLane < MAX_BYTE_LANES)
- {
- getWLByteDelay(pDCTData,ByteLane, dimm);
- setWLByteDelay(pDCTData,ByteLane, dimm, 1);
- ByteLane++;
+ for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) {
+ getWLByteDelay(pDCTstat, dct, ByteLane, dimm, pass);
+ }
+
+ pDCTData->WLCriticalGrossDelayPrevPass = 0x1f;
+}
+
+void AgesaHwWlPhase2(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat,
+ u8 dct, u8 dimm, u8 pass)
+{
+ u8 ByteLane;
+ sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
+
+ if (is_fam15h()) {
+ int32_t gross_diff[MAX_BYTE_LANES];
+ int32_t cgd = pDCTData->WLCriticalGrossDelayPrevPass;
+ uint8_t index = (uint8_t)(MAX_BYTE_LANES * dimm);
+
+ /* Calculate the Critical Gross Delay */
+ for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) {
+ /* Calculate the gross delay differential for this lane */
+ gross_diff[ByteLane] = pDCTData->WLSeedGrossDelay[index+ByteLane] + pDCTData->WLGrossDelay[index+ByteLane];
+ gross_diff[ByteLane] -= pDCTData->WLSeedPreGrossDelay[index+ByteLane];
+
+ /* WrDqDqsEarly values greater than 2 are reserved */
+ if (gross_diff[ByteLane] < -2)
+ gross_diff[ByteLane] = -2;
+
+ /* Update the Critical Gross Delay */
+ if (gross_diff[ByteLane] < cgd)
+ cgd = gross_diff[ByteLane];
+ }
+
+ pDCTData->WLCriticalGrossDelayPrevPass = cgd;
+
+ /* Compensate for occasional noise/instability causing sporadic training failure */
+ for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) {
+ uint16_t total_delay_seed = ((pDCTData->WLSeedGrossDelay[index+ByteLane] & 0x1f) << 5) | (pDCTData->WLSeedFineDelay[index+ByteLane] & 0x1f);
+ uint16_t total_delay_phy = ((pDCTData->WLGrossDelay[index+ByteLane] & 0x1f) << 5) | (pDCTData->WLFineDelay[index+ByteLane] & 0x1f);
+ if (abs(total_delay_phy - total_delay_seed) > 0x20) {
+ printk(BIOS_DEBUG, "%s: overriding faulty phy value\n", __func__);
+ pDCTData->WLGrossDelay[index+ByteLane] = pDCTData->WLSeedGrossDelay[index+ByteLane];
+ pDCTData->WLFineDelay[index+ByteLane] = pDCTData->WLSeedFineDelay[index+ByteLane];
+ }
+ }
+ }
+}
+
+void AgesaHwWlPhase3(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat,
+ u8 dct, u8 dimm, u8 pass)
+{
+ u8 ByteLane;
+ sMCTStruct *pMCTData = pDCTstat->C_MCTPtr;
+ sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
+
+ if (is_fam15h()) {
+ uint32_t dword;
+ int32_t gross_diff[MAX_BYTE_LANES];
+ int32_t cgd = pDCTData->WLCriticalGrossDelayPrevPass;
+ uint8_t index = (uint8_t)(MAX_BYTE_LANES * dimm);
+
+ /* Apply offset(s) if needed */
+ if (cgd < 0) {
+ dword = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0xa8);
+ dword &= ~(0x3 << 24); /* WrDqDqsEarly = abs(cgd) */
+ dword |= ((abs(cgd) & 0x3) << 24);
+ Set_NB32_DCT(pDCTstat->dev_dct, dct, 0xa8, dword);
+
+ for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) {
+ /* Calculate the gross delay differential for this lane */
+ gross_diff[ByteLane] = pDCTData->WLSeedGrossDelay[index+ByteLane] + pDCTData->WLGrossDelay[index+ByteLane];
+ gross_diff[ByteLane] -= pDCTData->WLSeedPreGrossDelay[index+ByteLane];
+
+ /* Prevent underflow in the presence of noise / instability*/
+ if (gross_diff[ByteLane] < cgd)
+ gross_diff[ByteLane] = cgd;
+
+ pDCTData->WLGrossDelay[index+ByteLane] = (gross_diff[ByteLane] + (abs(cgd) & 0x3));
+ }
+ } else {
+ dword = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0xa8);
+ dword &= ~(0x3 << 24); /* WrDqDqsEarly = 0 */
+ Set_NB32_DCT(pDCTstat->dev_dct, dct, 0xa8, dword);
+ }
+ }
+
+ /* Write the adjusted gross and fine delay settings
+ * to the target DIMM. */
+ for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) {
+ setWLByteDelay(pDCTstat, dct, ByteLane, dimm, 1, pass);
}
/* 6. Configure DRAM Phy Control Register so that the phy stops driving
* write levelization ODT. */
- set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId, FUN_DCT,
+ set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
DRAM_ADD_DCT_PHY_CONTROL_REG, WrLvOdtEn, WrLvOdtEn, 0);
+ if (is_fam15h())
+ proc_MFENCE();
+
/* Wait 10 MEMCLKs to allow for ODT signal settling. */
- pMCTData->AgesaDelay(10);
+ if (is_fam15h())
+ precise_memclk_delay_fam15(pMCTstat, pDCTstat, dct, 10);
+ else
+ pMCTData->AgesaDelay(10);
/* 7. Program the target DIMM back to normal operation by configuring
* the following (See section 2.8.5.4.1.1
@@ -151,7 +279,7 @@ void AgesaHwWlPhase1(sMCTStruct *pMCTData, sDCTStruct *pDCTData,
* For a two DIMM system, program the Rtt value for the target DIMM
* to the normal operating termination:
*/
- prepareDimms(pMCTData, pDCTData,dimm,FALSE);
+ prepareDimms(pMCTstat, pDCTstat, dct, dimm, FALSE);
}
/*----------------------------------------------------------------------------
@@ -161,7 +289,7 @@ void AgesaHwWlPhase1(sMCTStruct *pMCTData, sDCTStruct *pDCTData,
*/
/*-----------------------------------------------------------------------------
- * u32 swapAddrBits_wl(sDCTStruct *pDCTData, u32 MRSValue)
+ * u32 swapAddrBits_wl(struct DCTStatStruc *pDCTstat, uint8_t dct, u32 MRSValue)
*
* Description:
* This function swaps the bits in MSR register value
@@ -173,12 +301,17 @@ void AgesaHwWlPhase1(sMCTStruct *pMCTData, sDCTStruct *pDCTData,
*
* ----------------------------------------------------------------------------
*/
-u32 swapAddrBits_wl(sDCTStruct *pDCTData, u32 MRSValue)
+u32 swapAddrBits_wl(struct DCTStatStruc *pDCTstat, uint8_t dct, uint32_t MRSValue)
{
+ sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
u32 tempW, tempW1;
- tempW1 = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
- FUN_DCT, DRAM_INIT, MrsChipSelStart, MrsChipSelEnd);
+ if (is_fam15h())
+ tempW1 = get_Bits(pDCTData, dct, pDCTData->NodeId,
+ FUN_DCT, DRAM_INIT, MrsChipSelStartFam15, MrsChipSelEndFam15);
+ else
+ tempW1 = get_Bits(pDCTData, dct, pDCTData->NodeId,
+ FUN_DCT, DRAM_INIT, MrsChipSelStartFam10, MrsChipSelEndFam10);
if (tempW1 & 1)
{
if ((pDCTData->Status[DCT_STATUS_OnDimmMirror]))
@@ -197,7 +330,7 @@ u32 swapAddrBits_wl(sDCTStruct *pDCTData, u32 MRSValue)
}
/*-----------------------------------------------------------------------------
- * u32 swapBankBits(sDCTStruct *pDCTData, u32 MRSValue)
+ * u32 swapBankBits(struct DCTStatStruc *pDCTstat, uint8_t dct, u32 MRSValue)
*
* Description:
* This function swaps the bits in MSR register value
@@ -209,12 +342,17 @@ u32 swapAddrBits_wl(sDCTStruct *pDCTData, u32 MRSValue)
*
* ----------------------------------------------------------------------------
*/
-u32 swapBankBits(sDCTStruct *pDCTData, u32 MRSValue)
+u32 swapBankBits(struct DCTStatStruc *pDCTstat, uint8_t dct, u32 MRSValue)
{
+ sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
u32 tempW, tempW1;
- tempW1 = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
- FUN_DCT, DRAM_INIT, MrsChipSelStart, MrsChipSelEnd);
+ if (is_fam15h())
+ tempW1 = get_Bits(pDCTData, dct, pDCTData->NodeId,
+ FUN_DCT, DRAM_INIT, MrsChipSelStartFam15, MrsChipSelEndFam15);
+ else
+ tempW1 = get_Bits(pDCTData, dct, pDCTData->NodeId,
+ FUN_DCT, DRAM_INIT, MrsChipSelStartFam10, MrsChipSelEndFam10);
if (tempW1 & 1)
{
if ((pDCTData->Status[DCT_STATUS_OnDimmMirror]))
@@ -265,7 +403,7 @@ static uint16_t unbuffered_dimm_nominal_termination_emrs(uint8_t number_of_dimms
return term;
}
-static uint16_t unbuffered_dimm_dynamic_termination_emrs(uint8_t number_of_dimms, uint8_t frequency_index, uint8_t rank_count, uint8_t rank)
+static uint16_t unbuffered_dimm_dynamic_termination_emrs(uint8_t number_of_dimms, uint8_t frequency_index, uint8_t rank_count)
{
uint16_t term;
@@ -296,27 +434,27 @@ static uint16_t unbuffered_dimm_dynamic_termination_emrs(uint8_t number_of_dimms
*
* Description:
* This function prepares DIMMS for training
- *
- * Parameters:
- * IN OUT *DCTData - Pointer to buffer with information about each DCT
- * *SPDData - Pointer to buffer with information about each DIMMs
- * SPD information
- * *MCTData - Pointer to buffer with runtime parameters,
- * IN Dimm - Logical DIMM number
- * WL - indicates if the routine is used for Write levelization
- * training
- *
- * OUT
- *
+ * Fam10h: BKDG Rev. 3.62 section 2.8.9.9.1
+ * Fam15h: BKDG Rev. 3.14 section 2.10.5.8.1
* ----------------------------------------------------------------------------
*/
-void prepareDimms(sMCTStruct *pMCTData, sDCTStruct *pDCTData, u8 dimm, BOOL wl)
+void prepareDimms(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat,
+ u8 dct, u8 dimm, BOOL wl)
{
u32 tempW, tempW1, tempW2, MrsBank;
u8 rank, currDimm, MemClkFreq;
+ sMCTStruct *pMCTData = pDCTstat->C_MCTPtr;
+ sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
+ uint8_t package_type = mctGet_NVbits(NV_PACK_TYPE);
+ uint8_t number_of_dimms = pDCTData->MaxDimmsInstalled;
- MemClkFreq = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
+ if (is_fam15h()) {
+ MemClkFreq = get_Bits(pDCTData, dct, pDCTData->NodeId,
+ FUN_DCT, DRAM_CONFIG_HIGH, 0, 4);
+ } else {
+ MemClkFreq = get_Bits(pDCTData, dct, pDCTData->NodeId,
FUN_DCT, DRAM_CONFIG_HIGH, 0, 2);
+ }
/* Configure the DCT to send initialization MR commands to the target DIMM
* by programming the F2x[1,0]7C register using the following steps.
*/
@@ -324,52 +462,95 @@ void prepareDimms(sMCTStruct *pMCTData, sDCTStruct *pDCTData, u8 dimm, BOOL wl)
while ((rank < pDCTData->DimmRanks[dimm]) && (rank < 2))
{
/* Program F2x[1, 0]7C[MrsChipSel[2:0]] for the current rank to be trained. */
- set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
- DRAM_INIT, MrsChipSelStart, MrsChipSelEnd, dimm*2+rank);
+ if (is_fam15h())
+ set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
+ DRAM_INIT, MrsChipSelStartFam15, MrsChipSelEndFam15, dimm*2+rank);
+ else
+ set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
+ DRAM_INIT, MrsChipSelStartFam10, MrsChipSelEndFam10, dimm*2+rank);
+
/* Program F2x[1, 0]7C[MrsBank[2:0]] for the appropriate internal DRAM
* register that defines the required DDR3-defined function for write
* levelization.
*/
- MrsBank = swapBankBits(pDCTData,1);
- set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
- DRAM_INIT, MrsBankStart, MrsBankEnd, MrsBank);
+ MrsBank = swapBankBits(pDCTstat, dct, 1);
+ if (is_fam15h())
+ set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
+ DRAM_INIT, MrsBankStartFam15, MrsBankEndFam15, MrsBank);
+ else
+ set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
+ DRAM_INIT, MrsBankStartFam10, MrsBankEndFam10, MrsBank);
+
/* Program F2x[1, 0]7C[MrsAddress[15:0]] to the required DDR3-defined function
* for write levelization.
*/
tempW = 0;/* DLL_DIS = 0, DIC = 0, AL = 0, TDQS = 0 */
- /* Set TDQS=1b for x8 DIMM, TDQS=0b for x4 DIMM, when mixed x8 & x4 */
- tempW2 = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
- FUN_DCT, DRAM_CONFIG_HIGH, RDqsEn, RDqsEn);
- if (tempW2)
- {
- if (pDCTData->DimmX8Present[dimm])
- tempW |= 0x800;
+ /* Retrieve normal settings of the MRS control word and clear Rtt_Nom */
+ if (is_fam15h()) {
+ tempW = mct_MR1(pMCTstat, pDCTstat, dct, dimm*2+rank) & 0xffff;
+ tempW &= ~(0x0244);
+ } else {
+ /* Set TDQS=1b for x8 DIMM, TDQS=0b for x4 DIMM, when mixed x8 & x4 */
+ tempW2 = get_Bits(pDCTData, dct, pDCTData->NodeId,
+ FUN_DCT, DRAM_CONFIG_HIGH, RDqsEn, RDqsEn);
+ if (tempW2)
+ {
+ if (pDCTData->DimmX8Present[dimm])
+ tempW |= 0x800;
+ }
}
/* determine Rtt_Nom for WL & Normal mode */
- if (pDCTData->Status[DCT_STATUS_REGISTERED]) {
- tempW1 = RttNomTargetRegDimm(pMCTData, pDCTData, dimm, wl, MemClkFreq, rank);
- } else {
+ if (is_fam15h()) {
if (wl) {
- if (rank == 0) {
- /* Get Rtt_WR for the current DIMM and rank */
- uint16_t dynamic_term = unbuffered_dimm_dynamic_termination_emrs(pDCTData->MaxDimmsInstalled, MemClkFreq, pDCTData->DimmRanks[dimm], rank);
-
- /* Convert dynamic termination code to corresponding nominal termination code */
- if (dynamic_term == 0x200)
- tempW1 = 0x04;
- else if (dynamic_term == 0x400)
- tempW1 = 0x40;
- else
- tempW1 = 0x0;
+ if (number_of_dimms > 1) {
+ if (rank == 0) {
+ /* Get Rtt_WR for the current DIMM and rank */
+ tempW2 = fam15_rttwr(pDCTstat, dct, dimm, rank, package_type);
+ } else {
+ tempW2 = fam15_rttnom(pDCTstat, dct, dimm, rank, package_type);
+ }
} else {
- tempW1 = unbuffered_dimm_nominal_termination_emrs(pDCTData->MaxDimmsInstalled, MemClkFreq, pDCTData->DimmRanks[dimm], rank);
+ tempW2 = fam15_rttnom(pDCTstat, dct, dimm, rank, package_type);
}
} else {
- tempW1 = unbuffered_dimm_nominal_termination_emrs(pDCTData->MaxDimmsInstalled, MemClkFreq, pDCTData->DimmRanks[dimm], rank);
+ tempW2 = fam15_rttnom(pDCTstat, dct, dimm, rank, package_type);
+ }
+ tempW1 = 0;
+ tempW1 |= ((tempW2 & 0x4) >> 2) << 9;
+ tempW1 |= ((tempW2 & 0x2) >> 1) << 6;
+ tempW1 |= ((tempW2 & 0x1) >> 0) << 2;
+ } else {
+ if (pDCTData->Status[DCT_STATUS_REGISTERED]) {
+ tempW1 = RttNomTargetRegDimm(pMCTData, pDCTData, dimm, wl, MemClkFreq, rank);
+ } else {
+ if (wl) {
+ if (number_of_dimms > 1) {
+ if (rank == 0) {
+ /* Get Rtt_WR for the current DIMM and rank */
+ uint16_t dynamic_term = unbuffered_dimm_dynamic_termination_emrs(pDCTData->MaxDimmsInstalled, MemClkFreq, pDCTData->DimmRanks[dimm]);
+
+ /* Convert dynamic termination code to corresponding nominal termination code */
+ if (dynamic_term == 0x200)
+ tempW1 = 0x04;
+ else if (dynamic_term == 0x400)
+ tempW1 = 0x40;
+ else
+ tempW1 = 0x0;
+ } else {
+ tempW1 = unbuffered_dimm_nominal_termination_emrs(pDCTData->MaxDimmsInstalled, MemClkFreq, pDCTData->DimmRanks[dimm], rank);
+ }
+ } else {
+ tempW1 = unbuffered_dimm_nominal_termination_emrs(pDCTData->MaxDimmsInstalled, MemClkFreq, pDCTData->DimmRanks[dimm], rank);
+ }
+ } else {
+ tempW1 = unbuffered_dimm_nominal_termination_emrs(pDCTData->MaxDimmsInstalled, MemClkFreq, pDCTData->DimmRanks[dimm], rank);
+ }
}
}
+
+ /* Apply Rtt_Nom to the MRS control word */
tempW=tempW|tempW1;
/* All ranks of the target DIMM are set to write levelization mode. */
@@ -389,68 +570,105 @@ void prepareDimms(sMCTStruct *pMCTData, sDCTStruct *pDCTData, u8 dimm, BOOL wl)
tempW = bitTestSet(tempW1, Qoff);
}
}
- /* Program MrsAddress[5,1]=output driver impedance control (DIC):
- * based on F2x[1,0]84[DrvImpCtrl]
- */
- tempW1 = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
- FUN_DCT, DRAM_MRS_REGISTER, DrvImpCtrlStart, DrvImpCtrlEnd);
+
+ /* Program MrsAddress[5,1]=output driver impedance control (DIC) */
+ if (is_fam15h()) {
+ tempW1 = fam15_dimm_dic(pDCTstat, dct, dimm, rank, package_type);
+ } else {
+ /* Read DIC from F2x[1,0]84[DrvImpCtrl] */
+ tempW1 = get_Bits(pDCTData, dct, pDCTData->NodeId,
+ FUN_DCT, DRAM_MRS_REGISTER, DrvImpCtrlStart, DrvImpCtrlEnd);
+ }
+
+ /* Apply DIC to the MRS control word */
if (bitTest(tempW1, 1))
tempW = bitTestSet(tempW, 5);
if (bitTest(tempW1, 0))
tempW = bitTestSet(tempW, 1);
- tempW = swapAddrBits_wl(pDCTData, tempW);
+ tempW = swapAddrBits_wl(pDCTstat, dct, tempW);
+
+ if (is_fam15h())
+ set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
+ DRAM_INIT, MrsAddressStartFam15, MrsAddressEndFam15, tempW);
+ else
+ set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
+ DRAM_INIT, MrsAddressStartFam10, MrsAddressEndFam10, tempW);
- set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
- DRAM_INIT, MrsAddressStart, MrsAddressEnd, tempW);
/* Program F2x[1, 0]7C[SendMrsCmd]=1 to initiate the command to
* the specified DIMM.
*/
- set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
+ set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
DRAM_INIT, SendMrsCmd, SendMrsCmd, 1);
/* Wait for F2x[1, 0]7C[SendMrsCmd] to be cleared by hardware. */
- while ((get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
+ while ((get_Bits(pDCTData, dct, pDCTData->NodeId,
FUN_DCT, DRAM_INIT, SendMrsCmd, SendMrsCmd)) == 0x1)
{
}
+
/* Program F2x[1, 0]7C[MrsBank[2:0]] for the appropriate internal DRAM
* register that defines the required DDR3-defined function for Rtt_WR.
*/
- MrsBank = swapBankBits(pDCTData,2);
- set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
- DRAM_INIT, MrsBankStart, MrsBankEnd, MrsBank);
+ MrsBank = swapBankBits(pDCTstat, dct, 2);
+ if (is_fam15h())
+ set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
+ DRAM_INIT, MrsBankStartFam15, MrsBankEndFam15, MrsBank);
+ else
+ set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
+ DRAM_INIT, MrsBankStartFam10, MrsBankEndFam10, MrsBank);
+
/* Program F2x[1, 0]7C[MrsAddress[15:0]] to the required DDR3-defined function
* for Rtt_WR (DRAMTermDyn).
*/
tempW = 0;/* PASR = 0,*/
- /* program MrsAddress[7,6,5:3]=SRT,ASR,CWL,
- * based on F2x[1,0]84[19,18,22:20]=,SRT,ASR,Tcwl */
- tempW1 = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
- FUN_DCT, DRAM_MRS_REGISTER, PCI_MIN_LOW, PCI_MAX_HIGH);
- if (bitTest(tempW1,19))
- {tempW = bitTestSet(tempW, 7);}
- if (bitTest(tempW1,18))
- {tempW = bitTestSet(tempW, 6);}
- /* tempW=tempW|(((tempW1>>20)&0x7)<<3); */
- tempW=tempW|((tempW1&0x00700000)>>17);
- /* workaround for DR-B0 */
- if ((pDCTData->LogicalCPUID & AMD_DR_Bx) && (pDCTData->Status[DCT_STATUS_REGISTERED]))
- tempW+=0x8;
+
+ /* Retrieve normal settings of the MRS control word and clear Rtt_WR */
+ if (is_fam15h()) {
+ tempW = mct_MR2(pMCTstat, pDCTstat, dct, dimm*2+rank) & 0xffff;
+ tempW &= ~(0x0600);
+ } else {
+ /* program MrsAddress[7,6,5:3]=SRT,ASR,CWL,
+ * based on F2x[1,0]84[19,18,22:20]=,SRT,ASR,Tcwl */
+ tempW1 = get_Bits(pDCTData, dct, pDCTData->NodeId,
+ FUN_DCT, DRAM_MRS_REGISTER, PCI_MIN_LOW, PCI_MAX_HIGH);
+ if (bitTest(tempW1,19))
+ {tempW = bitTestSet(tempW, 7);}
+ if (bitTest(tempW1,18))
+ {tempW = bitTestSet(tempW, 6);}
+ /* tempW=tempW|(((tempW1>>20)&0x7)<<3); */
+ tempW=tempW|((tempW1&0x00700000)>>17);
+ /* workaround for DR-B0 */
+ if ((pDCTData->LogicalCPUID & AMD_DR_Bx) && (pDCTData->Status[DCT_STATUS_REGISTERED]))
+ tempW+=0x8;
+ }
+
/* determine Rtt_WR for WL & Normal mode */
- if (pDCTData->Status[DCT_STATUS_REGISTERED])
- tempW1 = RttWrRegDimm(pMCTData, pDCTData, dimm, wl, MemClkFreq, rank);
- else
- tempW1 = unbuffered_dimm_dynamic_termination_emrs(pDCTData->MaxDimmsInstalled, MemClkFreq, pDCTData->DimmRanks[dimm], rank);
+ if (is_fam15h()) {
+ tempW1 = (fam15_rttwr(pDCTstat, dct, dimm, rank, package_type) << 9);
+ } else {
+ if (pDCTData->Status[DCT_STATUS_REGISTERED])
+ tempW1 = RttWrRegDimm(pMCTData, pDCTData, dimm, wl, MemClkFreq, rank);
+ else
+ tempW1 = unbuffered_dimm_dynamic_termination_emrs(pDCTData->MaxDimmsInstalled, MemClkFreq, pDCTData->DimmRanks[dimm]);
+ }
+
+ /* Apply Rtt_WR to the MRS control word */
tempW=tempW|tempW1;
- tempW = swapAddrBits_wl(pDCTData,tempW);
- set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
- DRAM_INIT, MrsAddressStart, MrsAddressEnd, tempW);
+ tempW = swapAddrBits_wl(pDCTstat, dct, tempW);
+ if (is_fam15h())
+ set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
+ DRAM_INIT, MrsAddressStartFam15, MrsAddressEndFam15, tempW);
+ else
+ set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
+ DRAM_INIT, MrsAddressStartFam10, MrsAddressEndFam10, tempW);
+
/* Program F2x[1, 0]7C[SendMrsCmd]=1 to initiate the command to
the specified DIMM.*/
- set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
+ set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
DRAM_INIT, SendMrsCmd, SendMrsCmd, 1);
+
/* Wait for F2x[1, 0]7C[SendMrsCmd] to be cleared by hardware. */
- while ((get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
+ while ((get_Bits(pDCTData, dct, pDCTData->NodeId,
FUN_DCT, DRAM_INIT, SendMrsCmd, SendMrsCmd)) == 0x1)
{
}
@@ -469,97 +687,163 @@ void prepareDimms(sMCTStruct *pMCTData, sDCTStruct *pDCTData, u8 dimm, BOOL wl)
rank = 0;
while ((rank < pDCTData->DimmRanks[currDimm]) && (rank < 2))
{
-
/* Program F2x[1, 0]7C[MrsChipSel[2:0]] for the current rank
* to be trained.
*/
- set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
- FUN_DCT, DRAM_INIT, MrsChipSelStart, MrsChipSelEnd, currDimm*2+rank);
+ if (is_fam15h())
+ set_Bits(pDCTData, dct, pDCTData->NodeId,
+ FUN_DCT, DRAM_INIT, MrsChipSelStartFam15, MrsChipSelEndFam15, currDimm*2+rank);
+ else
+ set_Bits(pDCTData, dct, pDCTData->NodeId,
+ FUN_DCT, DRAM_INIT, MrsChipSelStartFam10, MrsChipSelEndFam10, currDimm*2+rank);
+
/* Program F2x[1, 0]7C[MrsBank[2:0]] for the appropriate internal
* DRAM register that defines the required DDR3-defined function
* for write levelization.
*/
- MrsBank = swapBankBits(pDCTData,1);
- set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
- FUN_DCT, DRAM_INIT, MrsBankStart, MrsBankEnd, MrsBank);
+ MrsBank = swapBankBits(pDCTstat, dct, 1);
+ if (is_fam15h())
+ set_Bits(pDCTData, dct, pDCTData->NodeId,
+ FUN_DCT, DRAM_INIT, MrsBankStartFam15, MrsBankEndFam15, MrsBank);
+ else
+ set_Bits(pDCTData, dct, pDCTData->NodeId,
+ FUN_DCT, DRAM_INIT, MrsBankStartFam10, MrsBankEndFam10, MrsBank);
+
/* Program F2x[1, 0]7C[MrsAddress[15:0]] to the required
* DDR3-defined function for write levelization.
*/
tempW = 0;/* DLL_DIS = 0, DIC = 0, AL = 0, TDQS = 0, Level=0, Qoff=0 */
- /* Set TDQS=1b for x8 DIMM, TDQS=0b for x4 DIMM, when mixed x8 & x4 */
- tempW2 = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
- FUN_DCT, DRAM_CONFIG_HIGH, RDqsEn, RDqsEn);
- if (tempW2)
- {
- if (pDCTData->DimmX8Present[currDimm])
- tempW |= 0x800;
+ /* Retrieve normal settings of the MRS control word and clear Rtt_Nom */
+ if (is_fam15h()) {
+ tempW = mct_MR1(pMCTstat, pDCTstat, dct, dimm*2+rank) & 0xffff;
+ tempW &= ~(0x0244);
+ } else {
+ /* Set TDQS=1b for x8 DIMM, TDQS=0b for x4 DIMM, when mixed x8 & x4 */
+ tempW2 = get_Bits(pDCTData, dct, pDCTData->NodeId,
+ FUN_DCT, DRAM_CONFIG_HIGH, RDqsEn, RDqsEn);
+ if (tempW2)
+ {
+ if (pDCTData->DimmX8Present[currDimm])
+ tempW |= 0x800;
+ }
}
/* determine Rtt_Nom for WL & Normal mode */
- if (pDCTData->Status[DCT_STATUS_REGISTERED])
- tempW1 = RttNomNonTargetRegDimm(pMCTData, pDCTData, currDimm, wl, MemClkFreq, rank);
- else
- tempW1 = unbuffered_dimm_nominal_termination_emrs(pDCTData->MaxDimmsInstalled, MemClkFreq, pDCTData->DimmRanks[currDimm], rank);
+ if (is_fam15h()) {
+ tempW2 = fam15_rttnom(pDCTstat, dct, dimm, rank, package_type);
+ tempW1 = 0;
+ tempW1 |= ((tempW2 & 0x4) >> 2) << 9;
+ tempW1 |= ((tempW2 & 0x2) >> 1) << 6;
+ tempW1 |= ((tempW2 & 0x1) >> 0) << 2;
+ } else {
+ if (pDCTData->Status[DCT_STATUS_REGISTERED])
+ tempW1 = RttNomNonTargetRegDimm(pMCTData, pDCTData, currDimm, wl, MemClkFreq, rank);
+ else
+ tempW1 = unbuffered_dimm_nominal_termination_emrs(pDCTData->MaxDimmsInstalled, MemClkFreq, pDCTData->DimmRanks[currDimm], rank);
+ }
+
+ /* Apply Rtt_Nom to the MRS control word */
tempW=tempW|tempW1;
- /* program MrsAddress[5,1]=output driver impedance control (DIC):
- * based on F2x[1,0]84[DrvImpCtrl] */
- tempW1 = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
- FUN_DCT, DRAM_MRS_REGISTER, DrvImpCtrlStart, DrvImpCtrlEnd);
+
+ /* Program MrsAddress[5,1]=output driver impedance control (DIC) */
+ if (is_fam15h()) {
+ tempW1 = fam15_dimm_dic(pDCTstat, dct, dimm, rank, package_type);
+ } else {
+ /* Read DIC from F2x[1,0]84[DrvImpCtrl] */
+ tempW1 = get_Bits(pDCTData, dct, pDCTData->NodeId,
+ FUN_DCT, DRAM_MRS_REGISTER, DrvImpCtrlStart, DrvImpCtrlEnd);
+ }
+
+ /* Apply DIC to the MRS control word */
if (bitTest(tempW1,1))
{tempW = bitTestSet(tempW, 5);}
if (bitTest(tempW1,0))
{tempW = bitTestSet(tempW, 1);}
- tempW = swapAddrBits_wl(pDCTData,tempW);
- set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
- FUN_DCT, DRAM_INIT, MrsAddressStart, MrsAddressEnd, tempW);
+
+ tempW = swapAddrBits_wl(pDCTstat, dct, tempW);
+
+ if (is_fam15h())
+ set_Bits(pDCTData, dct, pDCTData->NodeId,
+ FUN_DCT, DRAM_INIT, MrsAddressStartFam15, MrsAddressEndFam15, tempW);
+ else
+ set_Bits(pDCTData, dct, pDCTData->NodeId,
+ FUN_DCT, DRAM_INIT, MrsAddressStartFam10, MrsAddressEndFam10, tempW);
+
/* Program F2x[1, 0]7C[SendMrsCmd]=1 to initiate the command
* to the specified DIMM.
*/
- set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
+ set_Bits(pDCTData, dct, pDCTData->NodeId,
FUN_DCT, DRAM_INIT, SendMrsCmd, SendMrsCmd, 1);
+
/* Wait for F2x[1, 0]7C[SendMrsCmd] to be cleared by hardware. */
- while ((get_Bits(pDCTData, pDCTData->CurrDct,
+ while ((get_Bits(pDCTData, dct,
pDCTData->NodeId, FUN_DCT, DRAM_INIT,
SendMrsCmd, SendMrsCmd)) == 1);
+
/* Program F2x[1, 0]7C[MrsBank[2:0]] for the appropriate internal DRAM
* register that defines the required DDR3-defined function for Rtt_WR.
*/
- MrsBank = swapBankBits(pDCTData,2);
- set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
- DRAM_INIT, MrsBankStart, MrsBankEnd, MrsBank);
+ MrsBank = swapBankBits(pDCTstat, dct, 2);
+ if (is_fam15h())
+ set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
+ DRAM_INIT, MrsBankStartFam15, MrsBankEndFam15, MrsBank);
+ else
+ set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
+ DRAM_INIT, MrsBankStartFam10, MrsBankEndFam10, MrsBank);
+
/* Program F2x[1, 0]7C[MrsAddress[15:0]] to the required DDR3-defined function
* for Rtt_WR (DRAMTermDyn).
*/
tempW = 0;/* PASR = 0,*/
- /* program MrsAddress[7,6,5:3]=SRT,ASR,CWL,
- * based on F2x[1,0]84[19,18,22:20]=,SRT,ASR,Tcwl */
- tempW1 = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
- FUN_DCT, DRAM_MRS_REGISTER, PCI_MIN_LOW, PCI_MAX_HIGH);
- if (bitTest(tempW1,19))
- {tempW = bitTestSet(tempW, 7);}
- if (bitTest(tempW1,18))
- {tempW = bitTestSet(tempW, 6);}
- /* tempW=tempW|(((tempW1>>20)&0x7)<<3); */
- tempW=tempW|((tempW1&0x00700000)>>17);
- /* workaround for DR-B0 */
- if ((pDCTData->LogicalCPUID & AMD_DR_Bx) && (pDCTData->Status[DCT_STATUS_REGISTERED]))
- tempW+=0x8;
+
+ /* Retrieve normal settings of the MRS control word and clear Rtt_WR */
+ if (is_fam15h()) {
+ tempW = mct_MR2(pMCTstat, pDCTstat, dct, dimm*2+rank) & 0xffff;
+ tempW &= ~(0x0600);
+ } else {
+ /* program MrsAddress[7,6,5:3]=SRT,ASR,CWL,
+ * based on F2x[1,0]84[19,18,22:20]=,SRT,ASR,Tcwl */
+ tempW1 = get_Bits(pDCTData, dct, pDCTData->NodeId,
+ FUN_DCT, DRAM_MRS_REGISTER, PCI_MIN_LOW, PCI_MAX_HIGH);
+ if (bitTest(tempW1,19))
+ {tempW = bitTestSet(tempW, 7);}
+ if (bitTest(tempW1,18))
+ {tempW = bitTestSet(tempW, 6);}
+ /* tempW=tempW|(((tempW1>>20)&0x7)<<3); */
+ tempW=tempW|((tempW1&0x00700000)>>17);
+ /* workaround for DR-B0 */
+ if ((pDCTData->LogicalCPUID & AMD_DR_Bx) && (pDCTData->Status[DCT_STATUS_REGISTERED]))
+ tempW+=0x8;
+ }
+
/* determine Rtt_WR for WL & Normal mode */
- if (pDCTData->Status[DCT_STATUS_REGISTERED])
- tempW1 = RttWrRegDimm(pMCTData, pDCTData, currDimm, wl, MemClkFreq, rank);
- else
- tempW1 = unbuffered_dimm_dynamic_termination_emrs(pDCTData->MaxDimmsInstalled, MemClkFreq, pDCTData->DimmRanks[currDimm], rank);
+ if (is_fam15h()) {
+ tempW1 = (fam15_rttwr(pDCTstat, dct, dimm, rank, package_type) << 9);
+ } else {
+ if (pDCTData->Status[DCT_STATUS_REGISTERED])
+ tempW1 = RttWrRegDimm(pMCTData, pDCTData, currDimm, wl, MemClkFreq, rank);
+ else
+ tempW1 = unbuffered_dimm_dynamic_termination_emrs(pDCTData->MaxDimmsInstalled, MemClkFreq, pDCTData->DimmRanks[currDimm]);
+ }
+
+ /* Apply Rtt_WR to the MRS control word */
tempW=tempW|tempW1;
- tempW = swapAddrBits_wl(pDCTData,tempW);
- set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
- DRAM_INIT, MrsAddressStart, MrsAddressEnd, tempW);
+ tempW = swapAddrBits_wl(pDCTstat, dct, tempW);
+ if (is_fam15h())
+ set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
+ DRAM_INIT, MrsAddressStartFam15, MrsAddressEndFam15, tempW);
+ else
+ set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
+ DRAM_INIT, MrsAddressStartFam10, MrsAddressEndFam10, tempW);
+
/* Program F2x[1, 0]7C[SendMrsCmd]=1 to initiate the command to
the specified DIMM.*/
- set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
+ set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
DRAM_INIT, SendMrsCmd, SendMrsCmd, 1);
+
/* Wait for F2x[1, 0]7C[SendMrsCmd] to be cleared by hardware. */
- while ((get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
+ while ((get_Bits(pDCTData, dct, pDCTData->NodeId,
FUN_DCT, DRAM_INIT, SendMrsCmd, SendMrsCmd)) == 0x1)
{
}
@@ -583,29 +867,60 @@ void prepareDimms(sMCTStruct *pMCTData, sDCTStruct *pDCTData, u8 dimm, BOOL wl)
* OUT
* ----------------------------------------------------------------------------
*/
-void programODT(sMCTStruct *pMCTData, sDCTStruct *pDCTData, u8 dimm)
+void programODT(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, uint8_t dct, u8 dimm)
{
+ sMCTStruct *pMCTData = pDCTstat->C_MCTPtr;
+ sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
+
u8 WrLvOdt1=0;
- if (pDCTData->Status[DCT_STATUS_REGISTERED] == 0) {
- if ((pDCTData->DctCSPresent & 0x05) == 0x05) {
- WrLvOdt1 = 0x03;
- } else if (bitTest((u32)pDCTData->DctCSPresent,(u8)(dimm*2+1))) {
- WrLvOdt1 = (u8)bitTestSet(WrLvOdt1, dimm+2);
+ if (is_fam15h()) {
+ /* Convert DIMM number to CS */
+ uint32_t dword;
+ uint8_t cs;
+ uint8_t rank = 0;
+
+ cs = (dimm * 2) + rank;
+
+ /* Fetch preprogammed ODT pattern from configuration registers */
+ dword = Get_NB32_DCT(pDCTstat->dev_dct, dct, ((cs>3)?0x23c:0x238));
+ if ((cs == 7) || (cs == 3))
+ WrLvOdt1 = ((dword >> 24) & 0xf);
+ else if ((cs == 6) || (cs == 2))
+ WrLvOdt1 = ((dword >> 16) & 0xf);
+ else if ((cs == 5) || (cs == 1))
+ WrLvOdt1 = ((dword >> 8) & 0xf);
+ else if ((cs == 4) || (cs == 0))
+ WrLvOdt1 = (dword & 0xf);
+ } else {
+ if (pDCTData->Status[DCT_STATUS_REGISTERED] == 0) {
+ if ((pDCTData->DctCSPresent & 0x05) == 0x05) {
+ WrLvOdt1 = 0x03;
+ } else if (bitTest((u32)pDCTData->DctCSPresent,(u8)(dimm*2+1))) {
+ WrLvOdt1 = (u8)bitTestSet(WrLvOdt1, dimm+2);
+ } else {
+ WrLvOdt1 = (u8)bitTestSet(WrLvOdt1, dimm);
+ }
} else {
- WrLvOdt1 = (u8)bitTestSet(WrLvOdt1, dimm);
+ WrLvOdt1 = WrLvOdtRegDimm(pMCTData, pDCTData, dimm);
}
- } else {
- WrLvOdt1 = WrLvOdtRegDimm(pMCTData, pDCTData, dimm);
}
- set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId, FUN_DCT,
+ set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
DRAM_ADD_DCT_PHY_CONTROL_REG, 8, 11, (u32)WrLvOdt1);
}
+#ifdef UNUSED_CODE
+static uint16_t fam15h_next_lowest_memclk_freq(uint16_t memclk_freq)
+{
+ uint16_t fam15h_next_lowest_freq_tab[] = {0, 0, 0, 0, 0x4, 0, 0x4, 0, 0, 0, 0x6, 0, 0, 0, 0xa, 0, 0, 0, 0xe, 0, 0, 0, 0x12};
+ return fam15h_next_lowest_freq_tab[memclk_freq];
+}
+#endif
+
/*-----------------------------------------------------------------------------
- * void procConifg(MCTStruct *MCTData,DCTStruct *DCTData, u8 Dimm, u8 Pass)
+ * void procConfig(MCTStruct *MCTData,DCTStruct *DCTData, u8 Dimm, u8 Pass)
*
* Description:
* This function programs the ODT values for the NB
@@ -618,31 +933,43 @@ void programODT(sMCTStruct *pMCTData, sDCTStruct *pDCTData, u8 dimm)
* OUT
* ----------------------------------------------------------------------------
*/
-void procConifg(sMCTStruct *pMCTData,sDCTStruct *pDCTData, u8 dimm, u8 pass)
+void procConfig(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, uint8_t dct, u8 dimm, u8 pass)
{
- u8 ByteLane, Seed_Gross, Seed_Fine, MemClkFreq;
+ u8 ByteLane, MemClkFreq;
+ int32_t Seed_Gross;
+ int32_t Seed_Fine;
+ uint8_t Seed_PreGross;
u32 Value, Addr;
u16 Addl_Data_Offset, Addl_Data_Port;
- u16 freq_tab[] = {400, 533, 667, 800};
+ sMCTStruct *pMCTData = pDCTstat->C_MCTPtr;
+ sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
+ u16 fam10h_freq_tab[] = {400, 533, 667, 800};
+ uint16_t fam15h_freq_tab[] = {0, 0, 0, 0, 333, 0, 400, 0, 0, 0, 533, 0, 0, 0, 667, 0, 0, 0, 800, 0, 0, 0, 933};
- /* MemClkFreq: 3: 400MHz; 4: 533MHz; 5: 667MHz; 6: 800MHz */
- MemClkFreq = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
- FUN_DCT, DRAM_CONFIG_HIGH, 0, 2);
+ if (is_fam15h()) {
+ /* MemClkFreq: 0x4: 333MHz; 0x6: 400MHz; 0xa: 533MHz; 0xe: 667MHz; 0x12: 800MHz; 0x16: 933MHz */
+ MemClkFreq = get_Bits(pDCTData, dct, pDCTData->NodeId,
+ FUN_DCT, DRAM_CONFIG_HIGH, 0, 4);
+ } else {
+ /* MemClkFreq: 3: 400MHz; 4: 533MHz; 5: 667MHz; 6: 800MHz */
+ MemClkFreq = get_Bits(pDCTData, dct, pDCTData->NodeId,
+ FUN_DCT, DRAM_CONFIG_HIGH, 0, 2);
+ }
/* Program F2x[1, 0]9C_x08[WrLvOdt[3:0]] to the proper ODT settings for the
* current memory subsystem configuration.
*/
- programODT(pMCTData, pDCTData, dimm);
+ programODT(pMCTstat, pDCTstat, dct, dimm);
/* Program F2x[1,0]9C_x08[WrLvOdtEn]=1 */
- if (pDCTData->LogicalCPUID & (AMD_DR_Cx | AMD_DR_Dx)) {
- set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId, FUN_DCT,
+ if (pDCTData->LogicalCPUID & (AMD_DR_Cx | AMD_DR_Dx | AMD_FAM15_ALL)) {
+ set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
DRAM_ADD_DCT_PHY_CONTROL_REG, WrLvOdtEn, WrLvOdtEn, (u32)1);
}
else
{
/* Program WrLvOdtEn=1 through set bit 12 of D3CSODT reg offset 0 for Rev.B */
- if (pDCTData->DctTrain)
+ if (dct)
{
Addl_Data_Offset=0x198;
Addl_Data_Port=0x19C;
@@ -665,33 +992,94 @@ void procConifg(sMCTStruct *pMCTData,sDCTStruct *pDCTData, u8 dimm, u8 pass)
DctAccessDone, DctAccessDone)) == 0);
}
+ if (is_fam15h())
+ proc_MFENCE();
+
/* Wait 10 MEMCLKs to allow for ODT signal settling. */
- pMCTData->AgesaDelay(10);
+ if (is_fam15h())
+ precise_memclk_delay_fam15(pMCTstat, pDCTstat, dct, 10);
+ else
+ pMCTData->AgesaDelay(10);
+
+ /* Program write levelling seed values */
if (pass == 1)
{
- if (pDCTData->Status[DCT_STATUS_REGISTERED])
- {
- if(pDCTData->RegMan1Present & ((1<<(dimm*2+pDCTData->DctTrain))))
+ /* Pass 1 */
+ if (is_fam15h()) {
+ uint8_t AddrCmdPrelaunch = 0; /* TODO: Fetch the correct value from RC2[0] */
+ uint8_t package_type = mctGet_NVbits(NV_PACK_TYPE);
+ uint16_t Seed_Total = 0;
+ if (package_type == PT_GR) {
+ /* Socket G34: Fam15h BKDG v3.14 Table 96 */
+ if (pDCTData->Status[DCT_STATUS_REGISTERED]) {
+ Seed_Total = 0x41;
+ } else if (pDCTData->Status[DCT_STATUS_LOAD_REDUCED]) {
+ Seed_Total = 0x0;
+ } else {
+ Seed_Total = 0xf;
+ }
+ } else if (package_type == PT_C3) {
+ /* Socket C32: Fam15h BKDG v3.14 Table 97 */
+ if (pDCTData->Status[DCT_STATUS_REGISTERED]) {
+ Seed_Total = 0x3e;
+ } else if (pDCTData->Status[DCT_STATUS_LOAD_REDUCED]) {
+ Seed_Total = 0x0;
+ } else {
+ Seed_Total = 0x12;
+ }
+ } else if (package_type == PT_M2) {
+ /* Socket AM3: Fam15h BKDG v3.14 Table 98 */
+ Seed_Total = 0xf;
+ }
+ if (pDCTData->Status[DCT_STATUS_REGISTERED])
+ Seed_Total += ((AddrCmdPrelaunch)?0x10:0x0);
+
+ /* Adjust seed for the minimum platform supported frequency */
+ Seed_Total = (int32_t) (((((int64_t) Seed_Total) *
+ fam15h_freq_tab[MemClkFreq] * 100) / (mctGet_NVbits(NV_MIN_MEMCLK) * 100)));
+
+ Seed_Gross = (Seed_Total >> 5) & 0x1f;
+ Seed_Fine = Seed_Total & 0x1f;
+
+ /* Save seed values for later use */
+ for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) {
+ pDCTData->WLSeedGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Gross;
+ pDCTData->WLSeedFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Fine;
+
+ if (Seed_Gross == 0)
+ Seed_PreGross = 0;
+ else if (Seed_Gross & 0x1)
+ Seed_PreGross = 1;
+ else
+ Seed_PreGross = 2;
+
+ pDCTData->WLSeedPreGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_PreGross;
+ }
+ } else {
+ if (pDCTData->Status[DCT_STATUS_REGISTERED])
{
- Seed_Gross = 0x02;
- Seed_Fine = 0x16;
+ if(pDCTData->RegMan1Present & ((1<<(dimm*2+dct))))
+ {
+ Seed_Gross = 0x02;
+ Seed_Fine = 0x16;
+ }
+ else
+ {
+ Seed_Gross = 0x02;
+ Seed_Fine = 0x00;
+ }
}
else
{
- Seed_Gross = 0x02;
- Seed_Fine = 0x00;
- }
- }
- else
- {
- if (MemClkFreq == 6) {
- /* DDR-800 */
- Seed_Gross = 0x00;
- Seed_Fine = 0x1a;
- } else {
- /* Use settings for DDR-400 (interpolated from BKDG) */
- Seed_Gross = 0x00;
- Seed_Fine = 0x0d;
+ if (MemClkFreq == 6) {
+ /* DDR-800 */
+ Seed_Gross = 0x00;
+ Seed_Fine = 0x1a;
+ } else {
+ /* Use settings for DDR-400 (interpolated from BKDG) */
+ Seed_Gross = 0x00;
+ Seed_Fine = 0x0d;
+ }
}
}
for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++)
@@ -707,39 +1095,91 @@ void procConifg(sMCTStruct *pMCTData,sDCTStruct *pDCTData, u8 dimm, u8 pass)
pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Gross;
pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Fine;
}
- } else { /* Pass 2 */
+ } else {
+ /* Pass 2 */
/* From BKDG, Write Leveling Seed Value. */
- u32 RegisterDelay, SeedTotal;
- for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++)
- {
- if (pDCTData->Status[DCT_STATUS_REGISTERED])
- RegisterDelay = 0x20; /* TODO: ((RCW2 & BIT0) == 0) ? 0x20 : 0x30; */
- else
- RegisterDelay = 0;
- SeedTotal = (pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f) |
- (pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] << 5);
- /* SeedTotalPreScaling = (the total delay value in F2x[1, 0]9C_x[4A:30] from pass 1 of write levelization
- training) - RegisterDelay. */
- SeedTotal = (uint16_t) (RegisterDelay + ((((uint64_t) SeedTotal - RegisterDelay) *
- freq_tab[MemClkFreq-3] * 100) / (freq_tab[0] * 100)));
- Seed_Gross = SeedTotal / 32;
- Seed_Fine = SeedTotal & 0x1f;
- if (Seed_Gross == 0)
- Seed_Gross = 0;
- else if (Seed_Gross & 0x1)
- Seed_Gross = 1;
- else
- Seed_Gross = 2;
- pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Gross;
- pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Fine;
+ if (is_fam15h()) {
+ uint32_t RegisterDelay;
+ int32_t SeedTotal;
+ int32_t SeedTotalPreScaling;
+ uint8_t AddrCmdPrelaunch = 0; /* TODO: Fetch the correct value from RC2[0] */
+
+ for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) {
+ if (pDCTData->Status[DCT_STATUS_REGISTERED]) {
+ if (AddrCmdPrelaunch)
+ RegisterDelay = 0x30;
+ else
+ RegisterDelay = 0x20;
+ } else {
+ RegisterDelay = 0;
+ }
+ /* Retrieve WrDqDqsEarly */
+ AmdMemPCIReadBits(MAKE_SBDFO(0,0,24+(pDCTData->NodeId), FUN_DCT, 0xa8), 25, 24, &Value);
+
+ /* Calculate adjusted seed values */
+ SeedTotal = (pDCTData->WLFineDelayPrevPass[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f) |
+ ((pDCTData->WLGrossDelayPrevPass[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f) << 5);
+ SeedTotalPreScaling = (SeedTotal - RegisterDelay - (0x20 * Value));
+ SeedTotal = (int32_t) (RegisterDelay + ((((int64_t) SeedTotalPreScaling) *
+ fam15h_freq_tab[MemClkFreq] * 100) / (fam15h_freq_tab[pDCTData->WLPrevMemclkFreq] * 100)));
+
+ if (SeedTotal >= 0) {
+ Seed_Gross = SeedTotal / 32;
+ Seed_Fine = SeedTotal % 32;
+ } else {
+ Seed_Gross = (SeedTotal / 32) - 1;
+ Seed_Fine = (SeedTotal % 32) + 32;
+ }
+
+ if (Seed_Gross == 0)
+ Seed_PreGross = 0;
+ else if (Seed_Gross & 0x1)
+ Seed_PreGross = 1;
+ else
+ Seed_PreGross = 2;
+
+ /* Save seed values for later use */
+ pDCTData->WLSeedGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Gross;
+ pDCTData->WLSeedFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Fine;
+ pDCTData->WLSeedPreGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_PreGross;
+
+ pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_PreGross;
+ pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Fine;
+ }
+ } else {
+ u32 RegisterDelay, SeedTotal;
+ for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++)
+ {
+ if (pDCTData->Status[DCT_STATUS_REGISTERED])
+ RegisterDelay = 0x20; /* TODO: ((RCW2 & BIT0) == 0) ? 0x20 : 0x30; */
+ else
+ RegisterDelay = 0;
+ SeedTotal = (pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f) |
+ (pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] << 5);
+ /* SeedTotalPreScaling = (the total delay value in F2x[1, 0]9C_x[4A:30] from pass 1 of write levelization
+ training) - RegisterDelay. */
+ SeedTotal = (uint16_t) (RegisterDelay + ((((uint64_t) SeedTotal - RegisterDelay) *
+ fam10h_freq_tab[MemClkFreq-3] * 100) / (fam10h_freq_tab[0] * 100)));
+ Seed_Gross = SeedTotal / 32;
+ Seed_Fine = SeedTotal & 0x1f;
+ if (Seed_Gross == 0)
+ Seed_Gross = 0;
+ else if (Seed_Gross & 0x1)
+ Seed_Gross = 1;
+ else
+ Seed_Gross = 2;
+ pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Gross;
+ pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Fine;
+ }
}
}
- setWLByteDelay(pDCTData, ByteLane, dimm, 0);
+ pDCTData->WLPrevMemclkFreq = MemClkFreq;
+ setWLByteDelay(pDCTstat, dct, ByteLane, dimm, 0, pass);
}
/*-----------------------------------------------------------------------------
- * void setWLByteDelay(DCTStruct *DCTData, u8 ByteLane, u8 Dimm){
+ * void setWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, u8 Dimm){
*
* Description:
* This function writes the write levelization byte delay for the Phase
@@ -759,8 +1199,9 @@ void procConifg(sMCTStruct *pMCTData,sDCTStruct *pDCTData, u8 dimm, u8 pass)
*
*-----------------------------------------------------------------------------
*/
-void setWLByteDelay(sDCTStruct *pDCTData, u8 ByteLane, u8 dimm, u8 targetAddr)
+void setWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, u8 dimm, u8 targetAddr, uint8_t pass)
{
+ sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
u8 fineStartLoc, fineEndLoc, grossStartLoc, grossEndLoc, tempB, index, offsetAddr;
u32 addr, fineDelayValue, grossDelayValue, ValueLow, ValueHigh, EccValue, tempW;
@@ -773,22 +1214,26 @@ void setWLByteDelay(sDCTStruct *pDCTData, u8 ByteLane, u8 dimm, u8 targetAddr)
EccValue = 0;
while (ByteLane < MAX_BYTE_LANES)
{
- /* This subtract 0xC workaround might be temporary. */
- if ((pDCTData->WLPass==2) && (pDCTData->RegMan1Present & (1<<(dimm*2+pDCTData->DctTrain))))
- {
- tempW = (pDCTData->WLGrossDelay[index+ByteLane] << 5) | pDCTData->WLFineDelay[index+ByteLane];
- tempW -= 0xC;
- pDCTData->WLGrossDelay[index+ByteLane] = (u8)(tempW >> 5);
- pDCTData->WLFineDelay[index+ByteLane] = (u8)(tempW & 0x1F);
- }
- grossDelayValue = pDCTData->WLGrossDelay[index+ByteLane];
- /* Adjust seed gross delay overflow (greater than 3):
- * - Program seed gross delay as 2 (gross is 4 or 6) or 1 (gross is 5).
- * - Keep original seed gross delay for later reference.
- */
- if(grossDelayValue >= 3)
- {
- grossDelayValue = (grossDelayValue&1)? 1 : 2;
+ if (is_fam15h()) {
+ grossDelayValue = pDCTData->WLGrossDelay[index+ByteLane];
+ } else {
+ /* This subtract 0xC workaround might be temporary. */
+ if ((pDCTData->WLPass==2) && (pDCTData->RegMan1Present & (1<<(dimm*2+dct))))
+ {
+ tempW = (pDCTData->WLGrossDelay[index+ByteLane] << 5) | pDCTData->WLFineDelay[index+ByteLane];
+ tempW -= 0xC;
+ pDCTData->WLGrossDelay[index+ByteLane] = (u8)(tempW >> 5);
+ pDCTData->WLFineDelay[index+ByteLane] = (u8)(tempW & 0x1F);
+ }
+ grossDelayValue = pDCTData->WLGrossDelay[index+ByteLane];
+ /* Adjust seed gross delay overflow (greater than 3):
+ * - Program seed gross delay as 2 (gross is 4 or 6) or 1 (gross is 5).
+ * - Keep original seed gross delay for later reference.
+ */
+ if(grossDelayValue >= 3)
+ {
+ grossDelayValue = (grossDelayValue&1)? 1 : 2;
+ }
}
fineDelayValue = pDCTData->WLFineDelay[index+ByteLane];
if (ByteLane < 4)
@@ -799,15 +1244,16 @@ void setWLByteDelay(sDCTStruct *pDCTData, u8 ByteLane, u8 dimm, u8 targetAddr)
EccValue = ((grossDelayValue << 5) | fineDelayValue);
ByteLane++;
}
- set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId, FUN_DCT,
+ set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
DRAM_CONT_ADD_PHASE_REC_CTRL_LOW, 0, 31, (u32)ValueLow);
- set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId, FUN_DCT,
+ set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
DRAM_CONT_ADD_PHASE_REC_CTRL_HIGH, 0, 31, (u32)ValueHigh);
- set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId, FUN_DCT,
+ set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
DRAM_CONT_ADD_ECC_PHASE_REC_CTRL, 0, 31, (u32)EccValue);
}
else
{
+ /* Fam10h BKDG Rev. 3.62 2.8.9.9.1 (6) */
index = (u8)(MAX_BYTE_LANES * dimm);
grossDelayValue = pDCTData->WLGrossDelay[index+ByteLane];
fineDelayValue = pDCTData->WLFineDelay[index+ByteLane];
@@ -837,16 +1283,24 @@ void setWLByteDelay(sDCTStruct *pDCTData, u8 ByteLane, u8 dimm, u8 targetAddr)
grossStartLoc = (u8)(fineEndLoc + 1);
grossEndLoc = (u8)(grossStartLoc + 1);
- set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId, FUN_DCT,
+ set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
(u16)addr, fineStartLoc, fineEndLoc,(u32)fineDelayValue);
- set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId, FUN_DCT,
+ set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
(u16)addr, grossStartLoc, grossEndLoc, (u32)grossDelayValue);
+
+ pDCTData->WLFineDelayPrevPass[index+ByteLane] = fineDelayValue;
+ pDCTData->WLGrossDelayPrevPass[index+ByteLane] = grossDelayValue;
+ if (pass == FirstPass) {
+ pDCTData->WLFineDelayFirstPass[index+ByteLane] = fineDelayValue;
+ pDCTData->WLGrossDelayFirstPass[index+ByteLane] = grossDelayValue;
+ pDCTData->WLCriticalGrossDelayFirstPass = pDCTData->WLCriticalGrossDelayPrevPass;
+ }
}
}
/*-----------------------------------------------------------------------------
- * void getWLByteDelay(DCTStruct *DCTData, u8 ByteLane, u8 Dimm)
+ * void getWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, u8 Dimm)
*
* Description:
* This function reads the write levelization byte delay from the Phase
@@ -864,8 +1318,9 @@ void setWLByteDelay(sDCTStruct *pDCTData, u8 ByteLane, u8 dimm, u8 targetAddr)
*
*-----------------------------------------------------------------------------
*/
-void getWLByteDelay(sDCTStruct *pDCTData, u8 ByteLane, u8 dimm)
+void getWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, u8 dimm, uint8_t pass)
{
+ sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
u8 fineStartLoc, fineEndLoc, grossStartLoc, grossEndLoc, tempB, tempB1, index;
u32 addr, fine, gross;
tempB = 0;
@@ -886,25 +1341,31 @@ void getWLByteDelay(sDCTStruct *pDCTData, u8 ByteLane, u8 dimm)
grossStartLoc = (u8)(fineEndLoc + 1);
grossEndLoc = (u8)(grossStartLoc + 1);
- fine = get_ADD_DCT_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId,
+ fine = get_ADD_DCT_Bits(pDCTData, dct, pDCTData->NodeId,
FUN_DCT, (u16)addr, fineStartLoc, fineEndLoc);
- gross = get_ADD_DCT_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId,
+ gross = get_ADD_DCT_Bits(pDCTData, dct, pDCTData->NodeId,
FUN_DCT, (u16)addr, grossStartLoc, grossEndLoc);
- /* Adjust seed gross delay overflow (greater than 3):
- * - Adjust the trained gross delay to the original seed gross delay.
- */
- if (pDCTData->WLGrossDelay[index+ByteLane] >= 3) {
- gross += pDCTData->WLGrossDelay[index+ByteLane];
- if(pDCTData->WLGrossDelay[index+ByteLane] & 1)
- gross -= 1;
- else
- gross -= 2;
- } else if ((pDCTData->WLGrossDelay[index+ByteLane] == 0) && (gross == 3)) {
- /* If seed gross delay is 0 but PRE result gross delay is 3, it is negative.
- * We will then round the negative number to 0.
+
+ if (!is_fam15h()) {
+ /* Adjust seed gross delay overflow (greater than 3):
+ * - Adjust the trained gross delay to the original seed gross delay.
*/
- gross = 0;
- fine = 0;
+ if(pDCTData->WLGrossDelay[index+ByteLane] >= 3)
+ {
+ gross += pDCTData->WLGrossDelay[index+ByteLane];
+ if(pDCTData->WLGrossDelay[index+ByteLane] & 1)
+ gross -= 1;
+ else
+ gross -= 2;
+ }
+ else if((pDCTData->WLGrossDelay[index+ByteLane] == 0) && (gross == 3))
+ {
+ /* If seed gross delay is 0 but PRE result gross delay is 3, it is negative.
+ * We will then round the negative number to 0.
+ */
+ gross = 0;
+ fine = 0;
+ }
}
pDCTData->WLFineDelay[index+ByteLane] = (u8)fine;
pDCTData->WLGrossDelay[index+ByteLane] = (u8)gross;
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mutilc_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mutilc_d.c
index 4ae0af183b..18cad7eae7 100644
--- a/src/northbridge/amd/amdmct/mct_ddr3/mutilc_d.c
+++ b/src/northbridge/amd/amdmct/mct_ddr3/mutilc_d.c
@@ -2,6 +2,7 @@
* This file is part of the coreboot project.
*
* Copyright (C) 2010 Advanced Micro Devices, Inc.
+ * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering
*
* 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
@@ -130,24 +131,48 @@ static u32 get_Bits(sDCTStruct *pDCTData,
u16 offset, u8 low, u8 high)
{
u32 temp;
+ uint32_t dword;
+
/* ASSERT(node < MAX_NODES); */
if (dct == BOTH_DCTS)
{
/* Registers exist on DCT0 only */
+ if (is_fam15h())
+ {
+ /* Select DCT 0 */
+ AmdMemPCIRead(MAKE_SBDFO(0,0,24+node,1,0x10c), &dword);
+ dword &= ~0x1;
+ AmdMemPCIWrite(MAKE_SBDFO(0,0,24+node,1,0x10c), &dword);
+ }
+
AmdMemPCIReadBits(MAKE_SBDFO(0,0,24+node,func,offset), high, low, &temp);
}
else
{
- if (dct == 1)
+ if (is_fam15h())
{
- /* Write to dct 1 */
- offset += 0x100;
+ /* Select DCT */
+ AmdMemPCIRead(MAKE_SBDFO(0,0,24+node,1,0x10c), &dword);
+ dword &= ~0x1;
+ dword |= (dct & 0x1);
+ AmdMemPCIWrite(MAKE_SBDFO(0,0,24+node,1,0x10c), &dword);
+
+ /* Read from the selected DCT */
AmdMemPCIReadBits(MAKE_SBDFO(0,0,24+node,func,offset), high, low, &temp);
}
else
{
- /* Write to dct 0 */
- AmdMemPCIReadBits(MAKE_SBDFO(0,0,24+node,func,offset), high, low, &temp);
+ if (dct == 1)
+ {
+ /* Read from dct 1 */
+ offset += 0x100;
+ AmdMemPCIReadBits(MAKE_SBDFO(0,0,24+node,func,offset), high, low, &temp);
+ }
+ else
+ {
+ /* Read from dct 0 */
+ AmdMemPCIReadBits(MAKE_SBDFO(0,0,24+node,func,offset), high, low, &temp);
+ }
}
}
return temp;
@@ -180,25 +205,49 @@ static void set_Bits(sDCTStruct *pDCTData,
u16 offset, u8 low, u8 high, u32 value)
{
u32 temp;
+ uint32_t dword;
+
temp = value;
if (dct == BOTH_DCTS)
{
/* Registers exist on DCT0 only */
+ if (is_fam15h())
+ {
+ /* Select DCT 0 */
+ AmdMemPCIRead(MAKE_SBDFO(0,0,24+node,1,0x10c), &dword);
+ dword &= ~0x1;
+ AmdMemPCIWrite(MAKE_SBDFO(0,0,24+node,1,0x10c), &dword);
+ }
+
AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+node,func,offset), high, low, &temp);
}
else
{
- if (dct == 1)
+ if (is_fam15h())
{
- /* Write to dct 1 */
- offset += 0x100;
+ /* Select DCT */
+ AmdMemPCIRead(MAKE_SBDFO(0,0,24+node,1,0x10c), &dword);
+ dword &= ~0x1;
+ dword |= (dct & 0x1);
+ AmdMemPCIWrite(MAKE_SBDFO(0,0,24+node,1,0x10c), &dword);
+
+ /* Write to the selected DCT */
AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+node,func,offset), high, low, &temp);
}
else
{
- /* Write to dct 0 */
- AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+node,func,offset), high, low, &temp);
+ if (dct == 1)
+ {
+ /* Write to dct 1 */
+ offset += 0x100;
+ AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+node,func,offset), high, low, &temp);
+ }
+ else
+ {
+ /* Write to dct 0 */
+ AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+node,func,offset), high, low, &temp);
+ }
}
}
}
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mwlc_d.h b/src/northbridge/amd/amdmct/mct_ddr3/mwlc_d.h
index 877256933a..46b865d737 100644
--- a/src/northbridge/amd/amdmct/mct_ddr3/mwlc_d.h
+++ b/src/northbridge/amd/amdmct/mct_ddr3/mwlc_d.h
@@ -2,6 +2,7 @@
* This file is part of the coreboot project.
*
* Copyright (C) 2010 Advanced Micro Devices, Inc.
+ * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering
*
* 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
@@ -29,7 +30,8 @@
#define C_MAX_DIMMS 4 /* Maximum Number of DIMMs on each DCT */
/* STATUS Definition */
-#define DCT_STATUS_REGISTERED 3 /* Registered DIMMs support */
+#define DCT_STATUS_REGISTERED 3 /* Registered DIMMs support */
+#define DCT_STATUS_LOAD_REDUCED 4 /* Load-Reduced DIMMs support */
#define DCT_STATUS_OnDimmMirror 24 /* OnDimmMirror support */
/* PCI Defintions */
@@ -74,12 +76,18 @@
#define SendMrsCmd 26
#define Qoff 12
#define MRS_Level 7
-#define MrsAddressStart 0
-#define MrsAddressEnd 15
-#define MrsBankStart 16
-#define MrsBankEnd 18
-#define MrsChipSelStart 20
-#define MrsChipSelEnd 22
+#define MrsAddressStartFam10 0
+#define MrsAddressEndFam10 15
+#define MrsAddressStartFam15 0
+#define MrsAddressEndFam15 17
+#define MrsBankStartFam10 16
+#define MrsBankEndFam10 18
+#define MrsBankStartFam15 18
+#define MrsBankEndFam15 20
+#define MrsChipSelStartFam10 20
+#define MrsChipSelEndFam10 22
+#define MrsChipSelStartFam15 21
+#define MrsChipSelEndFam15 23
#define ASR 18
#define SRT 19
#define DramTermDynStart 10
@@ -111,10 +119,32 @@ typedef struct _sDCTStruct
u8 DctTrain; /* Current DCT being trained */
u8 CurrDct; /* Current DCT number (0 or 1) */
u8 DctCSPresent; /* Current DCT CS mapping */
+ int32_t WLSeedGrossDelay[MAX_BYTE_LANES*MAX_LDIMMS]; /* Write Levelization Seed Gross Delay */
+ /* per byte Lane Per Logical DIMM*/
+ int32_t WLSeedFineDelay[MAX_BYTE_LANES*MAX_LDIMMS]; /* Write Levelization Seed Fine Delay */
+ /* per byte Lane Per Logical DIMM*/
+ int32_t WLSeedPreGrossDelay[MAX_BYTE_LANES*MAX_LDIMMS]; /* Write Levelization Seed Pre-Gross Delay */
+ /* per byte Lane Per Logical DIMM*/
u8 WLGrossDelay[MAX_BYTE_LANES*MAX_LDIMMS]; /* Write Levelization Gross Delay */
/* per byte Lane Per Logical DIMM*/
u8 WLFineDelay[MAX_BYTE_LANES*MAX_LDIMMS]; /* Write Levelization Fine Delay */
/* per byte Lane Per Logical DIMM*/
+ u8 WLGrossDelayFirstPass[MAX_BYTE_LANES*MAX_LDIMMS]; /* First-Pass Write Levelization Gross Delay */
+ /* per byte Lane Per Logical DIMM*/
+ u8 WLFineDelayFirstPass[MAX_BYTE_LANES*MAX_LDIMMS]; /* First-Pass Write Levelization Fine Delay */
+ /* per byte Lane Per Logical DIMM*/
+ u8 WLGrossDelayPrevPass[MAX_BYTE_LANES*MAX_LDIMMS]; /* Previous Pass Write Levelization Gross Delay */
+ /* per byte Lane Per Logical DIMM*/
+ u8 WLFineDelayPrevPass[MAX_BYTE_LANES*MAX_LDIMMS]; /* Previous Pass Write Levelization Fine Delay */
+ /* per byte Lane Per Logical DIMM*/
+ u8 WLGrossDelayFinalPass[MAX_BYTE_LANES*MAX_LDIMMS]; /* Final-Pass Write Levelization Gross Delay */
+ /* per byte Lane Per Logical DIMM*/
+ u8 WLFineDelayFinalPass[MAX_BYTE_LANES*MAX_LDIMMS]; /* Final-Pass Write Levelization Fine Delay */
+ /* per byte Lane Per Logical DIMM*/
+ int32_t WLCriticalGrossDelayFirstPass;
+ int32_t WLCriticalGrossDelayPrevPass;
+ int32_t WLCriticalGrossDelayFinalPass;
+ uint16_t WLPrevMemclkFreq;
u16 RegMan1Present;
u8 DimmPresent[MAX_TOTAL_DIMMS];/* Indicates which DIMMs are present */
/* from Total Number of DIMMs(per Node)*/
@@ -128,7 +158,7 @@ typedef struct _sDCTStruct
/* per byte lane */
u8 MaxDimmsInstalled; /* Max Dimms Installed for current DCT */
u8 DimmRanks[MAX_TOTAL_DIMMS]; /* Total Number of Ranks(per Dimm) */
- u32 LogicalCPUID;
+ uint64_t LogicalCPUID;
u8 WLPass;
} sDCTStruct;
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
index 4b745d2846..3c2043be54 100644
--- a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
+++ b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
@@ -14,6 +14,7 @@
*/
#include <string.h>
+#include <arch/cpu.h>
#include <arch/acpi.h>
#include <cpu/x86/msr.h>
#include <device/device.h>
@@ -28,6 +29,23 @@
#define S3NV_FILE_NAME "s3nv"
+#ifdef __RAMSTAGE__
+static inline uint8_t is_fam15h(void)
+{
+ uint8_t fam15h = 0;
+ uint32_t family;
+
+ family = cpuid_eax(0x80000001);
+ family = ((family & 0xf00000) >> 16) | ((family & 0xf00) >> 8);
+
+ if (family >= 0x6f)
+ /* Family 15h or later */
+ fam15h = 1;
+
+ return fam15h;
+}
+#endif
+
static ssize_t get_s3nv_file_offset(void);
ssize_t get_s3nv_file_offset(void)
@@ -43,6 +61,28 @@ ssize_t get_s3nv_file_offset(void)
return s3nv_region.region.offset;
}
+static uint32_t read_config32_dct(device_t dev, uint8_t node, uint8_t dct, uint32_t reg) {
+ if (is_fam15h()) {
+ uint32_t dword;
+#ifdef __PRE_RAM__
+ device_t dev_fn1 = PCI_DEV(0, 0x18 + node, 1);
+#else
+ device_t dev_fn1 = dev_find_slot(0, PCI_DEVFN(0x18 + node, 1));
+#endif
+
+ /* Select DCT */
+ dword = pci_read_config32(dev_fn1, 0x10c);
+ dword &= ~0x1;
+ dword |= (dct & 0x1);
+ pci_write_config32(dev_fn1, 0x10c, dword);
+ } else {
+ /* Apply offset */
+ reg += dct * 0x100;
+ }
+
+ return pci_read_config32(dev, reg);
+}
+
static uint32_t read_amd_dct_index_register(device_t dev, uint32_t index_ctl_reg, uint32_t index)
{
uint32_t dword;
@@ -57,12 +97,54 @@ static uint32_t read_amd_dct_index_register(device_t dev, uint32_t index_ctl_reg
return dword;
}
+static uint32_t read_amd_dct_index_register_dct(device_t dev, uint8_t node, uint8_t dct, uint32_t index_ctl_reg, uint32_t index)
+{
+ if (is_fam15h()) {
+ uint32_t dword;
+#ifdef __PRE_RAM__
+ device_t dev_fn1 = PCI_DEV(0, 0x18 + node, 1);
+#else
+ device_t dev_fn1 = dev_find_slot(0, PCI_DEVFN(0x18 + node, 1));
+#endif
+
+ /* Select DCT */
+ dword = pci_read_config32(dev_fn1, 0x10c);
+ dword &= ~0x1;
+ dword |= (dct & 0x1);
+ pci_write_config32(dev_fn1, 0x10c, dword);
+ } else {
+ /* Apply offset */
+ index_ctl_reg += dct * 0x100;
+ }
+
+ return read_amd_dct_index_register(dev, index_ctl_reg, index);
+}
+
#ifdef __RAMSTAGE__
static uint64_t rdmsr_uint64_t(unsigned long index) {
msr_t msr = rdmsr(index);
return (((uint64_t)msr.hi) << 32) | ((uint64_t)msr.lo);
}
+static uint32_t read_config32_dct_nbpstate(device_t dev, uint8_t node, uint8_t dct, uint8_t nb_pstate, uint32_t reg) {
+ uint32_t dword;
+ device_t dev_fn1 = dev_find_slot(0, PCI_DEVFN(0x18 + node, 1));
+
+ /* Select DCT */
+ dword = pci_read_config32(dev_fn1, 0x10c);
+ dword &= ~0x1;
+ dword |= (dct & 0x1);
+ pci_write_config32(dev_fn1, 0x10c, dword);
+
+ /* Select NB Pstate index */
+ dword = pci_read_config32(dev_fn1, 0x10c);
+ dword &= ~(0x3 << 4);
+ dword |= (nb_pstate & 0x3) << 4;
+ pci_write_config32(dev_fn1, 0x10c, dword);
+
+ return pci_read_config32(dev, reg);
+}
+
void copy_mct_data_to_save_variable(struct amd_s3_persistent_data* persistent_data)
{
uint8_t i;
@@ -78,7 +160,8 @@ void copy_mct_data_to_save_variable(struct amd_s3_persistent_data* persistent_da
device_t dev_fn1 = dev_find_slot(0, PCI_DEVFN(0x18 + node, 1));
device_t dev_fn2 = dev_find_slot(0, PCI_DEVFN(0x18 + node, 2));
device_t dev_fn3 = dev_find_slot(0, PCI_DEVFN(0x18 + node, 3));
- if ((!dev_fn1) || (!dev_fn2) || (!dev_fn3)) {
+ /* Test for node presence */
+ if ((!dev_fn1) || (pci_read_config32(dev_fn1, PCI_VENDOR_ID) == 0xffffffff)) {
persistent_data->node[node].node_present = 0;
continue;
}
@@ -91,22 +174,22 @@ void copy_mct_data_to_save_variable(struct amd_s3_persistent_data* persistent_da
data->f2x110 = pci_read_config32(dev_fn2, 0x110);
/* Stage 2 */
- data->f1x40 = pci_read_config32(dev_fn1, 0x40 + (0x100 * channel));
- data->f1x44 = pci_read_config32(dev_fn1, 0x44 + (0x100 * channel));
- data->f1x48 = pci_read_config32(dev_fn1, 0x48 + (0x100 * channel));
- data->f1x4c = pci_read_config32(dev_fn1, 0x4c + (0x100 * channel));
- data->f1x50 = pci_read_config32(dev_fn1, 0x50 + (0x100 * channel));
- data->f1x54 = pci_read_config32(dev_fn1, 0x54 + (0x100 * channel));
- data->f1x58 = pci_read_config32(dev_fn1, 0x58 + (0x100 * channel));
- data->f1x5c = pci_read_config32(dev_fn1, 0x5c + (0x100 * channel));
- data->f1x60 = pci_read_config32(dev_fn1, 0x60 + (0x100 * channel));
- data->f1x64 = pci_read_config32(dev_fn1, 0x64 + (0x100 * channel));
- data->f1x68 = pci_read_config32(dev_fn1, 0x68 + (0x100 * channel));
- data->f1x6c = pci_read_config32(dev_fn1, 0x6c + (0x100 * channel));
- data->f1x70 = pci_read_config32(dev_fn1, 0x70 + (0x100 * channel));
- data->f1x74 = pci_read_config32(dev_fn1, 0x74 + (0x100 * channel));
- data->f1x78 = pci_read_config32(dev_fn1, 0x78 + (0x100 * channel));
- data->f1x7c = pci_read_config32(dev_fn1, 0x7c + (0x100 * channel));
+ data->f1x40 = read_config32_dct(dev_fn1, node, channel, 0x40);
+ data->f1x44 = read_config32_dct(dev_fn1, node, channel, 0x44);
+ data->f1x48 = read_config32_dct(dev_fn1, node, channel, 0x48);
+ data->f1x4c = read_config32_dct(dev_fn1, node, channel, 0x4c);
+ data->f1x50 = read_config32_dct(dev_fn1, node, channel, 0x50);
+ data->f1x54 = read_config32_dct(dev_fn1, node, channel, 0x54);
+ data->f1x58 = read_config32_dct(dev_fn1, node, channel, 0x58);
+ data->f1x5c = read_config32_dct(dev_fn1, node, channel, 0x5c);
+ data->f1x60 = read_config32_dct(dev_fn1, node, channel, 0x60);
+ data->f1x64 = read_config32_dct(dev_fn1, node, channel, 0x64);
+ data->f1x68 = read_config32_dct(dev_fn1, node, channel, 0x68);
+ data->f1x6c = read_config32_dct(dev_fn1, node, channel, 0x6c);
+ data->f1x70 = read_config32_dct(dev_fn1, node, channel, 0x70);
+ data->f1x74 = read_config32_dct(dev_fn1, node, channel, 0x74);
+ data->f1x78 = read_config32_dct(dev_fn1, node, channel, 0x78);
+ data->f1x7c = read_config32_dct(dev_fn1, node, channel, 0x7c);
data->f1xf0 = pci_read_config32(dev_fn1, 0xf0);
data->f1x120 = pci_read_config32(dev_fn1, 0x120);
data->f1x124 = pci_read_config32(dev_fn1, 0x124);
@@ -130,75 +213,144 @@ void copy_mct_data_to_save_variable(struct amd_s3_persistent_data* persistent_da
data->msrc001001f = rdmsr_uint64_t(0xc001001f);
/* Stage 3 */
- data->f2x40 = pci_read_config32(dev_fn2, 0x40 + (0x100 * channel));
- data->f2x44 = pci_read_config32(dev_fn2, 0x44 + (0x100 * channel));
- data->f2x48 = pci_read_config32(dev_fn2, 0x48 + (0x100 * channel));
- data->f2x4c = pci_read_config32(dev_fn2, 0x4c + (0x100 * channel));
- data->f2x50 = pci_read_config32(dev_fn2, 0x50 + (0x100 * channel));
- data->f2x54 = pci_read_config32(dev_fn2, 0x54 + (0x100 * channel));
- data->f2x58 = pci_read_config32(dev_fn2, 0x58 + (0x100 * channel));
- data->f2x5c = pci_read_config32(dev_fn2, 0x5c + (0x100 * channel));
- data->f2x60 = pci_read_config32(dev_fn2, 0x60 + (0x100 * channel));
- data->f2x64 = pci_read_config32(dev_fn2, 0x64 + (0x100 * channel));
- data->f2x68 = pci_read_config32(dev_fn2, 0x68 + (0x100 * channel));
- data->f2x6c = pci_read_config32(dev_fn2, 0x6c + (0x100 * channel));
- data->f2x78 = pci_read_config32(dev_fn2, 0x78 + (0x100 * channel));
- data->f2x7c = pci_read_config32(dev_fn2, 0x7c + (0x100 * channel));
- data->f2x80 = pci_read_config32(dev_fn2, 0x80 + (0x100 * channel));
- data->f2x84 = pci_read_config32(dev_fn2, 0x84 + (0x100 * channel));
- data->f2x88 = pci_read_config32(dev_fn2, 0x88 + (0x100 * channel));
- data->f2x8c = pci_read_config32(dev_fn2, 0x8c + (0x100 * channel));
- data->f2x90 = pci_read_config32(dev_fn2, 0x90 + (0x100 * channel));
- data->f2xa4 = pci_read_config32(dev_fn2, 0xa4 + (0x100 * channel));
- data->f2xa8 = pci_read_config32(dev_fn2, 0xa8 + (0x100 * channel));
+ data->f2x40 = read_config32_dct(dev_fn2, node, channel, 0x40);
+ data->f2x44 = read_config32_dct(dev_fn2, node, channel, 0x44);
+ data->f2x48 = read_config32_dct(dev_fn2, node, channel, 0x48);
+ data->f2x4c = read_config32_dct(dev_fn2, node, channel, 0x4c);
+ data->f2x50 = read_config32_dct(dev_fn2, node, channel, 0x50);
+ data->f2x54 = read_config32_dct(dev_fn2, node, channel, 0x54);
+ data->f2x58 = read_config32_dct(dev_fn2, node, channel, 0x58);
+ data->f2x5c = read_config32_dct(dev_fn2, node, channel, 0x5c);
+ data->f2x60 = read_config32_dct(dev_fn2, node, channel, 0x60);
+ data->f2x64 = read_config32_dct(dev_fn2, node, channel, 0x64);
+ data->f2x68 = read_config32_dct(dev_fn2, node, channel, 0x68);
+ data->f2x6c = read_config32_dct(dev_fn2, node, channel, 0x6c);
+ data->f2x78 = read_config32_dct(dev_fn2, node, channel, 0x78);
+ data->f2x7c = read_config32_dct(dev_fn2, node, channel, 0x7c);
+ data->f2x80 = read_config32_dct(dev_fn2, node, channel, 0x80);
+ data->f2x84 = read_config32_dct(dev_fn2, node, channel, 0x84);
+ data->f2x88 = read_config32_dct(dev_fn2, node, channel, 0x88);
+ data->f2x8c = read_config32_dct(dev_fn2, node, channel, 0x8c);
+ data->f2x90 = read_config32_dct(dev_fn2, node, channel, 0x90);
+ data->f2xa4 = read_config32_dct(dev_fn2, node, channel, 0xa4);
+ data->f2xa8 = read_config32_dct(dev_fn2, node, channel, 0xa8);
+
+ /* Family 15h-specific configuration */
+ if (is_fam15h()) {
+ data->f2x200 = read_config32_dct(dev_fn2, node, channel, 0x200);
+ data->f2x204 = read_config32_dct(dev_fn2, node, channel, 0x204);
+ data->f2x208 = read_config32_dct(dev_fn2, node, channel, 0x208);
+ data->f2x20c = read_config32_dct(dev_fn2, node, channel, 0x20c);
+ for (i=0; i<4; i++)
+ data->f2x210[i] = read_config32_dct_nbpstate(dev_fn2, node, channel, i, 0x210);
+ data->f2x214 = read_config32_dct(dev_fn2, node, channel, 0x214);
+ data->f2x218 = read_config32_dct(dev_fn2, node, channel, 0x218);
+ data->f2x21c = read_config32_dct(dev_fn2, node, channel, 0x21c);
+ data->f2x22c = read_config32_dct(dev_fn2, node, channel, 0x22c);
+ data->f2x230 = read_config32_dct(dev_fn2, node, channel, 0x230);
+ data->f2x234 = read_config32_dct(dev_fn2, node, channel, 0x234);
+ data->f2x238 = read_config32_dct(dev_fn2, node, channel, 0x238);
+ data->f2x23c = read_config32_dct(dev_fn2, node, channel, 0x23c);
+ data->f2x240 = read_config32_dct(dev_fn2, node, channel, 0x240);
+
+ data->f2x9cx0d0fe003 = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fe003);
+ data->f2x9cx0d0fe013 = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fe013);
+ for (i=0; i<9; i++)
+ data->f2x9cx0d0f0_8_0_1f[i] = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f001f | (i << 8));
+ data->f2x9cx0d0f201f = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f201f);
+ data->f2x9cx0d0f211f = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f211f);
+ data->f2x9cx0d0f221f = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f221f);
+ data->f2x9cx0d0f801f = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f801f);
+ data->f2x9cx0d0f811f = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f811f);
+ data->f2x9cx0d0f821f = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f821f);
+ data->f2x9cx0d0fc01f = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fc01f);
+ data->f2x9cx0d0fc11f = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fc11f);
+ data->f2x9cx0d0fc21f = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fc21f);
+ data->f2x9cx0d0f4009 = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f4009);
+ for (i=0; i<9; i++)
+ data->f2x9cx0d0f0_8_0_02[i] = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f0002 | (i << 8));
+ for (i=0; i<9; i++)
+ data->f2x9cx0d0f0_8_0_06[i] = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f0006 | (i << 8));
+ for (i=0; i<9; i++)
+ data->f2x9cx0d0f0_8_0_0a[i] = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f000a | (i << 8));
+
+ data->f2x9cx0d0f2002 = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f2002);
+ data->f2x9cx0d0f2102 = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f2102);
+ data->f2x9cx0d0f2202 = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f2202);
+ data->f2x9cx0d0f8002 = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f8002);
+ data->f2x9cx0d0f8006 = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f8006);
+ data->f2x9cx0d0f800a = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f800a);
+ data->f2x9cx0d0f8102 = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f8102);
+ data->f2x9cx0d0f8106 = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f8106);
+ data->f2x9cx0d0f810a = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f810a);
+ data->f2x9cx0d0fc002 = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fc002);
+ data->f2x9cx0d0fc006 = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fc006);
+ data->f2x9cx0d0fc00a = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fc00a);
+ data->f2x9cx0d0fc00e = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fc00e);
+ data->f2x9cx0d0fc012 = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fc012);
+
+ data->f2x9cx0d0f2031 = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f2031);
+ data->f2x9cx0d0f2131 = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f2131);
+ data->f2x9cx0d0f2231 = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f2231);
+ data->f2x9cx0d0f8031 = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f8031);
+ data->f2x9cx0d0f8131 = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f8131);
+ data->f2x9cx0d0f8231 = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f8231);
+ data->f2x9cx0d0fc031 = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fc031);
+ data->f2x9cx0d0fc131 = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fc131);
+ data->f2x9cx0d0fc231 = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fc231);
+ for (i=0; i<9; i++)
+ data->f2x9cx0d0f0_0_f_31[i] = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f0031 | (i << 8));
+
+ data->f2x9cx0d0f8021 = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f8021);
+ }
/* Stage 4 */
- data->f2x94 = pci_read_config32(dev_fn2, 0x94 + (0x100 * channel));
+ data->f2x94 = read_config32_dct(dev_fn2, node, channel, 0x94);
/* Stage 6 */
for (i=0; i<9; i++)
for (j=0; j<3; j++)
- data->f2x9cx0d0f0_f_8_0_0_8_4_0[i][j] = read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x0d0f0000 | (i << 8) | (j * 4));
- data->f2x9cx00 = read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x00);
- data->f2x9cx0a = read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x0a);
- data->f2x9cx0c = read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x0c);
+ data->f2x9cx0d0f0_f_8_0_0_8_4_0[i][j] = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f0000 | (i << 8) | (j * 4));
+ data->f2x9cx00 = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x00);
+ data->f2x9cx0a = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0a);
+ data->f2x9cx0c = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0c);
/* Stage 7 */
- data->f2x9cx04 = read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x04);
+ data->f2x9cx04 = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x04);
/* Stage 9 */
- data->f2x9cx0d0fe006 = read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x0d0fe006);
- data->f2x9cx0d0fe007 = read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x0d0fe007);
+ data->f2x9cx0d0fe006 = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fe006);
+ data->f2x9cx0d0fe007 = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fe007);
/* Stage 10 */
for (i=0; i<12; i++)
- data->f2x9cx10[i] = read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x10 + i);
+ data->f2x9cx10[i] = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x10 + i);
for (i=0; i<12; i++)
- data->f2x9cx20[i] = read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x20 + i);
+ data->f2x9cx20[i] = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x20 + i);
for (i=0; i<4; i++)
for (j=0; j<3; j++)
- data->f2x9cx3_0_0_3_1[i][j] = read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), (0x01 + i) + (0x100 * j));
+ data->f2x9cx3_0_0_3_1[i][j] = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, (0x01 + i) + (0x100 * j));
for (i=0; i<4; i++)
for (j=0; j<3; j++)
- data->f2x9cx3_0_0_7_5[i][j] = read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), (0x05 + i) + (0x100 * j));
- data->f2x9cx0d = read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x0d);
+ data->f2x9cx3_0_0_7_5[i][j] = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, (0x05 + i) + (0x100 * j));
+ data->f2x9cx0d = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d);
for (i=0; i<9; i++)
- data->f2x9cx0d0f0_f_0_13[i] = read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x0d0f0013 | (i << 8));
+ data->f2x9cx0d0f0_f_0_13[i] = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f0013 | (i << 8));
for (i=0; i<9; i++)
- data->f2x9cx0d0f0_f_0_30[i] = read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x0d0f0030 | (i << 8));
+ data->f2x9cx0d0f0_f_0_30[i] = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f0030 | (i << 8));
for (i=0; i<4; i++)
- data->f2x9cx0d0f2_f_0_30[i] = read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x0d0f2030 | (i << 8));
+ data->f2x9cx0d0f2_f_0_30[i] = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f2030 | (i << 8));
for (i=0; i<2; i++)
for (j=0; j<3; j++)
- data->f2x9cx0d0f8_8_4_0[i][j] = read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x0d0f0000 | (i << 8) | (j * 4));
- data->f2x9cx0d0f812f = read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x0d0f812f);
+ data->f2x9cx0d0f8_8_4_0[i][j] = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f0000 | (i << 8) | (j * 4));
+ data->f2x9cx0d0f812f = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f812f);
/* Stage 11 */
if (IS_ENABLED(CONFIG_DIMM_DDR3)) {
for (i=0; i<12; i++)
- data->f2x9cx30[i] = read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x30 + i);
+ data->f2x9cx30[i] = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x30 + i);
for (i=0; i<12; i++)
- data->f2x9cx40[i] = read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x40 + i);
+ data->f2x9cx40[i] = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x40 + i);
}
/* Other */
@@ -208,6 +360,43 @@ void copy_mct_data_to_save_variable(struct amd_s3_persistent_data* persistent_da
}
}
#else
+static void write_config32_dct(device_t dev, uint8_t node, uint8_t dct, uint32_t reg, uint32_t value) {
+ if (is_fam15h()) {
+ uint32_t dword;
+ device_t dev_fn1 = PCI_DEV(0, 0x18 + node, 1);
+
+ /* Select DCT */
+ dword = pci_read_config32(dev_fn1, 0x10c);
+ dword &= ~0x1;
+ dword |= (dct & 0x1);
+ pci_write_config32(dev_fn1, 0x10c, dword);
+ } else {
+ /* Apply offset */
+ reg += dct * 0x100;
+ }
+
+ pci_write_config32(dev, reg, value);
+}
+
+static void write_config32_dct_nbpstate(device_t dev, uint8_t node, uint8_t dct, uint8_t nb_pstate, uint32_t reg, uint32_t value) {
+ uint32_t dword;
+ device_t dev_fn1 = PCI_DEV(0, 0x18 + node, 1);
+
+ /* Select DCT */
+ dword = pci_read_config32(dev_fn1, 0x10c);
+ dword &= ~0x1;
+ dword |= (dct & 0x1);
+ pci_write_config32(dev_fn1, 0x10c, dword);
+
+ /* Select NB Pstate index */
+ dword = pci_read_config32(dev_fn1, 0x10c);
+ dword &= ~(0x3 << 4);
+ dword |= (nb_pstate & 0x3) << 4;
+ pci_write_config32(dev_fn1, 0x10c, dword);
+
+ pci_write_config32(dev, reg, value);
+}
+
static void write_amd_dct_index_register(device_t dev, uint32_t index_ctl_reg, uint32_t index, uint32_t value)
{
uint32_t dword;
@@ -219,6 +408,25 @@ static void write_amd_dct_index_register(device_t dev, uint32_t index_ctl_reg, u
dword = pci_read_config32(dev, index_ctl_reg);
} while (!(dword & (1 << 31)));
}
+
+static void write_amd_dct_index_register_dct(device_t dev, uint8_t node, uint8_t dct, uint32_t index_ctl_reg, uint32_t index, uint32_t value)
+{
+ if (is_fam15h()) {
+ uint32_t dword;
+ device_t dev_fn1 = PCI_DEV(0, 0x18 + node, 1);
+
+ /* Select DCT */
+ dword = pci_read_config32(dev_fn1, 0x10c);
+ dword &= ~0x1;
+ dword |= (dct & 0x1);
+ pci_write_config32(dev_fn1, 0x10c, dword);
+ } else {
+ /* Apply offset */
+ index_ctl_reg += dct * 0x100;
+ }
+
+ return write_amd_dct_index_register(dev, index_ctl_reg, index, value);
+}
#endif
#ifdef __PRE_RAM__
@@ -258,31 +466,31 @@ void restore_mct_data_from_save_variable(struct amd_s3_persistent_data* persiste
if (!persistent_data->node[node].node_present)
continue;
- pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x40 + (0x100 * channel), data->f1x40);
- pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x44 + (0x100 * channel), data->f1x44);
- pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x48 + (0x100 * channel), data->f1x48);
- pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x4c + (0x100 * channel), data->f1x4c);
- pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x50 + (0x100 * channel), data->f1x50);
- pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x54 + (0x100 * channel), data->f1x54);
- pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x58 + (0x100 * channel), data->f1x58);
- pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x5c + (0x100 * channel), data->f1x5c);
- pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x60 + (0x100 * channel), data->f1x60);
- pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x64 + (0x100 * channel), data->f1x64);
- pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x68 + (0x100 * channel), data->f1x68);
- pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x6c + (0x100 * channel), data->f1x6c);
- pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x70 + (0x100 * channel), data->f1x70);
- pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x74 + (0x100 * channel), data->f1x74);
- pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x78 + (0x100 * channel), data->f1x78);
- pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x7c + (0x100 * channel), data->f1x7c);
- pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0xf0 + (0x100 * channel), data->f1xf0);
- pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x120 + (0x100 * channel), data->f1x120);
- pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x124 + (0x100 * channel), data->f1x124);
- pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x10c + (0x100 * channel), data->f2x10c);
- pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x114 + (0x100 * channel), data->f2x114);
- pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x118 + (0x100 * channel), data->f2x118);
- pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x11c + (0x100 * channel), data->f2x11c);
- pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x1b0 + (0x100 * channel), data->f2x1b0);
- pci_write_config32(PCI_DEV(0, 0x18 + node, 3), 0x44 + (0x100 * channel), data->f3x44);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, channel, 0x40, data->f1x40);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, channel, 0x44, data->f1x44);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, channel, 0x48, data->f1x48);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, channel, 0x4c, data->f1x4c);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, channel, 0x50, data->f1x50);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, channel, 0x54, data->f1x54);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, channel, 0x58, data->f1x58);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, channel, 0x5c, data->f1x5c);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, channel, 0x60, data->f1x60);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, channel, 0x64, data->f1x64);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, channel, 0x68, data->f1x68);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, channel, 0x6c, data->f1x6c);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, channel, 0x70, data->f1x70);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, channel, 0x74, data->f1x74);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, channel, 0x78, data->f1x78);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, channel, 0x7c, data->f1x7c);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, channel, 0xf0, data->f1xf0);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, channel, 0x120, data->f1x120);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, channel, 0x124, data->f1x124);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x10c, data->f2x10c);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x114, data->f2x114);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x118, data->f2x118);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x11c, data->f2x11c);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x1b0, data->f2x1b0);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 3), node, channel, 0x44, data->f3x44);
for (i=0; i<16; i++) {
wrmsr_uint64_t(0x00000200 | i, data->msr0000020[i]);
}
@@ -309,31 +517,97 @@ void restore_mct_data_from_save_variable(struct amd_s3_persistent_data* persiste
if (!persistent_data->node[node].node_present)
continue;
- ganged = !!(data->f2x110 & 0x10);
+ if (is_fam15h())
+ ganged = 0;
+ else
+ ganged = !!(data->f2x110 & 0x10);
if ((ganged == 1) && (channel > 0))
continue;
- pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x40 + (0x100 * channel), data->f2x40);
- pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x44 + (0x100 * channel), data->f2x44);
- pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x48 + (0x100 * channel), data->f2x48);
- pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x4c + (0x100 * channel), data->f2x4c);
- pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x50 + (0x100 * channel), data->f2x50);
- pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x54 + (0x100 * channel), data->f2x54);
- pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x58 + (0x100 * channel), data->f2x58);
- pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x5c + (0x100 * channel), data->f2x5c);
- pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x60 + (0x100 * channel), data->f2x60);
- pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x64 + (0x100 * channel), data->f2x64);
- pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x68 + (0x100 * channel), data->f2x68);
- pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x6c + (0x100 * channel), data->f2x6c);
- pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x78 + (0x100 * channel), data->f2x78);
- pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x7c + (0x100 * channel), data->f2x7c);
- pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x80 + (0x100 * channel), data->f2x80);
- pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x84 + (0x100 * channel), data->f2x84);
- pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x88 + (0x100 * channel), data->f2x88);
- pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x8c + (0x100 * channel), data->f2x8c);
- pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x90 + (0x100 * channel), data->f2x90);
- pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0xa4 + (0x100 * channel), data->f2xa4);
- pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0xa8 + (0x100 * channel), data->f2xa8);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x40, data->f2x40);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x44, data->f2x44);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x48, data->f2x48);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x4c, data->f2x4c);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x50, data->f2x50);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x54, data->f2x54);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x58, data->f2x58);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x5c, data->f2x5c);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x60, data->f2x60);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x64, data->f2x64);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x68, data->f2x68);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x6c, data->f2x6c);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x78, data->f2x78);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x7c, data->f2x7c);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x80, data->f2x80);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x84, data->f2x84);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x88, data->f2x88);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x8c, data->f2x8c);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x90, data->f2x90);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0xa4, data->f2xa4);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0xa8, data->f2xa8);
+ }
+ }
+
+ /* Family 15h-specific configuration */
+ if (is_fam15h()) {
+ for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
+ for (channel = 0; channel < 2; channel++) {
+ struct amd_s3_persistent_mct_channel_data* data = &persistent_data->node[node].channel[channel];
+ if (!persistent_data->node[node].node_present)
+ continue;
+
+ /* Initialize DCT */
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0000000b, 0x80000000);
+ dword = read_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0fe013);
+ dword &= ~0xffff;
+ dword |= 0x118;
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0fe013, dword);
+
+ /* Restore values */
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x200, data->f2x200);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x204, data->f2x204);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x208, data->f2x208);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x20c, data->f2x20c);
+ for (i=0; i<4; i++)
+ write_config32_dct_nbpstate(PCI_DEV(0, 0x18 + node, 2), node, channel, i, 0x210, data->f2x210[i]);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x214, data->f2x214);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x218, data->f2x218);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x21c, data->f2x21c);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x22c, data->f2x22c);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x230, data->f2x230);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x234, data->f2x234);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x238, data->f2x238);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x23c, data->f2x23c);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x240, data->f2x240);
+
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0fe013, data->f2x9cx0d0fe013);
+ for (i=0; i<9; i++)
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f001f | (i << 8), data->f2x9cx0d0f0_8_0_1f[i]);
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f201f, data->f2x9cx0d0f201f);
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f211f, data->f2x9cx0d0f211f);
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f221f, data->f2x9cx0d0f221f);
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f801f, data->f2x9cx0d0f801f);
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f811f, data->f2x9cx0d0f811f);
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f821f, data->f2x9cx0d0f821f);
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0fc01f, data->f2x9cx0d0fc01f);
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0fc11f, data->f2x9cx0d0fc11f);
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0fc21f, data->f2x9cx0d0fc21f);
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f4009, data->f2x9cx0d0f4009);
+
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f2031, data->f2x9cx0d0f2031);
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f2131, data->f2x9cx0d0f2131);
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f2231, data->f2x9cx0d0f2231);
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f8031, data->f2x9cx0d0f8031);
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f8131, data->f2x9cx0d0f8131);
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f8231, data->f2x9cx0d0f8231);
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0fc031, data->f2x9cx0d0fc031);
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0fc131, data->f2x9cx0d0fc131);
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0fc231, data->f2x9cx0d0fc231);
+ for (i=0; i<9; i++)
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f0031 | (i << 8), data->f2x9cx0d0f0_0_f_31[i]);
+
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f8021, data->f2x9cx0d0f8021);
+ }
}
}
@@ -344,33 +618,44 @@ void restore_mct_data_from_save_variable(struct amd_s3_persistent_data* persiste
if (!persistent_data->node[node].node_present)
continue;
- ganged = !!(data->f2x110 & 0x10);
+ if (is_fam15h())
+ ganged = 0;
+ else
+ ganged = !!(data->f2x110 & 0x10);
if ((ganged == 1) && (channel > 0))
continue;
- /* Disable PHY auto-compensation engine */
- dword = read_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 2), 0x98 + (0x100 * channel), 0x08);
- if (!(dword & (1 << 30))) {
- dword |= (1 << 30);
- write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 2), 0x98 + (0x100 * channel), 0x08, dword);
-
- /* Wait for 5us */
- mct_Wait(100);
+ if (is_fam15h()) {
+ /* Program PllLockTime = 0x190 */
+ dword = read_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0fe006);
+ dword &= ~0xffff;
+ dword |= 0x190;
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0fe006, dword);
+
+ /* Program MemClkFreqVal = 0 */
+ dword = read_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x94);
+ dword &= (0x1 << 7);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x94, dword);
+
+ /* Restore DRAM Adddress/Timing Control Register */
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x04, data->f2x9cx04);
+ } else {
+ /* Disable PHY auto-compensation engine */
+ dword = read_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x08);
+ if (!(dword & (1 << 30))) {
+ dword |= (1 << 30);
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x08, dword);
+
+ /* Wait for 5us */
+ mct_Wait(100);
+ }
}
/* Restore DRAM Configuration High Register */
- pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x94 + (0x100 * channel), data->f2x94);
-
- /* Enable PHY auto-compensation engine */
- dword = read_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 2), 0x98 + (0x100 * channel), 0x08);
- dword &= ~(1 << 30);
- write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 2), 0x98 + (0x100 * channel), 0x08, dword);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x94, data->f2x94);
}
}
- /* Wait for 750us */
- mct_Wait(15000);
-
/* Stage 5 */
for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
for (channel = 0; channel < 2; channel++) {
@@ -378,17 +663,40 @@ void restore_mct_data_from_save_variable(struct amd_s3_persistent_data* persiste
if (!persistent_data->node[node].node_present)
continue;
- ganged = !!(data->f2x110 & 0x10);
+ if (is_fam15h())
+ ganged = 0;
+ else
+ ganged = !!(data->f2x110 & 0x10);
if ((ganged == 1) && (channel > 0))
continue;
+ dct_enabled = !(data->f2x94 & (1 << 14));
+ if (!dct_enabled)
+ continue;
+
/* Wait for any pending PHY frequency changes to complete */
do {
- dword = read_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 2), 0x98 + (0x100 * channel), 0x08);
+ dword = read_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x94);
} while (dword & (1 << 21));
+
+ if (is_fam15h()) {
+ /* Program PllLockTime = 0xf */
+ dword = read_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0fe006);
+ dword &= ~0xffff;
+ dword |= 0xf;
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0fe006, dword);
+ } else {
+ /* Enable PHY auto-compensation engine */
+ dword = read_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x08);
+ dword &= ~(1 << 30);
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x08, dword);
+ }
}
}
+ /* Wait for 750us */
+ mct_Wait(15000);
+
/* Stage 6 */
for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
for (channel = 0; channel < 2; channel++) {
@@ -398,10 +706,49 @@ void restore_mct_data_from_save_variable(struct amd_s3_persistent_data* persiste
for (i=0; i<9; i++)
for (j=0; j<3; j++)
- write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 2), 0x98 + (0x100 * channel), 0x0d0f0000 | (i << 8) | (j * 4), data->f2x9cx0d0f0_f_8_0_0_8_4_0[i][j]);
- write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 2), 0x98 + (0x100 * channel), 0x00, data->f2x9cx00);
- write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 2), 0x98 + (0x100 * channel), 0x0a, data->f2x9cx0a);
- write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 2), 0x98 + (0x100 * channel), 0x0c, data->f2x9cx0c);
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f0000 | (i << 8) | (j * 4), data->f2x9cx0d0f0_f_8_0_0_8_4_0[i][j]);
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x00, data->f2x9cx00);
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0a, data->f2x9cx0a);
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0c, data->f2x9cx0c);
+ }
+ }
+
+ /* Family 15h-specific configuration */
+ if (is_fam15h()) {
+ for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
+ for (channel = 0; channel < 2; channel++) {
+ struct amd_s3_persistent_mct_channel_data* data = &persistent_data->node[node].channel[channel];
+ if (!persistent_data->node[node].node_present)
+ continue;
+
+ dword = read_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0fe003);
+ dword |= (0x3 << 13); /* DisAutoComp, DisablePredriverCal = 1 */
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0fe003, dword);
+
+ for (i=0; i<9; i++)
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f0006 | (i << 8), data->f2x9cx0d0f0_8_0_06[i]);
+ for (i=0; i<9; i++)
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f000a | (i << 8), data->f2x9cx0d0f0_8_0_0a[i]);
+ for (i=0; i<9; i++)
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f0002 | (i << 8), (0x8000 | data->f2x9cx0d0f0_8_0_02[i]));
+
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f8006, data->f2x9cx0d0f8006);
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f800a, data->f2x9cx0d0f800a);
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f8106, data->f2x9cx0d0f8106);
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f810a, data->f2x9cx0d0f810a);
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0fc006, data->f2x9cx0d0fc006);
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0fc00a, data->f2x9cx0d0fc00a);
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0fc00e, data->f2x9cx0d0fc00e);
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0fc012, data->f2x9cx0d0fc012);
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f8002, (0x8000 | data->f2x9cx0d0f8002));
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f8102, (0x8000 | data->f2x9cx0d0f8102));
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0fc002, (0x8000 | data->f2x9cx0d0fc002));
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f2002, (0x8000 | data->f2x9cx0d0f2002));
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f2102, (0x8000 | data->f2x9cx0d0f2102));
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f2202, (0x8000 | data->f2x9cx0d0f2202));
+
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0fe003, data->f2x9cx0d0fe003);
+ }
}
}
@@ -412,11 +759,15 @@ void restore_mct_data_from_save_variable(struct amd_s3_persistent_data* persiste
if (!persistent_data->node[node].node_present)
continue;
- ganged = !!(data->f2x110 & 0x10);
+ if (is_fam15h())
+ ganged = 0;
+ else
+ ganged = !!(data->f2x110 & 0x10);
if ((ganged == 1) && (channel > 0))
continue;
- write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 2), 0x98 + (0x100 * channel), 0x04, data->f2x9cx04);
+ if (!is_fam15h())
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x04, data->f2x9cx04);
}
}
@@ -431,16 +782,19 @@ void restore_mct_data_from_save_variable(struct amd_s3_persistent_data* persiste
if (!dct_enabled)
continue;
- ganged = !!(data->f2x110 & 0x10);
+ if (is_fam15h())
+ ganged = 0;
+ else
+ ganged = !!(data->f2x110 & 0x10);
if ((ganged == 1) && (channel > 0))
continue;
printk(BIOS_SPEW, "Taking DIMMs out of self refresh node: %d channel: %d\n", node, channel);
/* Exit self refresh mode */
- dword = pci_read_config32(PCI_DEV(0, 0x18 + node, 2), 0x90 + (0x100 * channel));
+ dword = read_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x90);
dword |= (1 << 1);
- pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x90 + (0x100 * channel), dword);
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x90, dword);
}
}
@@ -459,12 +813,12 @@ void restore_mct_data_from_save_variable(struct amd_s3_persistent_data* persiste
/* Wait for transition from self refresh mode to complete */
do {
- dword = pci_read_config32(PCI_DEV(0, 0x18 + node, 2), 0x90 + (0x100 * channel));
+ dword = read_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x90);
} while (dword & (1 << 1));
/* Restore registers */
- write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 2), 0x98 + (0x100 * channel), 0x0d0fe006, data->f2x9cx0d0fe006);
- write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 2), 0x98 + (0x100 * channel), 0x0d0fe007, data->f2x9cx0d0fe007);
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0fe006, data->f2x9cx0d0fe006);
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0fe007, data->f2x9cx0d0fe007);
}
}
@@ -476,26 +830,26 @@ void restore_mct_data_from_save_variable(struct amd_s3_persistent_data* persiste
continue;
for (i=0; i<12; i++)
- write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 2), 0x98 + (0x100 * channel), 0x10 + i, data->f2x9cx10[i]);
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x10 + i, data->f2x9cx10[i]);
for (i=0; i<12; i++)
- write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 2), 0x98 + (0x100 * channel), 0x20 + i, data->f2x9cx20[i]);
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x20 + i, data->f2x9cx20[i]);
for (i=0; i<4; i++)
for (j=0; j<3; j++)
- write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 2), 0x98 + (0x100 * channel), (0x01 + i) + (0x100 * j), data->f2x9cx3_0_0_3_1[i][j]);
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, (0x01 + i) + (0x100 * j), data->f2x9cx3_0_0_3_1[i][j]);
for (i=0; i<4; i++)
for (j=0; j<3; j++)
- write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 2), 0x98 + (0x100 * channel), (0x05 + i) + (0x100 * j), data->f2x9cx3_0_0_7_5[i][j]);
- write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 2), 0x98 + (0x100 * channel), 0x0d, data->f2x9cx0d);
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, (0x05 + i) + (0x100 * j), data->f2x9cx3_0_0_7_5[i][j]);
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d, data->f2x9cx0d);
for (i=0; i<9; i++)
- write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 2), 0x98 + (0x100 * channel), 0x0d0f0013 | (i << 8), data->f2x9cx0d0f0_f_0_13[i]);
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f0013 | (i << 8), data->f2x9cx0d0f0_f_0_13[i]);
for (i=0; i<9; i++)
- write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 2), 0x98 + (0x100 * channel), 0x0d0f0030 | (i << 8), data->f2x9cx0d0f0_f_0_30[i]);
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f0030 | (i << 8), data->f2x9cx0d0f0_f_0_30[i]);
for (i=0; i<4; i++)
- write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 2), 0x98 + (0x100 * channel), 0x0d0f2030 | (i << 8), data->f2x9cx0d0f2_f_0_30[i]);
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f2030 | (i << 8), data->f2x9cx0d0f2_f_0_30[i]);
for (i=0; i<2; i++)
for (j=0; j<3; j++)
- write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 2), 0x98 + (0x100 * channel), 0x0d0f0000 | (i << 8) | (j * 4), data->f2x9cx0d0f8_8_4_0[i][j]);
- write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 2), 0x98 + (0x100 * channel), 0x0d0f812f, data->f2x9cx0d0f812f);
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f0000 | (i << 8) | (j * 4), data->f2x9cx0d0f8_8_4_0[i][j]);
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f812f, data->f2x9cx0d0f812f);
}
}
@@ -508,9 +862,9 @@ void restore_mct_data_from_save_variable(struct amd_s3_persistent_data* persiste
continue;
for (i=0; i<12; i++)
- write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 2), 0x98 + (0x100 * channel), 0x30 + i, data->f2x9cx30[i]);
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x30 + i, data->f2x9cx30[i]);
for (i=0; i<12; i++)
- write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 2), 0x98 + (0x100 * channel), 0x40 + i, data->f2x9cx40[i]);
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x40 + i, data->f2x9cx40[i]);
}
}
}
diff --git a/src/northbridge/amd/amdmct/wrappers/mcti.h b/src/northbridge/amd/amdmct/wrappers/mcti.h
index 7bfc25dc89..762ef11f44 100644
--- a/src/northbridge/amd/amdmct/wrappers/mcti.h
+++ b/src/northbridge/amd/amdmct/wrappers/mcti.h
@@ -2,6 +2,7 @@
* This file is part of the coreboot project.
*
* Copyright (C) 2007 Advanced Micro Devices, Inc.
+ * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering
*
* 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
@@ -58,10 +59,15 @@ UPDATE AS NEEDED
#endif
#ifndef MEM_MAX_LOAD_FREQ
-#if (CONFIG_DIMM_SUPPORT & 0x000F)==0x0005 /* AMD_FAM10_DDR3 */
- #define MEM_MAX_LOAD_FREQ 800
-#else
- #define MEM_MAX_LOAD_FREQ 400
+#if (CONFIG_DIMM_SUPPORT & 0x000F)==0x0005 /* AMD_FAM10_DDR3 */
+ #define MEM_MAX_LOAD_FREQ 933
+ #define MEM_MIN_PLATFORM_FREQ_FAM10 400
+ #define MEM_MIN_PLATFORM_FREQ_FAM15 333
+#else /* AMD_FAM10_DDR2 */
+ #define MEM_MAX_LOAD_FREQ 400
+ #define MEM_MIN_PLATFORM_FREQ_FAM10 200
+ /* DDR2 not available on Family 15h */
+ #define MEM_MIN_PLATFORM_FREQ_FAM15 0
#endif
#endif
diff --git a/src/northbridge/amd/amdmct/wrappers/mcti_d.c b/src/northbridge/amd/amdmct/wrappers/mcti_d.c
index fbcfd871a2..48ab8007ab 100644
--- a/src/northbridge/amd/amdmct/wrappers/mcti_d.c
+++ b/src/northbridge/amd/amdmct/wrappers/mcti_d.c
@@ -40,7 +40,7 @@
#define MINIMUM_DRAM_BELOW_4G 0x1000000
static const uint16_t ddr2_limits[4] = {400, 333, 266, 200};
-static const uint16_t ddr3_limits[4] = {800, 666, 533, 400};
+static const uint16_t ddr3_limits[16] = {933, 800, 666, 533, 400, 333, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
static u16 mctGet_NVbits(u8 index)
{
@@ -77,12 +77,19 @@ static u16 mctGet_NVbits(u8 index)
if (get_option(&nvram, "max_mem_clock") == CB_SUCCESS) {
int limit = val;
if (IS_ENABLED(CONFIG_DIMM_DDR3))
- limit = ddr3_limits[nvram & 3];
+ limit = ddr3_limits[nvram & 0xf];
else if (IS_ENABLED(CONFIG_DIMM_DDR2))
- limit = ddr2_limits[nvram & 3];
+ limit = ddr2_limits[nvram & 0x3];
val = min(limit, val);
}
break;
+ case NV_MIN_MEMCLK:
+ /* Minimum platform supported memclk */
+ if (is_fam15h())
+ val = MEM_MIN_PLATFORM_FREQ_FAM15;
+ else
+ val = MEM_MIN_PLATFORM_FREQ_FAM10;
+ break;
case NV_ECC_CAP:
#if SYSTEM_TYPE == SERVER
val = 1; /* memory bus ECC capable */
@@ -250,6 +257,9 @@ static u16 mctGet_NVbits(u8 index)
case NV_L2BKScrub:
val = 0; /* Disabled - See L2Scrub in BKDG */
break;
+ case NV_L3BKScrub:
+ val = 0; /* Disabled - See L3Scrub in BKDG */
+ break;
case NV_DCBKScrub:
val = 0; /* Disabled - See DcacheScrub in BKDG */
break;
@@ -299,6 +309,9 @@ static void mctGet_MaxLoadFreq(struct DCTStatStruc *pDCTstat)
int ch2_count = 0;
uint8_t ch1_registered = 0;
uint8_t ch2_registered = 0;
+ uint8_t ch1_voltage = 0;
+ uint8_t ch2_voltage = 0;
+ uint8_t highest_rank_count[2];
int i;
for (i = 0; i < 15; i = i + 2) {
if (pDCTstat->DIMMValid & (1 << i))
@@ -317,8 +330,28 @@ static void mctGet_MaxLoadFreq(struct DCTStatStruc *pDCTstat)
printk(BIOS_DEBUG, "mctGet_MaxLoadFreq: Channel 2: %d DIMM(s) detected\n", ch2_count);
}
+#if (CONFIG_DIMM_SUPPORT & 0x000F)==0x0005 /* AMD_FAM10_DDR3 */
+ uint8_t dimm;
+
+ for (i = 0; i < 15; i = i + 2) {
+ if (pDCTstat->DIMMValid & (1 << i))
+ ch1_voltage |= pDCTstat->DimmConfiguredVoltage[i];
+ if (pDCTstat->DIMMValid & (1 << (i + 1)))
+ ch2_voltage |= pDCTstat->DimmConfiguredVoltage[i + 1];
+ }
+
+ for (i = 0; i < 2; i++) {
+ sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[i];
+ highest_rank_count[i] = 0x0;
+ for (dimm = 0; dimm < 8; dimm++) {
+ if (pDCTData->DimmRanks[dimm] > highest_rank_count[i])
+ highest_rank_count[i] = pDCTData->DimmRanks[dimm];
+ }
+ }
+#endif
+
/* Set limits if needed */
- pDCTstat->PresetmaxFreq = mct_MaxLoadFreq(max(ch1_count, ch2_count), (ch1_registered || ch2_registered), pDCTstat->PresetmaxFreq);
+ pDCTstat->PresetmaxFreq = mct_MaxLoadFreq(max(ch1_count, ch2_count), max(highest_rank_count[0], highest_rank_count[1]), (ch1_registered || ch2_registered), (ch1_voltage | ch2_voltage), pDCTstat->PresetmaxFreq);
}
#ifdef UNUSED_CODE
@@ -482,7 +515,7 @@ static void mctHookAfterAnyTraining(void)
{
}
-static u32 mctGetLogicalCPUID_D(u8 node)
+static uint64_t mctGetLogicalCPUID_D(u8 node)
{
return mctGetLogicalCPUID(node);
}