intel_panel.c 35.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
/*
 * Copyright © 2006-2010 Intel Corporation
 * Copyright (c) 2006 Dave Airlie <airlied@linux.ie>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 * Authors:
 *	Eric Anholt <eric@anholt.net>
 *      Dave Airlie <airlied@linux.ie>
 *      Jesse Barnes <jesse.barnes@intel.com>
 *      Chris Wilson <chris@chris-wilson.co.uk>
 */

31 32
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

33
#include <linux/moduleparam.h>
34 35 36
#include "intel_drv.h"

void
37
intel_fixed_panel_mode(const struct drm_display_mode *fixed_mode,
38 39
		       struct drm_display_mode *adjusted_mode)
{
40
	drm_mode_copy(adjusted_mode, fixed_mode);
41 42

	drm_mode_set_crtcinfo(adjusted_mode, 0);
43 44
}

J
Jani Nikula 已提交
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
/**
 * intel_find_panel_downclock - find the reduced downclock for LVDS in EDID
 * @dev: drm device
 * @fixed_mode : panel native mode
 * @connector: LVDS/eDP connector
 *
 * Return downclock_avail
 * Find the reduced downclock for LVDS/eDP in EDID.
 */
struct drm_display_mode *
intel_find_panel_downclock(struct drm_device *dev,
			struct drm_display_mode *fixed_mode,
			struct drm_connector *connector)
{
	struct drm_display_mode *scan, *tmp_mode;
	int temp_downclock;

	temp_downclock = fixed_mode->clock;
	tmp_mode = NULL;

	list_for_each_entry(scan, &connector->probed_modes, head) {
		/*
		 * If one mode has the same resolution with the fixed_panel
		 * mode while they have the different refresh rate, it means
		 * that the reduced downclock is found. In such
		 * case we can set the different FPx0/1 to dynamically select
		 * between low and high frequency.
		 */
		if (scan->hdisplay == fixed_mode->hdisplay &&
		    scan->hsync_start == fixed_mode->hsync_start &&
		    scan->hsync_end == fixed_mode->hsync_end &&
		    scan->htotal == fixed_mode->htotal &&
		    scan->vdisplay == fixed_mode->vdisplay &&
		    scan->vsync_start == fixed_mode->vsync_start &&
		    scan->vsync_end == fixed_mode->vsync_end &&
		    scan->vtotal == fixed_mode->vtotal) {
			if (scan->clock < temp_downclock) {
				/*
				 * The downclock is already found. But we
				 * expect to find the lower downclock.
				 */
				temp_downclock = scan->clock;
				tmp_mode = scan;
			}
		}
	}

	if (temp_downclock < fixed_mode->clock)
		return drm_mode_duplicate(dev, tmp_mode);
	else
		return NULL;
}

98 99
/* adjusted_mode has been preset to be the panel's fixed mode */
void
100 101 102
intel_pch_panel_fitting(struct intel_crtc *intel_crtc,
			struct intel_crtc_config *pipe_config,
			int fitting_mode)
103
{
104
	struct drm_display_mode *adjusted_mode;
105 106
	int x, y, width, height;

107 108
	adjusted_mode = &pipe_config->adjusted_mode;

109 110 111
	x = y = width = height = 0;

	/* Native modes don't need fitting */
112 113
	if (adjusted_mode->hdisplay == pipe_config->pipe_src_w &&
	    adjusted_mode->vdisplay == pipe_config->pipe_src_h)
114 115 116 117
		goto done;

	switch (fitting_mode) {
	case DRM_MODE_SCALE_CENTER:
118 119
		width = pipe_config->pipe_src_w;
		height = pipe_config->pipe_src_h;
120 121 122 123 124 125 126
		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 */
		{
127 128 129 130
			u32 scaled_width = adjusted_mode->hdisplay
				* pipe_config->pipe_src_h;
			u32 scaled_height = pipe_config->pipe_src_w
				* adjusted_mode->vdisplay;
131
			if (scaled_width > scaled_height) { /* pillar */
132
				width = scaled_height / pipe_config->pipe_src_h;
133
				if (width & 1)
134
					width++;
135 136 137 138
				x = (adjusted_mode->hdisplay - width + 1) / 2;
				y = 0;
				height = adjusted_mode->vdisplay;
			} else if (scaled_width < scaled_height) { /* letter */
139
				height = scaled_width / pipe_config->pipe_src_w;
140 141
				if (height & 1)
				    height++;
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
				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;

	case DRM_MODE_SCALE_FULLSCREEN:
		x = y = 0;
		width = adjusted_mode->hdisplay;
		height = adjusted_mode->vdisplay;
		break;
158 159 160 161

	default:
		WARN(1, "bad panel fit mode: %d\n", fitting_mode);
		return;
162 163 164
	}

done:
165 166
	pipe_config->pch_pfit.pos = (x << 16) | y;
	pipe_config->pch_pfit.size = (width << 16) | height;
167
	pipe_config->pch_pfit.enabled = pipe_config->pch_pfit.size != 0;
168
}
169

170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
static void
centre_horizontally(struct drm_display_mode *mode,
		    int width)
{
	u32 border, sync_pos, blank_width, sync_width;

	/* keep the hsync and hblank widths constant */
	sync_width = mode->crtc_hsync_end - mode->crtc_hsync_start;
	blank_width = mode->crtc_hblank_end - mode->crtc_hblank_start;
	sync_pos = (blank_width - sync_width + 1) / 2;

	border = (mode->hdisplay - width + 1) / 2;
	border += border & 1; /* make the border even */

	mode->crtc_hdisplay = width;
	mode->crtc_hblank_start = width + border;
	mode->crtc_hblank_end = mode->crtc_hblank_start + blank_width;

	mode->crtc_hsync_start = mode->crtc_hblank_start + sync_pos;
	mode->crtc_hsync_end = mode->crtc_hsync_start + sync_width;
}

static void
centre_vertically(struct drm_display_mode *mode,
		  int height)
{
	u32 border, sync_pos, blank_width, sync_width;

	/* keep the vsync and vblank widths constant */
	sync_width = mode->crtc_vsync_end - mode->crtc_vsync_start;
	blank_width = mode->crtc_vblank_end - mode->crtc_vblank_start;
	sync_pos = (blank_width - sync_width + 1) / 2;

	border = (mode->vdisplay - height + 1) / 2;

	mode->crtc_vdisplay = height;
	mode->crtc_vblank_start = height + border;
	mode->crtc_vblank_end = mode->crtc_vblank_start + blank_width;

	mode->crtc_vsync_start = mode->crtc_vblank_start + sync_pos;
	mode->crtc_vsync_end = mode->crtc_vsync_start + sync_width;
}

static inline u32 panel_fitter_scaling(u32 source, u32 target)
{
	/*
	 * Floating point operation is not supported. So the FACTOR
	 * is defined, which can avoid the floating point computation
	 * when calculating the panel ratio.
	 */
#define ACCURACY 12
#define FACTOR (1 << ACCURACY)
	u32 ratio = source * FACTOR / target;
	return (FACTOR * ratio + FACTOR/2) / FACTOR;
}

226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302
static void i965_scale_aspect(struct intel_crtc_config *pipe_config,
			      u32 *pfit_control)
{
	struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode;
	u32 scaled_width = adjusted_mode->hdisplay *
		pipe_config->pipe_src_h;
	u32 scaled_height = pipe_config->pipe_src_w *
		adjusted_mode->vdisplay;

	/* 965+ is easy, it does everything in hw */
	if (scaled_width > scaled_height)
		*pfit_control |= PFIT_ENABLE |
			PFIT_SCALING_PILLAR;
	else if (scaled_width < scaled_height)
		*pfit_control |= PFIT_ENABLE |
			PFIT_SCALING_LETTER;
	else if (adjusted_mode->hdisplay != pipe_config->pipe_src_w)
		*pfit_control |= PFIT_ENABLE | PFIT_SCALING_AUTO;
}

static void i9xx_scale_aspect(struct intel_crtc_config *pipe_config,
			      u32 *pfit_control, u32 *pfit_pgm_ratios,
			      u32 *border)
{
	struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode;
	u32 scaled_width = adjusted_mode->hdisplay *
		pipe_config->pipe_src_h;
	u32 scaled_height = pipe_config->pipe_src_w *
		adjusted_mode->vdisplay;
	u32 bits;

	/*
	 * For earlier chips we have to calculate the scaling
	 * ratio by hand and program it into the
	 * PFIT_PGM_RATIO register
	 */
	if (scaled_width > scaled_height) { /* pillar */
		centre_horizontally(adjusted_mode,
				    scaled_height /
				    pipe_config->pipe_src_h);

		*border = LVDS_BORDER_ENABLE;
		if (pipe_config->pipe_src_h != adjusted_mode->vdisplay) {
			bits = panel_fitter_scaling(pipe_config->pipe_src_h,
						    adjusted_mode->vdisplay);

			*pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT |
					     bits << PFIT_VERT_SCALE_SHIFT);
			*pfit_control |= (PFIT_ENABLE |
					  VERT_INTERP_BILINEAR |
					  HORIZ_INTERP_BILINEAR);
		}
	} else if (scaled_width < scaled_height) { /* letter */
		centre_vertically(adjusted_mode,
				  scaled_width /
				  pipe_config->pipe_src_w);

		*border = LVDS_BORDER_ENABLE;
		if (pipe_config->pipe_src_w != adjusted_mode->hdisplay) {
			bits = panel_fitter_scaling(pipe_config->pipe_src_w,
						    adjusted_mode->hdisplay);

			*pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT |
					     bits << PFIT_VERT_SCALE_SHIFT);
			*pfit_control |= (PFIT_ENABLE |
					  VERT_INTERP_BILINEAR |
					  HORIZ_INTERP_BILINEAR);
		}
	} else {
		/* Aspects match, Let hw scale both directions */
		*pfit_control |= (PFIT_ENABLE |
				  VERT_AUTO_SCALE | HORIZ_AUTO_SCALE |
				  VERT_INTERP_BILINEAR |
				  HORIZ_INTERP_BILINEAR);
	}
}

303 304 305 306 307 308
void intel_gmch_panel_fitting(struct intel_crtc *intel_crtc,
			      struct intel_crtc_config *pipe_config,
			      int fitting_mode)
{
	struct drm_device *dev = intel_crtc->base.dev;
	u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0;
309
	struct drm_display_mode *adjusted_mode;
310 311 312 313

	adjusted_mode = &pipe_config->adjusted_mode;

	/* Native modes don't need fitting */
314 315
	if (adjusted_mode->hdisplay == pipe_config->pipe_src_w &&
	    adjusted_mode->vdisplay == pipe_config->pipe_src_h)
316 317 318 319 320 321 322 323
		goto out;

	switch (fitting_mode) {
	case DRM_MODE_SCALE_CENTER:
		/*
		 * For centered modes, we have to calculate border widths &
		 * heights and modify the values programmed into the CRTC.
		 */
324 325
		centre_horizontally(adjusted_mode, pipe_config->pipe_src_w);
		centre_vertically(adjusted_mode, pipe_config->pipe_src_h);
326 327 328 329
		border = LVDS_BORDER_ENABLE;
		break;
	case DRM_MODE_SCALE_ASPECT:
		/* Scale but preserve the aspect ratio */
330 331 332 333 334
		if (INTEL_INFO(dev)->gen >= 4)
			i965_scale_aspect(pipe_config, &pfit_control);
		else
			i9xx_scale_aspect(pipe_config, &pfit_control,
					  &pfit_pgm_ratios, &border);
335 336 337 338 339 340
		break;
	case DRM_MODE_SCALE_FULLSCREEN:
		/*
		 * Full scaling, even if it changes the aspect ratio.
		 * Fortunately this is all done for us in hw.
		 */
341 342
		if (pipe_config->pipe_src_h != adjusted_mode->vdisplay ||
		    pipe_config->pipe_src_w != adjusted_mode->hdisplay) {
343 344 345 346 347 348 349 350 351 352
			pfit_control |= PFIT_ENABLE;
			if (INTEL_INFO(dev)->gen >= 4)
				pfit_control |= PFIT_SCALING_AUTO;
			else
				pfit_control |= (VERT_AUTO_SCALE |
						 VERT_INTERP_BILINEAR |
						 HORIZ_AUTO_SCALE |
						 HORIZ_INTERP_BILINEAR);
		}
		break;
353 354 355
	default:
		WARN(1, "bad panel fit mode: %d\n", fitting_mode);
		return;
356 357 358 359 360 361 362 363
	}

	/* 965+ wants fuzzy fitting */
	/* FIXME: handle multiple panels by failing gracefully */
	if (INTEL_INFO(dev)->gen >= 4)
		pfit_control |= ((intel_crtc->pipe << PFIT_PIPE_SHIFT) |
				 PFIT_FILTER_FUZZY);

364 365 366 367
	/* Make sure pre-965 set dither correctly for 18bpp panels. */
	if (INTEL_INFO(dev)->gen < 4 && pipe_config->pipe_bpp == 18)
		pfit_control |= PANEL_8TO6_DITHER_ENABLE;

368 369 370 371 372 373
out:
	if ((pfit_control & PFIT_ENABLE) == 0) {
		pfit_control = 0;
		pfit_pgm_ratios = 0;
	}

374 375
	pipe_config->gmch_pfit.control = pfit_control;
	pipe_config->gmch_pfit.pgm_ratios = pfit_pgm_ratios;
376
	pipe_config->gmch_pfit.lvds_border_bits = border;
377 378
}

J
Jani Nikula 已提交
379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400
enum drm_connector_status
intel_panel_detect(struct drm_device *dev)
{
	struct drm_i915_private *dev_priv = dev->dev_private;

	/* Assume that the BIOS does not lie through the OpRegion... */
	if (!i915.panel_ignore_lid && dev_priv->opregion.lid_state) {
		return ioread32(dev_priv->opregion.lid_state) & 0x1 ?
			connector_status_connected :
			connector_status_disconnected;
	}

	switch (i915.panel_ignore_lid) {
	case -2:
		return connector_status_connected;
	case -1:
		return connector_status_disconnected;
	default:
		return connector_status_unknown;
	}
}

401 402
static u32 intel_panel_compute_brightness(struct intel_connector *connector,
					  u32 val)
403
{
404
	struct drm_device *dev = connector->base.dev;
405
	struct drm_i915_private *dev_priv = dev->dev_private;
406 407 408
	struct intel_panel *panel = &connector->panel;

	WARN_ON(panel->backlight.max == 0);
409

410
	if (i915.invert_brightness < 0)
411 412
		return val;

413
	if (i915.invert_brightness > 0 ||
414
	    dev_priv->quirks & QUIRK_INVERT_BRIGHTNESS) {
415
		return panel->backlight.max - val;
416
	}
417 418 419 420

	return val;
}

421
static u32 bdw_get_backlight(struct intel_connector *connector)
422
{
423
	struct drm_device *dev = connector->base.dev;
424
	struct drm_i915_private *dev_priv = dev->dev_private;
425

426 427
	return I915_READ(BLC_PWM_PCH_CTL2) & BACKLIGHT_DUTY_CYCLE_MASK;
}
428

429
static u32 pch_get_backlight(struct intel_connector *connector)
430
{
431
	struct drm_device *dev = connector->base.dev;
432
	struct drm_i915_private *dev_priv = dev->dev_private;
433

434 435
	return I915_READ(BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
}
436

437 438 439 440
static u32 i9xx_get_backlight(struct intel_connector *connector)
{
	struct drm_device *dev = connector->base.dev;
	struct drm_i915_private *dev_priv = dev->dev_private;
441
	struct intel_panel *panel = &connector->panel;
442
	u32 val;
443

444 445 446
	val = I915_READ(BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
	if (INTEL_INFO(dev)->gen < 4)
		val >>= 1;
447

448
	if (panel->backlight.combination_mode) {
449
		u8 lbpc;
450

451 452
		pci_read_config_byte(dev->pdev, PCI_LBPC, &lbpc);
		val *= lbpc;
453 454
	}

455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483
	return val;
}

static u32 _vlv_get_backlight(struct drm_device *dev, enum pipe pipe)
{
	struct drm_i915_private *dev_priv = dev->dev_private;

	return I915_READ(VLV_BLC_PWM_CTL(pipe)) & BACKLIGHT_DUTY_CYCLE_MASK;
}

static u32 vlv_get_backlight(struct intel_connector *connector)
{
	struct drm_device *dev = connector->base.dev;
	enum pipe pipe = intel_get_pipe_from_connector(connector);

	return _vlv_get_backlight(dev, pipe);
}

static u32 intel_panel_get_backlight(struct intel_connector *connector)
{
	struct drm_device *dev = connector->base.dev;
	struct drm_i915_private *dev_priv = dev->dev_private;
	u32 val;
	unsigned long flags;

	spin_lock_irqsave(&dev_priv->backlight_lock, flags);

	val = dev_priv->display.get_backlight(connector);
	val = intel_panel_compute_brightness(connector, val);
484

485
	spin_unlock_irqrestore(&dev_priv->backlight_lock, flags);
486

487 488 489 490
	DRM_DEBUG_DRIVER("get backlight PWM = %d\n", val);
	return val;
}

491
static void bdw_set_backlight(struct intel_connector *connector, u32 level)
492
{
493
	struct drm_device *dev = connector->base.dev;
494 495 496 497 498
	struct drm_i915_private *dev_priv = dev->dev_private;
	u32 val = I915_READ(BLC_PWM_PCH_CTL2) & ~BACKLIGHT_DUTY_CYCLE_MASK;
	I915_WRITE(BLC_PWM_PCH_CTL2, val | level);
}

499
static void pch_set_backlight(struct intel_connector *connector, u32 level)
500
{
501
	struct drm_device *dev = connector->base.dev;
502
	struct drm_i915_private *dev_priv = dev->dev_private;
503 504 505 506
	u32 tmp;

	tmp = I915_READ(BLC_PWM_CPU_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK;
	I915_WRITE(BLC_PWM_CPU_CTL, tmp | level);
507 508
}

509
static void i9xx_set_backlight(struct intel_connector *connector, u32 level)
510
{
511
	struct drm_device *dev = connector->base.dev;
512
	struct drm_i915_private *dev_priv = dev->dev_private;
513
	struct intel_panel *panel = &connector->panel;
514
	u32 tmp, mask;
515

516 517
	WARN_ON(panel->backlight.max == 0);

518
	if (panel->backlight.combination_mode) {
519 520
		u8 lbpc;

521
		lbpc = level * 0xfe / panel->backlight.max + 1;
522 523 524 525
		level /= lbpc;
		pci_write_config_byte(dev->pdev, PCI_LBPC, lbpc);
	}

526 527 528
	if (IS_GEN4(dev)) {
		mask = BACKLIGHT_DUTY_CYCLE_MASK;
	} else {
529
		level <<= 1;
530 531
		mask = BACKLIGHT_DUTY_CYCLE_MASK_PNV;
	}
532

533
	tmp = I915_READ(BLC_PWM_CTL) & ~mask;
534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557
	I915_WRITE(BLC_PWM_CTL, tmp | level);
}

static void vlv_set_backlight(struct intel_connector *connector, u32 level)
{
	struct drm_device *dev = connector->base.dev;
	struct drm_i915_private *dev_priv = dev->dev_private;
	enum pipe pipe = intel_get_pipe_from_connector(connector);
	u32 tmp;

	tmp = I915_READ(VLV_BLC_PWM_CTL(pipe)) & ~BACKLIGHT_DUTY_CYCLE_MASK;
	I915_WRITE(VLV_BLC_PWM_CTL(pipe), tmp | level);
}

static void
intel_panel_actually_set_backlight(struct intel_connector *connector, u32 level)
{
	struct drm_device *dev = connector->base.dev;
	struct drm_i915_private *dev_priv = dev->dev_private;

	DRM_DEBUG_DRIVER("set backlight PWM = %d\n", level);

	level = intel_panel_compute_brightness(connector, level);
	dev_priv->display.set_backlight(connector, level);
558
}
559

560
/* set backlight brightness to level in range [0..max] */
561 562
void intel_panel_set_backlight(struct intel_connector *connector, u32 level,
			       u32 max)
563
{
564
	struct drm_device *dev = connector->base.dev;
565
	struct drm_i915_private *dev_priv = dev->dev_private;
566
	struct intel_panel *panel = &connector->panel;
567
	enum pipe pipe = intel_get_pipe_from_connector(connector);
568
	u32 freq;
569 570
	unsigned long flags;

571
	if (!panel->backlight.present || pipe == INVALID_PIPE)
572 573
		return;

574
	spin_lock_irqsave(&dev_priv->backlight_lock, flags);
575

576
	WARN_ON(panel->backlight.max == 0);
577

578 579
	/* scale to hardware max, but be careful to not overflow */
	freq = panel->backlight.max;
580 581 582 583
	if (freq < max)
		level = level * freq / max;
	else
		level = freq / max * level;
584

585 586 587
	panel->backlight.level = level;
	if (panel->backlight.device)
		panel->backlight.device->props.brightness = level;
588

589
	if (panel->backlight.enabled)
590
		intel_panel_actually_set_backlight(connector, level);
591

592
	spin_unlock_irqrestore(&dev_priv->backlight_lock, flags);
593 594
}

595 596 597 598 599 600
static void pch_disable_backlight(struct intel_connector *connector)
{
	struct drm_device *dev = connector->base.dev;
	struct drm_i915_private *dev_priv = dev->dev_private;
	u32 tmp;

601 602
	intel_panel_actually_set_backlight(connector, 0);

603 604 605 606 607 608 609
	tmp = I915_READ(BLC_PWM_CPU_CTL2);
	I915_WRITE(BLC_PWM_CPU_CTL2, tmp & ~BLM_PWM_ENABLE);

	tmp = I915_READ(BLC_PWM_PCH_CTL1);
	I915_WRITE(BLC_PWM_PCH_CTL1, tmp & ~BLM_PCH_PWM_ENABLE);
}

610 611 612 613 614
static void i9xx_disable_backlight(struct intel_connector *connector)
{
	intel_panel_actually_set_backlight(connector, 0);
}

615 616 617 618 619 620
static void i965_disable_backlight(struct intel_connector *connector)
{
	struct drm_device *dev = connector->base.dev;
	struct drm_i915_private *dev_priv = dev->dev_private;
	u32 tmp;

621 622
	intel_panel_actually_set_backlight(connector, 0);

623 624 625 626 627 628 629 630 631 632 633
	tmp = I915_READ(BLC_PWM_CTL2);
	I915_WRITE(BLC_PWM_CTL2, tmp & ~BLM_PWM_ENABLE);
}

static void vlv_disable_backlight(struct intel_connector *connector)
{
	struct drm_device *dev = connector->base.dev;
	struct drm_i915_private *dev_priv = dev->dev_private;
	enum pipe pipe = intel_get_pipe_from_connector(connector);
	u32 tmp;

634 635
	intel_panel_actually_set_backlight(connector, 0);

636 637 638 639
	tmp = I915_READ(VLV_BLC_PWM_CTL2(pipe));
	I915_WRITE(VLV_BLC_PWM_CTL2(pipe), tmp & ~BLM_PWM_ENABLE);
}

640
void intel_panel_disable_backlight(struct intel_connector *connector)
641
{
642
	struct drm_device *dev = connector->base.dev;
643
	struct drm_i915_private *dev_priv = dev->dev_private;
644
	struct intel_panel *panel = &connector->panel;
645
	enum pipe pipe = intel_get_pipe_from_connector(connector);
646 647
	unsigned long flags;

648
	if (!panel->backlight.present || pipe == INVALID_PIPE)
649 650
		return;

651 652 653 654 655 656 657 658 659 660 661
	/*
	 * Do not disable backlight on the vgaswitcheroo path. When switching
	 * away from i915, the other client may depend on i915 to handle the
	 * backlight. This will leave the backlight on unnecessarily when
	 * another client is not activated.
	 */
	if (dev->switch_power_state == DRM_SWITCH_POWER_CHANGING) {
		DRM_DEBUG_DRIVER("Skipping backlight disable on vga switch\n");
		return;
	}

662
	spin_lock_irqsave(&dev_priv->backlight_lock, flags);
663

664
	panel->backlight.enabled = false;
665
	dev_priv->display.disable_backlight(connector);
666

667 668
	spin_unlock_irqrestore(&dev_priv->backlight_lock, flags);
}
669

670 671 672 673 674 675 676 677 678 679 680 681 682
static void bdw_enable_backlight(struct intel_connector *connector)
{
	struct drm_device *dev = connector->base.dev;
	struct drm_i915_private *dev_priv = dev->dev_private;
	struct intel_panel *panel = &connector->panel;
	u32 pch_ctl1, pch_ctl2;

	pch_ctl1 = I915_READ(BLC_PWM_PCH_CTL1);
	if (pch_ctl1 & BLM_PCH_PWM_ENABLE) {
		DRM_DEBUG_KMS("pch backlight already enabled\n");
		pch_ctl1 &= ~BLM_PCH_PWM_ENABLE;
		I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1);
	}
683

684 685
	pch_ctl2 = panel->backlight.max << 16;
	I915_WRITE(BLC_PWM_PCH_CTL2, pch_ctl2);
686

687 688 689
	pch_ctl1 = 0;
	if (panel->backlight.active_low_pwm)
		pch_ctl1 |= BLM_PCH_POLARITY;
690

691 692 693 694 695 696 697 698 699
	/* BDW always uses the pch pwm controls. */
	pch_ctl1 |= BLM_PCH_OVERRIDE_ENABLE;

	I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1);
	POSTING_READ(BLC_PWM_PCH_CTL1);
	I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1 | BLM_PCH_PWM_ENABLE);

	/* This won't stick until the above enable. */
	intel_panel_actually_set_backlight(connector, panel->backlight.level);
700 701
}

702 703 704 705
static void pch_enable_backlight(struct intel_connector *connector)
{
	struct drm_device *dev = connector->base.dev;
	struct drm_i915_private *dev_priv = dev->dev_private;
706
	struct intel_panel *panel = &connector->panel;
707 708 709
	enum pipe pipe = intel_get_pipe_from_connector(connector);
	enum transcoder cpu_transcoder =
		intel_pipe_to_cpu_transcoder(dev_priv, pipe);
710
	u32 cpu_ctl2, pch_ctl1, pch_ctl2;
711

712 713 714 715 716 717
	cpu_ctl2 = I915_READ(BLC_PWM_CPU_CTL2);
	if (cpu_ctl2 & BLM_PWM_ENABLE) {
		WARN(1, "cpu backlight already enabled\n");
		cpu_ctl2 &= ~BLM_PWM_ENABLE;
		I915_WRITE(BLC_PWM_CPU_CTL2, cpu_ctl2);
	}
718

719 720 721 722 723 724
	pch_ctl1 = I915_READ(BLC_PWM_PCH_CTL1);
	if (pch_ctl1 & BLM_PCH_PWM_ENABLE) {
		DRM_DEBUG_KMS("pch backlight already enabled\n");
		pch_ctl1 &= ~BLM_PCH_PWM_ENABLE;
		I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1);
	}
725 726

	if (cpu_transcoder == TRANSCODER_EDP)
727
		cpu_ctl2 = BLM_TRANSCODER_EDP;
728
	else
729 730
		cpu_ctl2 = BLM_PIPE(cpu_transcoder);
	I915_WRITE(BLC_PWM_CPU_CTL2, cpu_ctl2);
731
	POSTING_READ(BLC_PWM_CPU_CTL2);
732
	I915_WRITE(BLC_PWM_CPU_CTL2, cpu_ctl2 | BLM_PWM_ENABLE);
733

734
	/* This won't stick until the above enable. */
735
	intel_panel_actually_set_backlight(connector, panel->backlight.level);
736 737 738 739 740 741 742

	pch_ctl2 = panel->backlight.max << 16;
	I915_WRITE(BLC_PWM_PCH_CTL2, pch_ctl2);

	pch_ctl1 = 0;
	if (panel->backlight.active_low_pwm)
		pch_ctl1 |= BLM_PCH_POLARITY;
743

744 745 746
	I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1);
	POSTING_READ(BLC_PWM_PCH_CTL1);
	I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1 | BLM_PCH_PWM_ENABLE);
747 748 749 750
}

static void i9xx_enable_backlight(struct intel_connector *connector)
{
751 752
	struct drm_device *dev = connector->base.dev;
	struct drm_i915_private *dev_priv = dev->dev_private;
753
	struct intel_panel *panel = &connector->panel;
754 755 756 757 758 759 760
	u32 ctl, freq;

	ctl = I915_READ(BLC_PWM_CTL);
	if (ctl & BACKLIGHT_DUTY_CYCLE_MASK_PNV) {
		WARN(1, "backlight already enabled\n");
		I915_WRITE(BLC_PWM_CTL, 0);
	}
761

762 763 764 765 766
	freq = panel->backlight.max;
	if (panel->backlight.combination_mode)
		freq /= 0xff;

	ctl = freq << 17;
767
	if (panel->backlight.combination_mode)
768 769 770 771 772 773 774 775
		ctl |= BLM_LEGACY_MODE;
	if (IS_PINEVIEW(dev) && panel->backlight.active_low_pwm)
		ctl |= BLM_POLARITY_PNV;

	I915_WRITE(BLC_PWM_CTL, ctl);
	POSTING_READ(BLC_PWM_CTL);

	/* XXX: combine this into above write? */
776
	intel_panel_actually_set_backlight(connector, panel->backlight.level);
777
}
778

779 780 781 782
static void i965_enable_backlight(struct intel_connector *connector)
{
	struct drm_device *dev = connector->base.dev;
	struct drm_i915_private *dev_priv = dev->dev_private;
783
	struct intel_panel *panel = &connector->panel;
784
	enum pipe pipe = intel_get_pipe_from_connector(connector);
785
	u32 ctl, ctl2, freq;
786

787 788 789 790 791 792
	ctl2 = I915_READ(BLC_PWM_CTL2);
	if (ctl2 & BLM_PWM_ENABLE) {
		WARN(1, "backlight already enabled\n");
		ctl2 &= ~BLM_PWM_ENABLE;
		I915_WRITE(BLC_PWM_CTL2, ctl2);
	}
793

794 795 796
	freq = panel->backlight.max;
	if (panel->backlight.combination_mode)
		freq /= 0xff;
797

798 799
	ctl = freq << 16;
	I915_WRITE(BLC_PWM_CTL, ctl);
800

801
	/* XXX: combine this into above write? */
802
	intel_panel_actually_set_backlight(connector, panel->backlight.level);
803 804 805 806 807 808 809 810 811

	ctl2 = BLM_PIPE(pipe);
	if (panel->backlight.combination_mode)
		ctl2 |= BLM_COMBINATION_MODE;
	if (panel->backlight.active_low_pwm)
		ctl2 |= BLM_POLARITY_I965;
	I915_WRITE(BLC_PWM_CTL2, ctl2);
	POSTING_READ(BLC_PWM_CTL2);
	I915_WRITE(BLC_PWM_CTL2, ctl2 | BLM_PWM_ENABLE);
812 813 814 815 816 817
}

static void vlv_enable_backlight(struct intel_connector *connector)
{
	struct drm_device *dev = connector->base.dev;
	struct drm_i915_private *dev_priv = dev->dev_private;
818
	struct intel_panel *panel = &connector->panel;
819
	enum pipe pipe = intel_get_pipe_from_connector(connector);
820
	u32 ctl, ctl2;
821

822 823 824 825 826 827
	ctl2 = I915_READ(VLV_BLC_PWM_CTL2(pipe));
	if (ctl2 & BLM_PWM_ENABLE) {
		WARN(1, "backlight already enabled\n");
		ctl2 &= ~BLM_PWM_ENABLE;
		I915_WRITE(VLV_BLC_PWM_CTL2(pipe), ctl2);
	}
828

829 830
	ctl = panel->backlight.max << 16;
	I915_WRITE(VLV_BLC_PWM_CTL(pipe), ctl);
831

832 833
	/* XXX: combine this into above write? */
	intel_panel_actually_set_backlight(connector, panel->backlight.level);
834

835 836 837 838
	ctl2 = 0;
	if (panel->backlight.active_low_pwm)
		ctl2 |= BLM_POLARITY_I965;
	I915_WRITE(VLV_BLC_PWM_CTL2(pipe), ctl2);
839
	POSTING_READ(VLV_BLC_PWM_CTL2(pipe));
840
	I915_WRITE(VLV_BLC_PWM_CTL2(pipe), ctl2 | BLM_PWM_ENABLE);
841 842
}

843
void intel_panel_enable_backlight(struct intel_connector *connector)
844
{
845
	struct drm_device *dev = connector->base.dev;
846
	struct drm_i915_private *dev_priv = dev->dev_private;
847
	struct intel_panel *panel = &connector->panel;
848
	enum pipe pipe = intel_get_pipe_from_connector(connector);
849 850
	unsigned long flags;

851
	if (!panel->backlight.present || pipe == INVALID_PIPE)
852 853
		return;

854
	DRM_DEBUG_KMS("pipe %c\n", pipe_name(pipe));
855

856
	spin_lock_irqsave(&dev_priv->backlight_lock, flags);
857

858 859
	WARN_ON(panel->backlight.max == 0);

860
	if (panel->backlight.level == 0) {
861
		panel->backlight.level = panel->backlight.max;
862 863 864
		if (panel->backlight.device)
			panel->backlight.device->props.brightness =
				panel->backlight.level;
865
	}
866

867
	dev_priv->display.enable_backlight(connector);
868
	panel->backlight.enabled = true;
869

870
	spin_unlock_irqrestore(&dev_priv->backlight_lock, flags);
871 872
}

873
#if IS_ENABLED(CONFIG_BACKLIGHT_CLASS_DEVICE)
874
static int intel_backlight_device_update_status(struct backlight_device *bd)
875
{
876 877 878
	struct intel_connector *connector = bl_get_data(bd);
	struct drm_device *dev = connector->base.dev;

879
	drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
880 881
	DRM_DEBUG_KMS("updating intel_backlight, brightness=%d/%d\n",
		      bd->props.brightness, bd->props.max_brightness);
882
	intel_panel_set_backlight(connector, bd->props.brightness,
883
				  bd->props.max_brightness);
884
	drm_modeset_unlock(&dev->mode_config.connection_mutex);
885 886 887
	return 0;
}

888
static int intel_backlight_device_get_brightness(struct backlight_device *bd)
889
{
890 891
	struct intel_connector *connector = bl_get_data(bd);
	struct drm_device *dev = connector->base.dev;
892
	struct drm_i915_private *dev_priv = dev->dev_private;
893
	int ret;
894

895
	intel_runtime_pm_get(dev_priv);
896
	drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
897
	ret = intel_panel_get_backlight(connector);
898
	drm_modeset_unlock(&dev->mode_config.connection_mutex);
899
	intel_runtime_pm_put(dev_priv);
900

901
	return ret;
902 903
}

904 905 906
static const struct backlight_ops intel_backlight_device_ops = {
	.update_status = intel_backlight_device_update_status,
	.get_brightness = intel_backlight_device_get_brightness,
907 908
};

909
static int intel_backlight_device_register(struct intel_connector *connector)
910
{
911
	struct intel_panel *panel = &connector->panel;
912 913
	struct backlight_properties props;

914
	if (WARN_ON(panel->backlight.device))
915 916
		return -ENODEV;

917 918
	BUG_ON(panel->backlight.max == 0);

919
	memset(&props, 0, sizeof(props));
920
	props.type = BACKLIGHT_RAW;
921
	props.brightness = panel->backlight.level;
922
	props.max_brightness = panel->backlight.max;
923 924 925 926 927 928

	/*
	 * Note: using the same name independent of the connector prevents
	 * registration of multiple backlight devices in the driver.
	 */
	panel->backlight.device =
929
		backlight_device_register("intel_backlight",
930 931 932
					  connector->base.kdev,
					  connector,
					  &intel_backlight_device_ops, &props);
933

934
	if (IS_ERR(panel->backlight.device)) {
935
		DRM_ERROR("Failed to register backlight: %ld\n",
936 937
			  PTR_ERR(panel->backlight.device));
		panel->backlight.device = NULL;
938 939 940 941 942
		return -ENODEV;
	}
	return 0;
}

943
static void intel_backlight_device_unregister(struct intel_connector *connector)
944
{
945 946 947 948 949
	struct intel_panel *panel = &connector->panel;

	if (panel->backlight.device) {
		backlight_device_unregister(panel->backlight.device);
		panel->backlight.device = NULL;
950
	}
951
}
952 953 954 955 956 957 958 959 960 961
#else /* CONFIG_BACKLIGHT_CLASS_DEVICE */
static int intel_backlight_device_register(struct intel_connector *connector)
{
	return 0;
}
static void intel_backlight_device_unregister(struct intel_connector *connector)
{
}
#endif /* CONFIG_BACKLIGHT_CLASS_DEVICE */

962 963 964 965 966 967
/*
 * Note: The setup hooks can't assume pipe is set!
 *
 * XXX: Query mode clock or hardware clock and program PWM modulation frequency
 * appropriately when it's 0. Use VBT and/or sane defaults.
 */
968
static int bdw_setup_backlight(struct intel_connector *connector)
969
{
970
	struct drm_device *dev = connector->base.dev;
971
	struct drm_i915_private *dev_priv = dev->dev_private;
972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991
	struct intel_panel *panel = &connector->panel;
	u32 pch_ctl1, pch_ctl2, val;

	pch_ctl1 = I915_READ(BLC_PWM_PCH_CTL1);
	panel->backlight.active_low_pwm = pch_ctl1 & BLM_PCH_POLARITY;

	pch_ctl2 = I915_READ(BLC_PWM_PCH_CTL2);
	panel->backlight.max = pch_ctl2 >> 16;
	if (!panel->backlight.max)
		return -ENODEV;

	val = bdw_get_backlight(connector);
	panel->backlight.level = intel_panel_compute_brightness(connector, val);

	panel->backlight.enabled = (pch_ctl1 & BLM_PCH_PWM_ENABLE) &&
		panel->backlight.level != 0;

	return 0;
}

992 993
static int pch_setup_backlight(struct intel_connector *connector)
{
994 995
	struct drm_device *dev = connector->base.dev;
	struct drm_i915_private *dev_priv = dev->dev_private;
996
	struct intel_panel *panel = &connector->panel;
997
	u32 cpu_ctl2, pch_ctl1, pch_ctl2, val;
998

999 1000 1001 1002 1003
	pch_ctl1 = I915_READ(BLC_PWM_PCH_CTL1);
	panel->backlight.active_low_pwm = pch_ctl1 & BLM_PCH_POLARITY;

	pch_ctl2 = I915_READ(BLC_PWM_PCH_CTL2);
	panel->backlight.max = pch_ctl2 >> 16;
1004 1005 1006 1007 1008 1009
	if (!panel->backlight.max)
		return -ENODEV;

	val = pch_get_backlight(connector);
	panel->backlight.level = intel_panel_compute_brightness(connector, val);

1010 1011 1012 1013
	cpu_ctl2 = I915_READ(BLC_PWM_CPU_CTL2);
	panel->backlight.enabled = (cpu_ctl2 & BLM_PWM_ENABLE) &&
		(pch_ctl1 & BLM_PCH_PWM_ENABLE) && panel->backlight.level != 0;

1014 1015 1016 1017 1018
	return 0;
}

static int i9xx_setup_backlight(struct intel_connector *connector)
{
1019 1020
	struct drm_device *dev = connector->base.dev;
	struct drm_i915_private *dev_priv = dev->dev_private;
1021
	struct intel_panel *panel = &connector->panel;
1022 1023 1024 1025
	u32 ctl, val;

	ctl = I915_READ(BLC_PWM_CTL);

1026
	if (IS_GEN2(dev) || IS_I915GM(dev) || IS_I945GM(dev))
1027 1028 1029 1030 1031 1032 1033 1034
		panel->backlight.combination_mode = ctl & BLM_LEGACY_MODE;

	if (IS_PINEVIEW(dev))
		panel->backlight.active_low_pwm = ctl & BLM_POLARITY_PNV;

	panel->backlight.max = ctl >> 17;
	if (panel->backlight.combination_mode)
		panel->backlight.max *= 0xff;
1035 1036 1037 1038 1039 1040 1041

	if (!panel->backlight.max)
		return -ENODEV;

	val = i9xx_get_backlight(connector);
	panel->backlight.level = intel_panel_compute_brightness(connector, val);

1042 1043
	panel->backlight.enabled = panel->backlight.level != 0;

1044 1045 1046 1047 1048
	return 0;
}

static int i965_setup_backlight(struct intel_connector *connector)
{
1049 1050
	struct drm_device *dev = connector->base.dev;
	struct drm_i915_private *dev_priv = dev->dev_private;
1051
	struct intel_panel *panel = &connector->panel;
1052 1053 1054 1055 1056 1057 1058 1059 1060 1061
	u32 ctl, ctl2, val;

	ctl2 = I915_READ(BLC_PWM_CTL2);
	panel->backlight.combination_mode = ctl2 & BLM_COMBINATION_MODE;
	panel->backlight.active_low_pwm = ctl2 & BLM_POLARITY_I965;

	ctl = I915_READ(BLC_PWM_CTL);
	panel->backlight.max = ctl >> 16;
	if (panel->backlight.combination_mode)
		panel->backlight.max *= 0xff;
1062 1063 1064 1065 1066 1067 1068

	if (!panel->backlight.max)
		return -ENODEV;

	val = i9xx_get_backlight(connector);
	panel->backlight.level = intel_panel_compute_brightness(connector, val);

1069 1070 1071
	panel->backlight.enabled = (ctl2 & BLM_PWM_ENABLE) &&
		panel->backlight.level != 0;

1072 1073 1074 1075 1076 1077 1078 1079 1080
	return 0;
}

static int vlv_setup_backlight(struct intel_connector *connector)
{
	struct drm_device *dev = connector->base.dev;
	struct drm_i915_private *dev_priv = dev->dev_private;
	struct intel_panel *panel = &connector->panel;
	enum pipe pipe;
1081
	u32 ctl, ctl2, val;
1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094

	for_each_pipe(pipe) {
		u32 cur_val = I915_READ(VLV_BLC_PWM_CTL(pipe));

		/* Skip if the modulation freq is already set */
		if (cur_val & ~BACKLIGHT_DUTY_CYCLE_MASK)
			continue;

		cur_val &= BACKLIGHT_DUTY_CYCLE_MASK;
		I915_WRITE(VLV_BLC_PWM_CTL(pipe), (0xf42 << 16) |
			   cur_val);
	}

1095 1096 1097 1098 1099
	ctl2 = I915_READ(VLV_BLC_PWM_CTL2(PIPE_A));
	panel->backlight.active_low_pwm = ctl2 & BLM_POLARITY_I965;

	ctl = I915_READ(VLV_BLC_PWM_CTL(PIPE_A));
	panel->backlight.max = ctl >> 16;
1100 1101 1102 1103 1104 1105
	if (!panel->backlight.max)
		return -ENODEV;

	val = _vlv_get_backlight(dev, PIPE_A);
	panel->backlight.level = intel_panel_compute_brightness(connector, val);

1106 1107 1108
	panel->backlight.enabled = (ctl2 & BLM_PWM_ENABLE) &&
		panel->backlight.level != 0;

1109 1110 1111
	return 0;
}

1112
int intel_panel_setup_backlight(struct drm_connector *connector)
1113
{
1114
	struct drm_device *dev = connector->dev;
1115
	struct drm_i915_private *dev_priv = dev->dev_private;
1116
	struct intel_connector *intel_connector = to_intel_connector(connector);
1117
	struct intel_panel *panel = &intel_connector->panel;
1118 1119
	unsigned long flags;
	int ret;
1120

1121 1122 1123 1124 1125
	if (!dev_priv->vbt.backlight.present) {
		DRM_DEBUG_KMS("native backlight control not available per VBT\n");
		return 0;
	}

1126 1127 1128 1129 1130 1131 1132
	/* set level and max in panel struct */
	spin_lock_irqsave(&dev_priv->backlight_lock, flags);
	ret = dev_priv->display.setup_backlight(intel_connector);
	spin_unlock_irqrestore(&dev_priv->backlight_lock, flags);

	if (ret) {
		DRM_DEBUG_KMS("failed to setup backlight for connector %s\n",
1133
			      connector->name);
1134 1135
		return ret;
	}
1136 1137 1138

	intel_backlight_device_register(intel_connector);

1139 1140
	panel->backlight.present = true;

1141 1142 1143 1144 1145 1146
	DRM_DEBUG_KMS("backlight initialized, %s, brightness %u/%u, "
		      "sysfs interface %sregistered\n",
		      panel->backlight.enabled ? "enabled" : "disabled",
		      panel->backlight.level, panel->backlight.max,
		      panel->backlight.device ? "" : "not ");

1147 1148 1149
	return 0;
}

1150
void intel_panel_destroy_backlight(struct drm_connector *connector)
1151
{
1152
	struct intel_connector *intel_connector = to_intel_connector(connector);
1153
	struct intel_panel *panel = &intel_connector->panel;
1154

1155
	panel->backlight.present = false;
1156
	intel_backlight_device_unregister(intel_connector);
1157
}
1158

1159 1160 1161 1162 1163
/* Set up chip specific backlight functions */
void intel_panel_init_backlight_funcs(struct drm_device *dev)
{
	struct drm_i915_private *dev_priv = dev->dev_private;

1164 1165 1166 1167 1168 1169 1170
	if (IS_BROADWELL(dev)) {
		dev_priv->display.setup_backlight = bdw_setup_backlight;
		dev_priv->display.enable_backlight = bdw_enable_backlight;
		dev_priv->display.disable_backlight = pch_disable_backlight;
		dev_priv->display.set_backlight = bdw_set_backlight;
		dev_priv->display.get_backlight = bdw_get_backlight;
	} else if (HAS_PCH_SPLIT(dev)) {
1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189
		dev_priv->display.setup_backlight = pch_setup_backlight;
		dev_priv->display.enable_backlight = pch_enable_backlight;
		dev_priv->display.disable_backlight = pch_disable_backlight;
		dev_priv->display.set_backlight = pch_set_backlight;
		dev_priv->display.get_backlight = pch_get_backlight;
	} else if (IS_VALLEYVIEW(dev)) {
		dev_priv->display.setup_backlight = vlv_setup_backlight;
		dev_priv->display.enable_backlight = vlv_enable_backlight;
		dev_priv->display.disable_backlight = vlv_disable_backlight;
		dev_priv->display.set_backlight = vlv_set_backlight;
		dev_priv->display.get_backlight = vlv_get_backlight;
	} else if (IS_GEN4(dev)) {
		dev_priv->display.setup_backlight = i965_setup_backlight;
		dev_priv->display.enable_backlight = i965_enable_backlight;
		dev_priv->display.disable_backlight = i965_disable_backlight;
		dev_priv->display.set_backlight = i9xx_set_backlight;
		dev_priv->display.get_backlight = i9xx_get_backlight;
	} else {
		dev_priv->display.setup_backlight = i9xx_setup_backlight;
1190 1191
		dev_priv->display.enable_backlight = i9xx_enable_backlight;
		dev_priv->display.disable_backlight = i9xx_disable_backlight;
1192 1193 1194 1195 1196
		dev_priv->display.set_backlight = i9xx_set_backlight;
		dev_priv->display.get_backlight = i9xx_get_backlight;
	}
}

1197
int intel_panel_init(struct intel_panel *panel,
1198 1199
		     struct drm_display_mode *fixed_mode,
		     struct drm_display_mode *downclock_mode)
1200
{
1201
	panel->fixed_mode = fixed_mode;
1202
	panel->downclock_mode = downclock_mode;
1203

1204 1205 1206 1207 1208
	return 0;
}

void intel_panel_fini(struct intel_panel *panel)
{
1209 1210 1211 1212 1213
	struct intel_connector *intel_connector =
		container_of(panel, struct intel_connector, panel);

	if (panel->fixed_mode)
		drm_mode_destroy(intel_connector->base.dev, panel->fixed_mode);
1214 1215 1216 1217

	if (panel->downclock_mode)
		drm_mode_destroy(intel_connector->base.dev,
				panel->downclock_mode);
1218
}