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