/ src / soc / intel / apollolake / meminit_util_glk.c
meminit_util_glk.c
  1  /* SPDX-License-Identifier: GPL-2.0-only */
  2  
  3  #include <cbmem.h>
  4  #include <console/console.h>
  5  #include <fsp/util.h>
  6  #include <memory_info.h>
  7  #include <soc/intel/common/smbios.h>
  8  #include <soc/meminit.h>
  9  #include <string.h>
 10  
 11  #define FSP_SMBIOS_MEMORY_INFO_GUID	\
 12  {	\
 13  	0x8c, 0x10, 0xa1, 0x01, 0xee, 0x9d, 0x84, 0x49,	\
 14  	0x88, 0xc3, 0xee, 0xe8, 0xc4, 0x9e, 0xfb, 0x89	\
 15  }
 16  
 17  void save_lpddr4_dimm_info_part_num(const char *dram_part_num)
 18  {
 19  	int channel, dimm, dimm_max, index, node;
 20  	size_t hob_size;
 21  	const DIMM_INFO *src_dimm;
 22  	struct dimm_info *dest_dimm;
 23  	struct memory_info *mem_info;
 24  	const CHANNEL_INFO *channel_info;
 25  	const FSP_SMBIOS_MEMORY_INFO *memory_info_hob;
 26  	const CONTROLLER_INFO *ctrl_info;
 27  	const uint8_t smbios_memory_info_guid[16] =
 28  			FSP_SMBIOS_MEMORY_INFO_GUID;
 29  
 30  	if (!dram_part_num)
 31  		dram_part_num = "Unknown";
 32  
 33  	/* Locate the memory info HOB */
 34  	memory_info_hob = fsp_find_extension_hob_by_guid(
 35  				smbios_memory_info_guid,
 36  				&hob_size);
 37  
 38  	if (memory_info_hob == NULL || hob_size == 0) {
 39  		printk(BIOS_ERR, "SMBIOS memory info HOB is missing\n");
 40  		return;
 41  	}
 42  
 43  	/*
 44  	 * Allocate CBMEM area for DIMM information used to populate SMBIOS
 45  	 * table 17
 46  	 */
 47  	mem_info = cbmem_add(CBMEM_ID_MEMINFO, sizeof(*mem_info));
 48  	if (mem_info == NULL) {
 49  		printk(BIOS_ERR, "CBMEM entry for DIMM info missing\n");
 50  		return;
 51  	}
 52  	memset(mem_info, 0, sizeof(*mem_info));
 53  
 54  	/* Describe the first N DIMMs in the system */
 55  	index = 0;
 56  	dimm_max = ARRAY_SIZE(mem_info->dimm);
 57  
 58  	for (node = 0; node < MAX_NODE_NUM; node++) {
 59  		ctrl_info = &memory_info_hob->Controller[node];
 60  		for (channel = 0; channel < ctrl_info->ChannelCount;
 61  			channel++) {
 62  			if (index >= dimm_max)
 63  				break;
 64  
 65  			channel_info = &ctrl_info->ChannelInfo[channel];
 66  
 67  			for (dimm = 0; dimm < channel_info->DimmCount; dimm++) {
 68  				if (index >= dimm_max)
 69  					break;
 70  				src_dimm = &channel_info->DimmInfo[dimm];
 71  				dest_dimm = &mem_info->dimm[index];
 72  
 73  				if (!src_dimm->DimmCapacity)
 74  					continue;
 75  
 76  				/* Populate the DIMM information */
 77  				dimm_info_fill(dest_dimm,
 78  				    src_dimm->DimmCapacity,
 79  				    memory_info_hob->MemoryType,
 80  				    memory_info_hob->ConfiguredMemoryClockSpeed,
 81  				    src_dimm->RankInDimm,
 82  				    channel_info->ChannelId,
 83  				    src_dimm->DimmId,
 84  				    dram_part_num,
 85  				    strlen(dram_part_num),
 86  				    src_dimm->SpdSave + SPD_SAVE_OFFSET_SERIAL,
 87  				    memory_info_hob->DataWidth,
 88  				    0,
 89  				    0,
 90  				    src_dimm->MfgId,
 91  				    src_dimm->SpdModuleType,
 92  				    node,
 93  				    memory_info_hob->MaximumMemoryClockSpeed);
 94  				index++;
 95  			}
 96  		}
 97  	}
 98  	mem_info->dimm_cnt = index;
 99  	printk(BIOS_DEBUG, "%d DIMMs found\n", mem_info->dimm_cnt);
100  }
101  
102  void save_lpddr4_dimm_info(const struct lpddr4_cfg *lp4cfg, size_t mem_sku)
103  {
104  	const char *part_num = NULL;
105  
106  	if (mem_sku >= lp4cfg->num_skus) {
107  		printk(BIOS_ERR, "Too few LPDDR4 SKUs: 0x%zx/0x%zx\n",
108  			mem_sku, lp4cfg->num_skus);
109  	} else {
110  		part_num = lp4cfg->skus[mem_sku].part_num;
111  	}
112  
113  	save_lpddr4_dimm_info_part_num(part_num);
114  }