blob: 2e52bd595c4ea45b97b3812af4ec62a2c0b49705 [file] [log] [blame]
Reka Norman2c439ad2021-10-07 16:08:18 +11001/* 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 /* Timing parameters */
29 TRFCABNs int
30 TRFCPBNs int
31 TRPABMinNs int
32 TRPPBMinNs int
33 TCKMinPs int
34 TAAMinPs int
35 TRCDMinNs int
36}
37
38type LP5DensityParams struct {
39 DensityEncoding byte
40 RowAddressBitsx8Channel int
41 RowAddressBitsx16Channel int
42 TRFCABNs int
43 TRFCPBNs int
44}
45
46type LP5SpeedParams struct {
47 TCKMinPs int
48 MaxCASLatency int
49}
50
51type LP5SPDAttribFunc func(*LP5MemAttributes) byte
52
53type LP5SPDAttribTableEntry struct {
54 constVal byte
55 getVal LP5SPDAttribFunc
56}
57
58/* ------------------------------------------------------------------------------------------ */
59/* Constants */
60/* ------------------------------------------------------------------------------------------ */
61
62const (
63 /* SPD Byte Index */
64 LP5SPDIndexSize = 0
65 LP5SPDIndexRevision = 1
66 LP5SPDIndexMemoryType = 2
67 LP5SPDIndexModuleType = 3
68 LP5SPDIndexDensityBanks = 4
69 LP5SPDIndexAddressing = 5
70 LP5SPDIndexPackageType = 6
71 LP5SPDIndexOptionalFeatures = 7
72 LP5SPDIndexModuleOrganization = 12
73 LP5SPDIndexBusWidth = 13
74 LP5SPDIndexTimebases = 17
75 LP5SPDIndexTCKMin = 18
76 LP5SPDIndexTAAMin = 24
77 LP5SPDIndexTRCDMin = 26
78 LP5SPDIndexTRPABMin = 27
79 LP5SPDIndexTRPPBMin = 28
80 LP5SPDIndexTRFCABMinLSB = 29
81 LP5SPDIndexTRFCABMinMSB = 30
82 LP5SPDIndexTRFCPBMinLSB = 31
83 LP5SPDIndexTRFCPBMinMSB = 32
84 LP5SPDIndexTRPPBMinFineOffset = 120
85 LP5SPDIndexTRPABMinFineOffset = 121
86 LP5SPDIndexTRCDMinFineOffset = 122
87 LP5SPDIndexTAAMinFineOffset = 123
88 LP5SPDIndexTCKMinFineOffset = 125
89 LP5SPDIndexManufacturerPartNumberStartByte = 329
90 LP5SPDIndexManufacturerPartNumberEndByte = 348
91
92 /* SPD Byte Value */
93
94 /*
95 * From JEDEC spec:
96 * 6:4 (Bytes total) = 2 (512 bytes)
97 * 3:0 (Bytes used) = 3 (384 bytes)
98 * Set to 0x23 for LPDDR5.
99 */
100 LP5SPDValueSize = 0x23
101
102 /*
103 * Revision 1.0.
104 */
105 LP5SPDValueRevision = 0x10
106
107 /*
108 * As per advisory #616599, ADL MRC expects LPDDR5 memory type = 0x13.
109 */
110 LP5SPDValueMemoryType = 0x13
111
112 /*
113 * From JEDEC spec:
114 * 7:7 (Hybrid) = 0 (Not hybrid)
115 * 6:4 (Hybrid media) = 000 (Not hybrid)
116 * 3:0 (Base Module Type) = 1110 (Non-DIMM solution)
117 *
118 * This is dependent on hardware design. LPDDR5 only has memory down solution.
119 * Hence this is not hybrid non-DIMM solution.
120 * Set to 0x0E.
121 */
122 LP5SPDValueModuleType = 0x0e
123
124 /*
125 * From JEDEC spec:
126 * 5:4 (Maximum Activate Window) = 00 (8192 * tREFI)
127 * 3:0 (Maximum Activate Count) = 1000 (Unlimited MAC)
128 * Set to 0x08.
129 */
130 LP5SPDValueOptionalFeatures = 0x08
131
132 /*
133 * For ADL (as per advisory #616599):
134 * 7:5 (Number of system channels) = 000 (1 channel always)
135 * 4:3 (Bus width extension) = 00 (no ECC)
136 * 2:0 (Bus width) = 001 (x16 always)
137 * Set to 0x01.
138 */
139 LP5SPDValueBusWidth = 0x01
140
141 /*
142 * From JEDEC spec:
143 * 3:2 (MTB) = 00 (0.125ns)
144 * 1:0 (FTB) = 00 (1ps)
145 * Set to 0x00.
146 */
147 LP5SPDValueTimebases = 0x00
148
149 /* As per JEDEC spec, unused digits of manufacturer part number are left as blank. */
150 LP5SPDValueManufacturerPartNumberBlank = 0x20
151)
152
153const (
154 /*
155 * LPDDR5 has a flexible bank architecture with three programmable bank modes: BG, 8B, 16B.
156 * ADL will use 8B mode for all parts.
157 *
158 * From JEDEC spec:
159 * 7:6 (Bank Group Bits) = 00 (no bank groups)
160 * 5:4 (Bank Address Bits) = 01 (8 banks)
161 * Set bits 7:4 to 0b0001.
162 */
163 LP5BankGroupsBanks = 0x1
164
165 /*
166 * Tables 8 and 9 from JESD209-5B.
167 * ADL uses 8B mode for all parts. The column addresses are the same for x8 and x16.
168 * Effective column address bits = column address bits + burst address bits = 6 + 5 = 11.
169 * As per JESD 21-C, this is encoded as 0b010.
170 */
171 LP5ColumnAddressBits = 0x2
172)
173
174/* ------------------------------------------------------------------------------------------ */
175/* Global variables */
176/* ------------------------------------------------------------------------------------------ */
177
178var LP5PlatformSetMap = map[int][]int{
179 0: {PlatformADL},
180}
181
182var LP5PartAttributeMap = map[string]LP5MemAttributes{}
183var LP5CurrSet int
184
185/*
186 * DensityEncoding: Maps the die density in Gb to the SPD encoding of the die density
187 * as per JESD 21-C.
188 *
189 * RowAddressBits: Maps the die density to the number of row address bits.
190 * Tables 6-11 in JESD209-5B (same for all three bank modes).
191 *
192 * TRFCABNs/TRFCPBNs: Maps the die density to the refresh timings.
193 * Tables 235 and 236 in JESD209-5B (same for all three bank modes).
194 */
195var LP5DensityGbToSPDEncoding = map[int]LP5DensityParams{
196 4: {
197 DensityEncoding: 0x4,
198 RowAddressBitsx8Channel: 15,
199 RowAddressBitsx16Channel: 14,
200 TRFCABNs: 180,
201 TRFCPBNs: 90,
202 },
203 6: {
204 DensityEncoding: 0xb,
205 RowAddressBitsx8Channel: 16,
206 RowAddressBitsx16Channel: 15,
207 TRFCABNs: 210,
208 TRFCPBNs: 120,
209 },
210 8: {
211 DensityEncoding: 0x5,
212 RowAddressBitsx8Channel: 16,
213 RowAddressBitsx16Channel: 15,
214 TRFCABNs: 210,
215 TRFCPBNs: 120,
216 },
217 12: {
218 DensityEncoding: 0x8,
219 RowAddressBitsx8Channel: 17,
220 RowAddressBitsx16Channel: 16,
221 TRFCABNs: 280,
222 TRFCPBNs: 140,
223 },
224 16: {
225 DensityEncoding: 0x6,
226 RowAddressBitsx8Channel: 17,
227 RowAddressBitsx16Channel: 16,
228 TRFCABNs: 280,
229 TRFCPBNs: 140,
230 },
231 24: {
232 DensityEncoding: 0x9,
233 RowAddressBitsx8Channel: 18,
234 RowAddressBitsx16Channel: 17,
235 TRFCABNs: 380,
236 TRFCPBNs: 190,
237 },
238 32: {
239 DensityEncoding: 0x7,
240 RowAddressBitsx8Channel: 18,
241 RowAddressBitsx16Channel: 17,
242 TRFCABNs: 380,
243 TRFCPBNs: 190,
244 },
245}
246
247/*
248 * Maps the number of row address bits to the SPD encoding as per JESD 21-C.
249 */
250var LP5RowAddressBitsEncoding = map[int]byte{
251 14: 0x2,
252 15: 0x3,
253 16: 0x4,
254 17: 0x5,
255 18: 0x6,
256}
257
258/*
259 * TCKMinPs:
260 * LPDDR5 has two clocks: the command/address clock (CK) and the data clock (WCK). They are
261 * related by the WCK:CK ratio, which can be either 4:1 or 2:1. On ADL, 4:1 is used.
262 * For ADL, the MRC expects the tCKmin to encode the CK period. This is calculated as:
263 * tCKmin = 1 / CK rate
264 * = 1 / (WCK rate / WCK:CK)
265 * = 1 / (speed grade / 2 / WCK:CK) // "double data rate"
266 *
267 * MaxCASLatency:
268 * From Table 220 of JESD209-5B, using a 4:1 WCK:CK ratio and Set 0.
269 */
270var LP5SpeedMbpsToSPDEncoding = map[int]LP5SpeedParams{
271 6400: {
272 TCKMinPs: 1250, /* 1 / (6400 / 2 / 4) */
273 MaxCASLatency: 17,
274 },
275 5500: {
276 TCKMinPs: 1455, /* 1 / (5500 / 2 / 4) */
277 MaxCASLatency: 15,
278 },
279}
280
281var LP5SPDAttribTable = map[int]LP5SPDAttribTableEntry{
282 LP5SPDIndexSize: {constVal: LP5SPDValueSize},
283 LP5SPDIndexRevision: {constVal: LP5SPDValueRevision},
284 LP5SPDIndexMemoryType: {constVal: LP5SPDValueMemoryType},
285 LP5SPDIndexModuleType: {constVal: LP5SPDValueModuleType},
286 LP5SPDIndexDensityBanks: {getVal: LP5EncodeDensityBanks},
287 LP5SPDIndexAddressing: {getVal: LP5EncodeSdramAddressing},
288 LP5SPDIndexPackageType: {getVal: LP5EncodePackageType},
289 LP5SPDIndexOptionalFeatures: {constVal: LP5SPDValueOptionalFeatures},
290 LP5SPDIndexModuleOrganization: {getVal: LP5EncodeModuleOrganization},
291 LP5SPDIndexBusWidth: {constVal: LP5SPDValueBusWidth},
292 LP5SPDIndexTimebases: {constVal: LP5SPDValueTimebases},
293 LP5SPDIndexTCKMin: {getVal: LP5EncodeTCKMin},
294 LP5SPDIndexTCKMinFineOffset: {getVal: LP5EncodeTCKMinFineOffset},
295 LP5SPDIndexTAAMin: {getVal: LP5EncodeTAAMin},
296 LP5SPDIndexTAAMinFineOffset: {getVal: LP5EncodeTAAMinFineOffset},
297 LP5SPDIndexTRCDMin: {getVal: LP5EncodeTRCDMin},
298 LP5SPDIndexTRCDMinFineOffset: {getVal: LP5EncodeTRCDMinFineOffset},
299 LP5SPDIndexTRPABMin: {getVal: LP5EncodeTRPABMin},
300 LP5SPDIndexTRPABMinFineOffset: {getVal: LP5EncodeTRPABMinFineOffset},
301 LP5SPDIndexTRPPBMin: {getVal: LP5EncodeTRPPBMin},
302 LP5SPDIndexTRPPBMinFineOffset: {getVal: LP5EncodeTRPPBMinFineOffset},
303 LP5SPDIndexTRFCABMinLSB: {getVal: LP5EncodeTRFCABMinLsb},
304 LP5SPDIndexTRFCABMinMSB: {getVal: LP5EncodeTRFCABMinMsb},
305 LP5SPDIndexTRFCPBMinLSB: {getVal: LP5EncodeTRFCPBMinLsb},
306 LP5SPDIndexTRFCPBMinMSB: {getVal: LP5EncodeTRFCPBMinMsb},
307}
308
309/* ------------------------------------------------------------------------------------------ */
310/* Functions */
311/* ------------------------------------------------------------------------------------------ */
312
313func LP5EncodeDensityBanks(memAttribs *LP5MemAttributes) byte {
314 var b byte
315
316 // 3:0 Density per die.
317 b = LP5DensityGbToSPDEncoding[memAttribs.DensityPerDieGb].DensityEncoding
318
319 // 5:4 Bank address bits.
320 // 7:6 Bank group bits.
321 b |= LP5BankGroupsBanks << 4
322
323 return b
324}
325
326func LP5EncodeSdramAddressing(memAttribs *LP5MemAttributes) byte {
327 var b byte
328
329 // 2:0 Column address bits.
330 b = LP5ColumnAddressBits
331
332 // 5:3 Row address bits.
333 density := memAttribs.DensityPerDieGb
334 var rowAddressBits int
335 if memAttribs.BitWidthPerChannel == 8 {
336 rowAddressBits = LP5DensityGbToSPDEncoding[density].RowAddressBitsx8Channel
337 } else {
338 rowAddressBits = LP5DensityGbToSPDEncoding[density].RowAddressBitsx16Channel
339 }
340 b |= LP5RowAddressBitsEncoding[rowAddressBits] << 3
341
342 return b
343}
344
345func LP5EncodePackageType(memAttribs *LP5MemAttributes) byte {
346 var b byte
347
348 // 1:0 Signal loading index.
349 b = 1
350
351 // 3:2 Channels per package.
352 // Channels per package = package width (e.g. x32) / bitWidthPerChannel (x8 or x16).
353 // This can equivalently be calculated as diesPerPackage / ranksPerChannel.
354 // This calculation is used to avoid adding a redundant attribute for package width.
355 channels := memAttribs.DiesPerPackage / memAttribs.RanksPerChannel
356 b |= byte(channels>>1) << 2
357
358 // 6:4 Dies per package.
359 b |= (byte(memAttribs.DiesPerPackage) - 1) << 4
360
361 // 7:7 Package type.
362 var packageType byte
363 if memAttribs.DiesPerPackage > 1 {
364 packageType = 1 // Non-Monolithic
365 } else {
366 packageType = 0 // Monolithic
367 }
368 b |= packageType << 7
369
370 return b
371}
372
373func LP5EncodeModuleOrganization(memAttribs *LP5MemAttributes) byte {
374 var b byte
375
376 // 2:0 Device data width per channel
377 b = byte(memAttribs.BitWidthPerChannel / 8)
378
379 // 5:3 Package ranks per channel
380 b |= byte(memAttribs.RanksPerChannel-1) << 3
381
382 return b
383}
384
385func LP5EncodeTCKMin(memAttribs *LP5MemAttributes) byte {
386 return convPsToMtbByte(memAttribs.TCKMinPs)
387}
388
389func LP5EncodeTCKMinFineOffset(memAttribs *LP5MemAttributes) byte {
390 return convPsToFtbByte(memAttribs.TCKMinPs)
391}
392
393func LP5EncodeTAAMin(memAttribs *LP5MemAttributes) byte {
394 return convPsToMtbByte(memAttribs.TAAMinPs)
395}
396
397func LP5EncodeTAAMinFineOffset(memAttribs *LP5MemAttributes) byte {
398 return convPsToFtbByte(memAttribs.TAAMinPs)
399}
400
401func LP5EncodeTRCDMin(memAttribs *LP5MemAttributes) byte {
402 return convNsToMtbByte(memAttribs.TRCDMinNs)
403}
404
405func LP5EncodeTRCDMinFineOffset(memAttribs *LP5MemAttributes) byte {
406 return convNsToFtbByte(memAttribs.TRCDMinNs)
407}
408
409func LP5EncodeTRPABMin(memAttribs *LP5MemAttributes) byte {
410 return convNsToMtbByte(memAttribs.TRPABMinNs)
411}
412
413func LP5EncodeTRPABMinFineOffset(memAttribs *LP5MemAttributes) byte {
414 return convNsToFtbByte(memAttribs.TRPABMinNs)
415}
416
417func LP5EncodeTRPPBMin(memAttribs *LP5MemAttributes) byte {
418 return convNsToMtbByte(memAttribs.TRPPBMinNs)
419}
420
421func LP5EncodeTRPPBMinFineOffset(memAttribs *LP5MemAttributes) byte {
422 return convNsToFtbByte(memAttribs.TRPPBMinNs)
423}
424
425func LP5EncodeTRFCABMinMsb(memAttribs *LP5MemAttributes) byte {
426 return byte((convNsToMtb(memAttribs.TRFCABNs) >> 8) & 0xff)
427}
428
429func LP5EncodeTRFCABMinLsb(memAttribs *LP5MemAttributes) byte {
430 return byte(convNsToMtb(memAttribs.TRFCABNs) & 0xff)
431}
432
433func LP5EncodeTRFCPBMinMsb(memAttribs *LP5MemAttributes) byte {
434 return byte((convNsToMtb(memAttribs.TRFCPBNs) >> 8) & 0xff)
435}
436
437func LP5EncodeTRFCPBMinLsb(memAttribs *LP5MemAttributes) byte {
438 return byte(convNsToMtb(memAttribs.TRFCPBNs) & 0xff)
439}
440
441func LP5UpdateTCKMin(memAttribs *LP5MemAttributes) {
442 if memAttribs.TCKMinPs == 0 {
443 memAttribs.TCKMinPs = LP5SpeedMbpsToSPDEncoding[memAttribs.SpeedMbps].TCKMinPs
444 }
445}
446
447func LP5UpdateTAAMin(memAttribs *LP5MemAttributes) {
448 if memAttribs.TAAMinPs == 0 {
449 maxCAS := LP5SpeedMbpsToSPDEncoding[memAttribs.SpeedMbps].MaxCASLatency
450 memAttribs.TAAMinPs = memAttribs.TCKMinPs * maxCAS
451 }
452}
453
454func LP5UpdateTRFCAB(memAttribs *LP5MemAttributes) {
455 if memAttribs.TRFCABNs == 0 {
456 memAttribs.TRFCABNs = LP5DensityGbToSPDEncoding[memAttribs.DensityPerDieGb].TRFCABNs
457 }
458}
459
460func LP5UpdateTRFCPB(memAttribs *LP5MemAttributes) {
461 if memAttribs.TRFCPBNs == 0 {
462 memAttribs.TRFCPBNs = LP5DensityGbToSPDEncoding[memAttribs.DensityPerDieGb].TRFCPBNs
463 }
464}
465
466func LP5UpdateTRCD(memAttribs *LP5MemAttributes) {
467 if memAttribs.TRCDMinNs == 0 {
468 /* Table 372 from JESD209-5B */
469 memAttribs.TRCDMinNs = 18
470 }
471}
472
473func LP5UpdateTRPAB(memAttribs *LP5MemAttributes) {
474 if memAttribs.TRPABMinNs == 0 {
475 /* Table 372 from JESD209-5B */
476 memAttribs.TRPABMinNs = 21
477 }
478}
479
480func LP5UpdateTRPPB(memAttribs *LP5MemAttributes) {
481 if memAttribs.TRPPBMinNs == 0 {
482 /* Table 372 from JESD209-5B */
483 memAttribs.TRPPBMinNs = 18
484 }
485}
486
487func lp5UpdateMemoryAttributes(memAttribs *LP5MemAttributes) {
488 LP5UpdateTCKMin(memAttribs)
489 LP5UpdateTAAMin(memAttribs)
490 LP5UpdateTRFCAB(memAttribs)
491 LP5UpdateTRFCPB(memAttribs)
492 LP5UpdateTRCD(memAttribs)
493 LP5UpdateTRPAB(memAttribs)
494 LP5UpdateTRPPB(memAttribs)
495}
496
497func LP5ValidateDensity(density int) error {
498 if _, ok := LP5DensityGbToSPDEncoding[density]; !ok {
499 return fmt.Errorf("Incorrect density per die: %d Gb", density)
500 }
501 return nil
502}
503
504func LP5ValidateDies(dies int) error {
505 if dies != 2 && dies != 4 && dies != 8 {
506 return fmt.Errorf("Incorrect dies: %d", dies)
507 }
508 return nil
509}
510
511func LP5ValidateDataWidth(width int) error {
512 if width != 8 && width != 16 {
513 return fmt.Errorf("Incorrect bit width: %d", width)
514 }
515 return nil
516}
517
518func LP5ValidateRanks(ranks int) error {
519 if ranks != 1 && ranks != 2 {
520 return fmt.Errorf("Incorrect ranks: %d", ranks)
521 }
522 return nil
523}
524
525func LP5ValidateSpeed(speed int) error {
526 if _, ok := LP5SpeedMbpsToSPDEncoding[speed]; !ok {
527 return fmt.Errorf("Incorrect speed: %d Mbps", speed)
528 }
529 return nil
530}
531
532func lp5ValidateMemPartAttributes(memAttribs *LP5MemAttributes) error {
533 if err := LP5ValidateDensity(memAttribs.DensityPerDieGb); err != nil {
534 return err
535 }
536 if err := LP5ValidateDies(memAttribs.DiesPerPackage); err != nil {
537 return err
538 }
539 if err := LP5ValidateDataWidth(memAttribs.BitWidthPerChannel); err != nil {
540 return err
541 }
542 if err := LP5ValidateRanks(memAttribs.RanksPerChannel); err != nil {
543 return err
544 }
545 if err := LP5ValidateSpeed(memAttribs.SpeedMbps); err != nil {
546 return err
547 }
548
549 return nil
550}
551
552func LP5IsManufacturerPartNumberByte(index int) bool {
553 if index >= LP5SPDIndexManufacturerPartNumberStartByte &&
554 index <= LP5SPDIndexManufacturerPartNumberEndByte {
555 return true
556 }
557 return false
558}
559
560/* ------------------------------------------------------------------------------------------ */
561/* Interface Functions */
562/* ------------------------------------------------------------------------------------------ */
563
564func (lp5) getSetMap() map[int][]int {
565 return LP5PlatformSetMap
566}
567
568func (lp5) addNewPart(name string, attribs interface{}) error {
569 var lp5Attributes LP5MemAttributes
570 eByte, err := json.Marshal(attribs)
571 if err != nil {
572 return err
573 }
574
575 if err := json.Unmarshal(eByte, &lp5Attributes); err != nil {
576 return err
577 }
578
579 if err := lp5ValidateMemPartAttributes(&lp5Attributes); err != nil {
580 return err
581 }
582
583 LP5PartAttributeMap[name] = lp5Attributes
584 return nil
585}
586
587func (lp5) getSPDAttribs(name string, set int) (interface{}, error) {
588 lp5Attributes := LP5PartAttributeMap[name]
589
590 LP5CurrSet = set
591
592 lp5UpdateMemoryAttributes(&lp5Attributes)
593
594 return lp5Attributes, nil
595}
596
597func (lp5) getSPDLen() int {
598 return 512
599}
600
601func (lp5) getSPDByte(index int, attribs interface{}) byte {
602 e, ok := LP5SPDAttribTable[index]
603 if !ok {
604 if LP5IsManufacturerPartNumberByte(index) {
605 return LP5SPDValueManufacturerPartNumberBlank
606 }
607 return 0x00
608 }
609
610 if e.getVal != nil {
611 var lp5Attribs LP5MemAttributes
612 lp5Attribs = attribs.(LP5MemAttributes)
613 return e.getVal(&lp5Attribs)
614 }
615
616 return e.constVal
617}