summaryrefslogtreecommitdiff
path: root/src/northbridge/amd/amdfam10
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/amdfam10
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/amdfam10')
-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
9 files changed, 664 insertions, 74 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)
{