util/spd_tools: Add README for unified spd_tools

Combine the existing lp4x and ddr4 READMEs into a single file, and
update it to reflect the new unified version of the tools.

BUG=b:191776301
TEST=None

Change-Id: I866932a1d0b5b6b47b0daff893b37de7a302b4e6
Signed-off-by: Reka Norman <rekanorman@google.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/57796
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Furquan Shaikh <furquan@google.com>
Reviewed-by: Tim Wawrzynczak <twawrzynczak@chromium.org>
Reviewed-by: Karthik Ramasubramanian <kramasub@google.com>
diff --git a/util/spd_tools/README.md b/util/spd_tools/README.md
new file mode 100644
index 0000000..5be666b
--- /dev/null
+++ b/util/spd_tools/README.md
@@ -0,0 +1,495 @@
+# 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.
+
+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:
+
+*   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, e.g. "lp4x".
+
+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
+            }
+        },
+    ]
+}
+```
+
+### 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 inputs:
+
+*   The SoC platform which the board is based on, e.g. ADL.
+*   The memory technology used by the board, e.g. lp4x.
+*   The path to the directory where the generated Makefile.inc should be placed.
+*   A CSV file containing a list of the memory parts used by the board, with an
+    optional fixed ID for each part. NOTE: Only assign a fixed ID if required
+    for legacy reasons.
+
+Example of a CSV file using fixed IDs:
+
+```
+K4AAG165WA-BCWE,1
+MT40A512M16TB-062E:J
+MT40A1G16KD-062E:E
+K4A8G165WC-BCWE
+H5AN8G6NDJR-XNC,8
+H5ANAG6NCMR-XNC
+```
+
+Explanation: This will ensure that the SPDs for K4AAG165WA-BCWE and
+H5AN8G6NDJR-XNC are assigned to IDs 1 and 8 respectively. The SPDs for all other
+memory parts will be assigned to the first compatible ID. Assigning fixed IDs
+may result in duplicate SPD entries or gaps in the ID mapping.
+
+### Output
+
+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>
+```
+
+Example:
+
+```
+util/spd_tools/bin/spd_gen spd/lp4x/memory_parts.json lp4x
+```
+
+### `part_id_gen`
+
+Usage:
+
+```
+util/spd_tools/bin/part_id_gen <platform> <mem_technology> <makefile_dir> <mem_parts_used_file>
+```
+
+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.