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); 132*747d4f71SMonk 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 } 275