/* * "Restriction : When pipe scaling is enabled, the scaled * output must equal the pipe active area, so Pipe active * size = (2 * PF window position) + PF window size." * * The vertical direction seems more forgiving than the * horizontal direction, but still has some issues so * let's follow the same hard rule for both.
*/ if (adjusted_mode->crtc_hdisplay != 2 * x + width ||
adjusted_mode->crtc_vdisplay != 2 * y + height) {
drm_dbg_kms(display->drm, "[CRTC:%d:%s] pfit window (" DRM_RECT_FMT ") not centered\n",
crtc->base.base.id, crtc->base.name, DRM_RECT_ARG(dst)); return -EINVAL;
}
/* * "Restriction : The X position must not be programmed * to be 1 (28:16=0 0000 0000 0001b)."
*/ if (x == 1) {
drm_dbg_kms(display->drm, "[CRTC:%d:%s] pfit window (" DRM_RECT_FMT ") badly positioned\n",
crtc->base.base.id, crtc->base.name, DRM_RECT_ARG(dst)); return -EINVAL;
}
return 0;
}
staticint intel_pch_pfit_check_src_size(conststruct intel_crtc_state *crtc_state)
{ struct intel_display *display = to_intel_display(crtc_state); struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); int pipe_src_w = drm_rect_width(&crtc_state->pipe_src); int pipe_src_h = drm_rect_height(&crtc_state->pipe_src); int max_src_w, max_src_h;
if (DISPLAY_VER(display) >= 8) {
max_src_w = 4096;
max_src_h = 4096;
} elseif (DISPLAY_VER(display) >= 7) { /* * PF0 7x5 capable * PF1 3x3 capable (could be switched to 7x5 * mode on HSW when PF2 unused) * PF2 3x3 capable * * This assumes we use a 1:1 mapping between pipe and PF.
*/
max_src_w = crtc->pipe == PIPE_A ? 4096 : 2048;
max_src_h = 4096;
} else {
max_src_w = 4096;
max_src_h = 4096;
}
/* * The panel fitter is in the pipe and thus would affect every * cloned output. The relevant properties (scaling mode, TV * margins) are per-connector so we'd have to make sure each * output sets them up identically. Seems like a very niche use * case so let's just reject cloning entirely when pfit is used.
*/ if (crtc_state->uapi.encoder_mask &&
!is_power_of_2(crtc_state->uapi.encoder_mask)) {
drm_dbg_kms(display->drm, "[CRTC:%d:%s] no pfit when cloning\n",
crtc->base.base.id, crtc->base.name); return -EINVAL;
}
return 0;
}
/* adjusted_mode has been preset to be the panel's fixed mode */ staticint pch_panel_fitting(struct intel_crtc_state *crtc_state, conststruct drm_connector_state *conn_state)
{ struct intel_display *display = to_intel_display(crtc_state); conststruct drm_display_mode *adjusted_mode =
&crtc_state->hw.adjusted_mode; int pipe_src_w = drm_rect_width(&crtc_state->pipe_src); int pipe_src_h = drm_rect_height(&crtc_state->pipe_src); int ret, x, y, width, height;
drm_rect_init(&crtc_state->pch_pfit.dst,
x, y, width, height);
crtc_state->pch_pfit.enabled = true;
/* * SKL+ have unified scalers for pipes/planes so the * checks are done in a single place for all scalers.
*/ if (DISPLAY_VER(display) >= 9) return 0;
ret = intel_pch_pfit_check_dst_window(crtc_state); if (ret) return ret;
ret = intel_pch_pfit_check_src_size(crtc_state); if (ret) return ret;
ret = intel_pch_pfit_check_scaling(crtc_state); if (ret) return ret;
ret = intel_pch_pfit_check_timings(crtc_state); if (ret) return ret;
ret = intel_pch_pfit_check_cloning(crtc_state); if (ret) return ret;
static u32 panel_fitter_scaling(u32 source, u32 target)
{ /* * Floating point operation is not supported. So the FACTOR * is defined, which can avoid the floating point computation * when calculating the panel ratio.
*/ #define ACCURACY 12 #define FACTOR (1 << ACCURACY)
u32 ratio = source * FACTOR / target; return (FACTOR * ratio + FACTOR/2) / FACTOR;
}
/* * For earlier chips we have to calculate the scaling * ratio by hand and program it into the * PFIT_PGM_RATIO register
*/ if (scaled_width > scaled_height) { /* pillar */
centre_horizontally(adjusted_mode,
scaled_height / pipe_src_h);
/* Native modes don't need fitting */ if (adjusted_mode->crtc_hdisplay == pipe_src_w &&
adjusted_mode->crtc_vdisplay == pipe_src_h) goto out;
/* * TODO: implement downscaling for i965+. Need to account * for downscaling in intel_crtc_compute_pixel_rate().
*/ if (adjusted_mode->crtc_hdisplay < pipe_src_w) {
drm_dbg_kms(display->drm, "[CRTC:%d:%s] pfit horizontal downscaling (%d->%d) not supported\n",
crtc->base.base.id, crtc->base.name,
pipe_src_w, adjusted_mode->crtc_hdisplay); return -EINVAL;
} if (adjusted_mode->crtc_vdisplay < pipe_src_h) {
drm_dbg_kms(display->drm, "[CRTC:%d:%s] pfit vertical downscaling (%d->%d) not supported\n",
crtc->base.base.id, crtc->base.name,
pipe_src_h, adjusted_mode->crtc_vdisplay); return -EINVAL;
}
switch (conn_state->scaling_mode) { case DRM_MODE_SCALE_CENTER: /* * For centered modes, we have to calculate border widths & * heights and modify the values programmed into the CRTC.
*/
centre_horizontally(adjusted_mode, pipe_src_w);
centre_vertically(adjusted_mode, pipe_src_h);
border = LVDS_BORDER_ENABLE; break; case DRM_MODE_SCALE_ASPECT: /* Scale but preserve the aspect ratio */ if (DISPLAY_VER(display) >= 4)
i965_scale_aspect(crtc_state, &pfit_control); else
i9xx_scale_aspect(crtc_state, &pfit_control,
&pfit_pgm_ratios, &border); break; case DRM_MODE_SCALE_FULLSCREEN: /* * Full scaling, even if it changes the aspect ratio. * Fortunately this is all done for us in hw.
*/ if (pipe_src_h != adjusted_mode->crtc_vdisplay ||
pipe_src_w != adjusted_mode->crtc_hdisplay) {
pfit_control |= PFIT_ENABLE; if (DISPLAY_VER(display) >= 4)
pfit_control |= PFIT_SCALING_AUTO; else
pfit_control |= (PFIT_VERT_AUTO_SCALE |
PFIT_VERT_INTERP_BILINEAR |
PFIT_HORIZ_AUTO_SCALE |
PFIT_HORIZ_INTERP_BILINEAR);
} break; default:
MISSING_CASE(conn_state->scaling_mode); return -EINVAL;
}
/* * To avoid upsetting the power well on haswell only disable the pfit if * it's in use. The hw state code will make sure we get this right.
*/ if (!old_crtc_state->pch_pfit.enabled) return;
/* * We currently do not free assignments of panel fitters on * ivb/hsw (since we don't use the higher upscaling modes which * differentiates them) so just WARN about this case for now.
*/
drm_WARN_ON(display->drm, pipe != crtc->pipe);
}
/* * The panel fitter should only be adjusted whilst the pipe is disabled, * according to register description and PRM.
*/
drm_WARN_ON(display->drm,
intel_de_read(display, PFIT_CONTROL(display)) & PFIT_ENABLE);
assert_transcoder_disabled(display, crtc_state->cpu_transcoder);
/* * Border color in case we don't scale up to the full screen. Black by * default, change to something else for debugging.
*/
intel_de_write(display, BCLRPAT(display, crtc->pipe), 0);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.