xref: /gfx-drm/usr/src/uts/intel/io/i915/intel_panel.c (revision 47dc10d7)
1 /*
2  * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
3  */
4 
5 /*
6  * Copyright (c) 2006-2010, 2013, Intel Corporation
7  * Copyright (c) 2006 Dave Airlie <airlied@linux.ie>
8  *
9  * Permission is hereby granted, free of charge, to any person obtaining a
10  * copy of this software and associated documentation files (the "Software"),
11  * to deal in the Software without restriction, including without limitation
12  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13  * and/or sell copies of the Software, and to permit persons to whom the
14  * Software is furnished to do so, subject to the following conditions:
15  *
16  * The above copyright notice and this permission notice (including the next
17  * paragraph) shall be included in all copies or substantial portions of the
18  * Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
23  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26  * DEALINGS IN THE SOFTWARE.
27  *
28  * Authors:
29  *	Eric Anholt <eric@anholt.net>
30  *      Dave Airlie <airlied@linux.ie>
31  *      Jesse Barnes <jesse.barnes@intel.com>
32  *      Chris Wilson <chris@chris-wilson.co.uk>
33  */
34 
35 #include "intel_drv.h"
36 
37 #define PCI_LBPC 0xf4 /* legacy/combination backlight modes */
38 
39 void
intel_fixed_panel_mode(struct drm_display_mode * fixed_mode,struct drm_display_mode * adjusted_mode)40 intel_fixed_panel_mode(struct drm_display_mode *fixed_mode,
41 		       struct drm_display_mode *adjusted_mode)
42 {
43 	adjusted_mode->hdisplay = fixed_mode->hdisplay;
44 	adjusted_mode->hsync_start = fixed_mode->hsync_start;
45 	adjusted_mode->hsync_end = fixed_mode->hsync_end;
46 	adjusted_mode->htotal = fixed_mode->htotal;
47 
48 	adjusted_mode->vdisplay = fixed_mode->vdisplay;
49 	adjusted_mode->vsync_start = fixed_mode->vsync_start;
50 	adjusted_mode->vsync_end = fixed_mode->vsync_end;
51 	adjusted_mode->vtotal = fixed_mode->vtotal;
52 
53 	adjusted_mode->clock = fixed_mode->clock;
54 }
55 
56 /* adjusted_mode has been preset to be the panel's fixed mode */
57 void
intel_pch_panel_fitting(struct intel_crtc * intel_crtc,struct intel_crtc_config * pipe_config,int fitting_mode)58 intel_pch_panel_fitting(struct intel_crtc *intel_crtc,
59 			struct intel_crtc_config *pipe_config,
60 			int fitting_mode)
61 {
62 	struct drm_display_mode *mode, *adjusted_mode;
63 	int x, y, width, height;
64 
65 	mode = &pipe_config->requested_mode;
66 	adjusted_mode = &pipe_config->adjusted_mode;
67 
68 	x = y = width = height = 0;
69 
70 	/* Native modes don't need fitting */
71 	if (adjusted_mode->hdisplay == mode->hdisplay &&
72 	    adjusted_mode->vdisplay == mode->vdisplay)
73 		goto done;
74 
75 	switch (fitting_mode) {
76 	case DRM_MODE_SCALE_CENTER:
77 		width = mode->hdisplay;
78 		height = mode->vdisplay;
79 		x = (adjusted_mode->hdisplay - width + 1)/2;
80 		y = (adjusted_mode->vdisplay - height + 1)/2;
81 		break;
82 
83 	case DRM_MODE_SCALE_ASPECT:
84 		/* Scale but preserve the aspect ratio */
85 		{
86 			u32 scaled_width = adjusted_mode->hdisplay * mode->vdisplay;
87 			u32 scaled_height = mode->hdisplay * adjusted_mode->vdisplay;
88 			if (scaled_width > scaled_height) { /* pillar */
89 				width = scaled_height / mode->vdisplay;
90 				if (width & 1)
91 				    	width++;
92 				x = (adjusted_mode->hdisplay - width + 1) / 2;
93 				y = 0;
94 				height = adjusted_mode->vdisplay;
95 			} else if (scaled_width < scaled_height) { /* letter */
96 				height = scaled_width / mode->hdisplay;
97 				if (height & 1)
98 				    height++;
99 				y = (adjusted_mode->vdisplay - height + 1) / 2;
100 				x = 0;
101 				width = adjusted_mode->hdisplay;
102 			} else {
103 				x = y = 0;
104 				width = adjusted_mode->hdisplay;
105 				height = adjusted_mode->vdisplay;
106 			}
107 		}
108 		break;
109 
110 	case DRM_MODE_SCALE_FULLSCREEN:
111 		x = y = 0;
112 		width = adjusted_mode->hdisplay;
113 		height = adjusted_mode->vdisplay;
114 		break;
115 
116 	default:
117 		DRM_ERROR("bad panel fit mode: %d\n", fitting_mode);
118 		return;
119 	}
120 
121 done:
122 	pipe_config->pch_pfit.pos = (x << 16) | y;
123 	pipe_config->pch_pfit.size = (width << 16) | height;
124 }
125 
126 static void
centre_horizontally(struct drm_display_mode * mode,int width)127 centre_horizontally(struct drm_display_mode *mode,
128 		    int width)
129 {
130 	u32 border, sync_pos, blank_width, sync_width;
131 
132 	/* keep the hsync and hblank widths constant */
133 	sync_width = mode->crtc_hsync_end - mode->crtc_hsync_start;
134 	blank_width = mode->crtc_hblank_end - mode->crtc_hblank_start;
135 	sync_pos = (blank_width - sync_width + 1) / 2;
136 
137 	border = (mode->hdisplay - width + 1) / 2;
138 	border += border & 1; /* make the border even */
139 
140 	mode->crtc_hdisplay = width;
141 	mode->crtc_hblank_start = width + border;
142 	mode->crtc_hblank_end = mode->crtc_hblank_start + blank_width;
143 
144 	mode->crtc_hsync_start = mode->crtc_hblank_start + sync_pos;
145 	mode->crtc_hsync_end = mode->crtc_hsync_start + sync_width;
146 }
147 
148 static void
centre_vertically(struct drm_display_mode * mode,int height)149 centre_vertically(struct drm_display_mode *mode,
150 		  int height)
151 {
152 	u32 border, sync_pos, blank_width, sync_width;
153 
154 	/* keep the vsync and vblank widths constant */
155 	sync_width = mode->crtc_vsync_end - mode->crtc_vsync_start;
156 	blank_width = mode->crtc_vblank_end - mode->crtc_vblank_start;
157 	sync_pos = (blank_width - sync_width + 1) / 2;
158 
159 	border = (mode->vdisplay - height + 1) / 2;
160 
161 	mode->crtc_vdisplay = height;
162 	mode->crtc_vblank_start = height + border;
163 	mode->crtc_vblank_end = mode->crtc_vblank_start + blank_width;
164 
165 	mode->crtc_vsync_start = mode->crtc_vblank_start + sync_pos;
166 	mode->crtc_vsync_end = mode->crtc_vsync_start + sync_width;
167 }
168 
panel_fitter_scaling(u32 source,u32 target)169 static inline u32 panel_fitter_scaling(u32 source, u32 target)
170 {
171 	/*
172 	 * Floating point operation is not supported. So the FACTOR
173 	 * is defined, which can avoid the floating point computation
174 	 * when calculating the panel ratio.
175 	 */
176 #define ACCURACY 12
177 #define FACTOR (1 << ACCURACY)
178 	u32 ratio = source * FACTOR / target;
179 	return (FACTOR * ratio + FACTOR/2) / FACTOR;
180 }
181 
intel_gmch_panel_fitting(struct intel_crtc * intel_crtc,struct intel_crtc_config * pipe_config,int fitting_mode)182 void intel_gmch_panel_fitting(struct intel_crtc *intel_crtc,
183 			      struct intel_crtc_config *pipe_config,
184 			      int fitting_mode)
185 {
186 	struct drm_device *dev = intel_crtc->base.dev;
187 	u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0;
188 	struct drm_display_mode *mode, *adjusted_mode;
189 
190 	mode = &pipe_config->requested_mode;
191 	adjusted_mode = &pipe_config->adjusted_mode;
192 
193 	/* Native modes don't need fitting */
194 	if (adjusted_mode->hdisplay == mode->hdisplay &&
195 	    adjusted_mode->vdisplay == mode->vdisplay)
196 		goto out;
197 
198 	drm_mode_set_crtcinfo(adjusted_mode, 0);
199 	pipe_config->timings_set = true;
200 
201 	switch (fitting_mode) {
202 	case DRM_MODE_SCALE_CENTER:
203 		/*
204 		 * For centered modes, we have to calculate border widths &
205 		 * heights and modify the values programmed into the CRTC.
206 		 */
207 		centre_horizontally(adjusted_mode, mode->hdisplay);
208 		centre_vertically(adjusted_mode, mode->vdisplay);
209 		border = LVDS_BORDER_ENABLE;
210 		break;
211 	case DRM_MODE_SCALE_ASPECT:
212 		/* Scale but preserve the aspect ratio */
213 		if (INTEL_INFO(dev)->gen >= 4) {
214 			u32 scaled_width = adjusted_mode->hdisplay *
215 				mode->vdisplay;
216 			u32 scaled_height = mode->hdisplay *
217 				adjusted_mode->vdisplay;
218 
219 			/* 965+ is easy, it does everything in hw */
220 			if (scaled_width > scaled_height)
221 				pfit_control |= PFIT_ENABLE |
222 					PFIT_SCALING_PILLAR;
223 			else if (scaled_width < scaled_height)
224 				pfit_control |= PFIT_ENABLE |
225 					PFIT_SCALING_LETTER;
226 			else if (adjusted_mode->hdisplay != mode->hdisplay)
227 				pfit_control |= PFIT_ENABLE | PFIT_SCALING_AUTO;
228 		} else {
229 			u32 scaled_width = adjusted_mode->hdisplay *
230 				mode->vdisplay;
231 			u32 scaled_height = mode->hdisplay *
232 				adjusted_mode->vdisplay;
233 			/*
234 			 * For earlier chips we have to calculate the scaling
235 			 * ratio by hand and program it into the
236 			 * PFIT_PGM_RATIO register
237 			 */
238 			if (scaled_width > scaled_height) { /* pillar */
239 				centre_horizontally(adjusted_mode,
240 						    scaled_height /
241 						    mode->vdisplay);
242 
243 				border = LVDS_BORDER_ENABLE;
244 				if (mode->vdisplay != adjusted_mode->vdisplay) {
245 					u32 bits = panel_fitter_scaling(mode->vdisplay, adjusted_mode->vdisplay);
246 					pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT |
247 							    bits << PFIT_VERT_SCALE_SHIFT);
248 					pfit_control |= (PFIT_ENABLE |
249 							 VERT_INTERP_BILINEAR |
250 							 HORIZ_INTERP_BILINEAR);
251 				}
252 			} else if (scaled_width < scaled_height) { /* letter */
253 				centre_vertically(adjusted_mode,
254 						  scaled_width /
255 						  mode->hdisplay);
256 
257 				border = LVDS_BORDER_ENABLE;
258 				if (mode->hdisplay != adjusted_mode->hdisplay) {
259 					u32 bits = panel_fitter_scaling(mode->hdisplay, adjusted_mode->hdisplay);
260 					pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT |
261 							    bits << PFIT_VERT_SCALE_SHIFT);
262 					pfit_control |= (PFIT_ENABLE |
263 							 VERT_INTERP_BILINEAR |
264 							 HORIZ_INTERP_BILINEAR);
265 				}
266 			} else {
267 				/* Aspects match, Let hw scale both directions */
268 				pfit_control |= (PFIT_ENABLE |
269 						 VERT_AUTO_SCALE | HORIZ_AUTO_SCALE |
270 						 VERT_INTERP_BILINEAR |
271 						 HORIZ_INTERP_BILINEAR);
272 			}
273 		}
274 		break;
275 	case DRM_MODE_SCALE_FULLSCREEN:
276 		/*
277 		 * Full scaling, even if it changes the aspect ratio.
278 		 * Fortunately this is all done for us in hw.
279 		 */
280 		if (mode->vdisplay != adjusted_mode->vdisplay ||
281 		    mode->hdisplay != adjusted_mode->hdisplay) {
282 			pfit_control |= PFIT_ENABLE;
283 			if (INTEL_INFO(dev)->gen >= 4)
284 				pfit_control |= PFIT_SCALING_AUTO;
285 			else
286 				pfit_control |= (VERT_AUTO_SCALE |
287 						 VERT_INTERP_BILINEAR |
288 						 HORIZ_AUTO_SCALE |
289 						 HORIZ_INTERP_BILINEAR);
290 		}
291 		break;
292 	default:
293 		DRM_ERROR("bad panel fit mode: %d\n", fitting_mode);
294 		return;
295 	}
296 
297 	/* 965+ wants fuzzy fitting */
298 	/* FIXME: handle multiple panels by failing gracefully */
299 	if (INTEL_INFO(dev)->gen >= 4)
300 		pfit_control |= ((intel_crtc->pipe << PFIT_PIPE_SHIFT) |
301 				 PFIT_FILTER_FUZZY);
302 
303 out:
304 	if ((pfit_control & PFIT_ENABLE) == 0) {
305 		pfit_control = 0;
306 		pfit_pgm_ratios = 0;
307 	}
308 
309 	/* Make sure pre-965 set dither correctly for 18bpp panels. */
310 	if (INTEL_INFO(dev)->gen < 4 && pipe_config->pipe_bpp == 18)
311 		pfit_control |= PANEL_8TO6_DITHER_ENABLE;
312 
313 	pipe_config->gmch_pfit.control = pfit_control;
314 	pipe_config->gmch_pfit.pgm_ratios = pfit_pgm_ratios;
315 	pipe_config->gmch_pfit.lvds_border_bits = border;
316 }
317 
is_backlight_combination_mode(struct drm_device * dev)318 static int is_backlight_combination_mode(struct drm_device *dev)
319 {
320 	struct drm_i915_private *dev_priv = dev->dev_private;
321 
322 	if (INTEL_INFO(dev)->gen >= 4)
323 		return I915_READ(BLC_PWM_CTL2) & BLM_COMBINATION_MODE;
324 
325 	if (IS_GEN2(dev))
326 		return I915_READ(BLC_PWM_CTL) & BLM_LEGACY_MODE;
327 
328 	return 0;
329 }
330 
i915_read_blc_pwm_ctl(struct drm_device * dev)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 	/* Restore the CTL value if it lost, e.g. GPU reset */
337 
338 	if (HAS_PCH_SPLIT(dev_priv->dev)) {
339 		val = I915_READ(BLC_PWM_PCH_CTL2);
340 		if (dev_priv->regfile.saveBLC_PWM_CTL2 == 0) {
341 			dev_priv->regfile.saveBLC_PWM_CTL2 = val;
342 		} else if (val == 0) {
343 			val = dev_priv->regfile.saveBLC_PWM_CTL2;
344 			I915_WRITE(BLC_PWM_PCH_CTL2, val);
345 		}
346 	} else {
347 		val = I915_READ(BLC_PWM_CTL);
348 		if (dev_priv->regfile.saveBLC_PWM_CTL == 0) {
349 			dev_priv->regfile.saveBLC_PWM_CTL = val;
350 			if (INTEL_INFO(dev)->gen >= 4)
351 				dev_priv->regfile.saveBLC_PWM_CTL2 =
352 					I915_READ(BLC_PWM_CTL2);
353 		} else if (val == 0) {
354 			val = dev_priv->regfile.saveBLC_PWM_CTL;
355 			I915_WRITE(BLC_PWM_CTL, val);
356 			if (INTEL_INFO(dev)->gen >= 4)
357 				I915_WRITE(BLC_PWM_CTL2,
358 					   dev_priv->regfile.saveBLC_PWM_CTL2);
359 		}
360 	}
361 
362 	return val;
363 }
364 
intel_panel_get_max_backlight(struct drm_device * dev)365 static u32 intel_panel_get_max_backlight(struct drm_device *dev)
366 {
367 	u32 max;
368 
369 	max = i915_read_blc_pwm_ctl(dev);
370 
371 	if (HAS_PCH_SPLIT(dev)) {
372 		max >>= 16;
373 	} else {
374 		if (INTEL_INFO(dev)->gen < 4)
375 			max >>= 17;
376 		else
377 			max >>= 16;
378 
379 		if (is_backlight_combination_mode(dev))
380 			max *= 0xff;
381 	}
382 
383 	DRM_DEBUG_DRIVER("max backlight PWM = %d\n", max);
384 	return max;
385 }
386 
387 static int i915_panel_invert_brightness;
intel_panel_compute_brightness(struct drm_device * dev,u32 val)388 static u32 intel_panel_compute_brightness(struct drm_device *dev, u32 val)
389 {
390 	struct drm_i915_private *dev_priv = dev->dev_private;
391 
392 	if (i915_panel_invert_brightness < 0)
393 		return val;
394 
395 	if (i915_panel_invert_brightness > 0 ||
396 	    dev_priv->quirks & QUIRK_INVERT_BRIGHTNESS) {
397 		u32 max = intel_panel_get_max_backlight(dev);
398 		if (max)
399 			return max - val;
400 	}
401 
402 	return val;
403 }
404 
intel_panel_get_backlight(struct drm_device * dev)405 static u32 intel_panel_get_backlight(struct drm_device *dev)
406 {
407 	struct drm_i915_private *dev_priv = dev->dev_private;
408 	u32 val;
409 	unsigned long flags;
410 
411 	spin_lock_irqsave(&dev_priv->backlight.lock, flags);
412 
413 	if (HAS_PCH_SPLIT(dev)) {
414 		val = I915_READ(BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
415 	} else {
416 		val = I915_READ(BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
417 		if (INTEL_INFO(dev)->gen < 4)
418 			val >>= 1;
419 
420 		if (is_backlight_combination_mode(dev)){
421 			u8 lbpc;
422 
423 			pci_read_config_byte(dev->pdev, PCI_LBPC, &lbpc);
424 			val *= lbpc;
425 		}
426 	}
427 
428 	val = intel_panel_compute_brightness(dev, val);
429 
430 	spin_unlock_irqrestore(&dev_priv->backlight.lock, flags);
431 
432 	DRM_DEBUG_DRIVER("get backlight PWM = %d\n", val);
433 	return val;
434 }
435 
intel_pch_panel_set_backlight(struct drm_device * dev,u32 level)436 static void intel_pch_panel_set_backlight(struct drm_device *dev, u32 level)
437 {
438 	struct drm_i915_private *dev_priv = dev->dev_private;
439 	u32 val = I915_READ(BLC_PWM_CPU_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK;
440 	I915_WRITE(BLC_PWM_CPU_CTL, val | level);
441 }
442 
intel_panel_actually_set_backlight(struct drm_device * dev,u32 level)443 static void intel_panel_actually_set_backlight(struct drm_device *dev, u32 level)
444 {
445 	struct drm_i915_private *dev_priv = dev->dev_private;
446 	u32 tmp;
447 
448 	DRM_DEBUG_DRIVER("set backlight PWM = %d\n", level);
449 	level = intel_panel_compute_brightness(dev, level);
450 
451 	if (HAS_PCH_SPLIT(dev)) {
452 		intel_pch_panel_set_backlight(dev, level);
453 		return;
454 	}
455 
456 	if (is_backlight_combination_mode(dev)){
457 		u32 max = intel_panel_get_max_backlight(dev);
458 		u8 lbpc;
459 
460 		/* we're screwed, but keep behaviour backwards compatible */
461 		if (!max)
462 			max = 1;
463 
464 		lbpc = level * 0xfe / max + 1;
465 		level /= lbpc;
466 		pci_write_config_byte(dev->pdev, PCI_LBPC, lbpc);
467 	}
468 
469 	tmp = I915_READ(BLC_PWM_CTL);
470 	if (INTEL_INFO(dev)->gen < 4)
471 		level <<= 1;
472 	tmp &= ~BACKLIGHT_DUTY_CYCLE_MASK;
473 	I915_WRITE(BLC_PWM_CTL, tmp | level);
474 }
475 
476 /* set backlight brightness to level in range [0..max] */
intel_panel_set_backlight(struct drm_device * dev,u32 level,u32 max)477 void intel_panel_set_backlight(struct drm_device *dev, u32 level, u32 max)
478 {
479 	struct drm_i915_private *dev_priv = dev->dev_private;
480 	u32 freq;
481 	unsigned long flags;
482 
483 	spin_lock_irqsave(&dev_priv->backlight.lock, flags);
484 
485 	freq = intel_panel_get_max_backlight(dev);
486 	if (!freq) {
487 		/* we are screwed, bail out */
488 		goto out;
489 	}
490 
491 	/* scale to hardware, but be careful to not overflow */
492 	if (freq < max)
493 		level = level * freq / max;
494 	else
495 		level = freq / max * level;
496 
497 	dev_priv->backlight.level = level;
498 //	if (dev_priv->backlight.device)
499 //		dev_priv->backlight.device->props.brightness = level;
500 
501 	if (dev_priv->backlight.enabled)
502 		intel_panel_actually_set_backlight(dev, level);
503 out:
504 	spin_unlock_irqrestore(&dev_priv->backlight.lock, flags);
505 }
506 
intel_panel_disable_backlight(struct drm_device * dev)507 void intel_panel_disable_backlight(struct drm_device *dev)
508 {
509 	struct drm_i915_private *dev_priv = dev->dev_private;
510 	unsigned long flags;
511 
512 	/*
513 	 * Do not disable backlight on the vgaswitcheroo path. When switching
514 	 * away from i915, the other client may depend on i915 to handle the
515 	 * backlight. This will leave the backlight on unnecessarily when
516 	 * another client is not activated.
517 	 */
518 	if (dev->switch_power_state == DRM_SWITCH_POWER_CHANGING) {
519 		DRM_DEBUG_DRIVER("Skipping backlight disable on vga switch\n");
520 		return;
521 	}
522 
523 	spin_lock_irqsave(&dev_priv->backlight.lock, flags);
524 
525 	dev_priv->backlight.enabled = false;
526 	intel_panel_actually_set_backlight(dev, 0);
527 
528 	if (INTEL_INFO(dev)->gen >= 4) {
529 		uint32_t reg, tmp;
530 
531 		reg = HAS_PCH_SPLIT(dev) ? BLC_PWM_CPU_CTL2 : BLC_PWM_CTL2;
532 
533 		I915_WRITE(reg, I915_READ(reg) & ~BLM_PWM_ENABLE);
534 
535 		if (HAS_PCH_SPLIT(dev)) {
536 			tmp = I915_READ(BLC_PWM_PCH_CTL1);
537 			tmp &= ~BLM_PCH_PWM_ENABLE;
538 			I915_WRITE(BLC_PWM_PCH_CTL1, tmp);
539 		}
540 	}
541 
542 	spin_unlock_irqrestore(&dev_priv->backlight.lock, flags);
543 }
544 
intel_panel_enable_backlight(struct drm_device * dev,enum pipe pipe)545 void intel_panel_enable_backlight(struct drm_device *dev,
546 				  enum pipe pipe)
547 {
548 	struct drm_i915_private *dev_priv = dev->dev_private;
549 	enum transcoder cpu_transcoder =
550 		intel_pipe_to_cpu_transcoder(dev_priv, pipe);
551 	unsigned long flags;
552 
553 	spin_lock_irqsave(&dev_priv->backlight.lock, flags);
554 
555 	if (dev_priv->backlight.level == 0) {
556 		dev_priv->backlight.level = intel_panel_get_max_backlight(dev);
557 //		if (dev_priv->backlight.device)
558 //			dev_priv->backlight.device->props.brightness =
559 //				dev_priv->backlight.level;
560 	}
561 
562 	if (INTEL_INFO(dev)->gen >= 4) {
563 		uint32_t reg, tmp;
564 
565 		reg = HAS_PCH_SPLIT(dev) ? BLC_PWM_CPU_CTL2 : BLC_PWM_CTL2;
566 
567 
568 		tmp = I915_READ(reg);
569 
570 		/* Note that this can also get called through dpms changes. And
571 		 * we don't track the backlight dpms state, hence check whether
572 		 * we have to do anything first. */
573 		if (tmp & BLM_PWM_ENABLE)
574 			goto set_level;
575 
576 		if (INTEL_INFO(dev)->num_pipes == 3)
577 			tmp &= ~BLM_PIPE_SELECT_IVB;
578 		else
579 			tmp &= ~BLM_PIPE_SELECT;
580 
581 		if (cpu_transcoder == TRANSCODER_EDP)
582 			tmp |= BLM_TRANSCODER_EDP;
583 		else
584 			tmp |= BLM_PIPE(cpu_transcoder);
585 		tmp &= ~BLM_PWM_ENABLE;
586 
587 		I915_WRITE(reg, tmp);
588 		POSTING_READ(reg);
589 		I915_WRITE(reg, tmp | BLM_PWM_ENABLE);
590 
591 		if (HAS_PCH_SPLIT(dev) &&
592 		    !(dev_priv->quirks & QUIRK_NO_PCH_PWM_ENABLE)) {
593 			tmp = I915_READ(BLC_PWM_PCH_CTL1);
594 			tmp |= BLM_PCH_PWM_ENABLE;
595 			tmp &= ~BLM_PCH_OVERRIDE_ENABLE;
596 			I915_WRITE(BLC_PWM_PCH_CTL1, tmp);
597 		}
598 	}
599 
600 set_level:
601 	/* Call below after setting BLC_PWM_CPU_CTL2 and BLC_PWM_PCH_CTL1.
602 	 * BLC_PWM_CPU_CTL may be cleared to zero automatically when these
603 	 * registers are set.
604  	 */
605 	dev_priv->backlight.enabled = true;
606 	intel_panel_actually_set_backlight(dev, dev_priv->backlight.level);
607 
608 	spin_unlock_irqrestore(&dev_priv->backlight.lock, flags);
609 }
610 
intel_panel_init_backlight(struct drm_device * dev)611 static void intel_panel_init_backlight(struct drm_device *dev)
612 {
613 	struct drm_i915_private *dev_priv = dev->dev_private;
614 
615 	dev_priv->backlight.level = intel_panel_get_backlight(dev);
616 	dev_priv->backlight.enabled = dev_priv->backlight.level != 0;
617 }
618 
619 enum drm_connector_status
intel_panel_detect(struct drm_device * dev)620 intel_panel_detect(struct drm_device *dev)
621 {
622 #if 0
623 	struct drm_i915_private *dev_priv = dev->dev_private;
624 
625 	/* Assume that the BIOS does not lie through the OpRegion... */
626 	if (!i915_panel_ignore_lid && dev_priv->opregion.lid_state) {
627 		u32 *regs = (u32 *)dev_priv->opregion.lid_state;
628 		return regs[0] & 0x1 ?
629 			connector_status_connected :
630 			connector_status_disconnected;
631 	}
632 	switch (i915_panel_ignore_lid) {
633 	case -2:
634 		return connector_status_connected;
635 	case -1:
636 		return connector_status_disconnected;
637 	default:
638 		return connector_status_unknown;
639 	}
640 #endif
641 
642 	return connector_status_unknown;
643 }
644 
645 #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
intel_panel_update_status(struct backlight_device * bd)646 static int intel_panel_update_status(struct backlight_device *bd)
647 {
648 	struct drm_device *dev = bl_get_data(bd);
649 	intel_panel_set_backlight(dev, bd->props.brightness,
650 				  bd->props.max_brightness);
651 	return 0;
652 }
653 
intel_panel_get_brightness(struct backlight_device * bd)654 static int intel_panel_get_brightness(struct backlight_device *bd)
655 {
656 	struct drm_device *dev = bl_get_data(bd);
657 	return intel_panel_get_backlight(dev);
658 }
659 
660 static const struct backlight_ops intel_panel_bl_ops = {
661 	.update_status = intel_panel_update_status,
662 	.get_brightness = intel_panel_get_brightness,
663 };
664 
intel_panel_setup_backlight(struct drm_connector * connector)665 int intel_panel_setup_backlight(struct drm_connector *connector)
666 {
667 	struct drm_device *dev = connector->dev;
668 	struct drm_i915_private *dev_priv = dev->dev_private;
669 	struct backlight_properties props;
670 	unsigned long flags;
671 
672 	intel_panel_init_backlight(dev);
673 
674 	if (WARN_ON(dev_priv->backlight.device))
675 		return -ENODEV;
676 
677 	(void) memset(&props, 0, sizeof(props));
678 	props.type = BACKLIGHT_RAW;
679 	props.brightness = dev_priv->backlight.level;
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 	if (props.max_brightness == 0) {
685 		DRM_DEBUG_DRIVER("Failed to get maximum backlight value\n");
686 		return -ENODEV;
687 	}
688 	dev_priv->backlight.device =
689 		backlight_device_register("intel_backlight",
690 					  &connector->kdev, dev,
691 					  &intel_panel_bl_ops, &props);
692 
693 	if (IS_ERR(dev_priv->backlight.device)) {
694 		DRM_ERROR("Failed to register backlight: %ld\n",
695 			  PTR_ERR(dev_priv->backlight.device));
696 		dev_priv->backlight.device = NULL;
697 		return -ENODEV;
698 	}
699 	return 0;
700 }
701 
intel_panel_destroy_backlight(struct drm_device * dev)702 void intel_panel_destroy_backlight(struct drm_device *dev)
703 {
704 	struct drm_i915_private *dev_priv = dev->dev_private;
705 	if (dev_priv->backlight.device) {
706 		backlight_device_unregister(dev_priv->backlight.device);
707 		dev_priv->backlight.device = NULL;
708 	}
709 }
710 #else
intel_panel_setup_backlight(struct drm_connector * connector)711 int intel_panel_setup_backlight(struct drm_connector *connector)
712 {
713 	intel_panel_init_backlight(connector->dev);
714 	return 0;
715 }
716 
intel_panel_destroy_backlight(struct drm_device * dev)717 void intel_panel_destroy_backlight(struct drm_device *dev)
718 {
719 	return;
720 }
721 #endif
722 
intel_panel_init(struct intel_panel * panel,struct drm_display_mode * fixed_mode)723 int intel_panel_init(struct intel_panel *panel,
724 		     struct drm_display_mode *fixed_mode)
725  {
726 	panel->fixed_mode = fixed_mode;
727 
728 	return 0;
729 }
730 
intel_panel_fini(struct intel_panel * panel)731 void intel_panel_fini(struct intel_panel *panel)
732 {
733 	struct intel_connector *intel_connector =
734 		container_of(panel, struct intel_connector, panel);
735 
736 	if (panel->fixed_mode)
737 		drm_mode_destroy(intel_connector->base.dev, panel->fixed_mode);
738 }
739