@@ -123,6 +123,7 @@ static const struct drm_prop_enum_list drm_scaling_mode_enum_list[] =
{ DRM_MODE_SCALE_FULLSCREEN, "Full" },
{ DRM_MODE_SCALE_CENTER, "Center" },
{ DRM_MODE_SCALE_ASPECT, "Full aspect" },
+ { DRM_MODE_SCALE_MANUAL, "Manual" },
};
/*
@@ -886,12 +886,22 @@ intel_dp_compute_config(struct intel_encoder *encoder,
if (is_edp(intel_dp) && intel_connector->panel.fixed_mode) {
intel_fixed_panel_mode(intel_connector->panel.fixed_mode,
adjusted_mode);
- if (!HAS_PCH_SPLIT(dev))
- intel_gmch_panel_fitting(intel_crtc, pipe_config,
- intel_connector->panel.fitting_mode);
- else
- intel_pch_panel_fitting(intel_crtc, pipe_config,
- intel_connector->panel.fitting_mode);
+ if (!HAS_PCH_SPLIT(dev)) {
+ if (intel_connector->panel.fitting_mode == DRM_MODE_SCALE_MANUAL)
+ intel_gmch_manual_panel_fitting(intel_crtc, pipe_config,
+ intel_connector->panel.display_window_size);
+ else
+ intel_gmch_panel_fitting(intel_crtc, pipe_config,
+ intel_connector->panel.fitting_mode);
+ }
+ else {
+ if (intel_connector->panel.fitting_mode == DRM_MODE_SCALE_MANUAL)
+ intel_pch_manual_panel_fitting(intel_crtc, pipe_config,
+ intel_connector->panel.display_window_size);
+ else
+ intel_pch_panel_fitting(intel_crtc, pipe_config,
+ intel_connector->panel.fitting_mode);
+ }
}
if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK)
@@ -3376,14 +3386,36 @@ intel_dp_set_property(struct drm_connector *connector,
}
if (intel_connector->panel.fitting_mode == val) {
- /* the eDP scaling property is not changed */
- return 0;
+ /* Check if display window size has changed */
+ if ((val == DRM_MODE_SCALE_MANUAL) &&
+ intel_connector->panel.display_window_size_changed)
+ intel_connector->panel.display_window_size_changed = 0;
+ else {
+ /* the eDP scaling property is not changed */
+ return 0;
+ }
}
intel_connector->panel.fitting_mode = val;
+ if (val != DRM_MODE_SCALE_MANUAL)
+ intel_connector->panel.display_window_size = 0;
+
goto done;
}
+ if (is_edp(intel_dp) &&
+ property == connector->dev->mode_config.window_size_property) {
+ if (intel_connector->panel.display_window_size == val) {
+ /* the eDP panel window size property is not changed */
+ intel_connector->panel.display_window_size_changed = 0;
+ return 0;
+ }
+ intel_connector->panel.display_window_size = val;
+ intel_connector->panel.display_window_size_changed = 1;
+
+ return 0;
+ }
+
return -EINVAL;
done:
@@ -3517,6 +3549,16 @@ intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connect
connector->dev->mode_config.scaling_mode_property,
DRM_MODE_SCALE_ASPECT);
intel_connector->panel.fitting_mode = DRM_MODE_SCALE_ASPECT;
+
+ connector->dev->mode_config.window_size_property =
+ drm_property_create_range(connector->dev, 0,
+ "window size", 0, 0xFFFFFFFF);
+ drm_object_attach_property(
+ &connector->base,
+ connector->dev->mode_config.window_size_property,
+ 0);
+ intel_connector->panel.display_window_size = 0;
+ intel_connector->panel.display_window_size_changed = 0;
}
}
@@ -157,6 +157,8 @@ struct intel_panel {
struct drm_display_mode *fixed_mode;
struct drm_display_mode *downclock_mode;
int fitting_mode;
+ u32 display_window_size;
+ bool display_window_size_changed;
/* backlight */
struct {
@@ -841,9 +843,15 @@ void intel_fixed_panel_mode(const struct drm_display_mode *fixed_mode,
void intel_pch_panel_fitting(struct intel_crtc *crtc,
struct intel_crtc_config *pipe_config,
int fitting_mode);
+void intel_pch_manual_panel_fitting(struct intel_crtc *intel_crtc,
+ struct intel_crtc_config *pipe_config,
+ u32 display_window_size);
void intel_gmch_panel_fitting(struct intel_crtc *crtc,
struct intel_crtc_config *pipe_config,
int fitting_mode);
+void intel_gmch_manual_panel_fitting(struct intel_crtc *crtc,
+ struct intel_crtc_config *pipe_config,
+ u32 display_window_size);
void intel_panel_set_backlight(struct intel_connector *connector, u32 level,
u32 max);
int intel_panel_setup_backlight(struct drm_connector *connector);
@@ -114,6 +114,48 @@ done:
pipe_config->pch_pfit.enabled = pipe_config->pch_pfit.size != 0;
}
+void
+intel_pch_manual_panel_fitting(struct intel_crtc *intel_crtc,
+ struct intel_crtc_config *pipe_config,
+ u32 display_window_size)
+{
+ struct drm_display_mode *adjusted_mode;
+ int x, y;
+ u32 tot_width, tot_height;
+ u32 dst_width, dst_height;
+
+ adjusted_mode = &pipe_config->adjusted_mode;
+
+ tot_width = adjusted_mode->crtc_hdisplay;
+ tot_height = adjusted_mode->crtc_vdisplay;
+
+ dst_width = ((display_window_size >> 16) & 0xffff);
+ dst_height = (display_window_size & 0xffff);
+
+ x = y = 0;
+
+ if (tot_width < dst_width) {
+ DRM_ERROR("width is too big\n");
+ return;
+ } else if (dst_width & 1) {
+ DRM_ERROR("width must be even\n");
+ return;
+ } else if (tot_height < dst_height) {
+ DRM_ERROR("height is too big\n");
+ return;
+ } else if (dst_height & 1) {
+ DRM_ERROR("height must be even\n");
+ return;
+ }
+
+ x = (adjusted_mode->hdisplay - dst_width + 1)/2;
+ y = (adjusted_mode->vdisplay - dst_height + 1)/2;
+
+ pipe_config->pch_pfit.pos = (x << 16) | y;
+ pipe_config->pch_pfit.size = (dst_width << 16) | dst_height;
+ pipe_config->pch_pfit.enabled = pipe_config->pch_pfit.size != 0;
+}
+
static void
centre_horizontally(struct drm_display_mode *mode,
int width)
@@ -323,6 +365,68 @@ out:
pipe_config->gmch_pfit.lvds_border_bits = border;
}
+void intel_gmch_manual_panel_fitting(struct intel_crtc *intel_crtc,
+ struct intel_crtc_config *pipe_config,
+ u32 display_window_size)
+{
+ u32 pfit_control = 0, border = 0;
+ u32 pf_horizontal_ratio, pf_vertical_ratio;
+ struct drm_display_mode *adjusted_mode;
+ u32 tot_width, tot_height;
+ u32 src_width, src_height; /* pipesrc.x, pipesrc.y */
+ u32 dst_width, dst_height;
+
+ adjusted_mode = &pipe_config->adjusted_mode;
+
+ src_width = pipe_config->pipe_src_w;
+ src_height = pipe_config->pipe_src_h;
+
+ tot_width = adjusted_mode->crtc_hdisplay;
+ tot_height = adjusted_mode->crtc_vdisplay;
+
+ dst_width = ((display_window_size >> 16) & 0xffff);
+ dst_height = (display_window_size & 0xffff);
+
+ pf_horizontal_ratio = panel_fitter_scaling(src_width, dst_width);
+ pf_vertical_ratio = panel_fitter_scaling(src_height, dst_height);
+
+/* Max Downscale ratio of 1.125, expressed in 1.12 fixed point format */
+#define MAX_DOWNSCALE_RATIO (0x9 << 9)
+
+ if (pf_horizontal_ratio > MAX_DOWNSCALE_RATIO) {
+ DRM_ERROR("width is too small\n");
+ return;
+ } else if (tot_width < dst_width) {
+ DRM_ERROR("width is too big\n");
+ return;
+ } else if (dst_width & 1) {
+ DRM_ERROR("width must be even\n");
+ return;
+ } else if (pf_vertical_ratio > MAX_DOWNSCALE_RATIO) {
+ DRM_ERROR("height is too small\n");
+ return;
+ } else if (tot_height < dst_height) {
+ DRM_ERROR("height is too big\n");
+ return;
+ } else if (dst_height & 1) {
+ DRM_ERROR("height must be even\n");
+ return;
+ }
+
+ centre_horizontally(adjusted_mode, dst_width);
+ centre_vertically(adjusted_mode, dst_height);
+ border = LVDS_BORDER_ENABLE;
+
+ /* PFIT_SCALING_PROGRAMMED is de-featured on BYT */
+ pfit_control |= PFIT_ENABLE | PFIT_SCALING_AUTO;
+ pfit_control |= ((intel_crtc->pipe << PFIT_PIPE_SHIFT) | PFIT_FILTER_FUZZY);
+
+ pipe_config->gmch_pfit.control = pfit_control;
+ pipe_config->gmch_pfit.lvds_border_bits = border;
+
+ return;
+}
+
static u32 intel_panel_compute_brightness(struct intel_connector *connector,
u32 val)
{
@@ -902,6 +902,9 @@ struct drm_mode_config {
struct drm_property *scaling_mode_property;
struct drm_property *dirty_info_property;
+ /* Panel fitter output property */
+ struct drm_property *window_size_property;
+
/* dumb ioctl parameters */
uint32_t preferred_depth, prefer_shadow;
@@ -87,6 +87,7 @@
#define DRM_MODE_SCALE_FULLSCREEN 1 /* Full screen, ignore aspect */
#define DRM_MODE_SCALE_CENTER 2 /* Centered, no scaling */
#define DRM_MODE_SCALE_ASPECT 3 /* Full screen, preserve aspect */
+#define DRM_MODE_SCALE_MANUAL 4 /* User can control display window size */
/* Dithering mode options */
#define DRM_MODE_DITHERING_OFF 0