From e7bf974d33feb259b44c0c2f3856aab458c7575d Mon Sep 17 00:00:00 2001 From: Finley Xiao Date: Wed, 21 Aug 2024 10:48:25 +0800 Subject: [PATCH 1/4] clk: rockchip: rk3506: Remove frac parent clk for dclk vop Change-Id: I0c6d95eb180393f90e769f43f7b6dd08a49cc308 Signed-off-by: Finley Xiao --- drivers/clk/rockchip/clk-rk3506.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/rockchip/clk-rk3506.c b/drivers/clk/rockchip/clk-rk3506.c index 6f04d42c3138..bcfc64d76e5e 100644 --- a/drivers/clk/rockchip/clk-rk3506.c +++ b/drivers/clk/rockchip/clk-rk3506.c @@ -136,8 +136,8 @@ PNAME(mclk_sai_asrc_parents_p) = { "xin24m_gate", "clk_int_voice_matrix0", "cl PNAME(lrck_asrc_parents_p) = { "mclk_asrc0", "mclk_asrc1", "mclk_asrc2", "mclk_asrc3", "mclk_spdiftx", "clk_spdifrx_to_asrc", "clkout_pdm", "sai0_fs", "sai1_fs", "sai2_fs", "sai3_fs", "sai4_fs" }; PNAME(cclk_src_sdmmc_parents_p) = { "xin24m_gate", "gpll", "clk_v0pll_gate", "clk_v1pll_gate" }; -PNAME(dclk_vop_parents_p) = { "xin24m_gate", "clk_gpll_gate", "clk_v0pll_gate", "clk_v1pll_gate", "clk_frac_voice_matrix1", - "clk_frac_common_matrix0", "clk_frac_common_matrix1", "clk_frac_common_matrix2" }; +PNAME(dclk_vop_parents_p) = { "xin24m_gate", "clk_gpll_gate", "clk_v0pll_gate", "clk_v1pll_gate", "dummy_vop_dclk", + "dummy_vop_dclk", "dummy_vop_dclk", "dummy_vop_dclk" }; PNAME(dbclk_gpio0_parents_p) = { "xin24m", "clk_rc", "clk_32k_pmu" }; PNAME(clk_pmu_hp_timer_parents_p) = { "xin24m", "gpll_div_100m", "clk_core_pvtpll" }; PNAME(clk_ref_out_parents_p) = { "xin24m", "gpll", "v0pll", "v1pll" }; From c60bd1fdeafd24b7e21d20ccf980af76eb57643d Mon Sep 17 00:00:00 2001 From: Damon Ding Date: Sun, 9 Oct 2022 09:09:35 +0800 Subject: [PATCH 2/4] drm/rockchip: tve: add clk error check for rk3528 Signed-off-by: Damon Ding Change-Id: I00f83467aa82da3a023c7e2e7cd40d44b7a70b3a --- drivers/gpu/drm/rockchip/rockchip_drm_tve.c | 33 +++++++++++++++------ 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_tve.c b/drivers/gpu/drm/rockchip/rockchip_drm_tve.c index a8b5f0c4cbc1..69a0be7c5da3 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_tve.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_tve.c @@ -910,38 +910,41 @@ static int rockchip_tve_bind(struct device *dev, struct device *master, tve->pclk_vdac = devm_clk_get(tve->dev, "pclk_vdac"); if (IS_ERR(tve->pclk_vdac)) { dev_err(tve->dev, "Unable to get vdac pclk\n"); - return PTR_ERR(tve->pclk_vdac); + ret = PTR_ERR(tve->pclk_vdac); + goto err_disable_aclk; } ret = clk_prepare_enable(tve->pclk_vdac); if (ret) { dev_err(tve->dev, "Cannot enable vdac pclk: %d\n", ret); - return ret; + goto err_disable_aclk; } tve->dclk = devm_clk_get(tve->dev, "dclk"); if (IS_ERR(tve->dclk)) { dev_err(tve->dev, "Unable to get tve dclk\n"); - return PTR_ERR(tve->dclk); + ret = PTR_ERR(tve->dclk); + goto err_disable_pclk; } ret = clk_prepare_enable(tve->dclk); if (ret) { dev_err(tve->dev, "Cannot enable tve dclk: %d\n", ret); - return ret; + goto err_disable_pclk; } if (tve->upsample_mode == DCLK_UPSAMPLEx4) { tve->dclk_4x = devm_clk_get(tve->dev, "dclk_4x"); if (IS_ERR(tve->dclk_4x)) { dev_err(tve->dev, "Unable to get tve dclk_4x\n"); - return PTR_ERR(tve->dclk_4x); + ret = PTR_ERR(tve->dclk_4x); + goto err_disable_dclk; } ret = clk_prepare_enable(tve->dclk_4x); if (ret) { dev_err(tve->dev, "Cannot enable tve dclk_4x: %d\n", ret); - return ret; + goto err_disable_dclk; } } } @@ -960,7 +963,7 @@ static int rockchip_tve_bind(struct device *dev, struct device *master, DRM_MODE_ENCODER_TVDAC, NULL); if (ret < 0) { dev_err(tve->dev, "failed to initialize encoder with drm\n"); - goto err_disable_aclk; + goto err_disable_dclk_4x; } drm_encoder_helper_add(encoder, &rockchip_tve_encoder_helper_funcs); @@ -997,9 +1000,15 @@ err_free_connector: drm_connector_cleanup(connector); err_free_encoder: drm_encoder_cleanup(encoder); +err_disable_dclk_4x: + clk_disable_unprepare(tve->dclk_4x); +err_disable_dclk: + clk_disable_unprepare(tve->dclk); +err_disable_pclk: + clk_disable_unprepare(tve->pclk_vdac); err_disable_aclk: - if (tve->soc_type == SOC_RK3036) - clk_disable_unprepare(tve->aclk); + clk_disable_unprepare(tve->aclk); + clk_disable_unprepare(tve->hclk); return ret; } @@ -1015,6 +1024,12 @@ static void rockchip_tve_unbind(struct device *dev, struct device *master, drm_connector_cleanup(&tve->connector); drm_encoder_cleanup(&tve->encoder); + clk_disable_unprepare(tve->dclk_4x); + clk_disable_unprepare(tve->dclk); + clk_disable_unprepare(tve->pclk_vdac); + clk_disable_unprepare(tve->aclk); + clk_disable_unprepare(tve->hclk); + pm_runtime_disable(dev); dev_set_drvdata(dev, NULL); } From 1dcd984537f21c00001e62e1049978f21bdb1f3a Mon Sep 17 00:00:00 2001 From: Damon Ding Date: Mon, 19 Aug 2024 15:48:38 +0800 Subject: [PATCH 3/4] drm/rockchip: tve: add support to enable/disable tve/vdac clks dynamically for rk3528 It doesn't make sense to always enable tve/vdac clks in probing. The clks dynamic switching can also help to reduce the power consumption. Change-Id: Id93b5552d6e984d7a6306508f5ee74b383a0d3c5 Signed-off-by: Damon Ding --- drivers/gpu/drm/rockchip/rockchip_drm_tve.c | 107 ++++++++++---------- 1 file changed, 55 insertions(+), 52 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_tve.c b/drivers/gpu/drm/rockchip/rockchip_drm_tve.c index 69a0be7c5da3..05880ef46f9d 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_tve.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_tve.c @@ -368,6 +368,13 @@ static int cvbs_set_disable(struct rockchip_tve *tve) return ret; } dac_enable(tve, false); + + clk_disable_unprepare(tve->dclk_4x); + clk_disable_unprepare(tve->dclk); + clk_disable_unprepare(tve->pclk_vdac); + clk_disable_unprepare(tve->hclk); + clk_disable_unprepare(tve->aclk); + tve->enable = 0; return 0; @@ -398,12 +405,56 @@ static int cvbs_set_enable(struct rockchip_tve *tve) dev_err(tve->dev, "failed to get pm runtime: %d\n", ret); return ret; } + + ret = clk_prepare_enable(tve->aclk); + if (ret) { + dev_err(tve->dev, "Cannot enable tve aclk: %d\n", ret); + goto err_pm_put; + } + + ret = clk_prepare_enable(tve->hclk); + if (ret) { + dev_err(tve->dev, "Cannot enable tve hclk: %d\n", ret); + goto err_disable_aclk; + } + + ret = clk_prepare_enable(tve->pclk_vdac); + if (ret) { + dev_err(tve->dev, "Cannot enable vdac pclk: %d\n", ret); + goto err_disable_hclk; + } + + ret = clk_prepare_enable(tve->dclk); + if (ret) { + dev_err(tve->dev, "Cannot enable tve dclk: %d\n", ret); + goto err_disable_pclk; + } + + ret = clk_prepare_enable(tve->dclk_4x); + if (ret) { + dev_err(tve->dev, "Cannot enable tve dclk_4x: %d\n", ret); + goto err_disable_dclk; + } + tve_set_mode(tve); msleep(1000); dac_enable(tve, true); tve->enable = 1; return 0; + +err_disable_dclk: + clk_disable_unprepare(tve->dclk); +err_disable_pclk: + clk_disable_unprepare(tve->pclk_vdac); +err_disable_hclk: + clk_disable_unprepare(tve->hclk); +err_disable_aclk: + clk_disable_unprepare(tve->aclk); +err_pm_put: + pm_runtime_put_sync(tve->dev); + + return ret; } static void rockchip_tve_encoder_enable(struct drm_encoder *encoder) @@ -888,12 +939,6 @@ static int rockchip_tve_bind(struct device *dev, struct device *master, dev_err(tve->dev, "Unable to get tve aclk\n"); return PTR_ERR(tve->aclk); } - - ret = clk_prepare_enable(tve->aclk); - if (ret) { - dev_err(tve->dev, "Cannot enable tve aclk: %d\n", ret); - return ret; - } } else if (tve->soc_type == SOC_RK3528) { tve->hclk = devm_clk_get(tve->dev, "hclk"); if (IS_ERR(tve->hclk)) { @@ -901,50 +946,23 @@ static int rockchip_tve_bind(struct device *dev, struct device *master, return PTR_ERR(tve->hclk); } - ret = clk_prepare_enable(tve->hclk); - if (ret) { - dev_err(tve->dev, "Cannot enable tve hclk: %d\n", ret); - return ret; - } - tve->pclk_vdac = devm_clk_get(tve->dev, "pclk_vdac"); if (IS_ERR(tve->pclk_vdac)) { dev_err(tve->dev, "Unable to get vdac pclk\n"); - ret = PTR_ERR(tve->pclk_vdac); - goto err_disable_aclk; - } - - ret = clk_prepare_enable(tve->pclk_vdac); - if (ret) { - dev_err(tve->dev, "Cannot enable vdac pclk: %d\n", ret); - goto err_disable_aclk; + return PTR_ERR(tve->pclk_vdac); } tve->dclk = devm_clk_get(tve->dev, "dclk"); if (IS_ERR(tve->dclk)) { dev_err(tve->dev, "Unable to get tve dclk\n"); - ret = PTR_ERR(tve->dclk); - goto err_disable_pclk; - } - - ret = clk_prepare_enable(tve->dclk); - if (ret) { - dev_err(tve->dev, "Cannot enable tve dclk: %d\n", ret); - goto err_disable_pclk; + return PTR_ERR(tve->dclk); } if (tve->upsample_mode == DCLK_UPSAMPLEx4) { tve->dclk_4x = devm_clk_get(tve->dev, "dclk_4x"); if (IS_ERR(tve->dclk_4x)) { dev_err(tve->dev, "Unable to get tve dclk_4x\n"); - ret = PTR_ERR(tve->dclk_4x); - goto err_disable_dclk; - } - - ret = clk_prepare_enable(tve->dclk_4x); - if (ret) { - dev_err(tve->dev, "Cannot enable tve dclk_4x: %d\n", ret); - goto err_disable_dclk; + return PTR_ERR(tve->dclk_4x); } } } @@ -963,7 +981,7 @@ static int rockchip_tve_bind(struct device *dev, struct device *master, DRM_MODE_ENCODER_TVDAC, NULL); if (ret < 0) { dev_err(tve->dev, "failed to initialize encoder with drm\n"); - goto err_disable_dclk_4x; + return ret; } drm_encoder_helper_add(encoder, &rockchip_tve_encoder_helper_funcs); @@ -1000,15 +1018,6 @@ err_free_connector: drm_connector_cleanup(connector); err_free_encoder: drm_encoder_cleanup(encoder); -err_disable_dclk_4x: - clk_disable_unprepare(tve->dclk_4x); -err_disable_dclk: - clk_disable_unprepare(tve->dclk); -err_disable_pclk: - clk_disable_unprepare(tve->pclk_vdac); -err_disable_aclk: - clk_disable_unprepare(tve->aclk); - clk_disable_unprepare(tve->hclk); return ret; } @@ -1024,12 +1033,6 @@ static void rockchip_tve_unbind(struct device *dev, struct device *master, drm_connector_cleanup(&tve->connector); drm_encoder_cleanup(&tve->encoder); - clk_disable_unprepare(tve->dclk_4x); - clk_disable_unprepare(tve->dclk); - clk_disable_unprepare(tve->pclk_vdac); - clk_disable_unprepare(tve->aclk); - clk_disable_unprepare(tve->hclk); - pm_runtime_disable(dev); dev_set_drvdata(dev, NULL); } From e3b31a037dcdef9cd3a101d40ca505e40221cbb6 Mon Sep 17 00:00:00 2001 From: Damon Ding Date: Fri, 26 Jul 2024 17:00:05 +0800 Subject: [PATCH 4/4] drm/rockchip: tve: add .loader_protect() support for tve If logo display enabled, the rockchip_tve_encoder_loader_protect() helps to set the tve enable/disable status and call pm_runtime_get_sync()/pm_runtime_put(), which allows for the continuation of the display state from the U-Boot stage. In addition, fix the check of tve mode setting in .mode_set() to avoid display flashing, which caused by the off/on switch of dac. Change-Id: I6f1fcaf05cb6e362ce375e447c566fb5356c5380 Signed-off-by: Damon Ding --- drivers/gpu/drm/rockchip/rockchip_drm_tve.c | 84 ++++++++++++++++++++- 1 file changed, 81 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_tve.c b/drivers/gpu/drm/rockchip/rockchip_drm_tve.c index 05880ef46f9d..9184509fc2ba 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_tve.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_tve.c @@ -486,15 +486,17 @@ static void rockchip_tve_encoder_mode_set(struct drm_encoder *encoder, struct drm_display_mode *adjusted_mode) { struct rockchip_tve *tve = encoder_to_tve(encoder); + u32 tv_format; dev_dbg(tve->dev, "encoder mode set:%s\n", adjusted_mode->name); if (adjusted_mode->vdisplay == 576) - tve->tv_format = TVOUT_CVBS_PAL; + tv_format = TVOUT_CVBS_PAL; else - tve->tv_format = TVOUT_CVBS_NTSC; + tv_format = TVOUT_CVBS_NTSC; - if (tve->enable) { + if (tve->enable && tve->tv_format != tv_format) { + tve->tv_format = tv_format; dac_enable(tve, false); msleep(200); @@ -541,6 +543,81 @@ rockchip_tve_encoder_atomic_check(struct drm_encoder *encoder, return 0; } +static int rockchip_tve_encoder_loader_protect(struct drm_encoder *encoder, bool on) +{ + struct rockchip_tve *tve = encoder_to_tve(encoder); + int ret; + + if (on) { + ret = pm_runtime_get_sync(tve->dev); + if (ret < 0) { + dev_err(tve->dev, "failed to get pm runtime: %d\n", ret); + return ret; + } + + ret = clk_prepare_enable(tve->aclk); + if (ret) { + dev_err(tve->dev, "Cannot enable tve aclk: %d\n", ret); + goto err_pm_put; + } + + ret = clk_prepare_enable(tve->hclk); + if (ret) { + dev_err(tve->dev, "Cannot enable tve hclk: %d\n", ret); + goto err_disable_aclk; + } + + ret = clk_prepare_enable(tve->pclk_vdac); + if (ret) { + dev_err(tve->dev, "Cannot enable vdac pclk: %d\n", ret); + goto err_disable_hclk; + } + + ret = clk_prepare_enable(tve->dclk); + if (ret) { + dev_err(tve->dev, "Cannot enable tve dclk: %d\n", ret); + goto err_disable_pclk; + } + + ret = clk_prepare_enable(tve->dclk_4x); + if (ret) { + dev_err(tve->dev, "Cannot enable tve dclk_4x: %d\n", ret); + goto err_disable_dclk; + } + + tve->enable = 1; + } else { + ret = pm_runtime_put(tve->dev); + if (ret < 0) { + dev_err(tve->dev, "failed to put pm runtime: %d\n", ret); + return ret; + } + + clk_disable_unprepare(tve->dclk_4x); + clk_disable_unprepare(tve->dclk); + clk_disable_unprepare(tve->pclk_vdac); + clk_disable_unprepare(tve->hclk); + clk_disable_unprepare(tve->aclk); + + tve->enable = 0; + } + + return 0; + +err_disable_dclk: + clk_disable_unprepare(tve->dclk); +err_disable_pclk: + clk_disable_unprepare(tve->pclk_vdac); +err_disable_hclk: + clk_disable_unprepare(tve->hclk); +err_disable_aclk: + clk_disable_unprepare(tve->aclk); +err_pm_put: + pm_runtime_put_sync(tve->dev); + + return ret; +} + static const struct drm_connector_helper_funcs rockchip_tve_connector_helper_funcs = { .mode_valid = rockchip_tve_mode_valid, @@ -1006,6 +1083,7 @@ static int rockchip_tve_bind(struct device *dev, struct device *master, } tve->sub_dev.connector = &tve->connector; tve->sub_dev.of_node = tve->dev->of_node; + tve->sub_dev.loader_protect = rockchip_tve_encoder_loader_protect; rockchip_drm_register_sub_dev(&tve->sub_dev); pm_runtime_enable(dev);