/* * 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. */ #include "mct_d.h" /* Low swap bit vs bank size encoding (physical, not logical address bit) * ;To calculate the number by hand, add the number of Bank address bits * ;(2 or 3) to the number of column address bits, plus 3 (the logical * ;page size), and subtract 8. */ static const u8 Tab_int_D[] = { 6,7,7,8,8,8,8,8,9,9,8,9 }; void InterleaveBanks_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u8 dct) { u8 ChipSel, EnChipSels; u32 AddrLoMask, AddrHiMask; u32 AddrLoMaskN, AddrHiMaskN, MemSize = 0; u8 DoIntlv, _CsIntCap; u32 BitDelta, BankEncd = 0; u32 dev; u32 reg; u32 reg_off; u32 val; u32 val_lo, val_hi; DoIntlv = mctGet_NVbits(NV_BankIntlv); _CsIntCap = 0; EnChipSels = 0; dev = pDCTstat->dev_dct; reg_off = 0x100 * dct; ChipSel = 0; /* Find out if current configuration is capable */ while (DoIntlv && (ChipSel < MAX_CS_SUPPORTED)) { reg = 0x40+(ChipSel << 2) + reg_off; /* Dram CS Base 0 */ val = Get_NB32(dev, reg); if (val & (1 << CSEnable)) { EnChipSels++; reg = 0x60+((ChipSel >> 1) << 2)+reg_off; /*Dram CS Mask 0 */ val = Get_NB32(dev, reg); val >>= 19; val &= 0x3ff; val++; if (EnChipSels == 1) MemSize = val; else /*If mask sizes not same then skip */ if (val != MemSize) break; reg = 0x80 + reg_off; /*Dram Bank Addressing */ val = Get_NB32(dev, reg); val >>= (ChipSel >> 1) << 2; val &= 0x0f; if (EnChipSels == 1) BankEncd = val; else /*If number of Rows/Columns not equal, skip */ if (val != BankEncd) break; } ChipSel++; } if (ChipSel == MAX_CS_SUPPORTED) { if ((EnChipSels == 2) || (EnChipSels == 4) || (EnChipSels == 8)) _CsIntCap = 1; } if (DoIntlv) { if (!_CsIntCap) { pDCTstat->ErrStatus |= 1 << SB_BkIntDis; DoIntlv = 0; } } if (DoIntlv) { val = Tab_int_D[BankEncd]; if (pDCTstat->Status & (1 << SB_128bitmode)) val++; AddrLoMask = (EnChipSels - 1) << val; AddrLoMaskN = ~AddrLoMask; val = bsf(MemSize) + 19; AddrHiMask = (EnChipSels -1) << val; AddrHiMaskN = ~AddrHiMask; BitDelta = bsf(AddrHiMask) - bsf(AddrLoMask); for (ChipSel = 0; ChipSel < MAX_CS_SUPPORTED; ChipSel++) { reg = 0x40+(ChipSel << 2) + reg_off; /*Dram CS Base 0 */ val = Get_NB32(dev, reg); if (val & 3) { val_lo = val & AddrLoMask; val_hi = val & AddrHiMask; val &= AddrLoMaskN; val &= AddrHiMaskN; val_lo <<= BitDelta; val_hi >>= BitDelta; val |= val_lo; val |= val_hi; Set_NB32(dev, reg, val); if (ChipSel & 1) continue; reg = 0x60 + ((ChipSel >> 1) << 2) + reg_off; /*Dram CS Mask 0 */ val = Get_NB32(dev, reg); val_lo = val & AddrLoMask; val_hi = val & AddrHiMask; val &= AddrLoMaskN; val &= AddrHiMaskN; val_lo <<= BitDelta; val_hi >>= BitDelta; val |= val_lo; val |= val_hi; Set_NB32(dev, reg, val); } } print_t("InterleaveBanks_D: Banks Interleaved "); } /* DoIntlv */ print_tx("InterleaveBanks_D: Status ", pDCTstat->Status); print_tx("InterleaveBanks_D: ErrStatus ", pDCTstat->ErrStatus); print_tx("InterleaveBanks_D: ErrCode ", pDCTstat->ErrCode); print_t("InterleaveBanks_D: Done\n"); }