blob: 65a7a57c60fa5734b4181bf74b07de58a6e63918 [file] [log] [blame]
/* 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.
*/
LP5X bool
/* 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 {
defaultTCKMinPs 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
speedToTCKMinPs map[int]int
}
/* ------------------------------------------------------------------------------------------ */
/* 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 Mendocino
*/
LP5SPDValueRevision1_1 = 0x11
/*
* As per advisory #616599, ADL MRC expects LPDDR5 memory type = 0x13.
* From JEDEC spec, LPDDR5X memory type = 0x15.
*/
LP5SPDValueMemoryType = 0x13
LP5XSPDValueMemoryType = 0x15
/*
* 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: {PlatformMTL, PlatformADL},
1: {PlatformPHX, PlatformMDN},
}
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,
/*
* 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 cycle time.
* tCKmin = 1 / CK rate
* = 1 / (WCK rate / WCK:CK)
* = 1 / (speed grade / 2 / WCK:CK) // "double data rate"
*/
speedToTCKMinPs: map[int]int{
8533: 937, /* 1 / (8533 / 2 / 4) */
7500: 1066, /* 1 / (7500 / 2 / 4) */
6400: 1250, /* 1 / (6400 / 2 / 4) */
5500: 1455, /* 1 / (5500 / 2 / 4) */
},
},
1: {
SPDRevision: LP5SPDValueRevision1_1,
getBankArch: LP5GetBankArchSet1,
/*
* For Mendocino (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 Mendocino (as per advisory b/211510456):
* 7:6 (PPR) = 1 (Post Package Repair is supported)
* Set to 0x40.
*/
otherOptionalFeatures: 0x40,
/*
* For Mendocino (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:
* Data sheets recommend encoding the the WCK cycle time.
* tCKmin = 1 / WCK rate
* = 1 / (speed grade / 2) // "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{
8533: {
defaultTCKMinPs: 234, /* 1 / (8533 / 2) */
MaxCASLatency: 23,
},
7500: {
defaultTCKMinPs: 266, /* 1 / (7500 / 2) */
MaxCASLatency: 20,
},
6400: {
defaultTCKMinPs: 312, /* 1 / (6400 / 2) */
MaxCASLatency: 17,
},
5500: {
defaultTCKMinPs: 363, /* 1 / (5500 / 2) */
MaxCASLatency: 15,
},
}
var LP5SPDAttribTable = map[int]LP5SPDAttribTableEntry{
LP5SPDIndexSize: {constVal: LP5SPDValueSize},
LP5SPDIndexRevision: {getVal: LP5EncodeSPDRevision},
LP5SPDIndexMemoryType: {getVal: LP5EncodeMemoryType},
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 {
/*
* Mendocino 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 LP5EncodeMemoryType(memAttribs *LP5MemAttributes) byte {
var b byte
// Mendocino supports LP5x, but doesn't support 0x15 as a memory type currently.
// Temporary workaround until it's supported with ABL changes
if memAttribs.LP5X && LP5CurrSet != 1 {
b = LP5XSPDValueMemoryType
} else {
b = LP5SPDValueMemoryType
}
return b
}
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 LP5GetTCKMinPs(memAttribs *LP5MemAttributes) int {
f, ok := LP5SetInfo[LP5CurrSet]
if ok == false || f.speedToTCKMinPs == nil {
return LP5SpeedMbpsToSPDEncoding[memAttribs.SpeedMbps].defaultTCKMinPs
}
tCKMinPs, ok := f.speedToTCKMinPs[memAttribs.SpeedMbps]
if ok == false || tCKMinPs == 0 {
fmt.Printf("TCKMinPs not defined for speed %d(Mbps) in LP5Set %d\n", memAttribs.SpeedMbps, LP5CurrSet)
}
return tCKMinPs
}
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 = LP5GetTCKMinPs(memAttribs)
}
}
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
}