Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

phy: rockchip: samsung-hdptx: Add HDMI 2.1 FRL support

The PHY is capable of handling four HDMI 2.1 Fixed Rate Link (FRL)
lanes, and each one can operate at any of the rates of 3Gbps, 6Gbps,
8Gbps, 10Gbps or 12Gbps.

Add the necessary driver changes to support the feature.

Co-developed-by: Algea Cao <algea.cao@rock-chips.com>
Signed-off-by: Algea Cao <algea.cao@rock-chips.com>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
Link: https://patch.msgid.link/20260113-phy-hdptx-frl-v6-11-8d5f97419c0b@collabora.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>

authored by

Cristian Ciocaltea and committed by
Vinod Koul
de5dba83 b14fec4d

+418 -23
+418 -23
drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
··· 22 22 #include <linux/reset.h> 23 23 24 24 #define GRF_HDPTX_CON0 0x00 25 + #define LC_REF_CLK_SEL BIT(11) 25 26 #define HDPTX_I_PLL_EN BIT(7) 26 27 #define HDPTX_I_BIAS_EN BIT(6) 27 28 #define HDPTX_I_BGR_EN BIT(5) ··· 323 322 324 323 #define HDMI14_MAX_RATE 340000000 325 324 #define HDMI20_MAX_RATE 600000000 325 + #define FRL_3G3L_RATE 900000000 326 + #define FRL_6G3L_RATE 1800000000 327 + #define FRL_8G4L_RATE 3200000000 326 328 327 329 enum dp_link_rate { 328 330 DP_BW_RBR, 329 331 DP_BW_HBR, 330 332 DP_BW_HBR2, 333 + }; 334 + 335 + struct lcpll_config { 336 + unsigned long long rate; 337 + u8 lcvco_mode_en; 338 + u8 pi_en; 339 + u8 clk_en_100m; 340 + u8 pms_mdiv; 341 + u8 pms_mdiv_afc; 342 + u8 pms_pdiv; 343 + u8 pms_refdiv; 344 + u8 pms_sdiv; 345 + u8 sdm_deno; 346 + u8 sdm_num_sign; 347 + u8 sdm_num; 348 + u8 sdc_n; 331 349 }; 332 350 333 351 struct ropll_config { ··· 394 374 }; 395 375 396 376 struct rk_hdptx_hdmi_cfg { 377 + enum phy_hdmi_mode mode; 397 378 unsigned long long rate; 398 379 unsigned int bpc; 399 380 }; ··· 420 399 /* used for dp mode */ 421 400 unsigned int link_rate; 422 401 unsigned int lanes; 402 + }; 403 + 404 + static const struct lcpll_config rk_hdptx_frl_lcpll_cfg[] = { 405 + /* | pms | sdm | */ 406 + /* rate, lcen, pien, cken, mdiv, mdafc, pdiv, rdiv, sdiv, deno, nsig, num, sdcn, */ 407 + { 4800000000ULL, 1, 0, 0, 125, 125, 1, 1, 0, 1, 0, 0, 2, }, 408 + { 4000000000ULL, 1, 1, 0, 104, 104, 1, 1, 0, 9, 0, 1, 1, }, 409 + { 2400000000ULL, 1, 0, 0, 125, 125, 1, 1, 1, 1, 0, 0, 2, }, 410 + { 1800000000ULL, 1, 0, 0, 125, 125, 1, 1, 1, 1, 0, 0, 2, }, 411 + { 900000000ULL, 1, 0, 0, 125, 125, 1, 1, 3, 1, 0, 0, 2, }, 423 412 }; 424 413 425 414 static const struct ropll_config rk_hdptx_tmds_ropll_cfg[] = { ··· 531 500 REG_SEQ0(CMN_REG(009a), 0x11), 532 501 }; 533 502 503 + static const struct reg_sequence rk_hdptx_frl_lcpll_cmn_init_seq[] = { 504 + REG_SEQ0(CMN_REG(0011), 0x00), 505 + REG_SEQ0(CMN_REG(0017), 0x00), 506 + REG_SEQ0(CMN_REG(0025), 0x10), 507 + REG_SEQ0(CMN_REG(0026), 0x53), 508 + REG_SEQ0(CMN_REG(0027), 0x01), 509 + REG_SEQ0(CMN_REG(0028), 0x0d), 510 + REG_SEQ0(CMN_REG(002e), 0x02), 511 + REG_SEQ0(CMN_REG(002f), 0x0d), 512 + REG_SEQ0(CMN_REG(0030), 0x00), 513 + REG_SEQ0(CMN_REG(0031), 0x20), 514 + REG_SEQ0(CMN_REG(0032), 0x30), 515 + REG_SEQ0(CMN_REG(0033), 0x0b), 516 + REG_SEQ0(CMN_REG(0034), 0x23), 517 + REG_SEQ0(CMN_REG(003d), 0x00), 518 + REG_SEQ0(CMN_REG(0042), 0xb8), 519 + REG_SEQ0(CMN_REG(0046), 0xff), 520 + REG_SEQ0(CMN_REG(0048), 0x44), 521 + REG_SEQ0(CMN_REG(004e), 0x14), 522 + REG_SEQ0(CMN_REG(0051), 0x00), 523 + REG_SEQ0(CMN_REG(0055), 0x00), 524 + REG_SEQ0(CMN_REG(0059), 0x11), 525 + REG_SEQ0(CMN_REG(005a), 0x03), 526 + REG_SEQ0(CMN_REG(005c), 0x05), 527 + REG_SEQ0(CMN_REG(005d), 0x0c), 528 + REG_SEQ0(CMN_REG(005e), 0x07), 529 + REG_SEQ0(CMN_REG(0060), 0x01), 530 + REG_SEQ0(CMN_REG(0064), 0x07), 531 + REG_SEQ0(CMN_REG(0065), 0x00), 532 + REG_SEQ0(CMN_REG(0069), 0x00), 533 + REG_SEQ0(CMN_REG(006b), 0x04), 534 + REG_SEQ0(CMN_REG(006c), 0x00), 535 + REG_SEQ0(CMN_REG(0070), 0x01), 536 + REG_SEQ0(CMN_REG(0073), 0x30), 537 + REG_SEQ0(CMN_REG(0074), 0x00), 538 + REG_SEQ0(CMN_REG(0081), 0x09), 539 + REG_SEQ0(CMN_REG(0086), 0x01), 540 + REG_SEQ0(CMN_REG(0087), 0x0c), 541 + REG_SEQ0(CMN_REG(0089), 0x02), 542 + REG_SEQ0(CMN_REG(0095), 0x00), 543 + REG_SEQ0(CMN_REG(0097), 0x00), 544 + REG_SEQ0(CMN_REG(0099), 0x00), 545 + REG_SEQ0(CMN_REG(009b), 0x10), 546 + }; 547 + 548 + static const struct reg_sequence rk_hdptx_frl_lcpll_ropll_cmn_init_seq[] = { 549 + REG_SEQ0(CMN_REG(0008), 0xd0), 550 + REG_SEQ0(CMN_REG(0011), 0x00), 551 + REG_SEQ0(CMN_REG(0017), 0x00), 552 + REG_SEQ0(CMN_REG(001e), 0x35), 553 + REG_SEQ0(CMN_REG(0020), 0x6b), 554 + REG_SEQ0(CMN_REG(0021), 0x6b), 555 + REG_SEQ0(CMN_REG(0022), 0x11), 556 + REG_SEQ0(CMN_REG(0024), 0x00), 557 + REG_SEQ0(CMN_REG(0025), 0x10), 558 + REG_SEQ0(CMN_REG(0026), 0x53), 559 + REG_SEQ0(CMN_REG(0027), 0x15), 560 + REG_SEQ0(CMN_REG(0028), 0x0d), 561 + REG_SEQ0(CMN_REG(002a), 0x09), 562 + REG_SEQ0(CMN_REG(002b), 0x01), 563 + REG_SEQ0(CMN_REG(002c), 0x02), 564 + REG_SEQ0(CMN_REG(002d), 0x02), 565 + REG_SEQ0(CMN_REG(002e), 0x0d), 566 + REG_SEQ0(CMN_REG(002f), 0x61), 567 + REG_SEQ0(CMN_REG(0030), 0x00), 568 + REG_SEQ0(CMN_REG(0031), 0x20), 569 + REG_SEQ0(CMN_REG(0032), 0x30), 570 + REG_SEQ0(CMN_REG(0033), 0x0b), 571 + REG_SEQ0(CMN_REG(0034), 0x23), 572 + REG_SEQ0(CMN_REG(0037), 0x00), 573 + REG_SEQ0(CMN_REG(003d), 0xc0), 574 + REG_SEQ0(CMN_REG(0042), 0xb8), 575 + REG_SEQ0(CMN_REG(0046), 0xff), 576 + REG_SEQ0(CMN_REG(0048), 0x44), 577 + REG_SEQ0(CMN_REG(004e), 0x14), 578 + REG_SEQ0(CMN_REG(0054), 0x19), 579 + REG_SEQ0(CMN_REG(0058), 0x19), 580 + REG_SEQ0(CMN_REG(0059), 0x11), 581 + REG_SEQ0(CMN_REG(005b), 0x30), 582 + REG_SEQ0(CMN_REG(005c), 0x25), 583 + REG_SEQ0(CMN_REG(005d), 0x14), 584 + REG_SEQ0(CMN_REG(005e), 0x0e), 585 + REG_SEQ0(CMN_REG(0063), 0x01), 586 + REG_SEQ0(CMN_REG(0064), 0x0e), 587 + REG_SEQ0(CMN_REG(0068), 0x00), 588 + REG_SEQ0(CMN_REG(0069), 0x02), 589 + REG_SEQ0(CMN_REG(006b), 0x00), 590 + REG_SEQ0(CMN_REG(006f), 0x00), 591 + REG_SEQ0(CMN_REG(0073), 0x02), 592 + REG_SEQ0(CMN_REG(0074), 0x00), 593 + REG_SEQ0(CMN_REG(007a), 0x00), 594 + REG_SEQ0(CMN_REG(0081), 0x09), 595 + REG_SEQ0(CMN_REG(0086), 0x11), 596 + REG_SEQ0(CMN_REG(0087), 0x0c), 597 + REG_SEQ0(CMN_REG(0089), 0x00), 598 + REG_SEQ0(CMN_REG(0095), 0x03), 599 + REG_SEQ0(CMN_REG(0097), 0x00), 600 + REG_SEQ0(CMN_REG(0099), 0x00), 601 + REG_SEQ0(CMN_REG(009b), 0x10), 602 + REG_SEQ0(CMN_REG(009e), 0x03), 603 + REG_SEQ0(CMN_REG(009f), 0xff), 604 + REG_SEQ0(CMN_REG(00a0), 0x60), 605 + }; 606 + 534 607 static const struct reg_sequence rk_hdptx_tmds_cmn_init_seq[] = { 535 608 REG_SEQ0(CMN_REG(0008), 0x00), 536 609 REG_SEQ0(CMN_REG(0011), 0x01), ··· 686 551 REG_SEQ0(SB_REG(0115), 0x00), 687 552 REG_SEQ0(SB_REG(0116), 0x00), 688 553 REG_SEQ0(SB_REG(0117), 0x00), 554 + }; 555 + 556 + static const struct reg_sequence rk_hdptx_frl_lntop_init_seq[] = { 557 + REG_SEQ0(LNTOP_REG(0200), 0x04), 558 + REG_SEQ0(LNTOP_REG(0201), 0x00), 559 + REG_SEQ0(LNTOP_REG(0202), 0x00), 560 + REG_SEQ0(LNTOP_REG(0203), 0xf0), 561 + REG_SEQ0(LNTOP_REG(0204), 0xff), 562 + REG_SEQ0(LNTOP_REG(0205), 0xff), 563 + REG_SEQ0(LNTOP_REG(0206), 0x05), 689 564 }; 690 565 691 566 static const struct reg_sequence rk_hdptx_tmds_lntop_highbr_seq[] = { ··· 767 622 REG_SEQ0(LANE_REG(061b), 0x01), 768 623 REG_SEQ0(LANE_REG(061f), 0x15), 769 624 REG_SEQ0(LANE_REG(0620), 0xa0), 625 + }; 626 + 627 + static const struct reg_sequence rk_hdptx_frl_lane_init_seq[] = { 628 + REG_SEQ0(LANE_REG(0312), 0x3c), 629 + REG_SEQ0(LANE_REG(0412), 0x3c), 630 + REG_SEQ0(LANE_REG(0512), 0x3c), 631 + REG_SEQ0(LANE_REG(0612), 0x3c), 632 + REG_SEQ0(LANE_REG(0303), 0x2f), 633 + REG_SEQ0(LANE_REG(0403), 0x2f), 634 + REG_SEQ0(LANE_REG(0503), 0x2f), 635 + REG_SEQ0(LANE_REG(0603), 0x2f), 636 + REG_SEQ0(LANE_REG(0305), 0x03), 637 + REG_SEQ0(LANE_REG(0405), 0x03), 638 + REG_SEQ0(LANE_REG(0505), 0x03), 639 + REG_SEQ0(LANE_REG(0605), 0x03), 640 + REG_SEQ0(LANE_REG(0306), 0xfc), 641 + REG_SEQ0(LANE_REG(0406), 0xfc), 642 + REG_SEQ0(LANE_REG(0506), 0xfc), 643 + REG_SEQ0(LANE_REG(0606), 0xfc), 644 + REG_SEQ0(LANE_REG(0305), 0x4f), 645 + REG_SEQ0(LANE_REG(0405), 0x4f), 646 + REG_SEQ0(LANE_REG(0505), 0x4f), 647 + REG_SEQ0(LANE_REG(0605), 0x4f), 648 + REG_SEQ0(LANE_REG(0304), 0x14), 649 + REG_SEQ0(LANE_REG(0404), 0x14), 650 + REG_SEQ0(LANE_REG(0504), 0x14), 651 + REG_SEQ0(LANE_REG(0604), 0x14), 652 + /* Keep Inter-Pair Skew in the limits */ 653 + REG_SEQ0(LANE_REG(031e), 0x02), 654 + REG_SEQ0(LANE_REG(041e), 0x02), 655 + REG_SEQ0(LANE_REG(051e), 0x02), 656 + REG_SEQ0(LANE_REG(061e), 0x02), 770 657 }; 771 658 772 659 static const struct reg_sequence rk_hdptx_tmds_lane_init_seq[] = { ··· 964 787 HDPTX_I_BIAS_EN | HDPTX_I_BGR_EN; 965 788 regmap_write(hdptx->grf, GRF_HDPTX_CON0, val); 966 789 967 - regmap_write(hdptx->regmap, LNTOP_REG(0207), 0x0f); 790 + /* 3 lanes FRL mode */ 791 + if (hdptx->hdmi_cfg.rate == FRL_6G3L_RATE || 792 + hdptx->hdmi_cfg.rate == FRL_3G3L_RATE) 793 + regmap_write(hdptx->regmap, LNTOP_REG(0207), 0x07); 794 + else 795 + regmap_write(hdptx->regmap, LNTOP_REG(0207), 0x0f); 968 796 969 797 ret = regmap_read_poll_timeout(hdptx->grf, GRF_HDPTX_STATUS, val, 970 798 (val & HDPTX_O_PHY_RDY) && ··· 1113 931 return true; 1114 932 } 1115 933 934 + static int rk_hdptx_frl_lcpll_cmn_config(struct rk_hdptx_phy *hdptx) 935 + { 936 + const struct lcpll_config *cfg = NULL; 937 + int i; 938 + 939 + dev_dbg(hdptx->dev, "%s rate=%llu\n", __func__, hdptx->hdmi_cfg.rate); 940 + 941 + for (i = 0; i < ARRAY_SIZE(rk_hdptx_frl_lcpll_cfg); i++) { 942 + if (hdptx->hdmi_cfg.rate == rk_hdptx_frl_lcpll_cfg[i].rate) { 943 + cfg = &rk_hdptx_frl_lcpll_cfg[i]; 944 + break; 945 + } 946 + } 947 + 948 + if (!cfg) { 949 + dev_err(hdptx->dev, "%s cannot find pll cfg for rate=%llu\n", 950 + __func__, hdptx->hdmi_cfg.rate); 951 + return -EINVAL; 952 + } 953 + 954 + rk_hdptx_pre_power_up(hdptx); 955 + 956 + regmap_write(hdptx->grf, GRF_HDPTX_CON0, LC_REF_CLK_SEL << 16); 957 + 958 + rk_hdptx_multi_reg_write(hdptx, rk_hdptx_common_cmn_init_seq); 959 + rk_hdptx_multi_reg_write(hdptx, rk_hdptx_frl_lcpll_cmn_init_seq); 960 + 961 + regmap_update_bits(hdptx->regmap, CMN_REG(0008), 962 + LCPLL_EN_MASK | LCPLL_LCVCO_MODE_EN_MASK, 963 + FIELD_PREP(LCPLL_EN_MASK, 1) | 964 + FIELD_PREP(LCPLL_LCVCO_MODE_EN_MASK, cfg->lcvco_mode_en)); 965 + 966 + regmap_update_bits(hdptx->regmap, CMN_REG(001e), 967 + LCPLL_PI_EN_MASK | LCPLL_100M_CLK_EN_MASK, 968 + FIELD_PREP(LCPLL_PI_EN_MASK, cfg->pi_en) | 969 + FIELD_PREP(LCPLL_100M_CLK_EN_MASK, cfg->clk_en_100m)); 970 + 971 + regmap_write(hdptx->regmap, CMN_REG(0020), cfg->pms_mdiv); 972 + regmap_write(hdptx->regmap, CMN_REG(0021), cfg->pms_mdiv_afc); 973 + regmap_write(hdptx->regmap, CMN_REG(0022), 974 + (cfg->pms_pdiv << 4) | cfg->pms_refdiv); 975 + regmap_write(hdptx->regmap, CMN_REG(0023), 976 + (cfg->pms_sdiv << 4) | cfg->pms_sdiv); 977 + regmap_write(hdptx->regmap, CMN_REG(002a), cfg->sdm_deno); 978 + regmap_write(hdptx->regmap, CMN_REG(002b), cfg->sdm_num_sign); 979 + regmap_write(hdptx->regmap, CMN_REG(002c), cfg->sdm_num); 980 + 981 + regmap_update_bits(hdptx->regmap, CMN_REG(002d), LCPLL_SDC_N_MASK, 982 + FIELD_PREP(LCPLL_SDC_N_MASK, cfg->sdc_n)); 983 + 984 + regmap_update_bits(hdptx->regmap, CMN_REG(0086), PLL_PCG_POSTDIV_SEL_MASK, 985 + FIELD_PREP(PLL_PCG_POSTDIV_SEL_MASK, cfg->pms_sdiv)); 986 + regmap_update_bits(hdptx->regmap, CMN_REG(0086), PLL_PCG_CLK_SEL_MASK, 987 + FIELD_PREP(PLL_PCG_CLK_SEL_MASK, (hdptx->hdmi_cfg.bpc - 8) >> 1)); 988 + 989 + return rk_hdptx_post_enable_pll(hdptx); 990 + } 991 + 992 + static int rk_hdptx_frl_lcpll_ropll_cmn_config(struct rk_hdptx_phy *hdptx) 993 + { 994 + dev_dbg(hdptx->dev, "%s rate=%llu\n", __func__, hdptx->hdmi_cfg.rate); 995 + 996 + rk_hdptx_pre_power_up(hdptx); 997 + 998 + /* ROPLL input reference clock from LCPLL (cascade mode) */ 999 + regmap_write(hdptx->grf, GRF_HDPTX_CON0, 1000 + (LC_REF_CLK_SEL << 16) | LC_REF_CLK_SEL); 1001 + 1002 + rk_hdptx_multi_reg_write(hdptx, rk_hdptx_common_cmn_init_seq); 1003 + rk_hdptx_multi_reg_write(hdptx, rk_hdptx_frl_lcpll_ropll_cmn_init_seq); 1004 + 1005 + return rk_hdptx_post_enable_pll(hdptx); 1006 + } 1007 + 1116 1008 static int rk_hdptx_tmds_ropll_cmn_config(struct rk_hdptx_phy *hdptx) 1117 1009 { 1118 1010 const struct ropll_config *cfg = NULL; ··· 1217 961 cfg->sdm_en, cfg->sdm_num_sign, cfg->sdm_num, cfg->sdm_deno); 1218 962 1219 963 rk_hdptx_pre_power_up(hdptx); 964 + 965 + regmap_write(hdptx->grf, GRF_HDPTX_CON0, LC_REF_CLK_SEL << 16); 1220 966 1221 967 rk_hdptx_multi_reg_write(hdptx, rk_hdptx_common_cmn_init_seq); 1222 968 rk_hdptx_multi_reg_write(hdptx, rk_hdptx_tmds_cmn_init_seq); ··· 1256 998 FIELD_PREP(PLL_PCG_CLK_EN_MASK, 0x1)); 1257 999 1258 1000 return rk_hdptx_post_enable_pll(hdptx); 1001 + } 1002 + 1003 + static int rk_hdptx_pll_cmn_config(struct rk_hdptx_phy *hdptx) 1004 + { 1005 + if (hdptx->hdmi_cfg.rate <= HDMI20_MAX_RATE) 1006 + return rk_hdptx_tmds_ropll_cmn_config(hdptx); 1007 + 1008 + if (hdptx->hdmi_cfg.rate == FRL_8G4L_RATE) 1009 + return rk_hdptx_frl_lcpll_ropll_cmn_config(hdptx); 1010 + 1011 + return rk_hdptx_frl_lcpll_cmn_config(hdptx); 1012 + } 1013 + 1014 + static int rk_hdptx_frl_lcpll_mode_config(struct rk_hdptx_phy *hdptx) 1015 + { 1016 + rk_hdptx_multi_reg_write(hdptx, rk_hdptx_common_sb_init_seq); 1017 + rk_hdptx_multi_reg_write(hdptx, rk_hdptx_frl_lntop_init_seq); 1018 + 1019 + rk_hdptx_multi_reg_write(hdptx, rk_hdptx_common_lane_init_seq); 1020 + rk_hdptx_multi_reg_write(hdptx, rk_hdptx_frl_lane_init_seq); 1021 + 1022 + return rk_hdptx_post_enable_lane(hdptx); 1259 1023 } 1260 1024 1261 1025 static int rk_hdptx_tmds_ropll_mode_config(struct rk_hdptx_phy *hdptx) ··· 1356 1076 if (mode == PHY_MODE_DP) { 1357 1077 rk_hdptx_dp_reset(hdptx); 1358 1078 } else { 1359 - ret = rk_hdptx_tmds_ropll_cmn_config(hdptx); 1079 + ret = rk_hdptx_pll_cmn_config(hdptx); 1360 1080 if (ret) 1361 1081 goto dec_usage; 1362 1082 } ··· 1657 1377 int ret, lane; 1658 1378 1659 1379 if (mode != PHY_MODE_DP) { 1660 - if (!hdptx->hdmi_cfg.rate) { 1380 + if (!hdptx->hdmi_cfg.rate && hdptx->hdmi_cfg.mode != PHY_HDMI_MODE_FRL) { 1661 1381 /* 1662 1382 * FIXME: Temporary workaround to setup TMDS char rate 1663 1383 * from the RK DW HDMI QP bridge driver. ··· 1703 1423 regmap_write(hdptx->grf, GRF_HDPTX_CON0, 1704 1424 HDPTX_MODE_SEL << 16 | FIELD_PREP(HDPTX_MODE_SEL, 0x0)); 1705 1425 1706 - ret = rk_hdptx_tmds_ropll_mode_config(hdptx); 1426 + if (hdptx->hdmi_cfg.mode == PHY_HDMI_MODE_FRL) 1427 + ret = rk_hdptx_frl_lcpll_mode_config(hdptx); 1428 + else 1429 + ret = rk_hdptx_tmds_ropll_mode_config(hdptx); 1430 + 1707 1431 if (ret) 1708 1432 rk_hdptx_phy_consumer_put(hdptx, true); 1709 1433 } ··· 1728 1444 { 1729 1445 int i; 1730 1446 1731 - if (!hdmi_in->tmds_char_rate || hdmi_in->tmds_char_rate > HDMI20_MAX_RATE) 1732 - return -EINVAL; 1447 + if (hdptx->hdmi_cfg.mode == PHY_HDMI_MODE_FRL) { 1448 + unsigned long long frl_rate = 100000000ULL * hdmi_in->frl.lanes * 1449 + hdmi_in->frl.rate_per_lane; 1733 1450 1734 - for (i = 0; i < ARRAY_SIZE(rk_hdptx_tmds_ropll_cfg); i++) 1735 - if (hdmi_in->tmds_char_rate == rk_hdptx_tmds_ropll_cfg[i].rate) 1451 + switch (hdmi_in->frl.rate_per_lane) { 1452 + case 3: 1453 + case 6: 1454 + case 8: 1455 + case 10: 1456 + case 12: 1736 1457 break; 1458 + default: 1459 + return -EINVAL; 1460 + } 1737 1461 1738 - if (i == ARRAY_SIZE(rk_hdptx_tmds_ropll_cfg) && 1739 - !rk_hdptx_phy_clk_pll_calc(hdmi_in->tmds_char_rate, NULL)) 1740 - return -EINVAL; 1462 + if (!hdmi_in->frl.lanes || hdmi_in->frl.lanes > 4) 1463 + return -EINVAL; 1464 + 1465 + if (frl_rate != FRL_8G4L_RATE) { 1466 + for (i = 0; i < ARRAY_SIZE(rk_hdptx_frl_lcpll_cfg); i++) 1467 + if (frl_rate == rk_hdptx_frl_lcpll_cfg[i].rate) 1468 + break; 1469 + if (i == ARRAY_SIZE(rk_hdptx_frl_lcpll_cfg)) 1470 + return -EINVAL; 1471 + } 1472 + 1473 + if (hdmi_out) 1474 + hdmi_out->rate = frl_rate; 1475 + } else { 1476 + if (!hdmi_in->tmds_char_rate || hdmi_in->tmds_char_rate > HDMI20_MAX_RATE) 1477 + return -EINVAL; 1478 + 1479 + for (i = 0; i < ARRAY_SIZE(rk_hdptx_tmds_ropll_cfg); i++) 1480 + if (hdmi_in->tmds_char_rate == rk_hdptx_tmds_ropll_cfg[i].rate) 1481 + break; 1482 + 1483 + if (i == ARRAY_SIZE(rk_hdptx_tmds_ropll_cfg) && 1484 + !rk_hdptx_phy_clk_pll_calc(hdmi_in->tmds_char_rate, NULL)) 1485 + return -EINVAL; 1486 + 1487 + if (hdmi_out) 1488 + hdmi_out->rate = hdmi_in->tmds_char_rate; 1489 + } 1741 1490 1742 1491 switch (hdmi_in->bpc) { 1743 1492 case 0: ··· 1783 1466 return -EINVAL; 1784 1467 } 1785 1468 1786 - if (hdmi_out) { 1787 - hdmi_out->rate = hdmi_in->tmds_char_rate; 1469 + if (hdmi_out) 1788 1470 hdmi_out->bpc = hdmi_in->bpc ?: 8; 1789 - } 1790 1471 1791 1472 return 0; 1792 1473 } ··· 2044 1729 return 0; 2045 1730 } 2046 1731 1732 + static int rk_hdptx_phy_set_mode(struct phy *phy, enum phy_mode mode, int submode) 1733 + { 1734 + struct rk_hdptx_phy *hdptx = phy_get_drvdata(phy); 1735 + 1736 + if (mode == PHY_MODE_DP) 1737 + return 0; 1738 + 1739 + if (mode != PHY_MODE_HDMI) { 1740 + dev_err(&phy->dev, "invalid PHY mode: %d\n", mode); 1741 + return -EINVAL; 1742 + } 1743 + 1744 + switch (submode) { 1745 + case PHY_HDMI_MODE_TMDS: 1746 + case PHY_HDMI_MODE_FRL: 1747 + hdptx->hdmi_cfg.mode = submode; 1748 + break; 1749 + default: 1750 + dev_err(&phy->dev, "invalid HDMI mode: %d\n", submode); 1751 + return -EINVAL; 1752 + } 1753 + 1754 + return 0; 1755 + } 1756 + 2047 1757 static int rk_hdptx_phy_configure(struct phy *phy, union phy_configure_opts *opts) 2048 1758 { 2049 1759 struct rk_hdptx_phy *hdptx = phy_get_drvdata(phy); ··· 2136 1796 static const struct phy_ops rk_hdptx_phy_ops = { 2137 1797 .power_on = rk_hdptx_phy_power_on, 2138 1798 .power_off = rk_hdptx_phy_power_off, 1799 + .set_mode = rk_hdptx_phy_set_mode, 2139 1800 .configure = rk_hdptx_phy_configure, 2140 1801 .validate = rk_hdptx_phy_validate, 2141 1802 .owner = THIS_MODULE, ··· 2165 1824 2166 1825 static u64 rk_hdptx_phy_clk_calc_rate_from_pll_cfg(struct rk_hdptx_phy *hdptx) 2167 1826 { 1827 + struct lcpll_config lcpll_hw; 2168 1828 struct ropll_config ropll_hw; 2169 1829 u64 fout, sdm; 2170 1830 u32 mode, val; 2171 - int ret; 1831 + int ret, i; 2172 1832 2173 1833 ret = regmap_read(hdptx->regmap, CMN_REG(0008), &mode); 2174 1834 if (ret) 2175 1835 return 0; 2176 1836 2177 - if (mode & LCPLL_LCVCO_MODE_EN_MASK) 1837 + if (mode & LCPLL_LCVCO_MODE_EN_MASK) { 1838 + ret = regmap_read(hdptx->regmap, CMN_REG(0020), &val); 1839 + if (ret) 1840 + return 0; 1841 + lcpll_hw.pms_mdiv = val; 1842 + 1843 + ret = regmap_read(hdptx->regmap, CMN_REG(0023), &val); 1844 + if (ret) 1845 + return 0; 1846 + lcpll_hw.pms_sdiv = val & 0xf; 1847 + 1848 + ret = regmap_read(hdptx->regmap, CMN_REG(002B), &val); 1849 + if (ret) 1850 + return 0; 1851 + lcpll_hw.sdm_num_sign = val; 1852 + 1853 + ret = regmap_read(hdptx->regmap, CMN_REG(002C), &val); 1854 + if (ret) 1855 + return 0; 1856 + lcpll_hw.sdm_num = val; 1857 + 1858 + ret = regmap_read(hdptx->regmap, CMN_REG(002A), &val); 1859 + if (ret) 1860 + return 0; 1861 + lcpll_hw.sdm_deno = val; 1862 + 1863 + ret = regmap_read(hdptx->regmap, CMN_REG(002D), &val); 1864 + if (ret) 1865 + return 0; 1866 + lcpll_hw.sdc_n = (val & LCPLL_SDC_N_MASK) >> 1; 1867 + 1868 + for (i = 0; i < ARRAY_SIZE(rk_hdptx_frl_lcpll_cfg); i++) { 1869 + const struct lcpll_config *cfg = &rk_hdptx_frl_lcpll_cfg[i]; 1870 + 1871 + if (cfg->pms_mdiv == lcpll_hw.pms_mdiv && 1872 + cfg->pms_sdiv == lcpll_hw.pms_sdiv && 1873 + cfg->sdm_num_sign == lcpll_hw.sdm_num_sign && 1874 + cfg->sdm_num == lcpll_hw.sdm_num && 1875 + cfg->sdm_deno == lcpll_hw.sdm_deno && 1876 + cfg->sdc_n == lcpll_hw.sdc_n) 1877 + return cfg->rate; 1878 + } 1879 + 1880 + dev_dbg(hdptx->dev, "%s no FRL match found\n", __func__); 2178 1881 return 0; 1882 + } 2179 1883 2180 1884 ret = regmap_read(hdptx->regmap, CMN_REG(0051), &val); 2181 1885 if (ret) ··· 2297 1911 2298 1912 rate = rk_hdptx_phy_clk_calc_rate_from_pll_cfg(hdptx); 2299 1913 1914 + if (hdptx->hdmi_cfg.mode == PHY_HDMI_MODE_FRL) 1915 + return rate; 1916 + 2300 1917 return DIV_ROUND_CLOSEST_ULL(rate * 8, hdptx->hdmi_cfg.bpc); 2301 1918 } 2302 1919 ··· 2307 1918 struct clk_rate_request *req) 2308 1919 { 2309 1920 struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw); 1921 + 1922 + if (hdptx->hdmi_cfg.mode == PHY_HDMI_MODE_FRL) 1923 + return hdptx->hdmi_cfg.rate; 2310 1924 2311 1925 /* 2312 1926 * FIXME: Temporarily allow altering TMDS char rate via CCF. ··· 2341 1949 unsigned long parent_rate) 2342 1950 { 2343 1951 struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw); 2344 - unsigned long long tmds_rate = DIV_ROUND_CLOSEST_ULL(rate * hdptx->hdmi_cfg.bpc, 8); 1952 + unsigned long long link_rate = rate; 2345 1953 2346 - /* Revert any unlikely TMDS char rate change since determine_rate() */ 2347 - if (hdptx->hdmi_cfg.rate != tmds_rate) { 1954 + if (hdptx->hdmi_cfg.mode != PHY_HDMI_MODE_FRL) 1955 + link_rate = DIV_ROUND_CLOSEST_ULL(rate * hdptx->hdmi_cfg.bpc, 8); 1956 + 1957 + /* Revert any unlikely link rate change since determine_rate() */ 1958 + if (hdptx->hdmi_cfg.rate != link_rate) { 2348 1959 dev_warn(hdptx->dev, "Reverting unexpected rate change from %llu to %llu\n", 2349 - tmds_rate, hdptx->hdmi_cfg.rate); 2350 - hdptx->hdmi_cfg.rate = tmds_rate; 1960 + link_rate, hdptx->hdmi_cfg.rate); 1961 + hdptx->hdmi_cfg.rate = link_rate; 2351 1962 } 2352 1963 2353 1964 /* 2354 - * The TMDS char rate would be normally programmed in HW during 1965 + * The link rate would be normally programmed in HW during 2355 1966 * phy_ops.power_on() or clk_ops.prepare() callbacks, but it might 2356 1967 * happen that the former gets fired too late, i.e. after this call, 2357 1968 * while the latter being executed only once, i.e. when clock remains 2358 1969 * in the prepared state during rate changes. 2359 1970 */ 2360 - return rk_hdptx_tmds_ropll_cmn_config(hdptx); 1971 + return rk_hdptx_pll_cmn_config(hdptx); 2361 1972 } 2362 1973 2363 1974 static const struct clk_ops hdptx_phy_clk_ops = {