188dfc9a3SLikun Gao /* 288dfc9a3SLikun Gao * Copyright 2014 Advanced Micro Devices, Inc. 388dfc9a3SLikun Gao * Copyright 2008 Red Hat Inc. 488dfc9a3SLikun Gao * Copyright 2009 Jerome Glisse. 588dfc9a3SLikun Gao * 688dfc9a3SLikun Gao * Permission is hereby granted, free of charge, to any person obtaining a 788dfc9a3SLikun Gao * copy of this software and associated documentation files (the "Software"), 888dfc9a3SLikun Gao * to deal in the Software without restriction, including without limitation 988dfc9a3SLikun Gao * the rights to use, copy, modify, merge, publish, distribute, sublicense, 1088dfc9a3SLikun Gao * and/or sell copies of the Software, and to permit persons to whom the 1188dfc9a3SLikun Gao * Software is furnished to do so, subject to the following conditions: 1288dfc9a3SLikun Gao * 1388dfc9a3SLikun Gao * The above copyright notice and this permission notice shall be included in 1488dfc9a3SLikun Gao * all copies or substantial portions of the Software. 1588dfc9a3SLikun Gao * 1688dfc9a3SLikun Gao * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1788dfc9a3SLikun Gao * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1888dfc9a3SLikun Gao * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1988dfc9a3SLikun Gao * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 2088dfc9a3SLikun Gao * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 2188dfc9a3SLikun Gao * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 2288dfc9a3SLikun Gao * OTHER DEALINGS IN THE SOFTWARE. 2388dfc9a3SLikun Gao * 2488dfc9a3SLikun Gao */ 25106c7d61SLikun Gao #include <linux/firmware.h> 2688dfc9a3SLikun Gao #include "amdgpu.h" 2788dfc9a3SLikun Gao #include "amdgpu_gfx.h" 2888dfc9a3SLikun Gao #include "amdgpu_rlc.h" 2988dfc9a3SLikun Gao 3088dfc9a3SLikun Gao /** 31106c7d61SLikun Gao * amdgpu_gfx_rlc_enter_safe_mode - Set RLC into safe mode 32106c7d61SLikun Gao * 33106c7d61SLikun Gao * @adev: amdgpu_device pointer 34*ca2943feSSrinivasan Shanmugam * @xcc_id: xcc accelerated compute core id 35106c7d61SLikun Gao * 36106c7d61SLikun Gao * Set RLC enter into safe mode if RLC is enabled and haven't in safe mode. 37106c7d61SLikun Gao */ 3886b20703SLe Ma void amdgpu_gfx_rlc_enter_safe_mode(struct amdgpu_device *adev, int xcc_id) 39106c7d61SLikun Gao { 4086b20703SLe Ma if (adev->gfx.rlc.in_safe_mode[xcc_id]) 41106c7d61SLikun Gao return; 42106c7d61SLikun Gao 43106c7d61SLikun Gao /* if RLC is not enabled, do nothing */ 44106c7d61SLikun Gao if (!adev->gfx.rlc.funcs->is_rlc_enabled(adev)) 45106c7d61SLikun Gao return; 46106c7d61SLikun Gao 47106c7d61SLikun Gao if (adev->cg_flags & 48106c7d61SLikun Gao (AMD_CG_SUPPORT_GFX_CGCG | AMD_CG_SUPPORT_GFX_MGCG | 49106c7d61SLikun Gao AMD_CG_SUPPORT_GFX_3D_CGCG)) { 5086b20703SLe Ma adev->gfx.rlc.funcs->set_safe_mode(adev, xcc_id); 5186b20703SLe Ma adev->gfx.rlc.in_safe_mode[xcc_id] = true; 52106c7d61SLikun Gao } 53106c7d61SLikun Gao } 54106c7d61SLikun Gao 55106c7d61SLikun Gao /** 56106c7d61SLikun Gao * amdgpu_gfx_rlc_exit_safe_mode - Set RLC out of safe mode 57106c7d61SLikun Gao * 58106c7d61SLikun Gao * @adev: amdgpu_device pointer 59*ca2943feSSrinivasan Shanmugam * @xcc_id: xcc accelerated compute core id 60106c7d61SLikun Gao * 61106c7d61SLikun Gao * Set RLC exit safe mode if RLC is enabled and have entered into safe mode. 62106c7d61SLikun Gao */ 6386b20703SLe Ma void amdgpu_gfx_rlc_exit_safe_mode(struct amdgpu_device *adev, int xcc_id) 64106c7d61SLikun Gao { 6586b20703SLe Ma if (!(adev->gfx.rlc.in_safe_mode[xcc_id])) 66106c7d61SLikun Gao return; 67106c7d61SLikun Gao 68106c7d61SLikun Gao /* if RLC is not enabled, do nothing */ 69106c7d61SLikun Gao if (!adev->gfx.rlc.funcs->is_rlc_enabled(adev)) 70106c7d61SLikun Gao return; 71106c7d61SLikun Gao 72106c7d61SLikun Gao if (adev->cg_flags & 73106c7d61SLikun Gao (AMD_CG_SUPPORT_GFX_CGCG | AMD_CG_SUPPORT_GFX_MGCG | 74106c7d61SLikun Gao AMD_CG_SUPPORT_GFX_3D_CGCG)) { 7586b20703SLe Ma adev->gfx.rlc.funcs->unset_safe_mode(adev, xcc_id); 7686b20703SLe Ma adev->gfx.rlc.in_safe_mode[xcc_id] = false; 77106c7d61SLikun Gao } 78106c7d61SLikun Gao } 79106c7d61SLikun Gao 80106c7d61SLikun Gao /** 81106c7d61SLikun Gao * amdgpu_gfx_rlc_init_sr - Init save restore block 82106c7d61SLikun Gao * 83106c7d61SLikun Gao * @adev: amdgpu_device pointer 84106c7d61SLikun Gao * @dws: the size of save restore block 85106c7d61SLikun Gao * 86106c7d61SLikun Gao * Allocate and setup value to save restore block of rlc. 87106c7d61SLikun Gao * Returns 0 on succeess or negative error code if allocate failed. 88106c7d61SLikun Gao */ 89106c7d61SLikun Gao int amdgpu_gfx_rlc_init_sr(struct amdgpu_device *adev, u32 dws) 90106c7d61SLikun Gao { 91106c7d61SLikun Gao const u32 *src_ptr; 92106c7d61SLikun Gao volatile u32 *dst_ptr; 93106c7d61SLikun Gao u32 i; 94106c7d61SLikun Gao int r; 95106c7d61SLikun Gao 96106c7d61SLikun Gao /* allocate save restore block */ 97106c7d61SLikun Gao r = amdgpu_bo_create_reserved(adev, dws * 4, PAGE_SIZE, 9858ab2c08SChristian König AMDGPU_GEM_DOMAIN_VRAM | 9958ab2c08SChristian König AMDGPU_GEM_DOMAIN_GTT, 100106c7d61SLikun Gao &adev->gfx.rlc.save_restore_obj, 101106c7d61SLikun Gao &adev->gfx.rlc.save_restore_gpu_addr, 102106c7d61SLikun Gao (void **)&adev->gfx.rlc.sr_ptr); 103106c7d61SLikun Gao if (r) { 104106c7d61SLikun Gao dev_warn(adev->dev, "(%d) create RLC sr bo failed\n", r); 105106c7d61SLikun Gao amdgpu_gfx_rlc_fini(adev); 106106c7d61SLikun Gao return r; 107106c7d61SLikun Gao } 108106c7d61SLikun Gao 109106c7d61SLikun Gao /* write the sr buffer */ 110106c7d61SLikun Gao src_ptr = adev->gfx.rlc.reg_list; 111106c7d61SLikun Gao dst_ptr = adev->gfx.rlc.sr_ptr; 112106c7d61SLikun Gao for (i = 0; i < adev->gfx.rlc.reg_list_size; i++) 113106c7d61SLikun Gao dst_ptr[i] = cpu_to_le32(src_ptr[i]); 114106c7d61SLikun Gao amdgpu_bo_kunmap(adev->gfx.rlc.save_restore_obj); 115106c7d61SLikun Gao amdgpu_bo_unreserve(adev->gfx.rlc.save_restore_obj); 116106c7d61SLikun Gao 117106c7d61SLikun Gao return 0; 118106c7d61SLikun Gao } 119106c7d61SLikun Gao 120106c7d61SLikun Gao /** 121106c7d61SLikun Gao * amdgpu_gfx_rlc_init_csb - Init clear state block 122106c7d61SLikun Gao * 123106c7d61SLikun Gao * @adev: amdgpu_device pointer 124106c7d61SLikun Gao * 125106c7d61SLikun Gao * Allocate and setup value to clear state block of rlc. 126106c7d61SLikun Gao * Returns 0 on succeess or negative error code if allocate failed. 127106c7d61SLikun Gao */ 128106c7d61SLikun Gao int amdgpu_gfx_rlc_init_csb(struct amdgpu_device *adev) 129106c7d61SLikun Gao { 130106c7d61SLikun Gao u32 dws; 131106c7d61SLikun Gao int r; 132106c7d61SLikun Gao 133106c7d61SLikun Gao /* allocate clear state block */ 134106c7d61SLikun Gao adev->gfx.rlc.clear_state_size = dws = adev->gfx.rlc.funcs->get_csb_size(adev); 135747d4f71SMonk Liu r = amdgpu_bo_create_kernel(adev, dws * 4, PAGE_SIZE, 13658ab2c08SChristian König AMDGPU_GEM_DOMAIN_VRAM | 13758ab2c08SChristian König AMDGPU_GEM_DOMAIN_GTT, 138106c7d61SLikun Gao &adev->gfx.rlc.clear_state_obj, 139106c7d61SLikun Gao &adev->gfx.rlc.clear_state_gpu_addr, 140106c7d61SLikun Gao (void **)&adev->gfx.rlc.cs_ptr); 141106c7d61SLikun Gao if (r) { 142106c7d61SLikun Gao dev_err(adev->dev, "(%d) failed to create rlc csb bo\n", r); 143106c7d61SLikun Gao amdgpu_gfx_rlc_fini(adev); 144106c7d61SLikun Gao return r; 145106c7d61SLikun Gao } 146106c7d61SLikun Gao 147106c7d61SLikun Gao return 0; 148106c7d61SLikun Gao } 149106c7d61SLikun Gao 150106c7d61SLikun Gao /** 151106c7d61SLikun Gao * amdgpu_gfx_rlc_init_cpt - Init cp table 152106c7d61SLikun Gao * 153106c7d61SLikun Gao * @adev: amdgpu_device pointer 154106c7d61SLikun Gao * 155106c7d61SLikun Gao * Allocate and setup value to cp table of rlc. 156106c7d61SLikun Gao * Returns 0 on succeess or negative error code if allocate failed. 157106c7d61SLikun Gao */ 158106c7d61SLikun Gao int amdgpu_gfx_rlc_init_cpt(struct amdgpu_device *adev) 159106c7d61SLikun Gao { 160106c7d61SLikun Gao int r; 161106c7d61SLikun Gao 162106c7d61SLikun Gao r = amdgpu_bo_create_reserved(adev, adev->gfx.rlc.cp_table_size, 16358ab2c08SChristian König PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM | 16458ab2c08SChristian König AMDGPU_GEM_DOMAIN_GTT, 165106c7d61SLikun Gao &adev->gfx.rlc.cp_table_obj, 166106c7d61SLikun Gao &adev->gfx.rlc.cp_table_gpu_addr, 167106c7d61SLikun Gao (void **)&adev->gfx.rlc.cp_table_ptr); 168106c7d61SLikun Gao if (r) { 169106c7d61SLikun Gao dev_err(adev->dev, "(%d) failed to create cp table bo\n", r); 170106c7d61SLikun Gao amdgpu_gfx_rlc_fini(adev); 171106c7d61SLikun Gao return r; 172106c7d61SLikun Gao } 173106c7d61SLikun Gao 174106c7d61SLikun Gao /* set up the cp table */ 175106c7d61SLikun Gao amdgpu_gfx_rlc_setup_cp_table(adev); 176106c7d61SLikun Gao amdgpu_bo_kunmap(adev->gfx.rlc.cp_table_obj); 177106c7d61SLikun Gao amdgpu_bo_unreserve(adev->gfx.rlc.cp_table_obj); 178106c7d61SLikun Gao 179106c7d61SLikun Gao return 0; 180106c7d61SLikun Gao } 181106c7d61SLikun Gao 182106c7d61SLikun Gao /** 183106c7d61SLikun Gao * amdgpu_gfx_rlc_setup_cp_table - setup cp the buffer of cp table 184106c7d61SLikun Gao * 185106c7d61SLikun Gao * @adev: amdgpu_device pointer 186106c7d61SLikun Gao * 187106c7d61SLikun Gao * Write cp firmware data into cp table. 188106c7d61SLikun Gao */ 189106c7d61SLikun Gao void amdgpu_gfx_rlc_setup_cp_table(struct amdgpu_device *adev) 190106c7d61SLikun Gao { 191106c7d61SLikun Gao const __le32 *fw_data; 192106c7d61SLikun Gao volatile u32 *dst_ptr; 193106c7d61SLikun Gao int me, i, max_me; 194106c7d61SLikun Gao u32 bo_offset = 0; 195106c7d61SLikun Gao u32 table_offset, table_size; 196106c7d61SLikun Gao 197106c7d61SLikun Gao max_me = adev->gfx.rlc.funcs->get_cp_table_num(adev); 198106c7d61SLikun Gao 199106c7d61SLikun Gao /* write the cp table buffer */ 200106c7d61SLikun Gao dst_ptr = adev->gfx.rlc.cp_table_ptr; 201106c7d61SLikun Gao for (me = 0; me < max_me; me++) { 202106c7d61SLikun Gao if (me == 0) { 203106c7d61SLikun Gao const struct gfx_firmware_header_v1_0 *hdr = 204106c7d61SLikun Gao (const struct gfx_firmware_header_v1_0 *)adev->gfx.ce_fw->data; 205106c7d61SLikun Gao fw_data = (const __le32 *) 206106c7d61SLikun Gao (adev->gfx.ce_fw->data + 207106c7d61SLikun Gao le32_to_cpu(hdr->header.ucode_array_offset_bytes)); 208106c7d61SLikun Gao table_offset = le32_to_cpu(hdr->jt_offset); 209106c7d61SLikun Gao table_size = le32_to_cpu(hdr->jt_size); 210106c7d61SLikun Gao } else if (me == 1) { 211106c7d61SLikun Gao const struct gfx_firmware_header_v1_0 *hdr = 212106c7d61SLikun Gao (const struct gfx_firmware_header_v1_0 *)adev->gfx.pfp_fw->data; 213106c7d61SLikun Gao fw_data = (const __le32 *) 214106c7d61SLikun Gao (adev->gfx.pfp_fw->data + 215106c7d61SLikun Gao le32_to_cpu(hdr->header.ucode_array_offset_bytes)); 216106c7d61SLikun Gao table_offset = le32_to_cpu(hdr->jt_offset); 217106c7d61SLikun Gao table_size = le32_to_cpu(hdr->jt_size); 218106c7d61SLikun Gao } else if (me == 2) { 219106c7d61SLikun Gao const struct gfx_firmware_header_v1_0 *hdr = 220106c7d61SLikun Gao (const struct gfx_firmware_header_v1_0 *)adev->gfx.me_fw->data; 221106c7d61SLikun Gao fw_data = (const __le32 *) 222106c7d61SLikun Gao (adev->gfx.me_fw->data + 223106c7d61SLikun Gao le32_to_cpu(hdr->header.ucode_array_offset_bytes)); 224106c7d61SLikun Gao table_offset = le32_to_cpu(hdr->jt_offset); 225106c7d61SLikun Gao table_size = le32_to_cpu(hdr->jt_size); 226106c7d61SLikun Gao } else if (me == 3) { 227106c7d61SLikun Gao const struct gfx_firmware_header_v1_0 *hdr = 228106c7d61SLikun Gao (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec_fw->data; 229106c7d61SLikun Gao fw_data = (const __le32 *) 230106c7d61SLikun Gao (adev->gfx.mec_fw->data + 231106c7d61SLikun Gao le32_to_cpu(hdr->header.ucode_array_offset_bytes)); 232106c7d61SLikun Gao table_offset = le32_to_cpu(hdr->jt_offset); 233106c7d61SLikun Gao table_size = le32_to_cpu(hdr->jt_size); 234106c7d61SLikun Gao } else if (me == 4) { 235106c7d61SLikun Gao const struct gfx_firmware_header_v1_0 *hdr = 236106c7d61SLikun Gao (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec2_fw->data; 237106c7d61SLikun Gao fw_data = (const __le32 *) 238106c7d61SLikun Gao (adev->gfx.mec2_fw->data + 239106c7d61SLikun Gao le32_to_cpu(hdr->header.ucode_array_offset_bytes)); 240106c7d61SLikun Gao table_offset = le32_to_cpu(hdr->jt_offset); 241106c7d61SLikun Gao table_size = le32_to_cpu(hdr->jt_size); 242106c7d61SLikun Gao } 243106c7d61SLikun Gao 244106c7d61SLikun Gao for (i = 0; i < table_size; i ++) { 245106c7d61SLikun Gao dst_ptr[bo_offset + i] = 246106c7d61SLikun Gao cpu_to_le32(le32_to_cpu(fw_data[table_offset + i])); 247106c7d61SLikun Gao } 248106c7d61SLikun Gao 249106c7d61SLikun Gao bo_offset += table_size; 250106c7d61SLikun Gao } 251106c7d61SLikun Gao } 252106c7d61SLikun Gao 253106c7d61SLikun Gao /** 25488dfc9a3SLikun Gao * amdgpu_gfx_rlc_fini - Free BO which used for RLC 25588dfc9a3SLikun Gao * 25688dfc9a3SLikun Gao * @adev: amdgpu_device pointer 25788dfc9a3SLikun Gao * 25888dfc9a3SLikun Gao * Free three BO which is used for rlc_save_restore_block, rlc_clear_state_block 25988dfc9a3SLikun Gao * and rlc_jump_table_block. 26088dfc9a3SLikun Gao */ 26188dfc9a3SLikun Gao void amdgpu_gfx_rlc_fini(struct amdgpu_device *adev) 26288dfc9a3SLikun Gao { 26388dfc9a3SLikun Gao /* save restore block */ 26488dfc9a3SLikun Gao if (adev->gfx.rlc.save_restore_obj) { 26588dfc9a3SLikun Gao amdgpu_bo_free_kernel(&adev->gfx.rlc.save_restore_obj, 26688dfc9a3SLikun Gao &adev->gfx.rlc.save_restore_gpu_addr, 26788dfc9a3SLikun Gao (void **)&adev->gfx.rlc.sr_ptr); 26888dfc9a3SLikun Gao } 26988dfc9a3SLikun Gao 27088dfc9a3SLikun Gao /* clear state block */ 27188dfc9a3SLikun Gao amdgpu_bo_free_kernel(&adev->gfx.rlc.clear_state_obj, 27288dfc9a3SLikun Gao &adev->gfx.rlc.clear_state_gpu_addr, 27388dfc9a3SLikun Gao (void **)&adev->gfx.rlc.cs_ptr); 27488dfc9a3SLikun Gao 27588dfc9a3SLikun Gao /* jump table block */ 27688dfc9a3SLikun Gao amdgpu_bo_free_kernel(&adev->gfx.rlc.cp_table_obj, 27788dfc9a3SLikun Gao &adev->gfx.rlc.cp_table_gpu_addr, 27888dfc9a3SLikun Gao (void **)&adev->gfx.rlc.cp_table_ptr); 27988dfc9a3SLikun Gao } 2800641dbefSHawking Zhang 2810641dbefSHawking Zhang static int amdgpu_gfx_rlc_init_microcode_v2_0(struct amdgpu_device *adev) 2820641dbefSHawking Zhang { 2830641dbefSHawking Zhang const struct common_firmware_header *common_hdr; 2840641dbefSHawking Zhang const struct rlc_firmware_header_v2_0 *rlc_hdr; 2850641dbefSHawking Zhang struct amdgpu_firmware_info *info; 2860641dbefSHawking Zhang unsigned int *tmp; 2870641dbefSHawking Zhang unsigned int i; 2880641dbefSHawking Zhang 2890641dbefSHawking Zhang rlc_hdr = (const struct rlc_firmware_header_v2_0 *)adev->gfx.rlc_fw->data; 2900641dbefSHawking Zhang 2910641dbefSHawking Zhang adev->gfx.rlc_fw_version = le32_to_cpu(rlc_hdr->header.ucode_version); 2920641dbefSHawking Zhang adev->gfx.rlc_feature_version = le32_to_cpu(rlc_hdr->ucode_feature_version); 2930641dbefSHawking Zhang adev->gfx.rlc.save_and_restore_offset = 2940641dbefSHawking Zhang le32_to_cpu(rlc_hdr->save_and_restore_offset); 2950641dbefSHawking Zhang adev->gfx.rlc.clear_state_descriptor_offset = 2960641dbefSHawking Zhang le32_to_cpu(rlc_hdr->clear_state_descriptor_offset); 2970641dbefSHawking Zhang adev->gfx.rlc.avail_scratch_ram_locations = 2980641dbefSHawking Zhang le32_to_cpu(rlc_hdr->avail_scratch_ram_locations); 2990641dbefSHawking Zhang adev->gfx.rlc.reg_restore_list_size = 3000641dbefSHawking Zhang le32_to_cpu(rlc_hdr->reg_restore_list_size); 3010641dbefSHawking Zhang adev->gfx.rlc.reg_list_format_start = 3020641dbefSHawking Zhang le32_to_cpu(rlc_hdr->reg_list_format_start); 3030641dbefSHawking Zhang adev->gfx.rlc.reg_list_format_separate_start = 3040641dbefSHawking Zhang le32_to_cpu(rlc_hdr->reg_list_format_separate_start); 3050641dbefSHawking Zhang adev->gfx.rlc.starting_offsets_start = 3060641dbefSHawking Zhang le32_to_cpu(rlc_hdr->starting_offsets_start); 3070641dbefSHawking Zhang adev->gfx.rlc.reg_list_format_size_bytes = 3080641dbefSHawking Zhang le32_to_cpu(rlc_hdr->reg_list_format_size_bytes); 3090641dbefSHawking Zhang adev->gfx.rlc.reg_list_size_bytes = 3100641dbefSHawking Zhang le32_to_cpu(rlc_hdr->reg_list_size_bytes); 3110641dbefSHawking Zhang adev->gfx.rlc.register_list_format = 3120641dbefSHawking Zhang kmalloc(adev->gfx.rlc.reg_list_format_size_bytes + 3130641dbefSHawking Zhang adev->gfx.rlc.reg_list_size_bytes, GFP_KERNEL); 3140641dbefSHawking Zhang if (!adev->gfx.rlc.register_list_format) { 3150641dbefSHawking Zhang dev_err(adev->dev, "failed to allocate memory for rlc register_list_format\n"); 3160641dbefSHawking Zhang return -ENOMEM; 3170641dbefSHawking Zhang } 3180641dbefSHawking Zhang 3190641dbefSHawking Zhang tmp = (unsigned int *)((uintptr_t)rlc_hdr + 3200641dbefSHawking Zhang le32_to_cpu(rlc_hdr->reg_list_format_array_offset_bytes)); 3210641dbefSHawking Zhang for (i = 0 ; i < (rlc_hdr->reg_list_format_size_bytes >> 2); i++) 3220641dbefSHawking Zhang adev->gfx.rlc.register_list_format[i] = le32_to_cpu(tmp[i]); 3230641dbefSHawking Zhang 3240641dbefSHawking Zhang adev->gfx.rlc.register_restore = adev->gfx.rlc.register_list_format + i; 3250641dbefSHawking Zhang 3260641dbefSHawking Zhang tmp = (unsigned int *)((uintptr_t)rlc_hdr + 3270641dbefSHawking Zhang le32_to_cpu(rlc_hdr->reg_list_array_offset_bytes)); 3280641dbefSHawking Zhang for (i = 0 ; i < (rlc_hdr->reg_list_size_bytes >> 2); i++) 3290641dbefSHawking Zhang adev->gfx.rlc.register_restore[i] = le32_to_cpu(tmp[i]); 3300641dbefSHawking Zhang 3310641dbefSHawking Zhang if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { 3320641dbefSHawking Zhang info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_G]; 3330641dbefSHawking Zhang info->ucode_id = AMDGPU_UCODE_ID_RLC_G; 3340641dbefSHawking Zhang info->fw = adev->gfx.rlc_fw; 3350641dbefSHawking Zhang if (info->fw) { 3360641dbefSHawking Zhang common_hdr = (const struct common_firmware_header *)info->fw->data; 3370641dbefSHawking Zhang adev->firmware.fw_size += 3380641dbefSHawking Zhang ALIGN(le32_to_cpu(common_hdr->ucode_size_bytes), PAGE_SIZE); 3390641dbefSHawking Zhang } 3400641dbefSHawking Zhang } 3410641dbefSHawking Zhang 3420641dbefSHawking Zhang return 0; 3430641dbefSHawking Zhang } 344f3e6173bSHawking Zhang 345f3e6173bSHawking Zhang static void amdgpu_gfx_rlc_init_microcode_v2_1(struct amdgpu_device *adev) 346f3e6173bSHawking Zhang { 347f3e6173bSHawking Zhang const struct rlc_firmware_header_v2_1 *rlc_hdr; 348f3e6173bSHawking Zhang struct amdgpu_firmware_info *info; 349f3e6173bSHawking Zhang 350f3e6173bSHawking Zhang rlc_hdr = (const struct rlc_firmware_header_v2_1 *)adev->gfx.rlc_fw->data; 351f3e6173bSHawking Zhang adev->gfx.rlc_srlc_fw_version = le32_to_cpu(rlc_hdr->save_restore_list_cntl_ucode_ver); 352f3e6173bSHawking Zhang adev->gfx.rlc_srlc_feature_version = le32_to_cpu(rlc_hdr->save_restore_list_cntl_feature_ver); 353f3e6173bSHawking Zhang adev->gfx.rlc.save_restore_list_cntl_size_bytes = le32_to_cpu(rlc_hdr->save_restore_list_cntl_size_bytes); 354f3e6173bSHawking Zhang adev->gfx.rlc.save_restore_list_cntl = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->save_restore_list_cntl_offset_bytes); 355f3e6173bSHawking Zhang adev->gfx.rlc_srlg_fw_version = le32_to_cpu(rlc_hdr->save_restore_list_gpm_ucode_ver); 356f3e6173bSHawking Zhang adev->gfx.rlc_srlg_feature_version = le32_to_cpu(rlc_hdr->save_restore_list_gpm_feature_ver); 357f3e6173bSHawking Zhang adev->gfx.rlc.save_restore_list_gpm_size_bytes = le32_to_cpu(rlc_hdr->save_restore_list_gpm_size_bytes); 358f3e6173bSHawking Zhang adev->gfx.rlc.save_restore_list_gpm = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->save_restore_list_gpm_offset_bytes); 359f3e6173bSHawking Zhang adev->gfx.rlc_srls_fw_version = le32_to_cpu(rlc_hdr->save_restore_list_srm_ucode_ver); 360f3e6173bSHawking Zhang adev->gfx.rlc_srls_feature_version = le32_to_cpu(rlc_hdr->save_restore_list_srm_feature_ver); 361f3e6173bSHawking Zhang adev->gfx.rlc.save_restore_list_srm_size_bytes = le32_to_cpu(rlc_hdr->save_restore_list_srm_size_bytes); 362f3e6173bSHawking Zhang adev->gfx.rlc.save_restore_list_srm = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->save_restore_list_srm_offset_bytes); 363f3e6173bSHawking Zhang adev->gfx.rlc.reg_list_format_direct_reg_list_length = 364f3e6173bSHawking Zhang le32_to_cpu(rlc_hdr->reg_list_format_direct_reg_list_length); 365f3e6173bSHawking Zhang 366f3e6173bSHawking Zhang if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { 367940d4dd4SHawking Zhang if (adev->gfx.rlc.save_restore_list_cntl_size_bytes) { 368940d4dd4SHawking Zhang info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_RESTORE_LIST_CNTL]; 369940d4dd4SHawking Zhang info->ucode_id = AMDGPU_UCODE_ID_RLC_RESTORE_LIST_CNTL; 370940d4dd4SHawking Zhang info->fw = adev->gfx.rlc_fw; 371940d4dd4SHawking Zhang adev->firmware.fw_size += 372940d4dd4SHawking Zhang ALIGN(adev->gfx.rlc.save_restore_list_cntl_size_bytes, PAGE_SIZE); 373940d4dd4SHawking Zhang } 374940d4dd4SHawking Zhang 375f3e6173bSHawking Zhang if (adev->gfx.rlc.save_restore_list_gpm_size_bytes) { 376f3e6173bSHawking Zhang info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_RESTORE_LIST_GPM_MEM]; 377f3e6173bSHawking Zhang info->ucode_id = AMDGPU_UCODE_ID_RLC_RESTORE_LIST_GPM_MEM; 378f3e6173bSHawking Zhang info->fw = adev->gfx.rlc_fw; 379f3e6173bSHawking Zhang adev->firmware.fw_size += 380f3e6173bSHawking Zhang ALIGN(adev->gfx.rlc.save_restore_list_gpm_size_bytes, PAGE_SIZE); 381f3e6173bSHawking Zhang } 382f3e6173bSHawking Zhang 383f3e6173bSHawking Zhang if (adev->gfx.rlc.save_restore_list_srm_size_bytes) { 384f3e6173bSHawking Zhang info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_RESTORE_LIST_SRM_MEM]; 385f3e6173bSHawking Zhang info->ucode_id = AMDGPU_UCODE_ID_RLC_RESTORE_LIST_SRM_MEM; 386f3e6173bSHawking Zhang info->fw = adev->gfx.rlc_fw; 387f3e6173bSHawking Zhang adev->firmware.fw_size += 388f3e6173bSHawking Zhang ALIGN(adev->gfx.rlc.save_restore_list_srm_size_bytes, PAGE_SIZE); 389f3e6173bSHawking Zhang } 390f3e6173bSHawking Zhang } 391f3e6173bSHawking Zhang } 392a97d0ec8SHawking Zhang 393a97d0ec8SHawking Zhang static void amdgpu_gfx_rlc_init_microcode_v2_2(struct amdgpu_device *adev) 394a97d0ec8SHawking Zhang { 395a97d0ec8SHawking Zhang const struct rlc_firmware_header_v2_2 *rlc_hdr; 396a97d0ec8SHawking Zhang struct amdgpu_firmware_info *info; 397a97d0ec8SHawking Zhang 398a97d0ec8SHawking Zhang rlc_hdr = (const struct rlc_firmware_header_v2_2 *)adev->gfx.rlc_fw->data; 399a97d0ec8SHawking Zhang adev->gfx.rlc.rlc_iram_ucode_size_bytes = le32_to_cpu(rlc_hdr->rlc_iram_ucode_size_bytes); 400a97d0ec8SHawking Zhang adev->gfx.rlc.rlc_iram_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->rlc_iram_ucode_offset_bytes); 401a97d0ec8SHawking Zhang adev->gfx.rlc.rlc_dram_ucode_size_bytes = le32_to_cpu(rlc_hdr->rlc_dram_ucode_size_bytes); 402a97d0ec8SHawking Zhang adev->gfx.rlc.rlc_dram_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->rlc_dram_ucode_offset_bytes); 403a97d0ec8SHawking Zhang 404a97d0ec8SHawking Zhang if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { 405a97d0ec8SHawking Zhang if (adev->gfx.rlc.rlc_iram_ucode_size_bytes) { 406a97d0ec8SHawking Zhang info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_IRAM]; 407a97d0ec8SHawking Zhang info->ucode_id = AMDGPU_UCODE_ID_RLC_IRAM; 408a97d0ec8SHawking Zhang info->fw = adev->gfx.rlc_fw; 409a97d0ec8SHawking Zhang adev->firmware.fw_size += 410a97d0ec8SHawking Zhang ALIGN(adev->gfx.rlc.rlc_iram_ucode_size_bytes, PAGE_SIZE); 411a97d0ec8SHawking Zhang } 412a97d0ec8SHawking Zhang 413a97d0ec8SHawking Zhang if (adev->gfx.rlc.rlc_dram_ucode_size_bytes) { 414a97d0ec8SHawking Zhang info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_DRAM]; 415a97d0ec8SHawking Zhang info->ucode_id = AMDGPU_UCODE_ID_RLC_DRAM; 416a97d0ec8SHawking Zhang info->fw = adev->gfx.rlc_fw; 417a97d0ec8SHawking Zhang adev->firmware.fw_size += 418a97d0ec8SHawking Zhang ALIGN(adev->gfx.rlc.rlc_dram_ucode_size_bytes, PAGE_SIZE); 419a97d0ec8SHawking Zhang } 420a97d0ec8SHawking Zhang } 421a97d0ec8SHawking Zhang } 422a0d9084dSHawking Zhang 423a0d9084dSHawking Zhang static void amdgpu_gfx_rlc_init_microcode_v2_3(struct amdgpu_device *adev) 424a0d9084dSHawking Zhang { 425a0d9084dSHawking Zhang const struct rlc_firmware_header_v2_3 *rlc_hdr; 426a0d9084dSHawking Zhang struct amdgpu_firmware_info *info; 427a0d9084dSHawking Zhang 428a0d9084dSHawking Zhang rlc_hdr = (const struct rlc_firmware_header_v2_3 *)adev->gfx.rlc_fw->data; 429a0d9084dSHawking Zhang adev->gfx.rlcp_ucode_version = le32_to_cpu(rlc_hdr->rlcp_ucode_version); 430a0d9084dSHawking Zhang adev->gfx.rlcp_ucode_feature_version = le32_to_cpu(rlc_hdr->rlcp_ucode_feature_version); 431a0d9084dSHawking Zhang adev->gfx.rlc.rlcp_ucode_size_bytes = le32_to_cpu(rlc_hdr->rlcp_ucode_size_bytes); 432a0d9084dSHawking Zhang adev->gfx.rlc.rlcp_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->rlcp_ucode_offset_bytes); 433a0d9084dSHawking Zhang 434a0d9084dSHawking Zhang adev->gfx.rlcv_ucode_version = le32_to_cpu(rlc_hdr->rlcv_ucode_version); 435a0d9084dSHawking Zhang adev->gfx.rlcv_ucode_feature_version = le32_to_cpu(rlc_hdr->rlcv_ucode_feature_version); 436a0d9084dSHawking Zhang adev->gfx.rlc.rlcv_ucode_size_bytes = le32_to_cpu(rlc_hdr->rlcv_ucode_size_bytes); 437a0d9084dSHawking Zhang adev->gfx.rlc.rlcv_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->rlcv_ucode_offset_bytes); 438a0d9084dSHawking Zhang 439a0d9084dSHawking Zhang if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { 440a0d9084dSHawking Zhang if (adev->gfx.rlc.rlcp_ucode_size_bytes) { 441a0d9084dSHawking Zhang info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_P]; 442a0d9084dSHawking Zhang info->ucode_id = AMDGPU_UCODE_ID_RLC_P; 443a0d9084dSHawking Zhang info->fw = adev->gfx.rlc_fw; 444a0d9084dSHawking Zhang adev->firmware.fw_size += 445a0d9084dSHawking Zhang ALIGN(adev->gfx.rlc.rlcp_ucode_size_bytes, PAGE_SIZE); 446a0d9084dSHawking Zhang } 447a0d9084dSHawking Zhang 448a0d9084dSHawking Zhang if (adev->gfx.rlc.rlcv_ucode_size_bytes) { 449a0d9084dSHawking Zhang info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_V]; 450a0d9084dSHawking Zhang info->ucode_id = AMDGPU_UCODE_ID_RLC_V; 451a0d9084dSHawking Zhang info->fw = adev->gfx.rlc_fw; 452a0d9084dSHawking Zhang adev->firmware.fw_size += 453a0d9084dSHawking Zhang ALIGN(adev->gfx.rlc.rlcv_ucode_size_bytes, PAGE_SIZE); 454a0d9084dSHawking Zhang } 455a0d9084dSHawking Zhang } 456a0d9084dSHawking Zhang } 457435d6e6fSHawking Zhang 458435d6e6fSHawking Zhang static void amdgpu_gfx_rlc_init_microcode_v2_4(struct amdgpu_device *adev) 459435d6e6fSHawking Zhang { 460435d6e6fSHawking Zhang const struct rlc_firmware_header_v2_4 *rlc_hdr; 461435d6e6fSHawking Zhang struct amdgpu_firmware_info *info; 462435d6e6fSHawking Zhang 463435d6e6fSHawking Zhang rlc_hdr = (const struct rlc_firmware_header_v2_4 *)adev->gfx.rlc_fw->data; 464435d6e6fSHawking Zhang adev->gfx.rlc.global_tap_delays_ucode_size_bytes = le32_to_cpu(rlc_hdr->global_tap_delays_ucode_size_bytes); 465435d6e6fSHawking Zhang adev->gfx.rlc.global_tap_delays_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->global_tap_delays_ucode_offset_bytes); 466435d6e6fSHawking Zhang adev->gfx.rlc.se0_tap_delays_ucode_size_bytes = le32_to_cpu(rlc_hdr->se0_tap_delays_ucode_size_bytes); 467435d6e6fSHawking Zhang adev->gfx.rlc.se0_tap_delays_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->se0_tap_delays_ucode_offset_bytes); 468435d6e6fSHawking Zhang adev->gfx.rlc.se1_tap_delays_ucode_size_bytes = le32_to_cpu(rlc_hdr->se1_tap_delays_ucode_size_bytes); 469435d6e6fSHawking Zhang adev->gfx.rlc.se1_tap_delays_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->se1_tap_delays_ucode_offset_bytes); 470435d6e6fSHawking Zhang adev->gfx.rlc.se2_tap_delays_ucode_size_bytes = le32_to_cpu(rlc_hdr->se2_tap_delays_ucode_size_bytes); 471435d6e6fSHawking Zhang adev->gfx.rlc.se2_tap_delays_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->se2_tap_delays_ucode_offset_bytes); 472435d6e6fSHawking Zhang adev->gfx.rlc.se3_tap_delays_ucode_size_bytes = le32_to_cpu(rlc_hdr->se3_tap_delays_ucode_size_bytes); 473435d6e6fSHawking Zhang adev->gfx.rlc.se3_tap_delays_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->se3_tap_delays_ucode_offset_bytes); 474435d6e6fSHawking Zhang 475435d6e6fSHawking Zhang if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { 476435d6e6fSHawking Zhang if (adev->gfx.rlc.global_tap_delays_ucode_size_bytes) { 477435d6e6fSHawking Zhang info = &adev->firmware.ucode[AMDGPU_UCODE_ID_GLOBAL_TAP_DELAYS]; 478435d6e6fSHawking Zhang info->ucode_id = AMDGPU_UCODE_ID_GLOBAL_TAP_DELAYS; 479435d6e6fSHawking Zhang info->fw = adev->gfx.rlc_fw; 480435d6e6fSHawking Zhang adev->firmware.fw_size += 481435d6e6fSHawking Zhang ALIGN(adev->gfx.rlc.global_tap_delays_ucode_size_bytes, PAGE_SIZE); 482435d6e6fSHawking Zhang } 483435d6e6fSHawking Zhang 484435d6e6fSHawking Zhang if (adev->gfx.rlc.se0_tap_delays_ucode_size_bytes) { 485435d6e6fSHawking Zhang info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SE0_TAP_DELAYS]; 486435d6e6fSHawking Zhang info->ucode_id = AMDGPU_UCODE_ID_SE0_TAP_DELAYS; 487435d6e6fSHawking Zhang info->fw = adev->gfx.rlc_fw; 488435d6e6fSHawking Zhang adev->firmware.fw_size += 489435d6e6fSHawking Zhang ALIGN(adev->gfx.rlc.se0_tap_delays_ucode_size_bytes, PAGE_SIZE); 490435d6e6fSHawking Zhang } 491435d6e6fSHawking Zhang 492435d6e6fSHawking Zhang if (adev->gfx.rlc.se1_tap_delays_ucode_size_bytes) { 493435d6e6fSHawking Zhang info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SE1_TAP_DELAYS]; 494435d6e6fSHawking Zhang info->ucode_id = AMDGPU_UCODE_ID_SE1_TAP_DELAYS; 495435d6e6fSHawking Zhang info->fw = adev->gfx.rlc_fw; 496435d6e6fSHawking Zhang adev->firmware.fw_size += 497435d6e6fSHawking Zhang ALIGN(adev->gfx.rlc.se1_tap_delays_ucode_size_bytes, PAGE_SIZE); 498435d6e6fSHawking Zhang } 499435d6e6fSHawking Zhang 500435d6e6fSHawking Zhang if (adev->gfx.rlc.se2_tap_delays_ucode_size_bytes) { 501435d6e6fSHawking Zhang info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SE2_TAP_DELAYS]; 502435d6e6fSHawking Zhang info->ucode_id = AMDGPU_UCODE_ID_SE2_TAP_DELAYS; 503435d6e6fSHawking Zhang info->fw = adev->gfx.rlc_fw; 504435d6e6fSHawking Zhang adev->firmware.fw_size += 505435d6e6fSHawking Zhang ALIGN(adev->gfx.rlc.se2_tap_delays_ucode_size_bytes, PAGE_SIZE); 506435d6e6fSHawking Zhang } 507435d6e6fSHawking Zhang 508435d6e6fSHawking Zhang if (adev->gfx.rlc.se3_tap_delays_ucode_size_bytes) { 509435d6e6fSHawking Zhang info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SE3_TAP_DELAYS]; 510435d6e6fSHawking Zhang info->ucode_id = AMDGPU_UCODE_ID_SE3_TAP_DELAYS; 511435d6e6fSHawking Zhang info->fw = adev->gfx.rlc_fw; 512435d6e6fSHawking Zhang adev->firmware.fw_size += 513435d6e6fSHawking Zhang ALIGN(adev->gfx.rlc.se3_tap_delays_ucode_size_bytes, PAGE_SIZE); 514435d6e6fSHawking Zhang } 515435d6e6fSHawking Zhang } 516435d6e6fSHawking Zhang } 5175b415212SHawking Zhang 5185b415212SHawking Zhang int amdgpu_gfx_rlc_init_microcode(struct amdgpu_device *adev, 5195b415212SHawking Zhang uint16_t version_major, 5205b415212SHawking Zhang uint16_t version_minor) 5215b415212SHawking Zhang { 5225b415212SHawking Zhang int err; 5235b415212SHawking Zhang 5245b415212SHawking Zhang if (version_major < 2) { 5255b415212SHawking Zhang /* only support rlc_hdr v2.x and onwards */ 5265b415212SHawking Zhang dev_err(adev->dev, "unsupported rlc fw hdr\n"); 5275b415212SHawking Zhang return -EINVAL; 5285b415212SHawking Zhang } 5295b415212SHawking Zhang 5305b415212SHawking Zhang /* is_rlc_v2_1 is still used in APU code path */ 5315b415212SHawking Zhang if (version_major == 2 && version_minor == 1) 5325b415212SHawking Zhang adev->gfx.rlc.is_rlc_v2_1 = true; 5335b415212SHawking Zhang 5345b415212SHawking Zhang if (version_minor >= 0) { 5355b415212SHawking Zhang err = amdgpu_gfx_rlc_init_microcode_v2_0(adev); 5365b415212SHawking Zhang if (err) { 5375b415212SHawking Zhang dev_err(adev->dev, "fail to init rlc v2_0 microcode\n"); 5385b415212SHawking Zhang return err; 5395b415212SHawking Zhang } 5405b415212SHawking Zhang } 5415b415212SHawking Zhang if (version_minor >= 1) 5425b415212SHawking Zhang amdgpu_gfx_rlc_init_microcode_v2_1(adev); 5435b415212SHawking Zhang if (version_minor >= 2) 5445b415212SHawking Zhang amdgpu_gfx_rlc_init_microcode_v2_2(adev); 5455b415212SHawking Zhang if (version_minor == 3) 5465b415212SHawking Zhang amdgpu_gfx_rlc_init_microcode_v2_3(adev); 5475b415212SHawking Zhang if (version_minor == 4) 5485b415212SHawking Zhang amdgpu_gfx_rlc_init_microcode_v2_4(adev); 5495b415212SHawking Zhang 5505b415212SHawking Zhang return 0; 5515b415212SHawking Zhang } 552