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
|
# LPDDR4x SPD tools README
Tools for generating SPD files for LPDDR4x memory used in memory down
configurations on Intel Tiger Lake (TGL), Jasper Lake (JSL), and Alder
Lake (ADL) based platforms. These tools generate SPDs following
JESD209-4C specification and Intel recommendations (doc #616599,
#610202, #634730) for LPDDR4x SPD.
There are two tools provided that assist TGL, JSL and ADL 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`, `JSL` and `ADL`.
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.
|