}
static int
-intel_dp_compute_link_config(struct intel_encoder *encoder,
- struct intel_crtc_state *pipe_config,
- struct drm_connector_state *conn_state,
- bool respect_downstream_limits)
+intel_dp_compute_link_for_joined_pipes(struct intel_encoder *encoder,
+ struct intel_crtc_state *pipe_config,
+ struct drm_connector_state *conn_state,
+ bool respect_downstream_limits)
{
struct intel_display *display = to_intel_display(encoder);
- struct intel_crtc *crtc = to_intel_crtc(pipe_config->uapi.crtc);
+ int num_joined_pipes = intel_crtc_num_joined_pipes(pipe_config);
struct intel_connector *connector =
to_intel_connector(conn_state->connector);
const struct drm_display_mode *adjusted_mode =
&pipe_config->hw.adjusted_mode;
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+ int max_dotclk = display->cdclk.max_dotclk_freq;
struct link_config_limits limits;
bool dsc_needed, joiner_needs_dsc;
- int num_joined_pipes;
int ret = 0;
- if (pipe_config->fec_enable &&
- !intel_dp_supports_fec(intel_dp, connector, pipe_config))
- return -EINVAL;
-
- num_joined_pipes = intel_dp_num_joined_pipes(intel_dp, connector,
- adjusted_mode->crtc_hdisplay,
- adjusted_mode->crtc_clock);
- if (num_joined_pipes > 1)
- pipe_config->joiner_pipes = GENMASK(crtc->pipe + num_joined_pipes - 1, crtc->pipe);
-
+ max_dotclk *= num_joined_pipes;
joiner_needs_dsc = intel_dp_joiner_needs_dsc(display, num_joined_pipes);
dsc_needed = joiner_needs_dsc || intel_dp->force_dsc_en ||
fxp_q4_from_int(pipe_config->pipe_bpp),
fxp_q4_from_int(pipe_config->pipe_bpp),
0, false);
- if (ret)
+
+ if (ret || adjusted_mode->crtc_clock > max_dotclk)
dsc_needed = true;
}
conn_state, &limits, 64);
if (ret < 0)
return ret;
+
+ if (adjusted_mode->crtc_clock > max_dotclk)
+ return -EINVAL;
}
drm_dbg_kms(display->drm,
return 0;
}
+static int
+intel_dp_compute_link_config(struct intel_encoder *encoder,
+ struct intel_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state,
+ bool respect_downstream_limits)
+{
+ struct intel_display *display = to_intel_display(encoder);
+ struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+ struct intel_connector *connector =
+ to_intel_connector(conn_state->connector);
+ const struct drm_display_mode *adjusted_mode =
+ &crtc_state->hw.adjusted_mode;
+ struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+ int num_joined_pipes;
+ int ret = -EINVAL;
+
+ if (crtc_state->fec_enable &&
+ !intel_dp_supports_fec(intel_dp, connector, crtc_state))
+ return -EINVAL;
+
+ for (num_joined_pipes = 1; num_joined_pipes <= I915_MAX_PIPES; num_joined_pipes++) {
+ if (connector->force_joined_pipes &&
+ num_joined_pipes != connector->force_joined_pipes)
+ continue;
+
+ if (!intel_dp_can_join(display, num_joined_pipes))
+ continue;
+
+ if (adjusted_mode->hdisplay >
+ num_joined_pipes * intel_dp_max_hdisplay_per_pipe(display))
+ continue;
+
+ /*
+ * NOTE:
+ * The crtc_state->joiner_pipes should have been set at the end
+ * only if all the conditions are met. However that would mean
+ * that num_joined_pipes is passed around to all helpers and
+ * make them use it instead of using crtc_state->joiner_pipes
+ * directly or indirectly (via intel_crtc_num_joined_pipes()).
+ *
+ * For now, setting crtc_state->joiner_pipes to the candidate
+ * value to avoid the above churn and resetting it to 0, in case
+ * no joiner candidate is found to be suitable for the given
+ * configuration.
+ */
+ if (num_joined_pipes > 1)
+ crtc_state->joiner_pipes = GENMASK(crtc->pipe + num_joined_pipes - 1,
+ crtc->pipe);
+
+ ret = intel_dp_compute_link_for_joined_pipes(encoder, crtc_state, conn_state,
+ respect_downstream_limits);
+ if (ret == 0)
+ break;
+ }
+
+ if (ret < 0)
+ crtc_state->joiner_pipes = 0;
+
+ return ret;
+}
+
bool intel_dp_limited_color_range(const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state)
{