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 34106c7d61SLikun Gao * 35106c7d61SLikun Gao * Set RLC enter into safe mode if RLC is enabled and haven't in safe mode. 36106c7d61SLikun Gao */ 37106c7d61SLikun Gao void amdgpu_gfx_rlc_enter_safe_mode(struct amdgpu_device *adev) 38106c7d61SLikun Gao { 39106c7d61SLikun Gao if (adev->gfx.rlc.in_safe_mode) 40106c7d61SLikun Gao return; 41106c7d61SLikun Gao 42106c7d61SLikun Gao /* if RLC is not enabled, do nothing */ 43106c7d61SLikun Gao if (!adev->gfx.rlc.funcs->is_rlc_enabled(adev)) 44106c7d61SLikun Gao return; 45106c7d61SLikun Gao 46106c7d61SLikun Gao if (adev->cg_flags & 47106c7d61SLikun Gao (AMD_CG_SUPPORT_GFX_CGCG | AMD_CG_SUPPORT_GFX_MGCG | 48106c7d61SLikun Gao AMD_CG_SUPPORT_GFX_3D_CGCG)) { 49106c7d61SLikun Gao adev->gfx.rlc.funcs->set_safe_mode(adev); 50106c7d61SLikun Gao adev->gfx.rlc.in_safe_mode = true; 51106c7d61SLikun Gao } 52106c7d61SLikun Gao } 53106c7d61SLikun Gao 54106c7d61SLikun Gao /** 55106c7d61SLikun Gao * amdgpu_gfx_rlc_exit_safe_mode - Set RLC out of safe mode 56106c7d61SLikun Gao * 57106c7d61SLikun Gao * @adev: amdgpu_device pointer 58106c7d61SLikun Gao * 59106c7d61SLikun Gao * Set RLC exit safe mode if RLC is enabled and have entered into safe mode. 60106c7d61SLikun Gao */ 61106c7d61SLikun Gao void amdgpu_gfx_rlc_exit_safe_mode(struct amdgpu_device *adev) 62106c7d61SLikun Gao { 63106c7d61SLikun Gao if (!(adev->gfx.rlc.in_safe_mode)) 64106c7d61SLikun Gao return; 65106c7d61SLikun Gao 66106c7d61SLikun Gao /* if RLC is not enabled, do nothing */ 67106c7d61SLikun Gao if (!adev->gfx.rlc.funcs->is_rlc_enabled(adev)) 68106c7d61SLikun Gao return; 69106c7d61SLikun Gao 70106c7d61SLikun Gao if (adev->cg_flags & 71106c7d61SLikun Gao (AMD_CG_SUPPORT_GFX_CGCG | AMD_CG_SUPPORT_GFX_MGCG | 72106c7d61SLikun Gao AMD_CG_SUPPORT_GFX_3D_CGCG)) { 73106c7d61SLikun Gao adev->gfx.rlc.funcs->unset_safe_mode(adev); 74106c7d61SLikun Gao adev->gfx.rlc.in_safe_mode = false; 75106c7d61SLikun Gao } 76106c7d61SLikun Gao } 77106c7d61SLikun Gao 78106c7d61SLikun Gao /** 79106c7d61SLikun Gao * amdgpu_gfx_rlc_init_sr - Init save restore block 80106c7d61SLikun Gao * 81106c7d61SLikun Gao * @adev: amdgpu_device pointer 82106c7d61SLikun Gao * @dws: the size of save restore block 83106c7d61SLikun Gao * 84106c7d61SLikun Gao * Allocate and setup value to save restore block of rlc. 85106c7d61SLikun Gao * Returns 0 on succeess or negative error code if allocate failed. 86106c7d61SLikun Gao */ 87106c7d61SLikun Gao int amdgpu_gfx_rlc_init_sr(struct amdgpu_device *adev, u32 dws) 88106c7d61SLikun Gao { 89106c7d61SLikun Gao const u32 *src_ptr; 90106c7d61SLikun Gao volatile u32 *dst_ptr; 91106c7d61SLikun Gao u32 i; 92106c7d61SLikun Gao int r; 93106c7d61SLikun Gao 94106c7d61SLikun Gao /* allocate save restore block */ 95106c7d61SLikun Gao r = amdgpu_bo_create_reserved(adev, dws * 4, PAGE_SIZE, 96*58ab2c08SChristian König AMDGPU_GEM_DOMAIN_VRAM | 97*58ab2c08SChristian König AMDGPU_GEM_DOMAIN_GTT, 98106c7d61SLikun Gao &adev->gfx.rlc.save_restore_obj, 99106c7d61SLikun Gao &adev->gfx.rlc.save_restore_gpu_addr, 100106c7d61SLikun Gao (void **)&adev->gfx.rlc.sr_ptr); 101106c7d61SLikun Gao if (r) { 102106c7d61SLikun Gao dev_warn(adev->dev, "(%d) create RLC sr bo failed\n", r); 103106c7d61SLikun Gao amdgpu_gfx_rlc_fini(adev); 104106c7d61SLikun Gao return r; 105106c7d61SLikun Gao } 106106c7d61SLikun Gao 107106c7d61SLikun Gao /* write the sr buffer */ 108106c7d61SLikun Gao src_ptr = adev->gfx.rlc.reg_list; 109106c7d61SLikun Gao dst_ptr = adev->gfx.rlc.sr_ptr; 110106c7d61SLikun Gao for (i = 0; i < adev->gfx.rlc.reg_list_size; i++) 111106c7d61SLikun Gao dst_ptr[i] = cpu_to_le32(src_ptr[i]); 112106c7d61SLikun Gao amdgpu_bo_kunmap(adev->gfx.rlc.save_restore_obj); 113106c7d61SLikun Gao amdgpu_bo_unreserve(adev->gfx.rlc.save_restore_obj); 114106c7d61SLikun Gao 115106c7d61SLikun Gao return 0; 116106c7d61SLikun Gao } 117106c7d61SLikun Gao 118106c7d61SLikun Gao /** 119106c7d61SLikun Gao * amdgpu_gfx_rlc_init_csb - Init clear state block 120106c7d61SLikun Gao * 121106c7d61SLikun Gao * @adev: amdgpu_device pointer 122106c7d61SLikun Gao * 123106c7d61SLikun Gao * Allocate and setup value to clear state block of rlc. 124106c7d61SLikun Gao * Returns 0 on succeess or negative error code if allocate failed. 125106c7d61SLikun Gao */ 126106c7d61SLikun Gao int amdgpu_gfx_rlc_init_csb(struct amdgpu_device *adev) 127106c7d61SLikun Gao { 128106c7d61SLikun Gao u32 dws; 129106c7d61SLikun Gao int r; 130106c7d61SLikun Gao 131106c7d61SLikun Gao /* allocate clear state block */ 132106c7d61SLikun Gao adev->gfx.rlc.clear_state_size = dws = adev->gfx.rlc.funcs->get_csb_size(adev); 133747d4f71SMonk Liu r = amdgpu_bo_create_kernel(adev, dws * 4, PAGE_SIZE, 134*58ab2c08SChristian König AMDGPU_GEM_DOMAIN_VRAM | 135*58ab2c08SChristian König AMDGPU_GEM_DOMAIN_GTT, 136106c7d61SLikun Gao &adev->gfx.rlc.clear_state_obj, 137106c7d61SLikun Gao &adev->gfx.rlc.clear_state_gpu_addr, 138106c7d61SLikun Gao (void **)&adev->gfx.rlc.cs_ptr); 139106c7d61SLikun Gao if (r) { 140106c7d61SLikun Gao dev_err(adev->dev, "(%d) failed to create rlc csb bo\n", r); 141106c7d61SLikun Gao amdgpu_gfx_rlc_fini(adev); 142106c7d61SLikun Gao return r; 143106c7d61SLikun Gao } 144106c7d61SLikun Gao 145106c7d61SLikun Gao return 0; 146106c7d61SLikun Gao } 147106c7d61SLikun Gao 148106c7d61SLikun Gao /** 149106c7d61SLikun Gao * amdgpu_gfx_rlc_init_cpt - Init cp table 150106c7d61SLikun Gao * 151106c7d61SLikun Gao * @adev: amdgpu_device pointer 152106c7d61SLikun Gao * 153106c7d61SLikun Gao * Allocate and setup value to cp table of rlc. 154106c7d61SLikun Gao * Returns 0 on succeess or negative error code if allocate failed. 155106c7d61SLikun Gao */ 156106c7d61SLikun Gao int amdgpu_gfx_rlc_init_cpt(struct amdgpu_device *adev) 157106c7d61SLikun Gao { 158106c7d61SLikun Gao int r; 159106c7d61SLikun Gao 160106c7d61SLikun Gao r = amdgpu_bo_create_reserved(adev, adev->gfx.rlc.cp_table_size, 161*58ab2c08SChristian König PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM | 162*58ab2c08SChristian König AMDGPU_GEM_DOMAIN_GTT, 163106c7d61SLikun Gao &adev->gfx.rlc.cp_table_obj, 164106c7d61SLikun Gao &adev->gfx.rlc.cp_table_gpu_addr, 165106c7d61SLikun Gao (void **)&adev->gfx.rlc.cp_table_ptr); 166106c7d61SLikun Gao if (r) { 167106c7d61SLikun Gao dev_err(adev->dev, "(%d) failed to create cp table bo\n", r); 168106c7d61SLikun Gao amdgpu_gfx_rlc_fini(adev); 169106c7d61SLikun Gao return r; 170106c7d61SLikun Gao } 171106c7d61SLikun Gao 172106c7d61SLikun Gao /* set up the cp table */ 173106c7d61SLikun Gao amdgpu_gfx_rlc_setup_cp_table(adev); 174106c7d61SLikun Gao amdgpu_bo_kunmap(adev->gfx.rlc.cp_table_obj); 175106c7d61SLikun Gao amdgpu_bo_unreserve(adev->gfx.rlc.cp_table_obj); 176106c7d61SLikun Gao 177106c7d61SLikun Gao return 0; 178106c7d61SLikun Gao } 179106c7d61SLikun Gao 180106c7d61SLikun Gao /** 181106c7d61SLikun Gao * amdgpu_gfx_rlc_setup_cp_table - setup cp the buffer of cp table 182106c7d61SLikun Gao * 183106c7d61SLikun Gao * @adev: amdgpu_device pointer 184106c7d61SLikun Gao * 185106c7d61SLikun Gao * Write cp firmware data into cp table. 186106c7d61SLikun Gao */ 187106c7d61SLikun Gao void amdgpu_gfx_rlc_setup_cp_table(struct amdgpu_device *adev) 188106c7d61SLikun Gao { 189106c7d61SLikun Gao const __le32 *fw_data; 190106c7d61SLikun Gao volatile u32 *dst_ptr; 191106c7d61SLikun Gao int me, i, max_me; 192106c7d61SLikun Gao u32 bo_offset = 0; 193106c7d61SLikun Gao u32 table_offset, table_size; 194106c7d61SLikun Gao 195106c7d61SLikun Gao max_me = adev->gfx.rlc.funcs->get_cp_table_num(adev); 196106c7d61SLikun Gao 197106c7d61SLikun Gao /* write the cp table buffer */ 198106c7d61SLikun Gao dst_ptr = adev->gfx.rlc.cp_table_ptr; 199106c7d61SLikun Gao for (me = 0; me < max_me; me++) { 200106c7d61SLikun Gao if (me == 0) { 201106c7d61SLikun Gao const struct gfx_firmware_header_v1_0 *hdr = 202106c7d61SLikun Gao (const struct gfx_firmware_header_v1_0 *)adev->gfx.ce_fw->data; 203106c7d61SLikun Gao fw_data = (const __le32 *) 204106c7d61SLikun Gao (adev->gfx.ce_fw->data + 205106c7d61SLikun Gao le32_to_cpu(hdr->header.ucode_array_offset_bytes)); 206106c7d61SLikun Gao table_offset = le32_to_cpu(hdr->jt_offset); 207106c7d61SLikun Gao table_size = le32_to_cpu(hdr->jt_size); 208106c7d61SLikun Gao } else if (me == 1) { 209106c7d61SLikun Gao const struct gfx_firmware_header_v1_0 *hdr = 210106c7d61SLikun Gao (const struct gfx_firmware_header_v1_0 *)adev->gfx.pfp_fw->data; 211106c7d61SLikun Gao fw_data = (const __le32 *) 212106c7d61SLikun Gao (adev->gfx.pfp_fw->data + 213106c7d61SLikun Gao le32_to_cpu(hdr->header.ucode_array_offset_bytes)); 214106c7d61SLikun Gao table_offset = le32_to_cpu(hdr->jt_offset); 215106c7d61SLikun Gao table_size = le32_to_cpu(hdr->jt_size); 216106c7d61SLikun Gao } else if (me == 2) { 217106c7d61SLikun Gao const struct gfx_firmware_header_v1_0 *hdr = 218106c7d61SLikun Gao (const struct gfx_firmware_header_v1_0 *)adev->gfx.me_fw->data; 219106c7d61SLikun Gao fw_data = (const __le32 *) 220106c7d61SLikun Gao (adev->gfx.me_fw->data + 221106c7d61SLikun Gao le32_to_cpu(hdr->header.ucode_array_offset_bytes)); 222106c7d61SLikun Gao table_offset = le32_to_cpu(hdr->jt_offset); 223106c7d61SLikun Gao table_size = le32_to_cpu(hdr->jt_size); 224106c7d61SLikun Gao } else if (me == 3) { 225106c7d61SLikun Gao const struct gfx_firmware_header_v1_0 *hdr = 226106c7d61SLikun Gao (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec_fw->data; 227106c7d61SLikun Gao fw_data = (const __le32 *) 228106c7d61SLikun Gao (adev->gfx.mec_fw->data + 229106c7d61SLikun Gao le32_to_cpu(hdr->header.ucode_array_offset_bytes)); 230106c7d61SLikun Gao table_offset = le32_to_cpu(hdr->jt_offset); 231106c7d61SLikun Gao table_size = le32_to_cpu(hdr->jt_size); 232106c7d61SLikun Gao } else if (me == 4) { 233106c7d61SLikun Gao const struct gfx_firmware_header_v1_0 *hdr = 234106c7d61SLikun Gao (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec2_fw->data; 235106c7d61SLikun Gao fw_data = (const __le32 *) 236106c7d61SLikun Gao (adev->gfx.mec2_fw->data + 237106c7d61SLikun Gao le32_to_cpu(hdr->header.ucode_array_offset_bytes)); 238106c7d61SLikun Gao table_offset = le32_to_cpu(hdr->jt_offset); 239106c7d61SLikun Gao table_size = le32_to_cpu(hdr->jt_size); 240106c7d61SLikun Gao } 241106c7d61SLikun Gao 242106c7d61SLikun Gao for (i = 0; i < table_size; i ++) { 243106c7d61SLikun Gao dst_ptr[bo_offset + i] = 244106c7d61SLikun Gao cpu_to_le32(le32_to_cpu(fw_data[table_offset + i])); 245106c7d61SLikun Gao } 246106c7d61SLikun Gao 247106c7d61SLikun Gao bo_offset += table_size; 248106c7d61SLikun Gao } 249106c7d61SLikun Gao } 250106c7d61SLikun Gao 251106c7d61SLikun Gao /** 25288dfc9a3SLikun Gao * amdgpu_gfx_rlc_fini - Free BO which used for RLC 25388dfc9a3SLikun Gao * 25488dfc9a3SLikun Gao * @adev: amdgpu_device pointer 25588dfc9a3SLikun Gao * 25688dfc9a3SLikun Gao * Free three BO which is used for rlc_save_restore_block, rlc_clear_state_block 25788dfc9a3SLikun Gao * and rlc_jump_table_block. 25888dfc9a3SLikun Gao */ 25988dfc9a3SLikun Gao void amdgpu_gfx_rlc_fini(struct amdgpu_device *adev) 26088dfc9a3SLikun Gao { 26188dfc9a3SLikun Gao /* save restore block */ 26288dfc9a3SLikun Gao if (adev->gfx.rlc.save_restore_obj) { 26388dfc9a3SLikun Gao amdgpu_bo_free_kernel(&adev->gfx.rlc.save_restore_obj, 26488dfc9a3SLikun Gao &adev->gfx.rlc.save_restore_gpu_addr, 26588dfc9a3SLikun Gao (void **)&adev->gfx.rlc.sr_ptr); 26688dfc9a3SLikun Gao } 26788dfc9a3SLikun Gao 26888dfc9a3SLikun Gao /* clear state block */ 26988dfc9a3SLikun Gao amdgpu_bo_free_kernel(&adev->gfx.rlc.clear_state_obj, 27088dfc9a3SLikun Gao &adev->gfx.rlc.clear_state_gpu_addr, 27188dfc9a3SLikun Gao (void **)&adev->gfx.rlc.cs_ptr); 27288dfc9a3SLikun Gao 27388dfc9a3SLikun Gao /* jump table block */ 27488dfc9a3SLikun Gao amdgpu_bo_free_kernel(&adev->gfx.rlc.cp_table_obj, 27588dfc9a3SLikun Gao &adev->gfx.rlc.cp_table_gpu_addr, 27688dfc9a3SLikun Gao (void **)&adev->gfx.rlc.cp_table_ptr); 27788dfc9a3SLikun Gao } 2780641dbefSHawking Zhang 2790641dbefSHawking Zhang static int amdgpu_gfx_rlc_init_microcode_v2_0(struct amdgpu_device *adev) 2800641dbefSHawking Zhang { 2810641dbefSHawking Zhang const struct common_firmware_header *common_hdr; 2820641dbefSHawking Zhang const struct rlc_firmware_header_v2_0 *rlc_hdr; 2830641dbefSHawking Zhang struct amdgpu_firmware_info *info; 2840641dbefSHawking Zhang unsigned int *tmp; 2850641dbefSHawking Zhang unsigned int i; 2860641dbefSHawking Zhang 2870641dbefSHawking Zhang rlc_hdr = (const struct rlc_firmware_header_v2_0 *)adev->gfx.rlc_fw->data; 2880641dbefSHawking Zhang 2890641dbefSHawking Zhang adev->gfx.rlc_fw_version = le32_to_cpu(rlc_hdr->header.ucode_version); 2900641dbefSHawking Zhang adev->gfx.rlc_feature_version = le32_to_cpu(rlc_hdr->ucode_feature_version); 2910641dbefSHawking Zhang adev->gfx.rlc.save_and_restore_offset = 2920641dbefSHawking Zhang le32_to_cpu(rlc_hdr->save_and_restore_offset); 2930641dbefSHawking Zhang adev->gfx.rlc.clear_state_descriptor_offset = 2940641dbefSHawking Zhang le32_to_cpu(rlc_hdr->clear_state_descriptor_offset); 2950641dbefSHawking Zhang adev->gfx.rlc.avail_scratch_ram_locations = 2960641dbefSHawking Zhang le32_to_cpu(rlc_hdr->avail_scratch_ram_locations); 2970641dbefSHawking Zhang adev->gfx.rlc.reg_restore_list_size = 2980641dbefSHawking Zhang le32_to_cpu(rlc_hdr->reg_restore_list_size); 2990641dbefSHawking Zhang adev->gfx.rlc.reg_list_format_start = 3000641dbefSHawking Zhang le32_to_cpu(rlc_hdr->reg_list_format_start); 3010641dbefSHawking Zhang adev->gfx.rlc.reg_list_format_separate_start = 3020641dbefSHawking Zhang le32_to_cpu(rlc_hdr->reg_list_format_separate_start); 3030641dbefSHawking Zhang adev->gfx.rlc.starting_offsets_start = 3040641dbefSHawking Zhang le32_to_cpu(rlc_hdr->starting_offsets_start); 3050641dbefSHawking Zhang adev->gfx.rlc.reg_list_format_size_bytes = 3060641dbefSHawking Zhang le32_to_cpu(rlc_hdr->reg_list_format_size_bytes); 3070641dbefSHawking Zhang adev->gfx.rlc.reg_list_size_bytes = 3080641dbefSHawking Zhang le32_to_cpu(rlc_hdr->reg_list_size_bytes); 3090641dbefSHawking Zhang adev->gfx.rlc.register_list_format = 3100641dbefSHawking Zhang kmalloc(adev->gfx.rlc.reg_list_format_size_bytes + 3110641dbefSHawking Zhang adev->gfx.rlc.reg_list_size_bytes, GFP_KERNEL); 3120641dbefSHawking Zhang if (!adev->gfx.rlc.register_list_format) { 3130641dbefSHawking Zhang dev_err(adev->dev, "failed to allocate memory for rlc register_list_format\n"); 3140641dbefSHawking Zhang return -ENOMEM; 3150641dbefSHawking Zhang } 3160641dbefSHawking Zhang 3170641dbefSHawking Zhang tmp = (unsigned int *)((uintptr_t)rlc_hdr + 3180641dbefSHawking Zhang le32_to_cpu(rlc_hdr->reg_list_format_array_offset_bytes)); 3190641dbefSHawking Zhang for (i = 0 ; i < (rlc_hdr->reg_list_format_size_bytes >> 2); i++) 3200641dbefSHawking Zhang adev->gfx.rlc.register_list_format[i] = le32_to_cpu(tmp[i]); 3210641dbefSHawking Zhang 3220641dbefSHawking Zhang adev->gfx.rlc.register_restore = adev->gfx.rlc.register_list_format + i; 3230641dbefSHawking Zhang 3240641dbefSHawking Zhang tmp = (unsigned int *)((uintptr_t)rlc_hdr + 3250641dbefSHawking Zhang le32_to_cpu(rlc_hdr->reg_list_array_offset_bytes)); 3260641dbefSHawking Zhang for (i = 0 ; i < (rlc_hdr->reg_list_size_bytes >> 2); i++) 3270641dbefSHawking Zhang adev->gfx.rlc.register_restore[i] = le32_to_cpu(tmp[i]); 3280641dbefSHawking Zhang 3290641dbefSHawking Zhang if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { 3300641dbefSHawking Zhang info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_G]; 3310641dbefSHawking Zhang info->ucode_id = AMDGPU_UCODE_ID_RLC_G; 3320641dbefSHawking Zhang info->fw = adev->gfx.rlc_fw; 3330641dbefSHawking Zhang if (info->fw) { 3340641dbefSHawking Zhang common_hdr = (const struct common_firmware_header *)info->fw->data; 3350641dbefSHawking Zhang adev->firmware.fw_size += 3360641dbefSHawking Zhang ALIGN(le32_to_cpu(common_hdr->ucode_size_bytes), PAGE_SIZE); 3370641dbefSHawking Zhang } 3380641dbefSHawking Zhang } 3390641dbefSHawking Zhang 3400641dbefSHawking Zhang return 0; 3410641dbefSHawking Zhang } 342f3e6173bSHawking Zhang 343f3e6173bSHawking Zhang static void amdgpu_gfx_rlc_init_microcode_v2_1(struct amdgpu_device *adev) 344f3e6173bSHawking Zhang { 345f3e6173bSHawking Zhang const struct rlc_firmware_header_v2_1 *rlc_hdr; 346f3e6173bSHawking Zhang struct amdgpu_firmware_info *info; 347f3e6173bSHawking Zhang 348f3e6173bSHawking Zhang rlc_hdr = (const struct rlc_firmware_header_v2_1 *)adev->gfx.rlc_fw->data; 349f3e6173bSHawking Zhang adev->gfx.rlc_srlc_fw_version = le32_to_cpu(rlc_hdr->save_restore_list_cntl_ucode_ver); 350f3e6173bSHawking Zhang adev->gfx.rlc_srlc_feature_version = le32_to_cpu(rlc_hdr->save_restore_list_cntl_feature_ver); 351f3e6173bSHawking Zhang adev->gfx.rlc.save_restore_list_cntl_size_bytes = le32_to_cpu(rlc_hdr->save_restore_list_cntl_size_bytes); 352f3e6173bSHawking Zhang adev->gfx.rlc.save_restore_list_cntl = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->save_restore_list_cntl_offset_bytes); 353f3e6173bSHawking Zhang adev->gfx.rlc_srlg_fw_version = le32_to_cpu(rlc_hdr->save_restore_list_gpm_ucode_ver); 354f3e6173bSHawking Zhang adev->gfx.rlc_srlg_feature_version = le32_to_cpu(rlc_hdr->save_restore_list_gpm_feature_ver); 355f3e6173bSHawking Zhang adev->gfx.rlc.save_restore_list_gpm_size_bytes = le32_to_cpu(rlc_hdr->save_restore_list_gpm_size_bytes); 356f3e6173bSHawking Zhang adev->gfx.rlc.save_restore_list_gpm = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->save_restore_list_gpm_offset_bytes); 357f3e6173bSHawking Zhang adev->gfx.rlc_srls_fw_version = le32_to_cpu(rlc_hdr->save_restore_list_srm_ucode_ver); 358f3e6173bSHawking Zhang adev->gfx.rlc_srls_feature_version = le32_to_cpu(rlc_hdr->save_restore_list_srm_feature_ver); 359f3e6173bSHawking Zhang adev->gfx.rlc.save_restore_list_srm_size_bytes = le32_to_cpu(rlc_hdr->save_restore_list_srm_size_bytes); 360f3e6173bSHawking Zhang adev->gfx.rlc.save_restore_list_srm = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->save_restore_list_srm_offset_bytes); 361f3e6173bSHawking Zhang adev->gfx.rlc.reg_list_format_direct_reg_list_length = 362f3e6173bSHawking Zhang le32_to_cpu(rlc_hdr->reg_list_format_direct_reg_list_length); 363f3e6173bSHawking Zhang 364f3e6173bSHawking Zhang if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { 365940d4dd4SHawking Zhang if (adev->gfx.rlc.save_restore_list_cntl_size_bytes) { 366940d4dd4SHawking Zhang info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_RESTORE_LIST_CNTL]; 367940d4dd4SHawking Zhang info->ucode_id = AMDGPU_UCODE_ID_RLC_RESTORE_LIST_CNTL; 368940d4dd4SHawking Zhang info->fw = adev->gfx.rlc_fw; 369940d4dd4SHawking Zhang adev->firmware.fw_size += 370940d4dd4SHawking Zhang ALIGN(adev->gfx.rlc.save_restore_list_cntl_size_bytes, PAGE_SIZE); 371940d4dd4SHawking Zhang } 372940d4dd4SHawking Zhang 373f3e6173bSHawking Zhang if (adev->gfx.rlc.save_restore_list_gpm_size_bytes) { 374f3e6173bSHawking Zhang info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_RESTORE_LIST_GPM_MEM]; 375f3e6173bSHawking Zhang info->ucode_id = AMDGPU_UCODE_ID_RLC_RESTORE_LIST_GPM_MEM; 376f3e6173bSHawking Zhang info->fw = adev->gfx.rlc_fw; 377f3e6173bSHawking Zhang adev->firmware.fw_size += 378f3e6173bSHawking Zhang ALIGN(adev->gfx.rlc.save_restore_list_gpm_size_bytes, PAGE_SIZE); 379f3e6173bSHawking Zhang } 380f3e6173bSHawking Zhang 381f3e6173bSHawking Zhang if (adev->gfx.rlc.save_restore_list_srm_size_bytes) { 382f3e6173bSHawking Zhang info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_RESTORE_LIST_SRM_MEM]; 383f3e6173bSHawking Zhang info->ucode_id = AMDGPU_UCODE_ID_RLC_RESTORE_LIST_SRM_MEM; 384f3e6173bSHawking Zhang info->fw = adev->gfx.rlc_fw; 385f3e6173bSHawking Zhang adev->firmware.fw_size += 386f3e6173bSHawking Zhang ALIGN(adev->gfx.rlc.save_restore_list_srm_size_bytes, PAGE_SIZE); 387f3e6173bSHawking Zhang } 388f3e6173bSHawking Zhang } 389f3e6173bSHawking Zhang } 390a97d0ec8SHawking Zhang 391a97d0ec8SHawking Zhang static void amdgpu_gfx_rlc_init_microcode_v2_2(struct amdgpu_device *adev) 392a97d0ec8SHawking Zhang { 393a97d0ec8SHawking Zhang const struct rlc_firmware_header_v2_2 *rlc_hdr; 394a97d0ec8SHawking Zhang struct amdgpu_firmware_info *info; 395a97d0ec8SHawking Zhang 396a97d0ec8SHawking Zhang rlc_hdr = (const struct rlc_firmware_header_v2_2 *)adev->gfx.rlc_fw->data; 397a97d0ec8SHawking Zhang adev->gfx.rlc.rlc_iram_ucode_size_bytes = le32_to_cpu(rlc_hdr->rlc_iram_ucode_size_bytes); 398a97d0ec8SHawking Zhang adev->gfx.rlc.rlc_iram_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->rlc_iram_ucode_offset_bytes); 399a97d0ec8SHawking Zhang adev->gfx.rlc.rlc_dram_ucode_size_bytes = le32_to_cpu(rlc_hdr->rlc_dram_ucode_size_bytes); 400a97d0ec8SHawking Zhang adev->gfx.rlc.rlc_dram_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->rlc_dram_ucode_offset_bytes); 401a97d0ec8SHawking Zhang 402a97d0ec8SHawking Zhang if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { 403a97d0ec8SHawking Zhang if (adev->gfx.rlc.rlc_iram_ucode_size_bytes) { 404a97d0ec8SHawking Zhang info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_IRAM]; 405a97d0ec8SHawking Zhang info->ucode_id = AMDGPU_UCODE_ID_RLC_IRAM; 406a97d0ec8SHawking Zhang info->fw = adev->gfx.rlc_fw; 407a97d0ec8SHawking Zhang adev->firmware.fw_size += 408a97d0ec8SHawking Zhang ALIGN(adev->gfx.rlc.rlc_iram_ucode_size_bytes, PAGE_SIZE); 409a97d0ec8SHawking Zhang } 410a97d0ec8SHawking Zhang 411a97d0ec8SHawking Zhang if (adev->gfx.rlc.rlc_dram_ucode_size_bytes) { 412a97d0ec8SHawking Zhang info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_DRAM]; 413a97d0ec8SHawking Zhang info->ucode_id = AMDGPU_UCODE_ID_RLC_DRAM; 414a97d0ec8SHawking Zhang info->fw = adev->gfx.rlc_fw; 415a97d0ec8SHawking Zhang adev->firmware.fw_size += 416a97d0ec8SHawking Zhang ALIGN(adev->gfx.rlc.rlc_dram_ucode_size_bytes, PAGE_SIZE); 417a97d0ec8SHawking Zhang } 418a97d0ec8SHawking Zhang } 419a97d0ec8SHawking Zhang } 420a0d9084dSHawking Zhang 421a0d9084dSHawking Zhang static void amdgpu_gfx_rlc_init_microcode_v2_3(struct amdgpu_device *adev) 422a0d9084dSHawking Zhang { 423a0d9084dSHawking Zhang const struct rlc_firmware_header_v2_3 *rlc_hdr; 424a0d9084dSHawking Zhang struct amdgpu_firmware_info *info; 425a0d9084dSHawking Zhang 426a0d9084dSHawking Zhang rlc_hdr = (const struct rlc_firmware_header_v2_3 *)adev->gfx.rlc_fw->data; 427a0d9084dSHawking Zhang adev->gfx.rlcp_ucode_version = le32_to_cpu(rlc_hdr->rlcp_ucode_version); 428a0d9084dSHawking Zhang adev->gfx.rlcp_ucode_feature_version = le32_to_cpu(rlc_hdr->rlcp_ucode_feature_version); 429a0d9084dSHawking Zhang adev->gfx.rlc.rlcp_ucode_size_bytes = le32_to_cpu(rlc_hdr->rlcp_ucode_size_bytes); 430a0d9084dSHawking Zhang adev->gfx.rlc.rlcp_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->rlcp_ucode_offset_bytes); 431a0d9084dSHawking Zhang 432a0d9084dSHawking Zhang adev->gfx.rlcv_ucode_version = le32_to_cpu(rlc_hdr->rlcv_ucode_version); 433a0d9084dSHawking Zhang adev->gfx.rlcv_ucode_feature_version = le32_to_cpu(rlc_hdr->rlcv_ucode_feature_version); 434a0d9084dSHawking Zhang adev->gfx.rlc.rlcv_ucode_size_bytes = le32_to_cpu(rlc_hdr->rlcv_ucode_size_bytes); 435a0d9084dSHawking Zhang adev->gfx.rlc.rlcv_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->rlcv_ucode_offset_bytes); 436a0d9084dSHawking Zhang 437a0d9084dSHawking Zhang if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { 438a0d9084dSHawking Zhang if (adev->gfx.rlc.rlcp_ucode_size_bytes) { 439a0d9084dSHawking Zhang info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_P]; 440a0d9084dSHawking Zhang info->ucode_id = AMDGPU_UCODE_ID_RLC_P; 441a0d9084dSHawking Zhang info->fw = adev->gfx.rlc_fw; 442a0d9084dSHawking Zhang adev->firmware.fw_size += 443a0d9084dSHawking Zhang ALIGN(adev->gfx.rlc.rlcp_ucode_size_bytes, PAGE_SIZE); 444a0d9084dSHawking Zhang } 445a0d9084dSHawking Zhang 446a0d9084dSHawking Zhang if (adev->gfx.rlc.rlcv_ucode_size_bytes) { 447a0d9084dSHawking Zhang info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_V]; 448a0d9084dSHawking Zhang info->ucode_id = AMDGPU_UCODE_ID_RLC_V; 449a0d9084dSHawking Zhang info->fw = adev->gfx.rlc_fw; 450a0d9084dSHawking Zhang adev->firmware.fw_size += 451a0d9084dSHawking Zhang ALIGN(adev->gfx.rlc.rlcv_ucode_size_bytes, PAGE_SIZE); 452a0d9084dSHawking Zhang } 453a0d9084dSHawking Zhang } 454a0d9084dSHawking Zhang } 455435d6e6fSHawking Zhang 456435d6e6fSHawking Zhang static void amdgpu_gfx_rlc_init_microcode_v2_4(struct amdgpu_device *adev) 457435d6e6fSHawking Zhang { 458435d6e6fSHawking Zhang const struct rlc_firmware_header_v2_4 *rlc_hdr; 459435d6e6fSHawking Zhang struct amdgpu_firmware_info *info; 460435d6e6fSHawking Zhang 461435d6e6fSHawking Zhang rlc_hdr = (const struct rlc_firmware_header_v2_4 *)adev->gfx.rlc_fw->data; 462435d6e6fSHawking Zhang adev->gfx.rlc.global_tap_delays_ucode_size_bytes = le32_to_cpu(rlc_hdr->global_tap_delays_ucode_size_bytes); 463435d6e6fSHawking Zhang adev->gfx.rlc.global_tap_delays_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->global_tap_delays_ucode_offset_bytes); 464435d6e6fSHawking Zhang adev->gfx.rlc.se0_tap_delays_ucode_size_bytes = le32_to_cpu(rlc_hdr->se0_tap_delays_ucode_size_bytes); 465435d6e6fSHawking Zhang adev->gfx.rlc.se0_tap_delays_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->se0_tap_delays_ucode_offset_bytes); 466435d6e6fSHawking Zhang adev->gfx.rlc.se1_tap_delays_ucode_size_bytes = le32_to_cpu(rlc_hdr->se1_tap_delays_ucode_size_bytes); 467435d6e6fSHawking Zhang adev->gfx.rlc.se1_tap_delays_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->se1_tap_delays_ucode_offset_bytes); 468435d6e6fSHawking Zhang adev->gfx.rlc.se2_tap_delays_ucode_size_bytes = le32_to_cpu(rlc_hdr->se2_tap_delays_ucode_size_bytes); 469435d6e6fSHawking Zhang adev->gfx.rlc.se2_tap_delays_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->se2_tap_delays_ucode_offset_bytes); 470435d6e6fSHawking Zhang adev->gfx.rlc.se3_tap_delays_ucode_size_bytes = le32_to_cpu(rlc_hdr->se3_tap_delays_ucode_size_bytes); 471435d6e6fSHawking Zhang adev->gfx.rlc.se3_tap_delays_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->se3_tap_delays_ucode_offset_bytes); 472435d6e6fSHawking Zhang 473435d6e6fSHawking Zhang if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { 474435d6e6fSHawking Zhang if (adev->gfx.rlc.global_tap_delays_ucode_size_bytes) { 475435d6e6fSHawking Zhang info = &adev->firmware.ucode[AMDGPU_UCODE_ID_GLOBAL_TAP_DELAYS]; 476435d6e6fSHawking Zhang info->ucode_id = AMDGPU_UCODE_ID_GLOBAL_TAP_DELAYS; 477435d6e6fSHawking Zhang info->fw = adev->gfx.rlc_fw; 478435d6e6fSHawking Zhang adev->firmware.fw_size += 479435d6e6fSHawking Zhang ALIGN(adev->gfx.rlc.global_tap_delays_ucode_size_bytes, PAGE_SIZE); 480435d6e6fSHawking Zhang } 481435d6e6fSHawking Zhang 482435d6e6fSHawking Zhang if (adev->gfx.rlc.se0_tap_delays_ucode_size_bytes) { 483435d6e6fSHawking Zhang info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SE0_TAP_DELAYS]; 484435d6e6fSHawking Zhang info->ucode_id = AMDGPU_UCODE_ID_SE0_TAP_DELAYS; 485435d6e6fSHawking Zhang info->fw = adev->gfx.rlc_fw; 486435d6e6fSHawking Zhang adev->firmware.fw_size += 487435d6e6fSHawking Zhang ALIGN(adev->gfx.rlc.se0_tap_delays_ucode_size_bytes, PAGE_SIZE); 488435d6e6fSHawking Zhang } 489435d6e6fSHawking Zhang 490435d6e6fSHawking Zhang if (adev->gfx.rlc.se1_tap_delays_ucode_size_bytes) { 491435d6e6fSHawking Zhang info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SE1_TAP_DELAYS]; 492435d6e6fSHawking Zhang info->ucode_id = AMDGPU_UCODE_ID_SE1_TAP_DELAYS; 493435d6e6fSHawking Zhang info->fw = adev->gfx.rlc_fw; 494435d6e6fSHawking Zhang adev->firmware.fw_size += 495435d6e6fSHawking Zhang ALIGN(adev->gfx.rlc.se1_tap_delays_ucode_size_bytes, PAGE_SIZE); 496435d6e6fSHawking Zhang } 497435d6e6fSHawking Zhang 498435d6e6fSHawking Zhang if (adev->gfx.rlc.se2_tap_delays_ucode_size_bytes) { 499435d6e6fSHawking Zhang info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SE2_TAP_DELAYS]; 500435d6e6fSHawking Zhang info->ucode_id = AMDGPU_UCODE_ID_SE2_TAP_DELAYS; 501435d6e6fSHawking Zhang info->fw = adev->gfx.rlc_fw; 502435d6e6fSHawking Zhang adev->firmware.fw_size += 503435d6e6fSHawking Zhang ALIGN(adev->gfx.rlc.se2_tap_delays_ucode_size_bytes, PAGE_SIZE); 504435d6e6fSHawking Zhang } 505435d6e6fSHawking Zhang 506435d6e6fSHawking Zhang if (adev->gfx.rlc.se3_tap_delays_ucode_size_bytes) { 507435d6e6fSHawking Zhang info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SE3_TAP_DELAYS]; 508435d6e6fSHawking Zhang info->ucode_id = AMDGPU_UCODE_ID_SE3_TAP_DELAYS; 509435d6e6fSHawking Zhang info->fw = adev->gfx.rlc_fw; 510435d6e6fSHawking Zhang adev->firmware.fw_size += 511435d6e6fSHawking Zhang ALIGN(adev->gfx.rlc.se3_tap_delays_ucode_size_bytes, PAGE_SIZE); 512435d6e6fSHawking Zhang } 513435d6e6fSHawking Zhang } 514435d6e6fSHawking Zhang } 5155b415212SHawking Zhang 5165b415212SHawking Zhang int amdgpu_gfx_rlc_init_microcode(struct amdgpu_device *adev, 5175b415212SHawking Zhang uint16_t version_major, 5185b415212SHawking Zhang uint16_t version_minor) 5195b415212SHawking Zhang { 5205b415212SHawking Zhang int err; 5215b415212SHawking Zhang 5225b415212SHawking Zhang if (version_major < 2) { 5235b415212SHawking Zhang /* only support rlc_hdr v2.x and onwards */ 5245b415212SHawking Zhang dev_err(adev->dev, "unsupported rlc fw hdr\n"); 5255b415212SHawking Zhang return -EINVAL; 5265b415212SHawking Zhang } 5275b415212SHawking Zhang 5285b415212SHawking Zhang /* is_rlc_v2_1 is still used in APU code path */ 5295b415212SHawking Zhang if (version_major == 2 && version_minor == 1) 5305b415212SHawking Zhang adev->gfx.rlc.is_rlc_v2_1 = true; 5315b415212SHawking Zhang 5325b415212SHawking Zhang if (version_minor >= 0) { 5335b415212SHawking Zhang err = amdgpu_gfx_rlc_init_microcode_v2_0(adev); 5345b415212SHawking Zhang if (err) { 5355b415212SHawking Zhang dev_err(adev->dev, "fail to init rlc v2_0 microcode\n"); 5365b415212SHawking Zhang return err; 5375b415212SHawking Zhang } 5385b415212SHawking Zhang } 5395b415212SHawking Zhang if (version_minor >= 1) 5405b415212SHawking Zhang amdgpu_gfx_rlc_init_microcode_v2_1(adev); 5415b415212SHawking Zhang if (version_minor >= 2) 5425b415212SHawking Zhang amdgpu_gfx_rlc_init_microcode_v2_2(adev); 5435b415212SHawking Zhang if (version_minor == 3) 5445b415212SHawking Zhang amdgpu_gfx_rlc_init_microcode_v2_3(adev); 5455b415212SHawking Zhang if (version_minor == 4) 5465b415212SHawking Zhang amdgpu_gfx_rlc_init_microcode_v2_4(adev); 5475b415212SHawking Zhang 5485b415212SHawking Zhang return 0; 5495b415212SHawking Zhang } 550