diff options
Diffstat (limited to 'drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c')
-rw-r--r-- | drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 42 |
1 files changed, 35 insertions, 7 deletions
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index 2f4b8f64cbad..112699949db9 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c @@ -74,6 +74,7 @@ struct rockchip_hdmi { struct regmap *regmap; struct rockchip_encoder encoder; const struct rockchip_hdmi_chip_data *chip_data; + const struct dw_hdmi_plat_data *plat_data; struct clk *ref_clk; struct clk *grf_clk; struct dw_hdmi *hdmi; @@ -161,6 +162,12 @@ static const struct dw_hdmi_mpll_config rockchip_mpll_cfg[] = { { 0x4064, 0x0003} }, }, { + 340000000, { + { 0x0040, 0x0003 }, + { 0x3b4c, 0x0003 }, + { 0x5a64, 0x0003 }, + }, + }, { ~0UL, { { 0x00a0, 0x000a }, { 0x2001, 0x000f }, @@ -186,6 +193,8 @@ static const struct dw_hdmi_curr_ctrl rockchip_cur_ctr[] = { }, { 148500000, { 0x0000, 0x0038, 0x0038 }, }, { + 600000000, { 0x0000, 0x0000, 0x0000 }, + }, { ~0UL, { 0x0000, 0x0000, 0x0000}, } }; @@ -241,23 +250,39 @@ static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi) } static enum drm_mode_status -dw_hdmi_rockchip_mode_valid(struct dw_hdmi *hdmi, void *data, +dw_hdmi_rockchip_mode_valid(struct dw_hdmi *dw_hdmi, void *data, const struct drm_display_info *info, const struct drm_display_mode *mode) { + struct rockchip_hdmi *hdmi = data; const struct dw_hdmi_mpll_config *mpll_cfg = rockchip_mpll_cfg; int pclk = mode->clock * 1000; - bool valid = false; + bool exact_match = hdmi->plat_data->phy_force_vendor; int i; + if (hdmi->ref_clk) { + int rpclk = clk_round_rate(hdmi->ref_clk, pclk); + + if (abs(rpclk - pclk) > pclk / 1000) + return MODE_NOCLOCK; + } + for (i = 0; mpll_cfg[i].mpixelclock != (~0UL); i++) { - if (pclk == mpll_cfg[i].mpixelclock) { - valid = true; - break; - } + /* + * For vendor specific phys force an exact match of the pixelclock + * to preserve the original behaviour of the driver. + */ + if (exact_match && pclk == mpll_cfg[i].mpixelclock) + return MODE_OK; + /* + * The Synopsys phy can work with pixelclocks up to the value given + * in the corresponding mpll_cfg entry. + */ + if (!exact_match && pclk <= mpll_cfg[i].mpixelclock) + return MODE_OK; } - return (valid) ? MODE_OK : MODE_BAD; + return MODE_BAD; } static void dw_hdmi_rockchip_encoder_disable(struct drm_encoder *encoder) @@ -546,8 +571,10 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, return -ENOMEM; hdmi->dev = &pdev->dev; + hdmi->plat_data = plat_data; hdmi->chip_data = plat_data->phy_data; plat_data->phy_data = hdmi; + plat_data->priv_data = hdmi; encoder = &hdmi->encoder.encoder; encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node); @@ -640,6 +667,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); + drm_encoder_cleanup(&hdmi->encoder.encoder); clk_disable_unprepare(hdmi->ref_clk); regulator_disable(hdmi->avdd_1v8); |