From bbeca6dfc2e17a6daa3bc05138942f4b76eff751 Mon Sep 17 00:00:00 2001 From: Damon Ding Date: Fri, 15 Mar 2024 10:13:44 +0800 Subject: [PATCH] drm/rockchip: vop: use rockchip_drm_dclk_set_rate() for some special pll In addition, fix the version check process to switch for efficiency and readability. Change-Id: I372e528f61403a72ea574de5aae28174ef3f95fa Signed-off-by: Elaine Zhang Signed-off-by: Damon Ding --- drivers/gpu/drm/rockchip/rockchip_drm_clk.c | 118 ++++++++++++++++++-- drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 3 +- drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 2 + 3 files changed, 111 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_clk.c b/drivers/gpu/drm/rockchip/rockchip_drm_clk.c index 703158028856..fafbbaa01f9a 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_clk.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_clk.c @@ -64,6 +64,33 @@ static long rockchip_rk3568_drm_dclk_round_rate(struct clk *dclk, unsigned long return round_rate; } +static long rockchip_rk3576_vopl_drm_dclk_round_rate(struct clk *dclk, unsigned long rate) +{ + struct clk_hw *hw; + struct clk_hw *p_hw; + unsigned long round_rate; + const char *name; + + hw = __clk_get_hw(dclk); + if (!hw) + return -EINVAL; + + p_hw = clk_hw_get_parent(hw); + if (!p_hw) + return -EINVAL; + + name = clk_hw_get_name(p_hw); + + if (!strcmp(name, "vpll")) + round_rate = rate; + else if (!strcmp(name, "dclk_ebc_frac_src")) + round_rate = rate; + else + round_rate = clk_round_rate(dclk, rate); + + return round_rate; +} + static long rockchip_rk3576_drm_dclk_round_rate(struct clk *dclk, unsigned long rate) { struct clk_hw *hw; @@ -218,6 +245,57 @@ static int rockchip_rk3568_drm_dclk_set_rate(struct clk *dclk, unsigned long rat return 0; } +/* + * The rk3576 ebc setting clk rule. + * The dclk_ebc can select vpll, the vpll is ebc exclusive. + * The dclk_ebc can select dclk_ebc_frac_src, use digital decimal divider, the recommended frequency is less than 60M. + * The dclk_ebc can select gpll or cpll, can only choose the nearest frequency division(gpll:1188M,cpll:1000M), + * and can't support accurate frequency setting. + * + */ +static int rockchip_rk3576_vopl_drm_dclk_set_rate(struct clk *dclk, unsigned long rate) +{ + struct clk_hw *hw; + struct clk_hw *p_hw; + unsigned long pll_rate; + const char *name; + int div = 0; + + hw = __clk_get_hw(dclk); + if (!hw) + return -EINVAL; + + p_hw = clk_hw_get_parent(hw); + if (!p_hw) + return -EINVAL; + + name = clk_hw_get_name(p_hw); + + if (!strcmp(name, "vpll")) { + pll_rate = clk_hw_get_rate(p_hw); + if (pll_rate >= VOP2_PLL_LIMIT_FREQ && pll_rate % rate == 0) { + clk_set_rate(dclk, rate); + } else { + div = DIV_ROUND_UP(VOP2_PLL_LIMIT_FREQ, rate); + if (div % 2) + div += 1; + clk_set_rate(p_hw->clk, rate * div); + clk_set_rate(dclk, rate); + } + } else if (!strcmp(name, "dclk_ebc_frac_src")) { + clk_set_rate(p_hw->clk, rate); + clk_set_rate(dclk, rate); + } else { + clk_set_rate(dclk, rate); + } + + pr_debug("%s:request rate = %ld, %s = %ld %s = %ld\n", __func__, rate, + clk_hw_get_name(hw), clk_hw_get_rate(hw), + clk_hw_get_name(p_hw), clk_hw_get_rate(p_hw)); + + return 0; +} + /* * The rk3576 has three ports, dclk_vp0\1\2. * The dclk_vp0\1\2 can select 1 port specified on clk_hdmiphy_pixelx. @@ -330,16 +408,26 @@ long rockchip_drm_dclk_round_rate(u32 version, struct clk *dclk, unsigned long r { long round_rate; - if (version == VOP_VERSION_RK3562) + switch (version) { + case VOP_VERSION_RK3562: round_rate = rockchip_rk3562_drm_dclk_round_rate(dclk, rate); - else if (version == VOP_VERSION_RK3568) + break; + case VOP_VERSION_RK3568: round_rate = rockchip_rk3568_drm_dclk_round_rate(dclk, rate); - else if (version == VOP_VERSION_RK3576) + break; + case VOP_VERSION_RK3576: round_rate = rockchip_rk3576_drm_dclk_round_rate(dclk, rate); - else if (version == VOP_VERSION_RK3588) + break; + case VOP_VERSION_RK3576_LITE: + round_rate = rockchip_rk3576_vopl_drm_dclk_round_rate(dclk, rate); + break; + case VOP_VERSION_RK3588: round_rate = rockchip_rk3588_drm_dclk_round_rate(dclk, rate); - else + break; + default: round_rate = clk_round_rate(dclk, rate); + break; + } if (round_rate < 0) pr_warn("%s:the clk_hw of dclk or parent of dclk may be NULL\n", __func__); @@ -351,16 +439,26 @@ int rockchip_drm_dclk_set_rate(u32 version, struct clk *dclk, unsigned long rate { int ret; - if (version == VOP_VERSION_RK3562) + switch (version) { + case VOP_VERSION_RK3562: ret = rockchip_rk3562_drm_dclk_set_rate(dclk, rate); - else if (version == VOP_VERSION_RK3568) + break; + case VOP_VERSION_RK3568: ret = rockchip_rk3568_drm_dclk_set_rate(dclk, rate); - else if (version == VOP_VERSION_RK3576) + break; + case VOP_VERSION_RK3576: ret = rockchip_rk3576_drm_dclk_set_rate(dclk, rate); - else if (version == VOP_VERSION_RK3588) + break; + case VOP_VERSION_RK3576_LITE: + ret = rockchip_rk3576_vopl_drm_dclk_set_rate(dclk, rate); + break; + case VOP_VERSION_RK3588: ret = rockchip_rk3588_drm_dclk_set_rate(dclk, rate); - else + break; + default: ret = clk_set_rate(dclk, rate); + break; + } if (ret < 0) pr_warn("%s:the clk_hw of dclk or parent of dclk may be NULL\n", __func__); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index 16441a33ca18..92de8fe0220a 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -3687,8 +3687,7 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc, VOP_CTRL_SET(vop, win_csc_mode_sel, 1); - clk_set_rate(vop->dclk, adjusted_mode->crtc_clock * 1000); - + rockchip_drm_dclk_set_rate(vop->version, vop->dclk, adjusted_mode->crtc_clock * 1000); vop_cfg_done(vop); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h index c120b4b9ec4a..6e18d724c06b 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h @@ -21,6 +21,8 @@ #define VOP_MAJOR(version) ((version) >> 8) #define VOP_MINOR(version) ((version) & 0xff) +#define VOP_VERSION_RK3576_LITE VOP_VERSION(0x2, 0xd) + #define VOP2_VERSION(major, minor, build) ((major) << 24 | (minor) << 16 | (build)) #define VOP2_MAJOR(version) (((version) >> 24) & 0xff) #define VOP2_MINOR(version) (((version) >> 16) & 0xff)