Subversion Repositories Kolibri OS

Rev

Rev 3031 | 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 (IS_PINEVIEW(dev)) {
  197.                         max >>= 17;
  198.                 } else {
  199.                         max >>= 16;
  200.                         if (INTEL_INFO(dev)->gen < 4)
  201.                                 max &= ~1;
  202.                 }
  203.  
  204.                 if (is_backlight_combination_mode(dev))
  205.                         max *= 0xff;
  206.         }
  207.  
  208.         DRM_DEBUG_DRIVER("max backlight PWM = %d\n", max);
  209.         return max;
  210. }
  211.  
  212. u32 intel_panel_get_backlight(struct drm_device *dev)
  213. {
  214.         struct drm_i915_private *dev_priv = dev->dev_private;
  215.         u32 val;
  216.  
  217.         if (HAS_PCH_SPLIT(dev)) {
  218.                 val = I915_READ(BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
  219.         } else {
  220.                 val = I915_READ(BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
  221.                 if (IS_PINEVIEW(dev))
  222.                         val >>= 1;
  223.  
  224.                 if (is_backlight_combination_mode(dev)){
  225.                         u8 lbpc;
  226.  
  227.                         val &= ~1;
  228.                         pci_read_config_byte(dev->pdev, PCI_LBPC, &lbpc);
  229.                         val *= lbpc;
  230.                 }
  231.         }
  232.  
  233.         DRM_DEBUG_DRIVER("get backlight PWM = %d\n", val);
  234.         return val;
  235. }
  236.  
  237. static void intel_pch_panel_set_backlight(struct drm_device *dev, u32 level)
  238. {
  239.         struct drm_i915_private *dev_priv = dev->dev_private;
  240.         u32 val = I915_READ(BLC_PWM_CPU_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK;
  241.         I915_WRITE(BLC_PWM_CPU_CTL, val | level);
  242. }
  243.  
  244. void intel_panel_set_backlight(struct drm_device *dev, u32 level)
  245. {
  246.         struct drm_i915_private *dev_priv = dev->dev_private;
  247.         u32 tmp;
  248.  
  249.         DRM_DEBUG_DRIVER("set backlight PWM = %d\n", level);
  250.  
  251.         if (HAS_PCH_SPLIT(dev))
  252.                 return intel_pch_panel_set_backlight(dev, level);
  253.  
  254.         if (is_backlight_combination_mode(dev)){
  255.                 u32 max = intel_panel_get_max_backlight(dev);
  256.                 u8 lbpc;
  257.  
  258.                 lbpc = level * 0xfe / max + 1;
  259.                 level /= lbpc;
  260.                 pci_write_config_byte(dev->pdev, PCI_LBPC, lbpc);
  261.         }
  262.  
  263.         tmp = I915_READ(BLC_PWM_CTL);
  264.         if (IS_PINEVIEW(dev)) {
  265.                 tmp &= ~(BACKLIGHT_DUTY_CYCLE_MASK - 1);
  266.                 level <<= 1;
  267.         } else
  268.                 tmp &= ~BACKLIGHT_DUTY_CYCLE_MASK;
  269.         I915_WRITE(BLC_PWM_CTL, tmp | level);
  270. }
  271.  
  272. void intel_panel_disable_backlight(struct drm_device *dev)
  273. {
  274.         struct drm_i915_private *dev_priv = dev->dev_private;
  275.  
  276.         if (dev_priv->backlight_enabled) {
  277.                 dev_priv->backlight_level = intel_panel_get_backlight(dev);
  278.                 dev_priv->backlight_enabled = false;
  279.         }
  280.  
  281.         intel_panel_set_backlight(dev, 0);
  282. }
  283.  
  284. void intel_panel_enable_backlight(struct drm_device *dev)
  285. {
  286.         struct drm_i915_private *dev_priv = dev->dev_private;
  287.  
  288.         if (dev_priv->backlight_level == 0)
  289.                 dev_priv->backlight_level = intel_panel_get_max_backlight(dev);
  290.  
  291.         intel_panel_set_backlight(dev, dev_priv->backlight_level);
  292.         dev_priv->backlight_enabled = true;
  293. }
  294.  
  295. static void intel_panel_init_backlight(struct drm_device *dev)
  296. {
  297.         struct drm_i915_private *dev_priv = dev->dev_private;
  298.  
  299.         dev_priv->backlight_level = intel_panel_get_backlight(dev);
  300.         dev_priv->backlight_enabled = dev_priv->backlight_level != 0;
  301. }
  302.  
  303. enum drm_connector_status
  304. intel_panel_detect(struct drm_device *dev)
  305. {
  306. #if 0
  307.         struct drm_i915_private *dev_priv = dev->dev_private;
  308. #endif
  309.  
  310.         if (i915_panel_ignore_lid)
  311.                 return i915_panel_ignore_lid > 0 ?
  312.                         connector_status_connected :
  313.                         connector_status_disconnected;
  314.  
  315.         /* opregion lid state on HP 2540p is wrong at boot up,
  316.          * appears to be either the BIOS or Linux ACPI fault */
  317. #if 0
  318.         /* Assume that the BIOS does not lie through the OpRegion... */
  319.         if (dev_priv->opregion.lid_state)
  320.                 return ioread32(dev_priv->opregion.lid_state) & 0x1 ?
  321.                         connector_status_connected :
  322.                         connector_status_disconnected;
  323. #endif
  324.  
  325.         return connector_status_unknown;
  326. }
  327.  
  328. #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
  329. static int intel_panel_update_status(struct backlight_device *bd)
  330. {
  331.         struct drm_device *dev = bl_get_data(bd);
  332.         intel_panel_set_backlight(dev, bd->props.brightness);
  333.         return 0;
  334. }
  335.  
  336. static int intel_panel_get_brightness(struct backlight_device *bd)
  337. {
  338.         struct drm_device *dev = bl_get_data(bd);
  339.         return intel_panel_get_backlight(dev);
  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.