162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright 2016 Advanced Micro Devices, Inc. 362306a36Sopenharmony_ci * All Rights Reserved. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 662306a36Sopenharmony_ci * copy of this software and associated documentation files (the 762306a36Sopenharmony_ci * "Software"), to deal in the Software without restriction, including 862306a36Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish, 962306a36Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to 1062306a36Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to 1162306a36Sopenharmony_ci * the following conditions: 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1462306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1562306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 1662306a36Sopenharmony_ci * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 1762306a36Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 1862306a36Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 1962306a36Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE. 2062306a36Sopenharmony_ci * 2162306a36Sopenharmony_ci * The above copyright notice and this permission notice (including the 2262306a36Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions 2362306a36Sopenharmony_ci * of the Software. 2462306a36Sopenharmony_ci * 2562306a36Sopenharmony_ci */ 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#include <linux/firmware.h> 2862306a36Sopenharmony_ci#include <linux/module.h> 2962306a36Sopenharmony_ci#include <linux/dmi.h> 3062306a36Sopenharmony_ci#include <linux/pci.h> 3162306a36Sopenharmony_ci#include <linux/debugfs.h> 3262306a36Sopenharmony_ci#include <drm/drm_drv.h> 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#include "amdgpu.h" 3562306a36Sopenharmony_ci#include "amdgpu_pm.h" 3662306a36Sopenharmony_ci#include "amdgpu_vcn.h" 3762306a36Sopenharmony_ci#include "soc15d.h" 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci/* Firmware Names */ 4062306a36Sopenharmony_ci#define FIRMWARE_RAVEN "amdgpu/raven_vcn.bin" 4162306a36Sopenharmony_ci#define FIRMWARE_PICASSO "amdgpu/picasso_vcn.bin" 4262306a36Sopenharmony_ci#define FIRMWARE_RAVEN2 "amdgpu/raven2_vcn.bin" 4362306a36Sopenharmony_ci#define FIRMWARE_ARCTURUS "amdgpu/arcturus_vcn.bin" 4462306a36Sopenharmony_ci#define FIRMWARE_RENOIR "amdgpu/renoir_vcn.bin" 4562306a36Sopenharmony_ci#define FIRMWARE_GREEN_SARDINE "amdgpu/green_sardine_vcn.bin" 4662306a36Sopenharmony_ci#define FIRMWARE_NAVI10 "amdgpu/navi10_vcn.bin" 4762306a36Sopenharmony_ci#define FIRMWARE_NAVI14 "amdgpu/navi14_vcn.bin" 4862306a36Sopenharmony_ci#define FIRMWARE_NAVI12 "amdgpu/navi12_vcn.bin" 4962306a36Sopenharmony_ci#define FIRMWARE_SIENNA_CICHLID "amdgpu/sienna_cichlid_vcn.bin" 5062306a36Sopenharmony_ci#define FIRMWARE_NAVY_FLOUNDER "amdgpu/navy_flounder_vcn.bin" 5162306a36Sopenharmony_ci#define FIRMWARE_VANGOGH "amdgpu/vangogh_vcn.bin" 5262306a36Sopenharmony_ci#define FIRMWARE_DIMGREY_CAVEFISH "amdgpu/dimgrey_cavefish_vcn.bin" 5362306a36Sopenharmony_ci#define FIRMWARE_ALDEBARAN "amdgpu/aldebaran_vcn.bin" 5462306a36Sopenharmony_ci#define FIRMWARE_BEIGE_GOBY "amdgpu/beige_goby_vcn.bin" 5562306a36Sopenharmony_ci#define FIRMWARE_YELLOW_CARP "amdgpu/yellow_carp_vcn.bin" 5662306a36Sopenharmony_ci#define FIRMWARE_VCN_3_1_2 "amdgpu/vcn_3_1_2.bin" 5762306a36Sopenharmony_ci#define FIRMWARE_VCN4_0_0 "amdgpu/vcn_4_0_0.bin" 5862306a36Sopenharmony_ci#define FIRMWARE_VCN4_0_2 "amdgpu/vcn_4_0_2.bin" 5962306a36Sopenharmony_ci#define FIRMWARE_VCN4_0_3 "amdgpu/vcn_4_0_3.bin" 6062306a36Sopenharmony_ci#define FIRMWARE_VCN4_0_4 "amdgpu/vcn_4_0_4.bin" 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_RAVEN); 6362306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_PICASSO); 6462306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_RAVEN2); 6562306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_ARCTURUS); 6662306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_RENOIR); 6762306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_GREEN_SARDINE); 6862306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_ALDEBARAN); 6962306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_NAVI10); 7062306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_NAVI14); 7162306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_NAVI12); 7262306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_SIENNA_CICHLID); 7362306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_NAVY_FLOUNDER); 7462306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_VANGOGH); 7562306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_DIMGREY_CAVEFISH); 7662306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_BEIGE_GOBY); 7762306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_YELLOW_CARP); 7862306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_VCN_3_1_2); 7962306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_VCN4_0_0); 8062306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_VCN4_0_2); 8162306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_VCN4_0_3); 8262306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_VCN4_0_4); 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistatic void amdgpu_vcn_idle_work_handler(struct work_struct *work); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ciint amdgpu_vcn_early_init(struct amdgpu_device *adev) 8762306a36Sopenharmony_ci{ 8862306a36Sopenharmony_ci char ucode_prefix[30]; 8962306a36Sopenharmony_ci char fw_name[40]; 9062306a36Sopenharmony_ci int r; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci amdgpu_ucode_ip_version_decode(adev, UVD_HWIP, ucode_prefix, sizeof(ucode_prefix)); 9362306a36Sopenharmony_ci snprintf(fw_name, sizeof(fw_name), "amdgpu/%s.bin", ucode_prefix); 9462306a36Sopenharmony_ci r = amdgpu_ucode_request(adev, &adev->vcn.fw, fw_name); 9562306a36Sopenharmony_ci if (r) 9662306a36Sopenharmony_ci amdgpu_ucode_release(&adev->vcn.fw); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci return r; 9962306a36Sopenharmony_ci} 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ciint amdgpu_vcn_sw_init(struct amdgpu_device *adev) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci unsigned long bo_size; 10462306a36Sopenharmony_ci const struct common_firmware_header *hdr; 10562306a36Sopenharmony_ci unsigned char fw_check; 10662306a36Sopenharmony_ci unsigned int fw_shared_size, log_offset; 10762306a36Sopenharmony_ci int i, r; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci INIT_DELAYED_WORK(&adev->vcn.idle_work, amdgpu_vcn_idle_work_handler); 11062306a36Sopenharmony_ci mutex_init(&adev->vcn.vcn_pg_lock); 11162306a36Sopenharmony_ci mutex_init(&adev->vcn.vcn1_jpeg1_workaround); 11262306a36Sopenharmony_ci atomic_set(&adev->vcn.total_submission_cnt, 0); 11362306a36Sopenharmony_ci for (i = 0; i < adev->vcn.num_vcn_inst; i++) 11462306a36Sopenharmony_ci atomic_set(&adev->vcn.inst[i].dpg_enc_submission_cnt, 0); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci if ((adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) && 11762306a36Sopenharmony_ci (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG)) 11862306a36Sopenharmony_ci adev->vcn.indirect_sram = true; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci /* 12162306a36Sopenharmony_ci * Some Steam Deck's BIOS versions are incompatible with the 12262306a36Sopenharmony_ci * indirect SRAM mode, leading to amdgpu being unable to get 12362306a36Sopenharmony_ci * properly probed (and even potentially crashing the kernel). 12462306a36Sopenharmony_ci * Hence, check for these versions here - notice this is 12562306a36Sopenharmony_ci * restricted to Vangogh (Deck's APU). 12662306a36Sopenharmony_ci */ 12762306a36Sopenharmony_ci if (adev->ip_versions[UVD_HWIP][0] == IP_VERSION(3, 0, 2)) { 12862306a36Sopenharmony_ci const char *bios_ver = dmi_get_system_info(DMI_BIOS_VERSION); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci if (bios_ver && (!strncmp("F7A0113", bios_ver, 7) || 13162306a36Sopenharmony_ci !strncmp("F7A0114", bios_ver, 7))) { 13262306a36Sopenharmony_ci adev->vcn.indirect_sram = false; 13362306a36Sopenharmony_ci dev_info(adev->dev, 13462306a36Sopenharmony_ci "Steam Deck quirk: indirect SRAM disabled on BIOS %s\n", bios_ver); 13562306a36Sopenharmony_ci } 13662306a36Sopenharmony_ci } 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci hdr = (const struct common_firmware_header *)adev->vcn.fw->data; 13962306a36Sopenharmony_ci adev->vcn.fw_version = le32_to_cpu(hdr->ucode_version); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci /* Bit 20-23, it is encode major and non-zero for new naming convention. 14262306a36Sopenharmony_ci * This field is part of version minor and DRM_DISABLED_FLAG in old naming 14362306a36Sopenharmony_ci * convention. Since the l:wq!atest version minor is 0x5B and DRM_DISABLED_FLAG 14462306a36Sopenharmony_ci * is zero in old naming convention, this field is always zero so far. 14562306a36Sopenharmony_ci * These four bits are used to tell which naming convention is present. 14662306a36Sopenharmony_ci */ 14762306a36Sopenharmony_ci fw_check = (le32_to_cpu(hdr->ucode_version) >> 20) & 0xf; 14862306a36Sopenharmony_ci if (fw_check) { 14962306a36Sopenharmony_ci unsigned int dec_ver, enc_major, enc_minor, vep, fw_rev; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci fw_rev = le32_to_cpu(hdr->ucode_version) & 0xfff; 15262306a36Sopenharmony_ci enc_minor = (le32_to_cpu(hdr->ucode_version) >> 12) & 0xff; 15362306a36Sopenharmony_ci enc_major = fw_check; 15462306a36Sopenharmony_ci dec_ver = (le32_to_cpu(hdr->ucode_version) >> 24) & 0xf; 15562306a36Sopenharmony_ci vep = (le32_to_cpu(hdr->ucode_version) >> 28) & 0xf; 15662306a36Sopenharmony_ci DRM_INFO("Found VCN firmware Version ENC: %u.%u DEC: %u VEP: %u Revision: %u\n", 15762306a36Sopenharmony_ci enc_major, enc_minor, dec_ver, vep, fw_rev); 15862306a36Sopenharmony_ci } else { 15962306a36Sopenharmony_ci unsigned int version_major, version_minor, family_id; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci family_id = le32_to_cpu(hdr->ucode_version) & 0xff; 16262306a36Sopenharmony_ci version_major = (le32_to_cpu(hdr->ucode_version) >> 24) & 0xff; 16362306a36Sopenharmony_ci version_minor = (le32_to_cpu(hdr->ucode_version) >> 8) & 0xff; 16462306a36Sopenharmony_ci DRM_INFO("Found VCN firmware Version: %u.%u Family ID: %u\n", 16562306a36Sopenharmony_ci version_major, version_minor, family_id); 16662306a36Sopenharmony_ci } 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci bo_size = AMDGPU_VCN_STACK_SIZE + AMDGPU_VCN_CONTEXT_SIZE; 16962306a36Sopenharmony_ci if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) 17062306a36Sopenharmony_ci bo_size += AMDGPU_GPU_PAGE_ALIGN(le32_to_cpu(hdr->ucode_size_bytes) + 8); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci if (adev->ip_versions[UVD_HWIP][0] >= IP_VERSION(4, 0, 0)) { 17362306a36Sopenharmony_ci fw_shared_size = AMDGPU_GPU_PAGE_ALIGN(sizeof(struct amdgpu_vcn4_fw_shared)); 17462306a36Sopenharmony_ci log_offset = offsetof(struct amdgpu_vcn4_fw_shared, fw_log); 17562306a36Sopenharmony_ci } else { 17662306a36Sopenharmony_ci fw_shared_size = AMDGPU_GPU_PAGE_ALIGN(sizeof(struct amdgpu_fw_shared)); 17762306a36Sopenharmony_ci log_offset = offsetof(struct amdgpu_fw_shared, fw_log); 17862306a36Sopenharmony_ci } 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci bo_size += fw_shared_size; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci if (amdgpu_vcnfw_log) 18362306a36Sopenharmony_ci bo_size += AMDGPU_VCNFW_LOG_SIZE; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci for (i = 0; i < adev->vcn.num_vcn_inst; i++) { 18662306a36Sopenharmony_ci if (adev->vcn.harvest_config & (1 << i)) 18762306a36Sopenharmony_ci continue; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci r = amdgpu_bo_create_kernel(adev, bo_size, PAGE_SIZE, 19062306a36Sopenharmony_ci AMDGPU_GEM_DOMAIN_VRAM | 19162306a36Sopenharmony_ci AMDGPU_GEM_DOMAIN_GTT, 19262306a36Sopenharmony_ci &adev->vcn.inst[i].vcpu_bo, 19362306a36Sopenharmony_ci &adev->vcn.inst[i].gpu_addr, 19462306a36Sopenharmony_ci &adev->vcn.inst[i].cpu_addr); 19562306a36Sopenharmony_ci if (r) { 19662306a36Sopenharmony_ci dev_err(adev->dev, "(%d) failed to allocate vcn bo\n", r); 19762306a36Sopenharmony_ci return r; 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci adev->vcn.inst[i].fw_shared.cpu_addr = adev->vcn.inst[i].cpu_addr + 20162306a36Sopenharmony_ci bo_size - fw_shared_size; 20262306a36Sopenharmony_ci adev->vcn.inst[i].fw_shared.gpu_addr = adev->vcn.inst[i].gpu_addr + 20362306a36Sopenharmony_ci bo_size - fw_shared_size; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci adev->vcn.inst[i].fw_shared.mem_size = fw_shared_size; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci if (amdgpu_vcnfw_log) { 20862306a36Sopenharmony_ci adev->vcn.inst[i].fw_shared.cpu_addr -= AMDGPU_VCNFW_LOG_SIZE; 20962306a36Sopenharmony_ci adev->vcn.inst[i].fw_shared.gpu_addr -= AMDGPU_VCNFW_LOG_SIZE; 21062306a36Sopenharmony_ci adev->vcn.inst[i].fw_shared.log_offset = log_offset; 21162306a36Sopenharmony_ci } 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci if (adev->vcn.indirect_sram) { 21462306a36Sopenharmony_ci r = amdgpu_bo_create_kernel(adev, 64 * 2 * 4, PAGE_SIZE, 21562306a36Sopenharmony_ci AMDGPU_GEM_DOMAIN_VRAM | 21662306a36Sopenharmony_ci AMDGPU_GEM_DOMAIN_GTT, 21762306a36Sopenharmony_ci &adev->vcn.inst[i].dpg_sram_bo, 21862306a36Sopenharmony_ci &adev->vcn.inst[i].dpg_sram_gpu_addr, 21962306a36Sopenharmony_ci &adev->vcn.inst[i].dpg_sram_cpu_addr); 22062306a36Sopenharmony_ci if (r) { 22162306a36Sopenharmony_ci dev_err(adev->dev, "VCN %d (%d) failed to allocate DPG bo\n", i, r); 22262306a36Sopenharmony_ci return r; 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci } 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci return 0; 22862306a36Sopenharmony_ci} 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ciint amdgpu_vcn_sw_fini(struct amdgpu_device *adev) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci int i, j; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci for (j = 0; j < adev->vcn.num_vcn_inst; ++j) { 23562306a36Sopenharmony_ci if (adev->vcn.harvest_config & (1 << j)) 23662306a36Sopenharmony_ci continue; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci amdgpu_bo_free_kernel( 23962306a36Sopenharmony_ci &adev->vcn.inst[j].dpg_sram_bo, 24062306a36Sopenharmony_ci &adev->vcn.inst[j].dpg_sram_gpu_addr, 24162306a36Sopenharmony_ci (void **)&adev->vcn.inst[j].dpg_sram_cpu_addr); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci kvfree(adev->vcn.inst[j].saved_bo); 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci amdgpu_bo_free_kernel(&adev->vcn.inst[j].vcpu_bo, 24662306a36Sopenharmony_ci &adev->vcn.inst[j].gpu_addr, 24762306a36Sopenharmony_ci (void **)&adev->vcn.inst[j].cpu_addr); 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci amdgpu_ring_fini(&adev->vcn.inst[j].ring_dec); 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci for (i = 0; i < adev->vcn.num_enc_rings; ++i) 25262306a36Sopenharmony_ci amdgpu_ring_fini(&adev->vcn.inst[j].ring_enc[i]); 25362306a36Sopenharmony_ci } 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci amdgpu_ucode_release(&adev->vcn.fw); 25662306a36Sopenharmony_ci mutex_destroy(&adev->vcn.vcn1_jpeg1_workaround); 25762306a36Sopenharmony_ci mutex_destroy(&adev->vcn.vcn_pg_lock); 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci return 0; 26062306a36Sopenharmony_ci} 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci/* from vcn4 and above, only unified queue is used */ 26362306a36Sopenharmony_cistatic bool amdgpu_vcn_using_unified_queue(struct amdgpu_ring *ring) 26462306a36Sopenharmony_ci{ 26562306a36Sopenharmony_ci struct amdgpu_device *adev = ring->adev; 26662306a36Sopenharmony_ci bool ret = false; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci if (adev->ip_versions[UVD_HWIP][0] >= IP_VERSION(4, 0, 0)) 26962306a36Sopenharmony_ci ret = true; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci return ret; 27262306a36Sopenharmony_ci} 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_cibool amdgpu_vcn_is_disabled_vcn(struct amdgpu_device *adev, enum vcn_ring_type type, uint32_t vcn_instance) 27562306a36Sopenharmony_ci{ 27662306a36Sopenharmony_ci bool ret = false; 27762306a36Sopenharmony_ci int vcn_config = adev->vcn.vcn_config[vcn_instance]; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci if ((type == VCN_ENCODE_RING) && (vcn_config & VCN_BLOCK_ENCODE_DISABLE_MASK)) 28062306a36Sopenharmony_ci ret = true; 28162306a36Sopenharmony_ci else if ((type == VCN_DECODE_RING) && (vcn_config & VCN_BLOCK_DECODE_DISABLE_MASK)) 28262306a36Sopenharmony_ci ret = true; 28362306a36Sopenharmony_ci else if ((type == VCN_UNIFIED_RING) && (vcn_config & VCN_BLOCK_QUEUE_DISABLE_MASK)) 28462306a36Sopenharmony_ci ret = true; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci return ret; 28762306a36Sopenharmony_ci} 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ciint amdgpu_vcn_suspend(struct amdgpu_device *adev) 29062306a36Sopenharmony_ci{ 29162306a36Sopenharmony_ci unsigned int size; 29262306a36Sopenharmony_ci void *ptr; 29362306a36Sopenharmony_ci int i, idx; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci bool in_ras_intr = amdgpu_ras_intr_triggered(); 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci cancel_delayed_work_sync(&adev->vcn.idle_work); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci /* err_event_athub will corrupt VCPU buffer, so we need to 30062306a36Sopenharmony_ci * restore fw data and clear buffer in amdgpu_vcn_resume() */ 30162306a36Sopenharmony_ci if (in_ras_intr) 30262306a36Sopenharmony_ci return 0; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci for (i = 0; i < adev->vcn.num_vcn_inst; ++i) { 30562306a36Sopenharmony_ci if (adev->vcn.harvest_config & (1 << i)) 30662306a36Sopenharmony_ci continue; 30762306a36Sopenharmony_ci if (adev->vcn.inst[i].vcpu_bo == NULL) 30862306a36Sopenharmony_ci return 0; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci size = amdgpu_bo_size(adev->vcn.inst[i].vcpu_bo); 31162306a36Sopenharmony_ci ptr = adev->vcn.inst[i].cpu_addr; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci adev->vcn.inst[i].saved_bo = kvmalloc(size, GFP_KERNEL); 31462306a36Sopenharmony_ci if (!adev->vcn.inst[i].saved_bo) 31562306a36Sopenharmony_ci return -ENOMEM; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci if (drm_dev_enter(adev_to_drm(adev), &idx)) { 31862306a36Sopenharmony_ci memcpy_fromio(adev->vcn.inst[i].saved_bo, ptr, size); 31962306a36Sopenharmony_ci drm_dev_exit(idx); 32062306a36Sopenharmony_ci } 32162306a36Sopenharmony_ci } 32262306a36Sopenharmony_ci return 0; 32362306a36Sopenharmony_ci} 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ciint amdgpu_vcn_resume(struct amdgpu_device *adev) 32662306a36Sopenharmony_ci{ 32762306a36Sopenharmony_ci unsigned int size; 32862306a36Sopenharmony_ci void *ptr; 32962306a36Sopenharmony_ci int i, idx; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci for (i = 0; i < adev->vcn.num_vcn_inst; ++i) { 33262306a36Sopenharmony_ci if (adev->vcn.harvest_config & (1 << i)) 33362306a36Sopenharmony_ci continue; 33462306a36Sopenharmony_ci if (adev->vcn.inst[i].vcpu_bo == NULL) 33562306a36Sopenharmony_ci return -EINVAL; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci size = amdgpu_bo_size(adev->vcn.inst[i].vcpu_bo); 33862306a36Sopenharmony_ci ptr = adev->vcn.inst[i].cpu_addr; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci if (adev->vcn.inst[i].saved_bo != NULL) { 34162306a36Sopenharmony_ci if (drm_dev_enter(adev_to_drm(adev), &idx)) { 34262306a36Sopenharmony_ci memcpy_toio(ptr, adev->vcn.inst[i].saved_bo, size); 34362306a36Sopenharmony_ci drm_dev_exit(idx); 34462306a36Sopenharmony_ci } 34562306a36Sopenharmony_ci kvfree(adev->vcn.inst[i].saved_bo); 34662306a36Sopenharmony_ci adev->vcn.inst[i].saved_bo = NULL; 34762306a36Sopenharmony_ci } else { 34862306a36Sopenharmony_ci const struct common_firmware_header *hdr; 34962306a36Sopenharmony_ci unsigned int offset; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci hdr = (const struct common_firmware_header *)adev->vcn.fw->data; 35262306a36Sopenharmony_ci if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) { 35362306a36Sopenharmony_ci offset = le32_to_cpu(hdr->ucode_array_offset_bytes); 35462306a36Sopenharmony_ci if (drm_dev_enter(adev_to_drm(adev), &idx)) { 35562306a36Sopenharmony_ci memcpy_toio(adev->vcn.inst[i].cpu_addr, adev->vcn.fw->data + offset, 35662306a36Sopenharmony_ci le32_to_cpu(hdr->ucode_size_bytes)); 35762306a36Sopenharmony_ci drm_dev_exit(idx); 35862306a36Sopenharmony_ci } 35962306a36Sopenharmony_ci size -= le32_to_cpu(hdr->ucode_size_bytes); 36062306a36Sopenharmony_ci ptr += le32_to_cpu(hdr->ucode_size_bytes); 36162306a36Sopenharmony_ci } 36262306a36Sopenharmony_ci memset_io(ptr, 0, size); 36362306a36Sopenharmony_ci } 36462306a36Sopenharmony_ci } 36562306a36Sopenharmony_ci return 0; 36662306a36Sopenharmony_ci} 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_cistatic void amdgpu_vcn_idle_work_handler(struct work_struct *work) 36962306a36Sopenharmony_ci{ 37062306a36Sopenharmony_ci struct amdgpu_device *adev = 37162306a36Sopenharmony_ci container_of(work, struct amdgpu_device, vcn.idle_work.work); 37262306a36Sopenharmony_ci unsigned int fences = 0, fence[AMDGPU_MAX_VCN_INSTANCES] = {0}; 37362306a36Sopenharmony_ci unsigned int i, j; 37462306a36Sopenharmony_ci int r = 0; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci for (j = 0; j < adev->vcn.num_vcn_inst; ++j) { 37762306a36Sopenharmony_ci if (adev->vcn.harvest_config & (1 << j)) 37862306a36Sopenharmony_ci continue; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci for (i = 0; i < adev->vcn.num_enc_rings; ++i) 38162306a36Sopenharmony_ci fence[j] += amdgpu_fence_count_emitted(&adev->vcn.inst[j].ring_enc[i]); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) { 38462306a36Sopenharmony_ci struct dpg_pause_state new_state; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci if (fence[j] || 38762306a36Sopenharmony_ci unlikely(atomic_read(&adev->vcn.inst[j].dpg_enc_submission_cnt))) 38862306a36Sopenharmony_ci new_state.fw_based = VCN_DPG_STATE__PAUSE; 38962306a36Sopenharmony_ci else 39062306a36Sopenharmony_ci new_state.fw_based = VCN_DPG_STATE__UNPAUSE; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci adev->vcn.pause_dpg_mode(adev, j, &new_state); 39362306a36Sopenharmony_ci } 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci fence[j] += amdgpu_fence_count_emitted(&adev->vcn.inst[j].ring_dec); 39662306a36Sopenharmony_ci fences += fence[j]; 39762306a36Sopenharmony_ci } 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci if (!fences && !atomic_read(&adev->vcn.total_submission_cnt)) { 40062306a36Sopenharmony_ci amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_VCN, 40162306a36Sopenharmony_ci AMD_PG_STATE_GATE); 40262306a36Sopenharmony_ci r = amdgpu_dpm_switch_power_profile(adev, PP_SMC_POWER_PROFILE_VIDEO, 40362306a36Sopenharmony_ci false); 40462306a36Sopenharmony_ci if (r) 40562306a36Sopenharmony_ci dev_warn(adev->dev, "(%d) failed to disable video power profile mode\n", r); 40662306a36Sopenharmony_ci } else { 40762306a36Sopenharmony_ci schedule_delayed_work(&adev->vcn.idle_work, VCN_IDLE_TIMEOUT); 40862306a36Sopenharmony_ci } 40962306a36Sopenharmony_ci} 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_civoid amdgpu_vcn_ring_begin_use(struct amdgpu_ring *ring) 41262306a36Sopenharmony_ci{ 41362306a36Sopenharmony_ci struct amdgpu_device *adev = ring->adev; 41462306a36Sopenharmony_ci int r = 0; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci atomic_inc(&adev->vcn.total_submission_cnt); 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci if (!cancel_delayed_work_sync(&adev->vcn.idle_work)) { 41962306a36Sopenharmony_ci r = amdgpu_dpm_switch_power_profile(adev, PP_SMC_POWER_PROFILE_VIDEO, 42062306a36Sopenharmony_ci true); 42162306a36Sopenharmony_ci if (r) 42262306a36Sopenharmony_ci dev_warn(adev->dev, "(%d) failed to switch to video power profile mode\n", r); 42362306a36Sopenharmony_ci } 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci mutex_lock(&adev->vcn.vcn_pg_lock); 42662306a36Sopenharmony_ci amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_VCN, 42762306a36Sopenharmony_ci AMD_PG_STATE_UNGATE); 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) { 43062306a36Sopenharmony_ci struct dpg_pause_state new_state; 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci if (ring->funcs->type == AMDGPU_RING_TYPE_VCN_ENC) { 43362306a36Sopenharmony_ci atomic_inc(&adev->vcn.inst[ring->me].dpg_enc_submission_cnt); 43462306a36Sopenharmony_ci new_state.fw_based = VCN_DPG_STATE__PAUSE; 43562306a36Sopenharmony_ci } else { 43662306a36Sopenharmony_ci unsigned int fences = 0; 43762306a36Sopenharmony_ci unsigned int i; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci for (i = 0; i < adev->vcn.num_enc_rings; ++i) 44062306a36Sopenharmony_ci fences += amdgpu_fence_count_emitted(&adev->vcn.inst[ring->me].ring_enc[i]); 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci if (fences || atomic_read(&adev->vcn.inst[ring->me].dpg_enc_submission_cnt)) 44362306a36Sopenharmony_ci new_state.fw_based = VCN_DPG_STATE__PAUSE; 44462306a36Sopenharmony_ci else 44562306a36Sopenharmony_ci new_state.fw_based = VCN_DPG_STATE__UNPAUSE; 44662306a36Sopenharmony_ci } 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci adev->vcn.pause_dpg_mode(adev, ring->me, &new_state); 44962306a36Sopenharmony_ci } 45062306a36Sopenharmony_ci mutex_unlock(&adev->vcn.vcn_pg_lock); 45162306a36Sopenharmony_ci} 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_civoid amdgpu_vcn_ring_end_use(struct amdgpu_ring *ring) 45462306a36Sopenharmony_ci{ 45562306a36Sopenharmony_ci if (ring->adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG && 45662306a36Sopenharmony_ci ring->funcs->type == AMDGPU_RING_TYPE_VCN_ENC) 45762306a36Sopenharmony_ci atomic_dec(&ring->adev->vcn.inst[ring->me].dpg_enc_submission_cnt); 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci atomic_dec(&ring->adev->vcn.total_submission_cnt); 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci schedule_delayed_work(&ring->adev->vcn.idle_work, VCN_IDLE_TIMEOUT); 46262306a36Sopenharmony_ci} 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ciint amdgpu_vcn_dec_ring_test_ring(struct amdgpu_ring *ring) 46562306a36Sopenharmony_ci{ 46662306a36Sopenharmony_ci struct amdgpu_device *adev = ring->adev; 46762306a36Sopenharmony_ci uint32_t tmp = 0; 46862306a36Sopenharmony_ci unsigned int i; 46962306a36Sopenharmony_ci int r; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci /* VCN in SRIOV does not support direct register read/write */ 47262306a36Sopenharmony_ci if (amdgpu_sriov_vf(adev)) 47362306a36Sopenharmony_ci return 0; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci WREG32(adev->vcn.inst[ring->me].external.scratch9, 0xCAFEDEAD); 47662306a36Sopenharmony_ci r = amdgpu_ring_alloc(ring, 3); 47762306a36Sopenharmony_ci if (r) 47862306a36Sopenharmony_ci return r; 47962306a36Sopenharmony_ci amdgpu_ring_write(ring, PACKET0(adev->vcn.internal.scratch9, 0)); 48062306a36Sopenharmony_ci amdgpu_ring_write(ring, 0xDEADBEEF); 48162306a36Sopenharmony_ci amdgpu_ring_commit(ring); 48262306a36Sopenharmony_ci for (i = 0; i < adev->usec_timeout; i++) { 48362306a36Sopenharmony_ci tmp = RREG32(adev->vcn.inst[ring->me].external.scratch9); 48462306a36Sopenharmony_ci if (tmp == 0xDEADBEEF) 48562306a36Sopenharmony_ci break; 48662306a36Sopenharmony_ci udelay(1); 48762306a36Sopenharmony_ci } 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci if (i >= adev->usec_timeout) 49062306a36Sopenharmony_ci r = -ETIMEDOUT; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci return r; 49362306a36Sopenharmony_ci} 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ciint amdgpu_vcn_dec_sw_ring_test_ring(struct amdgpu_ring *ring) 49662306a36Sopenharmony_ci{ 49762306a36Sopenharmony_ci struct amdgpu_device *adev = ring->adev; 49862306a36Sopenharmony_ci uint32_t rptr; 49962306a36Sopenharmony_ci unsigned int i; 50062306a36Sopenharmony_ci int r; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci if (amdgpu_sriov_vf(adev)) 50362306a36Sopenharmony_ci return 0; 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci r = amdgpu_ring_alloc(ring, 16); 50662306a36Sopenharmony_ci if (r) 50762306a36Sopenharmony_ci return r; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci rptr = amdgpu_ring_get_rptr(ring); 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci amdgpu_ring_write(ring, VCN_DEC_SW_CMD_END); 51262306a36Sopenharmony_ci amdgpu_ring_commit(ring); 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci for (i = 0; i < adev->usec_timeout; i++) { 51562306a36Sopenharmony_ci if (amdgpu_ring_get_rptr(ring) != rptr) 51662306a36Sopenharmony_ci break; 51762306a36Sopenharmony_ci udelay(1); 51862306a36Sopenharmony_ci } 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci if (i >= adev->usec_timeout) 52162306a36Sopenharmony_ci r = -ETIMEDOUT; 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci return r; 52462306a36Sopenharmony_ci} 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_cistatic int amdgpu_vcn_dec_send_msg(struct amdgpu_ring *ring, 52762306a36Sopenharmony_ci struct amdgpu_ib *ib_msg, 52862306a36Sopenharmony_ci struct dma_fence **fence) 52962306a36Sopenharmony_ci{ 53062306a36Sopenharmony_ci u64 addr = AMDGPU_GPU_PAGE_ALIGN(ib_msg->gpu_addr); 53162306a36Sopenharmony_ci struct amdgpu_device *adev = ring->adev; 53262306a36Sopenharmony_ci struct dma_fence *f = NULL; 53362306a36Sopenharmony_ci struct amdgpu_job *job; 53462306a36Sopenharmony_ci struct amdgpu_ib *ib; 53562306a36Sopenharmony_ci int i, r; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci r = amdgpu_job_alloc_with_ib(ring->adev, NULL, NULL, 53862306a36Sopenharmony_ci 64, AMDGPU_IB_POOL_DIRECT, 53962306a36Sopenharmony_ci &job); 54062306a36Sopenharmony_ci if (r) 54162306a36Sopenharmony_ci goto err; 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci ib = &job->ibs[0]; 54462306a36Sopenharmony_ci ib->ptr[0] = PACKET0(adev->vcn.internal.data0, 0); 54562306a36Sopenharmony_ci ib->ptr[1] = addr; 54662306a36Sopenharmony_ci ib->ptr[2] = PACKET0(adev->vcn.internal.data1, 0); 54762306a36Sopenharmony_ci ib->ptr[3] = addr >> 32; 54862306a36Sopenharmony_ci ib->ptr[4] = PACKET0(adev->vcn.internal.cmd, 0); 54962306a36Sopenharmony_ci ib->ptr[5] = 0; 55062306a36Sopenharmony_ci for (i = 6; i < 16; i += 2) { 55162306a36Sopenharmony_ci ib->ptr[i] = PACKET0(adev->vcn.internal.nop, 0); 55262306a36Sopenharmony_ci ib->ptr[i+1] = 0; 55362306a36Sopenharmony_ci } 55462306a36Sopenharmony_ci ib->length_dw = 16; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci r = amdgpu_job_submit_direct(job, ring, &f); 55762306a36Sopenharmony_ci if (r) 55862306a36Sopenharmony_ci goto err_free; 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci amdgpu_ib_free(adev, ib_msg, f); 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci if (fence) 56362306a36Sopenharmony_ci *fence = dma_fence_get(f); 56462306a36Sopenharmony_ci dma_fence_put(f); 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci return 0; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_cierr_free: 56962306a36Sopenharmony_ci amdgpu_job_free(job); 57062306a36Sopenharmony_cierr: 57162306a36Sopenharmony_ci amdgpu_ib_free(adev, ib_msg, f); 57262306a36Sopenharmony_ci return r; 57362306a36Sopenharmony_ci} 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_cistatic int amdgpu_vcn_dec_get_create_msg(struct amdgpu_ring *ring, uint32_t handle, 57662306a36Sopenharmony_ci struct amdgpu_ib *ib) 57762306a36Sopenharmony_ci{ 57862306a36Sopenharmony_ci struct amdgpu_device *adev = ring->adev; 57962306a36Sopenharmony_ci uint32_t *msg; 58062306a36Sopenharmony_ci int r, i; 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci memset(ib, 0, sizeof(*ib)); 58362306a36Sopenharmony_ci r = amdgpu_ib_get(adev, NULL, AMDGPU_GPU_PAGE_SIZE * 2, 58462306a36Sopenharmony_ci AMDGPU_IB_POOL_DIRECT, 58562306a36Sopenharmony_ci ib); 58662306a36Sopenharmony_ci if (r) 58762306a36Sopenharmony_ci return r; 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci msg = (uint32_t *)AMDGPU_GPU_PAGE_ALIGN((unsigned long)ib->ptr); 59062306a36Sopenharmony_ci msg[0] = cpu_to_le32(0x00000028); 59162306a36Sopenharmony_ci msg[1] = cpu_to_le32(0x00000038); 59262306a36Sopenharmony_ci msg[2] = cpu_to_le32(0x00000001); 59362306a36Sopenharmony_ci msg[3] = cpu_to_le32(0x00000000); 59462306a36Sopenharmony_ci msg[4] = cpu_to_le32(handle); 59562306a36Sopenharmony_ci msg[5] = cpu_to_le32(0x00000000); 59662306a36Sopenharmony_ci msg[6] = cpu_to_le32(0x00000001); 59762306a36Sopenharmony_ci msg[7] = cpu_to_le32(0x00000028); 59862306a36Sopenharmony_ci msg[8] = cpu_to_le32(0x00000010); 59962306a36Sopenharmony_ci msg[9] = cpu_to_le32(0x00000000); 60062306a36Sopenharmony_ci msg[10] = cpu_to_le32(0x00000007); 60162306a36Sopenharmony_ci msg[11] = cpu_to_le32(0x00000000); 60262306a36Sopenharmony_ci msg[12] = cpu_to_le32(0x00000780); 60362306a36Sopenharmony_ci msg[13] = cpu_to_le32(0x00000440); 60462306a36Sopenharmony_ci for (i = 14; i < 1024; ++i) 60562306a36Sopenharmony_ci msg[i] = cpu_to_le32(0x0); 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci return 0; 60862306a36Sopenharmony_ci} 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_cistatic int amdgpu_vcn_dec_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle, 61162306a36Sopenharmony_ci struct amdgpu_ib *ib) 61262306a36Sopenharmony_ci{ 61362306a36Sopenharmony_ci struct amdgpu_device *adev = ring->adev; 61462306a36Sopenharmony_ci uint32_t *msg; 61562306a36Sopenharmony_ci int r, i; 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci memset(ib, 0, sizeof(*ib)); 61862306a36Sopenharmony_ci r = amdgpu_ib_get(adev, NULL, AMDGPU_GPU_PAGE_SIZE * 2, 61962306a36Sopenharmony_ci AMDGPU_IB_POOL_DIRECT, 62062306a36Sopenharmony_ci ib); 62162306a36Sopenharmony_ci if (r) 62262306a36Sopenharmony_ci return r; 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci msg = (uint32_t *)AMDGPU_GPU_PAGE_ALIGN((unsigned long)ib->ptr); 62562306a36Sopenharmony_ci msg[0] = cpu_to_le32(0x00000028); 62662306a36Sopenharmony_ci msg[1] = cpu_to_le32(0x00000018); 62762306a36Sopenharmony_ci msg[2] = cpu_to_le32(0x00000000); 62862306a36Sopenharmony_ci msg[3] = cpu_to_le32(0x00000002); 62962306a36Sopenharmony_ci msg[4] = cpu_to_le32(handle); 63062306a36Sopenharmony_ci msg[5] = cpu_to_le32(0x00000000); 63162306a36Sopenharmony_ci for (i = 6; i < 1024; ++i) 63262306a36Sopenharmony_ci msg[i] = cpu_to_le32(0x0); 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci return 0; 63562306a36Sopenharmony_ci} 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ciint amdgpu_vcn_dec_ring_test_ib(struct amdgpu_ring *ring, long timeout) 63862306a36Sopenharmony_ci{ 63962306a36Sopenharmony_ci struct dma_fence *fence = NULL; 64062306a36Sopenharmony_ci struct amdgpu_ib ib; 64162306a36Sopenharmony_ci long r; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci r = amdgpu_vcn_dec_get_create_msg(ring, 1, &ib); 64462306a36Sopenharmony_ci if (r) 64562306a36Sopenharmony_ci goto error; 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci r = amdgpu_vcn_dec_send_msg(ring, &ib, NULL); 64862306a36Sopenharmony_ci if (r) 64962306a36Sopenharmony_ci goto error; 65062306a36Sopenharmony_ci r = amdgpu_vcn_dec_get_destroy_msg(ring, 1, &ib); 65162306a36Sopenharmony_ci if (r) 65262306a36Sopenharmony_ci goto error; 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci r = amdgpu_vcn_dec_send_msg(ring, &ib, &fence); 65562306a36Sopenharmony_ci if (r) 65662306a36Sopenharmony_ci goto error; 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci r = dma_fence_wait_timeout(fence, false, timeout); 65962306a36Sopenharmony_ci if (r == 0) 66062306a36Sopenharmony_ci r = -ETIMEDOUT; 66162306a36Sopenharmony_ci else if (r > 0) 66262306a36Sopenharmony_ci r = 0; 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci dma_fence_put(fence); 66562306a36Sopenharmony_cierror: 66662306a36Sopenharmony_ci return r; 66762306a36Sopenharmony_ci} 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_cistatic uint32_t *amdgpu_vcn_unified_ring_ib_header(struct amdgpu_ib *ib, 67062306a36Sopenharmony_ci uint32_t ib_pack_in_dw, bool enc) 67162306a36Sopenharmony_ci{ 67262306a36Sopenharmony_ci uint32_t *ib_checksum; 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x00000010; /* single queue checksum */ 67562306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x30000002; 67662306a36Sopenharmony_ci ib_checksum = &ib->ptr[ib->length_dw++]; 67762306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = ib_pack_in_dw; 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x00000010; /* engine info */ 68062306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x30000001; 68162306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = enc ? 0x2 : 0x3; 68262306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = ib_pack_in_dw * sizeof(uint32_t); 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci return ib_checksum; 68562306a36Sopenharmony_ci} 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_cistatic void amdgpu_vcn_unified_ring_ib_checksum(uint32_t **ib_checksum, 68862306a36Sopenharmony_ci uint32_t ib_pack_in_dw) 68962306a36Sopenharmony_ci{ 69062306a36Sopenharmony_ci uint32_t i; 69162306a36Sopenharmony_ci uint32_t checksum = 0; 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci for (i = 0; i < ib_pack_in_dw; i++) 69462306a36Sopenharmony_ci checksum += *(*ib_checksum + 2 + i); 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci **ib_checksum = checksum; 69762306a36Sopenharmony_ci} 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_cistatic int amdgpu_vcn_dec_sw_send_msg(struct amdgpu_ring *ring, 70062306a36Sopenharmony_ci struct amdgpu_ib *ib_msg, 70162306a36Sopenharmony_ci struct dma_fence **fence) 70262306a36Sopenharmony_ci{ 70362306a36Sopenharmony_ci struct amdgpu_vcn_decode_buffer *decode_buffer = NULL; 70462306a36Sopenharmony_ci unsigned int ib_size_dw = 64; 70562306a36Sopenharmony_ci struct amdgpu_device *adev = ring->adev; 70662306a36Sopenharmony_ci struct dma_fence *f = NULL; 70762306a36Sopenharmony_ci struct amdgpu_job *job; 70862306a36Sopenharmony_ci struct amdgpu_ib *ib; 70962306a36Sopenharmony_ci uint64_t addr = AMDGPU_GPU_PAGE_ALIGN(ib_msg->gpu_addr); 71062306a36Sopenharmony_ci bool sq = amdgpu_vcn_using_unified_queue(ring); 71162306a36Sopenharmony_ci uint32_t *ib_checksum; 71262306a36Sopenharmony_ci uint32_t ib_pack_in_dw; 71362306a36Sopenharmony_ci int i, r; 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci if (sq) 71662306a36Sopenharmony_ci ib_size_dw += 8; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci r = amdgpu_job_alloc_with_ib(ring->adev, NULL, NULL, 71962306a36Sopenharmony_ci ib_size_dw * 4, AMDGPU_IB_POOL_DIRECT, 72062306a36Sopenharmony_ci &job); 72162306a36Sopenharmony_ci if (r) 72262306a36Sopenharmony_ci goto err; 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci ib = &job->ibs[0]; 72562306a36Sopenharmony_ci ib->length_dw = 0; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci /* single queue headers */ 72862306a36Sopenharmony_ci if (sq) { 72962306a36Sopenharmony_ci ib_pack_in_dw = sizeof(struct amdgpu_vcn_decode_buffer) / sizeof(uint32_t) 73062306a36Sopenharmony_ci + 4 + 2; /* engine info + decoding ib in dw */ 73162306a36Sopenharmony_ci ib_checksum = amdgpu_vcn_unified_ring_ib_header(ib, ib_pack_in_dw, false); 73262306a36Sopenharmony_ci } 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = sizeof(struct amdgpu_vcn_decode_buffer) + 8; 73562306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = cpu_to_le32(AMDGPU_VCN_IB_FLAG_DECODE_BUFFER); 73662306a36Sopenharmony_ci decode_buffer = (struct amdgpu_vcn_decode_buffer *)&(ib->ptr[ib->length_dw]); 73762306a36Sopenharmony_ci ib->length_dw += sizeof(struct amdgpu_vcn_decode_buffer) / 4; 73862306a36Sopenharmony_ci memset(decode_buffer, 0, sizeof(struct amdgpu_vcn_decode_buffer)); 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci decode_buffer->valid_buf_flag |= cpu_to_le32(AMDGPU_VCN_CMD_FLAG_MSG_BUFFER); 74162306a36Sopenharmony_ci decode_buffer->msg_buffer_address_hi = cpu_to_le32(addr >> 32); 74262306a36Sopenharmony_ci decode_buffer->msg_buffer_address_lo = cpu_to_le32(addr); 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci for (i = ib->length_dw; i < ib_size_dw; ++i) 74562306a36Sopenharmony_ci ib->ptr[i] = 0x0; 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci if (sq) 74862306a36Sopenharmony_ci amdgpu_vcn_unified_ring_ib_checksum(&ib_checksum, ib_pack_in_dw); 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci r = amdgpu_job_submit_direct(job, ring, &f); 75162306a36Sopenharmony_ci if (r) 75262306a36Sopenharmony_ci goto err_free; 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci amdgpu_ib_free(adev, ib_msg, f); 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci if (fence) 75762306a36Sopenharmony_ci *fence = dma_fence_get(f); 75862306a36Sopenharmony_ci dma_fence_put(f); 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci return 0; 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_cierr_free: 76362306a36Sopenharmony_ci amdgpu_job_free(job); 76462306a36Sopenharmony_cierr: 76562306a36Sopenharmony_ci amdgpu_ib_free(adev, ib_msg, f); 76662306a36Sopenharmony_ci return r; 76762306a36Sopenharmony_ci} 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ciint amdgpu_vcn_dec_sw_ring_test_ib(struct amdgpu_ring *ring, long timeout) 77062306a36Sopenharmony_ci{ 77162306a36Sopenharmony_ci struct dma_fence *fence = NULL; 77262306a36Sopenharmony_ci struct amdgpu_ib ib; 77362306a36Sopenharmony_ci long r; 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci r = amdgpu_vcn_dec_get_create_msg(ring, 1, &ib); 77662306a36Sopenharmony_ci if (r) 77762306a36Sopenharmony_ci goto error; 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci r = amdgpu_vcn_dec_sw_send_msg(ring, &ib, NULL); 78062306a36Sopenharmony_ci if (r) 78162306a36Sopenharmony_ci goto error; 78262306a36Sopenharmony_ci r = amdgpu_vcn_dec_get_destroy_msg(ring, 1, &ib); 78362306a36Sopenharmony_ci if (r) 78462306a36Sopenharmony_ci goto error; 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci r = amdgpu_vcn_dec_sw_send_msg(ring, &ib, &fence); 78762306a36Sopenharmony_ci if (r) 78862306a36Sopenharmony_ci goto error; 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci r = dma_fence_wait_timeout(fence, false, timeout); 79162306a36Sopenharmony_ci if (r == 0) 79262306a36Sopenharmony_ci r = -ETIMEDOUT; 79362306a36Sopenharmony_ci else if (r > 0) 79462306a36Sopenharmony_ci r = 0; 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci dma_fence_put(fence); 79762306a36Sopenharmony_cierror: 79862306a36Sopenharmony_ci return r; 79962306a36Sopenharmony_ci} 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ciint amdgpu_vcn_enc_ring_test_ring(struct amdgpu_ring *ring) 80262306a36Sopenharmony_ci{ 80362306a36Sopenharmony_ci struct amdgpu_device *adev = ring->adev; 80462306a36Sopenharmony_ci uint32_t rptr; 80562306a36Sopenharmony_ci unsigned int i; 80662306a36Sopenharmony_ci int r; 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci if (amdgpu_sriov_vf(adev)) 80962306a36Sopenharmony_ci return 0; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci r = amdgpu_ring_alloc(ring, 16); 81262306a36Sopenharmony_ci if (r) 81362306a36Sopenharmony_ci return r; 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci rptr = amdgpu_ring_get_rptr(ring); 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci amdgpu_ring_write(ring, VCN_ENC_CMD_END); 81862306a36Sopenharmony_ci amdgpu_ring_commit(ring); 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci for (i = 0; i < adev->usec_timeout; i++) { 82162306a36Sopenharmony_ci if (amdgpu_ring_get_rptr(ring) != rptr) 82262306a36Sopenharmony_ci break; 82362306a36Sopenharmony_ci udelay(1); 82462306a36Sopenharmony_ci } 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci if (i >= adev->usec_timeout) 82762306a36Sopenharmony_ci r = -ETIMEDOUT; 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci return r; 83062306a36Sopenharmony_ci} 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_cistatic int amdgpu_vcn_enc_get_create_msg(struct amdgpu_ring *ring, uint32_t handle, 83362306a36Sopenharmony_ci struct amdgpu_ib *ib_msg, 83462306a36Sopenharmony_ci struct dma_fence **fence) 83562306a36Sopenharmony_ci{ 83662306a36Sopenharmony_ci unsigned int ib_size_dw = 16; 83762306a36Sopenharmony_ci struct amdgpu_job *job; 83862306a36Sopenharmony_ci struct amdgpu_ib *ib; 83962306a36Sopenharmony_ci struct dma_fence *f = NULL; 84062306a36Sopenharmony_ci uint32_t *ib_checksum = NULL; 84162306a36Sopenharmony_ci uint64_t addr; 84262306a36Sopenharmony_ci bool sq = amdgpu_vcn_using_unified_queue(ring); 84362306a36Sopenharmony_ci int i, r; 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci if (sq) 84662306a36Sopenharmony_ci ib_size_dw += 8; 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci r = amdgpu_job_alloc_with_ib(ring->adev, NULL, NULL, 84962306a36Sopenharmony_ci ib_size_dw * 4, AMDGPU_IB_POOL_DIRECT, 85062306a36Sopenharmony_ci &job); 85162306a36Sopenharmony_ci if (r) 85262306a36Sopenharmony_ci return r; 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci ib = &job->ibs[0]; 85562306a36Sopenharmony_ci addr = AMDGPU_GPU_PAGE_ALIGN(ib_msg->gpu_addr); 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci ib->length_dw = 0; 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci if (sq) 86062306a36Sopenharmony_ci ib_checksum = amdgpu_vcn_unified_ring_ib_header(ib, 0x11, true); 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x00000018; 86362306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x00000001; /* session info */ 86462306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = handle; 86562306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = upper_32_bits(addr); 86662306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = addr; 86762306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x0000000b; 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x00000014; 87062306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x00000002; /* task info */ 87162306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x0000001c; 87262306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x00000000; 87362306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x00000000; 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x00000008; 87662306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x08000001; /* op initialize */ 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci for (i = ib->length_dw; i < ib_size_dw; ++i) 87962306a36Sopenharmony_ci ib->ptr[i] = 0x0; 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci if (sq) 88262306a36Sopenharmony_ci amdgpu_vcn_unified_ring_ib_checksum(&ib_checksum, 0x11); 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci r = amdgpu_job_submit_direct(job, ring, &f); 88562306a36Sopenharmony_ci if (r) 88662306a36Sopenharmony_ci goto err; 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci if (fence) 88962306a36Sopenharmony_ci *fence = dma_fence_get(f); 89062306a36Sopenharmony_ci dma_fence_put(f); 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci return 0; 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_cierr: 89562306a36Sopenharmony_ci amdgpu_job_free(job); 89662306a36Sopenharmony_ci return r; 89762306a36Sopenharmony_ci} 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_cistatic int amdgpu_vcn_enc_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle, 90062306a36Sopenharmony_ci struct amdgpu_ib *ib_msg, 90162306a36Sopenharmony_ci struct dma_fence **fence) 90262306a36Sopenharmony_ci{ 90362306a36Sopenharmony_ci unsigned int ib_size_dw = 16; 90462306a36Sopenharmony_ci struct amdgpu_job *job; 90562306a36Sopenharmony_ci struct amdgpu_ib *ib; 90662306a36Sopenharmony_ci struct dma_fence *f = NULL; 90762306a36Sopenharmony_ci uint32_t *ib_checksum = NULL; 90862306a36Sopenharmony_ci uint64_t addr; 90962306a36Sopenharmony_ci bool sq = amdgpu_vcn_using_unified_queue(ring); 91062306a36Sopenharmony_ci int i, r; 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci if (sq) 91362306a36Sopenharmony_ci ib_size_dw += 8; 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci r = amdgpu_job_alloc_with_ib(ring->adev, NULL, NULL, 91662306a36Sopenharmony_ci ib_size_dw * 4, AMDGPU_IB_POOL_DIRECT, 91762306a36Sopenharmony_ci &job); 91862306a36Sopenharmony_ci if (r) 91962306a36Sopenharmony_ci return r; 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci ib = &job->ibs[0]; 92262306a36Sopenharmony_ci addr = AMDGPU_GPU_PAGE_ALIGN(ib_msg->gpu_addr); 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci ib->length_dw = 0; 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci if (sq) 92762306a36Sopenharmony_ci ib_checksum = amdgpu_vcn_unified_ring_ib_header(ib, 0x11, true); 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x00000018; 93062306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x00000001; 93162306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = handle; 93262306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = upper_32_bits(addr); 93362306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = addr; 93462306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x0000000b; 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x00000014; 93762306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x00000002; 93862306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x0000001c; 93962306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x00000000; 94062306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x00000000; 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x00000008; 94362306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x08000002; /* op close session */ 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci for (i = ib->length_dw; i < ib_size_dw; ++i) 94662306a36Sopenharmony_ci ib->ptr[i] = 0x0; 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci if (sq) 94962306a36Sopenharmony_ci amdgpu_vcn_unified_ring_ib_checksum(&ib_checksum, 0x11); 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci r = amdgpu_job_submit_direct(job, ring, &f); 95262306a36Sopenharmony_ci if (r) 95362306a36Sopenharmony_ci goto err; 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci if (fence) 95662306a36Sopenharmony_ci *fence = dma_fence_get(f); 95762306a36Sopenharmony_ci dma_fence_put(f); 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci return 0; 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_cierr: 96262306a36Sopenharmony_ci amdgpu_job_free(job); 96362306a36Sopenharmony_ci return r; 96462306a36Sopenharmony_ci} 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ciint amdgpu_vcn_enc_ring_test_ib(struct amdgpu_ring *ring, long timeout) 96762306a36Sopenharmony_ci{ 96862306a36Sopenharmony_ci struct amdgpu_device *adev = ring->adev; 96962306a36Sopenharmony_ci struct dma_fence *fence = NULL; 97062306a36Sopenharmony_ci struct amdgpu_ib ib; 97162306a36Sopenharmony_ci long r; 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci memset(&ib, 0, sizeof(ib)); 97462306a36Sopenharmony_ci r = amdgpu_ib_get(adev, NULL, (128 << 10) + AMDGPU_GPU_PAGE_SIZE, 97562306a36Sopenharmony_ci AMDGPU_IB_POOL_DIRECT, 97662306a36Sopenharmony_ci &ib); 97762306a36Sopenharmony_ci if (r) 97862306a36Sopenharmony_ci return r; 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci r = amdgpu_vcn_enc_get_create_msg(ring, 1, &ib, NULL); 98162306a36Sopenharmony_ci if (r) 98262306a36Sopenharmony_ci goto error; 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci r = amdgpu_vcn_enc_get_destroy_msg(ring, 1, &ib, &fence); 98562306a36Sopenharmony_ci if (r) 98662306a36Sopenharmony_ci goto error; 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci r = dma_fence_wait_timeout(fence, false, timeout); 98962306a36Sopenharmony_ci if (r == 0) 99062306a36Sopenharmony_ci r = -ETIMEDOUT; 99162306a36Sopenharmony_ci else if (r > 0) 99262306a36Sopenharmony_ci r = 0; 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_cierror: 99562306a36Sopenharmony_ci amdgpu_ib_free(adev, &ib, fence); 99662306a36Sopenharmony_ci dma_fence_put(fence); 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci return r; 99962306a36Sopenharmony_ci} 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ciint amdgpu_vcn_unified_ring_test_ib(struct amdgpu_ring *ring, long timeout) 100262306a36Sopenharmony_ci{ 100362306a36Sopenharmony_ci struct amdgpu_device *adev = ring->adev; 100462306a36Sopenharmony_ci long r; 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci if (adev->ip_versions[UVD_HWIP][0] != IP_VERSION(4, 0, 3)) { 100762306a36Sopenharmony_ci r = amdgpu_vcn_enc_ring_test_ib(ring, timeout); 100862306a36Sopenharmony_ci if (r) 100962306a36Sopenharmony_ci goto error; 101062306a36Sopenharmony_ci } 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci r = amdgpu_vcn_dec_sw_ring_test_ib(ring, timeout); 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_cierror: 101562306a36Sopenharmony_ci return r; 101662306a36Sopenharmony_ci} 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_cienum amdgpu_ring_priority_level amdgpu_vcn_get_enc_ring_prio(int ring) 101962306a36Sopenharmony_ci{ 102062306a36Sopenharmony_ci switch (ring) { 102162306a36Sopenharmony_ci case 0: 102262306a36Sopenharmony_ci return AMDGPU_RING_PRIO_0; 102362306a36Sopenharmony_ci case 1: 102462306a36Sopenharmony_ci return AMDGPU_RING_PRIO_1; 102562306a36Sopenharmony_ci case 2: 102662306a36Sopenharmony_ci return AMDGPU_RING_PRIO_2; 102762306a36Sopenharmony_ci default: 102862306a36Sopenharmony_ci return AMDGPU_RING_PRIO_0; 102962306a36Sopenharmony_ci } 103062306a36Sopenharmony_ci} 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_civoid amdgpu_vcn_setup_ucode(struct amdgpu_device *adev) 103362306a36Sopenharmony_ci{ 103462306a36Sopenharmony_ci int i; 103562306a36Sopenharmony_ci unsigned int idx; 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { 103862306a36Sopenharmony_ci const struct common_firmware_header *hdr; 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci hdr = (const struct common_firmware_header *)adev->vcn.fw->data; 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci for (i = 0; i < adev->vcn.num_vcn_inst; i++) { 104362306a36Sopenharmony_ci if (adev->vcn.harvest_config & (1 << i)) 104462306a36Sopenharmony_ci continue; 104562306a36Sopenharmony_ci /* currently only support 2 FW instances */ 104662306a36Sopenharmony_ci if (i >= 2) { 104762306a36Sopenharmony_ci dev_info(adev->dev, "More then 2 VCN FW instances!\n"); 104862306a36Sopenharmony_ci break; 104962306a36Sopenharmony_ci } 105062306a36Sopenharmony_ci idx = AMDGPU_UCODE_ID_VCN + i; 105162306a36Sopenharmony_ci adev->firmware.ucode[idx].ucode_id = idx; 105262306a36Sopenharmony_ci adev->firmware.ucode[idx].fw = adev->vcn.fw; 105362306a36Sopenharmony_ci adev->firmware.fw_size += 105462306a36Sopenharmony_ci ALIGN(le32_to_cpu(hdr->ucode_size_bytes), PAGE_SIZE); 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci if (adev->ip_versions[UVD_HWIP][0] == IP_VERSION(4, 0, 3)) 105762306a36Sopenharmony_ci break; 105862306a36Sopenharmony_ci } 105962306a36Sopenharmony_ci dev_info(adev->dev, "Will use PSP to load VCN firmware\n"); 106062306a36Sopenharmony_ci } 106162306a36Sopenharmony_ci} 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci/* 106462306a36Sopenharmony_ci * debugfs for mapping vcn firmware log buffer. 106562306a36Sopenharmony_ci */ 106662306a36Sopenharmony_ci#if defined(CONFIG_DEBUG_FS) 106762306a36Sopenharmony_cistatic ssize_t amdgpu_debugfs_vcn_fwlog_read(struct file *f, char __user *buf, 106862306a36Sopenharmony_ci size_t size, loff_t *pos) 106962306a36Sopenharmony_ci{ 107062306a36Sopenharmony_ci struct amdgpu_vcn_inst *vcn; 107162306a36Sopenharmony_ci void *log_buf; 107262306a36Sopenharmony_ci volatile struct amdgpu_vcn_fwlog *plog; 107362306a36Sopenharmony_ci unsigned int read_pos, write_pos, available, i, read_bytes = 0; 107462306a36Sopenharmony_ci unsigned int read_num[2] = {0}; 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci vcn = file_inode(f)->i_private; 107762306a36Sopenharmony_ci if (!vcn) 107862306a36Sopenharmony_ci return -ENODEV; 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci if (!vcn->fw_shared.cpu_addr || !amdgpu_vcnfw_log) 108162306a36Sopenharmony_ci return -EFAULT; 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci log_buf = vcn->fw_shared.cpu_addr + vcn->fw_shared.mem_size; 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci plog = (volatile struct amdgpu_vcn_fwlog *)log_buf; 108662306a36Sopenharmony_ci read_pos = plog->rptr; 108762306a36Sopenharmony_ci write_pos = plog->wptr; 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci if (read_pos > AMDGPU_VCNFW_LOG_SIZE || write_pos > AMDGPU_VCNFW_LOG_SIZE) 109062306a36Sopenharmony_ci return -EFAULT; 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci if (!size || (read_pos == write_pos)) 109362306a36Sopenharmony_ci return 0; 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci if (write_pos > read_pos) { 109662306a36Sopenharmony_ci available = write_pos - read_pos; 109762306a36Sopenharmony_ci read_num[0] = min(size, (size_t)available); 109862306a36Sopenharmony_ci } else { 109962306a36Sopenharmony_ci read_num[0] = AMDGPU_VCNFW_LOG_SIZE - read_pos; 110062306a36Sopenharmony_ci available = read_num[0] + write_pos - plog->header_size; 110162306a36Sopenharmony_ci if (size > available) 110262306a36Sopenharmony_ci read_num[1] = write_pos - plog->header_size; 110362306a36Sopenharmony_ci else if (size > read_num[0]) 110462306a36Sopenharmony_ci read_num[1] = size - read_num[0]; 110562306a36Sopenharmony_ci else 110662306a36Sopenharmony_ci read_num[0] = size; 110762306a36Sopenharmony_ci } 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 111062306a36Sopenharmony_ci if (read_num[i]) { 111162306a36Sopenharmony_ci if (read_pos == AMDGPU_VCNFW_LOG_SIZE) 111262306a36Sopenharmony_ci read_pos = plog->header_size; 111362306a36Sopenharmony_ci if (read_num[i] == copy_to_user((buf + read_bytes), 111462306a36Sopenharmony_ci (log_buf + read_pos), read_num[i])) 111562306a36Sopenharmony_ci return -EFAULT; 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci read_bytes += read_num[i]; 111862306a36Sopenharmony_ci read_pos += read_num[i]; 111962306a36Sopenharmony_ci } 112062306a36Sopenharmony_ci } 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci plog->rptr = read_pos; 112362306a36Sopenharmony_ci *pos += read_bytes; 112462306a36Sopenharmony_ci return read_bytes; 112562306a36Sopenharmony_ci} 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_cistatic const struct file_operations amdgpu_debugfs_vcnfwlog_fops = { 112862306a36Sopenharmony_ci .owner = THIS_MODULE, 112962306a36Sopenharmony_ci .read = amdgpu_debugfs_vcn_fwlog_read, 113062306a36Sopenharmony_ci .llseek = default_llseek 113162306a36Sopenharmony_ci}; 113262306a36Sopenharmony_ci#endif 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_civoid amdgpu_debugfs_vcn_fwlog_init(struct amdgpu_device *adev, uint8_t i, 113562306a36Sopenharmony_ci struct amdgpu_vcn_inst *vcn) 113662306a36Sopenharmony_ci{ 113762306a36Sopenharmony_ci#if defined(CONFIG_DEBUG_FS) 113862306a36Sopenharmony_ci struct drm_minor *minor = adev_to_drm(adev)->primary; 113962306a36Sopenharmony_ci struct dentry *root = minor->debugfs_root; 114062306a36Sopenharmony_ci char name[32]; 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci sprintf(name, "amdgpu_vcn_%d_fwlog", i); 114362306a36Sopenharmony_ci debugfs_create_file_size(name, S_IFREG | 0444, root, vcn, 114462306a36Sopenharmony_ci &amdgpu_debugfs_vcnfwlog_fops, 114562306a36Sopenharmony_ci AMDGPU_VCNFW_LOG_SIZE); 114662306a36Sopenharmony_ci#endif 114762306a36Sopenharmony_ci} 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_civoid amdgpu_vcn_fwlog_init(struct amdgpu_vcn_inst *vcn) 115062306a36Sopenharmony_ci{ 115162306a36Sopenharmony_ci#if defined(CONFIG_DEBUG_FS) 115262306a36Sopenharmony_ci volatile uint32_t *flag = vcn->fw_shared.cpu_addr; 115362306a36Sopenharmony_ci void *fw_log_cpu_addr = vcn->fw_shared.cpu_addr + vcn->fw_shared.mem_size; 115462306a36Sopenharmony_ci uint64_t fw_log_gpu_addr = vcn->fw_shared.gpu_addr + vcn->fw_shared.mem_size; 115562306a36Sopenharmony_ci volatile struct amdgpu_vcn_fwlog *log_buf = fw_log_cpu_addr; 115662306a36Sopenharmony_ci volatile struct amdgpu_fw_shared_fw_logging *fw_log = vcn->fw_shared.cpu_addr 115762306a36Sopenharmony_ci + vcn->fw_shared.log_offset; 115862306a36Sopenharmony_ci *flag |= cpu_to_le32(AMDGPU_VCN_FW_LOGGING_FLAG); 115962306a36Sopenharmony_ci fw_log->is_enabled = 1; 116062306a36Sopenharmony_ci fw_log->addr_lo = cpu_to_le32(fw_log_gpu_addr & 0xFFFFFFFF); 116162306a36Sopenharmony_ci fw_log->addr_hi = cpu_to_le32(fw_log_gpu_addr >> 32); 116262306a36Sopenharmony_ci fw_log->size = cpu_to_le32(AMDGPU_VCNFW_LOG_SIZE); 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci log_buf->header_size = sizeof(struct amdgpu_vcn_fwlog); 116562306a36Sopenharmony_ci log_buf->buffer_size = AMDGPU_VCNFW_LOG_SIZE; 116662306a36Sopenharmony_ci log_buf->rptr = log_buf->header_size; 116762306a36Sopenharmony_ci log_buf->wptr = log_buf->header_size; 116862306a36Sopenharmony_ci log_buf->wrapped = 0; 116962306a36Sopenharmony_ci#endif 117062306a36Sopenharmony_ci} 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ciint amdgpu_vcn_process_poison_irq(struct amdgpu_device *adev, 117362306a36Sopenharmony_ci struct amdgpu_irq_src *source, 117462306a36Sopenharmony_ci struct amdgpu_iv_entry *entry) 117562306a36Sopenharmony_ci{ 117662306a36Sopenharmony_ci struct ras_common_if *ras_if = adev->vcn.ras_if; 117762306a36Sopenharmony_ci struct ras_dispatch_if ih_data = { 117862306a36Sopenharmony_ci .entry = entry, 117962306a36Sopenharmony_ci }; 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci if (!ras_if) 118262306a36Sopenharmony_ci return 0; 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci if (!amdgpu_sriov_vf(adev)) { 118562306a36Sopenharmony_ci ih_data.head = *ras_if; 118662306a36Sopenharmony_ci amdgpu_ras_interrupt_dispatch(adev, &ih_data); 118762306a36Sopenharmony_ci } else { 118862306a36Sopenharmony_ci if (adev->virt.ops && adev->virt.ops->ras_poison_handler) 118962306a36Sopenharmony_ci adev->virt.ops->ras_poison_handler(adev); 119062306a36Sopenharmony_ci else 119162306a36Sopenharmony_ci dev_warn(adev->dev, 119262306a36Sopenharmony_ci "No ras_poison_handler interface in SRIOV for VCN!\n"); 119362306a36Sopenharmony_ci } 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_ci return 0; 119662306a36Sopenharmony_ci} 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_ciint amdgpu_vcn_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *ras_block) 119962306a36Sopenharmony_ci{ 120062306a36Sopenharmony_ci int r, i; 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci r = amdgpu_ras_block_late_init(adev, ras_block); 120362306a36Sopenharmony_ci if (r) 120462306a36Sopenharmony_ci return r; 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_ci if (amdgpu_ras_is_supported(adev, ras_block->block)) { 120762306a36Sopenharmony_ci for (i = 0; i < adev->vcn.num_vcn_inst; i++) { 120862306a36Sopenharmony_ci if (adev->vcn.harvest_config & (1 << i) || 120962306a36Sopenharmony_ci !adev->vcn.inst[i].ras_poison_irq.funcs) 121062306a36Sopenharmony_ci continue; 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_ci r = amdgpu_irq_get(adev, &adev->vcn.inst[i].ras_poison_irq, 0); 121362306a36Sopenharmony_ci if (r) 121462306a36Sopenharmony_ci goto late_fini; 121562306a36Sopenharmony_ci } 121662306a36Sopenharmony_ci } 121762306a36Sopenharmony_ci return 0; 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_cilate_fini: 122062306a36Sopenharmony_ci amdgpu_ras_block_late_fini(adev, ras_block); 122162306a36Sopenharmony_ci return r; 122262306a36Sopenharmony_ci} 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ciint amdgpu_vcn_ras_sw_init(struct amdgpu_device *adev) 122562306a36Sopenharmony_ci{ 122662306a36Sopenharmony_ci int err; 122762306a36Sopenharmony_ci struct amdgpu_vcn_ras *ras; 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_ci if (!adev->vcn.ras) 123062306a36Sopenharmony_ci return 0; 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci ras = adev->vcn.ras; 123362306a36Sopenharmony_ci err = amdgpu_ras_register_ras_block(adev, &ras->ras_block); 123462306a36Sopenharmony_ci if (err) { 123562306a36Sopenharmony_ci dev_err(adev->dev, "Failed to register vcn ras block!\n"); 123662306a36Sopenharmony_ci return err; 123762306a36Sopenharmony_ci } 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_ci strcpy(ras->ras_block.ras_comm.name, "vcn"); 124062306a36Sopenharmony_ci ras->ras_block.ras_comm.block = AMDGPU_RAS_BLOCK__VCN; 124162306a36Sopenharmony_ci ras->ras_block.ras_comm.type = AMDGPU_RAS_ERROR__POISON; 124262306a36Sopenharmony_ci adev->vcn.ras_if = &ras->ras_block.ras_comm; 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_ci if (!ras->ras_block.ras_late_init) 124562306a36Sopenharmony_ci ras->ras_block.ras_late_init = amdgpu_vcn_ras_late_init; 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci return 0; 124862306a36Sopenharmony_ci} 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_ciint amdgpu_vcn_psp_update_sram(struct amdgpu_device *adev, int inst_idx, 125162306a36Sopenharmony_ci enum AMDGPU_UCODE_ID ucode_id) 125262306a36Sopenharmony_ci{ 125362306a36Sopenharmony_ci struct amdgpu_firmware_info ucode = { 125462306a36Sopenharmony_ci .ucode_id = (ucode_id ? ucode_id : 125562306a36Sopenharmony_ci (inst_idx ? AMDGPU_UCODE_ID_VCN1_RAM : 125662306a36Sopenharmony_ci AMDGPU_UCODE_ID_VCN0_RAM)), 125762306a36Sopenharmony_ci .mc_addr = adev->vcn.inst[inst_idx].dpg_sram_gpu_addr, 125862306a36Sopenharmony_ci .ucode_size = ((uintptr_t)adev->vcn.inst[inst_idx].dpg_sram_curr_addr - 125962306a36Sopenharmony_ci (uintptr_t)adev->vcn.inst[inst_idx].dpg_sram_cpu_addr), 126062306a36Sopenharmony_ci }; 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci return psp_execute_ip_fw_load(&adev->psp, &ucode); 126362306a36Sopenharmony_ci} 1264