blob: d38f05adcb86594d207661742066ee63bbff9119 [file] [log] [blame]
/* we will compile this into initram since some basic prototypes differ with same names on v2. Sigh. */
#include <mainboard.h>
#include <config.h>
#include <types.h>
#include <io.h>
#include <console.h>
#include <cpu.h>
#include <globalvars.h>
#include <lar.h>
#include <string.h>
#include <tables.h>
#include <lib.h>
#include <mc146818rtc.h>
#include <msr.h>
#include <mtrr.h>
#if 1
#define BIOS_MTRRS 6
#define OS_MTRRS 2
#else
#define BIOS_MTRRS 8
#define OS_MTRRS 0
#endif
#define MTRRS (BIOS_MTRRS + OS_MTRRS)
/* fms: find most sigificant bit set, stolen from Linux Kernel Source. */
static inline u32 fms(u32 x)
{
int r;
__asm__("bsrl %1,%0\n\t"
"jnz 1f\n\t"
"movl $0,%0\n"
"1:" : "=r" (r) : "g" (x));
return r;
}
/* fls: find least sigificant bit set */
static inline u32 fls(u32 x)
{
int r;
__asm__("bsfl %1,%0\n\t"
"jnz 1f\n\t"
"movl $32,%0\n"
"1:" : "=r" (r) : "g" (x));
return r;
}
u32 stage1_resk(u64 value)
{
u32 resultk;
if (value < (1ULL << 42)) {
resultk = value >> 10;
}
else {
resultk = 0xffffffff;
}
return resultk;
}
/* Sets the entire fixed mtrr to a cache type. */
void stage1_set_fix_mtrr(u32 reg, u8 type)
{
struct msr msr;
/* Enable Modify Extended RdMem and WrMem settings */
msr = rdmsr(SYSCFG_MSR);
msr.lo |= SYSCFG_MSR_MtrrFixDramModEn;
wrmsr(SYSCFG_MSR, msr);
msr.lo = (type << 24) | (type << 16) | (type << 8) | type;
msr.hi = (type << 24) | (type << 16) | (type << 8) | type;
wrmsr(reg, msr);
/* Disable Modify Extended RdMem and WrMem settings */
msr = rdmsr(SYSCFG_MSR);
msr.lo &= ~SYSCFG_MSR_MtrrFixDramModEn;
wrmsr(SYSCFG_MSR, msr);
}
/* Set a variable MTRR, comes from linux kernel source
* use stage1_range_to_mtrr() to set variable MTRRs.
*/
static void stage1_set_var_mtrr(u8 reg, u32 basek, u32 sizek,
u8 type, u32 address_bits)
{
struct msr base, mask;
u32 address_mask_high;
if (reg >= MTRRS) {
printk(BIOS_ERR,"Requested MTRR is out of range!\n");
return;
}
if (sizek == 0) {
struct msr zero;
zero.lo = zero.hi = 0;
disable_cache(); /* disable/enable cache when setting MTRRs */
/* The invalid bit is kept in the mask, so we simply clear the
relevant mask register to disable a range. */
wrmsr (MTRRphysMask_MSR(reg), zero);
enable_cache();
return;
}
address_mask_high = ((1u << (address_bits - 32u)) - 1u);
base.hi = basek >> 22;
base.lo = basek << 10;
printk(BIOS_SPEW, "ADDRESS_MASK_HIGH=%#x\n", address_mask_high);
if (sizek < 4*1024*1024) {
mask.hi = address_mask_high;
mask.lo = ~((sizek << 10) -1);
}
else {
mask.hi = address_mask_high & (~((sizek >> 22) -1));
mask.lo = 0;
}
disable_cache(); /* disable/enable cache when setting MTRRs */
/* Bit 32-35 of MTRRphysMask should be set to 1 */
base.lo |= type;
mask.lo |= 0x800;
wrmsr (MTRRphysBase_MSR(reg), base);
wrmsr (MTRRphysMask_MSR(reg), mask);
enable_cache();
}
/* Set a memory range to variable MTRRs.
* This handles the power of 2 alignment requirement.
*/
u8 stage1_range_to_mtrr(u8 reg, u32 range_startk, u32 range_sizek,
u8 type, u32 address_bits)
{
if (!range_sizek) {
printk(BIOS_SPEW, "Zero-sized MTRR range @%dKB\n", range_startk);
return reg;
}
if (reg >= BIOS_MTRRS) {
printk(BIOS_ERR, "ERROR: Out of MTRRs for base: %4dMB, range: %dMB, type %s\n",
range_startk >>10, range_sizek >> 10,
(type==MTRR_TYPE_UNCACHEABLE)?"UC":
((type==MTRR_TYPE_WRBACK)?"WB":"Other") );
return reg;
}
while(range_sizek) {
u32 max_align, align;
u32 sizek;
/* Compute the maximum size I can make a range */
max_align = fls(range_startk);
align = fms(range_sizek);
if (align > max_align) {
align = max_align;
}
sizek = 1 << align;
printk(BIOS_DEBUG,"Setting variable MTRR %d, base: %dKB, range: %dKB, type %s\n",
reg, range_startk, sizek,
(type==MTRR_TYPE_UNCACHEABLE)?"UC":
((type==MTRR_TYPE_WRBACK)?"WB":"Other")
);
stage1_set_var_mtrr(reg++, range_startk, sizek, type, address_bits);
range_startk += sizek;
range_sizek -= sizek;
if (reg >= BIOS_MTRRS) {
printk(BIOS_ERR, "Out of variable MTRRs!\n");
break;
}
}
return reg;
}
void cache_cbmem(int type)
{
/* Enable caching for 0 - 1MB(CONFIG_CBMEMK) using variable mtrr */
disable_cache();
stage1_range_to_mtrr(0, 0, CONFIG_CBMEMK, MTRR_TYPE_WRBACK, CPU_ADDR_BITS);
enable_cache();
}
/* early_mtrr_init was only usable for ROMCC compiled code. It nukes CAR.
* The only remaining purpose would be to enable ROM caching here instead of
* in stage0.S and even that is debatable.
*/
#if 0
/* the fixed and variable MTTRs are power-up with random values,
* clear them to MTRR_TYPE_UNCACHEABLE for safty.
*/
void do_early_mtrr_init(const unsigned long *mtrr_msrs)
{
/* Precondition:
* The cache is not enabled in cr0 nor in MTRRdefType_MSR
* entry32.inc ensures the cache is not enabled in cr0
*/
struct msr msr;
const unsigned long *msr_addr;
/* Inialize all of the relevant msrs to 0 */
msr.lo = 0;
msr.hi = 0;
unsigned long msr_nr;
for(msr_addr = mtrr_msrs; (msr_nr = *msr_addr); msr_addr++) {
wrmsr(msr_nr, msr);
}
#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.
#if 0
#if defined(XIP_ROM_SIZE)
/* enable write through caching so we can do execute in place
* on the flash rom.
*/
stage1_range_to_mtrr(1, 0, XIP_ROM_BASE >> 10, XIP_ROM_SIZE >> 10,
MTRR_TYPE_WRBACK, CPU_ADDR_BITS);
#endif
#endif
/* Set the default memory type and enable fixed and variable MTRRs
*/
/* Enable Variable MTRRs */
msr.hi = 0x00000000;
msr.lo = 0x00000800;
wrmsr(MTRRdefType_MSR, msr);
}
/**
* Call this function early in stage1 to enable mtrrs, which will ensure
* caching of ROM
*/
void early_mtrr_init(void)
{
static const unsigned long mtrr_msrs[] = {
/* fixed mtrr */
0x250, 0x258, 0x259,
0x268, 0x269, 0x26A,
0x26B, 0x26C, 0x26D,
0x26E, 0x26F,
/* var mtrr */
0x200, 0x201, 0x202, 0x203,
0x204, 0x205, 0x206, 0x207,
0x208, 0x209, 0x20A, 0x20B,
0x20C, 0x20D, 0x20E, 0x20F,
/* NULL end of table */
0
};
disable_cache();
do_early_mtrr_init(mtrr_msrs);
enable_cache();
}
#endif
int early_mtrr_init_detected(void)
{
struct msr msr;
/* See if MTRR's are enabled.
* a #RESET disables them while an #INIT
* preserves their state. This works
* on both Intel and AMD cpus, at least
* according to the documentation.
*/
msr = rdmsr(MTRRdefType_MSR);
return msr.lo & 0x00000800;
}