summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/i915
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/i915')
-rw-r--r--drivers/gpu/drm/i915/intel_ddi.c7
-rw-r--r--drivers/gpu/drm/i915/intel_display.c224
-rw-r--r--drivers/gpu/drm/i915/intel_hdmi.c13
-rw-r--r--drivers/gpu/drm/i915/intel_lvds.c12
4 files changed, 100 insertions, 156 deletions
diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index 3d09df0d4b9d..6c6b0124f17d 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -945,9 +945,7 @@ void intel_ddi_set_pipe_settings(struct drm_crtc *crtc)
temp |= TRANS_MSA_12_BPC;
break;
default:
- temp |= TRANS_MSA_8_BPC;
- WARN(1, "%d bpp unsupported by DDI function\n",
- intel_crtc->config.pipe_bpp);
+ BUG();
}
I915_WRITE(TRANS_MSA_MISC(cpu_transcoder), temp);
}
@@ -983,8 +981,7 @@ void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc)
temp |= TRANS_DDI_BPC_12;
break;
default:
- WARN(1, "%d bpp unsupported by transcoder DDI function\n",
- intel_crtc->config.pipe_bpp);
+ BUG();
}
if (crtc->mode.flags & DRM_MODE_FLAG_PVSYNC)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 4cc46ef9ca9f..14397726d3ac 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -4076,142 +4076,6 @@ static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv)
&& !(dev_priv->quirks & QUIRK_LVDS_SSC_DISABLE);
}
-/**
- * intel_choose_pipe_bpp_dither - figure out what color depth the pipe should send
- * @crtc: CRTC structure
- * @mode: requested mode
- *
- * A pipe may be connected to one or more outputs. Based on the depth of the
- * attached framebuffer, choose a good color depth to use on the pipe.
- *
- * If possible, match the pipe depth to the fb depth. In some cases, this
- * isn't ideal, because the connected output supports a lesser or restricted
- * set of depths. Resolve that here:
- * LVDS typically supports only 6bpc, so clamp down in that case
- * HDMI supports only 8bpc or 12bpc, so clamp to 8bpc with dither for 10bpc
- * Displays may support a restricted set as well, check EDID and clamp as
- * appropriate.
- * DP may want to dither down to 6bpc to fit larger modes
- *
- * RETURNS:
- * Dithering requirement (i.e. false if display bpc and pipe bpc match,
- * true if they don't match).
- */
-static bool intel_choose_pipe_bpp_dither(struct drm_crtc *crtc,
- struct drm_framebuffer *fb,
- unsigned int *pipe_bpp,
- struct drm_display_mode *mode)
-{
- struct drm_device *dev = crtc->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_connector *connector;
- struct intel_encoder *intel_encoder;
- unsigned int display_bpc = UINT_MAX, bpc;
-
- /* Walk the encoders & connectors on this crtc, get min bpc */
- for_each_encoder_on_crtc(dev, crtc, intel_encoder) {
-
- if (intel_encoder->type == INTEL_OUTPUT_LVDS) {
- unsigned int lvds_bpc;
-
- if ((I915_READ(PCH_LVDS) & LVDS_A3_POWER_MASK) ==
- LVDS_A3_POWER_UP)
- lvds_bpc = 8;
- else
- lvds_bpc = 6;
-
- if (lvds_bpc < display_bpc) {
- DRM_DEBUG_KMS("clamping display bpc (was %d) to LVDS (%d)\n", display_bpc, lvds_bpc);
- display_bpc = lvds_bpc;
- }
- continue;
- }
-
- /* Not one of the known troublemakers, check the EDID */
- list_for_each_entry(connector, &dev->mode_config.connector_list,
- head) {
- if (connector->encoder != &intel_encoder->base)
- continue;
-
- /* Don't use an invalid EDID bpc value */
- if (connector->display_info.bpc &&
- connector->display_info.bpc < display_bpc) {
- DRM_DEBUG_KMS("clamping display bpc (was %d) to EDID reported max of %d\n", display_bpc, connector->display_info.bpc);
- display_bpc = connector->display_info.bpc;
- }
- }
-
- if (intel_encoder->type == INTEL_OUTPUT_EDP) {
- /* Use VBT settings if we have an eDP panel */
- unsigned int edp_bpc = dev_priv->edp.bpp / 3;
-
- if (edp_bpc && edp_bpc < display_bpc) {
- DRM_DEBUG_KMS("clamping display bpc (was %d) to eDP (%d)\n", display_bpc, edp_bpc);
- display_bpc = edp_bpc;
- }
- continue;
- }
-
- /*
- * HDMI is either 12 or 8, so if the display lets 10bpc sneak
- * through, clamp it down. (Note: >12bpc will be caught below.)
- */
- if (intel_encoder->type == INTEL_OUTPUT_HDMI) {
- if (display_bpc > 8 && display_bpc < 12) {
- DRM_DEBUG_KMS("forcing bpc to 12 for HDMI\n");
- display_bpc = 12;
- } else {
- DRM_DEBUG_KMS("forcing bpc to 8 for HDMI\n");
- display_bpc = 8;
- }
- }
- }
-
- if (mode->private_flags & INTEL_MODE_DP_FORCE_6BPC) {
- DRM_DEBUG_KMS("Dithering DP to 6bpc\n");
- display_bpc = 6;
- }
-
- /*
- * We could just drive the pipe at the highest bpc all the time and
- * enable dithering as needed, but that costs bandwidth. So choose
- * the minimum value that expresses the full color range of the fb but
- * also stays within the max display bpc discovered above.
- */
-
- switch (fb->depth) {
- case 8:
- bpc = 8; /* since we go through a colormap */
- break;
- case 15:
- case 16:
- bpc = 6; /* min is 18bpp */
- break;
- case 24:
- bpc = 8;
- break;
- case 30:
- bpc = 10;
- break;
- case 48:
- bpc = 12;
- break;
- default:
- DRM_DEBUG("unsupported depth, assuming 24 bits\n");
- bpc = min((unsigned int)8, display_bpc);
- break;
- }
-
- display_bpc = min(display_bpc, bpc);
-
- DRM_DEBUG_KMS("setting pipe bpc to %d (max display bpc %d)\n",
- bpc, display_bpc);
-
- *pipe_bpp = display_bpc * 3;
-
- return display_bpc != bpc;
-}
-
static int vlv_get_refclk(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
@@ -4665,10 +4529,6 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
const intel_limit_t *limit;
int ret;
- /* temporary hack */
- intel_crtc->config.dither =
- adjusted_mode->private_flags & INTEL_MODE_DP_FORCE_6BPC;
-
for_each_encoder_on_crtc(dev, crtc, encoder) {
switch (encoder->type) {
case INTEL_OUTPUT_LVDS:
@@ -5673,10 +5533,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
intel_crtc_update_cursor(crtc, true);
/* determine panel color depth */
- dither = intel_choose_pipe_bpp_dither(crtc, fb,
- &intel_crtc->config.pipe_bpp,
- adjusted_mode);
- intel_crtc->config.dither = dither;
+ dither = intel_crtc->config.dither;
if (is_lvds && dev_priv->lvds_dither)
dither = true;
@@ -5841,10 +5698,7 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc,
intel_crtc_update_cursor(crtc, true);
/* determine panel color depth */
- dither = intel_choose_pipe_bpp_dither(crtc, fb,
- &intel_crtc->config.pipe_bpp,
- adjusted_mode);
- intel_crtc->config.dither = dither;
+ dither = intel_crtc->config.dither;
DRM_DEBUG_KMS("Mode for pipe %d:\n", pipe);
drm_mode_debug_printmodeline(mode);
@@ -7525,14 +7379,72 @@ static void intel_modeset_commit_output_state(struct drm_device *dev)
}
}
+static int
+pipe_config_set_bpp(struct drm_crtc *crtc,
+ struct drm_framebuffer *fb,
+ struct intel_crtc_config *pipe_config)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_connector *connector;
+ int bpp;
+
+ switch (fb->depth) {
+ case 8:
+ bpp = 8*3; /* since we go through a colormap */
+ break;
+ case 15:
+ case 16:
+ bpp = 6*3; /* min is 18bpp */
+ break;
+ case 24:
+ bpp = 8*3;
+ break;
+ case 30:
+ bpp = 10*3;
+ break;
+ case 48:
+ bpp = 12*3;
+ break;
+ default:
+ DRM_DEBUG_KMS("unsupported depth\n");
+ return -EINVAL;
+ }
+
+ if (fb->depth > 24 && !HAS_PCH_SPLIT(dev)) {
+ DRM_DEBUG_KMS("high depth not supported on gmch platforms\n");
+ return -EINVAL;
+ }
+
+ pipe_config->pipe_bpp = bpp;
+
+ /* Clamp display bpp to EDID value */
+ list_for_each_entry(connector, &dev->mode_config.connector_list,
+ head) {
+ if (connector->encoder && connector->encoder->crtc != crtc)
+ continue;
+
+ /* Don't use an invalid EDID bpc value */
+ if (connector->display_info.bpc &&
+ connector->display_info.bpc * 3 < bpp) {
+ DRM_DEBUG_KMS("clamping display bpp (was %d) to EDID reported max of %d\n",
+ bpp, connector->display_info.bpc*3);
+ pipe_config->pipe_bpp = connector->display_info.bpc*3;
+ }
+ }
+
+ return bpp;
+}
+
static struct intel_crtc_config *
intel_modeset_pipe_config(struct drm_crtc *crtc,
+ struct drm_framebuffer *fb,
struct drm_display_mode *mode)
{
struct drm_device *dev = crtc->dev;
struct drm_encoder_helper_funcs *encoder_funcs;
struct intel_encoder *encoder;
struct intel_crtc_config *pipe_config;
+ int plane_bpp;
pipe_config = kzalloc(sizeof(*pipe_config), GFP_KERNEL);
if (!pipe_config)
@@ -7541,6 +7453,10 @@ intel_modeset_pipe_config(struct drm_crtc *crtc,
drm_mode_copy(&pipe_config->adjusted_mode, mode);
drm_mode_copy(&pipe_config->requested_mode, mode);
+ plane_bpp = pipe_config_set_bpp(crtc, fb, pipe_config);
+ if (plane_bpp < 0)
+ goto fail;
+
/* Pass our mode to the connectors and the CRTC to give them a chance to
* adjust it according to limitations or connector properties, and also
* a chance to reject the mode entirely.
@@ -7569,12 +7485,20 @@ intel_modeset_pipe_config(struct drm_crtc *crtc,
}
}
+ /* temporary hack until the DP code doesn't use the 6BPC flag any more */
+ if (pipe_config->adjusted_mode.private_flags & INTEL_MODE_DP_FORCE_6BPC)
+ pipe_config->pipe_bpp = 6*8;
+
if (!(intel_crtc_compute_config(crtc, pipe_config))) {
DRM_DEBUG_KMS("CRTC fixup failed\n");
goto fail;
}
DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id);
+ pipe_config->dither = pipe_config->pipe_bpp != plane_bpp;
+ DRM_DEBUG_KMS("plane bpp: %i, pipe bpp: %i, dithering: %i\n",
+ plane_bpp, pipe_config->pipe_bpp, pipe_config->dither);
+
return pipe_config;
fail:
kfree(pipe_config);
@@ -7866,7 +7790,7 @@ int intel_set_mode(struct drm_crtc *crtc,
* pieces of code that are not yet converted to deal with mutliple crtcs
* changing their mode at the same time. */
if (modeset_pipes) {
- pipe_config = intel_modeset_pipe_config(crtc, mode);
+ pipe_config = intel_modeset_pipe_config(crtc, fb, mode);
if (IS_ERR(pipe_config)) {
ret = PTR_ERR(pipe_config);
pipe_config = NULL;
@@ -8305,8 +8229,6 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
dev_priv->plane_to_crtc_mapping[intel_crtc->plane] = &intel_crtc->base;
dev_priv->pipe_to_crtc_mapping[intel_crtc->pipe] = &intel_crtc->base;
- intel_crtc->config.pipe_bpp = 24; /* default for pre-Ironlake */
-
drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs);
}
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index 0731ba660aac..b206a0db7716 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -791,6 +791,19 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
if (HAS_PCH_SPLIT(dev) && !HAS_DDI(dev))
pipe_config->has_pch_encoder = true;
+ /*
+ * HDMI is either 12 or 8, so if the display lets 10bpc sneak
+ * through, clamp it down. Note that g4x/vlv don't support 12bpc hdmi
+ * outputs.
+ */
+ if (pipe_config->pipe_bpp > 8*3 && HAS_PCH_SPLIT(dev)) {
+ DRM_DEBUG_KMS("forcing bpc to 12 for HDMI\n");
+ pipe_config->pipe_bpp = 12*3;
+ } else {
+ DRM_DEBUG_KMS("forcing bpc to 8 for HDMI\n");
+ pipe_config->pipe_bpp = 8*3;
+ }
+
return true;
}
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index 9d6ed91b443d..7b6d07b6a02d 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -310,6 +310,7 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder,
struct drm_display_mode *mode = &pipe_config->requested_mode;
struct intel_crtc *intel_crtc = lvds_encoder->base.new_crtc;
u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0;
+ unsigned int lvds_bpp;
int pipe;
/* Should never happen!! */
@@ -321,6 +322,17 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder,
if (intel_encoder_check_is_cloned(&lvds_encoder->base))
return false;
+ if ((I915_READ(lvds_encoder->reg) & LVDS_A3_POWER_MASK) ==
+ LVDS_A3_POWER_UP)
+ lvds_bpp = 8*3;
+ else
+ lvds_bpp = 6*3;
+
+ if (lvds_bpp != pipe_config->pipe_bpp) {
+ DRM_DEBUG_KMS("forcing display bpp (was %d) to LVDS (%d)\n",
+ pipe_config->pipe_bpp, lvds_bpp);
+ pipe_config->pipe_bpp = lvds_bpp;
+ }
/*
* We have timings from the BIOS for the panel, put them in
* to the adjusted mode. The CRTC will be set up for this mode,