Subversion Repositories Kolibri OS

Rev

Rev 2330 | Rev 3037 | 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. #include "intel_drv.h"
  32.  
  33. static inline int pci_read_config_byte(struct pci_dev *dev, int where,
  34.                     u8 *val)
  35. {
  36.     *val = PciRead8(dev->busnr, dev->devfn, where);
  37.     return 1;
  38. }
  39.  
  40. static inline int pci_write_config_byte(struct pci_dev *dev, int where,
  41.                     u8 val)
  42. {
  43.     PciWrite8(dev->busnr, dev->devfn, where, val);
  44.     return 1;
  45. }
  46.  
  47.  
  48. #define PCI_LBPC 0xf4 /* legacy/combination backlight modes */
  49.  
  50. void
  51. intel_fixed_panel_mode(struct drm_display_mode *fixed_mode,
  52.                        struct drm_display_mode *adjusted_mode)
  53. {
  54.         adjusted_mode->hdisplay = fixed_mode->hdisplay;
  55.         adjusted_mode->hsync_start = fixed_mode->hsync_start;
  56.         adjusted_mode->hsync_end = fixed_mode->hsync_end;
  57.         adjusted_mode->htotal = fixed_mode->htotal;
  58.  
  59.         adjusted_mode->vdisplay = fixed_mode->vdisplay;
  60.         adjusted_mode->vsync_start = fixed_mode->vsync_start;
  61.         adjusted_mode->vsync_end = fixed_mode->vsync_end;
  62.         adjusted_mode->vtotal = fixed_mode->vtotal;
  63.  
  64.         adjusted_mode->clock = fixed_mode->clock;
  65.  
  66.         drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V);
  67. }
  68.  
  69. /* adjusted_mode has been preset to be the panel's fixed mode */
  70. void
  71. intel_pch_panel_fitting(struct drm_device *dev,
  72.                         int fitting_mode,
  73.                         struct drm_display_mode *mode,
  74.                         struct drm_display_mode *adjusted_mode)
  75. {
  76.         struct drm_i915_private *dev_priv = dev->dev_private;
  77.         int x, y, width, height;
  78.  
  79.         x = y = width = height = 0;
  80.  
  81.         /* Native modes don't need fitting */
  82.         if (adjusted_mode->hdisplay == mode->hdisplay &&
  83.             adjusted_mode->vdisplay == mode->vdisplay)
  84.                 goto done;
  85.  
  86.         switch (fitting_mode) {
  87.         case DRM_MODE_SCALE_CENTER:
  88.                 width = mode->hdisplay;
  89.                 height = mode->vdisplay;
  90.                 x = (adjusted_mode->hdisplay - width + 1)/2;
  91.                 y = (adjusted_mode->vdisplay - height + 1)/2;
  92.                 break;
  93.  
  94.         case DRM_MODE_SCALE_ASPECT:
  95.                 /* Scale but preserve the aspect ratio */
  96.                 {
  97.                         u32 scaled_width = adjusted_mode->hdisplay * mode->vdisplay;
  98.                         u32 scaled_height = mode->hdisplay * adjusted_mode->vdisplay;
  99.                         if (scaled_width > scaled_height) { /* pillar */
  100.                                 width = scaled_height / mode->vdisplay;
  101.                                 if (width & 1)
  102.                                         width++;
  103.                                 x = (adjusted_mode->hdisplay - width + 1) / 2;
  104.                                 y = 0;
  105.                                 height = adjusted_mode->vdisplay;
  106.                         } else if (scaled_width < scaled_height) { /* letter */
  107.                                 height = scaled_width / mode->hdisplay;
  108.                                 if (height & 1)
  109.                                     height++;
  110.                                 y = (adjusted_mode->vdisplay - height + 1) / 2;
  111.                                 x = 0;
  112.                                 width = adjusted_mode->hdisplay;
  113.                         } else {
  114.                                 x = y = 0;
  115.                                 width = adjusted_mode->hdisplay;
  116.                                 height = adjusted_mode->vdisplay;
  117.                         }
  118.                 }
  119.                 break;
  120.  
  121.         default:
  122.         case DRM_MODE_SCALE_FULLSCREEN:
  123.                 x = y = 0;
  124.                 width = adjusted_mode->hdisplay;
  125.                 height = adjusted_mode->vdisplay;
  126.                 break;
  127.         }
  128.  
  129. done:
  130.         dev_priv->pch_pf_pos = (x << 16) | y;
  131.         dev_priv->pch_pf_size = (width << 16) | height;
  132. }
  133.  
  134. static int is_backlight_combination_mode(struct drm_device *dev)
  135. {
  136.         struct drm_i915_private *dev_priv = dev->dev_private;
  137.  
  138.         if (INTEL_INFO(dev)->gen >= 4)
  139.                 return I915_READ(BLC_PWM_CTL2) & BLM_COMBINATION_MODE;
  140.  
  141.         if (IS_GEN2(dev))
  142.                 return I915_READ(BLC_PWM_CTL) & BLM_LEGACY_MODE;
  143.  
  144.         return 0;
  145. }
  146.  
  147. static u32 i915_read_blc_pwm_ctl(struct drm_i915_private *dev_priv)
  148. {
  149.         u32 val;
  150.  
  151.         /* Restore the CTL value if it lost, e.g. GPU reset */
  152.  
  153.         if (HAS_PCH_SPLIT(dev_priv->dev)) {
  154.                 val = I915_READ(BLC_PWM_PCH_CTL2);
  155.                 if (dev_priv->saveBLC_PWM_CTL2 == 0) {
  156.                         dev_priv->saveBLC_PWM_CTL2 = val;
  157.                 } else if (val == 0) {
  158.                         I915_WRITE(BLC_PWM_PCH_CTL2,
  159.                                    dev_priv->saveBLC_PWM_CTL);
  160.                         val = dev_priv->saveBLC_PWM_CTL;
  161.                 }
  162.         } else {
  163.                 val = I915_READ(BLC_PWM_CTL);
  164.                 if (dev_priv->saveBLC_PWM_CTL == 0) {
  165.                         dev_priv->saveBLC_PWM_CTL = val;
  166.                         dev_priv->saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_CTL2);
  167.                 } else if (val == 0) {
  168.                         I915_WRITE(BLC_PWM_CTL,
  169.                                    dev_priv->saveBLC_PWM_CTL);
  170.                         I915_WRITE(BLC_PWM_CTL2,
  171.                                    dev_priv->saveBLC_PWM_CTL2);
  172.                         val = dev_priv->saveBLC_PWM_CTL;
  173.                 }
  174.         }
  175.  
  176.         return val;
  177. }
  178.  
  179. u32 intel_panel_get_max_backlight(struct drm_device *dev)
  180. {
  181.         struct drm_i915_private *dev_priv = dev->dev_private;
  182.         u32 max;
  183.  
  184.         max = i915_read_blc_pwm_ctl(dev_priv);
  185.         if (max == 0) {
  186.                 /* XXX add code here to query mode clock or hardware clock
  187.                  * and program max PWM appropriately.
  188.                  */
  189.         printk(KERN_WARNING "fixme: max PWM is zero.\n");
  190.                 return 1;
  191.         }
  192.  
  193.         if (HAS_PCH_SPLIT(dev)) {
  194.                 max >>= 16;
  195.         } else {
  196.                 if (INTEL_INFO(dev)->gen < 4)
  197.                         max >>= 17;
  198.                 else
  199.                         max >>= 16;
  200.  
  201.                 if (is_backlight_combination_mode(dev))
  202.                         max *= 0xff;
  203.         }
  204.  
  205.         DRM_DEBUG_DRIVER("max backlight PWM = %d\n", max);
  206.         return max;
  207. }
  208.  
  209. u32 intel_panel_get_backlight(struct drm_device *dev)
  210. {
  211.         struct drm_i915_private *dev_priv = dev->dev_private;
  212.         u32 val;
  213.  
  214.         if (HAS_PCH_SPLIT(dev)) {
  215.                 val = I915_READ(BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
  216.         } else {
  217.                 val = I915_READ(BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
  218.                 if (INTEL_INFO(dev)->gen < 4)
  219.                         val >>= 1;
  220.  
  221.                 if (is_backlight_combination_mode(dev)) {
  222.                         u8 lbpc;
  223.  
  224.                         pci_read_config_byte(dev->pdev, PCI_LBPC, &lbpc);
  225.                         val *= lbpc;
  226.                 }
  227.         }
  228.  
  229.         DRM_DEBUG_DRIVER("get backlight PWM = %d\n", val);
  230.         return val;
  231. }
  232.  
  233. static void intel_pch_panel_set_backlight(struct drm_device *dev, u32 level)
  234. {
  235.         struct drm_i915_private *dev_priv = dev->dev_private;
  236.         u32 val = I915_READ(BLC_PWM_CPU_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK;
  237.         I915_WRITE(BLC_PWM_CPU_CTL, val | level);
  238. }
  239.  
  240. static void intel_panel_actually_set_backlight(struct drm_device *dev, u32 level)
  241. {
  242.         struct drm_i915_private *dev_priv = dev->dev_private;
  243.         u32 tmp;
  244.  
  245.         DRM_DEBUG_DRIVER("set backlight PWM = %d\n", level);
  246.  
  247.         if (HAS_PCH_SPLIT(dev))
  248.                 return intel_pch_panel_set_backlight(dev, level);
  249.  
  250.         if (is_backlight_combination_mode(dev)) {
  251.                 u32 max = intel_panel_get_max_backlight(dev);
  252.                 u8 lbpc;
  253.  
  254.                 lbpc = level * 0xfe / max + 1;
  255.                 level /= lbpc;
  256.                 pci_write_config_byte(dev->pdev, PCI_LBPC, lbpc);
  257.         }
  258.  
  259.         tmp = I915_READ(BLC_PWM_CTL);
  260.         if (INTEL_INFO(dev)->gen < 4)
  261.                 level <<= 1;
  262.                 tmp &= ~BACKLIGHT_DUTY_CYCLE_MASK;
  263.         I915_WRITE(BLC_PWM_CTL, tmp | level);
  264. }
  265.  
  266. void intel_panel_set_backlight(struct drm_device *dev, u32 level)
  267. {
  268.         struct drm_i915_private *dev_priv = dev->dev_private;
  269.  
  270.         dev_priv->backlight_level = level;
  271.         if (dev_priv->backlight_enabled)
  272.                 intel_panel_actually_set_backlight(dev, level);
  273. }
  274.  
  275. void intel_panel_disable_backlight(struct drm_device *dev)
  276. {
  277.         struct drm_i915_private *dev_priv = dev->dev_private;
  278.  
  279.                 dev_priv->backlight_enabled = false;
  280.         intel_panel_actually_set_backlight(dev, 0);
  281. }
  282.  
  283. void intel_panel_enable_backlight(struct drm_device *dev)
  284. {
  285.         struct drm_i915_private *dev_priv = dev->dev_private;
  286.  
  287.         if (dev_priv->backlight_level == 0)
  288.                 dev_priv->backlight_level = intel_panel_get_max_backlight(dev);
  289.  
  290.         dev_priv->backlight_enabled = true;
  291.         intel_panel_actually_set_backlight(dev, dev_priv->backlight_level);
  292. }
  293.  
  294. static void intel_panel_init_backlight(struct drm_device *dev)
  295. {
  296.         struct drm_i915_private *dev_priv = dev->dev_private;
  297.  
  298.         dev_priv->backlight_level = intel_panel_get_backlight(dev);
  299.         dev_priv->backlight_enabled = dev_priv->backlight_level != 0;
  300. }
  301.  
  302. enum drm_connector_status
  303. intel_panel_detect(struct drm_device *dev)
  304. {
  305. #if 0
  306.         struct drm_i915_private *dev_priv = dev->dev_private;
  307. #endif
  308.  
  309.         if (i915_panel_ignore_lid)
  310.                 return i915_panel_ignore_lid > 0 ?
  311.                         connector_status_connected :
  312.                         connector_status_disconnected;
  313.  
  314.         /* opregion lid state on HP 2540p is wrong at boot up,
  315.          * appears to be either the BIOS or Linux ACPI fault */
  316. #if 0
  317.         /* Assume that the BIOS does not lie through the OpRegion... */
  318.         if (dev_priv->opregion.lid_state)
  319.                 return ioread32(dev_priv->opregion.lid_state) & 0x1 ?
  320.                         connector_status_connected :
  321.                         connector_status_disconnected;
  322. #endif
  323.  
  324.         return connector_status_unknown;
  325. }
  326.  
  327. #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
  328. static int intel_panel_update_status(struct backlight_device *bd)
  329. {
  330.         struct drm_device *dev = bl_get_data(bd);
  331.         intel_panel_set_backlight(dev, bd->props.brightness);
  332.         return 0;
  333. }
  334.  
  335. static int intel_panel_get_brightness(struct backlight_device *bd)
  336. {
  337.         struct drm_device *dev = bl_get_data(bd);
  338.         struct drm_i915_private *dev_priv = dev->dev_private;
  339.         return dev_priv->backlight_level;
  340. }
  341.  
  342. static const struct backlight_ops intel_panel_bl_ops = {
  343.         .update_status = intel_panel_update_status,
  344.         .get_brightness = intel_panel_get_brightness,
  345. };
  346.  
  347. int intel_panel_setup_backlight(struct drm_device *dev)
  348. {
  349.         struct drm_i915_private *dev_priv = dev->dev_private;
  350.         struct backlight_properties props;
  351.         struct drm_connector *connector;
  352.  
  353.         intel_panel_init_backlight(dev);
  354.  
  355.         if (dev_priv->int_lvds_connector)
  356.                 connector = dev_priv->int_lvds_connector;
  357.         else if (dev_priv->int_edp_connector)
  358.                 connector = dev_priv->int_edp_connector;
  359.         else
  360.                 return -ENODEV;
  361.  
  362.         props.type = BACKLIGHT_RAW;
  363.         props.max_brightness = intel_panel_get_max_backlight(dev);
  364.         dev_priv->backlight =
  365.                 backlight_device_register("intel_backlight",
  366.                                           &connector->kdev, dev,
  367.                                           &intel_panel_bl_ops, &props);
  368.  
  369.         if (IS_ERR(dev_priv->backlight)) {
  370.                 DRM_ERROR("Failed to register backlight: %ld\n",
  371.                           PTR_ERR(dev_priv->backlight));
  372.                 dev_priv->backlight = NULL;
  373.                 return -ENODEV;
  374.         }
  375.         dev_priv->backlight->props.brightness = intel_panel_get_backlight(dev);
  376.         return 0;
  377. }
  378.  
  379. void intel_panel_destroy_backlight(struct drm_device *dev)
  380. {
  381.         struct drm_i915_private *dev_priv = dev->dev_private;
  382.         if (dev_priv->backlight)
  383.                 backlight_device_unregister(dev_priv->backlight);
  384. }
  385. #else
  386. int intel_panel_setup_backlight(struct drm_device *dev)
  387. {
  388.         intel_panel_init_backlight(dev);
  389.         return 0;
  390. }
  391.  
  392. void intel_panel_destroy_backlight(struct drm_device *dev)
  393. {
  394.         return;
  395. }
  396. #endif
  397.