Skip to content

Commit c4b09c5

Browse files
cristiccvinodkoul
authored andcommitted
phy: phy-rockchip-samsung-hdptx: Add clock provider support
The HDMI PHY PLL can be used as an alternative dclk source to RK3588 SoC CRU. It provides more accurate clock rates required by VOP2 to improve existing support for display modes handling, which is known to be problematic when dealing with non-integer refresh rates, among others. It is worth noting this only works for HDMI 2.0 or below, e.g. cannot be used to support HDMI 2.1 4K@120Hz mode. Signed-off-by: Cristian Ciocaltea <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Vinod Koul <[email protected]>
1 parent a652f22 commit c4b09c5

File tree

1 file changed

+173
-22
lines changed

1 file changed

+173
-22
lines changed

drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c

Lines changed: 173 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
*/
99
#include <linux/bitfield.h>
1010
#include <linux/clk.h>
11+
#include <linux/clk-provider.h>
1112
#include <linux/delay.h>
1213
#include <linux/mfd/syscon.h>
1314
#include <linux/module.h>
@@ -191,6 +192,8 @@
191192
#define LN3_TX_SER_RATE_SEL_HBR2 BIT(3)
192193
#define LN3_TX_SER_RATE_SEL_HBR3 BIT(2)
193194

195+
#define HDMI20_MAX_RATE 600000000
196+
194197
struct lcpll_config {
195198
u32 bit_rate;
196199
u8 lcvco_mode_en;
@@ -273,6 +276,12 @@ struct rk_hdptx_phy {
273276
struct clk_bulk_data *clks;
274277
int nr_clks;
275278
struct reset_control_bulk_data rsts[RST_MAX];
279+
280+
/* clk provider */
281+
struct clk_hw hw;
282+
unsigned long rate;
283+
284+
atomic_t usage_count;
276285
};
277286

278287
static const struct ropll_config ropll_tmds_cfg[] = {
@@ -760,6 +769,8 @@ static int rk_hdptx_ropll_tmds_cmn_config(struct rk_hdptx_phy *hdptx,
760769
struct ropll_config rc = {0};
761770
int i;
762771

772+
hdptx->rate = rate * 100;
773+
763774
for (i = 0; i < ARRAY_SIZE(ropll_tmds_cfg); i++)
764775
if (rate == ropll_tmds_cfg[i].bit_rate) {
765776
cfg = &ropll_tmds_cfg[i];
@@ -823,19 +834,6 @@ static int rk_hdptx_ropll_tmds_cmn_config(struct rk_hdptx_phy *hdptx,
823834
static int rk_hdptx_ropll_tmds_mode_config(struct rk_hdptx_phy *hdptx,
824835
unsigned int rate)
825836
{
826-
u32 val;
827-
int ret;
828-
829-
ret = regmap_read(hdptx->grf, GRF_HDPTX_STATUS, &val);
830-
if (ret)
831-
return ret;
832-
833-
if (!(val & HDPTX_O_PLL_LOCK_DONE)) {
834-
ret = rk_hdptx_ropll_tmds_cmn_config(hdptx, rate);
835-
if (ret)
836-
return ret;
837-
}
838-
839837
rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_common_sb_init_seq);
840838

841839
regmap_write(hdptx->regmap, LNTOP_REG(0200), 0x06);
@@ -857,10 +855,68 @@ static int rk_hdptx_ropll_tmds_mode_config(struct rk_hdptx_phy *hdptx,
857855
return rk_hdptx_post_enable_lane(hdptx);
858856
}
859857

858+
static int rk_hdptx_phy_consumer_get(struct rk_hdptx_phy *hdptx,
859+
unsigned int rate)
860+
{
861+
u32 status;
862+
int ret;
863+
864+
if (atomic_inc_return(&hdptx->usage_count) > 1)
865+
return 0;
866+
867+
ret = regmap_read(hdptx->grf, GRF_HDPTX_STATUS, &status);
868+
if (ret)
869+
goto dec_usage;
870+
871+
if (status & HDPTX_O_PLL_LOCK_DONE)
872+
dev_warn(hdptx->dev, "PLL locked by unknown consumer!\n");
873+
874+
if (rate) {
875+
ret = rk_hdptx_ropll_tmds_cmn_config(hdptx, rate);
876+
if (ret)
877+
goto dec_usage;
878+
}
879+
880+
return 0;
881+
882+
dec_usage:
883+
atomic_dec(&hdptx->usage_count);
884+
return ret;
885+
}
886+
887+
static int rk_hdptx_phy_consumer_put(struct rk_hdptx_phy *hdptx, bool force)
888+
{
889+
u32 status;
890+
int ret;
891+
892+
ret = atomic_dec_return(&hdptx->usage_count);
893+
if (ret > 0)
894+
return 0;
895+
896+
if (ret < 0) {
897+
dev_warn(hdptx->dev, "Usage count underflow!\n");
898+
ret = -EINVAL;
899+
} else {
900+
ret = regmap_read(hdptx->grf, GRF_HDPTX_STATUS, &status);
901+
if (!ret) {
902+
if (status & HDPTX_O_PLL_LOCK_DONE)
903+
rk_hdptx_phy_disable(hdptx);
904+
return 0;
905+
} else if (force) {
906+
return 0;
907+
}
908+
}
909+
910+
atomic_inc(&hdptx->usage_count);
911+
return ret;
912+
}
913+
860914
static int rk_hdptx_phy_power_on(struct phy *phy)
861915
{
862916
struct rk_hdptx_phy *hdptx = phy_get_drvdata(phy);
863917
int bus_width = phy_get_bus_width(hdptx->phy);
918+
int ret;
919+
864920
/*
865921
* FIXME: Temporary workaround to pass pixel_clk_rate
866922
* from the HDMI bridge driver until phy_configure_opts_hdmi
@@ -871,20 +927,22 @@ static int rk_hdptx_phy_power_on(struct phy *phy)
871927
dev_dbg(hdptx->dev, "%s bus_width=%x rate=%u\n",
872928
__func__, bus_width, rate);
873929

874-
return rk_hdptx_ropll_tmds_mode_config(hdptx, rate);
930+
ret = rk_hdptx_phy_consumer_get(hdptx, rate);
931+
if (ret)
932+
return ret;
933+
934+
ret = rk_hdptx_ropll_tmds_mode_config(hdptx, rate);
935+
if (ret)
936+
rk_hdptx_phy_consumer_put(hdptx, true);
937+
938+
return ret;
875939
}
876940

877941
static int rk_hdptx_phy_power_off(struct phy *phy)
878942
{
879943
struct rk_hdptx_phy *hdptx = phy_get_drvdata(phy);
880-
u32 val;
881-
int ret;
882944

883-
ret = regmap_read(hdptx->grf, GRF_HDPTX_STATUS, &val);
884-
if (ret == 0 && (val & HDPTX_O_PLL_LOCK_DONE))
885-
rk_hdptx_phy_disable(hdptx);
886-
887-
return ret;
945+
return rk_hdptx_phy_consumer_put(hdptx, false);
888946
}
889947

890948
static const struct phy_ops rk_hdptx_phy_ops = {
@@ -893,6 +951,99 @@ static const struct phy_ops rk_hdptx_phy_ops = {
893951
.owner = THIS_MODULE,
894952
};
895953

954+
static struct rk_hdptx_phy *to_rk_hdptx_phy(struct clk_hw *hw)
955+
{
956+
return container_of(hw, struct rk_hdptx_phy, hw);
957+
}
958+
959+
static int rk_hdptx_phy_clk_prepare(struct clk_hw *hw)
960+
{
961+
struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw);
962+
963+
return rk_hdptx_phy_consumer_get(hdptx, hdptx->rate / 100);
964+
}
965+
966+
static void rk_hdptx_phy_clk_unprepare(struct clk_hw *hw)
967+
{
968+
struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw);
969+
970+
rk_hdptx_phy_consumer_put(hdptx, true);
971+
}
972+
973+
static unsigned long rk_hdptx_phy_clk_recalc_rate(struct clk_hw *hw,
974+
unsigned long parent_rate)
975+
{
976+
struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw);
977+
978+
return hdptx->rate;
979+
}
980+
981+
static long rk_hdptx_phy_clk_round_rate(struct clk_hw *hw, unsigned long rate,
982+
unsigned long *parent_rate)
983+
{
984+
u32 bit_rate = rate / 100;
985+
int i;
986+
987+
if (rate > HDMI20_MAX_RATE)
988+
return rate;
989+
990+
for (i = 0; i < ARRAY_SIZE(ropll_tmds_cfg); i++)
991+
if (bit_rate == ropll_tmds_cfg[i].bit_rate)
992+
break;
993+
994+
if (i == ARRAY_SIZE(ropll_tmds_cfg) &&
995+
!rk_hdptx_phy_clk_pll_calc(bit_rate, NULL))
996+
return -EINVAL;
997+
998+
return rate;
999+
}
1000+
1001+
static int rk_hdptx_phy_clk_set_rate(struct clk_hw *hw, unsigned long rate,
1002+
unsigned long parent_rate)
1003+
{
1004+
struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw);
1005+
1006+
return rk_hdptx_ropll_tmds_cmn_config(hdptx, rate / 100);
1007+
}
1008+
1009+
static const struct clk_ops hdptx_phy_clk_ops = {
1010+
.prepare = rk_hdptx_phy_clk_prepare,
1011+
.unprepare = rk_hdptx_phy_clk_unprepare,
1012+
.recalc_rate = rk_hdptx_phy_clk_recalc_rate,
1013+
.round_rate = rk_hdptx_phy_clk_round_rate,
1014+
.set_rate = rk_hdptx_phy_clk_set_rate,
1015+
};
1016+
1017+
static int rk_hdptx_phy_clk_register(struct rk_hdptx_phy *hdptx)
1018+
{
1019+
struct device *dev = hdptx->dev;
1020+
const char *name, *pname;
1021+
struct clk *refclk;
1022+
int ret, id;
1023+
1024+
refclk = devm_clk_get(dev, "ref");
1025+
if (IS_ERR(refclk))
1026+
return dev_err_probe(dev, PTR_ERR(refclk),
1027+
"Failed to get ref clock\n");
1028+
1029+
id = of_alias_get_id(dev->of_node, "hdptxphy");
1030+
name = id > 0 ? "clk_hdmiphy_pixel1" : "clk_hdmiphy_pixel0";
1031+
pname = __clk_get_name(refclk);
1032+
1033+
hdptx->hw.init = CLK_HW_INIT(name, pname, &hdptx_phy_clk_ops,
1034+
CLK_GET_RATE_NOCACHE);
1035+
1036+
ret = devm_clk_hw_register(dev, &hdptx->hw);
1037+
if (ret)
1038+
return dev_err_probe(dev, ret, "Failed to register clock\n");
1039+
1040+
ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, &hdptx->hw);
1041+
if (ret)
1042+
return dev_err_probe(dev, ret,
1043+
"Failed to register clk provider\n");
1044+
return 0;
1045+
}
1046+
8961047
static int rk_hdptx_phy_runtime_suspend(struct device *dev)
8971048
{
8981049
struct rk_hdptx_phy *hdptx = dev_get_drvdata(dev);
@@ -987,7 +1138,7 @@ static int rk_hdptx_phy_probe(struct platform_device *pdev)
9871138
reset_control_deassert(hdptx->rsts[RST_CMN].rstc);
9881139
reset_control_deassert(hdptx->rsts[RST_INIT].rstc);
9891140

990-
return 0;
1141+
return rk_hdptx_phy_clk_register(hdptx);
9911142
}
9921143

9931144
static const struct dev_pm_ops rk_hdptx_phy_pm_ops = {

0 commit comments

Comments
 (0)