Loading drivers/gpu/drm/radeon/radeon.h +7 −0 Original line number Diff line number Diff line Loading @@ -2578,6 +2578,13 @@ static inline struct radeon_fence *to_radeon_fence(struct fence *f) tmp_ |= ((val) & ~(mask)); \ WREG32_PLL(reg, tmp_); \ } while (0) #define WREG32_SMC_P(reg, val, mask) \ do { \ uint32_t tmp_ = RREG32_SMC(reg); \ tmp_ &= (mask); \ tmp_ |= ((val) & ~(mask)); \ WREG32_SMC(reg, tmp_); \ } while (0) #define DREG32_SYS(sqf, rdev, reg) seq_printf((sqf), #reg " : 0x%08X\n", r100_mm_rreg((rdev), (reg), false)) #define RREG32_IO(reg) r100_io_rreg(rdev, (reg)) #define WREG32_IO(reg, v) r100_io_wreg(rdev, (reg), (v)) Loading drivers/gpu/drm/radeon/radeon_asic.c +1 −0 Original line number Diff line number Diff line Loading @@ -1973,6 +1973,7 @@ static struct radeon_asic si_asic = { .set_pcie_lanes = &r600_set_pcie_lanes, .set_clock_gating = NULL, .set_uvd_clocks = &si_set_uvd_clocks, .set_vce_clocks = &si_set_vce_clocks, .get_temperature = &si_get_temp, }, .dpm = { Loading drivers/gpu/drm/radeon/radeon_asic.h +1 −0 Original line number Diff line number Diff line Loading @@ -745,6 +745,7 @@ void si_dma_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring, u32 si_get_xclk(struct radeon_device *rdev); uint64_t si_get_gpu_clock_counter(struct radeon_device *rdev); int si_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk); int si_set_vce_clocks(struct radeon_device *rdev, u32 evclk, u32 ecclk); int si_get_temp(struct radeon_device *rdev); int si_get_allowed_info_register(struct radeon_device *rdev, u32 reg, u32 *val); Loading drivers/gpu/drm/radeon/si.c +121 −0 Original line number Diff line number Diff line Loading @@ -7675,3 +7675,124 @@ static void si_program_aspm(struct radeon_device *rdev) } } } int si_vce_send_vcepll_ctlreq(struct radeon_device *rdev) { 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 < 100; ++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 == 100) { DRM_ERROR("Timeout setting UVD clocks!\n"); return -ETIMEDOUT; } return 0; } int si_set_vce_clocks(struct radeon_device *rdev, u32 evclk, u32 ecclk) { unsigned fb_div = 0, evclk_div = 0, ecclk_div = 0; int r; /* 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; } r = radeon_uvd_calc_upll_dividers(rdev, evclk, ecclk, 125000, 250000, 16384, 0x03FFFFFF, 0, 128, 5, &fb_div, &evclk_div, &ecclk_div); if (r) return r; /* 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); r = si_vce_send_vcepll_ctlreq(rdev); if (r) return r; /* 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); r = si_vce_send_vcepll_ctlreq(rdev); if (r) return r; /* 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; } drivers/gpu/drm/radeon/sid.h +27 −0 Original line number Diff line number Diff line Loading @@ -1917,4 +1917,31 @@ #define VCE_CMD_IB_AUTO 0x00000005 #define VCE_CMD_SEMAPHORE 0x00000006 /* 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 Loading
drivers/gpu/drm/radeon/radeon.h +7 −0 Original line number Diff line number Diff line Loading @@ -2578,6 +2578,13 @@ static inline struct radeon_fence *to_radeon_fence(struct fence *f) tmp_ |= ((val) & ~(mask)); \ WREG32_PLL(reg, tmp_); \ } while (0) #define WREG32_SMC_P(reg, val, mask) \ do { \ uint32_t tmp_ = RREG32_SMC(reg); \ tmp_ &= (mask); \ tmp_ |= ((val) & ~(mask)); \ WREG32_SMC(reg, tmp_); \ } while (0) #define DREG32_SYS(sqf, rdev, reg) seq_printf((sqf), #reg " : 0x%08X\n", r100_mm_rreg((rdev), (reg), false)) #define RREG32_IO(reg) r100_io_rreg(rdev, (reg)) #define WREG32_IO(reg, v) r100_io_wreg(rdev, (reg), (v)) Loading
drivers/gpu/drm/radeon/radeon_asic.c +1 −0 Original line number Diff line number Diff line Loading @@ -1973,6 +1973,7 @@ static struct radeon_asic si_asic = { .set_pcie_lanes = &r600_set_pcie_lanes, .set_clock_gating = NULL, .set_uvd_clocks = &si_set_uvd_clocks, .set_vce_clocks = &si_set_vce_clocks, .get_temperature = &si_get_temp, }, .dpm = { Loading
drivers/gpu/drm/radeon/radeon_asic.h +1 −0 Original line number Diff line number Diff line Loading @@ -745,6 +745,7 @@ void si_dma_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring, u32 si_get_xclk(struct radeon_device *rdev); uint64_t si_get_gpu_clock_counter(struct radeon_device *rdev); int si_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk); int si_set_vce_clocks(struct radeon_device *rdev, u32 evclk, u32 ecclk); int si_get_temp(struct radeon_device *rdev); int si_get_allowed_info_register(struct radeon_device *rdev, u32 reg, u32 *val); Loading
drivers/gpu/drm/radeon/si.c +121 −0 Original line number Diff line number Diff line Loading @@ -7675,3 +7675,124 @@ static void si_program_aspm(struct radeon_device *rdev) } } } int si_vce_send_vcepll_ctlreq(struct radeon_device *rdev) { 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 < 100; ++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 == 100) { DRM_ERROR("Timeout setting UVD clocks!\n"); return -ETIMEDOUT; } return 0; } int si_set_vce_clocks(struct radeon_device *rdev, u32 evclk, u32 ecclk) { unsigned fb_div = 0, evclk_div = 0, ecclk_div = 0; int r; /* 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; } r = radeon_uvd_calc_upll_dividers(rdev, evclk, ecclk, 125000, 250000, 16384, 0x03FFFFFF, 0, 128, 5, &fb_div, &evclk_div, &ecclk_div); if (r) return r; /* 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); r = si_vce_send_vcepll_ctlreq(rdev); if (r) return r; /* 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); r = si_vce_send_vcepll_ctlreq(rdev); if (r) return r; /* 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; }
drivers/gpu/drm/radeon/sid.h +27 −0 Original line number Diff line number Diff line Loading @@ -1917,4 +1917,31 @@ #define VCE_CMD_IB_AUTO 0x00000005 #define VCE_CMD_SEMAPHORE 0x00000006 /* 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