@@ -2959,7 +2959,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
target_clock = mode->clock;
edp = intel_pipe_get_output(crtc);
intel_edp_link_config(to_intel_output(edp),
- &lane, &link_bw);
+ &lane, &link_bw, &bpp);
} else {
/* DP over FDI requires target mode clock
instead of link clock */
@@ -2981,6 +2981,22 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
temp |= PIPE_8BPC;
else
temp |= PIPE_6BPC;
+ } else if (is_edp) {
+ bpp /= 3;
+ switch (bpp) {
+ case 8:
+ temp |= PIPE_8BPC;
+ break;
+ case 10:
+ temp |= PIPE_10BPC;
+ break;
+ case 6:
+ temp |= PIPE_6BPC;
+ break;
+ case 12:
+ temp |= PIPE_12BPC;
+ break;
+ }
} else
temp |= PIPE_8BPC;
I915_WRITE(pipeconf_reg, temp);
@@ -57,6 +57,7 @@ struct intel_dp_priv {
struct intel_output *intel_output;
struct i2c_adapter adapter;
struct i2c_algo_dp_aux_data algo;
+ int bpp; /* eDP */
};
static void
@@ -68,7 +69,7 @@ intel_dp_link_down(struct intel_output *intel_output, uint32_t DP);
void
intel_edp_link_config (struct intel_output *intel_output,
- int *lane_num, int *link_bw)
+ int *lane_num, int *link_bw, int *bpp)
{
struct intel_dp_priv *dp_priv = intel_output->dev_priv;
@@ -77,6 +78,35 @@ intel_edp_link_config (struct intel_output *intel_output,
*link_bw = 162000;
else if (dp_priv->link_bw == DP_LINK_BW_2_7)
*link_bw = 270000;
+
+ *bpp = dp_priv->bpp;
+}
+
+static void
+intel_edp_detect_bpp(struct drm_i915_private *dev_priv, struct intel_dp_priv *dp_priv)
+{
+ u32 temp = I915_READ(DP_A);
+ int pipe_reg = (temp & DP_PIPEB_SELECT) ? PIPEBCONF : PIPEACONF;
+
+ temp = I915_READ(pipe_reg) & PIPE_BPC_MASK;
+
+ switch (temp & PIPE_BPC_MASK) {
+ case PIPE_8BPC:
+ dp_priv->bpp = 24;
+ break;
+ case PIPE_10BPC:
+ dp_priv->bpp = 30;
+ break;
+ case PIPE_6BPC:
+ dp_priv->bpp = 18;
+ break;
+ case PIPE_12BPC:
+ dp_priv->bpp = 36;
+ break;
+ default:
+ DRM_ERROR("unknown pipe bpc value\n");
+ dp_priv->bpp = 24;
+ }
}
static int
@@ -125,9 +155,14 @@ intel_dp_link_clock(uint8_t link_bw)
/* I think this is a fiction */
static int
-intel_dp_link_required(int pixel_clock)
+intel_dp_link_required(struct intel_output *intel_output, int pixel_clock)
{
- return pixel_clock * 3;
+ struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+
+ if (IS_eDP(intel_output))
+ return (pixel_clock * dp_priv->bpp) / 8;
+ else
+ return pixel_clock * 3;
}
static int
@@ -138,7 +173,7 @@ intel_dp_mode_valid(struct drm_connector *connector,
int max_link_clock = intel_dp_link_clock(intel_dp_max_link_bw(intel_output));
int max_lanes = intel_dp_max_lane_count(intel_output);
- if (intel_dp_link_required(mode->clock) > max_link_clock * max_lanes)
+ if (intel_dp_link_required(intel_output, mode->clock) > max_link_clock * max_lanes)
return MODE_CLOCK_HIGH;
if (mode->clock < 10000)
@@ -492,7 +527,7 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
for (clock = 0; clock <= max_clock; clock++) {
int link_avail = intel_dp_link_clock(bws[clock]) * lane_count;
- if (intel_dp_link_required(mode->clock) <= link_avail) {
+ if (intel_dp_link_required(intel_output, mode->clock) <= link_avail) {
dp_priv->link_bw = bws[clock];
dp_priv->lane_count = lane_count;
adjusted_mode->clock = intel_dp_link_clock(dp_priv->link_bw);
@@ -1323,11 +1358,10 @@ intel_dp_init(struct drm_device *dev, int output_reg)
else if (output_reg == DP_D || output_reg == PCH_DP_D)
intel_output->clone_mask = (1 << INTEL_DP_D_CLONE_BIT);
- if (IS_eDP(intel_output)) {
- intel_output->crtc_mask = (1 << 1);
+ if (IS_eDP(intel_output))
intel_output->clone_mask = (1 << INTEL_EDP_CLONE_BIT);
- } else
- intel_output->crtc_mask = (1 << 0) | (1 << 1);
+
+ intel_output->crtc_mask = (1 << 0) | (1 << 1);
connector->interlace_allowed = true;
connector->doublescan_allowed = 0;
@@ -1385,6 +1419,8 @@ intel_dp_init(struct drm_device *dev, int output_reg)
DRM_MODE_TYPE_PREFERRED;
}
}
+
+ intel_edp_detect_bpp(dev_priv, dp_priv);
}
/* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written
@@ -175,7 +175,7 @@ extern void intel_dp_init(struct drm_device *dev, int dp_reg);
void
intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode);
-extern void intel_edp_link_config (struct intel_output *, int *, int *);
+extern void intel_edp_link_config (struct intel_output *, int *, int *, int *);
extern int intel_panel_fitter_pipe (struct drm_device *dev);