/* SPDX-License-Identifier: GPL-2.0-only */ /* This file is part of the coreboot project. */ #include #include #include #include #include #include #include #include #include #include #include #include /** * Populate dimm_info using AGESA TYPE17_DMI_INFO. */ static void transfer_memory_info(TYPE17_DMI_INFO *dmi17, struct dimm_info *dimm) { hexstrtobin(dmi17->SerialNumber, dimm->serial, sizeof(dimm->serial)); dimm->dimm_size = smbios_memory_size_to_mib(dmi17->MemorySize, dmi17->ExtSize); dimm->ddr_type = dmi17->MemoryType; /* * dimm_info uses ddr_frequency for setting both config speed and max * speed. Lets use config speed so we don't get the false impression * that the RAM is running faster than it actually is. */ dimm->ddr_frequency = dmi17->ConfigSpeed; dimm->rank_per_dimm = dmi17->Attributes; dimm->mod_type = smbios_form_factor_to_spd_mod_type(dmi17->FormFactor); dimm->bus_width = smbios_bus_width_to_spd_width(dmi17->TotalWidth, dmi17->DataWidth); dimm->mod_id = dmi17->ManufacturerIdCode; dimm->bank_locator = 0; strncpy((char *)dimm->module_part_number, dmi17->PartNumber, sizeof(dimm->module_part_number) - 1); } static void print_dimm_info(const struct dimm_info *dimm) { printk(RAM_SPEW, "CBMEM_ID_MEMINFO:\n" " dimm_size: %u\n" " ddr_type: 0x%hx\n" " ddr_frequency: %hu\n" " rank_per_dimm: %hhu\n" " channel_num: %hhu\n" " dimm_num: %hhu\n" " bank_locator: %hhu\n" " mod_id: %hu\n" " mod_type: 0x%hhx\n" " bus_width: %hhu\n" " serial: %02hhx%02hhx%02hhx%02hhx\n" " module_part_number(%zu): %s\n", dimm->dimm_size, dimm->ddr_type, dimm->ddr_frequency, dimm->rank_per_dimm, dimm->channel_num, dimm->dimm_num, dimm->bank_locator, dimm->mod_id, dimm->mod_type, dimm->bus_width, dimm->serial[0], dimm->serial[1], dimm->serial[2], dimm->serial[3], strlen((char *) dimm->module_part_number), (char *) dimm->module_part_number ); } static void print_dmi_info(const TYPE17_DMI_INFO *dmi17) { printk(RAM_SPEW, "AGESA TYPE 17 DMI INFO:\n" " Handle: %hu\n" " TotalWidth: %hu\n" " DataWidth: %hu\n" " MemorySize: %hu\n" " DeviceSet: %hhu\n" " Speed: %hu\n" " ManufacturerIdCode: %llu\n" " Attributes: %hhu\n" " ExtSize: %u\n" " ConfigSpeed: %hu\n" " MemoryType: 0x%x\n" " FormFactor: 0x%x\n" " DeviceLocator: %8s\n" " BankLocator: %10s\n" " SerialNumber(%zu): %9s\n" " PartNumber(%zu): %19s\n", dmi17->Handle, dmi17->TotalWidth, dmi17->DataWidth, dmi17->MemorySize, dmi17->DeviceSet, dmi17->Speed, dmi17->ManufacturerIdCode, dmi17->Attributes, dmi17->ExtSize, dmi17->ConfigSpeed, dmi17->MemoryType, dmi17->FormFactor, dmi17->DeviceLocator, dmi17->BankLocator, strlen((char *) dmi17->SerialNumber), dmi17->SerialNumber, strlen((char *) dmi17->PartNumber), dmi17->PartNumber ); } static void prepare_dmi_17(void *unused) { DMI_INFO *DmiTable; TYPE17_DMI_INFO *address; struct memory_info *mem_info; struct dimm_info *dimm; int i, j, dimm_cnt = 0; mem_info = cbmem_add(CBMEM_ID_MEMINFO, sizeof(struct memory_info)); if (!mem_info) { printk(BIOS_NOTICE, "Failed to add memory info to CBMEM.\n"); return; } memset(mem_info, 0, sizeof(struct memory_info)); DmiTable = agesawrapper_getlateinitptr(PICK_DMI); for (i = 0; i < MAX_CHANNELS_PER_SOCKET; i++) { for (j = 0; j < MAX_DIMMS_PER_CHANNEL; j++) { address = &DmiTable->T17[0][i][j]; if (address->Handle > 0) { dimm = &mem_info->dimm[dimm_cnt]; dimm->channel_num = i; dimm->dimm_num = j; transfer_memory_info(address, dimm); print_dmi_info(address); print_dimm_info(dimm); dimm_cnt++; } } } mem_info->dimm_cnt = dimm_cnt; } BOOT_STATE_INIT_ENTRY(BS_WRITE_TABLES, BS_ON_ENTRY, prepare_dmi_17, NULL); static void agesawrapper_post_device(void *unused) { if (acpi_is_wakeup_s3()) return; do_agesawrapper(AMD_INIT_LATE, "amdinitlate"); if (!acpi_s3_resume_allowed()) return; do_agesawrapper(AMD_INIT_RTB, "amdinitrtb"); } BOOT_STATE_INIT_ENTRY(BS_POST_DEVICE, BS_ON_EXIT, agesawrapper_post_device, NULL);