xref: /dragonfly/sys/dev/drm/i915/intel_panel.c (revision e97a1dae)
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/moduleparam.h>
32 #include "intel_drv.h"
33 
34 #define PCI_LBPC 0xf4 /* legacy/combination backlight modes */
35 
36 void
37 intel_fixed_panel_mode(struct drm_display_mode *fixed_mode,
38 		       struct drm_display_mode *adjusted_mode)
39 {
40 	adjusted_mode->hdisplay = fixed_mode->hdisplay;
41 	adjusted_mode->hsync_start = fixed_mode->hsync_start;
42 	adjusted_mode->hsync_end = fixed_mode->hsync_end;
43 	adjusted_mode->htotal = fixed_mode->htotal;
44 
45 	adjusted_mode->vdisplay = fixed_mode->vdisplay;
46 	adjusted_mode->vsync_start = fixed_mode->vsync_start;
47 	adjusted_mode->vsync_end = fixed_mode->vsync_end;
48 	adjusted_mode->vtotal = fixed_mode->vtotal;
49 
50 	adjusted_mode->clock = fixed_mode->clock;
51 }
52 
53 /* adjusted_mode has been preset to be the panel's fixed mode */
54 void
55 intel_pch_panel_fitting(struct intel_crtc *intel_crtc,
56 			struct intel_crtc_config *pipe_config,
57 			int fitting_mode)
58 {
59 	struct drm_display_mode *mode, *adjusted_mode;
60 	int x, y, width, height;
61 
62 	mode = &pipe_config->requested_mode;
63 	adjusted_mode = &pipe_config->adjusted_mode;
64 
65 	x = y = width = height = 0;
66 
67 	/* Native modes don't need fitting */
68 	if (adjusted_mode->hdisplay == mode->hdisplay &&
69 	    adjusted_mode->vdisplay == mode->vdisplay)
70 		goto done;
71 
72 	switch (fitting_mode) {
73 	case DRM_MODE_SCALE_CENTER:
74 		width = mode->hdisplay;
75 		height = mode->vdisplay;
76 		x = (adjusted_mode->hdisplay - width + 1)/2;
77 		y = (adjusted_mode->vdisplay - height + 1)/2;
78 		break;
79 
80 	case DRM_MODE_SCALE_ASPECT:
81 		/* Scale but preserve the aspect ratio */
82 		{
83 			u32 scaled_width = adjusted_mode->hdisplay * mode->vdisplay;
84 			u32 scaled_height = mode->hdisplay * adjusted_mode->vdisplay;
85 			if (scaled_width > scaled_height) { /* pillar */
86 				width = scaled_height / mode->vdisplay;
87 				if (width & 1)
88 					width++;
89 				x = (adjusted_mode->hdisplay - width + 1) / 2;
90 				y = 0;
91 				height = adjusted_mode->vdisplay;
92 			} else if (scaled_width < scaled_height) { /* letter */
93 				height = scaled_width / mode->hdisplay;
94 				if (height & 1)
95 				    height++;
96 				y = (adjusted_mode->vdisplay - height + 1) / 2;
97 				x = 0;
98 				width = adjusted_mode->hdisplay;
99 			} else {
100 				x = y = 0;
101 				width = adjusted_mode->hdisplay;
102 				height = adjusted_mode->vdisplay;
103 			}
104 		}
105 		break;
106 
107 	case DRM_MODE_SCALE_FULLSCREEN:
108 		x = y = 0;
109 		width = adjusted_mode->hdisplay;
110 		height = adjusted_mode->vdisplay;
111 		break;
112 
113 	default:
114 		WARN(1, "bad panel fit mode: %d\n", fitting_mode);
115 		return;
116 	}
117 
118 done:
119 	pipe_config->pch_pfit.pos = (x << 16) | y;
120 	pipe_config->pch_pfit.size = (width << 16) | height;
121 }
122 
123 static void
124 centre_horizontally(struct drm_display_mode *mode,
125 		    int width)
126 {
127 	u32 border, sync_pos, blank_width, sync_width;
128 
129 	/* keep the hsync and hblank widths constant */
130 	sync_width = mode->crtc_hsync_end - mode->crtc_hsync_start;
131 	blank_width = mode->crtc_hblank_end - mode->crtc_hblank_start;
132 	sync_pos = (blank_width - sync_width + 1) / 2;
133 
134 	border = (mode->hdisplay - width + 1) / 2;
135 	border += border & 1; /* make the border even */
136 
137 	mode->crtc_hdisplay = width;
138 	mode->crtc_hblank_start = width + border;
139 	mode->crtc_hblank_end = mode->crtc_hblank_start + blank_width;
140 
141 	mode->crtc_hsync_start = mode->crtc_hblank_start + sync_pos;
142 	mode->crtc_hsync_end = mode->crtc_hsync_start + sync_width;
143 }
144 
145 static void
146 centre_vertically(struct drm_display_mode *mode,
147 		  int height)
148 {
149 	u32 border, sync_pos, blank_width, sync_width;
150 
151 	/* keep the vsync and vblank widths constant */
152 	sync_width = mode->crtc_vsync_end - mode->crtc_vsync_start;
153 	blank_width = mode->crtc_vblank_end - mode->crtc_vblank_start;
154 	sync_pos = (blank_width - sync_width + 1) / 2;
155 
156 	border = (mode->vdisplay - height + 1) / 2;
157 
158 	mode->crtc_vdisplay = height;
159 	mode->crtc_vblank_start = height + border;
160 	mode->crtc_vblank_end = mode->crtc_vblank_start + blank_width;
161 
162 	mode->crtc_vsync_start = mode->crtc_vblank_start + sync_pos;
163 	mode->crtc_vsync_end = mode->crtc_vsync_start + sync_width;
164 }
165 
166 static inline u32 panel_fitter_scaling(u32 source, u32 target)
167 {
168 	/*
169 	 * Floating point operation is not supported. So the FACTOR
170 	 * is defined, which can avoid the floating point computation
171 	 * when calculating the panel ratio.
172 	 */
173 #define ACCURACY 12
174 #define FACTOR (1 << ACCURACY)
175 	u32 ratio = source * FACTOR / target;
176 	return (FACTOR * ratio + FACTOR/2) / FACTOR;
177 }
178 
179 void intel_gmch_panel_fitting(struct intel_crtc *intel_crtc,
180 			      struct intel_crtc_config *pipe_config,
181 			      int fitting_mode)
182 {
183 	struct drm_device *dev = intel_crtc->base.dev;
184 	u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0;
185 	struct drm_display_mode *mode, *adjusted_mode;
186 
187 	mode = &pipe_config->requested_mode;
188 	adjusted_mode = &pipe_config->adjusted_mode;
189 
190 	/* Native modes don't need fitting */
191 	if (adjusted_mode->hdisplay == mode->hdisplay &&
192 	    adjusted_mode->vdisplay == mode->vdisplay)
193 		goto out;
194 
195 	drm_mode_set_crtcinfo(adjusted_mode, 0);
196 	pipe_config->timings_set = true;
197 
198 	switch (fitting_mode) {
199 	case DRM_MODE_SCALE_CENTER:
200 		/*
201 		 * For centered modes, we have to calculate border widths &
202 		 * heights and modify the values programmed into the CRTC.
203 		 */
204 		centre_horizontally(adjusted_mode, mode->hdisplay);
205 		centre_vertically(adjusted_mode, mode->vdisplay);
206 		border = LVDS_BORDER_ENABLE;
207 		break;
208 	case DRM_MODE_SCALE_ASPECT:
209 		/* Scale but preserve the aspect ratio */
210 		if (INTEL_INFO(dev)->gen >= 4) {
211 			u32 scaled_width = adjusted_mode->hdisplay *
212 				mode->vdisplay;
213 			u32 scaled_height = mode->hdisplay *
214 				adjusted_mode->vdisplay;
215 
216 			/* 965+ is easy, it does everything in hw */
217 			if (scaled_width > scaled_height)
218 				pfit_control |= PFIT_ENABLE |
219 					PFIT_SCALING_PILLAR;
220 			else if (scaled_width < scaled_height)
221 				pfit_control |= PFIT_ENABLE |
222 					PFIT_SCALING_LETTER;
223 			else if (adjusted_mode->hdisplay != mode->hdisplay)
224 				pfit_control |= PFIT_ENABLE | PFIT_SCALING_AUTO;
225 		} else {
226 			u32 scaled_width = adjusted_mode->hdisplay *
227 				mode->vdisplay;
228 			u32 scaled_height = mode->hdisplay *
229 				adjusted_mode->vdisplay;
230 			/*
231 			 * For earlier chips we have to calculate the scaling
232 			 * ratio by hand and program it into the
233 			 * PFIT_PGM_RATIO register
234 			 */
235 			if (scaled_width > scaled_height) { /* pillar */
236 				centre_horizontally(adjusted_mode,
237 						    scaled_height /
238 						    mode->vdisplay);
239 
240 				border = LVDS_BORDER_ENABLE;
241 				if (mode->vdisplay != adjusted_mode->vdisplay) {
242 					u32 bits = panel_fitter_scaling(mode->vdisplay, adjusted_mode->vdisplay);
243 					pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT |
244 							    bits << PFIT_VERT_SCALE_SHIFT);
245 					pfit_control |= (PFIT_ENABLE |
246 							 VERT_INTERP_BILINEAR |
247 							 HORIZ_INTERP_BILINEAR);
248 				}
249 			} else if (scaled_width < scaled_height) { /* letter */
250 				centre_vertically(adjusted_mode,
251 						  scaled_width /
252 						  mode->hdisplay);
253 
254 				border = LVDS_BORDER_ENABLE;
255 				if (mode->hdisplay != adjusted_mode->hdisplay) {
256 					u32 bits = panel_fitter_scaling(mode->hdisplay, adjusted_mode->hdisplay);
257 					pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT |
258 							    bits << PFIT_VERT_SCALE_SHIFT);
259 					pfit_control |= (PFIT_ENABLE |
260 							 VERT_INTERP_BILINEAR |
261 							 HORIZ_INTERP_BILINEAR);
262 				}
263 			} else {
264 				/* Aspects match, Let hw scale both directions */
265 				pfit_control |= (PFIT_ENABLE |
266 						 VERT_AUTO_SCALE | HORIZ_AUTO_SCALE |
267 						 VERT_INTERP_BILINEAR |
268 						 HORIZ_INTERP_BILINEAR);
269 			}
270 		}
271 		break;
272 	case DRM_MODE_SCALE_FULLSCREEN:
273 		/*
274 		 * Full scaling, even if it changes the aspect ratio.
275 		 * Fortunately this is all done for us in hw.
276 		 */
277 		if (mode->vdisplay != adjusted_mode->vdisplay ||
278 		    mode->hdisplay != adjusted_mode->hdisplay) {
279 			pfit_control |= PFIT_ENABLE;
280 			if (INTEL_INFO(dev)->gen >= 4)
281 				pfit_control |= PFIT_SCALING_AUTO;
282 			else
283 				pfit_control |= (VERT_AUTO_SCALE |
284 						 VERT_INTERP_BILINEAR |
285 						 HORIZ_AUTO_SCALE |
286 						 HORIZ_INTERP_BILINEAR);
287 		}
288 		break;
289 	default:
290 		WARN(1, "bad panel fit mode: %d\n", fitting_mode);
291 		return;
292 	}
293 
294 	/* 965+ wants fuzzy fitting */
295 	/* FIXME: handle multiple panels by failing gracefully */
296 	if (INTEL_INFO(dev)->gen >= 4)
297 		pfit_control |= ((intel_crtc->pipe << PFIT_PIPE_SHIFT) |
298 				 PFIT_FILTER_FUZZY);
299 
300 out:
301 	if ((pfit_control & PFIT_ENABLE) == 0) {
302 		pfit_control = 0;
303 		pfit_pgm_ratios = 0;
304 	}
305 
306 	/* Make sure pre-965 set dither correctly for 18bpp panels. */
307 	if (INTEL_INFO(dev)->gen < 4 && pipe_config->pipe_bpp == 18)
308 		pfit_control |= PANEL_8TO6_DITHER_ENABLE;
309 
310 	pipe_config->gmch_pfit.control = pfit_control;
311 	pipe_config->gmch_pfit.pgm_ratios = pfit_pgm_ratios;
312 	pipe_config->gmch_pfit.lvds_border_bits = border;
313 }
314 
315 static int is_backlight_combination_mode(struct drm_device *dev)
316 {
317 	struct drm_i915_private *dev_priv = dev->dev_private;
318 
319 	if (INTEL_INFO(dev)->gen >= 4)
320 		return I915_READ(BLC_PWM_CTL2) & BLM_COMBINATION_MODE;
321 
322 	if (IS_GEN2(dev))
323 		return I915_READ(BLC_PWM_CTL) & BLM_LEGACY_MODE;
324 
325 	return 0;
326 }
327 
328 /* XXX: query mode clock or hardware clock and program max PWM appropriately
329  * when it's 0.
330  */
331 static u32 i915_read_blc_pwm_ctl(struct drm_device *dev)
332 {
333 	struct drm_i915_private *dev_priv = dev->dev_private;
334 	u32 val;
335 
336 	WARN_ON_SMP(!spin_is_locked(&dev_priv->backlight.lock));
337 
338 	/* Restore the CTL value if it lost, e.g. GPU reset */
339 
340 	if (HAS_PCH_SPLIT(dev_priv->dev)) {
341 		val = I915_READ(BLC_PWM_PCH_CTL2);
342 		if (dev_priv->regfile.saveBLC_PWM_CTL2 == 0) {
343 			dev_priv->regfile.saveBLC_PWM_CTL2 = val;
344 		} else if (val == 0) {
345 			val = dev_priv->regfile.saveBLC_PWM_CTL2;
346 			I915_WRITE(BLC_PWM_PCH_CTL2, val);
347 		}
348 	} else {
349 		val = I915_READ(BLC_PWM_CTL);
350 		if (dev_priv->regfile.saveBLC_PWM_CTL == 0) {
351 			dev_priv->regfile.saveBLC_PWM_CTL = val;
352 			if (INTEL_INFO(dev)->gen >= 4)
353 				dev_priv->regfile.saveBLC_PWM_CTL2 =
354 					I915_READ(BLC_PWM_CTL2);
355 		} else if (val == 0) {
356 			val = dev_priv->regfile.saveBLC_PWM_CTL;
357 			I915_WRITE(BLC_PWM_CTL, val);
358 			if (INTEL_INFO(dev)->gen >= 4)
359 				I915_WRITE(BLC_PWM_CTL2,
360 					   dev_priv->regfile.saveBLC_PWM_CTL2);
361 		}
362 	}
363 
364 	return val;
365 }
366 
367 static u32 intel_panel_get_max_backlight(struct drm_device *dev)
368 {
369 	u32 max;
370 
371 	max = i915_read_blc_pwm_ctl(dev);
372 
373 	if (HAS_PCH_SPLIT(dev)) {
374 		max >>= 16;
375 	} else {
376 		if (INTEL_INFO(dev)->gen < 4)
377 			max >>= 17;
378 		else
379 			max >>= 16;
380 
381 		if (is_backlight_combination_mode(dev))
382 			max *= 0xff;
383 	}
384 
385 	DRM_DEBUG_DRIVER("max backlight PWM = %d\n", max);
386 
387 	return max;
388 }
389 
390 static int i915_panel_invert_brightness;
391 TUNABLE_INT("drm.i915.panel_invert_brightness", &i915_panel_invert_brightness);
392 MODULE_PARM_DESC(invert_brightness, "Invert backlight brightness "
393 	"(-1 force normal, 0 machine defaults, 1 force inversion), please "
394 	"report PCI device ID, subsystem vendor and subsystem device ID "
395 	"to dri-devel@lists.freedesktop.org, if your machine needs it. "
396 	"It will then be included in an upcoming module version.");
397 module_param_named(invert_brightness, i915_panel_invert_brightness, int, 0600);
398 static u32 intel_panel_compute_brightness(struct drm_device *dev, u32 val)
399 {
400 	struct drm_i915_private *dev_priv = dev->dev_private;
401 
402 	if (i915_panel_invert_brightness < 0)
403 		return val;
404 
405 	if (i915_panel_invert_brightness > 0 ||
406 	    dev_priv->quirks & QUIRK_INVERT_BRIGHTNESS) {
407 		u32 max = intel_panel_get_max_backlight(dev);
408 		if (max)
409 			return max - val;
410 	}
411 
412 	return val;
413 }
414 
415 static u32 intel_panel_get_backlight(struct drm_device *dev)
416 {
417 	struct drm_i915_private *dev_priv = dev->dev_private;
418 	u32 val;
419 
420 	spin_lock(&dev_priv->backlight.lock);
421 
422 	if (HAS_PCH_SPLIT(dev)) {
423 		val = I915_READ(BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
424 	} else {
425 		val = I915_READ(BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
426 		if (INTEL_INFO(dev)->gen < 4)
427 			val >>= 1;
428 
429 		if (is_backlight_combination_mode(dev)) {
430 			u8 lbpc;
431 
432 			pci_read_config_byte(dev->pdev, PCI_LBPC, &lbpc);
433 			val *= lbpc;
434 		}
435 	}
436 
437 	val = intel_panel_compute_brightness(dev, val);
438 
439 	spin_unlock(&dev_priv->backlight.lock);
440 
441 	DRM_DEBUG_DRIVER("get backlight PWM = %d\n", val);
442 	return val;
443 }
444 
445 static void intel_pch_panel_set_backlight(struct drm_device *dev, u32 level)
446 {
447 	struct drm_i915_private *dev_priv = dev->dev_private;
448 	u32 val = I915_READ(BLC_PWM_CPU_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK;
449 	I915_WRITE(BLC_PWM_CPU_CTL, val | level);
450 }
451 
452 static void intel_panel_actually_set_backlight(struct drm_device *dev, u32 level)
453 {
454 	struct drm_i915_private *dev_priv = dev->dev_private;
455 	u32 tmp;
456 
457 	DRM_DEBUG_DRIVER("set backlight PWM = %d\n", level);
458 	level = intel_panel_compute_brightness(dev, level);
459 
460 	if (HAS_PCH_SPLIT(dev))
461 		return intel_pch_panel_set_backlight(dev, level);
462 
463 	if (is_backlight_combination_mode(dev)) {
464 		u32 max = intel_panel_get_max_backlight(dev);
465 		u8 lbpc;
466 
467 		/* we're screwed, but keep behaviour backwards compatible */
468 		if (!max)
469 			max = 1;
470 
471 		lbpc = level * 0xfe / max + 1;
472 		level /= lbpc;
473 		pci_write_config_byte(dev->pdev, PCI_LBPC, lbpc);
474 	}
475 
476 	tmp = I915_READ(BLC_PWM_CTL);
477 	if (INTEL_INFO(dev)->gen < 4)
478 		level <<= 1;
479 	tmp &= ~BACKLIGHT_DUTY_CYCLE_MASK;
480 	I915_WRITE(BLC_PWM_CTL, tmp | level);
481 }
482 
483 /* set backlight brightness to level in range [0..max] */
484 void intel_panel_set_backlight(struct drm_device *dev, u32 level, u32 max)
485 {
486 	struct drm_i915_private *dev_priv = dev->dev_private;
487 	u32 freq;
488 
489 	spin_lock(&dev_priv->backlight.lock);
490 
491 	freq = intel_panel_get_max_backlight(dev);
492 	if (!freq) {
493 		/* we are screwed, bail out */
494 		goto out;
495 	}
496 
497 	/* scale to hardware, but be careful to not overflow */
498 	if (freq < max)
499 		level = level * freq / max;
500 	else
501 		level = freq / max * level;
502 
503 	dev_priv->backlight.level = level;
504 	if (dev_priv->backlight.device)
505 		dev_priv->backlight.device->props.brightness = level;
506 
507 	if (dev_priv->backlight.enabled)
508 		intel_panel_actually_set_backlight(dev, level);
509 out:
510 	spin_unlock(&dev_priv->backlight.lock);
511 }
512 
513 void intel_panel_disable_backlight(struct drm_device *dev)
514 {
515 	struct drm_i915_private *dev_priv = dev->dev_private;
516 
517 	spin_lock(&dev_priv->backlight.lock);
518 
519 	dev_priv->backlight.enabled = false;
520 	intel_panel_actually_set_backlight(dev, 0);
521 
522 	if (INTEL_INFO(dev)->gen >= 4) {
523 		uint32_t reg, tmp;
524 
525 		reg = HAS_PCH_SPLIT(dev) ? BLC_PWM_CPU_CTL2 : BLC_PWM_CTL2;
526 
527 		I915_WRITE(reg, I915_READ(reg) & ~BLM_PWM_ENABLE);
528 
529 		if (HAS_PCH_SPLIT(dev)) {
530 			tmp = I915_READ(BLC_PWM_PCH_CTL1);
531 			tmp &= ~BLM_PCH_PWM_ENABLE;
532 			I915_WRITE(BLC_PWM_PCH_CTL1, tmp);
533 		}
534 	}
535 
536 	spin_unlock(&dev_priv->backlight.lock);
537 }
538 
539 void intel_panel_enable_backlight(struct drm_device *dev,
540 				  enum i915_pipe pipe)
541 {
542 	struct drm_i915_private *dev_priv = dev->dev_private;
543 	enum transcoder cpu_transcoder =
544 		intel_pipe_to_cpu_transcoder(dev_priv, pipe);
545 
546 	spin_lock(&dev_priv->backlight.lock);
547 
548 	if (dev_priv->backlight.level == 0) {
549 		dev_priv->backlight.level = intel_panel_get_max_backlight(dev);
550 		if (dev_priv->backlight.device)
551 			dev_priv->backlight.device->props.brightness =
552 				dev_priv->backlight.level;
553 	}
554 
555 	if (INTEL_INFO(dev)->gen >= 4) {
556 		uint32_t reg, tmp;
557 
558 		reg = HAS_PCH_SPLIT(dev) ? BLC_PWM_CPU_CTL2 : BLC_PWM_CTL2;
559 
560 
561 		tmp = I915_READ(reg);
562 
563 		/* Note that this can also get called through dpms changes. And
564 		 * we don't track the backlight dpms state, hence check whether
565 		 * we have to do anything first. */
566 		if (tmp & BLM_PWM_ENABLE)
567 			goto set_level;
568 
569 		if (INTEL_INFO(dev)->num_pipes == 3)
570 			tmp &= ~BLM_PIPE_SELECT_IVB;
571 		else
572 			tmp &= ~BLM_PIPE_SELECT;
573 
574 		if (cpu_transcoder == TRANSCODER_EDP)
575 			tmp |= BLM_TRANSCODER_EDP;
576 		else
577 			tmp |= BLM_PIPE(cpu_transcoder);
578 		tmp &= ~BLM_PWM_ENABLE;
579 
580 		I915_WRITE(reg, tmp);
581 		POSTING_READ(reg);
582 		I915_WRITE(reg, tmp | BLM_PWM_ENABLE);
583 
584 		if (HAS_PCH_SPLIT(dev) &&
585 		    !(dev_priv->quirks & QUIRK_NO_PCH_PWM_ENABLE)) {
586 			tmp = I915_READ(BLC_PWM_PCH_CTL1);
587 			tmp |= BLM_PCH_PWM_ENABLE;
588 			tmp &= ~BLM_PCH_OVERRIDE_ENABLE;
589 			I915_WRITE(BLC_PWM_PCH_CTL1, tmp);
590 		}
591 	}
592 
593 set_level:
594 	/* Call below after setting BLC_PWM_CPU_CTL2 and BLC_PWM_PCH_CTL1.
595 	 * BLC_PWM_CPU_CTL may be cleared to zero automatically when these
596 	 * registers are set.
597 	 */
598 	dev_priv->backlight.enabled = true;
599 	intel_panel_actually_set_backlight(dev, dev_priv->backlight.level);
600 
601 	spin_unlock(&dev_priv->backlight.lock);
602 }
603 
604 static void intel_panel_init_backlight(struct drm_device *dev)
605 {
606 	struct drm_i915_private *dev_priv = dev->dev_private;
607 
608 	dev_priv->backlight.level = intel_panel_get_backlight(dev);
609 	dev_priv->backlight.enabled = dev_priv->backlight.level != 0;
610 }
611 
612 enum drm_connector_status
613 intel_panel_detect(struct drm_device *dev)
614 {
615 	struct drm_i915_private *dev_priv = dev->dev_private;
616 
617 	/* Assume that the BIOS does not lie through the OpRegion... */
618 	if (!i915_panel_ignore_lid && dev_priv->opregion.lid_state) {
619 		return ioread32(dev_priv->opregion.lid_state) & 0x1 ?
620 			connector_status_connected :
621 			connector_status_disconnected;
622 	}
623 
624 	switch (i915_panel_ignore_lid) {
625 	case -2:
626 		return connector_status_connected;
627 	case -1:
628 		return connector_status_disconnected;
629 	default:
630 		return connector_status_unknown;
631 	}
632 }
633 
634 #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
635 static int intel_panel_update_status(struct backlight_device *bd)
636 {
637 	struct drm_device *dev = bl_get_data(bd);
638 	intel_panel_set_backlight(dev, bd->props.brightness,
639 				  bd->props.max_brightness);
640 	return 0;
641 }
642 
643 static int intel_panel_get_brightness(struct backlight_device *bd)
644 {
645 	struct drm_device *dev = bl_get_data(bd);
646 	return intel_panel_get_backlight(dev);
647 }
648 
649 static const struct backlight_ops intel_panel_bl_ops = {
650 	.update_status = intel_panel_update_status,
651 	.get_brightness = intel_panel_get_brightness,
652 };
653 
654 int intel_panel_setup_backlight(struct drm_connector *connector)
655 {
656 	struct drm_device *dev = connector->dev;
657 	struct drm_i915_private *dev_priv = dev->dev_private;
658 	struct backlight_properties props;
659 	unsigned long flags;
660 
661 	intel_panel_init_backlight(dev);
662 
663 	if (WARN_ON(dev_priv->backlight.device))
664 		return -ENODEV;
665 
666 	memset(&props, 0, sizeof(props));
667 	props.type = BACKLIGHT_RAW;
668 	props.brightness = dev_priv->backlight.level;
669 
670 	/*
671 	 * Do not disable backlight on the vgaswitcheroo path. When switching
672 	 * away from i915, the other client may depend on i915 to handle the
673 	 * backlight. This will leave the backlight on unnecessarily when
674 	 * another client is not activated.
675 	 */
676 	if (dev->switch_power_state == DRM_SWITCH_POWER_CHANGING) {
677 		DRM_DEBUG_DRIVER("Skipping backlight disable on vga switch\n");
678 		return;
679 	}
680 
681 	spin_lock_irqsave(&dev_priv->backlight.lock, flags);
682 	props.max_brightness = intel_panel_get_max_backlight(dev);
683 	spin_unlock_irqrestore(&dev_priv->backlight.lock, flags);
684 
685 	if (props.max_brightness == 0) {
686 		DRM_DEBUG_DRIVER("Failed to get maximum backlight value\n");
687 		return -ENODEV;
688 	}
689 	dev_priv->backlight.device =
690 		backlight_device_register("intel_backlight",
691 					  &connector->kdev, dev,
692 					  &intel_panel_bl_ops, &props);
693 
694 	if (IS_ERR(dev_priv->backlight.device)) {
695 		DRM_ERROR("Failed to register backlight: %ld\n",
696 			  PTR_ERR(dev_priv->backlight.device));
697 		dev_priv->backlight.device = NULL;
698 		return -ENODEV;
699 	}
700 	return 0;
701 }
702 
703 void intel_panel_destroy_backlight(struct drm_device *dev)
704 {
705 	struct drm_i915_private *dev_priv = dev->dev_private;
706 	if (dev_priv->backlight.device) {
707 		backlight_device_unregister(dev_priv->backlight.device);
708 		dev_priv->backlight.device = NULL;
709 	}
710 }
711 #else
712 
713 /*
714  * Read max backlight level
715  */
716 static int
717 sysctl_backlight_max(SYSCTL_HANDLER_ARGS)
718 {
719 	int err, val;
720 	struct drm_i915_private *dev_priv;
721 
722 	dev_priv = ((struct drm_device *)arg1)->dev_private;
723 
724 	spin_lock(&dev_priv->backlight.lock);
725 	val = intel_panel_get_max_backlight((struct drm_device *)arg1);
726 	spin_unlock(&dev_priv->backlight.lock);
727 
728 	err = sysctl_handle_int(oidp, &val, 0, req);
729 	return(err);
730 }
731 
732 /*
733  * Read/write backlight level
734  */
735 static int
736 sysctl_backlight_handler(SYSCTL_HANDLER_ARGS)
737 {
738 	struct drm_i915_private *dev_priv;
739 	int err, val;
740 	u32 max_brightness;
741 
742 	dev_priv = ((struct drm_device *)arg1)->dev_private;
743 	val = dev_priv->backlight.level;
744 
745 	spin_lock(&dev_priv->backlight.lock);
746 	max_brightness = intel_panel_get_max_backlight((struct drm_device *)arg1);
747 	spin_unlock(&dev_priv->backlight.lock);
748 
749 	err = sysctl_handle_int(oidp, &val, 0, req);
750 	if (err != 0 || req->newptr == NULL) {
751 		return(err);
752 	}
753 
754 	if (val != dev_priv->backlight.level && val >=0 &&
755 			val <= max_brightness) {
756 		intel_panel_set_backlight(arg1, val, max_brightness);
757 	}
758 
759 	return(err);
760 }
761 
762 int intel_panel_setup_backlight(struct drm_connector *connector)
763 {
764 	intel_panel_init_backlight(connector->dev);
765 
766 	SYSCTL_ADD_PROC(&connector->dev->sysctl->ctx, &sysctl__hw_children,
767 			OID_AUTO, "backlight_max",
768 			CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_ANYBODY,
769 			connector->dev, sizeof(int),
770 			sysctl_backlight_max,
771 			"I", "Max backlight level");
772 	SYSCTL_ADD_PROC(&connector->dev->sysctl->ctx, &sysctl__hw_children,
773 			OID_AUTO, "backlight_level",
774 			CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY,
775 			connector->dev, sizeof(int),
776 			sysctl_backlight_handler,
777 			"I", "Backlight level");
778 	return 0;
779 }
780 
781 void intel_panel_destroy_backlight(struct drm_device *dev)
782 {
783 	return;
784 }
785 #endif
786 
787 int intel_panel_init(struct intel_panel *panel,
788 		     struct drm_display_mode *fixed_mode)
789 {
790 	panel->fixed_mode = fixed_mode;
791 
792 	return 0;
793 }
794 
795 void intel_panel_fini(struct intel_panel *panel)
796 {
797 	struct intel_connector *intel_connector =
798 		container_of(panel, struct intel_connector, panel);
799 
800 	if (panel->fixed_mode)
801 		drm_mode_destroy(intel_connector->base.dev, panel->fixed_mode);
802 }
803