14cd92098Szrj /*
24cd92098Szrj * Copyright 2013 Advanced Micro Devices, Inc.
34cd92098Szrj *
44cd92098Szrj * Permission is hereby granted, free of charge, to any person obtaining a
54cd92098Szrj * copy of this software and associated documentation files (the "Software"),
64cd92098Szrj * to deal in the Software without restriction, including without limitation
74cd92098Szrj * the rights to use, copy, modify, merge, publish, distribute, sublicense,
84cd92098Szrj * and/or sell copies of the Software, and to permit persons to whom the
94cd92098Szrj * Software is furnished to do so, subject to the following conditions:
104cd92098Szrj *
114cd92098Szrj * The above copyright notice and this permission notice shall be included in
124cd92098Szrj * all copies or substantial portions of the Software.
134cd92098Szrj *
144cd92098Szrj * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
154cd92098Szrj * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
164cd92098Szrj * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
174cd92098Szrj * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
184cd92098Szrj * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
194cd92098Szrj * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
204cd92098Szrj * OTHER DEALINGS IN THE SOFTWARE.
214cd92098Szrj *
224cd92098Szrj * Authors: Christian König <christian.koenig@amd.com>
234cd92098Szrj */
244cd92098Szrj
25591d5043SFrançois Tigeot #include <linux/firmware.h>
264cd92098Szrj #include <drm/drmP.h>
274cd92098Szrj #include "radeon.h"
284cd92098Szrj #include "radeon_asic.h"
294cd92098Szrj #include "r600d.h"
304cd92098Szrj
314cd92098Szrj /**
324cd92098Szrj * uvd_v1_0_get_rptr - get read pointer
334cd92098Szrj *
344cd92098Szrj * @rdev: radeon_device pointer
354cd92098Szrj * @ring: radeon_ring pointer
364cd92098Szrj *
374cd92098Szrj * Returns the current hardware read pointer
384cd92098Szrj */
uvd_v1_0_get_rptr(struct radeon_device * rdev,struct radeon_ring * ring)394cd92098Szrj uint32_t uvd_v1_0_get_rptr(struct radeon_device *rdev,
404cd92098Szrj struct radeon_ring *ring)
414cd92098Szrj {
424cd92098Szrj return RREG32(UVD_RBC_RB_RPTR);
434cd92098Szrj }
444cd92098Szrj
454cd92098Szrj /**
464cd92098Szrj * uvd_v1_0_get_wptr - get write pointer
474cd92098Szrj *
484cd92098Szrj * @rdev: radeon_device pointer
494cd92098Szrj * @ring: radeon_ring pointer
504cd92098Szrj *
514cd92098Szrj * Returns the current hardware write pointer
524cd92098Szrj */
uvd_v1_0_get_wptr(struct radeon_device * rdev,struct radeon_ring * ring)534cd92098Szrj uint32_t uvd_v1_0_get_wptr(struct radeon_device *rdev,
544cd92098Szrj struct radeon_ring *ring)
554cd92098Szrj {
564cd92098Szrj return RREG32(UVD_RBC_RB_WPTR);
574cd92098Szrj }
584cd92098Szrj
594cd92098Szrj /**
604cd92098Szrj * uvd_v1_0_set_wptr - set write pointer
614cd92098Szrj *
624cd92098Szrj * @rdev: radeon_device pointer
634cd92098Szrj * @ring: radeon_ring pointer
644cd92098Szrj *
654cd92098Szrj * Commits the write pointer to the hardware
664cd92098Szrj */
uvd_v1_0_set_wptr(struct radeon_device * rdev,struct radeon_ring * ring)674cd92098Szrj void uvd_v1_0_set_wptr(struct radeon_device *rdev,
684cd92098Szrj struct radeon_ring *ring)
694cd92098Szrj {
704cd92098Szrj WREG32(UVD_RBC_RB_WPTR, ring->wptr);
714cd92098Szrj }
724cd92098Szrj
734cd92098Szrj /**
74591d5043SFrançois Tigeot * uvd_v1_0_fence_emit - emit an fence & trap command
75591d5043SFrançois Tigeot *
76591d5043SFrançois Tigeot * @rdev: radeon_device pointer
77591d5043SFrançois Tigeot * @fence: fence to emit
78591d5043SFrançois Tigeot *
79591d5043SFrançois Tigeot * Write a fence and a trap command to the ring.
80591d5043SFrançois Tigeot */
uvd_v1_0_fence_emit(struct radeon_device * rdev,struct radeon_fence * fence)81591d5043SFrançois Tigeot void uvd_v1_0_fence_emit(struct radeon_device *rdev,
82591d5043SFrançois Tigeot struct radeon_fence *fence)
83591d5043SFrançois Tigeot {
84591d5043SFrançois Tigeot struct radeon_ring *ring = &rdev->ring[fence->ring];
85591d5043SFrançois Tigeot uint64_t addr = rdev->fence_drv[fence->ring].gpu_addr;
86591d5043SFrançois Tigeot
87591d5043SFrançois Tigeot radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_DATA0, 0));
88591d5043SFrançois Tigeot radeon_ring_write(ring, addr & 0xffffffff);
89591d5043SFrançois Tigeot radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_DATA1, 0));
90591d5043SFrançois Tigeot radeon_ring_write(ring, fence->seq);
91591d5043SFrançois Tigeot radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_CMD, 0));
92591d5043SFrançois Tigeot radeon_ring_write(ring, 0);
93591d5043SFrançois Tigeot
94591d5043SFrançois Tigeot radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_DATA0, 0));
95591d5043SFrançois Tigeot radeon_ring_write(ring, 0);
96591d5043SFrançois Tigeot radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_DATA1, 0));
97591d5043SFrançois Tigeot radeon_ring_write(ring, 0);
98591d5043SFrançois Tigeot radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_CMD, 0));
99591d5043SFrançois Tigeot radeon_ring_write(ring, 2);
100591d5043SFrançois Tigeot return;
101591d5043SFrançois Tigeot }
102591d5043SFrançois Tigeot
103591d5043SFrançois Tigeot /**
104591d5043SFrançois Tigeot * uvd_v1_0_resume - memory controller programming
105591d5043SFrançois Tigeot *
106591d5043SFrançois Tigeot * @rdev: radeon_device pointer
107591d5043SFrançois Tigeot *
108591d5043SFrançois Tigeot * Let the UVD memory controller know it's offsets
109591d5043SFrançois Tigeot */
uvd_v1_0_resume(struct radeon_device * rdev)110591d5043SFrançois Tigeot int uvd_v1_0_resume(struct radeon_device *rdev)
111591d5043SFrançois Tigeot {
112591d5043SFrançois Tigeot uint64_t addr;
113591d5043SFrançois Tigeot uint32_t size;
114591d5043SFrançois Tigeot int r;
115591d5043SFrançois Tigeot
116591d5043SFrançois Tigeot r = radeon_uvd_resume(rdev);
117591d5043SFrançois Tigeot if (r)
118591d5043SFrançois Tigeot return r;
119591d5043SFrançois Tigeot
120591d5043SFrançois Tigeot /* programm the VCPU memory controller bits 0-27 */
121591d5043SFrançois Tigeot addr = (rdev->uvd.gpu_addr >> 3) + 16;
122591d5043SFrançois Tigeot size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->datasize) >> 3;
123591d5043SFrançois Tigeot WREG32(UVD_VCPU_CACHE_OFFSET0, addr);
124591d5043SFrançois Tigeot WREG32(UVD_VCPU_CACHE_SIZE0, size);
125591d5043SFrançois Tigeot
126591d5043SFrançois Tigeot addr += size;
127*d78d3a22SFrançois Tigeot size = RADEON_UVD_HEAP_SIZE >> 3;
128591d5043SFrançois Tigeot WREG32(UVD_VCPU_CACHE_OFFSET1, addr);
129591d5043SFrançois Tigeot WREG32(UVD_VCPU_CACHE_SIZE1, size);
130591d5043SFrançois Tigeot
131591d5043SFrançois Tigeot addr += size;
132*d78d3a22SFrançois Tigeot size = (RADEON_UVD_STACK_SIZE +
133*d78d3a22SFrançois Tigeot (RADEON_UVD_SESSION_SIZE * rdev->uvd.max_handles)) >> 3;
134591d5043SFrançois Tigeot WREG32(UVD_VCPU_CACHE_OFFSET2, addr);
135591d5043SFrançois Tigeot WREG32(UVD_VCPU_CACHE_SIZE2, size);
136591d5043SFrançois Tigeot
137591d5043SFrançois Tigeot /* bits 28-31 */
138591d5043SFrançois Tigeot addr = (rdev->uvd.gpu_addr >> 28) & 0xF;
139591d5043SFrançois Tigeot WREG32(UVD_LMI_ADDR_EXT, (addr << 12) | (addr << 0));
140591d5043SFrançois Tigeot
141591d5043SFrançois Tigeot /* bits 32-39 */
142591d5043SFrançois Tigeot addr = (rdev->uvd.gpu_addr >> 32) & 0xFF;
143591d5043SFrançois Tigeot WREG32(UVD_LMI_EXT40_ADDR, addr | (0x9 << 16) | (0x1 << 31));
144591d5043SFrançois Tigeot
145591d5043SFrançois Tigeot WREG32(UVD_FW_START, *((uint32_t*)rdev->uvd.cpu_addr));
146591d5043SFrançois Tigeot
147591d5043SFrançois Tigeot return 0;
148591d5043SFrançois Tigeot }
149591d5043SFrançois Tigeot
150591d5043SFrançois Tigeot /**
1514cd92098Szrj * uvd_v1_0_init - start and test UVD block
1524cd92098Szrj *
1534cd92098Szrj * @rdev: radeon_device pointer
1544cd92098Szrj *
1554cd92098Szrj * Initialize the hardware, boot up the VCPU and do some testing
1564cd92098Szrj */
uvd_v1_0_init(struct radeon_device * rdev)1574cd92098Szrj int uvd_v1_0_init(struct radeon_device *rdev)
1584cd92098Szrj {
1594cd92098Szrj struct radeon_ring *ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX];
1604cd92098Szrj uint32_t tmp;
1614cd92098Szrj int r;
1624cd92098Szrj
1634cd92098Szrj /* raise clocks while booting up the VCPU */
164c6f73aabSFrançois Tigeot if (rdev->family < CHIP_RV740)
165c6f73aabSFrançois Tigeot radeon_set_uvd_clocks(rdev, 10000, 10000);
166c6f73aabSFrançois Tigeot else
1674cd92098Szrj radeon_set_uvd_clocks(rdev, 53300, 40000);
1684cd92098Szrj
1694cd92098Szrj r = uvd_v1_0_start(rdev);
1704cd92098Szrj if (r)
1714cd92098Szrj goto done;
1724cd92098Szrj
1734cd92098Szrj ring->ready = true;
1744cd92098Szrj r = radeon_ring_test(rdev, R600_RING_TYPE_UVD_INDEX, ring);
1754cd92098Szrj if (r) {
1764cd92098Szrj ring->ready = false;
1774cd92098Szrj goto done;
1784cd92098Szrj }
1794cd92098Szrj
1804cd92098Szrj r = radeon_ring_lock(rdev, ring, 10);
1814cd92098Szrj if (r) {
1824cd92098Szrj DRM_ERROR("radeon: ring failed to lock UVD ring (%d).\n", r);
1834cd92098Szrj goto done;
1844cd92098Szrj }
1854cd92098Szrj
1864cd92098Szrj tmp = PACKET0(UVD_SEMA_WAIT_FAULT_TIMEOUT_CNTL, 0);
1874cd92098Szrj radeon_ring_write(ring, tmp);
1884cd92098Szrj radeon_ring_write(ring, 0xFFFFF);
1894cd92098Szrj
1904cd92098Szrj tmp = PACKET0(UVD_SEMA_WAIT_INCOMPLETE_TIMEOUT_CNTL, 0);
1914cd92098Szrj radeon_ring_write(ring, tmp);
1924cd92098Szrj radeon_ring_write(ring, 0xFFFFF);
1934cd92098Szrj
1944cd92098Szrj tmp = PACKET0(UVD_SEMA_SIGNAL_INCOMPLETE_TIMEOUT_CNTL, 0);
1954cd92098Szrj radeon_ring_write(ring, tmp);
1964cd92098Szrj radeon_ring_write(ring, 0xFFFFF);
1974cd92098Szrj
1984cd92098Szrj /* Clear timeout status bits */
1994cd92098Szrj radeon_ring_write(ring, PACKET0(UVD_SEMA_TIMEOUT_STATUS, 0));
2004cd92098Szrj radeon_ring_write(ring, 0x8);
2014cd92098Szrj
2024cd92098Szrj radeon_ring_write(ring, PACKET0(UVD_SEMA_CNTL, 0));
2034cd92098Szrj radeon_ring_write(ring, 3);
2044cd92098Szrj
205c6f73aabSFrançois Tigeot radeon_ring_unlock_commit(rdev, ring, false);
2064cd92098Szrj
2074cd92098Szrj done:
2084cd92098Szrj /* lower clocks again */
2094cd92098Szrj radeon_set_uvd_clocks(rdev, 0, 0);
2104cd92098Szrj
211591d5043SFrançois Tigeot if (!r) {
212591d5043SFrançois Tigeot switch (rdev->family) {
213591d5043SFrançois Tigeot case CHIP_RV610:
214591d5043SFrançois Tigeot case CHIP_RV630:
215591d5043SFrançois Tigeot case CHIP_RV620:
216591d5043SFrançois Tigeot /* 64byte granularity workaround */
217591d5043SFrançois Tigeot WREG32(MC_CONFIG, 0);
218591d5043SFrançois Tigeot WREG32(MC_CONFIG, 1 << 4);
219591d5043SFrançois Tigeot WREG32(RS_DQ_RD_RET_CONF, 0x3f);
220591d5043SFrançois Tigeot WREG32(MC_CONFIG, 0x1f);
221591d5043SFrançois Tigeot
222591d5043SFrançois Tigeot /* fall through */
223591d5043SFrançois Tigeot case CHIP_RV670:
224591d5043SFrançois Tigeot case CHIP_RV635:
225591d5043SFrançois Tigeot
226591d5043SFrançois Tigeot /* write clean workaround */
227591d5043SFrançois Tigeot WREG32_P(UVD_VCPU_CNTL, 0x10, ~0x10);
228591d5043SFrançois Tigeot break;
229591d5043SFrançois Tigeot
230591d5043SFrançois Tigeot default:
231591d5043SFrançois Tigeot /* TODO: Do we need more? */
232591d5043SFrançois Tigeot break;
233591d5043SFrançois Tigeot }
234591d5043SFrançois Tigeot
2354cd92098Szrj DRM_INFO("UVD initialized successfully.\n");
236591d5043SFrançois Tigeot }
2374cd92098Szrj
2384cd92098Szrj return r;
2394cd92098Szrj }
2404cd92098Szrj
2414cd92098Szrj /**
2424cd92098Szrj * uvd_v1_0_fini - stop the hardware block
2434cd92098Szrj *
2444cd92098Szrj * @rdev: radeon_device pointer
2454cd92098Szrj *
2464cd92098Szrj * Stop the UVD block, mark ring as not ready any more
2474cd92098Szrj */
uvd_v1_0_fini(struct radeon_device * rdev)2484cd92098Szrj void uvd_v1_0_fini(struct radeon_device *rdev)
2494cd92098Szrj {
2504cd92098Szrj struct radeon_ring *ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX];
2514cd92098Szrj
2524cd92098Szrj uvd_v1_0_stop(rdev);
2534cd92098Szrj ring->ready = false;
2544cd92098Szrj }
2554cd92098Szrj
2564cd92098Szrj /**
2574cd92098Szrj * uvd_v1_0_start - start UVD block
2584cd92098Szrj *
2594cd92098Szrj * @rdev: radeon_device pointer
2604cd92098Szrj *
2614cd92098Szrj * Setup and start the UVD block
2624cd92098Szrj */
uvd_v1_0_start(struct radeon_device * rdev)2634cd92098Szrj int uvd_v1_0_start(struct radeon_device *rdev)
2644cd92098Szrj {
2654cd92098Szrj struct radeon_ring *ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX];
2664cd92098Szrj uint32_t rb_bufsz;
2674cd92098Szrj int i, j, r;
2684cd92098Szrj
2694cd92098Szrj /* disable byte swapping */
2704cd92098Szrj u32 lmi_swap_cntl = 0;
2714cd92098Szrj u32 mp_swap_cntl = 0;
2724cd92098Szrj
2734cd92098Szrj /* disable clock gating */
2744cd92098Szrj WREG32(UVD_CGC_GATE, 0);
2754cd92098Szrj
2764cd92098Szrj /* disable interupt */
2774cd92098Szrj WREG32_P(UVD_MASTINT_EN, 0, ~(1 << 1));
2784cd92098Szrj
2794cd92098Szrj /* Stall UMC and register bus before resetting VCPU */
2804cd92098Szrj WREG32_P(UVD_LMI_CTRL2, 1 << 8, ~(1 << 8));
2814cd92098Szrj WREG32_P(UVD_RB_ARB_CTRL, 1 << 3, ~(1 << 3));
2824cd92098Szrj mdelay(1);
2834cd92098Szrj
2844cd92098Szrj /* put LMI, VCPU, RBC etc... into reset */
2854cd92098Szrj WREG32(UVD_SOFT_RESET, LMI_SOFT_RESET | VCPU_SOFT_RESET |
2864cd92098Szrj LBSI_SOFT_RESET | RBC_SOFT_RESET | CSM_SOFT_RESET |
2874cd92098Szrj CXW_SOFT_RESET | TAP_SOFT_RESET | LMI_UMC_SOFT_RESET);
2884cd92098Szrj mdelay(5);
2894cd92098Szrj
2904cd92098Szrj /* take UVD block out of reset */
2914cd92098Szrj WREG32_P(SRBM_SOFT_RESET, 0, ~SOFT_RESET_UVD);
2924cd92098Szrj mdelay(5);
2934cd92098Szrj
2944cd92098Szrj /* initialize UVD memory controller */
2954cd92098Szrj WREG32(UVD_LMI_CTRL, 0x40 | (1 << 8) | (1 << 13) |
2964cd92098Szrj (1 << 21) | (1 << 9) | (1 << 20));
2974cd92098Szrj
2984cd92098Szrj #ifdef __BIG_ENDIAN
2994cd92098Szrj /* swap (8 in 32) RB and IB */
3004cd92098Szrj lmi_swap_cntl = 0xa;
3014cd92098Szrj mp_swap_cntl = 0;
3024cd92098Szrj #endif
3034cd92098Szrj WREG32(UVD_LMI_SWAP_CNTL, lmi_swap_cntl);
3044cd92098Szrj WREG32(UVD_MP_SWAP_CNTL, mp_swap_cntl);
3054cd92098Szrj
3064cd92098Szrj WREG32(UVD_MPC_SET_MUXA0, 0x40c2040);
3074cd92098Szrj WREG32(UVD_MPC_SET_MUXA1, 0x0);
3084cd92098Szrj WREG32(UVD_MPC_SET_MUXB0, 0x40c2040);
3094cd92098Szrj WREG32(UVD_MPC_SET_MUXB1, 0x0);
3104cd92098Szrj WREG32(UVD_MPC_SET_ALU, 0);
3114cd92098Szrj WREG32(UVD_MPC_SET_MUX, 0x88);
3124cd92098Szrj
3134cd92098Szrj /* take all subblocks out of reset, except VCPU */
3144cd92098Szrj WREG32(UVD_SOFT_RESET, VCPU_SOFT_RESET);
3154cd92098Szrj mdelay(5);
3164cd92098Szrj
3174cd92098Szrj /* enable VCPU clock */
3184cd92098Szrj WREG32(UVD_VCPU_CNTL, 1 << 9);
3194cd92098Szrj
3204cd92098Szrj /* enable UMC */
3214cd92098Szrj WREG32_P(UVD_LMI_CTRL2, 0, ~(1 << 8));
3224cd92098Szrj
323591d5043SFrançois Tigeot WREG32_P(UVD_RB_ARB_CTRL, 0, ~(1 << 3));
324591d5043SFrançois Tigeot
3254cd92098Szrj /* boot up the VCPU */
3264cd92098Szrj WREG32(UVD_SOFT_RESET, 0);
3274cd92098Szrj mdelay(10);
3284cd92098Szrj
3294cd92098Szrj for (i = 0; i < 10; ++i) {
3304cd92098Szrj uint32_t status;
3314cd92098Szrj for (j = 0; j < 100; ++j) {
3324cd92098Szrj status = RREG32(UVD_STATUS);
3334cd92098Szrj if (status & 2)
3344cd92098Szrj break;
3354cd92098Szrj mdelay(10);
3364cd92098Szrj }
3374cd92098Szrj r = 0;
3384cd92098Szrj if (status & 2)
3394cd92098Szrj break;
3404cd92098Szrj
3414cd92098Szrj DRM_ERROR("UVD not responding, trying to reset the VCPU!!!\n");
3424cd92098Szrj WREG32_P(UVD_SOFT_RESET, VCPU_SOFT_RESET, ~VCPU_SOFT_RESET);
3434cd92098Szrj mdelay(10);
3444cd92098Szrj WREG32_P(UVD_SOFT_RESET, 0, ~VCPU_SOFT_RESET);
3454cd92098Szrj mdelay(10);
3464cd92098Szrj r = -1;
3474cd92098Szrj }
3484cd92098Szrj
3494cd92098Szrj if (r) {
3504cd92098Szrj DRM_ERROR("UVD not responding, giving up!!!\n");
3514cd92098Szrj return r;
3524cd92098Szrj }
3534cd92098Szrj
3544cd92098Szrj /* enable interupt */
3554cd92098Szrj WREG32_P(UVD_MASTINT_EN, 3<<1, ~(3 << 1));
3564cd92098Szrj
3574cd92098Szrj /* force RBC into idle state */
3584cd92098Szrj WREG32(UVD_RBC_RB_CNTL, 0x11010101);
3594cd92098Szrj
3604cd92098Szrj /* Set the write pointer delay */
3614cd92098Szrj WREG32(UVD_RBC_RB_WPTR_CNTL, 0);
3624cd92098Szrj
3634cd92098Szrj /* programm the 4GB memory segment for rptr and ring buffer */
3644cd92098Szrj WREG32(UVD_LMI_EXT40_ADDR, upper_32_bits(ring->gpu_addr) |
3654cd92098Szrj (0x7 << 16) | (0x1 << 31));
3664cd92098Szrj
3674cd92098Szrj /* Initialize the ring buffer's read and write pointers */
3684cd92098Szrj WREG32(UVD_RBC_RB_RPTR, 0x0);
3694cd92098Szrj
370c6f73aabSFrançois Tigeot ring->wptr = RREG32(UVD_RBC_RB_RPTR);
3714cd92098Szrj WREG32(UVD_RBC_RB_WPTR, ring->wptr);
3724cd92098Szrj
3734cd92098Szrj /* set the ring address */
3744cd92098Szrj WREG32(UVD_RBC_RB_BASE, ring->gpu_addr);
3754cd92098Szrj
3764cd92098Szrj /* Set ring buffer size */
3774cd92098Szrj rb_bufsz = order_base_2(ring->ring_size);
3784cd92098Szrj rb_bufsz = (0x1 << 8) | rb_bufsz;
3794cd92098Szrj WREG32_P(UVD_RBC_RB_CNTL, rb_bufsz, ~0x11f1f);
3804cd92098Szrj
3814cd92098Szrj return 0;
3824cd92098Szrj }
3834cd92098Szrj
3844cd92098Szrj /**
3854cd92098Szrj * uvd_v1_0_stop - stop UVD block
3864cd92098Szrj *
3874cd92098Szrj * @rdev: radeon_device pointer
3884cd92098Szrj *
3894cd92098Szrj * stop the UVD block
3904cd92098Szrj */
uvd_v1_0_stop(struct radeon_device * rdev)3914cd92098Szrj void uvd_v1_0_stop(struct radeon_device *rdev)
3924cd92098Szrj {
3934cd92098Szrj /* force RBC into idle state */
3944cd92098Szrj WREG32(UVD_RBC_RB_CNTL, 0x11010101);
3954cd92098Szrj
3964cd92098Szrj /* Stall UMC and register bus before resetting VCPU */
3974cd92098Szrj WREG32_P(UVD_LMI_CTRL2, 1 << 8, ~(1 << 8));
3984cd92098Szrj WREG32_P(UVD_RB_ARB_CTRL, 1 << 3, ~(1 << 3));
3994cd92098Szrj mdelay(1);
4004cd92098Szrj
4014cd92098Szrj /* put VCPU into reset */
4024cd92098Szrj WREG32(UVD_SOFT_RESET, VCPU_SOFT_RESET);
4034cd92098Szrj mdelay(5);
4044cd92098Szrj
4054cd92098Szrj /* disable VCPU clock */
4064cd92098Szrj WREG32(UVD_VCPU_CNTL, 0x0);
4074cd92098Szrj
4084cd92098Szrj /* Unstall UMC and register bus */
4094cd92098Szrj WREG32_P(UVD_LMI_CTRL2, 0, ~(1 << 8));
4104cd92098Szrj WREG32_P(UVD_RB_ARB_CTRL, 0, ~(1 << 3));
4114cd92098Szrj }
4124cd92098Szrj
4134cd92098Szrj /**
4144cd92098Szrj * uvd_v1_0_ring_test - register write test
4154cd92098Szrj *
4164cd92098Szrj * @rdev: radeon_device pointer
4174cd92098Szrj * @ring: radeon_ring pointer
4184cd92098Szrj *
4194cd92098Szrj * Test if we can successfully write to the context register
4204cd92098Szrj */
uvd_v1_0_ring_test(struct radeon_device * rdev,struct radeon_ring * ring)4214cd92098Szrj int uvd_v1_0_ring_test(struct radeon_device *rdev, struct radeon_ring *ring)
4224cd92098Szrj {
4234cd92098Szrj uint32_t tmp = 0;
4244cd92098Szrj unsigned i;
4254cd92098Szrj int r;
4264cd92098Szrj
4274cd92098Szrj WREG32(UVD_CONTEXT_ID, 0xCAFEDEAD);
4284cd92098Szrj r = radeon_ring_lock(rdev, ring, 3);
4294cd92098Szrj if (r) {
4304cd92098Szrj DRM_ERROR("radeon: cp failed to lock ring %d (%d).\n",
4314cd92098Szrj ring->idx, r);
4324cd92098Szrj return r;
4334cd92098Szrj }
4344cd92098Szrj radeon_ring_write(ring, PACKET0(UVD_CONTEXT_ID, 0));
4354cd92098Szrj radeon_ring_write(ring, 0xDEADBEEF);
436c6f73aabSFrançois Tigeot radeon_ring_unlock_commit(rdev, ring, false);
4374cd92098Szrj for (i = 0; i < rdev->usec_timeout; i++) {
4384cd92098Szrj tmp = RREG32(UVD_CONTEXT_ID);
4394cd92098Szrj if (tmp == 0xDEADBEEF)
4404cd92098Szrj break;
4414cd92098Szrj DRM_UDELAY(1);
4424cd92098Szrj }
4434cd92098Szrj
4444cd92098Szrj if (i < rdev->usec_timeout) {
4454cd92098Szrj DRM_INFO("ring test on %d succeeded in %d usecs\n",
4464cd92098Szrj ring->idx, i);
4474cd92098Szrj } else {
4484cd92098Szrj DRM_ERROR("radeon: ring %d test failed (0x%08X)\n",
4494cd92098Szrj ring->idx, tmp);
4504cd92098Szrj r = -EINVAL;
4514cd92098Szrj }
4524cd92098Szrj return r;
4534cd92098Szrj }
4544cd92098Szrj
4554cd92098Szrj /**
4564cd92098Szrj * uvd_v1_0_semaphore_emit - emit semaphore command
4574cd92098Szrj *
4584cd92098Szrj * @rdev: radeon_device pointer
4594cd92098Szrj * @ring: radeon_ring pointer
4604cd92098Szrj * @semaphore: semaphore to emit commands for
4614cd92098Szrj * @emit_wait: true if we should emit a wait command
4624cd92098Szrj *
4634cd92098Szrj * Emit a semaphore command (either wait or signal) to the UVD ring.
4644cd92098Szrj */
uvd_v1_0_semaphore_emit(struct radeon_device * rdev,struct radeon_ring * ring,struct radeon_semaphore * semaphore,bool emit_wait)465c6f73aabSFrançois Tigeot bool uvd_v1_0_semaphore_emit(struct radeon_device *rdev,
4664cd92098Szrj struct radeon_ring *ring,
4674cd92098Szrj struct radeon_semaphore *semaphore,
4684cd92098Szrj bool emit_wait)
4694cd92098Szrj {
470c59a5c48SFrançois Tigeot /* disable semaphores for UVD V1 hardware */
471c59a5c48SFrançois Tigeot return false;
4724cd92098Szrj }
4734cd92098Szrj
4744cd92098Szrj /**
4754cd92098Szrj * uvd_v1_0_ib_execute - execute indirect buffer
4764cd92098Szrj *
4774cd92098Szrj * @rdev: radeon_device pointer
4784cd92098Szrj * @ib: indirect buffer to execute
4794cd92098Szrj *
4804cd92098Szrj * Write ring commands to execute the indirect buffer
4814cd92098Szrj */
uvd_v1_0_ib_execute(struct radeon_device * rdev,struct radeon_ib * ib)4824cd92098Szrj void uvd_v1_0_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib)
4834cd92098Szrj {
4844cd92098Szrj struct radeon_ring *ring = &rdev->ring[ib->ring];
4854cd92098Szrj
4864cd92098Szrj radeon_ring_write(ring, PACKET0(UVD_RBC_IB_BASE, 0));
4874cd92098Szrj radeon_ring_write(ring, ib->gpu_addr);
4884cd92098Szrj radeon_ring_write(ring, PACKET0(UVD_RBC_IB_SIZE, 0));
4894cd92098Szrj radeon_ring_write(ring, ib->length_dw);
4904cd92098Szrj }
4914cd92098Szrj
4924cd92098Szrj /**
4934cd92098Szrj * uvd_v1_0_ib_test - test ib execution
4944cd92098Szrj *
4954cd92098Szrj * @rdev: radeon_device pointer
4964cd92098Szrj * @ring: radeon_ring pointer
4974cd92098Szrj *
4984cd92098Szrj * Test if we can successfully execute an IB
4994cd92098Szrj */
uvd_v1_0_ib_test(struct radeon_device * rdev,struct radeon_ring * ring)5004cd92098Szrj int uvd_v1_0_ib_test(struct radeon_device *rdev, struct radeon_ring *ring)
5014cd92098Szrj {
5024cd92098Szrj struct radeon_fence *fence = NULL;
5034cd92098Szrj int r;
5044cd92098Szrj
505c6f73aabSFrançois Tigeot if (rdev->family < CHIP_RV740)
506c6f73aabSFrançois Tigeot r = radeon_set_uvd_clocks(rdev, 10000, 10000);
507c6f73aabSFrançois Tigeot else
5084cd92098Szrj r = radeon_set_uvd_clocks(rdev, 53300, 40000);
5094cd92098Szrj if (r) {
5104cd92098Szrj DRM_ERROR("radeon: failed to raise UVD clocks (%d).\n", r);
5114cd92098Szrj return r;
5124cd92098Szrj }
5134cd92098Szrj
5144cd92098Szrj r = radeon_uvd_get_create_msg(rdev, ring->idx, 1, NULL);
5154cd92098Szrj if (r) {
5164cd92098Szrj DRM_ERROR("radeon: failed to get create msg (%d).\n", r);
5174cd92098Szrj goto error;
5184cd92098Szrj }
5194cd92098Szrj
5204cd92098Szrj r = radeon_uvd_get_destroy_msg(rdev, ring->idx, 1, &fence);
5214cd92098Szrj if (r) {
5224cd92098Szrj DRM_ERROR("radeon: failed to get destroy ib (%d).\n", r);
5234cd92098Szrj goto error;
5244cd92098Szrj }
5254cd92098Szrj
526*d78d3a22SFrançois Tigeot r = radeon_fence_wait_timeout(fence, false, usecs_to_jiffies(
527*d78d3a22SFrançois Tigeot RADEON_USEC_IB_TEST_TIMEOUT));
528*d78d3a22SFrançois Tigeot if (r < 0) {
5294cd92098Szrj DRM_ERROR("radeon: fence wait failed (%d).\n", r);
5304cd92098Szrj goto error;
531*d78d3a22SFrançois Tigeot } else if (r == 0) {
532*d78d3a22SFrançois Tigeot DRM_ERROR("radeon: fence wait timed out.\n");
533*d78d3a22SFrançois Tigeot r = -ETIMEDOUT;
534*d78d3a22SFrançois Tigeot goto error;
5354cd92098Szrj }
536*d78d3a22SFrançois Tigeot r = 0;
5374cd92098Szrj DRM_INFO("ib test on ring %d succeeded\n", ring->idx);
5384cd92098Szrj error:
5394cd92098Szrj radeon_fence_unref(&fence);
5404cd92098Szrj radeon_set_uvd_clocks(rdev, 0, 0);
5414cd92098Szrj return r;
5424cd92098Szrj }
543