diff options
Diffstat (limited to 'util')
-rw-r--r-- | util/spd_tools/ddr4/README.md | 294 | ||||
-rw-r--r-- | util/spd_tools/ddr4/gen_part_id.go | 308 | ||||
-rw-r--r-- | util/spd_tools/ddr4/gen_spd.go | 1428 | ||||
-rw-r--r-- | util/spd_tools/ddr4/global_ddr4_mem_parts.json.txt | 254 | ||||
-rw-r--r-- | util/spd_tools/description.md | 11 | ||||
-rw-r--r-- | util/spd_tools/lp4x/README.md | 266 | ||||
-rw-r--r-- | util/spd_tools/lp4x/gen_part_id.go | 214 | ||||
-rw-r--r-- | util/spd_tools/lp4x/gen_spd.go | 996 | ||||
-rw-r--r-- | util/spd_tools/lp4x/global_lp4x_mem_parts.json.txt | 344 |
9 files changed, 0 insertions, 4115 deletions
diff --git a/util/spd_tools/ddr4/README.md b/util/spd_tools/ddr4/README.md deleted file mode 100644 index 75275441a2..0000000000 --- a/util/spd_tools/ddr4/README.md +++ /dev/null @@ -1,294 +0,0 @@ -# DDR4 SPD tools README - -Tools for generating SPD files for DDR4 memory used in platforms with -memory down configuration. These tools generate SPDs following JESD79-4C -and Jedec 4.1.2.L-5 R29 v103 specifications. - -There are two tools provided that assist with generating SPDs and Makefiles -to integrate in coreboot build. These tools can also be used to allocate -DRAM IDs (configure DRAM hardware straps) for any DDR4 memory part used -by the board. - -* gen_spd.go: Generates de-duplicated SPD files using a global memory - part list provided by the mainboard in JSON format. Additionally, - generates a SPD manifest file(in CSV format) with information about - what memory part from the global list uses which of the generated - SPD files. - -* gen_part_id.go: Allocates DRAM strap IDs for different DDR4 - memory parts used by the board. Takes as input a list of memory parts - used (in CSV format) by the board with optional fixed ids and the SPD - manifest file generated by gen_spd.go. Generates Makefile.inc for - integrating the generated SPD files in the coreboot build. - -## Tool 1 - gen_spd.go - -This program takes as input: -* Pointer to directory where the generated SPD files and manifest will - be placed. -* JSON file containing a global list of memory parts with their - attributes as per the datasheet. This is the list of all known - DDR4 memory parts irrespective of their usage on the board. -* SoC platform name for which the SPDs are being generated. Currently - supported platform names are `TGL`, `PCO` and `PLK`. - -Input JSON file requires the following two fields for every memory part: -* `name`: Name of the memory part -* `attribs`: List of attributes of the memory part as per its - datasheet. These attributes match the part specifications and are - independent of any SoC expectations. Tool takes care of translating - the physical attributes of the memory part to match JEDEC and Intel - MRC expectations. - -`attribs` field further contains two types of sub-fields: -* Mandatory: These attributes have to be provided for a memory part. -* Optional: These attributes can be provided by memory part if it wants - to override the defaults. - -### Mandatory `attribs` - -* `speedMTps`: Maximum rate supported by the part in MT/s. Valid values: - `1600, 1866, 2133, 2400, 2666, 2933, 3200` MT/s. - -* `CL_nRCD_nRP`: Refers to CAS Latency specified for the part (find - "CL-nRCD-nRP" in the vendor spec for the DDR4 part). - -* `capacityPerDieGb`: Capacity per die in gigabits. Valid values: - `2, 4, 8, 16` Gb part. - -* `diesPerPackage`: Number of dies on the part. Valid values: - `1, 2` dies per package. - -* `packageBusWidth`: Number of bits of the device's address bus. Valid values: - `8, 16` bit-wide bus. NOTE: Width of x4 is not supported by this tool. - -* `ranksPerPackage`: From Jedec doc 4_01_02_AnnexL-1R23: - “Package ranks per DIMM” refers to the collections of devices on the module - sharing common chip select signals (across the data width of the DIMM), - either from the edge connector for unbuffered modules or from the outputs of - a registering clock driver for RDIMMs and LRDIMMs.Number of bits of the - device's address bus. Valid values: - `1, 2` package ranks. - -### Optional `attribs` - -The following options are calculated by the tool based on the mandatory -attributes described for the part, but there may be cases where a default value -must be overridden, such as when a device appears to be 3200AA, but does not -support all of the CAS latencies typically supported by a speed bin 3200AA part. -Do deal with such a case, the variable can be overridden here and the tool will -use this value instead of calculating one. All values must be defined in -picosecond units, except for "CASLatencies", which would be represented as a -string like "9 10 11 12 14". - - * `TAAMinPs`: Defines the minimum CAS Latency. - Table 48 of Jedec doc 4_01_02_AnnexL-5R29 lists tAAmin for each speed grade. - - * `TRASMinPs`: Refers to the minimum active to precharge delay time. - Table 55 of Jedec doc 4_01_02_AnnexL-5R29 lists tRPmin for each speed grade. - - * `TCKMinPs`: Refers to the minimum clock cycle time. - Table 42 of Jedec doc 4_01_02_AnnexL-5R29 lists tCKmin for each speed grade. - - * `TCKMaxPs`:Refers to the minimum clock cycle time. - Table 44 of Jedec doc 4_01_02_AnnexL-5R29 lists tCKmin for each speed grade. - - * `TRFC1MinPs`: Refers to the minimum refresh recovery delay time. - Table 59 of Jedec doc 4_01_02_AnnexL-5R29 lists tRFC1min for each page size. - - * `TRFC2MinPs`: Refers to the minimum refresh recovery delay time. - Table 61 of Jedec doc 4_01_02_AnnexL-5R29 lists tRFC2min for each page size. - - * `TRFC4MinPs`: Refers to the minimum refresh recovery delay time. - Table 63 of Jedec doc 4_01_02_AnnexL-5R29 lists tRFC4min for each page size. - - * `TFAWMinPs`:: Refers to the minimum four activate window delay time. - Table 66 of Jedec doc 4_01_02_AnnexL-5R29 lists tFAWmin for each speed grade - and page size combination. - - * `TRRDSMinPs`: Refers to the minimum activate to activate delay time to - different bank groups. - Table 68 of Jedec doc 4_01_02_AnnexL-5R29 lists tRRD_Smin for each speed grade - and page size combination. - - * `TRRDLMinPs`: Refers to the minimum activate to activate delay time to the - same bank group. - Table 70 of Jedec doc 4_01_02_AnnexL-5R29 lists tRRD_Lmin for each speed grade - and page size combination. - - * `TCCDLMinPs`: Refers to the minimum CAS to CAS delay time to same bank group. - Table 72 of Jedec doc 4_01_02_AnnexL-5R29 lists tCCD_Lmin for each speed grade. - - * `TWRMinPs`: Refers to the minimum write recovery time. - Table 75 of Jedec doc 4_01_02_AnnexL-5R29 lists tWRmin for each ddr4 type. - - * `TWTRSMinPs`: Refers to minimum write to read time to different bank group. - Table 78 of Jedec doc 4_01_02_AnnexL-5R29 lists tWTR_Smin for each ddr4 type. - - * `TWTRLMinPs`: Refers to minimum write to read time to same bank group. - Table 80 of Jedec doc 4_01_02_AnnexL-5R29 lists tWTR_Lmin for each ddr4 type. - - * `CASLatencies`: Refers to the CAS latencies supported by the part. - The speed bin tables in the back of Jedec doc 4_01_02_AnnexL-5R29 define the - standard CAS latencies that a speed bin part is supposed to support. - In cases where a part does not support all of the CAS latencies listed in the - speed bin tables, this entry should be used to override the default settings. - -### Example JSON file -``` -{ - "parts": [ - { - "name": "MEMORY_PART_A", - "attribs": { - "speedMTps": 3200, - "CL_nRCD_nRP": 22 - "capacityPerDieGb": 8, - "diesPerPackage": 2, - "packageBusWidth": 16, - "ranksPerPackage": 1, - } - }, - { - "name": "MEMORY_PART_B", - "attribs": { - "speedMTps": 3200, - "CL_nRCD_nRP": 22 - "capacityPerDieGb": 8, - "diesPerPackage": 1, - "packageBusWidth": 16, - "ranksPerPackage": 2, - "casLatencies": "9 10 11 12 13 14 15 16 17 18 19 20", - "tCKMaxPs": "1250" - } - } - ] -} -``` - -### Output - -This tool generates the following files using the global list of -memory parts in JSON format as described above: - * De-duplicated SPDs required for the different memory parts. These - SPD files are named (ddr4-spd-1.hex, ddr4-spd-2.hex, and so on) - and placed in the directory provided as an input to the tool. - * CSV file representing which of the deduplicated SPD files is used - by which memory part. This file is named as - `ddr4_spd_manifest.generated.txt` and placed in the directory provided - as an input to the tool along with the generated SPD - files. Example CSV file: - ``` - MEMORY_PART_A, ddr4-spd-1.hex - MEMORY_PART_B, ddr4-spd-2.hex - MEMORY_PART_C, ddr4-spd-3.hex - MEMORY_PART_D, ddr4-spd-2.hex - MEMORY_PART_E, ddr4-spd-2.hex - ``` - -## Tool 2 - gen_part_id.go - -This program takes as input: -* Pointer to directory where the SPD files and the manifest file - `ddr4_spd_manifest.generated.txt` (in CSV format) are placed by - gen_spd.go -* CSV file containing list of memory parts used by the board and optional - fixed id. Each line of the file is supposed to contain one memory part `name` - as present in the global list of memory parts provided to gen_spd.go. - Optionally a fixed id may also be assigned to the part if required. - NOTE: Only assign a fixed ID if required for legacy reasons. - -* Pointer to directory where the generated Makefile.inc should be - placed by the tool. - -Sample input (mem_parts_used_file.txt): -``` -K4AAG165WA-BCWE,1 -MT40A512M16TB-062E:J -MT40A1G16KD-062E:E -K4A8G165WC-BCWE -H5AN8G6NDJR-XNC,8 -H5ANAG6NCMR-XNC -``` -NOTE: This will ensure SPDs compatible with K4AAG165WA-BCWE and H5AN8G6NDJR-XNC -are assigned to ID 1 and 8 respectively. All other memory parts will be -assigned to the first compatible ID. Assigning fixed IDs may result in -duplicate SPD entries or gaps in the ID mapping. - -### Output - -This program provides the following: - -* Prints out the list of DRAM hardware strap IDs that should be - allocated to each memory part listed in the input file. -* Makefile.inc is generated in the provided directory to integrate - SPDs generated by gen_spd.go with the coreboot build for the board. -* dram_id.generated.txt is generated in the same directory as - Makefile. This contains the part IDs assigned to the different - memory parts. (Useful to integrate in board schematics). - -Sample output (dram_id.generated.txt): -``` -DRAM Part Name ID to assign -MEMORY_PART_A 0 (0000) -MEMORY_PART_B 1 (0001) -MEMORY_PART_C 2 (0010) -MEMORY_PART_D 1 (0001) -``` - -Sample Makefile.inc: -``` -## SPDX-License-Identifier: GPL-2.0-or-later -## This is an auto-generated file. Do not edit!! - -SPD_SOURCES = -SPD_SOURCES += ddr4-spd-1.hex # ID = 0(0b0000) Parts = MEMORY_PART_A -SPD_SOURCES += ddr4-spd-2.hex # ID = 1(0b0001) Parts = MEMORY_PART_B, MEMORY_PART_D -SPD_SOURCES += ddr4-spd-empty.hex # ID = 2(0b0010) -SPD_SOURCES += ddr4-spd-3.hex # ID = 2(0b0010) Parts = MEMORY_PART_C -``` -NOTE: Empty entries may be required if there is a gap created by a memory part -with a fixed id. - -### Note of caution - -This program assigns DRAM IDs using the order of DRAM part names -provided in the input file. Thus, when adding a new memory part to the -list, it should always go to the end of the input text file. This -guarantees that the memory parts that were already assigned IDs do not -change. - -## How to build the tools? -``` -# go build gen_spd.go -# go build gen_part_id.go -``` - -## How to use the tools? -``` -# ./gen_spd <spd_dir> <mem_parts_list_json> <platform> -# ./gen_part_id <spd_dir> <makefile_dir> <mem_parts_used_file> -``` - -## Example Usage -``` -# ./gen_spd ../../../../src/soc/intel/tigerlake/spd/ddr4 ./global_ddr4_mem_parts.json.txt 'TGL' - -``` - -### Need to add a new memory part for a board? - -* If the memory part is not present in the global list of memory - parts, then add the memory part name and attributes as per the - datasheet to the file containing the global list. - * Use `gen_spd.go` with input as the file containing the global list - of memory parts to generate de-duplicated SPDs. - * If a new SPD file is generated, use `git add` to add it to the - tree and push a CL for review. -* Update the file containing memory parts used by board (variant) to - add the new memory part name at the end of the file. - * Use gen_part_id.go providing it pointer to the location where SPD - files are stored and file containing the list of memory parts used - by the board(variant). - * Use `git add` to add `Makefile.inc` and `dram_id.generated.txt` - with updated changes and push a CL for review. diff --git a/util/spd_tools/ddr4/gen_part_id.go b/util/spd_tools/ddr4/gen_part_id.go deleted file mode 100644 index 110b9b23bc..0000000000 --- a/util/spd_tools/ddr4/gen_part_id.go +++ /dev/null @@ -1,308 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -package main - -import ( - "encoding/csv" - "fmt" - "io" - "io/ioutil" - "log" - "os" - "path/filepath" - "strconv" -) - -/* - * This program allocates DRAM strap IDs for different parts that are being used by the variant. - * - * It expects the following inputs: - * Pointer to SPD directory. This is the location where SPD files and SPD Manifest generated by - * gen_spd.go are placed. - * Pointer to Makefile directory. Makefile.inc generated by this program is placed in this - * location. - * Text file containing a list of memory parts names used by the board. Each line in the file - * is expected to have one memory part name. - */ -const ( - SPDManifestFileName = "ddr4_spd_manifest.generated.txt" - MakefileName = "Makefile.inc" - DRAMIdFileName = "dram_id.generated.txt" - MaxMemoryId = 15 -) - -func usage() { - fmt.Printf("\nUsage: %s <spd_dir> <makefile_dir> <mem_parts_used_file>\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(" makefile_dir = Directory path where generated Makefile.inc should be placed\n") - fmt.Printf(" mem_parts_used_file = CSV file containing list of memory parts used by the board and optional fixed ids\n\n\n") -} - -func checkArgs() error { - - for _, arg := range os.Args[1:] { - if _, err := os.Stat(arg); err != nil { - return err - } - } - - return nil -} - -type usedPart struct { - partName string - index int -} - -/* - * Read input file CSV that contains list of memory part names used by the variant - * and an optional assigned id. - */ -func readParts(memPartsUsedFileName string) ([]usedPart, error) { - - f, err := os.Open(memPartsUsedFileName) - if err != nil { - return nil, err - } - defer f.Close() - r := csv.NewReader(f) - r.FieldsPerRecord = -1 // Allow variable length records - r.TrimLeadingSpace = true - r.Comment = '#' - - parts := []usedPart{} - - for { - fields, err := r.Read() - - if err == io.EOF { - break - } - - if err != nil { - return nil, err - } - - if len(fields) == 1 { - parts = append(parts, usedPart{fields[0], -1}) - } else if len(fields) == 2 { - assignedId, err := strconv.Atoi(fields[1]) - if err != nil { - return nil, err - } - if assignedId > MaxMemoryId || assignedId < 0 { - return nil, fmt.Errorf("Out of bounds assigned id %d for part %s", assignedId, fields[0]) - } - parts = append(parts, usedPart{fields[0], assignedId}) - } else { - return nil, fmt.Errorf("mem_parts_used_file file is incorrectly formatted") - } - } - - return parts, nil -} - -/* - * Read SPD manifest file(CSV) generated by gen_spd program and generate two maps: - * 1. Part to SPD Map : This maps global memory part name to generated SPD file name - * 2. SPD to Index Map: This generates a map of deduplicated SPD file names to index assigned to - * that SPD. This function sets index for all SPDs to -1. This index gets - * updated as part of genPartIdInfo() depending upon the SPDs actually used - * by the variant. - */ -func readSPDManifest(SPDDirName string) (map[string]string, map[string]int, error) { - f, err := os.Open(filepath.Join(SPDDirName, SPDManifestFileName)) - if err != nil { - return nil, nil, err - } - defer f.Close() - r := csv.NewReader(f) - - partToSPDMap := make(map[string]string) - SPDToIndexMap := make(map[string]int) - - for { - fields, err := r.Read() - - if err == io.EOF { - break - } - - if err != nil { - return nil, nil, err - } - - if len(fields) != 2 { - return nil, nil, fmt.Errorf("CSV file is incorrectly formatted") - } - - partToSPDMap[fields[0]] = fields[1] - SPDToIndexMap[fields[1]] = -1 - } - - return partToSPDMap, SPDToIndexMap, nil -} - -/* Print information about memory part used by variant and ID assigned to it. */ -func appendPartIdInfo(s *string, partName string, index int) { - *s += fmt.Sprintf("%-30s %d (%04b)\n", partName, index, int64(index)) -} - -type partIds struct { - SPDFileName string - memParts string -} - -/* - * For each part used by variant, check if the SPD (as per the manifest) already has an ID - * assigned to it. If yes, then add the part name to the list of memory parts supported by the - * SPD entry. If not, then assign the next ID to the SPD file and add the part name to the - * list of memory parts supported by the SPD entry. - * - * Returns list of partIds that contains spdFileName and supported memory parts for each - * assigned ID. - */ -func genPartIdInfo(parts []usedPart, partToSPDMap map[string]string, SPDToIndexMap map[string]int, makefileDirName string) ([]partIds, error) { - - partIdList := []partIds{} - var s string - - // Assign parts with fixed ids first - for _, p := range parts { - - if p.index == -1 { - continue - } - - if p.partName == "" { - return nil, fmt.Errorf("Invalid part entry") - } - - SPDFileName, ok := partToSPDMap[p.partName] - if !ok { - return nil, fmt.Errorf("Failed to find part ", p.partName, " in SPD Manifest. Please add the part to global part list and regenerate SPD Manifest") - } - - // Extend partIdList with empty entries if needed - for i := len(partIdList) - 1; i < p.index; i++ { - partIdList = append(partIdList, partIds{}) - } - - if partIdList[p.index].SPDFileName != "" { - return nil, fmt.Errorf("Part ", p.partName, " is assigned to an already assigned ID ", p.index) - } - - partIdList[p.index] = partIds{SPDFileName: SPDFileName, memParts: p.partName} - - // SPDToIndexMap should point to first assigned index in the used part list - if SPDToIndexMap[SPDFileName] < 0 { - SPDToIndexMap[SPDFileName] = p.index - } - } - - s += fmt.Sprintf("%-30s %s\n", "DRAM Part Name", "ID to assign") - - // Assign parts with no fixed id - for _, p := range parts { - if p.partName == "" { - return nil, fmt.Errorf("Invalid part entry") - } - - // Add assigned parts to dram id file in the order they appear - if p.index != -1 { - appendPartIdInfo(&s, p.partName, p.index) - continue - } - - SPDFileName, ok := partToSPDMap[p.partName] - if !ok { - return nil, fmt.Errorf("Failed to find part ", p.partName, " in SPD Manifest. Please add the part to global part list and regenerate SPD Manifest") - } - - index := SPDToIndexMap[SPDFileName] - if index != -1 { - partIdList[index].memParts += ", " + p.partName - appendPartIdInfo(&s, p.partName, index) - continue - } - - // Find first empty index - for i, partId := range partIdList { - if partId.SPDFileName == "" { - index = i - break - } - } - - // Append new entry - if index == -1 { - index = len(partIdList) - partIdList = append(partIdList, partIds{}) - } - - SPDToIndexMap[SPDFileName] = index - appendPartIdInfo(&s, p.partName, index) - partIdList[index] = partIds{SPDFileName: SPDFileName, memParts: p.partName} - } - - fmt.Printf("%s", s) - err := ioutil.WriteFile(filepath.Join(makefileDirName, DRAMIdFileName), []byte(s), 0644) - - return partIdList, err -} - -var generatedCodeLicense string = "## SPDX-License-Identifier: GPL-2.0-or-later" -var autoGeneratedInfo string = "## This is an auto-generated file. Do not edit!!" - -/* - * This function generates Makefile.inc under the variant directory path and adds assigned SPDs - * to SPD_SOURCES. - */ -func genMakefile(partIdList []partIds, makefileDirName string) error { - var s string - - s += fmt.Sprintf("%s\n%s\n\n", generatedCodeLicense, autoGeneratedInfo) - s += fmt.Sprintf("SPD_SOURCES =\n") - - for i := 0; i < len(partIdList); i++ { - if partIdList[i].SPDFileName == "" { - s += fmt.Sprintf("SPD_SOURCES += %s ", "ddr4-spd-empty.hex") - s += fmt.Sprintf(" # ID = %d(0b%04b)\n", i, int64(i)) - } else { - s += fmt.Sprintf("SPD_SOURCES += %s ", partIdList[i].SPDFileName) - s += fmt.Sprintf(" # ID = %d(0b%04b) ", i, int64(i)) - s += fmt.Sprintf(" Parts = %04s\n", partIdList[i].memParts) - } - } - - return ioutil.WriteFile(filepath.Join(makefileDirName, MakefileName), []byte(s), 0644) -} - -func main() { - if len(os.Args) != 4 { - usage() - log.Fatal("Incorrect number of arguments") - } - - SPDDir, MakefileDir, MemPartsUsedFile := os.Args[1], os.Args[2], os.Args[3] - - partToSPDMap, SPDToIndexMap, err := readSPDManifest(SPDDir) - if err != nil { - log.Fatal(err) - } - - parts, err := readParts(MemPartsUsedFile) - if err != nil { - log.Fatal(err) - } - - partIdList, err := genPartIdInfo(parts, partToSPDMap, SPDToIndexMap, MakefileDir) - if err != nil { - log.Fatal(err) - } - - if err := genMakefile(partIdList, MakefileDir); err != nil { - log.Fatal(err) - } -} diff --git a/util/spd_tools/ddr4/gen_spd.go b/util/spd_tools/ddr4/gen_spd.go deleted file mode 100644 index eaa56a793c..0000000000 --- a/util/spd_tools/ddr4/gen_spd.go +++ /dev/null @@ -1,1428 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -package main - -import ( - "encoding/json" - "fmt" - "io/ioutil" - "log" - "os" - "path/filepath" - "reflect" - "regexp" - "strconv" - "strings" -) - -/* - * 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 ( - SPDManifestFileName = "ddr4_spd_manifest.generated.txt" - - PlatformTGL = 0 - PlatformPCO = 1 - PlatformPLK = 2 -) - -var platformMap = map[string]int{ - "TGL": PlatformTGL, - "PCO": PlatformPCO, - "PLK": PlatformPLK, -} - -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 - 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 -} - -/* 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-4C. - * 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-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 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 - - 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 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 - - b = encodeDataWidth(memAttribs.dieBusWidth) - 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) -} - -/* This takes memAttribs.PackageBusWidth as an index */ -var pageSizefromBusWidthEncoding = map[int]int{ - 8: 1, - 16: 2, -} - -/* - * Per Table 169 & Table 170 of Jedec JESD79-4C - * tFAW timing is based on : - * Speed bin and page size - */ -func getTFAWMinPs(memAttribs *memAttributes) int { - var tFAWFixed int - - if pageSizefromBusWidthEncoding[memAttribs.PackageBusWidth] == 1 { - switch memAttribs.SpeedMTps { - case 1600: - tFAWFixed = 25000 - case 1866: - tFAWFixed = 23000 - default: - tFAWFixed = 21000 - } - } else if pageSizefromBusWidthEncoding[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 updateTFAWMin(memAttribs *memAttributes) { - var tFAWFromTck int - - if memAttribs.TFAWMinPs == 0 { - memAttribs.TFAWMinPs = getTFAWMinPs(memAttribs) - } - - switch pageSizefromBusWidthEncoding[memAttribs.PackageBusWidth] { - 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-4C Tables 169 & 170, tRRD_L is based on : - * Speed bin and page size - */ - switch pageSizefromBusWidthEncoding[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 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 - - switch pageSizefromBusWidthEncoding[memAttribs.PackageBusWidth] { - 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-4C 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.125ns) - * 1:0 (FTB) = 00 (1ps) - * 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 = 15nS 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.5nS 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 -} - -func createSPD(memAttribs *memAttributes) string { - var s string - - for i := 0; i < 512; i++ { - var b byte = 0 - if memAttribs != nil { - b = getSPDByte(i, memAttribs) - } - - if (i+1)%16 == 0 { - s += fmt.Sprintf("%02X\n", b) - } else { - s += fmt.Sprintf("%02X ", b) - } - } - - return s -} - -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) { - s := createSPD(&memPart.Attribs) - memPart.SPDFileName = fmt.Sprintf("ddr4-spd-%d.hex", SPDId) - ioutil.WriteFile(filepath.Join(SPDDirName, memPart.SPDFileName), []byte(s), 0644) -} - -func generateEmptySPD(SPDDirName string) { - - s := createSPD(nil) - SPDFileName := "ddr4-spd-empty.hex" - ioutil.WriteFile(filepath.Join(SPDDirName, SPDFileName), []byte(s), 0644) -} - -func readMemoryParts(memParts *memParts, memPartsFileName string) error { - databytes, err := ioutil.ReadFile(memPartsFileName) - if err != nil { - return err - } - - // Strip comments from json file - re := regexp.MustCompile(`(?m)^\s*//.*`) - databytes = re.ReplaceAll(databytes, []byte("")) - - 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) -} - -func validatePackageBusWidth(width int) error { - 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 { - memPartExists := make(map[string]bool) - - for i := 0; i < len(memParts.MemParts); i++ { - 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 - - 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 - } - if err := validatePackageBusWidth(memParts.MemParts[i].Attribs.PackageBusWidth); err != nil { - 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 -} - -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 - } -} - -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) { - updateDieBusWidth(memAttribs) - 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]) - } - } - - generateEmptySPD(SPDDir) - - if err := writeSPDManifest(&memParts, SPDDir); err != nil { - log.Fatal(err) - } -} diff --git a/util/spd_tools/ddr4/global_ddr4_mem_parts.json.txt b/util/spd_tools/ddr4/global_ddr4_mem_parts.json.txt deleted file mode 100644 index 66be6a9daf..0000000000 --- a/util/spd_tools/ddr4/global_ddr4_mem_parts.json.txt +++ /dev/null @@ -1,254 +0,0 @@ -// Global list of ddr4 memory part attributes. -// These attributes match the part specifications and are independent -// of any SoC expectations. -{ - "parts": [ - { - "name": "H5AN8G6NDJR-XNC", - "attribs": { - "speedMTps": 3200, - "CL_nRCD_nRP": 22, - "capacityPerDieGb": 8, - "diesPerPackage": 1, - "packageBusWidth": 16, - "ranksPerPackage": 1 - } - }, - { - "name": "MT40A512M16TB-062E:J", - "attribs": { - "speedMTps": 3200, - "CL_nRCD_nRP": 22, - "capacityPerDieGb": 8, - "diesPerPackage": 1, - "packageBusWidth": 16, - "ranksPerPackage": 1 - } - }, - { - "name": "H5ANAG6NCMR-XNC", - "attribs": { - "speedMTps": 3200, - "CL_nRCD_nRP": 22, - "capacityPerDieGb": 8, - "diesPerPackage": 2, - "packageBusWidth": 16, - "ranksPerPackage": 1 - } - }, - { - // Datasheet Revision: Rev. 1.1 / Sep.2017 - "name": "HMA851S6CJR6N-VK", - "attribs": { - "speedMTps": 2666, - "CL_nRCD_nRP": 19, - "capacityPerDieGb": 8, - "diesPerPackage": 1, - "packageBusWidth": 16, - "ranksPerPackage": 1 - } - }, - { - // Datasheet Revision: Rev. 1.5, Apr. 2017 - "name": "K4A8G165WC-BCTD", - "attribs": { - "speedMTps": 2666, - "CL_nRCD_nRP": 19, - "capacityPerDieGb": 8, - "diesPerPackage": 1, - "packageBusWidth": 16, - "ranksPerPackage": 1 - } - }, - { - // Datasheet Revision: Rev. 1.3 / Jun.2018 - "name": "H5AN8G6NCJR-VKC", - "attribs": { - "speedMTps": 2666, - "CL_nRCD_nRP": 19, - "capacityPerDieGb": 8, - "diesPerPackage": 1, - "packageBusWidth": 16, - "ranksPerPackage": 1 - } - }, - { - // Datasheet Revision: Rev. F 10/17 EN - "name": "MT40A1G16KNR-075:E", - "attribs": { - "speedMTps": 2666, - "CL_nRCD_nRP": 18, - "capacityPerDieGb": 8, - "diesPerPackage": 2, - "packageBusWidth": 16, - "ranksPerPackage": 1 - } - }, - { - // Datasheet Revision: Rev. 1.4, Jul. 2017 - "name": "K4AAG165WB-MCTD", - "attribs": { - "speedMTps": 2666, - "CL_nRCD_nRP": 19, - "capacityPerDieGb": 8, - "diesPerPackage": 1, - "packageBusWidth": 8, - "ranksPerPackage": 1 - } - }, - { - // Datasheet Revision: Rev. 1.0 / Aug.2018 - "name": "H5ANAG6NCMR-VKC", - "attribs": { - "speedMTps": 2666, - "CL_nRCD_nRP": 19, - "capacityPerDieGb": 8, - "diesPerPackage": 2, - "packageBusWidth": 16, - "ranksPerPackage": 1 - } - }, - { - // Datasheet Revision: Rev. 0.5, Jun. 2019 - "name": "K4A8G165WC-BCWE", - "attribs": { - "speedMTps": 3200, - "CL_nRCD_nRP": 22, - "capacityPerDieGb": 8, - "diesPerPackage": 1, - "packageBusWidth": 16, - "ranksPerPackage": 1 - } - }, - { - // Datasheet Revision: Rev. G 08/2020 EN - "name": "MT40A1G16KD-062E:E", - "attribs": { - "speedMTps": 3200, - "CL_nRCD_nRP": 22, - "capacityPerDieGb": 16, - "diesPerPackage": 1, - "packageBusWidth": 16, - "ranksPerPackage": 1, - // Table 158 - Refersh Timing - 16Gb - "TRFC1MinPs": 350000, - "TRFC2MinPs": 260000, - "TRFC4MinPs": 160000 - } - }, - { - // Datasheet Revision: Rev. 0.5, Feb. 2019 - "name": "K4AAG165WA-BCWE", - "attribs": { - "speedMTps": 3200, - "CL_nRCD_nRP": 22, - "capacityPerDieGb": 16, - "diesPerPackage": 1, - "packageBusWidth": 16, - "ranksPerPackage": 1, - // Table 57 - 16Gb - "TRFC1MinPs": 350000, - "TRFC2MinPs": 260000, - "TRFC4MinPs": 160000 - } - }, - { - // Datasheet Revision: Rev. 1.5 / Mar.2019 - "name": "H5AN8G6NCJR-XNC", - "attribs": { - "speedMTps": 3200, - "CL_nRCD_nRP": 22, - "capacityPerDieGb": 8, - "diesPerPackage": 1, - "packageBusWidth": 16, - "ranksPerPackage": 1 - } - }, - { - // Datasheet Revision: Rev. 1.0, Dec. 2019 - "name": "K4AAG165WA-BCTD", - "attribs": { - "speedMTps": 2666, - "CL_nRCD_nRP": 19, - "capacityPerDieGb": 16, - "diesPerPackage": 1, - "packageBusWidth": 16, - "ranksPerPackage": 1, - // Table 41 - Note: Both 550ns and 350ns tRFC1 is supported - "TRFC1MinPs": 350000, - "TRFC2MinPs": 260000, - "TRFC4MinPs": 160000 - } - }, - { - // Datasheet Revision: Rev. 1.0, Feb. 2020 - "name": "H5ANAG6NDMR-XNC", - "attribs": { - "speedMTps": 3200, - "CL_nRCD_nRP": 22, - "capacityPerDieGb": 8, - "diesPerPackage": 2, - "packageBusWidth": 16, - "ranksPerPackage": 1 - } - }, - { - // Datasheet Revision: Rev. 1.4, May. 2020 - "name": "H5ANAG6NCJR-XNC", - "attribs": { - "speedMTps": 3200, - "CL_nRCD_nRP": 22, - "capacityPerDieGb": 16, - "diesPerPackage": 1, - "packageBusWidth": 16, - "ranksPerPackage": 1 - } - }, - { - // Datasheet Revision: Rev. 0.0, Apr. 2020 - "name": "K4AAG165WB-BCWE", - "attribs": { - "speedMTps": 3200, - "CL_nRCD_nRP": 22, - "capacityPerDieGb": 16, - "diesPerPackage": 1, - "packageBusWidth": 16, - "ranksPerPackage": 1 - } - }, - { - // Datasheet Revision: Rev. A 03/2021 EN - "name": "MT40A1G16RC-062E:B", - "attribs": { - "speedMTps": 3200, - "CL_nRCD_nRP": 22, - "capacityPerDieGb": 16, - "diesPerPackage": 1, - "packageBusWidth": 16, - "ranksPerPackage": 1 - } - }, - { - "name": "MT40A512M16TB-062E:R", - "attribs": { - "speedMTps": 3200, - "CL_nRCD_nRP": 22, - "capacityPerDieGb": 8, - "diesPerPackage": 1, - "packageBusWidth": 16, - "ranksPerPackage": 1 - } - }, - { - "name": "4JQA-0622AD", - "attribs": { - "speedMTps": 3200, - "CL_nRCD_nRP": 22, - "capacityPerDieGb": 8, - "diesPerPackage": 1, - "packageBusWidth": 16, - "ranksPerPackage": 1 - } - } - ] -} diff --git a/util/spd_tools/description.md b/util/spd_tools/description.md deleted file mode 100644 index aa127816c5..0000000000 --- a/util/spd_tools/description.md +++ /dev/null @@ -1,11 +0,0 @@ -Tools for generating SPD files for DDR4 memory used in platforms with -memory down configuration. - - - -* _gen_spd.go_ - Generates de-duplicated SPD files using a - global memory part list provided by the - mainboard in JSON format. `Go` - -* _gen_part_id.go_ - Allocates DRAM strap IDs for different - DDR4 memory parts used by the board. `Go` diff --git a/util/spd_tools/lp4x/README.md b/util/spd_tools/lp4x/README.md deleted file mode 100644 index d74ed6b08b..0000000000 --- a/util/spd_tools/lp4x/README.md +++ /dev/null @@ -1,266 +0,0 @@ -# LPDDR4x SPD tools README - -Tools for generating SPD files for LPDDR4x memory used in memory down -configurations on Intel Tiger Lake (TGL), Jasper Lake (JSL), and Alder -Lake (ADL) based platforms. These tools generate SPDs following -JESD209-4C specification and Intel recommendations (doc #616599, -#610202, #634730) for LPDDR4x SPD. - -There are two tools provided that assist TGL, JSL and ADL based -mainboards to generate SPDs and Makefile to integrate these SPDs in -coreboot build. These tools can also be used to allocate DRAM IDs -(configure DRAM hardware straps) for any LPDDR4x memory part used by the -board. - -* gen_spd.go: Generates de-duplicated SPD files using a global memory - part list provided by the mainboard in JSON format. Additionally, - generates a SPD manifest file(in CSV format) with information about - what memory part from the global list uses which of the generated - SPD files. - -* gen_part_id.go: Allocates DRAM strap IDs for different LPDDR4x - memory parts used by the board. Takes as input list of memory parts - used by the board (with one memory part on each line) and the SPD - manifest file generated by gen_spd.go. Generates Makefile.inc for - integrating the generated SPD files in the coreboot build. - -## Tool 1 - gen_spd.go - -This program takes as input: -* Pointer to directory where the generated SPD files and manifest will - be placed. -* JSON file containing a global list of memory parts with their - attributes as per the datasheet. This is the list of all known - LPDDR4x memory parts irrespective of their usage on the board. -* SoC platform name for which the SPDs are being generated. Currently - supported platform names are `TGL`, `JSL` and `ADL`. - -Input JSON file requires the following two fields for every memory part: -* `name`: Name of the memory part -* `attribs`: List of attributes of the memory part as per its - datasheet. These attributes match the part specifications and are - independent of any SoC expectations. Tool takes care of translating - the physical attributes of the memory part to match JEDEC and Intel - MRC expectations. - -`attribs` field further contains two types of sub-fields: -* Mandatory: These attributes have to be provided for a memory part. -* Optional: These attributes can be provided by memory part if it wants - to override the defaults. - -### Mandatory `attribs` - -* `densityPerChannelGb`: Density in Gb of the physical channel. - -* `banks`: Number of banks per physical channel. This is typically 8 - for LPDDR4x memory parts. - -* `channelsPerDie`: Number of physical channels per die. Valid values: - `1, 2, 4`. For a part with x16 bit width, number of channels per die - is 1 or 2. For a part with x8 bit width, number of channels can be - 2 or 4 (4 is basically when two dual-channel byte mode devices are - combined as shown in Figure 3 in JESD209-4C). - -* `diesPerPackage`: Number of physical dies in each SDRAM - package. As per JESD209-4C, "Standard LPDDR4 package ballmaps - allocate one ZQ ball per die." Thus, number of diesPerPackage is the - number of ZQ balls on the package. - -* `bitWidthPerChannel`: Width of each physical channel. Valid values: - `8, 16` bits. - -* `ranksPerChannel`: Number of ranks per physical channel. Valid - values: `1, 2`. If the channels across multiple dies share the same - DQ/DQS pins but use a separate CS, then ranks is 2 else it is 1. - -* `speedMbps`: Maximum data rate supported by the part in Mbps. Valid - values: `3200, 3733, 4267` Mbps. - -### Optional `attribs` - -* `trfcabNs`: Minimum Refresh Recovery Delay Time (tRFCab) for all - banks in nanoseconds. As per JESD209-4C, this is dependent on the - density per channel. Default values used: - * 6Gb : 280ns - * 8Gb : 280ns - * 12Gb: 380ns - * 16Gb: 380ns - -* `trfcpbNs`: Minimum Refresh Recovery Delay Time (tRFCab) per - bank in nanoseconds. As per JESD209-4C, this is dependent on the - density per channel. Default values used: - * 6Gb : 140ns - * 8Gb : 140ns - * 12Gb: 190ns - * 16Gb: 190ns - -* `trpabMinNs`: Minimum Row Precharge Delay Time (tRPab) for all banks - in nanoseconds. As per JESD209-4C, this is max(21ns, 4nck) which - defaults to `21ns`. - -* `trppbMinNs`: Minimum Row Precharge Delay Time (tRPpb) per bank in - nanoseconds. As per JESD209-4C, this is max(18ns, 4nck) which - defaults to `18ns`. - -* `tckMinPs`: SDRAM minimum cycle time (tckMin) value in - picoseconds. This is typically calculated based on the `speedMbps` - attribute. `(1 / speedMbps) * 2`. Default values used(taken from - JESD209-4C): - * 4267 Mbps: 468ps - * 3733 Mbps: 535ps - * 3200 Mbps: 625ps - -* `tckMaxPs`: SDRAM maximum cycle time (tckMax) value in - picoseconds. Default value used: `31875ps`. As per JESD209-4C, - TCKmax should be 100ns (100000ps) for all speed grades. But the SPD - byte to encode this field is only 1 byte. Hence, the maximum value - that can be encoded is 31875ps. - -* `taaMinPs`: Minimum CAS Latency Time(taaMin) in picoseconds. This - value defaults to nck * tckMin, where nck is minimum CAS latency. - -* `trcdMinNs`: Minimum RAS# to CAS# Delay Time (tRCDmin) in - nanoseconds. As per JESD209-4C, this is max(18ns, 4nck) which - defaults to `18ns`. - -* `casLatencies`: List of CAS latencies supported by the - part. This is dependent on the attrib `speedMbps`. Default values - used: - * 4267: `"6 10 14 20 24 28 32 36"`. - * 3733: `"6 10 14 20 24 28 32"`. - * 3200: `"6 10 14 20 24 28"`. - -### Example JSON file -``` -{ - "parts": [ - { - "name": "MEMORY_PART_A", - "attribs": { - "densityPerChannelGb": 8, - "banks": 8, - "channelsPerDie": 2, - "diesPerPackage": 2, - "bitWidthPerChannel": 16, - "ranksPerChannel": 1, - "speedMbps": 4267 - } - }, - { - "name": "MEMORY_PART_B", - "attribs": { - "densityPerChannelGb": 8, - "banks": 8, - "channelsPerDie": 1, - "diesPerPackage": 2, - "bitWidthPerChannel": 16, - "ranksPerChannel": 1, - "speedMbps": 3733, - "casLatencies": "14 20 24 28 32", - "tckMaxPs": "1250" - } - } - ] -} -``` - -### Output - -This tool generates the following files using the global list of -memory parts in JSON format as described above: - * De-duplicated SPDs required for the different memory parts. These - SPD files are named (spd_1.hex, spd_2.hex, spd_3.hex and so on) - and placed in the directory provided as an input to the tool. - * CSV file representing which of the deduplicated SPD files is used - by which memory part. This file is named as - `spd_manifest.generated.txt` and placed in the directory provided - as an input to the tool along with the generated SPD - files. Example CSV file: - ``` - MEMORY_PART_A, spd_1.hex - MEMORY_PART_B, spd_2.hex - MEMORY_PART_C, spd_3.hex - MEMORY_PART_D, spd_2.hex - MEMORY_PART_E, spd_2.hex - ``` - -## Tool 2 - gen_part_id.go - -This program takes as input: -* Pointer to directory where the SPD files and the manifest file - `spd_manifest.generated.txt` (in CSV format) are placed by - gen_spd.go -* File containing list of memory parts used by the board. Each line of - the file is supposed to contain one memory part `name` as present in - the global list of memory parts provided to gen_spd.go -* Pointer to directory where the generated Makefile.inc should be - placed by the tool. - -### Output - -This program provides the following: - -* Prints out the list of DRAM hardware strap IDs that should be - allocated to each memory part listed in the input file. -* Makefile.inc is generated in the provided directory to integrate - SPDs generated by gen_spd.go with the coreboot build for the board. -* dram_id.generated.txt is generated in the same directory as - Makefile. This contains the part IDs assigned to the different - memory parts. (Useful to integrate in board schematics). - -Sample output (dram_id.generated.txt): -``` -DRAM Part Name ID to assign -MEMORY_PART_A 0 (0000) -MEMORY_PART_B 1 (0001) -MEMORY_PART_C 2 (0010) -MEMORY_PART_D 1 (0001) -``` - -Sample Makefile.inc: -``` -## SPDX-License-Identifier: GPL-2.0-or-later -## This is an auto-generated file. Do not edit!! - -SPD_SOURCES = -SPD_SOURCES += spd_1.hex # ID = 0(0b0000) Parts = MEMORY_PART_A -SPD_SOURCES += spd_2.hex # ID = 1(0b0001) Parts = MEMORY_PART_B, MEMORY_PART_D -SPD_SOURCES += spd_3.hex # ID = 2(0b0010) Parts = MEMORY_PART_C -``` - -### Note of caution - -This program assigns DRAM IDs using the order of DRAM part names -provided in the input file. Thus, when adding a new memory part to the -list, it should always go to the end of the input text file. This -guarantees that the memory parts that were already assigned IDs do not -change. - -## How to build the tools? -``` -# go build gen_spd.go -# go build gen_part_id.go -``` - -## How to use the tools? -``` -# ./gen_spd <spd_dir> <mem_parts_list_json> <platform> -# ./gen_part_id <spd_dir> <makefile_dir> <mem_parts_used_file> -``` - -### Need to add a new memory part for a board? - -* If the memory part is not present in the global list of memory - parts, then add the memory part name and attributes as per the - datasheet to the file containing the global list. - * Use `gen_spd.go` with input as the file containing the global list - of memory parts to generate de-duplicated SPDs. - * If a new SPD file is generated, use `git add` to add it to the - tree and push a CL for review. -* Update the file containing memory parts used by board (variant) to - add the new memory part name at the end of the file. - * Use gen_part_id.go providing it pointer to the location where SPD - files are stored and file containing the list of memory parts used - by the board(variant). - * Use `git add` to add `Makefile.inc` and `dram_id.generated.txt` - with updated changes and push a CL for review. diff --git a/util/spd_tools/lp4x/gen_part_id.go b/util/spd_tools/lp4x/gen_part_id.go deleted file mode 100644 index 71ef3ec11b..0000000000 --- a/util/spd_tools/lp4x/gen_part_id.go +++ /dev/null @@ -1,214 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -package main - -import ( - "encoding/csv" - "fmt" - "io" - "io/ioutil" - "log" - "os" - "path/filepath" - "strings" -) - -/* - * This program allocates DRAM strap IDs for different parts that are being used by the variant. - * - * It expects the following inputs: - * Pointer to SPD directory. This is the location where SPD files and SPD Manifest generated by - * gen_spd.go are placed. - * Pointer to Makefile directory. Makefile.inc generated by this program is placed in this - * location. - * Text file containing a list of memory parts names used by the board. Each line in the file - * is expected to have one memory part name. - */ -const ( - SPDManifestFileName = "lp4x_spd_manifest.generated.txt" - MakefileName = "Makefile.inc" - DRAMIdFileName = "dram_id.generated.txt" -) - -func usage() { - fmt.Printf("\nUsage: %s <spd_dir> <makefile_dir> <mem_parts_used_file>\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(" makefile_dir = Directory path where generated Makefile.inc should be placed\n") - fmt.Printf(" mem_parts_used_file = File containing list of memory parts used by the board\n\n\n") -} - -func checkArgs() error { - - for _, arg := range os.Args[1:] { - if _, err := os.Stat(arg); err != nil { - return err - } - } - - return nil -} - -/* - * Read input file that contains list of memory part names used by the variant (one on a line) - * and split into separate strings for each part name. - */ -func readParts(memPartsUsedFileName string) ([]string, error) { - lines, err := ioutil.ReadFile(memPartsUsedFileName) - if err != nil { - return nil, err - } - str := string(lines) - parts := strings.Split(str, "\n") - - return parts, nil -} - -/* - * Read SPD manifest file(CSV) generated by gen_spd program and generate two maps: - * 1. Part to SPD Map : This maps global memory part name to generated SPD file name - * 2. SPD to Index Map: This generates a map of deduplicated SPD file names to index assigned to - * that SPD. This function sets index for all SPDs to -1. This index gets - * updated as part of genPartIdInfo() depending upon the SPDs actually used - * by the variant. - */ -func readSPDManifest(SPDDirName string) (map[string]string, map[string]int, error) { - f, err := os.Open(filepath.Join(SPDDirName, SPDManifestFileName)) - if err != nil { - return nil, nil, err - } - defer f.Close() - r := csv.NewReader(f) - - partToSPDMap := make(map[string]string) - SPDToIndexMap := make(map[string]int) - - for { - fields, err := r.Read() - - if err == io.EOF { - break - } - - if err != nil { - return nil, nil, err - } - - if len(fields) != 2 { - return nil, nil, fmt.Errorf("CSV file is incorrectly formatted") - } - - partToSPDMap[fields[0]] = fields[1] - SPDToIndexMap[fields[1]] = -1 - } - - return partToSPDMap, SPDToIndexMap, nil -} - -/* Print information about memory part used by variant and ID assigned to it. */ -func appendPartIdInfo(s *string, partName string, index int) { - *s += fmt.Sprintf("%-30s %d (%04b)\n", partName, index, int64(index)) -} - -type partIds struct { - SPDFileName string - memParts string -} - -/* - * For each part used by variant, check if the SPD (as per the manifest) already has an ID - * assigned to it. If yes, then add the part name to the list of memory parts supported by the - * SPD entry. If not, then assign the next ID to the SPD file and add the part name to the - * list of memory parts supported by the SPD entry. - * - * Returns list of partIds that contains spdFileName and supported memory parts for each - * assigned ID. - */ -func genPartIdInfo(parts []string, partToSPDMap map[string]string, SPDToIndexMap map[string]int, makefileDirName string) ([]partIds, error) { - partIdList := []partIds{} - curId := 0 - var s string - - s += fmt.Sprintf("%-30s %s\n", "DRAM Part Name", "ID to assign") - - for _, p := range parts { - if p == "" { - continue - } - - SPDFileName, ok := partToSPDMap[p] - if !ok { - return nil, fmt.Errorf("Failed to find part ", p, " in SPD Manifest. Please add the part to global part list and regenerate SPD Manifest") - } - - index := SPDToIndexMap[SPDFileName] - if index != -1 { - partIdList[index].memParts += ", " + p - appendPartIdInfo(&s, p, index) - continue - } - - SPDToIndexMap[SPDFileName] = curId - - appendPartIdInfo(&s, p, curId) - entry := partIds{SPDFileName: SPDFileName, memParts: p} - partIdList = append(partIdList, entry) - - curId++ - } - - fmt.Printf("%s", s) - err := ioutil.WriteFile(filepath.Join(makefileDirName, DRAMIdFileName), []byte(s), 0644) - - return partIdList, err -} - -var generatedCodeLicense string = "## SPDX-License-Identifier: GPL-2.0-or-later" -var autoGeneratedInfo string = "## This is an auto-generated file. Do not edit!!" - -/* - * This function generates Makefile.inc under the variant directory path and adds assigned SPDs - * to SPD_SOURCES. - */ -func genMakefile(partIdList []partIds, makefileDirName string) error { - var s string - - s += fmt.Sprintf("%s\n%s\n\n", generatedCodeLicense, autoGeneratedInfo) - s += fmt.Sprintf("SPD_SOURCES =\n") - - for i := 0; i < len(partIdList); i++ { - s += fmt.Sprintf("SPD_SOURCES += %s ", partIdList[i].SPDFileName) - s += fmt.Sprintf(" # ID = %d(0b%04b) ", i, int64(i)) - s += fmt.Sprintf(" Parts = %04s\n", partIdList[i].memParts) - } - - return ioutil.WriteFile(filepath.Join(makefileDirName, MakefileName), []byte(s), 0644) -} - -func main() { - if len(os.Args) != 4 { - usage() - log.Fatal("Incorrect number of arguments") - } - - SPDDir, MakefileDir, MemPartsUsedFile := os.Args[1], os.Args[2], os.Args[3] - - partToSPDMap, SPDToIndexMap, err := readSPDManifest(SPDDir) - if err != nil { - log.Fatal(err) - } - - parts, err := readParts(MemPartsUsedFile) - if err != nil { - log.Fatal(err) - } - - partIdList, err := genPartIdInfo(parts, partToSPDMap, SPDToIndexMap, MakefileDir) - if err != nil { - log.Fatal(err) - } - - if err := genMakefile(partIdList, MakefileDir); err != nil { - log.Fatal(err) - } -} diff --git a/util/spd_tools/lp4x/gen_spd.go b/util/spd_tools/lp4x/gen_spd.go deleted file mode 100644 index aeb5e1923e..0000000000 --- a/util/spd_tools/lp4x/gen_spd.go +++ /dev/null @@ -1,996 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -package main - -import ( - "encoding/json" - "fmt" - "io/ioutil" - "log" - "os" - "path/filepath" - "reflect" - "strconv" - "strings" -) - -/* - * This program generates de-duplicated SPD files for LPDDR4x 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 ( - SPDManifestFileName = "lp4x_spd_manifest.generated.txt" - - PlatformTGLADL = 0 - PlatformJSL = 1 - PlatformCZN = 2 -) - -var platformMap = map[string]int{ - "TGL": PlatformTGLADL, - "JSL": PlatformJSL, - "ADL": PlatformTGLADL, - "CZN": PlatformCZN, -} - -var currPlatform int - -type memAttributes struct { - /* Primary attributes - must be provided by JSON file for each part */ - DensityPerChannelGb int - Banks int - ChannelsPerDie int - DiesPerPackage int - BitWidthPerChannel int - RanksPerChannel int - SpeedMbps int - - /* - * All the following parameters are optional and required only if the part requires - * special parameters as per the datasheet. - */ - /* Timing parameters */ - TRFCABNs int - TRFCPBNs int - TRPABMinNs int - TRPPBMinNs int - TCKMinPs int - TCKMaxPs int - TAAMinPs int - TRCDMinNs int - - /* CAS */ - CASLatencies string - CASFirstByte byte - CASSecondByte byte - CASThirdByte byte -} - -/* This encodes the density in Gb to SPD values as per JESD 21-C */ -var densityGbToSPDEncoding = map[int]byte{ - 4: 0x4, - 6: 0xb, - 8: 0x5, - 12: 0x8, - 16: 0x6, - 24: 0x9, - 32: 0x7, -} - -/* - * Table 3 from JESD209-4C. - * Maps density per physical channel to row-column encoding as per JESD 21-C for a device with - * x16 physical channel. - */ -var densityGbx16ChannelToRowColumnEncoding = map[int]byte{ - 4: 0x19, /* 15 rows, 10 columns */ - 6: 0x21, /* 16 rows, 10 columns */ - 8: 0x21, /* 16 rows, 10 columns */ - 12: 0x29, /* 17 rows, 10 columns */ - 16: 0x29, /* 17 rows, 10 columns */ -} - -/* - * Table 5 from JESD209-4C. - * Maps density per physical channel to row-column encoding as per JESD 21-C for a device with - * x8 physical channel. - */ -var densityGbx8ChannelToRowColumnEncoding = map[int]byte{ - 3: 0x21, /* 16 rows, 10 columns */ - 4: 0x21, /* 16 rows, 10 columns */ - 6: 0x29, /* 17 rows, 10 columns */ - 8: 0x29, /* 17 rows, 10 columns */ - 12: 0x31, /* 18 rows, 10 columns */ - 16: 0x31, /* 18 rows, 10 columns */ -} - -type refreshTimings struct { - TRFCABNs int - TRFCPBNs int -} - -/* - * Table 112 from JESD209-4C - * Maps density per physical channel to refresh timings. This is the same for x8 and x16 - * devices. - */ -var densityGbPhysicalChannelToRefreshEncoding = map[int]refreshTimings{ - 3: { - TRFCABNs: 180, - TRFCPBNs: 90, - }, - 4: { - TRFCABNs: 180, - TRFCPBNs: 90, - }, - 6: { - TRFCABNs: 280, - TRFCPBNs: 140, - }, - 8: { - TRFCABNs: 280, - TRFCPBNs: 140, - }, - 12: { - TRFCABNs: 380, - TRFCPBNs: 190, - }, - 16: { - TRFCABNs: 380, - TRFCPBNs: 190, - }, -} - -type speedParams struct { - TCKMinPs int - TCKMaxPs int - CASLatenciesx16Channel string - CASLatenciesx8Channel string -} - -const ( - /* First Byte */ - CAS6 = 1 << 1 - CAS10 = 1 << 4 - CAS14 = 1 << 7 - /* Second Byte */ - CAS16 = 1 << 0 - CAS20 = 1 << 2 - CAS22 = 1 << 3 - CAS24 = 1 << 4 - CAS26 = 1 << 5 - CAS28 = 1 << 6 - /* Third Byte */ - CAS32 = 1 << 0 - CAS36 = 1 << 2 - CAS40 = 1 << 4 -) - -const ( - /* - * JEDEC spec says that TCKmax should be 100ns for all speed grades. - * 100ns in MTB units comes out to be 0x320. But since this is a byte field, set it to - * 0xFF i.e. 31.875ns. - */ - TCKMaxPsDefault = 31875 -) - -var speedMbpsToSPDEncoding = map[int]speedParams{ - 4267: { - TCKMinPs: 468, /* 1/4267 * 2 */ - TCKMaxPs: TCKMaxPsDefault, - CASLatenciesx16Channel: "6 10 14 20 24 28 32 36", - CASLatenciesx8Channel: "6 10 16 22 26 32 36 40", - }, - 3733: { - TCKMinPs: 535, /* 1/3733 * 2 */ - TCKMaxPs: TCKMaxPsDefault, - CASLatenciesx16Channel: "6 10 14 20 24 28 32", - CASLatenciesx8Channel: "6 10 16 22 26 32 36", - }, - 3200: { - TCKMinPs: 625, /* 1/3200 * 2 */ - TCKMaxPs: TCKMaxPsDefault, - CASLatenciesx16Channel: "6 10 14 20 24 28", - CASLatenciesx8Channel: "6 10 16 22 26 32", - }, -} - -var bankEncoding = map[int]byte{ - 4: 0 << 4, - 8: 1 << 4, -} - -const ( - TGLLogicalChannelWidth = 16 -) - -/* Returns density to encode as per Intel MRC expectations. */ -func getMRCDensity(memAttribs *memAttributes) int { - if currPlatform == PlatformTGLADL { - /* - * Intel MRC on TGL expects density per logical channel to be encoded in - * SPDIndexDensityBanks. Logical channel on TGL is an x16 channel. - */ - return memAttribs.DensityPerChannelGb * TGLLogicalChannelWidth / memAttribs.BitWidthPerChannel - } else if currPlatform == PlatformJSL || currPlatform == PlatformCZN { - /* - * Intel MRC on JSL expects density per die to be encoded in - * SPDIndexDensityBanks. - */ - return memAttribs.DensityPerChannelGb * memAttribs.ChannelsPerDie - } - - return 0 -} - -func encodeDensityBanks(memAttribs *memAttributes) byte { - var b byte - - b = densityGbToSPDEncoding[getMRCDensity(memAttribs)] - b |= bankEncoding[memAttribs.Banks] - - return b -} - -func encodeSdramAddressing(memAttribs *memAttributes) byte { - densityPerChannelGb := memAttribs.DensityPerChannelGb - if memAttribs.BitWidthPerChannel == 8 { - return densityGbx8ChannelToRowColumnEncoding[densityPerChannelGb] - } else { - return densityGbx16ChannelToRowColumnEncoding[densityPerChannelGb] - } - return 0 -} - -func encodeChannelsPerDie(channels int) byte { - var temp byte - - temp = byte(channels >> 1) - - return temp << 2 -} - -func encodePackage(dies int) byte { - var temp byte - - if dies > 1 { - /* If more than one die, then this is a non-monolithic device. */ - temp = 1 - } else { - /* If only single die, then this is a monolithic device. */ - temp = 0 - } - - return temp << 7 -} - -/* Per JESD209-4C Dies = ZQ balls on the package */ -/* Note that this can be different than the part's die count */ -func encodeDiesPerPackage(memAttribs *memAttributes) byte { - var dies int = 0 - if currPlatform == PlatformTGLADL { - /* Intel MRC expects logical dies to be encoded for TGL. */ - dies = memAttribs.ChannelsPerDie * memAttribs.RanksPerChannel * memAttribs.BitWidthPerChannel / 16 - } else if currPlatform == PlatformJSL || currPlatform == PlatformCZN { - /* Intel MRC expects physical dies to be encoded for JSL. */ - /* AMD PSP expects physical dies (ZQ balls) */ - dies = memAttribs.DiesPerPackage - } - - b := encodePackage(dies) /* Monolithic / Non-monolithic device */ - b |= (byte(dies) - 1) << 4 - - return b -} - -func encodePackageType(memAttribs *memAttributes) byte { - var b byte - - b |= encodeChannelsPerDie(memAttribs.ChannelsPerDie) - b |= encodeDiesPerPackage(memAttribs) - - return b -} - -func encodeDataWidth(bitWidthPerChannel int) byte { - return byte(bitWidthPerChannel / 8) -} - -func encodeRanks(ranks int) byte { - var b byte - b = byte(ranks - 1) - return b << 3 -} - -func encodeModuleOrganization(memAttribs *memAttributes) byte { - var b byte - - b = encodeDataWidth(memAttribs.BitWidthPerChannel) - b |= encodeRanks(memAttribs.RanksPerChannel) - - return b -} - -const ( - /* - * As per advisory 616599: - * 7:5 (Number of system channels) = 000 (1 channel always) - * 2:0 (Bus width) = 001 (x16 always) - * Set to 0x01. - */ - SPDValueBusWidthTGL = 0x01 - /* - * As per advisory 610202: - * 7:5 (Number of system channels) = 001 (2 channel always) - * 2:0 (Bus width) = 010 (x32 always) - * Set to 0x01. - */ - SPDValueBusWidthJSL = 0x22 -) - -func encodeBusWidth(memAttribs *memAttributes) byte { - if currPlatform == PlatformTGLADL { - return SPDValueBusWidthTGL - } else if currPlatform == PlatformJSL || currPlatform == PlatformCZN { - return SPDValueBusWidthJSL - } - return 0 -} - -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 encodeCASFirstByte(memAttribs *memAttributes) byte { - return memAttribs.CASFirstByte -} - -func encodeCASSecondByte(memAttribs *memAttributes) byte { - return memAttribs.CASSecondByte -} - -func encodeCASThirdByte(memAttribs *memAttributes) byte { - return memAttribs.CASThirdByte -} - -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 convNsToMtb(timeNs int) int { - return convPsToMtb(convNsToPs(timeNs)) -} - -func convNsToMtbByte(timeNs int) byte { - return convPsToMtbByte(convNsToPs(timeNs)) -} - -func convNsToFtbByte(timeNs int) byte { - return convPsToFtbByte(convNsToPs(timeNs)) -} - -func encodeTAAMin(memAttribs *memAttributes) byte { - return convPsToMtbByte(memAttribs.TAAMinPs) -} - -func encodeTAAMinFineOffset(memAttribs *memAttributes) byte { - return convPsToFtbByte(memAttribs.TAAMinPs) -} - -func encodeTRCDMin(memAttribs *memAttributes) byte { - return convNsToMtbByte(memAttribs.TRCDMinNs) -} - -func encodeTRCDMinFineOffset(memAttribs *memAttributes) byte { - return convNsToFtbByte(memAttribs.TRCDMinNs) -} - -func encodeTRPABMin(memAttribs *memAttributes) byte { - return convNsToMtbByte(memAttribs.TRPABMinNs) -} - -func encodeTRPABMinFineOffset(memAttribs *memAttributes) byte { - return convNsToFtbByte(memAttribs.TRPABMinNs) -} - -func encodeTRPPBMin(memAttribs *memAttributes) byte { - return convNsToMtbByte(memAttribs.TRPPBMinNs) -} - -func encodeTRPPBMinFineOffset(memAttribs *memAttributes) byte { - return convNsToFtbByte(memAttribs.TRPPBMinNs) -} - -func encodeTRFCABMinMsb(memAttribs *memAttributes) byte { - return byte((convNsToMtb(memAttribs.TRFCABNs) >> 8) & 0xff) -} - -func encodeTRFCABMinLsb(memAttribs *memAttributes) byte { - return byte(convNsToMtb(memAttribs.TRFCABNs) & 0xff) -} - -func encodeTRFCPBMinMsb(memAttribs *memAttributes) byte { - return byte((convNsToMtb(memAttribs.TRFCPBNs) >> 8) & 0xff) -} - -func encodeTRFCPBMinLsb(memAttribs *memAttributes) byte { - return byte(convNsToMtb(memAttribs.TRFCPBNs) & 0xff) -} - -type SPDAttribFunc func(*memAttributes) byte - -type SPDAttribTableEntry struct { - constVal byte - getVal SPDAttribFunc -} - -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 - SPDIndexReadWriteLatency = 25 - SPDIndexTRCDMin = 26 - SPDIndexTRPABMin = 27 - SPDIndexTRPPBMin = 28 - SPDIndexTRFCABMinLSB = 29 - SPDIndexTRFCABMinMSB = 30 - SPDIndexTRFCPBMinLSB = 31 - SPDIndexTRFCPBMinMSB = 32 - SPDIndexTRPPBMinFineOffset = 120 - SPDIndexTRPABMinFineOffset = 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 LPDDR4x. - */ - SPDValueSize = 0x23 - - /* - * From JEDEC spec: Revision 1.1 - * Set to 0x11. - */ - SPDValueRevision = 0x11 - - /* LPDDR4x memory type = 0x11 */ - SPDValueMemoryType = 0x11 - - /* - * From JEDEC spec: - * 7:7 (Hybrid) = 0 (Not hybrid) - * 6:4 (Hybrid media) = 000 (Not hybrid) - * 3:0 (Base Module Type) = 1110 (Non-DIMM solution) - * - * This is dependent on hardware design. LPDDR4x only has memory down solution. - * Hence this is not hybrid non-DIMM solution. - * Set to 0x0E. - */ - SPDValueModuleType = 0x0e - - /* - * 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: - * 3:2 (MTB) = 00 (0.125ns) - * 1:0 (FTB) = 00 (1ps) - * Set to 0x00. - */ - SPDValueTimebases = 0x00 - - /* CAS fourth byte: All bits are reserved */ - SPDValueCASFourthByte = 0x00 - - /* Write Latency Set A and Read Latency DBI-RD disabled. */ - SPDValueReadWriteLatency = 0x00 - - /* As per JEDEC spec, unused digits of manufacturer part number are left as blank. */ - SPDValueManufacturerPartNumberBlank = 0x20 -) - -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: {getVal: encodeBusWidth}, - SPDIndexTimebases: {constVal: SPDValueTimebases}, - SPDIndexTCKMin: {getVal: encodeTCKMin}, - SPDIndexTCKMax: {getVal: encodeTCKMax}, - SPDIndexTCKMaxFineOffset: {getVal: encodeTCKMaxFineOffset}, - SPDIndexTCKMinFineOffset: {getVal: encodeTCKMinFineOffset}, - SPDIndexCASFirstByte: {getVal: encodeCASFirstByte}, - SPDIndexCASSecondByte: {getVal: encodeCASSecondByte}, - SPDIndexCASThirdByte: {getVal: encodeCASThirdByte}, - SPDIndexCASFourthByte: {constVal: SPDValueCASFourthByte}, - SPDIndexTAAMin: {getVal: encodeTAAMin}, - SPDIndexTAAMinFineOffset: {getVal: encodeTAAMinFineOffset}, - SPDIndexReadWriteLatency: {constVal: SPDValueReadWriteLatency}, - SPDIndexTRCDMin: {getVal: encodeTRCDMin}, - SPDIndexTRCDMinFineOffset: {getVal: encodeTRCDMinFineOffset}, - SPDIndexTRPABMin: {getVal: encodeTRPABMin}, - SPDIndexTRPABMinFineOffset: {getVal: encodeTRPABMinFineOffset}, - SPDIndexTRPPBMin: {getVal: encodeTRPPBMin}, - SPDIndexTRPPBMinFineOffset: {getVal: encodeTRPPBMinFineOffset}, - SPDIndexTRFCABMinLSB: {getVal: encodeTRFCABMinLsb}, - SPDIndexTRFCABMinMSB: {getVal: encodeTRFCABMinMsb}, - SPDIndexTRFCPBMinLSB: {getVal: encodeTRFCPBMinLsb}, - SPDIndexTRFCPBMinMSB: {getVal: encodeTRFCPBMinMsb}, -} - -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 -} - -func createSPD(memAttribs *memAttributes) string { - var s string - - for i := 0; i < 512; i++ { - b := getSPDByte(i, memAttribs) - - if (i+1)%16 == 0 { - s += fmt.Sprintf("%02X\n", b) - } else { - s += fmt.Sprintf("%02X ", b) - } - } - - return s -} - -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) { - s := createSPD(&memPart.Attribs) - memPart.SPDFileName = fmt.Sprintf("lp4x-spd-%d.hex", SPDId) - ioutil.WriteFile(filepath.Join(SPDDirName, memPart.SPDFileName), []byte(s), 0644) -} - -func readMemoryParts(memParts *memParts, memPartsFileName string) error { - databytes, err := ioutil.ReadFile(memPartsFileName) - if err != nil { - return err - } - - return json.Unmarshal(databytes, memParts) -} - -func validateDensityx8Channel(densityPerChannelGb int) error { - if _, ok := densityGbx8ChannelToRowColumnEncoding[densityPerChannelGb]; ok == false { - return fmt.Errorf("Incorrect x8 density: ", densityPerChannelGb, "Gb") - } - return nil -} - -func validateDensityx16Channel(densityPerChannelGb int) error { - if _, ok := densityGbx16ChannelToRowColumnEncoding[densityPerChannelGb]; ok == false { - return fmt.Errorf("Incorrect x16 density: ", densityPerChannelGb, "Gb") - } - return nil -} - -func validateDensity(memAttribs *memAttributes) error { - if memAttribs.BitWidthPerChannel == 8 { - return validateDensityx8Channel(memAttribs.DensityPerChannelGb) - } else if memAttribs.BitWidthPerChannel == 16 { - return validateDensityx16Channel(memAttribs.DensityPerChannelGb) - } - - return fmt.Errorf("No density table for this bit width: ", memAttribs.BitWidthPerChannel) -} - -func validateBanks(banks int) error { - if banks != 4 && banks != 8 { - return fmt.Errorf("Incorrect banks: ", banks) - } - return nil -} - -func validateChannels(channels int) error { - if channels != 1 && channels != 2 && channels != 4 { - return fmt.Errorf("Incorrect channels per die: ", channels) - } - return nil -} - -func validateDataWidth(width int) error { - if width != 8 && width != 16 { - return fmt.Errorf("Incorrect bit width: ", width) - } - return nil -} - -func validateRanks(ranks int) error { - if ranks != 1 && ranks != 2 { - return fmt.Errorf("Incorrect ranks: ", ranks) - } - return nil -} - -func validateSpeed(speed int) error { - if _, ok := speedMbpsToSPDEncoding[speed]; ok == false { - return fmt.Errorf("Incorrect speed: ", speed, " Mbps") - } - return nil -} - -func validateMemoryParts(memParts *memParts) error { - for i := 0; i < len(memParts.MemParts); i++ { - if err := validateBanks(memParts.MemParts[i].Attribs.Banks); err != nil { - return err - } - if err := validateChannels(memParts.MemParts[i].Attribs.ChannelsPerDie); err != nil { - return err - } - if err := validateDataWidth(memParts.MemParts[i].Attribs.BitWidthPerChannel); err != nil { - return err - } - if err := validateDensity(&memParts.MemParts[i].Attribs); err != nil { - return err - } - if err := validateRanks(memParts.MemParts[i].Attribs.RanksPerChannel); err != nil { - return err - } - if err := validateSpeed(memParts.MemParts[i].Attribs.SpeedMbps); err != nil { - return err - } - } - return nil -} - -func encodeLatencies(latency int, memAttribs *memAttributes) error { - switch latency { - case 6: - memAttribs.CASFirstByte |= CAS6 - case 10: - memAttribs.CASFirstByte |= CAS10 - case 14: - memAttribs.CASFirstByte |= CAS14 - case 16: - memAttribs.CASSecondByte |= CAS16 - case 20: - memAttribs.CASSecondByte |= CAS20 - case 22: - memAttribs.CASSecondByte |= CAS22 - case 24: - memAttribs.CASSecondByte |= CAS24 - case 26: - memAttribs.CASSecondByte |= CAS26 - case 28: - memAttribs.CASSecondByte |= CAS28 - case 32: - memAttribs.CASThirdByte |= CAS32 - case 36: - memAttribs.CASThirdByte |= CAS36 - case 40: - memAttribs.CASThirdByte |= CAS40 - default: - fmt.Errorf("Incorrect CAS Latency: ", latency) - } - - return nil -} - -func updateTCK(memAttribs *memAttributes) { - if memAttribs.TCKMinPs == 0 { - memAttribs.TCKMinPs = speedMbpsToSPDEncoding[memAttribs.SpeedMbps].TCKMinPs - } - if memAttribs.TCKMaxPs == 0 { - memAttribs.TCKMaxPs = speedMbpsToSPDEncoding[memAttribs.SpeedMbps].TCKMaxPs - } -} - -func getCASLatencies(memAttribs *memAttributes) string { - if memAttribs.BitWidthPerChannel == 16 { - return speedMbpsToSPDEncoding[memAttribs.SpeedMbps].CASLatenciesx16Channel - } else if memAttribs.BitWidthPerChannel == 8 { - return speedMbpsToSPDEncoding[memAttribs.SpeedMbps].CASLatenciesx8Channel - } - - return "" -} - -func updateCAS(memAttribs *memAttributes) error { - if len(memAttribs.CASLatencies) == 0 { - memAttribs.CASLatencies = getCASLatencies(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 getMinCAS(memAttribs *memAttributes) (int, error) { - if (memAttribs.CASThirdByte & CAS40) != 0 { - return 40, nil - } - if (memAttribs.CASThirdByte & CAS36) != 0 { - return 36, nil - } - if (memAttribs.CASThirdByte & CAS32) != 0 { - return 32, nil - } - if (memAttribs.CASSecondByte & CAS28) != 0 { - return 28, nil - } - - return 0, fmt.Errorf("Unexpected min CAS") -} - -func updateTAAMin(memAttribs *memAttributes) error { - if memAttribs.TAAMinPs == 0 { - minCAS, err := getMinCAS(memAttribs) - if err != nil { - return err - } - memAttribs.TAAMinPs = memAttribs.TCKMinPs * minCAS - } - - return nil -} - -func updateTRFCAB(memAttribs *memAttributes) { - if memAttribs.TRFCABNs == 0 { - memAttribs.TRFCABNs = densityGbPhysicalChannelToRefreshEncoding[memAttribs.DensityPerChannelGb].TRFCABNs - } -} - -func updateTRFCPB(memAttribs *memAttributes) { - if memAttribs.TRFCPBNs == 0 { - memAttribs.TRFCPBNs = densityGbPhysicalChannelToRefreshEncoding[memAttribs.DensityPerChannelGb].TRFCPBNs - } -} - -func updateTRCD(memAttribs *memAttributes) { - if memAttribs.TRCDMinNs == 0 { - /* JEDEC spec says max of 18ns */ - memAttribs.TRCDMinNs = 18 - } -} - -func updateTRPAB(memAttribs *memAttributes) { - if memAttribs.TRPABMinNs == 0 { - /* JEDEC spec says max of 21ns */ - memAttribs.TRPABMinNs = 21 - } -} - -func updateTRPPB(memAttribs *memAttributes) { - if memAttribs.TRPPBMinNs == 0 { - /* JEDEC spec says max of 18ns */ - memAttribs.TRPPBMinNs = 18 - } -} - -func normalizeMemoryAttributes(memAttribs *memAttributes) { - if currPlatform == PlatformTGLADL { - /* - * TGL does not really use physical organization of dies per package when - * generating the SPD. So, set it to 0 here so that deduplication ignores - * that field. - */ - memAttribs.DiesPerPackage = 0 - } -} - -func updateMemoryAttributes(memAttribs *memAttributes) error { - updateTCK(memAttribs) - if err := updateCAS(memAttribs); err != nil { - return err - } - if err := updateTAAMin(memAttribs); err != nil { - return err - } - updateTRFCAB(memAttribs) - updateTRFCPB(memAttribs) - updateTRCD(memAttribs) - updateTRPAB(memAttribs) - updateTRPPB(memAttribs) - - normalizeMemoryAttributes(memAttribs) - - return nil -} - -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") - fmt.Printf(" supported platforms: ") - keys := reflect.ValueOf(platformMap).MapKeys() - fmt.Println(keys) - fmt.Printf("\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++ { - if err := updateMemoryAttributes(&memParts.MemParts[i].Attribs); err != nil { - log.Fatal(err) - } - - if dedupeMemoryPart(dedupedParts, &memParts.MemParts[i]) == false { - generateSPD(&memParts.MemParts[i], SPDId, SPDDir) - SPDId++ - dedupedParts = append(dedupedParts, &memParts.MemParts[i]) - } - } - - if err := writeSPDManifest(&memParts, SPDDir); err != nil { - log.Fatal(err) - } -} diff --git a/util/spd_tools/lp4x/global_lp4x_mem_parts.json.txt b/util/spd_tools/lp4x/global_lp4x_mem_parts.json.txt deleted file mode 100644 index 68e241ac22..0000000000 --- a/util/spd_tools/lp4x/global_lp4x_mem_parts.json.txt +++ /dev/null @@ -1,344 +0,0 @@ -{ - "parts": [ - { - "name": "H9HCNNNBKMMLXR-NEE", - "attribs": { - "densityPerChannelGb": 8, - "banks": 8, - "channelsPerDie": 2, - "diesPerPackage": 1, - "bitWidthPerChannel": 16, - "ranksPerChannel": 1, - "speedMbps": 4267 - } - }, - { - "name": "H9HCNNNFAMMLXR-NEE", - "attribs": { - "densityPerChannelGb": 8, - "banks": 8, - "channelsPerDie": 4, - "diesPerPackage": 2, - "bitWidthPerChannel": 8, - "ranksPerChannel": 2, - "speedMbps": 4267 - } - }, - { - "name": "K4U6E3S4AA-MGCL", - "attribs": { - "densityPerChannelGb": 8, - "banks": 8, - "channelsPerDie": 2, - "diesPerPackage": 1, - "bitWidthPerChannel": 16, - "ranksPerChannel": 1, - "speedMbps": 4267 - } - }, - { - "name": "K4UBE3D4AA-MGCL", - "attribs": { - "densityPerChannelGb": 8, - "banks": 8, - "channelsPerDie": 2, - "diesPerPackage": 2, - "bitWidthPerChannel": 16, - "ranksPerChannel": 2, - "speedMbps": 4267 - } - }, - { - "name": "MT53E1G32D2NP-046 WT:A", - "attribs": { - "densityPerChannelGb": 16, - "banks": 8, - "channelsPerDie": 2, - "diesPerPackage": 1, - "bitWidthPerChannel": 16, - "ranksPerChannel": 1, - "speedMbps": 4267 - } - }, - { - "name": "MT53E1G32D2NP-046 WT:B", - "attribs": { - "densityPerChannelGb": 8, - "banks": 8, - "channelsPerDie": 2, - "diesPerPackage": 2, - "bitWidthPerChannel": 16, - "ranksPerChannel": 2, - "speedMbps": 4267 - } - }, - { - "name": "H9HKNNNCRMBVAR-NEH", - "attribs": { - "densityPerChannelGb": 8, - "banks": 8, - "channelsPerDie": 2, - "diesPerPackage": 2, - "bitWidthPerChannel": 16, - "ranksPerChannel": 1, - "speedMbps": 4267 - } - }, - { - "name": "MT53E1G64D4SQ-046 WT:A", - "attribs": { - "densityPerChannelGb": 16, - "banks": 8, - "channelsPerDie": 2, - "diesPerPackage": 2, - "bitWidthPerChannel": 16, - "ranksPerChannel": 1, - "speedMbps": 4267 - } - }, - { - "name": "MT53E512M32D2NP-046 WT:F", - "attribs": { - "densityPerChannelGb": 8, - "banks": 8, - "channelsPerDie": 2, - "diesPerPackage": 1, - "bitWidthPerChannel": 16, - "ranksPerChannel": 1, - "speedMbps": 4267 - } - }, - { - "name": "NT6AP256T32AV-J2", - "attribs": { - "densityPerChannelGb": 4, - "banks": 8, - "channelsPerDie": 2, - "diesPerPackage": 1, - "bitWidthPerChannel": 16, - "ranksPerChannel": 1, - "speedMbps": 3733, - "tckMaxPs": 1250, - "casLatencies": "14 20 24 28 32" - } - }, - { - "name": "K4U6E3S4AA-MGCR", - "attribs": { - "densityPerChannelGb": 8, - "banks": 8, - "channelsPerDie": 2, - "diesPerPackage": 1, - "bitWidthPerChannel": 16, - "ranksPerChannel": 1, - "speedMbps": 4267 - } - }, - { - "name": "MT53E512M32D2NP-046 WT:E", - "attribs": { - "densityPerChannelGb": 8, - "banks": 8, - "channelsPerDie": 2, - "diesPerPackage": 1, - "bitWidthPerChannel": 16, - "ranksPerChannel": 1, - "speedMbps": 4267 - } - }, - { - "name": "H9HCNNNCPMMLXR-NEE", - "attribs": { - "densityPerChannelGb": 8, - "banks": 8, - "channelsPerDie": 2, - "diesPerPackage": 2, - "bitWidthPerChannel": 16, - "ranksPerChannel": 2, - "speedMbps": 4267 - } - }, - { - "name": "K4UBE3D4AA-MGCR", - "attribs": { - "densityPerChannelGb": 8, - "banks": 8, - "channelsPerDie": 2, - "diesPerPackage": 2, - "bitWidthPerChannel": 16, - "ranksPerChannel": 2, - "speedMbps": 4267 - } - }, - { - "name": "MT53E512M64D4NW-046 WT:E", - "attribs": { - "densityPerChannelGb": 8, - "banks": 8, - "channelsPerDie": 2, - "diesPerPackage": 2, - "bitWidthPerChannel": 16, - "ranksPerChannel": 1, - "speedMbps": 4267 - } - }, - { - "name": "MT53E1G64D8NW-046 WT:E", - "attribs": { - "densityPerChannelGb": 8, - "banks": 8, - "channelsPerDie": 2, - "diesPerPackage": 4, - "bitWidthPerChannel": 16, - "ranksPerChannel": 2, - "speedMbps": 4267 - } - }, - { - "name": "H9HCNNNCRMBLPR-NEE", - "attribs": { - "densityPerChannelGb": 8, - "banks": 8, - "channelsPerDie": 2, - "diesPerPackage": 2, - "bitWidthPerChannel": 16, - "ranksPerChannel": 1, - "speedMbps": 4267 - } - }, - { - "name": "H9HCNNNFBMBLPR-NEE", - "attribs": { - "densityPerChannelGb": 8, - "banks": 8, - "channelsPerDie": 2, - "diesPerPackage": 4, - "bitWidthPerChannel": 16, - "ranksPerChannel": 2, - "speedMbps": 4267 - } - }, - { - "name": "MT53D1G64D4NW-046 WT:A", - "attribs": { - "densityPerChannelGb": 16, - "banks": 8, - "channelsPerDie": 2, - "diesPerPackage": 2, - "bitWidthPerChannel": 16, - "ranksPerChannel": 1, - "speedMbps": 4267 - } - }, - { - "name": "MT53D512M64D4NW-046 WT:F", - "attribs": { - "densityPerChannelGb": 8, - "banks": 8, - "channelsPerDie": 2, - "diesPerPackage": 2, - "bitWidthPerChannel": 16, - "ranksPerChannel": 1, - "speedMbps": 4267 - } - }, - { - "name": "NT6AP256T32AV-J1", - "attribs": { - "densityPerChannelGb": 4, - "banks": 8, - "channelsPerDie": 2, - "diesPerPackage": 1, - "bitWidthPerChannel": 16, - "ranksPerChannel": 1, - "speedMbps": 4267, - "tckMaxPs": 1250, - "casLatencies": "14 20 24 28 32 36" - } - }, - { - "name": "MT53E1G32D4NQ-046 WT:E", - "attribs": { - "densityPerChannelGb": 8, - "banks": 8, - "channelsPerDie": 2, - "diesPerPackage": 2, - "bitWidthPerChannel": 16, - "ranksPerChannel": 2, - "speedMbps": 4267 - } - }, - { - "name": "MT53E2G32D4NQ-046 WT:A", - "attribs": { - "densityPerChannelGb": 16, - "banks": 8, - "channelsPerDie": 2, - "diesPerPackage": 2, - "bitWidthPerChannel": 16, - "ranksPerChannel": 2, - "speedMbps": 4267 - } - }, - { - "name": "MT53E512M32D1NP-046 WT:B", - "attribs": { - "densityPerChannelGb": 8, - "banks": 8, - "channelsPerDie": 2, - "diesPerPackage": 1, - "bitWidthPerChannel": 16, - "ranksPerChannel": 1, - "speedMbps": 4267 - } - }, - { - "name": "H54G46CYRBX267", - "attribs": { - "densityPerChannelGb": 8, - "banks": 8, - "channelsPerDie": 2, - "diesPerPackage": 1, - "bitWidthPerChannel": 16, - "ranksPerChannel": 1, - "speedMbps": 4267 - } - }, - { - "name": "H54G56CYRBX247", - "attribs": { - "densityPerChannelGb": 8, - "banks": 8, - "channelsPerDie": 2, - "diesPerPackage": 2, - "bitWidthPerChannel": 16, - "ranksPerChannel": 2, - "speedMbps": 4267 - } - }, - { - "name": "K4U6E3S4AB-MGCL", - "attribs": { - "densityPerChannelGb": 8, - "banks": 8, - "channelsPerDie": 2, - "diesPerPackage": 1, - "bitWidthPerChannel": 16, - "ranksPerChannel": 1, - "speedMbps": 4267 - } - }, - { - "name": "K4UBE3D4AB-MGCL", - "attribs": { - "densityPerChannelGb": 8, - "banks": 8, - "channelsPerDie": 2, - "diesPerPackage": 2, - "bitWidthPerChannel": 16, - "ranksPerChannel": 2, - "speedMbps": 4267 - } - } - ] -} |