diff options
Diffstat (limited to 'src/northbridge/amd/amdmct/mct/mctmtr_d.c')
-rw-r--r-- | src/northbridge/amd/amdmct/mct/mctmtr_d.c | 213 |
1 files changed, 213 insertions, 0 deletions
diff --git a/src/northbridge/amd/amdmct/mct/mctmtr_d.c b/src/northbridge/amd/amdmct/mct/mctmtr_d.c new file mode 100644 index 0000000000..d7cb3649e5 --- /dev/null +++ b/src/northbridge/amd/amdmct/mct/mctmtr_d.c @@ -0,0 +1,213 @@ +/* + * This file is part of the LinuxBIOS project. + * + * Copyright (C) 2007 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 accomodate 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; + } + + val = mctGet_NVbits(NV_BottomUMA); + if(val == 0) + val++; + + val <<= (24-8); + if(val > Bottom32bIO) + val = Bottom32bIO; + + Cache32bTOP = val; + + /*====================================================================== + Set default values for CPU registers + ======================================================================*/ + + /* NOTE : For LinuxBIOS, 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 LinuxBIOS change from 0x200 to 0x204: LinuxBIOS 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*/ + print_tx("\t CPUMemTyping: Cache32bTOP:", 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); + print_tx("\t CPUMemTyping: Bottom32bIO:", Bottom32bIO); + print_tx("\t CPUMemTyping: Bottom40bIO:", 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 funtion 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; +} + + |