coreboot-v3/arch/x86/stage1_mtrr.c
<<
>>
Prefs
   1/* we will compile this into initram since some basic prototypes differ with same names on v2. Sigh. */
   2#include <mainboard.h>
   3#include <config.h>
   4#include <types.h>
   5#include <io.h>
   6#include <console.h>
   7#include <cpu.h>
   8#include <globalvars.h>
   9#include <lar.h>
  10#include <string.h>
  11#include <tables.h>
  12#include <lib.h>
  13#include <mc146818rtc.h>
  14#include <msr.h>
  15#include <mtrr.h>
  16
  17#if 1
  18#define BIOS_MTRRS 6
  19#define OS_MTRRS   2
  20#else
  21#define BIOS_MTRRS 8
  22#define OS_MTRRS   0
  23#endif
  24#define MTRRS (BIOS_MTRRS + OS_MTRRS)
  25
  26/* fms: find most sigificant bit set, stolen from Linux Kernel Source. */
  27static inline u32 fms(u32 x)
  28{
  29        int r;
  30
  31        __asm__("bsrl %1,%0\n\t"
  32                        "jnz 1f\n\t"
  33                        "movl $0,%0\n"
  34                        "1:" : "=r" (r) : "g" (x));
  35        return r;
  36}
  37
  38/* fls: find least sigificant bit set */
  39static inline u32 fls(u32 x)
  40{
  41        int r;
  42
  43        __asm__("bsfl %1,%0\n\t"
  44                        "jnz 1f\n\t"
  45                        "movl $32,%0\n"
  46                        "1:" : "=r" (r) : "g" (x));
  47        return r;
  48}
  49
  50u32 stage1_resk(u64 value)
  51{
  52        u32 resultk;
  53        if (value < (1ULL << 42)) {
  54                resultk = value >> 10;
  55        }
  56        else {
  57                resultk = 0xffffffff;
  58        }
  59        return resultk;
  60}
  61
  62/* Sets the entire fixed mtrr to a cache type. */
  63void stage1_set_fix_mtrr(u32 reg, u8 type)
  64{
  65        struct msr msr;
  66
  67        /* Enable Modify Extended RdMem and WrMem settings */
  68        msr = rdmsr(SYSCFG_MSR);
  69        msr.lo |= SYSCFG_MSR_MtrrFixDramModEn;
  70        wrmsr(SYSCFG_MSR, msr);
  71
  72        msr.lo = (type << 24) | (type << 16) | (type << 8) | type;
  73        msr.hi = (type << 24) | (type << 16) | (type << 8) | type;
  74        wrmsr(reg, msr);
  75
  76        /* Disable Modify Extended RdMem and WrMem settings */
  77        msr = rdmsr(SYSCFG_MSR);
  78        msr.lo &= ~SYSCFG_MSR_MtrrFixDramModEn;
  79        wrmsr(SYSCFG_MSR, msr);
  80}
  81
  82/* Set a variable MTRR, comes from linux kernel source
  83 * use stage1_range_to_mtrr() to set variable MTRRs.
  84 */
  85static void stage1_set_var_mtrr(u8 reg, u32 basek, u32 sizek,
  86                                                                u8 type, u32 address_bits)
  87{
  88        struct msr base, mask;
  89        u32 address_mask_high;
  90
  91        if (reg >= MTRRS) {
  92                printk(BIOS_ERR,"Requested MTRR is out of range!\n");
  93                return;
  94        }
  95
  96        if (sizek == 0) {
  97                struct msr zero;
  98                zero.lo = zero.hi = 0;
  99
 100                disable_cache();        /* disable/enable cache when setting MTRRs */
 101
 102                /* The invalid bit is kept in the mask, so we simply clear the
 103                relevant mask register to disable a range. */
 104                wrmsr (MTRRphysMask_MSR(reg), zero);
 105
 106                enable_cache();
 107                return;
 108        }
 109
 110
 111        address_mask_high = ((1u << (address_bits - 32u)) - 1u);
 112
 113        base.hi = basek >> 22;
 114        base.lo  = basek << 10;
 115
 116        printk(BIOS_SPEW, "ADDRESS_MASK_HIGH=%#x\n", address_mask_high);
 117
 118        if (sizek < 4*1024*1024) {
 119                mask.hi = address_mask_high;
 120                mask.lo = ~((sizek << 10) -1);
 121        }
 122        else {
 123                mask.hi = address_mask_high & (~((sizek >> 22) -1));
 124                mask.lo = 0;
 125        }
 126
 127        disable_cache();        /* disable/enable cache when setting MTRRs */
 128
 129        /* Bit 32-35 of MTRRphysMask should be set to 1 */
 130        base.lo |= type;
 131        mask.lo |= 0x800;
 132        wrmsr (MTRRphysBase_MSR(reg), base);
 133        wrmsr (MTRRphysMask_MSR(reg), mask);
 134
 135        enable_cache();
 136}
 137
 138/* Set a memory range to variable MTRRs.
 139 * This handles the power of 2 alignment requirement.
 140 */
 141u8 stage1_range_to_mtrr(u8 reg, u32 range_startk, u32 range_sizek,
 142                                                u8 type, u32 address_bits)
 143{
 144        if (!range_sizek) {
 145                printk(BIOS_SPEW, "Zero-sized MTRR range @%dKB\n", range_startk);
 146                return reg;
 147        }
 148
 149        if (reg >= BIOS_MTRRS) {
 150                printk(BIOS_ERR, "ERROR: Out of MTRRs for base: %4dMB, range: %dMB, type %s\n",
 151                                range_startk >>10, range_sizek >> 10,
 152                                (type==MTRR_TYPE_UNCACHEABLE)?"UC":
 153                                ((type==MTRR_TYPE_WRBACK)?"WB":"Other") );
 154                return reg;
 155        }
 156
 157        while(range_sizek) {
 158                u32 max_align, align;
 159                u32 sizek;
 160                /* Compute the maximum size I can make a range */
 161                max_align = fls(range_startk);
 162                align = fms(range_sizek);
 163                if (align > max_align) {
 164                        align = max_align;
 165                }
 166                sizek = 1 << align;
 167                printk(BIOS_DEBUG,"Setting variable MTRR %d, base: %dKB, range: %dKB, type %s\n",
 168                        reg, range_startk, sizek,
 169                        (type==MTRR_TYPE_UNCACHEABLE)?"UC":
 170                        ((type==MTRR_TYPE_WRBACK)?"WB":"Other")
 171                        );
 172                stage1_set_var_mtrr(reg++, range_startk, sizek, type, address_bits);
 173                range_startk += sizek;
 174                range_sizek -= sizek;
 175                if (reg >= BIOS_MTRRS) {
 176                        printk(BIOS_ERR, "Out of variable MTRRs!\n");
 177                        break;
 178                }
 179        }
 180        return reg;
 181}
 182
 183void cache_cbmem(int type)
 184{
 185        /* Enable caching for 0 - 1MB(CONFIG_CBMEMK) using variable mtrr */
 186        disable_cache();
 187        stage1_range_to_mtrr(0, 0, CONFIG_CBMEMK, MTRR_TYPE_WRBACK, CPU_ADDR_BITS);
 188        enable_cache();
 189}
 190
 191/* early_mtrr_init was only usable for ROMCC compiled code. It nukes CAR.
 192 * The only remaining purpose would be to enable ROM caching here instead of
 193 * in stage0.S and even that is debatable.
 194 */
 195#if 0
 196/* the fixed and variable MTTRs are power-up with random values,
 197 * clear them to MTRR_TYPE_UNCACHEABLE for safty.
 198 */
 199void do_early_mtrr_init(const unsigned long *mtrr_msrs)
 200{
 201        /* Precondition:
 202         *   The cache is not enabled in cr0 nor in MTRRdefType_MSR
 203         *   entry32.inc ensures the cache is not enabled in cr0
 204         */
 205        struct msr msr;
 206        const unsigned long *msr_addr;
 207
 208        /* Inialize all of the relevant msrs to 0 */
 209        msr.lo = 0;
 210        msr.hi = 0;
 211        unsigned long msr_nr;
 212        for(msr_addr = mtrr_msrs; (msr_nr = *msr_addr); msr_addr++) {
 213                wrmsr(msr_nr, msr);
 214        }
 215
 216#warning fix the XIP bits in stage1_mtrr.c that enable write through caching so we can do execute in place on the flash rom.
 217#if 0
 218#if defined(XIP_ROM_SIZE)
 219        /* enable write through caching so we can do execute in place
 220         * on the flash rom.
 221         */
 222        stage1_range_to_mtrr(1, 0, XIP_ROM_BASE >> 10, XIP_ROM_SIZE >> 10,
 223                                                MTRR_TYPE_WRBACK, CPU_ADDR_BITS);
 224#endif
 225#endif
 226
 227        /* Set the default memory type and enable fixed and variable MTRRs 
 228         */
 229        /* Enable Variable MTRRs */
 230        msr.hi = 0x00000000;
 231        msr.lo = 0x00000800;
 232        wrmsr(MTRRdefType_MSR, msr);
 233        
 234}
 235
 236/**
 237 * Call this function early in stage1 to enable mtrrs, which will ensure 
 238 * caching of ROM 
 239 */
 240void early_mtrr_init(void)
 241{
 242        static const unsigned long mtrr_msrs[] = {
 243                /* fixed mtrr */
 244                0x250, 0x258, 0x259,
 245                0x268, 0x269, 0x26A,
 246                0x26B, 0x26C, 0x26D,
 247                0x26E, 0x26F,
 248                /* var mtrr */
 249                0x200, 0x201, 0x202, 0x203,
 250                0x204, 0x205, 0x206, 0x207,
 251                0x208, 0x209, 0x20A, 0x20B,
 252                0x20C, 0x20D, 0x20E, 0x20F,
 253                /* NULL end of table */
 254                0
 255        };
 256        disable_cache();
 257        do_early_mtrr_init(mtrr_msrs);
 258        enable_cache();
 259}
 260#endif
 261
 262int early_mtrr_init_detected(void)
 263{
 264        struct msr msr;
 265        /* See if MTRR's are enabled.
 266         * a #RESET disables them while an #INIT
 267         * preserves their state.  This works
 268         * on both Intel and AMD cpus, at least
 269         * according to the documentation.
 270         */
 271        msr = rdmsr(MTRRdefType_MSR);
 272        return msr.lo & 0x00000800;
 273}
 274
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.