aboutsummaryrefslogtreecommitdiff
path: root/src/northbridge/amd/amdmct/mct/mctchi_d.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/northbridge/amd/amdmct/mct/mctchi_d.c')
-rw-r--r--src/northbridge/amd/amdmct/mct/mctchi_d.c130
1 files changed, 130 insertions, 0 deletions
diff --git a/src/northbridge/amd/amdmct/mct/mctchi_d.c b/src/northbridge/amd/amdmct/mct/mctchi_d.c
new file mode 100644
index 0000000000..f50fd6d62e
--- /dev/null
+++ b/src/northbridge/amd/amdmct/mct/mctchi_d.c
@@ -0,0 +1,130 @@
+/*
+ * 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
+ */
+
+
+
+void InterleaveChannels_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstatA)
+{
+
+ u8 Node;
+ u32 DramBase, DctSelBase;
+ u8 DctSelIntLvAddr, DctSelHi;
+ u8 HoleValid = 0;
+ u32 HoleSize, HoleBase = 0;
+ u32 val, tmp;
+ u32 dct0_size, dct1_size;
+ u8 enabled;
+ struct DCTStatStruc *pDCTstat;
+
+ /* HoleValid - indicates whether the current Node contains hole.
+ * HoleSize - indicates whether there is IO hole in the whole system
+ * memory.
+ */
+
+ /* call back to wrapper not needed ManualChannelInterleave_D(); */
+ /* call back - DctSelIntLvAddr = mctGet_NVbits(NV_ChannelIntlv);*/ /* override interleave */
+ // FIXME: Check for Cx
+ DctSelIntLvAddr = 5; /* use default: Enable channel interleave */
+ enabled = 1; /* with Hash*: exclusive OR of address bits[20:16, 6]. */
+ beforeInterleaveChannels_D(pDCTstatA, &enabled);
+
+ if (enabled) {
+ DctSelIntLvAddr >>= 1;
+ HoleSize = 0;
+ if ((pMCTstat->GStatus & (1 << GSB_SoftHole)) ||
+ (pMCTstat->GStatus & (1 << GSB_HWHole))) {
+ if (pMCTstat->HoleBase) {
+ HoleBase = pMCTstat->HoleBase >> 8;
+ HoleSize = HoleBase & 0xFFFF0000;
+ HoleSize |= ((~HoleBase) + 1) & 0xFFFF;
+ }
+ }
+ Node = 0;
+ while (Node < MAX_NODES_SUPPORTED) {
+ pDCTstat = pDCTstatA + Node;
+ val = Get_NB32(pDCTstat->dev_map, 0xF0);
+ if (val & (1 << DramHoleValid))
+ HoleValid = 1;
+ if (!pDCTstat->GangedMode && pDCTstat->DIMMValidDCT[0] && pDCTstat->DIMMValidDCT[1]) {
+ DramBase = pDCTstat->NodeSysBase >> 8;
+ dct1_size = ((pDCTstat->NodeSysLimit) + 2) >> 8;
+ dct0_size = Get_NB32(pDCTstat->dev_dct, 0x114);
+ if (dct0_size >= 0x10000) {
+ dct0_size -= HoleSize;
+ }
+
+ dct0_size -= DramBase;
+ dct1_size -= dct0_size;
+ DctSelHi = 0x05; /* DctSelHiRngEn = 1, DctSelHi = 0 */
+ if (dct1_size == dct0_size) {
+ dct1_size = 0;
+ DctSelHi = 0x04; /* DctSelHiRngEn = 0 */
+ } else if (dct1_size > dct0_size ) {
+ dct1_size = dct0_size;
+ DctSelHi = 0x07; /* DctSelHiRngEn = 1, DctSelHi = 1 */
+ }
+ dct0_size = dct1_size;
+ dct0_size += DramBase;
+ dct0_size += dct1_size;
+ if (dct0_size >= HoleBase) /* if DctSelBaseAddr > HoleBase */
+ dct0_size += HoleBase;
+ DctSelBase = dct0_size;
+
+ if (dct1_size == 0)
+ dct0_size = 0;
+ dct0_size -= dct1_size; /* DctSelBaseOffset = DctSelBaseAddr - Interleaved region */
+ Set_NB32(pDCTstat->dev_dct, 0x114, dct0_size);
+
+ if (dct1_size == 0)
+ dct1_size = DctSelBase;
+ val = Get_NB32(pDCTstat->dev_dct, 0x110);
+ val &= 0x7F8;
+ val |= dct1_size;
+ val |= DctSelHi;
+ val |= (DctSelIntLvAddr << 6) & 0xFF;
+ Set_NB32(pDCTstat->dev_dct, 0x110, val);
+ print_tx("InterleaveChannels: DRAM Controller Select Low Register = ", val);
+
+ if (HoleValid) {
+ tmp = DramBase;
+ val = DctSelBase;
+ if (val < HoleBase) { /* DctSelBaseAddr < DramHoleBase */
+ val -= DramBase;
+ val >>= 1;
+ tmp += val;
+ }
+ tmp += HoleSize;
+ val = Get_NB32(pDCTstat->dev_map, 0xF0); /* DramHoleOffset */
+ val &= 0x7F;
+ val |= (tmp & 0xFF);
+ Set_NB32(pDCTstat->dev_map, 0xF0, val);
+print_tx("InterleaveChannels:0xF0 = ", val);
+
+ }
+ }
+ print_tx("InterleaveChannels_D: Node ", Node);
+ print_tx("InterleaveChannels_D: Status ", pDCTstat->Status);
+ print_tx("InterleaveChannels_D: ErrStatus ", pDCTstat->ErrStatus);
+ print_tx("InterleaveChannels_D: ErrCode ", pDCTstat->ErrCode);
+ Node++;
+ }
+ }
+ print_t("InterleaveChannels_D: Done\n");
+}