d7cb3649e58f7ed82dceff25dcaf7716cc3d415b
[coreboot.git] / src / northbridge / amd / amdmct / mct / mctmtr_d.c
1 /*
2  * This file is part of the LinuxBIOS project.
3  *
4  * Copyright (C) 2007 Advanced Micro Devices, Inc.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; version 2 of the License.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
18  */
19
20
21 #include "mct_d.h"
22
23 static void SetMTRRrangeWB_D(u32 Base, u32 *pLimit, u32 *pMtrrAddr);
24 static void SetMTRRrange_D(u32 Base, u32 *pLimit, u32 *pMtrrAddr, u16 MtrrType);
25
26 void CPUMemTyping_D(struct MCTStatStruc *pMCTstat,
27                          struct DCTStatStruc *pDCTstatA)
28 {
29         /* BSP only.  Set the fixed MTRRs for common legacy ranges.
30          * Set TOP_MEM and TOM2.
31          * Set some variable MTRRs with WB Uncacheable type.
32          */
33
34         u32 Bottom32bIO, Bottom40bIO, Cache32bTOP;
35         u32 val;
36         u32 addr;
37         u32 lo, hi;
38
39         /* Set temporary top of memory from Node structure data.
40          * Adjust temp top of memory down to accomodate 32-bit IO space.
41          * Bottom40bIO=top of memory, right justified 8 bits
42          *      (defines dram versus IO space type)
43          * Bottom32bIO=sub 4GB top of memory, right justified 8 bits
44          *      (defines dram versus IO space type)
45          * Cache32bTOP=sub 4GB top of WB cacheable memory,
46          *      right justified 8 bits
47          */
48
49         val = mctGet_NVbits(NV_BottomIO);
50         if(val == 0)
51                 val++;
52
53         Bottom32bIO = val << (24-8);
54
55         val = pMCTstat->SysLimit + 1;
56         if(val <= _4GB_RJ8) {
57                 Bottom40bIO = 0;
58                 if(Bottom32bIO >= val)
59                         Bottom32bIO = val;
60         } else {
61                 Bottom40bIO = val;
62         }
63
64         val = mctGet_NVbits(NV_BottomUMA);
65         if(val == 0)
66                 val++;
67
68         val <<= (24-8);
69         if(val >  Bottom32bIO)
70                 val = Bottom32bIO;
71
72         Cache32bTOP = val;
73
74         /*======================================================================
75          Set default values for CPU registers
76         ======================================================================*/
77
78         /* NOTE : For LinuxBIOS, we don't need to set mtrr enables here because
79         they are still enable from cache_as_ram.inc */
80
81         addr = 0x250;
82         lo = 0x1E1E1E1E;
83         hi = lo;
84         _WRMSR(addr, lo, hi);           /* 0 - 512K = WB Mem */
85         addr = 0x258;
86         _WRMSR(addr, lo, hi);           /* 512K - 640K = WB Mem */
87
88         /*======================================================================
89           Set variable MTRR values
90          ======================================================================*/
91         /* NOTE: for LinuxBIOS change from 0x200 to 0x204: LinuxBIOS is using
92                 0x200, 0x201 for [1M, CONFIG_TOP_MEM)
93                 0x202, 0x203 for ROM Caching
94                  */
95         addr = 0x204;   /* MTRR phys base 2*/
96                         /* use TOP_MEM as limit*/
97                         /* Limit=TOP_MEM|TOM2*/
98                         /* Base=0*/
99         print_tx("\t CPUMemTyping: Cache32bTOP:", Cache32bTOP);
100         SetMTRRrangeWB_D(0, &Cache32bTOP, &addr);
101                                 /* Base */
102                                 /* Limit */
103                                 /* MtrrAddr */
104         if(addr == -1)          /* ran out of MTRRs?*/
105                 pMCTstat->GStatus |= 1<<GSB_MTRRshort;
106
107         pMCTstat->Sub4GCacheTop = Cache32bTOP<<8;
108
109         /*======================================================================
110          Set TOP_MEM and TOM2 CPU registers
111         ======================================================================*/
112         addr = TOP_MEM;
113         lo = Bottom32bIO<<8;
114         hi = Bottom32bIO>>24;
115         _WRMSR(addr, lo, hi);
116         print_tx("\t CPUMemTyping: Bottom32bIO:", Bottom32bIO);
117         print_tx("\t CPUMemTyping: Bottom40bIO:", Bottom40bIO);
118         if(Bottom40bIO) {
119                 hi = Bottom40bIO >> 24;
120                 lo = Bottom40bIO << 8;
121                 addr += 3;              /* TOM2 */
122                 _WRMSR(addr, lo, hi);
123         }
124         addr = 0xC0010010;              /* SYS_CFG */
125         _RDMSR(addr, &lo, &hi);
126         if(Bottom40bIO) {
127                 lo |= (1<<21);          /* MtrrTom2En=1 */
128                 lo |= (1<<22);          /* Tom2ForceMemTypeWB */
129         } else {
130                 lo &= ~(1<<21);         /* MtrrTom2En=0 */
131                 lo &= ~(1<<22);         /* Tom2ForceMemTypeWB */
132         }
133         _WRMSR(addr, lo, hi);
134 }
135
136
137 static void SetMTRRrangeWB_D(u32 Base, u32 *pLimit, u32 *pMtrrAddr)
138 {
139         /*set WB type*/
140         SetMTRRrange_D(Base, pLimit, pMtrrAddr, 6);
141 }
142
143
144 static void SetMTRRrange_D(u32 Base, u32 *pLimit, u32 *pMtrrAddr, u16 MtrrType)
145 {
146         /* Program MTRRs to describe given range as given cache type.
147          * Use MTRR pairs starting with the given MTRRphys Base address,
148          * and use as many as is required up to (excluding) MSR 020C, which
149          * is reserved for OS.
150          *
151          * "Limit" in the context of this procedure is not the numerically
152          * correct limit, but rather the Last address+1, for purposes of coding
153          * efficiency and readability.  Size of a region is then Limit-Base.
154          *
155          * 1. Size of each range must be a power of two
156          * 2. Each range must be naturally aligned (Base is same as size)
157          *
158          * There are two code paths: the ascending path and descending path
159          * (analogous to bsf and bsr), where the next limit is a funtion of the
160          * next set bit in a forward or backward sequence of bits (as a function
161          * of the Limit). We start with the ascending path, to ensure that
162          * regions are naturally aligned, then we switch to the descending path
163          * to maximize MTRR usage efficiency. Base=0 is a special case where we
164          * start with the descending path. Correct Mask for region is
165          * 2comp(Size-1)-1, which is 2comp(Limit-Base-1)-1
166          */
167
168         u32 curBase, curLimit, curSize;
169         u32 val, valx;
170         u32 addr;
171
172         val = curBase = Base;
173         curLimit = *pLimit;
174         addr = *pMtrrAddr;
175         while((addr >= 0x200) && (addr < 0x20C) && (val < *pLimit)) {
176                 /* start with "ascending" code path */
177                 /* alignment (largest block size)*/
178                 valx = 1 << bsf(curBase);
179                 curSize = valx;
180
181                 /* largest legal limit, given current non-zero range Base*/
182                 valx += curBase;
183                 if((curBase == 0) || (*pLimit < valx)) {
184                         /* flop direction to "descending" code path*/
185                         valx = 1<<bsr(*pLimit - curBase);
186                         curSize = valx;
187                         valx += curBase;
188                 }
189                 curLimit = valx;                /*eax=curBase, edx=curLimit*/
190                 valx = val>>24;
191                 val <<= 8;
192
193                 /* now program the MTRR */
194                 val |= MtrrType;                /* set cache type (UC or WB)*/
195                 _WRMSR(addr, val, valx);        /* prog. MTRR with current region Base*/
196                 val = ((~(curSize - 1))+1) - 1; /* Size-1*/ /*Mask=2comp(Size-1)-1*/
197                 valx = (val >> 24) | (0xff00);  /* GH have 48 bits addr */
198                 val <<= 8;
199                 val |= ( 1 << 11);                      /* set MTRR valid*/
200                 addr++;
201                 _WRMSR(addr, val, valx);        /* prog. MTRR with current region Mask*/
202                 val = curLimit;
203                 curBase = val;                  /* next Base = current Limit (loop exit)*/
204                 addr++;                         /* next MTRR pair addr */
205         }
206         if(val < *pLimit) {
207                 *pLimit = val;
208                 addr = -1;
209         }
210         *pMtrrAddr = addr;
211 }
212
213