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