intel_panel.c 23.6 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
#include "intel_drv.h"

36 37
#define PCI_LBPC 0xf4 /* legacy/combination backlight modes */

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

	drm_mode_set_crtcinfo(adjusted_mode, 0);
45 46 47 48
}

/* adjusted_mode has been preset to be the panel's fixed mode */
void
49 50 51
intel_pch_panel_fitting(struct intel_crtc *intel_crtc,
			struct intel_crtc_config *pipe_config,
			int fitting_mode)
52
{
53
	struct drm_display_mode *adjusted_mode;
54 55
	int x, y, width, height;

56 57
	adjusted_mode = &pipe_config->adjusted_mode;

58 59 60
	x = y = width = height = 0;

	/* Native modes don't need fitting */
61 62
	if (adjusted_mode->hdisplay == pipe_config->pipe_src_w &&
	    adjusted_mode->vdisplay == pipe_config->pipe_src_h)
63 64 65 66
		goto done;

	switch (fitting_mode) {
	case DRM_MODE_SCALE_CENTER:
67 68
		width = pipe_config->pipe_src_w;
		height = pipe_config->pipe_src_h;
69 70 71 72 73 74 75
		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 */
		{
76 77 78 79
			u32 scaled_width = adjusted_mode->hdisplay
				* pipe_config->pipe_src_h;
			u32 scaled_height = pipe_config->pipe_src_w
				* adjusted_mode->vdisplay;
80
			if (scaled_width > scaled_height) { /* pillar */
81
				width = scaled_height / pipe_config->pipe_src_h;
82
				if (width & 1)
83
					width++;
84 85 86 87
				x = (adjusted_mode->hdisplay - width + 1) / 2;
				y = 0;
				height = adjusted_mode->vdisplay;
			} else if (scaled_width < scaled_height) { /* letter */
88
				height = scaled_width / pipe_config->pipe_src_w;
89 90
				if (height & 1)
				    height++;
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
				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;
107 108 109 110

	default:
		WARN(1, "bad panel fit mode: %d\n", fitting_mode);
		return;
111 112 113
	}

done:
114 115
	pipe_config->pch_pfit.pos = (x << 16) | y;
	pipe_config->pch_pfit.size = (width << 16) | height;
116
	pipe_config->pch_pfit.enabled = pipe_config->pch_pfit.size != 0;
117
}
118

119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
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;
}

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 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
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);
	}
}

252 253 254 255 256 257
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;
258
	struct drm_display_mode *adjusted_mode;
259 260 261 262

	adjusted_mode = &pipe_config->adjusted_mode;

	/* Native modes don't need fitting */
263 264
	if (adjusted_mode->hdisplay == pipe_config->pipe_src_w &&
	    adjusted_mode->vdisplay == pipe_config->pipe_src_h)
265 266 267 268 269 270 271 272
		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.
		 */
273 274
		centre_horizontally(adjusted_mode, pipe_config->pipe_src_w);
		centre_vertically(adjusted_mode, pipe_config->pipe_src_h);
275 276 277 278
		border = LVDS_BORDER_ENABLE;
		break;
	case DRM_MODE_SCALE_ASPECT:
		/* Scale but preserve the aspect ratio */
279 280 281 282 283
		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);
284 285 286 287 288 289
		break;
	case DRM_MODE_SCALE_FULLSCREEN:
		/*
		 * Full scaling, even if it changes the aspect ratio.
		 * Fortunately this is all done for us in hw.
		 */
290 291
		if (pipe_config->pipe_src_h != adjusted_mode->vdisplay ||
		    pipe_config->pipe_src_w != adjusted_mode->hdisplay) {
292 293 294 295 296 297 298 299 300 301
			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;
302 303 304
	default:
		WARN(1, "bad panel fit mode: %d\n", fitting_mode);
		return;
305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322
	}

	/* 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);

out:
	if ((pfit_control & PFIT_ENABLE) == 0) {
		pfit_control = 0;
		pfit_pgm_ratios = 0;
	}

	/* 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;

323 324
	pipe_config->gmch_pfit.control = pfit_control;
	pipe_config->gmch_pfit.pgm_ratios = pfit_pgm_ratios;
325
	pipe_config->gmch_pfit.lvds_border_bits = border;
326 327
}

328 329 330 331
static int is_backlight_combination_mode(struct drm_device *dev)
{
	struct drm_i915_private *dev_priv = dev->dev_private;

332
	if (IS_GEN4(dev))
333 334 335 336 337 338 339 340
		return I915_READ(BLC_PWM_CTL2) & BLM_COMBINATION_MODE;

	if (IS_GEN2(dev))
		return I915_READ(BLC_PWM_CTL) & BLM_LEGACY_MODE;

	return 0;
}

341 342 343
/* XXX: query mode clock or hardware clock and program max PWM appropriately
 * when it's 0.
 */
344
static u32 i915_read_blc_pwm_ctl(struct drm_device *dev, enum pipe pipe)
345
{
346
	struct drm_i915_private *dev_priv = dev->dev_private;
347 348
	u32 val;

349
	WARN_ON_SMP(!spin_is_locked(&dev_priv->backlight.lock));
350

351 352 353 354
	/* Restore the CTL value if it lost, e.g. GPU reset */

	if (HAS_PCH_SPLIT(dev_priv->dev)) {
		val = I915_READ(BLC_PWM_PCH_CTL2);
355 356
		if (dev_priv->regfile.saveBLC_PWM_CTL2 == 0) {
			dev_priv->regfile.saveBLC_PWM_CTL2 = val;
357
		} else if (val == 0) {
358
			val = dev_priv->regfile.saveBLC_PWM_CTL2;
359
			I915_WRITE(BLC_PWM_PCH_CTL2, val);
360
		}
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375
	} else if (IS_VALLEYVIEW(dev)) {
		val = I915_READ(VLV_BLC_PWM_CTL(pipe));
		if (dev_priv->regfile.saveBLC_PWM_CTL == 0) {
			dev_priv->regfile.saveBLC_PWM_CTL = val;
			dev_priv->regfile.saveBLC_PWM_CTL2 =
				I915_READ(VLV_BLC_PWM_CTL2(pipe));
		} else if (val == 0) {
			val = dev_priv->regfile.saveBLC_PWM_CTL;
			I915_WRITE(VLV_BLC_PWM_CTL(pipe), val);
			I915_WRITE(VLV_BLC_PWM_CTL2(pipe),
				   dev_priv->regfile.saveBLC_PWM_CTL2);
		}

		if (!val)
			val = 0x0f42ffff;
376 377
	} else {
		val = I915_READ(BLC_PWM_CTL);
378 379
		if (dev_priv->regfile.saveBLC_PWM_CTL == 0) {
			dev_priv->regfile.saveBLC_PWM_CTL = val;
380 381 382
			if (INTEL_INFO(dev)->gen >= 4)
				dev_priv->regfile.saveBLC_PWM_CTL2 =
					I915_READ(BLC_PWM_CTL2);
383
		} else if (val == 0) {
384
			val = dev_priv->regfile.saveBLC_PWM_CTL;
385 386 387 388
			I915_WRITE(BLC_PWM_CTL, val);
			if (INTEL_INFO(dev)->gen >= 4)
				I915_WRITE(BLC_PWM_CTL2,
					   dev_priv->regfile.saveBLC_PWM_CTL2);
389 390 391 392 393 394
		}
	}

	return val;
}

395 396
static u32 intel_panel_get_max_backlight(struct drm_device *dev,
					 enum pipe pipe)
397 398 399
{
	u32 max;

400
	max = i915_read_blc_pwm_ctl(dev, pipe);
401

402
	if (HAS_PCH_SPLIT(dev)) {
403
		max >>= 16;
404
	} else {
405
		if (INTEL_INFO(dev)->gen < 4)
406
			max >>= 17;
407
		else
408
			max >>= 16;
409 410 411

		if (is_backlight_combination_mode(dev))
			max *= 0xff;
412 413 414
	}

	DRM_DEBUG_DRIVER("max backlight PWM = %d\n", max);
415

416 417 418
	return max;
}

419 420 421
static int i915_panel_invert_brightness;
MODULE_PARM_DESC(invert_brightness, "Invert backlight brightness "
	"(-1 force normal, 0 machine defaults, 1 force inversion), please "
422 423 424
	"report PCI device ID, subsystem vendor and subsystem device ID "
	"to dri-devel@lists.freedesktop.org, if your machine needs it. "
	"It will then be included in an upcoming module version.");
425
module_param_named(invert_brightness, i915_panel_invert_brightness, int, 0600);
426 427
static u32 intel_panel_compute_brightness(struct drm_device *dev,
					  enum pipe pipe, u32 val)
428
{
429 430 431 432 433 434
	struct drm_i915_private *dev_priv = dev->dev_private;

	if (i915_panel_invert_brightness < 0)
		return val;

	if (i915_panel_invert_brightness > 0 ||
435
	    dev_priv->quirks & QUIRK_INVERT_BRIGHTNESS) {
436
		u32 max = intel_panel_get_max_backlight(dev, pipe);
437 438 439
		if (max)
			return max - val;
	}
440 441 442 443

	return val;
}

444 445
static u32 intel_panel_get_backlight(struct drm_device *dev,
				     enum pipe pipe)
446 447 448
{
	struct drm_i915_private *dev_priv = dev->dev_private;
	u32 val;
449
	unsigned long flags;
450
	int reg;
451 452

	spin_lock_irqsave(&dev_priv->backlight.lock, flags);
453 454 455 456

	if (HAS_PCH_SPLIT(dev)) {
		val = I915_READ(BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
	} else {
457 458 459 460 461 462
		if (IS_VALLEYVIEW(dev))
			reg = VLV_BLC_PWM_CTL(pipe);
		else
			reg = BLC_PWM_CTL;

		val = I915_READ(reg) & BACKLIGHT_DUTY_CYCLE_MASK;
463
		if (INTEL_INFO(dev)->gen < 4)
464
			val >>= 1;
465

466
		if (is_backlight_combination_mode(dev)) {
467 468 469 470 471
			u8 lbpc;

			pci_read_config_byte(dev->pdev, PCI_LBPC, &lbpc);
			val *= lbpc;
		}
472 473
	}

474
	val = intel_panel_compute_brightness(dev, pipe, val);
475 476 477

	spin_unlock_irqrestore(&dev_priv->backlight.lock, flags);

478 479 480 481 482 483 484 485 486 487 488
	DRM_DEBUG_DRIVER("get backlight PWM = %d\n", val);
	return val;
}

static void intel_pch_panel_set_backlight(struct drm_device *dev, u32 level)
{
	struct drm_i915_private *dev_priv = dev->dev_private;
	u32 val = I915_READ(BLC_PWM_CPU_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK;
	I915_WRITE(BLC_PWM_CPU_CTL, val | level);
}

489
static void intel_panel_actually_set_backlight(struct drm_device *dev,
490
					       enum pipe pipe, u32 level)
491 492 493
{
	struct drm_i915_private *dev_priv = dev->dev_private;
	u32 tmp;
494
	int reg;
495 496

	DRM_DEBUG_DRIVER("set backlight PWM = %d\n", level);
497
	level = intel_panel_compute_brightness(dev, pipe, level);
498 499 500

	if (HAS_PCH_SPLIT(dev))
		return intel_pch_panel_set_backlight(dev, level);
501

502
	if (is_backlight_combination_mode(dev)) {
503
		u32 max = intel_panel_get_max_backlight(dev, pipe);
504 505
		u8 lbpc;

506 507 508 509
		/* we're screwed, but keep behaviour backwards compatible */
		if (!max)
			max = 1;

510 511 512 513 514
		lbpc = level * 0xfe / max + 1;
		level /= lbpc;
		pci_write_config_byte(dev->pdev, PCI_LBPC, lbpc);
	}

515 516 517 518 519 520
	if (IS_VALLEYVIEW(dev))
		reg = VLV_BLC_PWM_CTL(pipe);
	else
		reg = BLC_PWM_CTL;

	tmp = I915_READ(reg);
521
	if (INTEL_INFO(dev)->gen < 4)
522
		level <<= 1;
523
	tmp &= ~BACKLIGHT_DUTY_CYCLE_MASK;
524
	I915_WRITE(reg, tmp | level);
525
}
526

527
/* set backlight brightness to level in range [0..max] */
528 529
void intel_panel_set_backlight(struct intel_connector *connector, u32 level,
			       u32 max)
530
{
531
	struct drm_device *dev = connector->base.dev;
532
	struct drm_i915_private *dev_priv = dev->dev_private;
533
	enum pipe pipe = intel_get_pipe_from_connector(connector);
534
	u32 freq;
535 536
	unsigned long flags;

537 538 539
	if (pipe == INVALID_PIPE)
		return;

540
	spin_lock_irqsave(&dev_priv->backlight.lock, flags);
541

542
	freq = intel_panel_get_max_backlight(dev, pipe);
543 544
	if (!freq) {
		/* we are screwed, bail out */
545
		goto out;
546 547
	}

548 549 550 551 552
	/* scale to hardware, but be careful to not overflow */
	if (freq < max)
		level = level * freq / max;
	else
		level = freq / max * level;
553

554 555 556
	dev_priv->backlight.level = level;
	if (dev_priv->backlight.device)
		dev_priv->backlight.device->props.brightness = level;
557

558
	if (dev_priv->backlight.enabled)
559
		intel_panel_actually_set_backlight(dev, pipe, level);
560 561
out:
	spin_unlock_irqrestore(&dev_priv->backlight.lock, flags);
562 563
}

564
void intel_panel_disable_backlight(struct intel_connector *connector)
565
{
566
	struct drm_device *dev = connector->base.dev;
567
	struct drm_i915_private *dev_priv = dev->dev_private;
568
	enum pipe pipe = intel_get_pipe_from_connector(connector);
569 570
	unsigned long flags;

571 572 573
	if (pipe == INVALID_PIPE)
		return;

574 575 576 577 578 579 580 581 582 583 584
	/*
	 * 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;
	}

585
	spin_lock_irqsave(&dev_priv->backlight.lock, flags);
586

587
	dev_priv->backlight.enabled = false;
588
	intel_panel_actually_set_backlight(dev, pipe, 0);
589 590

	if (INTEL_INFO(dev)->gen >= 4) {
591
		uint32_t reg, tmp;
592

593 594 595 596 597 598
		if (HAS_PCH_SPLIT(dev))
			reg = BLC_PWM_CPU_CTL2;
		else if (IS_VALLEYVIEW(dev))
			reg = VLV_BLC_PWM_CTL2(pipe);
		else
			reg = BLC_PWM_CTL2;
599 600

		I915_WRITE(reg, I915_READ(reg) & ~BLM_PWM_ENABLE);
601 602 603 604 605 606

		if (HAS_PCH_SPLIT(dev)) {
			tmp = I915_READ(BLC_PWM_PCH_CTL1);
			tmp &= ~BLM_PCH_PWM_ENABLE;
			I915_WRITE(BLC_PWM_PCH_CTL1, tmp);
		}
607
	}
608 609

	spin_unlock_irqrestore(&dev_priv->backlight.lock, flags);
610 611
}

612
void intel_panel_enable_backlight(struct intel_connector *connector)
613
{
614
	struct drm_device *dev = connector->base.dev;
615
	struct drm_i915_private *dev_priv = dev->dev_private;
616
	enum pipe pipe = intel_get_pipe_from_connector(connector);
617 618
	enum transcoder cpu_transcoder =
		intel_pipe_to_cpu_transcoder(dev_priv, pipe);
619 620
	unsigned long flags;

621 622 623
	if (pipe == INVALID_PIPE)
		return;

624
	DRM_DEBUG_KMS("pipe %c\n", pipe_name(pipe));
625

626
	spin_lock_irqsave(&dev_priv->backlight.lock, flags);
627

628
	if (dev_priv->backlight.level == 0) {
629 630
		dev_priv->backlight.level = intel_panel_get_max_backlight(dev,
									  pipe);
631 632 633
		if (dev_priv->backlight.device)
			dev_priv->backlight.device->props.brightness =
				dev_priv->backlight.level;
634
	}
635

636 637 638
	if (INTEL_INFO(dev)->gen >= 4) {
		uint32_t reg, tmp;

639 640 641 642 643 644
		if (HAS_PCH_SPLIT(dev))
			reg = BLC_PWM_CPU_CTL2;
		else if (IS_VALLEYVIEW(dev))
			reg = VLV_BLC_PWM_CTL2(pipe);
		else
			reg = BLC_PWM_CTL2;
645 646 647 648 649 650 651

		tmp = I915_READ(reg);

		/* Note that this can also get called through dpms changes. And
		 * we don't track the backlight dpms state, hence check whether
		 * we have to do anything first. */
		if (tmp & BLM_PWM_ENABLE)
652
			goto set_level;
653

654
		if (INTEL_INFO(dev)->num_pipes == 3)
655 656 657 658
			tmp &= ~BLM_PIPE_SELECT_IVB;
		else
			tmp &= ~BLM_PIPE_SELECT;

659 660 661 662
		if (cpu_transcoder == TRANSCODER_EDP)
			tmp |= BLM_TRANSCODER_EDP;
		else
			tmp |= BLM_PIPE(cpu_transcoder);
663 664 665 666 667
		tmp &= ~BLM_PWM_ENABLE;

		I915_WRITE(reg, tmp);
		POSTING_READ(reg);
		I915_WRITE(reg, tmp | BLM_PWM_ENABLE);
668

669 670
		if (HAS_PCH_SPLIT(dev) &&
		    !(dev_priv->quirks & QUIRK_NO_PCH_PWM_ENABLE)) {
671 672 673 674 675
			tmp = I915_READ(BLC_PWM_PCH_CTL1);
			tmp |= BLM_PCH_PWM_ENABLE;
			tmp &= ~BLM_PCH_OVERRIDE_ENABLE;
			I915_WRITE(BLC_PWM_PCH_CTL1, tmp);
		}
676
	}
677 678

set_level:
679 680 681
	/* Call below after setting BLC_PWM_CPU_CTL2 and BLC_PWM_PCH_CTL1.
	 * BLC_PWM_CPU_CTL may be cleared to zero automatically when these
	 * registers are set.
682
	 */
683
	dev_priv->backlight.enabled = true;
684 685
	intel_panel_actually_set_backlight(dev, pipe,
					   dev_priv->backlight.level);
686 687

	spin_unlock_irqrestore(&dev_priv->backlight.lock, flags);
688 689
}

690 691 692 693 694 695
/* FIXME: use VBT vals to init PWM_CTL and PWM_CTL2 correctly */
static void intel_panel_init_backlight_regs(struct drm_device *dev)
{
	struct drm_i915_private *dev_priv = dev->dev_private;

	if (IS_VALLEYVIEW(dev)) {
696 697 698 699 700 701 702 703 704 705 706 707 708
		enum pipe pipe;

		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);
		}
709 710 711
	}
}

712
static void intel_panel_init_backlight(struct drm_device *dev)
713 714 715
{
	struct drm_i915_private *dev_priv = dev->dev_private;

716 717
	intel_panel_init_backlight_regs(dev);

718
	dev_priv->backlight.level = intel_panel_get_backlight(dev, 0);
719
	dev_priv->backlight.enabled = dev_priv->backlight.level != 0;
720
}
721 722 723 724 725 726 727

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... */
728
	if (!i915_panel_ignore_lid && dev_priv->opregion.lid_state) {
729 730 731
		return ioread32(dev_priv->opregion.lid_state) & 0x1 ?
			connector_status_connected :
			connector_status_disconnected;
732
	}
733

734 735 736 737 738 739 740 741
	switch (i915_panel_ignore_lid) {
	case -2:
		return connector_status_connected;
	case -1:
		return connector_status_disconnected;
	default:
		return connector_status_unknown;
	}
742
}
743

744
#if IS_ENABLED(CONFIG_BACKLIGHT_CLASS_DEVICE)
745 746
static int intel_panel_update_status(struct backlight_device *bd)
{
747 748 749 750
	struct intel_connector *connector = bl_get_data(bd);
	struct drm_device *dev = connector->base.dev;

	mutex_lock(&dev->mode_config.mutex);
751 752
	DRM_DEBUG_KMS("updating intel_backlight, brightness=%d/%d\n",
		      bd->props.brightness, bd->props.max_brightness);
753
	intel_panel_set_backlight(connector, bd->props.brightness,
754
				  bd->props.max_brightness);
755
	mutex_unlock(&dev->mode_config.mutex);
756 757 758 759 760
	return 0;
}

static int intel_panel_get_brightness(struct backlight_device *bd)
{
761 762 763 764 765 766 767 768 769 770 771
	struct intel_connector *connector = bl_get_data(bd);
	struct drm_device *dev = connector->base.dev;
	enum pipe pipe;

	mutex_lock(&dev->mode_config.mutex);
	pipe = intel_get_pipe_from_connector(connector);
	mutex_unlock(&dev->mode_config.mutex);
	if (pipe == INVALID_PIPE)
		return 0;

	return intel_panel_get_backlight(connector->base.dev, pipe);
772 773 774 775 776 777 778
}

static const struct backlight_ops intel_panel_bl_ops = {
	.update_status = intel_panel_update_status,
	.get_brightness = intel_panel_get_brightness,
};

779
int intel_panel_setup_backlight(struct drm_connector *connector)
780
{
781
	struct drm_device *dev = connector->dev;
782 783
	struct drm_i915_private *dev_priv = dev->dev_private;
	struct backlight_properties props;
784
	unsigned long flags;
785 786 787

	intel_panel_init_backlight(dev);

788 789 790
	if (WARN_ON(dev_priv->backlight.device))
		return -ENODEV;

791
	memset(&props, 0, sizeof(props));
792
	props.type = BACKLIGHT_RAW;
793
	props.brightness = dev_priv->backlight.level;
794 795

	spin_lock_irqsave(&dev_priv->backlight.lock, flags);
796
	props.max_brightness = intel_panel_get_max_backlight(dev, 0);
797 798
	spin_unlock_irqrestore(&dev_priv->backlight.lock, flags);

799
	if (props.max_brightness == 0) {
800
		DRM_DEBUG_DRIVER("Failed to get maximum backlight value\n");
801 802
		return -ENODEV;
	}
803
	dev_priv->backlight.device =
804
		backlight_device_register("intel_backlight",
805
					  connector->kdev,
806
					  to_intel_connector(connector),
807 808
					  &intel_panel_bl_ops, &props);

809
	if (IS_ERR(dev_priv->backlight.device)) {
810
		DRM_ERROR("Failed to register backlight: %ld\n",
811 812
			  PTR_ERR(dev_priv->backlight.device));
		dev_priv->backlight.device = NULL;
813 814 815 816 817 818 819 820
		return -ENODEV;
	}
	return 0;
}

void intel_panel_destroy_backlight(struct drm_device *dev)
{
	struct drm_i915_private *dev_priv = dev->dev_private;
821
	if (dev_priv->backlight.device) {
822
		backlight_device_unregister(dev_priv->backlight.device);
823 824
		dev_priv->backlight.device = NULL;
	}
825 826
}
#else
827
int intel_panel_setup_backlight(struct drm_connector *connector)
828
{
829
	intel_panel_init_backlight(connector->dev);
830 831 832 833 834 835 836 837
	return 0;
}

void intel_panel_destroy_backlight(struct drm_device *dev)
{
	return;
}
#endif
838

839 840
int intel_panel_init(struct intel_panel *panel,
		     struct drm_display_mode *fixed_mode)
841
{
842 843
	panel->fixed_mode = fixed_mode;

844 845 846 847 848
	return 0;
}

void intel_panel_fini(struct intel_panel *panel)
{
849 850 851 852 853
	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);
854
}