2020-08-13 02:02:49 +02:00
/* SPDX-License-Identifier: GPL-2.0-or-later */
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"os"
"path/filepath"
"reflect"
"strconv"
"strings"
2020-08-26 17:56:37 +02:00
"regexp"
2020-08-13 02:02:49 +02:00
)
/ *
* This program generates de - duplicated SPD files for DDR4 memory using the global memory
* part list provided in CSV format . In addition to that , it also generates SPD manifest in CSV
* format that contains entries of type ( DRAM part name , SPD file name ) which provides the SPD
* file name used by a given DRAM part .
*
* It takes as input :
* Pointer to directory where the generated SPD files will be placed .
* JSON file containing a list of memory parts with their attributes as per datasheet .
* /
const (
2020-08-21 01:19:44 +02:00
SPDManifestFileName = "ddr4_spd_manifest.generated.txt"
2020-08-13 02:02:49 +02:00
PlatformTGL = 0
2020-08-14 23:23:05 +02:00
PlatformPCO = 1
PlatformPLK = 2
2020-08-13 02:02:49 +02:00
)
var platformMap = map [ string ] int {
"TGL" : PlatformTGL ,
2020-08-14 23:23:05 +02:00
"PCO" : PlatformPCO ,
"PLK" : PlatformPLK ,
2020-08-13 02:02:49 +02:00
}
var currPlatform int
type memAttributes struct {
/* Primary attributes - must be provided by JSON file for each part */
SpeedMTps int
CL_nRCD_nRP int
CapacityPerDieGb int
DiesPerPackage int
2020-08-27 20:44:38 +02:00
PackageBusWidth int
2020-08-13 02:02:49 +02:00
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
T CKMaxPs 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
2020-08-27 20:44:38 +02:00
/* The following is for internal-use only and is not overridable */
dieBusWidth int
2020-08-13 02:02:49 +02:00
}
/* This encodes the density in Gb to SPD low nibble value as per JESD 4.1.2.L-5 R29 */
var densityGbToSPDEncoding = map [ int ] byte {
2 : 0x3 ,
4 : 0x4 ,
8 : 0x5 ,
16 : 0x6 ,
}
/ *
* Tables 4 thru Table 7 from JESD79 - 4 C .
* Maps density per die to row - column encoding for a device with x8 / x16
* physical channel .
* /
var densityGbx8x16DieCapacityToRowColumnEncoding = 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 - 4 C 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 tRFC1Encoding = map [ int ] int {
2 : 160000 ,
4 : 260000 ,
8 : 350000 ,
16 : 550000 ,
}
/* maps die density to rcf2 timing in pico seconds */
var tRFC2Encoding = map [ int ] int {
2 : 110000 ,
4 : 160000 ,
8 : 260000 ,
16 : 350000 ,
}
/* maps die density to rcf4 timing in pico seconds */
var tRFC4Encoding = map [ int ] int {
2 : 90000 ,
4 : 110000 ,
8 : 160000 ,
16 : 260000 ,
}
func getTRCMinPs ( memAttribs * memAttributes ) int {
return memAttribs . TAAMinPs + memAttribs . TRASMinPs
}
func getDefaultTCKMinPs ( memAttribs * memAttributes ) int {
/* value 2000000 = 2 * 1000000, where 1000000 is to convert mS to pS */
return 2000000 / memAttribs . SpeedMTps
}
type speedBinAttributes struct {
TRASMinPs int
TCKMaxPs int
}
var speedBinToSPDEncoding = map [ int ] speedBinAttributes {
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 ,
} ,
}
func getBankGroups ( memAttribs * memAttributes ) byte {
var bg byte
2020-08-27 20:44:38 +02:00
switch memAttribs . PackageBusWidth {
2020-08-13 02:02:49 +02:00
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 encodeBankGroups ( bg byte ) byte {
var val byte
switch bg {
case 2 :
val = 1
case 4 :
val = 2
}
return val << 6
}
func encodeDensityBanks ( memAttribs * memAttributes ) byte {
var b byte
b = densityGbToSPDEncoding [ memAttribs . CapacityPerDieGb ]
b |= encodeBankGroups ( getBankGroups ( memAttribs ) )
/* No need to encode banksPerGroup.it's always 4 ([4:5] = 0) */
return b
}
func encodeSdramAddressing ( memAttribs * memAttributes ) byte {
var b byte
b = densityGbx8x16DieCapacityToRowColumnEncoding [ memAttribs . CapacityPerDieGb ]
return b
}
func encodePackageDeviceType ( 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 encodeSignalLoadingFromDieCount ( 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 encodeDiesPerPackage ( dies int ) byte {
var b byte
b = encodePackageDeviceType ( dies ) /* Monolithic / Non-monolithic device */
b |= ( byte ( dies ) - 1 ) << 4
return b
}
func encodePackageType ( memAttribs * memAttributes ) byte {
var b byte
b = encodeDiesPerPackage ( memAttribs . DiesPerPackage )
b |= encodeSignalLoadingFromDieCount ( memAttribs . DiesPerPackage )
return b
}
func encodeDataWidth ( bitWidthPerDevice int ) byte {
var width byte
switch bitWidthPerDevice {
case 8 :
width = 1
case 16 :
width = 2
}
return width
}
func encodeRanks ( ranks int ) byte {
var b byte
b = byte ( ranks - 1 )
return b << 3
}
func encodeModuleOrganization ( memAttribs * memAttributes ) byte {
var b byte
2020-08-27 20:44:38 +02:00
b = encodeDataWidth ( memAttribs . dieBusWidth )
2020-08-13 02:02:49 +02:00
b |= encodeRanks ( memAttribs . RanksPerPackage )
return b
}
func encodeTCKMin ( memAttribs * memAttributes ) byte {
return convPsToMtbByte ( memAttribs . TCKMinPs )
}
func encodeTCKMinFineOffset ( memAttribs * memAttributes ) byte {
return convPsToFtbByte ( memAttribs . TCKMinPs )
}
func encodeTCKMax ( memAttribs * memAttributes ) byte {
return convPsToMtbByte ( memAttribs . TCKMaxPs )
}
func encodeTCKMaxFineOffset ( memAttribs * memAttributes ) byte {
return convPsToFtbByte ( memAttribs . TCKMaxPs )
}
func divRoundUp ( dividend int , divisor int ) int {
return ( dividend + divisor - 1 ) / divisor
}
func convNsToPs ( timeNs int ) int {
return timeNs * 1000
}
func convMtbToPs ( mtb int ) int {
return mtb * 125
}
func convPsToMtb ( timePs int ) int {
return divRoundUp ( timePs , 125 )
}
func convPsToMtbByte ( timePs int ) byte {
return byte ( convPsToMtb ( timePs ) & 0xff )
}
func convPsToFtbByte ( timePs int ) byte {
mtb := convPsToMtb ( timePs )
ftb := timePs - convMtbToPs ( mtb )
return byte ( ftb )
}
func encodeTAAMin ( memAttribs * memAttributes ) byte {
return convPsToMtbByte ( memAttribs . TAAMinPs )
}
func encodeTAAMinFineOffset ( memAttribs * memAttributes ) byte {
return convPsToFtbByte ( memAttribs . TAAMinPs )
}
func encodeTRCDMin ( memAttribs * memAttributes ) byte {
return convPsToMtbByte ( memAttribs . TRCDMinPs )
}
func encodeTRCDMinFineOffset ( memAttribs * memAttributes ) byte {
return convPsToFtbByte ( memAttribs . TRCDMinPs )
}
func encodeTRPMin ( memAttribs * memAttributes ) byte {
return convPsToMtbByte ( memAttribs . TRPMinPs )
}
func encodeTRCMinFineOffset ( memAttribs * memAttributes ) byte {
return convPsToFtbByte ( memAttribs . TRCMinPs )
}
func encodeTRPMinFineOffset ( memAttribs * memAttributes ) byte {
return convPsToFtbByte ( memAttribs . TRPMinPs )
}
func encodeTRASRCMinMSNs ( memAttribs * memAttributes ) byte {
var b byte
b = byte ( ( convPsToMtb ( memAttribs . TRASMinPs ) >> 4 ) & 0xf0 )
b |= byte ( ( convPsToMtb ( memAttribs . TRCMinPs ) >> 8 ) & 0x0f )
return b
}
func encodeTRASMinLsb ( memAttribs * memAttributes ) byte {
return byte ( convPsToMtb ( memAttribs . TRASMinPs ) & 0xff )
}
func encodeTRCMinLsb ( memAttribs * memAttributes ) byte {
return byte ( convPsToMtb ( memAttribs . TRCMinPs ) & 0xff )
}
2020-08-27 20:44:38 +02:00
/* This takes memAttribs.PackageBusWidth as an index */
2020-08-13 02:02:49 +02:00
var pageSizefromBusWidthEncoding = map [ int ] int {
8 : 1 ,
16 : 2 ,
}
/ *
2020-08-27 20:44:38 +02:00
* Per Table 169 & Table 170 of Jedec JESD79 - 4 C
2020-08-13 02:02:49 +02:00
* tFAW timing is based on :
* Speed bin and page size
* /
func getTFAWMinPs ( memAttribs * memAttributes ) int {
var tFAWFixed int
2020-08-27 20:44:38 +02:00
if pageSizefromBusWidthEncoding [ memAttribs . PackageBusWidth ] == 1 {
2020-08-13 02:02:49 +02:00
switch memAttribs . SpeedMTps {
case 1600 :
tFAWFixed = 25000
case 1866 :
tFAWFixed = 23000
default :
tFAWFixed = 21000
}
2020-08-27 20:44:38 +02:00
} else if pageSizefromBusWidthEncoding [ memAttribs . PackageBusWidth ] == 2 {
2020-08-13 02:02:49 +02:00
switch memAttribs . SpeedMTps {
case 1600 :
tFAWFixed = 35000
default :
tFAWFixed = 30000
}
}
return tFAWFixed
}
/* Update settings based on data sheet (json) supplied memory attributes */
func updateTFAWMin ( memAttribs * memAttributes ) {
var tFAWFromTck int
if memAttribs . TFAWMinPs == 0 {
memAttribs . TFAWMinPs = getTFAWMinPs ( memAttribs )
}
2020-08-27 20:44:38 +02:00
switch pageSizefromBusWidthEncoding [ memAttribs . PackageBusWidth ] {
2020-08-13 02:02:49 +02:00
case 1 :
tFAWFromTck = 20 * memAttribs . TCKMinPs
case 2 :
tFAWFromTck = 28 * memAttribs . TCKMinPs
}
if memAttribs . TFAWMinPs < tFAWFromTck {
memAttribs . TFAWMinPs = tFAWFromTck
}
}
func updateTRFC1Min ( memAttribs * memAttributes ) {
if memAttribs . TRFC1MinPs == 0 {
memAttribs . TRFC1MinPs = tRFC1Encoding [ memAttribs . CapacityPerDieGb ]
}
}
func updateTRFC2Min ( memAttribs * memAttributes ) {
if memAttribs . TRFC2MinPs == 0 {
memAttribs . TRFC2MinPs = tRFC2Encoding [ memAttribs . CapacityPerDieGb ]
}
}
func updateTRFC4Min ( memAttribs * memAttributes ) {
if memAttribs . TRFC4MinPs == 0 {
memAttribs . TRFC4MinPs = tRFC4Encoding [ memAttribs . CapacityPerDieGb ]
}
}
func getTRRDLMinPs ( memAttribs * memAttributes ) int {
var tRRDLFixed int
/ *
* Per JESD79 - 4 C Tables 169 & 170 , tRRD_L is based on :
* Speed bin and page size
* /
2020-08-27 20:44:38 +02:00
switch pageSizefromBusWidthEncoding [ memAttribs . PackageBusWidth ] {
2020-08-13 02:02:49 +02:00
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 updateTRRDLMin ( memAttribs * memAttributes ) {
var tRRDLFromTck int
if memAttribs . TRRDLMinPs == 0 {
memAttribs . TRRDLMinPs = getTRRDLMinPs ( memAttribs )
}
tRRDLFromTck = 4 * memAttribs . TCKMinPs
if memAttribs . TRRDLMinPs < tRRDLFromTck {
memAttribs . TRRDLMinPs = tRRDLFromTck
}
}
var speedToTRRDSMinPsOneKPageSize = map [ int ] int {
1600 : 5000 ,
1866 : 4200 ,
2133 : 3700 ,
2400 : 3300 ,
2666 : 3000 ,
2933 : 2700 ,
3200 : 2500 ,
}
var speedToTRRDSMinPsTwoKPageSize = map [ int ] int {
1600 : 6000 ,
1866 : 5300 ,
2133 : 5300 ,
2400 : 5300 ,
2666 : 5300 ,
2933 : 5300 ,
3200 : 5300 ,
}
func getTRRDSMinPs ( memAttribs * memAttributes ) int {
var tRRDFixed int
2020-08-27 20:44:38 +02:00
switch pageSizefromBusWidthEncoding [ memAttribs . PackageBusWidth ] {
2020-08-13 02:02:49 +02:00
case 1 :
tRRDFixed = speedToTRRDSMinPsOneKPageSize [ memAttribs . SpeedMTps ]
case 2 :
tRRDFixed = speedToTRRDSMinPsTwoKPageSize [ memAttribs . SpeedMTps ]
}
return tRRDFixed
}
func updateTRRDSMin ( memAttribs * memAttributes ) {
var tRRDFromTck int
if memAttribs . TRRDSMinPs == 0 {
memAttribs . TRRDSMinPs = getTRRDSMinPs ( memAttribs )
}
tRRDFromTck = 4 * memAttribs . TCKMinPs
if memAttribs . TRRDSMinPs < tRRDFromTck {
memAttribs . TRRDSMinPs = tRRDFromTck
}
}
/ *
* Per JESD79 - 4 C Tables 169 and 170 ,
* tCCD_L is based on :
* Speed Bin
* /
func getTCCDLMinPs ( memAttribs * memAttributes ) 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 updateTCCDLMin ( memAttribs * memAttributes ) {
var tCCDLFromTck int
if memAttribs . TCCDLMinPs == 0 {
memAttribs . TCCDLMinPs = getTCCDLMinPs ( memAttribs )
}
tCCDLFromTck = 5 * memAttribs . TCKMinPs
if memAttribs . TCCDLMinPs < tCCDLFromTck {
memAttribs . TCCDLMinPs = tCCDLFromTck
}
}
func encodeTRFC1MinLsb ( memAttribs * memAttributes ) byte {
var mtb int
mtb = convPsToMtb ( memAttribs . TRFC1MinPs )
return byte ( mtb & 0xff )
}
func encodeTRFC1MinMsb ( memAttribs * memAttributes ) byte {
var mtb int
mtb = convPsToMtb ( memAttribs . TRFC1MinPs )
return byte ( ( mtb >> 8 ) & 0xff )
}
func encodeTRFC2MinLsb ( memAttribs * memAttributes ) byte {
var mtb int
mtb = convPsToMtb ( memAttribs . TRFC2MinPs )
return byte ( mtb & 0xff )
}
func encodeTRFC2MinMsb ( memAttribs * memAttributes ) byte {
var mtb int
mtb = convPsToMtb ( memAttribs . TRFC2MinPs )
return byte ( ( mtb >> 8 ) & 0xff )
}
func encodeTRFC4MinLsb ( memAttribs * memAttributes ) byte {
var mtb int
mtb = convPsToMtb ( memAttribs . TRFC4MinPs )
return byte ( mtb & 0xff )
}
func encodeTRFC4MinMsb ( memAttribs * memAttributes ) byte {
var mtb int
mtb = convPsToMtb ( memAttribs . TRFC4MinPs )
return byte ( ( mtb >> 8 ) & 0xff )
}
func encodeTFAWMinMSN ( memAttribs * memAttributes ) byte {
var mtb int
mtb = convPsToMtb ( memAttribs . TFAWMinPs )
return byte ( ( mtb >> 8 ) & 0x0f )
}
func encodeTFAWMinLsb ( memAttribs * memAttributes ) byte {
var mtb int
mtb = convPsToMtb ( memAttribs . TFAWMinPs )
return byte ( mtb & 0xff )
}
func encodeCASFirstByte ( memAttribs * memAttributes ) byte {
return memAttribs . CASFirstByte
}
func encodeCASSecondByte ( memAttribs * memAttributes ) byte {
return memAttribs . CASSecondByte
}
func encodeCASThirdByte ( memAttribs * memAttributes ) byte {
return memAttribs . CASThirdByte
}
func encodeCASFourthByte ( memAttribs * memAttributes ) byte {
return memAttribs . CASFourthByte
}
func encodeTRRDSMin ( memAttribs * memAttributes ) byte {
return convPsToMtbByte ( memAttribs . TRRDSMinPs )
}
func encodeTRRDSMinFineOffset ( memAttribs * memAttributes ) byte {
return convPsToFtbByte ( memAttribs . TRRDSMinPs )
}
func encodeTRRDLMin ( memAttribs * memAttributes ) byte {
return convPsToMtbByte ( memAttribs . TRRDLMinPs )
}
func encodeTRRDLMinFineOffset ( memAttribs * memAttributes ) byte {
return convPsToFtbByte ( memAttribs . TRRDLMinPs )
}
func encodeTCCDLMin ( memAttribs * memAttributes ) byte {
return convPsToMtbByte ( memAttribs . TCCDLMinPs )
}
func encodeTCCDLMinFineOffset ( memAttribs * memAttributes ) byte {
return convPsToFtbByte ( memAttribs . TCCDLMinPs )
}
func encodeTWRMinMSN ( memAttribs * memAttributes ) byte {
return byte ( ( convPsToMtb ( TimingValueTWRMinPs ) >> 8 ) & 0x0f )
}
func encodeTWRMinLsb ( memAttribs * memAttributes ) byte {
return byte ( convPsToMtb ( TimingValueTWRMinPs ) & 0xff )
}
func encodeTWTRMinMSNs ( memAttribs * memAttributes ) byte {
var b byte
b = byte ( ( convPsToMtb ( memAttribs . TWTRLMinPs ) >> 4 ) & 0xf0 )
b |= byte ( ( convPsToMtb ( memAttribs . TWTRSMinPs ) >> 8 ) & 0x0f )
return b
}
func encodeTWTRSMinLsb ( memAttribs * memAttributes ) byte {
return byte ( convPsToMtb ( memAttribs . TWTRSMinPs ) & 0xff )
}
func encodeTWTRLMinLsb ( memAttribs * memAttributes ) byte {
return byte ( convPsToMtb ( memAttribs . TWTRLMinPs ) & 0xff )
}
type SPDMemAttribFunc func ( * memAttributes ) byte
type SPDConvConstFunc func ( ) byte
type SPDAttribTableEntry struct {
constVal byte
getVal SPDMemAttribFunc
}
const (
/* SPD Byte Index */
SPDIndexSize = 0
SPDIndexRevision = 1
SPDIndexMemoryType = 2
SPDIndexModuleType = 3
SPDIndexDensityBanks = 4
SPDIndexAddressing = 5
SPDIndexPackageType = 6
SPDIndexOptionalFeatures = 7
SPDIndexModuleOrganization = 12
SPDIndexBusWidth = 13
SPDIndexTimebases = 17
SPDIndexTCKMin = 18
SPDIndexTCKMax = 19
SPDIndexCASFirstByte = 20
SPDIndexCASSecondByte = 21
SPDIndexCASThirdByte = 22
SPDIndexCASFourthByte = 23
SPDIndexTAAMin = 24
SPDIndexTRCDMin = 25
SPDIndexTRPMin = 26
SPDIndexTRASRCMinMSNs = 27
SPDIndexTRASMinLsb = 28
SPDIndexTRCMinLsb = 29
SPDIndexTRFC1MinLsb = 30
SPDIndexTRFC1MinMsb = 31
SPDIndexTRFC2MinLsb = 32
SPDIndexTRFC2MinMsb = 33
SPDIndexTRFC4MinLsb = 34
SPDIndexTRFC4MinMsb = 35
SPDIndexTFAWMinMSN = 36
SPDIndexTFAWMinLsb = 37
SPDIndexTRRDSMin = 38
SPDIndexTRRDLMin = 39
SPDIndexTCCDLMin = 40
SPDIndexTWRMinMSN = 41
SPDIndexTWRMinLsb = 42
SPDIndexTWTRMinMSNs = 43
SPDIndexWTRSMinLsb = 44
SPDIndexWTRLMinLsb = 45
SPDIndexTCCDLMinFineOffset = 117
SPDIndexTRRDLMinFineOffset = 118
SPDIndexTRRDSMinFineOffset = 119
SPDIndexTRCMinFineOffset = 120
SPDIndexTRPMinFineOffset = 121
SPDIndexTRCDMinFineOffset = 122
SPDIndexTAAMinFineOffset = 123
SPDIndexTCKMaxFineOffset = 124
SPDIndexTCKMinFineOffset = 125
SPDIndexManufacturerPartNumberStartByte = 329
SPDIndexManufacturerPartNumberEndByte = 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 .
* /
SPDValueSize = 0x23
/ *
* From JEDEC spec : Revision 1.1
* Set to 0x11 .
* /
SPDValueRevision = 0x11
/* DDR4 memory type = 0x0C */
SPDValueMemoryType = 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 .
* /
SPDValueModuleType = 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
* /
SPDValueOptionalFeatures = 0x08
/ *
* From JEDEC spec :
* 2 : 0 Primary Bus Width in Bits = 011 ( x64 always )
* Set to 0x03 .
* /
SPDValueModuleBusWidth = 0x03
/ *
* From JEDEC spec :
* 3 : 2 ( MTB ) = 00 ( 0.125 ns )
* 1 : 0 ( FTB ) = 00 ( 1 ps )
* Set to 0x00 .
* /
SPDValueTimebases = 0x00
/* CAS fourth byte: All bits are reserved */
SPDValueCASFourthByte = 0x00
/* As per JEDEC spec, unused digits of manufacturer part number are left as blank. */
SPDValueManufacturerPartNumberBlank = 0x20
)
const (
/ *
* As per Table 75 of Jedec spec 4.1 .20 - L - 5 R29 v103 :
* tWRMin = 15 nS for all DDR4 Speed Bins
* Set to 15000 pS
* /
TimingValueTWRMinPs = 15000
/ *
* As per Table 78 of Jedec spec 4.1 .20 - L - 5 R29 v103 :
* tWTR_SMin = 2.5 nS for all DDR4 Speed Bins
* Set to 2500 pS
* /
TimingValueTWTRSMinPs = 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
* /
TimingValueTWTRLMinPs = 7500
)
var SPDAttribTable = map [ int ] SPDAttribTableEntry {
SPDIndexSize : { constVal : SPDValueSize } ,
SPDIndexRevision : { constVal : SPDValueRevision } ,
SPDIndexMemoryType : { constVal : SPDValueMemoryType } ,
SPDIndexModuleType : { constVal : SPDValueModuleType } ,
SPDIndexDensityBanks : { getVal : encodeDensityBanks } ,
SPDIndexAddressing : { getVal : encodeSdramAddressing } ,
SPDIndexPackageType : { getVal : encodePackageType } ,
SPDIndexOptionalFeatures : { constVal : SPDValueOptionalFeatures } ,
SPDIndexModuleOrganization : { getVal : encodeModuleOrganization } ,
SPDIndexBusWidth : { constVal : SPDValueModuleBusWidth } ,
SPDIndexTimebases : { constVal : SPDValueTimebases } ,
SPDIndexTCKMin : { getVal : encodeTCKMin } ,
SPDIndexTCKMinFineOffset : { getVal : encodeTCKMinFineOffset } ,
SPDIndexTCKMax : { getVal : encodeTCKMax } ,
SPDIndexTCKMaxFineOffset : { getVal : encodeTCKMaxFineOffset } ,
SPDIndexCASFirstByte : { getVal : encodeCASFirstByte } ,
SPDIndexCASSecondByte : { getVal : encodeCASSecondByte } ,
SPDIndexCASThirdByte : { getVal : encodeCASThirdByte } ,
SPDIndexCASFourthByte : { getVal : encodeCASFourthByte } ,
SPDIndexTAAMin : { getVal : encodeTAAMin } ,
SPDIndexTAAMinFineOffset : { getVal : encodeTAAMinFineOffset } ,
SPDIndexTRCDMin : { getVal : encodeTRCDMin } ,
SPDIndexTRCDMinFineOffset : { getVal : encodeTRCDMinFineOffset } ,
SPDIndexTRPMin : { getVal : encodeTRPMin } ,
SPDIndexTRPMinFineOffset : { getVal : encodeTRPMinFineOffset } ,
SPDIndexTRASRCMinMSNs : { getVal : encodeTRASRCMinMSNs } ,
SPDIndexTRASMinLsb : { getVal : encodeTRASMinLsb } ,
SPDIndexTRCMinLsb : { getVal : encodeTRCMinLsb } ,
SPDIndexTRCMinFineOffset : { getVal : encodeTRCMinFineOffset } ,
SPDIndexTRFC1MinLsb : { getVal : encodeTRFC1MinLsb } ,
SPDIndexTRFC1MinMsb : { getVal : encodeTRFC1MinMsb } ,
SPDIndexTRFC2MinLsb : { getVal : encodeTRFC2MinLsb } ,
SPDIndexTRFC2MinMsb : { getVal : encodeTRFC2MinMsb } ,
SPDIndexTRFC4MinLsb : { getVal : encodeTRFC4MinLsb } ,
SPDIndexTRFC4MinMsb : { getVal : encodeTRFC4MinMsb } ,
SPDIndexTFAWMinMSN : { getVal : encodeTFAWMinMSN } ,
SPDIndexTFAWMinLsb : { getVal : encodeTFAWMinLsb } ,
SPDIndexTRRDSMin : { getVal : encodeTRRDSMin } ,
SPDIndexTRRDSMinFineOffset : { getVal : encodeTRRDSMinFineOffset } ,
SPDIndexTRRDLMin : { getVal : encodeTRRDLMin } ,
SPDIndexTRRDLMinFineOffset : { getVal : encodeTRRDLMinFineOffset } ,
SPDIndexTCCDLMin : { getVal : encodeTCCDLMin } ,
SPDIndexTCCDLMinFineOffset : { getVal : encodeTCCDLMinFineOffset } ,
SPDIndexTWRMinMSN : { getVal : encodeTWRMinMSN } ,
SPDIndexTWRMinLsb : { getVal : encodeTWRMinLsb } ,
SPDIndexTWTRMinMSNs : { getVal : encodeTWTRMinMSNs } ,
SPDIndexWTRSMinLsb : { getVal : encodeTWTRSMinLsb } ,
SPDIndexWTRLMinLsb : { getVal : encodeTWTRLMinLsb } ,
}
type memParts struct {
MemParts [ ] memPart ` json:"parts" `
}
type memPart struct {
Name string
Attribs memAttributes
SPDFileName string
}
func writeSPDManifest ( memParts * memParts , SPDDirName string ) error {
var s string
fmt . Printf ( "Generating SPD Manifest with following entries:\n" )
for i := 0 ; i < len ( memParts . MemParts ) ; i ++ {
fmt . Printf ( "%-40s %s\n" , memParts . MemParts [ i ] . Name , memParts . MemParts [ i ] . SPDFileName )
s += fmt . Sprintf ( "%s,%s\n" , memParts . MemParts [ i ] . Name , memParts . MemParts [ i ] . SPDFileName )
}
return ioutil . WriteFile ( filepath . Join ( SPDDirName , SPDManifestFileName ) , [ ] byte ( s ) , 0644 )
}
func isManufacturerPartNumberByte ( index int ) bool {
if index >= SPDIndexManufacturerPartNumberStartByte && index <= SPDIndexManufacturerPartNumberEndByte {
return true
}
return false
}
func getSPDByte ( index int , memAttribs * memAttributes ) byte {
e , ok := SPDAttribTable [ index ]
if ok == false {
if isManufacturerPartNumberByte ( index ) {
return SPDValueManufacturerPartNumberBlank
}
return 0x00
}
if e . getVal != nil {
return e . getVal ( memAttribs )
}
return e . constVal
}
2020-10-02 16:51:46 +02:00
func createSPD ( memAttribs * memAttributes ) string {
var s string
2020-08-13 02:02:49 +02:00
for i := 0 ; i < 512 ; i ++ {
2020-08-14 17:40:04 +02:00
var b byte = 0
if memAttribs != nil {
b = getSPDByte ( i , memAttribs )
}
2020-08-13 02:02:49 +02:00
2020-10-02 16:51:46 +02:00
if ( i + 1 ) % 16 == 0 {
s += fmt . Sprintf ( "%02X\n" , b )
} else {
s += fmt . Sprintf ( "%02X " , b )
}
2020-08-13 02:02:49 +02:00
}
2020-10-02 16:51:46 +02:00
return s
2020-08-13 02:02:49 +02:00
}
func dedupeMemoryPart ( dedupedParts [ ] * memPart , memPart * memPart ) bool {
for i := 0 ; i < len ( dedupedParts ) ; i ++ {
if reflect . DeepEqual ( dedupedParts [ i ] . Attribs , memPart . Attribs ) {
memPart . SPDFileName = dedupedParts [ i ] . SPDFileName
return true
}
}
return false
}
func generateSPD ( memPart * memPart , SPDId int , SPDDirName string ) {
2020-10-02 16:51:46 +02:00
s := createSPD ( & memPart . Attribs )
memPart . SPDFileName = fmt . Sprintf ( "ddr4-spd-%d.hex" , SPDId )
ioutil . WriteFile ( filepath . Join ( SPDDirName , memPart . SPDFileName ) , [ ] byte ( s ) , 0644 )
2020-08-13 02:02:49 +02:00
}
2020-08-14 17:40:04 +02:00
func generateEmptySPD ( SPDDirName string ) {
2020-10-02 16:51:46 +02:00
s := createSPD ( nil )
SPDFileName := "ddr4-spd-empty.hex"
ioutil . WriteFile ( filepath . Join ( SPDDirName , SPDFileName ) , [ ] byte ( s ) , 0644 )
2020-08-14 17:40:04 +02:00
}
2020-08-13 02:02:49 +02:00
func readMemoryParts ( memParts * memParts , memPartsFileName string ) error {
databytes , err := ioutil . ReadFile ( memPartsFileName )
if err != nil {
return err
}
2020-08-26 17:56:37 +02:00
// Strip comments from json file
re := regexp . MustCompile ( ` (?m)^\s*//.* ` )
databytes = re . ReplaceAll ( databytes , [ ] byte ( "" ) )
2020-08-13 02:02:49 +02:00
return json . Unmarshal ( databytes , memParts )
}
func validateSpeedMTps ( speedBin int ) error {
if _ , ok := speedBinToSPDEncoding [ speedBin ] ; ok == false {
return fmt . Errorf ( "Incorrect speed bin: DDR4-" , speedBin )
}
return nil
}
func validateCapacityPerDie ( capacityPerDieGb int ) error {
if _ , ok := densityGbToSPDEncoding [ capacityPerDieGb ] ; ok == false {
return fmt . Errorf ( "Incorrect capacity per die: " , capacityPerDieGb )
}
return nil
}
func validateDiesPerPackage ( dieCount int ) error {
if dieCount >= 1 && dieCount <= 2 {
return nil
}
return fmt . Errorf ( "Incorrect dies per package count: " , dieCount )
}
2020-08-27 20:44:38 +02:00
func validatePackageBusWidth ( width int ) error {
2020-08-13 02:02:49 +02:00
if width != 8 && width != 16 {
return fmt . Errorf ( "Incorrect device bus width: " , width )
}
return nil
}
func validateRanksPerPackage ( ranks int ) error {
if ranks >= 1 && ranks <= 2 {
return nil
}
return fmt . Errorf ( "Incorrect package ranks: " , ranks )
}
func validateCASLatency ( CL int ) error {
if CL >= 10 && CL <= 24 && CL != 23 {
return nil
}
return fmt . Errorf ( "Incorrect CAS latency: " , CL )
}
/ *
1 ) validate memory parts
2 ) remove any fields that Intel does not care about
* /
/* verify the supplied CAS Latencies supported does not match default */
func verifySupportedCASLatencies ( part * memPart ) error {
if part . Attribs . CASLatencies == getDefaultCASLatencies ( & part . Attribs ) {
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" , part . Name , part . Name )
}
return nil
}
func validateMemoryParts ( memParts * memParts ) error {
2020-08-14 23:25:33 +02:00
memPartExists := make ( map [ string ] bool )
2020-08-13 02:02:49 +02:00
for i := 0 ; i < len ( memParts . MemParts ) ; i ++ {
2020-08-14 23:25:33 +02:00
if memPartExists [ memParts . MemParts [ i ] . Name ] {
return fmt . Errorf ( memParts . MemParts [ i ] . Name + " is duplicated in mem_parts_list_json" )
}
memPartExists [ memParts . MemParts [ i ] . Name ] = true
2020-08-13 02:02:49 +02:00
if err := validateSpeedMTps ( memParts . MemParts [ i ] . Attribs . SpeedMTps ) ; err != nil {
return err
}
if err := validateCapacityPerDie ( memParts . MemParts [ i ] . Attribs . CapacityPerDieGb ) ; err != nil {
return err
}
if err := validateDiesPerPackage ( memParts . MemParts [ i ] . Attribs . DiesPerPackage ) ; err != nil {
return err
}
2020-08-27 20:44:38 +02:00
if err := validatePackageBusWidth ( memParts . MemParts [ i ] . Attribs . PackageBusWidth ) ; err != nil {
2020-08-13 02:02:49 +02:00
return err
}
if err := validateRanksPerPackage ( memParts . MemParts [ i ] . Attribs . RanksPerPackage ) ; err != nil {
return err
}
if err := validateCASLatency ( memParts . MemParts [ i ] . Attribs . CL_nRCD_nRP ) ; err != nil {
return err
}
/* If CAS Latency was supplied, make sure it doesn't match default value */
if len ( memParts . MemParts [ i ] . Attribs . CASLatencies ) != 0 {
if err := verifySupportedCASLatencies ( & memParts . MemParts [ i ] ) ; err != nil {
return err
}
}
}
return nil
}
const (
/* First Byte */
CAS9 = 1 << 2
CAS10 = 1 << 3
CAS11 = 1 << 4
CAS12 = 1 << 5
CAS13 = 1 << 6
CAS14 = 1 << 7
/* Second Byte */
CAS15 = 1 << 0
CAS16 = 1 << 1
CAS17 = 1 << 2
CAS18 = 1 << 3
CAS19 = 1 << 4
CAS20 = 1 << 5
CAS21 = 1 << 6
CAS22 = 1 << 7
/* Third Byte */
CAS24 = 1 << 1
)
func encodeLatencies ( latency int , memAttribs * memAttributes ) error {
switch latency {
case 9 :
memAttribs . CASFirstByte |= CAS9
case 10 :
memAttribs . CASFirstByte |= CAS10
case 11 :
memAttribs . CASFirstByte |= CAS11
case 12 :
memAttribs . CASFirstByte |= CAS12
case 13 :
memAttribs . CASFirstByte |= CAS13
case 14 :
memAttribs . CASFirstByte |= CAS14
case 15 :
memAttribs . CASSecondByte |= CAS15
case 16 :
memAttribs . CASSecondByte |= CAS16
case 17 :
memAttribs . CASSecondByte |= CAS17
case 18 :
memAttribs . CASSecondByte |= CAS18
case 19 :
memAttribs . CASSecondByte |= CAS19
case 20 :
memAttribs . CASSecondByte |= CAS20
case 21 :
memAttribs . CASSecondByte |= CAS21
case 22 :
memAttribs . CASSecondByte |= CAS22
case 24 :
memAttribs . CASThirdByte |= CAS24
default :
fmt . Errorf ( "Incorrect CAS Latency: " , latency )
}
return nil
}
/* Default CAS Latencies from Speed Bin tables in JEDS79-4C */
func getDefaultCASLatencies ( memAttribs * memAttributes ) 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
}
2020-08-27 20:44:38 +02:00
func updateDieBusWidth ( memAttribs * memAttributes ) {
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
}
}
2020-08-13 02:02:49 +02:00
func updateCAS ( memAttribs * memAttributes ) error {
if len ( memAttribs . CASLatencies ) == 0 {
memAttribs . CASLatencies = getDefaultCASLatencies ( 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 := encodeLatencies ( latency , memAttribs ) ; err != nil {
return err
}
}
return nil
}
func getTAAMinPs ( memAttribs * memAttributes ) int {
return ( memAttribs . CL_nRCD_nRP * 2000000 ) / memAttribs . SpeedMTps
}
func updateTAAMin ( memAttribs * memAttributes ) {
if memAttribs . TAAMinPs == 0 {
memAttribs . TAAMinPs = getTAAMinPs ( memAttribs )
}
}
func updateTRCDMin ( memAttribs * memAttributes ) {
/* tRCDmin is same as tAAmin for all cases */
if memAttribs . TRCDMinPs == 0 {
memAttribs . TRCDMinPs = getTAAMinPs ( memAttribs )
}
}
func updateTRPMin ( memAttribs * memAttributes ) {
/* tRPmin is same as tAAmin for all cases */
if memAttribs . TRPMinPs == 0 {
memAttribs . TRPMinPs = getTAAMinPs ( memAttribs )
}
}
func updateTRASMin ( memAttribs * memAttributes ) {
if memAttribs . TRASMinPs == 0 {
memAttribs . TRASMinPs = speedBinToSPDEncoding [ memAttribs . SpeedMTps ] . TRASMinPs
}
}
func updateTRCMin ( memAttribs * memAttributes ) {
if memAttribs . TRCMinPs == 0 {
memAttribs . TRCMinPs = getTRCMinPs ( memAttribs )
}
}
func updateTCK ( memAttribs * memAttributes ) {
if memAttribs . TCKMinPs == 0 {
memAttribs . TCKMinPs = getDefaultTCKMinPs ( memAttribs )
}
if memAttribs . TCKMaxPs == 0 {
memAttribs . TCKMaxPs = speedBinToSPDEncoding [ memAttribs . SpeedMTps ] . TCKMaxPs
}
}
func updateTWRMin ( memAttribs * memAttributes ) {
if memAttribs . TWRMinPs == 0 {
memAttribs . TWRMinPs = TimingValueTWRMinPs
}
}
func updateTWTRMin ( memAttribs * memAttributes ) {
if memAttribs . TWTRLMinPs == 0 {
memAttribs . TWTRLMinPs = TimingValueTWTRLMinPs
}
if memAttribs . TWTRSMinPs == 0 {
memAttribs . TWTRSMinPs = TimingValueTWTRSMinPs
}
}
func updateMemoryAttributes ( memAttribs * memAttributes ) {
2020-08-27 20:44:38 +02:00
updateDieBusWidth ( memAttribs )
2020-08-13 02:02:49 +02:00
updateTCK ( memAttribs )
updateTAAMin ( memAttribs )
updateTRCDMin ( memAttribs )
updateTRPMin ( memAttribs )
updateTRASMin ( memAttribs )
updateTRCMin ( memAttribs )
updateTWRMin ( memAttribs )
updateTWTRMin ( memAttribs )
updateCAS ( memAttribs )
updateTRFC1Min ( memAttribs )
updateTRFC2Min ( memAttribs )
updateTRFC4Min ( memAttribs )
updateTCCDLMin ( memAttribs )
updateTRRDSMin ( memAttribs )
updateTRRDLMin ( memAttribs )
updateTFAWMin ( memAttribs )
}
func isPlatformSupported ( platform string ) error {
var ok bool
currPlatform , ok = platformMap [ platform ]
if ok == false {
return fmt . Errorf ( "Unsupported platform: " , platform )
}
return nil
}
func usage ( ) {
fmt . Printf ( "\nUsage: %s <spd_dir> <mem_parts_list_json> <platform>\n\n" , os . Args [ 0 ] )
fmt . Printf ( " where,\n" )
fmt . Printf ( " spd_dir = Directory path containing SPD files and manifest generated by gen_spd.go\n" )
fmt . Printf ( " mem_parts_list_json = JSON File containing list of memory parts and attributes\n" )
fmt . Printf ( " platform = SoC Platform for which the SPDs are being generated\n\n\n" )
}
func main ( ) {
if len ( os . Args ) != 4 {
usage ( )
log . Fatal ( "Incorrect number of arguments" )
}
var memParts memParts
var dedupedParts [ ] * memPart
SPDDir , GlobalMemPartsFile , Platform := os . Args [ 1 ] , os . Args [ 2 ] , strings . ToUpper ( os . Args [ 3 ] )
if err := isPlatformSupported ( Platform ) ; err != nil {
log . Fatal ( err )
}
if err := readMemoryParts ( & memParts , GlobalMemPartsFile ) ; err != nil {
log . Fatal ( err )
}
if err := validateMemoryParts ( & memParts ) ; err != nil {
log . Fatal ( err )
}
SPDId := 1
for i := 0 ; i < len ( memParts . MemParts ) ; i ++ {
updateMemoryAttributes ( & memParts . MemParts [ i ] . Attribs )
if dedupeMemoryPart ( dedupedParts , & memParts . MemParts [ i ] ) == false {
generateSPD ( & memParts . MemParts [ i ] , SPDId , SPDDir )
SPDId ++
dedupedParts = append ( dedupedParts , & memParts . MemParts [ i ] )
}
}
2020-08-14 17:40:04 +02:00
generateEmptySPD ( SPDDir )
2020-08-13 02:02:49 +02:00
if err := writeSPDManifest ( & memParts , SPDDir ) ; err != nil {
log . Fatal ( err )
}
}