blob: e50372f34cd95b6908c95aaf114b4266bf5abb41 [file] [log] [blame]
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2009 One Laptop per Child, Association, 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 DRAMClearEndingAddress(DRAM_SYS_ATTR * DramAttr);
void DRAMSizingEachRank(DRAM_SYS_ATTR * DramAttr);
BOOLEAN DoDynamicSizing1XM(DRAM_SYS_ATTR * DramAttr,
u8 * nRA, u8 * nCA, u8 * nBS, u8 PhyRank);
void DRAMSetRankMAType(DRAM_SYS_ATTR * DramAttr);
void DRAMSetEndingAddress(DRAM_SYS_ATTR * DramAttr);
void DRAMPRToVRMapping(DRAM_SYS_ATTR * DramAttr);
/*===================================================================
Function : DRAMBankInterleave()
Precondition :
Input :
DramAttr: pointer point to DRAMSYSATTR which consist the DDR and Dimm information in MotherBoard
Output : Void
Purpose : STEP 13 Set Bank Interleave VIANB3DRAMREG69[7:6] 00:No Interleave 01:2 Bank 10:4 Bank 11:8 Bank
Scan all DIMMs on board to find out the lowest Bank Interleave among these DIMMs and set register.
===================================================================*/
void DRAMBankInterleave(DRAM_SYS_ATTR * DramAttr)
{
u8 Data, SpdBAData;
DIMM_INFO *CurrentDimminfo;
u8 Bank = 3, Shift, RankNO, Count;
Shift = 1;
for (RankNO = 0; RankNO < 4; RankNO += 2) //all_even 0 RankNO 4 6
{
if ((DramAttr->RankPresentMap & Shift) != 0) {
CurrentDimminfo = &(DramAttr->DimmInfo[RankNO >> 1]); //this Rank in a dimm
SpdBAData =
(u8) (CurrentDimminfo->SPDDataBuf
[SPD_SDRAM_NO_OF_BANKS]);
if (SpdBAData == 4)
Count = 2;
else if (SpdBAData == 8)
Count = 3;
else
Count = 0;
if (Count < Bank)
Bank = Count;
}
Shift <<= 2;
}
Data = pci_read_config8(MEMCTRL, 0x69);
Data &= ~0xc0;
Data |= (Bank << 6);
pci_write_config8(MEMCTRL, 0x69, Data);
if (DramAttr->DimmNumChB > 0) {
CurrentDimminfo = &(DramAttr->DimmInfo[3]); //this Rank in a dimm
SpdBAData =
(u8) (CurrentDimminfo->SPDDataBuf[SPD_SDRAM_NO_OF_BANKS]);
if (SpdBAData == 4)
Bank = 2;
else if (SpdBAData == 2)
Bank = 1;
else
Bank = 0;
pci_write_config8(MEMCTRL, 0x87, Bank);
}
}
/*===================================================================
Function : DRAMSizingMATypeM()
Precondition :
Input :
DramAttr: pointer point to DRAMSYSATTR which consist the DDR and Dimm information in MotherBoard
Output : Void
Purpose : STEP 14 1 DRAM Sizing 2 Fill MA type 3 Prank to vrankMapping
===================================================================*/
void DRAMSizingMATypeM(DRAM_SYS_ATTR * DramAttr)
{
DRAMClearEndingAddress(DramAttr);
DRAMSizingEachRank(DramAttr);
//DRAMReInitDIMMBL (DramAttr);
DRAMSetRankMAType(DramAttr);
DRAMSetEndingAddress(DramAttr);
DRAMPRToVRMapping(DramAttr);
}
/*===================================================================
Function : DRAMClearEndingAddress()
Precondition :
Input :
DramAttr: pointer point to DRAMSYSATTR which consist the DDR and Dimm information in MotherBoard
Output : Void
Purpose : clear Ending and Start adress from 0x40-4f to zero
===================================================================*/
void DRAMClearEndingAddress(DRAM_SYS_ATTR * DramAttr)
{
u8 Data, Reg;
Data = 0;
for (Reg = 0x40; Reg <= 0x4f; Reg++) {
pci_write_config8(MEMCTRL, Reg, Data);
}
}
/*===================================================================
Function : DRAMSizingEachRank()
Precondition :
Input :
DramAttr: pointer point to DRAMSYSATTR which consist the DDR and Dimm information in MotherBoard
Output : Void
Purpose : Sizing each Rank invidually, by number of rows column banks pins, be care about 128bit
===================================================================*/
void DRAMSizingEachRank(DRAM_SYS_ATTR * DramAttr)
{
u8 Slot, RankIndex, Rows, Columns, Banks;
u32 Size;
BOOLEAN HasThreeBitBA;
u8 Data;
HasThreeBitBA = FALSE;
for (Slot = 0; Slot < 2; Slot++) {
if (!DramAttr->DimmInfo[Slot].bPresence)
continue;
Rows = DramAttr->DimmInfo[Slot].SPDDataBuf[SPD_SDRAM_ROW_ADDR];
Columns =
DramAttr->DimmInfo[Slot].SPDDataBuf[SPD_SDRAM_COL_ADDR];
Banks = DramAttr->DimmInfo[Slot].SPDDataBuf[SPD_SDRAM_NO_OF_BANKS]; //this is Bank number not Bank address bit
if (Banks == 4)
Banks = 2;
else if (Banks == 8)
Banks = 3;
else
Banks = 0;
Size = (u32) (1 << (Rows + Columns + Banks + 3));
RankIndex = 2 * Slot;
DramAttr->RankSize[RankIndex] = Size;
//if this module have two ranks
if ((DramAttr->
DimmInfo[Slot].SPDDataBuf[SPD_SDRAM_DIMM_RANKS] & 0x07) ==
0x01) {
RankIndex++;
DramAttr->RankSize[RankIndex] = Size;
}
PRINT_DEBUG_MEM("rows: ");
PRINT_DEBUG_MEM_HEX8(Rows);
PRINT_DEBUG_MEM(", columns:");
PRINT_DEBUG_MEM_HEX8(Columns);
PRINT_DEBUG_MEM(", banks:");
PRINT_DEBUG_MEM_HEX8(Banks);
PRINT_DEBUG_MEM("\r");
if (Banks == 3)
HasThreeBitBA = TRUE;
}
//must set BA2 enable if any 8-bank device exists
if (HasThreeBitBA) {
Data = pci_read_config8(MEMCTRL, 0x53);
Data |= 0x80;
pci_write_config8(MEMCTRL, 0x53, Data);
}
#if 1
for (RankIndex = 0; DramAttr->RankSize[RankIndex] != 0; RankIndex++) {
PRINT_DEBUG_MEM("Rank:");
PRINT_DEBUG_MEM_HEX8(RankIndex);
PRINT_DEBUG_MEM(", Size:");
PRINT_DEBUG_MEM_HEX32(DramAttr->RankSize[RankIndex] >> 20);
PRINT_DEBUG_MEM("\r");
}
#endif
}
/*===================================================================
Function : DRAMSetRankMAType()
Precondition :
Input :
DramAttr: pointer point to DRAMSYSATTR which consist the DDR and Dimm information in MotherBoard
Output : Void
Purpose : set the matype Reg by MAMapTypeTbl, which the rule can be found in memoryinit
===================================================================*/
void DRAMSetRankMAType(DRAM_SYS_ATTR * DramAttr)
{
u8 SlotNum, Data, j, Reg, or, and;
u8 ShiftBits[] = { 5, 1, 5, 1 }; /* Rank 0/1 MA Map Type is 7:5, Rank 2/3 MA Map Type is 3:1. See Fun3Rx50. */
u8 MAMapTypeTbl[] = { /* Table 12 of P4M800 Pro DataSheet. */
2, 9, 0, /* Bank Address Bits, Column Address Bits, Rank MA Map Type */
2, 10, 1,
2, 11, 2,
2, 12, 3,
3, 10, 5,
3, 11, 6,
3, 12, 7,
0, 0, 0
};
Data = pci_read_config8(MEMCTRL, 0x50);
Data &= 0x1;
pci_write_config8(MEMCTRL, 0x50, Data);
// disable MA32/16 MA33/17 swap in memory init it has this Reg fill
Data = pci_read_config8(MEMCTRL, 0x6b);
Data &= ~0x08;
pci_write_config8(MEMCTRL, 0x6b, Data);
Data = 0x00;
for (SlotNum = 0; SlotNum < MAX_DIMMS; SlotNum++) {
if (DramAttr->DimmInfo[SlotNum].bPresence) {
for (j = 0; MAMapTypeTbl[j] != 0; j += 3) {
if ((1 << MAMapTypeTbl[j]) ==
DramAttr->
DimmInfo[SlotNum].SPDDataBuf
[SPD_SDRAM_NO_OF_BANKS]
&& MAMapTypeTbl[j + 1] ==
DramAttr->
DimmInfo[SlotNum].SPDDataBuf
[SPD_SDRAM_COL_ADDR]) {
break;
}
}
if (0 == MAMapTypeTbl[j]) {
PRINT_DEBUG_MEM
("UNSUPPORTED Bank, Row and Column Addr Bits!\r");
return;
}
or = MAMapTypeTbl[j + 2] << ShiftBits[SlotNum];
if (DramAttr->CmdRate == 1)
or |= 0x01 << (ShiftBits[SlotNum] - 1);
Reg = SlotNum / 2;
if ((SlotNum & 0x01) == 0x01) {
and = 0xf1; // BUGBUG: it should be 0xf0
} else {
and = 0x1f; // BUGBUG: it should be 0x0f
}
Data = pci_read_config8(MEMCTRL, 0x50 + Reg);
Data &= and;
Data |= or;
pci_write_config8(MEMCTRL, 0x50 + Reg, Data);
}
}
//may have some Reg filling at add 3-52 11 and 3-53 in his function
}
/*===================================================================
Function : DRAMSetEndingAddress()
Precondition :
Input :
DramAttr: pointer point to DRAMSYSATTR which consist the DDR and Dimm information in MotherBoard
Output : Void
Purpose : realize the Vrank 40...Reg (Start and Ending Regs). Vrank have same order with phy Rank, Size is actual Size
===================================================================*/
void DRAMSetEndingAddress(DRAM_SYS_ATTR * DramAttr)
{
u8 Shift = 1, Data, RankNO, Size, Start = 0, End = 0, Vrank;
for (RankNO = 0; RankNO < 4; RankNO++) {
if ((DramAttr->RankPresentMap & Shift) != 0) {
Size = (u8) (DramAttr->RankSize[RankNO] >> 26); // current Size in the unit of 64M
if (Size != 0) {
End = End + Size; // calculate current ending address, add the current Size to ending
Vrank = RankNO; // get virtual Rank
Data = End; // set begin/End address register to correspondig virtual Rank #
pci_write_config8(MEMCTRL, 0x40 + Vrank, Data);
Data = Start;
pci_write_config8(MEMCTRL, 0x48 + Vrank, Data);
PRINT_DEBUG_MEM("Rank: ");
PRINT_DEBUG_MEM_HEX8(Vrank);
PRINT_DEBUG_MEM(", Start:");
PRINT_DEBUG_MEM_HEX8(Start);
PRINT_DEBUG_MEM(", End:");
PRINT_DEBUG_MEM_HEX8(End);
PRINT_DEBUG_MEM("\r");
Start = End;
}
}
Shift <<= 1;
}
if (DramAttr->RankNumChB > 0) {
//this is a bug,fixed is to 2,so the max LL size is 128M
Data = 0x02;
pci_write_config8(MEMCTRL, 0x44, Data);
}
Data = End * 4;
pci_write_config8(PCI_DEV(0, 17, 7), 0x60, Data);
// We should directly write to south Bridge, not in north bridge
// program LOW TOP Address
Data = pci_read_config8(MEMCTRL, 0x88);
pci_write_config8(MEMCTRL, 0x85, Data);
// also program vlink mirror
// We should directly write to south Bridge, not in north bridge
pci_write_config8(PCI_DEV(0, 17, 7), 0xe5, Data);
}
/*===================================================================
Function : DRAMPRToVRMapping()
Precondition :
Input :
DramAttr: pointer point to DRAMSYSATTR which consist the DDR and Dimm information in MotherBoard
Output : Void
Purpose : set the Vrank-prank map with the same order
===================================================================*/
void DRAMPRToVRMapping(DRAM_SYS_ATTR * DramAttr)
{
u8 Shift, Data, and, or, DimmNO = 0, PhyRankNO, Reg;
for (Reg = 0x54; Reg <= 0x57; Reg++) //clear the map-reg
{
Data = 0;
pci_write_config8(MEMCTRL, Reg, Data);
}
Shift = 1;
for (PhyRankNO = 0; PhyRankNO < MAX_RANKS; PhyRankNO++) {
if ((DramAttr->RankPresentMap & Shift) != 0) {
or = PhyRankNO; // get virtual Rank ,same with PhyRank
or |= 0x08;
if ((PhyRankNO & 0x01) == 0x01) // get mask for register
and = 0xf0;
else {
and = 0x0f;
or <<= 4;
}
DimmNO = (PhyRankNO >> 1);
Data = pci_read_config8(MEMCTRL, 0x54 + DimmNO);
Data &= and;
Data |= or;
pci_write_config8(MEMCTRL, 0x54 + DimmNO, Data);
}
Shift <<= 1;
}
}