xref: /aosp_15_r20/external/coreboot/util/spd_tools/src/spd_gen/lp5.go (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1/* SPDX-License-Identifier: GPL-2.0-or-later */
2package main
3
4import (
5	"encoding/json"
6	"fmt"
7)
8
9/* ------------------------------------------------------------------------------------------ */
10/*                                     LP5-defined types                                      */
11/* ------------------------------------------------------------------------------------------ */
12
13type lp5 struct {
14}
15
16type LP5MemAttributes struct {
17	/* Primary attributes - must be provided by JSON file for each part */
18	DensityPerDieGb    int
19	DiesPerPackage     int
20	BitWidthPerChannel int
21	RanksPerChannel    int
22	SpeedMbps          int
23
24	/*
25	 * All the following parameters are optional and required only if the part requires
26	 * special parameters as per the datasheet.
27	 */
28	LP5X bool
29
30	/* Timing parameters */
31	TRFCABNs   int
32	TRFCPBNs   int
33	TRPABMinNs int
34	TRPPBMinNs int
35	TCKMinPs   int
36	TAAMinPs   int
37	TRCDMinNs  int
38}
39
40type LP5DensityParams struct {
41	DensityEncoding          byte
42	RowAddressBitsx8Channel  int
43	RowAddressBitsx16Channel int
44	TRFCABNs                 int
45	TRFCPBNs                 int
46}
47
48type LP5SpeedParams struct {
49	defaultTCKMinPs int
50	MaxCASLatency   int
51}
52
53type LP5BankArchParams struct {
54	NumBanks         int
55	BankGroups       int
56	BurstAddressBits int
57}
58
59type LP5SPDAttribFunc func(*LP5MemAttributes) byte
60
61type LP5SPDAttribTableEntry struct {
62	constVal byte
63	getVal   LP5SPDAttribFunc
64}
65
66type LP5SetFunc func(*LP5MemAttributes) int
67
68type LP5Set struct {
69	SPDRevision           byte
70	getBankArch           LP5SetFunc
71	optionalFeatures      byte
72	otherOptionalFeatures byte
73	busWidthEncoding      byte
74	speedToTCKMinPs       map[int]int
75}
76
77/* ------------------------------------------------------------------------------------------ */
78/*                                         Constants                                          */
79/* ------------------------------------------------------------------------------------------ */
80
81const (
82	/* SPD Byte Index */
83	LP5SPDIndexSize                            = 0
84	LP5SPDIndexRevision                        = 1
85	LP5SPDIndexMemoryType                      = 2
86	LP5SPDIndexModuleType                      = 3
87	LP5SPDIndexDensityBanks                    = 4
88	LP5SPDIndexAddressing                      = 5
89	LP5SPDIndexPackageType                     = 6
90	LP5SPDIndexOptionalFeatures                = 7
91	LP5SPDIndexOtherOptionalFeatures           = 9
92	LP5SPDIndexModuleOrganization              = 12
93	LP5SPDIndexBusWidth                        = 13
94	LP5SPDIndexTimebases                       = 17
95	LP5SPDIndexTCKMin                          = 18
96	LP5SPDIndexTAAMin                          = 24
97	LP5SPDIndexTRCDMin                         = 26
98	LP5SPDIndexTRPABMin                        = 27
99	LP5SPDIndexTRPPBMin                        = 28
100	LP5SPDIndexTRFCABMinLSB                    = 29
101	LP5SPDIndexTRFCABMinMSB                    = 30
102	LP5SPDIndexTRFCPBMinLSB                    = 31
103	LP5SPDIndexTRFCPBMinMSB                    = 32
104	LP5SPDIndexTRPPBMinFineOffset              = 120
105	LP5SPDIndexTRPABMinFineOffset              = 121
106	LP5SPDIndexTRCDMinFineOffset               = 122
107	LP5SPDIndexTAAMinFineOffset                = 123
108	LP5SPDIndexTCKMinFineOffset                = 125
109	LP5SPDIndexManufacturerPartNumberStartByte = 329
110	LP5SPDIndexManufacturerPartNumberEndByte   = 348
111
112	/* SPD Byte Value */
113
114	/*
115	 * From JEDEC spec:
116	 * 6:4 (Bytes total) = 2 (512 bytes)
117	 * 3:0 (Bytes used) = 3 (384 bytes)
118	 * Set to 0x23 for LPDDR5.
119	 */
120	LP5SPDValueSize = 0x23
121
122	/*
123	 * Revision 1.0. Expected by ADL
124	 */
125	LP5SPDValueRevision1_0 = 0x10
126	/*
127	 * Revision 1.1. Expected by Mendocino
128	 */
129	LP5SPDValueRevision1_1 = 0x11
130
131	/*
132	 * As per advisory #616599, ADL MRC expects LPDDR5 memory type = 0x13.
133	 * From JEDEC spec, LPDDR5X memory type = 0x15.
134	 */
135	LP5SPDValueMemoryType  = 0x13
136	LP5XSPDValueMemoryType = 0x15
137
138	/*
139	 * From JEDEC spec:
140	 * 7:7 (Hybrid) = 0 (Not hybrid)
141	 * 6:4 (Hybrid media) = 000 (Not hybrid)
142	 * 3:0 (Base Module Type) = 1110 (Non-DIMM solution)
143	 *
144	 * This is dependent on hardware design. LPDDR5 only has memory down solution.
145	 * Hence this is not hybrid non-DIMM solution.
146	 * Set to 0x0E.
147	 */
148	LP5SPDValueModuleType = 0x0e
149
150	/*
151	 * From JEDEC spec:
152	 * 3:2 (MTB) = 00 (0.125ns)
153	 * 1:0 (FTB) = 00 (1ps)
154	 * Set to 0x00.
155	 */
156	LP5SPDValueTimebases = 0x00
157
158	/* As per JEDEC spec, unused digits of manufacturer part number are left as blank. */
159	LP5SPDValueManufacturerPartNumberBlank = 0x20
160)
161
162const (
163	// The column addresses are the same for x8 & x16 and for all Bank Architectures.
164	LP5ColAddressBits = 6
165)
166
167const (
168	// LPDDR5 has a flexible bank architecture with three programmable bank modes: BG, 8B, 16B.
169	LP5BGBankArch = iota
170	LP58BBankArch
171	LP516BBankArch
172)
173
174/* ------------------------------------------------------------------------------------------ */
175/*                                    Global variables                                        */
176/* ------------------------------------------------------------------------------------------ */
177
178var LP5PlatformSetMap = map[int][]int{
179	0: {PlatformMTL, PlatformADL},
180	1: {PlatformPHX, PlatformMDN},
181}
182
183var LP5SetInfo = map[int]LP5Set{
184	0: {
185		SPDRevision: LP5SPDValueRevision1_0,
186		getBankArch: LP5GetBankArchSet0,
187		/*
188		 * From JEDEC spec:
189		 * 5:4 (Maximum Activate Window) = 00 (8192 * tREFI)
190		 * 3:0 (Maximum Activate Count) = 1000 (Unlimited MAC)
191		 * Set to 0x08.
192		 */
193		optionalFeatures: 0x08,
194		/*
195		 * For ADL (as per advisory #616599):
196		 * 7:5 (Number of system channels) = 000 (1 channel always)
197		 * 4:3 (Bus width extension) = 00 (no ECC)
198		 * 2:0 (Bus width) = 001 (x16 always)
199		 * Set to 0x01.
200		 */
201		busWidthEncoding: 0x01,
202		/*
203		 * TCKMinPs:
204		 * LPDDR5 has two clocks: the command/address clock (CK) and the data clock (WCK). They are
205		 * related by the WCK:CK ratio, which can be either 4:1 or 2:1. On ADL, 4:1 is used.
206		 * For ADL, the MRC expects the tCKmin to encode the CK cycle time.
207		 *   tCKmin   = 1 / CK rate
208		 *            = 1 / (WCK rate / WCK:CK)
209		 *            = 1 / (speed grade / 2 / WCK:CK)      // "double data rate"
210		 */
211		speedToTCKMinPs: map[int]int{
212			8533: 937,  /* 1 / (8533 / 2 / 4) */
213			7500: 1066, /* 1 / (7500 / 2 / 4) */
214			6400: 1250, /* 1 / (6400 / 2 / 4) */
215			5500: 1455, /* 1 / (5500 / 2 / 4) */
216		},
217	},
218	1: {
219		SPDRevision: LP5SPDValueRevision1_1,
220		getBankArch: LP5GetBankArchSet1,
221		/*
222		 * For Mendocino (as per advisory b/211510456):
223		 * 5:4 (Maximum Activate Window) = 01 (4096 * tREFI)
224		 * 3:0 (Maximum Activate Count) = 1000 (Unlimited MAC)
225		 * Set to 0x18.
226		 */
227		optionalFeatures: 0x18,
228		/*
229		 * For Mendocino (as per advisory b/211510456):
230		 * 7:6 (PPR) = 1 (Post Package Repair is supported)
231		 * Set to 0x40.
232		 */
233		otherOptionalFeatures: 0x40,
234		/*
235		 * For Mendocino (as per advisory b/211510456):
236		 * 7:5 (Number of system channels) = 000 (1 channel always)
237		 * 4:3 (Bus width extension) = 00 (no ECC)
238		 * 2:0 (Bus width) = 010 (x32 always)
239		 * Set to 0x02.
240		 */
241		busWidthEncoding: 0x02,
242	},
243}
244
245var LP5PartAttributeMap = map[string]LP5MemAttributes{}
246var LP5CurrSet int
247
248/*
249 * DensityEncoding: Maps the die density in Gb to the SPD encoding of the die density
250 * as per JESD 21-C.
251 *
252 * RowAddressBits: Maps the die density to the number of row address bits.
253 * Tables 6-11 in JESD209-5B (same for all three bank modes).
254 *
255 * TRFCABNs/TRFCPBNs: Maps the die density to the refresh timings.
256 * Tables 235 and 236 in JESD209-5B (same for all three bank modes).
257 */
258var LP5DensityGbToSPDEncoding = map[int]LP5DensityParams{
259	4: {
260		DensityEncoding:          0x4,
261		RowAddressBitsx8Channel:  15,
262		RowAddressBitsx16Channel: 14,
263		TRFCABNs:                 180,
264		TRFCPBNs:                 90,
265	},
266	6: {
267		DensityEncoding:          0xb,
268		RowAddressBitsx8Channel:  16,
269		RowAddressBitsx16Channel: 15,
270		TRFCABNs:                 210,
271		TRFCPBNs:                 120,
272	},
273	8: {
274		DensityEncoding:          0x5,
275		RowAddressBitsx8Channel:  16,
276		RowAddressBitsx16Channel: 15,
277		TRFCABNs:                 210,
278		TRFCPBNs:                 120,
279	},
280	12: {
281		DensityEncoding:          0x8,
282		RowAddressBitsx8Channel:  17,
283		RowAddressBitsx16Channel: 16,
284		TRFCABNs:                 280,
285		TRFCPBNs:                 140,
286	},
287	16: {
288		DensityEncoding:          0x6,
289		RowAddressBitsx8Channel:  17,
290		RowAddressBitsx16Channel: 16,
291		TRFCABNs:                 280,
292		TRFCPBNs:                 140,
293	},
294	24: {
295		DensityEncoding:          0x9,
296		RowAddressBitsx8Channel:  18,
297		RowAddressBitsx16Channel: 17,
298		TRFCABNs:                 380,
299		TRFCPBNs:                 190,
300	},
301	32: {
302		DensityEncoding:          0x7,
303		RowAddressBitsx8Channel:  18,
304		RowAddressBitsx16Channel: 17,
305		TRFCABNs:                 380,
306		TRFCPBNs:                 190,
307	},
308}
309
310/*
311 * Maps the number of banks to the SPD encoding as per JESD 21-C.
312 */
313var LP5NumBanksEncoding = map[int]byte{
314	4:  0x0,
315	8:  0x1,
316	16: 0x2,
317}
318
319/*
320 * Maps the Bank Group bits to the SPD encoding as per JESD 21-C.
321 */
322var LP5BankGroupsEncoding = map[int]byte{
323	1: 0x0,
324	2: 0x1,
325	4: 0x2,
326}
327
328/*
329 * Maps the number of row address bits to the SPD encoding as per JESD 21-C.
330 */
331var LP5RowAddressBitsEncoding = map[int]byte{
332	14: 0x2,
333	15: 0x3,
334	16: 0x4,
335	17: 0x5,
336	18: 0x6,
337}
338
339/*
340 * Maps the number of column address bits to the SPD encoding as per JESD 21-C.
341 */
342var LP5ColAddressBitsEncoding = map[int]byte{
343	9:  0x0,
344	10: 0x1,
345	11: 0x2,
346	12: 0x3,
347}
348
349var LP5BankArchToSPDEncoding = map[int]LP5BankArchParams{
350	LP5BGBankArch: {
351		NumBanks:         4,
352		BankGroups:       4,
353		BurstAddressBits: 4,
354	},
355	LP58BBankArch: {
356		NumBanks:         8,
357		BankGroups:       1,
358		BurstAddressBits: 5,
359	},
360	LP516BBankArch: {
361		NumBanks:         16,
362		BankGroups:       1,
363		BurstAddressBits: 4,
364	},
365}
366
367/*
368 * TCKMinPs:
369 * Data sheets recommend encoding the the WCK cycle time.
370 *   tCKmin   = 1 / WCK rate
371 *            = 1 / (speed grade / 2)      // "double data rate"
372 *
373 * MaxCASLatency:
374 * From Table 220 of JESD209-5B, using a 4:1 WCK:CK ratio and Set 0.
375 */
376var LP5SpeedMbpsToSPDEncoding = map[int]LP5SpeedParams{
377	8533: {
378		defaultTCKMinPs: 234, /* 1 / (8533 / 2) */
379		MaxCASLatency:   23,
380	},
381	7500: {
382		defaultTCKMinPs: 266, /* 1 / (7500 / 2) */
383		MaxCASLatency:   20,
384	},
385	6400: {
386		defaultTCKMinPs: 312, /* 1 / (6400 / 2) */
387		MaxCASLatency:   17,
388	},
389	5500: {
390		defaultTCKMinPs: 363, /* 1 / (5500 / 2) */
391		MaxCASLatency:   15,
392	},
393}
394
395var LP5SPDAttribTable = map[int]LP5SPDAttribTableEntry{
396	LP5SPDIndexSize:                  {constVal: LP5SPDValueSize},
397	LP5SPDIndexRevision:              {getVal: LP5EncodeSPDRevision},
398	LP5SPDIndexMemoryType:            {getVal: LP5EncodeMemoryType},
399	LP5SPDIndexModuleType:            {constVal: LP5SPDValueModuleType},
400	LP5SPDIndexDensityBanks:          {getVal: LP5EncodeDensityBanks},
401	LP5SPDIndexAddressing:            {getVal: LP5EncodeSdramAddressing},
402	LP5SPDIndexPackageType:           {getVal: LP5EncodePackageType},
403	LP5SPDIndexOptionalFeatures:      {getVal: LP5EncodeOptionalFeatures},
404	LP5SPDIndexOtherOptionalFeatures: {getVal: LP5EncodeOtherOptionalFeatures},
405	LP5SPDIndexModuleOrganization:    {getVal: LP5EncodeModuleOrganization},
406	LP5SPDIndexBusWidth:              {getVal: LP5EncodeBusWidth},
407	LP5SPDIndexTimebases:             {constVal: LP5SPDValueTimebases},
408	LP5SPDIndexTCKMin:                {getVal: LP5EncodeTCKMin},
409	LP5SPDIndexTCKMinFineOffset:      {getVal: LP5EncodeTCKMinFineOffset},
410	LP5SPDIndexTAAMin:                {getVal: LP5EncodeTAAMin},
411	LP5SPDIndexTAAMinFineOffset:      {getVal: LP5EncodeTAAMinFineOffset},
412	LP5SPDIndexTRCDMin:               {getVal: LP5EncodeTRCDMin},
413	LP5SPDIndexTRCDMinFineOffset:     {getVal: LP5EncodeTRCDMinFineOffset},
414	LP5SPDIndexTRPABMin:              {getVal: LP5EncodeTRPABMin},
415	LP5SPDIndexTRPABMinFineOffset:    {getVal: LP5EncodeTRPABMinFineOffset},
416	LP5SPDIndexTRPPBMin:              {getVal: LP5EncodeTRPPBMin},
417	LP5SPDIndexTRPPBMinFineOffset:    {getVal: LP5EncodeTRPPBMinFineOffset},
418	LP5SPDIndexTRFCABMinLSB:          {getVal: LP5EncodeTRFCABMinLsb},
419	LP5SPDIndexTRFCABMinMSB:          {getVal: LP5EncodeTRFCABMinMsb},
420	LP5SPDIndexTRFCPBMinLSB:          {getVal: LP5EncodeTRFCPBMinLsb},
421	LP5SPDIndexTRFCPBMinMSB:          {getVal: LP5EncodeTRFCPBMinMsb},
422}
423
424/* ------------------------------------------------------------------------------------------ */
425/*                                        Functions                                           */
426/* ------------------------------------------------------------------------------------------ */
427func LP5EncodeSPDRevision(memAttribs *LP5MemAttributes) byte {
428	f, ok := LP5SetInfo[LP5CurrSet]
429
430	if ok == false {
431		return 0
432	}
433
434	return f.SPDRevision
435}
436
437func LP5GetBankArchSet0(memAttribs *LP5MemAttributes) int {
438	// ADL will use 8B mode for all parts.
439	return LP58BBankArch
440}
441
442func LP5GetBankArchSet1(memAttribs *LP5MemAttributes) int {
443	/*
444	 * Mendocino does not support 8B. It uses 16B Bank Architecture for speed <= 3200 Mbps.
445	 * It uses BG Bank Architecture for speed > 3200 Mbps.
446	 */
447	if memAttribs.SpeedMbps <= 3200 {
448		return LP516BBankArch
449	}
450	return LP5BGBankArch
451}
452
453func LP5GetBankArch(memAttribs *LP5MemAttributes) int {
454	f, ok := LP5SetInfo[LP5CurrSet]
455
456	if ok == false || f.getBankArch == nil {
457		return LP5BGBankArch
458	}
459
460	return f.getBankArch(memAttribs)
461}
462
463func LP5GetNumBanks(memAttribs *LP5MemAttributes) int {
464	return LP5BankArchToSPDEncoding[LP5GetBankArch(memAttribs)].NumBanks
465}
466
467func LP5GetBankGroups(memAttribs *LP5MemAttributes) int {
468	return LP5BankArchToSPDEncoding[LP5GetBankArch(memAttribs)].BankGroups
469}
470
471func LP5EncodeMemoryType(memAttribs *LP5MemAttributes) byte {
472	var b byte
473
474	// Mendocino supports LP5x, but doesn't support 0x15 as a memory type currently.
475	// Temporary workaround until it's supported with ABL changes
476	if memAttribs.LP5X && LP5CurrSet != 1 {
477		b = LP5XSPDValueMemoryType
478	} else {
479		b = LP5SPDValueMemoryType
480	}
481	return b
482}
483
484func LP5EncodeDensityBanks(memAttribs *LP5MemAttributes) byte {
485	var b byte
486
487	// 3:0 Density per die.
488	b = LP5DensityGbToSPDEncoding[memAttribs.DensityPerDieGb].DensityEncoding
489
490	// 5:4 Bank address bits.
491	b |= LP5NumBanksEncoding[LP5GetNumBanks(memAttribs)] << 4
492	// 7:6 Bank group bits.
493	b |= LP5BankGroupsEncoding[LP5GetBankGroups(memAttribs)] << 6
494
495	return b
496}
497
498func LP5GetBurstAddressBits(memAttribs *LP5MemAttributes) int {
499	return LP5BankArchToSPDEncoding[LP5GetBankArch(memAttribs)].BurstAddressBits
500}
501
502func LP5EncodeSdramAddressing(memAttribs *LP5MemAttributes) byte {
503	var b byte
504
505	// 2:0 Column address bits.
506	b = LP5ColAddressBitsEncoding[LP5ColAddressBits+LP5GetBurstAddressBits(memAttribs)]
507
508	// 5:3 Row address bits.
509	density := memAttribs.DensityPerDieGb
510	var rowAddressBits int
511	if memAttribs.BitWidthPerChannel == 8 {
512		rowAddressBits = LP5DensityGbToSPDEncoding[density].RowAddressBitsx8Channel
513	} else {
514		rowAddressBits = LP5DensityGbToSPDEncoding[density].RowAddressBitsx16Channel
515	}
516	b |= LP5RowAddressBitsEncoding[rowAddressBits] << 3
517
518	return b
519}
520
521func LP5EncodePackageType(memAttribs *LP5MemAttributes) byte {
522	var b byte
523
524	// 1:0 Signal loading index.
525	b = 1
526
527	// 3:2 Channels per package.
528	// Channels per package = package width (e.g. x32) / bitWidthPerChannel (x8 or x16).
529	// This can equivalently be calculated as diesPerPackage / ranksPerChannel.
530	// This calculation is used to avoid adding a redundant attribute for package width.
531	channels := memAttribs.DiesPerPackage / memAttribs.RanksPerChannel
532	b |= byte(channels>>1) << 2
533
534	// 6:4 Dies per package.
535	b |= (byte(memAttribs.DiesPerPackage) - 1) << 4
536
537	// 7:7 Package type.
538	var packageType byte
539	if memAttribs.DiesPerPackage > 1 {
540		packageType = 1 // Non-Monolithic
541	} else {
542		packageType = 0 // Monolithic
543	}
544	b |= packageType << 7
545
546	return b
547}
548
549func LP5EncodeModuleOrganization(memAttribs *LP5MemAttributes) byte {
550	var b byte
551
552	// 2:0 Device data width per channel
553	b = byte(memAttribs.BitWidthPerChannel / 8)
554
555	// 5:3 Package ranks per channel
556	b |= byte(memAttribs.RanksPerChannel-1) << 3
557
558	return b
559}
560
561func LP5EncodeOptionalFeatures(memAttribs *LP5MemAttributes) byte {
562	f, ok := LP5SetInfo[LP5CurrSet]
563
564	if ok == false {
565		return 0
566	}
567
568	return f.optionalFeatures
569}
570
571func LP5EncodeOtherOptionalFeatures(memAttribs *LP5MemAttributes) byte {
572	f, ok := LP5SetInfo[LP5CurrSet]
573
574	if ok == false {
575		return 0
576	}
577
578	return f.otherOptionalFeatures
579}
580
581func LP5EncodeBusWidth(memAttribs *LP5MemAttributes) byte {
582	f, ok := LP5SetInfo[LP5CurrSet]
583
584	if ok == false {
585		return 0
586	}
587
588	return f.busWidthEncoding
589}
590
591func LP5GetTCKMinPs(memAttribs *LP5MemAttributes) int {
592	f, ok := LP5SetInfo[LP5CurrSet]
593
594	if ok == false || f.speedToTCKMinPs == nil {
595		return LP5SpeedMbpsToSPDEncoding[memAttribs.SpeedMbps].defaultTCKMinPs
596	}
597
598	tCKMinPs, ok := f.speedToTCKMinPs[memAttribs.SpeedMbps]
599	if ok == false || tCKMinPs == 0 {
600		fmt.Printf("TCKMinPs not defined for speed %d(Mbps) in LP5Set %d\n", memAttribs.SpeedMbps, LP5CurrSet)
601	}
602
603	return tCKMinPs
604}
605
606func LP5EncodeTCKMin(memAttribs *LP5MemAttributes) byte {
607	return convPsToMtbByte(memAttribs.TCKMinPs)
608}
609
610func LP5EncodeTCKMinFineOffset(memAttribs *LP5MemAttributes) byte {
611	return convPsToFtbByte(memAttribs.TCKMinPs)
612}
613
614func LP5EncodeTAAMin(memAttribs *LP5MemAttributes) byte {
615	return convPsToMtbByte(memAttribs.TAAMinPs)
616}
617
618func LP5EncodeTAAMinFineOffset(memAttribs *LP5MemAttributes) byte {
619	return convPsToFtbByte(memAttribs.TAAMinPs)
620}
621
622func LP5EncodeTRCDMin(memAttribs *LP5MemAttributes) byte {
623	return convNsToMtbByte(memAttribs.TRCDMinNs)
624}
625
626func LP5EncodeTRCDMinFineOffset(memAttribs *LP5MemAttributes) byte {
627	return convNsToFtbByte(memAttribs.TRCDMinNs)
628}
629
630func LP5EncodeTRPABMin(memAttribs *LP5MemAttributes) byte {
631	return convNsToMtbByte(memAttribs.TRPABMinNs)
632}
633
634func LP5EncodeTRPABMinFineOffset(memAttribs *LP5MemAttributes) byte {
635	return convNsToFtbByte(memAttribs.TRPABMinNs)
636}
637
638func LP5EncodeTRPPBMin(memAttribs *LP5MemAttributes) byte {
639	return convNsToMtbByte(memAttribs.TRPPBMinNs)
640}
641
642func LP5EncodeTRPPBMinFineOffset(memAttribs *LP5MemAttributes) byte {
643	return convNsToFtbByte(memAttribs.TRPPBMinNs)
644}
645
646func LP5EncodeTRFCABMinMsb(memAttribs *LP5MemAttributes) byte {
647	return byte((convNsToMtb(memAttribs.TRFCABNs) >> 8) & 0xff)
648}
649
650func LP5EncodeTRFCABMinLsb(memAttribs *LP5MemAttributes) byte {
651	return byte(convNsToMtb(memAttribs.TRFCABNs) & 0xff)
652}
653
654func LP5EncodeTRFCPBMinMsb(memAttribs *LP5MemAttributes) byte {
655	return byte((convNsToMtb(memAttribs.TRFCPBNs) >> 8) & 0xff)
656}
657
658func LP5EncodeTRFCPBMinLsb(memAttribs *LP5MemAttributes) byte {
659	return byte(convNsToMtb(memAttribs.TRFCPBNs) & 0xff)
660}
661
662func LP5UpdateTCKMin(memAttribs *LP5MemAttributes) {
663	if memAttribs.TCKMinPs == 0 {
664		memAttribs.TCKMinPs = LP5GetTCKMinPs(memAttribs)
665	}
666}
667
668func LP5UpdateTAAMin(memAttribs *LP5MemAttributes) {
669	if memAttribs.TAAMinPs == 0 {
670		maxCAS := LP5SpeedMbpsToSPDEncoding[memAttribs.SpeedMbps].MaxCASLatency
671		memAttribs.TAAMinPs = memAttribs.TCKMinPs * maxCAS
672	}
673}
674
675func LP5UpdateTRFCAB(memAttribs *LP5MemAttributes) {
676	if memAttribs.TRFCABNs == 0 {
677		memAttribs.TRFCABNs = LP5DensityGbToSPDEncoding[memAttribs.DensityPerDieGb].TRFCABNs
678	}
679}
680
681func LP5UpdateTRFCPB(memAttribs *LP5MemAttributes) {
682	if memAttribs.TRFCPBNs == 0 {
683		memAttribs.TRFCPBNs = LP5DensityGbToSPDEncoding[memAttribs.DensityPerDieGb].TRFCPBNs
684	}
685}
686
687func LP5UpdateTRCD(memAttribs *LP5MemAttributes) {
688	if memAttribs.TRCDMinNs == 0 {
689		/* Table 372 from JESD209-5B */
690		memAttribs.TRCDMinNs = 18
691	}
692}
693
694func LP5UpdateTRPAB(memAttribs *LP5MemAttributes) {
695	if memAttribs.TRPABMinNs == 0 {
696		/* Table 372 from JESD209-5B */
697		memAttribs.TRPABMinNs = 21
698	}
699}
700
701func LP5UpdateTRPPB(memAttribs *LP5MemAttributes) {
702	if memAttribs.TRPPBMinNs == 0 {
703		/* Table 372 from JESD209-5B */
704		memAttribs.TRPPBMinNs = 18
705	}
706}
707
708func lp5UpdateMemoryAttributes(memAttribs *LP5MemAttributes) {
709	LP5UpdateTCKMin(memAttribs)
710	LP5UpdateTAAMin(memAttribs)
711	LP5UpdateTRFCAB(memAttribs)
712	LP5UpdateTRFCPB(memAttribs)
713	LP5UpdateTRCD(memAttribs)
714	LP5UpdateTRPAB(memAttribs)
715	LP5UpdateTRPPB(memAttribs)
716}
717
718func LP5ValidateDensity(density int) error {
719	if _, ok := LP5DensityGbToSPDEncoding[density]; !ok {
720		return fmt.Errorf("Incorrect density per die: %d Gb", density)
721	}
722	return nil
723}
724
725func LP5ValidateDies(dies int) error {
726	if dies != 2 && dies != 4 && dies != 8 {
727		return fmt.Errorf("Incorrect dies: %d", dies)
728	}
729	return nil
730}
731
732func LP5ValidateDataWidth(width int) error {
733	if width != 8 && width != 16 {
734		return fmt.Errorf("Incorrect bit width: %d", width)
735	}
736	return nil
737}
738
739func LP5ValidateRanks(ranks int) error {
740	if ranks != 1 && ranks != 2 {
741		return fmt.Errorf("Incorrect ranks: %d", ranks)
742	}
743	return nil
744}
745
746func LP5ValidateSpeed(speed int) error {
747	if _, ok := LP5SpeedMbpsToSPDEncoding[speed]; !ok {
748		return fmt.Errorf("Incorrect speed: %d Mbps", speed)
749	}
750	return nil
751}
752
753func lp5ValidateMemPartAttributes(memAttribs *LP5MemAttributes) error {
754	if err := LP5ValidateDensity(memAttribs.DensityPerDieGb); err != nil {
755		return err
756	}
757	if err := LP5ValidateDies(memAttribs.DiesPerPackage); err != nil {
758		return err
759	}
760	if err := LP5ValidateDataWidth(memAttribs.BitWidthPerChannel); err != nil {
761		return err
762	}
763	if err := LP5ValidateRanks(memAttribs.RanksPerChannel); err != nil {
764		return err
765	}
766	if err := LP5ValidateSpeed(memAttribs.SpeedMbps); err != nil {
767		return err
768	}
769
770	return nil
771}
772
773func LP5IsManufacturerPartNumberByte(index int) bool {
774	if index >= LP5SPDIndexManufacturerPartNumberStartByte &&
775		index <= LP5SPDIndexManufacturerPartNumberEndByte {
776		return true
777	}
778	return false
779}
780
781/* ------------------------------------------------------------------------------------------ */
782/*                                  Interface Functions                                       */
783/* ------------------------------------------------------------------------------------------ */
784
785func (lp5) getSetMap() map[int][]int {
786	return LP5PlatformSetMap
787}
788
789func (lp5) addNewPart(name string, attribs interface{}) error {
790	var lp5Attributes LP5MemAttributes
791	eByte, err := json.Marshal(attribs)
792	if err != nil {
793		return err
794	}
795
796	if err := json.Unmarshal(eByte, &lp5Attributes); err != nil {
797		return err
798	}
799
800	if err := lp5ValidateMemPartAttributes(&lp5Attributes); err != nil {
801		return err
802	}
803
804	LP5PartAttributeMap[name] = lp5Attributes
805	return nil
806}
807
808func (lp5) getSPDAttribs(name string, set int) (interface{}, error) {
809	lp5Attributes := LP5PartAttributeMap[name]
810
811	LP5CurrSet = set
812
813	lp5UpdateMemoryAttributes(&lp5Attributes)
814
815	return lp5Attributes, nil
816}
817
818func (lp5) getSPDLen() int {
819	return 512
820}
821
822func (lp5) getSPDByte(index int, attribs interface{}) byte {
823	e, ok := LP5SPDAttribTable[index]
824	if !ok {
825		if LP5IsManufacturerPartNumberByte(index) {
826			return LP5SPDValueManufacturerPartNumberBlank
827		}
828		return 0x00
829	}
830
831	if e.getVal != nil {
832		var lp5Attribs LP5MemAttributes
833		lp5Attribs = attribs.(LP5MemAttributes)
834		return e.getVal(&lp5Attribs)
835	}
836
837	return e.constVal
838}
839