195d0906fSLeo Liu /*
2fdce10ffSSonny Jiang * Copyright 2016-2024 Advanced Micro Devices, Inc.
395d0906fSLeo Liu * All Rights Reserved.
495d0906fSLeo Liu *
595d0906fSLeo Liu * Permission is hereby granted, free of charge, to any person obtaining a
695d0906fSLeo Liu * copy of this software and associated documentation files (the
795d0906fSLeo Liu * "Software"), to deal in the Software without restriction, including
895d0906fSLeo Liu * without limitation the rights to use, copy, modify, merge, publish,
995d0906fSLeo Liu * distribute, sub license, and/or sell copies of the Software, and to
1095d0906fSLeo Liu * permit persons to whom the Software is furnished to do so, subject to
1195d0906fSLeo Liu * the following conditions:
1295d0906fSLeo Liu *
1395d0906fSLeo Liu * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1495d0906fSLeo Liu * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1595d0906fSLeo Liu * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
1695d0906fSLeo Liu * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
1795d0906fSLeo Liu * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
1895d0906fSLeo Liu * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
1995d0906fSLeo Liu * USE OR OTHER DEALINGS IN THE SOFTWARE.
2095d0906fSLeo Liu *
2195d0906fSLeo Liu * The above copyright notice and this permission notice (including the
2295d0906fSLeo Liu * next paragraph) shall be included in all copies or substantial portions
2395d0906fSLeo Liu * of the Software.
2495d0906fSLeo Liu *
2595d0906fSLeo Liu */
2695d0906fSLeo Liu
2795d0906fSLeo Liu #include <linux/firmware.h>
2895d0906fSLeo Liu #include <linux/module.h>
291aff0a5dSGuilherme G. Piccoli #include <linux/dmi.h>
30fdf2f6c5SSam Ravnborg #include <linux/pci.h>
3111eb648dSRuijing Dong #include <linux/debugfs.h>
32f89f8c6bSAndrey Grodzovsky #include <drm/drm_drv.h>
33fdf2f6c5SSam Ravnborg
3495d0906fSLeo Liu #include "amdgpu.h"
3595d0906fSLeo Liu #include "amdgpu_pm.h"
3695d0906fSLeo Liu #include "amdgpu_vcn.h"
3795d0906fSLeo Liu #include "soc15d.h"
3895d0906fSLeo Liu
3995d0906fSLeo Liu /* Firmware Names */
4095d0906fSLeo Liu #define FIRMWARE_RAVEN "amdgpu/raven_vcn.bin"
4186771d9aSLikun Gao #define FIRMWARE_PICASSO "amdgpu/picasso_vcn.bin"
428b47cc9bSFeifei Xu #define FIRMWARE_RAVEN2 "amdgpu/raven2_vcn.bin"
43a7c0e401SLeo Liu #define FIRMWARE_ARCTURUS "amdgpu/arcturus_vcn.bin"
44dc9b6e93SLeo Liu #define FIRMWARE_RENOIR "amdgpu/renoir_vcn.bin"
455d731b5aSThong Thai #define FIRMWARE_GREEN_SARDINE "amdgpu/green_sardine_vcn.bin"
46a8790e24SLeo Liu #define FIRMWARE_NAVI10 "amdgpu/navi10_vcn.bin"
47e149a2f6SJames Zhu #define FIRMWARE_NAVI14 "amdgpu/navi14_vcn.bin"
48a3219816SBoyuan Zhang #define FIRMWARE_NAVI12 "amdgpu/navi12_vcn.bin"
49265120abSLeo Liu #define FIRMWARE_SIENNA_CICHLID "amdgpu/sienna_cichlid_vcn.bin"
505cc07534SBoyuan Zhang #define FIRMWARE_NAVY_FLOUNDER "amdgpu/navy_flounder_vcn.bin"
51b4e532d6SThong Thai #define FIRMWARE_VANGOGH "amdgpu/vangogh_vcn.bin"
520c2c02b6SJames Zhu #define FIRMWARE_DIMGREY_CAVEFISH "amdgpu/dimgrey_cavefish_vcn.bin"
5386d848b1SJames Zhu #define FIRMWARE_ALDEBARAN "amdgpu/aldebaran_vcn.bin"
54f703d4b6SVeerabadhran Gopalakrishnan #define FIRMWARE_BEIGE_GOBY "amdgpu/beige_goby_vcn.bin"
55737a9f86SJames Zhu #define FIRMWARE_YELLOW_CARP "amdgpu/yellow_carp_vcn.bin"
56dd481828SAlex Deucher #define FIRMWARE_VCN_3_1_2 "amdgpu/vcn_3_1_2.bin"
578da1170aSLeo Liu #define FIRMWARE_VCN4_0_0 "amdgpu/vcn_4_0_0.bin"
58cbe93a23SSonny Jiang #define FIRMWARE_VCN4_0_2 "amdgpu/vcn_4_0_2.bin"
5976e5e4c7SJames Zhu #define FIRMWARE_VCN4_0_3 "amdgpu/vcn_4_0_3.bin"
60fbd23b55SJames Zhu #define FIRMWARE_VCN4_0_4 "amdgpu/vcn_4_0_4.bin"
611827b375SSaleemkhan Jamadar #define FIRMWARE_VCN4_0_5 "amdgpu/vcn_4_0_5.bin"
622b53b366SVeerabadhran Gopalakrishnan #define FIRMWARE_VCN4_0_6 "amdgpu/vcn_4_0_6.bin"
636a7cbbc2SSaleemkhan Jamadar #define FIRMWARE_VCN4_0_6_1 "amdgpu/vcn_4_0_6_1.bin"
64816dae1dSSonny Jiang #define FIRMWARE_VCN5_0_0 "amdgpu/vcn_5_0_0.bin"
65fdce10ffSSonny Jiang #define FIRMWARE_VCN5_0_1 "amdgpu/vcn_5_0_1.bin"
6695d0906fSLeo Liu
6795d0906fSLeo Liu MODULE_FIRMWARE(FIRMWARE_RAVEN);
6886771d9aSLikun Gao MODULE_FIRMWARE(FIRMWARE_PICASSO);
698b47cc9bSFeifei Xu MODULE_FIRMWARE(FIRMWARE_RAVEN2);
70a7c0e401SLeo Liu MODULE_FIRMWARE(FIRMWARE_ARCTURUS);
71dc9b6e93SLeo Liu MODULE_FIRMWARE(FIRMWARE_RENOIR);
725d731b5aSThong Thai MODULE_FIRMWARE(FIRMWARE_GREEN_SARDINE);
7386d848b1SJames Zhu MODULE_FIRMWARE(FIRMWARE_ALDEBARAN);
74a8790e24SLeo Liu MODULE_FIRMWARE(FIRMWARE_NAVI10);
75e149a2f6SJames Zhu MODULE_FIRMWARE(FIRMWARE_NAVI14);
76a3219816SBoyuan Zhang MODULE_FIRMWARE(FIRMWARE_NAVI12);
77265120abSLeo Liu MODULE_FIRMWARE(FIRMWARE_SIENNA_CICHLID);
785cc07534SBoyuan Zhang MODULE_FIRMWARE(FIRMWARE_NAVY_FLOUNDER);
79b4e532d6SThong Thai MODULE_FIRMWARE(FIRMWARE_VANGOGH);
800c2c02b6SJames Zhu MODULE_FIRMWARE(FIRMWARE_DIMGREY_CAVEFISH);
81f703d4b6SVeerabadhran Gopalakrishnan MODULE_FIRMWARE(FIRMWARE_BEIGE_GOBY);
82737a9f86SJames Zhu MODULE_FIRMWARE(FIRMWARE_YELLOW_CARP);
83afc2f276SBoyuan Zhang MODULE_FIRMWARE(FIRMWARE_VCN_3_1_2);
848da1170aSLeo Liu MODULE_FIRMWARE(FIRMWARE_VCN4_0_0);
85cbe93a23SSonny Jiang MODULE_FIRMWARE(FIRMWARE_VCN4_0_2);
8676e5e4c7SJames Zhu MODULE_FIRMWARE(FIRMWARE_VCN4_0_3);
87fbd23b55SJames Zhu MODULE_FIRMWARE(FIRMWARE_VCN4_0_4);
881827b375SSaleemkhan Jamadar MODULE_FIRMWARE(FIRMWARE_VCN4_0_5);
892b53b366SVeerabadhran Gopalakrishnan MODULE_FIRMWARE(FIRMWARE_VCN4_0_6);
906a7cbbc2SSaleemkhan Jamadar MODULE_FIRMWARE(FIRMWARE_VCN4_0_6_1);
91816dae1dSSonny Jiang MODULE_FIRMWARE(FIRMWARE_VCN5_0_0);
92fdce10ffSSonny Jiang MODULE_FIRMWARE(FIRMWARE_VCN5_0_1);
9395d0906fSLeo Liu
9495d0906fSLeo Liu static void amdgpu_vcn_idle_work_handler(struct work_struct *work);
9595d0906fSLeo Liu
amdgpu_vcn_early_init(struct amdgpu_device * adev,int i)96f9867563SAlex Deucher int amdgpu_vcn_early_init(struct amdgpu_device *adev, int i)
9769939009SMario Limonciello {
987c2bc34aSSrinivasan Shanmugam char ucode_prefix[25];
99f9867563SAlex Deucher int r;
10069939009SMario Limonciello
101bee48570SAlex Deucher adev->vcn.inst[i].adev = adev;
102bee48570SAlex Deucher adev->vcn.inst[i].inst = i;
103f9867563SAlex Deucher amdgpu_ucode_ip_version_decode(adev, UVD_HWIP, ucode_prefix, sizeof(ucode_prefix));
104bee48570SAlex Deucher
105c51aa792SAlex Deucher if (i != 0 && adev->vcn.per_inst_fw) {
106ea5d4934SMario Limonciello r = amdgpu_ucode_request(adev, &adev->vcn.inst[i].fw,
107ea5d4934SMario Limonciello AMDGPU_UCODE_REQUIRED,
108ea5d4934SMario Limonciello "amdgpu/%s_%d.bin", ucode_prefix, i);
109c51aa792SAlex Deucher if (r)
110c51aa792SAlex Deucher amdgpu_ucode_release(&adev->vcn.inst[i].fw);
111c51aa792SAlex Deucher } else {
112c51aa792SAlex Deucher if (!adev->vcn.inst[0].fw) {
113c51aa792SAlex Deucher r = amdgpu_ucode_request(adev, &adev->vcn.inst[0].fw,
114ea5d4934SMario Limonciello AMDGPU_UCODE_REQUIRED,
115ea5d4934SMario Limonciello "amdgpu/%s.bin", ucode_prefix);
116c51aa792SAlex Deucher if (r)
117c51aa792SAlex Deucher amdgpu_ucode_release(&adev->vcn.inst[0].fw);
118c51aa792SAlex Deucher } else {
119c51aa792SAlex Deucher r = 0;
1206a7cbbc2SSaleemkhan Jamadar }
121c51aa792SAlex Deucher adev->vcn.inst[i].fw = adev->vcn.inst[0].fw;
122c51aa792SAlex Deucher }
123c51aa792SAlex Deucher
12469939009SMario Limonciello return r;
12569939009SMario Limonciello }
12669939009SMario Limonciello
amdgpu_vcn_sw_init(struct amdgpu_device * adev,int i)127f9867563SAlex Deucher int amdgpu_vcn_sw_init(struct amdgpu_device *adev, int i)
12895d0906fSLeo Liu {
129d10985f4SJames Zhu unsigned long bo_size;
13095d0906fSLeo Liu const struct common_firmware_header *hdr;
13162d5b8e3SJames Zhu unsigned char fw_check;
13211eb648dSRuijing Dong unsigned int fw_shared_size, log_offset;
133f9867563SAlex Deucher int r;
13495d0906fSLeo Liu
135cb107271SAlex Deucher mutex_init(&adev->vcn.inst[i].vcn1_jpeg1_workaround);
136bee48570SAlex Deucher mutex_init(&adev->vcn.inst[i].vcn_pg_lock);
137bee48570SAlex Deucher atomic_set(&adev->vcn.inst[i].total_submission_cnt, 0);
138bee48570SAlex Deucher INIT_DELAYED_WORK(&adev->vcn.inst[i].idle_work, amdgpu_vcn_idle_work_handler);
139e3b41d82SJames Zhu atomic_set(&adev->vcn.inst[i].dpg_enc_submission_cnt, 0);
1400c0dab86SJames Zhu if ((adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) &&
1410c0dab86SJames Zhu (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG))
142cb107271SAlex Deucher adev->vcn.inst[i].indirect_sram = true;
14395d0906fSLeo Liu
1441aff0a5dSGuilherme G. Piccoli /*
1451aff0a5dSGuilherme G. Piccoli * Some Steam Deck's BIOS versions are incompatible with the
1461aff0a5dSGuilherme G. Piccoli * indirect SRAM mode, leading to amdgpu being unable to get
1471aff0a5dSGuilherme G. Piccoli * properly probed (and even potentially crashing the kernel).
1481aff0a5dSGuilherme G. Piccoli * Hence, check for these versions here - notice this is
1491aff0a5dSGuilherme G. Piccoli * restricted to Vangogh (Deck's APU).
1501aff0a5dSGuilherme G. Piccoli */
1514e8303cfSLijo Lazar if (amdgpu_ip_version(adev, UVD_HWIP, 0) == IP_VERSION(3, 0, 2)) {
1521aff0a5dSGuilherme G. Piccoli const char *bios_ver = dmi_get_system_info(DMI_BIOS_VERSION);
1531aff0a5dSGuilherme G. Piccoli
1541aff0a5dSGuilherme G. Piccoli if (bios_ver && (!strncmp("F7A0113", bios_ver, 7) ||
1551aff0a5dSGuilherme G. Piccoli !strncmp("F7A0114", bios_ver, 7))) {
156cb107271SAlex Deucher adev->vcn.inst[i].indirect_sram = false;
1571aff0a5dSGuilherme G. Piccoli dev_info(adev->dev,
1581aff0a5dSGuilherme G. Piccoli "Steam Deck quirk: indirect SRAM disabled on BIOS %s\n", bios_ver);
1591aff0a5dSGuilherme G. Piccoli }
1601aff0a5dSGuilherme G. Piccoli }
1611aff0a5dSGuilherme G. Piccoli
162ecfa23c8SBoyuan Zhang /* from vcn4 and above, only unified queue is used */
163cb107271SAlex Deucher adev->vcn.inst[i].using_unified_queue =
164ecfa23c8SBoyuan Zhang amdgpu_ip_version(adev, UVD_HWIP, 0) >= IP_VERSION(4, 0, 0);
165ecfa23c8SBoyuan Zhang
166cb107271SAlex Deucher hdr = (const struct common_firmware_header *)adev->vcn.inst[i].fw->data;
167cb107271SAlex Deucher adev->vcn.inst[i].fw_version = le32_to_cpu(hdr->ucode_version);
168a0b2ac29SHuang Rui adev->vcn.fw_version = le32_to_cpu(hdr->ucode_version);
16962d5b8e3SJames Zhu
17062d5b8e3SJames Zhu /* Bit 20-23, it is encode major and non-zero for new naming convention.
17162d5b8e3SJames Zhu * This field is part of version minor and DRM_DISABLED_FLAG in old naming
17262d5b8e3SJames Zhu * convention. Since the l:wq!atest version minor is 0x5B and DRM_DISABLED_FLAG
17362d5b8e3SJames Zhu * is zero in old naming convention, this field is always zero so far.
17462d5b8e3SJames Zhu * These four bits are used to tell which naming convention is present.
17562d5b8e3SJames Zhu */
17662d5b8e3SJames Zhu fw_check = (le32_to_cpu(hdr->ucode_version) >> 20) & 0xf;
17762d5b8e3SJames Zhu if (fw_check) {
17862d5b8e3SJames Zhu unsigned int dec_ver, enc_major, enc_minor, vep, fw_rev;
17962d5b8e3SJames Zhu
18062d5b8e3SJames Zhu fw_rev = le32_to_cpu(hdr->ucode_version) & 0xfff;
18162d5b8e3SJames Zhu enc_minor = (le32_to_cpu(hdr->ucode_version) >> 12) & 0xff;
18262d5b8e3SJames Zhu enc_major = fw_check;
18362d5b8e3SJames Zhu dec_ver = (le32_to_cpu(hdr->ucode_version) >> 24) & 0xf;
18462d5b8e3SJames Zhu vep = (le32_to_cpu(hdr->ucode_version) >> 28) & 0xf;
1854d1b6535SAlex Deucher dev_info(adev->dev,
1864d1b6535SAlex Deucher "Found VCN firmware Version ENC: %u.%u DEC: %u VEP: %u Revision: %u\n",
18762d5b8e3SJames Zhu enc_major, enc_minor, dec_ver, vep, fw_rev);
18862d5b8e3SJames Zhu } else {
18962d5b8e3SJames Zhu unsigned int version_major, version_minor, family_id;
19062d5b8e3SJames Zhu
19195d0906fSLeo Liu family_id = le32_to_cpu(hdr->ucode_version) & 0xff;
19295d0906fSLeo Liu version_major = (le32_to_cpu(hdr->ucode_version) >> 24) & 0xff;
19395d0906fSLeo Liu version_minor = (le32_to_cpu(hdr->ucode_version) >> 8) & 0xff;
1944d1b6535SAlex Deucher dev_info(adev->dev, "Found VCN firmware Version: %u.%u Family ID: %u\n",
19595d0906fSLeo Liu version_major, version_minor, family_id);
19662d5b8e3SJames Zhu }
19795d0906fSLeo Liu
198825da4d9SJames Zhu bo_size = AMDGPU_VCN_STACK_SIZE + AMDGPU_VCN_CONTEXT_SIZE;
199134b1461SThong Thai if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP)
2004d77c0f6SLikun Gao bo_size += AMDGPU_GPU_PAGE_ALIGN(le32_to_cpu(hdr->ucode_size_bytes) + 8);
2018da1170aSLeo Liu
202754c366eSSonny Jiang if (amdgpu_ip_version(adev, UVD_HWIP, 0) >= IP_VERSION(5, 0, 0)) {
203754c366eSSonny Jiang fw_shared_size = AMDGPU_GPU_PAGE_ALIGN(sizeof(struct amdgpu_vcn5_fw_shared));
204754c366eSSonny Jiang log_offset = offsetof(struct amdgpu_vcn5_fw_shared, fw_log);
205754c366eSSonny Jiang } else if (amdgpu_ip_version(adev, UVD_HWIP, 0) >= IP_VERSION(4, 0, 0)) {
2068da1170aSLeo Liu fw_shared_size = AMDGPU_GPU_PAGE_ALIGN(sizeof(struct amdgpu_vcn4_fw_shared));
2078da1170aSLeo Liu log_offset = offsetof(struct amdgpu_vcn4_fw_shared, fw_log);
2088da1170aSLeo Liu } else {
209b6065ebfSRuijing Dong fw_shared_size = AMDGPU_GPU_PAGE_ALIGN(sizeof(struct amdgpu_fw_shared));
21011eb648dSRuijing Dong log_offset = offsetof(struct amdgpu_fw_shared, fw_log);
2118da1170aSLeo Liu }
2128da1170aSLeo Liu
213b6065ebfSRuijing Dong bo_size += fw_shared_size;
214fa739f4bSJames Zhu
21511eb648dSRuijing Dong if (amdgpu_vcnfw_log)
21611eb648dSRuijing Dong bo_size += AMDGPU_VCNFW_LOG_SIZE;
21711eb648dSRuijing Dong
21895d0906fSLeo Liu r = amdgpu_bo_create_kernel(adev, bo_size, PAGE_SIZE,
21958ab2c08SChristian König AMDGPU_GEM_DOMAIN_VRAM |
22058ab2c08SChristian König AMDGPU_GEM_DOMAIN_GTT,
22158ab2c08SChristian König &adev->vcn.inst[i].vcpu_bo,
22258ab2c08SChristian König &adev->vcn.inst[i].gpu_addr,
22358ab2c08SChristian König &adev->vcn.inst[i].cpu_addr);
22495d0906fSLeo Liu if (r) {
22595d0906fSLeo Liu dev_err(adev->dev, "(%d) failed to allocate vcn bo\n", r);
22695d0906fSLeo Liu return r;
22795d0906fSLeo Liu }
22895d0906fSLeo Liu
229b6065ebfSRuijing Dong adev->vcn.inst[i].fw_shared.cpu_addr = adev->vcn.inst[i].cpu_addr +
230b6065ebfSRuijing Dong bo_size - fw_shared_size;
231b6065ebfSRuijing Dong adev->vcn.inst[i].fw_shared.gpu_addr = adev->vcn.inst[i].gpu_addr +
232b6065ebfSRuijing Dong bo_size - fw_shared_size;
233b6065ebfSRuijing Dong
234b6065ebfSRuijing Dong adev->vcn.inst[i].fw_shared.mem_size = fw_shared_size;
2354908d026SJames Zhu
23611eb648dSRuijing Dong if (amdgpu_vcnfw_log) {
23711eb648dSRuijing Dong adev->vcn.inst[i].fw_shared.cpu_addr -= AMDGPU_VCNFW_LOG_SIZE;
23811eb648dSRuijing Dong adev->vcn.inst[i].fw_shared.gpu_addr -= AMDGPU_VCNFW_LOG_SIZE;
23911eb648dSRuijing Dong adev->vcn.inst[i].fw_shared.log_offset = log_offset;
24011eb648dSRuijing Dong }
24111eb648dSRuijing Dong
242cb107271SAlex Deucher if (adev->vcn.inst[i].indirect_sram) {
243a77b9fdfSLeo Liu r = amdgpu_bo_create_kernel(adev, 64 * 2 * 4, PAGE_SIZE,
24458ab2c08SChristian König AMDGPU_GEM_DOMAIN_VRAM |
24558ab2c08SChristian König AMDGPU_GEM_DOMAIN_GTT,
24658ab2c08SChristian König &adev->vcn.inst[i].dpg_sram_bo,
24758ab2c08SChristian König &adev->vcn.inst[i].dpg_sram_gpu_addr,
24858ab2c08SChristian König &adev->vcn.inst[i].dpg_sram_cpu_addr);
249a77b9fdfSLeo Liu if (r) {
2505db86843SJames Zhu dev_err(adev->dev, "VCN %d (%d) failed to allocate DPG bo\n", i, r);
251a77b9fdfSLeo Liu return r;
252a77b9fdfSLeo Liu }
253a77b9fdfSLeo Liu }
254a77b9fdfSLeo Liu
25595d0906fSLeo Liu return 0;
25695d0906fSLeo Liu }
25795d0906fSLeo Liu
amdgpu_vcn_sw_fini(struct amdgpu_device * adev,int i)258f9867563SAlex Deucher int amdgpu_vcn_sw_fini(struct amdgpu_device *adev, int i)
25995d0906fSLeo Liu {
260f9867563SAlex Deucher int j;
26195d0906fSLeo Liu
262f9867563SAlex Deucher if (adev->vcn.harvest_config & (1 << i))
263f9867563SAlex Deucher return 0;
2642c68f0e3SJames Zhu
265a3edd1acSLijo Lazar amdgpu_bo_free_kernel(
266f9867563SAlex Deucher &adev->vcn.inst[i].dpg_sram_bo,
267f9867563SAlex Deucher &adev->vcn.inst[i].dpg_sram_gpu_addr,
268f9867563SAlex Deucher (void **)&adev->vcn.inst[i].dpg_sram_cpu_addr);
269a3edd1acSLijo Lazar
270f9867563SAlex Deucher kvfree(adev->vcn.inst[i].saved_bo);
27195d0906fSLeo Liu
272f9867563SAlex Deucher amdgpu_bo_free_kernel(&adev->vcn.inst[i].vcpu_bo,
273f9867563SAlex Deucher &adev->vcn.inst[i].gpu_addr,
274f9867563SAlex Deucher (void **)&adev->vcn.inst[i].cpu_addr);
275fa739f4bSJames Zhu
276f9867563SAlex Deucher amdgpu_ring_fini(&adev->vcn.inst[i].ring_dec);
27795d0906fSLeo Liu
278f9867563SAlex Deucher for (j = 0; j < adev->vcn.inst[i].num_enc_rings; ++j)
279f9867563SAlex Deucher amdgpu_ring_fini(&adev->vcn.inst[i].ring_enc[j]);
2806a7cbbc2SSaleemkhan Jamadar
281c51aa792SAlex Deucher if (adev->vcn.per_inst_fw) {
282f9867563SAlex Deucher amdgpu_ucode_release(&adev->vcn.inst[i].fw);
283c51aa792SAlex Deucher } else {
284c51aa792SAlex Deucher amdgpu_ucode_release(&adev->vcn.inst[0].fw);
285c51aa792SAlex Deucher adev->vcn.inst[i].fw = NULL;
286c51aa792SAlex Deucher }
287f9867563SAlex Deucher mutex_destroy(&adev->vcn.inst[i].vcn_pg_lock);
288f9867563SAlex Deucher mutex_destroy(&adev->vcn.inst[i].vcn1_jpeg1_workaround);
2890c5e4b3eSBoyuan Zhang
29095d0906fSLeo Liu return 0;
29195d0906fSLeo Liu }
29295d0906fSLeo Liu
amdgpu_vcn_is_disabled_vcn(struct amdgpu_device * adev,enum vcn_ring_type type,uint32_t vcn_instance)293376002f4SBokun Zhang bool amdgpu_vcn_is_disabled_vcn(struct amdgpu_device *adev, enum vcn_ring_type type, uint32_t vcn_instance)
294376002f4SBokun Zhang {
295376002f4SBokun Zhang bool ret = false;
296cf1aa9ffSBoyuan Zhang int vcn_config = adev->vcn.inst[vcn_instance].vcn_config;
297376002f4SBokun Zhang
2985d062270SSrinivasan Shanmugam if ((type == VCN_ENCODE_RING) && (vcn_config & VCN_BLOCK_ENCODE_DISABLE_MASK))
299376002f4SBokun Zhang ret = true;
3005d062270SSrinivasan Shanmugam else if ((type == VCN_DECODE_RING) && (vcn_config & VCN_BLOCK_DECODE_DISABLE_MASK))
301376002f4SBokun Zhang ret = true;
3025d062270SSrinivasan Shanmugam else if ((type == VCN_UNIFIED_RING) && (vcn_config & VCN_BLOCK_QUEUE_DISABLE_MASK))
303376002f4SBokun Zhang ret = true;
304376002f4SBokun Zhang
305376002f4SBokun Zhang return ret;
306376002f4SBokun Zhang }
307376002f4SBokun Zhang
amdgpu_vcn_save_vcpu_bo_inst(struct amdgpu_device * adev,int i)308f9867563SAlex Deucher static int amdgpu_vcn_save_vcpu_bo_inst(struct amdgpu_device *adev, int i)
30995d0906fSLeo Liu {
3105d062270SSrinivasan Shanmugam unsigned int size;
31195d0906fSLeo Liu void *ptr;
312f9867563SAlex Deucher int idx;
31395d0906fSLeo Liu
314cd1fd7b3SJames Zhu if (adev->vcn.harvest_config & (1 << i))
315f9867563SAlex Deucher return 0;
316fa739f4bSJames Zhu if (adev->vcn.inst[i].vcpu_bo == NULL)
31795d0906fSLeo Liu return 0;
31895d0906fSLeo Liu
319fa739f4bSJames Zhu size = amdgpu_bo_size(adev->vcn.inst[i].vcpu_bo);
320fa739f4bSJames Zhu ptr = adev->vcn.inst[i].cpu_addr;
32195d0906fSLeo Liu
322fa739f4bSJames Zhu adev->vcn.inst[i].saved_bo = kvmalloc(size, GFP_KERNEL);
323fa739f4bSJames Zhu if (!adev->vcn.inst[i].saved_bo)
32495d0906fSLeo Liu return -ENOMEM;
32595d0906fSLeo Liu
326c58a863bSGuchun Chen if (drm_dev_enter(adev_to_drm(adev), &idx)) {
327fa739f4bSJames Zhu memcpy_fromio(adev->vcn.inst[i].saved_bo, ptr, size);
328f89f8c6bSAndrey Grodzovsky drm_dev_exit(idx);
329f89f8c6bSAndrey Grodzovsky }
330f9867563SAlex Deucher
331f9867563SAlex Deucher return 0;
332f9867563SAlex Deucher }
333f9867563SAlex Deucher
amdgpu_vcn_save_vcpu_bo(struct amdgpu_device * adev)334f9867563SAlex Deucher int amdgpu_vcn_save_vcpu_bo(struct amdgpu_device *adev)
335f9867563SAlex Deucher {
336f9867563SAlex Deucher int ret, i;
337f9867563SAlex Deucher
338f9867563SAlex Deucher for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
339f9867563SAlex Deucher ret = amdgpu_vcn_save_vcpu_bo_inst(adev, i);
340f9867563SAlex Deucher if (ret)
341f9867563SAlex Deucher return ret;
342fa739f4bSJames Zhu }
343591aec15SLijo Lazar
34495d0906fSLeo Liu return 0;
34595d0906fSLeo Liu }
34695d0906fSLeo Liu
amdgpu_vcn_suspend(struct amdgpu_device * adev,int i)347f9867563SAlex Deucher int amdgpu_vcn_suspend(struct amdgpu_device *adev, int i)
348591aec15SLijo Lazar {
349591aec15SLijo Lazar bool in_ras_intr = amdgpu_ras_intr_triggered();
350591aec15SLijo Lazar
351f9867563SAlex Deucher if (adev->vcn.harvest_config & (1 << i))
352f9867563SAlex Deucher return 0;
353f9867563SAlex Deucher
354bee48570SAlex Deucher cancel_delayed_work_sync(&adev->vcn.inst[i].idle_work);
355591aec15SLijo Lazar
356591aec15SLijo Lazar /* err_event_athub will corrupt VCPU buffer, so we need to
357591aec15SLijo Lazar * restore fw data and clear buffer in amdgpu_vcn_resume() */
358591aec15SLijo Lazar if (in_ras_intr)
359591aec15SLijo Lazar return 0;
360591aec15SLijo Lazar
361f9867563SAlex Deucher return amdgpu_vcn_save_vcpu_bo_inst(adev, i);
362591aec15SLijo Lazar }
363591aec15SLijo Lazar
amdgpu_vcn_resume(struct amdgpu_device * adev,int i)364f9867563SAlex Deucher int amdgpu_vcn_resume(struct amdgpu_device *adev, int i)
36595d0906fSLeo Liu {
3665d062270SSrinivasan Shanmugam unsigned int size;
36795d0906fSLeo Liu void *ptr;
368f9867563SAlex Deucher int idx;
36995d0906fSLeo Liu
370cd1fd7b3SJames Zhu if (adev->vcn.harvest_config & (1 << i))
371f9867563SAlex Deucher return 0;
372fa739f4bSJames Zhu if (adev->vcn.inst[i].vcpu_bo == NULL)
37395d0906fSLeo Liu return -EINVAL;
37495d0906fSLeo Liu
375fa739f4bSJames Zhu size = amdgpu_bo_size(adev->vcn.inst[i].vcpu_bo);
376fa739f4bSJames Zhu ptr = adev->vcn.inst[i].cpu_addr;
37795d0906fSLeo Liu
378fa739f4bSJames Zhu if (adev->vcn.inst[i].saved_bo != NULL) {
379c58a863bSGuchun Chen if (drm_dev_enter(adev_to_drm(adev), &idx)) {
380fa739f4bSJames Zhu memcpy_toio(ptr, adev->vcn.inst[i].saved_bo, size);
381f89f8c6bSAndrey Grodzovsky drm_dev_exit(idx);
382f89f8c6bSAndrey Grodzovsky }
383fa739f4bSJames Zhu kvfree(adev->vcn.inst[i].saved_bo);
384fa739f4bSJames Zhu adev->vcn.inst[i].saved_bo = NULL;
38595d0906fSLeo Liu } else {
38695d0906fSLeo Liu const struct common_firmware_header *hdr;
3875d062270SSrinivasan Shanmugam unsigned int offset;
38895d0906fSLeo Liu
389cf1aa9ffSBoyuan Zhang hdr = (const struct common_firmware_header *)adev->vcn.inst[i].fw->data;
390134b1461SThong Thai if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) {
39195d0906fSLeo Liu offset = le32_to_cpu(hdr->ucode_array_offset_bytes);
392c58a863bSGuchun Chen if (drm_dev_enter(adev_to_drm(adev), &idx)) {
3936a7cbbc2SSaleemkhan Jamadar memcpy_toio(adev->vcn.inst[i].cpu_addr,
394cf1aa9ffSBoyuan Zhang adev->vcn.inst[i].fw->data + offset,
39595d0906fSLeo Liu le32_to_cpu(hdr->ucode_size_bytes));
396f89f8c6bSAndrey Grodzovsky drm_dev_exit(idx);
397f89f8c6bSAndrey Grodzovsky }
39895d0906fSLeo Liu size -= le32_to_cpu(hdr->ucode_size_bytes);
39995d0906fSLeo Liu ptr += le32_to_cpu(hdr->ucode_size_bytes);
4004d77c0f6SLikun Gao }
40195d0906fSLeo Liu memset_io(ptr, 0, size);
40295d0906fSLeo Liu }
403f9867563SAlex Deucher
40495d0906fSLeo Liu return 0;
40595d0906fSLeo Liu }
40695d0906fSLeo Liu
amdgpu_vcn_idle_work_handler(struct work_struct * work)4073e1086cfSLeo Liu static void amdgpu_vcn_idle_work_handler(struct work_struct *work)
4083e1086cfSLeo Liu {
409bee48570SAlex Deucher struct amdgpu_vcn_inst *vcn_inst =
410bee48570SAlex Deucher container_of(work, struct amdgpu_vcn_inst, idle_work.work);
411bee48570SAlex Deucher struct amdgpu_device *adev = vcn_inst->adev;
412fa739f4bSJames Zhu unsigned int fences = 0, fence[AMDGPU_MAX_VCN_INSTANCES] = {0};
413bee48570SAlex Deucher unsigned int i = vcn_inst->inst, j;
4145ce71f59SKenneth Feng int r = 0;
415646e906dSAlex Deucher
416bee48570SAlex Deucher if (adev->vcn.harvest_config & (1 << i))
417bee48570SAlex Deucher return;
4185e1e89eeSLeo Liu
419cb107271SAlex Deucher for (j = 0; j < adev->vcn.inst[i].num_enc_rings; ++j)
420bee48570SAlex Deucher fence[i] += amdgpu_fence_count_emitted(&vcn_inst->ring_enc[j]);
4213e1086cfSLeo Liu
4227d75ef37SBoyuan Zhang /* Only set DPG pause for VCN3 or below, VCN4 and above will be handled by FW */
4237d75ef37SBoyuan Zhang if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG &&
424cb107271SAlex Deucher !adev->vcn.inst[i].using_unified_queue) {
425bd5d5180SJames Zhu struct dpg_pause_state new_state;
426bd5d5180SJames Zhu
427bee48570SAlex Deucher if (fence[i] ||
428bee48570SAlex Deucher unlikely(atomic_read(&vcn_inst->dpg_enc_submission_cnt)))
429bd5d5180SJames Zhu new_state.fw_based = VCN_DPG_STATE__PAUSE;
430bd5d5180SJames Zhu else
431bd5d5180SJames Zhu new_state.fw_based = VCN_DPG_STATE__UNPAUSE;
432bd5d5180SJames Zhu
43364303b72SAlex Deucher adev->vcn.inst[i].pause_dpg_mode(vcn_inst, &new_state);
434bd5d5180SJames Zhu }
435bd5d5180SJames Zhu
436bee48570SAlex Deucher fence[i] += amdgpu_fence_count_emitted(&vcn_inst->ring_dec);
437bee48570SAlex Deucher fences += fence[i];
4387b4e54a9SLeo Liu
439bee48570SAlex Deucher if (!fences && !atomic_read(&vcn_inst->total_submission_cnt)) {
4404ce4fe27SAlex Deucher vcn_inst->set_pg_state(vcn_inst, AMD_PG_STATE_GATE);
441ca6575a3SAlex Deucher mutex_lock(&adev->vcn.workload_profile_mutex);
442ca6575a3SAlex Deucher if (adev->vcn.workload_profile_active) {
4435ce71f59SKenneth Feng r = amdgpu_dpm_switch_power_profile(adev, PP_SMC_POWER_PROFILE_VIDEO,
4445ce71f59SKenneth Feng false);
4455ce71f59SKenneth Feng if (r)
4465ce71f59SKenneth Feng dev_warn(adev->dev, "(%d) failed to disable video power profile mode\n", r);
447ca6575a3SAlex Deucher adev->vcn.workload_profile_active = false;
448ca6575a3SAlex Deucher }
449ca6575a3SAlex Deucher mutex_unlock(&adev->vcn.workload_profile_mutex);
4503e1086cfSLeo Liu } else {
451bee48570SAlex Deucher schedule_delayed_work(&vcn_inst->idle_work, VCN_IDLE_TIMEOUT);
4523e1086cfSLeo Liu }
4533e1086cfSLeo Liu }
4543e1086cfSLeo Liu
amdgpu_vcn_ring_begin_use(struct amdgpu_ring * ring)4553e1086cfSLeo Liu void amdgpu_vcn_ring_begin_use(struct amdgpu_ring *ring)
4563e1086cfSLeo Liu {
4573e1086cfSLeo Liu struct amdgpu_device *adev = ring->adev;
4584ce4fe27SAlex Deucher struct amdgpu_vcn_inst *vcn_inst = &adev->vcn.inst[ring->me];
4595ce71f59SKenneth Feng int r = 0;
4603e1086cfSLeo Liu
4614ce4fe27SAlex Deucher atomic_inc(&vcn_inst->total_submission_cnt);
462ef3b2987SJiansong Chen
463*3b669df9SAlex Deucher cancel_delayed_work_sync(&vcn_inst->idle_work);
464*3b669df9SAlex Deucher
465*3b669df9SAlex Deucher /* We can safely return early here because we've cancelled the
466*3b669df9SAlex Deucher * the delayed work so there is no one else to set it to false
467*3b669df9SAlex Deucher * and we don't care if someone else sets it to true.
468*3b669df9SAlex Deucher */
469*3b669df9SAlex Deucher if (adev->vcn.workload_profile_active)
470*3b669df9SAlex Deucher goto pg_lock;
471*3b669df9SAlex Deucher
472ca6575a3SAlex Deucher mutex_lock(&adev->vcn.workload_profile_mutex);
473ca6575a3SAlex Deucher if (!adev->vcn.workload_profile_active) {
4745ce71f59SKenneth Feng r = amdgpu_dpm_switch_power_profile(adev, PP_SMC_POWER_PROFILE_VIDEO,
4755ce71f59SKenneth Feng true);
4765ce71f59SKenneth Feng if (r)
4775ce71f59SKenneth Feng dev_warn(adev->dev, "(%d) failed to switch to video power profile mode\n", r);
478ca6575a3SAlex Deucher adev->vcn.workload_profile_active = true;
479ca6575a3SAlex Deucher }
480ca6575a3SAlex Deucher mutex_unlock(&adev->vcn.workload_profile_mutex);
481bd718638SJames Zhu
482*3b669df9SAlex Deucher pg_lock:
4834ce4fe27SAlex Deucher mutex_lock(&vcn_inst->vcn_pg_lock);
4844ce4fe27SAlex Deucher vcn_inst->set_pg_state(vcn_inst, AMD_PG_STATE_UNGATE);
485bd5d5180SJames Zhu
4867d75ef37SBoyuan Zhang /* Only set DPG pause for VCN3 or below, VCN4 and above will be handled by FW */
4877d75ef37SBoyuan Zhang if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG &&
4884ce4fe27SAlex Deucher !vcn_inst->using_unified_queue) {
489bd5d5180SJames Zhu struct dpg_pause_state new_state;
490e3b41d82SJames Zhu
491e3b41d82SJames Zhu if (ring->funcs->type == AMDGPU_RING_TYPE_VCN_ENC) {
4924ce4fe27SAlex Deucher atomic_inc(&vcn_inst->dpg_enc_submission_cnt);
493e3b41d82SJames Zhu new_state.fw_based = VCN_DPG_STATE__PAUSE;
494e3b41d82SJames Zhu } else {
49512e8b301SJames Zhu unsigned int fences = 0;
49612e8b301SJames Zhu unsigned int i;
49712e8b301SJames Zhu
4984ce4fe27SAlex Deucher for (i = 0; i < vcn_inst->num_enc_rings; ++i)
4994ce4fe27SAlex Deucher fences += amdgpu_fence_count_emitted(&vcn_inst->ring_enc[i]);
500e3b41d82SJames Zhu
5014ce4fe27SAlex Deucher if (fences || atomic_read(&vcn_inst->dpg_enc_submission_cnt))
50212e8b301SJames Zhu new_state.fw_based = VCN_DPG_STATE__PAUSE;
50312e8b301SJames Zhu else
50412e8b301SJames Zhu new_state.fw_based = VCN_DPG_STATE__UNPAUSE;
505e3b41d82SJames Zhu }
506bd5d5180SJames Zhu
5074ce4fe27SAlex Deucher vcn_inst->pause_dpg_mode(vcn_inst, &new_state);
508bd5d5180SJames Zhu }
5094ce4fe27SAlex Deucher mutex_unlock(&vcn_inst->vcn_pg_lock);
5103e1086cfSLeo Liu }
5113e1086cfSLeo Liu
amdgpu_vcn_ring_end_use(struct amdgpu_ring * ring)5123e1086cfSLeo Liu void amdgpu_vcn_ring_end_use(struct amdgpu_ring *ring)
5133e1086cfSLeo Liu {
5147d75ef37SBoyuan Zhang struct amdgpu_device *adev = ring->adev;
5157d75ef37SBoyuan Zhang
5167d75ef37SBoyuan Zhang /* Only set DPG pause for VCN3 or below, VCN4 and above will be handled by FW */
517e3b41d82SJames Zhu if (ring->adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG &&
5187d75ef37SBoyuan Zhang ring->funcs->type == AMDGPU_RING_TYPE_VCN_ENC &&
519cb107271SAlex Deucher !adev->vcn.inst[ring->me].using_unified_queue)
520e3b41d82SJames Zhu atomic_dec(&ring->adev->vcn.inst[ring->me].dpg_enc_submission_cnt);
521e3b41d82SJames Zhu
522bee48570SAlex Deucher atomic_dec(&ring->adev->vcn.inst[ring->me].total_submission_cnt);
523bd718638SJames Zhu
524bee48570SAlex Deucher schedule_delayed_work(&ring->adev->vcn.inst[ring->me].idle_work,
525bee48570SAlex Deucher VCN_IDLE_TIMEOUT);
5263e1086cfSLeo Liu }
5273e1086cfSLeo Liu
amdgpu_vcn_dec_ring_test_ring(struct amdgpu_ring * ring)5288c303c01SLeo Liu int amdgpu_vcn_dec_ring_test_ring(struct amdgpu_ring *ring)
5298c303c01SLeo Liu {
5308c303c01SLeo Liu struct amdgpu_device *adev = ring->adev;
5318c303c01SLeo Liu uint32_t tmp = 0;
5325d062270SSrinivasan Shanmugam unsigned int i;
5338c303c01SLeo Liu int r;
5348c303c01SLeo Liu
535c8466cc0SJack Zhang /* VCN in SRIOV does not support direct register read/write */
536c8466cc0SJack Zhang if (amdgpu_sriov_vf(adev))
537c8466cc0SJack Zhang return 0;
538c8466cc0SJack Zhang
539fa739f4bSJames Zhu WREG32(adev->vcn.inst[ring->me].external.scratch9, 0xCAFEDEAD);
5408c303c01SLeo Liu r = amdgpu_ring_alloc(ring, 3);
541dc9eeff8SChristian König if (r)
5428c303c01SLeo Liu return r;
543cb107271SAlex Deucher amdgpu_ring_write(ring, PACKET0(adev->vcn.inst[ring->me].internal.scratch9, 0));
5448c303c01SLeo Liu amdgpu_ring_write(ring, 0xDEADBEEF);
5458c303c01SLeo Liu amdgpu_ring_commit(ring);
5468c303c01SLeo Liu for (i = 0; i < adev->usec_timeout; i++) {
547fa739f4bSJames Zhu tmp = RREG32(adev->vcn.inst[ring->me].external.scratch9);
5488c303c01SLeo Liu if (tmp == 0xDEADBEEF)
5498c303c01SLeo Liu break;
550c366be54SSam Ravnborg udelay(1);
5518c303c01SLeo Liu }
5528c303c01SLeo Liu
553dc9eeff8SChristian König if (i >= adev->usec_timeout)
554dc9eeff8SChristian König r = -ETIMEDOUT;
555dc9eeff8SChristian König
5568c303c01SLeo Liu return r;
5578c303c01SLeo Liu }
5588c303c01SLeo Liu
amdgpu_vcn_dec_sw_ring_test_ring(struct amdgpu_ring * ring)559bd88596fSJames Zhu int amdgpu_vcn_dec_sw_ring_test_ring(struct amdgpu_ring *ring)
560bd88596fSJames Zhu {
561bd88596fSJames Zhu struct amdgpu_device *adev = ring->adev;
562bd88596fSJames Zhu uint32_t rptr;
563bd88596fSJames Zhu unsigned int i;
564bd88596fSJames Zhu int r;
565bd88596fSJames Zhu
566bd88596fSJames Zhu if (amdgpu_sriov_vf(adev))
567bd88596fSJames Zhu return 0;
568bd88596fSJames Zhu
569bd88596fSJames Zhu r = amdgpu_ring_alloc(ring, 16);
570bd88596fSJames Zhu if (r)
571bd88596fSJames Zhu return r;
572bd88596fSJames Zhu
573bd88596fSJames Zhu rptr = amdgpu_ring_get_rptr(ring);
574bd88596fSJames Zhu
575bd88596fSJames Zhu amdgpu_ring_write(ring, VCN_DEC_SW_CMD_END);
576bd88596fSJames Zhu amdgpu_ring_commit(ring);
577bd88596fSJames Zhu
578bd88596fSJames Zhu for (i = 0; i < adev->usec_timeout; i++) {
579bd88596fSJames Zhu if (amdgpu_ring_get_rptr(ring) != rptr)
580bd88596fSJames Zhu break;
581bd88596fSJames Zhu udelay(1);
582bd88596fSJames Zhu }
583bd88596fSJames Zhu
584bd88596fSJames Zhu if (i >= adev->usec_timeout)
585bd88596fSJames Zhu r = -ETIMEDOUT;
586bd88596fSJames Zhu
587bd88596fSJames Zhu return r;
588bd88596fSJames Zhu }
589bd88596fSJames Zhu
amdgpu_vcn_dec_send_msg(struct amdgpu_ring * ring,struct amdgpu_ib * ib_msg,struct dma_fence ** fence)590add9f9a8SChristian König static int amdgpu_vcn_dec_send_msg(struct amdgpu_ring *ring,
591405a81aeSxinhui pan struct amdgpu_ib *ib_msg,
592add9f9a8SChristian König struct dma_fence **fence)
59395d0906fSLeo Liu {
594f7d66fb2SChristian König u64 addr = AMDGPU_GPU_PAGE_ALIGN(ib_msg->gpu_addr);
595add9f9a8SChristian König struct amdgpu_device *adev = ring->adev;
596add9f9a8SChristian König struct dma_fence *f = NULL;
59795d0906fSLeo Liu struct amdgpu_job *job;
59895d0906fSLeo Liu struct amdgpu_ib *ib;
59995d0906fSLeo Liu int i, r;
60095d0906fSLeo Liu
601f7d66fb2SChristian König r = amdgpu_job_alloc_with_ib(ring->adev, NULL, NULL,
602f7d66fb2SChristian König 64, AMDGPU_IB_POOL_DIRECT,
603f7d66fb2SChristian König &job);
60495d0906fSLeo Liu if (r)
60595d0906fSLeo Liu goto err;
60695d0906fSLeo Liu
60795d0906fSLeo Liu ib = &job->ibs[0];
608cb107271SAlex Deucher ib->ptr[0] = PACKET0(adev->vcn.inst[ring->me].internal.data0, 0);
609093b21f4SSaleemkhan Jamadar ib->ptr[1] = addr;
610cb107271SAlex Deucher ib->ptr[2] = PACKET0(adev->vcn.inst[ring->me].internal.data1, 0);
611093b21f4SSaleemkhan Jamadar ib->ptr[3] = addr >> 32;
612cb107271SAlex Deucher ib->ptr[4] = PACKET0(adev->vcn.inst[ring->me].internal.cmd, 0);
613093b21f4SSaleemkhan Jamadar ib->ptr[5] = 0;
614093b21f4SSaleemkhan Jamadar for (i = 6; i < 16; i += 2) {
615cb107271SAlex Deucher ib->ptr[i] = PACKET0(adev->vcn.inst[ring->me].internal.nop, 0);
61695d0906fSLeo Liu ib->ptr[i+1] = 0;
61795d0906fSLeo Liu }
61895d0906fSLeo Liu ib->length_dw = 16;
61995d0906fSLeo Liu
620ee913fd9SChristian König r = amdgpu_job_submit_direct(job, ring, &f);
62195d0906fSLeo Liu if (r)
62295d0906fSLeo Liu goto err_free;
62395d0906fSLeo Liu
6240014952bSPierre-Eric Pelloux-Prayer amdgpu_ib_free(ib_msg, f);
62595d0906fSLeo Liu
62695d0906fSLeo Liu if (fence)
62795d0906fSLeo Liu *fence = dma_fence_get(f);
62895d0906fSLeo Liu dma_fence_put(f);
62995d0906fSLeo Liu
63095d0906fSLeo Liu return 0;
63195d0906fSLeo Liu
63295d0906fSLeo Liu err_free:
63395d0906fSLeo Liu amdgpu_job_free(job);
63495d0906fSLeo Liu err:
6350014952bSPierre-Eric Pelloux-Prayer amdgpu_ib_free(ib_msg, f);
63695d0906fSLeo Liu return r;
63795d0906fSLeo Liu }
63895d0906fSLeo Liu
amdgpu_vcn_dec_get_create_msg(struct amdgpu_ring * ring,uint32_t handle,struct amdgpu_ib * ib)63995d0906fSLeo Liu static int amdgpu_vcn_dec_get_create_msg(struct amdgpu_ring *ring, uint32_t handle,
640405a81aeSxinhui pan struct amdgpu_ib *ib)
64195d0906fSLeo Liu {
64295d0906fSLeo Liu struct amdgpu_device *adev = ring->adev;
64395d0906fSLeo Liu uint32_t *msg;
64495d0906fSLeo Liu int r, i;
64595d0906fSLeo Liu
646405a81aeSxinhui pan memset(ib, 0, sizeof(*ib));
64733e88286SSaleemkhan Jamadar r = amdgpu_ib_get(adev, NULL, AMDGPU_GPU_PAGE_SIZE * 2,
648405a81aeSxinhui pan AMDGPU_IB_POOL_DIRECT,
649405a81aeSxinhui pan ib);
65095d0906fSLeo Liu if (r)
65195d0906fSLeo Liu return r;
65295d0906fSLeo Liu
653405a81aeSxinhui pan msg = (uint32_t *)AMDGPU_GPU_PAGE_ALIGN((unsigned long)ib->ptr);
6542d8a425bSLeo Liu msg[0] = cpu_to_le32(0x00000028);
6553b8f5ab3SLeo Liu msg[1] = cpu_to_le32(0x00000038);
6562d8a425bSLeo Liu msg[2] = cpu_to_le32(0x00000001);
65795d0906fSLeo Liu msg[3] = cpu_to_le32(0x00000000);
6582d8a425bSLeo Liu msg[4] = cpu_to_le32(handle);
65995d0906fSLeo Liu msg[5] = cpu_to_le32(0x00000000);
6602d8a425bSLeo Liu msg[6] = cpu_to_le32(0x00000001);
6612d8a425bSLeo Liu msg[7] = cpu_to_le32(0x00000028);
6623b8f5ab3SLeo Liu msg[8] = cpu_to_le32(0x00000010);
66395d0906fSLeo Liu msg[9] = cpu_to_le32(0x00000000);
6642d8a425bSLeo Liu msg[10] = cpu_to_le32(0x00000007);
6652d8a425bSLeo Liu msg[11] = cpu_to_le32(0x00000000);
6663b8f5ab3SLeo Liu msg[12] = cpu_to_le32(0x00000780);
6673b8f5ab3SLeo Liu msg[13] = cpu_to_le32(0x00000440);
6683b8f5ab3SLeo Liu for (i = 14; i < 1024; ++i)
66995d0906fSLeo Liu msg[i] = cpu_to_le32(0x0);
67095d0906fSLeo Liu
6719b84ec8eSJames Zhu return 0;
67295d0906fSLeo Liu }
67395d0906fSLeo Liu
amdgpu_vcn_dec_get_destroy_msg(struct amdgpu_ring * ring,uint32_t handle,struct amdgpu_ib * ib)67495d0906fSLeo Liu static int amdgpu_vcn_dec_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle,
675405a81aeSxinhui pan struct amdgpu_ib *ib)
67695d0906fSLeo Liu {
67795d0906fSLeo Liu struct amdgpu_device *adev = ring->adev;
67895d0906fSLeo Liu uint32_t *msg;
67995d0906fSLeo Liu int r, i;
68095d0906fSLeo Liu
681405a81aeSxinhui pan memset(ib, 0, sizeof(*ib));
68233e88286SSaleemkhan Jamadar r = amdgpu_ib_get(adev, NULL, AMDGPU_GPU_PAGE_SIZE * 2,
683405a81aeSxinhui pan AMDGPU_IB_POOL_DIRECT,
684405a81aeSxinhui pan ib);
68595d0906fSLeo Liu if (r)
68695d0906fSLeo Liu return r;
68795d0906fSLeo Liu
688405a81aeSxinhui pan msg = (uint32_t *)AMDGPU_GPU_PAGE_ALIGN((unsigned long)ib->ptr);
6892d8a425bSLeo Liu msg[0] = cpu_to_le32(0x00000028);
6902d8a425bSLeo Liu msg[1] = cpu_to_le32(0x00000018);
6912d8a425bSLeo Liu msg[2] = cpu_to_le32(0x00000000);
6922d8a425bSLeo Liu msg[3] = cpu_to_le32(0x00000002);
6932d8a425bSLeo Liu msg[4] = cpu_to_le32(handle);
6942d8a425bSLeo Liu msg[5] = cpu_to_le32(0x00000000);
6952d8a425bSLeo Liu for (i = 6; i < 1024; ++i)
69695d0906fSLeo Liu msg[i] = cpu_to_le32(0x0);
69795d0906fSLeo Liu
6989b84ec8eSJames Zhu return 0;
69995d0906fSLeo Liu }
70095d0906fSLeo Liu
amdgpu_vcn_dec_ring_test_ib(struct amdgpu_ring * ring,long timeout)70195d0906fSLeo Liu int amdgpu_vcn_dec_ring_test_ib(struct amdgpu_ring *ring, long timeout)
70295d0906fSLeo Liu {
7039b84ec8eSJames Zhu struct dma_fence *fence = NULL;
704405a81aeSxinhui pan struct amdgpu_ib ib;
70595d0906fSLeo Liu long r;
70695d0906fSLeo Liu
707405a81aeSxinhui pan r = amdgpu_vcn_dec_get_create_msg(ring, 1, &ib);
70898079389SChristian König if (r)
70995d0906fSLeo Liu goto error;
71095d0906fSLeo Liu
711405a81aeSxinhui pan r = amdgpu_vcn_dec_send_msg(ring, &ib, NULL);
7129b84ec8eSJames Zhu if (r)
7139b84ec8eSJames Zhu goto error;
714405a81aeSxinhui pan r = amdgpu_vcn_dec_get_destroy_msg(ring, 1, &ib);
7159b84ec8eSJames Zhu if (r)
7169b84ec8eSJames Zhu goto error;
7179b84ec8eSJames Zhu
718405a81aeSxinhui pan r = amdgpu_vcn_dec_send_msg(ring, &ib, &fence);
71998079389SChristian König if (r)
72095d0906fSLeo Liu goto error;
72195d0906fSLeo Liu
72295d0906fSLeo Liu r = dma_fence_wait_timeout(fence, false, timeout);
72398079389SChristian König if (r == 0)
72495d0906fSLeo Liu r = -ETIMEDOUT;
72598079389SChristian König else if (r > 0)
72695d0906fSLeo Liu r = 0;
72795d0906fSLeo Liu
72895d0906fSLeo Liu dma_fence_put(fence);
72995d0906fSLeo Liu error:
73095d0906fSLeo Liu return r;
73195d0906fSLeo Liu }
7322d531d81SLeo Liu
amdgpu_vcn_unified_ring_ib_header(struct amdgpu_ib * ib,uint32_t ib_pack_in_dw,bool enc)7334ed49c95SRuijing Dong static uint32_t *amdgpu_vcn_unified_ring_ib_header(struct amdgpu_ib *ib,
7344ed49c95SRuijing Dong uint32_t ib_pack_in_dw, bool enc)
7354ed49c95SRuijing Dong {
7364ed49c95SRuijing Dong uint32_t *ib_checksum;
7374ed49c95SRuijing Dong
7384ed49c95SRuijing Dong ib->ptr[ib->length_dw++] = 0x00000010; /* single queue checksum */
7394ed49c95SRuijing Dong ib->ptr[ib->length_dw++] = 0x30000002;
7404ed49c95SRuijing Dong ib_checksum = &ib->ptr[ib->length_dw++];
7414ed49c95SRuijing Dong ib->ptr[ib->length_dw++] = ib_pack_in_dw;
7424ed49c95SRuijing Dong
7434ed49c95SRuijing Dong ib->ptr[ib->length_dw++] = 0x00000010; /* engine info */
7444ed49c95SRuijing Dong ib->ptr[ib->length_dw++] = 0x30000001;
7454ed49c95SRuijing Dong ib->ptr[ib->length_dw++] = enc ? 0x2 : 0x3;
7464ed49c95SRuijing Dong ib->ptr[ib->length_dw++] = ib_pack_in_dw * sizeof(uint32_t);
7474ed49c95SRuijing Dong
7484ed49c95SRuijing Dong return ib_checksum;
7494ed49c95SRuijing Dong }
7504ed49c95SRuijing Dong
amdgpu_vcn_unified_ring_ib_checksum(uint32_t ** ib_checksum,uint32_t ib_pack_in_dw)7514ed49c95SRuijing Dong static void amdgpu_vcn_unified_ring_ib_checksum(uint32_t **ib_checksum,
7524ed49c95SRuijing Dong uint32_t ib_pack_in_dw)
7534ed49c95SRuijing Dong {
7544ed49c95SRuijing Dong uint32_t i;
7554ed49c95SRuijing Dong uint32_t checksum = 0;
7564ed49c95SRuijing Dong
7574ed49c95SRuijing Dong for (i = 0; i < ib_pack_in_dw; i++)
7584ed49c95SRuijing Dong checksum += *(*ib_checksum + 2 + i);
7594ed49c95SRuijing Dong
7604ed49c95SRuijing Dong **ib_checksum = checksum;
7614ed49c95SRuijing Dong }
7624ed49c95SRuijing Dong
amdgpu_vcn_dec_sw_send_msg(struct amdgpu_ring * ring,struct amdgpu_ib * ib_msg,struct dma_fence ** fence)763bd88596fSJames Zhu static int amdgpu_vcn_dec_sw_send_msg(struct amdgpu_ring *ring,
764405a81aeSxinhui pan struct amdgpu_ib *ib_msg,
765bd88596fSJames Zhu struct dma_fence **fence)
766bd88596fSJames Zhu {
767bd88596fSJames Zhu struct amdgpu_vcn_decode_buffer *decode_buffer = NULL;
7684ed49c95SRuijing Dong unsigned int ib_size_dw = 64;
769bd88596fSJames Zhu struct amdgpu_device *adev = ring->adev;
770bd88596fSJames Zhu struct dma_fence *f = NULL;
771bd88596fSJames Zhu struct amdgpu_job *job;
772bd88596fSJames Zhu struct amdgpu_ib *ib;
773405a81aeSxinhui pan uint64_t addr = AMDGPU_GPU_PAGE_ALIGN(ib_msg->gpu_addr);
7744ed49c95SRuijing Dong uint32_t *ib_checksum;
7754ed49c95SRuijing Dong uint32_t ib_pack_in_dw;
776bd88596fSJames Zhu int i, r;
777bd88596fSJames Zhu
778cb107271SAlex Deucher if (adev->vcn.inst[ring->me].using_unified_queue)
7794ed49c95SRuijing Dong ib_size_dw += 8;
7804ed49c95SRuijing Dong
781f7d66fb2SChristian König r = amdgpu_job_alloc_with_ib(ring->adev, NULL, NULL,
782f7d66fb2SChristian König ib_size_dw * 4, AMDGPU_IB_POOL_DIRECT,
783f7d66fb2SChristian König &job);
784bd88596fSJames Zhu if (r)
785bd88596fSJames Zhu goto err;
786bd88596fSJames Zhu
787bd88596fSJames Zhu ib = &job->ibs[0];
788bd88596fSJames Zhu ib->length_dw = 0;
789bd88596fSJames Zhu
7904ed49c95SRuijing Dong /* single queue headers */
791cb107271SAlex Deucher if (adev->vcn.inst[ring->me].using_unified_queue) {
7924ed49c95SRuijing Dong ib_pack_in_dw = sizeof(struct amdgpu_vcn_decode_buffer) / sizeof(uint32_t)
7934ed49c95SRuijing Dong + 4 + 2; /* engine info + decoding ib in dw */
7944ed49c95SRuijing Dong ib_checksum = amdgpu_vcn_unified_ring_ib_header(ib, ib_pack_in_dw, false);
7954ed49c95SRuijing Dong }
7964ed49c95SRuijing Dong
797bd88596fSJames Zhu ib->ptr[ib->length_dw++] = sizeof(struct amdgpu_vcn_decode_buffer) + 8;
798bd88596fSJames Zhu ib->ptr[ib->length_dw++] = cpu_to_le32(AMDGPU_VCN_IB_FLAG_DECODE_BUFFER);
799bd88596fSJames Zhu decode_buffer = (struct amdgpu_vcn_decode_buffer *)&(ib->ptr[ib->length_dw]);
800bd88596fSJames Zhu ib->length_dw += sizeof(struct amdgpu_vcn_decode_buffer) / 4;
801bd88596fSJames Zhu memset(decode_buffer, 0, sizeof(struct amdgpu_vcn_decode_buffer));
802bd88596fSJames Zhu
803bd88596fSJames Zhu decode_buffer->valid_buf_flag |= cpu_to_le32(AMDGPU_VCN_CMD_FLAG_MSG_BUFFER);
804bd88596fSJames Zhu decode_buffer->msg_buffer_address_hi = cpu_to_le32(addr >> 32);
805bd88596fSJames Zhu decode_buffer->msg_buffer_address_lo = cpu_to_le32(addr);
806bd88596fSJames Zhu
807bd88596fSJames Zhu for (i = ib->length_dw; i < ib_size_dw; ++i)
808bd88596fSJames Zhu ib->ptr[i] = 0x0;
809bd88596fSJames Zhu
810cb107271SAlex Deucher if (adev->vcn.inst[ring->me].using_unified_queue)
8114ed49c95SRuijing Dong amdgpu_vcn_unified_ring_ib_checksum(&ib_checksum, ib_pack_in_dw);
8124ed49c95SRuijing Dong
813bd88596fSJames Zhu r = amdgpu_job_submit_direct(job, ring, &f);
814bd88596fSJames Zhu if (r)
815bd88596fSJames Zhu goto err_free;
816bd88596fSJames Zhu
8170014952bSPierre-Eric Pelloux-Prayer amdgpu_ib_free(ib_msg, f);
818bd88596fSJames Zhu
819bd88596fSJames Zhu if (fence)
820bd88596fSJames Zhu *fence = dma_fence_get(f);
821bd88596fSJames Zhu dma_fence_put(f);
822bd88596fSJames Zhu
823bd88596fSJames Zhu return 0;
824bd88596fSJames Zhu
825bd88596fSJames Zhu err_free:
826bd88596fSJames Zhu amdgpu_job_free(job);
827bd88596fSJames Zhu err:
8280014952bSPierre-Eric Pelloux-Prayer amdgpu_ib_free(ib_msg, f);
829bd88596fSJames Zhu return r;
830bd88596fSJames Zhu }
831bd88596fSJames Zhu
amdgpu_vcn_dec_sw_ring_test_ib(struct amdgpu_ring * ring,long timeout)832bd88596fSJames Zhu int amdgpu_vcn_dec_sw_ring_test_ib(struct amdgpu_ring *ring, long timeout)
833bd88596fSJames Zhu {
834bd88596fSJames Zhu struct dma_fence *fence = NULL;
835405a81aeSxinhui pan struct amdgpu_ib ib;
836bd88596fSJames Zhu long r;
837bd88596fSJames Zhu
838405a81aeSxinhui pan r = amdgpu_vcn_dec_get_create_msg(ring, 1, &ib);
839bd88596fSJames Zhu if (r)
840bd88596fSJames Zhu goto error;
841bd88596fSJames Zhu
842405a81aeSxinhui pan r = amdgpu_vcn_dec_sw_send_msg(ring, &ib, NULL);
843bd88596fSJames Zhu if (r)
844bd88596fSJames Zhu goto error;
845405a81aeSxinhui pan r = amdgpu_vcn_dec_get_destroy_msg(ring, 1, &ib);
846bd88596fSJames Zhu if (r)
847bd88596fSJames Zhu goto error;
848bd88596fSJames Zhu
849405a81aeSxinhui pan r = amdgpu_vcn_dec_sw_send_msg(ring, &ib, &fence);
850bd88596fSJames Zhu if (r)
851bd88596fSJames Zhu goto error;
852bd88596fSJames Zhu
853bd88596fSJames Zhu r = dma_fence_wait_timeout(fence, false, timeout);
854bd88596fSJames Zhu if (r == 0)
855bd88596fSJames Zhu r = -ETIMEDOUT;
856bd88596fSJames Zhu else if (r > 0)
857bd88596fSJames Zhu r = 0;
858bd88596fSJames Zhu
859bd88596fSJames Zhu dma_fence_put(fence);
860bd88596fSJames Zhu error:
861bd88596fSJames Zhu return r;
862bd88596fSJames Zhu }
863bd88596fSJames Zhu
amdgpu_vcn_enc_ring_test_ring(struct amdgpu_ring * ring)8643e1086cfSLeo Liu int amdgpu_vcn_enc_ring_test_ring(struct amdgpu_ring *ring)
8653e1086cfSLeo Liu {
8663e1086cfSLeo Liu struct amdgpu_device *adev = ring->adev;
867e038b901SShirish S uint32_t rptr;
8685d062270SSrinivasan Shanmugam unsigned int i;
8693e1086cfSLeo Liu int r;
8703e1086cfSLeo Liu
87168430c6bSMonk Liu if (amdgpu_sriov_vf(adev))
87268430c6bSMonk Liu return 0;
87368430c6bSMonk Liu
8743e1086cfSLeo Liu r = amdgpu_ring_alloc(ring, 16);
875dc9eeff8SChristian König if (r)
8763e1086cfSLeo Liu return r;
877dc9eeff8SChristian König
878e038b901SShirish S rptr = amdgpu_ring_get_rptr(ring);
879e038b901SShirish S
880c3bd3040SLeo Liu amdgpu_ring_write(ring, VCN_ENC_CMD_END);
8813e1086cfSLeo Liu amdgpu_ring_commit(ring);
8823e1086cfSLeo Liu
8833e1086cfSLeo Liu for (i = 0; i < adev->usec_timeout; i++) {
8843e1086cfSLeo Liu if (amdgpu_ring_get_rptr(ring) != rptr)
8853e1086cfSLeo Liu break;
886c366be54SSam Ravnborg udelay(1);
8873e1086cfSLeo Liu }
8883e1086cfSLeo Liu
889dc9eeff8SChristian König if (i >= adev->usec_timeout)
8903e1086cfSLeo Liu r = -ETIMEDOUT;
8913e1086cfSLeo Liu
8923e1086cfSLeo Liu return r;
8933e1086cfSLeo Liu }
8943e1086cfSLeo Liu
amdgpu_vcn_enc_get_create_msg(struct amdgpu_ring * ring,uint32_t handle,struct amdgpu_ib * ib_msg,struct dma_fence ** fence)8952d531d81SLeo Liu static int amdgpu_vcn_enc_get_create_msg(struct amdgpu_ring *ring, uint32_t handle,
896405a81aeSxinhui pan struct amdgpu_ib *ib_msg,
8972d531d81SLeo Liu struct dma_fence **fence)
8982d531d81SLeo Liu {
899e751e4beSRuijing Dong unsigned int ib_size_dw = 16;
900ecfa23c8SBoyuan Zhang struct amdgpu_device *adev = ring->adev;
9012d531d81SLeo Liu struct amdgpu_job *job;
9022d531d81SLeo Liu struct amdgpu_ib *ib;
9032d531d81SLeo Liu struct dma_fence *f = NULL;
9044ed49c95SRuijing Dong uint32_t *ib_checksum = NULL;
9058c32d043SAlex Deucher uint64_t addr;
9062d531d81SLeo Liu int i, r;
9072d531d81SLeo Liu
908cb107271SAlex Deucher if (adev->vcn.inst[ring->me].using_unified_queue)
9094ed49c95SRuijing Dong ib_size_dw += 8;
9104ed49c95SRuijing Dong
911f7d66fb2SChristian König r = amdgpu_job_alloc_with_ib(ring->adev, NULL, NULL,
912f7d66fb2SChristian König ib_size_dw * 4, AMDGPU_IB_POOL_DIRECT,
913f7d66fb2SChristian König &job);
9142d531d81SLeo Liu if (r)
9152d531d81SLeo Liu return r;
9162d531d81SLeo Liu
9172d531d81SLeo Liu ib = &job->ibs[0];
918405a81aeSxinhui pan addr = AMDGPU_GPU_PAGE_ALIGN(ib_msg->gpu_addr);
9192d531d81SLeo Liu
9202d531d81SLeo Liu ib->length_dw = 0;
9214ed49c95SRuijing Dong
922cb107271SAlex Deucher if (adev->vcn.inst[ring->me].using_unified_queue)
9234ed49c95SRuijing Dong ib_checksum = amdgpu_vcn_unified_ring_ib_header(ib, 0x11, true);
9244ed49c95SRuijing Dong
92525547cfdSLeo Liu ib->ptr[ib->length_dw++] = 0x00000018;
92625547cfdSLeo Liu ib->ptr[ib->length_dw++] = 0x00000001; /* session info */
9272d531d81SLeo Liu ib->ptr[ib->length_dw++] = handle;
9288c32d043SAlex Deucher ib->ptr[ib->length_dw++] = upper_32_bits(addr);
9298c32d043SAlex Deucher ib->ptr[ib->length_dw++] = addr;
930e56b0421SSonny Jiang ib->ptr[ib->length_dw++] = 0x00000000;
93125547cfdSLeo Liu
93225547cfdSLeo Liu ib->ptr[ib->length_dw++] = 0x00000014;
93325547cfdSLeo Liu ib->ptr[ib->length_dw++] = 0x00000002; /* task info */
93425547cfdSLeo Liu ib->ptr[ib->length_dw++] = 0x0000001c;
93525547cfdSLeo Liu ib->ptr[ib->length_dw++] = 0x00000000;
93625547cfdSLeo Liu ib->ptr[ib->length_dw++] = 0x00000000;
93725547cfdSLeo Liu
93825547cfdSLeo Liu ib->ptr[ib->length_dw++] = 0x00000008;
93925547cfdSLeo Liu ib->ptr[ib->length_dw++] = 0x08000001; /* op initialize */
9402d531d81SLeo Liu
9412d531d81SLeo Liu for (i = ib->length_dw; i < ib_size_dw; ++i)
9422d531d81SLeo Liu ib->ptr[i] = 0x0;
9432d531d81SLeo Liu
944cb107271SAlex Deucher if (adev->vcn.inst[ring->me].using_unified_queue)
9454ed49c95SRuijing Dong amdgpu_vcn_unified_ring_ib_checksum(&ib_checksum, 0x11);
9464ed49c95SRuijing Dong
947ee913fd9SChristian König r = amdgpu_job_submit_direct(job, ring, &f);
9482d531d81SLeo Liu if (r)
9492d531d81SLeo Liu goto err;
9502d531d81SLeo Liu
9512d531d81SLeo Liu if (fence)
9522d531d81SLeo Liu *fence = dma_fence_get(f);
9532d531d81SLeo Liu dma_fence_put(f);
95425547cfdSLeo Liu
9552d531d81SLeo Liu return 0;
9562d531d81SLeo Liu
9572d531d81SLeo Liu err:
9582d531d81SLeo Liu amdgpu_job_free(job);
9592d531d81SLeo Liu return r;
9602d531d81SLeo Liu }
9612d531d81SLeo Liu
amdgpu_vcn_enc_get_destroy_msg(struct amdgpu_ring * ring,uint32_t handle,struct amdgpu_ib * ib_msg,struct dma_fence ** fence)9622d531d81SLeo Liu static int amdgpu_vcn_enc_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle,
963405a81aeSxinhui pan struct amdgpu_ib *ib_msg,
96425547cfdSLeo Liu struct dma_fence **fence)
9652d531d81SLeo Liu {
966e751e4beSRuijing Dong unsigned int ib_size_dw = 16;
967ecfa23c8SBoyuan Zhang struct amdgpu_device *adev = ring->adev;
9682d531d81SLeo Liu struct amdgpu_job *job;
9692d531d81SLeo Liu struct amdgpu_ib *ib;
9702d531d81SLeo Liu struct dma_fence *f = NULL;
9714ed49c95SRuijing Dong uint32_t *ib_checksum = NULL;
9728c32d043SAlex Deucher uint64_t addr;
9732d531d81SLeo Liu int i, r;
9742d531d81SLeo Liu
975cb107271SAlex Deucher if (adev->vcn.inst[ring->me].using_unified_queue)
9764ed49c95SRuijing Dong ib_size_dw += 8;
9774ed49c95SRuijing Dong
978f7d66fb2SChristian König r = amdgpu_job_alloc_with_ib(ring->adev, NULL, NULL,
979f7d66fb2SChristian König ib_size_dw * 4, AMDGPU_IB_POOL_DIRECT,
980f7d66fb2SChristian König &job);
9812d531d81SLeo Liu if (r)
9822d531d81SLeo Liu return r;
9832d531d81SLeo Liu
9842d531d81SLeo Liu ib = &job->ibs[0];
985405a81aeSxinhui pan addr = AMDGPU_GPU_PAGE_ALIGN(ib_msg->gpu_addr);
9862d531d81SLeo Liu
9872d531d81SLeo Liu ib->length_dw = 0;
9884ed49c95SRuijing Dong
989cb107271SAlex Deucher if (adev->vcn.inst[ring->me].using_unified_queue)
9904ed49c95SRuijing Dong ib_checksum = amdgpu_vcn_unified_ring_ib_header(ib, 0x11, true);
9914ed49c95SRuijing Dong
99225547cfdSLeo Liu ib->ptr[ib->length_dw++] = 0x00000018;
99325547cfdSLeo Liu ib->ptr[ib->length_dw++] = 0x00000001;
9942d531d81SLeo Liu ib->ptr[ib->length_dw++] = handle;
9958c32d043SAlex Deucher ib->ptr[ib->length_dw++] = upper_32_bits(addr);
9968c32d043SAlex Deucher ib->ptr[ib->length_dw++] = addr;
997e56b0421SSonny Jiang ib->ptr[ib->length_dw++] = 0x00000000;
9982d531d81SLeo Liu
99925547cfdSLeo Liu ib->ptr[ib->length_dw++] = 0x00000014;
100025547cfdSLeo Liu ib->ptr[ib->length_dw++] = 0x00000002;
100125547cfdSLeo Liu ib->ptr[ib->length_dw++] = 0x0000001c;
10022d531d81SLeo Liu ib->ptr[ib->length_dw++] = 0x00000000;
10032d531d81SLeo Liu ib->ptr[ib->length_dw++] = 0x00000000;
10042d531d81SLeo Liu
100525547cfdSLeo Liu ib->ptr[ib->length_dw++] = 0x00000008;
100625547cfdSLeo Liu ib->ptr[ib->length_dw++] = 0x08000002; /* op close session */
10072d531d81SLeo Liu
10082d531d81SLeo Liu for (i = ib->length_dw; i < ib_size_dw; ++i)
10092d531d81SLeo Liu ib->ptr[i] = 0x0;
10102d531d81SLeo Liu
1011cb107271SAlex Deucher if (adev->vcn.inst[ring->me].using_unified_queue)
10124ed49c95SRuijing Dong amdgpu_vcn_unified_ring_ib_checksum(&ib_checksum, 0x11);
10134ed49c95SRuijing Dong
1014ee913fd9SChristian König r = amdgpu_job_submit_direct(job, ring, &f);
10152d531d81SLeo Liu if (r)
10162d531d81SLeo Liu goto err;
10172d531d81SLeo Liu
10182d531d81SLeo Liu if (fence)
10192d531d81SLeo Liu *fence = dma_fence_get(f);
10202d531d81SLeo Liu dma_fence_put(f);
102125547cfdSLeo Liu
10222d531d81SLeo Liu return 0;
10232d531d81SLeo Liu
10242d531d81SLeo Liu err:
10252d531d81SLeo Liu amdgpu_job_free(job);
10262d531d81SLeo Liu return r;
10272d531d81SLeo Liu }
10282d531d81SLeo Liu
amdgpu_vcn_enc_ring_test_ib(struct amdgpu_ring * ring,long timeout)10292d531d81SLeo Liu int amdgpu_vcn_enc_ring_test_ib(struct amdgpu_ring *ring, long timeout)
10302d531d81SLeo Liu {
1031405a81aeSxinhui pan struct amdgpu_device *adev = ring->adev;
10322d531d81SLeo Liu struct dma_fence *fence = NULL;
1033405a81aeSxinhui pan struct amdgpu_ib ib;
10342d531d81SLeo Liu long r;
10352d531d81SLeo Liu
1036405a81aeSxinhui pan memset(&ib, 0, sizeof(ib));
1037405a81aeSxinhui pan r = amdgpu_ib_get(adev, NULL, (128 << 10) + AMDGPU_GPU_PAGE_SIZE,
1038405a81aeSxinhui pan AMDGPU_IB_POOL_DIRECT,
1039405a81aeSxinhui pan &ib);
10408c32d043SAlex Deucher if (r)
10418c32d043SAlex Deucher return r;
10428c32d043SAlex Deucher
1043405a81aeSxinhui pan r = amdgpu_vcn_enc_get_create_msg(ring, 1, &ib, NULL);
104498079389SChristian König if (r)
10452d531d81SLeo Liu goto error;
10462d531d81SLeo Liu
1047405a81aeSxinhui pan r = amdgpu_vcn_enc_get_destroy_msg(ring, 1, &ib, &fence);
104898079389SChristian König if (r)
10492d531d81SLeo Liu goto error;
10502d531d81SLeo Liu
10512d531d81SLeo Liu r = dma_fence_wait_timeout(fence, false, timeout);
105298079389SChristian König if (r == 0)
10532d531d81SLeo Liu r = -ETIMEDOUT;
105498079389SChristian König else if (r > 0)
10552d531d81SLeo Liu r = 0;
105698079389SChristian König
10572d531d81SLeo Liu error:
10580014952bSPierre-Eric Pelloux-Prayer amdgpu_ib_free(&ib, fence);
10592d531d81SLeo Liu dma_fence_put(fence);
1060e18d9a2bSNirmoy Das
10612d531d81SLeo Liu return r;
10622d531d81SLeo Liu }
10630ad29a4eSSatyajit Sahu
amdgpu_vcn_unified_ring_test_ib(struct amdgpu_ring * ring,long timeout)10644ed49c95SRuijing Dong int amdgpu_vcn_unified_ring_test_ib(struct amdgpu_ring *ring, long timeout)
10654ed49c95SRuijing Dong {
1066da044aaeSJames Zhu struct amdgpu_device *adev = ring->adev;
10674ed49c95SRuijing Dong long r;
10684ed49c95SRuijing Dong
1069346492f3SSonny Jiang if ((amdgpu_ip_version(adev, UVD_HWIP, 0) != IP_VERSION(4, 0, 3)) &&
1070346492f3SSonny Jiang (amdgpu_ip_version(adev, UVD_HWIP, 0) != IP_VERSION(5, 0, 1))) {
10714ed49c95SRuijing Dong r = amdgpu_vcn_enc_ring_test_ib(ring, timeout);
10724ed49c95SRuijing Dong if (r)
10734ed49c95SRuijing Dong goto error;
1074da044aaeSJames Zhu }
10754ed49c95SRuijing Dong
10764ed49c95SRuijing Dong r = amdgpu_vcn_dec_sw_ring_test_ib(ring, timeout);
10774ed49c95SRuijing Dong
10784ed49c95SRuijing Dong error:
10794ed49c95SRuijing Dong return r;
10804ed49c95SRuijing Dong }
10814ed49c95SRuijing Dong
amdgpu_vcn_get_enc_ring_prio(int ring)10820ad29a4eSSatyajit Sahu enum amdgpu_ring_priority_level amdgpu_vcn_get_enc_ring_prio(int ring)
10830ad29a4eSSatyajit Sahu {
10840ad29a4eSSatyajit Sahu switch (ring) {
10850ad29a4eSSatyajit Sahu case 0:
10860ad29a4eSSatyajit Sahu return AMDGPU_RING_PRIO_0;
10870ad29a4eSSatyajit Sahu case 1:
10880ad29a4eSSatyajit Sahu return AMDGPU_RING_PRIO_1;
10890ad29a4eSSatyajit Sahu case 2:
10900ad29a4eSSatyajit Sahu return AMDGPU_RING_PRIO_2;
10910ad29a4eSSatyajit Sahu default:
10920ad29a4eSSatyajit Sahu return AMDGPU_RING_PRIO_0;
10930ad29a4eSSatyajit Sahu }
10940ad29a4eSSatyajit Sahu }
1095c5dd5667SAlex Deucher
amdgpu_vcn_setup_ucode(struct amdgpu_device * adev,int i)1096f9867563SAlex Deucher void amdgpu_vcn_setup_ucode(struct amdgpu_device *adev, int i)
1097c5dd5667SAlex Deucher {
1098c5dd5667SAlex Deucher unsigned int idx;
1099c5dd5667SAlex Deucher
1100c5dd5667SAlex Deucher if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) {
1101c5dd5667SAlex Deucher const struct common_firmware_header *hdr;
11025d062270SSrinivasan Shanmugam
1103c5dd5667SAlex Deucher if (adev->vcn.harvest_config & (1 << i))
1104f9867563SAlex Deucher return;
1105f9867563SAlex Deucher
1106f9867563SAlex Deucher if ((amdgpu_ip_version(adev, UVD_HWIP, 0) == IP_VERSION(4, 0, 3) ||
1107f9867563SAlex Deucher amdgpu_ip_version(adev, UVD_HWIP, 0) == IP_VERSION(5, 0, 1))
1108f9867563SAlex Deucher && (i > 0))
1109f9867563SAlex Deucher return;
11106a7cbbc2SSaleemkhan Jamadar
1111cf1aa9ffSBoyuan Zhang hdr = (const struct common_firmware_header *)adev->vcn.inst[i].fw->data;
1112c5dd5667SAlex Deucher /* currently only support 2 FW instances */
1113c5dd5667SAlex Deucher if (i >= 2) {
1114c5dd5667SAlex Deucher dev_info(adev->dev, "More then 2 VCN FW instances!\n");
1115f9867563SAlex Deucher return;
1116c5dd5667SAlex Deucher }
1117c5dd5667SAlex Deucher idx = AMDGPU_UCODE_ID_VCN + i;
1118c5dd5667SAlex Deucher adev->firmware.ucode[idx].ucode_id = idx;
1119cf1aa9ffSBoyuan Zhang adev->firmware.ucode[idx].fw = adev->vcn.inst[i].fw;
1120c5dd5667SAlex Deucher adev->firmware.fw_size +=
1121c5dd5667SAlex Deucher ALIGN(le32_to_cpu(hdr->ucode_size_bytes), PAGE_SIZE);
1122c5dd5667SAlex Deucher }
1123c5dd5667SAlex Deucher }
112411eb648dSRuijing Dong
112511eb648dSRuijing Dong /*
112611eb648dSRuijing Dong * debugfs for mapping vcn firmware log buffer.
112711eb648dSRuijing Dong */
112811eb648dSRuijing Dong #if defined(CONFIG_DEBUG_FS)
amdgpu_debugfs_vcn_fwlog_read(struct file * f,char __user * buf,size_t size,loff_t * pos)112911eb648dSRuijing Dong static ssize_t amdgpu_debugfs_vcn_fwlog_read(struct file *f, char __user *buf,
113011eb648dSRuijing Dong size_t size, loff_t *pos)
113111eb648dSRuijing Dong {
113211eb648dSRuijing Dong struct amdgpu_vcn_inst *vcn;
113311eb648dSRuijing Dong void *log_buf;
113411eb648dSRuijing Dong volatile struct amdgpu_vcn_fwlog *plog;
113511eb648dSRuijing Dong unsigned int read_pos, write_pos, available, i, read_bytes = 0;
113611eb648dSRuijing Dong unsigned int read_num[2] = {0};
113711eb648dSRuijing Dong
113811eb648dSRuijing Dong vcn = file_inode(f)->i_private;
113911eb648dSRuijing Dong if (!vcn)
114011eb648dSRuijing Dong return -ENODEV;
114111eb648dSRuijing Dong
114211eb648dSRuijing Dong if (!vcn->fw_shared.cpu_addr || !amdgpu_vcnfw_log)
114311eb648dSRuijing Dong return -EFAULT;
114411eb648dSRuijing Dong
114511eb648dSRuijing Dong log_buf = vcn->fw_shared.cpu_addr + vcn->fw_shared.mem_size;
114611eb648dSRuijing Dong
114711eb648dSRuijing Dong plog = (volatile struct amdgpu_vcn_fwlog *)log_buf;
114811eb648dSRuijing Dong read_pos = plog->rptr;
114911eb648dSRuijing Dong write_pos = plog->wptr;
115011eb648dSRuijing Dong
115111eb648dSRuijing Dong if (read_pos > AMDGPU_VCNFW_LOG_SIZE || write_pos > AMDGPU_VCNFW_LOG_SIZE)
115211eb648dSRuijing Dong return -EFAULT;
115311eb648dSRuijing Dong
115411eb648dSRuijing Dong if (!size || (read_pos == write_pos))
115511eb648dSRuijing Dong return 0;
115611eb648dSRuijing Dong
115711eb648dSRuijing Dong if (write_pos > read_pos) {
115811eb648dSRuijing Dong available = write_pos - read_pos;
1159eb3b214cSSrinivasan Shanmugam read_num[0] = min_t(size_t, size, available);
116011eb648dSRuijing Dong } else {
116111eb648dSRuijing Dong read_num[0] = AMDGPU_VCNFW_LOG_SIZE - read_pos;
116211eb648dSRuijing Dong available = read_num[0] + write_pos - plog->header_size;
116311eb648dSRuijing Dong if (size > available)
116411eb648dSRuijing Dong read_num[1] = write_pos - plog->header_size;
116511eb648dSRuijing Dong else if (size > read_num[0])
116611eb648dSRuijing Dong read_num[1] = size - read_num[0];
116711eb648dSRuijing Dong else
116811eb648dSRuijing Dong read_num[0] = size;
116911eb648dSRuijing Dong }
117011eb648dSRuijing Dong
117111eb648dSRuijing Dong for (i = 0; i < 2; i++) {
117211eb648dSRuijing Dong if (read_num[i]) {
117311eb648dSRuijing Dong if (read_pos == AMDGPU_VCNFW_LOG_SIZE)
117411eb648dSRuijing Dong read_pos = plog->header_size;
117511eb648dSRuijing Dong if (read_num[i] == copy_to_user((buf + read_bytes),
117611eb648dSRuijing Dong (log_buf + read_pos), read_num[i]))
117711eb648dSRuijing Dong return -EFAULT;
117811eb648dSRuijing Dong
117911eb648dSRuijing Dong read_bytes += read_num[i];
118011eb648dSRuijing Dong read_pos += read_num[i];
118111eb648dSRuijing Dong }
118211eb648dSRuijing Dong }
118311eb648dSRuijing Dong
118411eb648dSRuijing Dong plog->rptr = read_pos;
118511eb648dSRuijing Dong *pos += read_bytes;
118611eb648dSRuijing Dong return read_bytes;
118711eb648dSRuijing Dong }
118811eb648dSRuijing Dong
118911eb648dSRuijing Dong static const struct file_operations amdgpu_debugfs_vcnfwlog_fops = {
119011eb648dSRuijing Dong .owner = THIS_MODULE,
119111eb648dSRuijing Dong .read = amdgpu_debugfs_vcn_fwlog_read,
119211eb648dSRuijing Dong .llseek = default_llseek
119311eb648dSRuijing Dong };
119411eb648dSRuijing Dong #endif
119511eb648dSRuijing Dong
amdgpu_debugfs_vcn_fwlog_init(struct amdgpu_device * adev,uint8_t i,struct amdgpu_vcn_inst * vcn)119611eb648dSRuijing Dong void amdgpu_debugfs_vcn_fwlog_init(struct amdgpu_device *adev, uint8_t i,
119711eb648dSRuijing Dong struct amdgpu_vcn_inst *vcn)
119811eb648dSRuijing Dong {
119911eb648dSRuijing Dong #if defined(CONFIG_DEBUG_FS)
120011eb648dSRuijing Dong struct drm_minor *minor = adev_to_drm(adev)->primary;
120111eb648dSRuijing Dong struct dentry *root = minor->debugfs_root;
120211eb648dSRuijing Dong char name[32];
120311eb648dSRuijing Dong
120411eb648dSRuijing Dong sprintf(name, "amdgpu_vcn_%d_fwlog", i);
12055d062270SSrinivasan Shanmugam debugfs_create_file_size(name, S_IFREG | 0444, root, vcn,
120611eb648dSRuijing Dong &amdgpu_debugfs_vcnfwlog_fops,
120711eb648dSRuijing Dong AMDGPU_VCNFW_LOG_SIZE);
120811eb648dSRuijing Dong #endif
120911eb648dSRuijing Dong }
121011eb648dSRuijing Dong
amdgpu_vcn_fwlog_init(struct amdgpu_vcn_inst * vcn)121111eb648dSRuijing Dong void amdgpu_vcn_fwlog_init(struct amdgpu_vcn_inst *vcn)
121211eb648dSRuijing Dong {
121311eb648dSRuijing Dong #if defined(CONFIG_DEBUG_FS)
121411eb648dSRuijing Dong volatile uint32_t *flag = vcn->fw_shared.cpu_addr;
121511eb648dSRuijing Dong void *fw_log_cpu_addr = vcn->fw_shared.cpu_addr + vcn->fw_shared.mem_size;
121611eb648dSRuijing Dong uint64_t fw_log_gpu_addr = vcn->fw_shared.gpu_addr + vcn->fw_shared.mem_size;
121711eb648dSRuijing Dong volatile struct amdgpu_vcn_fwlog *log_buf = fw_log_cpu_addr;
121811eb648dSRuijing Dong volatile struct amdgpu_fw_shared_fw_logging *fw_log = vcn->fw_shared.cpu_addr
121911eb648dSRuijing Dong + vcn->fw_shared.log_offset;
122011eb648dSRuijing Dong *flag |= cpu_to_le32(AMDGPU_VCN_FW_LOGGING_FLAG);
122111eb648dSRuijing Dong fw_log->is_enabled = 1;
122211eb648dSRuijing Dong fw_log->addr_lo = cpu_to_le32(fw_log_gpu_addr & 0xFFFFFFFF);
122311eb648dSRuijing Dong fw_log->addr_hi = cpu_to_le32(fw_log_gpu_addr >> 32);
122411eb648dSRuijing Dong fw_log->size = cpu_to_le32(AMDGPU_VCNFW_LOG_SIZE);
122511eb648dSRuijing Dong
122611eb648dSRuijing Dong log_buf->header_size = sizeof(struct amdgpu_vcn_fwlog);
122711eb648dSRuijing Dong log_buf->buffer_size = AMDGPU_VCNFW_LOG_SIZE;
122811eb648dSRuijing Dong log_buf->rptr = log_buf->header_size;
122911eb648dSRuijing Dong log_buf->wptr = log_buf->header_size;
123011eb648dSRuijing Dong log_buf->wrapped = 0;
123111eb648dSRuijing Dong #endif
123211eb648dSRuijing Dong }
12330ae99221SMohammad Zafar Ziya
amdgpu_vcn_process_poison_irq(struct amdgpu_device * adev,struct amdgpu_irq_src * source,struct amdgpu_iv_entry * entry)12340ae99221SMohammad Zafar Ziya int amdgpu_vcn_process_poison_irq(struct amdgpu_device *adev,
12350ae99221SMohammad Zafar Ziya struct amdgpu_irq_src *source,
12360ae99221SMohammad Zafar Ziya struct amdgpu_iv_entry *entry)
12370ae99221SMohammad Zafar Ziya {
12380ae99221SMohammad Zafar Ziya struct ras_common_if *ras_if = adev->vcn.ras_if;
12390ae99221SMohammad Zafar Ziya struct ras_dispatch_if ih_data = {
12400ae99221SMohammad Zafar Ziya .entry = entry,
12410ae99221SMohammad Zafar Ziya };
12420ae99221SMohammad Zafar Ziya
12430ae99221SMohammad Zafar Ziya if (!ras_if)
12440ae99221SMohammad Zafar Ziya return 0;
12450ae99221SMohammad Zafar Ziya
12466a822b7aSTao Zhou if (!amdgpu_sriov_vf(adev)) {
12470ae99221SMohammad Zafar Ziya ih_data.head = *ras_if;
12480ae99221SMohammad Zafar Ziya amdgpu_ras_interrupt_dispatch(adev, &ih_data);
12496a822b7aSTao Zhou } else {
12506a822b7aSTao Zhou if (adev->virt.ops && adev->virt.ops->ras_poison_handler)
1251ed1e1e42SYiPeng Chai adev->virt.ops->ras_poison_handler(adev, ras_if->block);
12526a822b7aSTao Zhou else
12536a822b7aSTao Zhou dev_warn(adev->dev,
12546a822b7aSTao Zhou "No ras_poison_handler interface in SRIOV for VCN!\n");
12556a822b7aSTao Zhou }
12560ae99221SMohammad Zafar Ziya
12570ae99221SMohammad Zafar Ziya return 0;
12580ae99221SMohammad Zafar Ziya }
12592ddb629bSTao Zhou
amdgpu_vcn_ras_late_init(struct amdgpu_device * adev,struct ras_common_if * ras_block)12602ecf927bSHoratio Zhang int amdgpu_vcn_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *ras_block)
12612ecf927bSHoratio Zhang {
12622ecf927bSHoratio Zhang int r, i;
12632ecf927bSHoratio Zhang
12642ecf927bSHoratio Zhang r = amdgpu_ras_block_late_init(adev, ras_block);
12652ecf927bSHoratio Zhang if (r)
12662ecf927bSHoratio Zhang return r;
12672ecf927bSHoratio Zhang
12682ecf927bSHoratio Zhang if (amdgpu_ras_is_supported(adev, ras_block->block)) {
12692ecf927bSHoratio Zhang for (i = 0; i < adev->vcn.num_vcn_inst; i++) {
12704ff96bccSTao Zhou if (adev->vcn.harvest_config & (1 << i) ||
12714ff96bccSTao Zhou !adev->vcn.inst[i].ras_poison_irq.funcs)
12722ecf927bSHoratio Zhang continue;
12732ecf927bSHoratio Zhang
12742ecf927bSHoratio Zhang r = amdgpu_irq_get(adev, &adev->vcn.inst[i].ras_poison_irq, 0);
12752ecf927bSHoratio Zhang if (r)
12762ecf927bSHoratio Zhang goto late_fini;
12772ecf927bSHoratio Zhang }
12782ecf927bSHoratio Zhang }
12792ecf927bSHoratio Zhang return 0;
12802ecf927bSHoratio Zhang
12812ecf927bSHoratio Zhang late_fini:
12822ecf927bSHoratio Zhang amdgpu_ras_block_late_fini(adev, ras_block);
12832ecf927bSHoratio Zhang return r;
12842ecf927bSHoratio Zhang }
12852ecf927bSHoratio Zhang
amdgpu_vcn_ras_sw_init(struct amdgpu_device * adev)1286f81c31d9SHawking Zhang int amdgpu_vcn_ras_sw_init(struct amdgpu_device *adev)
12872ddb629bSTao Zhou {
1288f81c31d9SHawking Zhang int err;
1289f81c31d9SHawking Zhang struct amdgpu_vcn_ras *ras;
1290f81c31d9SHawking Zhang
12912ddb629bSTao Zhou if (!adev->vcn.ras)
1292f81c31d9SHawking Zhang return 0;
12932ddb629bSTao Zhou
1294f81c31d9SHawking Zhang ras = adev->vcn.ras;
1295f81c31d9SHawking Zhang err = amdgpu_ras_register_ras_block(adev, &ras->ras_block);
1296f81c31d9SHawking Zhang if (err) {
1297f81c31d9SHawking Zhang dev_err(adev->dev, "Failed to register vcn ras block!\n");
1298f81c31d9SHawking Zhang return err;
1299f81c31d9SHawking Zhang }
13002ddb629bSTao Zhou
1301f81c31d9SHawking Zhang strcpy(ras->ras_block.ras_comm.name, "vcn");
1302f81c31d9SHawking Zhang ras->ras_block.ras_comm.block = AMDGPU_RAS_BLOCK__VCN;
1303f81c31d9SHawking Zhang ras->ras_block.ras_comm.type = AMDGPU_RAS_ERROR__POISON;
1304f81c31d9SHawking Zhang adev->vcn.ras_if = &ras->ras_block.ras_comm;
13052ddb629bSTao Zhou
1306f81c31d9SHawking Zhang if (!ras->ras_block.ras_late_init)
13072ecf927bSHoratio Zhang ras->ras_block.ras_late_init = amdgpu_vcn_ras_late_init;
1308f81c31d9SHawking Zhang
1309f81c31d9SHawking Zhang return 0;
13102ddb629bSTao Zhou }
13111ddcdb7cSLang Yu
amdgpu_vcn_psp_update_sram(struct amdgpu_device * adev,int inst_idx,enum AMDGPU_UCODE_ID ucode_id)13121ddcdb7cSLang Yu int amdgpu_vcn_psp_update_sram(struct amdgpu_device *adev, int inst_idx,
13131ddcdb7cSLang Yu enum AMDGPU_UCODE_ID ucode_id)
13141ddcdb7cSLang Yu {
13151ddcdb7cSLang Yu struct amdgpu_firmware_info ucode = {
13161ddcdb7cSLang Yu .ucode_id = (ucode_id ? ucode_id :
13171ddcdb7cSLang Yu (inst_idx ? AMDGPU_UCODE_ID_VCN1_RAM :
13181ddcdb7cSLang Yu AMDGPU_UCODE_ID_VCN0_RAM)),
13191ddcdb7cSLang Yu .mc_addr = adev->vcn.inst[inst_idx].dpg_sram_gpu_addr,
13201ddcdb7cSLang Yu .ucode_size = ((uintptr_t)adev->vcn.inst[inst_idx].dpg_sram_curr_addr -
13211ddcdb7cSLang Yu (uintptr_t)adev->vcn.inst[inst_idx].dpg_sram_cpu_addr),
13221ddcdb7cSLang Yu };
13231ddcdb7cSLang Yu
13241ddcdb7cSLang Yu return psp_execute_ip_fw_load(&adev->psp, &ucode);
13251ddcdb7cSLang Yu }
1326fb989824S[email protected]
amdgpu_get_vcn_reset_mask(struct device * dev,struct device_attribute * attr,char * buf)1327fb989824S[email protected] static ssize_t amdgpu_get_vcn_reset_mask(struct device *dev,
1328fb989824S[email protected] struct device_attribute *attr,
1329fb989824S[email protected] char *buf)
1330fb989824S[email protected] {
1331fb989824S[email protected] struct drm_device *ddev = dev_get_drvdata(dev);
1332fb989824S[email protected] struct amdgpu_device *adev = drm_to_adev(ddev);
1333fb989824S[email protected]
1334fb989824S[email protected] if (!adev)
1335fb989824S[email protected] return -ENODEV;
1336fb989824S[email protected]
1337fb989824S[email protected] return amdgpu_show_reset_mask(buf, adev->vcn.supported_reset);
1338fb989824S[email protected] }
1339fb989824S[email protected]
1340fb989824S[email protected] static DEVICE_ATTR(vcn_reset_mask, 0444,
1341fb989824S[email protected] amdgpu_get_vcn_reset_mask, NULL);
1342fb989824S[email protected]
amdgpu_vcn_sysfs_reset_mask_init(struct amdgpu_device * adev)1343fb989824S[email protected] int amdgpu_vcn_sysfs_reset_mask_init(struct amdgpu_device *adev)
1344fb989824S[email protected] {
1345fb989824S[email protected] int r = 0;
1346fb989824S[email protected]
1347fb989824S[email protected] if (adev->vcn.num_vcn_inst) {
1348fb989824S[email protected] r = device_create_file(adev->dev, &dev_attr_vcn_reset_mask);
1349fb989824S[email protected] if (r)
1350fb989824S[email protected] return r;
1351fb989824S[email protected] }
1352fb989824S[email protected]
1353fb989824S[email protected] return r;
1354fb989824S[email protected] }
1355fb989824S[email protected]
amdgpu_vcn_sysfs_reset_mask_fini(struct amdgpu_device * adev)1356fb989824S[email protected] void amdgpu_vcn_sysfs_reset_mask_fini(struct amdgpu_device *adev)
1357fb989824S[email protected] {
13582f1b1352S[email protected] if (adev->dev->kobj.sd) {
1359fb989824S[email protected] if (adev->vcn.num_vcn_inst)
1360fb989824S[email protected] device_remove_file(adev->dev, &dev_attr_vcn_reset_mask);
1361fb989824S[email protected] }
13622f1b1352S[email protected] }
1363de258d06SSathishkumar S
1364de258d06SSathishkumar S /*
1365de258d06SSathishkumar S * debugfs to enable/disable vcn job submission to specific core or
1366de258d06SSathishkumar S * instance. It is created only if the queue type is unified.
1367de258d06SSathishkumar S */
1368de258d06SSathishkumar S #if defined(CONFIG_DEBUG_FS)
amdgpu_debugfs_vcn_sched_mask_set(void * data,u64 val)1369de258d06SSathishkumar S static int amdgpu_debugfs_vcn_sched_mask_set(void *data, u64 val)
1370de258d06SSathishkumar S {
1371de258d06SSathishkumar S struct amdgpu_device *adev = (struct amdgpu_device *)data;
1372de258d06SSathishkumar S u32 i;
1373de258d06SSathishkumar S u64 mask;
1374de258d06SSathishkumar S struct amdgpu_ring *ring;
1375de258d06SSathishkumar S
1376de258d06SSathishkumar S if (!adev)
1377de258d06SSathishkumar S return -ENODEV;
1378de258d06SSathishkumar S
1379de258d06SSathishkumar S mask = (1ULL << adev->vcn.num_vcn_inst) - 1;
1380de258d06SSathishkumar S if ((val & mask) == 0)
1381de258d06SSathishkumar S return -EINVAL;
1382de258d06SSathishkumar S for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
1383de258d06SSathishkumar S ring = &adev->vcn.inst[i].ring_enc[0];
1384de258d06SSathishkumar S if (val & (1ULL << i))
1385de258d06SSathishkumar S ring->sched.ready = true;
1386de258d06SSathishkumar S else
1387de258d06SSathishkumar S ring->sched.ready = false;
1388de258d06SSathishkumar S }
1389de258d06SSathishkumar S /* publish sched.ready flag update effective immediately across smp */
1390de258d06SSathishkumar S smp_rmb();
1391de258d06SSathishkumar S return 0;
1392de258d06SSathishkumar S }
1393de258d06SSathishkumar S
amdgpu_debugfs_vcn_sched_mask_get(void * data,u64 * val)1394de258d06SSathishkumar S static int amdgpu_debugfs_vcn_sched_mask_get(void *data, u64 *val)
1395de258d06SSathishkumar S {
1396de258d06SSathishkumar S struct amdgpu_device *adev = (struct amdgpu_device *)data;
1397de258d06SSathishkumar S u32 i;
1398de258d06SSathishkumar S u64 mask = 0;
1399de258d06SSathishkumar S struct amdgpu_ring *ring;
1400de258d06SSathishkumar S
1401de258d06SSathishkumar S if (!adev)
1402de258d06SSathishkumar S return -ENODEV;
1403de258d06SSathishkumar S for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
1404de258d06SSathishkumar S ring = &adev->vcn.inst[i].ring_enc[0];
1405de258d06SSathishkumar S if (ring->sched.ready)
1406de258d06SSathishkumar S mask |= 1ULL << i;
1407de258d06SSathishkumar S }
1408de258d06SSathishkumar S *val = mask;
1409de258d06SSathishkumar S return 0;
1410de258d06SSathishkumar S }
1411de258d06SSathishkumar S
1412de258d06SSathishkumar S DEFINE_DEBUGFS_ATTRIBUTE(amdgpu_debugfs_vcn_sched_mask_fops,
1413de258d06SSathishkumar S amdgpu_debugfs_vcn_sched_mask_get,
1414de258d06SSathishkumar S amdgpu_debugfs_vcn_sched_mask_set, "%llx\n");
1415de258d06SSathishkumar S #endif
1416de258d06SSathishkumar S
amdgpu_debugfs_vcn_sched_mask_init(struct amdgpu_device * adev)1417de258d06SSathishkumar S void amdgpu_debugfs_vcn_sched_mask_init(struct amdgpu_device *adev)
1418de258d06SSathishkumar S {
1419de258d06SSathishkumar S #if defined(CONFIG_DEBUG_FS)
1420de258d06SSathishkumar S struct drm_minor *minor = adev_to_drm(adev)->primary;
1421de258d06SSathishkumar S struct dentry *root = minor->debugfs_root;
1422de258d06SSathishkumar S char name[32];
1423de258d06SSathishkumar S
1424cb107271SAlex Deucher if (adev->vcn.num_vcn_inst <= 1 || !adev->vcn.inst[0].using_unified_queue)
1425de258d06SSathishkumar S return;
1426de258d06SSathishkumar S sprintf(name, "amdgpu_vcn_sched_mask");
1427de258d06SSathishkumar S debugfs_create_file(name, 0600, root, adev,
1428de258d06SSathishkumar S &amdgpu_debugfs_vcn_sched_mask_fops);
1429de258d06SSathishkumar S #endif
1430de258d06SSathishkumar S }
1431a2cf2a88SAlex Deucher
1432a2cf2a88SAlex Deucher /**
1433a2cf2a88SAlex Deucher * vcn_set_powergating_state - set VCN block powergating state
1434a2cf2a88SAlex Deucher *
1435a2cf2a88SAlex Deucher * @ip_block: amdgpu_ip_block pointer
1436a2cf2a88SAlex Deucher * @state: power gating state
1437a2cf2a88SAlex Deucher *
1438a2cf2a88SAlex Deucher * Set VCN block powergating state
1439a2cf2a88SAlex Deucher */
vcn_set_powergating_state(struct amdgpu_ip_block * ip_block,enum amd_powergating_state state)1440a2cf2a88SAlex Deucher int vcn_set_powergating_state(struct amdgpu_ip_block *ip_block,
1441a2cf2a88SAlex Deucher enum amd_powergating_state state)
1442a2cf2a88SAlex Deucher {
1443a2cf2a88SAlex Deucher struct amdgpu_device *adev = ip_block->adev;
1444a2cf2a88SAlex Deucher int ret = 0, i;
1445a2cf2a88SAlex Deucher
1446a2cf2a88SAlex Deucher for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
1447a2cf2a88SAlex Deucher struct amdgpu_vcn_inst *vinst = &adev->vcn.inst[i];
1448a2cf2a88SAlex Deucher
1449a2cf2a88SAlex Deucher ret |= vinst->set_pg_state(vinst, state);
1450a2cf2a88SAlex Deucher }
1451a2cf2a88SAlex Deucher
1452a2cf2a88SAlex Deucher return ret;
1453a2cf2a88SAlex Deucher }
1454