2 * This file is part of the coreboot project.
4 * Copyright (C) 2007 Advanced Micro Devices, Inc.
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.
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.
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
22 void InterleaveNodes_D(struct MCTStatStruc *pMCTstat,
23 struct DCTStatStruc *pDCTstatA)
26 /* Applies Node memory interleaving if enabled and if all criteria are met. */
29 u32 MemSize, MemSize0 = 0;
30 u32 Dct0MemSize = 0, DctSelBase, DctSelBaseOffset;
43 struct DCTStatStruc *pDCTstat;
45 DoIntlv = mctGet_NVbits(NV_NodeIntlv);
48 HWHoleSz = 0; /*For HW remapping, NOT Node hoisting. */
50 pDCTstat = pDCTstatA + 0;
51 dev0 = pDCTstat->dev_host;
52 Nodes = ((Get_NB32(dev0, 0x60) >> 4) & 0x7) + 1;
55 dev0 = pDCTstat->dev_map;
61 while (DoIntlv && (Node < Nodes)) {
62 pDCTstat = pDCTstatA + Node;
63 if (pMCTstat->GStatus & (1 << GSB_SpIntRemapHole)) {
64 pMCTstat->GStatus |= 1 << GSB_HWHole;
66 } else if (pDCTstat->Status & (1 << SB_SWNodeHole)) {
73 Base = Get_NB32(dev0, reg0);
76 Base &= 0xFFFF0000; /* Base[39:8] */
78 if (pDCTstat->Status & (1 << SB_HWHole )) {
80 /* to get true amount of dram,
81 * subtract out memory hole if HW dram remapping */
82 DramHoleAddrReg = Get_NB32(pDCTstat->dev_map, 0xF0);
83 HWHoleSz = DramHoleAddrReg >> 16;
84 HWHoleSz = (((~HWHoleSz) + 1) & 0xFF);
87 /* check to see if the amount of memory on each channel
88 * are the same on all nodes */
90 DctSelBase = Get_NB32(pDCTstat->dev_dct, 0x114);
93 if ( pDCTstat->Status & (1 << SB_HWHole)) {
94 if (DctSelBase >= 0x1000000) {
95 DctSelBase -= HWHoleSz;
98 DctSelBaseOffset -= Base;
100 Dct0MemSize = DctSelBase;
101 } else if (DctSelBase != Dct0MemSize) {
106 MemSize = Get_NB32(dev0, reg0 + 4);
107 MemSize &= 0xFFFF0000;
108 MemSize += 0x00010000;
110 if ( pDCTstat->Status & (1 << SB_HWHole)) {
115 } else if (MemSize0 != MemSize) {
129 /* if all nodes have memory and no Node had SW memhole */
130 if (Nodes == 2 || Nodes == 4 || Nodes == 8)
138 if (pMCTstat->GStatus & 1 << (GSB_SpIntRemapHole)) {
139 HWHoleSz = pMCTstat->HoleBase;
141 HWHoleSz = mctGet_NVbits(NV_BottomIO) & 0xFF;
144 HWHoleSz = ((~HWHoleSz) + 1) & 0x00FF0000;
148 MCTMemClr_D(pMCTstat,pDCTstatA);
149 /* Program Interleaving enabled on Node 0 map only.*/
150 MemSize0 <<= bsf(Nodes); /* MemSize=MemSize*2 (or 4, or 8) */
151 Dct0MemSize <<= bsf(Nodes);
152 MemSize0 += HWHoleSz;
153 Base = ((Nodes - 1) << 8) | 3;
156 while(Node < Nodes) {
157 Set_NB32(dev0, reg0, Base);
160 MemSize &= 0xFFFF0000;
161 MemSize |= Node << 8; /* set IntlvSel[2:0] field */
162 MemSize |= Node; /* set DstNode[2:0] field */
163 Set_NB32(dev0, reg0 + 4, MemSize0);
168 /* set base/limit to F1x120/124 per Node */
170 while(Node < Nodes) {
171 pDCTstat = pDCTstatA + Node;
172 pDCTstat->NodeSysBase = 0;
176 pDCTstat->NodeSysLimit = MemSize;
177 Set_NB32(pDCTstat->dev_map, 0x120, Node << 21);
185 Set_NB32(pDCTstat->dev_map, 0x124, val);
187 if (pMCTstat->GStatus & (1 << GSB_HWHole)) {
188 HoleBase = pMCTstat->HoleBase;
189 if (Dct0MemSize >= HoleBase) {
195 val = HWHoleSz + Dct0MemSize;
198 val >>= 8; /* DramHoleOffset */
199 HoleBase <<= 8; /* DramHoleBase */
201 val |= 1 << DramMemHoistValid;
202 val |= 1 << DramHoleValid;
203 Set_NB32(pDCTstat->dev_map, 0xF0, val);
207 Set_NB32(pDCTstat->dev_dct, 0x114, Dct0MemSize >> 8); /* DctSelBaseOffset */
208 val = Get_NB32(pDCTstat->dev_dct, 0x110);
210 val |= Dct0MemSize >> 8;
211 Set_NB32(pDCTstat->dev_dct, 0x110, val); /* DctSelBaseAddr */
212 print_tx("InterleaveNodes: DRAM Controller Select Low Register = ", val);
217 /* Copy Node 0 into other Nodes' CSRs */
219 while (Node < Nodes) {
220 pDCTstat = pDCTstatA + Node;
222 for (i = 0x40; i <= 0x80; i++) {
223 val = Get_NB32(dev0, i);
224 Set_NB32(pDCTstat->dev_map, i, val);
227 val = Get_NB32(dev0, 0xF0);
228 Set_NB32(pDCTstat->dev_map, 0xF0, val);
231 pMCTstat->GStatus = (1 << GSB_NodeIntlv);
233 print_tx("InterleaveNodes_D: Status ", pDCTstat->Status);
234 print_tx("InterleaveNodes_D: ErrStatus ", pDCTstat->ErrStatus);
235 print_tx("InterleaveNodes_D: ErrCode ", pDCTstat->ErrCode);
236 print_t("InterleaveNodes_D: Done\n");