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