2020-05-21 06:37:51 +02:00
|
|
|
# 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
|
2020-10-02 16:51:46 +02:00
|
|
|
SPD files are named (spd_1.hex, spd_2.hex, spd_3.hex and so on)
|
2020-05-21 06:37:51 +02:00
|
|
|
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:
|
|
|
|
```
|
2020-10-02 16:51:46 +02:00
|
|
|
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
|
2020-05-21 06:37:51 +02:00
|
|
|
```
|
|
|
|
|
|
|
|
## 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 =
|
2020-10-02 16:51:46 +02:00
|
|
|
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
|
2020-05-21 06:37:51 +02:00
|
|
|
```
|
|
|
|
|
|
|
|
### 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.
|