Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v3.16 1221 lines 37 kB view raw
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 36void 37intel_fixed_panel_mode(const struct drm_display_mode *fixed_mode, 38 struct drm_display_mode *adjusted_mode) 39{ 40 drm_mode_copy(adjusted_mode, fixed_mode); 41 42 drm_mode_set_crtcinfo(adjusted_mode, 0); 43} 44 45/** 46 * intel_find_panel_downclock - find the reduced downclock for LVDS in EDID 47 * @dev: drm device 48 * @fixed_mode : panel native mode 49 * @connector: LVDS/eDP connector 50 * 51 * Return downclock_avail 52 * Find the reduced downclock for LVDS/eDP in EDID. 53 */ 54struct drm_display_mode * 55intel_find_panel_downclock(struct drm_device *dev, 56 struct drm_display_mode *fixed_mode, 57 struct drm_connector *connector) 58{ 59 struct drm_display_mode *scan, *tmp_mode; 60 int temp_downclock; 61 62 temp_downclock = fixed_mode->clock; 63 tmp_mode = NULL; 64 65 list_for_each_entry(scan, &connector->probed_modes, head) { 66 /* 67 * If one mode has the same resolution with the fixed_panel 68 * mode while they have the different refresh rate, it means 69 * that the reduced downclock is found. In such 70 * case we can set the different FPx0/1 to dynamically select 71 * between low and high frequency. 72 */ 73 if (scan->hdisplay == fixed_mode->hdisplay && 74 scan->hsync_start == fixed_mode->hsync_start && 75 scan->hsync_end == fixed_mode->hsync_end && 76 scan->htotal == fixed_mode->htotal && 77 scan->vdisplay == fixed_mode->vdisplay && 78 scan->vsync_start == fixed_mode->vsync_start && 79 scan->vsync_end == fixed_mode->vsync_end && 80 scan->vtotal == fixed_mode->vtotal) { 81 if (scan->clock < temp_downclock) { 82 /* 83 * The downclock is already found. But we 84 * expect to find the lower downclock. 85 */ 86 temp_downclock = scan->clock; 87 tmp_mode = scan; 88 } 89 } 90 } 91 92 if (temp_downclock < fixed_mode->clock) 93 return drm_mode_duplicate(dev, tmp_mode); 94 else 95 return NULL; 96} 97 98/* adjusted_mode has been preset to be the panel's fixed mode */ 99void 100intel_pch_panel_fitting(struct intel_crtc *intel_crtc, 101 struct intel_crtc_config *pipe_config, 102 int fitting_mode) 103{ 104 struct drm_display_mode *adjusted_mode; 105 int x, y, width, height; 106 107 adjusted_mode = &pipe_config->adjusted_mode; 108 109 x = y = width = height = 0; 110 111 /* Native modes don't need fitting */ 112 if (adjusted_mode->hdisplay == pipe_config->pipe_src_w && 113 adjusted_mode->vdisplay == pipe_config->pipe_src_h) 114 goto done; 115 116 switch (fitting_mode) { 117 case DRM_MODE_SCALE_CENTER: 118 width = pipe_config->pipe_src_w; 119 height = pipe_config->pipe_src_h; 120 x = (adjusted_mode->hdisplay - width + 1)/2; 121 y = (adjusted_mode->vdisplay - height + 1)/2; 122 break; 123 124 case DRM_MODE_SCALE_ASPECT: 125 /* Scale but preserve the aspect ratio */ 126 { 127 u32 scaled_width = adjusted_mode->hdisplay 128 * pipe_config->pipe_src_h; 129 u32 scaled_height = pipe_config->pipe_src_w 130 * adjusted_mode->vdisplay; 131 if (scaled_width > scaled_height) { /* pillar */ 132 width = scaled_height / pipe_config->pipe_src_h; 133 if (width & 1) 134 width++; 135 x = (adjusted_mode->hdisplay - width + 1) / 2; 136 y = 0; 137 height = adjusted_mode->vdisplay; 138 } else if (scaled_width < scaled_height) { /* letter */ 139 height = scaled_width / pipe_config->pipe_src_w; 140 if (height & 1) 141 height++; 142 y = (adjusted_mode->vdisplay - height + 1) / 2; 143 x = 0; 144 width = adjusted_mode->hdisplay; 145 } else { 146 x = y = 0; 147 width = adjusted_mode->hdisplay; 148 height = adjusted_mode->vdisplay; 149 } 150 } 151 break; 152 153 case DRM_MODE_SCALE_FULLSCREEN: 154 x = y = 0; 155 width = adjusted_mode->hdisplay; 156 height = adjusted_mode->vdisplay; 157 break; 158 159 default: 160 WARN(1, "bad panel fit mode: %d\n", fitting_mode); 161 return; 162 } 163 164done: 165 pipe_config->pch_pfit.pos = (x << 16) | y; 166 pipe_config->pch_pfit.size = (width << 16) | height; 167 pipe_config->pch_pfit.enabled = pipe_config->pch_pfit.size != 0; 168} 169 170static void 171centre_horizontally(struct drm_display_mode *mode, 172 int width) 173{ 174 u32 border, sync_pos, blank_width, sync_width; 175 176 /* keep the hsync and hblank widths constant */ 177 sync_width = mode->crtc_hsync_end - mode->crtc_hsync_start; 178 blank_width = mode->crtc_hblank_end - mode->crtc_hblank_start; 179 sync_pos = (blank_width - sync_width + 1) / 2; 180 181 border = (mode->hdisplay - width + 1) / 2; 182 border += border & 1; /* make the border even */ 183 184 mode->crtc_hdisplay = width; 185 mode->crtc_hblank_start = width + border; 186 mode->crtc_hblank_end = mode->crtc_hblank_start + blank_width; 187 188 mode->crtc_hsync_start = mode->crtc_hblank_start + sync_pos; 189 mode->crtc_hsync_end = mode->crtc_hsync_start + sync_width; 190} 191 192static void 193centre_vertically(struct drm_display_mode *mode, 194 int height) 195{ 196 u32 border, sync_pos, blank_width, sync_width; 197 198 /* keep the vsync and vblank widths constant */ 199 sync_width = mode->crtc_vsync_end - mode->crtc_vsync_start; 200 blank_width = mode->crtc_vblank_end - mode->crtc_vblank_start; 201 sync_pos = (blank_width - sync_width + 1) / 2; 202 203 border = (mode->vdisplay - height + 1) / 2; 204 205 mode->crtc_vdisplay = height; 206 mode->crtc_vblank_start = height + border; 207 mode->crtc_vblank_end = mode->crtc_vblank_start + blank_width; 208 209 mode->crtc_vsync_start = mode->crtc_vblank_start + sync_pos; 210 mode->crtc_vsync_end = mode->crtc_vsync_start + sync_width; 211} 212 213static inline u32 panel_fitter_scaling(u32 source, u32 target) 214{ 215 /* 216 * Floating point operation is not supported. So the FACTOR 217 * is defined, which can avoid the floating point computation 218 * when calculating the panel ratio. 219 */ 220#define ACCURACY 12 221#define FACTOR (1 << ACCURACY) 222 u32 ratio = source * FACTOR / target; 223 return (FACTOR * ratio + FACTOR/2) / FACTOR; 224} 225 226static void i965_scale_aspect(struct intel_crtc_config *pipe_config, 227 u32 *pfit_control) 228{ 229 struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; 230 u32 scaled_width = adjusted_mode->hdisplay * 231 pipe_config->pipe_src_h; 232 u32 scaled_height = pipe_config->pipe_src_w * 233 adjusted_mode->vdisplay; 234 235 /* 965+ is easy, it does everything in hw */ 236 if (scaled_width > scaled_height) 237 *pfit_control |= PFIT_ENABLE | 238 PFIT_SCALING_PILLAR; 239 else if (scaled_width < scaled_height) 240 *pfit_control |= PFIT_ENABLE | 241 PFIT_SCALING_LETTER; 242 else if (adjusted_mode->hdisplay != pipe_config->pipe_src_w) 243 *pfit_control |= PFIT_ENABLE | PFIT_SCALING_AUTO; 244} 245 246static void i9xx_scale_aspect(struct intel_crtc_config *pipe_config, 247 u32 *pfit_control, u32 *pfit_pgm_ratios, 248 u32 *border) 249{ 250 struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; 251 u32 scaled_width = adjusted_mode->hdisplay * 252 pipe_config->pipe_src_h; 253 u32 scaled_height = pipe_config->pipe_src_w * 254 adjusted_mode->vdisplay; 255 u32 bits; 256 257 /* 258 * For earlier chips we have to calculate the scaling 259 * ratio by hand and program it into the 260 * PFIT_PGM_RATIO register 261 */ 262 if (scaled_width > scaled_height) { /* pillar */ 263 centre_horizontally(adjusted_mode, 264 scaled_height / 265 pipe_config->pipe_src_h); 266 267 *border = LVDS_BORDER_ENABLE; 268 if (pipe_config->pipe_src_h != adjusted_mode->vdisplay) { 269 bits = panel_fitter_scaling(pipe_config->pipe_src_h, 270 adjusted_mode->vdisplay); 271 272 *pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT | 273 bits << PFIT_VERT_SCALE_SHIFT); 274 *pfit_control |= (PFIT_ENABLE | 275 VERT_INTERP_BILINEAR | 276 HORIZ_INTERP_BILINEAR); 277 } 278 } else if (scaled_width < scaled_height) { /* letter */ 279 centre_vertically(adjusted_mode, 280 scaled_width / 281 pipe_config->pipe_src_w); 282 283 *border = LVDS_BORDER_ENABLE; 284 if (pipe_config->pipe_src_w != adjusted_mode->hdisplay) { 285 bits = panel_fitter_scaling(pipe_config->pipe_src_w, 286 adjusted_mode->hdisplay); 287 288 *pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT | 289 bits << PFIT_VERT_SCALE_SHIFT); 290 *pfit_control |= (PFIT_ENABLE | 291 VERT_INTERP_BILINEAR | 292 HORIZ_INTERP_BILINEAR); 293 } 294 } else { 295 /* Aspects match, Let hw scale both directions */ 296 *pfit_control |= (PFIT_ENABLE | 297 VERT_AUTO_SCALE | HORIZ_AUTO_SCALE | 298 VERT_INTERP_BILINEAR | 299 HORIZ_INTERP_BILINEAR); 300 } 301} 302 303void intel_gmch_panel_fitting(struct intel_crtc *intel_crtc, 304 struct intel_crtc_config *pipe_config, 305 int fitting_mode) 306{ 307 struct drm_device *dev = intel_crtc->base.dev; 308 u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0; 309 struct drm_display_mode *adjusted_mode; 310 311 adjusted_mode = &pipe_config->adjusted_mode; 312 313 /* Native modes don't need fitting */ 314 if (adjusted_mode->hdisplay == pipe_config->pipe_src_w && 315 adjusted_mode->vdisplay == pipe_config->pipe_src_h) 316 goto out; 317 318 switch (fitting_mode) { 319 case DRM_MODE_SCALE_CENTER: 320 /* 321 * For centered modes, we have to calculate border widths & 322 * heights and modify the values programmed into the CRTC. 323 */ 324 centre_horizontally(adjusted_mode, pipe_config->pipe_src_w); 325 centre_vertically(adjusted_mode, pipe_config->pipe_src_h); 326 border = LVDS_BORDER_ENABLE; 327 break; 328 case DRM_MODE_SCALE_ASPECT: 329 /* Scale but preserve the aspect ratio */ 330 if (INTEL_INFO(dev)->gen >= 4) 331 i965_scale_aspect(pipe_config, &pfit_control); 332 else 333 i9xx_scale_aspect(pipe_config, &pfit_control, 334 &pfit_pgm_ratios, &border); 335 break; 336 case DRM_MODE_SCALE_FULLSCREEN: 337 /* 338 * Full scaling, even if it changes the aspect ratio. 339 * Fortunately this is all done for us in hw. 340 */ 341 if (pipe_config->pipe_src_h != adjusted_mode->vdisplay || 342 pipe_config->pipe_src_w != adjusted_mode->hdisplay) { 343 pfit_control |= PFIT_ENABLE; 344 if (INTEL_INFO(dev)->gen >= 4) 345 pfit_control |= PFIT_SCALING_AUTO; 346 else 347 pfit_control |= (VERT_AUTO_SCALE | 348 VERT_INTERP_BILINEAR | 349 HORIZ_AUTO_SCALE | 350 HORIZ_INTERP_BILINEAR); 351 } 352 break; 353 default: 354 WARN(1, "bad panel fit mode: %d\n", fitting_mode); 355 return; 356 } 357 358 /* 965+ wants fuzzy fitting */ 359 /* FIXME: handle multiple panels by failing gracefully */ 360 if (INTEL_INFO(dev)->gen >= 4) 361 pfit_control |= ((intel_crtc->pipe << PFIT_PIPE_SHIFT) | 362 PFIT_FILTER_FUZZY); 363 364out: 365 if ((pfit_control & PFIT_ENABLE) == 0) { 366 pfit_control = 0; 367 pfit_pgm_ratios = 0; 368 } 369 370 /* Make sure pre-965 set dither correctly for 18bpp panels. */ 371 if (INTEL_INFO(dev)->gen < 4 && pipe_config->pipe_bpp == 18) 372 pfit_control |= PANEL_8TO6_DITHER_ENABLE; 373 374 pipe_config->gmch_pfit.control = pfit_control; 375 pipe_config->gmch_pfit.pgm_ratios = pfit_pgm_ratios; 376 pipe_config->gmch_pfit.lvds_border_bits = border; 377} 378 379enum drm_connector_status 380intel_panel_detect(struct drm_device *dev) 381{ 382 struct drm_i915_private *dev_priv = dev->dev_private; 383 384 /* Assume that the BIOS does not lie through the OpRegion... */ 385 if (!i915.panel_ignore_lid && dev_priv->opregion.lid_state) { 386 return ioread32(dev_priv->opregion.lid_state) & 0x1 ? 387 connector_status_connected : 388 connector_status_disconnected; 389 } 390 391 switch (i915.panel_ignore_lid) { 392 case -2: 393 return connector_status_connected; 394 case -1: 395 return connector_status_disconnected; 396 default: 397 return connector_status_unknown; 398 } 399} 400 401static u32 intel_panel_compute_brightness(struct intel_connector *connector, 402 u32 val) 403{ 404 struct drm_device *dev = connector->base.dev; 405 struct drm_i915_private *dev_priv = dev->dev_private; 406 struct intel_panel *panel = &connector->panel; 407 408 WARN_ON(panel->backlight.max == 0); 409 410 if (i915.invert_brightness < 0) 411 return val; 412 413 if (i915.invert_brightness > 0 || 414 dev_priv->quirks & QUIRK_INVERT_BRIGHTNESS) { 415 return panel->backlight.max - val; 416 } 417 418 return val; 419} 420 421static u32 bdw_get_backlight(struct intel_connector *connector) 422{ 423 struct drm_device *dev = connector->base.dev; 424 struct drm_i915_private *dev_priv = dev->dev_private; 425 426 return I915_READ(BLC_PWM_PCH_CTL2) & BACKLIGHT_DUTY_CYCLE_MASK; 427} 428 429static u32 pch_get_backlight(struct intel_connector *connector) 430{ 431 struct drm_device *dev = connector->base.dev; 432 struct drm_i915_private *dev_priv = dev->dev_private; 433 434 return I915_READ(BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; 435} 436 437static u32 i9xx_get_backlight(struct intel_connector *connector) 438{ 439 struct drm_device *dev = connector->base.dev; 440 struct drm_i915_private *dev_priv = dev->dev_private; 441 struct intel_panel *panel = &connector->panel; 442 u32 val; 443 444 val = I915_READ(BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; 445 if (INTEL_INFO(dev)->gen < 4) 446 val >>= 1; 447 448 if (panel->backlight.combination_mode) { 449 u8 lbpc; 450 451 pci_read_config_byte(dev->pdev, PCI_LBPC, &lbpc); 452 val *= lbpc; 453 } 454 455 return val; 456} 457 458static u32 _vlv_get_backlight(struct drm_device *dev, enum pipe pipe) 459{ 460 struct drm_i915_private *dev_priv = dev->dev_private; 461 462 return I915_READ(VLV_BLC_PWM_CTL(pipe)) & BACKLIGHT_DUTY_CYCLE_MASK; 463} 464 465static u32 vlv_get_backlight(struct intel_connector *connector) 466{ 467 struct drm_device *dev = connector->base.dev; 468 enum pipe pipe = intel_get_pipe_from_connector(connector); 469 470 return _vlv_get_backlight(dev, pipe); 471} 472 473static u32 intel_panel_get_backlight(struct intel_connector *connector) 474{ 475 struct drm_device *dev = connector->base.dev; 476 struct drm_i915_private *dev_priv = dev->dev_private; 477 u32 val; 478 unsigned long flags; 479 480 spin_lock_irqsave(&dev_priv->backlight_lock, flags); 481 482 val = dev_priv->display.get_backlight(connector); 483 val = intel_panel_compute_brightness(connector, val); 484 485 spin_unlock_irqrestore(&dev_priv->backlight_lock, flags); 486 487 DRM_DEBUG_DRIVER("get backlight PWM = %d\n", val); 488 return val; 489} 490 491static void bdw_set_backlight(struct intel_connector *connector, u32 level) 492{ 493 struct drm_device *dev = connector->base.dev; 494 struct drm_i915_private *dev_priv = dev->dev_private; 495 u32 val = I915_READ(BLC_PWM_PCH_CTL2) & ~BACKLIGHT_DUTY_CYCLE_MASK; 496 I915_WRITE(BLC_PWM_PCH_CTL2, val | level); 497} 498 499static void pch_set_backlight(struct intel_connector *connector, u32 level) 500{ 501 struct drm_device *dev = connector->base.dev; 502 struct drm_i915_private *dev_priv = dev->dev_private; 503 u32 tmp; 504 505 tmp = I915_READ(BLC_PWM_CPU_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK; 506 I915_WRITE(BLC_PWM_CPU_CTL, tmp | level); 507} 508 509static void i9xx_set_backlight(struct intel_connector *connector, u32 level) 510{ 511 struct drm_device *dev = connector->base.dev; 512 struct drm_i915_private *dev_priv = dev->dev_private; 513 struct intel_panel *panel = &connector->panel; 514 u32 tmp, mask; 515 516 WARN_ON(panel->backlight.max == 0); 517 518 if (panel->backlight.combination_mode) { 519 u8 lbpc; 520 521 lbpc = level * 0xfe / panel->backlight.max + 1; 522 level /= lbpc; 523 pci_write_config_byte(dev->pdev, PCI_LBPC, lbpc); 524 } 525 526 if (IS_GEN4(dev)) { 527 mask = BACKLIGHT_DUTY_CYCLE_MASK; 528 } else { 529 level <<= 1; 530 mask = BACKLIGHT_DUTY_CYCLE_MASK_PNV; 531 } 532 533 tmp = I915_READ(BLC_PWM_CTL) & ~mask; 534 I915_WRITE(BLC_PWM_CTL, tmp | level); 535} 536 537static void vlv_set_backlight(struct intel_connector *connector, u32 level) 538{ 539 struct drm_device *dev = connector->base.dev; 540 struct drm_i915_private *dev_priv = dev->dev_private; 541 enum pipe pipe = intel_get_pipe_from_connector(connector); 542 u32 tmp; 543 544 tmp = I915_READ(VLV_BLC_PWM_CTL(pipe)) & ~BACKLIGHT_DUTY_CYCLE_MASK; 545 I915_WRITE(VLV_BLC_PWM_CTL(pipe), tmp | level); 546} 547 548static void 549intel_panel_actually_set_backlight(struct intel_connector *connector, u32 level) 550{ 551 struct drm_device *dev = connector->base.dev; 552 struct drm_i915_private *dev_priv = dev->dev_private; 553 554 DRM_DEBUG_DRIVER("set backlight PWM = %d\n", level); 555 556 level = intel_panel_compute_brightness(connector, level); 557 dev_priv->display.set_backlight(connector, level); 558} 559 560/* set backlight brightness to level in range [0..max] */ 561void intel_panel_set_backlight(struct intel_connector *connector, u32 level, 562 u32 max) 563{ 564 struct drm_device *dev = connector->base.dev; 565 struct drm_i915_private *dev_priv = dev->dev_private; 566 struct intel_panel *panel = &connector->panel; 567 enum pipe pipe = intel_get_pipe_from_connector(connector); 568 u32 freq; 569 unsigned long flags; 570 u64 n; 571 572 if (!panel->backlight.present || pipe == INVALID_PIPE) 573 return; 574 575 spin_lock_irqsave(&dev_priv->backlight_lock, flags); 576 577 WARN_ON(panel->backlight.max == 0); 578 579 /* scale to hardware max, but be careful to not overflow */ 580 freq = panel->backlight.max; 581 n = (u64)level * freq; 582 do_div(n, max); 583 level = n; 584 585 panel->backlight.level = level; 586 if (panel->backlight.device) 587 panel->backlight.device->props.brightness = level; 588 589 if (panel->backlight.enabled) 590 intel_panel_actually_set_backlight(connector, level); 591 592 spin_unlock_irqrestore(&dev_priv->backlight_lock, flags); 593} 594 595static void pch_disable_backlight(struct intel_connector *connector) 596{ 597 struct drm_device *dev = connector->base.dev; 598 struct drm_i915_private *dev_priv = dev->dev_private; 599 u32 tmp; 600 601 intel_panel_actually_set_backlight(connector, 0); 602 603 tmp = I915_READ(BLC_PWM_CPU_CTL2); 604 I915_WRITE(BLC_PWM_CPU_CTL2, tmp & ~BLM_PWM_ENABLE); 605 606 tmp = I915_READ(BLC_PWM_PCH_CTL1); 607 I915_WRITE(BLC_PWM_PCH_CTL1, tmp & ~BLM_PCH_PWM_ENABLE); 608} 609 610static void i9xx_disable_backlight(struct intel_connector *connector) 611{ 612 intel_panel_actually_set_backlight(connector, 0); 613} 614 615static void i965_disable_backlight(struct intel_connector *connector) 616{ 617 struct drm_device *dev = connector->base.dev; 618 struct drm_i915_private *dev_priv = dev->dev_private; 619 u32 tmp; 620 621 intel_panel_actually_set_backlight(connector, 0); 622 623 tmp = I915_READ(BLC_PWM_CTL2); 624 I915_WRITE(BLC_PWM_CTL2, tmp & ~BLM_PWM_ENABLE); 625} 626 627static void vlv_disable_backlight(struct intel_connector *connector) 628{ 629 struct drm_device *dev = connector->base.dev; 630 struct drm_i915_private *dev_priv = dev->dev_private; 631 enum pipe pipe = intel_get_pipe_from_connector(connector); 632 u32 tmp; 633 634 intel_panel_actually_set_backlight(connector, 0); 635 636 tmp = I915_READ(VLV_BLC_PWM_CTL2(pipe)); 637 I915_WRITE(VLV_BLC_PWM_CTL2(pipe), tmp & ~BLM_PWM_ENABLE); 638} 639 640void intel_panel_disable_backlight(struct intel_connector *connector) 641{ 642 struct drm_device *dev = connector->base.dev; 643 struct drm_i915_private *dev_priv = dev->dev_private; 644 struct intel_panel *panel = &connector->panel; 645 enum pipe pipe = intel_get_pipe_from_connector(connector); 646 unsigned long flags; 647 648 if (!panel->backlight.present || pipe == INVALID_PIPE) 649 return; 650 651 /* 652 * Do not disable backlight on the vgaswitcheroo path. When switching 653 * away from i915, the other client may depend on i915 to handle the 654 * backlight. This will leave the backlight on unnecessarily when 655 * another client is not activated. 656 */ 657 if (dev->switch_power_state == DRM_SWITCH_POWER_CHANGING) { 658 DRM_DEBUG_DRIVER("Skipping backlight disable on vga switch\n"); 659 return; 660 } 661 662 spin_lock_irqsave(&dev_priv->backlight_lock, flags); 663 664 panel->backlight.enabled = false; 665 dev_priv->display.disable_backlight(connector); 666 667 spin_unlock_irqrestore(&dev_priv->backlight_lock, flags); 668} 669 670static void bdw_enable_backlight(struct intel_connector *connector) 671{ 672 struct drm_device *dev = connector->base.dev; 673 struct drm_i915_private *dev_priv = dev->dev_private; 674 struct intel_panel *panel = &connector->panel; 675 u32 pch_ctl1, pch_ctl2; 676 677 pch_ctl1 = I915_READ(BLC_PWM_PCH_CTL1); 678 if (pch_ctl1 & BLM_PCH_PWM_ENABLE) { 679 DRM_DEBUG_KMS("pch backlight already enabled\n"); 680 pch_ctl1 &= ~BLM_PCH_PWM_ENABLE; 681 I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1); 682 } 683 684 pch_ctl2 = panel->backlight.max << 16; 685 I915_WRITE(BLC_PWM_PCH_CTL2, pch_ctl2); 686 687 pch_ctl1 = 0; 688 if (panel->backlight.active_low_pwm) 689 pch_ctl1 |= BLM_PCH_POLARITY; 690 691 /* BDW always uses the pch pwm controls. */ 692 pch_ctl1 |= BLM_PCH_OVERRIDE_ENABLE; 693 694 I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1); 695 POSTING_READ(BLC_PWM_PCH_CTL1); 696 I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1 | BLM_PCH_PWM_ENABLE); 697 698 /* This won't stick until the above enable. */ 699 intel_panel_actually_set_backlight(connector, panel->backlight.level); 700} 701 702static void pch_enable_backlight(struct intel_connector *connector) 703{ 704 struct drm_device *dev = connector->base.dev; 705 struct drm_i915_private *dev_priv = dev->dev_private; 706 struct intel_panel *panel = &connector->panel; 707 enum pipe pipe = intel_get_pipe_from_connector(connector); 708 enum transcoder cpu_transcoder = 709 intel_pipe_to_cpu_transcoder(dev_priv, pipe); 710 u32 cpu_ctl2, pch_ctl1, pch_ctl2; 711 712 cpu_ctl2 = I915_READ(BLC_PWM_CPU_CTL2); 713 if (cpu_ctl2 & BLM_PWM_ENABLE) { 714 WARN(1, "cpu backlight already enabled\n"); 715 cpu_ctl2 &= ~BLM_PWM_ENABLE; 716 I915_WRITE(BLC_PWM_CPU_CTL2, cpu_ctl2); 717 } 718 719 pch_ctl1 = I915_READ(BLC_PWM_PCH_CTL1); 720 if (pch_ctl1 & BLM_PCH_PWM_ENABLE) { 721 DRM_DEBUG_KMS("pch backlight already enabled\n"); 722 pch_ctl1 &= ~BLM_PCH_PWM_ENABLE; 723 I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1); 724 } 725 726 if (cpu_transcoder == TRANSCODER_EDP) 727 cpu_ctl2 = BLM_TRANSCODER_EDP; 728 else 729 cpu_ctl2 = BLM_PIPE(cpu_transcoder); 730 I915_WRITE(BLC_PWM_CPU_CTL2, cpu_ctl2); 731 POSTING_READ(BLC_PWM_CPU_CTL2); 732 I915_WRITE(BLC_PWM_CPU_CTL2, cpu_ctl2 | BLM_PWM_ENABLE); 733 734 /* This won't stick until the above enable. */ 735 intel_panel_actually_set_backlight(connector, panel->backlight.level); 736 737 pch_ctl2 = panel->backlight.max << 16; 738 I915_WRITE(BLC_PWM_PCH_CTL2, pch_ctl2); 739 740 pch_ctl1 = 0; 741 if (panel->backlight.active_low_pwm) 742 pch_ctl1 |= BLM_PCH_POLARITY; 743 744 I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1); 745 POSTING_READ(BLC_PWM_PCH_CTL1); 746 I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1 | BLM_PCH_PWM_ENABLE); 747} 748 749static void i9xx_enable_backlight(struct intel_connector *connector) 750{ 751 struct drm_device *dev = connector->base.dev; 752 struct drm_i915_private *dev_priv = dev->dev_private; 753 struct intel_panel *panel = &connector->panel; 754 u32 ctl, freq; 755 756 ctl = I915_READ(BLC_PWM_CTL); 757 if (ctl & BACKLIGHT_DUTY_CYCLE_MASK_PNV) { 758 WARN(1, "backlight already enabled\n"); 759 I915_WRITE(BLC_PWM_CTL, 0); 760 } 761 762 freq = panel->backlight.max; 763 if (panel->backlight.combination_mode) 764 freq /= 0xff; 765 766 ctl = freq << 17; 767 if (panel->backlight.combination_mode) 768 ctl |= BLM_LEGACY_MODE; 769 if (IS_PINEVIEW(dev) && panel->backlight.active_low_pwm) 770 ctl |= BLM_POLARITY_PNV; 771 772 I915_WRITE(BLC_PWM_CTL, ctl); 773 POSTING_READ(BLC_PWM_CTL); 774 775 /* XXX: combine this into above write? */ 776 intel_panel_actually_set_backlight(connector, panel->backlight.level); 777} 778 779static void i965_enable_backlight(struct intel_connector *connector) 780{ 781 struct drm_device *dev = connector->base.dev; 782 struct drm_i915_private *dev_priv = dev->dev_private; 783 struct intel_panel *panel = &connector->panel; 784 enum pipe pipe = intel_get_pipe_from_connector(connector); 785 u32 ctl, ctl2, freq; 786 787 ctl2 = I915_READ(BLC_PWM_CTL2); 788 if (ctl2 & BLM_PWM_ENABLE) { 789 WARN(1, "backlight already enabled\n"); 790 ctl2 &= ~BLM_PWM_ENABLE; 791 I915_WRITE(BLC_PWM_CTL2, ctl2); 792 } 793 794 freq = panel->backlight.max; 795 if (panel->backlight.combination_mode) 796 freq /= 0xff; 797 798 ctl = freq << 16; 799 I915_WRITE(BLC_PWM_CTL, ctl); 800 801 ctl2 = BLM_PIPE(pipe); 802 if (panel->backlight.combination_mode) 803 ctl2 |= BLM_COMBINATION_MODE; 804 if (panel->backlight.active_low_pwm) 805 ctl2 |= BLM_POLARITY_I965; 806 I915_WRITE(BLC_PWM_CTL2, ctl2); 807 POSTING_READ(BLC_PWM_CTL2); 808 I915_WRITE(BLC_PWM_CTL2, ctl2 | BLM_PWM_ENABLE); 809 810 intel_panel_actually_set_backlight(connector, panel->backlight.level); 811} 812 813static void vlv_enable_backlight(struct intel_connector *connector) 814{ 815 struct drm_device *dev = connector->base.dev; 816 struct drm_i915_private *dev_priv = dev->dev_private; 817 struct intel_panel *panel = &connector->panel; 818 enum pipe pipe = intel_get_pipe_from_connector(connector); 819 u32 ctl, ctl2; 820 821 ctl2 = I915_READ(VLV_BLC_PWM_CTL2(pipe)); 822 if (ctl2 & BLM_PWM_ENABLE) { 823 WARN(1, "backlight already enabled\n"); 824 ctl2 &= ~BLM_PWM_ENABLE; 825 I915_WRITE(VLV_BLC_PWM_CTL2(pipe), ctl2); 826 } 827 828 ctl = panel->backlight.max << 16; 829 I915_WRITE(VLV_BLC_PWM_CTL(pipe), ctl); 830 831 /* XXX: combine this into above write? */ 832 intel_panel_actually_set_backlight(connector, panel->backlight.level); 833 834 ctl2 = 0; 835 if (panel->backlight.active_low_pwm) 836 ctl2 |= BLM_POLARITY_I965; 837 I915_WRITE(VLV_BLC_PWM_CTL2(pipe), ctl2); 838 POSTING_READ(VLV_BLC_PWM_CTL2(pipe)); 839 I915_WRITE(VLV_BLC_PWM_CTL2(pipe), ctl2 | BLM_PWM_ENABLE); 840} 841 842void intel_panel_enable_backlight(struct intel_connector *connector) 843{ 844 struct drm_device *dev = connector->base.dev; 845 struct drm_i915_private *dev_priv = dev->dev_private; 846 struct intel_panel *panel = &connector->panel; 847 enum pipe pipe = intel_get_pipe_from_connector(connector); 848 unsigned long flags; 849 850 if (!panel->backlight.present || pipe == INVALID_PIPE) 851 return; 852 853 DRM_DEBUG_KMS("pipe %c\n", pipe_name(pipe)); 854 855 spin_lock_irqsave(&dev_priv->backlight_lock, flags); 856 857 WARN_ON(panel->backlight.max == 0); 858 859 if (panel->backlight.level == 0) { 860 panel->backlight.level = panel->backlight.max; 861 if (panel->backlight.device) 862 panel->backlight.device->props.brightness = 863 panel->backlight.level; 864 } 865 866 dev_priv->display.enable_backlight(connector); 867 panel->backlight.enabled = true; 868 869 spin_unlock_irqrestore(&dev_priv->backlight_lock, flags); 870} 871 872#if IS_ENABLED(CONFIG_BACKLIGHT_CLASS_DEVICE) 873static int intel_backlight_device_update_status(struct backlight_device *bd) 874{ 875 struct intel_connector *connector = bl_get_data(bd); 876 struct drm_device *dev = connector->base.dev; 877 878 drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); 879 DRM_DEBUG_KMS("updating intel_backlight, brightness=%d/%d\n", 880 bd->props.brightness, bd->props.max_brightness); 881 intel_panel_set_backlight(connector, bd->props.brightness, 882 bd->props.max_brightness); 883 drm_modeset_unlock(&dev->mode_config.connection_mutex); 884 return 0; 885} 886 887static int intel_backlight_device_get_brightness(struct backlight_device *bd) 888{ 889 struct intel_connector *connector = bl_get_data(bd); 890 struct drm_device *dev = connector->base.dev; 891 struct drm_i915_private *dev_priv = dev->dev_private; 892 int ret; 893 894 intel_runtime_pm_get(dev_priv); 895 drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); 896 ret = intel_panel_get_backlight(connector); 897 drm_modeset_unlock(&dev->mode_config.connection_mutex); 898 intel_runtime_pm_put(dev_priv); 899 900 return ret; 901} 902 903static const struct backlight_ops intel_backlight_device_ops = { 904 .update_status = intel_backlight_device_update_status, 905 .get_brightness = intel_backlight_device_get_brightness, 906}; 907 908static int intel_backlight_device_register(struct intel_connector *connector) 909{ 910 struct intel_panel *panel = &connector->panel; 911 struct backlight_properties props; 912 913 if (WARN_ON(panel->backlight.device)) 914 return -ENODEV; 915 916 BUG_ON(panel->backlight.max == 0); 917 918 memset(&props, 0, sizeof(props)); 919 props.type = BACKLIGHT_RAW; 920 props.brightness = panel->backlight.level; 921 props.max_brightness = panel->backlight.max; 922 923 /* 924 * Note: using the same name independent of the connector prevents 925 * registration of multiple backlight devices in the driver. 926 */ 927 panel->backlight.device = 928 backlight_device_register("intel_backlight", 929 connector->base.kdev, 930 connector, 931 &intel_backlight_device_ops, &props); 932 933 if (IS_ERR(panel->backlight.device)) { 934 DRM_ERROR("Failed to register backlight: %ld\n", 935 PTR_ERR(panel->backlight.device)); 936 panel->backlight.device = NULL; 937 return -ENODEV; 938 } 939 return 0; 940} 941 942static void intel_backlight_device_unregister(struct intel_connector *connector) 943{ 944 struct intel_panel *panel = &connector->panel; 945 946 if (panel->backlight.device) { 947 backlight_device_unregister(panel->backlight.device); 948 panel->backlight.device = NULL; 949 } 950} 951#else /* CONFIG_BACKLIGHT_CLASS_DEVICE */ 952static int intel_backlight_device_register(struct intel_connector *connector) 953{ 954 return 0; 955} 956static void intel_backlight_device_unregister(struct intel_connector *connector) 957{ 958} 959#endif /* CONFIG_BACKLIGHT_CLASS_DEVICE */ 960 961/* 962 * Note: The setup hooks can't assume pipe is set! 963 * 964 * XXX: Query mode clock or hardware clock and program PWM modulation frequency 965 * appropriately when it's 0. Use VBT and/or sane defaults. 966 */ 967static int bdw_setup_backlight(struct intel_connector *connector) 968{ 969 struct drm_device *dev = connector->base.dev; 970 struct drm_i915_private *dev_priv = dev->dev_private; 971 struct intel_panel *panel = &connector->panel; 972 u32 pch_ctl1, pch_ctl2, val; 973 974 pch_ctl1 = I915_READ(BLC_PWM_PCH_CTL1); 975 panel->backlight.active_low_pwm = pch_ctl1 & BLM_PCH_POLARITY; 976 977 pch_ctl2 = I915_READ(BLC_PWM_PCH_CTL2); 978 panel->backlight.max = pch_ctl2 >> 16; 979 if (!panel->backlight.max) 980 return -ENODEV; 981 982 val = bdw_get_backlight(connector); 983 panel->backlight.level = intel_panel_compute_brightness(connector, val); 984 985 panel->backlight.enabled = (pch_ctl1 & BLM_PCH_PWM_ENABLE) && 986 panel->backlight.level != 0; 987 988 return 0; 989} 990 991static int pch_setup_backlight(struct intel_connector *connector) 992{ 993 struct drm_device *dev = connector->base.dev; 994 struct drm_i915_private *dev_priv = dev->dev_private; 995 struct intel_panel *panel = &connector->panel; 996 u32 cpu_ctl2, pch_ctl1, pch_ctl2, val; 997 998 pch_ctl1 = I915_READ(BLC_PWM_PCH_CTL1); 999 panel->backlight.active_low_pwm = pch_ctl1 & BLM_PCH_POLARITY; 1000 1001 pch_ctl2 = I915_READ(BLC_PWM_PCH_CTL2); 1002 panel->backlight.max = pch_ctl2 >> 16; 1003 if (!panel->backlight.max) 1004 return -ENODEV; 1005 1006 val = pch_get_backlight(connector); 1007 panel->backlight.level = intel_panel_compute_brightness(connector, val); 1008 1009 cpu_ctl2 = I915_READ(BLC_PWM_CPU_CTL2); 1010 panel->backlight.enabled = (cpu_ctl2 & BLM_PWM_ENABLE) && 1011 (pch_ctl1 & BLM_PCH_PWM_ENABLE) && panel->backlight.level != 0; 1012 1013 return 0; 1014} 1015 1016static int i9xx_setup_backlight(struct intel_connector *connector) 1017{ 1018 struct drm_device *dev = connector->base.dev; 1019 struct drm_i915_private *dev_priv = dev->dev_private; 1020 struct intel_panel *panel = &connector->panel; 1021 u32 ctl, val; 1022 1023 ctl = I915_READ(BLC_PWM_CTL); 1024 1025 if (IS_GEN2(dev) || IS_I915GM(dev) || IS_I945GM(dev)) 1026 panel->backlight.combination_mode = ctl & BLM_LEGACY_MODE; 1027 1028 if (IS_PINEVIEW(dev)) 1029 panel->backlight.active_low_pwm = ctl & BLM_POLARITY_PNV; 1030 1031 panel->backlight.max = ctl >> 17; 1032 if (panel->backlight.combination_mode) 1033 panel->backlight.max *= 0xff; 1034 1035 if (!panel->backlight.max) 1036 return -ENODEV; 1037 1038 val = i9xx_get_backlight(connector); 1039 panel->backlight.level = intel_panel_compute_brightness(connector, val); 1040 1041 panel->backlight.enabled = panel->backlight.level != 0; 1042 1043 return 0; 1044} 1045 1046static int i965_setup_backlight(struct intel_connector *connector) 1047{ 1048 struct drm_device *dev = connector->base.dev; 1049 struct drm_i915_private *dev_priv = dev->dev_private; 1050 struct intel_panel *panel = &connector->panel; 1051 u32 ctl, ctl2, val; 1052 1053 ctl2 = I915_READ(BLC_PWM_CTL2); 1054 panel->backlight.combination_mode = ctl2 & BLM_COMBINATION_MODE; 1055 panel->backlight.active_low_pwm = ctl2 & BLM_POLARITY_I965; 1056 1057 ctl = I915_READ(BLC_PWM_CTL); 1058 panel->backlight.max = ctl >> 16; 1059 if (panel->backlight.combination_mode) 1060 panel->backlight.max *= 0xff; 1061 1062 if (!panel->backlight.max) 1063 return -ENODEV; 1064 1065 val = i9xx_get_backlight(connector); 1066 panel->backlight.level = intel_panel_compute_brightness(connector, val); 1067 1068 panel->backlight.enabled = (ctl2 & BLM_PWM_ENABLE) && 1069 panel->backlight.level != 0; 1070 1071 return 0; 1072} 1073 1074static int vlv_setup_backlight(struct intel_connector *connector) 1075{ 1076 struct drm_device *dev = connector->base.dev; 1077 struct drm_i915_private *dev_priv = dev->dev_private; 1078 struct intel_panel *panel = &connector->panel; 1079 enum pipe pipe; 1080 u32 ctl, ctl2, val; 1081 1082 for_each_pipe(pipe) { 1083 u32 cur_val = I915_READ(VLV_BLC_PWM_CTL(pipe)); 1084 1085 /* Skip if the modulation freq is already set */ 1086 if (cur_val & ~BACKLIGHT_DUTY_CYCLE_MASK) 1087 continue; 1088 1089 cur_val &= BACKLIGHT_DUTY_CYCLE_MASK; 1090 I915_WRITE(VLV_BLC_PWM_CTL(pipe), (0xf42 << 16) | 1091 cur_val); 1092 } 1093 1094 ctl2 = I915_READ(VLV_BLC_PWM_CTL2(PIPE_A)); 1095 panel->backlight.active_low_pwm = ctl2 & BLM_POLARITY_I965; 1096 1097 ctl = I915_READ(VLV_BLC_PWM_CTL(PIPE_A)); 1098 panel->backlight.max = ctl >> 16; 1099 if (!panel->backlight.max) 1100 return -ENODEV; 1101 1102 val = _vlv_get_backlight(dev, PIPE_A); 1103 panel->backlight.level = intel_panel_compute_brightness(connector, val); 1104 1105 panel->backlight.enabled = (ctl2 & BLM_PWM_ENABLE) && 1106 panel->backlight.level != 0; 1107 1108 return 0; 1109} 1110 1111int intel_panel_setup_backlight(struct drm_connector *connector) 1112{ 1113 struct drm_device *dev = connector->dev; 1114 struct drm_i915_private *dev_priv = dev->dev_private; 1115 struct intel_connector *intel_connector = to_intel_connector(connector); 1116 struct intel_panel *panel = &intel_connector->panel; 1117 unsigned long flags; 1118 int ret; 1119 1120 if (!dev_priv->vbt.backlight.present) { 1121 if (dev_priv->quirks & QUIRK_BACKLIGHT_PRESENT) { 1122 DRM_DEBUG_KMS("no backlight present per VBT, but present per quirk\n"); 1123 } else { 1124 DRM_DEBUG_KMS("no backlight present per VBT\n"); 1125 return 0; 1126 } 1127 } 1128 1129 /* set level and max in panel struct */ 1130 spin_lock_irqsave(&dev_priv->backlight_lock, flags); 1131 ret = dev_priv->display.setup_backlight(intel_connector); 1132 spin_unlock_irqrestore(&dev_priv->backlight_lock, flags); 1133 1134 if (ret) { 1135 DRM_DEBUG_KMS("failed to setup backlight for connector %s\n", 1136 connector->name); 1137 return ret; 1138 } 1139 1140 intel_backlight_device_register(intel_connector); 1141 1142 panel->backlight.present = true; 1143 1144 DRM_DEBUG_KMS("backlight initialized, %s, brightness %u/%u, " 1145 "sysfs interface %sregistered\n", 1146 panel->backlight.enabled ? "enabled" : "disabled", 1147 panel->backlight.level, panel->backlight.max, 1148 panel->backlight.device ? "" : "not "); 1149 1150 return 0; 1151} 1152 1153void intel_panel_destroy_backlight(struct drm_connector *connector) 1154{ 1155 struct intel_connector *intel_connector = to_intel_connector(connector); 1156 struct intel_panel *panel = &intel_connector->panel; 1157 1158 panel->backlight.present = false; 1159 intel_backlight_device_unregister(intel_connector); 1160} 1161 1162/* Set up chip specific backlight functions */ 1163void intel_panel_init_backlight_funcs(struct drm_device *dev) 1164{ 1165 struct drm_i915_private *dev_priv = dev->dev_private; 1166 1167 if (IS_BROADWELL(dev)) { 1168 dev_priv->display.setup_backlight = bdw_setup_backlight; 1169 dev_priv->display.enable_backlight = bdw_enable_backlight; 1170 dev_priv->display.disable_backlight = pch_disable_backlight; 1171 dev_priv->display.set_backlight = bdw_set_backlight; 1172 dev_priv->display.get_backlight = bdw_get_backlight; 1173 } else if (HAS_PCH_SPLIT(dev)) { 1174 dev_priv->display.setup_backlight = pch_setup_backlight; 1175 dev_priv->display.enable_backlight = pch_enable_backlight; 1176 dev_priv->display.disable_backlight = pch_disable_backlight; 1177 dev_priv->display.set_backlight = pch_set_backlight; 1178 dev_priv->display.get_backlight = pch_get_backlight; 1179 } else if (IS_VALLEYVIEW(dev)) { 1180 dev_priv->display.setup_backlight = vlv_setup_backlight; 1181 dev_priv->display.enable_backlight = vlv_enable_backlight; 1182 dev_priv->display.disable_backlight = vlv_disable_backlight; 1183 dev_priv->display.set_backlight = vlv_set_backlight; 1184 dev_priv->display.get_backlight = vlv_get_backlight; 1185 } else if (IS_GEN4(dev)) { 1186 dev_priv->display.setup_backlight = i965_setup_backlight; 1187 dev_priv->display.enable_backlight = i965_enable_backlight; 1188 dev_priv->display.disable_backlight = i965_disable_backlight; 1189 dev_priv->display.set_backlight = i9xx_set_backlight; 1190 dev_priv->display.get_backlight = i9xx_get_backlight; 1191 } else { 1192 dev_priv->display.setup_backlight = i9xx_setup_backlight; 1193 dev_priv->display.enable_backlight = i9xx_enable_backlight; 1194 dev_priv->display.disable_backlight = i9xx_disable_backlight; 1195 dev_priv->display.set_backlight = i9xx_set_backlight; 1196 dev_priv->display.get_backlight = i9xx_get_backlight; 1197 } 1198} 1199 1200int intel_panel_init(struct intel_panel *panel, 1201 struct drm_display_mode *fixed_mode, 1202 struct drm_display_mode *downclock_mode) 1203{ 1204 panel->fixed_mode = fixed_mode; 1205 panel->downclock_mode = downclock_mode; 1206 1207 return 0; 1208} 1209 1210void intel_panel_fini(struct intel_panel *panel) 1211{ 1212 struct intel_connector *intel_connector = 1213 container_of(panel, struct intel_connector, panel); 1214 1215 if (panel->fixed_mode) 1216 drm_mode_destroy(intel_connector->base.dev, panel->fixed_mode); 1217 1218 if (panel->downclock_mode) 1219 drm_mode_destroy(intel_connector->base.dev, 1220 panel->downclock_mode); 1221}