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