162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright 2014 Advanced Micro Devices, Inc. 362306a36Sopenharmony_ci * Copyright 2008 Red Hat Inc. 462306a36Sopenharmony_ci * Copyright 2009 Jerome Glisse. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 762306a36Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 862306a36Sopenharmony_ci * to deal in the Software without restriction, including without limitation 962306a36Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 1062306a36Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 1162306a36Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * The above copyright notice and this permission notice shall be included in 1462306a36Sopenharmony_ci * all copies or substantial portions of the Software. 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1762306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1862306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1962306a36Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 2062306a36Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 2162306a36Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 2262306a36Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE. 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci */ 2562306a36Sopenharmony_ci#include <linux/firmware.h> 2662306a36Sopenharmony_ci#include "amdgpu.h" 2762306a36Sopenharmony_ci#include "amdgpu_gfx.h" 2862306a36Sopenharmony_ci#include "amdgpu_rlc.h" 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci/** 3162306a36Sopenharmony_ci * amdgpu_gfx_rlc_enter_safe_mode - Set RLC into safe mode 3262306a36Sopenharmony_ci * 3362306a36Sopenharmony_ci * @adev: amdgpu_device pointer 3462306a36Sopenharmony_ci * @xcc_id: xcc accelerated compute core id 3562306a36Sopenharmony_ci * 3662306a36Sopenharmony_ci * Set RLC enter into safe mode if RLC is enabled and haven't in safe mode. 3762306a36Sopenharmony_ci */ 3862306a36Sopenharmony_civoid amdgpu_gfx_rlc_enter_safe_mode(struct amdgpu_device *adev, int xcc_id) 3962306a36Sopenharmony_ci{ 4062306a36Sopenharmony_ci if (adev->gfx.rlc.in_safe_mode[xcc_id]) 4162306a36Sopenharmony_ci return; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci /* if RLC is not enabled, do nothing */ 4462306a36Sopenharmony_ci if (!adev->gfx.rlc.funcs->is_rlc_enabled(adev)) 4562306a36Sopenharmony_ci return; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci if (adev->cg_flags & 4862306a36Sopenharmony_ci (AMD_CG_SUPPORT_GFX_CGCG | AMD_CG_SUPPORT_GFX_MGCG | 4962306a36Sopenharmony_ci AMD_CG_SUPPORT_GFX_3D_CGCG)) { 5062306a36Sopenharmony_ci adev->gfx.rlc.funcs->set_safe_mode(adev, xcc_id); 5162306a36Sopenharmony_ci adev->gfx.rlc.in_safe_mode[xcc_id] = true; 5262306a36Sopenharmony_ci } 5362306a36Sopenharmony_ci} 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci/** 5662306a36Sopenharmony_ci * amdgpu_gfx_rlc_exit_safe_mode - Set RLC out of safe mode 5762306a36Sopenharmony_ci * 5862306a36Sopenharmony_ci * @adev: amdgpu_device pointer 5962306a36Sopenharmony_ci * @xcc_id: xcc accelerated compute core id 6062306a36Sopenharmony_ci * 6162306a36Sopenharmony_ci * Set RLC exit safe mode if RLC is enabled and have entered into safe mode. 6262306a36Sopenharmony_ci */ 6362306a36Sopenharmony_civoid amdgpu_gfx_rlc_exit_safe_mode(struct amdgpu_device *adev, int xcc_id) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci if (!(adev->gfx.rlc.in_safe_mode[xcc_id])) 6662306a36Sopenharmony_ci return; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci /* if RLC is not enabled, do nothing */ 6962306a36Sopenharmony_ci if (!adev->gfx.rlc.funcs->is_rlc_enabled(adev)) 7062306a36Sopenharmony_ci return; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci if (adev->cg_flags & 7362306a36Sopenharmony_ci (AMD_CG_SUPPORT_GFX_CGCG | AMD_CG_SUPPORT_GFX_MGCG | 7462306a36Sopenharmony_ci AMD_CG_SUPPORT_GFX_3D_CGCG)) { 7562306a36Sopenharmony_ci adev->gfx.rlc.funcs->unset_safe_mode(adev, xcc_id); 7662306a36Sopenharmony_ci adev->gfx.rlc.in_safe_mode[xcc_id] = false; 7762306a36Sopenharmony_ci } 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci/** 8162306a36Sopenharmony_ci * amdgpu_gfx_rlc_init_sr - Init save restore block 8262306a36Sopenharmony_ci * 8362306a36Sopenharmony_ci * @adev: amdgpu_device pointer 8462306a36Sopenharmony_ci * @dws: the size of save restore block 8562306a36Sopenharmony_ci * 8662306a36Sopenharmony_ci * Allocate and setup value to save restore block of rlc. 8762306a36Sopenharmony_ci * Returns 0 on succeess or negative error code if allocate failed. 8862306a36Sopenharmony_ci */ 8962306a36Sopenharmony_ciint amdgpu_gfx_rlc_init_sr(struct amdgpu_device *adev, u32 dws) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci const u32 *src_ptr; 9262306a36Sopenharmony_ci volatile u32 *dst_ptr; 9362306a36Sopenharmony_ci u32 i; 9462306a36Sopenharmony_ci int r; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci /* allocate save restore block */ 9762306a36Sopenharmony_ci r = amdgpu_bo_create_reserved(adev, dws * 4, PAGE_SIZE, 9862306a36Sopenharmony_ci AMDGPU_GEM_DOMAIN_VRAM | 9962306a36Sopenharmony_ci AMDGPU_GEM_DOMAIN_GTT, 10062306a36Sopenharmony_ci &adev->gfx.rlc.save_restore_obj, 10162306a36Sopenharmony_ci &adev->gfx.rlc.save_restore_gpu_addr, 10262306a36Sopenharmony_ci (void **)&adev->gfx.rlc.sr_ptr); 10362306a36Sopenharmony_ci if (r) { 10462306a36Sopenharmony_ci dev_warn(adev->dev, "(%d) create RLC sr bo failed\n", r); 10562306a36Sopenharmony_ci amdgpu_gfx_rlc_fini(adev); 10662306a36Sopenharmony_ci return r; 10762306a36Sopenharmony_ci } 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci /* write the sr buffer */ 11062306a36Sopenharmony_ci src_ptr = adev->gfx.rlc.reg_list; 11162306a36Sopenharmony_ci dst_ptr = adev->gfx.rlc.sr_ptr; 11262306a36Sopenharmony_ci for (i = 0; i < adev->gfx.rlc.reg_list_size; i++) 11362306a36Sopenharmony_ci dst_ptr[i] = cpu_to_le32(src_ptr[i]); 11462306a36Sopenharmony_ci amdgpu_bo_kunmap(adev->gfx.rlc.save_restore_obj); 11562306a36Sopenharmony_ci amdgpu_bo_unreserve(adev->gfx.rlc.save_restore_obj); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci return 0; 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci/** 12162306a36Sopenharmony_ci * amdgpu_gfx_rlc_init_csb - Init clear state block 12262306a36Sopenharmony_ci * 12362306a36Sopenharmony_ci * @adev: amdgpu_device pointer 12462306a36Sopenharmony_ci * 12562306a36Sopenharmony_ci * Allocate and setup value to clear state block of rlc. 12662306a36Sopenharmony_ci * Returns 0 on succeess or negative error code if allocate failed. 12762306a36Sopenharmony_ci */ 12862306a36Sopenharmony_ciint amdgpu_gfx_rlc_init_csb(struct amdgpu_device *adev) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci u32 dws; 13162306a36Sopenharmony_ci int r; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci /* allocate clear state block */ 13462306a36Sopenharmony_ci adev->gfx.rlc.clear_state_size = dws = adev->gfx.rlc.funcs->get_csb_size(adev); 13562306a36Sopenharmony_ci r = amdgpu_bo_create_kernel(adev, dws * 4, PAGE_SIZE, 13662306a36Sopenharmony_ci AMDGPU_GEM_DOMAIN_VRAM | 13762306a36Sopenharmony_ci AMDGPU_GEM_DOMAIN_GTT, 13862306a36Sopenharmony_ci &adev->gfx.rlc.clear_state_obj, 13962306a36Sopenharmony_ci &adev->gfx.rlc.clear_state_gpu_addr, 14062306a36Sopenharmony_ci (void **)&adev->gfx.rlc.cs_ptr); 14162306a36Sopenharmony_ci if (r) { 14262306a36Sopenharmony_ci dev_err(adev->dev, "(%d) failed to create rlc csb bo\n", r); 14362306a36Sopenharmony_ci amdgpu_gfx_rlc_fini(adev); 14462306a36Sopenharmony_ci return r; 14562306a36Sopenharmony_ci } 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci return 0; 14862306a36Sopenharmony_ci} 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci/** 15162306a36Sopenharmony_ci * amdgpu_gfx_rlc_init_cpt - Init cp table 15262306a36Sopenharmony_ci * 15362306a36Sopenharmony_ci * @adev: amdgpu_device pointer 15462306a36Sopenharmony_ci * 15562306a36Sopenharmony_ci * Allocate and setup value to cp table of rlc. 15662306a36Sopenharmony_ci * Returns 0 on succeess or negative error code if allocate failed. 15762306a36Sopenharmony_ci */ 15862306a36Sopenharmony_ciint amdgpu_gfx_rlc_init_cpt(struct amdgpu_device *adev) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci int r; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci r = amdgpu_bo_create_reserved(adev, adev->gfx.rlc.cp_table_size, 16362306a36Sopenharmony_ci PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM | 16462306a36Sopenharmony_ci AMDGPU_GEM_DOMAIN_GTT, 16562306a36Sopenharmony_ci &adev->gfx.rlc.cp_table_obj, 16662306a36Sopenharmony_ci &adev->gfx.rlc.cp_table_gpu_addr, 16762306a36Sopenharmony_ci (void **)&adev->gfx.rlc.cp_table_ptr); 16862306a36Sopenharmony_ci if (r) { 16962306a36Sopenharmony_ci dev_err(adev->dev, "(%d) failed to create cp table bo\n", r); 17062306a36Sopenharmony_ci amdgpu_gfx_rlc_fini(adev); 17162306a36Sopenharmony_ci return r; 17262306a36Sopenharmony_ci } 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci /* set up the cp table */ 17562306a36Sopenharmony_ci amdgpu_gfx_rlc_setup_cp_table(adev); 17662306a36Sopenharmony_ci amdgpu_bo_kunmap(adev->gfx.rlc.cp_table_obj); 17762306a36Sopenharmony_ci amdgpu_bo_unreserve(adev->gfx.rlc.cp_table_obj); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci return 0; 18062306a36Sopenharmony_ci} 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci/** 18362306a36Sopenharmony_ci * amdgpu_gfx_rlc_setup_cp_table - setup cp the buffer of cp table 18462306a36Sopenharmony_ci * 18562306a36Sopenharmony_ci * @adev: amdgpu_device pointer 18662306a36Sopenharmony_ci * 18762306a36Sopenharmony_ci * Write cp firmware data into cp table. 18862306a36Sopenharmony_ci */ 18962306a36Sopenharmony_civoid amdgpu_gfx_rlc_setup_cp_table(struct amdgpu_device *adev) 19062306a36Sopenharmony_ci{ 19162306a36Sopenharmony_ci const __le32 *fw_data; 19262306a36Sopenharmony_ci volatile u32 *dst_ptr; 19362306a36Sopenharmony_ci int me, i, max_me; 19462306a36Sopenharmony_ci u32 bo_offset = 0; 19562306a36Sopenharmony_ci u32 table_offset, table_size; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci max_me = adev->gfx.rlc.funcs->get_cp_table_num(adev); 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci /* write the cp table buffer */ 20062306a36Sopenharmony_ci dst_ptr = adev->gfx.rlc.cp_table_ptr; 20162306a36Sopenharmony_ci for (me = 0; me < max_me; me++) { 20262306a36Sopenharmony_ci if (me == 0) { 20362306a36Sopenharmony_ci const struct gfx_firmware_header_v1_0 *hdr = 20462306a36Sopenharmony_ci (const struct gfx_firmware_header_v1_0 *)adev->gfx.ce_fw->data; 20562306a36Sopenharmony_ci fw_data = (const __le32 *) 20662306a36Sopenharmony_ci (adev->gfx.ce_fw->data + 20762306a36Sopenharmony_ci le32_to_cpu(hdr->header.ucode_array_offset_bytes)); 20862306a36Sopenharmony_ci table_offset = le32_to_cpu(hdr->jt_offset); 20962306a36Sopenharmony_ci table_size = le32_to_cpu(hdr->jt_size); 21062306a36Sopenharmony_ci } else if (me == 1) { 21162306a36Sopenharmony_ci const struct gfx_firmware_header_v1_0 *hdr = 21262306a36Sopenharmony_ci (const struct gfx_firmware_header_v1_0 *)adev->gfx.pfp_fw->data; 21362306a36Sopenharmony_ci fw_data = (const __le32 *) 21462306a36Sopenharmony_ci (adev->gfx.pfp_fw->data + 21562306a36Sopenharmony_ci le32_to_cpu(hdr->header.ucode_array_offset_bytes)); 21662306a36Sopenharmony_ci table_offset = le32_to_cpu(hdr->jt_offset); 21762306a36Sopenharmony_ci table_size = le32_to_cpu(hdr->jt_size); 21862306a36Sopenharmony_ci } else if (me == 2) { 21962306a36Sopenharmony_ci const struct gfx_firmware_header_v1_0 *hdr = 22062306a36Sopenharmony_ci (const struct gfx_firmware_header_v1_0 *)adev->gfx.me_fw->data; 22162306a36Sopenharmony_ci fw_data = (const __le32 *) 22262306a36Sopenharmony_ci (adev->gfx.me_fw->data + 22362306a36Sopenharmony_ci le32_to_cpu(hdr->header.ucode_array_offset_bytes)); 22462306a36Sopenharmony_ci table_offset = le32_to_cpu(hdr->jt_offset); 22562306a36Sopenharmony_ci table_size = le32_to_cpu(hdr->jt_size); 22662306a36Sopenharmony_ci } else if (me == 3) { 22762306a36Sopenharmony_ci const struct gfx_firmware_header_v1_0 *hdr = 22862306a36Sopenharmony_ci (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec_fw->data; 22962306a36Sopenharmony_ci fw_data = (const __le32 *) 23062306a36Sopenharmony_ci (adev->gfx.mec_fw->data + 23162306a36Sopenharmony_ci le32_to_cpu(hdr->header.ucode_array_offset_bytes)); 23262306a36Sopenharmony_ci table_offset = le32_to_cpu(hdr->jt_offset); 23362306a36Sopenharmony_ci table_size = le32_to_cpu(hdr->jt_size); 23462306a36Sopenharmony_ci } else if (me == 4) { 23562306a36Sopenharmony_ci const struct gfx_firmware_header_v1_0 *hdr = 23662306a36Sopenharmony_ci (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec2_fw->data; 23762306a36Sopenharmony_ci fw_data = (const __le32 *) 23862306a36Sopenharmony_ci (adev->gfx.mec2_fw->data + 23962306a36Sopenharmony_ci le32_to_cpu(hdr->header.ucode_array_offset_bytes)); 24062306a36Sopenharmony_ci table_offset = le32_to_cpu(hdr->jt_offset); 24162306a36Sopenharmony_ci table_size = le32_to_cpu(hdr->jt_size); 24262306a36Sopenharmony_ci } 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci for (i = 0; i < table_size; i ++) { 24562306a36Sopenharmony_ci dst_ptr[bo_offset + i] = 24662306a36Sopenharmony_ci cpu_to_le32(le32_to_cpu(fw_data[table_offset + i])); 24762306a36Sopenharmony_ci } 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci bo_offset += table_size; 25062306a36Sopenharmony_ci } 25162306a36Sopenharmony_ci} 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci/** 25462306a36Sopenharmony_ci * amdgpu_gfx_rlc_fini - Free BO which used for RLC 25562306a36Sopenharmony_ci * 25662306a36Sopenharmony_ci * @adev: amdgpu_device pointer 25762306a36Sopenharmony_ci * 25862306a36Sopenharmony_ci * Free three BO which is used for rlc_save_restore_block, rlc_clear_state_block 25962306a36Sopenharmony_ci * and rlc_jump_table_block. 26062306a36Sopenharmony_ci */ 26162306a36Sopenharmony_civoid amdgpu_gfx_rlc_fini(struct amdgpu_device *adev) 26262306a36Sopenharmony_ci{ 26362306a36Sopenharmony_ci /* save restore block */ 26462306a36Sopenharmony_ci if (adev->gfx.rlc.save_restore_obj) { 26562306a36Sopenharmony_ci amdgpu_bo_free_kernel(&adev->gfx.rlc.save_restore_obj, 26662306a36Sopenharmony_ci &adev->gfx.rlc.save_restore_gpu_addr, 26762306a36Sopenharmony_ci (void **)&adev->gfx.rlc.sr_ptr); 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci /* clear state block */ 27162306a36Sopenharmony_ci amdgpu_bo_free_kernel(&adev->gfx.rlc.clear_state_obj, 27262306a36Sopenharmony_ci &adev->gfx.rlc.clear_state_gpu_addr, 27362306a36Sopenharmony_ci (void **)&adev->gfx.rlc.cs_ptr); 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci /* jump table block */ 27662306a36Sopenharmony_ci amdgpu_bo_free_kernel(&adev->gfx.rlc.cp_table_obj, 27762306a36Sopenharmony_ci &adev->gfx.rlc.cp_table_gpu_addr, 27862306a36Sopenharmony_ci (void **)&adev->gfx.rlc.cp_table_ptr); 27962306a36Sopenharmony_ci} 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_cistatic int amdgpu_gfx_rlc_init_microcode_v2_0(struct amdgpu_device *adev) 28262306a36Sopenharmony_ci{ 28362306a36Sopenharmony_ci const struct common_firmware_header *common_hdr; 28462306a36Sopenharmony_ci const struct rlc_firmware_header_v2_0 *rlc_hdr; 28562306a36Sopenharmony_ci struct amdgpu_firmware_info *info; 28662306a36Sopenharmony_ci unsigned int *tmp; 28762306a36Sopenharmony_ci unsigned int i; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci rlc_hdr = (const struct rlc_firmware_header_v2_0 *)adev->gfx.rlc_fw->data; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci adev->gfx.rlc_fw_version = le32_to_cpu(rlc_hdr->header.ucode_version); 29262306a36Sopenharmony_ci adev->gfx.rlc_feature_version = le32_to_cpu(rlc_hdr->ucode_feature_version); 29362306a36Sopenharmony_ci adev->gfx.rlc.save_and_restore_offset = 29462306a36Sopenharmony_ci le32_to_cpu(rlc_hdr->save_and_restore_offset); 29562306a36Sopenharmony_ci adev->gfx.rlc.clear_state_descriptor_offset = 29662306a36Sopenharmony_ci le32_to_cpu(rlc_hdr->clear_state_descriptor_offset); 29762306a36Sopenharmony_ci adev->gfx.rlc.avail_scratch_ram_locations = 29862306a36Sopenharmony_ci le32_to_cpu(rlc_hdr->avail_scratch_ram_locations); 29962306a36Sopenharmony_ci adev->gfx.rlc.reg_restore_list_size = 30062306a36Sopenharmony_ci le32_to_cpu(rlc_hdr->reg_restore_list_size); 30162306a36Sopenharmony_ci adev->gfx.rlc.reg_list_format_start = 30262306a36Sopenharmony_ci le32_to_cpu(rlc_hdr->reg_list_format_start); 30362306a36Sopenharmony_ci adev->gfx.rlc.reg_list_format_separate_start = 30462306a36Sopenharmony_ci le32_to_cpu(rlc_hdr->reg_list_format_separate_start); 30562306a36Sopenharmony_ci adev->gfx.rlc.starting_offsets_start = 30662306a36Sopenharmony_ci le32_to_cpu(rlc_hdr->starting_offsets_start); 30762306a36Sopenharmony_ci adev->gfx.rlc.reg_list_format_size_bytes = 30862306a36Sopenharmony_ci le32_to_cpu(rlc_hdr->reg_list_format_size_bytes); 30962306a36Sopenharmony_ci adev->gfx.rlc.reg_list_size_bytes = 31062306a36Sopenharmony_ci le32_to_cpu(rlc_hdr->reg_list_size_bytes); 31162306a36Sopenharmony_ci adev->gfx.rlc.register_list_format = 31262306a36Sopenharmony_ci kmalloc(adev->gfx.rlc.reg_list_format_size_bytes + 31362306a36Sopenharmony_ci adev->gfx.rlc.reg_list_size_bytes, GFP_KERNEL); 31462306a36Sopenharmony_ci if (!adev->gfx.rlc.register_list_format) { 31562306a36Sopenharmony_ci dev_err(adev->dev, "failed to allocate memory for rlc register_list_format\n"); 31662306a36Sopenharmony_ci return -ENOMEM; 31762306a36Sopenharmony_ci } 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci tmp = (unsigned int *)((uintptr_t)rlc_hdr + 32062306a36Sopenharmony_ci le32_to_cpu(rlc_hdr->reg_list_format_array_offset_bytes)); 32162306a36Sopenharmony_ci for (i = 0 ; i < (rlc_hdr->reg_list_format_size_bytes >> 2); i++) 32262306a36Sopenharmony_ci adev->gfx.rlc.register_list_format[i] = le32_to_cpu(tmp[i]); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci adev->gfx.rlc.register_restore = adev->gfx.rlc.register_list_format + i; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci tmp = (unsigned int *)((uintptr_t)rlc_hdr + 32762306a36Sopenharmony_ci le32_to_cpu(rlc_hdr->reg_list_array_offset_bytes)); 32862306a36Sopenharmony_ci for (i = 0 ; i < (rlc_hdr->reg_list_size_bytes >> 2); i++) 32962306a36Sopenharmony_ci adev->gfx.rlc.register_restore[i] = le32_to_cpu(tmp[i]); 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { 33262306a36Sopenharmony_ci info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_G]; 33362306a36Sopenharmony_ci info->ucode_id = AMDGPU_UCODE_ID_RLC_G; 33462306a36Sopenharmony_ci info->fw = adev->gfx.rlc_fw; 33562306a36Sopenharmony_ci if (info->fw) { 33662306a36Sopenharmony_ci common_hdr = (const struct common_firmware_header *)info->fw->data; 33762306a36Sopenharmony_ci adev->firmware.fw_size += 33862306a36Sopenharmony_ci ALIGN(le32_to_cpu(common_hdr->ucode_size_bytes), PAGE_SIZE); 33962306a36Sopenharmony_ci } 34062306a36Sopenharmony_ci } 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci return 0; 34362306a36Sopenharmony_ci} 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_cistatic void amdgpu_gfx_rlc_init_microcode_v2_1(struct amdgpu_device *adev) 34662306a36Sopenharmony_ci{ 34762306a36Sopenharmony_ci const struct rlc_firmware_header_v2_1 *rlc_hdr; 34862306a36Sopenharmony_ci struct amdgpu_firmware_info *info; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci rlc_hdr = (const struct rlc_firmware_header_v2_1 *)adev->gfx.rlc_fw->data; 35162306a36Sopenharmony_ci adev->gfx.rlc_srlc_fw_version = le32_to_cpu(rlc_hdr->save_restore_list_cntl_ucode_ver); 35262306a36Sopenharmony_ci adev->gfx.rlc_srlc_feature_version = le32_to_cpu(rlc_hdr->save_restore_list_cntl_feature_ver); 35362306a36Sopenharmony_ci adev->gfx.rlc.save_restore_list_cntl_size_bytes = le32_to_cpu(rlc_hdr->save_restore_list_cntl_size_bytes); 35462306a36Sopenharmony_ci adev->gfx.rlc.save_restore_list_cntl = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->save_restore_list_cntl_offset_bytes); 35562306a36Sopenharmony_ci adev->gfx.rlc_srlg_fw_version = le32_to_cpu(rlc_hdr->save_restore_list_gpm_ucode_ver); 35662306a36Sopenharmony_ci adev->gfx.rlc_srlg_feature_version = le32_to_cpu(rlc_hdr->save_restore_list_gpm_feature_ver); 35762306a36Sopenharmony_ci adev->gfx.rlc.save_restore_list_gpm_size_bytes = le32_to_cpu(rlc_hdr->save_restore_list_gpm_size_bytes); 35862306a36Sopenharmony_ci adev->gfx.rlc.save_restore_list_gpm = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->save_restore_list_gpm_offset_bytes); 35962306a36Sopenharmony_ci adev->gfx.rlc_srls_fw_version = le32_to_cpu(rlc_hdr->save_restore_list_srm_ucode_ver); 36062306a36Sopenharmony_ci adev->gfx.rlc_srls_feature_version = le32_to_cpu(rlc_hdr->save_restore_list_srm_feature_ver); 36162306a36Sopenharmony_ci adev->gfx.rlc.save_restore_list_srm_size_bytes = le32_to_cpu(rlc_hdr->save_restore_list_srm_size_bytes); 36262306a36Sopenharmony_ci adev->gfx.rlc.save_restore_list_srm = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->save_restore_list_srm_offset_bytes); 36362306a36Sopenharmony_ci adev->gfx.rlc.reg_list_format_direct_reg_list_length = 36462306a36Sopenharmony_ci le32_to_cpu(rlc_hdr->reg_list_format_direct_reg_list_length); 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { 36762306a36Sopenharmony_ci if (adev->gfx.rlc.save_restore_list_cntl_size_bytes) { 36862306a36Sopenharmony_ci info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_RESTORE_LIST_CNTL]; 36962306a36Sopenharmony_ci info->ucode_id = AMDGPU_UCODE_ID_RLC_RESTORE_LIST_CNTL; 37062306a36Sopenharmony_ci info->fw = adev->gfx.rlc_fw; 37162306a36Sopenharmony_ci adev->firmware.fw_size += 37262306a36Sopenharmony_ci ALIGN(adev->gfx.rlc.save_restore_list_cntl_size_bytes, PAGE_SIZE); 37362306a36Sopenharmony_ci } 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci if (adev->gfx.rlc.save_restore_list_gpm_size_bytes) { 37662306a36Sopenharmony_ci info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_RESTORE_LIST_GPM_MEM]; 37762306a36Sopenharmony_ci info->ucode_id = AMDGPU_UCODE_ID_RLC_RESTORE_LIST_GPM_MEM; 37862306a36Sopenharmony_ci info->fw = adev->gfx.rlc_fw; 37962306a36Sopenharmony_ci adev->firmware.fw_size += 38062306a36Sopenharmony_ci ALIGN(adev->gfx.rlc.save_restore_list_gpm_size_bytes, PAGE_SIZE); 38162306a36Sopenharmony_ci } 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci if (adev->gfx.rlc.save_restore_list_srm_size_bytes) { 38462306a36Sopenharmony_ci info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_RESTORE_LIST_SRM_MEM]; 38562306a36Sopenharmony_ci info->ucode_id = AMDGPU_UCODE_ID_RLC_RESTORE_LIST_SRM_MEM; 38662306a36Sopenharmony_ci info->fw = adev->gfx.rlc_fw; 38762306a36Sopenharmony_ci adev->firmware.fw_size += 38862306a36Sopenharmony_ci ALIGN(adev->gfx.rlc.save_restore_list_srm_size_bytes, PAGE_SIZE); 38962306a36Sopenharmony_ci } 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci} 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_cistatic void amdgpu_gfx_rlc_init_microcode_v2_2(struct amdgpu_device *adev) 39462306a36Sopenharmony_ci{ 39562306a36Sopenharmony_ci const struct rlc_firmware_header_v2_2 *rlc_hdr; 39662306a36Sopenharmony_ci struct amdgpu_firmware_info *info; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci rlc_hdr = (const struct rlc_firmware_header_v2_2 *)adev->gfx.rlc_fw->data; 39962306a36Sopenharmony_ci adev->gfx.rlc.rlc_iram_ucode_size_bytes = le32_to_cpu(rlc_hdr->rlc_iram_ucode_size_bytes); 40062306a36Sopenharmony_ci adev->gfx.rlc.rlc_iram_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->rlc_iram_ucode_offset_bytes); 40162306a36Sopenharmony_ci adev->gfx.rlc.rlc_dram_ucode_size_bytes = le32_to_cpu(rlc_hdr->rlc_dram_ucode_size_bytes); 40262306a36Sopenharmony_ci adev->gfx.rlc.rlc_dram_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->rlc_dram_ucode_offset_bytes); 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { 40562306a36Sopenharmony_ci if (adev->gfx.rlc.rlc_iram_ucode_size_bytes) { 40662306a36Sopenharmony_ci info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_IRAM]; 40762306a36Sopenharmony_ci info->ucode_id = AMDGPU_UCODE_ID_RLC_IRAM; 40862306a36Sopenharmony_ci info->fw = adev->gfx.rlc_fw; 40962306a36Sopenharmony_ci adev->firmware.fw_size += 41062306a36Sopenharmony_ci ALIGN(adev->gfx.rlc.rlc_iram_ucode_size_bytes, PAGE_SIZE); 41162306a36Sopenharmony_ci } 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci if (adev->gfx.rlc.rlc_dram_ucode_size_bytes) { 41462306a36Sopenharmony_ci info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_DRAM]; 41562306a36Sopenharmony_ci info->ucode_id = AMDGPU_UCODE_ID_RLC_DRAM; 41662306a36Sopenharmony_ci info->fw = adev->gfx.rlc_fw; 41762306a36Sopenharmony_ci adev->firmware.fw_size += 41862306a36Sopenharmony_ci ALIGN(adev->gfx.rlc.rlc_dram_ucode_size_bytes, PAGE_SIZE); 41962306a36Sopenharmony_ci } 42062306a36Sopenharmony_ci } 42162306a36Sopenharmony_ci} 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_cistatic void amdgpu_gfx_rlc_init_microcode_v2_3(struct amdgpu_device *adev) 42462306a36Sopenharmony_ci{ 42562306a36Sopenharmony_ci const struct rlc_firmware_header_v2_3 *rlc_hdr; 42662306a36Sopenharmony_ci struct amdgpu_firmware_info *info; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci rlc_hdr = (const struct rlc_firmware_header_v2_3 *)adev->gfx.rlc_fw->data; 42962306a36Sopenharmony_ci adev->gfx.rlcp_ucode_version = le32_to_cpu(rlc_hdr->rlcp_ucode_version); 43062306a36Sopenharmony_ci adev->gfx.rlcp_ucode_feature_version = le32_to_cpu(rlc_hdr->rlcp_ucode_feature_version); 43162306a36Sopenharmony_ci adev->gfx.rlc.rlcp_ucode_size_bytes = le32_to_cpu(rlc_hdr->rlcp_ucode_size_bytes); 43262306a36Sopenharmony_ci adev->gfx.rlc.rlcp_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->rlcp_ucode_offset_bytes); 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci adev->gfx.rlcv_ucode_version = le32_to_cpu(rlc_hdr->rlcv_ucode_version); 43562306a36Sopenharmony_ci adev->gfx.rlcv_ucode_feature_version = le32_to_cpu(rlc_hdr->rlcv_ucode_feature_version); 43662306a36Sopenharmony_ci adev->gfx.rlc.rlcv_ucode_size_bytes = le32_to_cpu(rlc_hdr->rlcv_ucode_size_bytes); 43762306a36Sopenharmony_ci adev->gfx.rlc.rlcv_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->rlcv_ucode_offset_bytes); 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { 44062306a36Sopenharmony_ci if (adev->gfx.rlc.rlcp_ucode_size_bytes) { 44162306a36Sopenharmony_ci info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_P]; 44262306a36Sopenharmony_ci info->ucode_id = AMDGPU_UCODE_ID_RLC_P; 44362306a36Sopenharmony_ci info->fw = adev->gfx.rlc_fw; 44462306a36Sopenharmony_ci adev->firmware.fw_size += 44562306a36Sopenharmony_ci ALIGN(adev->gfx.rlc.rlcp_ucode_size_bytes, PAGE_SIZE); 44662306a36Sopenharmony_ci } 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci if (adev->gfx.rlc.rlcv_ucode_size_bytes) { 44962306a36Sopenharmony_ci info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_V]; 45062306a36Sopenharmony_ci info->ucode_id = AMDGPU_UCODE_ID_RLC_V; 45162306a36Sopenharmony_ci info->fw = adev->gfx.rlc_fw; 45262306a36Sopenharmony_ci adev->firmware.fw_size += 45362306a36Sopenharmony_ci ALIGN(adev->gfx.rlc.rlcv_ucode_size_bytes, PAGE_SIZE); 45462306a36Sopenharmony_ci } 45562306a36Sopenharmony_ci } 45662306a36Sopenharmony_ci} 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_cistatic void amdgpu_gfx_rlc_init_microcode_v2_4(struct amdgpu_device *adev) 45962306a36Sopenharmony_ci{ 46062306a36Sopenharmony_ci const struct rlc_firmware_header_v2_4 *rlc_hdr; 46162306a36Sopenharmony_ci struct amdgpu_firmware_info *info; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci rlc_hdr = (const struct rlc_firmware_header_v2_4 *)adev->gfx.rlc_fw->data; 46462306a36Sopenharmony_ci adev->gfx.rlc.global_tap_delays_ucode_size_bytes = le32_to_cpu(rlc_hdr->global_tap_delays_ucode_size_bytes); 46562306a36Sopenharmony_ci adev->gfx.rlc.global_tap_delays_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->global_tap_delays_ucode_offset_bytes); 46662306a36Sopenharmony_ci adev->gfx.rlc.se0_tap_delays_ucode_size_bytes = le32_to_cpu(rlc_hdr->se0_tap_delays_ucode_size_bytes); 46762306a36Sopenharmony_ci adev->gfx.rlc.se0_tap_delays_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->se0_tap_delays_ucode_offset_bytes); 46862306a36Sopenharmony_ci adev->gfx.rlc.se1_tap_delays_ucode_size_bytes = le32_to_cpu(rlc_hdr->se1_tap_delays_ucode_size_bytes); 46962306a36Sopenharmony_ci adev->gfx.rlc.se1_tap_delays_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->se1_tap_delays_ucode_offset_bytes); 47062306a36Sopenharmony_ci adev->gfx.rlc.se2_tap_delays_ucode_size_bytes = le32_to_cpu(rlc_hdr->se2_tap_delays_ucode_size_bytes); 47162306a36Sopenharmony_ci adev->gfx.rlc.se2_tap_delays_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->se2_tap_delays_ucode_offset_bytes); 47262306a36Sopenharmony_ci adev->gfx.rlc.se3_tap_delays_ucode_size_bytes = le32_to_cpu(rlc_hdr->se3_tap_delays_ucode_size_bytes); 47362306a36Sopenharmony_ci adev->gfx.rlc.se3_tap_delays_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->se3_tap_delays_ucode_offset_bytes); 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { 47662306a36Sopenharmony_ci if (adev->gfx.rlc.global_tap_delays_ucode_size_bytes) { 47762306a36Sopenharmony_ci info = &adev->firmware.ucode[AMDGPU_UCODE_ID_GLOBAL_TAP_DELAYS]; 47862306a36Sopenharmony_ci info->ucode_id = AMDGPU_UCODE_ID_GLOBAL_TAP_DELAYS; 47962306a36Sopenharmony_ci info->fw = adev->gfx.rlc_fw; 48062306a36Sopenharmony_ci adev->firmware.fw_size += 48162306a36Sopenharmony_ci ALIGN(adev->gfx.rlc.global_tap_delays_ucode_size_bytes, PAGE_SIZE); 48262306a36Sopenharmony_ci } 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci if (adev->gfx.rlc.se0_tap_delays_ucode_size_bytes) { 48562306a36Sopenharmony_ci info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SE0_TAP_DELAYS]; 48662306a36Sopenharmony_ci info->ucode_id = AMDGPU_UCODE_ID_SE0_TAP_DELAYS; 48762306a36Sopenharmony_ci info->fw = adev->gfx.rlc_fw; 48862306a36Sopenharmony_ci adev->firmware.fw_size += 48962306a36Sopenharmony_ci ALIGN(adev->gfx.rlc.se0_tap_delays_ucode_size_bytes, PAGE_SIZE); 49062306a36Sopenharmony_ci } 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci if (adev->gfx.rlc.se1_tap_delays_ucode_size_bytes) { 49362306a36Sopenharmony_ci info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SE1_TAP_DELAYS]; 49462306a36Sopenharmony_ci info->ucode_id = AMDGPU_UCODE_ID_SE1_TAP_DELAYS; 49562306a36Sopenharmony_ci info->fw = adev->gfx.rlc_fw; 49662306a36Sopenharmony_ci adev->firmware.fw_size += 49762306a36Sopenharmony_ci ALIGN(adev->gfx.rlc.se1_tap_delays_ucode_size_bytes, PAGE_SIZE); 49862306a36Sopenharmony_ci } 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci if (adev->gfx.rlc.se2_tap_delays_ucode_size_bytes) { 50162306a36Sopenharmony_ci info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SE2_TAP_DELAYS]; 50262306a36Sopenharmony_ci info->ucode_id = AMDGPU_UCODE_ID_SE2_TAP_DELAYS; 50362306a36Sopenharmony_ci info->fw = adev->gfx.rlc_fw; 50462306a36Sopenharmony_ci adev->firmware.fw_size += 50562306a36Sopenharmony_ci ALIGN(adev->gfx.rlc.se2_tap_delays_ucode_size_bytes, PAGE_SIZE); 50662306a36Sopenharmony_ci } 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci if (adev->gfx.rlc.se3_tap_delays_ucode_size_bytes) { 50962306a36Sopenharmony_ci info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SE3_TAP_DELAYS]; 51062306a36Sopenharmony_ci info->ucode_id = AMDGPU_UCODE_ID_SE3_TAP_DELAYS; 51162306a36Sopenharmony_ci info->fw = adev->gfx.rlc_fw; 51262306a36Sopenharmony_ci adev->firmware.fw_size += 51362306a36Sopenharmony_ci ALIGN(adev->gfx.rlc.se3_tap_delays_ucode_size_bytes, PAGE_SIZE); 51462306a36Sopenharmony_ci } 51562306a36Sopenharmony_ci } 51662306a36Sopenharmony_ci} 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ciint amdgpu_gfx_rlc_init_microcode(struct amdgpu_device *adev, 51962306a36Sopenharmony_ci uint16_t version_major, 52062306a36Sopenharmony_ci uint16_t version_minor) 52162306a36Sopenharmony_ci{ 52262306a36Sopenharmony_ci int err; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci if (version_major < 2) { 52562306a36Sopenharmony_ci /* only support rlc_hdr v2.x and onwards */ 52662306a36Sopenharmony_ci dev_err(adev->dev, "unsupported rlc fw hdr\n"); 52762306a36Sopenharmony_ci return -EINVAL; 52862306a36Sopenharmony_ci } 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci /* is_rlc_v2_1 is still used in APU code path */ 53162306a36Sopenharmony_ci if (version_major == 2 && version_minor == 1) 53262306a36Sopenharmony_ci adev->gfx.rlc.is_rlc_v2_1 = true; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci if (version_minor >= 0) { 53562306a36Sopenharmony_ci err = amdgpu_gfx_rlc_init_microcode_v2_0(adev); 53662306a36Sopenharmony_ci if (err) { 53762306a36Sopenharmony_ci dev_err(adev->dev, "fail to init rlc v2_0 microcode\n"); 53862306a36Sopenharmony_ci return err; 53962306a36Sopenharmony_ci } 54062306a36Sopenharmony_ci } 54162306a36Sopenharmony_ci if (version_minor >= 1) 54262306a36Sopenharmony_ci amdgpu_gfx_rlc_init_microcode_v2_1(adev); 54362306a36Sopenharmony_ci if (version_minor >= 2) 54462306a36Sopenharmony_ci amdgpu_gfx_rlc_init_microcode_v2_2(adev); 54562306a36Sopenharmony_ci if (version_minor == 3) 54662306a36Sopenharmony_ci amdgpu_gfx_rlc_init_microcode_v2_3(adev); 54762306a36Sopenharmony_ci if (version_minor == 4) 54862306a36Sopenharmony_ci amdgpu_gfx_rlc_init_microcode_v2_4(adev); 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci return 0; 55162306a36Sopenharmony_ci} 552