diff options
-rw-r--r-- | drivers/gpu/drm/drm_atomic.c | 20 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_crtc.c | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_mode_config.c | 24 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_display.c | 69 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_drv.h | 2 | ||||
-rw-r--r-- | include/drm/drm_crtc.h | 1 | ||||
-rw-r--r-- | include/drm/drm_mode_config.h | 4 | ||||
-rw-r--r-- | include/uapi/drm/drm_mode.h | 1 |
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 |