On 2020-06-25 4:14 a.m., Christian König wrote: > Am 24.06.20 um 22:31 schrieb Alex Jivin: >> Port functionality from the Radeon driver to support >> VCE clock control. >> >> Signed-off-by: Alex Jivin <alex.jivin@xxxxxxx> >> --- >> drivers/gpu/drm/amd/amdgpu/amdgpu.h | 9 ++ >> drivers/gpu/drm/amd/amdgpu/si.c | 126 +++++++++++++++++++++++++++- >> drivers/gpu/drm/amd/amdgpu/sid.h | 31 +++++++ >> 3 files changed, 165 insertions(+), 1 deletion(-) >> >> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h >> index 6c7dd0a707c9..4b5a9a259a21 100644 >> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h >> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h >> @@ -1083,6 +1083,15 @@ int emu_soc_asic_init(struct amdgpu_device *adev); >> tmp_ |= ((val) & ~(mask)); \ >> WREG32_PLL(reg, tmp_); \ >> } while (0) >> + >> +#define WREG32_SMC_P(_Reg, _Val, _Mask) \ >> + do { \ >> + u32 tmp = RREG32_SMC(_Reg); \ >> + tmp &= (_Mask); \ >> + tmp |= ((_Val) & ~(_Mask)); \ >> + WREG32_SMC(_Reg, tmp); \ >> + } while (0) >> + >> #define DREG32_SYS(sqf, adev, reg) seq_printf((sqf), #reg " : 0x%08X\n", amdgpu_device_rreg((adev), (reg), false)) >> #define RREG32_IO(reg) amdgpu_io_rreg(adev, (reg)) >> #define WREG32_IO(reg, v) amdgpu_io_wreg(adev, (reg), (v)) >> diff --git a/drivers/gpu/drm/amd/amdgpu/si.c b/drivers/gpu/drm/amd/amdgpu/si.c >> index 93609d69eff2..a5ad48fe502e 100644 >> --- a/drivers/gpu/drm/amd/amdgpu/si.c >> +++ b/drivers/gpu/drm/amd/amdgpu/si.c >> @@ -1650,6 +1650,130 @@ static int si_set_uvd_clocks(struct amdgpu_device *adev, u32 vclk, u32 dclk) >> return 0; >> } >> >> +static int si_vce_send_vcepll_ctlreq(struct amdgpu_device *adev) >> +{ >> + unsigned i; >> + >> + /* Make sure VCEPLL_CTLREQ is deasserted */ >> + WREG32_SMC_P(CG_VCEPLL_FUNC_CNTL, 0, ~UPLL_CTLREQ_MASK); >> + >> + mdelay(10); >> + >> + /* Assert UPLL_CTLREQ */ >> + WREG32_SMC_P(CG_VCEPLL_FUNC_CNTL, UPLL_CTLREQ_MASK, ~UPLL_CTLREQ_MASK); >> + >> + /* Wait for CTLACK and CTLACK2 to get asserted */ >> + for (i = 0; i < SI_MAX_CTLACKS_ASSERTION_WAIT; ++i) { >> + uint32_t mask = UPLL_CTLACK_MASK | UPLL_CTLACK2_MASK; >> + >> + if ((RREG32_SMC(CG_VCEPLL_FUNC_CNTL) & mask) == mask) >> + break; >> + mdelay(10); >> + } >> + >> + /* Deassert UPLL_CTLREQ */ >> + WREG32_SMC_P(CG_VCEPLL_FUNC_CNTL, 0, ~UPLL_CTLREQ_MASK); >> + >> + if (i == SI_MAX_CTLACKS_ASSERTION_WAIT) { >> + DRM_ERROR("Timeout setting UVD clocks!\n"); >> + return -ETIMEDOUT; >> + } >> + >> + return 0; >> +} >> + >> +static int si_set_vce_clocks(struct amdgpu_device *adev, u32 evclk, u32 ecclk) >> +{ >> + unsigned fb_div = 0, evclk_div = 0, ecclk_div = 0; >> + int a; > > Why "a"? Was that in radeon as well? > > We usually use r or ret for the return/error code of functions. > > Christian. > Changed it to r. Thanks Alex J >> + >> + /* Bypass evclk and ecclk with bclk */ >> + WREG32_SMC_P(CG_VCEPLL_FUNC_CNTL_2, >> + EVCLK_SRC_SEL(1) | ECCLK_SRC_SEL(1), >> + ~(EVCLK_SRC_SEL_MASK | ECCLK_SRC_SEL_MASK)); >> + >> + /* Put PLL in bypass mode */ >> + WREG32_SMC_P(CG_VCEPLL_FUNC_CNTL, VCEPLL_BYPASS_EN_MASK, >> + ~VCEPLL_BYPASS_EN_MASK); >> + >> + if (!evclk || !ecclk) { >> + /* Keep the Bypass mode, put PLL to sleep */ >> + WREG32_SMC_P(CG_VCEPLL_FUNC_CNTL, VCEPLL_SLEEP_MASK, >> + ~VCEPLL_SLEEP_MASK); >> + return 0; >> + } >> + >> + a = si_calc_upll_dividers(adev, evclk, ecclk, 125000, 250000, >> + 16384, 0x03FFFFFF, 0, 128, 5, >> + &fb_div, &evclk_div, &ecclk_div); >> + if (a) >> + return a; >> + >> + /* Set RESET_ANTI_MUX to 0 */ >> + WREG32_SMC_P(CG_VCEPLL_FUNC_CNTL_5, 0, ~RESET_ANTI_MUX_MASK); >> + >> + /* Set VCO_MODE to 1 */ >> + WREG32_SMC_P(CG_VCEPLL_FUNC_CNTL, VCEPLL_VCO_MODE_MASK, >> + ~VCEPLL_VCO_MODE_MASK); >> + >> + /* Toggle VCEPLL_SLEEP to 1 then back to 0 */ >> + WREG32_SMC_P(CG_VCEPLL_FUNC_CNTL, VCEPLL_SLEEP_MASK, >> + ~VCEPLL_SLEEP_MASK); >> + WREG32_SMC_P(CG_VCEPLL_FUNC_CNTL, 0, ~VCEPLL_SLEEP_MASK); >> + >> + /* Deassert VCEPLL_RESET */ >> + WREG32_SMC_P(CG_VCEPLL_FUNC_CNTL, 0, ~VCEPLL_RESET_MASK); >> + >> + mdelay(1); >> + >> + a = si_vce_send_vcepll_ctlreq(adev); >> + if (a) >> + return a; >> + >> + /* Assert VCEPLL_RESET again */ >> + WREG32_SMC_P(CG_VCEPLL_FUNC_CNTL, VCEPLL_RESET_MASK, ~VCEPLL_RESET_MASK); >> + >> + /* Disable spread spectrum. */ >> + WREG32_SMC_P(CG_VCEPLL_SPREAD_SPECTRUM, 0, ~SSEN_MASK); >> + >> + /* Set feedback divider */ >> + WREG32_SMC_P(CG_VCEPLL_FUNC_CNTL_3, >> + VCEPLL_FB_DIV(fb_div), >> + ~VCEPLL_FB_DIV_MASK); >> + >> + /* Set ref divider to 0 */ >> + WREG32_SMC_P(CG_VCEPLL_FUNC_CNTL, 0, ~VCEPLL_REF_DIV_MASK); >> + >> + /* Set PDIV_A and PDIV_B */ >> + WREG32_SMC_P(CG_VCEPLL_FUNC_CNTL_2, >> + VCEPLL_PDIV_A(evclk_div) | VCEPLL_PDIV_B(ecclk_div), >> + ~(VCEPLL_PDIV_A_MASK | VCEPLL_PDIV_B_MASK)); >> + >> + /* Give the PLL some time to settle */ >> + mdelay(15); >> + >> + /* Deassert PLL_RESET */ >> + WREG32_SMC_P(CG_VCEPLL_FUNC_CNTL, 0, ~VCEPLL_RESET_MASK); >> + >> + mdelay(15); >> + >> + /* Switch from bypass mode to normal mode */ >> + WREG32_SMC_P(CG_VCEPLL_FUNC_CNTL, 0, ~VCEPLL_BYPASS_EN_MASK); >> + >> + a = si_vce_send_vcepll_ctlreq(adev); >> + if (a) >> + return a; >> + >> + /* Switch VCLK and DCLK selection */ >> + WREG32_SMC_P(CG_VCEPLL_FUNC_CNTL_2, >> + EVCLK_SRC_SEL(16) | ECCLK_SRC_SEL(16), >> + ~(EVCLK_SRC_SEL_MASK | ECCLK_SRC_SEL_MASK)); >> + >> + mdelay(100); >> + >> + return 0; >> +} >> + >> static const struct amdgpu_asic_funcs si_asic_funcs = >> { >> .read_disabled_bios = &si_read_disabled_bios, >> @@ -1660,7 +1784,7 @@ static const struct amdgpu_asic_funcs si_asic_funcs = >> .set_vga_state = &si_vga_set_state, >> .get_xclk = &si_get_xclk, >> .set_uvd_clocks = &si_set_uvd_clocks, >> - .set_vce_clocks = NULL, >> + .set_vce_clocks = &si_set_vce_clocks, >> .get_pcie_lanes = &si_get_pcie_lanes, >> .set_pcie_lanes = &si_set_pcie_lanes, >> .get_config_memsize = &si_get_config_memsize, >> diff --git a/drivers/gpu/drm/amd/amdgpu/sid.h b/drivers/gpu/drm/amd/amdgpu/sid.h >> index 262da0fc8b2e..a3a966a83981 100644 >> --- a/drivers/gpu/drm/amd/amdgpu/sid.h >> +++ b/drivers/gpu/drm/amd/amdgpu/sid.h >> @@ -2461,4 +2461,35 @@ >> >> #define MC_VM_FB_OFFSET 0x81a >> >> +/* Discrete VCE clocks */ >> +#define CG_VCEPLL_FUNC_CNTL 0xc0030600 >> +#define VCEPLL_RESET_MASK 0x00000001 >> +#define VCEPLL_SLEEP_MASK 0x00000002 >> +#define VCEPLL_BYPASS_EN_MASK 0x00000004 >> +#define VCEPLL_CTLREQ_MASK 0x00000008 >> +#define VCEPLL_VCO_MODE_MASK 0x00000600 >> +#define VCEPLL_REF_DIV_MASK 0x003F0000 >> +#define VCEPLL_CTLACK_MASK 0x40000000 >> +#define VCEPLL_CTLACK2_MASK 0x80000000 >> + >> +#define CG_VCEPLL_FUNC_CNTL_2 0xc0030601 >> +#define VCEPLL_PDIV_A(x) ((x) << 0) >> +#define VCEPLL_PDIV_A_MASK 0x0000007F >> +#define VCEPLL_PDIV_B(x) ((x) << 8) >> +#define VCEPLL_PDIV_B_MASK 0x00007F00 >> +#define EVCLK_SRC_SEL(x) ((x) << 20) >> +#define EVCLK_SRC_SEL_MASK 0x01F00000 >> +#define ECCLK_SRC_SEL(x) ((x) << 25) >> +#define ECCLK_SRC_SEL_MASK 0x3E000000 >> + >> +#define CG_VCEPLL_FUNC_CNTL_3 0xc0030602 >> +#define VCEPLL_FB_DIV(x) ((x) << 0) >> +#define VCEPLL_FB_DIV_MASK 0x01FFFFFF >> + >> +#define CG_VCEPLL_FUNC_CNTL_4 0xc0030603 >> + >> +#define CG_VCEPLL_FUNC_CNTL_5 0xc0030604 >> +#define CG_VCEPLL_SPREAD_SPECTRUM 0xc0030606 >> +#define VCEPLL_SSEN_MASK 0x00000001 >> + >> #endif > _______________________________________________ amd-gfx mailing list amd-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/amd-gfx