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 */ 25*106c7d61SLikun 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 /** 31*106c7d61SLikun Gao * amdgpu_gfx_rlc_enter_safe_mode - Set RLC into safe mode 32*106c7d61SLikun Gao * 33*106c7d61SLikun Gao * @adev: amdgpu_device pointer 34*106c7d61SLikun Gao * 35*106c7d61SLikun Gao * Set RLC enter into safe mode if RLC is enabled and haven't in safe mode. 36*106c7d61SLikun Gao */ 37*106c7d61SLikun Gao void amdgpu_gfx_rlc_enter_safe_mode(struct amdgpu_device *adev) 38*106c7d61SLikun Gao { 39*106c7d61SLikun Gao if (adev->gfx.rlc.in_safe_mode) 40*106c7d61SLikun Gao return; 41*106c7d61SLikun Gao 42*106c7d61SLikun Gao /* if RLC is not enabled, do nothing */ 43*106c7d61SLikun Gao if (!adev->gfx.rlc.funcs->is_rlc_enabled(adev)) 44*106c7d61SLikun Gao return; 45*106c7d61SLikun Gao 46*106c7d61SLikun Gao if (adev->cg_flags & 47*106c7d61SLikun Gao (AMD_CG_SUPPORT_GFX_CGCG | AMD_CG_SUPPORT_GFX_MGCG | 48*106c7d61SLikun Gao AMD_CG_SUPPORT_GFX_3D_CGCG)) { 49*106c7d61SLikun Gao adev->gfx.rlc.funcs->set_safe_mode(adev); 50*106c7d61SLikun Gao adev->gfx.rlc.in_safe_mode = true; 51*106c7d61SLikun Gao } 52*106c7d61SLikun Gao } 53*106c7d61SLikun Gao 54*106c7d61SLikun Gao /** 55*106c7d61SLikun Gao * amdgpu_gfx_rlc_exit_safe_mode - Set RLC out of safe mode 56*106c7d61SLikun Gao * 57*106c7d61SLikun Gao * @adev: amdgpu_device pointer 58*106c7d61SLikun Gao * 59*106c7d61SLikun Gao * Set RLC exit safe mode if RLC is enabled and have entered into safe mode. 60*106c7d61SLikun Gao */ 61*106c7d61SLikun Gao void amdgpu_gfx_rlc_exit_safe_mode(struct amdgpu_device *adev) 62*106c7d61SLikun Gao { 63*106c7d61SLikun Gao if (!(adev->gfx.rlc.in_safe_mode)) 64*106c7d61SLikun Gao return; 65*106c7d61SLikun Gao 66*106c7d61SLikun Gao /* if RLC is not enabled, do nothing */ 67*106c7d61SLikun Gao if (!adev->gfx.rlc.funcs->is_rlc_enabled(adev)) 68*106c7d61SLikun Gao return; 69*106c7d61SLikun Gao 70*106c7d61SLikun Gao if (adev->cg_flags & 71*106c7d61SLikun Gao (AMD_CG_SUPPORT_GFX_CGCG | AMD_CG_SUPPORT_GFX_MGCG | 72*106c7d61SLikun Gao AMD_CG_SUPPORT_GFX_3D_CGCG)) { 73*106c7d61SLikun Gao adev->gfx.rlc.funcs->unset_safe_mode(adev); 74*106c7d61SLikun Gao adev->gfx.rlc.in_safe_mode = false; 75*106c7d61SLikun Gao } 76*106c7d61SLikun Gao } 77*106c7d61SLikun Gao 78*106c7d61SLikun Gao /** 79*106c7d61SLikun Gao * amdgpu_gfx_rlc_init_sr - Init save restore block 80*106c7d61SLikun Gao * 81*106c7d61SLikun Gao * @adev: amdgpu_device pointer 82*106c7d61SLikun Gao * @dws: the size of save restore block 83*106c7d61SLikun Gao * 84*106c7d61SLikun Gao * Allocate and setup value to save restore block of rlc. 85*106c7d61SLikun Gao * Returns 0 on succeess or negative error code if allocate failed. 86*106c7d61SLikun Gao */ 87*106c7d61SLikun Gao int amdgpu_gfx_rlc_init_sr(struct amdgpu_device *adev, u32 dws) 88*106c7d61SLikun Gao { 89*106c7d61SLikun Gao const u32 *src_ptr; 90*106c7d61SLikun Gao volatile u32 *dst_ptr; 91*106c7d61SLikun Gao u32 i; 92*106c7d61SLikun Gao int r; 93*106c7d61SLikun Gao 94*106c7d61SLikun Gao /* allocate save restore block */ 95*106c7d61SLikun Gao r = amdgpu_bo_create_reserved(adev, dws * 4, PAGE_SIZE, 96*106c7d61SLikun Gao AMDGPU_GEM_DOMAIN_VRAM, 97*106c7d61SLikun Gao &adev->gfx.rlc.save_restore_obj, 98*106c7d61SLikun Gao &adev->gfx.rlc.save_restore_gpu_addr, 99*106c7d61SLikun Gao (void **)&adev->gfx.rlc.sr_ptr); 100*106c7d61SLikun Gao if (r) { 101*106c7d61SLikun Gao dev_warn(adev->dev, "(%d) create RLC sr bo failed\n", r); 102*106c7d61SLikun Gao amdgpu_gfx_rlc_fini(adev); 103*106c7d61SLikun Gao return r; 104*106c7d61SLikun Gao } 105*106c7d61SLikun Gao 106*106c7d61SLikun Gao /* write the sr buffer */ 107*106c7d61SLikun Gao src_ptr = adev->gfx.rlc.reg_list; 108*106c7d61SLikun Gao dst_ptr = adev->gfx.rlc.sr_ptr; 109*106c7d61SLikun Gao for (i = 0; i < adev->gfx.rlc.reg_list_size; i++) 110*106c7d61SLikun Gao dst_ptr[i] = cpu_to_le32(src_ptr[i]); 111*106c7d61SLikun Gao amdgpu_bo_kunmap(adev->gfx.rlc.save_restore_obj); 112*106c7d61SLikun Gao amdgpu_bo_unreserve(adev->gfx.rlc.save_restore_obj); 113*106c7d61SLikun Gao 114*106c7d61SLikun Gao return 0; 115*106c7d61SLikun Gao } 116*106c7d61SLikun Gao 117*106c7d61SLikun Gao /** 118*106c7d61SLikun Gao * amdgpu_gfx_rlc_init_csb - Init clear state block 119*106c7d61SLikun Gao * 120*106c7d61SLikun Gao * @adev: amdgpu_device pointer 121*106c7d61SLikun Gao * 122*106c7d61SLikun Gao * Allocate and setup value to clear state block of rlc. 123*106c7d61SLikun Gao * Returns 0 on succeess or negative error code if allocate failed. 124*106c7d61SLikun Gao */ 125*106c7d61SLikun Gao int amdgpu_gfx_rlc_init_csb(struct amdgpu_device *adev) 126*106c7d61SLikun Gao { 127*106c7d61SLikun Gao volatile u32 *dst_ptr; 128*106c7d61SLikun Gao u32 dws; 129*106c7d61SLikun Gao int r; 130*106c7d61SLikun Gao 131*106c7d61SLikun Gao /* allocate clear state block */ 132*106c7d61SLikun Gao adev->gfx.rlc.clear_state_size = dws = adev->gfx.rlc.funcs->get_csb_size(adev); 133*106c7d61SLikun Gao r = amdgpu_bo_create_reserved(adev, dws * 4, PAGE_SIZE, 134*106c7d61SLikun Gao AMDGPU_GEM_DOMAIN_VRAM, 135*106c7d61SLikun Gao &adev->gfx.rlc.clear_state_obj, 136*106c7d61SLikun Gao &adev->gfx.rlc.clear_state_gpu_addr, 137*106c7d61SLikun Gao (void **)&adev->gfx.rlc.cs_ptr); 138*106c7d61SLikun Gao if (r) { 139*106c7d61SLikun Gao dev_err(adev->dev, "(%d) failed to create rlc csb bo\n", r); 140*106c7d61SLikun Gao amdgpu_gfx_rlc_fini(adev); 141*106c7d61SLikun Gao return r; 142*106c7d61SLikun Gao } 143*106c7d61SLikun Gao 144*106c7d61SLikun Gao /* set up the cs buffer */ 145*106c7d61SLikun Gao dst_ptr = adev->gfx.rlc.cs_ptr; 146*106c7d61SLikun Gao adev->gfx.rlc.funcs->get_csb_buffer(adev, dst_ptr); 147*106c7d61SLikun Gao amdgpu_bo_kunmap(adev->gfx.rlc.clear_state_obj); 148*106c7d61SLikun Gao amdgpu_bo_unpin(adev->gfx.rlc.clear_state_obj); 149*106c7d61SLikun Gao amdgpu_bo_unreserve(adev->gfx.rlc.clear_state_obj); 150*106c7d61SLikun Gao 151*106c7d61SLikun Gao return 0; 152*106c7d61SLikun Gao } 153*106c7d61SLikun Gao 154*106c7d61SLikun Gao /** 155*106c7d61SLikun Gao * amdgpu_gfx_rlc_init_cpt - Init cp table 156*106c7d61SLikun Gao * 157*106c7d61SLikun Gao * @adev: amdgpu_device pointer 158*106c7d61SLikun Gao * 159*106c7d61SLikun Gao * Allocate and setup value to cp table of rlc. 160*106c7d61SLikun Gao * Returns 0 on succeess or negative error code if allocate failed. 161*106c7d61SLikun Gao */ 162*106c7d61SLikun Gao int amdgpu_gfx_rlc_init_cpt(struct amdgpu_device *adev) 163*106c7d61SLikun Gao { 164*106c7d61SLikun Gao int r; 165*106c7d61SLikun Gao 166*106c7d61SLikun Gao r = amdgpu_bo_create_reserved(adev, adev->gfx.rlc.cp_table_size, 167*106c7d61SLikun Gao PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM, 168*106c7d61SLikun Gao &adev->gfx.rlc.cp_table_obj, 169*106c7d61SLikun Gao &adev->gfx.rlc.cp_table_gpu_addr, 170*106c7d61SLikun Gao (void **)&adev->gfx.rlc.cp_table_ptr); 171*106c7d61SLikun Gao if (r) { 172*106c7d61SLikun Gao dev_err(adev->dev, "(%d) failed to create cp table bo\n", r); 173*106c7d61SLikun Gao amdgpu_gfx_rlc_fini(adev); 174*106c7d61SLikun Gao return r; 175*106c7d61SLikun Gao } 176*106c7d61SLikun Gao 177*106c7d61SLikun Gao /* set up the cp table */ 178*106c7d61SLikun Gao amdgpu_gfx_rlc_setup_cp_table(adev); 179*106c7d61SLikun Gao amdgpu_bo_kunmap(adev->gfx.rlc.cp_table_obj); 180*106c7d61SLikun Gao amdgpu_bo_unreserve(adev->gfx.rlc.cp_table_obj); 181*106c7d61SLikun Gao 182*106c7d61SLikun Gao return 0; 183*106c7d61SLikun Gao } 184*106c7d61SLikun Gao 185*106c7d61SLikun Gao /** 186*106c7d61SLikun Gao * amdgpu_gfx_rlc_setup_cp_table - setup cp the buffer of cp table 187*106c7d61SLikun Gao * 188*106c7d61SLikun Gao * @adev: amdgpu_device pointer 189*106c7d61SLikun Gao * 190*106c7d61SLikun Gao * Write cp firmware data into cp table. 191*106c7d61SLikun Gao */ 192*106c7d61SLikun Gao void amdgpu_gfx_rlc_setup_cp_table(struct amdgpu_device *adev) 193*106c7d61SLikun Gao { 194*106c7d61SLikun Gao const __le32 *fw_data; 195*106c7d61SLikun Gao volatile u32 *dst_ptr; 196*106c7d61SLikun Gao int me, i, max_me; 197*106c7d61SLikun Gao u32 bo_offset = 0; 198*106c7d61SLikun Gao u32 table_offset, table_size; 199*106c7d61SLikun Gao 200*106c7d61SLikun Gao max_me = adev->gfx.rlc.funcs->get_cp_table_num(adev); 201*106c7d61SLikun Gao 202*106c7d61SLikun Gao /* write the cp table buffer */ 203*106c7d61SLikun Gao dst_ptr = adev->gfx.rlc.cp_table_ptr; 204*106c7d61SLikun Gao for (me = 0; me < max_me; me++) { 205*106c7d61SLikun Gao if (me == 0) { 206*106c7d61SLikun Gao const struct gfx_firmware_header_v1_0 *hdr = 207*106c7d61SLikun Gao (const struct gfx_firmware_header_v1_0 *)adev->gfx.ce_fw->data; 208*106c7d61SLikun Gao fw_data = (const __le32 *) 209*106c7d61SLikun Gao (adev->gfx.ce_fw->data + 210*106c7d61SLikun Gao le32_to_cpu(hdr->header.ucode_array_offset_bytes)); 211*106c7d61SLikun Gao table_offset = le32_to_cpu(hdr->jt_offset); 212*106c7d61SLikun Gao table_size = le32_to_cpu(hdr->jt_size); 213*106c7d61SLikun Gao } else if (me == 1) { 214*106c7d61SLikun Gao const struct gfx_firmware_header_v1_0 *hdr = 215*106c7d61SLikun Gao (const struct gfx_firmware_header_v1_0 *)adev->gfx.pfp_fw->data; 216*106c7d61SLikun Gao fw_data = (const __le32 *) 217*106c7d61SLikun Gao (adev->gfx.pfp_fw->data + 218*106c7d61SLikun Gao le32_to_cpu(hdr->header.ucode_array_offset_bytes)); 219*106c7d61SLikun Gao table_offset = le32_to_cpu(hdr->jt_offset); 220*106c7d61SLikun Gao table_size = le32_to_cpu(hdr->jt_size); 221*106c7d61SLikun Gao } else if (me == 2) { 222*106c7d61SLikun Gao const struct gfx_firmware_header_v1_0 *hdr = 223*106c7d61SLikun Gao (const struct gfx_firmware_header_v1_0 *)adev->gfx.me_fw->data; 224*106c7d61SLikun Gao fw_data = (const __le32 *) 225*106c7d61SLikun Gao (adev->gfx.me_fw->data + 226*106c7d61SLikun Gao le32_to_cpu(hdr->header.ucode_array_offset_bytes)); 227*106c7d61SLikun Gao table_offset = le32_to_cpu(hdr->jt_offset); 228*106c7d61SLikun Gao table_size = le32_to_cpu(hdr->jt_size); 229*106c7d61SLikun Gao } else if (me == 3) { 230*106c7d61SLikun Gao const struct gfx_firmware_header_v1_0 *hdr = 231*106c7d61SLikun Gao (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec_fw->data; 232*106c7d61SLikun Gao fw_data = (const __le32 *) 233*106c7d61SLikun Gao (adev->gfx.mec_fw->data + 234*106c7d61SLikun Gao le32_to_cpu(hdr->header.ucode_array_offset_bytes)); 235*106c7d61SLikun Gao table_offset = le32_to_cpu(hdr->jt_offset); 236*106c7d61SLikun Gao table_size = le32_to_cpu(hdr->jt_size); 237*106c7d61SLikun Gao } else if (me == 4) { 238*106c7d61SLikun Gao const struct gfx_firmware_header_v1_0 *hdr = 239*106c7d61SLikun Gao (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec2_fw->data; 240*106c7d61SLikun Gao fw_data = (const __le32 *) 241*106c7d61SLikun Gao (adev->gfx.mec2_fw->data + 242*106c7d61SLikun Gao le32_to_cpu(hdr->header.ucode_array_offset_bytes)); 243*106c7d61SLikun Gao table_offset = le32_to_cpu(hdr->jt_offset); 244*106c7d61SLikun Gao table_size = le32_to_cpu(hdr->jt_size); 245*106c7d61SLikun Gao } 246*106c7d61SLikun Gao 247*106c7d61SLikun Gao for (i = 0; i < table_size; i ++) { 248*106c7d61SLikun Gao dst_ptr[bo_offset + i] = 249*106c7d61SLikun Gao cpu_to_le32(le32_to_cpu(fw_data[table_offset + i])); 250*106c7d61SLikun Gao } 251*106c7d61SLikun Gao 252*106c7d61SLikun Gao bo_offset += table_size; 253*106c7d61SLikun Gao } 254*106c7d61SLikun Gao } 255*106c7d61SLikun Gao 256*106c7d61SLikun Gao /** 25788dfc9a3SLikun Gao * amdgpu_gfx_rlc_fini - Free BO which used for RLC 25888dfc9a3SLikun Gao * 25988dfc9a3SLikun Gao * @adev: amdgpu_device pointer 26088dfc9a3SLikun Gao * 26188dfc9a3SLikun Gao * Free three BO which is used for rlc_save_restore_block, rlc_clear_state_block 26288dfc9a3SLikun Gao * and rlc_jump_table_block. 26388dfc9a3SLikun Gao */ 26488dfc9a3SLikun Gao void amdgpu_gfx_rlc_fini(struct amdgpu_device *adev) 26588dfc9a3SLikun Gao { 26688dfc9a3SLikun Gao /* save restore block */ 26788dfc9a3SLikun Gao if (adev->gfx.rlc.save_restore_obj) { 26888dfc9a3SLikun Gao amdgpu_bo_free_kernel(&adev->gfx.rlc.save_restore_obj, 26988dfc9a3SLikun Gao &adev->gfx.rlc.save_restore_gpu_addr, 27088dfc9a3SLikun Gao (void **)&adev->gfx.rlc.sr_ptr); 27188dfc9a3SLikun Gao } 27288dfc9a3SLikun Gao 27388dfc9a3SLikun Gao /* clear state block */ 27488dfc9a3SLikun Gao amdgpu_bo_free_kernel(&adev->gfx.rlc.clear_state_obj, 27588dfc9a3SLikun Gao &adev->gfx.rlc.clear_state_gpu_addr, 27688dfc9a3SLikun Gao (void **)&adev->gfx.rlc.cs_ptr); 27788dfc9a3SLikun Gao 27888dfc9a3SLikun Gao /* jump table block */ 27988dfc9a3SLikun Gao amdgpu_bo_free_kernel(&adev->gfx.rlc.cp_table_obj, 28088dfc9a3SLikun Gao &adev->gfx.rlc.cp_table_gpu_addr, 28188dfc9a3SLikun Gao (void **)&adev->gfx.rlc.cp_table_ptr); 28288dfc9a3SLikun Gao } 283