diff options
author | Reka Norman <rekanorman@google.com> | 2021-09-08 18:50:58 +1000 |
---|---|---|
committer | Felix Held <felix-coreboot@felixheld.de> | 2021-09-17 14:49:22 +0000 |
commit | 0e79274d33ed701d320bd4cc3b7c26b97120557d (patch) | |
tree | aca22f39037a9f973ff1b437ab03a8f19228bfae /util/spd_tools/src/spd_gen/ddr4.go | |
parent | 20795899999bab47ba875b0d2a2c7e0a6ff4effa (diff) |
util/spd_tools: Implement a unified version of the spd_gen tool
Currently there are two versions of spd_tools: one for LP4x and one for
DDR4. This change is the first step in unifying these into a single
tool.
This change implements a unified version of the spd_gen tool, by
combining the functionality currently in lp4x/gen_spd.go and
ddr4/gen_spd.go. The unified version takes the memory technology as an
argument, and generates SPD files for all platforms supporting that
technology.
BUG=b:191776301
TEST=Compare the SPDs generated by the old and new versions of the tool
for all supported platforms. For reference, the test script used is
here: https://review.coreboot.org/c/coreboot/+/57511
Signed-off-by: Reka Norman <rekanorman@google.com>
Change-Id: I7fc036996dbafbb54e075da0c3ac2ea0886a6db2
Reviewed-on: https://review.coreboot.org/c/coreboot/+/57512
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Furquan Shaikh <furquan@google.com>
Reviewed-by: Tim Wawrzynczak <twawrzynczak@chromium.org>
Reviewed-by: Karthik Ramasubramanian <kramasub@google.com>
Reviewed-by: Michael Niewöhner <foss@mniewoehner.de>
Diffstat (limited to 'util/spd_tools/src/spd_gen/ddr4.go')
-rw-r--r-- | util/spd_tools/src/spd_gen/ddr4.go | 1284 |
1 files changed, 1284 insertions, 0 deletions
diff --git a/util/spd_tools/src/spd_gen/ddr4.go b/util/spd_tools/src/spd_gen/ddr4.go new file mode 100644 index 0000000000..ce60038b77 --- /dev/null +++ b/util/spd_tools/src/spd_gen/ddr4.go @@ -0,0 +1,1284 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +package main + +import ( + "encoding/json" + "fmt" + "strconv" + "strings" +) + +/* ------------------------------------------------------------------------------------------ */ +/* DDR4-defined types */ +/* ------------------------------------------------------------------------------------------ */ + +type ddr4 struct { +} + +type DDR4MemAttributes struct { + /* Primary attributes - must be provided by JSON file for each part */ + SpeedMTps int + CL_nRCD_nRP int + CapacityPerDieGb int + DiesPerPackage int + PackageBusWidth int + RanksPerPackage int + + /* + * All the following parameters are optional and required only if the part requires + * special parameters as per the datasheet. + */ + /* Timing parameters */ + TAAMinPs int + TRCDMinPs int + TRPMinPs int + TRASMinPs int + TRCMinPs int + TCKMinPs int + TCKMaxPs int + TRFC1MinPs int + TRFC2MinPs int + TRFC4MinPs int + TFAWMinPs int + TRRDLMinPs int + TRRDSMinPs int + TCCDLMinPs int + TWRMinPs int + TWTRLMinPs int + TWTRSMinPs int + + /* CAS */ + CASLatencies string + CASFirstByte byte + CASSecondByte byte + CASThirdByte byte + CASFourthByte byte + + /* The following is for internal-use only and is not overridable */ + dieBusWidth int +} + +type DDR4SpeedBinAttributes struct { + TRASMinPs int + TCKMaxPs int +} + +type DDR4SPDMemAttribFunc func(*DDR4MemAttributes) byte + +type DDR4SPDAttribTableEntry struct { + constVal byte + getVal DDR4SPDMemAttribFunc +} + +/* ------------------------------------------------------------------------------------------ */ +/* Constants */ +/* ------------------------------------------------------------------------------------------ */ + +const ( + /* SPD Byte Index */ + DDR4SPDIndexSize = 0 + DDR4SPDIndexRevision = 1 + DDR4SPDIndexMemoryType = 2 + DDR4SPDIndexModuleType = 3 + DDR4SPDIndexDensityBanks = 4 + DDR4SPDIndexAddressing = 5 + DDR4SPDIndexPackageType = 6 + DDR4SPDIndexOptionalFeatures = 7 + DDR4SPDIndexModuleOrganization = 12 + DDR4SPDIndexBusWidth = 13 + DDR4SPDIndexTimebases = 17 + DDR4SPDIndexTCKMin = 18 + DDR4SPDIndexTCKMax = 19 + DDR4SPDIndexCASFirstByte = 20 + DDR4SPDIndexCASSecondByte = 21 + DDR4SPDIndexCASThirdByte = 22 + DDR4SPDIndexCASFourthByte = 23 + DDR4SPDIndexTAAMin = 24 + DDR4SPDIndexTRCDMin = 25 + DDR4SPDIndexTRPMin = 26 + DDR4SPDIndexTRASRCMinMSNs = 27 + DDR4SPDIndexTRASMinLsb = 28 + DDR4SPDIndexTRCMinLsb = 29 + DDR4SPDIndexTRFC1MinLsb = 30 + DDR4SPDIndexTRFC1MinMsb = 31 + DDR4SPDIndexTRFC2MinLsb = 32 + DDR4SPDIndexTRFC2MinMsb = 33 + DDR4SPDIndexTRFC4MinLsb = 34 + DDR4SPDIndexTRFC4MinMsb = 35 + DDR4SPDIndexTFAWMinMSN = 36 + DDR4SPDIndexTFAWMinLsb = 37 + DDR4SPDIndexTRRDSMin = 38 + DDR4SPDIndexTRRDLMin = 39 + DDR4SPDIndexTCCDLMin = 40 + DDR4SPDIndexTWRMinMSN = 41 + DDR4SPDIndexTWRMinLsb = 42 + DDR4SPDIndexTWTRMinMSNs = 43 + DDR4SPDIndexWTRSMinLsb = 44 + DDR4SPDIndexWTRLMinLsb = 45 + DDR4SPDIndexTCCDLMinFineOffset = 117 + DDR4SPDIndexTRRDLMinFineOffset = 118 + DDR4SPDIndexTRRDSMinFineOffset = 119 + DDR4SPDIndexTRCMinFineOffset = 120 + DDR4SPDIndexTRPMinFineOffset = 121 + DDR4SPDIndexTRCDMinFineOffset = 122 + DDR4SPDIndexTAAMinFineOffset = 123 + DDR4SPDIndexTCKMaxFineOffset = 124 + DDR4SPDIndexTCKMinFineOffset = 125 + DDR4SPDIndexManufacturerPartNumberStartByte = 329 + DDR4SPDIndexManufacturerPartNumberEndByte = 348 + + /* SPD Byte Value */ + + /* + * From JEDEC spec: + * 6:4 (Bytes total) = 2 (512 bytes) + * 3:0 (Bytes used) = 3 (384 bytes) + * Set to 0x23 for DDR4. + */ + DDR4SPDValueSize = 0x23 + + /* + * From JEDEC spec: Revision 1.1 + * Set to 0x11. + */ + DDR4SPDValueRevision = 0x11 + + /* DDR4 memory type = 0x0C */ + DDR4SPDValueMemoryType = 0x0C + + /* + * From JEDEC spec: + * Module Type [0:3] : + * 0 = Undefined + * 1 = RDIMM (width = 133.35 mm nom) + * 2 = UDIMM (width = 133.35 mm nom) + * 3 = SO-DIMM (width = 68.60 mm nom) + * 4 = LRDIMM (width = 133.35 mm nom) + * + * DDR4 on TGL uses SO-DIMM type for for both memory down and DIMM config. + * Set to 0x03. + */ + DDR4SPDValueModuleType = 0x03 + + /* + * From JEDEC spec: + * 5:4 (Maximum Activate Window) = 00 (8192 * tREFI) + * 3:0 (Maximum Activate Count) = 1000 (Unlimited MAC) + * + * Needs to come from datasheet, but most parts seem to support unlimited MAC. + * MR#24 OP3 + */ + DDR4SPDValueOptionalFeatures = 0x08 + + /* + * From JEDEC spec: + * 2:0 Primary Bus Width in Bits = 011 (x64 always) + * Set to 0x03. + */ + DDR4SPDValueModuleBusWidth = 0x03 + + /* + * From JEDEC spec: + * 3:2 (MTB) = 00 (0.125ns) + * 1:0 (FTB) = 00 (1ps) + * Set to 0x00. + */ + DDR4SPDValueTimebases = 0x00 + + /* CAS fourth byte: All bits are reserved */ + DDR4SPDValueCASFourthByte = 0x00 + + /* As per JEDEC spec, unused digits of manufacturer part number are left as blank. */ + DDR4SPDValueManufacturerPartNumberBlank = 0x20 +) + +const ( + /* First Byte */ + DDR4CAS9 = 1 << 2 + DDR4CAS10 = 1 << 3 + DDR4CAS11 = 1 << 4 + DDR4CAS12 = 1 << 5 + DDR4CAS13 = 1 << 6 + DDR4CAS14 = 1 << 7 + /* Second Byte */ + DDR4CAS15 = 1 << 0 + DDR4CAS16 = 1 << 1 + DDR4CAS17 = 1 << 2 + DDR4CAS18 = 1 << 3 + DDR4CAS19 = 1 << 4 + DDR4CAS20 = 1 << 5 + DDR4CAS21 = 1 << 6 + DDR4CAS22 = 1 << 7 + /* Third Byte */ + DDR4CAS24 = 1 << 1 +) + +const ( + /* + * As per Table 75 of Jedec spec 4.1.20-L-5 R29 v103: + * tWRMin = 15nS for all DDR4 Speed Bins + * Set to 15000 pS + */ + DDR4TimingValueTWRMinPs = 15000 + + /* + * As per Table 78 of Jedec spec 4.1.20-L-5 R29 v103: + * tWTR_SMin = 2.5nS for all DDR4 Speed Bins + * Set to 2500 pS + */ + DDR4TimingValueTWTRSMinPs = 2500 + + /* + * As per Table 80 of Jedec spec 4.1.20-L-5 R29 v103: + * tWTR_LMin = 7.5 nS for all DDR4 Speed Bins + * Set to 7500 pS + */ + DDR4TimingValueTWTRLMinPs = 7500 +) + +/* ------------------------------------------------------------------------------------------ */ +/* Global variables */ +/* ------------------------------------------------------------------------------------------ */ + +var DDR4PlatformSetMap = map[int][]int{ + 0: {PlatformTGL, PlatformPCO, PlatformPLK}, +} + +var DDR4PartAttributeMap = map[string]DDR4MemAttributes{} +var DDR4CurrSet int + +/* This encodes the density in Gb to SPD low nibble value as per JESD 4.1.2.L-5 R29 */ +var DDR4DensityGbToSPDEncoding = map[int]byte{ + 2: 0x3, + 4: 0x4, + 8: 0x5, + 16: 0x6, +} + +/* + * Tables 4 thru Table 7 from JESD79-4C. + * Maps density per die to row-column encoding for a device with x8/x16 + * physical channel. + */ +var DDR4DensityGbx8x16DieCapacityToRowColumnEncoding = map[int]byte{ + 2: 0x11, /* 14 rows, 10 columns */ + 4: 0x19, /* 15 rows, 10 columns */ + 8: 0x21, /* 16 rows, 10 columns */ + 16: 0x29, /* 17 rows, 10 columns */ +} + +/* + * Tables 169 & 170 in the JESD79-4C spec + * Maps die density to refresh timings. This is the same for x8 and x16 + * devices. + */ + +/* maps die density to rcf1 timing in pico seconds */ +var DDR4TRFC1Encoding = map[int]int{ + 2: 160000, + 4: 260000, + 8: 350000, + 16: 550000, +} + +/* maps die density to rcf2 timing in pico seconds */ +var DDR4TRFC2Encoding = map[int]int{ + 2: 110000, + 4: 160000, + 8: 260000, + 16: 350000, +} + +/* maps die density to rcf4 timing in pico seconds */ +var DDR4TRFC4Encoding = map[int]int{ + 2: 90000, + 4: 110000, + 8: 160000, + 16: 260000, +} + +var DDR4SpeedBinToSPDEncoding = map[int]DDR4SpeedBinAttributes{ + 1600: { + TRASMinPs: 35000, + TCKMaxPs: 1500, + }, + 1866: { + TRASMinPs: 34000, + TCKMaxPs: 1250, + }, + 2133: { + TRASMinPs: 33000, + TCKMaxPs: 1071, + }, + 2400: { + TRASMinPs: 32000, + TCKMaxPs: 937, + }, + 2666: { + TRASMinPs: 32000, + TCKMaxPs: 833, + }, + 2933: { + TRASMinPs: 32000, + TCKMaxPs: 750, + }, + 3200: { + TRASMinPs: 32000, + TCKMaxPs: 682, + }, +} + +/* This takes memAttribs.PackageBusWidth as an index */ +var DDR4PageSizefromBusWidthEncoding = map[int]int{ + 8: 1, + 16: 2, +} + +var DDR4SpeedToTRRDSMinPsOneKPageSize = map[int]int{ + 1600: 5000, + 1866: 4200, + 2133: 3700, + 2400: 3300, + 2666: 3000, + 2933: 2700, + 3200: 2500, +} + +var DDR4SpeedToTRRDSMinPsTwoKPageSize = map[int]int{ + 1600: 6000, + 1866: 5300, + 2133: 5300, + 2400: 5300, + 2666: 5300, + 2933: 5300, + 3200: 5300, +} + +var DDR4SPDAttribTable = map[int]DDR4SPDAttribTableEntry{ + DDR4SPDIndexSize: {constVal: DDR4SPDValueSize}, + DDR4SPDIndexRevision: {constVal: DDR4SPDValueRevision}, + DDR4SPDIndexMemoryType: {constVal: DDR4SPDValueMemoryType}, + DDR4SPDIndexModuleType: {constVal: DDR4SPDValueModuleType}, + DDR4SPDIndexDensityBanks: {getVal: DDR4EncodeDensityBanks}, + DDR4SPDIndexAddressing: {getVal: DDR4EncodeSdramAddressing}, + DDR4SPDIndexPackageType: {getVal: DDR4EncodePackageType}, + DDR4SPDIndexOptionalFeatures: {constVal: DDR4SPDValueOptionalFeatures}, + DDR4SPDIndexModuleOrganization: {getVal: DDR4EncodeModuleOrganization}, + DDR4SPDIndexBusWidth: {constVal: DDR4SPDValueModuleBusWidth}, + DDR4SPDIndexTimebases: {constVal: DDR4SPDValueTimebases}, + DDR4SPDIndexTCKMin: {getVal: DDR4EncodeTCKMin}, + DDR4SPDIndexTCKMinFineOffset: {getVal: DDR4EncodeTCKMinFineOffset}, + DDR4SPDIndexTCKMax: {getVal: DDR4EncodeTCKMax}, + DDR4SPDIndexTCKMaxFineOffset: {getVal: DDR4EncodeTCKMaxFineOffset}, + DDR4SPDIndexCASFirstByte: {getVal: DDR4EncodeCASFirstByte}, + DDR4SPDIndexCASSecondByte: {getVal: DDR4EncodeCASSecondByte}, + DDR4SPDIndexCASThirdByte: {getVal: DDR4EncodeCASThirdByte}, + DDR4SPDIndexCASFourthByte: {getVal: DDR4EncodeCASFourthByte}, + DDR4SPDIndexTAAMin: {getVal: DDR4EncodeTAAMin}, + DDR4SPDIndexTAAMinFineOffset: {getVal: DDR4EncodeTAAMinFineOffset}, + DDR4SPDIndexTRCDMin: {getVal: DDR4EncodeTRCDMin}, + DDR4SPDIndexTRCDMinFineOffset: {getVal: DDR4EncodeTRCDMinFineOffset}, + DDR4SPDIndexTRPMin: {getVal: DDR4EncodeTRPMin}, + DDR4SPDIndexTRPMinFineOffset: {getVal: DDR4EncodeTRPMinFineOffset}, + DDR4SPDIndexTRASRCMinMSNs: {getVal: DDR4EncodeTRASRCMinMSNs}, + DDR4SPDIndexTRASMinLsb: {getVal: DDR4EncodeTRASMinLsb}, + DDR4SPDIndexTRCMinLsb: {getVal: DDR4EncodeTRCMinLsb}, + DDR4SPDIndexTRCMinFineOffset: {getVal: DDR4EncodeTRCMinFineOffset}, + DDR4SPDIndexTRFC1MinLsb: {getVal: DDR4EncodeTRFC1MinLsb}, + DDR4SPDIndexTRFC1MinMsb: {getVal: DDR4EncodeTRFC1MinMsb}, + DDR4SPDIndexTRFC2MinLsb: {getVal: DDR4EncodeTRFC2MinLsb}, + DDR4SPDIndexTRFC2MinMsb: {getVal: DDR4EncodeTRFC2MinMsb}, + DDR4SPDIndexTRFC4MinLsb: {getVal: DDR4EncodeTRFC4MinLsb}, + DDR4SPDIndexTRFC4MinMsb: {getVal: DDR4EncodeTRFC4MinMsb}, + DDR4SPDIndexTFAWMinMSN: {getVal: DDR4EncodeTFAWMinMSN}, + DDR4SPDIndexTFAWMinLsb: {getVal: DDR4EncodeTFAWMinLsb}, + DDR4SPDIndexTRRDSMin: {getVal: DDR4EncodeTRRDSMin}, + DDR4SPDIndexTRRDSMinFineOffset: {getVal: DDR4EncodeTRRDSMinFineOffset}, + DDR4SPDIndexTRRDLMin: {getVal: DDR4EncodeTRRDLMin}, + DDR4SPDIndexTRRDLMinFineOffset: {getVal: DDR4EncodeTRRDLMinFineOffset}, + DDR4SPDIndexTCCDLMin: {getVal: DDR4EncodeTCCDLMin}, + DDR4SPDIndexTCCDLMinFineOffset: {getVal: DDR4EncodeTCCDLMinFineOffset}, + DDR4SPDIndexTWRMinMSN: {getVal: DDR4EncodeTWRMinMSN}, + DDR4SPDIndexTWRMinLsb: {getVal: DDR4EncodeTWRMinLsb}, + DDR4SPDIndexTWTRMinMSNs: {getVal: DDR4EncodeTWTRMinMSNs}, + DDR4SPDIndexWTRSMinLsb: {getVal: DDR4EncodeTWTRSMinLsb}, + DDR4SPDIndexWTRLMinLsb: {getVal: DDR4EncodeTWTRLMinLsb}, +} + +/* ------------------------------------------------------------------------------------------ */ +/* Functions */ +/* ------------------------------------------------------------------------------------------ */ + +func DDR4GetBankGroups(memAttribs *DDR4MemAttributes) byte { + var bg byte + + switch memAttribs.PackageBusWidth { + case 8: + bg = 4 + case 16: + if memAttribs.DiesPerPackage == 1 { + bg = 2 /* x16 SDP has 2 bank groups */ + } else { + bg = 4 /* x16 DDP has 4 bank groups */ + } + } + + return bg +} + +func DDR4EncodeBankGroups(bg byte) byte { + var val byte + + switch bg { + case 2: + val = 1 + case 4: + val = 2 + } + + return val << 6 +} + +func DDR4EncodeDensityBanks(memAttribs *DDR4MemAttributes) byte { + var b byte + + b = DDR4DensityGbToSPDEncoding[memAttribs.CapacityPerDieGb] + b |= DDR4EncodeBankGroups(DDR4GetBankGroups(memAttribs)) + /* No need to encode banksPerGroup.it's always 4 ([4:5] = 0) */ + + return b +} + +func DDR4EncodeSdramAddressing(memAttribs *DDR4MemAttributes) byte { + var b byte + + b = DDR4DensityGbx8x16DieCapacityToRowColumnEncoding[memAttribs.CapacityPerDieGb] + + return b +} + +func DDR4EncodePackageDeviceType(dies int) byte { + var b byte + + if dies > 1 { + /* If more than one die, then this is a non-monolithic device. */ + b = 1 + } else { + /* If only single die, then this is a monolithic device. */ + b = 0 + } + + return b << 7 +} + +func DDR4EncodeSignalLoadingFromDieCount(dies int) byte { + var loading byte + + /* + * If die count = 1, signal loading = "not specified" = 0 + * If die count > 1, signal loading = "multi" = 2 + */ + if dies == 1 { + loading = 0 + } else { + loading = 1 + } + + return loading +} + +func DDR4EncodeDiesPerPackage(dies int) byte { + var b byte + + b = DDR4EncodePackageDeviceType(dies) /* Monolithic / Non-monolithic device */ + b |= (byte(dies) - 1) << 4 + + return b +} + +func DDR4EncodePackageType(memAttribs *DDR4MemAttributes) byte { + var b byte + + b = DDR4EncodeDiesPerPackage(memAttribs.DiesPerPackage) + b |= DDR4EncodeSignalLoadingFromDieCount(memAttribs.DiesPerPackage) + + return b +} + +func DDR4EncodeDataWidth(bitWidthPerDevice int) byte { + var width byte + + switch bitWidthPerDevice { + case 8: + width = 1 + case 16: + width = 2 + } + + return width +} + +func DDR4EncodeRanks(ranks int) byte { + var b byte + + b = byte(ranks - 1) + + return b << 3 +} + +func DDR4EncodeModuleOrganization(memAttribs *DDR4MemAttributes) byte { + var b byte + + b = DDR4EncodeDataWidth(memAttribs.dieBusWidth) + b |= DDR4EncodeRanks(memAttribs.RanksPerPackage) + + return b +} + +func DDR4EncodeTCKMin(memAttribs *DDR4MemAttributes) byte { + return convPsToMtbByte(memAttribs.TCKMinPs) +} + +func DDR4EncodeTCKMinFineOffset(memAttribs *DDR4MemAttributes) byte { + return convPsToFtbByte(memAttribs.TCKMinPs) +} + +func DDR4EncodeTCKMax(memAttribs *DDR4MemAttributes) byte { + return convPsToMtbByte(memAttribs.TCKMaxPs) +} + +func DDR4EncodeTCKMaxFineOffset(memAttribs *DDR4MemAttributes) byte { + return convPsToFtbByte(memAttribs.TCKMaxPs) +} + +func DDR4EncodeTAAMin(memAttribs *DDR4MemAttributes) byte { + return convPsToMtbByte(memAttribs.TAAMinPs) +} + +func DDR4EncodeTAAMinFineOffset(memAttribs *DDR4MemAttributes) byte { + return convPsToFtbByte(memAttribs.TAAMinPs) +} + +func DDR4EncodeTRCDMin(memAttribs *DDR4MemAttributes) byte { + return convPsToMtbByte(memAttribs.TRCDMinPs) +} + +func DDR4EncodeTRCDMinFineOffset(memAttribs *DDR4MemAttributes) byte { + return convPsToFtbByte(memAttribs.TRCDMinPs) +} + +func DDR4EncodeTRPMin(memAttribs *DDR4MemAttributes) byte { + return convPsToMtbByte(memAttribs.TRPMinPs) +} + +func DDR4EncodeTRCMinFineOffset(memAttribs *DDR4MemAttributes) byte { + return convPsToFtbByte(memAttribs.TRCMinPs) +} + +func DDR4EncodeTRPMinFineOffset(memAttribs *DDR4MemAttributes) byte { + return convPsToFtbByte(memAttribs.TRPMinPs) +} + +func DDR4EncodeTRASRCMinMSNs(memAttribs *DDR4MemAttributes) byte { + var b byte + + b = byte((convPsToMtb(memAttribs.TRASMinPs) >> 4) & 0xf0) + b |= byte((convPsToMtb(memAttribs.TRCMinPs) >> 8) & 0x0f) + + return b +} + +func DDR4EncodeTRASMinLsb(memAttribs *DDR4MemAttributes) byte { + return byte(convPsToMtb(memAttribs.TRASMinPs) & 0xff) +} + +func DDR4EncodeTRCMinLsb(memAttribs *DDR4MemAttributes) byte { + return byte(convPsToMtb(memAttribs.TRCMinPs) & 0xff) +} + +func DDR4EncodeTRFC1MinLsb(memAttribs *DDR4MemAttributes) byte { + var mtb int + + mtb = convPsToMtb(memAttribs.TRFC1MinPs) + + return byte(mtb & 0xff) +} + +func DDR4EncodeTRFC1MinMsb(memAttribs *DDR4MemAttributes) byte { + var mtb int + + mtb = convPsToMtb(memAttribs.TRFC1MinPs) + + return byte((mtb >> 8) & 0xff) +} + +func DDR4EncodeTRFC2MinLsb(memAttribs *DDR4MemAttributes) byte { + var mtb int + + mtb = convPsToMtb(memAttribs.TRFC2MinPs) + + return byte(mtb & 0xff) +} + +func DDR4EncodeTRFC2MinMsb(memAttribs *DDR4MemAttributes) byte { + var mtb int + + mtb = convPsToMtb(memAttribs.TRFC2MinPs) + + return byte((mtb >> 8) & 0xff) +} + +func DDR4EncodeTRFC4MinLsb(memAttribs *DDR4MemAttributes) byte { + var mtb int + + mtb = convPsToMtb(memAttribs.TRFC4MinPs) + + return byte(mtb & 0xff) +} + +func DDR4EncodeTRFC4MinMsb(memAttribs *DDR4MemAttributes) byte { + var mtb int + + mtb = convPsToMtb(memAttribs.TRFC4MinPs) + + return byte((mtb >> 8) & 0xff) +} + +func DDR4EncodeTFAWMinMSN(memAttribs *DDR4MemAttributes) byte { + var mtb int + + mtb = convPsToMtb(memAttribs.TFAWMinPs) + + return byte((mtb >> 8) & 0x0f) +} + +func DDR4EncodeTFAWMinLsb(memAttribs *DDR4MemAttributes) byte { + var mtb int + + mtb = convPsToMtb(memAttribs.TFAWMinPs) + + return byte(mtb & 0xff) +} + +func DDR4EncodeCASFirstByte(memAttribs *DDR4MemAttributes) byte { + return memAttribs.CASFirstByte +} + +func DDR4EncodeCASSecondByte(memAttribs *DDR4MemAttributes) byte { + return memAttribs.CASSecondByte +} + +func DDR4EncodeCASThirdByte(memAttribs *DDR4MemAttributes) byte { + return memAttribs.CASThirdByte +} + +func DDR4EncodeCASFourthByte(memAttribs *DDR4MemAttributes) byte { + return memAttribs.CASFourthByte +} + +func DDR4EncodeTRRDSMin(memAttribs *DDR4MemAttributes) byte { + return convPsToMtbByte(memAttribs.TRRDSMinPs) +} + +func DDR4EncodeTRRDSMinFineOffset(memAttribs *DDR4MemAttributes) byte { + return convPsToFtbByte(memAttribs.TRRDSMinPs) +} + +func DDR4EncodeTRRDLMin(memAttribs *DDR4MemAttributes) byte { + return convPsToMtbByte(memAttribs.TRRDLMinPs) +} + +func DDR4EncodeTRRDLMinFineOffset(memAttribs *DDR4MemAttributes) byte { + return convPsToFtbByte(memAttribs.TRRDLMinPs) +} + +func DDR4EncodeTCCDLMin(memAttribs *DDR4MemAttributes) byte { + return convPsToMtbByte(memAttribs.TCCDLMinPs) +} + +func DDR4EncodeTCCDLMinFineOffset(memAttribs *DDR4MemAttributes) byte { + return convPsToFtbByte(memAttribs.TCCDLMinPs) +} + +func DDR4EncodeTWRMinMSN(memAttribs *DDR4MemAttributes) byte { + return byte((convPsToMtb(DDR4TimingValueTWRMinPs) >> 8) & 0x0f) +} + +func DDR4EncodeTWRMinLsb(memAttribs *DDR4MemAttributes) byte { + return byte(convPsToMtb(DDR4TimingValueTWRMinPs) & 0xff) +} + +func DDR4EncodeTWTRMinMSNs(memAttribs *DDR4MemAttributes) byte { + var b byte + + b = byte((convPsToMtb(memAttribs.TWTRLMinPs) >> 4) & 0xf0) + b |= byte((convPsToMtb(memAttribs.TWTRSMinPs) >> 8) & 0x0f) + + return b +} + +func DDR4EncodeTWTRSMinLsb(memAttribs *DDR4MemAttributes) byte { + return byte(convPsToMtb(memAttribs.TWTRSMinPs) & 0xff) +} + +func DDR4EncodeTWTRLMinLsb(memAttribs *DDR4MemAttributes) byte { + return byte(convPsToMtb(memAttribs.TWTRLMinPs) & 0xff) +} + +func DDR4EncodeLatencies(latency int, memAttribs *DDR4MemAttributes) error { + switch latency { + case 9: + memAttribs.CASFirstByte |= DDR4CAS9 + case 10: + memAttribs.CASFirstByte |= DDR4CAS10 + case 11: + memAttribs.CASFirstByte |= DDR4CAS11 + case 12: + memAttribs.CASFirstByte |= DDR4CAS12 + case 13: + memAttribs.CASFirstByte |= DDR4CAS13 + case 14: + memAttribs.CASFirstByte |= DDR4CAS14 + case 15: + memAttribs.CASSecondByte |= DDR4CAS15 + case 16: + memAttribs.CASSecondByte |= DDR4CAS16 + case 17: + memAttribs.CASSecondByte |= DDR4CAS17 + case 18: + memAttribs.CASSecondByte |= DDR4CAS18 + case 19: + memAttribs.CASSecondByte |= DDR4CAS19 + case 20: + memAttribs.CASSecondByte |= DDR4CAS20 + case 21: + memAttribs.CASSecondByte |= DDR4CAS21 + case 22: + memAttribs.CASSecondByte |= DDR4CAS22 + case 24: + memAttribs.CASThirdByte |= DDR4CAS24 + default: + fmt.Errorf("Incorrect CAS Latency: ", latency) + } + + return nil +} + +/* Default CAS Latencies from Speed Bin tables in JEDS79-4C */ +func DDR4GetDefaultCASLatencies(memAttribs *DDR4MemAttributes) string { + var str string + + switch memAttribs.SpeedMTps { + case 1600: + switch memAttribs.CL_nRCD_nRP { + case 10: + str = "9 10 11 12" + case 11: + str = "9 11 12" + case 12: + str = "10 12" + } + case 1866: + switch memAttribs.CL_nRCD_nRP { + case 12: + str = "9 10 12 13 14" + case 13: + str = "9 11 12 13 14" + case 14: + str = "10 12 14" + } + case 2133: + switch memAttribs.CL_nRCD_nRP { + case 14: + str = "9 10 12 14 15 16" + case 15: + str = "9 11 12 13 14 15 16" + case 16: + str = "10 12 14 16" + } + case 2400: + switch memAttribs.CL_nRCD_nRP { + case 15: + str = "9 10 12 14 15 16 17 18" + case 16: + str = "9 11 12 13 14 15 16 17 18" + case 17: + str = "10 11 12 13 14 15 16 17 18" + case 18: + str = "10 12 14 16 18" + } + case 2666: + switch memAttribs.CL_nRCD_nRP { + case 17: + str = "9 10 11 12 13 14 15 16 17 18 19 20" + case 18: + str = "9 10 11 12 13 14 15 16 17 18 19 20" + case 19: + str = "10 11 12 13 14 15 16 17 18 19 20" + case 20: + str = "10 12 14 16 18 20" + } + case 2933: + switch memAttribs.CL_nRCD_nRP { + case 19: + str = "9 10 11 12 13 14 15 16 17 18 19 20 21 22" + case 20: + str = "10 11 12 13 14 15 16 17 18 19 20 21 22" + case 21: + str = "10 11 12 13 14 15 16 17 18 19 20 21 22" + case 22: + str = "10 12 14 16 18 20 22" + } + case 3200: + switch memAttribs.CL_nRCD_nRP { + case 20: + str = "9 10 11 12 13 14 15 16 17 18 19 20 21 22 24" + case 22: + str = "10 11 12 13 14 15 16 17 18 19 20 21 22 24" + case 24: + str = "10 12 14 16 18 20 22 24" + } + } + + return str +} + +func DDR4UpdateDieBusWidth(memAttribs *DDR4MemAttributes) { + if memAttribs.PackageBusWidth == 16 && memAttribs.RanksPerPackage == 1 && + memAttribs.DiesPerPackage == 2 { + /* + * If a x16 part has 2 die with single rank, PackageBusWidth + * needs to be converted to match die bus width. + */ + memAttribs.dieBusWidth = 8 + } else { + memAttribs.dieBusWidth = memAttribs.PackageBusWidth + } +} + +func DDR4UpdateCAS(memAttribs *DDR4MemAttributes) error { + if len(memAttribs.CASLatencies) == 0 { + memAttribs.CASLatencies = DDR4GetDefaultCASLatencies(memAttribs) + } + + latencies := strings.Fields(memAttribs.CASLatencies) + for i := 0; i < len(latencies); i++ { + latency, err := strconv.Atoi(latencies[i]) + if err != nil { + return fmt.Errorf("Unable to convert latency ", latencies[i]) + } + if err := DDR4EncodeLatencies(latency, memAttribs); err != nil { + return err + } + } + + return nil +} + +func DDR4GetTAAMinPs(memAttribs *DDR4MemAttributes) int { + return (memAttribs.CL_nRCD_nRP * 2000000) / memAttribs.SpeedMTps +} + +func DDR4UpdateTAAMin(memAttribs *DDR4MemAttributes) { + if memAttribs.TAAMinPs == 0 { + memAttribs.TAAMinPs = DDR4GetTAAMinPs(memAttribs) + } +} + +func DDR4UpdateTRCDMin(memAttribs *DDR4MemAttributes) { + /* tRCDmin is same as tAAmin for all cases */ + if memAttribs.TRCDMinPs == 0 { + memAttribs.TRCDMinPs = DDR4GetTAAMinPs(memAttribs) + } +} + +func DDR4UpdateTRPMin(memAttribs *DDR4MemAttributes) { + /* tRPmin is same as tAAmin for all cases */ + if memAttribs.TRPMinPs == 0 { + memAttribs.TRPMinPs = DDR4GetTAAMinPs(memAttribs) + } +} + +func DDR4UpdateTRASMin(memAttribs *DDR4MemAttributes) { + if memAttribs.TRASMinPs == 0 { + memAttribs.TRASMinPs = DDR4SpeedBinToSPDEncoding[memAttribs.SpeedMTps].TRASMinPs + } +} + +func DDR4GetTRCMinPs(memAttribs *DDR4MemAttributes) int { + return memAttribs.TAAMinPs + memAttribs.TRASMinPs +} + +func DDR4UpdateTRCMin(memAttribs *DDR4MemAttributes) { + if memAttribs.TRCMinPs == 0 { + memAttribs.TRCMinPs = DDR4GetTRCMinPs(memAttribs) + } +} + +func DDR4GetDefaultTCKMinPs(memAttribs *DDR4MemAttributes) int { + /* value 2000000 = 2 * 1000000, where 1000000 is to convert mS to pS */ + return 2000000 / memAttribs.SpeedMTps +} + +func DDR4UpdateTCK(memAttribs *DDR4MemAttributes) { + if memAttribs.TCKMinPs == 0 { + memAttribs.TCKMinPs = DDR4GetDefaultTCKMinPs(memAttribs) + } + if memAttribs.TCKMaxPs == 0 { + memAttribs.TCKMaxPs = DDR4SpeedBinToSPDEncoding[memAttribs.SpeedMTps].TCKMaxPs + } +} + +func DDR4UpdateTWRMin(memAttribs *DDR4MemAttributes) { + if memAttribs.TWRMinPs == 0 { + memAttribs.TWRMinPs = DDR4TimingValueTWRMinPs + } +} + +func DDR4UpdateTWTRMin(memAttribs *DDR4MemAttributes) { + if memAttribs.TWTRLMinPs == 0 { + memAttribs.TWTRLMinPs = DDR4TimingValueTWTRLMinPs + } + if memAttribs.TWTRSMinPs == 0 { + memAttribs.TWTRSMinPs = DDR4TimingValueTWTRSMinPs + } +} + +/* + * Per Table 169 & Table 170 of Jedec JESD79-4C + * tFAW timing is based on : + * Speed bin and page size + */ +func DDR4GetTFAWMinPs(memAttribs *DDR4MemAttributes) int { + var tFAWFixed int + + if DDR4PageSizefromBusWidthEncoding[memAttribs.PackageBusWidth] == 1 { + switch memAttribs.SpeedMTps { + case 1600: + tFAWFixed = 25000 + case 1866: + tFAWFixed = 23000 + default: + tFAWFixed = 21000 + } + } else if DDR4PageSizefromBusWidthEncoding[memAttribs.PackageBusWidth] == 2 { + switch memAttribs.SpeedMTps { + case 1600: + tFAWFixed = 35000 + default: + tFAWFixed = 30000 + } + } + + return tFAWFixed +} + +/* Update settings based on data sheet (json) supplied memory attributes */ + +func DDR4UpdateTFAWMin(memAttribs *DDR4MemAttributes) { + var tFAWFromTck int + + if memAttribs.TFAWMinPs == 0 { + memAttribs.TFAWMinPs = DDR4GetTFAWMinPs(memAttribs) + } + + switch DDR4PageSizefromBusWidthEncoding[memAttribs.PackageBusWidth] { + case 1: + tFAWFromTck = 20 * memAttribs.TCKMinPs + case 2: + tFAWFromTck = 28 * memAttribs.TCKMinPs + } + + if memAttribs.TFAWMinPs < tFAWFromTck { + memAttribs.TFAWMinPs = tFAWFromTck + } +} + +func DDR4UpdateTRFC1Min(memAttribs *DDR4MemAttributes) { + if memAttribs.TRFC1MinPs == 0 { + memAttribs.TRFC1MinPs = DDR4TRFC1Encoding[memAttribs.CapacityPerDieGb] + } +} + +func DDR4UpdateTRFC2Min(memAttribs *DDR4MemAttributes) { + if memAttribs.TRFC2MinPs == 0 { + memAttribs.TRFC2MinPs = DDR4TRFC2Encoding[memAttribs.CapacityPerDieGb] + } +} + +func DDR4UpdateTRFC4Min(memAttribs *DDR4MemAttributes) { + if memAttribs.TRFC4MinPs == 0 { + memAttribs.TRFC4MinPs = DDR4TRFC4Encoding[memAttribs.CapacityPerDieGb] + } +} + +func DDR4GetTRRDLMinPs(memAttribs *DDR4MemAttributes) int { + var tRRDLFixed int + + /* + * Per JESD79-4C Tables 169 & 170, tRRD_L is based on : + * Speed bin and page size + */ + switch DDR4PageSizefromBusWidthEncoding[memAttribs.PackageBusWidth] { + case 1: + switch memAttribs.SpeedMTps { + case 1600: + tRRDLFixed = 6000 + default: + tRRDLFixed = 5300 + } + case 2: + switch memAttribs.SpeedMTps { + case 1600: + tRRDLFixed = 7500 + default: + tRRDLFixed = 6400 + } + } + + return tRRDLFixed +} + +func DDR4UpdateTRRDLMin(memAttribs *DDR4MemAttributes) { + var tRRDLFromTck int + + if memAttribs.TRRDLMinPs == 0 { + memAttribs.TRRDLMinPs = DDR4GetTRRDLMinPs(memAttribs) + } + + tRRDLFromTck = 4 * memAttribs.TCKMinPs + + if memAttribs.TRRDLMinPs < tRRDLFromTck { + memAttribs.TRRDLMinPs = tRRDLFromTck + } +} + +func DDR4GetTRRDSMinPs(memAttribs *DDR4MemAttributes) int { + var tRRDFixed int + + switch DDR4PageSizefromBusWidthEncoding[memAttribs.PackageBusWidth] { + case 1: + tRRDFixed = DDR4SpeedToTRRDSMinPsOneKPageSize[memAttribs.SpeedMTps] + case 2: + tRRDFixed = DDR4SpeedToTRRDSMinPsTwoKPageSize[memAttribs.SpeedMTps] + } + + return tRRDFixed +} + +func DDR4UpdateTRRDSMin(memAttribs *DDR4MemAttributes) { + var tRRDFromTck int + + if memAttribs.TRRDSMinPs == 0 { + memAttribs.TRRDSMinPs = DDR4GetTRRDSMinPs(memAttribs) + } + + tRRDFromTck = 4 * memAttribs.TCKMinPs + + if memAttribs.TRRDSMinPs < tRRDFromTck { + memAttribs.TRRDSMinPs = tRRDFromTck + } +} + +/* + * Per JESD79-4C Tables 169 and 170, + * tCCD_L is based on : + * Speed Bin + */ +func DDR4GetTCCDLMinPs(memAttribs *DDR4MemAttributes) int { + var tCCDLFixed int + + switch memAttribs.SpeedMTps { + case 1600: + tCCDLFixed = 6250 + case 1866: + tCCDLFixed = 5355 + case 2133: + tCCDLFixed = 5355 + default: + tCCDLFixed = 5000 + } + + return tCCDLFixed +} + +func DDR4UpdateTCCDLMin(memAttribs *DDR4MemAttributes) { + var tCCDLFromTck int + + if memAttribs.TCCDLMinPs == 0 { + memAttribs.TCCDLMinPs = DDR4GetTCCDLMinPs(memAttribs) + } + + tCCDLFromTck = 5 * memAttribs.TCKMinPs + + if memAttribs.TCCDLMinPs < tCCDLFromTck { + memAttribs.TCCDLMinPs = tCCDLFromTck + } +} + +func DDR4UpdateMemoryAttributes(memAttribs *DDR4MemAttributes) { + DDR4UpdateDieBusWidth(memAttribs) + DDR4UpdateTCK(memAttribs) + DDR4UpdateTAAMin(memAttribs) + DDR4UpdateTRCDMin(memAttribs) + DDR4UpdateTRPMin(memAttribs) + DDR4UpdateTRASMin(memAttribs) + DDR4UpdateTRCMin(memAttribs) + DDR4UpdateTWRMin(memAttribs) + DDR4UpdateTWTRMin(memAttribs) + DDR4UpdateCAS(memAttribs) + DDR4UpdateTRFC1Min(memAttribs) + DDR4UpdateTRFC2Min(memAttribs) + DDR4UpdateTRFC4Min(memAttribs) + DDR4UpdateTCCDLMin(memAttribs) + DDR4UpdateTRRDSMin(memAttribs) + DDR4UpdateTRRDLMin(memAttribs) + DDR4UpdateTFAWMin(memAttribs) +} + +func DDR4ValidateSpeedMTps(speedBin int) error { + if _, ok := DDR4SpeedBinToSPDEncoding[speedBin]; ok == false { + return fmt.Errorf("Incorrect speed bin: DDR4-%d", speedBin) + } + return nil +} + +func DDR4ValidateCapacityPerDie(capacityPerDieGb int) error { + if _, ok := DDR4DensityGbToSPDEncoding[capacityPerDieGb]; ok == false { + return fmt.Errorf("Incorrect capacity per die: %d", capacityPerDieGb) + } + return nil +} + +func DDR4ValidateDiesPerPackage(dieCount int) error { + if dieCount >= 1 && dieCount <= 2 { + return nil + } + return fmt.Errorf("Incorrect dies per package count: %d", dieCount) +} + +func DDR4ValidatePackageBusWidth(width int) error { + if width != 8 && width != 16 { + return fmt.Errorf("Incorrect device bus width: %d", width) + } + return nil +} + +func DDR4ValidateRanksPerPackage(ranks int) error { + if ranks >= 1 && ranks <= 2 { + return nil + } + return fmt.Errorf("Incorrect package ranks: %d", ranks) +} + +func DDR4ValidateCASLatency(CL int) error { + if CL >= 10 && CL <= 24 && CL != 23 { + return nil + } + return fmt.Errorf("Incorrect CAS latency: %d", CL) +} + +func DDR4VerifySupportedCASLatencies(name string, memAttribs *DDR4MemAttributes) error { + if memAttribs.CASLatencies == DDR4GetDefaultCASLatencies(memAttribs) { + return fmt.Errorf("CASLatencies for %s already matches default,\nPlease remove CASLatencies override line from the %s part attributes in the global part list and regenerate SPD Manifest", name, name) + } + + return nil +} + +func DDR4ValidateMemPartAttributes(name string, memAttribs *DDR4MemAttributes) error { + if err := DDR4ValidateSpeedMTps(memAttribs.SpeedMTps); err != nil { + return err + } + if err := DDR4ValidateCapacityPerDie(memAttribs.CapacityPerDieGb); err != nil { + return err + } + if err := DDR4ValidateDiesPerPackage(memAttribs.DiesPerPackage); err != nil { + return err + } + if err := DDR4ValidatePackageBusWidth(memAttribs.PackageBusWidth); err != nil { + return err + } + if err := DDR4ValidateRanksPerPackage(memAttribs.RanksPerPackage); err != nil { + return err + } + if err := DDR4ValidateCASLatency(memAttribs.CL_nRCD_nRP); err != nil { + return err + } + + /* If CAS Latency was supplied, make sure it doesn't match default value */ + if len(memAttribs.CASLatencies) != 0 { + if err := DDR4VerifySupportedCASLatencies(name, memAttribs); err != nil { + return err + } + } + + return nil +} + +func DDR4IsManufacturerPartNumberByte(index int) bool { + if index >= DDR4SPDIndexManufacturerPartNumberStartByte && index <= DDR4SPDIndexManufacturerPartNumberEndByte { + return true + } + return false +} + +/* ------------------------------------------------------------------------------------------ */ +/* Interface Functions */ +/* ------------------------------------------------------------------------------------------ */ + +func (ddr4) getSetMap() map[int][]int { + return DDR4PlatformSetMap +} + +func (ddr4) addNewPart(name string, attribs interface{}) error { + var ddr4MemAttribs DDR4MemAttributes + eByte, err := json.Marshal(attribs) + if err != nil { + return err + } + + if err := json.Unmarshal(eByte, &ddr4MemAttribs); err != nil { + return err + } + + if err := DDR4ValidateMemPartAttributes(name, &ddr4MemAttribs); err != nil { + return err + } + + DDR4PartAttributeMap[name] = ddr4MemAttribs + return nil +} + +func (ddr4) getSPDAttribs(name string, set int) (interface{}, error) { + ddr4Attributes := DDR4PartAttributeMap[name] + + DDR4CurrSet = set + + DDR4UpdateMemoryAttributes(&ddr4Attributes) + + return ddr4Attributes, nil +} + +func (ddr4) getSPDLen() int { + return 512 +} + +func (ddr4) getSPDByte(index int, attribs interface{}) byte { + e, ok := DDR4SPDAttribTable[index] + if ok == false { + if DDR4IsManufacturerPartNumberByte(index) { + return DDR4SPDValueManufacturerPartNumberBlank + } + return 0x00 + } + + if e.getVal != nil { + var ddr4Attribs DDR4MemAttributes + ddr4Attribs = attribs.(DDR4MemAttributes) + return e.getVal(&ddr4Attribs) + + } + + return e.constVal +} |