blob: b73426379c99d0e5a45c8db1d50eda5775324387 [file] [log] [blame]
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2010 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
*/
/* 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);
}
}
} /* DoIntlv */
/* dump_pci_device(PCI_DEV(0, 0x18+pDCTstat->Node_ID, 2)); */
printk(BIOS_DEBUG, "InterleaveBanks_D: Status %x\n", pDCTstat->Status);
printk(BIOS_DEBUG, "InterleaveBanks_D: ErrStatus %x\n", pDCTstat->ErrStatus);
printk(BIOS_DEBUG, "InterleaveBanks_D: ErrCode %x\n", pDCTstat->ErrCode);
printk(BIOS_DEBUG, "InterleaveBanks_D: Done\n\n");
}