brintos

brintos / linux-shallow public Read only

0
0
Text · 24.2 KiB · efd903c Raw
930 lines · c
1/*2 * Copyright 2014 Advanced Micro Devices, Inc.3 *4 * Permission is hereby granted, free of charge, to any person obtaining a5 * copy of this software and associated documentation files (the "Software"),6 * to deal in the Software without restriction, including without limitation7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,8 * and/or sell copies of the Software, and to permit persons to whom the9 * Software is furnished to do so, subject to the following conditions:10 *11 * The above copyright notice and this permission notice shall be included in12 * all copies or substantial portions of the Software.13 *14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR20 * OTHER DEALINGS IN THE SOFTWARE.21 *22 * Authors: Christian König <christian.koenig@amd.com>23 */24 25#include <linux/delay.h>26#include <linux/firmware.h>27 28#include "amdgpu.h"29#include "amdgpu_uvd.h"30#include "vid.h"31#include "uvd/uvd_5_0_d.h"32#include "uvd/uvd_5_0_sh_mask.h"33#include "oss/oss_2_0_d.h"34#include "oss/oss_2_0_sh_mask.h"35#include "bif/bif_5_0_d.h"36#include "vi.h"37#include "smu/smu_7_1_2_d.h"38#include "smu/smu_7_1_2_sh_mask.h"39#include "ivsrcid/ivsrcid_vislands30.h"40 41static void uvd_v5_0_set_ring_funcs(struct amdgpu_device *adev);42static void uvd_v5_0_set_irq_funcs(struct amdgpu_device *adev);43static int uvd_v5_0_start(struct amdgpu_device *adev);44static void uvd_v5_0_stop(struct amdgpu_device *adev);45static int uvd_v5_0_set_clockgating_state(void *handle,46					  enum amd_clockgating_state state);47static void uvd_v5_0_enable_mgcg(struct amdgpu_device *adev,48				 bool enable);49/**50 * uvd_v5_0_ring_get_rptr - get read pointer51 *52 * @ring: amdgpu_ring pointer53 *54 * Returns the current hardware read pointer55 */56static uint64_t uvd_v5_0_ring_get_rptr(struct amdgpu_ring *ring)57{58	struct amdgpu_device *adev = ring->adev;59 60	return RREG32(mmUVD_RBC_RB_RPTR);61}62 63/**64 * uvd_v5_0_ring_get_wptr - get write pointer65 *66 * @ring: amdgpu_ring pointer67 *68 * Returns the current hardware write pointer69 */70static uint64_t uvd_v5_0_ring_get_wptr(struct amdgpu_ring *ring)71{72	struct amdgpu_device *adev = ring->adev;73 74	return RREG32(mmUVD_RBC_RB_WPTR);75}76 77/**78 * uvd_v5_0_ring_set_wptr - set write pointer79 *80 * @ring: amdgpu_ring pointer81 *82 * Commits the write pointer to the hardware83 */84static void uvd_v5_0_ring_set_wptr(struct amdgpu_ring *ring)85{86	struct amdgpu_device *adev = ring->adev;87 88	WREG32(mmUVD_RBC_RB_WPTR, lower_32_bits(ring->wptr));89}90 91static int uvd_v5_0_early_init(void *handle)92{93	struct amdgpu_device *adev = (struct amdgpu_device *)handle;94	adev->uvd.num_uvd_inst = 1;95 96	uvd_v5_0_set_ring_funcs(adev);97	uvd_v5_0_set_irq_funcs(adev);98 99	return 0;100}101 102static int uvd_v5_0_sw_init(void *handle)103{104	struct amdgpu_ring *ring;105	struct amdgpu_device *adev = (struct amdgpu_device *)handle;106	int r;107 108	/* UVD TRAP */109	r = amdgpu_irq_add_id(adev, AMDGPU_IRQ_CLIENTID_LEGACY, VISLANDS30_IV_SRCID_UVD_SYSTEM_MESSAGE, &adev->uvd.inst->irq);110	if (r)111		return r;112 113	r = amdgpu_uvd_sw_init(adev);114	if (r)115		return r;116 117	ring = &adev->uvd.inst->ring;118	sprintf(ring->name, "uvd");119	r = amdgpu_ring_init(adev, ring, 512, &adev->uvd.inst->irq, 0,120			     AMDGPU_RING_PRIO_DEFAULT, NULL);121	if (r)122		return r;123 124	r = amdgpu_uvd_resume(adev);125	if (r)126		return r;127 128	return r;129}130 131static int uvd_v5_0_sw_fini(void *handle)132{133	int r;134	struct amdgpu_device *adev = (struct amdgpu_device *)handle;135 136	r = amdgpu_uvd_suspend(adev);137	if (r)138		return r;139 140	return amdgpu_uvd_sw_fini(adev);141}142 143/**144 * uvd_v5_0_hw_init - start and test UVD block145 *146 * @handle: handle used to pass amdgpu_device pointer147 *148 * Initialize the hardware, boot up the VCPU and do some testing149 */150static int uvd_v5_0_hw_init(void *handle)151{152	struct amdgpu_device *adev = (struct amdgpu_device *)handle;153	struct amdgpu_ring *ring = &adev->uvd.inst->ring;154	uint32_t tmp;155	int r;156 157	amdgpu_asic_set_uvd_clocks(adev, 10000, 10000);158	uvd_v5_0_set_clockgating_state(adev, AMD_CG_STATE_UNGATE);159	uvd_v5_0_enable_mgcg(adev, true);160 161	r = amdgpu_ring_test_helper(ring);162	if (r)163		goto done;164 165	r = amdgpu_ring_alloc(ring, 10);166	if (r) {167		DRM_ERROR("amdgpu: ring failed to lock UVD ring (%d).\n", r);168		goto done;169	}170 171	tmp = PACKET0(mmUVD_SEMA_WAIT_FAULT_TIMEOUT_CNTL, 0);172	amdgpu_ring_write(ring, tmp);173	amdgpu_ring_write(ring, 0xFFFFF);174 175	tmp = PACKET0(mmUVD_SEMA_WAIT_INCOMPLETE_TIMEOUT_CNTL, 0);176	amdgpu_ring_write(ring, tmp);177	amdgpu_ring_write(ring, 0xFFFFF);178 179	tmp = PACKET0(mmUVD_SEMA_SIGNAL_INCOMPLETE_TIMEOUT_CNTL, 0);180	amdgpu_ring_write(ring, tmp);181	amdgpu_ring_write(ring, 0xFFFFF);182 183	/* Clear timeout status bits */184	amdgpu_ring_write(ring, PACKET0(mmUVD_SEMA_TIMEOUT_STATUS, 0));185	amdgpu_ring_write(ring, 0x8);186 187	amdgpu_ring_write(ring, PACKET0(mmUVD_SEMA_CNTL, 0));188	amdgpu_ring_write(ring, 3);189 190	amdgpu_ring_commit(ring);191 192done:193	if (!r)194		DRM_INFO("UVD initialized successfully.\n");195 196	return r;197 198}199 200/**201 * uvd_v5_0_hw_fini - stop the hardware block202 *203 * @handle: handle used to pass amdgpu_device pointer204 *205 * Stop the UVD block, mark ring as not ready any more206 */207static int uvd_v5_0_hw_fini(void *handle)208{209	struct amdgpu_device *adev = (struct amdgpu_device *)handle;210 211	cancel_delayed_work_sync(&adev->uvd.idle_work);212 213	if (RREG32(mmUVD_STATUS) != 0)214		uvd_v5_0_stop(adev);215 216	return 0;217}218 219static int uvd_v5_0_prepare_suspend(void *handle)220{221	struct amdgpu_device *adev = (struct amdgpu_device *)handle;222 223	return amdgpu_uvd_prepare_suspend(adev);224}225 226static int uvd_v5_0_suspend(void *handle)227{228	int r;229	struct amdgpu_device *adev = (struct amdgpu_device *)handle;230 231	/*232	 * Proper cleanups before halting the HW engine:233	 *   - cancel the delayed idle work234	 *   - enable powergating235	 *   - enable clockgating236	 *   - disable dpm237	 *238	 * TODO: to align with the VCN implementation, move the239	 * jobs for clockgating/powergating/dpm setting to240	 * ->set_powergating_state().241	 */242	cancel_delayed_work_sync(&adev->uvd.idle_work);243 244	if (adev->pm.dpm_enabled) {245		amdgpu_dpm_enable_uvd(adev, false);246	} else {247		amdgpu_asic_set_uvd_clocks(adev, 0, 0);248		/* shutdown the UVD block */249		amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_UVD,250						       AMD_PG_STATE_GATE);251		amdgpu_device_ip_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_UVD,252						       AMD_CG_STATE_GATE);253	}254 255	r = uvd_v5_0_hw_fini(adev);256	if (r)257		return r;258 259	return amdgpu_uvd_suspend(adev);260}261 262static int uvd_v5_0_resume(void *handle)263{264	int r;265	struct amdgpu_device *adev = (struct amdgpu_device *)handle;266 267	r = amdgpu_uvd_resume(adev);268	if (r)269		return r;270 271	return uvd_v5_0_hw_init(adev);272}273 274/**275 * uvd_v5_0_mc_resume - memory controller programming276 *277 * @adev: amdgpu_device pointer278 *279 * Let the UVD memory controller know it's offsets280 */281static void uvd_v5_0_mc_resume(struct amdgpu_device *adev)282{283	uint64_t offset;284	uint32_t size;285 286	/* program memory controller bits 0-27 */287	WREG32(mmUVD_LMI_VCPU_CACHE_64BIT_BAR_LOW,288			lower_32_bits(adev->uvd.inst->gpu_addr));289	WREG32(mmUVD_LMI_VCPU_CACHE_64BIT_BAR_HIGH,290			upper_32_bits(adev->uvd.inst->gpu_addr));291 292	offset = AMDGPU_UVD_FIRMWARE_OFFSET;293	size = AMDGPU_UVD_FIRMWARE_SIZE(adev);294	WREG32(mmUVD_VCPU_CACHE_OFFSET0, offset >> 3);295	WREG32(mmUVD_VCPU_CACHE_SIZE0, size);296 297	offset += size;298	size = AMDGPU_UVD_HEAP_SIZE;299	WREG32(mmUVD_VCPU_CACHE_OFFSET1, offset >> 3);300	WREG32(mmUVD_VCPU_CACHE_SIZE1, size);301 302	offset += size;303	size = AMDGPU_UVD_STACK_SIZE +304	       (AMDGPU_UVD_SESSION_SIZE * adev->uvd.max_handles);305	WREG32(mmUVD_VCPU_CACHE_OFFSET2, offset >> 3);306	WREG32(mmUVD_VCPU_CACHE_SIZE2, size);307 308	WREG32(mmUVD_UDEC_ADDR_CONFIG, adev->gfx.config.gb_addr_config);309	WREG32(mmUVD_UDEC_DB_ADDR_CONFIG, adev->gfx.config.gb_addr_config);310	WREG32(mmUVD_UDEC_DBW_ADDR_CONFIG, adev->gfx.config.gb_addr_config);311}312 313/**314 * uvd_v5_0_start - start UVD block315 *316 * @adev: amdgpu_device pointer317 *318 * Setup and start the UVD block319 */320static int uvd_v5_0_start(struct amdgpu_device *adev)321{322	struct amdgpu_ring *ring = &adev->uvd.inst->ring;323	uint32_t rb_bufsz, tmp;324	uint32_t lmi_swap_cntl;325	uint32_t mp_swap_cntl;326	int i, j, r;327 328	/*disable DPG */329	WREG32_P(mmUVD_POWER_STATUS, 0, ~(1 << 2));330 331	/* disable byte swapping */332	lmi_swap_cntl = 0;333	mp_swap_cntl = 0;334 335	uvd_v5_0_mc_resume(adev);336 337	/* disable interupt */338	WREG32_P(mmUVD_MASTINT_EN, 0, ~(1 << 1));339 340	/* stall UMC and register bus before resetting VCPU */341	WREG32_P(mmUVD_LMI_CTRL2, 1 << 8, ~(1 << 8));342	mdelay(1);343 344	/* put LMI, VCPU, RBC etc... into reset */345	WREG32(mmUVD_SOFT_RESET, UVD_SOFT_RESET__LMI_SOFT_RESET_MASK |346		UVD_SOFT_RESET__VCPU_SOFT_RESET_MASK | UVD_SOFT_RESET__LBSI_SOFT_RESET_MASK |347		UVD_SOFT_RESET__RBC_SOFT_RESET_MASK | UVD_SOFT_RESET__CSM_SOFT_RESET_MASK |348		UVD_SOFT_RESET__CXW_SOFT_RESET_MASK | UVD_SOFT_RESET__TAP_SOFT_RESET_MASK |349		UVD_SOFT_RESET__LMI_UMC_SOFT_RESET_MASK);350	mdelay(5);351 352	/* take UVD block out of reset */353	WREG32_P(mmSRBM_SOFT_RESET, 0, ~SRBM_SOFT_RESET__SOFT_RESET_UVD_MASK);354	mdelay(5);355 356	/* initialize UVD memory controller */357	WREG32(mmUVD_LMI_CTRL, 0x40 | (1 << 8) | (1 << 13) |358			     (1 << 21) | (1 << 9) | (1 << 20));359 360#ifdef __BIG_ENDIAN361	/* swap (8 in 32) RB and IB */362	lmi_swap_cntl = 0xa;363	mp_swap_cntl = 0;364#endif365	WREG32(mmUVD_LMI_SWAP_CNTL, lmi_swap_cntl);366	WREG32(mmUVD_MP_SWAP_CNTL, mp_swap_cntl);367 368	WREG32(mmUVD_MPC_SET_MUXA0, 0x40c2040);369	WREG32(mmUVD_MPC_SET_MUXA1, 0x0);370	WREG32(mmUVD_MPC_SET_MUXB0, 0x40c2040);371	WREG32(mmUVD_MPC_SET_MUXB1, 0x0);372	WREG32(mmUVD_MPC_SET_ALU, 0);373	WREG32(mmUVD_MPC_SET_MUX, 0x88);374 375	/* take all subblocks out of reset, except VCPU */376	WREG32(mmUVD_SOFT_RESET, UVD_SOFT_RESET__VCPU_SOFT_RESET_MASK);377	mdelay(5);378 379	/* enable VCPU clock */380	WREG32(mmUVD_VCPU_CNTL,  1 << 9);381 382	/* enable UMC */383	WREG32_P(mmUVD_LMI_CTRL2, 0, ~(1 << 8));384 385	/* boot up the VCPU */386	WREG32(mmUVD_SOFT_RESET, 0);387	mdelay(10);388 389	for (i = 0; i < 10; ++i) {390		uint32_t status;391		for (j = 0; j < 100; ++j) {392			status = RREG32(mmUVD_STATUS);393			if (status & 2)394				break;395			mdelay(10);396		}397		r = 0;398		if (status & 2)399			break;400 401		DRM_ERROR("UVD not responding, trying to reset the VCPU!!!\n");402		WREG32_P(mmUVD_SOFT_RESET, UVD_SOFT_RESET__VCPU_SOFT_RESET_MASK,403				~UVD_SOFT_RESET__VCPU_SOFT_RESET_MASK);404		mdelay(10);405		WREG32_P(mmUVD_SOFT_RESET, 0, ~UVD_SOFT_RESET__VCPU_SOFT_RESET_MASK);406		mdelay(10);407		r = -1;408	}409 410	if (r) {411		DRM_ERROR("UVD not responding, giving up!!!\n");412		return r;413	}414	/* enable master interrupt */415	WREG32_P(mmUVD_MASTINT_EN, 3 << 1, ~(3 << 1));416 417	/* clear the bit 4 of UVD_STATUS */418	WREG32_P(mmUVD_STATUS, 0, ~(2 << 1));419 420	rb_bufsz = order_base_2(ring->ring_size);421	tmp = 0;422	tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_BUFSZ, rb_bufsz);423	tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_BLKSZ, 1);424	tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_FETCH, 1);425	tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_WPTR_POLL_EN, 0);426	tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_UPDATE, 1);427	tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_RPTR_WR_EN, 1);428	/* force RBC into idle state */429	WREG32(mmUVD_RBC_RB_CNTL, tmp);430 431	/* set the write pointer delay */432	WREG32(mmUVD_RBC_RB_WPTR_CNTL, 0);433 434	/* set the wb address */435	WREG32(mmUVD_RBC_RB_RPTR_ADDR, (upper_32_bits(ring->gpu_addr) >> 2));436 437	/* program the RB_BASE for ring buffer */438	WREG32(mmUVD_LMI_RBC_RB_64BIT_BAR_LOW,439			lower_32_bits(ring->gpu_addr));440	WREG32(mmUVD_LMI_RBC_RB_64BIT_BAR_HIGH,441			upper_32_bits(ring->gpu_addr));442 443	/* Initialize the ring buffer's read and write pointers */444	WREG32(mmUVD_RBC_RB_RPTR, 0);445 446	ring->wptr = RREG32(mmUVD_RBC_RB_RPTR);447	WREG32(mmUVD_RBC_RB_WPTR, lower_32_bits(ring->wptr));448 449	WREG32_P(mmUVD_RBC_RB_CNTL, 0, ~UVD_RBC_RB_CNTL__RB_NO_FETCH_MASK);450 451	return 0;452}453 454/**455 * uvd_v5_0_stop - stop UVD block456 *457 * @adev: amdgpu_device pointer458 *459 * stop the UVD block460 */461static void uvd_v5_0_stop(struct amdgpu_device *adev)462{463	/* force RBC into idle state */464	WREG32(mmUVD_RBC_RB_CNTL, 0x11010101);465 466	/* Stall UMC and register bus before resetting VCPU */467	WREG32_P(mmUVD_LMI_CTRL2, 1 << 8, ~(1 << 8));468	mdelay(1);469 470	/* put VCPU into reset */471	WREG32(mmUVD_SOFT_RESET, UVD_SOFT_RESET__VCPU_SOFT_RESET_MASK);472	mdelay(5);473 474	/* disable VCPU clock */475	WREG32(mmUVD_VCPU_CNTL, 0x0);476 477	/* Unstall UMC and register bus */478	WREG32_P(mmUVD_LMI_CTRL2, 0, ~(1 << 8));479 480	WREG32(mmUVD_STATUS, 0);481}482 483/**484 * uvd_v5_0_ring_emit_fence - emit an fence & trap command485 *486 * @ring: amdgpu_ring pointer487 * @addr: address488 * @seq: sequence number489 * @flags: fence related flags490 *491 * Write a fence and a trap command to the ring.492 */493static void uvd_v5_0_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 seq,494				     unsigned flags)495{496	WARN_ON(flags & AMDGPU_FENCE_FLAG_64BIT);497 498	amdgpu_ring_write(ring, PACKET0(mmUVD_CONTEXT_ID, 0));499	amdgpu_ring_write(ring, seq);500	amdgpu_ring_write(ring, PACKET0(mmUVD_GPCOM_VCPU_DATA0, 0));501	amdgpu_ring_write(ring, addr & 0xffffffff);502	amdgpu_ring_write(ring, PACKET0(mmUVD_GPCOM_VCPU_DATA1, 0));503	amdgpu_ring_write(ring, upper_32_bits(addr) & 0xff);504	amdgpu_ring_write(ring, PACKET0(mmUVD_GPCOM_VCPU_CMD, 0));505	amdgpu_ring_write(ring, 0);506 507	amdgpu_ring_write(ring, PACKET0(mmUVD_GPCOM_VCPU_DATA0, 0));508	amdgpu_ring_write(ring, 0);509	amdgpu_ring_write(ring, PACKET0(mmUVD_GPCOM_VCPU_DATA1, 0));510	amdgpu_ring_write(ring, 0);511	amdgpu_ring_write(ring, PACKET0(mmUVD_GPCOM_VCPU_CMD, 0));512	amdgpu_ring_write(ring, 2);513}514 515/**516 * uvd_v5_0_ring_test_ring - register write test517 *518 * @ring: amdgpu_ring pointer519 *520 * Test if we can successfully write to the context register521 */522static int uvd_v5_0_ring_test_ring(struct amdgpu_ring *ring)523{524	struct amdgpu_device *adev = ring->adev;525	uint32_t tmp = 0;526	unsigned i;527	int r;528 529	WREG32(mmUVD_CONTEXT_ID, 0xCAFEDEAD);530	r = amdgpu_ring_alloc(ring, 3);531	if (r)532		return r;533	amdgpu_ring_write(ring, PACKET0(mmUVD_CONTEXT_ID, 0));534	amdgpu_ring_write(ring, 0xDEADBEEF);535	amdgpu_ring_commit(ring);536	for (i = 0; i < adev->usec_timeout; i++) {537		tmp = RREG32(mmUVD_CONTEXT_ID);538		if (tmp == 0xDEADBEEF)539			break;540		udelay(1);541	}542 543	if (i >= adev->usec_timeout)544		r = -ETIMEDOUT;545 546	return r;547}548 549/**550 * uvd_v5_0_ring_emit_ib - execute indirect buffer551 *552 * @ring: amdgpu_ring pointer553 * @job: job to retrieve vmid from554 * @ib: indirect buffer to execute555 * @flags: unused556 *557 * Write ring commands to execute the indirect buffer558 */559static void uvd_v5_0_ring_emit_ib(struct amdgpu_ring *ring,560				  struct amdgpu_job *job,561				  struct amdgpu_ib *ib,562				  uint32_t flags)563{564	amdgpu_ring_write(ring, PACKET0(mmUVD_LMI_RBC_IB_64BIT_BAR_LOW, 0));565	amdgpu_ring_write(ring, lower_32_bits(ib->gpu_addr));566	amdgpu_ring_write(ring, PACKET0(mmUVD_LMI_RBC_IB_64BIT_BAR_HIGH, 0));567	amdgpu_ring_write(ring, upper_32_bits(ib->gpu_addr));568	amdgpu_ring_write(ring, PACKET0(mmUVD_RBC_IB_SIZE, 0));569	amdgpu_ring_write(ring, ib->length_dw);570}571 572static void uvd_v5_0_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count)573{574	int i;575 576	WARN_ON(ring->wptr % 2 || count % 2);577 578	for (i = 0; i < count / 2; i++) {579		amdgpu_ring_write(ring, PACKET0(mmUVD_NO_OP, 0));580		amdgpu_ring_write(ring, 0);581	}582}583 584static bool uvd_v5_0_is_idle(void *handle)585{586	struct amdgpu_device *adev = (struct amdgpu_device *)handle;587 588	return !(RREG32(mmSRBM_STATUS) & SRBM_STATUS__UVD_BUSY_MASK);589}590 591static int uvd_v5_0_wait_for_idle(void *handle)592{593	unsigned i;594	struct amdgpu_device *adev = (struct amdgpu_device *)handle;595 596	for (i = 0; i < adev->usec_timeout; i++) {597		if (!(RREG32(mmSRBM_STATUS) & SRBM_STATUS__UVD_BUSY_MASK))598			return 0;599	}600	return -ETIMEDOUT;601}602 603static int uvd_v5_0_soft_reset(void *handle)604{605	struct amdgpu_device *adev = (struct amdgpu_device *)handle;606 607	uvd_v5_0_stop(adev);608 609	WREG32_P(mmSRBM_SOFT_RESET, SRBM_SOFT_RESET__SOFT_RESET_UVD_MASK,610			~SRBM_SOFT_RESET__SOFT_RESET_UVD_MASK);611	mdelay(5);612 613	return uvd_v5_0_start(adev);614}615 616static int uvd_v5_0_set_interrupt_state(struct amdgpu_device *adev,617					struct amdgpu_irq_src *source,618					unsigned type,619					enum amdgpu_interrupt_state state)620{621	// TODO622	return 0;623}624 625static int uvd_v5_0_process_interrupt(struct amdgpu_device *adev,626				      struct amdgpu_irq_src *source,627				      struct amdgpu_iv_entry *entry)628{629	DRM_DEBUG("IH: UVD TRAP\n");630	amdgpu_fence_process(&adev->uvd.inst->ring);631	return 0;632}633 634static void uvd_v5_0_enable_clock_gating(struct amdgpu_device *adev, bool enable)635{636	uint32_t data1, data3, suvd_flags;637 638	data1 = RREG32(mmUVD_SUVD_CGC_GATE);639	data3 = RREG32(mmUVD_CGC_GATE);640 641	suvd_flags = UVD_SUVD_CGC_GATE__SRE_MASK |642		     UVD_SUVD_CGC_GATE__SIT_MASK |643		     UVD_SUVD_CGC_GATE__SMP_MASK |644		     UVD_SUVD_CGC_GATE__SCM_MASK |645		     UVD_SUVD_CGC_GATE__SDB_MASK;646 647	if (enable) {648		data3 |= (UVD_CGC_GATE__SYS_MASK     |649			UVD_CGC_GATE__UDEC_MASK      |650			UVD_CGC_GATE__MPEG2_MASK     |651			UVD_CGC_GATE__RBC_MASK       |652			UVD_CGC_GATE__LMI_MC_MASK    |653			UVD_CGC_GATE__IDCT_MASK      |654			UVD_CGC_GATE__MPRD_MASK      |655			UVD_CGC_GATE__MPC_MASK       |656			UVD_CGC_GATE__LBSI_MASK      |657			UVD_CGC_GATE__LRBBM_MASK     |658			UVD_CGC_GATE__UDEC_RE_MASK   |659			UVD_CGC_GATE__UDEC_CM_MASK   |660			UVD_CGC_GATE__UDEC_IT_MASK   |661			UVD_CGC_GATE__UDEC_DB_MASK   |662			UVD_CGC_GATE__UDEC_MP_MASK   |663			UVD_CGC_GATE__WCB_MASK       |664			UVD_CGC_GATE__JPEG_MASK      |665			UVD_CGC_GATE__SCPU_MASK);666		/* only in pg enabled, we can gate clock to vcpu*/667		if (adev->pg_flags & AMD_PG_SUPPORT_UVD)668			data3 |= UVD_CGC_GATE__VCPU_MASK;669		data3 &= ~UVD_CGC_GATE__REGS_MASK;670		data1 |= suvd_flags;671	} else {672		data3 = 0;673		data1 = 0;674	}675 676	WREG32(mmUVD_SUVD_CGC_GATE, data1);677	WREG32(mmUVD_CGC_GATE, data3);678}679 680static void uvd_v5_0_set_sw_clock_gating(struct amdgpu_device *adev)681{682	uint32_t data, data2;683 684	data = RREG32(mmUVD_CGC_CTRL);685	data2 = RREG32(mmUVD_SUVD_CGC_CTRL);686 687 688	data &= ~(UVD_CGC_CTRL__CLK_OFF_DELAY_MASK |689		  UVD_CGC_CTRL__CLK_GATE_DLY_TIMER_MASK);690 691 692	data |= UVD_CGC_CTRL__DYN_CLOCK_MODE_MASK |693		(1 << REG_FIELD_SHIFT(UVD_CGC_CTRL, CLK_GATE_DLY_TIMER)) |694		(4 << REG_FIELD_SHIFT(UVD_CGC_CTRL, CLK_OFF_DELAY));695 696	data &= ~(UVD_CGC_CTRL__UDEC_RE_MODE_MASK |697			UVD_CGC_CTRL__UDEC_CM_MODE_MASK |698			UVD_CGC_CTRL__UDEC_IT_MODE_MASK |699			UVD_CGC_CTRL__UDEC_DB_MODE_MASK |700			UVD_CGC_CTRL__UDEC_MP_MODE_MASK |701			UVD_CGC_CTRL__SYS_MODE_MASK |702			UVD_CGC_CTRL__UDEC_MODE_MASK |703			UVD_CGC_CTRL__MPEG2_MODE_MASK |704			UVD_CGC_CTRL__REGS_MODE_MASK |705			UVD_CGC_CTRL__RBC_MODE_MASK |706			UVD_CGC_CTRL__LMI_MC_MODE_MASK |707			UVD_CGC_CTRL__LMI_UMC_MODE_MASK |708			UVD_CGC_CTRL__IDCT_MODE_MASK |709			UVD_CGC_CTRL__MPRD_MODE_MASK |710			UVD_CGC_CTRL__MPC_MODE_MASK |711			UVD_CGC_CTRL__LBSI_MODE_MASK |712			UVD_CGC_CTRL__LRBBM_MODE_MASK |713			UVD_CGC_CTRL__WCB_MODE_MASK |714			UVD_CGC_CTRL__VCPU_MODE_MASK |715			UVD_CGC_CTRL__JPEG_MODE_MASK |716			UVD_CGC_CTRL__SCPU_MODE_MASK);717	data2 &= ~(UVD_SUVD_CGC_CTRL__SRE_MODE_MASK |718			UVD_SUVD_CGC_CTRL__SIT_MODE_MASK |719			UVD_SUVD_CGC_CTRL__SMP_MODE_MASK |720			UVD_SUVD_CGC_CTRL__SCM_MODE_MASK |721			UVD_SUVD_CGC_CTRL__SDB_MODE_MASK);722 723	WREG32(mmUVD_CGC_CTRL, data);724	WREG32(mmUVD_SUVD_CGC_CTRL, data2);725}726 727#if 0728static void uvd_v5_0_set_hw_clock_gating(struct amdgpu_device *adev)729{730	uint32_t data, data1, cgc_flags, suvd_flags;731 732	data = RREG32(mmUVD_CGC_GATE);733	data1 = RREG32(mmUVD_SUVD_CGC_GATE);734 735	cgc_flags = UVD_CGC_GATE__SYS_MASK |736				UVD_CGC_GATE__UDEC_MASK |737				UVD_CGC_GATE__MPEG2_MASK |738				UVD_CGC_GATE__RBC_MASK |739				UVD_CGC_GATE__LMI_MC_MASK |740				UVD_CGC_GATE__IDCT_MASK |741				UVD_CGC_GATE__MPRD_MASK |742				UVD_CGC_GATE__MPC_MASK |743				UVD_CGC_GATE__LBSI_MASK |744				UVD_CGC_GATE__LRBBM_MASK |745				UVD_CGC_GATE__UDEC_RE_MASK |746				UVD_CGC_GATE__UDEC_CM_MASK |747				UVD_CGC_GATE__UDEC_IT_MASK |748				UVD_CGC_GATE__UDEC_DB_MASK |749				UVD_CGC_GATE__UDEC_MP_MASK |750				UVD_CGC_GATE__WCB_MASK |751				UVD_CGC_GATE__VCPU_MASK |752				UVD_CGC_GATE__SCPU_MASK;753 754	suvd_flags = UVD_SUVD_CGC_GATE__SRE_MASK |755				UVD_SUVD_CGC_GATE__SIT_MASK |756				UVD_SUVD_CGC_GATE__SMP_MASK |757				UVD_SUVD_CGC_GATE__SCM_MASK |758				UVD_SUVD_CGC_GATE__SDB_MASK;759 760	data |= cgc_flags;761	data1 |= suvd_flags;762 763	WREG32(mmUVD_CGC_GATE, data);764	WREG32(mmUVD_SUVD_CGC_GATE, data1);765}766#endif767 768static void uvd_v5_0_enable_mgcg(struct amdgpu_device *adev,769				 bool enable)770{771	u32 orig, data;772 773	if (enable && (adev->cg_flags & AMD_CG_SUPPORT_UVD_MGCG)) {774		data = RREG32_UVD_CTX(ixUVD_CGC_MEM_CTRL);775		data |= 0xfff;776		WREG32_UVD_CTX(ixUVD_CGC_MEM_CTRL, data);777 778		orig = data = RREG32(mmUVD_CGC_CTRL);779		data |= UVD_CGC_CTRL__DYN_CLOCK_MODE_MASK;780		if (orig != data)781			WREG32(mmUVD_CGC_CTRL, data);782	} else {783		data = RREG32_UVD_CTX(ixUVD_CGC_MEM_CTRL);784		data &= ~0xfff;785		WREG32_UVD_CTX(ixUVD_CGC_MEM_CTRL, data);786 787		orig = data = RREG32(mmUVD_CGC_CTRL);788		data &= ~UVD_CGC_CTRL__DYN_CLOCK_MODE_MASK;789		if (orig != data)790			WREG32(mmUVD_CGC_CTRL, data);791	}792}793 794static int uvd_v5_0_set_clockgating_state(void *handle,795					  enum amd_clockgating_state state)796{797	struct amdgpu_device *adev = (struct amdgpu_device *)handle;798	bool enable = (state == AMD_CG_STATE_GATE);799 800	if (enable) {801		/* wait for STATUS to clear */802		if (uvd_v5_0_wait_for_idle(handle))803			return -EBUSY;804		uvd_v5_0_enable_clock_gating(adev, true);805 806		/* enable HW gates because UVD is idle */807/*		uvd_v5_0_set_hw_clock_gating(adev); */808	} else {809		uvd_v5_0_enable_clock_gating(adev, false);810	}811 812	uvd_v5_0_set_sw_clock_gating(adev);813	return 0;814}815 816static int uvd_v5_0_set_powergating_state(void *handle,817					  enum amd_powergating_state state)818{819	/* This doesn't actually powergate the UVD block.820	 * That's done in the dpm code via the SMC.  This821	 * just re-inits the block as necessary.  The actual822	 * gating still happens in the dpm code.  We should823	 * revisit this when there is a cleaner line between824	 * the smc and the hw blocks825	 */826	struct amdgpu_device *adev = (struct amdgpu_device *)handle;827	int ret = 0;828 829	if (state == AMD_PG_STATE_GATE) {830		uvd_v5_0_stop(adev);831	} else {832		ret = uvd_v5_0_start(adev);833		if (ret)834			goto out;835	}836 837out:838	return ret;839}840 841static void uvd_v5_0_get_clockgating_state(void *handle, u64 *flags)842{843	struct amdgpu_device *adev = (struct amdgpu_device *)handle;844	int data;845 846	mutex_lock(&adev->pm.mutex);847 848	if (RREG32_SMC(ixCURRENT_PG_STATUS) &849				CURRENT_PG_STATUS__UVD_PG_STATUS_MASK) {850		DRM_INFO("Cannot get clockgating state when UVD is powergated.\n");851		goto out;852	}853 854	/* AMD_CG_SUPPORT_UVD_MGCG */855	data = RREG32(mmUVD_CGC_CTRL);856	if (data & UVD_CGC_CTRL__DYN_CLOCK_MODE_MASK)857		*flags |= AMD_CG_SUPPORT_UVD_MGCG;858 859out:860	mutex_unlock(&adev->pm.mutex);861}862 863static const struct amd_ip_funcs uvd_v5_0_ip_funcs = {864	.name = "uvd_v5_0",865	.early_init = uvd_v5_0_early_init,866	.late_init = NULL,867	.sw_init = uvd_v5_0_sw_init,868	.sw_fini = uvd_v5_0_sw_fini,869	.hw_init = uvd_v5_0_hw_init,870	.hw_fini = uvd_v5_0_hw_fini,871	.prepare_suspend = uvd_v5_0_prepare_suspend,872	.suspend = uvd_v5_0_suspend,873	.resume = uvd_v5_0_resume,874	.is_idle = uvd_v5_0_is_idle,875	.wait_for_idle = uvd_v5_0_wait_for_idle,876	.soft_reset = uvd_v5_0_soft_reset,877	.set_clockgating_state = uvd_v5_0_set_clockgating_state,878	.set_powergating_state = uvd_v5_0_set_powergating_state,879	.get_clockgating_state = uvd_v5_0_get_clockgating_state,880	.dump_ip_state = NULL,881	.print_ip_state = NULL,882};883 884static const struct amdgpu_ring_funcs uvd_v5_0_ring_funcs = {885	.type = AMDGPU_RING_TYPE_UVD,886	.align_mask = 0xf,887	.support_64bit_ptrs = false,888	.no_user_fence = true,889	.get_rptr = uvd_v5_0_ring_get_rptr,890	.get_wptr = uvd_v5_0_ring_get_wptr,891	.set_wptr = uvd_v5_0_ring_set_wptr,892	.parse_cs = amdgpu_uvd_ring_parse_cs,893	.emit_frame_size =894		14, /* uvd_v5_0_ring_emit_fence  x1 no user fence */895	.emit_ib_size = 6, /* uvd_v5_0_ring_emit_ib */896	.emit_ib = uvd_v5_0_ring_emit_ib,897	.emit_fence = uvd_v5_0_ring_emit_fence,898	.test_ring = uvd_v5_0_ring_test_ring,899	.test_ib = amdgpu_uvd_ring_test_ib,900	.insert_nop = uvd_v5_0_ring_insert_nop,901	.pad_ib = amdgpu_ring_generic_pad_ib,902	.begin_use = amdgpu_uvd_ring_begin_use,903	.end_use = amdgpu_uvd_ring_end_use,904};905 906static void uvd_v5_0_set_ring_funcs(struct amdgpu_device *adev)907{908	adev->uvd.inst->ring.funcs = &uvd_v5_0_ring_funcs;909}910 911static const struct amdgpu_irq_src_funcs uvd_v5_0_irq_funcs = {912	.set = uvd_v5_0_set_interrupt_state,913	.process = uvd_v5_0_process_interrupt,914};915 916static void uvd_v5_0_set_irq_funcs(struct amdgpu_device *adev)917{918	adev->uvd.inst->irq.num_types = 1;919	adev->uvd.inst->irq.funcs = &uvd_v5_0_irq_funcs;920}921 922const struct amdgpu_ip_block_version uvd_v5_0_ip_block =923{924		.type = AMD_IP_BLOCK_TYPE_UVD,925		.major = 5,926		.minor = 0,927		.rev = 0,928		.funcs = &uvd_v5_0_ip_funcs,929};930