build/patch/kernel/rk322x-current/01-linux-0006-experimental.patch.disabled
Paolo 804a6b60d4
Moved rk322x-dev to rk322x-current (current now is 5.7.y) (#2153)
Adapted rk322x-dev to kernel 5.8.y
Added ssv6x5x driver to legacy kernel, rk322x-config now allows the user to select which driver load at boot
Added esp8089 kernel module, device tree overlay and detection in rk322x-config script
Fixed some indentation
Added reset button binding
Added sdcard debounce
Fixes indentation, added device tree overlay for high-leakage cpus
Added support for bluetooth device tree overlay and realtek systemd service for rk322x targets
2020-08-28 18:48:55 +02:00

1825 lines
64 KiB
Text

diff --git a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
index 9ca20c947283..b0ac1d3ee390 100644
--- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
+++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
@@ -790,8 +790,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;
--
2.17.1
From 0ae81f8167f59ad2c781dc51f2b2fa3e0c9f976b Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Fri, 20 Dec 2019 08:12:42 +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 b0ac1d3ee390..093d2334e8cd 100644
--- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
+++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
@@ -745,10 +745,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,
--
2.17.1
From fcb6a75bac484bec5443241965757b2d7cf99182 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Fri, 20 Dec 2019 08:12:42 +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 093d2334e8cd..06db69c8373e 100644
--- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
+++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
@@ -714,7 +714,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;
@@ -737,9 +737,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));
--
2.17.1
From 8da78b0cf0c522be59656ed24a0018bd2fbea5a8 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Fri, 20 Dec 2019 08:12:42 +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 06db69c8373e..3a59a6da0440 100644
--- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
+++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
@@ -1020,9 +1020,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;
@@ -1030,7 +1031,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++)
--
2.17.1
From 790af1279068ad1cc4ef471d90050570a850f426 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Fri, 20 Dec 2019 08:12:42 +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: 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 3a59a6da0440..3719309ad0d0 100644
--- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
+++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
@@ -245,6 +245,7 @@ struct inno_hdmi_phy {
struct clk_hw hw;
struct clk *phyclk;
unsigned long pixclock;
+ unsigned long tmdsclock;
};
struct pre_pll_config {
@@ -485,6 +486,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;
@@ -509,6 +512,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;
@@ -628,6 +633,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);
@@ -670,6 +678,7 @@ static int inno_hdmi_phy_rk3228_clk_set_rate(struct clk_hw *hw,
}
inno->pixclock = rate;
+ inno->tmdsclock = tmdsclock;
return 0;
}
@@ -781,6 +790,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);
@@ -820,6 +832,7 @@ static int inno_hdmi_phy_rk3328_clk_set_rate(struct clk_hw *hw,
}
inno->pixclock = rate;
+ inno->tmdsclock = tmdsclock;
return 0;
}
--
2.17.1
From 852eb17bca3ae36762eb2975bb9a5642cf0865d8 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Sat, 21 Dec 2019 23:52:16 +0000
Subject: [PATCH] drm/rockchip: vop: limit resolution width to 3840
Using a destination width that is more then 3840 pixels
is not supported in scl_vop_cal_scl_fac().
Work around this limitation by filtering all modes with
a width above 3840.
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
---
drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index d04b3492bdac..f181897cbfad 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -1036,6 +1036,15 @@ static void vop_crtc_disable_vblank(struct drm_crtc *crtc)
spin_unlock_irqrestore(&vop->irq_lock, flags);
}
+enum drm_mode_status vop_crtc_mode_valid(struct drm_crtc *crtc,
+ const struct drm_display_mode *mode)
+{
+ if (mode->hdisplay > 3840)
+ return MODE_BAD_HVALUE;
+
+ 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)
@@ -1377,6 +1386,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,
--
2.17.1
From 1f18ed83f51df960be0688db39b086b9a58ef7d1 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Sun, 22 Dec 2019 12:43:36 +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 7f56d8c3491d..fae38b323a0c 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -318,6 +318,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);
+
return phy_power_on(hdmi->phy);
}
--
2.17.1
From d8ee714e54380f7b09dd088944f5c030aa1ee320 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Sun, 22 Dec 2019 12:35:16 +0000
Subject: [PATCH] drm/rockchip: dw-hdmi: require valid vpll clock rate on
rk3228/rk3328
RK3228/RK3328 can only support clock rates defined in the pre pll table.
Lets validate the mode clock rate against the pre pll config and filter
out any mode with a clock rate returning error from clk_round_rate().
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
---
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
index fae38b323a0c..45fcdce3f27f 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -245,6 +245,22 @@ static void dw_hdmi_rockchip_encoder_disable(struct drm_encoder *encoder)
{
}
+static enum drm_mode_status
+dw_hdmi_rockchip_encoder_mode_valid(struct drm_encoder *encoder,
+ const struct drm_display_mode *mode)
+{
+ struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder);
+ long rate;
+
+ if (hdmi->vpll_clk) {
+ rate = clk_round_rate(hdmi->vpll_clk, mode->clock * 1000);
+ if (rate < 0)
+ return MODE_CLOCK_RANGE;
+ }
+
+ return MODE_OK;
+}
+
static bool
dw_hdmi_rockchip_encoder_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
@@ -306,6 +322,7 @@ dw_hdmi_rockchip_encoder_atomic_check(struct drm_encoder *encoder,
}
static const struct drm_encoder_helper_funcs dw_hdmi_rockchip_encoder_helper_funcs = {
+ .mode_valid = dw_hdmi_rockchip_encoder_mode_valid,
.mode_fixup = dw_hdmi_rockchip_encoder_mode_fixup,
.mode_set = dw_hdmi_rockchip_encoder_mode_set,
.enable = dw_hdmi_rockchip_encoder_enable,
--
2.17.1
From f305ae2094370127c797a4af3772bd9ff4e8dfc2 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Sun, 22 Dec 2019 23:42:45 +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 d17cfb7a3ff4..25f79af22cb8 100644
--- a/drivers/clk/rockchip/clk-rk3228.c
+++ b/drivers/clk/rockchip/clk-rk3228.c
@@ -410,7 +410,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),
--
2.17.1
From 69f1bbcbc9c02c34f4fda49191ccae1f9dac410e Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Sun, 15 Dec 2019 10:05:46 +0000
Subject: [PATCH] arm64: dts: rockchip: increase vop clock rate on rk3328
The VOP on RK3328 needs to run faster in order to procude 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 bc9186f66d9c..d4cfb1066c5a 100644
--- a/arch/arm64/boot/dts/rockchip/rk3328.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3328.dtsi
@@ -834,8 +834,8 @@
<0>, <24000000>,
<24000000>, <24000000>,
<15000000>, <15000000>,
- <100000000>, <100000000>,
- <100000000>, <100000000>,
+ <300000000>, <100000000>,
+ <400000000>, <100000000>,
<50000000>, <100000000>,
<100000000>, <100000000>,
<50000000>, <50000000>,
--
2.17.1
From 2aeb955b7a259182df7c2244531abd4bf233f60b Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Sun, 22 Dec 2019 23:43:40 +0000
Subject: [PATCH] arm64: dts: rockchip: add vpll clock to hdmi node on rk3328
Add the hdmiphy clock as the vpll in hdmi node.
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
---
arch/arm64/boot/dts/rockchip/rk3328.dtsi | 2 ++
1 file changed, 2 insertions(+)
diff --git a/arch/arm64/boot/dts/rockchip/rk3328.dtsi b/arch/arm64/boot/dts/rockchip/rk3328.dtsi
index d4cfb1066c5a..991d2a830887 100644
--- a/arch/arm64/boot/dts/rockchip/rk3328.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3328.dtsi
@@ -750,9 +750,11 @@
<GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cru PCLK_HDMI>,
<&cru SCLK_HDMI_SFC>,
+ <&hdmiphy>,
<&cru SCLK_RTC32K>;
clock-names = "iahb",
"isfr",
+ "vpll",
"cec";
phys = <&hdmiphy>;
phy-names = "hdmi";
--
2.17.1
From a972a8f4fbc0db4c71fcf2d7eb1c1dcc31a8d089 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Sun, 22 Dec 2019 23:43:58 +0000
Subject: [PATCH] ARM: dts: rockchip: add vpll clock to hdmi node on rk3228
Add the hdmiphy clock as the vpll in hdmi node.
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
---
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 4e90efdc9630..1e31f6898797 100644
--- a/arch/arm/boot/dts/rk322x.dtsi
+++ b/arch/arm/boot/dts/rk322x.dtsi
@@ -639,8 +639,8 @@
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>;
--
2.17.1
From ad13781b15e2a4657e52147461565b99e16dca65 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Sun, 22 Dec 2019 10:42:02 +0000
Subject: [PATCH] drm/rockchip: dw-hdmi: limit tmds to 340mhz on rk3228/rk3328
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.
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
---
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 22 +++++++++++++++++++--
1 file changed, 20 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
index 45fcdce3f27f..66c14df4a680 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -237,6 +237,24 @@ dw_hdmi_rockchip_mode_valid(struct drm_connector *connector,
return (valid) ? MODE_OK : MODE_BAD;
}
+static enum drm_mode_status
+dw_hdmi_rk3228_mode_valid(struct drm_connector *connector,
+ const struct drm_display_mode *mode)
+{
+ struct drm_display_info *info = &connector->display_info;
+ int max_tmds_clock = max(info->max_tmds_clock, 165000);
+ int clock = mode->clock;
+
+ if (connector->ycbcr_420_allowed && drm_mode_is_420(info, mode) &&
+ (info->color_formats & DRM_COLOR_FORMAT_YCRCB420))
+ clock /= 2;
+
+ if (clock > max_tmds_clock || clock > 340000)
+ return MODE_CLOCK_HIGH;
+
+ return MODE_OK;
+}
+
static const struct drm_encoder_funcs dw_hdmi_rockchip_encoder_funcs = {
.destroy = drm_encoder_cleanup,
};
@@ -424,7 +442,7 @@ 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,
+ .mode_valid = dw_hdmi_rk3228_mode_valid,
.mpll_cfg = rockchip_mpll_cfg,
.cur_ctr = rockchip_cur_ctr,
.phy_config = rockchip_phy_config,
@@ -461,7 +479,7 @@ 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,
+ .mode_valid = dw_hdmi_rk3228_mode_valid,
.mpll_cfg = rockchip_mpll_cfg,
.cur_ctr = rockchip_cur_ctr,
.phy_config = rockchip_phy_config,
--
2.17.1
From 8e950f0d07a1cea3ad58bd654c91a747d2902c6c Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Sun, 22 Dec 2019 10:42:27 +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 66c14df4a680..a813299e97a2 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -443,9 +443,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_rk3228_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",
@@ -480,9 +477,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_rk3228_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",
--
2.17.1
From 34326d29065869cc262b2f1644310ec9417dac29 Mon Sep 17 00:00:00 2001
From: Algea Cao <algea.cao@rock-chips.com>
Date: Fri, 18 May 2018 14:32:08 +0800
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>
---
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 3719309ad0d0..bb8bdf5e3301 100644
--- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
+++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
@@ -291,32 +291,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 */ }
};
--
2.17.1
From e63e0475c82b77a9e255b1dd354df20e02a73390 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 | 121 ++++++++++++++--------
1 file changed, 78 insertions(+), 43 deletions(-)
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index cc39b544ae6e..66e3fed23f4b 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -1854,6 +1854,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_mode *mode)
{
@@ -1863,28 +1878,12 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
int hblank, vblank, h_de_hs, v_de_vs, hsync_len, vsync_len;
unsigned int vdisplay, hdisplay;
- vmode->mtmdsclock = vmode->mpixelclock = mode->clock * 1000;
+ 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);
-
- 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 = (u64)vmode->mpixelclock * 2;
- break;
- case 12:
- vmode->mtmdsclock = (u64)vmode->mpixelclock * 3 / 2;
- break;
- case 10:
- vmode->mtmdsclock = (u64)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 tmdsclk = %d\n", vmode->mtmdsclock);
/* Set up HDMI_FC_INVIDCONF */
@@ -2511,8 +2510,21 @@ static const struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs =
* - MEDIA_BUS_FMT_RGB888_1X24,
*/
-/* Can return a maximum of 12 possible output formats for a mode/connector */
-#define MAX_OUTPUT_SEL_FORMATS 12
+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 = max(info->max_tmds_clock, 165000);
+
+ if (max_tmds_clock >= tmdsclock)
+ return true;
+
+ return false;
+}
+
+/* Can return a maximum of 16 possible output formats for a mode/connector */
+#define MAX_OUTPUT_SEL_FORMATS 16
static u32 *dw_hdmi_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge,
struct drm_bridge_state *bridge_state,
@@ -2524,8 +2536,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;
int i = 0;
@@ -2540,29 +2550,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;
}
/*
@@ -2571,40 +2585,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;
@@ -2811,12 +2836,22 @@ dw_hdmi_bridge_mode_valid(struct drm_bridge *bridge,
{
struct dw_hdmi *hdmi = bridge->driver_private;
struct drm_connector *connector = &hdmi->connector;
+ struct drm_display_info *info = &connector->display_info;
enum drm_mode_status mode_status = MODE_OK;
+ int max_tmds_clock = max(info->max_tmds_clock, 165000);
+ int clock = mode->clock;
/* We don't support double-clocked modes */
if (mode->flags & DRM_MODE_FLAG_DBLCLK)
return MODE_BAD;
+ if (connector->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 (hdmi->plat_data->mode_valid)
mode_status = hdmi->plat_data->mode_valid(connector, mode);
--
2.17.1
From 5c3bbae0afe43b4856b9c9e344bb7eea3702e4f0 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Sat, 21 Dec 2019 06:23:52 +0000
Subject: [PATCH] WIP: drm/bridge: dw-hdmi: do not enable csc for yuv2yuv
---
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index 66e3fed23f4b..df1789cd8712 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -966,6 +966,14 @@ static void hdmi_video_sample(struct dw_hdmi *hdmi)
static int is_color_space_conversion(struct dw_hdmi *hdmi)
{
+ if (hdmi_bus_fmt_is_yuv444(hdmi->hdmi_data.enc_in_bus_format) &&
+ hdmi_bus_fmt_is_yuv422(hdmi->hdmi_data.enc_out_bus_format))
+ return 0;
+
+ if (hdmi_bus_fmt_is_yuv422(hdmi->hdmi_data.enc_in_bus_format) &&
+ hdmi_bus_fmt_is_yuv444(hdmi->hdmi_data.enc_out_bus_format))
+ return 0;
+
return hdmi->hdmi_data.enc_in_bus_format != hdmi->hdmi_data.enc_out_bus_format;
}
@@ -2050,7 +2058,9 @@ static void dw_hdmi_enable_video_path(struct dw_hdmi *hdmi)
hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS);
/* Enable csc path */
- if (is_color_space_conversion(hdmi)) {
+ if (is_color_space_conversion(hdmi) ||
+ is_color_space_decimation(hdmi) ||
+ is_color_space_interpolation(hdmi)) {
hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_CSCCLK_DISABLE;
hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS);
}
--
2.17.1
From fd86f78d28a4b6c5fc7440e42916f3f86a7797a4 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.
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
---
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 65 ++++++++++-----------
1 file changed, 31 insertions(+), 34 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
index a813299e97a2..8bc42090d0a3 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -67,6 +67,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;
@@ -259,15 +260,11 @@ static const struct drm_encoder_funcs dw_hdmi_rockchip_encoder_funcs = {
.destroy = drm_encoder_cleanup,
};
-static void dw_hdmi_rockchip_encoder_disable(struct drm_encoder *encoder)
-{
-}
-
static enum drm_mode_status
-dw_hdmi_rockchip_encoder_mode_valid(struct drm_encoder *encoder,
- const struct drm_display_mode *mode)
+dw_hdmi_rockchip_bridge_mode_valid(struct drm_bridge *bridge,
+ const struct drm_display_mode *mode)
{
- struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder);
+ struct rockchip_hdmi *hdmi = to_rockchip_hdmi(bridge);
long rate;
if (hdmi->vpll_clk) {
@@ -279,26 +276,20 @@ dw_hdmi_rockchip_encoder_mode_valid(struct drm_encoder *encoder,
return MODE_OK;
}
-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;
-}
-
-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_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(encoder);
+ struct rockchip_hdmi *hdmi = to_rockchip_hdmi(bridge);
- clk_set_rate(hdmi->vpll_clk, adj_mode->clock * 1000);
+ clk_set_rate(hdmi->vpll_clk, adjusted_mode->clock * 1000);
}
-static void dw_hdmi_rockchip_encoder_enable(struct drm_encoder *encoder)
+static void dw_hdmi_rockchip_bridge_enable(struct drm_bridge *bridge)
{
- 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;
@@ -327,9 +318,10 @@ static void dw_hdmi_rockchip_encoder_enable(struct drm_encoder *encoder)
}
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);
@@ -339,13 +331,11 @@ 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_valid = dw_hdmi_rockchip_encoder_mode_valid,
- .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 const struct drm_bridge_funcs dw_hdmi_rockchip_bridge_funcs = {
+ .mode_valid = dw_hdmi_rockchip_bridge_mode_valid,
+ .mode_set = dw_hdmi_rockchip_bridge_mode_set,
+ .enable = dw_hdmi_rockchip_bridge_enable,
+ .atomic_check = dw_hdmi_rockchip_bridge_atomic_check,
};
static int dw_hdmi_rockchip_genphy_init(struct dw_hdmi *dw_hdmi, void *data,
@@ -523,6 +513,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;
@@ -576,13 +567,15 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
return ret;
}
- drm_encoder_helper_add(encoder, &dw_hdmi_rockchip_encoder_helper_funcs);
drm_encoder_init(drm, encoder, &dw_hdmi_rockchip_encoder_funcs,
DRM_MODE_ENCODER_TMDS, NULL);
+ hdmi->bridge.funcs = &dw_hdmi_rockchip_bridge_funcs;
+ drm_bridge_attach(encoder, &hdmi->bridge, NULL);
+
platform_set_drvdata(pdev, hdmi);
- hdmi->hdmi = dw_hdmi_bind(pdev, encoder, plat_data);
+ hdmi->hdmi = dw_hdmi_probe(pdev, plat_data);
/*
* If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(),
@@ -594,6 +587,10 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
clk_disable_unprepare(hdmi->vpll_clk);
}
+ next_bridge = of_drm_find_bridge(pdev->dev.of_node);
+ if (next_bridge)
+ drm_bridge_attach(encoder, next_bridge, &hdmi->bridge);
+
return ret;
}
--
2.17.1
From 1e915225fe362b6ab98bec9bc71c62315347eccb 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: enable bridge bus format negotiation
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 | 35 +++++++++++++++++++++
1 file changed, 35 insertions(+)
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
index 8bc42090d0a3..83a22a061e52 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -317,6 +317,16 @@ static void dw_hdmi_rockchip_bridge_enable(struct drm_bridge *bridge)
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_bridge_atomic_check(struct drm_bridge *bridge,
struct drm_bridge_state *bridge_state,
@@ -331,11 +341,36 @@ dw_hdmi_rockchip_bridge_atomic_check(struct drm_bridge *bridge,
return 0;
}
+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_valid = dw_hdmi_rockchip_bridge_mode_valid,
.mode_set = dw_hdmi_rockchip_bridge_mode_set,
.enable = dw_hdmi_rockchip_bridge_enable,
.atomic_check = dw_hdmi_rockchip_bridge_atomic_check,
+ .atomic_get_input_bus_fmts = dw_hdmi_rockchip_get_input_bus_fmts,
};
static int dw_hdmi_rockchip_genphy_init(struct dw_hdmi *dw_hdmi, void *data,
--
2.17.1
From b4cbb8eae8f3a5dbdbb844d59dfd7c979a88f66a 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 +
drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 10 ++++-
3 files changed, 52 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
index 83a22a061e52..3c8a95cd38dc 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -76,6 +76,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 c5b06048124e..af1b85d8f7ee 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
@@ -30,6 +30,8 @@ struct rockchip_crtc_state {
int output_mode;
int output_bpc;
int output_flags;
+ u32 bus_format;
+ int bus_width;
};
#define to_rockchip_crtc_state(s) \
container_of(s, struct rockchip_crtc_state, base)
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index f181897cbfad..e59213d3ea62 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -1402,13 +1402,21 @@ static void vop_crtc_destroy(struct drm_crtc *crtc)
static struct drm_crtc_state *vop_crtc_duplicate_state(struct drm_crtc *crtc)
{
- struct rockchip_crtc_state *rockchip_state;
+ struct rockchip_crtc_state *rockchip_state, *s;
+
+ if (WARN_ON(!crtc->state))
+ return NULL;
rockchip_state = kzalloc(sizeof(*rockchip_state), GFP_KERNEL);
if (!rockchip_state)
return NULL;
__drm_atomic_helper_crtc_duplicate_state(crtc, &rockchip_state->base);
+
+ s = to_rockchip_crtc_state(crtc->state);
+ rockchip_state->bus_format = s->bus_format;
+ rockchip_state->bus_width = s->bus_width;
+
return &rockchip_state->base;
}
--
2.17.1
From 9fedc6efc787bddfad71c6145cf3cbee49ea257d 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 | 29 ++++++++++++++++++++-
drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 29 +++++++++++++++++++++
drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 5 ++++
drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 10 +++++++
4 files changed, 72 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
index 3c8a95cd38dc..9b3c2318ce0e 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -61,6 +61,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);
@@ -539,6 +565,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 = {
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index e59213d3ea62..5bf833ea8ce2 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -274,6 +274,17 @@ static enum vop_data_format vop_convert_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:
+ 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)
@@ -1181,6 +1192,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) {
@@ -1254,6 +1266,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
@@ -1269,6 +1283,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 0b3d18c457b2..9393cf12b1db 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
@@ -77,6 +77,11 @@ 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 {
diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
index 7a9d979c8d5d..b99e902d949e 100644
--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
+++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
@@ -606,6 +606,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),
};
/*
@@ -914,6 +919,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 = {
--
2.17.1
From 111c35c19a742d7b76b6f548103f8b561c45a186 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 | 22 +++++++++++++++++++++
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, 47 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
index 9b3c2318ce0e..eb405cb3d1f6 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;
@@ -575,6 +596,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 = {
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index 5bf833ea8ce2..b8c0d2fcc52a 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -275,6 +275,19 @@ static enum vop_data_format vop_convert_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:
@@ -1266,7 +1279,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);
@@ -1283,6 +1296,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 9393cf12b1db..89fe8d5c7721 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
@@ -79,6 +79,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;
@@ -230,11 +231,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 b99e902d949e..73d24c6bbf05 100644
--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
+++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
@@ -608,6 +608,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),
@@ -921,6 +922,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),
--
2.17.1
From a8f40af332f87e74015d578a14e4491d1e0c9291 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Sun, 8 Dec 2019 23:49:00 +0000
Subject: [PATCH] WIP: drm/bridge: dw-hdmi: signal default quant range
---
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index df1789cd8712..14a1131cfc21 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -1673,6 +1673,9 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
HDMI_EXTENDED_COLORIMETRY_XV_YCC_601;
}
+ drm_hdmi_avi_infoframe_quant_range(&frame, &hdmi->connector, mode,
+ drm_default_rgb_quant_range(mode));
+
drm_hdmi_avi_infoframe_content_type(&frame, conn_state);
hdmi_infoframe_log(KERN_INFO, hdmi->dev, (union hdmi_infoframe *)&frame);
--
2.17.1
From aa34fb23453ea76f533d0af601ec0ce5ee9d8312 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: use avmute during modeset
---
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 4 ++++
drivers/gpu/drm/bridge/synopsys/dw-hdmi.h | 4 ++++
2 files changed, 8 insertions(+)
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index 14a1131cfc21..6344c8aac13e 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -2328,10 +2328,14 @@ static void dw_hdmi_poweron(struct dw_hdmi *hdmi)
hdmi->bridge_is_on = true;
dw_hdmi_get_edid(&hdmi->connector);
dw_hdmi_setup(hdmi, &hdmi->previous_mode);
+
+ hdmi_writeb(hdmi, HDMI_FC_GCP_CLEAR_AVMUTE, HDMI_FC_GCP);
}
static void dw_hdmi_poweroff(struct dw_hdmi *hdmi)
{
+ hdmi_writeb(hdmi, HDMI_FC_GCP_SET_AVMUTE, HDMI_FC_GCP);
+
if (hdmi->phy.enabled) {
hdmi->phy.ops->disable(hdmi, hdmi->phy.data);
hdmi->phy.enabled = false;
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h
index 27a91128d0cc..3810326794cc 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h
@@ -842,6 +842,10 @@ enum {
HDMI_FC_AVICONF3_QUANT_RANGE_LIMITED = 0x00,
HDMI_FC_AVICONF3_QUANT_RANGE_FULL = 0x04,
+/* HDMI_FC_GCP */
+ HDMI_FC_GCP_SET_AVMUTE = 0x2,
+ HDMI_FC_GCP_CLEAR_AVMUTE = 0x1,
+
/* FC_DBGFORCE field values */
HDMI_FC_DBGFORCE_FORCEAUDIO = 0x10,
HDMI_FC_DBGFORCE_FORCEVIDEO = 0x1,
--
2.17.1