/* * 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 DutyCycleCtrl(DRAM_SYS_ATTR *DramAttr) { u8 Data, FreqId, i; if (DIMMFREQ_800 == DramAttr->DramFreq) FreqId = 2; else if (DIMMFREQ_667 == DramAttr->DramFreq) FreqId = 3; else if (DIMMFREQ_533 == DramAttr->DramFreq) FreqId = 4; else if (DIMMFREQ_400 == DramAttr->DramFreq) FreqId = 5; else FreqId = 5; if (DramAttr->RankNumChA > 0) { /* 1 rank */ for (i = 0; i < DUTY_CYCLE_REG_NUM; i++) { Data = pci_read_config8(MEMCTRL, ChA_Duty_Control_DDR2[i][0]); Data &= ChA_Duty_Control_DDR2[i][1]; /* mask */ Data |= ChA_Duty_Control_DDR2[i][FreqId]; /* set val */ pci_write_config8(MEMCTRL, ChA_Duty_Control_DDR2[i][0], Data); } } if (1 == ENABLE_CHC) { /* 1 rank */ for (i = 0; i < DUTY_CYCLE_REG_NUM; i++) { Data = pci_read_config8(MEMCTRL, ChB_Duty_Control_DDR2[i][0]); Data &= ChB_Duty_Control_DDR2[i][1]; /* mask */ Data |= ChB_Duty_Control_DDR2[i][FreqId]; /* set val */ pci_write_config8(MEMCTRL, ChB_Duty_Control_DDR2[i][0], Data); } } } /* * DRAM clock phase and delay control */ /* Subroutine list */ void ClkPhsCtrlFBMDDR2(DRAM_SYS_ATTR *DramAttr); void WrtDataPhsCtrl(DRAM_SYS_ATTR *DramAttr); void DQDQSOutputDlyCtrl(DRAM_SYS_ATTR *DramAttr); void DQSInputCaptureCtrl(DRAM_SYS_ATTR *DramAttr); void DCLKPhsCtrl(DRAM_SYS_ATTR *DramAttr); void DRAMClkCtrl(DRAM_SYS_ATTR *DramAttr) { /* Write data clock phase control. */ WrtDataPhsCtrl(DramAttr); /* Clock phase control */ ClkPhsCtrlFBMDDR2(DramAttr); /**/ DQDQSOutputDlyCtrl(DramAttr); /**/ DQSInputCaptureCtrl(DramAttr); DCLKPhsCtrl(DramAttr); } void ClkPhsCtrlFBMDDR2(DRAM_SYS_ATTR *DramAttr) { u8 Data, FreqId, i; if (DramAttr->DramFreq == DIMMFREQ_800) FreqId = 2; else if (DramAttr->DramFreq == DIMMFREQ_667) FreqId = 3; else if (DramAttr->DramFreq == DIMMFREQ_533) FreqId = 4; else if (DramAttr->DramFreq == DIMMFREQ_400) FreqId = 5; else FreqId = 5; /* Channel A */ // 2~4 Rank if (DramAttr->RankNumChA == 1) { /* 1 rank */ for (i = 0; i < 3; i++) { Data = pci_read_config8(MEMCTRL, DDR2_ChA_Clk_Phase_Table_1R[i][0]); Data &= DDR2_ChA_Clk_Phase_Table_1R[i][1]; /* mask */ Data |= DDR2_ChA_Clk_Phase_Table_1R[i][FreqId]; /* set val */ pci_write_config8(MEMCTRL, DDR2_ChA_Clk_Phase_Table_1R[i][0], Data); } } else if (DramAttr->RankNumChA > 1) { /* 2~4 Rank */ for (i = 0; i < 3; i++) { Data = pci_read_config8(MEMCTRL, DDR2_ChA_Clk_Phase_Table_2R[i][0]); Data &= DDR2_ChA_Clk_Phase_Table_2R[i][1]; /* mask */ Data |= DDR2_ChA_Clk_Phase_Table_2R[i][FreqId]; /* set val */ pci_write_config8(MEMCTRL, DDR2_ChA_Clk_Phase_Table_2R[i][0], Data); } } #if ENABLE_CHB if (DramAttr->RankNumChB > 0) { /* 1 rank */ for (i = 0; i < 3; i++) { Data = pci_read_config8(MEMCTRL, DDR2_ChB_Clk_Phase_Table_1R[i][0]); Data &= DDR2_ChB_Clk_Phase_Table_1R[i][1]; /* mask */ Data |= DDR2_ChB_Clk_Phase_Table_1R[i][FreqId]; /* set val */ pci_write_config8(MEMCTRL, DDR2_ChB_Clk_Phase_Table_1R[i][0], Data); } } #endif } void WrtDataPhsCtrl(DRAM_SYS_ATTR *DramAttr) { u8 Data, FreqId, i; if (DIMMFREQ_800 == DramAttr->DramFreq) FreqId = 2; else if (DIMMFREQ_667 == DramAttr->DramFreq) FreqId = 3; else if (DIMMFREQ_533 == DramAttr->DramFreq) FreqId = 4; else if (DIMMFREQ_400 == DramAttr->DramFreq) FreqId = 5; else FreqId = 5; if (DramAttr->RankNumChA > 0) { /* 1 rank */ for (i = 0; i < WrtData_REG_NUM; i++) { Data = pci_read_config8(MEMCTRL, DDR2_ChA_WrtData_Phase_Table[i][0]); Data &= DDR2_ChA_WrtData_Phase_Table[i][1]; /* mask */ Data |= DDR2_ChA_WrtData_Phase_Table[i][FreqId]; /* set val */ pci_write_config8(MEMCTRL, DDR2_ChA_WrtData_Phase_Table[i][0], Data); } } #if ENABLE_CHB if (DramAttr->RankNumChB > 0) { /* 1 rank */ for (i = 0; i < WrtData_REG_NUM; i++) { Data = pci_read_config8(MEMCTRL, DDR2_ChB_WrtData_Phase_Table[i][0]); Data &= DDR2_ChB_WrtData_Phase_Table[i][1]; /* mask */ Data |= DDR2_ChB_WrtData_Phase_Table[i][FreqId]; /* set val */ pci_write_config8(MEMCTRL, DDR2_ChB_WrtData_Phase_Table[i][0], Data); } } #endif Data = pci_read_config8(MEMCTRL, 0x8C); Data &= 0xFC; Data |= 0x03; pci_write_config8(MEMCTRL, 0x8C, Data); } void DQDQSOutputDlyCtrl(DRAM_SYS_ATTR *DramAttr) { u8 Data, 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 = 2; else FreqId = 0; if (DramAttr->RankNumChA > 0) { Data = DDR2_CHA_DQ_DQS_Delay_Table[FreqId][0]; pci_write_config8(MEMCTRL, 0xf0, Data); Data = DDR2_CHA_DQ_DQS_Delay_Table[FreqId][1]; pci_write_config8(MEMCTRL, 0xf1, Data); Data = DDR2_CHA_DQ_DQS_Delay_Table[FreqId][2]; pci_write_config8(MEMCTRL, 0xf2, Data); Data = DDR2_CHA_DQ_DQS_Delay_Table[FreqId][3]; pci_write_config8(MEMCTRL, 0xf3, Data); } #if ENABLE_CHB if (DramAttr->RankNumChB > 0) { Data = DDR2_CHB_DQ_DQS_Delay_Table[FreqId][0]; pci_write_config8(MEMCTRL, 0xf4, Data); Data = DDR2_CHB_DQ_DQS_Delay_Table[FreqId][1]; pci_write_config8(MEMCTRL, 0xf5, Data); Data = DDR2_CHB_DQ_DQS_Delay_Table[FreqId][2]; pci_write_config8(MEMCTRL, 0xf6, Data); Data = DDR2_CHB_DQ_DQS_Delay_Table[FreqId][3]; pci_write_config8(MEMCTRL, 0xf7, Data); } #endif } void DQSInputCaptureCtrl(DRAM_SYS_ATTR *DramAttr) { u8 Data, FreqId, i; if (DIMMFREQ_800 == DramAttr->DramFreq) FreqId = 2; else if (DIMMFREQ_667 == DramAttr->DramFreq) FreqId = 3; else if (DIMMFREQ_533 == DramAttr->DramFreq) FreqId = 4; else if (DIMMFREQ_400 == DramAttr->DramFreq) FreqId = 5; else FreqId = 2; Data = 0x8A; pci_write_config8(MEMCTRL, 0x77, Data); if (DramAttr->RankNumChA > 0) { /* 1 rank */ for (i = 0; i < DQS_INPUT_CAPTURE_REG_NUM; i++) { Data = pci_read_config8(MEMCTRL, DDR2_ChA_DQS_Input_Capture_Tbl[i][0]); Data &= DDR2_ChA_DQS_Input_Capture_Tbl[i][1]; /* mask */ Data |= DDR2_ChA_DQS_Input_Capture_Tbl[i][FreqId]; /* set val */ pci_write_config8(MEMCTRL, DDR2_ChA_DQS_Input_Capture_Tbl[i][0], Data); } } #if ENABLE_CHB if (DramAttr->RankNumChB > 0) { /* 1 rank */ for (i = 0; i < DQS_INPUT_CAPTURE_REG_NUM; i++) { Data = pci_read_config8(MEMCTRL, DDR2_ChB_DQS_Input_Capture_Tbl[i][0]); Data &= DDR2_ChB_DQS_Input_Capture_Tbl[i][1]; /* mask */ Data |= DDR2_ChB_DQS_Input_Capture_Tbl[i][FreqId]; /* set val */ pci_write_config8(MEMCTRL, DDR2_ChB_DQS_Input_Capture_Tbl[i][0], Data); } } #endif } /* * This is very important, if you don't set it correctly, DRAM will be * unreliable, * * Set DCLK Phase control(Reg99H[6:1]) according the DDRII in the DIMM. */ void DCLKPhsCtrl(DRAM_SYS_ATTR *DramAttr) { u8 Data; Data = 0; /* TODO: Can be dropped? */ Data = pci_read_config8(MEMCTRL, 0x99); Data &= 0xE1; /* DDR in Dimm1, MCLKOA[4,3,0] will output MCLK */ if (DramAttr->RankPresentMap & 0x03) Data |= 0x09 << 1; /* DDR in Dimm2, MCLKOA[5,2,1] will output MCLK */ if (DramAttr->RankPresentMap & 0x0C) Data |= 0x06 << 1; pci_write_config8(MEMCTRL, 0x99, Data); }