18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright 2013 Advanced Micro Devices, Inc.
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
58c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
68c2ecf20Sopenharmony_ci * to deal in the Software without restriction, including without limitation
78c2ecf20Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
88c2ecf20Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
98c2ecf20Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice shall be included in
128c2ecf20Sopenharmony_ci * all copies or substantial portions of the Software.
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
158c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
168c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
178c2ecf20Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
188c2ecf20Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
198c2ecf20Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
208c2ecf20Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE.
218c2ecf20Sopenharmony_ci *
228c2ecf20Sopenharmony_ci * Authors: Christian König <christian.koenig@amd.com>
238c2ecf20Sopenharmony_ci */
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#include <linux/firmware.h>
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#include "radeon.h"
288c2ecf20Sopenharmony_ci#include "radeon_asic.h"
298c2ecf20Sopenharmony_ci#include "r600d.h"
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci/**
328c2ecf20Sopenharmony_ci * uvd_v1_0_get_rptr - get read pointer
338c2ecf20Sopenharmony_ci *
348c2ecf20Sopenharmony_ci * @rdev: radeon_device pointer
358c2ecf20Sopenharmony_ci * @ring: radeon_ring pointer
368c2ecf20Sopenharmony_ci *
378c2ecf20Sopenharmony_ci * Returns the current hardware read pointer
388c2ecf20Sopenharmony_ci */
398c2ecf20Sopenharmony_ciuint32_t uvd_v1_0_get_rptr(struct radeon_device *rdev,
408c2ecf20Sopenharmony_ci			   struct radeon_ring *ring)
418c2ecf20Sopenharmony_ci{
428c2ecf20Sopenharmony_ci	return RREG32(UVD_RBC_RB_RPTR);
438c2ecf20Sopenharmony_ci}
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci/**
468c2ecf20Sopenharmony_ci * uvd_v1_0_get_wptr - get write pointer
478c2ecf20Sopenharmony_ci *
488c2ecf20Sopenharmony_ci * @rdev: radeon_device pointer
498c2ecf20Sopenharmony_ci * @ring: radeon_ring pointer
508c2ecf20Sopenharmony_ci *
518c2ecf20Sopenharmony_ci * Returns the current hardware write pointer
528c2ecf20Sopenharmony_ci */
538c2ecf20Sopenharmony_ciuint32_t uvd_v1_0_get_wptr(struct radeon_device *rdev,
548c2ecf20Sopenharmony_ci			   struct radeon_ring *ring)
558c2ecf20Sopenharmony_ci{
568c2ecf20Sopenharmony_ci	return RREG32(UVD_RBC_RB_WPTR);
578c2ecf20Sopenharmony_ci}
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci/**
608c2ecf20Sopenharmony_ci * uvd_v1_0_set_wptr - set write pointer
618c2ecf20Sopenharmony_ci *
628c2ecf20Sopenharmony_ci * @rdev: radeon_device pointer
638c2ecf20Sopenharmony_ci * @ring: radeon_ring pointer
648c2ecf20Sopenharmony_ci *
658c2ecf20Sopenharmony_ci * Commits the write pointer to the hardware
668c2ecf20Sopenharmony_ci */
678c2ecf20Sopenharmony_civoid uvd_v1_0_set_wptr(struct radeon_device *rdev,
688c2ecf20Sopenharmony_ci		       struct radeon_ring *ring)
698c2ecf20Sopenharmony_ci{
708c2ecf20Sopenharmony_ci	WREG32(UVD_RBC_RB_WPTR, ring->wptr);
718c2ecf20Sopenharmony_ci}
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci/**
748c2ecf20Sopenharmony_ci * uvd_v1_0_fence_emit - emit an fence & trap command
758c2ecf20Sopenharmony_ci *
768c2ecf20Sopenharmony_ci * @rdev: radeon_device pointer
778c2ecf20Sopenharmony_ci * @fence: fence to emit
788c2ecf20Sopenharmony_ci *
798c2ecf20Sopenharmony_ci * Write a fence and a trap command to the ring.
808c2ecf20Sopenharmony_ci */
818c2ecf20Sopenharmony_civoid uvd_v1_0_fence_emit(struct radeon_device *rdev,
828c2ecf20Sopenharmony_ci			 struct radeon_fence *fence)
838c2ecf20Sopenharmony_ci{
848c2ecf20Sopenharmony_ci	struct radeon_ring *ring = &rdev->ring[fence->ring];
858c2ecf20Sopenharmony_ci	uint64_t addr = rdev->fence_drv[fence->ring].gpu_addr;
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_DATA0, 0));
888c2ecf20Sopenharmony_ci	radeon_ring_write(ring, addr & 0xffffffff);
898c2ecf20Sopenharmony_ci	radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_DATA1, 0));
908c2ecf20Sopenharmony_ci	radeon_ring_write(ring, fence->seq);
918c2ecf20Sopenharmony_ci	radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_CMD, 0));
928c2ecf20Sopenharmony_ci	radeon_ring_write(ring, 0);
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_DATA0, 0));
958c2ecf20Sopenharmony_ci	radeon_ring_write(ring, 0);
968c2ecf20Sopenharmony_ci	radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_DATA1, 0));
978c2ecf20Sopenharmony_ci	radeon_ring_write(ring, 0);
988c2ecf20Sopenharmony_ci	radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_CMD, 0));
998c2ecf20Sopenharmony_ci	radeon_ring_write(ring, 2);
1008c2ecf20Sopenharmony_ci	return;
1018c2ecf20Sopenharmony_ci}
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci/**
1048c2ecf20Sopenharmony_ci * uvd_v1_0_resume - memory controller programming
1058c2ecf20Sopenharmony_ci *
1068c2ecf20Sopenharmony_ci * @rdev: radeon_device pointer
1078c2ecf20Sopenharmony_ci *
1088c2ecf20Sopenharmony_ci * Let the UVD memory controller know it's offsets
1098c2ecf20Sopenharmony_ci */
1108c2ecf20Sopenharmony_ciint uvd_v1_0_resume(struct radeon_device *rdev)
1118c2ecf20Sopenharmony_ci{
1128c2ecf20Sopenharmony_ci	uint64_t addr;
1138c2ecf20Sopenharmony_ci	uint32_t size;
1148c2ecf20Sopenharmony_ci	int r;
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	r = radeon_uvd_resume(rdev);
1178c2ecf20Sopenharmony_ci	if (r)
1188c2ecf20Sopenharmony_ci		return r;
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	/* program the VCPU memory controller bits 0-27 */
1218c2ecf20Sopenharmony_ci	addr = (rdev->uvd.gpu_addr >> 3) + 16;
1228c2ecf20Sopenharmony_ci	size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->size) >> 3;
1238c2ecf20Sopenharmony_ci	WREG32(UVD_VCPU_CACHE_OFFSET0, addr);
1248c2ecf20Sopenharmony_ci	WREG32(UVD_VCPU_CACHE_SIZE0, size);
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	addr += size;
1278c2ecf20Sopenharmony_ci	size = RADEON_UVD_HEAP_SIZE >> 3;
1288c2ecf20Sopenharmony_ci	WREG32(UVD_VCPU_CACHE_OFFSET1, addr);
1298c2ecf20Sopenharmony_ci	WREG32(UVD_VCPU_CACHE_SIZE1, size);
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	addr += size;
1328c2ecf20Sopenharmony_ci	size = (RADEON_UVD_STACK_SIZE +
1338c2ecf20Sopenharmony_ci	       (RADEON_UVD_SESSION_SIZE * rdev->uvd.max_handles)) >> 3;
1348c2ecf20Sopenharmony_ci	WREG32(UVD_VCPU_CACHE_OFFSET2, addr);
1358c2ecf20Sopenharmony_ci	WREG32(UVD_VCPU_CACHE_SIZE2, size);
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	/* bits 28-31 */
1388c2ecf20Sopenharmony_ci	addr = (rdev->uvd.gpu_addr >> 28) & 0xF;
1398c2ecf20Sopenharmony_ci	WREG32(UVD_LMI_ADDR_EXT, (addr << 12) | (addr << 0));
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	/* bits 32-39 */
1428c2ecf20Sopenharmony_ci	addr = (rdev->uvd.gpu_addr >> 32) & 0xFF;
1438c2ecf20Sopenharmony_ci	WREG32(UVD_LMI_EXT40_ADDR, addr | (0x9 << 16) | (0x1 << 31));
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	WREG32(UVD_FW_START, *((uint32_t*)rdev->uvd.cpu_addr));
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	return 0;
1488c2ecf20Sopenharmony_ci}
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci/**
1518c2ecf20Sopenharmony_ci * uvd_v1_0_init - start and test UVD block
1528c2ecf20Sopenharmony_ci *
1538c2ecf20Sopenharmony_ci * @rdev: radeon_device pointer
1548c2ecf20Sopenharmony_ci *
1558c2ecf20Sopenharmony_ci * Initialize the hardware, boot up the VCPU and do some testing
1568c2ecf20Sopenharmony_ci */
1578c2ecf20Sopenharmony_ciint uvd_v1_0_init(struct radeon_device *rdev)
1588c2ecf20Sopenharmony_ci{
1598c2ecf20Sopenharmony_ci	struct radeon_ring *ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX];
1608c2ecf20Sopenharmony_ci	uint32_t tmp;
1618c2ecf20Sopenharmony_ci	int r;
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	/* raise clocks while booting up the VCPU */
1648c2ecf20Sopenharmony_ci	if (rdev->family < CHIP_RV740)
1658c2ecf20Sopenharmony_ci		radeon_set_uvd_clocks(rdev, 10000, 10000);
1668c2ecf20Sopenharmony_ci	else
1678c2ecf20Sopenharmony_ci		radeon_set_uvd_clocks(rdev, 53300, 40000);
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	r = uvd_v1_0_start(rdev);
1708c2ecf20Sopenharmony_ci	if (r)
1718c2ecf20Sopenharmony_ci		goto done;
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	ring->ready = true;
1748c2ecf20Sopenharmony_ci	r = radeon_ring_test(rdev, R600_RING_TYPE_UVD_INDEX, ring);
1758c2ecf20Sopenharmony_ci	if (r) {
1768c2ecf20Sopenharmony_ci		ring->ready = false;
1778c2ecf20Sopenharmony_ci		goto done;
1788c2ecf20Sopenharmony_ci	}
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	r = radeon_ring_lock(rdev, ring, 10);
1818c2ecf20Sopenharmony_ci	if (r) {
1828c2ecf20Sopenharmony_ci		DRM_ERROR("radeon: ring failed to lock UVD ring (%d).\n", r);
1838c2ecf20Sopenharmony_ci		goto done;
1848c2ecf20Sopenharmony_ci	}
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	tmp = PACKET0(UVD_SEMA_WAIT_FAULT_TIMEOUT_CNTL, 0);
1878c2ecf20Sopenharmony_ci	radeon_ring_write(ring, tmp);
1888c2ecf20Sopenharmony_ci	radeon_ring_write(ring, 0xFFFFF);
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	tmp = PACKET0(UVD_SEMA_WAIT_INCOMPLETE_TIMEOUT_CNTL, 0);
1918c2ecf20Sopenharmony_ci	radeon_ring_write(ring, tmp);
1928c2ecf20Sopenharmony_ci	radeon_ring_write(ring, 0xFFFFF);
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	tmp = PACKET0(UVD_SEMA_SIGNAL_INCOMPLETE_TIMEOUT_CNTL, 0);
1958c2ecf20Sopenharmony_ci	radeon_ring_write(ring, tmp);
1968c2ecf20Sopenharmony_ci	radeon_ring_write(ring, 0xFFFFF);
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	/* Clear timeout status bits */
1998c2ecf20Sopenharmony_ci	radeon_ring_write(ring, PACKET0(UVD_SEMA_TIMEOUT_STATUS, 0));
2008c2ecf20Sopenharmony_ci	radeon_ring_write(ring, 0x8);
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	radeon_ring_write(ring, PACKET0(UVD_SEMA_CNTL, 0));
2038c2ecf20Sopenharmony_ci	radeon_ring_write(ring, 3);
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	radeon_ring_unlock_commit(rdev, ring, false);
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_cidone:
2088c2ecf20Sopenharmony_ci	/* lower clocks again */
2098c2ecf20Sopenharmony_ci	radeon_set_uvd_clocks(rdev, 0, 0);
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	if (!r) {
2128c2ecf20Sopenharmony_ci		switch (rdev->family) {
2138c2ecf20Sopenharmony_ci		case CHIP_RV610:
2148c2ecf20Sopenharmony_ci		case CHIP_RV630:
2158c2ecf20Sopenharmony_ci		case CHIP_RV620:
2168c2ecf20Sopenharmony_ci			/* 64byte granularity workaround */
2178c2ecf20Sopenharmony_ci			WREG32(MC_CONFIG, 0);
2188c2ecf20Sopenharmony_ci			WREG32(MC_CONFIG, 1 << 4);
2198c2ecf20Sopenharmony_ci			WREG32(RS_DQ_RD_RET_CONF, 0x3f);
2208c2ecf20Sopenharmony_ci			WREG32(MC_CONFIG, 0x1f);
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci			fallthrough;
2238c2ecf20Sopenharmony_ci		case CHIP_RV670:
2248c2ecf20Sopenharmony_ci		case CHIP_RV635:
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci			/* write clean workaround */
2278c2ecf20Sopenharmony_ci			WREG32_P(UVD_VCPU_CNTL, 0x10, ~0x10);
2288c2ecf20Sopenharmony_ci			break;
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci		default:
2318c2ecf20Sopenharmony_ci			/* TODO: Do we need more? */
2328c2ecf20Sopenharmony_ci			break;
2338c2ecf20Sopenharmony_ci		}
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci		DRM_INFO("UVD initialized successfully.\n");
2368c2ecf20Sopenharmony_ci	}
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	return r;
2398c2ecf20Sopenharmony_ci}
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci/**
2428c2ecf20Sopenharmony_ci * uvd_v1_0_fini - stop the hardware block
2438c2ecf20Sopenharmony_ci *
2448c2ecf20Sopenharmony_ci * @rdev: radeon_device pointer
2458c2ecf20Sopenharmony_ci *
2468c2ecf20Sopenharmony_ci * Stop the UVD block, mark ring as not ready any more
2478c2ecf20Sopenharmony_ci */
2488c2ecf20Sopenharmony_civoid uvd_v1_0_fini(struct radeon_device *rdev)
2498c2ecf20Sopenharmony_ci{
2508c2ecf20Sopenharmony_ci	struct radeon_ring *ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX];
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	uvd_v1_0_stop(rdev);
2538c2ecf20Sopenharmony_ci	ring->ready = false;
2548c2ecf20Sopenharmony_ci}
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci/**
2578c2ecf20Sopenharmony_ci * uvd_v1_0_start - start UVD block
2588c2ecf20Sopenharmony_ci *
2598c2ecf20Sopenharmony_ci * @rdev: radeon_device pointer
2608c2ecf20Sopenharmony_ci *
2618c2ecf20Sopenharmony_ci * Setup and start the UVD block
2628c2ecf20Sopenharmony_ci */
2638c2ecf20Sopenharmony_ciint uvd_v1_0_start(struct radeon_device *rdev)
2648c2ecf20Sopenharmony_ci{
2658c2ecf20Sopenharmony_ci	struct radeon_ring *ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX];
2668c2ecf20Sopenharmony_ci	uint32_t rb_bufsz;
2678c2ecf20Sopenharmony_ci	int i, j, r;
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	/* disable byte swapping */
2708c2ecf20Sopenharmony_ci	u32 lmi_swap_cntl = 0;
2718c2ecf20Sopenharmony_ci	u32 mp_swap_cntl = 0;
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	/* disable clock gating */
2748c2ecf20Sopenharmony_ci	WREG32(UVD_CGC_GATE, 0);
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	/* disable interupt */
2778c2ecf20Sopenharmony_ci	WREG32_P(UVD_MASTINT_EN, 0, ~(1 << 1));
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	/* Stall UMC and register bus before resetting VCPU */
2808c2ecf20Sopenharmony_ci	WREG32_P(UVD_LMI_CTRL2, 1 << 8, ~(1 << 8));
2818c2ecf20Sopenharmony_ci	WREG32_P(UVD_RB_ARB_CTRL, 1 << 3, ~(1 << 3));
2828c2ecf20Sopenharmony_ci	mdelay(1);
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	/* put LMI, VCPU, RBC etc... into reset */
2858c2ecf20Sopenharmony_ci	WREG32(UVD_SOFT_RESET, LMI_SOFT_RESET | VCPU_SOFT_RESET |
2868c2ecf20Sopenharmony_ci	       LBSI_SOFT_RESET | RBC_SOFT_RESET | CSM_SOFT_RESET |
2878c2ecf20Sopenharmony_ci	       CXW_SOFT_RESET | TAP_SOFT_RESET | LMI_UMC_SOFT_RESET);
2888c2ecf20Sopenharmony_ci	mdelay(5);
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	/* take UVD block out of reset */
2918c2ecf20Sopenharmony_ci	WREG32_P(SRBM_SOFT_RESET, 0, ~SOFT_RESET_UVD);
2928c2ecf20Sopenharmony_ci	mdelay(5);
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	/* initialize UVD memory controller */
2958c2ecf20Sopenharmony_ci	WREG32(UVD_LMI_CTRL, 0x40 | (1 << 8) | (1 << 13) |
2968c2ecf20Sopenharmony_ci			     (1 << 21) | (1 << 9) | (1 << 20));
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN
2998c2ecf20Sopenharmony_ci	/* swap (8 in 32) RB and IB */
3008c2ecf20Sopenharmony_ci	lmi_swap_cntl = 0xa;
3018c2ecf20Sopenharmony_ci	mp_swap_cntl = 0;
3028c2ecf20Sopenharmony_ci#endif
3038c2ecf20Sopenharmony_ci	WREG32(UVD_LMI_SWAP_CNTL, lmi_swap_cntl);
3048c2ecf20Sopenharmony_ci	WREG32(UVD_MP_SWAP_CNTL, mp_swap_cntl);
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	WREG32(UVD_MPC_SET_MUXA0, 0x40c2040);
3078c2ecf20Sopenharmony_ci	WREG32(UVD_MPC_SET_MUXA1, 0x0);
3088c2ecf20Sopenharmony_ci	WREG32(UVD_MPC_SET_MUXB0, 0x40c2040);
3098c2ecf20Sopenharmony_ci	WREG32(UVD_MPC_SET_MUXB1, 0x0);
3108c2ecf20Sopenharmony_ci	WREG32(UVD_MPC_SET_ALU, 0);
3118c2ecf20Sopenharmony_ci	WREG32(UVD_MPC_SET_MUX, 0x88);
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	/* take all subblocks out of reset, except VCPU */
3148c2ecf20Sopenharmony_ci	WREG32(UVD_SOFT_RESET, VCPU_SOFT_RESET);
3158c2ecf20Sopenharmony_ci	mdelay(5);
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	/* enable VCPU clock */
3188c2ecf20Sopenharmony_ci	WREG32(UVD_VCPU_CNTL,  1 << 9);
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	/* enable UMC */
3218c2ecf20Sopenharmony_ci	WREG32_P(UVD_LMI_CTRL2, 0, ~(1 << 8));
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	WREG32_P(UVD_RB_ARB_CTRL, 0, ~(1 << 3));
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	/* boot up the VCPU */
3268c2ecf20Sopenharmony_ci	WREG32(UVD_SOFT_RESET, 0);
3278c2ecf20Sopenharmony_ci	mdelay(10);
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	for (i = 0; i < 10; ++i) {
3308c2ecf20Sopenharmony_ci		uint32_t status;
3318c2ecf20Sopenharmony_ci		for (j = 0; j < 100; ++j) {
3328c2ecf20Sopenharmony_ci			status = RREG32(UVD_STATUS);
3338c2ecf20Sopenharmony_ci			if (status & 2)
3348c2ecf20Sopenharmony_ci				break;
3358c2ecf20Sopenharmony_ci			mdelay(10);
3368c2ecf20Sopenharmony_ci		}
3378c2ecf20Sopenharmony_ci		r = 0;
3388c2ecf20Sopenharmony_ci		if (status & 2)
3398c2ecf20Sopenharmony_ci			break;
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci		DRM_ERROR("UVD not responding, trying to reset the VCPU!!!\n");
3428c2ecf20Sopenharmony_ci		WREG32_P(UVD_SOFT_RESET, VCPU_SOFT_RESET, ~VCPU_SOFT_RESET);
3438c2ecf20Sopenharmony_ci		mdelay(10);
3448c2ecf20Sopenharmony_ci		WREG32_P(UVD_SOFT_RESET, 0, ~VCPU_SOFT_RESET);
3458c2ecf20Sopenharmony_ci		mdelay(10);
3468c2ecf20Sopenharmony_ci		r = -1;
3478c2ecf20Sopenharmony_ci	}
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	if (r) {
3508c2ecf20Sopenharmony_ci		DRM_ERROR("UVD not responding, giving up!!!\n");
3518c2ecf20Sopenharmony_ci		return r;
3528c2ecf20Sopenharmony_ci	}
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	/* enable interupt */
3558c2ecf20Sopenharmony_ci	WREG32_P(UVD_MASTINT_EN, 3<<1, ~(3 << 1));
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	/* force RBC into idle state */
3588c2ecf20Sopenharmony_ci	WREG32(UVD_RBC_RB_CNTL, 0x11010101);
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	/* Set the write pointer delay */
3618c2ecf20Sopenharmony_ci	WREG32(UVD_RBC_RB_WPTR_CNTL, 0);
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	/* program the 4GB memory segment for rptr and ring buffer */
3648c2ecf20Sopenharmony_ci	WREG32(UVD_LMI_EXT40_ADDR, upper_32_bits(ring->gpu_addr) |
3658c2ecf20Sopenharmony_ci				   (0x7 << 16) | (0x1 << 31));
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	/* Initialize the ring buffer's read and write pointers */
3688c2ecf20Sopenharmony_ci	WREG32(UVD_RBC_RB_RPTR, 0x0);
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	ring->wptr = RREG32(UVD_RBC_RB_RPTR);
3718c2ecf20Sopenharmony_ci	WREG32(UVD_RBC_RB_WPTR, ring->wptr);
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	/* set the ring address */
3748c2ecf20Sopenharmony_ci	WREG32(UVD_RBC_RB_BASE, ring->gpu_addr);
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	/* Set ring buffer size */
3778c2ecf20Sopenharmony_ci	rb_bufsz = order_base_2(ring->ring_size);
3788c2ecf20Sopenharmony_ci	rb_bufsz = (0x1 << 8) | rb_bufsz;
3798c2ecf20Sopenharmony_ci	WREG32_P(UVD_RBC_RB_CNTL, rb_bufsz, ~0x11f1f);
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	return 0;
3828c2ecf20Sopenharmony_ci}
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci/**
3858c2ecf20Sopenharmony_ci * uvd_v1_0_stop - stop UVD block
3868c2ecf20Sopenharmony_ci *
3878c2ecf20Sopenharmony_ci * @rdev: radeon_device pointer
3888c2ecf20Sopenharmony_ci *
3898c2ecf20Sopenharmony_ci * stop the UVD block
3908c2ecf20Sopenharmony_ci */
3918c2ecf20Sopenharmony_civoid uvd_v1_0_stop(struct radeon_device *rdev)
3928c2ecf20Sopenharmony_ci{
3938c2ecf20Sopenharmony_ci	/* force RBC into idle state */
3948c2ecf20Sopenharmony_ci	WREG32(UVD_RBC_RB_CNTL, 0x11010101);
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	/* Stall UMC and register bus before resetting VCPU */
3978c2ecf20Sopenharmony_ci	WREG32_P(UVD_LMI_CTRL2, 1 << 8, ~(1 << 8));
3988c2ecf20Sopenharmony_ci	WREG32_P(UVD_RB_ARB_CTRL, 1 << 3, ~(1 << 3));
3998c2ecf20Sopenharmony_ci	mdelay(1);
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	/* put VCPU into reset */
4028c2ecf20Sopenharmony_ci	WREG32(UVD_SOFT_RESET, VCPU_SOFT_RESET);
4038c2ecf20Sopenharmony_ci	mdelay(5);
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	/* disable VCPU clock */
4068c2ecf20Sopenharmony_ci	WREG32(UVD_VCPU_CNTL, 0x0);
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	/* Unstall UMC and register bus */
4098c2ecf20Sopenharmony_ci	WREG32_P(UVD_LMI_CTRL2, 0, ~(1 << 8));
4108c2ecf20Sopenharmony_ci	WREG32_P(UVD_RB_ARB_CTRL, 0, ~(1 << 3));
4118c2ecf20Sopenharmony_ci}
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci/**
4148c2ecf20Sopenharmony_ci * uvd_v1_0_ring_test - register write test
4158c2ecf20Sopenharmony_ci *
4168c2ecf20Sopenharmony_ci * @rdev: radeon_device pointer
4178c2ecf20Sopenharmony_ci * @ring: radeon_ring pointer
4188c2ecf20Sopenharmony_ci *
4198c2ecf20Sopenharmony_ci * Test if we can successfully write to the context register
4208c2ecf20Sopenharmony_ci */
4218c2ecf20Sopenharmony_ciint uvd_v1_0_ring_test(struct radeon_device *rdev, struct radeon_ring *ring)
4228c2ecf20Sopenharmony_ci{
4238c2ecf20Sopenharmony_ci	uint32_t tmp = 0;
4248c2ecf20Sopenharmony_ci	unsigned i;
4258c2ecf20Sopenharmony_ci	int r;
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	WREG32(UVD_CONTEXT_ID, 0xCAFEDEAD);
4288c2ecf20Sopenharmony_ci	r = radeon_ring_lock(rdev, ring, 3);
4298c2ecf20Sopenharmony_ci	if (r) {
4308c2ecf20Sopenharmony_ci		DRM_ERROR("radeon: cp failed to lock ring %d (%d).\n",
4318c2ecf20Sopenharmony_ci			  ring->idx, r);
4328c2ecf20Sopenharmony_ci		return r;
4338c2ecf20Sopenharmony_ci	}
4348c2ecf20Sopenharmony_ci	radeon_ring_write(ring, PACKET0(UVD_CONTEXT_ID, 0));
4358c2ecf20Sopenharmony_ci	radeon_ring_write(ring, 0xDEADBEEF);
4368c2ecf20Sopenharmony_ci	radeon_ring_unlock_commit(rdev, ring, false);
4378c2ecf20Sopenharmony_ci	for (i = 0; i < rdev->usec_timeout; i++) {
4388c2ecf20Sopenharmony_ci		tmp = RREG32(UVD_CONTEXT_ID);
4398c2ecf20Sopenharmony_ci		if (tmp == 0xDEADBEEF)
4408c2ecf20Sopenharmony_ci			break;
4418c2ecf20Sopenharmony_ci		udelay(1);
4428c2ecf20Sopenharmony_ci	}
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	if (i < rdev->usec_timeout) {
4458c2ecf20Sopenharmony_ci		DRM_INFO("ring test on %d succeeded in %d usecs\n",
4468c2ecf20Sopenharmony_ci			 ring->idx, i);
4478c2ecf20Sopenharmony_ci	} else {
4488c2ecf20Sopenharmony_ci		DRM_ERROR("radeon: ring %d test failed (0x%08X)\n",
4498c2ecf20Sopenharmony_ci			  ring->idx, tmp);
4508c2ecf20Sopenharmony_ci		r = -EINVAL;
4518c2ecf20Sopenharmony_ci	}
4528c2ecf20Sopenharmony_ci	return r;
4538c2ecf20Sopenharmony_ci}
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci/**
4568c2ecf20Sopenharmony_ci * uvd_v1_0_semaphore_emit - emit semaphore command
4578c2ecf20Sopenharmony_ci *
4588c2ecf20Sopenharmony_ci * @rdev: radeon_device pointer
4598c2ecf20Sopenharmony_ci * @ring: radeon_ring pointer
4608c2ecf20Sopenharmony_ci * @semaphore: semaphore to emit commands for
4618c2ecf20Sopenharmony_ci * @emit_wait: true if we should emit a wait command
4628c2ecf20Sopenharmony_ci *
4638c2ecf20Sopenharmony_ci * Emit a semaphore command (either wait or signal) to the UVD ring.
4648c2ecf20Sopenharmony_ci */
4658c2ecf20Sopenharmony_cibool uvd_v1_0_semaphore_emit(struct radeon_device *rdev,
4668c2ecf20Sopenharmony_ci			     struct radeon_ring *ring,
4678c2ecf20Sopenharmony_ci			     struct radeon_semaphore *semaphore,
4688c2ecf20Sopenharmony_ci			     bool emit_wait)
4698c2ecf20Sopenharmony_ci{
4708c2ecf20Sopenharmony_ci	/* disable semaphores for UVD V1 hardware */
4718c2ecf20Sopenharmony_ci	return false;
4728c2ecf20Sopenharmony_ci}
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci/**
4758c2ecf20Sopenharmony_ci * uvd_v1_0_ib_execute - execute indirect buffer
4768c2ecf20Sopenharmony_ci *
4778c2ecf20Sopenharmony_ci * @rdev: radeon_device pointer
4788c2ecf20Sopenharmony_ci * @ib: indirect buffer to execute
4798c2ecf20Sopenharmony_ci *
4808c2ecf20Sopenharmony_ci * Write ring commands to execute the indirect buffer
4818c2ecf20Sopenharmony_ci */
4828c2ecf20Sopenharmony_civoid uvd_v1_0_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib)
4838c2ecf20Sopenharmony_ci{
4848c2ecf20Sopenharmony_ci	struct radeon_ring *ring = &rdev->ring[ib->ring];
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	radeon_ring_write(ring, PACKET0(UVD_RBC_IB_BASE, 0));
4878c2ecf20Sopenharmony_ci	radeon_ring_write(ring, ib->gpu_addr);
4888c2ecf20Sopenharmony_ci	radeon_ring_write(ring, PACKET0(UVD_RBC_IB_SIZE, 0));
4898c2ecf20Sopenharmony_ci	radeon_ring_write(ring, ib->length_dw);
4908c2ecf20Sopenharmony_ci}
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci/**
4938c2ecf20Sopenharmony_ci * uvd_v1_0_ib_test - test ib execution
4948c2ecf20Sopenharmony_ci *
4958c2ecf20Sopenharmony_ci * @rdev: radeon_device pointer
4968c2ecf20Sopenharmony_ci * @ring: radeon_ring pointer
4978c2ecf20Sopenharmony_ci *
4988c2ecf20Sopenharmony_ci * Test if we can successfully execute an IB
4998c2ecf20Sopenharmony_ci */
5008c2ecf20Sopenharmony_ciint uvd_v1_0_ib_test(struct radeon_device *rdev, struct radeon_ring *ring)
5018c2ecf20Sopenharmony_ci{
5028c2ecf20Sopenharmony_ci	struct radeon_fence *fence = NULL;
5038c2ecf20Sopenharmony_ci	int r;
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	if (rdev->family < CHIP_RV740)
5068c2ecf20Sopenharmony_ci		r = radeon_set_uvd_clocks(rdev, 10000, 10000);
5078c2ecf20Sopenharmony_ci	else
5088c2ecf20Sopenharmony_ci		r = radeon_set_uvd_clocks(rdev, 53300, 40000);
5098c2ecf20Sopenharmony_ci	if (r) {
5108c2ecf20Sopenharmony_ci		DRM_ERROR("radeon: failed to raise UVD clocks (%d).\n", r);
5118c2ecf20Sopenharmony_ci		return r;
5128c2ecf20Sopenharmony_ci	}
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	r = radeon_uvd_get_create_msg(rdev, ring->idx, 1, NULL);
5158c2ecf20Sopenharmony_ci	if (r) {
5168c2ecf20Sopenharmony_ci		DRM_ERROR("radeon: failed to get create msg (%d).\n", r);
5178c2ecf20Sopenharmony_ci		goto error;
5188c2ecf20Sopenharmony_ci	}
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci	r = radeon_uvd_get_destroy_msg(rdev, ring->idx, 1, &fence);
5218c2ecf20Sopenharmony_ci	if (r) {
5228c2ecf20Sopenharmony_ci		DRM_ERROR("radeon: failed to get destroy ib (%d).\n", r);
5238c2ecf20Sopenharmony_ci		goto error;
5248c2ecf20Sopenharmony_ci	}
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci	r = radeon_fence_wait_timeout(fence, false, usecs_to_jiffies(
5278c2ecf20Sopenharmony_ci		RADEON_USEC_IB_TEST_TIMEOUT));
5288c2ecf20Sopenharmony_ci	if (r < 0) {
5298c2ecf20Sopenharmony_ci		DRM_ERROR("radeon: fence wait failed (%d).\n", r);
5308c2ecf20Sopenharmony_ci		goto error;
5318c2ecf20Sopenharmony_ci	} else if (r == 0) {
5328c2ecf20Sopenharmony_ci		DRM_ERROR("radeon: fence wait timed out.\n");
5338c2ecf20Sopenharmony_ci		r = -ETIMEDOUT;
5348c2ecf20Sopenharmony_ci		goto error;
5358c2ecf20Sopenharmony_ci	}
5368c2ecf20Sopenharmony_ci	r = 0;
5378c2ecf20Sopenharmony_ci	DRM_INFO("ib test on ring %d succeeded\n",  ring->idx);
5388c2ecf20Sopenharmony_cierror:
5398c2ecf20Sopenharmony_ci	radeon_fence_unref(&fence);
5408c2ecf20Sopenharmony_ci	radeon_set_uvd_clocks(rdev, 0, 0);
5418c2ecf20Sopenharmony_ci	return r;
5428c2ecf20Sopenharmony_ci}
543