162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright 2013 Advanced Micro Devices, Inc.
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
562306a36Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
662306a36Sopenharmony_ci * to deal in the Software without restriction, including without limitation
762306a36Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
862306a36Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
962306a36Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * The above copyright notice and this permission notice shall be included in
1262306a36Sopenharmony_ci * all copies or substantial portions of the Software.
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1562306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1662306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1762306a36Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
1862306a36Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
1962306a36Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
2062306a36Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE.
2162306a36Sopenharmony_ci *
2262306a36Sopenharmony_ci * Authors: Christian König <christian.koenig@amd.com>
2362306a36Sopenharmony_ci */
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#include <linux/firmware.h>
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#include "radeon.h"
2862306a36Sopenharmony_ci#include "radeon_asic.h"
2962306a36Sopenharmony_ci#include "r600d.h"
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci/**
3262306a36Sopenharmony_ci * uvd_v1_0_get_rptr - get read pointer
3362306a36Sopenharmony_ci *
3462306a36Sopenharmony_ci * @rdev: radeon_device pointer
3562306a36Sopenharmony_ci * @ring: radeon_ring pointer
3662306a36Sopenharmony_ci *
3762306a36Sopenharmony_ci * Returns the current hardware read pointer
3862306a36Sopenharmony_ci */
3962306a36Sopenharmony_ciuint32_t uvd_v1_0_get_rptr(struct radeon_device *rdev,
4062306a36Sopenharmony_ci			   struct radeon_ring *ring)
4162306a36Sopenharmony_ci{
4262306a36Sopenharmony_ci	return RREG32(UVD_RBC_RB_RPTR);
4362306a36Sopenharmony_ci}
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci/**
4662306a36Sopenharmony_ci * uvd_v1_0_get_wptr - get write pointer
4762306a36Sopenharmony_ci *
4862306a36Sopenharmony_ci * @rdev: radeon_device pointer
4962306a36Sopenharmony_ci * @ring: radeon_ring pointer
5062306a36Sopenharmony_ci *
5162306a36Sopenharmony_ci * Returns the current hardware write pointer
5262306a36Sopenharmony_ci */
5362306a36Sopenharmony_ciuint32_t uvd_v1_0_get_wptr(struct radeon_device *rdev,
5462306a36Sopenharmony_ci			   struct radeon_ring *ring)
5562306a36Sopenharmony_ci{
5662306a36Sopenharmony_ci	return RREG32(UVD_RBC_RB_WPTR);
5762306a36Sopenharmony_ci}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci/**
6062306a36Sopenharmony_ci * uvd_v1_0_set_wptr - set write pointer
6162306a36Sopenharmony_ci *
6262306a36Sopenharmony_ci * @rdev: radeon_device pointer
6362306a36Sopenharmony_ci * @ring: radeon_ring pointer
6462306a36Sopenharmony_ci *
6562306a36Sopenharmony_ci * Commits the write pointer to the hardware
6662306a36Sopenharmony_ci */
6762306a36Sopenharmony_civoid uvd_v1_0_set_wptr(struct radeon_device *rdev,
6862306a36Sopenharmony_ci		       struct radeon_ring *ring)
6962306a36Sopenharmony_ci{
7062306a36Sopenharmony_ci	WREG32(UVD_RBC_RB_WPTR, ring->wptr);
7162306a36Sopenharmony_ci}
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci/**
7462306a36Sopenharmony_ci * uvd_v1_0_fence_emit - emit an fence & trap command
7562306a36Sopenharmony_ci *
7662306a36Sopenharmony_ci * @rdev: radeon_device pointer
7762306a36Sopenharmony_ci * @fence: fence to emit
7862306a36Sopenharmony_ci *
7962306a36Sopenharmony_ci * Write a fence and a trap command to the ring.
8062306a36Sopenharmony_ci */
8162306a36Sopenharmony_civoid uvd_v1_0_fence_emit(struct radeon_device *rdev,
8262306a36Sopenharmony_ci			 struct radeon_fence *fence)
8362306a36Sopenharmony_ci{
8462306a36Sopenharmony_ci	struct radeon_ring *ring = &rdev->ring[fence->ring];
8562306a36Sopenharmony_ci	uint64_t addr = rdev->fence_drv[fence->ring].gpu_addr;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_DATA0, 0));
8862306a36Sopenharmony_ci	radeon_ring_write(ring, addr & 0xffffffff);
8962306a36Sopenharmony_ci	radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_DATA1, 0));
9062306a36Sopenharmony_ci	radeon_ring_write(ring, fence->seq);
9162306a36Sopenharmony_ci	radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_CMD, 0));
9262306a36Sopenharmony_ci	radeon_ring_write(ring, 0);
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_DATA0, 0));
9562306a36Sopenharmony_ci	radeon_ring_write(ring, 0);
9662306a36Sopenharmony_ci	radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_DATA1, 0));
9762306a36Sopenharmony_ci	radeon_ring_write(ring, 0);
9862306a36Sopenharmony_ci	radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_CMD, 0));
9962306a36Sopenharmony_ci	radeon_ring_write(ring, 2);
10062306a36Sopenharmony_ci	return;
10162306a36Sopenharmony_ci}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci/**
10462306a36Sopenharmony_ci * uvd_v1_0_resume - memory controller programming
10562306a36Sopenharmony_ci *
10662306a36Sopenharmony_ci * @rdev: radeon_device pointer
10762306a36Sopenharmony_ci *
10862306a36Sopenharmony_ci * Let the UVD memory controller know it's offsets
10962306a36Sopenharmony_ci */
11062306a36Sopenharmony_ciint uvd_v1_0_resume(struct radeon_device *rdev)
11162306a36Sopenharmony_ci{
11262306a36Sopenharmony_ci	uint64_t addr;
11362306a36Sopenharmony_ci	uint32_t size;
11462306a36Sopenharmony_ci	int r;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	r = radeon_uvd_resume(rdev);
11762306a36Sopenharmony_ci	if (r)
11862306a36Sopenharmony_ci		return r;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	/* program the VCPU memory controller bits 0-27 */
12162306a36Sopenharmony_ci	addr = (rdev->uvd.gpu_addr >> 3) + 16;
12262306a36Sopenharmony_ci	size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->size) >> 3;
12362306a36Sopenharmony_ci	WREG32(UVD_VCPU_CACHE_OFFSET0, addr);
12462306a36Sopenharmony_ci	WREG32(UVD_VCPU_CACHE_SIZE0, size);
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	addr += size;
12762306a36Sopenharmony_ci	size = RADEON_UVD_HEAP_SIZE >> 3;
12862306a36Sopenharmony_ci	WREG32(UVD_VCPU_CACHE_OFFSET1, addr);
12962306a36Sopenharmony_ci	WREG32(UVD_VCPU_CACHE_SIZE1, size);
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	addr += size;
13262306a36Sopenharmony_ci	size = (RADEON_UVD_STACK_SIZE +
13362306a36Sopenharmony_ci	       (RADEON_UVD_SESSION_SIZE * rdev->uvd.max_handles)) >> 3;
13462306a36Sopenharmony_ci	WREG32(UVD_VCPU_CACHE_OFFSET2, addr);
13562306a36Sopenharmony_ci	WREG32(UVD_VCPU_CACHE_SIZE2, size);
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	/* bits 28-31 */
13862306a36Sopenharmony_ci	addr = (rdev->uvd.gpu_addr >> 28) & 0xF;
13962306a36Sopenharmony_ci	WREG32(UVD_LMI_ADDR_EXT, (addr << 12) | (addr << 0));
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	/* bits 32-39 */
14262306a36Sopenharmony_ci	addr = (rdev->uvd.gpu_addr >> 32) & 0xFF;
14362306a36Sopenharmony_ci	WREG32(UVD_LMI_EXT40_ADDR, addr | (0x9 << 16) | (0x1 << 31));
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	WREG32(UVD_FW_START, *((uint32_t*)rdev->uvd.cpu_addr));
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	return 0;
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci/**
15162306a36Sopenharmony_ci * uvd_v1_0_init - start and test UVD block
15262306a36Sopenharmony_ci *
15362306a36Sopenharmony_ci * @rdev: radeon_device pointer
15462306a36Sopenharmony_ci *
15562306a36Sopenharmony_ci * Initialize the hardware, boot up the VCPU and do some testing
15662306a36Sopenharmony_ci */
15762306a36Sopenharmony_ciint uvd_v1_0_init(struct radeon_device *rdev)
15862306a36Sopenharmony_ci{
15962306a36Sopenharmony_ci	struct radeon_ring *ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX];
16062306a36Sopenharmony_ci	uint32_t tmp;
16162306a36Sopenharmony_ci	int r;
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	/* raise clocks while booting up the VCPU */
16462306a36Sopenharmony_ci	if (rdev->family < CHIP_RV740)
16562306a36Sopenharmony_ci		radeon_set_uvd_clocks(rdev, 10000, 10000);
16662306a36Sopenharmony_ci	else
16762306a36Sopenharmony_ci		radeon_set_uvd_clocks(rdev, 53300, 40000);
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	r = uvd_v1_0_start(rdev);
17062306a36Sopenharmony_ci	if (r)
17162306a36Sopenharmony_ci		goto done;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	ring->ready = true;
17462306a36Sopenharmony_ci	r = radeon_ring_test(rdev, R600_RING_TYPE_UVD_INDEX, ring);
17562306a36Sopenharmony_ci	if (r) {
17662306a36Sopenharmony_ci		ring->ready = false;
17762306a36Sopenharmony_ci		goto done;
17862306a36Sopenharmony_ci	}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	r = radeon_ring_lock(rdev, ring, 10);
18162306a36Sopenharmony_ci	if (r) {
18262306a36Sopenharmony_ci		DRM_ERROR("radeon: ring failed to lock UVD ring (%d).\n", r);
18362306a36Sopenharmony_ci		goto done;
18462306a36Sopenharmony_ci	}
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	tmp = PACKET0(UVD_SEMA_WAIT_FAULT_TIMEOUT_CNTL, 0);
18762306a36Sopenharmony_ci	radeon_ring_write(ring, tmp);
18862306a36Sopenharmony_ci	radeon_ring_write(ring, 0xFFFFF);
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	tmp = PACKET0(UVD_SEMA_WAIT_INCOMPLETE_TIMEOUT_CNTL, 0);
19162306a36Sopenharmony_ci	radeon_ring_write(ring, tmp);
19262306a36Sopenharmony_ci	radeon_ring_write(ring, 0xFFFFF);
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	tmp = PACKET0(UVD_SEMA_SIGNAL_INCOMPLETE_TIMEOUT_CNTL, 0);
19562306a36Sopenharmony_ci	radeon_ring_write(ring, tmp);
19662306a36Sopenharmony_ci	radeon_ring_write(ring, 0xFFFFF);
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	/* Clear timeout status bits */
19962306a36Sopenharmony_ci	radeon_ring_write(ring, PACKET0(UVD_SEMA_TIMEOUT_STATUS, 0));
20062306a36Sopenharmony_ci	radeon_ring_write(ring, 0x8);
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	radeon_ring_write(ring, PACKET0(UVD_SEMA_CNTL, 0));
20362306a36Sopenharmony_ci	radeon_ring_write(ring, 3);
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	radeon_ring_unlock_commit(rdev, ring, false);
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_cidone:
20862306a36Sopenharmony_ci	/* lower clocks again */
20962306a36Sopenharmony_ci	radeon_set_uvd_clocks(rdev, 0, 0);
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	if (!r) {
21262306a36Sopenharmony_ci		switch (rdev->family) {
21362306a36Sopenharmony_ci		case CHIP_RV610:
21462306a36Sopenharmony_ci		case CHIP_RV630:
21562306a36Sopenharmony_ci		case CHIP_RV620:
21662306a36Sopenharmony_ci			/* 64byte granularity workaround */
21762306a36Sopenharmony_ci			WREG32(MC_CONFIG, 0);
21862306a36Sopenharmony_ci			WREG32(MC_CONFIG, 1 << 4);
21962306a36Sopenharmony_ci			WREG32(RS_DQ_RD_RET_CONF, 0x3f);
22062306a36Sopenharmony_ci			WREG32(MC_CONFIG, 0x1f);
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci			fallthrough;
22362306a36Sopenharmony_ci		case CHIP_RV670:
22462306a36Sopenharmony_ci		case CHIP_RV635:
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci			/* write clean workaround */
22762306a36Sopenharmony_ci			WREG32_P(UVD_VCPU_CNTL, 0x10, ~0x10);
22862306a36Sopenharmony_ci			break;
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci		default:
23162306a36Sopenharmony_ci			/* TODO: Do we need more? */
23262306a36Sopenharmony_ci			break;
23362306a36Sopenharmony_ci		}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci		DRM_INFO("UVD initialized successfully.\n");
23662306a36Sopenharmony_ci	}
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	return r;
23962306a36Sopenharmony_ci}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci/**
24262306a36Sopenharmony_ci * uvd_v1_0_fini - stop the hardware block
24362306a36Sopenharmony_ci *
24462306a36Sopenharmony_ci * @rdev: radeon_device pointer
24562306a36Sopenharmony_ci *
24662306a36Sopenharmony_ci * Stop the UVD block, mark ring as not ready any more
24762306a36Sopenharmony_ci */
24862306a36Sopenharmony_civoid uvd_v1_0_fini(struct radeon_device *rdev)
24962306a36Sopenharmony_ci{
25062306a36Sopenharmony_ci	struct radeon_ring *ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX];
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	uvd_v1_0_stop(rdev);
25362306a36Sopenharmony_ci	ring->ready = false;
25462306a36Sopenharmony_ci}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci/**
25762306a36Sopenharmony_ci * uvd_v1_0_start - start UVD block
25862306a36Sopenharmony_ci *
25962306a36Sopenharmony_ci * @rdev: radeon_device pointer
26062306a36Sopenharmony_ci *
26162306a36Sopenharmony_ci * Setup and start the UVD block
26262306a36Sopenharmony_ci */
26362306a36Sopenharmony_ciint uvd_v1_0_start(struct radeon_device *rdev)
26462306a36Sopenharmony_ci{
26562306a36Sopenharmony_ci	struct radeon_ring *ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX];
26662306a36Sopenharmony_ci	uint32_t rb_bufsz;
26762306a36Sopenharmony_ci	int i, j, r;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	/* disable byte swapping */
27062306a36Sopenharmony_ci	u32 lmi_swap_cntl = 0;
27162306a36Sopenharmony_ci	u32 mp_swap_cntl = 0;
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	/* disable clock gating */
27462306a36Sopenharmony_ci	WREG32(UVD_CGC_GATE, 0);
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	/* disable interupt */
27762306a36Sopenharmony_ci	WREG32_P(UVD_MASTINT_EN, 0, ~(1 << 1));
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	/* Stall UMC and register bus before resetting VCPU */
28062306a36Sopenharmony_ci	WREG32_P(UVD_LMI_CTRL2, 1 << 8, ~(1 << 8));
28162306a36Sopenharmony_ci	WREG32_P(UVD_RB_ARB_CTRL, 1 << 3, ~(1 << 3));
28262306a36Sopenharmony_ci	mdelay(1);
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	/* put LMI, VCPU, RBC etc... into reset */
28562306a36Sopenharmony_ci	WREG32(UVD_SOFT_RESET, LMI_SOFT_RESET | VCPU_SOFT_RESET |
28662306a36Sopenharmony_ci	       LBSI_SOFT_RESET | RBC_SOFT_RESET | CSM_SOFT_RESET |
28762306a36Sopenharmony_ci	       CXW_SOFT_RESET | TAP_SOFT_RESET | LMI_UMC_SOFT_RESET);
28862306a36Sopenharmony_ci	mdelay(5);
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	/* take UVD block out of reset */
29162306a36Sopenharmony_ci	WREG32_P(SRBM_SOFT_RESET, 0, ~SOFT_RESET_UVD);
29262306a36Sopenharmony_ci	mdelay(5);
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	/* initialize UVD memory controller */
29562306a36Sopenharmony_ci	WREG32(UVD_LMI_CTRL, 0x40 | (1 << 8) | (1 << 13) |
29662306a36Sopenharmony_ci			     (1 << 21) | (1 << 9) | (1 << 20));
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci#ifdef __BIG_ENDIAN
29962306a36Sopenharmony_ci	/* swap (8 in 32) RB and IB */
30062306a36Sopenharmony_ci	lmi_swap_cntl = 0xa;
30162306a36Sopenharmony_ci	mp_swap_cntl = 0;
30262306a36Sopenharmony_ci#endif
30362306a36Sopenharmony_ci	WREG32(UVD_LMI_SWAP_CNTL, lmi_swap_cntl);
30462306a36Sopenharmony_ci	WREG32(UVD_MP_SWAP_CNTL, mp_swap_cntl);
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	WREG32(UVD_MPC_SET_MUXA0, 0x40c2040);
30762306a36Sopenharmony_ci	WREG32(UVD_MPC_SET_MUXA1, 0x0);
30862306a36Sopenharmony_ci	WREG32(UVD_MPC_SET_MUXB0, 0x40c2040);
30962306a36Sopenharmony_ci	WREG32(UVD_MPC_SET_MUXB1, 0x0);
31062306a36Sopenharmony_ci	WREG32(UVD_MPC_SET_ALU, 0);
31162306a36Sopenharmony_ci	WREG32(UVD_MPC_SET_MUX, 0x88);
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	/* take all subblocks out of reset, except VCPU */
31462306a36Sopenharmony_ci	WREG32(UVD_SOFT_RESET, VCPU_SOFT_RESET);
31562306a36Sopenharmony_ci	mdelay(5);
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	/* enable VCPU clock */
31862306a36Sopenharmony_ci	WREG32(UVD_VCPU_CNTL,  1 << 9);
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	/* enable UMC */
32162306a36Sopenharmony_ci	WREG32_P(UVD_LMI_CTRL2, 0, ~(1 << 8));
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	WREG32_P(UVD_RB_ARB_CTRL, 0, ~(1 << 3));
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	/* boot up the VCPU */
32662306a36Sopenharmony_ci	WREG32(UVD_SOFT_RESET, 0);
32762306a36Sopenharmony_ci	mdelay(10);
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	for (i = 0; i < 10; ++i) {
33062306a36Sopenharmony_ci		uint32_t status;
33162306a36Sopenharmony_ci		for (j = 0; j < 100; ++j) {
33262306a36Sopenharmony_ci			status = RREG32(UVD_STATUS);
33362306a36Sopenharmony_ci			if (status & 2)
33462306a36Sopenharmony_ci				break;
33562306a36Sopenharmony_ci			mdelay(10);
33662306a36Sopenharmony_ci		}
33762306a36Sopenharmony_ci		r = 0;
33862306a36Sopenharmony_ci		if (status & 2)
33962306a36Sopenharmony_ci			break;
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci		DRM_ERROR("UVD not responding, trying to reset the VCPU!!!\n");
34262306a36Sopenharmony_ci		WREG32_P(UVD_SOFT_RESET, VCPU_SOFT_RESET, ~VCPU_SOFT_RESET);
34362306a36Sopenharmony_ci		mdelay(10);
34462306a36Sopenharmony_ci		WREG32_P(UVD_SOFT_RESET, 0, ~VCPU_SOFT_RESET);
34562306a36Sopenharmony_ci		mdelay(10);
34662306a36Sopenharmony_ci		r = -1;
34762306a36Sopenharmony_ci	}
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	if (r) {
35062306a36Sopenharmony_ci		DRM_ERROR("UVD not responding, giving up!!!\n");
35162306a36Sopenharmony_ci		return r;
35262306a36Sopenharmony_ci	}
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	/* enable interupt */
35562306a36Sopenharmony_ci	WREG32_P(UVD_MASTINT_EN, 3<<1, ~(3 << 1));
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	/* force RBC into idle state */
35862306a36Sopenharmony_ci	WREG32(UVD_RBC_RB_CNTL, 0x11010101);
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	/* Set the write pointer delay */
36162306a36Sopenharmony_ci	WREG32(UVD_RBC_RB_WPTR_CNTL, 0);
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	/* program the 4GB memory segment for rptr and ring buffer */
36462306a36Sopenharmony_ci	WREG32(UVD_LMI_EXT40_ADDR, upper_32_bits(ring->gpu_addr) |
36562306a36Sopenharmony_ci				   (0x7 << 16) | (0x1 << 31));
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	/* Initialize the ring buffer's read and write pointers */
36862306a36Sopenharmony_ci	WREG32(UVD_RBC_RB_RPTR, 0x0);
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	ring->wptr = RREG32(UVD_RBC_RB_RPTR);
37162306a36Sopenharmony_ci	WREG32(UVD_RBC_RB_WPTR, ring->wptr);
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	/* set the ring address */
37462306a36Sopenharmony_ci	WREG32(UVD_RBC_RB_BASE, ring->gpu_addr);
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	/* Set ring buffer size */
37762306a36Sopenharmony_ci	rb_bufsz = order_base_2(ring->ring_size);
37862306a36Sopenharmony_ci	rb_bufsz = (0x1 << 8) | rb_bufsz;
37962306a36Sopenharmony_ci	WREG32_P(UVD_RBC_RB_CNTL, rb_bufsz, ~0x11f1f);
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	return 0;
38262306a36Sopenharmony_ci}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci/**
38562306a36Sopenharmony_ci * uvd_v1_0_stop - stop UVD block
38662306a36Sopenharmony_ci *
38762306a36Sopenharmony_ci * @rdev: radeon_device pointer
38862306a36Sopenharmony_ci *
38962306a36Sopenharmony_ci * stop the UVD block
39062306a36Sopenharmony_ci */
39162306a36Sopenharmony_civoid uvd_v1_0_stop(struct radeon_device *rdev)
39262306a36Sopenharmony_ci{
39362306a36Sopenharmony_ci	/* force RBC into idle state */
39462306a36Sopenharmony_ci	WREG32(UVD_RBC_RB_CNTL, 0x11010101);
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	/* Stall UMC and register bus before resetting VCPU */
39762306a36Sopenharmony_ci	WREG32_P(UVD_LMI_CTRL2, 1 << 8, ~(1 << 8));
39862306a36Sopenharmony_ci	WREG32_P(UVD_RB_ARB_CTRL, 1 << 3, ~(1 << 3));
39962306a36Sopenharmony_ci	mdelay(1);
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	/* put VCPU into reset */
40262306a36Sopenharmony_ci	WREG32(UVD_SOFT_RESET, VCPU_SOFT_RESET);
40362306a36Sopenharmony_ci	mdelay(5);
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	/* disable VCPU clock */
40662306a36Sopenharmony_ci	WREG32(UVD_VCPU_CNTL, 0x0);
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	/* Unstall UMC and register bus */
40962306a36Sopenharmony_ci	WREG32_P(UVD_LMI_CTRL2, 0, ~(1 << 8));
41062306a36Sopenharmony_ci	WREG32_P(UVD_RB_ARB_CTRL, 0, ~(1 << 3));
41162306a36Sopenharmony_ci}
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci/**
41462306a36Sopenharmony_ci * uvd_v1_0_ring_test - register write test
41562306a36Sopenharmony_ci *
41662306a36Sopenharmony_ci * @rdev: radeon_device pointer
41762306a36Sopenharmony_ci * @ring: radeon_ring pointer
41862306a36Sopenharmony_ci *
41962306a36Sopenharmony_ci * Test if we can successfully write to the context register
42062306a36Sopenharmony_ci */
42162306a36Sopenharmony_ciint uvd_v1_0_ring_test(struct radeon_device *rdev, struct radeon_ring *ring)
42262306a36Sopenharmony_ci{
42362306a36Sopenharmony_ci	uint32_t tmp = 0;
42462306a36Sopenharmony_ci	unsigned i;
42562306a36Sopenharmony_ci	int r;
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	WREG32(UVD_CONTEXT_ID, 0xCAFEDEAD);
42862306a36Sopenharmony_ci	r = radeon_ring_lock(rdev, ring, 3);
42962306a36Sopenharmony_ci	if (r) {
43062306a36Sopenharmony_ci		DRM_ERROR("radeon: cp failed to lock ring %d (%d).\n",
43162306a36Sopenharmony_ci			  ring->idx, r);
43262306a36Sopenharmony_ci		return r;
43362306a36Sopenharmony_ci	}
43462306a36Sopenharmony_ci	radeon_ring_write(ring, PACKET0(UVD_CONTEXT_ID, 0));
43562306a36Sopenharmony_ci	radeon_ring_write(ring, 0xDEADBEEF);
43662306a36Sopenharmony_ci	radeon_ring_unlock_commit(rdev, ring, false);
43762306a36Sopenharmony_ci	for (i = 0; i < rdev->usec_timeout; i++) {
43862306a36Sopenharmony_ci		tmp = RREG32(UVD_CONTEXT_ID);
43962306a36Sopenharmony_ci		if (tmp == 0xDEADBEEF)
44062306a36Sopenharmony_ci			break;
44162306a36Sopenharmony_ci		udelay(1);
44262306a36Sopenharmony_ci	}
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	if (i < rdev->usec_timeout) {
44562306a36Sopenharmony_ci		DRM_INFO("ring test on %d succeeded in %d usecs\n",
44662306a36Sopenharmony_ci			 ring->idx, i);
44762306a36Sopenharmony_ci	} else {
44862306a36Sopenharmony_ci		DRM_ERROR("radeon: ring %d test failed (0x%08X)\n",
44962306a36Sopenharmony_ci			  ring->idx, tmp);
45062306a36Sopenharmony_ci		r = -EINVAL;
45162306a36Sopenharmony_ci	}
45262306a36Sopenharmony_ci	return r;
45362306a36Sopenharmony_ci}
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci/**
45662306a36Sopenharmony_ci * uvd_v1_0_semaphore_emit - emit semaphore command
45762306a36Sopenharmony_ci *
45862306a36Sopenharmony_ci * @rdev: radeon_device pointer
45962306a36Sopenharmony_ci * @ring: radeon_ring pointer
46062306a36Sopenharmony_ci * @semaphore: semaphore to emit commands for
46162306a36Sopenharmony_ci * @emit_wait: true if we should emit a wait command
46262306a36Sopenharmony_ci *
46362306a36Sopenharmony_ci * Emit a semaphore command (either wait or signal) to the UVD ring.
46462306a36Sopenharmony_ci */
46562306a36Sopenharmony_cibool uvd_v1_0_semaphore_emit(struct radeon_device *rdev,
46662306a36Sopenharmony_ci			     struct radeon_ring *ring,
46762306a36Sopenharmony_ci			     struct radeon_semaphore *semaphore,
46862306a36Sopenharmony_ci			     bool emit_wait)
46962306a36Sopenharmony_ci{
47062306a36Sopenharmony_ci	/* disable semaphores for UVD V1 hardware */
47162306a36Sopenharmony_ci	return false;
47262306a36Sopenharmony_ci}
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci/**
47562306a36Sopenharmony_ci * uvd_v1_0_ib_execute - execute indirect buffer
47662306a36Sopenharmony_ci *
47762306a36Sopenharmony_ci * @rdev: radeon_device pointer
47862306a36Sopenharmony_ci * @ib: indirect buffer to execute
47962306a36Sopenharmony_ci *
48062306a36Sopenharmony_ci * Write ring commands to execute the indirect buffer
48162306a36Sopenharmony_ci */
48262306a36Sopenharmony_civoid uvd_v1_0_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib)
48362306a36Sopenharmony_ci{
48462306a36Sopenharmony_ci	struct radeon_ring *ring = &rdev->ring[ib->ring];
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	radeon_ring_write(ring, PACKET0(UVD_RBC_IB_BASE, 0));
48762306a36Sopenharmony_ci	radeon_ring_write(ring, ib->gpu_addr);
48862306a36Sopenharmony_ci	radeon_ring_write(ring, PACKET0(UVD_RBC_IB_SIZE, 0));
48962306a36Sopenharmony_ci	radeon_ring_write(ring, ib->length_dw);
49062306a36Sopenharmony_ci}
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci/**
49362306a36Sopenharmony_ci * uvd_v1_0_ib_test - test ib execution
49462306a36Sopenharmony_ci *
49562306a36Sopenharmony_ci * @rdev: radeon_device pointer
49662306a36Sopenharmony_ci * @ring: radeon_ring pointer
49762306a36Sopenharmony_ci *
49862306a36Sopenharmony_ci * Test if we can successfully execute an IB
49962306a36Sopenharmony_ci */
50062306a36Sopenharmony_ciint uvd_v1_0_ib_test(struct radeon_device *rdev, struct radeon_ring *ring)
50162306a36Sopenharmony_ci{
50262306a36Sopenharmony_ci	struct radeon_fence *fence = NULL;
50362306a36Sopenharmony_ci	int r;
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	if (rdev->family < CHIP_RV740)
50662306a36Sopenharmony_ci		r = radeon_set_uvd_clocks(rdev, 10000, 10000);
50762306a36Sopenharmony_ci	else
50862306a36Sopenharmony_ci		r = radeon_set_uvd_clocks(rdev, 53300, 40000);
50962306a36Sopenharmony_ci	if (r) {
51062306a36Sopenharmony_ci		DRM_ERROR("radeon: failed to raise UVD clocks (%d).\n", r);
51162306a36Sopenharmony_ci		return r;
51262306a36Sopenharmony_ci	}
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	r = radeon_uvd_get_create_msg(rdev, ring->idx, 1, NULL);
51562306a36Sopenharmony_ci	if (r) {
51662306a36Sopenharmony_ci		DRM_ERROR("radeon: failed to get create msg (%d).\n", r);
51762306a36Sopenharmony_ci		goto error;
51862306a36Sopenharmony_ci	}
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	r = radeon_uvd_get_destroy_msg(rdev, ring->idx, 1, &fence);
52162306a36Sopenharmony_ci	if (r) {
52262306a36Sopenharmony_ci		DRM_ERROR("radeon: failed to get destroy ib (%d).\n", r);
52362306a36Sopenharmony_ci		goto error;
52462306a36Sopenharmony_ci	}
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	r = radeon_fence_wait_timeout(fence, false, usecs_to_jiffies(
52762306a36Sopenharmony_ci		RADEON_USEC_IB_TEST_TIMEOUT));
52862306a36Sopenharmony_ci	if (r < 0) {
52962306a36Sopenharmony_ci		DRM_ERROR("radeon: fence wait failed (%d).\n", r);
53062306a36Sopenharmony_ci		goto error;
53162306a36Sopenharmony_ci	} else if (r == 0) {
53262306a36Sopenharmony_ci		DRM_ERROR("radeon: fence wait timed out.\n");
53362306a36Sopenharmony_ci		r = -ETIMEDOUT;
53462306a36Sopenharmony_ci		goto error;
53562306a36Sopenharmony_ci	}
53662306a36Sopenharmony_ci	r = 0;
53762306a36Sopenharmony_ci	DRM_INFO("ib test on ring %d succeeded\n",  ring->idx);
53862306a36Sopenharmony_cierror:
53962306a36Sopenharmony_ci	radeon_fence_unref(&fence);
54062306a36Sopenharmony_ci	radeon_set_uvd_clocks(rdev, 0, 0);
54162306a36Sopenharmony_ci	return r;
54262306a36Sopenharmony_ci}
543