This series make it possible to use more HDMI modes on RK3328, and presumably also on RK3228. It also prepares for a future YUV420 and 10-bit output series.
Part of this has been reworked from vendor BSP 4.4 kernel commits.
Patch 1-5 fixes issues and shortcomings in the inno hdmi phy driver.
Patch 6 filter out any mode having larger width then 3840 pixels, e.g 4096x2304 modes, since limitations in the scaler code trigger an error for a large console framebuffer.
Patch 7 prepares for use of high TMDS bit rates used with HDMI2.0 and 10-bit output modes.
Patch 8-14 changes rk3228/rk3328 to use mode_valid functions suited for the inno hdmi phy instead of the dw-hdmi phy. This
Patch 15 adds support for more pixel clock rates in order to support common DMT modes in addition to CEA modes.
Note: I have only been able to build test RK322x related changes as I do not have any RK322x device to test on.
All modes, including fractal modes, has been tested with modetest on a RK3328 Rock64 device.
modetest -M rockchip -s 39:3840x2160-29.97
Regards, Jonas
Algea Cao (1): phy/rockchip: inno-hdmi: Support more pre-pll configuration
Huicong Xu (1): phy/rockchip: inno-hdmi: force set_rate on power_on
Jonas Karlman (12): phy/rockchip: inno-hdmi: use correct vco_div_5 macro on rk3328 phy/rockchip: inno-hdmi: remove unused no_c from rk3328 recalc_rate phy/rockchip: inno-hdmi: do not power on rk3328 post pll on reg write drm/rockchip: vop: limit resolution width to 3840 drm/rockchip: dw-hdmi: allow high tmds bit rates drm/rockchip: dw-hdmi: require valid vpll clock rate on rk3228/rk3328 clk: rockchip: set parent rate for DCLK_VOP clock on rk3228 arm64: dts: rockchip: increase vop clock rate on rk3328 arm64: dts: rockchip: add vpll clock to hdmi node on rk3328 ARM: dts: rockchip: add vpll clock to hdmi node on rk3228 drm/rockchip: dw-hdmi: limit tmds to 340mhz on rk3228/rk3328 drm/rockchip: dw-hdmi: remove unused plat_data on rk3228/rk3328
Zheng Yang (1): phy/rockchip: inno-hdmi: round fractal pixclock in rk3328 recalc_rate
arch/arm/boot/dts/rk322x.dtsi | 4 +- arch/arm64/boot/dts/rockchip/rk3328.dtsi | 6 +- drivers/clk/rockchip/clk-rk3228.c | 2 +- drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 47 ++++++-- drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 10 ++ drivers/phy/rockchip/phy-rockchip-inno-hdmi.c | 110 ++++++++++++------ 6 files changed, 130 insertions(+), 49 deletions(-)
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 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;
From: Huicong Xu xhc@rock-chips.com
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 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; }
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),
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,
dri-devel@lists.freedesktop.org