xref: /aosp_15_r20/external/coreboot/util/spd_tools/src/spd_gen/lp4x.go (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1/* SPDX-License-Identifier: GPL-2.0-or-later */
2package main
3
4import (
5	"encoding/json"
6	"fmt"
7	"strconv"
8	"strings"
9)
10
11/* ------------------------------------------------------------------------------------------ */
12/*                                     LP4x-defined types                                     */
13/* ------------------------------------------------------------------------------------------ */
14
15type lp4x struct {
16}
17
18type LP4xMemAttributes struct {
19	/* Primary attributes - must be provided by JSON file for each part */
20	DensityPerChannelGb int
21	Banks               int
22	ChannelsPerDie      int
23	DiesPerPackage      int
24	BitWidthPerChannel  int
25	RanksPerChannel     int
26	SpeedMbps           int
27
28	/*
29	 * All the following parameters are optional and required only if the part requires
30	 * special parameters as per the datasheet.
31	 */
32	/* Timing parameters */
33	TRFCABNs   int
34	TRFCPBNs   int
35	TRPABMinNs int
36	TRPPBMinNs int
37	TCKMinPs   int
38	TCKMaxPs   int
39	TAAMinPs   int
40	TRCDMinNs  int
41
42	/* CAS */
43	CASLatencies  string
44	CASFirstByte  byte
45	CASSecondByte byte
46	CASThirdByte  byte
47}
48
49type LP4xSpeedParams struct {
50	TCKMinPs               int
51	TCKMaxPs               int
52	CASLatenciesx16Channel string
53	CASLatenciesx8Channel  string
54}
55
56type LP4xRefreshTimings struct {
57	TRFCABNs int
58	TRFCPBNs int
59}
60
61type LP4xSPDAttribFunc func(*LP4xMemAttributes) byte
62
63type LP4xSPDAttribTableEntry struct {
64	constVal byte
65	getVal   LP4xSPDAttribFunc
66}
67
68type LP4xSetFunc func(*LP4xMemAttributes) int
69
70type LP4xSet struct {
71	getMRCDensity     LP4xSetFunc
72	getDiesPerPackage LP4xSetFunc
73	busWidthEncoding  byte
74	normalizeAttribs  LP4xSetFunc
75}
76
77/* ------------------------------------------------------------------------------------------ */
78/*                                         Constants                                          */
79/* ------------------------------------------------------------------------------------------ */
80
81const (
82	/* SPD Byte Index */
83	LP4xSPDIndexSize                            = 0
84	LP4xSPDIndexRevision                        = 1
85	LP4xSPDIndexMemoryType                      = 2
86	LP4xSPDIndexModuleType                      = 3
87	LP4xSPDIndexDensityBanks                    = 4
88	LP4xSPDIndexAddressing                      = 5
89	LP4xSPDIndexPackageType                     = 6
90	LP4xSPDIndexOptionalFeatures                = 7
91	LP4xSPDIndexModuleOrganization              = 12
92	LP4xSPDIndexBusWidth                        = 13
93	LP4xSPDIndexTimebases                       = 17
94	LP4xSPDIndexTCKMin                          = 18
95	LP4xSPDIndexTCKMax                          = 19
96	LP4xSPDIndexCASFirstByte                    = 20
97	LP4xSPDIndexCASSecondByte                   = 21
98	LP4xSPDIndexCASThirdByte                    = 22
99	LP4xSPDIndexCASFourthByte                   = 23
100	LP4xSPDIndexTAAMin                          = 24
101	LP4xSPDIndexReadWriteLatency                = 25
102	LP4xSPDIndexTRCDMin                         = 26
103	LP4xSPDIndexTRPABMin                        = 27
104	LP4xSPDIndexTRPPBMin                        = 28
105	LP4xSPDIndexTRFCABMinLSB                    = 29
106	LP4xSPDIndexTRFCABMinMSB                    = 30
107	LP4xSPDIndexTRFCPBMinLSB                    = 31
108	LP4xSPDIndexTRFCPBMinMSB                    = 32
109	LP4xSPDIndexTRPPBMinFineOffset              = 120
110	LP4xSPDIndexTRPABMinFineOffset              = 121
111	LP4xSPDIndexTRCDMinFineOffset               = 122
112	LP4xSPDIndexTAAMinFineOffset                = 123
113	LP4xSPDIndexTCKMaxFineOffset                = 124
114	LP4xSPDIndexTCKMinFineOffset                = 125
115	LP4xSPDIndexManufacturerPartNumberStartByte = 329
116	LP4xSPDIndexManufacturerPartNumberEndByte   = 348
117
118	/* SPD Byte Value */
119
120	/*
121	 * From JEDEC spec:
122	 * 6:4 (Bytes total) = 2 (512 bytes)
123	 * 3:0 (Bytes used) = 3 (384 bytes)
124	 * Set to 0x23 for LPDDR4x.
125	 */
126	LP4xSPDValueSize = 0x23
127
128	/*
129	 * From JEDEC spec: Revision 1.1
130	 * Set to 0x11.
131	 */
132	LP4xSPDValueRevision = 0x11
133
134	/* LPDDR4x memory type = 0x11 */
135	LP4xSPDValueMemoryType = 0x11
136
137	/*
138	 * From JEDEC spec:
139	 * 7:7 (Hybrid) = 0 (Not hybrid)
140	 * 6:4 (Hybrid media) = 000 (Not hybrid)
141	 * 3:0 (Base Module Type) = 1110 (Non-DIMM solution)
142	 *
143	 * This is dependent on hardware design. LPDDR4x only has memory down solution.
144	 * Hence this is not hybrid non-DIMM solution.
145	 * Set to 0x0E.
146	 */
147	LP4xSPDValueModuleType = 0x0e
148
149	/*
150	 * From JEDEC spec:
151	 * 5:4 (Maximum Activate Window) = 00 (8192 * tREFI)
152	 * 3:0 (Maximum Activate Count) = 1000 (Unlimited MAC)
153	 *
154	 * Needs to come from datasheet, but most parts seem to support unlimited MAC.
155	 * MR#24 OP3
156	 */
157	LP4xSPDValueOptionalFeatures = 0x08
158
159	/*
160	 * From JEDEC spec:
161	 * 3:2 (MTB) = 00 (0.125ns)
162	 * 1:0 (FTB) = 00 (1ps)
163	 * Set to 0x00.
164	 */
165	LP4xSPDValueTimebases = 0x00
166
167	/* CAS fourth byte: All bits are reserved */
168	LP4xSPDValueCASFourthByte = 0x00
169
170	/* Write Latency Set A and Read Latency DBI-RD disabled. */
171	LP4xSPDValueReadWriteLatency = 0x00
172
173	/* As per JEDEC spec, unused digits of manufacturer part number are left as blank. */
174	LP4xSPDValueManufacturerPartNumberBlank = 0x20
175)
176
177const (
178	/* First Byte */
179	LP4xCAS6  = 1 << 1
180	LP4xCAS10 = 1 << 4
181	LP4xCAS14 = 1 << 7
182	/* Second Byte */
183	LP4xCAS16 = 1 << 0
184	LP4xCAS20 = 1 << 2
185	LP4xCAS22 = 1 << 3
186	LP4xCAS24 = 1 << 4
187	LP4xCAS26 = 1 << 5
188	LP4xCAS28 = 1 << 6
189	/* Third Byte */
190	LP4xCAS32 = 1 << 0
191	LP4xCAS36 = 1 << 2
192	LP4xCAS40 = 1 << 4
193)
194
195const (
196	/*
197	 * JEDEC spec says that TCKmax should be 100ns for all speed grades.
198	 * 100ns in MTB units comes out to be 0x320. But since this is a byte field, set it to
199	 * 0xFF i.e. 31.875ns.
200	 */
201	LP4xTCKMaxPsDefault = 31875
202)
203
204/* ------------------------------------------------------------------------------------------ */
205/*                                    Global variables                                        */
206/* ------------------------------------------------------------------------------------------ */
207
208var LP4xPlatformSetMap = map[int][]int{
209	0: {PlatformTGL, PlatformADL},
210	1: {PlatformJSL, PlatformCZN},
211}
212
213var LP4xSetInfo = map[int]LP4xSet{
214	0: {
215		getMRCDensity:     LP4xGetMRCDensitySet0,
216		getDiesPerPackage: LP4xGetDiesPerPackageSet0,
217		/*
218		 * As per advisory 616599:
219		 * 7:5 (Number of system channels) = 000 (1 channel always)
220		 * 2:0 (Bus width) = 001 (x16 always)
221		 * Set to 0x01.
222		 */
223		busWidthEncoding: 0x01,
224		normalizeAttribs: LP4xNormalizeAttribsSet0,
225	},
226	1: {
227		getMRCDensity:     LP4xGetMRCDensitySet1,
228		getDiesPerPackage: LP4xGetDiesPerPackageSet1,
229		/*
230		* As per advisory 610202:
231		* 7:5 (Number of system channels) = 001 (2 channel always)
232		* 2:0 (Bus width) = 010 (x32 always)
233		* Set to 0x22.
234		 */
235		busWidthEncoding: 0x22,
236	},
237}
238
239var LP4xPartAttributeMap = map[string]LP4xMemAttributes{}
240var LP4xCurrSet int
241
242/* This encodes the density in Gb to SPD values as per JESD 21-C */
243var LP4xDensityGbToSPDEncoding = map[int]byte{
244	4:  0x4,
245	6:  0xb,
246	8:  0x5,
247	12: 0x8,
248	16: 0x6,
249	24: 0x9,
250	32: 0x7,
251}
252
253/*
254 * Table 5 from JESD209-4C.
255 * Maps density per physical channel to row-column encoding as per JESD 21-C for a device with
256 * x8 physical channel.
257 */
258var LP4xDensityGbx8ChannelToRowColumnEncoding = map[int]byte{
259	3:  0x21, /* 16 rows, 10 columns */
260	4:  0x21, /* 16 rows, 10 columns */
261	6:  0x29, /* 17 rows, 10 columns */
262	8:  0x29, /* 17 rows, 10 columns */
263	12: 0x31, /* 18 rows, 10 columns */
264	16: 0x31, /* 18 rows, 10 columns */
265}
266
267/*
268 * Table 3 from JESD209-4C.
269 * Maps density per physical channel to row-column encoding as per JESD 21-C for a device with
270 * x16 physical channel.
271 */
272var LP4xDensityGbx16ChannelToRowColumnEncoding = map[int]byte{
273	4:  0x19, /* 15 rows, 10 columns */
274	6:  0x21, /* 16 rows, 10 columns */
275	8:  0x21, /* 16 rows, 10 columns */
276	12: 0x29, /* 17 rows, 10 columns */
277	16: 0x29, /* 17 rows, 10 columns */
278}
279
280/*
281 * Table 112 from JESD209-4C
282 * Maps density per physical channel to refresh timings. This is the same for x8 and x16
283 * devices.
284 */
285var LP4xDensityGbPhysicalChannelToRefreshEncoding = map[int]LP4xRefreshTimings{
286	3: {
287		TRFCABNs: 180,
288		TRFCPBNs: 90,
289	},
290	4: {
291		TRFCABNs: 180,
292		TRFCPBNs: 90,
293	},
294	6: {
295		TRFCABNs: 280,
296		TRFCPBNs: 140,
297	},
298	8: {
299		TRFCABNs: 280,
300		TRFCPBNs: 140,
301	},
302	12: {
303		TRFCABNs: 380,
304		TRFCPBNs: 190,
305	},
306	16: {
307		TRFCABNs: 380,
308		TRFCPBNs: 190,
309	},
310}
311
312var LP4xBankEncoding = map[int]byte{
313	4: 0 << 4,
314	8: 1 << 4,
315}
316
317var LP4xSpeedMbpsToSPDEncoding = map[int]LP4xSpeedParams{
318	4267: {
319		TCKMinPs:               468, /* 1/4267 * 2 */
320		TCKMaxPs:               LP4xTCKMaxPsDefault,
321		CASLatenciesx16Channel: "6 10 14 20 24 28 32 36",
322		CASLatenciesx8Channel:  "6 10 16 22 26 32 36 40",
323	},
324	3733: {
325		TCKMinPs:               535, /* 1/3733 * 2 */
326		TCKMaxPs:               LP4xTCKMaxPsDefault,
327		CASLatenciesx16Channel: "6 10 14 20 24 28 32",
328		CASLatenciesx8Channel:  "6 10 16 22 26 32 36",
329	},
330	3200: {
331		TCKMinPs:               625, /* 1/3200 * 2 */
332		TCKMaxPs:               LP4xTCKMaxPsDefault,
333		CASLatenciesx16Channel: "6 10 14 20 24 28",
334		CASLatenciesx8Channel:  "6 10 16 22 26 32",
335	},
336}
337
338var LP4xSPDAttribTable = map[int]LP4xSPDAttribTableEntry{
339	LP4xSPDIndexSize:               {constVal: LP4xSPDValueSize},
340	LP4xSPDIndexRevision:           {constVal: LP4xSPDValueRevision},
341	LP4xSPDIndexMemoryType:         {constVal: LP4xSPDValueMemoryType},
342	LP4xSPDIndexModuleType:         {constVal: LP4xSPDValueModuleType},
343	LP4xSPDIndexDensityBanks:       {getVal: LP4xEncodeDensityBanks},
344	LP4xSPDIndexAddressing:         {getVal: LP4xEncodeSdramAddressing},
345	LP4xSPDIndexPackageType:        {getVal: LP4xEncodePackageType},
346	LP4xSPDIndexOptionalFeatures:   {constVal: LP4xSPDValueOptionalFeatures},
347	LP4xSPDIndexModuleOrganization: {getVal: LP4xEncodeModuleOrganization},
348	LP4xSPDIndexBusWidth:           {getVal: LP4xEncodeBusWidth},
349	LP4xSPDIndexTimebases:          {constVal: LP4xSPDValueTimebases},
350	LP4xSPDIndexTCKMin:             {getVal: LP4xEncodeTCKMin},
351	LP4xSPDIndexTCKMax:             {getVal: LP4xEncodeTCKMax},
352	LP4xSPDIndexTCKMaxFineOffset:   {getVal: LP4xEncodeTCKMaxFineOffset},
353	LP4xSPDIndexTCKMinFineOffset:   {getVal: LP4xEncodeTCKMinFineOffset},
354	LP4xSPDIndexCASFirstByte:       {getVal: LP4xEncodeCASFirstByte},
355	LP4xSPDIndexCASSecondByte:      {getVal: LP4xEncodeCASSecondByte},
356	LP4xSPDIndexCASThirdByte:       {getVal: LP4xEncodeCASThirdByte},
357	LP4xSPDIndexCASFourthByte:      {constVal: LP4xSPDValueCASFourthByte},
358	LP4xSPDIndexTAAMin:             {getVal: LP4xEncodeTAAMin},
359	LP4xSPDIndexTAAMinFineOffset:   {getVal: LP4xEncodeTAAMinFineOffset},
360	LP4xSPDIndexReadWriteLatency:   {constVal: LP4xSPDValueReadWriteLatency},
361	LP4xSPDIndexTRCDMin:            {getVal: LP4xEncodeTRCDMin},
362	LP4xSPDIndexTRCDMinFineOffset:  {getVal: LP4xEncodeTRCDMinFineOffset},
363	LP4xSPDIndexTRPABMin:           {getVal: LP4xEncodeTRPABMin},
364	LP4xSPDIndexTRPABMinFineOffset: {getVal: LP4xEncodeTRPABMinFineOffset},
365	LP4xSPDIndexTRPPBMin:           {getVal: LP4xEncodeTRPPBMin},
366	LP4xSPDIndexTRPPBMinFineOffset: {getVal: LP4xEncodeTRPPBMinFineOffset},
367	LP4xSPDIndexTRFCABMinLSB:       {getVal: LP4xEncodeTRFCABMinLsb},
368	LP4xSPDIndexTRFCABMinMSB:       {getVal: LP4xEncodeTRFCABMinMsb},
369	LP4xSPDIndexTRFCPBMinLSB:       {getVal: LP4xEncodeTRFCPBMinLsb},
370	LP4xSPDIndexTRFCPBMinMSB:       {getVal: LP4xEncodeTRFCPBMinMsb},
371}
372
373/* ------------------------------------------------------------------------------------------ */
374/*                                        Functions                                           */
375/* ------------------------------------------------------------------------------------------ */
376
377func LP4xGetMRCDensitySet0(memAttribs *LP4xMemAttributes) int {
378	/*
379	 * Intel MRC on TGL/ADL expects density per logical channel to be encoded in
380	 * SPDIndexDensityBanks. Logical channel on TGL/ADL is an x16 channel.
381	 */
382	return memAttribs.DensityPerChannelGb * 16 / memAttribs.BitWidthPerChannel
383}
384
385func LP4xGetMRCDensitySet1(memAttribs *LP4xMemAttributes) int {
386	/*
387	 * Intel MRC on JSL expects density per die to be encoded in
388	 * SPDIndexDensityBanks.
389	 */
390	return memAttribs.DensityPerChannelGb * memAttribs.ChannelsPerDie
391}
392
393func LP4xGetMRCDensity(memAttribs *LP4xMemAttributes) int {
394	f, ok := LP4xSetInfo[LP4xCurrSet]
395
396	if ok == false || f.getMRCDensity == nil {
397		return 0
398	}
399
400	return f.getMRCDensity(memAttribs)
401}
402
403func LP4xEncodeDensityBanks(memAttribs *LP4xMemAttributes) byte {
404	var b byte
405
406	b = LP4xDensityGbToSPDEncoding[LP4xGetMRCDensity(memAttribs)]
407	b |= LP4xBankEncoding[memAttribs.Banks]
408
409	return b
410}
411
412func LP4xEncodeSdramAddressing(memAttribs *LP4xMemAttributes) byte {
413	densityPerChannelGb := memAttribs.DensityPerChannelGb
414	if memAttribs.BitWidthPerChannel == 8 {
415		return LP4xDensityGbx8ChannelToRowColumnEncoding[densityPerChannelGb]
416	} else {
417		return LP4xDensityGbx16ChannelToRowColumnEncoding[densityPerChannelGb]
418	}
419	return 0
420}
421
422func LP4xEncodePackage(dies int) byte {
423	var temp byte
424
425	if dies > 1 {
426		/* If more than one die, then this is a non-monolithic device. */
427		temp = 1
428	} else {
429		/* If only single die, then this is a monolithic device. */
430		temp = 0
431	}
432
433	return temp << 7
434}
435
436func LP4xEncodeChannelsPerDie(channels int) byte {
437	var temp byte
438
439	temp = byte(channels >> 1)
440
441	return temp << 2
442}
443
444func LP4xGetDiesPerPackageSet0(memAttribs *LP4xMemAttributes) int {
445	/* Intel MRC expects logical dies to be encoded for TGL/ADL. */
446	return memAttribs.ChannelsPerDie * memAttribs.RanksPerChannel * memAttribs.BitWidthPerChannel / 16
447}
448
449func LP4xGetDiesPerPackageSet1(memAttribs *LP4xMemAttributes) int {
450	/* Intel MRC expects physical dies to be encoded for JSL. */
451	/* AMD PSP expects physical dies (ZQ balls) */
452	return memAttribs.DiesPerPackage
453}
454
455/* Per JESD209-4C Dies = ZQ balls on the package */
456/* Note that this can be different than the part's die count */
457func LP4xEncodeDiesPerPackage(memAttribs *LP4xMemAttributes) byte {
458	var dies int = 0
459
460	f, ok := LP4xSetInfo[LP4xCurrSet]
461	if ok != false && f.getDiesPerPackage != nil {
462		dies = f.getDiesPerPackage(memAttribs)
463	}
464
465	b := LP4xEncodePackage(dies) /* Monolithic / Non-monolithic device */
466	b |= (byte(dies) - 1) << 4
467
468	return b
469}
470
471func LP4xEncodePackageType(memAttribs *LP4xMemAttributes) byte {
472	var b byte
473
474	b |= LP4xEncodeChannelsPerDie(memAttribs.ChannelsPerDie)
475	b |= LP4xEncodeDiesPerPackage(memAttribs)
476
477	return b
478}
479
480func LP4xEncodeDataWidth(bitWidthPerChannel int) byte {
481	return byte(bitWidthPerChannel / 8)
482}
483
484func LP4xEncodeRanks(ranks int) byte {
485	var b byte
486	b = byte(ranks - 1)
487	return b << 3
488}
489
490func LP4xEncodeModuleOrganization(memAttribs *LP4xMemAttributes) byte {
491	var b byte
492
493	b = LP4xEncodeDataWidth(memAttribs.BitWidthPerChannel)
494	b |= LP4xEncodeRanks(memAttribs.RanksPerChannel)
495
496	return b
497}
498
499func LP4xEncodeBusWidth(memAttribs *LP4xMemAttributes) byte {
500	f, ok := LP4xSetInfo[LP4xCurrSet]
501
502	if ok == false {
503		return 0
504	}
505
506	return f.busWidthEncoding
507}
508
509func LP4xEncodeTCKMin(memAttribs *LP4xMemAttributes) byte {
510	return convPsToMtbByte(memAttribs.TCKMinPs)
511}
512
513func LP4xEncodeTCKMinFineOffset(memAttribs *LP4xMemAttributes) byte {
514	return convPsToFtbByte(memAttribs.TCKMinPs)
515}
516
517func LP4xEncodeTCKMax(memAttribs *LP4xMemAttributes) byte {
518	return convPsToMtbByte(memAttribs.TCKMaxPs)
519}
520
521func LP4xEncodeTCKMaxFineOffset(memAttribs *LP4xMemAttributes) byte {
522	return convPsToFtbByte(memAttribs.TCKMaxPs)
523}
524
525func LP4xEncodeCASFirstByte(memAttribs *LP4xMemAttributes) byte {
526	return memAttribs.CASFirstByte
527}
528
529func LP4xEncodeCASSecondByte(memAttribs *LP4xMemAttributes) byte {
530	return memAttribs.CASSecondByte
531}
532
533func LP4xEncodeCASThirdByte(memAttribs *LP4xMemAttributes) byte {
534	return memAttribs.CASThirdByte
535}
536
537func LP4xEncodeTAAMin(memAttribs *LP4xMemAttributes) byte {
538	return convPsToMtbByte(memAttribs.TAAMinPs)
539}
540
541func LP4xEncodeTAAMinFineOffset(memAttribs *LP4xMemAttributes) byte {
542	return convPsToFtbByte(memAttribs.TAAMinPs)
543}
544
545func LP4xEncodeTRCDMin(memAttribs *LP4xMemAttributes) byte {
546	return convNsToMtbByte(memAttribs.TRCDMinNs)
547}
548
549func LP4xEncodeTRCDMinFineOffset(memAttribs *LP4xMemAttributes) byte {
550	return convNsToFtbByte(memAttribs.TRCDMinNs)
551}
552
553func LP4xEncodeTRPABMin(memAttribs *LP4xMemAttributes) byte {
554	return convNsToMtbByte(memAttribs.TRPABMinNs)
555}
556
557func LP4xEncodeTRPABMinFineOffset(memAttribs *LP4xMemAttributes) byte {
558	return convNsToFtbByte(memAttribs.TRPABMinNs)
559}
560
561func LP4xEncodeTRPPBMin(memAttribs *LP4xMemAttributes) byte {
562	return convNsToMtbByte(memAttribs.TRPPBMinNs)
563}
564
565func LP4xEncodeTRPPBMinFineOffset(memAttribs *LP4xMemAttributes) byte {
566	return convNsToFtbByte(memAttribs.TRPPBMinNs)
567}
568
569func LP4xEncodeTRFCABMinMsb(memAttribs *LP4xMemAttributes) byte {
570	return byte((convNsToMtb(memAttribs.TRFCABNs) >> 8) & 0xff)
571}
572
573func LP4xEncodeTRFCABMinLsb(memAttribs *LP4xMemAttributes) byte {
574	return byte(convNsToMtb(memAttribs.TRFCABNs) & 0xff)
575}
576
577func LP4xEncodeTRFCPBMinMsb(memAttribs *LP4xMemAttributes) byte {
578	return byte((convNsToMtb(memAttribs.TRFCPBNs) >> 8) & 0xff)
579}
580
581func LP4xEncodeTRFCPBMinLsb(memAttribs *LP4xMemAttributes) byte {
582	return byte(convNsToMtb(memAttribs.TRFCPBNs) & 0xff)
583}
584
585func LP4xEncodeLatencies(latency int, memAttribs *LP4xMemAttributes) error {
586	switch latency {
587	case 6:
588		memAttribs.CASFirstByte |= LP4xCAS6
589	case 10:
590		memAttribs.CASFirstByte |= LP4xCAS10
591	case 14:
592		memAttribs.CASFirstByte |= LP4xCAS14
593	case 16:
594		memAttribs.CASSecondByte |= LP4xCAS16
595	case 20:
596		memAttribs.CASSecondByte |= LP4xCAS20
597	case 22:
598		memAttribs.CASSecondByte |= LP4xCAS22
599	case 24:
600		memAttribs.CASSecondByte |= LP4xCAS24
601	case 26:
602		memAttribs.CASSecondByte |= LP4xCAS26
603	case 28:
604		memAttribs.CASSecondByte |= LP4xCAS28
605	case 32:
606		memAttribs.CASThirdByte |= LP4xCAS32
607	case 36:
608		memAttribs.CASThirdByte |= LP4xCAS36
609	case 40:
610		memAttribs.CASThirdByte |= LP4xCAS40
611	default:
612		fmt.Errorf("Incorrect CAS Latency: ", latency)
613	}
614
615	return nil
616}
617
618func LP4xUpdateTCK(memAttribs *LP4xMemAttributes) {
619	if memAttribs.TCKMinPs == 0 {
620		memAttribs.TCKMinPs = LP4xSpeedMbpsToSPDEncoding[memAttribs.SpeedMbps].TCKMinPs
621	}
622	if memAttribs.TCKMaxPs == 0 {
623		memAttribs.TCKMaxPs = LP4xSpeedMbpsToSPDEncoding[memAttribs.SpeedMbps].TCKMaxPs
624	}
625}
626
627func LP4xGetCASLatencies(memAttribs *LP4xMemAttributes) string {
628	if memAttribs.BitWidthPerChannel == 16 {
629		return LP4xSpeedMbpsToSPDEncoding[memAttribs.SpeedMbps].CASLatenciesx16Channel
630	} else if memAttribs.BitWidthPerChannel == 8 {
631		return LP4xSpeedMbpsToSPDEncoding[memAttribs.SpeedMbps].CASLatenciesx8Channel
632	}
633
634	return ""
635}
636
637func LP4xUpdateCAS(memAttribs *LP4xMemAttributes) error {
638	if len(memAttribs.CASLatencies) == 0 {
639		memAttribs.CASLatencies = LP4xGetCASLatencies(memAttribs)
640	}
641
642	latencies := strings.Fields(memAttribs.CASLatencies)
643	for i := 0; i < len(latencies); i++ {
644		latency, err := strconv.Atoi(latencies[i])
645		if err != nil {
646			return fmt.Errorf("Unable to convert latency ", latencies[i])
647		}
648		if err := LP4xEncodeLatencies(latency, memAttribs); err != nil {
649			return err
650		}
651	}
652	return nil
653}
654
655func LP4xGetMinCAS(memAttribs *LP4xMemAttributes) (int, error) {
656	if (memAttribs.CASThirdByte & LP4xCAS40) != 0 {
657		return 40, nil
658	}
659	if (memAttribs.CASThirdByte & LP4xCAS36) != 0 {
660		return 36, nil
661	}
662	if (memAttribs.CASThirdByte & LP4xCAS32) != 0 {
663		return 32, nil
664	}
665	if (memAttribs.CASSecondByte & LP4xCAS28) != 0 {
666		return 28, nil
667	}
668
669	return 0, fmt.Errorf("Unexpected min CAS")
670}
671
672func LP4xUpdateTAAMin(memAttribs *LP4xMemAttributes) error {
673	if memAttribs.TAAMinPs == 0 {
674		minCAS, err := LP4xGetMinCAS(memAttribs)
675		if err != nil {
676			return err
677		}
678		memAttribs.TAAMinPs = memAttribs.TCKMinPs * minCAS
679	}
680
681	return nil
682}
683
684func LP4xUpdateTRFCAB(memAttribs *LP4xMemAttributes) {
685	if memAttribs.TRFCABNs == 0 {
686		memAttribs.TRFCABNs = LP4xDensityGbPhysicalChannelToRefreshEncoding[memAttribs.DensityPerChannelGb].TRFCABNs
687	}
688}
689
690func LP4xUpdateTRFCPB(memAttribs *LP4xMemAttributes) {
691	if memAttribs.TRFCPBNs == 0 {
692		memAttribs.TRFCPBNs = LP4xDensityGbPhysicalChannelToRefreshEncoding[memAttribs.DensityPerChannelGb].TRFCPBNs
693	}
694}
695
696func LP4xUpdateTRCD(memAttribs *LP4xMemAttributes) {
697	if memAttribs.TRCDMinNs == 0 {
698		/* JEDEC spec says max of 18ns */
699		memAttribs.TRCDMinNs = 18
700	}
701}
702
703func LP4xUpdateTRPAB(memAttribs *LP4xMemAttributes) {
704	if memAttribs.TRPABMinNs == 0 {
705		/* JEDEC spec says max of 21ns */
706		memAttribs.TRPABMinNs = 21
707	}
708}
709
710func LP4xUpdateTRPPB(memAttribs *LP4xMemAttributes) {
711	if memAttribs.TRPPBMinNs == 0 {
712		/* JEDEC spec says max of 18ns */
713		memAttribs.TRPPBMinNs = 18
714	}
715}
716
717func LP4xNormalizeAttribsSet0(memAttribs *LP4xMemAttributes) int {
718	/*
719	 * TGL does not really use physical organization of dies per package when
720	 * generating the SPD. So, set it to 0 here so that deduplication ignores
721	 * that field.
722	 */
723	memAttribs.DiesPerPackage = 0
724
725	return 0
726}
727
728func LP4xNormalizeMemoryAttributes(memAttribs *LP4xMemAttributes) {
729	f, ok := LP4xSetInfo[LP4xCurrSet]
730
731	if ok == false || f.normalizeAttribs == nil {
732		return
733	}
734
735	f.normalizeAttribs(memAttribs)
736}
737
738func Lp4xUpdateMemoryAttributes(memAttribs *LP4xMemAttributes) error {
739	LP4xUpdateTCK(memAttribs)
740	if err := LP4xUpdateCAS(memAttribs); err != nil {
741		return err
742	}
743	if err := LP4xUpdateTAAMin(memAttribs); err != nil {
744		return err
745	}
746	LP4xUpdateTRFCAB(memAttribs)
747	LP4xUpdateTRFCPB(memAttribs)
748	LP4xUpdateTRCD(memAttribs)
749	LP4xUpdateTRPAB(memAttribs)
750	LP4xUpdateTRPPB(memAttribs)
751
752	LP4xNormalizeMemoryAttributes(memAttribs)
753
754	return nil
755}
756
757func LP4xValidateDensityx8Channel(densityPerChannelGb int) error {
758	if _, ok := LP4xDensityGbx8ChannelToRowColumnEncoding[densityPerChannelGb]; ok == false {
759		return fmt.Errorf("Incorrect x8 density: %d Gb", densityPerChannelGb)
760	}
761	return nil
762}
763
764func LP4xValidateDensityx16Channel(densityPerChannelGb int) error {
765	if _, ok := LP4xDensityGbx16ChannelToRowColumnEncoding[densityPerChannelGb]; ok == false {
766		return fmt.Errorf("Incorrect x16 density: %d Gb", densityPerChannelGb)
767	}
768	return nil
769}
770
771func LP4xValidateDensity(memAttribs *LP4xMemAttributes) error {
772	if memAttribs.BitWidthPerChannel == 8 {
773		return LP4xValidateDensityx8Channel(memAttribs.DensityPerChannelGb)
774	} else if memAttribs.BitWidthPerChannel == 16 {
775		return LP4xValidateDensityx16Channel(memAttribs.DensityPerChannelGb)
776	}
777
778	return fmt.Errorf("No density table for this bit width: %d", memAttribs.BitWidthPerChannel)
779}
780
781func LP4xValidateBanks(banks int) error {
782	if banks != 4 && banks != 8 {
783		return fmt.Errorf("Incorrect banks: %d", banks)
784	}
785	return nil
786}
787
788func LP4xValidateChannels(channels int) error {
789	if channels != 1 && channels != 2 && channels != 4 {
790		return fmt.Errorf("Incorrect channels per die: %d ", channels)
791	}
792	return nil
793}
794
795func LP4xValidateDataWidth(width int) error {
796	if width != 8 && width != 16 {
797		return fmt.Errorf("Incorrect bit width: %d", width)
798	}
799	return nil
800}
801
802func LP4xValidateRanks(ranks int) error {
803	if ranks != 1 && ranks != 2 {
804		return fmt.Errorf("Incorrect ranks: %d", ranks)
805	}
806	return nil
807}
808
809func LP4xValidateSpeed(speed int) error {
810	if _, ok := LP4xSpeedMbpsToSPDEncoding[speed]; ok == false {
811		return fmt.Errorf("Incorrect speed: %d Mbps", speed)
812	}
813	return nil
814}
815
816func Lp4xValidateMemPartAttributes(memAttribs *LP4xMemAttributes) error {
817	if err := LP4xValidateBanks(memAttribs.Banks); err != nil {
818		return err
819	}
820	if err := LP4xValidateChannels(memAttribs.ChannelsPerDie); err != nil {
821		return err
822	}
823	if err := LP4xValidateDataWidth(memAttribs.BitWidthPerChannel); err != nil {
824		return err
825	}
826	if err := LP4xValidateDensity(memAttribs); err != nil {
827		return err
828	}
829	if err := LP4xValidateRanks(memAttribs.RanksPerChannel); err != nil {
830		return err
831	}
832	if err := LP4xValidateSpeed(memAttribs.SpeedMbps); err != nil {
833		return err
834	}
835
836	return nil
837}
838
839func LP4xIsManufacturerPartNumberByte(index int) bool {
840	if index >= LP4xSPDIndexManufacturerPartNumberStartByte &&
841		index <= LP4xSPDIndexManufacturerPartNumberEndByte {
842		return true
843	}
844	return false
845}
846
847/* ------------------------------------------------------------------------------------------ */
848/*                                 Interface Functions                                       */
849/* ------------------------------------------------------------------------------------------ */
850
851func (lp4x) getSetMap() map[int][]int {
852	return LP4xPlatformSetMap
853}
854
855func (lp4x) addNewPart(name string, attribs interface{}) error {
856	var lp4xAttributes LP4xMemAttributes
857	eByte, err := json.Marshal(attribs)
858	if err != nil {
859		return err
860	}
861
862	if err := json.Unmarshal(eByte, &lp4xAttributes); err != nil {
863		return err
864	}
865
866	if err := Lp4xValidateMemPartAttributes(&lp4xAttributes); err != nil {
867		return err
868	}
869
870	LP4xPartAttributeMap[name] = lp4xAttributes
871	return nil
872}
873
874func (lp4x) getSPDAttribs(name string, set int) (interface{}, error) {
875	lp4xAttributes := LP4xPartAttributeMap[name]
876
877	LP4xCurrSet = set
878
879	if err := Lp4xUpdateMemoryAttributes(&lp4xAttributes); err != nil {
880		return lp4xAttributes, err
881	}
882
883	return lp4xAttributes, nil
884}
885
886func (lp4x) getSPDLen() int {
887	return 512
888}
889
890func (lp4x) getSPDByte(index int, attribs interface{}) byte {
891	e, ok := LP4xSPDAttribTable[index]
892	if ok == false {
893		if LP4xIsManufacturerPartNumberByte(index) {
894			return LP4xSPDValueManufacturerPartNumberBlank
895		}
896		return 0x00
897	}
898
899	if e.getVal != nil {
900		var lp4xAttribs LP4xMemAttributes
901		lp4xAttribs = attribs.(LP4xMemAttributes)
902		return e.getVal(&lp4xAttribs)
903	}
904
905	return e.constVal
906}
907