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