@@ -768,6 +768,52 @@ intel_dp_set_m2_n2(struct intel_crtc *crtc, struct intel_link_m_n *m_n)
I915_WRITE(PIPE_LINK_N2(transcoder), m_n->link_n);
}
+static bool link_config_is_possible(int mode_rate, int lanes, int bw)
+{
+ int link_clock, link_avail;
+
+ link_clock = drm_dp_bw_code_to_link_rate(bw);
+ link_avail = intel_dp_max_data_rate(link_clock, lanes);
+
+ DRM_DEBUG_KMS("DP link avail with 0x%x bw and %d lanes: %d. Required: %d (%d%%)\n",
+ bw, lanes, link_avail, mode_rate,
+ mode_rate * 100 / link_avail);
+
+ return (mode_rate <= link_avail);
+}
+
+/*
+ * This function tries to find the minimal number of lanes and BW required based
+ * on the parameters given. If not possible, it returns false.
+ */
+static bool intel_dp_compute_link_config(int mode_clock, int bpp,
+ int min_lanes, int max_lanes,
+ int min_bw, int max_bw,
+ int *lanes_used, int *bw_used)
+{
+ /* Conveniently, the link BW constants become indices with a shift...*/
+ static int bws[] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7, DP_LINK_BW_5_4 };
+ int min_bw_index = min_bw >> 3;
+ int max_bw_index = max_bw >> 3;
+ int mode_rate;
+ int lanes, bw_it;
+
+ mode_rate = intel_dp_link_required(mode_clock, bpp);
+
+ for (lanes = min_lanes; lanes <= max_lanes; lanes <<= 1)
+ for (bw_it = min_bw_index; bw_it <= max_bw_index; bw_it++)
+ if (link_config_is_possible(mode_rate, lanes,
+ bws[bw_it]))
+ goto found;
+
+ return false;
+
+found:
+ *lanes_used = lanes;
+ *bw_used = bws[bw_it];
+ return true;
+}
+
bool
intel_dp_compute_config(struct intel_encoder *encoder,
struct intel_crtc_config *pipe_config)
@@ -779,13 +825,10 @@ intel_dp_compute_config(struct intel_encoder *encoder,
enum port port = dp_to_dig_port(intel_dp)->port;
struct intel_crtc *intel_crtc = encoder->new_crtc;
struct intel_connector *intel_connector = intel_dp->attached_connector;
- int lane_count, clock;
+ int lanes_used, bw_used;
int max_lane_count = intel_dp_max_lane_count(intel_dp);
- /* Conveniently, the link BW constants become indices with a shift...*/
- int max_clock = intel_dp_max_link_bw(intel_dp) >> 3;
- int bpp, mode_rate;
- static int bws[] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7, DP_LINK_BW_5_4 };
- int link_avail, link_clock;
+ int max_bw = intel_dp_max_link_bw(intel_dp);
+ int bpp;
if (HAS_PCH_SPLIT(dev) && !HAS_DDI(dev) && port != PORT_A)
pipe_config->has_pch_encoder = true;
@@ -808,7 +851,7 @@ intel_dp_compute_config(struct intel_encoder *encoder,
DRM_DEBUG_KMS("DP link computation with max lane count %i "
"max bw %02x pixel clock %iKHz\n",
- max_lane_count, bws[max_clock],
+ max_lane_count, max_bw,
adjusted_mode->crtc_clock);
/* Walk through all bpp values. Luckily they're all nicely spaced with 2
@@ -821,26 +864,17 @@ intel_dp_compute_config(struct intel_encoder *encoder,
bpp = dev_priv->vbt.edp_bpp;
}
- for (; bpp >= 6*3; bpp -= 2*3) {
- mode_rate = intel_dp_link_required(adjusted_mode->crtc_clock,
- bpp);
-
- for (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) {
- for (clock = 0; clock <= max_clock; clock++) {
- link_clock = drm_dp_bw_code_to_link_rate(bws[clock]);
- link_avail = intel_dp_max_data_rate(link_clock,
- lane_count);
-
- if (mode_rate <= link_avail) {
- goto found;
- }
- }
- }
- }
+ for (; bpp >= 6*3; bpp -= 2*3)
+ if (intel_dp_compute_link_config(adjusted_mode->crtc_clock, bpp,
+ 1, max_lane_count,
+ DP_LINK_BW_1_62,
+ max_bw,
+ &lanes_used, &bw_used))
+ break;
- return false;
+ if (bpp < 6*3)
+ return false;
-found:
if (intel_dp->color_range_auto) {
/*
* See:
@@ -856,25 +890,23 @@ found:
if (intel_dp->color_range)
pipe_config->limited_color_range = true;
- intel_dp->link_bw = bws[clock];
- intel_dp->lane_count = lane_count;
+ intel_dp->link_bw = bw_used;
+ intel_dp->lane_count = lanes_used;
pipe_config->pipe_bpp = bpp;
pipe_config->port_clock = drm_dp_bw_code_to_link_rate(intel_dp->link_bw);
DRM_DEBUG_KMS("DP link bw %02x lane count %d clock %d bpp %d\n",
intel_dp->link_bw, intel_dp->lane_count,
pipe_config->port_clock, bpp);
- DRM_DEBUG_KMS("DP link bw required %i available %i\n",
- mode_rate, link_avail);
- intel_link_compute_m_n(bpp, lane_count,
+ intel_link_compute_m_n(bpp, lanes_used,
adjusted_mode->crtc_clock,
pipe_config->port_clock,
&pipe_config->dp_m_n);
if (intel_connector->panel.downclock_mode != NULL &&
intel_dp->drrs_state.type == SEAMLESS_DRRS_SUPPORT) {
- intel_link_compute_m_n(bpp, lane_count,
+ intel_link_compute_m_n(bpp, lanes_used,
intel_connector->panel.downclock_mode->clock,
pipe_config->port_clock,
&pipe_config->dp_m2_n2);