Lines Matching +full:rk3588 +full:- +full:hdptx +full:- +full:phy
1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (c) 2021-2022 Rockchip Electronics Co., Ltd.
6 * Author: Algea Cao <algea.cao@rock-chips.com>
11 #include <linux/clk-provider.h>
17 #include <linux/phy/phy.h>
274 struct phy *phy; member
589 #define rk_hdptx_multi_reg_write(hdptx, seq) \ argument
590 regmap_multi_reg_write((hdptx)->regmap, seq, ARRAY_SIZE(seq))
592 static void rk_hdptx_pre_power_up(struct rk_hdptx_phy *hdptx) in rk_hdptx_pre_power_up() argument
596 reset_control_assert(hdptx->rsts[RST_APB].rstc); in rk_hdptx_pre_power_up()
598 reset_control_deassert(hdptx->rsts[RST_APB].rstc); in rk_hdptx_pre_power_up()
600 reset_control_assert(hdptx->rsts[RST_LANE].rstc); in rk_hdptx_pre_power_up()
601 reset_control_assert(hdptx->rsts[RST_CMN].rstc); in rk_hdptx_pre_power_up()
602 reset_control_assert(hdptx->rsts[RST_INIT].rstc); in rk_hdptx_pre_power_up()
605 regmap_write(hdptx->grf, GRF_HDPTX_CON0, val); in rk_hdptx_pre_power_up()
608 static int rk_hdptx_post_enable_lane(struct rk_hdptx_phy *hdptx) in rk_hdptx_post_enable_lane() argument
613 reset_control_deassert(hdptx->rsts[RST_LANE].rstc); in rk_hdptx_post_enable_lane()
617 regmap_write(hdptx->grf, GRF_HDPTX_CON0, val); in rk_hdptx_post_enable_lane()
619 ret = regmap_read_poll_timeout(hdptx->grf, GRF_HDPTX_STATUS, val, in rk_hdptx_post_enable_lane()
624 dev_err(hdptx->dev, "Failed to get PHY lane lock: %d\n", ret); in rk_hdptx_post_enable_lane()
628 dev_dbg(hdptx->dev, "PHY lane locked\n"); in rk_hdptx_post_enable_lane()
633 static int rk_hdptx_post_enable_pll(struct rk_hdptx_phy *hdptx) in rk_hdptx_post_enable_pll() argument
640 regmap_write(hdptx->grf, GRF_HDPTX_CON0, val); in rk_hdptx_post_enable_pll()
643 reset_control_deassert(hdptx->rsts[RST_INIT].rstc); in rk_hdptx_post_enable_pll()
647 regmap_write(hdptx->grf, GRF_HDPTX_CON0, val); in rk_hdptx_post_enable_pll()
650 reset_control_deassert(hdptx->rsts[RST_CMN].rstc); in rk_hdptx_post_enable_pll()
652 ret = regmap_read_poll_timeout(hdptx->grf, GRF_HDPTX_STATUS, val, in rk_hdptx_post_enable_pll()
655 dev_err(hdptx->dev, "Failed to get PHY clk ready: %d\n", ret); in rk_hdptx_post_enable_pll()
659 dev_dbg(hdptx->dev, "PHY clk ready\n"); in rk_hdptx_post_enable_pll()
664 static void rk_hdptx_phy_disable(struct rk_hdptx_phy *hdptx) in rk_hdptx_phy_disable() argument
668 /* reset phy and apb, or phy locked flag may keep 1 */ in rk_hdptx_phy_disable()
669 reset_control_assert(hdptx->rsts[RST_PHY].rstc); in rk_hdptx_phy_disable()
671 reset_control_deassert(hdptx->rsts[RST_PHY].rstc); in rk_hdptx_phy_disable()
673 reset_control_assert(hdptx->rsts[RST_APB].rstc); in rk_hdptx_phy_disable()
675 reset_control_deassert(hdptx->rsts[RST_APB].rstc); in rk_hdptx_phy_disable()
677 regmap_write(hdptx->regmap, LANE_REG(0300), 0x82); in rk_hdptx_phy_disable()
678 regmap_write(hdptx->regmap, SB_REG(010f), 0xc1); in rk_hdptx_phy_disable()
679 regmap_write(hdptx->regmap, SB_REG(0110), 0x1); in rk_hdptx_phy_disable()
680 regmap_write(hdptx->regmap, LANE_REG(0301), 0x80); in rk_hdptx_phy_disable()
681 regmap_write(hdptx->regmap, LANE_REG(0401), 0x80); in rk_hdptx_phy_disable()
682 regmap_write(hdptx->regmap, LANE_REG(0501), 0x80); in rk_hdptx_phy_disable()
683 regmap_write(hdptx->regmap, LANE_REG(0601), 0x80); in rk_hdptx_phy_disable()
685 reset_control_assert(hdptx->rsts[RST_LANE].rstc); in rk_hdptx_phy_disable()
686 reset_control_assert(hdptx->rsts[RST_CMN].rstc); in rk_hdptx_phy_disable()
687 reset_control_assert(hdptx->rsts[RST_INIT].rstc); in rk_hdptx_phy_disable()
690 regmap_write(hdptx->grf, GRF_HDPTX_CON0, val); in rk_hdptx_phy_disable()
704 for (sdiv = 16; sdiv >= 1; sdiv--) { in rk_hdptx_phy_clk_pll_calc()
717 if (fref * mdiv - fvco) { in rk_hdptx_phy_clk_pll_calc()
725 rational_best_approximation(fref * mdiv - fvco, in rk_hdptx_phy_clk_pll_calc()
731 rational_best_approximation(sdc * n - fref * mdiv, in rk_hdptx_phy_clk_pll_calc()
745 cfg->pms_mdiv = mdiv; in rk_hdptx_phy_clk_pll_calc()
746 cfg->pms_mdiv_afc = mdiv; in rk_hdptx_phy_clk_pll_calc()
747 cfg->pms_pdiv = 1; in rk_hdptx_phy_clk_pll_calc()
748 cfg->pms_refdiv = 1; in rk_hdptx_phy_clk_pll_calc()
749 cfg->pms_sdiv = sdiv - 1; in rk_hdptx_phy_clk_pll_calc()
751 cfg->sdm_en = k > 0 ? 1 : 0; in rk_hdptx_phy_clk_pll_calc()
752 if (cfg->sdm_en) { in rk_hdptx_phy_clk_pll_calc()
753 cfg->sdm_deno = lc; in rk_hdptx_phy_clk_pll_calc()
754 cfg->sdm_num_sign = 1; in rk_hdptx_phy_clk_pll_calc()
755 cfg->sdm_num = k; in rk_hdptx_phy_clk_pll_calc()
756 cfg->sdc_n = n - 3; in rk_hdptx_phy_clk_pll_calc()
757 cfg->sdc_num = k_sub; in rk_hdptx_phy_clk_pll_calc()
758 cfg->sdc_deno = lc_sub; in rk_hdptx_phy_clk_pll_calc()
765 static int rk_hdptx_ropll_tmds_cmn_config(struct rk_hdptx_phy *hdptx, in rk_hdptx_ropll_tmds_cmn_config() argument
772 hdptx->rate = rate * 100; in rk_hdptx_ropll_tmds_cmn_config()
784 dev_err(hdptx->dev, "%s cannot find pll cfg\n", __func__); in rk_hdptx_ropll_tmds_cmn_config()
785 return -EINVAL; in rk_hdptx_ropll_tmds_cmn_config()
789 dev_dbg(hdptx->dev, "mdiv=%u, sdiv=%u, sdm_en=%u, k_sign=%u, k=%u, lc=%u\n", in rk_hdptx_ropll_tmds_cmn_config()
790 cfg->pms_mdiv, cfg->pms_sdiv + 1, cfg->sdm_en, in rk_hdptx_ropll_tmds_cmn_config()
791 cfg->sdm_num_sign, cfg->sdm_num, cfg->sdm_deno); in rk_hdptx_ropll_tmds_cmn_config()
793 rk_hdptx_pre_power_up(hdptx); in rk_hdptx_ropll_tmds_cmn_config()
795 reset_control_assert(hdptx->rsts[RST_ROPLL].rstc); in rk_hdptx_ropll_tmds_cmn_config()
797 reset_control_deassert(hdptx->rsts[RST_ROPLL].rstc); in rk_hdptx_ropll_tmds_cmn_config()
799 rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_common_cmn_init_seq); in rk_hdptx_ropll_tmds_cmn_config()
800 rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_tmds_cmn_init_seq); in rk_hdptx_ropll_tmds_cmn_config()
802 regmap_write(hdptx->regmap, CMN_REG(0051), cfg->pms_mdiv); in rk_hdptx_ropll_tmds_cmn_config()
803 regmap_write(hdptx->regmap, CMN_REG(0055), cfg->pms_mdiv_afc); in rk_hdptx_ropll_tmds_cmn_config()
804 regmap_write(hdptx->regmap, CMN_REG(0059), in rk_hdptx_ropll_tmds_cmn_config()
805 (cfg->pms_pdiv << 4) | cfg->pms_refdiv); in rk_hdptx_ropll_tmds_cmn_config()
806 regmap_write(hdptx->regmap, CMN_REG(005a), cfg->pms_sdiv << 4); in rk_hdptx_ropll_tmds_cmn_config()
808 regmap_update_bits(hdptx->regmap, CMN_REG(005e), ROPLL_SDM_EN_MASK, in rk_hdptx_ropll_tmds_cmn_config()
809 FIELD_PREP(ROPLL_SDM_EN_MASK, cfg->sdm_en)); in rk_hdptx_ropll_tmds_cmn_config()
810 if (!cfg->sdm_en) in rk_hdptx_ropll_tmds_cmn_config()
811 regmap_update_bits(hdptx->regmap, CMN_REG(005e), 0xf, 0); in rk_hdptx_ropll_tmds_cmn_config()
813 regmap_update_bits(hdptx->regmap, CMN_REG(0064), ROPLL_SDM_NUM_SIGN_RBR_MASK, in rk_hdptx_ropll_tmds_cmn_config()
814 FIELD_PREP(ROPLL_SDM_NUM_SIGN_RBR_MASK, cfg->sdm_num_sign)); in rk_hdptx_ropll_tmds_cmn_config()
816 regmap_write(hdptx->regmap, CMN_REG(0060), cfg->sdm_deno); in rk_hdptx_ropll_tmds_cmn_config()
817 regmap_write(hdptx->regmap, CMN_REG(0065), cfg->sdm_num); in rk_hdptx_ropll_tmds_cmn_config()
819 regmap_update_bits(hdptx->regmap, CMN_REG(0069), ROPLL_SDC_N_RBR_MASK, in rk_hdptx_ropll_tmds_cmn_config()
820 FIELD_PREP(ROPLL_SDC_N_RBR_MASK, cfg->sdc_n)); in rk_hdptx_ropll_tmds_cmn_config()
822 regmap_write(hdptx->regmap, CMN_REG(006c), cfg->sdc_num); in rk_hdptx_ropll_tmds_cmn_config()
823 regmap_write(hdptx->regmap, CMN_REG(0070), cfg->sdc_deno); in rk_hdptx_ropll_tmds_cmn_config()
825 regmap_update_bits(hdptx->regmap, CMN_REG(0086), PLL_PCG_POSTDIV_SEL_MASK, in rk_hdptx_ropll_tmds_cmn_config()
826 FIELD_PREP(PLL_PCG_POSTDIV_SEL_MASK, cfg->pms_sdiv)); in rk_hdptx_ropll_tmds_cmn_config()
828 regmap_update_bits(hdptx->regmap, CMN_REG(0086), PLL_PCG_CLK_EN, in rk_hdptx_ropll_tmds_cmn_config()
831 return rk_hdptx_post_enable_pll(hdptx); in rk_hdptx_ropll_tmds_cmn_config()
834 static int rk_hdptx_ropll_tmds_mode_config(struct rk_hdptx_phy *hdptx, in rk_hdptx_ropll_tmds_mode_config() argument
837 rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_common_sb_init_seq); in rk_hdptx_ropll_tmds_mode_config()
839 regmap_write(hdptx->regmap, LNTOP_REG(0200), 0x06); in rk_hdptx_ropll_tmds_mode_config()
843 rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_tmds_lntop_highbr_seq); in rk_hdptx_ropll_tmds_mode_config()
846 rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_tmds_lntop_lowbr_seq); in rk_hdptx_ropll_tmds_mode_config()
849 regmap_write(hdptx->regmap, LNTOP_REG(0206), 0x07); in rk_hdptx_ropll_tmds_mode_config()
850 regmap_write(hdptx->regmap, LNTOP_REG(0207), 0x0f); in rk_hdptx_ropll_tmds_mode_config()
852 rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_common_lane_init_seq); in rk_hdptx_ropll_tmds_mode_config()
853 rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_tmds_lane_init_seq); in rk_hdptx_ropll_tmds_mode_config()
855 return rk_hdptx_post_enable_lane(hdptx); in rk_hdptx_ropll_tmds_mode_config()
858 static int rk_hdptx_phy_consumer_get(struct rk_hdptx_phy *hdptx, in rk_hdptx_phy_consumer_get() argument
864 if (atomic_inc_return(&hdptx->usage_count) > 1) in rk_hdptx_phy_consumer_get()
867 ret = regmap_read(hdptx->grf, GRF_HDPTX_STATUS, &status); in rk_hdptx_phy_consumer_get()
872 dev_warn(hdptx->dev, "PLL locked by unknown consumer!\n"); in rk_hdptx_phy_consumer_get()
875 ret = rk_hdptx_ropll_tmds_cmn_config(hdptx, rate); in rk_hdptx_phy_consumer_get()
883 atomic_dec(&hdptx->usage_count); in rk_hdptx_phy_consumer_get()
887 static int rk_hdptx_phy_consumer_put(struct rk_hdptx_phy *hdptx, bool force) in rk_hdptx_phy_consumer_put() argument
892 ret = atomic_dec_return(&hdptx->usage_count); in rk_hdptx_phy_consumer_put()
897 dev_warn(hdptx->dev, "Usage count underflow!\n"); in rk_hdptx_phy_consumer_put()
898 ret = -EINVAL; in rk_hdptx_phy_consumer_put()
900 ret = regmap_read(hdptx->grf, GRF_HDPTX_STATUS, &status); in rk_hdptx_phy_consumer_put()
903 rk_hdptx_phy_disable(hdptx); in rk_hdptx_phy_consumer_put()
910 atomic_inc(&hdptx->usage_count); in rk_hdptx_phy_consumer_put()
914 static int rk_hdptx_phy_power_on(struct phy *phy) in rk_hdptx_phy_power_on() argument
916 struct rk_hdptx_phy *hdptx = phy_get_drvdata(phy); in rk_hdptx_phy_power_on() local
917 int bus_width = phy_get_bus_width(hdptx->phy); in rk_hdptx_phy_power_on()
923 * becomes available in the PHY API. in rk_hdptx_phy_power_on()
927 dev_dbg(hdptx->dev, "%s bus_width=%x rate=%u\n", in rk_hdptx_phy_power_on()
930 ret = rk_hdptx_phy_consumer_get(hdptx, rate); in rk_hdptx_phy_power_on()
934 ret = rk_hdptx_ropll_tmds_mode_config(hdptx, rate); in rk_hdptx_phy_power_on()
936 rk_hdptx_phy_consumer_put(hdptx, true); in rk_hdptx_phy_power_on()
941 static int rk_hdptx_phy_power_off(struct phy *phy) in rk_hdptx_phy_power_off() argument
943 struct rk_hdptx_phy *hdptx = phy_get_drvdata(phy); in rk_hdptx_phy_power_off() local
945 return rk_hdptx_phy_consumer_put(hdptx, false); in rk_hdptx_phy_power_off()
961 struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw); in rk_hdptx_phy_clk_prepare() local
963 return rk_hdptx_phy_consumer_get(hdptx, hdptx->rate / 100); in rk_hdptx_phy_clk_prepare()
968 struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw); in rk_hdptx_phy_clk_unprepare() local
970 rk_hdptx_phy_consumer_put(hdptx, true); in rk_hdptx_phy_clk_unprepare()
976 struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw); in rk_hdptx_phy_clk_recalc_rate() local
978 return hdptx->rate; in rk_hdptx_phy_clk_recalc_rate()
996 return -EINVAL; in rk_hdptx_phy_clk_round_rate()
1004 struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw); in rk_hdptx_phy_clk_set_rate() local
1006 return rk_hdptx_ropll_tmds_cmn_config(hdptx, rate / 100); in rk_hdptx_phy_clk_set_rate()
1017 static int rk_hdptx_phy_clk_register(struct rk_hdptx_phy *hdptx) in rk_hdptx_phy_clk_register() argument
1019 struct device *dev = hdptx->dev; in rk_hdptx_phy_clk_register()
1029 id = of_alias_get_id(dev->of_node, "hdptxphy"); in rk_hdptx_phy_clk_register()
1033 hdptx->hw.init = CLK_HW_INIT(name, pname, &hdptx_phy_clk_ops, in rk_hdptx_phy_clk_register()
1036 ret = devm_clk_hw_register(dev, &hdptx->hw); in rk_hdptx_phy_clk_register()
1040 ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, &hdptx->hw); in rk_hdptx_phy_clk_register()
1049 struct rk_hdptx_phy *hdptx = dev_get_drvdata(dev); in rk_hdptx_phy_runtime_suspend() local
1051 clk_bulk_disable_unprepare(hdptx->nr_clks, hdptx->clks); in rk_hdptx_phy_runtime_suspend()
1058 struct rk_hdptx_phy *hdptx = dev_get_drvdata(dev); in rk_hdptx_phy_runtime_resume() local
1061 ret = clk_bulk_prepare_enable(hdptx->nr_clks, hdptx->clks); in rk_hdptx_phy_runtime_resume()
1063 dev_err(hdptx->dev, "Failed to enable clocks: %d\n", ret); in rk_hdptx_phy_runtime_resume()
1071 struct device *dev = &pdev->dev; in rk_hdptx_phy_probe()
1072 struct rk_hdptx_phy *hdptx; in rk_hdptx_phy_probe() local
1076 hdptx = devm_kzalloc(dev, sizeof(*hdptx), GFP_KERNEL); in rk_hdptx_phy_probe()
1077 if (!hdptx) in rk_hdptx_phy_probe()
1078 return -ENOMEM; in rk_hdptx_phy_probe()
1080 hdptx->dev = dev; in rk_hdptx_phy_probe()
1087 ret = devm_clk_bulk_get_all(dev, &hdptx->clks); in rk_hdptx_phy_probe()
1091 return dev_err_probe(dev, -EINVAL, "Missing clocks\n"); in rk_hdptx_phy_probe()
1093 hdptx->nr_clks = ret; in rk_hdptx_phy_probe()
1095 hdptx->regmap = devm_regmap_init_mmio(dev, regs, in rk_hdptx_phy_probe()
1097 if (IS_ERR(hdptx->regmap)) in rk_hdptx_phy_probe()
1098 return dev_err_probe(dev, PTR_ERR(hdptx->regmap), in rk_hdptx_phy_probe()
1101 hdptx->rsts[RST_PHY].id = "phy"; in rk_hdptx_phy_probe()
1102 hdptx->rsts[RST_APB].id = "apb"; in rk_hdptx_phy_probe()
1103 hdptx->rsts[RST_INIT].id = "init"; in rk_hdptx_phy_probe()
1104 hdptx->rsts[RST_CMN].id = "cmn"; in rk_hdptx_phy_probe()
1105 hdptx->rsts[RST_LANE].id = "lane"; in rk_hdptx_phy_probe()
1106 hdptx->rsts[RST_ROPLL].id = "ropll"; in rk_hdptx_phy_probe()
1107 hdptx->rsts[RST_LCPLL].id = "lcpll"; in rk_hdptx_phy_probe()
1109 ret = devm_reset_control_bulk_get_exclusive(dev, RST_MAX, hdptx->rsts); in rk_hdptx_phy_probe()
1113 hdptx->grf = syscon_regmap_lookup_by_phandle(dev->of_node, in rk_hdptx_phy_probe()
1115 if (IS_ERR(hdptx->grf)) in rk_hdptx_phy_probe()
1116 return dev_err_probe(dev, PTR_ERR(hdptx->grf), in rk_hdptx_phy_probe()
1123 hdptx->phy = devm_phy_create(dev, NULL, &rk_hdptx_phy_ops); in rk_hdptx_phy_probe()
1124 if (IS_ERR(hdptx->phy)) in rk_hdptx_phy_probe()
1125 return dev_err_probe(dev, PTR_ERR(hdptx->phy), in rk_hdptx_phy_probe()
1126 "Failed to create HDMI PHY\n"); in rk_hdptx_phy_probe()
1128 platform_set_drvdata(pdev, hdptx); in rk_hdptx_phy_probe()
1129 phy_set_drvdata(hdptx->phy, hdptx); in rk_hdptx_phy_probe()
1130 phy_set_bus_width(hdptx->phy, 8); in rk_hdptx_phy_probe()
1135 "Failed to register PHY provider\n"); in rk_hdptx_phy_probe()
1137 reset_control_deassert(hdptx->rsts[RST_APB].rstc); in rk_hdptx_phy_probe()
1138 reset_control_deassert(hdptx->rsts[RST_CMN].rstc); in rk_hdptx_phy_probe()
1139 reset_control_deassert(hdptx->rsts[RST_INIT].rstc); in rk_hdptx_phy_probe()
1141 return rk_hdptx_phy_clk_register(hdptx); in rk_hdptx_phy_probe()
1150 { .compatible = "rockchip,rk3588-hdptx-phy", },
1158 .name = "rockchip-hdptx-phy",
1165 MODULE_AUTHOR("Algea Cao <algea.cao@rock-chips.com>");
1167 MODULE_DESCRIPTION("Samsung HDMI/eDP Transmitter Combo PHY Driver");