diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index 01d85f72981f..c7c97dab267f 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c @@ -2509,6 +2509,15 @@ static int dw_hdmi_connector_get_modes(struct drm_connector *connector) return ret; } +static struct drm_encoder * +dw_hdmi_connector_best_encoder(struct drm_connector *connector) +{ + struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, + connector); + + return hdmi->bridge.encoder; +} + static bool hdr_metadata_equal(const struct drm_connector_state *old_state, const struct drm_connector_state *new_state) { @@ -2572,6 +2581,7 @@ static const struct drm_connector_funcs dw_hdmi_connector_funcs = { static const struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs = { .get_modes = dw_hdmi_connector_get_modes, + .best_encoder = dw_hdmi_connector_best_encoder, .atomic_check = dw_hdmi_connector_atomic_check, }; @@ -2926,6 +2936,7 @@ dw_hdmi_bridge_mode_valid(struct drm_bridge *bridge, const struct drm_display_mode *mode) { struct dw_hdmi *hdmi = bridge->driver_private; + struct drm_connector *connector = &hdmi->connector; const struct dw_hdmi_plat_data *pdata = hdmi->plat_data; enum drm_mode_status mode_status = MODE_OK; @@ -2934,8 +2945,8 @@ dw_hdmi_bridge_mode_valid(struct drm_bridge *bridge, return MODE_BAD; if (pdata->mode_valid) - mode_status = pdata->mode_valid(hdmi, pdata->priv_data, info, - mode); + mode_status = pdata->mode_valid(connector, pdata->priv_data, + info, mode); return mode_status; } diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index 162d3d9eec4f..5b2658093042 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c @@ -273,21 +273,16 @@ 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 drm_connector *connector, 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; + struct drm_encoder *encoder = connector->encoder; + enum drm_mode_status status = MODE_OK; + struct drm_device *dev = connector->dev; + struct rockchip_drm_private *priv = dev->dev_private; + struct drm_crtc *crtc; - for (i = 0; mpll_cfg[i].mpixelclock != (~0UL); i++) { - if (pclk == mpll_cfg[i].mpixelclock) { - valid = true; - break; - } - } /* * Pixel clocks we support are always < 2GHz and so fit in an * int. We should make sure source rate does too so we don't get @@ -296,7 +291,41 @@ dw_hdmi_rockchip_mode_valid(struct dw_hdmi *hdmi, void *data, if (mode->clock > INT_MAX / 1000) return MODE_BAD; - return (valid) ? MODE_OK : MODE_BAD; + if (!encoder) { + const struct drm_connector_helper_funcs *funcs; + + funcs = connector->helper_private; + if (funcs->atomic_best_encoder) + encoder = funcs->atomic_best_encoder(connector, + connector->state); + else + encoder = funcs->best_encoder(connector); + } + + if (!encoder || !encoder->possible_crtcs) + return MODE_BAD; + /* + * ensure all drm display mode can work, if someone want support more + * resolutions, please limit the possible_crtc, only connect to + * needed crtc. + */ + drm_for_each_crtc(crtc, connector->dev) { + int pipe = drm_crtc_index(crtc); + const struct rockchip_crtc_funcs *funcs = + priv->crtc_funcs[pipe]; + + if (!(encoder->possible_crtcs & drm_crtc_mask(crtc))) + continue; + if (!funcs || !funcs->mode_valid) + continue; + + status = funcs->mode_valid(crtc, mode, + DRM_MODE_CONNECTOR_HDMIA); + if (status != MODE_OK) + return status; + } + + return status; } static void dw_hdmi_rockchip_encoder_disable(struct drm_encoder *encoder) diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h index 90242edb3f34..cc3680cc646c 100644 --- a/include/drm/bridge/dw_hdmi.h +++ b/include/drm/bridge/dw_hdmi.h @@ -144,7 +144,8 @@ struct dw_hdmi_plat_data { void *priv_data; /* Platform-specific mode validation (optional). */ - enum drm_mode_status (*mode_valid)(struct dw_hdmi *hdmi, void *data, + enum drm_mode_status (*mode_valid)(struct drm_connector *connector, + void *data, const struct drm_display_info *info, const struct drm_display_mode *mode);