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