util/spd_tools: Add LP5 support for ADL
Add LP5 support to spd_tools. Currently, only Intel Alder Lake (ADL) is supported. The SPDs are generated based on a combination of: - The LPDDR5 spec JESD209-5B. - The SPD spec SPD4.1.2.M-2 (the LPDDR3/4 spec is used since JEDEC has not released an SPD spec for LPDDR5). - Intel recommendations in advisory #616599. BUG=b:201234943, b:198704251 TEST=Generate the SPD and manifests for a test part, and check that the SPD matches Intel's expectation. More details in CB:58680. Change-Id: Ic1e68d44f7c0ad64aa9904b7e1297d24bd5db56e Signed-off-by: Reka Norman <rekanorman@google.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/58679 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Karthik Ramasubramanian <kramasub@google.com>
This commit is contained in:
		
				
					committed by
					
						
						Patrick Georgi
					
				
			
			
				
	
			
			
			
						parent
						
							e5be13e46b
						
					
				
				
					commit
					2c439adb51
				
			@@ -8,6 +8,9 @@ The memory technologies currently supported are:
 | 
				
			|||||||
*   LPDDR4x - based on the JESD209-4C spec and Intel recommendations
 | 
					*   LPDDR4x - based on the JESD209-4C spec and Intel recommendations
 | 
				
			||||||
    (docs #616599, #610202, #634730).
 | 
					    (docs #616599, #610202, #634730).
 | 
				
			||||||
*   DDR4 - based on the JESD79-4C and Jedec 4.1.2.L-5 R29 v103 specs.
 | 
					*   DDR4 - based on the JESD79-4C and Jedec 4.1.2.L-5 R29 v103 specs.
 | 
				
			||||||
 | 
					*   LPDDR5 - based on the LPDDR5 spec JESD209-5B, the SPD spec SPD4.1.2.M-2 (the
 | 
				
			||||||
 | 
					    LPDDR3/4 spec is used since JEDEC has not released an SPD spec for LPDDR5),
 | 
				
			||||||
 | 
					    and Intel recommendations in advisory #616599.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
There are two tools provided to assist with generating SPDs and Makefiles to
 | 
					There are two tools provided to assist with generating SPDs and Makefiles to
 | 
				
			||||||
integrate into the coreboot build. These tools can also be used to allocate DRAM
 | 
					integrate into the coreboot build. These tools can also be used to allocate DRAM
 | 
				
			||||||
@@ -292,6 +295,100 @@ string like "9 10 11 12 14".
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### LP5 attributes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### Mandatory
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*   `densityPerDieGb`: Density per die in Gb. Valid values: `4, 6, 8, 12, 16,
 | 
				
			||||||
 | 
					    24, 32` Gb per die.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*   `diesPerPackage`: Number of physical dies in each SDRAM package. Valid
 | 
				
			||||||
 | 
					    values: `2, 4, 8` dies per package.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*   `bitWidthPerChannel`: Width of each physical channel. Valid values: `8, 16`
 | 
				
			||||||
 | 
					    bits.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*   `ranksPerChannel`: Number of ranks per physical channel. Valid values: `1,
 | 
				
			||||||
 | 
					    2`. If the channels across multiple dies share the same DQ/DQS pins but use
 | 
				
			||||||
 | 
					    a separate CS, then ranks is 2 else it is 1.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*   `speedMbps`: Maximum data rate supported by the part in Mbps. Valid values:
 | 
				
			||||||
 | 
					    `5500, 6400` Mbps.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### Optional
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*   `trfcabNs`: Minimum Refresh Recovery Delay Time (tRFCab) for all banks in
 | 
				
			||||||
 | 
					    nanoseconds. As per JESD209-5B, this is dependent on the density per die.
 | 
				
			||||||
 | 
					    Default values used:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *   4 Gb : 180 ns
 | 
				
			||||||
 | 
					    *   6 Gb : 210 ns
 | 
				
			||||||
 | 
					    *   8 Gb : 210 ns
 | 
				
			||||||
 | 
					    *   12 Gb: 280 ns
 | 
				
			||||||
 | 
					    *   16 Gb: 280 ns
 | 
				
			||||||
 | 
					    *   24 Gb: 380 ns
 | 
				
			||||||
 | 
					    *   32 Gb: 380 ns
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*   `trfcpbNs`: Minimum Refresh Recovery Delay Time (tRFCpb) per bank in
 | 
				
			||||||
 | 
					    nanoseconds. As per JESD209-5B, this is dependent on the density per die.
 | 
				
			||||||
 | 
					    Default values used:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *   4 Gb : 90 ns
 | 
				
			||||||
 | 
					    *   6 Gb : 120 ns
 | 
				
			||||||
 | 
					    *   8 Gb : 120 ns
 | 
				
			||||||
 | 
					    *   12 Gb: 140 ns
 | 
				
			||||||
 | 
					    *   16 Gb: 140 ns
 | 
				
			||||||
 | 
					    *   24 Gb: 190 ns
 | 
				
			||||||
 | 
					    *   32 Gb: 190 ns
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*   `trpabMinNs`: Minimum Row Precharge Delay Time (tRPab) for all banks in
 | 
				
			||||||
 | 
					    nanoseconds. As per JESD209-5B, this is max(21ns, 2nCK), which defaults to
 | 
				
			||||||
 | 
					    `21 ns`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*   `trppbMinNs`: Minimum Row Precharge Delay Time (tRPpb) per bank in
 | 
				
			||||||
 | 
					    nanoseconds. As per JESD209-5B, this is max(18ns, 2nCK) which defaults to
 | 
				
			||||||
 | 
					    `18 ns`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*   `tckMinPs`: SDRAM minimum cycle time (tCKmin) value in picoseconds. LPDDR5
 | 
				
			||||||
 | 
					    has two clocks: the command/addrees clock (CK) and the data clock (WCK).
 | 
				
			||||||
 | 
					    They are related by the WCK:CK ratio, which can be either 4:1 or 2:1. For
 | 
				
			||||||
 | 
					    LPDDR5, tCKmin is the CK period, which can be calculated from the
 | 
				
			||||||
 | 
					    `speedMbps` attribute and the WCK:CK ratio as follows: `tCKmin = 1 /
 | 
				
			||||||
 | 
					    (speedMbps / 2 / WCK:CK)`. The default values used are for a 4:1 WCK:CK
 | 
				
			||||||
 | 
					    ratio:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *   6400 Mbps: 1250 ps
 | 
				
			||||||
 | 
					    *   5500 Mbps: 1455 ps
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*   `taaMinPs`: Minimum CAS Latency Time(tAAmin) in picoseconds. This value
 | 
				
			||||||
 | 
					    defaults to nck * tCKmin, where nck is maximum CAS latency, and is
 | 
				
			||||||
 | 
					    determined from the `speedMbps` attribute as per JESD209-5B:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *   6400 Mbps: 17
 | 
				
			||||||
 | 
					    *   5500 Mbps: 15
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*   `trcdMinNs`: Minimum RAS# to CAS# Delay Time (tRCDmin) in nanoseconds. As
 | 
				
			||||||
 | 
					    per JESD209-5B, this is max(18ns, 2nCK) which defaults to `18 ns`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### Example `memory_parts.json`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    "parts": [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            "name": "MT62F1G32D4DR-031 WT:B",
 | 
				
			||||||
 | 
					            "attribs": {
 | 
				
			||||||
 | 
					                "densityPerDieGb": 8,
 | 
				
			||||||
 | 
					                "diesPerPackage": 4,
 | 
				
			||||||
 | 
					                "bitWidthPerChannel": 16,
 | 
				
			||||||
 | 
					                "ranksPerChannel": 2,
 | 
				
			||||||
 | 
					                "speedMbps": 6400
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Output
 | 
					### Output
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The `spd_gen` tool generates the directory structure shown below. The inputs to
 | 
					The `spd_gen` tool generates the directory structure shown below. The inputs to
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -45,6 +45,7 @@ var supportedPlatforms = [...]string{
 | 
				
			|||||||
var supportedMemTechs = [...]string{
 | 
					var supportedMemTechs = [...]string{
 | 
				
			||||||
	"lp4x",
 | 
						"lp4x",
 | 
				
			||||||
	"ddr4",
 | 
						"ddr4",
 | 
				
			||||||
 | 
						"lp5",
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func usage() {
 | 
					func usage() {
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										617
									
								
								util/spd_tools/src/spd_gen/lp5.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										617
									
								
								util/spd_tools/src/spd_gen/lp5.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,617 @@
 | 
				
			|||||||
 | 
					/* SPDX-License-Identifier: GPL-2.0-or-later */
 | 
				
			||||||
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"encoding/json"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* ------------------------------------------------------------------------------------------ */
 | 
				
			||||||
 | 
					/*                                     LP5-defined types                                      */
 | 
				
			||||||
 | 
					/* ------------------------------------------------------------------------------------------ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type lp5 struct {
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type LP5MemAttributes struct {
 | 
				
			||||||
 | 
						/* Primary attributes - must be provided by JSON file for each part */
 | 
				
			||||||
 | 
						DensityPerDieGb    int
 | 
				
			||||||
 | 
						DiesPerPackage     int
 | 
				
			||||||
 | 
						BitWidthPerChannel int
 | 
				
			||||||
 | 
						RanksPerChannel    int
 | 
				
			||||||
 | 
						SpeedMbps          int
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * All the following parameters are optional and required only if the part requires
 | 
				
			||||||
 | 
						 * special parameters as per the datasheet.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						/* Timing parameters */
 | 
				
			||||||
 | 
						TRFCABNs   int
 | 
				
			||||||
 | 
						TRFCPBNs   int
 | 
				
			||||||
 | 
						TRPABMinNs int
 | 
				
			||||||
 | 
						TRPPBMinNs int
 | 
				
			||||||
 | 
						TCKMinPs   int
 | 
				
			||||||
 | 
						TAAMinPs   int
 | 
				
			||||||
 | 
						TRCDMinNs  int
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type LP5DensityParams struct {
 | 
				
			||||||
 | 
						DensityEncoding          byte
 | 
				
			||||||
 | 
						RowAddressBitsx8Channel  int
 | 
				
			||||||
 | 
						RowAddressBitsx16Channel int
 | 
				
			||||||
 | 
						TRFCABNs                 int
 | 
				
			||||||
 | 
						TRFCPBNs                 int
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type LP5SpeedParams struct {
 | 
				
			||||||
 | 
						TCKMinPs      int
 | 
				
			||||||
 | 
						MaxCASLatency int
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type LP5SPDAttribFunc func(*LP5MemAttributes) byte
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type LP5SPDAttribTableEntry struct {
 | 
				
			||||||
 | 
						constVal byte
 | 
				
			||||||
 | 
						getVal   LP5SPDAttribFunc
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* ------------------------------------------------------------------------------------------ */
 | 
				
			||||||
 | 
					/*                                         Constants                                          */
 | 
				
			||||||
 | 
					/* ------------------------------------------------------------------------------------------ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						/* SPD Byte Index */
 | 
				
			||||||
 | 
						LP5SPDIndexSize                            = 0
 | 
				
			||||||
 | 
						LP5SPDIndexRevision                        = 1
 | 
				
			||||||
 | 
						LP5SPDIndexMemoryType                      = 2
 | 
				
			||||||
 | 
						LP5SPDIndexModuleType                      = 3
 | 
				
			||||||
 | 
						LP5SPDIndexDensityBanks                    = 4
 | 
				
			||||||
 | 
						LP5SPDIndexAddressing                      = 5
 | 
				
			||||||
 | 
						LP5SPDIndexPackageType                     = 6
 | 
				
			||||||
 | 
						LP5SPDIndexOptionalFeatures                = 7
 | 
				
			||||||
 | 
						LP5SPDIndexModuleOrganization              = 12
 | 
				
			||||||
 | 
						LP5SPDIndexBusWidth                        = 13
 | 
				
			||||||
 | 
						LP5SPDIndexTimebases                       = 17
 | 
				
			||||||
 | 
						LP5SPDIndexTCKMin                          = 18
 | 
				
			||||||
 | 
						LP5SPDIndexTAAMin                          = 24
 | 
				
			||||||
 | 
						LP5SPDIndexTRCDMin                         = 26
 | 
				
			||||||
 | 
						LP5SPDIndexTRPABMin                        = 27
 | 
				
			||||||
 | 
						LP5SPDIndexTRPPBMin                        = 28
 | 
				
			||||||
 | 
						LP5SPDIndexTRFCABMinLSB                    = 29
 | 
				
			||||||
 | 
						LP5SPDIndexTRFCABMinMSB                    = 30
 | 
				
			||||||
 | 
						LP5SPDIndexTRFCPBMinLSB                    = 31
 | 
				
			||||||
 | 
						LP5SPDIndexTRFCPBMinMSB                    = 32
 | 
				
			||||||
 | 
						LP5SPDIndexTRPPBMinFineOffset              = 120
 | 
				
			||||||
 | 
						LP5SPDIndexTRPABMinFineOffset              = 121
 | 
				
			||||||
 | 
						LP5SPDIndexTRCDMinFineOffset               = 122
 | 
				
			||||||
 | 
						LP5SPDIndexTAAMinFineOffset                = 123
 | 
				
			||||||
 | 
						LP5SPDIndexTCKMinFineOffset                = 125
 | 
				
			||||||
 | 
						LP5SPDIndexManufacturerPartNumberStartByte = 329
 | 
				
			||||||
 | 
						LP5SPDIndexManufacturerPartNumberEndByte   = 348
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* SPD Byte Value */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * From JEDEC spec:
 | 
				
			||||||
 | 
						 * 6:4 (Bytes total) = 2 (512 bytes)
 | 
				
			||||||
 | 
						 * 3:0 (Bytes used) = 3 (384 bytes)
 | 
				
			||||||
 | 
						 * Set to 0x23 for LPDDR5.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						LP5SPDValueSize = 0x23
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Revision 1.0.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						LP5SPDValueRevision = 0x10
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * As per advisory #616599, ADL MRC expects LPDDR5 memory type = 0x13.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						LP5SPDValueMemoryType = 0x13
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * From JEDEC spec:
 | 
				
			||||||
 | 
						 * 7:7 (Hybrid) = 0 (Not hybrid)
 | 
				
			||||||
 | 
						 * 6:4 (Hybrid media) = 000 (Not hybrid)
 | 
				
			||||||
 | 
						 * 3:0 (Base Module Type) = 1110 (Non-DIMM solution)
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * This is dependent on hardware design. LPDDR5 only has memory down solution.
 | 
				
			||||||
 | 
						 * Hence this is not hybrid non-DIMM solution.
 | 
				
			||||||
 | 
						 * Set to 0x0E.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						LP5SPDValueModuleType = 0x0e
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * From JEDEC spec:
 | 
				
			||||||
 | 
						 * 5:4 (Maximum Activate Window) = 00 (8192 * tREFI)
 | 
				
			||||||
 | 
						 * 3:0 (Maximum Activate Count) = 1000 (Unlimited MAC)
 | 
				
			||||||
 | 
						 * Set to 0x08.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						LP5SPDValueOptionalFeatures = 0x08
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * For ADL (as per advisory #616599):
 | 
				
			||||||
 | 
						 * 7:5 (Number of system channels) = 000 (1 channel always)
 | 
				
			||||||
 | 
						 * 4:3 (Bus width extension) = 00 (no ECC)
 | 
				
			||||||
 | 
						 * 2:0 (Bus width) = 001 (x16 always)
 | 
				
			||||||
 | 
						 * Set to 0x01.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						LP5SPDValueBusWidth = 0x01
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * From JEDEC spec:
 | 
				
			||||||
 | 
						 * 3:2 (MTB) = 00 (0.125ns)
 | 
				
			||||||
 | 
						 * 1:0 (FTB) = 00 (1ps)
 | 
				
			||||||
 | 
						 * Set to 0x00.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						LP5SPDValueTimebases = 0x00
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* As per JEDEC spec, unused digits of manufacturer part number are left as blank. */
 | 
				
			||||||
 | 
						LP5SPDValueManufacturerPartNumberBlank = 0x20
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * LPDDR5 has a flexible bank architecture with three programmable bank modes: BG, 8B, 16B.
 | 
				
			||||||
 | 
						 * ADL will use 8B mode for all parts.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * From JEDEC spec:
 | 
				
			||||||
 | 
						 * 7:6 (Bank Group Bits) = 00 (no bank groups)
 | 
				
			||||||
 | 
						 * 5:4 (Bank Address Bits) = 01 (8 banks)
 | 
				
			||||||
 | 
						 * Set bits 7:4 to 0b0001.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						LP5BankGroupsBanks = 0x1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Tables 8 and 9 from JESD209-5B.
 | 
				
			||||||
 | 
						 * ADL uses 8B mode for all parts. The column addresses are the same for x8 and x16.
 | 
				
			||||||
 | 
						 * Effective column address bits = column address bits + burst address bits = 6 + 5 = 11.
 | 
				
			||||||
 | 
						 * As per JESD 21-C, this is encoded as 0b010.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						LP5ColumnAddressBits = 0x2
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* ------------------------------------------------------------------------------------------ */
 | 
				
			||||||
 | 
					/*                                    Global variables                                        */
 | 
				
			||||||
 | 
					/* ------------------------------------------------------------------------------------------ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var LP5PlatformSetMap = map[int][]int{
 | 
				
			||||||
 | 
						0: {PlatformADL},
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var LP5PartAttributeMap = map[string]LP5MemAttributes{}
 | 
				
			||||||
 | 
					var LP5CurrSet int
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * DensityEncoding: Maps the die density in Gb to the SPD encoding of the die density
 | 
				
			||||||
 | 
					 * as per JESD 21-C.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * RowAddressBits: Maps the die density to the number of row address bits.
 | 
				
			||||||
 | 
					 * Tables 6-11 in JESD209-5B (same for all three bank modes).
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * TRFCABNs/TRFCPBNs: Maps the die density to the refresh timings.
 | 
				
			||||||
 | 
					 * Tables 235 and 236 in JESD209-5B (same for all three bank modes).
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					var LP5DensityGbToSPDEncoding = map[int]LP5DensityParams{
 | 
				
			||||||
 | 
						4: {
 | 
				
			||||||
 | 
							DensityEncoding:          0x4,
 | 
				
			||||||
 | 
							RowAddressBitsx8Channel:  15,
 | 
				
			||||||
 | 
							RowAddressBitsx16Channel: 14,
 | 
				
			||||||
 | 
							TRFCABNs:                 180,
 | 
				
			||||||
 | 
							TRFCPBNs:                 90,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						6: {
 | 
				
			||||||
 | 
							DensityEncoding:          0xb,
 | 
				
			||||||
 | 
							RowAddressBitsx8Channel:  16,
 | 
				
			||||||
 | 
							RowAddressBitsx16Channel: 15,
 | 
				
			||||||
 | 
							TRFCABNs:                 210,
 | 
				
			||||||
 | 
							TRFCPBNs:                 120,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						8: {
 | 
				
			||||||
 | 
							DensityEncoding:          0x5,
 | 
				
			||||||
 | 
							RowAddressBitsx8Channel:  16,
 | 
				
			||||||
 | 
							RowAddressBitsx16Channel: 15,
 | 
				
			||||||
 | 
							TRFCABNs:                 210,
 | 
				
			||||||
 | 
							TRFCPBNs:                 120,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						12: {
 | 
				
			||||||
 | 
							DensityEncoding:          0x8,
 | 
				
			||||||
 | 
							RowAddressBitsx8Channel:  17,
 | 
				
			||||||
 | 
							RowAddressBitsx16Channel: 16,
 | 
				
			||||||
 | 
							TRFCABNs:                 280,
 | 
				
			||||||
 | 
							TRFCPBNs:                 140,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						16: {
 | 
				
			||||||
 | 
							DensityEncoding:          0x6,
 | 
				
			||||||
 | 
							RowAddressBitsx8Channel:  17,
 | 
				
			||||||
 | 
							RowAddressBitsx16Channel: 16,
 | 
				
			||||||
 | 
							TRFCABNs:                 280,
 | 
				
			||||||
 | 
							TRFCPBNs:                 140,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						24: {
 | 
				
			||||||
 | 
							DensityEncoding:          0x9,
 | 
				
			||||||
 | 
							RowAddressBitsx8Channel:  18,
 | 
				
			||||||
 | 
							RowAddressBitsx16Channel: 17,
 | 
				
			||||||
 | 
							TRFCABNs:                 380,
 | 
				
			||||||
 | 
							TRFCPBNs:                 190,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						32: {
 | 
				
			||||||
 | 
							DensityEncoding:          0x7,
 | 
				
			||||||
 | 
							RowAddressBitsx8Channel:  18,
 | 
				
			||||||
 | 
							RowAddressBitsx16Channel: 17,
 | 
				
			||||||
 | 
							TRFCABNs:                 380,
 | 
				
			||||||
 | 
							TRFCPBNs:                 190,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Maps the number of row address bits to the SPD encoding as per JESD 21-C.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					var LP5RowAddressBitsEncoding = map[int]byte{
 | 
				
			||||||
 | 
						14: 0x2,
 | 
				
			||||||
 | 
						15: 0x3,
 | 
				
			||||||
 | 
						16: 0x4,
 | 
				
			||||||
 | 
						17: 0x5,
 | 
				
			||||||
 | 
						18: 0x6,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * TCKMinPs:
 | 
				
			||||||
 | 
					 * LPDDR5 has two clocks: the command/address clock (CK) and the data clock (WCK). They are
 | 
				
			||||||
 | 
					 * related by the WCK:CK ratio, which can be either 4:1 or 2:1. On ADL, 4:1 is used.
 | 
				
			||||||
 | 
					 * For ADL, the MRC expects the tCKmin to encode the CK period. This is calculated as:
 | 
				
			||||||
 | 
					 *   tCKmin = 1 / CK rate
 | 
				
			||||||
 | 
					 *          = 1 / (WCK rate / WCK:CK)
 | 
				
			||||||
 | 
					 *          = 1 / (speed grade / 2 / WCK:CK)      // "double data rate"
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * MaxCASLatency:
 | 
				
			||||||
 | 
					 * From Table 220 of JESD209-5B, using a 4:1 WCK:CK ratio and Set 0.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					var LP5SpeedMbpsToSPDEncoding = map[int]LP5SpeedParams{
 | 
				
			||||||
 | 
						6400: {
 | 
				
			||||||
 | 
							TCKMinPs:      1250, /* 1 / (6400 / 2 / 4) */
 | 
				
			||||||
 | 
							MaxCASLatency: 17,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						5500: {
 | 
				
			||||||
 | 
							TCKMinPs:      1455, /* 1 / (5500 / 2 / 4) */
 | 
				
			||||||
 | 
							MaxCASLatency: 15,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var LP5SPDAttribTable = map[int]LP5SPDAttribTableEntry{
 | 
				
			||||||
 | 
						LP5SPDIndexSize:               {constVal: LP5SPDValueSize},
 | 
				
			||||||
 | 
						LP5SPDIndexRevision:           {constVal: LP5SPDValueRevision},
 | 
				
			||||||
 | 
						LP5SPDIndexMemoryType:         {constVal: LP5SPDValueMemoryType},
 | 
				
			||||||
 | 
						LP5SPDIndexModuleType:         {constVal: LP5SPDValueModuleType},
 | 
				
			||||||
 | 
						LP5SPDIndexDensityBanks:       {getVal: LP5EncodeDensityBanks},
 | 
				
			||||||
 | 
						LP5SPDIndexAddressing:         {getVal: LP5EncodeSdramAddressing},
 | 
				
			||||||
 | 
						LP5SPDIndexPackageType:        {getVal: LP5EncodePackageType},
 | 
				
			||||||
 | 
						LP5SPDIndexOptionalFeatures:   {constVal: LP5SPDValueOptionalFeatures},
 | 
				
			||||||
 | 
						LP5SPDIndexModuleOrganization: {getVal: LP5EncodeModuleOrganization},
 | 
				
			||||||
 | 
						LP5SPDIndexBusWidth:           {constVal: LP5SPDValueBusWidth},
 | 
				
			||||||
 | 
						LP5SPDIndexTimebases:          {constVal: LP5SPDValueTimebases},
 | 
				
			||||||
 | 
						LP5SPDIndexTCKMin:             {getVal: LP5EncodeTCKMin},
 | 
				
			||||||
 | 
						LP5SPDIndexTCKMinFineOffset:   {getVal: LP5EncodeTCKMinFineOffset},
 | 
				
			||||||
 | 
						LP5SPDIndexTAAMin:             {getVal: LP5EncodeTAAMin},
 | 
				
			||||||
 | 
						LP5SPDIndexTAAMinFineOffset:   {getVal: LP5EncodeTAAMinFineOffset},
 | 
				
			||||||
 | 
						LP5SPDIndexTRCDMin:            {getVal: LP5EncodeTRCDMin},
 | 
				
			||||||
 | 
						LP5SPDIndexTRCDMinFineOffset:  {getVal: LP5EncodeTRCDMinFineOffset},
 | 
				
			||||||
 | 
						LP5SPDIndexTRPABMin:           {getVal: LP5EncodeTRPABMin},
 | 
				
			||||||
 | 
						LP5SPDIndexTRPABMinFineOffset: {getVal: LP5EncodeTRPABMinFineOffset},
 | 
				
			||||||
 | 
						LP5SPDIndexTRPPBMin:           {getVal: LP5EncodeTRPPBMin},
 | 
				
			||||||
 | 
						LP5SPDIndexTRPPBMinFineOffset: {getVal: LP5EncodeTRPPBMinFineOffset},
 | 
				
			||||||
 | 
						LP5SPDIndexTRFCABMinLSB:       {getVal: LP5EncodeTRFCABMinLsb},
 | 
				
			||||||
 | 
						LP5SPDIndexTRFCABMinMSB:       {getVal: LP5EncodeTRFCABMinMsb},
 | 
				
			||||||
 | 
						LP5SPDIndexTRFCPBMinLSB:       {getVal: LP5EncodeTRFCPBMinLsb},
 | 
				
			||||||
 | 
						LP5SPDIndexTRFCPBMinMSB:       {getVal: LP5EncodeTRFCPBMinMsb},
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* ------------------------------------------------------------------------------------------ */
 | 
				
			||||||
 | 
					/*                                        Functions                                           */
 | 
				
			||||||
 | 
					/* ------------------------------------------------------------------------------------------ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func LP5EncodeDensityBanks(memAttribs *LP5MemAttributes) byte {
 | 
				
			||||||
 | 
						var b byte
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 3:0 Density per die.
 | 
				
			||||||
 | 
						b = LP5DensityGbToSPDEncoding[memAttribs.DensityPerDieGb].DensityEncoding
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 5:4 Bank address bits.
 | 
				
			||||||
 | 
						// 7:6 Bank group bits.
 | 
				
			||||||
 | 
						b |= LP5BankGroupsBanks << 4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return b
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func LP5EncodeSdramAddressing(memAttribs *LP5MemAttributes) byte {
 | 
				
			||||||
 | 
						var b byte
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 2:0 Column address bits.
 | 
				
			||||||
 | 
						b = LP5ColumnAddressBits
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 5:3 Row address bits.
 | 
				
			||||||
 | 
						density := memAttribs.DensityPerDieGb
 | 
				
			||||||
 | 
						var rowAddressBits int
 | 
				
			||||||
 | 
						if memAttribs.BitWidthPerChannel == 8 {
 | 
				
			||||||
 | 
							rowAddressBits = LP5DensityGbToSPDEncoding[density].RowAddressBitsx8Channel
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							rowAddressBits = LP5DensityGbToSPDEncoding[density].RowAddressBitsx16Channel
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						b |= LP5RowAddressBitsEncoding[rowAddressBits] << 3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return b
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func LP5EncodePackageType(memAttribs *LP5MemAttributes) byte {
 | 
				
			||||||
 | 
						var b byte
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 1:0 Signal loading index.
 | 
				
			||||||
 | 
						b = 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 3:2 Channels per package.
 | 
				
			||||||
 | 
						// Channels per package = package width (e.g. x32) / bitWidthPerChannel (x8 or x16).
 | 
				
			||||||
 | 
						// This can equivalently be calculated as diesPerPackage / ranksPerChannel.
 | 
				
			||||||
 | 
						// This calculation is used to avoid adding a redundant attribute for package width.
 | 
				
			||||||
 | 
						channels := memAttribs.DiesPerPackage / memAttribs.RanksPerChannel
 | 
				
			||||||
 | 
						b |= byte(channels>>1) << 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 6:4 Dies per package.
 | 
				
			||||||
 | 
						b |= (byte(memAttribs.DiesPerPackage) - 1) << 4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 7:7 Package type.
 | 
				
			||||||
 | 
						var packageType byte
 | 
				
			||||||
 | 
						if memAttribs.DiesPerPackage > 1 {
 | 
				
			||||||
 | 
							packageType = 1 // Non-Monolithic
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							packageType = 0 // Monolithic
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						b |= packageType << 7
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return b
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func LP5EncodeModuleOrganization(memAttribs *LP5MemAttributes) byte {
 | 
				
			||||||
 | 
						var b byte
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 2:0 Device data width per channel
 | 
				
			||||||
 | 
						b = byte(memAttribs.BitWidthPerChannel / 8)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 5:3 Package ranks per channel
 | 
				
			||||||
 | 
						b |= byte(memAttribs.RanksPerChannel-1) << 3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return b
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func LP5EncodeTCKMin(memAttribs *LP5MemAttributes) byte {
 | 
				
			||||||
 | 
						return convPsToMtbByte(memAttribs.TCKMinPs)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func LP5EncodeTCKMinFineOffset(memAttribs *LP5MemAttributes) byte {
 | 
				
			||||||
 | 
						return convPsToFtbByte(memAttribs.TCKMinPs)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func LP5EncodeTAAMin(memAttribs *LP5MemAttributes) byte {
 | 
				
			||||||
 | 
						return convPsToMtbByte(memAttribs.TAAMinPs)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func LP5EncodeTAAMinFineOffset(memAttribs *LP5MemAttributes) byte {
 | 
				
			||||||
 | 
						return convPsToFtbByte(memAttribs.TAAMinPs)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func LP5EncodeTRCDMin(memAttribs *LP5MemAttributes) byte {
 | 
				
			||||||
 | 
						return convNsToMtbByte(memAttribs.TRCDMinNs)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func LP5EncodeTRCDMinFineOffset(memAttribs *LP5MemAttributes) byte {
 | 
				
			||||||
 | 
						return convNsToFtbByte(memAttribs.TRCDMinNs)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func LP5EncodeTRPABMin(memAttribs *LP5MemAttributes) byte {
 | 
				
			||||||
 | 
						return convNsToMtbByte(memAttribs.TRPABMinNs)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func LP5EncodeTRPABMinFineOffset(memAttribs *LP5MemAttributes) byte {
 | 
				
			||||||
 | 
						return convNsToFtbByte(memAttribs.TRPABMinNs)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func LP5EncodeTRPPBMin(memAttribs *LP5MemAttributes) byte {
 | 
				
			||||||
 | 
						return convNsToMtbByte(memAttribs.TRPPBMinNs)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func LP5EncodeTRPPBMinFineOffset(memAttribs *LP5MemAttributes) byte {
 | 
				
			||||||
 | 
						return convNsToFtbByte(memAttribs.TRPPBMinNs)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func LP5EncodeTRFCABMinMsb(memAttribs *LP5MemAttributes) byte {
 | 
				
			||||||
 | 
						return byte((convNsToMtb(memAttribs.TRFCABNs) >> 8) & 0xff)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func LP5EncodeTRFCABMinLsb(memAttribs *LP5MemAttributes) byte {
 | 
				
			||||||
 | 
						return byte(convNsToMtb(memAttribs.TRFCABNs) & 0xff)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func LP5EncodeTRFCPBMinMsb(memAttribs *LP5MemAttributes) byte {
 | 
				
			||||||
 | 
						return byte((convNsToMtb(memAttribs.TRFCPBNs) >> 8) & 0xff)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func LP5EncodeTRFCPBMinLsb(memAttribs *LP5MemAttributes) byte {
 | 
				
			||||||
 | 
						return byte(convNsToMtb(memAttribs.TRFCPBNs) & 0xff)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func LP5UpdateTCKMin(memAttribs *LP5MemAttributes) {
 | 
				
			||||||
 | 
						if memAttribs.TCKMinPs == 0 {
 | 
				
			||||||
 | 
							memAttribs.TCKMinPs = LP5SpeedMbpsToSPDEncoding[memAttribs.SpeedMbps].TCKMinPs
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func LP5UpdateTAAMin(memAttribs *LP5MemAttributes) {
 | 
				
			||||||
 | 
						if memAttribs.TAAMinPs == 0 {
 | 
				
			||||||
 | 
							maxCAS := LP5SpeedMbpsToSPDEncoding[memAttribs.SpeedMbps].MaxCASLatency
 | 
				
			||||||
 | 
							memAttribs.TAAMinPs = memAttribs.TCKMinPs * maxCAS
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func LP5UpdateTRFCAB(memAttribs *LP5MemAttributes) {
 | 
				
			||||||
 | 
						if memAttribs.TRFCABNs == 0 {
 | 
				
			||||||
 | 
							memAttribs.TRFCABNs = LP5DensityGbToSPDEncoding[memAttribs.DensityPerDieGb].TRFCABNs
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func LP5UpdateTRFCPB(memAttribs *LP5MemAttributes) {
 | 
				
			||||||
 | 
						if memAttribs.TRFCPBNs == 0 {
 | 
				
			||||||
 | 
							memAttribs.TRFCPBNs = LP5DensityGbToSPDEncoding[memAttribs.DensityPerDieGb].TRFCPBNs
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func LP5UpdateTRCD(memAttribs *LP5MemAttributes) {
 | 
				
			||||||
 | 
						if memAttribs.TRCDMinNs == 0 {
 | 
				
			||||||
 | 
							/* Table 372 from JESD209-5B */
 | 
				
			||||||
 | 
							memAttribs.TRCDMinNs = 18
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func LP5UpdateTRPAB(memAttribs *LP5MemAttributes) {
 | 
				
			||||||
 | 
						if memAttribs.TRPABMinNs == 0 {
 | 
				
			||||||
 | 
							/* Table 372 from JESD209-5B */
 | 
				
			||||||
 | 
							memAttribs.TRPABMinNs = 21
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func LP5UpdateTRPPB(memAttribs *LP5MemAttributes) {
 | 
				
			||||||
 | 
						if memAttribs.TRPPBMinNs == 0 {
 | 
				
			||||||
 | 
							/* Table 372 from JESD209-5B */
 | 
				
			||||||
 | 
							memAttribs.TRPPBMinNs = 18
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func lp5UpdateMemoryAttributes(memAttribs *LP5MemAttributes) {
 | 
				
			||||||
 | 
						LP5UpdateTCKMin(memAttribs)
 | 
				
			||||||
 | 
						LP5UpdateTAAMin(memAttribs)
 | 
				
			||||||
 | 
						LP5UpdateTRFCAB(memAttribs)
 | 
				
			||||||
 | 
						LP5UpdateTRFCPB(memAttribs)
 | 
				
			||||||
 | 
						LP5UpdateTRCD(memAttribs)
 | 
				
			||||||
 | 
						LP5UpdateTRPAB(memAttribs)
 | 
				
			||||||
 | 
						LP5UpdateTRPPB(memAttribs)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func LP5ValidateDensity(density int) error {
 | 
				
			||||||
 | 
						if _, ok := LP5DensityGbToSPDEncoding[density]; !ok {
 | 
				
			||||||
 | 
							return fmt.Errorf("Incorrect density per die: %d Gb", density)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func LP5ValidateDies(dies int) error {
 | 
				
			||||||
 | 
						if dies != 2 && dies != 4 && dies != 8 {
 | 
				
			||||||
 | 
							return fmt.Errorf("Incorrect dies: %d", dies)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func LP5ValidateDataWidth(width int) error {
 | 
				
			||||||
 | 
						if width != 8 && width != 16 {
 | 
				
			||||||
 | 
							return fmt.Errorf("Incorrect bit width: %d", width)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func LP5ValidateRanks(ranks int) error {
 | 
				
			||||||
 | 
						if ranks != 1 && ranks != 2 {
 | 
				
			||||||
 | 
							return fmt.Errorf("Incorrect ranks: %d", ranks)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func LP5ValidateSpeed(speed int) error {
 | 
				
			||||||
 | 
						if _, ok := LP5SpeedMbpsToSPDEncoding[speed]; !ok {
 | 
				
			||||||
 | 
							return fmt.Errorf("Incorrect speed: %d Mbps", speed)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func lp5ValidateMemPartAttributes(memAttribs *LP5MemAttributes) error {
 | 
				
			||||||
 | 
						if err := LP5ValidateDensity(memAttribs.DensityPerDieGb); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if err := LP5ValidateDies(memAttribs.DiesPerPackage); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if err := LP5ValidateDataWidth(memAttribs.BitWidthPerChannel); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if err := LP5ValidateRanks(memAttribs.RanksPerChannel); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if err := LP5ValidateSpeed(memAttribs.SpeedMbps); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func LP5IsManufacturerPartNumberByte(index int) bool {
 | 
				
			||||||
 | 
						if index >= LP5SPDIndexManufacturerPartNumberStartByte &&
 | 
				
			||||||
 | 
							index <= LP5SPDIndexManufacturerPartNumberEndByte {
 | 
				
			||||||
 | 
							return true
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return false
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* ------------------------------------------------------------------------------------------ */
 | 
				
			||||||
 | 
					/*                                  Interface Functions                                       */
 | 
				
			||||||
 | 
					/* ------------------------------------------------------------------------------------------ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (lp5) getSetMap() map[int][]int {
 | 
				
			||||||
 | 
						return LP5PlatformSetMap
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (lp5) addNewPart(name string, attribs interface{}) error {
 | 
				
			||||||
 | 
						var lp5Attributes LP5MemAttributes
 | 
				
			||||||
 | 
						eByte, err := json.Marshal(attribs)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err := json.Unmarshal(eByte, &lp5Attributes); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err := lp5ValidateMemPartAttributes(&lp5Attributes); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LP5PartAttributeMap[name] = lp5Attributes
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (lp5) getSPDAttribs(name string, set int) (interface{}, error) {
 | 
				
			||||||
 | 
						lp5Attributes := LP5PartAttributeMap[name]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LP5CurrSet = set
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						lp5UpdateMemoryAttributes(&lp5Attributes)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return lp5Attributes, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (lp5) getSPDLen() int {
 | 
				
			||||||
 | 
						return 512
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (lp5) getSPDByte(index int, attribs interface{}) byte {
 | 
				
			||||||
 | 
						e, ok := LP5SPDAttribTable[index]
 | 
				
			||||||
 | 
						if !ok {
 | 
				
			||||||
 | 
							if LP5IsManufacturerPartNumberByte(index) {
 | 
				
			||||||
 | 
								return LP5SPDValueManufacturerPartNumberBlank
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return 0x00
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if e.getVal != nil {
 | 
				
			||||||
 | 
							var lp5Attribs LP5MemAttributes
 | 
				
			||||||
 | 
							lp5Attribs = attribs.(LP5MemAttributes)
 | 
				
			||||||
 | 
							return e.getVal(&lp5Attribs)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return e.constVal
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -65,6 +65,12 @@ var platformNames = map[int]string{
 | 
				
			|||||||
	PlatformCZN: "CZN",
 | 
						PlatformCZN: "CZN",
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var memTechMap = map[string]memTech{
 | 
				
			||||||
 | 
						"lp4x": lp4x{},
 | 
				
			||||||
 | 
						"ddr4": ddr4{},
 | 
				
			||||||
 | 
						"lp5":  lp5{},
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* ------------------------------------------------------------------------------------------ */
 | 
					/* ------------------------------------------------------------------------------------------ */
 | 
				
			||||||
/*                                Conversion Helper Functions                                 */
 | 
					/*                                Conversion Helper Functions                                 */
 | 
				
			||||||
/* ------------------------------------------------------------------------------------------ */
 | 
					/* ------------------------------------------------------------------------------------------ */
 | 
				
			||||||
@@ -211,7 +217,9 @@ func usage() {
 | 
				
			|||||||
	fmt.Printf("\nUsage: %s <mem_parts_list_json> <mem_technology>\n\n", os.Args[0])
 | 
						fmt.Printf("\nUsage: %s <mem_parts_list_json> <mem_technology>\n\n", os.Args[0])
 | 
				
			||||||
	fmt.Printf("   where,\n")
 | 
						fmt.Printf("   where,\n")
 | 
				
			||||||
	fmt.Printf("   mem_parts_list_json = JSON File containing list of memory parts and attributes\n")
 | 
						fmt.Printf("   mem_parts_list_json = JSON File containing list of memory parts and attributes\n")
 | 
				
			||||||
	fmt.Printf("   mem_technology = Memory technology -- one of lp4x, ddr4\n\n\n")
 | 
						fmt.Printf("   mem_technology = Memory technology for which to generate SPDs\n")
 | 
				
			||||||
 | 
						fmt.Printf("                    supported technologies: %v\n\n\n",
 | 
				
			||||||
 | 
							reflect.ValueOf(memTechMap).MapKeys())
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func main() {
 | 
					func main() {
 | 
				
			||||||
@@ -223,11 +231,8 @@ func main() {
 | 
				
			|||||||
	var t memTech
 | 
						var t memTech
 | 
				
			||||||
	memPartsFilePath, memTechnology := os.Args[1], os.Args[2]
 | 
						memPartsFilePath, memTechnology := os.Args[1], os.Args[2]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if strings.ToUpper(memTechnology) == "LP4X" {
 | 
						t, ok := memTechMap[strings.ToLower(memTechnology)]
 | 
				
			||||||
		t = lp4x{}
 | 
						if !ok {
 | 
				
			||||||
	} else if strings.ToUpper(memTechnology) == "DDR4" {
 | 
					 | 
				
			||||||
		t = ddr4{}
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		log.Fatal("Unsupported memory technology ", memTechnology)
 | 
							log.Fatal("Unsupported memory technology ", memTechnology)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user