[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