/* * Copyright 2014 Advanced Micro Devices, Inc. * All Rights Reserved. * * 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, sub license, 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 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 NON-INFRINGEMENT. IN NO EVENT SHALL * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS 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. * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial portions * of the Software. * * Authors: Christian König <christian.koenig@amd.com>
*/
/* Set Override to disable Clock Gating */
vce_v3_0_override_vce_clock_gating(adev, true);
/* This function enables MGCG which is controlled by firmware. With the clocks in the gated state the core is still accessible but the firmware will throttle the clocks on the fly as necessary.
*/ if (!gated) {
data = RREG32(mmVCE_CLOCK_GATING_B);
data |= 0x1ff;
data &= ~0xef0000;
WREG32(mmVCE_CLOCK_GATING_B, data);
data = RREG32(mmVCE_UENC_CLOCK_GATING);
data |= 0x3ff000;
data &= ~0xffc00000;
WREG32(mmVCE_UENC_CLOCK_GATING, data);
data = RREG32(mmVCE_UENC_CLOCK_GATING_2);
data |= 0x2;
data &= ~0x00010000;
WREG32(mmVCE_UENC_CLOCK_GATING_2, data);
data = RREG32(mmVCE_UENC_REG_CLOCK_GATING);
data |= 0x37f;
WREG32(mmVCE_UENC_REG_CLOCK_GATING, data);
data = RREG32(mmVCE_UENC_DMA_DCLK_CTRL);
data |= VCE_UENC_DMA_DCLK_CTRL__WRDMCLK_FORCEON_MASK |
VCE_UENC_DMA_DCLK_CTRL__RDDMCLK_FORCEON_MASK |
VCE_UENC_DMA_DCLK_CTRL__REGCLK_FORCEON_MASK |
0x8;
WREG32(mmVCE_UENC_DMA_DCLK_CTRL, data);
} else {
data = RREG32(mmVCE_CLOCK_GATING_B);
data &= ~0x80010;
data |= 0xe70008;
WREG32(mmVCE_CLOCK_GATING_B, data);
data = RREG32(mmVCE_UENC_CLOCK_GATING);
data |= 0xffc00000;
WREG32(mmVCE_UENC_CLOCK_GATING, data);
data = RREG32(mmVCE_UENC_CLOCK_GATING_2);
data |= 0x10000;
WREG32(mmVCE_UENC_CLOCK_GATING_2, data);
data = RREG32(mmVCE_UENC_REG_CLOCK_GATING);
data &= ~0x3ff;
WREG32(mmVCE_UENC_REG_CLOCK_GATING, data);
data = RREG32(mmVCE_UENC_DMA_DCLK_CTRL);
data &= ~(VCE_UENC_DMA_DCLK_CTRL__WRDMCLK_FORCEON_MASK |
VCE_UENC_DMA_DCLK_CTRL__RDDMCLK_FORCEON_MASK |
VCE_UENC_DMA_DCLK_CTRL__REGCLK_FORCEON_MASK |
0x8);
WREG32(mmVCE_UENC_DMA_DCLK_CTRL, data);
}
vce_v3_0_override_vce_clock_gating(adev, false);
}
staticint vce_v3_0_firmware_loaded(struct amdgpu_device *adev)
{ int i, j;
for (i = 0; i < 10; ++i) { for (j = 0; j < 100; ++j) {
uint32_t status = RREG32(mmVCE_STATUS);
if (status & VCE_STATUS_VCPU_REPORT_FW_LOADED_MASK) return 0;
mdelay(10);
}
DRM_ERROR("VCE not responding, trying to reset the ECPU!!!\n");
WREG32_FIELD(VCE_SOFT_RESET, ECPU_SOFT_RESET, 1);
mdelay(10);
WREG32_FIELD(VCE_SOFT_RESET, ECPU_SOFT_RESET, 0);
mdelay(10);
}
mutex_lock(&adev->grbm_idx_mutex); for (idx = 0; idx < 2; ++idx) { if (adev->vce.harvest_config & (1 << idx)) continue;
WREG32(mmGRBM_GFX_INDEX, GET_VCE_INSTANCE(idx));
/* Program instance 0 reg space for two instances or instance 0 case
program instance 1 reg space for only instance 1 available case */ if (idx != 1 || adev->vce.harvest_config == AMDGPU_VCE_HARVEST_VCE0) {
ring = &adev->vce.ring[0];
WREG32(mmVCE_RB_RPTR, lower_32_bits(ring->wptr));
WREG32(mmVCE_RB_WPTR, lower_32_bits(ring->wptr));
WREG32(mmVCE_RB_BASE_LO, ring->gpu_addr);
WREG32(mmVCE_RB_BASE_HI, upper_32_bits(ring->gpu_addr));
WREG32(mmVCE_RB_SIZE, ring->ring_size / 4);
/* * 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->vce.idle_work);
/* According to VCE team , we should use VCE_STATUS instead * SRBM_STATUS.VCE_BUSY bit for busy status checking. * GRBM_GFX_INDEX.INSTANCE_INDEX is used to specify which VCE * instance's registers are accessed * (0 for 1st instance, 10 for 2nd instance). * *VCE_STATUS *|UENC|ACPI|AUTO ACTIVE|RB1 |RB0 |RB2 | |FW_LOADED|JOB | *|----+----+-----------+----+----+----+----------+---------+----| *|bit8|bit7| bit6 |bit5|bit4|bit3| bit2 | bit1 |bit0| * * VCE team suggest use bit 3--bit 6 for busy status check
*/
mutex_lock(&adev->grbm_idx_mutex);
WREG32(mmGRBM_GFX_INDEX, GET_VCE_INSTANCE(0)); if (RREG32(mmVCE_STATUS) & AMDGPU_VCE_STATUS_BUSY_MASK) {
srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE0, 1);
srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE1, 1);
}
WREG32(mmGRBM_GFX_INDEX, GET_VCE_INSTANCE(1)); if (RREG32(mmVCE_STATUS) & AMDGPU_VCE_STATUS_BUSY_MASK) {
srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE0, 1);
srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE1, 1);
}
WREG32(mmGRBM_GFX_INDEX, GET_VCE_INSTANCE(0));
mutex_unlock(&adev->grbm_idx_mutex);
if (!(adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG)) return 0;
mutex_lock(&adev->grbm_idx_mutex); for (i = 0; i < 2; i++) { /* Program VCE Instance 0 or 1 if not harvested */ if (adev->vce.harvest_config & (1 << i)) continue;
WREG32(mmGRBM_GFX_INDEX, GET_VCE_INSTANCE(i));
if (!enable) { /* initialize VCE_CLOCK_GATING_A: Clock ON/OFF delay */
uint32_t data = RREG32(mmVCE_CLOCK_GATING_A);
data &= ~(0xf | 0xff0);
data |= ((0x0 << 0) | (0x04 << 4));
WREG32(mmVCE_CLOCK_GATING_A, data);
/* initialize VCE_UENC_CLOCK_GATING: Clock ON/OFF delay */
data = RREG32(mmVCE_UENC_CLOCK_GATING);
data &= ~(0xf | 0xff0);
data |= ((0x0 << 0) | (0x04 << 4));
WREG32(mmVCE_UENC_CLOCK_GATING, data);
}
staticint vce_v3_0_set_powergating_state(struct amdgpu_ip_block *ip_block, enum amd_powergating_state state)
{ /* This doesn't actually powergate the VCE 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; int ret = 0;
if (state == AMD_PG_STATE_GATE) {
ret = vce_v3_0_stop(adev); if (ret) goto out;
} else {
ret = vce_v3_0_start(adev); if (ret) goto out;
}
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.