util/spd_tools: Remove intel subfolder
Move ddr4 and lp4x to spd_tools root folder. The tool now applies to non intel platforms. BUG=b:162939176 TEST=Run tool Signed-off-by: Rob Barnes <robbarnes@google.com> Change-Id: I0941ea036d760ee27eb34f259f4506a4b7584bee Reviewed-on: https://review.coreboot.org/c/coreboot/+/44844 Reviewed-by: Furquan Shaikh <furquan@google.com> Reviewed-by: Nick Vaccaro <nvaccaro@google.com> Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
committed by
Furquan Shaikh
parent
1860cd460a
commit
196e9c0021
275
util/spd_tools/ddr4/README.md
Normal file
275
util/spd_tools/ddr4/README.md
Normal file
@ -0,0 +1,275 @@
|
||||
# DDR4 SPD tools README
|
||||
|
||||
Tools for generating SPD files for DDR4 memory used in memory down
|
||||
configurations on Intel Tiger Lake (TGL) based
|
||||
platforms. These tools generate SPDs following JESD79-4C
|
||||
and Jedec 4.1.2.L-5 R29 v103 specifications.
|
||||
|
||||
There are two tools provided that assist TGL 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 DDR4 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 DDR4
|
||||
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
|
||||
DDR4 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`.
|
||||
|
||||
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`
|
||||
|
||||
* `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.
|
||||
|
||||
* `deviceBusWidth`: 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 `attribs`
|
||||
|
||||
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.
|
||||
Do 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 JSON file
|
||||
```
|
||||
{
|
||||
"parts": [
|
||||
{
|
||||
"name": "MEMORY_PART_A",
|
||||
"attribs": {
|
||||
"speedMTps": 3200,
|
||||
"CL_nRCD_nRP": 22
|
||||
"capacityPerDieGb": 8,
|
||||
"diesPerPackage": 2,
|
||||
"deviceBusWidth": 16,
|
||||
"ranksPerPackage": 1,
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "MEMORY_PART_B",
|
||||
"attribs": {
|
||||
"speedMTps": 3200,
|
||||
"CL_nRCD_nRP": 22
|
||||
"capacityPerDieGb": 8,
|
||||
"diesPerPackage": 1,
|
||||
"deviceBusWidth": 16,
|
||||
"ranksPerPackage": 2,
|
||||
"casLatencies": "9 10 11 12 13 14 15 16 17 18 19 20",
|
||||
"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 (ddr4-spd-1.hex, ddr4-spd-2.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, ddr4-spd-1.hex
|
||||
MEMORY_PART_B, ddr4-spd-2.hex
|
||||
MEMORY_PART_C, ddr4-spd-3.hex
|
||||
MEMORY_PART_D, ddr4-spd-2.hex
|
||||
MEMORY_PART_E, ddr4-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 += ddr4-spd-1.hex # ID = 0(0b0000) Parts = MEMORY_PART_A
|
||||
SPD_SOURCES += ddr4-spd-2.hex # ID = 1(0b0001) Parts = MEMORY_PART_B, MEMORY_PART_D
|
||||
SPD_SOURCES += ddr4-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>
|
||||
```
|
||||
|
||||
## Example Usage
|
||||
```
|
||||
# ./gen_spd ../../../../src/soc/intel/tigerlake/spd/ddr4 ./global_ddr4_mem_parts.json.txt 'TGL'
|
||||
|
||||
```
|
||||
|
||||
### 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.
|
215
util/spd_tools/ddr4/gen_part_id.go
Normal file
215
util/spd_tools/ddr4/gen_part_id.go
Normal file
@ -0,0 +1,215 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/csv"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
/*
|
||||
* This program allocates DRAM strap IDs for different parts that are being used by the variant.
|
||||
*
|
||||
* It expects the following inputs:
|
||||
* Pointer to SPD directory. This is the location where SPD files and SPD Manifest generated by
|
||||
* gen_spd.go are placed.
|
||||
* Pointer to Makefile directory. Makefile.inc generated by this program is placed in this
|
||||
* location.
|
||||
* Text file containing a list of memory parts names used by the board. Each line in the file
|
||||
* is expected to have one memory part name.
|
||||
*/
|
||||
const (
|
||||
SPDManifestFileName = "spd_manifest.generated.txt"
|
||||
MakefileName = "Makefile.inc"
|
||||
DRAMIdFileName = "dram_id.generated.txt"
|
||||
)
|
||||
|
||||
func usage() {
|
||||
fmt.Printf("\nUsage: %s <spd_dir> <makefile_dir> <mem_parts_used_file>\n\n", os.Args[0])
|
||||
fmt.Printf(" where,\n")
|
||||
fmt.Printf(" spd_dir = Directory path containing SPD files and manifest generated by gen_spd.go\n")
|
||||
fmt.Printf(" makefile_dir = Directory path where generated Makefile.inc should be placed\n")
|
||||
fmt.Printf(" mem_parts_used_file = File containing list of memory parts used by the board\n\n\n")
|
||||
}
|
||||
|
||||
func checkArgs() error {
|
||||
|
||||
for _, arg := range os.Args[1:] {
|
||||
if _, err := os.Stat(arg); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
/*
|
||||
* Read input file that contains list of memory part names used by the variant (one on a line)
|
||||
* and split into separate strings for each part name.
|
||||
*/
|
||||
func readParts(memPartsUsedFileName string) ([]string, error) {
|
||||
lines, err := ioutil.ReadFile(memPartsUsedFileName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
str := string(lines)
|
||||
parts := strings.Split(str, "\n")
|
||||
|
||||
return parts, nil
|
||||
}
|
||||
|
||||
/*
|
||||
* Read SPD manifest file(CSV) generated by gen_spd program and generate two maps:
|
||||
* 1. Part to SPD Map : This maps global memory part name to generated SPD file name
|
||||
* 2. SPD to Index Map: This generates a map of deduplicated SPD file names to index assigned to
|
||||
* that SPD. This function sets index for all SPDs to -1. This index gets
|
||||
* updated as part of genPartIdInfo() depending upon the SPDs actually used
|
||||
* by the variant.
|
||||
*/
|
||||
func readSPDManifest(SPDDirName string) (map[string]string, map[string]int, error) {
|
||||
f, err := os.Open(filepath.Join(SPDDirName, SPDManifestFileName))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
r := csv.NewReader(f)
|
||||
|
||||
partToSPDMap := make(map[string]string)
|
||||
SPDToIndexMap := make(map[string]int)
|
||||
|
||||
for {
|
||||
fields, err := r.Read()
|
||||
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if len(fields) != 2 {
|
||||
return nil, nil, fmt.Errorf("CSV file is incorrectly formatted")
|
||||
}
|
||||
|
||||
partToSPDMap[fields[0]] = fields[1]
|
||||
SPDToIndexMap[fields[1]] = -1
|
||||
}
|
||||
|
||||
return partToSPDMap, SPDToIndexMap, nil
|
||||
}
|
||||
|
||||
/* Print information about memory part used by variant and ID assigned to it. */
|
||||
func appendPartIdInfo(s *string, partName string, index int) {
|
||||
*s += fmt.Sprintf("%-30s %d (%04b)\n", partName, index, int64(index))
|
||||
}
|
||||
|
||||
type partIds struct {
|
||||
SPDFileName string
|
||||
memParts string
|
||||
}
|
||||
|
||||
/*
|
||||
* For each part used by variant, check if the SPD (as per the manifest) already has an ID
|
||||
* assigned to it. If yes, then add the part name to the list of memory parts supported by the
|
||||
* SPD entry. If not, then assign the next ID to the SPD file and add the part name to the
|
||||
* list of memory parts supported by the SPD entry.
|
||||
*
|
||||
* Returns list of partIds that contains spdFileName and supported memory parts for each
|
||||
* assigned ID.
|
||||
*/
|
||||
func genPartIdInfo(parts []string, partToSPDMap map[string]string, SPDToIndexMap map[string]int, makefileDirName string) ([]partIds, error) {
|
||||
partIdList := []partIds{}
|
||||
curId := 0
|
||||
var s string
|
||||
|
||||
s += fmt.Sprintf("%-30s %s\n", "DRAM Part Name", "ID to assign")
|
||||
|
||||
for _, p := range parts {
|
||||
if p == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
SPDFileName,ok := partToSPDMap[p]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("Failed to find part ", p, " in SPD Manifest. Please add the part to global part list and regenerate SPD Manifest")
|
||||
}
|
||||
|
||||
index := SPDToIndexMap[SPDFileName]
|
||||
if index != -1 {
|
||||
partIdList[index].memParts += ", " + p
|
||||
appendPartIdInfo(&s, p, index)
|
||||
continue
|
||||
}
|
||||
|
||||
SPDToIndexMap[SPDFileName] = curId
|
||||
|
||||
appendPartIdInfo(&s, p, curId)
|
||||
entry := partIds{SPDFileName: SPDFileName, memParts: p}
|
||||
partIdList = append(partIdList, entry)
|
||||
|
||||
curId++
|
||||
}
|
||||
|
||||
fmt.Printf("%s", s)
|
||||
err := ioutil.WriteFile(filepath.Join(makefileDirName, DRAMIdFileName), []byte(s), 0644)
|
||||
|
||||
return partIdList, err
|
||||
}
|
||||
|
||||
var generatedCodeLicense string = "## SPDX-License-Identifier: GPL-2.0-or-later"
|
||||
var autoGeneratedInfo string = "## This is an auto-generated file. Do not edit!!"
|
||||
|
||||
/*
|
||||
* This function generates Makefile.inc under the variant directory path and adds assigned SPDs
|
||||
* to SPD_SOURCES.
|
||||
*/
|
||||
func genMakefile(partIdList []partIds, makefileDirName string) error {
|
||||
var s string
|
||||
|
||||
s += fmt.Sprintf("%s\n%s\n\n", generatedCodeLicense, autoGeneratedInfo)
|
||||
s += fmt.Sprintf("MEMORY_TYPE = ddr4\n\n")
|
||||
s += fmt.Sprintf("SPD_SOURCES =\n")
|
||||
|
||||
for i := 0; i < len(partIdList); i++ {
|
||||
s += fmt.Sprintf("SPD_SOURCES += %s ", partIdList[i].SPDFileName)
|
||||
s += fmt.Sprintf(" # ID = %d(0b%04b) ", i, int64(i))
|
||||
s += fmt.Sprintf(" Parts = %04s\n", partIdList[i].memParts)
|
||||
}
|
||||
|
||||
return ioutil.WriteFile(filepath.Join(makefileDirName, MakefileName), []byte(s), 0644)
|
||||
}
|
||||
|
||||
func main() {
|
||||
if len(os.Args) != 4 {
|
||||
usage()
|
||||
log.Fatal("Incorrect number of arguments")
|
||||
}
|
||||
|
||||
SPDDir, MakefileDir, MemPartsUsedFile := os.Args[1], os.Args[2], os.Args[3]
|
||||
|
||||
partToSPDMap, SPDToIndexMap, err := readSPDManifest(SPDDir)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
parts, err := readParts(MemPartsUsedFile)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
partIdList, err := genPartIdInfo(parts, partToSPDMap, SPDToIndexMap, MakefileDir)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if err := genMakefile(partIdList, MakefileDir); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
1386
util/spd_tools/ddr4/gen_spd.go
Normal file
1386
util/spd_tools/ddr4/gen_spd.go
Normal file
File diff suppressed because it is too large
Load Diff
37
util/spd_tools/ddr4/global_ddr4_mem_parts.json.txt
Normal file
37
util/spd_tools/ddr4/global_ddr4_mem_parts.json.txt
Normal file
@ -0,0 +1,37 @@
|
||||
{
|
||||
"parts": [
|
||||
{
|
||||
"name": "H5AN8G6NDJR-XNC",
|
||||
"attribs": {
|
||||
"speedMTps": 3200,
|
||||
"CL_nRCD_nRP": 22,
|
||||
"capacityPerDieGb": 8,
|
||||
"diesPerPackage": 1,
|
||||
"deviceBusWidth": 16,
|
||||
"ranksPerPackage": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "MT40A512M16TB-062E:J",
|
||||
"attribs": {
|
||||
"speedMTps": 3200,
|
||||
"CL_nRCD_nRP": 22,
|
||||
"capacityPerDieGb": 8,
|
||||
"diesPerPackage": 1,
|
||||
"deviceBusWidth": 16,
|
||||
"ranksPerPackage": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "H5ANAG6NCMR-XNC",
|
||||
"attribs": {
|
||||
"speedMTps": 3200,
|
||||
"CL_nRCD_nRP": 22,
|
||||
"capacityPerDieGb": 8,
|
||||
"diesPerPackage": 2,
|
||||
"deviceBusWidth": 16,
|
||||
"ranksPerPackage": 1
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
Reference in New Issue
Block a user