0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031 #include <linux/kernel.h>
0032 #include <linux/pwm.h>
0033
0034 #include "intel_backlight.h"
0035 #include "intel_connector.h"
0036 #include "intel_de.h"
0037 #include "intel_display_types.h"
0038 #include "intel_drrs.h"
0039 #include "intel_panel.h"
0040
0041 bool intel_panel_use_ssc(struct drm_i915_private *i915)
0042 {
0043 if (i915->params.panel_use_ssc >= 0)
0044 return i915->params.panel_use_ssc != 0;
0045 return i915->vbt.lvds_use_ssc
0046 && !(i915->quirks & QUIRK_LVDS_SSC_DISABLE);
0047 }
0048
0049 const struct drm_display_mode *
0050 intel_panel_preferred_fixed_mode(struct intel_connector *connector)
0051 {
0052 return list_first_entry_or_null(&connector->panel.fixed_modes,
0053 struct drm_display_mode, head);
0054 }
0055
0056 const struct drm_display_mode *
0057 intel_panel_fixed_mode(struct intel_connector *connector,
0058 const struct drm_display_mode *mode)
0059 {
0060 const struct drm_display_mode *fixed_mode, *best_mode = NULL;
0061 int vrefresh = drm_mode_vrefresh(mode);
0062
0063
0064 list_for_each_entry(fixed_mode, &connector->panel.fixed_modes, head) {
0065 if (!best_mode ||
0066 abs(drm_mode_vrefresh(fixed_mode) - vrefresh) <
0067 abs(drm_mode_vrefresh(best_mode) - vrefresh))
0068 best_mode = fixed_mode;
0069 }
0070
0071 return best_mode;
0072 }
0073
0074 static bool is_alt_drrs_mode(const struct drm_display_mode *mode,
0075 const struct drm_display_mode *preferred_mode)
0076 {
0077 return drm_mode_match(mode, preferred_mode,
0078 DRM_MODE_MATCH_TIMINGS |
0079 DRM_MODE_MATCH_FLAGS |
0080 DRM_MODE_MATCH_3D_FLAGS) &&
0081 mode->clock != preferred_mode->clock;
0082 }
0083
0084 static bool is_alt_vrr_mode(const struct drm_display_mode *mode,
0085 const struct drm_display_mode *preferred_mode)
0086 {
0087 return drm_mode_match(mode, preferred_mode,
0088 DRM_MODE_MATCH_FLAGS |
0089 DRM_MODE_MATCH_3D_FLAGS) &&
0090 mode->hdisplay == preferred_mode->hdisplay &&
0091 mode->vdisplay == preferred_mode->vdisplay &&
0092 mode->clock != preferred_mode->clock;
0093 }
0094
0095 const struct drm_display_mode *
0096 intel_panel_downclock_mode(struct intel_connector *connector,
0097 const struct drm_display_mode *adjusted_mode)
0098 {
0099 const struct drm_display_mode *fixed_mode, *best_mode = NULL;
0100 int min_vrefresh = connector->panel.vbt.seamless_drrs_min_refresh_rate;
0101 int max_vrefresh = drm_mode_vrefresh(adjusted_mode);
0102
0103
0104 list_for_each_entry(fixed_mode, &connector->panel.fixed_modes, head) {
0105 int vrefresh = drm_mode_vrefresh(fixed_mode);
0106
0107 if (is_alt_drrs_mode(fixed_mode, adjusted_mode) &&
0108 vrefresh >= min_vrefresh && vrefresh < max_vrefresh) {
0109 max_vrefresh = vrefresh;
0110 best_mode = fixed_mode;
0111 }
0112 }
0113
0114 return best_mode;
0115 }
0116
0117 int intel_panel_get_modes(struct intel_connector *connector)
0118 {
0119 const struct drm_display_mode *fixed_mode;
0120 int num_modes = 0;
0121
0122 list_for_each_entry(fixed_mode, &connector->panel.fixed_modes, head) {
0123 struct drm_display_mode *mode;
0124
0125 mode = drm_mode_duplicate(connector->base.dev, fixed_mode);
0126 if (mode) {
0127 drm_mode_probed_add(&connector->base, mode);
0128 num_modes++;
0129 }
0130 }
0131
0132 return num_modes;
0133 }
0134
0135 enum drrs_type intel_panel_drrs_type(struct intel_connector *connector)
0136 {
0137 if (list_empty(&connector->panel.fixed_modes) ||
0138 list_is_singular(&connector->panel.fixed_modes))
0139 return DRRS_TYPE_NONE;
0140
0141 return connector->panel.vbt.drrs_type;
0142 }
0143
0144 int intel_panel_compute_config(struct intel_connector *connector,
0145 struct drm_display_mode *adjusted_mode)
0146 {
0147 const struct drm_display_mode *fixed_mode =
0148 intel_panel_fixed_mode(connector, adjusted_mode);
0149
0150 if (!fixed_mode)
0151 return 0;
0152
0153
0154
0155
0156
0157
0158
0159 if (abs(drm_mode_vrefresh(adjusted_mode) - drm_mode_vrefresh(fixed_mode)) > 1) {
0160 drm_dbg_kms(connector->base.dev,
0161 "[CONNECTOR:%d:%s] Requested mode vrefresh (%d Hz) does not match fixed mode vrefresh (%d Hz)\n",
0162 connector->base.base.id, connector->base.name,
0163 drm_mode_vrefresh(adjusted_mode), drm_mode_vrefresh(fixed_mode));
0164
0165 return -EINVAL;
0166 }
0167
0168 drm_mode_copy(adjusted_mode, fixed_mode);
0169
0170 drm_mode_set_crtcinfo(adjusted_mode, 0);
0171
0172 return 0;
0173 }
0174
0175 static bool is_alt_fixed_mode(const struct drm_display_mode *mode,
0176 const struct drm_display_mode *preferred_mode,
0177 bool has_vrr)
0178 {
0179
0180 if (has_vrr)
0181 return is_alt_vrr_mode(mode, preferred_mode);
0182 else
0183 return is_alt_drrs_mode(mode, preferred_mode);
0184 }
0185
0186 static void intel_panel_add_edid_alt_fixed_modes(struct intel_connector *connector,
0187 bool has_vrr)
0188 {
0189 struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
0190 const struct drm_display_mode *preferred_mode =
0191 intel_panel_preferred_fixed_mode(connector);
0192 struct drm_display_mode *mode, *next;
0193
0194 list_for_each_entry_safe(mode, next, &connector->base.probed_modes, head) {
0195 if (!is_alt_fixed_mode(mode, preferred_mode, has_vrr))
0196 continue;
0197
0198 drm_dbg_kms(&dev_priv->drm,
0199 "[CONNECTOR:%d:%s] using alternate EDID fixed mode: " DRM_MODE_FMT "\n",
0200 connector->base.base.id, connector->base.name,
0201 DRM_MODE_ARG(mode));
0202
0203 list_move_tail(&mode->head, &connector->panel.fixed_modes);
0204 }
0205 }
0206
0207 static void intel_panel_add_edid_preferred_mode(struct intel_connector *connector)
0208 {
0209 struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
0210 struct drm_display_mode *scan, *fixed_mode = NULL;
0211
0212 if (list_empty(&connector->base.probed_modes))
0213 return;
0214
0215
0216 list_for_each_entry(scan, &connector->base.probed_modes, head) {
0217 if (scan->type & DRM_MODE_TYPE_PREFERRED) {
0218 fixed_mode = scan;
0219 break;
0220 }
0221 }
0222
0223 if (!fixed_mode)
0224 fixed_mode = list_first_entry(&connector->base.probed_modes,
0225 typeof(*fixed_mode), head);
0226
0227 drm_dbg_kms(&dev_priv->drm,
0228 "[CONNECTOR:%d:%s] using %s EDID fixed mode: " DRM_MODE_FMT "\n",
0229 connector->base.base.id, connector->base.name,
0230 fixed_mode->type & DRM_MODE_TYPE_PREFERRED ? "preferred" : "first",
0231 DRM_MODE_ARG(fixed_mode));
0232
0233 fixed_mode->type |= DRM_MODE_TYPE_PREFERRED;
0234
0235 list_move_tail(&fixed_mode->head, &connector->panel.fixed_modes);
0236 }
0237
0238 static void intel_panel_destroy_probed_modes(struct intel_connector *connector)
0239 {
0240 struct drm_i915_private *i915 = to_i915(connector->base.dev);
0241 struct drm_display_mode *mode, *next;
0242
0243 list_for_each_entry_safe(mode, next, &connector->base.probed_modes, head) {
0244 drm_dbg_kms(&i915->drm,
0245 "[CONNECTOR:%d:%s] not using EDID mode: " DRM_MODE_FMT "\n",
0246 connector->base.base.id, connector->base.name,
0247 DRM_MODE_ARG(mode));
0248 list_del(&mode->head);
0249 drm_mode_destroy(&i915->drm, mode);
0250 }
0251 }
0252
0253 void intel_panel_add_edid_fixed_modes(struct intel_connector *connector,
0254 bool has_drrs, bool has_vrr)
0255 {
0256 intel_panel_add_edid_preferred_mode(connector);
0257 if (intel_panel_preferred_fixed_mode(connector) && (has_drrs || has_vrr))
0258 intel_panel_add_edid_alt_fixed_modes(connector, has_vrr);
0259 intel_panel_destroy_probed_modes(connector);
0260 }
0261
0262 static void intel_panel_add_fixed_mode(struct intel_connector *connector,
0263 struct drm_display_mode *fixed_mode,
0264 const char *type)
0265 {
0266 struct drm_i915_private *i915 = to_i915(connector->base.dev);
0267 struct drm_display_info *info = &connector->base.display_info;
0268
0269 if (!fixed_mode)
0270 return;
0271
0272 fixed_mode->type |= DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER;
0273
0274 info->width_mm = fixed_mode->width_mm;
0275 info->height_mm = fixed_mode->height_mm;
0276
0277 drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] using %s fixed mode: " DRM_MODE_FMT "\n",
0278 connector->base.base.id, connector->base.name, type,
0279 DRM_MODE_ARG(fixed_mode));
0280
0281 list_add_tail(&fixed_mode->head, &connector->panel.fixed_modes);
0282 }
0283
0284 void intel_panel_add_vbt_lfp_fixed_mode(struct intel_connector *connector)
0285 {
0286 struct drm_i915_private *i915 = to_i915(connector->base.dev);
0287 const struct drm_display_mode *mode;
0288
0289 mode = connector->panel.vbt.lfp_lvds_vbt_mode;
0290 if (!mode)
0291 return;
0292
0293 intel_panel_add_fixed_mode(connector,
0294 drm_mode_duplicate(&i915->drm, mode),
0295 "VBT LFP");
0296 }
0297
0298 void intel_panel_add_vbt_sdvo_fixed_mode(struct intel_connector *connector)
0299 {
0300 struct drm_i915_private *i915 = to_i915(connector->base.dev);
0301 const struct drm_display_mode *mode;
0302
0303 mode = connector->panel.vbt.sdvo_lvds_vbt_mode;
0304 if (!mode)
0305 return;
0306
0307 intel_panel_add_fixed_mode(connector,
0308 drm_mode_duplicate(&i915->drm, mode),
0309 "VBT SDVO");
0310 }
0311
0312 void intel_panel_add_encoder_fixed_mode(struct intel_connector *connector,
0313 struct intel_encoder *encoder)
0314 {
0315 intel_panel_add_fixed_mode(connector,
0316 intel_encoder_current_mode(encoder),
0317 "current (BIOS)");
0318 }
0319
0320
0321 static int pch_panel_fitting(struct intel_crtc_state *crtc_state,
0322 const struct drm_connector_state *conn_state)
0323 {
0324 const struct drm_display_mode *adjusted_mode =
0325 &crtc_state->hw.adjusted_mode;
0326 int pipe_src_w = drm_rect_width(&crtc_state->pipe_src);
0327 int pipe_src_h = drm_rect_height(&crtc_state->pipe_src);
0328 int x, y, width, height;
0329
0330
0331 if (adjusted_mode->crtc_hdisplay == pipe_src_w &&
0332 adjusted_mode->crtc_vdisplay == pipe_src_h &&
0333 crtc_state->output_format != INTEL_OUTPUT_FORMAT_YCBCR420)
0334 return 0;
0335
0336 switch (conn_state->scaling_mode) {
0337 case DRM_MODE_SCALE_CENTER:
0338 width = pipe_src_w;
0339 height = pipe_src_h;
0340 x = (adjusted_mode->crtc_hdisplay - width + 1)/2;
0341 y = (adjusted_mode->crtc_vdisplay - height + 1)/2;
0342 break;
0343
0344 case DRM_MODE_SCALE_ASPECT:
0345
0346 {
0347 u32 scaled_width = adjusted_mode->crtc_hdisplay * pipe_src_h;
0348 u32 scaled_height = pipe_src_w * adjusted_mode->crtc_vdisplay;
0349 if (scaled_width > scaled_height) {
0350 width = scaled_height / pipe_src_h;
0351 if (width & 1)
0352 width++;
0353 x = (adjusted_mode->crtc_hdisplay - width + 1) / 2;
0354 y = 0;
0355 height = adjusted_mode->crtc_vdisplay;
0356 } else if (scaled_width < scaled_height) {
0357 height = scaled_width / pipe_src_w;
0358 if (height & 1)
0359 height++;
0360 y = (adjusted_mode->crtc_vdisplay - height + 1) / 2;
0361 x = 0;
0362 width = adjusted_mode->crtc_hdisplay;
0363 } else {
0364 x = y = 0;
0365 width = adjusted_mode->crtc_hdisplay;
0366 height = adjusted_mode->crtc_vdisplay;
0367 }
0368 }
0369 break;
0370
0371 case DRM_MODE_SCALE_NONE:
0372 WARN_ON(adjusted_mode->crtc_hdisplay != pipe_src_w);
0373 WARN_ON(adjusted_mode->crtc_vdisplay != pipe_src_h);
0374 fallthrough;
0375 case DRM_MODE_SCALE_FULLSCREEN:
0376 x = y = 0;
0377 width = adjusted_mode->crtc_hdisplay;
0378 height = adjusted_mode->crtc_vdisplay;
0379 break;
0380
0381 default:
0382 MISSING_CASE(conn_state->scaling_mode);
0383 return -EINVAL;
0384 }
0385
0386 drm_rect_init(&crtc_state->pch_pfit.dst,
0387 x, y, width, height);
0388 crtc_state->pch_pfit.enabled = true;
0389
0390 return 0;
0391 }
0392
0393 static void
0394 centre_horizontally(struct drm_display_mode *adjusted_mode,
0395 int width)
0396 {
0397 u32 border, sync_pos, blank_width, sync_width;
0398
0399
0400 sync_width = adjusted_mode->crtc_hsync_end - adjusted_mode->crtc_hsync_start;
0401 blank_width = adjusted_mode->crtc_hblank_end - adjusted_mode->crtc_hblank_start;
0402 sync_pos = (blank_width - sync_width + 1) / 2;
0403
0404 border = (adjusted_mode->crtc_hdisplay - width + 1) / 2;
0405 border += border & 1;
0406
0407 adjusted_mode->crtc_hdisplay = width;
0408 adjusted_mode->crtc_hblank_start = width + border;
0409 adjusted_mode->crtc_hblank_end = adjusted_mode->crtc_hblank_start + blank_width;
0410
0411 adjusted_mode->crtc_hsync_start = adjusted_mode->crtc_hblank_start + sync_pos;
0412 adjusted_mode->crtc_hsync_end = adjusted_mode->crtc_hsync_start + sync_width;
0413 }
0414
0415 static void
0416 centre_vertically(struct drm_display_mode *adjusted_mode,
0417 int height)
0418 {
0419 u32 border, sync_pos, blank_width, sync_width;
0420
0421
0422 sync_width = adjusted_mode->crtc_vsync_end - adjusted_mode->crtc_vsync_start;
0423 blank_width = adjusted_mode->crtc_vblank_end - adjusted_mode->crtc_vblank_start;
0424 sync_pos = (blank_width - sync_width + 1) / 2;
0425
0426 border = (adjusted_mode->crtc_vdisplay - height + 1) / 2;
0427
0428 adjusted_mode->crtc_vdisplay = height;
0429 adjusted_mode->crtc_vblank_start = height + border;
0430 adjusted_mode->crtc_vblank_end = adjusted_mode->crtc_vblank_start + blank_width;
0431
0432 adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vblank_start + sync_pos;
0433 adjusted_mode->crtc_vsync_end = adjusted_mode->crtc_vsync_start + sync_width;
0434 }
0435
0436 static u32 panel_fitter_scaling(u32 source, u32 target)
0437 {
0438
0439
0440
0441
0442
0443 #define ACCURACY 12
0444 #define FACTOR (1 << ACCURACY)
0445 u32 ratio = source * FACTOR / target;
0446 return (FACTOR * ratio + FACTOR/2) / FACTOR;
0447 }
0448
0449 static void i965_scale_aspect(struct intel_crtc_state *crtc_state,
0450 u32 *pfit_control)
0451 {
0452 const struct drm_display_mode *adjusted_mode =
0453 &crtc_state->hw.adjusted_mode;
0454 int pipe_src_w = drm_rect_width(&crtc_state->pipe_src);
0455 int pipe_src_h = drm_rect_height(&crtc_state->pipe_src);
0456 u32 scaled_width = adjusted_mode->crtc_hdisplay * pipe_src_h;
0457 u32 scaled_height = pipe_src_w * adjusted_mode->crtc_vdisplay;
0458
0459
0460 if (scaled_width > scaled_height)
0461 *pfit_control |= PFIT_ENABLE |
0462 PFIT_SCALING_PILLAR;
0463 else if (scaled_width < scaled_height)
0464 *pfit_control |= PFIT_ENABLE |
0465 PFIT_SCALING_LETTER;
0466 else if (adjusted_mode->crtc_hdisplay != pipe_src_w)
0467 *pfit_control |= PFIT_ENABLE | PFIT_SCALING_AUTO;
0468 }
0469
0470 static void i9xx_scale_aspect(struct intel_crtc_state *crtc_state,
0471 u32 *pfit_control, u32 *pfit_pgm_ratios,
0472 u32 *border)
0473 {
0474 struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode;
0475 int pipe_src_w = drm_rect_width(&crtc_state->pipe_src);
0476 int pipe_src_h = drm_rect_height(&crtc_state->pipe_src);
0477 u32 scaled_width = adjusted_mode->crtc_hdisplay * pipe_src_h;
0478 u32 scaled_height = pipe_src_w * adjusted_mode->crtc_vdisplay;
0479 u32 bits;
0480
0481
0482
0483
0484
0485
0486 if (scaled_width > scaled_height) {
0487 centre_horizontally(adjusted_mode,
0488 scaled_height / pipe_src_h);
0489
0490 *border = LVDS_BORDER_ENABLE;
0491 if (pipe_src_h != adjusted_mode->crtc_vdisplay) {
0492 bits = panel_fitter_scaling(pipe_src_h,
0493 adjusted_mode->crtc_vdisplay);
0494
0495 *pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT |
0496 bits << PFIT_VERT_SCALE_SHIFT);
0497 *pfit_control |= (PFIT_ENABLE |
0498 VERT_INTERP_BILINEAR |
0499 HORIZ_INTERP_BILINEAR);
0500 }
0501 } else if (scaled_width < scaled_height) {
0502 centre_vertically(adjusted_mode,
0503 scaled_width / pipe_src_w);
0504
0505 *border = LVDS_BORDER_ENABLE;
0506 if (pipe_src_w != adjusted_mode->crtc_hdisplay) {
0507 bits = panel_fitter_scaling(pipe_src_w,
0508 adjusted_mode->crtc_hdisplay);
0509
0510 *pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT |
0511 bits << PFIT_VERT_SCALE_SHIFT);
0512 *pfit_control |= (PFIT_ENABLE |
0513 VERT_INTERP_BILINEAR |
0514 HORIZ_INTERP_BILINEAR);
0515 }
0516 } else {
0517
0518 *pfit_control |= (PFIT_ENABLE |
0519 VERT_AUTO_SCALE | HORIZ_AUTO_SCALE |
0520 VERT_INTERP_BILINEAR |
0521 HORIZ_INTERP_BILINEAR);
0522 }
0523 }
0524
0525 static int gmch_panel_fitting(struct intel_crtc_state *crtc_state,
0526 const struct drm_connector_state *conn_state)
0527 {
0528 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
0529 struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
0530 u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0;
0531 struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode;
0532 int pipe_src_w = drm_rect_width(&crtc_state->pipe_src);
0533 int pipe_src_h = drm_rect_height(&crtc_state->pipe_src);
0534
0535
0536 if (adjusted_mode->crtc_hdisplay == pipe_src_w &&
0537 adjusted_mode->crtc_vdisplay == pipe_src_h)
0538 goto out;
0539
0540 switch (conn_state->scaling_mode) {
0541 case DRM_MODE_SCALE_CENTER:
0542
0543
0544
0545
0546 centre_horizontally(adjusted_mode, pipe_src_w);
0547 centre_vertically(adjusted_mode, pipe_src_h);
0548 border = LVDS_BORDER_ENABLE;
0549 break;
0550 case DRM_MODE_SCALE_ASPECT:
0551
0552 if (DISPLAY_VER(dev_priv) >= 4)
0553 i965_scale_aspect(crtc_state, &pfit_control);
0554 else
0555 i9xx_scale_aspect(crtc_state, &pfit_control,
0556 &pfit_pgm_ratios, &border);
0557 break;
0558 case DRM_MODE_SCALE_FULLSCREEN:
0559
0560
0561
0562
0563 if (pipe_src_h != adjusted_mode->crtc_vdisplay ||
0564 pipe_src_w != adjusted_mode->crtc_hdisplay) {
0565 pfit_control |= PFIT_ENABLE;
0566 if (DISPLAY_VER(dev_priv) >= 4)
0567 pfit_control |= PFIT_SCALING_AUTO;
0568 else
0569 pfit_control |= (VERT_AUTO_SCALE |
0570 VERT_INTERP_BILINEAR |
0571 HORIZ_AUTO_SCALE |
0572 HORIZ_INTERP_BILINEAR);
0573 }
0574 break;
0575 default:
0576 MISSING_CASE(conn_state->scaling_mode);
0577 return -EINVAL;
0578 }
0579
0580
0581
0582 if (DISPLAY_VER(dev_priv) >= 4)
0583 pfit_control |= PFIT_PIPE(crtc->pipe) | PFIT_FILTER_FUZZY;
0584
0585 out:
0586 if ((pfit_control & PFIT_ENABLE) == 0) {
0587 pfit_control = 0;
0588 pfit_pgm_ratios = 0;
0589 }
0590
0591
0592 if (DISPLAY_VER(dev_priv) < 4 && crtc_state->pipe_bpp == 18)
0593 pfit_control |= PANEL_8TO6_DITHER_ENABLE;
0594
0595 crtc_state->gmch_pfit.control = pfit_control;
0596 crtc_state->gmch_pfit.pgm_ratios = pfit_pgm_ratios;
0597 crtc_state->gmch_pfit.lvds_border_bits = border;
0598
0599 return 0;
0600 }
0601
0602 int intel_panel_fitting(struct intel_crtc_state *crtc_state,
0603 const struct drm_connector_state *conn_state)
0604 {
0605 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
0606 struct drm_i915_private *i915 = to_i915(crtc->base.dev);
0607
0608 if (HAS_GMCH(i915))
0609 return gmch_panel_fitting(crtc_state, conn_state);
0610 else
0611 return pch_panel_fitting(crtc_state, conn_state);
0612 }
0613
0614 enum drm_connector_status
0615 intel_panel_detect(struct drm_connector *connector, bool force)
0616 {
0617 struct drm_i915_private *i915 = to_i915(connector->dev);
0618
0619 if (!INTEL_DISPLAY_ENABLED(i915))
0620 return connector_status_disconnected;
0621
0622 return connector_status_connected;
0623 }
0624
0625 enum drm_mode_status
0626 intel_panel_mode_valid(struct intel_connector *connector,
0627 const struct drm_display_mode *mode)
0628 {
0629 const struct drm_display_mode *fixed_mode =
0630 intel_panel_fixed_mode(connector, mode);
0631
0632 if (!fixed_mode)
0633 return MODE_OK;
0634
0635 if (mode->hdisplay != fixed_mode->hdisplay)
0636 return MODE_PANEL;
0637
0638 if (mode->vdisplay != fixed_mode->vdisplay)
0639 return MODE_PANEL;
0640
0641 if (drm_mode_vrefresh(mode) != drm_mode_vrefresh(fixed_mode))
0642 return MODE_PANEL;
0643
0644 return MODE_OK;
0645 }
0646
0647 int intel_panel_init(struct intel_connector *connector)
0648 {
0649 struct intel_panel *panel = &connector->panel;
0650
0651 intel_backlight_init_funcs(panel);
0652
0653 drm_dbg_kms(connector->base.dev,
0654 "[CONNECTOR:%d:%s] DRRS type: %s\n",
0655 connector->base.base.id, connector->base.name,
0656 intel_drrs_type_str(intel_panel_drrs_type(connector)));
0657
0658 return 0;
0659 }
0660
0661 void intel_panel_fini(struct intel_connector *connector)
0662 {
0663 struct intel_panel *panel = &connector->panel;
0664 struct drm_display_mode *fixed_mode, *next;
0665
0666 intel_backlight_destroy(panel);
0667
0668 intel_bios_fini_panel(panel);
0669
0670 list_for_each_entry_safe(fixed_mode, next, &panel->fixed_modes, head) {
0671 list_del(&fixed_mode->head);
0672 drm_mode_destroy(connector->base.dev, fixed_mode);
0673 }
0674 }