/* * This file is part of the coreboot 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 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*/ print_tx("\t CPUMemTyping: Cache32bTOP:", Cache32bTOP); SetMTRRrangeWB_D(0, &Cache32bTOP, &addr); /* Base */ /* Limit */ /* MtrrAddr */ if(addr == -1) /* ran out of MTRRs?*/ pMCTstat->GStatus |= 1<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<>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; }