summaryrefslogtreecommitdiffstats
path: root/util/spd_tools/README.md
blob: bed34601cc3af6c0c2323c41ed51e89b01594a56 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
# 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`.