aboutsummaryrefslogtreecommitdiff
path: root/src/northbridge/amd/amdmct/mct/mctmtr_d.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/northbridge/amd/amdmct/mct/mctmtr_d.c')
-rw-r--r--src/northbridge/amd/amdmct/mct/mctmtr_d.c213
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;
+}
+
+