Subversion Repositories Kolibri OS

Rev

Rev 4104 | Rev 5060 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

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