diff options
author | Timothy Pearson <tpearson@raptorengineeringinc.com> | 2015-10-16 13:51:51 -0500 |
---|---|---|
committer | Martin Roth <martinroth@google.com> | 2015-11-02 23:45:19 +0100 |
commit | 730a043fb6cb4dd3cb5af8f8640365727b598648 (patch) | |
tree | 59afe45caca1a8e1682939c7e44e95344104533e /src/northbridge/amd/amdfam10 | |
parent | d150006c4a4584bc9933c2d8ff580a54c4f0cc2a (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/Kconfig | 2 | ||||
-rw-r--r-- | src/northbridge/amd/amdfam10/Makefile.inc | 2 | ||||
-rw-r--r-- | src/northbridge/amd/amdfam10/amdfam10.h | 6 | ||||
-rw-r--r-- | src/northbridge/amd/amdfam10/amdfam10_util.c | 13 | ||||
-rw-r--r-- | src/northbridge/amd/amdfam10/link_control.c | 86 | ||||
-rw-r--r-- | src/northbridge/amd/amdfam10/misc_control.c | 7 | ||||
-rw-r--r-- | src/northbridge/amd/amdfam10/nb_control.c | 85 | ||||
-rw-r--r-- | src/northbridge/amd/amdfam10/northbridge.c | 233 | ||||
-rw-r--r-- | src/northbridge/amd/amdfam10/raminit_amdmct.c | 304 |
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) { |