Merge 4.16

Change-Id: I11db70a8e25a6656c5ec640a703e7b06d5a3672e
This commit is contained in:
Jeremy Soller
2022-03-04 07:19:45 -07:00
parent af64e5d166
commit d97e25ac13
3138 changed files with 317025 additions and 23253 deletions

View File

@@ -8,6 +8,9 @@ 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 - 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
@@ -292,6 +295,100 @@ string like "9 10 11 12 14".
}
```
### 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
* `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
@@ -493,3 +590,48 @@ util/spd_tools/bin/part_id_gen \
`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`.

View File

@@ -45,6 +45,7 @@ var supportedPlatforms = [...]string{
var supportedMemTechs = [...]string{
"lp4x",
"ddr4",
"lp5",
}
func usage() {

View File

@@ -0,0 +1,785 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
package main
import (
"encoding/json"
"fmt"
)
/* ------------------------------------------------------------------------------------------ */
/* LP5-defined types */
/* ------------------------------------------------------------------------------------------ */
type lp5 struct {
}
type LP5MemAttributes struct {
/* Primary attributes - must be provided by JSON file for each part */
DensityPerDieGb int
DiesPerPackage int
BitWidthPerChannel int
RanksPerChannel int
SpeedMbps int
/*
* All the following parameters are optional and required only if the part requires
* special parameters as per the datasheet.
*/
/* Timing parameters */
TRFCABNs int
TRFCPBNs int
TRPABMinNs int
TRPPBMinNs int
TCKMinPs int
TAAMinPs int
TRCDMinNs int
}
type LP5DensityParams struct {
DensityEncoding byte
RowAddressBitsx8Channel int
RowAddressBitsx16Channel int
TRFCABNs int
TRFCPBNs int
}
type LP5SpeedParams struct {
TCKMinPs int
MaxCASLatency int
}
type LP5BankArchParams struct {
NumBanks int
BankGroups int
BurstAddressBits int
}
type LP5SPDAttribFunc func(*LP5MemAttributes) byte
type LP5SPDAttribTableEntry struct {
constVal byte
getVal LP5SPDAttribFunc
}
type LP5SetFunc func(*LP5MemAttributes) int
type LP5Set struct {
SPDRevision byte
getBankArch LP5SetFunc
optionalFeatures byte
otherOptionalFeatures byte
busWidthEncoding byte
}
/* ------------------------------------------------------------------------------------------ */
/* Constants */
/* ------------------------------------------------------------------------------------------ */
const (
/* SPD Byte Index */
LP5SPDIndexSize = 0
LP5SPDIndexRevision = 1
LP5SPDIndexMemoryType = 2
LP5SPDIndexModuleType = 3
LP5SPDIndexDensityBanks = 4
LP5SPDIndexAddressing = 5
LP5SPDIndexPackageType = 6
LP5SPDIndexOptionalFeatures = 7
LP5SPDIndexOtherOptionalFeatures = 9
LP5SPDIndexModuleOrganization = 12
LP5SPDIndexBusWidth = 13
LP5SPDIndexTimebases = 17
LP5SPDIndexTCKMin = 18
LP5SPDIndexTAAMin = 24
LP5SPDIndexTRCDMin = 26
LP5SPDIndexTRPABMin = 27
LP5SPDIndexTRPPBMin = 28
LP5SPDIndexTRFCABMinLSB = 29
LP5SPDIndexTRFCABMinMSB = 30
LP5SPDIndexTRFCPBMinLSB = 31
LP5SPDIndexTRFCPBMinMSB = 32
LP5SPDIndexTRPPBMinFineOffset = 120
LP5SPDIndexTRPABMinFineOffset = 121
LP5SPDIndexTRCDMinFineOffset = 122
LP5SPDIndexTAAMinFineOffset = 123
LP5SPDIndexTCKMinFineOffset = 125
LP5SPDIndexManufacturerPartNumberStartByte = 329
LP5SPDIndexManufacturerPartNumberEndByte = 348
/* SPD Byte Value */
/*
* From JEDEC spec:
* 6:4 (Bytes total) = 2 (512 bytes)
* 3:0 (Bytes used) = 3 (384 bytes)
* Set to 0x23 for LPDDR5.
*/
LP5SPDValueSize = 0x23
/*
* Revision 1.0. Expected by ADL
*/
LP5SPDValueRevision1_0 = 0x10
/*
* Revision 1.1. Expected by Sabrina
*/
LP5SPDValueRevision1_1 = 0x11
/*
* As per advisory #616599, ADL MRC expects LPDDR5 memory type = 0x13.
*/
LP5SPDValueMemoryType = 0x13
/*
* From JEDEC spec:
* 7:7 (Hybrid) = 0 (Not hybrid)
* 6:4 (Hybrid media) = 000 (Not hybrid)
* 3:0 (Base Module Type) = 1110 (Non-DIMM solution)
*
* This is dependent on hardware design. LPDDR5 only has memory down solution.
* Hence this is not hybrid non-DIMM solution.
* Set to 0x0E.
*/
LP5SPDValueModuleType = 0x0e
/*
* From JEDEC spec:
* 3:2 (MTB) = 00 (0.125ns)
* 1:0 (FTB) = 00 (1ps)
* Set to 0x00.
*/
LP5SPDValueTimebases = 0x00
/* As per JEDEC spec, unused digits of manufacturer part number are left as blank. */
LP5SPDValueManufacturerPartNumberBlank = 0x20
)
const (
// The column addresses are the same for x8 & x16 and for all Bank Architectures.
LP5ColAddressBits = 6
)
const (
// LPDDR5 has a flexible bank architecture with three programmable bank modes: BG, 8B, 16B.
LP5BGBankArch = iota
LP58BBankArch
LP516BBankArch
)
/* ------------------------------------------------------------------------------------------ */
/* Global variables */
/* ------------------------------------------------------------------------------------------ */
var LP5PlatformSetMap = map[int][]int{
0: {PlatformADL},
1: {PlatformSBR},
}
var LP5SetInfo = map[int]LP5Set{
0: {
SPDRevision: LP5SPDValueRevision1_0,
getBankArch: LP5GetBankArchSet0,
/*
* From JEDEC spec:
* 5:4 (Maximum Activate Window) = 00 (8192 * tREFI)
* 3:0 (Maximum Activate Count) = 1000 (Unlimited MAC)
* Set to 0x08.
*/
optionalFeatures: 0x08,
/*
* For ADL (as per advisory #616599):
* 7:5 (Number of system channels) = 000 (1 channel always)
* 4:3 (Bus width extension) = 00 (no ECC)
* 2:0 (Bus width) = 001 (x16 always)
* Set to 0x01.
*/
busWidthEncoding: 0x01,
},
1: {
SPDRevision: LP5SPDValueRevision1_1,
getBankArch: LP5GetBankArchSet1,
/*
* For Sabrina (as per advisory b/211510456):
* 5:4 (Maximum Activate Window) = 01 (4096 * tREFI)
* 3:0 (Maximum Activate Count) = 1000 (Unlimited MAC)
* Set to 0x18.
*/
optionalFeatures: 0x18,
/*
* For Sabrina (as per advisory b/211510456):
* 7:6 (PPR) = 1 (Post Package Repair is supported)
* Set to 0x40.
*/
otherOptionalFeatures: 0x40,
/*
* For Sabrina (as per advisory b/211510456):
* 7:5 (Number of system channels) = 000 (1 channel always)
* 4:3 (Bus width extension) = 00 (no ECC)
* 2:0 (Bus width) = 010 (x32 always)
* Set to 0x02.
*/
busWidthEncoding: 0x02,
},
}
var LP5PartAttributeMap = map[string]LP5MemAttributes{}
var LP5CurrSet int
/*
* DensityEncoding: Maps the die density in Gb to the SPD encoding of the die density
* as per JESD 21-C.
*
* RowAddressBits: Maps the die density to the number of row address bits.
* Tables 6-11 in JESD209-5B (same for all three bank modes).
*
* TRFCABNs/TRFCPBNs: Maps the die density to the refresh timings.
* Tables 235 and 236 in JESD209-5B (same for all three bank modes).
*/
var LP5DensityGbToSPDEncoding = map[int]LP5DensityParams{
4: {
DensityEncoding: 0x4,
RowAddressBitsx8Channel: 15,
RowAddressBitsx16Channel: 14,
TRFCABNs: 180,
TRFCPBNs: 90,
},
6: {
DensityEncoding: 0xb,
RowAddressBitsx8Channel: 16,
RowAddressBitsx16Channel: 15,
TRFCABNs: 210,
TRFCPBNs: 120,
},
8: {
DensityEncoding: 0x5,
RowAddressBitsx8Channel: 16,
RowAddressBitsx16Channel: 15,
TRFCABNs: 210,
TRFCPBNs: 120,
},
12: {
DensityEncoding: 0x8,
RowAddressBitsx8Channel: 17,
RowAddressBitsx16Channel: 16,
TRFCABNs: 280,
TRFCPBNs: 140,
},
16: {
DensityEncoding: 0x6,
RowAddressBitsx8Channel: 17,
RowAddressBitsx16Channel: 16,
TRFCABNs: 280,
TRFCPBNs: 140,
},
24: {
DensityEncoding: 0x9,
RowAddressBitsx8Channel: 18,
RowAddressBitsx16Channel: 17,
TRFCABNs: 380,
TRFCPBNs: 190,
},
32: {
DensityEncoding: 0x7,
RowAddressBitsx8Channel: 18,
RowAddressBitsx16Channel: 17,
TRFCABNs: 380,
TRFCPBNs: 190,
},
}
/*
* Maps the number of banks to the SPD encoding as per JESD 21-C.
*/
var LP5NumBanksEncoding = map[int]byte{
4: 0x0,
8: 0x1,
16: 0x2,
}
/*
* Maps the Bank Group bits to the SPD encoding as per JESD 21-C.
*/
var LP5BankGroupsEncoding = map[int]byte{
1: 0x0,
2: 0x1,
4: 0x2,
}
/*
* Maps the number of row address bits to the SPD encoding as per JESD 21-C.
*/
var LP5RowAddressBitsEncoding = map[int]byte{
14: 0x2,
15: 0x3,
16: 0x4,
17: 0x5,
18: 0x6,
}
/*
* Maps the number of column address bits to the SPD encoding as per JESD 21-C.
*/
var LP5ColAddressBitsEncoding = map[int]byte{
9: 0x0,
10: 0x1,
11: 0x2,
12: 0x3,
}
var LP5BankArchToSPDEncoding = map[int]LP5BankArchParams{
LP5BGBankArch: {
NumBanks: 4,
BankGroups: 4,
BurstAddressBits: 4,
},
LP58BBankArch: {
NumBanks: 8,
BankGroups: 1,
BurstAddressBits: 5,
},
LP516BBankArch: {
NumBanks: 16,
BankGroups: 1,
BurstAddressBits: 4,
},
}
/*
* TCKMinPs:
* LPDDR5 has two clocks: the command/address clock (CK) and the data clock (WCK). They are
* related by the WCK:CK ratio, which can be either 4:1 or 2:1. On ADL, 4:1 is used.
* For ADL, the MRC expects the tCKmin to encode the CK period. This is calculated as:
* tCKmin = 1 / CK rate
* = 1 / (WCK rate / WCK:CK)
* = 1 / (speed grade / 2 / WCK:CK) // "double data rate"
*
* MaxCASLatency:
* From Table 220 of JESD209-5B, using a 4:1 WCK:CK ratio and Set 0.
*/
var LP5SpeedMbpsToSPDEncoding = map[int]LP5SpeedParams{
6400: {
TCKMinPs: 1250, /* 1 / (6400 / 2 / 4) */
MaxCASLatency: 17,
},
5500: {
TCKMinPs: 1455, /* 1 / (5500 / 2 / 4) */
MaxCASLatency: 15,
},
}
var LP5SPDAttribTable = map[int]LP5SPDAttribTableEntry{
LP5SPDIndexSize: {constVal: LP5SPDValueSize},
LP5SPDIndexRevision: {getVal: LP5EncodeSPDRevision},
LP5SPDIndexMemoryType: {constVal: LP5SPDValueMemoryType},
LP5SPDIndexModuleType: {constVal: LP5SPDValueModuleType},
LP5SPDIndexDensityBanks: {getVal: LP5EncodeDensityBanks},
LP5SPDIndexAddressing: {getVal: LP5EncodeSdramAddressing},
LP5SPDIndexPackageType: {getVal: LP5EncodePackageType},
LP5SPDIndexOptionalFeatures: {getVal: LP5EncodeOptionalFeatures},
LP5SPDIndexOtherOptionalFeatures: {getVal: LP5EncodeOtherOptionalFeatures},
LP5SPDIndexModuleOrganization: {getVal: LP5EncodeModuleOrganization},
LP5SPDIndexBusWidth: {getVal: LP5EncodeBusWidth},
LP5SPDIndexTimebases: {constVal: LP5SPDValueTimebases},
LP5SPDIndexTCKMin: {getVal: LP5EncodeTCKMin},
LP5SPDIndexTCKMinFineOffset: {getVal: LP5EncodeTCKMinFineOffset},
LP5SPDIndexTAAMin: {getVal: LP5EncodeTAAMin},
LP5SPDIndexTAAMinFineOffset: {getVal: LP5EncodeTAAMinFineOffset},
LP5SPDIndexTRCDMin: {getVal: LP5EncodeTRCDMin},
LP5SPDIndexTRCDMinFineOffset: {getVal: LP5EncodeTRCDMinFineOffset},
LP5SPDIndexTRPABMin: {getVal: LP5EncodeTRPABMin},
LP5SPDIndexTRPABMinFineOffset: {getVal: LP5EncodeTRPABMinFineOffset},
LP5SPDIndexTRPPBMin: {getVal: LP5EncodeTRPPBMin},
LP5SPDIndexTRPPBMinFineOffset: {getVal: LP5EncodeTRPPBMinFineOffset},
LP5SPDIndexTRFCABMinLSB: {getVal: LP5EncodeTRFCABMinLsb},
LP5SPDIndexTRFCABMinMSB: {getVal: LP5EncodeTRFCABMinMsb},
LP5SPDIndexTRFCPBMinLSB: {getVal: LP5EncodeTRFCPBMinLsb},
LP5SPDIndexTRFCPBMinMSB: {getVal: LP5EncodeTRFCPBMinMsb},
}
/* ------------------------------------------------------------------------------------------ */
/* Functions */
/* ------------------------------------------------------------------------------------------ */
func LP5EncodeSPDRevision(memAttribs *LP5MemAttributes) byte {
f, ok := LP5SetInfo[LP5CurrSet]
if ok == false {
return 0
}
return f.SPDRevision
}
func LP5GetBankArchSet0(memAttribs *LP5MemAttributes) int {
// ADL will use 8B mode for all parts.
return LP58BBankArch
}
func LP5GetBankArchSet1(memAttribs *LP5MemAttributes) int {
/*
* Sabrina does not support 8B. It uses 16B Bank Architecture for speed <= 3200 Mbps.
* It uses BG Bank Architecture for speed > 3200 Mbps.
*/
if memAttribs.SpeedMbps <= 3200 {
return LP516BBankArch
}
return LP5BGBankArch
}
func LP5GetBankArch(memAttribs *LP5MemAttributes) int {
f, ok := LP5SetInfo[LP5CurrSet]
if ok == false || f.getBankArch == nil {
return LP5BGBankArch
}
return f.getBankArch(memAttribs)
}
func LP5GetNumBanks(memAttribs *LP5MemAttributes) int {
return LP5BankArchToSPDEncoding[LP5GetBankArch(memAttribs)].NumBanks
}
func LP5GetBankGroups(memAttribs *LP5MemAttributes) int {
return LP5BankArchToSPDEncoding[LP5GetBankArch(memAttribs)].BankGroups
}
func LP5EncodeDensityBanks(memAttribs *LP5MemAttributes) byte {
var b byte
// 3:0 Density per die.
b = LP5DensityGbToSPDEncoding[memAttribs.DensityPerDieGb].DensityEncoding
// 5:4 Bank address bits.
b |= LP5NumBanksEncoding[LP5GetNumBanks(memAttribs)] << 4
// 7:6 Bank group bits.
b |= LP5BankGroupsEncoding[LP5GetBankGroups(memAttribs)] << 6
return b
}
func LP5GetBurstAddressBits(memAttribs *LP5MemAttributes) int {
return LP5BankArchToSPDEncoding[LP5GetBankArch(memAttribs)].BurstAddressBits
}
func LP5EncodeSdramAddressing(memAttribs *LP5MemAttributes) byte {
var b byte
// 2:0 Column address bits.
b = LP5ColAddressBitsEncoding[LP5ColAddressBits + LP5GetBurstAddressBits(memAttribs)]
// 5:3 Row address bits.
density := memAttribs.DensityPerDieGb
var rowAddressBits int
if memAttribs.BitWidthPerChannel == 8 {
rowAddressBits = LP5DensityGbToSPDEncoding[density].RowAddressBitsx8Channel
} else {
rowAddressBits = LP5DensityGbToSPDEncoding[density].RowAddressBitsx16Channel
}
b |= LP5RowAddressBitsEncoding[rowAddressBits] << 3
return b
}
func LP5EncodePackageType(memAttribs *LP5MemAttributes) byte {
var b byte
// 1:0 Signal loading index.
b = 1
// 3:2 Channels per package.
// Channels per package = package width (e.g. x32) / bitWidthPerChannel (x8 or x16).
// This can equivalently be calculated as diesPerPackage / ranksPerChannel.
// This calculation is used to avoid adding a redundant attribute for package width.
channels := memAttribs.DiesPerPackage / memAttribs.RanksPerChannel
b |= byte(channels>>1) << 2
// 6:4 Dies per package.
b |= (byte(memAttribs.DiesPerPackage) - 1) << 4
// 7:7 Package type.
var packageType byte
if memAttribs.DiesPerPackage > 1 {
packageType = 1 // Non-Monolithic
} else {
packageType = 0 // Monolithic
}
b |= packageType << 7
return b
}
func LP5EncodeModuleOrganization(memAttribs *LP5MemAttributes) byte {
var b byte
// 2:0 Device data width per channel
b = byte(memAttribs.BitWidthPerChannel / 8)
// 5:3 Package ranks per channel
b |= byte(memAttribs.RanksPerChannel-1) << 3
return b
}
func LP5EncodeOptionalFeatures(memAttribs *LP5MemAttributes) byte {
f, ok := LP5SetInfo[LP5CurrSet]
if ok == false {
return 0
}
return f.optionalFeatures
}
func LP5EncodeOtherOptionalFeatures(memAttribs *LP5MemAttributes) byte {
f, ok := LP5SetInfo[LP5CurrSet]
if ok == false {
return 0
}
return f.otherOptionalFeatures
}
func LP5EncodeBusWidth(memAttribs *LP5MemAttributes) byte {
f, ok := LP5SetInfo[LP5CurrSet]
if ok == false {
return 0
}
return f.busWidthEncoding
}
func LP5EncodeTCKMin(memAttribs *LP5MemAttributes) byte {
return convPsToMtbByte(memAttribs.TCKMinPs)
}
func LP5EncodeTCKMinFineOffset(memAttribs *LP5MemAttributes) byte {
return convPsToFtbByte(memAttribs.TCKMinPs)
}
func LP5EncodeTAAMin(memAttribs *LP5MemAttributes) byte {
return convPsToMtbByte(memAttribs.TAAMinPs)
}
func LP5EncodeTAAMinFineOffset(memAttribs *LP5MemAttributes) byte {
return convPsToFtbByte(memAttribs.TAAMinPs)
}
func LP5EncodeTRCDMin(memAttribs *LP5MemAttributes) byte {
return convNsToMtbByte(memAttribs.TRCDMinNs)
}
func LP5EncodeTRCDMinFineOffset(memAttribs *LP5MemAttributes) byte {
return convNsToFtbByte(memAttribs.TRCDMinNs)
}
func LP5EncodeTRPABMin(memAttribs *LP5MemAttributes) byte {
return convNsToMtbByte(memAttribs.TRPABMinNs)
}
func LP5EncodeTRPABMinFineOffset(memAttribs *LP5MemAttributes) byte {
return convNsToFtbByte(memAttribs.TRPABMinNs)
}
func LP5EncodeTRPPBMin(memAttribs *LP5MemAttributes) byte {
return convNsToMtbByte(memAttribs.TRPPBMinNs)
}
func LP5EncodeTRPPBMinFineOffset(memAttribs *LP5MemAttributes) byte {
return convNsToFtbByte(memAttribs.TRPPBMinNs)
}
func LP5EncodeTRFCABMinMsb(memAttribs *LP5MemAttributes) byte {
return byte((convNsToMtb(memAttribs.TRFCABNs) >> 8) & 0xff)
}
func LP5EncodeTRFCABMinLsb(memAttribs *LP5MemAttributes) byte {
return byte(convNsToMtb(memAttribs.TRFCABNs) & 0xff)
}
func LP5EncodeTRFCPBMinMsb(memAttribs *LP5MemAttributes) byte {
return byte((convNsToMtb(memAttribs.TRFCPBNs) >> 8) & 0xff)
}
func LP5EncodeTRFCPBMinLsb(memAttribs *LP5MemAttributes) byte {
return byte(convNsToMtb(memAttribs.TRFCPBNs) & 0xff)
}
func LP5UpdateTCKMin(memAttribs *LP5MemAttributes) {
if memAttribs.TCKMinPs == 0 {
memAttribs.TCKMinPs = LP5SpeedMbpsToSPDEncoding[memAttribs.SpeedMbps].TCKMinPs
}
}
func LP5UpdateTAAMin(memAttribs *LP5MemAttributes) {
if memAttribs.TAAMinPs == 0 {
maxCAS := LP5SpeedMbpsToSPDEncoding[memAttribs.SpeedMbps].MaxCASLatency
memAttribs.TAAMinPs = memAttribs.TCKMinPs * maxCAS
}
}
func LP5UpdateTRFCAB(memAttribs *LP5MemAttributes) {
if memAttribs.TRFCABNs == 0 {
memAttribs.TRFCABNs = LP5DensityGbToSPDEncoding[memAttribs.DensityPerDieGb].TRFCABNs
}
}
func LP5UpdateTRFCPB(memAttribs *LP5MemAttributes) {
if memAttribs.TRFCPBNs == 0 {
memAttribs.TRFCPBNs = LP5DensityGbToSPDEncoding[memAttribs.DensityPerDieGb].TRFCPBNs
}
}
func LP5UpdateTRCD(memAttribs *LP5MemAttributes) {
if memAttribs.TRCDMinNs == 0 {
/* Table 372 from JESD209-5B */
memAttribs.TRCDMinNs = 18
}
}
func LP5UpdateTRPAB(memAttribs *LP5MemAttributes) {
if memAttribs.TRPABMinNs == 0 {
/* Table 372 from JESD209-5B */
memAttribs.TRPABMinNs = 21
}
}
func LP5UpdateTRPPB(memAttribs *LP5MemAttributes) {
if memAttribs.TRPPBMinNs == 0 {
/* Table 372 from JESD209-5B */
memAttribs.TRPPBMinNs = 18
}
}
func lp5UpdateMemoryAttributes(memAttribs *LP5MemAttributes) {
LP5UpdateTCKMin(memAttribs)
LP5UpdateTAAMin(memAttribs)
LP5UpdateTRFCAB(memAttribs)
LP5UpdateTRFCPB(memAttribs)
LP5UpdateTRCD(memAttribs)
LP5UpdateTRPAB(memAttribs)
LP5UpdateTRPPB(memAttribs)
}
func LP5ValidateDensity(density int) error {
if _, ok := LP5DensityGbToSPDEncoding[density]; !ok {
return fmt.Errorf("Incorrect density per die: %d Gb", density)
}
return nil
}
func LP5ValidateDies(dies int) error {
if dies != 2 && dies != 4 && dies != 8 {
return fmt.Errorf("Incorrect dies: %d", dies)
}
return nil
}
func LP5ValidateDataWidth(width int) error {
if width != 8 && width != 16 {
return fmt.Errorf("Incorrect bit width: %d", width)
}
return nil
}
func LP5ValidateRanks(ranks int) error {
if ranks != 1 && ranks != 2 {
return fmt.Errorf("Incorrect ranks: %d", ranks)
}
return nil
}
func LP5ValidateSpeed(speed int) error {
if _, ok := LP5SpeedMbpsToSPDEncoding[speed]; !ok {
return fmt.Errorf("Incorrect speed: %d Mbps", speed)
}
return nil
}
func lp5ValidateMemPartAttributes(memAttribs *LP5MemAttributes) error {
if err := LP5ValidateDensity(memAttribs.DensityPerDieGb); err != nil {
return err
}
if err := LP5ValidateDies(memAttribs.DiesPerPackage); err != nil {
return err
}
if err := LP5ValidateDataWidth(memAttribs.BitWidthPerChannel); err != nil {
return err
}
if err := LP5ValidateRanks(memAttribs.RanksPerChannel); err != nil {
return err
}
if err := LP5ValidateSpeed(memAttribs.SpeedMbps); err != nil {
return err
}
return nil
}
func LP5IsManufacturerPartNumberByte(index int) bool {
if index >= LP5SPDIndexManufacturerPartNumberStartByte &&
index <= LP5SPDIndexManufacturerPartNumberEndByte {
return true
}
return false
}
/* ------------------------------------------------------------------------------------------ */
/* Interface Functions */
/* ------------------------------------------------------------------------------------------ */
func (lp5) getSetMap() map[int][]int {
return LP5PlatformSetMap
}
func (lp5) addNewPart(name string, attribs interface{}) error {
var lp5Attributes LP5MemAttributes
eByte, err := json.Marshal(attribs)
if err != nil {
return err
}
if err := json.Unmarshal(eByte, &lp5Attributes); err != nil {
return err
}
if err := lp5ValidateMemPartAttributes(&lp5Attributes); err != nil {
return err
}
LP5PartAttributeMap[name] = lp5Attributes
return nil
}
func (lp5) getSPDAttribs(name string, set int) (interface{}, error) {
lp5Attributes := LP5PartAttributeMap[name]
LP5CurrSet = set
lp5UpdateMemoryAttributes(&lp5Attributes)
return lp5Attributes, nil
}
func (lp5) getSPDLen() int {
return 512
}
func (lp5) getSPDByte(index int, attribs interface{}) byte {
e, ok := LP5SPDAttribTable[index]
if !ok {
if LP5IsManufacturerPartNumberByte(index) {
return LP5SPDValueManufacturerPartNumberBlank
}
return 0x00
}
if e.getVal != nil {
var lp5Attribs LP5MemAttributes
lp5Attribs = attribs.(LP5MemAttributes)
return e.getVal(&lp5Attribs)
}
return e.constVal
}

View File

@@ -28,10 +28,37 @@ type memPart struct {
}
type memTech interface {
/*
* Returns the set -> platform mapping for the memory technology. Platforms with the
* same SPD requirements should be grouped together into a single set.
*/
getSetMap() map[int][]int
/*
* Takes the name and attributes of a part, as read from the memory_parts JSON file.
* Validates the attributes, returning an error if any attribute has an invalid value.
* Stores the name and attributes internally to be used later.
*/
addNewPart(string, interface{}) error
/*
* Takes the name of a part and a set number.
* Retrieves the part's attributes which were stored by addNewPart(). Updates them by
* setting any optional attributes which weren't specified in the JSON file to their
* default values.
* Returns these updated attributes.
*/
getSPDAttribs(string, int) (interface{}, error)
/*
* Returns the size of an SPD file for this memory technology.
*/
getSPDLen() int
/*
* Takes an SPD byte index and the attributes of a part.
* Returns the value which that SPD byte should be set to based on the attributes.
*/
getSPDByte(int, interface{}) byte
}
@@ -45,6 +72,7 @@ const (
PlatformJSL
PlatformPCO
PlatformCZN
PlatformSBR
PlatformMax
)
@@ -63,6 +91,13 @@ var platformNames = map[int]string{
PlatformJSL: "JSL",
PlatformPCO: "PCO",
PlatformCZN: "CZN",
PlatformSBR: "SBR",
}
var memTechMap = map[string]memTech{
"lp4x": lp4x{},
"ddr4": ddr4{},
"lp5": lp5{},
}
/* ------------------------------------------------------------------------------------------ */
@@ -211,7 +246,9 @@ func usage() {
fmt.Printf("\nUsage: %s <mem_parts_list_json> <mem_technology>\n\n", os.Args[0])
fmt.Printf(" where,\n")
fmt.Printf(" mem_parts_list_json = JSON File containing list of memory parts and attributes\n")
fmt.Printf(" mem_technology = Memory technology -- one of lp4x, ddr4\n\n\n")
fmt.Printf(" mem_technology = Memory technology for which to generate SPDs\n")
fmt.Printf(" supported technologies: %v\n\n\n",
reflect.ValueOf(memTechMap).MapKeys())
}
func main() {
@@ -223,11 +260,8 @@ func main() {
var t memTech
memPartsFilePath, memTechnology := os.Args[1], os.Args[2]
if strings.ToUpper(memTechnology) == "LP4X" {
t = lp4x{}
} else if strings.ToUpper(memTechnology) == "DDR4" {
t = ddr4{}
} else {
t, ok := memTechMap[strings.ToLower(memTechnology)]
if !ok {
log.Fatal("Unsupported memory technology ", memTechnology)
}