| /******************************************************************************* |
| Copyright (C) Marvell International Ltd. and its affiliates |
| |
| This software file (the "File") is owned and distributed by Marvell |
| International Ltd. and/or its affiliates ("Marvell") under the following |
| alternative licensing terms. Once you have made an election to distribute the |
| File under one of the following license alternatives, please (i) delete this |
| introductory statement regarding license alternatives, (ii) delete the two |
| license alternatives that you have not elected to use and (iii) preserve the |
| Marvell copyright notice above. |
| |
| ******************************************************************************** |
| Marvell Commercial License Option |
| |
| If you received this File from Marvell and you have entered into a commercial |
| license agreement (a "Commercial License") with Marvell, the File is licensed |
| to you under the terms of the applicable Commercial License. |
| |
| ******************************************************************************** |
| Marvell GPL License Option |
| |
| If you received this File from Marvell, you may opt to use, redistribute and/or |
| modify this File in accordance with the terms and conditions of the General |
| Public License Version 2, June 1991 (the "GPL License"), a copy of which is |
| available along with the File in the license.txt file or by writing to the Free |
| Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or |
| on the worldwide web at http://www.gnu.org/licenses/gpl.txt. |
| |
| THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED |
| WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY |
| DISCLAIMED. The GPL License provides additional details about this warranty |
| disclaimer. |
| ******************************************************************************** |
| Marvell BSD License Option |
| |
| If you received this File from Marvell, you may opt to use, redistribute and/or |
| modify this File under the following licensing terms. |
| Redistribution and use in source and binary forms, with or without modification, |
| are permitted provided that the following conditions are met: |
| |
| * Redistributions of source code must retain the above copyright notice, |
| this list of conditions and the following disclaimer. |
| |
| * Redistributions in binary form must reproduce the above copyright |
| notice, this list of conditions and the following disclaimer in the |
| documentation and/or other materials provided with the distribution. |
| |
| * Neither the name of Marvell nor the names of its contributors may be |
| used to endorse or promote products derived from this software without |
| specific prior written permission. |
| |
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
| ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR |
| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON |
| ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| *******************************************************************************/ |
| |
| #include "mvCommon.h" |
| #include "mvOs.h" |
| #include "ctrlEnv/mvCtrlEnvSpec.h" |
| #include "mvSysRtcConfig.h" |
| #include "ddr2/mvDramIf.h" |
| #include "ddr2/spd/mvSpd.h" |
| #include "boardEnv/mvBoardEnvLib.h" |
| #include "ddr2/mvSysDdr.h" |
| |
| /* #define MV_DEBUG */ |
| #ifdef MV_DEBUG |
| #define DB(x) x |
| #else |
| #define DB(x) |
| #endif |
| |
| static MV_VOID cpyDimm2BankInfo(MV_DIMM_INFO *pDimmInfo, MV_DRAM_BANK_INFO *pBankInfo); |
| static MV_U32 cas2ps(MV_U8 spd_byte); |
| /******************************************************************************* |
| * mvDramBankGet - Get the DRAM bank paramters. |
| * |
| * DESCRIPTION: |
| * This function retrieves DRAM bank parameters as described in |
| * DRAM_BANK_INFO struct to the controller DRAM unit. In case the board |
| * has its DRAM on DIMMs it will use its EEPROM to extract SPD data |
| * from it. Otherwise, if the DRAM is soldered on board, the function |
| * should insert its bank information into MV_DRAM_BANK_INFO struct. |
| * |
| * INPUT: |
| * bankNum - Board DRAM bank number. |
| * |
| * OUTPUT: |
| * pBankInfo - DRAM bank information struct. |
| * |
| * RETURN: |
| * MV_FAIL - Bank parameters could not be read. |
| * |
| *******************************************************************************/ |
| MV_STATUS mvDramBankInfoGet(MV_U32 bankNum, MV_DRAM_BANK_INFO *pBankInfo) |
| { |
| MV_DIMM_INFO dimmInfo; |
| |
| DB(mvOsPrintf("Dram: mvDramBankInfoGet bank %d\n", bankNum)); |
| /* zero pBankInfo structure */ |
| |
| if ((NULL == pBankInfo) || (bankNum >= MV_DRAM_MAX_CS)) { |
| DB(mvOsPrintf("Dram: mvDramBankInfoGet bad params \n")); |
| return MV_BAD_PARAM; |
| } |
| memset(pBankInfo, 0, sizeof(*pBankInfo)); |
| |
| if (MV_OK != dimmSpdGet((MV_U32) (bankNum / 2), &dimmInfo)) { |
| DB(mvOsPrintf("Dram: ERR dimmSpdGet failed to get dimm info \n")); |
| return MV_FAIL; |
| } |
| if ((dimmInfo.numOfModuleBanks == 1) && ((bankNum % 2) == 1)) { |
| DB(mvOsPrintf("Dram: ERR dimmSpdGet. Can't find DIMM bank 2 \n")); |
| return MV_FAIL; |
| } |
| /* convert Dimm info to Bank info */ |
| cpyDimm2BankInfo(&dimmInfo, pBankInfo); |
| return MV_OK; |
| } |
| |
| /******************************************************************************* |
| * cpyDimm2BankInfo - Convert a Dimm info struct into a bank info struct. |
| * |
| * DESCRIPTION: |
| * Convert a Dimm info struct into a bank info struct. |
| * |
| * INPUT: |
| * pDimmInfo - DIMM information structure. |
| * |
| * OUTPUT: |
| * pBankInfo - DRAM bank information struct. |
| * |
| * RETURN: |
| * None. |
| * |
| *******************************************************************************/ |
| static MV_VOID cpyDimm2BankInfo(MV_DIMM_INFO *pDimmInfo, MV_DRAM_BANK_INFO *pBankInfo) |
| { |
| pBankInfo->memoryType = pDimmInfo->memoryType; |
| |
| /* DIMM dimensions */ |
| pBankInfo->numOfRowAddr = pDimmInfo->numOfRowAddr; |
| pBankInfo->numOfColAddr = pDimmInfo->numOfColAddr; |
| pBankInfo->dataWidth = pDimmInfo->dataWidth; |
| pBankInfo->errorCheckType = pDimmInfo->errorCheckType; |
| pBankInfo->sdramWidth = pDimmInfo->sdramWidth; |
| pBankInfo->errorCheckDataWidth = pDimmInfo->errorCheckDataWidth; |
| pBankInfo->numOfBanksOnEachDevice = pDimmInfo->numOfBanksOnEachDevice; |
| pBankInfo->suportedCasLatencies = pDimmInfo->suportedCasLatencies; |
| pBankInfo->refreshInterval = pDimmInfo->refreshInterval; |
| |
| /* DIMM timing parameters */ |
| pBankInfo->minCycleTimeAtMaxCasLatPs = pDimmInfo->minCycleTimeAtMaxCasLatPs; |
| pBankInfo->minCycleTimeAtMaxCasLatMinus1Ps = pDimmInfo->minCycleTimeAtMaxCasLatMinus1Ps; |
| pBankInfo->minCycleTimeAtMaxCasLatMinus2Ps = pDimmInfo->minCycleTimeAtMaxCasLatMinus2Ps; |
| |
| pBankInfo->minRowPrechargeTime = pDimmInfo->minRowPrechargeTime; |
| pBankInfo->minRowActiveToRowActive = pDimmInfo->minRowActiveToRowActive; |
| pBankInfo->minRasToCasDelay = pDimmInfo->minRasToCasDelay; |
| pBankInfo->minRasPulseWidth = pDimmInfo->minRasPulseWidth; |
| pBankInfo->minWriteRecoveryTime = pDimmInfo->minWriteRecoveryTime; |
| pBankInfo->minWriteToReadCmdDelay = pDimmInfo->minWriteToReadCmdDelay; |
| pBankInfo->minReadToPrechCmdDelay = pDimmInfo->minReadToPrechCmdDelay; |
| pBankInfo->minRefreshToActiveCmd = pDimmInfo->minRefreshToActiveCmd; |
| |
| /* Parameters calculated from the extracted DIMM information */ |
| pBankInfo->size = pDimmInfo->size / pDimmInfo->numOfModuleBanks; |
| pBankInfo->deviceDensity = pDimmInfo->deviceDensity; |
| pBankInfo->numberOfDevices = pDimmInfo->numberOfDevices / pDimmInfo->numOfModuleBanks; |
| |
| /* DIMM attributes (MV_TRUE for yes) */ |
| |
| if ((pDimmInfo->memoryType == MEM_TYPE_SDRAM) || (pDimmInfo->memoryType == MEM_TYPE_DDR1)) { |
| if (pDimmInfo->dimmAttributes & BIT1) |
| pBankInfo->registeredAddrAndControlInputs = MV_TRUE; |
| else |
| pBankInfo->registeredAddrAndControlInputs = MV_FALSE; |
| } else { /* pDimmInfo->memoryType == MEM_TYPE_DDR2 */ |
| |
| if (pDimmInfo->dimmTypeInfo & (BIT0 | BIT4)) |
| pBankInfo->registeredAddrAndControlInputs = MV_TRUE; |
| else |
| pBankInfo->registeredAddrAndControlInputs = MV_FALSE; |
| } |
| |
| return; |
| } |
| |
| /******************************************************************************* |
| * dimmSpdCpy - Cpy SPD parameters from dimm 0 to dimm 1. |
| * |
| * DESCRIPTION: |
| * Read the DIMM SPD parameters from dimm 0 into dimm 1 SPD. |
| * |
| * INPUT: |
| * None. |
| * |
| * OUTPUT: |
| * None. |
| * |
| * RETURN: |
| * MV_TRUE if function could read DIMM parameters, MV_FALSE otherwise. |
| * |
| *******************************************************************************/ |
| MV_STATUS dimmSpdCpy(MV_VOID) |
| { |
| MV_U32 i; |
| MV_U32 spdChecksum; |
| |
| MV_U8 data[SPD_SIZE]; |
| |
| /* zero dimmInfo structure */ |
| memset(data, 0, SPD_SIZE); |
| |
| /* read the dimm eeprom */ |
| DB(mvOsPrintf("DRAM: Read Dimm eeprom\n")); |
| |
| if (MV_OK != mvSysDdrSpdRead(data, SPD_SIZE)) { |
| DB(mvOsPrintf("DRAM: ERR. no DIMM in dimmNum 0\n")); |
| return MV_FAIL; |
| } |
| |
| DB(puts("DRAM: Reading dimm info succeded.\n")); |
| |
| /* calculate SPD checksum */ |
| spdChecksum = 0; |
| |
| for (i = 0; i <= 62; i++) |
| spdChecksum += data[i]; |
| |
| if ((spdChecksum & 0xff) != data[63]) { |
| DB(mvOsPrintf("DRAM: Warning. Wrong SPD Checksum %2x, expValue=%2x\n", |
| (MV_U32) (spdChecksum & 0xff), data[63])); |
| } else { |
| DB(mvOsPrintf("DRAM: SPD Checksum ok!\n")); |
| } |
| |
| /* copy the SPD content 1:1 into the DIMM 1 SPD */ |
| for (i = 0; i < SPD_SIZE; i++) { |
| if (MV_OK != mvSysDdrSpdWrite(&data[i], 1)) { |
| mvOsPrintf("DRAM: ERR. no DIMM in dimmNum 1 byte %d \n", i); |
| return MV_FAIL; |
| } |
| mvOsDelay(5); |
| } |
| |
| DB(puts("DRAM: Reading dimm info succeded.\n")); |
| return MV_OK; |
| } |
| |
| /******************************************************************************* |
| * dimmSpdGet - Get the SPD parameters. |
| * |
| * DESCRIPTION: |
| * Read the DIMM SPD parameters into given struct parameter. |
| * |
| * INPUT: |
| * dimmNum - DIMM number. See MV_BOARD_DIMM_NUM enumerator. |
| * |
| * OUTPUT: |
| * pDimmInfo - DIMM information structure. |
| * |
| * RETURN: |
| * MV_TRUE if function could read DIMM parameters, MV_FALSE otherwise. |
| * |
| *******************************************************************************/ |
| MV_STATUS dimmSpdGet(MV_U32 dimmNum, MV_DIMM_INFO *pDimmInfo) |
| { |
| MV_U32 i; |
| MV_U32 density = 1; |
| MV_U32 spdChecksum; |
| |
| MV_U8 data[SPD_SIZE]; |
| |
| if ((NULL == pDimmInfo) || (dimmNum >= MAX_DIMM_NUM)) { |
| DB(mvOsPrintf("Dram: mvDramBankInfoGet bad params \n")); |
| return MV_BAD_PARAM; |
| } |
| |
| /* zero dimmInfo structure */ |
| memset(data, 0, SPD_SIZE); |
| |
| /* read the dimm eeprom */ |
| DB(mvOsPrintf("DRAM: Read Dimm eeprom\n")); |
| if (MV_OK != mvSysDdrSpdRead(data, SPD_SIZE)) { |
| DB(mvOsPrintf("DRAM: ERR. no DIMM in dimmNum %d \n", dimmNum)); |
| return MV_FAIL; |
| } |
| DB(puts("DRAM: Reading dimm info succeded.\n")); |
| |
| /* calculate SPD checksum */ |
| spdChecksum = 0; |
| |
| for (i = 0; i <= 62; i++) |
| spdChecksum += data[i]; |
| |
| if ((spdChecksum & 0xff) != data[63]) { |
| DB(mvOsPrintf("DRAM: Warning. Wrong SPD Checksum %2x, expValue=%2x\n", |
| (MV_U32) (spdChecksum & 0xff), data[63])); |
| } else { |
| DB(mvOsPrintf("DRAM: SPD Checksum ok!\n")); |
| } |
| |
| /* copy the SPD content 1:1 into the dimmInfo structure */ |
| for (i = 0; i < SPD_SIZE; i++) { |
| pDimmInfo->spdRawData[i] = data[i]; |
| DB(mvOsPrintf("SPD-EEPROM Byte %3d = %3x (%3d)\n", i, data[i], data[i])); |
| } |
| |
| DB(mvOsPrintf("DRAM SPD Information:\n")); |
| |
| /* Memory type (DDR / SDRAM) */ |
| switch (data[DIMM_MEM_TYPE]) { |
| case (DIMM_MEM_TYPE_SDRAM): |
| pDimmInfo->memoryType = MEM_TYPE_SDRAM; |
| DB(mvOsPrintf("DRAM Memeory type SDRAM\n")); |
| break; |
| case (DIMM_MEM_TYPE_DDR1): |
| pDimmInfo->memoryType = MEM_TYPE_DDR1; |
| DB(mvOsPrintf("DRAM Memeory type DDR1\n")); |
| break; |
| case (DIMM_MEM_TYPE_DDR2): |
| pDimmInfo->memoryType = MEM_TYPE_DDR2; |
| DB(mvOsPrintf("DRAM Memeory type DDR2\n")); |
| break; |
| default: |
| mvOsPrintf("ERROR: Undefined memory type!\n"); |
| return MV_ERROR; |
| } |
| |
| /* Number Of Row Addresses */ |
| pDimmInfo->numOfRowAddr = data[DIMM_ROW_NUM]; |
| DB(mvOsPrintf("DRAM numOfRowAddr[3] %d\n", pDimmInfo->numOfRowAddr)); |
| |
| /* Number Of Column Addresses */ |
| pDimmInfo->numOfColAddr = data[DIMM_COL_NUM]; |
| DB(mvOsPrintf("DRAM numOfColAddr[4] %d\n", pDimmInfo->numOfColAddr)); |
| |
| /* Number Of Module Banks */ |
| pDimmInfo->numOfModuleBanks = data[DIMM_MODULE_BANK_NUM]; |
| DB(mvOsPrintf("DRAM numOfModuleBanks[5] 0x%x\n", pDimmInfo->numOfModuleBanks)); |
| |
| /* Number of module banks encoded differently for DDR2 */ |
| if (pDimmInfo->memoryType == MEM_TYPE_DDR2) |
| pDimmInfo->numOfModuleBanks = (pDimmInfo->numOfModuleBanks & 0x7) + 1; |
| |
| /* Data Width */ |
| pDimmInfo->dataWidth = data[DIMM_DATA_WIDTH]; |
| DB(mvOsPrintf("DRAM dataWidth[6] 0x%x\n", pDimmInfo->dataWidth)); |
| |
| /* Minimum Cycle Time At Max CasLatancy */ |
| pDimmInfo->minCycleTimeAtMaxCasLatPs = cas2ps(data[DIMM_MIN_CC_AT_MAX_CAS]); |
| |
| /* Error Check Type */ |
| pDimmInfo->errorCheckType = data[DIMM_ERR_CHECK_TYPE]; |
| DB(mvOsPrintf("DRAM errorCheckType[11] 0x%x\n", pDimmInfo->errorCheckType)); |
| |
| /* Refresh Interval */ |
| pDimmInfo->refreshInterval = data[DIMM_REFRESH_INTERVAL]; |
| DB(mvOsPrintf("DRAM refreshInterval[12] 0x%x\n", pDimmInfo->refreshInterval)); |
| |
| /* Sdram Width */ |
| pDimmInfo->sdramWidth = data[DIMM_SDRAM_WIDTH]; |
| DB(mvOsPrintf("DRAM sdramWidth[13] 0x%x\n", pDimmInfo->sdramWidth)); |
| |
| /* Error Check Data Width */ |
| pDimmInfo->errorCheckDataWidth = data[DIMM_ERR_CHECK_DATA_WIDTH]; |
| DB(mvOsPrintf("DRAM errorCheckDataWidth[14] 0x%x\n", pDimmInfo->errorCheckDataWidth)); |
| |
| /* Burst Length Supported */ |
| /* SDRAM/DDR1: |
| *******-******-******-******-******-******-******-******* |
| * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 * |
| *******-******-******-******-******-******-******-******* |
| burst length = * Page | TBD | TBD | TBD | 8 | 4 | 2 | 1 * |
| *********************************************************/ |
| /* DDR2: |
| *******-******-******-******-******-******-******-******* |
| * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 * |
| *******-******-******-******-******-******-******-******* |
| burst length = * Page | TBD | TBD | TBD | 8 | 4 | TBD | TBD * |
| *********************************************************/ |
| |
| pDimmInfo->burstLengthSupported = data[DIMM_BURST_LEN_SUP]; |
| DB(mvOsPrintf("DRAM burstLengthSupported[16] 0x%x\n", pDimmInfo->burstLengthSupported)); |
| |
| /* Number Of Banks On Each Device */ |
| pDimmInfo->numOfBanksOnEachDevice = data[DIMM_DEV_BANK_NUM]; |
| DB(mvOsPrintf("DRAM numOfBanksOnEachDevice[17] 0x%x\n", pDimmInfo->numOfBanksOnEachDevice)); |
| |
| /* Suported Cas Latencies */ |
| |
| /* SDRAM: |
| *******-******-******-******-******-******-******-******* |
| * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 * |
| *******-******-******-******-******-******-******-******* |
| CAS = * TBD | 7 | 6 | 5 | 4 | 3 | 2 | 1 * |
| ********************************************************/ |
| |
| /* DDR 1: |
| *******-******-******-******-******-******-******-******* |
| * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 * |
| *******-******-******-******-******-******-******-******* |
| CAS = * TBD | 4 | 3.5 | 3 | 2.5 | 2 | 1.5 | 1 * |
| *********************************************************/ |
| |
| /* DDR 2: |
| *******-******-******-******-******-******-******-******* |
| * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 * |
| *******-******-******-******-******-******-******-******* |
| CAS = * TBD | TBD | 5 | 4 | 3 | 2 | TBD | TBD * |
| *********************************************************/ |
| |
| pDimmInfo->suportedCasLatencies = data[DIMM_SUP_CAL]; |
| DB(mvOsPrintf("DRAM suportedCasLatencies[18] 0x%x\n", pDimmInfo->suportedCasLatencies)); |
| |
| /* For DDR2 only, get the DIMM type information */ |
| if (pDimmInfo->memoryType == MEM_TYPE_DDR2) { |
| pDimmInfo->dimmTypeInfo = data[DIMM_DDR2_TYPE_INFORMATION]; |
| DB(mvOsPrintf("DRAM dimmTypeInfo[20] (DDR2) 0x%x\n", pDimmInfo->dimmTypeInfo)); |
| } |
| |
| /* SDRAM Modules Attributes */ |
| pDimmInfo->dimmAttributes = data[DIMM_BUF_ADDR_CONT_IN]; |
| DB(mvOsPrintf("DRAM dimmAttributes[21] 0x%x\n", pDimmInfo->dimmAttributes)); |
| |
| /* Minimum Cycle Time At Max CasLatancy Minus 1 */ |
| pDimmInfo->minCycleTimeAtMaxCasLatMinus1Ps = cas2ps(data[DIMM_MIN_CC_AT_MAX_CAS_MINUS1]); |
| |
| /* Minimum Cycle Time At Max CasLatancy Minus 2 */ |
| pDimmInfo->minCycleTimeAtMaxCasLatMinus2Ps = cas2ps(data[DIMM_MIN_CC_AT_MAX_CAS_MINUS2]); |
| |
| pDimmInfo->minRowPrechargeTime = data[DIMM_MIN_ROW_PRECHARGE_TIME]; |
| DB(mvOsPrintf("DRAM minRowPrechargeTime[27] 0x%x\n", pDimmInfo->minRowPrechargeTime)); |
| pDimmInfo->minRowActiveToRowActive = data[DIMM_MIN_ROW_ACTIVE_TO_ROW_ACTIVE]; |
| DB(mvOsPrintf("DRAM minRowActiveToRowActive[28] 0x%x\n", pDimmInfo->minRowActiveToRowActive)); |
| pDimmInfo->minRasToCasDelay = data[DIMM_MIN_RAS_TO_CAS_DELAY]; |
| DB(mvOsPrintf("DRAM minRasToCasDelay[29] 0x%x\n", pDimmInfo->minRasToCasDelay)); |
| pDimmInfo->minRasPulseWidth = data[DIMM_MIN_RAS_PULSE_WIDTH]; |
| DB(mvOsPrintf("DRAM minRasPulseWidth[30] 0x%x\n", pDimmInfo->minRasPulseWidth)); |
| |
| /* DIMM Bank Density */ |
| pDimmInfo->dimmBankDensity = data[DIMM_BANK_DENSITY]; |
| DB(mvOsPrintf("DRAM dimmBankDensity[31] 0x%x\n", pDimmInfo->dimmBankDensity)); |
| |
| /* Only DDR2 includes Write Recovery Time field. Other SDRAM ignore */ |
| pDimmInfo->minWriteRecoveryTime = data[DIMM_MIN_WRITE_RECOVERY_TIME]; |
| DB(mvOsPrintf("DRAM minWriteRecoveryTime[36] 0x%x\n", pDimmInfo->minWriteRecoveryTime)); |
| |
| /* Only DDR2 includes Internal Write To Read Command Delay field. */ |
| pDimmInfo->minWriteToReadCmdDelay = data[DIMM_MIN_WRITE_TO_READ_CMD_DELAY]; |
| DB(mvOsPrintf("DRAM minWriteToReadCmdDelay[37] 0x%x\n", pDimmInfo->minWriteToReadCmdDelay)); |
| |
| /* Only DDR2 includes Internal Read To Precharge Command Delay field. */ |
| pDimmInfo->minReadToPrechCmdDelay = data[DIMM_MIN_READ_TO_PRECH_CMD_DELAY]; |
| DB(mvOsPrintf("DRAM minReadToPrechCmdDelay[38] 0x%x\n", pDimmInfo->minReadToPrechCmdDelay)); |
| |
| /* Only DDR2 includes Minimum Refresh to Activate/Refresh Command field */ |
| pDimmInfo->minRefreshToActiveCmd = data[DIMM_MIN_REFRESH_TO_ACTIVATE_CMD]; |
| DB(mvOsPrintf("DRAM minRefreshToActiveCmd[42] 0x%x\n", pDimmInfo->minRefreshToActiveCmd)); |
| |
| /* calculating the sdram density. Representing device density from */ |
| /* bit 20 to allow representation of 4GB and above. */ |
| /* For example, if density is 512Mbit 0x20000000, will be represent in */ |
| /* deviceDensity by 0x20000000 >> 16 --> 0x00000200. Another example */ |
| /* is density 8GB 0x200000000 >> 16 --> 0x00002000. */ |
| density = (1 << ((pDimmInfo->numOfRowAddr + pDimmInfo->numOfColAddr) - 20)); |
| pDimmInfo->deviceDensity = density * pDimmInfo->numOfBanksOnEachDevice * pDimmInfo->sdramWidth; |
| DB(mvOsPrintf("DRAM deviceDensity %d\n", pDimmInfo->deviceDensity)); |
| |
| /* Number of devices includeing Error correction */ |
| pDimmInfo->numberOfDevices = (pDimmInfo->dataWidth / pDimmInfo->sdramWidth) * pDimmInfo->numOfModuleBanks; |
| DB(mvOsPrintf("DRAM numberOfDevices %d\n", pDimmInfo->numberOfDevices)); |
| |
| pDimmInfo->size = 0; |
| |
| /* Note that pDimmInfo->size is in MB units */ |
| if (pDimmInfo->memoryType == MEM_TYPE_SDRAM) { |
| if (pDimmInfo->dimmBankDensity & BIT0) |
| pDimmInfo->size += 1024; /* Equal to 1GB */ |
| else if (pDimmInfo->dimmBankDensity & BIT1) |
| pDimmInfo->size += 8; /* Equal to 8MB */ |
| else if (pDimmInfo->dimmBankDensity & BIT2) |
| pDimmInfo->size += 16; /* Equal to 16MB */ |
| else if (pDimmInfo->dimmBankDensity & BIT3) |
| pDimmInfo->size += 32; /* Equal to 32MB */ |
| else if (pDimmInfo->dimmBankDensity & BIT4) |
| pDimmInfo->size += 64; /* Equal to 64MB */ |
| else if (pDimmInfo->dimmBankDensity & BIT5) |
| pDimmInfo->size += 128; /* Equal to 128MB */ |
| else if (pDimmInfo->dimmBankDensity & BIT6) |
| pDimmInfo->size += 256; /* Equal to 256MB */ |
| else if (pDimmInfo->dimmBankDensity & BIT7) |
| pDimmInfo->size += 512; /* Equal to 512MB */ |
| } else if (pDimmInfo->memoryType == MEM_TYPE_DDR1) { |
| if (pDimmInfo->dimmBankDensity & BIT0) |
| pDimmInfo->size += 1024; /* Equal to 1GB */ |
| else if (pDimmInfo->dimmBankDensity & BIT1) |
| pDimmInfo->size += 2048; /* Equal to 2GB */ |
| else if (pDimmInfo->dimmBankDensity & BIT2) |
| pDimmInfo->size += 16; /* Equal to 16MB */ |
| else if (pDimmInfo->dimmBankDensity & BIT3) |
| pDimmInfo->size += 32; /* Equal to 32MB */ |
| else if (pDimmInfo->dimmBankDensity & BIT4) |
| pDimmInfo->size += 64; /* Equal to 64MB */ |
| else if (pDimmInfo->dimmBankDensity & BIT5) |
| pDimmInfo->size += 128; /* Equal to 128MB */ |
| else if (pDimmInfo->dimmBankDensity & BIT6) |
| pDimmInfo->size += 256; /* Equal to 256MB */ |
| else if (pDimmInfo->dimmBankDensity & BIT7) |
| pDimmInfo->size += 512; /* Equal to 512MB */ |
| } else { /* if (dimmInfo.memoryType == MEM_TYPE_DDR2) */ |
| |
| if (pDimmInfo->dimmBankDensity & BIT0) |
| pDimmInfo->size += 1024; /* Equal to 1GB */ |
| else if (pDimmInfo->dimmBankDensity & BIT1) |
| pDimmInfo->size += 2048; /* Equal to 2GB */ |
| else if (pDimmInfo->dimmBankDensity & BIT2) |
| pDimmInfo->size += 4096; /* Equal to 4GB */ |
| else if (pDimmInfo->dimmBankDensity & BIT3) |
| pDimmInfo->size += 8192; /* Equal to 8GB */ |
| else if (pDimmInfo->dimmBankDensity & BIT4) |
| pDimmInfo->size += 16384; /* Equal to 16GB */ |
| else if (pDimmInfo->dimmBankDensity & BIT5) |
| pDimmInfo->size += 128; /* Equal to 128MB */ |
| else if (pDimmInfo->dimmBankDensity & BIT6) |
| pDimmInfo->size += 256; /* Equal to 256MB */ |
| else if (pDimmInfo->dimmBankDensity & BIT7) |
| pDimmInfo->size += 512; /* Equal to 512MB */ |
| } |
| |
| pDimmInfo->size *= pDimmInfo->numOfModuleBanks; |
| |
| DB(mvOsPrintf("Dram: dimm size %dMB \n", pDimmInfo->size)); |
| |
| return MV_OK; |
| } |
| |
| /******************************************************************************* |
| * dimmSpdPrint - Print the SPD parameters. |
| * |
| * DESCRIPTION: |
| * Print the Dimm SPD parameters. |
| * |
| * INPUT: |
| * pDimmInfo - DIMM information structure. |
| * |
| * OUTPUT: |
| * None. |
| * |
| * RETURN: |
| * None. |
| * |
| *******************************************************************************/ |
| MV_VOID dimmSpdPrint(MV_U32 dimmNum, MV_U32 sysClock) |
| { |
| MV_DIMM_INFO dimmInfo; |
| MV_U32 i, temp = 0; |
| MV_U32 k, maskLeftOfPoint = 0, maskRightOfPoint = 0; |
| MV_U32 rightOfPoint = 0, leftOfPoint = 0, div, time_tmp, shift; |
| MV_U32 busClkPs; |
| MV_U8 trp_clocks = 0, trcd_clocks, tras_clocks, trrd_clocks, temp_buf[40], *spdRawData; |
| |
| busClkPs = 1000000000 / (sysClock / 100); /* in 10 ps units */ |
| |
| spdRawData = dimmInfo.spdRawData; |
| |
| if (MV_OK != dimmSpdGet(dimmNum, &dimmInfo)) { |
| mvOsOutput("ERROR: Could not read SPD information!\n"); |
| return; |
| } |
| |
| /* find Manufactura of Dimm Module */ |
| mvOsOutput("\nManufacturer's JEDEC ID Code: "); |
| for (i = 0; i < DIMM_MODULE_MANU_SIZE; i++) |
| mvOsOutput("%x", spdRawData[DIMM_MODULE_MANU_OFFS + i]); |
| |
| mvOsOutput("\n"); |
| |
| /* Manufacturer's Specific Data */ |
| for (i = 0; i < DIMM_MODULE_ID_SIZE; i++) |
| temp_buf[i] = spdRawData[DIMM_MODULE_ID_OFFS + i]; |
| |
| mvOsOutput("Manufacturer's Specific Data: %s\n", temp_buf); |
| |
| /* Module Part Number */ |
| for (i = 0; i < DIMM_MODULE_VEN_SIZE; i++) |
| temp_buf[i] = spdRawData[DIMM_MODULE_VEN_OFFS + i]; |
| |
| mvOsOutput("Module Part Number: %s\n", temp_buf); |
| |
| /* Module Serial Number */ |
| for (i = 0; i < sizeof(MV_U32); i++) |
| temp |= spdRawData[95 + i] << 8 * i; |
| |
| mvOsOutput("DIMM Serial No. %ld (%lx)\n", (long)temp, (long)temp); |
| |
| /* find Manufac-Data of Dimm Module */ |
| mvOsOutput("Manufactoring Date: Year 20%d%d/ ww %d%d\n", |
| ((spdRawData[93] & 0xf0) >> 4), (spdRawData[93] & 0xf), |
| ((spdRawData[94] & 0xf0) >> 4), (spdRawData[94] & 0xf)); |
| /* find modul_revision of Dimm Module */ |
| mvOsOutput("Module Revision: %d.%d\n", spdRawData[62] / 10, spdRawData[62] % 10); |
| |
| /* find manufac_place of Dimm Module */ |
| mvOsOutput("manufac_place: %d\n", spdRawData[72]); |
| |
| /* go over the first 35 I2C data bytes */ |
| for (i = 2; i <= 35; i++) |
| switch (i) { |
| case 2: /* Memory type (DDR1/2 / SDRAM) */ |
| if (dimmInfo.memoryType == MEM_TYPE_SDRAM) |
| mvOsOutput("Dram Type is: SDRAM\n"); |
| else if (dimmInfo.memoryType == MEM_TYPE_DDR1) |
| mvOsOutput("Dram Type is: SDRAM DDR1\n"); |
| else if (dimmInfo.memoryType == MEM_TYPE_DDR2) |
| mvOsOutput("Dram Type is: SDRAM DDR2\n"); |
| else |
| mvOsOutput("Dram Type unknown\n"); |
| break; |
| /*----------------------------------------------------------------------------*/ |
| |
| case 3: /* Number Of Row Addresses */ |
| mvOsOutput("Module Number of row addresses: %d\n", dimmInfo.numOfRowAddr); |
| break; |
| /*----------------------------------------------------------------------------*/ |
| |
| case 4: /* Number Of Column Addresses */ |
| mvOsOutput("Module Number of col addresses: %d\n", dimmInfo.numOfColAddr); |
| break; |
| /*----------------------------------------------------------------------------*/ |
| |
| case 5: /* Number Of Module Banks */ |
| mvOsOutput("Number of Banks on Mod.: %d\n", dimmInfo.numOfModuleBanks); |
| break; |
| /*----------------------------------------------------------------------------*/ |
| |
| case 6: /* Data Width */ |
| mvOsOutput("Module Data Width: %d bit\n", dimmInfo.dataWidth); |
| break; |
| /*----------------------------------------------------------------------------*/ |
| |
| case 8: /* Voltage Interface */ |
| switch (spdRawData[i]) { |
| case 0x0: |
| mvOsOutput("Module is TTL_5V_TOLERANT\n"); |
| break; |
| case 0x1: |
| mvOsOutput("Module is LVTTL\n"); |
| break; |
| case 0x2: |
| mvOsOutput("Module is HSTL_1_5V\n"); |
| break; |
| case 0x3: |
| mvOsOutput("Module is SSTL_3_3V\n"); |
| break; |
| case 0x4: |
| mvOsOutput("Module is SSTL_2_5V\n"); |
| break; |
| case 0x5: |
| if (dimmInfo.memoryType != MEM_TYPE_SDRAM) { |
| mvOsOutput("Module is SSTL_1_8V\n"); |
| break; |
| } |
| default: |
| mvOsOutput("Module is VOLTAGE_UNKNOWN\n"); |
| break; |
| } |
| break; |
| /*----------------------------------------------------------------------------*/ |
| |
| case 9: /* Minimum Cycle Time At Max CasLatancy */ |
| leftOfPoint = (spdRawData[i] & 0xf0) >> 4; |
| rightOfPoint = (spdRawData[i] & 0x0f) * 10; |
| |
| /* DDR2 addition of right of point */ |
| if ((spdRawData[i] & 0x0f) == 0xA) |
| rightOfPoint = 25; |
| if ((spdRawData[i] & 0x0f) == 0xB) |
| rightOfPoint = 33; |
| if ((spdRawData[i] & 0x0f) == 0xC) |
| rightOfPoint = 66; |
| if ((spdRawData[i] & 0x0f) == 0xD) |
| rightOfPoint = 75; |
| mvOsOutput("Minimum Cycle Time At Max CL: %d.%d [ns]\n", leftOfPoint, rightOfPoint); |
| break; |
| /*----------------------------------------------------------------------------*/ |
| |
| case 10: /* Clock To Data Out */ |
| div = (dimmInfo.memoryType == MEM_TYPE_SDRAM) ? 10 : 100; |
| time_tmp = (((spdRawData[i] & 0xf0) >> 4) * 10) + ((spdRawData[i] & 0x0f)); |
| leftOfPoint = time_tmp / div; |
| rightOfPoint = time_tmp % div; |
| mvOsOutput("Clock To Data Out: %d.%d [ns]\n", leftOfPoint, rightOfPoint); |
| break; |
| /*----------------------------------------------------------------------------*/ |
| |
| case 11: /* Error Check Type */ |
| mvOsOutput("Error Check Type (0=NONE): %d\n", dimmInfo.errorCheckType); |
| break; |
| /*----------------------------------------------------------------------------*/ |
| |
| case 12: /* Refresh Interval */ |
| mvOsOutput("Refresh Rate: %x\n", dimmInfo.refreshInterval); |
| break; |
| /*----------------------------------------------------------------------------*/ |
| |
| case 13: /* Sdram Width */ |
| mvOsOutput("Sdram Width: %d bits\n", dimmInfo.sdramWidth); |
| break; |
| /*----------------------------------------------------------------------------*/ |
| |
| case 14: /* Error Check Data Width */ |
| mvOsOutput("Error Check Data Width: %d bits\n", dimmInfo.errorCheckDataWidth); |
| break; |
| /*----------------------------------------------------------------------------*/ |
| |
| case 15: /* Minimum Clock Delay is unsupported */ |
| if ((dimmInfo.memoryType == MEM_TYPE_SDRAM) || (dimmInfo.memoryType == MEM_TYPE_DDR1)) |
| mvOsOutput("Minimum Clk Delay back to back: %d\n", spdRawData[i]); |
| break; |
| /*----------------------------------------------------------------------------*/ |
| |
| case 16: /* Burst Length Supported */ |
| /* SDRAM/DDR1: |
| *******-******-******-******-******-******-******-******* |
| * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 * |
| *******-******-******-******-******-******-******-******* |
| burst length = * Page | TBD | TBD | TBD | 8 | 4 | 2 | 1 * |
| *********************************************************/ |
| /* DDR2: |
| *******-******-******-******-******-******-******-******* |
| * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 * |
| *******-******-******-******-******-******-******-******* |
| burst length = * Page | TBD | TBD | TBD | 8 | 4 | TBD | TBD * |
| *********************************************************/ |
| mvOsOutput("Burst Length Supported: "); |
| if ((dimmInfo.memoryType == MEM_TYPE_SDRAM) || (dimmInfo.memoryType == MEM_TYPE_DDR1)) { |
| if (dimmInfo.burstLengthSupported & BIT0) |
| mvOsOutput("1, "); |
| if (dimmInfo.burstLengthSupported & BIT1) |
| mvOsOutput("2, "); |
| } |
| if (dimmInfo.burstLengthSupported & BIT2) |
| mvOsOutput("4, "); |
| if (dimmInfo.burstLengthSupported & BIT3) |
| mvOsOutput("8, "); |
| |
| mvOsOutput(" Bit \n"); |
| break; |
| /*----------------------------------------------------------------------------*/ |
| |
| case 17: /* Number Of Banks On Each Device */ |
| mvOsOutput("Number Of Banks On Each Chip: %d\n", dimmInfo.numOfBanksOnEachDevice); |
| break; |
| /*----------------------------------------------------------------------------*/ |
| |
| case 18: /* Suported Cas Latencies */ |
| |
| /* SDRAM: |
| *******-******-******-******-******-******-******-******* |
| * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 * |
| *******-******-******-******-******-******-******-******* |
| CAS = * TBD | 7 | 6 | 5 | 4 | 3 | 2 | 1 * |
| ********************************************************/ |
| |
| /* DDR 1: |
| *******-******-******-******-******-******-******-******* |
| * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 * |
| *******-******-******-******-******-******-******-******* |
| CAS = * TBD | 4 | 3.5 | 3 | 2.5 | 2 | 1.5 | 1 * |
| *********************************************************/ |
| |
| /* DDR 2: |
| *******-******-******-******-******-******-******-******* |
| * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 * |
| *******-******-******-******-******-******-******-******* |
| CAS = * TBD | TBD | 5 | 4 | 3 | 2 | TBD | TBD * |
| *********************************************************/ |
| |
| mvOsOutput("Suported Cas Latencies: (CL) "); |
| if (dimmInfo.memoryType == MEM_TYPE_SDRAM) { |
| for (k = 0; k <= 7; k++) { |
| if (dimmInfo.suportedCasLatencies & (1 << k)) |
| mvOsOutput("%d, ", k + 1); |
| } |
| } else if (dimmInfo.memoryType == MEM_TYPE_DDR1) { |
| if (dimmInfo.suportedCasLatencies & BIT0) |
| mvOsOutput("1, "); |
| if (dimmInfo.suportedCasLatencies & BIT1) |
| mvOsOutput("1.5, "); |
| if (dimmInfo.suportedCasLatencies & BIT2) |
| mvOsOutput("2, "); |
| if (dimmInfo.suportedCasLatencies & BIT3) |
| mvOsOutput("2.5, "); |
| if (dimmInfo.suportedCasLatencies & BIT4) |
| mvOsOutput("3, "); |
| if (dimmInfo.suportedCasLatencies & BIT5) |
| mvOsOutput("3.5, "); |
| } else if (dimmInfo.memoryType == MEM_TYPE_DDR2) { |
| if (dimmInfo.suportedCasLatencies & BIT2) |
| mvOsOutput("2, "); |
| if (dimmInfo.suportedCasLatencies & BIT3) |
| mvOsOutput("3, "); |
| if (dimmInfo.suportedCasLatencies & BIT4) |
| mvOsOutput("4, "); |
| if (dimmInfo.suportedCasLatencies & BIT5) |
| mvOsOutput("5, "); |
| } else |
| mvOsOutput("?.?, "); |
| mvOsOutput("\n"); |
| break; |
| /*----------------------------------------------------------------------------*/ |
| |
| case 20: /* DDR2 DIMM type info */ |
| if (dimmInfo.memoryType == MEM_TYPE_DDR2) { |
| if (dimmInfo.dimmTypeInfo & (BIT0 | BIT4)) |
| mvOsOutput("Registered DIMM (RDIMM)\n"); |
| else if (dimmInfo.dimmTypeInfo & (BIT1 | BIT5)) |
| mvOsOutput("Unbuffered DIMM (UDIMM)\n"); |
| else |
| mvOsOutput("Unknown DIMM type.\n"); |
| } |
| |
| break; |
| /*----------------------------------------------------------------------------*/ |
| |
| case 21: /* SDRAM Modules Attributes */ |
| mvOsOutput("\nModule Attributes (SPD Byte 21): \n"); |
| |
| if (dimmInfo.memoryType == MEM_TYPE_SDRAM) { |
| if (dimmInfo.dimmAttributes & BIT0) |
| mvOsOutput(" Buffered Addr/Control Input: Yes\n"); |
| else |
| mvOsOutput(" Buffered Addr/Control Input: No\n"); |
| |
| if (dimmInfo.dimmAttributes & BIT1) |
| mvOsOutput(" Registered Addr/Control Input: Yes\n"); |
| else |
| mvOsOutput(" Registered Addr/Control Input: No\n"); |
| |
| if (dimmInfo.dimmAttributes & BIT2) |
| mvOsOutput(" On-Card PLL (clock): Yes \n"); |
| else |
| mvOsOutput(" On-Card PLL (clock): No \n"); |
| |
| if (dimmInfo.dimmAttributes & BIT3) |
| mvOsOutput(" Bufferd DQMB Input: Yes \n"); |
| else |
| mvOsOutput(" Bufferd DQMB Inputs: No \n"); |
| |
| if (dimmInfo.dimmAttributes & BIT4) |
| mvOsOutput(" Registered DQMB Inputs: Yes \n"); |
| else |
| mvOsOutput(" Registered DQMB Inputs: No \n"); |
| |
| if (dimmInfo.dimmAttributes & BIT5) |
| mvOsOutput(" Differential Clock Input: Yes \n"); |
| else |
| mvOsOutput(" Differential Clock Input: No \n"); |
| |
| if (dimmInfo.dimmAttributes & BIT6) |
| mvOsOutput(" redundant Row Addressing: Yes \n"); |
| else |
| mvOsOutput(" redundant Row Addressing: No \n"); |
| } else if (dimmInfo.memoryType == MEM_TYPE_DDR1) { |
| if (dimmInfo.dimmAttributes & BIT0) |
| mvOsOutput(" Buffered Addr/Control Input: Yes\n"); |
| else |
| mvOsOutput(" Buffered Addr/Control Input: No\n"); |
| |
| if (dimmInfo.dimmAttributes & BIT1) |
| mvOsOutput(" Registered Addr/Control Input: Yes\n"); |
| else |
| mvOsOutput(" Registered Addr/Control Input: No\n"); |
| |
| if (dimmInfo.dimmAttributes & BIT2) |
| mvOsOutput(" On-Card PLL (clock): Yes \n"); |
| else |
| mvOsOutput(" On-Card PLL (clock): No \n"); |
| |
| if (dimmInfo.dimmAttributes & BIT3) |
| mvOsOutput(" FET Switch On-Card Enabled: Yes \n"); |
| else |
| mvOsOutput(" FET Switch On-Card Enabled: No \n"); |
| |
| if (dimmInfo.dimmAttributes & BIT4) |
| mvOsOutput(" FET Switch External Enabled: Yes \n"); |
| else |
| mvOsOutput(" FET Switch External Enabled: No \n"); |
| |
| if (dimmInfo.dimmAttributes & BIT5) |
| mvOsOutput(" Differential Clock Input: Yes \n"); |
| else |
| mvOsOutput(" Differential Clock Input: No \n"); |
| } else { /* if (dimmInfo.memoryType == MEM_TYPE_DDR2) */ |
| |
| mvOsOutput(" Number of Active Registers on the DIMM: %d\n", |
| (dimmInfo.dimmAttributes & 0x3) + 1); |
| |
| mvOsOutput(" Number of PLLs on the DIMM: %d\n", ((dimmInfo.dimmAttributes) >> 2) & 0x3); |
| |
| if (dimmInfo.dimmAttributes & BIT4) |
| mvOsOutput(" FET Switch External Enabled: Yes \n"); |
| else |
| mvOsOutput(" FET Switch External Enabled: No \n"); |
| |
| if (dimmInfo.dimmAttributes & BIT6) |
| mvOsOutput(" Analysis probe installed: Yes \n"); |
| else |
| mvOsOutput(" Analysis probe installed: No \n"); |
| } |
| |
| break; |
| /*----------------------------------------------------------------------------*/ |
| |
| case 22: /* Suported AutoPreCharge */ |
| mvOsOutput("\nModul Attributes (SPD Byte 22): \n"); |
| if (dimmInfo.memoryType == MEM_TYPE_SDRAM) { |
| if (spdRawData[i] & BIT0) |
| mvOsOutput(" Early Ras Precharge: Yes \n"); |
| else |
| mvOsOutput(" Early Ras Precharge: No \n"); |
| |
| if (spdRawData[i] & BIT1) |
| mvOsOutput(" AutoPreCharge: Yes \n"); |
| else |
| mvOsOutput(" AutoPreCharge: No \n"); |
| |
| if (spdRawData[i] & BIT2) |
| mvOsOutput(" Precharge All: Yes \n"); |
| else |
| mvOsOutput(" Precharge All: No \n"); |
| |
| if (spdRawData[i] & BIT3) |
| mvOsOutput(" Write 1/ReadBurst: Yes \n"); |
| else |
| mvOsOutput(" Write 1/ReadBurst: No \n"); |
| |
| if (spdRawData[i] & BIT4) |
| mvOsOutput(" lower VCC tolerance: 5%%\n"); |
| else |
| mvOsOutput(" lower VCC tolerance: 10%%\n"); |
| |
| if (spdRawData[i] & BIT5) |
| mvOsOutput(" upper VCC tolerance: 5%%\n"); |
| else |
| mvOsOutput(" upper VCC tolerance: 10%%\n"); |
| } else if (dimmInfo.memoryType == MEM_TYPE_DDR1) { |
| if (spdRawData[i] & BIT0) |
| mvOsOutput(" Supports Weak Driver: Yes \n"); |
| else |
| mvOsOutput(" Supports Weak Driver: No \n"); |
| |
| if (!(spdRawData[i] & BIT4)) |
| mvOsOutput(" lower VCC tolerance: 0.2V\n"); |
| |
| if (!(spdRawData[i] & BIT5)) |
| mvOsOutput(" upper VCC tolerance: 0.2V\n"); |
| |
| if (spdRawData[i] & BIT6) |
| mvOsOutput(" Concurrent Auto Preharge: Yes \n"); |
| else |
| mvOsOutput(" Concurrent Auto Preharge: No \n"); |
| |
| if (spdRawData[i] & BIT7) |
| mvOsOutput(" Supports Fast AP: Yes \n"); |
| else |
| mvOsOutput(" Supports Fast AP: No \n"); |
| } else if (dimmInfo.memoryType == MEM_TYPE_DDR2) { |
| if (spdRawData[i] & BIT0) |
| mvOsOutput(" Supports Weak Driver: Yes \n"); |
| else |
| mvOsOutput(" Supports Weak Driver: No \n"); |
| } |
| break; |
| /*----------------------------------------------------------------------------*/ |
| |
| case 23: |
| /* Minimum Cycle Time At Maximum Cas Latancy Minus 1 (2nd highest CL) */ |
| leftOfPoint = (spdRawData[i] & 0xf0) >> 4; |
| rightOfPoint = (spdRawData[i] & 0x0f) * 10; |
| |
| /* DDR2 addition of right of point */ |
| if ((spdRawData[i] & 0x0f) == 0xA) |
| rightOfPoint = 25; |
| if ((spdRawData[i] & 0x0f) == 0xB) |
| rightOfPoint = 33; |
| if ((spdRawData[i] & 0x0f) == 0xC) |
| rightOfPoint = 66; |
| if ((spdRawData[i] & 0x0f) == 0xD) |
| rightOfPoint = 75; |
| |
| mvOsOutput("Minimum Cycle Time At 2nd highest CasLatancy" |
| "(0 = Not supported): %d.%d [ns]\n", leftOfPoint, rightOfPoint); |
| break; |
| /*----------------------------------------------------------------------------*/ |
| |
| case 24: /* Clock To Data Out 2nd highest Cas Latency Value */ |
| div = (dimmInfo.memoryType == MEM_TYPE_SDRAM) ? 10 : 100; |
| time_tmp = (((spdRawData[i] & 0xf0) >> 4) * 10) + ((spdRawData[i] & 0x0f)); |
| leftOfPoint = time_tmp / div; |
| rightOfPoint = time_tmp % div; |
| mvOsOutput("Clock To Data Out (2nd CL value): %d.%d [ns]\n", |
| leftOfPoint, rightOfPoint); |
| break; |
| /*----------------------------------------------------------------------------*/ |
| |
| case 25: |
| /* Minimum Cycle Time At Maximum Cas Latancy Minus 2 (3rd highest CL) */ |
| if (dimmInfo.memoryType == MEM_TYPE_SDRAM) { |
| leftOfPoint = (spdRawData[i] & 0xfc) >> 2; |
| rightOfPoint = (spdRawData[i] & 0x3) * 25; |
| } else { /* DDR1 or DDR2 */ |
| |
| leftOfPoint = (spdRawData[i] & 0xf0) >> 4; |
| rightOfPoint = (spdRawData[i] & 0x0f) * 10; |
| |
| /* DDR2 addition of right of point */ |
| if ((spdRawData[i] & 0x0f) == 0xA) |
| rightOfPoint = 25; |
| if ((spdRawData[i] & 0x0f) == 0xB) |
| rightOfPoint = 33; |
| if ((spdRawData[i] & 0x0f) == 0xC) |
| rightOfPoint = 66; |
| if ((spdRawData[i] & 0x0f) == 0xD) |
| rightOfPoint = 75; |
| } |
| mvOsOutput("Minimum Cycle Time At 3rd highest CasLatancy" |
| "(0 = Not supported): %d.%d [ns]\n", leftOfPoint, rightOfPoint); |
| break; |
| /*----------------------------------------------------------------------------*/ |
| |
| case 26: /* Clock To Data Out 3rd highest Cas Latency Value */ |
| if (dimmInfo.memoryType == MEM_TYPE_SDRAM) { |
| leftOfPoint = (spdRawData[i] & 0xfc) >> 2; |
| rightOfPoint = (spdRawData[i] & 0x3) * 25; |
| } else { /* DDR1 or DDR2 */ |
| |
| time_tmp = (((spdRawData[i] & 0xf0) >> 4) * 10) + ((spdRawData[i] & 0x0f)); |
| leftOfPoint = 0; |
| rightOfPoint = time_tmp; |
| } |
| mvOsOutput("Clock To Data Out (3rd CL value): %d.%2d[ns]\n", |
| leftOfPoint, rightOfPoint); |
| break; |
| /*----------------------------------------------------------------------------*/ |
| |
| case 27: /* Minimum Row Precharge Time */ |
| shift = (dimmInfo.memoryType == MEM_TYPE_SDRAM) ? 0 : 2; |
| maskLeftOfPoint = (dimmInfo.memoryType == MEM_TYPE_SDRAM) ? 0xff : 0xfc; |
| maskRightOfPoint = (dimmInfo.memoryType == MEM_TYPE_SDRAM) ? 0x00 : 0x03; |
| leftOfPoint = ((spdRawData[i] & maskLeftOfPoint) >> shift); |
| rightOfPoint = (spdRawData[i] & maskRightOfPoint) * 25; |
| temp = ((leftOfPoint * 100) + rightOfPoint); /* in 10ps Intervals */ |
| trp_clocks = (temp + (busClkPs - 1)) / busClkPs; |
| mvOsOutput("Minimum Row Precharge Time [ns]: %d.%d = " |
| "in Clk cycles %d\n", leftOfPoint, rightOfPoint, trp_clocks); |
| break; |
| /*----------------------------------------------------------------------------*/ |
| |
| case 28: /* Minimum Row Active to Row Active Time */ |
| shift = (dimmInfo.memoryType == MEM_TYPE_SDRAM) ? 0 : 2; |
| maskLeftOfPoint = (dimmInfo.memoryType == MEM_TYPE_SDRAM) ? 0xff : 0xfc; |
| maskRightOfPoint = (dimmInfo.memoryType == MEM_TYPE_SDRAM) ? 0x00 : 0x03; |
| leftOfPoint = ((spdRawData[i] & maskLeftOfPoint) >> shift); |
| rightOfPoint = (spdRawData[i] & maskRightOfPoint) * 25; |
| temp = ((leftOfPoint * 100) + rightOfPoint); /* in 100ns Interval */ |
| trrd_clocks = (temp + (busClkPs - 1)) / busClkPs; |
| mvOsOutput("Minimum Row Active -To- Row Active Delay [ns]: " |
| "%d.%d = in Clk cycles %d\n", leftOfPoint, rightOfPoint, trp_clocks); |
| break; |
| /*----------------------------------------------------------------------------*/ |
| |
| case 29: /* Minimum Ras-To-Cas Delay */ |
| shift = (dimmInfo.memoryType == MEM_TYPE_SDRAM) ? 0 : 2; |
| maskLeftOfPoint = (dimmInfo.memoryType == MEM_TYPE_SDRAM) ? 0xff : 0xfc; |
| maskRightOfPoint = (dimmInfo.memoryType == MEM_TYPE_SDRAM) ? 0x00 : 0x03; |
| leftOfPoint = ((spdRawData[i] & maskLeftOfPoint) >> shift); |
| rightOfPoint = (spdRawData[i] & maskRightOfPoint) * 25; |
| temp = ((leftOfPoint * 100) + rightOfPoint); /* in 100ns Interval */ |
| trcd_clocks = (temp + (busClkPs - 1)) / busClkPs; |
| mvOsOutput("Minimum Ras-To-Cas Delay [ns]: %d.%d = " |
| "in Clk cycles %d\n", leftOfPoint, rightOfPoint, trp_clocks); |
| break; |
| /*----------------------------------------------------------------------------*/ |
| |
| case 30: /* Minimum Ras Pulse Width */ |
| tras_clocks = (cas2ps(spdRawData[i]) + (busClkPs - 1)) / busClkPs; |
| mvOsOutput("Minimum Ras Pulse Width [ns]: %d = " |
| "in Clk cycles %d\n", spdRawData[i], tras_clocks); |
| break; |
| /*----------------------------------------------------------------------------*/ |
| |
| case 31: /* Module Bank Density */ |
| mvOsOutput("Module Bank Density (more than 1= Multisize-Module):"); |
| |
| if (dimmInfo.memoryType == MEM_TYPE_SDRAM) { |
| if (dimmInfo.dimmBankDensity & BIT0) |
| mvOsOutput("1GB, "); |
| if (dimmInfo.dimmBankDensity & BIT1) |
| mvOsOutput("8MB, "); |
| if (dimmInfo.dimmBankDensity & BIT2) |
| mvOsOutput("16MB, "); |
| if (dimmInfo.dimmBankDensity & BIT3) |
| mvOsOutput("32MB, "); |
| if (dimmInfo.dimmBankDensity & BIT4) |
| mvOsOutput("64MB, "); |
| if (dimmInfo.dimmBankDensity & BIT5) |
| mvOsOutput("128MB, "); |
| if (dimmInfo.dimmBankDensity & BIT6) |
| mvOsOutput("256MB, "); |
| if (dimmInfo.dimmBankDensity & BIT7) |
| mvOsOutput("512MB, "); |
| } else if (dimmInfo.memoryType == MEM_TYPE_DDR1) { |
| if (dimmInfo.dimmBankDensity & BIT0) |
| mvOsOutput("1GB, "); |
| if (dimmInfo.dimmBankDensity & BIT1) |
| mvOsOutput("2GB, "); |
| if (dimmInfo.dimmBankDensity & BIT2) |
| mvOsOutput("16MB, "); |
| if (dimmInfo.dimmBankDensity & BIT3) |
| mvOsOutput("32MB, "); |
| if (dimmInfo.dimmBankDensity & BIT4) |
| mvOsOutput("64MB, "); |
| if (dimmInfo.dimmBankDensity & BIT5) |
| mvOsOutput("128MB, "); |
| if (dimmInfo.dimmBankDensity & BIT6) |
| mvOsOutput("256MB, "); |
| if (dimmInfo.dimmBankDensity & BIT7) |
| mvOsOutput("512MB, "); |
| } else { /* if (dimmInfo.memoryType == MEM_TYPE_DDR2) */ |
| |
| if (dimmInfo.dimmBankDensity & BIT0) |
| mvOsOutput("1GB, "); |
| if (dimmInfo.dimmBankDensity & BIT1) |
| mvOsOutput("2GB, "); |
| if (dimmInfo.dimmBankDensity & BIT2) |
| mvOsOutput("4GB, "); |
| if (dimmInfo.dimmBankDensity & BIT3) |
| mvOsOutput("8GB, "); |
| if (dimmInfo.dimmBankDensity & BIT4) |
| mvOsOutput("16GB, "); |
| if (dimmInfo.dimmBankDensity & BIT5) |
| mvOsOutput("128MB, "); |
| if (dimmInfo.dimmBankDensity & BIT6) |
| mvOsOutput("256MB, "); |
| if (dimmInfo.dimmBankDensity & BIT7) |
| mvOsOutput("512MB, "); |
| } |
| mvOsOutput("\n"); |
| break; |
| /*----------------------------------------------------------------------------*/ |
| |
| case 32: /* Address And Command Setup Time (measured in ns/1000) */ |
| if (dimmInfo.memoryType == MEM_TYPE_SDRAM) { |
| rightOfPoint = (spdRawData[i] & 0x0f); |
| leftOfPoint = (spdRawData[i] & 0xf0) >> 4; |
| if (leftOfPoint > 7) |
| leftOfPoint *= -1; |
| } else { /* DDR1 or DDR2 */ |
| |
| time_tmp = (((spdRawData[i] & 0xf0) >> 4) * 10) + ((spdRawData[i] & 0x0f)); |
| leftOfPoint = time_tmp / 100; |
| rightOfPoint = time_tmp % 100; |
| } |
| mvOsOutput("Address And Command Setup Time [ns]: %d.%d\n", |
| leftOfPoint, rightOfPoint); |
| break; |
| /*----------------------------------------------------------------------------*/ |
| |
| case 33: /* Address And Command Hold Time */ |
| if (dimmInfo.memoryType == MEM_TYPE_SDRAM) { |
| rightOfPoint = (spdRawData[i] & 0x0f); |
| leftOfPoint = (spdRawData[i] & 0xf0) >> 4; |
| if (leftOfPoint > 7) |
| leftOfPoint *= -1; |
| } else { /* DDR1 or DDR2 */ |
| |
| time_tmp = (((spdRawData[i] & 0xf0) >> 4) * 10) + ((spdRawData[i] & 0x0f)); |
| leftOfPoint = time_tmp / 100; |
| rightOfPoint = time_tmp % 100; |
| } |
| mvOsOutput("Address And Command Hold Time [ns]: %d.%d\n", |
| leftOfPoint, rightOfPoint); |
| break; |
| /*----------------------------------------------------------------------------*/ |
| |
| case 34: /* Data Input Setup Time */ |
| if (dimmInfo.memoryType == MEM_TYPE_SDRAM) { |
| rightOfPoint = (spdRawData[i] & 0x0f); |
| leftOfPoint = (spdRawData[i] & 0xf0) >> 4; |
| if (leftOfPoint > 7) |
| leftOfPoint *= -1; |
| } else { /* DDR1 or DDR2 */ |
| |
| time_tmp = (((spdRawData[i] & 0xf0) >> 4) * 10) + ((spdRawData[i] & 0x0f)); |
| leftOfPoint = time_tmp / 100; |
| rightOfPoint = time_tmp % 100; |
| } |
| mvOsOutput("Data Input Setup Time [ns]: %d.%d\n", |
| leftOfPoint, rightOfPoint); |
| break; |
| /*----------------------------------------------------------------------------*/ |
| |
| case 35: /* Data Input Hold Time */ |
| if (dimmInfo.memoryType == MEM_TYPE_SDRAM) { |
| rightOfPoint = (spdRawData[i] & 0x0f); |
| leftOfPoint = (spdRawData[i] & 0xf0) >> 4; |
| if (leftOfPoint > 7) |
| leftOfPoint *= -1; |
| } else { /* DDR1 or DDR2 */ |
| |
| time_tmp = (((spdRawData[i] & 0xf0) >> 4) * 10) + ((spdRawData[i] & 0x0f)); |
| leftOfPoint = time_tmp / 100; |
| rightOfPoint = time_tmp % 100; |
| } |
| mvOsOutput("Data Input Hold Time [ns]: %d.%d\n\n", leftOfPoint, rightOfPoint); |
| break; |
| /*----------------------------------------------------------------------------*/ |
| |
| case 36: /* Relevant for DDR2 only: Write Recovery Time */ |
| leftOfPoint = ((spdRawData[i] & maskLeftOfPoint) >> 2); |
| rightOfPoint = (spdRawData[i] & maskRightOfPoint) * 25; |
| mvOsOutput("Write Recovery Time [ns]: %d.%d\n", leftOfPoint, rightOfPoint); |
| break; |
| /*----------------------------------------------------------------------------*/ |
| } |
| |
| } |
| |
| /* |
| * translate ns.ns/10 coding of SPD timing values |
| * into ps unit values |
| */ |
| /******************************************************************************* |
| * cas2ps - Translate x.y ns parameter to pico-seconds values |
| * |
| * DESCRIPTION: |
| * This function translates x.y nano seconds to its value in pico seconds. |
| * For example 3.75ns will return 3750. |
| * |
| * INPUT: |
| * spd_byte - DIMM SPD byte. |
| * |
| * OUTPUT: |
| * None. |
| * |
| * RETURN: |
| * value in pico seconds. |
| * |
| *******************************************************************************/ |
| static MV_U32 cas2ps(MV_U8 spd_byte) |
| { |
| MV_U32 ns, ns10; |
| |
| /* isolate upper nibble */ |
| ns = (spd_byte >> 4) & 0x0F; |
| /* isolate lower nibble */ |
| ns10 = (spd_byte & 0x0F); |
| |
| if (ns10 < 10) |
| ns10 *= 10; |
| else if (ns10 == 10) |
| ns10 = 25; |
| else if (ns10 == 11) |
| ns10 = 33; |
| else if (ns10 == 12) |
| ns10 = 66; |
| else if (ns10 == 13) |
| ns10 = 75; |
| else |
| mvOsOutput("cas2ps Err. unsupported cycle time.\n"); |
| |
| return (ns * 1000 + ns10 * 10); |
| } |