blob: 8afdf5015a4463a809c171c3ebae1fbcf8e011a1 [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
*/
static u32 mct_ControlRC(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat, u32 MrsChipSel, u32 CtrlWordNum)
{
u8 Dimms, DimmNum, MaxDimm, Speed;
u32 val;
u32 dct = 0;
u32 reg_off = 0;
DimmNum = (MrsChipSel >> 20) & 0xFE;
/* assume dct=0; */
/* if (dct == 1) */
/* DimmNum ++; */
/* cl +=8; */
MaxDimm = mctGet_NVbits(NV_MAX_DIMMS);
Speed = pDCTstat->DIMMAutoSpeed;
if (pDCTstat->CSPresent_DCT[0] > 0) {
dct = 0;
} else if (pDCTstat->CSPresent_DCT[1] > 0 ){
dct = 1;
DimmNum ++;
}
reg_off = 0x100 * dct;
Dimms = pDCTstat->MAdimms[dct];
val = 0;
if (CtrlWordNum == 0)
val |= 1 << 1;
else if (CtrlWordNum == 1) {
if (!((pDCTstat->DimmDRPresent | pDCTstat->DimmQRPresent) & (1 << DimmNum)))
val |= 0xC; /* if single rank, set DBA1 and DBA0 */
} else if (CtrlWordNum == 2) {
if (MaxDimm == 4) {
if (Speed == 4) {
if (((pDCTstat->DimmQRPresent & (1 << DimmNum)) && (Dimms == 1)) || (Dimms == 2))
if (!(pDCTstat->MirrPresU_NumRegR & (1 << DimmNum)))
val |= 1 << 2;
} else {
if (pDCTstat->MirrPresU_NumRegR & (1 << DimmNum))
val |= 1 << 2;
}
} else {
if (Dimms > 1)
val |= 1 << 2;
}
} else if (CtrlWordNum == 3) {
val |= (pDCTstat->CtrlWrd3 >> (DimmNum << 2)) & 0xFF;
} else if (CtrlWordNum == 4) {
val |= (pDCTstat->CtrlWrd4 >> (DimmNum << 2)) & 0xFF;
} else if (CtrlWordNum == 5) {
val |= (pDCTstat->CtrlWrd5 >> (DimmNum << 2)) & 0xFF;
} else if (CtrlWordNum == 8) {
if (MaxDimm == 4)
if (Speed == 4)
if (pDCTstat->MirrPresU_NumRegR & (1 << DimmNum))
val |= 1 << 2;
} else if (CtrlWordNum == 9) {
val |= 0xD; /* DBA1, DBA0, DA3 = 0 */
}
val &= 0xffffff0f;
val = MrsChipSel | ((val >> 2) & 3) << 16 | ((val & 3) << 3);
/* transfer Control word number to address [BA2,A2,A1,A0] */
if (CtrlWordNum > 7) {
val |= 1 << 18;
CtrlWordNum &= 7;
}
val |= CtrlWordNum;
return val;
}
static void mct_SendCtrlWrd(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat, u32 val)
{
u32 reg_off = 0;
u32 dev = pDCTstat->dev_dct;
if (pDCTstat->CSPresent_DCT[0] > 0) {
reg_off = 0;
} else if (pDCTstat->CSPresent_DCT[1] > 0 ){
reg_off = 0x100;
}
val |= Get_NB32(dev, reg_off + 0x7C) & ~0xFFFFFF;
val |= 1 << SendControlWord;
Set_NB32(dev, reg_off + 0x7C, val);
do {
val = Get_NB32(dev, reg_off + 0x7C);
} while (val & (1 << SendControlWord));
}
void mct_DramControlReg_Init_D(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat, u8 dct)
{
u8 MrsChipSel;
u32 dev = pDCTstat->dev_dct;
u32 val, cw;
u32 reg_off = 0x100 * dct;
mct_Wait(1600);
mct_Wait(1200);
for (MrsChipSel = 0; MrsChipSel < 8; MrsChipSel ++, MrsChipSel ++) {
if (pDCTstat->CSPresent & (1 << MrsChipSel)) {
val = Get_NB32(dev, reg_off + 0xA8);
val &= ~(0xF << 8);
switch (MrsChipSel) {
case 0:
case 1:
val |= 3 << 8;
case 2:
case 3:
val |= (3 << 2) << 8;
case 4:
case 5:
val |= (3 << 4) << 8;
case 6:
case 7:
val |= (3 << 6) << 8;
}
Set_NB32(dev, reg_off + 0xA8 , val);
for (cw=0; cw <=15; cw ++) {
mct_Wait(1600);
if (!(cw==6 || cw==7)) {
val = mct_ControlRC(pMCTstat, pDCTstat, MrsChipSel << 20, cw);
mct_SendCtrlWrd(pMCTstat, pDCTstat, val);
}
}
}
}
mct_Wait(1200);
}
void FreqChgCtrlWrd(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat)
{
u32 SaveSpeed = pDCTstat->DIMMAutoSpeed;
u32 MrsChipSel;
u32 dev = pDCTstat->dev_dct;
u32 val;
pDCTstat->DIMMAutoSpeed = pDCTstat->TargetFreq;
for (MrsChipSel=0; MrsChipSel < 8; MrsChipSel++, MrsChipSel++) {
if (pDCTstat->CSPresent & (1 << MrsChipSel)) {
/* 2. Program F2x[1, 0]A8[CtrlWordCS]=bit mask for target chip selects. */
val = Get_NB32(dev, 0xA8); /* TODO: dct * 0x100 + 0xA8 */
val &= ~(0xFF << 8);
val |= (0x3 << (MrsChipSel & 0xFE)) << 8;
Set_NB32(dev, 0xA8, val); /* TODO: dct * 0x100 + 0xA8 */
/* Resend control word 10 */
mct_Wait(1600);
switch (pDCTstat->TargetFreq) {
case 5:
mct_SendCtrlWrd(pMCTstat, pDCTstat, MrsChipSel << 20 | 0x4000A);
break;
case 6:
mct_SendCtrlWrd(pMCTstat, pDCTstat, MrsChipSel << 20 | 0x40012);
break;
case 7:
mct_SendCtrlWrd(pMCTstat, pDCTstat, MrsChipSel << 20 | 0x4001A);
break;
}
mct_Wait(1600);
/* Resend control word 2 */
val = mct_ControlRC(pMCTstat, pDCTstat, MrsChipSel << 20, 2);
mct_SendCtrlWrd(pMCTstat, pDCTstat, val);
mct_Wait(1600);
/* Resend control word 8 */
val = mct_ControlRC(pMCTstat, pDCTstat, MrsChipSel << 20, 8);
mct_SendCtrlWrd(pMCTstat, pDCTstat, val);
mct_Wait(1600);
}
}
pDCTstat->DIMMAutoSpeed = SaveSpeed;
}