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