blob: 695fcabbf4963f271e8e21d58ff4de1db074cabf [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
*/
/*
Driving setting: ODT/DQS/DQ/CS/MAA/MAB/DCLK
*/
void DrivingODT(DRAM_SYS_ATTR * DramAttr);
void DrivingDQS(DRAM_SYS_ATTR * DramAttr);
void DrivingDQ(DRAM_SYS_ATTR * DramAttr);
void DrivingCS(DRAM_SYS_ATTR * DramAttr);
void DrivingMA(DRAM_SYS_ATTR * DramAttr);
void DrivingDCLK(DRAM_SYS_ATTR * DramAttr);
/* DRAM Driving Adjustment*/
void DRAMDriving(DRAM_SYS_ATTR * DramAttr)
{
PRINT_DEBUG_MEM("set ODT!\r");
DrivingODT(DramAttr);
PRINT_DEBUG_MEM("set DQS!\r");
DrivingDQS(DramAttr);
PRINT_DEBUG_MEM(("set DQ!\r"));
DrivingDQ(DramAttr);
PRINT_DEBUG_MEM("set CS!\r");
DrivingCS(DramAttr);
PRINT_DEBUG_MEM("set MAA!\r");
DrivingMA(DramAttr);
PRINT_DEBUG_MEM("set DCLK!\r");
DrivingDCLK(DramAttr);
}
/*
ODT Control for DQ/DQS/CKE/SCMD/DCLKO in ChA & ChB
which include driving enable/range and strong/weak selection
Processing: According to DRAM frequency to ODT control bits.
Because function enable bit must be the last one to be set.
So the register VIA_NB3DRAM_REGD4 and VIA_NB3DRAM_REGD3 should be
the last register to be programmed.
*/
//-------------------------------------------------------------------------------
// ODT Lookup Table
//-------------------------------------------------------------------------------
#define Rank0_ODT 0
#define Rank1_ODT 1
#define Rank2_ODT 2
#define Rank3_ODT 3
#define NA_ODT 0
#define NB_ODT_75ohm 0
#define NB_ODT_150ohm 1
#define DDR2_ODT_75ohm 0x20
#define DDR2_ODT_150ohm 0x40
// Setting of ODT Lookup TBL
// RankMAP , Rank 3 Rank 2 Rank 1 Rank 0 , DRAM & NB ODT setting
// db 0000b , Reserved
#define ODTLookup_Tbl_count 8
static const u8 ODTLookup_TBL[ODTLookup_Tbl_count][3] = {
// 0001b
{0x01,
(Rank3_ODT << 6) + (Rank2_ODT << 4) + (Rank1_ODT << 2) +
Rank0_ODT, DDR2_ODT_150ohm + NB_ODT_75ohm},
// 0010b , Reserved
// 0011b
{0x03,
(Rank3_ODT << 6) + (Rank2_ODT << 4) + (Rank0_ODT << 2) +
Rank1_ODT, DDR2_ODT_150ohm + NB_ODT_75ohm},
// 0100b
{0x04,
(Rank3_ODT << 6) + (Rank2_ODT << 4) + (Rank1_ODT << 2) +
Rank0_ODT, DDR2_ODT_150ohm + NB_ODT_75ohm},
// 0101b
{0x05,
(Rank3_ODT << 6) + (Rank0_ODT << 4) + (Rank1_ODT << 2) +
Rank2_ODT, DDR2_ODT_75ohm + NB_ODT_150ohm},
// 0110b , Reserved
// 0111b
{0x07,
(Rank3_ODT << 6) + (Rank0_ODT << 4) + (Rank2_ODT << 2) +
Rank2_ODT, DDR2_ODT_75ohm + NB_ODT_150ohm},
// 1000b , Reserved
// 1001b , Reserved
// 1010b , Reserved
// 1011b , Reserved
// 1100b
{0x0c,
(Rank2_ODT << 6) + (Rank3_ODT << 4) + (Rank1_ODT << 2) +
Rank0_ODT, DDR2_ODT_150ohm + NB_ODT_75ohm},
// 1101b
{0x0d,
(Rank0_ODT << 6) + (Rank0_ODT << 4) + (Rank1_ODT << 2) +
Rank2_ODT, DDR2_ODT_75ohm + NB_ODT_150ohm},
// 1110b , Reserved
// 1111b
{0x0f,
(Rank0_ODT << 6) + (Rank0_ODT << 4) + (Rank2_ODT << 2) +
Rank2_ODT, DDR2_ODT_75ohm + NB_ODT_150ohm}
};
#define ODT_Table_Width_DDR2 4
// RxD6 RxD3
static const u8 ODT_Control_DDR2[ODT_Table_Width_DDR2] = { 0xFC, 0x01 };
void DrivingODT(DRAM_SYS_ATTR * DramAttr)
{
u8 Data;
u8 i;
BOOLEAN bFound;
pci_write_config8(MEMCTRL, 0xD0, 0x88);
Data = ODT_Control_DDR2[0];
pci_write_config8(MEMCTRL, 0xd6, Data);
Data = ODT_Control_DDR2[1];
pci_write_config8(MEMCTRL, 0xd3, Data);
Data = pci_read_config8(MEMCTRL, 0x9e);
//set MD turn_around wait state
Data &= 0xCF; /*clear bit4,5 */
if (DIMMFREQ_400 == DramAttr->DramFreq)
Data |= 0x0;
else if (DIMMFREQ_533 == DramAttr->DramFreq)
Data |= 0x10;
else if (DIMMFREQ_667 == DramAttr->DramFreq)
Data |= 0x20;
else if (DIMMFREQ_800 == DramAttr->DramFreq)
Data |= 0x20;
else
Data |= 0;
pci_write_config8(MEMCTRL, 0x9e, Data);
if (DIMMFREQ_400 == DramAttr->DramFreq)
Data = 0x0;
else if (DIMMFREQ_533 == DramAttr->DramFreq)
Data = 0x11;
else if (DIMMFREQ_667 == DramAttr->DramFreq)
Data = 0x11;
else if (DIMMFREQ_800 == DramAttr->DramFreq)
Data = 0x11;
else
Data = 0;
pci_write_config8(MEMCTRL, 0x9f, Data);
/*channel A ODT select */
if (DramAttr->DimmNumChA > 0) {
Data = pci_read_config8(MEMCTRL, 0xd5);
Data &= 0x5F; /*clear bit7,5 */
if (DramAttr->RankNumChA > 2)
Data |= 0xA0; /*if rank number > 2 (3or4), set bit7,5 */
else
Data |= 0x00; /*if rank number is 1or2, clear bit5 */
pci_write_config8(MEMCTRL, 0xd5, Data);
Data = pci_read_config8(MEMCTRL, 0xd7);
Data &= 0xEF; /*clear bit7 */
if (DramAttr->RankNumChA > 2)
Data |= 0x80; /*if rank number > 2 (3or4), set bit7 */
else
Data |= 0x00; /*if rank number is 1or2, clear bit7 */
pci_write_config8(MEMCTRL, 0xd7, Data);
/*channel A */
Data = pci_read_config8(MEMCTRL, 0xd5);
Data &= 0xF3; //bit2,3
if (DramAttr->DimmNumChA == 2) /*2 Dimm, 3or4 Ranks */
Data |= 0x00;
else if (DramAttr->DimmNumChA == 1)
Data |= 0x04;
pci_write_config8(MEMCTRL, 0xd5, Data);
if ((DramAttr->RankPresentMap & 0x0F) != 0) { /*channel A */
// MAA ODT Lookup Table
bFound = FALSE;
for (i = 0; i < ODTLookup_Tbl_count; i++) {
if ((DramAttr->RankPresentMap & 0x0F) ==
ODTLookup_TBL[i][0]) {
Data = ODTLookup_TBL[i][1];
bFound = TRUE;
}
}
if (!bFound) { /*set default value */
Data =
ODTLookup_TBL[ODTLookup_Tbl_count - 1][1];
}
pci_write_config8(MEMCTRL, 0x9c, Data);
//set CHA MD ODT control State Dynamic-on
Data = pci_read_config8(MEMCTRL, 0xD4);
Data &= 0xC9;
Data |= 0x30;
pci_write_config8(MEMCTRL, 0xD4, Data);
Data = pci_read_config8(MEMCTRL, 0x9e);
Data |= 0x01;
pci_write_config8(MEMCTRL, 0x9e, Data);
}
}
/*channel B */
if (1 == ENABLE_CHC) {
//CHB has not auto compensation mode ,so must set it manual,or else CHB initialization will not successful
// Data =0x88;
//pci_write_config8(MEMCTRL, 0xd0, Data);
Data = pci_read_config8(MEMCTRL, 0xd5);
Data &= 0xAF;
if (DramAttr->RankNumChB > 2) /*rank number 3 or 4 */
Data |= 0x50;
else
Data |= 0x00;
pci_write_config8(MEMCTRL, 0xd5, Data);
Data = pci_read_config8(MEMCTRL, 0xd7);
Data &= 0xBF; /*clear bit6 */
if (DramAttr->RankNumChB > 2)
Data |= 0x40; /*if rank number > 2 (3or4), set bit7 */
else
Data |= 0x00; /*if rank number is 1or2, clear bit7 */
pci_write_config8(MEMCTRL, 0xd7, Data);
Data = pci_read_config8(MEMCTRL, 0xd5);
Data &= 0xFC;
if (DramAttr->DimmNumChB == 2) /*2 Dimm, 3or4 Ranks */
Data |= 0x00; // 2 dimm RxD5[2,0]=0,0b
else if (DramAttr->DimmNumChB == 1)
Data |= 0x01; // 1 dimm RxD5[2,0]=1,1b
pci_write_config8(MEMCTRL, 0xd5, Data);
//set CHB MD ODT control State Dynamic-on
Data = pci_read_config8(MEMCTRL, 0xD4);
Data &= 0xF6;
Data |= 0x08;
pci_write_config8(MEMCTRL, 0xD4, Data);
//enable CHB differential DQS input
Data = pci_read_config8(MEMCTRL, 0x9E);
Data |= 0x02;
pci_write_config8(MEMCTRL, 0x9E, Data);
}
//enable ODT Control
Data = pci_read_config8(MEMCTRL, 0x9e);
Data |= 0x80;
pci_write_config8(MEMCTRL, 0x9e, Data);
}
void DrivingDQS(DRAM_SYS_ATTR * DramAttr)
{
u8 Data;
/*channel A */
if (DramAttr->RankNumChA > 0) {
Data = DDR2_DQSA_Driving_Table[DramAttr->RankNumChA - 1];
pci_write_config8(MEMCTRL, 0xe0, Data);
}
/*channel B */
if (1 == ENABLE_CHC) {
Data = DDR2_DQSB_Driving_Table[DramAttr->RankNumChB - 1];
pci_write_config8(MEMCTRL, 0xe1, Data);
}
}
void DrivingDQ(DRAM_SYS_ATTR * DramAttr)
{
u8 Data;
/*channel A */
if (DramAttr->RankNumChA > 0) {
Data = DDR2_DQA_Driving_Table[DramAttr->RankNumChA - 1];
pci_write_config8(MEMCTRL, 0xe2, Data);
}
/*channel B */
if (1 == ENABLE_CHC) {
Data = DDR2_DQB_Driving_Table[DramAttr->RankNumChB - 1];
pci_write_config8(MEMCTRL, 0xe3, Data);
}
}
void DrivingCS(DRAM_SYS_ATTR * DramAttr)
{
u8 Data;
/*Channel A */
if (DramAttr->RankNumChA > 0) {
Data = DDR2_CSA_Driving_Table_x8[DramAttr->RankNumChA - 1];
pci_write_config8(MEMCTRL, 0xe4, Data);
}
/*channel B */
if (1 == ENABLE_CHC) {
Data = DDR2_CSB_Driving_Table_x8[DramAttr->RankNumChB - 1];
pci_write_config8(MEMCTRL, 0xe5, Data);
}
}
void DrivingMA(DRAM_SYS_ATTR * DramAttr)
{
u8 Data;
u8 i, FreqId;
if (DramAttr->RankNumChA > 0) {
if (DIMMFREQ_400 == DramAttr->DramFreq)
FreqId = 1;
else if (DIMMFREQ_533 == DramAttr->DramFreq)
FreqId = 2;
else if (DIMMFREQ_667 == DramAttr->DramFreq)
FreqId = 3;
else if (DIMMFREQ_800 == DramAttr->DramFreq)
FreqId = 4;
else
FreqId = 1;
for (i = 0; i < MA_Table; i++) {
if (DramAttr->LoadNumChA <=
DDR2_MAA_Driving_Table[i][0]) {
Data = DDR2_MAA_Driving_Table[i][FreqId];
break;
}
}
pci_write_config8(MEMCTRL, 0xe8, Data);
}
if (1 == ENABLE_CHC) {
for (i = 0; i < MA_Table; i++) {
if (DramAttr->LoadNumChA <=
DDR2_MAB_Driving_Table[i][0]) {
Data = DDR2_MAB_Driving_Table[i][1];
break;
}
}
pci_write_config8(MEMCTRL, 0xe9, Data);
}
}
void DrivingDCLK(DRAM_SYS_ATTR * DramAttr)
{
u8 Data;
u8 FreqId;
if (DIMMFREQ_400 == DramAttr->DramFreq)
FreqId = 0;
else if (DIMMFREQ_533 == DramAttr->DramFreq)
FreqId = 1;
else if (DIMMFREQ_667 == DramAttr->DramFreq)
FreqId = 2;
else if (DIMMFREQ_800 == DramAttr->DramFreq)
FreqId = 4;
else
FreqId = 0;
/*channel A */
if (DramAttr->RankNumChA > 0) {
Data = DDR2_DCLKA_Driving_Table[FreqId];
pci_write_config8(MEMCTRL, 0xe6, Data);
}
/*channel B */
if (1 == ENABLE_CHC) {
Data = DDR2_DCLKB_Driving_Table[FreqId];
pci_write_config8(MEMCTRL, 0xe7, Data);
}
}