xref: /dragonfly/sys/dev/drm/i915/intel_panel.c (revision 279dd846)
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 void
35 intel_fixed_panel_mode(const struct drm_display_mode *fixed_mode,
36 		       struct drm_display_mode *adjusted_mode)
37 {
38 	drm_mode_copy(adjusted_mode, fixed_mode);
39 
40 	drm_mode_set_crtcinfo(adjusted_mode, 0);
41 }
42 
43 /**
44  * intel_find_panel_downclock - find the reduced downclock for LVDS in EDID
45  * @dev: drm device
46  * @fixed_mode : panel native mode
47  * @connector: LVDS/eDP connector
48  *
49  * Return downclock_avail
50  * Find the reduced downclock for LVDS/eDP in EDID.
51  */
52 struct drm_display_mode *
53 intel_find_panel_downclock(struct drm_device *dev,
54 			struct drm_display_mode *fixed_mode,
55 			struct drm_connector *connector)
56 {
57 	struct drm_display_mode *scan, *tmp_mode;
58 	int temp_downclock;
59 
60 	temp_downclock = fixed_mode->clock;
61 	tmp_mode = NULL;
62 
63 	list_for_each_entry(scan, &connector->probed_modes, head) {
64 		/*
65 		 * If one mode has the same resolution with the fixed_panel
66 		 * mode while they have the different refresh rate, it means
67 		 * that the reduced downclock is found. In such
68 		 * case we can set the different FPx0/1 to dynamically select
69 		 * between low and high frequency.
70 		 */
71 		if (scan->hdisplay == fixed_mode->hdisplay &&
72 		    scan->hsync_start == fixed_mode->hsync_start &&
73 		    scan->hsync_end == fixed_mode->hsync_end &&
74 		    scan->htotal == fixed_mode->htotal &&
75 		    scan->vdisplay == fixed_mode->vdisplay &&
76 		    scan->vsync_start == fixed_mode->vsync_start &&
77 		    scan->vsync_end == fixed_mode->vsync_end &&
78 		    scan->vtotal == fixed_mode->vtotal) {
79 			if (scan->clock < temp_downclock) {
80 				/*
81 				 * The downclock is already found. But we
82 				 * expect to find the lower downclock.
83 				 */
84 				temp_downclock = scan->clock;
85 				tmp_mode = scan;
86 			}
87 		}
88 	}
89 
90 	if (temp_downclock < fixed_mode->clock)
91 		return drm_mode_duplicate(dev, tmp_mode);
92 	else
93 		return NULL;
94 }
95 
96 /* adjusted_mode has been preset to be the panel's fixed mode */
97 void
98 intel_pch_panel_fitting(struct intel_crtc *intel_crtc,
99 			struct intel_crtc_config *pipe_config,
100 			int fitting_mode)
101 {
102 	struct drm_display_mode *adjusted_mode;
103 	int x, y, width, height;
104 
105 	adjusted_mode = &pipe_config->adjusted_mode;
106 
107 	x = y = width = height = 0;
108 
109 	/* Native modes don't need fitting */
110 	if (adjusted_mode->hdisplay == pipe_config->pipe_src_w &&
111 	    adjusted_mode->vdisplay == pipe_config->pipe_src_h)
112 		goto done;
113 
114 	switch (fitting_mode) {
115 	case DRM_MODE_SCALE_CENTER:
116 		width = pipe_config->pipe_src_w;
117 		height = pipe_config->pipe_src_h;
118 		x = (adjusted_mode->hdisplay - width + 1)/2;
119 		y = (adjusted_mode->vdisplay - height + 1)/2;
120 		break;
121 
122 	case DRM_MODE_SCALE_ASPECT:
123 		/* Scale but preserve the aspect ratio */
124 		{
125 			u32 scaled_width = adjusted_mode->hdisplay
126 				* pipe_config->pipe_src_h;
127 			u32 scaled_height = pipe_config->pipe_src_w
128 				* adjusted_mode->vdisplay;
129 			if (scaled_width > scaled_height) { /* pillar */
130 				width = scaled_height / pipe_config->pipe_src_h;
131 				if (width & 1)
132 					width++;
133 				x = (adjusted_mode->hdisplay - width + 1) / 2;
134 				y = 0;
135 				height = adjusted_mode->vdisplay;
136 			} else if (scaled_width < scaled_height) { /* letter */
137 				height = scaled_width / pipe_config->pipe_src_w;
138 				if (height & 1)
139 				    height++;
140 				y = (adjusted_mode->vdisplay - height + 1) / 2;
141 				x = 0;
142 				width = adjusted_mode->hdisplay;
143 			} else {
144 				x = y = 0;
145 				width = adjusted_mode->hdisplay;
146 				height = adjusted_mode->vdisplay;
147 			}
148 		}
149 		break;
150 
151 	case DRM_MODE_SCALE_FULLSCREEN:
152 		x = y = 0;
153 		width = adjusted_mode->hdisplay;
154 		height = adjusted_mode->vdisplay;
155 		break;
156 
157 	default:
158 		WARN(1, "bad panel fit mode: %d\n", fitting_mode);
159 		return;
160 	}
161 
162 done:
163 	pipe_config->pch_pfit.pos = (x << 16) | y;
164 	pipe_config->pch_pfit.size = (width << 16) | height;
165 	pipe_config->pch_pfit.enabled = pipe_config->pch_pfit.size != 0;
166 }
167 
168 static void
169 centre_horizontally(struct drm_display_mode *mode,
170 		    int width)
171 {
172 	u32 border, sync_pos, blank_width, sync_width;
173 
174 	/* keep the hsync and hblank widths constant */
175 	sync_width = mode->crtc_hsync_end - mode->crtc_hsync_start;
176 	blank_width = mode->crtc_hblank_end - mode->crtc_hblank_start;
177 	sync_pos = (blank_width - sync_width + 1) / 2;
178 
179 	border = (mode->hdisplay - width + 1) / 2;
180 	border += border & 1; /* make the border even */
181 
182 	mode->crtc_hdisplay = width;
183 	mode->crtc_hblank_start = width + border;
184 	mode->crtc_hblank_end = mode->crtc_hblank_start + blank_width;
185 
186 	mode->crtc_hsync_start = mode->crtc_hblank_start + sync_pos;
187 	mode->crtc_hsync_end = mode->crtc_hsync_start + sync_width;
188 }
189 
190 static void
191 centre_vertically(struct drm_display_mode *mode,
192 		  int height)
193 {
194 	u32 border, sync_pos, blank_width, sync_width;
195 
196 	/* keep the vsync and vblank widths constant */
197 	sync_width = mode->crtc_vsync_end - mode->crtc_vsync_start;
198 	blank_width = mode->crtc_vblank_end - mode->crtc_vblank_start;
199 	sync_pos = (blank_width - sync_width + 1) / 2;
200 
201 	border = (mode->vdisplay - height + 1) / 2;
202 
203 	mode->crtc_vdisplay = height;
204 	mode->crtc_vblank_start = height + border;
205 	mode->crtc_vblank_end = mode->crtc_vblank_start + blank_width;
206 
207 	mode->crtc_vsync_start = mode->crtc_vblank_start + sync_pos;
208 	mode->crtc_vsync_end = mode->crtc_vsync_start + sync_width;
209 }
210 
211 static inline u32 panel_fitter_scaling(u32 source, u32 target)
212 {
213 	/*
214 	 * Floating point operation is not supported. So the FACTOR
215 	 * is defined, which can avoid the floating point computation
216 	 * when calculating the panel ratio.
217 	 */
218 #define ACCURACY 12
219 #define FACTOR (1 << ACCURACY)
220 	u32 ratio = source * FACTOR / target;
221 	return (FACTOR * ratio + FACTOR/2) / FACTOR;
222 }
223 
224 static void i965_scale_aspect(struct intel_crtc_config *pipe_config,
225 			      u32 *pfit_control)
226 {
227 	struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode;
228 	u32 scaled_width = adjusted_mode->hdisplay *
229 		pipe_config->pipe_src_h;
230 	u32 scaled_height = pipe_config->pipe_src_w *
231 		adjusted_mode->vdisplay;
232 
233 	/* 965+ is easy, it does everything in hw */
234 	if (scaled_width > scaled_height)
235 		*pfit_control |= PFIT_ENABLE |
236 			PFIT_SCALING_PILLAR;
237 	else if (scaled_width < scaled_height)
238 		*pfit_control |= PFIT_ENABLE |
239 			PFIT_SCALING_LETTER;
240 	else if (adjusted_mode->hdisplay != pipe_config->pipe_src_w)
241 		*pfit_control |= PFIT_ENABLE | PFIT_SCALING_AUTO;
242 }
243 
244 static void i9xx_scale_aspect(struct intel_crtc_config *pipe_config,
245 			      u32 *pfit_control, u32 *pfit_pgm_ratios,
246 			      u32 *border)
247 {
248 	struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode;
249 	u32 scaled_width = adjusted_mode->hdisplay *
250 		pipe_config->pipe_src_h;
251 	u32 scaled_height = pipe_config->pipe_src_w *
252 		adjusted_mode->vdisplay;
253 	u32 bits;
254 
255 	/*
256 	 * For earlier chips we have to calculate the scaling
257 	 * ratio by hand and program it into the
258 	 * PFIT_PGM_RATIO register
259 	 */
260 	if (scaled_width > scaled_height) { /* pillar */
261 		centre_horizontally(adjusted_mode,
262 				    scaled_height /
263 				    pipe_config->pipe_src_h);
264 
265 		*border = LVDS_BORDER_ENABLE;
266 		if (pipe_config->pipe_src_h != adjusted_mode->vdisplay) {
267 			bits = panel_fitter_scaling(pipe_config->pipe_src_h,
268 						    adjusted_mode->vdisplay);
269 
270 			*pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT |
271 					     bits << PFIT_VERT_SCALE_SHIFT);
272 			*pfit_control |= (PFIT_ENABLE |
273 					  VERT_INTERP_BILINEAR |
274 					  HORIZ_INTERP_BILINEAR);
275 		}
276 	} else if (scaled_width < scaled_height) { /* letter */
277 		centre_vertically(adjusted_mode,
278 				  scaled_width /
279 				  pipe_config->pipe_src_w);
280 
281 		*border = LVDS_BORDER_ENABLE;
282 		if (pipe_config->pipe_src_w != adjusted_mode->hdisplay) {
283 			bits = panel_fitter_scaling(pipe_config->pipe_src_w,
284 						    adjusted_mode->hdisplay);
285 
286 			*pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT |
287 					     bits << PFIT_VERT_SCALE_SHIFT);
288 			*pfit_control |= (PFIT_ENABLE |
289 					  VERT_INTERP_BILINEAR |
290 					  HORIZ_INTERP_BILINEAR);
291 		}
292 	} else {
293 		/* Aspects match, Let hw scale both directions */
294 		*pfit_control |= (PFIT_ENABLE |
295 				  VERT_AUTO_SCALE | HORIZ_AUTO_SCALE |
296 				  VERT_INTERP_BILINEAR |
297 				  HORIZ_INTERP_BILINEAR);
298 	}
299 }
300 
301 void intel_gmch_panel_fitting(struct intel_crtc *intel_crtc,
302 			      struct intel_crtc_config *pipe_config,
303 			      int fitting_mode)
304 {
305 	struct drm_device *dev = intel_crtc->base.dev;
306 	u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0;
307 	struct drm_display_mode *adjusted_mode;
308 
309 	adjusted_mode = &pipe_config->adjusted_mode;
310 
311 	/* Native modes don't need fitting */
312 	if (adjusted_mode->hdisplay == pipe_config->pipe_src_w &&
313 	    adjusted_mode->vdisplay == pipe_config->pipe_src_h)
314 		goto out;
315 
316 	switch (fitting_mode) {
317 	case DRM_MODE_SCALE_CENTER:
318 		/*
319 		 * For centered modes, we have to calculate border widths &
320 		 * heights and modify the values programmed into the CRTC.
321 		 */
322 		centre_horizontally(adjusted_mode, pipe_config->pipe_src_w);
323 		centre_vertically(adjusted_mode, pipe_config->pipe_src_h);
324 		border = LVDS_BORDER_ENABLE;
325 		break;
326 	case DRM_MODE_SCALE_ASPECT:
327 		/* Scale but preserve the aspect ratio */
328 		if (INTEL_INFO(dev)->gen >= 4)
329 			i965_scale_aspect(pipe_config, &pfit_control);
330 		else
331 			i9xx_scale_aspect(pipe_config, &pfit_control,
332 					  &pfit_pgm_ratios, &border);
333 		break;
334 	case DRM_MODE_SCALE_FULLSCREEN:
335 		/*
336 		 * Full scaling, even if it changes the aspect ratio.
337 		 * Fortunately this is all done for us in hw.
338 		 */
339 		if (pipe_config->pipe_src_h != adjusted_mode->vdisplay ||
340 		    pipe_config->pipe_src_w != adjusted_mode->hdisplay) {
341 			pfit_control |= PFIT_ENABLE;
342 			if (INTEL_INFO(dev)->gen >= 4)
343 				pfit_control |= PFIT_SCALING_AUTO;
344 			else
345 				pfit_control |= (VERT_AUTO_SCALE |
346 						 VERT_INTERP_BILINEAR |
347 						 HORIZ_AUTO_SCALE |
348 						 HORIZ_INTERP_BILINEAR);
349 		}
350 		break;
351 	default:
352 		WARN(1, "bad panel fit mode: %d\n", fitting_mode);
353 		return;
354 	}
355 
356 	/* 965+ wants fuzzy fitting */
357 	/* FIXME: handle multiple panels by failing gracefully */
358 	if (INTEL_INFO(dev)->gen >= 4)
359 		pfit_control |= ((intel_crtc->pipe << PFIT_PIPE_SHIFT) |
360 				 PFIT_FILTER_FUZZY);
361 
362 out:
363 	if ((pfit_control & PFIT_ENABLE) == 0) {
364 		pfit_control = 0;
365 		pfit_pgm_ratios = 0;
366 	}
367 
368 	/* Make sure pre-965 set dither correctly for 18bpp panels. */
369 	if (INTEL_INFO(dev)->gen < 4 && pipe_config->pipe_bpp == 18)
370 		pfit_control |= PANEL_8TO6_DITHER_ENABLE;
371 
372 	pipe_config->gmch_pfit.control = pfit_control;
373 	pipe_config->gmch_pfit.pgm_ratios = pfit_pgm_ratios;
374 	pipe_config->gmch_pfit.lvds_border_bits = border;
375 }
376 
377 enum drm_connector_status
378 intel_panel_detect(struct drm_device *dev)
379 {
380 	struct drm_i915_private *dev_priv = dev->dev_private;
381 
382 	/* Assume that the BIOS does not lie through the OpRegion... */
383 	if (!i915.panel_ignore_lid && dev_priv->opregion.lid_state) {
384 		return ioread32(dev_priv->opregion.lid_state) & 0x1 ?
385 			connector_status_connected :
386 			connector_status_disconnected;
387 	}
388 
389 	switch (i915.panel_ignore_lid) {
390 	case -2:
391 		return connector_status_connected;
392 	case -1:
393 		return connector_status_disconnected;
394 	default:
395 		return connector_status_unknown;
396 	}
397 }
398 
399 /**
400  * scale - scale values from one range to another
401  *
402  * @source_val: value in range [@source_min..@source_max]
403  *
404  * Return @source_val in range [@source_min..@source_max] scaled to range
405  * [@target_min..@target_max].
406  */
407 static uint32_t scale(uint32_t source_val,
408 		      uint32_t source_min, uint32_t source_max,
409 		      uint32_t target_min, uint32_t target_max)
410 {
411 	uint64_t target_val;
412 
413 	WARN_ON(source_min > source_max);
414 	WARN_ON(target_min > target_max);
415 
416 	/* defensive */
417 	source_val = clamp(source_val, source_min, source_max);
418 
419 	/* avoid overflows */
420 	target_val = (uint64_t)(source_val - source_min) *
421 		(target_max - target_min);
422 	do_div(target_val, source_max - source_min);
423 	target_val += target_min;
424 
425 	return target_val;
426 }
427 
428 /* Scale user_level in range [0..user_max] to [hw_min..hw_max]. */
429 static inline u32 scale_user_to_hw(struct intel_connector *connector,
430 				   u32 user_level, u32 user_max)
431 {
432 	struct intel_panel *panel = &connector->panel;
433 
434 	return scale(user_level, 0, user_max,
435 		     panel->backlight.min, panel->backlight.max);
436 }
437 
438 /* Scale user_level in range [0..user_max] to [0..hw_max], clamping the result
439  * to [hw_min..hw_max]. */
440 static inline u32 clamp_user_to_hw(struct intel_connector *connector,
441 				   u32 user_level, u32 user_max)
442 {
443 	struct intel_panel *panel = &connector->panel;
444 	u32 hw_level;
445 
446 	hw_level = scale(user_level, 0, user_max, 0, panel->backlight.max);
447 	hw_level = clamp(hw_level, panel->backlight.min, panel->backlight.max);
448 
449 	return hw_level;
450 }
451 
452 /* Scale hw_level in range [hw_min..hw_max] to [0..user_max]. */
453 static inline u32 scale_hw_to_user(struct intel_connector *connector,
454 				   u32 hw_level, u32 user_max)
455 {
456 	struct intel_panel *panel = &connector->panel;
457 
458 	return scale(hw_level, panel->backlight.min, panel->backlight.max,
459 		     0, user_max);
460 }
461 
462 static u32 intel_panel_compute_brightness(struct intel_connector *connector,
463 					  u32 val)
464 {
465 	struct drm_device *dev = connector->base.dev;
466 	struct drm_i915_private *dev_priv = dev->dev_private;
467 	struct intel_panel *panel = &connector->panel;
468 
469 	WARN_ON(panel->backlight.max == 0);
470 
471 	if (i915.invert_brightness < 0)
472 		return val;
473 
474 	if (i915.invert_brightness > 0 ||
475 	    dev_priv->quirks & QUIRK_INVERT_BRIGHTNESS) {
476 		return panel->backlight.max - val;
477 	}
478 
479 	return val;
480 }
481 
482 static u32 bdw_get_backlight(struct intel_connector *connector)
483 {
484 	struct drm_device *dev = connector->base.dev;
485 	struct drm_i915_private *dev_priv = dev->dev_private;
486 
487 	return I915_READ(BLC_PWM_PCH_CTL2) & BACKLIGHT_DUTY_CYCLE_MASK;
488 }
489 
490 static u32 pch_get_backlight(struct intel_connector *connector)
491 {
492 	struct drm_device *dev = connector->base.dev;
493 	struct drm_i915_private *dev_priv = dev->dev_private;
494 
495 	return I915_READ(BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
496 }
497 
498 static u32 i9xx_get_backlight(struct intel_connector *connector)
499 {
500 	struct drm_device *dev = connector->base.dev;
501 	struct drm_i915_private *dev_priv = dev->dev_private;
502 	struct intel_panel *panel = &connector->panel;
503 	u32 val;
504 
505 	val = I915_READ(BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
506 	if (INTEL_INFO(dev)->gen < 4)
507 		val >>= 1;
508 
509 	if (panel->backlight.combination_mode) {
510 		u8 lbpc;
511 
512 		pci_read_config_byte(dev->pdev, PCI_LBPC, &lbpc);
513 		val *= lbpc;
514 	}
515 
516 	return val;
517 }
518 
519 static u32 _vlv_get_backlight(struct drm_device *dev, enum i915_pipe pipe)
520 {
521 	struct drm_i915_private *dev_priv = dev->dev_private;
522 
523 	return I915_READ(VLV_BLC_PWM_CTL(pipe)) & BACKLIGHT_DUTY_CYCLE_MASK;
524 }
525 
526 static u32 vlv_get_backlight(struct intel_connector *connector)
527 {
528 	struct drm_device *dev = connector->base.dev;
529 	enum i915_pipe pipe = intel_get_pipe_from_connector(connector);
530 
531 	return _vlv_get_backlight(dev, pipe);
532 }
533 
534 #if 0
535 static u32 intel_panel_get_backlight(struct intel_connector *connector)
536 {
537 	struct drm_device *dev = connector->base.dev;
538 	struct drm_i915_private *dev_priv = dev->dev_private;
539 	u32 val;
540 	unsigned long flags;
541 
542 	spin_lock_irqsave(&dev_priv->backlight_lock, flags);
543 
544 	val = dev_priv->display.get_backlight(connector);
545 	val = intel_panel_compute_brightness(connector, val);
546 
547 	spin_unlock_irqrestore(&dev_priv->backlight_lock, flags);
548 
549 	DRM_DEBUG_DRIVER("get backlight PWM = %d\n", val);
550 	return val;
551 }
552 #endif
553 
554 static void bdw_set_backlight(struct intel_connector *connector, u32 level)
555 {
556 	struct drm_device *dev = connector->base.dev;
557 	struct drm_i915_private *dev_priv = dev->dev_private;
558 	u32 val = I915_READ(BLC_PWM_PCH_CTL2) & ~BACKLIGHT_DUTY_CYCLE_MASK;
559 	I915_WRITE(BLC_PWM_PCH_CTL2, val | level);
560 }
561 
562 static void pch_set_backlight(struct intel_connector *connector, u32 level)
563 {
564 	struct drm_device *dev = connector->base.dev;
565 	struct drm_i915_private *dev_priv = dev->dev_private;
566 	u32 tmp;
567 
568 	tmp = I915_READ(BLC_PWM_CPU_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK;
569 	I915_WRITE(BLC_PWM_CPU_CTL, tmp | level);
570 }
571 
572 static void i9xx_set_backlight(struct intel_connector *connector, u32 level)
573 {
574 	struct drm_device *dev = connector->base.dev;
575 	struct drm_i915_private *dev_priv = dev->dev_private;
576 	struct intel_panel *panel = &connector->panel;
577 	u32 tmp, mask;
578 
579 	WARN_ON(panel->backlight.max == 0);
580 
581 	if (panel->backlight.combination_mode) {
582 		u8 lbpc;
583 
584 		lbpc = level * 0xfe / panel->backlight.max + 1;
585 		level /= lbpc;
586 		pci_write_config_byte(dev->pdev, PCI_LBPC, lbpc);
587 	}
588 
589 	if (IS_GEN4(dev)) {
590 		mask = BACKLIGHT_DUTY_CYCLE_MASK;
591 	} else {
592 		level <<= 1;
593 		mask = BACKLIGHT_DUTY_CYCLE_MASK_PNV;
594 	}
595 
596 	tmp = I915_READ(BLC_PWM_CTL) & ~mask;
597 	I915_WRITE(BLC_PWM_CTL, tmp | level);
598 }
599 
600 static void vlv_set_backlight(struct intel_connector *connector, u32 level)
601 {
602 	struct drm_device *dev = connector->base.dev;
603 	struct drm_i915_private *dev_priv = dev->dev_private;
604 	enum i915_pipe pipe = intel_get_pipe_from_connector(connector);
605 	u32 tmp;
606 
607 	tmp = I915_READ(VLV_BLC_PWM_CTL(pipe)) & ~BACKLIGHT_DUTY_CYCLE_MASK;
608 	I915_WRITE(VLV_BLC_PWM_CTL(pipe), tmp | level);
609 }
610 
611 static void
612 intel_panel_actually_set_backlight(struct intel_connector *connector, u32 level)
613 {
614 	struct drm_device *dev = connector->base.dev;
615 	struct drm_i915_private *dev_priv = dev->dev_private;
616 
617 	DRM_DEBUG_DRIVER("set backlight PWM = %d\n", level);
618 
619 	level = intel_panel_compute_brightness(connector, level);
620 	dev_priv->display.set_backlight(connector, level);
621 }
622 
623 /* set backlight brightness to level in range [0..max], scaling wrt hw min */
624 static void intel_panel_set_backlight(struct intel_connector *connector,
625 				      u32 user_level, u32 user_max)
626 {
627 	struct drm_device *dev = connector->base.dev;
628 	struct drm_i915_private *dev_priv = dev->dev_private;
629 	struct intel_panel *panel = &connector->panel;
630 	enum i915_pipe pipe = intel_get_pipe_from_connector(connector);
631 	u32 hw_level;
632 
633 	if (!panel->backlight.present || pipe == INVALID_PIPE)
634 		return;
635 
636 	spin_lock(&dev_priv->backlight_lock);
637 
638 	WARN_ON(panel->backlight.max == 0);
639 
640 	hw_level = scale_user_to_hw(connector, user_level, user_max);
641 	panel->backlight.level = hw_level;
642 
643 	if (panel->backlight.enabled)
644 		intel_panel_actually_set_backlight(connector, hw_level);
645 
646 	spin_unlock(&dev_priv->backlight_lock);
647 }
648 
649 /* set backlight brightness to level in range [0..max], assuming hw min is
650  * respected.
651  */
652 void intel_panel_set_backlight_acpi(struct intel_connector *connector,
653 				    u32 user_level, u32 user_max)
654 {
655 	struct drm_device *dev = connector->base.dev;
656 	struct drm_i915_private *dev_priv = dev->dev_private;
657 	struct intel_panel *panel = &connector->panel;
658 	enum i915_pipe pipe = intel_get_pipe_from_connector(connector);
659 	u32 hw_level;
660 
661 	if (!panel->backlight.present || pipe == INVALID_PIPE)
662 		return;
663 
664 	spin_lock(&dev_priv->backlight_lock);
665 
666 	WARN_ON(panel->backlight.max == 0);
667 
668 	hw_level = clamp_user_to_hw(connector, user_level, user_max);
669 	panel->backlight.level = hw_level;
670 
671 	if (panel->backlight.device)
672 		panel->backlight.device->props.brightness =
673 			scale_hw_to_user(connector,
674 					 panel->backlight.level,
675 					 panel->backlight.device->props.max_brightness);
676 
677 	if (panel->backlight.enabled)
678 		intel_panel_actually_set_backlight(connector, hw_level);
679 
680 	spin_unlock(&dev_priv->backlight_lock);
681 }
682 
683 static void pch_disable_backlight(struct intel_connector *connector)
684 {
685 	struct drm_device *dev = connector->base.dev;
686 	struct drm_i915_private *dev_priv = dev->dev_private;
687 	u32 tmp;
688 
689 	intel_panel_actually_set_backlight(connector, 0);
690 
691 	tmp = I915_READ(BLC_PWM_CPU_CTL2);
692 	I915_WRITE(BLC_PWM_CPU_CTL2, tmp & ~BLM_PWM_ENABLE);
693 
694 	tmp = I915_READ(BLC_PWM_PCH_CTL1);
695 	I915_WRITE(BLC_PWM_PCH_CTL1, tmp & ~BLM_PCH_PWM_ENABLE);
696 }
697 
698 static void i9xx_disable_backlight(struct intel_connector *connector)
699 {
700 	intel_panel_actually_set_backlight(connector, 0);
701 }
702 
703 static void i965_disable_backlight(struct intel_connector *connector)
704 {
705 	struct drm_device *dev = connector->base.dev;
706 	struct drm_i915_private *dev_priv = dev->dev_private;
707 	u32 tmp;
708 
709 	intel_panel_actually_set_backlight(connector, 0);
710 
711 	tmp = I915_READ(BLC_PWM_CTL2);
712 	I915_WRITE(BLC_PWM_CTL2, tmp & ~BLM_PWM_ENABLE);
713 }
714 
715 static void vlv_disable_backlight(struct intel_connector *connector)
716 {
717 	struct drm_device *dev = connector->base.dev;
718 	struct drm_i915_private *dev_priv = dev->dev_private;
719 	enum i915_pipe pipe = intel_get_pipe_from_connector(connector);
720 	u32 tmp;
721 
722 	intel_panel_actually_set_backlight(connector, 0);
723 
724 	tmp = I915_READ(VLV_BLC_PWM_CTL2(pipe));
725 	I915_WRITE(VLV_BLC_PWM_CTL2(pipe), tmp & ~BLM_PWM_ENABLE);
726 }
727 
728 void intel_panel_disable_backlight(struct intel_connector *connector)
729 {
730 	struct drm_device *dev = connector->base.dev;
731 	struct drm_i915_private *dev_priv = dev->dev_private;
732 	struct intel_panel *panel = &connector->panel;
733 	enum i915_pipe pipe = intel_get_pipe_from_connector(connector);
734 
735 	if (!panel->backlight.present || pipe == INVALID_PIPE)
736 		return;
737 
738 	/*
739 	 * Do not disable backlight on the vgaswitcheroo path. When switching
740 	 * away from i915, the other client may depend on i915 to handle the
741 	 * backlight. This will leave the backlight on unnecessarily when
742 	 * another client is not activated.
743 	 */
744 	if (dev->switch_power_state == DRM_SWITCH_POWER_CHANGING) {
745 		DRM_DEBUG_DRIVER("Skipping backlight disable on vga switch\n");
746 		return;
747 	}
748 
749 	spin_lock(&dev_priv->backlight_lock);
750 
751 	panel->backlight.enabled = false;
752 	dev_priv->display.disable_backlight(connector);
753 
754 	spin_unlock(&dev_priv->backlight_lock);
755 }
756 
757 static void bdw_enable_backlight(struct intel_connector *connector)
758 {
759 	struct drm_device *dev = connector->base.dev;
760 	struct drm_i915_private *dev_priv = dev->dev_private;
761 	struct intel_panel *panel = &connector->panel;
762 	u32 pch_ctl1, pch_ctl2;
763 
764 	pch_ctl1 = I915_READ(BLC_PWM_PCH_CTL1);
765 	if (pch_ctl1 & BLM_PCH_PWM_ENABLE) {
766 		DRM_DEBUG_KMS("pch backlight already enabled\n");
767 		pch_ctl1 &= ~BLM_PCH_PWM_ENABLE;
768 		I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1);
769 	}
770 
771 	pch_ctl2 = panel->backlight.max << 16;
772 	I915_WRITE(BLC_PWM_PCH_CTL2, pch_ctl2);
773 
774 	pch_ctl1 = 0;
775 	if (panel->backlight.active_low_pwm)
776 		pch_ctl1 |= BLM_PCH_POLARITY;
777 
778 	/* BDW always uses the pch pwm controls. */
779 	pch_ctl1 |= BLM_PCH_OVERRIDE_ENABLE;
780 
781 	I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1);
782 	POSTING_READ(BLC_PWM_PCH_CTL1);
783 	I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1 | BLM_PCH_PWM_ENABLE);
784 
785 	/* This won't stick until the above enable. */
786 	intel_panel_actually_set_backlight(connector, panel->backlight.level);
787 }
788 
789 static void pch_enable_backlight(struct intel_connector *connector)
790 {
791 	struct drm_device *dev = connector->base.dev;
792 	struct drm_i915_private *dev_priv = dev->dev_private;
793 	struct intel_panel *panel = &connector->panel;
794 	enum i915_pipe pipe = intel_get_pipe_from_connector(connector);
795 	enum transcoder cpu_transcoder =
796 		intel_pipe_to_cpu_transcoder(dev_priv, pipe);
797 	u32 cpu_ctl2, pch_ctl1, pch_ctl2;
798 
799 	cpu_ctl2 = I915_READ(BLC_PWM_CPU_CTL2);
800 	if (cpu_ctl2 & BLM_PWM_ENABLE) {
801 		DRM_DEBUG_KMS("cpu backlight already enabled\n");
802 		cpu_ctl2 &= ~BLM_PWM_ENABLE;
803 		I915_WRITE(BLC_PWM_CPU_CTL2, cpu_ctl2);
804 	}
805 
806 	pch_ctl1 = I915_READ(BLC_PWM_PCH_CTL1);
807 	if (pch_ctl1 & BLM_PCH_PWM_ENABLE) {
808 		DRM_DEBUG_KMS("pch backlight already enabled\n");
809 		pch_ctl1 &= ~BLM_PCH_PWM_ENABLE;
810 		I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1);
811 	}
812 
813 	if (cpu_transcoder == TRANSCODER_EDP)
814 		cpu_ctl2 = BLM_TRANSCODER_EDP;
815 	else
816 		cpu_ctl2 = BLM_PIPE(cpu_transcoder);
817 	I915_WRITE(BLC_PWM_CPU_CTL2, cpu_ctl2);
818 	POSTING_READ(BLC_PWM_CPU_CTL2);
819 	I915_WRITE(BLC_PWM_CPU_CTL2, cpu_ctl2 | BLM_PWM_ENABLE);
820 
821 	/* This won't stick until the above enable. */
822 	intel_panel_actually_set_backlight(connector, panel->backlight.level);
823 
824 	pch_ctl2 = panel->backlight.max << 16;
825 	I915_WRITE(BLC_PWM_PCH_CTL2, pch_ctl2);
826 
827 	pch_ctl1 = 0;
828 	if (panel->backlight.active_low_pwm)
829 		pch_ctl1 |= BLM_PCH_POLARITY;
830 
831 	I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1);
832 	POSTING_READ(BLC_PWM_PCH_CTL1);
833 	I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1 | BLM_PCH_PWM_ENABLE);
834 }
835 
836 static void i9xx_enable_backlight(struct intel_connector *connector)
837 {
838 	struct drm_device *dev = connector->base.dev;
839 	struct drm_i915_private *dev_priv = dev->dev_private;
840 	struct intel_panel *panel = &connector->panel;
841 	u32 ctl, freq;
842 
843 	ctl = I915_READ(BLC_PWM_CTL);
844 	if (ctl & BACKLIGHT_DUTY_CYCLE_MASK_PNV) {
845 		DRM_DEBUG_KMS("backlight already enabled\n");
846 		I915_WRITE(BLC_PWM_CTL, 0);
847 	}
848 
849 	freq = panel->backlight.max;
850 	if (panel->backlight.combination_mode)
851 		freq /= 0xff;
852 
853 	ctl = freq << 17;
854 	if (panel->backlight.combination_mode)
855 		ctl |= BLM_LEGACY_MODE;
856 	if (IS_PINEVIEW(dev) && panel->backlight.active_low_pwm)
857 		ctl |= BLM_POLARITY_PNV;
858 
859 	I915_WRITE(BLC_PWM_CTL, ctl);
860 	POSTING_READ(BLC_PWM_CTL);
861 
862 	/* XXX: combine this into above write? */
863 	intel_panel_actually_set_backlight(connector, panel->backlight.level);
864 }
865 
866 static void i965_enable_backlight(struct intel_connector *connector)
867 {
868 	struct drm_device *dev = connector->base.dev;
869 	struct drm_i915_private *dev_priv = dev->dev_private;
870 	struct intel_panel *panel = &connector->panel;
871 	enum i915_pipe pipe = intel_get_pipe_from_connector(connector);
872 	u32 ctl, ctl2, freq;
873 
874 	ctl2 = I915_READ(BLC_PWM_CTL2);
875 	if (ctl2 & BLM_PWM_ENABLE) {
876 		DRM_DEBUG_KMS("backlight already enabled\n");
877 		ctl2 &= ~BLM_PWM_ENABLE;
878 		I915_WRITE(BLC_PWM_CTL2, ctl2);
879 	}
880 
881 	freq = panel->backlight.max;
882 	if (panel->backlight.combination_mode)
883 		freq /= 0xff;
884 
885 	ctl = freq << 16;
886 	I915_WRITE(BLC_PWM_CTL, ctl);
887 
888 	ctl2 = BLM_PIPE(pipe);
889 	if (panel->backlight.combination_mode)
890 		ctl2 |= BLM_COMBINATION_MODE;
891 	if (panel->backlight.active_low_pwm)
892 		ctl2 |= BLM_POLARITY_I965;
893 	I915_WRITE(BLC_PWM_CTL2, ctl2);
894 	POSTING_READ(BLC_PWM_CTL2);
895 	I915_WRITE(BLC_PWM_CTL2, ctl2 | BLM_PWM_ENABLE);
896 
897 	intel_panel_actually_set_backlight(connector, panel->backlight.level);
898 }
899 
900 static void vlv_enable_backlight(struct intel_connector *connector)
901 {
902 	struct drm_device *dev = connector->base.dev;
903 	struct drm_i915_private *dev_priv = dev->dev_private;
904 	struct intel_panel *panel = &connector->panel;
905 	enum i915_pipe pipe = intel_get_pipe_from_connector(connector);
906 	u32 ctl, ctl2;
907 
908 	ctl2 = I915_READ(VLV_BLC_PWM_CTL2(pipe));
909 	if (ctl2 & BLM_PWM_ENABLE) {
910 		DRM_DEBUG_KMS("backlight already enabled\n");
911 		ctl2 &= ~BLM_PWM_ENABLE;
912 		I915_WRITE(VLV_BLC_PWM_CTL2(pipe), ctl2);
913 	}
914 
915 	ctl = panel->backlight.max << 16;
916 	I915_WRITE(VLV_BLC_PWM_CTL(pipe), ctl);
917 
918 	/* XXX: combine this into above write? */
919 	intel_panel_actually_set_backlight(connector, panel->backlight.level);
920 
921 	ctl2 = 0;
922 	if (panel->backlight.active_low_pwm)
923 		ctl2 |= BLM_POLARITY_I965;
924 	I915_WRITE(VLV_BLC_PWM_CTL2(pipe), ctl2);
925 	POSTING_READ(VLV_BLC_PWM_CTL2(pipe));
926 	I915_WRITE(VLV_BLC_PWM_CTL2(pipe), ctl2 | BLM_PWM_ENABLE);
927 }
928 
929 void intel_panel_enable_backlight(struct intel_connector *connector)
930 {
931 	struct drm_device *dev = connector->base.dev;
932 	struct drm_i915_private *dev_priv = dev->dev_private;
933 	struct intel_panel *panel = &connector->panel;
934 	enum i915_pipe pipe = intel_get_pipe_from_connector(connector);
935 
936 	if (!panel->backlight.present || pipe == INVALID_PIPE)
937 		return;
938 
939 	DRM_DEBUG_KMS("pipe %c\n", pipe_name(pipe));
940 
941 	spin_lock(&dev_priv->backlight_lock);
942 
943 	WARN_ON(panel->backlight.max == 0);
944 
945 	if (panel->backlight.level == 0) {
946 		panel->backlight.level = panel->backlight.max;
947 		if (panel->backlight.device)
948 			panel->backlight.device->props.brightness =
949 				scale_hw_to_user(connector,
950 						 panel->backlight.level,
951 						 panel->backlight.device->props.max_brightness);
952 	}
953 
954 	dev_priv->display.enable_backlight(connector);
955 	panel->backlight.enabled = true;
956 
957 	spin_unlock(&dev_priv->backlight_lock);
958 }
959 
960 #if IS_ENABLED(CONFIG_BACKLIGHT_CLASS_DEVICE)
961 static int intel_backlight_device_update_status(struct backlight_device *bd)
962 {
963 	struct intel_connector *connector = bl_get_data(bd);
964 	struct drm_device *dev = connector->base.dev;
965 
966 	drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
967 	DRM_DEBUG_KMS("updating intel_backlight, brightness=%d/%d\n",
968 		      bd->props.brightness, bd->props.max_brightness);
969 	intel_panel_set_backlight(connector, bd->props.brightness,
970 				  bd->props.max_brightness);
971 	drm_modeset_unlock(&dev->mode_config.connection_mutex);
972 	return 0;
973 }
974 
975 static int intel_backlight_device_get_brightness(struct backlight_device *bd)
976 {
977 	struct intel_connector *connector = bl_get_data(bd);
978 	struct drm_device *dev = connector->base.dev;
979 	struct drm_i915_private *dev_priv = dev->dev_private;
980 	u32 hw_level;
981 	int ret;
982 
983 	intel_runtime_pm_get(dev_priv);
984 	drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
985 
986 	hw_level = intel_panel_get_backlight(connector);
987 	ret = scale_hw_to_user(connector, hw_level, bd->props.max_brightness);
988 
989 	drm_modeset_unlock(&dev->mode_config.connection_mutex);
990 	intel_runtime_pm_put(dev_priv);
991 
992 	return ret;
993 }
994 
995 static const struct backlight_ops intel_backlight_device_ops = {
996 	.update_status = intel_backlight_device_update_status,
997 	.get_brightness = intel_backlight_device_get_brightness,
998 };
999 
1000 static int intel_backlight_device_register(struct intel_connector *connector)
1001 {
1002 	struct intel_panel *panel = &connector->panel;
1003 	struct backlight_properties props;
1004 
1005 	if (WARN_ON(panel->backlight.device))
1006 		return -ENODEV;
1007 
1008 	WARN_ON(panel->backlight.max == 0);
1009 
1010 	memset(&props, 0, sizeof(props));
1011 	props.type = BACKLIGHT_RAW;
1012 
1013 	/*
1014 	 * Note: Everything should work even if the backlight device max
1015 	 * presented to the userspace is arbitrarily chosen.
1016 	 */
1017 	props.max_brightness = panel->backlight.max;
1018 	props.brightness = scale_hw_to_user(connector,
1019 					    panel->backlight.level,
1020 					    props.max_brightness);
1021 
1022 	/*
1023 	 * Note: using the same name independent of the connector prevents
1024 	 * registration of multiple backlight devices in the driver.
1025 	 */
1026 	panel->backlight.device =
1027 		backlight_device_register("intel_backlight",
1028 					  connector->base.kdev,
1029 					  connector,
1030 					  &intel_backlight_device_ops, &props);
1031 
1032 	if (IS_ERR(panel->backlight.device)) {
1033 		DRM_ERROR("Failed to register backlight: %ld\n",
1034 			  PTR_ERR(panel->backlight.device));
1035 		panel->backlight.device = NULL;
1036 		return -ENODEV;
1037 	}
1038 	return 0;
1039 }
1040 
1041 static void intel_backlight_device_unregister(struct intel_connector *connector)
1042 {
1043 	struct intel_panel *panel = &connector->panel;
1044 
1045 	if (panel->backlight.device) {
1046 		backlight_device_unregister(panel->backlight.device);
1047 		panel->backlight.device = NULL;
1048 	}
1049 }
1050 #else /* CONFIG_BACKLIGHT_CLASS_DEVICE */
1051 static int intel_backlight_device_register(struct intel_connector *connector)
1052 {
1053 	return 0;
1054 }
1055 static void intel_backlight_device_unregister(struct intel_connector *connector)
1056 {
1057 }
1058 #endif /* CONFIG_BACKLIGHT_CLASS_DEVICE */
1059 
1060 /*
1061  * Note: The setup hooks can't assume pipe is set!
1062  *
1063  * XXX: Query mode clock or hardware clock and program PWM modulation frequency
1064  * appropriately when it's 0. Use VBT and/or sane defaults.
1065  */
1066 static u32 get_backlight_min_vbt(struct intel_connector *connector)
1067 {
1068 	struct drm_device *dev = connector->base.dev;
1069 	struct drm_i915_private *dev_priv = dev->dev_private;
1070 	struct intel_panel *panel = &connector->panel;
1071 
1072 	WARN_ON(panel->backlight.max == 0);
1073 
1074 	/* vbt value is a coefficient in range [0..255] */
1075 	return scale(dev_priv->vbt.backlight.min_brightness, 0, 255,
1076 		     0, panel->backlight.max);
1077 }
1078 
1079 static int bdw_setup_backlight(struct intel_connector *connector)
1080 {
1081 	struct drm_device *dev = connector->base.dev;
1082 	struct drm_i915_private *dev_priv = dev->dev_private;
1083 	struct intel_panel *panel = &connector->panel;
1084 	u32 pch_ctl1, pch_ctl2, val;
1085 
1086 	pch_ctl1 = I915_READ(BLC_PWM_PCH_CTL1);
1087 	panel->backlight.active_low_pwm = pch_ctl1 & BLM_PCH_POLARITY;
1088 
1089 	pch_ctl2 = I915_READ(BLC_PWM_PCH_CTL2);
1090 	panel->backlight.max = pch_ctl2 >> 16;
1091 	if (!panel->backlight.max)
1092 		return -ENODEV;
1093 
1094 	panel->backlight.min = get_backlight_min_vbt(connector);
1095 
1096 	val = bdw_get_backlight(connector);
1097 	panel->backlight.level = intel_panel_compute_brightness(connector, val);
1098 
1099 	panel->backlight.enabled = (pch_ctl1 & BLM_PCH_PWM_ENABLE) &&
1100 		panel->backlight.level != 0;
1101 
1102 	return 0;
1103 }
1104 
1105 static int pch_setup_backlight(struct intel_connector *connector)
1106 {
1107 	struct drm_device *dev = connector->base.dev;
1108 	struct drm_i915_private *dev_priv = dev->dev_private;
1109 	struct intel_panel *panel = &connector->panel;
1110 	u32 cpu_ctl2, pch_ctl1, pch_ctl2, val;
1111 
1112 	pch_ctl1 = I915_READ(BLC_PWM_PCH_CTL1);
1113 	panel->backlight.active_low_pwm = pch_ctl1 & BLM_PCH_POLARITY;
1114 
1115 	pch_ctl2 = I915_READ(BLC_PWM_PCH_CTL2);
1116 	panel->backlight.max = pch_ctl2 >> 16;
1117 	if (!panel->backlight.max)
1118 		return -ENODEV;
1119 
1120 	panel->backlight.min = get_backlight_min_vbt(connector);
1121 
1122 	val = pch_get_backlight(connector);
1123 	panel->backlight.level = intel_panel_compute_brightness(connector, val);
1124 
1125 	cpu_ctl2 = I915_READ(BLC_PWM_CPU_CTL2);
1126 	panel->backlight.enabled = (cpu_ctl2 & BLM_PWM_ENABLE) &&
1127 		(pch_ctl1 & BLM_PCH_PWM_ENABLE) && panel->backlight.level != 0;
1128 
1129 	return 0;
1130 }
1131 
1132 static int i9xx_setup_backlight(struct intel_connector *connector)
1133 {
1134 	struct drm_device *dev = connector->base.dev;
1135 	struct drm_i915_private *dev_priv = dev->dev_private;
1136 	struct intel_panel *panel = &connector->panel;
1137 	u32 ctl, val;
1138 
1139 	ctl = I915_READ(BLC_PWM_CTL);
1140 
1141 	if (IS_GEN2(dev) || IS_I915GM(dev) || IS_I945GM(dev))
1142 		panel->backlight.combination_mode = ctl & BLM_LEGACY_MODE;
1143 
1144 	if (IS_PINEVIEW(dev))
1145 		panel->backlight.active_low_pwm = ctl & BLM_POLARITY_PNV;
1146 
1147 	panel->backlight.max = ctl >> 17;
1148 	if (panel->backlight.combination_mode)
1149 		panel->backlight.max *= 0xff;
1150 
1151 	if (!panel->backlight.max)
1152 		return -ENODEV;
1153 
1154 	panel->backlight.min = get_backlight_min_vbt(connector);
1155 
1156 	val = i9xx_get_backlight(connector);
1157 	panel->backlight.level = intel_panel_compute_brightness(connector, val);
1158 
1159 	panel->backlight.enabled = panel->backlight.level != 0;
1160 
1161 	return 0;
1162 }
1163 
1164 static int i965_setup_backlight(struct intel_connector *connector)
1165 {
1166 	struct drm_device *dev = connector->base.dev;
1167 	struct drm_i915_private *dev_priv = dev->dev_private;
1168 	struct intel_panel *panel = &connector->panel;
1169 	u32 ctl, ctl2, val;
1170 
1171 	ctl2 = I915_READ(BLC_PWM_CTL2);
1172 	panel->backlight.combination_mode = ctl2 & BLM_COMBINATION_MODE;
1173 	panel->backlight.active_low_pwm = ctl2 & BLM_POLARITY_I965;
1174 
1175 	ctl = I915_READ(BLC_PWM_CTL);
1176 	panel->backlight.max = ctl >> 16;
1177 	if (panel->backlight.combination_mode)
1178 		panel->backlight.max *= 0xff;
1179 
1180 	if (!panel->backlight.max)
1181 		return -ENODEV;
1182 
1183 	panel->backlight.min = get_backlight_min_vbt(connector);
1184 
1185 	val = i9xx_get_backlight(connector);
1186 	panel->backlight.level = intel_panel_compute_brightness(connector, val);
1187 
1188 	panel->backlight.enabled = (ctl2 & BLM_PWM_ENABLE) &&
1189 		panel->backlight.level != 0;
1190 
1191 	return 0;
1192 }
1193 
1194 static int vlv_setup_backlight(struct intel_connector *connector)
1195 {
1196 	struct drm_device *dev = connector->base.dev;
1197 	struct drm_i915_private *dev_priv = dev->dev_private;
1198 	struct intel_panel *panel = &connector->panel;
1199 	enum i915_pipe pipe;
1200 	u32 ctl, ctl2, val;
1201 
1202 	for_each_pipe(pipe) {
1203 		u32 cur_val = I915_READ(VLV_BLC_PWM_CTL(pipe));
1204 
1205 		/* Skip if the modulation freq is already set */
1206 		if (cur_val & ~BACKLIGHT_DUTY_CYCLE_MASK)
1207 			continue;
1208 
1209 		cur_val &= BACKLIGHT_DUTY_CYCLE_MASK;
1210 		I915_WRITE(VLV_BLC_PWM_CTL(pipe), (0xf42 << 16) |
1211 			   cur_val);
1212 	}
1213 
1214 	ctl2 = I915_READ(VLV_BLC_PWM_CTL2(PIPE_A));
1215 	panel->backlight.active_low_pwm = ctl2 & BLM_POLARITY_I965;
1216 
1217 	ctl = I915_READ(VLV_BLC_PWM_CTL(PIPE_A));
1218 	panel->backlight.max = ctl >> 16;
1219 	if (!panel->backlight.max)
1220 		return -ENODEV;
1221 
1222 	panel->backlight.min = get_backlight_min_vbt(connector);
1223 
1224 	val = _vlv_get_backlight(dev, PIPE_A);
1225 	panel->backlight.level = intel_panel_compute_brightness(connector, val);
1226 
1227 	panel->backlight.enabled = (ctl2 & BLM_PWM_ENABLE) &&
1228 		panel->backlight.level != 0;
1229 
1230 	return 0;
1231 }
1232 
1233 /* XXX: DragonFly-specific begin */
1234 /*
1235  * Read max backlight level
1236  */
1237 static int
1238 sysctl_backlight_max(SYSCTL_HANDLER_ARGS)
1239 {
1240 	int err, val;
1241 	struct intel_connector *connector = arg1;
1242 	struct drm_device *dev = connector->base.dev;
1243 	struct drm_i915_private *dev_priv = dev->dev_private;
1244 	struct intel_panel *panel = &connector->panel;
1245 
1246 	spin_lock(&dev_priv->backlight_lock);
1247 	val = panel->backlight.max;
1248 	spin_unlock(&dev_priv->backlight_lock);
1249 
1250 	err = sysctl_handle_int(oidp, &val, 0, req);
1251 	return(err);
1252 }
1253 
1254 /*
1255  * Read/write backlight level
1256  */
1257 static int
1258 sysctl_backlight_handler(SYSCTL_HANDLER_ARGS)
1259 {
1260 	struct intel_connector *connector = arg1;
1261 	struct drm_device *dev = connector->base.dev;
1262 	struct drm_i915_private *dev_priv = dev->dev_private;
1263 	struct intel_panel *panel = &connector->panel;
1264 	int err, val;
1265 	u32 max_brightness;
1266 
1267 	val = panel->backlight.level;
1268 
1269 	spin_lock(&dev_priv->backlight_lock);
1270 	max_brightness = panel->backlight.max;
1271 	spin_unlock(&dev_priv->backlight_lock);
1272 
1273 	err = sysctl_handle_int(oidp, &val, 0, req);
1274 	if (err != 0 || req->newptr == NULL) {
1275 		return(err);
1276 	}
1277 
1278 	if (val != panel->backlight.level && val >=0 &&
1279 			val <= max_brightness) {
1280 		drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
1281 		intel_panel_set_backlight(arg1, val, max_brightness);
1282 		drm_modeset_unlock(&dev->mode_config.connection_mutex);
1283 	}
1284 
1285 	return(err);
1286 }
1287 /* XXX: DragonFly-specific end */
1288 
1289 int intel_panel_setup_backlight(struct drm_connector *connector)
1290 {
1291 	struct drm_device *dev = connector->dev;
1292 	struct drm_i915_private *dev_priv = dev->dev_private;
1293 	struct intel_connector *intel_connector = to_intel_connector(connector);
1294 	struct intel_panel *panel = &intel_connector->panel;
1295 	int ret;
1296 
1297 	if (!dev_priv->vbt.backlight.present) {
1298 		if (dev_priv->quirks & QUIRK_BACKLIGHT_PRESENT) {
1299 			DRM_DEBUG_KMS("no backlight present per VBT, but present per quirk\n");
1300 		} else {
1301 			DRM_DEBUG_KMS("no backlight present per VBT\n");
1302 			return 0;
1303 		}
1304 	}
1305 
1306 	/* set level and max in panel struct */
1307 	spin_lock(&dev_priv->backlight_lock);
1308 	ret = dev_priv->display.setup_backlight(intel_connector);
1309 	spin_unlock(&dev_priv->backlight_lock);
1310 
1311 	if (ret) {
1312 		DRM_DEBUG_KMS("failed to setup backlight for connector %s\n",
1313 			      connector->name);
1314 		return ret;
1315 	}
1316 
1317 	intel_backlight_device_register(intel_connector);
1318 
1319 	panel->backlight.present = true;
1320 
1321 	/* XXX: DragonFly-specific begin */
1322 	SYSCTL_ADD_PROC(&connector->dev->sysctl->ctx, &sysctl__hw_children,
1323 			OID_AUTO, "backlight_max",
1324 			CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_ANYBODY,
1325 			connector, sizeof(int),
1326 			sysctl_backlight_max,
1327 			"I", "Max backlight level");
1328 	SYSCTL_ADD_PROC(&connector->dev->sysctl->ctx, &sysctl__hw_children,
1329 			OID_AUTO, "backlight_level",
1330 			CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY,
1331 			connector, sizeof(int),
1332 			sysctl_backlight_handler,
1333 			"I", "Backlight level");
1334 	/* XXX: DragonFly-specific end */
1335 
1336 	DRM_DEBUG_KMS("backlight initialized, %s, brightness %u/%u, "
1337 		      "sysfs interface %sregistered\n",
1338 		      panel->backlight.enabled ? "enabled" : "disabled",
1339 		      panel->backlight.level, panel->backlight.max,
1340 		      panel->backlight.device ? "" : "not ");
1341 
1342 	return 0;
1343 }
1344 
1345 void intel_panel_destroy_backlight(struct drm_connector *connector)
1346 {
1347 	struct intel_connector *intel_connector = to_intel_connector(connector);
1348 	struct intel_panel *panel = &intel_connector->panel;
1349 
1350 	panel->backlight.present = false;
1351 	intel_backlight_device_unregister(intel_connector);
1352 }
1353 
1354 /* Set up chip specific backlight functions */
1355 void intel_panel_init_backlight_funcs(struct drm_device *dev)
1356 {
1357 	struct drm_i915_private *dev_priv = dev->dev_private;
1358 
1359 	if (IS_BROADWELL(dev)) {
1360 		dev_priv->display.setup_backlight = bdw_setup_backlight;
1361 		dev_priv->display.enable_backlight = bdw_enable_backlight;
1362 		dev_priv->display.disable_backlight = pch_disable_backlight;
1363 		dev_priv->display.set_backlight = bdw_set_backlight;
1364 		dev_priv->display.get_backlight = bdw_get_backlight;
1365 	} else if (HAS_PCH_SPLIT(dev)) {
1366 		dev_priv->display.setup_backlight = pch_setup_backlight;
1367 		dev_priv->display.enable_backlight = pch_enable_backlight;
1368 		dev_priv->display.disable_backlight = pch_disable_backlight;
1369 		dev_priv->display.set_backlight = pch_set_backlight;
1370 		dev_priv->display.get_backlight = pch_get_backlight;
1371 	} else if (IS_VALLEYVIEW(dev)) {
1372 		dev_priv->display.setup_backlight = vlv_setup_backlight;
1373 		dev_priv->display.enable_backlight = vlv_enable_backlight;
1374 		dev_priv->display.disable_backlight = vlv_disable_backlight;
1375 		dev_priv->display.set_backlight = vlv_set_backlight;
1376 		dev_priv->display.get_backlight = vlv_get_backlight;
1377 	} else if (IS_GEN4(dev)) {
1378 		dev_priv->display.setup_backlight = i965_setup_backlight;
1379 		dev_priv->display.enable_backlight = i965_enable_backlight;
1380 		dev_priv->display.disable_backlight = i965_disable_backlight;
1381 		dev_priv->display.set_backlight = i9xx_set_backlight;
1382 		dev_priv->display.get_backlight = i9xx_get_backlight;
1383 	} else {
1384 		dev_priv->display.setup_backlight = i9xx_setup_backlight;
1385 		dev_priv->display.enable_backlight = i9xx_enable_backlight;
1386 		dev_priv->display.disable_backlight = i9xx_disable_backlight;
1387 		dev_priv->display.set_backlight = i9xx_set_backlight;
1388 		dev_priv->display.get_backlight = i9xx_get_backlight;
1389 	}
1390 }
1391 
1392 int intel_panel_init(struct intel_panel *panel,
1393 		     struct drm_display_mode *fixed_mode,
1394 		     struct drm_display_mode *downclock_mode)
1395 {
1396 	panel->fixed_mode = fixed_mode;
1397 	panel->downclock_mode = downclock_mode;
1398 
1399 	return 0;
1400 }
1401 
1402 void intel_panel_fini(struct intel_panel *panel)
1403 {
1404 	struct intel_connector *intel_connector =
1405 		container_of(panel, struct intel_connector, panel);
1406 
1407 	if (panel->fixed_mode)
1408 		drm_mode_destroy(intel_connector->base.dev, panel->fixed_mode);
1409 
1410 	if (panel->downclock_mode)
1411 		drm_mode_destroy(intel_connector->base.dev,
1412 				panel->downclock_mode);
1413 }
1414