static void set_dimm_info(uint8_t *spd, struct dimm_info *dimm) { const int spd_capmb[8] = { 1, 2, 4, 8, 16, 32, 64, 0 }; const int spd_ranks[8] = { 1, 2, 3, 4, -1, -1, -1, -1 }; const int spd_devw[8] = { 4, 8, 16, 32, -1, -1, -1, -1 }; const int spd_busw[8] = { 8, 16, 32, 64, -1, -1, -1, -1 }; int capmb = spd_capmb[spd[SPD_DENSITY_BANKS] & 7] * 256; int ranks = spd_ranks[(spd[SPD_ORGANIZATION] >> 3) & 7]; int devw = spd_devw[spd[SPD_ORGANIZATION] & 7]; int busw = spd_busw[spd[SPD_BUS_DEV_WIDTH] & 7]; void *hob_list_ptr; EFI_HOB_GUID_TYPE *hob_ptr; FSP_SMBIOS_MEMORY_INFO *memory_info_hob; const EFI_GUID memory_info_hob_guid = FSP_SMBIOS_MEMORY_INFO_GUID; /* Locate the memory info HOB, presence validated by raminit */ hob_list_ptr = fsp_get_hob_list(); hob_ptr = get_next_guid_hob(&memory_info_hob_guid, hob_list_ptr); if (hob_ptr != NULL) { memory_info_hob = (FSP_SMBIOS_MEMORY_INFO *)(hob_ptr + 1); dimm->ddr_frequency = memory_info_hob->MemoryFrequencyInMHz; } else { printk(BIOS_ERR, "Can't get memory info hob pointer\n"); dimm->ddr_frequency = 0; } /* Parse the SPD data to determine the DIMM information */ if (IS_ENABLED(CONFIG_BOARD_GOOGLE_CYAN)) { dimm->ddr_type = MEMORY_TYPE_DDR3; } else { dimm->ddr_type = MEMORY_TYPE_LPDDR3; } dimm->dimm_size = capmb / 8 * busw / devw * ranks; /* MiB */ dimm->mod_type = spd[3] & 0xf; strncpy((char *)&dimm->module_part_number[0], (char *)&spd[0x80], LPDDR3_SPD_PART_LEN); dimm->module_part_number[LPDDR3_SPD_PART_LEN] = 0; dimm->mod_id = *(uint16_t *)&spd[0x94]; switch (busw) { default: case 8: dimm->bus_width = MEMORY_BUS_WIDTH_8; break; case 16: dimm->bus_width = MEMORY_BUS_WIDTH_16; break; case 32: dimm->bus_width = MEMORY_BUS_WIDTH_32; break; case 64: dimm->bus_width = MEMORY_BUS_WIDTH_64; break; } }
/* Returns the pointer to the HOB list. */ void *get_hob_list(void) { void *hob_list; hob_list = fsp_get_hob_list(); if (hob_list == NULL) die("Call fsp_set_runtime() before this call!\n"); return hob_list; }
/* Save the DIMM information for SMBIOS table 17 */ __attribute__((weak)) void mainboard_save_dimm_info( struct romstage_params *params) { int channel; CHANNEL_INFO *channel_info; int dimm; DIMM_INFO *dimm_info; int dimm_max; void *hob_list_ptr; EFI_HOB_GUID_TYPE *hob_ptr; int index; struct memory_info *mem_info; FSP_SMBIOS_MEMORY_INFO *memory_info_hob; const EFI_GUID memory_info_hob_guid = FSP_SMBIOS_MEMORY_INFO_GUID; /* Locate the memory info HOB, presence validated by raminit */ hob_list_ptr = fsp_get_hob_list(); hob_ptr = get_next_guid_hob(&memory_info_hob_guid, hob_list_ptr); memory_info_hob = (FSP_SMBIOS_MEMORY_INFO *)(hob_ptr + 1); /* Display the data in the FSP_SMBIOS_MEMORY_INFO HOB */ if (IS_ENABLED(CONFIG_DISPLAY_HOBS)) { printk(BIOS_DEBUG, "FSP_SMBIOS_MEMORY_INFO HOB\n"); printk(BIOS_DEBUG, " 0x%02x: Revision\n", memory_info_hob->Revision); printk(BIOS_DEBUG, " 0x%02x: MemoryType\n", memory_info_hob->MemoryType); printk(BIOS_DEBUG, " %d: MemoryFrequencyInMHz\n", memory_info_hob->MemoryFrequencyInMHz); printk(BIOS_DEBUG, " %d: DataWidth in bits\n", memory_info_hob->DataWidth); printk(BIOS_DEBUG, " 0x%02x: ErrorCorrectionType\n", memory_info_hob->ErrorCorrectionType); printk(BIOS_DEBUG, " 0x%02x: ChannelCount\n", memory_info_hob->ChannelCount); for (channel = 0; channel < memory_info_hob->ChannelCount; channel++) { channel_info = &memory_info_hob->ChannelInfo[channel]; printk(BIOS_DEBUG, " Channel %d\n", channel); printk(BIOS_DEBUG, " 0x%02x: ChannelId\n", channel_info->ChannelId); printk(BIOS_DEBUG, " 0x%02x: DimmCount\n", channel_info->DimmCount); for (dimm = 0; dimm < channel_info->DimmCount; dimm++) { dimm_info = &channel_info->DimmInfo[dimm]; printk(BIOS_DEBUG, " DIMM %d\n", dimm); printk(BIOS_DEBUG, " 0x%02x: DimmId\n", dimm_info->DimmId); printk(BIOS_DEBUG, " %d: SizeInMb\n", dimm_info->SizeInMb); } } } /* * Allocate CBMEM area for DIMM information used to populate SMBIOS * table 17 */ mem_info = cbmem_add(CBMEM_ID_MEMINFO, sizeof(*mem_info)); printk(BIOS_DEBUG, "CBMEM entry for DIMM info: 0x%p\n", mem_info); if (mem_info == NULL) return; memset(mem_info, 0, sizeof(*mem_info)); /* Describe the first N DIMMs in the system */ index = 0; dimm_max = ARRAY_SIZE(mem_info->dimm); for (channel = 0; channel < memory_info_hob->ChannelCount; channel++) { if (index >= dimm_max) break; channel_info = &memory_info_hob->ChannelInfo[channel]; for (dimm = 0; dimm < channel_info->DimmCount; dimm++) { if (index >= dimm_max) break; dimm_info = &channel_info->DimmInfo[dimm]; /* Populate the DIMM information */ if (dimm_info->SizeInMb) { mem_info->dimm[index].dimm_size = dimm_info->SizeInMb; mem_info->dimm[index].ddr_type = memory_info_hob->MemoryType; mem_info->dimm[index].ddr_frequency = memory_info_hob->MemoryFrequencyInMHz; mem_info->dimm[index].channel_num = channel_info->ChannelId; mem_info->dimm[index].dimm_num = dimm_info->DimmId; switch (memory_info_hob->DataWidth) { default: case 8: mem_info->dimm[index].bus_width = MEMORY_BUS_WIDTH_8; break; case 16: mem_info->dimm[index].bus_width = MEMORY_BUS_WIDTH_16; break; case 32: mem_info->dimm[index].bus_width = MEMORY_BUS_WIDTH_32; break; case 64: mem_info->dimm[index].bus_width = MEMORY_BUS_WIDTH_64; break; case 128: mem_info->dimm[index].bus_width = MEMORY_BUS_WIDTH_128; break; } /* Add any mainboard specific information */ mainboard_add_dimm_info(params, mem_info, channel, dimm, index); index++; } } } mem_info->dimm_cnt = index; printk(BIOS_DEBUG, "%d DIMMs found\n", mem_info->dimm_cnt); }