blob: 4eb61a57a6d02663b9a26b9a35f3f1714aed4146 [file] [log] [blame]
/*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "mct_d.h"
static void SetMTRRrangeWB_D(u32 Base, u32 *pLimit, u32 *pMtrrAddr);
static void SetMTRRrange_D(u32 Base, u32 *pLimit, u32 *pMtrrAddr, u16 MtrrType);
void CPUMemTyping_D(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstatA)
{
/* BSP only. Set the fixed MTRRs for common legacy ranges.
* Set TOP_MEM and TOM2.
* Set some variable MTRRs with WB Uncacheable type.
*/
u32 Bottom32bIO, Bottom40bIO, Cache32bTOP;
u32 val;
u32 addr;
u32 lo, hi;
/* Set temporary top of memory from Node structure data.
* Adjust temp top of memory down to accommodate 32-bit IO space.
* Bottom40bIO=top of memory, right justified 8 bits
* (defines dram versus IO space type)
* Bottom32bIO=sub 4GB top of memory, right justified 8 bits
* (defines dram versus IO space type)
* Cache32bTOP=sub 4GB top of WB cacheable memory,
* right justified 8 bits
*/
val = mctGet_NVbits(NV_BottomIO);
if(val == 0)
val++;
Bottom32bIO = val << (24-8);
val = pMCTstat->SysLimit + 1;
if(val <= _4GB_RJ8) {
Bottom40bIO = 0;
if(Bottom32bIO >= val)
Bottom32bIO = val;
} else {
Bottom40bIO = val;
}
Cache32bTOP = Bottom32bIO;
/*======================================================================
Set default values for CPU registers
======================================================================*/
/* NOTE : For coreboot, we don't need to set mtrr enables here because
they are still enable from cache_as_ram.inc */
addr = 0x250;
lo = 0x1E1E1E1E;
hi = lo;
_WRMSR(addr, lo, hi); /* 0 - 512K = WB Mem */
addr = 0x258;
_WRMSR(addr, lo, hi); /* 512K - 640K = WB Mem */
/*======================================================================
Set variable MTRR values
======================================================================*/
/* NOTE: for coreboot change from 0x200 to 0x204: coreboot is using
0x200, 0x201 for [1M, CONFIG_TOP_MEM)
0x202, 0x203 for ROM Caching
*/
addr = 0x204; /* MTRR phys base 2*/
/* use TOP_MEM as limit*/
/* Limit=TOP_MEM|TOM2*/
/* Base=0*/
printk(BIOS_DEBUG, "\t CPUMemTyping: Cache32bTOP:%x\n", Cache32bTOP);
SetMTRRrangeWB_D(0, &Cache32bTOP, &addr);
/* Base */
/* Limit */
/* MtrrAddr */
if(addr == -1) /* ran out of MTRRs?*/
pMCTstat->GStatus |= 1<<GSB_MTRRshort;
pMCTstat->Sub4GCacheTop = Cache32bTOP<<8;
/*======================================================================
Set TOP_MEM and TOM2 CPU registers
======================================================================*/
addr = TOP_MEM;
lo = Bottom32bIO<<8;
hi = Bottom32bIO>>24;
_WRMSR(addr, lo, hi);
printk(BIOS_DEBUG, "\t CPUMemTyping: Bottom32bIO:%x\n", Bottom32bIO);
printk(BIOS_DEBUG, "\t CPUMemTyping: Bottom40bIO:%x\n", Bottom40bIO);
if(Bottom40bIO) {
hi = Bottom40bIO >> 24;
lo = Bottom40bIO << 8;
addr += 3; /* TOM2 */
_WRMSR(addr, lo, hi);
}
addr = 0xC0010010; /* SYS_CFG */
_RDMSR(addr, &lo, &hi);
if(Bottom40bIO) {
lo |= (1<<21); /* MtrrTom2En=1 */
lo |= (1<<22); /* Tom2ForceMemTypeWB */
} else {
lo &= ~(1<<21); /* MtrrTom2En=0 */
lo &= ~(1<<22); /* Tom2ForceMemTypeWB */
}
_WRMSR(addr, lo, hi);
}
static void SetMTRRrangeWB_D(u32 Base, u32 *pLimit, u32 *pMtrrAddr)
{
/*set WB type*/
SetMTRRrange_D(Base, pLimit, pMtrrAddr, 6);
}
static void SetMTRRrange_D(u32 Base, u32 *pLimit, u32 *pMtrrAddr, u16 MtrrType)
{
/* Program MTRRs to describe given range as given cache type.
* Use MTRR pairs starting with the given MTRRphys Base address,
* and use as many as is required up to (excluding) MSR 020C, which
* is reserved for OS.
*
* "Limit" in the context of this procedure is not the numerically
* correct limit, but rather the Last address+1, for purposes of coding
* efficiency and readability. Size of a region is then Limit-Base.
*
* 1. Size of each range must be a power of two
* 2. Each range must be naturally aligned (Base is same as size)
*
* There are two code paths: the ascending path and descending path
* (analogous to bsf and bsr), where the next limit is a function of the
* next set bit in a forward or backward sequence of bits (as a function
* of the Limit). We start with the ascending path, to ensure that
* regions are naturally aligned, then we switch to the descending path
* to maximize MTRR usage efficiency. Base=0 is a special case where we
* start with the descending path. Correct Mask for region is
* 2comp(Size-1)-1, which is 2comp(Limit-Base-1)-1
*/
u32 curBase, curLimit, curSize;
u32 val, valx;
u32 addr;
val = curBase = Base;
curLimit = *pLimit;
addr = *pMtrrAddr;
while((addr >= 0x200) && (addr < 0x20C) && (val < *pLimit)) {
/* start with "ascending" code path */
/* alignment (largest block size)*/
valx = 1 << bsf(curBase);
curSize = valx;
/* largest legal limit, given current non-zero range Base*/
valx += curBase;
if((curBase == 0) || (*pLimit < valx)) {
/* flop direction to "descending" code path*/
valx = 1<<bsr(*pLimit - curBase);
curSize = valx;
valx += curBase;
}
curLimit = valx; /*eax=curBase, edx=curLimit*/
valx = val>>24;
val <<= 8;
/* now program the MTRR */
val |= MtrrType; /* set cache type (UC or WB)*/
_WRMSR(addr, val, valx); /* prog. MTRR with current region Base*/
val = ((~(curSize - 1))+1) - 1; /* Size-1*/ /*Mask=2comp(Size-1)-1*/
valx = (val >> 24) | (0xff00); /* GH have 48 bits addr */
val <<= 8;
val |= ( 1 << 11); /* set MTRR valid*/
addr++;
_WRMSR(addr, val, valx); /* prog. MTRR with current region Mask*/
val = curLimit;
curBase = val; /* next Base = current Limit (loop exit)*/
addr++; /* next MTRR pair addr */
}
if(val < *pLimit) {
*pLimit = val;
addr = -1;
}
*pMtrrAddr = addr;
}
void UMAMemTyping_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA)
{
/* UMA memory size may need splitting the MTRR configuration into two
Before training use NB_BottomIO or the physical memory size to set the MTRRs.
After training, add UMAMemTyping function to reconfigure the MTRRs based on
NV_BottomUMA (for UMA systems only).
This two-step process allows all memory to be cached for training
*/
u32 Bottom32bIO, Cache32bTOP;
u32 val;
u32 addr;
u32 lo, hi;
/*======================================================================
* Adjust temp top of memory down to accommodate UMA memory start
*======================================================================*/
/* Bottom32bIO=sub 4GB top of memory, right justified 8 bits
* (defines dram versus IO space type)
* Cache32bTOP=sub 4GB top of WB cacheable memory, right justified 8 bits */
Bottom32bIO = pMCTstat->Sub4GCacheTop >> 8;
val = mctGet_NVbits(NV_BottomUMA);
if (val == 0)
val++;
val <<= (24-8);
if (val < Bottom32bIO) {
Cache32bTOP = val;
pMCTstat->Sub4GCacheTop = val;
/*======================================================================
* Clear variable MTRR values
*======================================================================*/
addr = 0x200;
lo = 0;
hi = lo;
while( addr < 0x20C) {
_WRMSR(addr, lo, hi); /* prog. MTRR with current region Mask */
addr++; /* next MTRR pair addr */
}
/*======================================================================
* Set variable MTRR values
*======================================================================*/
printk(BIOS_DEBUG, "\t UMAMemTyping_D: Cache32bTOP:%x\n", Cache32bTOP);
SetMTRRrangeWB_D(0, &Cache32bTOP, &addr);
if(addr == -1) /* ran out of MTRRs?*/
pMCTstat->GStatus |= 1<<GSB_MTRRshort;
}
}