diff options
Diffstat (limited to 'src/northbridge/via/vx800/freq_setting.c')
-rw-r--r-- | src/northbridge/via/vx800/freq_setting.c | 235 |
1 files changed, 235 insertions, 0 deletions
diff --git a/src/northbridge/via/vx800/freq_setting.c b/src/northbridge/via/vx800/freq_setting.c new file mode 100644 index 0000000000..ed4184ec77 --- /dev/null +++ b/src/northbridge/via/vx800/freq_setting.c @@ -0,0 +1,235 @@ +/* + * 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 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, IndexDelta; + 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 */ + PRINT_DEBUG_MEM("SPD Data Error, Can not get CL !!!! \r"); + for (;;); + } + + /*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! + for (;;); + } + + /* 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"); +} |