diff options
Diffstat (limited to 'src/northbridge')
29 files changed, 1 insertions, 16080 deletions
diff --git a/src/northbridge/amd/amdk8/Kconfig b/src/northbridge/amd/amdk8/Kconfig deleted file mode 100644 index 83f70c90c2..0000000000 --- a/src/northbridge/amd/amdk8/Kconfig +++ /dev/null @@ -1,138 +0,0 @@ -## -## This file is part of the coreboot project. -## -## Copyright (C) 2007-2009 coresystems GmbH -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; version 2 of the License. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## - -config NORTHBRIDGE_AMD_AMDK8 - bool - select HAVE_DEBUG_RAM_SETUP - select HAVE_DEBUG_SMBUS - select HAVE_DEBUG_CAR - select HYPERTRANSPORT_PLUGIN_SUPPORT - select LATE_CBMEM_INIT - -if NORTHBRIDGE_AMD_AMDK8 - -config NO_MMCONF_SUPPORT - bool - default y - help - If you want to remove this, you need to make sure any access to CPU - nodes 0:18.0, 0:19.0, ... continue to use PCI IO config access. - -config AGP_APERTURE_SIZE - hex - default 0x4000000 - -config K8_HT_FREQ_1G_SUPPORT - bool - default n - -config RAMINIT_SYSINFO - bool - default n - -config WAIT_BEFORE_CPUS_INIT - bool - default n - -# Force 2T DRAM timing (vendor BIOS does it even for single DIMM setups and -# single DIMM is indeed unreliable without it). -config K8_FORCE_2T_DRAM_TIMING - bool - default n - -config HW_MEM_HOLE_SIZEK - hex - default 0x100000 - -config HW_MEM_HOLE_SIZE_AUTO_INC - bool - default n - -config BOOTBLOCK_NORTHBRIDGE_INIT - string - default "northbridge/amd/amdk8/bootblock.c" - -config SB_HT_CHAIN_UNITID_OFFSET_ONLY - bool - default n - -config HT_CHAIN_DISTRIBUTE - def_bool n - -config QRANK_DIMM_SUPPORT - bool - default n - -config K8_ALLOCATE_IO_RANGE - bool - default n - -config K8_REV_F_SUPPORT - bool - select RAMINIT_SYSINFO - default n - -if K8_REV_F_SUPPORT - -config DIMM_DDR2 - bool - default n - -config DIMM_REGISTERED - bool - default n - -if DIMM_DDR2 - if DIMM_REGISTERED - config DIMM_SUPPORT - hex - default 0x0104 - endif - - if !DIMM_REGISTERED - config DIMM_SUPPORT - hex - default 0x0004 - endif -endif #DIMM_DDR2 - -config MEM_TRAIN_SEQ - int - default 0 - -endif #K8_REV_F_SUPPORT - -# TODO: Reservation for heap seems excessive -config HEAP_SIZE - hex - default 0x40000 - -config IOMMU - bool - default y - -config CBB - hex - default 0x00 - -config CDB - hex - default 0x18 - -config MAX_REBOOT_CNT - int - default 6 - -endif #NORTHBRIDGE_AMD_K8 diff --git a/src/northbridge/amd/amdk8/Makefile.inc b/src/northbridge/amd/amdk8/Makefile.inc deleted file mode 100644 index 263e06f201..0000000000 --- a/src/northbridge/amd/amdk8/Makefile.inc +++ /dev/null @@ -1,42 +0,0 @@ -ifeq ($(CONFIG_NORTHBRIDGE_AMD_AMDK8),y) - -ramstage-y += northbridge.c -ramstage-y += misc_control.c -ramstage-y += get_sblk_pci1234.c -ramstage-$(CONFIG_HAVE_ACPI_TABLES) += acpi.c - -romstage-y += debug.c -ifeq ($(CONFIG_K8_REV_F_SUPPORT),y) -romstage-$(CONFIG_HAVE_ACPI_RESUME) += exit_from_self.c -romstage-y += raminit_f.c -endif - -romstage-y += reset_test.c -romstage-y += coherent_ht.c - -# Enable this if you want to check the values of the PCI routing registers. -# Call show_all_routes() anywhere amdk8.h is included. -#ramstage-y += util.c - -# Not sure what to do with these yet. How did raminit_test even work? -# Should be a target in -y form. -#if IS_ENABLED(CONFIG_K8_REV_F_SUPPORT) -# -#makerule raminit_test -# depends "$(TOP)/src/northbridge/amd/amdk8/raminit_test.c" -# depends "$(TOP)/src/northbridge/amd/amdk8/raminit_f.c" -# action "$(HOSTCC) $(HOSTCFLAGS) $(CPUFLAGS) -Wno-unused-function -I$(TOP)/src/include -g $< -o $@" -#end -# -#else -# -#makerule raminit_test -# depends "$(TOP)/src/northbridge/amd/amdk8/raminit_test.c" -# depends "$(TOP)/src/northbridge/amd/amdk8/raminit.c" -# action "$(HOSTCC) $(HOSTCFLAGS) $(CPUFLAGS) -Wno-unused-function -I$(TOP)/src/include -g $< -o $@" -#end -# -#end -# - -endif diff --git a/src/northbridge/amd/amdk8/acpi.c b/src/northbridge/amd/amdk8/acpi.c deleted file mode 100644 index 0d42911697..0000000000 --- a/src/northbridge/amd/amdk8/acpi.c +++ /dev/null @@ -1,311 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2005 Advanced Micro Devices, Inc. - * Copyright (C) 2010 Advanced Micro Devices, Inc. - * - * 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; either version 2 of the License, or - * (at your option) any later version. - * - * 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. - */ - -/* - * Description: Add madt lapic creat dynamically and SRAT related by yhlu -*/ - -#include <console/console.h> -#include <string.h> -#include <arch/acpi.h> -#include <arch/acpigen.h> -#include <device/pci.h> -#include <cpu/x86/msr.h> -#include <cpu/amd/mtrr.h> -#include <cpu/amd/amdk8_sysconf.h> -#include "acpi.h" - -//it seems some functions can be moved arch/x86/boot/acpi.c - -unsigned long acpi_create_madt_lapic_nmis(unsigned long current, u16 flags, u8 lint) -{ - struct device *cpu; - int cpu_index = 0; - - for (cpu = all_devices; cpu; cpu = cpu->next) { - if ((cpu->path.type != DEVICE_PATH_APIC) || - (cpu->bus->dev->path.type != DEVICE_PATH_CPU_CLUSTER)) { - continue; - } - if (!cpu->enabled) { - continue; - } - current += acpi_create_madt_lapic_nmi((acpi_madt_lapic_nmi_t *)current, cpu_index, flags, lint); - cpu_index++; - } - return current; -} - -unsigned long acpi_create_srat_lapics(unsigned long current) -{ - struct device *cpu; - int cpu_index = 0; - - for (cpu = all_devices; cpu; cpu = cpu->next) { - if ((cpu->path.type != DEVICE_PATH_APIC) || - (cpu->bus->dev->path.type != DEVICE_PATH_CPU_CLUSTER)) { - continue; - } - if (!cpu->enabled) { - continue; - } - printk(BIOS_DEBUG, "SRAT: lapic cpu_index=%02x, node_id=%02x, apic_id=%02x\n", cpu_index, cpu->path.apic.node_id, cpu->path.apic.apic_id); - current += acpi_create_srat_lapic((acpi_srat_lapic_t *)current, cpu->path.apic.node_id, cpu->path.apic.apic_id); - cpu_index++; - } - return current; -} - -static unsigned long resk(uint64_t value) -{ - unsigned long resultk; - if (value < (1ULL << 42)) { - resultk = value >> 10; - } else { - resultk = 0xffffffff; - } - return resultk; -} - -struct acpi_srat_mem_state { - unsigned long current; -}; - -static void set_srat_mem(void *gp, struct device *dev, struct resource *res) -{ - struct acpi_srat_mem_state *state = gp; - unsigned long basek, sizek; - basek = resk(res->base); - sizek = resk(res->size); - - printk(BIOS_DEBUG, "set_srat_mem: dev %s, res->index=%04lx startk=%08lx, sizek=%08lx\n", - dev_path(dev), res->index, basek, sizek); - /* - * 0-640K must be on node 0 - * next range is from 1M--- - * So will cut off before 1M in the mem range - */ - if ((basek+sizek)<1024) return; - - if (basek < 1024) { - sizek -= 1024 - basek; - basek = 1024; - } - - // need to figure out NV - state->current += acpi_create_srat_mem((acpi_srat_mem_t *)state->current, (res->index & 0xf), basek, sizek, 1); -} - -static unsigned long acpi_fill_srat(unsigned long current) -{ - struct acpi_srat_mem_state srat_mem_state; - - /* create all subtables for processors */ - current = acpi_create_srat_lapics(current); - - /* create all subteble for memory range */ - - /* 0-640K must be on node 0 */ - current += acpi_create_srat_mem((acpi_srat_mem_t *)current, 0, 0, 640, 1);//enable - - srat_mem_state.current = current; - search_global_resources( - IORESOURCE_MEM | IORESOURCE_CACHEABLE, IORESOURCE_MEM | IORESOURCE_CACHEABLE, - set_srat_mem, &srat_mem_state); - - current = srat_mem_state.current; - return current; -} - -static unsigned long acpi_fill_slit(unsigned long current) -{ - /* need to find out the node num at first */ - /* fill the first 8 byte with that num */ - /* fill the next num*num byte with distance, local is 10, 1 hop mean 20, and 2 hop with 30.... */ - - /* because We has assume that we know the topology of the HT connection, So we can have set if we know the node_num */ - static u8 hops_8[] = { 0, 1, 1, 2, 2, 3, 3, 4, - 1, 0, 2, 1, 3, 2, 4, 3, - 1, 2, 0, 1, 1, 2, 2, 3, - 2, 1, 1, 0, 2, 1, 3, 2, - 2, 3, 1, 2, 0, 1, 1, 2, - 3, 2, 2, 1, 1, 0, 2, 1, - 3, 4, 2, 3, 1, 2, 0, 1, - 4, 4, 3, 2, 2, 1, 1, 0 }; - - u8 *p = (u8 *)current; - int nodes = sysconf.nodes; - int i,j; - memset(p, 0, 8+nodes*nodes); - *p = (u8) nodes; - p += 8; - - for (i = 0; i < nodes; i++) { - for (j = 0; j < nodes; j++) { - if (i == j) { - p[i*nodes+j] = 10; - } else { - p[i*nodes+j] = hops_8[i*nodes+j] * 2 + 10; - - } - } - } - - current += 8+nodes*nodes; - - return current; -} - -unsigned long northbridge_write_acpi_tables( - struct device *device, - unsigned long start, - acpi_rsdp_t *rsdp) -{ - unsigned long current; - acpi_srat_t *srat; - acpi_slit_t *slit; - - current = start; - - /* Fills sysconf structure needed for SRAT and SLIT. */ - get_bus_conf(); - - current = ALIGN(current, 16); - srat = (acpi_srat_t *) current; - printk(BIOS_DEBUG, "ACPI: * SRAT @ %p\n", srat); - acpi_create_srat(srat, acpi_fill_srat); - current += srat->header.length; - acpi_add_table(rsdp, srat); - - /* SLIT */ - current = ALIGN(current, 16); - slit = (acpi_slit_t *) current; - printk(BIOS_DEBUG, "ACPI: * SLIT @ %p\n", slit); - acpi_create_slit(slit, acpi_fill_slit); - current+=slit->header.length; - acpi_add_table(rsdp,slit); - - return current; -} - -static void k8acpi_write_HT(void) { - int i; - - acpigen_write_name("HCLK"); - acpigen_write_package(HC_POSSIBLE_NUM); - - for (i = 0; i < sysconf.hc_possible_num; i++) { - acpigen_write_dword(sysconf.pci1234[i]); - } - for (i = sysconf.hc_possible_num; i < HC_POSSIBLE_NUM; i++) { // in case we set array size to other than 8 - acpigen_write_dword(0x0); - } - - acpigen_pop_len(); - - acpigen_write_name("HCDN"); - acpigen_write_package(HC_POSSIBLE_NUM); - - for (i = 0; i < sysconf.hc_possible_num; i++) { - acpigen_write_dword(sysconf.hcdn[i]); - } - for (i = sysconf.hc_possible_num; i < HC_POSSIBLE_NUM; i++) { // in case we set array size to other than 8 - acpigen_write_dword(0x20202020); - } - acpigen_pop_len(); -} - -static void k8acpi_write_pci_data(int dlen, const char *name, int offset) { - struct device *dev; - uint32_t dword; - int i; - - dev = dev_find_slot(0, PCI_DEVFN(0x18, 1)); - - acpigen_write_name(name); - acpigen_write_package(dlen); - for (i = 0; i < dlen; i++) { - dword = pci_read_config32(dev, offset+i*4); - acpigen_write_dword(dword); - } - // minus the opcode - acpigen_pop_len(); -} - -void k8acpi_write_vars(struct device *device) -{ - /* - * If more than one physical CPU is installed k8acpi_write_vars() - * is called more than once. If we don't prevent it, a SSDT table - * with duplicate variables will cause some ACPI parsers to be - * confused enough to fail. - */ - static uint8_t ssdt_generated = 0; - if (ssdt_generated) - return; - ssdt_generated = 1; - - msr_t msr; - char pscope[] = "\\_SB.PCI0"; - - acpigen_write_scope(pscope); - k8acpi_write_pci_data(4, "BUSN", 0xe0); - k8acpi_write_pci_data(8, "PCIO", 0xc0); - k8acpi_write_pci_data(16, "MMIO", 0x80); - acpigen_write_name_byte("SBLK", sysconf.sblk); - acpigen_write_name_byte("CBST", - ((sysconf.pci1234[0] >> 12) & 0xff) ? 0xf : 0x0); - acpigen_write_name_dword("SBDN", sysconf.sbdn); - msr = rdmsr(TOP_MEM); - acpigen_write_name_dword("TOM1", msr.lo); - msr = rdmsr(TOP_MEM2); - /* - * Since XP only implements parts of ACPI 2.0, we can't use a qword - * here. - * See http://www.acpi.info/presentations/S01USMOBS169_OS%2520new.ppt - * slide 22ff. - * Shift value right by 20 bit to make it fit into 32bit, - * giving us 1MB granularity and a limit of almost 4Exabyte of memory. - */ - acpigen_write_name_dword("TOM2", (msr.hi << 12) | msr.lo >> 20); - - k8acpi_write_HT(); - //minus opcode - acpigen_pop_len(); -} - -void update_ssdtx(void *ssdtx, int i) -{ - u8 *PCI; - u8 *HCIN; - u8 *UID; - - PCI = ssdtx + 0x32; - HCIN = ssdtx + 0x39; - UID = ssdtx + 0x40; - - if (i < 7) { - *PCI = (u8) ('4' + i - 1); - } else { - *PCI = (u8) ('A' + i - 1 - 6); - } - *HCIN = (u8) i; - *UID = (u8) (i + 3); - - /* FIXME: need to update the GSI id in the ssdtx too */ - -} diff --git a/src/northbridge/amd/amdk8/acpi.h b/src/northbridge/amd/amdk8/acpi.h deleted file mode 100644 index 934792d1cc..0000000000 --- a/src/northbridge/amd/amdk8/acpi.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2009 Rudolf Marek <r.marek@assembler.cz> - * - * 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. - */ - -#ifndef AMDK8_ACPI_H -#define AMDK8_ACPI_H -#include <arch/acpigen.h> - -void k8acpi_write_vars(struct device *device); -unsigned long northbridge_write_acpi_tables(struct device *device, - unsigned long start, - acpi_rsdp_t *rsdp); - -#endif diff --git a/src/northbridge/amd/amdk8/amdk8.h b/src/northbridge/amd/amdk8/amdk8.h index 363e9a45b1..d8cbc36ff8 100644 --- a/src/northbridge/amd/amdk8/amdk8.h +++ b/src/northbridge/amd/amdk8/amdk8.h @@ -12,18 +12,9 @@ */ #ifndef AMDK8_H - #define AMDK8_H -#if IS_ENABLED(CONFIG_K8_REV_F_SUPPORT) - -#define K8_REV_F_SUPPORT_F0_F1_WORKAROUND 0 - - #include "f.h" -#else - #include "pre_f.h" -#endif - +#define HT_INIT_CONTROL 0x6C #define HTIC_ColdR_Detect (1<<4) #define HTIC_BIOSR_Detect (1<<5) #define HTIC_INIT_Detect (1<<6) @@ -32,25 +23,9 @@ #define NODE_MP(x) PCI_DEV(0,24+x,1) #define NODE_MC(x) PCI_DEV(0,24+x,3) - -#ifdef __PRE_RAM__ -void showallroutes(int level, pci_devfn_t dev); -void setup_resource_map_offset(const unsigned int *register_values, int max, unsigned offset_pci_dev, unsigned offset_io_base); -void fill_mem_ctrl(int controllers, struct mem_controller *ctrl_a, const uint16_t *spd_addr); -int optimize_link_coherent_ht(void); -unsigned int get_nodes(void); -#if IS_ENABLED(CONFIG_RAMINIT_SYSINFO) -void setup_coherent_ht_domain(void); -#else -int setup_coherent_ht_domain(void); -#endif -#endif - void set_bios_reset(void); void distinguish_cpu_resets(unsigned int nodeid); unsigned int get_sblk(void); unsigned int get_sbbusn(unsigned sblk); -void cpus_ready_for_init(void); - #endif /* AMDK8_H */ diff --git a/src/northbridge/amd/amdk8/bootblock.c b/src/northbridge/amd/amdk8/bootblock.c deleted file mode 100644 index 411b58ad07..0000000000 --- a/src/northbridge/amd/amdk8/bootblock.c +++ /dev/null @@ -1,20 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * 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. - */ - -#include <arch/io.h> -#include <device/pci_def.h> -#include "northbridge/amd/amdk8/early_ht.c" - -static void bootblock_northbridge_init(void) { - enumerate_ht_chain(); -} diff --git a/src/northbridge/amd/amdk8/coherent_ht.c b/src/northbridge/amd/amdk8/coherent_ht.c deleted file mode 100644 index 1f8b9cedc2..0000000000 --- a/src/northbridge/amd/amdk8/coherent_ht.c +++ /dev/null @@ -1,1809 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * written by Stefan Reinauer <stepan@openbios.org> - * (c) 2003-2004 by SuSE Linux AG - * - * (c) 2004 Tyan Computer - * 2004.12 yhlu added support to create routing table dynamically. - * it also support 8 ways too. (8 ways ladder or 8 ways crossbar) - * - * 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. - */ - -/* coherent hypertransport initialization for AMD64 - */ - -/* - * This algorithm assumes a grid configuration as follows: - * - * nodes : 1 2 4 6 8 - * org. : 1x1 2x1 2x2 2x3 2x4 - Ladder: - CPU7-------------CPU6 - | | - | | - | | - | | - | | - | | - CPU5-------------CPU4 - | | - | | - | | - | | - | | - | | - CPU3-------------CPU2 - | | - | | - | | - | | - | | - | | - CPU1-------------CPU0 - CROSS_BAR_47_56: - CPU7-------------CPU6 - | \____ ___/ | - | \ / | - | \/ | - | /\ | - | / \ | - | ____/ \___ | - CPU5 CPU4 - | | - | | - | | - | | - | | - | | - CPU3-------------CPU2 - | | - | | - | | - | | - | | - | | - CPU1-------------CPU0 - */ - -#include <console/console.h> -#include <cpu/amd/model_fxx_rev.h> -#include <device/pci_def.h> -#include <device/pci_ids.h> -#include <device/hypertransport_def.h> -#include <lib.h> -#include <stdlib.h> -#include <stdint.h> -#include <arch/io.h> -#include <pc80/mc146818rtc.h> -#if IS_ENABLED(CONFIG_HAVE_OPTION_TABLE) -#include "option_table.h" -#endif - -#include "amdk8.h" - -#define enable_bsp_routing() enable_routing(0) - -#define DEFAULT 0x00010101 /* default row entry */ - - -#ifndef CROSS_BAR_47_56 - #define CROSS_BAR_47_56 0 -#endif - -#ifndef TRY_HIGH_FIRST - #define TRY_HIGH_FIRST 0 -#endif - -#ifndef K8_HT_CHECK_PENDING_LINK - #if CONFIG_MAX_PHYSICAL_CPUS >= 4 - #define K8_HT_CHECK_PENDING_LINK 1 - #else - #define K8_HT_CHECK_PENDING_LINK 0 - #endif -#endif - -#ifndef CONFIG_MAX_PHYSICAL_CPUS_4_BUT_MORE_INSTALLED - #define CONFIG_MAX_PHYSICAL_CPUS_4_BUT_MORE_INSTALLED 0 -#endif - -static inline void print_linkn (const char *strval, uint8_t byteval) -{ - printk(BIOS_DEBUG, "%s%02x\n", strval, byteval); -} - -static void disable_probes(void) -{ - /* disable read/write/fill probes for uniprocessor setup - * they don't make sense if only one CPU is available - */ - - /* Hypetransport Transaction Control Register - * F0:0x68 - * [ 0: 0] Disable read byte probe - * 0 = Probes issues - * 1 = Probes not issued - * [ 1: 1] Disable Read Doubleword probe - * 0 = Probes issued - * 1 = Probes not issued - * [ 2: 2] Disable write byte probes - * 0 = Probes issued - * 1 = Probes not issued - * [ 3: 3] Disable Write Doubleword Probes - * 0 = Probes issued - * 1 = Probes not issued. - * [10:10] Disable Fill Probe - * 0 = Probes issued for cache fills - * 1 = Probes not issued for cache fills. - */ - - u32 val; - - printk(BIOS_SPEW, "Disabling read/write/fill probes for UP... "); - - val = pci_read_config32(NODE_HT(0), HT_TRANSACTION_CONTROL); - val |= HTTC_DIS_FILL_P | HTTC_DIS_RMT_MEM_C | HTTC_DIS_P_MEM_C | - HTTC_DIS_MTS | HTTC_DIS_WR_DW_P | HTTC_DIS_WR_B_P | - HTTC_DIS_RD_DW_P | HTTC_DIS_RD_B_P; - pci_write_config32(NODE_HT(0), HT_TRANSACTION_CONTROL, val); - - printk(BIOS_SPEW, "done.\n"); - -} - -static void enable_routing(u8 node) -{ - u32 val; - - /* HT Initialization Control Register - * F0:0x6C - * [ 0: 0] Routing Table Disable - * 0 = Packets are routed according to routing tables - * 1 = Packets are routed according to the default link field - * [ 1: 1] Request Disable (BSP should clear this) - * 0 = Request packets may be generated - * 1 = Request packets may not be generated. - * [ 3: 2] Default Link (Read-only) - * 00 = LDT0 - * 01 = LDT1 - * 10 = LDT2 - * 11 = CPU on same node - * [ 4: 4] Cold Reset - * - Scratch bit cleared by a cold reset - * [ 5: 5] BIOS Reset Detect - * - Scratch bit cleared by a cold reset - * [ 6: 6] INIT Detect - * - Scratch bit cleared by a warm or cold reset not by an INIT - * - */ - - /* Enable routing table */ - printk(BIOS_SPEW, "Enabling routing table for node %d", node); - - val = pci_read_config32(NODE_HT(node), 0x6c); - val &= ~((1<<1)|(1<<0)); - pci_write_config32(NODE_HT(node), 0x6c, val); - - printk(BIOS_SPEW, " done.\n"); -} - -#if CONFIG_MAX_PHYSICAL_CPUS > 1 -static void fill_row(u8 node, u8 row, u32 value) -{ - pci_write_config32(NODE_HT(node), 0x40+(row<<2), value); -} - -static u8 link_to_register(int ldt) -{ - /* - * [ 0: 3] Request Route - * [0] Route to this node - * [1] Route to Link 0 - * [2] Route to Link 1 - * [3] Route to Link 2 - */ - - if (ldt&0x08) return 0x40; - if (ldt&0x04) return 0x20; - if (ldt&0x02) return 0x00; - - /* we should never get here */ - printk(BIOS_SPEW, "Unknown Link\n"); - return 0; -} - -static u32 get_row(u8 node, u8 row) -{ - return pci_read_config32(NODE_HT(node), 0x40+(row<<2)); -} - -static int link_connection(u8 src, u8 dest) -{ - return get_row(src, dest) & 0x0f; -} - -static void rename_temp_node(u8 node) -{ - uint32_t val; - - printk(BIOS_SPEW, "Renaming current temporary node to %d", node); - - val = pci_read_config32(NODE_HT(7), 0x60); - val &= (~7); /* clear low bits. */ - val |= node; /* new node */ - pci_write_config32(NODE_HT(7), 0x60, val); - - printk(BIOS_SPEW, " done.\n"); -} - -static int verify_connection(u8 dest) -{ - /* See if we have a valid connection to dest */ - u32 val; - - /* Verify that the coherent hypertransport link is - * established and actually working by reading the - * remode node's vendor/device id - */ - val = pci_read_config32(NODE_HT(dest),0); - if (val != 0x11001022) - return 0; - - return 1; -} - -static uint16_t read_freq_cap(pci_devfn_t dev, uint8_t pos) -{ - /* Handle bugs in valid hypertransport frequency reporting */ - uint16_t freq_cap; - uint32_t id; - - freq_cap = pci_read_config16(dev, pos); - freq_cap &= ~(1 << HT_FREQ_VENDOR); /* Ignore Vendor HT frequencies */ - -#if IS_ENABLED(CONFIG_K8_HT_FREQ_1G_SUPPORT) - #if !IS_ENABLED(CONFIG_K8_REV_F_SUPPORT) - if (!is_cpu_pre_e0()) - #endif - { - return freq_cap; - } -#endif - - id = pci_read_config32(dev, 0); - - /* AMD K8 Unsupported 1GHz? */ - if (id == (PCI_VENDOR_ID_AMD | (0x1100 << 16))) { - freq_cap &= ~(1 << HT_FREQ_1000Mhz); - } - - return freq_cap; -} - -static int optimize_connection(pci_devfn_t node1, uint8_t link1, - pci_devfn_t node2, uint8_t link2) -{ - static const uint8_t link_width_to_pow2[]= { 3, 4, 0, 5, 1, 2, 0, 0 }; - static const uint8_t pow2_to_link_width[] = { 0x7, 4, 5, 0, 1, 3 }; - uint16_t freq_cap1, freq_cap2; - uint8_t width_cap1, width_cap2, width, old_width, ln_width1, ln_width2; - uint8_t freq, old_freq; - int needs_reset; - /* Set link width and frequency */ - - /* Initially assume everything is already optimized and I don't need a reset */ - needs_reset = 0; - - /* Get the frequency capabilities */ - freq_cap1 = read_freq_cap(node1, link1 + PCI_HT_CAP_HOST_FREQ_CAP); - freq_cap2 = read_freq_cap(node2, link2 + PCI_HT_CAP_HOST_FREQ_CAP); - - /* Calculate the highest possible frequency */ - freq = log2(freq_cap1 & freq_cap2); - - /* See if I am changing the link freqency */ - old_freq = pci_read_config8(node1, link1 + PCI_HT_CAP_HOST_FREQ); - old_freq &= 0x0f; - needs_reset |= old_freq != freq; - old_freq = pci_read_config8(node2, link2 + PCI_HT_CAP_HOST_FREQ); - old_freq &= 0x0f; - needs_reset |= old_freq != freq; - - /* Set the Calulcated link frequency */ - pci_write_config8(node1, link1 + PCI_HT_CAP_HOST_FREQ, freq); - pci_write_config8(node2, link2 + PCI_HT_CAP_HOST_FREQ, freq); - - /* Get the width capabilities */ - width_cap1 = pci_read_config8(node1, link1 + PCI_HT_CAP_HOST_WIDTH); - width_cap2 = pci_read_config8(node2, link2 + PCI_HT_CAP_HOST_WIDTH); - - /* Calculate node1's input width */ - ln_width1 = link_width_to_pow2[width_cap1 & 7]; - ln_width2 = link_width_to_pow2[(width_cap2 >> 4) & 7]; - if (ln_width1 > ln_width2) { - ln_width1 = ln_width2; - } - width = pow2_to_link_width[ln_width1]; - /* Calculate node1's output width */ - ln_width1 = link_width_to_pow2[(width_cap1 >> 4) & 7]; - ln_width2 = link_width_to_pow2[width_cap2 & 7]; - if (ln_width1 > ln_width2) { - ln_width1 = ln_width2; - } - width |= pow2_to_link_width[ln_width1] << 4; - - /* See if I am changing node1's width */ - old_width = pci_read_config8(node1, link1 + PCI_HT_CAP_HOST_WIDTH + 1); - old_width &= 0x77; - needs_reset |= old_width != width; - - /* Set node1's widths */ - pci_write_config8(node1, link1 + PCI_HT_CAP_HOST_WIDTH + 1, width); - - // * Calculate node2's width */ - width = ((width & 0x70) >> 4) | ((width & 0x7) << 4); - - /* See if I am changing node2's width */ - old_width = pci_read_config8(node2, link2 + PCI_HT_CAP_HOST_WIDTH + 1); - old_width &= 0x77; - needs_reset |= old_width != width; - - /* Set node2's widths */ - pci_write_config8(node2, link2 + PCI_HT_CAP_HOST_WIDTH + 1, width); - - return needs_reset; -} - -static uint8_t get_linkn_first(uint8_t byte) -{ - if (byte & 0x02) { byte = 0; } - else if (byte & 0x04) { byte = 1; } - else if (byte & 0x08) { byte = 2; } - return byte; -} - -#if TRY_HIGH_FIRST == 1 -static uint8_t get_linkn_last(uint8_t byte) -{ - if (byte & 0x02) { byte &= 0x0f; byte |= 0x00; } - if (byte & 0x04) { byte &= 0x0f; byte |= 0x10; } - if (byte & 0x08) { byte &= 0x0f; byte |= 0x20; } - return byte>>4; -} -#endif - -#if (CONFIG_MAX_PHYSICAL_CPUS > 2) || CONFIG_MAX_PHYSICAL_CPUS_4_BUT_MORE_INSTALLED -static uint8_t get_linkn_last_count(uint8_t byte) -{ - byte &= 0x0f; - if (byte & 0x02) { byte &= 0xcf; byte |= 0x00; byte+=0x40; } - if (byte & 0x04) { byte &= 0xcf; byte |= 0x10; byte+=0x40; } - if (byte & 0x08) { byte &= 0xcf; byte |= 0x20; byte+=0x40; } - return byte>>4; -} -#endif - -static void setup_row_local(u8 source, u8 row) /* source will be 7 when it is for temp use*/ -{ - uint8_t linkn; - uint32_t val; - val = 1; - for (linkn = 0; linkn < 3; linkn++) { - uint8_t regpos; - uint32_t reg; - regpos = 0x98 + 0x20 * linkn; - reg = pci_read_config32(NODE_HT(source), regpos); - if ((reg & 0x17) != 3) continue; /* it is not conherent or not connected*/ - val |= 1<<(linkn+1); - } - val <<= 16; - val |= 0x0101; - fill_row(source,row, val); -} - -static void setup_row_direct_x(u8 temp, u8 source, u8 dest, u8 linkn) -{ - uint32_t val; - uint32_t val_s; - val = 1<<(linkn+1); - val |= 1<<(linkn+1+8); /*for direct connect response route should equal to request table*/ - - if (((source &1)!=(dest &1)) -#if CROSS_BAR_47_56 - && ((source < 4)||(source > 5)) //(6,7) (7,6) should still be here - //(6,5) (7,4) should be here -#endif - ) { - val |= (1<<16); - } else { - /*for CROSS_BAR_47_56 47, 56, should be here too - and for 47, 56, 57, 75, 46, 64 we need to substract another link to - 6, 7, 6, 6, 7, 7 - */ - val_s = get_row(temp, source); - val |= ((val_s>>16) - (1<<(linkn+1)))<<16; - } - - fill_row(temp,dest, val); -} - -#if CROSS_BAR_47_56 -static void opt_broadcast_rt(u8 source, u8 dest, u8 kickout) -{ - uint32_t val; - val = get_row(source, dest); - val -= link_connection(source, kickout)<<16; - fill_row(source, dest, val); -} - -static void opt_broadcast_rt_group(const u8 *conn, int num) -{ - int i; - - for (i = 0; i < num; i+=3) { - opt_broadcast_rt(conn[i], conn[i+1],conn[i+2]); - } -} - -static void opt_broadcast_rt_plus(u8 source, u8 dest, u8 kickout) -{ - uint32_t val; - val = get_row(source, dest); - val += link_connection(source, kickout)<<16; - fill_row(source, dest, val); -} - -static void opt_broadcast_rt_plus_group(const u8 *conn, int num) -{ - int i; - - for (i = 0; i < num; i+=3) { - opt_broadcast_rt_plus(conn[i], conn[i+1],conn[i+2]); - } -} -#endif - -static void setup_row_direct(u8 source, u8 dest, u8 linkn) -{ - setup_row_direct_x(source, source, dest, linkn); -} - -static void setup_remote_row_direct(u8 source, u8 dest, u8 linkn) -{ - setup_row_direct_x(7, source, dest, linkn); -} - -static void setup_temp_row(u8 source, u8 dest) -{ - /* copy value from (source, dest) to (source,7) */ - fill_row(source, 7, get_row(source, dest)); -} - -static void setup_remote_node(u8 node) -{ - static const uint8_t pci_reg[] = { - 0x44, 0x4c, 0x54, 0x5c, 0x64, 0x6c, 0x74, 0x7c, - 0x40, 0x48, 0x50, 0x58, 0x60, 0x68, 0x70, 0x78, - 0x84, 0x8c, 0x94, 0x9c, 0xa4, 0xac, 0xb4, 0xbc, - 0x80, 0x88, 0x90, 0x98, 0xa0, 0xa8, 0xb0, 0xb8, - 0xc4, 0xcc, 0xd4, 0xdc, - 0xc0, 0xc8, 0xd0, 0xd8, - 0xe0, 0xe4, 0xe8, 0xec, - }; - int i; - - printk(BIOS_SPEW, "setup_remote_node: "); - - /* copy the default resource map from node 0 */ - for (i = 0; i < ARRAY_SIZE(pci_reg); i++) { - uint32_t value; - uint8_t reg; - reg = pci_reg[i]; - value = pci_read_config32(NODE_MP(0), reg); - pci_write_config32(NODE_MP(7), reg, value); - - } - printk(BIOS_SPEW, "done\n"); -} - -#endif /* CONFIG_MAX_PHYSICAL_CPUS > 1*/ - - -#if CONFIG_MAX_PHYSICAL_CPUS > 2 -#if !CROSS_BAR_47_56 -static void setup_row_indirect_x(u8 temp, u8 source, u8 dest) -#else -static void setup_row_indirect_x(u8 temp, u8 source, u8 dest, u8 gateway, u8 diff) -#endif -{ - /*for indirect connection, we need to compute the val from val_s(source, source), and val_g(source, gateway) */ - uint32_t val_s; - uint32_t val; -#if !CROSS_BAR_47_56 - u8 gateway; - u8 diff; - if (source < dest) { - gateway = source + 2; - } else { - gateway = source - 2; - } -#endif - val_s = get_row(temp, source); - val = get_row(temp, gateway); - - val &= 0xffff; - val_s >>= 16; - val_s &= 0xfe; - -#if !CROSS_BAR_47_56 - diff = ((source&1)!=(dest &1)); -#endif - - if (diff && (val_s!=(val&0xff))) { /* use another connect as response*/ - val_s -= val & 0xff; -#if (CONFIG_MAX_PHYSICAL_CPUS > 4) || CONFIG_MAX_PHYSICAL_CPUS_4_BUT_MORE_INSTALLED - uint8_t byte; - /* Some node have two links left - * don't worry we only have (2, (3 as source need to handle - */ - byte = val_s; - byte = get_linkn_last_count(byte); - if ((byte>>2)>1) { /* make sure not the corner*/ - if (source < dest) { - val_s-=link_connection(temp, source-2); /* -down*/ - } else { -#if CROSS_BAR_47_56 - if (source < gateway) { // for 5, 4 via 7 - val_s-=link_connection(temp, source-2); - } else -#endif - val_s-=link_connection(temp, source+2); /* -up*/ - } - } -#endif - val &= 0xff; - val |= (val_s<<8); - } - - if (diff) { /* cross rung?*/ - val |= (1<<16); - } - else { - val_s = get_row(temp, source); - val |= ((val_s>>16) - link_connection(temp, gateway))<<16; - } - - fill_row(temp, dest, val); - -} - -#if !CROSS_BAR_47_56 -static void setup_row_indirect(u8 source, u8 dest) -{ - setup_row_indirect_x(source, source, dest); -} -#else -static void setup_row_indirect(u8 source, u8 dest, u8 gateway, u8 diff) -{ - setup_row_indirect_x(source, source, dest, gateway, diff); -} -#endif - -static void setup_row_indirect_group(const u8 *conn, int num) -{ - int i; - -#if !CROSS_BAR_47_56 - for (i = 0; i < num; i+=2) { - setup_row_indirect(conn[i], conn[i+1]); -#else - for (i = 0; i < num; i+=4) { - setup_row_indirect(conn[i], conn[i+1],conn[i+2], conn[i+3]); -#endif - - } -} - -#if !CROSS_BAR_47_56 -static void setup_remote_row_indirect(u8 source, u8 dest) -{ - setup_row_indirect_x(7, source, dest); -} -#else -static void setup_remote_row_indirect(u8 source, u8 dest, u8 gateway, u8 diff) -{ - setup_row_indirect_x(7, source, dest, gateway, diff); -} -#endif - -static void setup_remote_row_indirect_group(const u8 *conn, int num) -{ - int i; - -#if !CROSS_BAR_47_56 - for (i = 0; i < num; i+=2) { - setup_remote_row_indirect(conn[i], conn[i+1]); -#else - for (i = 0; i < num; i+=4) { - setup_remote_row_indirect(conn[i], conn[i+1],conn[i+2], conn[i+3]); -#endif - } -} - -#endif /*CONFIG_MAX_PHYSICAL_CPUS > 2*/ - - -static void setup_uniprocessor(void) -{ - printk(BIOS_SPEW, "Enabling UP settings\n"); -#if IS_ENABLED(CONFIG_LOGICAL_CPUS) - unsigned tmp = (pci_read_config32(NODE_MC(0), 0xe8) >> 12) & 3; - if (tmp > 0) return; -#endif - disable_probes(); -} - -#if CONFIG_MAX_PHYSICAL_CPUS > 2 -static int optimize_connection_group(const u8 *opt_conn, int num) -{ - int needs_reset = 0; - int i; - for (i = 0; i < num; i+=2) { - needs_reset = optimize_connection( - NODE_HT(opt_conn[i]), 0x80 + link_to_register(link_connection(opt_conn[i],opt_conn[i+1])), - NODE_HT(opt_conn[i+1]), 0x80 + link_to_register(link_connection(opt_conn[i+1],opt_conn[i]))); - } - return needs_reset; -} -#endif - -#if CONFIG_MAX_PHYSICAL_CPUS > 1 -static unsigned setup_smp2(void) -{ - unsigned nodes; - u8 byte; - uint32_t val; - nodes = 2; - - setup_row_local(0, 0); /* it will update the broadcast RT*/ - - val = get_row(0,0); - byte = (val>>16) & 0xfe; - if (byte < 0x2) { /* no coherent connection so get out.*/ - nodes = 1; - return nodes; - } - - /* Setup and check a temporary connection to node 1 */ -#if TRY_HIGH_FIRST == 1 - byte = get_linkn_last(byte); /* Max Link to node1 */ -#else - byte = get_linkn_first(byte); /*Min Link to node1 --- according to AMD*/ -#endif - print_linkn("(0,1) link=", byte); - setup_row_direct(0,1, byte); - setup_temp_row(0, 1); - - verify_connection(7); - - /* We found 2 nodes so far */ - val = pci_read_config32(NODE_HT(7), 0x6c); - byte = (val>>2) & 0x3; /*get default link on node7 to node0*/ - print_linkn("(1,0) link=", byte); - setup_row_local(7,1); - setup_remote_row_direct(1, 0, byte); - -#if (CONFIG_MAX_PHYSICAL_CPUS > 4) || CONFIG_MAX_PHYSICAL_CPUS_4_BUT_MORE_INSTALLED - val = get_row(7,1); - byte = (val>>16) & 0xfe; - byte = get_linkn_last_count(byte); - if ((byte>>2) == 3) { /* Oh! we need to treat it as node2. So use another link*/ - val = get_row(0,0); - byte = (val>>16) & 0xfe; -#if TRY_HIGH_FIRST == 1 - byte = get_linkn_first(byte); /* Min link to Node1 */ -#else - byte = get_linkn_last(byte); /* Max link to Node1*/ -#endif - print_linkn("\t-->(0,1) link=", byte); - setup_row_direct(0,1, byte); - setup_temp_row(0, 1); - - verify_connection(7); - - /* We found 2 nodes so far */ - val = pci_read_config32(NODE_HT(7), 0x6c); - byte = (val>>2) & 0x3; /* get default link on node7 to node0*/ - print_linkn("\t-->(1,0) link=", byte); - setup_row_local(7,1); - setup_remote_row_direct(1, 0, byte); - } -#endif - - setup_remote_node(1); /* Setup the regs on the remote node */ - rename_temp_node(1); /* Rename Node 7 to Node 1 */ - enable_routing(1); /* Enable routing on Node 1 */ - - return nodes; -} -#endif /*CONFIG_MAX_PHYSICAL_CPUS > 1 */ - -#if CONFIG_MAX_PHYSICAL_CPUS > 2 - -static unsigned setup_smp4(void) -{ - unsigned nodes; - u8 byte; - uint32_t val; - - nodes = 4; - - /* Setup and check temporary connection from Node 0 to Node 2 */ - val = get_row(0,0); - byte = ((val>>16) & 0xfe) - link_connection(0,1); - byte = get_linkn_last_count(byte); - - if ((byte>>2) == 0) { /* We should have two coherent for 4p and above*/ - nodes = 2; - return nodes; - } - - byte &= 3; /* bit [3,2] is count-1*/ - print_linkn("(0,2) link=", byte); - setup_row_direct(0, 2, byte); /*(0,2) direct link done*/ - - /* We found 3 nodes so far. Now setup a temporary - * connection from node 0 to node 3 via node 1 - */ - setup_temp_row(0,1); /* temp. link between nodes 0 and 1 */ - /* here should setup_row_direct(1,3) at first, before that we should find the link in node 1 to 3*/ - val = get_row(1,1); - byte = ((val>>16) & 0xfe) - link_connection(1,0); - byte = get_linkn_first(byte); - print_linkn("(1,3) link=", byte); - setup_row_direct(1,3,byte); /* (1, 3) direct link done*/ - - /* We found 4 nodes so far. Now setup all nodes for 4p */ - // We need to make sure 0,2 and 1,3 link is set already -#if !CROSS_BAR_47_56 - static const u8 conn4_1[] = { - 0,3, - 1,2, - }; -#else - static const u8 conn4_1[] = { - 0,3,2,1, - 1,2,3,1, - }; -#endif - - setup_row_indirect_group(conn4_1, ARRAY_SIZE(conn4_1)); - - setup_temp_row(0,2); - verify_connection(7); - val = pci_read_config32(NODE_HT(7), 0x6c); - byte = (val>>2) & 0x3; /* get default link on 7 to 0*/ - print_linkn("(2,0) link=", byte); - - setup_row_local(7,2); - setup_remote_row_direct(2, 0, byte); /* node 2 to node 0 direct link done */ - setup_remote_node(2); /* Setup the regs on the remote node */ - - rename_temp_node(2); /* Rename Node 7 to Node 2 */ - enable_routing(2); /* Enable routing on Node 2 */ - - setup_temp_row(0,1); - setup_temp_row(1,3); - verify_connection(7); - - val = pci_read_config32(NODE_HT(7), 0x6c); - byte = (val>>2) & 0x3; /* get default link on 7 to 1*/ - print_linkn("(3,1) link=", byte); - - setup_row_local(7,3); - setup_remote_row_direct(3, 1, byte); /* node 3 to node 1 direct link done */ - setup_remote_node(3); /* Setup the regs on the remote node */ - - /* We need to init link between 2, and 3 direct link */ - val = get_row(2,2); - byte = ((val>>16) & 0xfe) - link_connection(2,0); - byte = get_linkn_last_count(byte); - print_linkn("(2,3) link=", byte & 3); - - setup_row_direct(2,3, byte & 0x3); - setup_temp_row(0,2); - setup_temp_row(2,3); - verify_connection(7); /* to 3*/ - -#if (CONFIG_MAX_PHYSICAL_CPUS > 4) || CONFIG_MAX_PHYSICAL_CPUS_4_BUT_MORE_INSTALLED - /* We need to find out which link is to node3 */ - if ((byte>>2) == 2) { /* one to node3, one to node0, one to node4*/ - val = get_row(7,3); - if ((val>>16) == 1) { /* that link is to node4, because via node1 it has been set, recompute it*/ - val = get_row(2,2); - byte = ((val>>16) & 0xfe) - link_connection(2,0); - byte = get_linkn_first(byte); - print_linkn("\t-->(2,3) link=", byte); - setup_row_direct(2,3,byte); - setup_temp_row(2,3); - verify_connection(7); /* to 3*/ - } - } -#endif - - val = pci_read_config32(NODE_HT(7), 0x6c); - byte = (val>>2) & 0x3; /* get default link on 7 to 2*/ - print_linkn("(3,2) link=", byte); - setup_remote_row_direct(3,2, byte); - -#if (CONFIG_MAX_PHYSICAL_CPUS > 4) || CONFIG_MAX_PHYSICAL_CPUS_4_BUT_MORE_INSTALLED - /* set link from 3 to 5 before enable it*/ - val = get_row(7,3); - byte = ((val>>16) & 0xfe) - link_connection(7,2) - link_connection(7,1); - byte = get_linkn_last_count(byte); - if ((byte>>2) == 1) { /* We should have three coherent links on node 3 for 6p and above*/ - byte &= 3; /*bit [3,2] is count-2*/ - print_linkn("(3,5) link=", byte); - setup_remote_row_direct(3, 5, byte); - } - - val = get_row(2,2); - byte = ((val>>16) & 0xfe) - link_connection(2,3) - link_connection(2,0); - byte = get_linkn_last_count(byte); - - if ((byte>>2) == 1) { /* We should have three coherent link on node 2 for 6p and above*/ - byte &= 3; /* bit [3,2] is count-2*/ - print_linkn("(2,4) link=", byte); - setup_row_direct(2, 4, byte); - } -#endif - - //Beside 3, 1 is set, We need to make sure 3, 5 is set already in case has three link in 3 -#if !CROSS_BAR_47_56 - static const u8 conn4_3[] = { - 3,0, - }; -#else - static const u8 conn4_3[] = { - 3,0,1,1, - }; -#endif - setup_remote_row_indirect_group(conn4_3, ARRAY_SIZE(conn4_3)); - -/* ready to enable RT for Node 3 */ - rename_temp_node(3); - enable_routing(3); /* enable routing on node 3 (temp.) */ - - // beside 2, 0 is set, We need to make sure 2, 4 link is set already in case has three link in 2 -#if !CROSS_BAR_47_56 - static const u8 conn4_2[] = { - 2,1, - }; -#else - static const u8 conn4_2[] = { - 2,1,0,1, - }; -#endif - setup_row_indirect_group(conn4_2, ARRAY_SIZE(conn4_2)); - - return nodes; - -} - -#endif /* CONFIG_MAX_PHYSICAL_CPUS > 2 */ - -#if CONFIG_MAX_PHYSICAL_CPUS > 4 - -static unsigned setup_smp6(void) -{ - unsigned nodes; - u8 byte; - uint32_t val; - - nodes = 6; - - /* Setup and check temporary connection from Node 0 to Node 4 through 2*/ - val = get_row(2,2); - byte = ((val>>16) & 0xfe) - link_connection(2,3) - link_connection(2,0); - byte = get_linkn_last_count(byte); - - if ((byte>>2) == 0) { /* We should have three coherent link on node 2 for 6p and above*/ - nodes = 4; - return nodes; - } - - /* Setup and check temporary connection from Node 0 to Node 5 through 1, 3*/ - /* set link from 3 to 5 before enable it*/ - val = get_row(3,3); - byte = ((val>>16) & 0xfe) - link_connection(3,2) - link_connection(3,1); - byte = get_linkn_last_count(byte); - if ((byte>>2) == 0) { /* We should have three coherent links on node 3 for 6p and above*/ - nodes = 4; - return nodes; - } - - /* We found 6 nodes so far. Now setup all nodes for 6p */ -#warning "FIXME we need to find out the correct gateway for 6p" - static const u8 conn6_1[] = { -#if !CROSS_BAR_47_56 - 0, 4, - 0, 5, - 1, 4, - 1, 5, - 2, 5, - 3, 4, -#else - 0, 4, 2, 0, - 0, 5, 2, 1, - 1, 4, 3, 1, - 1, 5, 3, 0, - 2, 5, 3, 0, - 3, 4, 2, 0, -#endif - }; - - setup_row_indirect_group(conn6_1, ARRAY_SIZE(conn6_1)); - - for (byte = 0; byte < 4; byte+=2) { - setup_temp_row(byte,byte+2); - } - verify_connection(7); - val = pci_read_config32(NODE_HT(7), 0x6c); - byte = (val>>2) & 0x3; /*get default link on 7 to 2*/ - print_linkn("(4,2) link=", byte); - - setup_row_local(7,4); - setup_remote_row_direct(4, 2, byte); - setup_remote_node(4); /* Setup the regs on the remote node */ - - /* Set indirect connection to 0, to 3 */ - //we only need to set 4,0 here - static const u8 conn6_2[] = { -#if !CROSS_BAR_47_56 - 4, 0, -#else - 4, 0, 2, 0, -#endif - }; - - setup_remote_row_indirect_group(conn6_2, ARRAY_SIZE(conn6_2)); - - rename_temp_node(4); - enable_routing(4); - - setup_temp_row(0,1); - for (byte = 0; byte < 4; byte+=2) { - setup_temp_row(byte+1,byte+3); - } - verify_connection(7); - - val = pci_read_config32(NODE_HT(7), 0x6c); - byte = (val>>2) & 0x3; /* get default link on 7 to 3*/ - print_linkn("(5,3) link=", byte); - setup_row_local(7,5); - setup_remote_row_direct(5, 3, byte); - setup_remote_node(5); /* Setup the regs on the remote node */ - -#if !CROSS_BAR_47_56 - /* We need to init link between 4, and 5 direct link */ - val = get_row(4,4); - byte = ((val>>16) & 0xfe) - link_connection(4,2); - byte = get_linkn_last_count(byte); - print_linkn("(4,5) link=", byte & 3); - - setup_row_direct(4,5, byte & 0x3); - setup_temp_row(0,2); - setup_temp_row(2,4); - setup_temp_row(4,5); - verify_connection(7); /* to 5*/ - -#if CONFIG_MAX_PHYSICAL_CPUS > 6 - /* We need to find out which link is to node5 */ - - if ((byte>>2) == 2) { /* one to node5, one to node2, one to node6*/ - val = get_row(7,5); - if ((val>>16) == 1) { /* that link is to node6, because via node 3 node 5 has been set*/ - val = get_row(4,4); - byte = ((val>>16) & 0xfe) - link_connection(4,2); - byte = get_linkn_first(byte); - print_linkn("\t-->(4,5) link=", byte); - setup_row_direct(4,5,byte); - setup_temp_row(4,5); - verify_connection(7); /* to 5*/ - } - } -#endif - - val = pci_read_config32(NODE_HT(7), 0x6c); - byte = (val>>2) & 0x3; /* get default link on 7 to 4*/ - print_linkn("(5,4) link=", byte); - setup_remote_row_direct(5,4, byte); - - //init 5, 7 here - val = get_row(7,5); - byte = ((val>>16) & 0xfe) - link_connection(7,4) - link_connection(7,3); - byte = get_linkn_last_count(byte); - if ((byte>>2) == 1) { /* We should have three coherent links on node 5 for 6p and above*/ - byte &= 3; /*bit [3,2] is count-2*/ - print_linkn("(5,7) link=", byte); - setup_remote_row_direct(5, 7, byte); - } - - //init 4,6 here - val = get_row(4,4); - byte = ((val>>16) & 0xfe) - link_connection(4,5) - link_connection(4,2); - byte = get_linkn_last_count(byte); - - if ((byte>>2) == 1) { /* We should have three coherent link on node 4 for 6p and above*/ - byte &= 3; /* bit [3,2] is count-2*/ - print_linkn("(4,6) link=", byte); - setup_row_direct(4, 6, byte); - } - -#endif - - //We need to set 5,0 here only, We need to set up 5, 7 to make 5,0 - /* Set indirect connection to 0, to 3 for indirect we will use clockwise routing */ - static const u8 conn6_3[] = { -#if !CROSS_BAR_47_56 - 5, 0, -#else - 5, 0, 3, 0, -#endif - }; - - setup_remote_row_indirect_group(conn6_3, ARRAY_SIZE(conn6_3)); - -/* ready to enable RT for 5 */ - rename_temp_node(5); - enable_routing(5); /* enable routing on node 5 (temp.) */ - - static const u8 conn6_4[] = { -#if !CROSS_BAR_47_56 - 4, 1, - 4, 3, - - 5, 2, - 5, 1, - -#else - 4, 1, 2, 0, - 4, 3, 2, 0, - 4, 5, 2, 0, - - 5, 2, 3, 0, - 5, 1, 3, 0, - 5, 4, 3, 0, - -#endif - }; - - setup_row_indirect_group(conn6_4, ARRAY_SIZE(conn6_4)); - - return nodes; - -} - -#endif /* CONFIG_MAX_PHYSICAL_CPUS > 4 */ - -#if CONFIG_MAX_PHYSICAL_CPUS > 6 - -static unsigned setup_smp8(void) -{ - unsigned nodes; - u8 byte; - uint32_t val; - - nodes = 8; - - /* Setup and check temporary connection from Node 0 to Node 6 via 2 and 4 to 7 */ - val = get_row(4,4); -#if CROSS_BAR_47_56 - byte = ((val>>16) & 0xfe) - link_connection(4,2); -#else - byte = ((val>>16) & 0xfe) - link_connection(4,5) - link_connection(4,2); - byte = get_linkn_last_count(byte); /* Max link to 6*/ - if ((byte>>2) == 0) { /* We should have two or three coherent links on node 4 for 8p*/ - nodes = 6; - return nodes; - } -#endif - -#if CROSS_BAR_47_56 - byte = get_linkn_last_count(byte); /* Max link to 6*/ - if ((byte>>2)<2) { /* We should have two or three coherent links on node 4 for 8p*/ - nodes = 6; - return nodes; - } -#if TRY_HIGH_FIRST == 1 - byte = ((val>>16) & 0xfe) - link_connection(4,2); - byte = get_linkn_first(byte); /*Min link to 6*/ -#else - byte &= 3; /* bit [3,2] is count-1 or 2*/ -#endif - print_linkn("(4,6) link=", byte); - setup_row_direct(4, 6, byte); -#endif - -#if !CROSS_BAR_47_56 - /* Setup and check temporary connection from Node 0 to Node 7 through 1, 3, 5*/ - val = get_row(5,5); - byte = ((val>>16) & 0xfe) - link_connection(5,4) - link_connection(5,3); - byte = get_linkn_last_count(byte); - if ((byte>>2) == 0) { /* We should have three coherent links on node 5 for 6p and above*/ - nodes = 6; - return nodes; - } -#endif - - /* We found 8 nodes so far. Now setup all nodes for 8p */ - static const u8 conn8_1[] = { -#if !CROSS_BAR_47_56 - 0, 6, - /*0, 7,*/ - 1, 6, - /*1, 7,*/ - 2, 6, - /*2, 7,*/ - 3, 6, - /*3, 7,*/ - /*4, 7,*/ - 5, 6, -#else - 0, 6, 2, 0, - /*0, 7, 2, 0,*/ - 1, 6, 3, 0, - /*1, 7, 3, 0,*/ - 2, 6, 4, 0, - /*2, 7, 4, 0,*/ - 3, 6, 5, 1, - /*3, 7, 5, 0,*/ -#endif - }; - - setup_row_indirect_group(conn8_1,ARRAY_SIZE(conn8_1)); - - for (byte = 0; byte < 6; byte+=2) { - setup_temp_row(byte,byte+2); - } - verify_connection(7); - val = pci_read_config32(NODE_HT(7), 0x6c); - byte = (val>>2) & 0x3; /* get default link on 7 to 4*/ - print_linkn("(6,4) link=", byte); - - setup_row_local(7,6); - setup_remote_row_direct(6, 4, byte); - setup_remote_node(6); /* Setup the regs on the remote node */ - /* Set indirect connection to 0, to 3 */ -#warning "FIXME we need to find out the correct gateway for 8p" - static const u8 conn8_2[] = { -#if !CROSS_BAR_47_56 - 6, 0, -#else - 6, 0, 4, 0, -#endif - }; - - setup_remote_row_indirect_group(conn8_2, ARRAY_SIZE(conn8_2)); - -#if CROSS_BAR_47_56 - //init 5, 6 here - /* here init 5, 6 */ - /* Setup and check temporary connection from Node 0 to Node 5 through 1, 3, 5*/ - val = get_row(5,5); - byte = ((val>>16) & 0xfe) - link_connection(5,3); -#if TRY_HIGH_FIRST == 1 - byte = get_linkn_first(byte); -#else - byte = get_linkn_last(byte); -#endif - print_linkn("(5,6) link=", byte); - setup_row_direct(5, 6, byte); - - setup_temp_row(0,1); /* temp. link between nodes 0 and 1 */ - for (byte = 0; byte < 4; byte+=2) { - setup_temp_row(byte+1,byte+3); - } - setup_temp_row(5,6); - - verify_connection(7); - - val = get_row(7,6); // to chect it if it is node6 before renaming - if ((val>>16) == 1) { // it is real node 7 so swap it - /* We need to recompute link to 6 */ - val = get_row(5,5); - byte = ((val>>16) & 0xfe) - link_connection(5,3); -#if TRY_HIGH_FIRST == 1 - byte = get_linkn_first(byte); -#else - byte = get_linkn_last(byte); -#endif - print_linkn("\t-->(5,6) link=", byte); - setup_row_direct(5, 6, byte); - setup_temp_row(5,6); - - verify_connection(7); - } - val = pci_read_config32(NODE_HT(7), 0x6c); - byte = (val>>2) & 0x3; /* get default link on 7 to 5*/ - print_linkn("(6,5) link=", byte); - setup_remote_row_direct(6, 5, byte); - /*Till now 56, 65 done */ -#endif - - rename_temp_node(6); - enable_routing(6); - -#if !CROSS_BAR_47_56 - setup_temp_row(0,1); - for (byte = 0; byte < 6; byte+=2) { - setup_temp_row(byte+1,byte+3); - } - - verify_connection(7); - - val = pci_read_config32(NODE_HT(7), 0x6c); - byte = (val>>2) & 0x3; /* get default link on 7 to 5*/ - print_linkn("(7,5) link=", byte); - setup_row_local(7,7); - setup_remote_row_direct(7, 5, byte); - -#else - val = get_row(4,4); - byte = ((val>>16) & 0xfe) - link_connection(4,2) - link_connection(4,6); - byte = get_linkn_first(byte); - print_linkn("(4,7) link=", byte); - setup_row_direct(4, 7, byte); - - /* Setup and check temporary connection from Node 0 to Node 7 through 2, and 4*/ - for (byte = 0; byte < 4; byte+=2) { - setup_temp_row(byte,byte+2); - } - - verify_connection(7); - - val = pci_read_config32(NODE_HT(7), 0x6c); - byte = (val>>2) & 0x3; /* get default link on 7 to 4*/ - print_linkn("(7,4) link=", byte); - setup_row_local(7,7); - setup_remote_row_direct(7, 4, byte); - /* till now 4-7, 7-4 done. */ -#endif - setup_remote_node(7); /* Setup the regs on the remote node */ - -#if CROSS_BAR_47_56 - /* here init 5, 7 */ - /* Setup and check temporary connection from Node 0 to Node 5 through 1, 3, 5*/ - val = get_row(5,5); - byte = ((val>>16) & 0xfe) - link_connection(5,3) - link_connection(5,6); - byte = get_linkn_first(byte); - print_linkn("(5,7) link=", byte); - setup_row_direct(5, 7, byte); - - setup_temp_row(0,1); /* temp. link between nodes 0 and 1 */ - for (byte = 0; byte < 4; byte+=2) { - setup_temp_row(byte+1,byte+3); - } - - verify_connection(7); - - val = pci_read_config32(NODE_HT(7), 0x6c); - byte = (val>>2) & 0x3; /* get default link on 7 to 5*/ - print_linkn("(7,5) link=", byte); - setup_remote_row_direct(7, 5, byte); - /*Till now 57, 75 done */ - -#endif - - /* We need to init link between 6, and 7 direct link */ - val = get_row(6,6); -#if !CROSS_BAR_47_56 - byte = ((val>>16) & 0xfe) - link_connection(6,4); -#else - byte = ((val>>16) & 0xfe) - link_connection(6,4) - link_connection(6,5); -#endif - byte = get_linkn_first(byte); - print_linkn("(6,7) link=", byte); - setup_row_direct(6,7, byte); - - val = get_row(7,7); -#if !CROSS_BAR_47_56 - byte = ((val>>16) & 0xfe) - link_connection(7,5); -#else - byte = ((val>>16) & 0xfe) - link_connection(7,5) - link_connection(7,4); -#endif - byte = get_linkn_first(byte); - print_linkn("(7,6) link=", byte); - setup_row_direct(7,6, byte); - - /* Set indirect connection to 0, to 3 for indirect we will use clockwise routing */ - static const u8 conn8_3[] = { -#if !CROSS_BAR_47_56 - 0, 7, /* restore it*/ - 1, 7, - 2, 7, - 3, 7, - 4, 7, - - 6, 1, - 6, 2, - 6, 3, - 6, 5, - - 7, 0, - 7, 1, - 7, 2, - 7, 3, - 7, 4, -#else - - - 4, 5, 6, 1, - 5, 4, 7, 1, - - 6, 1, 5, 0, // or 4, 1 - 6, 2, 4, 0, - 6, 3, 5, 0, // or 4, 1 - - 7, 0, 4, 0, // or 5, 1 - 7, 1, 5, 0, - 7, 2, 4, 0, // or 5, 1 - 7, 3, 5, 0, - - 0, 7, 2, 0, /* restore it*/ - 1, 7, 3, 0, - 2, 7, 4, 1, - 3, 7, 5, 0, - - 2, 5, 4, 1, /* reset it */ - 3, 4, 5, 1, - - 4, 1, 2, 1, /* reset it */ - 4, 3, 2, 1, - - 5, 2, 3, 1, /* reset it */ - 5, 0, 3, 1, - -#endif - }; - - setup_row_indirect_group(conn8_3, ARRAY_SIZE(conn8_3)); - -#if CROSS_BAR_47_56 - /* for 47, 56, 57, 75, 46, 64 we need to substract another link to - 6, 7, 6, 6, 7, 7 */ - static const u8 conn8_4[] = { -//direct - 4, 7, 6, - 5, 6, 7, - 5, 7, 6, - 7, 5, 6, - 4, 6, 7, - 6, 4, 7, - -//in direct - 0, 6, 1, - 0, 7, 1, - - 1, 6, 0, - 1, 7, 0, - - 2, 6, 3, -// 2, 7, 3, + - -// 3, 6, 1, + - 3, 7, 2, - - 6, 0, 7, - 6, 1, 7, // needed for via 5 - 6, 1, 4, // ??? - 6, 2, 7, - 6, 3, 7, // needed for via 5 - 6, 3, 4, //??? - 7, 0, 6, // needed for via 4 - 7, 0, 5, //??? - 7, 1, 6, - 7, 2, 6, // needed for via 4 - 7, 2, 5, //??? - 7, 3, 6, - }; - - opt_broadcast_rt_group(conn8_4, ARRAY_SIZE(conn8_4)); - - static const u8 conn8_5[] = { - 2, 7, 0, - - 3, 6, 1, - }; - - opt_broadcast_rt_plus_group(conn8_5, ARRAY_SIZE(conn8_5)); -#endif - - - -/* ready to enable RT for Node 7 */ - enable_routing(7); /* enable routing on node 7 (temp.) */ - - return nodes; -} - -#endif /* CONFIG_MAX_PHYSICAL_CPUS > 6 */ - - -#if CONFIG_MAX_PHYSICAL_CPUS > 1 - -static unsigned setup_smp(void) -{ - unsigned nodes; - - printk(BIOS_SPEW, "Enabling SMP settings\n"); - - nodes = setup_smp2(); -#if CONFIG_MAX_PHYSICAL_CPUS > 2 - if (nodes == 2) - nodes = setup_smp4(); -#endif - -#if CONFIG_MAX_PHYSICAL_CPUS > 4 - if (nodes == 4) - nodes = setup_smp6(); -#endif - -#if CONFIG_MAX_PHYSICAL_CPUS > 6 - if (nodes == 6) - nodes = setup_smp8(); -#endif - - printk(BIOS_DEBUG, "%02x nodes initialized.\n", nodes); - - return nodes; -} - -static unsigned verify_mp_capabilities(unsigned nodes) -{ - unsigned node, mask; - - mask = 0x06; /* BigMPCap */ - - for (node = 0; node < nodes; node++) { - mask &= pci_read_config32(NODE_MC(node), 0xe8); - } - - switch(mask) { -#if CONFIG_MAX_PHYSICAL_CPUS > 2 - case 0x02: /* MPCap */ - if (nodes > 2) { - printk(BIOS_ERR, "Going back to DP\n"); - return 2; - } - break; -#endif - case 0x00: /* Non SMP */ - if (nodes >1) { - printk(BIOS_ERR, "Going back to UP\n"); - return 1; - } - break; - } - - return nodes; - -} - - -static void clear_dead_routes(unsigned nodes) -{ - int last_row; - int node, row; -#if CONFIG_MAX_PHYSICAL_CPUS == 8 - if (nodes == 8) return;/* don't touch (7,7)*/ -#endif - last_row = nodes; - if (nodes == 1) { - last_row = 0; - } - for (node = 7; node >= 0; node--) { - for (row = 7; row >= last_row; row--) { - fill_row(node, row, DEFAULT); - } - } - - /* Update the local row */ - for (node = 0; node < nodes; node++) { - uint32_t val = 0; - for (row =0; row < nodes; row++) { - val |= get_row(node, row); - } - fill_row(node, node, (((val & 0xff) | ((val >> 8) & 0xff)) << 16) | 0x0101); - } -} -#endif /* CONFIG_MAX_PHYSICAL_CPUS > 1 */ - -#if IS_ENABLED(CONFIG_LOGICAL_CPUS) -static unsigned verify_dualcore(unsigned nodes) -{ - unsigned node, totalcpus, tmp; - - totalcpus = 0; - for (node = 0; node < nodes; node++) { - tmp = (pci_read_config32(NODE_MC(node), 0xe8) >> 12) & 3; - totalcpus += (tmp + 1); - } - - return totalcpus; - -} -#endif - -static void coherent_ht_finalize(unsigned nodes) -{ - unsigned node; -#if !IS_ENABLED(CONFIG_K8_REV_F_SUPPORT) - int rev_a0; -#endif -#if IS_ENABLED(CONFIG_LOGICAL_CPUS) - unsigned total_cpus; - - if (read_option(multi_core, 0) == 0) { /* multi_core */ - total_cpus = verify_dualcore(nodes); - } - else { - total_cpus = nodes; - } -#endif - - /* set up CPU count and node count and enable Limit - * Config Space Range for all available CPUs. - * Also clear non coherent hypertransport bus range - * registers on Hammer A0 revision. - */ - - printk(BIOS_SPEW, "coherent_ht_finalize\n"); -#if !IS_ENABLED(CONFIG_K8_REV_F_SUPPORT) - rev_a0 = is_cpu_rev_a0(); -#endif - for (node = 0; node < nodes; node++) { - pci_devfn_t dev; - uint32_t val; - dev = NODE_HT(node); - - /* Set the Total CPU and Node count in the system */ - val = pci_read_config32(dev, 0x60); - val &= (~0x000F0070); -#if IS_ENABLED(CONFIG_LOGICAL_CPUS) - val |= ((total_cpus-1)<<16)|((nodes-1)<<4); -#else - val |= ((nodes-1)<<16)|((nodes-1)<<4); -#endif - pci_write_config32(dev, 0x60, val); - - /* Only respond to real CPU pci configuration cycles - * and optimize the HT settings - */ - val = pci_read_config32(dev, HT_TRANSACTION_CONTROL); - val &= ~((HTTC_BUF_REL_PRI_MASK << HTTC_BUF_REL_PRI_SHIFT) | - (HTTC_MED_PRI_BYP_CNT_MASK << HTTC_MED_PRI_BYP_CNT_SHIFT) | - (HTTC_HI_PRI_BYP_CNT_MASK << HTTC_HI_PRI_BYP_CNT_SHIFT)); - val |= HTTC_LIMIT_CLDT_CFG | - (HTTC_BUF_REL_PRI_8 << HTTC_BUF_REL_PRI_SHIFT) | - (3 << HTTC_MED_PRI_BYP_CNT_SHIFT) | - (3 << HTTC_HI_PRI_BYP_CNT_SHIFT); - pci_write_config32(dev, HT_TRANSACTION_CONTROL, val); - -#if !IS_ENABLED(CONFIG_K8_REV_F_SUPPORT) - if (rev_a0) { - pci_write_config32(dev, 0x94, 0); - pci_write_config32(dev, 0xb4, 0); - pci_write_config32(dev, 0xd4, 0); - } -#endif - } - - printk(BIOS_SPEW, "done\n"); -} - -static int apply_cpu_errata_fixes(unsigned nodes) -{ - unsigned node; - int needs_reset = 0; - for (node = 0; node < nodes; node++) { - pci_devfn_t dev; - uint32_t cmd; - dev = NODE_MC(node); -#if !IS_ENABLED(CONFIG_K8_REV_F_SUPPORT) - if (is_cpu_pre_c0()) { - - /* Errata 66 - * Limit the number of downstream posted requests to 1 - */ - cmd = pci_read_config32(dev, 0x70); - if ((cmd & (3 << 0)) != 2) { - cmd &= ~(3<<0); - cmd |= (2<<0); - pci_write_config32(dev, 0x70, cmd); - needs_reset = 1; - } - cmd = pci_read_config32(dev, 0x7c); - if ((cmd & (3 << 4)) != 0) { - cmd &= ~(3<<4); - cmd |= (0<<4); - pci_write_config32(dev, 0x7c, cmd); - needs_reset = 1; - } - /* Clock Power/Timing Low */ - cmd = pci_read_config32(dev, 0xd4); - if (cmd != 0x000D0001) { - cmd = 0x000D0001; - pci_write_config32(dev, 0xd4, cmd); - needs_reset = 1; /* Needed? */ - } - - } - else if (is_cpu_pre_d0()) { // d0 later don't need it - uint32_t cmd_ref; - /* Errata 98 - * Set Clk Ramp Hystersis to 7 - * Clock Power/Timing Low - */ - cmd_ref = 0x04e20707; /* Registered */ - cmd = pci_read_config32(dev, 0xd4); - if (cmd != cmd_ref) { - pci_write_config32(dev, 0xd4, cmd_ref); - needs_reset = 1; /* Needed? */ - } - } -#endif - - -#if !IS_ENABLED(CONFIG_K8_REV_F_SUPPORT) - /* I can't touch this msr on early buggy cpus, and cannot apply either 169 or 131 */ - if (!is_cpu_pre_b3()) -#endif - { - /* Errata 169 */ - /* We also need to set some bits in NB_CFG_MSR, which is handled in src/cpu/amd/model_fxx/ */ - dev = NODE_HT(node); - cmd = pci_read_config32(dev, 0x68); - cmd &= ~(1 << 22); - cmd |= (1 << 21); - pci_write_config32(dev, 0x68, cmd); - } - } - return needs_reset; -} - -static int optimize_link_read_pointers(unsigned nodes) -{ - unsigned node; - int needs_reset = 0; - for (node = 0; node < nodes; node++) { - pci_devfn_t f0_dev, f3_dev; - uint32_t cmd_ref, cmd; - int link; - f0_dev = NODE_HT(node); - f3_dev = NODE_MC(node); - cmd_ref = cmd = pci_read_config32(f3_dev, 0xdc); - for (link = 0; link < 3; link++) { - uint32_t link_type; - unsigned reg; - /* This works on an Athlon64 because unimplemented links return 0 */ - reg = 0x98 + (link * 0x20); - link_type = pci_read_config32(f0_dev, reg); - /* Only handle coherent links */ - if ((link_type & (LinkConnected | InitComplete|NonCoherent)) == - (LinkConnected|InitComplete)) - { - cmd &= ~(0xff << (link *8)); - cmd |= 0x25 << (link *8); - } - } - if (cmd != cmd_ref) { - pci_write_config32(f3_dev, 0xdc, cmd); - needs_reset = 1; - } - } - return needs_reset; -} - -unsigned int get_nodes(void) -{ - return ((pci_read_config32(PCI_DEV(0, 0x18, 0), 0x60)>>4) & 7) + 1; -} - -int optimize_link_coherent_ht(void) -{ - int needs_reset = 0; - - unsigned nodes; - - nodes = get_nodes(); - -#if CONFIG_MAX_PHYSICAL_CPUS > 1 - if (nodes > 1) { - needs_reset |= optimize_connection( - NODE_HT(0), 0x80 + link_to_register(link_connection(0,1)), - NODE_HT(1), 0x80 + link_to_register(link_connection(1,0))); - } - -#if CONFIG_MAX_PHYSICAL_CPUS > 2 - if (nodes > 2) { - /* optimize physical connections - by LYH */ - static const u8 opt_conn4[] = { - 0,2, - 1,3, - 2,3, - }; - needs_reset |= optimize_connection_group(opt_conn4, ARRAY_SIZE(opt_conn4)); - } -#endif - -#if CONFIG_MAX_PHYSICAL_CPUS > 4 - if (nodes > 4) { - static const uint8_t opt_conn6[] ={ - 2, 4, - 3, 5, - #if !CROSS_BAR_47_56 - 4, 5, - #endif - }; - needs_reset |= optimize_connection_group(opt_conn6, ARRAY_SIZE(opt_conn6)); - } -#endif - -#if CONFIG_MAX_PHYSICAL_CPUS > 6 - if (nodes > 6) { - static const uint8_t opt_conn8[] ={ - 4, 6, - #if CROSS_BAR_47_56 - 4, 7, - 5, 6, - #endif - 5, 7, - 6, 7, - }; - needs_reset |= optimize_connection_group(opt_conn8, ARRAY_SIZE(opt_conn8)); - } -#endif - -#endif - - needs_reset |= apply_cpu_errata_fixes(nodes); - needs_reset |= optimize_link_read_pointers(nodes); - - return needs_reset; -} - -#if IS_ENABLED(CONFIG_RAMINIT_SYSINFO) -void setup_coherent_ht_domain(void) -#else -int setup_coherent_ht_domain(void) -#endif -{ - unsigned nodes; - nodes = 1; - - enable_bsp_routing(); - -#if CONFIG_MAX_PHYSICAL_CPUS > 1 - nodes = setup_smp(); - nodes = verify_mp_capabilities(nodes); - clear_dead_routes(nodes); -#endif - - if (nodes == 1) { - setup_uniprocessor(); - } - coherent_ht_finalize(nodes); - -#if !IS_ENABLED(CONFIG_RAMINIT_SYSINFO) - return optimize_link_coherent_ht(); -#endif -} diff --git a/src/northbridge/amd/amdk8/debug.c b/src/northbridge/amd/amdk8/debug.c deleted file mode 100644 index 6480db48ed..0000000000 --- a/src/northbridge/amd/amdk8/debug.c +++ /dev/null @@ -1,259 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * 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. - */ - -/* - * generic K8 debug code, used by mainboard specific romstage.c - * - */ - -#include "debug.h" -#include <console/console.h> -#include <arch/io.h> -#include <device/pci_def.h> -#include <delay.h> -#include "raminit.h" - -void print_debug_addr(const char *str, void *val) -{ -#if IS_ENABLED(CONFIG_DEBUG_CAR) - printk(BIOS_DEBUG, "------Address debug: %s%p------\n", str, val); -#endif -} - -#if 1 -void print_debug_pci_dev(unsigned dev) -{ - printk(BIOS_DEBUG, "PCI: %02x:%02x.%02x", (dev>>20) & 0xff, (dev>>15) & 0x1f, (dev>>12) & 0x7); -} - -void print_pci_devices(void) -{ - pci_devfn_t dev; - for (dev = PCI_DEV(0, 0, 0); - dev <= PCI_DEV(0xff, 0x1f, 0x7); - dev += PCI_DEV(0,0,1)) { - uint32_t id; - id = pci_read_config32(dev, PCI_VENDOR_ID); - if (((id & 0xffff) == 0x0000) || ((id & 0xffff) == 0xffff) || - (((id >> 16) & 0xffff) == 0xffff) || - (((id >> 16) & 0xffff) == 0x0000)) { - continue; - } - print_debug_pci_dev(dev); - printk(BIOS_DEBUG, " %04x:%04x\n", (id & 0xffff), (id>>16)); - if (((dev>>12) & 0x07) == 0) { - uint8_t hdr_type; - hdr_type = pci_read_config8(dev, PCI_HEADER_TYPE); - if ((hdr_type & 0x80) != 0x80) { - dev += PCI_DEV(0,0,7); - } - } - } -} - -void dump_pci_device(unsigned dev) -{ - int i; - print_debug_pci_dev(dev); - - for (i = 0; i < 256; i++) { - unsigned char val; - if ((i & 0x0f) == 0) { - printk(BIOS_DEBUG, "\n%02x:",i); - } - val = pci_read_config8(dev, i); - printk(BIOS_DEBUG, " %02x", val); - } - printk(BIOS_DEBUG, "\n"); -} - -#if IS_ENABLED(CONFIG_K8_REV_F_SUPPORT) -void dump_pci_device_index_wait(unsigned dev, uint32_t index_reg) -{ - int i; - print_debug_pci_dev(dev); - printk(BIOS_DEBUG, " -- index_reg=%08x", index_reg); - - for (i = 0; i < 0x40; i++) { - uint32_t val; - int j; - printk(BIOS_DEBUG, "\n%02x:",i); - val = pci_read_config32_index_wait(dev, index_reg, i); - for (j = 0; j < 4; j++) { - printk(BIOS_DEBUG, " %02x", val & 0xff); - val >>= 8; - } - - } - printk(BIOS_DEBUG, "\n"); -} -#endif - -void dump_pci_devices(void) -{ - pci_devfn_t dev; - for (dev = PCI_DEV(0, 0, 0); - dev <= PCI_DEV(0xff, 0x1f, 0x7); - dev += PCI_DEV(0,0,1)) { - uint32_t id; - id = pci_read_config32(dev, PCI_VENDOR_ID); - if (((id & 0xffff) == 0x0000) || ((id & 0xffff) == 0xffff) || - (((id >> 16) & 0xffff) == 0xffff) || - (((id >> 16) & 0xffff) == 0x0000)) { - continue; - } - dump_pci_device(dev); - - if (((dev>>12) & 0x07) == 0) { - uint8_t hdr_type; - hdr_type = pci_read_config8(dev, PCI_HEADER_TYPE); - if ((hdr_type & 0x80) != 0x80) { - dev += PCI_DEV(0,0,7); - } - } - } -} - -void dump_pci_devices_on_bus(unsigned busn) -{ - pci_devfn_t dev; - for (dev = PCI_DEV(busn, 0, 0); - dev <= PCI_DEV(busn, 0x1f, 0x7); - dev += PCI_DEV(0,0,1)) { - uint32_t id; - id = pci_read_config32(dev, PCI_VENDOR_ID); - if (((id & 0xffff) == 0x0000) || ((id & 0xffff) == 0xffff) || - (((id >> 16) & 0xffff) == 0xffff) || - (((id >> 16) & 0xffff) == 0x0000)) { - continue; - } - dump_pci_device(dev); - - if (((dev>>12) & 0x07) == 0) { - uint8_t hdr_type; - hdr_type = pci_read_config8(dev, PCI_HEADER_TYPE); - if ((hdr_type & 0x80) != 0x80) { - dev += PCI_DEV(0,0,7); - } - } - } -} - -#if IS_ENABLED(CONFIG_DEBUG_SMBUS) - -void dump_spd_registers(const struct mem_controller *ctrl) -{ - int i; - printk(BIOS_DEBUG, "\n"); - for (i = 0; i < 4; i++) { - unsigned device; - device = ctrl->channel0[i]; - if (device) { - int j; - printk(BIOS_DEBUG, "dimm: %02x.0: %02x", i, device); - for (j = 0; j < 128; j++) { - int status; - unsigned char byte; - if ((j & 0xf) == 0) { - printk(BIOS_DEBUG, "\n%02x: ", j); - } - status = spd_read_byte(device, j); - if (status < 0) { - break; - } - byte = status & 0xff; - printk(BIOS_DEBUG, "%02x ", byte); - } - printk(BIOS_DEBUG, "\n"); - } - device = ctrl->channel1[i]; - if (device) { - int j; - printk(BIOS_DEBUG, "dimm: %02x.1: %02x", i, device); - for (j = 0; j < 128; j++) { - int status; - unsigned char byte; - if ((j & 0xf) == 0) { - printk(BIOS_DEBUG, "\n%02x: ", j); - } - status = spd_read_byte(device, j); - if (status < 0) { - break; - } - byte = status & 0xff; - printk(BIOS_DEBUG, "%02x ", byte); - } - printk(BIOS_DEBUG, "\n"); - } - } -} -void dump_smbus_registers(void) -{ - unsigned device; - printk(BIOS_DEBUG, "\n"); - for (device = 1; device < 0x80; device++) { - int j; - if (spd_read_byte(device, 0) < 0) - continue; - printk(BIOS_DEBUG, "smbus: %02x", device); - for (j = 0; j < 256; j++) { - int status; - unsigned char byte; - status = spd_read_byte(device, j); - if (status < 0) { - break; - } - if ((j & 0xf) == 0) { - printk(BIOS_DEBUG, "\n%02x: ",j); - } - byte = status & 0xff; - printk(BIOS_DEBUG, "%02x ", byte); - } - printk(BIOS_DEBUG, "\n"); - } -} -#endif - -void dump_io_resources(unsigned port) -{ - - int i; - udelay(2000); - printk(BIOS_DEBUG, "%04x:\n", port); - for (i = 0; i < 256; i++) { - uint8_t val; - if ((i & 0x0f) == 0) { - printk(BIOS_DEBUG, "%02x:", i); - } - val = inb(port); - printk(BIOS_DEBUG, " %02x",val); - if ((i & 0x0f) == 0x0f) { - printk(BIOS_DEBUG, "\n"); - } - port++; - } -} - -void dump_mem(unsigned start, unsigned end) -{ - unsigned i; - printk(BIOS_DEBUG, "dump_mem:"); - for (i = start; i < end; i++) { - if ((i & 0xf) == 0) { - printk(BIOS_DEBUG, "\n%08x:", i); - } - printk(BIOS_DEBUG, " %02x", (unsigned char)*((unsigned char *)i)); - } - printk(BIOS_DEBUG, "\n"); - } -#endif diff --git a/src/northbridge/amd/amdk8/debug.h b/src/northbridge/amd/amdk8/debug.h deleted file mode 100644 index 06ed51923b..0000000000 --- a/src/northbridge/amd/amdk8/debug.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * 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. - */ - -#ifndef AMDK8_DEBUG_H -#define AMDK8_DEBUG_H - -#include <inttypes.h> -#include <arch/io.h> - -void print_debug_addr(const char *str, void *val); -void print_debug_pci_dev(unsigned int dev); -void print_pci_devices(void); -void dump_pci_device(unsigned int dev); -void dump_pci_device_index_wait(unsigned int dev, uint32_t index_reg); -uint32_t pci_read_config32_index_wait(pci_devfn_t dev, - uint32_t index_reg, uint32_t index); -void dump_pci_devices(void); -void dump_pci_devices_on_bus(unsigned int busn); -void dump_io_resources(unsigned int port); -void dump_mem(unsigned start, unsigned end); - -#endif diff --git a/src/northbridge/amd/amdk8/early_ht.c b/src/northbridge/amd/amdk8/early_ht.c deleted file mode 100644 index 0683579656..0000000000 --- a/src/northbridge/amd/amdk8/early_ht.c +++ /dev/null @@ -1,154 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * 2005.11 yhlu add let the real sb to use small unitid - * - * 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. - */ - -// only for sb ht chain -static void enumerate_ht_chain(void) -{ -#if CONFIG_HT_CHAIN_UNITID_BASE != 0 -/* CONFIG_HT_CHAIN_UNITID_BASE could be 0 (only one ht device in the ht chain), if so, don't need to go through the chain */ - - /* Assumption the HT chain that is bus 0 has the HT I/O Hub on it. - * On most boards this just happens. If a CPU has multiple - * non Coherent links the appropriate bus registers for the - * links needs to be programed to point at bus 0. - */ - unsigned next_unitid, last_unitid; - pci_devfn_t dev; -#if CONFIG_HT_CHAIN_END_UNITID_BASE != 0x20 - //let't record the device of last ht device, So we can set the Unitid to CONFIG_HT_CHAIN_END_UNITID_BASE - unsigned real_last_unitid = 0; - uint8_t real_last_pos = 0; - int ht_dev_num = 0; // except host_bridge - uint8_t end_used = 0; -#endif - - dev = PCI_DEV(0,0,0); - next_unitid = CONFIG_HT_CHAIN_UNITID_BASE; - do { - uint32_t id; - uint8_t hdr_type, pos; - last_unitid = next_unitid; - - id = pci_read_config32(dev, PCI_VENDOR_ID); - /* If the chain is enumerated quit */ - if (((id & 0xffff) == 0x0000) || ((id & 0xffff) == 0xffff) || - (((id >> 16) & 0xffff) == 0xffff) || - (((id >> 16) & 0xffff) == 0x0000)) - { - break; - } - - hdr_type = pci_read_config8(dev, PCI_HEADER_TYPE); - pos = 0; - hdr_type &= 0x7f; - - if ((hdr_type == PCI_HEADER_TYPE_NORMAL) || - (hdr_type == PCI_HEADER_TYPE_BRIDGE)) - { - pos = pci_read_config8(dev, PCI_CAPABILITY_LIST); - } - while (pos != 0) { - uint8_t cap; - cap = pci_read_config8(dev, pos + PCI_CAP_LIST_ID); - if (cap == PCI_CAP_ID_HT) { - uint16_t flags; - /* Read and write and reread flags so the link - * direction bit is valid. - */ - flags = pci_read_config16(dev, pos + PCI_CAP_FLAGS); - pci_write_config16(dev, pos + PCI_CAP_FLAGS, flags); - flags = pci_read_config16(dev, pos + PCI_CAP_FLAGS); - if ((flags >> 13) == 0) { - unsigned count; - unsigned ctrl, ctrl_off; - pci_devfn_t devx; - -#if CONFIG_HT_CHAIN_END_UNITID_BASE != 0x20 - if (next_unitid >= 0x18) { // don't get mask out by k8, at this time BSP, RT is not enabled, it will response from 0x18,0--0x1f. - if (!end_used) { - next_unitid = CONFIG_HT_CHAIN_END_UNITID_BASE; - end_used = 1; - } else { - goto out; - } - } - real_last_unitid = next_unitid; - real_last_pos = pos; - ht_dev_num++; -#endif - - flags &= ~0x1f; - flags |= next_unitid & 0x1f; - count = (flags >> 5) & 0x1f; - - devx = PCI_DEV(0, next_unitid, 0); - pci_write_config16(dev, pos + PCI_CAP_FLAGS, flags); - - next_unitid += count; - - flags = pci_read_config16(devx, pos + PCI_CAP_FLAGS); - /* Test for end of chain */ - ctrl_off = ((flags >> 10) & 1)? - PCI_HT_CAP_SLAVE_CTRL0 : PCI_HT_CAP_SLAVE_CTRL1; // another end - - do { - ctrl = pci_read_config16(devx, pos + ctrl_off); - /* Is this the end of the hypertransport chain? */ - if (ctrl & (1 << 6)) { - goto out; - } - - if (ctrl & ((1 << 4) | (1 << 8))) { - /* - * Either the link has failed, or we have - * a CRC error. - * Sometimes this can happen due to link - * retrain, so lets knock it down and see - * if its transient - */ - ctrl |= ((1 << 4) | (1 <<8)); // Link fail + Crc - pci_write_config16(devx, pos + ctrl_off, ctrl); - ctrl = pci_read_config16(devx, pos + ctrl_off); - if (ctrl & ((1 << 4) | (1 << 8))) { - // can not clear the error - break; - } - } - } while ((ctrl & (1 << 5)) == 0); - - break; - } - } - pos = pci_read_config8(dev, pos + PCI_CAP_LIST_NEXT); - } - } while (last_unitid != next_unitid); - -out: - ; - -#if CONFIG_HT_CHAIN_END_UNITID_BASE != 0x20 - if ((ht_dev_num > 1) && (real_last_unitid != CONFIG_HT_CHAIN_END_UNITID_BASE) && !end_used) { - uint16_t flags; - dev = PCI_DEV(0,real_last_unitid, 0); - flags = pci_read_config16(dev, real_last_pos + PCI_CAP_FLAGS); - flags &= ~0x1f; - flags |= CONFIG_HT_CHAIN_END_UNITID_BASE & 0x1f; - pci_write_config16(dev, real_last_pos + PCI_CAP_FLAGS, flags); - } -#endif - -#endif - -} diff --git a/src/northbridge/amd/amdk8/exit_from_self.c b/src/northbridge/amd/amdk8/exit_from_self.c deleted file mode 100644 index 4b6f4e2a57..0000000000 --- a/src/northbridge/amd/amdk8/exit_from_self.c +++ /dev/null @@ -1,193 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2009 Rudolf Marek <r.marek@assembler.cz> - * - * 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. - */ - -#include <arch/io.h> -#include <console/console.h> -#include <cpu/x86/lapic.h> -#include <delay.h> -#include <cpu/amd/mtrr.h> -#include "raminit.h" -#include "f.h" - -void exit_from_self(int controllers, const struct mem_controller *ctrl, - struct sys_info *sysinfo) -{ - int i; - u32 dcl, dch; - u32 pcidev; - u8 bitmask; - u8 is_post_rev_g; - u32 local_cpuid; - - for (i = 0; i < controllers; i++) { - if (!sysinfo->ctrl_present[i]) - continue; - /* Skip everything if I don't have any memory on this controller */ - dch = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_HIGH); - if (!(dch & DCH_MemClkFreqVal)) { - continue; - } - - local_cpuid = pci_read_config32(ctrl[i].f3, 0xfc); - is_post_rev_g = ((local_cpuid & 0xfff00) > 0x50f00); - - /* ChipKill */ - dcl = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_LOW); - if (dcl & DCL_DimmEccEn) { - u32 mnc; - printk(BIOS_SPEW, "ECC enabled\n"); - mnc = pci_read_config32(ctrl[i].f3, MCA_NB_CONFIG); - mnc |= MNC_ECC_EN; - if (dcl & DCL_Width128) { - mnc |= MNC_CHIPKILL_EN; - } - pci_write_config32(ctrl[i].f3, MCA_NB_CONFIG, mnc); - } - - printk(BIOS_DEBUG, "before resume errata #%d\n", - (is_post_rev_g) ? 270 : 125); - /* - 1. Restore memory controller registers as normal. - 2. Set the DisAutoRefresh bit (Dev:2x8C[18]). (270 only) - 3. Set the EnDramInit bit (Dev:2x7C[31]), clear all other bits in the same register). - 4. Wait at least 750 us. - 5. Clear the EnDramInit bit. - 6. Clear the DisAutoRefresh bit. (270 only) - 7. Read the value of Dev:2x80 and write that value back to Dev:2x80. - 8. Set the exit from the self refresh bit (Dev:2x90[1]). - 9. Clear the exit from self refresh bit immediately. - Note: Steps 8 and 9 must be executed in a single 64-byte aligned uninterrupted instruction stream. - */ - - enable_lapic(); - init_timer(); - - printk(BIOS_DEBUG, "before exit errata - timer enabled\n"); - - if (is_post_rev_g) { - dcl = - pci_read_config32(ctrl[i].f2, - DRAM_TIMING_HIGH); - dcl |= (1 << 18); - pci_write_config32(ctrl[i].f2, DRAM_TIMING_HIGH, - dcl); - } - - dcl = DI_EnDramInit; - pci_write_config32(ctrl[i].f2, DRAM_INIT, dcl); - - udelay(800); - - printk(BIOS_DEBUG, "before exit errata - after mdelay\n"); - - dcl = pci_read_config32(ctrl[i].f2, DRAM_INIT); - dcl &= ~DI_EnDramInit; - pci_write_config32(ctrl[i].f2, DRAM_INIT, dcl); - - if (is_post_rev_g) { - dcl = - pci_read_config32(ctrl[i].f2, - DRAM_TIMING_HIGH); - dcl &= ~(1 << 18); - pci_write_config32(ctrl[i].f2, DRAM_TIMING_HIGH, - dcl); - } - - dcl = pci_read_config32(ctrl[i].f2, DRAM_BANK_ADDR_MAP); - pci_write_config32(ctrl[i].f2, DRAM_BANK_ADDR_MAP, dcl); - - /* I was unable to do that like: ctrl[i].f2->path.pci.devfn << 8 */ - pcidev = - 0x80000000 | ((((ctrl[i].node_id + 0x18) << 3) | 0x2) - << 8) | 0x90; - printk(BIOS_DEBUG, "pcidev is %x\n", pcidev); - bitmask = 2; - __asm__ __volatile__("pushl %0\n\t" - "movw $0xcf8, %%dx\n\t" - "out %%eax, (%%dx)\n\t" - "movw $0xcfc, %%dx\n\t" - "inl %%dx, %%eax\n\t" - "orb %1, %%al\n\t" - "not %1\n\t" - ".align 64\n\t" - "outl %%eax, (%%dx)\n\t" - "andb %1, %%al\n\t" - "outl %%eax, (%%dx)\n\t" - "popl %0\n\t"::"a"(pcidev), - "q"(bitmask):"edx"); - } - - printk(BIOS_DEBUG, "after exit errata\n"); - - - for (i = 0; i < controllers; i++) { - u32 dcm; - if (!sysinfo->ctrl_present[i]) - continue; - /* Skip everything if I don't have any memory on this controller */ - if (sysinfo->meminfo[i].dimm_mask == 0x00) - continue; - - printk(BIOS_DEBUG, "Exiting memory from self refresh: "); - int loops = 0; - do { - loops++; - if ((loops & 1023) == 0) { - printk(BIOS_DEBUG, "."); - } - dcm = - pci_read_config32(ctrl[i].f2, DRAM_CTRL_MISC); - } while (((dcm & DCM_MemClrStatus) == - 0) /* || ((dcm & DCM_DramEnabled) == 0) */); - - if (loops >= TIMEOUT_LOOPS) { - printk(BIOS_DEBUG, "timeout with with cntrl[%d]\n", i); - continue; - } - - printk(BIOS_DEBUG, " done\n"); - } - -#if CONFIG_HW_MEM_HOLE_SIZEK != 0 - /* init hw mem hole here */ - /* DramHoleValid bit only can be set after MemClrStatus is set by Hardware */ - set_hw_mem_hole(controllers, ctrl); -#endif - - /* store tom to sysinfo, and it will be used by dqs_timing */ - { - msr_t msr; - //[1M, TOM) - msr = rdmsr(TOP_MEM); - sysinfo->tom_k = ((msr.hi << 24) | (msr.lo >> 8)) >> 2; - - //[4G, TOM2) - msr = rdmsr(TOP_MEM2); - sysinfo->tom2_k = ((msr.hi << 24) | (msr.lo >> 8)) >> 2; - } - - for (i = 0; i < controllers; i++) { - - if (!sysinfo->ctrl_present[i]) - continue; - - /* Skip everything if I don't have any memory on this controller */ - if (sysinfo->meminfo[i].dimm_mask == 0x00) - continue; - - dqs_restore_MC_NVRAM((ctrl + i)->f2); - sysinfo->mem_trained[i] = 1; // mem was trained - } -} diff --git a/src/northbridge/amd/amdk8/f.h b/src/northbridge/amd/amdk8/f.h deleted file mode 100644 index ec70cb0167..0000000000 --- a/src/northbridge/amd/amdk8/f.h +++ /dev/null @@ -1,606 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * 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. - */ - -#ifndef AMDK8_F_H -#define AMDK8_F_H - -#include <compiler.h> - -/* Definitions of various K8 registers */ -/* Function 0 */ -#define HT_TRANSACTION_CONTROL 0x68 -#define HTTC_DIS_RD_B_P (1 << 0) -#define HTTC_DIS_RD_DW_P (1 << 1) -#define HTTC_DIS_WR_B_P (1 << 2) -#define HTTC_DIS_WR_DW_P (1 << 3) -#define HTTC_DIS_MTS (1 << 4) -#define HTTC_CPU1_EN (1 << 5) -#define HTTC_CPU_REQ_PASS_PW (1 << 6) -#define HTTC_CPU_RD_RSP_PASS_PW (1 << 7) -#define HTTC_DIS_P_MEM_C (1 << 8) -#define HTTC_DIS_RMT_MEM_C (1 << 9) -#define HTTC_DIS_FILL_P (1 << 10) -#define HTTC_RSP_PASS_PW (1 << 11) -#define HTTC_CHG_ISOC_TO_ORD (1 << 12) -#define HTTC_BUF_REL_PRI_SHIFT 13 -#define HTTC_BUF_REL_PRI_MASK 3 -#define HTTC_BUF_REL_PRI_64 0 -#define HTTC_BUF_REL_PRI_16 1 -#define HTTC_BUF_REL_PRI_8 2 -#define HTTC_BUF_REL_PRI_2 3 -#define HTTC_LIMIT_CLDT_CFG (1 << 15) -#define HTTC_LINT_EN (1 << 16) -#define HTTC_APIC_EXT_BRD_CST (1 << 17) -#define HTTC_APIC_EXT_ID (1 << 18) -#define HTTC_APIC_EXT_SPUR (1 << 19) -#define HTTC_SEQ_ID_SRC_NODE_EN (1 << 20) -#define HTTC_DS_NP_REQ_LIMIT_SHIFT 21 -#define HTTC_DS_NP_REQ_LIMIT_MASK 3 -#define HTTC_DS_NP_REQ_LIMIT_NONE 0 -#define HTTC_DS_NP_REQ_LIMIT_1 1 -#define HTTC_DS_NP_REQ_LIMIT_4 2 -#define HTTC_DS_NP_REQ_LIMIT_8 3 -#define HTTC_MED_PRI_BYP_CNT_SHIFT 24 -#define HTTC_MED_PRI_BYP_CNT_MASK 3 -#define HTTC_HI_PRI_BYP_CNT_SHIFT 26 -#define HTTC_HI_PRI_BYP_CNT_MASK 3 - - -/* Function 1 */ -#define PCI_IO_BASE0 0xc0 -#define PCI_IO_BASE1 0xc8 -#define PCI_IO_BASE2 0xd0 -#define PCI_IO_BASE3 0xd8 -#define PCI_IO_BASE_VGA_EN (1 << 4) -#define PCI_IO_BASE_NO_ISA (1 << 5) - - -/* Function 2 */ -#define DRAM_CSBASE 0x40 -#define DRAM_CSMASK 0x60 -#define DRAM_BANK_ADDR_MAP 0x80 - -#define DRAM_CTRL 0x78 -#define DC_RdPtrInit_SHIFT 0 -#define DC_RdPrtInit_MASK 0xf -#define DC_RdPadRcvFifoDly_SHIFT 4 -#define DC_RdPadRcvFifoDly_MASK 7 -#define DC_RdPadRcvFiloDly_1_5_CLK 2 -#define DC_RdPadRcvFiloDly_2_CLK 3 -#define DC_RdPadRcvFiloDly_2_5_CLK 4 -#define DC_RdPadRcvFiloDly_3_CLK 5 -#define DC_RdPadRcvFiloDly_3_5_CLK 6 -#define DC_AltVidC3MemClkTriEn (1<<16) -#define DC_DllTempAdjTime_SHIFT 17 -#define DC_DllTempAdjTime_MASK 1 -#define DC_DllTempAdjTime_5_MS 0 -#define DC_DllTempAdjTime_1_MS 1 -#define DC_DqsRcvEnTrain (1<<18) - -#define DRAM_INIT 0x7c -#define DI_MrsAddress_SHIFT 0 -#define DI_MrsAddress_MASK 0xffff -#define DI_MrsBank_SHIFT 16 -#define DI_MrsBank_MASK 7 -#define DI_SendRchgAll (1<<24) -#define DI_SendAutoRefresh (1<<25) -#define DI_SendMrsCmd (1<<26) -#define DI_DeassertMemRstX (1<<27) -#define DI_AssertCke (1<<28) -#define DI_EnDramInit (1<<31) - -#define DRAM_TIMING_LOW 0x88 -#define DTL_TCL_SHIFT 0 -#define DTL_TCL_MASK 7 -#define DTL_TCL_BASE 1 -#define DTL_TCL_MIN 3 -#define DTL_TCL_MAX 6 -#define DTL_TRCD_SHIFT 4 -#define DTL_TRCD_MASK 3 -#define DTL_TRCD_BASE 3 -#define DTL_TRCD_MIN 3 -#define DTL_TRCD_MAX 6 -#define DTL_TRP_SHIFT 8 -#define DTL_TRP_MASK 3 -#define DTL_TRP_BASE 3 -#define DTL_TRP_MIN 3 -#define DTL_TRP_MAX 6 -#define DTL_TRTP_SHIFT 11 -#define DTL_TRTP_MASK 1 -#define DTL_TRTP_BASE 2 -#define DTL_TRTP_MIN 2 /* 4 for 64 bytes*/ -#define DTL_TRTP_MAX 3 /* 5 for 64 bytes */ -#define DTL_TRAS_SHIFT 12 -#define DTL_TRAS_MASK 0xf -#define DTL_TRAS_BASE 3 -#define DTL_TRAS_MIN 5 -#define DTL_TRAS_MAX 18 -#define DTL_TRC_SHIFT 16 -#define DTL_TRC_MASK 0xf -#define DTL_TRC_BASE 11 -#define DTL_TRC_MIN 11 -#define DTL_TRC_MAX 26 -#define DTL_TWR_SHIFT 20 -#define DTL_TWR_MASK 3 -#define DTL_TWR_BASE 3 -#define DTL_TWR_MIN 3 -#define DTL_TWR_MAX 6 -#define DTL_TRRD_SHIFT 22 -#define DTL_TRRD_MASK 3 -#define DTL_TRRD_BASE 2 -#define DTL_TRRD_MIN 2 -#define DTL_TRRD_MAX 5 -#define DTL_MemClkDis_SHIFT 24 /* Channel A */ -#define DTL_MemClkDis3 (1 << 26) -#define DTL_MemClkDis2 (1 << 27) -#define DTL_MemClkDis1 (1 << 28) -#define DTL_MemClkDis0 (1 << 29) -#define DTL_MemClkDis1_AM2 (0x51 << 24) -#define DTL_MemClkDis0_AM2 (0xa2 << 24) -#define DTL_MemClkDis0_S1g1 (0xa2 << 24) - -/* DTL_MemClkDis for m2 and s1g1 is different */ - -#define DRAM_TIMING_HIGH 0x8c -#define DTH_TRWTTO_SHIFT 4 -#define DTH_TRWTTO_MASK 7 -#define DTH_TRWTTO_BASE 2 -#define DTH_TRWTTO_MIN 2 -#define DTH_TRWTTO_MAX 9 -#define DTH_TWTR_SHIFT 8 -#define DTH_TWTR_MASK 3 -#define DTH_TWTR_BASE 0 -#define DTH_TWTR_MIN 1 -#define DTH_TWTR_MAX 3 -#define DTH_TWRRD_SHIFT 10 -#define DTH_TWRRD_MASK 3 -#define DTH_TWRRD_BASE 0 -#define DTH_TWRRD_MIN 0 -#define DTH_TWRRD_MAX 3 -#define DTH_TWRWR_SHIFT 12 -#define DTH_TWRWR_MASK 3 -#define DTH_TWRWR_BASE 1 -#define DTH_TWRWR_MIN 1 -#define DTH_TWRWR_MAX 3 -#define DTH_TRDRD_SHIFT 14 -#define DTH_TRDRD_MASK 3 -#define DTH_TRDRD_BASE 2 -#define DTH_TRDRD_MIN 2 -#define DTH_TRDRD_MAX 5 -#define DTH_TREF_SHIFT 16 -#define DTH_TREF_MASK 3 -#define DTH_TREF_7_8_US 2 -#define DTH_TREF_3_9_US 3 -#define DTH_TRFC0_SHIFT 20 /* for Logical DIMM0 */ -#define DTH_TRFC_MASK 7 -#define DTH_TRFC_75_256M 0 -#define DTH_TRFC_105_512M 1 -#define DTH_TRFC_127_5_1G 2 -#define DTH_TRFC_195_2G 3 -#define DTH_TRFC_327_5_4G 4 -#define DTH_TRFC1_SHIFT 23 /*for Logical DIMM1 */ -#define DTH_TRFC2_SHIFT 26 /*for Logical DIMM2 */ -#define DTH_TRFC3_SHIFT 29 /*for Logical DIMM3 */ - -#define DRAM_CONFIG_LOW 0x90 -#define DCL_InitDram (1<<0) -#define DCL_ExitSelfRef (1<<1) -#define DCL_DramTerm_SHIFT 4 -#define DCL_DramTerm_MASK 3 -#define DCL_DramTerm_No 0 -#define DCL_DramTerm_75_OH 1 -#define DCL_DramTerm_150_OH 2 -#define DCL_DramTerm_50_OH 3 -#define DCL_DrvWeak (1<<7) -#define DCL_ParEn (1<<8) -#define DCL_SelfRefRateEn (1<<9) -#define DCL_BurstLength32 (1<<10) -#define DCL_Width128 (1<<11) -#define DCL_X4Dimm_SHIFT 12 -#define DCL_X4Dimm_MASK 0xf -#define DCL_UnBuffDimm (1<<16) -#define DCL_DimmEccEn (1<<19) - -#define DRAM_CONFIG_HIGH 0x94 -#define DCH_MemClkFreq_SHIFT 0 -#define DCH_MemClkFreq_MASK 7 -#define DCH_MemClkFreq_200MHz 0 -#define DCH_MemClkFreq_266MHz 1 -#define DCH_MemClkFreq_333MHz 2 -#define DCH_MemClkFreq_400MHz 3 -#define DCH_MemClkFreqVal (1<<3) -#define DCH_MaxAsyncLat_SHIFT 4 -#define DCH_MaxAsyncLat_MASK 0xf -#define DCH_MaxAsyncLat_BASE 0 -#define DCH_MaxAsyncLat_MIN 0 -#define DCH_MaxAsyncLat_MAX 15 -#define DCH_RDqsEn (1<<12) -#define DCH_DisDramInterface (1<<14) -#define DCH_PowerDownEn (1<<15) -#define DCH_PowerDownMode_SHIFT 16 -#define DCH_PowerDownMode_MASK 1 -#define DCH_PowerDownMode_Channel_CKE 0 -#define DCH_PowerDownMode_ChipSelect_CKE 1 -#define DCH_FourRankSODimm (1<<17) -#define DCH_FourRankRDimm (1<<18) -#define DCH_SlowAccessMode (1<<19) -#define DCH_BankSwizzleMode (1<<22) -#define DCH_DcqBypassMax_SHIFT 24 -#define DCH_DcqBypassMax_MASK 0xf -#define DCH_DcqBypassMax_BASE 0 -#define DCH_DcqBypassMax_MIN 0 -#define DCH_DcqBypassMax_MAX 15 -#define DCH_FourActWindow_SHIFT 28 -#define DCH_FourActWindow_MASK 0xf -#define DCH_FourActWindow_BASE 7 -#define DCH_FourActWindow_MIN 8 -#define DCH_FourActWindow_MAX 20 - - -// for 0x98 index and 0x9c data -#define DRAM_CTRL_ADDI_DATA_OFFSET 0x98 -#define DCAO_DctOffset_SHIFT 0 -#define DCAO_DctOffset_MASK 0x3fffffff -#define DCAO_DctAccessWrite (1<<30) -#define DCAO_DctAccessDone (1<<31) - -#define DRAM_CTRL_ADDI_DATA_PORT 0x9c - -#define DRAM_OUTPUT_DRV_COMP_CTRL 0x00 -#define DODCC_CkeDrvStren_SHIFT 0 -#define DODCC_CkeDrvStren_MASK 3 -#define DODCC_CkeDrvStren_1_0X 0 -#define DODCC_CkeDrvStren_1_25X 1 -#define DODCC_CkeDrvStren_1_5X 2 -#define DODCC_CkeDrvStren_2_0X 3 -#define DODCC_CsOdtDrvStren_SHIFT 4 -#define DODCC_CsOdtDrvStren_MASK 3 -#define DODCC_CsOdtDrvStren_1_0X 0 -#define DODCC_CsOdtDrvStren_1_25X 1 -#define DODCC_CsOdtDrvStren_1_5X 2 -#define DODCC_CsOdtDrvStren_2_0X 3 -#define DODCC_AddrCmdDrvStren_SHIFT 8 -#define DODCC_AddrCmdDrvStren_MASK 3 -#define DODCC_AddrCmdDrvStren_1_0X 0 -#define DODCC_AddrCmdDrvStren_1_25X 1 -#define DODCC_AddrCmdDrvStren_1_5X 2 -#define DODCC_AddrCmdDrvStren_2_0X 3 -#define DODCC_ClkDrvStren_SHIFT 12 -#define DODCC_ClkDrvStren_MASK 3 -#define DODCC_ClkDrvStren_0_75X 0 -#define DODCC_ClkDrvStren_1_0X 1 -#define DODCC_ClkDrvStren_1_25X 2 -#define DODCC_ClkDrvStren_1_5X 3 -#define DODCC_DataDrvStren_SHIFT 16 -#define DODCC_DataDrvStren_MASK 3 -#define DODCC_DataDrvStren_0_75X 0 -#define DODCC_DataDrvStren_1_0X 1 -#define DODCC_DataDrvStren_1_25X 2 -#define DODCC_DataDrvStren_1_5X 3 -#define DODCC_DqsDrvStren_SHIFT 20 -#define DODCC_DqsDrvStren_MASK 3 -#define DODCC_DqsDrvStren_0_75X 0 -#define DODCC_DqsDrvStren_1_0X 1 -#define DODCC_DqsDrvStren_1_25X 2 -#define DODCC_DqsDrvStren_1_5X 3 -#define DODCC_ProcOdt_SHIFT 28 -#define DODCC_ProcOdt_MASK 3 -#define DODCC_ProcOdt_300_OHMS 0 -#define DODCC_ProcOdt_150_OHMS 1 -#define DODCC_ProcOdt_75_OHMS 2 - -#define DRAM_WRITE_DATA_TIMING_CTRL_LOW 0x01 -#define DWDTCL_WrDatTimeByte0_SHIFT 0 -#define DWDTC_WrDatTimeByte_MASK 0x3f -#define DWDTC_WrDatTimeByte_BASE 0 -#define DWDTC_WrDatTimeByte_MIN 0 -#define DWDTC_WrDatTimeByte_MAX 47 -#define DWDTCL_WrDatTimeByte1_SHIFT 8 -#define DWDTCL_WrDatTimeByte2_SHIFT 16 -#define DWDTCL_WrDatTimeByte3_SHIFT 24 - -#define DRAM_WRITE_DATA_TIMING_CTRL_HIGH 0x02 -#define DWDTCH_WrDatTimeByte4_SHIFT 0 -#define DWDTCH_WrDatTimeByte5_SHIFT 8 -#define DWDTCH_WrDatTimeByte6_SHIFT 16 -#define DWDTCH_WrDatTimeByte7_SHIFT 24 - -#define DRAM_WRITE_DATA_ECC_TIMING_CTRL 0x03 -#define DWDETC_WrChkTime_SHIFT 0 -#define DWDETC_WrChkTime_MASK 0x3f -#define DWDETC_WrChkTime_BASE 0 -#define DWDETC_WrChkTime_MIN 0 -#define DWDETC_WrChkTime_MAX 47 - -#define DRAM_ADDR_TIMING_CTRL 0x04 -#define DATC_CkeFineDelay_SHIFT 0 -#define DATC_CkeFineDelay_MASK 0x1f -#define DATC_CkeFineDelay_BASE 0 -#define DATC_CkeFineDelay_MIN 0 -#define DATC_CkeFineDelay_MAX 31 -#define DATC_CkeSetup (1<<5) -#define DATC_CsOdtFineDelay_SHIFT 8 -#define DATC_CsOdtFineDelay_MASK 0x1f -#define DATC_CsOdtFineDelay_BASE 0 -#define DATC_CsOdtFineDelay_MIN 0 -#define DATC_CsOdtFineDelay_MAX 31 -#define DATC_CsOdtSetup (1<<13) -#define DATC_AddrCmdFineDelay_SHIFT 16 -#define DATC_AddrCmdFineDelay_MASK 0x1f -#define DATC_AddrCmdFineDelay_BASE 0 -#define DATC_AddrCmdFineDelay_MIN 0 -#define DATC_AddrCmdFineDelay_MAX 31 -#define DATC_AddrCmdSetup (1<<21) - -#define DRAM_READ_DQS_TIMING_CTRL_LOW 0x05 -#define DRDTCL_RdDqsTimeByte0_SHIFT 0 -#define DRDTC_RdDqsTimeByte_MASK 0x3f -#define DRDTC_RdDqsTimeByte_BASE 0 -#define DRDTC_RdDqsTimeByte_MIN 0 -#define DRDTC_RdDqsTimeByte_MAX 47 -#define DRDTCL_RdDqsTimeByte1_SHIFT 8 -#define DRDTCL_RdDqsTimeByte2_SHIFT 16 -#define DRDTCL_RdDqsTimeByte3_SHIFT 24 - -#define DRAM_READ_DQS_TIMING_CTRL_HIGH 0x06 -#define DRDTCH_RdDqsTimeByte4_SHIFT 0 -#define DRDTCH_RdDqsTimeByte5_SHIFT 8 -#define DRDTCH_RdDqsTimeByte6_SHIFT 16 -#define DRDTCH_RdDqsTimeByte7_SHIFT 24 - -#define DRAM_READ_DQS_ECC_TIMING_CTRL 0x07 -#define DRDETC_RdDqsTimeCheck_SHIFT 0 -#define DRDETC_RdDqsTimeCheck_MASK 0x3f -#define DRDETC_RdDqsTimeCheck_BASE 0 -#define DRDETC_RdDqsTimeCheck_MIN 0 -#define DRDETC_RdDqsTimeCheck_MAX 47 - -#define DRAM_DQS_RECV_ENABLE_TIME0 0x10 -#define DDRET_DqsRcvEnDelay_SHIFT 0 -#define DDRET_DqsRcvEnDelay_MASK 0xff -#define DDRET_DqsRcvEnDelay_BASE 0 -#define DDRET_DqsRcvEnDelay_MIN 0 -#define DDRET_DqsRcvEnDelay_MAX 0xae /* unit is 50ps */ - -#define DRAM_DQS_RECV_ENABLE_TIME1 0x13 -#define DRAM_DQS_RECV_ENABLE_TIME2 0x16 -#define DRAM_DQS_RECV_ENABLE_TIME3 0x19 - -/* there are index 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x30, 0x33, 0x36, 0x39 -that are corresponding to 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x10, 0x13, 0x16, 0x19 -*/ -#define DRAM_CTRL_MISC 0xa0 -#define DCM_MemClrStatus (1<<0) -#define DCM_DisableJitter (1<<1) -#define DCM_RdWrQByp_SHIFT 2 -#define DCM_RdWrQByp_MASK 3 -#define DCM_RdWrQByp_2 0 -#define DCM_RdWrQByp_4 1 -#define DCM_RdWrQByp_8 2 -#define DCM_RdWrQByp_16 3 -#define DCM_Mode64BitMux (1<<4) -#define DCM_DCC_EN (1<<5) -#define DCM_ILD_lmt_SHIFT 6 -#define DCM_ILD_lmt_MASK 7 -#define DCM_ILD_lmt_0 0 -#define DCM_ILD_lmt_4 1 -#define DCM_ILD_lmt_8 2 -#define DCM_ILD_lmt_16 3 -#define DCM_ILD_lmt_32 4 -#define DCM_ILD_lmt_64 5 -#define DCM_ILD_lmt_128 6 -#define DCM_ILD_lmt_256 7 -#define DCM_DramEnabled (1<<9) -#define DCM_MemClkDis_SHIFT 24 /* Channel B */ -#define DCM_MemClkDis3 (1 << 26) -#define DCM_MemClkDis2 (1 << 27) -#define DCM_MemClkDis1 (1 << 28) -#define DCM_MemClkDis0 (1 << 29) - - -/* Function 3 */ -#define MCA_NB_CONFIG 0x44 -#define MNC_ECC_EN (1 << 22) -#define MNC_CHIPKILL_EN (1 << 23) - -#define SCRUB_CONTROL 0x58 -#define SCRUB_NONE 0 -#define SCRUB_40ns 1 -#define SCRUB_80ns 2 -#define SCRUB_160ns 3 -#define SCRUB_320ns 4 -#define SCRUB_640ns 5 -#define SCRUB_1_28us 6 -#define SCRUB_2_56us 7 -#define SCRUB_5_12us 8 -#define SCRUB_10_2us 9 -#define SCRUB_20_5us 10 -#define SCRUB_41_0us 11 -#define SCRUB_81_9us 12 -#define SCRUB_163_8us 13 -#define SCRUB_327_7us 14 -#define SCRUB_655_4us 15 -#define SCRUB_1_31ms 16 -#define SCRUB_2_62ms 17 -#define SCRUB_5_24ms 18 -#define SCRUB_10_49ms 19 -#define SCRUB_20_97ms 20 -#define SCRUB_42ms 21 -#define SCRUB_84ms 22 -#define SC_DRAM_SCRUB_RATE_SHFIT 0 -#define SC_DRAM_SCRUB_RATE_MASK 0x1f -#define SC_L2_SCRUB_RATE_SHIFT 8 -#define SC_L2_SCRUB_RATE_MASK 0x1f -#define SC_L1D_SCRUB_RATE_SHIFT 16 -#define SC_L1D_SCRUB_RATE_MASK 0x1f - -#define SCRUB_ADDR_LOW 0x5C - -#define SCRUB_ADDR_HIGH 0x60 - -#define NORTHBRIDGE_CAP 0xE8 -#define NBCAP_128Bit (1 << 0) -#define NBCAP_MP (1 << 1) -#define NBCAP_BIG_MP (1 << 2) -#define NBCAP_ECC (1 << 3) -#define NBCAP_CHIPKILL_ECC (1 << 4) -#define NBCAP_MEMCLK_SHIFT 5 -#define NBCAP_MEMCLK_MASK 3 -#define NBCAP_MEMCLK_200MHZ 3 -#define NBCAP_MEMCLK_266MHZ 2 -#define NBCAP_MEMCLK_333MHZ 1 -#define NBCAP_MEMCLK_NOLIMIT 0 -#define NBCAP_MEMCTRL (1 << 8) -#define NBCAP_HtcCap (1<<10) -#define NBCAP_CmpCap_SHIFT 12 -#define NBCAP_CmpCap_MASK 3 - - -#define LinkConnected (1 << 0) -#define InitComplete (1 << 1) -#define NonCoherent (1 << 2) -#define ConnectionPending (1 << 4) - -#include "raminit.h" -//struct definitions - -struct dimm_size { - uint8_t per_rank; // it is rows + col + bank_lines + data lines */ - uint8_t rows; - uint8_t col; - uint8_t bank; //1, 2, 3 mean 2, 4, 8 - uint8_t rank; -} __packed; - -struct mem_info { // pernode - uint32_t dimm_mask; - struct dimm_size sz[DIMM_SOCKETS]; - uint32_t x4_mask; - uint32_t x16_mask; - uint32_t single_rank_mask; - uint32_t page_1k_mask; -// uint32_t ecc_mask; -// uint32_t registered_mask; - uint8_t is_opteron; - uint8_t is_registered; - uint8_t is_ecc; - uint8_t is_Width128; - uint8_t is_64MuxMode; - uint8_t memclk_set; // we need to use this to retrieve the mem param - uint8_t rsv[2]; -} __packed; - -struct link_pair_st { - pci_devfn_t udev; - uint32_t upos; - uint32_t uoffs; - pci_devfn_t dev; - uint32_t pos; - uint32_t offs; - -} __packed; - -struct sys_info { - uint8_t ctrl_present[NODE_NUMS]; - struct mem_info meminfo[NODE_NUMS]; - struct mem_controller ctrl[NODE_NUMS]; - uint8_t mem_trained[NODE_NUMS]; //0: no dimm, 1: trained, 0x80: not started, 0x81: recv1 fail, 0x82: Pos Fail, 0x83:recv2 fail - uint32_t tom_k; - uint32_t tom2_k; - - uint32_t mem_base[NODE_NUMS]; - uint32_t cs_base[NODE_NUMS*8]; //8 cs_idx - uint32_t hole_reg[NODE_NUMS]; // can we spare it to one, and put ctrl idx in it - - uint8_t dqs_delay_a[NODE_NUMS*2*2*9]; //8 node channel 2, direction 2 , bytelane *9 - uint8_t dqs_rcvr_dly_a[NODE_NUMS*2*8]; //8 node, channel 2, receiver 8 - uint32_t nodes; - struct link_pair_st link_pair[16];// enough? only in_conherent - uint32_t link_pair_num; - uint32_t ht_c_num; - uint32_t sbdn; - uint32_t sblk; - uint32_t sbbusn; -} __packed; - -#ifdef __PRE_RAM__ -#include <arch/early_variables.h> -extern struct sys_info sysinfo_car; -#endif - -#include <reset.h> - -#if ((CONFIG_MEM_TRAIN_SEQ != 1) && defined(__PRE_RAM__)) || \ - ((CONFIG_MEM_TRAIN_SEQ == 1) && !defined(__PRE_RAM__)) -static inline void wait_all_core0_mem_trained(struct sys_info *sysinfo) -{ - - int i; - uint32_t mask = 0; - unsigned needs_reset = 0; - - - if (sysinfo->nodes == 1) return; // in case only one CPU installed - - for (i = 1; i < sysinfo->nodes; i++) { - /* Skip everything if I don't have any memory on this controller */ - if (sysinfo->mem_trained[i]== 0x00) continue; - - mask |= (1<<i); - - } - - i = 1; - while (1) { - if (mask & (1<<i)) { - if ((sysinfo->mem_trained[i])!=0x80) { - mask &= ~(1<<i); - } - } - - if (!mask) break; - - i++; - i%=sysinfo->nodes; - } - - for (i = 0; i < sysinfo->nodes; i++) { - printk(BIOS_DEBUG, "mem_trained[%02x]=%02x\n", i, sysinfo->mem_trained[i]); - switch(sysinfo->mem_trained[i]) { - case 0: //don't need train - case 1: //trained - break; - case 0x81: //recv1: fail - case 0x82: //Pos :fail - case 0x83: //recv2: fail - needs_reset = 1; - break; - } - } - if (needs_reset) { - printk(BIOS_DEBUG, "mem trained failed\n"); -#ifdef __PRE_RAM__ - soft_reset(); -#else - hard_reset(); -#endif - } - -} -#endif - -void dqs_restore_MC_NVRAM(unsigned int dev); -void train_ram_on_node(unsigned nodeid, unsigned coreid, - struct sys_info *sysinfo, unsigned retcall); - -#endif /* AMDK8_F_H */ diff --git a/src/northbridge/amd/amdk8/f_pci.c b/src/northbridge/amd/amdk8/f_pci.c deleted file mode 100644 index 9c259b008a..0000000000 --- a/src/northbridge/amd/amdk8/f_pci.c +++ /dev/null @@ -1,73 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * 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. - */ - -#ifndef AMDK8_F_PCI_C -#define AMDK8_F_PCI_C - -#include "debug.h" - -#ifdef UNUSED_CODE -/* bit [10,8] are dev func, bit[1,0] are dev index */ -static uint32_t pci_read_config32_index(pci_devfn_t dev, uint32_t index_reg, - uint32_t index) -{ - uint32_t dword; - - pci_write_config32(dev, index_reg, index); - - dword = pci_read_config32(dev, index_reg+0x4); - - return dword; -} - -static void pci_write_config32_index(pci_devfn_t dev, uint32_t index_reg, - uint32_t index, uint32_t data) -{ - pci_write_config32(dev, index_reg, index); - - pci_write_config32(dev, index_reg + 0x4, data); -} -#endif - -uint32_t pci_read_config32_index_wait(pci_devfn_t dev, - uint32_t index_reg, uint32_t index) -{ - uint32_t dword; - - index &= ~(1<<30); - pci_write_config32(dev, index_reg, index); - - do { - dword = pci_read_config32(dev, index_reg); - } while (!(dword & (1<<31))); - - dword = pci_read_config32(dev, index_reg+0x4); - - return dword; -} - -static void pci_write_config32_index_wait(pci_devfn_t dev, uint32_t index_reg, - uint32_t index, uint32_t data) -{ - uint32_t dword; - - pci_write_config32(dev, index_reg + 0x4, data); - - index |= (1<<30); - pci_write_config32(dev, index_reg, index); - do { - dword = pci_read_config32(dev, index_reg); - } while (!(dword & (1<<31))); -} - -#endif diff --git a/src/northbridge/amd/amdk8/get_sblk_pci1234.c b/src/northbridge/amd/amdk8/get_sblk_pci1234.c deleted file mode 100644 index fd9584f349..0000000000 --- a/src/northbridge/amd/amdk8/get_sblk_pci1234.c +++ /dev/null @@ -1,217 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2005 - 2008 Advanced Micro Devices, Inc. - * Copyright (C) 2007 coresystems GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - - -// 2005.9 yhlu serengeti support -// 2005.9 yhlu modify that to more dynamic for AMD Opteron Based MB -// 2007.9 stepan improve code documentation - -#include <console/console.h> -#include <device/pci.h> -#include <device/pci_ids.h> -#include <string.h> -#include <stdint.h> - -#include <cpu/amd/amdk8_sysconf.h> - -/* - * Why we need the pci1234[] array - * - * It will keep the sequence of HT devices in the HT link registers even when a - * given HT I/O card is not installed. - * - * The final result for pci1234[] will be - * - * pci1234[0] will record the south bridge link and bus range - * pci1234[i] will record HT chain i. - * - * For example, on the Tyan S2885 ramstage will put the AMD8151 chain (HT - * link 0) into the register 0xE0, and the AMD8131/8111 HT chain into the - * register 0xE4. - * - * So we need to make sure that the south bridge link will always be on - * pci1234[0]. - * - * Imagine a scenario with multiple HT I/O cards, where you don't install HT I/O 1, - * but you only install HT I/O 2 and HT I/O 3. The HT I/Os will end up in registers - * 0xE4 and 0xE8. - * - * But we want to leave pci1234[1] to HT I/O 1 (even though it is disabled), - * and let HT I/O 2 and HT I/O 3 still use pci1234[2] and pci1234[3]. - * - * So we keep the sequence. You need to preset the pci1234[1], pci1234[2], - * pci1234[3] for this purpose. - * - * For this example you need to set - * - * unsigned pci1234[] = { - * 0x0000ff0, - * 0x0000f10, // HT IO 1 card always on node 1 - * 0x0000f20, // HT IO 2 card always on node 2 - * 0x0000f30 // HT IO 3 card always on node 3 - * }; - * - * For 2P + htio(n1) + htio(n0_1) + htio(n1_1), 2P + htio(n1) + 2P + htio(n2) + htio(n3): - * You need an array pci1234[6]: - * - * unsigned pci1234[] = { - * 0x0000ff0, - * 0x0000010, // HT IO 1 card always on node 1 - * 0x0000f00, // HT IO 2 card always on node 0 - * 0x0000110, // HT IO 3 card always on node 1 - * 0x0000f20, // HT IO 4 card always on node 2 - * 0x0000f30 // HT IO 5 card always on node 3 - * }; - * - * - * For 4p+htio(n1)+htio(n2)+htio(n3),4p+htio(n1)+4p+htio(n6)+htio(n7): - * You need an array pci1234[6]: - * - * unsigned pci1234[] = { - * 0x0000ff0, - * 0x0000f10, // HT IO 1 card always on node 1 - * 0x0000f20, // HT IO 2 card always on node 2 - * 0x0000f30, // HT IO 3 card always on node 3 - * 0x0000f60, // HT IO 4 card always on node 6 - * 0x0000f70 // HT IO 5 card always on node 7 - * }; - * - * - * For 2p + htio(n1) + htio(n0_1) + htio(n1_1), 2P + htio(n1) + 2P + - * htio(n2) + htio(n3), 2P + htio(n1) + 4P + htio(n4) + htio(n5), - * you need an array pci1234[8]: - * - * unsigned pci1234[] = { - * 0x0000ff0, - * 0x0000010, // HT IO 1 card always on node 1 - * 0x0000f00, // HT IO 2 card always on node 0 - * 0x0000110, // HT IO 3 card always on node 1 - * 0x0000f20, // HT IO 4 card always on node 2 - * 0x0000f30 // HT IO 5 card always on node 3 - * 0x0000f40, // HT IO 6 card always on node 4 - * 0x0000f50 // HT IO 7 card always on node 5 - * }; - * - * - * For 4P + htio(n1) + htio(n2) + htio(n3), 4p + htio(n1) + 2p + htio(n4) + - * htio(n5), 4p + htio(n1) + 4p + htio(n6) + htio(n7), - * you need an array pci1234[8]: - * - * unsigned pci1234[] = { - * 0x0000ff0, - * 0x0000f10, // HT IO 1 card always on node 1 - * 0x0000f20, // HT IO 2 card always on node 2 - * 0x0000f30, // HT IO 3 card always on node 3 - * 0x0000f40, // HT IO 4 card always on node 4 - * 0x0000f50 // HT IO 5 card always on node 5 - * 0x0000f60, // HT IO 6 card always on node 6 - * 0x0000f70 // HT IO 7 card always on node 7 - * }; - * - * - * So the maximum posible value of HC_POSSIBLE_NUM is 8. (FIXME Why?) - * - * 1n: 3 - * 2n: 2x2 - 1 - * 4n: 1x4 - 2 - * 6n: 2 - * 8n: 2 - * Total: 12 - * - * Just put all the possible HT Node/link to the list tp pci1234[] in - * src/mainboard/<vendor>/<mainboard>get_bus_conf.c - * - * What about co-processor in socket 1 on a 2 way system? Or socket 2 and - * socket 3 on a 4 way system? Treat that as an HC, too! - * - */ - -void get_sblk_pci1234(void) -{ - - struct device *dev; - int i,j; - uint32_t dword; - - /* read PCI_DEV(0,0x18,0) 0x64 bit [8:9] to find out SbLink m */ - dev = dev_find_slot(0, PCI_DEVFN(0x18,0)); - dword = pci_read_config32(dev, 0x64); - sysconf.sblk = (dword>>8) & 0x3; - - dword &=0x0300; - dword |= 1; - sysconf.pci1234[0] = dword; - sysconf.hcid[0] = 0; - - /* About hardcoded numbering for HT_IO support - * - * Set the node_id and link_id that could have a HT chain in the one - * array, (FIXME: which one?) then check if is enabled. Then update - * final value - */ - - /* Here we need to set hcdn - * - * 1. hypertransport.c needs to record hcdn_reg together with 0xe0, - * 0xe4, 0xe8, 0xec when are set (FIXME: when WHAT is set?) - * - * 2. So at the same time we need update hcdn with hcdn_reg here. FIXME: Why? - */ - - dev = dev_find_slot(0, PCI_DEVFN(0x18, 1)); - - for (j = 0; j < 4; j++) { - uint32_t dwordx; - dwordx = pci_read_config32(dev, 0xe0 + j*4); - dwordx &=0xffff0ff1; /* keep bus num, node_id, link_num, enable bits */ - if ((dwordx & 0xff1) == dword) { /* SBLINK */ - sysconf.pci1234[0] = dwordx; - sysconf.hcdn[0] = sysconf.hcdn_reg[j]; - continue; - } - - if ((dwordx & 1) == 1) { - /* We need to find out the number of HC - * for exact match - */ - for (i = 1; i < sysconf.hc_possible_num; i++) { - if ((dwordx & 0xff0) == (sysconf.pci1234[i] & 0xff0)) { - sysconf.pci1234[i] = dwordx; - sysconf.hcdn[i] = sysconf.hcdn_reg[j]; - break; - } - } - - /* For 0xff0 match or same node */ - for (i = 1; i < sysconf.hc_possible_num; i++) { - if ((dwordx & 0xff0) == (dwordx & sysconf.pci1234[i] & 0xff0)) { - sysconf.pci1234[i] = dwordx; - sysconf.hcdn[i] = sysconf.hcdn_reg[j]; - break; - } - } - } - } - - for (i = 1; i < sysconf.hc_possible_num; i++) { - if ((sysconf.pci1234[i] & 1) != 1) { - sysconf.pci1234[i] = 0; - sysconf.hcdn[i] = 0x20202020; - } - sysconf.hcid[i] = 0; - } - -} diff --git a/src/northbridge/amd/amdk8/incoherent_ht.c b/src/northbridge/amd/amdk8/incoherent_ht.c deleted file mode 100644 index 614c199735..0000000000 --- a/src/northbridge/amd/amdk8/incoherent_ht.c +++ /dev/null @@ -1,821 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * 2004.12 yhlu add multi ht chain dynamically support - * 2005.11 yhlu add let real sb to use small unitid - * - * 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. - */ - -#include <device/pci_def.h> -#include <device/pci_ids.h> -#include <device/hypertransport_def.h> -#include <lib.h> -#include "amdk8.h" - -// Do we need allocate MMIO? Current We direct last 64M to sblink only, We can not lose access to last 4M range to ROM -#ifndef K8_ALLOCATE_MMIO_RANGE - #define K8_ALLOCATE_MMIO_RANGE 0 -#endif - -static inline void print_linkn_in (const char *strval, uint8_t byteval) -{ - printk(BIOS_DEBUG, "%s%02x\n", strval, byteval); -} - -static uint8_t ht_lookup_capability(pci_devfn_t dev, uint16_t val) -{ - uint8_t pos; - uint8_t hdr_type; - - hdr_type = pci_read_config8(dev, PCI_HEADER_TYPE); - pos = 0; - hdr_type &= 0x7f; - - if ((hdr_type == PCI_HEADER_TYPE_NORMAL) || - (hdr_type == PCI_HEADER_TYPE_BRIDGE)) { - pos = PCI_CAPABILITY_LIST; - } - if (pos > PCI_CAP_LIST_NEXT) { - pos = pci_read_config8(dev, pos); - } - while (pos != 0) { /* loop through the linked list */ - uint8_t cap; - cap = pci_read_config8(dev, pos + PCI_CAP_LIST_ID); - if (cap == PCI_CAP_ID_HT) { - uint16_t flags; - - flags = pci_read_config16(dev, pos + PCI_CAP_FLAGS); - if ((flags >> 13) == val) { - /* Entry is a slave or host , success... */ - break; - } - } - pos = pci_read_config8(dev, pos + PCI_CAP_LIST_NEXT); - } - return pos; -} - -static uint8_t ht_lookup_slave_capability(pci_devfn_t dev) -{ - return ht_lookup_capability(dev, 0); // Slave/Primary Interface Block Format -} - -static void ht_collapse_previous_enumeration(uint8_t bus, unsigned offset_unitid) -{ - pci_devfn_t dev; - - //actually, only for one HT device HT chain, and unitid is 0 -#if !CONFIG_HT_CHAIN_UNITID_BASE - if (offset_unitid) { - return; - } -#endif - - /* Check if is already collapsed */ - if ((!offset_unitid) || (offset_unitid && (!((CONFIG_HT_CHAIN_END_UNITID_BASE == 0) && (CONFIG_HT_CHAIN_END_UNITID_BASE <CONFIG_HT_CHAIN_UNITID_BASE))))) { - uint32_t id; - dev = PCI_DEV(bus, 0, 0); - id = pci_read_config32(dev, PCI_VENDOR_ID); - if (!((id == 0xffffffff) || (id == 0x00000000) || - (id == 0x0000ffff) || (id == 0xffff0000))) { - return; - } - } - - /* Spin through the devices and collapse any previous - * hypertransport enumeration. - */ - for (dev = PCI_DEV(bus, 1, 0); dev <= PCI_DEV(bus, 0x1f, 0x7); dev += PCI_DEV(0, 1, 0)) { - uint32_t id; - uint8_t pos; - uint16_t flags; - - id = pci_read_config32(dev, PCI_VENDOR_ID); - if ((id == 0xffffffff) || (id == 0x00000000) || - (id == 0x0000ffff) || (id == 0xffff0000)) { - continue; - } - - pos = ht_lookup_slave_capability(dev); - if (!pos) { - continue; - } - - /* Clear the unitid */ - flags = pci_read_config16(dev, pos + PCI_CAP_FLAGS); - flags &= ~0x1f; - pci_write_config16(dev, pos + PCI_CAP_FLAGS, flags); - } -} - -static uint16_t ht_read_freq_cap(pci_devfn_t dev, uint8_t pos) -{ - /* Handle bugs in valid hypertransport frequency reporting */ - uint16_t freq_cap; - uint32_t id; - - freq_cap = pci_read_config16(dev, pos); - printk(BIOS_SPEW, "pos=0x%x, unfiltered freq_cap=0x%x\n", pos, freq_cap); - freq_cap &= ~(1 << HT_FREQ_VENDOR); /* Ignore Vendor HT frequencies */ - - id = pci_read_config32(dev, 0); - - /* AMD 8131 Errata 48 */ - if (id == (PCI_VENDOR_ID_AMD | (PCI_DEVICE_ID_AMD_8131_PCIX << 16))) { - freq_cap &= ~(1 << HT_FREQ_800Mhz); - return freq_cap; - } - - /* AMD 8151 Errata 23 */ - if (id == (PCI_VENDOR_ID_AMD | (PCI_DEVICE_ID_AMD_8151_SYSCTRL << 16))) { - freq_cap &= ~(1 << HT_FREQ_800Mhz); - return freq_cap; - } - - /* AMD K8 Unsupported 1GHz? */ - if (id == (PCI_VENDOR_ID_AMD | (0x1100 << 16))) { - #if IS_ENABLED(CONFIG_K8_HT_FREQ_1G_SUPPORT) - #if !IS_ENABLED(CONFIG_K8_REV_F_SUPPORT) - if (is_cpu_pre_e0()) { // only E0 later support 1GHz - freq_cap &= ~(1 << HT_FREQ_1000Mhz); - } - #endif - #else - freq_cap &= ~(1 << HT_FREQ_1000Mhz); - #endif - } - - printk(BIOS_SPEW, "pos=0x%x, filtered freq_cap=0x%x\n", pos, freq_cap); - - return freq_cap; -} - -static uint8_t ht_read_width_cap(pci_devfn_t dev, uint8_t pos) -{ - uint8_t width_cap = pci_read_config8(dev, pos); - - uint32_t id; - - id = pci_read_config32(dev, 0); - - /* netlogic micro cap doesn't support 16 bit yet */ - if (id == (0x184e | (0x0001 << 16))) { - if ((width_cap & 0x77) == 0x11) { - width_cap &= 0x88; - } - } - - return width_cap; - -} - -#define LINK_OFFS(CTRL, WIDTH,FREQ,FREQ_CAP) \ - (((CTRL & 0xff) << 24) | ((WIDTH & 0xff) << 16) | ((FREQ & 0xff) << 8) | (FREQ_CAP & 0xFF)) - -#define LINK_CTRL(OFFS) ((OFFS >> 24) & 0xFF) -#define LINK_WIDTH(OFFS) ((OFFS >> 16) & 0xFF) -#define LINK_FREQ(OFFS) ((OFFS >> 8) & 0xFF) -#define LINK_FREQ_CAP(OFFS) ((OFFS) & 0xFF) - -#define PCI_HT_HOST_OFFS LINK_OFFS( \ - PCI_HT_CAP_HOST_CTRL, \ - PCI_HT_CAP_HOST_WIDTH, \ - PCI_HT_CAP_HOST_FREQ, \ - PCI_HT_CAP_HOST_FREQ_CAP) - -#define PCI_HT_SLAVE0_OFFS LINK_OFFS( \ - PCI_HT_CAP_SLAVE_CTRL0, \ - PCI_HT_CAP_SLAVE_WIDTH0, \ - PCI_HT_CAP_SLAVE_FREQ0, \ - PCI_HT_CAP_SLAVE_FREQ_CAP0) - -#define PCI_HT_SLAVE1_OFFS LINK_OFFS( \ - PCI_HT_CAP_SLAVE_CTRL1, \ - PCI_HT_CAP_SLAVE_WIDTH1, \ - PCI_HT_CAP_SLAVE_FREQ1, \ - PCI_HT_CAP_SLAVE_FREQ_CAP1) - -static int ht_optimize_link( - pci_devfn_t dev1, uint8_t pos1, unsigned offs1, - pci_devfn_t dev2, uint8_t pos2, unsigned offs2) -{ - static const uint8_t link_width_to_pow2[]= { 3, 4, 0, 5, 1, 2, 0, 0 }; - static const uint8_t pow2_to_link_width[] = { 0x7, 4, 5, 0, 1, 3 }; - uint16_t freq_cap1, freq_cap2; - uint8_t width_cap1, width_cap2, width, old_width, ln_width1, ln_width2; - uint8_t freq, old_freq; - int needs_reset; - /* Set link width and frequency */ - - printk(BIOS_SPEW, "entering ht_optimize_link\n"); - /* Initially assume everything is already optimized and I don't need a reset */ - needs_reset = 0; - - /* Get the frequency capabilities */ - freq_cap1 = ht_read_freq_cap(dev1, pos1 + LINK_FREQ_CAP(offs1)); - freq_cap2 = ht_read_freq_cap(dev2, pos2 + LINK_FREQ_CAP(offs2)); - printk(BIOS_SPEW, "freq_cap1=0x%x, freq_cap2=0x%x\n", freq_cap1, freq_cap2); - - /* Calculate the highest possible frequency */ - freq = log2(freq_cap1 & freq_cap2); - - /* See if I am changing the link freqency */ - old_freq = pci_read_config8(dev1, pos1 + LINK_FREQ(offs1)); - old_freq &= 0x0f; - needs_reset |= old_freq != freq; - printk(BIOS_SPEW, "dev1 old_freq=0x%x, freq=0x%x, needs_reset=0x%0x\n", old_freq, freq, needs_reset); - old_freq = pci_read_config8(dev2, pos2 + LINK_FREQ(offs2)); - old_freq &= 0x0f; - needs_reset |= old_freq != freq; - printk(BIOS_SPEW, "dev2 old_freq=0x%x, freq=0x%x, needs_reset=0x%0x\n", old_freq, freq, needs_reset); - - /* Set the Calculated link frequency */ - pci_write_config8(dev1, pos1 + LINK_FREQ(offs1), freq); - pci_write_config8(dev2, pos2 + LINK_FREQ(offs2), freq); - - /* Get the width capabilities */ - width_cap1 = ht_read_width_cap(dev1, pos1 + LINK_WIDTH(offs1)); - width_cap2 = ht_read_width_cap(dev2, pos2 + LINK_WIDTH(offs2)); - printk(BIOS_SPEW, "width_cap1=0x%x, width_cap2=0x%x\n", width_cap1, width_cap2); - - /* Calculate dev1's input width */ - ln_width1 = link_width_to_pow2[width_cap1 & 7]; - ln_width2 = link_width_to_pow2[(width_cap2 >> 4) & 7]; - printk(BIOS_SPEW, "dev1 input ln_width1=0x%x, ln_width2=0x%x\n", ln_width1, ln_width2); - if (ln_width1 > ln_width2) { - ln_width1 = ln_width2; - } - width = pow2_to_link_width[ln_width1]; - printk(BIOS_SPEW, "dev1 input width=0x%x\n", width); - /* Calculate dev1's output width */ - ln_width1 = link_width_to_pow2[(width_cap1 >> 4) & 7]; - ln_width2 = link_width_to_pow2[width_cap2 & 7]; - printk(BIOS_SPEW, "dev1 output ln_width1=0x%x, ln_width2=0x%x\n", ln_width1, ln_width2); - if (ln_width1 > ln_width2) { - ln_width1 = ln_width2; - } - width |= pow2_to_link_width[ln_width1] << 4; - printk(BIOS_SPEW, "dev1 input|output width=0x%x\n", width); - - /* See if I am changing dev1's width */ - old_width = pci_read_config8(dev1, pos1 + LINK_WIDTH(offs1) + 1); - old_width &= 0x77; - needs_reset |= old_width != width; - printk(BIOS_SPEW, "old dev1 input|output width=0x%x\n", width); - - /* Set dev1's widths */ - pci_write_config8(dev1, pos1 + LINK_WIDTH(offs1) + 1, width); - - /* Calculate dev2's width */ - width = ((width & 0x70) >> 4) | ((width & 0x7) << 4); - printk(BIOS_SPEW, "dev2 input|output width=0x%x\n", width); - - /* See if I am changing dev2's width */ - old_width = pci_read_config8(dev2, pos2 + LINK_WIDTH(offs2) + 1); - old_width &= 0x77; - needs_reset |= old_width != width; - printk(BIOS_SPEW, "old dev2 input|output width=0x%x\n", width); - - /* Set dev2's widths */ - pci_write_config8(dev2, pos2 + LINK_WIDTH(offs2) + 1, width); - - return needs_reset; -} - -#if IS_ENABLED(CONFIG_RAMINIT_SYSINFO) -static void ht_setup_chainx(pci_devfn_t udev, uint8_t upos, uint8_t bus, - unsigned offset_unitid, struct sys_info *sysinfo) -#else -static int ht_setup_chainx(pci_devfn_t udev, uint8_t upos, uint8_t bus, - unsigned offset_unitid) -#endif -{ - //even CONFIG_HT_CHAIN_UNITID_BASE == 0, we still can go through this function, because of end_of_chain check, also We need it to optimize link - - uint8_t next_unitid, last_unitid; - unsigned uoffs; - -#if !IS_ENABLED(CONFIG_RAMINIT_SYSINFO) - int reset_needed = 0; -#endif - -#if CONFIG_HT_CHAIN_END_UNITID_BASE != 0x20 - //let't record the device of last ht device, So we can set the Unitid to CONFIG_HT_CHAIN_END_UNITID_BASE - unsigned real_last_unitid = 0; - uint8_t real_last_pos = 0; - int ht_dev_num = 0; - uint8_t end_used = 0; -#endif - - uoffs = PCI_HT_HOST_OFFS; - next_unitid = (offset_unitid) ? CONFIG_HT_CHAIN_UNITID_BASE:1; - - do { - uint32_t id; - uint8_t pos; - uint16_t flags, ctrl; - uint8_t count; - unsigned offs; - - /* Wait until the link initialization is complete */ - do { - ctrl = pci_read_config16(udev, upos + LINK_CTRL(uoffs)); - /* Is this the end of the hypertransport chain? */ - if (ctrl & (1 << 6)) { - goto end_of_chain; - } - - if (ctrl & ((1 << 4) | (1 << 8))) { - /* - * Either the link has failed, or we have - * a CRC error. - * Sometimes this can happen due to link - * retrain, so lets knock it down and see - * if its transient - */ - ctrl |= ((1 << 4) | (1 <<8)); // Link fail + Crc - pci_write_config16(udev, upos + LINK_CTRL(uoffs), ctrl); - ctrl = pci_read_config16(udev, upos + LINK_CTRL(uoffs)); - if (ctrl & ((1 << 4) | (1 << 8))) { - printk(BIOS_ERR, "Detected error on Hypertransport Link\n"); - break; - } - } - } while ((ctrl & (1 << 5)) == 0); - - pci_devfn_t dev = PCI_DEV(bus, 0, 0); - last_unitid = next_unitid; - - id = pci_read_config32(dev, PCI_VENDOR_ID); - - /* If the chain is enumerated quit */ - if ((id == 0xffffffff) || (id == 0x00000000) || - (id == 0x0000ffff) || (id == 0xffff0000)) - { - break; - } - - pos = ht_lookup_slave_capability(dev); - if (!pos) { - printk(BIOS_ERR, "udev=%08x", udev); - printk(BIOS_ERR, "\tupos=%08x", upos); - printk(BIOS_ERR, "\tuoffs=%08x", uoffs); - printk(BIOS_ERR, "\tHT link capability not found\n"); - break; - } - - -#if CONFIG_HT_CHAIN_END_UNITID_BASE != 0x20 - if (offset_unitid) { - if (next_unitid >= (bus ? 0x20:0x18)) { - if (!end_used) { - next_unitid = CONFIG_HT_CHAIN_END_UNITID_BASE; - end_used = 1; - } else { - goto out; - } - - } - real_last_pos = pos; - real_last_unitid = next_unitid; - ht_dev_num++; - } -#endif - /* Update the Unitid of the current device */ - flags = pci_read_config16(dev, pos + PCI_CAP_FLAGS); - flags &= ~0x1f; /* mask out the base Unit ID */ - flags |= next_unitid & 0x1f; - pci_write_config16(dev, pos + PCI_CAP_FLAGS, flags); - - /* Compute the number of unitids consumed */ - count = (flags >> 5) & 0x1f; - - /* Note the change in device number */ - dev = PCI_DEV(bus, next_unitid, 0); - - next_unitid += count; - - /* Find which side of the ht link we are on, - * by reading which direction our last write to PCI_CAP_FLAGS - * came from. - */ - flags = pci_read_config16(dev, pos + PCI_CAP_FLAGS); - offs = ((flags>>10) & 1) ? PCI_HT_SLAVE1_OFFS : PCI_HT_SLAVE0_OFFS; - - #if IS_ENABLED(CONFIG_RAMINIT_SYSINFO) - /* store the link pair here and we will Setup the Hypertransport link later, after we get final FID/VID */ - { - struct link_pair_st *link_pair = &sysinfo->link_pair[sysinfo->link_pair_num]; - link_pair->udev = udev; - link_pair->upos = upos; - link_pair->uoffs = uoffs; - link_pair->dev = dev; - link_pair->pos = pos; - link_pair->offs = offs; - sysinfo->link_pair_num++; - } - #else - reset_needed |= ht_optimize_link(udev, upos, uoffs, dev, pos, offs); - #endif - - /* Remeber the location of the last device */ - udev = dev; - upos = pos; - uoffs = (offs != PCI_HT_SLAVE0_OFFS) ? PCI_HT_SLAVE0_OFFS : PCI_HT_SLAVE1_OFFS; - - } while (last_unitid != next_unitid); - -#if CONFIG_HT_CHAIN_END_UNITID_BASE != 0x20 -out: -#endif -end_of_chain:; - -#if CONFIG_HT_CHAIN_END_UNITID_BASE != 0x20 - if (offset_unitid && (ht_dev_num > 1) && (real_last_unitid != CONFIG_HT_CHAIN_END_UNITID_BASE) && !end_used) { - uint16_t flags; - flags = pci_read_config16(PCI_DEV(bus,real_last_unitid,0), real_last_pos + PCI_CAP_FLAGS); - flags &= ~0x1f; - flags |= CONFIG_HT_CHAIN_END_UNITID_BASE & 0x1f; - pci_write_config16(PCI_DEV(bus, real_last_unitid, 0), real_last_pos + PCI_CAP_FLAGS, flags); - - #if IS_ENABLED(CONFIG_RAMINIT_SYSINFO) - // Here need to change the dev in the array - int i; - for (i = 0; i < sysinfo->link_pair_num; i++) - { - struct link_pair_st *link_pair = &sysinfo->link_pair[i]; - if (link_pair->udev == PCI_DEV(bus, real_last_unitid, 0)) { - link_pair->udev = PCI_DEV(bus, CONFIG_HT_CHAIN_END_UNITID_BASE, 0); - continue; - } - if (link_pair->dev == PCI_DEV(bus, real_last_unitid, 0)) { - link_pair->dev = PCI_DEV(bus, CONFIG_HT_CHAIN_END_UNITID_BASE, 0); - } - } - #endif - - } -#endif - -#if !IS_ENABLED(CONFIG_RAMINIT_SYSINFO) - return reset_needed; -#endif - -} - -static int optimize_link_read_pointer(uint8_t node, uint8_t linkn, uint8_t linkt, uint8_t val) -{ - uint32_t dword, dword_old; - uint8_t link_type; - - /* This works on an Athlon64 because unimplemented links return 0 */ - dword = pci_read_config32(PCI_DEV(0,0x18+node,0), 0x98 + (linkn * 0x20)); - link_type = dword & 0xff; - - - if ((link_type & 7) == linkt) { /* Coherent Link only linkt = 3, ncoherent = 7*/ - dword_old = dword = pci_read_config32(PCI_DEV(0,0x18+node,3), 0xdc); - dword &= ~(0xff<<(linkn *8)); - dword |= val << (linkn *8); - - if (dword != dword_old) { - pci_write_config32(PCI_DEV(0,0x18+node,3), 0xdc, dword); - return 1; - } - } - - return 0; -} - -static int optimize_link_read_pointers_chain(uint8_t ht_c_num) -{ - int reset_needed; - uint8_t i; - - reset_needed = 0; - - /* First one is SB HT chain. */ - for (i = 0; i < ht_c_num; i++) { - uint32_t reg; - uint8_t nodeid, linkn; - uint8_t busn; - uint8_t val; - unsigned devn; - - reg = pci_read_config32(PCI_DEV(0,0x18,1), 0xe0 + i * 4); - - nodeid = ((reg & 0xf0)>>4); // nodeid - linkn = ((reg & 0xf00)>>8); // link n - busn = (reg & 0xff0000)>>16; //busn - - devn = offset_unit_id(i == 0) ? CONFIG_HT_CHAIN_UNITID_BASE : 1; - - reg = pci_read_config32(PCI_DEV(busn, devn, 0), PCI_VENDOR_ID); // ? the chain dev maybe offseted - if ((reg & 0xffff) == PCI_VENDOR_ID_AMD) { - val = 0x25; - } else if ((reg & 0xffff) == PCI_VENDOR_ID_NVIDIA) { - val = 0x25;//??? - } else { - continue; - } - - reset_needed |= optimize_link_read_pointer(nodeid, linkn, 0x07, val); - - } - - return reset_needed; -} - -#if IS_ENABLED(CONFIG_SOUTHBRIDGE_NVIDIA_CK804) -static int set_ht_link_buffer_count(uint8_t node, uint8_t linkn, uint8_t linkt, unsigned val) -{ - uint32_t dword; - uint8_t link_type; - unsigned regpos; - pci_devfn_t dev; - - /* This works on an Athlon64 because unimplemented links return 0 */ - regpos = 0x98 + (linkn * 0x20); - dev = PCI_DEV(0,0x18+node,0); - dword = pci_read_config32(dev, regpos); - link_type = dword & 0xff; - - if ((link_type & 0x7) == linkt) { /* Coherent Link only linkt = 3, ncoherent = 7*/ - regpos = 0x90 + (linkn * 0x20); - dword = pci_read_config32(dev, regpos); - - if (dword != val) { - pci_write_config32(dev, regpos, val); - return 1; - } - } - - return 0; -} - -static int set_ht_link_buffer_counts_chain(uint8_t ht_c_num, unsigned vendorid, unsigned val) -{ - int reset_needed; - uint8_t i; - - reset_needed = 0; - - for (i = 0; i < ht_c_num; i++) { - uint32_t reg; - uint8_t nodeid, linkn; - uint8_t busn; - unsigned devn; - - reg = pci_read_config32(PCI_DEV(0,0x18,1), 0xe0 + i * 4); - if ((reg & 3) != 3) continue; // not enabled - - nodeid = ((reg & 0xf0)>>4); // nodeid - linkn = ((reg & 0xf00)>>8); // link n - busn = (reg & 0xff0000)>>16; //busn - - for (devn = 0; devn < 0x20; devn++) { - reg = pci_read_config32(PCI_DEV(busn, devn, 0), PCI_VENDOR_ID); //1? - if ((reg & 0xffff) == vendorid) { - reset_needed |= set_ht_link_buffer_count(nodeid, linkn, 0x07,val); - break; - } - } - } - - return reset_needed; -} -#endif - -#if IS_ENABLED(CONFIG_RAMINIT_SYSINFO) -static void ht_setup_chains(uint8_t ht_c_num, struct sys_info *sysinfo) -#else -static int ht_setup_chains(uint8_t ht_c_num) -#endif -{ - /* Assumption the HT chain that is bus 0 has the HT I/O Hub on it. - * On most boards this just happens. If a CPU has multiple - * non Coherent links the appropriate bus registers for the - * links needs to be programed to point at bus 0. - */ - uint8_t upos; - pci_devfn_t udev; - uint8_t i; - -#if !IS_ENABLED(CONFIG_RAMINIT_SYSINFO) - int reset_needed = 0; -#else - sysinfo->link_pair_num = 0; -#endif - - /* First one is SB HT chain. */ - for (i = 0; i < ht_c_num; i++) { - uint32_t reg; - uint8_t devpos; - unsigned regpos; - uint32_t dword; - uint8_t busn; - - reg = pci_read_config32(PCI_DEV(0,0x18,1), 0xe0 + i * 4); - - //We need setup 0x94, 0xb4, and 0xd4 according to the reg - devpos = ((reg & 0xf0)>>4)+0x18; // nodeid;it will decide 0x18 or 0x19 - regpos = ((reg & 0xf00)>>8) * 0x20 + 0x94; // link n;it will decide 0x94 or 0xb4, 0x0xd4; - busn = (reg & 0xff0000)>>16; - - dword = pci_read_config32(PCI_DEV(0, devpos, 0), regpos); - dword &= ~(0xffff<<8); - dword |= (reg & 0xffff0000)>>8; - pci_write_config32(PCI_DEV(0, devpos,0), regpos , dword); - - /* Make certain the HT bus is not enumerated */ - ht_collapse_previous_enumeration(busn, offset_unit_id(i == 0)); - - upos = ((reg & 0xf00)>>8) * 0x20 + 0x80; - udev = PCI_DEV(0, devpos, 0); - -#if IS_ENABLED(CONFIG_RAMINIT_SYSINFO) - ht_setup_chainx(udev,upos,busn, offset_unit_id(i == 0), sysinfo); // all not -#else - reset_needed |= ht_setup_chainx(udev,upos,busn, offset_unit_id(i == 0)); //all not -#endif - - } - -#if !IS_ENABLED(CONFIG_RAMINIT_SYSINFO) - reset_needed |= optimize_link_read_pointers_chain(ht_c_num); - - return reset_needed; -#endif - -} - -#if IS_ENABLED(CONFIG_RAMINIT_SYSINFO) -static void ht_setup_chains_x(struct sys_info *sysinfo) -#else -static int ht_setup_chains_x(void) -#endif -{ - uint8_t nodeid; - uint32_t reg; - uint32_t tempreg; - uint8_t next_busn; - uint8_t ht_c_num; - uint8_t nodes; -#if IS_ENABLED(CONFIG_K8_ALLOCATE_IO_RANGE) - unsigned next_io_base; -#endif - - nodes = get_nodes(); - - /* read PCI_DEV(0,0x18,0) 0x64 bit [8:9] to find out SbLink m */ - reg = pci_read_config32(PCI_DEV(0, 0x18, 0), 0x64); - /* update PCI_DEV(0, 0x18, 1) 0xe0 to 0x05000m03, and next_busn = 0x3f+1 */ - print_linkn_in("SBLink=", ((reg>>8) & 3)); -#if IS_ENABLED(CONFIG_RAMINIT_SYSINFO) - sysinfo->sblk = (reg>>8) & 3; - sysinfo->sbbusn = 0; - sysinfo->nodes = nodes; -#endif - tempreg = 3 | (0<<4) | (((reg>>8) & 3)<<8) | (0<<16)| (0x3f<<24); - pci_write_config32(PCI_DEV(0, 0x18, 1), 0xe0, tempreg); - - next_busn = 0x3f+1; /* 0 will be used ht chain with SB we need to keep SB in bus0 in auto stage*/ - -#if IS_ENABLED(CONFIG_K8_ALLOCATE_IO_RANGE) - /* io range allocation */ - tempreg = 0 | (((reg>>8) & 0x3) << 4)| (0x3<<12); //limit - pci_write_config32(PCI_DEV(0, 0x18, 1), 0xC4, tempreg); - tempreg = 3 | (3<<4) | (0<<12); //base - pci_write_config32(PCI_DEV(0, 0x18, 1), 0xC0, tempreg); - next_io_base = 0x3+0x1; -#endif - - /* clean others */ - for (ht_c_num = 1;ht_c_num < 4; ht_c_num++) { - pci_write_config32(PCI_DEV(0, 0x18, 1), 0xe0 + ht_c_num * 4, 0); - -#if IS_ENABLED(CONFIG_K8_ALLOCATE_IO_RANGE) - /* io range allocation */ - pci_write_config32(PCI_DEV(0, 0x18, 1), 0xc4 + ht_c_num * 8, 0); - pci_write_config32(PCI_DEV(0, 0x18, 1), 0xc0 + ht_c_num * 8, 0); -#endif - } - - for (nodeid = 0; nodeid < nodes; nodeid++) { - pci_devfn_t dev; - uint8_t linkn; - dev = PCI_DEV(0, 0x18+nodeid,0); - for (linkn = 0; linkn < 3; linkn++) { - unsigned regpos; - regpos = 0x98 + 0x20 * linkn; - reg = pci_read_config32(dev, regpos); - if ((reg & 0x17) != 7) continue; /* it is not non conherent or not connected*/ - print_linkn_in("NC node|link=", ((nodeid & 0xf)<<4)|(linkn & 0xf)); - tempreg = 3 | (nodeid <<4) | (linkn<<8); - /*compare (temp & 0xffff), with (PCI(0, 0x18, 1) 0xe0 to 0xec & 0xfffff) */ - for (ht_c_num = 0;ht_c_num < 4; ht_c_num++) { - reg = pci_read_config32(PCI_DEV(0, 0x18, 1), 0xe0 + ht_c_num * 4); - if (((reg & 0xffff) == (tempreg & 0xffff)) || ((reg & 0xffff) == 0x0000)) { /*we got it*/ - break; - } - } - if (ht_c_num == 4) break; /*used up only 4 non conherent allowed*/ - /*update to 0xe0...*/ - if ((reg & 0xf) == 3) continue; /*SbLink so don't touch it */ - print_linkn_in("\tbusn=", next_busn); - tempreg |= (next_busn<<16)|((next_busn+0x3f)<<24); - pci_write_config32(PCI_DEV(0, 0x18, 1), 0xe0 + ht_c_num * 4, tempreg); - next_busn+=0x3f+1; - -#if IS_ENABLED(CONFIG_K8_ALLOCATE_IO_RANGE) - /* io range allocation */ - tempreg = nodeid | (linkn<<4) | ((next_io_base+0x3)<<12); //limit - pci_write_config32(PCI_DEV(0, 0x18, 1), 0xC4 + ht_c_num * 8, tempreg); - tempreg = 3 /*| (3<<4)*/ | (next_io_base<<12); //base :ISA and VGA ? - pci_write_config32(PCI_DEV(0, 0x18, 1), 0xC0 + ht_c_num * 8, tempreg); - next_io_base += 0x3+0x1; -#endif - - } - } - /*update 0xe0, 0xe4, 0xe8, 0xec from PCI_DEV(0, 0x18,1) to PCI_DEV(0, 0x19,1) to PCI_DEV(0, 0x1f,1);*/ - - for (nodeid = 1; nodeid < nodes; nodeid++) { - int i; - pci_devfn_t dev; - dev = PCI_DEV(0, 0x18+nodeid,1); - for (i = 0; i < 4; i++) { - unsigned regpos; - regpos = 0xe0 + i * 4; - reg = pci_read_config32(PCI_DEV(0, 0x18, 1), regpos); - pci_write_config32(dev, regpos, reg); - } - -#if IS_ENABLED(CONFIG_K8_ALLOCATE_IO_RANGE) - /* io range allocation */ - for (i = 0; i < 4; i++) { - unsigned regpos; - regpos = 0xc4 + i * 8; - reg = pci_read_config32(PCI_DEV(0, 0x18, 1), regpos); - pci_write_config32(dev, regpos, reg); - } - for (i = 0; i < 4; i++) { - unsigned regpos; - regpos = 0xc0 + i * 8; - reg = pci_read_config32(PCI_DEV(0, 0x18, 1), regpos); - pci_write_config32(dev, regpos, reg); - } -#endif - } - - /* recount ht_c_num*/ - uint8_t i = 0; - for (ht_c_num = 0;ht_c_num < 4; ht_c_num++) { - reg = pci_read_config32(PCI_DEV(0, 0x18, 1), 0xe0 + ht_c_num * 4); - if (((reg & 0xf) != 0x0)) { - i++; - } - } - -#if IS_ENABLED(CONFIG_RAMINIT_SYSINFO) - sysinfo->ht_c_num = i; - ht_setup_chains(i, sysinfo); - sysinfo->sbdn = get_sbdn(sysinfo->sbbusn); -#else - return ht_setup_chains(i); -#endif - -} - -#if IS_ENABLED(CONFIG_RAMINIT_SYSINFO) -static int optimize_link_incoherent_ht(struct sys_info *sysinfo) -{ - // We need to use recorded link pair info to optimize the link - int i; - int reset_needed = 0; - - unsigned link_pair_num = sysinfo->link_pair_num; - - printk(BIOS_SPEW, "entering optimize_link_incoherent_ht\n"); - printk(BIOS_SPEW, "sysinfo->link_pair_num=0x%x\n", link_pair_num); - for (i = 0; i < link_pair_num; i++) { - struct link_pair_st *link_pair= &sysinfo->link_pair[i]; - reset_needed |= ht_optimize_link(link_pair->udev, link_pair->upos, link_pair->uoffs, link_pair->dev, link_pair->pos, link_pair->offs); - printk(BIOS_SPEW, "after ht_optimize_link for link pair %d, reset_needed=0x%x\n", i, reset_needed); - } - - reset_needed |= optimize_link_read_pointers_chain(sysinfo->ht_c_num); - printk(BIOS_SPEW, "after optimize_link_read_pointers_chain, reset_needed=0x%x\n", reset_needed); - - return reset_needed; - -} -#endif diff --git a/src/northbridge/amd/amdk8/misc_control.c b/src/northbridge/amd/amdk8/misc_control.c deleted file mode 100644 index 0edd58c2dd..0000000000 --- a/src/northbridge/amd/amdk8/misc_control.c +++ /dev/null @@ -1,246 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * written in 2003 by Eric Biederman - * - * - Athlon64 workarounds by Stefan Reinauer - * - "reset once" logic by Yinghai Lu - * - * 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. - */ - -/* Turn off machine check triggers when reading - * PCI space where there are no devices. - * This is necessary when scanning the bus for - * devices which is done by the kernel - * - */ - -#include <console/console.h> -#include <device/device.h> -#include <device/pci.h> -#include <device/pci_ids.h> -#include <device/pci_ops.h> -#include <reset.h> -#include <pc80/mc146818rtc.h> -#include <lib.h> -#include <cpu/amd/model_fxx_rev.h> - -#include "amdk8.h" - -/** - * @brief Read resources for AGP aperture - * - * @param dev - * - * There is only one AGP aperture resource needed. The resource is added to - * the northbridge of BSP. - * - * The same trick can be used to augment legacy VGA resources which can - * be detect by generic PCI resource allocator for VGA devices. - * BAD: it is more tricky than I think, the resource allocation code is - * implemented in a way to NOT DOING legacy VGA resource allocation on - * purpose :-(. - */ -static void mcf3_read_resources(struct device *dev) -{ - struct resource *resource; - unsigned char iommu; - /* Read the generic PCI resources */ - pci_dev_read_resources(dev); - - /* If we are not the first processor don't allocate the GART aperture */ - if (dev->path.pci.devfn != PCI_DEVFN(0x18, 3)) { - return; - } - - iommu = CONFIG_IOMMU; - get_option(&iommu, "iommu"); - - if (iommu) { - /* Add a GART aperture resource */ - resource = new_resource(dev, 0x94); - resource->size = CONFIG_AGP_APERTURE_SIZE; - resource->align = log2(resource->size); - resource->gran = log2(resource->size); - resource->limit = 0xffffffff; /* 4G */ - resource->flags = IORESOURCE_MEM; - } -} - -static void set_agp_aperture(struct device *dev) -{ - struct resource *resource; - - resource = probe_resource(dev, 0x94); - if (resource) { - struct device *pdev; - uint32_t gart_base, gart_acr; - - /* Remember this resource has been stored */ - resource->flags |= IORESOURCE_STORED; - - /* Find the size of the GART aperture */ - gart_acr = (0<<6)|(0<<5)|(0<<4)|((resource->gran - 25) << 1)|(0<<0); - - /* Get the base address */ - gart_base = ((resource->base) >> 25) & 0x00007fff; - - /* Update the other northbridges */ - pdev = 0; - while ((pdev = dev_find_device(PCI_VENDOR_ID_AMD, 0x1103, pdev))) { - /* Store the GART size but don't enable it */ - pci_write_config32(pdev, 0x90, gart_acr); - - /* Store the GART base address */ - pci_write_config32(pdev, 0x94, gart_base); - - /* Don't set the GART Table base address */ - pci_write_config32(pdev, 0x98, 0); - - /* Report the resource has been stored... */ - report_resource_stored(pdev, resource, " <gart>"); - } - } -} - -static void mcf3_set_resources(struct device *dev) -{ - /* Set the gart apeture */ - set_agp_aperture(dev); - - /* Set the generic PCI resources */ - pci_dev_set_resources(dev); -} - -static void misc_control_init(struct device *dev) -{ - uint32_t cmd, cmd_ref; - int needs_reset; - struct device *f0_dev; - - printk(BIOS_DEBUG, "NB: Function 3 Misc Control.. "); - needs_reset = 0; - - /* Disable Machine checks from Invalid Locations. - * This is needed for PC backwards compatibility. - */ - cmd = pci_read_config32(dev, 0x44); - cmd |= (1<<6) | (1<<25); - pci_write_config32(dev, 0x44, cmd); -#if !IS_ENABLED(CONFIG_K8_REV_F_SUPPORT) - if (is_cpu_pre_c0()) { - - /* Errata 58 - * Disable CPU low power states C2, C1 and throttling - */ - cmd = pci_read_config32(dev, 0x80); - cmd &= ~(1<<0); - pci_write_config32(dev, 0x80, cmd); - cmd = pci_read_config32(dev, 0x84); - cmd &= ~(1<<24); - cmd &= ~(1<<8); - pci_write_config32(dev, 0x84, cmd); - - /* Errata 66 - * Limit the number of downstream posted requests to 1 - */ - cmd = pci_read_config32(dev, 0x70); - if ((cmd & (3 << 0)) != 2) { - cmd &= ~(3<<0); - cmd |= (2<<0); - pci_write_config32(dev, 0x70, cmd); - needs_reset = 1; - } - cmd = pci_read_config32(dev, 0x7c); - if ((cmd & (3 << 4)) != 0) { - cmd &= ~(3<<4); - cmd |= (0<<4); - pci_write_config32(dev, 0x7c, cmd); - needs_reset = 1; - } - /* Clock Power/Timing Low */ - cmd = pci_read_config32(dev, 0xd4); - if (cmd != 0x000D0001) { - cmd = 0x000D0001; - pci_write_config32(dev, 0xd4, cmd); - needs_reset = 1; /* Needed? */ - } - } - else if (is_cpu_pre_d0()) { - struct device *f2_dev; - uint32_t dcl; - f2_dev = dev_find_slot(0, dev->path.pci.devfn - 3 + 2); - /* Errata 98 - * Set Clk Ramp Hystersis to 7 - * Clock Power/Timing Low - */ - cmd_ref = 0x04e20707; /* Registered */ - dcl = pci_read_config32(f2_dev, DRAM_CONFIG_LOW); - if (dcl & DCL_UnBuffDimm) { - cmd_ref = 0x000D0701; /* Unbuffered */ - } - cmd = pci_read_config32(dev, 0xd4); - if (cmd != cmd_ref) { - pci_write_config32(dev, 0xd4, cmd_ref); - needs_reset = 1; /* Needed? */ - } - } -#endif - /* Optimize the Link read pointers */ - f0_dev = dev_find_slot(0, dev->path.pci.devfn - 3); - if (f0_dev) { - int link; - cmd_ref = cmd = pci_read_config32(dev, 0xdc); - for (link = 0; link < 3; link++) { - uint32_t link_type; - unsigned reg; - /* This works on an Athlon64 because unimplemented links return 0 */ - reg = 0x98 + (link * 0x20); - link_type = pci_read_config32(f0_dev, reg); - /* Only handle coherent link here please */ - if ((link_type & (LinkConnected|InitComplete|NonCoherent)) - == (LinkConnected|InitComplete)) - { - cmd &= ~(0xff << (link *8)); - /* FIXME this assumes the device on the other side is an AMD device */ - cmd |= 0x25 << (link *8); - } - } - if (cmd != cmd_ref) { - pci_write_config32(dev, 0xdc, cmd); - needs_reset = 1; - } - } - else { - printk(BIOS_ERR, "Missing f0 device!\n"); - } - if (needs_reset) { - printk(BIOS_DEBUG, "resetting cpu\n"); - hard_reset(); - } - printk(BIOS_DEBUG, "done.\n"); -} - - -static struct device_operations mcf3_ops = { - .read_resources = mcf3_read_resources, - .set_resources = mcf3_set_resources, - .enable_resources = pci_dev_enable_resources, - .init = misc_control_init, - .scan_bus = 0, - .ops_pci = 0, -}; - -static const struct pci_driver mcf3_driver __pci_driver = { - .ops = &mcf3_ops, - .vendor = PCI_VENDOR_ID_AMD, - .device = 0x1103, -}; diff --git a/src/northbridge/amd/amdk8/northbridge.c b/src/northbridge/amd/amdk8/northbridge.c deleted file mode 100644 index ab6be96ddb..0000000000 --- a/src/northbridge/amd/amdk8/northbridge.c +++ /dev/null @@ -1,1288 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * 2004.12 yhlu add dual core support - * 2005.01 yhlu add support move apic before pci_domain in MB devicetree.cb - * 2005.02 yhlu add e0 memory hole support - * 2005.11 yhlu add put sb ht chain on bus 0 - * - * 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. - */ - -#include <console/console.h> -#include <arch/io.h> -#include <stdint.h> -#include <device/device.h> -#include <device/pci.h> -#include <device/pci_ids.h> -#include <device/hypertransport.h> -#include <stdlib.h> -#include <string.h> -#include <lib.h> -#include <cpu/cpu.h> -#if IS_ENABLED(CONFIG_HAVE_ACPI_TABLES) -#include <arch/acpi.h> -#include "acpi.h" -#endif - -#include <cpu/x86/lapic.h> -#include <cpu/amd/mtrr.h> - -#include <cpu/amd/multicore.h> -#if IS_ENABLED(CONFIG_LOGICAL_CPUS) -#include <pc80/mc146818rtc.h> -#endif - -#include "northbridge.h" - -#include "amdk8.h" - -#include <cpu/amd/model_fxx_rev.h> - -#include <cpu/amd/amdk8_sysconf.h> - -struct amdk8_sysconf_t sysconf; - -#define MAX_FX_DEVS 8 -static struct device *__f0_dev[MAX_FX_DEVS]; -static struct device *__f1_dev[MAX_FX_DEVS]; -static unsigned fx_devs = 0; - -static void get_fx_devs(void) -{ - int i; - for (i = 0; i < MAX_FX_DEVS; i++) { - __f0_dev[i] = dev_find_slot(0, PCI_DEVFN(0x18 + i, 0)); - __f1_dev[i] = dev_find_slot(0, PCI_DEVFN(0x18 + i, 1)); - if (__f0_dev[i] != NULL && __f1_dev[i] != NULL) - fx_devs = i+1; - } - if (__f1_dev[0] == NULL || __f0_dev[0] == NULL || fx_devs == 0) { - die("Cannot find 0:0x18.[0|1]\n"); - } -} - -static u32 f1_read_config32(unsigned reg) -{ - if (fx_devs == 0) - get_fx_devs(); - return pci_read_config32(__f1_dev[0], reg); -} - -static void f1_write_config32(unsigned reg, u32 value) -{ - int i; - if (fx_devs == 0) - get_fx_devs(); - for (i = 0; i < fx_devs; i++) { - struct device *dev; - dev = __f1_dev[i]; - if (dev && dev->enabled) { - pci_write_config32(dev, reg, value); - } - } -} - -typedef enum { - HT_ROUTE_CLOSE, - HT_ROUTE_SCAN, - HT_ROUTE_FINAL, -} scan_state; - -static void ht_route_link(struct bus *link, scan_state mode) -{ - struct device *dev = link->dev; - struct bus *parent = dev->bus; - u32 busses; - - if (mode == HT_ROUTE_SCAN) { - if (link->dev->bus->subordinate == 0) - link->secondary = 0; - else - link->secondary = parent->subordinate + 1; - - link->subordinate = link->secondary; - } - - /* Configure the bus numbers for this bridge: the configuration - * transactions will not be propagated by the bridge if it is - * not correctly configured - */ - busses = pci_read_config32(link->dev, link->cap + 0x14); - busses &= 0xff000000; - busses |= parent->secondary & 0xff; - if (mode == HT_ROUTE_CLOSE) { - busses |= 0xfeff << 8; - } else if (mode == HT_ROUTE_SCAN) { - busses |= ((u32) link->secondary & 0xff) << 8; - busses |= 0xff << 16; - } else if (mode == HT_ROUTE_FINAL) { - busses |= ((u32) link->secondary & 0xff) << 8; - busses |= ((u32) link->subordinate & 0xff) << 16; - } - pci_write_config32(link->dev, link->cap + 0x14, busses); - - if (mode == HT_ROUTE_FINAL) { - /* Second chain will be on 0x40, third 0x80, forth 0xc0. */ - if (CONFIG_HT_CHAIN_DISTRIBUTE) - parent->subordinate = ALIGN_UP(link->subordinate, 0x40) - 1; - else - parent->subordinate = link->subordinate; - } -} - -static u32 amdk8_nodeid(struct device *dev) -{ - return (dev->path.pci.devfn >> 3) - 0x18; -} - -static void amdk8_scan_chain(struct bus *link) -{ - unsigned int next_unitid; - int index; - u32 config_busses; - u32 free_reg, config_reg; - u32 nodeid = amdk8_nodeid(link->dev); - - /* See if there is an available configuration space mapping - * register in function 1. - */ - free_reg = 0; - for (config_reg = 0xe0; config_reg <= 0xec; config_reg += 4) { - u32 config; - config = f1_read_config32(config_reg); - if (!free_reg && ((config & 3) == 0)) { - free_reg = config_reg; - continue; - } - if (((config & 3) == 3) && - (((config >> 4) & 7) == nodeid) && - (((config >> 8) & 3) == link->link_num)) { - break; - } - } - if (free_reg && (config_reg > 0xec)) { - config_reg = free_reg; - } - /* If we can't find an available configuration space mapping - * register skip this bus - */ - if (config_reg > 0xec) { - return; - } - - /* Set up the primary, secondary and subordinate bus numbers. - * We have no idea how many busses are behind this bridge yet, - * so we set the subordinate bus number to 0xff for the moment. - */ - - ht_route_link(link, HT_ROUTE_SCAN); - - config_busses = f1_read_config32(config_reg); - config_busses &= 0x000fc88; - config_busses |= - (3 << 0) | /* rw enable, no device compare */ - ((nodeid & 7) << 4) | - ((link->link_num & 3) << 8) | - ((link->secondary) << 16) | - (0xff << 24); - f1_write_config32(config_reg, config_busses); - - /* Now we can scan all of the subordinate busses i.e. the - * chain on the hypertranport link - */ - - next_unitid = hypertransport_scan_chain(link); - - /* Now that nothing is overlapping it is safe to scan the children. */ - pci_scan_bus(link, 0x00, ((next_unitid - 1) << 3) | 7); - - /* We know the number of busses behind this bridge. Set the - * subordinate bus number to it's real value - */ - - ht_route_link(link, HT_ROUTE_FINAL); - - config_busses = (config_busses & 0x00ffffff) | - (link->subordinate << 24); - f1_write_config32(config_reg, config_busses); - - index = (config_reg-0xe0) >> 2; - sysconf.hcdn_reg[index] = link->hcdn_reg; -} - -/* Do sb ht chain at first, in case s2885 put sb chain - * (8131/8111) on link2, but put 8151 on link0. - */ -static void relocate_sb_ht_chain(void) -{ - struct device *dev; - struct bus *link, *prev = NULL; - u8 sblink; - - dev = dev_find_slot(CONFIG_CBB, PCI_DEVFN(CONFIG_CDB, 0)); - sblink = (pci_read_config32(dev, 0x64)>>8) & 3; - link = dev->link_list; - - while (link) { - if (link->link_num == sblink) { - if (!prev) - return; - prev->next = link->next; - link->next = dev->link_list; - dev->link_list = link; - return; - } - prev = link; - link = link->next; - } -} - -static void trim_ht_chain(struct device *dev) -{ - struct bus *link; - - /* Check for connected links. */ - for (link = dev->link_list; link; link = link->next) { - link->cap = 0x80 + (link->link_num * 0x20); - link->ht_link_up = ht_is_non_coherent_link(link); - } -} - -static void amdk8_scan_chains(struct device *dev) -{ - struct bus *link; - - trim_ht_chain(dev); - - for (link = dev->link_list; link; link = link->next) { - if (link->ht_link_up) - amdk8_scan_chain(link); - } -} - - -static int reg_useable(unsigned reg, struct device *goal_dev, - unsigned goal_nodeid, unsigned goal_link) -{ - struct resource *res; - unsigned nodeid, link = 0; - int result; - res = 0; - for (nodeid = 0; !res && (nodeid < fx_devs); nodeid++) { - struct device *dev; - dev = __f0_dev[nodeid]; - if (!dev) - continue; - for (link = 0; !res && (link < 3); link++) { - res = probe_resource(dev, IOINDEX(0x100 + reg, link)); - } - } - result = 2; - if (res) { - result = 0; - if ( (goal_link == (link - 1)) && - (goal_nodeid == (nodeid - 1)) && - (res->flags <= 1)) { - result = 1; - } - } - return result; -} - -static unsigned amdk8_find_reg(struct device *dev, unsigned nodeid, - unsigned link, unsigned min, unsigned max) -{ - unsigned resource; - unsigned free_reg, reg; - resource = 0; - free_reg = 0; - for (reg = min; reg <= max; reg += 0x8) { - int result; - result = reg_useable(reg, dev, nodeid, link); - if (result == 1) { - /* I have been allocated this one */ - break; - } - else if (result > 1) { - /* I have a free register pair */ - free_reg = reg; - } - } - if (reg > max) { - reg = free_reg; - } - if (reg > 0) { - resource = IOINDEX(0x100 + reg, link); - } - return resource; -} - -static unsigned amdk8_find_iopair(struct device *dev, unsigned nodeid, - unsigned link) -{ - return amdk8_find_reg(dev, nodeid, link, 0xc0, 0xd8); -} - -static unsigned amdk8_find_mempair(struct device *dev, unsigned nodeid, - unsigned link) -{ - return amdk8_find_reg(dev, nodeid, link, 0x80, 0xb8); -} - -static void amdk8_link_read_bases(struct device *dev, unsigned nodeid, - unsigned link) -{ - struct resource *resource; - - /* Initialize the io space constraints on the current bus */ - resource = new_resource(dev, IOINDEX(0, link)); - if (resource) { - resource->base = 0; - resource->size = 0; - resource->align = log2(HT_IO_HOST_ALIGN); - resource->gran = log2(HT_IO_HOST_ALIGN); - resource->limit = 0xffffUL; - resource->flags = IORESOURCE_IO | IORESOURCE_BRIDGE; - } - - /* Initialize the prefetchable memory constraints on the current bus */ - resource = new_resource(dev, IOINDEX(2, link)); - if (resource) { - resource->base = 0; - resource->size = 0; - resource->align = log2(HT_MEM_HOST_ALIGN); - resource->gran = log2(HT_MEM_HOST_ALIGN); - resource->limit = 0xffffffffffULL; - resource->flags = IORESOURCE_MEM | IORESOURCE_PREFETCH; - resource->flags |= IORESOURCE_BRIDGE; - } - - /* Initialize the memory constraints on the current bus */ - resource = new_resource(dev, IOINDEX(1, link)); - if (resource) { - resource->base = 0; - resource->size = 0; - resource->align = log2(HT_MEM_HOST_ALIGN); - resource->gran = log2(HT_MEM_HOST_ALIGN); - resource->limit = 0xffffffffULL; - resource->flags = IORESOURCE_MEM | IORESOURCE_BRIDGE; - } -} - -static void amdk8_create_vga_resource(struct device *dev, unsigned nodeid); - -static void amdk8_read_resources(struct device *dev) -{ - unsigned nodeid; - struct bus *link; - nodeid = amdk8_nodeid(dev); - for (link = dev->link_list; link; link = link->next) { - if (link->children) { - amdk8_link_read_bases(dev, nodeid, link->link_num); - } - } - amdk8_create_vga_resource(dev, nodeid); -} - -static void amdk8_set_resource(struct device *dev, struct resource *resource, - unsigned nodeid) -{ - struct bus *link; - resource_t rbase, rend; - unsigned reg, link_num; - char buf[50]; - - /* Make certain the resource has actually been set */ - if (!(resource->flags & IORESOURCE_ASSIGNED)) { - printk(BIOS_ERR, "%s: can't set unassigned resource @%lx %lx\n", - __func__, resource->index, resource->flags); - return; - } - - /* If I have already stored this resource don't worry about it */ - if (resource->flags & IORESOURCE_STORED) { - printk(BIOS_ERR, "%s: can't set stored resource @%lx %lx\n", __func__, - resource->index, resource->flags); - return; - } - - /* Only handle PCI memory and IO resources */ - if (!(resource->flags & (IORESOURCE_MEM | IORESOURCE_IO))) - return; - - /* Ensure I am actually looking at a resource of function 1 */ - if (resource->index < 0x100) { - return; - } - - if (resource->size == 0) - return; - - /* Get the base address */ - rbase = resource->base; - - /* Get the limit (rounded up) */ - rend = resource_end(resource); - - /* Get the register and link */ - reg = resource->index & 0xfc; - link_num = IOINDEX_LINK(resource->index); - - for (link = dev->link_list; link; link = link->next) - if (link->link_num == link_num) - break; - - if (link == NULL) { - printk(BIOS_ERR, "%s: can't find link %x for %lx\n", __func__, - link_num, resource->index); - return; - } - - if (resource->flags & IORESOURCE_IO) { - u32 base, limit; - base = f1_read_config32(reg); - limit = f1_read_config32(reg + 0x4); - base &= 0xfe000fcc; - base |= rbase & 0x01fff000; - base |= 3; - limit &= 0xfe000fc8; - limit |= rend & 0x01fff000; - limit |= (link_num & 3) << 4; - limit |= (nodeid & 7); - - if (link->bridge_ctrl & PCI_BRIDGE_CTL_VGA) { - printk(BIOS_SPEW, "%s, enabling legacy VGA IO forwarding for %s link 0x%x\n", - __func__, dev_path(dev), link_num); - base |= PCI_IO_BASE_VGA_EN; - } - if (link->bridge_ctrl & PCI_BRIDGE_CTL_NO_ISA) { - base |= PCI_IO_BASE_NO_ISA; - } - - f1_write_config32(reg + 0x4, limit); - f1_write_config32(reg, base); - } - else if (resource->flags & IORESOURCE_MEM) { - u32 base, limit; - base = f1_read_config32(reg); - limit = f1_read_config32(reg + 0x4); - base &= 0x000000f0; - base |= (rbase >> 8) & 0xffffff00; - base |= 3; - limit &= 0x00000048; - limit |= (rend >> 8) & 0xffffff00; - limit |= (link_num & 3) << 4; - limit |= (nodeid & 7); - f1_write_config32(reg + 0x4, limit); - f1_write_config32(reg, base); - } - resource->flags |= IORESOURCE_STORED; - snprintf(buf, sizeof(buf), " <node %x link %x>", - nodeid, link_num); - report_resource_stored(dev, resource, buf); -} - -static void amdk8_create_vga_resource(struct device *dev, unsigned nodeid) -{ - struct resource *resource; - struct bus *link; - - /* find out which link the VGA card is connected, - * we only deal with the 'first' vga card */ - for (link = dev->link_list; link; link = link->next) { - if (link->bridge_ctrl & PCI_BRIDGE_CTL_VGA) { -#if IS_ENABLED(CONFIG_MULTIPLE_VGA_ADAPTERS) - extern struct device *vga_pri; // the primary vga device, defined in device.c - printk(BIOS_DEBUG, "VGA: vga_pri bus num = %d link bus range [%d,%d]\n", vga_pri->bus->secondary, - link->secondary,link->subordinate); - /* We need to make sure the vga_pri is under the link */ - if ((vga_pri->bus->secondary >= link->secondary) && - (vga_pri->bus->secondary <= link->subordinate) - ) -#endif - break; - } - } - - /* no VGA card installed */ - if (link == NULL) - return; - - printk(BIOS_DEBUG, "VGA: %s (aka node %d) link %d has VGA device\n", dev_path(dev), nodeid, link->link_num); - - /* allocate a temp resource for the legacy VGA buffer */ - resource = new_resource(dev, IOINDEX(4, link->link_num)); - if (!resource) { - printk(BIOS_DEBUG, "VGA: %s out of resources.\n", dev_path(dev)); - return; - } - resource->base = 0xa0000; - resource->size = 0x20000; - resource->limit = 0xffffffff; - resource->flags = IORESOURCE_FIXED | IORESOURCE_MEM | - IORESOURCE_ASSIGNED; -} - -static void amdk8_set_resources(struct device *dev) -{ - unsigned nodeid; - struct bus *bus; - struct resource *res; - - /* Find the nodeid */ - nodeid = amdk8_nodeid(dev); - - /* Set each resource we have found */ - for (res = dev->resource_list; res; res = res->next) { - struct resource *old = NULL; - unsigned index; - - if (res->size == 0) /* No need to allocate registers. */ - continue; - - if (res->flags & IORESOURCE_IO) - index = amdk8_find_iopair(dev, nodeid, - IOINDEX_LINK(res->index)); - else - index = amdk8_find_mempair(dev, nodeid, - IOINDEX_LINK(res->index)); - - old = probe_resource(dev, index); - if (old) { - res->index = old->index; - old->index = 0; - old->flags = 0; - } - else - res->index = index; - - amdk8_set_resource(dev, res, nodeid); - } - - compact_resources(dev); - - for (bus = dev->link_list; bus; bus = bus->next) { - if (bus->children) { - assign_resources(bus); - } - } -} - -static void mcf0_control_init(struct device *dev) -{ -} - -static struct device_operations northbridge_operations = { - .read_resources = amdk8_read_resources, - .set_resources = amdk8_set_resources, - .enable_resources = pci_dev_enable_resources, -#if IS_ENABLED(CONFIG_HAVE_ACPI_TABLES) - .acpi_fill_ssdt_generator = k8acpi_write_vars, - .write_acpi_tables = northbridge_write_acpi_tables, -#endif - .init = mcf0_control_init, - .scan_bus = amdk8_scan_chains, - .enable = 0, - .ops_pci = 0, -}; - - -static const struct pci_driver mcf0_driver __pci_driver = { - .ops = &northbridge_operations, - .vendor = PCI_VENDOR_ID_AMD, - .device = 0x1100, -}; - -static void amdk8_nb_init(void *chip_info) -{ - relocate_sb_ht_chain(); -} - -struct chip_operations northbridge_amd_amdk8_ops = { - CHIP_NAME("AMD K8 Northbridge") - .enable_dev = 0, - .init = amdk8_nb_init, -}; - -static void amdk8_domain_read_resources(struct device *dev) -{ - unsigned reg; - - /* Find the already assigned resource pairs */ - get_fx_devs(); - for (reg = 0x80; reg <= 0xd8; reg+= 0x08) { - u32 base, limit; - base = f1_read_config32(reg); - limit = f1_read_config32(reg + 0x04); - /* Is this register allocated? */ - if ((base & 3) != 0) { - unsigned nodeid, reg_link; - struct device *reg_dev; - nodeid = limit & 7; - reg_link = (limit >> 4) & 3; - reg_dev = __f0_dev[nodeid]; - if (reg_dev) { - /* Reserve the resource */ - struct resource *res; - res = new_resource(reg_dev, IOINDEX(0x100 + reg, reg_link)); - if (res) { - res->base = base; - res->limit = limit; - res->flags = 1; - } - } - } - } - - pci_domain_read_resources(dev); -} - -static void my_tolm_test(void *gp, struct device *dev, struct resource *new) -{ - struct resource **best_p = gp; - struct resource *best; - best = *best_p; - /* Skip VGA. */ - if (!best || (best->base > new->base && new->base > 0xa0000)) { - best = new; - } - *best_p = best; -} - -static u32 my_find_pci_tolm(struct bus *bus) -{ - struct resource *min; - u32 tolm; - min = 0; - search_bus_resources(bus, IORESOURCE_MEM, IORESOURCE_MEM, my_tolm_test, &min); - tolm = 0xffffffffUL; - if (min && tolm > min->base) { - tolm = min->base; - } - return tolm; -} - -#if CONFIG_HW_MEM_HOLE_SIZEK != 0 - -struct hw_mem_hole_info { - unsigned hole_startk; - int node_id; -}; - -static struct hw_mem_hole_info get_hw_mem_hole_info(void) -{ - struct hw_mem_hole_info mem_hole; - int i; - - mem_hole.hole_startk = CONFIG_HW_MEM_HOLE_SIZEK; - mem_hole.node_id = -1; - - for (i = 0; i < fx_devs; i++) { - u32 base; - u32 hole; - base = f1_read_config32(0x40 + (i << 3)); - if ((base & ((1<<1)|(1<<0))) != ((1<<1)|(1<<0))) { - continue; - } - - hole = pci_read_config32(__f1_dev[i], 0xf0); - if (hole & 1) { // we find the hole - mem_hole.hole_startk = (hole & (0xff<<24)) >> 10; - mem_hole.node_id = i; // record the node No with hole - break; // only one hole - } - } - - /* We need to double check if there is special set on base reg and limit reg - * are not continuous instead of hole, it will find out its hole_startk. - */ - if (mem_hole.node_id==-1) { - u32 limitk_pri = 0; - for (i = 0; i < 8; i++) { - u32 base, limit; - unsigned base_k, limit_k; - base = f1_read_config32(0x40 + (i << 3)); - if ((base & ((1<<1)|(1<<0))) != ((1<<1)|(1<<0))) { - continue; - } - - base_k = (base & 0xffff0000) >> 2; - if (limitk_pri != base_k) { // we find the hole - mem_hole.hole_startk = limitk_pri; - mem_hole.node_id = i; - break; //only one hole - } - - limit = f1_read_config32(0x44 + (i << 3)); - limit_k = ((limit + 0x00010000) & 0xffff0000) >> 2; - limitk_pri = limit_k; - } - } - return mem_hole; -} - -static void disable_hoist_memory(unsigned long hole_startk, int node_id) -{ - int i; - struct device *dev; - u32 base, limit; - u32 hoist; - u32 hole_sizek; - - - //1. find which node has hole - //2. change limit in that node. - //3. change base and limit in later node - //4. clear that node f0 - - //if there is not mem hole enabled, we need to change it's base instead - - hole_sizek = (4*1024*1024) - hole_startk; - - for (i = 7; i > node_id; i--) { - - base = f1_read_config32(0x40 + (i << 3)); - if ((base & ((1<<1)|(1<<0))) != ((1<<1)|(1<<0))) { - continue; - } - limit = f1_read_config32(0x44 + (i << 3)); - f1_write_config32(0x44 + (i << 3),limit - (hole_sizek << 2)); - f1_write_config32(0x40 + (i << 3),base - (hole_sizek << 2)); - } - limit = f1_read_config32(0x44 + (node_id << 3)); - f1_write_config32(0x44 + (node_id << 3),limit - (hole_sizek << 2)); - dev = __f1_dev[node_id]; - if (dev == NULL) { - printk(BIOS_ERR, "%s: node %x is NULL!\n", __func__, node_id); - return; - } - hoist = pci_read_config32(dev, 0xf0); - if (hoist & 1) { - pci_write_config32(dev, 0xf0, 0); - } else { - base = pci_read_config32(dev, 0x40 + (node_id << 3)); - f1_write_config32(0x40 + (node_id << 3),base - (hole_sizek << 2)); - } -} - -static u32 hoist_memory(unsigned long hole_startk, int node_id) -{ - int i; - u32 carry_over; - struct device *dev; - u32 base, limit; - u32 basek; - u32 hoist; - - carry_over = (4*1024*1024) - hole_startk; - - for (i = 7; i > node_id; i--) { - - base = f1_read_config32(0x40 + (i << 3)); - if ((base & ((1<<1)|(1<<0))) != ((1<<1)|(1<<0))) { - continue; - } - limit = f1_read_config32(0x44 + (i << 3)); - f1_write_config32(0x44 + (i << 3),limit + (carry_over << 2)); - f1_write_config32(0x40 + (i << 3),base + (carry_over << 2)); - } - limit = f1_read_config32(0x44 + (node_id << 3)); - f1_write_config32(0x44 + (node_id << 3),limit + (carry_over << 2)); - dev = __f1_dev[node_id]; - base = pci_read_config32(dev, 0x40 + (node_id << 3)); - basek = (base & 0xffff0000) >> 2; - if (basek == hole_startk) { - //don't need set memhole here, because hole off set will be 0, overflow - //so need to change base reg instead, new basek will be 4*1024*1024 - base &= 0x0000ffff; - base |= (4*1024*1024)<<2; - f1_write_config32(0x40 + (node_id<<3), base); - } - else if (dev) - { - hoist = /* hole start address */ - ((hole_startk << 10) & 0xff000000) + - /* hole address to memory controller address */ - (((basek + carry_over) >> 6) & 0x0000ff00) + - /* enable */ - 1; - - pci_write_config32(dev, 0xf0, hoist); - } - - return carry_over; -} -#endif - -#include <cbmem.h> - -static void setup_uma_memory(void) -{ -#if IS_ENABLED(CONFIG_GFXUMA) - uint32_t topmem = (uint32_t) bsp_topmem(); - - switch (topmem) { - case 0x10000000: /* 256M system memory */ - uma_memory_size = 0x2000000; /* 32M recommended UMA */ - break; - - case 0x18000000: /* 384M system memory */ - uma_memory_size = 0x4000000; /* 64M recommended UMA */ - break; - - case 0x20000000: /* 512M system memory */ - uma_memory_size = 0x4000000; /* 64M recommended UMA */ - break; - - default: /* 1GB and above system memory */ - uma_memory_size = 0x8000000; /* 128M recommended UMA */ - break; - } - - uma_memory_base = topmem - uma_memory_size; /* TOP_MEM1 */ - printk(BIOS_INFO, "%s: uma size 0x%08llx, memory start 0x%08llx\n", - __func__, uma_memory_size, uma_memory_base); -#endif -} - -static void amdk8_domain_set_resources(struct device *dev) -{ - unsigned long mmio_basek; - u32 pci_tolm; - u64 ramtop = 0; - int i, idx; -#if CONFIG_HW_MEM_HOLE_SIZEK != 0 - struct hw_mem_hole_info mem_hole; - u32 reset_memhole = 1; -#endif - - pci_tolm = my_find_pci_tolm(dev->link_list); - - // FIXME handle interleaved nodes. If you fix this here, please fix - // amdfam10, too. - mmio_basek = pci_tolm >> 10; - /* Round mmio_basek to something the processor can support */ - mmio_basek &= ~((1 << 6) -1); - - // FIXME improve mtrr.c so we don't use up all of the mtrrs with a 64M - // MMIO hole. If you fix this here, please fix amdfam10, too. - /* Round the mmio hole to 64M */ - mmio_basek &= ~((64*1024) - 1); - -#if CONFIG_HW_MEM_HOLE_SIZEK != 0 - /* if the hw mem hole is already set in raminit stage, here we will compare mmio_basek and hole_basek - * if mmio_basek is bigger that hole_basek and will use hole_basek as mmio_basek and we don't need to reset hole. - * otherwise We reset the hole to the mmio_basek - */ - #if !IS_ENABLED(CONFIG_K8_REV_F_SUPPORT) - if (!is_cpu_pre_e0()) { - #endif - - mem_hole = get_hw_mem_hole_info(); - - if ((mem_hole.node_id != -1) && (mmio_basek > mem_hole.hole_startk)) { //We will use hole_basek as mmio_basek, and we don't need to reset hole anymore - mmio_basek = mem_hole.hole_startk; - reset_memhole = 0; - } - - if (reset_memhole) { - if (mem_hole.node_id!=-1) { // We need to select CONFIG_HW_MEM_HOLE_SIZEK for raminit, it can not make hole_startk to some basek too....! - // We need to reset our Mem Hole, because We want more big HOLE than we already set - //Before that We need to disable mem hole at first, becase memhole could already be set on i+1 instead - disable_hoist_memory(mem_hole.hole_startk, mem_hole.node_id); - } - - #if IS_ENABLED(CONFIG_HW_MEM_HOLE_SIZE_AUTO_INC) - //We need to double check if the mmio_basek is valid for hole setting, if it is equal to basek, we need to decrease it some - u32 basek_pri; - for (i = 0; i < fx_devs; i++) { - u32 base; - u32 basek; - base = f1_read_config32(0x40 + (i << 3)); - if ((base & ((1<<1)|(1<<0))) != ((1<<1)|(1<<0))) { - continue; - } - - basek = (base & 0xffff0000) >> 2; - if (mmio_basek == basek) { - mmio_basek -= (basek - basek_pri)>>1; // increase mem hole size to make sure it is on middle of pri node - break; - } - basek_pri = basek; - } - #endif - } - -#if !IS_ENABLED(CONFIG_K8_REV_F_SUPPORT) - } // is_cpu_pre_e0 -#endif - -#endif - - idx = 0x10; - for (i = 0; i < fx_devs; i++) { - u32 base, limit; - u32 basek, limitk, sizek; - base = f1_read_config32(0x40 + (i << 3)); - limit = f1_read_config32(0x44 + (i << 3)); - if ((base & ((1<<1)|(1<<0))) != ((1<<1)|(1<<0))) { - continue; - } - basek = (base & 0xffff0000) >> 2; - limitk = ((limit + 0x00010000) & 0xffff0000) >> 2; - sizek = limitk - basek; - - /* see if we need a hole from 0xa0000 to 0xbffff */ - if ((basek < ((8*64)+(8*16))) && (sizek > ((8*64)+(16*16)))) { - ram_resource(dev, (idx | i), basek, ((8*64)+(8*16)) - basek); - idx += 0x10; - basek = (8*64)+(16*16); - sizek = limitk - ((8*64)+(16*16)); - - } - - -#if IS_ENABLED(CONFIG_GFXUMA) - printk(BIOS_DEBUG, "node %d : uma_memory_base/1024=0x%08llx, mmio_basek=0x%08lx, basek=0x%08x, limitk=0x%08x\n", i, uma_memory_base >> 10, mmio_basek, basek, limitk); - if ((uma_memory_base >> 10) < mmio_basek) - printk(BIOS_ALERT, "node %d: UMA memory starts below mmio_basek\n", i); -#endif - - /* See if I need to split the region to accommodate pci memory space */ - if ((basek < 4*1024*1024) && (limitk > mmio_basek)) { - if (basek <= mmio_basek) { - unsigned pre_sizek; - pre_sizek = mmio_basek - basek; - if (pre_sizek > 0) { - ram_resource(dev, (idx | i), basek, pre_sizek); - idx += 0x10; - sizek -= pre_sizek; - if (!ramtop) - ramtop = mmio_basek * 1024; - } - #if CONFIG_HW_MEM_HOLE_SIZEK != 0 - if (reset_memhole) - #if !IS_ENABLED(CONFIG_K8_REV_F_SUPPORT) - if (!is_cpu_pre_e0()) - #endif - sizek += hoist_memory(mmio_basek,i); - #endif - - basek = mmio_basek; - } - if ((basek + sizek) <= 4*1024*1024) { - sizek = 0; - } - else { - basek = 4*1024*1024; - sizek -= (4*1024*1024 - mmio_basek); - } - } - - ram_resource(dev, (idx | i), basek, sizek); - idx += 0x10; - printk(BIOS_DEBUG, "%d: mmio_basek=%08lx, basek=%08x, limitk=%08x\n", - i, mmio_basek, basek, limitk); - if (!ramtop) - ramtop = limitk * 1024; - } - -#if IS_ENABLED(CONFIG_GFXUMA) - set_late_cbmem_top(uma_memory_base); - uma_resource(dev, 7, uma_memory_base >> 10, uma_memory_size >> 10); -#else - set_late_cbmem_top(ramtop); -#endif - assign_resources(dev->link_list); - -} - -static void amdk8_domain_scan_bus(struct device *dev) -{ - u32 reg; - int i; - struct bus *link = dev->link_list; - - /* Unmap all of the HT chains */ - for (reg = 0xe0; reg <= 0xec; reg += 4) { - f1_write_config32(reg, 0); - } - - link->secondary = dev->bus->subordinate; - pci_scan_bus(link, PCI_DEVFN(0x18, 0), 0xff); - dev->bus->subordinate = link->subordinate; - - /* Tune the hypertransport transaction for best performance. - * Including enabling relaxed ordering if it is safe. - */ - get_fx_devs(); - for (i = 0; i < fx_devs; i++) { - struct device *f0_dev; - f0_dev = __f0_dev[i]; - if (f0_dev && f0_dev->enabled) { - u32 httc; - httc = pci_read_config32(f0_dev, HT_TRANSACTION_CONTROL); - httc &= ~HTTC_RSP_PASS_PW; - if (!dev->link_list->disable_relaxed_ordering) { - httc |= HTTC_RSP_PASS_PW; - } - printk(BIOS_SPEW, "%s passpw: %s\n", - dev_path(dev), - (!dev->link_list->disable_relaxed_ordering)? - "enabled":"disabled"); - pci_write_config32(f0_dev, HT_TRANSACTION_CONTROL, httc); - } - } -} - -static struct device_operations pci_domain_ops = { - .read_resources = amdk8_domain_read_resources, - .set_resources = amdk8_domain_set_resources, - .enable_resources = NULL, - .init = NULL, - .scan_bus = amdk8_domain_scan_bus, -}; - -static void add_more_links(struct device *dev, unsigned total_links) -{ - struct bus *link, *last = NULL; - int link_num = -1; - - for (link = dev->link_list; link; link = link->next) { - if (link_num < link->link_num) - link_num = link->link_num; - last = link; - } - - if (last) { - int links = total_links - (link_num + 1); - if (links > 0) { - link = malloc(links*sizeof(*link)); - if (!link) - die("Couldn't allocate more links!\n"); - memset(link, 0, links*sizeof(*link)); - last->next = link; - } - } - else { - link = malloc(total_links*sizeof(*link)); - memset(link, 0, total_links*sizeof(*link)); - dev->link_list = link; - } - - for (link_num = link_num + 1; link_num < total_links; link_num++) { - link->link_num = link_num; - link->dev = dev; - link->next = link + 1; - last = link; - link = link->next; - } - last->next = NULL; -} - -static void remap_bsp_lapic(struct bus *cpu_bus) -{ - struct device_path cpu_path; - struct device *cpu; - u32 bsp_lapic_id = lapicid(); - - if (bsp_lapic_id) { - cpu_path.type = DEVICE_PATH_APIC; - cpu_path.apic.apic_id = 0; - cpu = find_dev_path(cpu_bus, &cpu_path); - if (cpu) - cpu->path.apic.apic_id = bsp_lapic_id; - } -} - -static void cpu_bus_scan(struct device *dev) -{ - struct bus *cpu_bus; - struct device *dev_mc; - int bsp_apicid; - int i,j; - unsigned nb_cfg_54; - unsigned siblings; - int e0_later_single_core; - int disable_siblings; - - nb_cfg_54 = 0; - sysconf.enabled_apic_ext_id = 0; - sysconf.lift_bsp_apicid = 0; - siblings = 0; - - /* Find the bootstrap processors apicid */ - bsp_apicid = lapicid(); - sysconf.apicid_offset = bsp_apicid; - - disable_siblings = !CONFIG_LOGICAL_CPUS; -#if IS_ENABLED(CONFIG_LOGICAL_CPUS) - get_option(&disable_siblings, "multi_core"); -#endif - - // for pre_e0, nb_cfg_54 can not be set, (when you read it still is 0) - // How can I get the nb_cfg_54 of every node's nb_cfg_54 in bsp??? - // and differ d0 and e0 single core - nb_cfg_54 = read_nb_cfg_54(); - - dev_mc = dev_find_slot(0, PCI_DEVFN(0x18, 0)); - if (!dev_mc) { - die("0:18.0 not found?"); - } - - sysconf.nodes = ((pci_read_config32(dev_mc, 0x60)>>4) & 7) + 1; - - - if (pci_read_config32(dev_mc, 0x68) & (HTTC_APIC_EXT_ID|HTTC_APIC_EXT_BRD_CST)) - { - sysconf.enabled_apic_ext_id = 1; - if (bsp_apicid == 0) { - /* bsp apic id is not changed */ - sysconf.apicid_offset = CONFIG_APIC_ID_OFFSET; - } else - { - sysconf.lift_bsp_apicid = 1; - } - - } - - /* Find which cpus are present */ - cpu_bus = dev->link_list; - - /* Always use the devicetree node with lapic_id 0 for BSP. */ - remap_bsp_lapic(cpu_bus); - - for (i = 0; i < sysconf.nodes; i++) { - struct device *cpu_dev; - - /* Find the cpu's pci device */ - cpu_dev = dev_find_slot(0, PCI_DEVFN(0x18 + i, 3)); - if (!cpu_dev) { - /* If I am probing things in a weird order - * ensure all of the cpu's pci devices are found. - */ - int local_j; - struct device *dev_f0; - for (local_j = 0; local_j <= 3; local_j++) { - cpu_dev = pci_probe_dev(NULL, dev_mc->bus, - PCI_DEVFN(0x18 + i, local_j)); - } - /* Ok, We need to set the links for that device. - * otherwise the device under it will not be scanned - */ - dev_f0 = dev_find_slot(0, PCI_DEVFN(0x18+i,0)); - if (dev_f0) { - add_more_links(dev_f0, 3); - } - } - - e0_later_single_core = 0; - int enable_node = cpu_dev && cpu_dev->enabled; - if (enable_node) { - j = pci_read_config32(cpu_dev, 0xe8); - j = (j >> 12) & 3; // dev is func 3 - printk(BIOS_DEBUG, " %s siblings=%d\n", dev_path(cpu_dev), j); - - if (nb_cfg_54) { - // For e0 single core if nb_cfg_54 is set, apicid will be 0, 2, 4.... - // ----> you can mixed single core e0 and dual core e0 at any sequence - // That is the typical case - - if (j == 0) { - #if !IS_ENABLED(CONFIG_K8_REV_F_SUPPORT) - e0_later_single_core = is_e0_later_in_bsp(i); // single core - #else - e0_later_single_core = is_cpu_f0_in_bsp(i); // We can read cpuid(1) from Func3 - #endif - } else { - e0_later_single_core = 0; - } - if (e0_later_single_core) { - printk(BIOS_DEBUG, "\tFound Rev E or Rev F later single core\n"); - - j = 1; - } - - if (siblings > j) { - } - else { - siblings = j; - } - } else { - siblings = j; - } - } - - u32 jj; - if (e0_later_single_core || disable_siblings) { - jj = 0; - } else - { - jj = siblings; - } - - for (j = 0; j <= jj; j++) { - u32 apic_id = i * (nb_cfg_54?(siblings+1):1) + j * (nb_cfg_54?1:8); - if (sysconf.enabled_apic_ext_id) { - if (apic_id != 0 || sysconf.lift_bsp_apicid) { - apic_id += sysconf.apicid_offset; - } - } - - struct device *cpu = add_cpu_device(cpu_bus, apic_id, - enable_node); - if (cpu) - amd_cpu_topology(cpu, i, j); - } //j - } -} - -static void cpu_bus_init(struct device *dev) -{ -#if IS_ENABLED(CONFIG_WAIT_BEFORE_CPUS_INIT) - cpus_ready_for_init(); -#endif - initialize_cpus(dev->link_list); -} - -static struct device_operations cpu_bus_ops = { - .read_resources = DEVICE_NOOP, - .set_resources = DEVICE_NOOP, - .enable_resources = DEVICE_NOOP, - .init = cpu_bus_init, - .scan_bus = cpu_bus_scan, -}; - -static void root_complex_enable_dev(struct device *dev) -{ - static int done = 0; - - /* Do not delay UMA setup, as a device on the PCI bus may evaluate - the global uma_memory variables already in its enable function. */ - if (!done) { - setup_bsp_ramtop(); - setup_uma_memory(); - done = 1; - } - - /* Set the operations if it is a special bus type */ - if (dev->path.type == DEVICE_PATH_DOMAIN) { - dev->ops = &pci_domain_ops; - } - else if (dev->path.type == DEVICE_PATH_CPU_CLUSTER) { - dev->ops = &cpu_bus_ops; - } -} - -struct chip_operations northbridge_amd_amdk8_root_complex_ops = { - CHIP_NAME("AMD K8 Root Complex") - .enable_dev = root_complex_enable_dev, -}; diff --git a/src/northbridge/amd/amdk8/northbridge.h b/src/northbridge/amd/amdk8/northbridge.h deleted file mode 100644 index 9fe434ac88..0000000000 --- a/src/northbridge/amd/amdk8/northbridge.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * 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. - */ - -#ifndef NORTHBRIDGE_AMD_AMDK8_H -#define NORTHBRIDGE_AMD_AMDK8_H - -extern unsigned int amdk8_scan_root_bus(struct device *root, unsigned int max); - -#endif /* NORTHBRIDGE_AMD_AMDK8_H */ diff --git a/src/northbridge/amd/amdk8/pre_f.h b/src/northbridge/amd/amdk8/pre_f.h deleted file mode 100644 index 1d2aaede1f..0000000000 --- a/src/northbridge/amd/amdk8/pre_f.h +++ /dev/null @@ -1,285 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * 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. - */ - -#ifndef AMDK8_PRE_F_H -#define AMDK8_PRE_F_H - -#include <compiler.h> - -/* Definitions of various K8 registers */ -/* Function 0 */ -#define HT_TRANSACTION_CONTROL 0x68 -#define HTTC_DIS_RD_B_P (1 << 0) -#define HTTC_DIS_RD_DW_P (1 << 1) -#define HTTC_DIS_WR_B_P (1 << 2) -#define HTTC_DIS_WR_DW_P (1 << 3) -#define HTTC_DIS_MTS (1 << 4) -#define HTTC_CPU1_EN (1 << 5) -#define HTTC_CPU_REQ_PASS_PW (1 << 6) -#define HTTC_CPU_RD_RSP_PASS_PW (1 << 7) -#define HTTC_DIS_P_MEM_C (1 << 8) -#define HTTC_DIS_RMT_MEM_C (1 << 9) -#define HTTC_DIS_FILL_P (1 << 10) -#define HTTC_RSP_PASS_PW (1 << 11) -#define HTTC_CHG_ISOC_TO_ORD (1 << 12) -#define HTTC_BUF_REL_PRI_SHIFT 13 -#define HTTC_BUF_REL_PRI_MASK 3 -#define HTTC_BUF_REL_PRI_64 0 -#define HTTC_BUF_REL_PRI_16 1 -#define HTTC_BUF_REL_PRI_8 2 -#define HTTC_BUF_REL_PRI_2 3 -#define HTTC_LIMIT_CLDT_CFG (1 << 15) -#define HTTC_LINT_EN (1 << 16) -#define HTTC_APIC_EXT_BRD_CST (1 << 17) -#define HTTC_APIC_EXT_ID (1 << 18) -#define HTTC_APIC_EXT_SPUR (1 << 19) -#define HTTC_SEQ_ID_SRC_NODE_EN (1 << 20) -#define HTTC_DS_NP_REQ_LIMIT_SHIFT 21 -#define HTTC_DS_NP_REQ_LIMIT_MASK 3 -#define HTTC_DS_NP_REQ_LIMIT_NONE 0 -#define HTTC_DS_NP_REQ_LIMIT_1 1 -#define HTTC_DS_NP_REQ_LIMIT_4 2 -#define HTTC_DS_NP_REQ_LIMIT_8 3 -#define HTTC_MED_PRI_BYP_CNT_SHIFT 24 -#define HTTC_MED_PRI_BYP_CNT_MASK 3 -#define HTTC_HI_PRI_BYP_CNT_SHIFT 26 -#define HTTC_HI_PRI_BYP_CNT_MASK 3 - - -/* Function 1 */ -#define PCI_IO_BASE0 0xc0 -#define PCI_IO_BASE1 0xc8 -#define PCI_IO_BASE2 0xd0 -#define PCI_IO_BASE3 0xd8 -#define PCI_IO_BASE_VGA_EN (1 << 4) -#define PCI_IO_BASE_NO_ISA (1 << 5) - - -/* Function 2 */ -#define DRAM_CSBASE 0x40 -#define DRAM_CSMASK 0x60 -#define DRAM_BANK_ADDR_MAP 0x80 - -#define DRAM_TIMING_LOW 0x88 -#define DTL_TCL_SHIFT 0 -#define DTL_TCL_MASK 0x7 -#define DTL_CL_2 1 -#define DTL_CL_3 2 -#define DTL_CL_2_5 5 -#define DTL_TRC_SHIFT 4 -#define DTL_TRC_MASK 0xf -#define DTL_TRC_BASE 7 -#define DTL_TRC_MIN 7 -#define DTL_TRC_MAX 22 -#define DTL_TRFC_SHIFT 8 -#define DTL_TRFC_MASK 0xf -#define DTL_TRFC_BASE 9 -#define DTL_TRFC_MIN 9 -#define DTL_TRFC_MAX 24 -#define DTL_TRCD_SHIFT 12 -#define DTL_TRCD_MASK 0x7 -#define DTL_TRCD_BASE 0 -#define DTL_TRCD_MIN 2 -#define DTL_TRCD_MAX 6 -#define DTL_TRRD_SHIFT 16 -#define DTL_TRRD_MASK 0x7 -#define DTL_TRRD_BASE 0 -#define DTL_TRRD_MIN 2 -#define DTL_TRRD_MAX 4 -#define DTL_TRAS_SHIFT 20 -#define DTL_TRAS_MASK 0xf -#define DTL_TRAS_BASE 0 -#define DTL_TRAS_MIN 5 -#define DTL_TRAS_MAX 15 -#define DTL_TRP_SHIFT 24 -#define DTL_TRP_MASK 0x7 -#define DTL_TRP_BASE 0 -#define DTL_TRP_MIN 2 -#define DTL_TRP_MAX 6 -#define DTL_TWR_SHIFT 28 -#define DTL_TWR_MASK 0x1 -#define DTL_TWR_BASE 2 -#define DTL_TWR_MIN 2 -#define DTL_TWR_MAX 3 - -#define DRAM_TIMING_HIGH 0x8c -#define DTH_TWTR_SHIFT 0 -#define DTH_TWTR_MASK 0x1 -#define DTH_TWTR_BASE 1 -#define DTH_TWTR_MIN 1 -#define DTH_TWTR_MAX 2 -#define DTH_TRWT_SHIFT 4 -#define DTH_TRWT_MASK 0x7 -#define DTH_TRWT_BASE 1 -#define DTH_TRWT_MIN 1 -#define DTH_TRWT_MAX 6 -#define DTH_TREF_SHIFT 8 -#define DTH_TREF_MASK 0x1f -#define DTH_TREF_100MHZ_4K 0x00 -#define DTH_TREF_133MHZ_4K 0x01 -#define DTH_TREF_166MHZ_4K 0x02 -#define DTH_TREF_200MHZ_4K 0x03 -#define DTH_TREF_100MHZ_8K 0x08 -#define DTH_TREF_133MHZ_8K 0x09 -#define DTH_TREF_166MHZ_8K 0x0A -#define DTH_TREF_200MHZ_8K 0x0B -#define DTH_TWCL_SHIFT 20 -#define DTH_TWCL_MASK 0x7 -#define DTH_TWCL_BASE 1 -#define DTH_TWCL_MIN 1 -#define DTH_TWCL_MAX 2 - -#define DRAM_CONFIG_LOW 0x90 -#define DCL_DLL_Disable (1<<0) -#define DCL_D_DRV (1<<1) -#define DCL_QFC_EN (1<<2) -#define DCL_DisDqsHys (1<<3) -#define DCL_Burst2Opt (1<<5) -#define DCL_DramInit (1<<8) -#define DCL_DualDIMMen (1<<9) -#define DCL_DramEnable (1<<10) -#define DCL_MemClrStatus (1<<11) -#define DCL_ESR (1<<12) -#define DCL_SRS (1<<13) -#define DCL_128BitEn (1<<16) -#define DCL_DimmEccEn (1<<17) -#define DCL_UnBuffDimm (1<<18) -#define DCL_32ByteEn (1<<19) -#define DCL_x4DIMM_SHIFT 20 -#define DCL_DisInRcvrs (1<<24) -#define DCL_BypMax_SHIFT 25 -#define DCL_En2T (1<<28) -#define DCL_UpperCSMap (1<<29) - -#define DRAM_CONFIG_HIGH 0x94 -#define DCH_ASYNC_LAT_SHIFT 0 -#define DCH_ASYNC_LAT_MASK 0xf -#define DCH_ASYNC_LAT_BASE 0 -#define DCH_ASYNC_LAT_MIN 0 -#define DCH_ASYNC_LAT_MAX 15 -#define DCH_RDPREAMBLE_SHIFT 8 -#define DCH_RDPREAMBLE_MASK 0xf -#define DCH_RDPREAMBLE_BASE ((2<<1)+0) /* 2.0 ns */ -#define DCH_RDPREAMBLE_MIN ((2<<1)+0) /* 2.0 ns */ -#define DCH_RDPREAMBLE_MAX ((9<<1)+1) /* 9.5 ns */ -#define DCH_IDLE_LIMIT_SHIFT 16 -#define DCH_IDLE_LIMIT_MASK 0x7 -#define DCH_IDLE_LIMIT_0 0 -#define DCH_IDLE_LIMIT_4 1 -#define DCH_IDLE_LIMIT_8 2 -#define DCH_IDLE_LIMIT_16 3 -#define DCH_IDLE_LIMIT_32 4 -#define DCH_IDLE_LIMIT_64 5 -#define DCH_IDLE_LIMIT_128 6 -#define DCH_IDLE_LIMIT_256 7 -#define DCH_DYN_IDLE_CTR_EN (1 << 19) -#define DCH_MEMCLK_SHIFT 20 -#define DCH_MEMCLK_MASK 0x7 -#define DCH_MEMCLK_100MHZ 0 -#define DCH_MEMCLK_133MHZ 2 -#define DCH_MEMCLK_166MHZ 5 -#define DCH_MEMCLK_200MHZ 7 -#define DCH_MEMCLK_VALID (1 << 25) -#define DCH_MEMCLK_EN0 (1 << 26) -#define DCH_MEMCLK_EN1 (1 << 27) -#define DCH_MEMCLK_EN2 (1 << 28) -#define DCH_MEMCLK_EN3 (1 << 29) - -/* Function 3 */ -#define MCA_NB_CONFIG 0x44 -#define MNC_ECC_EN (1 << 22) -#define MNC_CHIPKILL_EN (1 << 23) -#define SCRUB_CONTROL 0x58 -#define SCRUB_NONE 0 -#define SCRUB_40ns 1 -#define SCRUB_80ns 2 -#define SCRUB_160ns 3 -#define SCRUB_320ns 4 -#define SCRUB_640ns 5 -#define SCRUB_1_28us 6 -#define SCRUB_2_56us 7 -#define SCRUB_5_12us 8 -#define SCRUB_10_2us 9 -#define SCRUB_20_5us 10 -#define SCRUB_41_0us 11 -#define SCRUB_81_9us 12 -#define SCRUB_163_8us 13 -#define SCRUB_327_7us 14 -#define SCRUB_655_4us 15 -#define SCRUB_1_31ms 16 -#define SCRUB_2_62ms 17 -#define SCRUB_5_24ms 18 -#define SCRUB_10_49ms 19 -#define SCRUB_20_97ms 20 -#define SCRUB_42ms 21 -#define SCRUB_84ms 22 -#define SC_DRAM_SCRUB_RATE_SHFIT 0 -#define SC_DRAM_SCRUB_RATE_MASK 0x1f -#define SC_L2_SCRUB_RATE_SHIFT 8 -#define SC_L2_SCRUB_RATE_MASK 0x1f -#define SC_L1D_SCRUB_RATE_SHIFT 16 -#define SC_L1D_SCRUB_RATE_MASK 0x1f -#define SCRUB_ADDR_LOW 0x5C -#define SCRUB_ADDR_HIGH 0x60 -#define NORTHBRIDGE_CAP 0xE8 -#define NBCAP_128Bit (1 << 0) -#define NBCAP_MP (1 << 1) -#define NBCAP_BIG_MP (1 << 2) -#define NBCAP_ECC (1 << 3) -#define NBCAP_CHIPKILL_ECC (1 << 4) -#define NBCAP_MEMCLK_SHIFT 5 -#define NBCAP_MEMCLK_MASK 3 -#define NBCAP_MEMCLK_100MHZ 3 -#define NBCAP_MEMCLK_133MHZ 2 -#define NBCAP_MEMCLK_166MHZ 1 -#define NBCAP_MEMCLK_200MHZ 0 -#define NBCAP_MEMCTRL (1 << 8) - - -#define LinkConnected (1 << 0) -#define InitComplete (1 << 1) -#define NonCoherent (1 << 2) -#define ConnectionPending (1 << 4) - -#include "raminit.h" -//struct definitions - -struct link_pair_st { - pci_devfn_t udev; - uint32_t upos; - uint32_t uoffs; - pci_devfn_t dev; - uint32_t pos; - uint32_t offs; - -} __packed; - -struct sys_info { - uint8_t ctrl_present[NODE_NUMS]; - struct mem_controller ctrl[NODE_NUMS]; - - uint32_t nodes; - struct link_pair_st link_pair[16];// enough? only in_conherent - uint32_t link_pair_num; - uint32_t ht_c_num; - uint32_t sbdn; - uint32_t sblk; - uint32_t sbbusn; -} __packed; - -#ifdef __PRE_RAM__ -#include <arch/early_variables.h> -extern struct sys_info sysinfo_car; -#endif - -#endif /* AMDK8_PRE_F_H */ diff --git a/src/northbridge/amd/amdk8/raminit.c b/src/northbridge/amd/amdk8/raminit.c deleted file mode 100644 index ac1fced750..0000000000 --- a/src/northbridge/amd/amdk8/raminit.c +++ /dev/null @@ -1,2507 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * 2004.11 yhlu add 4 rank DIMM support - * 2004.12 yhlu add D0 support - * 2005.02 yhlu add E0 memory hole support - * - * 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. - */ - -#include <cpu/x86/cache.h> -#include <cpu/x86/lapic.h> -#include <cpu/x86/mtrr.h> -#include <cpu/x86/msr.h> -#include <cpu/amd/mtrr.h> -#include <lib.h> -#include <stdlib.h> -#include <arch/acpi.h> -#include <reset.h> -#include "raminit.h" -#include "amdk8.h" -#if IS_ENABLED(CONFIG_HAVE_OPTION_TABLE) -#include "option_table.h" -#endif - -#include <arch/early_variables.h> -struct sys_info sysinfo_car CAR_GLOBAL; - -void setup_resource_map(const unsigned int *register_values, int max) -{ - int i; - for (i = 0; i < max; i += 3) { - pci_devfn_t dev; - unsigned where; - unsigned long reg; - dev = register_values[i] & ~0xfff; - where = register_values[i] & 0xfff; - reg = pci_read_config32(dev, where); - reg &= register_values[i+1]; - reg |= register_values[i+2]; - pci_write_config32(dev, where, reg); - } -} - -static int controller_present(const struct mem_controller *ctrl) -{ - return pci_read_config32(ctrl->f0, 0) == 0x11001022; -} - -#if IS_ENABLED(CONFIG_RAMINIT_SYSINFO) -void sdram_set_registers(const struct mem_controller *ctrl, struct sys_info *sysinfo) -#else -void sdram_set_registers(const struct mem_controller *ctrl) -#endif -{ - static const unsigned int register_values[] = { - - /* Careful set limit registers before base registers which - contain the enables */ - /* DRAM Limit i Registers - * F1:0x44 i = 0 - * F1:0x4C i = 1 - * F1:0x54 i = 2 - * F1:0x5C i = 3 - * F1:0x64 i = 4 - * F1:0x6C i = 5 - * F1:0x74 i = 6 - * F1:0x7C i = 7 - * [ 2: 0] Destination Node ID - * 000 = Node 0 - * 001 = Node 1 - * 010 = Node 2 - * 011 = Node 3 - * 100 = Node 4 - * 101 = Node 5 - * 110 = Node 6 - * 111 = Node 7 - * [ 7: 3] Reserved - * [10: 8] Interleave select - * specifies the values of A[14:12] to use with interleave enable. - * [15:11] Reserved - * [31:16] DRAM Limit Address i Bits 39-24 - * This field defines the upper address bits of a 40 bit address - * that define the end of the DRAM region. - */ - PCI_ADDR(0, 0x18, 1, 0x44), 0x0000f8f8, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0x4C), 0x0000f8f8, 0x00000001, - PCI_ADDR(0, 0x18, 1, 0x54), 0x0000f8f8, 0x00000002, - PCI_ADDR(0, 0x18, 1, 0x5C), 0x0000f8f8, 0x00000003, - PCI_ADDR(0, 0x18, 1, 0x64), 0x0000f8f8, 0x00000004, - PCI_ADDR(0, 0x18, 1, 0x6C), 0x0000f8f8, 0x00000005, - PCI_ADDR(0, 0x18, 1, 0x74), 0x0000f8f8, 0x00000006, - PCI_ADDR(0, 0x18, 1, 0x7C), 0x0000f8f8, 0x00000007, - /* DRAM Base i Registers - * F1:0x40 i = 0 - * F1:0x48 i = 1 - * F1:0x50 i = 2 - * F1:0x58 i = 3 - * F1:0x60 i = 4 - * F1:0x68 i = 5 - * F1:0x70 i = 6 - * F1:0x78 i = 7 - * [ 0: 0] Read Enable - * 0 = Reads Disabled - * 1 = Reads Enabled - * [ 1: 1] Write Enable - * 0 = Writes Disabled - * 1 = Writes Enabled - * [ 7: 2] Reserved - * [10: 8] Interleave Enable - * 000 = No interleave - * 001 = Interleave on A[12] (2 nodes) - * 010 = reserved - * 011 = Interleave on A[12] and A[14] (4 nodes) - * 100 = reserved - * 101 = reserved - * 110 = reserved - * 111 = Interleve on A[12] and A[13] and A[14] (8 nodes) - * [15:11] Reserved - * [13:16] DRAM Base Address i Bits 39-24 - * This field defines the upper address bits of a 40-bit address - * that define the start of the DRAM region. - */ - PCI_ADDR(0, 0x18, 1, 0x40), 0x0000f8fc, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0x48), 0x0000f8fc, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0x50), 0x0000f8fc, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0x58), 0x0000f8fc, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0x60), 0x0000f8fc, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0x68), 0x0000f8fc, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0x70), 0x0000f8fc, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0x78), 0x0000f8fc, 0x00000000, - - /* DRAM CS Base Address i Registers - * F2:0x40 i = 0 - * F2:0x44 i = 1 - * F2:0x48 i = 2 - * F2:0x4C i = 3 - * F2:0x50 i = 4 - * F2:0x54 i = 5 - * F2:0x58 i = 6 - * F2:0x5C i = 7 - * [ 0: 0] Chip-Select Bank Enable - * 0 = Bank Disabled - * 1 = Bank Enabled - * [ 8: 1] Reserved - * [15: 9] Base Address (19-13) - * An optimization used when all DIMM are the same size... - * [20:16] Reserved - * [31:21] Base Address (35-25) - * This field defines the top 11 addresses bit of a 40-bit - * address that define the memory address space. These - * bits decode 32-MByte blocks of memory. - */ - PCI_ADDR(0, 0x18, 2, 0x40), 0x001f01fe, 0x00000000, - PCI_ADDR(0, 0x18, 2, 0x44), 0x001f01fe, 0x00000000, - PCI_ADDR(0, 0x18, 2, 0x48), 0x001f01fe, 0x00000000, - PCI_ADDR(0, 0x18, 2, 0x4C), 0x001f01fe, 0x00000000, - PCI_ADDR(0, 0x18, 2, 0x50), 0x001f01fe, 0x00000000, - PCI_ADDR(0, 0x18, 2, 0x54), 0x001f01fe, 0x00000000, - PCI_ADDR(0, 0x18, 2, 0x58), 0x001f01fe, 0x00000000, - PCI_ADDR(0, 0x18, 2, 0x5C), 0x001f01fe, 0x00000000, - /* DRAM CS Mask Address i Registers - * F2:0x60 i = 0 - * F2:0x64 i = 1 - * F2:0x68 i = 2 - * F2:0x6C i = 3 - * F2:0x70 i = 4 - * F2:0x74 i = 5 - * F2:0x78 i = 6 - * F2:0x7C i = 7 - * Select bits to exclude from comparison with the DRAM Base address register. - * [ 8: 0] Reserved - * [15: 9] Address Mask (19-13) - * Address to be excluded from the optimized case - * [20:16] Reserved - * [29:21] Address Mask (33-25) - * The bits with an address mask of 1 are excluded from address comparison - * [31:30] Reserved - * - */ - PCI_ADDR(0, 0x18, 2, 0x60), 0xC01f01ff, 0x00000000, - PCI_ADDR(0, 0x18, 2, 0x64), 0xC01f01ff, 0x00000000, - PCI_ADDR(0, 0x18, 2, 0x68), 0xC01f01ff, 0x00000000, - PCI_ADDR(0, 0x18, 2, 0x6C), 0xC01f01ff, 0x00000000, - PCI_ADDR(0, 0x18, 2, 0x70), 0xC01f01ff, 0x00000000, - PCI_ADDR(0, 0x18, 2, 0x74), 0xC01f01ff, 0x00000000, - PCI_ADDR(0, 0x18, 2, 0x78), 0xC01f01ff, 0x00000000, - PCI_ADDR(0, 0x18, 2, 0x7C), 0xC01f01ff, 0x00000000, - /* DRAM Bank Address Mapping Register - * F2:0x80 - * Specify the memory module size - * [ 2: 0] CS1/0 - * [ 6: 4] CS3/2 - * [10: 8] CS5/4 - * [14:12] CS7/6 - * 000 = 32Mbyte (Rows = 12 & Col = 8) - * 001 = 64Mbyte (Rows = 12 & Col = 9) - * 010 = 128Mbyte (Rows = 13 & Col = 9)|(Rows = 12 & Col = 10) - * 011 = 256Mbyte (Rows = 13 & Col = 10)|(Rows = 12 & Col = 11) - * 100 = 512Mbyte (Rows = 13 & Col = 11)|(Rows = 14 & Col = 10) - * 101 = 1Gbyte (Rows = 14 & Col = 11)|(Rows = 13 & Col = 12) - * 110 = 2Gbyte (Rows = 14 & Col = 12) - * 111 = reserved - * [ 3: 3] Reserved - * [ 7: 7] Reserved - * [11:11] Reserved - * [31:15] - */ - PCI_ADDR(0, 0x18, 2, 0x80), 0xffff8888, 0x00000000, - /* DRAM Timing Low Register - * F2:0x88 - * [ 2: 0] Tcl (Cas# Latency, Cas# to read-data-valid) - * 000 = reserved - * 001 = CL 2 - * 010 = CL 3 - * 011 = reserved - * 100 = reserved - * 101 = CL 2.5 - * 110 = reserved - * 111 = reserved - * [ 3: 3] Reserved - * [ 7: 4] Trc (Row Cycle Time, Ras#-active to Ras#-active/bank auto refresh) - * 0000 = 7 bus clocks - * 0001 = 8 bus clocks - * ... - * 1110 = 21 bus clocks - * 1111 = 22 bus clocks - * [11: 8] Trfc (Row refresh Cycle time, Auto-refresh-active to RAS#-active or RAS#auto-refresh) - * 0000 = 9 bus clocks - * 0010 = 10 bus clocks - * .... - * 1110 = 23 bus clocks - * 1111 = 24 bus clocks - * [14:12] Trcd (Ras#-active to Case#-read/write Delay) - * 000 = reserved - * 001 = reserved - * 010 = 2 bus clocks - * 011 = 3 bus clocks - * 100 = 4 bus clocks - * 101 = 5 bus clocks - * 110 = 6 bus clocks - * 111 = reserved - * [15:15] Reserved - * [18:16] Trrd (Ras# to Ras# Delay) - * 000 = reserved - * 001 = reserved - * 010 = 2 bus clocks - * 011 = 3 bus clocks - * 100 = 4 bus clocks - * 101 = reserved - * 110 = reserved - * 111 = reserved - * [19:19] Reserved - * [23:20] Tras (Minmum Ras# Active Time) - * 0000 to 0100 = reserved - * 0101 = 5 bus clocks - * ... - * 1111 = 15 bus clocks - * [26:24] Trp (Row Precharge Time) - * 000 = reserved - * 001 = reserved - * 010 = 2 bus clocks - * 011 = 3 bus clocks - * 100 = 4 bus clocks - * 101 = 5 bus clocks - * 110 = 6 bus clocks - * 111 = reserved - * [27:27] Reserved - * [28:28] Twr (Write Recovery Time) - * 0 = 2 bus clocks - * 1 = 3 bus clocks - * [31:29] Reserved - */ - PCI_ADDR(0, 0x18, 2, 0x88), 0xe8088008, 0x02522001 /* 0x03623125 */ , - /* DRAM Timing High Register - * F2:0x8C - * [ 0: 0] Twtr (Write to Read Delay) - * 0 = 1 bus Clocks - * 1 = 2 bus Clocks - * [ 3: 1] Reserved - * [ 6: 4] Trwt (Read to Write Delay) - * 000 = 1 bus clocks - * 001 = 2 bus clocks - * 010 = 3 bus clocks - * 011 = 4 bus clocks - * 100 = 5 bus clocks - * 101 = 6 bus clocks - * 110 = reserved - * 111 = reserved - * [ 7: 7] Reserved - * [12: 8] Tref (Refresh Rate) - * 00000 = 100MHz 4K rows - * 00001 = 133MHz 4K rows - * 00010 = 166MHz 4K rows - * 00011 = 200MHz 4K rows - * 01000 = 100MHz 8K/16K rows - * 01001 = 133MHz 8K/16K rows - * 01010 = 166MHz 8K/16K rows - * 01011 = 200MHz 8K/16K rows - * [19:13] Reserved - * [22:20] Twcl (Write CAS Latency) - * 000 = 1 Mem clock after CAS# (Unbuffered Dimms) - * 001 = 2 Mem clocks after CAS# (Registered Dimms) - * [31:23] Reserved - */ - PCI_ADDR(0, 0x18, 2, 0x8c), 0xff8fe08e, (0 << 20)|(0 << 8)|(0 << 4)|(0 << 0), - /* DRAM Config Low Register - * F2:0x90 - * [ 0: 0] DLL Disable - * 0 = Enabled - * 1 = Disabled - * [ 1: 1] D_DRV - * 0 = Normal Drive - * 1 = Weak Drive - * [ 2: 2] QFC_EN - * 0 = Disabled - * 1 = Enabled - * [ 3: 3] Disable DQS Hystersis (FIXME handle this one carefully) - * 0 = Enable DQS input filter - * 1 = Disable DQS input filtering - * [ 7: 4] Reserved - * [ 8: 8] DRAM_Init - * 0 = Initialization done or not yet started. - * 1 = Initiate DRAM intialization sequence - * [ 9: 9] SO-Dimm Enable - * 0 = Do nothing - * 1 = SO-Dimms present - * [10:10] DramEnable - * 0 = DRAM not enabled - * 1 = DRAM initialized and enabled - * [11:11] Memory Clear Status - * 0 = Memory Clear function has not completed - * 1 = Memory Clear function has completed - * [12:12] Exit Self-Refresh - * 0 = Exit from self-refresh done or not yet started - * 1 = DRAM exiting from self refresh - * [13:13] Self-Refresh Status - * 0 = Normal Operation - * 1 = Self-refresh mode active - * [15:14] Read/Write Queue Bypass Count - * 00 = 2 - * 01 = 4 - * 10 = 8 - * 11 = 16 - * [16:16] 128-bit/64-Bit - * 0 = 64bit Interface to DRAM - * 1 = 128bit Interface to DRAM - * [17:17] DIMM ECC Enable - * 0 = Some DIMMs do not have ECC - * 1 = ALL DIMMS have ECC bits - * [18:18] UnBuffered DIMMs - * 0 = Buffered DIMMS - * 1 = Unbuffered DIMMS - * [19:19] Enable 32-Byte Granularity - * 0 = Optimize for 64byte bursts - * 1 = Optimize for 32byte bursts - * [20:20] DIMM 0 is x4 - * [21:21] DIMM 1 is x4 - * [22:22] DIMM 2 is x4 - * [23:23] DIMM 3 is x4 - * 0 = DIMM is not x4 - * 1 = x4 DIMM present - * [24:24] Disable DRAM Receivers - * 0 = Receivers enabled - * 1 = Receivers disabled - * [27:25] Bypass Max - * 000 = Arbiters chois is always respected - * 001 = Oldest entry in DCQ can be bypassed 1 time - * 010 = Oldest entry in DCQ can be bypassed 2 times - * 011 = Oldest entry in DCQ can be bypassed 3 times - * 100 = Oldest entry in DCQ can be bypassed 4 times - * 101 = Oldest entry in DCQ can be bypassed 5 times - * 110 = Oldest entry in DCQ can be bypassed 6 times - * 111 = Oldest entry in DCQ can be bypassed 7 times - * [31:28] Reserved - */ - PCI_ADDR(0, 0x18, 2, 0x90), 0xf0000000, - (4 << 25)|(0 << 24)| - (0 << 23)|(0 << 22)|(0 << 21)|(0 << 20)| - (1 << 19)|(0 << 18)|(1 << 17)|(0 << 16)| - (2 << 14)|(0 << 13)|(0 << 12)| - (0 << 11)|(0 << 10)|(0 << 9)|(0 << 8)| - (0 << 3) |(0 << 1) |(0 << 0), - /* DRAM Config High Register - * F2:0x94 - * [ 0: 3] Maximum Asynchronous Latency - * 0000 = 0 ns - * ... - * 1111 = 15 ns - * [ 7: 4] Reserved - * [11: 8] Read Preamble - * 0000 = 2.0 ns - * 0001 = 2.5 ns - * 0010 = 3.0 ns - * 0011 = 3.5 ns - * 0100 = 4.0 ns - * 0101 = 4.5 ns - * 0110 = 5.0 ns - * 0111 = 5.5 ns - * 1000 = 6.0 ns - * 1001 = 6.5 ns - * 1010 = 7.0 ns - * 1011 = 7.5 ns - * 1100 = 8.0 ns - * 1101 = 8.5 ns - * 1110 = 9.0 ns - * 1111 = 9.5 ns - * [15:12] Reserved - * [18:16] Idle Cycle Limit - * 000 = 0 cycles - * 001 = 4 cycles - * 010 = 8 cycles - * 011 = 16 cycles - * 100 = 32 cycles - * 101 = 64 cycles - * 110 = 128 cycles - * 111 = 256 cycles - * [19:19] Dynamic Idle Cycle Center Enable - * 0 = Use Idle Cycle Limit - * 1 = Generate a dynamic Idle cycle limit - * [22:20] DRAM MEMCLK Frequency - * 000 = 100MHz - * 001 = reserved - * 010 = 133MHz - * 011 = reserved - * 100 = reserved - * 101 = 166MHz - * 110 = reserved - * 111 = reserved - * [24:23] Reserved - * [25:25] Memory Clock Ratio Valid (FIXME carefully enable memclk) - * 0 = Disable MemClks - * 1 = Enable MemClks - * [26:26] Memory Clock 0 Enable - * 0 = Disabled - * 1 = Enabled - * [27:27] Memory Clock 1 Enable - * 0 = Disabled - * 1 = Enabled - * [28:28] Memory Clock 2 Enable - * 0 = Disabled - * 1 = Enabled - * [29:29] Memory Clock 3 Enable - * 0 = Disabled - * 1 = Enabled - * [31:30] Reserved - */ - PCI_ADDR(0, 0x18, 2, 0x94), 0xc180f0f0, - (0 << 29)|(0 << 28)|(0 << 27)|(0 << 26)|(0 << 25)| - (0 << 20)|(0 << 19)|(DCH_IDLE_LIMIT_16 << 16)|(0 << 8)|(0 << 0), - /* DRAM Delay Line Register - * F2:0x98 - * Adjust the skew of the input DQS strobe relative to DATA - * [15: 0] Reserved - * [23:16] Delay Line Adjust - * Adjusts the DLL derived PDL delay by one or more delay stages - * in either the faster or slower direction. - * [24:24} Adjust Slower - * 0 = Do Nothing - * 1 = Adj is used to increase the PDL delay - * [25:25] Adjust Faster - * 0 = Do Nothing - * 1 = Adj is used to decrease the PDL delay - * [31:26] Reserved - */ - PCI_ADDR(0, 0x18, 2, 0x98), 0xfc00ffff, 0x00000000, - /* MCA NB Status Low reg */ - PCI_ADDR(0, 0x18, 3, 0x48), 0x00f00000, 0x00000000, - /* MCA NB Status high reg */ - PCI_ADDR(0, 0x18, 3, 0x4c), 0x01801e8c, 0x00000000, - /* MCA NB address Low reg */ - PCI_ADDR(0, 0x18, 3, 0x50), 0x00000007, 0x00000000, - /* MCA NB address high reg */ - PCI_ADDR(0, 0x18, 3, 0x54), 0xffffff00, 0x00000000, - /* DRAM Scrub Control Register - * F3:0x58 - * [ 4: 0] DRAM Scrube Rate - * [ 7: 5] reserved - * [12: 8] L2 Scrub Rate - * [15:13] reserved - * [20:16] Dcache Scrub - * [31:21] reserved - * Scrub Rates - * 00000 = Do not scrub - * 00001 = 40.00 ns - * 00010 = 80.00 ns - * 00011 = 160.00 ns - * 00100 = 320.00 ns - * 00101 = 640.00 ns - * 00110 = 1.28 us - * 00111 = 2.56 us - * 01000 = 5.12 us - * 01001 = 10.20 us - * 01011 = 41.00 us - * 01100 = 81.90 us - * 01101 = 163.80 us - * 01110 = 327.70 us - * 01111 = 655.40 us - * 10000 = 1.31 ms - * 10001 = 2.62 ms - * 10010 = 5.24 ms - * 10011 = 10.49 ms - * 10100 = 20.97 ms - * 10101 = 42.00 ms - * 10110 = 84.00 ms - * All Others = Reserved - */ - PCI_ADDR(0, 0x18, 3, 0x58), 0xffe0e0e0, 0x00000000, - /* DRAM Scrub Address Low Register - * F3:0x5C - * [ 0: 0] DRAM Scrubber Redirect Enable - * 0 = Do nothing - * 1 = Scrubber Corrects errors found in normal operation - * [ 5: 1] Reserved - * [31: 6] DRAM Scrub Address 31-6 - */ - PCI_ADDR(0, 0x18, 3, 0x5C), 0x0000003e, 0x00000000, - /* DRAM Scrub Address High Register - * F3:0x60 - * [ 7: 0] DRAM Scrubb Address 39-32 - * [31: 8] Reserved - */ - PCI_ADDR(0, 0x18, 3, 0x60), 0xffffff00, 0x00000000, - }; - int i; - int max; - - if (!controller_present(ctrl)) { - return; - } - printk(BIOS_SPEW, "setting up CPU%02x northbridge registers\n", ctrl->node_id); - max = ARRAY_SIZE(register_values); - for (i = 0; i < max; i += 3) { - pci_devfn_t dev; - unsigned where; - unsigned long reg; - dev = (register_values[i] & ~0xfff) - PCI_DEV(0, 0x18, 0) + ctrl->f0; - where = register_values[i] & 0xfff; - reg = pci_read_config32(dev, where); - reg &= register_values[i+1]; - reg |= register_values[i+2]; - pci_write_config32(dev, where, reg); - } - printk(BIOS_SPEW, "done.\n"); -} - -static void hw_enable_ecc(const struct mem_controller *ctrl) -{ - uint32_t dcl, nbcap; - nbcap = pci_read_config32(ctrl->f3, NORTHBRIDGE_CAP); - dcl = pci_read_config32(ctrl->f2, DRAM_CONFIG_LOW); - dcl &= ~DCL_DimmEccEn; - if (nbcap & NBCAP_ECC) { - dcl |= DCL_DimmEccEn; - } - if (read_option(ECC_memory, 1) == 0) { - dcl &= ~DCL_DimmEccEn; - } - pci_write_config32(ctrl->f2, DRAM_CONFIG_LOW, dcl); -} - -static int is_dual_channel(const struct mem_controller *ctrl) -{ - uint32_t dcl; - dcl = pci_read_config32(ctrl->f2, DRAM_CONFIG_LOW); - return dcl & DCL_128BitEn; -} - -static int is_opteron(const struct mem_controller *ctrl) -{ - /* Test to see if I am an Opteron. Socket 939 based Athlon64 - * have dual channel capability, too, so we need a better test - * for Opterons. - * However, all code uses is_opteron() to find out whether to - * use dual channel, so if we really check for opteron here, we - * need to fix up all code using this function, too. - */ - uint32_t nbcap; - nbcap = pci_read_config32(ctrl->f3, NORTHBRIDGE_CAP); - return !!(nbcap & NBCAP_128Bit); -} - -static int is_registered(const struct mem_controller *ctrl) -{ - /* Test to see if we are dealing with registered SDRAM. - * If we are not registered we are unbuffered. - * This function must be called after spd_handle_unbuffered_dimms. - */ - uint32_t dcl; - dcl = pci_read_config32(ctrl->f2, DRAM_CONFIG_LOW); - return !(dcl & DCL_UnBuffDimm); -} - -struct dimm_size { - unsigned long side1; - unsigned long side2; - unsigned long rows; - unsigned long col; -#if IS_ENABLED(CONFIG_QRANK_DIMM_SUPPORT) - unsigned long rank; -#endif -}; - -static struct dimm_size spd_get_dimm_size(unsigned device) -{ - /* Calculate the log base 2 size of a DIMM in bits */ - struct dimm_size sz; - int value, low; - sz.side1 = 0; - sz.side2 = 0; - sz.rows = 0; - sz.col = 0; -#if IS_ENABLED(CONFIG_QRANK_DIMM_SUPPORT) - sz.rank = 0; -#endif - - /* Note it might be easier to use byte 31 here, it has the DIMM size as - * a multiple of 4MB. The way we do it now we can size both - * sides of an assymetric dimm. - */ - value = spd_read_byte(device, 3); /* rows */ - if (value < 0) goto hw_err; - if ((value & 0xf) == 0) goto val_err; - sz.side1 += value & 0xf; - sz.rows = value & 0xf; - - value = spd_read_byte(device, 4); /* columns */ - if (value < 0) goto hw_err; - if ((value & 0xf) == 0) goto val_err; - sz.side1 += value & 0xf; - sz.col = value & 0xf; - - value = spd_read_byte(device, 17); /* banks */ - if (value < 0) goto hw_err; - if ((value & 0xff) == 0) goto val_err; - sz.side1 += log2(value & 0xff); - - /* Get the module data width and convert it to a power of two */ - value = spd_read_byte(device, 7); /* (high byte) */ - if (value < 0) goto hw_err; - value &= 0xff; - value <<= 8; - - low = spd_read_byte(device, 6); /* (low byte) */ - if (low < 0) goto hw_err; - value = value | (low & 0xff); - if ((value != 72) && (value != 64)) goto val_err; - sz.side1 += log2(value); - - /* side 2 */ - value = spd_read_byte(device, 5); /* number of physical banks */ - if (value < 0) goto hw_err; - if (value == 1) goto out; - if ((value != 2) && (value != 4)) { - goto val_err; - } -#if IS_ENABLED(CONFIG_QRANK_DIMM_SUPPORT) - sz.rank = value; -#endif - - /* Start with the symmetrical case */ - sz.side2 = sz.side1; - - value = spd_read_byte(device, 3); /* rows */ - if (value < 0) goto hw_err; - if ((value & 0xf0) == 0) goto out; /* If symmetrical we are done */ - sz.side2 -= (value & 0x0f); /* Subtract out rows on side 1 */ - sz.side2 += ((value >> 4) & 0x0f); /* Add in rows on side 2 */ - - value = spd_read_byte(device, 4); /* columns */ - if (value < 0) goto hw_err; - if ((value & 0xff) == 0) goto val_err; - sz.side2 -= (value & 0x0f); /* Subtract out columns on side 1 */ - sz.side2 += ((value >> 4) & 0x0f); /* Add in columsn on side 2 */ - - goto out; - - val_err: - die("Bad SPD value\n"); - /* If an hw_error occurs report that I have no memory */ -hw_err: - sz.side1 = 0; - sz.side2 = 0; - sz.rows = 0; - sz.col = 0; -#if IS_ENABLED(CONFIG_QRANK_DIMM_SUPPORT) - sz.rank = 0; -#endif -out: - return sz; -} - - -static void set_dimm_size(const struct mem_controller *ctrl, struct dimm_size sz, unsigned index) -{ - uint32_t base0, base1; - uint32_t dch; - - if (sz.side1 != sz.side2) { - sz.side2 = 0; - } - - /* For each base register. - * Place the dimm size in 32 MB quantities in the bits 31 - 21. - * The initialize dimm size is in bits. - * Set the base enable bit0. - */ - - base0 = base1 = 0; - - /* Make certain side1 of the dimm is at least 32MB */ - if (sz.side1 >= (25 +3)) { - base0 = (1 << ((sz.side1 - (25 + 3)) + 21)) | 1; - } - - /* Make certain side2 of the dimm is at least 32MB */ - if (sz.side2 >= (25 + 3)) { - base1 = (1 << ((sz.side2 - (25 + 3)) + 21)) | 1; - } - - /* Double the size if we are using dual channel memory */ - if (is_dual_channel(ctrl)) { - base0 = (base0 << 1) | (base0 & 1); - base1 = (base1 << 1) | (base1 & 1); - } - - /* Clear the reserved bits */ - base0 &= ~0x001ffffe; - base1 &= ~0x001ffffe; - - /* Set the appropriate DIMM base address register */ - pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1)+0)<<2), base0); - pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1)+1)<<2), base1); -#if IS_ENABLED(CONFIG_QRANK_DIMM_SUPPORT) - if (sz.rank == 4) { - pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1)+4)<<2), base0); - pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1)+5)<<2), base1); - } -#endif - - /* Enable the memory clocks for this DIMM */ - if (base0) { - dch = pci_read_config32(ctrl->f2, DRAM_CONFIG_HIGH); - dch |= DCH_MEMCLK_EN0 << index; -#if IS_ENABLED(CONFIG_QRANK_DIMM_SUPPORT) - if (sz.rank == 4) { - dch |= DCH_MEMCLK_EN0 << (index + 2); - } -#endif - pci_write_config32(ctrl->f2, DRAM_CONFIG_HIGH, dch); - } -} - -static void set_dimm_map(const struct mem_controller *ctrl, struct dimm_size sz, unsigned index) -{ - static const unsigned cs_map_aa[] = { - /* (row=12, col=8)(14, 12) ---> (0, 0) (2, 4) */ - 0, 1, 3, 6, 0, - 0, 2, 4, 7, 9, - 0, 0, 5, 8,10, - }; - - uint32_t map; - - map = pci_read_config32(ctrl->f2, DRAM_BANK_ADDR_MAP); - map &= ~(0xf << (index * 4)); -#if IS_ENABLED(CONFIG_QRANK_DIMM_SUPPORT) - if (sz.rank == 4) { - map &= ~(0xf << ((index + 2) * 4)); - } -#endif - - - /* Make certain side1 of the dimm is at least 32MB */ - if (sz.side1 >= (25 +3)) { - if (is_cpu_pre_d0()) { - map |= (sz.side1 - (25 + 3)) << (index *4); -#if IS_ENABLED(CONFIG_QRANK_DIMM_SUPPORT) - if (sz.rank == 4) { - map |= (sz.side1 - (25 + 3)) << ((index + 2) * 4); - } -#endif - } - else { - map |= cs_map_aa[(sz.rows - 12) * 5 + (sz.col - 8) ] << (index*4); -#if IS_ENABLED(CONFIG_QRANK_DIMM_SUPPORT) - if (sz.rank == 4) { - map |= cs_map_aa[(sz.rows - 12) * 5 + (sz.col - 8) ] << ((index + 2) * 4); - } -#endif - } - } - - pci_write_config32(ctrl->f2, DRAM_BANK_ADDR_MAP, map); - -} - -static long spd_set_ram_size(const struct mem_controller *ctrl, long dimm_mask) -{ - int i; - - for (i = 0; i < DIMM_SOCKETS; i++) { - struct dimm_size sz; - if (!(dimm_mask & (1 << i))) { - continue; - } - sz = spd_get_dimm_size(ctrl->channel0[i]); - if (sz.side1 == 0) { - return -1; /* Report SPD error */ - } - set_dimm_size(ctrl, sz, i); - set_dimm_map (ctrl, sz, i); - } - return dimm_mask; -} - -static void route_dram_accesses(const struct mem_controller *ctrl, - unsigned long base_k, unsigned long limit_k) -{ - /* Route the addresses to the controller node */ - unsigned node_id; - unsigned limit; - unsigned base; - unsigned index; - unsigned limit_reg, base_reg; - pci_devfn_t device; - - node_id = ctrl->node_id; - index = (node_id << 3); - limit = (limit_k << 2); - limit &= 0xffff0000; - limit -= 0x00010000; - limit |= (0 << 8) | (node_id << 0); - base = (base_k << 2); - base &= 0xffff0000; - base |= (0 << 8) | (1<<1) | (1<<0); - - limit_reg = 0x44 + index; - base_reg = 0x40 + index; - for (device = PCI_DEV(0, 0x18, 1); device <= PCI_DEV(0, 0x1f, 1); device += PCI_DEV(0, 1, 0)) { - pci_write_config32(device, limit_reg, limit); - pci_write_config32(device, base_reg, base); - } -} - -static void set_top_mem(unsigned tom_k, unsigned hole_startk) -{ - /* Error if I don't have memory */ - if (!tom_k) { - die("No memory?"); - } - - /* Report the amount of memory. */ - printk(BIOS_DEBUG, "RAM end at 0x%08x kB\n", tom_k); - - /* Now set top of memory */ - msr_t msr; - if (tom_k > (4*1024*1024)) { - printk(BIOS_SPEW, "Handling memory mapped above 4 GB\n"); - printk(BIOS_SPEW, "Upper RAM end at 0x%08x kB\n", tom_k); - msr.lo = (tom_k & 0x003fffff) << 10; - msr.hi = (tom_k & 0xffc00000) >> 22; - wrmsr(TOP_MEM2, msr); - printk(BIOS_SPEW, "Correcting memory amount mapped below 4 GB\n"); - } - - /* Leave a 64M hole between TOP_MEM and TOP_MEM2 - * so I can see my ROM chip and other I/O devices. - */ - if (tom_k >= 0x003f0000) { -#if CONFIG_HW_MEM_HOLE_SIZEK != 0 - if (hole_startk != 0) { - tom_k = hole_startk; - } else -#endif - tom_k = 0x3f0000; - printk(BIOS_SPEW, "Adjusting lower RAM end\n"); - } - printk(BIOS_SPEW, "Lower RAM end at 0x%08x kB\n", tom_k); - msr.lo = (tom_k & 0x003fffff) << 10; - msr.hi = (tom_k & 0xffc00000) >> 22; - wrmsr(TOP_MEM, msr); -} - -static unsigned long interleave_chip_selects(const struct mem_controller *ctrl) -{ - /* 35 - 25 */ - static const uint8_t csbase_low_shift[] = { - /* 32MB */ (13 - 4), - /* 64MB */ (14 - 4), - /* 128MB */ (14 - 4), - /* 256MB */ (15 - 4), - /* 512MB */ (15 - 4), - /* 1GB */ (16 - 4), - /* 2GB */ (16 - 4), - }; - - static const uint8_t csbase_low_d0_shift[] = { - /* 32MB */ (13 - 4), - /* 64MB */ (14 - 4), - /* 128MB */ (14 - 4), - /* 128MB */ (15 - 4), - /* 256MB */ (15 - 4), - /* 512MB */ (15 - 4), - /* 256MB */ (16 - 4), - /* 512MB */ (16 - 4), - /* 1GB */ (16 - 4), - /* 1GB */ (17 - 4), - /* 2GB */ (17 - 4), - }; - - /* cs_base_high is not changed */ - - uint32_t csbase_inc; - int chip_selects, index; - int bits; - unsigned common_size; - unsigned common_cs_mode; - uint32_t csbase, csmask; - - /* See if all of the memory chip selects are the same size - * and if so count them. - */ - chip_selects = 0; - common_size = 0; - common_cs_mode = 0; - for (index = 0; index < 8; index++) { - unsigned size; - unsigned cs_mode; - uint32_t value; - - value = pci_read_config32(ctrl->f2, DRAM_CSBASE + (index << 2)); - - /* Is it enabled? */ - if (!(value & 1)) { - continue; - } - chip_selects++; - size = value >> 21; - if (common_size == 0) { - common_size = size; - } - /* The size differed fail */ - if (common_size != size) { - return 0; - } - - value = pci_read_config32(ctrl->f2, DRAM_BANK_ADDR_MAP); - cs_mode =(value >> ((index>>1)*4)) & 0xf; - if (cs_mode == 0) continue; - if (common_cs_mode == 0) { - common_cs_mode = cs_mode; - } - /* The cs_mode differed fail */ - if (common_cs_mode != cs_mode) { - return 0; - } - } - - /* Chip selects can only be interleaved when there is - * more than one and their is a power of two of them. - */ - bits = log2(chip_selects); - if (((1 << bits) != chip_selects) || (bits < 1) || (bits > 3)) { - return 0; - } - - /* Find the bits of csbase that we need to interleave on */ - if (is_cpu_pre_d0()) { - csbase_inc = 1 << csbase_low_shift[common_cs_mode]; - if (is_dual_channel(ctrl)) { - /* Also we run out of address mask bits if we try and interleave 8 4GB dimms */ - if ((bits == 3) && (common_size == (1 << (32 - 3)))) { - return 0; - } - csbase_inc <<=1; - } - } - else { - csbase_inc = 1 << csbase_low_d0_shift[common_cs_mode]; - if (is_dual_channel(ctrl)) { - if ((bits == 3) && (common_cs_mode > 8)) { - return 0; - } - csbase_inc <<=1; - } - } - - /* Compute the initial values for csbase and csbask. - * In csbase just set the enable bit and the base to zero. - * In csmask set the mask bits for the size and page level interleave. - */ - csbase = 0 | 1; - csmask = (((common_size << bits) - 1) << 21); - csmask |= 0xfe00 & ~((csbase_inc << bits) - csbase_inc); - for (index = 0; index < 8; index++) { - uint32_t value; - - value = pci_read_config32(ctrl->f2, DRAM_CSBASE + (index << 2)); - /* Is it enabled? */ - if (!(value & 1)) { - continue; - } - pci_write_config32(ctrl->f2, DRAM_CSBASE + (index << 2), csbase); - pci_write_config32(ctrl->f2, DRAM_CSMASK + (index << 2), csmask); - csbase += csbase_inc; - } - - printk(BIOS_SPEW, "Interleaved\n"); - - /* Return the memory size in K */ - return common_size << (15 + bits); -} - -static unsigned long order_chip_selects(const struct mem_controller *ctrl) -{ - unsigned long tom; - - /* Remember which registers we have used in the high 8 bits of tom */ - tom = 0; - for (;;) { - /* Find the largest remaining candidate */ - unsigned index, candidate; - uint32_t csbase, csmask; - unsigned size; - csbase = 0; - candidate = 0; - for (index = 0; index < 8; index++) { - uint32_t value; - value = pci_read_config32(ctrl->f2, DRAM_CSBASE + (index << 2)); - - /* Is it enabled? */ - if (!(value & 1)) { - continue; - } - - /* Is it greater? */ - if (value <= csbase) { - continue; - } - - /* Has it already been selected */ - if (tom & (1 << (index + 24))) { - continue; - } - /* I have a new candidate */ - csbase = value; - candidate = index; - } - - /* See if I have found a new candidate */ - if (csbase == 0) { - break; - } - - /* Remember the dimm size */ - size = csbase >> 21; - - /* Remember I have used this register */ - tom |= (1 << (candidate + 24)); - - /* Recompute the cs base register value */ - csbase = (tom << 21) | 1; - - /* Increment the top of memory */ - tom += size; - - /* Compute the memory mask */ - csmask = ((size -1) << 21); - csmask |= 0xfe00; /* For now don't optimize */ - - /* Write the new base register */ - pci_write_config32(ctrl->f2, DRAM_CSBASE + (candidate << 2), csbase); - /* Write the new mask register */ - pci_write_config32(ctrl->f2, DRAM_CSMASK + (candidate << 2), csmask); - - } - /* Return the memory size in K */ - return (tom & ~0xff000000) << 15; -} - -static unsigned long memory_end_k(const struct mem_controller *ctrl, int max_node_id) -{ - unsigned node_id; - unsigned end_k; - /* Find the last memory address used */ - end_k = 0; - for (node_id = 0; node_id < max_node_id; node_id++) { - uint32_t limit, base; - unsigned index; - index = node_id << 3; - base = pci_read_config32(ctrl->f1, 0x40 + index); - /* Only look at the limit if the base is enabled */ - if ((base & 3) == 3) { - limit = pci_read_config32(ctrl->f1, 0x44 + index); - end_k = ((limit + 0x00010000) & 0xffff0000) >> 2; - } - } - return end_k; -} - -static void order_dimms(const struct mem_controller *ctrl) -{ - unsigned long tom_k, base_k; - - if (read_option(interleave_chip_selects, 1) != 0) { - tom_k = interleave_chip_selects(ctrl); - } else { - printk(BIOS_DEBUG, "Interleaving disabled\n"); - tom_k = 0; - } - - if (!tom_k) { - tom_k = order_chip_selects(ctrl); - } - - /* Compute the memory base address */ - base_k = memory_end_k(ctrl, ctrl->node_id); - tom_k += base_k; - route_dram_accesses(ctrl, base_k, tom_k); - set_top_mem(tom_k, 0); -} - -static long disable_dimm(const struct mem_controller *ctrl, unsigned index, long dimm_mask) -{ - printk(BIOS_DEBUG, "disabling dimm %02x\n", index); - pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1)+0)<<2), 0); - pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1)+1)<<2), 0); - dimm_mask &= ~(1 << index); - return dimm_mask; -} - -static long spd_handle_unbuffered_dimms(const struct mem_controller *ctrl, - long dimm_mask) -{ - int i; - int registered; - int unbuffered; - int has_dualch = is_opteron(ctrl); - uint32_t dcl; - unbuffered = 0; - registered = 0; - for (i = 0; (i < DIMM_SOCKETS); i++) { - int value; - if (!(dimm_mask & (1 << i))) { - continue; - } - value = spd_read_byte(ctrl->channel0[i], 21); - if (value < 0) { - return -1; - } - - /* Registered dimm ? */ - if (value & (1 << 1)) { - registered = 1; - } - /* Otherwise it must be an unbuffered dimm */ - else { - unbuffered = 1; - } - } - if (unbuffered && registered) { - die("Mixed buffered and registered dimms not supported"); - } - - dcl = pci_read_config32(ctrl->f2, DRAM_CONFIG_LOW); - dcl &= ~DCL_UnBuffDimm; - if (unbuffered) { - if ((has_dualch) && (!is_cpu_pre_d0())) { - dcl |= DCL_UnBuffDimm; -#if IS_ENABLED(CONFIG_CPU_AMD_SOCKET_939) - if ((cpuid_eax(1) & 0x30) == 0x30) { - /* CS[7:4] is copy of CS[3:0], should be set for 939 socket */ - dcl |= DCL_UpperCSMap; - } -#endif - } else { - dcl |= DCL_UnBuffDimm; - } - } - pci_write_config32(ctrl->f2, DRAM_CONFIG_LOW, dcl); - - if (is_registered(ctrl)) { - printk(BIOS_SPEW, "Registered\n"); - } else { - printk(BIOS_SPEW, "Unbuffered\n"); - } - - return dimm_mask; -} - -static unsigned int spd_detect_dimms(const struct mem_controller *ctrl) -{ - unsigned dimm_mask; - int i; - dimm_mask = 0; - for (i = 0; i < DIMM_SOCKETS; i++) { - int byte; - unsigned device; - device = ctrl->channel0[i]; - if (device) { - byte = spd_read_byte(ctrl->channel0[i], 2); /* Type */ - if (byte == 7) { - dimm_mask |= (1 << i); - } - } - device = ctrl->channel1[i]; - if (device) { - byte = spd_read_byte(ctrl->channel1[i], 2); - if (byte == 7) { - dimm_mask |= (1 << (i + DIMM_SOCKETS)); - } - } - } - return dimm_mask; -} - -static long spd_enable_2channels(const struct mem_controller *ctrl, long dimm_mask) -{ - int i; - uint32_t nbcap; - /* SPD addresses to verify are identical */ - static const uint8_t addresses[] = { - 2, /* Type should be DDR SDRAM */ - 3, /* *Row addresses */ - 4, /* *Column addresses */ - 5, /* *Physical Banks */ - 6, /* *Module Data Width low */ - 7, /* *Module Data Width high */ - 9, /* *Cycle time at highest CAS Latency CL = X */ - 11, /* *SDRAM Type */ - 13, /* *SDRAM Width */ - 17, /* *Logical Banks */ - 18, /* *Supported CAS Latencies */ - 21, /* *SDRAM Module Attributes */ - 23, /* *Cycle time at CAS Latency (CLX - 0.5) */ - 25, /* *Cycle time at CAS Latency (CLX - 1.0) */ - 27, /* *tRP Row precharge time */ - 28, /* *Minimum Row Active to Row Active Delay (tRRD) */ - 29, /* *tRCD RAS to CAS */ - 30, /* *tRAS Activate to Precharge */ - 41, /* *Minimum Active to Active/Auto Refresh Time(Trc) */ - 42, /* *Minimum Auto Refresh Command Time(Trfc) */ - }; - /* If the dimms are not in pairs do not do dual channels */ - if ((dimm_mask & ((1 << DIMM_SOCKETS) - 1)) != - ((dimm_mask >> DIMM_SOCKETS) & ((1 << DIMM_SOCKETS) - 1))) { - goto single_channel; - } - /* If the CPU is not capable of doing dual channels don't do dual channels */ - nbcap = pci_read_config32(ctrl->f3, NORTHBRIDGE_CAP); - if (!(nbcap & NBCAP_128Bit)) { - goto single_channel; - } - for (i = 0; (i < 4) && (ctrl->channel0[i]); i++) { - unsigned device0, device1; - int value0, value1; - int j; - /* If I don't have a dimm skip this one */ - if (!(dimm_mask & (1 << i))) { - continue; - } - device0 = ctrl->channel0[i]; - device1 = ctrl->channel1[i]; - for (j = 0; j < ARRAY_SIZE(addresses); j++) { - unsigned addr; - addr = addresses[j]; - value0 = spd_read_byte(device0, addr); - if (value0 < 0) { - return -1; - } - value1 = spd_read_byte(device1, addr); - if (value1 < 0) { - return -1; - } - if (value0 != value1) { - goto single_channel; - } - } - } - printk(BIOS_SPEW, "Enabling dual channel memory\n"); - uint32_t dcl; - dcl = pci_read_config32(ctrl->f2, DRAM_CONFIG_LOW); - dcl &= ~DCL_32ByteEn; - dcl |= DCL_128BitEn; - pci_write_config32(ctrl->f2, DRAM_CONFIG_LOW, dcl); - return dimm_mask; - single_channel: - dimm_mask &= ~((1 << (DIMM_SOCKETS *2)) - (1 << DIMM_SOCKETS)); - return dimm_mask; -} - -struct mem_param { - uint8_t cycle_time; - uint8_t divisor; /* In 1/2 ns increments */ - uint8_t tRC; - uint8_t tRFC; - uint32_t dch_memclk; - uint16_t dch_tref4k, dch_tref8k; - uint8_t dtl_twr; - uint8_t dtl_twtr; - uint8_t dtl_trwt[3][3]; /* first index is CAS_LAT 2/2.5/3 and 128/registered64/64 */ - uint8_t rdpreamble[4]; /* 0 is for registered, 1 for 1-2 DIMMS, 2 and 3 for 3 or 4 unreg dimm slots */ - char name[9]; -}; - -static const struct mem_param *get_mem_param(int freq) -{ - static const struct mem_param speed[] = { - [NBCAP_MEMCLK_100MHZ] = { - .name = "100MHz", - .cycle_time = 0xa0, - .divisor = (10 <<1), - .tRC = 0x46, - .tRFC = 0x50, - .dch_memclk = DCH_MEMCLK_100MHZ << DCH_MEMCLK_SHIFT, - .dch_tref4k = DTH_TREF_100MHZ_4K, - .dch_tref8k = DTH_TREF_100MHZ_8K, - .dtl_twr = 2, - .dtl_twtr = 1, - .dtl_trwt = { { 2, 2, 3 }, { 3, 3, 4 }, { 3, 3, 4 }}, - .rdpreamble = { ((9 << 1) + 0), ((9 << 1) + 0), ((9 << 1) + 0), ((9 << 1) + 0) } - }, - [NBCAP_MEMCLK_133MHZ] = { - .name = "133MHz", - .cycle_time = 0x75, - .divisor = (7<<1)+1, - .tRC = 0x41, - .tRFC = 0x4B, - .dch_memclk = DCH_MEMCLK_133MHZ << DCH_MEMCLK_SHIFT, - .dch_tref4k = DTH_TREF_133MHZ_4K, - .dch_tref8k = DTH_TREF_133MHZ_8K, - .dtl_twr = 2, - .dtl_twtr = 1, - .dtl_trwt = { { 2, 2, 3 }, { 3, 3, 4 }, { 3, 3, 4 }}, - .rdpreamble = { ((8 << 1) + 0), ((7 << 1) + 0), ((7 << 1) + 1), ((7 << 1) + 0) } - }, - [NBCAP_MEMCLK_166MHZ] = { - .name = "166MHz", - .cycle_time = 0x60, - .divisor = (6<<1), - .tRC = 0x3C, - .tRFC = 0x48, - .dch_memclk = DCH_MEMCLK_166MHZ << DCH_MEMCLK_SHIFT, - .dch_tref4k = DTH_TREF_166MHZ_4K, - .dch_tref8k = DTH_TREF_166MHZ_8K, - .dtl_twr = 3, - .dtl_twtr = 1, - .dtl_trwt = { { 3, 2, 3 }, { 3, 3, 4 }, { 4, 3, 4 }}, - .rdpreamble = { ((7 << 1) + 1), ((6 << 1) + 0), ((6 << 1) + 1), ((6 << 1) + 0) } - }, - [NBCAP_MEMCLK_200MHZ] = { - .name = "200MHz", - .cycle_time = 0x50, - .divisor = (5<<1), - .tRC = 0x37, - .tRFC = 0x46, - .dch_memclk = DCH_MEMCLK_200MHZ << DCH_MEMCLK_SHIFT, - .dch_tref4k = DTH_TREF_200MHZ_4K, - .dch_tref8k = DTH_TREF_200MHZ_8K, - .dtl_twr = 3, - .dtl_twtr = 2, - .dtl_trwt = { { 0, 2, 3 }, { 3, 3, 4 }, { 3, 3, 4 }}, - .rdpreamble = { ((7 << 1) + 0), ((5 << 1) + 0), ((5 << 1) + 1), ((5 << 1) + 1) } - } - }; - const struct mem_param *param; - - param = speed + freq; - printk(BIOS_SPEW, "%s\n", param->name); - return param; -} - -struct spd_set_memclk_result { - const struct mem_param *param; - long dimm_mask; -}; - -static int spd_dimm_loading_socket(const struct mem_controller *ctrl, long dimm_mask, int *freq_1t) -{ - -#if IS_ENABLED(CONFIG_CPU_AMD_SOCKET_939) - -/* + 1 raise so we detect 0 as bad field */ -#define DDR200 (NBCAP_MEMCLK_100MHZ + 1) -#define DDR333 (NBCAP_MEMCLK_166MHZ + 1) -#define DDR400 (NBCAP_MEMCLK_200MHZ + 1) -#define DDR_2T 0x80 -#define DDR_MASK 0x7 - -#define DDR200_2T (DDR_2T | DDR200) -#define DDR333_2T (DDR_2T | DDR333) -#define DDR400_2T (DDR_2T | DDR400) - -/* - Following table comes directly from BKDG (unbuffered DIMM support) - [Y][X] Y = ch0_0, ch1_0, ch0_1, ch1_1 1 = present 0 = empty - X uses same layout but 1 means double rank 0 is single rank/empty - - Following tables come from BKDG the ch{0_0,1_0,0_1,1_1} maps to - MEMCS_{1L,1H,2L,2H} in i the PDF. PreE is table 45, and revE table 46. -*/ - - static const unsigned char dimm_loading_config_preE[16][16] = { - [0x8] = {[0x0] = DDR400,[0x8] = DDR400}, - [0x2] = {[0x0] = DDR333,[0x2] = DDR400}, - [0xa] = {[0x0] = DDR400_2T,[0x2] = DDR400_2T, - [0x8] = DDR400_2T,[0xa] = DDR333_2T}, - [0xc] = {[0x0] = DDR400,[0xc] = DDR400}, - [0x3] = {[0x0] = DDR333,[0x3] = DDR400}, - [0xf] = {[0x0] = DDR400_2T,[0x3] = DDR400_2T, - [0xc] = DDR400_2T,[0xf] = DDR333_2T}, - }; - - static const unsigned char dimm_loading_config_revE[16][16] = { - [0x8] = {[0x0] = DDR400, [0x8] = DDR400}, - [0x2] = {[0x0] = DDR333, [0x2] = DDR400}, - [0x4] = {[0x0] = DDR400, [0x4] = DDR400}, - [0x1] = {[0x0] = DDR333, [0x1] = DDR400}, - [0xa] = {[0x0] = DDR400_2T, [0x2] = DDR400_2T, - [0x8] = DDR400_2T, [0xa] = DDR333_2T}, - [0x5] = {[0x0] = DDR400_2T, [0x1] = DDR400_2T, - [0x4] = DDR400_2T, [0x5] = DDR333_2T}, - [0xc] = {[0x0] = DDR400, [0xc] = DDR400, [0x4] = DDR400, [0x8] = DDR400}, - [0x3] = {[0x0] = DDR333, [0x1] = DDR333, [0x2] = DDR333, [0x3] = DDR400}, - [0xe] = {[0x0] = DDR400_2T, [0x4] = DDR400_2T, [0x2] = DDR400_2T, - [0x6] = DDR400_2T, [0x8] = DDR400_2T, [0xc] = DDR400_2T, - [0xa] = DDR333_2T, [0xe] = DDR333_2T}, - [0xb] = {[0x0] = DDR333, [0x1] = DDR400_2T, [0x2] = DDR333_2T, - [0x3] = DDR400_2T, [0x8] = DDR333_2T, [0x9] = DDR400_2T, - [0xa] = DDR333_2T, [0xb] = DDR333_2T}, - [0xd] = {[0x0] = DDR400_2T, [0x8] = DDR400_2T, [0x1] = DDR400_2T, - [0x9] = DDR333_2T, [0x4] = DDR400_2T, [0xc] = DDR400_2T, - [0x5] = DDR333_2T, [0xd] = DDR333_2T}, - [0x7] = {[0x0] = DDR333, [0x2] = DDR400_2T, [0x1] = DDR333_2T, - [0x3] = DDR400_2T, [0x4] = DDR333_2T, [0x6] = DDR400_2T, - [0x5] = DDR333_2T, [0x7] = DDR333_2T}, - [0xf] = {[0x0] = DDR400_2T, [0x1] = DDR400_2T, [0x4] = DDR400_2T, - [0x5] = DDR333_2T, [0x2] = DDR400_2T, [0x3] = DDR400_2T, - [0x6] = DDR400_2T, [0x7] = DDR333_2T, [0x8] = DDR400_2T, - [0x9] = DDR400_2T, [0xc] = DDR400_2T, [0xd] = DDR333_2T, - [0xa] = DDR333_2T, [0xb] = DDR333_2T, [0xe] = DDR333_2T, - [0xf] = DDR333_2T}, - }; - /*The dpos matches channel positions defined in BKDG and above arrays - The rpos is bitmask of dual rank dimms in same order as dpos */ - unsigned int dloading = 0, i, rpos = 0, dpos = 0; - const unsigned char (*dimm_loading_config)[16] = dimm_loading_config_revE; - int rank; - uint32_t dcl; - - if (is_cpu_pre_e0()) { - dimm_loading_config = dimm_loading_config_preE; - } - - /* only DIMMS two per channel */ - for (i = 0; i < 2; i++) { - if ((dimm_mask & (1 << i))) { - /* read rank channel 0 */ - rank = spd_read_byte(ctrl->channel0[i], 5); - if (rank < 0) goto hw_error; - rpos |= (rank == 2) ? (1 << (3 - (i * 2))) : 0; - dpos |= (1 << (3 - (i * 2))); - } - - if ((dimm_mask & (1 << (i+DIMM_SOCKETS)))) { - /* read rank channel 1*/ - rank = spd_read_byte(ctrl->channel1[i], 5); - if (rank < 0) goto hw_error; - rpos |= (rank == 2) ? (1 << (2 - (i * 2))) : 0; - dpos |= (1 << (2 - (i * 2))); - } - } - /* now the lookup, decode the max speed DDR400_2T etc */ - dloading = dimm_loading_config[dpos][rpos] & DDR_MASK; - -hw_error: - if (dloading != 0) { - /* we have valid combination check the restrictions */ - dcl = pci_read_config32(ctrl->f2, DRAM_CONFIG_LOW); - dcl |= ((dimm_loading_config[dpos][rpos] & DDR_2T) || CONFIG_K8_FORCE_2T_DRAM_TIMING) ? (DCL_En2T) : 0; - /* Set DuallDimm is second channel is completely empty (revD+) */ - if (((cpuid_eax(1) & 0xfff0f) >= 0x10f00) && ((dpos & 0x5) == 0)) { - printk(BIOS_DEBUG, "Setting DualDIMMen\n"); - dcl |= DCL_DualDIMMen; - } - pci_write_config32(ctrl->f2, DRAM_CONFIG_LOW, dcl); - return dloading - 1; - } else { - /* if we don't find it we se it to DDR400 */ - printk(BIOS_WARNING, "Detected strange DIMM configuration, may not work! (or bug)\n"); - return NBCAP_MEMCLK_200MHZ; - } - -#elif IS_ENABLED(CONFIG_CPU_AMD_SOCKET_754) - -#define CFGIDX(DIMM1,DIMM2,DIMM3) ((DIMM3)*9+(DIMM2)*3+(DIMM1)) - -#define EMPTY 0 -#define X8S_X16 1 -#define X8D 2 - -#define DDR200 NBCAP_MEMCLK_100MHZ -#define DDR333 NBCAP_MEMCLK_166MHZ -#define DDR400 NBCAP_MEMCLK_200MHZ - - /* this is table 42 from the BKDG, ignoring footnote 4, - * with the EMPTY, EMPTY, EMPTY row added */ - static const unsigned char cfgtable[][2] = { - [CFGIDX(EMPTY, EMPTY, EMPTY )] = { DDR400, DDR400 }, - [CFGIDX(X8S_X16, EMPTY, EMPTY )] = { DDR400, DDR400 }, - [CFGIDX(EMPTY, X8S_X16, EMPTY )] = { DDR400, DDR400 }, - [CFGIDX(EMPTY, EMPTY, X8S_X16 )] = { DDR400, DDR400 }, - [CFGIDX(X8D, EMPTY, EMPTY )] = { DDR400, DDR400 }, - [CFGIDX(EMPTY, X8D, EMPTY )] = { DDR400, DDR400 }, - [CFGIDX(EMPTY, EMPTY, X8D )] = { DDR400, DDR400 }, - [CFGIDX(X8S_X16, X8S_X16, EMPTY )] = { DDR400, DDR400 }, - [CFGIDX(X8S_X16, X8D, EMPTY )] = { DDR400, DDR400 }, - [CFGIDX(X8S_X16, EMPTY, X8S_X16 )] = { DDR400, DDR400 }, - [CFGIDX(X8S_X16, EMPTY, X8D )] = { DDR400, DDR400 }, - [CFGIDX(X8D, X8S_X16, EMPTY )] = { DDR400, DDR400 }, - [CFGIDX(X8D, X8D, EMPTY )] = { DDR333, DDR333 }, - [CFGIDX(X8D, EMPTY, X8S_X16 )] = { DDR400, DDR400 }, - [CFGIDX(X8D, EMPTY, X8D )] = { DDR333, DDR333 }, - [CFGIDX(EMPTY, X8S_X16, X8S_X16 )] = { DDR333, DDR400 }, - [CFGIDX(EMPTY, X8S_X16, X8D )] = { DDR200, DDR400 }, - [CFGIDX(EMPTY, X8D, X8S_X16 )] = { DDR200, DDR400 }, - [CFGIDX(EMPTY, X8D, X8D )] = { DDR200, DDR333 }, - [CFGIDX(X8S_X16, X8S_X16, X8S_X16 )] = { DDR333, DDR400 }, - [CFGIDX(X8S_X16, X8S_X16, X8D )] = { DDR200, DDR333 }, - [CFGIDX(X8S_X16, X8D, X8S_X16 )] = { DDR200, DDR333 }, - [CFGIDX(X8S_X16, X8D, X8D )] = { DDR200, DDR333 }, - [CFGIDX(X8D, X8S_X16, X8S_X16 )] = { DDR333, DDR333 }, - [CFGIDX(X8D, X8S_X16, X8D )] = { DDR200, DDR333 }, - [CFGIDX(X8D, X8D, X8S_X16 )] = { DDR200, DDR333 }, - [CFGIDX(X8D, X8D, X8D )] = { DDR200, DDR333 } - }; - - int i, rank, width, dimmtypes[3]; - const unsigned char *cfg; - - for (i = 0; i < 3; i++) { - if (dimm_mask & (1 << i)) { - rank = spd_read_byte(ctrl->channel0[i], 5); - width = spd_read_byte(ctrl->channel0[i], 13); - if (rank < 0 || width < 0) die("failed to read SPD"); - width &= 0x7f; - /* this is my guess as to how the criteria in the table - * are to be understood: - */ - dimmtypes[i] = width >= (rank == 1 ? 8 : 16) ? X8S_X16 : X8D; - } else { - dimmtypes[i] = EMPTY; - } - } - cfg = cfgtable[CFGIDX(dimmtypes[0], dimmtypes[1], dimmtypes[2])]; - *freq_1t = cfg[0]; - return is_cpu_c0() ? cfg[0] : cfg[1]; - -#else /* CONFIG_CPU_AMD_SOCKET_* */ - -/* well, there are socket 940 boards supported which obviously fail to - * compile with this */ -// #error load dependent memory clock limiting is not implemented for this socket - - /* see BKDG 4.1.3--if you just want to test a setup that doesn't - * require limiting, you may use the following code */ - - *freq_1t = NBCAP_MEMCLK_200MHZ; - return NBCAP_MEMCLK_200MHZ; - -#endif /* CONFIG_CPU_AMD_SOCKET_* */ - -} - -static struct spd_set_memclk_result spd_set_memclk(const struct mem_controller *ctrl, long dimm_mask) -{ - struct spd_set_memclk_result result; - unsigned char cl_at_freq[NBCAP_MEMCLK_MASK + 1]; - int dimm, freq, max_freq_bios, max_freq_dloading, max_freq_1t; - uint32_t value; - - static const uint8_t spd_min_cycle_time_indices[] = { 9, 23, 25 }; - static const unsigned char cycle_time_at_freq[] = { - [NBCAP_MEMCLK_200MHZ] = 0x50, /* 5ns */ - [NBCAP_MEMCLK_166MHZ] = 0x60, /* 6ns */ - [NBCAP_MEMCLK_133MHZ] = 0x75, /* 7.5ns */ - [NBCAP_MEMCLK_100MHZ] = 0xa0, /* 10ns */ - }; - - /* BEWARE that the constants for frequencies order in reverse of what - * would be intuitive. 200 MHz has the lowest constant, 100 MHz the - * highest. Thus, all comparisons and traversal directions having to - * do with frequencies are/have to be the opposite of what would be - * intuitive. - */ - - /* the CLs supported by the controller: */ - memset(cl_at_freq, 0x1c, sizeof(cl_at_freq)); - memset(cl_at_freq, 0x00, - (pci_read_config32(ctrl->f3, NORTHBRIDGE_CAP) >> - NBCAP_MEMCLK_SHIFT) & NBCAP_MEMCLK_MASK); - max_freq_bios = read_option(max_mem_clock, 0); - if (max_freq_bios <= NBCAP_MEMCLK_100MHZ) - memset(cl_at_freq, 0x00, max_freq_bios); - for (dimm = 0; dimm < DIMM_SOCKETS; dimm++) { - int x,i,spd_cls,cl,spd_min_cycle_time; - unsigned char cl_at_freq_mask[sizeof(cl_at_freq)]; - - if (!(dimm_mask & (1 << dimm))) - continue; - /* Byte 18 for DDR SDRAM is interpreted: - * bit 0 == CAS Latency = 1.0 - * bit 1 == CAS Latency = 1.5 - * bit 2 == CAS Latency = 2.0 - * bit 3 == CAS Latency = 2.5 - * bit 4 == CAS Latency = 3.0 - * bit 5 == CAS Latency = 3.5 - * bit 6 == CAS Latency = 4.0 - * bit 7 == TBD - */ - spd_cls = spd_read_byte(ctrl->channel0[dimm], 18); - if (spd_cls <= 0) - goto hw_error; - memset(cl_at_freq_mask, 0x00, sizeof(cl_at_freq_mask)); - for (cl = 1 << log2(spd_cls), i = 0; i < 3; cl >>= 1, i++) { - if (!(spd_cls & cl)) - continue; - spd_min_cycle_time = spd_read_byte(ctrl->channel0[dimm], - spd_min_cycle_time_indices[i]); - if (spd_min_cycle_time < 0) - goto hw_error; - if ((!spd_min_cycle_time) || (spd_min_cycle_time & 0x0f) > 9) - continue; - for (x = 0; x < sizeof(cl_at_freq_mask); x++) - if (cycle_time_at_freq[x] >= spd_min_cycle_time) - cl_at_freq_mask[x] |= cl; - } - for (x = 0; x < sizeof(cl_at_freq_mask); x++) - cl_at_freq[x] &= cl_at_freq_mask[x]; - } - - freq = NBCAP_MEMCLK_200MHZ; - while (freq < sizeof(cl_at_freq) && !cl_at_freq[freq]) - freq++; - - max_freq_dloading = spd_dimm_loading_socket(ctrl, dimm_mask, &max_freq_1t); - if (max_freq_dloading > freq) { - printk(BIOS_WARNING, "Memory speed reduced due to signal loading conditions\n"); - freq = max_freq_dloading; - while (freq < sizeof(cl_at_freq) && !cl_at_freq[freq]) - freq++; - } - - /* if the next lower frequency gives a CL at least one whole cycle - * shorter, select that (see end of BKDG 4.1.1.1) */ - if (freq < sizeof(cl_at_freq)-1 && cl_at_freq[freq+1] && - __ffs(cl_at_freq[freq]) - __ffs(cl_at_freq[freq+1]) >= 2) - freq++; - - if (freq == sizeof(cl_at_freq)) - goto hw_error; - -#if IS_ENABLED(CONFIG_CPU_AMD_SOCKET_754) - if (freq < max_freq_1t || CONFIG_K8_FORCE_2T_DRAM_TIMING) { - pci_write_config32(ctrl->f2, DRAM_CONFIG_LOW, - pci_read_config32(ctrl->f2, DRAM_CONFIG_LOW) | DCL_En2T); - } -#endif - - result.param = get_mem_param(freq); - - /* Update DRAM Config High with our selected memory speed */ - value = pci_read_config32(ctrl->f2, DRAM_CONFIG_HIGH); - value &= ~(DCH_MEMCLK_MASK << DCH_MEMCLK_SHIFT); - - value |= result.param->dch_memclk; - pci_write_config32(ctrl->f2, DRAM_CONFIG_HIGH, value); - - static const unsigned latencies[] = { DTL_CL_2, DTL_CL_2_5, DTL_CL_3 }; - - /* Update DRAM Timing Low with our selected cas latency */ - value = pci_read_config32(ctrl->f2, DRAM_TIMING_LOW); - value &= ~(DTL_TCL_MASK << DTL_TCL_SHIFT); - value |= latencies[__ffs(cl_at_freq[freq]) - 2] << DTL_TCL_SHIFT; - pci_write_config32(ctrl->f2, DRAM_TIMING_LOW, value); - - result.dimm_mask = dimm_mask; - return result; - hw_error: - result.param = (const struct mem_param *)0; - result.dimm_mask = -1; - return result; -} - - -static int update_dimm_Trc(const struct mem_controller *ctrl, const struct mem_param *param, int i) -{ - unsigned clocks, old_clocks; - uint32_t dtl; - int value; - value = spd_read_byte(ctrl->channel0[i], 41); - if (value < 0) return -1; - if ((value == 0) || (value == 0xff)) { - value = param->tRC; - } - clocks = CEIL_DIV((value << 1), param->divisor); - if (clocks < DTL_TRC_MIN) { - clocks = DTL_TRC_MIN; - } - if (clocks > DTL_TRC_MAX) { - return 0; - } - - dtl = pci_read_config32(ctrl->f2, DRAM_TIMING_LOW); - old_clocks = ((dtl >> DTL_TRC_SHIFT) & DTL_TRC_MASK) + DTL_TRC_BASE; - if (old_clocks > clocks) { - clocks = old_clocks; - } - dtl &= ~(DTL_TRC_MASK << DTL_TRC_SHIFT); - dtl |= ((clocks - DTL_TRC_BASE) << DTL_TRC_SHIFT); - pci_write_config32(ctrl->f2, DRAM_TIMING_LOW, dtl); - return 1; -} - -static int update_dimm_Trfc(const struct mem_controller *ctrl, const struct mem_param *param, int i) -{ - unsigned clocks, old_clocks; - uint32_t dtl; - int value; - value = spd_read_byte(ctrl->channel0[i], 42); - if (value < 0) return -1; - if ((value == 0) || (value == 0xff)) { - value = param->tRFC; - } - clocks = CEIL_DIV((value << 1), param->divisor); - if (clocks < DTL_TRFC_MIN) { - clocks = DTL_TRFC_MIN; - } - if (clocks > DTL_TRFC_MAX) { - return 0; - } - dtl = pci_read_config32(ctrl->f2, DRAM_TIMING_LOW); - old_clocks = ((dtl >> DTL_TRFC_SHIFT) & DTL_TRFC_MASK) + DTL_TRFC_BASE; - if (old_clocks > clocks) { - clocks = old_clocks; - } - dtl &= ~(DTL_TRFC_MASK << DTL_TRFC_SHIFT); - dtl |= ((clocks - DTL_TRFC_BASE) << DTL_TRFC_SHIFT); - pci_write_config32(ctrl->f2, DRAM_TIMING_LOW, dtl); - return 1; -} - - -static int update_dimm_Trcd(const struct mem_controller *ctrl, const struct mem_param *param, int i) -{ - unsigned clocks, old_clocks; - uint32_t dtl; - int value; - value = spd_read_byte(ctrl->channel0[i], 29); - if (value < 0) return -1; - clocks = CEIL_DIV(value, (param->divisor << 1)); - if (clocks < DTL_TRCD_MIN) { - clocks = DTL_TRCD_MIN; - } - if (clocks > DTL_TRCD_MAX) { - return 0; - } - dtl = pci_read_config32(ctrl->f2, DRAM_TIMING_LOW); - old_clocks = ((dtl >> DTL_TRCD_SHIFT) & DTL_TRCD_MASK) + DTL_TRCD_BASE; - if (old_clocks > clocks) { - clocks = old_clocks; - } - dtl &= ~(DTL_TRCD_MASK << DTL_TRCD_SHIFT); - dtl |= ((clocks - DTL_TRCD_BASE) << DTL_TRCD_SHIFT); - pci_write_config32(ctrl->f2, DRAM_TIMING_LOW, dtl); - return 1; -} - -static int update_dimm_Trrd(const struct mem_controller *ctrl, const struct mem_param *param, int i) -{ - unsigned clocks, old_clocks; - uint32_t dtl; - int value; - value = spd_read_byte(ctrl->channel0[i], 28); - if (value < 0) return -1; - clocks = CEIL_DIV(value, (param->divisor << 1)); - if (clocks < DTL_TRRD_MIN) { - clocks = DTL_TRRD_MIN; - } - if (clocks > DTL_TRRD_MAX) { - return 0; - } - dtl = pci_read_config32(ctrl->f2, DRAM_TIMING_LOW); - old_clocks = ((dtl >> DTL_TRRD_SHIFT) & DTL_TRRD_MASK) + DTL_TRRD_BASE; - if (old_clocks > clocks) { - clocks = old_clocks; - } - dtl &= ~(DTL_TRRD_MASK << DTL_TRRD_SHIFT); - dtl |= ((clocks - DTL_TRRD_BASE) << DTL_TRRD_SHIFT); - pci_write_config32(ctrl->f2, DRAM_TIMING_LOW, dtl); - return 1; -} - -static int update_dimm_Tras(const struct mem_controller *ctrl, const struct mem_param *param, int i) -{ - unsigned clocks, old_clocks; - uint32_t dtl; - int value; - value = spd_read_byte(ctrl->channel0[i], 30); - if (value < 0) return -1; - clocks = CEIL_DIV((value << 1), param->divisor); - if (clocks < DTL_TRAS_MIN) { - clocks = DTL_TRAS_MIN; - } - if (clocks > DTL_TRAS_MAX) { - return 0; - } - dtl = pci_read_config32(ctrl->f2, DRAM_TIMING_LOW); - old_clocks = ((dtl >> DTL_TRAS_SHIFT) & DTL_TRAS_MASK) + DTL_TRAS_BASE; - if (old_clocks > clocks) { - clocks = old_clocks; - } - dtl &= ~(DTL_TRAS_MASK << DTL_TRAS_SHIFT); - dtl |= ((clocks - DTL_TRAS_BASE) << DTL_TRAS_SHIFT); - pci_write_config32(ctrl->f2, DRAM_TIMING_LOW, dtl); - return 1; -} - -static int update_dimm_Trp(const struct mem_controller *ctrl, const struct mem_param *param, int i) -{ - unsigned clocks, old_clocks; - uint32_t dtl; - int value; - value = spd_read_byte(ctrl->channel0[i], 27); - if (value < 0) return -1; - clocks = CEIL_DIV(value, (param->divisor << 1)); - if (clocks < DTL_TRP_MIN) { - clocks = DTL_TRP_MIN; - } - if (clocks > DTL_TRP_MAX) { - return 0; - } - dtl = pci_read_config32(ctrl->f2, DRAM_TIMING_LOW); - old_clocks = ((dtl >> DTL_TRP_SHIFT) & DTL_TRP_MASK) + DTL_TRP_BASE; - if (old_clocks > clocks) { - clocks = old_clocks; - } - dtl &= ~(DTL_TRP_MASK << DTL_TRP_SHIFT); - dtl |= ((clocks - DTL_TRP_BASE) << DTL_TRP_SHIFT); - pci_write_config32(ctrl->f2, DRAM_TIMING_LOW, dtl); - return 1; -} - -static void set_Twr(const struct mem_controller *ctrl, const struct mem_param *param) -{ - uint32_t dtl; - dtl = pci_read_config32(ctrl->f2, DRAM_TIMING_LOW); - dtl &= ~(DTL_TWR_MASK << DTL_TWR_SHIFT); - dtl |= (param->dtl_twr - DTL_TWR_BASE) << DTL_TWR_SHIFT; - pci_write_config32(ctrl->f2, DRAM_TIMING_LOW, dtl); -} - - -static void init_Tref(const struct mem_controller *ctrl, const struct mem_param *param) -{ - uint32_t dth; - dth = pci_read_config32(ctrl->f2, DRAM_TIMING_HIGH); - dth &= ~(DTH_TREF_MASK << DTH_TREF_SHIFT); - dth |= (param->dch_tref4k << DTH_TREF_SHIFT); - pci_write_config32(ctrl->f2, DRAM_TIMING_HIGH, dth); -} - -static int update_dimm_Tref(const struct mem_controller *ctrl, const struct mem_param *param, int i) -{ - uint32_t dth; - int value; - unsigned tref, old_tref; - value = spd_read_byte(ctrl->channel0[i], 3); - if (value < 0) return -1; - value &= 0xf; - - tref = param->dch_tref8k; - if (value == 12) { - tref = param->dch_tref4k; - } - - dth = pci_read_config32(ctrl->f2, DRAM_TIMING_HIGH); - old_tref = (dth >> DTH_TREF_SHIFT) & DTH_TREF_MASK; - if ((value == 12) && (old_tref == param->dch_tref4k)) { - tref = param->dch_tref4k; - } else { - tref = param->dch_tref8k; - } - dth &= ~(DTH_TREF_MASK << DTH_TREF_SHIFT); - dth |= (tref << DTH_TREF_SHIFT); - pci_write_config32(ctrl->f2, DRAM_TIMING_HIGH, dth); - return 1; -} - - -static int update_dimm_x4(const struct mem_controller *ctrl, const struct mem_param *param, int i) -{ - uint32_t dcl; - int value; -#if IS_ENABLED(CONFIG_QRANK_DIMM_SUPPORT) - int rank; -#endif - int dimm; - value = spd_read_byte(ctrl->channel0[i], 13); - if (value < 0) { - return -1; - } - -#if IS_ENABLED(CONFIG_QRANK_DIMM_SUPPORT) - rank = spd_read_byte(ctrl->channel0[i], 5); /* number of physical banks */ - if (rank < 0) { - return -1; - } -#endif - - dimm = 1<<(DCL_x4DIMM_SHIFT+i); -#if IS_ENABLED(CONFIG_QRANK_DIMM_SUPPORT) - if (rank == 4) { - dimm |= 1<<(DCL_x4DIMM_SHIFT+i+2); - } -#endif - dcl = pci_read_config32(ctrl->f2, DRAM_CONFIG_LOW); - dcl &= ~dimm; - if (value == 4) { - dcl |= dimm; - } - pci_write_config32(ctrl->f2, DRAM_CONFIG_LOW, dcl); - return 1; -} - -static int update_dimm_ecc(const struct mem_controller *ctrl, const struct mem_param *param, int i) -{ - uint32_t dcl; - int value; - value = spd_read_byte(ctrl->channel0[i], 11); - if (value < 0) { - return -1; - } - if (value != 2) { - dcl = pci_read_config32(ctrl->f2, DRAM_CONFIG_LOW); - dcl &= ~DCL_DimmEccEn; - pci_write_config32(ctrl->f2, DRAM_CONFIG_LOW, dcl); - } - return 1; -} - -static int count_dimms(const struct mem_controller *ctrl) -{ - int dimms; - unsigned index; - dimms = 0; - for (index = 0; index < 8; index += 2) { - uint32_t csbase; - csbase = pci_read_config32(ctrl->f2, (DRAM_CSBASE + (index << 2))); - if (csbase & 1) { - dimms += 1; - } - } - return dimms; -} - -static void set_Twtr(const struct mem_controller *ctrl, const struct mem_param *param) -{ - uint32_t dth; - - dth = pci_read_config32(ctrl->f2, DRAM_TIMING_HIGH); - dth &= ~(DTH_TWTR_MASK << DTH_TWTR_SHIFT); - dth |= ((param->dtl_twtr - DTH_TWTR_BASE) << DTH_TWTR_SHIFT); - pci_write_config32(ctrl->f2, DRAM_TIMING_HIGH, dth); -} - -static void set_Trwt(const struct mem_controller *ctrl, const struct mem_param *param) -{ - uint32_t dth, dtl; - unsigned latency; - unsigned clocks; - int lat, mtype; - - clocks = 0; - dtl = pci_read_config32(ctrl->f2, DRAM_TIMING_LOW); - latency = (dtl >> DTL_TCL_SHIFT) & DTL_TCL_MASK; - - if (is_opteron(ctrl)) { - mtype = 0; /* dual channel */ - } else if (is_registered(ctrl)) { - mtype = 1; /* registered 64bit interface */ - } else { - mtype = 2; /* unbuffered 64bit interface */ - } - - switch (latency) { - case DTL_CL_2: - lat = 0; - break; - case DTL_CL_2_5: - lat = 1; - break; - case DTL_CL_3: - lat = 2; - break; - default: - die("Unknown LAT for Trwt"); - } - - clocks = param->dtl_trwt[lat][mtype]; - if ((clocks < DTH_TRWT_MIN) || (clocks > DTH_TRWT_MAX)) { - die("Unknown Trwt\n"); - } - - dth = pci_read_config32(ctrl->f2, DRAM_TIMING_HIGH); - dth &= ~(DTH_TRWT_MASK << DTH_TRWT_SHIFT); - dth |= ((clocks - DTH_TRWT_BASE) << DTH_TRWT_SHIFT); - pci_write_config32(ctrl->f2, DRAM_TIMING_HIGH, dth); - return; -} - -static void set_Twcl(const struct mem_controller *ctrl, const struct mem_param *param) -{ - /* Memory Clocks after CAS# */ - uint32_t dth; - unsigned clocks; - if (is_registered(ctrl)) { - clocks = 2; - } else { - clocks = 1; - } - dth = pci_read_config32(ctrl->f2, DRAM_TIMING_HIGH); - dth &= ~(DTH_TWCL_MASK << DTH_TWCL_SHIFT); - dth |= ((clocks - DTH_TWCL_BASE) << DTH_TWCL_SHIFT); - pci_write_config32(ctrl->f2, DRAM_TIMING_HIGH, dth); -} - - -static void set_read_preamble(const struct mem_controller *ctrl, const struct mem_param *param) -{ - uint32_t dch; - unsigned rdpreamble; - int slots, i; - - slots = 0; - - for (i = 0; i < 4; i++) { - if (ctrl->channel0[i]) { - slots += 1; - } - } - - /* map to index to param.rdpreamble array */ - if (is_registered(ctrl)) { - i = 0; - } else if (slots < 3) { - i = 1; - } else if (slots == 3) { - i = 2; - } else if (slots == 4) { - i = 3; - } else { - die("Unknown rdpreamble for this nr of slots"); - } - - dch = pci_read_config32(ctrl->f2, DRAM_CONFIG_HIGH); - dch &= ~(DCH_RDPREAMBLE_MASK << DCH_RDPREAMBLE_SHIFT); - rdpreamble = param->rdpreamble[i]; - - if ((rdpreamble < DCH_RDPREAMBLE_MIN) || (rdpreamble > DCH_RDPREAMBLE_MAX)) { - die("Unknown rdpreamble"); - } - - dch |= (rdpreamble - DCH_RDPREAMBLE_BASE) << DCH_RDPREAMBLE_SHIFT; - pci_write_config32(ctrl->f2, DRAM_CONFIG_HIGH, dch); -} - -static void set_max_async_latency(const struct mem_controller *ctrl, const struct mem_param *param) -{ - uint32_t dch; - unsigned async_lat; - int dimms; - - dimms = count_dimms(ctrl); - - dch = pci_read_config32(ctrl->f2, DRAM_CONFIG_HIGH); - dch &= ~(DCH_ASYNC_LAT_MASK << DCH_ASYNC_LAT_SHIFT); - async_lat = 0; - if (is_registered(ctrl)) { - if (dimms == 4) { - /* 9ns */ - async_lat = 9; - } - else { - /* 8ns */ - async_lat = 8; - } - } - else { - if (dimms > 3) { - die("Too many unbuffered dimms"); - } - else if (dimms == 3) { - /* 7ns */ - async_lat = 7; - } - else { - /* 6ns */ - async_lat = 6; - } - } - dch |= ((async_lat - DCH_ASYNC_LAT_BASE) << DCH_ASYNC_LAT_SHIFT); - pci_write_config32(ctrl->f2, DRAM_CONFIG_HIGH, dch); -} - -static void set_idle_cycle_limit(const struct mem_controller *ctrl, const struct mem_param *param) -{ - uint32_t dch; - /* AMD says to Hardcode this */ - dch = pci_read_config32(ctrl->f2, DRAM_CONFIG_HIGH); - dch &= ~(DCH_IDLE_LIMIT_MASK << DCH_IDLE_LIMIT_SHIFT); - dch |= DCH_IDLE_LIMIT_16 << DCH_IDLE_LIMIT_SHIFT; - dch |= DCH_DYN_IDLE_CTR_EN; - pci_write_config32(ctrl->f2, DRAM_CONFIG_HIGH, dch); -} - -static long spd_set_dram_timing(const struct mem_controller *ctrl, const struct mem_param *param, long dimm_mask) -{ - int i; - - init_Tref(ctrl, param); - for (i = 0; i < DIMM_SOCKETS; i++) { - int rc; - if (!(dimm_mask & (1 << i))) { - continue; - } - /* DRAM Timing Low Register */ - if ((rc = update_dimm_Trc (ctrl, param, i)) <= 0) goto dimm_err; - if ((rc = update_dimm_Trfc(ctrl, param, i)) <= 0) goto dimm_err; - if ((rc = update_dimm_Trcd(ctrl, param, i)) <= 0) goto dimm_err; - if ((rc = update_dimm_Trrd(ctrl, param, i)) <= 0) goto dimm_err; - if ((rc = update_dimm_Tras(ctrl, param, i)) <= 0) goto dimm_err; - if ((rc = update_dimm_Trp (ctrl, param, i)) <= 0) goto dimm_err; - - /* DRAM Timing High Register */ - if ((rc = update_dimm_Tref(ctrl, param, i)) <= 0) goto dimm_err; - - - /* DRAM Config Low */ - if ((rc = update_dimm_x4 (ctrl, param, i)) <= 0) goto dimm_err; - if ((rc = update_dimm_ecc(ctrl, param, i)) <= 0) goto dimm_err; - continue; - dimm_err: - if (rc < 0) { - return -1; - } - dimm_mask = disable_dimm(ctrl, i, dimm_mask); - } - /* DRAM Timing Low Register */ - set_Twr(ctrl, param); - - /* DRAM Timing High Register */ - set_Twtr(ctrl, param); - set_Trwt(ctrl, param); - set_Twcl(ctrl, param); - - /* DRAM Config High */ - set_read_preamble(ctrl, param); - set_max_async_latency(ctrl, param); - set_idle_cycle_limit(ctrl, param); - return dimm_mask; -} - -#if IS_ENABLED(CONFIG_RAMINIT_SYSINFO) -void sdram_set_spd_registers(const struct mem_controller *ctrl, struct sys_info *sysinfo) -#else -void sdram_set_spd_registers(const struct mem_controller *ctrl) -#endif -{ - struct spd_set_memclk_result result; - const struct mem_param *param; - long dimm_mask; -#if 1 - if (!controller_present(ctrl)) { - return; - } -#endif - hw_enable_ecc(ctrl); - activate_spd_rom(ctrl); - dimm_mask = spd_detect_dimms(ctrl); - if (!(dimm_mask & ((1 << DIMM_SOCKETS) - 1))) { - printk(BIOS_DEBUG, "No memory for this cpu\n"); - return; - } - dimm_mask = spd_enable_2channels(ctrl, dimm_mask); - if (dimm_mask < 0) - goto hw_spd_err; - dimm_mask = spd_set_ram_size(ctrl , dimm_mask); - if (dimm_mask < 0) - goto hw_spd_err; - dimm_mask = spd_handle_unbuffered_dimms(ctrl, dimm_mask); - if (dimm_mask < 0) - goto hw_spd_err; - result = spd_set_memclk(ctrl, dimm_mask); - param = result.param; - dimm_mask = result.dimm_mask; - if (dimm_mask < 0) - goto hw_spd_err; - dimm_mask = spd_set_dram_timing(ctrl, param , dimm_mask); - if (dimm_mask < 0) - goto hw_spd_err; - order_dimms(ctrl); - return; - hw_spd_err: - /* Unrecoverable error reading SPD data */ - printk(BIOS_ERR, "SPD error - reset\n"); - hard_reset(); - return; -} - -#if CONFIG_HW_MEM_HOLE_SIZEK != 0 -static uint32_t hoist_memory(int controllers, const struct mem_controller *ctrl,unsigned hole_startk, int i) -{ - int ii; - uint32_t carry_over; - pci_devfn_t dev; - uint32_t base, limit; - uint32_t basek; - uint32_t hoist; - int j; - - carry_over = (4*1024*1024) - hole_startk; - - for (ii = controllers - 1; ii > i; ii--) { - base = pci_read_config32(ctrl[0].f1, 0x40 + (ii << 3)); - if ((base & ((1<<1)|(1<<0))) != ((1<<1)|(1<<0))) { - continue; - } - limit = pci_read_config32(ctrl[0].f1, 0x44 + (ii << 3)); - for (j = 0; j < controllers; j++) { - pci_write_config32(ctrl[j].f1, 0x44 + (ii << 3), limit + (carry_over << 2)); - pci_write_config32(ctrl[j].f1, 0x40 + (ii << 3), base + (carry_over << 2)); - } - } - limit = pci_read_config32(ctrl[0].f1, 0x44 + (i << 3)); - for (j = 0; j < controllers; j++) { - pci_write_config32(ctrl[j].f1, 0x44 + (i << 3), limit + (carry_over << 2)); - } - dev = ctrl[i].f1; - base = pci_read_config32(dev, 0x40 + (i << 3)); - basek = (base & 0xffff0000) >> 2; - if (basek == hole_startk) { - //don't need set memhole here, because hole off set will be 0, overflow - //so need to change base reg instead, new basek will be 4*1024*1024 - base &= 0x0000ffff; - base |= (4*1024*1024)<<2; - for (j = 0; j < controllers; j++) { - pci_write_config32(ctrl[j].f1, 0x40 + (i<<3), base); - } - } - else { - hoist = /* hole start address */ - ((hole_startk << 10) & 0xff000000) + - /* hole address to memory controller address */ - (((basek + carry_over) >> 6) & 0x0000ff00) + - /* enable */ - 1; - pci_write_config32(dev, 0xf0, hoist); - } - - return carry_over; -} - -void set_hw_mem_hole(int controllers, const struct mem_controller *ctrl) -{ - - uint32_t hole_startk; - int i; - - hole_startk = 4*1024*1024 - CONFIG_HW_MEM_HOLE_SIZEK; - - printk(BIOS_SPEW, "Handling memory hole at 0x%08x (default)\n", hole_startk); -#if IS_ENABLED(CONFIG_HW_MEM_HOLE_SIZE_AUTO_INC) - /* We need to double check if hole_startk is valid. - * If it is equal to the dram base address in K (base_k), - * we need to decrease it. - */ - uint32_t basek_pri; - for (i = 0; i < controllers; i++) { - uint32_t base; - unsigned base_k; - base = pci_read_config32(ctrl[0].f1, 0x40 + (i << 3)); - if ((base & ((1<<1)|(1<<0))) != ((1<<1)|(1<<0))) { - continue; - } - base_k = (base & 0xffff0000) >> 2; - if (base_k == hole_startk) { - /* decrease memory hole startk to make sure it is - * in the middle of the previous node - */ - hole_startk -= (base_k - basek_pri)>>1; - break; /* only one hole */ - } - basek_pri = base_k; - } - - printk(BIOS_SPEW, "Handling memory hole at 0x%08x (adjusted)\n", hole_startk); -#endif - /* Find node number that needs the memory hole configured */ - for (i = 0; i < controllers; i++) { - uint32_t base, limit; - unsigned base_k, limit_k; - base = pci_read_config32(ctrl[0].f1, 0x40 + (i << 3)); - if ((base & ((1<<1)|(1<<0))) != ((1<<1)|(1<<0))) { - continue; - } - limit = pci_read_config32(ctrl[0].f1, 0x44 + (i << 3)); - base_k = (base & 0xffff0000) >> 2; - limit_k = ((limit + 0x00010000) & 0xffff0000) >> 2; - if ((base_k <= hole_startk) && (limit_k > hole_startk)) { - unsigned end_k; - hoist_memory(controllers, ctrl, hole_startk, i); - end_k = memory_end_k(ctrl, controllers); - set_top_mem(end_k, hole_startk); - break; /* only one hole */ - } - } - -} - -#endif - -#if IS_ENABLED(CONFIG_RAMINIT_SYSINFO) -void sdram_enable(int controllers, const struct mem_controller *ctrl, struct sys_info *sysinfo) -#else -void sdram_enable(int controllers, const struct mem_controller *ctrl) -#endif -{ - int i; - u32 whatWait = 0; - int suspend = acpi_is_wakeup_s3(); - - /* Error if I don't have memory */ - if (memory_end_k(ctrl, controllers) == 0) { - die("No memory\n"); - } - - /* Before enabling memory start the memory clocks */ - for (i = 0; i < controllers; i++) { - uint32_t dch; - if (!controller_present(ctrl + i)) - continue; - dch = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_HIGH); - if (dch & (DCH_MEMCLK_EN0|DCH_MEMCLK_EN1|DCH_MEMCLK_EN2|DCH_MEMCLK_EN3)) { - dch |= DCH_MEMCLK_VALID; - pci_write_config32(ctrl[i].f2, DRAM_CONFIG_HIGH, dch); - } - else { - /* Disable dram receivers */ - uint32_t dcl; - dcl = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_LOW); - dcl |= DCL_DisInRcvrs; - pci_write_config32(ctrl[i].f2, DRAM_CONFIG_LOW, dcl); - } - } - - /* We need to wait a minimum of 20 MEMCLKS to enable the InitDram */ - /* And if necessary toggle the the reset on the dimms by hand */ - memreset(controllers, ctrl); - - for (i = 0; i < controllers; i++) { - uint32_t dcl, dch; - if (!controller_present(ctrl + i)) - continue; - /* Skip everything if I don't have any memory on this controller */ - dch = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_HIGH); - if (!(dch & DCH_MEMCLK_VALID)) { - continue; - } - - /* Toggle DisDqsHys to get it working */ - dcl = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_LOW); - if (dcl & DCL_DimmEccEn) { - uint32_t mnc; - printk(BIOS_SPEW, "ECC enabled\n"); - mnc = pci_read_config32(ctrl[i].f3, MCA_NB_CONFIG); - mnc |= MNC_ECC_EN; - if (dcl & DCL_128BitEn) { - mnc |= MNC_CHIPKILL_EN; - } - pci_write_config32(ctrl[i].f3, MCA_NB_CONFIG, mnc); - } - - if (!suspend) { - dcl |= DCL_DisDqsHys; - pci_write_config32(ctrl[i].f2, DRAM_CONFIG_LOW, dcl); - } - dcl &= ~DCL_DisDqsHys; - dcl &= ~DCL_DLL_Disable; - dcl &= ~DCL_D_DRV; - dcl &= ~DCL_QFC_EN; - - if (suspend) { - enable_lapic(); - init_timer(); - dcl |= (DCL_ESR | DCL_SRS); - /* Handle errata 85 Insufficient Delay Between MEMCLK Startup - and CKE Assertion During Resume From S3 */ - udelay(10); /* for unregistered */ - if (is_registered(&ctrl[i])) { - udelay(100); /* 110us for registered (we wait 10us already) */ - } - whatWait = DCL_ESR; - } else { - dcl |= DCL_DramInit; - whatWait = DCL_DramInit; - } - pci_write_config32(ctrl[i].f2, DRAM_CONFIG_LOW, dcl); - } - - for (i = 0; i < controllers; i++) { - uint32_t dcl, dch; - if (!controller_present(ctrl + i)) - continue; - /* Skip everything if I don't have any memory on this controller */ - dch = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_HIGH); - if (!(dch & DCH_MEMCLK_VALID)) { - continue; - } - - printk(BIOS_DEBUG, "Initializing memory: "); - int loops = 0; - do { - dcl = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_LOW); - loops++; - if ((loops & 1023) == 0) { - printk(BIOS_DEBUG, "."); - } - } while (((dcl & whatWait) != 0) && (loops < TIMEOUT_LOOPS)); - if (loops >= TIMEOUT_LOOPS) { - printk(BIOS_DEBUG, " failed\n"); - continue; - } - - if (!is_cpu_pre_c0()) { - /* Wait until it is safe to touch memory */ - do { - dcl = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_LOW); - } while (((dcl & DCL_MemClrStatus) == 0) || ((dcl & DCL_DramEnable) == 0) || - ((dcl & DCL_SRS))); - } - - printk(BIOS_DEBUG, " done\n"); - } - -#if CONFIG_HW_MEM_HOLE_SIZEK != 0 - // init hw mem hole here - /* DramHoleValid bit only can be set after MemClrStatus is set by Hardware */ - if (!is_cpu_pre_e0()) - set_hw_mem_hole(controllers, ctrl); -#endif - - //FIXME add enable node interleaving here -- yhlu - /*needed? - 1. check how many nodes we have , if not all has RAM installed get out - 2. check cs_base lo is 0, node 0 f2 0x40,,,,, if any one is not using lo is CS_BASE, get out - 3. check if other node is the same as node 0 about f2 0x40,,,,, otherwise get out - 4. if all ready enable node_interleaving in f1 0x40..... of every node - 5. for node interleaving we need to set mem hole to every node (need recalcute hole offset in f0 for every node) - */ - -} - -void set_sysinfo_in_ram(unsigned val) -{ -} - -void fill_mem_ctrl(int controllers, struct mem_controller *ctrl_a, - const uint16_t *spd_addr) -{ - int i; - int j; - struct mem_controller *ctrl; - for (i = 0; i < controllers; i++) { - ctrl = &ctrl_a[i]; - ctrl->node_id = i; - ctrl->f0 = PCI_DEV(0, 0x18+i, 0); - ctrl->f1 = PCI_DEV(0, 0x18+i, 1); - ctrl->f2 = PCI_DEV(0, 0x18+i, 2); - ctrl->f3 = PCI_DEV(0, 0x18+i, 3); - - if (spd_addr == (void *)0) continue; - - for (j = 0; j < DIMM_SOCKETS; j++) { - ctrl->channel0[j] = spd_addr[(i*2+0)*DIMM_SOCKETS + j]; - ctrl->channel1[j] = spd_addr[(i*2+1)*DIMM_SOCKETS + j]; - } - } -} diff --git a/src/northbridge/amd/amdk8/raminit.h b/src/northbridge/amd/amdk8/raminit.h deleted file mode 100644 index 002c5adbec..0000000000 --- a/src/northbridge/amd/amdk8/raminit.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * 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. - */ - -#ifndef RAMINIT_H -#define RAMINIT_H - -#include <arch/io.h> - -#define NODE_ID 0x60 -#define HT_INIT_CONTROL 0x6c - -#define NODE_NUMS 8 - -#define DIMM_SOCKETS 4 -struct mem_controller { - unsigned node_id; - pci_devfn_t f0, f1, f2, f3; - uint16_t channel0[DIMM_SOCKETS]; - uint16_t channel1[DIMM_SOCKETS]; -}; - -struct sys_info; - -void exit_from_self(int controllers, const struct mem_controller *ctrl, struct sys_info *sysinfo); -void setup_resource_map(const unsigned int *register_values, int max); -void set_hw_mem_hole(int controllers, const struct mem_controller *ctrl); -int spd_read_byte(unsigned device, unsigned address); -void activate_spd_rom(const struct mem_controller *ctrl); -void memreset(int controllers, const struct mem_controller *ctrl); -void set_sysinfo_in_ram(unsigned int val); - -#define TIMEOUT_LOOPS 300000 - -#if defined(__PRE_RAM__) && IS_ENABLED(CONFIG_RAMINIT_SYSINFO) -void sdram_initialize(int controllers, const struct mem_controller *ctrl, void *sysinfo); -void sdram_enable(int controllers, const struct mem_controller *ctrl, - struct sys_info *sysinfo); -void sdram_set_registers(const struct mem_controller *ctrl, struct sys_info *sysinfo); -void sdram_set_spd_registers(const struct mem_controller *ctrl, - struct sys_info *sysinfo); -void dump_spd_registers(const struct mem_controller *ctrl); -void dump_smbus_registers(void); -#else -void sdram_set_registers(const struct mem_controller *ctrl); -void sdram_set_spd_registers(const struct mem_controller *ctrl); -void sdram_enable(int controllers, const struct mem_controller *ctrl); -void sdram_initialize(int controllers, const struct mem_controller *ctrl); -#endif - -#endif /* RAMINIT_H */ diff --git a/src/northbridge/amd/amdk8/raminit_f.c b/src/northbridge/amd/amdk8/raminit_f.c deleted file mode 100644 index ba17df28f9..0000000000 --- a/src/northbridge/amd/amdk8/raminit_f.c +++ /dev/null @@ -1,3211 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2002 Linux Networx - * (Written by Eric Biederman <ebiederman@lnxi.com> for Linux Networx) - * Copyright (C) 2004 YingHai Lu - * Copyright (C) 2008 Advanced Micro Devices, Inc. - * - * 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. -*/ - -#include <arch/io.h> -#include <console/console.h> -#include <cpu/x86/cache.h> -#include <cpu/x86/msr.h> -#include <cpu/x86/mtrr.h> -#include <cpu/x86/tsc.h> -#include <cpu/amd/mtrr.h> -#include <pc80/mc146818rtc.h> - -#include <lib.h> -#include <stdlib.h> -#include <string.h> -#include <arch/acpi.h> -#include "amdk8.h" -#include "raminit.h" -#include "f.h" -#include <spd_ddr2.h> -#if IS_ENABLED(CONFIG_HAVE_OPTION_TABLE) -#include "option_table.h" -#endif - -#if IS_ENABLED(CONFIG_DEBUG_RAM_SETUP) -#define printk_raminit(args...) printk(BIOS_DEBUG, args) -#else -#define printk_raminit(args...) -#endif - -#include <arch/early_variables.h> -struct sys_info sysinfo_car CAR_GLOBAL; - -#include "f_pci.c" - - /* for PCI_ADDR(0, 0x18, 2, 0x98) index, - and PCI_ADDR(0x, 0x18, 2, 0x9c) data */ - /* -index: - [29: 0] DctOffset (Dram Controller Offset) - [30:30] DctAccessWrite (Dram Controller Read/Write Select) - 0 = read access - 1 = write access - [31:31] DctAccessDone (Dram Controller Access Done) - 0 = Access in progress - 1 = No access is progress - - Data: - [31: 0] DctOffsetData (Dram Controller Offset Data) - - Read: - - Write the register num to DctOffset with - DctAccessWrite = 0 - - poll the DctAccessDone until it = 1 - - Read the data from DctOffsetData - Write: - - Write the data to DctOffsetData - - Write register num to DctOffset with DctAccessWrite = 1 - - poll the DctAccessDone until it = 1 - */ - - -void setup_resource_map(const unsigned int *register_values, int max) -{ - int i; - for (i = 0; i < max; i += 3) { - pci_devfn_t dev; - unsigned where; - unsigned long reg; - dev = register_values[i] & ~0xff; - where = register_values[i] & 0xff; - reg = pci_read_config32(dev, where); - reg &= register_values[i+1]; - reg |= register_values[i+2]; - pci_write_config32(dev, where, reg); - } -} - -static int controller_present(const struct mem_controller *ctrl) -{ - return pci_read_config32(ctrl->f0, 0) == 0x11001022; -} - -void sdram_set_registers(const struct mem_controller *ctrl, struct sys_info *sysinfo) -{ - static const unsigned int register_values[] = { - - /* Careful set limit registers before base registers which - contain the enables */ - /* DRAM Limit i Registers - * F1:0x44 i = 0 - * F1:0x4C i = 1 - * F1:0x54 i = 2 - * F1:0x5C i = 3 - * F1:0x64 i = 4 - * F1:0x6C i = 5 - * F1:0x74 i = 6 - * F1:0x7C i = 7 - * [ 2: 0] Destination Node ID - * 000 = Node 0 - * 001 = Node 1 - * 010 = Node 2 - * 011 = Node 3 - * 100 = Node 4 - * 101 = Node 5 - * 110 = Node 6 - * 111 = Node 7 - * [ 7: 3] Reserved - * [10: 8] Interleave select - * specifies the values of A[14:12] to use with interleave enable. - * [15:11] Reserved - * [31:16] DRAM Limit Address i Bits 39-24 - * This field defines the upper address bits of a 40 bit address - * that define the end of the DRAM region. - */ - PCI_ADDR(0, 0x18, 1, 0x44), 0x0000f8f8, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0x4C), 0x0000f8f8, 0x00000001, - PCI_ADDR(0, 0x18, 1, 0x54), 0x0000f8f8, 0x00000002, - PCI_ADDR(0, 0x18, 1, 0x5C), 0x0000f8f8, 0x00000003, - PCI_ADDR(0, 0x18, 1, 0x64), 0x0000f8f8, 0x00000004, - PCI_ADDR(0, 0x18, 1, 0x6C), 0x0000f8f8, 0x00000005, - PCI_ADDR(0, 0x18, 1, 0x74), 0x0000f8f8, 0x00000006, - PCI_ADDR(0, 0x18, 1, 0x7C), 0x0000f8f8, 0x00000007, - /* DRAM Base i Registers - * F1:0x40 i = 0 - * F1:0x48 i = 1 - * F1:0x50 i = 2 - * F1:0x58 i = 3 - * F1:0x60 i = 4 - * F1:0x68 i = 5 - * F1:0x70 i = 6 - * F1:0x78 i = 7 - * [ 0: 0] Read Enable - * 0 = Reads Disabled - * 1 = Reads Enabled - * [ 1: 1] Write Enable - * 0 = Writes Disabled - * 1 = Writes Enabled - * [ 7: 2] Reserved - * [10: 8] Interleave Enable - * 000 = No interleave - * 001 = Interleave on A[12] (2 nodes) - * 010 = reserved - * 011 = Interleave on A[12] and A[14] (4 nodes) - * 100 = reserved - * 101 = reserved - * 110 = reserved - * 111 = Interleave on A[12] and A[13] and A[14] (8 nodes) - * [15:11] Reserved - * [13:16] DRAM Base Address i Bits 39-24 - * This field defines the upper address bits of a 40-bit address - * that define the start of the DRAM region. - */ - PCI_ADDR(0, 0x18, 1, 0x40), 0x0000f8fc, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0x48), 0x0000f8fc, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0x50), 0x0000f8fc, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0x58), 0x0000f8fc, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0x60), 0x0000f8fc, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0x68), 0x0000f8fc, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0x70), 0x0000f8fc, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0x78), 0x0000f8fc, 0x00000000, - - /* DRAM CS Base Address i Registers - * F2:0x40 i = 0 - * F2:0x44 i = 1 - * F2:0x48 i = 2 - * F2:0x4C i = 3 - * F2:0x50 i = 4 - * F2:0x54 i = 5 - * F2:0x58 i = 6 - * F2:0x5C i = 7 - * [ 0: 0] Chip-Select Bank Enable - * 0 = Bank Disabled - * 1 = Bank Enabled - * [ 1: 1] Spare Rank - * [ 2: 2] Memory Test Failed - * [ 4: 3] Reserved - * [13: 5] Base Address (21-13) - * An optimization used when all DIMM are the same size... - * [18:14] Reserved - * [28:19] Base Address (36-27) - * This field defines the top 11 addresses bit of a 40-bit - * address that define the memory address space. These - * bits decode 32-MByte blocks of memory. - * [31:29] Reserved - */ - PCI_ADDR(0, 0x18, 2, 0x40), 0xe007c018, 0x00000000, - PCI_ADDR(0, 0x18, 2, 0x44), 0xe007c018, 0x00000000, - PCI_ADDR(0, 0x18, 2, 0x48), 0xe007c018, 0x00000000, - PCI_ADDR(0, 0x18, 2, 0x4C), 0xe007c018, 0x00000000, - PCI_ADDR(0, 0x18, 2, 0x50), 0xe007c018, 0x00000000, - PCI_ADDR(0, 0x18, 2, 0x54), 0xe007c018, 0x00000000, - PCI_ADDR(0, 0x18, 2, 0x58), 0xe007c018, 0x00000000, - PCI_ADDR(0, 0x18, 2, 0x5C), 0xe007c018, 0x00000000, - /* DRAM CS Mask Address i Registers - * F2:0x60 i = 0,1 - * F2:0x64 i = 2,3 - * F2:0x68 i = 4,5 - * F2:0x6C i = 6,7 - * Select bits to exclude from comparison with the DRAM Base address register. - * [ 4: 0] Reserved - * [13: 5] Address Mask (21-13) - * Address to be excluded from the optimized case - * [18:14] Reserved - * [28:19] Address Mask (36-27) - * The bits with an address mask of 1 are excluded from address comparison - * [31:29] Reserved - * - */ - PCI_ADDR(0, 0x18, 2, 0x60), 0xe007c01f, 0x00000000, - PCI_ADDR(0, 0x18, 2, 0x64), 0xe007c01f, 0x00000000, - PCI_ADDR(0, 0x18, 2, 0x68), 0xe007c01f, 0x00000000, - PCI_ADDR(0, 0x18, 2, 0x6C), 0xe007c01f, 0x00000000, - - /* DRAM Control Register - * F2:0x78 - * [ 3: 0] RdPtrInit (Read Pointer Initial Value) - * 0x03-0x00: reserved - * [ 6: 4] RdPadRcvFifoDly (Read Delay from Pad Receive FIFO) - * 000 = reserved - * 001 = reserved - * 010 = 1.5 Memory Clocks - * 011 = 2 Memory Clocks - * 100 = 2.5 Memory Clocks - * 101 = 3 Memory Clocks - * 110 = 3.5 Memory Clocks - * 111 = Reserved - * [15: 7] Reserved - * [16:16] AltVidC3MemClkTriEn (AltVID Memory Clock Tristate Enable) - * Enables the DDR memory clocks to be tristated when alternate VID - * mode is enabled. This bit has no effect if the DisNbClkRamp bit - * (F3, 0x88) is set - * [17:17] DllTempAdjTime (DLL Temperature Adjust Cycle Time) - * 0 = 5 ms - * 1 = 1 ms - * [18:18] DqsRcvEnTrain (DQS Receiver Enable Training Mode) - * 0 = Normal DQS Receiver enable operation - * 1 = DQS receiver enable training mode - * [31:19] reserved - */ - PCI_ADDR(0, 0x18, 2, 0x78), 0xfff80000, (6<<4)|(6<<0), - - /* DRAM Initialization Register - * F2:0x7C - * [15: 0] MrsAddress (Address for MRS/EMRS Commands) - * this field specifies the data driven on the DRAM address pins - * 15-0 for MRS and EMRS commands - * [18:16] MrsBank (Bank Address for MRS/EMRS Commands) - * this files specifies the data driven on the DRAM bank pins for - * the MRS and EMRS commands - * [23:19] reserved - * [24:24] SendPchgAll (Send Precharge All Command) - * Setting this bit causes the DRAM controller to send a precharge - * all command. This bit is cleared by the hardware after the - * command completes - * [25:25] SendAutoRefresh (Send Auto Refresh Command) - * Setting this bit causes the DRAM controller to send an auto - * refresh command. This bit is cleared by the hardware after the - * command completes - * [26:26] SendMrsCmd (Send MRS/EMRS Command) - * Setting this bit causes the DRAM controller to send the MRS or - * EMRS command defined by the MrsAddress and MrsBank fields. This - * bit is cleared by the hardware after the command completes - * [27:27] DeassertMemRstX (De-assert Memory Reset) - * Setting this bit causes the DRAM controller to de-assert the - * memory reset pin. This bit cannot be used to assert the memory - * reset pin - * [28:28] AssertCke (Assert CKE) - * setting this bit causes the DRAM controller to assert the CKE - * pins. This bit cannot be used to de-assert the CKE pins - * [30:29] reserved - * [31:31] EnDramInit (Enable DRAM Initialization) - * Setting this bit puts the DRAM controller in a BIOS controlled - * DRAM initialization mode. BIOS must clear this bit aster DRAM - * initialization is complete. - */ -// PCI_ADDR(0, 0x18, 2, 0x7C), 0x60f80000, 0, - - - /* DRAM Bank Address Mapping Register - * F2:0x80 - * Specify the memory module size - * [ 3: 0] CS1/0 - * [ 7: 4] CS3/2 - * [11: 8] CS5/4 - * [15:12] CS7/6 - * [31:16] - row col bank - 0: 13 9 2 :128M - 1: 13 10 2 :256M - 2: 14 10 2 :512M - 3: 13 11 2 :512M - 4: 13 10 3 :512M - 5: 14 10 3 :1G - 6: 14 11 2 :1G - 7: 15 10 3 :2G - 8: 14 11 3 :2G - 9: 15 11 3 :4G - 10: 16 10 3 :4G - 11: 16 11 3 :8G - */ - PCI_ADDR(0, 0x18, 2, 0x80), 0xffff0000, 0x00000000, - /* DRAM Timing Low Register - * F2:0x88 - * [ 2: 0] Tcl (Cas# Latency, Cas# to read-data-valid) - * 000 = reserved - * 001 = reserved - * 010 = CL 3 - * 011 = CL 4 - * 100 = CL 5 - * 101 = CL 6 - * 110 = reserved - * 111 = reserved - * [ 3: 3] Reserved - * [ 5: 4] Trcd (Ras#-active to Cas# read/write delay) - * 00 = 3 clocks - * 01 = 4 clocks - * 10 = 5 clocks - * 11 = 6 clocks - * [ 7: 6] Reserved - * [ 9: 8] Trp (Row Precharge Time, Precharge-to-Active or Auto-Refresh) - * 00 = 3 clocks - * 01 = 4 clocks - * 10 = 5 clocks - * 11 = 6 clocks - * [10:10] Reserved - * [11:11] Trtp (Read to Precharge Time, read Cas# to precharge time) - * 0 = 2 clocks for Burst Length of 32 Bytes - * 4 clocks for Burst Length of 64 Bytes - * 1 = 3 clocks for Burst Length of 32 Bytes - * 5 clocks for Burst Length of 64 Bytes - * [15:12] Tras (Minimum Ras# Active Time) - * 0000 = reserved - * 0001 = reserved - * 0010 = 5 bus clocks - * ... - * 1111 = 18 bus clocks - * [19:16] Trc (Row Cycle Time, Ras#-active to Ras#-active or auto - * refresh of the same bank) - * 0000 = 11 bus clocks - * 0010 = 12 bus clocks - * ... - * 1110 = 25 bus clocks - * 1111 = 26 bus clocks - * [21:20] Twr (Write Recovery Time, From the last data to precharge, - * writes can go back-to-back) - * 00 = 3 bus clocks - * 01 = 4 bus clocks - * 10 = 5 bus clocks - * 11 = 6 bus clocks - * [23:22] Trrd (Active-to-active(Ras#-to-Ras#) Delay of different banks) - * 00 = 2 bus clocks - * 01 = 3 bus clocks - * 10 = 4 bus clocks - * 11 = 5 bus clocks - * [31:24] MemClkDis (Disable the MEMCLK outputs for DRAM channel A, - * BIOS should set it to reduce the power consumption) - * Bit F(1207) M2 Package S1g1 Package - * 0 N/A MA1_CLK1 N/A - * 1 N/A MA0_CLK1 MA0_CLK1 - * 2 MA3_CLK N/A N/A - * 3 MA2_CLK N/A N/A - * 4 MA1_CLK MA1_CLK0 N/A - * 5 MA0_CLK MA0_CLK0 MA0_CLK0 - * 6 N/A MA1_CLK2 N/A - * 7 N/A MA0_CLK2 MA0_CLK2 - */ - PCI_ADDR(0, 0x18, 2, 0x88), 0x000004c8, 0xff000002 /* 0x03623125 */ , - /* DRAM Timing High Register - * F2:0x8C - * [ 3: 0] Reserved - * [ 6: 4] TrwtTO (Read-to-Write Turnaround for Data, DQS Contention) - * 000 = 2 bus clocks - * 001 = 3 bus clocks - * 010 = 4 bus clocks - * 011 = 5 bus clocks - * 100 = 6 bus clocks - * 101 = 7 bus clocks - * 110 = 8 bus clocks - * 111 = 9 bus clocks - * [ 7: 7] Reserved - * [ 9: 8] Twtr (Internal DRAM Write-to-Read Command Delay, - * Minimum write-to-read delay when both access the same chip select) - * 00 = Reserved - * 01 = 1 bus clocks - * 10 = 2 bus clocks - * 11 = 3 bus clocks - * [11:10] Twrrd (Write to Read DIMM Termination Turnaround, minimum - * write-to-read delay when accessing two different DIMMs) - * 00 = 0 bus clocks - * 01 = 1 bus clocks - * 10 = 2 bus clocks - * 11 = 3 bus clocks - * [13:12] Twrwr (Write to Write Timing) - * 00 = 1 bus clocks (0 idle cycle on the bus) - * 01 = 2 bus clocks (1 idle cycle on the bus) - * 10 = 3 bus clocks (2 idle cycles on the bus) - * 11 = Reserved - * [15:14] Trdrd (Read to Read Timing) - * 00 = 2 bus clocks (1 idle cycle on the bus) - * 01 = 3 bus clocks (2 idle cycles on the bus) - * 10 = 4 bus clocks (3 idle cycles on the bus) - * 11 = 5 bus clocks (4 idle cycles on the bus) - * [17:16] Tref (Refresh Rate) - * 00 = Undefined behavior - * 01 = Reserved - * 10 = Refresh interval of 7.8 microseconds - * 11 = Refresh interval of 3.9 microseconds - * [19:18] Reserved - * [22:20] Trfc0 (Auto-Refresh Row Cycle Time for the Logical DIMM0, - * based on DRAM density and speed) - * 000 = 75 ns (all speeds, 256Mbit) - * 001 = 105 ns (all speeds, 512Mbit) - * 010 = 127.5 ns (all speeds, 1Gbit) - * 011 = 195 ns (all speeds, 2Gbit) - * 100 = 327.5 ns (all speeds, 4Gbit) - * 101 = reserved - * 110 = reserved - * 111 = reserved - * [25:23] Trfc1 (Auto-Refresh Row Cycle Time for the Logical DIMM1, - * based on DRAM density and speed) - * [28:26] Trfc2 (Auto-Refresh Row Cycle Time for the Logical DIMM2, - * based on DRAM density and speed) - * [31:29] Trfc3 (Auto-Refresh Row Cycle Time for the Logical DIMM3, - * based on DRAM density and speed) - */ - PCI_ADDR(0, 0x18, 2, 0x8c), 0x000c008f, (2 << 16)|(1 << 8), - /* DRAM Config Low Register - * F2:0x90 - * [ 0: 0] InitDram (Initialize DRAM) - * 1 = write 1 cause DRAM controller to execute the DRAM - * initialization, when done it read to 0 - * [ 1: 1] ExitSelfRef (Exit Self Refresh Command) - * 1 = write 1 causes the DRAM controller to bring the DRAMs out - * for self refresh mode - * [ 3: 2] Reserved - * [ 5: 4] DramTerm (DRAM Termination) - * 00 = On die termination disabled - * 01 = 75 ohms - * 10 = 150 ohms - * 11 = 50 ohms - * [ 6: 6] Reserved - * [ 7: 7] DramDrvWeak (DRAM Drivers Weak Mode) - * 0 = Normal drive strength mode. - * 1 = Weak drive strength mode - * [ 8: 8] ParEn (Parity Enable) - * 1 = Enable address parity computation output, PAR, - * and enables the parity error input, ERR - * [ 9: 9] SelfRefRateEn (Faster Self Refresh Rate Enable) - * 1 = Enable high temperature (two times normal) - * self refresh rate - * [10:10] BurstLength32 (DRAM Burst Length Set for 32 Bytes) - * 0 = 64-byte mode - * 1 = 32-byte mode - * [11:11] Width128 (Width of DRAM interface) - * 0 = the controller DRAM interface is 64-bits wide - * 1 = the controller DRAM interface is 128-bits wide - * [12:12] X4Dimm (DIMM 0 is x4) - * [13:13] X4Dimm (DIMM 1 is x4) - * [14:14] X4Dimm (DIMM 2 is x4) - * [15:15] X4Dimm (DIMM 3 is x4) - * 0 = DIMM is not x4 - * 1 = x4 DIMM present - * [16:16] UnBuffDimm (Unbuffered DIMMs) - * 0 = Buffered DIMMs - * 1 = Unbuffered DIMMs - * [18:17] Reserved - * [19:19] DimmEccEn (DIMM ECC Enable) - * 1 = ECC checking is being enabled for all DIMMs on the DRAM - * controller (Through F3 0x44[EccEn]) - * [31:20] Reserved - */ - PCI_ADDR(0, 0x18, 2, 0x90), 0xfff6004c, 0x00000010, - /* DRAM Config High Register - * F2:0x94 - * [ 0: 2] MemClkFreq (Memory Clock Frequency) - * 000 = 200MHz - * 001 = 266MHz - * 010 = 333MHz - * 011 = reserved - * 1xx = reserved - * [ 3: 3] MemClkFreqVal (Memory Clock Frequency Valid) - * 1 = BIOS need to set the bit when setting up MemClkFreq to - * the proper value - * [ 7: 4] MaxAsyncLat (Maximum Asynchronous Latency) - * 0000 = 0 ns - * ... - * 1111 = 15 ns - * [11: 8] Reserved - * [12:12] RDqsEn (Read DQS Enable) This bit is only be set if x8 - * registered DIMMs are present in the system - * 0 = DM pins function as data mask pins - * 1 = DM pins function as read DQS pins - * [13:13] Reserved - * [14:14] DisDramInterface (Disable the DRAM interface) When this bit - * is set, the DRAM controller is disabled, and interface in low power - * state - * 0 = Enabled (default) - * 1 = Disabled - * [15:15] PowerDownEn (Power Down Mode Enable) - * 0 = Disabled (default) - * 1 = Enabled - * [16:16] PowerDown (Power Down Mode) - * 0 = Channel CKE Control - * 1 = Chip Select CKE Control - * [17:17] FourRankSODimm (Four Rank SO-DIMM) - * 1 = this bit is set by BIOS to indicate that a four rank - * SO-DIMM is present - * [18:18] FourRankRDimm (Four Rank Registered DIMM) - * 1 = this bit is set by BIOS to indicate that a four rank - * registered DIMM is present - * [19:19] Reserved - * [20:20] SlowAccessMode (Slow Access Mode (2T Mode)) - * 0 = DRAM address and control signals are driven for one - * MEMCLK cycle - * 1 = One additional MEMCLK of setup time is provided on all - * DRAM address and control signals except CS, CKE, and ODT; - * i.e., these signals are driven for two MEMCLK cycles - * rather than one - * [21:21] Reserved - * [22:22] BankSwizzleMode (Bank Swizzle Mode), - * 0 = Disabled (default) - * 1 = Enabled - * [23:23] Reserved - * [27:24] DcqBypassMax (DRAM Controller Queue Bypass Maximum) - * 0000 = No bypass; the oldest request is never bypassed - * 0001 = The oldest request may be bypassed no more than 1 time - * ... - * 1111 = The oldest request may be bypassed no more than 15\ - * times - * [31:28] FourActWindow (Four Bank Activate Window) , not more than - * 4 banks in a 8 bank device are activated - * 0000 = No tFAW window restriction - * 0001 = 8 MEMCLK cycles - * 0010 = 9 MEMCLK cycles - * ... - * 1101 = 20 MEMCLK cycles - * 111x = reserved - */ - PCI_ADDR(0, 0x18, 2, 0x94), 0x00a82f00,0x00008000, - /* DRAM Delay Line Register - * F2:0xa0 - * [ 0: 0] MemClrStatus (Memory Clear Status) : Readonly - * when set, this bit indicates that the memory clear function - * is complete. Only clear by reset. BIOS should not write or - * read the DRAM until this bit is set by hardware - * [ 1: 1] DisableJitter (Disable Jitter) - * When set the DDR compensation circuit will not change the - * values unless the change is more than one step from the - * current value - * [ 3: 2] RdWrQByp (Read/Write Queue Bypass Count) - * 00 = 2 - * 01 = 4 - * 10 = 8 - * 11 = 16 - * [ 4: 4] Mode64BitMux (Mismatched DIMM Support Enable) - * 1 When bit enables support for mismatched DIMMs when using - * 128-bit DRAM interface, the Width128 no effect, only for - * AM2 and s1g1 - * [ 5: 5] DCC_EN (Dynamic Idle Cycle Counter Enable) - * When set to 1, indicates that each entry in the page tables - * dynamically adjusts the idle cycle limit based on page - * Conflict/Page Miss (PC/PM) traffic - * [ 8: 6] ILD_lmt (Idle Cycle Limit) - * 000 = 0 cycles - * 001 = 4 cycles - * 010 = 8 cycles - * 011 = 16 cycles - * 100 = 32 cycles - * 101 = 64 cycles - * 110 = 128 cycles - * 111 = 256 cycles - * [ 9: 9] DramEnabled (DRAM Enabled) - * When Set, this bit indicates that the DRAM is enabled, this - * bit is set by hardware after DRAM initialization or on an exit - * from self refresh. The DRAM controller is initialized after the - * hardware-controlled initialization process (initiated by the - * F2 0x90[DramInit]) completes or when the BIOS-controlled - * initialization process completes (F2 0x7c(EnDramInit] is - * written from 1 to 0) - * [23:10] Reserved - * [31:24] MemClkDis (Disable the MEMCLK outputs for DRAM channel B, - * BIOS should set it to reduce the power consumption) - * Bit F(1207) M2 Package S1g1 Package - * 0 N/A MA1_CLK1 N/A - * 1 N/A MA0_CLK1 MA0_CLK1 - * 2 MA3_CLK N/A N/A - * 3 MA2_CLK N/A N/A - * 4 MA1_CLK MA1_CLK0 N/A - * 5 MA0_CLK MA0_CLK0 MA0_CLK0 - * 6 N/A MA1_CLK2 N/A - * 7 N/A MA0_CLK2 MA0_CLK2 - */ - PCI_ADDR(0, 0x18, 2, 0xa0), 0x00fffc00, 0xff000000, - - /* DRAM Scrub Control Register - * F3:0x58 - * [ 4: 0] DRAM Scrub Rate - * [ 7: 5] reserved - * [12: 8] L2 Scrub Rate - * [15:13] reserved - * [20:16] Dcache Scrub - * [31:21] reserved - * Scrub Rates - * 00000 = Do not scrub - * 00001 = 40.00 ns - * 00010 = 80.00 ns - * 00011 = 160.00 ns - * 00100 = 320.00 ns - * 00101 = 640.00 ns - * 00110 = 1.28 us - * 00111 = 2.56 us - * 01000 = 5.12 us - * 01001 = 10.20 us - * 01011 = 41.00 us - * 01100 = 81.90 us - * 01101 = 163.80 us - * 01110 = 327.70 us - * 01111 = 655.40 us - * 10000 = 1.31 ms - * 10001 = 2.62 ms - * 10010 = 5.24 ms - * 10011 = 10.49 ms - * 10100 = 20.97 ms - * 10101 = 42.00 ms - * 10110 = 84.00 ms - * All Others = Reserved - */ - PCI_ADDR(0, 0x18, 3, 0x58), 0xffe0e0e0, 0x00000000, - /* DRAM Scrub Address Low Register - * F3:0x5C - * [ 0: 0] DRAM Scrubber Redirect Enable - * 0 = Do nothing - * 1 = Scrubber Corrects errors found in normal operation - * [ 5: 1] Reserved - * [31: 6] DRAM Scrub Address 31-6 - */ - PCI_ADDR(0, 0x18, 3, 0x5C), 0x0000003e, 0x00000000, - /* DRAM Scrub Address High Register - * F3:0x60 - * [ 7: 0] DRAM Scrub Address 39-32 - * [31: 8] Reserved - */ - PCI_ADDR(0, 0x18, 3, 0x60), 0xffffff00, 0x00000000, - }; - /* for PCI_ADDR(0, 0x18, 2, 0x98) index, - and PCI_ADDR(0x, 0x18, 2, 0x9c) data */ - /* -index: - [29: 0] DctOffset (Dram Controller Offset) - [30:30] DctAccessWrite (Dram Controller Read/Write Select) - 0 = read access - 1 = write access - [31:31] DctAccessDone (Dram Controller Access Done) - 0 = Access in progress - 1 = No access is progress - - Data: - [31: 0] DctOffsetData (Dram Controller Offset Data) - - Read: - - Write the register num to DctOffset with DctAccessWrite = 0 - - poll the DctAccessDone until it = 1 - - Read the data from DctOffsetData - Write: - - Write the data to DctOffsetData - - Write register num to DctOffset with DctAccessWrite = 1 - - poll the DctAccessDone until it = 1 - - */ - int i; - int max; - - if (!controller_present(ctrl)) { - sysinfo->ctrl_present[ctrl->node_id] = 0; - return; - } - sysinfo->ctrl_present[ctrl->node_id] = 1; - - printk(BIOS_SPEW, "setting up CPU %02x northbridge registers\n", ctrl->node_id); - max = ARRAY_SIZE(register_values); - for (i = 0; i < max; i += 3) { - pci_devfn_t dev; - unsigned where; - unsigned long reg; - dev = (register_values[i] & ~0xff) - PCI_DEV(0, 0x18, 0) + ctrl->f0; - where = register_values[i] & 0xff; - reg = pci_read_config32(dev, where); - reg &= register_values[i+1]; - reg |= register_values[i+2]; - pci_write_config32(dev, where, reg); - } - printk(BIOS_SPEW, "done.\n"); -} - -static int is_opteron(const struct mem_controller *ctrl) -{ - /* Test to see if I am an Opteron. M2 and S1G1 support dual - * channel, too, but only support unbuffered DIMMs so we need a - * better test for Opterons. - * However, all code uses is_opteron() to find out whether to - * use dual channel, so if we really check for opteron here, we - * need to fix up all code using this function, too. - */ - - uint32_t nbcap; - nbcap = pci_read_config32(ctrl->f3, NORTHBRIDGE_CAP); - return !!(nbcap & NBCAP_128Bit); -} - -static void spd_get_dimm_size(unsigned device, struct dimm_size *sz) -{ - /* Calculate the log base 2 size of a DIMM in bits */ - int value; - sz->per_rank = 0; - sz->rows = 0; - sz->col = 0; - sz->rank = 0; - - value = spd_read_byte(device, SPD_ROW_NUM); /* rows */ - if (value < 0) goto hw_err; - if ((value & 0xff) == 0) goto val_err; /* max is 16 ? */ - sz->per_rank += value & 0xff; - sz->rows = value & 0xff; - - value = spd_read_byte(device, SPD_COL_NUM); /* columns */ - if (value < 0) goto hw_err; - if ((value & 0xff) == 0) goto val_err; /* max is 11 */ - sz->per_rank += value & 0xff; - sz->col = value & 0xff; - - value = spd_read_byte(device, SPD_BANK_NUM); /* banks */ - if (value < 0) goto hw_err; - if ((value & 0xff) == 0) goto val_err; - sz->bank = log2(value & 0xff); // convert 4 to 2, and 8 to 3 - sz->per_rank += sz->bank; - - /* Get the module data width and convert it to a power of two */ - value = spd_read_byte(device, SPD_DATA_WIDTH); - if (value < 0) goto hw_err; - value &= 0xff; - if ((value != 72) && (value != 64)) goto val_err; - sz->per_rank += log2(value) - 3; //64 bit So another 3 lines - - /* How many ranks? */ - /* number of physical banks */ - value = spd_read_byte(device, SPD_MOD_ATTRIB_RANK); - if (value < 0) goto hw_err; - value &= SPD_MOD_ATTRIB_RANK_NUM_MASK; - value += SPD_MOD_ATTRIB_RANK_NUM_BASE; // 0-->1, 1-->2, 3-->4 - /* - rank == 1 only one rank or say one side - rank == 2 two side , and two ranks - rank == 4 two side , and four ranks total - Some one side two ranks, because of stacked - */ - if ((value != 1) && (value != 2) && (value != 4)) { - goto val_err; - } - sz->rank = value; - - /* verify if per_rank is equal byte 31 - it has the DIMM size as a multiple of 128MB. - */ - value = spd_read_byte(device, SPD_RANK_SIZE); - if (value < 0) goto hw_err; - value &= 0xff; - value = log2(value); - if (value <= 4) value += 8; // add back to 1G to high - value += (27-5); // make 128MB to the real lines - if (value != (sz->per_rank)) { - printk(BIOS_ERR, "Bad RANK Size --\n"); - goto val_err; - } - - goto out; - - val_err: - die("Bad SPD value\n"); - /* If an hw_error occurs report that I have no memory */ - hw_err: - sz->per_rank = 0; - sz->rows = 0; - sz->col = 0; - sz->bank = 0; - sz->rank = 0; -out: - return; -} - - -static void set_dimm_size(const struct mem_controller *ctrl, - struct dimm_size *sz, unsigned index, - struct mem_info *meminfo) -{ - uint32_t base0, base1; - - /* For each base register. - * Place the dimm size in 32 MB quantities in the bits 31 - 21. - * The initialize dimm size is in bits. - * Set the base enable bit0. - */ - - base0 = base1 = 0; - - /* Make certain side1 of the dimm is at least 128MB */ - if (sz->per_rank >= 27) { - base0 = (1 << ((sz->per_rank - 27) + 19)) | 1; - } - - /* Make certain side2 of the dimm is at least 128MB */ - if (sz->rank > 1) { // 2 ranks or 4 ranks - base1 = (1 << ((sz->per_rank - 27) + 19)) | 1; - } - - /* Double the size if we are using dual channel memory */ - if (meminfo->is_Width128) { - base0 = (base0 << 1) | (base0 & 1); - base1 = (base1 << 1) | (base1 & 1); - } - - /* Clear the reserved bits */ - base0 &= ~0xe007fffe; - base1 &= ~0xe007fffe; - - if (!(meminfo->dimm_mask & 0x0F) && (meminfo->dimm_mask & 0xF0)) { /* channelB only? */ - pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1) + 4) << 2), base0); - pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1) + 5) << 2), base1); - } else { - /* Set the appropriate DIMM base address register */ - pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1) + 0) << 2), base0); - pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1) + 1) << 2), base1); -#if IS_ENABLED(CONFIG_QRANK_DIMM_SUPPORT) - if (sz->rank == 4) { - pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1) + 4) << 2), base0); - pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1) + 5) << 2), base1); - } -#endif - } - - /* Enable the memory clocks for this DIMM by Clear the MemClkDis bit*/ - if (base0) { - uint32_t dword; - uint32_t ClkDis0; -#if CONFIG_CPU_SOCKET_TYPE == 0x10 /* L1 */ - ClkDis0 = DTL_MemClkDis0; -#elif CONFIG_CPU_SOCKET_TYPE == 0x11 /* AM2 */ - ClkDis0 = DTL_MemClkDis0_AM2; -#elif CONFIG_CPU_SOCKET_TYPE == 0x12 /* S1G1 */ - ClkDis0 = DTL_MemClkDis0_S1g1; -#endif - - if (!(meminfo->dimm_mask & 0x0F) && (meminfo->dimm_mask & 0xF0)) { /* channelB only? */ - dword = pci_read_config32(ctrl->f2, DRAM_CTRL_MISC); - dword &= ~(ClkDis0 >> index); - pci_write_config32(ctrl->f2, DRAM_CTRL_MISC, dword); - - } else { - dword = pci_read_config32(ctrl->f2, DRAM_TIMING_LOW); //Channel A - dword &= ~(ClkDis0 >> index); -#if IS_ENABLED(CONFIG_QRANK_DIMM_SUPPORT) - if (sz->rank == 4) { - dword &= ~(ClkDis0 >> (index+2)); - } -#endif - pci_write_config32(ctrl->f2, DRAM_TIMING_LOW, dword); - - if (meminfo->is_Width128) { // ChannelA+B - dword = pci_read_config32(ctrl->f2, DRAM_CTRL_MISC); - dword &= ~(ClkDis0 >> index); -#if IS_ENABLED(CONFIG_QRANK_DIMM_SUPPORT) - if (sz->rank == 4) { - dword &= ~(ClkDis0 >> (index+2)); - } -#endif - pci_write_config32(ctrl->f2, DRAM_CTRL_MISC, dword); - } - } - - } -} - -/* row col bank for 64 bit - 0: 13 9 2 :128M - 1: 13 10 2 :256M - 2: 14 10 2 :512M - 3: 13 11 2 :512M - 4: 13 10 3 :512M - 5: 14 10 3 :1G - 6: 14 11 2 :1G - 7: 15 10 3 :2G - 8: 14 11 3 :2G - 9: 15 11 3 :4G - 10: 16 10 3 :4G - 11: 16 11 3 :8G -*/ - - -static void set_dimm_cs_map(const struct mem_controller *ctrl, - struct dimm_size *sz, unsigned index, - struct mem_info *meminfo) -{ - static const uint8_t cs_map_aaa[24] = { - /* (bank=2, row=13, col=9)(3, 16, 11) ---> (0, 0, 0) (1, 3, 2) */ - //Bank2 - 0, 1, 3, - 0, 2, 6, - 0, 0, 0, - 0, 0, 0, - //Bank3 - 0, 4, 0, - 0, 5, 8, - 0, 7, 9, - 0,10,11, - }; - - uint32_t map; - - if (!(meminfo->dimm_mask & 0x0F) && (meminfo->dimm_mask & 0xF0)) { /* channelB only? */ - index += 2; - } - map = pci_read_config32(ctrl->f2, DRAM_BANK_ADDR_MAP); - map &= ~(0xf << (index * 4)); -#if IS_ENABLED(CONFIG_QRANK_DIMM_SUPPORT) - if (sz->rank == 4) { - map &= ~(0xf << ((index + 2) * 4)); - } -#endif - - /* Make certain side1 of the dimm is at least 128MB */ - if (sz->per_rank >= 27) { - unsigned temp_map; - temp_map = cs_map_aaa[(sz->bank-2)*3*4 + (sz->rows - 13)*3 + (sz->col - 9) ]; - map |= temp_map << (index*4); -#if IS_ENABLED(CONFIG_QRANK_DIMM_SUPPORT) - if (sz->rank == 4) { - map |= temp_map << ((index + 2) * 4); - } -#endif - } - - pci_write_config32(ctrl->f2, DRAM_BANK_ADDR_MAP, map); - -} - - -static long spd_set_ram_size(const struct mem_controller *ctrl, - struct mem_info *meminfo) -{ - int i; - - for (i = 0; i < DIMM_SOCKETS; i++) { - struct dimm_size *sz = &(meminfo->sz[i]); - u32 spd_device = ctrl->channel0[i]; - - if (!(meminfo->dimm_mask & (1 << i))) { - if (meminfo->dimm_mask & (1 << (DIMM_SOCKETS + i))) { /* channelB only? */ - spd_device = ctrl->channel1[i]; - } else { - continue; - } - } - - spd_get_dimm_size(spd_device, sz); - if (sz->per_rank == 0) { - return -1; /* Report SPD error */ - } - set_dimm_size(ctrl, sz, i, meminfo); - set_dimm_cs_map(ctrl, sz, i, meminfo); - } - return meminfo->dimm_mask; -} - -static void route_dram_accesses(const struct mem_controller *ctrl, - unsigned long base_k, unsigned long limit_k) -{ - /* Route the addresses to the controller node */ - unsigned node_id; - unsigned limit; - unsigned base; - unsigned index; - unsigned limit_reg, base_reg; - pci_devfn_t device; - - node_id = ctrl->node_id; - index = (node_id << 3); - limit = (limit_k << 2); - limit &= 0xffff0000; - limit -= 0x00010000; - limit |= (0 << 8) | (node_id << 0); - base = (base_k << 2); - base &= 0xffff0000; - base |= (0 << 8) | (1<<1) | (1<<0); - - limit_reg = 0x44 + index; - base_reg = 0x40 + index; - for (device = PCI_DEV(0, 0x18, 1); device <= PCI_DEV(0, 0x1f, 1); - device += PCI_DEV(0, 1, 0)) { - pci_write_config32(device, limit_reg, limit); - pci_write_config32(device, base_reg, base); - } -} - -static void set_top_mem(unsigned tom_k, unsigned hole_startk) -{ - /* Error if I don't have memory */ - if (!tom_k) { - die("No memory?"); - } - - /* Report the amount of memory. */ - printk(BIOS_DEBUG, "RAM end at 0x%08x kB\n", tom_k); - - /* Now set top of memory */ - msr_t msr; - if (tom_k > (4*1024*1024)) { - printk_raminit("Handling memory mapped above 4 GB\n"); - printk_raminit("Upper RAM end at 0x%08x kB\n", tom_k); - msr.lo = (tom_k & 0x003fffff) << 10; - msr.hi = (tom_k & 0xffc00000) >> 22; - wrmsr(TOP_MEM2, msr); - printk_raminit("Correcting memory amount mapped below 4 GB\n"); - } - - /* Leave a 64M hole between TOP_MEM and TOP_MEM2 - * so I can see my ROM chip and other I/O devices. - */ - if (tom_k >= 0x003f0000) { -#if CONFIG_HW_MEM_HOLE_SIZEK != 0 - if (hole_startk != 0) { - tom_k = hole_startk; - } else -#endif - tom_k = 0x3f0000; - printk_raminit("Adjusting lower RAM end\n"); - } - printk_raminit("Lower RAM end at 0x%08x kB\n", tom_k); - msr.lo = (tom_k & 0x003fffff) << 10; - msr.hi = (tom_k & 0xffc00000) >> 22; - wrmsr(TOP_MEM, msr); -} - -static unsigned long interleave_chip_selects(const struct mem_controller *ctrl, int is_Width128) -{ - /* 35 - 27 */ - - static const uint8_t csbase_low_f0_shift[] = { - /* 128MB */ (14 - (13-5)), - /* 256MB */ (15 - (13-5)), - /* 512MB */ (15 - (13-5)), - /* 512MB */ (16 - (13-5)), - /* 512MB */ (16 - (13-5)), - /* 1GB */ (16 - (13-5)), - /* 1GB */ (16 - (13-5)), - /* 2GB */ (16 - (13-5)), - /* 2GB */ (17 - (13-5)), - /* 4GB */ (17 - (13-5)), - /* 4GB */ (16 - (13-5)), - /* 8GB */ (17 - (13-5)), - }; - - /* cs_base_high is not changed */ - - uint32_t csbase_inc; - int chip_selects, index; - int bits; - unsigned common_size; - unsigned common_cs_mode; - uint32_t csbase, csmask; - - /* See if all of the memory chip selects are the same size - * and if so count them. - */ -#if defined(CMOS_VSTART_interleave_chip_selects) - if (read_option(interleave_chip_selects, 1) == 0) - return 0; -#else -#if !defined(CONFIG_INTERLEAVE_CHIP_SELECTS) || !CONFIG_INTERLEAVE_CHIP_SELECTS - return 0; -#endif -#endif - - chip_selects = 0; - common_size = 0; - common_cs_mode = 0xff; - for (index = 0; index < 8; index++) { - unsigned size; - unsigned cs_mode; - uint32_t value; - - value = pci_read_config32(ctrl->f2, DRAM_CSBASE + (index << 2)); - - /* Is it enabled? */ - if (!(value & 1)) { - continue; - } - chip_selects++; - size = (value >> 19) & 0x3ff; - if (common_size == 0) { - common_size = size; - } - /* The size differed fail */ - if (common_size != size) { - return 0; - } - - value = pci_read_config32(ctrl->f2, DRAM_BANK_ADDR_MAP); - cs_mode =(value >> ((index>>1)*4)) & 0xf; - if (common_cs_mode == 0xff) { - common_cs_mode = cs_mode; - } - /* The cs_mode differed fail */ - if (common_cs_mode != cs_mode) { - return 0; - } - } - - /* Chip selects can only be interleaved when there is - * more than one and their is a power of two of them. - */ - bits = log2(chip_selects); - if (((1 << bits) != chip_selects) || (bits < 1) || (bits > 3)) { - //chip_selects max = 8 - return 0; - } - - /* Find the bits of csbase that we need to interleave on */ - csbase_inc = 1 << (csbase_low_f0_shift[common_cs_mode]); - if (is_Width128) { - csbase_inc <<=1; - } - - /* Compute the initial values for csbase and csmask. - * In csbase just set the enable bit and the base to zero. - * In csmask set the mask bits for the size and page level interleave. - */ - csbase = 0 | 1; - csmask = (((common_size << bits) - 1) << 19); - csmask |= 0x3fe0 & ~((csbase_inc << bits) - csbase_inc); - for (index = 0; index < 8; index++) { - uint32_t value; - - value = pci_read_config32(ctrl->f2, DRAM_CSBASE + (index << 2)); - /* Is it enabled? */ - if (!(value & 1)) { - continue; - } - pci_write_config32(ctrl->f2, DRAM_CSBASE + (index << 2), csbase); - if ((index & 1) == 0) { //only have 4 CSMASK - pci_write_config32(ctrl->f2, DRAM_CSMASK + ((index>>1) << 2), csmask); - } - csbase += csbase_inc; - } - - printk(BIOS_DEBUG, "Interleaved\n"); - - /* Return the memory size in K */ - return common_size << ((27-10) + bits); -} - -static unsigned long order_chip_selects(const struct mem_controller *ctrl) -{ - unsigned long tom; - - /* Remember which registers we have used in the high 8 bits of tom */ - tom = 0; - for (;;) { - /* Find the largest remaining candidate */ - unsigned index, canidate; - uint32_t csbase, csmask; - unsigned size; - csbase = 0; - canidate = 0; - for (index = 0; index < 8; index++) { - uint32_t value; - value = pci_read_config32(ctrl->f2, DRAM_CSBASE + (index << 2)); - - /* Is it enabled? */ - if (!(value & 1)) { - continue; - } - - /* Is it greater? */ - if (value <= csbase) { - continue; - } - - /* Has it already been selected */ - if (tom & (1 << (index + 24))) { - continue; - } - /* I have a new candidate */ - csbase = value; - canidate = index; - } - - /* See if I have found a new candidate */ - if (csbase == 0) { - break; - } - - /* Remember the dimm size */ - size = csbase >> 19; - - /* Remember I have used this register */ - tom |= (1 << (canidate + 24)); - - /* Recompute the cs base register value */ - csbase = (tom << 19) | 1; - - /* Increment the top of memory */ - tom += size; - - /* Compute the memory mask */ - csmask = ((size -1) << 19); - csmask |= 0x3fe0; /* For now don't optimize */ - - /* Write the new base register */ - pci_write_config32(ctrl->f2, DRAM_CSBASE + (canidate << 2), csbase); - /* Write the new mask register */ - if ((canidate & 1) == 0) { //only have 4 CSMASK - pci_write_config32(ctrl->f2, DRAM_CSMASK + ((canidate >> 1) << 2), csmask); - } - - } - /* Return the memory size in K */ - return (tom & ~0xff000000) << (27-10); -} - -static unsigned long memory_end_k(const struct mem_controller *ctrl, int max_node_id) -{ - unsigned node_id; - unsigned end_k; - /* Find the last memory address used */ - end_k = 0; - for (node_id = 0; node_id < max_node_id; node_id++) { - uint32_t limit, base; - unsigned index; - index = node_id << 3; - base = pci_read_config32(ctrl->f1, 0x40 + index); - /* Only look at the limit if the base is enabled */ - if ((base & 3) == 3) { - limit = pci_read_config32(ctrl->f1, 0x44 + index); - end_k = ((limit + 0x00010000) & 0xffff0000) >> 2; - } - } - return end_k; -} - -static void order_dimms(const struct mem_controller *ctrl, - struct mem_info *meminfo) -{ - unsigned long tom_k, base_k; - - tom_k = interleave_chip_selects(ctrl, meminfo->is_Width128); - - if (!tom_k) { - printk(BIOS_DEBUG, "Interleaving disabled\n"); - tom_k = order_chip_selects(ctrl); - } - - /* Compute the memory base address */ - base_k = memory_end_k(ctrl, ctrl->node_id); - tom_k += base_k; - route_dram_accesses(ctrl, base_k, tom_k); - set_top_mem(tom_k, 0); -} - -static long disable_dimm(const struct mem_controller *ctrl, unsigned index, - struct mem_info *meminfo) -{ - printk(BIOS_DEBUG, "disabling dimm %02x\n", index); - if (!(meminfo->dimm_mask & 0x0F) && (meminfo->dimm_mask & 0xF0)) { /* channelB only? */ - pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1) + 4) << 2), 0); - pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1) + 5) << 2), 0); - } else { - pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1) + 0) << 2), 0); - pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1) + 1) << 2), 0); -#if IS_ENABLED(CONFIG_QRANK_DIMM_SUPPORT) - if (meminfo->sz[index].rank == 4) { - pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1) + 4) << 2), 0); - pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1) + 5) << 2), 0); - } -#endif - } - - meminfo->dimm_mask &= ~(1 << index); - return meminfo->dimm_mask; -} - -static long spd_handle_unbuffered_dimms(const struct mem_controller *ctrl, - struct mem_info *meminfo) -{ - int i; - uint32_t registered; - uint32_t dcl; - registered = 0; - for (i = 0; (i < DIMM_SOCKETS); i++) { - int value; - u32 spd_device = ctrl->channel0[i]; - if (!(meminfo->dimm_mask & (1 << i))) { - if (meminfo->dimm_mask & (1 << (DIMM_SOCKETS + i))) { /* channelB only? */ - spd_device = ctrl->channel1[i]; - } else { - continue; - } - } - value = spd_read_byte(spd_device, SPD_DIMM_TYPE); - if (value < 0) { - return -1; - } - - /* Registered dimm ? */ - value &= 0x3f; - if ((value == SPD_DIMM_TYPE_RDIMM) || (value == SPD_DIMM_TYPE_mRDIMM)) { - //check SPD_MOD_ATTRIB to verify it is SPD_MOD_ATTRIB_REGADC (0x11)? - registered |= (1<<i); - } - } - - if (is_opteron(ctrl)) { - } - - - dcl = pci_read_config32(ctrl->f2, DRAM_CONFIG_LOW); - dcl &= ~DCL_UnBuffDimm; - meminfo->is_registered = 1; - if (!registered) { - dcl |= DCL_UnBuffDimm; - meminfo->is_registered = 0; - } - pci_write_config32(ctrl->f2, DRAM_CONFIG_LOW, dcl); - - if (meminfo->is_registered) { - printk(BIOS_SPEW, "Registered\n"); - } else { - printk(BIOS_SPEW, "Unbuffered\n"); - } - return meminfo->dimm_mask; -} - -static unsigned int spd_detect_dimms(const struct mem_controller *ctrl) -{ - unsigned dimm_mask; - int i; - dimm_mask = 0; - for (i = 0; i < DIMM_SOCKETS; i++) { - int byte; - unsigned device; - device = ctrl->channel0[i]; - printk_raminit("DIMM socket %i, channel 0 SPD device is 0x%02x\n", i, device); - if (device) { - byte = spd_read_byte(ctrl->channel0[i], SPD_MEM_TYPE); /* Type */ - if (byte == SPD_MEM_TYPE_SDRAM_DDR2) { - printk_raminit("\tDIMM detected\n"); - dimm_mask |= (1 << i); - } - } - device = ctrl->channel1[i]; - printk_raminit("DIMM socket %i, channel 1 SPD device is 0x%02x\n", i, device); - if (device) { - byte = spd_read_byte(ctrl->channel1[i], SPD_MEM_TYPE); - if (byte == SPD_MEM_TYPE_SDRAM_DDR2) { - printk_raminit("\tDIMM detected\n"); - dimm_mask |= (1 << (i + DIMM_SOCKETS)); - } - } - } - return dimm_mask; -} - -static long spd_enable_2channels(const struct mem_controller *ctrl, struct mem_info *meminfo) -{ - int i; - uint32_t nbcap; - /* SPD addresses to verify are identical */ - static const uint8_t addresses[] = { - 2, /* Type should be DDR2 SDRAM */ - 3, /* *Row addresses */ - 4, /* *Column addresses */ - 5, /* *Number of DIMM Ranks */ - 6, /* *Module Data Width*/ - 11, /* *DIMM Conf Type */ - 13, /* *Pri SDRAM Width */ - 17, /* *Logical Banks */ - 20, /* *DIMM Type Info */ - 21, /* *SDRAM Module Attributes */ - 27, /* *tRP Row precharge time */ - 28, /* *Minimum Row Active to Row Active Delay (tRRD) */ - 29, /* *tRCD RAS to CAS */ - 30, /* *tRAS Activate to Precharge */ - 36, /* *Write recovery time (tWR) */ - 37, /* *Internal write to read command delay (tRDP) */ - 38, /* *Internal read to precharge command delay (tRTP) */ - 40, /* *Extension of Byte 41 tRC and Byte 42 tRFC */ - 41, /* *Minimum Active to Active/Auto Refresh Time(Trc) */ - 42, /* *Minimum Auto Refresh Command Time(Trfc) */ - /* The SPD addresses 18, 9, 23, 26 need special treatment like - * in spd_set_memclk. Right now they cause many false negatives. - * Keep them at the end to see other mismatches (if any). - */ - 18, /* *Supported CAS Latencies */ - 9, /* *Cycle time at highest CAS Latency CL=X */ - 23, /* *Cycle time at CAS Latency (CLX - 1) */ - 25, /* *Cycle time at CAS Latency (CLX - 2) */ - }; - u32 dcl, dcm; - u8 common_cl; - -/* S1G1 and AM2 sockets are Mod64BitMux capable. */ -#if CONFIG_CPU_SOCKET_TYPE == 0x11 || CONFIG_CPU_SOCKET_TYPE == 0x12 - u8 mux_cap = 1; -#else - u8 mux_cap = 0; -#endif - - /* If the dimms are not in pairs do not do dual channels */ - if ((meminfo->dimm_mask & ((1 << DIMM_SOCKETS) - 1)) != - ((meminfo->dimm_mask >> DIMM_SOCKETS) & ((1 << DIMM_SOCKETS) - 1))) { - goto single_channel; - } - /* If the CPU is not capable of doing dual channels don't do dual channels */ - nbcap = pci_read_config32(ctrl->f3, NORTHBRIDGE_CAP); - if (!(nbcap & NBCAP_128Bit)) { - goto single_channel; - } - for (i = 0; (i < 4) && (ctrl->channel0[i]); i++) { - unsigned device0, device1; - int value0, value1; - int j; - /* If I don't have a dimm skip this one */ - if (!(meminfo->dimm_mask & (1 << i))) { - continue; - } - device0 = ctrl->channel0[i]; - device1 = ctrl->channel1[i]; - /* Abort if the chips don't support a common CAS latency. */ - common_cl = spd_read_byte(device0, 18) & spd_read_byte(device1, 18); - if (!common_cl) { - printk(BIOS_DEBUG, "No common CAS latency supported\n"); - goto single_channel; - } else { - printk_raminit("Common CAS latency bitfield: 0x%02x\n", common_cl); - } - for (j = 0; j < ARRAY_SIZE(addresses); j++) { - unsigned addr; - addr = addresses[j]; - value0 = spd_read_byte(device0, addr); - if (value0 < 0) { - return -1; - } - value1 = spd_read_byte(device1, addr); - if (value1 < 0) { - return -1; - } - if (value0 != value1) { - printk_raminit("SPD values differ between channel 0/1 for byte %i\n", addr); - goto single_channel; - } - } - } - printk(BIOS_SPEW, "Enabling dual channel memory\n"); - dcl = pci_read_config32(ctrl->f2, DRAM_CONFIG_LOW); - dcl &= ~DCL_BurstLength32; /* 32byte mode may be preferred in platforms that include graphics controllers that generate a lot of 32-bytes system memory accesses - 32byte mode is not supported when the DRAM interface is 128 bits wide, even 32byte mode is set, system still use 64 byte mode */ - dcl |= DCL_Width128; - pci_write_config32(ctrl->f2, DRAM_CONFIG_LOW, dcl); - meminfo->is_Width128 = 1; - return meminfo->dimm_mask; - - single_channel: - meminfo->is_Width128 = 0; - meminfo->is_64MuxMode = 0; - - /* single dimm */ - if ((meminfo->dimm_mask & ((1 << DIMM_SOCKETS) - 1)) != - ((meminfo->dimm_mask >> DIMM_SOCKETS) & ((1 << DIMM_SOCKETS) - 1))) { - if (((meminfo->dimm_mask >> DIMM_SOCKETS) & ((1 << DIMM_SOCKETS) - 1))) { - /* mux capable and single dimm in channelB */ - if (mux_cap) { - printk(BIOS_SPEW, "Enable 64MuxMode & BurstLength32\n"); - dcm = pci_read_config32(ctrl->f2, DRAM_CTRL_MISC); - dcm |= DCM_Mode64BitMux; - pci_write_config32(ctrl->f2, DRAM_CTRL_MISC, dcm); - dcl = pci_read_config32(ctrl->f2, DRAM_CONFIG_LOW); - pci_write_config32(ctrl->f2, DRAM_CONFIG_LOW, dcl); - meminfo->is_64MuxMode = 1; - } else { - meminfo->dimm_mask &= ~((1 << (DIMM_SOCKETS * 2)) - (1 << DIMM_SOCKETS)); - } - } - } else { /* unmatched dual dimms ? */ - /* unmatched dual dimms not supported by meminit code. Use single channelA dimm. */ - meminfo->dimm_mask &= ~((1 << (DIMM_SOCKETS * 2)) - (1 << DIMM_SOCKETS)); - printk(BIOS_SPEW, "Unmatched dual dimms. Use single channelA dimm.\n"); - } - return meminfo->dimm_mask; -} - -struct mem_param { - uint16_t cycle_time; - uint8_t divisor; /* In 1/40 ns increments */ - uint8_t TrwtTO; - uint8_t Twrrd; - uint8_t Twrwr; - uint8_t Trdrd; - uint8_t DcqByPassMax; - uint32_t dch_memclk; - char name[9]; -}; - - static const struct mem_param speed[] = { - { - .name = "200MHz", - .cycle_time = 0x500, - .divisor = 200, // how many 1/40ns per clock - .dch_memclk = DCH_MemClkFreq_200MHz, //0 - .TrwtTO = 7, - .Twrrd = 2, - .Twrwr = 2, - .Trdrd = 3, - .DcqByPassMax = 4, - - }, - { - .name = "266MHz", - .cycle_time = 0x375, - .divisor = 150, //???? - .dch_memclk = DCH_MemClkFreq_266MHz, //1 - .TrwtTO = 7, - .Twrrd = 2, - .Twrwr = 2, - .Trdrd = 3, - .DcqByPassMax = 4, - }, - { - .name = "333MHz", - .cycle_time = 0x300, - .divisor = 120, - .dch_memclk = DCH_MemClkFreq_333MHz, //2 - .TrwtTO = 7, - .Twrrd = 2, - .Twrwr = 2, - .Trdrd = 3, - .DcqByPassMax = 4, - - }, - { - .name = "400MHz", - .cycle_time = 0x250, - .divisor = 100, - .dch_memclk = DCH_MemClkFreq_400MHz,//3 - .TrwtTO = 7, - .Twrrd = 2, - .Twrwr = 2, - .Trdrd = 3, - .DcqByPassMax = 4, - }, - { - .cycle_time = 0x000, - }, - }; - -static const struct mem_param *get_mem_param(unsigned min_cycle_time) -{ - - const struct mem_param *param; - for (param = &speed[0]; param->cycle_time; param++) { - if (min_cycle_time > (param+1)->cycle_time) { - break; - } - } - if (!param->cycle_time) { - die("min_cycle_time to low"); - } - printk(BIOS_SPEW, "%s\n", param->name); - return param; -} - -static uint8_t get_exact_divisor(int i, uint8_t divisor) -{ - //input divisor could be 200(200), 150(266), 120(333), 100 (400) - static const uint8_t dv_a[] = { - /* 200 266 333 400 */ - /*4 */ 250, 250, 250, 250, - /*5 */ 200, 200, 200, 100, - /*6 */ 200, 166, 166, 100, - /*7 */ 200, 171, 142, 100, - - /*8 */ 200, 150, 125, 100, - /*9 */ 200, 156, 133, 100, - /*10*/ 200, 160, 120, 100, - /*11*/ 200, 163, 127, 100, - - /*12*/ 200, 150, 133, 100, - /*13*/ 200, 153, 123, 100, - /*14*/ 200, 157, 128, 100, - /*15*/ 200, 160, 120, 100, - }; - - - int index; - msr_t msr; - - /* Check for FID control support */ - struct cpuid_result cpuid1; - cpuid1 = cpuid(0x80000007); - if (cpuid1.edx & 0x02) { - /* Use current FID */ - unsigned fid_cur; - msr = rdmsr(0xc0010042); - fid_cur = msr.lo & 0x3f; - - index = fid_cur>>1; - } else { - /* Use startup FID */ - unsigned fid_start; - msr = rdmsr(0xc0010015); - fid_start = (msr.lo & (0x3f << 24)); - - index = fid_start>>25; - } - - if (index > 12) return divisor; - - if (i > 3) return divisor; - - return dv_a[index * 4+i]; - -} - - -struct spd_set_memclk_result { - const struct mem_param *param; - long dimm_mask; -}; - - -static unsigned convert_to_linear(unsigned value) -{ - static const unsigned fraction[] = { 0x25, 0x33, 0x66, 0x75 }; - unsigned valuex; - - /* We need to convert value to more readable */ - if ((value & 0xf) < 10) { //no .25, .33, .66, .75 - value <<= 4; - } else { - valuex = ((value & 0xf0) << 4) | fraction [(value & 0xf)-10]; - value = valuex; - } - return value; -} - -static const uint8_t latency_indicies[] = { 25, 23, 9 }; - -static int find_optimum_spd_latency(u32 spd_device, unsigned *min_latency, unsigned *min_cycle_time) -{ - int new_cycle_time, new_latency; - int index; - int latencies; - int latency; - - /* First find the supported CAS latencies - * Byte 18 for DDR SDRAM is interpreted: - * bit 3 == CAS Latency = 3 - * bit 4 == CAS Latency = 4 - * bit 5 == CAS Latency = 5 - * bit 6 == CAS Latency = 6 - */ - new_cycle_time = 0x500; - new_latency = 6; - - latencies = spd_read_byte(spd_device, SPD_CAS_LAT); - if (latencies <= 0) - return 1; - - printk_raminit("\tlatencies: %08x\n", latencies); - /* Compute the lowest cas latency which can be expressed in this - * particular SPD EEPROM. You can store at most settings for 3 - * contiguous CAS latencies, so by taking the highest CAS - * latency marked as supported in the SPD and subtracting 2 you - * get the lowest expressible CAS latency. That latency is not - * necessarily supported, but a (maybe invalid) entry exists - * for it. - */ - latency = log2(latencies) - 2; - - /* Loop through and find a fast clock with a low latency */ - for (index = 0; index < 3; index++, latency++) { - int value; - if ((latency < 3) || (latency > 6) || - (!(latencies & (1 << latency)))) { - continue; - } - value = spd_read_byte(spd_device, latency_indicies[index]); - if (value < 0) { - return -1; - } - - printk_raminit("\tindex: %08x\n", index); - printk_raminit("\t\tlatency: %08x\n", latency); - printk_raminit("\t\tvalue1: %08x\n", value); - - value = convert_to_linear(value); - - printk_raminit("\t\tvalue2: %08x\n", value); - - /* Only increase the latency if we decrease the clock */ - if (value >= *min_cycle_time) { - if (value < new_cycle_time) { - new_cycle_time = value; - new_latency = latency; - } else if (value == new_cycle_time) { - if (new_latency > latency) { - new_latency = latency; - } - } - } - printk_raminit("\t\tnew_cycle_time: %08x\n", new_cycle_time); - printk_raminit("\t\tnew_latency: %08x\n", new_latency); - - } - - if (new_latency > 6) { - return 1; - } - - /* Does min_latency need to be increased? */ - if (new_cycle_time > *min_cycle_time) { - *min_cycle_time = new_cycle_time; - } - - /* Does min_cycle_time need to be increased? */ - if (new_latency > *min_latency) { - *min_latency = new_latency; - } - - printk_raminit("2 min_cycle_time: %08x\n", *min_cycle_time); - printk_raminit("2 min_latency: %08x\n", *min_latency); - - return 0; -} - -static struct spd_set_memclk_result spd_set_memclk(const struct mem_controller *ctrl, struct mem_info *meminfo) -{ - /* Compute the minimum cycle time for these dimms */ - struct spd_set_memclk_result result; - unsigned min_cycle_time, min_latency, bios_cycle_time; - int i; - uint32_t value; - - static const uint16_t min_cycle_times[] = { // use full speed to compare - [NBCAP_MEMCLK_NOLIMIT] = 0x250, /*2.5ns */ - [NBCAP_MEMCLK_333MHZ] = 0x300, /* 3.0ns */ - [NBCAP_MEMCLK_266MHZ] = 0x375, /* 3.75ns */ - [NBCAP_MEMCLK_200MHZ] = 0x500, /* 5.0s */ - }; - - - value = pci_read_config32(ctrl->f3, NORTHBRIDGE_CAP); - min_cycle_time = min_cycle_times[(value >> NBCAP_MEMCLK_SHIFT) & NBCAP_MEMCLK_MASK]; - bios_cycle_time = min_cycle_times[ -#ifdef CMOS_VSTART_max_mem_clock - read_option(max_mem_clock, 0) -#else -#if defined(CONFIG_MAX_MEM_CLOCK) - CONFIG_MAX_MEM_CLOCK -#else - 0 // use DDR400 as default -#endif -#endif - ]; - - if (bios_cycle_time > min_cycle_time) { - min_cycle_time = bios_cycle_time; - } - min_latency = 3; - - printk_raminit("1 min_cycle_time: %08x\n", min_cycle_time); - - /* Compute the least latency with the fastest clock supported - * by both the memory controller and the dimms. - */ - for (i = 0; i < DIMM_SOCKETS; i++) { - u32 spd_device; - - printk_raminit("1.1 dimm_mask: %08x\n", meminfo->dimm_mask); - printk_raminit("i: %08x\n",i); - - if (meminfo->dimm_mask & (1 << i)) { - spd_device = ctrl->channel0[i]; - printk_raminit("Channel 0 settings:\n"); - - switch (find_optimum_spd_latency(spd_device, &min_latency, &min_cycle_time)) { - case -1: - goto hw_error; - break; - case 1: - continue; - } - } - if (meminfo->dimm_mask & (1 << (DIMM_SOCKETS + i))) { - spd_device = ctrl->channel1[i]; - printk_raminit("Channel 1 settings:\n"); - - switch (find_optimum_spd_latency(spd_device, &min_latency, &min_cycle_time)) { - case -1: - goto hw_error; - break; - case 1: - continue; - } - } - - } - /* Make a second pass through the dimms and disable - * any that cannot support the selected memclk and cas latency. - */ - - printk_raminit("3 min_cycle_time: %08x\n", min_cycle_time); - printk_raminit("3 min_latency: %08x\n", min_latency); - - for (i = 0; (i < DIMM_SOCKETS); i++) { - int latencies; - int latency; - int index; - int val; - u32 spd_device = ctrl->channel0[i]; - - if (!(meminfo->dimm_mask & (1 << i))) { - if (meminfo->dimm_mask & (1 << (DIMM_SOCKETS + i))) { /* channelB only? */ - spd_device = ctrl->channel1[i]; - } else { - continue; - } - } - - latencies = spd_read_byte(spd_device, SPD_CAS_LAT); - if (latencies < 0) goto hw_error; - if (latencies == 0) { - continue; - } - - /* Compute the lowest cas latency supported */ - latency = log2(latencies) -2; - - /* Walk through searching for the selected latency */ - for (index = 0; index < 3; index++, latency++) { - if (!(latencies & (1 << latency))) { - continue; - } - if (latency == min_latency) - break; - } - /* If I can't find the latency or my index is bad error */ - if ((latency != min_latency) || (index >= 3)) { - goto dimm_err; - } - - /* Read the min_cycle_time for this latency */ - val = spd_read_byte(spd_device, latency_indicies[index]); - if (val < 0) goto hw_error; - - val = convert_to_linear(val); - /* All is good if the selected clock speed - * is what I need or slower. - */ - if (val <= min_cycle_time) { - continue; - } - /* Otherwise I have an error, disable the dimm */ - dimm_err: - meminfo->dimm_mask = disable_dimm(ctrl, i, meminfo); - } - - printk_raminit("4 min_cycle_time: %08x\n", min_cycle_time); - - /* Now that I know the minimum cycle time lookup the memory parameters */ - result.param = get_mem_param(min_cycle_time); - - /* Update DRAM Config High with our selected memory speed */ - value = pci_read_config32(ctrl->f2, DRAM_CONFIG_HIGH); - value &= ~(DCH_MemClkFreq_MASK << DCH_MemClkFreq_SHIFT); - - value |= result.param->dch_memclk << DCH_MemClkFreq_SHIFT; - pci_write_config32(ctrl->f2, DRAM_CONFIG_HIGH, value); - - printk(BIOS_DEBUG, "%s\n", result.param->name); - - /* Update DRAM Timing Low with our selected cas latency */ - value = pci_read_config32(ctrl->f2, DRAM_TIMING_LOW); - value &= ~(DTL_TCL_MASK << DTL_TCL_SHIFT); - value |= (min_latency - DTL_TCL_BASE) << DTL_TCL_SHIFT; - pci_write_config32(ctrl->f2, DRAM_TIMING_LOW, value); - - result.dimm_mask = meminfo->dimm_mask; - return result; - hw_error: - result.param = (const struct mem_param *)0; - result.dimm_mask = -1; - return result; -} - -static unsigned convert_to_1_4(unsigned value) -{ - static const uint8_t fraction[] = { 0, 1, 2, 2, 3, 3, 0 }; - unsigned valuex; - - /* We need to convert value to more readable */ - valuex = fraction [value & 0x7]; - return valuex; -} - -static int get_dimm_Trc_clocks(u32 spd_device, const struct mem_param *param) -{ - int value; - int value2; - int clocks; - value = spd_read_byte(spd_device, SPD_TRC); - if (value < 0) - return -1; - printk_raminit("update_dimm_Trc: tRC (41) = %08x\n", value); - - value2 = spd_read_byte(spd_device, SPD_TRC -1); - value <<= 2; - value += convert_to_1_4(value2>>4); - - value *= 10; - printk_raminit("update_dimm_Trc: tRC final value = %i\n", value); - - clocks = CEIL_DIV(value, param->divisor); - printk_raminit("update_dimm_Trc: clocks = %i\n", clocks); - - if (clocks < DTL_TRC_MIN) { - // We might want to die here instead or (at least|better) disable this bank. - printk(BIOS_NOTICE, "update_dimm_Trc: Can't refresh fast enough, " - "want %i clocks, minimum is %i clocks.\n", clocks, DTL_TRC_MIN); - clocks = DTL_TRC_MIN; - } - return clocks; -} - -static int update_dimm_Trc(const struct mem_controller *ctrl, - const struct mem_param *param, - int i, long dimm_mask) -{ - int clocks, old_clocks; - uint32_t dtl; - u32 spd_device = ctrl->channel0[i]; - - if (!(dimm_mask & (1 << i)) && (dimm_mask & (1 << (DIMM_SOCKETS + i)))) { /* channelB only? */ - spd_device = ctrl->channel1[i]; - } - - clocks = get_dimm_Trc_clocks(spd_device, param); - if (clocks == -1) - return clocks; - if (clocks > DTL_TRC_MAX) { - return 0; - } - printk_raminit("update_dimm_Trc: clocks after adjustment = %i\n", clocks); - - dtl = pci_read_config32(ctrl->f2, DRAM_TIMING_LOW); - old_clocks = ((dtl >> DTL_TRC_SHIFT) & DTL_TRC_MASK) + DTL_TRC_BASE; - if (old_clocks >= clocks) { //?? someone did it - // clocks = old_clocks; - return 1; - } - dtl &= ~(DTL_TRC_MASK << DTL_TRC_SHIFT); - dtl |= ((clocks - DTL_TRC_BASE) << DTL_TRC_SHIFT); - pci_write_config32(ctrl->f2, DRAM_TIMING_LOW, dtl); - return 1; -} - -static int update_dimm_Trfc(const struct mem_controller *ctrl, const struct mem_param *param, int i, struct mem_info *meminfo) -{ - unsigned clocks, old_clocks; - uint32_t dth; - int value; - u8 ch_b = 0; - u32 spd_device = ctrl->channel0[i]; - - if (!(meminfo->dimm_mask & (1 << i)) && (meminfo->dimm_mask & (1 << (DIMM_SOCKETS + i)))) { /* channelB only? */ - spd_device = ctrl->channel1[i]; - ch_b = 2; /* offset to channelB trfc setting */ - } - - //get the cs_size --> logic dimm size - value = spd_read_byte(spd_device, SPD_PRI_WIDTH); - if (value < 0) { - return -1; - } - - value = 6 - log2(value); //4-->4, 8-->3, 16-->2 - - clocks = meminfo->sz[i].per_rank - 27 + 2 - value; - - dth = pci_read_config32(ctrl->f2, DRAM_TIMING_HIGH); - - old_clocks = ((dth >> (DTH_TRFC0_SHIFT + ((i + ch_b) * 3))) & DTH_TRFC_MASK); - - if (old_clocks >= clocks) { // some one did it? - return 1; - } - dth &= ~(DTH_TRFC_MASK << (DTH_TRFC0_SHIFT + ((i + ch_b) * 3))); - dth |= clocks << (DTH_TRFC0_SHIFT + ((i + ch_b) * 3)); - pci_write_config32(ctrl->f2, DRAM_TIMING_HIGH, dth); - return 1; -} - -static int update_dimm_TT_1_4(const struct mem_controller *ctrl, const struct mem_param *param, int i, long dimm_mask, - unsigned TT_REG, - unsigned SPD_TT, unsigned TT_SHIFT, unsigned TT_MASK, unsigned TT_BASE, unsigned TT_MIN, unsigned TT_MAX) -{ - unsigned clocks, old_clocks; - uint32_t dtl; - int value; - u32 spd_device = ctrl->channel0[i]; - - if (!(dimm_mask & (1 << i)) && (dimm_mask & (1 << (DIMM_SOCKETS + i)))) { /* channelB only? */ - spd_device = ctrl->channel1[i]; - } - - value = spd_read_byte(spd_device, SPD_TT); //already in 1/4 ns - if (value < 0) return -1; - value *=10; - clocks = CEIL_DIV(value, param->divisor); - if (clocks < TT_MIN) { - clocks = TT_MIN; - } - - if (clocks > TT_MAX) { - printk(BIOS_INFO, "warning spd byte : %x = %x > TT_MAX: %x, setting TT_MAX", SPD_TT, value, TT_MAX); - clocks = TT_MAX; - } - - dtl = pci_read_config32(ctrl->f2, TT_REG); - - old_clocks = ((dtl >> TT_SHIFT) & TT_MASK) + TT_BASE; - if (old_clocks >= clocks) { //some one did it? - return 1; - } - dtl &= ~(TT_MASK << TT_SHIFT); - dtl |= ((clocks - TT_BASE) << TT_SHIFT); - pci_write_config32(ctrl->f2, TT_REG, dtl); - return 1; -} - -static int update_dimm_Trcd(const struct mem_controller *ctrl, - const struct mem_param *param, int i, long dimm_mask) -{ - return update_dimm_TT_1_4(ctrl, param, i, dimm_mask, DRAM_TIMING_LOW, SPD_TRCD, DTL_TRCD_SHIFT, DTL_TRCD_MASK, DTL_TRCD_BASE, DTL_TRCD_MIN, DTL_TRCD_MAX); -} - -static int update_dimm_Trrd(const struct mem_controller *ctrl, const struct mem_param *param, int i, long dimm_mask) -{ - return update_dimm_TT_1_4(ctrl, param, i, dimm_mask, DRAM_TIMING_LOW, SPD_TRRD, DTL_TRRD_SHIFT, DTL_TRRD_MASK, DTL_TRRD_BASE, DTL_TRRD_MIN, DTL_TRRD_MAX); -} - -static int update_dimm_Tras(const struct mem_controller *ctrl, const struct mem_param *param, int i, long dimm_mask) -{ - unsigned clocks, old_clocks; - uint32_t dtl; - int value; - u32 spd_device = ctrl->channel0[i]; - - if (!(dimm_mask & (1 << i)) && (dimm_mask & (1 << (DIMM_SOCKETS + i)))) { /* channelB only? */ - spd_device = ctrl->channel1[i]; - } - - value = spd_read_byte(spd_device, SPD_TRAS); //in 1 ns - if (value < 0) return -1; - printk_raminit("update_dimm_Tras: 0 value= %08x\n", value); - - value <<= 2; //convert it to in 1/4ns - - value *= 10; - printk_raminit("update_dimm_Tras: 1 value= %08x\n", value); - - clocks = CEIL_DIV(value, param->divisor); - printk_raminit("update_dimm_Tras: divisor= %08x\n", param->divisor); - printk_raminit("update_dimm_Tras: clocks= %08x\n", clocks); - if (clocks < DTL_TRAS_MIN) { - clocks = DTL_TRAS_MIN; - } - if (clocks > DTL_TRAS_MAX) { - return 0; - } - dtl = pci_read_config32(ctrl->f2, DRAM_TIMING_LOW); - old_clocks = ((dtl >> DTL_TRAS_SHIFT) & DTL_TRAS_MASK) + DTL_TRAS_BASE; - if (old_clocks >= clocks) { // someone did it? - return 1; - } - dtl &= ~(DTL_TRAS_MASK << DTL_TRAS_SHIFT); - dtl |= ((clocks - DTL_TRAS_BASE) << DTL_TRAS_SHIFT); - pci_write_config32(ctrl->f2, DRAM_TIMING_LOW, dtl); - return 1; -} - -static int update_dimm_Trp(const struct mem_controller *ctrl, - const struct mem_param *param, int i, long dimm_mask) -{ - return update_dimm_TT_1_4(ctrl, param, i, dimm_mask, DRAM_TIMING_LOW, SPD_TRP, DTL_TRP_SHIFT, DTL_TRP_MASK, DTL_TRP_BASE, DTL_TRP_MIN, DTL_TRP_MAX); -} - - -static int update_dimm_Trtp(const struct mem_controller *ctrl, - const struct mem_param *param, int i, struct mem_info *meminfo) -{ - /* need to figure if it is 32 byte burst or 64 bytes burst */ - int offset = 2; - if (!meminfo->is_Width128) { - uint32_t dword; - dword = pci_read_config32(ctrl->f2, DRAM_CONFIG_LOW); - if ((dword & DCL_BurstLength32)) offset = 0; - } - return update_dimm_TT_1_4(ctrl, param, i, meminfo->dimm_mask, DRAM_TIMING_LOW, SPD_TRTP, DTL_TRTP_SHIFT, DTL_TRTP_MASK, DTL_TRTP_BASE+offset, DTL_TRTP_MIN+offset, DTL_TRTP_MAX+offset); -} - - -static int update_dimm_Twr(const struct mem_controller *ctrl, const struct mem_param *param, int i, long dimm_mask) -{ - return update_dimm_TT_1_4(ctrl, param, i, dimm_mask, DRAM_TIMING_LOW, SPD_TWR, DTL_TWR_SHIFT, DTL_TWR_MASK, DTL_TWR_BASE, DTL_TWR_MIN, DTL_TWR_MAX); -} - - -static int update_dimm_Tref(const struct mem_controller *ctrl, - const struct mem_param *param, int i, long dimm_mask) -{ - uint32_t dth, dth_old; - int value; - u32 spd_device = ctrl->channel0[i]; - - if (!(dimm_mask & (1 << i)) && (dimm_mask & (1 << (DIMM_SOCKETS + i)))) { /* channelB only? */ - spd_device = ctrl->channel1[i]; - } - - value = spd_read_byte(spd_device, SPD_TREF); // 0: 15.625us, 1: 3.9us 2: 7.8 us.... - if (value < 0) return -1; - - if (value == 1) { - value = 3; - } else { - value = 2; - } - - dth = pci_read_config32(ctrl->f2, DRAM_TIMING_HIGH); - - dth_old = dth; - dth &= ~(DTH_TREF_MASK << DTH_TREF_SHIFT); - dth |= (value << DTH_TREF_SHIFT); - if (dth_old != dth) { - pci_write_config32(ctrl->f2, DRAM_TIMING_HIGH, dth); - } - return 1; -} - -static void set_4RankRDimm(const struct mem_controller *ctrl, - const struct mem_param *param, struct mem_info *meminfo) -{ -#if IS_ENABLED(CONFIG_QRANK_DIMM_SUPPORT) - int value; - int i; - long dimm_mask = meminfo->dimm_mask; - - - if (!(meminfo->is_registered)) return; - - value = 0; - - for (i = 0; i < DIMM_SOCKETS; i++) { - if (!(dimm_mask & (1 << i))) { - continue; - } - - if (meminfo->sz[i].rank == 4) { - value = 1; - break; - } - } - - if (value == 1) { - uint32_t dch; - dch = pci_read_config32(ctrl->f2, DRAM_CONFIG_HIGH); - dch |= DCH_FourRankRDimm; - pci_write_config32(ctrl->f2, DRAM_CONFIG_HIGH, dch); - } -#endif -} - -static uint32_t get_extra_dimm_mask(const struct mem_controller *ctrl, - struct mem_info *meminfo) -{ - int i; - - uint32_t mask_x4; - uint32_t mask_x16; - uint32_t mask_single_rank; - uint32_t mask_page_1k; - int value; -#if IS_ENABLED(CONFIG_QRANK_DIMM_SUPPORT) - int rank; -#endif - - long dimm_mask = meminfo->dimm_mask; - - - mask_x4 = 0; - mask_x16 = 0; - mask_single_rank = 0; - mask_page_1k = 0; - - for (i = 0; i < DIMM_SOCKETS; i++) { - u32 spd_device = ctrl->channel0[i]; - if (!(dimm_mask & (1 << i))) { - if (dimm_mask & (1 << (DIMM_SOCKETS + i))) { /* channelB only? */ - spd_device = ctrl->channel1[i]; - } else { - continue; - } - } - - if (meminfo->sz[i].rank == 1) { - mask_single_rank |= 1<<i; - } - - if (meminfo->sz[i].col == 10) { - mask_page_1k |= 1<<i; - } - - - value = spd_read_byte(spd_device, SPD_PRI_WIDTH); - - #if IS_ENABLED(CONFIG_QRANK_DIMM_SUPPORT) - rank = meminfo->sz[i].rank; - #endif - - if (value == 4) { - mask_x4 |= (1<<i); - #if IS_ENABLED(CONFIG_QRANK_DIMM_SUPPORT) - if (rank == 4) { - mask_x4 |= 1<<(i+2); - } - #endif - } else if (value == 16) { - mask_x16 |= (1<<i); - #if IS_ENABLED(CONFIG_QRANK_DIMM_SUPPORT) - if (rank == 4) { - mask_x16 |= 1<<(i+2); - } - #endif - } - - } - - meminfo->x4_mask= mask_x4; - meminfo->x16_mask = mask_x16; - - meminfo->single_rank_mask = mask_single_rank; - meminfo->page_1k_mask = mask_page_1k; - - return mask_x4; - -} - - -static void set_dimm_x4(const struct mem_controller *ctrl, const struct mem_param *param, struct mem_info *meminfo) -{ - uint32_t dcl; - dcl = pci_read_config32(ctrl->f2, DRAM_CONFIG_LOW); - dcl &= ~(DCL_X4Dimm_MASK<<DCL_X4Dimm_SHIFT); - dcl |= ((meminfo->x4_mask) & 0xf) << (DCL_X4Dimm_SHIFT); - pci_write_config32(ctrl->f2, DRAM_CONFIG_LOW, dcl); -} - - -static int count_ones(uint32_t dimm_mask) -{ - int dimms; - unsigned index; - dimms = 0; - for (index = 0; index < (2 * DIMM_SOCKETS); index++, dimm_mask >>= 1) { - if (dimm_mask & 1) { - dimms++; - } - } - return dimms; -} - - -static void set_DramTerm(const struct mem_controller *ctrl, - const struct mem_param *param, struct mem_info *meminfo) -{ - uint32_t dcl; - unsigned odt; - odt = 1; // 75 ohms - - if (param->divisor == 100) { //DDR2 800 - if (meminfo->is_Width128) { - if (count_ones(meminfo->dimm_mask & 0x0f) == 2) { - odt = 3; //50 ohms - } - } - - } - - -#if CONFIG_DIMM_SUPPORT == 0x0204 - odt = 0x2; /* 150 ohms */ -#endif - - dcl = pci_read_config32(ctrl->f2, DRAM_CONFIG_LOW); - dcl &= ~(DCL_DramTerm_MASK<<DCL_DramTerm_SHIFT); - dcl |= (odt & DCL_DramTerm_MASK) << (DCL_DramTerm_SHIFT); - pci_write_config32(ctrl->f2, DRAM_CONFIG_LOW, dcl); -} - -static void set_ecc(const struct mem_controller *ctrl, - const struct mem_param *param, struct mem_info *meminfo) -{ - int i; - int value; - - uint32_t dcl, nbcap; - nbcap = pci_read_config32(ctrl->f3, NORTHBRIDGE_CAP); - dcl = pci_read_config32(ctrl->f2, DRAM_CONFIG_LOW); - dcl &= ~DCL_DimmEccEn; - if (nbcap & NBCAP_ECC) { - dcl |= DCL_DimmEccEn; - } -#ifdef CMOS_VSTART_ECC_memory - if (read_option(ECC_memory, 1) == 0) { - dcl &= ~DCL_DimmEccEn; - } -#else // CMOS_VSTART_ECC_memory not defined -#if 1 // was !IS_ENABLED CONFIG_ECC_MEMORY - dcl &= ~DCL_DimmEccEn; -#endif -#endif - pci_write_config32(ctrl->f2, DRAM_CONFIG_LOW, dcl); - - meminfo->is_ecc = 1; - if (!(dcl & DCL_DimmEccEn)) { - meminfo->is_ecc = 0; - printk(BIOS_DEBUG, "set_ecc: ECC disabled\n"); - return; // already disabled the ECC, so don't need to read SPD any more - } - - for (i = 0; i < DIMM_SOCKETS; i++) { - u32 spd_device = ctrl->channel0[i]; - if (!(meminfo->dimm_mask & (1 << i))) { - if (meminfo->dimm_mask & (1 << (DIMM_SOCKETS + i))) { /* channelB only? */ - spd_device = ctrl->channel1[i]; - printk(BIOS_DEBUG, "set_ecc spd_device: 0x%x\n", spd_device); - } else { - continue; - } - } - - value = spd_read_byte(ctrl->channel0[i], SPD_DIMM_CONF_TYPE); - - if (!(value & SPD_DIMM_CONF_TYPE_ECC)) { - dcl &= ~DCL_DimmEccEn; - pci_write_config32(ctrl->f2, DRAM_CONFIG_LOW, dcl); - meminfo->is_ecc = 0; - return; - } - - } -} - - -static int update_dimm_Twtr(const struct mem_controller *ctrl, - const struct mem_param *param, int i, long dimm_mask) -{ - return update_dimm_TT_1_4(ctrl, param, i, dimm_mask, DRAM_TIMING_HIGH, SPD_TWTR, DTH_TWTR_SHIFT, DTH_TWTR_MASK, DTH_TWTR_BASE, DTH_TWTR_MIN, DTH_TWTR_MAX); -} - -static void set_TT(const struct mem_controller *ctrl, - const struct mem_param *param, unsigned TT_REG, unsigned TT_SHIFT, - unsigned TT_MASK, unsigned TT_BASE, unsigned TT_MIN, unsigned TT_MAX, - unsigned val, const char *str) -{ - uint32_t reg; - - if ((val < TT_MIN) || (val > TT_MAX)) { - printk(BIOS_ERR, "%s", str); - die(" Unknown\n"); - } - - reg = pci_read_config32(ctrl->f2, TT_REG); - reg &= ~(TT_MASK << TT_SHIFT); - reg |= ((val - TT_BASE) << TT_SHIFT); - pci_write_config32(ctrl->f2, TT_REG, reg); - return; -} - - -static void set_TrwtTO(const struct mem_controller *ctrl, - const struct mem_param *param) -{ - set_TT(ctrl, param, DRAM_TIMING_HIGH, DTH_TRWTTO_SHIFT, DTH_TRWTTO_MASK,DTH_TRWTTO_BASE, DTH_TRWTTO_MIN, DTH_TRWTTO_MAX, param->TrwtTO, "TrwtTO"); -} - - -static void set_Twrrd(const struct mem_controller *ctrl, const struct mem_param *param) -{ - set_TT(ctrl, param, DRAM_TIMING_HIGH, DTH_TWRRD_SHIFT, DTH_TWRRD_MASK,DTH_TWRRD_BASE, DTH_TWRRD_MIN, DTH_TWRRD_MAX, param->Twrrd, "Twrrd"); -} - - -static void set_Twrwr(const struct mem_controller *ctrl, const struct mem_param *param) -{ - set_TT(ctrl, param, DRAM_TIMING_HIGH, DTH_TWRWR_SHIFT, DTH_TWRWR_MASK,DTH_TWRWR_BASE, DTH_TWRWR_MIN, DTH_TWRWR_MAX, param->Twrwr, "Twrwr"); -} - -static void set_Trdrd(const struct mem_controller *ctrl, const struct mem_param *param) -{ - set_TT(ctrl, param, DRAM_TIMING_HIGH, DTH_TRDRD_SHIFT, DTH_TRDRD_MASK,DTH_TRDRD_BASE, DTH_TRDRD_MIN, DTH_TRDRD_MAX, param->Trdrd, "Trdrd"); -} - -static void set_DcqBypassMax(const struct mem_controller *ctrl, const struct mem_param *param) -{ - set_TT(ctrl, param, DRAM_CONFIG_HIGH, DCH_DcqBypassMax_SHIFT, DCH_DcqBypassMax_MASK,DCH_DcqBypassMax_BASE, DCH_DcqBypassMax_MIN, DCH_DcqBypassMax_MAX, param->DcqByPassMax, "DcqBypassMax"); // value need to be in CMOS -} - -static void set_Tfaw(const struct mem_controller *ctrl, const struct mem_param *param, struct mem_info *meminfo) -{ - static const uint8_t faw_1k[] = {8, 10, 13, 14}; - static const uint8_t faw_2k[] = {10, 14, 17, 18}; - unsigned memclkfreq_index; - unsigned faw; - - - memclkfreq_index = param->dch_memclk; - - if (meminfo->page_1k_mask != 0) { //1k page - faw = faw_1k[memclkfreq_index]; - } else { - faw = faw_2k[memclkfreq_index]; - } - - set_TT(ctrl, param, DRAM_CONFIG_HIGH, DCH_FourActWindow_SHIFT, DCH_FourActWindow_MASK, DCH_FourActWindow_BASE, DCH_FourActWindow_MIN, DCH_FourActWindow_MAX, faw, "FourActWindow"); -} - -static void set_max_async_latency(const struct mem_controller *ctrl, const struct mem_param *param) -{ - uint32_t dch; - unsigned async_lat; - - - dch = pci_read_config32(ctrl->f2, DRAM_CONFIG_HIGH); - dch &= ~(DCH_MaxAsyncLat_MASK << DCH_MaxAsyncLat_SHIFT); - - //FIXME: We need to use Max of DqsRcvEnDelay + 6ns here: After training and get that from index reg 0x10, 0x13, 0x16, 0x19, 0x30, 0x33, 0x36, 0x39 - async_lat = 6 + 6; - - - dch |= ((async_lat - DCH_MaxAsyncLat_BASE) << DCH_MaxAsyncLat_SHIFT); - pci_write_config32(ctrl->f2, DRAM_CONFIG_HIGH, dch); -} - -#if (CONFIG_DIMM_SUPPORT & 0x0100) == 0x0000 /* 2T mode only used for unbuffered DIMM */ -static void set_SlowAccessMode(const struct mem_controller *ctrl) -{ - uint32_t dch; - - dch = pci_read_config32(ctrl->f2, DRAM_CONFIG_HIGH); - - dch |= (1<<20); - - pci_write_config32(ctrl->f2, DRAM_CONFIG_HIGH, dch); -} -#endif - -/* - DRAM_OUTPUT_DRV_COMP_CTRL 0, 0x20 - DRAM_ADDR_TIMING_CTRL 04, 0x24 -*/ -static void set_misc_timing(const struct mem_controller *ctrl, struct mem_info *meminfo) -{ - uint32_t dword; - uint32_t dwordx; -#if (CONFIG_DIMM_SUPPORT & 0x0100) == 0x0000 /* 2T mode only used for unbuffered DIMM */ - unsigned SlowAccessMode = 0; -#endif - -#if CONFIG_DIMM_SUPPORT == 0x0104 /* DDR2 and REG */ - long dimm_mask = meminfo->dimm_mask & 0x0f; - /* for REG DIMM */ - dword = 0x00111222; - dwordx = 0x002f0000; - switch (meminfo->memclk_set) { - case DCH_MemClkFreq_266MHz: - if ((dimm_mask == 0x03) || (dimm_mask == 0x02) || (dimm_mask == 0x01)) { - dwordx = 0x002f2700; - } - break; - case DCH_MemClkFreq_333MHz: - if ((dimm_mask == 0x03) || (dimm_mask == 0x02) || (dimm_mask == 0x01)) { - if ((meminfo->single_rank_mask & 0x03)!=0x03) { //any double rank there? - dwordx = 0x002f2f00; - } - } - break; - case DCH_MemClkFreq_400MHz: - dwordx = 0x002f3300; - break; - } - -#endif - -#if CONFIG_DIMM_SUPPORT == 0x0204 /* DDR2 and SO-DIMM, S1G1 */ - dword = 0x00111222; - dwordx = 0x002F2F00; - - switch (meminfo->memclk_set) { - case DCH_MemClkFreq_200MHz: /* nothing to be set here */ - break; - case DCH_MemClkFreq_266MHz: - if ((meminfo->single_rank_mask == 0) - && (meminfo->x4_mask == 0) && (meminfo->x16_mask)) - dwordx = 0x002C2C00; /* Double rank x8 */ - /* else SRx16, SRx8, DRx16 == 0x002F2F00 */ - break; - case DCH_MemClkFreq_333MHz: - if ((meminfo->single_rank_mask == 1) - && (meminfo->x16_mask == 1)) /* SR x16 */ - dwordx = 0x00272700; - else if ((meminfo->x4_mask == 0) && (meminfo->x16_mask == 0) - && (meminfo->single_rank_mask == 0)) { /* DR x8 */ - SlowAccessMode = 1; - dwordx = 0x00002800; - } else { /* SR x8, DR x16 */ - dwordx = 0x002A2A00; - } - break; - case DCH_MemClkFreq_400MHz: - if ((meminfo->single_rank_mask == 1) - && (meminfo->x16_mask == 1)) /* SR x16 */ - dwordx = 0x00292900; - else if ((meminfo->x4_mask == 0) && (meminfo->x16_mask == 0) - && (meminfo->single_rank_mask == 0)) { /* DR x8 */ - SlowAccessMode = 1; - dwordx = 0x00002A00; - } else { /* SR x8, DR x16 */ - dwordx = 0x002A2A00; - } - break; - } -#endif - -#if CONFIG_DIMM_SUPPORT == 0x0004 /* DDR2 and unbuffered */ - long dimm_mask = meminfo->dimm_mask & 0x0f; - /* for UNBUF DIMM */ - dword = 0x00111222; - dwordx = 0x002f2f00; - switch (meminfo->memclk_set) { - case DCH_MemClkFreq_200MHz: - if (dimm_mask == 0x03) { - SlowAccessMode = 1; - dword = 0x00111322; - } - break; - case DCH_MemClkFreq_266MHz: - if (dimm_mask == 0x03) { - SlowAccessMode = 1; - dword = 0x00111322; - if ((meminfo->x4_mask == 0) && (meminfo->x16_mask == 0)) { - switch (meminfo->single_rank_mask) { - case 0x03: - dwordx = 0x00002f00; //x8 single Rank - break; - case 0x00: - dwordx = 0x00342f00; //x8 double Rank - break; - default: - dwordx = 0x00372f00; //x8 single Rank and double Rank mixed - } - } else if ((meminfo->x4_mask == 0) && (meminfo->x16_mask == 0x01) && (meminfo->single_rank_mask == 0x01)) { - dwordx = 0x00382f00; //x8 Double Rank and x16 single Rank mixed - } else if ((meminfo->x4_mask == 0) && (meminfo->x16_mask == 0x02) && (meminfo->single_rank_mask == 0x02)) { - dwordx = 0x00382f00; //x16 single Rank and x8 double Rank mixed - } - - } else { - if ((meminfo->x4_mask == 0) && (meminfo->x16_mask == 0x00) && ((meminfo->single_rank_mask == 0x01)||(meminfo->single_rank_mask == 0x02))) { //x8 single rank - dwordx = 0x002f2f00; - } else { - dwordx = 0x002b2f00; - } - } - break; - case DCH_MemClkFreq_333MHz: - dwordx = 0x00202220; - if (dimm_mask == 0x03) { - SlowAccessMode = 1; - dword = 0x00111322; - if ((meminfo->x4_mask == 0) && (meminfo->x16_mask == 0)) { - switch (meminfo->single_rank_mask) { - case 0x03: - dwordx = 0x00302220; //x8 single Rank - break; - case 0x00: - dwordx = 0x002b2220; //x8 double Rank - break; - default: - dwordx = 0x002a2220; //x8 single Rank and double Rank mixed - } - } else if ((meminfo->x4_mask == 0) && (meminfo->x16_mask == 0x01) && (meminfo->single_rank_mask == 0x01)) { - dwordx = 0x002c2220; //x8 Double Rank and x16 single Rank mixed - } else if ((meminfo->x4_mask == 0) && (meminfo->x16_mask == 0x02) && (meminfo->single_rank_mask == 0x02)) { - dwordx = 0x002c2220; //x16 single Rank and x8 double Rank mixed - } - } - break; - case DCH_MemClkFreq_400MHz: - dwordx = 0x00202520; - SlowAccessMode = 1; - if (dimm_mask == 0x03) { - dword = 0x00113322; - } else { - dword = 0x00113222; - } - break; - } - - printk_raminit("\tdimm_mask = %08x\n", meminfo->dimm_mask); - printk_raminit("\tx4_mask = %08x\n", meminfo->x4_mask); - printk_raminit("\tx16_mask = %08x\n", meminfo->x16_mask); - printk_raminit("\tsingle_rank_mask = %08x\n", meminfo->single_rank_mask); - printk_raminit("\tODC = %08x\n", dword); - printk_raminit("\tAddr Timing= %08x\n", dwordx); -#endif - -#if (CONFIG_DIMM_SUPPORT & 0x0100) == 0x0000 /* 2T mode only used for unbuffered DIMM */ - if (SlowAccessMode) { - set_SlowAccessMode(ctrl); - } -#endif - - if (!(meminfo->dimm_mask & 0x0F) && (meminfo->dimm_mask & 0xF0)) { /* channelB only? */ - /* Program the Output Driver Compensation Control Registers (Function 2:Offset 0x9c, index 0, 0x20) */ - pci_write_config32_index_wait(ctrl->f2, 0x98, 0x20, dword); - - /* Program the Address Timing Control Registers (Function 2:Offset 0x9c, index 4, 0x24) */ - pci_write_config32_index_wait(ctrl->f2, 0x98, 0x24, dwordx); - } else { - /* Program the Output Driver Compensation Control Registers (Function 2:Offset 0x9c, index 0, 0x20) */ - pci_write_config32_index_wait(ctrl->f2, 0x98, 0, dword); - if (meminfo->is_Width128) { - pci_write_config32_index_wait(ctrl->f2, 0x98, 0x20, dword); - } - - /* Program the Address Timing Control Registers (Function 2:Offset 0x9c, index 4, 0x24) */ - pci_write_config32_index_wait(ctrl->f2, 0x98, 4, dwordx); - if (meminfo->is_Width128) { - pci_write_config32_index_wait(ctrl->f2, 0x98, 0x24, dwordx); - } - } -} - - -static void set_RDqsEn(const struct mem_controller *ctrl, - const struct mem_param *param, struct mem_info *meminfo) -{ -#if CONFIG_CPU_SOCKET_TYPE == 0x10 - //only need to set for reg and x8 - uint32_t dch; - - dch = pci_read_config32(ctrl->f2, DRAM_CONFIG_HIGH); - - dch &= ~DCH_RDqsEn; - if ((!meminfo->x4_mask) && (!meminfo->x16_mask)) { - dch |= DCH_RDqsEn; - } - - pci_write_config32(ctrl->f2, DRAM_CONFIG_HIGH, dch); -#endif -} - -static void set_idle_cycle_limit(const struct mem_controller *ctrl, - const struct mem_param *param) -{ - uint32_t dcm; - /* AMD says to Hardcode this */ - dcm = pci_read_config32(ctrl->f2, DRAM_CTRL_MISC); - dcm &= ~(DCM_ILD_lmt_MASK << DCM_ILD_lmt_SHIFT); - dcm |= DCM_ILD_lmt_16 << DCM_ILD_lmt_SHIFT; - dcm |= DCM_DCC_EN; - pci_write_config32(ctrl->f2, DRAM_CTRL_MISC, dcm); -} - -static void set_RdWrQByp(const struct mem_controller *ctrl, - const struct mem_param *param) -{ - set_TT(ctrl, param, DRAM_CTRL_MISC, DCM_RdWrQByp_SHIFT, DCM_RdWrQByp_MASK,0, 0, 3, 2, "RdWrQByp"); -} - -static long spd_set_dram_timing(const struct mem_controller *ctrl, - const struct mem_param *param, - struct mem_info *meminfo) -{ - int i; - - for (i = 0; i < DIMM_SOCKETS; i++) { - int rc; - if (!(meminfo->dimm_mask & (1 << i)) && - !(meminfo->dimm_mask & (1 << (DIMM_SOCKETS + i)))) { - continue; - } - printk_raminit("spd_set_dram_timing dimm socket: %08x\n", i); - /* DRAM Timing Low Register */ - printk_raminit("\ttrc\n"); - if ((rc = update_dimm_Trc (ctrl, param, i, meminfo->dimm_mask)) <= 0) goto dimm_err; - - printk_raminit("\ttrcd\n"); - if ((rc = update_dimm_Trcd(ctrl, param, i, meminfo->dimm_mask)) <= 0) goto dimm_err; - - printk_raminit("\ttrrd\n"); - if ((rc = update_dimm_Trrd(ctrl, param, i, meminfo->dimm_mask)) <= 0) goto dimm_err; - - printk_raminit("\ttras\n"); - if ((rc = update_dimm_Tras(ctrl, param, i, meminfo->dimm_mask)) <= 0) goto dimm_err; - - printk_raminit("\ttrp\n"); - if ((rc = update_dimm_Trp (ctrl, param, i, meminfo->dimm_mask)) <= 0) goto dimm_err; - - printk_raminit("\ttrtp\n"); - if ((rc = update_dimm_Trtp(ctrl, param, i, meminfo)) <= 0) goto dimm_err; - - printk_raminit("\ttwr\n"); - if ((rc = update_dimm_Twr (ctrl, param, i, meminfo->dimm_mask)) <= 0) goto dimm_err; - - /* DRAM Timing High Register */ - printk_raminit("\ttref\n"); - if ((rc = update_dimm_Tref(ctrl, param, i, meminfo->dimm_mask)) <= 0) goto dimm_err; - - printk_raminit("\ttwtr\n"); - if ((rc = update_dimm_Twtr(ctrl, param, i, meminfo->dimm_mask)) <= 0) goto dimm_err; - - printk_raminit("\ttrfc\n"); - if ((rc = update_dimm_Trfc(ctrl, param, i, meminfo)) <= 0) goto dimm_err; - - /* DRAM Config Low */ - - continue; - dimm_err: - printk(BIOS_DEBUG, "spd_set_dram_timing dimm_err!\n"); - if (rc < 0) { - return -1; - } - meminfo->dimm_mask = disable_dimm(ctrl, i, meminfo); - } - - get_extra_dimm_mask(ctrl, meminfo); // will be used by RDqsEn and dimm_x4 - /* DRAM Timing Low Register */ - - /* DRAM Timing High Register */ - set_TrwtTO(ctrl, param); - set_Twrrd (ctrl, param); - set_Twrwr (ctrl, param); - set_Trdrd (ctrl, param); - - set_4RankRDimm(ctrl, param, meminfo); - - /* DRAM Config High */ - set_Tfaw(ctrl, param, meminfo); - set_DcqBypassMax(ctrl, param); - set_max_async_latency(ctrl, param); - set_RDqsEn(ctrl, param, meminfo); - - /* DRAM Config Low */ - set_ecc(ctrl, param, meminfo); - set_dimm_x4(ctrl, param, meminfo); - set_DramTerm(ctrl, param, meminfo); - - /* DRAM Control Misc */ - set_idle_cycle_limit(ctrl, param); - set_RdWrQByp(ctrl, param); - - return meminfo->dimm_mask; -} - -void sdram_set_spd_registers(const struct mem_controller *ctrl, - struct sys_info *sysinfo) -{ - struct spd_set_memclk_result result; - const struct mem_param *param; - struct mem_param paramx; - struct mem_info *meminfo; -#if 1 - if (!sysinfo->ctrl_present[ctrl->node_id]) { - return; - } -#endif - meminfo = &sysinfo->meminfo[ctrl->node_id]; - - printk(BIOS_DEBUG, "sdram_set_spd_registers: paramx :%p\n", ¶mx); - - activate_spd_rom(ctrl); - meminfo->dimm_mask = spd_detect_dimms(ctrl); - - printk_raminit("sdram_set_spd_registers: dimm_mask=0x%x\n", meminfo->dimm_mask); - - if (!(meminfo->dimm_mask & ((1 << 2*DIMM_SOCKETS) - 1))) - { - printk(BIOS_DEBUG, "No memory for this cpu\n"); - return; - } - meminfo->dimm_mask = spd_enable_2channels(ctrl, meminfo); - printk_raminit("spd_enable_2channels: dimm_mask=0x%x\n", meminfo->dimm_mask); - if (meminfo->dimm_mask == -1) - goto hw_spd_err; - - meminfo->dimm_mask = spd_set_ram_size(ctrl, meminfo); - printk_raminit("spd_set_ram_size: dimm_mask=0x%x\n", meminfo->dimm_mask); - if (meminfo->dimm_mask == -1) - goto hw_spd_err; - - meminfo->dimm_mask = spd_handle_unbuffered_dimms(ctrl, meminfo); - printk_raminit("spd_handle_unbuffered_dimms: dimm_mask=0x%x\n", meminfo->dimm_mask); - if (meminfo->dimm_mask == -1) - goto hw_spd_err; - - result = spd_set_memclk(ctrl, meminfo); - param = result.param; - meminfo->dimm_mask = result.dimm_mask; - printk_raminit("spd_set_memclk: dimm_mask=0x%x\n", meminfo->dimm_mask); - if (meminfo->dimm_mask == -1) - goto hw_spd_err; - - //store memclk set to sysinfo, in case we need rebuilt param again - meminfo->memclk_set = param->dch_memclk; - - memcpy(¶mx, param, sizeof(paramx)); - - paramx.divisor = get_exact_divisor(param->dch_memclk, paramx.divisor); - - meminfo->dimm_mask = spd_set_dram_timing(ctrl, ¶mx, meminfo); - printk_raminit("spd_set_dram_timing: dimm_mask=0x%x\n", meminfo->dimm_mask); - if (meminfo->dimm_mask == -1) - goto hw_spd_err; - - order_dimms(ctrl, meminfo); - - return; - hw_spd_err: - /* Unrecoverable error reading SPD data */ - die("Unrecoverable error reading SPD data. No qualified DIMMs?"); - return; -} - -#include "raminit_f_dqs.c" - -#if CONFIG_HW_MEM_HOLE_SIZEK != 0 -static uint32_t hoist_memory(int controllers, const struct mem_controller *ctrl,unsigned hole_startk, int i) -{ - int ii; - uint32_t carry_over; - pci_devfn_t dev; - uint32_t base, limit; - uint32_t basek; - uint32_t hoist; - int j; - - carry_over = (4*1024*1024) - hole_startk; - - for (ii = controllers - 1; ii > i; ii--) { - base = pci_read_config32(ctrl[0].f1, 0x40 + (ii << 3)); - if ((base & ((1<<1)|(1<<0))) != ((1<<1)|(1<<0))) { - continue; - } - limit = pci_read_config32(ctrl[0].f1, 0x44 + (ii << 3)); - limit += (carry_over << 2); - base += (carry_over << 2); - for (j = 0; j < controllers; j++) { - pci_write_config32(ctrl[j].f1, 0x44 + (ii << 3), limit); - pci_write_config32(ctrl[j].f1, 0x40 + (ii << 3), base); - } - } - limit = pci_read_config32(ctrl[0].f1, 0x44 + (i << 3)); - limit += (carry_over << 2); - for (j = 0; j < controllers; j++) { - pci_write_config32(ctrl[j].f1, 0x44 + (i << 3), limit); - } - dev = ctrl[i].f1; - base = pci_read_config32(dev, 0x40 + (i << 3)); - basek = (base & 0xffff0000) >> 2; - if (basek == hole_startk) { - //don't need set memhole here, because hole off set will be 0, overflow - //so need to change base reg instead, new basek will be 4*1024*1024 - base &= 0x0000ffff; - base |= (4*1024*1024)<<2; - for (j = 0; j < controllers; j++) { - pci_write_config32(ctrl[j].f1, 0x40 + (i<<3), base); - } - } else { - hoist = /* hole start address */ - ((hole_startk << 10) & 0xff000000) + - /* hole address to memory controller address */ - (((basek + carry_over) >> 6) & 0x0000ff00) + - /* enable */ - 1; - pci_write_config32(dev, 0xf0, hoist); - } - - return carry_over; -} - -void set_hw_mem_hole(int controllers, const struct mem_controller *ctrl) -{ - - uint32_t hole_startk; - int i; - - hole_startk = 4*1024*1024 - CONFIG_HW_MEM_HOLE_SIZEK; - - printk_raminit("Handling memory hole at 0x%08x (default)\n", hole_startk); -#if IS_ENABLED(CONFIG_HW_MEM_HOLE_SIZE_AUTO_INC) - /* We need to double check if the hole_startk is valid, if it is equal - to basek, we need to decrease it some */ - uint32_t basek_pri; - for (i = 0; i < controllers; i++) { - uint32_t base; - unsigned base_k; - base = pci_read_config32(ctrl[0].f1, 0x40 + (i << 3)); - if ((base & ((1<<1)|(1<<0))) != ((1<<1)|(1<<0))) { - continue; - } - base_k = (base & 0xffff0000) >> 2; - if (base_k == hole_startk) { - /* decrease mem hole startk to make sure it is - on middle of previous node */ - hole_startk -= (base_k - basek_pri) >> 1; - break; //only one hole - } - basek_pri = base_k; - } - printk_raminit("Handling memory hole at 0x%08x (adjusted)\n", hole_startk); -#endif - /* find node index that need do set hole */ - for (i = 0; i < controllers; i++) { - uint32_t base, limit; - unsigned base_k, limit_k; - base = pci_read_config32(ctrl[0].f1, 0x40 + (i << 3)); - if ((base & ((1 << 1) | (1 << 0))) != ((1 << 1) | (1 << 0))) { - continue; - } - limit = pci_read_config32(ctrl[0].f1, 0x44 + (i << 3)); - base_k = (base & 0xffff0000) >> 2; - limit_k = ((limit + 0x00010000) & 0xffff0000) >> 2; - if ((base_k <= hole_startk) && (limit_k > hole_startk)) { - unsigned end_k; - hoist_memory(controllers, ctrl, hole_startk, i); - end_k = memory_end_k(ctrl, controllers); - set_top_mem(end_k, hole_startk); - break; //only one hole - } - } - -} -#endif - -void sdram_enable(int controllers, const struct mem_controller *ctrl, - struct sys_info *sysinfo) -{ - int i; - int suspend = acpi_is_wakeup_s3(); - -#if K8_REV_F_SUPPORT_F0_F1_WORKAROUND == 1 - unsigned cpu_f0_f1[8]; - /* FIXME: How about 32 node machine later? */ - tsc_t tsc, tsc0[8]; - - printk(BIOS_DEBUG, "sdram_enable: tsc0[8]: %p", &tsc0[0]); - uint32_t dword; -#endif - - /* Error if I don't have memory */ - if (memory_end_k(ctrl, controllers) == 0) { - die("No memory\n"); - } - - /* Before enabling memory start the memory clocks */ - for (i = 0; i < controllers; i++) { - uint32_t dch; - if (!sysinfo->ctrl_present[ i ]) - continue; - dch = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_HIGH); - - /* if no memory installed, disabled the interface */ - if (sysinfo->meminfo[i].dimm_mask == 0x00) { - dch |= DCH_DisDramInterface; - pci_write_config32(ctrl[i].f2, DRAM_CONFIG_HIGH, dch); - - } else { - dch |= DCH_MemClkFreqVal; - pci_write_config32(ctrl[i].f2, DRAM_CONFIG_HIGH, dch); - /* address timing and Output driver comp Control */ - set_misc_timing(ctrl+i, sysinfo->meminfo+i); - } - } - - /* We need to wait a minimum of 20 MEMCLKS to enable the InitDram */ - memreset(controllers, ctrl); - - /* lets override the rest of the routine */ - if (suspend) { - printk(BIOS_DEBUG, "Wakeup!\n"); - exit_from_self(controllers, ctrl, sysinfo); - printk(BIOS_DEBUG, "Mem running !\n"); - return; - } - - for (i = 0; i < controllers; i++) { - uint32_t dcl, dch; - if (!sysinfo->ctrl_present[ i ]) - continue; - /* Skip everything if I don't have any memory on this controller */ - dch = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_HIGH); - if (!(dch & DCH_MemClkFreqVal)) { - continue; - } - - /* ChipKill */ - dcl = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_LOW); - if (dcl & DCL_DimmEccEn) { - uint32_t mnc; - printk(BIOS_SPEW, "ECC enabled\n"); - mnc = pci_read_config32(ctrl[i].f3, MCA_NB_CONFIG); - mnc |= MNC_ECC_EN; - if (dcl & DCL_Width128) { - mnc |= MNC_CHIPKILL_EN; - } - pci_write_config32(ctrl[i].f3, MCA_NB_CONFIG, mnc); - } - -#if K8_REV_F_SUPPORT_F0_F1_WORKAROUND == 1 - cpu_f0_f1[i] = is_cpu_pre_f2_in_bsp(i); - if (cpu_f0_f1[i]) { - //Rev F0/F1 workaround -#if 1 - /* Set the DqsRcvEnTrain bit */ - dword = pci_read_config32(ctrl[i].f2, DRAM_CTRL); - dword |= DC_DqsRcvEnTrain; - pci_write_config32(ctrl[i].f2, DRAM_CTRL, dword); -#endif - tsc0[i] = rdtsc(); - } -#endif - - pci_write_config32(ctrl[i].f2, DRAM_CONFIG_LOW, dcl); - dcl |= DCL_InitDram; - pci_write_config32(ctrl[i].f2, DRAM_CONFIG_LOW, dcl); - } - - for (i = 0; i < controllers; i++) { - uint32_t dcl, dcm; - if (!sysinfo->ctrl_present[ i ]) - continue; - /* Skip everything if I don't have any memory on this controller */ - if (sysinfo->meminfo[i].dimm_mask == 0x00) continue; - - printk(BIOS_DEBUG, "Initializing memory: "); - int loops = 0; - do { - dcl = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_LOW); - loops++; - if ((loops & 1023) == 0) { - printk(BIOS_DEBUG, "."); - } - } while (((dcl & DCL_InitDram) != 0) && (loops < TIMEOUT_LOOPS)); - if (loops >= TIMEOUT_LOOPS) { - printk(BIOS_DEBUG, " failed\n"); - continue; - } - - /* Wait until it is safe to touch memory */ - do { - dcm = pci_read_config32(ctrl[i].f2, DRAM_CTRL_MISC); - } while (((dcm & DCM_MemClrStatus) == 0) /* || ((dcm & DCM_DramEnabled) == 0)*/); - -#if K8_REV_F_SUPPORT_F0_F1_WORKAROUND == 1 - if (cpu_f0_f1[i]) { - tsc= rdtsc(); - - print_debug_dqs_tsc("\nbegin tsc0", i, tsc0[i].hi, tsc0[i].lo, 2); - print_debug_dqs_tsc("end tsc ", i, tsc.hi, tsc.lo, 2); - - if (tsc.lo < tsc0[i].lo) { - tsc.hi--; - } - tsc.lo -= tsc0[i].lo; - tsc.hi -= tsc0[i].hi; - - tsc0[i].lo = tsc.lo; - tsc0[i].hi = tsc.hi; - - print_debug_dqs_tsc(" dtsc0", i, tsc0[i].hi, tsc0[i].lo, 2); - } -#endif - printk(BIOS_DEBUG, " done\n"); - } - -#if CONFIG_HW_MEM_HOLE_SIZEK != 0 - /* init hw mem hole here */ - /* DramHoleValid bit only can be set after MemClrStatus is set by Hardware */ - set_hw_mem_hole(controllers, ctrl); -#endif - - /* store tom to sysinfo, and it will be used by dqs_timing */ - { - msr_t msr; - //[1M, TOM) - msr = rdmsr(TOP_MEM); - sysinfo->tom_k = ((msr.hi<<24) | (msr.lo>>8))>>2; - - //[4G, TOM2) - msr = rdmsr(TOP_MEM2); - sysinfo->tom2_k = ((msr.hi<<24)| (msr.lo>>8))>>2; - } - - for (i = 0; i < controllers; i++) { - sysinfo->mem_trained[i] = 0; - - if (!sysinfo->ctrl_present[ i ]) - continue; - - /* Skip everything if I don't have any memory on this controller */ - if (sysinfo->meminfo[i].dimm_mask == 0x00) - continue; - - sysinfo->mem_trained[i] = 0x80; // mem need to be trained - } - - -#if CONFIG_MEM_TRAIN_SEQ == 0 - #if K8_REV_F_SUPPORT_F0_F1_WORKAROUND == 1 - dqs_timing(controllers, ctrl, tsc0, sysinfo); - #else - dqs_timing(controllers, ctrl, sysinfo); - #endif -#else - -#if CONFIG_MEM_TRAIN_SEQ == 2 - /* need to enable mtrr, so dqs training could access the test address */ - setup_mtrr_dqs(sysinfo->tom_k, sysinfo->tom2_k); -#endif - - for (i = 0; i < controllers; i++) { - /* Skip everything if I don't have any memory on this controller */ - if (sysinfo->mem_trained[i]!=0x80) - continue; - - dqs_timing(i, &ctrl[i], sysinfo, 1); - -#if CONFIG_MEM_TRAIN_SEQ == 1 - break; // only train the first node with ram -#endif - } - -#if CONFIG_MEM_TRAIN_SEQ == 2 - clear_mtrr_dqs(sysinfo->tom2_k); -#endif - -#endif - -#if CONFIG_MEM_TRAIN_SEQ != 1 - wait_all_core0_mem_trained(sysinfo); -#endif - -} - -void fill_mem_ctrl(int controllers, struct mem_controller *ctrl_a, - const uint16_t *spd_addr) -{ - int i; - int j; - struct mem_controller *ctrl; - for (i = 0; i < controllers; i++) { - ctrl = &ctrl_a[i]; - ctrl->node_id = i; - ctrl->f0 = PCI_DEV(0, 0x18+i, 0); - ctrl->f1 = PCI_DEV(0, 0x18+i, 1); - ctrl->f2 = PCI_DEV(0, 0x18+i, 2); - ctrl->f3 = PCI_DEV(0, 0x18+i, 3); - - if (spd_addr == (void *)0) continue; - - for (j = 0; j < DIMM_SOCKETS; j++) { - ctrl->channel0[j] = spd_addr[(i*2+0)*DIMM_SOCKETS + j]; - ctrl->channel1[j] = spd_addr[(i*2+1)*DIMM_SOCKETS + j]; - } - } -} diff --git a/src/northbridge/amd/amdk8/raminit_f_dqs.c b/src/northbridge/amd/amdk8/raminit_f_dqs.c deleted file mode 100644 index 1573ce1899..0000000000 --- a/src/northbridge/amd/amdk8/raminit_f_dqs.c +++ /dev/null @@ -1,2058 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2005 YingHai Lu - * Copyright (C) 2008 Advanced Micro Devices, Inc. - * - * 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. -*/ - -#include <arch/stages.h> -#include <cpu/x86/cr.h> -#include <cpu/x86/mtrr.h> -#include <arch/early_variables.h> -#if IS_ENABLED(CONFIG_SOUTHBRIDGE_AMD_SB700) -#include <southbridge/amd/sb700/sb700.h> -#endif - -//0: mean no debug info -#define DQS_TRAIN_DEBUG 0 - -static inline void print_debug_dqs(const char *str, unsigned val, unsigned level) -{ -#if DQS_TRAIN_DEBUG > 0 - if (DQS_TRAIN_DEBUG > level) { - printk(BIOS_DEBUG, "%s%x\n", str, val); - } -#endif -} - -static inline void print_debug_dqs_pair(const char *str, unsigned val, const char *str2, unsigned val2, unsigned level) -{ -#if DQS_TRAIN_DEBUG > 0 - if (DQS_TRAIN_DEBUG > level) { - printk(BIOS_DEBUG, "%s%08x%s%08x\n", str, val, str2, val2); - } -#endif -} - -static inline void print_debug_dqs_tsc(const char *str, unsigned i, unsigned val, unsigned val2, unsigned level) -{ -#if DQS_TRAIN_DEBUG > 0 - if (DQS_TRAIN_DEBUG > level) { - printk(BIOS_DEBUG, "%s[%02x]=%08x%08x\n", str, i, val, val2); - } -#endif -} - -static inline void print_debug_dqs_tsc_x(const char *str, unsigned i, unsigned val, unsigned val2) -{ - printk(BIOS_DEBUG, "%s[%02x]=%08x%08x\n", str, i, val, val2); - -} - -static void fill_mem_cs_sysinfo(unsigned nodeid, const struct mem_controller *ctrl, struct sys_info *sysinfo) -{ - - int i; - sysinfo->mem_base[nodeid] = pci_read_config32(ctrl->f1, 0x40 + (nodeid << 3)); - - for (i = 0; i < 8; i++) { - sysinfo->cs_base[nodeid*8+i] = pci_read_config32(ctrl->f2, 0x40 + (i << 2)); - } - - sysinfo->hole_reg[nodeid] = pci_read_config32(ctrl->f1, 0xf0); - -} -static unsigned Get_MCTSysAddr(const struct mem_controller *ctrl, unsigned cs_idx, struct sys_info *sysinfo) -{ - uint32_t dword; - uint32_t mem_base; - unsigned nodeid = ctrl->node_id; - -#if CONFIG_HW_MEM_HOLE_SIZEK != 0 - uint32_t hole_reg; -#endif - - //get the local base addr of the chipselect - dword = sysinfo->cs_base[nodeid * 8 + cs_idx]; - dword &= 0xfffffff0; - - //sys addr= node base + local cs base - mem_base = sysinfo->mem_base[nodeid]; - mem_base &= 0xffff0000; - - dword += mem_base; -#if CONFIG_HW_MEM_HOLE_SIZEK != 0 - hole_reg = sysinfo->hole_reg[nodeid]; - if (hole_reg & 1) { - unsigned hole_startk; - hole_startk = (hole_reg & (0xff << 24)) >> 10; - if ((dword >= (hole_startk << 2)) && (dword < ((4*1024*1024) << 2))) { - dword += ((4*1024*1024 - hole_startk) << 2); - } - } -#endif - - //add 1MB offset to avoid compat area - dword += (1<<(20-8)); - - //So final result is upper 32 bit addr - - return dword; - -} - -static unsigned Get_RcvrSysAddr(const struct mem_controller * ctrl, unsigned channel, unsigned cs_idx, struct sys_info *sysinfo) -{ - return Get_MCTSysAddr(ctrl, cs_idx, sysinfo); - -} - -static inline void enable_sse2(void) -{ - unsigned long cr4; - cr4 = read_cr4(); - cr4 |= (1<<9); - write_cr4(cr4); -} - -static inline void disable_sse2(void) -{ - unsigned long cr4; - cr4 = read_cr4(); - cr4 &= ~(1<<9); - write_cr4(cr4); -} - - -static void set_wrap32dis(void) { - msr_t msr; - - msr = rdmsr(0xc0010015); - msr.lo |= (1<<17); - - wrmsr(0xc0010015, msr); - -} - -static void clear_wrap32dis(void) { - msr_t msr; - - msr = rdmsr(0xc0010015); - msr.lo &= ~(1<<17); - - wrmsr(0xc0010015, msr); - -} - -static void set_FSBASE(uint32_t addr_hi) -{ - msr_t msr; - - //set fs and use fs prefix to access the mem - msr.hi = addr_hi; - msr.lo = 0; - wrmsr(0xc0000100, msr); //FS_BASE - -} - -static unsigned ChipSelPresent(const struct mem_controller *ctrl, unsigned cs_idx, struct sys_info *sysinfo) -{ - unsigned enabled; - unsigned nodeid = ctrl->node_id; - - - enabled = sysinfo->cs_base[nodeid * 8 + cs_idx]; - enabled &= 1; - - return enabled; - -} - -static unsigned RcvrRankEnabled(const struct mem_controller *ctrl, int channel, int cs_idx, unsigned is_Width128, struct sys_info *sysinfo) -{ - return ChipSelPresent(ctrl, cs_idx, sysinfo); -} - -static void WriteLNTestPattern(unsigned addr_lo, uint8_t *buf_a, unsigned line_num) -{ - __asm__ volatile ( - "1:\n\t" - "movdqa (%3), %%xmm0\n\t" - "movntdq %%xmm0, %%fs:(%0)\n\t" /* xmm0 is 128 bit */ - "addl %1, %0\n\t" - "addl %1, %3\n\t" - "loop 1b\n\t" - - :: "a" (addr_lo), "d" (16), "c" (line_num * 4), "b"(buf_a) - ); - - -} - -static void Write1LTestPattern(unsigned addr, unsigned p, uint8_t *buf_a, uint8_t *buf_b) -{ - uint8_t *buf; - if (p == 1) { buf = buf_b; } - else { buf = buf_a; } - - set_FSBASE (addr >> 24); - - WriteLNTestPattern(addr << 8, buf, 1); -} - -static void Read1LTestPattern(unsigned addr) -{ - unsigned value; - - set_FSBASE(addr>>24); - - /* 1st move causes read fill (to exclusive or shared)*/ - __asm__ volatile ( - "movl %%fs:(%1), %0\n\t" - :"=b"(value): "a" (addr << 8) - ); - -} - -#define DQS_PASS 0 -#define DQS_FAIL 1 - -#define DQS_FIRST_PASS 1 -#define DQS_SECOND_PASS 2 - -#define SB_NORCVREN 11 -#define RCVREN_MARGIN 6 -#define SB_SmallRCVR 13 -#define SB_CHA2BRCVREN 12 -#define SB_NODQSPOS 14 -#define MIN_DQS_WNDW 3 -#define SB_SMALLDQS 15 - - -static unsigned CompareTestPatternQW0(unsigned channel, unsigned addr, unsigned pattern, const uint32_t *TestPattern0, const uint32_t *TestPattern1, const uint32_t *TestPattern2, unsigned Pass, unsigned is_Width128) -{ - uint32_t addr_lo; - uint32_t *test_buf; - uint32_t value; - uint32_t value_test; - unsigned result = DQS_FAIL; - - if (Pass == DQS_FIRST_PASS) { - if (pattern == 1) { - test_buf = (uint32_t *)TestPattern1; - } - else { - test_buf = (uint32_t *)TestPattern0; - } - } - else { - test_buf = (uint32_t *)TestPattern2; - } - - set_FSBASE(addr >> 24); - - addr_lo = addr << 8; - - if (is_Width128 && (channel == 1)) { - addr_lo += 8; //second channel - test_buf += 2; - } - - __asm__ volatile ( - "movl %%fs:(%1), %0\n\t" - :"=b"(value): "a" (addr_lo) - ); - - value_test = *test_buf; - - - print_debug_dqs_pair("\t\t\t\t\t\tQW0.lo : test_buf= ", (unsigned)test_buf, " value = ", value_test, 4); - print_debug_dqs_pair("\t\t\t\t\t\tQW0.lo : addr_lo = ", addr_lo, " value = ", value, 4); - - if (value == value_test) { - addr_lo += 4; - test_buf++; - __asm__ volatile ( - "movl %%fs:(%1), %0\n\t" - :"=b"(value): "a" (addr_lo) - ); - value_test = *test_buf; - print_debug_dqs_pair("\t\t\t\t\t\tQW0.hi : test_buf= ", (unsigned)test_buf, " value = ", value_test, 4); - print_debug_dqs_pair("\t\t\t\t\t\tQW0.hi : addr_lo = ", addr_lo, " value = ", value, 4); - - if (value == value_test) { - result = DQS_PASS; - } - } - - if (Pass == DQS_SECOND_PASS) { // second pass need to be inverted - if (result == DQS_PASS) { - result = DQS_FAIL; - } - else { - result = DQS_PASS; - } - } - - return result; - -} - -static void SetMaxAL_RcvrDly(const struct mem_controller *ctrl, unsigned dly) -{ - uint32_t reg; - - dly += (20-1); // round it - dly /= 20; // convert from unit 50ps to 1ns - - dly += 6; - - - reg = pci_read_config32(ctrl->f2, DRAM_CONFIG_HIGH); - reg &= ~(DCH_MaxAsyncLat_MASK << DCH_MaxAsyncLat_SHIFT); - reg |= ((dly - DCH_MaxAsyncLat_BASE) << DCH_MaxAsyncLat_SHIFT); - pci_write_config32(ctrl->f2, DRAM_CONFIG_HIGH, reg); - -} - -/* - Set the Target range to WT IO (using an IORR overlapping the already existing - WB dram type). Use IORR0 -*/ -static void SetTargetWTIO(unsigned addr) -{ - msr_t msr; - msr.hi = addr >> 24; - msr.lo = addr << 8; - wrmsr(0xc0010016, msr); //IORR0 BASE - - msr.hi = 0xff; - msr.lo = 0xfc000800; // 64MB Mask - wrmsr(0xc0010017, msr); // IORR0 Mask -} - -static void ResetTargetWTIO(void) -{ - msr_t msr; - - msr.hi = 0; - msr.lo = 0; - wrmsr(0xc0010017, msr); // IORR0 Mask -} - -static void proc_CLFLUSH(unsigned addr) -{ - - set_FSBASE(addr>>24); - - /* 1st move causes read fill (to exclusive or shared)*/ - __asm__ volatile ( - /* clflush fs:[eax] */ - "clflush %%fs:(%0)\n\t" - ::"a" (addr << 8) - ); - -} -static void proc_IOCLFLUSH(unsigned addr) -{ - SetTargetWTIO(addr); - proc_CLFLUSH(addr); - ResetTargetWTIO(); -} - -static void ResetDCTWrPtr(const struct mem_controller *ctrl) -{ - uint32_t dword; - unsigned index = 0x10; - - dword = pci_read_config32_index_wait(ctrl->f2, 0x98, index); - pci_write_config32_index_wait(ctrl->f2, 0x98, index, dword); - - index += 0x20; - dword = pci_read_config32_index_wait(ctrl->f2, 0x98, index); - pci_write_config32_index_wait(ctrl->f2, 0x98, index, dword); - -} - - -static uint16_t get_exact_T1000(unsigned i) -{ - // 200 266, 333, 400 - static const uint16_t T1000_a[]= { 5000, 3759, 3003, 2500 }; - - static const uint16_t TT_a[] = { - /*200 266 333 400 */ - /*4 */ 6250, 6250, 6250, 6250, - /*5 */ 5000, 5000, 5000, 2500, - /*6 */ 5000, 4166, 4166, 2500, - /*7 */ 5000, 4285, 3571, 2500, - - /*8 */ 5000, 3750, 3125, 2500, - /*9 */ 5000, 3888, 3333, 2500, - /*10*/ 5000, 4000, 3000, 2500, - /*11*/ 5000, 4090, 3181, 2500, - - /*12*/ 5000, 3750, 3333, 2500, - /*13*/ 5000, 3846, 3076, 2500, - /*14*/ 5000, 3928, 3214, 2500, - /*15*/ 5000, 4000, 3000, 2500, - }; - - int index; - msr_t msr; - - /* Check for FID control support */ - struct cpuid_result cpuid1; - cpuid1 = cpuid(0x80000007); - if (cpuid1.edx & 0x02) { - /* Use current FID */ - unsigned fid_cur; - msr = rdmsr(0xc0010042); - fid_cur = msr.lo & 0x3f; - - index = fid_cur>>1; - } else { - /* Use startup FID */ - unsigned fid_start; - msr = rdmsr(0xc0010015); - fid_start = (msr.lo & (0x3f << 24)); - - index = fid_start>>25; - } - - if (index > 12) return T1000_a[i]; - - return TT_a[index * 4+i]; - -} - -static void InitDQSPos4RcvrEn(const struct mem_controller *ctrl) -{ - int i; - uint32_t dword; - - dword = 0x00000000; - for (i = 1; i <= 3; i++) { - /* Program the DQS Write Timing Control Registers (Function 2:Offset 0x9c, index 0x01-0x03, 0x21-0x23) to 0x00 for all bytes */ - pci_write_config32_index_wait(ctrl->f2, 0x98, i, dword); - pci_write_config32_index_wait(ctrl->f2, 0x98, i+0x20, dword); - } - - dword = 0x2f2f2f2f; - for (i = 5; i <= 7; i++) { - /* Program the DQS Write Timing Control Registers (Function 2:Offset 0x9c, index 0x05-0x07, 0x25-0x27) to 0x2f for all bytes */ - pci_write_config32_index_wait(ctrl->f2, 0x98, i, dword); - pci_write_config32_index_wait(ctrl->f2, 0x98, i+0x20, dword); - } - - -} - -static unsigned TrainRcvrEn(const struct mem_controller *ctrl, unsigned Pass, struct sys_info *sysinfo) -{ - - static const uint32_t TestPattern0[] = { - 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, - 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, - 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, - 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, - }; - static const uint32_t TestPattern1[] = { - 0x55555555, 0x55555555, 0x55555555, 0x55555555, - 0x55555555, 0x55555555, 0x55555555, 0x55555555, - 0x55555555, 0x55555555, 0x55555555, 0x55555555, - 0x55555555, 0x55555555, 0x55555555, 0x55555555, - }; - static const uint32_t TestPattern2[] = { - 0x12345678, 0x87654321, 0x23456789, 0x98765432, - 0x59385824, 0x30496724, 0x24490795, 0x99938733, - 0x40385642, 0x38465245, 0x29432163, 0x05067894, - 0x12349045, 0x98723467, 0x12387634, 0x34587623, - }; - - uint8_t pattern_buf_x[64 * 4 + 16]; // We need to two cache line So have more 16 bytes to keep 16 byte alignment */ - uint8_t *buf_a, *buf_b; - uint32_t ecc_bit; - uint32_t dword; - uint8_t *dqs_rcvr_dly_a = &sysinfo->dqs_rcvr_dly_a[ctrl->node_id * 2* 8]; //8 node, channel 2, receiver 8 - - int i; - - unsigned channel, receiver; - - unsigned Errors; - unsigned CTLRMaxDelay; - unsigned T1000; - - unsigned LastTest; - unsigned CurrTest; - unsigned Test0, Test1; - - unsigned RcvrEnDlyRmin; - - unsigned two_ranks; - unsigned RcvrEnDly; - - unsigned PatternA; - unsigned PatternB; - - unsigned TestAddr0, TestAddr0B, TestAddr1 = 0, TestAddr1B = 0; - - unsigned CurrRcvrCHADelay = 0; - - unsigned tmp; - - unsigned is_Width128 = sysinfo->meminfo[ctrl->node_id].is_Width128; - -#if K8_REV_F_SUPPORT_F0_F1_WORKAROUND == 1 - unsigned cpu_f0_f1 = 0; -#endif - - if (Pass == DQS_FIRST_PASS) { - InitDQSPos4RcvrEn(ctrl); - } - - //enable SSE2 - enable_sse2(); - - //wrap32dis - set_wrap32dis(); - - //disable ECC temp - dword = pci_read_config32(ctrl->f2, DRAM_CONFIG_LOW); - ecc_bit = dword & DCL_DimmEccEn; - dword &= ~(DCL_DimmEccEn); - pci_write_config32(ctrl->f2, DRAM_CONFIG_LOW, dword); - - - if (Pass == DQS_FIRST_PASS) { -#if K8_REV_F_SUPPORT_F0_F1_WORKAROUND == 1 - cpu_f0_f1 = is_cpu_pre_f2_in_bsp(ctrl->node_id); - if (!cpu_f0_f1) -#endif - { -#if 1 - /* Set the DqsRcvEnTrain bit */ - dword = pci_read_config32(ctrl->f2, DRAM_CTRL); - dword |= DC_DqsRcvEnTrain; - pci_write_config32(ctrl->f2, DRAM_CTRL, dword); -#endif - } - } - - //get T1000 figures (cycle time (ns)) * 1K - dword = pci_read_config32(ctrl->f2, DRAM_CONFIG_HIGH); - dword &= DCH_MemClkFreq_MASK; - - T1000 = get_exact_T1000(dword); - - // SetupRcvrPattern - buf_a = (uint8_t *)(((uint32_t)(&pattern_buf_x[0]) + 0x10) & (0xfffffff0)); - buf_b = buf_a + 128; //?? - if (Pass == DQS_FIRST_PASS) { - for (i = 0; i < 16; i++) { - *((uint32_t *)(buf_a + i*4)) = TestPattern0[i]; - *((uint32_t *)(buf_b + i*4)) = TestPattern1[i]; - } - } - else { - for (i = 0; i < 16; i++) { - *((uint32_t *)(buf_a + i*4)) = TestPattern2[i]; - *((uint32_t *)(buf_b + i*4)) = TestPattern2[i]; - } - } - - print_debug_dqs("\nTrainRcvEn: 0 ctrl", ctrl->node_id, 0); - - print_debug_addr("TrainRcvEn: buf_a:", buf_a); - - Errors = 0; - /* for each channel */ - CTLRMaxDelay = 0; - channel = 0; - - if (!(sysinfo->meminfo[ctrl->node_id].dimm_mask & 0x0F) && - (sysinfo->meminfo[ctrl->node_id].dimm_mask & 0xF0)) { /* channelB only? */ - channel = 1; - } - - for (; (channel < 2) && (!Errors); channel++) - { - print_debug_dqs("\tTrainRcvEn51: channel ",channel, 1); - - /* for each rank */ - /* there are four receiver pairs, loosely associated with CS */ - for (receiver = 0; (receiver < 8) && (!Errors); receiver+=2) - { - - unsigned index=(receiver>>1) * 3 + 0x10; - - print_debug_dqs("\t\tTrainRcvEn52: index ", index, 2); - - if (is_Width128) { - if (channel) { - dword = pci_read_config32_index_wait(ctrl->f2, 0x98, index); - CurrRcvrCHADelay= dword & 0xff; - } - } - else { - if (channel) { - index += 0x20; - } - } - - LastTest = DQS_FAIL; - RcvrEnDlyRmin = 0xaf; - - if (!RcvrRankEnabled(ctrl, channel, receiver, is_Width128, sysinfo)) continue; - - /* for each DQS receiver enable setting */ - - TestAddr0 = Get_RcvrSysAddr(ctrl, channel, receiver, sysinfo); - - TestAddr0B = TestAddr0 + (1<<(20+2-8)); // 4MB - - if (RcvrRankEnabled(ctrl, channel, receiver+1, is_Width128, sysinfo)) { - TestAddr1 = Get_RcvrSysAddr(ctrl, channel, receiver+1, sysinfo); - TestAddr1B = TestAddr1 + (1<<(20+2-8)); //4MB - two_ranks = 1; - } - else { - two_ranks = 0; - } - - print_debug_dqs("\t\tTrainRcvEn53: TestAddr0B ", TestAddr0B, 2); - - Write1LTestPattern(TestAddr0, 0, buf_a, buf_b); // rank0 of dimm, test p0 - Write1LTestPattern(TestAddr0B, 1, buf_a, buf_b); //rank0 of dimm, test p1 - - if (two_ranks == 1) { - Write1LTestPattern(TestAddr1, 0, buf_a, buf_b); //rank 1 of dimm - Write1LTestPattern(TestAddr1B, 1, buf_a, buf_b);//rank 1 of dimm - } - - if (Pass == DQS_FIRST_PASS) { - RcvrEnDly = 0; - } else { - RcvrEnDly = dqs_rcvr_dly_a[channel * 8 + receiver]; - } - - while (RcvrEnDly < 0xaf) { // Sweep Delay value here - print_debug_dqs("\t\t\tTrainRcvEn541: RcvrEnDly ", RcvrEnDly, 3); - - if (RcvrEnDly & 1) { - /* Odd steps get another pattern such that even - * and odd steps alternate. - * The pointers to the patterns will be swapped - * at the end of the loop so they are correspond - */ - PatternA = 1; - PatternB = 0; - } - else { - /* Even step */ - PatternA = 0; - PatternB = 1; - } - - /* Program current Receiver enable delay */ - pci_write_config32_index_wait(ctrl->f2, 0x98, index, RcvrEnDly); - /* FIXME: 64bit MUX */ - - if (is_Width128) { - /* Program current Receiver enable delay channel b */ - pci_write_config32_index_wait(ctrl->f2, 0x98, index+ 0x20, RcvrEnDly); - } - - /* Program the MaxAsyncLat filed with the - * current DQS receiver enable setting plus 6ns - */ - /* Program MaxAsyncLat to correspond with current delay */ - SetMaxAL_RcvrDly(ctrl, RcvrEnDly); - - CurrTest = DQS_FAIL; - - Read1LTestPattern(TestAddr0); //Cache Fill - /* ROM vs cache compare */ - Test0 = CompareTestPatternQW0(channel, TestAddr0, PatternA, TestPattern0, TestPattern1, TestPattern2, Pass, is_Width128); - proc_IOCLFLUSH(TestAddr0); - - ResetDCTWrPtr(ctrl); - - print_debug_dqs("\t\t\tTrainRcvEn542: Test0 ", Test0, 3); - - if (Test0 == DQS_PASS) { - - Read1LTestPattern(TestAddr0B); - Test1 = CompareTestPatternQW0(channel, TestAddr0B, PatternB, TestPattern0, TestPattern1, TestPattern2, Pass, is_Width128); - proc_IOCLFLUSH(TestAddr0B); - - ResetDCTWrPtr(ctrl); - - print_debug_dqs("\t\t\tTrainRcvEn543: Test1 ", Test1, 3); - - if (Test1 == DQS_PASS) { - if (two_ranks) { - Read1LTestPattern(TestAddr1); - Test0 = CompareTestPatternQW0(channel, TestAddr1, PatternA, TestPattern0, TestPattern1, TestPattern2, Pass, is_Width128); - proc_IOCLFLUSH(TestAddr1); - ResetDCTWrPtr(ctrl); - - if (Test0 == DQS_PASS) { - Read1LTestPattern(TestAddr1B); - Test1 = CompareTestPatternQW0(channel, TestAddr1B, PatternB, TestPattern0, TestPattern1, TestPattern2, Pass, is_Width128); - proc_IOCLFLUSH(TestAddr1B); - ResetDCTWrPtr(ctrl); - - if (Test1 == DQS_PASS) { - CurrTest = DQS_PASS; - } - } - print_debug_dqs("\t\t\tTrainRcvEn544: Test0 ", Test0, 3); - } - else { - CurrTest = DQS_PASS; - } - } - } - - print_debug_dqs("\t\t\tTrainRcvEn55: RcvrEnDly ", RcvrEnDly, 3); - - if (CurrTest == DQS_PASS) { - if (LastTest == DQS_FAIL) { - RcvrEnDlyRmin = RcvrEnDly; - break; - } - } - - LastTest = CurrTest; - - /* swap the rank 0 pointers */ - tmp = TestAddr0; - TestAddr0 = TestAddr0B; - TestAddr0B = tmp; - - /* swap the rank 1 pointers */ - tmp = TestAddr1; - TestAddr1 = TestAddr1B; - TestAddr1B = tmp; - - print_debug_dqs("\t\t\tTrainRcvEn56: RcvrEnDly ", RcvrEnDly, 3); - - RcvrEnDly++; - - } // while RcvrEnDly - - print_debug_dqs("\t\tTrainRcvEn61: RcvrEnDly ", RcvrEnDly, 2); - - if (RcvrEnDlyRmin == 0xaf) { - //no passing window - Errors |= SB_NORCVREN; - } - - if (Pass == DQS_FIRST_PASS) { - // We need a better value for DQSPos training - RcvrEnDly = RcvrEnDlyRmin /* + RCVREN_MARGIN * T1000/64/50 */; - } else { - RcvrEnDly = RcvrEnDlyRmin; - } - - if (RcvrEnDly > 0xae) { - //passing window too narrow, too far delayed - Errors |= SB_SmallRCVR; - RcvrEnDly = 0xae; - } - - if (Pass == DQS_SECOND_PASS) { //second pass must average vales - RcvrEnDly += dqs_rcvr_dly_a[channel * 8 + receiver] /* - (RCVREN_MARGIN * T1000/64/50)*/; - RcvrEnDly >>= 1; - } - - dqs_rcvr_dly_a[channel * 8 + receiver] = RcvrEnDly; - - //Set final RcvrEnDly for this DIMM and Channel - pci_write_config32_index_wait(ctrl->f2, 0x98, index, RcvrEnDly); - - if (is_Width128) { - pci_write_config32_index_wait(ctrl->f2, 0x98, index+0x20, RcvrEnDly); // channel B - if (channel) { - pci_write_config32_index_wait(ctrl->f2, 0x98, index, CurrRcvrCHADelay); - if (RcvrEnDly > CurrRcvrCHADelay) { - dword = RcvrEnDly - CurrRcvrCHADelay; - } - else { - dword = CurrRcvrCHADelay - RcvrEnDly; - } - dword *= 50; - if (dword > T1000) { - Errors |= SB_CHA2BRCVREN; - } - } - } - - print_debug_dqs("\t\tTrainRcvEn63: RcvrEnDly ", RcvrEnDly, 2); - - if (RcvrEnDly > CTLRMaxDelay) { - CTLRMaxDelay = RcvrEnDly; - } - - print_debug_dqs("\t\tTrainRcvEn64: CTLRMaxDelay ", CTLRMaxDelay, 2); - - } /* receiver */ - } /* channel */ - - print_debug_dqs("\tTrainRcvEn65: CTLRMaxDelay ", CTLRMaxDelay, 1); - - /* Program the MaxAsysncLat field with the largest DQS Receiver Enable setting */ - SetMaxAL_RcvrDly(ctrl, CTLRMaxDelay); - ResetDCTWrPtr(ctrl); - - //Enable ECC again - dword = pci_read_config32(ctrl->f2, DRAM_CONFIG_LOW); - dword &= ~(DCL_DimmEccEn); - dword |= ecc_bit; - pci_write_config32(ctrl->f2, DRAM_CONFIG_LOW, dword); - - if (Pass == DQS_FIRST_PASS) { -#if K8_REV_F_SUPPORT_F0_F1_WORKAROUND == 1 - if (!cpu_f0_f1) -#endif - { - dword = pci_read_config32(ctrl->f2, DRAM_CTRL); - dword &= ~DC_DqsRcvEnTrain; - pci_write_config32(ctrl->f2, DRAM_CTRL, dword); - } - } - - //Clear wrap32dis - - clear_wrap32dis(); - - //restore SSE2 setting - disable_sse2(); - -#if CONFIG_MEM_TRAIN_SEQ != 1 - /* We need tidy output for type 1 */ - printk(BIOS_DEBUG, " CTLRMaxDelay=%02x\n", CTLRMaxDelay); -#endif - - return (CTLRMaxDelay == 0xae)?1:0; - -} - -#define DQS_READDIR 1 -#define DQS_WRITEDIR 0 - - -static void SetDQSDelayCSR(const struct mem_controller *ctrl, unsigned channel, unsigned bytelane, unsigned direction, unsigned dqs_delay) -{ //ByteLane could be 0-8, last is for ECC - unsigned index; - uint32_t dword; - unsigned shift; - - dqs_delay &= 0xff; - - index = (bytelane>>2) + 1 + channel * 0x20 + (direction << 2); - shift = bytelane; - while (shift > 3) { - shift-=4; - } - shift <<= 3; // 8 bit - - dword = pci_read_config32_index_wait(ctrl->f2, 0x98, index); - dword &= ~(0x3f << shift); - dword |= (dqs_delay << shift); - pci_write_config32_index_wait(ctrl->f2, 0x98, index, dword); - -} - -static void SetDQSDelayAllCSR(const struct mem_controller *ctrl, unsigned channel, unsigned direction, unsigned dqs_delay) -{ - unsigned index; - uint32_t dword; - int i; - - dword = 0; - dqs_delay &= 0xff; - for (i = 0; i < 4; i++) { - dword |= dqs_delay << (i*8); - } - - index = 1 + channel * 0x20 + direction * 4; - - for (i = 0; i < 2; i++) { - pci_write_config32_index_wait(ctrl->f2, 0x98, index + i, dword); - } - -} - -static unsigned MiddleDQS(unsigned min_d, unsigned max_d) -{ - unsigned size_d; - size_d = max_d-min_d; - if (size_d & 1) { //need round up - min_d++; - } - return (min_d + (size_d>>1)); -} - -static inline void save_dqs_delay(unsigned channel, unsigned bytelane, unsigned direction, uint8_t *dqs_delay_a, uint8_t dqs_delay) -{ - dqs_delay_a[channel * 2*9 + direction * 9 + bytelane] = dqs_delay; -} - -static void WriteDQSTestPattern(unsigned addr_lo, unsigned pattern , uint8_t *buf_a) -{ - WriteLNTestPattern(addr_lo, buf_a, (pattern+1) * 9); -} - -static void ReadL18TestPattern(unsigned addr_lo) -{ - //set fs and use fs prefix to access the mem - __asm__ volatile ( - "movl %%fs:-128(%%esi), %%eax\n\t" //TestAddr cache line - "movl %%fs:-64(%%esi), %%eax\n\t" //+1 - "movl %%fs:(%%esi), %%eax\n\t" //+2 - "movl %%fs:64(%%esi), %%eax\n\t" //+3 - - "movl %%fs:-128(%%edi), %%eax\n\t" //+4 - "movl %%fs:-64(%%edi), %%eax\n\t" //+5 - "movl %%fs:(%%edi), %%eax\n\t" //+6 - "movl %%fs:64(%%edi), %%eax\n\t" //+7 - - "movl %%fs:-128(%%ebx), %%eax\n\t" //+8 - "movl %%fs:-64(%%ebx), %%eax\n\t" //+9 - "movl %%fs:(%%ebx), %%eax\n\t" //+10 - "movl %%fs:64(%%ebx), %%eax\n\t" //+11 - - "movl %%fs:-128(%%ecx), %%eax\n\t" //+12 - "movl %%fs:-64(%%ecx), %%eax\n\t" //+13 - "movl %%fs:(%%ecx), %%eax\n\t" //+14 - "movl %%fs:64(%%ecx), %%eax\n\t" //+15 - - "movl %%fs:-128(%%edx), %%eax\n\t" //+16 - "movl %%fs:-64(%%edx), %%eax\n\t" //+17 - - :: "a"(0), "b" (addr_lo+128+8*64), "c" (addr_lo+128+12*64), "d" (addr_lo +128+16*64), "S"(addr_lo+128), "D"(addr_lo+128+4*64) - ); - -} - -static void ReadL9TestPattern(unsigned addr_lo) -{ - - //set fs and use fs prefix to access the mem - __asm__ volatile ( - - "movl %%fs:-128(%%ecx), %%eax\n\t" //TestAddr cache line - "movl %%fs:-64(%%ecx), %%eax\n\t" //+1 - "movl %%fs:(%%ecx), %%eax\n\t" //+2 - "movl %%fs:64(%%ecx), %%eax\n\t" //+3 - - "movl %%fs:-128(%%edx), %%eax\n\t" //+4 - "movl %%fs:-64(%%edx), %%eax\n\t" //+5 - "movl %%fs:(%%edx), %%eax\n\t" //+6 - "movl %%fs:64(%%edx), %%eax\n\t" //+7 - - "movl %%fs:-128(%%ebx), %%eax\n\t" //+8 - - :: "a"(0), "b" (addr_lo+128+8*64), "c"(addr_lo+128), "d"(addr_lo+128+4*64) - ); - -} - - -static void ReadDQSTestPattern(unsigned addr_lo, unsigned pattern) -{ - if (pattern == 0) { - ReadL9TestPattern(addr_lo); - } - else { - ReadL18TestPattern(addr_lo); - } -} - -static void FlushDQSTestPattern_L9(unsigned addr_lo) -{ - __asm__ volatile ( - "clflush %%fs:-128(%%ecx)\n\t" - "clflush %%fs:-64(%%ecx)\n\t" - "clflush %%fs:(%%ecx)\n\t" - "clflush %%fs:64(%%ecx)\n\t" - - "clflush %%fs:-128(%%eax)\n\t" - "clflush %%fs:-64(%%eax)\n\t" - "clflush %%fs:(%%eax)\n\t" - "clflush %%fs:64(%%eax)\n\t" - - "clflush %%fs:-128(%%ebx)\n\t" - - :: "b" (addr_lo+128+8*64), "c"(addr_lo+128), "a"(addr_lo+128+4*64) - ); - -} -static __attribute__((noinline)) void FlushDQSTestPattern_L18(unsigned addr_lo) -{ - __asm__ volatile ( - "clflush %%fs:-128(%%eax)\n\t" - "clflush %%fs:-64(%%eax)\n\t" - "clflush %%fs:(%%eax)\n\t" - "clflush %%fs:64(%%eax)\n\t" - - "clflush %%fs:-128(%%edi)\n\t" - "clflush %%fs:-64(%%edi)\n\t" - "clflush %%fs:(%%edi)\n\t" - "clflush %%fs:64(%%edi)\n\t" - - "clflush %%fs:-128(%%ebx)\n\t" - "clflush %%fs:-64(%%ebx)\n\t" - "clflush %%fs:(%%ebx)\n\t" - "clflush %%fs:64(%%ebx)\n\t" - - "clflush %%fs:-128(%%ecx)\n\t" - "clflush %%fs:-64(%%ecx)\n\t" - "clflush %%fs:(%%ecx)\n\t" - "clflush %%fs:64(%%ecx)\n\t" - - "clflush %%fs:-128(%%edx)\n\t" - "clflush %%fs:-64(%%edx)\n\t" - - :: "b" (addr_lo+128+8*64), "c" (addr_lo+128+12*64), "d" (addr_lo +128+16*64), "a"(addr_lo+128), "D"(addr_lo+128+4*64) - ); -} - -static void FlushDQSTestPattern(unsigned addr_lo, unsigned pattern) -{ - - if (pattern == 0) { - FlushDQSTestPattern_L9(addr_lo); - } - else { - FlushDQSTestPattern_L18(addr_lo); - } -} - -static unsigned CompareDQSTestPattern(unsigned channel, unsigned addr_lo, unsigned pattern, uint8_t *buf_a) -{ - uint32_t *test_buf; - unsigned bitmap = 0xff; - unsigned bytelane; - int i; - uint32_t value; - int j; - uint32_t value_test; - - test_buf = (uint32_t *)buf_a; - - - if (pattern && channel) { - addr_lo += 8; //second channel - test_buf+= 2; - } - - bytelane = 0; - for (i = 0; i < 9*64/4; i++) { - __asm__ volatile ( - "movl %%fs:(%1), %0\n\t" - :"=b"(value): "a" (addr_lo) - ); - value_test = *test_buf; - - print_debug_dqs_pair("\t\t\t\t\t\ttest_buf= ", (unsigned)test_buf, " value = ", value_test, 7); - print_debug_dqs_pair("\t\t\t\t\t\ttaddr_lo = ",addr_lo, " value = ", value, 7); - - for (j = 0; j < 4*8; j+=8) { - if (((value>>j)&0xff) != ((value_test>>j)& 0xff)) { - bitmap &= ~(1 << bytelane); - } - - bytelane++; - bytelane &= 0x7; - } - print_debug_dqs("\t\t\t\t\t\tbitmap = ", bitmap, 7); - - if (bytelane == 0) { - if (pattern == 1) { //dual channel - addr_lo += 8; //skip over other channel's data - test_buf += 2; - } - } - addr_lo += 4; - test_buf +=1; - - } - - - return bitmap; - -} - -static unsigned TrainDQSPos(const struct mem_controller *ctrl, unsigned channel, unsigned Direction, unsigned Pattern, uint8_t *buf_a, uint8_t *dqs_delay_a, struct sys_info *sysinfo) -{ - unsigned ByteLane; - unsigned Errors; - unsigned BanksPresent; - - unsigned MutualCSPassW[48]; - - unsigned ChipSel; - unsigned DQSDelay; - - unsigned TestAddr; - - unsigned LastTest; - unsigned RnkDlyFilterMax, RnkDlyFilterMin = 0; - unsigned RnkDlySeqPassMax, RnkDlySeqPassMin = 0; - - Errors = 0; - BanksPresent = 0; - - print_debug_dqs("\t\t\tTrainDQSPos begin ", 0, 3); - - printk(BIOS_DEBUG, "TrainDQSPos: MutualCSPassW[48] :%p\n", MutualCSPassW); - - for (DQSDelay = 0; DQSDelay < 48; DQSDelay++) { - MutualCSPassW[DQSDelay] = 0xff; // Bitmapped status per delay setting, 0xff=All positions passing (1= PASS) - } - - for (ChipSel = 0; ChipSel < 8; ChipSel++) { //logical register chipselects 0..7 - print_debug_dqs("\t\t\t\tTrainDQSPos: 11 ChipSel ", ChipSel, 4); - //FIXME: process 64MUXedMode - if (!ChipSelPresent(ctrl, ChipSel, sysinfo)) continue; - BanksPresent = 1; - - TestAddr = Get_MCTSysAddr(ctrl, ChipSel, sysinfo); - - print_debug_dqs("\t\t\t\tTrainDQSPos: 12 TestAddr ", TestAddr, 4); - - //set fs and use fs prefix to access the mem - set_FSBASE(TestAddr>>24); - - if (Direction == DQS_READDIR) { - print_debug_dqs("\t\t\t\tTrainDQSPos: 13 for read so write at first", 0, 4); - WriteDQSTestPattern(TestAddr << 8, Pattern, buf_a); - } - - for (DQSDelay = 0; DQSDelay < 48; DQSDelay++) { - print_debug_dqs("\t\t\t\t\tTrainDQSPos: 141 DQSDelay ", DQSDelay, 5); - if (MutualCSPassW[DQSDelay] == 0) continue; //skip current delay value if other chipselects have failed all 8 bytelanes - SetDQSDelayAllCSR(ctrl, channel, Direction, DQSDelay); - print_debug_dqs("\t\t\t\t\tTrainDQSPos: 142 MutualCSPassW ", MutualCSPassW[DQSDelay], 5); - if (Direction == DQS_WRITEDIR) { - print_debug_dqs("\t\t\t\t\tTrainDQSPos: 143 for write", 0, 5); - WriteDQSTestPattern(TestAddr << 8, Pattern, buf_a); - } - print_debug_dqs("\t\t\t\t\tTrainDQSPos: 144 Pattern ", Pattern, 5); - ReadDQSTestPattern(TestAddr << 8, Pattern); - print_debug_dqs("\t\t\t\t\tTrainDQSPos: 145 MutualCSPassW ", MutualCSPassW[DQSDelay], 5); - MutualCSPassW[DQSDelay] &= CompareDQSTestPattern(channel, TestAddr << 8, Pattern, buf_a); //0: fail, 1=pass - print_debug_dqs("\t\t\t\t\tTrainDQSPos: 146 MutualCSPassW ", MutualCSPassW[DQSDelay], 5); - SetTargetWTIO(TestAddr); - FlushDQSTestPattern(TestAddr << 8, Pattern); - ResetTargetWTIO(); - } - } - - if (BanksPresent) - for (ByteLane = 0; ByteLane < 8; ByteLane++) { - print_debug_dqs("\t\t\t\tTrainDQSPos: 31 ByteLane ",ByteLane, 4); - - LastTest = DQS_FAIL; - RnkDlySeqPassMax = 0; - RnkDlyFilterMax = 0; - RnkDlyFilterMin = 0; - for (DQSDelay = 0; DQSDelay < 48; DQSDelay++) { - if (MutualCSPassW[DQSDelay] & (1 << ByteLane)) { - - print_debug_dqs("\t\t\t\t\tTrainDQSPos: 321 DQSDelay ", DQSDelay, 5); - print_debug_dqs("\t\t\t\t\tTrainDQSPos: 322 MutualCSPassW ", MutualCSPassW[DQSDelay], 5); - - RnkDlySeqPassMax = DQSDelay; - if (LastTest == DQS_FAIL) { - RnkDlySeqPassMin = DQSDelay; //start sequential run - } - if ((RnkDlySeqPassMax - RnkDlySeqPassMin)>(RnkDlyFilterMax-RnkDlyFilterMin)) { - RnkDlyFilterMin = RnkDlySeqPassMin; - RnkDlyFilterMax = RnkDlySeqPassMax; - } - LastTest = DQS_PASS; - } - else { - LastTest = DQS_FAIL; - } - } - print_debug_dqs("\t\t\t\tTrainDQSPos: 33 RnkDlySeqPassMax ", RnkDlySeqPassMax, 4); - - if (RnkDlySeqPassMax == 0) { - Errors |= SB_NODQSPOS; // no passing window - } - else { - print_debug_dqs("\t\t\t\tTrainDQSPos: 34 RnkDlyFilterMax ", RnkDlyFilterMax, 4); - print_debug_dqs("\t\t\t\tTrainDQSPos: 34 RnkDlyFilterMin ", RnkDlyFilterMin, 4); - if ((RnkDlyFilterMax - RnkDlyFilterMin)< MIN_DQS_WNDW) { - Errors |= SB_SMALLDQS; - } - else { - unsigned middle_dqs; - middle_dqs = MiddleDQS(RnkDlyFilterMin, RnkDlyFilterMax); - print_debug_dqs("\t\t\t\tTrainDQSPos: 35 middle_dqs ",middle_dqs, 4); - SetDQSDelayCSR(ctrl, channel, ByteLane, Direction, middle_dqs); - save_dqs_delay(channel, ByteLane, Direction, dqs_delay_a, middle_dqs); - } - } - - } - - print_debug_dqs("\t\t\tTrainDQSPos: end", 0xff, 3); - - return Errors; - - -} - -static unsigned TrainReadDQS(const struct mem_controller *ctrl, unsigned channel, unsigned pattern, uint8_t *buf_a, uint8_t *dqs_delay_a, struct sys_info *sysinfo) -{ - print_debug_dqs("\t\tTrainReadPos", 0, 2); - return TrainDQSPos(ctrl, channel, DQS_READDIR, pattern, buf_a, dqs_delay_a, sysinfo); -} - -static unsigned TrainWriteDQS(const struct mem_controller *ctrl, unsigned channel, unsigned pattern, uint8_t *buf_a, uint8_t *dqs_delay_a, struct sys_info *sysinfo) -{ - print_debug_dqs("\t\tTrainWritePos", 0, 2); - return TrainDQSPos(ctrl, channel, DQS_WRITEDIR, pattern, buf_a, dqs_delay_a, sysinfo); -} - - - -static unsigned TrainDQSRdWrPos(const struct mem_controller *ctrl, struct sys_info *sysinfo) -{ - static const uint32_t TestPatternJD1a[] = { - 0x00000000,0x00000000,0xFFFFFFFF,0xFFFFFFFF, // QW0-1, ALL-EVEN - 0x00000000,0x00000000,0x00000000,0x00000000, // QW2-3, ALL-EVEN - 0x00000000,0x00000000,0xFFFFFFFF,0xFFFFFFFF, // QW4-5, ALL-EVEN - 0x00000000,0x00000000,0x00000000,0x00000000, // QW6-7, ALL-EVEN - 0xFeFeFeFe,0xFeFeFeFe,0x01010101,0x01010101, // QW0-1, DQ0-ODD - 0xFeFeFeFe,0xFeFeFeFe,0x01010101,0x01010101, // QW2-3, DQ0-ODD - 0x01010101,0x01010101,0xFeFeFeFe,0xFeFeFeFe, // QW4-5, DQ0-ODD - 0xFeFeFeFe,0xFeFeFeFe,0x01010101,0x01010101, // QW6-7, DQ0-ODD - 0x02020202,0x02020202,0x02020202,0x02020202, // QW0-1, DQ1-ODD - 0xFdFdFdFd,0xFdFdFdFd,0xFdFdFdFd,0xFdFdFdFd, // QW2-3, DQ1-ODD - 0xFdFdFdFd,0xFdFdFdFd,0x02020202,0x02020202, // QW4-5, DQ1-ODD - 0x02020202,0x02020202,0x02020202,0x02020202, // QW6-7, DQ1-ODD - 0x04040404,0x04040404,0xfBfBfBfB,0xfBfBfBfB, // QW0-1, DQ2-ODD - 0x04040404,0x04040404,0x04040404,0x04040404, // QW2-3, DQ2-ODD - 0xfBfBfBfB,0xfBfBfBfB,0xfBfBfBfB,0xfBfBfBfB, // QW4-5, DQ2-ODD - 0xfBfBfBfB,0xfBfBfBfB,0xfBfBfBfB,0xfBfBfBfB, // QW6-7, DQ2-ODD - 0x08080808,0x08080808,0xF7F7F7F7,0xF7F7F7F7, // QW0-1, DQ3-ODD - 0x08080808,0x08080808,0x08080808,0x08080808, // QW2-3, DQ3-ODD - 0xF7F7F7F7,0xF7F7F7F7,0x08080808,0x08080808, // QW4-5, DQ3-ODD - 0xF7F7F7F7,0xF7F7F7F7,0xF7F7F7F7,0xF7F7F7F7, // QW6-7, DQ3-ODD - 0x10101010,0x10101010,0x10101010,0x10101010, // QW0-1, DQ4-ODD - 0xeFeFeFeF,0xeFeFeFeF,0x10101010,0x10101010, // QW2-3, DQ4-ODD - 0xeFeFeFeF,0xeFeFeFeF,0xeFeFeFeF,0xeFeFeFeF, // QW4-5, DQ4-ODD - 0xeFeFeFeF,0xeFeFeFeF,0x10101010,0x10101010, // QW6-7, DQ4-ODD - 0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF, // QW0-1, DQ5-ODD - 0xdFdFdFdF,0xdFdFdFdF,0x20202020,0x20202020, // QW2-3, DQ5-ODD - 0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF, // QW4-5, DQ5-ODD - 0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF, // QW6-7, DQ5-ODD - 0xBfBfBfBf,0xBfBfBfBf,0xBfBfBfBf,0xBfBfBfBf, // QW0-1, DQ6-ODD - 0x40404040,0x40404040,0xBfBfBfBf,0xBfBfBfBf, // QW2-3, DQ6-ODD - 0x40404040,0x40404040,0xBfBfBfBf,0xBfBfBfBf, // QW4-5, DQ6-ODD - 0x40404040,0x40404040,0xBfBfBfBf,0xBfBfBfBf, // QW6-7, DQ6-ODD - 0x80808080,0x80808080,0x7F7F7F7F,0x7F7F7F7F, // QW0-1, DQ7-ODD - 0x80808080,0x80808080,0x7F7F7F7F,0x7F7F7F7F, // QW2-3, DQ7-ODD - 0x80808080,0x80808080,0x7F7F7F7F,0x7F7F7F7F, // QW4-5, DQ7-ODD - 0x80808080,0x80808080,0x80808080,0x80808080 // QW6-7, DQ7-ODD - }; - static const uint32_t TestPatternJD1b[] = { - 0x00000000,0x00000000,0x00000000,0x00000000, // QW0,CHA-B, ALL-EVEN - 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, // QW1,CHA-B, ALL-EVEN - 0x00000000,0x00000000,0x00000000,0x00000000, // QW2,CHA-B, ALL-EVEN - 0x00000000,0x00000000,0x00000000,0x00000000, // QW3,CHA-B, ALL-EVEN - 0x00000000,0x00000000,0x00000000,0x00000000, // QW4,CHA-B, ALL-EVEN - 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, // QW5,CHA-B, ALL-EVEN - 0x00000000,0x00000000,0x00000000,0x00000000, // QW6,CHA-B, ALL-EVEN - 0x00000000,0x00000000,0x00000000,0x00000000, // QW7,CHA-B, ALL-EVEN - 0xFeFeFeFe,0xFeFeFeFe,0xFeFeFeFe,0xFeFeFeFe, // QW0,CHA-B, DQ0-ODD - 0x01010101,0x01010101,0x01010101,0x01010101, // QW1,CHA-B, DQ0-ODD - 0xFeFeFeFe,0xFeFeFeFe,0xFeFeFeFe,0xFeFeFeFe, // QW2,CHA-B, DQ0-ODD - 0x01010101,0x01010101,0x01010101,0x01010101, // QW3,CHA-B, DQ0-ODD - 0x01010101,0x01010101,0x01010101,0x01010101, // QW4,CHA-B, DQ0-ODD - 0xFeFeFeFe,0xFeFeFeFe,0xFeFeFeFe,0xFeFeFeFe, // QW5,CHA-B, DQ0-ODD - 0xFeFeFeFe,0xFeFeFeFe,0xFeFeFeFe,0xFeFeFeFe, // QW6,CHA-B, DQ0-ODD - 0x01010101,0x01010101,0x01010101,0x01010101, // QW7,CHA-B, DQ0-ODD - 0x02020202,0x02020202,0x02020202,0x02020202, // QW0,CHA-B, DQ1-ODD - 0x02020202,0x02020202,0x02020202,0x02020202, // QW1,CHA-B, DQ1-ODD - 0xFdFdFdFd,0xFdFdFdFd,0xFdFdFdFd,0xFdFdFdFd, // QW2,CHA-B, DQ1-ODD - 0xFdFdFdFd,0xFdFdFdFd,0xFdFdFdFd,0xFdFdFdFd, // QW3,CHA-B, DQ1-ODD - 0xFdFdFdFd,0xFdFdFdFd,0xFdFdFdFd,0xFdFdFdFd, // QW4,CHA-B, DQ1-ODD - 0x02020202,0x02020202,0x02020202,0x02020202, // QW5,CHA-B, DQ1-ODD - 0x02020202,0x02020202,0x02020202,0x02020202, // QW6,CHA-B, DQ1-ODD - 0x02020202,0x02020202,0x02020202,0x02020202, // QW7,CHA-B, DQ1-ODD - 0x04040404,0x04040404,0x04040404,0x04040404, // QW0,CHA-B, DQ2-ODD - 0xfBfBfBfB,0xfBfBfBfB,0xfBfBfBfB,0xfBfBfBfB, // QW1,CHA-B, DQ2-ODD - 0x04040404,0x04040404,0x04040404,0x04040404, // QW2,CHA-B, DQ2-ODD - 0x04040404,0x04040404,0x04040404,0x04040404, // QW3,CHA-B, DQ2-ODD - 0xfBfBfBfB,0xfBfBfBfB,0xfBfBfBfB,0xfBfBfBfB, // QW4,CHA-B, DQ2-ODD - 0xfBfBfBfB,0xfBfBfBfB,0xfBfBfBfB,0xfBfBfBfB, // QW5,CHA-B, DQ2-ODD - 0xfBfBfBfB,0xfBfBfBfB,0xfBfBfBfB,0xfBfBfBfB, // QW6,CHA-B, DQ2-ODD - 0xfBfBfBfB,0xfBfBfBfB,0xfBfBfBfB,0xfBfBfBfB, // QW7,CHA-B, DQ2-ODD - 0x08080808,0x08080808,0x08080808,0x08080808, // QW0,CHA-B, DQ3-ODD - 0xF7F7F7F7,0xF7F7F7F7,0xF7F7F7F7,0xF7F7F7F7, // QW1,CHA-B, DQ3-ODD - 0x08080808,0x08080808,0x08080808,0x08080808, // QW2,CHA-B, DQ3-ODD - 0x08080808,0x08080808,0x08080808,0x08080808, // QW3,CHA-B, DQ3-ODD - 0xF7F7F7F7,0xF7F7F7F7,0xF7F7F7F7,0xF7F7F7F7, // QW4,CHA-B, DQ3-ODD - 0x08080808,0x08080808,0x08080808,0x08080808, // QW5,CHA-B, DQ3-ODD - 0xF7F7F7F7,0xF7F7F7F7,0xF7F7F7F7,0xF7F7F7F7, // QW6,CHA-B, DQ3-ODD - 0xF7F7F7F7,0xF7F7F7F7,0xF7F7F7F7,0xF7F7F7F7, // QW7,CHA-B, DQ3-ODD - 0x10101010,0x10101010,0x10101010,0x10101010, // QW0,CHA-B, DQ4-ODD - 0x10101010,0x10101010,0x10101010,0x10101010, // QW1,CHA-B, DQ4-ODD - 0xeFeFeFeF,0xeFeFeFeF,0xeFeFeFeF,0xeFeFeFeF, // QW2,CHA-B, DQ4-ODD - 0x10101010,0x10101010,0x10101010,0x10101010, // QW3,CHA-B, DQ4-ODD - 0xeFeFeFeF,0xeFeFeFeF,0xeFeFeFeF,0xeFeFeFeF, // QW4,CHA-B, DQ4-ODD - 0xeFeFeFeF,0xeFeFeFeF,0xeFeFeFeF,0xeFeFeFeF, // QW5,CHA-B, DQ4-ODD - 0xeFeFeFeF,0xeFeFeFeF,0xeFeFeFeF,0xeFeFeFeF, // QW6,CHA-B, DQ4-ODD - 0x10101010,0x10101010,0x10101010,0x10101010, // QW7,CHA-B, DQ4-ODD - 0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF, // QW0,CHA-B, DQ5-ODD - 0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF, // QW1,CHA-B, DQ5-ODD - 0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF, // QW2,CHA-B, DQ5-ODD - 0x20202020,0x20202020,0x20202020,0x20202020, // QW3,CHA-B, DQ5-ODD - 0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF, // QW4,CHA-B, DQ5-ODD - 0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF, // QW5,CHA-B, DQ5-ODD - 0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF, // QW6,CHA-B, DQ5-ODD - 0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF, // QW7,CHA-B, DQ5-ODD - 0xBfBfBfBf,0xBfBfBfBf,0xBfBfBfBf,0xBfBfBfBf, // QW0,CHA-B, DQ6-ODD - 0xBfBfBfBf,0xBfBfBfBf,0xBfBfBfBf,0xBfBfBfBf, // QW1,CHA-B, DQ6-ODD - 0x40404040,0x40404040,0x40404040,0x40404040, // QW2,CHA-B, DQ6-ODD - 0xBfBfBfBf,0xBfBfBfBf,0xBfBfBfBf,0xBfBfBfBf, // QW3,CHA-B, DQ6-ODD - 0x40404040,0x40404040,0x40404040,0x40404040, // QW4,CHA-B, DQ6-ODD - 0xBfBfBfBf,0xBfBfBfBf,0xBfBfBfBf,0xBfBfBfBf, // QW5,CHA-B, DQ6-ODD - 0x40404040,0x40404040,0x40404040,0x40404040, // QW6,CHA-B, DQ6-ODD - 0xBfBfBfBf,0xBfBfBfBf,0xBfBfBfBf,0xBfBfBfBf, // QW7,CHA-B, DQ6-ODD - 0x80808080,0x80808080,0x80808080,0x80808080, // QW0,CHA-B, DQ7-ODD - 0x7F7F7F7F,0x7F7F7F7F,0x7F7F7F7F,0x7F7F7F7F, // QW1,CHA-B, DQ7-ODD - 0x80808080,0x80808080,0x80808080,0x80808080, // QW2,CHA-B, DQ7-ODD - 0x7F7F7F7F,0x7F7F7F7F,0x7F7F7F7F,0x7F7F7F7F, // QW3,CHA-B, DQ7-ODD - 0x80808080,0x80808080,0x80808080,0x80808080, // QW4,CHA-B, DQ7-ODD - 0x7F7F7F7F,0x7F7F7F7F,0x7F7F7F7F,0x7F7F7F7F, // QW5,CHA-B, DQ7-ODD - 0x80808080,0x80808080,0x80808080,0x80808080, // QW6,CHA-B, DQ7-ODD - 0x80808080,0x80808080,0x80808080,0x80808080 // QW7,CHA-B, DQ7-ODD - }; - uint8_t pattern_buf_x[64 * 18 + 16]; // We need to two cache line So have more 16 bytes to keep 16 byte alignment */ - uint8_t *buf_a; - - unsigned pattern; - uint32_t dword; - uint32_t ecc_bit; - unsigned Errors; - unsigned channel; - int i; - unsigned DQSWrDelay; - unsigned is_Width128 = sysinfo->meminfo[ctrl->node_id].is_Width128; - uint8_t *dqs_delay_a = &sysinfo->dqs_delay_a[ctrl->node_id * 2*2*9]; //channel 2, direction 2 , bytelane *9 - - //enable SSE2 - enable_sse2(); - - //wrap32dis - set_wrap32dis(); - - //disable ECC temp - dword = pci_read_config32(ctrl->f2, DRAM_CONFIG_LOW); - ecc_bit = dword & DCL_DimmEccEn; - dword &= ~(DCL_DimmEccEn); - pci_write_config32(ctrl->f2, DRAM_CONFIG_LOW, dword); - - //SetupDqsPattern - buf_a = (uint8_t *)(((uint32_t)(&pattern_buf_x[0]) + 0x10) & (~0xf)); - - if (is_Width128) { - pattern = 1; - for (i = 0; i < 16*18; i++) { - *((uint32_t *)(buf_a + i*4)) = TestPatternJD1b[i]; - } - } - else { - pattern = 0; - for (i = 0; i < 16*9; i++) { - *((uint32_t *)(buf_a + i*4)) = TestPatternJD1a[i]; - } - - } - - print_debug_dqs("\nTrainDQSRdWrPos: 0 ctrl ", ctrl->node_id, 0); - - printk(BIOS_DEBUG, "TrainDQSRdWrPos: buf_a:%p\n", buf_a); - - Errors = 0; - channel = 0; - - if (!(sysinfo->meminfo[ctrl->node_id].dimm_mask & 0x0F) && - (sysinfo->meminfo[ctrl->node_id].dimm_mask & 0xF0)) { /* channelB only? */ - channel = 1; - } - - while ((channel < 2) && (!Errors)) { - print_debug_dqs("\tTrainDQSRdWrPos: 1 channel ",channel, 1); - for (DQSWrDelay = 0; DQSWrDelay < 48; DQSWrDelay++) { - unsigned err; - SetDQSDelayAllCSR(ctrl, channel, DQS_WRITEDIR, DQSWrDelay); - print_debug_dqs("\t\tTrainDQSRdWrPos: 21 DQSWrDelay ", DQSWrDelay, 2); - err= TrainReadDQS(ctrl, channel, pattern, buf_a, dqs_delay_a, sysinfo); - print_debug_dqs("\t\tTrainDQSRdWrPos: 22 err ",err, 2); - if (err == 0) break; - Errors |= err; - } - - print_debug_dqs("\tTrainDQSRdWrPos: 3 DQSWrDelay ", DQSWrDelay, 1); - - if (DQSWrDelay < 48) { - Errors = TrainWriteDQS(ctrl, channel, pattern, buf_a, dqs_delay_a, sysinfo); - print_debug_dqs("\tTrainDQSRdWrPos: 4 Errors ", Errors, 1); - - } - channel++; - if (!is_Width128) { - //FIXME: 64MuxMode?? - channel++; // skip channel if 64-bit mode - } - } - - //Enable ECC again - dword = pci_read_config32(ctrl->f2, DRAM_CONFIG_LOW); - dword &= ~(DCL_DimmEccEn); - dword |= ecc_bit; - pci_write_config32(ctrl->f2, DRAM_CONFIG_LOW, dword); - - //Clear wrap32dis - - clear_wrap32dis(); - - //restore SSE2 setting - disable_sse2(); - - print_debug_dqs("TrainDQSRdWrPos: ", 5, 0); - - return Errors; - -} -static inline uint8_t get_dqs_delay(unsigned channel, unsigned bytelane, unsigned direction, uint8_t *dqs_delay_a) -{ - return dqs_delay_a[channel * 2*9 + direction * 9 + bytelane]; -} - -static unsigned CalcEccDQSPos(unsigned channel,unsigned ByteLane0, unsigned ByteLane1, unsigned InterFactor, unsigned Direction, uint8_t *dqs_delay_a) -/* InterFactor: 0: 100% ByteLane 0 - 0x80: 50% between ByteLane 0 and 1 - 0xff: 99.6% ByteLane 1 and 0.4% like 0 -*/ -{ - unsigned DQSDelay0, DQSDelay1; - unsigned DQSDelay; - - DQSDelay0 = get_dqs_delay(channel, ByteLane0, Direction, dqs_delay_a); - DQSDelay1 = get_dqs_delay(channel, ByteLane1, Direction, dqs_delay_a); - - if (DQSDelay0 > DQSDelay1) { - DQSDelay = DQSDelay0 - DQSDelay1; - InterFactor = 0xff - InterFactor; - } - else { - DQSDelay = DQSDelay1 - DQSDelay0; - } - - DQSDelay *= InterFactor; - - DQSDelay >>= 8; // /255 - - if (DQSDelay0 > DQSDelay1) { - DQSDelay += DQSDelay1; - } - else { - DQSDelay += DQSDelay0; - } - - return DQSDelay; - -} - -static void SetEccDQSRdWrPos(const struct mem_controller *ctrl, struct sys_info *sysinfo) -{ - unsigned channel; - unsigned ByteLane; - unsigned Direction; - unsigned lane0, lane1, ratio; - unsigned dqs_delay; - - unsigned direction[] = { DQS_READDIR, DQS_WRITEDIR }; - int i; - uint8_t *dqs_delay_a = &sysinfo->dqs_delay_a[ctrl->node_id * 2*2*9]; //channel 2, direction 2 , bytelane *9 - - ByteLane = 8; - - for (channel = 0; channel < 2; channel++) { - for (i = 0; i < 2; i++) { - Direction = direction[i]; - lane0 = 4; lane1 = 5; ratio = 0; - dqs_delay = CalcEccDQSPos(channel, lane0, lane1, ratio, Direction, dqs_delay_a); - print_debug_dqs_pair("\t\tSetEccDQSRdWrPos: channel ", channel, Direction == DQS_READDIR? " R dqs_delay":" W dqs_delay", dqs_delay, 2); - SetDQSDelayCSR(ctrl, channel, ByteLane, Direction, dqs_delay); - save_dqs_delay(channel, ByteLane, Direction, dqs_delay_a, dqs_delay); - } - } -} - -static unsigned train_DqsRcvrEn(const struct mem_controller *ctrl, unsigned Pass, struct sys_info *sysinfo) -{ - print_debug_dqs("\ntrain_DqsRcvrEn: begin ctrl ", ctrl->node_id, 0); - if (TrainRcvrEn(ctrl, Pass, sysinfo)) { - return 1; - } - print_debug_dqs("\ntrain_DqsRcvrEn: end ctrl ", ctrl->node_id, 0); - return 0; - -} -static unsigned train_DqsPos(const struct mem_controller *ctrl, struct sys_info *sysinfo) -{ - print_debug_dqs("\ntrain_DqsPos: begin ctrl ", ctrl->node_id, 0); - if (TrainDQSRdWrPos(ctrl, sysinfo) != 0) { - printk(BIOS_ERR, "\nDQS Training Rd Wr failed ctrl%02x\n", ctrl->node_id); - return 1; - } - else { - SetEccDQSRdWrPos(ctrl, sysinfo); - } - print_debug_dqs("\ntrain_DqsPos: end ctrl ", ctrl->node_id, 0); - return 0; - -} - -#if K8_REV_F_SUPPORT_F0_F1_WORKAROUND == 1 -static void f0_svm_workaround(int controllers, const struct mem_controller *ctrl, tsc_t *tsc0, struct sys_info *sysinfo) -{ - tsc_t tsc1[8]; - unsigned cpu_f0_f1[8]; - int i; - - print_debug_addr("dqs_timing: tsc1[8] :", tsc1); - - for (i = 0; i < controllers; i++) { - if (!sysinfo->ctrl_present[i]) - continue; - - /* Skip everything if I don't have any memory on this controller */ - if (sysinfo->meminfo[i].dimm_mask == 0x00) continue; - - uint32_t dword; - - cpu_f0_f1[i] = is_cpu_pre_f2_in_bsp(i); - - if (!cpu_f0_f1[i]) continue; - - dword = pci_read_config32(ctrl[i].f2, DRAM_CTRL); - dword &= ~DC_DqsRcvEnTrain; - pci_write_config32(ctrl[i].f2, DRAM_CTRL, dword); - - dword = pci_read_config32(ctrl[i].f2, DRAM_INIT); - dword |= DI_EnDramInit; - pci_write_config32(ctrl[i].f2, DRAM_INIT, dword); - dword &= ~DI_EnDramInit; - pci_write_config32(ctrl[i].f2, DRAM_INIT, dword); - - tsc1[i] = rdtsc(); - print_debug_dqs_tsc("begin: tsc1", i, tsc1[i].hi, tsc1[i].lo, 2); - - dword = tsc1[i].lo + tsc0[i].lo; - if ((dword < tsc1[i].lo) || (dword < tsc0[i].lo)) { - tsc1[i].hi++; - } - tsc1[i].lo = dword; - tsc1[i].hi+= tsc0[i].hi; - - print_debug_dqs_tsc("end : tsc1", i, tsc1[i].hi, tsc1[i].lo, 2); - - } - - for (i = 0; i < controllers; i++) { - if (!sysinfo->ctrl_present[i]) - continue; - - /* Skip everything if I don't have any memory on this controller */ - if (sysinfo->meminfo[i].dimm_mask == 0x00) continue; - - if (!cpu_f0_f1[i]) continue; - - tsc_t tsc; - - do { - tsc = rdtsc(); - } while ((tsc1[i].hi > tsc.hi) || ((tsc1[i].hi == tsc.hi) && (tsc1[i].lo > tsc.lo))); - - print_debug_dqs_tsc("end : tsc ", i, tsc.hi, tsc.lo, 2); - } - -} - -#endif - - -/* setting variable mtrr, comes from linux kernel source */ -static void set_var_mtrr_dqs( - unsigned int reg, unsigned long basek, unsigned long sizek, - unsigned char type, unsigned address_bits) -{ - msr_t base, mask; - unsigned address_mask_high; - - address_mask_high = ((1u << (address_bits - 32u)) - 1u); - - base.hi = basek >> 22; - base.lo = basek << 10; - - if (sizek < 4*1024*1024) { - mask.hi = address_mask_high; - mask.lo = ~((sizek << 10) -1); - } - else { - mask.hi = address_mask_high & (~((sizek >> 22) -1)); - mask.lo = 0; - } - - if (reg >= 8) - return; - - if (sizek == 0) { - msr_t zero; - zero.lo = zero.hi = 0; - /* The invalid bit is kept in the mask, so we simply clear the - relevant mask register to disable a range. */ - wrmsr (MTRR_PHYS_MASK(reg), zero); - } else { - /* Bit 32-35 of MTRRphysMask should be set to 1 */ - base.lo |= type; - mask.lo |= 0x800; - wrmsr (MTRR_PHYS_BASE(reg), base); - wrmsr (MTRR_PHYS_MASK(reg), mask); - } -} - -static unsigned int range_to_mtrr(unsigned int reg, - unsigned long range_startk, unsigned long range_sizek, - unsigned long next_range_startk, unsigned char type, unsigned address_bits) -{ - if (!range_sizek || (reg >= 8)) { - return reg; - } - while (range_sizek) { - unsigned long max_align, align; - unsigned long sizek; - /* Compute the maximum size I can make a range */ - max_align = fls(range_startk); - align = fms(range_sizek); - if (align > max_align) { - align = max_align; - } - sizek = 1 << align; -#if CONFIG_MEM_TRAIN_SEQ != 1 - printk(BIOS_DEBUG, "Setting variable MTRR %d, base: %4ldMB, range: %4ldMB, type %s\n", - reg, range_startk >>10, sizek >> 10, - (type == MTRR_TYPE_UNCACHEABLE)?"UC": - ((type == MTRR_TYPE_WRBACK)?"WB":"Other") - ); -#endif - set_var_mtrr_dqs(reg++, range_startk, sizek, type, address_bits); - range_startk += sizek; - range_sizek -= sizek; - if (reg >= 8) - break; - } - return reg; -} - -#if CONFIG_MEM_TRAIN_SEQ == 1 -static void set_top_mem_ap(unsigned tom_k, unsigned tom2_k) -{ - msr_t msr; - - /* Now set top of memory */ - msr.lo = (tom2_k & 0x003fffff) << 10; - msr.hi = (tom2_k & 0xffc00000) >> 22; - wrmsr(TOP_MEM2, msr); - - msr.lo = (tom_k & 0x003fffff) << 10; - msr.hi = (tom_k & 0xffc00000) >> 22; - wrmsr(TOP_MEM, msr); -} -#endif - -static void setup_mtrr_dqs(unsigned tom_k, unsigned tom2_k) -{ - msr_t msr; - - //[0,512k), [512k, 640k) - msr.hi = 0x1e1e1e1e; - msr.lo = msr.hi; - wrmsr(0x250, msr); - wrmsr(0x258, msr); - - //[1M, TOM) - range_to_mtrr(2, 0, tom_k,4*1024*1024, MTRR_TYPE_WRBACK, 40); - - //[4G, TOM2) - if (tom2_k) { - //enable tom2 and type - msr = rdmsr(SYSCFG_MSR); - msr.lo |= (1<<21) | (1<<22); //MtrrTom2En and Tom2ForceMemTypeWB - wrmsr(SYSCFG_MSR, msr); - } - -} - -static void clear_mtrr_dqs(unsigned tom2_k) -{ - msr_t msr; - unsigned i; - - //still enable from cache_as_ram.inc - msr = rdmsr(SYSCFG_MSR); - msr.lo |= SYSCFG_MSR_MtrrFixDramModEn; - wrmsr(SYSCFG_MSR,msr); - - //[0,512k), [512k, 640k) - msr.hi = 0; - msr.lo = msr.hi; - wrmsr(0x250, msr); - wrmsr(0x258, msr); - - //[1M, TOM) - for (i = 0x204; i < 0x210; i++) { - wrmsr(i, msr); - } - - //[4G, TOM2) - if (tom2_k) { - //enable tom2 and type - msr = rdmsr(SYSCFG_MSR); - msr.lo &= ~((1<<21) | (1<<22)); //MtrrTom2En and Tom2ForceMemTypeWB - wrmsr(SYSCFG_MSR, msr); - } -} - -#if CONFIG_MEM_TRAIN_SEQ == 1 -static void set_htic_bit(unsigned i, unsigned val, unsigned bit) -{ - uint32_t dword; - dword = pci_read_config32(PCI_DEV(0, 0x18+i, 0), HT_INIT_CONTROL); - dword &= ~(1 << bit); - dword |= ((val & 1) << bit); - pci_write_config32(PCI_DEV(0, 0x18+i, 0), HT_INIT_CONTROL, dword); -} - -static unsigned get_htic_bit(unsigned i, unsigned bit) -{ - uint32_t dword; - dword = pci_read_config32(PCI_DEV(0, 0x18+i, 0), HT_INIT_CONTROL); - dword &= (1 << bit); - return dword; -} - -static void wait_till_sysinfo_in_ram(void) -{ - while (1) { - if (get_htic_bit(0, 9)) return; - } -} -#endif - -void set_sysinfo_in_ram(unsigned val) -{ -#if CONFIG_MEM_TRAIN_SEQ == 1 - set_htic_bit(0, val, 9); -#endif -} - -#if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME) - -#if CONFIG_MEM_TRAIN_SEQ == 0 -static int save_index_to_pos(unsigned int dev, int size, int index, int nvram_pos) -{ - u32 dword = pci_read_config32_index_wait(dev, 0x98, index); - - return s3_save_nvram_early(dword, size, nvram_pos); -} -#endif - -static int load_index_to_pos(unsigned int dev, int size, int index, int nvram_pos) -{ - - u32 old_dword = pci_read_config32_index_wait(dev, 0x98, index); - nvram_pos = s3_load_nvram_early(size, &old_dword, nvram_pos); - pci_write_config32_index_wait(dev, 0x98, index, old_dword); - return nvram_pos; -} - -static int dqs_load_MC_NVRAM_ch(unsigned int dev, int ch, int pos) -{ - /* 30 bytes per channel */ - ch *= 0x20; - pos = load_index_to_pos(dev, 4, 0x00 + ch, pos); - pos = load_index_to_pos(dev, 4, 0x01 + ch, pos); - pos = load_index_to_pos(dev, 4, 0x02 + ch, pos); - pos = load_index_to_pos(dev, 1, 0x03 + ch, pos); - pos = load_index_to_pos(dev, 4, 0x04 + ch, pos); - pos = load_index_to_pos(dev, 4, 0x05 + ch, pos); - pos = load_index_to_pos(dev, 4, 0x06 + ch, pos); - pos = load_index_to_pos(dev, 1, 0x07 + ch, pos); - pos = load_index_to_pos(dev, 1, 0x10 + ch, pos); - pos = load_index_to_pos(dev, 1, 0x13 + ch, pos); - pos = load_index_to_pos(dev, 1, 0x16 + ch, pos); - pos = load_index_to_pos(dev, 1, 0x19 + ch, pos); - return pos; -} - -#if CONFIG_MEM_TRAIN_SEQ == 0 -static int dqs_save_MC_NVRAM_ch(unsigned int dev, int ch, int pos) -{ - /* 30 bytes per channel */ - ch *= 0x20; - pos = save_index_to_pos(dev, 4, 0x00 + ch, pos); - pos = save_index_to_pos(dev, 4, 0x01 + ch, pos); - pos = save_index_to_pos(dev, 4, 0x02 + ch, pos); - pos = save_index_to_pos(dev, 1, 0x03 + ch, pos); - pos = save_index_to_pos(dev, 4, 0x04 + ch, pos); - pos = save_index_to_pos(dev, 4, 0x05 + ch, pos); - pos = save_index_to_pos(dev, 4, 0x06 + ch, pos); - pos = save_index_to_pos(dev, 1, 0x07 + ch, pos); - pos = save_index_to_pos(dev, 1, 0x10 + ch, pos); - pos = save_index_to_pos(dev, 1, 0x13 + ch, pos); - pos = save_index_to_pos(dev, 1, 0x16 + ch, pos); - pos = save_index_to_pos(dev, 1, 0x19 + ch, pos); - return pos; -} - -static void dqs_save_MC_NVRAM(unsigned int dev) -{ - int pos = 0; - u32 reg; - printk(BIOS_DEBUG, "DQS SAVE NVRAM: %x\n", dev); - pos = dqs_save_MC_NVRAM_ch(dev, 0, pos); - pos = dqs_save_MC_NVRAM_ch(dev, 1, pos); - /* save the maxasync lat here */ - reg = pci_read_config32(dev, DRAM_CONFIG_HIGH); - pos = s3_save_nvram_early(reg, 4, pos); -} -#endif - -void dqs_restore_MC_NVRAM(unsigned int dev) -{ - int pos = 0; - u32 reg; - - printk(BIOS_DEBUG, "DQS RESTORE FROM NVRAM: %x\n", dev); - pos = dqs_load_MC_NVRAM_ch(dev, 0, pos); - pos = dqs_load_MC_NVRAM_ch(dev, 1, pos); - /* load the maxasync lat here */ - pos = s3_load_nvram_early(4, ®, pos); - reg &= (DCH_MaxAsyncLat_MASK << DCH_MaxAsyncLat_SHIFT); - reg |= pci_read_config32(dev, DRAM_CONFIG_HIGH); - pci_write_config32(dev, DRAM_CONFIG_HIGH, reg); -} -#endif - -#if CONFIG_MEM_TRAIN_SEQ == 0 -#if K8_REV_F_SUPPORT_F0_F1_WORKAROUND == 1 -static void dqs_timing(int controllers, const struct mem_controller *ctrl, tsc_t *tsc0, struct sys_info *sysinfo) -#else -static void dqs_timing(int controllers, const struct mem_controller *ctrl, struct sys_info *sysinfo) -#endif -{ - int i; - - tsc_t tsc[5]; - - //need to enable mtrr, so dqs training could access the test address - setup_mtrr_dqs(sysinfo->tom_k, sysinfo->tom2_k); - - for (i = 0; i < controllers; i++) { - if (!sysinfo->ctrl_present[ i ]) - continue; - - /* Skip everything if I don't have any memory on this controller */ - if (sysinfo->meminfo[i].dimm_mask == 0x00) continue; - - fill_mem_cs_sysinfo(i, ctrl+i, sysinfo); - } - - tsc[0] = rdtsc(); - for (i = 0; i < controllers; i++) { - if (!sysinfo->ctrl_present[ i ]) - continue; - - /* Skip everything if I don't have any memory on this controller */ - if (sysinfo->meminfo[i].dimm_mask == 0x00) continue; - - printk(BIOS_DEBUG, "DQS Training:RcvrEn:Pass1: %02x\n", i); - if (train_DqsRcvrEn(ctrl+i, 1, sysinfo)) goto out; - printk(BIOS_DEBUG, " done\n"); - } - - tsc[1] = rdtsc(); -#if K8_REV_F_SUPPORT_F0_F1_WORKAROUND == 1 - f0_svm_workaround(controllers, ctrl, tsc0, sysinfo); -#endif - - tsc[2] = rdtsc(); - for (i = 0; i < controllers; i++) { - if (!sysinfo->ctrl_present[i]) - continue; - - /* Skip everything if I don't have any memory on this controller */ - if (sysinfo->meminfo[i].dimm_mask == 0x00) continue; - - printk(BIOS_DEBUG, "DQS Training:DQSPos: %02x\n", i); - if (train_DqsPos(ctrl+i, sysinfo)) goto out; - printk(BIOS_DEBUG, " done\n"); - } - - tsc[3] = rdtsc(); - for (i = 0; i < controllers; i++) { - if (!sysinfo->ctrl_present[i]) - continue; - - /* Skip everything if I don't have any memory on this controller */ - if (sysinfo->meminfo[i].dimm_mask == 0x00) continue; - - printk(BIOS_DEBUG, "DQS Training:RcvrEn:Pass2: %02x\n", i); - if (train_DqsRcvrEn(ctrl+i, 2, sysinfo)) goto out; - printk(BIOS_DEBUG, " done\n"); - sysinfo->mem_trained[i]=1; -#if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME) - dqs_save_MC_NVRAM((ctrl+i)->f2); -#endif - } - -out: - tsc[4] = rdtsc(); - clear_mtrr_dqs(sysinfo->tom2_k); - - - for (i = 0; i < 5; i++) { - print_debug_dqs_tsc_x("DQS Training:tsc", i, tsc[i].hi, tsc[i].lo); - } - - - -} - -#endif - - -#if CONFIG_MEM_TRAIN_SEQ > 0 - -static void dqs_timing(int i, const struct mem_controller *ctrl, struct sys_info *sysinfo, unsigned v) -{ - - int ii; - - tsc_t tsc[4]; - - if (sysinfo->mem_trained[i] != 0x80) return; - -#if CONFIG_MEM_TRAIN_SEQ == 1 - //need to enable mtrr, so dqs training could access the test address - setup_mtrr_dqs(sysinfo->tom_k, sysinfo->tom2_k); -#endif - - fill_mem_cs_sysinfo(i, ctrl, sysinfo); - - if (v) { - tsc[0] = rdtsc(); - - printk(BIOS_DEBUG, "set DQS timing:RcvrEn:Pass1: %02x\n", i); - } - if (train_DqsRcvrEn(ctrl, 1, sysinfo)) { - sysinfo->mem_trained[i]=0x81; // - goto out; - } - - if (v) { - printk(BIOS_DEBUG, " done\n"); - tsc[1] = rdtsc(); - printk(BIOS_DEBUG, "set DQS timing:DQSPos: %02x\n", i); - } - - if (train_DqsPos(ctrl, sysinfo)) { - sysinfo->mem_trained[i]=0x82; // - goto out; - } - - if (v) { - printk(BIOS_DEBUG, " done\n"); - tsc[2] = rdtsc(); - - printk(BIOS_DEBUG, "set DQS timing:RcvrEn:Pass2: %02x\n", i); - } - if (train_DqsRcvrEn(ctrl, 2, sysinfo)) { - sysinfo->mem_trained[i]=0x83; // - goto out; - } - - if (v) { - printk(BIOS_DEBUG, " done\n"); - - tsc[3] = rdtsc(); - } - -out: -#if CONFIG_MEM_TRAIN_SEQ == 1 - clear_mtrr_dqs(sysinfo->tom2_k); -#endif - - if (v) { - for (ii = 0; ii < 4; ii++) { - print_debug_dqs_tsc_x("Total DQS Training : tsc ", ii, tsc[ii].hi, tsc[ii].lo); - } - } - - if (sysinfo->mem_trained[i] == 0x80) { - sysinfo->mem_trained[i]=1; - } - -} -#endif - -#if CONFIG_MEM_TRAIN_SEQ == 1 -static void train_ram(unsigned nodeid, struct sys_info *sysinfo, struct sys_info *sysinfox) -{ - dqs_timing(nodeid, &sysinfo->ctrl[nodeid], sysinfo, 0); // keep the output tidy - sysinfox->mem_trained[nodeid] = sysinfo->mem_trained[nodeid]; - -} - -void train_ram_on_node(unsigned nodeid, unsigned coreid, struct sys_info *sysinfo, unsigned retcall) -{ - if (coreid) return; // only do it on core0 - struct sys_info *sysinfox; - uintptr_t migrated_base = CONFIG_RAMTOP - car_data_size(); - - sysinfox = (void *)(migrated_base + car_object_offset(&sysinfo_car)); - - wait_till_sysinfo_in_ram(); // use pci to get it - - if (sysinfox->mem_trained[nodeid] == 0x80) { - memcpy(sysinfo, sysinfox, sizeof(*sysinfo)); - set_top_mem_ap(sysinfo->tom_k, sysinfo->tom2_k); // keep the ap's tom consistent with bsp's - printk(BIOS_DEBUG, "CODE IN ROM AND RUN ON NODE: %02x\n", nodeid); - train_ram(nodeid, sysinfo, sysinfox); - } -} -#endif diff --git a/src/northbridge/amd/amdk8/raminit_test.c b/src/northbridge/amd/amdk8/raminit_test.c deleted file mode 100644 index a22db10129..0000000000 --- a/src/northbridge/amd/amdk8/raminit_test.c +++ /dev/null @@ -1,409 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * 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. - */ - -#include <unistd.h> -#include <limits.h> -#include <lib.h> -#include <stdint.h> -#include <string.h> -#include <setjmp.h> -#include <device/pci_def.h> -#include <stdlib.h> -#include "amdk8.h" - -jmp_buf end_buf; - -static int is_cpu_pre_c0(void) -{ - return 0; -} - -#define PCI_ADDR(BUS, DEV, FN, WHERE) ( \ - (((BUS) & 0xFF) << 16) | \ - (((DEV) & 0x1f) << 11) | \ - (((FN) & 0x07) << 8) | \ - ((WHERE) & 0xFF)) - -#define PCI_DEV(BUS, DEV, FN) ( \ - (((BUS) & 0xFF) << 16) | \ - (((DEV) & 0x1f) << 11) | \ - (((FN) & 0x7) << 8)) - -#define PCI_ID(VENDOR_ID, DEVICE_ID) \ - ((((DEVICE_ID) & 0xFFFF) << 16) | ((VENDOR_ID) & 0xFFFF)) - -typedef unsigned device_t; - -unsigned char pci_register[256*5*3*256]; - -static uint8_t pci_read_config8(device_t dev, unsigned where) -{ - unsigned addr; - addr = dev | where; - return pci_register[addr]; -} - -static uint16_t pci_read_config16(device_t dev, unsigned where) -{ - unsigned addr; - addr = dev | where; - return pci_register[addr] | (pci_register[addr + 1] << 8); -} - -static uint32_t pci_read_config32(device_t dev, unsigned where) -{ - unsigned addr; - uint32_t value; - addr = dev | where; - value = pci_register[addr] | - (pci_register[addr + 1] << 8) | - (pci_register[addr + 2] << 16) | - (pci_register[addr + 3] << 24); - return value; - -} - -static void pci_write_config8(device_t dev, unsigned where, uint8_t value) -{ - unsigned addr; - addr = dev | where; - pci_register[addr] = value; -} - -static void pci_write_config16(device_t dev, unsigned where, uint16_t value) -{ - unsigned addr; - addr = dev | where; - pci_register[addr] = value & 0xff; - pci_register[addr + 1] = (value >> 8) & 0xff; -} - -static void pci_write_config32(device_t dev, unsigned where, uint32_t value) -{ - unsigned addr; - addr = dev | where; - pci_register[addr] = value & 0xff; - pci_register[addr + 1] = (value >> 8) & 0xff; - pci_register[addr + 2] = (value >> 16) & 0xff; - pci_register[addr + 3] = (value >> 24) & 0xff; -} - -#define PCI_DEV_INVALID (0xffffffffU) -static device_t pci_locate_device(unsigned pci_id, device_t dev) -{ - for (; dev <= PCI_DEV(255, 31, 7); dev += PCI_DEV(0,0,1)) { - unsigned int id; - id = pci_read_config32(dev, 0); - if (id == pci_id) { - return dev; - } - } - return PCI_DEV_INVALID; -} - - - - -static void uart_tx_byte(unsigned char data) -{ - write(STDOUT_FILENO, &data, 1); -} -static void hlt(void) -{ - longjmp(end_buf, 2); -} -#include "console/console.c" - -unsigned long log2(unsigned long x) -{ - // assume 8 bits per byte. - unsigned long i = 1 << (sizeof(x)*8 - 1); - unsigned long pow = sizeof(x) * 8 - 1; - - if (! x) { - static const char errmsg[] = " called with invalid parameter of 0\n"; - write(STDERR_FILENO, __func__, sizeof(__func__) - 1); - write(STDERR_FILENO, errmsg, sizeof(errmsg) - 1); - hlt(); - } - for (; i > x; i >>= 1, pow--) - ; - - return pow; -} - -typedef struct msr_struct -{ - unsigned lo; - unsigned hi; -} msr_t; - -static inline msr_t rdmsr(unsigned index) -{ - msr_t result; - result.lo = 0; - result.hi = 0; - return result; -} - -static inline void wrmsr(unsigned index, msr_t msr) -{ -} - -#include "raminit.h" - -#define SIO_BASE 0x2e - -static void hard_reset(void) -{ - /* FIXME implement the hard reset case... */ - longjmp(end_buf, 3); -} - -static void memreset_setup(void) -{ - /* Nothing to do */ -} - -static void memreset(int controllers, const struct mem_controller *ctrl) -{ - /* Nothing to do */ -} - -void activate_spd_rom(const struct mem_controller *ctrl) -{ - /* nothing to do */ -} - - -static uint8_t spd_mt4lsdt464a[256] = -{ - 0x80, 0x08, 0x04, 0x0C, 0x08, 0x01, 0x40, 0x00, 0x01, 0x70, - 0x54, 0x00, 0x80, 0x10, 0x00, 0x01, 0x8F, 0x04, 0x06, 0x01, - 0x01, 0x00, 0x0E, 0x75, 0x54, 0x00, 0x00, 0x0F, 0x0E, 0x0F, - - 0x25, 0x08, 0x15, 0x08, 0x15, 0x08, 0x00, 0x12, 0x01, 0x4E, - 0x9C, 0xE4, 0xB7, 0x46, 0x2C, 0xFF, 0x01, 0x02, 0x03, 0x04, - 0x05, 0x06, 0x07, 0x08, 0x09, 0x01, 0x02, 0x03, 0x04, 0x05, - 0x06, 0x07, 0x08, 0x09, 0x00, -}; - -static uint8_t spd_micron_512MB_DDR333[256] = -{ - 0x80, 0x08, 0x07, 0x0d, 0x0b, 0x02, 0x48, 0x00, 0x04, 0x60, - 0x70, 0x02, 0x82, 0x04, 0x04, 0x01, 0x0e, 0x04, 0x0c, 0x01, - 0x02, 0x26, 0xc0, 0x75, 0x70, 0x00, 0x00, 0x48, 0x30, 0x48, - 0x2a, 0x80, 0x80, 0x80, 0x45, 0x45, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x3c, 0x48, 0x30, 0x28, 0x50, 0x00, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x10, 0x6f, 0x2c, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x01, 0x33, 0x36, 0x56, 0x44, 0x44, 0x46, 0x31, - 0x32, 0x38, 0x37, 0x32, 0x47, 0x2d, 0x33, 0x33, 0x35, 0x43, - 0x33, 0x03, 0x00, 0x03, 0x23, 0x17, 0x07, 0x5a, 0xb2, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; - -static uint8_t spd_micron_256MB_DDR333[256] = -{ - 0x80, 0x08, 0x07, 0x0d, 0x0b, 0x01, 0x48, 0x00, 0x04, 0x60, - 0x70, 0x02, 0x82, 0x04, 0x04, 0x01, 0x0e, 0x04, 0x0c, 0x01, - 0x02, 0x26, 0xc0, 0x75, 0x70, 0x00, 0x00, 0x48, 0x30, 0x48, - 0x2a, 0x80, 0x80, 0x80, 0x45, 0x45, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x3c, 0x48, 0x30, 0x23, 0x50, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x58, 0x2c, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x01, 0x31, 0x38, 0x56, 0x44, 0x44, 0x46, 0x36, - 0x34, 0x37, 0x32, 0x47, 0x2d, 0x33, 0x33, 0x35, 0x43, 0x31, - 0x20, 0x01, 0x00, 0x03, 0x19, 0x17, 0x05, 0xb2, 0xf4, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, -}; - -#define MAX_DIMMS 16 -static uint8_t spd_data[MAX_DIMMS*256]; - -static unsigned spd_count, spd_fail_count; -static int spd_read_byte(unsigned device, unsigned address) -{ - int result; - spd_count++; - if ((device < DIMM0) || (device >= (DIMM0 + MAX_DIMMS))) { - result = -1; - } - else { - device -= DIMM0; /* 0x50 */ - - if (address > 256) { - result = -1; - } - else if (spd_data[(device << 8) | 2] != 7) { - result = -1; - } - else { - result = spd_data[(device << 8) | address]; - } - } - if (spd_count >= spd_fail_count) { - result = -1; - } - return result; -} - -/* no specific code here. this should go away completely */ -static void coherent_ht_mainboard(unsigned cpus) -{ -} - -#include "raminit.c" -#include "../../../lib/generic_sdram.c" - -#define FIRST_CPU 1 -#define SECOND_CPU 1 -#define TOTAL_CPUS (FIRST_CPU + SECOND_CPU) -static void raminit_main(void) -{ - /* - * GPIO28 of 8111 will control H0_MEMRESET_L - * GPIO29 of 8111 will control H1_MEMRESET_L - */ - static const struct mem_controller cpu[] = { -#if FIRST_CPU - { - .node_id = 0, - .f0 = PCI_DEV(0, 0x18, 0), - .f1 = PCI_DEV(0, 0x18, 1), - .f2 = PCI_DEV(0, 0x18, 2), - .f3 = PCI_DEV(0, 0x18, 3), - .channel0 = { DIMM0+0, DIMM0+2, DIMM0+4, DIMM0+6 }, - .channel1 = { DIMM0+1, DIMM0+3, DIMM0+5, DIMM0+7 }, - }, -#endif -#if SECOND_CPU - { - .node_id = 1, - .f0 = PCI_DEV(0, 0x19, 0), - .f1 = PCI_DEV(0, 0x19, 1), - .f2 = PCI_DEV(0, 0x19, 2), - .f3 = PCI_DEV(0, 0x19, 3), - .channel0 = { DIMM0+8, DIMM0+10, DIMM0+12, DIMM0+14 }, - .channel1 = { DIMM0+9, DIMM0+11, DIMM0+13, DIMM0+15 }, - }, -#endif - }; - console_init(); - memreset_setup(); - sdram_initialize(ARRAY_SIZE(cpu), cpu); - -} - -static void reset_tests(void) -{ - /* Clear the results of any previous tests */ - memset(pci_register, 0, sizeof(pci_register)); - memset(spd_data, 0, sizeof(spd_data)); - spd_count = 0; - spd_fail_count = UINT_MAX; - - pci_write_config32(PCI_DEV(0, 0x18, 3), NORTHBRIDGE_CAP, - NBCAP_128Bit | - NBCAP_MP| NBCAP_BIG_MP | - /* NBCAP_ECC | NBCAP_CHIPKILL_ECC | */ - (NBCAP_MEMCLK_200MHZ << NBCAP_MEMCLK_SHIFT) | - NBCAP_MEMCTRL); - - pci_write_config32(PCI_DEV(0, 0x19, 3), NORTHBRIDGE_CAP, - NBCAP_128Bit | - NBCAP_MP| NBCAP_BIG_MP | - /* NBCAP_ECC | NBCAP_CHIPKILL_ECC | */ - (NBCAP_MEMCLK_200MHZ << NBCAP_MEMCLK_SHIFT) | - NBCAP_MEMCTRL); -} - -static void test1(void) -{ - reset_tests(); - - memcpy(&spd_data[0*256], spd_micron_512MB_DDR333, 256); - memcpy(&spd_data[1*256], spd_micron_512MB_DDR333, 256); - raminit_main(); -} - - -static void do_test2(int i) -{ - jmp_buf tmp_buf; - memcpy(&tmp_buf, &end_buf, sizeof(end_buf)); - if (setjmp(end_buf) != 0) { - goto done; - } - reset_tests(); - spd_fail_count = i; - - printk(BIOS_DEBUG, "\nSPD will fail after: %d accesses.\n", %d); - - memcpy(&spd_data[0*256], spd_micron_512MB_DDR333, 256); - memcpy(&spd_data[1*256], spd_micron_512MB_DDR333, 256); - - raminit_main(); - -done: - memcpy(&end_buf, &tmp_buf, sizeof(end_buf)); -} - -static void test2(void) -{ - int i; - for (i = 0; i < 0x48; i++) { - do_test2(i); - } - -} - -int main(int argc, char **argv) -{ - if (setjmp(end_buf) != 0) { - return -1; - } - test1(); - test2(); - return 0; -} diff --git a/src/northbridge/amd/amdk8/resourcemap.c b/src/northbridge/amd/amdk8/resourcemap.c deleted file mode 100644 index 2bf868050c..0000000000 --- a/src/northbridge/amd/amdk8/resourcemap.c +++ /dev/null @@ -1,271 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * 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. - */ - -static void setup_default_resource_map(void) -{ - static const unsigned int register_values[] = { - /* Careful set limit registers before base registers which contain the enables */ - /* DRAM Limit i Registers - * F1:0x44 i = 0 - * F1:0x4C i = 1 - * F1:0x54 i = 2 - * F1:0x5C i = 3 - * F1:0x64 i = 4 - * F1:0x6C i = 5 - * F1:0x74 i = 6 - * F1:0x7C i = 7 - * [ 2: 0] Destination Node ID - * 000 = Node 0 - * 001 = Node 1 - * 010 = Node 2 - * 011 = Node 3 - * 100 = Node 4 - * 101 = Node 5 - * 110 = Node 6 - * 111 = Node 7 - * [ 7: 3] Reserved - * [10: 8] Interleave select - * specifies the values of A[14:12] to use with interleave enable. - * [15:11] Reserved - * [31:16] DRAM Limit Address i Bits 39-24 - * This field defines the upper address bits of a 40 bit address - * that define the end of the DRAM region. - */ - PCI_ADDR(0, 0x18, 1, 0x44), 0x0000f8f8, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0x4C), 0x0000f8f8, 0x00000001, - PCI_ADDR(0, 0x18, 1, 0x54), 0x0000f8f8, 0x00000002, - PCI_ADDR(0, 0x18, 1, 0x5C), 0x0000f8f8, 0x00000003, - PCI_ADDR(0, 0x18, 1, 0x64), 0x0000f8f8, 0x00000004, - PCI_ADDR(0, 0x18, 1, 0x6C), 0x0000f8f8, 0x00000005, - PCI_ADDR(0, 0x18, 1, 0x74), 0x0000f8f8, 0x00000006, - PCI_ADDR(0, 0x18, 1, 0x7C), 0x0000f8f8, 0x00000007, - /* DRAM Base i Registers - * F1:0x40 i = 0 - * F1:0x48 i = 1 - * F1:0x50 i = 2 - * F1:0x58 i = 3 - * F1:0x60 i = 4 - * F1:0x68 i = 5 - * F1:0x70 i = 6 - * F1:0x78 i = 7 - * [ 0: 0] Read Enable - * 0 = Reads Disabled - * 1 = Reads Enabled - * [ 1: 1] Write Enable - * 0 = Writes Disabled - * 1 = Writes Enabled - * [ 7: 2] Reserved - * [10: 8] Interleave Enable - * 000 = No interleave - * 001 = Interleave on A[12] (2 nodes) - * 010 = reserved - * 011 = Interleave on A[12] and A[14] (4 nodes) - * 100 = reserved - * 101 = reserved - * 110 = reserved - * 111 = Interleve on A[12] and A[13] and A[14] (8 nodes) - * [15:11] Reserved - * [13:16] DRAM Base Address i Bits 39-24 - * This field defines the upper address bits of a 40-bit address - * that define the start of the DRAM region. - */ - PCI_ADDR(0, 0x18, 1, 0x40), 0x0000f8fc, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0x48), 0x0000f8fc, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0x50), 0x0000f8fc, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0x58), 0x0000f8fc, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0x60), 0x0000f8fc, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0x68), 0x0000f8fc, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0x70), 0x0000f8fc, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0x78), 0x0000f8fc, 0x00000000, - - /* Memory-Mapped I/O Limit i Registers - * F1:0x84 i = 0 - * F1:0x8C i = 1 - * F1:0x94 i = 2 - * F1:0x9C i = 3 - * F1:0xA4 i = 4 - * F1:0xAC i = 5 - * F1:0xB4 i = 6 - * F1:0xBC i = 7 - * [ 2: 0] Destination Node ID - * 000 = Node 0 - * 001 = Node 1 - * 010 = Node 2 - * 011 = Node 3 - * 100 = Node 4 - * 101 = Node 5 - * 110 = Node 6 - * 111 = Node 7 - * [ 3: 3] Reserved - * [ 5: 4] Destination Link ID - * 00 = Link 0 - * 01 = Link 1 - * 10 = Link 2 - * 11 = Reserved - * [ 6: 6] Reserved - * [ 7: 7] Non-Posted - * 0 = CPU writes may be posted - * 1 = CPU writes must be non-posted - * [31: 8] Memory-Mapped I/O Limit Address i (39-16) - * This field defines the upp adddress bits of a 40-bit address that - * defines the end of a memory-mapped I/O region n - */ - PCI_ADDR(0, 0x18, 1, 0x84), 0x00000048, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0x8C), 0x00000048, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0x94), 0x00000048, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0x9C), 0x00000048, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0xA4), 0x00000048, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0xAC), 0x00000048, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0xB4), 0x00000048, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0xBC), 0x00000048, 0x00ffff00, - - /* Memory-Mapped I/O Base i Registers - * F1:0x80 i = 0 - * F1:0x88 i = 1 - * F1:0x90 i = 2 - * F1:0x98 i = 3 - * F1:0xA0 i = 4 - * F1:0xA8 i = 5 - * F1:0xB0 i = 6 - * F1:0xB8 i = 7 - * [ 0: 0] Read Enable - * 0 = Reads disabled - * 1 = Reads Enabled - * [ 1: 1] Write Enable - * 0 = Writes disabled - * 1 = Writes Enabled - * [ 2: 2] Cpu Disable - * 0 = Cpu can use this I/O range - * 1 = Cpu requests do not use this I/O range - * [ 3: 3] Lock - * 0 = base/limit registers i are read/write - * 1 = base/limit registers i are read-only - * [ 7: 4] Reserved - * [31: 8] Memory-Mapped I/O Base Address i (39-16) - * This field defines the upper address bits of a 40bit address - * that defines the start of memory-mapped I/O region i - */ - PCI_ADDR(0, 0x18, 1, 0x80), 0x000000f0, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0x88), 0x000000f0, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0x90), 0x000000f0, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0x98), 0x000000f0, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0xA0), 0x000000f0, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0xA8), 0x000000f0, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0xB0), 0x000000f0, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0xB8), 0x000000f0, 0x00fc0003, - - /* PCI I/O Limit i Registers - * F1:0xC4 i = 0 - * F1:0xCC i = 1 - * F1:0xD4 i = 2 - * F1:0xDC i = 3 - * [ 2: 0] Destination Node ID - * 000 = Node 0 - * 001 = Node 1 - * 010 = Node 2 - * 011 = Node 3 - * 100 = Node 4 - * 101 = Node 5 - * 110 = Node 6 - * 111 = Node 7 - * [ 3: 3] Reserved - * [ 5: 4] Destination Link ID - * 00 = Link 0 - * 01 = Link 1 - * 10 = Link 2 - * 11 = reserved - * [11: 6] Reserved - * [24:12] PCI I/O Limit Address i - * This field defines the end of PCI I/O region n - * [31:25] Reserved - */ - PCI_ADDR(0, 0x18, 1, 0xC4), 0xFE000FC8, 0x01fff000, - PCI_ADDR(0, 0x18, 1, 0xCC), 0xFE000FC8, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0xD4), 0xFE000FC8, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0xDC), 0xFE000FC8, 0x00000000, - - /* PCI I/O Base i Registers - * F1:0xC0 i = 0 - * F1:0xC8 i = 1 - * F1:0xD0 i = 2 - * F1:0xD8 i = 3 - * [ 0: 0] Read Enable - * 0 = Reads Disabled - * 1 = Reads Enabled - * [ 1: 1] Write Enable - * 0 = Writes Disabled - * 1 = Writes Enabled - * [ 3: 2] Reserved - * [ 4: 4] VGA Enable - * 0 = VGA matches Disabled - * 1 = matches all address < 64K and where A[9:0] is in the - * range 3B0-3BB or 3C0-3DF independen of the base & limit registers - * [ 5: 5] ISA Enable - * 0 = ISA matches Disabled - * 1 = Blocks address < 64K and in the last 768 bytes of eack 1K block - * from matching agains this base/limit pair - * [11: 6] Reserved - * [24:12] PCI I/O Base i - * This field defines the start of PCI I/O region n - * [31:25] Reserved - */ - PCI_ADDR(0, 0x18, 1, 0xC0), 0xFE000FCC, 0x00000003, - PCI_ADDR(0, 0x18, 1, 0xC8), 0xFE000FCC, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0xD0), 0xFE000FCC, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0xD8), 0xFE000FCC, 0x00000000, - - /* Config Base and Limit i Registers - * F1:0xE0 i = 0 - * F1:0xE4 i = 1 - * F1:0xE8 i = 2 - * F1:0xEC i = 3 - * [ 0: 0] Read Enable - * 0 = Reads Disabled - * 1 = Reads Enabled - * [ 1: 1] Write Enable - * 0 = Writes Disabled - * 1 = Writes Enabled - * [ 2: 2] Device Number Compare Enable - * 0 = The ranges are based on bus number - * 1 = The ranges are ranges of devices on bus 0 - * [ 3: 3] Reserved - * [ 6: 4] Destination Node - * 000 = Node 0 - * 001 = Node 1 - * 010 = Node 2 - * 011 = Node 3 - * 100 = Node 4 - * 101 = Node 5 - * 110 = Node 6 - * 111 = Node 7 - * [ 7: 7] Reserved - * [ 9: 8] Destination Link - * 00 = Link 0 - * 01 = Link 1 - * 10 = Link 2 - * 11 - Reserved - * [15:10] Reserved - * [23:16] Bus Number Base i - * This field defines the lowest bus number in configuration region i - * [31:24] Bus Number Limit i - * This field defines the highest bus number in configuration region i - */ - PCI_ADDR(0, 0x18, 1, 0xE0), 0x0000FC88, 0xff000003, - PCI_ADDR(0, 0x18, 1, 0xE4), 0x0000FC88, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0xE8), 0x0000FC88, 0x00000000, - PCI_ADDR(0, 0x18, 1, 0xEC), 0x0000FC88, 0x00000000, - }; - int max; - max = ARRAY_SIZE(register_values); - setup_resource_map(register_values, max); -} diff --git a/src/northbridge/amd/amdk8/setup_resource_map.c b/src/northbridge/amd/amdk8/setup_resource_map.c deleted file mode 100644 index 23d2949b1d..0000000000 --- a/src/northbridge/amd/amdk8/setup_resource_map.c +++ /dev/null @@ -1,117 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * 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. - */ - -#include "amdk8.h" - -#define RES_DEBUG 0 - -void setup_resource_map_offset(const unsigned int *register_values, int max, unsigned offset_pci_dev, unsigned offset_io_base) -{ - int i; -#if RES_DEBUG - printk(BIOS_DEBUG, "setting up resource map offset....\n"); -#endif - for (i = 0; i < max; i += 3) { - pci_devfn_t dev; - unsigned where; - unsigned long reg = 0; -#if RES_DEBUG - prink_debug("%08x <- %08x\n", register_values[i] + offset_pci_dev, register_values[i+2]); -#endif - dev = (register_values[i] & ~0xfff) + offset_pci_dev; - where = register_values[i] & 0xfff; - if (register_values[i+1]) - reg = pci_read_config32(dev, where); - reg &= register_values[i+1]; - reg |= register_values[i+2] + offset_io_base; - pci_write_config32(dev, where, reg); - } -#if RES_DEBUG - printk(BIOS_DEBUG, "done.\n"); -#endif -} - -#define RES_PCI_IO 0x10 -#define RES_PORT_IO_8 0x22 -#define RES_PORT_IO_32 0x20 -#define RES_MEM_IO 0x40 - -static void setup_resource_map_x_offset(const unsigned int *register_values, int max, unsigned offset_pci_dev, unsigned offset_io_base) -{ - int i; - -#if RES_DEBUG - printk(BIOS_DEBUG, "setting up resource map ex offset....\n"); -#endif - for (i = 0; i < max; i += 4) { -#if RES_DEBUG - printk(BIOS_DEBUG, "%04x: %02x %08x <- & %08x | %08x\n", - i>>2, register_values[i], - register_values[i+1] + ((register_values[i]==RES_PCI_IO) ? offset_pci_dev : 0), - register_values[i+2], - register_values[i+3] + (((register_values[i] & RES_PORT_IO_32) == RES_PORT_IO_32) ? offset_io_base : 0) - ); -#endif - switch (register_values[i]) { - case RES_PCI_IO: //PCI - { - pci_devfn_t dev; - unsigned where; - unsigned long reg = 0; - dev = (register_values[i+1] & ~0xfff) + offset_pci_dev; - where = register_values[i+1] & 0xfff; - if (register_values[i+2]) - reg = pci_read_config32(dev, where); - reg &= register_values[i+2]; - reg |= register_values[i+3]; - pci_write_config32(dev, where, reg); - } - break; - case RES_PORT_IO_8: // io 8 - { - unsigned where; - unsigned reg = 0; - where = register_values[i+1] + offset_io_base; - if (register_values[i+2]) - reg = inb(where); - reg &= register_values[i+2]; - reg |= register_values[i+3]; - outb(reg, where); - } - break; - case RES_PORT_IO_32: //io32 - { - unsigned where; - unsigned long reg = 0; - where = register_values[i+1] + offset_io_base; - if (register_values[i+2]) - reg = inl(where); - reg &= register_values[i+2]; - reg |= register_values[i+3]; - outl(reg, where); - } - break; - } // switch - - - } - -#if RES_DEBUG - printk(BIOS_DEBUG, "done.\n"); -#endif -} - -static inline void setup_resource_map_x(const unsigned int *register_values, int max) -{ - setup_resource_map_x_offset(register_values, max, 0, 0); -} diff --git a/src/northbridge/amd/amdk8/thermal_mixin.asl b/src/northbridge/amd/amdk8/thermal_mixin.asl deleted file mode 100644 index b738d965c8..0000000000 --- a/src/northbridge/amd/amdk8/thermal_mixin.asl +++ /dev/null @@ -1,285 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2011 Christoph Grenz <christophg+cb@grenz-bonn.de> - * - * 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. - */ - -/* - * include this file into a mainboards DSDT inside the PCI device - * "K8 Miscellaneous Control" and it will expose the temperature - * sensors of the processor as thermal zones. - * - * If, for example, the K8 Misc. Control device is on 0:18.3, include the - * following inside the PCI0 device: - * - * Device(K8MC) { - * Name (_ADR, 0x00180003) - * #include northbridge/amd/amdk8/thermal_mixin.asl - * } - * - * Note: as only the current temperature and the trip temperature for - * "Software Thermal Control" are available in the PCI registers, but the - * linux driver for thermal zones needs a critical temperature value, a - * reasonable critical temperature is calculated by simply adding 6°C to - * the trip temperature. - * - * The used registers are documented in the "BIOS and Kernel Developer's - * Guide for AMD NPT Family 0Fh Processors" - * http://support.amd.com/us/Processor_TechDocs/32559.pdf - * - */ - -#ifndef K8TEMP_CRITICAL_ADD -# define K8TEMP_CRITICAL_ADD 6 -#endif - -OperationRegion(K8TR, PCI_Config, 0xE4, 0x4) -Field(K8TR, DWordAcc, NoLock, Preserve) { - , 1, - THTP, 1, /* Temperature sensor trip occurred */ - CORE, 1, /* Select Core */ - TTS0, 1, /* Temperature sensor trip on CPU1 (or single core CPU0) */ - TTS1, 1, /* Temperature sensor trip on CPU0 */ - TTEN, 1, /* Temperature sensor trip enabled */ - PLAC, 1, /* Select Sensor */ - , 1, - DOFF, 6, /* Diode offset (signed 6bit-Integer) in °C */ - TFRC, 2, /* Temperature fractions */ - TVAL, 8, /* Temperature value in °C biased by -49 */ - TJOF, 5, - , 2, - SWTT, 1, /* Induce a thermtrip event (for diagnostic purposes) */ -} - -OperationRegion(K8ST, PCI_Config, 0x70, 0x1) -Field(K8ST, ByteAcc, NoLock, Preserve) { - TMAX, 5, /* Maximum temperature for software thermal control, in °C, biased by 52 */ -} - -/* Calculates temperature in tenths Kelvin from given TVAL and TFRC values */ -Method(K8PT, 2) { - Divide(Multiply(Arg1, 5), 2, , Local0) - Return (Add(Multiply(Add(Arg0, 224),10), Local0)) -} - -/* Calculates the diode offset from a DOFF value */ -Method(K8PO, 1) { - If (And(Arg0, 0x20)) - { - Return (Multiply(Subtract(Xor(Arg0, 0x3F), 1), 10)) - } - Else { - Return (Multiply(Arg0, 10)) - } -} - -ThermalZone (K8T0) { - Name(_HID, EisaId("PNP0C11")) - Name(_UID, "k8-0") - Name(_STR, Unicode("K8 compatible CPU Core 1 Thermal Sensor 1")) - - Method(_STA) { - Store(CORE, Local0) - Store(PLAC, Local1) - - Store(Zero, CORE) - Store(Zero, PLAC) - If (LOr(PLAC, CORE)) { - Store(Local0, CORE) - Store(Local1, PLAC) - Return (0x00) - } - - If (LOr(LNot(TVAL), LEqual(TVAL, 0xFF))) { - Return (0x00) - } - - Store(Local0, CORE) - Store(Local1, PLAC) - Return (0x0F) - } - - Method(_TMP) { - Store(CORE, Local0) - Store(PLAC, Local1) - - Store(Zero, CORE) - Store(Zero, PLAC) - - Store (K8PT(TVAL, TFRC), Local2) - Add (K8PO(DOFF), Local2, Local2) - Store(Local0, CORE) - Store(Local1, PLAC) - - Return (Local2) - } - - Method(_CRT) { - Add(TMAX, 325, Local0) - Add(Local0, K8TEMP_CRITICAL_ADD, Local0) - Return (Multiply(Local0, 10)) - } -} - -ThermalZone (K8T1) { - Name(_HID, EisaId("PNP0C11")) - Name(_UID, "k8-1") - Name(_STR, Unicode("K8 compatible CPU Core 1 Thermal Sensor 2")) - - Name(_TZD, Package () {\_PR.CP00}) - - Method(_STA) { - Store(CORE, Local0) - Store(PLAC, Local1) - - Store(Zero, CORE) - Store(Zero, PLAC) - If (LOr(PLAC, CORE)) { - Store(Local0, CORE) - Store(Local1, PLAC) - Return (0x00) - } - - Store(One, PLAC) - If (LOr(LNot(TVAL), LEqual(TVAL, 0xFF))) { - Return (0x00) - } - - Store(Local0, CORE) - Store(Local1, PLAC) - Return (0x0F) - } - - Method(_TMP) { - Store(CORE, Local0) - Store(PLAC, Local1) - - Store(Zero, CORE) - Store(One, PLAC) - - Store (K8PT(TVAL, TFRC), Local2) - Add (K8PO(DOFF), Local2, Local2) - Store(Local0, CORE) - Store(Local1, PLAC) - - Return (Local2) - } - - Method(_CRT) { - Add(TMAX, 325, Local0) - Add(Local0, K8TEMP_CRITICAL_ADD, Local0) - Return (Multiply(Local0, 10)) - } -} - -ThermalZone (K8T2) { - Name(_HID, EisaId("PNP0C11")) - Name(_UID, "k8-2") - Name(_STR, Unicode("K8 compatible CPU Core 2 Thermal Sensor 1")) - - Name(_TZD, Package () {\_PR.CP00}) - - Method(_STA) { - Store(CORE, Local0) - Store(PLAC, Local1) - - Store(Zero, CORE) - Store(Zero, PLAC) - If (LOr(PLAC, CORE)) { - Store(Local0, CORE) - Store(Local1, PLAC) - Return (0x00) - } - - Store(One, CORE) - If (LOr(LNot(TVAL), LEqual(TVAL, 0xFF))) { - Return (0x00) - } - - Store(Local0, CORE) - Store(Local1, PLAC) - Return (0x0F) - } - - Method(_TMP) { - Store(CORE, Local0) - Store(PLAC, Local1) - - Store(One, CORE) - Store(Zero, PLAC) - - Store (K8PT(TVAL, TFRC), Local2) - Add (K8PO(DOFF), Local2, Local2) - Store(Local0, CORE) - Store(Local1, PLAC) - - Return (Local2) - } - - Method(_CRT) { - Add(TMAX, 325, Local0) - Add(Local0, K8TEMP_CRITICAL_ADD, Local0) - Return (Multiply(Local0, 10)) - } -} - -ThermalZone (K8T3) { - Name(_HID, EisaId("PNP0C11")) - Name(_UID, "k8-3") - Name(_STR, Unicode("K8 compatible CPU Core 2 Thermal Sensor 2")) - - Name(_TZD, Package () {\_PR.CP00}) - - Method(_STA) { - Store(CORE, Local0) - Store(PLAC, Local1) - - Store(Zero, CORE) - Store(Zero, PLAC) - If (LOr(PLAC, CORE)) { - Store(Local0, CORE) - Store(Local1, PLAC) - Return (0x00) - } - - Store(One, CORE) - Store(One, PLAC) - If (LOr(LNot(TVAL), LEqual(TVAL, 0xFF))) { - Return (0x00) - } - - Store(Local0, CORE) - Store(Local1, PLAC) - Return (0x0F) - } - - Method(_TMP) { - Store(CORE, Local0) - Store(PLAC, Local1) - - Store(One, CORE) - Store(One, PLAC) - - Store (K8PT(TVAL, TFRC), Local2) - Add (K8PO(DOFF), Local2, Local2) - Store(Local0, CORE) - Store(Local1, PLAC) - - Return (Local2) - } - - Method(_CRT) { - Add(TMAX, 325, Local0) - Add(Local0, K8TEMP_CRITICAL_ADD, Local0) - Return (Multiply(Local0, 10)) - } -} diff --git a/src/northbridge/amd/amdk8/util.asl b/src/northbridge/amd/amdk8/util.asl deleted file mode 100644 index d272233d2d..0000000000 --- a/src/northbridge/amd/amdk8/util.asl +++ /dev/null @@ -1,329 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright 2005 AMD - * - * 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. - */ - -//AMD k8 util for BUSB and res range - -Scope (\_SB) -{ - - Name (OSTB, Ones) - Method (OSVR, 0, NotSerialized) - { - If (LEqual (^OSTB, Ones)) - { - Store (0x00, ^OSTB) - } - - Return (^OSTB) - } - - Method (SEQL, 2, Serialized) - { - Store (SizeOf (Arg0), Local0) - Store (SizeOf (Arg1), Local1) - If (LNot (LEqual (Local0, Local1))) { Return (Zero) } - - Name (BUF0, Buffer (Local0) {}) - Store (Arg0, BUF0) - Name (BUF1, Buffer (Local0) {}) - Store (Arg1, BUF1) - Store (Zero, Local2) - While (LLess (Local2, Local0)) - { - Store (DerefOf (Index (BUF0, Local2)), Local3) - Store (DerefOf (Index (BUF1, Local2)), Local4) - If (LNot (LEqual (Local3, Local4))) { Return (Zero) } - - Increment (Local2) - } - - Return (One) - } - - - Method (DADD, 2, NotSerialized) - { - Store(Arg1, Local0) - Store(Arg0, Local1) - Add(ShiftLeft(Local1,16), Local0, Local0) - Return (Local0) - } - - - Method (GHCE, 1, NotSerialized) // check if the HC enabled - { - Store (DerefOf (Index (\_SB.PCI0.HCLK, Arg0)), Local1) - if (LEqual (And(Local1, 0x01), 0x01)) { Return (0x0F) } - Else { Return (0x00) } - } - - Method (GHCN, 1, NotSerialized) // get the node num for the HC - { - Store (0x00, Local0) - Store (DerefOf (Index (\_SB.PCI0.HCLK, Arg0)), Local1) - Store (ShiftRight(And (Local1, 0xf0), 0x04), Local0) - Return (Local0) - } - - Method (GHCL, 1, NotSerialized) // get the link num on node for the HC - { - Store (0x00, Local0) - Store (DerefOf (Index (\_SB.PCI0.HCLK, Arg0)), Local1) - Store (ShiftRight(And (Local1, 0xf00), 0x08), Local0) - Return (Local0) - } - - Method (GHCD, 2, NotSerialized) // get the unit id base for the HT device in HC - { - Store (0x00, Local0) - Store (DerefOf (Index (\_SB.PCI0.HCDN, Arg0)), Local1) - Store (Arg1, Local2) // Arg1 could be 3, 2, 1, 0 - Multiply (Local2, 0x08, Local2) // change to 24, 16, 8, 0 - Store (And (ShiftRight(Local1, Local2), 0xff), Local0) - Return (Local0) - } - - /* GetBus(Node, Link) */ - Method (GBUS, 2, NotSerialized) - { - Store (0x00, Local0) - While (LLess (Local0, 0x04)) - { - Store (DerefOf (Index (\_SB.PCI0.BUSN, Local0)), Local1) - If (LEqual (And (Local1, 0x03), 0x03)) - { - If (LEqual (Arg0, ShiftRight (And (Local1, 0x70), 0x04))) - { - If (LOr (LEqual (Arg1, 0xFF), LEqual (Arg1, ShiftRight (And (Local1, 0x0300), 0x08)))) - { - Return (ShiftRight (And (Local1, 0x00FF0000), 0x10)) - } - } - } - - Increment (Local0) - } - - Return (0x00) - } - - /* GetBusResources(Node, Link) */ - Method (GWBN, 2, Serialized) - { - Name (BUF0, ResourceTemplate () - { - WordBusNumber (ResourceProducer, MinFixed, MaxFixed, PosDecode, - 0x0000, // Address Space Granularity - 0x0000, // Address Range Minimum - 0x0000, // Address Range Maximum - 0x0000, // Address Translation Offset - 0x0001,,,) - }) - CreateWordField (BUF0, 0x08, BMIN) - CreateWordField (BUF0, 0x0A, BMAX) - CreateWordField (BUF0, 0x0E, BLEN) - Store (0x00, Local0) - While (LLess (Local0, 0x04)) - { - Store (DerefOf (Index (\_SB.PCI0.BUSN, Local0)), Local1) - If (LEqual (And (Local1, 0x03), 0x03)) - { - If (LEqual (Arg0, ShiftRight (And (Local1, 0x70), 0x04))) - { - If (LOr (LEqual (Arg1, 0xFF), LEqual (Arg1, ShiftRight (And (Local1, 0x0300), 0x08)))) - { - Store (ShiftRight (And (Local1, 0x00FF0000), 0x10), BMIN) - Store (ShiftRight (Local1, 0x18), BMAX) - Subtract (BMAX, BMIN, BLEN) - Increment (BLEN) - Return (RTAG (BUF0)) - } - } - } - - Increment (Local0) - } - - Return (RTAG (BUF0)) - } - - /* GetMemoryResources(Node, Link) */ - Method (GMEM, 2, Serialized) - { - Name (BUF0, ResourceTemplate () - { - DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, NonCacheable, ReadWrite, - 0x00000000, // Address Space Granularity - 0x00000000, // Address Range Minimum - 0x00000000, // Address Range Maximum - 0x00000000, // Address Translation Offset - 0x00000001,,, - , AddressRangeMemory, TypeStatic) - }) - CreateDWordField (BUF0, 0x0A, MMIN) - CreateDWordField (BUF0, 0x0E, MMAX) - CreateDWordField (BUF0, 0x16, MLEN) - Store (0x00, Local0) - Store (0x00, Local4) - Store (0x00, Local3) - While (LLess (Local0, 0x10)) - { - /* Get value of the first register */ - Store (DerefOf (Index (\_SB.PCI0.MMIO, Local0)), Local1) - Increment (Local0) - Store (DerefOf (Index (\_SB.PCI0.MMIO, Local0)), Local2) - If (LEqual (And (Local1, 0x03), 0x03)) /* Pair enabled? */ - { - If (LEqual (Arg0, And (Local2, 0x07))) /* Node matches? */ - { - /* If Link Matches (or we got passed 0xFF) */ - If (LOr (LEqual (Arg1, 0xFF), LEqual (Arg1, ShiftRight (And (Local2, 0x30), 0x04)))) - { - /* Extract the Base and Limit values */ - Store (ShiftLeft (And (Local1, 0xFFFFFF00), 0x08), MMIN) - Store (ShiftLeft (And (Local2, 0xFFFFFF00), 0x08), MMAX) - Or (MMAX, 0xFFFF, MMAX) - Subtract (MMAX, MMIN, MLEN) - Increment (MLEN) - - If (Local4) /* I've already done this once */ - { - Concatenate (RTAG (BUF0), Local3, Local5) - Store (Local5, Local3) - } - Else - { - Store (RTAG (BUF0), Local3) - } - - Increment (Local4) - } - } - } - - Increment (Local0) - } - - If (LNot (Local4)) /* No resources for this node and link. */ - { - Store (RTAG (BUF0), Local3) - } - - Return (Local3) - } - - /* GetIOResources(Node, Link) */ - Method (GIOR, 2, Serialized) - { - Name (BUF0, ResourceTemplate () - { - DWordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange, - 0x00000000, // Address Space Granularity - 0x00000000, // Address Range Minimum - 0x00000000, // Address Range Maximum - 0x00000000, // Address Translation Offset - 0x00000001,,, - , TypeStatic) - }) - CreateDWordField (BUF0, 0x0A, PMIN) - CreateDWordField (BUF0, 0x0E, PMAX) - CreateDWordField (BUF0, 0x16, PLEN) - Store (0x00, Local0) - Store (0x00, Local4) - Store (0x00, Local3) - While (LLess (Local0, 0x08)) - { - Store (DerefOf (Index (\_SB.PCI0.PCIO, Local0)), Local1) - Increment (Local0) - Store (DerefOf (Index (\_SB.PCI0.PCIO, Local0)), Local2) - If (LEqual (And (Local1, 0x03), 0x03)) /* Pair enabled? */ - { - If (LEqual (Arg0, And (Local2, 0x07))) /* Node matches? */ - { - /* If Link Matches (or we got passed 0xFF) */ - If (LOr (LEqual (Arg1, 0xFF), LEqual (Arg1, ShiftRight (And (Local2, 0x30), 0x04)))) - { - /* Extract the Base and Limit values */ - Store (And (Local1, 0x01FFF000), PMIN) - Store (And (Local2, 0x01FFF000), PMAX) - Or (PMAX, 0x0FFF, PMAX) - Subtract (PMAX, PMIN, PLEN) - Increment (PLEN) - - If (Local4) /* I've already done this once */ - { - Concatenate (RTAG (BUF0), Local3, Local5) - Store (Local5, Local3) - } - Else - { - If (LGreater (PMAX, PMIN)) - { - If (LOr (LAnd (LEqual (Arg1, 0xFF), LEqual (Arg0, 0x00)), LEqual (Arg1, \_SB.PCI0.SBLK))) - { - Store (0x0D00, PMIN) - Subtract (PMAX, PMIN, PLEN) - Increment (PLEN) - } - - Store (RTAG (BUF0), Local3) - Increment (Local4) - } - - If (And (Local1, 0x10)) - { - Store (0x03B0, PMIN) - Store (0x03DF, PMAX) - Store (0x30, PLEN) - - If (Local4) - { - Concatenate (RTAG (BUF0), Local3, Local5) - Store (Local5, Local3) - } - Else - { - Store (RTAG (BUF0), Local3) - } - } - } - - Increment (Local4) - } - } - } - - Increment (Local0) - } - - If (LNot (Local4)) /* No resources for this node and link. */ - { - Store (RTAG (BUF0), Local3) - } - - Return (Local3) - } - - Method (RTAG, 1, NotSerialized) - { - Store (Arg0, Local0) - Store (SizeOf (Local0), Local1) - Subtract (Local1, 0x02, Local1) - Multiply (Local1, 0x08, Local1) - CreateField (Local0, 0x00, Local1, RETB) - Store (RETB, Local2) - Return (Local2) - } -} diff --git a/src/northbridge/amd/amdk8/util.c b/src/northbridge/amd/amdk8/util.c deleted file mode 100644 index aea046935c..0000000000 --- a/src/northbridge/amd/amdk8/util.c +++ /dev/null @@ -1,269 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2008 Vincent Legoll <vincent.legoll@gmail.com> - * Copyright (C) 2008 Ronald G. Minnich <rminnich@gmail.com> - * - * 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. - */ - -/* - * K8 northbridge utilities (dump routing registers). - * Designed to be called at any time. - * It can be called before RAM is set up by including this file. - * It can be called after RAM is set up by including amdk8.h and enabling the - * compilation of this file in src/northbridge/amd/amdk8/Makefile.inc. - */ -#ifndef __PRE_RAM__ -#include <console/console.h> -#include <device/pci.h> -#include <device/pci_ops.h> -#endif -#include "amdk8.h" - -/* Function 1 */ -/* the DRAM, MMIO,and PCIIO routing are 64-bit registers, hence the ending at - * 0x78, 0xb8, and 0xd8 - */ -#define DRAM_ROUTE_START 0x40 -#define DRAM_ROUTE_END 0x78 -#define MMIO_ROUTE_START 0x80 -#define MMIO_ROUTE_END 0xb8 -#define PCIIO_ROUTE_START 0xc0 -#define PCIIO_ROUTE_END 0xd8 -#define CONFIG_ROUTE_START 0xe0 -#define CONFIG_ROUTE_END 0xec - -#define PCI_IO_BASE0 0xc0 -#define PCI_IO_BASE1 0xc8 -#define PCI_IO_BASE2 0xd0 -#define PCI_IO_BASE3 0xd8 -#define PCI_IO_BASE_VGA_EN (1 << 4) -#define PCI_IO_BASE_NO_ISA (1 << 5) - -#define BITS(r, shift, mask) (((r>>shift)&mask)) - -/** - * Return "R" if the register has read-enable bit set. - */ -static const char *re(u32 i) -{ - return ((i & 1) ? "R" : ""); -} - -/** - * Return "W" if the register has write-enable bit set. - */ -static const char *we(u32 i) -{ - return ((i & 1) ? "W" : ""); -} - -/** - * Return a string containing the interleave settings. - */ -static const char *ileave(u32 base) -{ - switch ((base >> 8) & 7) { - case 0: - return "No interleave"; - case 1: - return "2 nodes"; - case 3: - return "4 nodes"; - case 7: - return "8 nodes"; - default: - return "Reserved"; - } -} - -/** - * Return the node number. - * For one case (config registers) these are not the right bit fields. - */ -static int r_node(u32 reg) -{ - return BITS(reg, 0, 0x7); -} - -/** - * Return the link number. - * For one case (config registers) these are not the right bit fields. - */ -static int r_link(u32 reg) -{ - return BITS(reg, 4, 0x3); -} - -/** - * Print the DRAM routing info for one base/limit pair. - * - * Show base, limit, dest node, dest link on that node, read and write - * enable, and interleave information. - * - * @param level Printing level - * @param which Register number - * @param base Base register - * @param lim Limit register - */ -static void showdram(int level, u8 which, u32 base, u32 lim) -{ - printk(level, "DRAM(%02x)%010llx-%010llx, ->(%d), %s, %s, %s, %d\n", - which, (((u64) base & 0xffff0000) << 8), - (((u64) lim & 0xffff0000) << 8) + 0xffffff, - r_node(lim), re(base), we(base), ileave(base), (lim >> 8) & 3); -} - -/** - * Print the config routing info for a config register. - * - * Show base, limit, dest node, dest link on that node, read and write - * enable, and device number compare enable - * - * @param level Printing level - * @param which Register number - * @param reg Config register - */ -static void showconfig(int level, u8 which, u32 reg) -{ - /* Don't use r_node() and r_link() here. */ - printk(level, "CONFIG(%02x)%02x-%02x ->(%d,%d),%s %s (%s numbers)\n", - which, BITS(reg, 16, 0xff), BITS(reg, 24, 0xff), - BITS(reg, 4, 0x7), BITS(reg, 8, 0x3), - re(reg), we(reg), - BITS(reg, 2, 0x1)?"dev":"bus"); -} - -/** - * Print the PCIIO routing info for one base/limit pair. - * - * Show base, limit, dest node, dest link on that node, read and write - * enable, and VGA and ISA Enable. - * - * @param level Printing level - * @param which Register number - * @param base Base register - * @param lim Limit register - */ -static void showpciio(int level, u8 which, u32 base, u32 lim) -{ - printk(level, "PCIIO(%02x)%07x-%07x, ->(%d,%d), %s, %s,VGA %d ISA %d\n", - which, BITS(base, 12, 0x3fff) << 12, - (BITS(lim, 12, 0x3fff) << 12) + 0xfff, r_node(lim), r_link(lim), - re(base), we(base), BITS(base, 4, 0x1), BITS(base, 5, 0x1)); -} - -/** - * Print the MMIO routing info for one base/limit pair. - * - * Show base, limit, dest node, dest link on that node, read and write - * enable, and CPU Disable, Lock, and Non-posted. - * - * @param level Printing level - * @param which Register number - * @param base Base register - * @param lim Limit register - */ -static void showmmio(int level, u8 which, u32 base, u32 lim) -{ - printk(level, "MMIO(%02x)%010llx-%010llx, ->(%d,%d), %s, %s, " - "CPU disable %d, Lock %d, Non posted %d\n", - which, ((u64) BITS(base, 0, 0xffffff00)) << 8, - (((u64) BITS(lim, 0, 0xffffff00)) << 8) + 0xffff, r_node(lim), - r_link(lim), re(base), we(base), BITS(base, 4, 0x1), - BITS(base, 7, 0x1), BITS(lim, 7, 0x1)); -} - -/** - * Show all DRAM routing registers. This function is callable at any time. - * - * @param level The debug level. - * @param dev A 32-bit number in the standard bus/dev/fn format which is used - * raw config space. - */ -static void showalldram(int level, struct device *dev) -{ - u8 reg; - for (reg = DRAM_ROUTE_START; reg <= DRAM_ROUTE_END; reg += 8) { - u32 base = pci_read_config32(dev, reg); - u32 lim = pci_read_config32(dev, reg + 4); - if (base || lim!=(reg-DRAM_ROUTE_START)/8) - showdram(level, reg, base, lim); - } -} - -/** - * Show all MMIO routing registers. This function is callable at any time. - * - * @param level The debug level. - * @param dev A 32-bit number in the standard bus/dev/fn format which is used - * raw config space. - */ -static void showallmmio(int level, struct device *dev) -{ - u8 reg; - for (reg = MMIO_ROUTE_START; reg <= MMIO_ROUTE_END; reg += 8) { - u32 base = pci_read_config32(dev, reg); - u32 lim = pci_read_config32(dev, reg + 4); - if (base || lim) - showmmio(level, reg, base, lim); - } -} - -/** - * Show all PCIIO routing registers. This function is callable at any time. - * - * @param level The debug level. - * @param dev A 32-bit number in the standard bus/dev/fn format which is used - * raw config space. - */ -static void showallpciio(int level, struct device *dev) -{ - u8 reg; - for (reg = PCIIO_ROUTE_START; reg <= PCIIO_ROUTE_END; reg += 8) { - u32 base = pci_read_config32(dev, reg); - u32 lim = pci_read_config32(dev, reg + 4); - if (base || lim) - showpciio(level, reg, base, lim); - } -} - -/** - * Show all config routing registers. This function is callable at any time. - * - * @param level The debug level. - * @param dev A 32-bit number in the standard bus/dev/fn format which is used - * raw config space. - */ -static void showallconfig(int level, struct device *dev) -{ - u8 reg; - for (reg = CONFIG_ROUTE_START; reg <= CONFIG_ROUTE_END; reg += 4) { - u32 val = pci_read_config32(dev, reg); - if (val) - showconfig(level, reg, val); - } -} - -/** - * Show all routing registers. This function is callable at any time. - * - * @param level The debug level. - * @param dev A 32-bit number in the standard bus/dev/fn format which is used - * raw config space. - */ -void showallroutes(int level, struct device *dev) -{ - showalldram(level, dev); - showallmmio(level, dev); - showallpciio(level, dev); - showallconfig(level, dev); -} |