bug=b:260128250 TEST=none Change-Id: I412044a13f636e87db1d2266b33c9134e746e1a2 Signed-off-by: Nick Vaccaro <nvaccaro@google.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/76543 Reviewed-by: Subrata Banik <subratabanik@google.com> Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
		
			
				
	
	
		
			659 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			659 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
| # SPD tools
 | |
| 
 | |
| A set of tools to generate SPD files for platforms with memory down
 | |
| configurations.
 | |
| 
 | |
| The memory technologies currently supported are:
 | |
| 
 | |
| *   LPDDR4x - based on the JESD209-4C spec and Intel recommendations
 | |
|     (docs #616599, #610202, #634730).
 | |
| *   DDR4 - based on the JESD79-4C and Jedec 4.1.2.L-5 R29 v103 specs.
 | |
| *   LPDDR5/5X - based on the LPDDR5 spec JESD209-5B, the SPD spec SPD4.1.2.M-2
 | |
|     (the LPDDR3/4 spec is used since JEDEC has not released an SPD spec for
 | |
|     LPDDR5), and Intel recommendations in advisory #616599.
 | |
| 
 | |
| There are two tools provided to assist with generating SPDs and Makefiles to
 | |
| integrate into the coreboot build. These tools can also be used to allocate DRAM
 | |
| IDs (configure DRAM hardware straps) for any memory part used by a board.
 | |
| 
 | |
| *   `spd_gen`: This tool generates de-duplicated SPD files using a global memory
 | |
|     part list. It also generates a CSV manifest file which maps each memory part
 | |
|     in the global list to one of the generated SPD files. For each supported
 | |
|     memory technology, multiple sets of SPDs are generated. Each set corresponds
 | |
|     to a set of SoC platforms with different SPD requirements, e.g. due to
 | |
|     different expectations in the memory training code. Another CSV manifest
 | |
|     maps each supported platform to one of these sets.
 | |
| *   `part_id_gen`: This tool allocates DRAM strap IDs for the different memory
 | |
|     parts used by a board. It takes as input a CSV file of the memory parts used
 | |
|     with optional fixed IDs. It generates a Makefile.inc which is used to
 | |
|     integrate the SPD files generated by `spd_gen` into the coreboot build.
 | |
| 
 | |
| ## Tool 1 - `spd_gen`
 | |
| 
 | |
| This program takes the following inputs:
 | |
| 
 | |
| *   Path to a JSON file containing a global list of memory parts with their
 | |
|     attributes as per the datasheet. This is the list of all known memory parts
 | |
|     for the given memory technology.
 | |
| 
 | |
| *   The memory technology for which to generate the SPDs,
 | |
|     One of:
 | |
|         ddr4,
 | |
|         lp4x,
 | |
|         lp5
 | |
| 
 | |
| The input JSON file requires the following two fields for every memory part:
 | |
| 
 | |
| *   `name`: The name of the memory part.
 | |
| *   `attribs`: A list of the memory part's attributes, as per its datasheet.
 | |
|     These attributes match the part specifications and are independent of any
 | |
|     SoC expectations. The tool takes care of translating the physical attributes
 | |
|     of the memory part to match JEDEC spec and memory traning code expectations.
 | |
| 
 | |
| The `attribs` field further contains two types of sub-field:
 | |
| 
 | |
| *   Mandatory: These attributes must be provided for each memory part.
 | |
| *   Optional: These attributes may be provided for a memory part in order to
 | |
|     override the defaults.
 | |
| 
 | |
| The attributes are different for each memory technology.
 | |
| 
 | |
| ### LP4x attributes
 | |
| 
 | |
| #### Mandatory
 | |
| 
 | |
| *   `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
 | |
| 
 | |
| *   `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 `memory_parts.json`
 | |
| 
 | |
| ```
 | |
| {
 | |
|     "parts": [
 | |
|         {
 | |
|             "name": "MT53D512M64D4NW-046 WT:F",
 | |
|             "attribs": {
 | |
|                 "densityPerChannelGb": 8,
 | |
|                 "banks": 8,
 | |
|                 "channelsPerDie": 2,
 | |
|                 "diesPerPackage": 2,
 | |
|                 "bitWidthPerChannel": 16,
 | |
|                 "ranksPerChannel": 1,
 | |
|                 "speedMbps": 4267
 | |
|             }
 | |
|         },
 | |
|         {
 | |
|             "name": "NT6AP256T32AV-J1",
 | |
|             "attribs": {
 | |
|                 "densityPerChannelGb": 4,
 | |
|                 "banks": 8,
 | |
|                 "channelsPerDie": 2,
 | |
|                 "diesPerPackage": 1,
 | |
|                 "bitWidthPerChannel": 16,
 | |
|                 "ranksPerChannel": 1,
 | |
|                 "speedMbps": 4267,
 | |
|                 "tckMaxPs": 1250,
 | |
|                 "casLatencies": "14 20 24 28 32 36"
 | |
|             }
 | |
|         },
 | |
|     ]
 | |
| }
 | |
| ```
 | |
| 
 | |
| ### DDR4 attributes
 | |
| 
 | |
| #### Mandatory
 | |
| 
 | |
| *   `speedMTps`: Maximum rate supported by the part in MT/s. Valid values:
 | |
|     `1600, 1866, 2133, 2400, 2666, 2933, 3200` MT/s.
 | |
| 
 | |
| *   `CL_nRCD_nRP`: Refers to CAS Latency specified for the part (find
 | |
|     "CL-nRCD-nRP" in the vendor spec for the DDR4 part).
 | |
| 
 | |
| *   `capacityPerDieGb`: Capacity per die in gigabits. Valid values: `2, 4, 8,
 | |
|     16` Gb part.
 | |
| 
 | |
| *   `diesPerPackage`: Number of dies on the part. Valid values: `1, 2` dies per
 | |
|     package.
 | |
| 
 | |
| *   `packageBusWidth`: Number of bits of the device's address bus. Valid values:
 | |
|     `8, 16` bit-wide bus. NOTE: Width of x4 is not supported by this tool.
 | |
| 
 | |
| *   `ranksPerPackage`: From Jedec doc 4_01_02_AnnexL-1R23: “Package ranks per
 | |
|     DIMM” refers to the collections of devices on the module sharing common chip
 | |
|     select signals (across the data width of the DIMM), either from the edge
 | |
|     connector for unbuffered modules or from the outputs of a registering clock
 | |
|     driver for RDIMMs and LRDIMMs.Number of bits of the device's address bus.
 | |
|     Valid values: `1, 2` package ranks.
 | |
| 
 | |
| #### Optional
 | |
| 
 | |
| The following options are calculated by the tool based on the mandatory
 | |
| attributes described for the part, but there may be cases where a default value
 | |
| must be overridden, such as when a device appears to be 3200AA, but does not
 | |
| support all of the CAS latencies typically supported by a speed bin 3200AA part.
 | |
| To deal with such a case, the variable can be overridden here and the tool will
 | |
| use this value instead of calculating one. All values must be defined in
 | |
| picosecond units, except for "CASLatencies", which would be represented as a
 | |
| string like "9 10 11 12 14".
 | |
| 
 | |
| *   `TAAMinPs`: Defines the minimum CAS Latency. Table 48 of Jedec doc
 | |
|     4_01_02_AnnexL-5R29 lists tAAmin for each speed grade.
 | |
| 
 | |
| *   `TRASMinPs`: Refers to the minimum active to precharge delay time. Table 55
 | |
|     of Jedec doc 4_01_02_AnnexL-5R29 lists tRPmin for each speed grade.
 | |
| 
 | |
| *   `TCKMinPs`: Refers to the minimum clock cycle time. Table 42 of Jedec doc
 | |
|     4_01_02_AnnexL-5R29 lists tCKmin for each speed grade.
 | |
| 
 | |
| *   `TCKMaxPs`:Refers to the minimum clock cycle time. Table 44 of Jedec doc
 | |
|     4_01_02_AnnexL-5R29 lists tCKmin for each speed grade.
 | |
| 
 | |
| *   `TRFC1MinPs`: Refers to the minimum refresh recovery delay time. Table 59 of
 | |
|     Jedec doc 4_01_02_AnnexL-5R29 lists tRFC1min for each page size.
 | |
| 
 | |
| *   `TRFC2MinPs`: Refers to the minimum refresh recovery delay time. Table 61 of
 | |
|     Jedec doc 4_01_02_AnnexL-5R29 lists tRFC2min for each page size.
 | |
| 
 | |
| *   `TRFC4MinPs`: Refers to the minimum refresh recovery delay time. Table 63 of
 | |
|     Jedec doc 4_01_02_AnnexL-5R29 lists tRFC4min for each page size.
 | |
| 
 | |
| *   `TFAWMinPs`:: Refers to the minimum four activate window delay time. Table
 | |
|     66 of Jedec doc 4_01_02_AnnexL-5R29 lists tFAWmin for each speed grade and
 | |
|     page size combination.
 | |
| 
 | |
| *   `TRRDSMinPs`: Refers to the minimum activate to activate delay time to
 | |
|     different bank groups. Table 68 of Jedec doc 4_01_02_AnnexL-5R29 lists
 | |
|     tRRD_Smin for each speed grade and page size combination.
 | |
| 
 | |
| *   `TRRDLMinPs`: Refers to the minimum activate to activate delay time to the
 | |
|     same bank group. Table 70 of Jedec doc 4_01_02_AnnexL-5R29 lists tRRD_Lmin
 | |
|     for each speed grade and page size combination.
 | |
| 
 | |
| *   `TCCDLMinPs`: Refers to the minimum CAS to CAS delay time to same bank
 | |
|     group. Table 72 of Jedec doc 4_01_02_AnnexL-5R29 lists tCCD_Lmin for each
 | |
|     speed grade.
 | |
| 
 | |
| *   `TWRMinPs`: Refers to the minimum write recovery time. Table 75 of Jedec doc
 | |
|     4_01_02_AnnexL-5R29 lists tWRmin for each ddr4 type.
 | |
| 
 | |
| *   `TWTRSMinPs`: Refers to minimum write to read time to different bank group.
 | |
|     Table 78 of Jedec doc 4_01_02_AnnexL-5R29 lists tWTR_Smin for each ddr4
 | |
|     type.
 | |
| 
 | |
| *   `TWTRLMinPs`: Refers to minimum write to read time to same bank group. Table
 | |
|     80 of Jedec doc 4_01_02_AnnexL-5R29 lists tWTR_Lmin for each ddr4 type.
 | |
| 
 | |
| *   `CASLatencies`: Refers to the CAS latencies supported by the part. The speed
 | |
|     bin tables in the back of Jedec doc 4_01_02_AnnexL-5R29 define the standard
 | |
|     CAS latencies that a speed bin part is supposed to support. In cases where a
 | |
|     part does not support all of the CAS latencies listed in the speed bin
 | |
|     tables, this entry should be used to override the default settings.
 | |
| 
 | |
| #### Example `memory_parts.json`
 | |
| 
 | |
| ```
 | |
| {
 | |
|     "parts": [
 | |
|         {
 | |
|             "name": "K4A8G165WC-BCWE",
 | |
|             "attribs": {
 | |
|                 "speedMTps": 3200,
 | |
|                 "CL_nRCD_nRP": 22,
 | |
|                 "capacityPerDieGb": 8,
 | |
|                 "diesPerPackage": 1,
 | |
|                 "packageBusWidth": 16,
 | |
|                 "ranksPerPackage": 1
 | |
|             }
 | |
|         },
 | |
|         {
 | |
|             "name": "MT40A1G16KD-062E:E",
 | |
|             "attribs": {
 | |
|                 "speedMTps": 3200,
 | |
|                 "CL_nRCD_nRP": 22,
 | |
|                 "capacityPerDieGb": 16,
 | |
|                 "diesPerPackage": 1,
 | |
|                 "packageBusWidth": 16,
 | |
|                 "ranksPerPackage": 1,
 | |
|                 "TRFC1MinPs": 350000,
 | |
|                 "TRFC2MinPs": 260000,
 | |
|                 "TRFC4MinPs": 160000
 | |
|             }
 | |
|         },
 | |
|     ]
 | |
| }
 | |
| ```
 | |
| 
 | |
| ### LP5 attributes
 | |
| 
 | |
| #### Mandatory
 | |
| 
 | |
| *   `densityPerDieGb`: Density per die in Gb. Valid values: `4, 6, 8, 12, 16,
 | |
|     24, 32` Gb per die.
 | |
| 
 | |
| *   `diesPerPackage`: Number of physical dies in each SDRAM package. Valid
 | |
|     values: `2, 4, 8` dies per 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:
 | |
|     `5500, 6400` Mbps.
 | |
| 
 | |
| #### Optional
 | |
| 
 | |
| *   `lp5x`: If this is an LP5X part. SPD format is identical for LP5/5X aside
 | |
|     from the memory type byte.
 | |
| 
 | |
| *   `trfcabNs`: Minimum Refresh Recovery Delay Time (tRFCab) for all banks in
 | |
|     nanoseconds. As per JESD209-5B, this is dependent on the density per die.
 | |
|     Default values used:
 | |
| 
 | |
|     *   4 Gb : 180 ns
 | |
|     *   6 Gb : 210 ns
 | |
|     *   8 Gb : 210 ns
 | |
|     *   12 Gb: 280 ns
 | |
|     *   16 Gb: 280 ns
 | |
|     *   24 Gb: 380 ns
 | |
|     *   32 Gb: 380 ns
 | |
| 
 | |
| *   `trfcpbNs`: Minimum Refresh Recovery Delay Time (tRFCpb) per bank in
 | |
|     nanoseconds. As per JESD209-5B, this is dependent on the density per die.
 | |
|     Default values used:
 | |
| 
 | |
|     *   4 Gb : 90 ns
 | |
|     *   6 Gb : 120 ns
 | |
|     *   8 Gb : 120 ns
 | |
|     *   12 Gb: 140 ns
 | |
|     *   16 Gb: 140 ns
 | |
|     *   24 Gb: 190 ns
 | |
|     *   32 Gb: 190 ns
 | |
| 
 | |
| *   `trpabMinNs`: Minimum Row Precharge Delay Time (tRPab) for all banks in
 | |
|     nanoseconds. As per JESD209-5B, this is max(21ns, 2nCK), which defaults to
 | |
|     `21 ns`.
 | |
| 
 | |
| *   `trppbMinNs`: Minimum Row Precharge Delay Time (tRPpb) per bank in
 | |
|     nanoseconds. As per JESD209-5B, this is max(18ns, 2nCK) which defaults to
 | |
|     `18 ns`.
 | |
| 
 | |
| *   `tckMinPs`: SDRAM minimum cycle time (tCKmin) value in picoseconds. LPDDR5
 | |
|     has two clocks: the command/addrees clock (CK) and the data clock (WCK).
 | |
|     They are related by the WCK:CK ratio, which can be either 4:1 or 2:1. For
 | |
|     LPDDR5, tCKmin is the CK period, which can be calculated from the
 | |
|     `speedMbps` attribute and the WCK:CK ratio as follows: `tCKmin = 1 /
 | |
|     (speedMbps / 2 / WCK:CK)`. The default values used are for a 4:1 WCK:CK
 | |
|     ratio:
 | |
| 
 | |
|     *   6400 Mbps: 1250 ps
 | |
|     *   5500 Mbps: 1455 ps
 | |
| 
 | |
| *   `taaMinPs`: Minimum CAS Latency Time(tAAmin) in picoseconds. This value
 | |
|     defaults to nck * tCKmin, where nck is maximum CAS latency, and is
 | |
|     determined from the `speedMbps` attribute as per JESD209-5B:
 | |
| 
 | |
|     *   6400 Mbps: 17
 | |
|     *   5500 Mbps: 15
 | |
| 
 | |
| *   `trcdMinNs`: Minimum RAS# to CAS# Delay Time (tRCDmin) in nanoseconds. As
 | |
|     per JESD209-5B, this is max(18ns, 2nCK) which defaults to `18 ns`.
 | |
| 
 | |
| #### Example `memory_parts.json`
 | |
| 
 | |
| ```
 | |
| {
 | |
|     "parts": [
 | |
|         {
 | |
|             "name": "MT62F1G32D4DR-031 WT:B",
 | |
|             "attribs": {
 | |
|                 "densityPerDieGb": 8,
 | |
|                 "diesPerPackage": 4,
 | |
|                 "bitWidthPerChannel": 16,
 | |
|                 "ranksPerChannel": 2,
 | |
|                 "speedMbps": 6400
 | |
|             }
 | |
|         },
 | |
|     ]
 | |
| }
 | |
| ```
 | |
| 
 | |
| ### Output
 | |
| 
 | |
| The `spd_gen` tool generates the directory structure shown below. The inputs to
 | |
| the tool are the `memory_parts.json` files, and all other files are generated.
 | |
| 
 | |
| ```
 | |
|     spd
 | |
|       |
 | |
|       |_ lp4x
 | |
|            |
 | |
|            |_ memory_parts.json
 | |
|            |_ platforms_manifest.generated.txt
 | |
|            |_ set-0
 | |
|                 |_parts_spd_manifest.generated.txt
 | |
|                 |_spd-1.hex
 | |
|                 |_spd-2.hex
 | |
|                 |_...
 | |
|            |_ set-1
 | |
|                 |_...
 | |
|            |_...
 | |
|       |
 | |
|       |_ ddr4
 | |
|            |
 | |
|            |_ memory_parts.json
 | |
|            |_ platforms_manifest.generated.txt
 | |
|            |_ set-0
 | |
|                 |_parts_spd_manifest.generated.txt
 | |
|                 |_spd-1.hex
 | |
|                 |_spd-2.hex
 | |
|                 |_...
 | |
|            |_ set-1
 | |
|                 |_...
 | |
|            |_...
 | |
|       |_...
 | |
| ```
 | |
| 
 | |
| The files generated are:
 | |
| 
 | |
| *   `spd-X.hex`: Deduplicated SPDs for all the memory parts in the input JSON
 | |
|     file.
 | |
| 
 | |
| *   `parts_spd_manifest.generated.txt`: A CSV file mapping each memory part to
 | |
|     one of the deduplicated SPD files. E.g.
 | |
| 
 | |
|     ```
 | |
|     H9HCNNNBKMMLXR-NEE,spd-1.hex
 | |
|     H9HCNNNFAMMLXR-NEE,spd-2.hex
 | |
|     K4U6E3S4AA-MGCL,spd-1.hex
 | |
|     K4UBE3D4AA-MGCL,spd-3.hex
 | |
|     MT53E1G32D2NP-046 WT:A,spd-4.hex
 | |
|     ```
 | |
| 
 | |
| *   `platforms_manifest.generated.txt`: A CSV file mapping each platform to the
 | |
|     SPD set used by that platform. E.g.
 | |
| 
 | |
|     ```
 | |
|     TGL,set-0
 | |
|     ADL,set-0
 | |
|     JSL,set-1
 | |
|     CZN,set-1
 | |
|     ```
 | |
| 
 | |
| ## Tool 2 - `part_id_gen`
 | |
| 
 | |
| This program takes the following 4 inputs:
 | |
| 
 | |
| *   1) The SoC platform which the board is based on, e.g. ADL.
 | |
| *   2) The memory technology used by the board, One of ddr4, lp4x, or lp5.
 | |
| *   3) The path to the directory where the generated Makefile.inc should be placed.
 | |
| *   4) A CSV file containing a list of the memory parts used by the board, with an
 | |
|         optional fixed or exclusive ID for each part and an optional SPD override file.
 | |
|         A fixed ID is simply an integer and it ensure that part (and any that share the
 | |
|         same SPD) will be assigned that ID. An exclusive ID is prefixed with `*` and ensures
 | |
|         that only parts with the same exclusive ID will be assigned that ID, even if they would
 | |
|         otherwise share the same ID. When using an SPD override file, the file will be searched
 | |
|         for in the directory where mem_parts_used is located, if it is not found there then it
 | |
|         will be searched for in the appropriate default spd directory.
 | |
| 
 | |
|         NOTE: Only assign a fixed/exclusive ID if required for legacy reasons.
 | |
| 
 | |
| Example of a CSV file using fixed and exclusive IDs, and SPD file overrides:
 | |
| 
 | |
| ```
 | |
| K4AAG165WA-BCWE,1
 | |
| MT40A512M16TB-062E:J
 | |
| MT40A1G16KD-062E:E
 | |
| K4A8G165WC-BCWE
 | |
| H5AN8G6NDJR-XNC,8
 | |
| H5ANAG6NCMR-XNC,*9
 | |
| H9HCNNNCPMMLXR-NEE,,H9HCNNNCPMMLXR-NEE.hex
 | |
| H54G56CYRBX247,4,H54G56CYRBX247.hex
 | |
| ```
 | |
| 
 | |
| Explanation: This will ensure that the SPDs for K4AAG165WA-BCWE and
 | |
| H5AN8G6NDJR-XNC are assigned to IDs 1 and 8 respectively. H5ANAG6NCMR-XNC
 | |
| will be assigned ID 9 and no other part will be assigned ID 9 even if it
 | |
| shares the same SPD. The SPDs for all other memory parts will be assigned to
 | |
| the first compatible ID. Assigning fixed/exclusive IDs may result in duplicate
 | |
| SPD entries or gaps in the ID mapping.
 | |
| 
 | |
| ### Output
 | |
| 
 | |
| The `part_id_gen` tool outputs the following:
 | |
| 
 | |
| *   It prints the DRAM hardware strap ID which should be allocated to each
 | |
|     memory part in the input file.
 | |
| *   It generates a `Makefile.inc` in the given directory. This is used to
 | |
|     integrate the SPD files generated by `spd_gen` with the coreboot build for
 | |
|     the board.
 | |
| *   It generates a `dram_id.generated.txt` in the same directory as the
 | |
|     `Makefile.inc`. This lists the part IDs assigned to each memory part, and is
 | |
|     useful for itegration with the board schematics.
 | |
| 
 | |
| Sample `Makefile.inc`:
 | |
| 
 | |
| ```
 | |
| # SPDX-License-Identifier: GPL-2.0-or-later
 | |
| # This is an auto-generated file. Do not edit!!
 | |
| # Generated by:
 | |
| # util/spd_tools/bin/part_id_gen ADL lp4x src/mainboard/google/brya/variants/felwinter/memory src/mainboard/google/brya/variants/felwinter/memory/mem_parts_used.txt
 | |
| 
 | |
| SPD_SOURCES =
 | |
| SPD_SOURCES += spd/lp4x/set-0/spd-1.hex      # ID = 0(0b0000)  Parts = K4U6E3S4AA-MGCR, H9HCNNNBKMMLXR-NEE
 | |
| SPD_SOURCES += spd/lp4x/set-0/spd-3.hex      # ID = 1(0b0001)  Parts = K4UBE3D4AA-MGCR
 | |
| SPD_SOURCES += spd/lp4x/set-0/spd-4.hex      # ID = 2(0b0010)  Parts = MT53E1G32D2NP-046 WT:A
 | |
| ```
 | |
| 
 | |
| NOTE: Empty entries may be required if there is a gap created by a memory part
 | |
| with a fixed ID.
 | |
| 
 | |
| Sample `dram_id.generated.txt`:
 | |
| 
 | |
| ```
 | |
| # SPDX-License-Identifier: GPL-2.0-or-later
 | |
| # This is an auto-generated file. Do not edit!!
 | |
| # Generated by:
 | |
| # util/spd_tools/bin/part_id_gen ADL lp4x src/mainboard/google/brya/variants/felwinter/memory src/mainboard/google/brya/variants/felwinter/memory/mem_parts_used.txt
 | |
| 
 | |
| DRAM Part Name                 ID to assign
 | |
| K4U6E3S4AA-MGCR                0 (0000)
 | |
| K4UBE3D4AA-MGCR                1 (0001)
 | |
| H9HCNNNBKMMLXR-NEE             0 (0000)
 | |
| MT53E1G32D2NP-046 WT:A         2 (0010)
 | |
| ```
 | |
| 
 | |
| ### Note of caution
 | |
| 
 | |
| The `part_id_gen` tool assigns DRAM IDs based on the order of the part names in
 | |
| the input file. Thus, when adding a new memory part to the list, it should
 | |
| always go at the end of the file. This guarantees that the memory parts that
 | |
| were already assigned IDs do not change.
 | |
| 
 | |
| ## How to build the tools?
 | |
| 
 | |
| ```
 | |
| make clean -C util/spd_tools
 | |
| make -C util/spd_tools
 | |
| ```
 | |
| 
 | |
| ## How to use the tools?
 | |
| 
 | |
| ### `spd_gen`
 | |
| 
 | |
| Usage:
 | |
| 
 | |
| ```
 | |
| util/spd_tools/bin/spd_gen <mem_parts_list_json> <mem_technology>
 | |
| ```
 | |
| 
 | |
| Usage Examples:
 | |
| 
 | |
| ```
 | |
| util/spd_tools/bin/spd_gen spd/ddr4/memory_parts.json ddr4
 | |
| util/spd_tools/bin/spd_gen spd/lp4x/memory_parts.json lp4x
 | |
| util/spd_tools/bin/spd_gen spd/lp5/memory_parts.json lp5
 | |
| ```
 | |
| 
 | |
| ### `part_id_gen`
 | |
| 
 | |
| Usage:
 | |
| 
 | |
| ```
 | |
| util/spd_tools/bin/part_id_gen <platform> <mem_technology> <makefile_dir> <mem_parts_used_file>
 | |
| ```
 | |
| 
 | |
| Usage Example:
 | |
| 
 | |
| ```
 | |
| util/spd_tools/bin/part_id_gen \
 | |
|   ADL \
 | |
|   lp4x \
 | |
|   src/mainboard/google/brya/variants/felwinter/memory \
 | |
|   src/mainboard/google/brya/variants/felwinter/memory/mem_parts_used.txt
 | |
| ```
 | |
| 
 | |
| ### Need to add a new memory part for a board?
 | |
| 
 | |
| *   If the memory part is not present in the global list of memory parts for
 | |
|     that memory technology (e.g. `spd/lp4x/memory_parts.json`), then add the
 | |
|     memory part name and attributes as per the datasheet.
 | |
| 
 | |
|     *   Use `spd_gen` to regenerate all the SPD files and manifests for that
 | |
|         memory technology. Either a new SPD file will be generated for the new
 | |
|         part, or an existing one will be reused.
 | |
|     *   Upload the new SPD (if one is created) and the manifest changes for
 | |
|         review.
 | |
| 
 | |
| *   Update the file containing the memory parts used by board (variant), by
 | |
|     adding the new memory part name at the end of the file.
 | |
| 
 | |
|     *   Use `part_id_gen` to update the variant's `Makefile.inc` and
 | |
|         `dram_id.generated.txt` with the new part.
 | |
|     *   Upload the changes to `Makefile.inc` and `dram_id.generated.txt` for
 | |
|         review.
 | |
| 
 | |
| ## How to add support for a new memory technology
 | |
| 
 | |
| ### 1. Gather the SPD requirements
 | |
| 
 | |
| To generate SPDs for the new memory technology, information is needed about the
 | |
| list of bytes in the SPD and how the value of each byte should be determined.
 | |
| This information usually comes from a combination of:
 | |
| 
 | |
| *   The JEDEC spec for the memory technology, e.g. JESD209-5B for LPDDR5.
 | |
| *   The JEDEC SPD spec for the memory technology, e.g. SPD4.1.2.M-2 for LPDDR3/4
 | |
|     (also used for LP4x and LP5).
 | |
| *   Platform-specific requirements. SoC vendors often don't follow the JEDEC
 | |
|     specs exactly. E.g. the memory training code may expect certain SPD bytes to
 | |
|     encode a different value to what is stated in the spec. So for each SoC
 | |
|     platform using the new memory technology, any platform-specific requirements
 | |
|     need to be gathered.
 | |
| 
 | |
| ### 2. Implement support in spd_tools
 | |
| 
 | |
| Support for the new memory technology needs to be added to both the `spd_gen`
 | |
| and `part_id_gen` tools.
 | |
| 
 | |
| #### `spd_gen`
 | |
| 
 | |
| Adding support to `spd_gen` requires implementing the logic to generate SPDs for
 | |
| the new memory technology. The changes required are:
 | |
| 
 | |
| *   Add the new memory technology to the `memTechMap` in `spd_gen/spd_gen.go`.
 | |
| *   Add a new file `spd_gen/<mem_tech>.go`. This file will contain all the logic
 | |
|     for generating SPDs for the new memory technology. It needs to implement the
 | |
|     `memTech` interface defined in `spd_gen/spd_gen.go`. The interface functions
 | |
|     are documented inline. Examples of how the interface is implemented for
 | |
|     existing memory technologies can be found in the `spd_gen/` directory, e.g.
 | |
|     `lp4x.go`, `ddr4.go`, `lp5.go`. While not strictly necessary, it is
 | |
|     recommended to follow the overall structure of these existing files when
 | |
|     adding a new memory technology.
 | |
| 
 | |
| #### `part_id_gen`
 | |
| 
 | |
| The `part_id_gen` tool is memory technology-agnostic, so the only change
 | |
| required is:
 | |
| 
 | |
| *   Add the new memory technology to the `supportedMemTechs` list in
 | |
|     `part_id_gen/part_id_gen.go`.
 |