[Intel-gfx] [PATCH] drm/i915: Enable panel-fitter for any mode != adjusted mode
Chris Wilson
chris at chris-wilson.co.uk
Thu Dec 16 22:10:07 CET 2010
Continuing the Libretto W100 saga, in order to use a non-native mode on
the SDVO panel, I need to engage the panel fitter for that pipe. So try
to do so in a generic fashion such that we use the panel fitter to fixup
any input (adjusted) mode that is not equal to the output mode.
Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
---
drivers/gpu/drm/i915/i915_drv.h | 2 -
drivers/gpu/drm/i915/intel_display.c | 69 +++++++++++++++++++++++++++++++--
drivers/gpu/drm/i915/intel_dp.c | 2 -
drivers/gpu/drm/i915/intel_drv.h | 20 ++++++++--
drivers/gpu/drm/i915/intel_lvds.c | 6 +--
drivers/gpu/drm/i915/intel_panel.c | 61 ------------------------------
6 files changed, 82 insertions(+), 78 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 30780f2..80a243e 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -644,8 +644,6 @@ typedef struct drm_i915_private {
struct sdvo_device_mapping sdvo_mappings[2];
/* indicate whether the LVDS_BORDER should be enabled or not */
unsigned int lvds_border_bits;
- /* Panel fitter placement and size for Ironlake+ */
- u32 pch_pf_pos, pch_pf_size;
struct drm_crtc *plane_to_crtc_mapping[2];
struct drm_crtc *pipe_to_crtc_mapping[2];
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 8645a97..2b2c010 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -2024,6 +2024,63 @@ static void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
atomic_read(&obj->pending_flip) == 0);
}
+static bool pch_pf_enable(struct intel_crtc *crtc,
+ int *x, int *y, int *width, int *height)
+{
+ struct drm_device *dev = crtc->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int htotal = I915_READ(HTOTAL(crtc->pipe)) & 0xffff;
+ int vtotal = I915_READ(VTOTAL(crtc->pipe)) & 0xffff;
+ int src = I915_READ(PIPESRC(crtc->pipe));
+ int src_width, src_height;
+ int dst_width, dst_height;
+
+ /* Native modes don't need fitting */
+ if ((htotal << 16 | vtotal) == src)
+ return false;
+
+ src_width = (src >> 16) + 1;
+ src_height = (src & 0xffff) + 1;
+ dst_width = (htotal & 0xffff) + 1;
+ dst_height = (vtotal & 0xffff) + 1;
+
+ switch (crtc->fitting_mode) {
+ case DRM_MODE_SCALE_CENTER:
+ *width = src_width;
+ *height = src_height;
+ *x = (dst_width - src_width + 1)/2;
+ *y = (dst_height - src_height + 1)/2;
+ break;
+
+ default:
+ case DRM_MODE_SCALE_ASPECT:
+ /* Scale but preserve the aspect ratio */
+ {
+ u32 scaled_width = dst_width * src_height;
+ u32 scaled_height = src_width * dst_height;
+ if (scaled_width > scaled_height) { /* pillar */
+ *width = scaled_height / src_height;
+ *x = (dst_width - *width + 1) / 2;
+ *y = 0;
+ *height = dst_height;
+ } else if (scaled_width < scaled_height) { /* letter */
+ *height = scaled_width / src_width;
+ *y = (dst_height - *height + 1) / 2;
+ *x = 0;
+ *width = dst_width;
+ } else {
+ case DRM_MODE_SCALE_FULLSCREEN:
+ *x = *y = 0;
+ *width = dst_width;
+ *height = dst_height;
+ }
+ }
+ break;
+ }
+
+ return true;
+}
+
static void ironlake_crtc_enable(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
@@ -2031,6 +2088,7 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
int pipe = intel_crtc->pipe;
int plane = intel_crtc->plane;
+ int x, y, width, height;
u32 reg, temp;
if (intel_crtc->active)
@@ -2047,9 +2105,7 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
ironlake_fdi_enable(crtc);
- /* Enable panel fitting for LVDS */
- if (dev_priv->pch_pf_size &&
- (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) || HAS_eDP)) {
+ if (pch_pf_enable(intel_crtc, &x, &y, &width, &height)) {
/* Force use of hard-coded filter coefficients
* as some pre-programmed values are broken,
* e.g. x201.
@@ -2057,9 +2113,9 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
I915_WRITE(pipe ? PFB_CTL_1 : PFA_CTL_1,
PF_ENABLE | PF_FILTER_MED_3x3);
I915_WRITE(pipe ? PFB_WIN_POS : PFA_WIN_POS,
- dev_priv->pch_pf_pos);
+ x << 16 | y);
I915_WRITE(pipe ? PFB_WIN_SZ : PFA_WIN_SZ,
- dev_priv->pch_pf_size);
+ width << 16 | height);
}
/* Enable CPU pipe */
@@ -2631,6 +2687,9 @@ static bool intel_crtc_mode_fixup(struct drm_crtc *crtc,
if (adjusted_mode->crtc_htotal == 0)
drm_mode_set_crtcinfo(adjusted_mode, 0);
+ to_intel_crtc(crtc)->fitting_mode =
+ intel_mode_get_panel_fitting(adjusted_mode);
+
return true;
}
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 1dc6040..f452714 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -598,8 +598,6 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
if (is_edp(intel_dp) && dev_priv->panel_fixed_mode) {
intel_fixed_panel_mode(dev_priv->panel_fixed_mode, adjusted_mode);
- intel_pch_panel_fitting(dev, DRM_MODE_SCALE_FULLSCREEN,
- mode, adjusted_mode);
/*
* the mode->clock is used to calculate the Data&Link M/N
* of the pipe. For the eDP the fixed clock should be used.
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index acdea65..8b29fce 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -110,6 +110,8 @@
/* drm_display_mode->private_flags */
#define INTEL_MODE_PIXEL_MULTIPLIER_SHIFT (0x0)
#define INTEL_MODE_PIXEL_MULTIPLIER_MASK (0xf << INTEL_MODE_PIXEL_MULTIPLIER_SHIFT)
+#define INTEL_MODE_PANEL_FITTING_SHIFT (0x4)
+#define INTEL_MODE_PANEL_FITTING_MASK (0xf << INTEL_MODE_PANEL_FITTING_SHIFT)
static inline void
intel_mode_set_pixel_multiplier(struct drm_display_mode *mode,
@@ -125,6 +127,19 @@ intel_mode_get_pixel_multiplier(const struct drm_display_mode *mode)
return (mode->private_flags & INTEL_MODE_PIXEL_MULTIPLIER_MASK) >> INTEL_MODE_PIXEL_MULTIPLIER_SHIFT;
}
+static inline void
+intel_mode_set_panel_fitting(struct drm_display_mode *mode,
+ int pf_mode)
+{
+ mode->private_flags |= pf_mode << INTEL_MODE_PANEL_FITTING_SHIFT;
+}
+
+static inline int
+intel_mode_get_panel_fitting(const struct drm_display_mode *mode)
+{
+ return (mode->private_flags & INTEL_MODE_PANEL_FITTING_MASK)>> INTEL_MODE_PANEL_FITTING_SHIFT;
+}
+
struct intel_framebuffer {
struct drm_framebuffer base;
struct drm_i915_gem_object *obj;
@@ -158,6 +173,7 @@ struct intel_crtc {
enum plane plane;
u8 lut_r[256], lut_g[256], lut_b[256];
int dpms_mode;
+ int fitting_mode;
bool active; /* is the crtc on? independent of the dpms mode */
bool busy; /* is scanout buffer being updated frequently? */
struct timer_list idle_timer;
@@ -250,10 +266,6 @@ extern bool intel_encoder_is_pch_edp(struct drm_encoder *encoder);
/* intel_panel.c */
extern void intel_fixed_panel_mode(struct drm_display_mode *fixed_mode,
struct drm_display_mode *adjusted_mode);
-extern void intel_pch_panel_fitting(struct drm_device *dev,
- int fitting_mode,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode);
extern u32 intel_panel_get_max_backlight(struct drm_device *dev);
extern u32 intel_panel_get_backlight(struct drm_device *dev);
extern void intel_panel_set_backlight(struct drm_device *dev, u32 level);
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index aa23070..55c9ac3 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -255,12 +255,10 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
* of the original mode.
*/
intel_fixed_panel_mode(intel_lvds->fixed_mode, adjusted_mode);
+ intel_mode_set_panel_fitting(adjusted_mode, intel_lvds->fitting_mode);
- if (HAS_PCH_SPLIT(dev)) {
- intel_pch_panel_fitting(dev, intel_lvds->fitting_mode,
- mode, adjusted_mode);
+ if (HAS_PCH_SPLIT(dev))
return true;
- }
/* Make sure pre-965s set dither correctly */
if (INTEL_INFO(dev)->gen < 4) {
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c
index 7350ec2..4dda915 100644
--- a/drivers/gpu/drm/i915/intel_panel.c
+++ b/drivers/gpu/drm/i915/intel_panel.c
@@ -51,67 +51,6 @@ intel_fixed_panel_mode(struct drm_display_mode *fixed_mode,
drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V);
}
-/* adjusted_mode has been preset to be the panel's fixed mode */
-void
-intel_pch_panel_fitting(struct drm_device *dev,
- int fitting_mode,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- int x, y, width, height;
-
- x = y = width = height = 0;
-
- /* Native modes don't need fitting */
- if (adjusted_mode->hdisplay == mode->hdisplay &&
- adjusted_mode->vdisplay == mode->vdisplay)
- goto done;
-
- switch (fitting_mode) {
- case DRM_MODE_SCALE_CENTER:
- width = mode->hdisplay;
- height = mode->vdisplay;
- x = (adjusted_mode->hdisplay - width + 1)/2;
- y = (adjusted_mode->vdisplay - height + 1)/2;
- break;
-
- case DRM_MODE_SCALE_ASPECT:
- /* Scale but preserve the aspect ratio */
- {
- u32 scaled_width = adjusted_mode->hdisplay * mode->vdisplay;
- u32 scaled_height = mode->hdisplay * adjusted_mode->vdisplay;
- if (scaled_width > scaled_height) { /* pillar */
- width = scaled_height / mode->vdisplay;
- x = (adjusted_mode->hdisplay - width + 1) / 2;
- y = 0;
- height = adjusted_mode->vdisplay;
- } else if (scaled_width < scaled_height) { /* letter */
- height = scaled_width / mode->hdisplay;
- y = (adjusted_mode->vdisplay - height + 1) / 2;
- x = 0;
- width = adjusted_mode->hdisplay;
- } else {
- x = y = 0;
- width = adjusted_mode->hdisplay;
- height = adjusted_mode->vdisplay;
- }
- }
- break;
-
- default:
- case DRM_MODE_SCALE_FULLSCREEN:
- x = y = 0;
- width = adjusted_mode->hdisplay;
- height = adjusted_mode->vdisplay;
- break;
- }
-
-done:
- dev_priv->pch_pf_pos = (x << 16) | y;
- dev_priv->pch_pf_size = (width << 16) | height;
-}
-
static int is_backlight_combination_mode(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
--
1.7.2.3
More information about the Intel-gfx
mailing list