Since some people disapprove of white space cleanups mixed in regular commits
[coreboot.git] / src / northbridge / via / vx800 / freq_setting.c
1 /*
2  * This file is part of the coreboot project.
3  *
4  * Copyright (C) 2009 One Laptop per Child, Association, Inc.
5  *
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.
9  *
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.
14  *
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
18  */
19
20 void CalcCLAndFreq(DRAM_SYS_ATTR * DramAttr);
21
22 /*
23  Set DRAM Frequency
24 */
25 void DRAMFreqSetting(DRAM_SYS_ATTR * DramAttr)
26 {
27
28         u8 Data = 0;
29
30         PRINT_DEBUG_MEM("Dram Frequency setting \r");
31
32         //calculate dram frequency using SPD data
33         CalcCLAndFreq(DramAttr);
34
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);
40
41         //in order to make sure NB command buffer don`t have pending request(C2P cycle)
42         //CPU DELAY
43         WaitMicroSec(20);
44
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);
49
50         WaitMicroSec(20);
51
52         //Set Dram Frequency.
53         Data = pci_read_config8(MEMCTRL, 0x90);
54         switch (DramAttr->DramFreq) {
55         case DIMMFREQ_400:
56                 Data = (u8) ((Data & 0xf8) | 3);
57                 break;
58         case DIMMFREQ_533:
59                 Data = (u8) ((Data & 0xf8) | 4);
60                 break;
61         case DIMMFREQ_667:
62                 Data = (u8) ((Data & 0xf8) | 5);
63                 break;
64         case DIMMFREQ_800:
65                 Data = (u8) ((Data & 0xf8) | 6);
66                 break;
67         default:
68                 Data = (u8) ((Data & 0xf8) | 1);;
69         }
70         pci_write_config8(MEMCTRL, 0x90, Data);
71
72         //CPU Delay
73         WaitMicroSec(20);
74
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);
79
80         //CPU Delay
81         WaitMicroSec(20);
82
83         Data = pci_read_config8(MEMCTRL, 0x6B);
84         Data = (u8) (Data | 0x10);
85         pci_write_config8(MEMCTRL, 0x6B, Data);
86
87         //CPU Delay
88         WaitMicroSec(20);
89
90         Data = pci_read_config8(MEMCTRL, 0x6B);
91         Data = (u8) (Data & 0x3f);
92         pci_write_config8(MEMCTRL, 0x6B, Data);
93
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);
99
100 }
101
102 /*
103  calculate CL and dram freq
104  DDR1
105  +---+---+---+---+---+---+---+---+
106  | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
107  +---+---+---+---+---+---+---+---+
108  |TBD| 4 |3.5| 3 |2.5| 2 |1.5| 1 |
109  +---+---+---+---+---+---+---+---+
110  DDR2
111  +---+---+---+---+---+---+---+---+
112  | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
113  +---+---+---+---+---+---+---+---+
114  |TBD| 6 | 5 | 4 | 3 | 2 |TBD|TBD|
115  +---+---+---+---+---+---+---+---+
116 */
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 };
119
120 void CalcCLAndFreq(DRAM_SYS_ATTR * DramAttr)
121 {
122         u8 AllDimmSupportedCL, Tmp;
123         u8 CLMask, tmpMask;
124         u8 SckId, BitId, TmpId;
125         u16 CycTime, TmpCycTime;
126
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 */
131         else                    /*DDR1 */
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 &=
136                             (DramAttr->
137                              DimmInfo[SckId].SPDDataBuf[SPD_SDRAM_CAS_LATENCY]);
138                 }
139         }
140         if (!AllDimmSupportedCL) {      /*if equal 0, no supported CL */
141                 PRINT_DEBUG_MEM("SPD Data Error, Can not get CL !!!! \r");
142                 for (;;) ;
143         }
144
145         /*Get CL Value */
146         CLMask = 0x40;          /*from Bit6 */
147
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];
152                         else    /*DDR1 */
153                                 DramAttr->CL = CL_DDR1[BitId - 1];
154                         break;
155                 }
156                 CLMask >>= 1;
157         }
158
159         /*according the CL value calculate the cycle time, for X or X-1 or X-2 */
160         CycTime = 0;
161         TmpCycTime = 0;
162
163         for (SckId = 0; SckId < MAX_SOCKETS; SckId++) {
164                 if (DramAttr->DimmInfo[SckId].bPresence) {
165                         Tmp =
166                             (DramAttr->
167                              DimmInfo[SckId].SPDDataBuf[SPD_SDRAM_CAS_LATENCY]);
168                         tmpMask = 0x40;
169                         for (TmpId = 7; TmpId > 0; TmpId--) {
170                                 if ((Tmp & tmpMask) == tmpMask)
171                                         break;
172                                 tmpMask >>= 1;
173                         }
174                         if (TmpId - BitId == 0) {       /*get Cycle time for X, SPD BYTE9 */
175                                 TmpCycTime =
176                                     DramAttr->
177                                     DimmInfo[SckId].SPDDataBuf
178                                     [SPD_SDRAM_TCLK_X];
179                         } else if (TmpId - BitId == 1) {        /*get Cycle time for X-1, SPD BYTE23 */
180                                 TmpCycTime =
181                                     DramAttr->
182                                     DimmInfo[SckId].SPDDataBuf
183                                     [SPD_SDRAM_TCLK_X_1];
184                         } else if (TmpId - BitId == 2) {        /*get cycle time for X-2, SPD BYTE25 */
185                                 TmpCycTime =
186                                     DramAttr->
187                                     DimmInfo[SckId].SPDDataBuf
188                                     [SPD_SDRAM_TCLK_X_2];
189                         } else {
190                                 //error!!!
191                         }
192                         if (TmpCycTime > CycTime)       /*get the most cycle time,there is some problem! */
193                                 CycTime = TmpCycTime;
194                 }
195         }
196
197         if (CycTime <= 0) {
198                 //error!
199                 for (;;) ;
200         }
201
202         /* cycle time value
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
210          */
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;
232         }
233         //if set the frequence mannul
234         PRINT_DEBUG_MEM("Dram Frequency:");
235         PRINT_DEBUG_MEM_HEX16(DramAttr->DramFreq);
236         PRINT_DEBUG_MEM(" \r");
237 }