cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

intel_panel.c (20189B)


      1/*
      2 * Copyright © 2006-2010 Intel Corporation
      3 * Copyright (c) 2006 Dave Airlie <airlied@linux.ie>
      4 *
      5 * Permission is hereby granted, free of charge, to any person obtaining a
      6 * copy of this software and associated documentation files (the "Software"),
      7 * to deal in the Software without restriction, including without limitation
      8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      9 * and/or sell copies of the Software, and to permit persons to whom the
     10 * Software is furnished to do so, subject to the following conditions:
     11 *
     12 * The above copyright notice and this permission notice (including the next
     13 * paragraph) shall be included in all copies or substantial portions of the
     14 * Software.
     15 *
     16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     22 * DEALINGS IN THE SOFTWARE.
     23 *
     24 * Authors:
     25 *	Eric Anholt <eric@anholt.net>
     26 *      Dave Airlie <airlied@linux.ie>
     27 *      Jesse Barnes <jesse.barnes@intel.com>
     28 *      Chris Wilson <chris@chris-wilson.co.uk>
     29 */
     30
     31#include <linux/kernel.h>
     32#include <linux/pwm.h>
     33
     34#include "intel_backlight.h"
     35#include "intel_connector.h"
     36#include "intel_de.h"
     37#include "intel_display_types.h"
     38#include "intel_drrs.h"
     39#include "intel_panel.h"
     40
     41bool intel_panel_use_ssc(struct drm_i915_private *i915)
     42{
     43	if (i915->params.panel_use_ssc >= 0)
     44		return i915->params.panel_use_ssc != 0;
     45	return i915->vbt.lvds_use_ssc
     46		&& !(i915->quirks & QUIRK_LVDS_SSC_DISABLE);
     47}
     48
     49const struct drm_display_mode *
     50intel_panel_preferred_fixed_mode(struct intel_connector *connector)
     51{
     52	return list_first_entry_or_null(&connector->panel.fixed_modes,
     53					struct drm_display_mode, head);
     54}
     55
     56const struct drm_display_mode *
     57intel_panel_fixed_mode(struct intel_connector *connector,
     58		       const struct drm_display_mode *mode)
     59{
     60	const struct drm_display_mode *fixed_mode, *best_mode = NULL;
     61	int vrefresh = drm_mode_vrefresh(mode);
     62
     63	/* pick the fixed_mode that is closest in terms of vrefresh */
     64	list_for_each_entry(fixed_mode, &connector->panel.fixed_modes, head) {
     65		if (!best_mode ||
     66		    abs(drm_mode_vrefresh(fixed_mode) - vrefresh) <
     67		    abs(drm_mode_vrefresh(best_mode) - vrefresh))
     68			best_mode = fixed_mode;
     69	}
     70
     71	return best_mode;
     72}
     73
     74const struct drm_display_mode *
     75intel_panel_downclock_mode(struct intel_connector *connector,
     76			   const struct drm_display_mode *adjusted_mode)
     77{
     78	struct drm_i915_private *i915 = to_i915(connector->base.dev);
     79	const struct drm_display_mode *fixed_mode, *best_mode = NULL;
     80	int min_vrefresh = i915->vbt.seamless_drrs_min_refresh_rate;
     81	int max_vrefresh = drm_mode_vrefresh(adjusted_mode);
     82
     83	/* pick the fixed_mode with the lowest refresh rate */
     84	list_for_each_entry(fixed_mode, &connector->panel.fixed_modes, head) {
     85		int vrefresh = drm_mode_vrefresh(fixed_mode);
     86
     87		if (vrefresh >= min_vrefresh && vrefresh < max_vrefresh) {
     88			max_vrefresh = vrefresh;
     89			best_mode = fixed_mode;
     90		}
     91	}
     92
     93	return best_mode;
     94}
     95
     96int intel_panel_get_modes(struct intel_connector *connector)
     97{
     98	const struct drm_display_mode *fixed_mode;
     99	int num_modes = 0;
    100
    101	list_for_each_entry(fixed_mode, &connector->panel.fixed_modes, head) {
    102		struct drm_display_mode *mode;
    103
    104		mode = drm_mode_duplicate(connector->base.dev, fixed_mode);
    105		if (mode) {
    106			drm_mode_probed_add(&connector->base, mode);
    107			num_modes++;
    108		}
    109	}
    110
    111	return num_modes;
    112}
    113
    114enum drrs_type intel_panel_drrs_type(struct intel_connector *connector)
    115{
    116	struct drm_i915_private *i915 = to_i915(connector->base.dev);
    117
    118	if (list_empty(&connector->panel.fixed_modes) ||
    119	    list_is_singular(&connector->panel.fixed_modes))
    120		return DRRS_TYPE_NONE;
    121
    122	return i915->vbt.drrs_type;
    123}
    124
    125int intel_panel_compute_config(struct intel_connector *connector,
    126			       struct drm_display_mode *adjusted_mode)
    127{
    128	const struct drm_display_mode *fixed_mode =
    129		intel_panel_fixed_mode(connector, adjusted_mode);
    130
    131	if (!fixed_mode)
    132		return 0;
    133
    134	/*
    135	 * We don't want to lie too much to the user about the refresh
    136	 * rate they're going to get. But we have to allow a bit of latitude
    137	 * for Xorg since it likes to automagically cook up modes with slightly
    138	 * off refresh rates.
    139	 */
    140	if (abs(drm_mode_vrefresh(adjusted_mode) - drm_mode_vrefresh(fixed_mode)) > 1) {
    141		drm_dbg_kms(connector->base.dev,
    142			    "[CONNECTOR:%d:%s] Requested mode vrefresh (%d Hz) does not match fixed mode vrefresh (%d Hz)\n",
    143			    connector->base.base.id, connector->base.name,
    144			    drm_mode_vrefresh(adjusted_mode), drm_mode_vrefresh(fixed_mode));
    145
    146		return -EINVAL;
    147	}
    148
    149	drm_mode_copy(adjusted_mode, fixed_mode);
    150
    151	drm_mode_set_crtcinfo(adjusted_mode, 0);
    152
    153	return 0;
    154}
    155
    156static bool is_alt_fixed_mode(const struct drm_display_mode *mode,
    157			      const struct drm_display_mode *preferred_mode)
    158{
    159	return drm_mode_match(mode, preferred_mode,
    160			      DRM_MODE_MATCH_TIMINGS |
    161			      DRM_MODE_MATCH_FLAGS |
    162			      DRM_MODE_MATCH_3D_FLAGS) &&
    163		mode->clock != preferred_mode->clock;
    164}
    165
    166static void intel_panel_add_edid_alt_fixed_modes(struct intel_connector *connector)
    167{
    168	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
    169	const struct drm_display_mode *preferred_mode =
    170		intel_panel_preferred_fixed_mode(connector);
    171	struct drm_display_mode *mode, *next;
    172
    173	list_for_each_entry_safe(mode, next, &connector->base.probed_modes, head) {
    174		if (!is_alt_fixed_mode(mode, preferred_mode))
    175			continue;
    176
    177		drm_dbg_kms(&dev_priv->drm,
    178			    "[CONNECTOR:%d:%s] using alternate EDID fixed mode: " DRM_MODE_FMT "\n",
    179			    connector->base.base.id, connector->base.name,
    180			    DRM_MODE_ARG(mode));
    181
    182		list_move_tail(&mode->head, &connector->panel.fixed_modes);
    183	}
    184}
    185
    186static void intel_panel_add_edid_preferred_mode(struct intel_connector *connector)
    187{
    188	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
    189	struct drm_display_mode *scan, *fixed_mode = NULL;
    190
    191	if (list_empty(&connector->base.probed_modes))
    192		return;
    193
    194	/* make sure the preferred mode is first */
    195	list_for_each_entry(scan, &connector->base.probed_modes, head) {
    196		if (scan->type & DRM_MODE_TYPE_PREFERRED) {
    197			fixed_mode = scan;
    198			break;
    199		}
    200	}
    201
    202	if (!fixed_mode)
    203		fixed_mode = list_first_entry(&connector->base.probed_modes,
    204					      typeof(*fixed_mode), head);
    205
    206	drm_dbg_kms(&dev_priv->drm,
    207		    "[CONNECTOR:%d:%s] using %s EDID fixed mode: " DRM_MODE_FMT "\n",
    208		    connector->base.base.id, connector->base.name,
    209		    fixed_mode->type & DRM_MODE_TYPE_PREFERRED ? "preferred" : "first",
    210		    DRM_MODE_ARG(fixed_mode));
    211
    212	fixed_mode->type |= DRM_MODE_TYPE_PREFERRED;
    213
    214	list_move_tail(&fixed_mode->head, &connector->panel.fixed_modes);
    215}
    216
    217static void intel_panel_destroy_probed_modes(struct intel_connector *connector)
    218{
    219	struct drm_i915_private *i915 = to_i915(connector->base.dev);
    220	struct drm_display_mode *mode, *next;
    221
    222	list_for_each_entry_safe(mode, next, &connector->base.probed_modes, head) {
    223		list_del(&mode->head);
    224		drm_mode_destroy(&i915->drm, mode);
    225	}
    226}
    227
    228void intel_panel_add_edid_fixed_modes(struct intel_connector *connector, bool has_drrs)
    229{
    230	intel_panel_add_edid_preferred_mode(connector);
    231	if (intel_panel_preferred_fixed_mode(connector) && has_drrs)
    232		intel_panel_add_edid_alt_fixed_modes(connector);
    233	intel_panel_destroy_probed_modes(connector);
    234}
    235
    236static void intel_panel_add_fixed_mode(struct intel_connector *connector,
    237				       struct drm_display_mode *fixed_mode,
    238				       const char *type)
    239{
    240	struct drm_i915_private *i915 = to_i915(connector->base.dev);
    241	struct drm_display_info *info = &connector->base.display_info;
    242
    243	if (!fixed_mode)
    244		return;
    245
    246	fixed_mode->type |= DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER;
    247
    248	info->width_mm = fixed_mode->width_mm;
    249	info->height_mm = fixed_mode->height_mm;
    250
    251	drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] using %s fixed mode: " DRM_MODE_FMT "\n",
    252		    connector->base.base.id, connector->base.name, type,
    253		    DRM_MODE_ARG(fixed_mode));
    254
    255	list_add_tail(&fixed_mode->head, &connector->panel.fixed_modes);
    256}
    257
    258void intel_panel_add_vbt_lfp_fixed_mode(struct intel_connector *connector)
    259{
    260	struct drm_i915_private *i915 = to_i915(connector->base.dev);
    261	const struct drm_display_mode *mode;
    262
    263	mode = i915->vbt.lfp_lvds_vbt_mode;
    264	if (!mode)
    265		return;
    266
    267	intel_panel_add_fixed_mode(connector,
    268				   drm_mode_duplicate(&i915->drm, mode),
    269				   "VBT LFP");
    270}
    271
    272void intel_panel_add_vbt_sdvo_fixed_mode(struct intel_connector *connector)
    273{
    274	struct drm_i915_private *i915 = to_i915(connector->base.dev);
    275	const struct drm_display_mode *mode;
    276
    277	mode = i915->vbt.sdvo_lvds_vbt_mode;
    278	if (!mode)
    279		return;
    280
    281	intel_panel_add_fixed_mode(connector,
    282				   drm_mode_duplicate(&i915->drm, mode),
    283				   "VBT SDVO");
    284}
    285
    286void intel_panel_add_encoder_fixed_mode(struct intel_connector *connector,
    287					struct intel_encoder *encoder)
    288{
    289	intel_panel_add_fixed_mode(connector,
    290				   intel_encoder_current_mode(encoder),
    291				   "current (BIOS)");
    292}
    293
    294/* adjusted_mode has been preset to be the panel's fixed mode */
    295static int pch_panel_fitting(struct intel_crtc_state *crtc_state,
    296			     const struct drm_connector_state *conn_state)
    297{
    298	const struct drm_display_mode *adjusted_mode =
    299		&crtc_state->hw.adjusted_mode;
    300	int pipe_src_w = drm_rect_width(&crtc_state->pipe_src);
    301	int pipe_src_h = drm_rect_height(&crtc_state->pipe_src);
    302	int x, y, width, height;
    303
    304	/* Native modes don't need fitting */
    305	if (adjusted_mode->crtc_hdisplay == pipe_src_w &&
    306	    adjusted_mode->crtc_vdisplay == pipe_src_h &&
    307	    crtc_state->output_format != INTEL_OUTPUT_FORMAT_YCBCR420)
    308		return 0;
    309
    310	switch (conn_state->scaling_mode) {
    311	case DRM_MODE_SCALE_CENTER:
    312		width = pipe_src_w;
    313		height = pipe_src_h;
    314		x = (adjusted_mode->crtc_hdisplay - width + 1)/2;
    315		y = (adjusted_mode->crtc_vdisplay - height + 1)/2;
    316		break;
    317
    318	case DRM_MODE_SCALE_ASPECT:
    319		/* Scale but preserve the aspect ratio */
    320		{
    321			u32 scaled_width = adjusted_mode->crtc_hdisplay * pipe_src_h;
    322			u32 scaled_height = pipe_src_w * adjusted_mode->crtc_vdisplay;
    323			if (scaled_width > scaled_height) { /* pillar */
    324				width = scaled_height / pipe_src_h;
    325				if (width & 1)
    326					width++;
    327				x = (adjusted_mode->crtc_hdisplay - width + 1) / 2;
    328				y = 0;
    329				height = adjusted_mode->crtc_vdisplay;
    330			} else if (scaled_width < scaled_height) { /* letter */
    331				height = scaled_width / pipe_src_w;
    332				if (height & 1)
    333				    height++;
    334				y = (adjusted_mode->crtc_vdisplay - height + 1) / 2;
    335				x = 0;
    336				width = adjusted_mode->crtc_hdisplay;
    337			} else {
    338				x = y = 0;
    339				width = adjusted_mode->crtc_hdisplay;
    340				height = adjusted_mode->crtc_vdisplay;
    341			}
    342		}
    343		break;
    344
    345	case DRM_MODE_SCALE_NONE:
    346		WARN_ON(adjusted_mode->crtc_hdisplay != pipe_src_w);
    347		WARN_ON(adjusted_mode->crtc_vdisplay != pipe_src_h);
    348		fallthrough;
    349	case DRM_MODE_SCALE_FULLSCREEN:
    350		x = y = 0;
    351		width = adjusted_mode->crtc_hdisplay;
    352		height = adjusted_mode->crtc_vdisplay;
    353		break;
    354
    355	default:
    356		MISSING_CASE(conn_state->scaling_mode);
    357		return -EINVAL;
    358	}
    359
    360	drm_rect_init(&crtc_state->pch_pfit.dst,
    361		      x, y, width, height);
    362	crtc_state->pch_pfit.enabled = true;
    363
    364	return 0;
    365}
    366
    367static void
    368centre_horizontally(struct drm_display_mode *adjusted_mode,
    369		    int width)
    370{
    371	u32 border, sync_pos, blank_width, sync_width;
    372
    373	/* keep the hsync and hblank widths constant */
    374	sync_width = adjusted_mode->crtc_hsync_end - adjusted_mode->crtc_hsync_start;
    375	blank_width = adjusted_mode->crtc_hblank_end - adjusted_mode->crtc_hblank_start;
    376	sync_pos = (blank_width - sync_width + 1) / 2;
    377
    378	border = (adjusted_mode->crtc_hdisplay - width + 1) / 2;
    379	border += border & 1; /* make the border even */
    380
    381	adjusted_mode->crtc_hdisplay = width;
    382	adjusted_mode->crtc_hblank_start = width + border;
    383	adjusted_mode->crtc_hblank_end = adjusted_mode->crtc_hblank_start + blank_width;
    384
    385	adjusted_mode->crtc_hsync_start = adjusted_mode->crtc_hblank_start + sync_pos;
    386	adjusted_mode->crtc_hsync_end = adjusted_mode->crtc_hsync_start + sync_width;
    387}
    388
    389static void
    390centre_vertically(struct drm_display_mode *adjusted_mode,
    391		  int height)
    392{
    393	u32 border, sync_pos, blank_width, sync_width;
    394
    395	/* keep the vsync and vblank widths constant */
    396	sync_width = adjusted_mode->crtc_vsync_end - adjusted_mode->crtc_vsync_start;
    397	blank_width = adjusted_mode->crtc_vblank_end - adjusted_mode->crtc_vblank_start;
    398	sync_pos = (blank_width - sync_width + 1) / 2;
    399
    400	border = (adjusted_mode->crtc_vdisplay - height + 1) / 2;
    401
    402	adjusted_mode->crtc_vdisplay = height;
    403	adjusted_mode->crtc_vblank_start = height + border;
    404	adjusted_mode->crtc_vblank_end = adjusted_mode->crtc_vblank_start + blank_width;
    405
    406	adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vblank_start + sync_pos;
    407	adjusted_mode->crtc_vsync_end = adjusted_mode->crtc_vsync_start + sync_width;
    408}
    409
    410static u32 panel_fitter_scaling(u32 source, u32 target)
    411{
    412	/*
    413	 * Floating point operation is not supported. So the FACTOR
    414	 * is defined, which can avoid the floating point computation
    415	 * when calculating the panel ratio.
    416	 */
    417#define ACCURACY 12
    418#define FACTOR (1 << ACCURACY)
    419	u32 ratio = source * FACTOR / target;
    420	return (FACTOR * ratio + FACTOR/2) / FACTOR;
    421}
    422
    423static void i965_scale_aspect(struct intel_crtc_state *crtc_state,
    424			      u32 *pfit_control)
    425{
    426	const struct drm_display_mode *adjusted_mode =
    427		&crtc_state->hw.adjusted_mode;
    428	int pipe_src_w = drm_rect_width(&crtc_state->pipe_src);
    429	int pipe_src_h = drm_rect_height(&crtc_state->pipe_src);
    430	u32 scaled_width = adjusted_mode->crtc_hdisplay * pipe_src_h;
    431	u32 scaled_height = pipe_src_w * adjusted_mode->crtc_vdisplay;
    432
    433	/* 965+ is easy, it does everything in hw */
    434	if (scaled_width > scaled_height)
    435		*pfit_control |= PFIT_ENABLE |
    436			PFIT_SCALING_PILLAR;
    437	else if (scaled_width < scaled_height)
    438		*pfit_control |= PFIT_ENABLE |
    439			PFIT_SCALING_LETTER;
    440	else if (adjusted_mode->crtc_hdisplay != pipe_src_w)
    441		*pfit_control |= PFIT_ENABLE | PFIT_SCALING_AUTO;
    442}
    443
    444static void i9xx_scale_aspect(struct intel_crtc_state *crtc_state,
    445			      u32 *pfit_control, u32 *pfit_pgm_ratios,
    446			      u32 *border)
    447{
    448	struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode;
    449	int pipe_src_w = drm_rect_width(&crtc_state->pipe_src);
    450	int pipe_src_h = drm_rect_height(&crtc_state->pipe_src);
    451	u32 scaled_width = adjusted_mode->crtc_hdisplay * pipe_src_h;
    452	u32 scaled_height = pipe_src_w * adjusted_mode->crtc_vdisplay;
    453	u32 bits;
    454
    455	/*
    456	 * For earlier chips we have to calculate the scaling
    457	 * ratio by hand and program it into the
    458	 * PFIT_PGM_RATIO register
    459	 */
    460	if (scaled_width > scaled_height) { /* pillar */
    461		centre_horizontally(adjusted_mode,
    462				    scaled_height / pipe_src_h);
    463
    464		*border = LVDS_BORDER_ENABLE;
    465		if (pipe_src_h != adjusted_mode->crtc_vdisplay) {
    466			bits = panel_fitter_scaling(pipe_src_h,
    467						    adjusted_mode->crtc_vdisplay);
    468
    469			*pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT |
    470					     bits << PFIT_VERT_SCALE_SHIFT);
    471			*pfit_control |= (PFIT_ENABLE |
    472					  VERT_INTERP_BILINEAR |
    473					  HORIZ_INTERP_BILINEAR);
    474		}
    475	} else if (scaled_width < scaled_height) { /* letter */
    476		centre_vertically(adjusted_mode,
    477				  scaled_width / pipe_src_w);
    478
    479		*border = LVDS_BORDER_ENABLE;
    480		if (pipe_src_w != adjusted_mode->crtc_hdisplay) {
    481			bits = panel_fitter_scaling(pipe_src_w,
    482						    adjusted_mode->crtc_hdisplay);
    483
    484			*pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT |
    485					     bits << PFIT_VERT_SCALE_SHIFT);
    486			*pfit_control |= (PFIT_ENABLE |
    487					  VERT_INTERP_BILINEAR |
    488					  HORIZ_INTERP_BILINEAR);
    489		}
    490	} else {
    491		/* Aspects match, Let hw scale both directions */
    492		*pfit_control |= (PFIT_ENABLE |
    493				  VERT_AUTO_SCALE | HORIZ_AUTO_SCALE |
    494				  VERT_INTERP_BILINEAR |
    495				  HORIZ_INTERP_BILINEAR);
    496	}
    497}
    498
    499static int gmch_panel_fitting(struct intel_crtc_state *crtc_state,
    500			      const struct drm_connector_state *conn_state)
    501{
    502	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
    503	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
    504	u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0;
    505	struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode;
    506	int pipe_src_w = drm_rect_width(&crtc_state->pipe_src);
    507	int pipe_src_h = drm_rect_height(&crtc_state->pipe_src);
    508
    509	/* Native modes don't need fitting */
    510	if (adjusted_mode->crtc_hdisplay == pipe_src_w &&
    511	    adjusted_mode->crtc_vdisplay == pipe_src_h)
    512		goto out;
    513
    514	switch (conn_state->scaling_mode) {
    515	case DRM_MODE_SCALE_CENTER:
    516		/*
    517		 * For centered modes, we have to calculate border widths &
    518		 * heights and modify the values programmed into the CRTC.
    519		 */
    520		centre_horizontally(adjusted_mode, pipe_src_w);
    521		centre_vertically(adjusted_mode, pipe_src_h);
    522		border = LVDS_BORDER_ENABLE;
    523		break;
    524	case DRM_MODE_SCALE_ASPECT:
    525		/* Scale but preserve the aspect ratio */
    526		if (DISPLAY_VER(dev_priv) >= 4)
    527			i965_scale_aspect(crtc_state, &pfit_control);
    528		else
    529			i9xx_scale_aspect(crtc_state, &pfit_control,
    530					  &pfit_pgm_ratios, &border);
    531		break;
    532	case DRM_MODE_SCALE_FULLSCREEN:
    533		/*
    534		 * Full scaling, even if it changes the aspect ratio.
    535		 * Fortunately this is all done for us in hw.
    536		 */
    537		if (pipe_src_h != adjusted_mode->crtc_vdisplay ||
    538		    pipe_src_w != adjusted_mode->crtc_hdisplay) {
    539			pfit_control |= PFIT_ENABLE;
    540			if (DISPLAY_VER(dev_priv) >= 4)
    541				pfit_control |= PFIT_SCALING_AUTO;
    542			else
    543				pfit_control |= (VERT_AUTO_SCALE |
    544						 VERT_INTERP_BILINEAR |
    545						 HORIZ_AUTO_SCALE |
    546						 HORIZ_INTERP_BILINEAR);
    547		}
    548		break;
    549	default:
    550		MISSING_CASE(conn_state->scaling_mode);
    551		return -EINVAL;
    552	}
    553
    554	/* 965+ wants fuzzy fitting */
    555	/* FIXME: handle multiple panels by failing gracefully */
    556	if (DISPLAY_VER(dev_priv) >= 4)
    557		pfit_control |= PFIT_PIPE(crtc->pipe) | PFIT_FILTER_FUZZY;
    558
    559out:
    560	if ((pfit_control & PFIT_ENABLE) == 0) {
    561		pfit_control = 0;
    562		pfit_pgm_ratios = 0;
    563	}
    564
    565	/* Make sure pre-965 set dither correctly for 18bpp panels. */
    566	if (DISPLAY_VER(dev_priv) < 4 && crtc_state->pipe_bpp == 18)
    567		pfit_control |= PANEL_8TO6_DITHER_ENABLE;
    568
    569	crtc_state->gmch_pfit.control = pfit_control;
    570	crtc_state->gmch_pfit.pgm_ratios = pfit_pgm_ratios;
    571	crtc_state->gmch_pfit.lvds_border_bits = border;
    572
    573	return 0;
    574}
    575
    576int intel_panel_fitting(struct intel_crtc_state *crtc_state,
    577			const struct drm_connector_state *conn_state)
    578{
    579	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
    580	struct drm_i915_private *i915 = to_i915(crtc->base.dev);
    581
    582	if (HAS_GMCH(i915))
    583		return gmch_panel_fitting(crtc_state, conn_state);
    584	else
    585		return pch_panel_fitting(crtc_state, conn_state);
    586}
    587
    588enum drm_connector_status
    589intel_panel_detect(struct drm_connector *connector, bool force)
    590{
    591	struct drm_i915_private *i915 = to_i915(connector->dev);
    592
    593	if (!INTEL_DISPLAY_ENABLED(i915))
    594		return connector_status_disconnected;
    595
    596	return connector_status_connected;
    597}
    598
    599enum drm_mode_status
    600intel_panel_mode_valid(struct intel_connector *connector,
    601		       const struct drm_display_mode *mode)
    602{
    603	const struct drm_display_mode *fixed_mode =
    604		intel_panel_fixed_mode(connector, mode);
    605
    606	if (!fixed_mode)
    607		return MODE_OK;
    608
    609	if (mode->hdisplay != fixed_mode->hdisplay)
    610		return MODE_PANEL;
    611
    612	if (mode->vdisplay != fixed_mode->vdisplay)
    613		return MODE_PANEL;
    614
    615	if (drm_mode_vrefresh(mode) != drm_mode_vrefresh(fixed_mode))
    616		return MODE_PANEL;
    617
    618	return MODE_OK;
    619}
    620
    621int intel_panel_init(struct intel_connector *connector)
    622{
    623	struct intel_panel *panel = &connector->panel;
    624
    625	intel_backlight_init_funcs(panel);
    626
    627	drm_dbg_kms(connector->base.dev,
    628		    "[CONNECTOR:%d:%s] DRRS type: %s\n",
    629		    connector->base.base.id, connector->base.name,
    630		    intel_drrs_type_str(intel_panel_drrs_type(connector)));
    631
    632	return 0;
    633}
    634
    635void intel_panel_fini(struct intel_connector *connector)
    636{
    637	struct intel_panel *panel = &connector->panel;
    638	struct drm_display_mode *fixed_mode, *next;
    639
    640	intel_backlight_destroy(panel);
    641
    642	list_for_each_entry_safe(fixed_mode, next, &panel->fixed_modes, head) {
    643		list_del(&fixed_mode->head);
    644		drm_mode_destroy(connector->base.dev, fixed_mode);
    645	}
    646}