summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/drm_atomic.c20
-rw-r--r--drivers/gpu/drm/drm_crtc.c8
-rw-r--r--drivers/gpu/drm/drm_mode_config.c24
-rw-r--r--drivers/gpu/drm/i915/intel_display.c69
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h2
-rw-r--r--include/drm/drm_crtc.h1
-rw-r--r--include/drm/drm_mode_config.h4
-rw-r--r--include/uapi/drm/drm_mode.h1
8 files changed, 125 insertions, 4 deletions
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 3568a354c2d3..d132e98f7a4c 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -525,6 +525,18 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
} else if (property == config->prop_fitting_mode) {
state->fitting_mode = val;
state->pipescaler_changed = true;
+ } else if (property == config->prop_pipe_dst_x) {
+ state->dst_x = val;
+ state->pipescaler_changed = true;
+ } else if (property == config->prop_pipe_dst_y) {
+ state->dst_y = val;
+ state->pipescaler_changed = true;
+ } else if (property == config->prop_pipe_dst_w) {
+ state->dst_w = val;
+ state->pipescaler_changed = true;
+ } else if (property == config->prop_pipe_dst_h) {
+ state->dst_h = val;
+ state->pipescaler_changed = true;
} else if (crtc->funcs->atomic_set_property)
return crtc->funcs->atomic_set_property(crtc, state, property, val);
else
@@ -575,6 +587,14 @@ drm_atomic_crtc_get_property(struct drm_crtc *crtc,
*val = state->src_h;
else if (property == config->prop_fitting_mode)
*val = state->fitting_mode;
+ else if (property == config->prop_pipe_dst_x)
+ *val = state->dst_x;
+ else if (property == config->prop_pipe_dst_y)
+ *val = state->dst_y;
+ else if (property == config->prop_pipe_dst_w)
+ *val = state->dst_w;
+ else if (property == config->prop_pipe_dst_h)
+ *val = state->dst_h;
else if (crtc->funcs->atomic_get_property)
return crtc->funcs->atomic_get_property(crtc, state, property, val);
else
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 766641709e66..4784dd017df1 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -342,6 +342,14 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
config->prop_pipe_src_h, 0);
drm_object_attach_property(&crtc->base,
config->prop_fitting_mode, 0);
+ drm_object_attach_property(&crtc->base,
+ config->prop_pipe_dst_x, 0);
+ drm_object_attach_property(&crtc->base,
+ config->prop_pipe_dst_y, 0);
+ drm_object_attach_property(&crtc->base,
+ config->prop_pipe_dst_w, 0);
+ drm_object_attach_property(&crtc->base,
+ config->prop_pipe_dst_h, 0);
}
return 0;
diff --git a/drivers/gpu/drm/drm_mode_config.c b/drivers/gpu/drm/drm_mode_config.c
index 5b512fc6b718..424bb0f0b641 100644
--- a/drivers/gpu/drm/drm_mode_config.c
+++ b/drivers/gpu/drm/drm_mode_config.c
@@ -354,6 +354,30 @@ static int drm_mode_create_standard_properties(struct drm_device *dev)
return -ENOMEM;
dev->mode_config.prop_fitting_mode = prop;
+ prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
+ "PIPE_DST_X", 0, INT_MAX);
+ if (!prop)
+ return -ENOMEM;
+ dev->mode_config.prop_pipe_dst_x = prop;
+
+ prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
+ "PIPE_DST_Y", 0, INT_MAX);
+ if (!prop)
+ return -ENOMEM;
+ dev->mode_config.prop_pipe_dst_y = prop;
+
+ prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
+ "PIPE_DST_W", 0, INT_MAX);
+ if (!prop)
+ return -ENOMEM;
+ dev->mode_config.prop_pipe_dst_w = prop;
+
+ prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
+ "PIPE_DST_H", 0, INT_MAX);
+ if (!prop)
+ return -ENOMEM;
+ dev->mode_config.prop_pipe_dst_h = prop;
+
return 0;
}
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index ef783a98c007..82be6b717ffe 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -10926,6 +10926,35 @@ static bool check_single_encoder_cloning(struct drm_atomic_state *state,
return true;
}
+void
+intel_gen9_pipe_scale(struct intel_crtc *intel_crtc,
+ struct intel_crtc_state *pipe_config,
+ int fitting_mode)
+{
+ const struct drm_display_mode *adjusted_mode =
+ &pipe_config->base.adjusted_mode;
+ int x = 0, y = 0, width = 0, height = 0;
+
+ /* Native modes don't need fitting */
+ if ((adjusted_mode->crtc_hdisplay == pipe_config->pipe_src_w &&
+ adjusted_mode->crtc_vdisplay == pipe_config->pipe_src_h) &&
+ ((pipe_config->pipe_dst_x + pipe_config->pipe_dst_w) ==
+ pipe_config->pipe_src_w) &&
+ ((pipe_config->pipe_dst_y + pipe_config->pipe_dst_h) ==
+ pipe_config->pipe_src_w))
+ goto done;
+
+ x = pipe_config->pipe_dst_x;
+ y = pipe_config->pipe_dst_y;
+ width = pipe_config->pipe_dst_w;
+ height = pipe_config->pipe_dst_h;
+
+done:
+ pipe_config->pch_pfit.pos = (x << 16) | y;
+ pipe_config->pch_pfit.size = (width << 16) | height;
+ pipe_config->pch_pfit.enabled = pipe_config->pch_pfit.size != 0;
+}
+
static int skylake_pfiter_calculate(struct drm_crtc *crtc,
struct drm_crtc_state *crtc_state)
{
@@ -10938,16 +10967,36 @@ static int skylake_pfiter_calculate(struct drm_crtc *crtc,
if (((pipe_config->pipe_scaling_mode !=
intel_crtc->config->pipe_scaling_mode) ||
(pipe_config->pipe_src_w != intel_crtc->config->pipe_src_w) ||
- (pipe_config->pipe_src_h != intel_crtc->config->pipe_src_h)) &&
+ (pipe_config->pipe_src_h != intel_crtc->config->pipe_src_h) ||
+ (pipe_config->pipe_dst_x != intel_crtc->config->pipe_dst_x) ||
+ (pipe_config->pipe_dst_y != intel_crtc->config->pipe_dst_y) ||
+ (pipe_config->pipe_dst_w != intel_crtc->config->pipe_dst_w) ||
+ (pipe_config->pipe_dst_h != intel_crtc->config->pipe_dst_h)) &&
(!mode_changed)) {
pipe_config->update_pipe = true;
}
if ((mode_changed) || (pipe_config->update_pipe)) {
ret = skl_update_scaler_crtc(pipe_config);
- if (!ret)
- intel_pch_panel_fitting(intel_crtc, pipe_config,
- pipe_config->pipe_scaling_mode);
+ if (!ret) {
+ if (pipe_config->pipe_scaling_mode ==
+ DRM_MODE_SCALE_CUSTOM) {
+ intel_gen9_pipe_scale(intel_crtc, pipe_config,
+ pipe_config->pipe_scaling_mode);
+ } else {
+ intel_pch_panel_fitting(intel_crtc,
+ pipe_config,
+ pipe_config->pipe_scaling_mode);
+ pipe_config->pipe_dst_x =
+ (pipe_config->pch_pfit.pos >> 16);
+ pipe_config->pipe_dst_y =
+ (pipe_config->pch_pfit.pos & 0xffff);
+ pipe_config->pipe_dst_w =
+ (pipe_config->pch_pfit.size >> 16);
+ pipe_config->pipe_dst_h =
+ (pipe_config->pch_pfit.size & 0xffff);
+ }
+ }
}
return ret;
}
@@ -11402,6 +11451,9 @@ intel_modeset_pipe_config(struct drm_crtc *crtc,
pipe_config->output_types |= 1 << encoder->type;
}
+ pipe_config->pipe_dst_w = pipe_config->pipe_src_w;
+ pipe_config->pipe_dst_h = pipe_config->pipe_src_h;
+
encoder_retry:
/* Ensure the port clock defaults are reset when retrying. */
pipe_config->port_clock = 0;
@@ -12507,11 +12559,20 @@ static int intel_atomic_check(struct drm_device *dev,
crtc_state->src_w = adjusted_mode->hdisplay;
crtc_state->src_h = adjusted_mode->vdisplay;
+ crtc_state->dst_w = adjusted_mode->hdisplay;
+ crtc_state->dst_h = adjusted_mode->vdisplay;
+ crtc_state->dst_x = 0;
+ crtc_state->dst_y = 0;
+ crtc_state->fitting_mode = 0;
}
pipe_config->pipe_src_w = crtc_state->src_w;
pipe_config->pipe_src_h = crtc_state->src_h;
pipe_config->pipe_scaling_mode =
crtc_state->fitting_mode;
+ pipe_config->pipe_dst_x = crtc_state->dst_x;
+ pipe_config->pipe_dst_y = crtc_state->dst_y;
+ pipe_config->pipe_dst_w = crtc_state->dst_w;
+ pipe_config->pipe_dst_h = crtc_state->dst_h;
crtc_state->pipescaler_changed = false;
}
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 35d3fd99d44f..d43acad4bace 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -586,6 +586,8 @@ struct intel_crtc_state {
* and get clipped at the edges. */
int pipe_src_w, pipe_src_h;
u32 pipe_scaling_mode;
+ int pipe_dst_x, pipe_dst_y;
+ int pipe_dst_w, pipe_dst_h;
/*
* Pipe pixel rate, adjusted for
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index bf5e679a8729..91a95a2587e5 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -218,6 +218,7 @@ struct drm_crtc_state {
bool pipescaler_changed;
u32 src_w, src_h;
u32 fitting_mode;
+ u32 dst_x, dst_y, dst_w, dst_h;
};
/**
diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h
index 6ef878944f79..f345c184b5d6 100644
--- a/include/drm/drm_mode_config.h
+++ b/include/drm/drm_mode_config.h
@@ -540,6 +540,10 @@ struct drm_mode_config {
struct drm_property *prop_pipe_src_w;
struct drm_property *prop_pipe_src_h;
struct drm_property *prop_fitting_mode;
+ struct drm_property *prop_pipe_dst_x;
+ struct drm_property *prop_pipe_dst_y;
+ struct drm_property *prop_pipe_dst_w;
+ struct drm_property *prop_pipe_dst_h;
/**
* @dvi_i_subconnector_property: Optional DVI-I property to
diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h
index 8c67fc03d53d..57abc956e384 100644
--- a/include/uapi/drm/drm_mode.h
+++ b/include/uapi/drm/drm_mode.h
@@ -112,6 +112,7 @@ extern "C" {
#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_CUSTOM 4 /* Custom pipe scaling */
/* Dithering mode options */
#define DRM_MODE_DITHERING_OFF 0