From 1543e317f1da31b75942316931e8f491a8920811 Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Thu, 04 Jan 2024 10:08:02 +0000
Subject: [PATCH] disable FB
---
kernel/drivers/phy/rockchip/phy-rockchip-inno-hdmi-phy.c | 311 ++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 304 insertions(+), 7 deletions(-)
diff --git a/kernel/drivers/phy/rockchip/phy-rockchip-inno-hdmi-phy.c b/kernel/drivers/phy/rockchip/phy-rockchip-inno-hdmi-phy.c
index 4bbdc15..23f1e5d 100644
--- a/kernel/drivers/phy/rockchip/phy-rockchip-inno-hdmi-phy.c
+++ b/kernel/drivers/phy/rockchip/phy-rockchip-inno-hdmi-phy.c
@@ -153,7 +153,8 @@
enum inno_hdmi_phy_type {
INNO_HDMI_PHY_RK3228,
- INNO_HDMI_PHY_RK3328
+ INNO_HDMI_PHY_RK3328,
+ INNO_HDMI_PHY_RK3528
};
struct phy_config {
@@ -287,9 +288,13 @@
{33750000, 1, 10, 2, 4},
{74250000, 1, 40, 8, 1},
{74250000, 18, 80, 8, 2},
+ {74250000, 1, 20, 4, 8},
{148500000, 2, 40, 4, 3},
+ {148500000, 1, 10, 2, 8},
{297000000, 4, 40, 2, 3},
+ {297000000, 2, 20, 2, 8},
{594000000, 8, 40, 1, 3},
+ {594000000, 4, 20, 1, 8},
{ ~0UL, 0, 0, 0, 0}
};
@@ -330,6 +335,30 @@
594000000, {
0x10, 0x1a, 0x1a, 0x1a, 0x07, 0x15, 0x08, 0x08, 0x08,
0x00, 0xac, 0xcc, 0xcc, 0xcc,
+ },
+ }, {
+ ~0UL, {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00,
+ },
+ }
+};
+
+static const struct phy_config rk3528_phy_cfg[] = {
+ /* tmdsclk bias-clk bias-data voltage-clk voltage-data pre-emphasis-data */
+ { 165000000, {
+ 0x03, 0x04, 0x0c, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00,
+ },
+ }, {
+ 340000000, {
+ 0x03, 0x04, 0x0c, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00,
+ },
+ }, {
+ 594000000, {
+ 0x02, 0x08, 0x0d, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00,
},
}, {
~0UL, {
@@ -462,6 +491,8 @@
else if (inno->plat_data->dev_type == INNO_HDMI_PHY_RK3228 &&
tmdsclock <= 33750000 && inno->efuse_flag)
chipversion = 4;
+ else if (inno->plat_data->dev_type == INNO_HDMI_PHY_RK3528)
+ chipversion = 8;
for (; cfg->tmdsclock != ~0UL; cfg++)
if (tmdsclock <= cfg->tmdsclock &&
@@ -631,10 +662,17 @@
{
struct device *dev = inno->dev;
struct device_node *np = dev->of_node;
+ struct device_node *clk_np = NULL;
struct clk_init_data init = {};
struct clk *refclk;
const char *parent_name;
int ret;
+
+ if (inno->plat_data->dev_type == INNO_HDMI_PHY_RK3528)
+ clk_np = of_get_child_by_name(np, "clk-port");
+
+ if (!clk_np)
+ clk_np = np;
refclk = devm_clk_get(dev, "refclk");
if (IS_ERR(refclk)) {
@@ -651,7 +689,7 @@
init.ops = &inno_hdmi_phy_clk_ops;
/* optional override of the clock name */
- of_property_read_string(np, "clock-output-names", &init.name);
+ of_property_read_string(clk_np, "clock-output-names", &init.name);
inno->hw.init = &init;
@@ -662,7 +700,7 @@
return ret;
}
- ret = of_clk_add_provider(np, of_clk_src_simple_get, inno->pclk);
+ ret = of_clk_add_provider(clk_np, of_clk_src_simple_get, inno->pclk);
if (ret) {
dev_err(dev, "failed to register OF clock provider: %d\n", ret);
return ret;
@@ -1078,6 +1116,245 @@
return frac;
}
+static int
+inno_hdmi_phy_rk3528_power_on(struct inno_hdmi_phy *inno,
+ const struct post_pll_config *cfg,
+ const struct phy_config *phy_cfg)
+{
+ u32 val;
+ u64 temp;
+
+ /* Power off post PLL */
+ inno_update_bits(inno, 0xaa, 1, 0);
+
+ val = cfg->prediv;
+ inno_write(inno, 0xab, val);
+
+ if (cfg->postdiv == 1) {
+ inno_write(inno, 0xad, 0x8);
+ inno_write(inno, 0xaa, 2);
+ } else {
+ val = (cfg->postdiv / 2) - 1;
+ inno_write(inno, 0xad, val);
+ inno_write(inno, 0xaa, 0x0e);
+ }
+
+ val = cfg->fbdiv & 0xff;
+ inno_write(inno, 0xac, val);
+ val = (cfg->fbdiv >> 8) & BIT(0);
+ inno_update_bits(inno, 0xad, BIT(4), val);
+
+ /* current bias clk/data 2 */
+ val = phy_cfg->regs[0] << 4 | phy_cfg->regs[1];
+ inno_write(inno, 0xbf, val);
+
+ /* current bias data 1/0 */
+ val = phy_cfg->regs[1] << 4 | phy_cfg->regs[1];
+ inno_write(inno, 0xc0, val);
+
+ /* output voltage */
+ inno_write(inno, 0xb5, phy_cfg->regs[2]);
+ inno_write(inno, 0xb6, phy_cfg->regs[3]);
+ inno_write(inno, 0xb7, phy_cfg->regs[3]);
+ inno_write(inno, 0xb8, phy_cfg->regs[3]);
+
+ /* pre-emphasis */
+ inno_write(inno, 0xbb, phy_cfg->regs[4]);
+ inno_write(inno, 0xbc, phy_cfg->regs[4]);
+ inno_write(inno, 0xbd, phy_cfg->regs[4]);
+
+ /* enable LDO */
+ inno_write(inno, 0xb4, 0x7);
+
+ /* enable serializer */
+ inno_write(inno, 0xbe, 0x70);
+
+ inno_write(inno, 0xb2, 0x0f);
+
+ for (val = 0; val < 5; val++) {
+ if (inno_read(inno, 0xaf) & 1)
+ break;
+ udelay(1000);
+ }
+ if (!(inno_read(inno, 0xaf) & 1)) {
+ dev_err(inno->dev, "HDMI PHY Post PLL unlock\n");
+ return -ETIMEDOUT;
+ }
+
+ /* set termination resistance */
+ if (phy_cfg->tmdsclock > 340000000) {
+ inno_write(inno, 0xc7, 0x76);
+ inno_write(inno, 0xc5, 0x83);
+ inno_write(inno, 0xc8, 0x00);
+ inno_write(inno, 0xc9, 0x2f);
+ inno_write(inno, 0xca, 0x2f);
+ inno_write(inno, 0xcb, 0x2f);
+ } else {
+ inno_write(inno, 0xc7, 0x76);
+ inno_write(inno, 0xc5, 0x83);
+ inno_write(inno, 0xc8, 0x00);
+ inno_write(inno, 0xc9, 0x0f);
+ inno_write(inno, 0xca, 0x0f);
+ inno_write(inno, 0xcb, 0x0f);
+ }
+
+ /* set TMDS sync detection counter length */
+ temp = 47520000000;
+ do_div(temp, inno->tmdsclock);
+ inno_write(inno, 0xd8, (temp >> 8) & 0xff);
+ inno_write(inno, 0xd9, temp & 0xff);
+
+ /* Power up post PLL */
+ inno_update_bits(inno, 0xaa, 1, 0);
+ /* Power up tmds driver */
+ inno_update_bits(inno, 0xb0, 4, 4);
+ inno_write(inno, 0xb2, 0x0f);
+
+ if (phy_cfg->tmdsclock > 340000000)
+ msleep(100);
+ /* set pdata_en to 0/1 */
+ inno_update_bits(inno, 0x02, 1, 0);
+ inno_update_bits(inno, 0x02, 1, 1);
+
+ /* Enable PHY IRQ */
+ inno_write(inno, 0x05, 0x22);
+ inno_write(inno, 0x07, 0x22);
+ inno_write(inno, 0xcc, 0x0f);
+
+ return 0;
+}
+
+static void inno_hdmi_phy_rk3528_power_off(struct inno_hdmi_phy *inno)
+{
+ /* Power off driver */
+ inno_write(inno, 0xb2, 0);
+ /* Power off serializer */
+ inno_write(inno, 0xbe, 0);
+ /* Power off post pll */
+ inno_update_bits(inno, 0xaa, 1, 1);
+ /* Power off rxsense detection circuit */
+ inno_write(inno, 0xcc, 0);
+ /* Power off band gap */
+ inno_update_bits(inno, 0xb0, 4, 0);
+ /* Disable PHY IRQ */
+ inno_write(inno, 0x05, 0);
+ inno_write(inno, 0x07, 0);
+}
+
+static void inno_hdmi_phy_rk3528_init(struct inno_hdmi_phy *inno)
+{
+ /*
+ * Use phy internal register control
+ * rxsense/poweron/pllpd/pdataen signal.
+ */
+ inno_write(inno, 0x02, 0x81);
+
+ /* if phy had been set in uboot, pll is locked */
+ if (inno_read(inno, 0xa9) & BIT(0)) {
+ dev_info(inno->dev, "phy had been powered up\n");
+ inno->phy->power_count = 1;
+ } else {
+ /* manual power down post-PLL */
+ inno_hdmi_phy_rk3528_power_off(inno);
+ }
+}
+
+static int
+inno_hdmi_phy_rk3528_pre_pll_update(struct inno_hdmi_phy *inno,
+ const struct pre_pll_config *cfg)
+{
+ u32 val;
+
+ inno_update_bits(inno, 0xb0, 4, 4);
+ inno_write(inno, 0xcc, 0x0f);
+
+ /* Power on PLL */
+ inno_update_bits(inno, 0xa0, 1, 0);
+ /* Configure pre-pll */
+ inno_update_bits(inno, 0xa0, 2, (cfg->vco_div_5_en & 1) << 1);
+ inno_write(inno, 0xa1, cfg->prediv);
+ if (cfg->fracdiv)
+ val = ((cfg->fbdiv >> 8) & 0x0f) | 0xc0;
+ else
+ val = ((cfg->fbdiv >> 8) & 0x0f) | 0xf0;
+ inno_write(inno, 0xa2, val);
+ inno_write(inno, 0xa3, cfg->fbdiv & 0xff);
+ val = (cfg->pclk_div_a & 0x1f) |
+ ((cfg->pclk_div_b & 3) << 5);
+ inno_write(inno, 0xa5, val);
+ val = (cfg->pclk_div_d & 0x1f) |
+ ((cfg->pclk_div_c & 3) << 5);
+ inno_write(inno, 0xa6, val);
+ val = ((cfg->tmds_div_a & 3) << 4) |
+ ((cfg->tmds_div_b & 3) << 2) |
+ (cfg->tmds_div_c & 3);
+ inno_write(inno, 0xa4, val);
+
+ if (cfg->fracdiv) {
+ val = cfg->fracdiv & 0xff;
+ inno_write(inno, 0xd3, val);
+ val = (cfg->fracdiv >> 8) & 0xff;
+ inno_write(inno, 0xd2, val);
+ val = (cfg->fracdiv >> 16) & 0xff;
+ inno_write(inno, 0xd1, val);
+ } else {
+ inno_write(inno, 0xd3, 0);
+ inno_write(inno, 0xd2, 0);
+ inno_write(inno, 0xd1, 0);
+ }
+
+ /* Wait for PLL lock */
+ for (val = 0; val < 5; val++) {
+ if (inno_read(inno, 0xa9) & 1)
+ break;
+ usleep_range(1000, 2000);
+ }
+ if (val == 5) {
+ dev_err(inno->dev, "Pre-PLL unlock\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static unsigned long
+inno_hdmi_rk3528_phy_pll_recalc_rate(struct inno_hdmi_phy *inno,
+ unsigned long parent_rate)
+{
+ unsigned long frac;
+ u8 nd, no_a, no_b, no_d;
+ u16 nf;
+ u64 vco = parent_rate;
+
+ nd = inno_read(inno, 0xa1) & 0x3f;
+ nf = ((inno_read(inno, 0xa2) & 0x0f) << 8) | inno_read(inno, 0xa3);
+ vco *= nf;
+ if ((inno_read(inno, 0xa2) & 0x30) == 0) {
+ frac = inno_read(inno, 0xd3) |
+ (inno_read(inno, 0xd2) << 8) |
+ (inno_read(inno, 0xd1) << 16);
+ vco += DIV_ROUND_CLOSEST(parent_rate * frac, (1 << 24));
+ }
+ if (inno_read(inno, 0xa0) & 2) {
+ do_div(vco, nd * 5);
+ } else {
+ no_a = inno_read(inno, 0xa5) & 0x1f;
+ no_b = ((inno_read(inno, 0xa5) >> 5) & 7) + 2;
+ no_d = inno_read(inno, 0xa6) & 0x1f;
+ if (no_a == 1)
+ do_div(vco, nd * no_b * no_d * 2);
+ else
+ do_div(vco, nd * no_a * no_d * 2);
+ }
+
+ frac = vco;
+ inno->pixclock = DIV_ROUND_CLOSEST(frac, 1000) * 1000;
+
+ dev_dbg(inno->dev, "%s rate %lu\n", __func__, inno->pixclock);
+
+ return frac;
+}
+
static unsigned long
inno_hdmi_rk3228_phy_pll_recalc_rate(struct inno_hdmi_phy *inno,
unsigned long parent_rate)
@@ -1128,6 +1405,14 @@
.recalc_rate = inno_hdmi_rk3328_phy_pll_recalc_rate,
};
+static const struct inno_hdmi_phy_ops rk3528_hdmi_phy_ops = {
+ .init = inno_hdmi_phy_rk3528_init,
+ .power_on = inno_hdmi_phy_rk3528_power_on,
+ .power_off = inno_hdmi_phy_rk3528_power_off,
+ .pre_pll_update = inno_hdmi_phy_rk3528_pre_pll_update,
+ .recalc_rate = inno_hdmi_rk3528_phy_pll_recalc_rate,
+};
+
static const struct inno_hdmi_phy_drv_data rk3228_hdmi_phy_drv_data = {
.dev_type = INNO_HDMI_PHY_RK3228,
.ops = &rk3228_hdmi_phy_ops,
@@ -1140,12 +1425,21 @@
.phy_cfg_table = rk3328_phy_cfg,
};
+static const struct inno_hdmi_phy_drv_data rk3528_hdmi_phy_drv_data = {
+ .dev_type = INNO_HDMI_PHY_RK3528,
+ .ops = &rk3528_hdmi_phy_ops,
+ .phy_cfg_table = rk3528_phy_cfg,
+};
+
static const struct of_device_id inno_hdmi_phy_of_match[] = {
{ .compatible = "rockchip,rk3228-hdmi-phy",
.data = &rk3228_hdmi_phy_drv_data
},
{ .compatible = "rockchip,rk3328-hdmi-phy",
.data = &rk3328_hdmi_phy_drv_data
+ },
+ { .compatible = "rockchip,rk3528-hdmi-phy",
+ .data = &rk3528_hdmi_phy_drv_data
},
{}
};
@@ -1244,13 +1538,15 @@
if (of_get_property(np, "rockchip,phy-table", &val)) {
if (val % PHY_TAB_LEN || !val) {
dev_err(dev, "Invalid phy cfg table format!\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto err_regsmap;
}
phy_config = kmalloc(val, GFP_KERNEL);
if (!phy_config) {
dev_err(dev, "kmalloc phy table failed\n");
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto err_regsmap;
}
phy_table_size = val / PHY_TAB_LEN;
@@ -1259,7 +1555,8 @@
GFP_KERNEL);
if (!inno->phy_cfg) {
kfree(phy_config);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto err_regsmap;
}
of_property_read_u32_array(np, "rockchip,phy-table",
phy_config, val / sizeof(u32));
@@ -1268,7 +1565,7 @@
phy_table_size);
if (ret) {
kfree(phy_config);
- return ret;
+ goto err_regsmap;
}
kfree(phy_config);
} else {
--
Gitblit v1.6.2