From da33ef8e9efda22a64be565c8c4dd5b37def5544 Mon Sep 17 00:00:00 2001 From: Damon Ding Date: Tue, 21 May 2024 15:13:45 +0800 Subject: [PATCH] phy/rockchip: samsung-hdptx: add support for rate R216/R243/R324/R432 R216/R243/R324/R432 are the new recommended link rates in eDP v1.4, which may be read from DPCD SUPPORTED_LINK_RATES (0x00010h through 0x0001fh). And set the link rate by DPCD LINK_BW_SET(0x00100h). Signed-off-by: Damon Ding Change-Id: Ib692d18cd79765eb172fb0455cbc1bc1f0594d79 --- .../phy/rockchip/phy-rockchip-samsung-hdptx.c | 129 +++++++++++++++++- 1 file changed, 124 insertions(+), 5 deletions(-) diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c index 20491361145e..838ed3037894 100644 --- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c +++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c @@ -342,6 +342,13 @@ enum { DP_BW_HBR3, }; +enum { + EDP_BW_2_16, + EDP_BW_2_43, + EDP_BW_3_24, + EDP_BW_4_32, +}; + struct tx_drv_ctrl { u8 tx_drv_lvl_ctrl; u8 tx_drv_post_lvl_ctrl; @@ -351,6 +358,19 @@ struct tx_drv_ctrl { u8 ana_tx_drv_accdrv_ctrl; } __packed; +struct tx_pll_ctrl { + u8 mdiv; + u8 sdiv; + u8 sdm_denominator; + u8 sdm_numerator_sign; + u8 sdm_numerator; + u8 sdc_clock_div; + u8 sdc_numerator; + u8 sdc_denominator; + u8 ssc_deviation; + u8 ssc_freq; +} __packed; + static struct tx_drv_ctrl tx_drv_ctrl_rbr[4][4] = { /* voltage swing 0, pre-emphasis 0->3 */ { @@ -435,6 +455,14 @@ static struct tx_drv_ctrl tx_drv_ctrl_hbr2[4][4] = { } }; +/* pll configurations for link rate R216/R243/R324/R432 */ +static struct tx_pll_ctrl tx_pll_ctrl_extra[4] = { + { 0x5a, 0x01, 0x32, 0x00, 0x00, 0x00, 0x01, 0x04, 0x0f, 0x18 }, /* R216 */ + { 0x65, 0x01, 0x60, 0x00, 0x10, 0x01, 0x13, 0x18, 0x20, 0x0b }, /* R243 */ + { 0x87, 0x01, 0x21, 0x00, 0x00, 0x02, 0x03, 0x08, 0x0e, 0x1a }, /* R324 */ + { 0x5a, 0x00, 0x32, 0x00, 0x00, 0x00, 0x01, 0x01, 0x0f, 0x18 }, /* R432 */ +}; + static int rockchip_hdptx_phy_parse_training_table(struct device *dev) { size_t size = sizeof(struct tx_drv_ctrl) * 10; @@ -492,7 +520,11 @@ static int rockchip_hdptx_phy_verify_config(struct rockchip_hdptx_phy *hdptx, if (dp->set_rate) { switch (dp->link_rate) { case 1620: + case 2160: + case 2430: case 2700: + case 3240: + case 4320: case 5400: break; default: @@ -536,12 +568,16 @@ static void rockchip_hdptx_phy_set_voltage(struct rockchip_hdptx_phy *hdptx, LN_TX_SER_40BIT_EN_RBR, FIELD_PREP(LN_TX_SER_40BIT_EN_RBR, 0x1)); break; + case 2160: + case 2430: case 2700: ctrl = &tx_drv_ctrl_hbr[dp->voltage[lane]][dp->pre[lane]]; regmap_update_bits(hdptx->regmap, LANE_REG(lane, 0x0c44), LN_TX_SER_40BIT_EN_HBR, FIELD_PREP(LN_TX_SER_40BIT_EN_HBR, 0x1)); break; + case 3240: + case 4320: case 5400: default: ctrl = &tx_drv_ctrl_hbr2[dp->voltage[lane]][dp->pre[lane]]; @@ -647,10 +683,24 @@ static int rockchip_hdptx_phy_set_lanes(struct rockchip_hdptx_phy *hdptx, return 0; } +static bool is_extra_recommended_link_rate(u32 link_rate) +{ + switch (link_rate) { + case 2160: + case 2430: + case 3240: + case 4320: + return true; + } + + return false; +} + static int rockchip_hdptx_phy_set_rate(struct rockchip_hdptx_phy *hdptx, struct phy_configure_opts_dp *dp) { u32 bw, status; + u32 bw_extra = 0; int ret; rockchip_grf_write(hdptx->grf, HDPTXPHY_GRF_CON0, PLL_EN, @@ -660,9 +710,25 @@ static int rockchip_hdptx_phy_set_rate(struct rockchip_hdptx_phy *hdptx, case 1620: bw = DP_BW_RBR; break; + case 2160: + bw_extra = EDP_BW_2_16; + bw = DP_BW_HBR; + break; + case 2430: + bw_extra = EDP_BW_2_43; + bw = DP_BW_HBR; + break; case 2700: bw = DP_BW_HBR; break; + case 3240: + bw_extra = EDP_BW_3_24; + bw = DP_BW_HBR2; + break; + case 4320: + bw_extra = EDP_BW_4_32; + bw = DP_BW_HBR2; + break; case 5400: bw = DP_BW_HBR2; break; @@ -670,6 +736,47 @@ static int rockchip_hdptx_phy_set_rate(struct rockchip_hdptx_phy *hdptx, return -EINVAL; } + if (is_extra_recommended_link_rate(dp->link_rate)) { + const struct tx_pll_ctrl *pll_ctrl = &tx_pll_ctrl_extra[bw_extra]; + + regmap_write(hdptx->regmap, 0x0144 + bw * 0x4, + FIELD_PREP(ROPLL_PMS_MDIV, pll_ctrl->mdiv)); + regmap_write(hdptx->regmap, 0x0180 + bw * 0x4, + FIELD_PREP(ROPLL_SDM_DENOMINATOR, pll_ctrl->sdm_denominator)); + regmap_write(hdptx->regmap, 0x0194 + bw * 0x4, + FIELD_PREP(ROPLL_SDM_NUMERATOR, pll_ctrl->sdm_numerator)); + regmap_write(hdptx->regmap, 0x01b0 + bw * 0x4, + FIELD_PREP(ROPLL_SDC_NUMERATOR, pll_ctrl->sdc_numerator)); + regmap_write(hdptx->regmap, 0x01c0 + bw * 0x4, + FIELD_PREP(ROPLL_SDC_DENOMINATOR, pll_ctrl->sdc_denominator)); + + if (bw == DP_BW_RBR) { + regmap_update_bits(hdptx->regmap, 0x0168, ROPLL_PMS_SDIV_RBR, + FIELD_PREP(ROPLL_PMS_SDIV_RBR, pll_ctrl->sdiv)); + regmap_update_bits(hdptx->regmap, 0x0190, ROPLL_SDM_NUMERATOR_SIGN_RBR, + FIELD_PREP(ROPLL_SDM_NUMERATOR_SIGN_RBR, + pll_ctrl->sdm_numerator_sign)); + regmap_update_bits(hdptx->regmap, 0x01a4, ROPLL_SDC_N_RBR, + FIELD_PREP(ROPLL_SDC_N_RBR, pll_ctrl->sdc_clock_div)); + } else if (bw == DP_BW_HBR) { + regmap_update_bits(hdptx->regmap, 0x0168, ROPLL_PMS_SDIV_HBR, + FIELD_PREP(ROPLL_PMS_SDIV_HBR, pll_ctrl->sdiv)); + regmap_update_bits(hdptx->regmap, 0x0190, ROPLL_SDM_NUMERATOR_SIGN_HBR, + FIELD_PREP(ROPLL_SDM_NUMERATOR_SIGN_HBR, + pll_ctrl->sdm_numerator_sign)); + regmap_update_bits(hdptx->regmap, 0x01a8, ROPLL_SDC_N_HBR, + FIELD_PREP(ROPLL_SDC_N_HBR, pll_ctrl->sdc_clock_div)); + } else { + regmap_update_bits(hdptx->regmap, 0x016c, ROPLL_PMS_SDIV_HBR2, + FIELD_PREP(ROPLL_PMS_SDIV_HBR2, pll_ctrl->sdiv)); + regmap_update_bits(hdptx->regmap, 0x0190, ROPLL_SDM_NUMERATOR_SIGN_HBR2, + FIELD_PREP(ROPLL_SDM_NUMERATOR_SIGN_HBR2, + pll_ctrl->sdm_numerator_sign)); + regmap_update_bits(hdptx->regmap, 0x01a8, ROPLL_SDC_N_HBR2, + FIELD_PREP(ROPLL_SDC_N_HBR2, pll_ctrl->sdc_clock_div)); + } + } + regmap_update_bits(hdptx->regmap, 0x0254, DP_TX_LINK_BW, FIELD_PREP(DP_TX_LINK_BW, bw)); @@ -678,11 +785,23 @@ static int rockchip_hdptx_phy_set_rate(struct rockchip_hdptx_phy *hdptx, OVRD_ROPLL_SSC_EN | ROPLL_SSC_EN, FIELD_PREP(OVRD_ROPLL_SSC_EN, 0x1) | FIELD_PREP(ROPLL_SSC_EN, 0x1)); - regmap_write(hdptx->regmap, 0x01d4, - FIELD_PREP(ANA_ROPLL_SSC_FM_DEVIATION, 0xc)); - regmap_update_bits(hdptx->regmap, 0x01d8, - ANA_ROPLL_SSC_FM_FREQ, - FIELD_PREP(ANA_ROPLL_SSC_FM_FREQ, 0x1f)); + if (is_extra_recommended_link_rate(dp->link_rate)) { + const struct tx_pll_ctrl *pll_ctrl = &tx_pll_ctrl_extra[bw_extra]; + + regmap_write(hdptx->regmap, 0x01d4, + FIELD_PREP(ANA_ROPLL_SSC_FM_DEVIATION, + pll_ctrl->ssc_deviation)); + regmap_update_bits(hdptx->regmap, 0x01d8, + ANA_ROPLL_SSC_FM_FREQ, + FIELD_PREP(ANA_ROPLL_SSC_FM_FREQ, + pll_ctrl->ssc_freq)); + } else { + regmap_write(hdptx->regmap, 0x01d4, + FIELD_PREP(ANA_ROPLL_SSC_FM_DEVIATION, 0xc)); + regmap_update_bits(hdptx->regmap, 0x01d8, + ANA_ROPLL_SSC_FM_FREQ, + FIELD_PREP(ANA_ROPLL_SSC_FM_FREQ, 0x1f)); + } regmap_update_bits(hdptx->regmap, 0x0264, SSC_EN, FIELD_PREP(SSC_EN, 0x2)); } else {