summaryrefslogtreecommitdiff
path: root/src/northbridge/via/vx800/freq_setting.c
blob: 4eeba12886c426ff805d6135d2f20b9a5db058a3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
/*
 * 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.
 */

void CalcCLAndFreq(DRAM_SYS_ATTR * DramAttr);

/*
 Set DRAM Frequency
*/
void DRAMFreqSetting(DRAM_SYS_ATTR * DramAttr)
{

	u8 Data = 0;

	PRINT_DEBUG_MEM("Dram Frequency setting \r");

	//calculate dram frequency using SPD data
	CalcCLAndFreq(DramAttr);

	//init some Dramc control by Simon Chu slide
	//Must use "CPU delay" to make sure VLINK is dis-connect
	Data = pci_read_config8(PCI_DEV(0, 0, 7), 0x47);
	Data = (u8) (Data | 0x04);
	pci_write_config8(PCI_DEV(0, 0, 7), 0x47, Data);

	//in order to make sure NB command buffer don`t have pending request(C2P cycle)
	//CPU DELAY
	WaitMicroSec(20);

	//Before Set Dram Frequency, we must set 111 by Simon Chu slide.
	Data = pci_read_config8(MEMCTRL, 0x90);
	Data = (u8) ((Data & 0xf8) | 7);
	pci_write_config8(MEMCTRL, 0x90, Data);

	WaitMicroSec(20);

	//Set Dram Frequency.
	Data = pci_read_config8(MEMCTRL, 0x90);
	switch (DramAttr->DramFreq) {
	case DIMMFREQ_400:
		Data = (u8) ((Data & 0xf8) | 3);
		break;
	case DIMMFREQ_533:
		Data = (u8) ((Data & 0xf8) | 4);
		break;
	case DIMMFREQ_667:
		Data = (u8) ((Data & 0xf8) | 5);
		break;
	case DIMMFREQ_800:
		Data = (u8) ((Data & 0xf8) | 6);
		break;
	default:
		Data = (u8) ((Data & 0xf8) | 1);
	}
	pci_write_config8(MEMCTRL, 0x90, Data);

	//CPU Delay
	WaitMicroSec(20);

	// Manual       reset and adjust DLL when DRAM change frequency
	Data = pci_read_config8(MEMCTRL, 0x6B);
	Data = (u8) ((Data & 0x2f) | 0xC0);
	pci_write_config8(MEMCTRL, 0x6B, Data);

	//CPU Delay
	WaitMicroSec(20);

	Data = pci_read_config8(MEMCTRL, 0x6B);
	Data = (u8) (Data | 0x10);
	pci_write_config8(MEMCTRL, 0x6B, Data);

	//CPU Delay
	WaitMicroSec(20);

	Data = pci_read_config8(MEMCTRL, 0x6B);
	Data = (u8) (Data & 0x3f);
	pci_write_config8(MEMCTRL, 0x6B, Data);

	//disable V_LINK Auto-Disconnect, or else program may stopped at some place and
	//we cannot find the reason
	Data = pci_read_config8(PCI_DEV(0, 0, 7), 0x47);
	Data = (u8) (Data & 0xFB);
	pci_write_config8(PCI_DEV(0, 0, 7), 0x47, Data);

}

/*
 calculate CL and dram freq
 DDR1
 +---+---+---+---+---+---+---+---+
 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
 +---+---+---+---+---+---+---+---+
 |TBD| 4 |3.5| 3 |2.5| 2 |1.5| 1 |
 +---+---+---+---+---+---+---+---+
 DDR2
 +---+---+---+---+---+---+---+---+
 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
 +---+---+---+---+---+---+---+---+
 |TBD| 6 | 5 | 4 | 3 | 2 |TBD|TBD|
 +---+---+---+---+---+---+---+---+
*/
static const u8 CL_DDR1[7] = { 10, 15, 20, 25, 30, 35, 40 };
static const u8 CL_DDR2[7] = { 0, 0, 20, 30, 40, 50, 60 };

void CalcCLAndFreq(DRAM_SYS_ATTR * DramAttr)
{
	u8 AllDimmSupportedCL, Tmp;
	u8 CLMask, tmpMask;
	u8 SckId, BitId, TmpId;
	u16 CycTime, TmpCycTime;

	/*1.list the CL value that all DIMM supported */
	AllDimmSupportedCL = 0xFF;
	if (RAMTYPE_SDRAMDDR2 == DramAttr->DramType)
		AllDimmSupportedCL &= 0x7C;	/*bit2,3,4,5,6 */
	else			/*DDR1 */
		AllDimmSupportedCL &= 0x7F;	/*bit0,1,2,3,4,5,6 */
	for (SckId = 0; SckId < MAX_SOCKETS; SckId++) {
		if (DramAttr->DimmInfo[SckId].bPresence) {	/*all DIMM supported CL */
			AllDimmSupportedCL &=
			    (DramAttr->
			     DimmInfo[SckId].SPDDataBuf[SPD_SDRAM_CAS_LATENCY]);
		}
	}
	if (!AllDimmSupportedCL) {	/*if equal 0, no supported CL */
		die("SPD Data Error, Can not get CL !!!! \r");

	}

	/*Get CL Value */
	CLMask = 0x40;		/*from Bit6 */

	for (BitId = 7; BitId > 0; BitId--) {
		if ((AllDimmSupportedCL & CLMask) == CLMask) {	/*find the first bit */
			if (RAMTYPE_SDRAMDDR2 == DramAttr->DramType)
				DramAttr->CL = CL_DDR2[BitId - 1];
			else	/*DDR1 */
				DramAttr->CL = CL_DDR1[BitId - 1];
			break;
		}
		CLMask >>= 1;
	}

	/*according the CL value calculate the cycle time, for X or X-1 or X-2 */
	CycTime = 0;
	TmpCycTime = 0;

	for (SckId = 0; SckId < MAX_SOCKETS; SckId++) {
		if (DramAttr->DimmInfo[SckId].bPresence) {
			Tmp =
			    (DramAttr->
			     DimmInfo[SckId].SPDDataBuf[SPD_SDRAM_CAS_LATENCY]);
			tmpMask = 0x40;
			for (TmpId = 7; TmpId > 0; TmpId--) {
				if ((Tmp & tmpMask) == tmpMask)
					break;
				tmpMask >>= 1;
			}
			if (TmpId - BitId == 0) {	/*get Cycle time for X, SPD BYTE9 */
				TmpCycTime =
				    DramAttr->
				    DimmInfo[SckId].SPDDataBuf
				    [SPD_SDRAM_TCLK_X];
			} else if (TmpId - BitId == 1) {	/*get Cycle time for X-1, SPD BYTE23 */
				TmpCycTime =
				    DramAttr->
				    DimmInfo[SckId].SPDDataBuf
				    [SPD_SDRAM_TCLK_X_1];
			} else if (TmpId - BitId == 2) {	/*get cycle time for X-2, SPD BYTE25 */
				TmpCycTime =
				    DramAttr->
				    DimmInfo[SckId].SPDDataBuf
				    [SPD_SDRAM_TCLK_X_2];
			} else {
				//error!!!
			}
			if (TmpCycTime > CycTime)	/*get the most cycle time,there is some problem! */
				CycTime = TmpCycTime;
		}
	}

	if (CycTime <= 0) {
		//error!
		die("Error, cycle time <= 0\n");
	}

	/* cycle time value
	   0x25-->2.5ns Freq = 400  DDR800
	   0x30-->3.0ns Freq = 333  DDR667
	   0x3D-->3.75ns Freq = 266 DDR533
	   0x50-->5.0ns Freq = 200  DDR400
	   0x60-->6.0ns Freq = 166  DDR333
	   0x75-->7.5ns Freq = 133  DDR266
	   0xA0-->10.0ns Freq = 100 DDR200
	 */
	if (CycTime <= 0x25) {
		DramAttr->DramFreq = DIMMFREQ_800;
		DramAttr->DramCyc = 250;
	} else if (CycTime <= 0x30) {
		DramAttr->DramFreq = DIMMFREQ_667;
		DramAttr->DramCyc = 300;
	} else if (CycTime <= 0x3d) {
		DramAttr->DramFreq = DIMMFREQ_533;
		DramAttr->DramCyc = 375;
	} else if (CycTime <= 0x50) {
		DramAttr->DramFreq = DIMMFREQ_400;
		DramAttr->DramCyc = 500;
	} else if (CycTime <= 0x60) {
		DramAttr->DramFreq = DIMMFREQ_333;
		DramAttr->DramCyc = 600;
	} else if (CycTime <= 0x75) {
		DramAttr->DramFreq = DIMMFREQ_266;
		DramAttr->DramCyc = 750;
	} else if (CycTime <= 0xA0) {
		DramAttr->DramFreq = DIMMFREQ_200;
		DramAttr->DramCyc = 1000;
	}
	//if set the frequence mannul
	PRINT_DEBUG_MEM("Dram Frequency:");
	PRINT_DEBUG_MEM_HEX16(DramAttr->DramFreq);
	PRINT_DEBUG_MEM(" \r");
}