mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 10:58:48 +09:00
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:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user