/* * 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 */ 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"); }