Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright © 2006-2010 Intel Corporation
0003  * Copyright (c) 2006 Dave Airlie <airlied@linux.ie>
0004  *
0005  * Permission is hereby granted, free of charge, to any person obtaining a
0006  * copy of this software and associated documentation files (the "Software"),
0007  * to deal in the Software without restriction, including without limitation
0008  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0009  * and/or sell copies of the Software, and to permit persons to whom the
0010  * Software is furnished to do so, subject to the following conditions:
0011  *
0012  * The above copyright notice and this permission notice (including the next
0013  * paragraph) shall be included in all copies or substantial portions of the
0014  * Software.
0015  *
0016  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0017  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0018  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0019  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
0020  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
0021  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
0022  * DEALINGS IN THE SOFTWARE.
0023  *
0024  * Authors:
0025  *  Eric Anholt <eric@anholt.net>
0026  *      Dave Airlie <airlied@linux.ie>
0027  *      Jesse Barnes <jesse.barnes@intel.com>
0028  *      Chris Wilson <chris@chris-wilson.co.uk>
0029  */
0030 
0031 #include <linux/kernel.h>
0032 #include <linux/pwm.h>
0033 
0034 #include "intel_backlight.h"
0035 #include "intel_connector.h"
0036 #include "intel_de.h"
0037 #include "intel_display_types.h"
0038 #include "intel_drrs.h"
0039 #include "intel_panel.h"
0040 
0041 bool intel_panel_use_ssc(struct drm_i915_private *i915)
0042 {
0043     if (i915->params.panel_use_ssc >= 0)
0044         return i915->params.panel_use_ssc != 0;
0045     return i915->vbt.lvds_use_ssc
0046         && !(i915->quirks & QUIRK_LVDS_SSC_DISABLE);
0047 }
0048 
0049 const struct drm_display_mode *
0050 intel_panel_preferred_fixed_mode(struct intel_connector *connector)
0051 {
0052     return list_first_entry_or_null(&connector->panel.fixed_modes,
0053                     struct drm_display_mode, head);
0054 }
0055 
0056 const struct drm_display_mode *
0057 intel_panel_fixed_mode(struct intel_connector *connector,
0058                const struct drm_display_mode *mode)
0059 {
0060     const struct drm_display_mode *fixed_mode, *best_mode = NULL;
0061     int vrefresh = drm_mode_vrefresh(mode);
0062 
0063     /* pick the fixed_mode that is closest in terms of vrefresh */
0064     list_for_each_entry(fixed_mode, &connector->panel.fixed_modes, head) {
0065         if (!best_mode ||
0066             abs(drm_mode_vrefresh(fixed_mode) - vrefresh) <
0067             abs(drm_mode_vrefresh(best_mode) - vrefresh))
0068             best_mode = fixed_mode;
0069     }
0070 
0071     return best_mode;
0072 }
0073 
0074 static bool is_alt_drrs_mode(const struct drm_display_mode *mode,
0075                  const struct drm_display_mode *preferred_mode)
0076 {
0077     return drm_mode_match(mode, preferred_mode,
0078                   DRM_MODE_MATCH_TIMINGS |
0079                   DRM_MODE_MATCH_FLAGS |
0080                   DRM_MODE_MATCH_3D_FLAGS) &&
0081         mode->clock != preferred_mode->clock;
0082 }
0083 
0084 static bool is_alt_vrr_mode(const struct drm_display_mode *mode,
0085                 const struct drm_display_mode *preferred_mode)
0086 {
0087     return drm_mode_match(mode, preferred_mode,
0088                   DRM_MODE_MATCH_FLAGS |
0089                   DRM_MODE_MATCH_3D_FLAGS) &&
0090         mode->hdisplay == preferred_mode->hdisplay &&
0091         mode->vdisplay == preferred_mode->vdisplay &&
0092         mode->clock != preferred_mode->clock;
0093 }
0094 
0095 const struct drm_display_mode *
0096 intel_panel_downclock_mode(struct intel_connector *connector,
0097                const struct drm_display_mode *adjusted_mode)
0098 {
0099     const struct drm_display_mode *fixed_mode, *best_mode = NULL;
0100     int min_vrefresh = connector->panel.vbt.seamless_drrs_min_refresh_rate;
0101     int max_vrefresh = drm_mode_vrefresh(adjusted_mode);
0102 
0103     /* pick the fixed_mode with the lowest refresh rate */
0104     list_for_each_entry(fixed_mode, &connector->panel.fixed_modes, head) {
0105         int vrefresh = drm_mode_vrefresh(fixed_mode);
0106 
0107         if (is_alt_drrs_mode(fixed_mode, adjusted_mode) &&
0108             vrefresh >= min_vrefresh && vrefresh < max_vrefresh) {
0109             max_vrefresh = vrefresh;
0110             best_mode = fixed_mode;
0111         }
0112     }
0113 
0114     return best_mode;
0115 }
0116 
0117 int intel_panel_get_modes(struct intel_connector *connector)
0118 {
0119     const struct drm_display_mode *fixed_mode;
0120     int num_modes = 0;
0121 
0122     list_for_each_entry(fixed_mode, &connector->panel.fixed_modes, head) {
0123         struct drm_display_mode *mode;
0124 
0125         mode = drm_mode_duplicate(connector->base.dev, fixed_mode);
0126         if (mode) {
0127             drm_mode_probed_add(&connector->base, mode);
0128             num_modes++;
0129         }
0130     }
0131 
0132     return num_modes;
0133 }
0134 
0135 enum drrs_type intel_panel_drrs_type(struct intel_connector *connector)
0136 {
0137     if (list_empty(&connector->panel.fixed_modes) ||
0138         list_is_singular(&connector->panel.fixed_modes))
0139         return DRRS_TYPE_NONE;
0140 
0141     return connector->panel.vbt.drrs_type;
0142 }
0143 
0144 int intel_panel_compute_config(struct intel_connector *connector,
0145                    struct drm_display_mode *adjusted_mode)
0146 {
0147     const struct drm_display_mode *fixed_mode =
0148         intel_panel_fixed_mode(connector, adjusted_mode);
0149 
0150     if (!fixed_mode)
0151         return 0;
0152 
0153     /*
0154      * We don't want to lie too much to the user about the refresh
0155      * rate they're going to get. But we have to allow a bit of latitude
0156      * for Xorg since it likes to automagically cook up modes with slightly
0157      * off refresh rates.
0158      */
0159     if (abs(drm_mode_vrefresh(adjusted_mode) - drm_mode_vrefresh(fixed_mode)) > 1) {
0160         drm_dbg_kms(connector->base.dev,
0161                 "[CONNECTOR:%d:%s] Requested mode vrefresh (%d Hz) does not match fixed mode vrefresh (%d Hz)\n",
0162                 connector->base.base.id, connector->base.name,
0163                 drm_mode_vrefresh(adjusted_mode), drm_mode_vrefresh(fixed_mode));
0164 
0165         return -EINVAL;
0166     }
0167 
0168     drm_mode_copy(adjusted_mode, fixed_mode);
0169 
0170     drm_mode_set_crtcinfo(adjusted_mode, 0);
0171 
0172     return 0;
0173 }
0174 
0175 static bool is_alt_fixed_mode(const struct drm_display_mode *mode,
0176                   const struct drm_display_mode *preferred_mode,
0177                   bool has_vrr)
0178 {
0179     /* is_alt_drrs_mode() is a subset of is_alt_vrr_mode() */
0180     if (has_vrr)
0181         return is_alt_vrr_mode(mode, preferred_mode);
0182     else
0183         return is_alt_drrs_mode(mode, preferred_mode);
0184 }
0185 
0186 static void intel_panel_add_edid_alt_fixed_modes(struct intel_connector *connector,
0187                          bool has_vrr)
0188 {
0189     struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
0190     const struct drm_display_mode *preferred_mode =
0191         intel_panel_preferred_fixed_mode(connector);
0192     struct drm_display_mode *mode, *next;
0193 
0194     list_for_each_entry_safe(mode, next, &connector->base.probed_modes, head) {
0195         if (!is_alt_fixed_mode(mode, preferred_mode, has_vrr))
0196             continue;
0197 
0198         drm_dbg_kms(&dev_priv->drm,
0199                 "[CONNECTOR:%d:%s] using alternate EDID fixed mode: " DRM_MODE_FMT "\n",
0200                 connector->base.base.id, connector->base.name,
0201                 DRM_MODE_ARG(mode));
0202 
0203         list_move_tail(&mode->head, &connector->panel.fixed_modes);
0204     }
0205 }
0206 
0207 static void intel_panel_add_edid_preferred_mode(struct intel_connector *connector)
0208 {
0209     struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
0210     struct drm_display_mode *scan, *fixed_mode = NULL;
0211 
0212     if (list_empty(&connector->base.probed_modes))
0213         return;
0214 
0215     /* make sure the preferred mode is first */
0216     list_for_each_entry(scan, &connector->base.probed_modes, head) {
0217         if (scan->type & DRM_MODE_TYPE_PREFERRED) {
0218             fixed_mode = scan;
0219             break;
0220         }
0221     }
0222 
0223     if (!fixed_mode)
0224         fixed_mode = list_first_entry(&connector->base.probed_modes,
0225                           typeof(*fixed_mode), head);
0226 
0227     drm_dbg_kms(&dev_priv->drm,
0228             "[CONNECTOR:%d:%s] using %s EDID fixed mode: " DRM_MODE_FMT "\n",
0229             connector->base.base.id, connector->base.name,
0230             fixed_mode->type & DRM_MODE_TYPE_PREFERRED ? "preferred" : "first",
0231             DRM_MODE_ARG(fixed_mode));
0232 
0233     fixed_mode->type |= DRM_MODE_TYPE_PREFERRED;
0234 
0235     list_move_tail(&fixed_mode->head, &connector->panel.fixed_modes);
0236 }
0237 
0238 static void intel_panel_destroy_probed_modes(struct intel_connector *connector)
0239 {
0240     struct drm_i915_private *i915 = to_i915(connector->base.dev);
0241     struct drm_display_mode *mode, *next;
0242 
0243     list_for_each_entry_safe(mode, next, &connector->base.probed_modes, head) {
0244         drm_dbg_kms(&i915->drm,
0245                 "[CONNECTOR:%d:%s] not using EDID mode: " DRM_MODE_FMT "\n",
0246                 connector->base.base.id, connector->base.name,
0247                 DRM_MODE_ARG(mode));
0248         list_del(&mode->head);
0249         drm_mode_destroy(&i915->drm, mode);
0250     }
0251 }
0252 
0253 void intel_panel_add_edid_fixed_modes(struct intel_connector *connector,
0254                       bool has_drrs, bool has_vrr)
0255 {
0256     intel_panel_add_edid_preferred_mode(connector);
0257     if (intel_panel_preferred_fixed_mode(connector) && (has_drrs || has_vrr))
0258         intel_panel_add_edid_alt_fixed_modes(connector, has_vrr);
0259     intel_panel_destroy_probed_modes(connector);
0260 }
0261 
0262 static void intel_panel_add_fixed_mode(struct intel_connector *connector,
0263                        struct drm_display_mode *fixed_mode,
0264                        const char *type)
0265 {
0266     struct drm_i915_private *i915 = to_i915(connector->base.dev);
0267     struct drm_display_info *info = &connector->base.display_info;
0268 
0269     if (!fixed_mode)
0270         return;
0271 
0272     fixed_mode->type |= DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER;
0273 
0274     info->width_mm = fixed_mode->width_mm;
0275     info->height_mm = fixed_mode->height_mm;
0276 
0277     drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] using %s fixed mode: " DRM_MODE_FMT "\n",
0278             connector->base.base.id, connector->base.name, type,
0279             DRM_MODE_ARG(fixed_mode));
0280 
0281     list_add_tail(&fixed_mode->head, &connector->panel.fixed_modes);
0282 }
0283 
0284 void intel_panel_add_vbt_lfp_fixed_mode(struct intel_connector *connector)
0285 {
0286     struct drm_i915_private *i915 = to_i915(connector->base.dev);
0287     const struct drm_display_mode *mode;
0288 
0289     mode = connector->panel.vbt.lfp_lvds_vbt_mode;
0290     if (!mode)
0291         return;
0292 
0293     intel_panel_add_fixed_mode(connector,
0294                    drm_mode_duplicate(&i915->drm, mode),
0295                    "VBT LFP");
0296 }
0297 
0298 void intel_panel_add_vbt_sdvo_fixed_mode(struct intel_connector *connector)
0299 {
0300     struct drm_i915_private *i915 = to_i915(connector->base.dev);
0301     const struct drm_display_mode *mode;
0302 
0303     mode = connector->panel.vbt.sdvo_lvds_vbt_mode;
0304     if (!mode)
0305         return;
0306 
0307     intel_panel_add_fixed_mode(connector,
0308                    drm_mode_duplicate(&i915->drm, mode),
0309                    "VBT SDVO");
0310 }
0311 
0312 void intel_panel_add_encoder_fixed_mode(struct intel_connector *connector,
0313                     struct intel_encoder *encoder)
0314 {
0315     intel_panel_add_fixed_mode(connector,
0316                    intel_encoder_current_mode(encoder),
0317                    "current (BIOS)");
0318 }
0319 
0320 /* adjusted_mode has been preset to be the panel's fixed mode */
0321 static int pch_panel_fitting(struct intel_crtc_state *crtc_state,
0322                  const struct drm_connector_state *conn_state)
0323 {
0324     const struct drm_display_mode *adjusted_mode =
0325         &crtc_state->hw.adjusted_mode;
0326     int pipe_src_w = drm_rect_width(&crtc_state->pipe_src);
0327     int pipe_src_h = drm_rect_height(&crtc_state->pipe_src);
0328     int x, y, width, height;
0329 
0330     /* Native modes don't need fitting */
0331     if (adjusted_mode->crtc_hdisplay == pipe_src_w &&
0332         adjusted_mode->crtc_vdisplay == pipe_src_h &&
0333         crtc_state->output_format != INTEL_OUTPUT_FORMAT_YCBCR420)
0334         return 0;
0335 
0336     switch (conn_state->scaling_mode) {
0337     case DRM_MODE_SCALE_CENTER:
0338         width = pipe_src_w;
0339         height = pipe_src_h;
0340         x = (adjusted_mode->crtc_hdisplay - width + 1)/2;
0341         y = (adjusted_mode->crtc_vdisplay - height + 1)/2;
0342         break;
0343 
0344     case DRM_MODE_SCALE_ASPECT:
0345         /* Scale but preserve the aspect ratio */
0346         {
0347             u32 scaled_width = adjusted_mode->crtc_hdisplay * pipe_src_h;
0348             u32 scaled_height = pipe_src_w * adjusted_mode->crtc_vdisplay;
0349             if (scaled_width > scaled_height) { /* pillar */
0350                 width = scaled_height / pipe_src_h;
0351                 if (width & 1)
0352                     width++;
0353                 x = (adjusted_mode->crtc_hdisplay - width + 1) / 2;
0354                 y = 0;
0355                 height = adjusted_mode->crtc_vdisplay;
0356             } else if (scaled_width < scaled_height) { /* letter */
0357                 height = scaled_width / pipe_src_w;
0358                 if (height & 1)
0359                     height++;
0360                 y = (adjusted_mode->crtc_vdisplay - height + 1) / 2;
0361                 x = 0;
0362                 width = adjusted_mode->crtc_hdisplay;
0363             } else {
0364                 x = y = 0;
0365                 width = adjusted_mode->crtc_hdisplay;
0366                 height = adjusted_mode->crtc_vdisplay;
0367             }
0368         }
0369         break;
0370 
0371     case DRM_MODE_SCALE_NONE:
0372         WARN_ON(adjusted_mode->crtc_hdisplay != pipe_src_w);
0373         WARN_ON(adjusted_mode->crtc_vdisplay != pipe_src_h);
0374         fallthrough;
0375     case DRM_MODE_SCALE_FULLSCREEN:
0376         x = y = 0;
0377         width = adjusted_mode->crtc_hdisplay;
0378         height = adjusted_mode->crtc_vdisplay;
0379         break;
0380 
0381     default:
0382         MISSING_CASE(conn_state->scaling_mode);
0383         return -EINVAL;
0384     }
0385 
0386     drm_rect_init(&crtc_state->pch_pfit.dst,
0387               x, y, width, height);
0388     crtc_state->pch_pfit.enabled = true;
0389 
0390     return 0;
0391 }
0392 
0393 static void
0394 centre_horizontally(struct drm_display_mode *adjusted_mode,
0395             int width)
0396 {
0397     u32 border, sync_pos, blank_width, sync_width;
0398 
0399     /* keep the hsync and hblank widths constant */
0400     sync_width = adjusted_mode->crtc_hsync_end - adjusted_mode->crtc_hsync_start;
0401     blank_width = adjusted_mode->crtc_hblank_end - adjusted_mode->crtc_hblank_start;
0402     sync_pos = (blank_width - sync_width + 1) / 2;
0403 
0404     border = (adjusted_mode->crtc_hdisplay - width + 1) / 2;
0405     border += border & 1; /* make the border even */
0406 
0407     adjusted_mode->crtc_hdisplay = width;
0408     adjusted_mode->crtc_hblank_start = width + border;
0409     adjusted_mode->crtc_hblank_end = adjusted_mode->crtc_hblank_start + blank_width;
0410 
0411     adjusted_mode->crtc_hsync_start = adjusted_mode->crtc_hblank_start + sync_pos;
0412     adjusted_mode->crtc_hsync_end = adjusted_mode->crtc_hsync_start + sync_width;
0413 }
0414 
0415 static void
0416 centre_vertically(struct drm_display_mode *adjusted_mode,
0417           int height)
0418 {
0419     u32 border, sync_pos, blank_width, sync_width;
0420 
0421     /* keep the vsync and vblank widths constant */
0422     sync_width = adjusted_mode->crtc_vsync_end - adjusted_mode->crtc_vsync_start;
0423     blank_width = adjusted_mode->crtc_vblank_end - adjusted_mode->crtc_vblank_start;
0424     sync_pos = (blank_width - sync_width + 1) / 2;
0425 
0426     border = (adjusted_mode->crtc_vdisplay - height + 1) / 2;
0427 
0428     adjusted_mode->crtc_vdisplay = height;
0429     adjusted_mode->crtc_vblank_start = height + border;
0430     adjusted_mode->crtc_vblank_end = adjusted_mode->crtc_vblank_start + blank_width;
0431 
0432     adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vblank_start + sync_pos;
0433     adjusted_mode->crtc_vsync_end = adjusted_mode->crtc_vsync_start + sync_width;
0434 }
0435 
0436 static u32 panel_fitter_scaling(u32 source, u32 target)
0437 {
0438     /*
0439      * Floating point operation is not supported. So the FACTOR
0440      * is defined, which can avoid the floating point computation
0441      * when calculating the panel ratio.
0442      */
0443 #define ACCURACY 12
0444 #define FACTOR (1 << ACCURACY)
0445     u32 ratio = source * FACTOR / target;
0446     return (FACTOR * ratio + FACTOR/2) / FACTOR;
0447 }
0448 
0449 static void i965_scale_aspect(struct intel_crtc_state *crtc_state,
0450                   u32 *pfit_control)
0451 {
0452     const struct drm_display_mode *adjusted_mode =
0453         &crtc_state->hw.adjusted_mode;
0454     int pipe_src_w = drm_rect_width(&crtc_state->pipe_src);
0455     int pipe_src_h = drm_rect_height(&crtc_state->pipe_src);
0456     u32 scaled_width = adjusted_mode->crtc_hdisplay * pipe_src_h;
0457     u32 scaled_height = pipe_src_w * adjusted_mode->crtc_vdisplay;
0458 
0459     /* 965+ is easy, it does everything in hw */
0460     if (scaled_width > scaled_height)
0461         *pfit_control |= PFIT_ENABLE |
0462             PFIT_SCALING_PILLAR;
0463     else if (scaled_width < scaled_height)
0464         *pfit_control |= PFIT_ENABLE |
0465             PFIT_SCALING_LETTER;
0466     else if (adjusted_mode->crtc_hdisplay != pipe_src_w)
0467         *pfit_control |= PFIT_ENABLE | PFIT_SCALING_AUTO;
0468 }
0469 
0470 static void i9xx_scale_aspect(struct intel_crtc_state *crtc_state,
0471                   u32 *pfit_control, u32 *pfit_pgm_ratios,
0472                   u32 *border)
0473 {
0474     struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode;
0475     int pipe_src_w = drm_rect_width(&crtc_state->pipe_src);
0476     int pipe_src_h = drm_rect_height(&crtc_state->pipe_src);
0477     u32 scaled_width = adjusted_mode->crtc_hdisplay * pipe_src_h;
0478     u32 scaled_height = pipe_src_w * adjusted_mode->crtc_vdisplay;
0479     u32 bits;
0480 
0481     /*
0482      * For earlier chips we have to calculate the scaling
0483      * ratio by hand and program it into the
0484      * PFIT_PGM_RATIO register
0485      */
0486     if (scaled_width > scaled_height) { /* pillar */
0487         centre_horizontally(adjusted_mode,
0488                     scaled_height / pipe_src_h);
0489 
0490         *border = LVDS_BORDER_ENABLE;
0491         if (pipe_src_h != adjusted_mode->crtc_vdisplay) {
0492             bits = panel_fitter_scaling(pipe_src_h,
0493                             adjusted_mode->crtc_vdisplay);
0494 
0495             *pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT |
0496                          bits << PFIT_VERT_SCALE_SHIFT);
0497             *pfit_control |= (PFIT_ENABLE |
0498                       VERT_INTERP_BILINEAR |
0499                       HORIZ_INTERP_BILINEAR);
0500         }
0501     } else if (scaled_width < scaled_height) { /* letter */
0502         centre_vertically(adjusted_mode,
0503                   scaled_width / pipe_src_w);
0504 
0505         *border = LVDS_BORDER_ENABLE;
0506         if (pipe_src_w != adjusted_mode->crtc_hdisplay) {
0507             bits = panel_fitter_scaling(pipe_src_w,
0508                             adjusted_mode->crtc_hdisplay);
0509 
0510             *pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT |
0511                          bits << PFIT_VERT_SCALE_SHIFT);
0512             *pfit_control |= (PFIT_ENABLE |
0513                       VERT_INTERP_BILINEAR |
0514                       HORIZ_INTERP_BILINEAR);
0515         }
0516     } else {
0517         /* Aspects match, Let hw scale both directions */
0518         *pfit_control |= (PFIT_ENABLE |
0519                   VERT_AUTO_SCALE | HORIZ_AUTO_SCALE |
0520                   VERT_INTERP_BILINEAR |
0521                   HORIZ_INTERP_BILINEAR);
0522     }
0523 }
0524 
0525 static int gmch_panel_fitting(struct intel_crtc_state *crtc_state,
0526                   const struct drm_connector_state *conn_state)
0527 {
0528     struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
0529     struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
0530     u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0;
0531     struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode;
0532     int pipe_src_w = drm_rect_width(&crtc_state->pipe_src);
0533     int pipe_src_h = drm_rect_height(&crtc_state->pipe_src);
0534 
0535     /* Native modes don't need fitting */
0536     if (adjusted_mode->crtc_hdisplay == pipe_src_w &&
0537         adjusted_mode->crtc_vdisplay == pipe_src_h)
0538         goto out;
0539 
0540     switch (conn_state->scaling_mode) {
0541     case DRM_MODE_SCALE_CENTER:
0542         /*
0543          * For centered modes, we have to calculate border widths &
0544          * heights and modify the values programmed into the CRTC.
0545          */
0546         centre_horizontally(adjusted_mode, pipe_src_w);
0547         centre_vertically(adjusted_mode, pipe_src_h);
0548         border = LVDS_BORDER_ENABLE;
0549         break;
0550     case DRM_MODE_SCALE_ASPECT:
0551         /* Scale but preserve the aspect ratio */
0552         if (DISPLAY_VER(dev_priv) >= 4)
0553             i965_scale_aspect(crtc_state, &pfit_control);
0554         else
0555             i9xx_scale_aspect(crtc_state, &pfit_control,
0556                       &pfit_pgm_ratios, &border);
0557         break;
0558     case DRM_MODE_SCALE_FULLSCREEN:
0559         /*
0560          * Full scaling, even if it changes the aspect ratio.
0561          * Fortunately this is all done for us in hw.
0562          */
0563         if (pipe_src_h != adjusted_mode->crtc_vdisplay ||
0564             pipe_src_w != adjusted_mode->crtc_hdisplay) {
0565             pfit_control |= PFIT_ENABLE;
0566             if (DISPLAY_VER(dev_priv) >= 4)
0567                 pfit_control |= PFIT_SCALING_AUTO;
0568             else
0569                 pfit_control |= (VERT_AUTO_SCALE |
0570                          VERT_INTERP_BILINEAR |
0571                          HORIZ_AUTO_SCALE |
0572                          HORIZ_INTERP_BILINEAR);
0573         }
0574         break;
0575     default:
0576         MISSING_CASE(conn_state->scaling_mode);
0577         return -EINVAL;
0578     }
0579 
0580     /* 965+ wants fuzzy fitting */
0581     /* FIXME: handle multiple panels by failing gracefully */
0582     if (DISPLAY_VER(dev_priv) >= 4)
0583         pfit_control |= PFIT_PIPE(crtc->pipe) | PFIT_FILTER_FUZZY;
0584 
0585 out:
0586     if ((pfit_control & PFIT_ENABLE) == 0) {
0587         pfit_control = 0;
0588         pfit_pgm_ratios = 0;
0589     }
0590 
0591     /* Make sure pre-965 set dither correctly for 18bpp panels. */
0592     if (DISPLAY_VER(dev_priv) < 4 && crtc_state->pipe_bpp == 18)
0593         pfit_control |= PANEL_8TO6_DITHER_ENABLE;
0594 
0595     crtc_state->gmch_pfit.control = pfit_control;
0596     crtc_state->gmch_pfit.pgm_ratios = pfit_pgm_ratios;
0597     crtc_state->gmch_pfit.lvds_border_bits = border;
0598 
0599     return 0;
0600 }
0601 
0602 int intel_panel_fitting(struct intel_crtc_state *crtc_state,
0603             const struct drm_connector_state *conn_state)
0604 {
0605     struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
0606     struct drm_i915_private *i915 = to_i915(crtc->base.dev);
0607 
0608     if (HAS_GMCH(i915))
0609         return gmch_panel_fitting(crtc_state, conn_state);
0610     else
0611         return pch_panel_fitting(crtc_state, conn_state);
0612 }
0613 
0614 enum drm_connector_status
0615 intel_panel_detect(struct drm_connector *connector, bool force)
0616 {
0617     struct drm_i915_private *i915 = to_i915(connector->dev);
0618 
0619     if (!INTEL_DISPLAY_ENABLED(i915))
0620         return connector_status_disconnected;
0621 
0622     return connector_status_connected;
0623 }
0624 
0625 enum drm_mode_status
0626 intel_panel_mode_valid(struct intel_connector *connector,
0627                const struct drm_display_mode *mode)
0628 {
0629     const struct drm_display_mode *fixed_mode =
0630         intel_panel_fixed_mode(connector, mode);
0631 
0632     if (!fixed_mode)
0633         return MODE_OK;
0634 
0635     if (mode->hdisplay != fixed_mode->hdisplay)
0636         return MODE_PANEL;
0637 
0638     if (mode->vdisplay != fixed_mode->vdisplay)
0639         return MODE_PANEL;
0640 
0641     if (drm_mode_vrefresh(mode) != drm_mode_vrefresh(fixed_mode))
0642         return MODE_PANEL;
0643 
0644     return MODE_OK;
0645 }
0646 
0647 int intel_panel_init(struct intel_connector *connector)
0648 {
0649     struct intel_panel *panel = &connector->panel;
0650 
0651     intel_backlight_init_funcs(panel);
0652 
0653     drm_dbg_kms(connector->base.dev,
0654             "[CONNECTOR:%d:%s] DRRS type: %s\n",
0655             connector->base.base.id, connector->base.name,
0656             intel_drrs_type_str(intel_panel_drrs_type(connector)));
0657 
0658     return 0;
0659 }
0660 
0661 void intel_panel_fini(struct intel_connector *connector)
0662 {
0663     struct intel_panel *panel = &connector->panel;
0664     struct drm_display_mode *fixed_mode, *next;
0665 
0666     intel_backlight_destroy(panel);
0667 
0668     intel_bios_fini_panel(panel);
0669 
0670     list_for_each_entry_safe(fixed_mode, next, &panel->fixed_modes, head) {
0671         list_del(&fixed_mode->head);
0672         drm_mode_destroy(connector->base.dev, fixed_mode);
0673     }
0674 }