diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 740711ac1037..219c53797752 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -152,12 +152,6 @@ MODULE_FIRMWARE(FIRMWARE_DCN_36_DMUB); #define FIRMWARE_DCN_401_DMUB "amdgpu/dcn_4_0_1_dmcub.bin" MODULE_FIRMWARE(FIRMWARE_DCN_401_DMUB); -/* Number of bytes in PSP header for firmware. */ -#define PSP_HEADER_BYTES 0x100 - -/* Number of bytes in PSP footer for firmware. */ -#define PSP_FOOTER_BYTES 0x100 - /** * DOC: overview * @@ -1298,15 +1292,14 @@ static int dm_dmub_hw_init(struct amdgpu_device *adev) fw_inst_const = dmub_fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes) + - PSP_HEADER_BYTES; + PSP_HEADER_BYTES_256; fw_bss_data = dmub_fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes) + le32_to_cpu(hdr->inst_const_bytes); /* Copy firmware and bios info into FB memory. */ - fw_inst_const_size = le32_to_cpu(hdr->inst_const_bytes) - - PSP_HEADER_BYTES - PSP_FOOTER_BYTES; + fw_inst_const_size = adev->dm.fw_inst_size; fw_bss_data_size = le32_to_cpu(hdr->bss_data_bytes); @@ -2437,9 +2430,11 @@ static void amdgpu_dm_dmub_reg_write(void *ctx, uint32_t address, static int dm_dmub_sw_init(struct amdgpu_device *adev) { struct dmub_srv_create_params create_params; + struct dmub_srv_fw_meta_info_params fw_meta_info_params; struct dmub_srv_region_params region_params; struct dmub_srv_region_info region_info; struct dmub_srv_memory_params memory_params; + struct dmub_fw_meta_info fw_info; struct dmub_srv_fb_info *fb_info; struct dmub_srv *dmub_srv; const struct dmcub_firmware_header_v1_0 *hdr; @@ -2547,22 +2542,37 @@ static int dm_dmub_sw_init(struct amdgpu_device *adev) return -EINVAL; } + /* Extract the FW meta info. */ + memset(&fw_meta_info_params, 0, sizeof(fw_meta_info_params)); + + fw_meta_info_params.inst_const_size = le32_to_cpu(hdr->inst_const_bytes) - + PSP_HEADER_BYTES_256; + fw_meta_info_params.bss_data_size = le32_to_cpu(hdr->bss_data_bytes); + fw_meta_info_params.fw_inst_const = adev->dm.dmub_fw->data + + le32_to_cpu(hdr->header.ucode_array_offset_bytes) + + PSP_HEADER_BYTES_256; + fw_meta_info_params.fw_bss_data = region_params.bss_data_size ? adev->dm.dmub_fw->data + + le32_to_cpu(hdr->header.ucode_array_offset_bytes) + + le32_to_cpu(hdr->inst_const_bytes) : NULL; + fw_meta_info_params.custom_psp_footer_size = 0; + + status = dmub_srv_get_fw_meta_info_from_raw_fw(&fw_meta_info_params, &fw_info); + if (status != DMUB_STATUS_OK) { + /* Skip returning early, just log the error. */ + drm_err(adev_to_drm(adev), "Error getting DMUB FW meta info: %d\n", status); + // return -EINVAL; + } + /* Calculate the size of all the regions for the DMUB service. */ memset(®ion_params, 0, sizeof(region_params)); - region_params.inst_const_size = le32_to_cpu(hdr->inst_const_bytes) - - PSP_HEADER_BYTES - PSP_FOOTER_BYTES; - region_params.bss_data_size = le32_to_cpu(hdr->bss_data_bytes); + region_params.inst_const_size = fw_meta_info_params.inst_const_size; + region_params.bss_data_size = fw_meta_info_params.bss_data_size; region_params.vbios_size = adev->bios_size; - region_params.fw_bss_data = region_params.bss_data_size ? - adev->dm.dmub_fw->data + - le32_to_cpu(hdr->header.ucode_array_offset_bytes) + - le32_to_cpu(hdr->inst_const_bytes) : NULL; - region_params.fw_inst_const = - adev->dm.dmub_fw->data + - le32_to_cpu(hdr->header.ucode_array_offset_bytes) + - PSP_HEADER_BYTES; + region_params.fw_bss_data = fw_meta_info_params.fw_bss_data; + region_params.fw_inst_const = fw_meta_info_params.fw_inst_const; region_params.window_memory_type = window_memory_type; + region_params.fw_info = (status == DMUB_STATUS_OK) ? &fw_info : NULL; status = dmub_srv_calc_region_info(dmub_srv, ®ion_params, ®ion_info); @@ -2609,6 +2619,7 @@ static int dm_dmub_sw_init(struct amdgpu_device *adev) } adev->dm.bb_from_dmub = dm_dmub_get_vbios_bounding_box(adev); + adev->dm.fw_inst_size = fw_meta_info_params.inst_const_size; return 0; } diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h index bd0403005f37..ab363f2f6d47 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -413,6 +413,13 @@ struct amdgpu_display_manager { */ uint32_t dmcub_fw_version; + /** + * @fw_inst_size: + * + * Size of the firmware instruction buffer. + */ + uint32_t fw_inst_size; + /** * @cgs_device: * diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 37d301e82d39..57df6dc81041 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -1188,6 +1188,7 @@ struct dc_debug_options { short auxless_alpm_lfps_t1t2_offset_us; bool disable_stutter_for_wm_program; bool enable_block_sequence_programming; + uint32_t custom_psp_footer_size; }; diff --git a/drivers/gpu/drm/amd/display/dmub/dmub_srv.h b/drivers/gpu/drm/amd/display/dmub/dmub_srv.h index 9d0168986fe7..12c1f9f7115a 100644 --- a/drivers/gpu/drm/amd/display/dmub/dmub_srv.h +++ b/drivers/gpu/drm/amd/display/dmub/dmub_srv.h @@ -72,6 +72,9 @@ /* Default tracebuffer size if meta is absent. */ #define DMUB_TRACE_BUFFER_SIZE (64 * 1024) +#define PSP_HEADER_BYTES_256 0x100 // 256 bytes +#define PSP_FOOTER_BYTES_256 0x100 // 256 bytes + /* Forward declarations */ struct dmub_srv; struct dmub_srv_common_regs; @@ -227,6 +230,23 @@ struct dmub_srv_region_params { const uint8_t *fw_inst_const; const uint8_t *fw_bss_data; const enum dmub_window_memory_type *window_memory_type; + const struct dmub_fw_meta_info *fw_info; +}; + +/** + * struct dmub_srv_fw_meta_info_params - params used for fetching fw meta info from fw_image + * @inst_const_size: size of the fw inst const section + * @bss_data_size: size of the fw bss data section + * @fw_inst_const: raw firmware inst const section + * @fw_bss_data: raw firmware bss data section + * @custom_psp_footer_size: custom psp footer size to use when indexing for fw meta info + */ +struct dmub_srv_fw_meta_info_params { + uint32_t inst_const_size; + uint32_t bss_data_size; + const uint8_t *fw_inst_const; + const uint8_t *fw_bss_data; + uint32_t custom_psp_footer_size; }; /** @@ -249,6 +269,7 @@ struct dmub_srv_region_info { uint32_t gart_size; uint8_t num_regions; struct dmub_region regions[DMUB_WINDOW_TOTAL]; + uint32_t verified_psp_footer_size; }; /** @@ -1098,4 +1119,16 @@ enum dmub_status dmub_srv_update_inbox_status(struct dmub_srv *dmub); */ bool dmub_srv_get_preos_info(struct dmub_srv *dmub); +/** + * dmub_srv_get_fw_meta_info_from_raw_fw() - Fetch firmware metadata info from raw firmware image + * @params: parameters for fetching firmware metadata info + * @fw_info_out: output buffer for firmware metadata info + * + * Return: + * DMUB_STATUS_OK - success + * DMUB_STATUS_INVALID - no FW meta info found + */ +enum dmub_status dmub_srv_get_fw_meta_info_from_raw_fw(struct dmub_srv_fw_meta_info_params *params, + struct dmub_fw_meta_info *fw_info_out); + #endif /* _DMUB_SRV_H_ */ diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c index a6ae1d2e9685..be893531ae7d 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c @@ -134,7 +134,7 @@ dmub_get_fw_meta_info_from_blob(const uint8_t *blob, uint32_t blob_size, uint32_ } static const struct dmub_fw_meta_info * -dmub_get_fw_meta_info(const struct dmub_srv_region_params *params) +dmub_get_fw_meta_info(const struct dmub_srv_fw_meta_info_params *params) { const struct dmub_fw_meta_info *info = NULL; @@ -159,6 +159,46 @@ dmub_get_fw_meta_info(const struct dmub_srv_region_params *params) return info; } +enum dmub_status +dmub_srv_get_fw_meta_info_from_raw_fw(struct dmub_srv_fw_meta_info_params *params, + struct dmub_fw_meta_info *fw_info_out) +{ + const struct dmub_fw_meta_info *fw_info = NULL; + uint32_t inst_const_size_temp = params->inst_const_size; + + /* First try custom psp footer size, if present */ + if (params->custom_psp_footer_size) { + params->inst_const_size -= params->custom_psp_footer_size; + fw_info = dmub_get_fw_meta_info(params); + if (fw_info) { + memcpy(fw_info_out, fw_info, sizeof(*fw_info)); + return DMUB_STATUS_OK; + } + params->inst_const_size = inst_const_size_temp; + } + + /* Try 256-byte psp footer size */ + params->inst_const_size -= PSP_FOOTER_BYTES_256; + fw_info = dmub_get_fw_meta_info(params); + if (fw_info) { + memcpy(fw_info_out, fw_info, sizeof(*fw_info)); + return DMUB_STATUS_OK; + } + + /* Try 512-byte psp footer size - final attempt */ + params->inst_const_size -= PSP_FOOTER_BYTES_256; // 256 bytes already subtracted, subtract 256 again + fw_info = dmub_get_fw_meta_info(params); + if (fw_info) { + memcpy(fw_info_out, fw_info, sizeof(*fw_info)); + return DMUB_STATUS_OK; + } + + /* Restore original inst_const_size and subtract default PSP footer size - default behaviour */ + params->inst_const_size = inst_const_size_temp - PSP_FOOTER_BYTES_256; + + return DMUB_STATUS_INVALID; +} + static bool dmub_srv_hw_setup(struct dmub_srv *dmub, enum dmub_asic asic) { struct dmub_srv_hw_funcs *funcs = &dmub->hw_funcs; @@ -524,7 +564,6 @@ enum dmub_status const struct dmub_srv_region_params *params, struct dmub_srv_region_info *out) { - const struct dmub_fw_meta_info *fw_info; uint32_t fw_state_size = DMUB_FW_STATE_SIZE; uint32_t trace_buffer_size = DMUB_TRACE_BUFFER_SIZE; uint32_t shared_state_size = DMUB_FW_HEADER_SHARED_STATE_SIZE; @@ -538,14 +577,12 @@ enum dmub_status out->num_regions = DMUB_NUM_WINDOWS; - fw_info = dmub_get_fw_meta_info(params); + if (params->fw_info) { + memcpy(&dmub->meta_info, params->fw_info, sizeof(*params->fw_info)); - if (fw_info) { - memcpy(&dmub->meta_info, fw_info, sizeof(*fw_info)); - - fw_state_size = fw_info->fw_region_size; - trace_buffer_size = fw_info->trace_buffer_size; - shared_state_size = fw_info->shared_state_size; + fw_state_size = params->fw_info->fw_region_size; + trace_buffer_size = params->fw_info->trace_buffer_size; + shared_state_size = params->fw_info->shared_state_size; /** * If DM didn't fill in a version, then fill it in based on @@ -555,7 +592,7 @@ enum dmub_status * pass during creation. */ if (dmub->fw_version == 0) - dmub->fw_version = fw_info->fw_version; + dmub->fw_version = params->fw_info->fw_version; } window_sizes[DMUB_WINDOW_0_INST_CONST] = params->inst_const_size;