xref: /openbmc/linux/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c (revision 736f7308)
18da1170aSLeo Liu /*
28da1170aSLeo Liu  * Copyright 2021 Advanced Micro Devices, Inc.
38da1170aSLeo Liu  *
48da1170aSLeo Liu  * Permission is hereby granted, free of charge, to any person obtaining a
58da1170aSLeo Liu  * copy of this software and associated documentation files (the "Software"),
68da1170aSLeo Liu  * to deal in the Software without restriction, including without limitation
78da1170aSLeo Liu  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
88da1170aSLeo Liu  * and/or sell copies of the Software, and to permit persons to whom the
98da1170aSLeo Liu  * Software is furnished to do so, subject to the following conditions:
108da1170aSLeo Liu  *
118da1170aSLeo Liu  * The above copyright notice and this permission notice shall be included in
128da1170aSLeo Liu  * all copies or substantial portions of the Software.
138da1170aSLeo Liu  *
148da1170aSLeo Liu  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
158da1170aSLeo Liu  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
168da1170aSLeo Liu  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
178da1170aSLeo Liu  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
188da1170aSLeo Liu  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
198da1170aSLeo Liu  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
208da1170aSLeo Liu  * OTHER DEALINGS IN THE SOFTWARE.
218da1170aSLeo Liu  *
228da1170aSLeo Liu  */
238da1170aSLeo Liu 
248da1170aSLeo Liu #include <linux/firmware.h>
258da1170aSLeo Liu #include "amdgpu.h"
268da1170aSLeo Liu #include "amdgpu_vcn.h"
278da1170aSLeo Liu #include "amdgpu_pm.h"
280b15205cSSonny Jiang #include "amdgpu_cs.h"
298da1170aSLeo Liu #include "soc15.h"
308da1170aSLeo Liu #include "soc15d.h"
318da1170aSLeo Liu #include "soc15_hw_ip.h"
328da1170aSLeo Liu #include "vcn_v2_0.h"
338da1170aSLeo Liu 
348da1170aSLeo Liu #include "vcn/vcn_4_0_0_offset.h"
358da1170aSLeo Liu #include "vcn/vcn_4_0_0_sh_mask.h"
368da1170aSLeo Liu #include "ivsrcid/vcn/irqsrcs_vcn_4_0.h"
378da1170aSLeo Liu 
388da1170aSLeo Liu #include <drm/drm_drv.h>
398da1170aSLeo Liu 
408da1170aSLeo Liu #define mmUVD_DPG_LMA_CTL							regUVD_DPG_LMA_CTL
418da1170aSLeo Liu #define mmUVD_DPG_LMA_CTL_BASE_IDX						regUVD_DPG_LMA_CTL_BASE_IDX
428da1170aSLeo Liu #define mmUVD_DPG_LMA_DATA							regUVD_DPG_LMA_DATA
438da1170aSLeo Liu #define mmUVD_DPG_LMA_DATA_BASE_IDX						regUVD_DPG_LMA_DATA_BASE_IDX
448da1170aSLeo Liu 
458da1170aSLeo Liu #define VCN_VID_SOC_ADDRESS_2_0							0x1fb00
468da1170aSLeo Liu #define VCN1_VID_SOC_ADDRESS_3_0						0x48300
478da1170aSLeo Liu 
480b15205cSSonny Jiang #define RDECODE_MSG_CREATE							0x00000000
490b15205cSSonny Jiang #define RDECODE_MESSAGE_CREATE							0x00000001
500b15205cSSonny Jiang 
518da1170aSLeo Liu static int amdgpu_ih_clientid_vcns[] = {
528da1170aSLeo Liu 	SOC15_IH_CLIENTID_VCN,
538da1170aSLeo Liu 	SOC15_IH_CLIENTID_VCN1
548da1170aSLeo Liu };
558da1170aSLeo Liu 
56bb4f196bSRuijing Dong static void vcn_v4_0_set_unified_ring_funcs(struct amdgpu_device *adev);
578da1170aSLeo Liu static void vcn_v4_0_set_irq_funcs(struct amdgpu_device *adev);
588da1170aSLeo Liu static int vcn_v4_0_set_powergating_state(void *handle,
598da1170aSLeo Liu         enum amd_powergating_state state);
608da1170aSLeo Liu static int vcn_v4_0_pause_dpg_mode(struct amdgpu_device *adev,
618da1170aSLeo Liu         int inst_idx, struct dpg_pause_state *new_state);
628da1170aSLeo Liu 
638da1170aSLeo Liu /**
648da1170aSLeo Liu  * vcn_v4_0_early_init - set function pointers
658da1170aSLeo Liu  *
668da1170aSLeo Liu  * @handle: amdgpu_device pointer
678da1170aSLeo Liu  *
688da1170aSLeo Liu  * Set ring and irq function pointers
698da1170aSLeo Liu  */
708da1170aSLeo Liu static int vcn_v4_0_early_init(void *handle)
718da1170aSLeo Liu {
728da1170aSLeo Liu 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
738da1170aSLeo Liu 
74bb4f196bSRuijing Dong 	/* re-use enc ring as unified ring */
758da1170aSLeo Liu 	adev->vcn.num_enc_rings = 1;
768da1170aSLeo Liu 
77bb4f196bSRuijing Dong 	vcn_v4_0_set_unified_ring_funcs(adev);
788da1170aSLeo Liu 	vcn_v4_0_set_irq_funcs(adev);
798da1170aSLeo Liu 
808da1170aSLeo Liu 	return 0;
818da1170aSLeo Liu }
828da1170aSLeo Liu 
838da1170aSLeo Liu /**
848da1170aSLeo Liu  * vcn_v4_0_sw_init - sw init for VCN block
858da1170aSLeo Liu  *
868da1170aSLeo Liu  * @handle: amdgpu_device pointer
878da1170aSLeo Liu  *
888da1170aSLeo Liu  * Load firmware and sw initialization
898da1170aSLeo Liu  */
908da1170aSLeo Liu static int vcn_v4_0_sw_init(void *handle)
918da1170aSLeo Liu {
928da1170aSLeo Liu 	struct amdgpu_ring *ring;
938da1170aSLeo Liu 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
94bb4f196bSRuijing Dong 	int i, r;
958da1170aSLeo Liu 
968da1170aSLeo Liu 	r = amdgpu_vcn_sw_init(adev);
978da1170aSLeo Liu 	if (r)
988da1170aSLeo Liu 		return r;
998da1170aSLeo Liu 
1008da1170aSLeo Liu 	amdgpu_vcn_setup_ucode(adev);
1018da1170aSLeo Liu 
1028da1170aSLeo Liu 	r = amdgpu_vcn_resume(adev);
1038da1170aSLeo Liu 	if (r)
1048da1170aSLeo Liu 		return r;
1058da1170aSLeo Liu 
1068da1170aSLeo Liu 	for (i = 0; i < adev->vcn.num_vcn_inst; i++) {
1078da1170aSLeo Liu 		volatile struct amdgpu_vcn4_fw_shared *fw_shared;
108bb4f196bSRuijing Dong 
1098da1170aSLeo Liu 		if (adev->vcn.harvest_config & (1 << i))
1108da1170aSLeo Liu 			continue;
1118da1170aSLeo Liu 
1128da1170aSLeo Liu 		atomic_set(&adev->vcn.inst[i].sched_score, 0);
1138da1170aSLeo Liu 
114bb4f196bSRuijing Dong 		/* VCN UNIFIED TRAP */
1158da1170aSLeo Liu 		r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[i],
116bb4f196bSRuijing Dong 				VCN_4_0__SRCID__UVD_ENC_GENERAL_PURPOSE, &adev->vcn.inst[i].irq);
1178da1170aSLeo Liu 		if (r)
1188da1170aSLeo Liu 			return r;
1198da1170aSLeo Liu 
120bb4f196bSRuijing Dong 		ring = &adev->vcn.inst[i].ring_enc[0];
1218da1170aSLeo Liu 		ring->use_doorbell = true;
122bb4f196bSRuijing Dong 		ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 << 1) + 2 + 8 * i;
1238da1170aSLeo Liu 
124bb4f196bSRuijing Dong 		sprintf(ring->name, "vcn_unified_%d", i);
1258da1170aSLeo Liu 
1268da1170aSLeo Liu 		r = amdgpu_ring_init(adev, ring, 512, &adev->vcn.inst[i].irq, 0,
127bb4f196bSRuijing Dong 						AMDGPU_RING_PRIO_0, &adev->vcn.inst[i].sched_score);
1288da1170aSLeo Liu 		if (r)
1298da1170aSLeo Liu 			return r;
1308da1170aSLeo Liu 
1318da1170aSLeo Liu 		fw_shared = adev->vcn.inst[i].fw_shared.cpu_addr;
132bb4f196bSRuijing Dong 		fw_shared->present_flag_0 = cpu_to_le32(AMDGPU_FW_SHARED_FLAG_0_UNIFIED_QUEUE);
1338da1170aSLeo Liu 		fw_shared->sq.is_enabled = 1;
1348da1170aSLeo Liu 
1358da1170aSLeo Liu 		if (amdgpu_vcnfw_log)
1368da1170aSLeo Liu 			amdgpu_vcn_fwlog_init(&adev->vcn.inst[i]);
1378da1170aSLeo Liu 	}
1388da1170aSLeo Liu 
1398da1170aSLeo Liu 	if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG)
1408da1170aSLeo Liu 		adev->vcn.pause_dpg_mode = vcn_v4_0_pause_dpg_mode;
141bb4f196bSRuijing Dong 
1428da1170aSLeo Liu 	return 0;
1438da1170aSLeo Liu }
1448da1170aSLeo Liu 
1458da1170aSLeo Liu /**
1468da1170aSLeo Liu  * vcn_v4_0_sw_fini - sw fini for VCN block
1478da1170aSLeo Liu  *
1488da1170aSLeo Liu  * @handle: amdgpu_device pointer
1498da1170aSLeo Liu  *
1508da1170aSLeo Liu  * VCN suspend and free up sw allocation
1518da1170aSLeo Liu  */
1528da1170aSLeo Liu static int vcn_v4_0_sw_fini(void *handle)
1538da1170aSLeo Liu {
1548da1170aSLeo Liu 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
1558da1170aSLeo Liu 	int i, r, idx;
1568da1170aSLeo Liu 
1578585732bSGuchun Chen 	if (drm_dev_enter(adev_to_drm(adev), &idx)) {
1588da1170aSLeo Liu 		for (i = 0; i < adev->vcn.num_vcn_inst; i++) {
1598da1170aSLeo Liu 			volatile struct amdgpu_vcn4_fw_shared *fw_shared;
1608da1170aSLeo Liu 
1618da1170aSLeo Liu 			if (adev->vcn.harvest_config & (1 << i))
1628da1170aSLeo Liu 				continue;
1638da1170aSLeo Liu 
1648da1170aSLeo Liu 			fw_shared = adev->vcn.inst[i].fw_shared.cpu_addr;
1658da1170aSLeo Liu 			fw_shared->present_flag_0 = 0;
1668da1170aSLeo Liu 			fw_shared->sq.is_enabled = 0;
1678da1170aSLeo Liu 		}
1688da1170aSLeo Liu 
1698da1170aSLeo Liu 		drm_dev_exit(idx);
1708da1170aSLeo Liu 	}
1718da1170aSLeo Liu 
1728da1170aSLeo Liu 	r = amdgpu_vcn_suspend(adev);
1738da1170aSLeo Liu 	if (r)
1748da1170aSLeo Liu 		return r;
1758da1170aSLeo Liu 
1768da1170aSLeo Liu 	r = amdgpu_vcn_sw_fini(adev);
1778da1170aSLeo Liu 
1788da1170aSLeo Liu 	return r;
1798da1170aSLeo Liu }
1808da1170aSLeo Liu 
1818da1170aSLeo Liu /**
1828da1170aSLeo Liu  * vcn_v4_0_hw_init - start and test VCN block
1838da1170aSLeo Liu  *
1848da1170aSLeo Liu  * @handle: amdgpu_device pointer
1858da1170aSLeo Liu  *
1868da1170aSLeo Liu  * Initialize the hardware, boot up the VCPU and do some testing
1878da1170aSLeo Liu  */
1888da1170aSLeo Liu static int vcn_v4_0_hw_init(void *handle)
1898da1170aSLeo Liu {
1908da1170aSLeo Liu 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
1918da1170aSLeo Liu 	struct amdgpu_ring *ring;
192bb4f196bSRuijing Dong 	int i, r;
1938da1170aSLeo Liu 
1948da1170aSLeo Liu 	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
1958da1170aSLeo Liu 		if (adev->vcn.harvest_config & (1 << i))
1968da1170aSLeo Liu 			continue;
197bb4f196bSRuijing Dong 
1988da1170aSLeo Liu 		ring = &adev->vcn.inst[i].ring_enc[0];
1998da1170aSLeo Liu 
2008da1170aSLeo Liu 		adev->nbio.funcs->vcn_doorbell_range(adev, ring->use_doorbell,
2018da1170aSLeo Liu 				((adev->doorbell_index.vcn.vcn_ring0_1 << 1) + 8 * i), i);
2028da1170aSLeo Liu 
2038da1170aSLeo Liu 		r = amdgpu_ring_test_helper(ring);
2048da1170aSLeo Liu 		if (r)
2058da1170aSLeo Liu 			goto done;
2068da1170aSLeo Liu 	}
2078da1170aSLeo Liu 
2088da1170aSLeo Liu done:
2098da1170aSLeo Liu 	if (!r)
2108da1170aSLeo Liu 		DRM_INFO("VCN decode and encode initialized successfully(under %s).\n",
2118da1170aSLeo Liu 			(adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG)?"DPG Mode":"SPG Mode");
2128da1170aSLeo Liu 
2138da1170aSLeo Liu 	return r;
2148da1170aSLeo Liu }
2158da1170aSLeo Liu 
2168da1170aSLeo Liu /**
2178da1170aSLeo Liu  * vcn_v4_0_hw_fini - stop the hardware block
2188da1170aSLeo Liu  *
2198da1170aSLeo Liu  * @handle: amdgpu_device pointer
2208da1170aSLeo Liu  *
2218da1170aSLeo Liu  * Stop the VCN block, mark ring as not ready any more
2228da1170aSLeo Liu  */
2238da1170aSLeo Liu static int vcn_v4_0_hw_fini(void *handle)
2248da1170aSLeo Liu {
2258da1170aSLeo Liu 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
2268da1170aSLeo Liu 	int i;
2278da1170aSLeo Liu 
2288da1170aSLeo Liu 	cancel_delayed_work_sync(&adev->vcn.idle_work);
2298da1170aSLeo Liu 
2308da1170aSLeo Liu 	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
2318da1170aSLeo Liu 		if (adev->vcn.harvest_config & (1 << i))
2328da1170aSLeo Liu 			continue;
2338da1170aSLeo Liu 
2348da1170aSLeo Liu 		if ((adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) ||
2358da1170aSLeo Liu                         (adev->vcn.cur_state != AMD_PG_STATE_GATE &&
2368da1170aSLeo Liu                                 RREG32_SOC15(VCN, i, regUVD_STATUS))) {
2378da1170aSLeo Liu                         vcn_v4_0_set_powergating_state(adev, AMD_PG_STATE_GATE);
2388da1170aSLeo Liu 		}
2398da1170aSLeo Liu 	}
2408da1170aSLeo Liu 
2418da1170aSLeo Liu 	return 0;
2428da1170aSLeo Liu }
2438da1170aSLeo Liu 
2448da1170aSLeo Liu /**
2458da1170aSLeo Liu  * vcn_v4_0_suspend - suspend VCN block
2468da1170aSLeo Liu  *
2478da1170aSLeo Liu  * @handle: amdgpu_device pointer
2488da1170aSLeo Liu  *
2498da1170aSLeo Liu  * HW fini and suspend VCN block
2508da1170aSLeo Liu  */
2518da1170aSLeo Liu static int vcn_v4_0_suspend(void *handle)
2528da1170aSLeo Liu {
2538da1170aSLeo Liu 	int r;
2548da1170aSLeo Liu 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
2558da1170aSLeo Liu 
2568da1170aSLeo Liu 	r = vcn_v4_0_hw_fini(adev);
2578da1170aSLeo Liu 	if (r)
2588da1170aSLeo Liu 		return r;
2598da1170aSLeo Liu 
2608da1170aSLeo Liu 	r = amdgpu_vcn_suspend(adev);
2618da1170aSLeo Liu 
2628da1170aSLeo Liu 	return r;
2638da1170aSLeo Liu }
2648da1170aSLeo Liu 
2658da1170aSLeo Liu /**
2668da1170aSLeo Liu  * vcn_v4_0_resume - resume VCN block
2678da1170aSLeo Liu  *
2688da1170aSLeo Liu  * @handle: amdgpu_device pointer
2698da1170aSLeo Liu  *
2708da1170aSLeo Liu  * Resume firmware and hw init VCN block
2718da1170aSLeo Liu  */
2728da1170aSLeo Liu static int vcn_v4_0_resume(void *handle)
2738da1170aSLeo Liu {
2748da1170aSLeo Liu 	int r;
2758da1170aSLeo Liu 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
2768da1170aSLeo Liu 
2778da1170aSLeo Liu 	r = amdgpu_vcn_resume(adev);
2788da1170aSLeo Liu 	if (r)
2798da1170aSLeo Liu 		return r;
2808da1170aSLeo Liu 
2818da1170aSLeo Liu 	r = vcn_v4_0_hw_init(adev);
2828da1170aSLeo Liu 
2838da1170aSLeo Liu 	return r;
2848da1170aSLeo Liu }
2858da1170aSLeo Liu 
2868da1170aSLeo Liu /**
2878da1170aSLeo Liu  * vcn_v4_0_mc_resume - memory controller programming
2888da1170aSLeo Liu  *
2898da1170aSLeo Liu  * @adev: amdgpu_device pointer
2908da1170aSLeo Liu  * @inst: instance number
2918da1170aSLeo Liu  *
2928da1170aSLeo Liu  * Let the VCN memory controller know it's offsets
2938da1170aSLeo Liu  */
2948da1170aSLeo Liu static void vcn_v4_0_mc_resume(struct amdgpu_device *adev, int inst)
2958da1170aSLeo Liu {
2968da1170aSLeo Liu 	uint32_t offset, size;
2978da1170aSLeo Liu 	const struct common_firmware_header *hdr;
2988da1170aSLeo Liu 
2998da1170aSLeo Liu 	hdr = (const struct common_firmware_header *)adev->vcn.fw->data;
3008da1170aSLeo Liu 	size = AMDGPU_GPU_PAGE_ALIGN(le32_to_cpu(hdr->ucode_size_bytes) + 8);
3018da1170aSLeo Liu 
3028da1170aSLeo Liu 	/* cache window 0: fw */
3038da1170aSLeo Liu 	if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) {
3048da1170aSLeo Liu 		WREG32_SOC15(VCN, inst, regUVD_LMI_VCPU_CACHE_64BIT_BAR_LOW,
3058da1170aSLeo Liu 			(adev->firmware.ucode[AMDGPU_UCODE_ID_VCN + inst].tmr_mc_addr_lo));
3068da1170aSLeo Liu 		WREG32_SOC15(VCN, inst, regUVD_LMI_VCPU_CACHE_64BIT_BAR_HIGH,
3078da1170aSLeo Liu 			(adev->firmware.ucode[AMDGPU_UCODE_ID_VCN + inst].tmr_mc_addr_hi));
3088da1170aSLeo Liu 		WREG32_SOC15(VCN, inst, regUVD_VCPU_CACHE_OFFSET0, 0);
3098da1170aSLeo Liu 		offset = 0;
3108da1170aSLeo Liu 	} else {
3118da1170aSLeo Liu 		WREG32_SOC15(VCN, inst, regUVD_LMI_VCPU_CACHE_64BIT_BAR_LOW,
3128da1170aSLeo Liu 			lower_32_bits(adev->vcn.inst[inst].gpu_addr));
3138da1170aSLeo Liu 		WREG32_SOC15(VCN, inst, regUVD_LMI_VCPU_CACHE_64BIT_BAR_HIGH,
3148da1170aSLeo Liu 			upper_32_bits(adev->vcn.inst[inst].gpu_addr));
3158da1170aSLeo Liu 		offset = size;
3168da1170aSLeo Liu                 WREG32_SOC15(VCN, inst, regUVD_VCPU_CACHE_OFFSET0, AMDGPU_UVD_FIRMWARE_OFFSET >> 3);
3178da1170aSLeo Liu 	}
3188da1170aSLeo Liu 	WREG32_SOC15(VCN, inst, regUVD_VCPU_CACHE_SIZE0, size);
3198da1170aSLeo Liu 
3208da1170aSLeo Liu 	/* cache window 1: stack */
3218da1170aSLeo Liu 	WREG32_SOC15(VCN, inst, regUVD_LMI_VCPU_CACHE1_64BIT_BAR_LOW,
3228da1170aSLeo Liu 		lower_32_bits(adev->vcn.inst[inst].gpu_addr + offset));
3238da1170aSLeo Liu 	WREG32_SOC15(VCN, inst, regUVD_LMI_VCPU_CACHE1_64BIT_BAR_HIGH,
3248da1170aSLeo Liu 		upper_32_bits(adev->vcn.inst[inst].gpu_addr + offset));
3258da1170aSLeo Liu 	WREG32_SOC15(VCN, inst, regUVD_VCPU_CACHE_OFFSET1, 0);
3268da1170aSLeo Liu 	WREG32_SOC15(VCN, inst, regUVD_VCPU_CACHE_SIZE1, AMDGPU_VCN_STACK_SIZE);
3278da1170aSLeo Liu 
3288da1170aSLeo Liu 	/* cache window 2: context */
3298da1170aSLeo Liu 	WREG32_SOC15(VCN, inst, regUVD_LMI_VCPU_CACHE2_64BIT_BAR_LOW,
3308da1170aSLeo Liu 		lower_32_bits(adev->vcn.inst[inst].gpu_addr + offset + AMDGPU_VCN_STACK_SIZE));
3318da1170aSLeo Liu 	WREG32_SOC15(VCN, inst, regUVD_LMI_VCPU_CACHE2_64BIT_BAR_HIGH,
3328da1170aSLeo Liu 		upper_32_bits(adev->vcn.inst[inst].gpu_addr + offset + AMDGPU_VCN_STACK_SIZE));
3338da1170aSLeo Liu 	WREG32_SOC15(VCN, inst, regUVD_VCPU_CACHE_OFFSET2, 0);
3348da1170aSLeo Liu 	WREG32_SOC15(VCN, inst, regUVD_VCPU_CACHE_SIZE2, AMDGPU_VCN_CONTEXT_SIZE);
3358da1170aSLeo Liu 
3368da1170aSLeo Liu 	/* non-cache window */
3378da1170aSLeo Liu 	WREG32_SOC15(VCN, inst, regUVD_LMI_VCPU_NC0_64BIT_BAR_LOW,
3388da1170aSLeo Liu 		lower_32_bits(adev->vcn.inst[inst].fw_shared.gpu_addr));
3398da1170aSLeo Liu 	WREG32_SOC15(VCN, inst, regUVD_LMI_VCPU_NC0_64BIT_BAR_HIGH,
3408da1170aSLeo Liu 		upper_32_bits(adev->vcn.inst[inst].fw_shared.gpu_addr));
3418da1170aSLeo Liu 	WREG32_SOC15(VCN, inst, regUVD_VCPU_NONCACHE_OFFSET0, 0);
3428da1170aSLeo Liu 	WREG32_SOC15(VCN, inst, regUVD_VCPU_NONCACHE_SIZE0,
3438da1170aSLeo Liu 		AMDGPU_GPU_PAGE_ALIGN(sizeof(struct amdgpu_vcn4_fw_shared)));
3448da1170aSLeo Liu }
3458da1170aSLeo Liu 
3468da1170aSLeo Liu /**
3478da1170aSLeo Liu  * vcn_v4_0_mc_resume_dpg_mode - memory controller programming for dpg mode
3488da1170aSLeo Liu  *
3498da1170aSLeo Liu  * @adev: amdgpu_device pointer
3508da1170aSLeo Liu  * @inst_idx: instance number index
3518da1170aSLeo Liu  * @indirect: indirectly write sram
3528da1170aSLeo Liu  *
3538da1170aSLeo Liu  * Let the VCN memory controller know it's offsets with dpg mode
3548da1170aSLeo Liu  */
3558da1170aSLeo Liu static void vcn_v4_0_mc_resume_dpg_mode(struct amdgpu_device *adev, int inst_idx, bool indirect)
3568da1170aSLeo Liu {
3578da1170aSLeo Liu 	uint32_t offset, size;
3588da1170aSLeo Liu 	const struct common_firmware_header *hdr;
3598da1170aSLeo Liu 	hdr = (const struct common_firmware_header *)adev->vcn.fw->data;
3608da1170aSLeo Liu 	size = AMDGPU_GPU_PAGE_ALIGN(le32_to_cpu(hdr->ucode_size_bytes) + 8);
3618da1170aSLeo Liu 
3628da1170aSLeo Liu 	/* cache window 0: fw */
3638da1170aSLeo Liu 	if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) {
3648da1170aSLeo Liu 		if (!indirect) {
3658da1170aSLeo Liu 			WREG32_SOC15_DPG_MODE(inst_idx, SOC15_DPG_MODE_OFFSET(
3668da1170aSLeo Liu 				VCN, inst_idx, regUVD_LMI_VCPU_CACHE_64BIT_BAR_LOW),
3678da1170aSLeo Liu 				(adev->firmware.ucode[AMDGPU_UCODE_ID_VCN + inst_idx].tmr_mc_addr_lo), 0, indirect);
3688da1170aSLeo Liu 			WREG32_SOC15_DPG_MODE(inst_idx, SOC15_DPG_MODE_OFFSET(
3698da1170aSLeo Liu 				VCN, inst_idx, regUVD_LMI_VCPU_CACHE_64BIT_BAR_HIGH),
3708da1170aSLeo Liu 				(adev->firmware.ucode[AMDGPU_UCODE_ID_VCN + inst_idx].tmr_mc_addr_hi), 0, indirect);
3718da1170aSLeo Liu 			WREG32_SOC15_DPG_MODE(inst_idx, SOC15_DPG_MODE_OFFSET(
3728da1170aSLeo Liu 				VCN, inst_idx, regUVD_VCPU_CACHE_OFFSET0), 0, 0, indirect);
3738da1170aSLeo Liu 		} else {
3748da1170aSLeo Liu 			WREG32_SOC15_DPG_MODE(inst_idx, SOC15_DPG_MODE_OFFSET(
3758da1170aSLeo Liu 				VCN, inst_idx, regUVD_LMI_VCPU_CACHE_64BIT_BAR_LOW), 0, 0, indirect);
3768da1170aSLeo Liu 			WREG32_SOC15_DPG_MODE(inst_idx, SOC15_DPG_MODE_OFFSET(
3778da1170aSLeo Liu 				VCN, inst_idx, regUVD_LMI_VCPU_CACHE_64BIT_BAR_HIGH), 0, 0, indirect);
3788da1170aSLeo Liu 			WREG32_SOC15_DPG_MODE(inst_idx, SOC15_DPG_MODE_OFFSET(
3798da1170aSLeo Liu 				VCN, inst_idx, regUVD_VCPU_CACHE_OFFSET0), 0, 0, indirect);
3808da1170aSLeo Liu 		}
3818da1170aSLeo Liu 		offset = 0;
3828da1170aSLeo Liu 	} else {
3838da1170aSLeo Liu 		WREG32_SOC15_DPG_MODE(inst_idx, SOC15_DPG_MODE_OFFSET(
3848da1170aSLeo Liu 			VCN, inst_idx, regUVD_LMI_VCPU_CACHE_64BIT_BAR_LOW),
3858da1170aSLeo Liu 			lower_32_bits(adev->vcn.inst[inst_idx].gpu_addr), 0, indirect);
3868da1170aSLeo Liu 		WREG32_SOC15_DPG_MODE(inst_idx, SOC15_DPG_MODE_OFFSET(
3878da1170aSLeo Liu 			VCN, inst_idx, regUVD_LMI_VCPU_CACHE_64BIT_BAR_HIGH),
3888da1170aSLeo Liu 			upper_32_bits(adev->vcn.inst[inst_idx].gpu_addr), 0, indirect);
3898da1170aSLeo Liu 		offset = size;
3908da1170aSLeo Liu 		WREG32_SOC15_DPG_MODE(inst_idx, SOC15_DPG_MODE_OFFSET(
3918da1170aSLeo Liu 			VCN, inst_idx, regUVD_VCPU_CACHE_OFFSET0),
3928da1170aSLeo Liu 			AMDGPU_UVD_FIRMWARE_OFFSET >> 3, 0, indirect);
3938da1170aSLeo Liu 	}
3948da1170aSLeo Liu 
3958da1170aSLeo Liu 	if (!indirect)
3968da1170aSLeo Liu 		WREG32_SOC15_DPG_MODE(inst_idx, SOC15_DPG_MODE_OFFSET(
3978da1170aSLeo Liu 			VCN, inst_idx, regUVD_VCPU_CACHE_SIZE0), size, 0, indirect);
3988da1170aSLeo Liu 	else
3998da1170aSLeo Liu 		WREG32_SOC15_DPG_MODE(inst_idx, SOC15_DPG_MODE_OFFSET(
4008da1170aSLeo Liu 			VCN, inst_idx, regUVD_VCPU_CACHE_SIZE0), 0, 0, indirect);
4018da1170aSLeo Liu 
4028da1170aSLeo Liu 	/* cache window 1: stack */
4038da1170aSLeo Liu 	if (!indirect) {
4048da1170aSLeo Liu 		WREG32_SOC15_DPG_MODE(inst_idx, SOC15_DPG_MODE_OFFSET(
4058da1170aSLeo Liu 			VCN, inst_idx, regUVD_LMI_VCPU_CACHE1_64BIT_BAR_LOW),
4068da1170aSLeo Liu 			lower_32_bits(adev->vcn.inst[inst_idx].gpu_addr + offset), 0, indirect);
4078da1170aSLeo Liu 		WREG32_SOC15_DPG_MODE(inst_idx, SOC15_DPG_MODE_OFFSET(
4088da1170aSLeo Liu 			VCN, inst_idx, regUVD_LMI_VCPU_CACHE1_64BIT_BAR_HIGH),
4098da1170aSLeo Liu 			upper_32_bits(adev->vcn.inst[inst_idx].gpu_addr + offset), 0, indirect);
4108da1170aSLeo Liu 		WREG32_SOC15_DPG_MODE(inst_idx, SOC15_DPG_MODE_OFFSET(
4118da1170aSLeo Liu 			VCN, inst_idx, regUVD_VCPU_CACHE_OFFSET1), 0, 0, indirect);
4128da1170aSLeo Liu 	} else {
4138da1170aSLeo Liu 		WREG32_SOC15_DPG_MODE(inst_idx, SOC15_DPG_MODE_OFFSET(
4148da1170aSLeo Liu 			VCN, inst_idx, regUVD_LMI_VCPU_CACHE1_64BIT_BAR_LOW), 0, 0, indirect);
4158da1170aSLeo Liu 		WREG32_SOC15_DPG_MODE(inst_idx, SOC15_DPG_MODE_OFFSET(
4168da1170aSLeo Liu 			VCN, inst_idx, regUVD_LMI_VCPU_CACHE1_64BIT_BAR_HIGH), 0, 0, indirect);
4178da1170aSLeo Liu 		WREG32_SOC15_DPG_MODE(inst_idx, SOC15_DPG_MODE_OFFSET(
4188da1170aSLeo Liu 			VCN, inst_idx, regUVD_VCPU_CACHE_OFFSET1), 0, 0, indirect);
4198da1170aSLeo Liu 	}
4208da1170aSLeo Liu 	WREG32_SOC15_DPG_MODE(inst_idx, SOC15_DPG_MODE_OFFSET(
4218da1170aSLeo Liu 			VCN, inst_idx, regUVD_VCPU_CACHE_SIZE1), AMDGPU_VCN_STACK_SIZE, 0, indirect);
4228da1170aSLeo Liu 
4238da1170aSLeo Liu 	/* cache window 2: context */
4248da1170aSLeo Liu 	WREG32_SOC15_DPG_MODE(inst_idx, SOC15_DPG_MODE_OFFSET(
4258da1170aSLeo Liu 			VCN, inst_idx, regUVD_LMI_VCPU_CACHE2_64BIT_BAR_LOW),
4268da1170aSLeo Liu 			lower_32_bits(adev->vcn.inst[inst_idx].gpu_addr + offset + AMDGPU_VCN_STACK_SIZE), 0, indirect);
4278da1170aSLeo Liu 	WREG32_SOC15_DPG_MODE(inst_idx, SOC15_DPG_MODE_OFFSET(
4288da1170aSLeo Liu 			VCN, inst_idx, regUVD_LMI_VCPU_CACHE2_64BIT_BAR_HIGH),
4298da1170aSLeo Liu 			upper_32_bits(adev->vcn.inst[inst_idx].gpu_addr + offset + AMDGPU_VCN_STACK_SIZE), 0, indirect);
4308da1170aSLeo Liu 	WREG32_SOC15_DPG_MODE(inst_idx, SOC15_DPG_MODE_OFFSET(
4318da1170aSLeo Liu 			VCN, inst_idx, regUVD_VCPU_CACHE_OFFSET2), 0, 0, indirect);
4328da1170aSLeo Liu 	WREG32_SOC15_DPG_MODE(inst_idx, SOC15_DPG_MODE_OFFSET(
4338da1170aSLeo Liu 			VCN, inst_idx, regUVD_VCPU_CACHE_SIZE2), AMDGPU_VCN_CONTEXT_SIZE, 0, indirect);
4348da1170aSLeo Liu 
4358da1170aSLeo Liu 	/* non-cache window */
4368da1170aSLeo Liu 	WREG32_SOC15_DPG_MODE(inst_idx, SOC15_DPG_MODE_OFFSET(
4378da1170aSLeo Liu 			VCN, inst_idx, regUVD_LMI_VCPU_NC0_64BIT_BAR_LOW),
4388da1170aSLeo Liu 			lower_32_bits(adev->vcn.inst[inst_idx].fw_shared.gpu_addr), 0, indirect);
4398da1170aSLeo Liu 	WREG32_SOC15_DPG_MODE(inst_idx, SOC15_DPG_MODE_OFFSET(
4408da1170aSLeo Liu 			VCN, inst_idx, regUVD_LMI_VCPU_NC0_64BIT_BAR_HIGH),
4418da1170aSLeo Liu 			upper_32_bits(adev->vcn.inst[inst_idx].fw_shared.gpu_addr), 0, indirect);
4428da1170aSLeo Liu 	WREG32_SOC15_DPG_MODE(inst_idx, SOC15_DPG_MODE_OFFSET(
4438da1170aSLeo Liu 			VCN, inst_idx, regUVD_VCPU_NONCACHE_OFFSET0), 0, 0, indirect);
4448da1170aSLeo Liu 	WREG32_SOC15_DPG_MODE(inst_idx, SOC15_DPG_MODE_OFFSET(
4458da1170aSLeo Liu 			VCN, inst_idx, regUVD_VCPU_NONCACHE_SIZE0),
4468da1170aSLeo Liu 			AMDGPU_GPU_PAGE_ALIGN(sizeof(struct amdgpu_vcn4_fw_shared)), 0, indirect);
4478da1170aSLeo Liu 
4488da1170aSLeo Liu 	/* VCN global tiling registers */
4498da1170aSLeo Liu 	WREG32_SOC15_DPG_MODE(inst_idx, SOC15_DPG_MODE_OFFSET(
4508da1170aSLeo Liu 		VCN, 0, regUVD_GFX10_ADDR_CONFIG), adev->gfx.config.gb_addr_config, 0, indirect);
4518da1170aSLeo Liu }
4528da1170aSLeo Liu 
4538da1170aSLeo Liu /**
4548da1170aSLeo Liu  * vcn_v4_0_disable_static_power_gating - disable VCN static power gating
4558da1170aSLeo Liu  *
4568da1170aSLeo Liu  * @adev: amdgpu_device pointer
4578da1170aSLeo Liu  * @inst: instance number
4588da1170aSLeo Liu  *
4598da1170aSLeo Liu  * Disable static power gating for VCN block
4608da1170aSLeo Liu  */
4618da1170aSLeo Liu static void vcn_v4_0_disable_static_power_gating(struct amdgpu_device *adev, int inst)
4628da1170aSLeo Liu {
4638da1170aSLeo Liu 	uint32_t data = 0;
4648da1170aSLeo Liu 
4658da1170aSLeo Liu 	if (adev->pg_flags & AMD_PG_SUPPORT_VCN) {
4668da1170aSLeo Liu 		data = (1 << UVD_PGFSM_CONFIG__UVDM_PWR_CONFIG__SHIFT
4678da1170aSLeo Liu 			| 1 << UVD_PGFSM_CONFIG__UVDS_PWR_CONFIG__SHIFT
4688da1170aSLeo Liu 			| 1 << UVD_PGFSM_CONFIG__UVDLM_PWR_CONFIG__SHIFT
4698da1170aSLeo Liu 			| 2 << UVD_PGFSM_CONFIG__UVDF_PWR_CONFIG__SHIFT
4708da1170aSLeo Liu 			| 2 << UVD_PGFSM_CONFIG__UVDTC_PWR_CONFIG__SHIFT
4718da1170aSLeo Liu 			| 2 << UVD_PGFSM_CONFIG__UVDB_PWR_CONFIG__SHIFT
4728da1170aSLeo Liu 			| 2 << UVD_PGFSM_CONFIG__UVDTA_PWR_CONFIG__SHIFT
4738da1170aSLeo Liu 			| 2 << UVD_PGFSM_CONFIG__UVDTD_PWR_CONFIG__SHIFT
4748da1170aSLeo Liu 			| 2 << UVD_PGFSM_CONFIG__UVDTE_PWR_CONFIG__SHIFT
4758da1170aSLeo Liu 			| 2 << UVD_PGFSM_CONFIG__UVDE_PWR_CONFIG__SHIFT
4768da1170aSLeo Liu 			| 2 << UVD_PGFSM_CONFIG__UVDAB_PWR_CONFIG__SHIFT
4778da1170aSLeo Liu 			| 2 << UVD_PGFSM_CONFIG__UVDTB_PWR_CONFIG__SHIFT
4788da1170aSLeo Liu 			| 2 << UVD_PGFSM_CONFIG__UVDNA_PWR_CONFIG__SHIFT
4798da1170aSLeo Liu 			| 2 << UVD_PGFSM_CONFIG__UVDNB_PWR_CONFIG__SHIFT);
4808da1170aSLeo Liu 
4818da1170aSLeo Liu 		WREG32_SOC15(VCN, inst, regUVD_PGFSM_CONFIG, data);
4828da1170aSLeo Liu 		SOC15_WAIT_ON_RREG(VCN, inst, regUVD_PGFSM_STATUS,
4838da1170aSLeo Liu 			UVD_PGFSM_STATUS__UVDM_UVDU_UVDLM_PWR_ON_3_0, 0x3F3FFFFF);
4848da1170aSLeo Liu 	} else {
4858da1170aSLeo Liu 		uint32_t value;
4868da1170aSLeo Liu 
4878da1170aSLeo Liu 		value = (inst) ? 0x2200800 : 0;
4888da1170aSLeo Liu 		data = (1 << UVD_PGFSM_CONFIG__UVDM_PWR_CONFIG__SHIFT
4898da1170aSLeo Liu 			| 1 << UVD_PGFSM_CONFIG__UVDS_PWR_CONFIG__SHIFT
4908da1170aSLeo Liu 			| 1 << UVD_PGFSM_CONFIG__UVDLM_PWR_CONFIG__SHIFT
4918da1170aSLeo Liu 			| 1 << UVD_PGFSM_CONFIG__UVDF_PWR_CONFIG__SHIFT
4928da1170aSLeo Liu 			| 1 << UVD_PGFSM_CONFIG__UVDTC_PWR_CONFIG__SHIFT
4938da1170aSLeo Liu 			| 1 << UVD_PGFSM_CONFIG__UVDB_PWR_CONFIG__SHIFT
4948da1170aSLeo Liu 			| 1 << UVD_PGFSM_CONFIG__UVDTA_PWR_CONFIG__SHIFT
4958da1170aSLeo Liu 			| 1 << UVD_PGFSM_CONFIG__UVDTD_PWR_CONFIG__SHIFT
4968da1170aSLeo Liu 			| 1 << UVD_PGFSM_CONFIG__UVDTE_PWR_CONFIG__SHIFT
4978da1170aSLeo Liu 			| 1 << UVD_PGFSM_CONFIG__UVDE_PWR_CONFIG__SHIFT
4988da1170aSLeo Liu 			| 1 << UVD_PGFSM_CONFIG__UVDAB_PWR_CONFIG__SHIFT
4998da1170aSLeo Liu 			| 1 << UVD_PGFSM_CONFIG__UVDTB_PWR_CONFIG__SHIFT
5008da1170aSLeo Liu 			| 1 << UVD_PGFSM_CONFIG__UVDNA_PWR_CONFIG__SHIFT
5018da1170aSLeo Liu 			| 1 << UVD_PGFSM_CONFIG__UVDNB_PWR_CONFIG__SHIFT);
5028da1170aSLeo Liu 
5038da1170aSLeo Liu                 WREG32_SOC15(VCN, inst, regUVD_PGFSM_CONFIG, data);
5048da1170aSLeo Liu                 SOC15_WAIT_ON_RREG(VCN, inst, regUVD_PGFSM_STATUS, value,  0x3F3FFFFF);
5058da1170aSLeo Liu         }
5068da1170aSLeo Liu 
5078da1170aSLeo Liu         data = RREG32_SOC15(VCN, inst, regUVD_POWER_STATUS);
5088da1170aSLeo Liu         data &= ~0x103;
5098da1170aSLeo Liu         if (adev->pg_flags & AMD_PG_SUPPORT_VCN)
5108da1170aSLeo Liu                 data |= UVD_PGFSM_CONFIG__UVDM_UVDU_PWR_ON |
5118da1170aSLeo Liu                         UVD_POWER_STATUS__UVD_PG_EN_MASK;
5128da1170aSLeo Liu 
5138da1170aSLeo Liu         WREG32_SOC15(VCN, inst, regUVD_POWER_STATUS, data);
5148da1170aSLeo Liu 
5158da1170aSLeo Liu         return;
5168da1170aSLeo Liu }
5178da1170aSLeo Liu 
5188da1170aSLeo Liu /**
5198da1170aSLeo Liu  * vcn_v4_0_enable_static_power_gating - enable VCN static power gating
5208da1170aSLeo Liu  *
5218da1170aSLeo Liu  * @adev: amdgpu_device pointer
5228da1170aSLeo Liu  * @inst: instance number
5238da1170aSLeo Liu  *
5248da1170aSLeo Liu  * Enable static power gating for VCN block
5258da1170aSLeo Liu  */
5268da1170aSLeo Liu static void vcn_v4_0_enable_static_power_gating(struct amdgpu_device *adev, int inst)
5278da1170aSLeo Liu {
5288da1170aSLeo Liu 	uint32_t data;
5298da1170aSLeo Liu 
5308da1170aSLeo Liu 	if (adev->pg_flags & AMD_PG_SUPPORT_VCN) {
5318da1170aSLeo Liu 		/* Before power off, this indicator has to be turned on */
5328da1170aSLeo Liu 		data = RREG32_SOC15(VCN, inst, regUVD_POWER_STATUS);
5338da1170aSLeo Liu 		data &= ~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK;
5348da1170aSLeo Liu 		data |= UVD_POWER_STATUS__UVD_POWER_STATUS_TILES_OFF;
5358da1170aSLeo Liu 		WREG32_SOC15(VCN, inst, regUVD_POWER_STATUS, data);
5368da1170aSLeo Liu 
5378da1170aSLeo Liu 		data = (2 << UVD_PGFSM_CONFIG__UVDM_PWR_CONFIG__SHIFT
5388da1170aSLeo Liu 			| 2 << UVD_PGFSM_CONFIG__UVDS_PWR_CONFIG__SHIFT
5398da1170aSLeo Liu 			| 2 << UVD_PGFSM_CONFIG__UVDF_PWR_CONFIG__SHIFT
5408da1170aSLeo Liu 			| 2 << UVD_PGFSM_CONFIG__UVDTC_PWR_CONFIG__SHIFT
5418da1170aSLeo Liu 			| 2 << UVD_PGFSM_CONFIG__UVDB_PWR_CONFIG__SHIFT
5428da1170aSLeo Liu 			| 2 << UVD_PGFSM_CONFIG__UVDTA_PWR_CONFIG__SHIFT
5438da1170aSLeo Liu 			| 2 << UVD_PGFSM_CONFIG__UVDLM_PWR_CONFIG__SHIFT
5448da1170aSLeo Liu 			| 2 << UVD_PGFSM_CONFIG__UVDTD_PWR_CONFIG__SHIFT
5458da1170aSLeo Liu 			| 2 << UVD_PGFSM_CONFIG__UVDTE_PWR_CONFIG__SHIFT
5468da1170aSLeo Liu 			| 2 << UVD_PGFSM_CONFIG__UVDE_PWR_CONFIG__SHIFT
5478da1170aSLeo Liu 			| 2 << UVD_PGFSM_CONFIG__UVDAB_PWR_CONFIG__SHIFT
5488da1170aSLeo Liu 			| 2 << UVD_PGFSM_CONFIG__UVDTB_PWR_CONFIG__SHIFT
5498da1170aSLeo Liu 			| 2 << UVD_PGFSM_CONFIG__UVDNA_PWR_CONFIG__SHIFT
5508da1170aSLeo Liu 			| 2 << UVD_PGFSM_CONFIG__UVDNB_PWR_CONFIG__SHIFT);
5518da1170aSLeo Liu 		WREG32_SOC15(VCN, inst, regUVD_PGFSM_CONFIG, data);
5528da1170aSLeo Liu 
5538da1170aSLeo Liu 		data = (2 << UVD_PGFSM_STATUS__UVDM_PWR_STATUS__SHIFT
5548da1170aSLeo Liu 			| 2 << UVD_PGFSM_STATUS__UVDS_PWR_STATUS__SHIFT
5558da1170aSLeo Liu 			| 2 << UVD_PGFSM_STATUS__UVDF_PWR_STATUS__SHIFT
5568da1170aSLeo Liu 			| 2 << UVD_PGFSM_STATUS__UVDTC_PWR_STATUS__SHIFT
5578da1170aSLeo Liu 			| 2 << UVD_PGFSM_STATUS__UVDB_PWR_STATUS__SHIFT
5588da1170aSLeo Liu 			| 2 << UVD_PGFSM_STATUS__UVDTA_PWR_STATUS__SHIFT
5598da1170aSLeo Liu 			| 2 << UVD_PGFSM_STATUS__UVDLM_PWR_STATUS__SHIFT
5608da1170aSLeo Liu 			| 2 << UVD_PGFSM_STATUS__UVDTD_PWR_STATUS__SHIFT
5618da1170aSLeo Liu 			| 2 << UVD_PGFSM_STATUS__UVDTE_PWR_STATUS__SHIFT
5628da1170aSLeo Liu 			| 2 << UVD_PGFSM_STATUS__UVDE_PWR_STATUS__SHIFT
5638da1170aSLeo Liu 			| 2 << UVD_PGFSM_STATUS__UVDAB_PWR_STATUS__SHIFT
5648da1170aSLeo Liu 			| 2 << UVD_PGFSM_STATUS__UVDTB_PWR_STATUS__SHIFT
5658da1170aSLeo Liu 			| 2 << UVD_PGFSM_STATUS__UVDNA_PWR_STATUS__SHIFT
5668da1170aSLeo Liu 			| 2 << UVD_PGFSM_STATUS__UVDNB_PWR_STATUS__SHIFT);
5678da1170aSLeo Liu 		SOC15_WAIT_ON_RREG(VCN, inst, regUVD_PGFSM_STATUS, data, 0x3F3FFFFF);
5688da1170aSLeo Liu 	}
5698da1170aSLeo Liu 
5708da1170aSLeo Liu         return;
5718da1170aSLeo Liu }
5728da1170aSLeo Liu 
5738da1170aSLeo Liu /**
5748da1170aSLeo Liu  * vcn_v4_0_disable_clock_gating - disable VCN clock gating
5758da1170aSLeo Liu  *
5768da1170aSLeo Liu  * @adev: amdgpu_device pointer
5778da1170aSLeo Liu  * @inst: instance number
5788da1170aSLeo Liu  *
5798da1170aSLeo Liu  * Disable clock gating for VCN block
5808da1170aSLeo Liu  */
5818da1170aSLeo Liu static void vcn_v4_0_disable_clock_gating(struct amdgpu_device *adev, int inst)
5828da1170aSLeo Liu {
5838da1170aSLeo Liu 	uint32_t data;
5848da1170aSLeo Liu 
5858da1170aSLeo Liu 	if (adev->cg_flags & AMD_CG_SUPPORT_VCN_MGCG)
5868da1170aSLeo Liu 		return;
5878da1170aSLeo Liu 
5888da1170aSLeo Liu 	/* VCN disable CGC */
5898da1170aSLeo Liu 	data = RREG32_SOC15(VCN, inst, regUVD_CGC_CTRL);
5908da1170aSLeo Liu 	data &= ~UVD_CGC_CTRL__DYN_CLOCK_MODE_MASK;
5918da1170aSLeo Liu 	data |= 1 << UVD_CGC_CTRL__CLK_GATE_DLY_TIMER__SHIFT;
5928da1170aSLeo Liu 	data |= 4 << UVD_CGC_CTRL__CLK_OFF_DELAY__SHIFT;
5938da1170aSLeo Liu 	WREG32_SOC15(VCN, inst, regUVD_CGC_CTRL, data);
5948da1170aSLeo Liu 
5958da1170aSLeo Liu 	data = RREG32_SOC15(VCN, inst, regUVD_CGC_GATE);
5968da1170aSLeo Liu 	data &= ~(UVD_CGC_GATE__SYS_MASK
5978da1170aSLeo Liu 		| UVD_CGC_GATE__UDEC_MASK
5988da1170aSLeo Liu 		| UVD_CGC_GATE__MPEG2_MASK
5998da1170aSLeo Liu 		| UVD_CGC_GATE__REGS_MASK
6008da1170aSLeo Liu 		| UVD_CGC_GATE__RBC_MASK
6018da1170aSLeo Liu 		| UVD_CGC_GATE__LMI_MC_MASK
6028da1170aSLeo Liu 		| UVD_CGC_GATE__LMI_UMC_MASK
6038da1170aSLeo Liu 		| UVD_CGC_GATE__IDCT_MASK
6048da1170aSLeo Liu 		| UVD_CGC_GATE__MPRD_MASK
6058da1170aSLeo Liu 		| UVD_CGC_GATE__MPC_MASK
6068da1170aSLeo Liu 		| UVD_CGC_GATE__LBSI_MASK
6078da1170aSLeo Liu 		| UVD_CGC_GATE__LRBBM_MASK
6088da1170aSLeo Liu 		| UVD_CGC_GATE__UDEC_RE_MASK
6098da1170aSLeo Liu 		| UVD_CGC_GATE__UDEC_CM_MASK
6108da1170aSLeo Liu 		| UVD_CGC_GATE__UDEC_IT_MASK
6118da1170aSLeo Liu 		| UVD_CGC_GATE__UDEC_DB_MASK
6128da1170aSLeo Liu 		| UVD_CGC_GATE__UDEC_MP_MASK
6138da1170aSLeo Liu 		| UVD_CGC_GATE__WCB_MASK
6148da1170aSLeo Liu 		| UVD_CGC_GATE__VCPU_MASK
6158da1170aSLeo Liu 		| UVD_CGC_GATE__MMSCH_MASK);
6168da1170aSLeo Liu 
6178da1170aSLeo Liu 	WREG32_SOC15(VCN, inst, regUVD_CGC_GATE, data);
6188da1170aSLeo Liu 	SOC15_WAIT_ON_RREG(VCN, inst, regUVD_CGC_GATE, 0,  0xFFFFFFFF);
6198da1170aSLeo Liu 
6208da1170aSLeo Liu 	data = RREG32_SOC15(VCN, inst, regUVD_CGC_CTRL);
6218da1170aSLeo Liu 	data &= ~(UVD_CGC_CTRL__UDEC_RE_MODE_MASK
6228da1170aSLeo Liu 		| UVD_CGC_CTRL__UDEC_CM_MODE_MASK
6238da1170aSLeo Liu 		| UVD_CGC_CTRL__UDEC_IT_MODE_MASK
6248da1170aSLeo Liu 		| UVD_CGC_CTRL__UDEC_DB_MODE_MASK
6258da1170aSLeo Liu 		| UVD_CGC_CTRL__UDEC_MP_MODE_MASK
6268da1170aSLeo Liu 		| UVD_CGC_CTRL__SYS_MODE_MASK
6278da1170aSLeo Liu 		| UVD_CGC_CTRL__UDEC_MODE_MASK
6288da1170aSLeo Liu 		| UVD_CGC_CTRL__MPEG2_MODE_MASK
6298da1170aSLeo Liu 		| UVD_CGC_CTRL__REGS_MODE_MASK
6308da1170aSLeo Liu 		| UVD_CGC_CTRL__RBC_MODE_MASK
6318da1170aSLeo Liu 		| UVD_CGC_CTRL__LMI_MC_MODE_MASK
6328da1170aSLeo Liu 		| UVD_CGC_CTRL__LMI_UMC_MODE_MASK
6338da1170aSLeo Liu 		| UVD_CGC_CTRL__IDCT_MODE_MASK
6348da1170aSLeo Liu 		| UVD_CGC_CTRL__MPRD_MODE_MASK
6358da1170aSLeo Liu 		| UVD_CGC_CTRL__MPC_MODE_MASK
6368da1170aSLeo Liu 		| UVD_CGC_CTRL__LBSI_MODE_MASK
6378da1170aSLeo Liu 		| UVD_CGC_CTRL__LRBBM_MODE_MASK
6388da1170aSLeo Liu 		| UVD_CGC_CTRL__WCB_MODE_MASK
6398da1170aSLeo Liu 		| UVD_CGC_CTRL__VCPU_MODE_MASK
6408da1170aSLeo Liu 		| UVD_CGC_CTRL__MMSCH_MODE_MASK);
6418da1170aSLeo Liu 	WREG32_SOC15(VCN, inst, regUVD_CGC_CTRL, data);
6428da1170aSLeo Liu 
6438da1170aSLeo Liu 	data = RREG32_SOC15(VCN, inst, regUVD_SUVD_CGC_GATE);
6448da1170aSLeo Liu 	data |= (UVD_SUVD_CGC_GATE__SRE_MASK
6458da1170aSLeo Liu 		| UVD_SUVD_CGC_GATE__SIT_MASK
6468da1170aSLeo Liu 		| UVD_SUVD_CGC_GATE__SMP_MASK
6478da1170aSLeo Liu 		| UVD_SUVD_CGC_GATE__SCM_MASK
6488da1170aSLeo Liu 		| UVD_SUVD_CGC_GATE__SDB_MASK
6498da1170aSLeo Liu 		| UVD_SUVD_CGC_GATE__SRE_H264_MASK
6508da1170aSLeo Liu 		| UVD_SUVD_CGC_GATE__SRE_HEVC_MASK
6518da1170aSLeo Liu 		| UVD_SUVD_CGC_GATE__SIT_H264_MASK
6528da1170aSLeo Liu 		| UVD_SUVD_CGC_GATE__SIT_HEVC_MASK
6538da1170aSLeo Liu 		| UVD_SUVD_CGC_GATE__SCM_H264_MASK
6548da1170aSLeo Liu 		| UVD_SUVD_CGC_GATE__SCM_HEVC_MASK
6558da1170aSLeo Liu 		| UVD_SUVD_CGC_GATE__SDB_H264_MASK
6568da1170aSLeo Liu 		| UVD_SUVD_CGC_GATE__SDB_HEVC_MASK
6578da1170aSLeo Liu 		| UVD_SUVD_CGC_GATE__SCLR_MASK
6588da1170aSLeo Liu 		| UVD_SUVD_CGC_GATE__UVD_SC_MASK
6598da1170aSLeo Liu 		| UVD_SUVD_CGC_GATE__ENT_MASK
6608da1170aSLeo Liu 		| UVD_SUVD_CGC_GATE__SIT_HEVC_DEC_MASK
6618da1170aSLeo Liu 		| UVD_SUVD_CGC_GATE__SIT_HEVC_ENC_MASK
6628da1170aSLeo Liu 		| UVD_SUVD_CGC_GATE__SITE_MASK
6638da1170aSLeo Liu 		| UVD_SUVD_CGC_GATE__SRE_VP9_MASK
6648da1170aSLeo Liu 		| UVD_SUVD_CGC_GATE__SCM_VP9_MASK
6658da1170aSLeo Liu 		| UVD_SUVD_CGC_GATE__SIT_VP9_DEC_MASK
6668da1170aSLeo Liu 		| UVD_SUVD_CGC_GATE__SDB_VP9_MASK
6678da1170aSLeo Liu 		| UVD_SUVD_CGC_GATE__IME_HEVC_MASK);
6688da1170aSLeo Liu 	WREG32_SOC15(VCN, inst, regUVD_SUVD_CGC_GATE, data);
6698da1170aSLeo Liu 
6708da1170aSLeo Liu 	data = RREG32_SOC15(VCN, inst, regUVD_SUVD_CGC_CTRL);
6718da1170aSLeo Liu 	data &= ~(UVD_SUVD_CGC_CTRL__SRE_MODE_MASK
6728da1170aSLeo Liu 		| UVD_SUVD_CGC_CTRL__SIT_MODE_MASK
6738da1170aSLeo Liu 		| UVD_SUVD_CGC_CTRL__SMP_MODE_MASK
6748da1170aSLeo Liu 		| UVD_SUVD_CGC_CTRL__SCM_MODE_MASK
6758da1170aSLeo Liu 		| UVD_SUVD_CGC_CTRL__SDB_MODE_MASK
6768da1170aSLeo Liu 		| UVD_SUVD_CGC_CTRL__SCLR_MODE_MASK
6778da1170aSLeo Liu 		| UVD_SUVD_CGC_CTRL__UVD_SC_MODE_MASK
6788da1170aSLeo Liu 		| UVD_SUVD_CGC_CTRL__ENT_MODE_MASK
6798da1170aSLeo Liu 		| UVD_SUVD_CGC_CTRL__IME_MODE_MASK
6808da1170aSLeo Liu 		| UVD_SUVD_CGC_CTRL__SITE_MODE_MASK);
6818da1170aSLeo Liu 	WREG32_SOC15(VCN, inst, regUVD_SUVD_CGC_CTRL, data);
6828da1170aSLeo Liu }
6838da1170aSLeo Liu 
6848da1170aSLeo Liu /**
6858da1170aSLeo Liu  * vcn_v4_0_disable_clock_gating_dpg_mode - disable VCN clock gating dpg mode
6868da1170aSLeo Liu  *
6878da1170aSLeo Liu  * @adev: amdgpu_device pointer
6888da1170aSLeo Liu  * @sram_sel: sram select
6898da1170aSLeo Liu  * @inst_idx: instance number index
6908da1170aSLeo Liu  * @indirect: indirectly write sram
6918da1170aSLeo Liu  *
6928da1170aSLeo Liu  * Disable clock gating for VCN block with dpg mode
6938da1170aSLeo Liu  */
6948da1170aSLeo Liu static void vcn_v4_0_disable_clock_gating_dpg_mode(struct amdgpu_device *adev, uint8_t sram_sel,
6958da1170aSLeo Liu       int inst_idx, uint8_t indirect)
6968da1170aSLeo Liu {
6978da1170aSLeo Liu 	uint32_t reg_data = 0;
6988da1170aSLeo Liu 
6998da1170aSLeo Liu 	if (adev->cg_flags & AMD_CG_SUPPORT_VCN_MGCG)
7008da1170aSLeo Liu 		return;
7018da1170aSLeo Liu 
7028da1170aSLeo Liu 	/* enable sw clock gating control */
7038da1170aSLeo Liu 	reg_data = 0 << UVD_CGC_CTRL__DYN_CLOCK_MODE__SHIFT;
7048da1170aSLeo Liu 	reg_data |= 1 << UVD_CGC_CTRL__CLK_GATE_DLY_TIMER__SHIFT;
7058da1170aSLeo Liu 	reg_data |= 4 << UVD_CGC_CTRL__CLK_OFF_DELAY__SHIFT;
7068da1170aSLeo Liu 	reg_data &= ~(UVD_CGC_CTRL__UDEC_RE_MODE_MASK |
7078da1170aSLeo Liu 		 UVD_CGC_CTRL__UDEC_CM_MODE_MASK |
7088da1170aSLeo Liu 		 UVD_CGC_CTRL__UDEC_IT_MODE_MASK |
7098da1170aSLeo Liu 		 UVD_CGC_CTRL__UDEC_DB_MODE_MASK |
7108da1170aSLeo Liu 		 UVD_CGC_CTRL__UDEC_MP_MODE_MASK |
7118da1170aSLeo Liu 		 UVD_CGC_CTRL__SYS_MODE_MASK |
7128da1170aSLeo Liu 		 UVD_CGC_CTRL__UDEC_MODE_MASK |
7138da1170aSLeo Liu 		 UVD_CGC_CTRL__MPEG2_MODE_MASK |
7148da1170aSLeo Liu 		 UVD_CGC_CTRL__REGS_MODE_MASK |
7158da1170aSLeo Liu 		 UVD_CGC_CTRL__RBC_MODE_MASK |
7168da1170aSLeo Liu 		 UVD_CGC_CTRL__LMI_MC_MODE_MASK |
7178da1170aSLeo Liu 		 UVD_CGC_CTRL__LMI_UMC_MODE_MASK |
7188da1170aSLeo Liu 		 UVD_CGC_CTRL__IDCT_MODE_MASK |
7198da1170aSLeo Liu 		 UVD_CGC_CTRL__MPRD_MODE_MASK |
7208da1170aSLeo Liu 		 UVD_CGC_CTRL__MPC_MODE_MASK |
7218da1170aSLeo Liu 		 UVD_CGC_CTRL__LBSI_MODE_MASK |
7228da1170aSLeo Liu 		 UVD_CGC_CTRL__LRBBM_MODE_MASK |
7238da1170aSLeo Liu 		 UVD_CGC_CTRL__WCB_MODE_MASK |
7248da1170aSLeo Liu 		 UVD_CGC_CTRL__VCPU_MODE_MASK);
7258da1170aSLeo Liu 	WREG32_SOC15_DPG_MODE(inst_idx, SOC15_DPG_MODE_OFFSET(
7268da1170aSLeo Liu 		VCN, inst_idx, regUVD_CGC_CTRL), reg_data, sram_sel, indirect);
7278da1170aSLeo Liu 
7288da1170aSLeo Liu 	/* turn off clock gating */
7298da1170aSLeo Liu 	WREG32_SOC15_DPG_MODE(inst_idx, SOC15_DPG_MODE_OFFSET(
7308da1170aSLeo Liu 		VCN, inst_idx, regUVD_CGC_GATE), 0, sram_sel, indirect);
7318da1170aSLeo Liu 
7328da1170aSLeo Liu 	/* turn on SUVD clock gating */
7338da1170aSLeo Liu 	WREG32_SOC15_DPG_MODE(inst_idx, SOC15_DPG_MODE_OFFSET(
7348da1170aSLeo Liu 		VCN, inst_idx, regUVD_SUVD_CGC_GATE), 1, sram_sel, indirect);
7358da1170aSLeo Liu 
7368da1170aSLeo Liu 	/* turn on sw mode in UVD_SUVD_CGC_CTRL */
7378da1170aSLeo Liu 	WREG32_SOC15_DPG_MODE(inst_idx, SOC15_DPG_MODE_OFFSET(
7388da1170aSLeo Liu 		VCN, inst_idx, regUVD_SUVD_CGC_CTRL), 0, sram_sel, indirect);
7398da1170aSLeo Liu }
7408da1170aSLeo Liu 
7418da1170aSLeo Liu /**
7428da1170aSLeo Liu  * vcn_v4_0_enable_clock_gating - enable VCN clock gating
7438da1170aSLeo Liu  *
7448da1170aSLeo Liu  * @adev: amdgpu_device pointer
7458da1170aSLeo Liu  * @inst: instance number
7468da1170aSLeo Liu  *
7478da1170aSLeo Liu  * Enable clock gating for VCN block
7488da1170aSLeo Liu  */
7498da1170aSLeo Liu static void vcn_v4_0_enable_clock_gating(struct amdgpu_device *adev, int inst)
7508da1170aSLeo Liu {
7518da1170aSLeo Liu 	uint32_t data;
7528da1170aSLeo Liu 
7538da1170aSLeo Liu 	if (adev->cg_flags & AMD_CG_SUPPORT_VCN_MGCG)
7548da1170aSLeo Liu 		return;
7558da1170aSLeo Liu 
7568da1170aSLeo Liu 	/* enable VCN CGC */
7578da1170aSLeo Liu 	data = RREG32_SOC15(VCN, inst, regUVD_CGC_CTRL);
7588da1170aSLeo Liu 	data |= 0 << UVD_CGC_CTRL__DYN_CLOCK_MODE__SHIFT;
7598da1170aSLeo Liu 	data |= 1 << UVD_CGC_CTRL__CLK_GATE_DLY_TIMER__SHIFT;
7608da1170aSLeo Liu 	data |= 4 << UVD_CGC_CTRL__CLK_OFF_DELAY__SHIFT;
7618da1170aSLeo Liu 	WREG32_SOC15(VCN, inst, regUVD_CGC_CTRL, data);
7628da1170aSLeo Liu 
7638da1170aSLeo Liu 	data = RREG32_SOC15(VCN, inst, regUVD_CGC_CTRL);
7648da1170aSLeo Liu 	data |= (UVD_CGC_CTRL__UDEC_RE_MODE_MASK
7658da1170aSLeo Liu 		| UVD_CGC_CTRL__UDEC_CM_MODE_MASK
7668da1170aSLeo Liu 		| UVD_CGC_CTRL__UDEC_IT_MODE_MASK
7678da1170aSLeo Liu 		| UVD_CGC_CTRL__UDEC_DB_MODE_MASK
7688da1170aSLeo Liu 		| UVD_CGC_CTRL__UDEC_MP_MODE_MASK
7698da1170aSLeo Liu 		| UVD_CGC_CTRL__SYS_MODE_MASK
7708da1170aSLeo Liu 		| UVD_CGC_CTRL__UDEC_MODE_MASK
7718da1170aSLeo Liu 		| UVD_CGC_CTRL__MPEG2_MODE_MASK
7728da1170aSLeo Liu 		| UVD_CGC_CTRL__REGS_MODE_MASK
7738da1170aSLeo Liu 		| UVD_CGC_CTRL__RBC_MODE_MASK
7748da1170aSLeo Liu 		| UVD_CGC_CTRL__LMI_MC_MODE_MASK
7758da1170aSLeo Liu 		| UVD_CGC_CTRL__LMI_UMC_MODE_MASK
7768da1170aSLeo Liu 		| UVD_CGC_CTRL__IDCT_MODE_MASK
7778da1170aSLeo Liu 		| UVD_CGC_CTRL__MPRD_MODE_MASK
7788da1170aSLeo Liu 		| UVD_CGC_CTRL__MPC_MODE_MASK
7798da1170aSLeo Liu 		| UVD_CGC_CTRL__LBSI_MODE_MASK
7808da1170aSLeo Liu 		| UVD_CGC_CTRL__LRBBM_MODE_MASK
7818da1170aSLeo Liu 		| UVD_CGC_CTRL__WCB_MODE_MASK
7828da1170aSLeo Liu 		| UVD_CGC_CTRL__VCPU_MODE_MASK
7838da1170aSLeo Liu 		| UVD_CGC_CTRL__MMSCH_MODE_MASK);
7848da1170aSLeo Liu 	WREG32_SOC15(VCN, inst, regUVD_CGC_CTRL, data);
7858da1170aSLeo Liu 
7868da1170aSLeo Liu 	data = RREG32_SOC15(VCN, inst, regUVD_SUVD_CGC_CTRL);
7878da1170aSLeo Liu 	data |= (UVD_SUVD_CGC_CTRL__SRE_MODE_MASK
7888da1170aSLeo Liu 		| UVD_SUVD_CGC_CTRL__SIT_MODE_MASK
7898da1170aSLeo Liu 		| UVD_SUVD_CGC_CTRL__SMP_MODE_MASK
7908da1170aSLeo Liu 		| UVD_SUVD_CGC_CTRL__SCM_MODE_MASK
7918da1170aSLeo Liu 		| UVD_SUVD_CGC_CTRL__SDB_MODE_MASK
7928da1170aSLeo Liu 		| UVD_SUVD_CGC_CTRL__SCLR_MODE_MASK
7938da1170aSLeo Liu 		| UVD_SUVD_CGC_CTRL__UVD_SC_MODE_MASK
7948da1170aSLeo Liu 		| UVD_SUVD_CGC_CTRL__ENT_MODE_MASK
7958da1170aSLeo Liu 		| UVD_SUVD_CGC_CTRL__IME_MODE_MASK
7968da1170aSLeo Liu 		| UVD_SUVD_CGC_CTRL__SITE_MODE_MASK);
7978da1170aSLeo Liu 	WREG32_SOC15(VCN, inst, regUVD_SUVD_CGC_CTRL, data);
7988da1170aSLeo Liu 
7998da1170aSLeo Liu 	return;
8008da1170aSLeo Liu }
8018da1170aSLeo Liu 
8028da1170aSLeo Liu /**
8038da1170aSLeo Liu  * vcn_v4_0_start_dpg_mode - VCN start with dpg mode
8048da1170aSLeo Liu  *
8058da1170aSLeo Liu  * @adev: amdgpu_device pointer
8068da1170aSLeo Liu  * @inst_idx: instance number index
8078da1170aSLeo Liu  * @indirect: indirectly write sram
8088da1170aSLeo Liu  *
8098da1170aSLeo Liu  * Start VCN block with dpg mode
8108da1170aSLeo Liu  */
8118da1170aSLeo Liu static int vcn_v4_0_start_dpg_mode(struct amdgpu_device *adev, int inst_idx, bool indirect)
8128da1170aSLeo Liu {
8138da1170aSLeo Liu 	volatile struct amdgpu_vcn4_fw_shared *fw_shared = adev->vcn.inst[inst_idx].fw_shared.cpu_addr;
8148da1170aSLeo Liu 	struct amdgpu_ring *ring;
8158da1170aSLeo Liu 	uint32_t tmp;
8168da1170aSLeo Liu 
8178da1170aSLeo Liu 	/* disable register anti-hang mechanism */
8188da1170aSLeo Liu 	WREG32_P(SOC15_REG_OFFSET(VCN, inst_idx, regUVD_POWER_STATUS), 1,
8198da1170aSLeo Liu 		~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
8208da1170aSLeo Liu 	/* enable dynamic power gating mode */
8218da1170aSLeo Liu 	tmp = RREG32_SOC15(VCN, inst_idx, regUVD_POWER_STATUS);
8228da1170aSLeo Liu 	tmp |= UVD_POWER_STATUS__UVD_PG_MODE_MASK;
8238da1170aSLeo Liu 	tmp |= UVD_POWER_STATUS__UVD_PG_EN_MASK;
8248da1170aSLeo Liu 	WREG32_SOC15(VCN, inst_idx, regUVD_POWER_STATUS, tmp);
8258da1170aSLeo Liu 
8268da1170aSLeo Liu 	if (indirect)
8278da1170aSLeo Liu 		adev->vcn.inst[inst_idx].dpg_sram_curr_addr = (uint32_t *)adev->vcn.inst[inst_idx].dpg_sram_cpu_addr;
8288da1170aSLeo Liu 
8298da1170aSLeo Liu 	/* enable clock gating */
8308da1170aSLeo Liu 	vcn_v4_0_disable_clock_gating_dpg_mode(adev, 0, inst_idx, indirect);
8318da1170aSLeo Liu 
8328da1170aSLeo Liu 	/* enable VCPU clock */
8338da1170aSLeo Liu 	tmp = (0xFF << UVD_VCPU_CNTL__PRB_TIMEOUT_VAL__SHIFT);
8348da1170aSLeo Liu 	tmp |= UVD_VCPU_CNTL__CLK_EN_MASK | UVD_VCPU_CNTL__BLK_RST_MASK;
8358da1170aSLeo Liu 	WREG32_SOC15_DPG_MODE(inst_idx, SOC15_DPG_MODE_OFFSET(
8368da1170aSLeo Liu 		VCN, inst_idx, regUVD_VCPU_CNTL), tmp, 0, indirect);
8378da1170aSLeo Liu 
8388da1170aSLeo Liu 	/* disable master interupt */
8398da1170aSLeo Liu 	WREG32_SOC15_DPG_MODE(inst_idx, SOC15_DPG_MODE_OFFSET(
8408da1170aSLeo Liu 		VCN, inst_idx, regUVD_MASTINT_EN), 0, 0, indirect);
8418da1170aSLeo Liu 
8428da1170aSLeo Liu 	/* setup regUVD_LMI_CTRL */
8438da1170aSLeo Liu 	tmp = (UVD_LMI_CTRL__WRITE_CLEAN_TIMER_EN_MASK |
8448da1170aSLeo Liu 		UVD_LMI_CTRL__REQ_MODE_MASK |
8458da1170aSLeo Liu 		UVD_LMI_CTRL__CRC_RESET_MASK |
8468da1170aSLeo Liu 		UVD_LMI_CTRL__MASK_MC_URGENT_MASK |
8478da1170aSLeo Liu 		UVD_LMI_CTRL__DATA_COHERENCY_EN_MASK |
8488da1170aSLeo Liu 		UVD_LMI_CTRL__VCPU_DATA_COHERENCY_EN_MASK |
8498da1170aSLeo Liu 		(8 << UVD_LMI_CTRL__WRITE_CLEAN_TIMER__SHIFT) |
8508da1170aSLeo Liu 		0x00100000L);
8518da1170aSLeo Liu 	WREG32_SOC15_DPG_MODE(inst_idx, SOC15_DPG_MODE_OFFSET(
8528da1170aSLeo Liu 		VCN, inst_idx, regUVD_LMI_CTRL), tmp, 0, indirect);
8538da1170aSLeo Liu 
8548da1170aSLeo Liu 	WREG32_SOC15_DPG_MODE(inst_idx, SOC15_DPG_MODE_OFFSET(
8558da1170aSLeo Liu 		VCN, inst_idx, regUVD_MPC_CNTL),
8568da1170aSLeo Liu 		0x2 << UVD_MPC_CNTL__REPLACEMENT_MODE__SHIFT, 0, indirect);
8578da1170aSLeo Liu 
8588da1170aSLeo Liu 	WREG32_SOC15_DPG_MODE(inst_idx, SOC15_DPG_MODE_OFFSET(
8598da1170aSLeo Liu 		VCN, inst_idx, regUVD_MPC_SET_MUXA0),
8608da1170aSLeo Liu 		((0x1 << UVD_MPC_SET_MUXA0__VARA_1__SHIFT) |
8618da1170aSLeo Liu 		 (0x2 << UVD_MPC_SET_MUXA0__VARA_2__SHIFT) |
8628da1170aSLeo Liu 		 (0x3 << UVD_MPC_SET_MUXA0__VARA_3__SHIFT) |
8638da1170aSLeo Liu 		 (0x4 << UVD_MPC_SET_MUXA0__VARA_4__SHIFT)), 0, indirect);
8648da1170aSLeo Liu 
8658da1170aSLeo Liu 	WREG32_SOC15_DPG_MODE(inst_idx, SOC15_DPG_MODE_OFFSET(
8668da1170aSLeo Liu 		VCN, inst_idx, regUVD_MPC_SET_MUXB0),
8678da1170aSLeo Liu 		 ((0x1 << UVD_MPC_SET_MUXB0__VARB_1__SHIFT) |
8688da1170aSLeo Liu 		 (0x2 << UVD_MPC_SET_MUXB0__VARB_2__SHIFT) |
8698da1170aSLeo Liu 		 (0x3 << UVD_MPC_SET_MUXB0__VARB_3__SHIFT) |
8708da1170aSLeo Liu 		 (0x4 << UVD_MPC_SET_MUXB0__VARB_4__SHIFT)), 0, indirect);
8718da1170aSLeo Liu 
8728da1170aSLeo Liu 	WREG32_SOC15_DPG_MODE(inst_idx, SOC15_DPG_MODE_OFFSET(
8738da1170aSLeo Liu 		VCN, inst_idx, regUVD_MPC_SET_MUX),
8748da1170aSLeo Liu 		((0x0 << UVD_MPC_SET_MUX__SET_0__SHIFT) |
8758da1170aSLeo Liu 		 (0x1 << UVD_MPC_SET_MUX__SET_1__SHIFT) |
8768da1170aSLeo Liu 		 (0x2 << UVD_MPC_SET_MUX__SET_2__SHIFT)), 0, indirect);
8778da1170aSLeo Liu 
8788da1170aSLeo Liu 	vcn_v4_0_mc_resume_dpg_mode(adev, inst_idx, indirect);
8798da1170aSLeo Liu 
8808da1170aSLeo Liu 	tmp = (0xFF << UVD_VCPU_CNTL__PRB_TIMEOUT_VAL__SHIFT);
8818da1170aSLeo Liu 	tmp |= UVD_VCPU_CNTL__CLK_EN_MASK;
8828da1170aSLeo Liu 	WREG32_SOC15_DPG_MODE(inst_idx, SOC15_DPG_MODE_OFFSET(
8838da1170aSLeo Liu 		VCN, inst_idx, regUVD_VCPU_CNTL), tmp, 0, indirect);
8848da1170aSLeo Liu 
8858da1170aSLeo Liu 	/* enable LMI MC and UMC channels */
8868da1170aSLeo Liu 	tmp = 0x1f << UVD_LMI_CTRL2__RE_OFLD_MIF_WR_REQ_NUM__SHIFT;
8878da1170aSLeo Liu 	WREG32_SOC15_DPG_MODE(inst_idx, SOC15_DPG_MODE_OFFSET(
8888da1170aSLeo Liu 		VCN, inst_idx, regUVD_LMI_CTRL2), tmp, 0, indirect);
8898da1170aSLeo Liu 
8908da1170aSLeo Liu 	/* enable master interrupt */
8918da1170aSLeo Liu 	WREG32_SOC15_DPG_MODE(inst_idx, SOC15_DPG_MODE_OFFSET(
8928da1170aSLeo Liu 		VCN, inst_idx, regUVD_MASTINT_EN),
8938da1170aSLeo Liu 		UVD_MASTINT_EN__VCPU_EN_MASK, 0, indirect);
8948da1170aSLeo Liu 
8958da1170aSLeo Liu 
8968da1170aSLeo Liu 	if (indirect)
8978da1170aSLeo Liu 		psp_update_vcn_sram(adev, inst_idx, adev->vcn.inst[inst_idx].dpg_sram_gpu_addr,
8988da1170aSLeo Liu 			(uint32_t)((uintptr_t)adev->vcn.inst[inst_idx].dpg_sram_curr_addr -
8998da1170aSLeo Liu 				(uintptr_t)adev->vcn.inst[inst_idx].dpg_sram_cpu_addr));
9008da1170aSLeo Liu 
9018da1170aSLeo Liu 	ring = &adev->vcn.inst[inst_idx].ring_enc[0];
9028da1170aSLeo Liu 
9038da1170aSLeo Liu 	WREG32_SOC15(VCN, inst_idx, regUVD_RB_BASE_LO, ring->gpu_addr);
9048da1170aSLeo Liu 	WREG32_SOC15(VCN, inst_idx, regUVD_RB_BASE_HI, upper_32_bits(ring->gpu_addr));
9058da1170aSLeo Liu 	WREG32_SOC15(VCN, inst_idx, regUVD_RB_SIZE, ring->ring_size / 4);
906bb4f196bSRuijing Dong 
907bb4f196bSRuijing Dong 	tmp = RREG32_SOC15(VCN, inst_idx, regVCN_RB_ENABLE);
908bb4f196bSRuijing Dong 	tmp &= ~(VCN_RB_ENABLE__RB1_EN_MASK);
909bb4f196bSRuijing Dong 	WREG32_SOC15(VCN, inst_idx, regVCN_RB_ENABLE, tmp);
910bb4f196bSRuijing Dong 	fw_shared->sq.queue_mode |= FW_QUEUE_RING_RESET;
911bb4f196bSRuijing Dong 	WREG32_SOC15(VCN, inst_idx, regUVD_RB_RPTR, 0);
912bb4f196bSRuijing Dong 	WREG32_SOC15(VCN, inst_idx, regUVD_RB_WPTR, 0);
913bb4f196bSRuijing Dong 
9148da1170aSLeo Liu 	tmp = RREG32_SOC15(VCN, inst_idx, regUVD_RB_RPTR);
9158da1170aSLeo Liu 	WREG32_SOC15(VCN, inst_idx, regUVD_RB_WPTR, tmp);
9168da1170aSLeo Liu 	ring->wptr = RREG32_SOC15(VCN, inst_idx, regUVD_RB_WPTR);
9178da1170aSLeo Liu 
918bb4f196bSRuijing Dong 	tmp = RREG32_SOC15(VCN, inst_idx, regVCN_RB_ENABLE);
919bb4f196bSRuijing Dong 	tmp |= VCN_RB_ENABLE__RB1_EN_MASK;
920bb4f196bSRuijing Dong 	WREG32_SOC15(VCN, inst_idx, regVCN_RB_ENABLE, tmp);
921bb4f196bSRuijing Dong 	fw_shared->sq.queue_mode &= ~(FW_QUEUE_RING_RESET | FW_QUEUE_DPG_HOLD_OFF);
922bb4f196bSRuijing Dong 
9238da1170aSLeo Liu 	WREG32_SOC15(VCN, inst_idx, regVCN_RB1_DB_CTRL,
9248da1170aSLeo Liu 			ring->doorbell_index << VCN_RB1_DB_CTRL__OFFSET__SHIFT |
9258da1170aSLeo Liu 			VCN_RB1_DB_CTRL__EN_MASK);
926bb4f196bSRuijing Dong 
9278da1170aSLeo Liu 	return 0;
9288da1170aSLeo Liu }
9298da1170aSLeo Liu 
9308da1170aSLeo Liu 
9318da1170aSLeo Liu /**
9328da1170aSLeo Liu  * vcn_v4_0_start - VCN start
9338da1170aSLeo Liu  *
9348da1170aSLeo Liu  * @adev: amdgpu_device pointer
9358da1170aSLeo Liu  *
9368da1170aSLeo Liu  * Start VCN block
9378da1170aSLeo Liu  */
9388da1170aSLeo Liu static int vcn_v4_0_start(struct amdgpu_device *adev)
9398da1170aSLeo Liu {
9408da1170aSLeo Liu 	volatile struct amdgpu_vcn4_fw_shared *fw_shared;
9418da1170aSLeo Liu 	struct amdgpu_ring *ring;
9428da1170aSLeo Liu 	uint32_t tmp;
9438da1170aSLeo Liu 	int i, j, k, r;
9448da1170aSLeo Liu 
9458da1170aSLeo Liu 	if (adev->pm.dpm_enabled)
9468da1170aSLeo Liu 		amdgpu_dpm_enable_uvd(adev, true);
9478da1170aSLeo Liu 
9488da1170aSLeo Liu 	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
949bb4f196bSRuijing Dong 		fw_shared = adev->vcn.inst[i].fw_shared.cpu_addr;
950bb4f196bSRuijing Dong 
9518da1170aSLeo Liu 		if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
9528da1170aSLeo Liu 			r = vcn_v4_0_start_dpg_mode(adev, i, adev->vcn.indirect_sram);
9538da1170aSLeo Liu 			continue;
9548da1170aSLeo Liu 		}
9558da1170aSLeo Liu 
9568da1170aSLeo Liu 		/* disable VCN power gating */
9578da1170aSLeo Liu 		vcn_v4_0_disable_static_power_gating(adev, i);
9588da1170aSLeo Liu 
9598da1170aSLeo Liu 		/* set VCN status busy */
9608da1170aSLeo Liu 		tmp = RREG32_SOC15(VCN, i, regUVD_STATUS) | UVD_STATUS__UVD_BUSY;
9618da1170aSLeo Liu 		WREG32_SOC15(VCN, i, regUVD_STATUS, tmp);
9628da1170aSLeo Liu 
9638da1170aSLeo Liu 		/*SW clock gating */
9648da1170aSLeo Liu 		vcn_v4_0_disable_clock_gating(adev, i);
9658da1170aSLeo Liu 
9668da1170aSLeo Liu 		/* enable VCPU clock */
9678da1170aSLeo Liu 		WREG32_P(SOC15_REG_OFFSET(VCN, i, regUVD_VCPU_CNTL),
9688da1170aSLeo Liu 				UVD_VCPU_CNTL__CLK_EN_MASK, ~UVD_VCPU_CNTL__CLK_EN_MASK);
9698da1170aSLeo Liu 
9708da1170aSLeo Liu 		/* disable master interrupt */
9718da1170aSLeo Liu 		WREG32_P(SOC15_REG_OFFSET(VCN, i, regUVD_MASTINT_EN), 0,
9728da1170aSLeo Liu 				~UVD_MASTINT_EN__VCPU_EN_MASK);
9738da1170aSLeo Liu 
9748da1170aSLeo Liu 		/* enable LMI MC and UMC channels */
9758da1170aSLeo Liu 		WREG32_P(SOC15_REG_OFFSET(VCN, i, regUVD_LMI_CTRL2), 0,
9768da1170aSLeo Liu 				~UVD_LMI_CTRL2__STALL_ARB_UMC_MASK);
9778da1170aSLeo Liu 
9788da1170aSLeo Liu 		tmp = RREG32_SOC15(VCN, i, regUVD_SOFT_RESET);
9798da1170aSLeo Liu 		tmp &= ~UVD_SOFT_RESET__LMI_SOFT_RESET_MASK;
9808da1170aSLeo Liu 		tmp &= ~UVD_SOFT_RESET__LMI_UMC_SOFT_RESET_MASK;
9818da1170aSLeo Liu 		WREG32_SOC15(VCN, i, regUVD_SOFT_RESET, tmp);
9828da1170aSLeo Liu 
9838da1170aSLeo Liu 		/* setup regUVD_LMI_CTRL */
9848da1170aSLeo Liu 		tmp = RREG32_SOC15(VCN, i, regUVD_LMI_CTRL);
9858da1170aSLeo Liu 		WREG32_SOC15(VCN, i, regUVD_LMI_CTRL, tmp |
9868da1170aSLeo Liu 				UVD_LMI_CTRL__WRITE_CLEAN_TIMER_EN_MASK |
9878da1170aSLeo Liu 				UVD_LMI_CTRL__MASK_MC_URGENT_MASK |
9888da1170aSLeo Liu 				UVD_LMI_CTRL__DATA_COHERENCY_EN_MASK |
9898da1170aSLeo Liu 				UVD_LMI_CTRL__VCPU_DATA_COHERENCY_EN_MASK);
9908da1170aSLeo Liu 
9918da1170aSLeo Liu 		/* setup regUVD_MPC_CNTL */
9928da1170aSLeo Liu 		tmp = RREG32_SOC15(VCN, i, regUVD_MPC_CNTL);
9938da1170aSLeo Liu 		tmp &= ~UVD_MPC_CNTL__REPLACEMENT_MODE_MASK;
9948da1170aSLeo Liu 		tmp |= 0x2 << UVD_MPC_CNTL__REPLACEMENT_MODE__SHIFT;
9958da1170aSLeo Liu 		WREG32_SOC15(VCN, i, regUVD_MPC_CNTL, tmp);
9968da1170aSLeo Liu 
9978da1170aSLeo Liu 		/* setup UVD_MPC_SET_MUXA0 */
9988da1170aSLeo Liu 		WREG32_SOC15(VCN, i, regUVD_MPC_SET_MUXA0,
9998da1170aSLeo Liu 				((0x1 << UVD_MPC_SET_MUXA0__VARA_1__SHIFT) |
10008da1170aSLeo Liu 				 (0x2 << UVD_MPC_SET_MUXA0__VARA_2__SHIFT) |
10018da1170aSLeo Liu 				 (0x3 << UVD_MPC_SET_MUXA0__VARA_3__SHIFT) |
10028da1170aSLeo Liu 				 (0x4 << UVD_MPC_SET_MUXA0__VARA_4__SHIFT)));
10038da1170aSLeo Liu 
10048da1170aSLeo Liu 		/* setup UVD_MPC_SET_MUXB0 */
10058da1170aSLeo Liu 		WREG32_SOC15(VCN, i, regUVD_MPC_SET_MUXB0,
10068da1170aSLeo Liu 				((0x1 << UVD_MPC_SET_MUXB0__VARB_1__SHIFT) |
10078da1170aSLeo Liu 				 (0x2 << UVD_MPC_SET_MUXB0__VARB_2__SHIFT) |
10088da1170aSLeo Liu 				 (0x3 << UVD_MPC_SET_MUXB0__VARB_3__SHIFT) |
10098da1170aSLeo Liu 				 (0x4 << UVD_MPC_SET_MUXB0__VARB_4__SHIFT)));
10108da1170aSLeo Liu 
10118da1170aSLeo Liu 		/* setup UVD_MPC_SET_MUX */
10128da1170aSLeo Liu 		WREG32_SOC15(VCN, i, regUVD_MPC_SET_MUX,
10138da1170aSLeo Liu 				((0x0 << UVD_MPC_SET_MUX__SET_0__SHIFT) |
10148da1170aSLeo Liu 				 (0x1 << UVD_MPC_SET_MUX__SET_1__SHIFT) |
10158da1170aSLeo Liu 				 (0x2 << UVD_MPC_SET_MUX__SET_2__SHIFT)));
10168da1170aSLeo Liu 
10178da1170aSLeo Liu 		vcn_v4_0_mc_resume(adev, i);
10188da1170aSLeo Liu 
10198da1170aSLeo Liu 		/* VCN global tiling registers */
10208da1170aSLeo Liu 		WREG32_SOC15(VCN, i, regUVD_GFX10_ADDR_CONFIG,
10218da1170aSLeo Liu 				adev->gfx.config.gb_addr_config);
10228da1170aSLeo Liu 
10238da1170aSLeo Liu 		/* unblock VCPU register access */
10248da1170aSLeo Liu 		WREG32_P(SOC15_REG_OFFSET(VCN, i, regUVD_RB_ARB_CTRL), 0,
10258da1170aSLeo Liu 				~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
10268da1170aSLeo Liu 
10278da1170aSLeo Liu 		/* release VCPU reset to boot */
10288da1170aSLeo Liu 		WREG32_P(SOC15_REG_OFFSET(VCN, i, regUVD_VCPU_CNTL), 0,
10298da1170aSLeo Liu 				~UVD_VCPU_CNTL__BLK_RST_MASK);
10308da1170aSLeo Liu 
10318da1170aSLeo Liu 		for (j = 0; j < 10; ++j) {
10328da1170aSLeo Liu 			uint32_t status;
10338da1170aSLeo Liu 
10348da1170aSLeo Liu 			for (k = 0; k < 100; ++k) {
10358da1170aSLeo Liu 				status = RREG32_SOC15(VCN, i, regUVD_STATUS);
10368da1170aSLeo Liu 				if (status & 2)
10378da1170aSLeo Liu 					break;
10388da1170aSLeo Liu 				mdelay(10);
10398da1170aSLeo Liu 				if (amdgpu_emu_mode==1)
10408da1170aSLeo Liu 					msleep(1);
10418da1170aSLeo Liu 			}
10428da1170aSLeo Liu 
10438da1170aSLeo Liu 			if (amdgpu_emu_mode==1) {
1044*736f7308SSonny Jiang 				r = -1;
10458da1170aSLeo Liu 				if (status & 2) {
10468da1170aSLeo Liu 					r = 0;
10478da1170aSLeo Liu 					break;
10488da1170aSLeo Liu 				}
10498da1170aSLeo Liu 			} else {
10508da1170aSLeo Liu 				r = 0;
10518da1170aSLeo Liu 				if (status & 2)
10528da1170aSLeo Liu 					break;
10538da1170aSLeo Liu 
1054bb4f196bSRuijing Dong 				dev_err(adev->dev, "VCN[%d] is not responding, trying to reset the VCPU!!!\n", i);
10558da1170aSLeo Liu 				WREG32_P(SOC15_REG_OFFSET(VCN, i, regUVD_VCPU_CNTL),
10568da1170aSLeo Liu 							UVD_VCPU_CNTL__BLK_RST_MASK,
10578da1170aSLeo Liu 							~UVD_VCPU_CNTL__BLK_RST_MASK);
10588da1170aSLeo Liu 				mdelay(10);
10598da1170aSLeo Liu 				WREG32_P(SOC15_REG_OFFSET(VCN, i, regUVD_VCPU_CNTL), 0,
10608da1170aSLeo Liu 						~UVD_VCPU_CNTL__BLK_RST_MASK);
10618da1170aSLeo Liu 
10628da1170aSLeo Liu 				mdelay(10);
10638da1170aSLeo Liu 				r = -1;
10648da1170aSLeo Liu 			}
10658da1170aSLeo Liu 		}
10668da1170aSLeo Liu 
10678da1170aSLeo Liu 		if (r) {
1068bb4f196bSRuijing Dong 			dev_err(adev->dev, "VCN[%d] is not responding, giving up!!!\n", i);
10698da1170aSLeo Liu 			return r;
10708da1170aSLeo Liu 		}
10718da1170aSLeo Liu 
10728da1170aSLeo Liu 		/* enable master interrupt */
10738da1170aSLeo Liu 		WREG32_P(SOC15_REG_OFFSET(VCN, i, regUVD_MASTINT_EN),
10748da1170aSLeo Liu 				UVD_MASTINT_EN__VCPU_EN_MASK,
10758da1170aSLeo Liu 				~UVD_MASTINT_EN__VCPU_EN_MASK);
10768da1170aSLeo Liu 
10778da1170aSLeo Liu 		/* clear the busy bit of VCN_STATUS */
10788da1170aSLeo Liu 		WREG32_P(SOC15_REG_OFFSET(VCN, i, regUVD_STATUS), 0,
10798da1170aSLeo Liu 				~(2 << UVD_STATUS__VCPU_REPORT__SHIFT));
10808da1170aSLeo Liu 
10818da1170aSLeo Liu 		ring = &adev->vcn.inst[i].ring_enc[0];
10828da1170aSLeo Liu 		WREG32_SOC15(VCN, i, regVCN_RB1_DB_CTRL,
10838da1170aSLeo Liu 				ring->doorbell_index << VCN_RB1_DB_CTRL__OFFSET__SHIFT |
10848da1170aSLeo Liu 				VCN_RB1_DB_CTRL__EN_MASK);
1085bb4f196bSRuijing Dong 
10868da1170aSLeo Liu 		WREG32_SOC15(VCN, i, regUVD_RB_BASE_LO, ring->gpu_addr);
10878da1170aSLeo Liu 		WREG32_SOC15(VCN, i, regUVD_RB_BASE_HI, upper_32_bits(ring->gpu_addr));
10888da1170aSLeo Liu 		WREG32_SOC15(VCN, i, regUVD_RB_SIZE, ring->ring_size / 4);
1089bb4f196bSRuijing Dong 
1090bb4f196bSRuijing Dong 		tmp = RREG32_SOC15(VCN, i, regVCN_RB_ENABLE);
1091bb4f196bSRuijing Dong 		tmp &= ~(VCN_RB_ENABLE__RB1_EN_MASK);
1092bb4f196bSRuijing Dong 		WREG32_SOC15(VCN, i, regVCN_RB_ENABLE, tmp);
1093bb4f196bSRuijing Dong 		fw_shared->sq.queue_mode |= FW_QUEUE_RING_RESET;
1094bb4f196bSRuijing Dong 		WREG32_SOC15(VCN, i, regUVD_RB_RPTR, 0);
1095bb4f196bSRuijing Dong 		WREG32_SOC15(VCN, i, regUVD_RB_WPTR, 0);
1096bb4f196bSRuijing Dong 
1097bb4f196bSRuijing Dong 		tmp = RREG32_SOC15(VCN, i, regUVD_RB_RPTR);
1098bb4f196bSRuijing Dong 		WREG32_SOC15(VCN, i, regUVD_RB_WPTR, tmp);
1099bb4f196bSRuijing Dong 		ring->wptr = RREG32_SOC15(VCN, i, regUVD_RB_WPTR);
1100bb4f196bSRuijing Dong 
1101bb4f196bSRuijing Dong 		tmp = RREG32_SOC15(VCN, i, regVCN_RB_ENABLE);
1102bb4f196bSRuijing Dong 		tmp |= VCN_RB_ENABLE__RB1_EN_MASK;
1103bb4f196bSRuijing Dong 		WREG32_SOC15(VCN, i, regVCN_RB_ENABLE, tmp);
11048da1170aSLeo Liu 		fw_shared->sq.queue_mode &= ~(FW_QUEUE_RING_RESET | FW_QUEUE_DPG_HOLD_OFF);
11058da1170aSLeo Liu 	}
11068da1170aSLeo Liu 
11078da1170aSLeo Liu 	return 0;
11088da1170aSLeo Liu }
11098da1170aSLeo Liu 
11108da1170aSLeo Liu /**
11118da1170aSLeo Liu  * vcn_v4_0_stop_dpg_mode - VCN stop with dpg mode
11128da1170aSLeo Liu  *
11138da1170aSLeo Liu  * @adev: amdgpu_device pointer
11148da1170aSLeo Liu  * @inst_idx: instance number index
11158da1170aSLeo Liu  *
11168da1170aSLeo Liu  * Stop VCN block with dpg mode
11178da1170aSLeo Liu  */
11188da1170aSLeo Liu static int vcn_v4_0_stop_dpg_mode(struct amdgpu_device *adev, int inst_idx)
11198da1170aSLeo Liu {
11208da1170aSLeo Liu 	uint32_t tmp;
11218da1170aSLeo Liu 
11228da1170aSLeo Liu 	/* Wait for power status to be 1 */
11238da1170aSLeo Liu 	SOC15_WAIT_ON_RREG(VCN, inst_idx, regUVD_POWER_STATUS, 1,
11248da1170aSLeo Liu 		UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
11258da1170aSLeo Liu 
11268da1170aSLeo Liu 	/* wait for read ptr to be equal to write ptr */
11278da1170aSLeo Liu 	tmp = RREG32_SOC15(VCN, inst_idx, regUVD_RB_WPTR);
11288da1170aSLeo Liu 	SOC15_WAIT_ON_RREG(VCN, inst_idx, regUVD_RB_RPTR, tmp, 0xFFFFFFFF);
11298da1170aSLeo Liu 
11308da1170aSLeo Liu 	SOC15_WAIT_ON_RREG(VCN, inst_idx, regUVD_POWER_STATUS, 1,
11318da1170aSLeo Liu 		UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
11328da1170aSLeo Liu 
11338da1170aSLeo Liu 	/* disable dynamic power gating mode */
11348da1170aSLeo Liu 	WREG32_P(SOC15_REG_OFFSET(VCN, inst_idx, regUVD_POWER_STATUS), 0,
11358da1170aSLeo Liu 		~UVD_POWER_STATUS__UVD_PG_MODE_MASK);
11368da1170aSLeo Liu 	return 0;
11378da1170aSLeo Liu }
11388da1170aSLeo Liu 
11398da1170aSLeo Liu /**
11408da1170aSLeo Liu  * vcn_v4_0_stop - VCN stop
11418da1170aSLeo Liu  *
11428da1170aSLeo Liu  * @adev: amdgpu_device pointer
11438da1170aSLeo Liu  *
11448da1170aSLeo Liu  * Stop VCN block
11458da1170aSLeo Liu  */
11468da1170aSLeo Liu static int vcn_v4_0_stop(struct amdgpu_device *adev)
11478da1170aSLeo Liu {
1148bb4f196bSRuijing Dong 	volatile struct amdgpu_vcn4_fw_shared *fw_shared;
11498da1170aSLeo Liu 	uint32_t tmp;
11508da1170aSLeo Liu 	int i, r = 0;
11518da1170aSLeo Liu 
11528da1170aSLeo Liu 	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
1153bb4f196bSRuijing Dong 		fw_shared = adev->vcn.inst[i].fw_shared.cpu_addr;
1154bb4f196bSRuijing Dong 		fw_shared->sq.queue_mode |= FW_QUEUE_DPG_HOLD_OFF;
1155bb4f196bSRuijing Dong 
11568da1170aSLeo Liu 		if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
11578da1170aSLeo Liu 			r = vcn_v4_0_stop_dpg_mode(adev, i);
11588da1170aSLeo Liu 			continue;
11598da1170aSLeo Liu 		}
11608da1170aSLeo Liu 
11618da1170aSLeo Liu 		/* wait for vcn idle */
11628da1170aSLeo Liu 		r = SOC15_WAIT_ON_RREG(VCN, i, regUVD_STATUS, UVD_STATUS__IDLE, 0x7);
11638da1170aSLeo Liu 		if (r)
11648da1170aSLeo Liu 			return r;
11658da1170aSLeo Liu 
11668da1170aSLeo Liu 		tmp = UVD_LMI_STATUS__VCPU_LMI_WRITE_CLEAN_MASK |
11678da1170aSLeo Liu 			UVD_LMI_STATUS__READ_CLEAN_MASK |
11688da1170aSLeo Liu 			UVD_LMI_STATUS__WRITE_CLEAN_MASK |
11698da1170aSLeo Liu 			UVD_LMI_STATUS__WRITE_CLEAN_RAW_MASK;
11708da1170aSLeo Liu 		r = SOC15_WAIT_ON_RREG(VCN, i, regUVD_LMI_STATUS, tmp, tmp);
11718da1170aSLeo Liu 		if (r)
11728da1170aSLeo Liu 			return r;
11738da1170aSLeo Liu 
11748da1170aSLeo Liu 		/* disable LMI UMC channel */
11758da1170aSLeo Liu 		tmp = RREG32_SOC15(VCN, i, regUVD_LMI_CTRL2);
11768da1170aSLeo Liu 		tmp |= UVD_LMI_CTRL2__STALL_ARB_UMC_MASK;
11778da1170aSLeo Liu 		WREG32_SOC15(VCN, i, regUVD_LMI_CTRL2, tmp);
11788da1170aSLeo Liu 		tmp = UVD_LMI_STATUS__UMC_READ_CLEAN_RAW_MASK |
11798da1170aSLeo Liu 			UVD_LMI_STATUS__UMC_WRITE_CLEAN_RAW_MASK;
11808da1170aSLeo Liu 		r = SOC15_WAIT_ON_RREG(VCN, i, regUVD_LMI_STATUS, tmp, tmp);
11818da1170aSLeo Liu 		if (r)
11828da1170aSLeo Liu 			return r;
11838da1170aSLeo Liu 
11848da1170aSLeo Liu 		/* block VCPU register access */
11858da1170aSLeo Liu 		WREG32_P(SOC15_REG_OFFSET(VCN, i, regUVD_RB_ARB_CTRL),
11868da1170aSLeo Liu 				UVD_RB_ARB_CTRL__VCPU_DIS_MASK,
11878da1170aSLeo Liu 				~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
11888da1170aSLeo Liu 
11898da1170aSLeo Liu 		/* reset VCPU */
11908da1170aSLeo Liu 		WREG32_P(SOC15_REG_OFFSET(VCN, i, regUVD_VCPU_CNTL),
11918da1170aSLeo Liu 				UVD_VCPU_CNTL__BLK_RST_MASK,
11928da1170aSLeo Liu 				~UVD_VCPU_CNTL__BLK_RST_MASK);
11938da1170aSLeo Liu 
11948da1170aSLeo Liu 		/* disable VCPU clock */
11958da1170aSLeo Liu 		WREG32_P(SOC15_REG_OFFSET(VCN, i, regUVD_VCPU_CNTL), 0,
11968da1170aSLeo Liu 				~(UVD_VCPU_CNTL__CLK_EN_MASK));
11978da1170aSLeo Liu 
11988da1170aSLeo Liu 		/* apply soft reset */
11998da1170aSLeo Liu 		tmp = RREG32_SOC15(VCN, i, regUVD_SOFT_RESET);
12008da1170aSLeo Liu 		tmp |= UVD_SOFT_RESET__LMI_UMC_SOFT_RESET_MASK;
12018da1170aSLeo Liu 		WREG32_SOC15(VCN, i, regUVD_SOFT_RESET, tmp);
12028da1170aSLeo Liu 		tmp = RREG32_SOC15(VCN, i, regUVD_SOFT_RESET);
12038da1170aSLeo Liu 		tmp |= UVD_SOFT_RESET__LMI_SOFT_RESET_MASK;
12048da1170aSLeo Liu 		WREG32_SOC15(VCN, i, regUVD_SOFT_RESET, tmp);
12058da1170aSLeo Liu 
12068da1170aSLeo Liu 		/* clear status */
12078da1170aSLeo Liu 		WREG32_SOC15(VCN, i, regUVD_STATUS, 0);
12088da1170aSLeo Liu 
12098da1170aSLeo Liu 		/* apply HW clock gating */
12108da1170aSLeo Liu 		vcn_v4_0_enable_clock_gating(adev, i);
12118da1170aSLeo Liu 
12128da1170aSLeo Liu 		/* enable VCN power gating */
12138da1170aSLeo Liu 		vcn_v4_0_enable_static_power_gating(adev, i);
12148da1170aSLeo Liu 	}
12158da1170aSLeo Liu 
12168da1170aSLeo Liu 	if (adev->pm.dpm_enabled)
12178da1170aSLeo Liu 		amdgpu_dpm_enable_uvd(adev, false);
12188da1170aSLeo Liu 
12198da1170aSLeo Liu 	return 0;
12208da1170aSLeo Liu }
12218da1170aSLeo Liu 
12228da1170aSLeo Liu /**
12238da1170aSLeo Liu  * vcn_v4_0_pause_dpg_mode - VCN pause with dpg mode
12248da1170aSLeo Liu  *
12258da1170aSLeo Liu  * @adev: amdgpu_device pointer
12268da1170aSLeo Liu  * @inst_idx: instance number index
12278da1170aSLeo Liu  * @new_state: pause state
12288da1170aSLeo Liu  *
12298da1170aSLeo Liu  * Pause dpg mode for VCN block
12308da1170aSLeo Liu  */
12318da1170aSLeo Liu static int vcn_v4_0_pause_dpg_mode(struct amdgpu_device *adev, int inst_idx,
12328da1170aSLeo Liu       struct dpg_pause_state *new_state)
12338da1170aSLeo Liu {
12348da1170aSLeo Liu 	uint32_t reg_data = 0;
12358da1170aSLeo Liu 	int ret_code;
12368da1170aSLeo Liu 
12378da1170aSLeo Liu 	/* pause/unpause if state is changed */
12388da1170aSLeo Liu 	if (adev->vcn.inst[inst_idx].pause_state.fw_based != new_state->fw_based) {
12398da1170aSLeo Liu 		DRM_DEV_DEBUG(adev->dev, "dpg pause state changed %d -> %d",
12408da1170aSLeo Liu 			adev->vcn.inst[inst_idx].pause_state.fw_based,	new_state->fw_based);
12418da1170aSLeo Liu 		reg_data = RREG32_SOC15(VCN, inst_idx, regUVD_DPG_PAUSE) &
12428da1170aSLeo Liu 			(~UVD_DPG_PAUSE__NJ_PAUSE_DPG_ACK_MASK);
12438da1170aSLeo Liu 
12448da1170aSLeo Liu 		if (new_state->fw_based == VCN_DPG_STATE__PAUSE) {
12458da1170aSLeo Liu 			ret_code = SOC15_WAIT_ON_RREG(VCN, inst_idx, regUVD_POWER_STATUS, 0x1,
12468da1170aSLeo Liu 				UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
12478da1170aSLeo Liu 
12488da1170aSLeo Liu 			if (!ret_code) {
12498da1170aSLeo Liu 				/* pause DPG */
12508da1170aSLeo Liu 				reg_data |= UVD_DPG_PAUSE__NJ_PAUSE_DPG_REQ_MASK;
12518da1170aSLeo Liu 				WREG32_SOC15(VCN, inst_idx, regUVD_DPG_PAUSE, reg_data);
12528da1170aSLeo Liu 
12538da1170aSLeo Liu 				/* wait for ACK */
12548da1170aSLeo Liu 				SOC15_WAIT_ON_RREG(VCN, inst_idx, regUVD_DPG_PAUSE,
12558da1170aSLeo Liu 					UVD_DPG_PAUSE__NJ_PAUSE_DPG_ACK_MASK,
12568da1170aSLeo Liu 					UVD_DPG_PAUSE__NJ_PAUSE_DPG_ACK_MASK);
12578da1170aSLeo Liu 
12588da1170aSLeo Liu 				SOC15_WAIT_ON_RREG(VCN, inst_idx, regUVD_POWER_STATUS,
12598da1170aSLeo Liu 					UVD_PGFSM_CONFIG__UVDM_UVDU_PWR_ON, UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
12608da1170aSLeo Liu 			}
12618da1170aSLeo Liu 		} else {
12628da1170aSLeo Liu 			/* unpause dpg, no need to wait */
12638da1170aSLeo Liu 			reg_data &= ~UVD_DPG_PAUSE__NJ_PAUSE_DPG_REQ_MASK;
12648da1170aSLeo Liu 			WREG32_SOC15(VCN, inst_idx, regUVD_DPG_PAUSE, reg_data);
12658da1170aSLeo Liu 		}
12668da1170aSLeo Liu 		adev->vcn.inst[inst_idx].pause_state.fw_based = new_state->fw_based;
12678da1170aSLeo Liu 	}
12688da1170aSLeo Liu 
12698da1170aSLeo Liu 	return 0;
12708da1170aSLeo Liu }
12718da1170aSLeo Liu 
12728da1170aSLeo Liu /**
1273bb4f196bSRuijing Dong  * vcn_v4_0_unified_ring_get_rptr - get unified read pointer
12748da1170aSLeo Liu  *
12758da1170aSLeo Liu  * @ring: amdgpu_ring pointer
12768da1170aSLeo Liu  *
1277bb4f196bSRuijing Dong  * Returns the current hardware unified read pointer
12788da1170aSLeo Liu  */
1279bb4f196bSRuijing Dong static uint64_t vcn_v4_0_unified_ring_get_rptr(struct amdgpu_ring *ring)
12808da1170aSLeo Liu {
12818da1170aSLeo Liu 	struct amdgpu_device *adev = ring->adev;
12828da1170aSLeo Liu 
1283bb4f196bSRuijing Dong 	if (ring != &adev->vcn.inst[ring->me].ring_enc[0])
1284bb4f196bSRuijing Dong 		DRM_ERROR("wrong ring id is identified in %s", __func__);
12858da1170aSLeo Liu 
12868da1170aSLeo Liu 	return RREG32_SOC15(VCN, ring->me, regUVD_RB_RPTR);
12878da1170aSLeo Liu }
12888da1170aSLeo Liu 
12898da1170aSLeo Liu /**
1290bb4f196bSRuijing Dong  * vcn_v4_0_unified_ring_get_wptr - get unified write pointer
12918da1170aSLeo Liu  *
12928da1170aSLeo Liu  * @ring: amdgpu_ring pointer
12938da1170aSLeo Liu  *
1294bb4f196bSRuijing Dong  * Returns the current hardware unified write pointer
12958da1170aSLeo Liu  */
1296bb4f196bSRuijing Dong static uint64_t vcn_v4_0_unified_ring_get_wptr(struct amdgpu_ring *ring)
12978da1170aSLeo Liu {
12988da1170aSLeo Liu 	struct amdgpu_device *adev = ring->adev;
12998da1170aSLeo Liu 
1300bb4f196bSRuijing Dong 	if (ring != &adev->vcn.inst[ring->me].ring_enc[0])
1301bb4f196bSRuijing Dong 		DRM_ERROR("wrong ring id is identified in %s", __func__);
1302bb4f196bSRuijing Dong 
13038da1170aSLeo Liu 	if (ring->use_doorbell)
13048da1170aSLeo Liu 		return *ring->wptr_cpu_addr;
13058da1170aSLeo Liu 	else
13068da1170aSLeo Liu 		return RREG32_SOC15(VCN, ring->me, regUVD_RB_WPTR);
13078da1170aSLeo Liu }
13088da1170aSLeo Liu 
13098da1170aSLeo Liu /**
1310bb4f196bSRuijing Dong  * vcn_v4_0_unified_ring_set_wptr - set enc write pointer
13118da1170aSLeo Liu  *
13128da1170aSLeo Liu  * @ring: amdgpu_ring pointer
13138da1170aSLeo Liu  *
13148da1170aSLeo Liu  * Commits the enc write pointer to the hardware
13158da1170aSLeo Liu  */
1316bb4f196bSRuijing Dong static void vcn_v4_0_unified_ring_set_wptr(struct amdgpu_ring *ring)
13178da1170aSLeo Liu {
13188da1170aSLeo Liu 	struct amdgpu_device *adev = ring->adev;
13198da1170aSLeo Liu 
1320bb4f196bSRuijing Dong 	if (ring != &adev->vcn.inst[ring->me].ring_enc[0])
1321bb4f196bSRuijing Dong 		DRM_ERROR("wrong ring id is identified in %s", __func__);
1322bb4f196bSRuijing Dong 
13238da1170aSLeo Liu 	if (ring->use_doorbell) {
13248da1170aSLeo Liu 		*ring->wptr_cpu_addr = lower_32_bits(ring->wptr);
13258da1170aSLeo Liu 		WDOORBELL32(ring->doorbell_index, lower_32_bits(ring->wptr));
13268da1170aSLeo Liu 	} else {
13278da1170aSLeo Liu 		WREG32_SOC15(VCN, ring->me, regUVD_RB_WPTR, lower_32_bits(ring->wptr));
13288da1170aSLeo Liu 	}
13298da1170aSLeo Liu }
13308da1170aSLeo Liu 
13310b15205cSSonny Jiang static int vcn_v4_0_limit_sched(struct amdgpu_cs_parser *p)
13320b15205cSSonny Jiang {
13330b15205cSSonny Jiang 	struct drm_gpu_scheduler **scheds;
13340b15205cSSonny Jiang 
13350b15205cSSonny Jiang 	/* The create msg must be in the first IB submitted */
13360b15205cSSonny Jiang 	if (atomic_read(&p->entity->fence_seq))
13370b15205cSSonny Jiang 		return -EINVAL;
13380b15205cSSonny Jiang 
13390b15205cSSonny Jiang 	scheds = p->adev->gpu_sched[AMDGPU_HW_IP_VCN_ENC]
13400b15205cSSonny Jiang 		[AMDGPU_RING_PRIO_0].sched;
13410b15205cSSonny Jiang 	drm_sched_entity_modify_sched(p->entity, scheds, 1);
13420b15205cSSonny Jiang 	return 0;
13430b15205cSSonny Jiang }
13440b15205cSSonny Jiang 
13450b15205cSSonny Jiang static int vcn_v4_0_dec_msg(struct amdgpu_cs_parser *p, uint64_t addr)
13460b15205cSSonny Jiang {
13470b15205cSSonny Jiang 	struct ttm_operation_ctx ctx = { false, false };
13480b15205cSSonny Jiang 	struct amdgpu_bo_va_mapping *map;
13490b15205cSSonny Jiang 	uint32_t *msg, num_buffers;
13500b15205cSSonny Jiang 	struct amdgpu_bo *bo;
13510b15205cSSonny Jiang 	uint64_t start, end;
13520b15205cSSonny Jiang 	unsigned int i;
13530b15205cSSonny Jiang 	void *ptr;
13540b15205cSSonny Jiang 	int r;
13550b15205cSSonny Jiang 
13560b15205cSSonny Jiang 	addr &= AMDGPU_GMC_HOLE_MASK;
13570b15205cSSonny Jiang 	r = amdgpu_cs_find_mapping(p, addr, &bo, &map);
13580b15205cSSonny Jiang 	if (r) {
13590b15205cSSonny Jiang 		DRM_ERROR("Can't find BO for addr 0x%08llx\n", addr);
13600b15205cSSonny Jiang 		return r;
13610b15205cSSonny Jiang 	}
13620b15205cSSonny Jiang 
13630b15205cSSonny Jiang 	start = map->start * AMDGPU_GPU_PAGE_SIZE;
13640b15205cSSonny Jiang 	end = (map->last + 1) * AMDGPU_GPU_PAGE_SIZE;
13650b15205cSSonny Jiang 	if (addr & 0x7) {
13660b15205cSSonny Jiang 		DRM_ERROR("VCN messages must be 8 byte aligned!\n");
13670b15205cSSonny Jiang 		return -EINVAL;
13680b15205cSSonny Jiang 	}
13690b15205cSSonny Jiang 
13700b15205cSSonny Jiang 	bo->flags |= AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED;
13710b15205cSSonny Jiang 	amdgpu_bo_placement_from_domain(bo, bo->allowed_domains);
13720b15205cSSonny Jiang 	r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx);
13730b15205cSSonny Jiang 	if (r) {
13740b15205cSSonny Jiang 		DRM_ERROR("Failed validating the VCN message BO (%d)!\n", r);
13750b15205cSSonny Jiang 		return r;
13760b15205cSSonny Jiang 	}
13770b15205cSSonny Jiang 
13780b15205cSSonny Jiang 	r = amdgpu_bo_kmap(bo, &ptr);
13790b15205cSSonny Jiang 	if (r) {
13800b15205cSSonny Jiang 		DRM_ERROR("Failed mapping the VCN message (%d)!\n", r);
13810b15205cSSonny Jiang 		return r;
13820b15205cSSonny Jiang 	}
13830b15205cSSonny Jiang 
13840b15205cSSonny Jiang 	msg = ptr + addr - start;
13850b15205cSSonny Jiang 
13860b15205cSSonny Jiang 	/* Check length */
13870b15205cSSonny Jiang 	if (msg[1] > end - addr) {
13880b15205cSSonny Jiang 		r = -EINVAL;
13890b15205cSSonny Jiang 		goto out;
13900b15205cSSonny Jiang 	}
13910b15205cSSonny Jiang 
13920b15205cSSonny Jiang 	if (msg[3] != RDECODE_MSG_CREATE)
13930b15205cSSonny Jiang 		goto out;
13940b15205cSSonny Jiang 
13950b15205cSSonny Jiang 	num_buffers = msg[2];
13960b15205cSSonny Jiang 	for (i = 0, msg = &msg[6]; i < num_buffers; ++i, msg += 4) {
13970b15205cSSonny Jiang 		uint32_t offset, size, *create;
13980b15205cSSonny Jiang 
13990b15205cSSonny Jiang 		if (msg[0] != RDECODE_MESSAGE_CREATE)
14000b15205cSSonny Jiang 			continue;
14010b15205cSSonny Jiang 
14020b15205cSSonny Jiang 		offset = msg[1];
14030b15205cSSonny Jiang 		size = msg[2];
14040b15205cSSonny Jiang 
14050b15205cSSonny Jiang 		if (offset + size > end) {
14060b15205cSSonny Jiang 			r = -EINVAL;
14070b15205cSSonny Jiang 			goto out;
14080b15205cSSonny Jiang 		}
14090b15205cSSonny Jiang 
14100b15205cSSonny Jiang 		create = ptr + addr + offset - start;
14110b15205cSSonny Jiang 
14120b15205cSSonny Jiang 		/* H246, HEVC and VP9 can run on any instance */
14130b15205cSSonny Jiang 		if (create[0] == 0x7 || create[0] == 0x10 || create[0] == 0x11)
14140b15205cSSonny Jiang 			continue;
14150b15205cSSonny Jiang 
14160b15205cSSonny Jiang 		r = vcn_v4_0_limit_sched(p);
14170b15205cSSonny Jiang 		if (r)
14180b15205cSSonny Jiang 			goto out;
14190b15205cSSonny Jiang 	}
14200b15205cSSonny Jiang 
14210b15205cSSonny Jiang out:
14220b15205cSSonny Jiang 	amdgpu_bo_kunmap(bo);
14230b15205cSSonny Jiang 	return r;
14240b15205cSSonny Jiang }
14250b15205cSSonny Jiang 
14260b15205cSSonny Jiang #define RADEON_VCN_ENGINE_TYPE_DECODE                                 (0x00000003)
14270b15205cSSonny Jiang 
14280b15205cSSonny Jiang static int vcn_v4_0_ring_patch_cs_in_place(struct amdgpu_cs_parser *p,
14290b15205cSSonny Jiang 				struct amdgpu_job *job,
14300b15205cSSonny Jiang 				struct amdgpu_ib *ib)
14310b15205cSSonny Jiang {
14320b15205cSSonny Jiang 	struct amdgpu_ring *ring = to_amdgpu_ring(p->entity->rq->sched);
14330b15205cSSonny Jiang 	struct amdgpu_vcn_decode_buffer *decode_buffer = NULL;
14340b15205cSSonny Jiang 	uint32_t val;
14350b15205cSSonny Jiang 	int r = 0;
14360b15205cSSonny Jiang 
14370b15205cSSonny Jiang 	/* The first instance can decode anything */
14380b15205cSSonny Jiang 	if (!ring->me)
14390b15205cSSonny Jiang 		return r;
14400b15205cSSonny Jiang 
14410b15205cSSonny Jiang 	/* unified queue ib header has 8 double words. */
14420b15205cSSonny Jiang 	if (ib->length_dw < 8)
14430b15205cSSonny Jiang 		return r;
14440b15205cSSonny Jiang 
14450b15205cSSonny Jiang 	val = amdgpu_ib_get_value(ib, 6); //RADEON_VCN_ENGINE_TYPE
14460b15205cSSonny Jiang 
14470b15205cSSonny Jiang 	if (val == RADEON_VCN_ENGINE_TYPE_DECODE) {
14480b15205cSSonny Jiang 		decode_buffer = (struct amdgpu_vcn_decode_buffer *)&ib->ptr[10];
14490b15205cSSonny Jiang 
14500b15205cSSonny Jiang 		if (decode_buffer->valid_buf_flag  & 0x1)
14510b15205cSSonny Jiang 			r = vcn_v4_0_dec_msg(p, ((u64)decode_buffer->msg_buffer_address_hi) << 32 |
14520b15205cSSonny Jiang 						decode_buffer->msg_buffer_address_lo);
14530b15205cSSonny Jiang 	}
14540b15205cSSonny Jiang 	return r;
14550b15205cSSonny Jiang }
14560b15205cSSonny Jiang 
1457bb4f196bSRuijing Dong static const struct amdgpu_ring_funcs vcn_v4_0_unified_ring_vm_funcs = {
14588da1170aSLeo Liu 	.type = AMDGPU_RING_TYPE_VCN_ENC,
14598da1170aSLeo Liu 	.align_mask = 0x3f,
14608da1170aSLeo Liu 	.nop = VCN_ENC_CMD_NO_OP,
14618da1170aSLeo Liu 	.vmhub = AMDGPU_MMHUB_0,
1462bb4f196bSRuijing Dong 	.get_rptr = vcn_v4_0_unified_ring_get_rptr,
1463bb4f196bSRuijing Dong 	.get_wptr = vcn_v4_0_unified_ring_get_wptr,
1464bb4f196bSRuijing Dong 	.set_wptr = vcn_v4_0_unified_ring_set_wptr,
14650b15205cSSonny Jiang 	.patch_cs_in_place = vcn_v4_0_ring_patch_cs_in_place,
14668da1170aSLeo Liu 	.emit_frame_size =
14678da1170aSLeo Liu 		SOC15_FLUSH_GPU_TLB_NUM_WREG * 3 +
14688da1170aSLeo Liu 		SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 4 +
14698da1170aSLeo Liu 		4 + /* vcn_v2_0_enc_ring_emit_vm_flush */
14708da1170aSLeo Liu 		5 + 5 + /* vcn_v2_0_enc_ring_emit_fence x2 vm fence */
14718da1170aSLeo Liu 		1, /* vcn_v2_0_enc_ring_insert_end */
14728da1170aSLeo Liu 	.emit_ib_size = 5, /* vcn_v2_0_enc_ring_emit_ib */
14738da1170aSLeo Liu 	.emit_ib = vcn_v2_0_enc_ring_emit_ib,
14748da1170aSLeo Liu 	.emit_fence = vcn_v2_0_enc_ring_emit_fence,
14758da1170aSLeo Liu 	.emit_vm_flush = vcn_v2_0_enc_ring_emit_vm_flush,
14768da1170aSLeo Liu 	.test_ring = amdgpu_vcn_enc_ring_test_ring,
1477bb4f196bSRuijing Dong 	.test_ib = amdgpu_vcn_unified_ring_test_ib,
14788da1170aSLeo Liu 	.insert_nop = amdgpu_ring_insert_nop,
14798da1170aSLeo Liu 	.insert_end = vcn_v2_0_enc_ring_insert_end,
14808da1170aSLeo Liu 	.pad_ib = amdgpu_ring_generic_pad_ib,
14818da1170aSLeo Liu 	.begin_use = amdgpu_vcn_ring_begin_use,
14828da1170aSLeo Liu 	.end_use = amdgpu_vcn_ring_end_use,
14838da1170aSLeo Liu 	.emit_wreg = vcn_v2_0_enc_ring_emit_wreg,
14848da1170aSLeo Liu 	.emit_reg_wait = vcn_v2_0_enc_ring_emit_reg_wait,
14858da1170aSLeo Liu 	.emit_reg_write_reg_wait = amdgpu_ring_emit_reg_write_reg_wait_helper,
14868da1170aSLeo Liu };
14878da1170aSLeo Liu 
14888da1170aSLeo Liu /**
1489bb4f196bSRuijing Dong  * vcn_v4_0_set_unified_ring_funcs - set unified ring functions
14908da1170aSLeo Liu  *
14918da1170aSLeo Liu  * @adev: amdgpu_device pointer
14928da1170aSLeo Liu  *
1493bb4f196bSRuijing Dong  * Set unified ring functions
14948da1170aSLeo Liu  */
1495bb4f196bSRuijing Dong static void vcn_v4_0_set_unified_ring_funcs(struct amdgpu_device *adev)
14968da1170aSLeo Liu {
14978da1170aSLeo Liu 	int i;
14988da1170aSLeo Liu 
14998da1170aSLeo Liu 	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
15008da1170aSLeo Liu 		if (adev->vcn.harvest_config & (1 << i))
15018da1170aSLeo Liu 			continue;
15028da1170aSLeo Liu 
1503bb4f196bSRuijing Dong 		adev->vcn.inst[i].ring_enc[0].funcs = &vcn_v4_0_unified_ring_vm_funcs;
1504bb4f196bSRuijing Dong 		adev->vcn.inst[i].ring_enc[0].me = i;
15058da1170aSLeo Liu 
1506bb4f196bSRuijing Dong 		DRM_INFO("VCN(%d) encode/decode are enabled in VM mode\n", i);
15078da1170aSLeo Liu 	}
15088da1170aSLeo Liu }
15098da1170aSLeo Liu 
15108da1170aSLeo Liu /**
15118da1170aSLeo Liu  * vcn_v4_0_is_idle - check VCN block is idle
15128da1170aSLeo Liu  *
15138da1170aSLeo Liu  * @handle: amdgpu_device pointer
15148da1170aSLeo Liu  *
15158da1170aSLeo Liu  * Check whether VCN block is idle
15168da1170aSLeo Liu  */
15178da1170aSLeo Liu static bool vcn_v4_0_is_idle(void *handle)
15188da1170aSLeo Liu {
15198da1170aSLeo Liu 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
15208da1170aSLeo Liu 	int i, ret = 1;
15218da1170aSLeo Liu 
15228da1170aSLeo Liu 	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
15238da1170aSLeo Liu 		if (adev->vcn.harvest_config & (1 << i))
15248da1170aSLeo Liu 			continue;
15258da1170aSLeo Liu 
15268da1170aSLeo Liu 		ret &= (RREG32_SOC15(VCN, i, regUVD_STATUS) == UVD_STATUS__IDLE);
15278da1170aSLeo Liu 	}
15288da1170aSLeo Liu 
15298da1170aSLeo Liu 	return ret;
15308da1170aSLeo Liu }
15318da1170aSLeo Liu 
15328da1170aSLeo Liu /**
15338da1170aSLeo Liu  * vcn_v4_0_wait_for_idle - wait for VCN block idle
15348da1170aSLeo Liu  *
15358da1170aSLeo Liu  * @handle: amdgpu_device pointer
15368da1170aSLeo Liu  *
15378da1170aSLeo Liu  * Wait for VCN block idle
15388da1170aSLeo Liu  */
15398da1170aSLeo Liu static int vcn_v4_0_wait_for_idle(void *handle)
15408da1170aSLeo Liu {
15418da1170aSLeo Liu 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
15428da1170aSLeo Liu 	int i, ret = 0;
15438da1170aSLeo Liu 
15448da1170aSLeo Liu 	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
15458da1170aSLeo Liu 		if (adev->vcn.harvest_config & (1 << i))
15468da1170aSLeo Liu 			continue;
15478da1170aSLeo Liu 
15488da1170aSLeo Liu 		ret = SOC15_WAIT_ON_RREG(VCN, i, regUVD_STATUS, UVD_STATUS__IDLE,
15498da1170aSLeo Liu 			UVD_STATUS__IDLE);
15508da1170aSLeo Liu 		if (ret)
15518da1170aSLeo Liu 			return ret;
15528da1170aSLeo Liu 	}
15538da1170aSLeo Liu 
15548da1170aSLeo Liu 	return ret;
15558da1170aSLeo Liu }
15568da1170aSLeo Liu 
15578da1170aSLeo Liu /**
15588da1170aSLeo Liu  * vcn_v4_0_set_clockgating_state - set VCN block clockgating state
15598da1170aSLeo Liu  *
15608da1170aSLeo Liu  * @handle: amdgpu_device pointer
15618da1170aSLeo Liu  * @state: clock gating state
15628da1170aSLeo Liu  *
15638da1170aSLeo Liu  * Set VCN block clockgating state
15648da1170aSLeo Liu  */
15658da1170aSLeo Liu static int vcn_v4_0_set_clockgating_state(void *handle, enum amd_clockgating_state state)
15668da1170aSLeo Liu {
15678da1170aSLeo Liu 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
15688da1170aSLeo Liu 	bool enable = (state == AMD_CG_STATE_GATE) ? true : false;
15698da1170aSLeo Liu 	int i;
15708da1170aSLeo Liu 
15718da1170aSLeo Liu 	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
15728da1170aSLeo Liu 		if (adev->vcn.harvest_config & (1 << i))
15738da1170aSLeo Liu 			continue;
15748da1170aSLeo Liu 
15758da1170aSLeo Liu 		if (enable) {
15768da1170aSLeo Liu 			if (RREG32_SOC15(VCN, i, regUVD_STATUS) != UVD_STATUS__IDLE)
15778da1170aSLeo Liu 				return -EBUSY;
15788da1170aSLeo Liu 			vcn_v4_0_enable_clock_gating(adev, i);
15798da1170aSLeo Liu 		} else {
15808da1170aSLeo Liu 			vcn_v4_0_disable_clock_gating(adev, i);
15818da1170aSLeo Liu 		}
15828da1170aSLeo Liu 	}
15838da1170aSLeo Liu 
15848da1170aSLeo Liu 	return 0;
15858da1170aSLeo Liu }
15868da1170aSLeo Liu 
15878da1170aSLeo Liu /**
15888da1170aSLeo Liu  * vcn_v4_0_set_powergating_state - set VCN block powergating state
15898da1170aSLeo Liu  *
15908da1170aSLeo Liu  * @handle: amdgpu_device pointer
15918da1170aSLeo Liu  * @state: power gating state
15928da1170aSLeo Liu  *
15938da1170aSLeo Liu  * Set VCN block powergating state
15948da1170aSLeo Liu  */
15958da1170aSLeo Liu static int vcn_v4_0_set_powergating_state(void *handle, enum amd_powergating_state state)
15968da1170aSLeo Liu {
15978da1170aSLeo Liu 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
15988da1170aSLeo Liu 	int ret;
15998da1170aSLeo Liu 
16008da1170aSLeo Liu 	if(state == adev->vcn.cur_state)
16018da1170aSLeo Liu 		return 0;
16028da1170aSLeo Liu 
16038da1170aSLeo Liu 	if (state == AMD_PG_STATE_GATE)
16048da1170aSLeo Liu 		ret = vcn_v4_0_stop(adev);
16058da1170aSLeo Liu 	else
16068da1170aSLeo Liu 		ret = vcn_v4_0_start(adev);
16078da1170aSLeo Liu 
16088da1170aSLeo Liu 	if(!ret)
16098da1170aSLeo Liu 		adev->vcn.cur_state = state;
16108da1170aSLeo Liu 
16118da1170aSLeo Liu 	return ret;
16128da1170aSLeo Liu }
16138da1170aSLeo Liu 
16148da1170aSLeo Liu /**
16158da1170aSLeo Liu  * vcn_v4_0_set_interrupt_state - set VCN block interrupt state
16168da1170aSLeo Liu  *
16178da1170aSLeo Liu  * @adev: amdgpu_device pointer
16188da1170aSLeo Liu  * @source: interrupt sources
16198da1170aSLeo Liu  * @type: interrupt types
16208da1170aSLeo Liu  * @state: interrupt states
16218da1170aSLeo Liu  *
16228da1170aSLeo Liu  * Set VCN block interrupt state
16238da1170aSLeo Liu  */
16248da1170aSLeo Liu static int vcn_v4_0_set_interrupt_state(struct amdgpu_device *adev, struct amdgpu_irq_src *source,
16258da1170aSLeo Liu       unsigned type, enum amdgpu_interrupt_state state)
16268da1170aSLeo Liu {
16278da1170aSLeo Liu 	return 0;
16288da1170aSLeo Liu }
16298da1170aSLeo Liu 
16308da1170aSLeo Liu /**
16318da1170aSLeo Liu  * vcn_v4_0_process_interrupt - process VCN block interrupt
16328da1170aSLeo Liu  *
16338da1170aSLeo Liu  * @adev: amdgpu_device pointer
16348da1170aSLeo Liu  * @source: interrupt sources
16358da1170aSLeo Liu  * @entry: interrupt entry from clients and sources
16368da1170aSLeo Liu  *
16378da1170aSLeo Liu  * Process VCN block interrupt
16388da1170aSLeo Liu  */
16398da1170aSLeo Liu static int vcn_v4_0_process_interrupt(struct amdgpu_device *adev, struct amdgpu_irq_src *source,
16408da1170aSLeo Liu       struct amdgpu_iv_entry *entry)
16418da1170aSLeo Liu {
16428da1170aSLeo Liu 	uint32_t ip_instance;
16438da1170aSLeo Liu 
16448da1170aSLeo Liu 	switch (entry->client_id) {
16458da1170aSLeo Liu 	case SOC15_IH_CLIENTID_VCN:
16468da1170aSLeo Liu 		ip_instance = 0;
16478da1170aSLeo Liu 		break;
16488da1170aSLeo Liu 	case SOC15_IH_CLIENTID_VCN1:
16498da1170aSLeo Liu 		ip_instance = 1;
16508da1170aSLeo Liu 		break;
16518da1170aSLeo Liu 	default:
16528da1170aSLeo Liu 		DRM_ERROR("Unhandled client id: %d\n", entry->client_id);
16538da1170aSLeo Liu 		return 0;
16548da1170aSLeo Liu 	}
16558da1170aSLeo Liu 
16568da1170aSLeo Liu 	DRM_DEBUG("IH: VCN TRAP\n");
16578da1170aSLeo Liu 
16588da1170aSLeo Liu 	switch (entry->src_id) {
16598da1170aSLeo Liu 	case VCN_4_0__SRCID__UVD_ENC_GENERAL_PURPOSE:
16608da1170aSLeo Liu 		amdgpu_fence_process(&adev->vcn.inst[ip_instance].ring_enc[0]);
16618da1170aSLeo Liu 		break;
16628da1170aSLeo Liu 	default:
16638da1170aSLeo Liu 		DRM_ERROR("Unhandled interrupt: %d %d\n",
16648da1170aSLeo Liu 			  entry->src_id, entry->src_data[0]);
16658da1170aSLeo Liu 		break;
16668da1170aSLeo Liu 	}
16678da1170aSLeo Liu 
16688da1170aSLeo Liu 	return 0;
16698da1170aSLeo Liu }
16708da1170aSLeo Liu 
16718da1170aSLeo Liu static const struct amdgpu_irq_src_funcs vcn_v4_0_irq_funcs = {
16728da1170aSLeo Liu 	.set = vcn_v4_0_set_interrupt_state,
16738da1170aSLeo Liu 	.process = vcn_v4_0_process_interrupt,
16748da1170aSLeo Liu };
16758da1170aSLeo Liu 
16768da1170aSLeo Liu /**
16778da1170aSLeo Liu  * vcn_v4_0_set_irq_funcs - set VCN block interrupt irq functions
16788da1170aSLeo Liu  *
16798da1170aSLeo Liu  * @adev: amdgpu_device pointer
16808da1170aSLeo Liu  *
16818da1170aSLeo Liu  * Set VCN block interrupt irq functions
16828da1170aSLeo Liu  */
16838da1170aSLeo Liu static void vcn_v4_0_set_irq_funcs(struct amdgpu_device *adev)
16848da1170aSLeo Liu {
16858da1170aSLeo Liu 	int i;
16868da1170aSLeo Liu 
16878da1170aSLeo Liu 	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
16888da1170aSLeo Liu 		if (adev->vcn.harvest_config & (1 << i))
16898da1170aSLeo Liu 			continue;
16908da1170aSLeo Liu 
16918da1170aSLeo Liu 		adev->vcn.inst[i].irq.num_types = adev->vcn.num_enc_rings + 1;
16928da1170aSLeo Liu 		adev->vcn.inst[i].irq.funcs = &vcn_v4_0_irq_funcs;
16938da1170aSLeo Liu 	}
16948da1170aSLeo Liu }
16958da1170aSLeo Liu 
16968da1170aSLeo Liu static const struct amd_ip_funcs vcn_v4_0_ip_funcs = {
16978da1170aSLeo Liu 	.name = "vcn_v4_0",
16988da1170aSLeo Liu 	.early_init = vcn_v4_0_early_init,
16998da1170aSLeo Liu 	.late_init = NULL,
17008da1170aSLeo Liu 	.sw_init = vcn_v4_0_sw_init,
17018da1170aSLeo Liu 	.sw_fini = vcn_v4_0_sw_fini,
17028da1170aSLeo Liu 	.hw_init = vcn_v4_0_hw_init,
17038da1170aSLeo Liu 	.hw_fini = vcn_v4_0_hw_fini,
17048da1170aSLeo Liu 	.suspend = vcn_v4_0_suspend,
17058da1170aSLeo Liu 	.resume = vcn_v4_0_resume,
17068da1170aSLeo Liu 	.is_idle = vcn_v4_0_is_idle,
17078da1170aSLeo Liu 	.wait_for_idle = vcn_v4_0_wait_for_idle,
17088da1170aSLeo Liu 	.check_soft_reset = NULL,
17098da1170aSLeo Liu 	.pre_soft_reset = NULL,
17108da1170aSLeo Liu 	.soft_reset = NULL,
17118da1170aSLeo Liu 	.post_soft_reset = NULL,
17128da1170aSLeo Liu 	.set_clockgating_state = vcn_v4_0_set_clockgating_state,
17138da1170aSLeo Liu 	.set_powergating_state = vcn_v4_0_set_powergating_state,
17148da1170aSLeo Liu };
17158da1170aSLeo Liu 
17168da1170aSLeo Liu const struct amdgpu_ip_block_version vcn_v4_0_ip_block =
17178da1170aSLeo Liu {
17188da1170aSLeo Liu 	.type = AMD_IP_BLOCK_TYPE_VCN,
17198da1170aSLeo Liu 	.major = 4,
17208da1170aSLeo Liu 	.minor = 0,
17218da1170aSLeo Liu 	.rev = 0,
17228da1170aSLeo Liu 	.funcs = &vcn_v4_0_ip_funcs,
17238da1170aSLeo Liu };
1724