summaryrefslogtreecommitdiff
path: root/src/soc
diff options
context:
space:
mode:
authorSubrata Banik <subrata.banik@intel.com>2017-03-07 14:02:23 +0530
committerMartin Roth <martinroth@google.com>2017-03-28 16:38:42 +0200
commit03e971cd23e96b9293fc3ecc420f56ad91326cd9 (patch)
tree722243549211ec6204f190f1d2c1d825d41aa466 /src/soc
parent0637e567e13adab5b204a33fc57a54f437761f3f (diff)
downloadcoreboot-03e971cd23e96b9293fc3ecc420f56ad91326cd9.tar.xz
soc/intel/common/block: Add cache as ram init and teardown code
Create sample model for common car init and teardown programming. TEST=Booted Reef, KCRD/EVE, GLKRVP with CAR_CQOS, CAR_NEM_ENHANCED and CAR_NEM configs till post code 0x2a. Change-Id: Iffd0c3e3ca81a3d283d5f1da115222a222e6b157 Signed-off-by: Subrata Banik <subrata.banik@intel.com> Reviewed-on: https://review.coreboot.org/18381 Tested-by: build bot (Jenkins) Reviewed-by: Martin Roth <martinroth@google.com>
Diffstat (limited to 'src/soc')
-rw-r--r--src/soc/intel/common/block/cpu/Kconfig32
-rw-r--r--src/soc/intel/common/block/cpu/Makefile.inc3
-rw-r--r--src/soc/intel/common/block/cpu/car/cache_as_ram.S (renamed from src/soc/intel/skylake/bootblock/cache_as_ram.S)259
-rw-r--r--src/soc/intel/common/block/cpu/car/exit_car.S96
-rw-r--r--src/soc/intel/skylake/Kconfig26
-rw-r--r--src/soc/intel/skylake/Makefile.inc1
-rw-r--r--src/soc/intel/skylake/include/soc/car_teardown.S54
-rw-r--r--src/soc/intel/skylake/romstage/car_stage_fsp20.S3
8 files changed, 367 insertions, 107 deletions
diff --git a/src/soc/intel/common/block/cpu/Kconfig b/src/soc/intel/common/block/cpu/Kconfig
new file mode 100644
index 0000000000..7b78c53ea7
--- /dev/null
+++ b/src/soc/intel/common/block/cpu/Kconfig
@@ -0,0 +1,32 @@
+config SOC_INTEL_COMMON_BLOCK_CAR
+ bool
+ default n
+ help
+ This option allows you to select how cache-as-ram (CAR) is set up.
+
+config INTEL_CAR_NEM
+ bool
+ default n
+ help
+ Traditionally, CAR is set up by using Non-Evict mode. This method
+ does not allow CAR and cache to co-exist, because cache fills are
+ blocked in NEM.
+
+config INTEL_CAR_CQOS
+ bool
+ default n
+ help
+ Cache Quality of Service allows more fine-grained control of cache
+ usage. As result, it is possible to set up a portion of L2 cache for
+ CAR and use the remainder for actual caching.
+
+config INTEL_CAR_NEM_ENHANCED
+ bool
+ default n
+ help
+ A current limitation of NEM (Non-Evict mode) is that code and data sizes
+ are derived from the requirement to not write out any modified cache line.
+ With NEM, if there is no physical memory behind the cached area,
+ the modified data will be lost and NEM results will be inconsistent.
+ ENHANCED NEM guarantees that modified data is always
+ kept in cache while clean data is replaced.
diff --git a/src/soc/intel/common/block/cpu/Makefile.inc b/src/soc/intel/common/block/cpu/Makefile.inc
new file mode 100644
index 0000000000..abdff2f58b
--- /dev/null
+++ b/src/soc/intel/common/block/cpu/Makefile.inc
@@ -0,0 +1,3 @@
+bootblock-$(CONFIG_SOC_INTEL_COMMON_BLOCK_CAR) += car/cache_as_ram.S
+postcar-$(CONFIG_SOC_INTEL_COMMON_BLOCK_CAR) += car/exit_car.S
+romstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_CAR) += car/exit_car.S
diff --git a/src/soc/intel/skylake/bootblock/cache_as_ram.S b/src/soc/intel/common/block/cpu/car/cache_as_ram.S
index 04abba65fd..79c5c77d27 100644
--- a/src/soc/intel/skylake/bootblock/cache_as_ram.S
+++ b/src/soc/intel/common/block/cpu/car/cache_as_ram.S
@@ -14,17 +14,13 @@
*
*/
+#include <commonlib/helpers.h>
#include <cpu/x86/cache.h>
#include <cpu/x86/cr.h>
#include <cpu/x86/mtrr.h>
#include <cpu/x86/post_code.h>
#include <rules.h>
-
-#define IA32_PQR_ASSOC 0x0c8f
-#define IA32_L3_MASK_1 0x0c91
-#define IA32_L3_MASK_2 0x0c92
-#define CACHE_INIT_VALUE 0
-#define MSR_EVICT_CTL 0x2e0
+#include <intelblocks/msr.h>
.global bootblock_pre_c_entry
bootblock_pre_c_entry:
@@ -42,7 +38,7 @@ check_for_clean_reset:
and $(MTRR_DEF_TYPE_EN | MTRR_DEF_TYPE_FIX_EN), %eax
cmp $0, %eax
jz no_reset
- /* perform soft reset */
+ /* perform warm reset */
movw $0xcf9, %dx
movb $0x06, %al
outb %al, %dx
@@ -54,6 +50,7 @@ no_reset:
mov $fixed_mtrr_list_size, %ebx
xor %eax, %eax
xor %edx, %edx
+
clear_fixed_mtrr:
add $-2, %ebx
movzwl fixed_mtrr_list(%ebx), %ecx
@@ -107,6 +104,7 @@ clear_var_mtrr:
post_code(0x24)
+#if ((CONFIG_DCACHE_RAM_SIZE & (CONFIG_DCACHE_RAM_SIZE - 1)) == 0)
/* Configure CAR region as write-back (WB) */
mov $MTRR_PHYS_BASE(0), %ecx
mov $CONFIG_DCACHE_RAM_BASE, %eax
@@ -120,8 +118,40 @@ clear_var_mtrr:
dec %eax
not %eax
or $MTRR_PHYS_MASK_VALID, %eax
+ movl %esi, %edx /* edx <- MTRR_PHYS_MASK_HIGH */
+ wrmsr
+#elif (CONFIG_DCACHE_RAM_SIZE == 768 * KiB) /* 768 KiB */
+ /* Configure CAR region as write-back (WB) */
+ mov $MTRR_PHYS_BASE(0), %ecx
+ mov $CONFIG_DCACHE_RAM_BASE, %eax
+ or $MTRR_TYPE_WRBACK, %eax
+ xor %edx,%edx
+ wrmsr
+
+ mov $MTRR_PHYS_MASK(0), %ecx
+ mov $(512 * KiB), %eax /* size mask */
+ dec %eax
+ not %eax
+ or $MTRR_PHYS_MASK_VALID, %eax
+ movl %esi, %edx /* edx <- MTRR_PHYS_MASK_HIGH */
+ wrmsr
+
+ mov $MTRR_PHYS_BASE(1), %ecx
+ mov $(CONFIG_DCACHE_RAM_BASE + 512 * KiB), %eax
+ or $MTRR_TYPE_WRBACK, %eax
+ xor %edx,%edx
wrmsr
+ mov $MTRR_PHYS_MASK(1), %ecx
+ mov $(256 * KiB), %eax /* size mask */
+ dec %eax
+ not %eax
+ or $MTRR_PHYS_MASK_VALID, %eax
+ movl %esi, %edx /* edx <- MTRR_PHYS_MASK_HIGH */
+ wrmsr
+#else
+#error "DCACHE_RAM_SIZE is not a power of 2 and setup code is missing"
+#endif
post_code(0x25)
/* Enable variable MTRRs */
@@ -136,6 +166,168 @@ clear_var_mtrr:
invd
mov %eax, %cr0
+#if IS_ENABLED(CONFIG_INTEL_CAR_NEM)
+ jmp car_nem
+#elif IS_ENABLED(CONFIG_INTEL_CAR_CQOS)
+ jmp car_cqos
+#elif IS_ENABLED(CONFIG_INTEL_CAR_NEM_ENHANCED)
+ jmp car_nem_enhanced
+#else
+ jmp .halt_forever /* In case nothing has selected */
+#endif
+
+.global car_init_done
+car_init_done:
+
+ post_code(0x29)
+
+ /* Setup bootblock stack */
+ mov $_car_stack_end, %esp
+
+ /*push TSC value to stack*/
+ movd %mm2, %eax
+ pushl %eax /* tsc[63:32] */
+ movd %mm1, %eax
+ pushl %eax /* tsc[31:0] */
+
+before_carstage:
+ post_code(0x2A)
+
+ call bootblock_c_entry
+ /* Never reached */
+
+.halt_forever:
+ post_code(POST_DEAD_CODE)
+ hlt
+ jmp .halt_forever
+
+fixed_mtrr_list:
+ .word MTRR_FIX_64K_00000
+ .word MTRR_FIX_16K_80000
+ .word MTRR_FIX_16K_A0000
+ .word MTRR_FIX_4K_C0000
+ .word MTRR_FIX_4K_C8000
+ .word MTRR_FIX_4K_D0000
+ .word MTRR_FIX_4K_D8000
+ .word MTRR_FIX_4K_E0000
+ .word MTRR_FIX_4K_E8000
+ .word MTRR_FIX_4K_F0000
+ .word MTRR_FIX_4K_F8000
+fixed_mtrr_list_size = . - fixed_mtrr_list
+
+#if IS_ENABLED(CONFIG_INTEL_CAR_NEM)
+.global car_nem
+car_nem:
+ /* Disable cache eviction (setup stage) */
+ mov $MSR_EVICT_CTL, %ecx
+ rdmsr
+ or $0x1, %eax
+ wrmsr
+
+ post_code(0x26)
+
+ /* Clear the cache memory region. This will also fill up the cache */
+ movl $CONFIG_DCACHE_RAM_BASE, %edi
+ movl $CONFIG_DCACHE_RAM_SIZE, %ecx
+ shr $0x02, %ecx
+ xor %eax, %eax
+ cld
+ rep stosl
+
+ post_code(0x27)
+
+ /* Disable cache eviction (run stage) */
+ mov $MSR_EVICT_CTL, %ecx
+ rdmsr
+ or $0x2, %eax
+ wrmsr
+
+ post_code(0x28)
+
+ jmp car_init_done
+
+#elif IS_ENABLED(CONFIG_INTEL_CAR_CQOS)
+.global car_cqos
+car_cqos:
+ /*
+ * Disable both L1 and L2 prefetcher. For yet-to-understood reason,
+ * prefetchers slow down filling cache with rep stos in CQOS mode.
+ */
+ mov $MSR_PREFETCH_CTL, %ecx
+ rdmsr
+ or $(PREFETCH_L1_DISABLE | PREFETCH_L2_DISABLE), %eax
+ wrmsr
+
+#if (CONFIG_DCACHE_RAM_SIZE == CONFIG_L2_CACHE_SIZE)
+/*
+ * If CAR size is set to full L2 size, mask is calculated as all-zeros.
+ * This is not supported by the CPU/uCode.
+ */
+#error "CQOS CAR may not use whole L2 cache area"
+#endif
+
+ /* Calculate how many bits to be used for CAR */
+ xor %edx, %edx
+ mov $CONFIG_DCACHE_RAM_SIZE, %eax /* dividend */
+ mov $CONFIG_CACHE_QOS_SIZE_PER_BIT, %ecx /* divisor */
+ div %ecx /* result is in eax */
+ mov %eax, %ecx /* save to ecx */
+ mov $1, %ebx
+ shl %cl, %ebx
+ sub $1, %ebx /* resulting mask is is in ebx */
+
+ /* Set this mask for initial cache fill */
+ mov $MSR_L2_QOS_MASK(0), %ecx
+ rdmsr
+ mov %bl, %al
+ wrmsr
+
+ /* Set CLOS selector to 0 */
+ mov $MSR_IA32_PQR_ASSOC, %ecx
+ rdmsr
+ and $~IA32_PQR_ASSOC_MASK, %edx /* select mask 0 */
+ wrmsr
+
+ /* We will need to block CAR region from evicts */
+ mov $MSR_L2_QOS_MASK(1), %ecx
+ rdmsr
+ /* Invert bits that are to be used for cache */
+ mov %bl, %al
+ xor $~0, %al /* invert 8 bits */
+ wrmsr
+
+ post_code(0x26)
+
+ /* Clear the cache memory region. This will also fill up the cache */
+ movl $CONFIG_DCACHE_RAM_BASE, %edi
+ movl $CONFIG_DCACHE_RAM_SIZE, %ecx
+ shr $0x02, %ecx
+ xor %eax, %eax
+ cld
+ rep stosl
+
+ post_code(0x27)
+
+ /* Cache is populated. Use mask 1 that will block evicts */
+ mov $MSR_IA32_PQR_ASSOC, %ecx
+ rdmsr
+ and $~IA32_PQR_ASSOC_MASK, %edx /* clear index bits first */
+ or $1, %edx /* select mask 1 */
+ wrmsr
+
+ /* Enable prefetchers */
+ mov $MSR_PREFETCH_CTL, %ecx
+ rdmsr
+ and $~(PREFETCH_L1_DISABLE | PREFETCH_L2_DISABLE), %eax
+ wrmsr
+
+ post_code(0x28)
+
+ jmp car_init_done
+
+#elif IS_ENABLED(CONFIG_INTEL_CAR_NEM_ENHANCED)
+.global car_nem_enhanced
+car_nem_enhanced:
/* Disable cache eviction (setup stage) */
mov $MSR_EVICT_CTL, %ecx
rdmsr
@@ -188,7 +380,7 @@ find_llc_subleaf:
*/
shl %cl, %eax
subl $0x02, %eax
- movl $IA32_L3_MASK_1, %ecx
+ movl $MSR_IA32_L3_MASK_1, %ecx
xorl %edx, %edx
wrmsr
/*
@@ -197,12 +389,12 @@ find_llc_subleaf:
* For SKL SOC, data size remains 256K consistently.
* Hence, creating 1-way associative cache for Data
*/
- mov $IA32_L3_MASK_2, %ecx
+ mov $MSR_IA32_L3_MASK_2, %ecx
mov $0x01, %eax
xorl %edx, %edx
wrmsr
/*
- * Set IA32_PQR_ASSOC = 0x02
+ * Set MSR_IA32_PQR_ASSOC = 0x02
*
* Possible values:
* 0: Default value, no way mask should be applied
@@ -210,7 +402,7 @@ find_llc_subleaf:
* 2: Apply way mask 2 to LLC
* 3: Shouldn't be use in NEM Mode
*/
- movl $IA32_PQR_ASSOC, %ecx
+ movl $MSR_IA32_PQR_ASSOC, %ecx
movl $0x02, %eax
xorl %edx, %edx
wrmsr
@@ -218,15 +410,15 @@ find_llc_subleaf:
movl $CONFIG_DCACHE_RAM_BASE, %edi
movl $CONFIG_DCACHE_RAM_SIZE, %ecx
shr $0x02, %ecx
- movl $CACHE_INIT_VALUE, %eax
+ xor %eax, %eax
cld
rep stosl
/*
- * Set IA32_PQR_ASSOC = 0x01
+ * Set MSR_IA32_PQR_ASSOC = 0x01
* At this stage we apply LLC_WAY_MASK_1 to the cache.
* i.e. way 0 is protected from eviction.
*/
- movl $IA32_PQR_ASSOC, %ecx
+ movl $MSR_IA32_PQR_ASSOC, %ecx
movl $0x01, %eax
xorl %edx, %edx
wrmsr
@@ -242,42 +434,7 @@ find_llc_subleaf:
orl $0x02, %eax
wrmsr
-car_init_done:
-
post_code(0x28)
- /* Setup bootblock stack */
- mov $_car_stack_end, %esp
-
- post_code(0x29)
-
- /*push TSC value to stack*/
- movd %mm2, %eax
- pushl %eax /* tsc[63:32] */
- movd %mm1, %eax
- pushl %eax /* tsc[31:0] */
-
-before_carstage:
- post_code(0x2A)
-
- call bootblock_c_entry
- /* Never reached */
-
-.halt_forever:
- post_code(POST_DEAD_CODE)
- hlt
- jmp .halt_forever
-
-fixed_mtrr_list:
- .word MTRR_FIX_64K_00000
- .word MTRR_FIX_16K_80000
- .word MTRR_FIX_16K_A0000
- .word MTRR_FIX_4K_C0000
- .word MTRR_FIX_4K_C8000
- .word MTRR_FIX_4K_D0000
- .word MTRR_FIX_4K_D8000
- .word MTRR_FIX_4K_E0000
- .word MTRR_FIX_4K_E8000
- .word MTRR_FIX_4K_F0000
- .word MTRR_FIX_4K_F8000
-fixed_mtrr_list_size = . - fixed_mtrr_list
+ jmp car_init_done
+#endif
diff --git a/src/soc/intel/common/block/cpu/car/exit_car.S b/src/soc/intel/common/block/cpu/car/exit_car.S
new file mode 100644
index 0000000000..15e7f17358
--- /dev/null
+++ b/src/soc/intel/common/block/cpu/car/exit_car.S
@@ -0,0 +1,96 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2017 Intel Corp.
+ *
+ * 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/cr.h>
+#include <intelblocks/msr.h>
+
+.text
+.global chipset_teardown_car
+chipset_teardown_car:
+
+ /*
+ * Retrieve return address from stack as it will get trashed below if
+ * execution is utilizing the cache-as-ram stack.
+ */
+ pop %ebx
+
+ /* Disable MTRRs. */
+ mov $(MTRR_DEF_TYPE_MSR), %ecx
+ rdmsr
+ and $(~(MTRR_DEF_TYPE_EN | MTRR_DEF_TYPE_FIX_EN)), %eax
+ wrmsr
+
+#if IS_ENABLED(CONFIG_INTEL_CAR_NEM)
+.global car_nem_teardown
+car_nem_teardown:
+
+ /* invalidate cache contents. */
+ invd
+
+ /* Knock down bit 1 then bit 0 of NEM control not combining steps. */
+ mov $(MSR_EVICT_CTL), %ecx
+ rdmsr
+ and $(~(1 << 1)), %eax
+ wrmsr
+ and $(~(1 << 0)), %eax
+ wrmsr
+
+#elif IS_ENABLED(CONFIG_INTEL_CAR_CQOS)
+.global car_cqos_teardown
+car_cqos_teardown:
+
+ /* Go back to all-evicting mode, set both masks to all-1s */
+ mov $MSR_L2_QOS_MASK(0), %ecx
+ rdmsr
+ mov $~0, %al
+ wrmsr
+
+ mov $MSR_L2_QOS_MASK(1), %ecx
+ rdmsr
+ mov $~0, %al
+ wrmsr
+
+ /* Reset CLOS selector to 0 */
+ mov $MSR_IA32_PQR_ASSOC, %ecx
+ rdmsr
+ and $~IA32_PQR_ASSOC_MASK, %edx
+ wrmsr
+
+#elif IS_ENABLED(CONFIG_INTEL_CAR_NEM_ENHANCED)
+.global car_nem_enhanced_teardown
+car_nem_enhanced_teardown:
+
+ /* invalidate cache contents. */
+ invd
+
+ /* Knock down bit 1 then bit 0 of NEM control not combining steps. */
+ mov $(MSR_EVICT_CTL), %ecx
+ rdmsr
+ and $(~(1 << 1)), %eax
+ wrmsr
+ and $(~(1 << 0)), %eax
+ wrmsr
+
+ /* Reset CLOS selector to 0 */
+ mov $MSR_IA32_PQR_ASSOC, %ecx
+ rdmsr
+ and $~IA32_PQR_ASSOC_MASK, %edx
+ wrmsr
+#endif
+
+ /* Return to caller. */
+ jmp *%ebx
diff --git a/src/soc/intel/skylake/Kconfig b/src/soc/intel/skylake/Kconfig
index a56d0444de..ebdcbe3a24 100644
--- a/src/soc/intel/skylake/Kconfig
+++ b/src/soc/intel/skylake/Kconfig
@@ -255,6 +255,32 @@ config NHLT_MAX98927
help
Include DSP firmware settings for max98927 amplifier.
+choice
+ prompt "Cache-as-ram implementation"
+ default CAR_NEM_ENHANCED
+ help
+ This option allows you to select how cache-as-ram (CAR) is set up.
+
+config CAR_NEM_ENHANCED
+ bool "Enhanced Non-evict mode"
+ select SOC_INTEL_COMMON_BLOCK_CAR
+ select INTEL_CAR_NEM_ENHANCED
+ help
+ A current limitation of NEM (Non-Evict mode) is that code and data sizes
+ are derived from the requirement to not write out any modified cache line.
+ With NEM, if there is no physical memory behind the cached area,
+ the modified data will be lost and NEM results will be inconsistent.
+ ENHANCED NEM guarantees that modified data is always
+ kept in cache while clean data is replaced.
+
+config USE_SKYLAKE_FSP_CAR
+ bool "Use FSP CAR"
+ select FSP_CAR
+ help
+ Use FSP APIs to initialize & tear Down the Cache-As-Ram.
+
+endchoice
+
config SKIP_FSP_CAR
bool "Skip cache as RAM setup in FSP"
default y
diff --git a/src/soc/intel/skylake/Makefile.inc b/src/soc/intel/skylake/Makefile.inc
index 1d5d89f3e5..49f818d2ff 100644
--- a/src/soc/intel/skylake/Makefile.inc
+++ b/src/soc/intel/skylake/Makefile.inc
@@ -10,7 +10,6 @@ subdirs-y += ../../../cpu/x86/smm
subdirs-y += ../../../cpu/x86/tsc
bootblock-y += bootblock/bootblock.c
-bootblock-y += bootblock/cache_as_ram.S
bootblock-y += bootblock/cpu.c
bootblock-y += bootblock/i2c.c
bootblock-y += bootblock/pch.c
diff --git a/src/soc/intel/skylake/include/soc/car_teardown.S b/src/soc/intel/skylake/include/soc/car_teardown.S
deleted file mode 100644
index 315b3c1deb..0000000000
--- a/src/soc/intel/skylake/include/soc/car_teardown.S
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * This file is part of the coreboot project.
- *
- * Copyright (C) 2013-2014 Sage Electronic Engineering, LLC.
- * Copyright (C) 2016 Intel Corp.
- *
- * 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.
- *
- */
-
-.equ IA32_PQR_ASSOC, 0x0c8f
-
- /* Disable MTRR by clearing the IA32_MTRR_DEF_TYPE MSR E flag. */
- movl $MTRR_DEF_TYPE_MSR, %ecx
- rdmsr
- andl $(~MTRR_DEF_TYPE_EN), %eax
- wrmsr
-
- /* Invalidate Cache */
- invd
-
- /*
- * Disable No-Eviction Mode Run State by clearing
- * NO_EVICT_MODE MSR 2E0h bit [1] = 0
- */
- movl $0x000002E0, %ecx
- rdmsr
- andl $~(0x2), %eax
- wrmsr
-
- /*
- * Disable No-Eviction Mode Setup State by clearing
- * NO_EVICT_MODE MSR 2E0h bit [0] = 0
- */
- rdmsr
- andl $~(0x1), %eax
- wrmsr
-
- /*
- * Set IA32_PQR_ASSOC = 0x00
- * This step guarantees that no protected way remain in LLC cache,
- * all the ways are open for the evictions.
- */
- movl $IA32_PQR_ASSOC, %ecx
- movl $0x00, %eax
- xorl %edx, %edx
- wrmsr
diff --git a/src/soc/intel/skylake/romstage/car_stage_fsp20.S b/src/soc/intel/skylake/romstage/car_stage_fsp20.S
index c6401fa597..5ef8bd61bf 100644
--- a/src/soc/intel/skylake/romstage/car_stage_fsp20.S
+++ b/src/soc/intel/skylake/romstage/car_stage_fsp20.S
@@ -37,7 +37,8 @@ car_stage_entry:
/* Switch to the stack in RAM */
movl %eax, %esp
- #include <soc/car_teardown.S>
+ /* chipset_teardown_car() is expected to disable cache-as-ram. */
+ call chipset_teardown_car
/* Display the MTRRs */
call soc_display_mtrrs