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