Michał Żygowski has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/62070 )
Change subject: KGPE-D16: Add minimal source for bootblock from 4.11_branch ......................................................................
KGPE-D16: Add minimal source for bootblock from 4.11_branch
This is the unmodified source of KGPE-D16 from 4.11_branch with the necessary silicon source for bootblock and a part of romstage. The subsequent commits will add small changes to make the code buildable and implement C environment bootblock. Patchsets for romstage and later will be added in separate topics.
Signed-off-by: Michał Żygowski michal.zygowski@3mdeb.com Change-Id: Ide558d3276d8770d1dea2b1b5790ca42595d9730 --- A src/cpu/amd/car/cache_as_ram.inc A src/cpu/amd/family_10h-family_15h/Kconfig A src/cpu/amd/family_10h-family_15h/Makefile.inc A src/cpu/amd/socket_G34/Kconfig A src/cpu/amd/socket_G34/Makefile.inc A src/cpu/amd/socket_G34/socket_G34.c A src/mainboard/asus/kgpe-d16/Kconfig A src/mainboard/asus/kgpe-d16/Kconfig.name A src/mainboard/asus/kgpe-d16/Makefile.inc A src/mainboard/asus/kgpe-d16/acpi_tables.c A src/mainboard/asus/kgpe-d16/board_info.txt A src/mainboard/asus/kgpe-d16/bootblock.c A src/mainboard/asus/kgpe-d16/cmos.default A src/mainboard/asus/kgpe-d16/cmos.layout A src/mainboard/asus/kgpe-d16/devicetree.cb A src/mainboard/asus/kgpe-d16/dsdt.asl A src/mainboard/asus/kgpe-d16/mainboard.c A src/mainboard/asus/kgpe-d16/spd_notes.txt A src/northbridge/amd/amdfam10/Kconfig A src/northbridge/amd/amdfam10/Makefile.inc A src/northbridge/amd/amdfam10/acpi.c A src/northbridge/amd/amdfam10/bootblock.c A src/northbridge/amd/amdfam10/chip.h A src/northbridge/amd/amdfam10/early_ht.c A src/northbridge/amd/amdfam10/early_ht.h A src/northbridge/amd/amdfam10/northbridge.c A src/northbridge/amd/amdfam10/northbridge.h A src/northbridge/amd/amdfam10/nums.h A src/southbridge/amd/sb700/Kconfig A src/southbridge/amd/sb700/Makefile.inc A src/southbridge/amd/sb700/bootblock.c A src/southbridge/amd/sb700/chip.h A src/southbridge/amd/sb700/enable_usbdebug.c A src/southbridge/amd/sb700/fadt.c A src/southbridge/amd/sb700/ramtop.c A src/southbridge/amd/sb700/reset.c A src/southbridge/amd/sb700/sb700.c A src/southbridge/amd/sb700/sb700.h A src/southbridge/amd/sr5650/Kconfig A src/southbridge/amd/sr5650/Makefile.inc A src/southbridge/amd/sr5650/chip.h A src/southbridge/amd/sr5650/rev.h A src/southbridge/amd/sr5650/sr5650.c A src/southbridge/amd/sr5650/sr5650.h 44 files changed, 7,317 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/70/62070/1
diff --git a/src/cpu/amd/car/cache_as_ram.inc b/src/cpu/amd/car/cache_as_ram.inc new file mode 100644 index 0000000..2054ea3 --- /dev/null +++ b/src/cpu/amd/car/cache_as_ram.inc @@ -0,0 +1,648 @@ +/* + * 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 <cpu/x86/mtrr.h> +#include <cpu/x86/cache.h> +#include <cpu/amd/msr.h> +#include <cpu/amd/mtrr.h> + +#define CacheSize CONFIG_DCACHE_RAM_SIZE +#define CacheBase CONFIG_DCACHE_RAM_BASE +#define CacheSizeBSPStack CONFIG_DCACHE_BSP_TOP_STACK_SIZE +#define CacheSizeBSPSlush CONFIG_DCACHE_BSP_TOP_STACK_SLUSH + +/* For CAR with Fam10h. */ +#define CacheSizeAPStack CONFIG_DCACHE_AP_STACK_SIZE + +#define jmp_if_not_k8(x) comisd %xmm2, %xmm1; jae x +#define jmp_if_k8(x) comisd %xmm2, %xmm1; jb x +#define jmp_if_not_fam15h(x) comisd %xmm3, %xmm1; jb x +#define jmp_if_fam15h(x) comisd %xmm3, %xmm1; jae x + +#define CPUID_MASK 0x0ff00f00 +#define CPUID_VAL_FAM10_ROTATED 0x0f000010 +#define CPUID_VAL_FAM15_ROTATED 0x0f000060 + +/* + * XMM map: + * xmm1: CPU family + * xmm2: Fam10h comparison value + * xmm3: Fam15h comparison value + * xmm4: Backup EBX + * xmm5: coreboot init detect + */ + + /* Save the BIST result. */ + movl %eax, %ebp + + /* + * For normal part %ebx already contain cpu_init_detected + * from fallback call. + */ + +cache_as_ram_setup: + post_code(0xa0) + + /* Enable SSE. */ + movl %cr4, %eax + orl $(3 << 9), %eax + movl %eax, %cr4 + + /* Figure out the CPU family. */ + cvtsi2sd %ebx, %xmm4 + movl $0x01, %eax + cpuid + /* Base family is bits 8..11, extended family is bits 20..27. */ + andl $CPUID_MASK, %eax + /* Reorder bits for easier comparison by value. */ + roll $0x10, %eax + cvtsi2sd %eax, %xmm1 + movl $CPUID_VAL_FAM10_ROTATED, %eax + cvtsi2sd %eax, %xmm2 + movl $CPUID_VAL_FAM15_ROTATED, %eax + cvtsi2sd %eax, %xmm3 + cvtsd2si %xmm4, %ebx + + /* Check if cpu_init_detected. */ + movl $MTRR_DEF_TYPE_MSR, %ecx + rdmsr + andl $MTRR_DEF_TYPE_EN, %eax + movl %eax, %ebx /* We store the status. */ + cvtsi2sd %ebx, %xmm5 + + jmp_if_k8(CAR_FAM10_out_post_errata) + + /* + * For GH, CAR need to set DRAM Base/Limit registers to direct that + * to node0. + * Only BSP needed, for other nodes set during HT/memory init. + * So we need to check if it is BSP. + */ + movl $0x1b, %ecx + rdmsr + bt $8, %eax /* BSP */ + jnc CAR_FAM10_out + + /* Enable RT tables on BSP. */ + movl $0x8000c06c, %eax + movw $0xcf8, %dx + outl %eax, %dx + addw $4, %dx + inl %dx, %eax + btr $0, %eax + outl %eax, %dx + + /* Setup temporary DRAM map: [0,16M) bit 0-23. */ + movl $0x8000c144, %eax + movw $0xcf8, %dx + outl %eax, %dx + addw $4, %dx + movl $0, %eax + outl %eax, %dx + + movl $0x8000c140, %eax + movw $0xcf8, %dx + outl %eax, %dx + addw $4, %dx + movl $3, %eax + outl %eax, %dx + +CAR_FAM10_out: + + jmp_if_fam15h(CAR_FAM10_errata_applied) + /* + * Errata 193: Disable clean copybacks to L3 cache to allow cached ROM. + * Re-enable it in after RAM is initialized and before CAR is disabled. + */ + movl $BU_CFG2_MSR, %ecx + rdmsr + bts $15, %eax /* Set bit 15 in EDX:EAX (bit 15 in EAX). */ + wrmsr + + /* Erratum 343, RevGuide for Fam10h, Pub#41322 Rev. 3.33 */ + movl $BU_CFG2_MSR, %ecx + rdmsr + bts $35-32, %edx /* Set bit 35 in EDX:EAX (bit 3 in EDX). */ + wrmsr + +CAR_FAM10_errata_applied: + +#if CONFIG(MMCONF_SUPPORT) + #if (CONFIG_MMCONF_BASE_ADDRESS > 0xFFFFFFFF) + #error "MMCONF_BASE_ADDRESS too big" + #elif (CONFIG_MMCONF_BASE_ADDRESS & 0xFFFFF) + #error "MMCONF_BASE_ADDRESS not 1MB aligned" + #endif + movl $0, %edx + movl $((CONFIG_MMCONF_BASE_ADDRESS) | (1 << 0)), %eax + #if (CONFIG_MMCONF_BUS_NUMBER == 1) + #elif (CONFIG_MMCONF_BUS_NUMBER == 2) + orl $(1 << 2), %eax + #elif (CONFIG_MMCONF_BUS_NUMBER == 4) + orl $(2 << 2), %eax + #elif (CONFIG_MMCONF_BUS_NUMBER == 8) + orl $(3 << 2), %eax + #elif (CONFIG_MMCONF_BUS_NUMBER == 16) + orl $(4 << 2), %eax + #elif (CONFIG_MMCONF_BUS_NUMBER == 32) + orl $(5 << 2), %eax + #elif (CONFIG_MMCONF_BUS_NUMBER == 64) + orl $(6 << 2), %eax + #elif (CONFIG_MMCONF_BUS_NUMBER == 128) + orl $(7 << 2), %eax + #elif (CONFIG_MMCONF_BUS_NUMBER == 256) + orl $(8 << 2), %eax + #else + #error "bad MMCONF_BUS_NUMBER value" + #endif + movl $MMIO_CONF_BASE, %ecx + wrmsr +#endif + +CAR_FAM10_out_post_errata: + + /* Fam15h APIC IDs do not depend on NB config bit 54 */ + jmp_if_not_fam15h(skip_nb54_set) + movl $NB_CFG_MSR, %ecx + rdmsr + bts $(54 - 32), %edx /* Set NB config bit 54 */ + wrmsr + +skip_nb54_set: + /* On Fam15h CPUs each compute unit's MTRRs are shared between two cores */ + jmp_if_not_fam15h(skip_cu_check) + + /* Get the initial APIC ID. */ + movl $1, %eax + cpuid + movl %ebx, %eax + + /* Restore init detect */ + cvtsd2si %xmm5, %ebx + + /* Determine if this is the second core to start in a compute unit; if so, wait for first core start, clear init detect and skip MTRR init */ + bt $24, %eax + jnc skip_cu_check /* First core in the compute unit jumps to skip_cu_check */ + + /* Determine if this is the second core to start in a compute unit; if so, clear init detect and skip MTRR init */ + /* Busywait until the first core sets up the MTRRs */ +check_init_detect_1: + /* Check if cpu_init_detected. */ + movl $MTRR_DEF_TYPE_MSR, %ecx + rdmsr + andl $MTRR_DEF_TYPE_EN, %eax + cmp $0x00000000, %eax + je check_init_detect_1 /* First core has not yet started */ + +check_init_detect_2: + movl $SYSCFG_MSR, %ecx + rdmsr + andl $(SYSCFG_MSR_MtrrFixDramEn | SYSCFG_MSR_MtrrVarDramEn), %eax + cmp $0x00000000, %eax + je check_init_detect_2 /* First core has not yet started */ + + /* First core has now started */ + movl $0x00000000, %ebx /* Clear init detect flag */ + cvtsi2sd %ebx, %xmm5 + jmp fam10_mtrr_setup_complete + +skip_cu_check: + + jmp_if_not_fam15h(CAR_FAM15_errata_applied) + + /* Erratum 714, RevGuide for Fam15h, Pub#48063 Rev. 3.24 */ + movl $BU_CFG2_MSR, %ecx + rdmsr + bts $8, %eax /* Set bit 8 in EDX:EAX (bit 8 in EAX). */ + wrmsr + +CAR_FAM15_errata_applied: + + /* Set MtrrFixDramModEn for clear fixed MTRR. */ +enable_fixed_mtrr_dram_modify: + movl $SYSCFG_MSR, %ecx + rdmsr + andl $(~(SYSCFG_MSR_MtrrFixDramEn | SYSCFG_MSR_MtrrVarDramEn)), %eax + orl $SYSCFG_MSR_MtrrFixDramModEn, %eax + wrmsr + + /* Clear all MTRRs. */ + xorl %edx, %edx + movl $all_mtrr_msrs, %esi + +clear_fixed_var_mtrr: + lodsl (%esi), %eax + testl %eax, %eax + jz clear_fixed_var_mtrr_out + + movl %eax, %ecx + xorl %eax, %eax + wrmsr + + jmp clear_fixed_var_mtrr +clear_fixed_var_mtrr_out: + +/* + * 0x06 is the WB IO type for a given 4k segment. + * 0x1e is the MEM IO type for a given 4k segment (K10 and above). + * segs is the number of 4k segments in the area of the particular + * register we want to use for CAR. + * reg is the register where the IO type should be stored. + */ +.macro extractmask segs, reg +.if \segs <= 0 + /* + * The xorl here is superfluous because at the point of first execution + * of this macro, %eax and %edx are cleared. Later invocations of this + * macro will have a monotonically increasing segs parameter. + */ + xorl \reg, \reg +.else + jmp_if_k8(1f) + +.if \segs == 1 + movl $0x1e000000, \reg /* WB MEM type */ +.elseif \segs == 2 + movl $0x1e1e0000, \reg /* WB MEM type */ +.elseif \segs == 3 + movl $0x1e1e1e00, \reg /* WB MEM type */ +.elseif \segs >= 4 + movl $0x1e1e1e1e, \reg /* WB MEM type */ +.endif + jmp 2f +1: +.if \segs == 1 + movl $0x06000000, \reg /* WB IO type */ +.elseif \segs == 2 + movl $0x06060000, \reg /* WB IO type */ +.elseif \segs == 3 + movl $0x06060600, \reg /* WB IO type */ +.elseif \segs >= 4 + movl $0x06060606, \reg /* WB IO type */ +.endif +2: +.endif /* if \segs <= 0 */ +.endm + +/* + * carsize is the cache size in bytes we want to use for CAR. + * windowoffset is the 32k-aligned window into CAR size. + */ +.macro simplemask carsize, windowoffset + .set gas_bug_workaround,(((\carsize - \windowoffset) >> 12) - 4) + extractmask gas_bug_workaround, %eax + .set gas_bug_workaround,(((\carsize - \windowoffset) >> 12)) + extractmask gas_bug_workaround, %edx + /* + * Without the gas bug workaround, the entire macro would consist + * only of the two lines below: + * extractmask (((\carsize - \windowoffset) >> 12) - 4), %eax + * extractmask (((\carsize - \windowoffset) >> 12)), %edx + */ +.endm + +#if CONFIG(CPU_AMD_MODEL_10XXX) + #if CacheSize > 0x80000 + #error Invalid CAR size, must be at most 128k (processor limit is 512k). + #endif +#else + #if CacheSize > 0x10000 + #error Invalid CAR size, must be at most 64k. + #endif +#endif +#if CacheSize < 0x1000 +#error Invalid CAR size, must be at least 4k. This is a processor limitation. +#endif +#if (CacheSize & (0x1000 - 1)) +#error Invalid CAR size, is not a multiple of 4k. This is a processor limitation. +#endif + +#if CacheSize > 0x8000 + /* Enable caching for 32K-64K using fixed MTRR. */ + movl $MTRR_FIX_4K_C0000, %ecx + simplemask CacheSize, 0x8000 + wrmsr +#endif + +#if CacheSize > 0x10000 + /* Enable caching for 64K-96K using fixed MTRR. */ + movl $MTRR_FIX_4K_D0000, %ecx + simplemask CacheSize, 0x10000 + wrmsr +#endif + +#if CacheSize > 0x18000 + /* Enable caching for 96K-128K using fixed MTRR. */ + movl $MTRR_FIX_4K_D8000, %ecx + simplemask CacheSize, 0x18000 + wrmsr +#endif + + /* Enable caching for 0-32K using fixed MTRR. */ + movl $MTRR_FIX_4K_C8000, %ecx + simplemask CacheSize, 0 + wrmsr + + jmp_if_fam15h(fam15_skip_dram_mtrr_setup) + + /* Enable memory access for first MBs using top_mem. */ + movl $TOP_MEM, %ecx + xorl %edx, %edx + movl $(((CONFIG_RAMTOP) + TOP_MEM_MASK) & ~TOP_MEM_MASK) , %eax + wrmsr + +fam15_skip_dram_mtrr_setup: + +#if CONFIG_XIP_ROM_SIZE + + /* Enable write base caching so we can do execute in place (XIP) + * on the flash ROM. + */ + movl $MTRR_PHYS_BASE(1), %ecx + xorl %edx, %edx + /* + * IMPORTANT: The following calculation _must_ be done at runtime. See + * https://mail.coreboot.org/pipermail/coreboot/2010-October/060922.html + */ + movl $_program, %eax + andl $(~(CONFIG_XIP_ROM_SIZE - 1)), %eax + orl $MTRR_TYPE_WRBACK, %eax + wrmsr + + movl $MTRR_PHYS_MASK(1), %ecx + movl $0xff, %edx /* (1 << (CONFIG_CPU_ADDR_BITS - 32)) - 1 for K8 (CONFIG_CPU_ADDR_BITS = 40) */ + jmp_if_k8(wbcache_post_fam10_setup) + movl $0xffff, %edx /* (1 << (CONFIG_CPU_ADDR_BITS - 32)) - 1 for FAM10 (CONFIG_CPU_ADDR_BITS = 48) */ +wbcache_post_fam10_setup: + movl $(~(CONFIG_XIP_ROM_SIZE - 1) | MTRR_PHYS_MASK_VALID), %eax + wrmsr +#endif /* CONFIG_XIP_ROM_SIZE */ + + /* Set the default memory type and enable fixed and variable MTRRs. */ + movl $MTRR_DEF_TYPE_MSR, %ecx + xorl %edx, %edx + movl $(MTRR_DEF_TYPE_EN | MTRR_DEF_TYPE_FIX_EN), %eax + wrmsr + + /* Enable the MTRRs and IORRs in SYSCFG. */ + movl $SYSCFG_MSR, %ecx + rdmsr + orl $(SYSCFG_MSR_MtrrVarDramEn | SYSCFG_MSR_MtrrFixDramEn), %eax + wrmsr + +fam10_mtrr_setup_complete: + post_code(0xa1) + + /* Disable conversion of INVD to WBINVD (INVDWBINVD = 0) */ + mov $HWCR_MSR, %ecx + rdmsr + btr $4, %eax + wrmsr + +jmp_if_not_fam15h(fam15_car_msr_setup_complete) + /* Disable streaming store (DisSS = 1) */ + mov $LS_CFG_MSR, %ecx + rdmsr + bts $28, %eax + wrmsr + + /* Disable speculative ITLB reloads (DisSpecTlbRld = 1) */ + mov $IC_CFG_MSR, %ecx + rdmsr + bts $9, %eax + wrmsr + + /* Disable speculative DTLB reloads (DisSpecTlbRld = 1) and set DisHwPf = 1 */ + mov $DC_CFG_MSR, %ecx + rdmsr + bts $4, %eax + bts $13, %eax + wrmsr + + /* Disable CR0 combining (CombineCr0Cd = 0) */ + mov $BU_CFG3_MSR, %ecx + rdmsr + btr $49-32, %edx + wrmsr +fam15_car_msr_setup_complete: + + /* Enable cache. */ + movl %cr0, %eax + andl $(~(CR0_CacheDisable | CR0_NoWriteThrough)), %eax + movl %eax, %cr0 + + jmp_if_not_k8(CAR_skip_k8_errata_part1) + + /* Set DisFillP on BSP. */ + movl $0x8000c068, %eax + movw $0xcf8, %dx + outl %eax, %dx + addw $4, %dx + inl %dx, %eax + bts $10, %eax + outl %eax, %dx + +CAR_skip_k8_errata_part1: + + jmp_if_k8(fam10_end_part1) + + /* So we need to check if it is BSP. */ + movl $0x1b, %ecx + rdmsr + bt $8, %eax /* BSP */ + jnc CAR_FAM10_ap +fam10_end_part1: + + post_code(0xa2) + + /* Read the range with lodsl. */ + cld + movl $CacheBase, %esi + movl $(CacheSize >> 2), %ecx + rep lodsl + + /* Clear the range. */ + movl $CacheBase, %edi + movl $(CacheSize >> 2), %ecx + xorl %eax, %eax + rep stosl + + jmp_if_not_k8(CAR_skip_k8_errata_part2) + + /* Clear DisFillP on BSP. */ + movl $0x8000c068, %eax + movw $0xcf8, %dx + outl %eax, %dx + addw $4, %dx + inl %dx, %eax + btr $10, %eax + outl %eax, %dx + +CAR_skip_k8_errata_part2: + + /* Set up the stack pointer. */ + movl $(CacheBase + CacheSize), %eax + movl %eax, %esp + + /* Poison the lower stack boundary */ + movl $((CacheBase + CacheSize) - CacheSizeBSPStack), %eax + movl $0xdeadbeef, (%eax) + + post_code(0xa3) + + jmp CAR_FAM10_ap_out +CAR_FAM10_ap: + /* + * Need to set stack pointer for AP. + * It will be from: + * CacheBase + (CacheSize - (CacheSizeBSPStack + CacheSizeBSPSlush)) + * - (NodeID << CoreIDbits + CoreID) * CacheSizeAPStack + * The spacing between the BSP stack and the top of the AP + * stacks is purposefully set larger (an extra CacheSizeBSPSlush + * worth of unused space) than necessary to aid debugging when + * additional stack variables are added by future developers. + * The extra space will allow BSP overruns to be caught by + * the warning logic and easily fixed instead of crashing the + * system with no obvious clues of what went wrong. + * + * So, need to get the NodeID and CoreID at first. + * If NB_CFG_MSR bit 54 is set just use initial APIC ID, otherwise need + * to reverse it. + */ + + /* Get the coreid bits at first. */ + movl $0x80000008, %eax + cpuid + shrl $12, %ecx + andl $0x0f, %ecx + movl %ecx, %edi + + /* Get the initial APIC ID. */ + movl $1, %eax + cpuid + shrl $24, %ebx + + /* Get the nb cfg bit 54. */ + movl $NB_CFG_MSR, %ecx + rdmsr + movl %edi, %ecx /* CoreID bits */ + bt $(54 - 32), %edx + jc roll_cfg + + /* Fam10h NB config bit 54 was not set */ + rolb %cl, %bl +roll_cfg: + jmp_if_not_fam15h(ap_apicid_ready) + cmp $0x5, %ecx + jne ap_apicid_ready + + /* This is a multi-node CPU + * Adjust the maximum APIC ID to a more reasonable value + * given that no 32-core Family 15h processors exist + */ + movl %ebx, %ecx + and $0x0f, %ecx /* Get lower 4 bits of CPU number */ + and $0x60, %ebx /* Get node ID */ + shrl $0x1, %ebx /* Shift node ID part of APIC ID down by 1 */ + or %ecx, %ebx /* Recombine node ID and CPU number */ + +ap_apicid_ready: + + /* Calculate stack pointer using adjusted APIC ID stored in ebx */ + movl $CacheSizeAPStack, %eax + mull %ebx + movl $(CacheBase + (CacheSize - (CacheSizeBSPStack + CacheSizeBSPSlush))), %esp + subl %eax, %esp + + /* Restore init detect */ + cvtsd2si %xmm5, %ebx + + post_code(0xa4) + +CAR_FAM10_ap_out: + + post_code(0xa5) + + /* Disable SSE. */ + movl %cr4, %eax + andl $~(3 << 9), %eax + movl %eax, %cr4 + + post_code(0xa6) + + /* Restore the BIST result. */ + movl %ebp, %eax + + /* We need to set EBP? No need. */ + movl %esp, %ebp + pushl %ebx /* Init detected. */ + pushl %eax /* BIST */ + + post_code(0xa7) + + call cache_as_ram_main + + call post_cache_as_ram + movl %eax, %esp + + call cache_as_ram_new_stack + + /* We will not go back. */ + + post_code(0xaf) /* Should never see this POST code. */ + +all_mtrr_msrs: + /* fixed MTRR MSRs */ + .long MTRR_FIX_64K_00000 + .long MTRR_FIX_16K_80000 + .long MTRR_FIX_16K_A0000 + .long MTRR_FIX_4K_C0000 + .long MTRR_FIX_4K_C8000 + .long MTRR_FIX_4K_D0000 + .long MTRR_FIX_4K_D8000 + .long MTRR_FIX_4K_E0000 + .long MTRR_FIX_4K_E8000 + .long MTRR_FIX_4K_F0000 + .long MTRR_FIX_4K_F8000 + + /* var MTRR MSRs */ + .long MTRR_PHYS_BASE(0) + .long MTRR_PHYS_MASK(0) + .long MTRR_PHYS_BASE(1) + .long MTRR_PHYS_MASK(1) + .long MTRR_PHYS_BASE(2) + .long MTRR_PHYS_MASK(2) + .long MTRR_PHYS_BASE(3) + .long MTRR_PHYS_MASK(3) + .long MTRR_PHYS_BASE(4) + .long MTRR_PHYS_MASK(4) + .long MTRR_PHYS_BASE(5) + .long MTRR_PHYS_MASK(5) + .long MTRR_PHYS_BASE(6) + .long MTRR_PHYS_MASK(6) + .long MTRR_PHYS_BASE(7) + .long MTRR_PHYS_MASK(7) + + /* Variable IORR MTRR MSRs */ + .long IORRBase_MSR(0) + .long IORRMask_MSR(0) + .long IORRBase_MSR(1) + .long IORRMask_MSR(1) + + /* Top of memory MTRR MSRs */ + .long TOP_MEM + .long TOP_MEM2 + + .long 0x000 /* NULL, end of table */ + +cache_as_ram_setup_out: diff --git a/src/cpu/amd/family_10h-family_15h/Kconfig b/src/cpu/amd/family_10h-family_15h/Kconfig new file mode 100644 index 0000000..ad4f5f4 --- /dev/null +++ b/src/cpu/amd/family_10h-family_15h/Kconfig @@ -0,0 +1,90 @@ +config CPU_AMD_MODEL_10XXX + bool + select ARCH_BOOTBLOCK_X86_32 + select ARCH_VERSTAGE_X86_32 + select ARCH_ROMSTAGE_X86_32 + select ARCH_RAMSTAGE_X86_32 + select SSE2 + select TSC_SYNC_LFENCE + select UDELAY_LAPIC + select SUPPORT_CPU_UCODE_IN_CBFS + select CPU_MICROCODE_MULTIPLE_FILES + select CAR_GLOBAL_MIGRATION + +if CPU_AMD_MODEL_10XXX + +config USE_LARGE_DCACHE + bool + default y if CPU_AMD_SOCKET_G34_NON_AGESA + default y if CPU_AMD_SOCKET_FM2_NON_AGESA + default y if CPU_AMD_SOCKET_C32_NON_AGESA + default n + +config NUM_IPI_STARTS + int + default 1 + +config CPU_ADDR_BITS + int + default 48 + +config DCACHE_RAM_BASE + hex + default 0xc4000 + +config DCACHE_RAM_SIZE + hex + default 0x0c000 + +config DCACHE_BSP_TOP_STACK_SIZE + hex + default 0x4000 + +config DCACHE_BSP_TOP_STACK_SLUSH + hex + default 0x4000 if USE_LARGE_DCACHE + default 0x1000 + +config DCACHE_AP_STACK_SIZE + hex + default 0x500 + +config SET_FIDVID + bool + default y + +config MAX_PHYSICAL_CPUS + int + default 1 + +config LIFT_BSP_APIC_ID + bool + default n + +if SET_FIDVID +config SET_FIDVID_DEBUG + bool + default y + +config SET_FIDVID_STORE_AP_APICID_AT_FIRST + bool + default y + +config SET_FIDVID_CORE0_ONLY + bool + default n + +# 0: all cores +# 1: core 0 only +# 2: all but core 0 +config SET_FIDVID_CORE_RANGE + int + default 0 + +endif # SET_FIDVID + +config UDELAY_LAPIC_FIXED_FSB + int + default 200 + +endif # CPU_AMD_MODEL_10XXX diff --git a/src/cpu/amd/family_10h-family_15h/Makefile.inc b/src/cpu/amd/family_10h-family_15h/Makefile.inc new file mode 100644 index 0000000..7035323 --- /dev/null +++ b/src/cpu/amd/family_10h-family_15h/Makefile.inc @@ -0,0 +1,25 @@ +romstage-y += ../../x86/mtrr/earlymtrr.c +romstage-y += ../car/post_cache_as_ram.c + +romstage-y += init_cpus.c + +ramstage-y += model_10xxx_init.c +ramstage-y += processor_name.c + +romstage-y += update_microcode.c +romstage-y += tsc_freq.c +ramstage-y += tsc_freq.c +romstage-y += ram_calc.c +ramstage-y += ram_calc.c +ramstage-y += monotonic_timer.c +ramstage-$(CONFIG_HAVE_ACPI_TABLES) += powernow_acpi.c + +# Microcode for Family 10h, 11h, 12h, and 14h +cbfs-files-$(CONFIG_CPU_MICROCODE_CBFS_DEFAULT_BINS) += microcode_amd.bin +microcode_amd.bin-file := 3rdparty/blobs/cpu/amd/family_10h-family_14h/microcode_amd.bin +microcode_amd.bin-type := microcode + +# Microcode for Family 15h +cbfs-files-$(CONFIG_CPU_MICROCODE_CBFS_DEFAULT_BINS) += microcode_amd_fam15h.bin +microcode_amd_fam15h.bin-file := 3rdparty/blobs/cpu/amd/family_15h/microcode_amd_fam15h.bin +microcode_amd_fam15h.bin-type := microcode diff --git a/src/cpu/amd/socket_G34/Kconfig b/src/cpu/amd/socket_G34/Kconfig new file mode 100644 index 0000000..abc9726 --- /dev/null +++ b/src/cpu/amd/socket_G34/Kconfig @@ -0,0 +1,29 @@ +config CPU_AMD_SOCKET_G34_NON_AGESA + bool + select CPU_AMD_MODEL_10XXX + select PCI_IO_CFG_EXT + select X86_AMD_FIXED_MTRRS + +if CPU_AMD_SOCKET_G34_NON_AGESA + +config CPU_SOCKET_TYPE + hex + default 0x15 + +config EXT_RT_TBL_SUPPORT + bool + default n + +config CBB + hex + default 0x0 + +config CDB + hex + default 0x18 + +config XIP_ROM_SIZE + hex + default 0x80000 + +endif diff --git a/src/cpu/amd/socket_G34/Makefile.inc b/src/cpu/amd/socket_G34/Makefile.inc new file mode 100644 index 0000000..de33cd3 --- /dev/null +++ b/src/cpu/amd/socket_G34/Makefile.inc @@ -0,0 +1,14 @@ +ramstage-y += socket_G34.c +subdirs-y += ../family_10h-family_15h +subdirs-y += ../quadcore +subdirs-y += ../mtrr +subdirs-y += ../microcode +subdirs-y += ../../x86/tsc +subdirs-y += ../../x86/lapic +subdirs-y += ../../x86/cache +subdirs-y += ../../x86/pae +subdirs-y += ../../x86/mtrr +subdirs-y += ../../x86/smm +subdirs-y += ../smm + +cpu_incs-y += $(src)/cpu/amd/car/cache_as_ram.inc diff --git a/src/cpu/amd/socket_G34/socket_G34.c b/src/cpu/amd/socket_G34/socket_G34.c new file mode 100644 index 0000000..1cac37c --- /dev/null +++ b/src/cpu/amd/socket_G34/socket_G34.c @@ -0,0 +1,18 @@ +/* + * 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 <device/device.h> + +struct chip_operations cpu_amd_socket_G34_ops = { + CHIP_NAME("socket G34") +}; diff --git a/src/mainboard/asus/kgpe-d16/Kconfig b/src/mainboard/asus/kgpe-d16/Kconfig new file mode 100644 index 0000000..ffbfd531 --- /dev/null +++ b/src/mainboard/asus/kgpe-d16/Kconfig @@ -0,0 +1,102 @@ +if BOARD_ASUS_KGPE_D16 + +config BOARD_SPECIFIC_OPTIONS + def_bool y + select CPU_AMD_SOCKET_G34_NON_AGESA + select DIMM_DDR3 + select DIMM_REGISTERED + # select QRANK_DIMM_SUPPORT + select DIMM_VOLTAGE_SET_SUPPORT + select NORTHBRIDGE_AMD_AMDFAM10 + select SOUTHBRIDGE_AMD_SR5650 + select SOUTHBRIDGE_AMD_SB700 + select SOUTHBRIDGE_AMD_SB700_DISABLE_ISA_DMA + select SOUTHBRIDGE_AMD_SUBTYPE_SP5100 + select SUPERIO_WINBOND_W83667HG_A + select PARALLEL_CPU_INIT + select HAVE_ROMSTAGE_CONSOLE_SPINLOCK + select HAVE_ROMSTAGE_NVRAM_CBFS_SPINLOCK + select HAVE_ROMSTAGE_MICROCODE_CBFS_SPINLOCK + select HAVE_OPTION_TABLE + select HAVE_CMOS_DEFAULT + select HAVE_PIRQ_TABLE + select HAVE_MP_TABLE + select HAVE_ACPI_TABLES + select SB_HT_CHAIN_UNITID_OFFSET_ONLY + select LIFT_BSP_APIC_ID + select BOARD_ROMSIZE_KB_2048 + select ENABLE_APIC_EXT_ID + select SPI_FLASH + select MAINBOARD_HAS_LPC_TPM + select DRIVERS_I2C_W83795 + select DRIVERS_ASPEED_AST2050 + select MAINBOARD_FORCE_NATIVE_VGA_INIT + select POWER_STATE_DEFAULT_ON_AFTER_FAILURE + select IPMI_KCS + +config MAINBOARD_DIR + string + default "asus/kgpe-d16" + +config BOOTBLOCK_MAINBOARD_INIT + string + default "mainboard/asus/kgpe-d16/bootblock.c" + +config DCACHE_RAM_BASE + hex + default 0xc2000 + +config DCACHE_RAM_SIZE + hex + default 0x1e000 + +config APIC_ID_OFFSET + hex + default 0x0 + +config MAINBOARD_PART_NUMBER + string + default "KGPE-D16" + +config HW_MEM_HOLE_SIZEK + hex + default 0x100000 + +config MAX_CPUS + int + default 32 + +# 2 (internal) processors per G34 socket +config MAX_PHYSICAL_CPUS + int + default 4 + +config HT_CHAIN_UNITID_BASE + hex + default 0x0 + +config HT_CHAIN_END_UNITID_BASE + hex + default 0x20 + +config IRQ_SLOT_COUNT + int + default 13 + +config SOUTHBRIDGE_AMD_SB700_SATA_PORT_COUNT_BITFIELD + hex + default 0x3f + +config ONBOARD_VGA_IS_PRIMARY + bool + default y + +config VGA_BIOS_ID + string + default "1a03,2000" + +config MAX_REBOOT_CNT + int + default 10 + +endif # BOARD_ASUS_KGPE_D16 diff --git a/src/mainboard/asus/kgpe-d16/Kconfig.name b/src/mainboard/asus/kgpe-d16/Kconfig.name new file mode 100644 index 0000000..bdfa31a --- /dev/null +++ b/src/mainboard/asus/kgpe-d16/Kconfig.name @@ -0,0 +1,2 @@ +config BOARD_ASUS_KGPE_D16 + bool "KGPE-D16" diff --git a/src/mainboard/asus/kgpe-d16/Makefile.inc b/src/mainboard/asus/kgpe-d16/Makefile.inc new file mode 100644 index 0000000..91d4b39 --- /dev/null +++ b/src/mainboard/asus/kgpe-d16/Makefile.inc @@ -0,0 +1,16 @@ +# +# 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. +# + +romstage-y += resourcemap.c + +ramstage-y += get_bus_conf.c diff --git a/src/mainboard/asus/kgpe-d16/acpi_tables.c b/src/mainboard/asus/kgpe-d16/acpi_tables.c new file mode 100644 index 0000000..53622ba --- /dev/null +++ b/src/mainboard/asus/kgpe-d16/acpi_tables.c @@ -0,0 +1,103 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2010 Advanced Micro Devices, Inc. + * Copyright (C) 2015 Timothy Pearson tpearson@raptorengineeringinc.com, Raptor Engineering + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * 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/acpi.h> +#include <arch/ioapic.h> +#include <device/pci.h> +#include <device/pci_ops.h> +#include <cpu/amd/amdfam10_sysconf.h> + +unsigned long acpi_fill_madt(unsigned long current) +{ + struct device *dev; + u32 dword; + u32 gsi_base = 0; + uint32_t apicid_sp5100; + uint32_t apicid_sr5650; + /* create all subtables for processors */ + current = acpi_create_madt_lapics(current); + + if (CONFIG(ENABLE_APIC_EXT_ID) && (CONFIG_APIC_ID_OFFSET > 0)) + apicid_sp5100 = 0x0; + else + apicid_sp5100 = 0x20; + apicid_sr5650 = apicid_sp5100 + 1; + + /* Write SB700 IOAPIC, only one */ + current += acpi_create_madt_ioapic((acpi_madt_ioapic_t *) current, apicid_sp5100, + IO_APIC_ADDR, gsi_base); + /* IOAPIC on rs5690 */ + gsi_base += 24; /* SB700 has 24 IOAPIC entries. */ + dev = pcidev_on_root(0, 0); + if (dev) { + pci_write_config32(dev, 0xF8, 0x1); + dword = pci_read_config32(dev, 0xFC) & 0xfffffff0; + current += acpi_create_madt_ioapic((acpi_madt_ioapic_t *) current, apicid_sr5650, + dword, gsi_base); + } + + /* bus, source, gsirq, flags */ + current += acpi_create_madt_irqoverride((acpi_madt_irqoverride_t *) + current, 0, 0, 2, 0); + current += acpi_create_madt_irqoverride((acpi_madt_irqoverride_t *) + current, 0, 9, 9, 0xf); + + /* create all subtables for processors */ + current += acpi_create_madt_lapic_nmi((acpi_madt_lapic_nmi_t *)current, 0xff, 0, 1); + /* 1: LINT1 connect to NMI */ + + return current; +} + +unsigned long acpi_fill_ivrs_ioapic(acpi_ivrs_t *ivrs, unsigned long current) +{ + uint8_t *p; + + uint32_t apicid_sp5100; + uint32_t apicid_sr5650; + + if (CONFIG(ENABLE_APIC_EXT_ID) && (CONFIG_APIC_ID_OFFSET > 0)) + apicid_sp5100 = 0x0; + else + apicid_sp5100 = 0x20; + apicid_sr5650 = apicid_sp5100 + 1; + + /* Describe NB IOAPIC */ + p = (uint8_t *)current; + p[0] = 0x48; /* Entry type */ + p[1] = 0; /* Device */ + p[2] = 0; /* Bus */ + p[3] = 0x0; /* Data */ + p[4] = apicid_sr5650; /* IOAPIC ID */ + p[5] = 0x1; /* Device 0 Function 1 */ + p[6] = 0x0; /* Northbridge bus */ + p[7] = 0x1; /* Variety */ + current += 8; + + /* Describe SB IOAPIC */ + p = (uint8_t *)current; + p[0] = 0x48; /* Entry type */ + p[1] = 0; /* Device */ + p[2] = 0; /* Bus */ + p[3] = 0xd7; /* Data */ + p[4] = apicid_sp5100; /* IOAPIC ID */ + p[5] = 0x14 << 3; /* Device 0x14 Function 0 */ + p[6] = 0x0; /* Southbridge bus */ + p[7] = 0x1; /* Variety */ + current += 8; + + return current; +} diff --git a/src/mainboard/asus/kgpe-d16/board_info.txt b/src/mainboard/asus/kgpe-d16/board_info.txt new file mode 100644 index 0000000..e69d31a --- /dev/null +++ b/src/mainboard/asus/kgpe-d16/board_info.txt @@ -0,0 +1,5 @@ +Category: server +ROM package: DIP-8 +ROM protocol: SPI +ROM socketed: y +Flashrom support: y diff --git a/src/mainboard/asus/kgpe-d16/bootblock.c b/src/mainboard/asus/kgpe-d16/bootblock.c new file mode 100644 index 0000000..543ffed --- /dev/null +++ b/src/mainboard/asus/kgpe-d16/bootblock.c @@ -0,0 +1,52 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2015 Timothy Pearson tpearson@raptorengineeringinc.com, Raptor Engineering + * Copyright (C) 2014 Edward O'Callaghan eocallaghan@alterapraxis.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; 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. + */ + +#include <device/pci_ops.h> +#include <pc80/mc146818rtc.h> + +void bootblock_mainboard_init(void) +{ + uint8_t recovery_enabled; + unsigned char addr; + unsigned char byte; + + bootblock_northbridge_init(); + bootblock_southbridge_init(); + + /* Recovery jumper is connected to SP5100 GPIO61, and clears the GPIO when placed in the Recovery position */ + byte = pci_io_read_config8(PCI_DEV(0, 0x14, 0), 0x56); + byte |= 0x1 << 4; /* Set GPIO61 to input mode */ + pci_io_write_config8(PCI_DEV(0, 0x14, 0), 0x56, byte); + recovery_enabled = (!(pci_io_read_config8(PCI_DEV(0, 0x14, 0), 0x57) & 0x1)); + if (recovery_enabled) { +#if CONFIG(USE_OPTION_TABLE) + /* Clear NVRAM checksum */ + for (addr = LB_CKS_RANGE_START; addr <= LB_CKS_RANGE_END; addr++) { + cmos_write(0x0, addr); + } + + /* Set fallback boot */ + byte = cmos_read(RTC_BOOT_BYTE); + byte &= 0xfc; + cmos_write(byte, RTC_BOOT_BYTE); +#else + /* FIXME + * Figure out how to recover if the option table is not available + */ +#endif + } +} diff --git a/src/mainboard/asus/kgpe-d16/cmos.default b/src/mainboard/asus/kgpe-d16/cmos.default new file mode 100644 index 0000000..7c496a5 --- /dev/null +++ b/src/mainboard/asus/kgpe-d16/cmos.default @@ -0,0 +1,30 @@ +debug_level=Debug +multi_core=Enable +slow_cpu=off +compute_unit_siblings=Enable +iommu=Enable +nmi=Disable +hypertransport_speed_limit=Auto +max_mem_clock=DDR3-1600 +minimum_memory_voltage=1.5V +dimm_spd_checksum=Enforce +ECC_memory=Enable +ECC_redirection=Enable +ecc_scrub_rate=1.28us +interleave_chip_selects=Enable +interleave_nodes=Disable +interleave_memory_channels=Enable +cpu_c_states=Enable +cpu_cc6_state=Enable +cpu_core_boost=Enable +sata_ahci_mode=Enable +sata_alpm=Disable +maximum_p_state_limit=0xf +probe_filter=Auto +l3_cache_partitioning=Disable +ieee1394_controller=Enable +gart=Enable +ehci_async_data_cache=Enable +experimental_memory_speed_boost=Disable +power_on_after_fail=On +boot_option=Fallback diff --git a/src/mainboard/asus/kgpe-d16/cmos.layout b/src/mainboard/asus/kgpe-d16/cmos.layout new file mode 100644 index 0000000..1c8d466 --- /dev/null +++ b/src/mainboard/asus/kgpe-d16/cmos.layout @@ -0,0 +1,150 @@ +## +## This file is part of the coreboot project. +## +## Copyright (C) 2015 Timothy Pearson tpearson@raptorengineeringinc.com, Raptor Engineering +## Copyright (C) 2007 AMD +## Written by Yinghai Lu yinghailu@amd.com for 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; 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. +## + +entries + +0 384 r 0 reserved_memory +384 1 e 4 boot_option +388 4 h 0 reboot_counter +393 3 r 0 unused +#394 7 unused +401 1 e 1 interleave_chip_selects +402 1 e 1 interleave_nodes +403 1 e 1 interleave_memory_channels +404 4 e 8 max_mem_clock +408 1 e 2 multi_core +412 4 e 6 debug_level +416 5 e 10 ecc_scrub_rate +440 4 e 9 slow_cpu +444 1 e 1 nmi +445 1 e 1 gart +446 2 e 3 power_on_after_fail +456 1 e 1 ECC_memory +457 1 e 1 ECC_redirection +458 4 e 11 hypertransport_speed_limit +462 2 e 12 minimum_memory_voltage +464 1 e 2 compute_unit_siblings +465 1 e 1 cpu_c_states +466 1 e 1 cpu_cc6_state +467 1 e 1 sata_ahci_mode +468 1 e 1 sata_alpm +#469 4 unused +473 2 e 13 dimm_spd_checksum +475 1 e 14 probe_filter +476 1 e 1 l3_cache_partitioning +477 1 e 1 ieee1394_controller +478 1 e 1 iommu +479 1 e 1 cpu_core_boost +480 1 e 2 ehci_async_data_cache +481 1 e 1 experimental_memory_speed_boost +482 1 r 0 allow_spd_nvram_cache_restore +483 4 h 0 maximum_p_state_limit +728 256 h 0 user_data +984 16 h 0 check_sum +# Reserve the extended AMD configuration registers +1000 24 r 0 amd_reserved + + + +enumerations + +#ID value text +1 0 Disable +1 1 Enable +2 0 Enable +2 1 Disable +3 0 Off +3 1 On +3 2 Last +4 0 Fallback +4 1 Normal +6 0 Emergency +6 1 Alert +6 2 Critical +6 3 Error +6 4 Warning +6 5 Notice +6 6 Information +6 7 Debug +6 8 Spew +8 0 DDR3-1866 +8 1 DDR3-1600 +8 2 DDR3-1333 +8 3 DDR3-1066 +8 4 DDR3-800 +8 5 DDR3-667 +9 0 off +9 1 87.5% +9 2 75.0% +9 3 62.5% +9 4 50.0% +9 5 37.5% +9 6 25.0% +9 7 12.5% +10 0 Disabled +10 1 40ns +10 2 80ns +10 3 160ns +10 4 320ns +10 5 640ns +10 6 1.28us +10 7 2.56us +10 8 5.12us +10 9 10.2us +10 10 20.5us +10 11 41us +10 12 81.9us +10 13 163.8us +10 14 327.7us +10 15 655.4us +10 16 1.31ms +10 17 2.62ms +10 18 5.24ms +10 19 10.49ms +10 20 20.97ms +10 21 42ms +10 22 84ms +11 0 Auto +11 1 3.2GHz +11 2 3.0GHz +11 3 2.8GHz +11 4 2.6GHz +11 5 2.4GHz +11 6 2.2GHz +11 7 2.0GHz +11 8 1.8GHz +11 9 1.6GHz +11 10 1.4GHz +11 11 1.2GHz +11 12 1.0GHz +11 13 800MHz +11 14 600MHz +11 15 500MHz +12 0 1.5V +12 1 1.35V +12 2 1.25V +12 3 1.15V +13 0 Enforce +13 1 Ignore +13 2 Override +14 0 Disable +14 1 Auto + +checksums + +checksum 392 983 984 diff --git a/src/mainboard/asus/kgpe-d16/devicetree.cb b/src/mainboard/asus/kgpe-d16/devicetree.cb new file mode 100644 index 0000000..31bd3e3 --- /dev/null +++ b/src/mainboard/asus/kgpe-d16/devicetree.cb @@ -0,0 +1,259 @@ +chip northbridge/amd/amdfam10/root_complex # Root complex + device cpu_cluster 0 on # (L)APIC cluster + chip cpu/amd/socket_F_1207 # CPU socket + device lapic 0 on end # Local APIC of the CPU + end + end + device domain 0 on # PCI domain + subsystemid 0x1043 0x8163 inherit + chip northbridge/amd/amdfam10 # Northbridge / RAM controller + register "maximum_memory_capacity" = "0x4000000000" # 256GB + device pci 18.0 on end # Link 0 == LDT 0 + device pci 18.0 on end # Link 1 == LDT 1 + device pci 18.0 on end # Link 2 == LDT 2 + device pci 18.0 on # Link 3 == LDT 3 [SB on link 3] + chip southbridge/amd/sr5650 # Primary southbridge + device pci 0.0 on end # HT Root Complex 0x9600 + device pci 0.1 on end # CLKCONFIG + device pci 0.2 on end # IOMMU + device pci 2.0 on # PCIE P2P bridge 0x9603 (GPP1 Port0) + # Slot # PCI E 1 / PCI E 2 + end + device pci 3.0 off end # PCIE P2P bridge 0x960b (GPP1 Port1) + device pci 4.0 on # PCIE P2P bridge 0x9604 (GPP3a Port0) + # PIKE SAS + end + device pci 5.0 off end # PCIE P2P bridge 0x9605 (GPP3a Port1) + device pci 6.0 off end # PCIE P2P bridge 0x9606 (GPP3a Port2) + device pci 7.0 off end # PCIE P2P bridge 0x9607 (GPP3a Port3) + device pci 8.0 off end # NB/SB Link P2P bridge + device pci 9.0 on # Bridge (GPP3a Port4) + # Onboard # NIC A + end + device pci a.0 on # Bridge (GPP3a Port5) + # Onboard # NIC B + end + device pci b.0 on # Bridge (GPP2 Port0) + # Slot # PCI E 4 + end + device pci c.0 on # Bridge (GPP2 Port1) + # Slot # PCI E 5 + end + device pci d.0 on # Bridge (GPP3b Port0) + # Slot # PCI E 3 + end + register "gpp1_configuration" = "0" # Configuration 16:0 default + register "gpp2_configuration" = "1" # Configuration 8:8 + register "gpp3a_configuration" = "2" # Configuration 4:1:1:0:0:0 + register "port_enable" = "0x3f1c" # Enable all ports except 0, 1, 5, 6, and 7 + register "pcie_settling_time" = "1000000" # Allow PIKE to be detected / configured + end + chip southbridge/amd/sb700 # Secondary southbridge + device pci 11.0 on end # SATA + device pci 12.0 on end # USB + device pci 12.1 on end # USB + device pci 12.2 on end # USB + device pci 13.0 on end # USB + device pci 13.1 on end # USB + device pci 13.2 on end # USB + device pci 14.0 on # SM + chip drivers/generic/generic # DIMM n-0-0-0 + device i2c 50 on end + end + chip drivers/generic/generic # DIMM n-0-0-1 + device i2c 51 on end + end + chip drivers/generic/generic # DIMM n-0-1-0 + device i2c 52 on end + end + chip drivers/generic/generic # DIMM n-0-1-1 + device i2c 53 on end + end + chip drivers/generic/generic # DIMM n-1-0-0 + device i2c 54 on end + end + chip drivers/generic/generic # DIMM n-1-0-1 + device i2c 55 on end + end + chip drivers/generic/generic # DIMM n-1-1-0 + device i2c 56 on end + end + chip drivers/generic/generic # DIMM n-1-1-1 + device i2c 57 on end + end + chip drivers/i2c/w83795 + register "fanin_ctl1" = "0xff" # Enable monitoring of FANIN1 - FANIN8 + register "fanin_ctl2" = "0x00" # Connect FANIN11 - FANIN14 to alternate functions + register "temp_ctl1" = "0x2a" # Enable monitoring of DTS, VSEN12, and VSEN13 + register "temp_ctl2" = "0x01" # Enable monitoring of TD1/TR1 + register "temp_dtse" = "0x03" # Enable DTS1 and DTS2 + register "volt_ctl1" = "0xff" # Enable monitoring of VSEN1 - VSEN8 + register "volt_ctl2" = "0xf7" # Enable monitoring of VSEN9 - VSEN11, 3VDD, 3VSB, and VBAT + register "temp1_fan_select" = "0x00" # All fans to manual mode (no dependence on Temp1) + register "temp2_fan_select" = "0x00" # All fans to manual mode (no dependence on Temp2) + register "temp3_fan_select" = "0x00" # All fans to manual mode (no dependence on Temp3) + register "temp4_fan_select" = "0x00" # All fans to manual mode (no dependence on Temp4) + register "temp5_fan_select" = "0x00" # All fans to manual mode (no dependence on Temp5) + register "temp6_fan_select" = "0x00" # All fans to manual mode (no dependence on Temp6) + register "temp1_source_select" = "0x00" # Use TD1/TR1 as data source for Temp1 + register "temp2_source_select" = "0x00" # Use TD2/TR2 as data source for Temp2 + register "temp3_source_select" = "0x00" # Use TD3/TR3 as data source for Temp3 + register "temp4_source_select" = "0x00" # Use TD4/TR4 as data source for Temp4 + register "temp5_source_select" = "0x00" # Use TR5 as data source for Temp5 + register "temp6_source_select" = "0x00" # Use TR6 as data source for Temp6 + register "tr1_critical_temperature" = "85" # Set TD1/TR1 critical temperature to 85°C + register "tr1_critical_hysteresis" = "80" # Set TD1/TR1 critical hysteresis temperature to 80°C + register "tr1_warning_temperature" = "70" # Set TD1/TR1 warning temperature to 70°C + register "tr1_warning_hysteresis" = "65" # Set TD1/TR1 warning hysteresis temperature to 65°C + register "dts_critical_temperature" = "85" # Set DTS (CPU) critical temperature to 85°C + register "dts_critical_hysteresis" = "80" # Set DTS (CPU) critical hysteresis temperature to 80°C + register "dts_warning_temperature" = "70" # Set DTS (CPU) warning temperature to 70°C + register "dts_warning_hysteresis" = "65" # Set DTS (CPU) warning hysteresis temperature to 65°C + register "temp1_critical_temperature" = "80" # Set Temp1 critical temperature to 80°C + register "temp2_critical_temperature" = "80" # Set Temp1 critical temperature to 80°C + register "temp3_critical_temperature" = "80" # Set Temp1 critical temperature to 80°C + register "temp4_critical_temperature" = "80" # Set Temp1 critical temperature to 80°C + register "temp5_critical_temperature" = "80" # Set Temp1 critical temperature to 80°C + register "temp6_critical_temperature" = "80" # Set Temp1 critical temperature to 80°C + register "temp1_target_temperature" = "80" # Set Temp1 target temperature to 80°C + register "temp2_target_temperature" = "80" # Set Temp1 target temperature to 80°C + register "temp3_target_temperature" = "80" # Set Temp1 target temperature to 80°C + register "temp4_target_temperature" = "80" # Set Temp1 target temperature to 80°C + register "temp5_target_temperature" = "80" # Set Temp1 target temperature to 80°C + register "temp6_target_temperature" = "80" # Set Temp1 target temperature to 80°C + register "fan1_nonstop" = "7" # Set Fan 1 minimum speed + register "fan2_nonstop" = "7" # Set Fan 2 minimum speed + register "fan3_nonstop" = "7" # Set Fan 3 minimum speed + register "fan4_nonstop" = "7" # Set Fan 4 minimum speed + register "fan5_nonstop" = "7" # Set Fan 5 minimum speed + register "fan6_nonstop" = "7" # Set Fan 6 minimum speed + register "fan7_nonstop" = "7" # Set Fan 7 minimum speed + register "fan8_nonstop" = "7" # Set Fan 8 minimum speed + register "default_speed" = "100" # All fans to full speed on power up + register "fan1_duty" = "100" # Fan 1 to full speed + register "fan2_duty" = "100" # Fan 2 to full speed + register "fan3_duty" = "100" # Fan 3 to full speed + register "fan4_duty" = "100" # Fan 4 to full speed + register "fan5_duty" = "100" # Fan 5 to full speed + register "fan6_duty" = "100" # Fan 6 to full speed + register "fan7_duty" = "100" # Fan 7 to full speed + register "fan8_duty" = "100" # Fan 8 to full speed + register "vcore1_high_limit_mv" = "1500" # VCORE1 (Node 0) high limit to 1.5V + register "vcore1_low_limit_mv" = "900" # VCORE1 (Node 0) low limit to 0.9V + register "vcore2_high_limit_mv" = "1500" # VCORE2 (Node 1) high limit to 1.5V + register "vcore2_low_limit_mv" = "900" # VCORE2 (Node 1) low limit to 0.9V + register "vsen3_high_limit_mv" = "1600" # VSEN1 (Node 0 RAM voltage) high limit to 1.6V + register "vsen3_low_limit_mv" = "1100" # VSEN1 (Node 0 RAM voltage) low limit to 1.1V + register "vsen4_high_limit_mv" = "1600" # VSEN2 (Node 1 RAM voltage) high limit to 1.6V + register "vsen4_low_limit_mv" = "1100" # VSEN2 (Node 1 RAM voltage) low limit to 1.1V + register "vsen5_high_limit_mv" = "1250" # VSEN5 (Node 0 HT link voltage) high limit to 1.25V + register "vsen5_low_limit_mv" = "1150" # VSEN5 (Node 0 HT link voltage) low limit to 1.15V + register "vsen6_high_limit_mv" = "1250" # VSEN6 (Node 1 HT link voltage) high limit to 1.25V + register "vsen6_low_limit_mv" = "1150" # VSEN6 (Node 1 HT link voltage) low limit to 1.15V + register "vsen7_high_limit_mv" = "1250" # VSEN7 (Northbridge core voltage) high limit to 1.25V + register "vsen7_low_limit_mv" = "1050" # VSEN7 (Northbridge core voltage) low limit to 1.05V + register "vsen8_high_limit_mv" = "1900" # VSEN8 (+1.8V) high limit to 1.9V + register "vsen8_low_limit_mv" = "1700" # VSEN8 (+1.8V) low limit to 1.7V + register "vsen9_high_limit_mv" = "1250" # VSEN9 (+1.2V) high limit to 1.25V + register "vsen9_low_limit_mv" = "1150" # VSEN9 (+1.2V) low limit to 1.15V + register "vsen10_high_limit_mv" = "1150" # VSEN10 (+1.1V) high limit to 1.15V + register "vsen10_low_limit_mv" = "1050" # VSEN10 (+1.1V) low limit to 1.05V + register "vsen11_high_limit_mv" = "1625" # VSEN11 (5VSB, scaling factor ~3.2) high limit to 5.2V + register "vsen11_low_limit_mv" = "1500" # VSEN11 (5VSB, scaling factor ~3.2) low limit to 4.8V + register "vsen12_high_limit_mv" = "1083" # VSEN12 (+12V, scaling factor ~12) high limit to 13V + register "vsen12_low_limit_mv" = "917" # VSEN12 (+12V, scaling factor ~12) low limit to 11V + register "vsen13_high_limit_mv" = "1625" # VSEN13 (+5V, scaling factor ~3.2) high limit to 5.2V + register "vsen13_low_limit_mv" = "1500" # VSEN13 (+5V, scaling factor ~3.2) low limit to 4.8V + register "vdd_high_limit_mv" = "3500" # 3VDD high limit to 3.5V + register "vdd_low_limit_mv" = "3100" # 3VDD low limit to 3.1V + register "vsb_high_limit_mv" = "3500" # 3VSB high limit to 3.5V + register "vsb_low_limit_mv" = "3100" # 3VSB low limit to 3.1V + register "vbat_high_limit_mv" = "3500" # VBAT (+3V) high limit to 3.5V + register "vbat_low_limit_mv" = "2500" # VBAT (+3V) low limit to 2.5V + register "smbus_aux" = "1" # Device located on auxiliary SMBUS controller + device i2c 0x2f on end + end + end + device pci 14.1 on end # IDE 0x439c + device pci 14.2 on end # HDA 0x4383 (ASUS MIO add-on card) + device pci 14.3 on # LPC 0x439d (SMBUS primary controller) + chip superio/winbond/w83667hg-a # Super I/O + device pnp 2e.0 off end # FDC; Not available on the KGPE-D16 + device pnp 2e.1 off end # LPT1; Not available on the KGPE-D16 + device pnp 2e.2 on # COM1 + io 0x60 = 0x3f8 + irq 0x70 = 4 + end + device pnp 2e.3 on # COM2 + io 0x60 = 0x2f8 + irq 0x70 = 3 + end + device pnp 2e.5 on # PS/2 keyboard & mouse + io 0x60 = 0x60 + io 0x62 = 0x64 + irq 0x70 = 1 + irq 0x72 = 12 + end + device pnp 2e.106 off end # SPI: Not available on the KGPE-D16 + device pnp 2e.107 off end # GIPO6 + device pnp 2e.207 off end # GIPO7 + device pnp 2e.307 off end # GIPO8 + device pnp 2e.407 off end # GIPO9 + device pnp 2e.8 off end # WDT + device pnp 2e.108 off end # GPIO 1 + device pnp 2e.9 off end # GPIO2 + device pnp 2e.109 off end # GPIO3 + device pnp 2e.209 off end # GPIO4 + device pnp 2e.309 off end # GPIO5 + device pnp 2e.a on end # ACPI + device pnp 2e.b on # HW Monitor + io 0x60 = 0x290 + # IRQ purposefully not assigned to prevent lockups + end + device pnp 2e.c off end # PECI + device pnp 2e.d off end # VID_BUSSEL + device pnp 2e.f off end # GPIO_PP_OD + end + chip drivers/pc80/tpm + device pnp 4e.0 on end # TPM module + end + chip drivers/ipmi # BMC KCS + device pnp ca2.0 on end + end + end + device pci 14.4 on # Bridge + device pci 1.0 on end # VGA + device pci 2.0 on end # FireWire + device pci 3.0 on # Slot + # Slot # PCI 0 + end + end + device pci 14.5 on end # USB OHCI2 0x4399 + end + end + device pci 18.1 on end + device pci 18.2 on end + device pci 18.3 on end + device pci 18.4 on end + device pci 18.5 on end + device pci 19.0 on end # Socket 0 node 1 + device pci 19.1 on end + device pci 19.2 on end + device pci 19.3 on end + device pci 19.4 on end + device pci 19.5 on end + device pci 1a.0 on end # Socket 1 node 0 + device pci 1a.1 on end + device pci 1a.2 on end + device pci 1a.3 on end + device pci 1a.4 on end + device pci 1a.5 on end + device pci 1b.0 on end # Socket 1 node 1 + device pci 1b.1 on end + device pci 1b.2 on end + device pci 1b.3 on end + device pci 1b.4 on end + device pci 1b.5 on end + end + end +end diff --git a/src/mainboard/asus/kgpe-d16/dsdt.asl b/src/mainboard/asus/kgpe-d16/dsdt.asl new file mode 100644 index 0000000..efb67a5 --- /dev/null +++ b/src/mainboard/asus/kgpe-d16/dsdt.asl @@ -0,0 +1,809 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2015 Timothy Pearson tpearson@raptorengineeringinc.com, Raptor Engineering + * Copyright (C) 2005 - 2012 Advanced Micro Devices, Inc. + * Copyright (C) 2007-2009 coresystems GmbH + * Copyright (C) 2004 Nick Barker Nick.Barker9@btinternet.com + * Copyright (C) 2007, 2008 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. + */ + +/* + * WARNING: Sleep/Wake is a work in progress and is still somewhat flaky! + * Everything else does to the best of my knowledge... (T.P. 01/26/2015) + */ + +/* + * ISA portions taken from QEMU acpi-dsdt.dsl. + */ + +/* + * PCI link routing templates taken from ck804.asl and modified for this board + */ + +#include <arch/acpi.h> +DefinitionBlock ( + "DSDT.AML", /* Output filename */ + "DSDT", /* Signature */ + 0x02, /* DSDT Revision, needs to be 2 or higher for 64bit */ + OEM_ID, + ACPI_TABLE_CREATOR, + 0x00000001 /* OEM Revision */ + ) +{ + #include <northbridge/amd/amdfam10/amdfam10_util.asl> + #include <southbridge/amd/sr5650/acpi/sr5650.asl> + + /* Some global data */ + Name(OSVR, 3) /* Assume nothing. WinXp = 1, Vista = 2, Linux = 3, WinCE = 4 */ + Name(OSV, Ones) /* Assume nothing */ + Name(PICM, One) /* Assume APIC */ + + /* HPET enable */ + Name (HPTE, 0x1) + + #include <southbridge/amd/common/acpi/sleepstates.asl> + + /* The _PIC method is called by the OS to choose between interrupt + * routing via the i8259 interrupt controller or the APIC. + * + * _PIC is called with a parameter of 0 for i8259 configuration and + * with a parameter of 1 for Local Apic/IOAPIC configuration. + */ + Method (_PIC, 1, Serialized) { + If (Arg0) + { + _SB.CIRQ() + } + Store (Arg0, PICM) + } + + /* _PR CPU0 is dynamically supplied by SSDT */ + /* CPU objects and _PSS entries are dynamically supplied by SSDT */ + + Scope(_GPE) { /* Start Scope GPE */ + /* General event 3 */ + Method(_L03) { + /* Level-Triggered GPE */ + Notify(_SB.PWRB, 0x02) /* NOTIFY_DEVICE_WAKE */ + } + + /* General event 4 */ + Method(_L04) { + /* Level-Triggered GPE */ + Notify (_SB.PCI0.PBR0, 0x02) /* NOTIFY_DEVICE_WAKE */ + Notify (_SB.PWRB, 0x02) /* NOTIFY_DEVICE_WAKE */ + } + + /* Keyboard controller PME# */ + Method(_L08) { + /* Level-Triggered GPE */ + Notify(_SB.PCI0.LPC.PS2K, 0x02) /* NOTIFY_DEVICE_WAKE */ + Notify(_SB.PCI0.LPC.PS2M, 0x02) /* NOTIFY_DEVICE_WAKE */ + Notify(_SB.PWRB, 0x02) /* NOTIFY_DEVICE_WAKE */ + } + + /* USB controller PME# */ + Method(_L0B) { + /* Level-Triggered GPE */ + Notify (_SB.PCI0.USB0, 0x02) /* NOTIFY_DEVICE_WAKE */ + Notify (_SB.PCI0.USB1, 0x02) /* NOTIFY_DEVICE_WAKE */ + Notify (_SB.PCI0.USB2, 0x02) /* NOTIFY_DEVICE_WAKE */ + Notify (_SB.PCI0.USB3, 0x02) /* NOTIFY_DEVICE_WAKE */ + Notify (_SB.PCI0.USB4, 0x02) /* NOTIFY_DEVICE_WAKE */ + Notify (_SB.PCI0.USB5, 0x02) /* NOTIFY_DEVICE_WAKE */ + Notify (_SB.PCI0.USB6, 0x02) /* NOTIFY_DEVICE_WAKE */ + Notify (_SB.PWRB, 0x02) /* NOTIFY_DEVICE_WAKE */ + } + + /* GPIO0 or GEvent8 event */ + Method(_L18) { + /* Level-Triggered GPE */ + Notify (_SB.PCI0.PCE1, 0x02) /* NOTIFY_DEVICE_WAKE */ + Notify (_SB.PCI0.NICA, 0x02) /* NOTIFY_DEVICE_WAKE */ + Notify (_SB.PCI0.NICB, 0x02) /* NOTIFY_DEVICE_WAKE */ + Notify (_SB.PCI0.PCE4, 0x02) /* NOTIFY_DEVICE_WAKE */ + Notify (_SB.PCI0.PCE5, 0x02) /* NOTIFY_DEVICE_WAKE */ + Notify (_SB.PCI0.PCE3, 0x02) /* NOTIFY_DEVICE_WAKE */ + } + + } /* End Scope GPE */ + + /* Root of the bus hierarchy */ + Scope (_SB) + { + /* Top southbridge PCI device (SR5690 + SP5100) */ + Device (PCI0) + { + /* BUS0 root bus */ + + Name (_HID, EisaId ("PNP0A08")) /* PCI-e root bus (SR5690) */ + Name (_CID, EisaId ("PNP0A03")) /* PCI root bus (SP5100) */ + Name (_ADR, 0x00180001) + Name (_UID, 0x00) + + Name (HCIN, 0x00) // HC1 + + Method (_BBN, 0, NotSerialized) + { + Return (GBUS (GHCN(HCIN), GHCL(HCIN))) + } + + /* Operating System Capabilities Method */ + Method(_OSC,4) + { + /* Let OS control everything */ + Return (Arg3) + } + + External (BUSN) + External (MMIO) + External (PCIO) + External (SBLK) + External (TOM1) + External (HCLK) + External (SBDN) + External (HCDN) + External (CBST) + + /* PCI Routing Tables */ + Name (PR00, Package () { + /* PIC */ + /* Top southbridge device (SR5690) */ + /* HT Link */ + Package (0x04) { 0x0000FFFF, 0x00, LNKA, 0x00 }, + + /* PCI-E Slot 1 (Bridge) */ + Package (0x04) { 0x0002FFFF, 0x00, LNKE, 0x00 }, + + /* NIC A (Bridge) */ + Package (0x04) { 0x0009FFFF, 0x00, LNKF, 0x00 }, + + /* NIC B (Bridge) */ + Package (0x04) { 0x000AFFFF, 0x00, LNKG, 0x00 }, + + /* PCI-E Slot 4 (Bridge) */ + Package (0x04) { 0x000BFFFF, 0x00, LNKG, 0x00 }, + + /* PCI-E Slot 5 (Bridge) */ + Package (0x04) { 0x000CFFFF, 0x00, LNKG, 0x00 }, + + /* PCI-E Slot 3 (Bridge) */ + Package (0x04) { 0x000DFFFF, 0x00, LNKG, 0x00 }, + + /* Bottom southbridge device (SP5100) */ + /* SATA 0 */ + Package (0x04) { 0x0011FFFF, 0x00, LNKG, 0x00 }, + + /* USB 0 */ + Package (0x04) { 0x0012FFFF, 0x00, LNKA, 0x00 }, + Package (0x04) { 0x0012FFFF, 0x01, LNKB, 0x00 }, + Package (0x04) { 0x0012FFFF, 0x02, LNKC, 0x00 }, + Package (0x04) { 0x0012FFFF, 0x03, LNKD, 0x00 }, + + /* USB 1 */ + Package (0x04) { 0x0013FFFF, 0x00, LNKC, 0x00 }, + Package (0x04) { 0x0013FFFF, 0x01, LNKD, 0x00 }, + Package (0x04) { 0x0013FFFF, 0x02, LNKA, 0x00 }, + Package (0x04) { 0x0013FFFF, 0x03, LNKB, 0x00 }, + + /* SMBUS / IDE / LPC / VGA / FireWire / PCI Slot 0 */ + Package (0x04) { 0x0014FFFF, 0x00, LNKA, 0x00 }, + Package (0x04) { 0x0014FFFF, 0x01, LNKB, 0x00 }, + Package (0x04) { 0x0014FFFF, 0x02, LNKC, 0x00 }, + Package (0x04) { 0x0014FFFF, 0x03, LNKD, 0x00 }, + }) + + Name (AR00, Package () { + /* APIC */ + /* Top southbridge device (SR5690) */ + /* HT Link */ + Package (0x04) { 0x0000FFFF, 0x00, 0x00, 55 }, + + /* PCI-E Slot 1 (Bridge) */ + Package (0x04) { 0x0002FFFF, 0x00, 0x00, 52 }, + + /* NIC A (Bridge) */ + Package (0x04) { 0x0009FFFF, 0x00, 0x00, 53 }, + + /* NIC B (Bridge) */ + Package (0x04) { 0x000AFFFF, 0x00, 0x00, 54 }, + + /* PCI-E Slot 4 (Bridge) */ + Package (0x04) { 0x000BFFFF, 0x00, 0x00, 54 }, + + /* PCI-E Slot 5 (Bridge) */ + Package (0x04) { 0x000CFFFF, 0x00, 0x00, 54 }, + + /* PCI-E Slot 3 (Bridge) */ + Package (0x04) { 0x000DFFFF, 0x00, 0x00, 54 }, + + /* Bottom southbridge device (SP5100) */ + /* SATA 0 */ + Package (0x04) { 0x0011FFFF, 0x00, 0x00, 22 }, + + /* USB 0 */ + Package (0x04) { 0x0012FFFF, 0x00, 0x00, 16 }, + Package (0x04) { 0x0012FFFF, 0x01, 0x00, 17 }, + Package (0x04) { 0x0012FFFF, 0x02, 0x00, 18 }, + Package (0x04) { 0x0012FFFF, 0x03, 0x00, 19 }, + + /* USB 1 */ + Package (0x04) { 0x0013FFFF, 0x00, 0x00, 18 }, + Package (0x04) { 0x0013FFFF, 0x01, 0x00, 19 }, + Package (0x04) { 0x0013FFFF, 0x02, 0x00, 16 }, + Package (0x04) { 0x0013FFFF, 0x03, 0x00, 17 }, + + /* SMBUS / IDE / LPC / VGA / FireWire / PCI Slot 0 */ + Package (0x04) { 0x0014FFFF, 0x00, 0x00, 16 }, + Package (0x04) { 0x0014FFFF, 0x01, 0x00, 17 }, + Package (0x04) { 0x0014FFFF, 0x02, 0x00, 18 }, + Package (0x04) { 0x0014FFFF, 0x03, 0x00, 19 }, + }) + + Name (PR01, Package () { + /* PIC */ + Package (0x04) { 0x1FFFF, 0x00, LNKF, 0x00 }, + Package (0x04) { 0x2FFFF, 0x00, LNKE, 0x00 }, + Package (0x04) { 0x3FFFF, 0x00, LNKG, 0x00 }, + Package (0x04) { 0x3FFFF, 0x01, LNKH, 0x00 }, + Package (0x04) { 0x3FFFF, 0x02, LNKE, 0x00 }, + Package (0x04) { 0x3FFFF, 0x03, LNKF, 0x00 }, + }) + + Name (AR01, Package () { + /* APIC */ + Package (0x04) { 0x1FFFF, 0x00, 0x00, 21 }, + Package (0x04) { 0x2FFFF, 0x00, 0x00, 20 }, + Package (0x04) { 0x3FFFF, 0x00, 0x00, 22 }, + Package (0x04) { 0x3FFFF, 0x01, 0x00, 23 }, + Package (0x04) { 0x3FFFF, 0x02, 0x00, 20 }, + Package (0x04) { 0x3FFFF, 0x03, 0x00, 21 }, + }) + + Name (PR02, Package () { + /* PIC */ + Package (0x04) { 0xFFFF, 0x00, LNKA, 0x00 }, + Package (0x04) { 0xFFFF, 0x01, LNKB, 0x00 }, + Package (0x04) { 0xFFFF, 0x02, LNKC, 0x00 }, + Package (0x04) { 0xFFFF, 0x03, LNKD, 0x00 }, + }) + + Name (AR02, Package () { + /* APIC */ + Package (0x04) { 0xFFFF, 0x00, 0x00, 24 }, + Package (0x04) { 0xFFFF, 0x01, 0x00, 25 }, + Package (0x04) { 0xFFFF, 0x02, 0x00, 26 }, + Package (0x04) { 0xFFFF, 0x03, 0x00, 27 }, + }) + + Name (PR03, Package () { + /* PIC */ + Package (0x04) { 0xFFFF, 0x00, LNKE, 0x00 }, + Package (0x04) { 0xFFFF, 0x01, LNKF, 0x00 }, + Package (0x04) { 0xFFFF, 0x02, LNKG, 0x00 }, + Package (0x04) { 0xFFFF, 0x03, LNKH, 0x00 }, + }) + + Name (AR03, Package () { + /* APIC */ + Package (0x04) { 0xFFFF, 0x00, 0x00, 44 }, + Package (0x04) { 0xFFFF, 0x01, 0x00, 45 }, + Package (0x04) { 0xFFFF, 0x02, 0x00, 46 }, + Package (0x04) { 0xFFFF, 0x03, 0x00, 47 }, + }) + + Name (PR04, Package () { + /* PIC */ + Package (0x04) { 0xFFFF, 0x00, LNKA, 0x00 }, + Package (0x04) { 0xFFFF, 0x01, LNKB, 0x00 }, + Package (0x04) { 0xFFFF, 0x02, LNKC, 0x00 }, + Package (0x04) { 0xFFFF, 0x03, LNKD, 0x00 }, + }) + + Name (AR04, Package () { + /* APIC */ + Package (0x04) { 0xFFFF, 0x00, 0x00, 48 }, + Package (0x04) { 0xFFFF, 0x01, 0x00, 49 }, + Package (0x04) { 0xFFFF, 0x02, 0x00, 50 }, + Package (0x04) { 0xFFFF, 0x03, 0x00, 51 }, + }) + + Name (PR05, Package () { + /* PIC */ + Package (0x04) { 0xFFFF, 0x00, LNKH, 0x00 }, + Package (0x04) { 0xFFFF, 0x01, LNKE, 0x00 }, + Package (0x04) { 0xFFFF, 0x02, LNKF, 0x00 }, + Package (0x04) { 0xFFFF, 0x03, LNKG, 0x00 }, + }) + + Name (AR05, Package () { + /* APIC */ + Package (0x04) { 0xFFFF, 0x00, 0x00, 47 }, + Package (0x04) { 0xFFFF, 0x01, 0x00, 44 }, + Package (0x04) { 0xFFFF, 0x02, 0x00, 45 }, + Package (0x04) { 0xFFFF, 0x03, 0x00, 46 }, + }) + + Name (PR06, Package () { + /* PIC */ + Package (0x04) { 0xFFFF, 0x00, LNKA, 0x00 }, + Package (0x04) { 0xFFFF, 0x01, LNKB, 0x00 }, + Package (0x04) { 0xFFFF, 0x02, LNKC, 0x00 }, + Package (0x04) { 0xFFFF, 0x03, LNKD, 0x00 }, + }) + + Name (AR06, Package () { + /* APIC */ + Package (0x04) { 0xFFFF, 0x00, 0x00, 32 }, + Package (0x04) { 0xFFFF, 0x01, 0x00, 33 }, + Package (0x04) { 0xFFFF, 0x02, 0x00, 34 }, + Package (0x04) { 0xFFFF, 0x03, 0x00, 35 }, + }) + + Name (PR07, Package () { + /* PIC */ + Package (0x04) { 0xFFFF, 0x00, LNKE, 0x00 }, + Package (0x04) { 0xFFFF, 0x01, LNKF, 0x00 }, + Package (0x04) { 0xFFFF, 0x02, LNKG, 0x00 }, + Package (0x04) { 0xFFFF, 0x03, LNKH, 0x00 }, + }) + + Name (AR07, Package () { + /* APIC */ + Package (0x04) { 0xFFFF, 0x00, 0x00, 36 }, + Package (0x04) { 0xFFFF, 0x01, 0x00, 37 }, + Package (0x04) { 0xFFFF, 0x02, 0x00, 38 }, + Package (0x04) { 0xFFFF, 0x03, 0x00, 39 }, + }) + + Name (PR08, Package () { + /* PIC */ + Package (0x04) { 0xFFFF, 0x00, LNKA, 0x00 }, + Package (0x04) { 0xFFFF, 0x01, LNKB, 0x00 }, + Package (0x04) { 0xFFFF, 0x02, LNKC, 0x00 }, + Package (0x04) { 0xFFFF, 0x03, LNKD, 0x00 }, + }) + + Name (AR08, Package () { + /* APIC */ + Package (0x04) { 0xFFFF, 0x00, 0x00, 40 }, + Package (0x04) { 0xFFFF, 0x01, 0x00, 41 }, + Package (0x04) { 0xFFFF, 0x02, 0x00, 42 }, + Package (0x04) { 0xFFFF, 0x03, 0x00, 43 }, + }) + + /* PCI Resource Tables */ + + /* PCI Resource Settings Access */ + Method (_CRS, 0, Serialized) + { + Name (BUF0, ResourceTemplate () + { + IO (Decode16, + 0x0CF8, // Address Range Minimum + 0x0CF8, // Address Range Maximum + 0x01, // Address Alignment + 0x08, // Address Length + ) + WordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange, + 0x0000, // Address Space Granularity + 0x0000, // Address Range Minimum + 0x0CF7, // Address Range Maximum + 0x0000, // Address Translation Offset + 0x0CF8, // Address Length + ,, , TypeStatic) + }) + /* Methods below use SSDT to get actual MMIO regs + The IO ports are from 0xd00, optionally an VGA, + otherwise the info from MMIO is used. + _SB.GXXX(node, link) + */ + Concatenate (_SB.GMEM (0x00, _SB.PCI0.SBLK), BUF0, Local1) + Concatenate (_SB.GIOR (0x00, _SB.PCI0.SBLK), Local1, Local2) + Concatenate (_SB.GWBN (0x00, _SB.PCI0.SBLK), Local2, Local3) + Return (Local3) + } + + /* PCI Routing Table Access */ + Method (_PRT, 0, NotSerialized) { + If (PICM) { + Return (AR00) + } Else { + Return (PR00) + } + } + + /* 0:11.0 SP5100 SATA 0 */ + Device(SAT0) + { + Name (_ADR, 0x00110000) // _ADR: Address + Name(_PRW, Package () {0x05, 0x04}) // Wake from S1-S4 + #include <southbridge/amd/sb700/acpi/sata.asl> + } + + /* 0:12.0 SP5100 USB 0 */ + Device (USB0) + { + Name (_ADR, 0x00120000) // _ADR: Address + Name(_PRW, Package () {0x05, 0x04}) // Wake from S1-S4 + } + + /* 0:12.1 SP5100 USB 1 */ + Device (USB1) + { + Name (_ADR, 0x00120001) // _ADR: Address + Name(_PRW, Package () {0x05, 0x04}) // Wake from S1-S4 + } + + /* 0:12.2 SP5100 USB 2 */ + Device (USB2) + { + Name (_ADR, 0x00120002) // _ADR: Address + Name(_PRW, Package () {0x05, 0x04}) // Wake from S1-S4 + } + + /* 0:13.0 SP5100 USB 3 */ + Device (USB3) + { + Name (_ADR, 0x00130000) // _ADR: Address + Name(_PRW, Package () {0x05, 0x04}) // Wake from S1-S4 + } + + /* 0:13.1 SP5100 USB 4 */ + Device (USB4) + { + Name (_ADR, 0x00130001) // _ADR: Address + Name(_PRW, Package () {0x05, 0x04}) // Wake from S1-S4 + } + + /* 0:13.2 SP5100 USB 5 */ + Device (USB5) + { + Name (_ADR, 0x00130002) // _ADR: Address + Name(_PRW, Package () {0x05, 0x04}) // Wake from S1-S4 + } + + /* 0:14.1 SP5100 IDE Controller */ + Device (IDEC) + { + Name (_ADR, 0x00140001) // _ADR: Address + Name(_PRW, Package () {0x05, 0x04}) // Wake from S1-S4 + #include <southbridge/amd/sb700/acpi/ide.asl> + } + + /* 0:14.3 SP5100 LPC */ + Device (LPC) { + Name (_HID, EisaId ("PNP0A05")) + Name (_ADR, 0x00140003) + + /* Real Time Clock Device */ + Device(RTC0) { + Name(_HID, EISAID("PNP0B00")) /* AT Real Time Clock (not PIIX4 compatible) */ + Name(BUF0, ResourceTemplate() { + IO(Decode16, 0x0070, 0x0070, 0x01, 0x02) + }) + Name(BUF1, ResourceTemplate() { + IRQNoFlags() { 8 } + IO(Decode16, 0x0070, 0x0070, 0x01, 0x02) + }) + Method(_CRS, 0) { + If(HPTE) { + Return(BUF0) + } + Return(BUF1) + } + } + + Device(TMR) { /* Timer */ + Name(_HID,EISAID("PNP0100")) /* System Timer */ + Name(BUF0, ResourceTemplate() { + IO(Decode16, 0x0040, 0x0040, 0x01, 0x04) + }) + Name(BUF1, ResourceTemplate() { + IRQNoFlags() { 0 } + IO(Decode16, 0x0040, 0x0040, 0x01, 0x04) + }) + Method(_CRS, 0) { + If(HPTE) { + Return(BUF0) + } + Return(BUF1) + } + } + + Device(SPKR) { /* Speaker */ + Name(_HID,EISAID("PNP0800")) /* AT style speaker */ + Name(_CRS, ResourceTemplate() { + IO(Decode16, 0x0061, 0x0061, 0, 1) + }) + } + + Device(PIC) { + Name(_HID,EISAID("PNP0000")) /* AT Interrupt Controller */ + Name(_CRS, ResourceTemplate() { + IRQNoFlags() { 2 } + IO(Decode16,0x0020, 0x0020, 0, 2) + IO(Decode16,0x00A0, 0x00A0, 0, 2) + }) + } + + Device(MAD) { /* 8257 DMA */ + Name(_HID,EISAID("PNP0200")) /* Hardware Device ID */ + Name(_CRS, ResourceTemplate() { + DMA(Compatibility,BusMaster,Transfer8){4} + IO(Decode16, 0x0000, 0x0000, 0x10, 0x10) + IO(Decode16, 0x0081, 0x0081, 0x01, 0x03) + IO(Decode16, 0x0087, 0x0087, 0x01, 0x01) + IO(Decode16, 0x0089, 0x0089, 0x01, 0x03) + IO(Decode16, 0x008F, 0x008F, 0x01, 0x01) + IO(Decode16, 0x00C0, 0x00C0, 0x10, 0x20) + }) /* End Name(_SB.PCI0.LpcIsaBr.MAD._CRS) */ + } + + Device(COPR) { + Name(_HID,EISAID("PNP0C04")) /* Math Coprocessor */ + Name(_CRS, ResourceTemplate() { + IO(Decode16, 0x00F0, 0x00F0, 0, 0x10) + IRQNoFlags(){13} + }) + } + + #include <superio/winbond/w83667hg-a/ps2_controller.asl> + + /* UART 1 */ + Device (URT1) + { + Name (_HID, EisaId ("PNP0501")) // "PNP0501" for UART + Name(_PRW, Package () {0x03, 0x04}) // Wake from S1-S4 + Method (_STA, 0, NotSerialized) + { + Return (0x0f) // Always enable + } + Name (_PRS, ResourceTemplate() { + StartDependentFn(0, 1) { + IO(Decode16, 0x3f8, 0x3f8, 0x8, 0x8) + IRQNoFlags() { 4 } + } EndDependentFn() + }) + Method (_CRS, 0) + { + Return(ResourceTemplate() { + IO(Decode16, 0x3f8, 0x3f8, 0x8, 0x8) + IRQNoFlags() { 4 } + }) + } + } + + /* UART 2 */ + Device (URT2) + { + Name (_HID, EisaId ("PNP0501")) // "PNP0501" for UART + Name(_PRW, Package () {0x03, 0x04}) // Wake from S1-S4 + Method (_STA, 0, NotSerialized) + { + Return (0x0f) // Always enable + } + Name (_PRS, ResourceTemplate() { + StartDependentFn(0, 1) { + IO(Decode16, 0x2f8, 0x2f8, 0x8, 0x8) + IRQNoFlags() { 3 } + } EndDependentFn() + }) + Method (_CRS, 0) + { + Return(ResourceTemplate() { + IO(Decode16, 0x2f8, 0x2f8, 0x8, 0x8) + IRQNoFlags() { 3 } + }) + } + } + } + + /* High Precision Event Timer */ + Device (HPET) + { + Name (_HID, EisaId ("PNP0103")) + Name (CRS, ResourceTemplate () + { + Memory32Fixed(ReadOnly, 0xFED00000, 0x00000400) + }) + Method (_STA, 0) + { + If(HPTE) { + Return (0x0F) + } + Return (0x0) + } + Method(_CRS, 0) + { + Return(CRS) + } + } + + /* 0:14.4 PCI Bridge */ + Device (PBR0) + { + Name (_ADR, 0x00140004) // _ADR: Address + Name(_PRW, Package () {0x11, 0x04}) // Wake from S1-S4 + Method (_PRT, 0, NotSerialized) // _PRT: PCI Routing Table + { + If (PICM) { + Return (AR01) + } Else { + Return (PR01) + } + } + Device (SLT1) + { + Name (_ADR, 0xFFFF) // _ADR: Address + Name(_PRW, Package () {0x0B, 0x04}) // Wake from S1-S4 + } + } + + /* 0:14.5 SP5100 USB 6 */ + Device (USB6) + { + Name (_ADR, 0x00140005) // _ADR: Address + Name(_PRW, Package () {0x05, 0x04}) // Wake from S1-S4 + } + + /* 2:00.0 PCIe x16 */ + Device (PCE1) + { + Name (_ADR, 0x00020000) // _ADR: Address + Name(_PRW, Package () {0x11, 0x04}) // Wake from S1-S4 + Method (_PRT, 0, NotSerialized) // _PRT: PCI Routing Table + { + If (PICM) { + Return (AR02) + } Else { + Return (PR02) + } + } + Device (SLT1) + { + Name (_ADR, 0xFFFF) // _ADR: Address + Name(_PRW, Package () {0x0B, 0x04}) // Wake from S1-S4 + } + } + + /* 1:00.0 PIKE */ + Device (PIKE) + { + Name (_ADR, 0x00040000) // _ADR: Address + Name(_PRW, Package () {0x11, 0x04}) // Wake from S1-S4 + Method (_PRT, 0, NotSerialized) // _PRT: PCI Routing Table + { + If (PICM) { + Return (AR03) + } Else { + Return (PR03) + } + } + Device (SLT1) + { + Name (_ADR, 0xFFFF) // _ADR: Address + Name(_PRW, Package () {0x0B, 0x04}) // Wake from S1-S4 + } + } + + /* 3:00.0 PCIe NIC A */ + Device (NICA) + { + Name (_ADR, 0x00090000) // _ADR: Address + Name(_PRW, Package () {0x11, 0x04}) // Wake from S1-S4 + Method (_PRT, 0, NotSerialized) // _PRT: PCI Routing Table + { + If (PICM) { + Return (AR04) + } Else { + Return (PR04) + } + } + Device (BDC1) + { + Name (_ADR, Zero) // _ADR: Address + } + } + + /* 4:00.0 PCIe NIC B */ + Device (NICB) + { + Name (_ADR, 0x000A0000) // _ADR: Address + Name(_PRW, Package () {0x11, 0x04}) // Wake from S1-S4 + Method (_PRT, 0, NotSerialized) // _PRT: PCI Routing Table + { + If (PICM) { + Return (AR05) + } Else { + Return (PR05) + } + } + Device (BDC2) + { + Name (_ADR, Zero) // _ADR: Address + } + } + + /* 5:00.0 PCIe x16 */ + Device (PCE4) + { + Name (_ADR, 0x000B0000) // _ADR: Address + Name(_PRW, Package () {0x11, 0x04}) // Wake from S1-S4 + Method (_PRT, 0, NotSerialized) // _PRT: PCI Routing Table + { + If (PICM) { + Return (AR06) + } Else { + Return (PR06) + } + } + Device (SLT1) + { + Name (_ADR, 0xFFFF) // _ADR: Address + Name(_PRW, Package () {0x0B, 0x04}) // Wake from S1-S4 + } + } + + /* 6:00.0 PCIe x16 */ + Device (PCE5) + { + Name (_ADR, 0x000C0000) // _ADR: Address + Name(_PRW, Package () {0x11, 0x04}) // Wake from S1-S4 + Method (_PRT, 0, NotSerialized) // _PRT: PCI Routing Table + { + If (PICM) { + Return (AR07) + } Else { + Return (PR07) + } + } + Device (SLT1) + { + Name (_ADR, 0xFFFF) // _ADR: Address + Name(_PRW, Package () {0x0B, 0x04}) // Wake from S1-S4 + } + } + + /* 7:00.0 PCIe x16 */ + Device (PCE3) + { + Name (_ADR, 0x000D0000) // _ADR: Address + Name(_PRW, Package () {0x11, 0x04}) // Wake from S1-S4 + Method (_PRT, 0, NotSerialized) // _PRT: PCI Routing Table + { + If (PICM) { + Return (AR08) + } Else { + Return (PR08) + } + } + Device (SLT1) + { + Name (_ADR, 0xFFFF) // _ADR: Address + Name(_PRW, Package () {0x0B, 0x04}) // Wake from S1-S4 + } + } + } + + Device (PWRB) { /* Start Power button device */ + Name(_HID, EISAID("PNP0C0C")) + Name(_UID, 0xAA) + Name(_PRW, Package () {3, 0x04}) /* wake from S1-S4 */ + Name(_STA, 0x0B) /* sata is invisible */ + } + } + +#include "acpi/pm_ctrl.asl" + +} diff --git a/src/mainboard/asus/kgpe-d16/mainboard.c b/src/mainboard/asus/kgpe-d16/mainboard.c new file mode 100644 index 0000000..a03953b --- /dev/null +++ b/src/mainboard/asus/kgpe-d16/mainboard.c @@ -0,0 +1,114 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2015 Timothy Pearson tpearson@raptorengineeringinc.com, Raptor Engineering + * 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; 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 <device/device.h> +#include <device/pci.h> +#include <device/mmio.h> +#include <device/pci_ops.h> +#include <cpu/x86/msr.h> +#include <cpu/amd/mtrr.h> +#include <device/pci_def.h> +#include <southbridge/amd/sb700/sb700.h> +#include <southbridge/amd/sr5650/cmn.h> + +void set_pcie_reset(void) +{ + struct device *pcie_core_dev; + + pcie_core_dev = pcidev_on_root(0, 0); + set_htiu_enable_bits(pcie_core_dev, 0xA8, 0xFFFFFFFF, 0x28282828); + set_htiu_enable_bits(pcie_core_dev, 0xA9, 0x000000FF, 0x00000028); +} + +void set_pcie_dereset(void) +{ + struct device *pcie_core_dev; + + pcie_core_dev = pcidev_on_root(0, 0); + set_htiu_enable_bits(pcie_core_dev, 0xA8, 0xFFFFFFFF, 0x6F6F6F6F); + set_htiu_enable_bits(pcie_core_dev, 0xA9, 0x000000FF, 0x0000006F); +} + +/************************************************* +* enable the dedicated function in kgpe-d16 board. +* This function is called earlier than sr5650_enable. +*************************************************/ + +static void mainboard_enable(struct device *dev) +{ + printk(BIOS_INFO, "Mainboard KGPE-D16 Enable. dev=0x%p\n", dev); + + msr_t msr, msr2; + + /* TOP_MEM: the top of DRAM below 4G */ + msr = rdmsr(TOP_MEM); + printk + (BIOS_INFO, "%s, TOP MEM: msr.lo = 0x%08x, msr.hi = 0x%08x\n", + __func__, msr.lo, msr.hi); + + /* TOP_MEM2: the top of DRAM above 4G */ + msr2 = rdmsr(TOP_MEM2); + printk + (BIOS_INFO, "%s, TOP MEM2: msr2.lo = 0x%08x, msr2.hi = 0x%08x\n", + __func__, msr2.lo, msr2.hi); + + set_pcie_dereset(); + /* get_ide_dma66(); */ +} + +/* override the default SATA PHY setup */ +void sb7xx_51xx_setup_sata_phys(struct device *dev) +{ + /* RPR7.6.1 Program the PHY Global Control to 0x2C00 */ + pci_write_config16(dev, 0x86, 0x2c00); + + /* RPR7.6.2 SATA GENI PHY ports setting */ + pci_write_config32(dev, 0x88, 0x01b48016); + pci_write_config32(dev, 0x8c, 0x01b48016); + pci_write_config32(dev, 0x90, 0x01b48016); + pci_write_config32(dev, 0x94, 0x01b48016); + pci_write_config32(dev, 0x98, 0x01b48016); + pci_write_config32(dev, 0x9c, 0x01b48016); + + /* RPR7.6.3 SATA GEN II PHY port setting for port [0~5]. */ + pci_write_config16(dev, 0xa0, 0xa07a); + pci_write_config16(dev, 0xa2, 0xa07a); + pci_write_config16(dev, 0xa4, 0xa07a); + pci_write_config16(dev, 0xa6, 0xa07a); + pci_write_config16(dev, 0xa8, 0xa07a); + pci_write_config16(dev, 0xaa, 0xa07a); +} + +/* override the default SATA port setup */ +void sb7xx_51xx_setup_sata_port_indication(void *sata_bar5) +{ + uint32_t dword; + + /* RPR7.9 Program Port Indication Registers */ + dword = read32(sata_bar5 + 0xf8); + dword &= ~(0x3f << 12); /* All ports are iSATA */ + dword &= ~0x3f; + write32(sata_bar5 + 0xf8, dword); + + dword = read32(sata_bar5 + 0xfc); + dword &= ~(0x1 << 20); /* No eSATA ports are present */ + write32(sata_bar5 + 0xfc, dword); +} + +struct chip_operations mainboard_ops = { + .enable_dev = mainboard_enable, +}; diff --git a/src/mainboard/asus/kgpe-d16/spd_notes.txt b/src/mainboard/asus/kgpe-d16/spd_notes.txt new file mode 100644 index 0000000..d944229 --- /dev/null +++ b/src/mainboard/asus/kgpe-d16/spd_notes.txt @@ -0,0 +1,46 @@ +==================================================================================================== +SPD mux +==================================================================================================== + SP5100 + GPIO 60 GPIO 59 +Disabled 0 0 +Normal operation 0 1 +CPU 0 SPD 1 0 +CPU 1 SPD 1 1 + +==================================================================================================== +W83795 +==================================================================================================== + +Sensor mappings: +CPU_FAN1: FAN1 +CPU_FAN2: FAN2 +FRNT_FAN1: FAN3 +FRNT_FAN2: FAN4 +FRNT_FAN3: FAN5 +FRNT_FAN4: FAN6 +FRNT_FAN5: FAN7 +REAR_FAN1: FAN8 + +==================================================================================================== +Other hardware +==================================================================================================== + +RECOVERY1 middle pin is connected to southbridge (AMD SP5100) GPIO 61 +Normal is HIGH, recovery is LOW. + ++12VSB is generated using a charge pump attached to pin 7 of PU24 (APW7145). + +The +12VSB standby voltage to each bank of DIMMs is switched by a bank of small FETs located close to each RAM power regulator control chip. +The +12V primary voltage (lower left pin of the FET placed on the upper left of the control chip of the second node) is also connected to the 232GE located near the PCI slot. + +The control line running to the gates of the +12VSB control FETs is connected to the +5VSB power for the USB ports. +That line in turn is connected to +5VSB via the lone P06P03G PMOS transistor on the reverse side of the board, near the center on the lower half. +The gate of that transistor is connected via a resistor to the source of the P06P03G PMOS transistor located adjacent to the unpopulated SMA clock header. +The gate of that transistor is connected directly to the drain of the small FET directly below it. +After that, there's a cascade of small FETs and resistors in that region, eventually leading to SuperIO pin 81. + +SuperIO pin 81 (VSBGATE#) enables the standby voltage rails when set LOW. +VSBGATE# is reset on every assertion of PWRGOOD. + +Setting SuperIO LDN 9 CRF4 bits 1 or 0 (or both) to 0 disables NICB. diff --git a/src/northbridge/amd/amdfam10/Kconfig b/src/northbridge/amd/amdfam10/Kconfig new file mode 100644 index 0000000..6435887 --- /dev/null +++ b/src/northbridge/amd/amdfam10/Kconfig @@ -0,0 +1,145 @@ +## +## This file is part of the coreboot project. +## +## Copyright (C) 2015 Timothy Pearson tpearson@raptorengineeringinc.com, Raptor Engineering +## 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_AMDFAM10 + bool + select HAVE_DEBUG_RAM_SETUP + select HAVE_DEBUG_SMBUS + select HAVE_DEBUG_CAR + select HYPERTRANSPORT_PLUGIN_SUPPORT + select PCIEXP_ASPM + select PCIEXP_COMMON_CLOCK + select PCIEXP_CLK_PM + select PCIEXP_L1_SUB_STATE + select NO_RELOCATABLE_RAMSTAGE + +if NORTHBRIDGE_AMD_AMDFAM10 +config AGP_APERTURE_SIZE + hex + default 0x4000000 + +config HW_MEM_HOLE_SIZEK + hex + default 0x100000 + +config MMCONF_BASE_ADDRESS + hex + default 0xc0000000 + +config MMCONF_BUS_NUMBER + int + default 256 + +# TODO: Reservation for heap seems excessive +config HEAP_SIZE + hex + default 0xc0000 + +config BOOTBLOCK_NORTHBRIDGE_INIT + string + default "northbridge/amd/amdfam10/bootblock.c" + +config SB_HT_CHAIN_UNITID_OFFSET_ONLY + bool + default n + +config HT_CHAIN_DISTRIBUTE + def_bool n + +config DIMM_DDR2 + bool + default n + +config DIMM_DDR3 + bool + default n + +config DIMM_REGISTERED + bool + default n + +config DIMM_VOLTAGE_SET_SUPPORT + bool + default n + +config S3_DATA_SIZE + int + default 32768 + depends on (HAVE_ACPI_RESUME) + +config S3_DATA_POS + hex + default 0x0 + depends on (HAVE_ACPI_RESUME) + +config SVI_HIGH_FREQ + bool + default n + help + Select this for boards with a Voltage Regulator able to operate + at 3.4 MHz in SVI mode. Ignored unless the AMD CPU is rev C3. + +menu "HyperTransport setup" + #could be implemented for K8 (NORTHBRIDGE_AMD_AMDK8) + depends on (NORTHBRIDGE_AMD_AMDFAM10) + +choice + prompt "HyperTransport downlink width" + default LIMIT_HT_DOWN_WIDTH_16 + help + This option sets the maximum permissible HyperTransport + downlink width. + + Use of this option will only limit the autodetected HT width. + It will not (and cannot) increase the width beyond the autodetected + limits. + + This is primarily used to work around poorly designed or laid out HT + traces on certain motherboards. + +config LIMIT_HT_DOWN_WIDTH_8 + bool "8 bits" +config LIMIT_HT_DOWN_WIDTH_16 + bool "16 bits" +endchoice + +choice + prompt "HyperTransport uplink width" + default LIMIT_HT_UP_WIDTH_16 + help + This option sets the maximum permissible HyperTransport + uplink width. + + Use of this option will only limit the autodetected HT width. + It will not (and cannot) increase the width beyond the autodetected + limits. + + This is primarily used to work around poorly designed or laid out HT + traces on certain motherboards. + +config LIMIT_HT_UP_WIDTH_8 + bool "8 bits" +config LIMIT_HT_UP_WIDTH_16 + bool "16 bits" +endchoice + +endmenu + +config MAX_REBOOT_CNT + int + default 6 + +endif # NORTHBRIDGE_AMD_AMDFAM10 diff --git a/src/northbridge/amd/amdfam10/Makefile.inc b/src/northbridge/amd/amdfam10/Makefile.inc new file mode 100644 index 0000000..787f444 --- /dev/null +++ b/src/northbridge/amd/amdfam10/Makefile.inc @@ -0,0 +1,34 @@ +ifeq ($(CONFIG_NORTHBRIDGE_AMD_AMDFAM10),y) + +subdirs-y += ../amdht +subdirs-y += ../amdmct/wrappers +subdirs-$(CONFIG_DIMM_DDR3) += ../amdmct/mct_ddr3 +subdirs-$(CONFIG_DIMM_DDR2) += ../amdmct/mct + +# Generic ROMSTAGE stuff +romstage-y += reset_test.c debug.c setup_resource_map.c raminit_sysinfo_in_ram.c +romstage-y += raminit_amdmct.c pci.c early_ht.c amdfam10_util.c + +# RAMSTAGE +ramstage-y += northbridge.c misc_control.c link_control.c nb_control.c +ramstage-y += amdfam10_util.c ht_config.c get_pci1234.c +ramstage-$(CONFIG_HAVE_ACPI_TABLES) += acpi.c + +# Enable this if you want to check the values of the PCI routing registers. +# Call show_all_routes() anywhere amdfam10.h is included. +#ramstage-y += util.c + +# Reserve 2x CONFIG_S3_DATA_SIZE to allow for random file placement +# (not respecting erase sector boundaries) within CBFS +$(obj)/coreboot_s3nv.rom: $(obj)/config.h + echo " S3 NVRAM $(CONFIG_S3_DATA_POS) (S3 storage area)" + # force C locale, so cygwin awk doesn't try to interpret the 0xff below as UTF-8 (or worse) + printf %d $(CONFIG_S3_DATA_SIZE) | LC_ALL=C awk '{for (i=0; i<$$1*2; i++) {printf "%c", 255}}' > $@.tmp + mv $@.tmp $@ + +cbfs-files-$(CONFIG_HAVE_ACPI_RESUME) += s3nv +s3nv-file := $(obj)/coreboot_s3nv.rom +s3nv-align := $(CONFIG_S3_DATA_SIZE) +s3nv-type := raw + +endif diff --git a/src/northbridge/amd/amdfam10/acpi.c b/src/northbridge/amd/amdfam10/acpi.c new file mode 100644 index 0000000..dc139ad --- /dev/null +++ b/src/northbridge/amd/amdfam10/acpi.c @@ -0,0 +1,351 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2015 Timothy Pearson tpearson@raptorengineeringinc.com, Raptor Engineering + * Copyright (C) 2007 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 <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/amdfam10_sysconf.h> +#include "amdfam10.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 + if (res->index > 0xf) /* Exclude MMIO resources, e.g. as set in northbridge.c amdfam10_domain_read_resources() */ + 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) +{ + /* Implement SLIT algorithm in BKDG Rev. 3.62 Section 2.3.6.1 + * Fill the first 8 bytes with the node number, + * then fill the next num*num byte with the distance, + * Distance entries vary with topology; the local node + * is always 10. + * + * Fully connected: + * Set all non-local nodes to 16 + * + * Partially connected; with probe filter: + * Set all non-local nodes to 10+(num_hops*6) + * + * Partially connected; without probe filter: + * Set all non-local nodes to 13 + * + * FIXME + * The partially connected cases are not implemented; + * once a means is found to detect partially connected + * topologies, implement the remaining cases. + */ + + 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] = 16; + } + } + + current += 8+nodes*nodes; + return current; +} + +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 */ + +} + +void northbridge_acpi_write_vars(struct device *device) +{ + /* + * If more than one physical CPU is installed, northbridge_acpi_write_vars() + * is called more than once and the resultant SSDT table is corrupted + * (duplicated entries). + * This prevents Linux from booting, with log messages like these: + * ACPI Error: [BUSN] Namespace lookup failure, AE_ALREADY_EXISTS (/dswload-353) + * ACPI Exception: AE_ALREADY_EXISTS, During name lookup/catalog (/psobject-222) + * followed by a slew of ACPI method failures and a hang when the invalid PCI + * resource entries are used. + * This routine prevents the SSDT table from being corrupted. + */ + static uint8_t ssdt_generated = 0; + if (ssdt_generated) + return; + ssdt_generated = 1; + + msr_t msr; + char pscope[] = "\_SB.PCI0"; + int i; + + acpigen_write_scope(pscope); + + acpigen_write_name("BUSN"); + acpigen_write_package(HC_NUMS); + for (i = 0; i < HC_NUMS; i++) { + acpigen_write_dword(sysconf.ht_c_conf_bus[i]); + } + // minus the opcode + acpigen_pop_len(); + + acpigen_write_name("MMIO"); + + acpigen_write_package(HC_NUMS * 4); + + for (i = 0; i<(HC_NUMS*2); i++) { // FIXME: change to more chain + acpigen_write_dword(sysconf.conf_mmio_addrx[i]); //base + acpigen_write_dword(sysconf.conf_mmio_addr[i]); //mask + } + // minus the opcode + acpigen_pop_len(); + + acpigen_write_name("PCIO"); + + acpigen_write_package(HC_NUMS * 2); + + for (i = 0; i < HC_NUMS; i++) { // FIXME: change to more chain + acpigen_write_dword(sysconf.conf_io_addrx[i]); + acpigen_write_dword(sysconf.conf_io_addr[i]); + } + + // minus the opcode + acpigen_pop_len(); + + acpigen_write_name_byte("SBLK", sysconf.sblk); + + 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); + + + acpigen_write_name_dword("SBDN", sysconf.sbdn); + + 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(0x00000000); + } + // minus the opcode + 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); + } + // minus the opcode + acpigen_pop_len(); + + acpigen_write_name_byte("CBB", CONFIG_CBB); + + u8 CBST, CBB2, CBS2; + + if (CONFIG_CBB == 0xff) { + CBST = (u8) (0x0f); + } else { + if ((sysconf.pci1234[0] >> 12) & 0xff) { //sb chain on other than bus 0 + CBST = (u8) (0x0f); + } else { + CBST = (u8) (0x00); + } + } + + acpigen_write_name_byte("CBST", CBST); + + if ((CONFIG_CBB == 0xff) && (sysconf.nodes > 32)) { + CBS2 = 0x0f; + CBB2 = (u8)(CONFIG_CBB-1); + } else { + CBS2 = 0x00; + CBB2 = 0x00; + } + + acpigen_write_name_byte("CBB2", CBB2); + acpigen_write_name_byte("CBS2", CBS2); + + //minus opcode + acpigen_pop_len(); +} + +unsigned long northbridge_write_acpi_tables(struct device *device, + unsigned long current, + struct acpi_rsdp *rsdp) +{ + acpi_srat_t *srat; + acpi_slit_t *slit; + + /* SRAT */ + current = ALIGN(current, 8); + printk(BIOS_DEBUG, "ACPI: * SRAT at %lx\n", current); + srat = (acpi_srat_t *) current; + acpi_create_srat(srat, acpi_fill_srat); + current += srat->header.length; + acpi_add_table(rsdp, srat); + + /* SLIT */ + current = ALIGN(current, 8); + printk(BIOS_DEBUG, "ACPI: * SLIT at %lx\n", current); + slit = (acpi_slit_t *) current; + acpi_create_slit(slit, acpi_fill_slit); + current += slit->header.length; + acpi_add_table(rsdp, slit); + + return current; +} diff --git a/src/northbridge/amd/amdfam10/bootblock.c b/src/northbridge/amd/amdfam10/bootblock.c new file mode 100644 index 0000000..f2d5f89 --- /dev/null +++ b/src/northbridge/amd/amdfam10/bootblock.c @@ -0,0 +1,22 @@ +/* + * 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 "northbridge/amd/amdfam10/early_ht.c" + +static void bootblock_northbridge_init(void) { + /* Nothing special needs to be done to find bus 0 */ + /* Allow the HT devices to be found */ + /* mov bsp to bus 0xff when > 8 nodes */ + set_bsp_node_CHtExtNodeCfgEn(); + enumerate_ht_chain(); +} diff --git a/src/northbridge/amd/amdfam10/chip.h b/src/northbridge/amd/amdfam10/chip.h new file mode 100644 index 0000000..daf429d --- /dev/null +++ b/src/northbridge/amd/amdfam10/chip.h @@ -0,0 +1,25 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2015 Timothy Pearson tpearson@raptorengineeringinc.com, Raptor Engineering + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _AMD_FAM10_CHIP_H_ +#define _AMD_FAM10_CHIP_H_ + +#include <stdint.h> + +struct northbridge_amd_amdfam10_config { + uint64_t maximum_memory_capacity; +}; + +#endif /* _AMD_FAM10_CHIP_H_ */ diff --git a/src/northbridge/amd/amdfam10/early_ht.c b/src/northbridge/amd/amdfam10/early_ht.c new file mode 100644 index 0000000..dc0f684 --- /dev/null +++ b/src/northbridge/amd/amdfam10/early_ht.c @@ -0,0 +1,176 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007 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 "early_ht.h" +#include <stdint.h> +#include <device/pci_ops.h> +#include <device/pci_def.h> + +// For SB HT chain only +// mmconf is not ready yet +void set_bsp_node_CHtExtNodeCfgEn(void) +{ +#if CONFIG(EXT_RT_TBL_SUPPORT) + u32 dword; + dword = pci_io_read_config32(PCI_DEV(0, 0x18, 0), 0x68); + dword |= (1<<27) | (1<<25); + /* CHtExtNodeCfgEn: coherent link extended node configuration enable, + Nodes[31:0] will be 0xff:[31:0], Nodes[63:32] will be 0xfe:[31:0] + ---- 32 nodes now only + It can be used even nodes less than 8 nodes. + We can have 8 more device on bus 0 in that case + */ + + /* CHtExtAddrEn */ + pci_io_write_config32(PCI_DEV(0, 0x18, 0), 0x68, dword); + // CPU on bus 0xff and 0xfe now. For now on we can use CONFIG_CBB and CONFIG_CDB. +#endif +} + +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 int next_unitid, last_unitid = 0; +#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 int real_last_unitid = 0; + u8 real_last_pos = 0; + int ht_dev_num = 0; // except host_bridge + u8 end_used = 0; +#endif + + next_unitid = CONFIG_HT_CHAIN_UNITID_BASE; + do { + u32 id; + u8 hdr_type, pos; + last_unitid = next_unitid; + + id = pci_io_read_config32(PCI_DEV(0,0,0), 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_io_read_config8(PCI_DEV(0,0,0), PCI_HEADER_TYPE); + pos = 0; + hdr_type &= 0x7f; + + if ((hdr_type == PCI_HEADER_TYPE_NORMAL) || + (hdr_type == PCI_HEADER_TYPE_BRIDGE)) + { + pos = pci_io_read_config8(PCI_DEV(0,0,0), PCI_CAPABILITY_LIST); + } + while (pos != 0) { + u8 cap; + cap = pci_io_read_config8(PCI_DEV(0,0,0), pos + PCI_CAP_LIST_ID); + if (cap == PCI_CAP_ID_HT) { + u16 flags; + /* Read and write and reread flags so the link + * direction bit is valid. + */ + flags = pci_io_read_config16(PCI_DEV(0,0,0), pos + PCI_CAP_FLAGS); + pci_io_write_config16(PCI_DEV(0,0,0), pos + PCI_CAP_FLAGS, flags); + flags = pci_io_read_config16(PCI_DEV(0,0,0), pos + PCI_CAP_FLAGS); + if ((flags >> 13) == 0) { + unsigned int count; + unsigned int ctrl, ctrl_off; + pci_devfn_t devx; + +#if CONFIG_HT_CHAIN_END_UNITID_BASE != 0x20 + if (next_unitid >= 0x18) { + 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 + #if !CONFIG_HT_CHAIN_END_UNITID_BASE + if (!next_unitid) + goto out; + #endif + flags &= ~0x1f; + flags |= next_unitid & 0x1f; + count = (flags >> 5) & 0x1f; + devx = PCI_DEV(0, next_unitid, 0); + next_unitid += count; + + pci_io_write_config16(PCI_DEV(0, 0, 0), pos + PCI_CAP_FLAGS, flags); + + /* Test for end of chain */ + ctrl_off = ((flags >> 10) & 1)? + PCI_HT_CAP_SLAVE_CTRL0 : PCI_HT_CAP_SLAVE_CTRL1; + + do { + ctrl = pci_io_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_io_write_config16(devx, pos + ctrl_off, ctrl); + ctrl = pci_io_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_io_read_config8(PCI_DEV(0, 0, 0), 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) { + u16 flags; + flags = pci_io_read_config16(PCI_DEV(0,real_last_unitid,0), real_last_pos + PCI_CAP_FLAGS); + flags &= ~0x1f; + flags |= CONFIG_HT_CHAIN_END_UNITID_BASE & 0x1f; + pci_io_write_config16(PCI_DEV(0, real_last_unitid, 0), real_last_pos + PCI_CAP_FLAGS, flags); + } +#endif + +#endif +} diff --git a/src/northbridge/amd/amdfam10/early_ht.h b/src/northbridge/amd/amdfam10/early_ht.h new file mode 100644 index 0000000..67476fd --- /dev/null +++ b/src/northbridge/amd/amdfam10/early_ht.h @@ -0,0 +1,21 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2016 Damien Zammit damien@zamaudio.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. + */ +#ifndef EARLY_HT_H +#define EARLY_HT_H + +void set_bsp_node_CHtExtNodeCfgEn(void); +void enumerate_ht_chain(void); + +#endif diff --git a/src/northbridge/amd/amdfam10/northbridge.c b/src/northbridge/amd/amdfam10/northbridge.c new file mode 100644 index 0000000..df1d947 --- /dev/null +++ b/src/northbridge/amd/amdfam10/northbridge.c @@ -0,0 +1,1928 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2016 Damien Zammit damien@zamaudio.com + * Copyright (C) 2015 - 2017 Timothy Pearson tpearson@raptorengineering.com, Raptor Engineering + * Copyright (C) 2007 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 <console/console.h> +#include <device/pci_ops.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 <smbios.h> +#include <cpu/cpu.h> +#include <delay.h> +#include <cpu/x86/lapic.h> +#include <cpu/x86/cache.h> +#include <cpu/amd/mtrr.h> +#include <cpu/amd/amdfam10_sysconf.h> +#include <cpu/amd/msr.h> +#include <cpu/amd/family_10h-family_15h/ram_calc.h> +#include <types.h> + +#if CONFIG(LOGICAL_CPUS) +#include <cpu/amd/multicore.h> +#include <pc80/mc146818rtc.h> +#endif + +#include "northbridge.h" +#include "amdfam10.h" +#include "ht_config.h" +#include "chip.h" + +#if CONFIG_HW_MEM_HOLE_SIZEK != 0 +#include <cpu/amd/model_10xxx_rev.h> +#endif + +#if CONFIG(DIMM_DDR3) +#include "../amdmct/mct_ddr3/s3utils.h" +#endif + +struct amdfam10_sysconf_t sysconf; +u8 pirq_router_bus; + +#define FX_DEVS NODE_NUMS +static struct device *__f0_dev[FX_DEVS]; +struct device *__f1_dev[FX_DEVS]; +static struct device *__f2_dev[FX_DEVS]; +static struct device *__f4_dev[FX_DEVS]; +static unsigned int fx_devs = 0; + +struct device *get_node_pci(u32 nodeid, u32 fn) +{ +#if NODE_NUMS + CONFIG_CDB >= 32 + if ((CONFIG_CDB + nodeid) < 32) { + return dev_find_slot(CONFIG_CBB, PCI_DEVFN(CONFIG_CDB + nodeid, fn)); + } else { + return dev_find_slot(CONFIG_CBB-1, PCI_DEVFN(CONFIG_CDB + nodeid - 32, fn)); + } + +#else + return dev_find_slot(CONFIG_CBB, PCI_DEVFN(CONFIG_CDB + nodeid, fn)); +#endif +} + +static void get_fx_devs(void) +{ + int i; + for (i = 0; i < FX_DEVS; i++) { + __f0_dev[i] = get_node_pci(i, 0); + __f1_dev[i] = get_node_pci(i, 1); + __f2_dev[i] = get_node_pci(i, 2); + __f4_dev[i] = get_node_pci(i, 4); + 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 int reg) +{ + if (fx_devs == 0) + get_fx_devs(); + return pci_read_config32(__f1_dev[0], reg); +} + +static void f1_write_config32(unsigned int 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); + } + } +} + +u32 amdfam10_nodeid(struct device *dev) +{ +#if NODE_NUMS == 64 + unsigned int busn; + busn = dev->bus->secondary; + if (busn != CONFIG_CBB) { + return (dev->path.pci.devfn >> 3) - CONFIG_CDB + 32; + } else { + return (dev->path.pci.devfn >> 3) - CONFIG_CDB; + } + +#else + return (dev->path.pci.devfn >> 3) - CONFIG_CDB; +#endif +} + +static void set_vga_enable_reg(u32 nodeid, u32 linkn) +{ + u32 val; + + val = 1 | (nodeid<<4) | (linkn<<12); + /* it will routing (1)mmio 0xa0000:0xbffff (2) io 0x3b0:0x3bb, + 0x3c0:0x3df */ + f1_write_config32(0xf4, val); + +} + +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 bus *parent = link->dev->bus; + u32 busses; + + if (mode == HT_ROUTE_SCAN) { + if (parent->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 &= ~(0xff << 8); + busses |= parent->secondary & 0xff; + if (mode == HT_ROUTE_CLOSE) + busses |= 0xff << 8; + else if (mode == HT_ROUTE_SCAN) + busses |= ((u32) link->secondary & 0xff) << 8; + else if (mode == HT_ROUTE_FINAL) + busses |= ((u32) link->secondary & 0xff) << 8; + pci_write_config32(link->dev, link->cap + 0x14, busses); + + if (mode == HT_ROUTE_FINAL) { + if (CONFIG(HT_CHAIN_DISTRIBUTE)) + parent->subordinate = ALIGN_UP(link->subordinate, 8) - 1; + else + parent->subordinate = link->subordinate; + } +} + +static void amd_g34_fixup(struct bus *link, struct device *dev) +{ + uint32_t nodeid = amdfam10_nodeid(dev); + uint8_t rev_gte_d = 0; + uint8_t dual_node = 0; + uint32_t f3xe8; + + if (cpuid_eax(0x80000001) >= 0x8) + /* Revision D or later */ + rev_gte_d = 1; + + if (rev_gte_d || is_fam15h()) { + f3xe8 = pci_read_config32(get_node_pci(0, 3), 0xe8); + + /* Check for dual node capability */ + if (f3xe8 & 0x20000000) + dual_node = 1; + + if (dual_node) { + /* Each G34 processor contains a defective HT link. + * See the BKDG Rev 3.62 section 2.7.1.5 for details. + */ + f3xe8 = pci_read_config32(get_node_pci(nodeid, 3), 0xe8); + uint8_t internal_node_number = ((f3xe8 & 0xc0000000) >> 30); + if (internal_node_number == 0) { + /* Node 0 */ + if (link->link_num == 6) /* Link 2 Sublink 1 */ + printk(BIOS_DEBUG, "amdfam10_scan_chain(): node %d (internal node ID %d): skipping defective HT link\n", nodeid, internal_node_number); + } else { + /* Node 1 */ + if (link->link_num == 5) /* Link 1 Sublink 1 */ + printk(BIOS_DEBUG, "amdfam10_scan_chain(): node %d (internal node ID %d): skipping defective HT link\n", nodeid, internal_node_number); + } + } + } +} + +static void amdfam10_scan_chain(struct bus *link) +{ + unsigned int next_unitid; + + /* See if there is an available configuration space mapping + * register in function 1. + */ + if (get_ht_c_index(link) >= 4) + 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); + + /* set the config map space */ + set_config_map_reg(link); + + /* 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); + + ht_route_link(link, HT_ROUTE_FINAL); + + /* We know the number of busses behind this bridge. Set the + * subordinate bus number to it's real value + */ + if (0) { + /* Clear the extend reg. */ + clear_config_map_reg(link); + } + + set_config_map_reg(link); + + store_ht_c_conf_bus(link); +} + +/* 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) & 7; + 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 link. */ + 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 amdfam10_scan_chains(struct device *dev) +{ + struct bus *link; + +#if CONFIG(CPU_AMD_SOCKET_G34_NON_AGESA) + if (is_fam15h()) { + uint8_t current_link_number = 0; + + for (link = dev->link_list; link; link = link->next) { + /* The following links have changed position in Fam15h G34 processors: + * Fam10 Fam15 + * Node 0 + * L3 --> L1 + * L0 --> L3 + * L1 --> L2 + * L2 --> L0 + * Node 1 + * L0 --> L0 + * L1 --> L3 + * L2 --> L1 + * L3 --> L2 + */ + if (link->link_num == 0) + link->link_num = 3; + else if (link->link_num == 1) + link->link_num = 2; + else if (link->link_num == 2) + link->link_num = 0; + else if (link->link_num == 3) + link->link_num = 1; + else if (link->link_num == 5) + link->link_num = 7; + else if (link->link_num == 6) + link->link_num = 5; + else if (link->link_num == 7) + link->link_num = 6; + + current_link_number++; + if (current_link_number > 3) + current_link_number = 0; + } + } +#endif + + /* Do sb ht chain at first, in case s2885 put sb chain (8131/8111) on link2, but put 8151 on link0 */ + trim_ht_chain(dev); + + for (link = dev->link_list; link; link = link->next) { + if (link->ht_link_up) { + if (CONFIG(CPU_AMD_MODEL_10XXX)) + amd_g34_fixup(link, dev); + amdfam10_scan_chain(link); + } + } +} + + +static int reg_useable(unsigned int reg, struct device *goal_dev, unsigned int goal_nodeid, + unsigned int goal_link) +{ + struct resource *res; + unsigned int 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 < 8); link++) { + res = probe_resource(dev, IOINDEX(0x1000 + 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 struct resource *amdfam10_find_iopair(struct device *dev, unsigned int nodeid, unsigned int link) +{ + struct resource *resource; + u32 free_reg, reg; + resource = 0; + free_reg = 0; + for (reg = 0xc0; reg <= 0xd8; 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 > 0xd8) { + reg = free_reg; // if no free, the free_reg still be 0 + } + + //Ext conf space + if (!reg) { + //because of Extend conf space, we will never run out of reg, but we need one index to differ them. so same node and same link can have multi range + u32 index = get_io_addr_index(nodeid, link); + reg = 0x110+ (index<<24) + (4<<20); // index could be 0, 255 + } + + resource = new_resource(dev, IOINDEX(0x1000 + reg, link)); + + return resource; +} + +static struct resource *amdfam10_find_mempair(struct device *dev, u32 nodeid, u32 link) +{ + struct resource *resource; + u32 free_reg, reg; + resource = 0; + free_reg = 0; + for (reg = 0x80; reg <= 0xb8; 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 > 0xb8) { + reg = free_reg; + } + + //Ext conf space + if (!reg) { + //because of Extend conf space, we will never run out of reg, + // but we need one index to differ them. so same node and + // same link can have multi range + u32 index = get_mmio_addr_index(nodeid, link); + reg = 0x110+ (index<<24) + (6<<20); // index could be 0, 63 + + } + resource = new_resource(dev, IOINDEX(0x1000 + reg, link)); + return resource; +} + + +static void amdfam10_link_read_bases(struct device *dev, u32 nodeid, u32 link) +{ + struct resource *resource; + + /* Initialize the io space constraints on the current bus */ + resource = amdfam10_find_iopair(dev, nodeid, link); + if (resource) { + u32 align; + align = log2(HT_IO_HOST_ALIGN); + resource->base = 0; + resource->size = 0; + resource->align = align; + resource->gran = align; + resource->limit = 0xffffUL; + resource->flags = IORESOURCE_IO | IORESOURCE_BRIDGE; + } + + /* Initialize the prefetchable memory constraints on the current bus */ + resource = amdfam10_find_mempair(dev, nodeid, 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 = amdfam10_find_mempair(dev, nodeid, 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_BRIDGE; + } +} + +static void amdfam10_read_resources(struct device *dev) +{ + u32 nodeid; + struct bus *link; + nodeid = amdfam10_nodeid(dev); + for (link = dev->link_list; link; link = link->next) { + if (link->children) { + amdfam10_link_read_bases(dev, nodeid, link->link_num); + } + } +} + +static void amdfam10_set_resource(struct device *dev, struct resource *resource, + u32 nodeid) +{ + resource_t rbase, rend; + unsigned int reg, link_num; + char buf[50]; + + /* Make certain the resource has actually been set */ + if (!(resource->flags & IORESOURCE_ASSIGNED)) { + return; + } + + /* If I have already stored this resource don't worry about it */ + if (resource->flags & IORESOURCE_STORED) { + 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 & 0xffff) < 0x1000) { + 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 & 0xfff; // 4k + link_num = IOINDEX_LINK(resource->index); + + if (resource->flags & IORESOURCE_IO) { + + set_io_addr_reg(dev, nodeid, link_num, reg, rbase>>8, rend>>8); + store_conf_io_addr(nodeid, link_num, reg, (resource->index >> 24), rbase>>8, rend>>8); + } else if (resource->flags & IORESOURCE_MEM) { + set_mmio_addr_reg(nodeid, link_num, reg, (resource->index >>24), rbase>>8, rend>>8, sysconf.nodes); // [39:8] + store_conf_mmio_addr(nodeid, link_num, reg, (resource->index >>24), rbase>>8, rend>>8); + } + resource->flags |= IORESOURCE_STORED; + snprintf(buf, sizeof(buf), " <node %x link %x>", + nodeid, link_num); + report_resource_stored(dev, resource, buf); +} + +/** + * I tried to reuse the resource allocation code in amdfam10_set_resource() + * but it is too difficult to deal with the resource allocation magic. + */ + +static void amdfam10_create_vga_resource(struct device *dev, unsigned int nodeid) +{ + struct bus *link; + struct resource *res; + + /* 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 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 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); + set_vga_enable_reg(nodeid, link->link_num); + + /* Redirect VGA memory access to MMIO + * This signals the Family 10h resource parser + * to add a new MMIO mapping to the Range 11 + * MMIO control registers (starting at F1x1B8), + * and also reserves the resource in the E820 map. + */ + res = new_resource(dev, IOINDEX(0x1000 + 0x1b8, link->link_num)); + res->base = 0xa0000; + res->size = 0x20000; + res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED; + amdfam10_set_resource(dev, res, nodeid); +} + +static void amdfam10_set_resources(struct device *dev) +{ + unsigned int nodeid; + struct bus *bus; + struct resource *res; + + /* Find the nodeid */ + nodeid = amdfam10_nodeid(dev); + + amdfam10_create_vga_resource(dev, nodeid); + + /* Set each resource we have found */ + for (res = dev->resource_list; res; res = res->next) { + amdfam10_set_resource(dev, res, nodeid); + } + + for (bus = dev->link_list; bus; bus = bus->next) { + if (bus->children) { + assign_resources(bus); + } + } +} + +static void mcf0_control_init(struct device *dev) +{ +} + +#if CONFIG(HAVE_ACPI_TABLES) +static const char *amdfam10_northbridge_acpi_name(const struct device *dev) +{ + return ""; +} +#endif + +static struct device_operations northbridge_operations = { + .read_resources = amdfam10_read_resources, + .set_resources = amdfam10_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = mcf0_control_init, + .scan_bus = amdfam10_scan_chains, +#if CONFIG(HAVE_ACPI_TABLES) + .write_acpi_tables = northbridge_write_acpi_tables, + .acpi_fill_ssdt_generator = northbridge_acpi_write_vars, + .acpi_name = amdfam10_northbridge_acpi_name, +#endif + .enable = 0, + .ops_pci = 0, +}; + +static const struct pci_driver mcf0_driver __pci_driver = { + .ops = &northbridge_operations, + .vendor = PCI_VENDOR_ID_AMD, + .device = 0x1200, +}; + +static void amdfam10_nb_init(void *chip_info) +{ + relocate_sb_ht_chain(); +} + +static const struct pci_driver mcf0_driver_fam15_model10 __pci_driver = { + .ops = &northbridge_operations, + .vendor = PCI_VENDOR_ID_AMD, + .device = 0x1400, +}; + +static const struct pci_driver mcf0_driver_fam15 __pci_driver = { + .ops = &northbridge_operations, + .vendor = PCI_VENDOR_ID_AMD, + .device = 0x1600, +}; + +struct chip_operations northbridge_amd_amdfam10_ops = { + CHIP_NAME("AMD Family 10h/15h Northbridge") + .enable_dev = 0, + .init = amdfam10_nb_init, +}; + +static void amdfam10_domain_read_resources(struct device *dev) +{ + unsigned int reg; + uint8_t nvram; + uint8_t enable_cc6; + + /* 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 int nodeid, reg_link; + struct device *reg_dev; + if (reg < 0xc0) { // mmio + nodeid = (limit & 0xf) + (base&0x30); + } else { // io + nodeid = (limit & 0xf) + ((base>>4)&0x30); + } + reg_link = (limit >> 4) & 7; + reg_dev = __f0_dev[nodeid]; + if (reg_dev) { + /* Reserve the resource */ + struct resource *res; + res = new_resource(reg_dev, IOINDEX(0x1000 + reg, reg_link)); + if (res) { + res->flags = 1; + } + } + } + } + /* FIXME: do we need to check extend conf space? + I don't believe that much preset value */ + + pci_domain_read_resources(dev); + + /* We have MMCONF_SUPPORT, create the resource window. */ + mmconf_resource(dev, MMIO_CONF_BASE); + + /* Reserve lower DRAM region to force PCI MMIO region to correct location above 0xefffffff */ + ram_resource(dev, 7, 0, rdmsr(TOP_MEM).lo >> 10); + + if (is_fam15h()) { + enable_cc6 = 0; + if (get_option(&nvram, "cpu_cc6_state") == CB_SUCCESS) + enable_cc6 = !!nvram; + + if (enable_cc6) { + uint8_t node; + uint8_t interleaved; + int8_t range; + uint8_t max_node; + uint64_t max_range_limit; + uint32_t dword; + uint32_t dword2; + uint64_t qword; + uint8_t num_nodes; + + /* Find highest DRAM range (DramLimitAddr) */ + num_nodes = 0; + max_node = 0; + interleaved = 0; + max_range_limit = 0; + struct device *node_dev; + for (node = 0; node < FX_DEVS; node++) { + node_dev = get_node_pci(node, 0); + /* Test for node presence */ + if ((!node_dev) || (pci_read_config32(node_dev, PCI_VENDOR_ID) == 0xffffffff)) + continue; + + num_nodes++; + for (range = 0; range < 8; range++) { + dword = pci_read_config32(get_node_pci(node, 1), 0x40 + (range * 0x8)); + if (!(dword & 0x3)) + continue; + + if ((dword >> 8) & 0x7) + interleaved = 1; + + dword = pci_read_config32(get_node_pci(node, 1), 0x44 + (range * 0x8)); + dword2 = pci_read_config32(get_node_pci(node, 1), 0x144 + (range * 0x8)); + qword = 0xffffff; + qword |= ((((uint64_t)dword) >> 16) & 0xffff) << 24; + qword |= (((uint64_t)dword2) & 0xff) << 40; + + if (qword > max_range_limit) { + max_range_limit = qword; + max_node = dword & 0x7; + } + } + } + + /* Calculate CC6 storage area size */ + if (interleaved) + qword = (uint64_t)0x1000000 * num_nodes; + else + qword = 0x1000000; + + /* FIXME + * The BKDG appears to be incorrect as to the location of the CC6 save region + * lower boundary on non-interleaved systems, causing lockups on attempted write + * to the CC6 save region. + * + * For now, work around by allocating the maximum possible CC6 save region size. + * + * Determine if this is a BKDG error or a setup problem and remove this warning! + */ + qword = (0x1 << 27); + max_range_limit = (((uint64_t)(pci_read_config32(get_node_pci(max_node, 1), 0x124) & 0x1fffff)) << 27) - 1; + + printk(BIOS_INFO, "Reserving CC6 save segment base: %08llx size: %08llx\n", (max_range_limit + 1), qword); + + /* Reserve the CC6 save segment */ + reserved_ram_resource(dev, 8, (max_range_limit + 1) >> 10, qword >> 10); + } + } +} + +static u32 my_find_pci_tolm(struct bus *bus, u32 tolm) +{ + struct resource *min; + min = 0; + search_bus_resources(bus, IORESOURCE_MEM, IORESOURCE_MEM, tolm_test, &min); + if (min && tolm > min->base) { + tolm = min->base; + } + return tolm; +} + +#if CONFIG_HW_MEM_HOLE_SIZEK != 0 + +struct hw_mem_hole_info { + unsigned int 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 < sysconf.nodes; i++) { + struct dram_base_mask_t d; + u32 hole; + d = get_dram_base_mask(i); + if (!(d.mask & 1)) continue; // no memory on this node + + 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) { + resource_t limitk_pri = 0; + for (i = 0; i < sysconf.nodes; i++) { + struct dram_base_mask_t d; + resource_t base_k, limit_k; + d = get_dram_base_mask(i); + if (!(d.base & 1)) continue; + + base_k = ((resource_t)(d.base & 0x1fffff00)) <<9; + if (base_k > 4 *1024 * 1024) break; // don't need to go to check + if (limitk_pri != base_k) { // we find the hole + mem_hole.hole_startk = (unsigned int)limitk_pri; // must beblow 4G + mem_hole.node_id = i; + break; //only one hole + } + + limit_k = ((resource_t)((d.mask + 0x00000100) & 0x1fffff00)) << 9; + limitk_pri = limit_k; + } + } + return mem_hole; +} + +#endif + +#include <cbmem.h> + +static void setup_uma_memory(void) +{ +#if CONFIG(GFXUMA) + uint32_t topmem = (uint32_t) bsp_topmem(); + uma_memory_size = get_uma_memory_size(topmem); + 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 amdfam10_domain_set_resources(struct device *dev) +{ + unsigned long mmio_basek; + u32 pci_tolm; + int i, idx; + struct bus *link; +#if CONFIG_HW_MEM_HOLE_SIZEK != 0 + struct hw_mem_hole_info mem_hole; +#endif + + pci_tolm = 0xffffffffUL; + for (link = dev->link_list; link; link = link->next) { + pci_tolm = my_find_pci_tolm(link, pci_tolm); + } + + // FIXME handle interleaved nodes. If you fix this here, please fix + // amdk8, 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 amdk8, 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 + */ + + mem_hole = get_hw_mem_hole_info(); + + // Use hole_basek as mmio_basek, and we don't need to reset hole anymore + if ((mem_hole.node_id != -1) && (mmio_basek > mem_hole.hole_startk)) { + mmio_basek = mem_hole.hole_startk; + } + +#endif + + idx = 0x10; + for (i = 0; i < sysconf.nodes; i++) { + struct dram_base_mask_t d; + resource_t basek, limitk, sizek; // 4 1T + d = get_dram_base_mask(i); + + if (!(d.mask & 1)) continue; + basek = ((resource_t)(d.base & 0x1fffff00)) << 9; // could overflow, we may lost 6 bit here + limitk = ((resource_t)((d.mask + 0x00000100) & 0x1fffff00)) << 9; + 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)); + + } + + /* split the region to accommodate pci memory space */ + if ((basek < 4*1024*1024) && (limitk > mmio_basek)) { + if (basek <= mmio_basek) { + unsigned int pre_sizek; + pre_sizek = mmio_basek - basek; + if (pre_sizek > 0) { + ram_resource(dev, (idx | i), basek, pre_sizek); + idx += 0x10; + sizek -= pre_sizek; + } + 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=%08llx, limitk=%08llx\n", + i, mmio_basek, basek, limitk); + } + +#if CONFIG(GFXUMA) + uma_resource(dev, 7, uma_memory_base >> 10, uma_memory_size >> 10); +#endif + + for (link = dev->link_list; link; link = link->next) { + if (link->children) { + assign_resources(link); + } + } +} + +static void amdfam10_domain_scan_bus(struct device *dev) +{ + u32 reg; + int i; + struct bus *link; + /* Unmap all of the HT chains */ + for (reg = 0xe0; reg <= 0xec; reg += 4) { + f1_write_config32(reg, 0); + } + + for (link = dev->link_list; link; link = link->next) { + link->secondary = dev->bus->subordinate; + pci_scan_bus(link, PCI_DEVFN(CONFIG_CDB, 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); + } + } +} + +#if CONFIG(GENERATE_SMBIOS_TABLES) +static int amdfam10_get_smbios_data16(int *count, int handle, + unsigned long *current) +{ + struct amdmct_memory_info *mem_info; + mem_info = cbmem_find(CBMEM_ID_AMDMCT_MEMINFO); + if (mem_info == NULL) + return 0; /* can't find amdmct information in cbmem */ + + struct device *dev = get_node_pci(0, 0); + struct northbridge_amd_amdfam10_config *config = dev->chip_info; + + int node; + int slot; + + struct smbios_type16 *t = (struct smbios_type16 *)*current; + int len = sizeof(struct smbios_type16); + + memset(t, 0, sizeof(struct smbios_type16)); + t->type = SMBIOS_PHYS_MEMORY_ARRAY; + t->handle = handle; + t->length = len - 2; + t->location = MEMORY_ARRAY_LOCATION_SYSTEM_BOARD; + t->use = MEMORY_ARRAY_USE_SYSTEM; + t->memory_error_correction = MEMORY_ARRAY_ECC_NONE; + if ((mem_info->ecc_enabled) + && (mem_info->mct_stat.GStatus & (1 << GSB_ECCDIMMs)) + && !(mem_info->mct_stat.GStatus & (1 << GSB_DramECCDis))) + /* Single-bit ECC enabled */ + t->memory_error_correction = MEMORY_ARRAY_ECC_SINGLE_BIT; + t->maximum_capacity = config->maximum_memory_capacity / 1024; /* Convert to kilobytes */ + t->memory_error_information_handle = 0xFFFE; /* no error information handle available */ + + t->number_of_memory_devices = 0; + /* Check all nodes for installed DIMMs */ + for (node = 0; node < MAX_NODES_SUPPORTED; node++) + /* Check all slots for installed DIMMs */ + for (slot = 0; slot < MAX_DIMMS_SUPPORTED; slot++) + if (mem_info->dct_stat[node].DIMMPresent & (1 << slot)) + /* Found an installed DIMM; increment count */ + t->number_of_memory_devices++; + + *current += len; + *count += 1; + return len; +} + +static uint16_t amdmct_mct_speed_enum_to_mhz(uint8_t speed) +{ + if (is_fam15h()) { + if (CONFIG(DIMM_DDR3)) { + switch (speed) { + case 0x4: + return 333; + case 0x6: + return 400; + case 0xa: + return 533; + case 0xe: + return 667; + case 0x12: + return 800; + case 0x16: + return 933; + default: + return 0; + } + } else { + return 0; + } + } else { + if (CONFIG(DIMM_DDR2)) { + switch (speed) { + case 1: + return 200; + case 2: + return 266; + case 3: + return 333; + case 4: + return 400; + case 5: + return 533; + default: + return 0; + } + } else if (CONFIG(DIMM_DDR3)) { + switch (speed) { + case 3: + return 333; + case 4: + return 400; + case 5: + return 533; + case 6: + return 667; + case 7: + return 800; + default: + return 0; + } + } else { + return 0; + } + } +} + +static int amdfam10_get_smbios_data17(int *count, int handle, int parent_handle, + unsigned long *current) +{ + struct amdmct_memory_info *mem_info; + mem_info = cbmem_find(CBMEM_ID_AMDMCT_MEMINFO); + if (mem_info == NULL) + return 0; /* can't find amdmct information in cbmem */ + + int single_len; + int len = 0; + int node; + int slot; + + /* Check all nodes for installed DIMMs */ + for (node = 0; node < MAX_NODES_SUPPORTED; node++) { + /* Get configured RAM bus speed */ + uint16_t speed; + speed = amdmct_mct_speed_enum_to_mhz(mem_info->dct_stat[node].Speed); + + /* Get maximum RAM bus speed */ + uint16_t max_speed; + max_speed = amdmct_mct_speed_enum_to_mhz(mem_info->dct_stat[node].DIMMAutoSpeed); + + /* Check all slots for installed DIMMs */ + for (slot = 0; slot < MAX_DIMMS_SUPPORTED; slot++) { + if (mem_info->dct_stat[node].DIMMPresent & (1 << slot)) { + /* Found an installed DIMM; populate tables */ + struct smbios_type17 *t = (struct smbios_type17 *)*current; + char string_buffer[256]; + + /* Initialize structure */ + memset(t, 0, sizeof(struct smbios_type17)); + + /* Calculate the total module size in bytes: + * Primary data width * 2^(#rows) * 2^(#cols) * #banks * #ranks + */ + uint8_t width, rows, cols, banks, ranks; + uint64_t chip_size; + uint32_t chip_width; + rows = mem_info->dct_stat[node].DimmRows[slot]; + cols = mem_info->dct_stat[node].DimmCols[slot]; + ranks = mem_info->dct_stat[node].DimmRanks[slot]; + banks = mem_info->dct_stat[node].DimmBanks[slot]; +#if CONFIG(DIMM_DDR3) + chip_size = mem_info->dct_stat[node].DimmChipSize[slot]; + chip_width = mem_info->dct_stat[node].DimmChipWidth[slot]; +#else + chip_size = 0; + chip_width = 0; +#endif + uint64_t dimm_size_bytes; + if (CONFIG(DIMM_DDR3)) { + width = mem_info->dct_stat[node].DimmWidth[slot]; + dimm_size_bytes = ((width / chip_width) * chip_size * ranks) / 8; + } else { + width = 8; + dimm_size_bytes = width * (1ULL << rows) * (1ULL << cols) * banks * ranks; + } + + memset(t, 0, sizeof(struct smbios_type17)); + t->type = SMBIOS_MEMORY_DEVICE; + t->handle = handle; + t->phys_memory_array_handle = parent_handle; + t->length = sizeof(struct smbios_type17) - 2; + if (dimm_size_bytes > 0x800000000) { + t->size = 0x7FFF; + t->extended_size = dimm_size_bytes >> 16; + } else { + t->size = dimm_size_bytes / (1024*1024); + t->size &= (~0x8000); /* size specified in megabytes */ + } + t->total_width = t->data_width = 64; + if (mem_info->dct_stat[node].DimmECCPresent & (1 << slot)) + t->total_width += 8; + t->attributes = 0; + t->attributes |= ranks & 0xf; /* rank number is stored in the lowest 4 bits of the attributes field */ + t->form_factor = MEMORY_FORMFACTOR_DIMM; + if (mem_info->dct_stat[node].Dual_Node_Package) { + snprintf(string_buffer, sizeof(string_buffer), "NODE %d DIMM_%s%d", node >> 1, + (mem_info->dct_stat[node].Internal_Node_ID)?((slot & 0x1)?"D":"C"):((slot & 0x1)?"B":"A"), (slot >> 1) + 1); + } else { + snprintf(string_buffer, sizeof(string_buffer), "NODE %d DIMM_%s%d", node, (slot & 0x1)?"B":"A", (slot >> 1) + 1); + } + t->device_locator = smbios_add_string(t->eos, string_buffer); + if (CONFIG(DIMM_DDR2)) + t->memory_type = MEMORY_TYPE_DDR2; + else if (CONFIG(DIMM_DDR3)) + t->memory_type = MEMORY_TYPE_DDR3; + t->type_detail = MEMORY_TYPE_DETAIL_SYNCHRONOUS; + if (mem_info->dct_stat[node].DimmRegistered[slot]) + t->type_detail |= MEMORY_TYPE_DETAIL_REGISTERED; + else + t->type_detail |= MEMORY_TYPE_DETAIL_UNBUFFERED; + t->speed = max_speed; + t->clock_speed = speed; + smbios_fill_dimm_manufacturer_from_id(mem_info->dct_stat[node].DimmManufacturerID[slot], t); + t->part_number = smbios_add_string(t->eos, mem_info->dct_stat[node].DimmPartNumber[slot]); + if (mem_info->dct_stat[node].DimmSerialNumber[slot] == 0) { + t->serial_number = smbios_add_string(t->eos, "None"); + } else { + snprintf(string_buffer, sizeof(string_buffer), "%08X", mem_info->dct_stat[node].DimmSerialNumber[slot]); + t->serial_number = smbios_add_string(t->eos, string_buffer); + } + if (CONFIG(DIMM_DDR2)) { + /* JEDEC specifies 1.8V only, so assume that the memory is configured for 1.8V */ + t->minimum_voltage = 1800; + t->maximum_voltage = 1800; + t->configured_voltage = 1800; + } else if (CONFIG(DIMM_DDR3)) { +#if CONFIG(DIMM_DDR3) + /* Find the maximum and minimum supported voltages */ + uint8_t supported_voltages = mem_info->dct_stat[node].DimmSupportedVoltages[slot]; + uint8_t configured_voltage = mem_info->dct_stat[node].DimmConfiguredVoltage[slot]; + + if (supported_voltages & 0x8) + t->minimum_voltage = 1150; + else if (supported_voltages & 0x4) + t->minimum_voltage = 1250; + else if (supported_voltages & 0x2) + t->minimum_voltage = 1350; + else if (supported_voltages & 0x1) + t->minimum_voltage = 1500; + + if (supported_voltages & 0x1) + t->maximum_voltage = 1500; + else if (supported_voltages & 0x2) + t->maximum_voltage = 1350; + else if (supported_voltages & 0x4) + t->maximum_voltage = 1250; + else if (supported_voltages & 0x8) + t->maximum_voltage = 1150; + + if (configured_voltage & 0x8) + t->configured_voltage = 1150; + else if (configured_voltage & 0x4) + t->configured_voltage = 1250; + else if (configured_voltage & 0x2) + t->configured_voltage = 1350; + else if (configured_voltage & 0x1) + t->configured_voltage = 1500; +#endif + } + t->memory_error_information_handle = 0xFFFE; /* no error information handle available */ + single_len = t->length + smbios_string_table_len(t->eos); + len += single_len; + *current += single_len; + handle++; + *count += 1; + } + } + } + + return len; +} + +static int amdfam10_get_smbios_data(struct device *dev, int *handle, unsigned long *current) +{ + int len; + int count = 0; + len = amdfam10_get_smbios_data16(&count, *handle, current); + len += amdfam10_get_smbios_data17(&count, *handle + 1, *handle, current); + *handle += count; + return len; +} +#endif + +#if CONFIG(HAVE_ACPI_TABLES) +static const char *amdfam10_domain_acpi_name(const struct device *dev) +{ + if (dev->path.type == DEVICE_PATH_DOMAIN) + return "PCI0"; + + return NULL; +} +#endif + +static struct device_operations pci_domain_ops = { + .read_resources = amdfam10_domain_read_resources, + .set_resources = amdfam10_domain_set_resources, + .enable_resources = NULL, + .init = NULL, + .scan_bus = amdfam10_domain_scan_bus, +#if CONFIG(HAVE_ACPI_TABLES) + .acpi_name = amdfam10_domain_acpi_name, +#endif +#if CONFIG(GENERATE_SMBIOS_TABLES) + .get_smbios_data = amdfam10_get_smbios_data, +#endif +}; + +static void sysconf_init(struct device *dev) // first node +{ + sysconf.sblk = (pci_read_config32(dev, 0x64)>>8) & 7; // don't forget sublink1 + sysconf.segbit = 0; + sysconf.ht_c_num = 0; + + unsigned int ht_c_index; + + for (ht_c_index = 0; ht_c_index < 32; ht_c_index++) { + sysconf.ht_c_conf_bus[ht_c_index] = 0; + } + + sysconf.nodes = ((pci_read_config32(dev, 0x60)>>4) & 7) + 1; +#if CONFIG_MAX_PHYSICAL_CPUS > 8 + sysconf.nodes += (((pci_read_config32(dev, 0x160)>>4) & 7)<<3); +#endif + + sysconf.enabled_apic_ext_id = 0; + sysconf.lift_bsp_apicid = 0; + + /* Find the bootstrap processors apicid */ + sysconf.bsp_apicid = lapicid(); + sysconf.apicid_offset = sysconf.bsp_apicid; + +#if CONFIG(ENABLE_APIC_EXT_ID) + if (pci_read_config32(dev, 0x68) & (HTTC_APIC_EXT_ID|HTTC_APIC_EXT_BRD_CST)) + { + sysconf.enabled_apic_ext_id = 1; + } + #if (CONFIG_APIC_ID_OFFSET > 0) + if (sysconf.enabled_apic_ext_id) { + if (sysconf.bsp_apicid == 0) { + /* bsp apic id is not changed */ + sysconf.apicid_offset = CONFIG_APIC_ID_OFFSET; + } else { + sysconf.lift_bsp_apicid = 1; + } + } + #endif +#endif +} + +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; +#if CONFIG_CBB + struct device *pci_domain; +#endif + int nvram = 0; + int i,j; + int nodes; + unsigned int nb_cfg_54; + unsigned int siblings; + int cores_found; + int disable_siblings; + uint8_t disable_cu_siblings = 0; + unsigned int ApicIdCoreIdSize; + + nb_cfg_54 = 0; + ApicIdCoreIdSize = (cpuid_ecx(0x80000008)>>12 & 0xf); + if (ApicIdCoreIdSize) { + siblings = (1<<ApicIdCoreIdSize)-1; + } else { + siblings = 3; //quad core + } + + disable_siblings = !CONFIG(LOGICAL_CPUS); +#if CONFIG(LOGICAL_CPUS) + get_option(&disable_siblings, "multi_core"); +#endif + + // How can I get the nb_cfg_54 of every node's nb_cfg_54 in bsp??? + nb_cfg_54 = read_nb_cfg_54(); + +#if CONFIG_CBB + dev_mc = pcidev_on_root(CONFIG_CDB, 0); //0x00 + if (dev_mc && dev_mc->bus) { + printk(BIOS_DEBUG, "%s found", dev_path(dev_mc)); + pci_domain = dev_mc->bus->dev; + if (pci_domain && (pci_domain->path.type == DEVICE_PATH_DOMAIN)) { + printk(BIOS_DEBUG, "\n%s move to ",dev_path(dev_mc)); + dev_mc->bus->secondary = CONFIG_CBB; // move to 0xff + printk(BIOS_DEBUG, "%s",dev_path(dev_mc)); + + } else { + printk(BIOS_DEBUG, " but it is not under pci_domain directly "); + } + printk(BIOS_DEBUG, "\n"); + } + dev_mc = dev_find_slot(CONFIG_CBB, PCI_DEVFN(CONFIG_CDB, 0)); + if (!dev_mc) { + dev_mc = pcidev_on_root(0x18, 0); + if (dev_mc && dev_mc->bus) { + printk(BIOS_DEBUG, "%s found\n", dev_path(dev_mc)); + pci_domain = dev_mc->bus->dev; + if (pci_domain && (pci_domain->path.type == DEVICE_PATH_DOMAIN)) { + if ((pci_domain->link_list) && (pci_domain->link_list->children == dev_mc)) { + printk(BIOS_DEBUG, "%s move to ",dev_path(dev_mc)); + dev_mc->bus->secondary = CONFIG_CBB; // move to 0xff + printk(BIOS_DEBUG, "%s\n",dev_path(dev_mc)); + while (dev_mc) { + printk(BIOS_DEBUG, "%s move to ",dev_path(dev_mc)); + dev_mc->path.pci.devfn -= PCI_DEVFN(0x18,0); + printk(BIOS_DEBUG, "%s\n",dev_path(dev_mc)); + dev_mc = dev_mc->sibling; + } + } + } + } + } + +#endif + + dev_mc = dev_find_slot(CONFIG_CBB, PCI_DEVFN(CONFIG_CDB, 0)); + if (!dev_mc) { + printk(BIOS_ERR, "%02x:%02x.0 not found", CONFIG_CBB, CONFIG_CDB); + die(""); + } + + sysconf_init(dev_mc); + + nodes = sysconf.nodes; + +#if CONFIG_CBB && (NODE_NUMS > 32) + if (nodes > 32) { // need to put node 32 to node 63 to bus 0xfe + if (pci_domain->link_list && !pci_domain->link_list->next) { + struct bus *new_link = new_link(pci_domain); + pci_domain->link_list->next = new_link; + new_link->link_num = 1; + new_link->dev = pci_domain; + new_link->children = 0; + printk(BIOS_DEBUG, "%s links now 2\n", dev_path(pci_domain)); + } + pci_domain->link_list->next->secondary = CONFIG_CBB - 1; + } +#endif + /* 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); + + if (get_option(&nvram, "compute_unit_siblings") == CB_SUCCESS) + disable_cu_siblings = !!nvram; + + if (disable_cu_siblings) + printk(BIOS_DEBUG, "Disabling siblings on each compute unit as requested\n"); + + for (i = 0; i < nodes; i++) { + struct device *cdb_dev; + unsigned int busn, devn; + struct bus *pbus; + + uint8_t fam15h = 0; + uint8_t rev_gte_d = 0; + uint8_t dual_node = 0; + uint32_t f3xe8; + uint32_t model; + + busn = CONFIG_CBB; + devn = CONFIG_CDB+i; + pbus = dev_mc->bus; +#if CONFIG_CBB && (NODE_NUMS > 32) + if (i >= 32) { + busn--; + devn-=32; + pbus = pci_domain->link_list->next; + } +#endif + + /* Find the cpu's pci device */ + cdb_dev = dev_find_slot(busn, PCI_DEVFN(devn, 0)); + if (!cdb_dev) { + /* If I am probing things in a weird order + * ensure all of the cpu's pci devices are found. + */ + int fn; + for (fn = 0; fn <= 5; fn++) { //FBDIMM? + cdb_dev = pci_probe_dev(NULL, pbus, + PCI_DEVFN(devn, fn)); + } + } + + + /* Ok, We need to set the links for that device. + * otherwise the device under it will not be scanned + */ + cdb_dev = dev_find_slot(busn, PCI_DEVFN(devn, 0)); + if (cdb_dev) + add_more_links(cdb_dev, 4); + + cdb_dev = dev_find_slot(busn, PCI_DEVFN(devn, 4)); + if (cdb_dev) + add_more_links(cdb_dev, 4); + + f3xe8 = pci_read_config32(get_node_pci(0, 3), 0xe8); + + model = cpuid_eax(0x80000001); + model = ((model & 0xf0000) >> 12) | ((model & 0xf0) >> 4); + + if (is_fam15h()) { + /* Family 15h or later */ + fam15h = 1; + nb_cfg_54 = 1; + } + + if ((model >= 0x8) || fam15h) + /* Revision D or later */ + rev_gte_d = 1; + + if (rev_gte_d) + /* Check for dual node capability */ + if (f3xe8 & 0x20000000) + dual_node = 1; + + cores_found = 0; // one core + if (fam15h) + cdb_dev = dev_find_slot(busn, PCI_DEVFN(devn, 5)); + else + cdb_dev = dev_find_slot(busn, PCI_DEVFN(devn, 3)); + int enable_node = cdb_dev && cdb_dev->enabled; + if (enable_node) { + if (fam15h) { + cores_found = pci_read_config32(cdb_dev, 0x84) & 0xff; + } else { + j = pci_read_config32(cdb_dev, 0xe8); + cores_found = (j >> 12) & 3; // dev is func 3 + if (siblings > 3) + cores_found |= (j >> 13) & 4; + } + printk(BIOS_DEBUG, " %s siblings=%d\n", dev_path(cdb_dev), cores_found); + } + + if (siblings > cores_found) + siblings = cores_found; + + u32 jj; + if (disable_siblings) { + jj = 0; + } else + { + jj = cores_found; + } + + for (j = 0; j <=jj; j++) { + u32 apic_id; + + if (dual_node) { + apic_id = 0; + if (fam15h) { + apic_id |= ((i >> 1) & 0x3) << 5; /* Node ID */ + apic_id |= ((i & 0x1) * (siblings + 1)) + j; /* Core ID */ + } else { + if (nb_cfg_54) { + apic_id |= ((i >> 1) & 0x3) << 4; /* Node ID */ + apic_id |= ((i & 0x1) * (siblings + 1)) + j; /* Core ID */ + } else { + apic_id |= i & 0x3; /* Node ID */ + apic_id |= (((i & 0x1) * (siblings + 1)) + j) << 4; /* Core ID */ + } + } + } else { + if (fam15h) { + apic_id = 0; + apic_id |= (i & 0x7) << 4; /* Node ID */ + apic_id |= j & 0xf; /* Core ID */ + } else { + apic_id = i * (nb_cfg_54?(siblings+1):1) + j * (nb_cfg_54?1:64); // ? + } + } + +#if CONFIG(ENABLE_APIC_EXT_ID) && (CONFIG_APIC_ID_OFFSET > 0) + if (sysconf.enabled_apic_ext_id) { + if (apic_id != 0 || sysconf.lift_bsp_apicid) { + apic_id += sysconf.apicid_offset; + } + } +#endif + if (disable_cu_siblings && (j & 0x1)) + continue; + + struct device *cpu = add_cpu_device(cpu_bus, apic_id, enable_node); + if (cpu) + amd_cpu_topology(cpu, i, j); + } + } +} + +static void detect_and_enable_probe_filter(struct device *dev) +{ + uint32_t dword; + + uint8_t nvram; + uint8_t enable_probe_filter; + + /* Check to see if the probe filter is allowed */ + enable_probe_filter = 1; + if (get_option(&nvram, "probe_filter") == CB_SUCCESS) + enable_probe_filter = !!nvram; + + if (!enable_probe_filter) + return; + + uint8_t fam15h = 0; + uint8_t rev_gte_d = 0; + uint32_t model; + + model = cpuid_eax(0x80000001); + model = ((model & 0xf0000) >> 12) | ((model & 0xf0) >> 4); + + if (is_fam15h()) { + /* Family 15h or later */ + fam15h = 1; + } + + if ((model >= 0x8) || fam15h) + /* Revision D or later */ + rev_gte_d = 1; + + if (rev_gte_d && (sysconf.nodes > 1)) { + /* Enable the probe filter */ + uint8_t i; + uint8_t pfmode = 0x0; + + uint32_t f3x58[MAX_NODES_SUPPORTED]; + uint32_t f3x5c[MAX_NODES_SUPPORTED]; + + printk(BIOS_DEBUG, "Enabling probe filter\n"); + + /* Disable L3 and DRAM scrubbers and configure system for probe filter support */ + for (i = 0; i < sysconf.nodes; i++) { + struct device *f2x_dev = pcidev_on_root(0x18 + i, 2); + struct device *f3x_dev = pcidev_on_root(0x18 + i, 3); + + f3x58[i] = pci_read_config32(f3x_dev, 0x58); + f3x5c[i] = pci_read_config32(f3x_dev, 0x5c); + pci_write_config32(f3x_dev, 0x58, f3x58[i] & ~((0x1f << 24) | 0x1f)); + pci_write_config32(f3x_dev, 0x5c, f3x5c[i] & ~0x1); + + dword = pci_read_config32(f2x_dev, 0x1b0); + dword &= ~(0x7 << 8); /* CohPrefPrbLmt = 0x0 */ + pci_write_config32(f2x_dev, 0x1b0, dword); + + msr_t msr = rdmsr_amd(BU_CFG2_MSR); + msr.hi |= 1 << (42 - 32); + wrmsr_amd(BU_CFG2_MSR, msr); + + if (is_fam15h()) { + uint8_t subcache_size = 0x0; + uint8_t pref_so_repl = 0x0; + uint32_t f3x1c4 = pci_read_config32(f3x_dev, 0x1c4); + if ((f3x1c4 & 0xffff) == 0xcccc) { + subcache_size = 0x1; + pref_so_repl = 0x2; + pfmode = 0x3; + } else { + pfmode = 0x2; + } + + dword = pci_read_config32(f3x_dev, 0x1d4); + dword |= 0x1 << 29; /* PFLoIndexHashEn = 0x1 */ + dword &= ~(0x3 << 20); /* PFPreferredSORepl = pref_so_repl */ + dword |= (pref_so_repl & 0x3) << 20; + dword |= 0x1 << 17; /* PFWayHashEn = 0x1 */ + dword |= 0xf << 12; /* PFSubCacheEn = 0xf */ + dword &= ~(0x3 << 10); /* PFSubCacheSize3 = subcache_size */ + dword |= (subcache_size & 0x3) << 10; + dword &= ~(0x3 << 8); /* PFSubCacheSize2 = subcache_size */ + dword |= (subcache_size & 0x3) << 8; + dword &= ~(0x3 << 6); /* PFSubCacheSize1 = subcache_size */ + dword |= (subcache_size & 0x3) << 6; + dword &= ~(0x3 << 4); /* PFSubCacheSize0 = subcache_size */ + dword |= (subcache_size & 0x3) << 4; + dword &= ~(0x3 << 2); /* PFWayNum = 0x2 */ + dword |= 0x2 << 2; + pci_write_config32(f3x_dev, 0x1d4, dword); + } else { + pfmode = 0x2; + + dword = pci_read_config32(f3x_dev, 0x1d4); + dword |= 0x1 << 29; /* PFLoIndexHashEn = 0x1 */ + dword &= ~(0x3 << 20); /* PFPreferredSORepl = 0x2 */ + dword |= 0x2 << 20; + dword |= 0xf << 12; /* PFSubCacheEn = 0xf */ + dword &= ~(0x3 << 10); /* PFSubCacheSize3 = 0x0 */ + dword &= ~(0x3 << 8); /* PFSubCacheSize2 = 0x0 */ + dword &= ~(0x3 << 6); /* PFSubCacheSize1 = 0x0 */ + dword &= ~(0x3 << 4); /* PFSubCacheSize0 = 0x0 */ + dword &= ~(0x3 << 2); /* PFWayNum = 0x2 */ + dword |= 0x2 << 2; + pci_write_config32(f3x_dev, 0x1d4, dword); + } + } + + udelay(40); + + disable_cache(); + wbinvd(); + + /* Enable probe filter */ + for (i = 0; i < sysconf.nodes; i++) { + struct device *f3x_dev = pcidev_on_root(0x18 + i, 3); + + dword = pci_read_config32(f3x_dev, 0x1c4); + dword |= (0x1 << 31); /* L3TagInit = 1 */ + pci_write_config32(f3x_dev, 0x1c4, dword); + do { + } while (pci_read_config32(f3x_dev, 0x1c4) & (0x1 << 31)); + + dword = pci_read_config32(f3x_dev, 0x1d4); + dword &= ~0x3; /* PFMode = pfmode */ + dword |= pfmode & 0x3; + pci_write_config32(f3x_dev, 0x1d4, dword); + do { + } while (!(pci_read_config32(f3x_dev, 0x1d4) & (0x1 << 19))); + } + + if (is_fam15h()) { + printk(BIOS_DEBUG, "Enabling ATM mode\n"); + + /* Enable ATM mode */ + for (i = 0; i < sysconf.nodes; i++) { + struct device *f0x_dev = + pcidev_on_root(0x18 + i, 0); + struct device *f3x_dev = + pcidev_on_root(0x18 + i, 3); + + dword = pci_read_config32(f0x_dev, 0x68); + dword |= (0x1 << 12); /* ATMModeEn = 1 */ + pci_write_config32(f0x_dev, 0x68, dword); + + dword = pci_read_config32(f3x_dev, 0x1b8); + dword |= (0x1 << 27); /* L3ATMModeEn = 1 */ + pci_write_config32(f3x_dev, 0x1b8, dword); + } + } + + enable_cache(); + + /* Reenable L3 and DRAM scrubbers */ + for (i = 0; i < sysconf.nodes; i++) { + struct device *f3x_dev = pcidev_on_root(0x18 + i, 3); + + pci_write_config32(f3x_dev, 0x58, f3x58[i]); + pci_write_config32(f3x_dev, 0x5c, f3x5c[i]); + } + + } +} + +static void detect_and_enable_cache_partitioning(struct device *dev) +{ + uint8_t i; + uint32_t dword; + + uint8_t nvram; + uint8_t enable_l3_cache_partitioning; + + /* Check to see if cache partitioning is allowed */ + enable_l3_cache_partitioning = 0; + if (get_option(&nvram, "l3_cache_partitioning") == CB_SUCCESS) + enable_l3_cache_partitioning = !!nvram; + + if (!enable_l3_cache_partitioning) + return; + + if (is_fam15h()) { + printk(BIOS_DEBUG, "Enabling L3 cache partitioning\n"); + + uint32_t f5x80; + uint8_t cu_enabled; + uint8_t compute_unit_count = 0; + + for (i = 0; i < sysconf.nodes; i++) { + struct device *f3x_dev = pcidev_on_root(0x18 + i, 3); + struct device *f4x_dev = pcidev_on_root(0x18 + i, 4); + struct device *f5x_dev = pcidev_on_root(0x18 + i, 5); + + /* Determine the number of active compute units on this node */ + f5x80 = pci_read_config32(f5x_dev, 0x80); + cu_enabled = f5x80 & 0xf; + if (cu_enabled == 0x1) + compute_unit_count = 1; + if (cu_enabled == 0x3) + compute_unit_count = 2; + if (cu_enabled == 0x7) + compute_unit_count = 3; + if (cu_enabled == 0xf) + compute_unit_count = 4; + + /* Disable BAN mode */ + dword = pci_read_config32(f3x_dev, 0x1b8); + dword &= ~(0x7 << 19); /* L3BanMode = 0x0 */ + pci_write_config32(f3x_dev, 0x1b8, dword); + + /* Set up cache mapping */ + dword = pci_read_config32(f4x_dev, 0x1d4); + if (compute_unit_count == 1) { + dword |= 0xf; /* ComputeUnit0SubCacheEn = 0xf */ + } + if (compute_unit_count == 2) { + dword &= ~(0xf << 4); /* ComputeUnit1SubCacheEn = 0xc */ + dword |= (0xc << 4); + dword &= ~0xf; /* ComputeUnit0SubCacheEn = 0x3 */ + dword |= 0x3; + } + if (compute_unit_count == 3) { + dword &= ~(0xf << 8); /* ComputeUnit2SubCacheEn = 0x8 */ + dword |= (0x8 << 8); + dword &= ~(0xf << 4); /* ComputeUnit1SubCacheEn = 0x4 */ + dword |= (0x4 << 4); + dword &= ~0xf; /* ComputeUnit0SubCacheEn = 0x3 */ + dword |= 0x3; + } + if (compute_unit_count == 4) { + dword &= ~(0xf << 12); /* ComputeUnit3SubCacheEn = 0x8 */ + dword |= (0x8 << 12); + dword &= ~(0xf << 8); /* ComputeUnit2SubCacheEn = 0x4 */ + dword |= (0x4 << 8); + dword &= ~(0xf << 4); /* ComputeUnit1SubCacheEn = 0x2 */ + dword |= (0x2 << 4); + dword &= ~0xf; /* ComputeUnit0SubCacheEn = 0x1 */ + dword |= 0x1; + } + pci_write_config32(f4x_dev, 0x1d4, dword); + + /* Enable cache partitioning */ + pci_write_config32(f4x_dev, 0x1d4, dword); + if (compute_unit_count == 1) { + dword &= ~(0xf << 26); /* MaskUpdateForComputeUnit = 0x1 */ + dword |= (0x1 << 26); + } else if (compute_unit_count == 2) { + dword &= ~(0xf << 26); /* MaskUpdateForComputeUnit = 0x3 */ + dword |= (0x3 << 26); + } else if (compute_unit_count == 3) { + dword &= ~(0xf << 26); /* MaskUpdateForComputeUnit = 0x7 */ + dword |= (0x7 << 26); + } else if (compute_unit_count == 4) { + dword |= (0xf << 26); /* MaskUpdateForComputeUnit = 0xf */ + } + pci_write_config32(f4x_dev, 0x1d4, dword); + } + } +} + +static void cpu_bus_init(struct device *dev) +{ + detect_and_enable_probe_filter(dev); + detect_and_enable_cache_partitioning(dev); + 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; + } +} + +static void root_complex_finalize(void *chip_info) { +#if CONFIG(HAVE_ACPI_RESUME) && CONFIG(DIMM_DDR3) + save_mct_information_to_nvram(); +#endif +} + +struct chip_operations northbridge_amd_amdfam10_root_complex_ops = { + CHIP_NAME("AMD Family 10h/15h Root Complex") + .enable_dev = root_complex_enable_dev, + .final = root_complex_finalize, +}; diff --git a/src/northbridge/amd/amdfam10/northbridge.h b/src/northbridge/amd/amdfam10/northbridge.h new file mode 100644 index 0000000..fdfd4c8 --- /dev/null +++ b/src/northbridge/amd/amdfam10/northbridge.h @@ -0,0 +1,21 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007 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. + */ + +#ifndef NORTHBRIDGE_AMD_AMDFAM10_H +#define NORTHBRIDGE_AMD_AMDFAM10_H + +u32 amdfam10_scan_root_bus(struct device *root, u32 max); + +#endif /* NORTHBRIDGE_AMD_AMDFAM10_H */ diff --git a/src/northbridge/amd/amdfam10/nums.h b/src/northbridge/amd/amdfam10/nums.h new file mode 100644 index 0000000..771ef12 --- /dev/null +++ b/src/northbridge/amd/amdfam10/nums.h @@ -0,0 +1,36 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007 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. + */ + +#ifndef AMDFAM10_NUMS_H + +#define AMDFAM10_NUMS_H + +#if CONFIG_MAX_PHYSICAL_CPUS > 8 + #if CONFIG_MAX_PHYSICAL_CPUS > 32 + #define NODE_NUMS 64 + #else + #define NODE_NUMS 32 + #endif +#else + #define NODE_NUMS 8 +#endif + +// max HC installed at the same time. ...could be bigger than (48+24) if we have 3x4x4 +#define HC_NUMS 32 + +//it could be more bigger +#define HC_POSSIBLE_NUM 32 + +#endif diff --git a/src/southbridge/amd/sb700/Kconfig b/src/southbridge/amd/sb700/Kconfig new file mode 100644 index 0000000..58dc75a --- /dev/null +++ b/src/southbridge/amd/sb700/Kconfig @@ -0,0 +1,68 @@ +## +## This file is part of the coreboot project. +## +## 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; 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 SOUTHBRIDGE_AMD_SB700 + bool + +if SOUTHBRIDGE_AMD_SB700 + +config SOUTHBRIDGE_SPECIFIC_OPTIONS # dummy + def_bool y + select IOAPIC + select HAVE_USBDEBUG_OPTIONS + select SMBUS_HAS_AUX_CHANNELS + select HAVE_POWER_STATE_AFTER_FAILURE + select HAVE_POWER_STATE_PREVIOUS_AFTER_FAILURE + +config SOUTHBRIDGE_AMD_SB700_33MHZ_SPI + bool "Enable high speed SPI clock" + default n + help + When set, the SPI clock will run at 33MHz instead + of the compatibility mode 16.5MHz. Note that not + all ROMs are capable of 33MHz operation, so you + will need to verify this option is appropriate for + the ROM you are using. + +# Set for southbridge SP5100 which also uses SB700 driver +config SOUTHBRIDGE_AMD_SUBTYPE_SP5100 + bool + default n + +config BOOTBLOCK_SOUTHBRIDGE_INIT + string + default "southbridge/amd/sb700/bootblock.c" + +config SOUTHBRIDGE_AMD_SB700_SKIP_ISA_DMA_INIT + bool + default n + +config SOUTHBRIDGE_AMD_SB700_DISABLE_ISA_DMA + bool + default n + +config SOUTHBRIDGE_AMD_SB700_SATA_PORT_COUNT_BITFIELD + hex + default 0xf + +config EHCI_BAR + hex + default 0xfef00000 + +config HPET_MIN_TICKS + hex + default 0x14 + +endif # SOUTHBRIDGE_AMD_SB700 diff --git a/src/southbridge/amd/sb700/Makefile.inc b/src/southbridge/amd/sb700/Makefile.inc new file mode 100644 index 0000000..0a20a8c --- /dev/null +++ b/src/southbridge/amd/sb700/Makefile.inc @@ -0,0 +1,27 @@ +ifeq ($(CONFIG_SOUTHBRIDGE_AMD_SB700),y) + +ramstage-y += sb700.c +ramstage-y += usb.c +ramstage-y += lpc.c +ramstage-y += smbus.c +ramstage-y += sm.c +ramstage-y += ide.c +ramstage-y += sata.c +ramstage-y += hda.c +ramstage-y += pci.c +ramstage-$(CONFIG_HAVE_ACPI_TABLES) += fadt.c +romstage-y += reset.c +ramstage-y += reset.c +ramstage-y += spi.c + +bootblock-y += enable_usbdebug.c +romstage-y += enable_usbdebug.c +ramstage-y += enable_usbdebug.c + +romstage-y += early_setup.c +romstage-y += smbus.c + +romstage-y += ramtop.c +ramstage-y += ramtop.c + +endif diff --git a/src/southbridge/amd/sb700/bootblock.c b/src/southbridge/amd/sb700/bootblock.c new file mode 100644 index 0000000..222b33d --- /dev/null +++ b/src/southbridge/amd/sb700/bootblock.c @@ -0,0 +1,129 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2015 Timothy Pearson tpearson@raptorengineeringinc.com, Raptor Engineering + * 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; 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 <stdint.h> +#include <device/pci_ops.h> + +#define IO_MEM_PORT_DECODE_ENABLE_5 0x48 +#define IO_MEM_PORT_DECODE_ENABLE_6 0x4a +#define SPI_BASE_ADDRESS 0xa0 + +#define SPI_CONTROL_1 0xc +#define TEMPORARY_SPI_BASE_ADDRESS 0xfec10000 + +/* + * Enable 4MB (LPC) ROM access at 0xFFC00000 - 0xFFFFFFFF. + * + * Hardware should enable LPC ROM by pin straps. This function does not + * handle the theoretically possible PCI ROM, FWH, or SPI ROM configurations. + * + * The SB700 power-on default is to map 512K ROM space. + * + * Details: AMD SB700/710/750 BIOS Developer's Guide (BDG), Rev. 1.00, + * PN 43366_sb7xx_bdg_pub_1.00, June 2009, section 3.1, page 14. + */ +static void sb700_enable_rom(void) +{ + u8 reg8; + u32 dword; + pci_devfn_t dev; + + dev = PCI_DEV(0, 0x14, 3); + + reg8 = pci_io_read_config8(dev, IO_MEM_PORT_DECODE_ENABLE_5); + if (CONFIG(SPI_FLASH)) + /* Disable decode of variable LPC ROM address ranges 1 and 2. */ + reg8 &= ~((1 << 3) | (1 << 4)); + else + /* Decode variable LPC ROM address ranges 1 and 2. */ + reg8 |= (1 << 3) | (1 << 4); + pci_io_write_config8(dev, IO_MEM_PORT_DECODE_ENABLE_5, reg8); + + /* LPC ROM address range 1: */ + /* Enable LPC ROM range mirroring start at 0x000e(0000). */ + pci_io_write_config16(dev, 0x68, 0x000e); + /* Enable LPC ROM range mirroring end at 0x000f(ffff). */ + pci_io_write_config16(dev, 0x6a, 0x000f); + + /* LPC ROM address range 2: */ + /* + * Enable LPC ROM range start at: + * 0xfff8(0000): 512KB + * 0xfff0(0000): 1MB + * 0xffe0(0000): 2MB + * 0xffc0(0000): 4MB + * 0xff80(0000): 8MB + */ + pci_io_write_config16(dev, 0x6c, 0x10000 - (CONFIG_COREBOOT_ROMSIZE_KB >> 6)); + /* Enable LPC ROM range end at 0xffff(ffff). */ + pci_io_write_config16(dev, 0x6e, 0xffff); + + /* SB700 LPC Bridge 0x48. + * Turn on all LPC IO Port decode enables + */ + pci_io_write_config32(dev, 0x44, 0xffffffff); + + /* SB700 LPC Bridge 0x48. + * BIT0: Port Enable for SuperIO 0x2E-0x2F + * BIT1: Port Enable for SuperIO 0x4E-0x4F + * BIT6: Port Enable for RTC IO 0x70-0x73 + */ + reg8 = pci_io_read_config8(dev, IO_MEM_PORT_DECODE_ENABLE_5); + reg8 |= (1 << 0) | (1 << 1) | (1 << 6); + pci_io_write_config8(dev, IO_MEM_PORT_DECODE_ENABLE_5, reg8); + + /* SB700 LPC Bridge 0x4a. + * BIT5: Port Enable for Port 0x80 + */ + reg8 = pci_io_read_config8(dev, IO_MEM_PORT_DECODE_ENABLE_6); + reg8 |= (1 << 5); + pci_io_write_config8(dev, IO_MEM_PORT_DECODE_ENABLE_6, reg8); +} + +static void sb700_configure_rom(void) +{ + pci_devfn_t dev; + uint32_t dword; + + dev = PCI_DEV(0, 0x14, 3); + + if (CONFIG(SOUTHBRIDGE_AMD_SB700_33MHZ_SPI)) { + uint32_t prev_spi_cfg; + volatile uint32_t *spi_mmio; + + /* Temporarily set up SPI access to change SPI speed */ + prev_spi_cfg = dword = pci_io_read_config32(dev, SPI_BASE_ADDRESS); + dword &= ~(0x7ffffff << 5); /* SPI_BaseAddr */ + dword |= TEMPORARY_SPI_BASE_ADDRESS & (0x7ffffff << 5); + dword |= (0x1 << 1); /* SpiRomEnable = 1 */ + pci_io_write_config32(dev, SPI_BASE_ADDRESS, dword); + + spi_mmio = (void *)(TEMPORARY_SPI_BASE_ADDRESS + SPI_CONTROL_1); + dword = *spi_mmio; + dword &= ~(0x3 << 12); /* NormSpeed = 0x1 */ + dword |= (0x1 << 12); + *spi_mmio = dword; + + /* Restore previous SPI access */ + pci_io_write_config32(dev, SPI_BASE_ADDRESS, prev_spi_cfg); + } +} + +static void bootblock_southbridge_init(void) +{ + sb700_enable_rom(); + sb700_configure_rom(); +} diff --git a/src/southbridge/amd/sb700/chip.h b/src/southbridge/amd/sb700/chip.h new file mode 100644 index 0000000..fe3289d --- /dev/null +++ b/src/southbridge/amd/sb700/chip.h @@ -0,0 +1,24 @@ +/* + * This file is part of the coreboot project. + * + * 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; 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 SB700_CHIP_H +#define SB700_CHIP_H + +struct southbridge_amd_sb700_config +{ + u32 boot_switch_sata_ide : 1; +}; + +#endif /* SB700_CHIP_H */ diff --git a/src/southbridge/amd/sb700/enable_usbdebug.c b/src/southbridge/amd/sb700/enable_usbdebug.c new file mode 100644 index 0000000..4f859c6 --- /dev/null +++ b/src/southbridge/amd/sb700/enable_usbdebug.c @@ -0,0 +1,47 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2010 Advanced Micro Devices, Inc. + * Copyright (C) 2010 Uwe Hermann uwe@hermann-uwe.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. + */ + +// Use simple device model for this file even in ramstage +#define __SIMPLE_DEVICE__ + +#include <stdint.h> +#include <device/mmio.h> +#include <device/pci_ehci.h> +#include <device/pci_def.h> +#include "sb700.h" + +#define DEBUGPORT_MISC_CONTROL 0x80 + +pci_devfn_t pci_ehci_dbg_dev(unsigned int hcd_idx) +{ + if (hcd_idx == 2) + return PCI_DEV(0, 0x13, 2); + else + return PCI_DEV(0, 0x12, 2); +} + +void pci_ehci_dbg_set_port(pci_devfn_t dev, unsigned int port) +{ + u8 *base_regs = pci_ehci_base_regs(dev); + u32 reg32; + + /* Write the port number to DEBUGPORT_MISC_CONTROL[31:28]. */ + reg32 = read32(base_regs + DEBUGPORT_MISC_CONTROL); + reg32 &= ~(0xf << 28); + reg32 |= (port << 28); + reg32 |= (1 << 27); /* Enable Debug Port port number remapping. */ + write32(base_regs + DEBUGPORT_MISC_CONTROL, reg32); +} diff --git a/src/southbridge/amd/sb700/fadt.c b/src/southbridge/amd/sb700/fadt.c new file mode 100644 index 0000000..c81e644 --- /dev/null +++ b/src/southbridge/amd/sb700/fadt.c @@ -0,0 +1,162 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2010 Advanced Micro Devices, Inc. + * Copyright (C) 2015 Raptor Engineering + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* + * ACPI - create the Fixed ACPI Description Tables (FADT) + */ + +#include <string.h> +#include <console/console.h> +#include <arch/acpi.h> +#include <device/device.h> +#include <cpu/amd/powernow.h> +#include <version.h> + +#include "sb700.h" + +void acpi_create_fadt(acpi_fadt_t * fadt, acpi_facs_t * facs, void *dsdt) +{ + acpi_header_t *header = &(fadt->header); + + printk(BIOS_DEBUG, "pm_base: 0x%04x\n", SB700_ACPI_IO_BASE); + + /* Prepare the header */ + memset((void *)fadt, 0, sizeof(acpi_fadt_t)); + memcpy(header->signature, "FACP", 4); + header->length = sizeof(acpi_fadt_t); + header->revision = get_acpi_table_revision(FADT); + memcpy(header->oem_id, OEM_ID, 6); + memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8); + memcpy(header->asl_compiler_id, ASLC, 4); + header->asl_compiler_revision = asl_revision; + + fadt->firmware_ctrl = (u32) facs; + fadt->dsdt = (u32) dsdt; + /* 3=Workstation,4=Enterprise Server, 7=Performance Server */ + fadt->preferred_pm_profile = 0x03; + fadt->sci_int = 9; + /* disable system management mode by setting to 0: */ + fadt->smi_cmd = 0; + fadt->acpi_enable = 0xf0; + fadt->acpi_disable = 0xf1; + fadt->s4bios_req = 0x0; + fadt->pstate_cnt = 0xe2; + fadt->pm1a_evt_blk = ACPI_PM_EVT_BLK; + fadt->pm1b_evt_blk = 0x0000; + fadt->pm1a_cnt_blk = ACPI_PM1_CNT_BLK; + fadt->pm1b_cnt_blk = 0x0000; + fadt->pm2_cnt_blk = ACPI_PMA_CNT_BLK; + fadt->pm_tmr_blk = ACPI_PM_TMR_BLK; + fadt->gpe0_blk = ACPI_GPE0_BLK; + fadt->gpe1_blk = 0x0000; /* we don't have gpe1 block, do we? */ + + fadt->pm1_evt_len = 4; + fadt->pm1_cnt_len = 2; + fadt->pm2_cnt_len = 1; + fadt->pm_tmr_len = 4; + fadt->gpe0_blk_len = 8; + fadt->gpe1_blk_len = 0; + fadt->gpe1_base = 0; + + fadt->cst_cnt = 0xe3; + fadt->p_lvl2_lat = 101; + fadt->p_lvl3_lat = 1001; + fadt->flush_size = 0; + fadt->flush_stride = 0; + fadt->duty_offset = 1; + fadt->duty_width = 3; + fadt->day_alrm = 0; /* 0x7d these have to be */ + fadt->mon_alrm = 0; /* 0x7e added to cmos.layout */ + fadt->century = 0; /* 0x7f to make rtc alarm work */ + fadt->iapc_boot_arch = 0x3; /* See table 5-11 */ + fadt->flags = 0x0001c1a5;/* 0x25; */ + + fadt->res2 = 0; + + fadt->reset_reg.space_id = 1; + fadt->reset_reg.bit_width = 8; + fadt->reset_reg.bit_offset = 0; + fadt->reset_reg.access_size = 0; + fadt->reset_reg.addrl = 0xcf9; + fadt->reset_reg.addrh = 0x0; + + fadt->reset_value = 6; + fadt->x_firmware_ctl_l = (u32) facs; + fadt->x_firmware_ctl_h = 0; + fadt->x_dsdt_l = (u32) dsdt; + fadt->x_dsdt_h = 0; + + fadt->x_pm1a_evt_blk.space_id = 1; + fadt->x_pm1a_evt_blk.bit_width = 32; + fadt->x_pm1a_evt_blk.bit_offset = 0; + fadt->x_pm1a_evt_blk.access_size = 0; + fadt->x_pm1a_evt_blk.addrl = ACPI_PM_EVT_BLK; + fadt->x_pm1a_evt_blk.addrh = 0x0; + + fadt->x_pm1b_evt_blk.space_id = 1; + fadt->x_pm1b_evt_blk.bit_width = 4; + fadt->x_pm1b_evt_blk.bit_offset = 0; + fadt->x_pm1b_evt_blk.access_size = 0; + fadt->x_pm1b_evt_blk.addrl = 0x0; + fadt->x_pm1b_evt_blk.addrh = 0x0; + + fadt->x_pm1a_cnt_blk.space_id = 1; + fadt->x_pm1a_cnt_blk.bit_width = 16; + fadt->x_pm1a_cnt_blk.bit_offset = 0; + fadt->x_pm1a_cnt_blk.access_size = 0; + fadt->x_pm1a_cnt_blk.addrl = ACPI_PM1_CNT_BLK; + fadt->x_pm1a_cnt_blk.addrh = 0x0; + + fadt->x_pm1b_cnt_blk.space_id = 1; + fadt->x_pm1b_cnt_blk.bit_width = 2; + fadt->x_pm1b_cnt_blk.bit_offset = 0; + fadt->x_pm1b_cnt_blk.access_size = 0; + fadt->x_pm1b_cnt_blk.addrl = 0x0; + fadt->x_pm1b_cnt_blk.addrh = 0x0; + + fadt->x_pm2_cnt_blk.space_id = 1; + fadt->x_pm2_cnt_blk.bit_width = 8; + fadt->x_pm2_cnt_blk.bit_offset = 0; + fadt->x_pm2_cnt_blk.access_size = 0; + fadt->x_pm2_cnt_blk.addrl = ACPI_PMA_CNT_BLK; + fadt->x_pm2_cnt_blk.addrh = 0x0; + + fadt->x_pm_tmr_blk.space_id = 1; + fadt->x_pm_tmr_blk.bit_width = 32; + fadt->x_pm_tmr_blk.bit_offset = 0; + fadt->x_pm_tmr_blk.access_size = 0; + fadt->x_pm_tmr_blk.addrl = ACPI_PM_TMR_BLK; + fadt->x_pm_tmr_blk.addrh = 0x0; + + fadt->x_gpe0_blk.space_id = 1; + fadt->x_gpe0_blk.bit_width = 64; + fadt->x_gpe0_blk.bit_offset = 0; + fadt->x_gpe0_blk.access_size = 0; + fadt->x_gpe0_blk.addrl = ACPI_GPE0_BLK; + fadt->x_gpe0_blk.addrh = 0x0; + + fadt->x_gpe1_blk.space_id = 1; + fadt->x_gpe1_blk.bit_width = 0; + fadt->x_gpe1_blk.bit_offset = 0; + fadt->x_gpe1_blk.access_size = 0; + fadt->x_gpe1_blk.addrl = 0; + fadt->x_gpe1_blk.addrh = 0x0; + + if (CONFIG(CPU_AMD_MODEL_10XXX)) + amd_powernow_update_fadt(fadt); + + header->checksum = acpi_checksum((void *)fadt, sizeof(acpi_fadt_t)); +} diff --git a/src/southbridge/amd/sb700/ramtop.c b/src/southbridge/amd/sb700/ramtop.c new file mode 100644 index 0000000..4d26121 --- /dev/null +++ b/src/southbridge/amd/sb700/ramtop.c @@ -0,0 +1,51 @@ +/* + * This file is part of the coreboot project. + * + * 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; 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 <stdint.h> +#include <arch/io.h> +#include <arch/acpi.h> +#include <cbmem.h> +#include "sb700.h" + +int acpi_get_sleep_type(void) +{ + u16 tmp; + tmp = inw(ACPI_PM1_CNT_BLK); + return ((tmp & (7 << 10)) >> 10); +} + +void backup_top_of_low_cacheable(uintptr_t ramtop) +{ + u32 dword = (u32) ramtop; + int nvram_pos = 0xfc, i; + for (i = 0; i < 4; i++) { + outb(nvram_pos, BIOSRAM_INDEX); + outb((dword >> (8 * i)) & 0xff, BIOSRAM_DATA); + nvram_pos++; + } +} + +uintptr_t restore_top_of_low_cacheable(void) +{ + uint32_t xdata = 0; + int xnvram_pos = 0xfc, xi; + for (xi = 0; xi < 4; xi++) { + outb(xnvram_pos, BIOSRAM_INDEX); + xdata &= ~(0xff << (xi * 8)); + xdata |= inb(BIOSRAM_DATA) << (xi *8); + xnvram_pos++; + } + return xdata; +} diff --git a/src/southbridge/amd/sb700/reset.c b/src/southbridge/amd/sb700/reset.c new file mode 100644 index 0000000..9a04459 --- /dev/null +++ b/src/southbridge/amd/sb700/reset.c @@ -0,0 +1,66 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2010 - 2011 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. + */ + +// Use simple device model for this file even in ramstage +#define __SIMPLE_DEVICE__ + +#include <arch/io.h> +#include <device/pci_ops.h> +#include <reset.h> +#include <southbridge/amd/common/reset.h> + +#define HT_INIT_CONTROL 0x6C +#define HTIC_BIOSR_Detect (1<<5) + +#if CONFIG_MAX_PHYSICAL_CPUS > 32 +#define NODE_PCI(x, fn) ((x < 32)?(PCI_DEV(CONFIG_CBB,(CONFIG_CDB+x),fn)):(PCI_DEV((CONFIG_CBB-1),(CONFIG_CDB+x-32),fn))) +#else +#define NODE_PCI(x, fn) PCI_DEV(CONFIG_CBB,(CONFIG_CDB+x),fn) +#endif + +static void set_bios_reset(void) +{ + u32 nodes; + u32 htic; + pci_devfn_t dev; + int i; + + nodes = ((pci_read_config32(PCI_DEV(CONFIG_CBB, CONFIG_CDB, 0), 0x60) >> 4) & 7) + 1; + for (i = 0; i < nodes; i++) { + dev = NODE_PCI(i, 0); + htic = pci_read_config32(dev, HT_INIT_CONTROL); + htic &= ~HTIC_BIOSR_Detect; + pci_write_config32(dev, HT_INIT_CONTROL, htic); + } +} + +void do_board_reset(void) +{ + set_bios_reset(); + + /* Try rebooting through port 0xcf9 */ + /* Actually it is not a real hard_reset + * --- it only reset coherent link table, but not reset link freq and width + */ + outb((0 << 3) | (0 << 2) | (1 << 1), 0xcf9); + outb((0 << 3) | (1 << 2) | (1 << 1), 0xcf9); +} + +void do_soft_reset(void) +{ + set_bios_reset(); + /* link reset */ + outb(0x06, 0x0cf9); +} diff --git a/src/southbridge/amd/sb700/sb700.c b/src/southbridge/amd/sb700/sb700.c new file mode 100644 index 0000000..1eaf347 --- /dev/null +++ b/src/southbridge/amd/sb700/sb700.c @@ -0,0 +1,227 @@ +/* + * This file is part of the coreboot project. + * + * 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; 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 <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <device/pci_ops.h> +#include "sb700.h" +#include "chip.h" + +static struct device *find_sm_dev(struct device *dev, u32 devfn) +{ + struct device *sm_dev; + + sm_dev = pcidev_path_behind(dev->bus, devfn); + if (!sm_dev) + return sm_dev; + + if ((sm_dev->vendor != PCI_VENDOR_ID_ATI) || + ((sm_dev->device != PCI_DEVICE_ID_ATI_SB700_SM))) { + u32 id; + id = pci_read_config32(sm_dev, PCI_VENDOR_ID); + if ((id != + (PCI_VENDOR_ID_ATI | (PCI_DEVICE_ID_ATI_SB700_SM << 16)))) + { + sm_dev = 0; + } + } + + return sm_dev; +} + +void set_sm_enable_bits(struct device *sm_dev, u32 reg_pos, u32 mask, u32 val) +{ + u32 reg_old, reg; + reg = reg_old = pci_read_config32(sm_dev, reg_pos); + reg &= ~mask; + reg |= val; + if (reg != reg_old) { + pci_write_config32(sm_dev, reg_pos, reg); + } +} + +static void pmio_write_index(u16 port_base, u8 reg, u8 value) +{ + outb(reg, port_base); + outb(value, port_base + 1); +} + +static u8 pmio_read_index(u16 port_base, u8 reg) +{ + outb(reg, port_base); + return inb(port_base + 1); +} + +void pm_iowrite(u8 reg, u8 value) +{ + pmio_write_index(PM_INDEX, reg, value); +} + +u8 pm_ioread(u8 reg) +{ + return pmio_read_index(PM_INDEX, reg); +} + +void pm2_iowrite(u8 reg, u8 value) +{ + pmio_write_index(PM2_INDEX, reg, value); +} + +u8 pm2_ioread(u8 reg) +{ + return pmio_read_index(PM2_INDEX, reg); +} + +static void set_pmio_enable_bits(struct device *sm_dev, u32 reg_pos, + u32 mask, u32 val) +{ + u8 reg_old, reg; + reg = reg_old = pm_ioread(reg_pos); + reg &= ~mask; + reg |= val; + if (reg != reg_old) { + pm_iowrite(reg_pos, reg); + } +} + +void sb7xx_51xx_enable(struct device *dev) +{ + struct device *sm_dev = NULL; + struct device *bus_dev = NULL; + int index; + u32 deviceid; + u32 vendorid; + + /* struct southbridge_ati_sb700_config *conf; */ + /* conf = dev->chip_info; */ + int i; + + u32 devfn; + + printk(BIOS_DEBUG, "sb7xx_51xx_enable()\n"); + + /* + * 0:11.0 SATA bit 8 of sm_dev 0xac : 1 - enable, default + 32 * 3 + * 0:12.0 OHCI0-USB1 bit 0 of sm_dev 0x68 + * 0:12.1 OHCI1-USB1 bit 1 of sm_dev 0x68 + * 0:12.2 EHCI-USB1 bit 2 of sm_dev 0x68 + * 0:13.0 OHCI0-USB2 bit 4 of sm_dev 0x68 + * 0:13.1 OHCI1-USB2 bit 5 of sm_dev 0x68 + * 0:13.2 EHCI-USB2 bit 6 of sm_dev 0x68 + * 0:14.5 OHCI0-USB3 bit 7 of sm_dev 0x68 + * 0:14.0 SMBUS 0 + * 0:14.1 IDE 1 + * 0:14.2 HDA bit 3 of pm_io 0x59 : 1 - enable, default + 32 * 4 + * 0:14.3 LPC bit 20 of sm_dev 0x64 : 0 - disable, default + 32 * 1 + * 0:14.4 PCI 4 + */ + if (dev->device == 0x0000) { + vendorid = pci_read_config32(dev, PCI_VENDOR_ID); + deviceid = (vendorid >> 16) & 0xffff; + vendorid &= 0xffff; + } else { + vendorid = dev->vendor; + deviceid = dev->device; + } + + bus_dev = dev->bus->dev; + if ((bus_dev->vendor == PCI_VENDOR_ID_ATI) && + (bus_dev->device == PCI_DEVICE_ID_ATI_SB700_PCI)) { + devfn = (bus_dev->path.pci.devfn) & ~7; + sm_dev = find_sm_dev(bus_dev, devfn); + if (!sm_dev) + return; + + /* something under 00:01.0 */ + switch (dev->path.pci.devfn) { + case 5 << 3: + ; + } + return; + } + + i = (dev->path.pci.devfn) & ~7; + i += (3 << 3); + for (devfn = (0x14 << 3); devfn <= i; devfn += (1 << 3)) { + sm_dev = find_sm_dev(dev, devfn); + if (sm_dev) + break; + } + if (!sm_dev) + return; + + switch (dev->path.pci.devfn - (devfn - (0x14 << 3))) { + case PCI_DEVFN(0x11, 0): + index = 8; + set_sm_enable_bits(sm_dev, 0xac, 1 << index, + (dev->enabled ? 1 : 0) << index); + break; + case PCI_DEVFN(0x12, 0): + case PCI_DEVFN(0x12, 1): + case PCI_DEVFN(0x12, 2): + index = dev->path.pci.devfn & 3; + set_sm_enable_bits(sm_dev, 0x68, 1 << index, + (dev->enabled ? 1 : 0) << index); + break; + case PCI_DEVFN(0x13, 0): + case PCI_DEVFN(0x13, 1): + case PCI_DEVFN(0x13, 2): + index = (dev->path.pci.devfn & 3) + 4; + set_sm_enable_bits(sm_dev, 0x68, 1 << index, + (dev->enabled ? 1 : 0) << index); + break; + case PCI_DEVFN(0x14, 5): + index = 7; + set_sm_enable_bits(sm_dev, 0x68, 1 << index, + (dev->enabled ? 1 : 0) << index); + break; + case PCI_DEVFN(0x14, 0): + break; + case PCI_DEVFN(0x14, 1): + break; + case PCI_DEVFN(0x14, 2): + index = 3; + set_pmio_enable_bits(sm_dev, 0x59, 1 << index, + (dev->enabled ? 1 : 0) << index); + break; + case PCI_DEVFN(0x14, 3): + index = 20; + set_sm_enable_bits(sm_dev, 0x64, 1 << index, + (dev->enabled ? 1 : 0) << index); + break; + case PCI_DEVFN(0x14, 4): + break; + default: + printk(BIOS_DEBUG, "unknown dev: %s deviceid=%4x\n", dev_path(dev), + deviceid); + } +} + +#if CONFIG(SOUTHBRIDGE_AMD_SUBTYPE_SP5100) +struct chip_operations southbridge_amd_sb700_ops = { + CHIP_NAME("ATI SP5100") + .enable_dev = sb7xx_51xx_enable, +}; +#else +struct chip_operations southbridge_amd_sb700_ops = { + CHIP_NAME("ATI SB700") + .enable_dev = sb7xx_51xx_enable, +}; +#endif diff --git a/src/southbridge/amd/sb700/sb700.h b/src/southbridge/amd/sb700/sb700.h new file mode 100644 index 0000000..4b863a0 --- /dev/null +++ b/src/southbridge/amd/sb700/sb700.h @@ -0,0 +1,83 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2010 Advanced Micro Devices, Inc. + * Copyright (C) 2015 Timothy Pearson tpearson@raptorengineeringinc.com, Raptor Engineering + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * 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 SB700_H +#define SB700_H + +#include <types.h> +#include <device/device.h> + +/* Power management index/data registers */ +#define BIOSRAM_INDEX 0xcd4 +#define BIOSRAM_DATA 0xcd5 +#define PM_INDEX 0xcd6 +#define PM_DATA 0xcd7 +#define PM2_INDEX 0xcd0 +#define PM2_DATA 0xcd1 + +#define SB700_ACPI_IO_BASE 0x800 + +#define ACPI_PM_EVT_BLK (SB700_ACPI_IO_BASE + 0x00) /* 4 bytes */ +#define ACPI_PM1_CNT_BLK (SB700_ACPI_IO_BASE + 0x04) /* 2 bytes */ +#define ACPI_PMA_CNT_BLK (SB700_ACPI_IO_BASE + 0x16) /* 1 byte */ +#define ACPI_PM_TMR_BLK (SB700_ACPI_IO_BASE + 0x20) /* 4 bytes */ +#define ACPI_GPE0_BLK (SB700_ACPI_IO_BASE + 0x18) /* 8 bytes */ +#define ACPI_CPU_CONTROL (SB700_ACPI_IO_BASE + 0x08) /* 6 bytes */ +#define ACPI_CPU_P_LVL2 (ACPI_CPU_CONTROL + 0x4) /* 1 byte */ + +void pm_iowrite(u8 reg, u8 value); +u8 pm_ioread(u8 reg); +void pm2_iowrite(u8 reg, u8 value); +u8 pm2_ioread(u8 reg); + +void set_sm_enable_bits(struct device *sm_dev, u32 reg_pos, u32 mask, u32 val); + +#define REV_SB700_A11 0x11 +#define REV_SB700_A12 0x12 +#define REV_SB700_A14 0x14 +#define REV_SB700_A15 0x15 + +/* This shouldn't be called before set_sb700_revision() is called. + * Once set_sb700_revision() is called, we use get_sb700_revision(), + * the simpler one, to get the sb700 revision ID. + * The id is 0x39 if A11, 0x3A if A12, 0x3C if A14, 0x3D if A15. + * The differentiate is 0x28, isn't it? */ +#define get_sb700_revision(sm_dev) (pci_read_config8((sm_dev), 0x08) - 0x28) + + +void sb7xx_51xx_lpc_port80(void); +void sb7xx_51xx_pci_port80(void); +void sb7xx_51xx_lpc_init(void); +void sb7xx_51xx_enable_wideio(u8 wio_index, u16 base); +void sb7xx_51xx_disable_wideio(u8 wio_index); +void sb7xx_51xx_early_setup(void); +void sb7xx_51xx_before_pci_init(void); +uint16_t sb7xx_51xx_decode_last_reset(void); + + +/* allow override in mainboard.c */ +void sb7xx_51xx_setup_sata_phys(struct device *dev); +void sb7xx_51xx_setup_sata_port_indication(void *sata_bar5); +void sb7xx_51xx_enable(struct device *dev); + +void set_lpc_sticky_ctl(bool enable); + +int s3_save_nvram_early(u32 dword, int size, int nvram_pos); +int s3_load_nvram_early(int size, u32 *old_dword, int nvram_pos); + +void enable_fid_change_on_sb(u32 sbbusn, u32 sbdn); + +#endif /* SB700_H */ diff --git a/src/southbridge/amd/sr5650/Kconfig b/src/southbridge/amd/sr5650/Kconfig new file mode 100644 index 0000000..85f6b13 --- /dev/null +++ b/src/southbridge/amd/sr5650/Kconfig @@ -0,0 +1,26 @@ +## +## This file is part of the coreboot project. +## +## 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; 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 SOUTHBRIDGE_AMD_SR5650 + bool + +if SOUTHBRIDGE_AMD_SR5650 +config EXT_CONF_SUPPORT + bool "Enable PCI-E MMCONFIG support" + default y + help + Select to enable PCI-E MMCONFIG support on the SR5650. + +endif diff --git a/src/southbridge/amd/sr5650/Makefile.inc b/src/southbridge/amd/sr5650/Makefile.inc new file mode 100644 index 0000000..f695a11 --- /dev/null +++ b/src/southbridge/amd/sr5650/Makefile.inc @@ -0,0 +1,9 @@ +ifeq ($(CONFIG_SOUTHBRIDGE_AMD_SR5650),y) + +ramstage-y += sr5650.c +ramstage-y += pcie.c +ramstage-y += ht.c + +romstage-y += early_setup.c + +endif diff --git a/src/southbridge/amd/sr5650/chip.h b/src/southbridge/amd/sr5650/chip.h new file mode 100644 index 0000000..082300e --- /dev/null +++ b/src/southbridge/amd/sr5650/chip.h @@ -0,0 +1,34 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2010 Advanced Micro Devices, Inc. + * Copyright (C) 2015 Timothy Pearson tpearson@raptorengineeringinc.com, Raptor Engineering + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * 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 SR5650_CHIP_H +#define SR5650_CHIP_H + +#include <stdint.h> + +/* Member variables are defined in Config.lb. */ +struct southbridge_amd_sr5650_config +{ + u8 gpp1_configuration; /* The configuration of General Purpose Port. */ + u8 gpp2_configuration; /* The configuration of General Purpose Port. */ + u8 gpp3a_configuration; /* The configuration of General Purpose Port. */ + u16 port_enable; /* Which port is enabled? GPP(2,3,4,5,6,7,9,10,11,12,13) */ + uint32_t pcie_settling_time; /* How long to wait after link training for PCI-e devices to + * initialize before probing PCI-e busses (in microseconds). + */ +}; + +#endif /* SR5650_CHIP_H */ diff --git a/src/southbridge/amd/sr5650/rev.h b/src/southbridge/amd/sr5650/rev.h new file mode 100644 index 0000000..31e9914 --- /dev/null +++ b/src/southbridge/amd/sr5650/rev.h @@ -0,0 +1,23 @@ +/* + * This file is part of the coreboot project. + * + * 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; 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 __SR5650_REV_H__ +#define __SR5650_REV_H__ + +#define REV_SR5650_A11 0 +#define REV_SR5650_A12 1 +#define REV_SR5650_A21 2 + +#endif /* __SR5650_REV_H__ */ diff --git a/src/southbridge/amd/sr5650/sr5650.c b/src/southbridge/amd/sr5650/sr5650.c new file mode 100644 index 0000000..8131e77 --- /dev/null +++ b/src/southbridge/amd/sr5650/sr5650.c @@ -0,0 +1,931 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2010 Advanced Micro Devices, Inc. + * Copyright (C) 2015 Timothy Pearson tpearson@raptorengineeringinc.com, Raptor Engineering + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * 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 <device/mmio.h> +#include <arch/acpi_ivrs.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <device/pci_ops.h> +#include <cpu/x86/msr.h> +#include <cpu/amd/msr.h> +#include <cpu/amd/mtrr.h> +#include <stdlib.h> +#include <delay.h> +#include <option.h> +#include "sr5650.h" +#include "cmn.h" + +/* + * extern function declaration + */ +struct resource *sr5650_retrieve_cpu_mmio_resource() +{ + struct device *domain; + struct resource *res; + + for (domain = all_devices; domain; domain = domain->next) { + if (domain->bus->dev->path.type != DEVICE_PATH_DOMAIN) + continue; + res = probe_resource(domain->bus->dev, MMIO_CONF_BASE); + if (res) + return res; + } + + return NULL; +} + +/* extension registers */ +u32 pci_ext_read_config32(struct device *nb_dev, struct device *dev, u32 reg) +{ + /*get BAR3 base address for nbcfg0x1c */ + u32 addr = pci_read_config32(nb_dev, 0x1c) & ~0xF; + printk(BIOS_DEBUG, "addr=%x,bus=%x,devfn=%x\n", addr, dev->bus->secondary, + dev->path.pci.devfn); + addr |= dev->bus->secondary << 20 | /* bus num */ + dev->path.pci.devfn << 12 | reg; + return *((u32 *) addr); +} + +void pci_ext_write_config32(struct device *nb_dev, struct device *dev, u32 reg_pos, u32 mask, u32 val) +{ + u32 reg_old, reg; + + /*get BAR3 base address for nbcfg0x1c */ + u32 addr = pci_read_config32(nb_dev, 0x1c) & ~0xF; + /*printk(BIOS_DEBUG, "write: addr=%x,bus=%x,devfn=%x\n", addr, dev->bus->secondary, + dev->path.pci.devfn);*/ + addr |= dev->bus->secondary << 20 | /* bus num */ + dev->path.pci.devfn << 12 | reg_pos; + + reg = reg_old = *((u32 *) addr); + reg &= ~mask; + reg |= val; + if (reg != reg_old) { + *((u32 *) addr) = reg; + } +} + +u32 nbpcie_p_read_index(struct device *dev, u32 index) +{ + return nb_read_index((dev), NBPCIE_INDEX, (index)); +} + +void nbpcie_p_write_index(struct device *dev, u32 index, u32 data) +{ + nb_write_index((dev), NBPCIE_INDEX, (index), (data)); +} + +u32 nbpcie_ind_read_index(struct device *nb_dev, u32 index) +{ + return nb_read_index((nb_dev), NBPCIE_INDEX, (index)); +} + +void nbpcie_ind_write_index(struct device *nb_dev, u32 index, u32 data) +{ + nb_write_index((nb_dev), NBPCIE_INDEX, (index), (data)); +} + +uint32_t l2cfg_ind_read_index(struct device *nb_dev, uint32_t index) +{ + return nb_read_index((nb_dev), L2CFG_INDEX, (index)); +} + +void l2cfg_ind_write_index(struct device *nb_dev, uint32_t index, uint32_t data) +{ + nb_write_index((nb_dev), L2CFG_INDEX | (0x1 << 8), (index), (data)); +} + +uint32_t l1cfg_ind_read_index(struct device *nb_dev, uint32_t index) +{ + return nb_read_index((nb_dev), L1CFG_INDEX, (index)); +} + +void l1cfg_ind_write_index(struct device *nb_dev, uint32_t index, uint32_t data) +{ + nb_write_index((nb_dev), L1CFG_INDEX | (0x1 << 31), (index), (data)); +} + +/*********************************************************** +* To access bar3 we need to program PCI MMIO 7 in K8. +* in_out: +* 1: enable/enter k8 temp mmio base +* 0: disable/restore +***********************************************************/ +void ProgK8TempMmioBase(u8 in_out, u32 pcie_base_add, u32 mmio_base_add) +{ + /* K8 Function1 is address map */ + struct device *k8_f1 = pcidev_on_root(0x18, 1); + struct device *k8_f0 = pcidev_on_root(0x18, 0); + + if (in_out) { + u32 dword, sblk; + + /* Get SBLink value (HyperTransport I/O Hub Link ID). */ + dword = pci_read_config32(k8_f0, 0x64); + sblk = (dword >> 8) & 0x3; + + /* Fill MMIO limit/base pair. */ + pci_write_config32(k8_f1, 0xbc, + (((pcie_base_add + 0x10000000 - + 1) >> 8) & 0xffffff00) | 0x80 | (sblk << 4)); + pci_write_config32(k8_f1, 0xb8, (pcie_base_add >> 8) | 0x3); + pci_write_config32(k8_f1, 0xb4, + (((mmio_base_add + 0x10000000 - + 1) >> 8) & 0xffffff00) | (sblk << 4)); + pci_write_config32(k8_f1, 0xb0, (mmio_base_add >> 8) | 0x3); + } else { + pci_write_config32(k8_f1, 0xb8, 0); + pci_write_config32(k8_f1, 0xbc, 0); + pci_write_config32(k8_f1, 0xb0, 0); + pci_write_config32(k8_f1, 0xb4, 0); + } +} + +void PcieReleasePortTraining(struct device *nb_dev, struct device *dev, u32 port) +{ + switch (port) { + case 2: /* GPP1, bit4-5 */ + case 3: + set_nbmisc_enable_bits(nb_dev, PCIE_LINK_CFG, + 1 << (port + 2), 0 << (port + 2)); + break; + case 4: /* GPP3a, bit20-24 */ + case 5: + case 6: + case 7: + set_nbmisc_enable_bits(nb_dev, PCIE_LINK_CFG, + 1 << (port + 17), 0 << (port + 17)); + break; + case 9: /* GPP3a, bit25,26 */ + case 10: + set_nbmisc_enable_bits(nb_dev, PCIE_LINK_CFG, + 1 << (port + 16), 0 << (port + 16)); + break; + case 11: /* GPP2, bit6-7 */ + case 12: + set_nbmisc_enable_bits(nb_dev, PCIE_LINK_CFG, + 1 << (port - 5), 0 << (port - 5)); + break; + case 13: /* GPP3b, bit4 of NBMISCIND:0x2A */ + set_nbmisc_enable_bits(nb_dev, 0x2A, + 1 << 4, 0 << 4); + break; + } +} + +/******************************************************************************************************** +* Output: +* 0: no device is present. +* 1: device is present and is trained. +********************************************************************************************************/ +u8 PcieTrainPort(struct device *nb_dev, struct device *dev, u32 port) +{ + u16 count = 5000; + u32 lc_state, reg, current_link_width, lane_mask; + u8 current, res = 0; + u32 gpp_sb_sel = 0; + + switch (port) { + case 2: + case 3: + gpp_sb_sel = PCIE_CORE_INDEX_GPP1; + break; + case 4 ... 7: + case 9: + case 10: + gpp_sb_sel = PCIE_CORE_INDEX_GPP3a; + break; + case 11: + case 12: + gpp_sb_sel = PCIE_CORE_INDEX_GPP2; + break; + case 13: + gpp_sb_sel = PCIE_CORE_INDEX_GPP3b; + break; + } + + while (count--) { + udelay(40200); + lc_state = nbpcie_p_read_index(dev, 0xa5); /* lc_state */ + printk(BIOS_DEBUG, "PcieLinkTraining port=%x:lc current state=%x\n", + port, lc_state); + current = lc_state & 0x3f; /* get LC_CURRENT_STATE, bit0-5 */ + + switch (current) { + /* 0x00-0x04 means no device is present */ + case 0x06: + /* read back current link width [6:4]. */ + current_link_width = (nbpcie_p_read_index(dev, 0xA2) >> 4) & 0x7; + /* 4 means 7:4 and 15:12 + * 3 means 7:2 and 15:10 + * 2 means 7:1 and 15:9 + * ignoring the reversal case + */ + lane_mask = (0xFF << (current_link_width - 2) * 2) & 0xFF; + reg = nbpcie_ind_read_index(nb_dev, 0x65 | gpp_sb_sel); + reg |= lane_mask << 8 | lane_mask; + /* NOTE: See the comments in rs780_pcie.c + * switching_gppsb_configurations + * In CIMx 4.5.0 and RPR, 4c is done before 5 & 6. + * But in this way, a x4 device in port B (dev 4) of + * Configuration B can only be detected as x1, instead + * of x4. When the port B is being trained, the + * LC_CURRENT_STATE is 6 and the LC_LINK_WIDTH_RD is 1. + * We have to set the PCIEIND:0x65 as 0xE0E0 and reset + * the slot. Then the card seems to work in x1 mode. + */ + reg = 0xE0E0; /*I think that the lane_mask calc above is wrong, and this can't be hardcoded because the configuration changes.*/ + nbpcie_ind_write_index(nb_dev, 0x65 | gpp_sb_sel, reg); + printk(BIOS_DEBUG, "link_width=%x, lane_mask=%x", + current_link_width, lane_mask); + set_pcie_reset(); + mdelay(1); + set_pcie_dereset(); + break; + case 0x07: /* device is in compliance state (training sequence is done). Move to train the next device */ + res = 1; + count = 0; + break; + case 0x10: + reg = + pci_ext_read_config32(nb_dev, dev, + PCIE_VC0_RESOURCE_STATUS); + printk(BIOS_DEBUG, "PcieTrainPort reg=0x%x\n", reg); + /* check bit1 */ + if (reg & VC_NEGOTIATION_PENDING) { /* bit1=1 means the link needs to be re-trained. */ + /* set bit8=1, bit0-2=bit4-6 */ + u32 tmp; + reg = nbpcie_p_read_index(dev, PCIE_LC_LINK_WIDTH); + tmp = (reg >> 4) & 0x7; /* get bit4-6 */ + reg &= 0xfff8; /* clear bit0-2 */ + reg += tmp; /* merge */ + reg |= 1 << 8; + nbpcie_p_write_index(dev, PCIE_LC_LINK_WIDTH, reg); + count++; /* CIM said "keep in loop"? */ + } else { + res = 1; + count = 0; + } + break; + default: + /* CIMx Unknown Workaround - There is a device that won't train. Try to reset it. */ + /* if there are no device resets and nothing works, CIMx does a cf9 system reset (yikes!) */ + set_pcie_reset(); + mdelay(1); + set_pcie_dereset(); + res = 0; + count = 0; /* break loop */ + break; + } + } + return res; +} + +/* + * Set Top Of Memory below and above 4G. + */ +void sr5650_set_tom(struct device *nb_dev) +{ + msr_t sysmem; + + /* The system top memory in SR56X0. */ + sysmem = rdmsr(TOP_MEM); + printk(BIOS_DEBUG, "Sysmem TOM = %x_%x\n", sysmem.hi, sysmem.lo); + pci_write_config32(nb_dev, 0x90, sysmem.lo); + + sysmem = rdmsr(TOP_MEM2); + printk(BIOS_DEBUG, "Sysmem TOM2 = %x_%x\n", sysmem.hi, sysmem.lo); + htiu_write_index(nb_dev, 0x31, sysmem.hi); + htiu_write_index(nb_dev, 0x30, sysmem.lo | 1); +} + +u32 get_vid_did(struct device *dev) +{ + return pci_read_config32(dev, 0); +} + +void detect_and_enable_iommu(struct device *iommu_dev) { + uint32_t dword; + uint8_t l1_target; + unsigned char iommu; + void *mmio_base; + + iommu = 1; + get_option(&iommu, "iommu"); + + if (iommu) { + printk(BIOS_DEBUG, "Initializing IOMMU\n"); + + struct device *nb_dev = pcidev_on_root(0, 0); + + if (!nb_dev) { + printk(BIOS_WARNING, "Unable to find SR5690 device! IOMMU NOT initialized\n"); + return; + } + + mmio_base = (void *)(pci_read_config32(iommu_dev, 0x44) & + 0xffffc000); + + // if (get_nb_rev(nb_dev) == REV_SR5650_A11) { + // dword = pci_read_config32(iommu_dev, 0x6c); + // dword &= ~(0x1 << 8); + // pci_write_config32(iommu_dev, 0x6c, dword); + // } + + dword = pci_read_config32(iommu_dev, 0x50); + dword &= ~(0x1 << 22); + pci_write_config32(iommu_dev, 0x50, dword); + + dword = pci_read_config32(iommu_dev, 0x44); + dword |= 0x1; + pci_write_config32(iommu_dev, 0x44, dword); + + write32((void *)(mmio_base + 0x8), 0x0); + write32((void *)(mmio_base + 0xc), 0x08000000); + write32((void *)(mmio_base + 0x10), 0x0); + write32((void *)(mmio_base + 0x2008), 0x0); + write32((void *)(mmio_base + 0x2010), 0x0); + + /* IOMMU L1 initialization */ + for (l1_target = 0; l1_target < 6; l1_target++) { + dword = l1cfg_ind_read_index(nb_dev, (l1_target << 16) + 0xc); + dword |= (0x7 << 28); + l1cfg_ind_write_index(nb_dev, (l1_target << 16) + 0xc, dword); + + dword = l1cfg_ind_read_index(nb_dev, (l1_target << 16) + 0x7); + dword |= (0x1 << 5); + l1cfg_ind_write_index(nb_dev, (l1_target << 16) + 0x7, dword); + } + + /* IOMMU L2 initialization */ + dword = l2cfg_ind_read_index(nb_dev, 0xc); + dword |= (0x7 << 29); + l2cfg_ind_write_index(nb_dev, 0xc, dword); + + dword = l2cfg_ind_read_index(nb_dev, 0x10); + dword &= ~(0x3 << 8); + dword |= (0x2 << 8); + l2cfg_ind_write_index(nb_dev, 0x10, dword); + + dword = l2cfg_ind_read_index(nb_dev, 0x14); + dword &= ~(0x3 << 8); + dword |= (0x2 << 8); + l2cfg_ind_write_index(nb_dev, 0x14, dword); + + dword = l2cfg_ind_read_index(nb_dev, 0x18); + dword &= ~(0x3 << 8); + dword |= (0x2 << 8); + l2cfg_ind_write_index(nb_dev, 0x18, dword); + + dword = l2cfg_ind_read_index(nb_dev, 0x1c); + dword &= ~(0x3 << 8); + dword |= (0x2 << 8); + l2cfg_ind_write_index(nb_dev, 0x1c, dword); + + dword = l2cfg_ind_read_index(nb_dev, 0x50); + dword &= ~(0x3 << 8); + dword |= (0x2 << 8); + l2cfg_ind_write_index(nb_dev, 0x50, dword); + + dword = l2cfg_ind_read_index(nb_dev, 0x10); + dword |= (0x1 << 4); + l2cfg_ind_write_index(nb_dev, 0x10, dword); + + dword = l2cfg_ind_read_index(nb_dev, 0x14); + dword |= (0x1 << 4); + l2cfg_ind_write_index(nb_dev, 0x14, dword); + + dword = l2cfg_ind_read_index(nb_dev, 0x18); + dword |= (0x1 << 4); + l2cfg_ind_write_index(nb_dev, 0x18, dword); + + dword = l2cfg_ind_read_index(nb_dev, 0x1c); + dword |= (0x1 << 4); + l2cfg_ind_write_index(nb_dev, 0x1c, dword); + + dword = l2cfg_ind_read_index(nb_dev, 0x50); + dword |= (0x1 << 4); + l2cfg_ind_write_index(nb_dev, 0x50, dword); + + dword = l2cfg_ind_read_index(nb_dev, 0x6); + dword |= (0x1 << 7); + l2cfg_ind_write_index(nb_dev, 0x6, dword); + + dword = l2cfg_ind_read_index(nb_dev, 0x44); + dword |= (0x1 << 0); + l2cfg_ind_write_index(nb_dev, 0x44, dword); + +// if (get_nb_rev(nb_dev) == REV_SR5650_A21) { + dword = l2cfg_ind_read_index(nb_dev, 0x7); + dword |= (0x1 << 1); + l2cfg_ind_write_index(nb_dev, 0x7, dword); + + dword = l2cfg_ind_read_index(nb_dev, 0x44); + dword |= (0x1 << 1); + l2cfg_ind_write_index(nb_dev, 0x44, dword); + + dword = l2cfg_ind_read_index(nb_dev, 0x7); + dword |= (0x1 << 2); + l2cfg_ind_write_index(nb_dev, 0x7, dword); + + dword = l2cfg_ind_read_index(nb_dev, 0x7); + dword |= (0x1 << 3); + l2cfg_ind_write_index(nb_dev, 0x7, dword); + + dword = l2cfg_ind_read_index(nb_dev, 0x44); + dword |= (0x1 << 3); + l2cfg_ind_write_index(nb_dev, 0x44, dword); + + dword = l2cfg_ind_read_index(nb_dev, 0x7); + dword |= (0x1 << 4); + l2cfg_ind_write_index(nb_dev, 0x7, dword); + + dword = l2cfg_ind_read_index(nb_dev, 0x6); + dword |= (0x1 << 5); + l2cfg_ind_write_index(nb_dev, 0x6, dword); + + dword = l2cfg_ind_read_index(nb_dev, 0x6); + dword |= (0x1 << 6); + l2cfg_ind_write_index(nb_dev, 0x6, dword); + + dword = l2cfg_ind_read_index(nb_dev, 0x7); + dword |= (0x1 << 5); + l2cfg_ind_write_index(nb_dev, 0x7, dword); + + dword = l2cfg_ind_read_index(nb_dev, 0x44); + dword |= (0x1 << 4); + l2cfg_ind_write_index(nb_dev, 0x44, dword); + + dword = l2cfg_ind_read_index(nb_dev, 0x7); + dword |= (0x1 << 6); + l2cfg_ind_write_index(nb_dev, 0x7, dword); + + dword = l2cfg_ind_read_index(nb_dev, 0x7); + dword |= (0x1 << 7); + l2cfg_ind_write_index(nb_dev, 0x7, dword); + + dword = l2cfg_ind_read_index(nb_dev, 0x6); + dword |= (0x1 << 8); + l2cfg_ind_write_index(nb_dev, 0x6, dword); +// } + + l2cfg_ind_write_index(nb_dev, 0x52, 0xf0000002); + + dword = l2cfg_ind_read_index(nb_dev, 0x80); + dword |= (0x1 << 0); + l2cfg_ind_write_index(nb_dev, 0x80, dword); + + dword = l2cfg_ind_read_index(nb_dev, 0x30); + dword |= (0x1 << 0); + l2cfg_ind_write_index(nb_dev, 0x30, dword); + } +} + +void sr5650_iommu_read_resources(struct device *dev) +{ + unsigned char iommu; + struct resource *res; + + iommu = 1; + get_option(&iommu, "iommu"); + + /* Get the normal pci resources of this device */ + pci_dev_read_resources(dev); + + if (iommu) { + /* Request MMIO range allocation */ + res = new_resource(dev, 0x44); /* IOMMU */ + res->base = 0x0; + res->size = 0x4000; + res->limit = 0xFFFFFFFFUL; /* res->base + res->size -1; */ + res->align = 14; /* 16k alignment */ + res->gran = 14; + res->flags = IORESOURCE_MEM | IORESOURCE_RESERVE; + } + + compact_resources(dev); +} + +void sr5650_iommu_set_resources(struct device *dev) +{ + unsigned char iommu; + struct resource *res; + + iommu = 1; + get_option(&iommu, "iommu"); + + /* Get the normal pci resources of this device */ + pci_dev_read_resources(dev); + + if (iommu) { + /* Get the allocated range */ + res = find_resource(dev, 0x44); + + if (res->base == 0) { + printk(BIOS_WARNING, "Unable to allocate MMIO range to IOMMU\n"); + } + + /* Assign the range to hardware */ + pci_write_config32(dev, 0x44, res->base & 0xffffc000); + pci_write_config32(dev, 0x48, 0x0); + } + + /* Run standard resource set routine */ + pci_dev_set_resources(dev); +} + +void sr5650_iommu_enable_resources(struct device *dev) +{ + detect_and_enable_iommu(dev); +} + +void sr5650_nb_pci_table(struct device *nb_dev) +{ /* NBPOR_InitPOR function. */ + u8 temp8; + u16 temp16; + u32 temp32; + + /* Program NB PCI table. */ + temp16 = pci_read_config16(nb_dev, 0x04); + printk(BIOS_DEBUG, "NB_PCI_REG04 = %x.\n", temp16); + temp32 = pci_read_config32(nb_dev, 0x84); + printk(BIOS_DEBUG, "NB_PCI_REG84 = %x.\n", temp32); + //Reg4Ch[1]=1 (APIC_ENABLE) force CPU request with address 0xFECx_xxxx to south-bridge + //Reg4Ch[6]=1 (BMMsgEn) enable BM_Set message generation + pci_write_config8(nb_dev, 0x4c, 0x42); + temp8 = pci_read_config8(nb_dev, 0x4e); + temp8 |= 0x05; /* BAR1_ENABLE */ + pci_write_config8(nb_dev, 0x4e, temp8); + + temp32 = pci_read_config32(nb_dev, 0x4c); + printk(BIOS_DEBUG, "NB_PCI_REG4C = %x.\n", temp32); + + /* disable GFX debug. */ + temp8 = pci_read_config8(nb_dev, 0x8d); + temp8 &= ~(1<<1); + pci_write_config8(nb_dev, 0x8d, temp8); + + /* The system top memory in SR56X0. */ + sr5650_set_tom(nb_dev); + + /* Program NB HTIU table. */ + //set_htiu_enable_bits(nb_dev, 0x05, 1<<10 | 1<<9, 1<<10|1<<9); + set_htiu_enable_bits(nb_dev, 0x06, 1, 0x4203a202); + //set_htiu_enable_bits(nb_dev, 0x07, 1<<1 | 1<<2, 0x8001); + set_htiu_enable_bits(nb_dev, 0x15, 0, 1<<31 | 1<<30 | 1<<27); + set_htiu_enable_bits(nb_dev, 0x1c, 0, 0xfffe0000); + set_htiu_enable_bits(nb_dev, 0x0c, 0x3f, 1 | 1<<3); + set_htiu_enable_bits(nb_dev, 0x19, 0xfffff+(1<<31), 0x186a0+(1<<31)); + set_htiu_enable_bits(nb_dev, 0x16, 0x3f<<10, 0x7<<10); + set_htiu_enable_bits(nb_dev, 0x23, 0, 1<<28); +} + +/*********************************************** +* 0:00.0 NBCFG : +* 0:00.1 CLK : bit 0 of nb_cfg 0x4c : 0 - disable, default +* 0:01.0 P2P Internal: +* 0:02.0 P2P : bit 2 of nbmiscind 0x0c : 0 - enable, default + 32 * 2 +* 0:03.0 P2P : bit 3 of nbmiscind 0x0c : 0 - enable, default + 32 * 2 +* 0:04.0 P2P : bit 4 of nbmiscind 0x0c : 0 - enable, default + 32 * 2 +* 0:05.0 P2P : bit 5 of nbmiscind 0x0c : 0 - enable, default + 32 * 2 +* 0:06.0 P2P : bit 6 of nbmiscind 0x0c : 0 - enable, default + 32 * 2 +* 0:07.0 P2P : bit 7 of nbmiscind 0x0c : 0 - enable, default + 32 * 2 +* 0:08.0 NB2SB : bit 6 of nbmiscind 0x00 : 0 - disable, default + 32 * 1 +* case 0 will be called twice, one is by CPU in hypertransport.c line458, +* the other is by sr5650. +***********************************************/ +void sr5650_enable(struct device *dev) +{ + struct device *nb_dev = NULL, *sb_dev = NULL; + int dev_ind; + struct southbridge_amd_sr5650_config *cfg; + + printk(BIOS_INFO, "sr5650_enable: dev=%p, VID_DID=0x%x\n", dev, get_vid_did(dev)); + nb_dev = pcidev_on_root(0, 0); + if (!nb_dev) { + die("sr5650_enable: CAN NOT FIND SR5650 DEVICE, HALT!\n"); + /* NOT REACHED */ + } + cfg = (struct southbridge_amd_sr5650_config *)nb_dev->chip_info; + + /* sb_dev (dev 8) is a bridge that links to southbridge. */ + sb_dev = pcidev_on_root(8, 0); + if (!sb_dev) { + die("sr5650_enable: CAN NOT FIND SB bridge, HALT!\n"); + /* NOT REACHED */ + } + + dev_ind = dev->path.pci.devfn >> 3; + switch (dev_ind) { + case 0: /* bus0, dev0, fun0; */ + switch (dev->path.pci.devfn & 0x7) { + case 0: + printk(BIOS_INFO, "Bus-0, Dev-0, Fun-0.\n"); + enable_pcie_bar3(nb_dev); /* PCIEMiscInit */ + + config_gpp_core(nb_dev, sb_dev); + sr5650_gpp_sb_init(nb_dev, sb_dev, 8); + + sr5650_nb_pci_table(nb_dev); + break; + case 1: + printk(BIOS_INFO, "Bus-0, Dev-0, Fun-1.\n"); + break; + case 2: + printk(BIOS_INFO, "Bus-0, Dev-0, Fun-2.\n"); + break; + } + break; + + case 2: /* bus0, dev2,3 GPP1 */ + case 3: + printk(BIOS_INFO, "Bus-0, Dev-2,3, Fun-0. enable=%d\n", dev->enabled); + set_nbmisc_enable_bits(nb_dev, 0x0c, 1 << dev_ind, + (dev->enabled ? 0 : 1) << dev_ind); + if (dev->enabled) + sr5650_gpp_sb_init(nb_dev, dev, dev_ind); /* Note, dev 2,3 are generic PCIe ports. */ + break; + case 4: /* bus0, dev4-7, four GPP3a */ + case 5: + case 6: + case 7: + enable_pcie_bar3(nb_dev); /* PCIEMiscInit */ + printk(BIOS_INFO, "Bus-0, Dev-4,5,6,7, Fun-0. enable=%d\n", + dev->enabled); + set_nbmisc_enable_bits(nb_dev, 0x0c, 1 << dev_ind, + (dev->enabled ? 0 : 1) << dev_ind); + if (dev->enabled) + sr5650_gpp_sb_init(nb_dev, dev, dev_ind); + break; + case 8: /* bus0, dev8, SB */ + printk(BIOS_INFO, "Bus-0, Dev-8, Fun-0. enable=%d\n", dev->enabled); + set_nbmisc_enable_bits(nb_dev, 0x00, 1 << 6, + (dev->enabled ? 1 : 0) << 6); + if (dev->enabled) + sr5650_gpp_sb_init(nb_dev, dev, dev_ind); + disable_pcie_bar3(nb_dev); + break; + case 9: /* bus 0, dev 9,10, GPP3a */ + case 10: + printk(BIOS_INFO, "Bus-0, Dev-9, 10, Fun-0. enable=%d\n", + dev->enabled); + enable_pcie_bar3(nb_dev); /* PCIEMiscInit */ + set_nbmisc_enable_bits(nb_dev, 0x0c, 1 << (7 + dev_ind), + (dev->enabled ? 0 : 1) << (7 + dev_ind)); + if (dev->enabled) + sr5650_gpp_sb_init(nb_dev, dev, dev_ind); + /* Don't call disable_pcie_bar3(nb_dev) here, otherwise the screen will crash. */ + break; + case 11: + case 12: /* bus 0, dev 11,12, GPP2 */ + printk(BIOS_INFO, "Bus-0, Dev-11,12, Fun-0. enable=%d\n", dev->enabled); + set_nbmisc_enable_bits(nb_dev, 0x0c, 1 << (7 + dev_ind), + (dev->enabled ? 0 : 1) << (7 + dev_ind)); + if (dev->enabled) + sr5650_gpp_sb_init(nb_dev, dev, dev_ind); + break; + case 13: /* bus 0, dev 12, GPP3b */ + set_nbmisc_enable_bits(nb_dev, 0x0c, 1 << (7 + dev_ind), + (dev->enabled ? 0 : 1) << (7 + dev_ind)); + if (dev->enabled) + sr5650_gpp_sb_init(nb_dev, dev, dev_ind); + break; + default: + printk(BIOS_DEBUG, "unknown dev: %s\n", dev_path(dev)); + } + + /* Lock HWInit Register after the last device was done */ + if (dev_ind == 13) { + sr56x0_lock_hwinitreg(); + udelay(cfg->pcie_settling_time); + } +} + +static void add_ivrs_device_entries(struct device *parent, struct device *dev, + int depth, int linknum, int8_t *root_level, + unsigned long *current, uint16_t *length) +{ + uint8_t *p = (uint8_t *) *current; + + struct device *sibling; + struct bus *link; + + if ((dev->path.type == DEVICE_PATH_PCI) && + (dev->bus->secondary == 0x0) && (dev->path.pci.devfn == 0x0)) + *root_level = depth; + + if ((dev->path.type == DEVICE_PATH_PCI) && (*root_level != -1) && + (depth >= *root_level) && (dev->enabled)) { + + *p = 0; + if (depth == *root_level) { + if (dev->path.pci.devfn < (0x1 << 3)) { + /* SR5690 control device */ + } else if ((dev->path.pci.devfn >= (0x1 << 3)) && + (dev->path.pci.devfn < (0xe << 3))) { + /* SR5690 PCIe bridge device */ + } else if (dev->path.pci.devfn == (0x14 << 3)) { + /* SMBUS controller */ + p[0] = IVHD_DEV_4_BYTE_SELECT; /* Entry type */ + p[1] = dev->path.pci.devfn; /* Device */ + p[2] = dev->bus->secondary; /* Bus */ + p[3] = IVHD_DTE_LINT_1_PASS | /* Data */ + IVHD_DTE_SYS_MGT_NO_TRANS | + IVHD_DTE_NMI_PASS | + IVHD_DTE_EXT_INT_PASS | + IVHD_DTE_INIT_PASS; + } else { + /* Other southbridge device */ + p[0] = IVHD_DEV_4_BYTE_SELECT; /* Entry type */ + p[1] = dev->path.pci.devfn; /* Device */ + p[2] = dev->bus->secondary; /* Bus */ + p[3] = 0x0; /* Data */ + } + } else if ((dev->hdr_type & 0x7f) == PCI_HEADER_TYPE_NORMAL) { + /* Device behind bridge */ + if (pci_find_capability(dev, PCI_CAP_ID_PCIE)) { + /* Device is PCIe */ + p[0] = IVHD_DEV_4_BYTE_SELECT; /* Entry type */ + p[1] = dev->path.pci.devfn; /* Device */ + p[2] = dev->bus->secondary; /* Bus */ + p[3] = 0x0; /* Data */ + } else { + /* Device is legacy PCI or PCI-X */ + p[0] = IVHD_DEV_8_BYTE_ALIAS_SELECT; /* Entry */ + p[1] = dev->path.pci.devfn; /* Device */ + p[2] = dev->bus->secondary; /* Bus */ + p[3] = 0x0; /* Data */ + p[4] = 0x0; /* Reserved */ + p[5] = parent->path.pci.devfn; /* Device */ + p[6] = parent->bus->secondary; /* Bus */ + p[7] = 0x0; /* Reserved */ + } + } + + if (*p == IVHD_DEV_4_BYTE_SELECT) { + *length += 4; + *current += 4; + } else if (*p == IVHD_DEV_8_BYTE_ALIAS_SELECT) { + *length += 8; + *current += 8; + } + } + + for (link = dev->link_list; link; link = link->next) + for (sibling = link->children; sibling; + sibling = sibling->sibling) + add_ivrs_device_entries(dev, sibling, depth + 1, + depth, root_level, current, length); +} + +unsigned long acpi_fill_mcfg(unsigned long current) +{ + struct resource *res; + resource_t mmconf_base = EXT_CONF_BASE_ADDRESS; + + if (CONFIG(EXT_CONF_SUPPORT)) { + res = sr5650_retrieve_cpu_mmio_resource(); + if (res) + mmconf_base = res->base; + + current += acpi_create_mcfg_mmconfig((acpi_mcfg_mmconfig_t *)current, mmconf_base, 0x0, 0x0, 0x1f); + } + + return current; +} + +static unsigned long acpi_fill_ivrs(acpi_ivrs_t *ivrs, unsigned long current) +{ + uint8_t *p; + + struct device *nb_dev = pcidev_on_root(0, 0); + if (!nb_dev) { + printk(BIOS_WARNING, "acpi_fill_ivrs: Unable to locate SR5650 " + "device! IVRS table not generated...\n"); + return (unsigned long)ivrs; + } + + struct device *iommu_dev = pcidev_on_root(0, 2); + if (!iommu_dev) { + printk(BIOS_WARNING, "acpi_fill_ivrs: Unable to locate SR5650 " + "IOMMU device! IVRS table not generated...\n"); + return (unsigned long)ivrs; + } + + ivrs->iv_info = IVINFO_VA_SIZE_64_BITS | IVINFO_PA_SIZE_52_BITS; + + ivrs->ivhd.type = IVHD_BLOCK_TYPE_LEGACY__FIXED; + ivrs->ivhd.flags = IVHD_FLAG_ISOC | + IVHD_FLAG_RES_PASS_PW | + IVHD_FLAG_PASS_PW | + IVHD_FLAG_IOTLB_SUP; + + ivrs->ivhd.length = sizeof(struct acpi_ivrs_ivhd); + + /* BDF <bus>:00.2 */ + ivrs->ivhd.device_id = 0x2 | (nb_dev->bus->secondary << 8); + + /* Capability block 0x40 (type 0xf, "Secure device") */ + ivrs->ivhd.capability_offset = 0x40; + ivrs->ivhd.iommu_base_low = pci_read_config32(iommu_dev, 0x44) & + 0xffffc000; + ivrs->ivhd.iommu_base_high = pci_read_config32(iommu_dev, 0x48); + ivrs->ivhd.pci_segment_group = 0x0; + ivrs->ivhd.iommu_info = 0x0; + ivrs->ivhd.iommu_info |= (0x14 << IOMMU_INFO_UNIT_ID_SHIFT); + ivrs->ivhd.iommu_feature_info = 0x0; + + /* Describe HPET */ + p = (uint8_t *)current; + p[0] = IVHD_DEV_8_BYTE_EXT_SPECIAL_DEV; /* Entry type */ + p[1] = 0; /* Device */ + p[2] = 0; /* Bus */ + p[3] = IVHD_DTE_LINT_1_PASS | /* DTE */ + IVHD_DTE_LINT_0_PASS | + IVHD_DTE_SYS_MGT_INTX_NO_TRANS | + IVHD_DTE_NMI_PASS | + IVHD_DTE_EXT_INT_PASS | + IVHD_DTE_INIT_PASS; + p[4] = 0x0; /* HPET number */ + p[5] = 0x14 << 3; /* HPET device */ + p[6] = nb_dev->bus->secondary; /* HPET bus */ + p[7] = IVHD_SPECIAL_DEV_HPET; /* Variety */ + ivrs->ivhd.length += 8; + current += 8; + + /* Describe PCI devices */ + int8_t root_level = -1; + add_ivrs_device_entries(NULL, all_devices, 0, -1, &root_level, ¤t, + &ivrs->ivhd.length); + + /* Describe IOAPICs */ + unsigned long prev_current = current; + current = acpi_fill_ivrs_ioapic(ivrs, current); + ivrs->ivhd.length += (current - prev_current); + + return current; +} + +unsigned long southbridge_write_acpi_tables(struct device *device, + unsigned long current, + struct acpi_rsdp *rsdp) +{ + unsigned char iommu; + + iommu = 1; + get_option(&iommu, "iommu"); + + if (iommu) { + acpi_ivrs_t *ivrs; + + /* IVRS */ + current = ALIGN(current, 8); + printk(BIOS_DEBUG, "ACPI: * IVRS at %lx\n", current); + ivrs = (acpi_ivrs_t *) current; + acpi_create_ivrs(ivrs, acpi_fill_ivrs); + current += ivrs->header.length; + acpi_add_table(rsdp, ivrs); + } + + return current; +} + +static struct pci_operations iommu_ops_pci = { + .set_subsystem = pci_dev_set_subsystem, +}; + +static struct device_operations iommu_ops = { + .read_resources = sr5650_iommu_read_resources, + .set_resources = sr5650_iommu_set_resources, + .enable_resources = sr5650_iommu_enable_resources, + .write_acpi_tables = southbridge_write_acpi_tables, + .init = 0, + .scan_bus = 0, + .ops_pci = &iommu_ops_pci, +}; + +static const struct pci_driver ht_driver_sr5690 __pci_driver = { + .ops = &iommu_ops, + .vendor = PCI_VENDOR_ID_ATI, + .device = PCI_DEVICE_ID_AMD_SR5650_IOMMU, +}; + +struct chip_operations southbridge_amd_sr5650_ops = { + CHIP_NAME("ATI SR5650") + .enable_dev = sr5650_enable, +}; diff --git a/src/southbridge/amd/sr5650/sr5650.h b/src/southbridge/amd/sr5650/sr5650.h new file mode 100644 index 0000000..06a4279 --- /dev/null +++ b/src/southbridge/amd/sr5650/sr5650.h @@ -0,0 +1,139 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2010 Advanced Micro Devices, Inc. + * Copyright (C) 2015 Timothy Pearson tpearson@raptorengineeringinc.com, Raptor Engineering + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * 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 __SR5650_H__ +#define __SR5650_H__ + +#include <stdint.h> +#include <arch/acpi.h> +#include "chip.h" +#include "rev.h" + +typedef struct __PCIE_CFG__ { + u16 Config; + u8 ResetReleaseDelay; + u8 Gfx0Width; + u8 Gfx1Width; + u8 GfxPayload; + u8 GppPayload; + u16 PortDetect; + u8 PortHp; /* hot plug */ + u16 DbgConfig; + u32 DbgConfig2; + u8 GfxLx; + u8 GppLx; + u8 NBSBLx; + u8 PortSlotInit; + u8 Gfx0Pwr; + u8 Gfx1Pwr; + u8 GppPwr; +} PCIE_CFG; + +/* PCIE config flags */ +#define PCIE_DUALSLOT_CONFIG (1 << 0) +#define PCIE_OVERCLOCK_ENABLE (1 << 1) +#define PCIE_GPP_CLK_GATING (1 << 2) +#define PCIE_ENABLE_STATIC_DEV_REMAP (1 << 3) +#define PCIE_OFF_UNUSED_GFX_LANES (1 << 4) +#define PCIE_OFF_UNUSED_GPP_LANES (1 << 5) +#define PCIE_DISABLE_HIDE_UNUSED_PORTS (1 << 7) +#define PCIE_GFX_CLK_GATING (1 << 11) +#define PCIE_GFX_COMPLIANCE (1 << 14) +#define PCIE_GPP_COMPLIANCE (1 << 15) + +/* -------------------- ---------------------- +* NBMISCIND + ------------------- -----------------------*/ +#define PCIE_LINK_CFG 0x8 +#define PCIE_NBCFG_REG7 0x37 +#define STRAPS_OUTPUT_MUX_7 0x67 +#define STRAPS_OUTPUT_MUX_A 0x6a + +/* -------------------- ---------------------- +* PCIEIND + ------------------- -----------------------*/ +#define PCIE_CI_CNTL 0x20 +#define PCIE_LC_LINK_WIDTH 0xa2 +#define PCIE_LC_STATE0 0xa5 +#define PCIE_VC0_RESOURCE_STATUS 0x12a /* 16bit read only */ + +#define PCIE_CORE_INDEX_SB (0x05 << 16) /* see rpr 4.3.2.2, bdg 2.1 */ +#define PCIE_CORE_INDEX_GPP1 (0x04 << 16) +#define PCIE_CORE_INDEX_GPP2 (0x06 << 16) +#define PCIE_CORE_INDEX_GPP1_GPP2 (0x00 << 16) +#define PCIE_CORE_INDEX_GPP3a (0x07 << 16) +#define PCIE_CORE_INDEX_GPP3b (0x03 << 16) + +/* contents of PCIE_VC0_RESOURCE_STATUS */ +#define VC_NEGOTIATION_PENDING (1 << 1) + +#define LC_STATE_RECONFIG_GPPSB 0x10 + +/* ------------------------------------------------ +* Global variable +* ------------------------------------------------- */ +extern PCIE_CFG AtiPcieCfg; + +/* ----------------- export functions ----------------- */ +u32 nbpcie_p_read_index(struct device *dev, u32 index); +void nbpcie_p_write_index(struct device *dev, u32 index, u32 data); +u32 nbpcie_ind_read_index(struct device *nb_dev, u32 index); +void nbpcie_ind_write_index(struct device *nb_dev, u32 index, u32 data); +uint32_t l2cfg_ind_read_index(struct device *nb_dev, uint32_t index); +void l2cfg_ind_write_index(struct device *nb_dev, uint32_t index, + uint32_t data); +uint32_t l1cfg_ind_read_index(struct device *nb_dev, uint32_t index); +void l1cfg_ind_write_index(struct device *nb_dev, uint32_t index, + uint32_t data); +u32 pci_ext_read_config32(struct device *nb_dev, struct device *dev, u32 reg); +void pci_ext_write_config32(struct device *nb_dev, struct device *dev, u32 reg, + u32 mask, u32 val); +void sr5650_set_tom(struct device *nb_dev); + +unsigned long southbridge_write_acpi_tables(struct device *device, + unsigned long current, + struct acpi_rsdp *rsdp); + +void ProgK8TempMmioBase(u8 in_out, u32 pcie_base_add, u32 mmio_base_add); +void enable_pcie_bar3(struct device *nb_dev); +void disable_pcie_bar3(struct device *nb_dev); + +void enable_sr5650_dev8(void); +void sr5650_htinit(void); +void sr5650_htinit_dect_and_enable_isochronous_link(void); +void sr5650_early_setup(void); +void sr5650_before_pci_init(void); +void sr5650_enable(struct device *dev); +void sr5650_gpp_sb_init(struct device *nb_dev, struct device *dev, u32 port); +void sr5650_gfx_init(struct device *nb_dev, struct device *dev, u32 port); +void avoid_lpc_dma_deadlock(struct device *nb_dev, struct device *sb_dev); +void config_gpp_core(struct device *nb_dev, struct device *sb_dev); +void PcieReleasePortTraining(struct device *nb_dev, struct device *dev, + u32 port); +u8 PcieTrainPort(struct device *nb_dev, struct device *dev, u32 port); +void pcie_config_misc_clk(struct device *nb_dev); +void fam10_optimization(void); +void sr5650_disable_pcie_bridge(void); +u32 get_vid_did(struct device *dev); +void detect_and_enable_iommu(struct device *iommu_dev); +void sr5650_iommu_read_resources(struct device *dev); +void sr5650_iommu_set_resources(struct device *dev); +void sr5650_iommu_enable_resources(struct device *dev); +void sr5650_nb_pci_table(struct device *nb_dev); +void init_gen2(struct device *nb_dev, struct device *dev, u8 port); +void sr56x0_lock_hwinitreg(void); +struct resource * sr5650_retrieve_cpu_mmio_resource(void); +#endif /* __SR5650_H__ */