diff mbox

[U-Boot,21/39] x86: chromebook_link: Implement CAR support (cache as RAM)

Message ID 1415305231-30180-22-git-send-email-sjg@chromium.org
State Superseded
Delegated to: Simon Glass
Headers show

Commit Message

Simon Glass Nov. 6, 2014, 8:20 p.m. UTC
Add support for CAR so that we have memory to use prior to DRAM init.
On link there is a total of 128KB of CAR available, although some is
used for the memory reference code.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

 arch/x86/Kconfig                     |  16 ++++
 arch/x86/cpu/ivybridge/car.S         | 156 ++++++++++++++++++++++++++++++++++-
 arch/x86/cpu/ivybridge/cpu.c         |   2 +
 arch/x86/include/asm/mtrr.h          | 121 +++++++++++++++++++++++++++
 arch/x86/include/asm/post.h          |  13 ++-
 board/google/chromebook_link/Kconfig |  12 +++
 6 files changed, 318 insertions(+), 2 deletions(-)
 create mode 100644 arch/x86/include/asm/mtrr.h

Comments

Bin Meng Nov. 7, 2014, 2:07 p.m. UTC | #1
Hi Simon,

On Fri, Nov 7, 2014 at 4:20 AM, Simon Glass <sjg@chromium.org> wrote:
> Add support for CAR so that we have memory to use prior to DRAM init.
> On link there is a total of 128KB of CAR available, although some is
> used for the memory reference code.
>
> Signed-off-by: Simon Glass <sjg@chromium.org>
> ---
>
>  arch/x86/Kconfig                     |  16 ++++
>  arch/x86/cpu/ivybridge/car.S         | 156 ++++++++++++++++++++++++++++++++++-
>  arch/x86/cpu/ivybridge/cpu.c         |   2 +
>  arch/x86/include/asm/mtrr.h          | 121 +++++++++++++++++++++++++++
>  arch/x86/include/asm/post.h          |  13 ++-
>  board/google/chromebook_link/Kconfig |  12 +++
>  6 files changed, 318 insertions(+), 2 deletions(-)
>  create mode 100644 arch/x86/include/asm/mtrr.h
>
> diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
> index d9ce129..73fe8b2 100644
> --- a/arch/x86/Kconfig
> +++ b/arch/x86/Kconfig
> @@ -34,6 +34,22 @@ config TARGET_CHROMEBOOK_LINK
>
>  endchoice
>
> +config RAMBASE
> +       hex
> +       default 0x100000
> +
> +config RAMTOP
> +       hex
> +       default 0x200000
> +
> +config XIP_ROM_SIZE
> +       hex
> +       default 0x10000
> +
> +config CPU_ADDR_BITS
> +       int
> +       default 36
> +
>  config ROM_SIZE
>         hex
>         default 0x800000
> diff --git a/arch/x86/cpu/ivybridge/car.S b/arch/x86/cpu/ivybridge/car.S
> index 0480813..391f6df 100644
> --- a/arch/x86/cpu/ivybridge/car.S
> +++ b/arch/x86/cpu/ivybridge/car.S
> @@ -12,9 +12,163 @@
>   */
>
>  #include <common.h>
> +#include <asm/mtrr.h>
> +#include <asm/post.h>
> +#include <asm/processor-flags.h>
> +
> +#define MTRRphysBase_MSR(reg) (0x200 + 2 * (reg))
> +#define MTRRphysMask_MSR(reg) (0x200 + 2 * (reg) + 1)

Should these macros be all capital?

> +#define CACHE_AS_RAM_SIZE      CONFIG_DCACHE_RAM_SIZE
> +#define CACHE_AS_RAM_BASE      CONFIG_DCACHE_RAM_BASE
> +
> +/* Cache 4GB - MRC_SIZE_KB for MRC */
> +#define CACHE_MRC_BYTES        ((CONFIG_CACHE_MRC_SIZE_KB << 10) - 1)
> +#define CACHE_MRC_BASE         (0xFFFFFFFF - CACHE_MRC_BYTES)
> +#define CACHE_MRC_MASK         (~CACHE_MRC_BYTES)
> +
> +#define CPU_PHYSMASK_HI        (1 << (CONFIG_CPU_ADDR_BITS - 32) - 1)
> +
> +#define NoEvictMod_MSR 0x2e0

Ditto.

>         /* Note: ebp must not be touched in this code */

I think mentioning ebp holds the value of BIST would help more?

>  .globl car_init
>  car_init:
> -       /* TODO: Add cache-as-RAM init here */
> +       post_code(POST_CAR_START)
> +
> +       /* Send INIT IPI to all excluding ourself */
> +       movl    $0x000C4500, %eax
> +       movl    $0xFEE00300, %esi
> +       movl    %eax, (%esi)
> +
> +       /* All CPUs need to be in Wait for SIPI state */
> +wait_for_sipi:
> +       movl    (%esi), %eax
> +       bt      $12, %eax
> +       jc      wait_for_sipi

Is this a must to send INIT IPI before CAR initialization?

> +       post_code(POST_CAR_SIPI)
> +       /* Zero out all fixed range and variable range MTRRs */
> +       movl    $mtrr_table, %esi
> +       movl    $((mtrr_table_end - mtrr_table) / 2), %edi
> +       xorl    %eax, %eax
> +       xorl    %edx, %edx
> +clear_mtrrs:
> +       movw    (%esi), %bx
> +       movzx   %bx, %ecx
> +       wrmsr
> +       add     $2, %esi
> +       dec     %edi
> +       jnz     clear_mtrrs
> +
> +       post_code(POST_CAR_MTRR)
> +       /* Configure the default memory type to uncacheable */
> +       movl    $MTRRdefType_MSR, %ecx
> +       rdmsr
> +       andl    $(~0x00000cff), %eax
> +       wrmsr
> +
> +       post_code(POST_CAR_UNCACHEABLE)
> +       /* Set Cache-as-RAM base address */
> +       movl    $(MTRRphysBase_MSR(0)), %ecx
> +       movl    $(CACHE_AS_RAM_BASE | MTRR_TYPE_WRBACK), %eax
> +       xorl    %edx, %edx
> +       wrmsr
> +
> +       post_code(POST_CAR_BASE_ADDRESS)
> +       /* Set Cache-as-RAM mask */
> +       movl    $(MTRRphysMask_MSR(0)), %ecx
> +       movl    $(~(CACHE_AS_RAM_SIZE - 1) | MTRRphysMaskValid), %eax
> +       movl    $CPU_PHYSMASK_HI, %edx
> +       wrmsr
> +
> +       post_code(POST_CAR_MASK)
> +
> +       /* Enable MTRR */
> +       movl    $MTRRdefType_MSR, %ecx
> +       rdmsr
> +       orl     $MTRRdefTypeEn, %eax
> +       wrmsr
> +
> +       /* Enable cache (CR0.CD = 0, CR0.NW = 0) */
> +        movl   %cr0, %eax
> +       andl    $(~(X86_CR0_CD | X86_CR0_NW)), %eax
> +       invd
> +       movl    %eax, %cr0
> +
> +       /* enable the 'no eviction' mode */
> +       movl    $NoEvictMod_MSR, %ecx
> +       rdmsr
> +       orl     $1, %eax
> +       andl    $~2, %eax
> +       wrmsr
> +
> +       /* Clear the cache memory region. This will also fill up the cache */
> +       movl    $CACHE_AS_RAM_BASE, %esi
> +       movl    %esi, %edi
> +       movl    $(CACHE_AS_RAM_SIZE / 4), %ecx
> +       xorl    %eax, %eax
> +       rep     stosl
> +
> +       /* enable the 'no eviction run' state */
> +       movl    $NoEvictMod_MSR, %ecx
> +       rdmsr
> +       orl     $3, %eax
> +       wrmsr
> +
> +       post_code(POST_CAR_FILL)
> +       /* Enable Cache-as-RAM mode by disabling cache */
> +       movl    %cr0, %eax
> +       orl     $X86_CR0_CD, %eax
> +       movl    %eax, %cr0
> +
> +       /* Enable cache for our code in Flash because we do XIP here */
> +       movl    $MTRRphysBase_MSR(1), %ecx
> +       xorl    %edx, %edx
> +       movl    $car_init_ret, %eax
> +       andl    $(~(CONFIG_XIP_ROM_SIZE - 1)), %eax
> +       orl     $MTRR_TYPE_WRPROT, %eax
> +       wrmsr
> +
> +       movl    $MTRRphysMask_MSR(1), %ecx
> +       movl    $CPU_PHYSMASK_HI, %edx
> +       movl    $(~(CONFIG_XIP_ROM_SIZE - 1) | MTRRphysMaskValid), %eax
> +       wrmsr
> +
> +       post_code(POST_CAR_ROM_CACHE)
> +#ifdef CONFIG_CACHE_MRC_BIN
> +       /* Enable caching for ram init code to run faster */
> +       movl    $MTRRphysBase_MSR(2), %ecx
> +       movl    $(CACHE_MRC_BASE | MTRR_TYPE_WRPROT), %eax
> +       xorl    %edx, %edx
> +       wrmsr
> +       movl    $MTRRphysMask_MSR(2), %ecx
> +       movl    $(CACHE_MRC_MASK | MTRRphysMaskValid), %eax
> +       movl    $CPU_PHYSMASK_HI, %edx
> +       wrmsr
> +#endif
> +
> +       post_code(POST_CAR_MRC_CACHE)
> +       /* Enable cache */
> +       movl    %cr0, %eax
> +       andl    $(~(X86_CR0_CD | X86_CR0_NW)), %eax
> +       movl    %eax, %cr0
> +
> +       post_code(POST_CAR_CPU_CACHE)
> +
> +       /* return */
>         jmp     car_init_ret
> +
> +mtrr_table:
> +       /* Fixed MTRRs */
> +       .word 0x250, 0x258, 0x259
> +       .word 0x268, 0x269, 0x26A
> +       .word 0x26B, 0x26C, 0x26D
> +       .word 0x26E, 0x26F
> +       /* Variable MTRRs */
> +       .word 0x200, 0x201, 0x202, 0x203
> +       .word 0x204, 0x205, 0x206, 0x207
> +       .word 0x208, 0x209, 0x20A, 0x20B
> +       .word 0x20C, 0x20D, 0x20E, 0x20F
> +       .word 0x210, 0x211, 0x212, 0x213
> +mtrr_table_end:
> diff --git a/arch/x86/cpu/ivybridge/cpu.c b/arch/x86/cpu/ivybridge/cpu.c
> index 7e77be6..a9884ca 100644
> --- a/arch/x86/cpu/ivybridge/cpu.c
> +++ b/arch/x86/cpu/ivybridge/cpu.c
> @@ -11,6 +11,7 @@
>   */
>
>  #include <common.h>
> +#include <asm/post.h>
>  #include <asm/processor.h>
>
>  DECLARE_GLOBAL_DATA_PTR;
> @@ -19,6 +20,7 @@ int arch_cpu_init(void)
>  {
>         int ret;
>
> +       post_code(POST_CPU_INIT);
>         timer_set_base(rdtsc());
>
>         ret = x86_cpu_init_f();
> diff --git a/arch/x86/include/asm/mtrr.h b/arch/x86/include/asm/mtrr.h
> new file mode 100644
> index 0000000..5f05a48
> --- /dev/null
> +++ b/arch/x86/include/asm/mtrr.h
> @@ -0,0 +1,121 @@
> +/*
> + * Copyright (c) 2014 Google, Inc
> + *
> + * From Coreboot file of the same name
> + *
> + * SPDX-License-Identifier:    GPL-2.0+
> + */
> +
> +#ifndef _ASM_MTRR_H
> +#define _ASM_MTRR_H
> +
> +/*  These are the region types  */
> +#define MTRR_TYPE_UNCACHEABLE 0
> +#define MTRR_TYPE_WRCOMB     1
> +/*#define MTRR_TYPE_         2*/
> +/*#define MTRR_TYPE_         3*/
> +#define MTRR_TYPE_WRTHROUGH  4
> +#define MTRR_TYPE_WRPROT     5
> +#define MTRR_TYPE_WRBACK     6
> +#define MTRR_NUM_TYPES       7
> +
> +#define MTRRcap_MSR     0x0fe
> +#define MTRRdefType_MSR 0x2ff
> +
> +#define MTRRdefTypeEn          (1 << 11)
> +#define MTRRdefTypeFixEn       (1 << 10)
> +
> +#define SMRRphysBase_MSR 0x1f2
> +#define SMRRphysMask_MSR 0x1f3
> +
> +#define MTRRphysBase_MSR(reg) (0x200 + 2 * (reg))
> +#define MTRRphysMask_MSR(reg) (0x200 + 2 * (reg) + 1)
> +
> +#define MTRRphysMaskValid      (1 << 11)
> +
> +#define NUM_FIXED_RANGES 88
> +#define RANGES_PER_FIXED_MTRR 8
> +#define MTRRfix64K_00000_MSR 0x250
> +#define MTRRfix16K_80000_MSR 0x258
> +#define MTRRfix16K_A0000_MSR 0x259
> +#define MTRRfix4K_C0000_MSR 0x268
> +#define MTRRfix4K_C8000_MSR 0x269
> +#define MTRRfix4K_D0000_MSR 0x26a
> +#define MTRRfix4K_D8000_MSR 0x26b
> +#define MTRRfix4K_E0000_MSR 0x26c
> +#define MTRRfix4K_E8000_MSR 0x26d
> +#define MTRRfix4K_F0000_MSR 0x26e
> +#define MTRRfix4K_F8000_MSR 0x26f

Ditto.

> +#if !defined(__ASSEMBLER__)
> +
> +/*
> + * The MTRR code has some side effects that the callers should be aware for.
> + * 1. The call sequence matters. x86_setup_mtrrs() calls
> + *    x86_setup_fixed_mtrrs_no_enable() then enable_fixed_mtrrs() (equivalent
> + *    of x86_setup_fixed_mtrrs()) then x86_setup_var_mtrrs(). If the callers
> + *    want to call the components of x86_setup_mtrrs() because of other
> + *    rquirements the ordering should still preserved.
> + * 2. enable_fixed_mtrr() will enable both variable and fixed MTRRs because
> + *    of the nature of the global MTRR enable flag. Therefore, all direct
> + *    or indirect callers of enable_fixed_mtrr() should ensure that the
> + *    variable MTRR MSRs do not contain bad ranges.
> + * 3. If CONFIG_CACHE_ROM is selected an MTRR is allocated for enabling
> + *    the caching of the ROM. However, it is set to uncacheable (UC). It
> + *    is the responsiblity of the caller to enable it by calling
> + *    x86_mtrr_enable_rom_caching().
> + */
> +void x86_setup_mtrrs(void);
> +/*
> + * x86_setup_var_mtrrs() parameters:
> + * address_bits - number of physical address bits supported by cpu
> + * above4gb - 2 means dynamically detect number of variable MTRRs available.
> + *            non-zero means handle memory ranges above 4GiB.
> + *            0 means ignore memory ranges above 4GiB
> + */
> +void x86_setup_var_mtrrs(unsigned int address_bits, unsigned int above4gb);
> +void enable_fixed_mtrr(void);
> +void x86_setup_fixed_mtrrs(void);
> +/* Set up fixed MTRRs but do not enable them. */
> +void x86_setup_fixed_mtrrs_no_enable(void);
> +int x86_mtrr_check(void);
> +/* ROM caching can be used after variable MTRRs are set up. Beware that
> + * enabling CONFIG_CACHE_ROM will eat through quite a few MTRRs based on
> + * one's IO hole size and WRCOMB resources. Be sure to check the console
> + * log when enabling CONFIG_CACHE_ROM or adding WRCOMB resources. Beware that
> + * on CPUs with core-scoped MTRR registers such as hyperthreaded CPUs the
> + * rom caching will be disabled if all threads run the MTRR code. Therefore,
> + * one needs to call x86_mtrr_enable_rom_caching() after all threads of the
> + * same core have run the MTRR code. */
> +#if CONFIG_CACHE_ROM
> +void x86_mtrr_enable_rom_caching(void);
> +void x86_mtrr_disable_rom_caching(void);
> +/* Return the variable range MTRR index of the ROM cache. */
> +long x86_mtrr_rom_cache_var_index(void);
> +#else
> +static inline void x86_mtrr_enable_rom_caching(void) {}
> +static inline void x86_mtrr_disable_rom_caching(void) {}
> +static inline long x86_mtrr_rom_cache_var_index(void) { return -1; }
> +#endif /* CONFIG_CACHE_ROM */
> +
> +#endif
> +
> +#if !defined(CONFIG_RAMTOP)
> +# error "CONFIG_RAMTOP not defined"
> +#endif
> +
> +#if ((CONFIG_XIP_ROM_SIZE & (CONFIG_XIP_ROM_SIZE - 1)) != 0)
> +# error "CONFIG_XIP_ROM_SIZE is not a power of 2"
> +#endif
> +
> +#if ((CONFIG_CACHE_ROM_SIZE & (CONFIG_CACHE_ROM_SIZE - 1)) != 0)
> +# error "CONFIG_CACHE_ROM_SIZE is not a power of 2"
> +#endif
> +
> +#define CACHE_ROM_BASE (((1 << 20) - (CONFIG_CACHE_ROM_SIZE >> 12)) << 12)
> +
> +#if (CONFIG_RAMTOP & (CONFIG_RAMTOP - 1)) != 0
> +# error "CONFIG_RAMTOP must be a power of 2"
> +#endif
> +
> +#endif
> diff --git a/arch/x86/include/asm/post.h b/arch/x86/include/asm/post.h
> index 3371185..b203dc9 100644
> --- a/arch/x86/include/asm/post.h
> +++ b/arch/x86/include/asm/post.h
> @@ -13,9 +13,18 @@
>  /* post codes which represent various stages of init */
>  #define POST_START             0x1e
>  #define POST_CAR_START         0x1f
> -
> +#define POST_CAR_SIPI          0x20
> +#define POST_CAR_MTRR          0x21
> +#define POST_CAR_UNCACHEABLE   0x22
> +#define POST_CAR_BASE_ADDRESS  0x23
> +#define POST_CAR_MASK          0x24
> +#define POST_CAR_FILL          0x25
> +#define POST_CAR_ROM_CACHE     0x26
> +#define POST_CAR_MRC_CACHE     0x27
> +#define POST_CAR_CPU_CACHE     0x28
>  #define POST_START_STACK       0x29
>  #define POST_START_DONE                0x2a
> +#define POST_CPU_INIT          0x2b
>
>  /* Output a post code using al - value must be 0 to 0xff */
>  #ifdef __ASSEMBLY__
> @@ -23,6 +32,8 @@
>         movb    $value, %al; \
>         outb    %al, $POST_PORT
>  #else
> +#include <asm/io.h>
> +
>  static inline void post_code(int code)
>  {
>         outb(code, POST_PORT);
> diff --git a/board/google/chromebook_link/Kconfig b/board/google/chromebook_link/Kconfig
> index 9c715ba..3a4f557 100644
> --- a/board/google/chromebook_link/Kconfig
> +++ b/board/google/chromebook_link/Kconfig
> @@ -12,6 +12,18 @@ config SYS_SOC
>  config SYS_CONFIG_NAME
>         default "chromebook_link"
>
> +config BOARD_SPECIFIC_OPTIONS # dummy
> +       def_bool y
> +       select CPU_INTEL_SOCKET_RPGA989
> +       select NORTHBRIDGE_INTEL_IVYBRIDGE
> +       select SOUTHBRIDGE_INTEL_C216
> +       select HAVE_ACPI_RESUME
> +       select MARK_GRAPHICS_MEM_WRCOMB
> +
> +config MMCONF_BASE_ADDRESS
> +       hex
> +       default 0xf0000000
> +
>  config EARLY_POST_CROS_EC
>         bool "Enable early post to Chrome OS EC"
>         default y
> --

Regards,
Bin
Simon Glass Nov. 7, 2014, 2:44 p.m. UTC | #2
Hi Bin,

On 7 November 2014 07:07, Bin Meng <bmeng.cn@gmail.com> wrote:
> Hi Simon,
>
> On Fri, Nov 7, 2014 at 4:20 AM, Simon Glass <sjg@chromium.org> wrote:
>> Add support for CAR so that we have memory to use prior to DRAM init.
>> On link there is a total of 128KB of CAR available, although some is
>> used for the memory reference code.
>>
>> Signed-off-by: Simon Glass <sjg@chromium.org>
>> ---
>>
>>  arch/x86/Kconfig                     |  16 ++++
>>  arch/x86/cpu/ivybridge/car.S         | 156 ++++++++++++++++++++++++++++++++++-
>>  arch/x86/cpu/ivybridge/cpu.c         |   2 +
>>  arch/x86/include/asm/mtrr.h          | 121 +++++++++++++++++++++++++++
>>  arch/x86/include/asm/post.h          |  13 ++-
>>  board/google/chromebook_link/Kconfig |  12 +++
>>  6 files changed, 318 insertions(+), 2 deletions(-)
>>  create mode 100644 arch/x86/include/asm/mtrr.h
>>
>> diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
>> index d9ce129..73fe8b2 100644
>> --- a/arch/x86/Kconfig
>> +++ b/arch/x86/Kconfig
>> @@ -34,6 +34,22 @@ config TARGET_CHROMEBOOK_LINK
>>
>>  endchoice
>>
>> +config RAMBASE
>> +       hex
>> +       default 0x100000
>> +
>> +config RAMTOP
>> +       hex
>> +       default 0x200000
>> +
>> +config XIP_ROM_SIZE
>> +       hex
>> +       default 0x10000
>> +
>> +config CPU_ADDR_BITS
>> +       int
>> +       default 36
>> +
>>  config ROM_SIZE
>>         hex
>>         default 0x800000
>> diff --git a/arch/x86/cpu/ivybridge/car.S b/arch/x86/cpu/ivybridge/car.S
>> index 0480813..391f6df 100644
>> --- a/arch/x86/cpu/ivybridge/car.S
>> +++ b/arch/x86/cpu/ivybridge/car.S
>> @@ -12,9 +12,163 @@
>>   */
>>
>>  #include <common.h>
>> +#include <asm/mtrr.h>
>> +#include <asm/post.h>
>> +#include <asm/processor-flags.h>
>> +
>> +#define MTRRphysBase_MSR(reg) (0x200 + 2 * (reg))
>> +#define MTRRphysMask_MSR(reg) (0x200 + 2 * (reg) + 1)
>
> Should these macros be all capital?

Yes I'll fix that. I had in mind keeping it similar to where it came
from, but there are lots of changes needed so it's not worth it.

>
>> +#define CACHE_AS_RAM_SIZE      CONFIG_DCACHE_RAM_SIZE
>> +#define CACHE_AS_RAM_BASE      CONFIG_DCACHE_RAM_BASE
>> +
>> +/* Cache 4GB - MRC_SIZE_KB for MRC */
>> +#define CACHE_MRC_BYTES        ((CONFIG_CACHE_MRC_SIZE_KB << 10) - 1)
>> +#define CACHE_MRC_BASE         (0xFFFFFFFF - CACHE_MRC_BYTES)
>> +#define CACHE_MRC_MASK         (~CACHE_MRC_BYTES)
>> +
>> +#define CPU_PHYSMASK_HI        (1 << (CONFIG_CPU_ADDR_BITS - 32) - 1)
>> +
>> +#define NoEvictMod_MSR 0x2e0
>
> Ditto.
>
>>         /* Note: ebp must not be touched in this code */
>
> I think mentioning ebp holds the value of BIST would help more?

OK

>
>>  .globl car_init
>>  car_init:
>> -       /* TODO: Add cache-as-RAM init here */
>> +       post_code(POST_CAR_START)
>> +
>> +       /* Send INIT IPI to all excluding ourself */
>> +       movl    $0x000C4500, %eax
>> +       movl    $0xFEE00300, %esi
>> +       movl    %eax, (%esi)
>> +
>> +       /* All CPUs need to be in Wait for SIPI state */
>> +wait_for_sipi:
>> +       movl    (%esi), %eax
>> +       bt      $12, %eax
>> +       jc      wait_for_sipi
>
> Is this a must to send INIT IPI before CAR initialization?

I'll test it.

[snip]

Regards,
Simon
diff mbox

Patch

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index d9ce129..73fe8b2 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -34,6 +34,22 @@  config TARGET_CHROMEBOOK_LINK
 
 endchoice
 
+config RAMBASE
+	hex
+	default 0x100000
+
+config RAMTOP
+	hex
+	default 0x200000
+
+config XIP_ROM_SIZE
+	hex
+	default 0x10000
+
+config CPU_ADDR_BITS
+	int
+	default 36
+
 config ROM_SIZE
 	hex
 	default 0x800000
diff --git a/arch/x86/cpu/ivybridge/car.S b/arch/x86/cpu/ivybridge/car.S
index 0480813..391f6df 100644
--- a/arch/x86/cpu/ivybridge/car.S
+++ b/arch/x86/cpu/ivybridge/car.S
@@ -12,9 +12,163 @@ 
  */
 
 #include <common.h>
+#include <asm/mtrr.h>
+#include <asm/post.h>
+#include <asm/processor-flags.h>
+
+#define MTRRphysBase_MSR(reg) (0x200 + 2 * (reg))
+#define MTRRphysMask_MSR(reg) (0x200 + 2 * (reg) + 1)
+
+#define CACHE_AS_RAM_SIZE	CONFIG_DCACHE_RAM_SIZE
+#define CACHE_AS_RAM_BASE	CONFIG_DCACHE_RAM_BASE
+
+/* Cache 4GB - MRC_SIZE_KB for MRC */
+#define CACHE_MRC_BYTES	((CONFIG_CACHE_MRC_SIZE_KB << 10) - 1)
+#define CACHE_MRC_BASE		(0xFFFFFFFF - CACHE_MRC_BYTES)
+#define CACHE_MRC_MASK		(~CACHE_MRC_BYTES)
+
+#define CPU_PHYSMASK_HI	(1 << (CONFIG_CPU_ADDR_BITS - 32) - 1)
+
+#define NoEvictMod_MSR 0x2e0
 
 	/* Note: ebp must not be touched in this code */
 .globl car_init
 car_init:
-	/* TODO: Add cache-as-RAM init here */
+	post_code(POST_CAR_START)
+
+	/* Send INIT IPI to all excluding ourself */
+	movl	$0x000C4500, %eax
+	movl	$0xFEE00300, %esi
+	movl	%eax, (%esi)
+
+	/* All CPUs need to be in Wait for SIPI state */
+wait_for_sipi:
+	movl	(%esi), %eax
+	bt	$12, %eax
+	jc	wait_for_sipi
+
+	post_code(POST_CAR_SIPI)
+	/* Zero out all fixed range and variable range MTRRs */
+	movl	$mtrr_table, %esi
+	movl	$((mtrr_table_end - mtrr_table) / 2), %edi
+	xorl	%eax, %eax
+	xorl	%edx, %edx
+clear_mtrrs:
+	movw	(%esi), %bx
+	movzx	%bx, %ecx
+	wrmsr
+	add	$2, %esi
+	dec	%edi
+	jnz	clear_mtrrs
+
+	post_code(POST_CAR_MTRR)
+	/* Configure the default memory type to uncacheable */
+	movl	$MTRRdefType_MSR, %ecx
+	rdmsr
+	andl	$(~0x00000cff), %eax
+	wrmsr
+
+	post_code(POST_CAR_UNCACHEABLE)
+	/* Set Cache-as-RAM base address */
+	movl	$(MTRRphysBase_MSR(0)), %ecx
+	movl	$(CACHE_AS_RAM_BASE | MTRR_TYPE_WRBACK), %eax
+	xorl	%edx, %edx
+	wrmsr
+
+	post_code(POST_CAR_BASE_ADDRESS)
+	/* Set Cache-as-RAM mask */
+	movl	$(MTRRphysMask_MSR(0)), %ecx
+	movl	$(~(CACHE_AS_RAM_SIZE - 1) | MTRRphysMaskValid), %eax
+	movl	$CPU_PHYSMASK_HI, %edx
+	wrmsr
+
+	post_code(POST_CAR_MASK)
+
+	/* Enable MTRR */
+	movl	$MTRRdefType_MSR, %ecx
+	rdmsr
+	orl	$MTRRdefTypeEn, %eax
+	wrmsr
+
+	/* Enable cache (CR0.CD = 0, CR0.NW = 0) */
+        movl	%cr0, %eax
+	andl	$(~(X86_CR0_CD | X86_CR0_NW)), %eax
+	invd
+	movl	%eax, %cr0
+
+	/* enable the 'no eviction' mode */
+	movl    $NoEvictMod_MSR, %ecx
+	rdmsr
+	orl     $1, %eax
+	andl    $~2, %eax
+	wrmsr
+
+       /* Clear the cache memory region. This will also fill up the cache */
+	movl	$CACHE_AS_RAM_BASE, %esi
+	movl	%esi, %edi
+	movl	$(CACHE_AS_RAM_SIZE / 4), %ecx
+	xorl	%eax, %eax
+	rep	stosl
+
+	/* enable the 'no eviction run' state */
+	movl    $NoEvictMod_MSR, %ecx
+	rdmsr
+	orl     $3, %eax
+	wrmsr
+
+	post_code(POST_CAR_FILL)
+	/* Enable Cache-as-RAM mode by disabling cache */
+	movl	%cr0, %eax
+	orl	$X86_CR0_CD, %eax
+	movl	%eax, %cr0
+
+	/* Enable cache for our code in Flash because we do XIP here */
+	movl	$MTRRphysBase_MSR(1), %ecx
+	xorl	%edx, %edx
+	movl    $car_init_ret, %eax
+	andl    $(~(CONFIG_XIP_ROM_SIZE - 1)), %eax
+	orl	$MTRR_TYPE_WRPROT, %eax
+	wrmsr
+
+	movl	$MTRRphysMask_MSR(1), %ecx
+	movl	$CPU_PHYSMASK_HI, %edx
+	movl	$(~(CONFIG_XIP_ROM_SIZE - 1) | MTRRphysMaskValid), %eax
+	wrmsr
+
+	post_code(POST_CAR_ROM_CACHE)
+#ifdef CONFIG_CACHE_MRC_BIN
+	/* Enable caching for ram init code to run faster */
+	movl	$MTRRphysBase_MSR(2), %ecx
+	movl	$(CACHE_MRC_BASE | MTRR_TYPE_WRPROT), %eax
+	xorl	%edx, %edx
+	wrmsr
+	movl	$MTRRphysMask_MSR(2), %ecx
+	movl	$(CACHE_MRC_MASK | MTRRphysMaskValid), %eax
+	movl	$CPU_PHYSMASK_HI, %edx
+	wrmsr
+#endif
+
+	post_code(POST_CAR_MRC_CACHE)
+	/* Enable cache */
+	movl	%cr0, %eax
+	andl	$(~(X86_CR0_CD | X86_CR0_NW)), %eax
+	movl	%eax, %cr0
+
+	post_code(POST_CAR_CPU_CACHE)
+
+	/* return */
 	jmp	car_init_ret
+
+mtrr_table:
+	/* Fixed MTRRs */
+	.word 0x250, 0x258, 0x259
+	.word 0x268, 0x269, 0x26A
+	.word 0x26B, 0x26C, 0x26D
+	.word 0x26E, 0x26F
+	/* Variable MTRRs */
+	.word 0x200, 0x201, 0x202, 0x203
+	.word 0x204, 0x205, 0x206, 0x207
+	.word 0x208, 0x209, 0x20A, 0x20B
+	.word 0x20C, 0x20D, 0x20E, 0x20F
+	.word 0x210, 0x211, 0x212, 0x213
+mtrr_table_end:
diff --git a/arch/x86/cpu/ivybridge/cpu.c b/arch/x86/cpu/ivybridge/cpu.c
index 7e77be6..a9884ca 100644
--- a/arch/x86/cpu/ivybridge/cpu.c
+++ b/arch/x86/cpu/ivybridge/cpu.c
@@ -11,6 +11,7 @@ 
  */
 
 #include <common.h>
+#include <asm/post.h>
 #include <asm/processor.h>
 
 DECLARE_GLOBAL_DATA_PTR;
@@ -19,6 +20,7 @@  int arch_cpu_init(void)
 {
 	int ret;
 
+	post_code(POST_CPU_INIT);
 	timer_set_base(rdtsc());
 
 	ret = x86_cpu_init_f();
diff --git a/arch/x86/include/asm/mtrr.h b/arch/x86/include/asm/mtrr.h
new file mode 100644
index 0000000..5f05a48
--- /dev/null
+++ b/arch/x86/include/asm/mtrr.h
@@ -0,0 +1,121 @@ 
+/*
+ * Copyright (c) 2014 Google, Inc
+ *
+ * From Coreboot file of the same name
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _ASM_MTRR_H
+#define _ASM_MTRR_H
+
+/*  These are the region types  */
+#define MTRR_TYPE_UNCACHEABLE 0
+#define MTRR_TYPE_WRCOMB     1
+/*#define MTRR_TYPE_         2*/
+/*#define MTRR_TYPE_         3*/
+#define MTRR_TYPE_WRTHROUGH  4
+#define MTRR_TYPE_WRPROT     5
+#define MTRR_TYPE_WRBACK     6
+#define MTRR_NUM_TYPES       7
+
+#define MTRRcap_MSR     0x0fe
+#define MTRRdefType_MSR 0x2ff
+
+#define MTRRdefTypeEn		(1 << 11)
+#define MTRRdefTypeFixEn	(1 << 10)
+
+#define SMRRphysBase_MSR 0x1f2
+#define SMRRphysMask_MSR 0x1f3
+
+#define MTRRphysBase_MSR(reg) (0x200 + 2 * (reg))
+#define MTRRphysMask_MSR(reg) (0x200 + 2 * (reg) + 1)
+
+#define MTRRphysMaskValid	(1 << 11)
+
+#define NUM_FIXED_RANGES 88
+#define RANGES_PER_FIXED_MTRR 8
+#define MTRRfix64K_00000_MSR 0x250
+#define MTRRfix16K_80000_MSR 0x258
+#define MTRRfix16K_A0000_MSR 0x259
+#define MTRRfix4K_C0000_MSR 0x268
+#define MTRRfix4K_C8000_MSR 0x269
+#define MTRRfix4K_D0000_MSR 0x26a
+#define MTRRfix4K_D8000_MSR 0x26b
+#define MTRRfix4K_E0000_MSR 0x26c
+#define MTRRfix4K_E8000_MSR 0x26d
+#define MTRRfix4K_F0000_MSR 0x26e
+#define MTRRfix4K_F8000_MSR 0x26f
+
+#if !defined(__ASSEMBLER__)
+
+/*
+ * The MTRR code has some side effects that the callers should be aware for.
+ * 1. The call sequence matters. x86_setup_mtrrs() calls
+ *    x86_setup_fixed_mtrrs_no_enable() then enable_fixed_mtrrs() (equivalent
+ *    of x86_setup_fixed_mtrrs()) then x86_setup_var_mtrrs(). If the callers
+ *    want to call the components of x86_setup_mtrrs() because of other
+ *    rquirements the ordering should still preserved.
+ * 2. enable_fixed_mtrr() will enable both variable and fixed MTRRs because
+ *    of the nature of the global MTRR enable flag. Therefore, all direct
+ *    or indirect callers of enable_fixed_mtrr() should ensure that the
+ *    variable MTRR MSRs do not contain bad ranges.
+ * 3. If CONFIG_CACHE_ROM is selected an MTRR is allocated for enabling
+ *    the caching of the ROM. However, it is set to uncacheable (UC). It
+ *    is the responsiblity of the caller to enable it by calling
+ *    x86_mtrr_enable_rom_caching().
+ */
+void x86_setup_mtrrs(void);
+/*
+ * x86_setup_var_mtrrs() parameters:
+ * address_bits - number of physical address bits supported by cpu
+ * above4gb - 2 means dynamically detect number of variable MTRRs available.
+ *            non-zero means handle memory ranges above 4GiB.
+ *            0 means ignore memory ranges above 4GiB
+ */
+void x86_setup_var_mtrrs(unsigned int address_bits, unsigned int above4gb);
+void enable_fixed_mtrr(void);
+void x86_setup_fixed_mtrrs(void);
+/* Set up fixed MTRRs but do not enable them. */
+void x86_setup_fixed_mtrrs_no_enable(void);
+int x86_mtrr_check(void);
+/* ROM caching can be used after variable MTRRs are set up. Beware that
+ * enabling CONFIG_CACHE_ROM will eat through quite a few MTRRs based on
+ * one's IO hole size and WRCOMB resources. Be sure to check the console
+ * log when enabling CONFIG_CACHE_ROM or adding WRCOMB resources. Beware that
+ * on CPUs with core-scoped MTRR registers such as hyperthreaded CPUs the
+ * rom caching will be disabled if all threads run the MTRR code. Therefore,
+ * one needs to call x86_mtrr_enable_rom_caching() after all threads of the
+ * same core have run the MTRR code. */
+#if CONFIG_CACHE_ROM
+void x86_mtrr_enable_rom_caching(void);
+void x86_mtrr_disable_rom_caching(void);
+/* Return the variable range MTRR index of the ROM cache. */
+long x86_mtrr_rom_cache_var_index(void);
+#else
+static inline void x86_mtrr_enable_rom_caching(void) {}
+static inline void x86_mtrr_disable_rom_caching(void) {}
+static inline long x86_mtrr_rom_cache_var_index(void) { return -1; }
+#endif /* CONFIG_CACHE_ROM */
+
+#endif
+
+#if !defined(CONFIG_RAMTOP)
+# error "CONFIG_RAMTOP not defined"
+#endif
+
+#if ((CONFIG_XIP_ROM_SIZE & (CONFIG_XIP_ROM_SIZE - 1)) != 0)
+# error "CONFIG_XIP_ROM_SIZE is not a power of 2"
+#endif
+
+#if ((CONFIG_CACHE_ROM_SIZE & (CONFIG_CACHE_ROM_SIZE - 1)) != 0)
+# error "CONFIG_CACHE_ROM_SIZE is not a power of 2"
+#endif
+
+#define CACHE_ROM_BASE	(((1 << 20) - (CONFIG_CACHE_ROM_SIZE >> 12)) << 12)
+
+#if (CONFIG_RAMTOP & (CONFIG_RAMTOP - 1)) != 0
+# error "CONFIG_RAMTOP must be a power of 2"
+#endif
+
+#endif
diff --git a/arch/x86/include/asm/post.h b/arch/x86/include/asm/post.h
index 3371185..b203dc9 100644
--- a/arch/x86/include/asm/post.h
+++ b/arch/x86/include/asm/post.h
@@ -13,9 +13,18 @@ 
 /* post codes which represent various stages of init */
 #define POST_START		0x1e
 #define POST_CAR_START		0x1f
-
+#define POST_CAR_SIPI		0x20
+#define POST_CAR_MTRR		0x21
+#define POST_CAR_UNCACHEABLE	0x22
+#define POST_CAR_BASE_ADDRESS	0x23
+#define POST_CAR_MASK		0x24
+#define POST_CAR_FILL		0x25
+#define POST_CAR_ROM_CACHE	0x26
+#define POST_CAR_MRC_CACHE	0x27
+#define POST_CAR_CPU_CACHE	0x28
 #define POST_START_STACK	0x29
 #define POST_START_DONE		0x2a
+#define POST_CPU_INIT		0x2b
 
 /* Output a post code using al - value must be 0 to 0xff */
 #ifdef __ASSEMBLY__
@@ -23,6 +32,8 @@ 
 	movb	$value, %al; \
 	outb	%al, $POST_PORT
 #else
+#include <asm/io.h>
+
 static inline void post_code(int code)
 {
 	outb(code, POST_PORT);
diff --git a/board/google/chromebook_link/Kconfig b/board/google/chromebook_link/Kconfig
index 9c715ba..3a4f557 100644
--- a/board/google/chromebook_link/Kconfig
+++ b/board/google/chromebook_link/Kconfig
@@ -12,6 +12,18 @@  config SYS_SOC
 config SYS_CONFIG_NAME
 	default "chromebook_link"
 
+config BOARD_SPECIFIC_OPTIONS # dummy
+	def_bool y
+	select CPU_INTEL_SOCKET_RPGA989
+	select NORTHBRIDGE_INTEL_IVYBRIDGE
+	select SOUTHBRIDGE_INTEL_C216
+	select HAVE_ACPI_RESUME
+	select MARK_GRAPHICS_MEM_WRCOMB
+
+config MMCONF_BASE_ADDRESS
+	hex
+	default 0xf0000000
+
 config EARLY_POST_CROS_EC
 	bool "Enable early post to Chrome OS EC"
 	default y