blob: eb1ddcc2e615f018fd9bbb79ea60026782a76843 [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
*/
/* FIXME this should go away */
static const struct mem_controller ctrl = {
.channel0 = {DIMM0, DIMM1},
};
/* read data */
CB_STATUS GetSPDData(u8 Slot, u8 Length, u8 *Buf);
void DRAMCmdRate(DRAM_SYS_ATTR *DramAttr);
CB_STATUS GetInfoFromSPD(DRAM_SYS_ATTR *DramAttr);
CB_STATUS GetSPDData(u8 Slot, u8 Length, u8 *Buf)
{
// CB_STATUS Status = CB_NOT_READY;
u8 Val, i;
if (1 > Length || NULL == Buf)
return CB_INVALID_PARAMETER;
for (i = 0; i < Length; i++) {
Val = get_spd_data(ctrl.channel0[Slot], i);
*(Buf + i) = Val;
}
return CB_SUCCESS;
}
CB_STATUS DRAMDetect(DRAM_SYS_ATTR *DramAttr)
{
CB_STATUS Status = CB_SUCCESS;
PRINT_DEBUG_MEM("DRAM detection \r");
/* Read D0F3Rx6C, detect memory type DDR1 or DDR2. */
/* 353 supports DDR2 only */
DramAttr->DramType = RAMTYPE_SDRAMDDR2;
/* Get information for SPD. */
Status = GetInfoFromSPD(DramAttr);
if (CB_SUCCESS == Status) {
/* 64bit or 128Bit */
// if (RAMTYPE_SDRAMDDR == DramAttr->DramType)
/* Select command rate. */
DRAMCmdRate(DramAttr);
}
return Status;
}
/*
* Determine 1T or 2T command rate.
*
* To enable 1T command rate, the system will satisfy the following
* three conditions:
*
* 1. Each DRAM channel may have 1 or 2 ranks of DIMM. 3/4 ranks can not
* support 1T command rate. It's for loading issue. 1T can supports
* (a) only one socket with two ranks, OR
* (b) two sockets each with 1 rank.
* 2. User wishes to enable 1T command rate mode and turn on by setup menu.
* 3. If 1T command rate can be enabled, just set EBP bit here.
*/
void DRAMCmdRate(DRAM_SYS_ATTR *DramAttr)
{
u8 Data;
// 5.1t/2t command rate, use the stable set
//offset50
DramAttr->CmdRate = 2;
Data = pci_read_config8(MEMCTRL, 0x50);
Data = (u8) (Data & 0xEE);
pci_write_config8(MEMCTRL, 0x50, Data);
}
/*
* Get SPD data and set RANK presence map.
*
* Sockets0,1 is Channel A / Sockets2,3 is Channel B.
*
* Socket0 SPD device address 0x50 / socket1 SPD device address 0x51
* Socket2 SPD device address 0x52 / socket3 SPD device address 0x53
*/
CB_STATUS GetInfoFromSPD(DRAM_SYS_ATTR *DramAttr)
{
CB_STATUS Status;
u8 *pSPDDataBuf;
u8 ModuleDataWidth, ChipWidth, RankNum, LoadNum, Sockets, i;
BOOLEAN bFind; /* FIXME: We don't have/want BOOLEAN. */
bFind = FALSE; /* FIXME: We don't have/want FALSE. */
Status = CB_DEVICE_ERROR;
for (Sockets = 0; Sockets < MAX_SOCKETS; Sockets++) {
pSPDDataBuf = DramAttr->DimmInfo[Sockets].SPDDataBuf;
pSPDDataBuf[SPD_MEMORY_TYPE] =
get_spd_data(ctrl.channel0[Sockets], SPD_MEMORY_TYPE);
if (pSPDDataBuf[SPD_MEMORY_TYPE] == 0) {
Status = CB_NOT_READY;
} else {
Status =
GetSPDData(Sockets, SPD_DATA_SIZE, pSPDDataBuf);
PRINT_DEBUG_MEM("SPD : \r");
for (i = 0; i < SPD_DATA_SIZE; i++) {
PRINT_DEBUG_MEM(" ");
PRINT_DEBUG_MEM_HEX8(pSPDDataBuf[i]);
}
}
if (CB_SUCCESS == Status) {
/*
* If DRAM controller detected type not same as the
* type got from SPD, there are ERROR.
*/
if (pSPDDataBuf[SPD_MEMORY_TYPE] != DramAttr->DramType) {
Status = CB_DEVICE_ERROR; /* memory int error */
PRINT_DEBUG_MEM("Memory Device ERROR: DRAM "
"controller detected type != "
"type got from SPD\r");
break;
}
DramAttr->DimmInfo[Sockets].bPresence = TRUE;
/* Calculate load number (chips number). */
ModuleDataWidth = (u8) (DramAttr->
DimmInfo[Sockets].SPDDataBuf
[SPD_SDRAM_MOD_DATA_WIDTH + 1]);
ModuleDataWidth = (u8) (ModuleDataWidth << 8);
ModuleDataWidth |= (u8) (DramAttr->
DimmInfo[Sockets].SPDDataBuf
[SPD_SDRAM_MOD_DATA_WIDTH]);
ChipWidth = (u8) ((DramAttr->
DimmInfo[Sockets].SPDDataBuf
[SPD_SDRAM_WIDTH]) & 0x7F);
LoadNum = (u8) (ModuleDataWidth / ChipWidth);
/* Set the RANK map. */
/* Get bit0,1, the most number of supported RANK is 2. */
RankNum = (u8) (pSPDDataBuf[SPD_SDRAM_DIMM_RANKS] & 0x3);
if (RAMTYPE_SDRAMDDR2 == DramAttr->DramType)
/*
* For DDR bit[0,1]: 01->1 RANK, 10->2 RANK
* For DDR2 bit[0,1]: 00->1 RANK, 01->2 RANK
*/
RankNum++;
/* Every DIMM have 1 or 2 ranks. */
if (RankNum != 2 && RankNum != 1) {
Status = CB_DEVICE_ERROR;
PRINT_DEBUG_MEM("Memory Device ERROR: Number "
"of RANK not supported!\r");
break;
}
if (Sockets < 2) { /* Sockets0,1 is channel A */
DramAttr->RankNumChA =
(u8) (DramAttr->RankNumChA + RankNum);
DramAttr->DimmNumChA++;
DramAttr->LoadNumChA =
(u8) (DramAttr->LoadNumChA * LoadNum *
RankNum);
} else { /* Sockets2,3 is channel B */
DramAttr->RankNumChB =
(u8) (DramAttr->RankNumChB + RankNum);
DramAttr->DimmNumChB++;
DramAttr->LoadNumChB =
(u8) (DramAttr->LoadNumChB * LoadNum *
RankNum);;
}
RankNum |= 1; /* Set rank map. */
DramAttr->RankPresentMap |= (RankNum << (Sockets * 2));
bFind = TRUE;
}
}
PRINT_DEBUG_MEM("Rank Present Map:");
PRINT_DEBUG_MEM_HEX8(DramAttr->RankPresentMap);
PRINT_DEBUG_MEM("\r");
if (bFind)
Status = CB_SUCCESS;
return Status;
}