phy/rockchip: samsung-hdptx-hdmi: Add PLL setting calculation

Signed-off-by: Wyon Bi <bivvy.bi@rock-chips.com>
Change-Id: I22cbeff98f6f2a13344dc0addf1e1795a3fdaa59
This commit is contained in:
Wyon Bi
2022-03-08 17:58:29 +08:00
committed by Tao Huang
parent 6856fde65c
commit 157bfadfc2

View File

@@ -19,6 +19,7 @@
#include <linux/mfd/syscon.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/rational.h>
#include <linux/regmap.h>
#include <linux/rockchip/cpu.h>
#include <linux/slab.h>
@@ -1124,11 +1125,83 @@ static void hdptx_earc_config(struct rockchip_hdptx_phy *hdptx)
hdptx_update_bits(hdptx, SB_REG0123, SB_READY_MASK, SB_READY(1));
}
static bool hdptx_phy_clk_pll_calc(unsigned int data_rate,
struct ropll_config *cfg)
{
unsigned int fref = 24000;
unsigned int sdc;
unsigned int fout = data_rate / 2;
unsigned int fvco;
u32 mdiv, sdiv, n = 8;
unsigned long k = 0, lc, k_sub, lc_sub;
for (sdiv = 1; sdiv <= 16; sdiv++) {
if (sdiv % 2 && sdiv != 1)
continue;
fvco = fout * sdiv;
if (fvco < 2000000 || fvco > 4000000)
continue;
mdiv = DIV_ROUND_UP(fvco, fref);
if (mdiv < 20 || mdiv > 255)
continue;
if (fref * mdiv - fvco) {
for (sdc = 264000; sdc <= 750000; sdc += fref)
if (sdc * n > fref * mdiv)
break;
if (sdc > 750000)
continue;
rational_best_approximation(fref * mdiv - fvco,
sdc / 16,
GENMASK(6, 0),
GENMASK(7, 0),
&k, &lc);
rational_best_approximation(sdc * n - fref * mdiv,
sdc,
GENMASK(6, 0),
GENMASK(7, 0),
&k_sub, &lc_sub);
}
break;
}
if (sdiv > 16)
return false;
if (cfg) {
cfg->pms_mdiv = mdiv;
cfg->pms_mdiv_afc = mdiv;
cfg->pms_pdiv = 1;
cfg->pms_refdiv = 1;
cfg->pms_sdiv = sdiv - 1;
cfg->sdm_en = k > 0 ? 1 : 0;
if (cfg->sdm_en) {
cfg->sdm_deno = lc;
cfg->sdm_num_sign = 1;
cfg->sdm_num = k;
cfg->sdc_n = n - 3;
cfg->sdc_num = k_sub;
cfg->sdc_deno = lc_sub;
}
}
return true;
}
static int hdptx_ropll_cmn_config(struct rockchip_hdptx_phy *hdptx, unsigned long bit_rate)
{
int bus_width = phy_get_bus_width(hdptx->phy);
u8 color_depth = (bus_width & COLOR_DEPTH_MASK) ? 1 : 0;
struct ropll_config *cfg = ropll_tmds_cfg;
struct ropll_config rc = {0};
dev_info(hdptx->dev, "%s bus_width:%x rate:%lu\n", __func__, bus_width, bit_rate);
hdptx->rate = bit_rate * 100;
@@ -1138,10 +1211,21 @@ static int hdptx_ropll_cmn_config(struct rockchip_hdptx_phy *hdptx, unsigned lon
break;
if (cfg->bit_rate == ~0) {
dev_err(hdptx->dev, "%s can't find pll cfg\n", __func__);
return -EINVAL;
if (hdptx_phy_clk_pll_calc(bit_rate, &rc)) {
cfg = &rc;
} else {
dev_err(hdptx->dev, "%s can't find pll cfg\n", __func__);
return -EINVAL;
}
}
dev_dbg(hdptx->dev, "mdiv=%u, sdiv=%u\n",
cfg->pms_mdiv, cfg->pms_sdiv + 1);
dev_dbg(hdptx->dev, "sdm_en=%u, k_sign=%u, k=%u, lc=%u",
cfg->sdm_en, cfg->sdm_num_sign, cfg->sdm_num, cfg->sdm_deno);
dev_dbg(hdptx->dev, "n=%u, k_sub=%u, lc_sub=%u\n",
cfg->sdc_n + 3, cfg->sdc_num, cfg->sdc_deno);
hdptx_pre_power_up(hdptx);
reset_control_assert(hdptx->ropll_reset);
@@ -1936,7 +2020,7 @@ static long hdptx_phy_clk_round_rate(struct clk_hw *hw, unsigned long rate,
if (bit_rate == cfg->bit_rate)
break;
if (cfg->bit_rate == ~0)
if (cfg->bit_rate == ~0 && !hdptx_phy_clk_pll_calc(bit_rate, NULL))
return -EINVAL;
return rate;