1fb4d8502Sjsg /* 2fb4d8502Sjsg * Copyright 2016 Advanced Micro Devices, Inc. 3fb4d8502Sjsg * All Rights Reserved. 4fb4d8502Sjsg * 5fb4d8502Sjsg * Permission is hereby granted, free of charge, to any person obtaining a 6fb4d8502Sjsg * copy of this software and associated documentation files (the 7fb4d8502Sjsg * "Software"), to deal in the Software without restriction, including 8fb4d8502Sjsg * without limitation the rights to use, copy, modify, merge, publish, 9fb4d8502Sjsg * distribute, sub license, and/or sell copies of the Software, and to 10fb4d8502Sjsg * permit persons to whom the Software is furnished to do so, subject to 11fb4d8502Sjsg * the following conditions: 12fb4d8502Sjsg * 13fb4d8502Sjsg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14fb4d8502Sjsg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15fb4d8502Sjsg * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 16fb4d8502Sjsg * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 17fb4d8502Sjsg * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 18fb4d8502Sjsg * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 19fb4d8502Sjsg * USE OR OTHER DEALINGS IN THE SOFTWARE. 20fb4d8502Sjsg * 21fb4d8502Sjsg * The above copyright notice and this permission notice (including the 22fb4d8502Sjsg * next paragraph) shall be included in all copies or substantial portions 23fb4d8502Sjsg * of the Software. 24fb4d8502Sjsg * 25fb4d8502Sjsg */ 26fb4d8502Sjsg 27fb4d8502Sjsg #include <linux/firmware.h> 28fb4d8502Sjsg #include <linux/module.h> 29a401c30cSjsg #include <linux/dmi.h> 30c349dbc7Sjsg #include <linux/pci.h> 311bb76ff1Sjsg #include <linux/debugfs.h> 325ca02815Sjsg #include <drm/drm_drv.h> 33fb4d8502Sjsg 34fb4d8502Sjsg #include "amdgpu.h" 35fb4d8502Sjsg #include "amdgpu_pm.h" 36fb4d8502Sjsg #include "amdgpu_vcn.h" 37fb4d8502Sjsg #include "soc15d.h" 38fb4d8502Sjsg 39fb4d8502Sjsg /* Firmware Names */ 40fb4d8502Sjsg #define FIRMWARE_RAVEN "amdgpu/raven_vcn.bin" 41b603abd6Sjsg #define FIRMWARE_PICASSO "amdgpu/picasso_vcn.bin" 42c349dbc7Sjsg #define FIRMWARE_RAVEN2 "amdgpu/raven2_vcn.bin" 43c349dbc7Sjsg #define FIRMWARE_ARCTURUS "amdgpu/arcturus_vcn.bin" 44c349dbc7Sjsg #define FIRMWARE_RENOIR "amdgpu/renoir_vcn.bin" 45ad8b1aafSjsg #define FIRMWARE_GREEN_SARDINE "amdgpu/green_sardine_vcn.bin" 46c349dbc7Sjsg #define FIRMWARE_NAVI10 "amdgpu/navi10_vcn.bin" 47c349dbc7Sjsg #define FIRMWARE_NAVI14 "amdgpu/navi14_vcn.bin" 48c349dbc7Sjsg #define FIRMWARE_NAVI12 "amdgpu/navi12_vcn.bin" 49ad8b1aafSjsg #define FIRMWARE_SIENNA_CICHLID "amdgpu/sienna_cichlid_vcn.bin" 50ad8b1aafSjsg #define FIRMWARE_NAVY_FLOUNDER "amdgpu/navy_flounder_vcn.bin" 515ca02815Sjsg #define FIRMWARE_VANGOGH "amdgpu/vangogh_vcn.bin" 525ca02815Sjsg #define FIRMWARE_DIMGREY_CAVEFISH "amdgpu/dimgrey_cavefish_vcn.bin" 535ca02815Sjsg #define FIRMWARE_ALDEBARAN "amdgpu/aldebaran_vcn.bin" 545ca02815Sjsg #define FIRMWARE_BEIGE_GOBY "amdgpu/beige_goby_vcn.bin" 555ca02815Sjsg #define FIRMWARE_YELLOW_CARP "amdgpu/yellow_carp_vcn.bin" 561bb76ff1Sjsg #define FIRMWARE_VCN_3_1_2 "amdgpu/vcn_3_1_2.bin" 571bb76ff1Sjsg #define FIRMWARE_VCN4_0_0 "amdgpu/vcn_4_0_0.bin" 581bb76ff1Sjsg #define FIRMWARE_VCN4_0_2 "amdgpu/vcn_4_0_2.bin" 59f005ef32Sjsg #define FIRMWARE_VCN4_0_3 "amdgpu/vcn_4_0_3.bin" 601bb76ff1Sjsg #define FIRMWARE_VCN4_0_4 "amdgpu/vcn_4_0_4.bin" 61fb4d8502Sjsg 62fb4d8502Sjsg MODULE_FIRMWARE(FIRMWARE_RAVEN); 63b603abd6Sjsg MODULE_FIRMWARE(FIRMWARE_PICASSO); 64c349dbc7Sjsg MODULE_FIRMWARE(FIRMWARE_RAVEN2); 65c349dbc7Sjsg MODULE_FIRMWARE(FIRMWARE_ARCTURUS); 66c349dbc7Sjsg MODULE_FIRMWARE(FIRMWARE_RENOIR); 67ad8b1aafSjsg MODULE_FIRMWARE(FIRMWARE_GREEN_SARDINE); 685ca02815Sjsg MODULE_FIRMWARE(FIRMWARE_ALDEBARAN); 69c349dbc7Sjsg MODULE_FIRMWARE(FIRMWARE_NAVI10); 70c349dbc7Sjsg MODULE_FIRMWARE(FIRMWARE_NAVI14); 71c349dbc7Sjsg MODULE_FIRMWARE(FIRMWARE_NAVI12); 72ad8b1aafSjsg MODULE_FIRMWARE(FIRMWARE_SIENNA_CICHLID); 73ad8b1aafSjsg MODULE_FIRMWARE(FIRMWARE_NAVY_FLOUNDER); 745ca02815Sjsg MODULE_FIRMWARE(FIRMWARE_VANGOGH); 755ca02815Sjsg MODULE_FIRMWARE(FIRMWARE_DIMGREY_CAVEFISH); 765ca02815Sjsg MODULE_FIRMWARE(FIRMWARE_BEIGE_GOBY); 775ca02815Sjsg MODULE_FIRMWARE(FIRMWARE_YELLOW_CARP); 781bb76ff1Sjsg MODULE_FIRMWARE(FIRMWARE_VCN_3_1_2); 791bb76ff1Sjsg MODULE_FIRMWARE(FIRMWARE_VCN4_0_0); 801bb76ff1Sjsg MODULE_FIRMWARE(FIRMWARE_VCN4_0_2); 81f005ef32Sjsg MODULE_FIRMWARE(FIRMWARE_VCN4_0_3); 821bb76ff1Sjsg MODULE_FIRMWARE(FIRMWARE_VCN4_0_4); 83fb4d8502Sjsg 84fb4d8502Sjsg static void amdgpu_vcn_idle_work_handler(struct work_struct *work); 85fb4d8502Sjsg 86f005ef32Sjsg int amdgpu_vcn_early_init(struct amdgpu_device *adev) 87f005ef32Sjsg { 88f005ef32Sjsg char ucode_prefix[30]; 89f005ef32Sjsg char fw_name[40]; 90f005ef32Sjsg int r; 91f005ef32Sjsg 92f005ef32Sjsg amdgpu_ucode_ip_version_decode(adev, UVD_HWIP, ucode_prefix, sizeof(ucode_prefix)); 93f005ef32Sjsg snprintf(fw_name, sizeof(fw_name), "amdgpu/%s.bin", ucode_prefix); 94f005ef32Sjsg r = amdgpu_ucode_request(adev, &adev->vcn.fw, fw_name); 95f005ef32Sjsg if (r) 96f005ef32Sjsg amdgpu_ucode_release(&adev->vcn.fw); 97f005ef32Sjsg 98f005ef32Sjsg return r; 99f005ef32Sjsg } 100f005ef32Sjsg 101fb4d8502Sjsg int amdgpu_vcn_sw_init(struct amdgpu_device *adev) 102fb4d8502Sjsg { 103fb4d8502Sjsg unsigned long bo_size; 104fb4d8502Sjsg const struct common_firmware_header *hdr; 105fb4d8502Sjsg unsigned char fw_check; 1061bb76ff1Sjsg unsigned int fw_shared_size, log_offset; 107c349dbc7Sjsg int i, r; 108fb4d8502Sjsg 109fb4d8502Sjsg INIT_DELAYED_WORK(&adev->vcn.idle_work, amdgpu_vcn_idle_work_handler); 110ad8b1aafSjsg rw_init(&adev->vcn.vcn_pg_lock, "vcnpg"); 111ad8b1aafSjsg rw_init(&adev->vcn.vcn1_jpeg1_workaround, "vcnwa"); 112ad8b1aafSjsg atomic_set(&adev->vcn.total_submission_cnt, 0); 113ad8b1aafSjsg for (i = 0; i < adev->vcn.num_vcn_inst; i++) 114ad8b1aafSjsg atomic_set(&adev->vcn.inst[i].dpg_enc_submission_cnt, 0); 115fb4d8502Sjsg 116c349dbc7Sjsg if ((adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) && 117c349dbc7Sjsg (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG)) 118c349dbc7Sjsg adev->vcn.indirect_sram = true; 119ad8b1aafSjsg 120f005ef32Sjsg /* 121f005ef32Sjsg * Some Steam Deck's BIOS versions are incompatible with the 122f005ef32Sjsg * indirect SRAM mode, leading to amdgpu being unable to get 123f005ef32Sjsg * properly probed (and even potentially crashing the kernel). 124f005ef32Sjsg * Hence, check for these versions here - notice this is 125f005ef32Sjsg * restricted to Vangogh (Deck's APU). 126f005ef32Sjsg */ 127f005ef32Sjsg if (adev->ip_versions[UVD_HWIP][0] == IP_VERSION(3, 0, 2)) { 128f005ef32Sjsg const char *bios_ver = dmi_get_system_info(DMI_BIOS_VERSION); 129f005ef32Sjsg 130f005ef32Sjsg if (bios_ver && (!strncmp("F7A0113", bios_ver, 7) || 131f005ef32Sjsg !strncmp("F7A0114", bios_ver, 7))) { 132f005ef32Sjsg adev->vcn.indirect_sram = false; 133f005ef32Sjsg dev_info(adev->dev, 134f005ef32Sjsg "Steam Deck quirk: indirect SRAM disabled on BIOS %s\n", bios_ver); 135fb4d8502Sjsg } 136fb4d8502Sjsg } 137fb4d8502Sjsg 1386809abd7Sjsg /* from vcn4 and above, only unified queue is used */ 1396809abd7Sjsg adev->vcn.using_unified_queue = 1406809abd7Sjsg adev->ip_versions[UVD_HWIP][0] >= IP_VERSION(4, 0, 0); 1416809abd7Sjsg 142fb4d8502Sjsg hdr = (const struct common_firmware_header *)adev->vcn.fw->data; 143fb4d8502Sjsg adev->vcn.fw_version = le32_to_cpu(hdr->ucode_version); 144fb4d8502Sjsg 145fb4d8502Sjsg /* Bit 20-23, it is encode major and non-zero for new naming convention. 146fb4d8502Sjsg * This field is part of version minor and DRM_DISABLED_FLAG in old naming 147fb4d8502Sjsg * convention. Since the l:wq!atest version minor is 0x5B and DRM_DISABLED_FLAG 148fb4d8502Sjsg * is zero in old naming convention, this field is always zero so far. 149fb4d8502Sjsg * These four bits are used to tell which naming convention is present. 150fb4d8502Sjsg */ 151fb4d8502Sjsg fw_check = (le32_to_cpu(hdr->ucode_version) >> 20) & 0xf; 152fb4d8502Sjsg if (fw_check) { 153fb4d8502Sjsg unsigned int dec_ver, enc_major, enc_minor, vep, fw_rev; 154fb4d8502Sjsg 155fb4d8502Sjsg fw_rev = le32_to_cpu(hdr->ucode_version) & 0xfff; 156fb4d8502Sjsg enc_minor = (le32_to_cpu(hdr->ucode_version) >> 12) & 0xff; 157fb4d8502Sjsg enc_major = fw_check; 158fb4d8502Sjsg dec_ver = (le32_to_cpu(hdr->ucode_version) >> 24) & 0xf; 159fb4d8502Sjsg vep = (le32_to_cpu(hdr->ucode_version) >> 28) & 0xf; 160fb4d8502Sjsg DRM_INFO("Found VCN firmware Version ENC: %u.%u DEC: %u VEP: %u Revision: %u\n", 161fb4d8502Sjsg enc_major, enc_minor, dec_ver, vep, fw_rev); 162fb4d8502Sjsg } else { 163fb4d8502Sjsg unsigned int version_major, version_minor, family_id; 164fb4d8502Sjsg 165fb4d8502Sjsg family_id = le32_to_cpu(hdr->ucode_version) & 0xff; 166fb4d8502Sjsg version_major = (le32_to_cpu(hdr->ucode_version) >> 24) & 0xff; 167fb4d8502Sjsg version_minor = (le32_to_cpu(hdr->ucode_version) >> 8) & 0xff; 168fb4d8502Sjsg DRM_INFO("Found VCN firmware Version: %u.%u Family ID: %u\n", 169fb4d8502Sjsg version_major, version_minor, family_id); 170fb4d8502Sjsg } 171fb4d8502Sjsg 172c349dbc7Sjsg bo_size = AMDGPU_VCN_STACK_SIZE + AMDGPU_VCN_CONTEXT_SIZE; 173fb4d8502Sjsg if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) 174fb4d8502Sjsg bo_size += AMDGPU_GPU_PAGE_ALIGN(le32_to_cpu(hdr->ucode_size_bytes) + 8); 1751bb76ff1Sjsg 1761bb76ff1Sjsg if (adev->ip_versions[UVD_HWIP][0] >= IP_VERSION(4, 0, 0)) { 1771bb76ff1Sjsg fw_shared_size = AMDGPU_GPU_PAGE_ALIGN(sizeof(struct amdgpu_vcn4_fw_shared)); 1781bb76ff1Sjsg log_offset = offsetof(struct amdgpu_vcn4_fw_shared, fw_log); 1791bb76ff1Sjsg } else { 1801bb76ff1Sjsg fw_shared_size = AMDGPU_GPU_PAGE_ALIGN(sizeof(struct amdgpu_fw_shared)); 1811bb76ff1Sjsg log_offset = offsetof(struct amdgpu_fw_shared, fw_log); 1821bb76ff1Sjsg } 1831bb76ff1Sjsg 1841bb76ff1Sjsg bo_size += fw_shared_size; 1851bb76ff1Sjsg 1861bb76ff1Sjsg if (amdgpu_vcnfw_log) 1871bb76ff1Sjsg bo_size += AMDGPU_VCNFW_LOG_SIZE; 188c349dbc7Sjsg 189c349dbc7Sjsg for (i = 0; i < adev->vcn.num_vcn_inst; i++) { 190c349dbc7Sjsg if (adev->vcn.harvest_config & (1 << i)) 191c349dbc7Sjsg continue; 192c349dbc7Sjsg 193fb4d8502Sjsg r = amdgpu_bo_create_kernel(adev, bo_size, PAGE_SIZE, 194f005ef32Sjsg AMDGPU_GEM_DOMAIN_VRAM | 195f005ef32Sjsg AMDGPU_GEM_DOMAIN_GTT, 196f005ef32Sjsg &adev->vcn.inst[i].vcpu_bo, 197f005ef32Sjsg &adev->vcn.inst[i].gpu_addr, 198f005ef32Sjsg &adev->vcn.inst[i].cpu_addr); 199fb4d8502Sjsg if (r) { 200fb4d8502Sjsg dev_err(adev->dev, "(%d) failed to allocate vcn bo\n", r); 201fb4d8502Sjsg return r; 202fb4d8502Sjsg } 203fb4d8502Sjsg 2041bb76ff1Sjsg adev->vcn.inst[i].fw_shared.cpu_addr = adev->vcn.inst[i].cpu_addr + 2051bb76ff1Sjsg bo_size - fw_shared_size; 2061bb76ff1Sjsg adev->vcn.inst[i].fw_shared.gpu_addr = adev->vcn.inst[i].gpu_addr + 2071bb76ff1Sjsg bo_size - fw_shared_size; 2081bb76ff1Sjsg 2091bb76ff1Sjsg adev->vcn.inst[i].fw_shared.mem_size = fw_shared_size; 2101bb76ff1Sjsg 2111bb76ff1Sjsg if (amdgpu_vcnfw_log) { 2121bb76ff1Sjsg adev->vcn.inst[i].fw_shared.cpu_addr -= AMDGPU_VCNFW_LOG_SIZE; 2131bb76ff1Sjsg adev->vcn.inst[i].fw_shared.gpu_addr -= AMDGPU_VCNFW_LOG_SIZE; 2141bb76ff1Sjsg adev->vcn.inst[i].fw_shared.log_offset = log_offset; 2151bb76ff1Sjsg } 216ad8b1aafSjsg 217c349dbc7Sjsg if (adev->vcn.indirect_sram) { 218c349dbc7Sjsg r = amdgpu_bo_create_kernel(adev, 64 * 2 * 4, PAGE_SIZE, 219f005ef32Sjsg AMDGPU_GEM_DOMAIN_VRAM | 220f005ef32Sjsg AMDGPU_GEM_DOMAIN_GTT, 221f005ef32Sjsg &adev->vcn.inst[i].dpg_sram_bo, 222f005ef32Sjsg &adev->vcn.inst[i].dpg_sram_gpu_addr, 223f005ef32Sjsg &adev->vcn.inst[i].dpg_sram_cpu_addr); 224c349dbc7Sjsg if (r) { 225c349dbc7Sjsg dev_err(adev->dev, "VCN %d (%d) failed to allocate DPG bo\n", i, r); 226c349dbc7Sjsg return r; 227c349dbc7Sjsg } 228c349dbc7Sjsg } 229c349dbc7Sjsg } 230c349dbc7Sjsg 231fb4d8502Sjsg return 0; 232fb4d8502Sjsg } 233fb4d8502Sjsg 234fb4d8502Sjsg int amdgpu_vcn_sw_fini(struct amdgpu_device *adev) 235fb4d8502Sjsg { 236c349dbc7Sjsg int i, j; 237fb4d8502Sjsg 238c349dbc7Sjsg for (j = 0; j < adev->vcn.num_vcn_inst; ++j) { 239c349dbc7Sjsg if (adev->vcn.harvest_config & (1 << j)) 240c349dbc7Sjsg continue; 241ad8b1aafSjsg 242f005ef32Sjsg amdgpu_bo_free_kernel( 243f005ef32Sjsg &adev->vcn.inst[j].dpg_sram_bo, 244c349dbc7Sjsg &adev->vcn.inst[j].dpg_sram_gpu_addr, 245c349dbc7Sjsg (void **)&adev->vcn.inst[j].dpg_sram_cpu_addr); 246f005ef32Sjsg 247c349dbc7Sjsg kvfree(adev->vcn.inst[j].saved_bo); 248fb4d8502Sjsg 249c349dbc7Sjsg amdgpu_bo_free_kernel(&adev->vcn.inst[j].vcpu_bo, 250c349dbc7Sjsg &adev->vcn.inst[j].gpu_addr, 251c349dbc7Sjsg (void **)&adev->vcn.inst[j].cpu_addr); 252c349dbc7Sjsg 253c349dbc7Sjsg amdgpu_ring_fini(&adev->vcn.inst[j].ring_dec); 254fb4d8502Sjsg 255fb4d8502Sjsg for (i = 0; i < adev->vcn.num_enc_rings; ++i) 256c349dbc7Sjsg amdgpu_ring_fini(&adev->vcn.inst[j].ring_enc[i]); 257c349dbc7Sjsg } 258fb4d8502Sjsg 259f005ef32Sjsg amdgpu_ucode_release(&adev->vcn.fw); 260ad8b1aafSjsg mutex_destroy(&adev->vcn.vcn1_jpeg1_workaround); 261ad8b1aafSjsg mutex_destroy(&adev->vcn.vcn_pg_lock); 262fb4d8502Sjsg 263fb4d8502Sjsg return 0; 264fb4d8502Sjsg } 265fb4d8502Sjsg 2665ca02815Sjsg bool amdgpu_vcn_is_disabled_vcn(struct amdgpu_device *adev, enum vcn_ring_type type, uint32_t vcn_instance) 2675ca02815Sjsg { 2685ca02815Sjsg bool ret = false; 2691bb76ff1Sjsg int vcn_config = adev->vcn.vcn_config[vcn_instance]; 2705ca02815Sjsg 271f005ef32Sjsg if ((type == VCN_ENCODE_RING) && (vcn_config & VCN_BLOCK_ENCODE_DISABLE_MASK)) 2725ca02815Sjsg ret = true; 273f005ef32Sjsg else if ((type == VCN_DECODE_RING) && (vcn_config & VCN_BLOCK_DECODE_DISABLE_MASK)) 2745ca02815Sjsg ret = true; 275f005ef32Sjsg else if ((type == VCN_UNIFIED_RING) && (vcn_config & VCN_BLOCK_QUEUE_DISABLE_MASK)) 2765ca02815Sjsg ret = true; 2775ca02815Sjsg 2785ca02815Sjsg return ret; 2795ca02815Sjsg } 2805ca02815Sjsg 281fb4d8502Sjsg int amdgpu_vcn_suspend(struct amdgpu_device *adev) 282fb4d8502Sjsg { 283f005ef32Sjsg unsigned int size; 284fb4d8502Sjsg void *ptr; 2855ca02815Sjsg int i, idx; 286fb4d8502Sjsg 287d272372aSjsg bool in_ras_intr = amdgpu_ras_intr_triggered(); 288d272372aSjsg 289fb4d8502Sjsg cancel_delayed_work_sync(&adev->vcn.idle_work); 290fb4d8502Sjsg 291d272372aSjsg /* err_event_athub will corrupt VCPU buffer, so we need to 292d272372aSjsg * restore fw data and clear buffer in amdgpu_vcn_resume() */ 293d272372aSjsg if (in_ras_intr) 294d272372aSjsg return 0; 295d272372aSjsg 296c349dbc7Sjsg for (i = 0; i < adev->vcn.num_vcn_inst; ++i) { 297c349dbc7Sjsg if (adev->vcn.harvest_config & (1 << i)) 298c349dbc7Sjsg continue; 299c349dbc7Sjsg if (adev->vcn.inst[i].vcpu_bo == NULL) 300fb4d8502Sjsg return 0; 301fb4d8502Sjsg 302c349dbc7Sjsg size = amdgpu_bo_size(adev->vcn.inst[i].vcpu_bo); 303c349dbc7Sjsg ptr = adev->vcn.inst[i].cpu_addr; 304fb4d8502Sjsg 305c349dbc7Sjsg adev->vcn.inst[i].saved_bo = kvmalloc(size, GFP_KERNEL); 306c349dbc7Sjsg if (!adev->vcn.inst[i].saved_bo) 307fb4d8502Sjsg return -ENOMEM; 308fb4d8502Sjsg 3091bb76ff1Sjsg if (drm_dev_enter(adev_to_drm(adev), &idx)) { 310c349dbc7Sjsg memcpy_fromio(adev->vcn.inst[i].saved_bo, ptr, size); 3115ca02815Sjsg drm_dev_exit(idx); 3125ca02815Sjsg } 313c349dbc7Sjsg } 314fb4d8502Sjsg return 0; 315fb4d8502Sjsg } 316fb4d8502Sjsg 317fb4d8502Sjsg int amdgpu_vcn_resume(struct amdgpu_device *adev) 318fb4d8502Sjsg { 319f005ef32Sjsg unsigned int size; 320fb4d8502Sjsg void *ptr; 3215ca02815Sjsg int i, idx; 322fb4d8502Sjsg 323c349dbc7Sjsg for (i = 0; i < adev->vcn.num_vcn_inst; ++i) { 324c349dbc7Sjsg if (adev->vcn.harvest_config & (1 << i)) 325c349dbc7Sjsg continue; 326c349dbc7Sjsg if (adev->vcn.inst[i].vcpu_bo == NULL) 327fb4d8502Sjsg return -EINVAL; 328fb4d8502Sjsg 329c349dbc7Sjsg size = amdgpu_bo_size(adev->vcn.inst[i].vcpu_bo); 330c349dbc7Sjsg ptr = adev->vcn.inst[i].cpu_addr; 331fb4d8502Sjsg 332c349dbc7Sjsg if (adev->vcn.inst[i].saved_bo != NULL) { 3331bb76ff1Sjsg if (drm_dev_enter(adev_to_drm(adev), &idx)) { 334c349dbc7Sjsg memcpy_toio(ptr, adev->vcn.inst[i].saved_bo, size); 3355ca02815Sjsg drm_dev_exit(idx); 3365ca02815Sjsg } 337c349dbc7Sjsg kvfree(adev->vcn.inst[i].saved_bo); 338c349dbc7Sjsg adev->vcn.inst[i].saved_bo = NULL; 339fb4d8502Sjsg } else { 340fb4d8502Sjsg const struct common_firmware_header *hdr; 341f005ef32Sjsg unsigned int offset; 342fb4d8502Sjsg 343fb4d8502Sjsg hdr = (const struct common_firmware_header *)adev->vcn.fw->data; 344fb4d8502Sjsg if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) { 345fb4d8502Sjsg offset = le32_to_cpu(hdr->ucode_array_offset_bytes); 3461bb76ff1Sjsg if (drm_dev_enter(adev_to_drm(adev), &idx)) { 347c349dbc7Sjsg memcpy_toio(adev->vcn.inst[i].cpu_addr, adev->vcn.fw->data + offset, 348fb4d8502Sjsg le32_to_cpu(hdr->ucode_size_bytes)); 3495ca02815Sjsg drm_dev_exit(idx); 3505ca02815Sjsg } 351fb4d8502Sjsg size -= le32_to_cpu(hdr->ucode_size_bytes); 352fb4d8502Sjsg ptr += le32_to_cpu(hdr->ucode_size_bytes); 353fb4d8502Sjsg } 354fb4d8502Sjsg memset_io(ptr, 0, size); 355fb4d8502Sjsg } 356c349dbc7Sjsg } 357fb4d8502Sjsg return 0; 358fb4d8502Sjsg } 359fb4d8502Sjsg 360fb4d8502Sjsg static void amdgpu_vcn_idle_work_handler(struct work_struct *work) 361fb4d8502Sjsg { 362fb4d8502Sjsg struct amdgpu_device *adev = 363fb4d8502Sjsg container_of(work, struct amdgpu_device, vcn.idle_work.work); 364c349dbc7Sjsg unsigned int fences = 0, fence[AMDGPU_MAX_VCN_INSTANCES] = {0}; 365c349dbc7Sjsg unsigned int i, j; 3665ca02815Sjsg int r = 0; 367c349dbc7Sjsg 368c349dbc7Sjsg for (j = 0; j < adev->vcn.num_vcn_inst; ++j) { 369c349dbc7Sjsg if (adev->vcn.harvest_config & (1 << j)) 370c349dbc7Sjsg continue; 371fb4d8502Sjsg 372f005ef32Sjsg for (i = 0; i < adev->vcn.num_enc_rings; ++i) 373c349dbc7Sjsg fence[j] += amdgpu_fence_count_emitted(&adev->vcn.inst[j].ring_enc[i]); 374fb4d8502Sjsg 375*1bcdd048Sjsg /* Only set DPG pause for VCN3 or below, VCN4 and above will be handled by FW */ 376*1bcdd048Sjsg if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG && 377*1bcdd048Sjsg !adev->vcn.using_unified_queue) { 378c349dbc7Sjsg struct dpg_pause_state new_state; 379c349dbc7Sjsg 380ad8b1aafSjsg if (fence[j] || 381ad8b1aafSjsg unlikely(atomic_read(&adev->vcn.inst[j].dpg_enc_submission_cnt))) 382c349dbc7Sjsg new_state.fw_based = VCN_DPG_STATE__PAUSE; 383c349dbc7Sjsg else 384c349dbc7Sjsg new_state.fw_based = VCN_DPG_STATE__UNPAUSE; 385c349dbc7Sjsg 386c349dbc7Sjsg adev->vcn.pause_dpg_mode(adev, j, &new_state); 387c349dbc7Sjsg } 388c349dbc7Sjsg 389c349dbc7Sjsg fence[j] += amdgpu_fence_count_emitted(&adev->vcn.inst[j].ring_dec); 390c349dbc7Sjsg fences += fence[j]; 391c349dbc7Sjsg } 392fb4d8502Sjsg 393ad8b1aafSjsg if (!fences && !atomic_read(&adev->vcn.total_submission_cnt)) { 394fb4d8502Sjsg amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_VCN, 395fb4d8502Sjsg AMD_PG_STATE_GATE); 3965ca02815Sjsg r = amdgpu_dpm_switch_power_profile(adev, PP_SMC_POWER_PROFILE_VIDEO, 3975ca02815Sjsg false); 3985ca02815Sjsg if (r) 3995ca02815Sjsg dev_warn(adev->dev, "(%d) failed to disable video power profile mode\n", r); 400fb4d8502Sjsg } else { 401fb4d8502Sjsg schedule_delayed_work(&adev->vcn.idle_work, VCN_IDLE_TIMEOUT); 402fb4d8502Sjsg } 403fb4d8502Sjsg } 404fb4d8502Sjsg 405fb4d8502Sjsg void amdgpu_vcn_ring_begin_use(struct amdgpu_ring *ring) 406fb4d8502Sjsg { 407fb4d8502Sjsg struct amdgpu_device *adev = ring->adev; 4085ca02815Sjsg int r = 0; 409fb4d8502Sjsg 410ad8b1aafSjsg atomic_inc(&adev->vcn.total_submission_cnt); 4115ca02815Sjsg 4125ca02815Sjsg if (!cancel_delayed_work_sync(&adev->vcn.idle_work)) { 4135ca02815Sjsg r = amdgpu_dpm_switch_power_profile(adev, PP_SMC_POWER_PROFILE_VIDEO, 4145ca02815Sjsg true); 4155ca02815Sjsg if (r) 4165ca02815Sjsg dev_warn(adev->dev, "(%d) failed to switch to video power profile mode\n", r); 4175ca02815Sjsg } 418ad8b1aafSjsg 419ad8b1aafSjsg mutex_lock(&adev->vcn.vcn_pg_lock); 420fb4d8502Sjsg amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_VCN, 421fb4d8502Sjsg AMD_PG_STATE_UNGATE); 422c349dbc7Sjsg 423*1bcdd048Sjsg /* Only set DPG pause for VCN3 or below, VCN4 and above will be handled by FW */ 424*1bcdd048Sjsg if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG && 425*1bcdd048Sjsg !adev->vcn.using_unified_queue) { 426c349dbc7Sjsg struct dpg_pause_state new_state; 427ad8b1aafSjsg 428ad8b1aafSjsg if (ring->funcs->type == AMDGPU_RING_TYPE_VCN_ENC) { 429ad8b1aafSjsg atomic_inc(&adev->vcn.inst[ring->me].dpg_enc_submission_cnt); 430ad8b1aafSjsg new_state.fw_based = VCN_DPG_STATE__PAUSE; 431ad8b1aafSjsg } else { 432c349dbc7Sjsg unsigned int fences = 0; 433c349dbc7Sjsg unsigned int i; 434c349dbc7Sjsg 435ad8b1aafSjsg for (i = 0; i < adev->vcn.num_enc_rings; ++i) 436c349dbc7Sjsg fences += amdgpu_fence_count_emitted(&adev->vcn.inst[ring->me].ring_enc[i]); 437ad8b1aafSjsg 438ad8b1aafSjsg if (fences || atomic_read(&adev->vcn.inst[ring->me].dpg_enc_submission_cnt)) 439c349dbc7Sjsg new_state.fw_based = VCN_DPG_STATE__PAUSE; 440c349dbc7Sjsg else 441c349dbc7Sjsg new_state.fw_based = VCN_DPG_STATE__UNPAUSE; 442ad8b1aafSjsg } 443c349dbc7Sjsg 444c349dbc7Sjsg adev->vcn.pause_dpg_mode(adev, ring->me, &new_state); 445c349dbc7Sjsg } 446ad8b1aafSjsg mutex_unlock(&adev->vcn.vcn_pg_lock); 447fb4d8502Sjsg } 448fb4d8502Sjsg 449fb4d8502Sjsg void amdgpu_vcn_ring_end_use(struct amdgpu_ring *ring) 450fb4d8502Sjsg { 451*1bcdd048Sjsg struct amdgpu_device *adev = ring->adev; 452*1bcdd048Sjsg 453*1bcdd048Sjsg /* Only set DPG pause for VCN3 or below, VCN4 and above will be handled by FW */ 454ad8b1aafSjsg if (ring->adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG && 455*1bcdd048Sjsg ring->funcs->type == AMDGPU_RING_TYPE_VCN_ENC && 456*1bcdd048Sjsg !adev->vcn.using_unified_queue) 457ad8b1aafSjsg atomic_dec(&ring->adev->vcn.inst[ring->me].dpg_enc_submission_cnt); 458ad8b1aafSjsg 459ad8b1aafSjsg atomic_dec(&ring->adev->vcn.total_submission_cnt); 460ad8b1aafSjsg 461fb4d8502Sjsg schedule_delayed_work(&ring->adev->vcn.idle_work, VCN_IDLE_TIMEOUT); 462fb4d8502Sjsg } 463fb4d8502Sjsg 464fb4d8502Sjsg int amdgpu_vcn_dec_ring_test_ring(struct amdgpu_ring *ring) 465fb4d8502Sjsg { 466fb4d8502Sjsg struct amdgpu_device *adev = ring->adev; 467fb4d8502Sjsg uint32_t tmp = 0; 468f005ef32Sjsg unsigned int i; 469fb4d8502Sjsg int r; 470fb4d8502Sjsg 471ad8b1aafSjsg /* VCN in SRIOV does not support direct register read/write */ 472ad8b1aafSjsg if (amdgpu_sriov_vf(adev)) 473ad8b1aafSjsg return 0; 474ad8b1aafSjsg 475c349dbc7Sjsg WREG32(adev->vcn.inst[ring->me].external.scratch9, 0xCAFEDEAD); 476fb4d8502Sjsg r = amdgpu_ring_alloc(ring, 3); 477c349dbc7Sjsg if (r) 478fb4d8502Sjsg return r; 479c349dbc7Sjsg amdgpu_ring_write(ring, PACKET0(adev->vcn.internal.scratch9, 0)); 480fb4d8502Sjsg amdgpu_ring_write(ring, 0xDEADBEEF); 481fb4d8502Sjsg amdgpu_ring_commit(ring); 482fb4d8502Sjsg for (i = 0; i < adev->usec_timeout; i++) { 483c349dbc7Sjsg tmp = RREG32(adev->vcn.inst[ring->me].external.scratch9); 484fb4d8502Sjsg if (tmp == 0xDEADBEEF) 485fb4d8502Sjsg break; 486c349dbc7Sjsg udelay(1); 487fb4d8502Sjsg } 488fb4d8502Sjsg 489c349dbc7Sjsg if (i >= adev->usec_timeout) 490c349dbc7Sjsg r = -ETIMEDOUT; 491c349dbc7Sjsg 492fb4d8502Sjsg return r; 493fb4d8502Sjsg } 494fb4d8502Sjsg 4955ca02815Sjsg int amdgpu_vcn_dec_sw_ring_test_ring(struct amdgpu_ring *ring) 4965ca02815Sjsg { 4975ca02815Sjsg struct amdgpu_device *adev = ring->adev; 4985ca02815Sjsg uint32_t rptr; 4995ca02815Sjsg unsigned int i; 5005ca02815Sjsg int r; 5015ca02815Sjsg 5025ca02815Sjsg if (amdgpu_sriov_vf(adev)) 5035ca02815Sjsg return 0; 5045ca02815Sjsg 5055ca02815Sjsg r = amdgpu_ring_alloc(ring, 16); 5065ca02815Sjsg if (r) 5075ca02815Sjsg return r; 5085ca02815Sjsg 5095ca02815Sjsg rptr = amdgpu_ring_get_rptr(ring); 5105ca02815Sjsg 5115ca02815Sjsg amdgpu_ring_write(ring, VCN_DEC_SW_CMD_END); 5125ca02815Sjsg amdgpu_ring_commit(ring); 5135ca02815Sjsg 5145ca02815Sjsg for (i = 0; i < adev->usec_timeout; i++) { 5155ca02815Sjsg if (amdgpu_ring_get_rptr(ring) != rptr) 5165ca02815Sjsg break; 5175ca02815Sjsg udelay(1); 5185ca02815Sjsg } 5195ca02815Sjsg 5205ca02815Sjsg if (i >= adev->usec_timeout) 5215ca02815Sjsg r = -ETIMEDOUT; 5225ca02815Sjsg 5235ca02815Sjsg return r; 5245ca02815Sjsg } 5255ca02815Sjsg 526fb4d8502Sjsg static int amdgpu_vcn_dec_send_msg(struct amdgpu_ring *ring, 5271bb76ff1Sjsg struct amdgpu_ib *ib_msg, 528fb4d8502Sjsg struct dma_fence **fence) 529fb4d8502Sjsg { 530f005ef32Sjsg u64 addr = AMDGPU_GPU_PAGE_ALIGN(ib_msg->gpu_addr); 531fb4d8502Sjsg struct amdgpu_device *adev = ring->adev; 532fb4d8502Sjsg struct dma_fence *f = NULL; 533fb4d8502Sjsg struct amdgpu_job *job; 534fb4d8502Sjsg struct amdgpu_ib *ib; 535fb4d8502Sjsg int i, r; 536fb4d8502Sjsg 537f005ef32Sjsg r = amdgpu_job_alloc_with_ib(ring->adev, NULL, NULL, 538f005ef32Sjsg 64, AMDGPU_IB_POOL_DIRECT, 539f005ef32Sjsg &job); 540fb4d8502Sjsg if (r) 541fb4d8502Sjsg goto err; 542fb4d8502Sjsg 543fb4d8502Sjsg ib = &job->ibs[0]; 544c349dbc7Sjsg ib->ptr[0] = PACKET0(adev->vcn.internal.data0, 0); 545fb4d8502Sjsg ib->ptr[1] = addr; 546c349dbc7Sjsg ib->ptr[2] = PACKET0(adev->vcn.internal.data1, 0); 547fb4d8502Sjsg ib->ptr[3] = addr >> 32; 548c349dbc7Sjsg ib->ptr[4] = PACKET0(adev->vcn.internal.cmd, 0); 549fb4d8502Sjsg ib->ptr[5] = 0; 550fb4d8502Sjsg for (i = 6; i < 16; i += 2) { 551c349dbc7Sjsg ib->ptr[i] = PACKET0(adev->vcn.internal.nop, 0); 552fb4d8502Sjsg ib->ptr[i+1] = 0; 553fb4d8502Sjsg } 554fb4d8502Sjsg ib->length_dw = 16; 555fb4d8502Sjsg 556fb4d8502Sjsg r = amdgpu_job_submit_direct(job, ring, &f); 557fb4d8502Sjsg if (r) 558fb4d8502Sjsg goto err_free; 559fb4d8502Sjsg 5601bb76ff1Sjsg amdgpu_ib_free(adev, ib_msg, f); 5615ca02815Sjsg 5625ca02815Sjsg if (fence) 5635ca02815Sjsg *fence = dma_fence_get(f); 5645ca02815Sjsg dma_fence_put(f); 5655ca02815Sjsg 5665ca02815Sjsg return 0; 5675ca02815Sjsg 5685ca02815Sjsg err_free: 5695ca02815Sjsg amdgpu_job_free(job); 5705ca02815Sjsg err: 5711bb76ff1Sjsg amdgpu_ib_free(adev, ib_msg, f); 5725ca02815Sjsg return r; 5735ca02815Sjsg } 5745ca02815Sjsg 5755ca02815Sjsg static int amdgpu_vcn_dec_get_create_msg(struct amdgpu_ring *ring, uint32_t handle, 5761bb76ff1Sjsg struct amdgpu_ib *ib) 5775ca02815Sjsg { 5785ca02815Sjsg struct amdgpu_device *adev = ring->adev; 5795ca02815Sjsg uint32_t *msg; 5805ca02815Sjsg int r, i; 5815ca02815Sjsg 5821bb76ff1Sjsg memset(ib, 0, sizeof(*ib)); 5831bb76ff1Sjsg r = amdgpu_ib_get(adev, NULL, AMDGPU_GPU_PAGE_SIZE * 2, 5841bb76ff1Sjsg AMDGPU_IB_POOL_DIRECT, 5851bb76ff1Sjsg ib); 5865ca02815Sjsg if (r) 5875ca02815Sjsg return r; 5885ca02815Sjsg 5891bb76ff1Sjsg msg = (uint32_t *)AMDGPU_GPU_PAGE_ALIGN((unsigned long)ib->ptr); 5905ca02815Sjsg msg[0] = cpu_to_le32(0x00000028); 5915ca02815Sjsg msg[1] = cpu_to_le32(0x00000038); 5925ca02815Sjsg msg[2] = cpu_to_le32(0x00000001); 5935ca02815Sjsg msg[3] = cpu_to_le32(0x00000000); 5945ca02815Sjsg msg[4] = cpu_to_le32(handle); 5955ca02815Sjsg msg[5] = cpu_to_le32(0x00000000); 5965ca02815Sjsg msg[6] = cpu_to_le32(0x00000001); 5975ca02815Sjsg msg[7] = cpu_to_le32(0x00000028); 5985ca02815Sjsg msg[8] = cpu_to_le32(0x00000010); 5995ca02815Sjsg msg[9] = cpu_to_le32(0x00000000); 6005ca02815Sjsg msg[10] = cpu_to_le32(0x00000007); 6015ca02815Sjsg msg[11] = cpu_to_le32(0x00000000); 6025ca02815Sjsg msg[12] = cpu_to_le32(0x00000780); 6035ca02815Sjsg msg[13] = cpu_to_le32(0x00000440); 6045ca02815Sjsg for (i = 14; i < 1024; ++i) 6055ca02815Sjsg msg[i] = cpu_to_le32(0x0); 6065ca02815Sjsg 6075ca02815Sjsg return 0; 6085ca02815Sjsg } 6095ca02815Sjsg 6105ca02815Sjsg static int amdgpu_vcn_dec_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle, 6111bb76ff1Sjsg struct amdgpu_ib *ib) 6125ca02815Sjsg { 6135ca02815Sjsg struct amdgpu_device *adev = ring->adev; 6145ca02815Sjsg uint32_t *msg; 6155ca02815Sjsg int r, i; 6165ca02815Sjsg 6171bb76ff1Sjsg memset(ib, 0, sizeof(*ib)); 6181bb76ff1Sjsg r = amdgpu_ib_get(adev, NULL, AMDGPU_GPU_PAGE_SIZE * 2, 6191bb76ff1Sjsg AMDGPU_IB_POOL_DIRECT, 6201bb76ff1Sjsg ib); 6215ca02815Sjsg if (r) 6225ca02815Sjsg return r; 6235ca02815Sjsg 6241bb76ff1Sjsg msg = (uint32_t *)AMDGPU_GPU_PAGE_ALIGN((unsigned long)ib->ptr); 6255ca02815Sjsg msg[0] = cpu_to_le32(0x00000028); 6265ca02815Sjsg msg[1] = cpu_to_le32(0x00000018); 6275ca02815Sjsg msg[2] = cpu_to_le32(0x00000000); 6285ca02815Sjsg msg[3] = cpu_to_le32(0x00000002); 6295ca02815Sjsg msg[4] = cpu_to_le32(handle); 6305ca02815Sjsg msg[5] = cpu_to_le32(0x00000000); 6315ca02815Sjsg for (i = 6; i < 1024; ++i) 6325ca02815Sjsg msg[i] = cpu_to_le32(0x0); 6335ca02815Sjsg 6345ca02815Sjsg return 0; 6355ca02815Sjsg } 6365ca02815Sjsg 6375ca02815Sjsg int amdgpu_vcn_dec_ring_test_ib(struct amdgpu_ring *ring, long timeout) 6385ca02815Sjsg { 6395ca02815Sjsg struct dma_fence *fence = NULL; 6401bb76ff1Sjsg struct amdgpu_ib ib; 6415ca02815Sjsg long r; 6425ca02815Sjsg 6431bb76ff1Sjsg r = amdgpu_vcn_dec_get_create_msg(ring, 1, &ib); 6445ca02815Sjsg if (r) 6455ca02815Sjsg goto error; 6465ca02815Sjsg 6471bb76ff1Sjsg r = amdgpu_vcn_dec_send_msg(ring, &ib, NULL); 6485ca02815Sjsg if (r) 6495ca02815Sjsg goto error; 6501bb76ff1Sjsg r = amdgpu_vcn_dec_get_destroy_msg(ring, 1, &ib); 6515ca02815Sjsg if (r) 6525ca02815Sjsg goto error; 6535ca02815Sjsg 6541bb76ff1Sjsg r = amdgpu_vcn_dec_send_msg(ring, &ib, &fence); 6555ca02815Sjsg if (r) 6565ca02815Sjsg goto error; 6575ca02815Sjsg 6585ca02815Sjsg r = dma_fence_wait_timeout(fence, false, timeout); 6595ca02815Sjsg if (r == 0) 6605ca02815Sjsg r = -ETIMEDOUT; 6615ca02815Sjsg else if (r > 0) 6625ca02815Sjsg r = 0; 6635ca02815Sjsg 6645ca02815Sjsg dma_fence_put(fence); 6655ca02815Sjsg error: 6665ca02815Sjsg return r; 6675ca02815Sjsg } 6685ca02815Sjsg 6691bb76ff1Sjsg static uint32_t *amdgpu_vcn_unified_ring_ib_header(struct amdgpu_ib *ib, 6701bb76ff1Sjsg uint32_t ib_pack_in_dw, bool enc) 6711bb76ff1Sjsg { 6721bb76ff1Sjsg uint32_t *ib_checksum; 6731bb76ff1Sjsg 6741bb76ff1Sjsg ib->ptr[ib->length_dw++] = 0x00000010; /* single queue checksum */ 6751bb76ff1Sjsg ib->ptr[ib->length_dw++] = 0x30000002; 6761bb76ff1Sjsg ib_checksum = &ib->ptr[ib->length_dw++]; 6771bb76ff1Sjsg ib->ptr[ib->length_dw++] = ib_pack_in_dw; 6781bb76ff1Sjsg 6791bb76ff1Sjsg ib->ptr[ib->length_dw++] = 0x00000010; /* engine info */ 6801bb76ff1Sjsg ib->ptr[ib->length_dw++] = 0x30000001; 6811bb76ff1Sjsg ib->ptr[ib->length_dw++] = enc ? 0x2 : 0x3; 6821bb76ff1Sjsg ib->ptr[ib->length_dw++] = ib_pack_in_dw * sizeof(uint32_t); 6831bb76ff1Sjsg 6841bb76ff1Sjsg return ib_checksum; 6851bb76ff1Sjsg } 6861bb76ff1Sjsg 6871bb76ff1Sjsg static void amdgpu_vcn_unified_ring_ib_checksum(uint32_t **ib_checksum, 6881bb76ff1Sjsg uint32_t ib_pack_in_dw) 6891bb76ff1Sjsg { 6901bb76ff1Sjsg uint32_t i; 6911bb76ff1Sjsg uint32_t checksum = 0; 6921bb76ff1Sjsg 6931bb76ff1Sjsg for (i = 0; i < ib_pack_in_dw; i++) 6941bb76ff1Sjsg checksum += *(*ib_checksum + 2 + i); 6951bb76ff1Sjsg 6961bb76ff1Sjsg **ib_checksum = checksum; 6971bb76ff1Sjsg } 6981bb76ff1Sjsg 6995ca02815Sjsg static int amdgpu_vcn_dec_sw_send_msg(struct amdgpu_ring *ring, 7001bb76ff1Sjsg struct amdgpu_ib *ib_msg, 7015ca02815Sjsg struct dma_fence **fence) 7025ca02815Sjsg { 7035ca02815Sjsg struct amdgpu_vcn_decode_buffer *decode_buffer = NULL; 7041bb76ff1Sjsg unsigned int ib_size_dw = 64; 7055ca02815Sjsg struct amdgpu_device *adev = ring->adev; 7065ca02815Sjsg struct dma_fence *f = NULL; 7075ca02815Sjsg struct amdgpu_job *job; 7085ca02815Sjsg struct amdgpu_ib *ib; 7091bb76ff1Sjsg uint64_t addr = AMDGPU_GPU_PAGE_ALIGN(ib_msg->gpu_addr); 7101bb76ff1Sjsg uint32_t *ib_checksum; 7111bb76ff1Sjsg uint32_t ib_pack_in_dw; 7125ca02815Sjsg int i, r; 7135ca02815Sjsg 7146809abd7Sjsg if (adev->vcn.using_unified_queue) 7151bb76ff1Sjsg ib_size_dw += 8; 7161bb76ff1Sjsg 717f005ef32Sjsg r = amdgpu_job_alloc_with_ib(ring->adev, NULL, NULL, 718f005ef32Sjsg ib_size_dw * 4, AMDGPU_IB_POOL_DIRECT, 719f005ef32Sjsg &job); 7205ca02815Sjsg if (r) 7215ca02815Sjsg goto err; 7225ca02815Sjsg 7235ca02815Sjsg ib = &job->ibs[0]; 7245ca02815Sjsg ib->length_dw = 0; 7255ca02815Sjsg 7261bb76ff1Sjsg /* single queue headers */ 7276809abd7Sjsg if (adev->vcn.using_unified_queue) { 7281bb76ff1Sjsg ib_pack_in_dw = sizeof(struct amdgpu_vcn_decode_buffer) / sizeof(uint32_t) 7291bb76ff1Sjsg + 4 + 2; /* engine info + decoding ib in dw */ 7301bb76ff1Sjsg ib_checksum = amdgpu_vcn_unified_ring_ib_header(ib, ib_pack_in_dw, false); 7311bb76ff1Sjsg } 7321bb76ff1Sjsg 7335ca02815Sjsg ib->ptr[ib->length_dw++] = sizeof(struct amdgpu_vcn_decode_buffer) + 8; 7345ca02815Sjsg ib->ptr[ib->length_dw++] = cpu_to_le32(AMDGPU_VCN_IB_FLAG_DECODE_BUFFER); 7355ca02815Sjsg decode_buffer = (struct amdgpu_vcn_decode_buffer *)&(ib->ptr[ib->length_dw]); 7365ca02815Sjsg ib->length_dw += sizeof(struct amdgpu_vcn_decode_buffer) / 4; 7375ca02815Sjsg memset(decode_buffer, 0, sizeof(struct amdgpu_vcn_decode_buffer)); 7385ca02815Sjsg 7395ca02815Sjsg decode_buffer->valid_buf_flag |= cpu_to_le32(AMDGPU_VCN_CMD_FLAG_MSG_BUFFER); 7405ca02815Sjsg decode_buffer->msg_buffer_address_hi = cpu_to_le32(addr >> 32); 7415ca02815Sjsg decode_buffer->msg_buffer_address_lo = cpu_to_le32(addr); 7425ca02815Sjsg 7435ca02815Sjsg for (i = ib->length_dw; i < ib_size_dw; ++i) 7445ca02815Sjsg ib->ptr[i] = 0x0; 7455ca02815Sjsg 7466809abd7Sjsg if (adev->vcn.using_unified_queue) 7471bb76ff1Sjsg amdgpu_vcn_unified_ring_ib_checksum(&ib_checksum, ib_pack_in_dw); 7481bb76ff1Sjsg 7495ca02815Sjsg r = amdgpu_job_submit_direct(job, ring, &f); 7505ca02815Sjsg if (r) 7515ca02815Sjsg goto err_free; 7525ca02815Sjsg 7531bb76ff1Sjsg amdgpu_ib_free(adev, ib_msg, f); 754fb4d8502Sjsg 755fb4d8502Sjsg if (fence) 756fb4d8502Sjsg *fence = dma_fence_get(f); 757fb4d8502Sjsg dma_fence_put(f); 758fb4d8502Sjsg 759fb4d8502Sjsg return 0; 760fb4d8502Sjsg 761fb4d8502Sjsg err_free: 762fb4d8502Sjsg amdgpu_job_free(job); 763fb4d8502Sjsg err: 7641bb76ff1Sjsg amdgpu_ib_free(adev, ib_msg, f); 765fb4d8502Sjsg return r; 766fb4d8502Sjsg } 767fb4d8502Sjsg 7685ca02815Sjsg int amdgpu_vcn_dec_sw_ring_test_ib(struct amdgpu_ring *ring, long timeout) 769fb4d8502Sjsg { 7705ca02815Sjsg struct dma_fence *fence = NULL; 7711bb76ff1Sjsg struct amdgpu_ib ib; 772fb4d8502Sjsg long r; 773fb4d8502Sjsg 7741bb76ff1Sjsg r = amdgpu_vcn_dec_get_create_msg(ring, 1, &ib); 775c349dbc7Sjsg if (r) 776fb4d8502Sjsg goto error; 777fb4d8502Sjsg 7781bb76ff1Sjsg r = amdgpu_vcn_dec_sw_send_msg(ring, &ib, NULL); 7795ca02815Sjsg if (r) 7805ca02815Sjsg goto error; 7811bb76ff1Sjsg r = amdgpu_vcn_dec_get_destroy_msg(ring, 1, &ib); 7825ca02815Sjsg if (r) 7835ca02815Sjsg goto error; 7845ca02815Sjsg 7851bb76ff1Sjsg r = amdgpu_vcn_dec_sw_send_msg(ring, &ib, &fence); 786c349dbc7Sjsg if (r) 787fb4d8502Sjsg goto error; 788fb4d8502Sjsg 789fb4d8502Sjsg r = dma_fence_wait_timeout(fence, false, timeout); 790c349dbc7Sjsg if (r == 0) 791fb4d8502Sjsg r = -ETIMEDOUT; 792c349dbc7Sjsg else if (r > 0) 793fb4d8502Sjsg r = 0; 794fb4d8502Sjsg 795fb4d8502Sjsg dma_fence_put(fence); 796fb4d8502Sjsg error: 797fb4d8502Sjsg return r; 798fb4d8502Sjsg } 799fb4d8502Sjsg 800fb4d8502Sjsg int amdgpu_vcn_enc_ring_test_ring(struct amdgpu_ring *ring) 801fb4d8502Sjsg { 802fb4d8502Sjsg struct amdgpu_device *adev = ring->adev; 803e5adc274Sjsg uint32_t rptr; 804f005ef32Sjsg unsigned int i; 805fb4d8502Sjsg int r; 806fb4d8502Sjsg 807c349dbc7Sjsg if (amdgpu_sriov_vf(adev)) 808c349dbc7Sjsg return 0; 809c349dbc7Sjsg 810fb4d8502Sjsg r = amdgpu_ring_alloc(ring, 16); 811c349dbc7Sjsg if (r) 812fb4d8502Sjsg return r; 813e5adc274Sjsg 814e5adc274Sjsg rptr = amdgpu_ring_get_rptr(ring); 815e5adc274Sjsg 816fb4d8502Sjsg amdgpu_ring_write(ring, VCN_ENC_CMD_END); 817fb4d8502Sjsg amdgpu_ring_commit(ring); 818fb4d8502Sjsg 819fb4d8502Sjsg for (i = 0; i < adev->usec_timeout; i++) { 820fb4d8502Sjsg if (amdgpu_ring_get_rptr(ring) != rptr) 821fb4d8502Sjsg break; 822c349dbc7Sjsg udelay(1); 823fb4d8502Sjsg } 824fb4d8502Sjsg 825c349dbc7Sjsg if (i >= adev->usec_timeout) 826fb4d8502Sjsg r = -ETIMEDOUT; 827fb4d8502Sjsg 828fb4d8502Sjsg return r; 829fb4d8502Sjsg } 830fb4d8502Sjsg 831fb4d8502Sjsg static int amdgpu_vcn_enc_get_create_msg(struct amdgpu_ring *ring, uint32_t handle, 8321bb76ff1Sjsg struct amdgpu_ib *ib_msg, 833fb4d8502Sjsg struct dma_fence **fence) 834fb4d8502Sjsg { 8351bb76ff1Sjsg unsigned int ib_size_dw = 16; 8366809abd7Sjsg struct amdgpu_device *adev = ring->adev; 837fb4d8502Sjsg struct amdgpu_job *job; 838fb4d8502Sjsg struct amdgpu_ib *ib; 839fb4d8502Sjsg struct dma_fence *f = NULL; 8401bb76ff1Sjsg uint32_t *ib_checksum = NULL; 841c349dbc7Sjsg uint64_t addr; 842fb4d8502Sjsg int i, r; 843fb4d8502Sjsg 8446809abd7Sjsg if (adev->vcn.using_unified_queue) 8451bb76ff1Sjsg ib_size_dw += 8; 8461bb76ff1Sjsg 847f005ef32Sjsg r = amdgpu_job_alloc_with_ib(ring->adev, NULL, NULL, 848f005ef32Sjsg ib_size_dw * 4, AMDGPU_IB_POOL_DIRECT, 849f005ef32Sjsg &job); 850fb4d8502Sjsg if (r) 851fb4d8502Sjsg return r; 852fb4d8502Sjsg 853fb4d8502Sjsg ib = &job->ibs[0]; 8541bb76ff1Sjsg addr = AMDGPU_GPU_PAGE_ALIGN(ib_msg->gpu_addr); 855fb4d8502Sjsg 856fb4d8502Sjsg ib->length_dw = 0; 8571bb76ff1Sjsg 8586809abd7Sjsg if (adev->vcn.using_unified_queue) 8591bb76ff1Sjsg ib_checksum = amdgpu_vcn_unified_ring_ib_header(ib, 0x11, true); 8601bb76ff1Sjsg 861fb4d8502Sjsg ib->ptr[ib->length_dw++] = 0x00000018; 862fb4d8502Sjsg ib->ptr[ib->length_dw++] = 0x00000001; /* session info */ 863fb4d8502Sjsg ib->ptr[ib->length_dw++] = handle; 864c349dbc7Sjsg ib->ptr[ib->length_dw++] = upper_32_bits(addr); 865c349dbc7Sjsg ib->ptr[ib->length_dw++] = addr; 866fb4d8502Sjsg ib->ptr[ib->length_dw++] = 0x0000000b; 867fb4d8502Sjsg 868fb4d8502Sjsg ib->ptr[ib->length_dw++] = 0x00000014; 869fb4d8502Sjsg ib->ptr[ib->length_dw++] = 0x00000002; /* task info */ 870fb4d8502Sjsg ib->ptr[ib->length_dw++] = 0x0000001c; 871fb4d8502Sjsg ib->ptr[ib->length_dw++] = 0x00000000; 872fb4d8502Sjsg ib->ptr[ib->length_dw++] = 0x00000000; 873fb4d8502Sjsg 874fb4d8502Sjsg ib->ptr[ib->length_dw++] = 0x00000008; 875fb4d8502Sjsg ib->ptr[ib->length_dw++] = 0x08000001; /* op initialize */ 876fb4d8502Sjsg 877fb4d8502Sjsg for (i = ib->length_dw; i < ib_size_dw; ++i) 878fb4d8502Sjsg ib->ptr[i] = 0x0; 879fb4d8502Sjsg 8806809abd7Sjsg if (adev->vcn.using_unified_queue) 8811bb76ff1Sjsg amdgpu_vcn_unified_ring_ib_checksum(&ib_checksum, 0x11); 8821bb76ff1Sjsg 883fb4d8502Sjsg r = amdgpu_job_submit_direct(job, ring, &f); 884fb4d8502Sjsg if (r) 885fb4d8502Sjsg goto err; 886fb4d8502Sjsg 887fb4d8502Sjsg if (fence) 888fb4d8502Sjsg *fence = dma_fence_get(f); 889fb4d8502Sjsg dma_fence_put(f); 890fb4d8502Sjsg 891fb4d8502Sjsg return 0; 892fb4d8502Sjsg 893fb4d8502Sjsg err: 894fb4d8502Sjsg amdgpu_job_free(job); 895fb4d8502Sjsg return r; 896fb4d8502Sjsg } 897fb4d8502Sjsg 898fb4d8502Sjsg static int amdgpu_vcn_enc_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle, 8991bb76ff1Sjsg struct amdgpu_ib *ib_msg, 900fb4d8502Sjsg struct dma_fence **fence) 901fb4d8502Sjsg { 9021bb76ff1Sjsg unsigned int ib_size_dw = 16; 9036809abd7Sjsg struct amdgpu_device *adev = ring->adev; 904fb4d8502Sjsg struct amdgpu_job *job; 905fb4d8502Sjsg struct amdgpu_ib *ib; 906fb4d8502Sjsg struct dma_fence *f = NULL; 9071bb76ff1Sjsg uint32_t *ib_checksum = NULL; 908c349dbc7Sjsg uint64_t addr; 909fb4d8502Sjsg int i, r; 910fb4d8502Sjsg 9116809abd7Sjsg if (adev->vcn.using_unified_queue) 9121bb76ff1Sjsg ib_size_dw += 8; 9131bb76ff1Sjsg 914f005ef32Sjsg r = amdgpu_job_alloc_with_ib(ring->adev, NULL, NULL, 915f005ef32Sjsg ib_size_dw * 4, AMDGPU_IB_POOL_DIRECT, 916f005ef32Sjsg &job); 917fb4d8502Sjsg if (r) 918fb4d8502Sjsg return r; 919fb4d8502Sjsg 920fb4d8502Sjsg ib = &job->ibs[0]; 9211bb76ff1Sjsg addr = AMDGPU_GPU_PAGE_ALIGN(ib_msg->gpu_addr); 922fb4d8502Sjsg 923fb4d8502Sjsg ib->length_dw = 0; 9241bb76ff1Sjsg 9256809abd7Sjsg if (adev->vcn.using_unified_queue) 9261bb76ff1Sjsg ib_checksum = amdgpu_vcn_unified_ring_ib_header(ib, 0x11, true); 9271bb76ff1Sjsg 928fb4d8502Sjsg ib->ptr[ib->length_dw++] = 0x00000018; 929fb4d8502Sjsg ib->ptr[ib->length_dw++] = 0x00000001; 930fb4d8502Sjsg ib->ptr[ib->length_dw++] = handle; 931c349dbc7Sjsg ib->ptr[ib->length_dw++] = upper_32_bits(addr); 932c349dbc7Sjsg ib->ptr[ib->length_dw++] = addr; 933fb4d8502Sjsg ib->ptr[ib->length_dw++] = 0x0000000b; 934fb4d8502Sjsg 935fb4d8502Sjsg ib->ptr[ib->length_dw++] = 0x00000014; 936fb4d8502Sjsg ib->ptr[ib->length_dw++] = 0x00000002; 937fb4d8502Sjsg ib->ptr[ib->length_dw++] = 0x0000001c; 938fb4d8502Sjsg ib->ptr[ib->length_dw++] = 0x00000000; 939fb4d8502Sjsg ib->ptr[ib->length_dw++] = 0x00000000; 940fb4d8502Sjsg 941fb4d8502Sjsg ib->ptr[ib->length_dw++] = 0x00000008; 942fb4d8502Sjsg ib->ptr[ib->length_dw++] = 0x08000002; /* op close session */ 943fb4d8502Sjsg 944fb4d8502Sjsg for (i = ib->length_dw; i < ib_size_dw; ++i) 945fb4d8502Sjsg ib->ptr[i] = 0x0; 946fb4d8502Sjsg 9476809abd7Sjsg if (adev->vcn.using_unified_queue) 9481bb76ff1Sjsg amdgpu_vcn_unified_ring_ib_checksum(&ib_checksum, 0x11); 9491bb76ff1Sjsg 950fb4d8502Sjsg r = amdgpu_job_submit_direct(job, ring, &f); 951fb4d8502Sjsg if (r) 952fb4d8502Sjsg goto err; 953fb4d8502Sjsg 954fb4d8502Sjsg if (fence) 955fb4d8502Sjsg *fence = dma_fence_get(f); 956fb4d8502Sjsg dma_fence_put(f); 957fb4d8502Sjsg 958fb4d8502Sjsg return 0; 959fb4d8502Sjsg 960fb4d8502Sjsg err: 961fb4d8502Sjsg amdgpu_job_free(job); 962fb4d8502Sjsg return r; 963fb4d8502Sjsg } 964fb4d8502Sjsg 965fb4d8502Sjsg int amdgpu_vcn_enc_ring_test_ib(struct amdgpu_ring *ring, long timeout) 966fb4d8502Sjsg { 9671bb76ff1Sjsg struct amdgpu_device *adev = ring->adev; 968fb4d8502Sjsg struct dma_fence *fence = NULL; 9691bb76ff1Sjsg struct amdgpu_ib ib; 970fb4d8502Sjsg long r; 971fb4d8502Sjsg 9721bb76ff1Sjsg memset(&ib, 0, sizeof(ib)); 9731bb76ff1Sjsg r = amdgpu_ib_get(adev, NULL, (128 << 10) + AMDGPU_GPU_PAGE_SIZE, 9741bb76ff1Sjsg AMDGPU_IB_POOL_DIRECT, 9751bb76ff1Sjsg &ib); 976fb4d8502Sjsg if (r) 977fb4d8502Sjsg return r; 978fb4d8502Sjsg 9791bb76ff1Sjsg r = amdgpu_vcn_enc_get_create_msg(ring, 1, &ib, NULL); 980fb4d8502Sjsg if (r) 981fb4d8502Sjsg goto error; 982c349dbc7Sjsg 9831bb76ff1Sjsg r = amdgpu_vcn_enc_get_destroy_msg(ring, 1, &ib, &fence); 984c349dbc7Sjsg if (r) 985c349dbc7Sjsg goto error; 986fb4d8502Sjsg 987fb4d8502Sjsg r = dma_fence_wait_timeout(fence, false, timeout); 988c349dbc7Sjsg if (r == 0) 989fb4d8502Sjsg r = -ETIMEDOUT; 990c349dbc7Sjsg else if (r > 0) 991fb4d8502Sjsg r = 0; 992fb4d8502Sjsg 993fb4d8502Sjsg error: 9941bb76ff1Sjsg amdgpu_ib_free(adev, &ib, fence); 995c349dbc7Sjsg dma_fence_put(fence); 9965ca02815Sjsg 997fb4d8502Sjsg return r; 998fb4d8502Sjsg } 9991bb76ff1Sjsg 10001bb76ff1Sjsg int amdgpu_vcn_unified_ring_test_ib(struct amdgpu_ring *ring, long timeout) 10011bb76ff1Sjsg { 1002f005ef32Sjsg struct amdgpu_device *adev = ring->adev; 10031bb76ff1Sjsg long r; 10041bb76ff1Sjsg 1005f005ef32Sjsg if (adev->ip_versions[UVD_HWIP][0] != IP_VERSION(4, 0, 3)) { 10061bb76ff1Sjsg r = amdgpu_vcn_enc_ring_test_ib(ring, timeout); 10071bb76ff1Sjsg if (r) 10081bb76ff1Sjsg goto error; 1009f005ef32Sjsg } 10101bb76ff1Sjsg 10111bb76ff1Sjsg r = amdgpu_vcn_dec_sw_ring_test_ib(ring, timeout); 10121bb76ff1Sjsg 10131bb76ff1Sjsg error: 10141bb76ff1Sjsg return r; 10151bb76ff1Sjsg } 10161bb76ff1Sjsg 10171bb76ff1Sjsg enum amdgpu_ring_priority_level amdgpu_vcn_get_enc_ring_prio(int ring) 10181bb76ff1Sjsg { 10191bb76ff1Sjsg switch (ring) { 10201bb76ff1Sjsg case 0: 10211bb76ff1Sjsg return AMDGPU_RING_PRIO_0; 10221bb76ff1Sjsg case 1: 10231bb76ff1Sjsg return AMDGPU_RING_PRIO_1; 10241bb76ff1Sjsg case 2: 10251bb76ff1Sjsg return AMDGPU_RING_PRIO_2; 10261bb76ff1Sjsg default: 10271bb76ff1Sjsg return AMDGPU_RING_PRIO_0; 10281bb76ff1Sjsg } 10291bb76ff1Sjsg } 10301bb76ff1Sjsg 10311bb76ff1Sjsg void amdgpu_vcn_setup_ucode(struct amdgpu_device *adev) 10321bb76ff1Sjsg { 10331bb76ff1Sjsg int i; 10341bb76ff1Sjsg unsigned int idx; 10351bb76ff1Sjsg 10361bb76ff1Sjsg if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { 10371bb76ff1Sjsg const struct common_firmware_header *hdr; 1038f005ef32Sjsg 10391bb76ff1Sjsg hdr = (const struct common_firmware_header *)adev->vcn.fw->data; 10401bb76ff1Sjsg 10411bb76ff1Sjsg for (i = 0; i < adev->vcn.num_vcn_inst; i++) { 10421bb76ff1Sjsg if (adev->vcn.harvest_config & (1 << i)) 10431bb76ff1Sjsg continue; 10441bb76ff1Sjsg /* currently only support 2 FW instances */ 10451bb76ff1Sjsg if (i >= 2) { 10461bb76ff1Sjsg dev_info(adev->dev, "More then 2 VCN FW instances!\n"); 10471bb76ff1Sjsg break; 10481bb76ff1Sjsg } 10491bb76ff1Sjsg idx = AMDGPU_UCODE_ID_VCN + i; 10501bb76ff1Sjsg adev->firmware.ucode[idx].ucode_id = idx; 10511bb76ff1Sjsg adev->firmware.ucode[idx].fw = adev->vcn.fw; 10521bb76ff1Sjsg adev->firmware.fw_size += 1053f005ef32Sjsg ALIGN(le32_to_cpu(hdr->ucode_size_bytes), PAGE_SIZE); 1054f005ef32Sjsg 1055f005ef32Sjsg if (adev->ip_versions[UVD_HWIP][0] == IP_VERSION(4, 0, 3)) 1056f005ef32Sjsg break; 10571bb76ff1Sjsg } 10581bb76ff1Sjsg dev_info(adev->dev, "Will use PSP to load VCN firmware\n"); 10591bb76ff1Sjsg } 10601bb76ff1Sjsg } 10611bb76ff1Sjsg 10621bb76ff1Sjsg /* 10631bb76ff1Sjsg * debugfs for mapping vcn firmware log buffer. 10641bb76ff1Sjsg */ 10651bb76ff1Sjsg #if defined(CONFIG_DEBUG_FS) 10661bb76ff1Sjsg static ssize_t amdgpu_debugfs_vcn_fwlog_read(struct file *f, char __user *buf, 10671bb76ff1Sjsg size_t size, loff_t *pos) 10681bb76ff1Sjsg { 10691bb76ff1Sjsg struct amdgpu_vcn_inst *vcn; 10701bb76ff1Sjsg void *log_buf; 10711bb76ff1Sjsg volatile struct amdgpu_vcn_fwlog *plog; 10721bb76ff1Sjsg unsigned int read_pos, write_pos, available, i, read_bytes = 0; 10731bb76ff1Sjsg unsigned int read_num[2] = {0}; 10741bb76ff1Sjsg 10751bb76ff1Sjsg vcn = file_inode(f)->i_private; 10761bb76ff1Sjsg if (!vcn) 10771bb76ff1Sjsg return -ENODEV; 10781bb76ff1Sjsg 10791bb76ff1Sjsg if (!vcn->fw_shared.cpu_addr || !amdgpu_vcnfw_log) 10801bb76ff1Sjsg return -EFAULT; 10811bb76ff1Sjsg 10821bb76ff1Sjsg log_buf = vcn->fw_shared.cpu_addr + vcn->fw_shared.mem_size; 10831bb76ff1Sjsg 10841bb76ff1Sjsg plog = (volatile struct amdgpu_vcn_fwlog *)log_buf; 10851bb76ff1Sjsg read_pos = plog->rptr; 10861bb76ff1Sjsg write_pos = plog->wptr; 10871bb76ff1Sjsg 10881bb76ff1Sjsg if (read_pos > AMDGPU_VCNFW_LOG_SIZE || write_pos > AMDGPU_VCNFW_LOG_SIZE) 10891bb76ff1Sjsg return -EFAULT; 10901bb76ff1Sjsg 10911bb76ff1Sjsg if (!size || (read_pos == write_pos)) 10921bb76ff1Sjsg return 0; 10931bb76ff1Sjsg 10941bb76ff1Sjsg if (write_pos > read_pos) { 10951bb76ff1Sjsg available = write_pos - read_pos; 10961bb76ff1Sjsg read_num[0] = min(size, (size_t)available); 10971bb76ff1Sjsg } else { 10981bb76ff1Sjsg read_num[0] = AMDGPU_VCNFW_LOG_SIZE - read_pos; 10991bb76ff1Sjsg available = read_num[0] + write_pos - plog->header_size; 11001bb76ff1Sjsg if (size > available) 11011bb76ff1Sjsg read_num[1] = write_pos - plog->header_size; 11021bb76ff1Sjsg else if (size > read_num[0]) 11031bb76ff1Sjsg read_num[1] = size - read_num[0]; 11041bb76ff1Sjsg else 11051bb76ff1Sjsg read_num[0] = size; 11061bb76ff1Sjsg } 11071bb76ff1Sjsg 11081bb76ff1Sjsg for (i = 0; i < 2; i++) { 11091bb76ff1Sjsg if (read_num[i]) { 11101bb76ff1Sjsg if (read_pos == AMDGPU_VCNFW_LOG_SIZE) 11111bb76ff1Sjsg read_pos = plog->header_size; 11121bb76ff1Sjsg if (read_num[i] == copy_to_user((buf + read_bytes), 11131bb76ff1Sjsg (log_buf + read_pos), read_num[i])) 11141bb76ff1Sjsg return -EFAULT; 11151bb76ff1Sjsg 11161bb76ff1Sjsg read_bytes += read_num[i]; 11171bb76ff1Sjsg read_pos += read_num[i]; 11181bb76ff1Sjsg } 11191bb76ff1Sjsg } 11201bb76ff1Sjsg 11211bb76ff1Sjsg plog->rptr = read_pos; 11221bb76ff1Sjsg *pos += read_bytes; 11231bb76ff1Sjsg return read_bytes; 11241bb76ff1Sjsg } 11251bb76ff1Sjsg 11261bb76ff1Sjsg static const struct file_operations amdgpu_debugfs_vcnfwlog_fops = { 11271bb76ff1Sjsg .owner = THIS_MODULE, 11281bb76ff1Sjsg .read = amdgpu_debugfs_vcn_fwlog_read, 11291bb76ff1Sjsg .llseek = default_llseek 11301bb76ff1Sjsg }; 11311bb76ff1Sjsg #endif 11321bb76ff1Sjsg 11331bb76ff1Sjsg void amdgpu_debugfs_vcn_fwlog_init(struct amdgpu_device *adev, uint8_t i, 11341bb76ff1Sjsg struct amdgpu_vcn_inst *vcn) 11351bb76ff1Sjsg { 11361bb76ff1Sjsg #if defined(CONFIG_DEBUG_FS) 11371bb76ff1Sjsg struct drm_minor *minor = adev_to_drm(adev)->primary; 11381bb76ff1Sjsg struct dentry *root = minor->debugfs_root; 11391bb76ff1Sjsg char name[32]; 11401bb76ff1Sjsg 11411bb76ff1Sjsg sprintf(name, "amdgpu_vcn_%d_fwlog", i); 1142f005ef32Sjsg debugfs_create_file_size(name, S_IFREG | 0444, root, vcn, 11431bb76ff1Sjsg &amdgpu_debugfs_vcnfwlog_fops, 11441bb76ff1Sjsg AMDGPU_VCNFW_LOG_SIZE); 11451bb76ff1Sjsg #endif 11461bb76ff1Sjsg } 11471bb76ff1Sjsg 11481bb76ff1Sjsg void amdgpu_vcn_fwlog_init(struct amdgpu_vcn_inst *vcn) 11491bb76ff1Sjsg { 11501bb76ff1Sjsg #if defined(CONFIG_DEBUG_FS) 11511bb76ff1Sjsg volatile uint32_t *flag = vcn->fw_shared.cpu_addr; 11521bb76ff1Sjsg void *fw_log_cpu_addr = vcn->fw_shared.cpu_addr + vcn->fw_shared.mem_size; 11531bb76ff1Sjsg uint64_t fw_log_gpu_addr = vcn->fw_shared.gpu_addr + vcn->fw_shared.mem_size; 11541bb76ff1Sjsg volatile struct amdgpu_vcn_fwlog *log_buf = fw_log_cpu_addr; 11551bb76ff1Sjsg volatile struct amdgpu_fw_shared_fw_logging *fw_log = vcn->fw_shared.cpu_addr 11561bb76ff1Sjsg + vcn->fw_shared.log_offset; 11571bb76ff1Sjsg *flag |= cpu_to_le32(AMDGPU_VCN_FW_LOGGING_FLAG); 11581bb76ff1Sjsg fw_log->is_enabled = 1; 11591bb76ff1Sjsg fw_log->addr_lo = cpu_to_le32(fw_log_gpu_addr & 0xFFFFFFFF); 11601bb76ff1Sjsg fw_log->addr_hi = cpu_to_le32(fw_log_gpu_addr >> 32); 11611bb76ff1Sjsg fw_log->size = cpu_to_le32(AMDGPU_VCNFW_LOG_SIZE); 11621bb76ff1Sjsg 11631bb76ff1Sjsg log_buf->header_size = sizeof(struct amdgpu_vcn_fwlog); 11641bb76ff1Sjsg log_buf->buffer_size = AMDGPU_VCNFW_LOG_SIZE; 11651bb76ff1Sjsg log_buf->rptr = log_buf->header_size; 11661bb76ff1Sjsg log_buf->wptr = log_buf->header_size; 11671bb76ff1Sjsg log_buf->wrapped = 0; 11681bb76ff1Sjsg #endif 11691bb76ff1Sjsg } 11701bb76ff1Sjsg 11711bb76ff1Sjsg int amdgpu_vcn_process_poison_irq(struct amdgpu_device *adev, 11721bb76ff1Sjsg struct amdgpu_irq_src *source, 11731bb76ff1Sjsg struct amdgpu_iv_entry *entry) 11741bb76ff1Sjsg { 11751bb76ff1Sjsg struct ras_common_if *ras_if = adev->vcn.ras_if; 11761bb76ff1Sjsg struct ras_dispatch_if ih_data = { 11771bb76ff1Sjsg .entry = entry, 11781bb76ff1Sjsg }; 11791bb76ff1Sjsg 11801bb76ff1Sjsg if (!ras_if) 11811bb76ff1Sjsg return 0; 11821bb76ff1Sjsg 1183f005ef32Sjsg if (!amdgpu_sriov_vf(adev)) { 11841bb76ff1Sjsg ih_data.head = *ras_if; 11851bb76ff1Sjsg amdgpu_ras_interrupt_dispatch(adev, &ih_data); 1186f005ef32Sjsg } else { 1187f005ef32Sjsg if (adev->virt.ops && adev->virt.ops->ras_poison_handler) 1188f005ef32Sjsg adev->virt.ops->ras_poison_handler(adev); 1189f005ef32Sjsg else 1190f005ef32Sjsg dev_warn(adev->dev, 1191f005ef32Sjsg "No ras_poison_handler interface in SRIOV for VCN!\n"); 1192f005ef32Sjsg } 11931bb76ff1Sjsg 11941bb76ff1Sjsg return 0; 11951bb76ff1Sjsg } 1196f005ef32Sjsg 1197f005ef32Sjsg int amdgpu_vcn_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *ras_block) 1198f005ef32Sjsg { 1199f005ef32Sjsg int r, i; 1200f005ef32Sjsg 1201f005ef32Sjsg r = amdgpu_ras_block_late_init(adev, ras_block); 1202f005ef32Sjsg if (r) 1203f005ef32Sjsg return r; 1204f005ef32Sjsg 1205f005ef32Sjsg if (amdgpu_ras_is_supported(adev, ras_block->block)) { 1206f005ef32Sjsg for (i = 0; i < adev->vcn.num_vcn_inst; i++) { 1207f005ef32Sjsg if (adev->vcn.harvest_config & (1 << i) || 1208f005ef32Sjsg !adev->vcn.inst[i].ras_poison_irq.funcs) 1209f005ef32Sjsg continue; 1210f005ef32Sjsg 1211f005ef32Sjsg r = amdgpu_irq_get(adev, &adev->vcn.inst[i].ras_poison_irq, 0); 1212f005ef32Sjsg if (r) 1213f005ef32Sjsg goto late_fini; 1214f005ef32Sjsg } 1215f005ef32Sjsg } 1216f005ef32Sjsg return 0; 1217f005ef32Sjsg 1218f005ef32Sjsg late_fini: 1219f005ef32Sjsg amdgpu_ras_block_late_fini(adev, ras_block); 1220f005ef32Sjsg return r; 1221f005ef32Sjsg } 1222f005ef32Sjsg 1223f005ef32Sjsg int amdgpu_vcn_ras_sw_init(struct amdgpu_device *adev) 1224f005ef32Sjsg { 1225f005ef32Sjsg int err; 1226f005ef32Sjsg struct amdgpu_vcn_ras *ras; 1227f005ef32Sjsg 1228f005ef32Sjsg if (!adev->vcn.ras) 1229f005ef32Sjsg return 0; 1230f005ef32Sjsg 1231f005ef32Sjsg ras = adev->vcn.ras; 1232f005ef32Sjsg err = amdgpu_ras_register_ras_block(adev, &ras->ras_block); 1233f005ef32Sjsg if (err) { 1234f005ef32Sjsg dev_err(adev->dev, "Failed to register vcn ras block!\n"); 1235f005ef32Sjsg return err; 1236f005ef32Sjsg } 1237f005ef32Sjsg 1238f005ef32Sjsg strlcpy(ras->ras_block.ras_comm.name, "vcn", 1239f005ef32Sjsg sizeof(ras->ras_block.ras_comm.name)); 1240f005ef32Sjsg ras->ras_block.ras_comm.block = AMDGPU_RAS_BLOCK__VCN; 1241f005ef32Sjsg ras->ras_block.ras_comm.type = AMDGPU_RAS_ERROR__POISON; 1242f005ef32Sjsg adev->vcn.ras_if = &ras->ras_block.ras_comm; 1243f005ef32Sjsg 1244f005ef32Sjsg if (!ras->ras_block.ras_late_init) 1245f005ef32Sjsg ras->ras_block.ras_late_init = amdgpu_vcn_ras_late_init; 1246f005ef32Sjsg 1247f005ef32Sjsg return 0; 1248f005ef32Sjsg } 1249f005ef32Sjsg 1250f005ef32Sjsg int amdgpu_vcn_psp_update_sram(struct amdgpu_device *adev, int inst_idx, 1251f005ef32Sjsg enum AMDGPU_UCODE_ID ucode_id) 1252f005ef32Sjsg { 1253f005ef32Sjsg struct amdgpu_firmware_info ucode = { 1254f005ef32Sjsg .ucode_id = (ucode_id ? ucode_id : 1255f005ef32Sjsg (inst_idx ? AMDGPU_UCODE_ID_VCN1_RAM : 1256f005ef32Sjsg AMDGPU_UCODE_ID_VCN0_RAM)), 1257f005ef32Sjsg .mc_addr = adev->vcn.inst[inst_idx].dpg_sram_gpu_addr, 1258f005ef32Sjsg .ucode_size = ((uintptr_t)adev->vcn.inst[inst_idx].dpg_sram_curr_addr - 1259f005ef32Sjsg (uintptr_t)adev->vcn.inst[inst_idx].dpg_sram_cpu_addr), 1260f005ef32Sjsg }; 1261f005ef32Sjsg 1262f005ef32Sjsg return psp_execute_ip_fw_load(&adev->psp, &ucode); 1263f005ef32Sjsg } 1264