2 * This file is part of the coreboot project.
4 * Copyright (C) 2009 One Laptop per Child, Association, Inc.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 void CalcCLAndFreq(DRAM_SYS_ATTR * DramAttr);
25 void DRAMFreqSetting(DRAM_SYS_ATTR * DramAttr)
30 PRINT_DEBUG_MEM("Dram Frequency setting \r");
32 //calculate dram frequency using SPD data
33 CalcCLAndFreq(DramAttr);
35 //init some Dramc control by Simon Chu slide
36 //Must use "CPU delay" to make sure VLINK is dis-connect
37 Data = pci_read_config8(PCI_DEV(0, 0, 7), 0x47);
38 Data = (u8) (Data | 0x04);
39 pci_write_config8(PCI_DEV(0, 0, 7), 0x47, Data);
41 //in order to make sure NB command buffer don`t have pending request(C2P cycle)
45 //Before Set Dram Frequency, we must set 111 by Simon Chu slide.
46 Data = pci_read_config8(MEMCTRL, 0x90);
47 Data = (u8) ((Data & 0xf8) | 7);
48 pci_write_config8(MEMCTRL, 0x90, Data);
53 Data = pci_read_config8(MEMCTRL, 0x90);
54 switch (DramAttr->DramFreq) {
56 Data = (u8) ((Data & 0xf8) | 3);
59 Data = (u8) ((Data & 0xf8) | 4);
62 Data = (u8) ((Data & 0xf8) | 5);
65 Data = (u8) ((Data & 0xf8) | 6);
68 Data = (u8) ((Data & 0xf8) | 1);;
70 pci_write_config8(MEMCTRL, 0x90, Data);
75 // Manual reset and adjust DLL when DRAM change frequency
76 Data = pci_read_config8(MEMCTRL, 0x6B);
77 Data = (u8) ((Data & 0x2f) | 0xC0);
78 pci_write_config8(MEMCTRL, 0x6B, Data);
83 Data = pci_read_config8(MEMCTRL, 0x6B);
84 Data = (u8) (Data | 0x10);
85 pci_write_config8(MEMCTRL, 0x6B, Data);
90 Data = pci_read_config8(MEMCTRL, 0x6B);
91 Data = (u8) (Data & 0x3f);
92 pci_write_config8(MEMCTRL, 0x6B, Data);
94 //disable V_LINK Auto-Disconnect, or else program may stopped at some place and
95 //we cannot find the reason
96 Data = pci_read_config8(PCI_DEV(0, 0, 7), 0x47);
97 Data = (u8) (Data & 0xFB);
98 pci_write_config8(PCI_DEV(0, 0, 7), 0x47, Data);
103 calculate CL and dram freq
105 +---+---+---+---+---+---+---+---+
106 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
107 +---+---+---+---+---+---+---+---+
108 |TBD| 4 |3.5| 3 |2.5| 2 |1.5| 1 |
109 +---+---+---+---+---+---+---+---+
111 +---+---+---+---+---+---+---+---+
112 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
113 +---+---+---+---+---+---+---+---+
114 |TBD| 6 | 5 | 4 | 3 | 2 |TBD|TBD|
115 +---+---+---+---+---+---+---+---+
117 static const u8 CL_DDR1[7] = { 10, 15, 20, 25, 30, 35, 40 };
118 static const u8 CL_DDR2[7] = { 0, 0, 20, 30, 40, 50, 60 };
120 void CalcCLAndFreq(DRAM_SYS_ATTR * DramAttr)
122 u8 AllDimmSupportedCL, Tmp;
124 u8 SckId, BitId, TmpId;
125 u16 CycTime, TmpCycTime;
127 /*1.list the CL value that all DIMM supported */
128 AllDimmSupportedCL = 0xFF;
129 if (RAMTYPE_SDRAMDDR2 == DramAttr->DramType)
130 AllDimmSupportedCL &= 0x7C; /*bit2,3,4,5,6 */
132 AllDimmSupportedCL &= 0x7F; /*bit0,1,2,3,4,5,6 */
133 for (SckId = 0; SckId < MAX_SOCKETS; SckId++) {
134 if (DramAttr->DimmInfo[SckId].bPresence) { /*all DIMM supported CL */
135 AllDimmSupportedCL &=
137 DimmInfo[SckId].SPDDataBuf[SPD_SDRAM_CAS_LATENCY]);
140 if (!AllDimmSupportedCL) { /*if equal 0, no supported CL */
141 PRINT_DEBUG_MEM("SPD Data Error, Can not get CL !!!! \r");
146 CLMask = 0x40; /*from Bit6 */
148 for (BitId = 7; BitId > 0; BitId--) {
149 if ((AllDimmSupportedCL & CLMask) == CLMask) { /*find the first bit */
150 if (RAMTYPE_SDRAMDDR2 == DramAttr->DramType)
151 DramAttr->CL = CL_DDR2[BitId - 1];
153 DramAttr->CL = CL_DDR1[BitId - 1];
159 /*according the CL value calculate the cycle time, for X or X-1 or X-2 */
163 for (SckId = 0; SckId < MAX_SOCKETS; SckId++) {
164 if (DramAttr->DimmInfo[SckId].bPresence) {
167 DimmInfo[SckId].SPDDataBuf[SPD_SDRAM_CAS_LATENCY]);
169 for (TmpId = 7; TmpId > 0; TmpId--) {
170 if ((Tmp & tmpMask) == tmpMask)
174 if (TmpId - BitId == 0) { /*get Cycle time for X, SPD BYTE9 */
177 DimmInfo[SckId].SPDDataBuf
179 } else if (TmpId - BitId == 1) { /*get Cycle time for X-1, SPD BYTE23 */
182 DimmInfo[SckId].SPDDataBuf
183 [SPD_SDRAM_TCLK_X_1];
184 } else if (TmpId - BitId == 2) { /*get cycle time for X-2, SPD BYTE25 */
187 DimmInfo[SckId].SPDDataBuf
188 [SPD_SDRAM_TCLK_X_2];
192 if (TmpCycTime > CycTime) /*get the most cycle time,there is some problem! */
193 CycTime = TmpCycTime;
203 0x25-->2.5ns Freq=400 DDR800
204 0x30-->3.0ns Freq=333 DDR667
205 0x3D-->3.75ns Freq=266 DDR533
206 0x50-->5.0ns Freq=200 DDR400
207 0x60-->6.0ns Freq=166 DDR333
208 0x75-->7.5ns Freq=133 DDR266
209 0xA0-->10.0ns Freq=100 DDR200
211 if (CycTime <= 0x25) {
212 DramAttr->DramFreq = DIMMFREQ_800;
213 DramAttr->DramCyc = 250;
214 } else if (CycTime <= 0x30) {
215 DramAttr->DramFreq = DIMMFREQ_667;
216 DramAttr->DramCyc = 300;
217 } else if (CycTime <= 0x3d) {
218 DramAttr->DramFreq = DIMMFREQ_533;
219 DramAttr->DramCyc = 375;
220 } else if (CycTime <= 0x50) {
221 DramAttr->DramFreq = DIMMFREQ_400;
222 DramAttr->DramCyc = 500;
223 } else if (CycTime <= 0x60) {
224 DramAttr->DramFreq = DIMMFREQ_333;
225 DramAttr->DramCyc = 600;
226 } else if (CycTime <= 0x75) {
227 DramAttr->DramFreq = DIMMFREQ_266;
228 DramAttr->DramCyc = 750;
229 } else if (CycTime <= 0xA0) {
230 DramAttr->DramFreq = DIMMFREQ_200;
231 DramAttr->DramCyc = 1000;
233 //if set the frequence mannul
234 PRINT_DEBUG_MEM("Dram Frequency:");
235 PRINT_DEBUG_MEM_HEX16(DramAttr->DramFreq);
236 PRINT_DEBUG_MEM(" \r");