/* * 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); } }