Furquan Shaikh has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/41612 )
Change subject: util/mb/google: Add spd_tools to generate SPDs for TGL boards ......................................................................
util/mb/google: Add spd_tools to generate SPDs for TGL boards
This change adds tools for generating SPD files for LPDDR4x memory used in memory down configurations on Intel Tiger Lake(TGL) based Chrome OS platforms. These tools generate SPDs following JESD209-4C specification and Intel recommendations(doc #616599) for LPDDR4x SPD.
Two tools are provided: * 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.
BUG=b:155239397,b:147321551
Change-Id: Ia9b64d1d48371ccea1c01630a33a245d90f45214 Signed-off-by: Furquan Shaikh furquan@google.com --- A util/mainboard/google/spd_tools/lp4x/README.md A util/mainboard/google/spd_tools/lp4x/gen_part_id.go A util/mainboard/google/spd_tools/lp4x/gen_spd.go 3 files changed, 1,247 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/12/41612/1
diff --git a/util/mainboard/google/spd_tools/lp4x/README.md b/util/mainboard/google/spd_tools/lp4x/README.md new file mode 100644 index 0000000..1a2cdd0 --- /dev/null +++ b/util/mainboard/google/spd_tools/lp4x/README.md @@ -0,0 +1,232 @@ +# LPDDR4x SPD tools README + +Tools for generating SPD files for LPDDR4x memory used in memory down +configurations on Intel Tiger Lake(TGL) based Chrome OS +platforms. These tools generate SPDs following JESD209-4C +specification and Intel recommendations(doc #616599) for LPDDR4x SPD. + +There are two tools provided that assist TGL-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: +* JSON file containing a global list of memory parts with their + attributes as per the datasheet (Argument: `--mem_list`). This is + the list of all known LPDDR4x memory parts irrespective of their + usage on the board. +* Pointer to directory where the generated SPD files and manifest will + be placed (Argument: `--spd_dir`). + +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. + +`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 logical channel. Logical + channel is considered as a 16-bit wide channel. Thus, this attribute + is expected to provide the density of a 16-wide logical + channel. Valid values: `6, 8, 12, 16` Gb. + +* `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` + +* `diesPerPackage`: Number of dies in the package: `SDP = 1`, `DDP = + 2`, `QDP = 4`, `ODP = 8`. + +* `bitWidthPerChannel`: Width of each physical channel. Valid values: + `8, 16` bits. + +* `ranksPerChannel`: Number of ranks per physical channel. Valid + values: `1, 2`. + +* `speedMbps`: Maximum data rate supported by the part in Mbps. Valid + values: `3200, 3733, 4267` Mbps. + +### Optional `attribs` + +* `tckPs`: 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 + +* `trfcabNs`: Minimum Refresh Recovery Delay Time (tRFCab) for all + banks in nanoseconds. As per JESD209-4C, this is dependent on the + density per channel (in this case density per logical + 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 (in this case density per logical + 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`. + +* `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": "EXAMPLE-MEMORY", + "attribs": { + "densityPerChannelGb": 8, + "banks": 8, + "channelsPerDie": 2, + "diesPerPackage": 2, + "bitWidthPerChannel": 16, + "ranksPerChannel": 1, + "speedMbps": 4267 + } + } +} +``` + +### 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 diretory 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. + +Sample output: +``` +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 + +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 <Path to store SPD files> --mem_list <Global list of memory parts> +# ./gen_part_id --spd_dir <Path where SPD files are stored> --mem_pars_used <List of parts used by board> -- makefile_dir <Path where Makefile.inc should be generated> +``` + +### Need to add a new memory part for a board? + +* If the memory part is not present in the global list of memory parts + as maintained by the reference board, 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` with updated changes and push a + CL for review. diff --git a/util/mainboard/google/spd_tools/lp4x/gen_part_id.go b/util/mainboard/google/spd_tools/lp4x/gen_part_id.go new file mode 100644 index 0000000..4e91b38 --- /dev/null +++ b/util/mainboard/google/spd_tools/lp4x/gen_part_id.go @@ -0,0 +1,208 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +package main + +import "encoding/csv" +import "flag" +import "fmt" +import "io" +import "io/ioutil" +import "log" +import "os" +import "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. + * 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. + * Pointer to Makefile directory. Makefile.inc generated by this program is placed in this + * location. + */ +var spdDirPtr = flag.String("spd_dir", "", "Directory containing SPD files and manifest") +var memPartListPtr = flag.String("mem_parts_used", "", + "File containing list of memory parts used by the board") +var makefileDirPtr = flag.String("makefile_dir", "", + "Directory where the generated Makefile.inc file should be placed") + +var spdManifestFileName = "spd_manifest.generated.txt" +var makefileName = "Makefile.inc" + +func checkArgs() { + if *spdDirPtr == "" { + log.Fatal("SPD directory not provided!\n") + } + + if *makefileDirPtr == "" { + log.Fatal("Makefile.inc directory not provided!\n") + } + + if *memPartListPtr == "" { + log.Fatal("List of memory parts not provided!\n") + } + + if _, err := os.Stat(*spdDirPtr); err != nil { + log.Fatal(err) + } + + if _, err := os.Stat(*makefileDirPtr); err != nil { + log.Fatal(err) + } + + if _,err := os.Stat(*memPartListPtr); err != nil { + log.Fatal(err) + } +} + +/* + * 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() []string { + lines, err := ioutil.ReadFile(*memPartListPtr) + if err != nil { + log.Fatal(err) + } + str := string(lines) + parts := strings.Split(str, "\n") + + return parts +} + +/* + * 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() (map[string]string, map[string]int) { + filePath := *spdDirPtr + "/" + spdManifestFileName + f, err := os.Open(filePath) + if err != nil { + log.Fatal(err) + } + defer f.Close() + r := csv.NewReader(f) + + partToSpdMap := make(map[string]string) + spdToIndexMap := make(map[string]int) + + for true { + fields, err := r.Read() + + if err == io.EOF { + break + } + + if err != nil { + log.Fatal(err) + } + + if len(fields) != 2 { + log.Fatal("CSV file is incorrectly formatted!\n") + } + + partToSpdMap[fields[0]] = fields[1] + + if _, ok := spdToIndexMap[fields[1]]; ok == false { + spdToIndexMap[fields[1]] = -1 + } + } + + return partToSpdMap, spdToIndexMap +} + +/* Print information about memory part used by variant and ID assigned to it. */ +func printPartIdInfo(partName string, index int) { + fmt.Printf("%-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) []partIds { + partIdList := []partIds{} + curId := 0 + + fmt.Printf("%-30s %s\n", "DRAM Part Name", "ID to assign") + for i := 0; i < len(parts); i++ { + if parts[i] == "" { + continue + } + + spdFileName,ok := partToSpdMap[parts[i]] + if ok == false { + log.Fatal("Failed to find part ", parts[i], " in SPD Manifest! Please add the part to global part list and regenerate SPD Manifest!\n") + } + + index := spdToIndexMap[spdFileName] + if index != -1 { + partIdList[index].memParts += ", " + parts[i] + printPartIdInfo(parts[i], index) + continue + } + + spdToIndexMap[spdFileName] = curId + + printPartIdInfo(parts[i], curId) + entry := partIds{spdFileName: spdFileName, memParts: parts[i]} + partIdList = append(partIdList, entry) + + curId++ + } + + return partIdList +} + +var generatedCodeLicense string = "## SPDX-License-Identifier: GPL-2.0-or-later" + +/* + * This function generates Makefile.inc under the variant directory path and adds assigned SPDs + * to SPD_SOURCES. + */ +func genMakefile(partIdList []partIds) { + filePath := *makefileDirPtr + "/" + makefileName + f, err := os.Create(filePath) + + if err != nil { + log.Fatal(err) + } + defer f.Close() + fmt.Fprintf(f, "%s\n\n", generatedCodeLicense) + fmt.Fprintf(f, "SPD_SOURCES =\n") + + for i := 0; i < len(partIdList); i++ { + fmt.Fprintf(f, "SPD_SOURCES += %s ", partIdList[i].spdFileName) + fmt.Fprintf(f, " # ID = %d(0b%04b) ", i, int64(i)) + fmt.Fprintf(f, " Parts = %04s\n", partIdList[i].memParts) + } +} + +func main() { + flag.Parse() + checkArgs() + + partToSpdMap, spdToIndexMap := readSpdManifest() + parts := readParts() + + partIdList := genPartIdInfo(parts, partToSpdMap, spdToIndexMap) + + genMakefile(partIdList) +} diff --git a/util/mainboard/google/spd_tools/lp4x/gen_spd.go b/util/mainboard/google/spd_tools/lp4x/gen_spd.go new file mode 100644 index 0000000..ac5603f --- /dev/null +++ b/util/mainboard/google/spd_tools/lp4x/gen_spd.go @@ -0,0 +1,807 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +package main + +import "bufio" +import "bytes" +import "encoding/csv" +import "encoding/json" +import "flag" +import "fmt" +import "io/ioutil" +import "log" +import "os" +import "reflect" +import "strconv" +import "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. + */ +var spdDirPtr = flag.String("spd_dir", "", "Directory to store SPD files and manifest") +var memPartListPtr = flag.String("mem_list", "", "File containing global list of memory parts with attributes") + +var spdManifestFileName = "spd_manifest.generated.txt" + +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 + TckPs int + TaaPs int + TrcdMinNs int + + /* CAS */ + CasLatencies string + casFirstByte byte + casSecondByte byte + casThirdByte byte +} + +func encodeSpdSize(memAttribs *memAttributes) byte { + /* + * From JEDEC spec: + * 6:4 (Bytes total) = 2 (512 bytes) + * 3:0 (Bytes used) = 3 (384 bytes) + * Set to 0x23 for LPDDR4x. + */ + return 0x23 +} + +func encodeSpdRevision(memAttribs *memAttributes) byte { + /* + * From JEDEC spec: Revision 1.1 + * Set to 0x11. + */ + return 0x11 +} + +func encodeMemoryType(memAttribs *memAttributes) byte { + /* LPDDR4x memory type = 0x11 */ + return 0x11 +} + +func encodeModuleType(memAttribs *memAttributes) byte { + /* + * 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. + */ + return 0x0e +} + +type densityParams struct { + densityEncoding byte + rowColumnEncoding byte + trfcabNs int + trfcpbNs int +} + +var densityGbToSPDEncoding = map[int]densityParams { + 6: { + densityEncoding: 0xb, + rowColumnEncoding: 0x21, /* 16 rows, 10 columns */ + trfcabNs: 280, + trfcpbNs: 140, + }, + 8: { + densityEncoding: 0x5, + rowColumnEncoding: 0x21, /* 16 rows, 10 columns */ + trfcabNs: 280, + trfcpbNs: 140, + }, + 12: { + densityEncoding: 0x8, + rowColumnEncoding: 0x29, /* 17 rows, 10 columns */ + trfcabNs: 380, + trfcpbNs: 190, + }, + 16: { + densityEncoding: 0x6, + rowColumnEncoding: 0x29, /* 17 rows, 10 columns */ + trfcabNs: 380, + trfcpbNs: 190, + }, +} + +type speedParams struct { + tckPs int + casFirstByte byte + casSecondByte byte + casThirdByte byte +} + +const ( + CAS_6 = 1 << 1 /* 10 - 266 MHz */ + CAS_10 = 1 << 4 /* 266 - 533 MHz */ + CAS_14 = 1 << 7 /* 533 - 800 MHz */ + CAS_20 = 1 << 2 /* 800 - 1066 MHz */ + CAS_24 = 1 << 4 /* 1066 - 1333 MHz */ + CAS_28 = 1 << 6 /* 1333 - 1600 MHz */ + CAS_32 = 1 << 0 /* 1600 - 1866 MHz */ + CAS_36 = 1 << 2 /* 1866 - 2133 MHz */ +) + +var speedMbpsToSpdEncoding = map[int]speedParams { + 4267: { + tckPs: 468, /* 1/4267 * 2 */ + casFirstByte: CAS_6 | CAS_10 | CAS_14, + casSecondByte: CAS_20 | CAS_24 | CAS_28, + casThirdByte: CAS_32 | CAS_36, + }, + 3733: { + tckPs: 535, /* 1/3733 * 2 */ + casFirstByte: CAS_6 | CAS_10 | CAS_14, + casSecondByte: CAS_20 | CAS_24 | CAS_28, + casThirdByte: CAS_32, + }, + 3200: { + tckPs: 625, /* 1/3200 * 2 */ + casFirstByte: CAS_6 | CAS_10 | CAS_14, + casSecondByte: CAS_20 | CAS_24 | CAS_28, + casThirdByte: 0, + }, +} + +func encodeDensity(densityPerChannelGb int) byte { + return densityGbToSPDEncoding[densityPerChannelGb].densityEncoding +} + +func encodeBanks(banks int) byte { + var temp byte + + if banks == 4 { + temp = 0 + } else if banks == 8 { + temp = 1 + } + + return temp << 4 +} + +func encodeDensityBanks(memAttribs *memAttributes) byte { + var b byte + + b = encodeDensity(memAttribs.DensityPerChannelGb) + b |= encodeBanks(memAttribs.Banks) + + return b +} + +func encodeSdramAddressing(memAttribs *memAttributes) byte { + return densityGbToSPDEncoding[memAttribs.DensityPerChannelGb].rowColumnEncoding +} + +func encodeChannelsPerDie(channels int) byte { + var temp byte + + temp = byte(channels >> 1) + + return temp << 2 +} + +func encodeDiesPerPackage(dies int) byte { + return (byte(dies) - 1) << 4 +} + +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 +} + +func encodePackageType(memAttribs *memAttributes) byte { + var b byte + + b = encodePackage(memAttribs.DiesPerPackage) /* Non-monolithic device */ + b |= 0x1 /* Signal Loading Matrix 1 */ + + b |= encodeChannelsPerDie(memAttribs.ChannelsPerDie) + b |= encodeDiesPerPackage(memAttribs.DiesPerPackage) + + return b +} + +func encodeOptionalFeatures(memAttribs *memAttributes) byte { + /* + * 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 + */ + return 0x08 +} + +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 +} + +func encodeBusWidth(memAttribs *memAttributes) byte { + /* + * As per advisory 616599: + * 7:5 (Number of system channels) = 000 (1 channel always) + * 2:0 (Bus width) = 001 (x16 always) + * Set to 0x01. + */ + return 0x01 +} + +func encodeSignalLoading(memAttribs *memAttributes) byte { + /* Unsure about this ??? Check with Intel!!! */ + return 0x48 +} + +func encodeTimebases(memAttribs *memAttributes) byte { + /* + * From JEDEC spec: + * 3:2 (MTB) = 00 (0.125ns) + * 1:0 (FTB) = 00 (1ps) + * Set to 0x00. + */ + return 0x00 +} + +func encodeTckMin(memAttribs *memAttributes) byte { + return convPsToMtbByte(memAttribs.TckPs) +} + +func encodeTckMinFineOffset(memAttribs *memAttributes) byte { + return convPsToFtbByte(memAttribs.TckPs) +} + +func encodeTckMax(memAttribs *memAttributes) byte { + /* + * 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. + */ + return 0xff +} + +func encodeTckMaxFineOffset(memAttribs *memAttributes) byte { + /* No fine offset for TckMax */ + return 0x00 +} + +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 { + /* All bits are reserved */ + return 0x00 +} + +func encodeReadWriteLatency(memAttribs *memAttributes) byte { + /* Write Latency Set A and Read Latency DBI-RD disabled. */ + return 0 +} + +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.TaaPs) +} + +func encodeTaaMinFineOffset(memAttribs *memAttributes) byte { + return convPsToFtbByte(memAttribs.TaaPs) +} + +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 + +const ( + SPD_INDEX_SIZE = 0 + SPD_INDEX_REVISION = 1 + SPD_INDEX_MEMORY_TYPE = 2 + SPD_INDEX_MODULE_TYPE = 3 + SPD_INDEX_DENSITY_BANKS = 4 + SPD_INDEX_ADDRESSING = 5 + SPD_INDEX_PACKAGE_TYPE = 6 + SPD_INDEX_OPTIONAL_FEATURES = 7 + SPD_INDEX_MODULE_ORGANIZATION = 12 + SPD_INDEX_BUS_WIDTH = 13 + SPD_INDEX_SIGNAL_LOADING = 16 + SPD_INDEX_TIMEBASES = 17 + SPD_INDEX_TCK_MIN = 18 + SPD_INDEX_TCK_MAX = 19 + SPD_INDEX_CAS_FIRST_BYTE = 20 + SPD_INDEX_CAS_SECOND_BYTE = 21 + SPD_INDEX_CAS_THIRD_BYTE = 22 + SPD_INDEX_CAS_FOURTH_BYTE = 23 + SPD_INDEX_TAA_MIN = 24 + SPD_INDEX_READ_WRITE_LATENCY = 25 + SPD_INDEX_TRCD_MIN = 26 + SPD_INDEX_TRPAB_MIN = 27 + SPD_INDEX_TRPPB_MIN = 28 + SPD_INDEX_TRFCAB_MIN_LSB = 29 + SPD_INDEX_TRFCAB_MIN_MSB = 30 + SPD_INDEX_TRFCPB_MIN_LSB = 31 + SPD_INDEX_TRFCPB_MIN_MSB = 32 + SPD_INDEX_TRPPB_MIN_FINE_OFFSET = 120 + SPD_INDEX_TRPAB_MIN_FINE_OFFSET = 121 + SPD_INDEX_TRCD_MIN_FINE_OFFSET = 122 + SPD_INDEX_TAA_MIN_FINE_OFFSET = 123 + SPD_INDEX_TCK_MAX_FINE_OFFSET = 124 + SPD_INDEX_TCK_MIN_FINE_OFFSET = 125 +) + +var spdAttribFuncTable = map[int]spdAttribFunc { + SPD_INDEX_SIZE: encodeSpdSize, + SPD_INDEX_REVISION: encodeSpdRevision, + SPD_INDEX_MEMORY_TYPE: encodeMemoryType, + SPD_INDEX_MODULE_TYPE: encodeModuleType, + SPD_INDEX_DENSITY_BANKS: encodeDensityBanks, + SPD_INDEX_ADDRESSING: encodeSdramAddressing, + SPD_INDEX_PACKAGE_TYPE: encodePackageType, + SPD_INDEX_OPTIONAL_FEATURES: encodeOptionalFeatures, + SPD_INDEX_MODULE_ORGANIZATION: encodeModuleOrganization, + SPD_INDEX_BUS_WIDTH: encodeBusWidth, + SPD_INDEX_SIGNAL_LOADING: encodeSignalLoading, + SPD_INDEX_TIMEBASES: encodeTimebases, + SPD_INDEX_TCK_MIN: encodeTckMin, + SPD_INDEX_TCK_MAX: encodeTckMax, + SPD_INDEX_TCK_MAX_FINE_OFFSET: encodeTckMaxFineOffset, + SPD_INDEX_TCK_MIN_FINE_OFFSET: encodeTckMinFineOffset, + SPD_INDEX_CAS_FIRST_BYTE: encodeCasFirstByte, + SPD_INDEX_CAS_SECOND_BYTE: encodeCasSecondByte, + SPD_INDEX_CAS_THIRD_BYTE: encodeCasThirdByte, + SPD_INDEX_CAS_FOURTH_BYTE: encodeCasFourthByte, + SPD_INDEX_TAA_MIN: encodeTaaMin, + SPD_INDEX_TAA_MIN_FINE_OFFSET: encodeTaaMinFineOffset, + SPD_INDEX_READ_WRITE_LATENCY: encodeReadWriteLatency, + SPD_INDEX_TRCD_MIN: encodeTrcdMin, + SPD_INDEX_TRCD_MIN_FINE_OFFSET: encodeTrcdMinFineOffset, + SPD_INDEX_TRPAB_MIN: encodeTrpabMin, + SPD_INDEX_TRPAB_MIN_FINE_OFFSET: encodeTrpabMinFineOffset, + SPD_INDEX_TRPPB_MIN: encodeTrppbMin, + SPD_INDEX_TRPPB_MIN_FINE_OFFSET: encodeTrppbMinFineOffset, + SPD_INDEX_TRFCAB_MIN_LSB: encodeTrfcabMinLsb, + SPD_INDEX_TRFCAB_MIN_MSB: encodeTrfcabMinMsb, + SPD_INDEX_TRFCPB_MIN_LSB: encodeTrfcpbMinLsb, + SPD_INDEX_TRFCPB_MIN_MSB: encodeTrfcpbMinMsb, +} + +type memParts struct { + MemParts []memPart `json:"parts"` +} + +type memPart struct { + Name string + Attribs memAttributes + spdFileName string +} + +func writeSpdManifest(memParts *memParts) { + filePath := *spdDirPtr + "/" + spdManifestFileName + f, err := os.Create(filePath) + + if err != nil { + log.Fatal(err) + } + defer f.Close() + w := csv.NewWriter(f) + + records := [][]string{} + + fmt.Printf("Generating SPD Manifest with following entries:\n") + + for i := 0; i < len(memParts.MemParts); i++ { + entry := []string{memParts.MemParts[i].Name, memParts.MemParts[i].spdFileName} + + records = append(records, entry) + fmt.Printf("%-40s %s\n", memParts.MemParts[i].Name, memParts.MemParts[i].spdFileName) + } + w.WriteAll(records) +} + +func getSpdByte(index int, memAttribs *memAttributes) byte { + f, ok := spdAttribFuncTable[index] + if ok == false { + return 0x00 + } + return f(memAttribs) +} + +func writeByteToFile(w *bufio.Writer, b *bytes.Buffer, c byte) { + temp, _ := b.ReadByte() + fmt.Fprintf(w, "%02X%c", temp, c) +} + +func writeSpd(fileName string, b bytes.Buffer) { + filePath := *spdDirPtr + "/" + fileName + f, err := os.Create(filePath) + + if err != nil { + log.Fatal(err) + } + defer f.Close() + w := bufio.NewWriter(f) + + for i := 0; i < 512; i += 16 { + for j := 0; j < 15; j++ { + writeByteToFile(w, &b, ' ') + } + writeByteToFile(w, &b, '\n') + } + + w.Flush() +} + +func createSpd(memAttribs *memAttributes) bytes.Buffer { + var b bytes.Buffer + + for i := 0; i < 512; i++ { + b.WriteByte(getSpdByte(i, memAttribs)) + } + + return b +} + +func generateSpd(dedupedParts []*memPart, memPart *memPart, spdId *int) bool { + for i := 0; i < len(dedupedParts); i++ { + if reflect.DeepEqual(dedupedParts[i].Attribs, memPart.Attribs) { + memPart.spdFileName = dedupedParts[i].spdFileName + return false + } + } + + b := createSpd(&memPart.Attribs) + memPart.spdFileName = fmt.Sprintf("spd-%d.hex", *spdId) + writeSpd(memPart.spdFileName, b) + + *spdId++ + return true +} + +func readMemoryParts(memParts *memParts) { + partsFile, err := os.Open(*memPartListPtr) + if err != nil { + log.Fatal(err) + } + defer partsFile.Close() + + databytes, _ := ioutil.ReadAll(partsFile) + + if err := json.Unmarshal(databytes, memParts); err != nil { + log.Fatal(err) + } +} + +func validateDensity(densityPerChannelGb int) { + if _, ok := densityGbToSPDEncoding[densityPerChannelGb]; ok == false { + log.Fatal("Incorrect density: ", densityPerChannelGb, "Gb!\n") + } +} + +func validateBanks(banks int) { + if banks != 4 && banks != 8 { + log.Fatal("Incorrect banks: ", banks, "!\n") + } +} + +func validateChannels(channels int) { + if channels != 1 && channels != 2 && channels != 4 { + log.Fatal("Incorrect channels per die: ", channels, "!\n") + } +} + +func validateDies(dies int) { + if dies > 8 || dies < 1 { + log.Fatal("Incorrect dies per package: ", dies, "!\n") + } +} + +func validateDataWidth(width int) { + if width != 8 && width != 16 { + log.Fatal("Incorrect bit width: ", width, "!\n") + } +} + +func validateRanks(ranks int) { + if ranks != 1 && ranks != 2 { + log.Fatal("Incorrect ranks: ", ranks, "!\n") + } +} + +func validateSpeed(speed int) { + if _, ok := speedMbpsToSpdEncoding[speed]; ok == false { + log.Fatal("Incorrect speed: ", speed, " Mbps!\n") + } +} + +func validateMemoryParts(memParts *memParts) { + for i := 0; i < len(memParts.MemParts); i++ { + validateDensity(memParts.MemParts[i].Attribs.DensityPerChannelGb) + validateBanks(memParts.MemParts[i].Attribs.Banks) + validateChannels(memParts.MemParts[i].Attribs.ChannelsPerDie) + validateDies(memParts.MemParts[i].Attribs.DiesPerPackage) + validateDataWidth(memParts.MemParts[i].Attribs.BitWidthPerChannel) + validateRanks(memParts.MemParts[i].Attribs.RanksPerChannel) + validateSpeed(memParts.MemParts[i].Attribs.SpeedMbps) + } +} + +func encodeLatencies(latency int, firstByte *byte, secondByte *byte, thirdByte *byte) { + switch latency { + case 6: + *firstByte |= CAS_6 + case 10: + *firstByte |= CAS_10 + case 14: + *firstByte |= CAS_14 + case 20: + *secondByte |= CAS_20 + case 24: + *secondByte |= CAS_24 + case 28: + *secondByte |= CAS_28 + case 32: + *thirdByte |= CAS_32 + case 36: + *thirdByte |= CAS_36 + default: + log.Fatal("Incorrect CAS Latency: ", latency, "!\n") + } +} + +func updateTck(memAttribs *memAttributes) { + if memAttribs.TckPs == 0 { + memAttribs.TckPs = speedMbpsToSpdEncoding[memAttribs.SpeedMbps].tckPs + } +} + +func updateCas(memAttribs *memAttributes) { + if len(memAttribs.CasLatencies) == 0 { + memAttribs.casFirstByte = speedMbpsToSpdEncoding[memAttribs.SpeedMbps].casFirstByte + memAttribs.casSecondByte = speedMbpsToSpdEncoding[memAttribs.SpeedMbps].casSecondByte + memAttribs.casThirdByte = speedMbpsToSpdEncoding[memAttribs.SpeedMbps].casThirdByte + } else { + latencies := strings.Fields(memAttribs.CasLatencies) + for i := 0; i < len(latencies); i++ { + latency,err := strconv.Atoi(latencies[i]) + if err != nil { + log.Fatal("Unable to convert latency ", latencies[i], "!\n") + } + encodeLatencies(latency, &memAttribs.casFirstByte, &memAttribs.casSecondByte, &memAttribs.casThirdByte) + } + } +} + +func getMinCas(memAttribs *memAttributes) int { + if (memAttribs.casThirdByte & CAS_36) != 0 { + return 36 + } + if (memAttribs.casThirdByte & CAS_32) != 0 { + return 32 + } + if (memAttribs.casSecondByte & CAS_28) != 0 { + return 28 + } + log.Fatal("Unexpected min CAS!\n") + return 0 +} + +func updateTaa(memAttribs *memAttributes) { + if memAttribs.TaaPs == 0 { + memAttribs.TaaPs = memAttribs.TckPs * getMinCas(memAttribs) + } +} + +func updateTrfcab(memAttribs *memAttributes) { + if memAttribs.TrfcabNs == 0 { + memAttribs.TrfcabNs = densityGbToSPDEncoding[memAttribs.DensityPerChannelGb].trfcabNs + } +} + +func updateTrfcpb(memAttribs *memAttributes) { + if memAttribs.TrfcpbNs == 0 { + memAttribs.TrfcpbNs = densityGbToSPDEncoding[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 updateMemoryAttributes(memAttribs *memAttributes) { + updateTck(memAttribs) + updateCas(memAttribs) + updateTaa(memAttribs) + updateTrfcab(memAttribs) + updateTrfcpb(memAttribs) + updateTrcd(memAttribs) + updateTrpab(memAttribs) + updateTrppb(memAttribs) +} + +func checkArgs() { + if *spdDirPtr == "" { + log.Fatal("SPD directory not provided!\n"); + } + + if *memPartListPtr == "" { + log.Fatal("Global memory part list not provided!\n"); + } + + if _, err := os.Stat(*spdDirPtr); err != nil { + log.Fatal(err) + } + + if _, err := os.Stat(*memPartListPtr); err != nil { + log.Fatal(err) + } +} + +func main() { + flag.Parse() + checkArgs() + + var memParts memParts + var dedupedParts []*memPart + + readMemoryParts(&memParts) + validateMemoryParts(&memParts) + + spdId := 1 + + for i := 0; i < len(memParts.MemParts); i++ { + updateMemoryAttributes(&memParts.MemParts[i].Attribs) + if generateSpd(dedupedParts, &memParts.MemParts[i], &spdId) == true { + dedupedParts = append(dedupedParts, &memParts.MemParts[i]) + } + } + + writeSpdManifest(&memParts) +}
build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/41612 )
Change subject: util/mb/google: Add spd_tools to generate SPDs for TGL boards ......................................................................
Patch Set 1:
(1 comment)
https://review.coreboot.org/c/coreboot/+/41612/1/util/mainboard/google/spd_t... File util/mainboard/google/spd_tools/lp4x/README.md:
https://review.coreboot.org/c/coreboot/+/41612/1/util/mainboard/google/spd_t... PS1, Line 145: `spd_manifest.generated.txt` and placed in the diretory provided 'diretory' may be misspelled - perhaps 'directory'?
Hello Nick Vaccaro, Dossym Nurmukhanov, Aaron Durbin,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/41612
to look at the new patch set (#2).
Change subject: util/mb/google: Add spd_tools to generate SPDs for TGL boards ......................................................................
util/mb/google: Add spd_tools to generate SPDs for TGL boards
This change adds tools for generating SPD files for LPDDR4x memory used in memory down configurations on Intel Tiger Lake(TGL) based Chrome OS platforms. These tools generate SPDs following JESD209-4C specification and Intel recommendations(doc #616599) for LPDDR4x SPD.
Two tools are provided: * 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.
BUG=b:155239397,b:147321551
Change-Id: Ia9b64d1d48371ccea1c01630a33a245d90f45214 Signed-off-by: Furquan Shaikh furquan@google.com --- A util/mainboard/google/spd_tools/lp4x/README.md A util/mainboard/google/spd_tools/lp4x/gen_part_id.go A util/mainboard/google/spd_tools/lp4x/gen_spd.go 3 files changed, 1,247 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/12/41612/2
Furquan Shaikh has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/41612 )
Change subject: util/mb/google: Add spd_tools to generate SPDs for TGL boards ......................................................................
Patch Set 2:
(1 comment)
https://review.coreboot.org/c/coreboot/+/41612/1/util/mainboard/google/spd_t... File util/mainboard/google/spd_tools/lp4x/README.md:
https://review.coreboot.org/c/coreboot/+/41612/1/util/mainboard/google/spd_t... PS1, Line 145: `spd_manifest.generated.txt` and placed in the diretory provided
'diretory' may be misspelled - perhaps 'directory'?
Done
Paul Menzel has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/41612 )
Change subject: util/mb/google: Add spd_tools to generate SPDs for TGL boards ......................................................................
Patch Set 2:
(4 comments)
Please add it under top level `util`.
Does the coreboot SDK need to be updated to provide a Go lang toolchain?
https://review.coreboot.org/c/coreboot/+/41612/2//COMMIT_MSG Commit Message:
https://review.coreboot.org/c/coreboot/+/41612/2//COMMIT_MSG@12 PS2, Line 12: recommendations(doc #616599) Please add a space.
https://review.coreboot.org/c/coreboot/+/41612/2/util/mainboard/google/spd_t... File util/mainboard/google/spd_tools/lp4x/README.md:
https://review.coreboot.org/c/coreboot/+/41612/2/util/mainboard/google/spd_t... PS2, Line 4: Intel Tiger Lake(TGL) Please add a space before (.
https://review.coreboot.org/c/coreboot/+/41612/2/util/mainboard/google/spd_t... PS2, Line 6: recommendations(doc #616599) Ditto.
https://review.coreboot.org/c/coreboot/+/41612/2/util/mainboard/google/spd_t... PS2, Line 134: ``` If possible, just indent code blocks by four spaces instead of using ```.
Duncan Laurie has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/41612 )
Change subject: util/mb/google: Add spd_tools to generate SPDs for TGL boards ......................................................................
Patch Set 2:
I'm out of my depth reviewing Go code, adding Ron in case he can or knows someone who can take a look.
Duncan Laurie has removed Paul Menzel from this change. ( https://review.coreboot.org/c/coreboot/+/41612 )
Change subject: util/mb/google: Add spd_tools to generate SPDs for TGL boards ......................................................................
Removed reviewer Paul Menzel.
Hello build bot (Jenkins), Duncan Laurie, Nick Vaccaro, Dossym Nurmukhanov, Aaron Durbin, Ron Minnich, Karthik Ramasubramanian,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/41612
to look at the new patch set (#3).
Change subject: util/mb/google: Add spd_tools to generate SPDs for TGL boards ......................................................................
util/mb/google: Add spd_tools to generate SPDs for TGL boards
This change adds tools for generating SPD files for LPDDR4x memory used in memory down configurations on Intel Tiger Lake(TGL) based Chrome OS platforms. These tools generate SPDs following JESD209-4C specification and Intel recommendations(doc #616599) for LPDDR4x SPD.
Two tools are provided: * 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.
BUG=b:155239397,b:147321551
Change-Id: Ia9b64d1d48371ccea1c01630a33a245d90f45214 Signed-off-by: Furquan Shaikh furquan@google.com --- A util/mainboard/google/spd_tools/lp4x/README.md A util/mainboard/google/spd_tools/lp4x/gen_part_id.go A util/mainboard/google/spd_tools/lp4x/gen_spd.go 3 files changed, 1,247 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/12/41612/3
ron minnich has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/41612 )
Change subject: util/mb/google: Add spd_tools to generate SPDs for TGL boards ......................................................................
Patch Set 3:
(18 comments)
https://review.coreboot.org/c/coreboot/+/41612/2/util/mainboard/google/spd_t... File util/mainboard/google/spd_tools/lp4x/README.md:
https://review.coreboot.org/c/coreboot/+/41612/2/util/mainboard/google/spd_t... PS2, Line 134: ```
If possible, just indent code blocks by four spaces instead of using ```.
yeah, but this is JSON, so does that apply?
https://review.coreboot.org/c/coreboot/+/41612/2/util/mainboard/google/spd_t... File util/mainboard/google/spd_tools/lp4x/gen_part_id.go:
https://review.coreboot.org/c/coreboot/+/41612/2/util/mainboard/google/spd_t... PS2, Line 5: import "encoding/csv" Go ahead and do this: import ( "encoding/csv" etc. etc. )
https://review.coreboot.org/c/coreboot/+/41612/2/util/mainboard/google/spd_t... PS2, Line 25: var spdDirPtr = flag.String("spd_dir", "", "Directory containing SPD files and manifest") it's also common here var ( spdDirPtr = whatever memPartListPart = whatever )
and so on. Thing of all the space you save :-)
https://review.coreboot.org/c/coreboot/+/41612/2/util/mainboard/google/spd_t... PS2, Line 35: if *spdDirPtr == "" { if a flag is not optional, I think it's not really a flag. It might be cleaner just to require it as a positional parameter.
calling log.Fatal everywhere is frowned upon. usually you return an error to main. Why? testing.
I'm hardly a paragon of virtue when it comes to testing, but that said, I think some tests would be good here.
I'm not even sure you absolutely need these stats here; is there harm done if you read the first two files and the last fails? probably not. Just wondering.
https://review.coreboot.org/c/coreboot/+/41612/2/util/mainboard/google/spd_t... PS2, Line 64: func readParts() []string { so here, for example: func readParts() ([]string, error)
if err != nil { return nil, err }
return parts, nil
https://review.coreboot.org/c/coreboot/+/41612/2/util/mainboard/google/spd_t... PS2, Line 83: func readSpdManifest() (map[string]string, map[string]int) { func readSpdManifest() (map[string]string, map[string]int, error)
https://review.coreboot.org/c/coreboot/+/41612/2/util/mainboard/google/spd_t... PS2, Line 95: for true { you can just say for https://play.golang.org/p/OqptsHybDRP
https://review.coreboot.org/c/coreboot/+/41612/2/util/mainboard/google/spd_t... PS2, Line 145: for i := 0; i < len(parts); i++ { for i := range parts
or, better, since you can avoid parts[i] everywhere for _, p := range parts { if p == "" { } etc.
https://review.coreboot.org/c/coreboot/+/41612/2/util/mainboard/google/spd_t... PS2, Line 151: if ok == false { if ! ok { }
https://review.coreboot.org/c/coreboot/+/41612/2/util/mainboard/google/spd_t... PS2, Line 181: filePath := *makefileDirPtr + "/" + makefileName The Go convention is all errors should be checked, and you are missing many here.
Suggestion: build a string via fmt.Sprintf: var s string s += fmt.Sprint(etc. etc.)
and then the last step if _, err := ioutil.WriteFile(filePath, []byte(string)) { return err }
this lets you blow off the create, the defer, and gets all your writes into one place in a way that's easy to check.
So the overall pattern
func genMakefile(partIdList []partIds) error { s := fmt.Sprintf("%s\n\n", generatedCodeLicense) 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(*makefileDirPtr, makefileName), []byte(s)) }
https://review.coreboot.org/c/coreboot/+/41612/2/util/mainboard/google/spd_t... File util/mainboard/google/spd_tools/lp4x/gen_spd.go:
https://review.coreboot.org/c/coreboot/+/41612/2/util/mainboard/google/spd_t... PS2, Line 5: import "bufio" same here, fix imports
https://review.coreboot.org/c/coreboot/+/41612/2/util/mainboard/google/spd_t... PS2, Line 63: func encodeSpdSize(memAttribs *memAttributes) byte { can't these just be const?
https://review.coreboot.org/c/coreboot/+/41612/2/util/mainboard/google/spd_t... PS2, Line 510: filePath := *spdDirPtr + "/" + spdManifestFileName always use filepath.Join
Consider using the pattern I showed for writing in that previous file.
https://review.coreboot.org/c/coreboot/+/41612/2/util/mainboard/google/spd_t... PS2, Line 546: filePath := *spdDirPtr + "/" + fileName always use filepath.Join
https://review.coreboot.org/c/coreboot/+/41612/2/util/mainboard/google/spd_t... PS2, Line 592: partsFile, err := os.Open(*memPartListPtr) you could, also, just use ioutil.ReadFile func ReadFile(filename string) ([]byte, error)
https://review.coreboot.org/c/coreboot/+/41612/2/util/mainboard/google/spd_t... PS2, Line 605: func validateDensity(densityPerChannelGb int) { return an error, then writing tests is easier
https://review.coreboot.org/c/coreboot/+/41612/2/util/mainboard/google/spd_t... PS2, Line 770: if *spdDirPtr == "" { I'd still argue fore positional arguments but...
https://review.coreboot.org/c/coreboot/+/41612/2/util/mainboard/google/spd_t... PS2, Line 794: readMemoryParts(&memParts) here is where you'd have if err := readMemoryParts(&memParts); err != nil { log.Fatal(err) }
note that the file read and write functions return errs with filename embedded: https://play.golang.org/p/N1LDiSghWy0
Hello build bot (Jenkins), Duncan Laurie, Nick Vaccaro, Dossym Nurmukhanov, Aaron Durbin, Ron Minnich, Karthik Ramasubramanian,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/41612
to look at the new patch set (#4).
Change subject: util/mb/google: Add spd_tools to generate SPDs for TGL boards ......................................................................
util/mb/google: Add spd_tools to generate SPDs for TGL boards
This change adds tools for generating SPD files for LPDDR4x memory used in memory down configurations on Intel Tiger Lake(TGL) based Chrome OS platforms. These tools generate SPDs following JESD209-4C specification and Intel recommendations(doc #616599) for LPDDR4x SPD.
Two tools are provided: * 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.
BUG=b:155239397,b:147321551
Change-Id: Ia9b64d1d48371ccea1c01630a33a245d90f45214 Signed-off-by: Furquan Shaikh furquan@google.com --- A util/mainboard/google/spd_tools/lp4x/README.md A util/mainboard/google/spd_tools/lp4x/gen_part_id.go A util/mainboard/google/spd_tools/lp4x/gen_spd.go 3 files changed, 1,247 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/12/41612/4
Furquan Shaikh has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/41612 )
Change subject: util/mb/google: Add spd_tools to generate SPDs for TGL boards ......................................................................
Patch Set 4:
(2 comments)
Patch Set 3:
(18 comments)
Thanks for all the helpful comments, Ron. I will work on these and push a patchset.
https://review.coreboot.org/c/coreboot/+/41612/2/util/mainboard/google/spd_t... File util/mainboard/google/spd_tools/lp4x/gen_part_id.go:
https://review.coreboot.org/c/coreboot/+/41612/2/util/mainboard/google/spd_t... PS2, Line 5: import "encoding/csv"
Go ahead and do this: […]
Done
https://review.coreboot.org/c/coreboot/+/41612/2/util/mainboard/google/spd_t... PS2, Line 25: var spdDirPtr = flag.String("spd_dir", "", "Directory containing SPD files and manifest")
it's also common here […]
Done
Hello build bot (Jenkins), Duncan Laurie, Nick Vaccaro, Dossym Nurmukhanov, Aaron Durbin, Ron Minnich, Karthik Ramasubramanian,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/41612
to look at the new patch set (#5).
Change subject: util/mb/google: Add spd_tools to generate SPDs for TGL boards ......................................................................
util/mb/google: Add spd_tools to generate SPDs for TGL boards
This change adds tools for generating SPD files for LPDDR4x memory used in memory down configurations on Intel Tiger Lake(TGL) based Chrome OS platforms. These tools generate SPDs following JESD209-4C specification and Intel recommendations(doc #616599) for LPDDR4x SPD.
Two tools are provided: * 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.
BUG=b:155239397,b:147321551
Change-Id: Ia9b64d1d48371ccea1c01630a33a245d90f45214 Signed-off-by: Furquan Shaikh furquan@google.com --- A util/spd_tools/intel/lp4x/README.md A util/spd_tools/intel/lp4x/gen_part_id.go A util/spd_tools/intel/lp4x/gen_spd.go 3 files changed, 1,252 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/12/41612/5
Furquan Shaikh has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/41612 )
Change subject: util/mb/google: Add spd_tools to generate SPDs for TGL boards ......................................................................
Patch Set 4:
(18 comments)
Patch Set 2:
(4 comments)
Please add it under top level `util`.
Done.
Does the coreboot SDK need to be updated to provide a Go lang toolchain?
I don't think so. We already have support for that.
https://review.coreboot.org/c/coreboot/+/41612/2/util/mainboard/google/spd_t... File util/mainboard/google/spd_tools/lp4x/README.md:
https://review.coreboot.org/c/coreboot/+/41612/2/util/mainboard/google/spd_t... PS2, Line 4: Intel Tiger Lake(TGL)
Please add a space before (.
Done
https://review.coreboot.org/c/coreboot/+/41612/2/util/mainboard/google/spd_t... PS2, Line 6: recommendations(doc #616599)
Ditto.
Done
https://review.coreboot.org/c/coreboot/+/41612/2/util/mainboard/google/spd_t... PS2, Line 134: ```
yeah, but this is JSON, so does that apply?
I think it is easier to read even in the MD format with the ```: https://review.coreboot.org/plugins/gitiles/coreboot/+/refs/changes/12/41612...
I am thinking of keeping this as is.
https://review.coreboot.org/c/coreboot/+/41612/2/util/mainboard/google/spd_t... File util/mainboard/google/spd_tools/lp4x/gen_part_id.go:
https://review.coreboot.org/c/coreboot/+/41612/2/util/mainboard/google/spd_t... PS2, Line 35: if *spdDirPtr == "" {
if a flag is not optional, I think it's not really a flag. […]
Done
https://review.coreboot.org/c/coreboot/+/41612/2/util/mainboard/google/spd_t... PS2, Line 64: func readParts() []string {
so here, for example: […]
Done
https://review.coreboot.org/c/coreboot/+/41612/2/util/mainboard/google/spd_t... PS2, Line 83: func readSpdManifest() (map[string]string, map[string]int) {
func readSpdManifest() (map[string]string, map[string]int, error)
Done
https://review.coreboot.org/c/coreboot/+/41612/2/util/mainboard/google/spd_t... PS2, Line 95: for true {
you can just say for […]
Done
https://review.coreboot.org/c/coreboot/+/41612/2/util/mainboard/google/spd_t... PS2, Line 145: for i := 0; i < len(parts); i++ {
for i := range parts […]
Done
https://review.coreboot.org/c/coreboot/+/41612/2/util/mainboard/google/spd_t... PS2, Line 151: if ok == false {
if ! ok { […]
Done
https://review.coreboot.org/c/coreboot/+/41612/2/util/mainboard/google/spd_t... PS2, Line 181: filePath := *makefileDirPtr + "/" + makefileName
The Go convention is all errors should be checked, and you are missing many here. […]
Done. Thanks that was very helpful.
https://review.coreboot.org/c/coreboot/+/41612/2/util/mainboard/google/spd_t... File util/mainboard/google/spd_tools/lp4x/gen_spd.go:
https://review.coreboot.org/c/coreboot/+/41612/2/util/mainboard/google/spd_t... PS2, Line 5: import "bufio"
same here, fix imports
Done
https://review.coreboot.org/c/coreboot/+/41612/2/util/mainboard/google/spd_t... PS2, Line 63: func encodeSpdSize(memAttribs *memAttributes) byte {
can't these just be const?
I went back and forth a little on this and decided to use functions to keep all byte handling consistent. I have changed these to const now.
https://review.coreboot.org/c/coreboot/+/41612/2/util/mainboard/google/spd_t... PS2, Line 510: filePath := *spdDirPtr + "/" + spdManifestFileName
always use filepath.Join […]
Done
https://review.coreboot.org/c/coreboot/+/41612/2/util/mainboard/google/spd_t... PS2, Line 546: filePath := *spdDirPtr + "/" + fileName
always use filepath. […]
Done
https://review.coreboot.org/c/coreboot/+/41612/2/util/mainboard/google/spd_t... PS2, Line 592: partsFile, err := os.Open(*memPartListPtr)
you could, also, just use ioutil.ReadFile […]
Done
https://review.coreboot.org/c/coreboot/+/41612/2/util/mainboard/google/spd_t... PS2, Line 605: func validateDensity(densityPerChannelGb int) {
return an error, then writing tests is easier
Done
https://review.coreboot.org/c/coreboot/+/41612/2/util/mainboard/google/spd_t... PS2, Line 770: if *spdDirPtr == "" {
I'd still argue fore positional arguments but...
Done
https://review.coreboot.org/c/coreboot/+/41612/2/util/mainboard/google/spd_t... PS2, Line 794: readMemoryParts(&memParts)
here is where you'd have […]
Done
Hello build bot (Jenkins), Duncan Laurie, Nick Vaccaro, Dossym Nurmukhanov, Aaron Durbin, Ron Minnich, Karthik Ramasubramanian,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/41612
to look at the new patch set (#6).
Change subject: util/mb/google: Add spd_tools to generate SPDs for TGL boards ......................................................................
util/mb/google: Add spd_tools to generate SPDs for TGL boards
This change adds tools for generating SPD files for LPDDR4x memory used in memory down configurations on Intel Tiger Lake (TGL) based Chrome OS platforms. These tools generate SPDs following JESD209-4C specification and Intel recommendations (doc #616599) for LPDDR4x SPD.
Two tools are provided: * 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.
BUG=b:155239397,b:147321551
Change-Id: Ia9b64d1d48371ccea1c01630a33a245d90f45214 Signed-off-by: Furquan Shaikh furquan@google.com --- A util/spd_tools/intel/lp4x/README.md A util/spd_tools/intel/lp4x/gen_part_id.go A util/spd_tools/intel/lp4x/gen_spd.go 3 files changed, 1,252 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/12/41612/6
Hello build bot (Jenkins), Duncan Laurie, Nick Vaccaro, Dossym Nurmukhanov, Aaron Durbin, Ron Minnich, Karthik Ramasubramanian,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/41612
to look at the new patch set (#7).
Change subject: util: Add spd_tools to generate SPDs for TGL boards ......................................................................
util: Add spd_tools to generate SPDs for TGL boards
This change adds tools for generating SPD files for LPDDR4x memory used in memory down configurations on Intel Tiger Lake (TGL) based Chrome OS platforms. These tools generate SPDs following JESD209-4C specification and Intel recommendations (doc #616599) for LPDDR4x SPD.
Two tools are provided: * 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.
BUG=b:155239397,b:147321551
Change-Id: Ia9b64d1d48371ccea1c01630a33a245d90f45214 Signed-off-by: Furquan Shaikh furquan@google.com --- A util/spd_tools/intel/lp4x/README.md A util/spd_tools/intel/lp4x/gen_part_id.go A util/spd_tools/intel/lp4x/gen_spd.go 3 files changed, 1,252 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/12/41612/7
Furquan Shaikh has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/41612 )
Change subject: util: Add spd_tools to generate SPDs for TGL boards ......................................................................
Patch Set 7:
(1 comment)
https://review.coreboot.org/c/coreboot/+/41612/2//COMMIT_MSG Commit Message:
https://review.coreboot.org/c/coreboot/+/41612/2//COMMIT_MSG@12 PS2, Line 12: recommendations(doc #616599)
Please add a space.
Done
ron minnich has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/41612 )
Change subject: util: Add spd_tools to generate SPDs for TGL boards ......................................................................
Patch Set 7:
(6 comments)
one more round and done.
We ought to consider putting some test files into here but this is nice stuff.
https://review.coreboot.org/c/coreboot/+/41612/7/util/spd_tools/intel/lp4x/g... File util/spd_tools/intel/lp4x/gen_part_id.go:
https://review.coreboot.org/c/coreboot/+/41612/7/util/spd_tools/intel/lp4x/g... PS7, Line 47: return fmt.Errorf("Incorrect number of arguments\n") The go convention is no puncutation (!) or newline characters, so probably best to remove the \n and ! below.
https://review.coreboot.org/c/coreboot/+/41612/7/util/spd_tools/intel/lp4x/g... PS7, Line 63: func readParts() ([]string, error) { for testing and other purposes, might be nicer if you could pass the file name into readParts: func readParts(name string) etc. etc.
Then you need not refer to a global in here.l Further, should you ever add flags back, os.Args would be the wrong thing to use anyway.
https://review.coreboot.org/c/coreboot/+/41612/7/util/spd_tools/intel/lp4x/g... PS7, Line 82: func readSpdManifest() (map[string]string, map[string]int, error) { same here, pass name in as a parameter.
Sorry I did not notice this last time.
https://review.coreboot.org/c/coreboot/+/41612/7/util/spd_tools/intel/lp4x/g... PS7, Line 135: spdToIndexMap map[string]int) ([]partIds, error) { up to you, but my personal preference is not to split lines this way. Go tends not to be fixated on line length :-)
https://review.coreboot.org/c/coreboot/+/41612/7/util/spd_tools/intel/lp4x/g... PS7, Line 188: return ioutil.WriteFile(filepath.Join(os.Args[MAKEFILE_DIR_ARG], makefileName), []byte(s), 0644) very nice, hope you like this too.
same caveat: pass the file name in as a parameter.
https://review.coreboot.org/c/coreboot/+/41612/7/util/spd_tools/intel/lp4x/g... File util/spd_tools/intel/lp4x/gen_spd.go:
https://review.coreboot.org/c/coreboot/+/41612/7/util/spd_tools/intel/lp4x/g... PS7, Line 72: 6: { unrelated note: felix held was complaining that clang-format formats superio struct inits this way, and now I see it here :-)
This is fine, I just think it's funny that none of us can agree on code formatting :-)
Hello build bot (Jenkins), Duncan Laurie, Nick Vaccaro, Dossym Nurmukhanov, Aaron Durbin, Ron Minnich, Karthik Ramasubramanian,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/41612
to look at the new patch set (#8).
Change subject: util: Add spd_tools to generate SPDs for TGL boards ......................................................................
util: Add spd_tools to generate SPDs for TGL boards
This change adds tools for generating SPD files for LPDDR4x memory used in memory down configurations on Intel Tiger Lake (TGL) based Chrome OS platforms. These tools generate SPDs following JESD209-4C specification and Intel recommendations (doc #616599) for LPDDR4x SPD.
Two tools are provided: * 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.
BUG=b:155239397,b:147321551
Change-Id: Ia9b64d1d48371ccea1c01630a33a245d90f45214 Signed-off-by: Furquan Shaikh furquan@google.com --- A util/spd_tools/intel/lp4x/README.md A util/spd_tools/intel/lp4x/gen_part_id.go A util/spd_tools/intel/lp4x/gen_spd.go 3 files changed, 1,251 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/12/41612/8
Furquan Shaikh has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/41612 )
Change subject: util: Add spd_tools to generate SPDs for TGL boards ......................................................................
Patch Set 8:
(5 comments)
Patch Set 7:
(6 comments)
one more round and done.
We ought to consider putting some test files into here but this is nice stuff.
Thanks for the helpful comments, Ron! I will look into adding test files as follow-up.
https://review.coreboot.org/c/coreboot/+/41612/7/util/spd_tools/intel/lp4x/g... File util/spd_tools/intel/lp4x/gen_part_id.go:
https://review.coreboot.org/c/coreboot/+/41612/7/util/spd_tools/intel/lp4x/g... PS7, Line 47: return fmt.Errorf("Incorrect number of arguments\n")
The go convention is no puncutation (!) or newline characters, so probably best to remove the \n and […]
Done
https://review.coreboot.org/c/coreboot/+/41612/7/util/spd_tools/intel/lp4x/g... PS7, Line 63: func readParts() ([]string, error) {
for testing and other purposes, might be nicer if you could pass the file name into readParts: […]
Done
https://review.coreboot.org/c/coreboot/+/41612/7/util/spd_tools/intel/lp4x/g... PS7, Line 82: func readSpdManifest() (map[string]string, map[string]int, error) {
same here, pass name in as a parameter. […]
Done
https://review.coreboot.org/c/coreboot/+/41612/7/util/spd_tools/intel/lp4x/g... PS7, Line 135: spdToIndexMap map[string]int) ([]partIds, error) {
up to you, but my personal preference is not to split lines this way. […]
Done
https://review.coreboot.org/c/coreboot/+/41612/7/util/spd_tools/intel/lp4x/g... PS7, Line 188: return ioutil.WriteFile(filepath.Join(os.Args[MAKEFILE_DIR_ARG], makefileName), []byte(s), 0644)
very nice, hope you like this too. […]
Done
Furquan Shaikh has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/41612 )
Change subject: util: Add spd_tools to generate SPDs for TGL boards ......................................................................
Patch Set 8:
(1 comment)
https://review.coreboot.org/c/coreboot/+/41612/2/util/mainboard/google/spd_t... File util/mainboard/google/spd_tools/lp4x/README.md:
https://review.coreboot.org/c/coreboot/+/41612/2/util/mainboard/google/spd_t... PS2, Line 134: ```
I think it is easier to read even in the MD format with the ```: https://review.coreboot. […]
Done
ron minnich has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/41612 )
Change subject: util: Add spd_tools to generate SPDs for TGL boards ......................................................................
Patch Set 8: Code-Review+2
(4 comments)
This would not pass the Go conventions but you are probably worn out on my carping, so I leave it up to you whether you'd like to do another pass or call it a day :-)
https://review.coreboot.org/c/coreboot/+/41612/8/util/spd_tools/intel/lp4x/g... File util/spd_tools/intel/lp4x/gen_part_id.go:
https://review.coreboot.org/c/coreboot/+/41612/8/util/spd_tools/intel/lp4x/g... PS8, Line 28: SPD_DIR_ARG = 1 So sorry I did not notice this. Go frowns on this type of constant. SPDDir would be fine, really. MakefileDir MempartsUsedFile
But there's a much easier way to do it.
In your main()
SPDDir, MakefileDir, MemParts := os.Args[0], os.Args[1], os.Args[2]
Then you can skip the constants, and it actually reduces the size by 2 lines :-)
Also, the convention is that acronyms are all caps ... SPD, not like UEFI Spd :-)
https://review.coreboot.org/c/coreboot/+/41612/8/util/spd_tools/intel/lp4x/g... PS8, Line 44: func checkArgs() error { Honest opinion here? I am not convinced you need this at all. in main() if len(os.Args) != 4 { log.Fatal("arg count message") }
SPDDir, MakefileDir, MemParts := os.Args[0], os.Args[1], os.Args[2]
is the os.Stat absolutely necessary? Could you just let the functions you call error out?
https://review.coreboot.org/c/coreboot/+/41612/8/util/spd_tools/intel/lp4x/g... File util/spd_tools/intel/lp4x/gen_spd.go:
https://review.coreboot.org/c/coreboot/+/41612/8/util/spd_tools/intel/lp4x/g... PS8, Line 28: SPD_DIR_ARG = 1 same comment re const names
https://review.coreboot.org/c/coreboot/+/41612/8/util/spd_tools/intel/lp4x/g... PS8, Line 438: SPD_INDEX_SIZE: { constVal: SPD_VALUE_SIZE }, also you could do SPDIndexSize but OTOH maybe this is the hardware name, in which case you'd get a pass :-)
Aaron Durbin has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/41612 )
Change subject: util: Add spd_tools to generate SPDs for TGL boards ......................................................................
Patch Set 8: Code-Review+1
(6 comments)
https://review.coreboot.org/c/coreboot/+/41612/3/util/mainboard/google/spd_t... File util/mainboard/google/spd_tools/lp4x/gen_spd.go:
https://review.coreboot.org/c/coreboot/+/41612/3/util/mainboard/google/spd_t... PS3, Line 280: Intel I only see this mention of Intel. Which fields are non-conforming to the JEDEC spec?
https://review.coreboot.org/c/coreboot/+/41612/3/util/mainboard/google/spd_t... PS3, Line 280: /* Unsure about this ??? Check with Intel!!! */ Is there a bug filed to get this info?
https://review.coreboot.org/c/coreboot/+/41612/3/util/mainboard/google/spd_t... PS3, Line 510: "/" os.PathSeparator
https://review.coreboot.org/c/coreboot/+/41612/3/util/mainboard/google/spd_t... PS3, Line 617: func validateChannels(channels int) { What is a channel in LPDDR4x? Likewise, what does datawidth represent? Per die?
https://review.coreboot.org/c/coreboot/+/41612/3/util/mainboard/google/spd_t... PS3, Line 700: encodeLatencies(latency, &memAttribs.casFirstByte, &memAttribs.casSecondByte, &memAttribs.casThirdByte) why not just pass the object pointer?
https://review.coreboot.org/c/coreboot/+/41612/3/util/mainboard/google/spd_t... PS3, Line 801: if generateSpd(dedupedParts, &memParts.MemParts[i], &spdId) == true { You could just return the new spdId value. Or just pull the dedupe check into its own function and call it from here.
Karthik Ramasubramanian has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/41612 )
Change subject: util: Add spd_tools to generate SPDs for TGL boards ......................................................................
Patch Set 8:
(4 comments)
https://review.coreboot.org/c/coreboot/+/41612/8/util/spd_tools/intel/lp4x/g... File util/spd_tools/intel/lp4x/gen_spd.go:
https://review.coreboot.org/c/coreboot/+/41612/8/util/spd_tools/intel/lp4x/g... PS8, Line 333: SPD_INDEX_OPTIONAL_FEATURES = 7 Probably want to encode byte 9 SDRAM optiona features as 0x80 or 0xc0? They reflect as reserved. '0' refers to Post Package Repair not supported.
https://review.coreboot.org/c/coreboot/+/41612/8/util/spd_tools/intel/lp4x/g... PS8, Line 335: SPD_INDEX_BUS_WIDTH = 13 I am not sure if none of the memory parts support Thermal sensor. If any of them support, probably want to consider encoding that byte(index 14).
https://review.coreboot.org/c/coreboot/+/41612/8/util/spd_tools/intel/lp4x/g... PS8, Line 407: SPD_VALUE_BUS_WIDTH = 0x01 W.r.t advisory 610202, this byte is different. I am not sure if there are different advisories for different SoCs. Probably want to accomodate that - one option might be to include SoC info in the global JSON file.
For example: In JSL, this byte corresponds to 0x22 i.e. Number of channels 2, Channel Bus Width 32 bits.
https://review.coreboot.org/c/coreboot/+/41612/8/util/spd_tools/intel/lp4x/g... PS8, Line 425: SPD_VALUE_TCK_MAX = 0xff Any impact of fixing on the max TCK? Is it a good candidate for optional attribute?
Karthik Ramasubramanian has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/41612 )
Change subject: util: Add spd_tools to generate SPDs for TGL boards ......................................................................
Patch Set 8:
(1 comment)
https://review.coreboot.org/c/coreboot/+/41612/8/util/spd_tools/intel/lp4x/R... File util/spd_tools/intel/lp4x/README.md:
https://review.coreboot.org/c/coreboot/+/41612/8/util/spd_tools/intel/lp4x/R... PS8, Line 46: densityPerChannelGb Is it the same as density per Die i.e. on a dual-die Package will this translate to Total Package Density = 2 * densityPerChannelGb?
The reason I am asking is MRC for JSL & ICL expects this to be density Per Die.
Aaron Durbin has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/41612 )
Change subject: util: Add spd_tools to generate SPDs for TGL boards ......................................................................
Patch Set 8:
(1 comment)
https://review.coreboot.org/c/coreboot/+/41612/8/util/spd_tools/intel/lp4x/g... File util/spd_tools/intel/lp4x/gen_spd.go:
https://review.coreboot.org/c/coreboot/+/41612/8/util/spd_tools/intel/lp4x/g... PS8, Line 407: SPD_VALUE_BUS_WIDTH = 0x01
W.r.t advisory 610202, this byte is different. […]
I had similar sentiments: we should drive the SoC expectations as a transformation of the main data supplied by the datasheets.
Hello build bot (Jenkins), Duncan Laurie, Nick Vaccaro, Dossym Nurmukhanov, Aaron Durbin, Karthik Ramasubramanian, ron minnich, Ron Minnich,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/41612
to look at the new patch set (#9).
Change subject: util: Add spd_tools to generate SPDs for TGL boards ......................................................................
util: Add spd_tools to generate SPDs for TGL boards
This change adds tools for generating SPD files for LPDDR4x memory used in memory down configurations on Intel Tiger Lake (TGL) based Chrome OS platforms. These tools generate SPDs following JESD209-4C specification and Intel recommendations (doc #616599) for LPDDR4x SPD.
Two tools are provided: * 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.
BUG=b:155239397,b:147321551
Change-Id: Ia9b64d1d48371ccea1c01630a33a245d90f45214 Signed-off-by: Furquan Shaikh furquan@google.com --- A util/spd_tools/intel/lp4x/README.md A util/spd_tools/intel/lp4x/gen_part_id.go A util/spd_tools/intel/lp4x/gen_spd.go 3 files changed, 1,229 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/12/41612/9
Furquan Shaikh has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/41612 )
Change subject: util: Add spd_tools to generate SPDs for TGL boards ......................................................................
Patch Set 9:
(12 comments)
https://review.coreboot.org/c/coreboot/+/41612/3/util/mainboard/google/spd_t... File util/mainboard/google/spd_tools/lp4x/gen_spd.go:
https://review.coreboot.org/c/coreboot/+/41612/3/util/mainboard/google/spd_t... PS3, Line 280: /* Unsure about this ??? Check with Intel!!! */
Is there a bug filed to get this info?
I have asked for clarification here: https://b.corp.google.com/issues/147321551#comment34
https://review.coreboot.org/c/coreboot/+/41612/3/util/mainboard/google/spd_t... PS3, Line 280: Intel
I only see this mention of Intel. […]
This is byte 16 (signal loading).
https://review.coreboot.org/c/coreboot/+/41612/3/util/mainboard/google/spd_t... PS3, Line 510: "/"
os. […]
This is fixed in latest patchset.
https://review.coreboot.org/c/coreboot/+/41612/3/util/mainboard/google/spd_t... PS3, Line 700: encodeLatencies(latency, &memAttribs.casFirstByte, &memAttribs.casSecondByte, &memAttribs.casThirdByte)
why not just pass the object pointer?
Done
https://review.coreboot.org/c/coreboot/+/41612/3/util/mainboard/google/spd_t... PS3, Line 801: if generateSpd(dedupedParts, &memParts.MemParts[i], &spdId) == true {
You could just return the new spdId value. […]
Done
https://review.coreboot.org/c/coreboot/+/41612/8/util/spd_tools/intel/lp4x/g... File util/spd_tools/intel/lp4x/gen_part_id.go:
https://review.coreboot.org/c/coreboot/+/41612/8/util/spd_tools/intel/lp4x/g... PS8, Line 28: SPD_DIR_ARG = 1
So sorry I did not notice this. Go frowns on this type of constant. […]
Done
https://review.coreboot.org/c/coreboot/+/41612/8/util/spd_tools/intel/lp4x/g... PS8, Line 44: func checkArgs() error {
Honest opinion here? I am not convinced you need this at all. […]
Done
https://review.coreboot.org/c/coreboot/+/41612/8/util/spd_tools/intel/lp4x/g... File util/spd_tools/intel/lp4x/gen_spd.go:
https://review.coreboot.org/c/coreboot/+/41612/8/util/spd_tools/intel/lp4x/g... PS8, Line 28: SPD_DIR_ARG = 1
same comment re const names
Done
https://review.coreboot.org/c/coreboot/+/41612/8/util/spd_tools/intel/lp4x/g... PS8, Line 333: SPD_INDEX_OPTIONAL_FEATURES = 7
Probably want to encode byte 9 SDRAM optiona features as 0x80 or 0xc0? They reflect as reserved. […]
As per what Intel mentioned, that byte is not really used by MRC: https://docs.google.com/spreadsheets/d/1LA4eoYuA1ANBX6N5-RC6UOSPQgeh4A0XcE5c...
https://review.coreboot.org/c/coreboot/+/41612/8/util/spd_tools/intel/lp4x/g... PS8, Line 335: SPD_INDEX_BUS_WIDTH = 13
I am not sure if none of the memory parts support Thermal sensor. […]
Byte 14 is not used by MRC: https://docs.google.com/spreadsheets/d/1LA4eoYuA1ANBX6N5-RC6UOSPQgeh4A0XcE5c...
https://review.coreboot.org/c/coreboot/+/41612/8/util/spd_tools/intel/lp4x/g... PS8, Line 425: SPD_VALUE_TCK_MAX = 0xff
Any impact of fixing on the max TCK? Is it a good candidate for optional attribute?
JEDEC spec says that max TCK should be 100ns. I see that all parts follow the same. I was thinking of keeping it as constant especially since we can't really encode 100ns in the SPD byte and instead have to stick to using 0xff i.e. 31.875ns. We can always make it optional if we see a part that needs a smaller value.
https://review.coreboot.org/c/coreboot/+/41612/8/util/spd_tools/intel/lp4x/g... PS8, Line 438: SPD_INDEX_SIZE: { constVal: SPD_VALUE_SIZE },
also you could do SPDIndexSize but OTOH maybe this is the hardware name, in which case you'd get a p […]
Done
Furquan Shaikh has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/41612 )
Change subject: util: Add spd_tools to generate SPDs for TGL boards ......................................................................
Patch Set 9:
(1 comment)
https://review.coreboot.org/c/coreboot/+/41612/8/util/spd_tools/intel/lp4x/g... File util/spd_tools/intel/lp4x/gen_spd.go:
https://review.coreboot.org/c/coreboot/+/41612/8/util/spd_tools/intel/lp4x/g... PS8, Line 407: SPD_VALUE_BUS_WIDTH = 0x01
I had similar sentiments: we should drive the SoC expectations as a transformation of the main data […]
I haven't yet addressed this. Looking at the advisory to see what all differs between TGL and JSL. I agree that it would be better to <encode JSON as per datasheet with no SoC specific encodings> and then use that data to generate SPDs differently for different SoCs as required.
Hello build bot (Jenkins), Duncan Laurie, Nick Vaccaro, Dossym Nurmukhanov, Aaron Durbin, Karthik Ramasubramanian, ron minnich, Ron Minnich,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/41612
to look at the new patch set (#10).
Change subject: util: Add spd_tools to generate SPDs for TGL boards ......................................................................
util: Add spd_tools to generate SPDs for TGL boards
This change adds tools for generating SPD files for LPDDR4x memory used in memory down configurations on Intel Tiger Lake (TGL) based Chrome OS platforms. These tools generate SPDs following JESD209-4C specification and Intel recommendations (doc #616599) for LPDDR4x SPD.
Two tools are provided: * 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.
BUG=b:155239397,b:147321551
Change-Id: Ia9b64d1d48371ccea1c01630a33a245d90f45214 Signed-off-by: Furquan Shaikh furquan@google.com --- A util/spd_tools/intel/lp4x/README.md A util/spd_tools/intel/lp4x/gen_part_id.go A util/spd_tools/intel/lp4x/gen_spd.go 3 files changed, 1,224 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/12/41612/10
Nick Vaccaro has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/41612 )
Change subject: util: Add spd_tools to generate SPDs for TGL boards ......................................................................
Patch Set 10:
(1 comment)
https://review.coreboot.org/c/coreboot/+/41612/10/util/spd_tools/intel/lp4x/... File util/spd_tools/intel/lp4x/README.md:
https://review.coreboot.org/c/coreboot/+/41612/10/util/spd_tools/intel/lp4x/... PS10, Line 65: SDRAM minimum cycle time What about SDRAM maximum cycle time?
Furquan Shaikh has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/41612 )
Change subject: util: Add spd_tools to generate SPDs for TGL boards ......................................................................
Patch Set 10:
(1 comment)
https://review.coreboot.org/c/coreboot/+/41612/10/util/spd_tools/intel/lp4x/... File util/spd_tools/intel/lp4x/README.md:
https://review.coreboot.org/c/coreboot/+/41612/10/util/spd_tools/intel/lp4x/... PS10, Line 65: SDRAM minimum cycle time
What about SDRAM maximum cycle time?
https://review.coreboot.org/c/coreboot/+/41612/8/util/spd_tools/intel/lp4x/g...
JEDEC spec says that max TCK should be 100ns. I see that all parts follow the same. I was thinking of keeping it as constant especially since we can't really encode 100ns in the SPD byte and instead have to stick to using 0xff i.e. 31.875ns.
Nick Vaccaro has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/41612 )
Change subject: util: Add spd_tools to generate SPDs for TGL boards ......................................................................
Patch Set 10: Code-Review+1
Aaron Durbin has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/41612 )
Change subject: util: Add spd_tools to generate SPDs for TGL boards ......................................................................
Patch Set 10: Code-Review+2
Furquan Shaikh has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/41612 )
Change subject: util: Add spd_tools to generate SPDs for TGL boards ......................................................................
Patch Set 12:
This change is ready for review.
Furquan Shaikh has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/41612 )
Change subject: util: Add spd_tools to generate SPDs for TGL boards ......................................................................
Patch Set 12:
(2 comments)
https://review.coreboot.org/c/coreboot/+/41612/8/util/spd_tools/intel/lp4x/g... File util/spd_tools/intel/lp4x/gen_spd.go:
https://review.coreboot.org/c/coreboot/+/41612/8/util/spd_tools/intel/lp4x/g... PS8, Line 407: SPD_VALUE_BUS_WIDTH = 0x01
I haven't yet addressed this. Looking at the advisory to see what all differs between TGL and JSL. […]
Done
https://review.coreboot.org/c/coreboot/+/41612/8/util/spd_tools/intel/lp4x/g... PS8, Line 425: SPD_VALUE_TCK_MAX = 0xff
I see that tckMax is 100ns for for Micron as per datasheet for MT53E512M32D2NP-046WT:F - Table 187. […]
Done
Furquan Shaikh has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/41612 )
Change subject: util: Add spd_tools to generate SPDs for TGL boards ......................................................................
Patch Set 12:
(5 comments)
https://review.coreboot.org/c/coreboot/+/41612/3/util/mainboard/google/spd_t... File util/mainboard/google/spd_tools/lp4x/gen_spd.go:
https://review.coreboot.org/c/coreboot/+/41612/3/util/mainboard/google/spd_t... PS3, Line 280: Intel
This is byte 16 (signal loading).
Checked MRC. This is not even a defined field in MRC structure. Dropping from the tool.
https://review.coreboot.org/c/coreboot/+/41612/3/util/mainboard/google/spd_t... PS3, Line 280: /* Unsure about this ??? Check with Intel!!! */
I have asked for clarification here: https://b.corp.google. […]
Done
https://review.coreboot.org/c/coreboot/+/41612/3/util/mainboard/google/spd_t... PS3, Line 617: func validateChannels(channels int) {
What is a channel in LPDDR4x? Likewise, what does datawidth represent? Per die?
Channel as input from the JSON file is the physical channel which can be x8 or x16. Datawidth is supposed to be per channel. Should there be more info/comments added to README or this file?
https://review.coreboot.org/c/coreboot/+/41612/8/util/spd_tools/intel/lp4x/g... File util/spd_tools/intel/lp4x/gen_spd.go:
https://review.coreboot.org/c/coreboot/+/41612/8/util/spd_tools/intel/lp4x/g... PS8, Line 333: SPD_INDEX_OPTIONAL_FEATURES = 7
You are looking at the right file. […]
I have left it as 0x00 for now. We can revisit this with Intel.
https://review.coreboot.org/c/coreboot/+/41612/8/util/spd_tools/intel/lp4x/g... PS8, Line 335: SPD_INDEX_BUS_WIDTH = 13
Byte 14 is not used by MRC: https://docs.google. […]
Left as 0x00.
Furquan Shaikh has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/41612 )
Change subject: util: Add spd_tools to generate SPDs for TGL boards ......................................................................
Patch Set 12:
(4 comments)
https://review.coreboot.org/c/coreboot/+/41612/8/util/spd_tools/intel/lp4x/R... File util/spd_tools/intel/lp4x/README.md:
https://review.coreboot.org/c/coreboot/+/41612/8/util/spd_tools/intel/lp4x/R... PS8, Line 46: densityPerChannelGb
Is it the same as density per Die i.e. […]
No, this is updated to density per physical channel in the latest patchset.
https://review.coreboot.org/c/coreboot/+/41612/10/util/spd_tools/intel/lp4x/... File util/spd_tools/intel/lp4x/README.md:
https://review.coreboot.org/c/coreboot/+/41612/10/util/spd_tools/intel/lp4x/... PS10, Line 65: SDRAM minimum cycle time
https://review.coreboot.org/c/coreboot/+/41612/8/util/spd_tools/intel/lp4x/g... […]
Done. Added as optional attribute.
https://review.coreboot.org/c/coreboot/+/41612/10/util/spd_tools/intel/lp4x/... PS10, Line 117: "diesPerPackage": 2,
Nit: diesPerPackage has been removed in the later patchset. We have to use channelsPerDie.
Added it back.
https://review.coreboot.org/c/coreboot/+/41612/10/util/spd_tools/intel/lp4x/... File util/spd_tools/intel/lp4x/gen_spd.go:
https://review.coreboot.org/c/coreboot/+/41612/10/util/spd_tools/intel/lp4x/... PS10, Line 119: CASFirstByte: CAS6 | CAS10 | CAS14,
This is not right. CAS is also dependent on byte-mode v/s x16 mode. […]
Done
Hello build bot (Jenkins), Shreesh Chhabbi, Ravishankar Sarawadi, Duncan Laurie, Nick Vaccaro, Dossym Nurmukhanov, Nick Vaccaro, Aamir Bohra, Aaron Durbin, Karthik Ramasubramanian, ron minnich, Ron Minnich,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/41612
to look at the new patch set (#13).
Change subject: util: Add spd_tools to generate SPDs for TGL and JSL boards ......................................................................
util: Add spd_tools to generate SPDs for TGL and JSL boards
This change adds tools for generating SPD files for LPDDR4x memory used in memory down configurations on Intel Tiger Lake (TGL) and Jasper Lake (JSL) based platforms. These tools generate SPDs following JESD209-4C specification and Intel recommendations (doc #616599,
Two tools are provided: * 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.
BUG=b:155239397,b:147321551
Change-Id: Ia9b64d1d48371ccea1c01630a33a245d90f45214 Signed-off-by: Furquan Shaikh furquan@google.com --- A util/spd_tools/intel/lp4x/README.md A util/spd_tools/intel/lp4x/gen_part_id.go A util/spd_tools/intel/lp4x/gen_spd.go 3 files changed, 1,444 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/12/41612/13
Karthik Ramasubramanian has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/41612 )
Change subject: util: Add spd_tools to generate SPDs for TGL and JSL boards ......................................................................
Patch Set 14: Code-Review+2
Karthik Ramasubramanian has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/41612 )
Change subject: util: Add spd_tools to generate SPDs for TGL and JSL boards ......................................................................
Patch Set 14:
(1 comment)
https://review.coreboot.org/c/coreboot/+/41612/14/util/spd_tools/intel/lp4x/... File util/spd_tools/intel/lp4x/gen_part_id.go:
https://review.coreboot.org/c/coreboot/+/41612/14/util/spd_tools/intel/lp4x/... PS14, Line 177: MEM_TYPE = lp4x Any significance of this makefile variable? I am not seeing it being used in volteer or dedede unless I missed something.
Furquan Shaikh has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/41612 )
Change subject: util: Add spd_tools to generate SPDs for TGL and JSL boards ......................................................................
Patch Set 14:
(1 comment)
https://review.coreboot.org/c/coreboot/+/41612/14/util/spd_tools/intel/lp4x/... File util/spd_tools/intel/lp4x/gen_part_id.go:
https://review.coreboot.org/c/coreboot/+/41612/14/util/spd_tools/intel/lp4x/... PS14, Line 177: MEM_TYPE = lp4x
Any significance of this makefile variable? I am not seeing it being used in volteer or dedede unles […]
I used it here: https://review.coreboot.org/c/coreboot/+/41881/3/src/mainboard/google/dedede...
I don't really like it though. If you think its too brittle, I can drop it.
Karthik Ramasubramanian has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/41612 )
Change subject: util: Add spd_tools to generate SPDs for TGL and JSL boards ......................................................................
Patch Set 14:
(1 comment)
https://review.coreboot.org/c/coreboot/+/41612/14/util/spd_tools/intel/lp4x/... File util/spd_tools/intel/lp4x/gen_part_id.go:
https://review.coreboot.org/c/coreboot/+/41612/14/util/spd_tools/intel/lp4x/... PS14, Line 177: MEM_TYPE = lp4x
I used it here: https://review.coreboot. […]
I am not sure about plans to support other types of memory technologies and how their SPDs are going to be managed. Hence I have no preference either way.
Hello build bot (Jenkins), Shreesh Chhabbi, Ravishankar Sarawadi, Duncan Laurie, Nick Vaccaro, Dossym Nurmukhanov, Nick Vaccaro, Aamir Bohra, Aaron Durbin, Karthik Ramasubramanian, ron minnich, Ron Minnich,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/41612
to look at the new patch set (#15).
Change subject: util: Add spd_tools to generate SPDs for TGL and JSL boards ......................................................................
util: Add spd_tools to generate SPDs for TGL and JSL boards
This change adds tools for generating SPD files for LPDDR4x memory used in memory down configurations on Intel Tiger Lake (TGL) and Jasper Lake (JSL) based platforms. These tools generate SPDs following JESD209-4C specification and Intel recommendations (doc #616599,
Two tools are provided: * 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.
BUG=b:155239397,b:147321551
Change-Id: Ia9b64d1d48371ccea1c01630a33a245d90f45214 Signed-off-by: Furquan Shaikh furquan@google.com --- A util/spd_tools/intel/lp4x/README.md A util/spd_tools/intel/lp4x/gen_part_id.go A util/spd_tools/intel/lp4x/gen_spd.go 3 files changed, 1,443 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/12/41612/15
Furquan Shaikh has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/41612 )
Change subject: util: Add spd_tools to generate SPDs for TGL and JSL boards ......................................................................
Patch Set 15:
(1 comment)
https://review.coreboot.org/c/coreboot/+/41612/14/util/spd_tools/intel/lp4x/... File util/spd_tools/intel/lp4x/gen_part_id.go:
https://review.coreboot.org/c/coreboot/+/41612/14/util/spd_tools/intel/lp4x/... PS14, Line 177: MEM_TYPE = lp4x
I am not sure about plans to support other types of memory technologies and how their SPDs are going […]
I dropped this. I didn't really like it much.
Furquan Shaikh has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/41612 )
Change subject: util: Add spd_tools to generate SPDs for TGL and JSL boards ......................................................................
Patch Set 16:
This change is ready for review.
Hello build bot (Jenkins), Shreesh Chhabbi, Ravishankar Sarawadi, Duncan Laurie, Nick Vaccaro, Dossym Nurmukhanov, Nick Vaccaro, Aamir Bohra, Aaron Durbin, Karthik Ramasubramanian, ron minnich, Ron Minnich,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/41612
to look at the new patch set (#17).
Change subject: util: Add spd_tools to generate SPDs for TGL and JSL boards ......................................................................
util: Add spd_tools to generate SPDs for TGL and JSL boards
This change adds tools for generating SPD files for LPDDR4x memory used in memory down configurations on Intel Tiger Lake (TGL) and Jasper Lake (JSL) based platforms. These tools generate SPDs following JESD209-4C specification and Intel recommendations (doc #616599,
Two tools are provided: * 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.
BUG=b:155239397,b:147321551
Change-Id: Ia9b64d1d48371ccea1c01630a33a245d90f45214 Signed-off-by: Furquan Shaikh furquan@google.com --- A util/spd_tools/intel/lp4x/README.md A util/spd_tools/intel/lp4x/gen_part_id.go A util/spd_tools/intel/lp4x/gen_spd.go 3 files changed, 1,450 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/12/41612/17
Paul Menzel has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/41612 )
Change subject: util: Add spd_tools to generate SPDs for TGL and JSL boards ......................................................................
Patch Set 17:
(4 comments)
https://review.coreboot.org/c/coreboot/+/41612/17//COMMIT_MSG Commit Message:
https://review.coreboot.org/c/coreboot/+/41612/17//COMMIT_MSG@8 PS17, Line 8: Add an introduction stating, that current SPD files are incorrect in some places?
https://review.coreboot.org/c/coreboot/+/41612/17//COMMIT_MSG@12 PS17, Line 12: JESD209-4C specification and Intel recommendations (doc #616599, Is there a doc number missing? Closing ) is missing.
From the `README.md`, I’d assume *#610202)*.
https://review.coreboot.org/c/coreboot/+/41612/17/util/spd_tools/intel/lp4x/... File util/spd_tools/intel/lp4x/README.md:
https://review.coreboot.org/c/coreboot/+/41612/17/util/spd_tools/intel/lp4x/... PS17, Line 255: gen_spd.go Mark up as code with `x`?
https://review.coreboot.org/c/coreboot/+/41612/17/util/spd_tools/intel/lp4x/... PS17, Line 259: board(variant) I’d add a space before (.
Paul Menzel has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/41612 )
Change subject: util: Add spd_tools to generate SPDs for TGL and JSL boards ......................................................................
Patch Set 17:
By the way, thank you for writing these tools to avoid errors in manually created files. An announcement to the list about these cool tools would be great.
Hello build bot (Jenkins), Shreesh Chhabbi, Ravishankar Sarawadi, Duncan Laurie, Nick Vaccaro, Dossym Nurmukhanov, Nick Vaccaro, Aamir Bohra, Aaron Durbin, Karthik Ramasubramanian, ron minnich, Ron Minnich,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/41612
to look at the new patch set (#18).
Change subject: util: Add spd_tools to generate SPDs for TGL and JSL boards ......................................................................
util: Add spd_tools to generate SPDs for TGL and JSL boards
Serial Presence Detect (SPD) data for memory modules is used by Memory Reference Code (MRC) for training the memory. This SPD data is typically obtained from part vendors but has to be massaged to format it correctly as per JEDEC and MRC expectations. There have been numerous times in the past where the SPD data used is not always correct.
In order to reduce the manual effort of creating SPDs and generating DRAM IDs, this change adds tools for generating SPD files for LPDDR4x memory used in memory down configurations on Intel Tiger Lake (TGL) and Jasper Lake (JSL) based platforms. These tools generate SPDs following JESD209-4C specification and Intel recommendations (doc
Two tools are provided: * 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.
BUG=b:155239397,b:147321551
Change-Id: Ia9b64d1d48371ccea1c01630a33a245d90f45214 Signed-off-by: Furquan Shaikh furquan@google.com --- A util/spd_tools/intel/lp4x/README.md A util/spd_tools/intel/lp4x/gen_part_id.go A util/spd_tools/intel/lp4x/gen_spd.go 3 files changed, 1,450 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/12/41612/18
Furquan Shaikh has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/41612 )
Change subject: util: Add spd_tools to generate SPDs for TGL and JSL boards ......................................................................
Patch Set 18:
(4 comments)
https://review.coreboot.org/c/coreboot/+/41612/17//COMMIT_MSG Commit Message:
https://review.coreboot.org/c/coreboot/+/41612/17//COMMIT_MSG@8 PS17, Line 8:
Add an introduction stating, that current SPD files are incorrect in some places?
Done
https://review.coreboot.org/c/coreboot/+/41612/17//COMMIT_MSG@12 PS17, Line 12: JESD209-4C specification and Intel recommendations (doc #616599,
Is there a doc number missing? Closing ) is missing. […]
Done
https://review.coreboot.org/c/coreboot/+/41612/17/util/spd_tools/intel/lp4x/... File util/spd_tools/intel/lp4x/README.md:
https://review.coreboot.org/c/coreboot/+/41612/17/util/spd_tools/intel/lp4x/... PS17, Line 255: gen_spd.go
Mark up as code with `x`?
Done
https://review.coreboot.org/c/coreboot/+/41612/17/util/spd_tools/intel/lp4x/... PS17, Line 259: board(variant)
I’d add a space before (.
Done
Hello build bot (Jenkins), Shreesh Chhabbi, Ravishankar Sarawadi, Duncan Laurie, Nick Vaccaro, Dossym Nurmukhanov, Nick Vaccaro, Aamir Bohra, Aaron Durbin, Karthik Ramasubramanian, ron minnich, Ron Minnich,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/41612
to look at the new patch set (#19).
Change subject: util: Add spd_tools to generate SPDs for TGL and JSL boards ......................................................................
util: Add spd_tools to generate SPDs for TGL and JSL boards
Serial Presence Detect (SPD) data for memory modules is used by Memory Reference Code (MRC) for training the memory. This SPD data is typically obtained from part vendors but has to be massaged to format it correctly as per JEDEC and MRC expectations. There have been numerous times in the past where the SPD data used is not always correct.
In order to reduce the manual effort of creating SPDs and generating DRAM IDs, this change adds tools for generating SPD files for LPDDR4x memory used in memory down configurations on Intel Tiger Lake (TGL) and Jasper Lake (JSL) based platforms. These tools generate SPDs following JESD209-4C specification and Intel recommendations (doc
Two tools are provided: * 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.
BUG=b:155239397,b:147321551
Change-Id: Ia9b64d1d48371ccea1c01630a33a245d90f45214 Signed-off-by: Furquan Shaikh furquan@google.com --- A util/spd_tools/intel/lp4x/README.md A util/spd_tools/intel/lp4x/gen_part_id.go A util/spd_tools/intel/lp4x/gen_spd.go 3 files changed, 1,450 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/12/41612/19
Nick Vaccaro has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/41612 )
Change subject: util: Add spd_tools to generate SPDs for TGL and JSL boards ......................................................................
Patch Set 19: Code-Review+2
Karthik Ramasubramanian has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/41612 )
Change subject: util: Add spd_tools to generate SPDs for TGL and JSL boards ......................................................................
Patch Set 19: Code-Review+2
Furquan Shaikh has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/41612 )
Change subject: util: Add spd_tools to generate SPDs for TGL and JSL boards ......................................................................
Patch Set 19:
(1 comment)
https://review.coreboot.org/c/coreboot/+/41612/3/util/mainboard/google/spd_t... File util/mainboard/google/spd_tools/lp4x/gen_spd.go:
https://review.coreboot.org/c/coreboot/+/41612/3/util/mainboard/google/spd_t... PS3, Line 617: func validateChannels(channels int) {
Channel as input from the JSON file is the physical channel which can be x8 or x16. […]
Added more details to README.md
Furquan Shaikh has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/41612 )
Change subject: util: Add spd_tools to generate SPDs for TGL and JSL boards ......................................................................
Patch Set 20:
Patch Set 17:
By the way, thank you for writing these tools to avoid errors in manually created files. An announcement to the list about these cool tools would be great.
Added to release notes here: https://review.coreboot.org/c/coreboot/+/42092
Patrick Georgi has submitted this change. ( https://review.coreboot.org/c/coreboot/+/41612 )
Change subject: util: Add spd_tools to generate SPDs for TGL and JSL boards ......................................................................
util: Add spd_tools to generate SPDs for TGL and JSL boards
Serial Presence Detect (SPD) data for memory modules is used by Memory Reference Code (MRC) for training the memory. This SPD data is typically obtained from part vendors but has to be massaged to format it correctly as per JEDEC and MRC expectations. There have been numerous times in the past where the SPD data used is not always correct.
In order to reduce the manual effort of creating SPDs and generating DRAM IDs, this change adds tools for generating SPD files for LPDDR4x memory used in memory down configurations on Intel Tiger Lake (TGL) and Jasper Lake (JSL) based platforms. These tools generate SPDs following JESD209-4C specification and Intel recommendations (doc
Two tools are provided: * 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.
BUG=b:155239397,b:147321551
Change-Id: Ia9b64d1d48371ccea1c01630a33a245d90f45214 Signed-off-by: Furquan Shaikh furquan@google.com Reviewed-on: https://review.coreboot.org/c/coreboot/+/41612 Tested-by: build bot (Jenkins) no-reply@coreboot.org Reviewed-by: Nick Vaccaro nvaccaro@google.com Reviewed-by: Karthik Ramasubramanian kramasub@google.com --- A util/spd_tools/intel/lp4x/README.md A util/spd_tools/intel/lp4x/gen_part_id.go A util/spd_tools/intel/lp4x/gen_spd.go 3 files changed, 1,450 insertions(+), 0 deletions(-)
Approvals: build bot (Jenkins): Verified Nick Vaccaro: Looks good to me, approved Karthik Ramasubramanian: Looks good to me, approved
diff --git a/util/spd_tools/intel/lp4x/README.md b/util/spd_tools/intel/lp4x/README.md new file mode 100644 index 0000000..e614f25 --- /dev/null +++ b/util/spd_tools/intel/lp4x/README.md @@ -0,0 +1,265 @@ +# LPDDR4x SPD tools README + +Tools for generating SPD files for LPDDR4x memory used in memory down +configurations on Intel Tiger Lake (TGL) and Jasper Lake (JSL) based +platforms. These tools generate SPDs following JESD209-4C +specification and Intel recommendations (doc #616599, #610202) for +LPDDR4x SPD. + +There are two tools provided that assist TGL and JSL 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` and `JSL`. + +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/intel/lp4x/gen_part_id.go b/util/spd_tools/intel/lp4x/gen_part_id.go new file mode 100644 index 0000000..6c2ca11 --- /dev/null +++ b/util/spd_tools/intel/lp4x/gen_part_id.go @@ -0,0 +1,214 @@ +/* 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 = "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/intel/lp4x/gen_spd.go b/util/spd_tools/intel/lp4x/gen_spd.go new file mode 100644 index 0000000..acdc265 --- /dev/null +++ b/util/spd_tools/intel/lp4x/gen_spd.go @@ -0,0 +1,971 @@ +/* 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 = "spd_manifest.generated.txt" + + PlatformTGL = 0 + PlatformJSL = 1 +) + +var platformMap = map[string]int { + "TGL": PlatformTGL, + "JSL": PlatformJSL, +} + +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 == PlatformTGL { + /* + * 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 { + /* + * 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 +} + +func encodeDiesPerPackage(memAttribs *memAttributes) byte { + var dies int = 0 + if currPlatform == PlatformTGL { + /* Intel MRC expects logical dies to be encoded for TGL. */ + dies = memAttribs.ChannelsPerDie * memAttribs.RanksPerChannel * memAttribs.BitWidthPerChannel / 16 + } else if currPlatform == PlatformJSL { + /* Intel MRC expects physical dies to be encoded for JSL. */ + 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 == PlatformTGL { + return SPDValueBusWidthTGL + } else if currPlatform == PlatformJSL { + 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 + + /* 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 +) + +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 getSPDByte(index int, memAttribs *memAttributes) byte { + e, ok := SPDAttribTable[index] + if ok == false { + 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("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 == PlatformTGL { + /* + * 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\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) + } +}
9elements QA has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/41612 )
Change subject: util: Add spd_tools to generate SPDs for TGL and JSL boards ......................................................................
Patch Set 21:
Automatic boot test returned (PASS/FAIL/TOTAL): 4/0/4 Emulation targets: "QEMU x86 q35/ich9" using payload TianoCore : SUCCESS : https://lava.9esec.io/r/5161 "QEMU x86 q35/ich9" using payload SeaBIOS : SUCCESS : https://lava.9esec.io/r/5160 "QEMU x86 i440fx/piix4" using payload SeaBIOS : SUCCESS : https://lava.9esec.io/r/5159 "QEMU AArch64" using payload LinuxBoot_u-root_kexec : SUCCESS : https://lava.9esec.io/r/5158
Please note: This test is under development and might not be accurate at all!