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