[PATCH 6/6] drm/amdgpu: Enable static pg feature on RV
Alex Deucher
alexdeucher at gmail.com
Wed May 16 15:51:28 UTC 2018
On Wed, May 16, 2018 at 8:53 AM, Rex Zhu <Rex.Zhu at amd.com> wrote:
> Signed-off-by: Rex Zhu <Rex.Zhu at amd.com>
> ---
> drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h | 11 ++
> drivers/gpu/drm/amd/amdgpu/soc15.c | 3 +-
> drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c | 183 ++++++++++++++++++++++++++++++--
> 3 files changed, 187 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h
> index 2fd7db8..181e6af 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h
> @@ -45,6 +45,17 @@
> #define VCN_ENC_CMD_REG_WRITE 0x0000000b
> #define VCN_ENC_CMD_REG_WAIT 0x0000000c
>
> +enum engine_status_constants {
> + UVD_PGFSM_STATUS__UVDM_UVDU_PWR_ON = 0x2AAAA0,
> + UVD_PGFSM_CONFIG__UVDM_UVDU_PWR_ON = 0x00000002,
> + UVD_STATUS__UVD_BUSY = 0x00000004,
> + GB_ADDR_CONFIG_DEFAULT = 0x26010011,
> + UVD_STATUS__IDLE = 0x2,
> + UVD_STATUS__BUSY = 0x5,
> + UVD_POWER_STATUS__UVD_POWER_STATUS_TILES_OFF = 0x1,
> + UVD_STATUS__RBC_BUSY = 0x1,
> +};
> +
> struct amdgpu_vcn {
> struct amdgpu_bo *vcpu_bo;
> void *cpu_addr;
> diff --git a/drivers/gpu/drm/amd/amdgpu/soc15.c b/drivers/gpu/drm/amd/amdgpu/soc15.c
> index 485cb43..9a7a85d 100644
> --- a/drivers/gpu/drm/amd/amdgpu/soc15.c
> +++ b/drivers/gpu/drm/amd/amdgpu/soc15.c
> @@ -713,7 +713,8 @@ static int soc15_common_early_init(void *handle)
> AMD_CG_SUPPORT_SDMA_MGCG |
> AMD_CG_SUPPORT_SDMA_LS |
> AMD_CG_SUPPORT_VCN_MGCG;
> - adev->pg_flags = AMD_PG_SUPPORT_SDMA;
> +
> + adev->pg_flags = AMD_PG_SUPPORT_SDMA | AMD_PG_SUPPORT_VCN;
>
Make this a separate patch. Split out the setting of the flag to
enable this from the implementation.
> if (adev->powerplay.pp_feature & PP_GFXOFF_MASK)
> adev->pg_flags |= AMD_PG_SUPPORT_GFX_PG |
> diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c
> index 9e0a2b1..89a9477 100644
> --- a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c
> +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c
> @@ -146,10 +146,6 @@ static int vcn_v1_0_hw_init(void *handle)
> struct amdgpu_ring *ring = &adev->vcn.ring_dec;
> int i, r;
>
> - r = vcn_v1_0_start(adev);
> - if (r)
> - goto done;
> -
> ring->ready = true;
> r = amdgpu_ring_test_ring(ring);
> if (r) {
> @@ -480,6 +476,117 @@ static void vcn_v1_0_enable_clock_gating(struct amdgpu_device *adev)
> WREG32_SOC15(VCN, 0, mmUVD_SUVD_CGC_CTRL, data);
> }
>
> +static int vcn_wait_on_reg_read(struct amdgpu_device *adev, uint32_t segment_index,
> + uint32_t reg, uint32_t expected_value,
> + uint32_t mask)
> +{
> + uint32_t loop, data;
> +
> + data = RREG32(adev->reg_offset[VCN_HWIP][0][segment_index] + reg);
> +
> + loop = 1000;
> +
> + while ((data & mask) != expected_value) {
> + udelay(10);
> + data = RREG32(adev->reg_offset[VCN_HWIP][0][segment_index] + reg);
> + loop--;
> + if (!loop)
> + return -ETIMEDOUT;
> + }
> +
> + return 0;
> +}
Might be nice to wrap this with a macro so we can do something like:
WAIT_REG_SOC15((reg), (val), (mask))
rather than having to pass the segment_index directly. No big deal either way.
> +
> +static void vcn_1_0_disable_static_power_gating(struct amdgpu_device *adev)
> +{
> + uint32_t data = 0;
> +
> + if (adev->pg_flags & AMD_PG_SUPPORT_VCN) {
> + data = (1 << UVD_PGFSM_CONFIG__UVDM_PWR_CONFIG__SHIFT
> + | 1 << UVD_PGFSM_CONFIG__UVDU_PWR_CONFIG__SHIFT
> + | 2 << UVD_PGFSM_CONFIG__UVDF_PWR_CONFIG__SHIFT
> + | 2 << UVD_PGFSM_CONFIG__UVDC_PWR_CONFIG__SHIFT
> + | 2 << UVD_PGFSM_CONFIG__UVDB_PWR_CONFIG__SHIFT
> + | 2 << UVD_PGFSM_CONFIG__UVDIL_PWR_CONFIG__SHIFT
> + | 2 << UVD_PGFSM_CONFIG__UVDIR_PWR_CONFIG__SHIFT
> + | 2 << UVD_PGFSM_CONFIG__UVDTD_PWR_CONFIG__SHIFT
> + | 2 << UVD_PGFSM_CONFIG__UVDTE_PWR_CONFIG__SHIFT
> + | 2 << UVD_PGFSM_CONFIG__UVDE_PWR_CONFIG__SHIFT
> + | 2 << UVD_PGFSM_CONFIG__UVDW_PWR_CONFIG__SHIFT);
> +
> + WREG32_SOC15(VCN, 0, mmUVD_PGFSM_CONFIG, data);
> + vcn_wait_on_reg_read(adev, mmUVD_PGFSM_STATUS_BASE_IDX, mmUVD_PGFSM_STATUS,
> + UVD_PGFSM_STATUS__UVDM_UVDU_PWR_ON, 0xFFFFFF);
> + } else {
> + data = (1 << UVD_PGFSM_CONFIG__UVDM_PWR_CONFIG__SHIFT
> + | 1 << UVD_PGFSM_CONFIG__UVDU_PWR_CONFIG__SHIFT
> + | 1 << UVD_PGFSM_CONFIG__UVDF_PWR_CONFIG__SHIFT
> + | 1 << UVD_PGFSM_CONFIG__UVDC_PWR_CONFIG__SHIFT
> + | 1 << UVD_PGFSM_CONFIG__UVDB_PWR_CONFIG__SHIFT
> + | 1 << UVD_PGFSM_CONFIG__UVDIL_PWR_CONFIG__SHIFT
> + | 1 << UVD_PGFSM_CONFIG__UVDIR_PWR_CONFIG__SHIFT
> + | 1 << UVD_PGFSM_CONFIG__UVDTD_PWR_CONFIG__SHIFT
> + | 1 << UVD_PGFSM_CONFIG__UVDTE_PWR_CONFIG__SHIFT
> + | 1 << UVD_PGFSM_CONFIG__UVDE_PWR_CONFIG__SHIFT
> + | 1 << UVD_PGFSM_CONFIG__UVDW_PWR_CONFIG__SHIFT);
> + WREG32_SOC15(VCN, 0, mmUVD_PGFSM_CONFIG, data);
> + vcn_wait_on_reg_read(adev, mmUVD_PGFSM_STATUS_BASE_IDX, mmUVD_PGFSM_STATUS,
> + 0, 0xFFFFFFFF);
> + }
> +
> + /* polling UVD_PGFSM_STATUS to confirm UVDM_PWR_STATUS , UVDU_PWR_STATUS are 0 (power on) */
> +
> + data = RREG32_SOC15(VCN, 0, mmUVD_POWER_STATUS);
> + data &= ~0x103;
> + if (adev->pg_flags & AMD_PG_SUPPORT_VCN)
> + data |= UVD_PGFSM_CONFIG__UVDM_UVDU_PWR_ON | UVD_POWER_STATUS__UVD_PG_EN_MASK;
> +
> + WREG32_SOC15(VCN, 0, mmUVD_POWER_STATUS, data);
> +}
> +
> +static void vcn_1_0_enable_static_power_gating(struct amdgpu_device *adev)
> +{
> + uint32_t data = 0;
> +
> + if (adev->pg_flags & AMD_PG_SUPPORT_VCN) {
> + /* Before power off, this indicator has to be turned on */
> + data = RREG32_SOC15(VCN, 0, mmUVD_POWER_STATUS);
> + data &= ~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK;
> + data |= UVD_POWER_STATUS__UVD_POWER_STATUS_TILES_OFF;
> + WREG32_SOC15(VCN, 0, mmUVD_POWER_STATUS, data);
> +
> +
> + data = (2 << UVD_PGFSM_CONFIG__UVDM_PWR_CONFIG__SHIFT
> + | 2 << UVD_PGFSM_CONFIG__UVDU_PWR_CONFIG__SHIFT
> + | 2 << UVD_PGFSM_CONFIG__UVDF_PWR_CONFIG__SHIFT
> + | 2 << UVD_PGFSM_CONFIG__UVDC_PWR_CONFIG__SHIFT
> + | 2 << UVD_PGFSM_CONFIG__UVDB_PWR_CONFIG__SHIFT
> + | 2 << UVD_PGFSM_CONFIG__UVDIL_PWR_CONFIG__SHIFT
> + | 2 << UVD_PGFSM_CONFIG__UVDIR_PWR_CONFIG__SHIFT
> + | 2 << UVD_PGFSM_CONFIG__UVDTD_PWR_CONFIG__SHIFT
> + | 2 << UVD_PGFSM_CONFIG__UVDTE_PWR_CONFIG__SHIFT
> + | 2 << UVD_PGFSM_CONFIG__UVDE_PWR_CONFIG__SHIFT
> + | 2 << UVD_PGFSM_CONFIG__UVDW_PWR_CONFIG__SHIFT);
> +
> + WREG32_SOC15(VCN, 0, mmUVD_PGFSM_CONFIG, data);
> +
> +
> + data = (2 << UVD_PGFSM_STATUS__UVDM_PWR_STATUS__SHIFT
> + | 2 << UVD_PGFSM_STATUS__UVDU_PWR_STATUS__SHIFT
> + | 2 << UVD_PGFSM_STATUS__UVDF_PWR_STATUS__SHIFT
> + | 2 << UVD_PGFSM_STATUS__UVDC_PWR_STATUS__SHIFT
> + | 2 << UVD_PGFSM_STATUS__UVDB_PWR_STATUS__SHIFT
> + | 2 << UVD_PGFSM_STATUS__UVDIL_PWR_STATUS__SHIFT
> + | 2 << UVD_PGFSM_STATUS__UVDIR_PWR_STATUS__SHIFT
> + | 2 << UVD_PGFSM_STATUS__UVDTD_PWR_STATUS__SHIFT
> + | 2 << UVD_PGFSM_STATUS__UVDTE_PWR_STATUS__SHIFT
> + | 2 << UVD_PGFSM_STATUS__UVDE_PWR_STATUS__SHIFT
> + | 2 << UVD_PGFSM_STATUS__UVDW_PWR_STATUS__SHIFT);
> + vcn_wait_on_reg_read(adev, mmUVD_PGFSM_STATUS_BASE_IDX,
> + mmUVD_PGFSM_STATUS, data, 0xFFFFFFFF);
> + }
> +}
> +
> /**
> * vcn_v1_0_start - start VCN block
> *
> @@ -499,6 +606,7 @@ static int vcn_v1_0_start(struct amdgpu_device *adev)
>
> vcn_v1_0_mc_resume(adev);
>
> + vcn_1_0_disable_static_power_gating(adev);
> /* disable clock gating */
> vcn_v1_0_disable_clock_gating(adev);
>
> @@ -681,15 +789,46 @@ static int vcn_v1_0_stop(struct amdgpu_device *adev)
> ~UVD_LMI_CTRL2__STALL_ARB_UMC_MASK);
>
> /* enable clock gating */
> - vcn_v1_0_enable_clock_gating(adev);
>
> + vcn_v1_0_enable_clock_gating(adev);
> + vcn_1_0_enable_static_power_gating(adev);
> return 0;
> }
>
> +
> +bool vcn_v1_0_is_idle(void *handle)
> +{
> + struct amdgpu_device *adev = (struct amdgpu_device *)handle;
> +
> + return (RREG32_SOC15(VCN, 0, mmUVD_STATUS) == 0x2);
> +}
> +
> +int vcn_v1_0_wait_for_idle(void *handle)
> +{
> + struct amdgpu_device *adev = (struct amdgpu_device *)handle;
> +
> + vcn_wait_on_reg_read(adev, mmUVD_STATUS_BASE_IDX, mmUVD_STATUS,
> + 0x2, 0x2);
> + return (RREG32_SOC15(VCN, 0, mmUVD_STATUS) == 0x2);
> +}
> +
> static int vcn_v1_0_set_clockgating_state(void *handle,
> enum amd_clockgating_state state)
> {
> - /* needed for driver unload*/
> + struct amdgpu_device *adev = (struct amdgpu_device *)handle;
> + bool enable = (state == AMD_CG_STATE_GATE) ? true : false;
> +
> + if (enable) {
> + /* wait for STATUS to clear */
> + if (vcn_v1_0_is_idle(handle))
> + return -EBUSY;
> + vcn_v1_0_enable_clock_gating(adev);
> + /* enable HW gates because UVD is idle */
> +/* uvd_v6_0_set_hw_clock_gating(adev); */
> + } else {
> + /* disable HW gating and enable Sw gating */
> + vcn_v1_0_disable_clock_gating(adev);
> + }
> return 0;
> }
>
> @@ -1058,6 +1197,32 @@ static void vcn_v1_0_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count)
>
> }
>
> +static int vcn_v1_0_set_powergating_state(void *handle,
> + enum amd_powergating_state state)
> +{
> + /* This doesn't actually powergate the VCN 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 = (struct amdgpu_device *)handle;
> + int ret = 0;
> +
> + //WREG32(mmUVD_POWER_STATUS, UVD_POWER_STATUS__UVD_PG_EN_MASK);
> +
drop this debugging leftover?
> + if (state == AMD_PG_STATE_GATE) {
> + vcn_v1_0_stop(adev);
> + } else {
> + ret = vcn_v1_0_start(adev);
> + if (ret)
> + goto out;
> + }
> +
> +out:
> + return ret;
> +}
>
> static const struct amd_ip_funcs vcn_v1_0_ip_funcs = {
> .name = "vcn_v1_0",
> @@ -1069,14 +1234,14 @@ static void vcn_v1_0_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count)
> .hw_fini = vcn_v1_0_hw_fini,
> .suspend = vcn_v1_0_suspend,
> .resume = vcn_v1_0_resume,
> - .is_idle = NULL /* vcn_v1_0_is_idle */,
> - .wait_for_idle = NULL /* vcn_v1_0_wait_for_idle */,
> + .is_idle = vcn_v1_0_is_idle,
> + .wait_for_idle = vcn_v1_0_wait_for_idle,
> .check_soft_reset = NULL /* vcn_v1_0_check_soft_reset */,
> .pre_soft_reset = NULL /* vcn_v1_0_pre_soft_reset */,
> .soft_reset = NULL /* vcn_v1_0_soft_reset */,
> .post_soft_reset = NULL /* vcn_v1_0_post_soft_reset */,
> .set_clockgating_state = vcn_v1_0_set_clockgating_state,
> - .set_powergating_state = NULL /* vcn_v1_0_set_powergating_state */,
> + .set_powergating_state = vcn_v1_0_set_powergating_state,
> };
>
> static const struct amdgpu_ring_funcs vcn_v1_0_dec_ring_vm_funcs = {
> --
> 1.9.1
>
> _______________________________________________
> amd-gfx mailing list
> amd-gfx at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/amd-gfx
More information about the amd-gfx
mailing list