/* * Copyright 2013 Advanced Micro Devices, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * Authors: Christian König <christian.koenig@amd.com>
*/
staticvoid uvd_v4_2_enable_mgcg(struct amdgpu_device *adev, bool enable); /** * uvd_v4_2_hw_init - start and test UVD block * * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Initialize the hardware, boot up the VCPU and do some testing
*/ staticint uvd_v4_2_hw_init(struct amdgpu_ip_block *ip_block)
{ struct amdgpu_device *adev = ip_block->adev; struct amdgpu_ring *ring = &adev->uvd.inst->ring;
uint32_t tmp; int r;
done: if (!r)
DRM_INFO("UVD initialized successfully.\n");
return r;
}
/** * uvd_v4_2_hw_fini - stop the hardware block * * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Stop the UVD block, mark ring as not ready any more
*/ staticint uvd_v4_2_hw_fini(struct amdgpu_ip_block *ip_block)
{ struct amdgpu_device *adev = ip_block->adev;
cancel_delayed_work_sync(&adev->uvd.idle_work);
if (RREG32(mmUVD_STATUS) != 0)
uvd_v4_2_stop(adev);
/* * Proper cleanups before halting the HW engine: * - cancel the delayed idle work * - enable powergating * - enable clockgating * - disable dpm * * TODO: to align with the VCN implementation, move the * jobs for clockgating/powergating/dpm setting to * ->set_powergating_state().
*/
cancel_delayed_work_sync(&adev->uvd.idle_work);
for (i = 0; i < 10; ++i) {
uint32_t status; for (j = 0; j < 100; ++j) {
status = RREG32(mmUVD_STATUS); if (status & 2) break;
mdelay(10);
}
r = 0; if (status & 2) break;
DRM_ERROR("UVD not responding, trying to reset the VCPU!!!\n");
WREG32_P(mmUVD_SOFT_RESET, UVD_SOFT_RESET__VCPU_SOFT_RESET_MASK,
~UVD_SOFT_RESET__VCPU_SOFT_RESET_MASK);
mdelay(10);
WREG32_P(mmUVD_SOFT_RESET, 0, ~UVD_SOFT_RESET__VCPU_SOFT_RESET_MASK);
mdelay(10);
r = -1;
}
if (r) {
DRM_ERROR("UVD not responding, giving up!!!\n"); return r;
}
for (i = 0; i < 10; ++i) { for (j = 0; j < 100; ++j) {
status = RREG32(mmUVD_STATUS); if (status & 2) break;
mdelay(1);
} if (status & 2) break;
}
for (i = 0; i < 10; ++i) { for (j = 0; j < 100; ++j) {
status = RREG32(mmUVD_LMI_STATUS); if (status & 0xf) break;
mdelay(1);
} if (status & 0xf) break;
}
/* Stall UMC and register bus before resetting VCPU */
WREG32_P(mmUVD_LMI_CTRL2, 1 << 8, ~(1 << 8));
for (i = 0; i < 10; ++i) { for (j = 0; j < 100; ++j) {
status = RREG32(mmUVD_LMI_STATUS); if (status & 0x240) break;
mdelay(1);
} if (status & 0x240) break;
}
WREG32_P(0x3D49, 0, ~(1 << 2));
WREG32_P(mmUVD_VCPU_CNTL, 0, ~(1 << 9));
/* put LMI, VCPU, RBC etc... into reset */
WREG32(mmUVD_SOFT_RESET, UVD_SOFT_RESET__LMI_SOFT_RESET_MASK |
UVD_SOFT_RESET__VCPU_SOFT_RESET_MASK |
UVD_SOFT_RESET__LMI_UMC_SOFT_RESET_MASK);
WREG32(mmUVD_STATUS, 0);
uvd_v4_2_set_dcm(adev, false);
}
/** * uvd_v4_2_ring_emit_fence - emit an fence & trap command * * @ring: amdgpu_ring pointer * @addr: address * @seq: sequence number * @flags: fence related flags * * Write a fence and a trap command to the ring.
*/ staticvoid uvd_v4_2_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 seq, unsigned flags)
{
WARN_ON(flags & AMDGPU_FENCE_FLAG_64BIT);
if (enable && (adev->cg_flags & AMD_CG_SUPPORT_UVD_MGCG)) {
data = RREG32_UVD_CTX(ixUVD_CGC_MEM_CTRL);
data |= 0xfff;
WREG32_UVD_CTX(ixUVD_CGC_MEM_CTRL, data);
orig = data = RREG32(mmUVD_CGC_CTRL);
data |= UVD_CGC_CTRL__DYN_CLOCK_MODE_MASK; if (orig != data)
WREG32(mmUVD_CGC_CTRL, data);
} else {
data = RREG32_UVD_CTX(ixUVD_CGC_MEM_CTRL);
data &= ~0xfff;
WREG32_UVD_CTX(ixUVD_CGC_MEM_CTRL, data);
orig = data = RREG32(mmUVD_CGC_CTRL);
data &= ~UVD_CGC_CTRL__DYN_CLOCK_MODE_MASK; if (orig != data)
WREG32(mmUVD_CGC_CTRL, data);
}
}
staticint uvd_v4_2_set_powergating_state(struct amdgpu_ip_block *ip_block, enum amd_powergating_state state)
{ /* This doesn't actually powergate the UVD block. * That's done in the dpm code via the SMC. This * just re-inits the block as necessary. The actual * gating still happens in the dpm code. We should * revisit this when there is a cleaner line between * the smc and the hw blocks
*/ struct amdgpu_device *adev = ip_block->adev;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.