mirror of
https://github.com/Fishwaldo/build.git
synced 2025-07-23 13:29:33 +00:00
Removed default-sample-phase property for base rk322x-box device tree Enabled spdif out for rk322x-current and -dev flavours Removed reserved node in device tree, u-boot v2020.10 and OPTEE autoconfigure reserved zones automatically
5389 lines
180 KiB
Diff
5389 lines
180 KiB
Diff
From dd7efcfd32481cecf647067cedd23c1d799daead Mon Sep 17 00:00:00 2001
|
|
From: Jonas Karlman <jonas@kwiboo.se>
|
|
Date: Wed, 8 Jan 2020 21:07:47 +0000
|
|
Subject: [PATCH] phy/rockchip: inno-hdmi: use correct vco_div_5 macro on
|
|
rk3328
|
|
|
|
inno_hdmi_phy_rk3328_clk_set_rate() is using the RK3228 macro
|
|
when configuring vco_div_5 on RK3328.
|
|
|
|
Fix this by using correct vco_div_5 macro for RK3328.
|
|
|
|
Fixes: 53706a116863 ("phy: add Rockchip Innosilicon hdmi phy")
|
|
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
|
---
|
|
drivers/phy/rockchip/phy-rockchip-inno-hdmi.c | 4 ++--
|
|
1 file changed, 2 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
|
|
index b1a9ff0131eb..f784408926d6 100644
|
|
--- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
|
|
+++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
|
|
@@ -797,8 +797,8 @@ static int inno_hdmi_phy_rk3328_clk_set_rate(struct clk_hw *hw,
|
|
RK3328_PRE_PLL_POWER_DOWN);
|
|
|
|
/* Configure pre-pll */
|
|
- inno_update_bits(inno, 0xa0, RK3228_PCLK_VCO_DIV_5_MASK,
|
|
- RK3228_PCLK_VCO_DIV_5(cfg->vco_div_5_en));
|
|
+ inno_update_bits(inno, 0xa0, RK3328_PCLK_VCO_DIV_5_MASK,
|
|
+ RK3328_PCLK_VCO_DIV_5(cfg->vco_div_5_en));
|
|
inno_write(inno, 0xa1, RK3328_PRE_PLL_PRE_DIV(cfg->prediv));
|
|
|
|
val = RK3328_SPREAD_SPECTRUM_MOD_DISABLE;
|
|
|
|
From 3b35058e573c01959e413e4899f3c6a6be8058da Mon Sep 17 00:00:00 2001
|
|
From: Zheng Yang <zhengyang@rock-chips.com>
|
|
Date: Wed, 8 Jan 2020 21:07:48 +0000
|
|
Subject: [PATCH] phy/rockchip: inno-hdmi: round fractal pixclock in rk3328
|
|
recalc_rate
|
|
|
|
inno_hdmi_phy_rk3328_clk_recalc_rate() is returning a rate not found
|
|
in the pre pll config table when the fractal divider is used.
|
|
This can prevent proper power_on because a tmdsclock for the new rate
|
|
is not found in the pre pll config table.
|
|
|
|
Fix this by saving and returning a rounded pixel rate that exist
|
|
in the pre pll config table.
|
|
|
|
Fixes: 53706a116863 ("phy: add Rockchip Innosilicon hdmi phy")
|
|
Signed-off-by: Zheng Yang <zhengyang@rock-chips.com>
|
|
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
|
---
|
|
drivers/phy/rockchip/phy-rockchip-inno-hdmi.c | 8 +++++---
|
|
1 file changed, 5 insertions(+), 3 deletions(-)
|
|
|
|
diff --git a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
|
|
index f784408926d6..4f000942c824 100644
|
|
--- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
|
|
+++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
|
|
@@ -752,10 +752,12 @@ unsigned long inno_hdmi_phy_rk3328_clk_recalc_rate(struct clk_hw *hw,
|
|
do_div(vco, (nd * (no_a == 1 ? no_b : no_a) * no_d * 2));
|
|
}
|
|
|
|
- inno->pixclock = vco;
|
|
- dev_dbg(inno->dev, "%s rate %lu\n", __func__, inno->pixclock);
|
|
+ inno->pixclock = DIV_ROUND_CLOSEST((unsigned long)vco, 1000) * 1000;
|
|
|
|
- return vco;
|
|
+ dev_dbg(inno->dev, "%s rate %lu vco %llu\n",
|
|
+ __func__, inno->pixclock, vco);
|
|
+
|
|
+ return inno->pixclock;
|
|
}
|
|
|
|
static long inno_hdmi_phy_rk3328_clk_round_rate(struct clk_hw *hw,
|
|
|
|
From 893babbe917db2895ead295b8897c74f40396afe Mon Sep 17 00:00:00 2001
|
|
From: Jonas Karlman <jonas@kwiboo.se>
|
|
Date: Wed, 8 Jan 2020 21:07:48 +0000
|
|
Subject: [PATCH] phy/rockchip: inno-hdmi: remove unused no_c from rk3328
|
|
recalc_rate
|
|
|
|
no_c is not used in any calculation, lets remove it.
|
|
|
|
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
|
---
|
|
drivers/phy/rockchip/phy-rockchip-inno-hdmi.c | 5 +----
|
|
1 file changed, 1 insertion(+), 4 deletions(-)
|
|
|
|
diff --git a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
|
|
index 4f000942c824..05a5362c1f73 100644
|
|
--- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
|
|
+++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
|
|
@@ -721,7 +721,7 @@ unsigned long inno_hdmi_phy_rk3328_clk_recalc_rate(struct clk_hw *hw,
|
|
{
|
|
struct inno_hdmi_phy *inno = to_inno_hdmi_phy(hw);
|
|
unsigned long frac;
|
|
- u8 nd, no_a, no_b, no_c, no_d;
|
|
+ u8 nd, no_a, no_b, no_d;
|
|
u64 vco;
|
|
u16 nf;
|
|
|
|
@@ -744,9 +744,6 @@ unsigned long inno_hdmi_phy_rk3328_clk_recalc_rate(struct clk_hw *hw,
|
|
no_b = inno_read(inno, 0xa5) & RK3328_PRE_PLL_PCLK_DIV_B_MASK;
|
|
no_b >>= RK3328_PRE_PLL_PCLK_DIV_B_SHIFT;
|
|
no_b += 2;
|
|
- no_c = inno_read(inno, 0xa6) & RK3328_PRE_PLL_PCLK_DIV_C_MASK;
|
|
- no_c >>= RK3328_PRE_PLL_PCLK_DIV_C_SHIFT;
|
|
- no_c = 1 << no_c;
|
|
no_d = inno_read(inno, 0xa6) & RK3328_PRE_PLL_PCLK_DIV_D_MASK;
|
|
|
|
do_div(vco, (nd * (no_a == 1 ? no_b : no_a) * no_d * 2));
|
|
|
|
From 8674a04f14c6bb56b84dcf934f4f921c213e62e5 Mon Sep 17 00:00:00 2001
|
|
From: Jonas Karlman <jonas@kwiboo.se>
|
|
Date: Wed, 8 Jan 2020 21:07:48 +0000
|
|
Subject: [PATCH] phy/rockchip: inno-hdmi: do not power on rk3328 post pll on
|
|
reg write
|
|
|
|
inno_write is used to configure 0xaa reg, that also hold the
|
|
POST_PLL_POWER_DOWN bit.
|
|
When POST_PLL_REFCLK_SEL_TMDS is configured the power down bit is not
|
|
taken into consideration.
|
|
|
|
Fix this by keeping the power down bit until configuration is complete.
|
|
Also reorder the reg write order for consistency.
|
|
|
|
Fixes: 53706a116863 ("phy: add Rockchip Innosilicon hdmi phy")
|
|
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
|
---
|
|
drivers/phy/rockchip/phy-rockchip-inno-hdmi.c | 6 ++++--
|
|
1 file changed, 4 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
|
|
index 05a5362c1f73..5e07346af27c 100644
|
|
--- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
|
|
+++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
|
|
@@ -1054,9 +1054,10 @@ inno_hdmi_phy_rk3328_power_on(struct inno_hdmi_phy *inno,
|
|
|
|
inno_write(inno, 0xac, RK3328_POST_PLL_FB_DIV_7_0(cfg->fbdiv));
|
|
if (cfg->postdiv == 1) {
|
|
- inno_write(inno, 0xaa, RK3328_POST_PLL_REFCLK_SEL_TMDS);
|
|
inno_write(inno, 0xab, RK3328_POST_PLL_FB_DIV_8(cfg->fbdiv) |
|
|
RK3328_POST_PLL_PRE_DIV(cfg->prediv));
|
|
+ inno_write(inno, 0xaa, RK3328_POST_PLL_REFCLK_SEL_TMDS |
|
|
+ RK3328_POST_PLL_POWER_DOWN);
|
|
} else {
|
|
v = (cfg->postdiv / 2) - 1;
|
|
v &= RK3328_POST_PLL_POST_DIV_MASK;
|
|
@@ -1064,7 +1065,8 @@ inno_hdmi_phy_rk3328_power_on(struct inno_hdmi_phy *inno,
|
|
inno_write(inno, 0xab, RK3328_POST_PLL_FB_DIV_8(cfg->fbdiv) |
|
|
RK3328_POST_PLL_PRE_DIV(cfg->prediv));
|
|
inno_write(inno, 0xaa, RK3328_POST_PLL_POST_DIV_ENABLE |
|
|
- RK3328_POST_PLL_REFCLK_SEL_TMDS);
|
|
+ RK3328_POST_PLL_REFCLK_SEL_TMDS |
|
|
+ RK3328_POST_PLL_POWER_DOWN);
|
|
}
|
|
|
|
for (v = 0; v < 14; v++)
|
|
|
|
From e6e89b9198928abb1fc417985cce8000b2e55839 Mon Sep 17 00:00:00 2001
|
|
From: Huicong Xu <xhc@rock-chips.com>
|
|
Date: Wed, 8 Jan 2020 21:07:49 +0000
|
|
Subject: [PATCH] phy/rockchip: inno-hdmi: force set_rate on power_on
|
|
|
|
Regular 8-bit and Deep Color video formats mainly differ in TMDS rate and
|
|
not in pixel clock rate.
|
|
When the hdmiphy clock is configured with the same pixel clock rate using
|
|
clk_set_rate() the clock framework do not signal the hdmi phy driver
|
|
to set_rate when switching between 8-bit and Deep Color.
|
|
This result in pre/post pll not being re-configured when switching between
|
|
regular 8-bit and Deep Color video formats.
|
|
|
|
Fix this by calling set_rate in power_on to force pre pll re-configuration.
|
|
|
|
Signed-off-by: Huicong Xu <xhc@rock-chips.com>
|
|
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
|
---
|
|
drivers/phy/rockchip/phy-rockchip-inno-hdmi.c | 13 +++++++++++++
|
|
1 file changed, 13 insertions(+)
|
|
|
|
diff --git a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
|
|
index 5e07346af27c..29e9a1c1e76b 100644
|
|
--- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
|
|
+++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
|
|
@@ -248,6 +248,7 @@ struct inno_hdmi_phy {
|
|
struct clk_hw hw;
|
|
struct clk *phyclk;
|
|
unsigned long pixclock;
|
|
+ unsigned long tmdsclock;
|
|
};
|
|
|
|
struct pre_pll_config {
|
|
@@ -492,6 +493,8 @@ static int inno_hdmi_phy_power_on(struct phy *phy)
|
|
|
|
dev_dbg(inno->dev, "Inno HDMI PHY Power On\n");
|
|
|
|
+ inno->plat_data->clk_ops->set_rate(&inno->hw, inno->pixclock, 24000000);
|
|
+
|
|
ret = clk_prepare_enable(inno->phyclk);
|
|
if (ret)
|
|
return ret;
|
|
@@ -516,6 +519,8 @@ static int inno_hdmi_phy_power_off(struct phy *phy)
|
|
|
|
clk_disable_unprepare(inno->phyclk);
|
|
|
|
+ inno->tmdsclock = 0;
|
|
+
|
|
dev_dbg(inno->dev, "Inno HDMI PHY Power Off\n");
|
|
|
|
return 0;
|
|
@@ -635,6 +640,9 @@ static int inno_hdmi_phy_rk3228_clk_set_rate(struct clk_hw *hw,
|
|
dev_dbg(inno->dev, "%s rate %lu tmdsclk %lu\n",
|
|
__func__, rate, tmdsclock);
|
|
|
|
+ if (inno->pixclock == rate && inno->tmdsclock == tmdsclock)
|
|
+ return 0;
|
|
+
|
|
cfg = inno_hdmi_phy_get_pre_pll_cfg(inno, rate);
|
|
if (IS_ERR(cfg))
|
|
return PTR_ERR(cfg);
|
|
@@ -677,6 +685,7 @@ static int inno_hdmi_phy_rk3228_clk_set_rate(struct clk_hw *hw,
|
|
}
|
|
|
|
inno->pixclock = rate;
|
|
+ inno->tmdsclock = tmdsclock;
|
|
|
|
return 0;
|
|
}
|
|
@@ -788,6 +797,9 @@ static int inno_hdmi_phy_rk3328_clk_set_rate(struct clk_hw *hw,
|
|
dev_dbg(inno->dev, "%s rate %lu tmdsclk %lu\n",
|
|
__func__, rate, tmdsclock);
|
|
|
|
+ if (inno->pixclock == rate && inno->tmdsclock == tmdsclock)
|
|
+ return 0;
|
|
+
|
|
cfg = inno_hdmi_phy_get_pre_pll_cfg(inno, rate);
|
|
if (IS_ERR(cfg))
|
|
return PTR_ERR(cfg);
|
|
@@ -827,6 +839,7 @@ static int inno_hdmi_phy_rk3328_clk_set_rate(struct clk_hw *hw,
|
|
}
|
|
|
|
inno->pixclock = rate;
|
|
+ inno->tmdsclock = tmdsclock;
|
|
|
|
return 0;
|
|
}
|
|
|
|
From 43a9498fb30c743d2afe70b9d39f561910ddcb5b Mon Sep 17 00:00:00 2001
|
|
From: Algea Cao <algea.cao@rock-chips.com>
|
|
Date: Wed, 8 Jan 2020 21:07:53 +0000
|
|
Subject: [PATCH] phy/rockchip: inno-hdmi: Support more pre-pll configuration
|
|
|
|
Adding the following freq cfg in 8-bit and 10-bit color depth:
|
|
|
|
{
|
|
40000000, 65000000, 71000000, 83500000, 85750000,
|
|
88750000, 108000000, 119000000, 162000000
|
|
}
|
|
|
|
New freq has been validated by quantumdata 980.
|
|
|
|
For some freq which can't be got by only using integer freq div,
|
|
frac freq div is needed, Such as 88.75Mhz 10-bit. But The actual
|
|
freq is different from the target freq, We must try to narrow
|
|
the gap between them. RK322X only support integer freq div.
|
|
|
|
The VCO of pre-PLL must be more than 2Ghz, otherwise PLL may be
|
|
unlocked.
|
|
|
|
Signed-off-by: Algea Cao <algea.cao@rock-chips.com>
|
|
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
|
Acked-by: Heiko Stuebner <heiko@sntech.de>
|
|
---
|
|
drivers/phy/rockchip/phy-rockchip-inno-hdmi.c | 74 ++++++++++++-------
|
|
1 file changed, 49 insertions(+), 25 deletions(-)
|
|
|
|
diff --git a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
|
|
index 29e9a1c1e76b..0c7a97352714 100644
|
|
--- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
|
|
+++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
|
|
@@ -294,32 +294,56 @@ struct inno_hdmi_phy_drv_data {
|
|
const struct phy_config *phy_cfg_table;
|
|
};
|
|
|
|
+/*
|
|
+ * If only using integer freq div can't get frequency we want, frac
|
|
+ * freq div is needed. For example, pclk 88.75 Mhz and tmdsclk
|
|
+ * 110.9375 Mhz must use frac div 0xF00000. The actual frequency is different
|
|
+ * from the target frequency. Such as the tmds clock 110.9375 Mhz,
|
|
+ * the actual tmds clock we get is 110.93719 Mhz. It is important
|
|
+ * to note that RK322X platforms do not support frac div.
|
|
+ */
|
|
static const struct pre_pll_config pre_pll_cfg_table[] = {
|
|
- { 27000000, 27000000, 1, 90, 3, 2, 2, 10, 3, 3, 4, 0, 0},
|
|
- { 27000000, 33750000, 1, 90, 1, 3, 3, 10, 3, 3, 4, 0, 0},
|
|
- { 40000000, 40000000, 1, 80, 2, 2, 2, 12, 2, 2, 2, 0, 0},
|
|
- { 59341000, 59341000, 1, 98, 3, 1, 2, 1, 3, 3, 4, 0, 0xE6AE6B},
|
|
- { 59400000, 59400000, 1, 99, 3, 1, 1, 1, 3, 3, 4, 0, 0},
|
|
- { 59341000, 74176250, 1, 98, 0, 3, 3, 1, 3, 3, 4, 0, 0xE6AE6B},
|
|
- { 59400000, 74250000, 1, 99, 1, 2, 2, 1, 3, 3, 4, 0, 0},
|
|
- { 74176000, 74176000, 1, 98, 1, 2, 2, 1, 2, 3, 4, 0, 0xE6AE6B},
|
|
- { 74250000, 74250000, 1, 99, 1, 2, 2, 1, 2, 3, 4, 0, 0},
|
|
- { 74176000, 92720000, 4, 494, 1, 2, 2, 1, 3, 3, 4, 0, 0x816817},
|
|
- { 74250000, 92812500, 4, 495, 1, 2, 2, 1, 3, 3, 4, 0, 0},
|
|
- {148352000, 148352000, 1, 98, 1, 1, 1, 1, 2, 2, 2, 0, 0xE6AE6B},
|
|
- {148500000, 148500000, 1, 99, 1, 1, 1, 1, 2, 2, 2, 0, 0},
|
|
- {148352000, 185440000, 4, 494, 0, 2, 2, 1, 3, 2, 2, 0, 0x816817},
|
|
- {148500000, 185625000, 4, 495, 0, 2, 2, 1, 3, 2, 2, 0, 0},
|
|
- {296703000, 296703000, 1, 98, 0, 1, 1, 1, 0, 2, 2, 0, 0xE6AE6B},
|
|
- {297000000, 297000000, 1, 99, 0, 1, 1, 1, 0, 2, 2, 0, 0},
|
|
- {296703000, 370878750, 4, 494, 1, 2, 0, 1, 3, 1, 1, 0, 0x816817},
|
|
- {297000000, 371250000, 4, 495, 1, 2, 0, 1, 3, 1, 1, 0, 0},
|
|
- {593407000, 296703500, 1, 98, 0, 1, 1, 1, 0, 2, 1, 0, 0xE6AE6B},
|
|
- {594000000, 297000000, 1, 99, 0, 1, 1, 1, 0, 2, 1, 0, 0},
|
|
- {593407000, 370879375, 4, 494, 1, 2, 0, 1, 3, 1, 1, 1, 0x816817},
|
|
- {594000000, 371250000, 4, 495, 1, 2, 0, 1, 3, 1, 1, 1, 0},
|
|
- {593407000, 593407000, 1, 98, 0, 2, 0, 1, 0, 1, 1, 0, 0xE6AE6B},
|
|
- {594000000, 594000000, 1, 99, 0, 2, 0, 1, 0, 1, 1, 0, 0},
|
|
+ { 27000000, 27000000, 1, 90, 3, 2, 2, 10, 3, 3, 4, 0, 0},
|
|
+ { 27000000, 33750000, 1, 90, 1, 3, 3, 10, 3, 3, 4, 0, 0},
|
|
+ { 40000000, 40000000, 1, 80, 2, 2, 2, 12, 2, 2, 2, 0, 0},
|
|
+ { 40000000, 50000000, 1, 100, 2, 2, 2, 1, 0, 0, 15, 0, 0},
|
|
+ { 59341000, 59341000, 1, 98, 3, 1, 2, 1, 3, 3, 4, 0, 0xE6AE6B},
|
|
+ { 59400000, 59400000, 1, 99, 3, 1, 1, 1, 3, 3, 4, 0, 0},
|
|
+ { 59341000, 74176250, 1, 98, 0, 3, 3, 1, 3, 3, 4, 0, 0xE6AE6B},
|
|
+ { 59400000, 74250000, 1, 99, 1, 2, 2, 1, 3, 3, 4, 0, 0},
|
|
+ { 65000000, 65000000, 1, 130, 2, 2, 2, 1, 0, 0, 12, 0, 0},
|
|
+ { 65000000, 81250000, 3, 325, 0, 3, 3, 1, 0, 0, 10, 0, 0},
|
|
+ { 71000000, 71000000, 3, 284, 0, 3, 3, 1, 0, 0, 8, 0, 0},
|
|
+ { 71000000, 88750000, 3, 355, 0, 3, 3, 1, 0, 0, 10, 0, 0},
|
|
+ { 74176000, 74176000, 1, 98, 1, 2, 2, 1, 2, 3, 4, 0, 0xE6AE6B},
|
|
+ { 74250000, 74250000, 1, 99, 1, 2, 2, 1, 2, 3, 4, 0, 0},
|
|
+ { 74176000, 92720000, 4, 494, 1, 2, 2, 1, 3, 3, 4, 0, 0x816817},
|
|
+ { 74250000, 92812500, 4, 495, 1, 2, 2, 1, 3, 3, 4, 0, 0},
|
|
+ { 83500000, 83500000, 2, 167, 2, 1, 1, 1, 0, 0, 6, 0, 0},
|
|
+ { 83500000, 104375000, 1, 104, 2, 1, 1, 1, 1, 0, 5, 0, 0x600000},
|
|
+ { 85750000, 85750000, 3, 343, 0, 3, 3, 1, 0, 0, 8, 0, 0},
|
|
+ { 88750000, 88750000, 3, 355, 0, 3, 3, 1, 0, 0, 8, 0, 0},
|
|
+ { 88750000, 110937500, 1, 110, 2, 1, 1, 1, 1, 0, 5, 0, 0xF00000},
|
|
+ {108000000, 108000000, 1, 90, 3, 0, 0, 1, 0, 0, 5, 0, 0},
|
|
+ {108000000, 135000000, 1, 90, 0, 2, 2, 1, 0, 0, 5, 0, 0},
|
|
+ {119000000, 119000000, 1, 119, 2, 1, 1, 1, 0, 0, 6, 0, 0},
|
|
+ {119000000, 148750000, 1, 99, 0, 2, 2, 1, 0, 0, 5, 0, 0x2AAAAA},
|
|
+ {148352000, 148352000, 1, 98, 1, 1, 1, 1, 2, 2, 2, 0, 0xE6AE6B},
|
|
+ {148500000, 148500000, 1, 99, 1, 1, 1, 1, 2, 2, 2, 0, 0},
|
|
+ {148352000, 185440000, 4, 494, 0, 2, 2, 1, 3, 2, 2, 0, 0x816817},
|
|
+ {148500000, 185625000, 4, 495, 0, 2, 2, 1, 3, 2, 2, 0, 0},
|
|
+ {162000000, 162000000, 1, 108, 0, 2, 2, 1, 0, 0, 4, 0, 0},
|
|
+ {162000000, 202500000, 1, 135, 0, 2, 2, 1, 0, 0, 5, 0, 0},
|
|
+ {296703000, 296703000, 1, 98, 0, 1, 1, 1, 0, 2, 2, 0, 0xE6AE6B},
|
|
+ {297000000, 297000000, 1, 99, 0, 1, 1, 1, 0, 2, 2, 0, 0},
|
|
+ {296703000, 370878750, 4, 494, 1, 2, 0, 1, 3, 1, 1, 0, 0x816817},
|
|
+ {297000000, 371250000, 4, 495, 1, 2, 0, 1, 3, 1, 1, 0, 0},
|
|
+ {593407000, 296703500, 1, 98, 0, 1, 1, 1, 0, 2, 1, 0, 0xE6AE6B},
|
|
+ {594000000, 297000000, 1, 99, 0, 1, 1, 1, 0, 2, 1, 0, 0},
|
|
+ {593407000, 370879375, 4, 494, 1, 2, 0, 1, 3, 1, 1, 1, 0x816817},
|
|
+ {594000000, 371250000, 4, 495, 1, 2, 0, 1, 3, 1, 1, 1, 0},
|
|
+ {593407000, 593407000, 1, 98, 0, 2, 0, 1, 0, 1, 1, 0, 0xE6AE6B},
|
|
+ {594000000, 594000000, 1, 99, 0, 2, 0, 1, 0, 1, 1, 0, 0},
|
|
{ /* sentinel */ }
|
|
};
|
|
|
|
|
|
From d9dca0f6a52f6d013240398187c4460600abcdf4 Mon Sep 17 00:00:00 2001
|
|
From: Jonas Karlman <jonas@kwiboo.se>
|
|
Date: Sun, 3 May 2020 16:51:31 +0000
|
|
Subject: [PATCH] drm/rockchip: vop: filter modes outside 0.5% pixel clock
|
|
tolerance
|
|
|
|
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
|
---
|
|
drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 33 +++++++++++++++++++++
|
|
1 file changed, 33 insertions(+)
|
|
|
|
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
|
|
index c80f7d9fd13f..6cbdb4672a4b 100644
|
|
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
|
|
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
|
|
@@ -1142,6 +1142,38 @@ static void vop_crtc_disable_vblank(struct drm_crtc *crtc)
|
|
spin_unlock_irqrestore(&vop->irq_lock, flags);
|
|
}
|
|
|
|
+/*
|
|
+ * The VESA DMT standard specifies a 0.5% pixel clock frequency tolerance.
|
|
+ * The CVT spec reuses that tolerance in its examples.
|
|
+ */
|
|
+#define CLOCK_TOLERANCE_PER_MILLE 5
|
|
+
|
|
+static enum drm_mode_status vop_crtc_mode_valid(struct drm_crtc *crtc,
|
|
+ const struct drm_display_mode *mode)
|
|
+{
|
|
+ struct vop *vop = to_vop(crtc);
|
|
+ struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc->state);
|
|
+ long rounded_rate;
|
|
+ long lowest, highest;
|
|
+
|
|
+ if (s->output_type != DRM_MODE_CONNECTOR_HDMIA)
|
|
+ return MODE_OK;
|
|
+
|
|
+ rounded_rate = clk_round_rate(vop->dclk, mode->clock * 1000 + 999);
|
|
+ if (rounded_rate < 0)
|
|
+ return MODE_NOCLOCK;
|
|
+
|
|
+ lowest = mode->clock * (1000 - CLOCK_TOLERANCE_PER_MILLE);
|
|
+ if (rounded_rate < lowest)
|
|
+ return MODE_CLOCK_LOW;
|
|
+
|
|
+ highest = mode->clock * (1000 + CLOCK_TOLERANCE_PER_MILLE);
|
|
+ if (rounded_rate > highest)
|
|
+ return MODE_CLOCK_HIGH;
|
|
+
|
|
+ return MODE_OK;
|
|
+}
|
|
+
|
|
static bool vop_crtc_mode_fixup(struct drm_crtc *crtc,
|
|
const struct drm_display_mode *mode,
|
|
struct drm_display_mode *adjusted_mode)
|
|
@@ -1512,6 +1544,7 @@ static void vop_crtc_atomic_flush(struct drm_crtc *crtc,
|
|
}
|
|
|
|
static const struct drm_crtc_helper_funcs vop_crtc_helper_funcs = {
|
|
+ .mode_valid = vop_crtc_mode_valid,
|
|
.mode_fixup = vop_crtc_mode_fixup,
|
|
.atomic_check = vop_crtc_atomic_check,
|
|
.atomic_begin = vop_crtc_atomic_begin,
|
|
|
|
From b6030ac943d755d31b69c658f498999875a0a46d Mon Sep 17 00:00:00 2001
|
|
From: Jonas Karlman <jonas@kwiboo.se>
|
|
Date: Mon, 20 Jul 2020 11:46:16 +0000
|
|
Subject: [PATCH] WIP: drm/rockchip: vop: max_output
|
|
|
|
---
|
|
drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 5 +++++
|
|
drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 6 ++++++
|
|
drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 7 +++++++
|
|
3 files changed, 18 insertions(+)
|
|
|
|
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
|
|
index 6cbdb4672a4b..106b38ea12df 100644
|
|
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
|
|
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
|
|
@@ -1152,6 +1152,7 @@ static enum drm_mode_status vop_crtc_mode_valid(struct drm_crtc *crtc,
|
|
const struct drm_display_mode *mode)
|
|
{
|
|
struct vop *vop = to_vop(crtc);
|
|
+ const struct vop_rect *max_output = &vop->data->max_output;
|
|
struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc->state);
|
|
long rounded_rate;
|
|
long lowest, highest;
|
|
@@ -1171,6 +1172,10 @@ static enum drm_mode_status vop_crtc_mode_valid(struct drm_crtc *crtc,
|
|
if (rounded_rate > highest)
|
|
return MODE_CLOCK_HIGH;
|
|
|
|
+ if (max_output->width && max_output->height)
|
|
+ return drm_mode_validate_size(mode, max_output->width,
|
|
+ max_output->height);
|
|
+
|
|
return MODE_OK;
|
|
}
|
|
|
|
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
|
|
index 4a2099cb582e..1516231bbf93 100644
|
|
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
|
|
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
|
|
@@ -185,6 +185,11 @@ struct vop_win_data {
|
|
enum drm_plane_type type;
|
|
};
|
|
|
|
+struct vop_rect {
|
|
+ int width;
|
|
+ int height;
|
|
+};
|
|
+
|
|
struct vop_data {
|
|
uint32_t version;
|
|
const struct vop_intr *intr;
|
|
@@ -197,6 +202,7 @@ struct vop_data {
|
|
const struct vop_win_data *win;
|
|
unsigned int win_size;
|
|
unsigned int lut_size;
|
|
+ struct vop_rect max_output;
|
|
|
|
#define VOP_FEATURE_OUTPUT_RGB10 BIT(0)
|
|
#define VOP_FEATURE_INTERNAL_RGB BIT(1)
|
|
diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
|
|
index 80053d91a301..57c36e9207c1 100644
|
|
--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
|
|
+++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
|
|
@@ -682,6 +682,7 @@ static const struct vop_intr rk3288_vop_intr = {
|
|
static const struct vop_data rk3288_vop = {
|
|
.version = VOP_VERSION(3, 1),
|
|
.feature = VOP_FEATURE_OUTPUT_RGB10,
|
|
+ .max_output = { 3840, 2160 },
|
|
.intr = &rk3288_vop_intr,
|
|
.common = &rk3288_common,
|
|
.modeset = &rk3288_modeset,
|
|
@@ -782,6 +783,7 @@ static const struct vop_misc rk3368_misc = {
|
|
|
|
static const struct vop_data rk3368_vop = {
|
|
.version = VOP_VERSION(3, 2),
|
|
+ .max_output = { 4096, 2160 },
|
|
.intr = &rk3368_vop_intr,
|
|
.common = &rk3288_common,
|
|
.modeset = &rk3288_modeset,
|
|
@@ -803,6 +805,7 @@ static const struct vop_intr rk3366_vop_intr = {
|
|
|
|
static const struct vop_data rk3366_vop = {
|
|
.version = VOP_VERSION(3, 4),
|
|
+ .max_output = { 4096, 2160 },
|
|
.intr = &rk3366_vop_intr,
|
|
.common = &rk3288_common,
|
|
.modeset = &rk3288_modeset,
|
|
@@ -909,6 +912,7 @@ static const struct vop_afbc rk3399_vop_afbc = {
|
|
static const struct vop_data rk3399_vop_big = {
|
|
.version = VOP_VERSION(3, 5),
|
|
.feature = VOP_FEATURE_OUTPUT_RGB10,
|
|
+ .max_output = { 4096, 2160 },
|
|
.intr = &rk3366_vop_intr,
|
|
.common = &rk3288_common,
|
|
.modeset = &rk3288_modeset,
|
|
@@ -935,6 +939,7 @@ static const struct vop_win_yuv2yuv_data rk3399_vop_lit_win_yuv2yuv_data[] = {
|
|
|
|
static const struct vop_data rk3399_vop_lit = {
|
|
.version = VOP_VERSION(3, 6),
|
|
+ .max_output = { 2560, 1600 },
|
|
.intr = &rk3366_vop_intr,
|
|
.common = &rk3288_common,
|
|
.modeset = &rk3288_modeset,
|
|
@@ -955,6 +960,7 @@ static const struct vop_win_data rk3228_vop_win_data[] = {
|
|
static const struct vop_data rk3228_vop = {
|
|
.version = VOP_VERSION(3, 7),
|
|
.feature = VOP_FEATURE_OUTPUT_RGB10,
|
|
+ .max_output = { 4096, 2160 },
|
|
.intr = &rk3366_vop_intr,
|
|
.common = &rk3288_common,
|
|
.modeset = &rk3288_modeset,
|
|
@@ -1026,6 +1032,7 @@ static const struct vop_win_data rk3328_vop_win_data[] = {
|
|
static const struct vop_data rk3328_vop = {
|
|
.version = VOP_VERSION(3, 8),
|
|
.feature = VOP_FEATURE_OUTPUT_RGB10,
|
|
+ .max_output = { 4096, 2160 },
|
|
.intr = &rk3328_vop_intr,
|
|
.common = &rk3328_common,
|
|
.modeset = &rk3328_modeset,
|
|
|
|
From 7c8b58413c38c263e4a9103281a214cb3a2db69c Mon Sep 17 00:00:00 2001
|
|
From: Jonas Karlman <jonas@kwiboo.se>
|
|
Date: Wed, 8 Jan 2020 21:07:51 +0000
|
|
Subject: [PATCH] arm64: dts: rockchip: increase vop clock rate on rk3328
|
|
|
|
The VOP on RK3328 needs to run at higher rate in order to
|
|
produce a proper 3840x2160 signal.
|
|
|
|
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
|
---
|
|
arch/arm64/boot/dts/rockchip/rk3328.dtsi | 4 ++--
|
|
1 file changed, 2 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/arch/arm64/boot/dts/rockchip/rk3328.dtsi b/arch/arm64/boot/dts/rockchip/rk3328.dtsi
|
|
index bbdb19a3e85d..6547e2b4b617 100644
|
|
--- a/arch/arm64/boot/dts/rockchip/rk3328.dtsi
|
|
+++ b/arch/arm64/boot/dts/rockchip/rk3328.dtsi
|
|
@@ -802,8 +802,8 @@ cru: clock-controller@ff440000 {
|
|
<0>, <24000000>,
|
|
<24000000>, <24000000>,
|
|
<15000000>, <15000000>,
|
|
- <100000000>, <100000000>,
|
|
- <100000000>, <100000000>,
|
|
+ <300000000>, <100000000>,
|
|
+ <400000000>, <100000000>,
|
|
<50000000>, <100000000>,
|
|
<100000000>, <100000000>,
|
|
<50000000>, <50000000>,
|
|
|
|
From b6d211f4b212569724efed3c9eaaf06615268d61 Mon Sep 17 00:00:00 2001
|
|
From: Jonas Karlman <jonas@kwiboo.se>
|
|
Date: Wed, 8 Jan 2020 21:07:49 +0000
|
|
Subject: [PATCH] drm/rockchip: dw-hdmi: allow high tmds bit rates
|
|
|
|
Prepare support for High TMDS Bit Rates used by HDMI2.0 display modes.
|
|
|
|
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
|
---
|
|
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 2 ++
|
|
1 file changed, 2 insertions(+)
|
|
|
|
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
|
index 23de359a1dec..cdf953850873 100644
|
|
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
|
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
|
@@ -317,6 +317,8 @@ static int dw_hdmi_rockchip_genphy_init(struct dw_hdmi *dw_hdmi, void *data,
|
|
{
|
|
struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
|
|
|
|
+ dw_hdmi_set_high_tmds_clock_ratio(dw_hdmi, display);
|
|
+
|
|
return phy_power_on(hdmi->phy);
|
|
}
|
|
|
|
|
|
From 1efdc8bf4ab51829d5b086f6bc45e7f02da1170c Mon Sep 17 00:00:00 2001
|
|
From: Yakir Yang <ykk@rock-chips.com>
|
|
Date: Mon, 11 Jul 2016 19:05:39 +0800
|
|
Subject: [PATCH] drm/rockchip: dw_hdmi: adjust cklvl & txlvl for RF/EMI
|
|
|
|
Dut to the high HDMI signal voltage driver, Mickey have meet
|
|
a serious RF/EMI problem, so we decided to reduce HDMI signal
|
|
voltage to a proper value.
|
|
|
|
The default params for phy is cklvl = 20 & txlvl = 13 (RF/EMI failed)
|
|
ck: lvl = 13, term=100, vlo = 2.71, vhi=3.14, vswing = 0.43
|
|
tx: lvl = 20, term=100, vlo = 2.81, vhi=3.16, vswing = 0.35
|
|
|
|
1. We decided to reduce voltage value to lower, but VSwing still
|
|
keep high, RF/EMI have been improved but still failed.
|
|
ck: lvl = 6, term=100, vlo = 2.61, vhi=3.11, vswing = 0.50
|
|
tx: lvl = 6, term=100, vlo = 2.61, vhi=3.11, vswing = 0.50
|
|
|
|
2. We try to keep voltage value and vswing both lower, then RF/EMI
|
|
test all passed ;)
|
|
ck: lvl = 11, term= 66, vlo = 2.68, vhi=3.09, vswing = 0.40
|
|
tx: lvl = 11, term= 66, vlo = 2.68, vhi=3.09, vswing = 0.40
|
|
When we back to run HDMI different test and single-end test, we see
|
|
different test passed, but signle-end test failed. The oscilloscope
|
|
show that simgle-end clock's VL value is 1.78v (which remind LowLimit
|
|
should not lower then 2.6v).
|
|
|
|
3. That's to say there are some different between PHY document and
|
|
measure value. And according to experiment 2 results, we need to
|
|
higher clock voltage and lower data voltage, then we can keep RF/EMI
|
|
satisfied and single-end & differen test passed.
|
|
ck: lvl = 9, term=100, vlo = 2.65, vhi=3.12, vswing = 0.47
|
|
tx: lvl = 16, term=100, vlo = 2.75, vhi=3.15, vswing = 0.39
|
|
|
|
Signed-off-by: Yakir Yang <ykk@rock-chips.com>
|
|
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
|
---
|
|
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 2 +-
|
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
|
|
|
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
|
index cdf953850873..4652c0e0dcd6 100644
|
|
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
|
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
|
@@ -181,7 +181,7 @@ static const struct dw_hdmi_curr_ctrl rockchip_cur_ctr[] = {
|
|
static const struct dw_hdmi_phy_config rockchip_phy_config[] = {
|
|
/*pixelclk symbol term vlev*/
|
|
{ 74250000, 0x8009, 0x0004, 0x0272},
|
|
- { 148500000, 0x802b, 0x0004, 0x028d},
|
|
+ { 165000000, 0x802b, 0x0004, 0x0209},
|
|
{ 297000000, 0x8039, 0x0005, 0x028d},
|
|
{ ~0UL, 0x0000, 0x0000, 0x0000}
|
|
};
|
|
|
|
From d010c041afc48d4592625e23082aa31871042847 Mon Sep 17 00:00:00 2001
|
|
From: Nickey Yang <nickey.yang@rock-chips.com>
|
|
Date: Mon, 13 Feb 2017 15:40:29 +0800
|
|
Subject: [PATCH] drm/rockchip: dw_hdmi: add phy_config for 594Mhz pixel clock
|
|
|
|
Add phy_config for 594Mhz pixel clock used for 4K@60hz
|
|
|
|
Signed-off-by: Nickey Yang <nickey.yang@rock-chips.com>
|
|
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
|
---
|
|
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 1 +
|
|
1 file changed, 1 insertion(+)
|
|
|
|
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
|
index 4652c0e0dcd6..10c3dc521cbd 100644
|
|
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
|
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
|
@@ -183,6 +183,7 @@ static const struct dw_hdmi_phy_config rockchip_phy_config[] = {
|
|
{ 74250000, 0x8009, 0x0004, 0x0272},
|
|
{ 165000000, 0x802b, 0x0004, 0x0209},
|
|
{ 297000000, 0x8039, 0x0005, 0x028d},
|
|
+ { 594000000, 0x8039, 0x0000, 0x019d},
|
|
{ ~0UL, 0x0000, 0x0000, 0x0000}
|
|
};
|
|
|
|
|
|
From c4e637b2fc48c3bdb6f1ff8d5a5883e21587f051 Mon Sep 17 00:00:00 2001
|
|
From: Douglas Anderson <dianders@chromium.org>
|
|
Date: Mon, 11 Jul 2016 19:05:36 +0800
|
|
Subject: [PATCH] drm/rockchip: dw_hdmi: Set cur_ctr to 0 always
|
|
|
|
Jitter was improved by lowering the MPLL bandwidth to account for high
|
|
frequency noise in the rk3288 PLL. In each case MPLL bandwidth was
|
|
lowered only enough to get us a comfortable margin. We believe that
|
|
lowering the bandwidth like this is safe given sufficient testing.
|
|
|
|
Signed-off-by: Douglas Anderson <dianders@chromium.org>
|
|
Signed-off-by: Yakir Yang <ykk@rock-chips.com>
|
|
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
|
---
|
|
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 16 ++--------------
|
|
1 file changed, 2 insertions(+), 14 deletions(-)
|
|
|
|
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
|
index 10c3dc521cbd..cc7675638e4f 100644
|
|
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
|
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
|
@@ -160,20 +160,8 @@ static const struct dw_hdmi_mpll_config rockchip_mpll_cfg[] = {
|
|
static const struct dw_hdmi_curr_ctrl rockchip_cur_ctr[] = {
|
|
/* pixelclk bpp8 bpp10 bpp12 */
|
|
{
|
|
- 40000000, { 0x0018, 0x0018, 0x0018 },
|
|
- }, {
|
|
- 65000000, { 0x0028, 0x0028, 0x0028 },
|
|
- }, {
|
|
- 66000000, { 0x0038, 0x0038, 0x0038 },
|
|
- }, {
|
|
- 74250000, { 0x0028, 0x0038, 0x0038 },
|
|
- }, {
|
|
- 83500000, { 0x0028, 0x0038, 0x0038 },
|
|
- }, {
|
|
- 146250000, { 0x0038, 0x0038, 0x0038 },
|
|
- }, {
|
|
- 148500000, { 0x0000, 0x0038, 0x0038 },
|
|
- }, {
|
|
+ 600000000, { 0x0000, 0x0000, 0x0000 },
|
|
+ }, {
|
|
~0UL, { 0x0000, 0x0000, 0x0000},
|
|
}
|
|
};
|
|
|
|
From 2b9a23ae36142d8d4d9fcce63a90b9c8329ad187 Mon Sep 17 00:00:00 2001
|
|
From: Douglas Anderson <dianders@chromium.org>
|
|
Date: Mon, 11 Jul 2016 19:05:42 +0800
|
|
Subject: [PATCH] drm/rockchip: dw_hdmi: Use auto-generated tables
|
|
|
|
The previous tables for mpll_cfg and curr_ctrl were created using the
|
|
20-pages of example settings provided by the PHY vendor. Those
|
|
example settings weren't particularly dense, so there were places
|
|
where we were guessing what the settings would be for 10-bit and
|
|
12-bit (not that we use those anyway). It was also always a lot of
|
|
extra work every time we wanted to add a new clock rate since we had
|
|
to cross-reference several tables.
|
|
|
|
In <http://crosreview.com/285855> I've gone through the work to figure
|
|
out how to generate this table automatically. Let's now use the
|
|
automatically generated table and then we'll never need to look at it
|
|
again.
|
|
|
|
We only support 8-bit mode right now and only support a small number
|
|
of clock rates and and I've verified that the only 8-bit rate that was
|
|
affected was 148.5. That mode appears to have been wrong in the old
|
|
table.
|
|
|
|
Signed-off-by: Douglas Anderson <dianders@chromium.org>
|
|
Signed-off-by: Yakir Yang <ykk@rock-chips.com>
|
|
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
|
---
|
|
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 130 +++++++++++---------
|
|
1 file changed, 69 insertions(+), 61 deletions(-)
|
|
|
|
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
|
index cc7675638e4f..c4c158106ca4 100644
|
|
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
|
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
|
@@ -79,80 +79,88 @@ struct rockchip_hdmi {
|
|
|
|
static const struct dw_hdmi_mpll_config rockchip_mpll_cfg[] = {
|
|
{
|
|
- 27000000, {
|
|
- { 0x00b3, 0x0000},
|
|
- { 0x2153, 0x0000},
|
|
- { 0x40f3, 0x0000}
|
|
+ 30666000, {
|
|
+ { 0x00b3, 0x0000 },
|
|
+ { 0x2153, 0x0000 },
|
|
+ { 0x40f3, 0x0000 },
|
|
},
|
|
- }, {
|
|
- 36000000, {
|
|
- { 0x00b3, 0x0000},
|
|
- { 0x2153, 0x0000},
|
|
- { 0x40f3, 0x0000}
|
|
+ }, {
|
|
+ 36800000, {
|
|
+ { 0x00b3, 0x0000 },
|
|
+ { 0x2153, 0x0000 },
|
|
+ { 0x40a2, 0x0001 },
|
|
},
|
|
- }, {
|
|
- 40000000, {
|
|
- { 0x00b3, 0x0000},
|
|
- { 0x2153, 0x0000},
|
|
- { 0x40f3, 0x0000}
|
|
+ }, {
|
|
+ 46000000, {
|
|
+ { 0x00b3, 0x0000 },
|
|
+ { 0x2142, 0x0001 },
|
|
+ { 0x40a2, 0x0001 },
|
|
},
|
|
- }, {
|
|
- 54000000, {
|
|
- { 0x0072, 0x0001},
|
|
- { 0x2142, 0x0001},
|
|
- { 0x40a2, 0x0001},
|
|
+ }, {
|
|
+ 61333000, {
|
|
+ { 0x0072, 0x0001 },
|
|
+ { 0x2142, 0x0001 },
|
|
+ { 0x40a2, 0x0001 },
|
|
},
|
|
- }, {
|
|
- 65000000, {
|
|
- { 0x0072, 0x0001},
|
|
- { 0x2142, 0x0001},
|
|
- { 0x40a2, 0x0001},
|
|
+ }, {
|
|
+ 73600000, {
|
|
+ { 0x0072, 0x0001 },
|
|
+ { 0x2142, 0x0001 },
|
|
+ { 0x4061, 0x0002 },
|
|
},
|
|
- }, {
|
|
- 66000000, {
|
|
- { 0x013e, 0x0003},
|
|
- { 0x217e, 0x0002},
|
|
- { 0x4061, 0x0002}
|
|
+ }, {
|
|
+ 92000000, {
|
|
+ { 0x0072, 0x0001 },
|
|
+ { 0x2145, 0x0002 },
|
|
+ { 0x4061, 0x0002 },
|
|
+ },
|
|
+ }, {
|
|
+ 122666000, {
|
|
+ { 0x0051, 0x0002 },
|
|
+ { 0x2145, 0x0002 },
|
|
+ { 0x4061, 0x0002 },
|
|
},
|
|
- }, {
|
|
- 74250000, {
|
|
- { 0x0072, 0x0001},
|
|
- { 0x2145, 0x0002},
|
|
- { 0x4061, 0x0002}
|
|
+ }, {
|
|
+ 147200000, {
|
|
+ { 0x0051, 0x0002 },
|
|
+ { 0x2145, 0x0002 },
|
|
+ { 0x4064, 0x0003 },
|
|
},
|
|
- }, {
|
|
- 83500000, {
|
|
- { 0x0072, 0x0001},
|
|
+ }, {
|
|
+ 184000000, {
|
|
+ { 0x0051, 0x0002 },
|
|
+ { 0x214c, 0x0003 },
|
|
+ { 0x4064, 0x0003 },
|
|
},
|
|
- }, {
|
|
- 108000000, {
|
|
- { 0x0051, 0x0002},
|
|
- { 0x2145, 0x0002},
|
|
- { 0x4061, 0x0002}
|
|
+ }, {
|
|
+ 226666000, {
|
|
+ { 0x0040, 0x0003 },
|
|
+ { 0x214c, 0x0003 },
|
|
+ { 0x4064, 0x0003 },
|
|
},
|
|
- }, {
|
|
- 106500000, {
|
|
- { 0x0051, 0x0002},
|
|
- { 0x2145, 0x0002},
|
|
- { 0x4061, 0x0002}
|
|
+ }, {
|
|
+ 272000000, {
|
|
+ { 0x0040, 0x0003 },
|
|
+ { 0x214c, 0x0003 },
|
|
+ { 0x5a64, 0x0003 },
|
|
},
|
|
- }, {
|
|
- 146250000, {
|
|
- { 0x0051, 0x0002},
|
|
- { 0x2145, 0x0002},
|
|
- { 0x4061, 0x0002}
|
|
+ }, {
|
|
+ 340000000, {
|
|
+ { 0x0040, 0x0003 },
|
|
+ { 0x3b4c, 0x0003 },
|
|
+ { 0x5a64, 0x0003 },
|
|
},
|
|
- }, {
|
|
- 148500000, {
|
|
- { 0x0051, 0x0003},
|
|
- { 0x214c, 0x0003},
|
|
- { 0x4064, 0x0003}
|
|
+ }, {
|
|
+ 600000000, {
|
|
+ { 0x1a40, 0x0003 },
|
|
+ { 0x3b4c, 0x0003 },
|
|
+ { 0x5a64, 0x0003 },
|
|
},
|
|
- }, {
|
|
+ }, {
|
|
~0UL, {
|
|
- { 0x00a0, 0x000a },
|
|
- { 0x2001, 0x000f },
|
|
- { 0x4002, 0x000f },
|
|
+ { 0x0000, 0x0000 },
|
|
+ { 0x0000, 0x0000 },
|
|
+ { 0x0000, 0x0000 },
|
|
},
|
|
}
|
|
};
|
|
|
|
From fd940089282dffc01cc7b45a5aef11acd59a4f9f Mon Sep 17 00:00:00 2001
|
|
From: Jonas Karlman <jonas@kwiboo.se>
|
|
Date: Wed, 8 Jan 2020 21:07:52 +0000
|
|
Subject: [PATCH] drm/rockchip: dw-hdmi: limit tmds to 340mhz
|
|
|
|
RK3228/RK3328 does not provide a stable hdmi signal at TMDS rates
|
|
above 371.25MHz (340MHz pixel clock).
|
|
|
|
Limit the pixel clock rate to 340MHz to provide a stable signal.
|
|
Also limit the pixel clock to the display reported max tmds clock.
|
|
|
|
This also enables use of pixel clocks up to 340MHz on RK3288/RK3399.
|
|
|
|
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
|
---
|
|
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 16 ++++------------
|
|
1 file changed, 4 insertions(+), 12 deletions(-)
|
|
|
|
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
|
index c4c158106ca4..b62d8f4fc9a8 100644
|
|
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
|
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
|
@@ -221,19 +221,11 @@ dw_hdmi_rockchip_mode_valid(struct dw_hdmi *hdmi, void *data,
|
|
const struct drm_display_info *info,
|
|
const struct drm_display_mode *mode)
|
|
{
|
|
- const struct dw_hdmi_mpll_config *mpll_cfg = rockchip_mpll_cfg;
|
|
- int pclk = mode->clock * 1000;
|
|
- bool valid = false;
|
|
- int i;
|
|
-
|
|
- for (i = 0; mpll_cfg[i].mpixelclock != (~0UL); i++) {
|
|
- if (pclk == mpll_cfg[i].mpixelclock) {
|
|
- valid = true;
|
|
- break;
|
|
- }
|
|
- }
|
|
+ if (mode->clock > 340000 ||
|
|
+ (info->max_tmds_clock && mode->clock > info->max_tmds_clock))
|
|
+ return MODE_CLOCK_HIGH;
|
|
|
|
- return (valid) ? MODE_OK : MODE_BAD;
|
|
+ return MODE_OK;
|
|
}
|
|
|
|
static void dw_hdmi_rockchip_encoder_disable(struct drm_encoder *encoder)
|
|
|
|
From c2ac79d4d979bc7cdee94bc4ecad5946b31d2caf Mon Sep 17 00:00:00 2001
|
|
From: Jonas Karlman <jonas@kwiboo.se>
|
|
Date: Sun, 3 May 2020 22:36:23 +0000
|
|
Subject: [PATCH] drm/rockchip: dw-hdmi: limit resolution to 3840x2160
|
|
|
|
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
|
---
|
|
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 2 +-
|
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
|
|
|
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
|
index b62d8f4fc9a8..6f7641fbe6cc 100644
|
|
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
|
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
|
@@ -225,7 +225,7 @@ dw_hdmi_rockchip_mode_valid(struct dw_hdmi *hdmi, void *data,
|
|
(info->max_tmds_clock && mode->clock > info->max_tmds_clock))
|
|
return MODE_CLOCK_HIGH;
|
|
|
|
- return MODE_OK;
|
|
+ return drm_mode_validate_size(mode, 3840, 2160);
|
|
}
|
|
|
|
static void dw_hdmi_rockchip_encoder_disable(struct drm_encoder *encoder)
|
|
|
|
From f7e97888e1b955bee4e7fc778b9434c3c3aeaa1c Mon Sep 17 00:00:00 2001
|
|
From: Jonas Karlman <jonas@kwiboo.se>
|
|
Date: Wed, 8 Jan 2020 21:07:52 +0000
|
|
Subject: [PATCH] drm/rockchip: dw-hdmi: remove unused plat_data on
|
|
rk3228/rk3328
|
|
|
|
mpll_cfg/cur_ctr/phy_config is not used when phy_force_vendor is true,
|
|
lets remove them.
|
|
|
|
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
|
---
|
|
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 6 ------
|
|
1 file changed, 6 deletions(-)
|
|
|
|
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
|
index 6f7641fbe6cc..cc20a83fa9b8 100644
|
|
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
|
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
|
@@ -396,9 +396,6 @@ static struct rockchip_hdmi_chip_data rk3228_chip_data = {
|
|
|
|
static const struct dw_hdmi_plat_data rk3228_hdmi_drv_data = {
|
|
.mode_valid = dw_hdmi_rockchip_mode_valid,
|
|
- .mpll_cfg = rockchip_mpll_cfg,
|
|
- .cur_ctr = rockchip_cur_ctr,
|
|
- .phy_config = rockchip_phy_config,
|
|
.phy_data = &rk3228_chip_data,
|
|
.phy_ops = &rk3228_hdmi_phy_ops,
|
|
.phy_name = "inno_dw_hdmi_phy2",
|
|
@@ -433,9 +430,6 @@ static struct rockchip_hdmi_chip_data rk3328_chip_data = {
|
|
|
|
static const struct dw_hdmi_plat_data rk3328_hdmi_drv_data = {
|
|
.mode_valid = dw_hdmi_rockchip_mode_valid,
|
|
- .mpll_cfg = rockchip_mpll_cfg,
|
|
- .cur_ctr = rockchip_cur_ctr,
|
|
- .phy_config = rockchip_phy_config,
|
|
.phy_data = &rk3328_chip_data,
|
|
.phy_ops = &rk3328_hdmi_phy_ops,
|
|
.phy_name = "inno_dw_hdmi_phy2",
|
|
|
|
From db3a0bad2ab53b12c7dbeec032cb8f3d7ef0563d Mon Sep 17 00:00:00 2001
|
|
From: Jonas Karlman <jonas@kwiboo.se>
|
|
Date: Wed, 8 Jan 2020 21:07:50 +0000
|
|
Subject: [PATCH] clk: rockchip: set parent rate for DCLK_VOP clock on rk3228
|
|
|
|
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
|
---
|
|
drivers/clk/rockchip/clk-rk3228.c | 2 +-
|
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
|
|
|
diff --git a/drivers/clk/rockchip/clk-rk3228.c b/drivers/clk/rockchip/clk-rk3228.c
|
|
index 6c39ecd3db7e..0c422e4bb213 100644
|
|
--- a/drivers/clk/rockchip/clk-rk3228.c
|
|
+++ b/drivers/clk/rockchip/clk-rk3228.c
|
|
@@ -393,7 +393,7 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = {
|
|
RK2928_CLKSEL_CON(29), 0, 3, DFLAGS),
|
|
DIV(0, "sclk_vop_pre", "sclk_vop_src", 0,
|
|
RK2928_CLKSEL_CON(27), 8, 8, DFLAGS),
|
|
- MUX(DCLK_VOP, "dclk_vop", mux_dclk_vop_p, 0,
|
|
+ MUX(DCLK_VOP, "dclk_vop", mux_dclk_vop_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
|
|
RK2928_CLKSEL_CON(27), 1, 1, MFLAGS),
|
|
|
|
FACTOR(0, "xin12m", "xin24m", 0, 1, 2),
|
|
|
|
From d25ae20e096caca3783c95d14586a4357fa83449 Mon Sep 17 00:00:00 2001
|
|
From: Nickey Yang <nickey.yang@rock-chips.com>
|
|
Date: Mon, 17 Jul 2017 16:35:34 +0800
|
|
Subject: [PATCH] HACK: clk: rockchip: rk3288: dedicate npll for vopb and hdmi
|
|
use
|
|
|
|
MINIARM: set npll be used for hdmi only
|
|
|
|
Signed-off-by: Nickey Yang <nickey.yang@rock-chips.com>
|
|
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
|
---
|
|
arch/arm/boot/dts/rk3288.dtsi | 2 ++
|
|
drivers/clk/rockchip/clk-rk3288.c | 4 ++--
|
|
2 files changed, 4 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi
|
|
index 68d5a58cfe88..a376dea3bb1b 100644
|
|
--- a/arch/arm/boot/dts/rk3288.dtsi
|
|
+++ b/arch/arm/boot/dts/rk3288.dtsi
|
|
@@ -1046,6 +1046,8 @@ vopb: vop@ff930000 {
|
|
resets = <&cru SRST_LCDC0_AXI>, <&cru SRST_LCDC0_AHB>, <&cru SRST_LCDC0_DCLK>;
|
|
reset-names = "axi", "ahb", "dclk";
|
|
iommus = <&vopb_mmu>;
|
|
+ assigned-clocks = <&cru DCLK_VOP0>;
|
|
+ assigned-clock-parents = <&cru PLL_NPLL>;
|
|
status = "disabled";
|
|
|
|
vopb_out: port {
|
|
diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c
|
|
index 15c8f1dcba9a..460b19d65ef3 100644
|
|
--- a/drivers/clk/rockchip/clk-rk3288.c
|
|
+++ b/drivers/clk/rockchip/clk-rk3288.c
|
|
@@ -234,7 +234,7 @@ static struct rockchip_pll_clock rk3288_pll_clks[] __initdata = {
|
|
[gpll] = PLL(pll_rk3066, PLL_GPLL, "gpll", mux_pll_p, 0, RK3288_PLL_CON(12),
|
|
RK3288_MODE_CON, 12, 8, ROCKCHIP_PLL_SYNC_RATE, rk3288_pll_rates),
|
|
[npll] = PLL(pll_rk3066, PLL_NPLL, "npll", mux_pll_p, 0, RK3288_PLL_CON(16),
|
|
- RK3288_MODE_CON, 14, 9, ROCKCHIP_PLL_SYNC_RATE, rk3288_pll_rates),
|
|
+ RK3288_MODE_CON, 14, 9, 0, rk3288_pll_rates),
|
|
};
|
|
|
|
static struct clk_div_table div_hclk_cpu_t[] = {
|
|
@@ -444,7 +444,7 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
|
|
RK3288_CLKSEL_CON(30), 14, 2, MFLAGS, 8, 5, DFLAGS,
|
|
RK3288_CLKGATE_CON(3), 4, GFLAGS),
|
|
|
|
- COMPOSITE(DCLK_VOP0, "dclk_vop0", mux_pll_src_cpll_gpll_npll_p, 0,
|
|
+ COMPOSITE(DCLK_VOP0, "dclk_vop0", mux_pll_src_cpll_gpll_npll_p, CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT,
|
|
RK3288_CLKSEL_CON(27), 0, 2, MFLAGS, 8, 8, DFLAGS,
|
|
RK3288_CLKGATE_CON(3), 1, GFLAGS),
|
|
COMPOSITE(DCLK_VOP1, "dclk_vop1", mux_pll_src_cpll_gpll_npll_p, 0,
|
|
|
|
From f971cfab78a201e0e4c3413a69b3ab1467ca6e3e Mon Sep 17 00:00:00 2001
|
|
From: Jonas Karlman <jonas@kwiboo.se>
|
|
Date: Sat, 4 Aug 2018 14:51:14 +0200
|
|
Subject: [PATCH] HACK: clk: rockchip: rk3288: use npll table to to improve
|
|
HDMI compatibility
|
|
|
|
Based on https://github.com/TinkerBoard/debian_kernel/commit/3d90870530b8a2901681f7b7fa598ee7381e49f3
|
|
|
|
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
|
---
|
|
drivers/clk/rockchip/clk-rk3288.c | 23 ++++++++++++++++++++++-
|
|
1 file changed, 22 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c
|
|
index 460b19d65ef3..b973c6b0315b 100644
|
|
--- a/drivers/clk/rockchip/clk-rk3288.c
|
|
+++ b/drivers/clk/rockchip/clk-rk3288.c
|
|
@@ -124,6 +124,27 @@ static struct rockchip_pll_rate_table rk3288_pll_rates[] = {
|
|
{ /* sentinel */ },
|
|
};
|
|
|
|
+static struct rockchip_pll_rate_table rk3288_npll_rates[] = {
|
|
+ RK3066_PLL_RATE_NB(594000000, 1, 99, 4, 32),
|
|
+ RK3066_PLL_RATE_NB(585000000, 6, 585, 4, 32),
|
|
+ RK3066_PLL_RATE_NB(432000000, 3, 216, 4, 32),
|
|
+ RK3066_PLL_RATE_NB(426000000, 3, 213, 4, 32),
|
|
+ RK3066_PLL_RATE_NB(400000000, 1, 100, 6, 32),
|
|
+ RK3066_PLL_RATE_NB(342000000, 3, 171, 4, 32),
|
|
+ RK3066_PLL_RATE_NB(297000000, 2, 198, 8, 16),
|
|
+ RK3066_PLL_RATE_NB(270000000, 1, 135, 12, 32),
|
|
+ RK3066_PLL_RATE_NB(260000000, 1, 130, 12, 32),
|
|
+ RK3066_PLL_RATE_NB(148500000, 1, 99, 16, 32),
|
|
+ RK3066_PLL_RATE(148352000, 13, 1125, 14),
|
|
+ RK3066_PLL_RATE_NB(146250000, 6, 585, 16, 32),
|
|
+ RK3066_PLL_RATE_NB(108000000, 1, 54, 12, 32),
|
|
+ RK3066_PLL_RATE_NB(106500000, 4, 213, 12, 32),
|
|
+ RK3066_PLL_RATE_NB(85500000, 4, 171, 12, 32),
|
|
+ RK3066_PLL_RATE_NB(74250000, 4, 198, 16, 32),
|
|
+ RK3066_PLL_RATE(74176000, 26, 1125, 14),
|
|
+ { /* sentinel */ },
|
|
+};
|
|
+
|
|
#define RK3288_DIV_ACLK_CORE_M0_MASK 0xf
|
|
#define RK3288_DIV_ACLK_CORE_M0_SHIFT 0
|
|
#define RK3288_DIV_ACLK_CORE_MP_MASK 0xf
|
|
@@ -234,7 +255,7 @@ static struct rockchip_pll_clock rk3288_pll_clks[] __initdata = {
|
|
[gpll] = PLL(pll_rk3066, PLL_GPLL, "gpll", mux_pll_p, 0, RK3288_PLL_CON(12),
|
|
RK3288_MODE_CON, 12, 8, ROCKCHIP_PLL_SYNC_RATE, rk3288_pll_rates),
|
|
[npll] = PLL(pll_rk3066, PLL_NPLL, "npll", mux_pll_p, 0, RK3288_PLL_CON(16),
|
|
- RK3288_MODE_CON, 14, 9, 0, rk3288_pll_rates),
|
|
+ RK3288_MODE_CON, 14, 9, 0, rk3288_npll_rates),
|
|
};
|
|
|
|
static struct clk_div_table div_hclk_cpu_t[] = {
|
|
|
|
From 611c4656dadc68be76767b04c27266c183748090 Mon Sep 17 00:00:00 2001
|
|
From: Jonas Karlman <jonas@kwiboo.se>
|
|
Date: Sun, 28 Oct 2018 21:43:01 +0100
|
|
Subject: [PATCH] HACK: clk: rockchip: rk3288: add more npll clocks
|
|
|
|
Fixes 2560x1440@60Hz, 1600x1200@60Hz, 1920x1200@60Hz, 1680x1050@60Hz and 1440x900@60Hz modes on my monitor
|
|
|
|
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
|
---
|
|
drivers/clk/rockchip/clk-rk3288.c | 16 ++++++++++++++++
|
|
1 file changed, 16 insertions(+)
|
|
|
|
diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c
|
|
index b973c6b0315b..9192b89c2550 100644
|
|
--- a/drivers/clk/rockchip/clk-rk3288.c
|
|
+++ b/drivers/clk/rockchip/clk-rk3288.c
|
|
@@ -130,18 +130,34 @@ static struct rockchip_pll_rate_table rk3288_npll_rates[] = {
|
|
RK3066_PLL_RATE_NB(432000000, 3, 216, 4, 32),
|
|
RK3066_PLL_RATE_NB(426000000, 3, 213, 4, 32),
|
|
RK3066_PLL_RATE_NB(400000000, 1, 100, 6, 32),
|
|
+ RK3066_PLL_RATE(348500000, 8, 697, 6),
|
|
RK3066_PLL_RATE_NB(342000000, 3, 171, 4, 32),
|
|
RK3066_PLL_RATE_NB(297000000, 2, 198, 8, 16),
|
|
RK3066_PLL_RATE_NB(270000000, 1, 135, 12, 32),
|
|
RK3066_PLL_RATE_NB(260000000, 1, 130, 12, 32),
|
|
+ RK3066_PLL_RATE(241500000, 2, 161, 8),
|
|
+ RK3066_PLL_RATE(162000000, 1, 81, 12),
|
|
+ RK3066_PLL_RATE(154000000, 6, 539, 14),
|
|
RK3066_PLL_RATE_NB(148500000, 1, 99, 16, 32),
|
|
RK3066_PLL_RATE(148352000, 13, 1125, 14),
|
|
RK3066_PLL_RATE_NB(146250000, 6, 585, 16, 32),
|
|
+ RK3066_PLL_RATE(121750000, 6, 487, 16),
|
|
+ RK3066_PLL_RATE(119000000, 3, 238, 16),
|
|
RK3066_PLL_RATE_NB(108000000, 1, 54, 12, 32),
|
|
RK3066_PLL_RATE_NB(106500000, 4, 213, 12, 32),
|
|
+ RK3066_PLL_RATE(101000000, 3, 202, 16),
|
|
+ RK3066_PLL_RATE(88750000, 6, 355, 16),
|
|
RK3066_PLL_RATE_NB(85500000, 4, 171, 12, 32),
|
|
+ RK3066_PLL_RATE(83500000, 3, 167, 16),
|
|
+ RK3066_PLL_RATE(79500000, 1, 53, 16),
|
|
RK3066_PLL_RATE_NB(74250000, 4, 198, 16, 32),
|
|
RK3066_PLL_RATE(74176000, 26, 1125, 14),
|
|
+ RK3066_PLL_RATE(72000000, 1, 48, 16),
|
|
+ RK3066_PLL_RATE(71000000, 3, 142, 16),
|
|
+ RK3066_PLL_RATE(68250000, 2, 91, 16),
|
|
+ RK3066_PLL_RATE(65000000, 3, 130, 16),
|
|
+ RK3066_PLL_RATE(40000000, 3, 80, 16),
|
|
+ RK3066_PLL_RATE(33750000, 2, 45, 16),
|
|
{ /* sentinel */ },
|
|
};
|
|
|
|
|
|
From 1e71e8f100f877a3fb04a63c437869732bab5974 Mon Sep 17 00:00:00 2001
|
|
From: Jonas Karlman <jonas@kwiboo.se>
|
|
Date: Mon, 25 May 2020 20:36:45 +0000
|
|
Subject: [PATCH] HACK: clk: rockchip: rk3399: dedicate vpll for vopb and hdmi
|
|
use
|
|
|
|
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
|
---
|
|
drivers/clk/rockchip/clk-rk3399.c | 32 +++++++++++++++++++++++++------
|
|
1 file changed, 26 insertions(+), 6 deletions(-)
|
|
|
|
diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c
|
|
index 3682d5675cf7..0934145c09ad 100644
|
|
--- a/drivers/clk/rockchip/clk-rk3399.c
|
|
+++ b/drivers/clk/rockchip/clk-rk3399.c
|
|
@@ -111,6 +111,25 @@ static struct rockchip_pll_rate_table rk3399_pll_rates[] = {
|
|
{ /* sentinel */ },
|
|
};
|
|
|
|
+static struct rockchip_pll_rate_table rk3399_vpll_rates[] = {
|
|
+ /* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */
|
|
+ RK3036_PLL_RATE( 594000000, 1, 123, 5, 1, 0, 12582912), /* vco = 2970000000 */
|
|
+ RK3036_PLL_RATE( 593406592, 1, 123, 5, 1, 0, 10508804), /* vco = 2967032965 */
|
|
+ RK3036_PLL_RATE( 297000000, 1, 123, 5, 2, 0, 12582912), /* vco = 2970000000 */
|
|
+ RK3036_PLL_RATE( 296703296, 1, 123, 5, 2, 0, 10508807), /* vco = 2967032970 */
|
|
+ RK3036_PLL_RATE( 148500000, 1, 129, 7, 3, 0, 15728640), /* vco = 3118500000 */
|
|
+ RK3036_PLL_RATE( 148351648, 1, 123, 5, 4, 0, 10508800), /* vco = 2967032960 */
|
|
+ RK3036_PLL_RATE( 106500000, 1, 124, 7, 4, 0, 4194304), /* vco = 2982000000 */
|
|
+ RK3036_PLL_RATE( 74250000, 1, 129, 7, 6, 0, 15728640), /* vco = 3118500000 */
|
|
+ RK3036_PLL_RATE( 74175824, 1, 129, 7, 6, 0, 13550823), /* vco = 3115384608 */
|
|
+ RK3036_PLL_RATE( 65000000, 1, 113, 7, 6, 0, 12582912), /* vco = 2730000000 */
|
|
+ RK3036_PLL_RATE( 59340659, 1, 121, 7, 7, 0, 2581098), /* vco = 2907692291 */
|
|
+ RK3036_PLL_RATE( 54000000, 1, 110, 7, 7, 0, 4194304), /* vco = 2646000000 */
|
|
+ RK3036_PLL_RATE( 27000000, 1, 55, 7, 7, 0, 2097152), /* vco = 1323000000 */
|
|
+ RK3036_PLL_RATE( 26973026, 1, 55, 7, 7, 0, 1173232), /* vco = 1321678323 */
|
|
+ { /* sentinel */ },
|
|
+};
|
|
+
|
|
/* CRU parents */
|
|
PNAME(mux_pll_p) = { "xin24m", "xin32k" };
|
|
|
|
@@ -129,7 +148,7 @@ PNAME(mux_ddrclk_p) = { "clk_ddrc_lpll_src",
|
|
PNAME(mux_aclk_cci_p) = { "cpll_aclk_cci_src",
|
|
"gpll_aclk_cci_src",
|
|
"npll_aclk_cci_src",
|
|
- "vpll_aclk_cci_src" };
|
|
+ "prevent:vpll" };
|
|
PNAME(mux_cci_trace_p) = { "cpll_cci_trace",
|
|
"gpll_cci_trace" };
|
|
PNAME(mux_cs_p) = { "cpll_cs", "gpll_cs",
|
|
@@ -156,9 +175,10 @@ PNAME(mux_pll_src_cpll_gpll_npll_ppll_upll_24m_p) = { "cpll", "gpll", "npll",
|
|
"ppll", "upll", "xin24m" };
|
|
|
|
PNAME(mux_pll_src_vpll_cpll_gpll_p) = { "vpll", "cpll", "gpll" };
|
|
-PNAME(mux_pll_src_vpll_cpll_gpll_npll_p) = { "vpll", "cpll", "gpll",
|
|
+
|
|
+PNAME(mux_pll_src_vpll_cpll_gpll_npll_p) = { "prevent:vpll", "cpll", "gpll",
|
|
"npll" };
|
|
-PNAME(mux_pll_src_vpll_cpll_gpll_24m_p) = { "vpll", "cpll", "gpll",
|
|
+PNAME(mux_pll_src_vpll_cpll_gpll_24m_p) = { "prevent:vpll", "cpll", "gpll",
|
|
"xin24m" };
|
|
|
|
PNAME(mux_dclk_vop0_p) = { "dclk_vop0_div",
|
|
@@ -235,7 +255,7 @@ static struct rockchip_pll_clock rk3399_pll_clks[] __initdata = {
|
|
[npll] = PLL(pll_rk3399, PLL_NPLL, "npll", mux_pll_p, 0, RK3399_PLL_CON(40),
|
|
RK3399_PLL_CON(43), 8, 31, ROCKCHIP_PLL_SYNC_RATE, rk3399_pll_rates),
|
|
[vpll] = PLL(pll_rk3399, PLL_VPLL, "vpll", mux_pll_p, 0, RK3399_PLL_CON(48),
|
|
- RK3399_PLL_CON(51), 8, 31, ROCKCHIP_PLL_SYNC_RATE, rk3399_pll_rates),
|
|
+ RK3399_PLL_CON(51), 8, 31, ROCKCHIP_PLL_SYNC_RATE, rk3399_vpll_rates),
|
|
};
|
|
|
|
static struct rockchip_pll_clock rk3399_pmu_pll_clks[] __initdata = {
|
|
@@ -285,7 +305,7 @@ static struct rockchip_clk_branch rk3399_uart4_pmu_fracmux __initdata =
|
|
RK3399_PMU_CLKSEL_CON(5), 8, 2, MFLAGS);
|
|
|
|
static struct rockchip_clk_branch rk3399_dclk_vop0_fracmux __initdata =
|
|
- MUX(DCLK_VOP0, "dclk_vop0", mux_dclk_vop0_p, CLK_SET_RATE_PARENT,
|
|
+ MUX(DCLK_VOP0, "dclk_vop0", mux_dclk_vop0_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
|
|
RK3399_CLKSEL_CON(49), 11, 1, MFLAGS);
|
|
|
|
static struct rockchip_clk_branch rk3399_dclk_vop1_fracmux __initdata =
|
|
@@ -1166,7 +1186,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = {
|
|
GATE(HCLK_VOP0_NOC, "hclk_vop0_noc", "hclk_vop0_pre", CLK_IGNORE_UNUSED,
|
|
RK3399_CLKGATE_CON(28), 0, GFLAGS),
|
|
|
|
- COMPOSITE(DCLK_VOP0_DIV, "dclk_vop0_div", mux_pll_src_vpll_cpll_gpll_p, 0,
|
|
+ COMPOSITE(DCLK_VOP0_DIV, "dclk_vop0_div", mux_pll_src_vpll_cpll_gpll_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
|
|
RK3399_CLKSEL_CON(49), 8, 2, MFLAGS, 0, 8, DFLAGS,
|
|
RK3399_CLKGATE_CON(10), 12, GFLAGS),
|
|
|
|
|
|
From aafa27ca194b5601de77c56773aa69c2e2db0051 Mon Sep 17 00:00:00 2001
|
|
From: Jonas Karlman <jonas@kwiboo.se>
|
|
Date: Sun, 19 Jul 2020 16:35:11 +0000
|
|
Subject: [PATCH] HACK: dts: rockchip: do not use vopl for hdmi
|
|
|
|
---
|
|
arch/arm/boot/dts/rk3288.dtsi | 9 ---------
|
|
arch/arm64/boot/dts/rockchip/rk3399.dtsi | 9 ---------
|
|
2 files changed, 18 deletions(-)
|
|
|
|
diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi
|
|
index a376dea3bb1b..9757976d6e8a 100644
|
|
--- a/arch/arm/boot/dts/rk3288.dtsi
|
|
+++ b/arch/arm/boot/dts/rk3288.dtsi
|
|
@@ -1104,11 +1104,6 @@ vopl_out: port {
|
|
#address-cells = <1>;
|
|
#size-cells = <0>;
|
|
|
|
- vopl_out_hdmi: endpoint@0 {
|
|
- reg = <0>;
|
|
- remote-endpoint = <&hdmi_in_vopl>;
|
|
- };
|
|
-
|
|
vopl_out_edp: endpoint@1 {
|
|
reg = <1>;
|
|
remote-endpoint = <&edp_in_vopl>;
|
|
@@ -1249,10 +1244,6 @@ hdmi_in_vopb: endpoint@0 {
|
|
reg = <0>;
|
|
remote-endpoint = <&vopb_out_hdmi>;
|
|
};
|
|
- hdmi_in_vopl: endpoint@1 {
|
|
- reg = <1>;
|
|
- remote-endpoint = <&vopl_out_hdmi>;
|
|
- };
|
|
};
|
|
};
|
|
};
|
|
diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
|
|
index ada724b12f01..8973bf68d652 100644
|
|
--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
|
|
+++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
|
|
@@ -1637,11 +1637,6 @@ vopl_out_edp: endpoint@1 {
|
|
remote-endpoint = <&edp_in_vopl>;
|
|
};
|
|
|
|
- vopl_out_hdmi: endpoint@2 {
|
|
- reg = <2>;
|
|
- remote-endpoint = <&hdmi_in_vopl>;
|
|
- };
|
|
-
|
|
vopl_out_mipi1: endpoint@3 {
|
|
reg = <3>;
|
|
remote-endpoint = <&mipi1_in_vopl>;
|
|
@@ -1787,10 +1782,6 @@ hdmi_in_vopb: endpoint@0 {
|
|
reg = <0>;
|
|
remote-endpoint = <&vopb_out_hdmi>;
|
|
};
|
|
- hdmi_in_vopl: endpoint@1 {
|
|
- reg = <1>;
|
|
- remote-endpoint = <&vopl_out_hdmi>;
|
|
- };
|
|
};
|
|
};
|
|
};
|
|
|
|
From 667178b6aeeeca36baf3f739902e5888efce6705 Mon Sep 17 00:00:00 2001
|
|
From: Jonas Karlman <jonas@kwiboo.se>
|
|
Date: Tue, 26 Feb 2019 20:45:14 +0000
|
|
Subject: [PATCH] WIP: dw-hdmi-cec: sleep 100ms on error
|
|
|
|
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
|
---
|
|
drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c | 19 +++++++++++++++++--
|
|
1 file changed, 17 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c
|
|
index 70ab4fbdc23e..f6a85f73b90d 100644
|
|
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c
|
|
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c
|
|
@@ -4,6 +4,7 @@
|
|
*
|
|
* Copyright (C) 2015-2017 Russell King.
|
|
*/
|
|
+#include <linux/delay.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/io.h>
|
|
#include <linux/module.h>
|
|
@@ -129,8 +130,16 @@ static irqreturn_t dw_hdmi_cec_hardirq(int irq, void *data)
|
|
|
|
dw_hdmi_write(cec, stat, HDMI_IH_CEC_STAT0);
|
|
|
|
- if (stat & CEC_STAT_ERROR_INIT) {
|
|
- cec->tx_status = CEC_TX_STATUS_ERROR;
|
|
+ /*
|
|
+ * Status with both done and error_initiator bits have been seen
|
|
+ * on Rockchip RK3328 devices, transmit attempt seems to have failed
|
|
+ * when this happens, report as low drive and block cec-framework
|
|
+ * 100ms before core retransmits the failed message, this seems to
|
|
+ * mitigate the issue with failed transmit attempts.
|
|
+ */
|
|
+ if ((stat & (CEC_STAT_DONE|CEC_STAT_ERROR_INIT)) == (CEC_STAT_DONE|CEC_STAT_ERROR_INIT)) {
|
|
+ pr_info("dw_hdmi_cec_hardirq: stat=%02x LOW_DRIVE\n", stat);
|
|
+ cec->tx_status = CEC_TX_STATUS_LOW_DRIVE;
|
|
cec->tx_done = true;
|
|
ret = IRQ_WAKE_THREAD;
|
|
} else if (stat & CEC_STAT_DONE) {
|
|
@@ -141,6 +150,10 @@ static irqreturn_t dw_hdmi_cec_hardirq(int irq, void *data)
|
|
cec->tx_status = CEC_TX_STATUS_NACK;
|
|
cec->tx_done = true;
|
|
ret = IRQ_WAKE_THREAD;
|
|
+ } else if (stat & CEC_STAT_ERROR_INIT) {
|
|
+ cec->tx_status = CEC_TX_STATUS_ERROR;
|
|
+ cec->tx_done = true;
|
|
+ ret = IRQ_WAKE_THREAD;
|
|
}
|
|
|
|
if (stat & CEC_STAT_EOM) {
|
|
@@ -173,6 +186,8 @@ static irqreturn_t dw_hdmi_cec_thread(int irq, void *data)
|
|
|
|
if (cec->tx_done) {
|
|
cec->tx_done = false;
|
|
+ if (cec->tx_status == CEC_TX_STATUS_LOW_DRIVE)
|
|
+ msleep(100);
|
|
cec_transmit_attempt_done(adap, cec->tx_status);
|
|
}
|
|
if (cec->rx_done) {
|
|
|
|
From 2642ca152420726d73313a469423e6447df393a6 Mon Sep 17 00:00:00 2001
|
|
From: Jonas Karlman <jonas@kwiboo.se>
|
|
Date: Sat, 18 Jul 2020 20:54:38 +0000
|
|
Subject: [PATCH] asdf
|
|
|
|
---
|
|
drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c | 36 +++++++++++++++----
|
|
drivers/media/cec/core/cec-adap.c | 2 +-
|
|
2 files changed, 30 insertions(+), 8 deletions(-)
|
|
|
|
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c
|
|
index f6a85f73b90d..e6953219beee 100644
|
|
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c
|
|
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c
|
|
@@ -58,6 +58,7 @@ struct dw_hdmi_cec {
|
|
u32 addresses;
|
|
struct cec_adapter *adap;
|
|
struct cec_msg rx_msg;
|
|
+ unsigned int tx_attempts;
|
|
unsigned int tx_status;
|
|
bool tx_done;
|
|
bool rx_done;
|
|
@@ -96,6 +97,8 @@ static int dw_hdmi_cec_transmit(struct cec_adapter *adap, u8 attempts,
|
|
struct dw_hdmi_cec *cec = cec_get_drvdata(adap);
|
|
unsigned int i, ctrl;
|
|
|
|
+ pr_info("%s: attempts=%u signal_free_time=%u msg=%*ph (sequence: %u)\n", __func__, attempts, signal_free_time, msg->len, msg->msg, msg->sequence);
|
|
+
|
|
switch (signal_free_time) {
|
|
case CEC_SIGNAL_FREE_TIME_RETRY:
|
|
ctrl = CEC_CTRL_RETRY;
|
|
@@ -131,26 +134,35 @@ static irqreturn_t dw_hdmi_cec_hardirq(int irq, void *data)
|
|
dw_hdmi_write(cec, stat, HDMI_IH_CEC_STAT0);
|
|
|
|
/*
|
|
- * Status with both done and error_initiator bits have been seen
|
|
- * on Rockchip RK3328 devices, transmit attempt seems to have failed
|
|
- * when this happens, report as low drive and block cec-framework
|
|
+ * Status with both done and error_initiator bits have been observed
|
|
+ * on Rockchip RK3328/RK3399 devices, transmit attempt seems to have
|
|
+ * failed when this happens, report as low drive and block cec-framework
|
|
* 100ms before core retransmits the failed message, this seems to
|
|
* mitigate the issue with failed transmit attempts.
|
|
*/
|
|
if ((stat & (CEC_STAT_DONE|CEC_STAT_ERROR_INIT)) == (CEC_STAT_DONE|CEC_STAT_ERROR_INIT)) {
|
|
- pr_info("dw_hdmi_cec_hardirq: stat=%02x LOW_DRIVE\n", stat);
|
|
+ if (!cec->tx_attempts)
|
|
+ cec->tx_attempts = 2;
|
|
cec->tx_status = CEC_TX_STATUS_LOW_DRIVE;
|
|
cec->tx_done = true;
|
|
ret = IRQ_WAKE_THREAD;
|
|
+ } else if (stat & CEC_STAT_ARBLOST) {
|
|
+ cec->tx_attempts = 0;
|
|
+ cec->tx_status = CEC_TX_STATUS_ARB_LOST;
|
|
+ cec->tx_done = true;
|
|
+ ret = IRQ_WAKE_THREAD;
|
|
} else if (stat & CEC_STAT_DONE) {
|
|
+ cec->tx_attempts = 0;
|
|
cec->tx_status = CEC_TX_STATUS_OK;
|
|
cec->tx_done = true;
|
|
ret = IRQ_WAKE_THREAD;
|
|
} else if (stat & CEC_STAT_NACK) {
|
|
+ cec->tx_attempts = 0;
|
|
cec->tx_status = CEC_TX_STATUS_NACK;
|
|
cec->tx_done = true;
|
|
ret = IRQ_WAKE_THREAD;
|
|
} else if (stat & CEC_STAT_ERROR_INIT) {
|
|
+ cec->tx_attempts = 0;
|
|
cec->tx_status = CEC_TX_STATUS_ERROR;
|
|
cec->tx_done = true;
|
|
ret = IRQ_WAKE_THREAD;
|
|
@@ -176,6 +188,8 @@ static irqreturn_t dw_hdmi_cec_hardirq(int irq, void *data)
|
|
ret = IRQ_WAKE_THREAD;
|
|
}
|
|
|
|
+ pr_info("%s: stat=%x ret=%x tx_done=%d rx_done=%d tx_status=%u tx_attempts=%u\n", __func__, stat, ret, cec->tx_done, cec->rx_done, cec->tx_status, cec->tx_attempts);
|
|
+
|
|
return ret;
|
|
}
|
|
|
|
@@ -184,11 +198,19 @@ static irqreturn_t dw_hdmi_cec_thread(int irq, void *data)
|
|
struct cec_adapter *adap = data;
|
|
struct dw_hdmi_cec *cec = cec_get_drvdata(adap);
|
|
|
|
+ //pr_info("%s: tx_done=%d rx_done=%d tx_status=%u tx_attempts=%u\n", __func__, cec->tx_done, cec->rx_done, cec->tx_status, cec->tx_attempts);
|
|
+
|
|
if (cec->tx_done) {
|
|
cec->tx_done = false;
|
|
if (cec->tx_status == CEC_TX_STATUS_LOW_DRIVE)
|
|
msleep(100);
|
|
- cec_transmit_attempt_done(adap, cec->tx_status);
|
|
+ if (cec->tx_attempts > 1) {
|
|
+ cec->tx_attempts--;
|
|
+ dw_hdmi_write(cec, CEC_CTRL_RETRY | CEC_CTRL_START, HDMI_CEC_CTRL);
|
|
+ } else {
|
|
+ cec->tx_attempts = 0;
|
|
+ cec_transmit_attempt_done(adap, cec->tx_status);
|
|
+ }
|
|
}
|
|
if (cec->rx_done) {
|
|
cec->rx_done = false;
|
|
@@ -219,8 +241,8 @@ static int dw_hdmi_cec_enable(struct cec_adapter *adap, bool enable)
|
|
|
|
cec->ops->enable(cec->hdmi);
|
|
|
|
- irqs = CEC_STAT_ERROR_INIT | CEC_STAT_NACK | CEC_STAT_EOM |
|
|
- CEC_STAT_DONE;
|
|
+ irqs = CEC_STAT_ERROR_INIT | CEC_STAT_ARBLOST | CEC_STAT_NACK |
|
|
+ CEC_STAT_EOM | CEC_STAT_DONE;
|
|
dw_hdmi_write(cec, irqs, HDMI_CEC_POLARITY);
|
|
dw_hdmi_write(cec, ~irqs, HDMI_CEC_MASK);
|
|
dw_hdmi_write(cec, ~irqs, HDMI_IH_MUTE_CEC_STAT0);
|
|
diff --git a/drivers/media/cec/core/cec-adap.c b/drivers/media/cec/core/cec-adap.c
|
|
index 926d65db6d3e..7b17539f656c 100644
|
|
--- a/drivers/media/cec/core/cec-adap.c
|
|
+++ b/drivers/media/cec/core/cec-adap.c
|
|
@@ -599,7 +599,6 @@ void cec_transmit_done_ts(struct cec_adapter *adap, u8 status,
|
|
unsigned int attempts_made = arb_lost_cnt + nack_cnt +
|
|
low_drive_cnt + error_cnt;
|
|
|
|
- dprintk(2, "%s: status 0x%02x\n", __func__, status);
|
|
if (attempts_made < 1)
|
|
attempts_made = 1;
|
|
|
|
@@ -620,6 +619,7 @@ void cec_transmit_done_ts(struct cec_adapter *adap, u8 status,
|
|
adap->transmit_in_progress = false;
|
|
|
|
msg = &data->msg;
|
|
+ dprintk(2, "%s: %*ph (sequence: %u, attempts: %d, status: %02x)\n", __func__, msg->len, msg->msg, msg->sequence, attempts_made, status);
|
|
|
|
/* Drivers must fill in the status! */
|
|
WARN_ON(status == 0);
|
|
|
|
From 2acbc9339a2fe44e1c7d5b2b97d2a09ba16c96fb Mon Sep 17 00:00:00 2001
|
|
From: Jonas Karlman <jonas@kwiboo.se>
|
|
Date: Mon, 20 Jul 2020 11:44:01 +0000
|
|
Subject: [PATCH] cec dprintk revert
|
|
|
|
---
|
|
drivers/media/cec/core/cec-adap.c | 2 +-
|
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
|
|
|
diff --git a/drivers/media/cec/core/cec-adap.c b/drivers/media/cec/core/cec-adap.c
|
|
index 7b17539f656c..926d65db6d3e 100644
|
|
--- a/drivers/media/cec/core/cec-adap.c
|
|
+++ b/drivers/media/cec/core/cec-adap.c
|
|
@@ -599,6 +599,7 @@ void cec_transmit_done_ts(struct cec_adapter *adap, u8 status,
|
|
unsigned int attempts_made = arb_lost_cnt + nack_cnt +
|
|
low_drive_cnt + error_cnt;
|
|
|
|
+ dprintk(2, "%s: status 0x%02x\n", __func__, status);
|
|
if (attempts_made < 1)
|
|
attempts_made = 1;
|
|
|
|
@@ -619,7 +620,6 @@ void cec_transmit_done_ts(struct cec_adapter *adap, u8 status,
|
|
adap->transmit_in_progress = false;
|
|
|
|
msg = &data->msg;
|
|
- dprintk(2, "%s: %*ph (sequence: %u, attempts: %d, status: %02x)\n", __func__, msg->len, msg->msg, msg->sequence, attempts_made, status);
|
|
|
|
/* Drivers must fill in the status! */
|
|
WARN_ON(status == 0);
|
|
|
|
From 0e1dc6a91a725e1d3417f693f620a77e29a222ad Mon Sep 17 00:00:00 2001
|
|
From: Jonas Karlman <jonas@kwiboo.se>
|
|
Date: Mon, 20 Jul 2020 12:33:01 +0000
|
|
Subject: [PATCH] Revert "fixup! WIP: drm/rockchip: vop: max_output"
|
|
|
|
This reverts commit c69612ca6820500cd1a0a3e4f8eb8c6f7b971cda.
|
|
---
|
|
drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 11 +++++++++++
|
|
1 file changed, 11 insertions(+)
|
|
|
|
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
|
|
index 106b38ea12df..138f449924f8 100644
|
|
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
|
|
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
|
|
@@ -1184,8 +1184,19 @@ static bool vop_crtc_mode_fixup(struct drm_crtc *crtc,
|
|
struct drm_display_mode *adjusted_mode)
|
|
{
|
|
struct vop *vop = to_vop(crtc);
|
|
+ const struct vop_rect *max_output = &vop->data->max_output;
|
|
unsigned long rate;
|
|
|
|
+ if (max_output->width && max_output->height) {
|
|
+ enum drm_mode_status status;
|
|
+
|
|
+ status = drm_mode_validate_size(adjusted_mode,
|
|
+ max_output->width,
|
|
+ max_output->height);
|
|
+ if (status != MODE_OK)
|
|
+ return false;
|
|
+ }
|
|
+
|
|
/*
|
|
* Clock craziness.
|
|
*
|
|
|
|
From 0b9759fa2630678c7e12f1b922ff866f53df90d1 Mon Sep 17 00:00:00 2001
|
|
From: Jonas Karlman <jonas@kwiboo.se>
|
|
Date: Wed, 15 Jul 2020 15:24:47 +0000
|
|
Subject: [PATCH] drm/rockchip: vop: fix crtc duplicate state
|
|
|
|
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
|
---
|
|
drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 6 +++++-
|
|
1 file changed, 5 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
|
|
index 138f449924f8..0a25de483515 100644
|
|
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
|
|
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
|
|
@@ -1578,7 +1578,11 @@ static struct drm_crtc_state *vop_crtc_duplicate_state(struct drm_crtc *crtc)
|
|
{
|
|
struct rockchip_crtc_state *rockchip_state;
|
|
|
|
- rockchip_state = kzalloc(sizeof(*rockchip_state), GFP_KERNEL);
|
|
+ if (WARN_ON(!crtc->state))
|
|
+ return NULL;
|
|
+
|
|
+ rockchip_state = kmemdup(to_rockchip_crtc_state(crtc->state),
|
|
+ sizeof(*rockchip_state), GFP_KERNEL);
|
|
if (!rockchip_state)
|
|
return NULL;
|
|
|
|
|
|
From dbf463be2403be5cd1e538fce49d85f7e26d4b3e Mon Sep 17 00:00:00 2001
|
|
From: Jonas Karlman <jonas@kwiboo.se>
|
|
Date: Mon, 20 Jul 2020 15:15:50 +0000
|
|
Subject: [PATCH] WIP: drm/rockchip: vop: filter interlaced modes
|
|
|
|
---
|
|
drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 3 +++
|
|
1 file changed, 3 insertions(+)
|
|
|
|
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
|
|
index 0a25de483515..5ab1412173a7 100644
|
|
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
|
|
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
|
|
@@ -1160,6 +1160,9 @@ static enum drm_mode_status vop_crtc_mode_valid(struct drm_crtc *crtc,
|
|
if (s->output_type != DRM_MODE_CONNECTOR_HDMIA)
|
|
return MODE_OK;
|
|
|
|
+ if (mode->flags & DRM_MODE_FLAG_INTERLACE)
|
|
+ return MODE_NO_INTERLACE;
|
|
+
|
|
rounded_rate = clk_round_rate(vop->dclk, mode->clock * 1000 + 999);
|
|
if (rounded_rate < 0)
|
|
return MODE_NOCLOCK;
|
|
|
|
From c846700ec7fdd8b7982f523bbfe867db3d08711b Mon Sep 17 00:00:00 2001
|
|
From: Jonas Karlman <jonas@kwiboo.se>
|
|
Date: Fri, 20 Dec 2019 08:12:42 +0000
|
|
Subject: [PATCH] drm/rockchip: dw-hdmi: add bridge and switch to
|
|
drm_bridge_funcs
|
|
|
|
Switch the dw-hdmi driver to drm_bridge_funcs by implementing
|
|
a new local bridge, connecting it to the dw-hdmi bridge.
|
|
|
|
Also enable bridge format negotiation by implementing
|
|
atomic_get_input_bus_fmts and support for 8-bit RGB 4:4:4.
|
|
|
|
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
|
---
|
|
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 138 ++++++++++++++------
|
|
1 file changed, 95 insertions(+), 43 deletions(-)
|
|
|
|
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
|
index cc20a83fa9b8..745fd1c13cef 100644
|
|
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
|
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
|
@@ -68,6 +68,7 @@ struct rockchip_hdmi {
|
|
struct device *dev;
|
|
struct regmap *regmap;
|
|
struct drm_encoder encoder;
|
|
+ struct drm_bridge bridge;
|
|
const struct rockchip_hdmi_chip_data *chip_data;
|
|
struct clk *vpll_clk;
|
|
struct clk *grf_clk;
|
|
@@ -228,30 +229,20 @@ dw_hdmi_rockchip_mode_valid(struct dw_hdmi *hdmi, void *data,
|
|
return drm_mode_validate_size(mode, 3840, 2160);
|
|
}
|
|
|
|
-static void dw_hdmi_rockchip_encoder_disable(struct drm_encoder *encoder)
|
|
+static void
|
|
+dw_hdmi_rockchip_bridge_mode_set(struct drm_bridge *bridge,
|
|
+ const struct drm_display_mode *mode,
|
|
+ const struct drm_display_mode *adjusted_mode)
|
|
{
|
|
-}
|
|
+ struct rockchip_hdmi *hdmi = to_rockchip_hdmi(bridge);
|
|
|
|
-static bool
|
|
-dw_hdmi_rockchip_encoder_mode_fixup(struct drm_encoder *encoder,
|
|
- const struct drm_display_mode *mode,
|
|
- struct drm_display_mode *adj_mode)
|
|
-{
|
|
- return true;
|
|
+ clk_set_rate(hdmi->vpll_clk, adjusted_mode->clock * 1000);
|
|
}
|
|
|
|
-static void dw_hdmi_rockchip_encoder_mode_set(struct drm_encoder *encoder,
|
|
- struct drm_display_mode *mode,
|
|
- struct drm_display_mode *adj_mode)
|
|
+static void dw_hdmi_rockchip_bridge_enable(struct drm_bridge *bridge)
|
|
{
|
|
- struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder);
|
|
-
|
|
- clk_set_rate(hdmi->vpll_clk, adj_mode->clock * 1000);
|
|
-}
|
|
-
|
|
-static void dw_hdmi_rockchip_encoder_enable(struct drm_encoder *encoder)
|
|
-{
|
|
- struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder);
|
|
+ struct rockchip_hdmi *hdmi = to_rockchip_hdmi(bridge);
|
|
+ struct drm_encoder *encoder = bridge->encoder;
|
|
u32 val;
|
|
int ret;
|
|
|
|
@@ -279,10 +270,21 @@ static void dw_hdmi_rockchip_encoder_enable(struct drm_encoder *encoder)
|
|
ret ? "LIT" : "BIG");
|
|
}
|
|
|
|
+static bool is_rgb(u32 format)
|
|
+{
|
|
+ switch (format) {
|
|
+ case MEDIA_BUS_FMT_RGB888_1X24:
|
|
+ return true;
|
|
+ default:
|
|
+ return false;
|
|
+ }
|
|
+}
|
|
+
|
|
static int
|
|
-dw_hdmi_rockchip_encoder_atomic_check(struct drm_encoder *encoder,
|
|
- struct drm_crtc_state *crtc_state,
|
|
- struct drm_connector_state *conn_state)
|
|
+dw_hdmi_rockchip_bridge_atomic_check(struct drm_bridge *bridge,
|
|
+ struct drm_bridge_state *bridge_state,
|
|
+ struct drm_crtc_state *crtc_state,
|
|
+ struct drm_connector_state *conn_state)
|
|
{
|
|
struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
|
|
|
|
@@ -292,12 +294,38 @@ dw_hdmi_rockchip_encoder_atomic_check(struct drm_encoder *encoder,
|
|
return 0;
|
|
}
|
|
|
|
-static const struct drm_encoder_helper_funcs dw_hdmi_rockchip_encoder_helper_funcs = {
|
|
- .mode_fixup = dw_hdmi_rockchip_encoder_mode_fixup,
|
|
- .mode_set = dw_hdmi_rockchip_encoder_mode_set,
|
|
- .enable = dw_hdmi_rockchip_encoder_enable,
|
|
- .disable = dw_hdmi_rockchip_encoder_disable,
|
|
- .atomic_check = dw_hdmi_rockchip_encoder_atomic_check,
|
|
+static u32 *dw_hdmi_rockchip_get_input_bus_fmts(struct drm_bridge *bridge,
|
|
+ struct drm_bridge_state *bridge_state,
|
|
+ struct drm_crtc_state *crtc_state,
|
|
+ struct drm_connector_state *conn_state,
|
|
+ u32 output_fmt,
|
|
+ unsigned int *num_input_fmts)
|
|
+{
|
|
+ u32 *input_fmt;
|
|
+
|
|
+ *num_input_fmts = 0;
|
|
+
|
|
+ if (!is_rgb(output_fmt))
|
|
+ return NULL;
|
|
+
|
|
+ input_fmt = kzalloc(sizeof(*input_fmt), GFP_KERNEL);
|
|
+ if (!input_fmt)
|
|
+ return NULL;
|
|
+
|
|
+ *num_input_fmts = 1;
|
|
+ *input_fmt = output_fmt;
|
|
+
|
|
+ return input_fmt;
|
|
+}
|
|
+
|
|
+static const struct drm_bridge_funcs dw_hdmi_rockchip_bridge_funcs = {
|
|
+ .mode_set = dw_hdmi_rockchip_bridge_mode_set,
|
|
+ .enable = dw_hdmi_rockchip_bridge_enable,
|
|
+ .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
|
+ .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
|
+ .atomic_get_input_bus_fmts = dw_hdmi_rockchip_get_input_bus_fmts,
|
|
+ .atomic_check = dw_hdmi_rockchip_bridge_atomic_check,
|
|
+ .atomic_reset = drm_atomic_helper_bridge_reset,
|
|
};
|
|
|
|
static int dw_hdmi_rockchip_genphy_init(struct dw_hdmi *dw_hdmi, void *data,
|
|
@@ -476,6 +504,7 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
|
|
struct dw_hdmi_plat_data *plat_data;
|
|
const struct of_device_id *match;
|
|
struct drm_device *drm = data;
|
|
+ struct drm_bridge *next_bridge;
|
|
struct drm_encoder *encoder;
|
|
struct rockchip_hdmi *hdmi;
|
|
int ret;
|
|
@@ -516,8 +545,7 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
|
|
|
|
ret = clk_prepare_enable(hdmi->vpll_clk);
|
|
if (ret) {
|
|
- DRM_DEV_ERROR(hdmi->dev, "Failed to enable HDMI vpll: %d\n",
|
|
- ret);
|
|
+ DRM_DEV_ERROR(hdmi->dev, "Failed to enable vpll: %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
@@ -525,27 +553,51 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
|
|
if (IS_ERR(hdmi->phy)) {
|
|
ret = PTR_ERR(hdmi->phy);
|
|
if (ret != -EPROBE_DEFER)
|
|
- DRM_DEV_ERROR(hdmi->dev, "failed to get phy\n");
|
|
- return ret;
|
|
+ DRM_DEV_ERROR(hdmi->dev, "Failed to get phy: %d\n", ret);
|
|
+ goto err_disable_clk;
|
|
}
|
|
|
|
- drm_encoder_helper_add(encoder, &dw_hdmi_rockchip_encoder_helper_funcs);
|
|
- drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
|
|
+ ret = drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
|
|
+ if (ret) {
|
|
+ DRM_DEV_ERROR(hdmi->dev, "Failed to init encoder: %d\n", ret);
|
|
+ goto err_disable_clk;
|
|
+ }
|
|
|
|
- platform_set_drvdata(pdev, hdmi);
|
|
+ hdmi->bridge.funcs = &dw_hdmi_rockchip_bridge_funcs;
|
|
+ drm_bridge_attach(encoder, &hdmi->bridge, NULL, 0);
|
|
|
|
- hdmi->hdmi = dw_hdmi_bind(pdev, encoder, plat_data);
|
|
+ platform_set_drvdata(pdev, hdmi);
|
|
|
|
- /*
|
|
- * If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(),
|
|
- * which would have called the encoder cleanup. Do it manually.
|
|
- */
|
|
+ hdmi->hdmi = dw_hdmi_probe(pdev, plat_data);
|
|
if (IS_ERR(hdmi->hdmi)) {
|
|
ret = PTR_ERR(hdmi->hdmi);
|
|
- drm_encoder_cleanup(encoder);
|
|
- clk_disable_unprepare(hdmi->vpll_clk);
|
|
+ if (ret != -EPROBE_DEFER)
|
|
+ DRM_DEV_ERROR(hdmi->dev, "Failed to init dw-hdmi bridge: %d\n", ret);
|
|
+ goto err_encoder_cleanup;
|
|
+ }
|
|
+
|
|
+ next_bridge = of_drm_find_bridge(pdev->dev.of_node);
|
|
+ if (!next_bridge) {
|
|
+ ret = -EPROBE_DEFER;
|
|
+ goto err_dw_hdmi_remove;
|
|
+ }
|
|
+
|
|
+ ret = drm_bridge_attach(encoder, next_bridge, &hdmi->bridge, 0);
|
|
+ if (ret) {
|
|
+ if (ret != -EPROBE_DEFER)
|
|
+ DRM_DEV_ERROR(hdmi->dev, "Failed to attach dw-hdmi bridge: %d\n", ret);
|
|
+ goto err_dw_hdmi_remove;
|
|
}
|
|
|
|
+ return 0;
|
|
+
|
|
+err_dw_hdmi_remove:
|
|
+ dw_hdmi_remove(hdmi->hdmi);
|
|
+err_encoder_cleanup:
|
|
+ drm_encoder_cleanup(encoder);
|
|
+err_disable_clk:
|
|
+ clk_disable_unprepare(hdmi->vpll_clk);
|
|
+
|
|
return ret;
|
|
}
|
|
|
|
@@ -554,7 +606,7 @@ static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master,
|
|
{
|
|
struct rockchip_hdmi *hdmi = dev_get_drvdata(dev);
|
|
|
|
- dw_hdmi_unbind(hdmi->hdmi);
|
|
+ dw_hdmi_remove(hdmi->hdmi);
|
|
clk_disable_unprepare(hdmi->vpll_clk);
|
|
}
|
|
|
|
|
|
From a1b98d86294a9320fe154aa11e104dea6becee4a Mon Sep 17 00:00:00 2001
|
|
From: Jonas Karlman <jonas@kwiboo.se>
|
|
Date: Mon, 20 Jul 2020 18:00:44 +0000
|
|
Subject: [PATCH] drm/bridge: dw-hdmi: add mtmdsclock parameter to phy
|
|
configure ops
|
|
|
|
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
|
---
|
|
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 10 ++++++----
|
|
drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c | 3 ++-
|
|
include/drm/bridge/dw_hdmi.h | 3 ++-
|
|
3 files changed, 10 insertions(+), 6 deletions(-)
|
|
|
|
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
|
index 748df1cacd2b..c25d5ac7bb07 100644
|
|
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
|
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
|
@@ -137,7 +137,8 @@ struct dw_hdmi_phy_data {
|
|
bool has_svsret;
|
|
int (*configure)(struct dw_hdmi *hdmi,
|
|
const struct dw_hdmi_plat_data *pdata,
|
|
- unsigned long mpixelclock);
|
|
+ unsigned long mpixelclock,
|
|
+ unsigned long mtmdsclock);
|
|
};
|
|
|
|
struct dw_hdmi {
|
|
@@ -1441,7 +1442,8 @@ static int dw_hdmi_phy_power_on(struct dw_hdmi *hdmi)
|
|
*/
|
|
static int hdmi_phy_configure_dwc_hdmi_3d_tx(struct dw_hdmi *hdmi,
|
|
const struct dw_hdmi_plat_data *pdata,
|
|
- unsigned long mpixelclock)
|
|
+ unsigned long mpixelclock,
|
|
+ unsigned long mtmdsclock)
|
|
{
|
|
const struct dw_hdmi_mpll_config *mpll_config = pdata->mpll_cfg;
|
|
const struct dw_hdmi_curr_ctrl *curr_ctrl = pdata->cur_ctr;
|
|
@@ -1516,9 +1518,9 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi,
|
|
|
|
/* Write to the PHY as configured by the platform */
|
|
if (pdata->configure_phy)
|
|
- ret = pdata->configure_phy(hdmi, pdata->priv_data, mpixelclock);
|
|
+ ret = pdata->configure_phy(hdmi, pdata->priv_data, mpixelclock, mtmdsclock);
|
|
else
|
|
- ret = phy->configure(hdmi, pdata, mpixelclock);
|
|
+ ret = phy->configure(hdmi, pdata, mpixelclock, mtmdsclock);
|
|
if (ret) {
|
|
dev_err(hdmi->dev, "PHY configuration failed (clock %lu)\n",
|
|
mpixelclock);
|
|
diff --git a/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c b/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c
|
|
index 7b8ec8310699..539d86131fd4 100644
|
|
--- a/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c
|
|
+++ b/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c
|
|
@@ -53,7 +53,8 @@ rcar_hdmi_mode_valid(struct dw_hdmi *hdmi, void *data,
|
|
}
|
|
|
|
static int rcar_hdmi_phy_configure(struct dw_hdmi *hdmi, void *data,
|
|
- unsigned long mpixelclock)
|
|
+ unsigned long mpixelclock,
|
|
+ unsigned long mtmdsclock)
|
|
{
|
|
const struct rcar_hdmi_phy_params *params = rcar_hdmi_phy_params;
|
|
|
|
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
|
|
index ea34ca146b82..4f61ede6486d 100644
|
|
--- a/include/drm/bridge/dw_hdmi.h
|
|
+++ b/include/drm/bridge/dw_hdmi.h
|
|
@@ -152,7 +152,8 @@ struct dw_hdmi_plat_data {
|
|
const struct dw_hdmi_curr_ctrl *cur_ctr;
|
|
const struct dw_hdmi_phy_config *phy_config;
|
|
int (*configure_phy)(struct dw_hdmi *hdmi, void *data,
|
|
- unsigned long mpixelclock);
|
|
+ unsigned long mpixelclock,
|
|
+ unsigned long mtmdsclock);
|
|
};
|
|
|
|
struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev,
|
|
|
|
From 1f152929c7bb18b6349fffbc06a003007e5e3783 Mon Sep 17 00:00:00 2001
|
|
From: Jonas Karlman <jonas@kwiboo.se>
|
|
Date: Mon, 20 Jul 2020 21:34:48 +0000
|
|
Subject: [PATCH] drm/bridge: dw-hdmi: support configuring phy for deep color
|
|
|
|
Q: Should we rename dw_hdmi_curr_ctrl and dw_hdmi_phy_config mpixelclock to mtmdsclock ?
|
|
|
|
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
|
---
|
|
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 17 ++++++++++++-----
|
|
1 file changed, 12 insertions(+), 5 deletions(-)
|
|
|
|
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
|
index c25d5ac7bb07..bcdd823907c2 100644
|
|
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
|
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
|
@@ -1448,6 +1448,7 @@ static int hdmi_phy_configure_dwc_hdmi_3d_tx(struct dw_hdmi *hdmi,
|
|
const struct dw_hdmi_mpll_config *mpll_config = pdata->mpll_cfg;
|
|
const struct dw_hdmi_curr_ctrl *curr_ctrl = pdata->cur_ctr;
|
|
const struct dw_hdmi_phy_config *phy_config = pdata->phy_config;
|
|
+ int depth;
|
|
|
|
/* TOFIX Will need 420 specific PHY configuration tables */
|
|
|
|
@@ -1457,11 +1458,11 @@ static int hdmi_phy_configure_dwc_hdmi_3d_tx(struct dw_hdmi *hdmi,
|
|
break;
|
|
|
|
for (; curr_ctrl->mpixelclock != ~0UL; curr_ctrl++)
|
|
- if (mpixelclock <= curr_ctrl->mpixelclock)
|
|
+ if (mtmdsclock <= curr_ctrl->mpixelclock)
|
|
break;
|
|
|
|
for (; phy_config->mpixelclock != ~0UL; phy_config++)
|
|
- if (mpixelclock <= phy_config->mpixelclock)
|
|
+ if (mtmdsclock <= phy_config->mpixelclock)
|
|
break;
|
|
|
|
if (mpll_config->mpixelclock == ~0UL ||
|
|
@@ -1469,11 +1470,17 @@ static int hdmi_phy_configure_dwc_hdmi_3d_tx(struct dw_hdmi *hdmi,
|
|
phy_config->mpixelclock == ~0UL)
|
|
return -EINVAL;
|
|
|
|
- dw_hdmi_phy_i2c_write(hdmi, mpll_config->res[0].cpce,
|
|
+ depth = hdmi_bus_fmt_color_depth(hdmi->hdmi_data.enc_out_bus_format);
|
|
+ if (depth > 8 && mpixelclock != mtmdsclock)
|
|
+ depth = fls(depth - 8) - 1;
|
|
+ else
|
|
+ depth = 0;
|
|
+
|
|
+ dw_hdmi_phy_i2c_write(hdmi, mpll_config->res[depth].cpce,
|
|
HDMI_3D_TX_PHY_CPCE_CTRL);
|
|
- dw_hdmi_phy_i2c_write(hdmi, mpll_config->res[0].gmp,
|
|
+ dw_hdmi_phy_i2c_write(hdmi, mpll_config->res[depth].gmp,
|
|
HDMI_3D_TX_PHY_GMPCTRL);
|
|
- dw_hdmi_phy_i2c_write(hdmi, curr_ctrl->curr[0],
|
|
+ dw_hdmi_phy_i2c_write(hdmi, curr_ctrl->curr[depth],
|
|
HDMI_3D_TX_PHY_CURRCTRL);
|
|
|
|
dw_hdmi_phy_i2c_write(hdmi, 0, HDMI_3D_TX_PHY_PLLPHBYCTRL);
|
|
|
|
From 9c5117c0b3a6d5a128c6ce2102f8e81676752978 Mon Sep 17 00:00:00 2001
|
|
From: Jonas Karlman <jonas@kwiboo.se>
|
|
Date: Mon, 20 Jul 2020 22:25:15 +0000
|
|
Subject: [PATCH] drm/bridge: dw-hdmi: add mpll_cfg_420 for ycbcr420 mode
|
|
|
|
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
|
---
|
|
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 4 +++-
|
|
include/drm/bridge/dw_hdmi.h | 1 +
|
|
2 files changed, 4 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
|
index bcdd823907c2..f5d048adf649 100644
|
|
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
|
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
|
@@ -1450,7 +1450,9 @@ static int hdmi_phy_configure_dwc_hdmi_3d_tx(struct dw_hdmi *hdmi,
|
|
const struct dw_hdmi_phy_config *phy_config = pdata->phy_config;
|
|
int depth;
|
|
|
|
- /* TOFIX Will need 420 specific PHY configuration tables */
|
|
+ if (hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format) &&
|
|
+ pdata->mpll_cfg_420)
|
|
+ mpll_config = pdata->mpll_cfg_420;
|
|
|
|
/* PLL/MPLL Cfg - always match on final entry */
|
|
for (; mpll_config->mpixelclock != ~0UL; mpll_config++)
|
|
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
|
|
index 4f61ede6486d..0ebe01835d2a 100644
|
|
--- a/include/drm/bridge/dw_hdmi.h
|
|
+++ b/include/drm/bridge/dw_hdmi.h
|
|
@@ -149,6 +149,7 @@ struct dw_hdmi_plat_data {
|
|
|
|
/* Synopsys PHY support */
|
|
const struct dw_hdmi_mpll_config *mpll_cfg;
|
|
+ const struct dw_hdmi_mpll_config *mpll_cfg_420;
|
|
const struct dw_hdmi_curr_ctrl *cur_ctr;
|
|
const struct dw_hdmi_phy_config *phy_config;
|
|
int (*configure_phy)(struct dw_hdmi *hdmi, void *data,
|
|
|
|
From dadb0b7e99a25a71a8b9e41d6cb154cb2ddf856e Mon Sep 17 00:00:00 2001
|
|
From: Jonas Karlman <jonas@kwiboo.se>
|
|
Date: Wed, 15 Jul 2020 09:49:21 +0000
|
|
Subject: [PATCH] drm/rockchip: dw-hdmi: mode_valid: allow 420 clock rate
|
|
|
|
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
|
---
|
|
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 12 ++++++++++--
|
|
1 file changed, 10 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
|
index 745fd1c13cef..9784111ea746 100644
|
|
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
|
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
|
@@ -222,8 +222,15 @@ dw_hdmi_rockchip_mode_valid(struct dw_hdmi *hdmi, void *data,
|
|
const struct drm_display_info *info,
|
|
const struct drm_display_mode *mode)
|
|
{
|
|
- if (mode->clock > 340000 ||
|
|
- (info->max_tmds_clock && mode->clock > info->max_tmds_clock))
|
|
+ struct dw_hdmi_plat_data *pdata = (struct dw_hdmi_plat_data *)data;
|
|
+ int clock = mode->clock;
|
|
+
|
|
+ if (pdata->ycbcr_420_allowed && drm_mode_is_420(info, mode) &&
|
|
+ (info->color_formats & DRM_COLOR_FORMAT_YCRCB420))
|
|
+ clock /= 2;
|
|
+
|
|
+ if (clock > 340000 ||
|
|
+ (info->max_tmds_clock && clock > info->max_tmds_clock))
|
|
return MODE_CLOCK_HIGH;
|
|
|
|
return drm_mode_validate_size(mode, 3840, 2160);
|
|
@@ -524,6 +531,7 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
|
|
|
|
hdmi->dev = &pdev->dev;
|
|
hdmi->chip_data = plat_data->phy_data;
|
|
+ plat_data->priv_data = plat_data;
|
|
plat_data->phy_data = hdmi;
|
|
encoder = &hdmi->encoder;
|
|
|
|
|
|
From 0f936ce17398a9cee1be5027cf86b44430fcd23e Mon Sep 17 00:00:00 2001
|
|
From: Jonas Karlman <jonas@kwiboo.se>
|
|
Date: Mon, 20 Jul 2020 22:26:19 +0000
|
|
Subject: [PATCH] drm/rockchip: dw-hdmi: rk3399: add mpll_cfg_420
|
|
|
|
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
|
---
|
|
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 41 +++++++++++++++++++++
|
|
1 file changed, 41 insertions(+)
|
|
|
|
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
|
index 9784111ea746..e7fbeb9132fb 100644
|
|
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
|
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
|
@@ -166,6 +166,46 @@ static const struct dw_hdmi_mpll_config rockchip_mpll_cfg[] = {
|
|
}
|
|
};
|
|
|
|
+static const struct dw_hdmi_mpll_config rockchip_mpll_cfg_420[] = {
|
|
+ {
|
|
+ 30666000, {
|
|
+ { 0x00b7, 0x0000 },
|
|
+ { 0x2157, 0x0000 },
|
|
+ { 0x40f7, 0x0000 },
|
|
+ },
|
|
+ }, {
|
|
+ 92000000, {
|
|
+ { 0x00b7, 0x0000 },
|
|
+ { 0x2143, 0x0001 },
|
|
+ { 0x40a3, 0x0001 },
|
|
+ },
|
|
+ }, {
|
|
+ 184000000, {
|
|
+ { 0x0073, 0x0001 },
|
|
+ { 0x2146, 0x0002 },
|
|
+ { 0x4062, 0x0002 },
|
|
+ },
|
|
+ }, {
|
|
+ 340000000, {
|
|
+ { 0x0052, 0x0003 },
|
|
+ { 0x214d, 0x0003 },
|
|
+ { 0x4065, 0x0003 },
|
|
+ },
|
|
+ }, {
|
|
+ 600000000, {
|
|
+ { 0x0041, 0x0003 },
|
|
+ { 0x3b4d, 0x0003 },
|
|
+ { 0x5a65, 0x0003 },
|
|
+ },
|
|
+ }, {
|
|
+ ~0UL, {
|
|
+ { 0x0000, 0x0000 },
|
|
+ { 0x0000, 0x0000 },
|
|
+ { 0x0000, 0x0000 },
|
|
+ },
|
|
+ }
|
|
+};
|
|
+
|
|
static const struct dw_hdmi_curr_ctrl rockchip_cur_ctr[] = {
|
|
/* pixelclk bpp8 bpp10 bpp12 */
|
|
{
|
|
@@ -481,6 +521,7 @@ static struct rockchip_hdmi_chip_data rk3399_chip_data = {
|
|
static const struct dw_hdmi_plat_data rk3399_hdmi_drv_data = {
|
|
.mode_valid = dw_hdmi_rockchip_mode_valid,
|
|
.mpll_cfg = rockchip_mpll_cfg,
|
|
+ .mpll_cfg_420 = rockchip_mpll_cfg_420,
|
|
.cur_ctr = rockchip_cur_ctr,
|
|
.phy_config = rockchip_phy_config,
|
|
.phy_data = &rk3399_chip_data,
|
|
|
|
From 240069c903db02016afcbacbde7a292d651eeb36 Mon Sep 17 00:00:00 2001
|
|
From: Jonas Karlman <jonas@kwiboo.se>
|
|
Date: Fri, 20 Dec 2019 08:12:43 +0000
|
|
Subject: [PATCH] WIP: drm/bridge: dw-hdmi: limit mode and bus format to
|
|
max_tmds_clock
|
|
|
|
---
|
|
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 120 ++++++++++++++--------
|
|
1 file changed, 76 insertions(+), 44 deletions(-)
|
|
|
|
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
|
index f5d048adf649..26c64cf2d00a 100644
|
|
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
|
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
|
@@ -1859,6 +1859,21 @@ static void hdmi_config_drm_infoframe(struct dw_hdmi *hdmi,
|
|
HDMI_FC_PACKET_TX_EN_DRM_MASK, HDMI_FC_PACKET_TX_EN);
|
|
}
|
|
|
|
+static unsigned int
|
|
+hdmi_get_tmdsclock(unsigned int bus_format, unsigned int pixelclock)
|
|
+{
|
|
+ int color_depth = hdmi_bus_fmt_color_depth(bus_format);
|
|
+ unsigned int tmdsclock = pixelclock;
|
|
+
|
|
+ if (!hdmi_bus_fmt_is_yuv422(bus_format) && color_depth > 8)
|
|
+ tmdsclock = (u64)pixelclock * color_depth / 8;
|
|
+
|
|
+ if (hdmi_bus_fmt_is_yuv420(bus_format))
|
|
+ tmdsclock /= 2;
|
|
+
|
|
+ return tmdsclock;
|
|
+}
|
|
+
|
|
static void hdmi_av_composer(struct dw_hdmi *hdmi,
|
|
const struct drm_display_info *display,
|
|
const struct drm_display_mode *mode)
|
|
@@ -1870,29 +1885,11 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
|
|
unsigned int vdisplay, hdisplay;
|
|
|
|
vmode->mpixelclock = mode->clock * 1000;
|
|
+ vmode->mtmdsclock =
|
|
+ hdmi_get_tmdsclock(hdmi->hdmi_data.enc_out_bus_format,
|
|
+ vmode->mpixelclock);
|
|
|
|
dev_dbg(hdmi->dev, "final pixclk = %d\n", vmode->mpixelclock);
|
|
-
|
|
- vmode->mtmdsclock = vmode->mpixelclock;
|
|
-
|
|
- if (!hdmi_bus_fmt_is_yuv422(hdmi->hdmi_data.enc_out_bus_format)) {
|
|
- switch (hdmi_bus_fmt_color_depth(
|
|
- hdmi->hdmi_data.enc_out_bus_format)) {
|
|
- case 16:
|
|
- vmode->mtmdsclock = vmode->mpixelclock * 2;
|
|
- break;
|
|
- case 12:
|
|
- vmode->mtmdsclock = vmode->mpixelclock * 3 / 2;
|
|
- break;
|
|
- case 10:
|
|
- vmode->mtmdsclock = vmode->mpixelclock * 5 / 4;
|
|
- break;
|
|
- }
|
|
- }
|
|
-
|
|
- if (hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format))
|
|
- vmode->mtmdsclock /= 2;
|
|
-
|
|
dev_dbg(hdmi->dev, "final tmdsclock = %d\n", vmode->mtmdsclock);
|
|
|
|
/* Set up HDMI_FC_INVIDCONF */
|
|
@@ -2550,8 +2547,21 @@ static int dw_hdmi_connector_create(struct dw_hdmi *hdmi)
|
|
* - MEDIA_BUS_FMT_RGB888_1X24,
|
|
*/
|
|
|
|
-/* Can return a maximum of 11 possible output formats for a mode/connector */
|
|
-#define MAX_OUTPUT_SEL_FORMATS 11
|
|
+/* Can return a maximum of 15 possible output formats for a mode/connector */
|
|
+#define MAX_OUTPUT_SEL_FORMATS 15
|
|
+
|
|
+static bool is_tmds_allowed(struct drm_display_info *info,
|
|
+ struct drm_display_mode *mode,
|
|
+ u32 bus_format)
|
|
+{
|
|
+ unsigned long tmdsclock = hdmi_get_tmdsclock(bus_format, mode->clock);
|
|
+ int max_tmds_clock = info->max_tmds_clock ? info->max_tmds_clock : 340000;
|
|
+
|
|
+ if (max_tmds_clock >= tmdsclock)
|
|
+ return true;
|
|
+
|
|
+ return false;
|
|
+}
|
|
|
|
static u32 *dw_hdmi_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge,
|
|
struct drm_bridge_state *bridge_state,
|
|
@@ -2563,8 +2573,6 @@ static u32 *dw_hdmi_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge,
|
|
struct drm_display_info *info = &conn->display_info;
|
|
struct drm_display_mode *mode = &crtc_state->mode;
|
|
u8 max_bpc = conn_state->max_requested_bpc;
|
|
- bool is_hdmi2_sink = info->hdmi.scdc.supported ||
|
|
- (info->color_formats & DRM_COLOR_FORMAT_YCRCB420);
|
|
u32 *output_fmts;
|
|
unsigned int i = 0;
|
|
|
|
@@ -2587,29 +2595,33 @@ static u32 *dw_hdmi_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge,
|
|
* If the current mode enforces 4:2:0, force the output but format
|
|
* to 4:2:0 and do not add the YUV422/444/RGB formats
|
|
*/
|
|
- if (conn->ycbcr_420_allowed &&
|
|
- (drm_mode_is_420_only(info, mode) ||
|
|
- (is_hdmi2_sink && drm_mode_is_420_also(info, mode)))) {
|
|
+ if (conn->ycbcr_420_allowed && drm_mode_is_420(info, mode) &&
|
|
+ (info->color_formats & DRM_COLOR_FORMAT_YCRCB420)) {
|
|
|
|
/* Order bus formats from 16bit to 8bit if supported */
|
|
if (max_bpc >= 16 && info->bpc == 16 &&
|
|
- (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_48))
|
|
+ (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_48) &&
|
|
+ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_UYYVYY16_0_5X48))
|
|
output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY16_0_5X48;
|
|
|
|
if (max_bpc >= 12 && info->bpc >= 12 &&
|
|
- (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_36))
|
|
+ (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_36) &&
|
|
+ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_UYYVYY12_0_5X36))
|
|
output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY12_0_5X36;
|
|
|
|
if (max_bpc >= 10 && info->bpc >= 10 &&
|
|
- (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_30))
|
|
+ (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_30) &&
|
|
+ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_UYYVYY10_0_5X30))
|
|
output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY10_0_5X30;
|
|
|
|
/* Default 8bit fallback */
|
|
- output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY8_0_5X24;
|
|
+ if (is_tmds_allowed(info, mode, MEDIA_BUS_FMT_UYYVYY8_0_5X24))
|
|
+ output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY8_0_5X24;
|
|
|
|
*num_output_fmts = i;
|
|
|
|
- return output_fmts;
|
|
+ if (drm_mode_is_420_only(info, mode))
|
|
+ return output_fmts;
|
|
}
|
|
|
|
/*
|
|
@@ -2618,40 +2630,51 @@ static u32 *dw_hdmi_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge,
|
|
*/
|
|
|
|
if (max_bpc >= 16 && info->bpc == 16) {
|
|
- if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
|
|
+ if ((info->color_formats & DRM_COLOR_FORMAT_YCRCB444) &&
|
|
+ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_YUV16_1X48))
|
|
output_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48;
|
|
|
|
- output_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48;
|
|
+ if (is_tmds_allowed(info, mode, MEDIA_BUS_FMT_RGB161616_1X48))
|
|
+ output_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48;
|
|
}
|
|
|
|
if (max_bpc >= 12 && info->bpc >= 12) {
|
|
- if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422)
|
|
+ if ((info->color_formats & DRM_COLOR_FORMAT_YCRCB422) &&
|
|
+ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_UYVY12_1X24))
|
|
output_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
|
|
|
|
- if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
|
|
+ if ((info->color_formats & DRM_COLOR_FORMAT_YCRCB444) &&
|
|
+ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_YUV12_1X36))
|
|
output_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
|
|
|
|
- output_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
|
|
+ if (is_tmds_allowed(info, mode, MEDIA_BUS_FMT_RGB121212_1X36))
|
|
+ output_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
|
|
}
|
|
|
|
if (max_bpc >= 10 && info->bpc >= 10) {
|
|
- if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422)
|
|
+ if ((info->color_formats & DRM_COLOR_FORMAT_YCRCB422) &&
|
|
+ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_UYVY10_1X20))
|
|
output_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
|
|
|
|
- if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
|
|
+ if ((info->color_formats & DRM_COLOR_FORMAT_YCRCB444) &&
|
|
+ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_YUV10_1X30))
|
|
output_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
|
|
|
|
- output_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
|
|
+ if (is_tmds_allowed(info, mode, MEDIA_BUS_FMT_RGB101010_1X30))
|
|
+ output_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
|
|
}
|
|
|
|
- if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422)
|
|
+ if ((info->color_formats & DRM_COLOR_FORMAT_YCRCB422) &&
|
|
+ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_UYVY8_1X16))
|
|
output_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
|
|
|
|
- if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
|
|
+ if ((info->color_formats & DRM_COLOR_FORMAT_YCRCB444) &&
|
|
+ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_YUV8_1X24))
|
|
output_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
|
|
|
|
/* Default 8bit RGB fallback */
|
|
- output_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
|
|
+ if (is_tmds_allowed(info, mode, MEDIA_BUS_FMT_RGB888_1X24))
|
|
+ output_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
|
|
|
|
*num_output_fmts = i;
|
|
|
|
@@ -2831,11 +2854,20 @@ dw_hdmi_bridge_mode_valid(struct drm_bridge *bridge,
|
|
struct dw_hdmi *hdmi = bridge->driver_private;
|
|
const struct dw_hdmi_plat_data *pdata = hdmi->plat_data;
|
|
enum drm_mode_status mode_status = MODE_OK;
|
|
+ int max_tmds_clock = info->max_tmds_clock ? info->max_tmds_clock : 340000;
|
|
+ int clock = mode->clock;
|
|
|
|
/* We don't support double-clocked modes */
|
|
if (mode->flags & DRM_MODE_FLAG_DBLCLK)
|
|
return MODE_BAD;
|
|
|
|
+ if (pdata->ycbcr_420_allowed && drm_mode_is_420(info, mode) &&
|
|
+ (info->color_formats & DRM_COLOR_FORMAT_YCRCB420))
|
|
+ clock /= 2;
|
|
+
|
|
+ if (clock > max_tmds_clock)
|
|
+ return MODE_CLOCK_HIGH;
|
|
+
|
|
if (pdata->mode_valid)
|
|
mode_status = pdata->mode_valid(hdmi, pdata->priv_data, info,
|
|
mode);
|
|
|
|
From 636c91cfca72fb0c6b8c5e8084867d74491b5dfa Mon Sep 17 00:00:00 2001
|
|
From: Jonas Karlman <jonas@kwiboo.se>
|
|
Date: Fri, 20 Dec 2019 08:12:42 +0000
|
|
Subject: [PATCH] WIP: drm/rockchip: dw_hdmi: add 10-bit rgb bus format
|
|
|
|
---
|
|
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 41 +++++++++++++++++++++
|
|
drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 2 +
|
|
2 files changed, 43 insertions(+)
|
|
|
|
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
|
index e7fbeb9132fb..cd87ee8a65c3 100644
|
|
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
|
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
|
@@ -77,6 +77,7 @@ struct rockchip_hdmi {
|
|
};
|
|
|
|
#define to_rockchip_hdmi(x) container_of(x, struct rockchip_hdmi, x)
|
|
+#define to_crtc_state(x) container_of(x, struct drm_crtc_state, x)
|
|
|
|
static const struct dw_hdmi_mpll_config rockchip_mpll_cfg[] = {
|
|
{
|
|
@@ -282,6 +283,11 @@ dw_hdmi_rockchip_bridge_mode_set(struct drm_bridge *bridge,
|
|
const struct drm_display_mode *adjusted_mode)
|
|
{
|
|
struct rockchip_hdmi *hdmi = to_rockchip_hdmi(bridge);
|
|
+ struct drm_crtc_state *crtc_state = to_crtc_state(adjusted_mode);
|
|
+ struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
|
|
+
|
|
+ if (hdmi->phy)
|
|
+ phy_set_bus_width(hdmi->phy, s->bus_width);
|
|
|
|
clk_set_rate(hdmi->vpll_clk, adjusted_mode->clock * 1000);
|
|
}
|
|
@@ -320,6 +326,7 @@ static void dw_hdmi_rockchip_bridge_enable(struct drm_bridge *bridge)
|
|
static bool is_rgb(u32 format)
|
|
{
|
|
switch (format) {
|
|
+ case MEDIA_BUS_FMT_RGB101010_1X30:
|
|
case MEDIA_BUS_FMT_RGB888_1X24:
|
|
return true;
|
|
default:
|
|
@@ -327,6 +334,16 @@ static bool is_rgb(u32 format)
|
|
}
|
|
}
|
|
|
|
+static bool is_10bit(u32 format)
|
|
+{
|
|
+ switch (format) {
|
|
+ case MEDIA_BUS_FMT_RGB101010_1X30:
|
|
+ return true;
|
|
+ default:
|
|
+ return false;
|
|
+ }
|
|
+}
|
|
+
|
|
static int
|
|
dw_hdmi_rockchip_bridge_atomic_check(struct drm_bridge *bridge,
|
|
struct drm_bridge_state *bridge_state,
|
|
@@ -334,9 +351,24 @@ dw_hdmi_rockchip_bridge_atomic_check(struct drm_bridge *bridge,
|
|
struct drm_connector_state *conn_state)
|
|
{
|
|
struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
|
|
+ struct drm_atomic_state *state = bridge_state->base.state;
|
|
+ struct drm_crtc_state *old_crtc_state;
|
|
+ struct rockchip_crtc_state *old_state;
|
|
+ u32 format = bridge_state->output_bus_cfg.format;
|
|
|
|
s->output_mode = ROCKCHIP_OUT_MODE_AAAA;
|
|
s->output_type = DRM_MODE_CONNECTOR_HDMIA;
|
|
+ s->output_bpc = 10;
|
|
+ s->bus_format = format;
|
|
+ s->bus_width = is_10bit(format) ? 10 : 8;
|
|
+
|
|
+ old_crtc_state = drm_atomic_get_old_crtc_state(state, conn_state->crtc);
|
|
+ if (old_crtc_state && !crtc_state->mode_changed) {
|
|
+ old_state = to_rockchip_crtc_state(old_crtc_state);
|
|
+ if (s->bus_format != old_state->bus_format ||
|
|
+ s->bus_width != old_state->bus_width)
|
|
+ crtc_state->mode_changed = true;
|
|
+ }
|
|
|
|
return 0;
|
|
}
|
|
@@ -348,10 +380,19 @@ static u32 *dw_hdmi_rockchip_get_input_bus_fmts(struct drm_bridge *bridge,
|
|
u32 output_fmt,
|
|
unsigned int *num_input_fmts)
|
|
{
|
|
+ struct rockchip_hdmi *hdmi = to_rockchip_hdmi(bridge);
|
|
+ struct drm_encoder *encoder = bridge->encoder;
|
|
u32 *input_fmt;
|
|
+ bool has_10bit = true;
|
|
|
|
*num_input_fmts = 0;
|
|
|
|
+ if (drm_of_encoder_active_endpoint_id(hdmi->dev->of_node, encoder))
|
|
+ has_10bit = false;
|
|
+
|
|
+ if (!has_10bit && is_10bit(output_fmt))
|
|
+ return NULL;
|
|
+
|
|
if (!is_rgb(output_fmt))
|
|
return NULL;
|
|
|
|
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
|
|
index e33c2dcd0d4b..03944e08b6c7 100644
|
|
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
|
|
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
|
|
@@ -31,6 +31,8 @@ struct rockchip_crtc_state {
|
|
int output_bpc;
|
|
int output_flags;
|
|
bool enable_afbc;
|
|
+ u32 bus_format;
|
|
+ int bus_width;
|
|
};
|
|
#define to_rockchip_crtc_state(s) \
|
|
container_of(s, struct rockchip_crtc_state, base)
|
|
|
|
From ff80104f4a32e591e12358432a85aabc5b436b63 Mon Sep 17 00:00:00 2001
|
|
From: Jonas Karlman <jonas@kwiboo.se>
|
|
Date: Sun, 8 Dec 2019 23:42:44 +0000
|
|
Subject: [PATCH] WIP: drm: dw-hdmi: add content type connector property
|
|
|
|
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
|
---
|
|
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 8 +++++++-
|
|
1 file changed, 7 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
|
index 26c64cf2d00a..ffb72e6874c8 100644
|
|
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
|
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
|
@@ -1646,6 +1646,7 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi,
|
|
const struct drm_connector *connector,
|
|
const struct drm_display_mode *mode)
|
|
{
|
|
+ const struct drm_connector_state *conn_state = connector->state;
|
|
struct hdmi_avi_infoframe frame;
|
|
u8 val;
|
|
|
|
@@ -1703,6 +1704,8 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi,
|
|
HDMI_EXTENDED_COLORIMETRY_XV_YCC_601;
|
|
}
|
|
|
|
+ drm_hdmi_avi_infoframe_content_type(&frame, conn_state);
|
|
+
|
|
/*
|
|
* The Designware IP uses a different byte format from standard
|
|
* AVI info frames, though generally the bits are in the correct
|
|
@@ -2437,7 +2440,8 @@ static int dw_hdmi_connector_atomic_check(struct drm_connector *connector,
|
|
if (!crtc)
|
|
return 0;
|
|
|
|
- if (!hdr_metadata_equal(old_state, new_state)) {
|
|
+ if (!hdr_metadata_equal(old_state, new_state) ||
|
|
+ old_state->content_type != new_state->content_type) {
|
|
crtc_state = drm_atomic_get_crtc_state(state, crtc);
|
|
if (IS_ERR(crtc_state))
|
|
return PTR_ERR(crtc_state);
|
|
@@ -2505,6 +2509,8 @@ static int dw_hdmi_connector_create(struct dw_hdmi *hdmi)
|
|
|
|
drm_connector_attach_max_bpc_property(connector, 8, 16);
|
|
|
|
+ drm_connector_attach_content_type_property(connector);
|
|
+
|
|
if (hdmi->version >= 0x200a && hdmi->plat_data->use_drm_infoframe)
|
|
drm_object_attach_property(&connector->base,
|
|
connector->dev->mode_config.hdr_output_metadata_property, 0);
|
|
|
|
From 9d3f655dae4e7d01ed64783958c228ab031b723c Mon Sep 17 00:00:00 2001
|
|
From: Jonas Karlman <jonas@kwiboo.se>
|
|
Date: Fri, 20 Dec 2019 08:12:43 +0000
|
|
Subject: [PATCH] WIP: drm/rockchip: add yuv444 support
|
|
|
|
---
|
|
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 30 ++++++++++++++++++++-
|
|
drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 29 ++++++++++++++++++++
|
|
drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 6 +++++
|
|
drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 14 ++++++++++
|
|
4 files changed, 78 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
|
index cd87ee8a65c3..436a9223e5e4 100644
|
|
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
|
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
|
@@ -62,6 +62,7 @@ struct rockchip_hdmi_chip_data {
|
|
int lcdsel_grf_reg;
|
|
u32 lcdsel_big;
|
|
u32 lcdsel_lit;
|
|
+ bool ycbcr_444_allowed;
|
|
};
|
|
|
|
struct rockchip_hdmi {
|
|
@@ -334,10 +335,22 @@ static bool is_rgb(u32 format)
|
|
}
|
|
}
|
|
|
|
+static bool is_yuv444(u32 format)
|
|
+{
|
|
+ switch (format) {
|
|
+ case MEDIA_BUS_FMT_YUV10_1X30:
|
|
+ case MEDIA_BUS_FMT_YUV8_1X24:
|
|
+ return true;
|
|
+ default:
|
|
+ return false;
|
|
+ }
|
|
+}
|
|
+
|
|
static bool is_10bit(u32 format)
|
|
{
|
|
switch (format) {
|
|
case MEDIA_BUS_FMT_RGB101010_1X30:
|
|
+ case MEDIA_BUS_FMT_YUV10_1X30:
|
|
return true;
|
|
default:
|
|
return false;
|
|
@@ -354,12 +367,22 @@ dw_hdmi_rockchip_bridge_atomic_check(struct drm_bridge *bridge,
|
|
struct drm_atomic_state *state = bridge_state->base.state;
|
|
struct drm_crtc_state *old_crtc_state;
|
|
struct rockchip_crtc_state *old_state;
|
|
+ struct drm_bridge *next_bridge;
|
|
+ struct drm_bridge_state *next_bridge_state;
|
|
u32 format = bridge_state->output_bus_cfg.format;
|
|
|
|
s->output_mode = ROCKCHIP_OUT_MODE_AAAA;
|
|
s->output_type = DRM_MODE_CONNECTOR_HDMIA;
|
|
s->output_bpc = 10;
|
|
s->bus_format = format;
|
|
+
|
|
+ next_bridge = drm_bridge_get_next_bridge(bridge);
|
|
+ if (next_bridge) {
|
|
+ next_bridge_state = drm_atomic_get_new_bridge_state(state,
|
|
+ next_bridge);
|
|
+ format = next_bridge_state->output_bus_cfg.format;
|
|
+ }
|
|
+
|
|
s->bus_width = is_10bit(format) ? 10 : 8;
|
|
|
|
old_crtc_state = drm_atomic_get_old_crtc_state(state, conn_state->crtc);
|
|
@@ -393,7 +416,10 @@ static u32 *dw_hdmi_rockchip_get_input_bus_fmts(struct drm_bridge *bridge,
|
|
if (!has_10bit && is_10bit(output_fmt))
|
|
return NULL;
|
|
|
|
- if (!is_rgb(output_fmt))
|
|
+ if (is_yuv444(output_fmt)) {
|
|
+ if (!hdmi->chip_data->ycbcr_444_allowed)
|
|
+ return NULL;
|
|
+ } else if (!is_rgb(output_fmt))
|
|
return NULL;
|
|
|
|
input_fmt = kzalloc(sizeof(*input_fmt), GFP_KERNEL);
|
|
@@ -542,6 +568,7 @@ static const struct dw_hdmi_phy_ops rk3328_hdmi_phy_ops = {
|
|
|
|
static struct rockchip_hdmi_chip_data rk3328_chip_data = {
|
|
.lcdsel_grf_reg = -1,
|
|
+ .ycbcr_444_allowed = true,
|
|
};
|
|
|
|
static const struct dw_hdmi_plat_data rk3328_hdmi_drv_data = {
|
|
@@ -557,6 +584,7 @@ static struct rockchip_hdmi_chip_data rk3399_chip_data = {
|
|
.lcdsel_grf_reg = RK3399_GRF_SOC_CON20,
|
|
.lcdsel_big = HIWORD_UPDATE(0, RK3399_HDMI_LCDC_SEL),
|
|
.lcdsel_lit = HIWORD_UPDATE(RK3399_HDMI_LCDC_SEL, RK3399_HDMI_LCDC_SEL),
|
|
+ .ycbcr_444_allowed = true,
|
|
};
|
|
|
|
static const struct dw_hdmi_plat_data rk3399_hdmi_drv_data = {
|
|
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
|
|
index 5ab1412173a7..a17bd4e90ba7 100644
|
|
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
|
|
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
|
|
@@ -310,6 +310,17 @@ static int vop_convert_afbc_format(uint32_t format)
|
|
return -EINVAL;
|
|
}
|
|
|
|
+static bool is_yuv_output(uint32_t bus_format)
|
|
+{
|
|
+ switch (bus_format) {
|
|
+ case MEDIA_BUS_FMT_YUV8_1X24:
|
|
+ case MEDIA_BUS_FMT_YUV10_1X30:
|
|
+ return true;
|
|
+ default:
|
|
+ return false;
|
|
+ }
|
|
+}
|
|
+
|
|
static uint16_t scl_vop_cal_scale(enum scale_mode mode, uint32_t src,
|
|
uint32_t dst, bool is_horizontal,
|
|
int vsu_mode, int *vskiplines)
|
|
@@ -1329,6 +1340,7 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc,
|
|
u16 vact_end = vact_st + vdisplay;
|
|
uint32_t pin_pol, val;
|
|
int dither_bpc = s->output_bpc ? s->output_bpc : 10;
|
|
+ bool yuv_output = is_yuv_output(s->bus_format);
|
|
int ret;
|
|
|
|
if (old_state && old_state->self_refresh_active) {
|
|
@@ -1402,6 +1414,8 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc,
|
|
!(vop_data->feature & VOP_FEATURE_OUTPUT_RGB10))
|
|
s->output_mode = ROCKCHIP_OUT_MODE_P888;
|
|
|
|
+ VOP_REG_SET(vop, common, dsp_data_swap, yuv_output ? 2 : 0);
|
|
+
|
|
if (s->output_mode == ROCKCHIP_OUT_MODE_AAAA && dither_bpc <= 8)
|
|
VOP_REG_SET(vop, common, pre_dither_down, 1);
|
|
else
|
|
@@ -1417,6 +1431,21 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc,
|
|
|
|
VOP_REG_SET(vop, common, out_mode, s->output_mode);
|
|
|
|
+ VOP_REG_SET(vop, common, overlay_mode, yuv_output);
|
|
+ VOP_REG_SET(vop, common, dsp_out_yuv, yuv_output);
|
|
+
|
|
+ /*
|
|
+ * Background color is 10bit depth if vop version >= 3.5
|
|
+ */
|
|
+ if (!yuv_output)
|
|
+ val = 0;
|
|
+ else if (VOP_MAJOR(vop_data->version) == 3 &&
|
|
+ VOP_MINOR(vop_data->version) >= 5)
|
|
+ val = 0x20010200;
|
|
+ else
|
|
+ val = 0x801080;
|
|
+ VOP_REG_SET(vop, common, dsp_background, val);
|
|
+
|
|
VOP_REG_SET(vop, modeset, htotal_pw, (htotal << 16) | hsync_len);
|
|
val = hact_st << 16;
|
|
val |= hact_end;
|
|
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
|
|
index 1516231bbf93..b820ad3fa091 100644
|
|
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
|
|
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
|
|
@@ -92,10 +92,16 @@ struct vop_common {
|
|
struct vop_reg mmu_en;
|
|
struct vop_reg out_mode;
|
|
struct vop_reg standby;
|
|
+
|
|
+ struct vop_reg overlay_mode;
|
|
+ struct vop_reg dsp_data_swap;
|
|
+ struct vop_reg dsp_out_yuv;
|
|
+ struct vop_reg dsp_background;
|
|
};
|
|
|
|
struct vop_misc {
|
|
struct vop_reg global_regdone_en;
|
|
+ struct vop_reg win_channel[4];
|
|
};
|
|
|
|
struct vop_intr {
|
|
diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
|
|
index 57c36e9207c1..800b9341dd42 100644
|
|
--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
|
|
+++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
|
|
@@ -644,6 +644,11 @@ static const struct vop_common rk3288_common = {
|
|
.dsp_blank = VOP_REG(RK3288_DSP_CTRL0, 0x3, 18),
|
|
.out_mode = VOP_REG(RK3288_DSP_CTRL0, 0xf, 0),
|
|
.cfg_done = VOP_REG_SYNC(RK3288_REG_CFG_DONE, 0x1, 0),
|
|
+
|
|
+ .overlay_mode = VOP_REG(RK3288_SYS_CTRL, 0x1, 16),
|
|
+ .dsp_data_swap = VOP_REG(RK3288_DSP_CTRL0, 0x1f, 12),
|
|
+ .dsp_out_yuv = VOP_REG(RK3288_POST_SCL_CTRL, 0x1, 2),
|
|
+ .dsp_background = VOP_REG(RK3288_DSP_BG, 0xffffffff, 0),
|
|
};
|
|
|
|
/*
|
|
@@ -996,6 +1001,10 @@ static const struct vop_output rk3328_output = {
|
|
|
|
static const struct vop_misc rk3328_misc = {
|
|
.global_regdone_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 11),
|
|
+
|
|
+ .win_channel[0] = VOP_REG(RK3328_WIN0_CTRL2, 0xff, 0),
|
|
+ .win_channel[1] = VOP_REG(RK3328_WIN1_CTRL2, 0xff, 0),
|
|
+ .win_channel[2] = VOP_REG(RK3328_WIN2_CTRL2, 0xff, 0),
|
|
};
|
|
|
|
static const struct vop_common rk3328_common = {
|
|
@@ -1008,6 +1017,11 @@ static const struct vop_common rk3328_common = {
|
|
.dsp_blank = VOP_REG(RK3328_DSP_CTRL0, 0x3, 18),
|
|
.out_mode = VOP_REG(RK3328_DSP_CTRL0, 0xf, 0),
|
|
.cfg_done = VOP_REG_SYNC(RK3328_REG_CFG_DONE, 0x1, 0),
|
|
+
|
|
+ .overlay_mode = VOP_REG(RK3328_SYS_CTRL, 0x1, 16),
|
|
+ .dsp_data_swap = VOP_REG(RK3328_DSP_CTRL0, 0x1f, 12),
|
|
+ .dsp_out_yuv = VOP_REG(RK3328_POST_SCL_CTRL, 0x1, 2),
|
|
+ .dsp_background = VOP_REG(RK3328_DSP_BG, 0xffffffff, 0),
|
|
};
|
|
|
|
static const struct vop_intr rk3328_vop_intr = {
|
|
|
|
From 32b8598b1300eb3efd9e01b7afe0b6ca86b15123 Mon Sep 17 00:00:00 2001
|
|
From: Jonas Karlman <jonas@kwiboo.se>
|
|
Date: Fri, 20 Dec 2019 08:12:43 +0000
|
|
Subject: [PATCH] WIP: drm/rockchip: add yuv420 support
|
|
|
|
---
|
|
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 23 +++++++++++++++++++++
|
|
drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 18 +++++++++++++++-
|
|
drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 10 +++++----
|
|
drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 2 ++
|
|
4 files changed, 48 insertions(+), 5 deletions(-)
|
|
|
|
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
|
index 436a9223e5e4..1abc46a023a4 100644
|
|
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
|
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
|
@@ -346,9 +346,21 @@ static bool is_yuv444(u32 format)
|
|
}
|
|
}
|
|
|
|
+static bool is_yuv420(u32 format)
|
|
+{
|
|
+ switch (format) {
|
|
+ case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
|
|
+ case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
|
|
+ return true;
|
|
+ default:
|
|
+ return false;
|
|
+ }
|
|
+}
|
|
+
|
|
static bool is_10bit(u32 format)
|
|
{
|
|
switch (format) {
|
|
+ case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
|
|
case MEDIA_BUS_FMT_RGB101010_1X30:
|
|
case MEDIA_BUS_FMT_YUV10_1X30:
|
|
return true;
|
|
@@ -385,6 +397,11 @@ dw_hdmi_rockchip_bridge_atomic_check(struct drm_bridge *bridge,
|
|
|
|
s->bus_width = is_10bit(format) ? 10 : 8;
|
|
|
|
+ if (is_yuv420(format)) {
|
|
+ s->output_mode = ROCKCHIP_OUT_MODE_YUV420;
|
|
+ s->bus_width /= 2;
|
|
+ }
|
|
+
|
|
old_crtc_state = drm_atomic_get_old_crtc_state(state, conn_state->crtc);
|
|
if (old_crtc_state && !crtc_state->mode_changed) {
|
|
old_state = to_rockchip_crtc_state(old_crtc_state);
|
|
@@ -405,6 +422,7 @@ static u32 *dw_hdmi_rockchip_get_input_bus_fmts(struct drm_bridge *bridge,
|
|
{
|
|
struct rockchip_hdmi *hdmi = to_rockchip_hdmi(bridge);
|
|
struct drm_encoder *encoder = bridge->encoder;
|
|
+ struct drm_connector *connector = conn_state->connector;
|
|
u32 *input_fmt;
|
|
bool has_10bit = true;
|
|
|
|
@@ -419,6 +437,9 @@ static u32 *dw_hdmi_rockchip_get_input_bus_fmts(struct drm_bridge *bridge,
|
|
if (is_yuv444(output_fmt)) {
|
|
if (!hdmi->chip_data->ycbcr_444_allowed)
|
|
return NULL;
|
|
+ } else if (is_yuv420(output_fmt)) {
|
|
+ if (!connector->ycbcr_420_allowed)
|
|
+ return NULL;
|
|
} else if (!is_rgb(output_fmt))
|
|
return NULL;
|
|
|
|
@@ -578,6 +599,7 @@ static const struct dw_hdmi_plat_data rk3328_hdmi_drv_data = {
|
|
.phy_name = "inno_dw_hdmi_phy2",
|
|
.phy_force_vendor = true,
|
|
.use_drm_infoframe = true,
|
|
+ .ycbcr_420_allowed = true,
|
|
};
|
|
|
|
static struct rockchip_hdmi_chip_data rk3399_chip_data = {
|
|
@@ -595,6 +617,7 @@ static const struct dw_hdmi_plat_data rk3399_hdmi_drv_data = {
|
|
.phy_config = rockchip_phy_config,
|
|
.phy_data = &rk3399_chip_data,
|
|
.use_drm_infoframe = true,
|
|
+ .ycbcr_420_allowed = true,
|
|
};
|
|
|
|
static const struct of_device_id dw_hdmi_rockchip_dt_ids[] = {
|
|
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
|
|
index a17bd4e90ba7..5ea8031eb0f7 100644
|
|
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
|
|
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
|
|
@@ -311,6 +311,19 @@ static int vop_convert_afbc_format(uint32_t format)
|
|
}
|
|
|
|
static bool is_yuv_output(uint32_t bus_format)
|
|
+{
|
|
+ switch (bus_format) {
|
|
+ case MEDIA_BUS_FMT_YUV8_1X24:
|
|
+ case MEDIA_BUS_FMT_YUV10_1X30:
|
|
+ case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
|
|
+ case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
|
|
+ return true;
|
|
+ default:
|
|
+ return false;
|
|
+ }
|
|
+}
|
|
+
|
|
+static bool has_uv_swapped(uint32_t bus_format)
|
|
{
|
|
switch (bus_format) {
|
|
case MEDIA_BUS_FMT_YUV8_1X24:
|
|
@@ -1414,7 +1427,7 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc,
|
|
!(vop_data->feature & VOP_FEATURE_OUTPUT_RGB10))
|
|
s->output_mode = ROCKCHIP_OUT_MODE_P888;
|
|
|
|
- VOP_REG_SET(vop, common, dsp_data_swap, yuv_output ? 2 : 0);
|
|
+ VOP_REG_SET(vop, common, dsp_data_swap, has_uv_swapped(s->bus_format) ? 2 : 0);
|
|
|
|
if (s->output_mode == ROCKCHIP_OUT_MODE_AAAA && dither_bpc <= 8)
|
|
VOP_REG_SET(vop, common, pre_dither_down, 1);
|
|
@@ -1431,6 +1444,9 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc,
|
|
|
|
VOP_REG_SET(vop, common, out_mode, s->output_mode);
|
|
|
|
+ VOP_REG_SET(vop, common, dclk_ddr,
|
|
+ s->output_mode == ROCKCHIP_OUT_MODE_YUV420 ? 1 : 0);
|
|
+
|
|
VOP_REG_SET(vop, common, overlay_mode, yuv_output);
|
|
VOP_REG_SET(vop, common, dsp_out_yuv, yuv_output);
|
|
|
|
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
|
|
index b820ad3fa091..8e6e999e5163 100644
|
|
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
|
|
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
|
|
@@ -94,6 +94,7 @@ struct vop_common {
|
|
struct vop_reg standby;
|
|
|
|
struct vop_reg overlay_mode;
|
|
+ struct vop_reg dclk_ddr;
|
|
struct vop_reg dsp_data_swap;
|
|
struct vop_reg dsp_out_yuv;
|
|
struct vop_reg dsp_background;
|
|
@@ -257,11 +258,12 @@ struct vop_data {
|
|
/*
|
|
* display output interface supported by rockchip lcdc
|
|
*/
|
|
-#define ROCKCHIP_OUT_MODE_P888 0
|
|
-#define ROCKCHIP_OUT_MODE_P666 1
|
|
-#define ROCKCHIP_OUT_MODE_P565 2
|
|
+#define ROCKCHIP_OUT_MODE_P888 0
|
|
+#define ROCKCHIP_OUT_MODE_P666 1
|
|
+#define ROCKCHIP_OUT_MODE_P565 2
|
|
+#define ROCKCHIP_OUT_MODE_YUV420 14
|
|
/* for use special outface */
|
|
-#define ROCKCHIP_OUT_MODE_AAAA 15
|
|
+#define ROCKCHIP_OUT_MODE_AAAA 15
|
|
|
|
/* output flags */
|
|
#define ROCKCHIP_OUTPUT_DSI_DUAL BIT(0)
|
|
diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
|
|
index 800b9341dd42..dd4546f9f410 100644
|
|
--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
|
|
+++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
|
|
@@ -646,6 +646,7 @@ static const struct vop_common rk3288_common = {
|
|
.cfg_done = VOP_REG_SYNC(RK3288_REG_CFG_DONE, 0x1, 0),
|
|
|
|
.overlay_mode = VOP_REG(RK3288_SYS_CTRL, 0x1, 16),
|
|
+ .dclk_ddr = VOP_REG(RK3288_DSP_CTRL0, 0x1, 8),
|
|
.dsp_data_swap = VOP_REG(RK3288_DSP_CTRL0, 0x1f, 12),
|
|
.dsp_out_yuv = VOP_REG(RK3288_POST_SCL_CTRL, 0x1, 2),
|
|
.dsp_background = VOP_REG(RK3288_DSP_BG, 0xffffffff, 0),
|
|
@@ -1019,6 +1020,7 @@ static const struct vop_common rk3328_common = {
|
|
.cfg_done = VOP_REG_SYNC(RK3328_REG_CFG_DONE, 0x1, 0),
|
|
|
|
.overlay_mode = VOP_REG(RK3328_SYS_CTRL, 0x1, 16),
|
|
+ .dclk_ddr = VOP_REG(RK3328_DSP_CTRL0, 0x1, 8),
|
|
.dsp_data_swap = VOP_REG(RK3328_DSP_CTRL0, 0x1f, 12),
|
|
.dsp_out_yuv = VOP_REG(RK3328_POST_SCL_CTRL, 0x1, 2),
|
|
.dsp_background = VOP_REG(RK3328_DSP_BG, 0xffffffff, 0),
|
|
|
|
From bf070727c435df4b370aa6e7fdf0ecba2fd6985c Mon Sep 17 00:00:00 2001
|
|
From: Jonas Karlman <jonas@kwiboo.se>
|
|
Date: Sun, 7 Jun 2020 20:25:25 +0000
|
|
Subject: [PATCH] drm: drm_fourcc: add NV20 and NV30 YUV formats
|
|
|
|
DRM_FORMAT_NV20 and DRM_FORMAT_NV30 formats is the 2x1 and non-subsampled
|
|
variant of NV15, a 10-bit 2-plane YUV format that has no padding between
|
|
components. Instead, luminance and chrominance samples are grouped into 4s
|
|
so that each group is packed into an integer number of bytes:
|
|
|
|
YYYY = UVUV = 4 * 10 bits = 40 bits = 5 bytes
|
|
|
|
The '20' and '30' suffix refers to the optimum effective bits per pixel
|
|
which is achieved when the total number of luminance samples is a multiple
|
|
of 4.
|
|
|
|
V2: Added NV30 format
|
|
|
|
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
|
---
|
|
drivers/gpu/drm/drm_fourcc.c | 8 ++++++++
|
|
include/uapi/drm/drm_fourcc.h | 2 ++
|
|
2 files changed, 10 insertions(+)
|
|
|
|
diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c
|
|
index 722c7ebe4e88..2daf8a304b53 100644
|
|
--- a/drivers/gpu/drm/drm_fourcc.c
|
|
+++ b/drivers/gpu/drm/drm_fourcc.c
|
|
@@ -278,6 +278,14 @@ const struct drm_format_info *__drm_format_info(u32 format)
|
|
.num_planes = 2, .char_per_block = { 5, 5, 0 },
|
|
.block_w = { 4, 2, 0 }, .block_h = { 1, 1, 0 }, .hsub = 2,
|
|
.vsub = 2, .is_yuv = true },
|
|
+ { .format = DRM_FORMAT_NV20, .depth = 0,
|
|
+ .num_planes = 2, .char_per_block = { 5, 5, 0 },
|
|
+ .block_w = { 4, 2, 0 }, .block_h = { 1, 1, 0 }, .hsub = 2,
|
|
+ .vsub = 1, .is_yuv = true },
|
|
+ { .format = DRM_FORMAT_NV30, .depth = 0,
|
|
+ .num_planes = 2, .char_per_block = { 5, 5, 0 },
|
|
+ .block_w = { 4, 2, 0 }, .block_h = { 1, 1, 0 }, .hsub = 1,
|
|
+ .vsub = 1, .is_yuv = true },
|
|
{ .format = DRM_FORMAT_Q410, .depth = 0,
|
|
.num_planes = 3, .char_per_block = { 2, 2, 2 },
|
|
.block_w = { 1, 1, 1 }, .block_h = { 1, 1, 1 }, .hsub = 0,
|
|
diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h
|
|
index 82f327801267..d8e6159213dc 100644
|
|
--- a/include/uapi/drm/drm_fourcc.h
|
|
+++ b/include/uapi/drm/drm_fourcc.h
|
|
@@ -242,6 +242,8 @@ extern "C" {
|
|
* index 1 = Cr:Cb plane, [39:0] Cr1:Cb1:Cr0:Cb0 little endian
|
|
*/
|
|
#define DRM_FORMAT_NV15 fourcc_code('N', 'V', '1', '5') /* 2x2 subsampled Cr:Cb plane */
|
|
+#define DRM_FORMAT_NV20 fourcc_code('N', 'V', '2', '0') /* 2x1 subsampled Cr:Cb plane */
|
|
+#define DRM_FORMAT_NV30 fourcc_code('N', 'V', '3', '0') /* non-subsampled Cr:Cb plane */
|
|
|
|
/*
|
|
* 2 plane YCbCr MSB aligned
|
|
|
|
From f4c0d6f87d4231a92f4337ba8d1b0913eacb963e Mon Sep 17 00:00:00 2001
|
|
From: Jonas Karlman <jonas@kwiboo.se>
|
|
Date: Sun, 7 Jun 2020 20:25:26 +0000
|
|
Subject: [PATCH] drm: rockchip: add NV15, NV20 and NV30 support
|
|
|
|
Add support for displaying 10-bit 4:2:0 and 4:2:2 formats produced by the
|
|
Rockchip Video Decoder on RK322X, RK3288, RK3328, RK3368 and RK3399.
|
|
Also add support for 10-bit 4:4:4 format while at it.
|
|
|
|
V2: Added NV30 support
|
|
|
|
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
|
---
|
|
drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 29 +++++++++++++++++--
|
|
drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 1 +
|
|
drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 32 +++++++++++++++++----
|
|
3 files changed, 54 insertions(+), 8 deletions(-)
|
|
|
|
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
|
|
index 5ea8031eb0f7..413534cf1a93 100644
|
|
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
|
|
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
|
|
@@ -261,6 +261,18 @@ static bool has_rb_swapped(uint32_t format)
|
|
}
|
|
}
|
|
|
|
+static bool is_fmt_10(uint32_t format)
|
|
+{
|
|
+ switch (format) {
|
|
+ case DRM_FORMAT_NV15:
|
|
+ case DRM_FORMAT_NV20:
|
|
+ case DRM_FORMAT_NV30:
|
|
+ return true;
|
|
+ default:
|
|
+ return false;
|
|
+ }
|
|
+}
|
|
+
|
|
static enum vop_data_format vop_convert_format(uint32_t format)
|
|
{
|
|
switch (format) {
|
|
@@ -276,10 +288,13 @@ static enum vop_data_format vop_convert_format(uint32_t format)
|
|
case DRM_FORMAT_BGR565:
|
|
return VOP_FMT_RGB565;
|
|
case DRM_FORMAT_NV12:
|
|
+ case DRM_FORMAT_NV15:
|
|
return VOP_FMT_YUV420SP;
|
|
case DRM_FORMAT_NV16:
|
|
+ case DRM_FORMAT_NV20:
|
|
return VOP_FMT_YUV422SP;
|
|
case DRM_FORMAT_NV24:
|
|
+ case DRM_FORMAT_NV30:
|
|
return VOP_FMT_YUV444SP;
|
|
default:
|
|
DRM_ERROR("unsupported format[%08x]\n", format);
|
|
@@ -946,7 +961,12 @@ static void vop_plane_atomic_update(struct drm_plane *plane,
|
|
dsp_sty = dest->y1 + crtc->mode.vtotal - crtc->mode.vsync_start;
|
|
dsp_st = dsp_sty << 16 | (dsp_stx & 0xffff);
|
|
|
|
- offset = (src->x1 >> 16) * fb->format->cpp[0];
|
|
+ if (fb->format->block_w[0])
|
|
+ offset = (src->x1 >> 16) * fb->format->char_per_block[0] /
|
|
+ fb->format->block_w[0];
|
|
+ else
|
|
+ offset = (src->x1 >> 16) * fb->format->cpp[0];
|
|
+
|
|
offset += (src->y1 >> 16) * fb->pitches[0];
|
|
dma_addr = rk_obj->dma_addr + offset + fb->offsets[0];
|
|
|
|
@@ -972,6 +992,7 @@ static void vop_plane_atomic_update(struct drm_plane *plane,
|
|
}
|
|
|
|
VOP_WIN_SET(vop, win, format, format);
|
|
+ VOP_WIN_SET(vop, win, fmt_10, is_fmt_10(fb->format->format));
|
|
VOP_WIN_SET(vop, win, yrgb_vir, DIV_ROUND_UP(fb->pitches[0], 4));
|
|
VOP_WIN_SET(vop, win, yrgb_mst, dma_addr);
|
|
VOP_WIN_YUV2YUV_SET(vop, win_yuv2yuv, y2r_en, is_yuv);
|
|
@@ -988,7 +1009,11 @@ static void vop_plane_atomic_update(struct drm_plane *plane,
|
|
uv_obj = fb->obj[1];
|
|
rk_uv_obj = to_rockchip_obj(uv_obj);
|
|
|
|
- offset = (src->x1 >> 16) * bpp / hsub;
|
|
+ if (fb->format->block_w[1])
|
|
+ offset = (src->x1 >> 16) * bpp /
|
|
+ fb->format->block_w[1] / hsub;
|
|
+ else
|
|
+ offset = (src->x1 >> 16) * bpp / hsub;
|
|
offset += (src->y1 >> 16) * fb->pitches[1] / vsub;
|
|
|
|
dma_addr = rk_uv_obj->dma_addr + offset + fb->offsets[1];
|
|
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
|
|
index 8e6e999e5163..9f50e0e00127 100644
|
|
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
|
|
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
|
|
@@ -161,6 +161,7 @@ struct vop_win_phy {
|
|
struct vop_reg enable;
|
|
struct vop_reg gate;
|
|
struct vop_reg format;
|
|
+ struct vop_reg fmt_10;
|
|
struct vop_reg rb_swap;
|
|
struct vop_reg act_info;
|
|
struct vop_reg dsp_info;
|
|
diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
|
|
index dd4546f9f410..7d5191421ddf 100644
|
|
--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
|
|
+++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
|
|
@@ -50,6 +50,23 @@ static const uint32_t formats_win_full[] = {
|
|
DRM_FORMAT_NV24,
|
|
};
|
|
|
|
+static const uint32_t formats_win_full_10[] = {
|
|
+ DRM_FORMAT_XRGB8888,
|
|
+ DRM_FORMAT_ARGB8888,
|
|
+ DRM_FORMAT_XBGR8888,
|
|
+ DRM_FORMAT_ABGR8888,
|
|
+ DRM_FORMAT_RGB888,
|
|
+ DRM_FORMAT_BGR888,
|
|
+ DRM_FORMAT_RGB565,
|
|
+ DRM_FORMAT_BGR565,
|
|
+ DRM_FORMAT_NV12,
|
|
+ DRM_FORMAT_NV16,
|
|
+ DRM_FORMAT_NV24,
|
|
+ DRM_FORMAT_NV15,
|
|
+ DRM_FORMAT_NV20,
|
|
+ DRM_FORMAT_NV30,
|
|
+};
|
|
+
|
|
static const uint64_t format_modifiers_win_full[] = {
|
|
DRM_FORMAT_MOD_LINEAR,
|
|
DRM_FORMAT_MOD_INVALID,
|
|
@@ -579,11 +596,12 @@ static const struct vop_scl_regs rk3288_win_full_scl = {
|
|
|
|
static const struct vop_win_phy rk3288_win01_data = {
|
|
.scl = &rk3288_win_full_scl,
|
|
- .data_formats = formats_win_full,
|
|
- .nformats = ARRAY_SIZE(formats_win_full),
|
|
+ .data_formats = formats_win_full_10,
|
|
+ .nformats = ARRAY_SIZE(formats_win_full_10),
|
|
.format_modifiers = format_modifiers_win_full,
|
|
.enable = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 0),
|
|
.format = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 1),
|
|
+ .fmt_10 = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 4),
|
|
.rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12),
|
|
.act_info = VOP_REG(RK3288_WIN0_ACT_INFO, 0x1fff1fff, 0),
|
|
.dsp_info = VOP_REG(RK3288_WIN0_DSP_INFO, 0x0fff0fff, 0),
|
|
@@ -720,11 +738,12 @@ static const struct vop_intr rk3368_vop_intr = {
|
|
|
|
static const struct vop_win_phy rk3368_win01_data = {
|
|
.scl = &rk3288_win_full_scl,
|
|
- .data_formats = formats_win_full,
|
|
- .nformats = ARRAY_SIZE(formats_win_full),
|
|
+ .data_formats = formats_win_full_10,
|
|
+ .nformats = ARRAY_SIZE(formats_win_full_10),
|
|
.format_modifiers = format_modifiers_win_full,
|
|
.enable = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 0),
|
|
.format = VOP_REG(RK3368_WIN0_CTRL0, 0x7, 1),
|
|
+ .fmt_10 = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 4),
|
|
.rb_swap = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 12),
|
|
.x_mir_en = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 21),
|
|
.y_mir_en = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 22),
|
|
@@ -871,11 +890,12 @@ static const struct vop_win_yuv2yuv_data rk3399_vop_big_win_yuv2yuv_data[] = {
|
|
|
|
static const struct vop_win_phy rk3399_win01_data = {
|
|
.scl = &rk3288_win_full_scl,
|
|
- .data_formats = formats_win_full,
|
|
- .nformats = ARRAY_SIZE(formats_win_full),
|
|
+ .data_formats = formats_win_full_10,
|
|
+ .nformats = ARRAY_SIZE(formats_win_full_10),
|
|
.format_modifiers = format_modifiers_win_full_afbc,
|
|
.enable = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 0),
|
|
.format = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 1),
|
|
+ .fmt_10 = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 4),
|
|
.rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12),
|
|
.y_mir_en = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 22),
|
|
.act_info = VOP_REG(RK3288_WIN0_ACT_INFO, 0x1fff1fff, 0),
|
|
|
|
From e6aab013424e8e5a033f2da27757735f2a31c24e Mon Sep 17 00:00:00 2001
|
|
From: Alex Bee <knaerzche@gmail.com>
|
|
Date: Sat, 15 Aug 2020 21:11:08 +0200
|
|
Subject: [PATCH] drm/rockchip: rk3368's vop does not support 10-bit formats -
|
|
neither as input nor as output
|
|
|
|
---
|
|
drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 4 ++--
|
|
1 file changed, 2 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
|
|
index 7d5191421ddf..20c3e6248ec7 100644
|
|
--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
|
|
+++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
|
|
@@ -738,8 +738,8 @@ static const struct vop_intr rk3368_vop_intr = {
|
|
|
|
static const struct vop_win_phy rk3368_win01_data = {
|
|
.scl = &rk3288_win_full_scl,
|
|
- .data_formats = formats_win_full_10,
|
|
- .nformats = ARRAY_SIZE(formats_win_full_10),
|
|
+ .data_formats = formats_win_full,
|
|
+ .nformats = ARRAY_SIZE(formats_win_full),
|
|
.format_modifiers = format_modifiers_win_full,
|
|
.enable = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 0),
|
|
.format = VOP_REG(RK3368_WIN0_CTRL0, 0x7, 1),
|
|
|
|
From e3b1ffdb8a4620cb05ad1a2fb3ca6c398bf6470f Mon Sep 17 00:00:00 2001
|
|
From: Alex Bee <knaerzche@gmail.com>
|
|
Date: Sat, 15 Aug 2020 23:20:34 +0200
|
|
Subject: [PATCH] drm/rockchip: enable ycbcr_420_allowed and ycbcr_444_allowed
|
|
for RK3228
|
|
|
|
---
|
|
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 2 ++
|
|
1 file changed, 2 insertions(+)
|
|
|
|
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
|
index 1abc46a023a4..64a79b33ff18 100644
|
|
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
|
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
|
@@ -555,6 +555,7 @@ static const struct dw_hdmi_phy_ops rk3228_hdmi_phy_ops = {
|
|
|
|
static struct rockchip_hdmi_chip_data rk3228_chip_data = {
|
|
.lcdsel_grf_reg = -1,
|
|
+ .ycbcr_444_allowed = true,
|
|
};
|
|
|
|
static const struct dw_hdmi_plat_data rk3228_hdmi_drv_data = {
|
|
@@ -563,6 +564,7 @@ static const struct dw_hdmi_plat_data rk3228_hdmi_drv_data = {
|
|
.phy_ops = &rk3228_hdmi_phy_ops,
|
|
.phy_name = "inno_dw_hdmi_phy2",
|
|
.phy_force_vendor = true,
|
|
+ .ycbcr_420_allowed = true,
|
|
};
|
|
|
|
static struct rockchip_hdmi_chip_data rk3288_chip_data = {
|
|
|
|
From 8bdc71e93099e4a8e3fd8791832a83dfe485cd99 Mon Sep 17 00:00:00 2001
|
|
From: Alex Bee <knaerzche@gmail.com>
|
|
Date: Wed, 22 Jul 2020 20:13:28 +0200
|
|
Subject: [PATCH] drm: rockchip: add scaling for RK3036 win1
|
|
|
|
Add the registers needed to make scaling work on RK3036's win1.
|
|
|
|
Signed-off-by: Alex Bee <knaerzche@gmail.com>
|
|
---
|
|
drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 10 ++++++++--
|
|
1 file changed, 8 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
|
|
index 20c3e6248ec7..93a00b6ac295 100644
|
|
--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
|
|
+++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
|
|
@@ -94,15 +94,20 @@ static const uint64_t format_modifiers_win_lite[] = {
|
|
DRM_FORMAT_MOD_INVALID,
|
|
};
|
|
|
|
-static const struct vop_scl_regs rk3036_win_scl = {
|
|
+static const struct vop_scl_regs rk3036_win0_scl = {
|
|
.scale_yrgb_x = VOP_REG(RK3036_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0),
|
|
.scale_yrgb_y = VOP_REG(RK3036_WIN0_SCL_FACTOR_YRGB, 0xffff, 16),
|
|
.scale_cbcr_x = VOP_REG(RK3036_WIN0_SCL_FACTOR_CBR, 0xffff, 0x0),
|
|
.scale_cbcr_y = VOP_REG(RK3036_WIN0_SCL_FACTOR_CBR, 0xffff, 16),
|
|
};
|
|
|
|
+static const struct vop_scl_regs rk3036_win1_scl = {
|
|
+ .scale_yrgb_x = VOP_REG(RK3036_WIN1_SCL_FACTOR_YRGB, 0xffff, 0x0),
|
|
+ .scale_yrgb_y = VOP_REG(RK3036_WIN1_SCL_FACTOR_YRGB, 0xffff, 16),
|
|
+};
|
|
+
|
|
static const struct vop_win_phy rk3036_win0_data = {
|
|
- .scl = &rk3036_win_scl,
|
|
+ .scl = &rk3036_win0_scl,
|
|
.data_formats = formats_win_full,
|
|
.nformats = ARRAY_SIZE(formats_win_full),
|
|
.format_modifiers = format_modifiers_win_full,
|
|
@@ -119,6 +124,7 @@ static const struct vop_win_phy rk3036_win0_data = {
|
|
};
|
|
|
|
static const struct vop_win_phy rk3036_win1_data = {
|
|
+ .scl = &rk3036_win1_scl,
|
|
.data_formats = formats_win_lite,
|
|
.nformats = ARRAY_SIZE(formats_win_lite),
|
|
.format_modifiers = format_modifiers_win_lite,
|
|
|
|
From e2153eb92daad4a2e35b86096cbfe5f3ec4dc5ed Mon Sep 17 00:00:00 2001
|
|
From: Alex Bee <knaerzche@gmail.com>
|
|
Date: Wed, 22 Jul 2020 20:13:29 +0200
|
|
Subject: [PATCH] drm: rockchip: add missing registers for RK3188
|
|
|
|
Add dither_up, dsp_lut_en and data_blank registers to enable their
|
|
respective functionality for RK3188's VOP.
|
|
|
|
Signed-off-by: Alex Bee <knaerzche@gmail.com>
|
|
---
|
|
drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 3 +++
|
|
1 file changed, 3 insertions(+)
|
|
|
|
diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
|
|
index 93a00b6ac295..2638d084f9ce 100644
|
|
--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
|
|
+++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
|
|
@@ -529,6 +529,9 @@ static const struct vop_common rk3188_common = {
|
|
.dither_down_en = VOP_REG(RK3188_DSP_CTRL0, 0x1, 11),
|
|
.dither_down_mode = VOP_REG(RK3188_DSP_CTRL0, 0x1, 10),
|
|
.dsp_blank = VOP_REG(RK3188_DSP_CTRL1, 0x3, 24),
|
|
+ .dither_up = VOP_REG(RK3188_DSP_CTRL0, 0x1, 9),
|
|
+ .dsp_lut_en = VOP_REG(RK3188_SYS_CTRL, 0x1, 28),
|
|
+ .data_blank = VOP_REG(RK3188_DSP_CTRL1, 0x1, 25),
|
|
};
|
|
|
|
static const struct vop_win_data rk3188_vop_win_data[] = {
|
|
|
|
From c0e58f92ce8d4a6d792fb3e49ec2c1e46039ae76 Mon Sep 17 00:00:00 2001
|
|
From: Alex Bee <knaerzche@gmail.com>
|
|
Date: Wed, 22 Jul 2020 20:13:30 +0200
|
|
Subject: [PATCH] drm: rockchip: add alpha support for RK3036, RK3066, RK3126
|
|
and RK3188
|
|
|
|
With commit 2aae8ed1f390
|
|
("drm/rockchip: Add per-pixel alpha support for the PX30 VOP") alpha
|
|
support was introduced for PX30's VOP.
|
|
RK3036, RK3066, RK3126 and RK3188 VOPs support alpha blending in the
|
|
same manner.
|
|
With the exception of RK3066 all of them support pre-multiplied alpha.
|
|
|
|
Lets add these registers to make this work for those VOPs as well.
|
|
|
|
Signed-off-by: Alex Bee <knaerzche@gmail.com>
|
|
---
|
|
drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 21 +++++++++++++++++++++
|
|
drivers/gpu/drm/rockchip/rockchip_vop_reg.h | 1 +
|
|
2 files changed, 22 insertions(+)
|
|
|
|
diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
|
|
index 2638d084f9ce..e1db4e57c51a 100644
|
|
--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
|
|
+++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
|
|
@@ -121,6 +121,9 @@ static const struct vop_win_phy rk3036_win0_data = {
|
|
.uv_mst = VOP_REG(RK3036_WIN0_CBR_MST, 0xffffffff, 0),
|
|
.yrgb_vir = VOP_REG(RK3036_WIN0_VIR, 0xffff, 0),
|
|
.uv_vir = VOP_REG(RK3036_WIN0_VIR, 0x1fff, 16),
|
|
+ .alpha_mode = VOP_REG(RK3036_DSP_CTRL0, 0x1, 18),
|
|
+ .alpha_en = VOP_REG(RK3036_ALPHA_CTRL, 0x1, 0),
|
|
+ .alpha_pre_mul = VOP_REG(RK3036_DSP_CTRL0, 0x1, 29),
|
|
};
|
|
|
|
static const struct vop_win_phy rk3036_win1_data = {
|
|
@@ -136,6 +139,9 @@ static const struct vop_win_phy rk3036_win1_data = {
|
|
.dsp_st = VOP_REG(RK3036_WIN1_DSP_ST, 0x1fff1fff, 0),
|
|
.yrgb_mst = VOP_REG(RK3036_WIN1_MST, 0xffffffff, 0),
|
|
.yrgb_vir = VOP_REG(RK3036_WIN1_VIR, 0xffff, 0),
|
|
+ .alpha_mode = VOP_REG(RK3036_DSP_CTRL0, 0x1, 19),
|
|
+ .alpha_en = VOP_REG(RK3036_ALPHA_CTRL, 0x1, 1),
|
|
+ .alpha_pre_mul = VOP_REG(RK3036_DSP_CTRL0, 0x1, 29),
|
|
};
|
|
|
|
static const struct vop_win_data rk3036_vop_win_data[] = {
|
|
@@ -202,6 +208,9 @@ static const struct vop_win_phy rk3126_win1_data = {
|
|
.dsp_st = VOP_REG(RK3126_WIN1_DSP_ST, 0x1fff1fff, 0),
|
|
.yrgb_mst = VOP_REG(RK3126_WIN1_MST, 0xffffffff, 0),
|
|
.yrgb_vir = VOP_REG(RK3036_WIN1_VIR, 0xffff, 0),
|
|
+ .alpha_mode = VOP_REG(RK3036_DSP_CTRL0, 0x1, 19),
|
|
+ .alpha_en = VOP_REG(RK3036_ALPHA_CTRL, 0x1, 1),
|
|
+ .alpha_pre_mul = VOP_REG(RK3036_DSP_CTRL0, 0x1, 29),
|
|
};
|
|
|
|
static const struct vop_win_data rk3126_vop_win_data[] = {
|
|
@@ -381,6 +390,8 @@ static const struct vop_win_phy rk3066_win0_data = {
|
|
.uv_mst = VOP_REG(RK3066_WIN0_CBR_MST0, 0xffffffff, 0),
|
|
.yrgb_vir = VOP_REG(RK3066_WIN0_VIR, 0xffff, 0),
|
|
.uv_vir = VOP_REG(RK3066_WIN0_VIR, 0x1fff, 16),
|
|
+ .alpha_mode = VOP_REG(RK3066_DSP_CTRL0, 0x1, 21),
|
|
+ .alpha_en = VOP_REG(RK3066_BLEND_CTRL, 0x1, 0),
|
|
};
|
|
|
|
static const struct vop_win_phy rk3066_win1_data = {
|
|
@@ -398,6 +409,8 @@ static const struct vop_win_phy rk3066_win1_data = {
|
|
.uv_mst = VOP_REG(RK3066_WIN1_CBR_MST, 0xffffffff, 0),
|
|
.yrgb_vir = VOP_REG(RK3066_WIN1_VIR, 0xffff, 0),
|
|
.uv_vir = VOP_REG(RK3066_WIN1_VIR, 0x1fff, 16),
|
|
+ .alpha_mode = VOP_REG(RK3066_DSP_CTRL0, 0x1, 22),
|
|
+ .alpha_en = VOP_REG(RK3066_BLEND_CTRL, 0x1, 1),
|
|
};
|
|
|
|
static const struct vop_win_phy rk3066_win2_data = {
|
|
@@ -411,6 +424,8 @@ static const struct vop_win_phy rk3066_win2_data = {
|
|
.dsp_st = VOP_REG(RK3066_WIN2_DSP_ST, 0x1fff1fff, 0),
|
|
.yrgb_mst = VOP_REG(RK3066_WIN2_MST, 0xffffffff, 0),
|
|
.yrgb_vir = VOP_REG(RK3066_WIN2_VIR, 0xffff, 0),
|
|
+ .alpha_mode = VOP_REG(RK3066_DSP_CTRL0, 0x1, 23),
|
|
+ .alpha_en = VOP_REG(RK3066_BLEND_CTRL, 0x1, 2),
|
|
};
|
|
|
|
static const struct vop_modeset rk3066_modeset = {
|
|
@@ -493,6 +508,9 @@ static const struct vop_win_phy rk3188_win0_data = {
|
|
.yrgb_mst = VOP_REG(RK3188_WIN0_YRGB_MST0, 0xffffffff, 0),
|
|
.uv_mst = VOP_REG(RK3188_WIN0_CBR_MST0, 0xffffffff, 0),
|
|
.yrgb_vir = VOP_REG(RK3188_WIN_VIR, 0x1fff, 0),
|
|
+ .alpha_mode = VOP_REG(RK3188_DSP_CTRL0, 0x1, 18),
|
|
+ .alpha_en = VOP_REG(RK3188_ALPHA_CTRL, 0x1, 0),
|
|
+ .alpha_pre_mul = VOP_REG(RK3188_DSP_CTRL0, 0x1, 29),
|
|
};
|
|
|
|
static const struct vop_win_phy rk3188_win1_data = {
|
|
@@ -507,6 +525,9 @@ static const struct vop_win_phy rk3188_win1_data = {
|
|
.dsp_st = VOP_REG(RK3188_WIN1_DSP_ST, 0x0fff0fff, 0),
|
|
.yrgb_mst = VOP_REG(RK3188_WIN1_MST, 0xffffffff, 0),
|
|
.yrgb_vir = VOP_REG(RK3188_WIN_VIR, 0x1fff, 16),
|
|
+ .alpha_mode = VOP_REG(RK3188_DSP_CTRL0, 0x1, 19),
|
|
+ .alpha_en = VOP_REG(RK3188_ALPHA_CTRL, 0x1, 1),
|
|
+ .alpha_pre_mul = VOP_REG(RK3188_DSP_CTRL0, 0x1, 29),
|
|
};
|
|
|
|
static const struct vop_modeset rk3188_modeset = {
|
|
diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.h b/drivers/gpu/drm/rockchip/rockchip_vop_reg.h
|
|
index 6e9fa5815d4d..0b3cd65ba5c1 100644
|
|
--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.h
|
|
+++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.h
|
|
@@ -955,6 +955,7 @@
|
|
#define RK3188_DSP_CTRL0 0x04
|
|
#define RK3188_DSP_CTRL1 0x08
|
|
#define RK3188_INT_STATUS 0x10
|
|
+#define RK3188_ALPHA_CTRL 0x14
|
|
#define RK3188_WIN0_YRGB_MST0 0x20
|
|
#define RK3188_WIN0_CBR_MST0 0x24
|
|
#define RK3188_WIN0_YRGB_MST1 0x28
|
|
|
|
From 03532318ac2db5df4e83226628cb80399466bcd1 Mon Sep 17 00:00:00 2001
|
|
From: Alex Bee <knaerzche@gmail.com>
|
|
Date: Wed, 22 Jul 2020 20:13:31 +0200
|
|
Subject: [PATCH] drm: rockchip: set alpha_en to 0 if it is not used
|
|
|
|
alpha_en should be set to 0 if it is not used, i.e. to disable alpha
|
|
blending if it was enabled before and should be disabled now.
|
|
|
|
Fixes: 2aae8ed1f390 ("drm/rockchip: Add per-pixel alpha support for the PX30 VOP")
|
|
|
|
Signed-off-by: Alex Bee <knaerzche@gmail.com>
|
|
---
|
|
drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 1 +
|
|
1 file changed, 1 insertion(+)
|
|
|
|
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
|
|
index 413534cf1a93..9b1cc0f413fc 100644
|
|
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
|
|
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
|
|
@@ -1062,6 +1062,7 @@ static void vop_plane_atomic_update(struct drm_plane *plane,
|
|
VOP_WIN_SET(vop, win, alpha_en, 1);
|
|
} else {
|
|
VOP_WIN_SET(vop, win, src_alpha_ctl, SRC_ALPHA_EN(0));
|
|
+ VOP_WIN_SET(vop, win, alpha_en, 0);
|
|
}
|
|
|
|
VOP_WIN_SET(vop, win, enable, 1);
|
|
|
|
From 5447465aa564564d938209b4c5a2675f8d744354 Mon Sep 17 00:00:00 2001
|
|
From: Alex Bee <knaerzche@gmail.com>
|
|
Date: Sat, 15 Aug 2020 23:38:05 +0200
|
|
Subject: [PATCH] rockchip/drm: add dsp_data_swap register for RK3188
|
|
|
|
---
|
|
drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 1 +
|
|
1 file changed, 1 insertion(+)
|
|
|
|
diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
|
|
index e1db4e57c51a..e10cb2d33951 100644
|
|
--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
|
|
+++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
|
|
@@ -553,6 +553,7 @@ static const struct vop_common rk3188_common = {
|
|
.dither_up = VOP_REG(RK3188_DSP_CTRL0, 0x1, 9),
|
|
.dsp_lut_en = VOP_REG(RK3188_SYS_CTRL, 0x1, 28),
|
|
.data_blank = VOP_REG(RK3188_DSP_CTRL1, 0x1, 25),
|
|
+ .dsp_data_swap = VOP_REG(RK3188_DSP_CTRL1, 0x1f, 26),
|
|
};
|
|
|
|
static const struct vop_win_data rk3188_vop_win_data[] = {
|
|
|
|
From ee7a494712813333d714ff7360dae7e91d8ebdc3 Mon Sep 17 00:00:00 2001
|
|
From: Alex Bee <knaerzche@gmail.com>
|
|
Date: Sun, 16 Aug 2020 00:55:19 +0200
|
|
Subject: [PATCH] drm/rockchip: inno hdmi - add audio support - add required
|
|
aclk - fix video timing - fix phy pre-emphasis
|
|
|
|
---
|
|
.../display/rockchip/inno_hdmi-rockchip.txt | 6 +-
|
|
arch/arm/boot/dts/rk3036.dtsi | 24 +-
|
|
drivers/gpu/drm/rockchip/inno_hdmi.c | 266 +++++++++++++++++-
|
|
drivers/gpu/drm/rockchip/inno_hdmi.h | 2 +
|
|
4 files changed, 279 insertions(+), 19 deletions(-)
|
|
|
|
diff --git a/Documentation/devicetree/bindings/display/rockchip/inno_hdmi-rockchip.txt b/Documentation/devicetree/bindings/display/rockchip/inno_hdmi-rockchip.txt
|
|
index cec21714f0e0..b022c931e186 100644
|
|
--- a/Documentation/devicetree/bindings/display/rockchip/inno_hdmi-rockchip.txt
|
|
+++ b/Documentation/devicetree/bindings/display/rockchip/inno_hdmi-rockchip.txt
|
|
@@ -7,7 +7,7 @@ Required properties:
|
|
- reg:
|
|
Physical base address and length of the controller's registers.
|
|
- clocks, clock-names:
|
|
- Phandle to hdmi controller clock, name should be "pclk"
|
|
+ Phandle to hdmi controller clock, name should be "aclk" and "pclk".
|
|
- interrupts:
|
|
HDMI interrupt number
|
|
- ports:
|
|
@@ -21,8 +21,8 @@ hdmi: hdmi@20034000 {
|
|
compatible = "rockchip,rk3036-inno-hdmi";
|
|
reg = <0x20034000 0x4000>;
|
|
interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
|
|
- clocks = <&cru PCLK_HDMI>;
|
|
- clock-names = "pclk";
|
|
+ clocks = <&cru ACLK_VIO>, <&cru PCLK_HDMI>;
|
|
+ clock-names = "aclk", "pclk";
|
|
pinctrl-names = "default";
|
|
pinctrl-0 = <&hdmi_ctl>;
|
|
|
|
diff --git a/arch/arm/boot/dts/rk3036.dtsi b/arch/arm/boot/dts/rk3036.dtsi
|
|
index 838040b08967..4ffe72ab5f63 100644
|
|
--- a/arch/arm/boot/dts/rk3036.dtsi
|
|
+++ b/arch/arm/boot/dts/rk3036.dtsi
|
|
@@ -344,11 +344,14 @@ hdmi: hdmi@20034000 {
|
|
compatible = "rockchip,rk3036-inno-hdmi";
|
|
reg = <0x20034000 0x4000>;
|
|
interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
|
|
- clocks = <&cru PCLK_HDMI>;
|
|
- clock-names = "pclk";
|
|
+ clocks = <&cru ACLK_VIO>, <&cru PCLK_HDMI>;
|
|
+ clock-names = "aclk", "pclk";
|
|
rockchip,grf = <&grf>;
|
|
pinctrl-names = "default";
|
|
pinctrl-0 = <&hdmi_ctl>;
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+ #sound-dai-cells = <0>;
|
|
status = "disabled";
|
|
|
|
hdmi_in: port {
|
|
@@ -361,6 +364,23 @@ hdmi_in_vop: endpoint@0 {
|
|
};
|
|
};
|
|
|
|
+ hdmi_sound: hdmi-sound {
|
|
+ compatible = "simple-audio-card";
|
|
+ simple-audio-card,name = "HDMI";
|
|
+ status = "disabled";
|
|
+
|
|
+ simple-audio-card,dai-link {
|
|
+ format = "i2s";
|
|
+ mclk-fs = <256>;
|
|
+ cpu {
|
|
+ sound-dai = <&i2s>;
|
|
+ };
|
|
+ codec {
|
|
+ sound-dai = <&hdmi>;
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+
|
|
timer: timer@20044000 {
|
|
compatible = "rockchip,rk3036-timer", "rockchip,rk3288-timer";
|
|
reg = <0x20044000 0x20>;
|
|
diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c
|
|
index 7afdc54eb3ec..7e93208609a0 100644
|
|
--- a/drivers/gpu/drm/rockchip/inno_hdmi.c
|
|
+++ b/drivers/gpu/drm/rockchip/inno_hdmi.c
|
|
@@ -14,6 +14,7 @@
|
|
#include <linux/module.h>
|
|
#include <linux/mutex.h>
|
|
#include <linux/of_device.h>
|
|
+#include <linux/regmap.h>
|
|
|
|
#include <drm/drm_atomic_helper.h>
|
|
#include <drm/drm_edid.h>
|
|
@@ -21,6 +22,8 @@
|
|
#include <drm/drm_probe_helper.h>
|
|
#include <drm/drm_simple_kms_helper.h>
|
|
|
|
+#include <sound/hdmi-codec.h>
|
|
+
|
|
#include "rockchip_drm_drv.h"
|
|
#include "rockchip_drm_vop.h"
|
|
|
|
@@ -28,6 +31,12 @@
|
|
|
|
#define to_inno_hdmi(x) container_of(x, struct inno_hdmi, x)
|
|
|
|
+struct audio_info {
|
|
+ int sample_rate;
|
|
+ int channels;
|
|
+ int sample_width;
|
|
+};
|
|
+
|
|
struct hdmi_data_info {
|
|
int vic;
|
|
bool sink_is_hdmi;
|
|
@@ -52,8 +61,10 @@ struct inno_hdmi {
|
|
struct drm_device *drm_dev;
|
|
|
|
int irq;
|
|
+ struct clk *aclk;
|
|
struct clk *pclk;
|
|
void __iomem *regs;
|
|
+ struct regmap *regmap;
|
|
|
|
struct drm_connector connector;
|
|
struct drm_encoder encoder;
|
|
@@ -63,6 +74,9 @@ struct inno_hdmi {
|
|
|
|
unsigned int tmds_rate;
|
|
|
|
+ struct platform_device *audio_pdev;
|
|
+ bool audio_enable;
|
|
+
|
|
struct hdmi_data_info hdmi_data;
|
|
struct drm_display_mode previous_mode;
|
|
};
|
|
@@ -189,11 +203,17 @@ static void inno_hdmi_sys_power(struct inno_hdmi *hdmi, bool enable)
|
|
|
|
static void inno_hdmi_set_pwr_mode(struct inno_hdmi *hdmi, int mode)
|
|
{
|
|
+
|
|
+ u8 value;
|
|
+
|
|
switch (mode) {
|
|
case NORMAL:
|
|
inno_hdmi_sys_power(hdmi, false);
|
|
-
|
|
- hdmi_writeb(hdmi, HDMI_PHY_PRE_EMPHASIS, 0x6f);
|
|
+ if (hdmi->tmds_rate > 140000000)
|
|
+ value = 0x6f;
|
|
+ else
|
|
+ value = 0x3f;
|
|
+ hdmi_writeb(hdmi, HDMI_PHY_PRE_EMPHASIS, value);
|
|
hdmi_writeb(hdmi, HDMI_PHY_DRIVER, 0xbb);
|
|
|
|
hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x15);
|
|
@@ -301,6 +321,21 @@ static int inno_hdmi_config_video_avi(struct inno_hdmi *hdmi,
|
|
return inno_hdmi_upload_frame(hdmi, rc, &frame, INFOFRAME_AVI, 0, 0, 0);
|
|
}
|
|
|
|
+static int inno_hdmi_config_audio_aai(struct inno_hdmi *hdmi,
|
|
+ struct audio_info *audio)
|
|
+{
|
|
+ struct hdmi_audio_infoframe *faudio;
|
|
+ union hdmi_infoframe frame;
|
|
+ int rc;
|
|
+
|
|
+ rc = hdmi_audio_infoframe_init(&frame.audio);
|
|
+ faudio = (struct hdmi_audio_infoframe *)&frame;
|
|
+
|
|
+ faudio->channels = audio->channels;
|
|
+
|
|
+ return inno_hdmi_upload_frame(hdmi, rc, &frame, INFOFRAME_AAI, 0, 0, 0);
|
|
+}
|
|
+
|
|
static int inno_hdmi_config_video_csc(struct inno_hdmi *hdmi)
|
|
{
|
|
struct hdmi_data_info *data = &hdmi->hdmi_data;
|
|
@@ -383,6 +418,11 @@ static int inno_hdmi_config_video_timing(struct inno_hdmi *hdmi,
|
|
{
|
|
int value;
|
|
|
|
+ value = BIT(20) | BIT(21);
|
|
+ value |= mode->flags & DRM_MODE_FLAG_PHSYNC ? BIT(4) : 0;
|
|
+ value |= mode->flags & DRM_MODE_FLAG_PVSYNC ? BIT(5) : 0;
|
|
+ regmap_write(hdmi->regmap, 0x148, value);
|
|
+
|
|
/* Set detail external video timing polarity and interlace mode */
|
|
value = v_EXTERANL_VIDEO(1);
|
|
value |= mode->flags & DRM_MODE_FLAG_PHSYNC ?
|
|
@@ -402,7 +442,7 @@ static int inno_hdmi_config_video_timing(struct inno_hdmi *hdmi,
|
|
hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HBLANK_L, value & 0xFF);
|
|
hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HBLANK_H, (value >> 8) & 0xFF);
|
|
|
|
- value = mode->hsync_start - mode->hdisplay;
|
|
+ value = mode->htotal - mode->hsync_start;
|
|
hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HDELAY_L, value & 0xFF);
|
|
hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HDELAY_H, (value >> 8) & 0xFF);
|
|
|
|
@@ -417,7 +457,7 @@ static int inno_hdmi_config_video_timing(struct inno_hdmi *hdmi,
|
|
value = mode->vtotal - mode->vdisplay;
|
|
hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VBLANK, value & 0xFF);
|
|
|
|
- value = mode->vsync_start - mode->vdisplay;
|
|
+ value = mode->vtotal - mode->vsync_start;
|
|
hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VDELAY, value & 0xFF);
|
|
|
|
value = mode->vsync_end - mode->vsync_start;
|
|
@@ -473,8 +513,9 @@ static int inno_hdmi_setup(struct inno_hdmi *hdmi,
|
|
inno_hdmi_i2c_init(hdmi);
|
|
|
|
/* Unmute video and audio output */
|
|
- hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_VIDEO_BLACK,
|
|
- v_AUDIO_MUTE(0) | v_VIDEO_MUTE(0));
|
|
+ hdmi_modb(hdmi, HDMI_AV_MUTE, m_VIDEO_BLACK, v_VIDEO_MUTE(0));
|
|
+ if (hdmi->audio_enable)
|
|
+ hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE, v_AUDIO_MUTE(0));
|
|
|
|
return 0;
|
|
}
|
|
@@ -521,6 +562,7 @@ inno_hdmi_encoder_atomic_check(struct drm_encoder *encoder,
|
|
|
|
s->output_mode = ROCKCHIP_OUT_MODE_P888;
|
|
s->output_type = DRM_MODE_CONNECTOR_HDMIA;
|
|
+ s->bus_format = MEDIA_BUS_FMT_RGB888_1X24;
|
|
|
|
return 0;
|
|
}
|
|
@@ -597,6 +639,175 @@ static struct drm_connector_helper_funcs inno_hdmi_connector_helper_funcs = {
|
|
.mode_valid = inno_hdmi_connector_mode_valid,
|
|
};
|
|
|
|
+int inno_hdmi_audio_config_set(struct inno_hdmi *hdmi, struct audio_info *audio)
|
|
+{
|
|
+ int rate, N, channel;
|
|
+
|
|
+ if (audio->channels < 3)
|
|
+ channel = I2S_CHANNEL_1_2;
|
|
+ else if (audio->channels < 5)
|
|
+ channel = I2S_CHANNEL_3_4;
|
|
+ else if (audio->channels < 7)
|
|
+ channel = I2S_CHANNEL_5_6;
|
|
+ else
|
|
+ channel = I2S_CHANNEL_7_8;
|
|
+
|
|
+ switch (audio->sample_rate) {
|
|
+ case 32000:
|
|
+ rate = AUDIO_32K;
|
|
+ N = N_32K;
|
|
+ break;
|
|
+ case 44100:
|
|
+ rate = AUDIO_441K;
|
|
+ N = N_441K;
|
|
+ break;
|
|
+ case 48000:
|
|
+ rate = AUDIO_48K;
|
|
+ N = N_48K;
|
|
+ break;
|
|
+ case 88200:
|
|
+ rate = AUDIO_882K;
|
|
+ N = N_882K;
|
|
+ break;
|
|
+ case 96000:
|
|
+ rate = AUDIO_96K;
|
|
+ N = N_96K;
|
|
+ break;
|
|
+ case 176400:
|
|
+ rate = AUDIO_1764K;
|
|
+ N = N_1764K;
|
|
+ break;
|
|
+ case 192000:
|
|
+ rate = AUDIO_192K;
|
|
+ N = N_192K;
|
|
+ break;
|
|
+ default:
|
|
+ dev_err(hdmi->dev, "[%s] not support such sample rate %d\n",
|
|
+ __func__, audio->sample_rate);
|
|
+ return -ENOENT;
|
|
+ }
|
|
+
|
|
+ /* set_audio source I2S */
|
|
+ hdmi_writeb(hdmi, HDMI_AUDIO_CTRL1, 0x01);
|
|
+ hdmi_writeb(hdmi, AUDIO_SAMPLE_RATE, rate);
|
|
+ hdmi_writeb(hdmi, AUDIO_I2S_MODE, v_I2S_MODE(I2S_STANDARD) |
|
|
+ v_I2S_CHANNEL(channel));
|
|
+
|
|
+ hdmi_writeb(hdmi, AUDIO_I2S_MAP, 0x00);
|
|
+ hdmi_writeb(hdmi, AUDIO_I2S_SWAPS_SPDIF, 0);
|
|
+
|
|
+ /* Set N value */
|
|
+ hdmi_writeb(hdmi, AUDIO_N_H, (N >> 16) & 0x0F);
|
|
+ hdmi_writeb(hdmi, AUDIO_N_M, (N >> 8) & 0xFF);
|
|
+ hdmi_writeb(hdmi, AUDIO_N_L, N & 0xFF);
|
|
+
|
|
+ /*Set hdmi nlpcm mode to support hdmi bitstream*/
|
|
+ hdmi_writeb(hdmi, HDMI_AUDIO_CHANNEL_STATUS, v_AUDIO_STATUS_NLPCM(0));
|
|
+
|
|
+ return inno_hdmi_config_audio_aai(hdmi, audio);
|
|
+}
|
|
+
|
|
+static int inno_hdmi_audio_hw_params(struct device *dev, void *data,
|
|
+ struct hdmi_codec_daifmt *daifmt,
|
|
+ struct hdmi_codec_params *params)
|
|
+{
|
|
+ struct inno_hdmi *hdmi = dev_get_drvdata(dev);
|
|
+ struct audio_info audio = {
|
|
+ .sample_width = params->sample_width,
|
|
+ .sample_rate = params->sample_rate,
|
|
+ .channels = params->channels,
|
|
+ };
|
|
+
|
|
+ if (!hdmi->hdmi_data.sink_has_audio) {
|
|
+ dev_err(hdmi->dev, "Sink do not support audio!\n");
|
|
+ return -ENODEV;
|
|
+ }
|
|
+
|
|
+ if (!hdmi->encoder.crtc)
|
|
+ return -ENODEV;
|
|
+
|
|
+ switch (daifmt->fmt) {
|
|
+ case HDMI_I2S:
|
|
+ break;
|
|
+ default:
|
|
+ dev_err(dev, "%s: Invalid format %d\n", __func__, daifmt->fmt);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ return inno_hdmi_audio_config_set(hdmi, &audio);
|
|
+}
|
|
+
|
|
+static void inno_hdmi_audio_shutdown(struct device *dev, void *data)
|
|
+{
|
|
+ /* do nothing */
|
|
+}
|
|
+
|
|
+static int inno_hdmi_audio_digital_mute(struct device *dev, void *data, bool mute)
|
|
+{
|
|
+ struct inno_hdmi *hdmi = dev_get_drvdata(dev);
|
|
+
|
|
+ if (!hdmi->hdmi_data.sink_has_audio) {
|
|
+ dev_err(hdmi->dev, "Sink do not support audio!\n");
|
|
+ return -ENODEV;
|
|
+ }
|
|
+
|
|
+ hdmi->audio_enable = !mute;
|
|
+
|
|
+ if (mute)
|
|
+ hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_AUDIO_PD,
|
|
+ v_AUDIO_MUTE(1) | v_AUDIO_PD(1));
|
|
+ else
|
|
+ hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_AUDIO_PD,
|
|
+ v_AUDIO_MUTE(0) | v_AUDIO_PD(0));
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int inno_hdmi_audio_get_eld(struct device *dev, void *data,
|
|
+ uint8_t *buf, size_t len)
|
|
+{
|
|
+ struct inno_hdmi *hdmi = dev_get_drvdata(dev);
|
|
+ struct drm_mode_config *config = &hdmi->encoder.dev->mode_config;
|
|
+ struct drm_connector *connector;
|
|
+ int ret = -ENODEV;
|
|
+
|
|
+ mutex_lock(&config->mutex);
|
|
+ list_for_each_entry(connector, &config->connector_list, head) {
|
|
+ if (&hdmi->encoder == connector->encoder) {
|
|
+ memcpy(buf, connector->eld,
|
|
+ min(sizeof(connector->eld), len));
|
|
+ ret = 0;
|
|
+ }
|
|
+ }
|
|
+ mutex_unlock(&config->mutex);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static const struct hdmi_codec_ops audio_codec_ops = {
|
|
+ .hw_params = inno_hdmi_audio_hw_params,
|
|
+ .audio_shutdown = inno_hdmi_audio_shutdown,
|
|
+ //.digital_mute = inno_hdmi_audio_digital_mute,
|
|
+ .get_eld = inno_hdmi_audio_get_eld,
|
|
+};
|
|
+
|
|
+static int inno_hdmi_audio_codec_init(struct inno_hdmi *hdmi,
|
|
+ struct device *dev)
|
|
+{
|
|
+ struct hdmi_codec_pdata codec_data = {
|
|
+ .i2s = 1,
|
|
+ .ops = &audio_codec_ops,
|
|
+ .max_i2s_channels = 8,
|
|
+ };
|
|
+
|
|
+ hdmi->audio_enable = false;
|
|
+ hdmi->audio_pdev = platform_device_register_data(
|
|
+ dev, HDMI_CODEC_DRV_NAME, PLATFORM_DEVID_NONE,
|
|
+ &codec_data, sizeof(codec_data));
|
|
+
|
|
+ return PTR_ERR_OR_ZERO(hdmi->audio_pdev);
|
|
+}
|
|
+
|
|
static int inno_hdmi_register(struct drm_device *drm, struct inno_hdmi *hdmi)
|
|
{
|
|
struct drm_encoder *encoder = &hdmi->encoder;
|
|
@@ -627,6 +838,8 @@ static int inno_hdmi_register(struct drm_device *drm, struct inno_hdmi *hdmi)
|
|
|
|
drm_connector_attach_encoder(&hdmi->connector, encoder);
|
|
|
|
+ inno_hdmi_audio_codec_init(hdmi, dev);
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
@@ -826,23 +1039,44 @@ static int inno_hdmi_bind(struct device *dev, struct device *master,
|
|
if (IS_ERR(hdmi->regs))
|
|
return PTR_ERR(hdmi->regs);
|
|
|
|
+ irq = platform_get_irq(pdev, 0);
|
|
+ if (irq < 0)
|
|
+ return irq;
|
|
+
|
|
+ hdmi->aclk = devm_clk_get(hdmi->dev, "aclk");
|
|
+ if (IS_ERR(hdmi->aclk)) {
|
|
+ dev_err(hdmi->dev, "Unable to get HDMI aclk clk\n");
|
|
+ return PTR_ERR(hdmi->aclk);
|
|
+ }
|
|
+
|
|
hdmi->pclk = devm_clk_get(hdmi->dev, "pclk");
|
|
if (IS_ERR(hdmi->pclk)) {
|
|
DRM_DEV_ERROR(hdmi->dev, "Unable to get HDMI pclk clk\n");
|
|
return PTR_ERR(hdmi->pclk);
|
|
}
|
|
|
|
+ ret = clk_prepare_enable(hdmi->aclk);
|
|
+ if (ret) {
|
|
+ DRM_DEV_ERROR(hdmi->dev,
|
|
+ "Cannot enable HDMI aclk clock: %d\n", ret);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+
|
|
ret = clk_prepare_enable(hdmi->pclk);
|
|
if (ret) {
|
|
DRM_DEV_ERROR(hdmi->dev,
|
|
"Cannot enable HDMI pclk clock: %d\n", ret);
|
|
- return ret;
|
|
+ goto err_disable_aclk;
|
|
}
|
|
|
|
- irq = platform_get_irq(pdev, 0);
|
|
- if (irq < 0) {
|
|
- ret = irq;
|
|
- goto err_disable_clk;
|
|
+ hdmi->regmap =
|
|
+ syscon_regmap_lookup_by_phandle(hdmi->dev->of_node,
|
|
+ "rockchip,grf");
|
|
+ if (IS_ERR(hdmi->regmap)) {
|
|
+ dev_err(hdmi->dev, "Unable to get rockchip,grf\n");
|
|
+ ret = PTR_ERR(hdmi->regmap);
|
|
+ goto err_disable_aclk;
|
|
}
|
|
|
|
inno_hdmi_reset(hdmi);
|
|
@@ -851,7 +1085,7 @@ static int inno_hdmi_bind(struct device *dev, struct device *master,
|
|
if (IS_ERR(hdmi->ddc)) {
|
|
ret = PTR_ERR(hdmi->ddc);
|
|
hdmi->ddc = NULL;
|
|
- goto err_disable_clk;
|
|
+ goto err_disable_pclk;
|
|
}
|
|
|
|
/*
|
|
@@ -884,9 +1118,12 @@ static int inno_hdmi_bind(struct device *dev, struct device *master,
|
|
hdmi->encoder.funcs->destroy(&hdmi->encoder);
|
|
err_put_adapter:
|
|
i2c_put_adapter(hdmi->ddc);
|
|
-err_disable_clk:
|
|
+err_disable_pclk:
|
|
clk_disable_unprepare(hdmi->pclk);
|
|
- return ret;
|
|
+err_disable_aclk:
|
|
+ clk_disable_unprepare(hdmi->aclk);
|
|
+
|
|
+return ret;
|
|
}
|
|
|
|
static void inno_hdmi_unbind(struct device *dev, struct device *master,
|
|
@@ -899,6 +1136,7 @@ static void inno_hdmi_unbind(struct device *dev, struct device *master,
|
|
|
|
i2c_put_adapter(hdmi->ddc);
|
|
clk_disable_unprepare(hdmi->pclk);
|
|
+ clk_disable_unprepare(hdmi->aclk);
|
|
}
|
|
|
|
static const struct component_ops inno_hdmi_ops = {
|
|
diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.h b/drivers/gpu/drm/rockchip/inno_hdmi.h
|
|
index 93245b55f967..b722afc4e41f 100644
|
|
--- a/drivers/gpu/drm/rockchip/inno_hdmi.h
|
|
+++ b/drivers/gpu/drm/rockchip/inno_hdmi.h
|
|
@@ -96,11 +96,13 @@ enum {
|
|
#define HDMI_AV_MUTE 0x05
|
|
#define m_AVMUTE_CLEAR (1 << 7)
|
|
#define m_AVMUTE_ENABLE (1 << 6)
|
|
+#define m_AUDIO_PD (1 << 2)
|
|
#define m_AUDIO_MUTE (1 << 1)
|
|
#define m_VIDEO_BLACK (1 << 0)
|
|
#define v_AVMUTE_CLEAR(n) (n << 7)
|
|
#define v_AVMUTE_ENABLE(n) (n << 6)
|
|
#define v_AUDIO_MUTE(n) (n << 1)
|
|
+#define v_AUDIO_PD(n) (n << 2)
|
|
#define v_VIDEO_MUTE(n) (n << 0)
|
|
|
|
#define HDMI_VIDEO_TIMING_CTL 0x08
|
|
|
|
From 36a713bfb58368d37e19926d79709971183d86c8 Mon Sep 17 00:00:00 2001
|
|
From: Phong LE <ple@baylibre.com>
|
|
Date: Wed, 11 Mar 2020 13:51:33 +0100
|
|
Subject: [PATCH] dt-bindings: display: bridge: add it66121 bindings
|
|
|
|
Add the ITE bridge HDMI it66121 bindings.
|
|
|
|
Signed-off-by: Phong LE <ple@baylibre.com>
|
|
---
|
|
.../bindings/display/bridge/ite,it66121.yaml | 98 +++++++++++++++++++
|
|
1 file changed, 98 insertions(+)
|
|
create mode 100644 Documentation/devicetree/bindings/display/bridge/ite,it66121.yaml
|
|
|
|
diff --git a/Documentation/devicetree/bindings/display/bridge/ite,it66121.yaml b/Documentation/devicetree/bindings/display/bridge/ite,it66121.yaml
|
|
new file mode 100644
|
|
index 000000000000..1717e880d130
|
|
--- /dev/null
|
|
+++ b/Documentation/devicetree/bindings/display/bridge/ite,it66121.yaml
|
|
@@ -0,0 +1,98 @@
|
|
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
|
+%YAML 1.2
|
|
+---
|
|
+$id: http://devicetree.org/schemas/display/bridge/ite,it66121.yaml#
|
|
+$schema: http://devicetree.org/meta-schemas/core.yaml#
|
|
+
|
|
+title: ITE it66121 HDMI bridge Device Tree Bindings
|
|
+
|
|
+maintainers:
|
|
+ - Phong LE <ple@baylibre.com>
|
|
+ - Neil Armstrong <narmstrong@baylibre.com>
|
|
+
|
|
+description: |
|
|
+ The IT66121 is a high-performance and low-power single channel HDMI
|
|
+ transmitter, fully compliant with HDMI 1.3a, HDCP 1.2 and backward compatible
|
|
+ to DVI 1.0 specifications.
|
|
+
|
|
+properties:
|
|
+ compatible:
|
|
+ const: ite,it66121
|
|
+
|
|
+ reg:
|
|
+ maxItems: 1
|
|
+ description: base I2C address of the device
|
|
+
|
|
+ reset-gpios:
|
|
+ maxItems: 1
|
|
+ description: GPIO connected to active low reset
|
|
+
|
|
+ vrf12-supply:
|
|
+ maxItems: 1
|
|
+ description: Regulator for 1.2V analog core power.
|
|
+
|
|
+ vcn33-supply:
|
|
+ maxItems: 1
|
|
+ description: Regulator for 3.3V digital core power.
|
|
+
|
|
+ vcn18-supply:
|
|
+ maxItems: 1
|
|
+ description: Regulator for 1.8V IO core power.
|
|
+
|
|
+ interrupts:
|
|
+ maxItems: 1
|
|
+
|
|
+ pclk-dual-edge:
|
|
+ maxItems: 1
|
|
+ description: enable pclk dual edge mode.
|
|
+
|
|
+ port:
|
|
+ type: object
|
|
+
|
|
+ properties:
|
|
+ endpoint:
|
|
+ type: object
|
|
+ description: |
|
|
+ Input endpoints of the bridge.
|
|
+
|
|
+ required:
|
|
+ - endpoint
|
|
+
|
|
+required:
|
|
+ - compatible
|
|
+ - reg
|
|
+ - reset-gpios
|
|
+ - vrf12-supply
|
|
+ - vcn33-supply
|
|
+ - vcn18-supply
|
|
+ - interrupts
|
|
+ - port
|
|
+
|
|
+additionalProperties: false
|
|
+
|
|
+examples:
|
|
+ - |
|
|
+ i2c6 {
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+
|
|
+ it66121hdmitx: it66121hdmitx@4c {
|
|
+ compatible = "ite,it66121";
|
|
+ pinctrl-names = "default";
|
|
+ pinctrl-0 = <&ite_pins_default>;
|
|
+ vcn33-supply = <&mt6358_vcn33_wifi_reg>;
|
|
+ vcn18-supply = <&mt6358_vcn18_reg>;
|
|
+ vrf12-supply = <&mt6358_vrf12_reg>;
|
|
+ reset-gpios = <&pio 160 1 /* GPIO_ACTIVE_LOW */>;
|
|
+ interrupt-parent = <&pio>;
|
|
+ interrupts = <4 8 /* IRQ_TYPE_LEVEL_LOW */>;
|
|
+ reg = <0x4c>;
|
|
+ pclk-dual-edge;
|
|
+
|
|
+ port {
|
|
+ it66121_in: endpoint {
|
|
+ remote-endpoint = <&display_out>;
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+ };
|
|
|
|
From 55408304bc6a2c5e546743701e589f2ece3f3877 Mon Sep 17 00:00:00 2001
|
|
From: Phong LE <ple@baylibre.com>
|
|
Date: Wed, 11 Mar 2020 13:51:34 +0100
|
|
Subject: [PATCH] drm: bridge: add it66121 driver
|
|
|
|
This commit is a simple driver for bridge HMDI it66121.
|
|
The input format is RBG and there is no color conversion.
|
|
Audio, HDCP and CEC are not supported yet.
|
|
|
|
Signed-off-by: Phong LE <ple@baylibre.com>
|
|
---
|
|
drivers/gpu/drm/bridge/Kconfig | 8 +
|
|
drivers/gpu/drm/bridge/Makefile | 1 +
|
|
drivers/gpu/drm/bridge/ite-it66121.c | 997 +++++++++++++++++++++++++++
|
|
3 files changed, 1006 insertions(+)
|
|
create mode 100644 drivers/gpu/drm/bridge/ite-it66121.c
|
|
|
|
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
|
|
index 43271c21d3fc..204246d65f44 100644
|
|
--- a/drivers/gpu/drm/bridge/Kconfig
|
|
+++ b/drivers/gpu/drm/bridge/Kconfig
|
|
@@ -48,6 +48,14 @@ config DRM_DISPLAY_CONNECTOR
|
|
on ARM-based platforms. Saying Y here when this driver is not needed
|
|
will not cause any issue.
|
|
|
|
+config DRM_ITE_IT66121
|
|
+ tristate "ITE IT66121 HDMI bridge"
|
|
+ depends on OF
|
|
+ select DRM_KMS_HELPER
|
|
+ select REGMAP_I2C
|
|
+ help
|
|
+ Support for ITE IT66121 HDMI bridge.
|
|
+
|
|
config DRM_LVDS_CODEC
|
|
tristate "Transparent LVDS encoders and decoders support"
|
|
depends on OF
|
|
diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
|
|
index d63d4b7e4347..ffa91a5a6bda 100644
|
|
--- a/drivers/gpu/drm/bridge/Makefile
|
|
+++ b/drivers/gpu/drm/bridge/Makefile
|
|
@@ -2,6 +2,7 @@
|
|
obj-$(CONFIG_DRM_CDNS_DSI) += cdns-dsi.o
|
|
obj-$(CONFIG_DRM_CHRONTEL_CH7033) += chrontel-ch7033.o
|
|
obj-$(CONFIG_DRM_DISPLAY_CONNECTOR) += display-connector.o
|
|
+obj-$(CONFIG_DRM_ITE_IT66121) += ite-it66121.o
|
|
obj-$(CONFIG_DRM_LVDS_CODEC) += lvds-codec.o
|
|
obj-$(CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW) += megachips-stdpxxxx-ge-b850v3-fw.o
|
|
obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o
|
|
diff --git a/drivers/gpu/drm/bridge/ite-it66121.c b/drivers/gpu/drm/bridge/ite-it66121.c
|
|
new file mode 100644
|
|
index 000000000000..7e1a90319a6a
|
|
--- /dev/null
|
|
+++ b/drivers/gpu/drm/bridge/ite-it66121.c
|
|
@@ -0,0 +1,997 @@
|
|
+// SPDX-License-Identifier: GPL-2.0-only
|
|
+/*
|
|
+ * Copyright (C) 2020 BayLibre, SAS
|
|
+ * Author: Phong LE <ple@baylibre.com>
|
|
+ * Copyright (C) 2018-2019, Artem Mygaiev
|
|
+ * Copyright (C) 2017, Fresco Logic, Incorporated.
|
|
+ *
|
|
+ */
|
|
+
|
|
+#include <linux/device.h>
|
|
+#include <linux/i2c.h>
|
|
+#include <linux/interrupt.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/of.h>
|
|
+#include <linux/of_device.h>
|
|
+#include <linux/of_gpio.h>
|
|
+#include <linux/pinctrl/consumer.h>
|
|
+#include <linux/regmap.h>
|
|
+#include <linux/regulator/consumer.h>
|
|
+
|
|
+#include <drm/drm_atomic_helper.h>
|
|
+#include <drm/drm_bridge.h>
|
|
+#include <drm/drm_crtc_helper.h>
|
|
+#include <drm/drm_edid.h>
|
|
+#include <drm/drm_modes.h>
|
|
+#include <drm/drm_print.h>
|
|
+#include <drm/drm_probe_helper.h>
|
|
+
|
|
+#define IT66121_MASTER_SEL_REG 0x10
|
|
+#define IT66121_MASTER_SEL_HOST BIT(0)
|
|
+
|
|
+#define IT66121_AFE_DRV_REG 0x61
|
|
+#define IT66121_AFE_DRV_RST BIT(4)
|
|
+#define IT66121_AFE_DRV_PWD BIT(5)
|
|
+
|
|
+#define IT66121_INPUT_MODE_REG 0x70
|
|
+#define IT66121_INPUT_MODE_RGB (0 << 6)
|
|
+#define IT66121_INPUT_MODE_YUV422 BIT(6)
|
|
+#define IT66121_INPUT_MODE_YUV444 (2 << 6)
|
|
+#define IT66121_INPUT_MODE_CCIR656 BIT(4)
|
|
+#define IT66121_INPUT_MODE_SYNCEMB BIT(3)
|
|
+#define IT66121_INPUT_MODE_DDR BIT(2)
|
|
+
|
|
+#define IT66121_INPUT_CSC_REG 0x72
|
|
+#define IT66121_INPUT_CSC_ENDITHER BIT(7)
|
|
+#define IT66121_INPUT_CSC_ENUDFILTER BIT(6)
|
|
+#define IT66121_INPUT_CSC_DNFREE_GO BIT(5)
|
|
+#define IT66121_INPUT_CSC_RGB_TO_YUV 0x02
|
|
+#define IT66121_INPUT_CSC_YUV_TO_RGB 0x03
|
|
+#define IT66121_INPUT_CSC_NO_CONV 0x00
|
|
+
|
|
+#define IT66121_AFE_XP_REG 0x62
|
|
+#define IT66121_AFE_XP_GAINBIT BIT(7)
|
|
+#define IT66121_AFE_XP_PWDPLL BIT(6)
|
|
+#define IT66121_AFE_XP_ENI BIT(5)
|
|
+#define IT66121_AFE_XP_ENO BIT(4)
|
|
+#define IT66121_AFE_XP_RESETB BIT(3)
|
|
+#define IT66121_AFE_XP_PWDI BIT(2)
|
|
+
|
|
+#define IT66121_AFE_IP_REG 0x64
|
|
+#define IT66121_AFE_IP_GAINBIT BIT(7)
|
|
+#define IT66121_AFE_IP_PWDPLL BIT(6)
|
|
+#define IT66121_AFE_IP_CKSEL_05 (0 << 4)
|
|
+#define IT66121_AFE_IP_CKSEL_1 BIT(4)
|
|
+#define IT66121_AFE_IP_CKSEL_2 (2 << 4)
|
|
+#define IT66121_AFE_IP_CKSEL_2OR4 (3 << 4)
|
|
+#define IT66121_AFE_IP_ER0 BIT(3)
|
|
+#define IT66121_AFE_IP_RESETB BIT(2)
|
|
+#define IT66121_AFE_IP_ENC BIT(1)
|
|
+#define IT66121_AFE_IP_EC1 BIT(0)
|
|
+
|
|
+#define IT66121_AFE_XP_EC1_REG 0x68
|
|
+#define IT66121_AFE_XP_EC1_LOWCLK BIT(4)
|
|
+
|
|
+#define IT66121_SW_RST_REG 0x04
|
|
+#define IT66121_SW_RST_REF BIT(5)
|
|
+#define IT66121_SW_RST_AREF BIT(4)
|
|
+#define IT66121_SW_RST_VID BIT(3)
|
|
+#define IT66121_SW_RST_AUD BIT(2)
|
|
+#define IT66121_SW_RST_HDCP BIT(0)
|
|
+
|
|
+#define IT66121_DDC_COMMAND_REG 0x15
|
|
+#define IT66121_DDC_COMMAND_BURST_READ 0x0
|
|
+#define IT66121_DDC_COMMAND_EDID_READ 0x3
|
|
+#define IT66121_DDC_COMMAND_FIFO_CLR 0x9
|
|
+#define IT66121_DDC_COMMAND_SCL_PULSE 0xA
|
|
+#define IT66121_DDC_COMMAND_ABORT 0xF
|
|
+
|
|
+#define IT66121_HDCP_REG 0x20
|
|
+#define IT66121_HDCP_CPDESIRED BIT(0)
|
|
+#define IT66121_HDCP_EN1P1FEAT BIT(1)
|
|
+
|
|
+#define IT66121_INT_STATUS1_REG 0x06
|
|
+#define IT66121_INT_STATUS1_AUD_OVF BIT(7)
|
|
+#define IT66121_INT_STATUS1_DDC_NOACK BIT(5)
|
|
+#define IT66121_INT_STATUS1_DDC_FIFOERR BIT(4)
|
|
+#define IT66121_INT_STATUS1_DDC_BUSHANG BIT(2)
|
|
+#define IT66121_INT_STATUS1_RX_SENS_STATUS BIT(1)
|
|
+#define IT66121_INT_STATUS1_HPD_STATUS BIT(0)
|
|
+
|
|
+#define IT66121_DDC_HEADER_REG 0x11
|
|
+#define IT66121_DDC_HEADER_HDCP 0x74
|
|
+#define IT66121_DDC_HEADER_EDID 0xA0
|
|
+
|
|
+#define IT66121_DDC_OFFSET_REG 0x12
|
|
+#define IT66121_DDC_BYTE_REG 0x13
|
|
+#define IT66121_DDC_SEGMENT_REG 0x14
|
|
+#define IT66121_DDC_RD_FIFO_REG 0x17
|
|
+
|
|
+#define IT66121_CLK_BANK_REG 0x0F
|
|
+#define IT66121_CLK_BANK_PWROFF_RCLK BIT(6)
|
|
+#define IT66121_CLK_BANK_PWROFF_ACLK BIT(5)
|
|
+#define IT66121_CLK_BANK_PWROFF_TXCLK BIT(4)
|
|
+#define IT66121_CLK_BANK_PWROFF_CRCLK BIT(3)
|
|
+#define IT66121_CLK_BANK_0 0
|
|
+#define IT66121_CLK_BANK_1 1
|
|
+
|
|
+#define IT66121_INT_REG 0x05
|
|
+#define IT66121_INT_ACTIVE_HIGH BIT(7)
|
|
+#define IT66121_INT_OPEN_DRAIN BIT(6)
|
|
+#define IT66121_INT_TX_CLK_OFF BIT(0)
|
|
+
|
|
+#define IT66121_INT_MASK1_REG 0x09
|
|
+#define IT66121_INT_MASK1_AUD_OVF BIT(7)
|
|
+#define IT66121_INT_MASK1_DDC_NOACK BIT(5)
|
|
+#define IT66121_INT_MASK1_DDC_FIFOERR BIT(4)
|
|
+#define IT66121_INT_MASK1_DDC_BUSHANG BIT(2)
|
|
+#define IT66121_INT_MASK1_RX_SENS BIT(1)
|
|
+#define IT66121_INT_MASK1_HPD BIT(0)
|
|
+
|
|
+#define IT66121_INT_CLR1_REG 0x0C
|
|
+#define IT66121_INT_CLR1_PKTACP BIT(7)
|
|
+#define IT66121_INT_CLR1_PKTNULL BIT(6)
|
|
+#define IT66121_INT_CLR1_PKTGEN BIT(5)
|
|
+#define IT66121_INT_CLR1_KSVLISTCHK BIT(4)
|
|
+#define IT66121_INT_CLR1_AUTHDONE BIT(3)
|
|
+#define IT66121_INT_CLR1_AUTHFAIL BIT(2)
|
|
+#define IT66121_INT_CLR1_RX_SENS BIT(1)
|
|
+#define IT66121_INT_CLR1_HPD BIT(0)
|
|
+
|
|
+#define IT66121_AV_MUTE_REG 0xC1
|
|
+#define IT66121_AV_MUTE_ON BIT(0)
|
|
+#define IT66121_AV_MUTE_BLUESCR BIT(1)
|
|
+
|
|
+#define IT66121_PKT_GEN_CTRL_REG 0xC6
|
|
+#define IT66121_PKT_GEN_CTRL_ON BIT(0)
|
|
+#define IT66121_PKT_GEN_CTRL_RPT BIT(1)
|
|
+
|
|
+#define IT66121_AVIINFO_DB1_REG 0x158
|
|
+#define IT66121_AVIINFO_DB2_REG 0x159
|
|
+#define IT66121_AVIINFO_DB3_REG 0x15A
|
|
+#define IT66121_AVIINFO_DB4_REG 0x15B
|
|
+#define IT66121_AVIINFO_DB5_REG 0x15C
|
|
+#define IT66121_AVIINFO_CSUM_REG 0x15D
|
|
+#define IT66121_AVIINFO_DB6_REG 0x15E
|
|
+#define IT66121_AVIINFO_DB7_REG 0x15F
|
|
+#define IT66121_AVIINFO_DB8_REG 0x160
|
|
+#define IT66121_AVIINFO_DB9_REG 0x161
|
|
+#define IT66121_AVIINFO_DB10_REG 0x162
|
|
+#define IT66121_AVIINFO_DB11_REG 0x163
|
|
+#define IT66121_AVIINFO_DB12_REG 0x164
|
|
+#define IT66121_AVIINFO_DB13_REG 0x165
|
|
+
|
|
+#define IT66121_AVI_INFO_PKT_REG 0xCD
|
|
+#define IT66121_AVI_INFO_PKT_ON BIT(0)
|
|
+#define IT66121_AVI_INFO_PKT_RPT BIT(1)
|
|
+
|
|
+#define IT66121_HDMI_MODE_REG 0xC0
|
|
+#define IT66121_HDMI_MODE_HDMI BIT(0)
|
|
+
|
|
+#define IT66121_SYS_STATUS_REG 0x0E
|
|
+#define IT66121_SYS_STATUS_ACTIVE_IRQ BIT(7)
|
|
+#define IT66121_SYS_STATUS_HPDETECT BIT(6)
|
|
+#define IT66121_SYS_STATUS_SENDECTECT BIT(5)
|
|
+#define IT66121_SYS_STATUS_VID_STABLE BIT(4)
|
|
+#define IT66121_SYS_STATUS_AUD_CTS_CLR BIT(1)
|
|
+#define IT66121_SYS_STATUS_CLEAR_IRQ BIT(0)
|
|
+
|
|
+#define IT66121_DDC_STATUS_REG 0x16
|
|
+#define IT66121_DDC_STATUS_TX_DONE BIT(7)
|
|
+#define IT66121_DDC_STATUS_ACTIVE BIT(6)
|
|
+#define IT66121_DDC_STATUS_NOACK BIT(5)
|
|
+#define IT66121_DDC_STATUS_WAIT_BUS BIT(4)
|
|
+#define IT66121_DDC_STATUS_ARBI_LOSE BIT(3)
|
|
+#define IT66121_DDC_STATUS_FIFO_FULL BIT(2)
|
|
+#define IT66121_DDC_STATUS_FIFO_EMPTY BIT(1)
|
|
+#define IT66121_DDC_STATUS_FIFO_VALID BIT(0)
|
|
+
|
|
+#define IT66121_VENDOR_ID0 0x54
|
|
+#define IT66121_VENDOR_ID1 0x49
|
|
+#define IT66121_DEVICE_ID0 0x12
|
|
+#define IT66121_DEVICE_ID1 0x06
|
|
+#define IT66121_DEVICE_MASK 0x0F
|
|
+#define IT66121_EDID_SLEEP 20000
|
|
+#define IT66121_EDID_TIMEOUT 200000
|
|
+#define IT66121_EDID_FIFO_SIZE 32
|
|
+#define IT66121_AFE_CLK_HIGH 80000
|
|
+
|
|
+struct it66121_conf {
|
|
+ unsigned int input_mode_reg;
|
|
+ unsigned int input_conversion_reg;
|
|
+};
|
|
+
|
|
+struct it66121_ctx {
|
|
+ struct regmap *regmap;
|
|
+ struct drm_bridge bridge;
|
|
+ struct drm_connector connector;
|
|
+ struct device *dev;
|
|
+ struct gpio_desc *gpio_reset;
|
|
+ struct i2c_client *client;
|
|
+ struct regulator_bulk_data supplies[3];
|
|
+ bool dual_edge;
|
|
+ const struct it66121_conf *conf;
|
|
+ struct mutex lock; /* Protects fields below and device registers */
|
|
+ struct edid *edid;
|
|
+ struct hdmi_avi_infoframe hdmi_avi_infoframe;
|
|
+};
|
|
+
|
|
+static const struct regmap_range_cfg it66121_regmap_banks[] = {
|
|
+ {
|
|
+ .name = "it66121",
|
|
+ .range_min = 0x00,
|
|
+ .range_max = 0x1FF,
|
|
+ .selector_reg = IT66121_CLK_BANK_REG,
|
|
+ .selector_mask = 0x1,
|
|
+ .selector_shift = 0,
|
|
+ .window_start = 0x00,
|
|
+ .window_len = 0x130,
|
|
+ },
|
|
+};
|
|
+
|
|
+static const struct regmap_config it66121_regmap_config = {
|
|
+ .val_bits = 8,
|
|
+ .reg_bits = 8,
|
|
+ .max_register = 0x1FF,
|
|
+ .ranges = it66121_regmap_banks,
|
|
+ .num_ranges = ARRAY_SIZE(it66121_regmap_banks),
|
|
+};
|
|
+
|
|
+static const struct it66121_conf it66121_conf_simple = {
|
|
+ .input_mode_reg = IT66121_INPUT_MODE_RGB | IT66121_INPUT_MODE_DDR,
|
|
+ .input_conversion_reg = IT66121_INPUT_CSC_NO_CONV,
|
|
+};
|
|
+
|
|
+static void it66121_hw_reset(struct it66121_ctx *ctx)
|
|
+{
|
|
+ gpiod_set_value(ctx->gpio_reset, 1);
|
|
+ msleep(20);
|
|
+ gpiod_set_value(ctx->gpio_reset, 0);
|
|
+}
|
|
+
|
|
+static int ite66121_power_on(struct it66121_ctx *ctx)
|
|
+{
|
|
+ return regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
|
|
+}
|
|
+
|
|
+static int ite66121_power_off(struct it66121_ctx *ctx)
|
|
+{
|
|
+ return regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
|
|
+}
|
|
+
|
|
+static int it66121_preamble_ddc(struct it66121_ctx *ctx)
|
|
+{
|
|
+ return regmap_write(ctx->regmap, IT66121_MASTER_SEL_REG,
|
|
+ IT66121_MASTER_SEL_HOST);
|
|
+}
|
|
+
|
|
+static int it66121_fire_afe(struct it66121_ctx *ctx)
|
|
+{
|
|
+ return regmap_write(ctx->regmap, IT66121_AFE_DRV_REG, 0);
|
|
+}
|
|
+
|
|
+static int it66121_configure_input(struct it66121_ctx *ctx)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ ret = regmap_write(ctx->regmap, IT66121_INPUT_MODE_REG,
|
|
+ ctx->conf->input_mode_reg);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ return regmap_write(ctx->regmap, IT66121_INPUT_CSC_REG,
|
|
+ ctx->conf->input_conversion_reg);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * it66121_configure_afe() - Configure the analog front end
|
|
+ * @ctx: it66121_ctx object
|
|
+ *
|
|
+ * RETURNS:
|
|
+ * zero if success, a negative error code otherwise.
|
|
+ */
|
|
+static int it66121_configure_afe(struct it66121_ctx *ctx,
|
|
+ const struct drm_display_mode *mode)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ ret = regmap_write(ctx->regmap, IT66121_AFE_DRV_REG,
|
|
+ IT66121_AFE_DRV_RST);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ if (mode->clock > IT66121_AFE_CLK_HIGH) {
|
|
+ ret = regmap_write_bits(ctx->regmap, IT66121_AFE_XP_REG,
|
|
+ IT66121_AFE_XP_GAINBIT |
|
|
+ IT66121_AFE_XP_ENO,
|
|
+ IT66121_AFE_XP_GAINBIT);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ ret = regmap_write_bits(ctx->regmap, IT66121_AFE_IP_REG,
|
|
+ IT66121_AFE_IP_GAINBIT |
|
|
+ IT66121_AFE_IP_ER0 |
|
|
+ IT66121_AFE_IP_EC1,
|
|
+ IT66121_AFE_IP_GAINBIT);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ ret = regmap_write_bits(ctx->regmap, IT66121_AFE_XP_EC1_REG,
|
|
+ IT66121_AFE_XP_EC1_LOWCLK, 0x80);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+ } else {
|
|
+ ret = regmap_write_bits(ctx->regmap, IT66121_AFE_XP_REG,
|
|
+ IT66121_AFE_XP_GAINBIT |
|
|
+ IT66121_AFE_XP_ENO,
|
|
+ IT66121_AFE_XP_ENO);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ ret = regmap_write_bits(ctx->regmap, IT66121_AFE_IP_REG,
|
|
+ IT66121_AFE_IP_GAINBIT |
|
|
+ IT66121_AFE_IP_ER0 |
|
|
+ IT66121_AFE_IP_EC1, IT66121_AFE_IP_ER0 |
|
|
+ IT66121_AFE_IP_EC1);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ ret = regmap_write_bits(ctx->regmap, IT66121_AFE_XP_EC1_REG,
|
|
+ IT66121_AFE_XP_EC1_LOWCLK,
|
|
+ IT66121_AFE_XP_EC1_LOWCLK);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ /* Clear reset flags */
|
|
+ ret = regmap_write_bits(ctx->regmap, IT66121_SW_RST_REG,
|
|
+ IT66121_SW_RST_REF | IT66121_SW_RST_VID,
|
|
+ ~(IT66121_SW_RST_REF | IT66121_SW_RST_VID) &
|
|
+ 0xFF);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ return it66121_fire_afe(ctx);
|
|
+}
|
|
+
|
|
+static inline int it66121_wait_ddc_ready(struct it66121_ctx *ctx)
|
|
+{
|
|
+ int ret, val;
|
|
+
|
|
+ ret = regmap_read_poll_timeout(ctx->regmap, IT66121_DDC_STATUS_REG,
|
|
+ val, true,
|
|
+ IT66121_EDID_SLEEP,
|
|
+ IT66121_EDID_TIMEOUT);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ if (val & (IT66121_DDC_STATUS_NOACK | IT66121_DDC_STATUS_WAIT_BUS |
|
|
+ IT66121_DDC_STATUS_ARBI_LOSE))
|
|
+ return -EAGAIN;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int it66121_clear_ddc_fifo(struct it66121_ctx *ctx)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ ret = it66121_preamble_ddc(ctx);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ return regmap_write(ctx->regmap, IT66121_DDC_COMMAND_REG,
|
|
+ IT66121_DDC_COMMAND_FIFO_CLR);
|
|
+}
|
|
+
|
|
+static int it66121_abort_ddc_ops(struct it66121_ctx *ctx)
|
|
+{
|
|
+ int ret;
|
|
+ unsigned int swreset, cpdesire;
|
|
+
|
|
+ ret = regmap_read(ctx->regmap, IT66121_SW_RST_REG, &swreset);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ ret = regmap_read(ctx->regmap, IT66121_HDCP_REG, &cpdesire);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ ret = regmap_write(ctx->regmap, IT66121_HDCP_REG,
|
|
+ cpdesire & (~IT66121_HDCP_CPDESIRED & 0xFF));
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ ret = regmap_write(ctx->regmap, IT66121_SW_RST_REG,
|
|
+ swreset | IT66121_SW_RST_HDCP);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ ret = it66121_preamble_ddc(ctx);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ ret = regmap_write(ctx->regmap, IT66121_DDC_COMMAND_REG,
|
|
+ IT66121_DDC_COMMAND_ABORT);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ return it66121_wait_ddc_ready(ctx);
|
|
+}
|
|
+
|
|
+static int it66121_get_edid_block(void *context, u8 *buf,
|
|
+ unsigned int block, size_t len)
|
|
+{
|
|
+ struct it66121_ctx *ctx = context;
|
|
+ unsigned int val;
|
|
+ int remain = len;
|
|
+ int offset = 0;
|
|
+ int ret, cnt;
|
|
+
|
|
+ offset = (block % 2) * len;
|
|
+ block = block / 2;
|
|
+
|
|
+ ret = regmap_read(ctx->regmap, IT66121_INT_STATUS1_REG, &val);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ if (val & IT66121_INT_STATUS1_DDC_BUSHANG) {
|
|
+ ret = it66121_abort_ddc_ops(ctx);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ ret = it66121_clear_ddc_fifo(ctx);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ while (remain > 0) {
|
|
+ cnt = (remain > IT66121_EDID_FIFO_SIZE) ?
|
|
+ IT66121_EDID_FIFO_SIZE : remain;
|
|
+ ret = it66121_preamble_ddc(ctx);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ ret = regmap_write(ctx->regmap, IT66121_DDC_COMMAND_REG,
|
|
+ IT66121_DDC_COMMAND_FIFO_CLR);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ ret = it66121_wait_ddc_ready(ctx);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ ret = regmap_read(ctx->regmap, IT66121_INT_STATUS1_REG, &val);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ if (val & IT66121_INT_STATUS1_DDC_BUSHANG) {
|
|
+ ret = it66121_abort_ddc_ops(ctx);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ ret = it66121_preamble_ddc(ctx);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ ret = regmap_write(ctx->regmap, IT66121_DDC_HEADER_REG,
|
|
+ IT66121_DDC_HEADER_EDID);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ ret = regmap_write(ctx->regmap, IT66121_DDC_OFFSET_REG, offset);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ ret = regmap_write(ctx->regmap, IT66121_DDC_BYTE_REG, cnt);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ ret = regmap_write(ctx->regmap, IT66121_DDC_SEGMENT_REG, block);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ ret = regmap_write(ctx->regmap, IT66121_DDC_COMMAND_REG,
|
|
+ IT66121_DDC_COMMAND_EDID_READ);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ offset += cnt;
|
|
+ remain -= cnt;
|
|
+ msleep(20);
|
|
+
|
|
+ ret = it66121_wait_ddc_ready(ctx);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ do {
|
|
+ ret = regmap_read(ctx->regmap,
|
|
+ IT66121_DDC_RD_FIFO_REG, &val);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+ *(buf++) = val;
|
|
+ cnt--;
|
|
+ } while (cnt > 0);
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int it66121_connector_get_modes(struct drm_connector *connector)
|
|
+{
|
|
+ int ret, num_modes = 0;
|
|
+ struct it66121_ctx *ctx = container_of(connector, struct it66121_ctx,
|
|
+ connector);
|
|
+
|
|
+ if (ctx->edid)
|
|
+ return drm_add_edid_modes(connector, ctx->edid);
|
|
+
|
|
+ mutex_lock(&ctx->lock);
|
|
+
|
|
+ ctx->edid = drm_do_get_edid(connector, it66121_get_edid_block, ctx);
|
|
+ if (!ctx->edid) {
|
|
+ DRM_ERROR("Failed to read EDID\n");
|
|
+ goto unlock;
|
|
+ }
|
|
+
|
|
+ ret = drm_connector_update_edid_property(connector,
|
|
+ ctx->edid);
|
|
+ if (ret) {
|
|
+ DRM_ERROR("Failed to update EDID property: %d\n", ret);
|
|
+ goto unlock;
|
|
+ }
|
|
+
|
|
+ num_modes = drm_add_edid_modes(connector, ctx->edid);
|
|
+
|
|
+unlock:
|
|
+ mutex_unlock(&ctx->lock);
|
|
+
|
|
+ return num_modes;
|
|
+}
|
|
+
|
|
+static bool it66121_is_hpd_detect(struct it66121_ctx *ctx)
|
|
+{
|
|
+ int val;
|
|
+
|
|
+ if (regmap_read(ctx->regmap, IT66121_SYS_STATUS_REG, &val))
|
|
+ return false;
|
|
+
|
|
+ return (val & IT66121_SYS_STATUS_HPDETECT);
|
|
+}
|
|
+
|
|
+static int it66121_connector_detect_ctx(struct drm_connector *connector,
|
|
+ struct drm_modeset_acquire_ctx *c,
|
|
+ bool force)
|
|
+{
|
|
+ struct it66121_ctx *ctx = container_of(connector, struct it66121_ctx,
|
|
+ connector);
|
|
+
|
|
+ return (it66121_is_hpd_detect(ctx)) ?
|
|
+ connector_status_connected : connector_status_disconnected;
|
|
+}
|
|
+
|
|
+static enum drm_mode_status
|
|
+it66121_connector_mode_valid(struct drm_connector *connector,
|
|
+ struct drm_display_mode *mode)
|
|
+{
|
|
+ unsigned long max_clock;
|
|
+ struct it66121_ctx *ctx = container_of(connector, struct it66121_ctx,
|
|
+ connector);
|
|
+
|
|
+ max_clock = ctx->dual_edge ? 74250 : 148500;
|
|
+
|
|
+ if (mode->clock > max_clock)
|
|
+ return MODE_CLOCK_HIGH;
|
|
+
|
|
+ if (mode->clock < 25000)
|
|
+ return MODE_CLOCK_LOW;
|
|
+
|
|
+ return MODE_OK;
|
|
+}
|
|
+
|
|
+static struct drm_connector_helper_funcs it66121_connector_helper_funcs = {
|
|
+ .get_modes = it66121_connector_get_modes,
|
|
+ .detect_ctx = it66121_connector_detect_ctx,
|
|
+ .mode_valid = it66121_connector_mode_valid,
|
|
+};
|
|
+
|
|
+static const struct drm_connector_funcs it66121_connector_funcs = {
|
|
+ .reset = drm_atomic_helper_connector_reset,
|
|
+ .fill_modes = drm_helper_probe_single_connector_modes,
|
|
+ .destroy = drm_connector_cleanup,
|
|
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
|
|
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
|
|
+};
|
|
+
|
|
+static int it66121_bridge_attach(struct drm_bridge *bridge,
|
|
+ enum drm_bridge_attach_flags flags)
|
|
+{
|
|
+ int ret;
|
|
+ struct it66121_ctx *ctx = container_of(bridge, struct it66121_ctx,
|
|
+ bridge);
|
|
+
|
|
+ if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) {
|
|
+ DRM_ERROR("Fix bridge driver to make connector optional!");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ if (!bridge->encoder) {
|
|
+ DRM_ERROR("Parent encoder object not found");
|
|
+ return -ENODEV;
|
|
+ }
|
|
+
|
|
+ ret = regmap_write_bits(ctx->regmap, IT66121_CLK_BANK_REG,
|
|
+ IT66121_CLK_BANK_PWROFF_RCLK, 0);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ ret = regmap_write_bits(ctx->regmap, IT66121_INT_REG,
|
|
+ IT66121_INT_TX_CLK_OFF, 0);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ ret = regmap_write_bits(ctx->regmap, IT66121_AFE_DRV_REG,
|
|
+ IT66121_AFE_DRV_PWD, 0);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ ret = regmap_write_bits(ctx->regmap, IT66121_AFE_XP_REG,
|
|
+ IT66121_AFE_XP_PWDI | IT66121_AFE_XP_PWDPLL, 0);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ ret = regmap_write_bits(ctx->regmap, IT66121_AFE_IP_REG,
|
|
+ IT66121_AFE_IP_PWDPLL, 0);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ ret = regmap_write_bits(ctx->regmap, IT66121_AFE_DRV_REG,
|
|
+ IT66121_AFE_DRV_RST, 0);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ ret = regmap_write_bits(ctx->regmap, IT66121_AFE_XP_REG,
|
|
+ IT66121_AFE_XP_RESETB, IT66121_AFE_XP_RESETB);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ ret = regmap_write_bits(ctx->regmap, IT66121_AFE_IP_REG,
|
|
+ IT66121_AFE_IP_RESETB, IT66121_AFE_IP_RESETB);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ ret = regmap_write_bits(ctx->regmap, IT66121_SW_RST_REG,
|
|
+ IT66121_SW_RST_REF,
|
|
+ IT66121_SW_RST_REF);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ msleep(50);
|
|
+
|
|
+ ret = drm_connector_init(bridge->dev, &ctx->connector,
|
|
+ &it66121_connector_funcs,
|
|
+ DRM_MODE_CONNECTOR_HDMIA);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ ctx->connector.polled = DRM_CONNECTOR_POLL_HPD;
|
|
+ drm_connector_helper_add(&ctx->connector,
|
|
+ &it66121_connector_helper_funcs);
|
|
+
|
|
+ ret = drm_connector_attach_encoder(&ctx->connector, bridge->encoder);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ ret = drm_connector_register(&ctx->connector);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ /* Start interrupts */
|
|
+ return regmap_write_bits(ctx->regmap, IT66121_INT_MASK1_REG,
|
|
+ IT66121_INT_MASK1_DDC_NOACK |
|
|
+ IT66121_INT_MASK1_HPD |
|
|
+ IT66121_INT_MASK1_DDC_FIFOERR |
|
|
+ IT66121_INT_MASK1_DDC_BUSHANG,
|
|
+ ~(IT66121_INT_MASK1_DDC_NOACK |
|
|
+ IT66121_INT_MASK1_HPD |
|
|
+ IT66121_INT_MASK1_DDC_FIFOERR |
|
|
+ IT66121_INT_MASK1_DDC_BUSHANG) & 0xFF);
|
|
+}
|
|
+
|
|
+static int it66121_set_mute(struct it66121_ctx *ctx, bool mute)
|
|
+{
|
|
+ int ret;
|
|
+ unsigned int val;
|
|
+
|
|
+ val = mute ? IT66121_AV_MUTE_ON : (~IT66121_AV_MUTE_ON & 0xFF);
|
|
+ ret = regmap_write_bits(ctx->regmap, IT66121_AV_MUTE_REG,
|
|
+ IT66121_AV_MUTE_ON, val);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ return regmap_write(ctx->regmap, IT66121_PKT_GEN_CTRL_REG,
|
|
+ IT66121_PKT_GEN_CTRL_ON |
|
|
+ IT66121_PKT_GEN_CTRL_RPT);
|
|
+}
|
|
+
|
|
+static void it66121_bridge_enable(struct drm_bridge *bridge)
|
|
+{
|
|
+ struct it66121_ctx *ctx = container_of(bridge, struct it66121_ctx,
|
|
+ bridge);
|
|
+
|
|
+ it66121_set_mute(ctx, false);
|
|
+}
|
|
+
|
|
+static void it66121_bridge_disable(struct drm_bridge *bridge)
|
|
+{
|
|
+ struct it66121_ctx *ctx = container_of(bridge, struct it66121_ctx,
|
|
+ bridge);
|
|
+
|
|
+ it66121_set_mute(ctx, true);
|
|
+}
|
|
+
|
|
+static
|
|
+void it66121_bridge_mode_set(struct drm_bridge *bridge,
|
|
+ const struct drm_display_mode *mode,
|
|
+ const struct drm_display_mode *adjusted_mode)
|
|
+{
|
|
+ int ret, i;
|
|
+ u8 buf[HDMI_INFOFRAME_SIZE(AVI)];
|
|
+ struct it66121_ctx *ctx = container_of(bridge, struct it66121_ctx,
|
|
+ bridge);
|
|
+ const u16 aviinfo_reg[HDMI_AVI_INFOFRAME_SIZE] = {
|
|
+ IT66121_AVIINFO_DB1_REG,
|
|
+ IT66121_AVIINFO_DB2_REG,
|
|
+ IT66121_AVIINFO_DB3_REG,
|
|
+ IT66121_AVIINFO_DB4_REG,
|
|
+ IT66121_AVIINFO_DB5_REG,
|
|
+ IT66121_AVIINFO_DB6_REG,
|
|
+ IT66121_AVIINFO_DB7_REG,
|
|
+ IT66121_AVIINFO_DB8_REG,
|
|
+ IT66121_AVIINFO_DB9_REG,
|
|
+ IT66121_AVIINFO_DB10_REG,
|
|
+ IT66121_AVIINFO_DB11_REG,
|
|
+ IT66121_AVIINFO_DB12_REG,
|
|
+ IT66121_AVIINFO_DB13_REG
|
|
+ };
|
|
+
|
|
+ mutex_lock(&ctx->lock);
|
|
+
|
|
+ hdmi_avi_infoframe_init(&ctx->hdmi_avi_infoframe);
|
|
+
|
|
+ ret = drm_hdmi_avi_infoframe_from_display_mode(&ctx->hdmi_avi_infoframe,
|
|
+ &ctx->connector,
|
|
+ adjusted_mode);
|
|
+ if (ret) {
|
|
+ DRM_ERROR("Failed to setup AVI infoframe: %d\n", ret);
|
|
+ goto unlock;
|
|
+ }
|
|
+
|
|
+ ret = hdmi_avi_infoframe_pack(&ctx->hdmi_avi_infoframe, buf,
|
|
+ sizeof(buf));
|
|
+ if (ret < 0) {
|
|
+ DRM_ERROR("Failed to pack infoframe: %d\n", ret);
|
|
+ goto unlock;
|
|
+ }
|
|
+
|
|
+ /* Write new AVI infoframe packet */
|
|
+ for (i = 0; i < HDMI_AVI_INFOFRAME_SIZE; i++) {
|
|
+ if (regmap_write(ctx->regmap, aviinfo_reg[i],
|
|
+ buf[i + HDMI_INFOFRAME_HEADER_SIZE]))
|
|
+ goto unlock;
|
|
+ }
|
|
+ if (regmap_write(ctx->regmap, IT66121_AVIINFO_CSUM_REG, buf[3]))
|
|
+ goto unlock;
|
|
+
|
|
+ /* Enable AVI infoframe */
|
|
+ if (regmap_write(ctx->regmap, IT66121_AVI_INFO_PKT_REG,
|
|
+ IT66121_AVI_INFO_PKT_ON |
|
|
+ IT66121_AVI_INFO_PKT_RPT))
|
|
+ goto unlock;
|
|
+
|
|
+ /* Set TX mode to HDMI */
|
|
+ if (regmap_write(ctx->regmap, IT66121_HDMI_MODE_REG,
|
|
+ IT66121_HDMI_MODE_HDMI))
|
|
+ goto unlock;
|
|
+
|
|
+ if (regmap_write_bits(ctx->regmap, IT66121_CLK_BANK_REG,
|
|
+ IT66121_CLK_BANK_PWROFF_TXCLK,
|
|
+ IT66121_CLK_BANK_PWROFF_TXCLK))
|
|
+ goto unlock;
|
|
+
|
|
+ if (it66121_configure_input(ctx))
|
|
+ goto unlock;
|
|
+
|
|
+ if (it66121_configure_afe(ctx, adjusted_mode))
|
|
+ goto unlock;
|
|
+
|
|
+ regmap_write_bits(ctx->regmap, IT66121_CLK_BANK_REG,
|
|
+ IT66121_CLK_BANK_PWROFF_TXCLK,
|
|
+ ~IT66121_CLK_BANK_PWROFF_TXCLK & 0xFF);
|
|
+
|
|
+unlock:
|
|
+ mutex_unlock(&ctx->lock);
|
|
+}
|
|
+
|
|
+static const struct drm_bridge_funcs it66121_bridge_funcs = {
|
|
+ .attach = it66121_bridge_attach,
|
|
+ .enable = it66121_bridge_enable,
|
|
+ .disable = it66121_bridge_disable,
|
|
+ .mode_set = it66121_bridge_mode_set,
|
|
+};
|
|
+
|
|
+static irqreturn_t it66121_irq_threaded_handler(int irq, void *dev_id)
|
|
+{
|
|
+ int ret;
|
|
+ unsigned int val;
|
|
+ struct it66121_ctx *ctx = dev_id;
|
|
+ struct device *dev = ctx->dev;
|
|
+ bool event = false;
|
|
+
|
|
+ mutex_lock(&ctx->lock);
|
|
+
|
|
+ ret = regmap_read(ctx->regmap, IT66121_SYS_STATUS_REG, &val);
|
|
+ if (ret)
|
|
+ goto unlock;
|
|
+
|
|
+ if (val & IT66121_SYS_STATUS_ACTIVE_IRQ) {
|
|
+ ret = regmap_read(ctx->regmap, IT66121_INT_STATUS1_REG, &val);
|
|
+ if (ret) {
|
|
+ dev_err(dev, "Cannot read STATUS1_REG %d\n", ret);
|
|
+ } else {
|
|
+ if (val & IT66121_INT_STATUS1_DDC_FIFOERR)
|
|
+ it66121_clear_ddc_fifo(ctx);
|
|
+ if (val & (IT66121_INT_STATUS1_DDC_BUSHANG |
|
|
+ IT66121_INT_STATUS1_DDC_NOACK))
|
|
+ it66121_abort_ddc_ops(ctx);
|
|
+ if (val & IT66121_INT_STATUS1_HPD_STATUS) {
|
|
+ regmap_write_bits(ctx->regmap,
|
|
+ IT66121_INT_CLR1_REG,
|
|
+ IT66121_INT_CLR1_HPD,
|
|
+ IT66121_INT_CLR1_HPD);
|
|
+
|
|
+ if (!it66121_is_hpd_detect(ctx)) {
|
|
+ kfree(ctx->edid);
|
|
+ ctx->edid = NULL;
|
|
+ }
|
|
+ event = true;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ regmap_write_bits(ctx->regmap, IT66121_SYS_STATUS_REG,
|
|
+ IT66121_SYS_STATUS_CLEAR_IRQ,
|
|
+ IT66121_SYS_STATUS_CLEAR_IRQ);
|
|
+ }
|
|
+
|
|
+unlock:
|
|
+ mutex_unlock(&ctx->lock);
|
|
+
|
|
+ if (event)
|
|
+ drm_helper_hpd_irq_event(ctx->bridge.dev);
|
|
+
|
|
+ return IRQ_HANDLED;
|
|
+}
|
|
+
|
|
+static int it66121_probe(struct i2c_client *client,
|
|
+ const struct i2c_device_id *id)
|
|
+{
|
|
+ u8 ids[4];
|
|
+ int i, ret;
|
|
+ struct it66121_ctx *ctx;
|
|
+ struct device *dev = &client->dev;
|
|
+
|
|
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
|
|
+ dev_err(dev, "I2C check functionality failed.\n");
|
|
+ return -ENXIO;
|
|
+ }
|
|
+
|
|
+ ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
|
|
+ if (!ctx)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ ctx->dev = dev;
|
|
+ ctx->client = client;
|
|
+ i2c_set_clientdata(client, ctx);
|
|
+ mutex_init(&ctx->lock);
|
|
+ ctx->conf = (struct it66121_conf *)of_device_get_match_data(dev);
|
|
+ if (!ctx->conf)
|
|
+ return -ENODEV;
|
|
+
|
|
+ ctx->supplies[0].supply = "vcn33";
|
|
+ ctx->supplies[1].supply = "vcn18";
|
|
+ ctx->supplies[2].supply = "vrf12";
|
|
+ ret = devm_regulator_bulk_get(ctx->dev, 3, ctx->supplies);
|
|
+ if (ret) {
|
|
+ dev_err(ctx->dev, "regulator_bulk failed\n");
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ ctx->dual_edge = of_property_read_bool(dev->of_node, "pclk-dual-edge");
|
|
+
|
|
+ ret = ite66121_power_on(ctx);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ it66121_hw_reset(ctx);
|
|
+
|
|
+ ctx->regmap = devm_regmap_init_i2c(client, &it66121_regmap_config);
|
|
+ if (IS_ERR(ctx->regmap)) {
|
|
+ ite66121_power_off(ctx);
|
|
+ return PTR_ERR(ctx);
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < 4; i++) {
|
|
+ regmap_read(ctx->regmap, i, &ret);
|
|
+ ids[i] = ret;
|
|
+ }
|
|
+
|
|
+ if (ids[0] != IT66121_VENDOR_ID0 ||
|
|
+ ids[1] != IT66121_VENDOR_ID1 ||
|
|
+ ids[2] != IT66121_DEVICE_ID0 ||
|
|
+ ((ids[3] & IT66121_DEVICE_MASK) != IT66121_DEVICE_ID1)) {
|
|
+ ite66121_power_off(ctx);
|
|
+ return -ENODEV;
|
|
+ }
|
|
+
|
|
+ ctx->bridge.funcs = &it66121_bridge_funcs;
|
|
+ ctx->bridge.of_node = dev->of_node;
|
|
+
|
|
+ ret = devm_request_threaded_irq(dev, client->irq, NULL,
|
|
+ it66121_irq_threaded_handler,
|
|
+ IRQF_SHARED | IRQF_TRIGGER_LOW |
|
|
+ IRQF_ONESHOT,
|
|
+ dev_name(dev),
|
|
+ ctx);
|
|
+ if (ret < 0) {
|
|
+ dev_err(dev, "Failed to request irq %d:%d\n", client->irq, ret);
|
|
+ ite66121_power_off(ctx);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ drm_bridge_add(&ctx->bridge);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int it66121_remove(struct i2c_client *client)
|
|
+{
|
|
+ struct it66121_ctx *ctx = i2c_get_clientdata(client);
|
|
+
|
|
+ ite66121_power_off(ctx);
|
|
+ drm_bridge_remove(&ctx->bridge);
|
|
+ kfree(ctx->edid);
|
|
+ mutex_destroy(&ctx->lock);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static const struct of_device_id it66121_dt_match[] = {
|
|
+ { .compatible = "ite,it66121",
|
|
+ .data = &it66121_conf_simple,
|
|
+ },
|
|
+ { },
|
|
+};
|
|
+MODULE_DEVICE_TABLE(of, it66121_dt_match);
|
|
+
|
|
+static const struct i2c_device_id it66121_id[] = {
|
|
+ { "it66121", 0 },
|
|
+ { },
|
|
+};
|
|
+MODULE_DEVICE_TABLE(i2c, it66121_id);
|
|
+
|
|
+static struct i2c_driver it66121_driver = {
|
|
+ .driver = {
|
|
+ .name = "it66121",
|
|
+ .of_match_table = it66121_dt_match,
|
|
+ },
|
|
+ .probe = it66121_probe,
|
|
+ .remove = it66121_remove,
|
|
+ .id_table = it66121_id,
|
|
+};
|
|
+
|
|
+module_i2c_driver(it66121_driver);
|
|
+
|
|
+MODULE_AUTHOR("Phong LE");
|
|
+MODULE_DESCRIPTION("IT66121 HDMI transmitter driver");
|
|
+MODULE_LICENSE("GPL v2");
|
|
|
|
From 16bbf295dbfda3cf315c62bbf42cd5e6a0796e45 Mon Sep 17 00:00:00 2001
|
|
From: Phong LE <ple@baylibre.com>
|
|
Date: Wed, 11 Mar 2020 13:51:35 +0100
|
|
Subject: [PATCH] MAINTAINERS: add it66121 HDMI bridge driver entry
|
|
|
|
Add Neil Armstrong and myself as maintainers
|
|
|
|
Signed-off-by: Phong LE <ple@baylibre.com>
|
|
---
|
|
MAINTAINERS | 8 ++++++++
|
|
1 file changed, 8 insertions(+)
|
|
|
|
diff --git a/MAINTAINERS b/MAINTAINERS
|
|
index 0a14444b5f65..587c013211ae 100644
|
|
--- a/MAINTAINERS
|
|
+++ b/MAINTAINERS
|
|
@@ -9309,6 +9309,14 @@ Q: http://patchwork.linuxtv.org/project/linux-media/list/
|
|
T: git git://linuxtv.org/anttip/media_tree.git
|
|
F: drivers/media/tuners/it913x*
|
|
|
|
+ITE IT66121 HDMI BRIDGE DRIVER
|
|
+M: Phong LE <ple@baylibre.com>
|
|
+M: Neil Armstrong <narmstrong@baylibre.com>
|
|
+S: Maintained
|
|
+F: drivers/gpu/drm/bridge/ite-it66121.c
|
|
+T: git git://anongit.freedesktop.org/drm/drm-misc
|
|
+F: Documentation/devicetree/bindings/display/bridge/ite,it66121.yaml
|
|
+
|
|
IVTV VIDEO4LINUX DRIVER
|
|
M: Andy Walls <awalls@md.metrocast.net>
|
|
L: linux-media@vger.kernel.org
|
|
|
|
From 687354cbf754607f5a6746a85289ff1096cf0242 Mon Sep 17 00:00:00 2001
|
|
From: Alex Bee <knaerzche@gmail.com>
|
|
Date: Tue, 26 May 2020 13:48:12 +0200
|
|
Subject: [PATCH] drm: bridge: it66121: add IT66121FN variant
|
|
|
|
---
|
|
drivers/gpu/drm/bridge/ite-it66121.c | 8 ++++++++
|
|
1 file changed, 8 insertions(+)
|
|
|
|
diff --git a/drivers/gpu/drm/bridge/ite-it66121.c b/drivers/gpu/drm/bridge/ite-it66121.c
|
|
index 7e1a90319a6a..68f7e50fdddd 100644
|
|
--- a/drivers/gpu/drm/bridge/ite-it66121.c
|
|
+++ b/drivers/gpu/drm/bridge/ite-it66121.c
|
|
@@ -242,6 +242,11 @@ static const struct it66121_conf it66121_conf_simple = {
|
|
.input_conversion_reg = IT66121_INPUT_CSC_NO_CONV,
|
|
};
|
|
|
|
+static const struct it66121_conf it66121fn_conf_simple = {
|
|
+ .input_mode_reg = IT66121_INPUT_MODE_RGB,
|
|
+ .input_conversion_reg = IT66121_INPUT_CSC_NO_CONV,
|
|
+};
|
|
+
|
|
static void it66121_hw_reset(struct it66121_ctx *ctx)
|
|
{
|
|
gpiod_set_value(ctx->gpio_reset, 1);
|
|
@@ -970,6 +975,9 @@ static const struct of_device_id it66121_dt_match[] = {
|
|
{ .compatible = "ite,it66121",
|
|
.data = &it66121_conf_simple,
|
|
},
|
|
+ { .compatible = "ite,it66121fn",
|
|
+ .data = &it66121fn_conf_simple,
|
|
+ },
|
|
{ },
|
|
};
|
|
MODULE_DEVICE_TABLE(of, it66121_dt_match);
|
|
|
|
From 2877f7c88109d3f0573073ca5183c8baef437c9d Mon Sep 17 00:00:00 2001
|
|
From: Alex Bee <knaerzche@gmail.com>
|
|
Date: Sun, 16 Aug 2020 23:40:24 +0200
|
|
Subject: [PATCH] WIP: ARM: dts: rockchip add vpll clock to RK322Xs hdmi node
|
|
|
|
---
|
|
arch/arm/boot/dts/rk322x.dtsi | 4 ++--
|
|
1 file changed, 2 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi
|
|
index 4bc631881c05..f98a945c68d3 100644
|
|
--- a/arch/arm/boot/dts/rk322x.dtsi
|
|
+++ b/arch/arm/boot/dts/rk322x.dtsi
|
|
@@ -766,8 +766,8 @@ hdmi: hdmi@200a0000 {
|
|
interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
|
|
assigned-clocks = <&cru SCLK_HDMI_PHY>;
|
|
assigned-clock-parents = <&hdmi_phy>;
|
|
- clocks = <&cru SCLK_HDMI_HDCP>, <&cru PCLK_HDMI_CTRL>, <&cru SCLK_HDMI_CEC>;
|
|
- clock-names = "isfr", "iahb", "cec";
|
|
+ clocks = <&cru SCLK_HDMI_HDCP>, <&cru PCLK_HDMI_CTRL>, <&hdmi_phy>, <&cru SCLK_HDMI_CEC>;
|
|
+ clock-names = "isfr", "iahb", "vpll", "cec";
|
|
pinctrl-names = "default";
|
|
pinctrl-0 = <&hdmii2c_xfer &hdmi_hpd &hdmi_cec>;
|
|
resets = <&cru SRST_HDMI_P>;
|
|
|
|
From d1df7c9067139e04b9e0f6c11e5b1b88d4a6a07c Mon Sep 17 00:00:00 2001
|
|
From: Alex Bee <knaerzche@gmail.com>
|
|
Date: Tue, 18 Aug 2020 11:19:53 +0200
|
|
Subject: [PATCH] drm/bridge: !cleanup: remove pr_infos
|
|
|
|
---
|
|
drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c | 6 ------
|
|
1 file changed, 6 deletions(-)
|
|
|
|
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c
|
|
index e6953219beee..2cfd5b418c05 100644
|
|
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c
|
|
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c
|
|
@@ -97,8 +97,6 @@ static int dw_hdmi_cec_transmit(struct cec_adapter *adap, u8 attempts,
|
|
struct dw_hdmi_cec *cec = cec_get_drvdata(adap);
|
|
unsigned int i, ctrl;
|
|
|
|
- pr_info("%s: attempts=%u signal_free_time=%u msg=%*ph (sequence: %u)\n", __func__, attempts, signal_free_time, msg->len, msg->msg, msg->sequence);
|
|
-
|
|
switch (signal_free_time) {
|
|
case CEC_SIGNAL_FREE_TIME_RETRY:
|
|
ctrl = CEC_CTRL_RETRY;
|
|
@@ -188,8 +186,6 @@ static irqreturn_t dw_hdmi_cec_hardirq(int irq, void *data)
|
|
ret = IRQ_WAKE_THREAD;
|
|
}
|
|
|
|
- pr_info("%s: stat=%x ret=%x tx_done=%d rx_done=%d tx_status=%u tx_attempts=%u\n", __func__, stat, ret, cec->tx_done, cec->rx_done, cec->tx_status, cec->tx_attempts);
|
|
-
|
|
return ret;
|
|
}
|
|
|
|
@@ -198,8 +194,6 @@ static irqreturn_t dw_hdmi_cec_thread(int irq, void *data)
|
|
struct cec_adapter *adap = data;
|
|
struct dw_hdmi_cec *cec = cec_get_drvdata(adap);
|
|
|
|
- //pr_info("%s: tx_done=%d rx_done=%d tx_status=%u tx_attempts=%u\n", __func__, cec->tx_done, cec->rx_done, cec->tx_status, cec->tx_attempts);
|
|
-
|
|
if (cec->tx_done) {
|
|
cec->tx_done = false;
|
|
if (cec->tx_status == CEC_TX_STATUS_LOW_DRIVE)
|
|
|
|
From b145995aa4a89abae1799b469297fef1857d62b3 Mon Sep 17 00:00:00 2001
|
|
From: Jonas Karlman <jonas@kwiboo.se>
|
|
Date: Sat, 18 Nov 2017 11:09:39 +0100
|
|
Subject: [PATCH] rockchip: vop: force skip lines if image too big
|
|
|
|
---
|
|
drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 13 ++++++++++---
|
|
1 file changed, 10 insertions(+), 3 deletions(-)
|
|
|
|
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
|
|
index 9b1cc0f413fc..a34ff7593e1f 100644
|
|
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
|
|
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
|
|
@@ -932,6 +932,7 @@ static void vop_plane_atomic_update(struct drm_plane *plane,
|
|
int format;
|
|
int is_yuv = fb->format->is_yuv;
|
|
int i;
|
|
+ int skiplines = 0;
|
|
|
|
/*
|
|
* can't update plane when vop is disabled.
|
|
@@ -950,8 +951,14 @@ static void vop_plane_atomic_update(struct drm_plane *plane,
|
|
obj = fb->obj[0];
|
|
rk_obj = to_rockchip_obj(obj);
|
|
|
|
+ /*
|
|
+ * Force skip lines when image is yuv and 3840 width,
|
|
+ * fixes a "jumping" green lines issue on RK3328.
|
|
+ */
|
|
actual_w = drm_rect_width(src) >> 16;
|
|
- actual_h = drm_rect_height(src) >> 16;
|
|
+ if (actual_w == 3840 && is_yuv)
|
|
+ skiplines = 1;
|
|
+ actual_h = drm_rect_height(src) >> (16 + skiplines);
|
|
act_info = (actual_h - 1) << 16 | ((actual_w - 1) & 0xffff);
|
|
|
|
dsp_info = (drm_rect_height(dest) - 1) << 16;
|
|
@@ -993,7 +1000,7 @@ static void vop_plane_atomic_update(struct drm_plane *plane,
|
|
|
|
VOP_WIN_SET(vop, win, format, format);
|
|
VOP_WIN_SET(vop, win, fmt_10, is_fmt_10(fb->format->format));
|
|
- VOP_WIN_SET(vop, win, yrgb_vir, DIV_ROUND_UP(fb->pitches[0], 4));
|
|
+ VOP_WIN_SET(vop, win, yrgb_vir, DIV_ROUND_UP(fb->pitches[0], 4 >> skiplines));
|
|
VOP_WIN_SET(vop, win, yrgb_mst, dma_addr);
|
|
VOP_WIN_YUV2YUV_SET(vop, win_yuv2yuv, y2r_en, is_yuv);
|
|
VOP_WIN_SET(vop, win, y_mir_en,
|
|
@@ -1017,7 +1024,7 @@ static void vop_plane_atomic_update(struct drm_plane *plane,
|
|
offset += (src->y1 >> 16) * fb->pitches[1] / vsub;
|
|
|
|
dma_addr = rk_uv_obj->dma_addr + offset + fb->offsets[1];
|
|
- VOP_WIN_SET(vop, win, uv_vir, DIV_ROUND_UP(fb->pitches[1], 4));
|
|
+ VOP_WIN_SET(vop, win, uv_vir, DIV_ROUND_UP(fb->pitches[1], 4 >> skiplines));
|
|
VOP_WIN_SET(vop, win, uv_mst, dma_addr);
|
|
|
|
for (i = 0; i < NUM_YUV2YUV_COEFFICIENTS; i++) {
|