Commit 3c4fdcfb authored by Kristian Høgsberg's avatar Kristian Høgsberg Committed by Dave Airlie

drm: pin new and unpin old buffer when setting a mode.

This removes the requirement for user space to pin a buffer before
setting a mode that is backed by the pixels from that buffer.
Signed-off-by: default avatarKristian Høgsberg <krh@redhat.com>
Signed-off-by: default avatarEric Anholt <eric@anholt.net>
Signed-off-by: default avatarDave Airlie <airlied@linux.ie>
parent d1e22c6e
...@@ -432,7 +432,8 @@ static void drm_setup_crtcs(struct drm_device *dev) ...@@ -432,7 +432,8 @@ static void drm_setup_crtcs(struct drm_device *dev)
*/ */
bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
struct drm_display_mode *mode, struct drm_display_mode *mode,
int x, int y) int x, int y,
struct drm_framebuffer *old_fb)
{ {
struct drm_device *dev = crtc->dev; struct drm_device *dev = crtc->dev;
struct drm_display_mode *adjusted_mode, saved_mode; struct drm_display_mode *adjusted_mode, saved_mode;
...@@ -462,7 +463,8 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, ...@@ -462,7 +463,8 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
if (drm_mode_equal(&saved_mode, &crtc->mode)) { if (drm_mode_equal(&saved_mode, &crtc->mode)) {
if (saved_x != crtc->x || saved_y != crtc->y) { if (saved_x != crtc->x || saved_y != crtc->y) {
crtc_funcs->mode_set_base(crtc, crtc->x, crtc->y); crtc_funcs->mode_set_base(crtc, crtc->x, crtc->y,
old_fb);
goto done; goto done;
} }
} }
...@@ -501,7 +503,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, ...@@ -501,7 +503,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
/* Set up the DPLL and any encoders state that needs to adjust or depend /* Set up the DPLL and any encoders state that needs to adjust or depend
* on the DPLL. * on the DPLL.
*/ */
crtc_funcs->mode_set(crtc, mode, adjusted_mode, x, y); crtc_funcs->mode_set(crtc, mode, adjusted_mode, x, y, old_fb);
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
...@@ -564,6 +566,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) ...@@ -564,6 +566,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
struct drm_device *dev; struct drm_device *dev;
struct drm_crtc **save_crtcs, *new_crtc; struct drm_crtc **save_crtcs, *new_crtc;
struct drm_encoder **save_encoders, *new_encoder; struct drm_encoder **save_encoders, *new_encoder;
struct drm_framebuffer *old_fb;
bool save_enabled; bool save_enabled;
bool changed = false; bool changed = false;
bool flip_or_move = false; bool flip_or_move = false;
...@@ -684,13 +687,15 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) ...@@ -684,13 +687,15 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
changed = true; changed = true;
if (changed) { if (changed) {
old_fb = set->crtc->fb;
set->crtc->fb = set->fb; set->crtc->fb = set->fb;
set->crtc->enabled = (set->mode != NULL); set->crtc->enabled = (set->mode != NULL);
if (set->mode != NULL) { if (set->mode != NULL) {
DRM_DEBUG("attempting to set mode from userspace\n"); DRM_DEBUG("attempting to set mode from userspace\n");
drm_mode_debug_printmodeline(set->mode); drm_mode_debug_printmodeline(set->mode);
if (!drm_crtc_helper_set_mode(set->crtc, set->mode, if (!drm_crtc_helper_set_mode(set->crtc, set->mode,
set->x, set->y)) { set->x, set->y,
old_fb)) {
ret = -EINVAL; ret = -EINVAL;
goto fail_set_mode; goto fail_set_mode;
} }
...@@ -701,9 +706,10 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) ...@@ -701,9 +706,10 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
} }
drm_helper_disable_unused_functions(dev); drm_helper_disable_unused_functions(dev);
} else if (flip_or_move) { } else if (flip_or_move) {
old_fb = set->crtc->fb;
if (set->crtc->fb != set->fb) if (set->crtc->fb != set->fb)
set->crtc->fb = set->fb; set->crtc->fb = set->fb;
crtc_funcs->mode_set_base(set->crtc, set->x, set->y); crtc_funcs->mode_set_base(set->crtc, set->x, set->y, old_fb);
} }
kfree(save_encoders); kfree(save_encoders);
...@@ -809,8 +815,8 @@ int drm_helper_resume_force_mode(struct drm_device *dev) ...@@ -809,8 +815,8 @@ int drm_helper_resume_force_mode(struct drm_device *dev)
if (!crtc->enabled) if (!crtc->enabled)
continue; continue;
ret = drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x, ret = drm_crtc_helper_set_mode(crtc, &crtc->mode,
crtc->y); crtc->x, crtc->y, crtc->fb);
if (ret == false) if (ret == false)
DRM_ERROR("failed to set mode on crtc %p\n", crtc); DRM_ERROR("failed to set mode on crtc %p\n", crtc);
......
...@@ -344,7 +344,8 @@ intel_wait_for_vblank(struct drm_device *dev) ...@@ -344,7 +344,8 @@ intel_wait_for_vblank(struct drm_device *dev)
} }
static void static void
intel_pipe_set_base(struct drm_crtc *crtc, int x, int y) intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
struct drm_framebuffer *old_fb)
{ {
struct drm_device *dev = crtc->dev; struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
...@@ -359,7 +360,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y) ...@@ -359,7 +360,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y)
int dspsurf = (pipe == 0 ? DSPASURF : DSPBSURF); int dspsurf = (pipe == 0 ? DSPASURF : DSPBSURF);
int dspstride = (pipe == 0) ? DSPASTRIDE : DSPBSTRIDE; int dspstride = (pipe == 0) ? DSPASTRIDE : DSPBSTRIDE;
int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR; int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR;
u32 dspcntr; u32 dspcntr, alignment;
/* no fb bound */ /* no fb bound */
if (!crtc->fb) { if (!crtc->fb) {
...@@ -368,10 +369,32 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y) ...@@ -368,10 +369,32 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y)
} }
intel_fb = to_intel_framebuffer(crtc->fb); intel_fb = to_intel_framebuffer(crtc->fb);
obj = intel_fb->obj; obj = intel_fb->obj;
obj_priv = obj->driver_private; obj_priv = obj->driver_private;
switch (obj_priv->tiling_mode) {
case I915_TILING_NONE:
alignment = 64 * 1024;
break;
case I915_TILING_X:
if (IS_I9XX(dev))
alignment = 1024 * 1024;
else
alignment = 512 * 1024;
break;
case I915_TILING_Y:
/* FIXME: Is this true? */
DRM_ERROR("Y tiled not allowed for scan out buffers\n");
return;
default:
BUG();
}
if (i915_gem_object_pin(intel_fb->obj, alignment))
return;
i915_gem_object_set_to_gtt_domain(intel_fb->obj, 1);
Start = obj_priv->gtt_offset; Start = obj_priv->gtt_offset;
Offset = y * crtc->fb->pitch + x * (crtc->fb->bits_per_pixel / 8); Offset = y * crtc->fb->pitch + x * (crtc->fb->bits_per_pixel / 8);
...@@ -409,6 +432,12 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y) ...@@ -409,6 +432,12 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y)
I915_READ(dspbase); I915_READ(dspbase);
} }
intel_wait_for_vblank(dev);
if (old_fb) {
intel_fb = to_intel_framebuffer(old_fb);
i915_gem_object_unpin(intel_fb->obj);
}
if (!dev->primary->master) if (!dev->primary->master)
return; return;
...@@ -680,7 +709,8 @@ static int intel_panel_fitter_pipe (struct drm_device *dev) ...@@ -680,7 +709,8 @@ static int intel_panel_fitter_pipe (struct drm_device *dev)
static void intel_crtc_mode_set(struct drm_crtc *crtc, static void intel_crtc_mode_set(struct drm_crtc *crtc,
struct drm_display_mode *mode, struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode, struct drm_display_mode *adjusted_mode,
int x, int y) int x, int y,
struct drm_framebuffer *old_fb)
{ {
struct drm_device *dev = crtc->dev; struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
...@@ -915,9 +945,7 @@ static void intel_crtc_mode_set(struct drm_crtc *crtc, ...@@ -915,9 +945,7 @@ static void intel_crtc_mode_set(struct drm_crtc *crtc,
I915_WRITE(dspcntr_reg, dspcntr); I915_WRITE(dspcntr_reg, dspcntr);
/* Flush the plane changes */ /* Flush the plane changes */
intel_pipe_set_base(crtc, x, y); intel_pipe_set_base(crtc, x, y, old_fb);
intel_wait_for_vblank(dev);
drm_vblank_post_modeset(dev, pipe); drm_vblank_post_modeset(dev, pipe);
} }
...@@ -1153,7 +1181,7 @@ struct drm_crtc *intel_get_load_detect_pipe(struct intel_output *intel_output, ...@@ -1153,7 +1181,7 @@ struct drm_crtc *intel_get_load_detect_pipe(struct intel_output *intel_output,
if (!crtc->enabled) { if (!crtc->enabled) {
if (!mode) if (!mode)
mode = &load_detect_mode; mode = &load_detect_mode;
drm_crtc_helper_set_mode(crtc, mode, 0, 0); drm_crtc_helper_set_mode(crtc, mode, 0, 0, crtc->fb);
} else { } else {
if (intel_crtc->dpms_mode != DRM_MODE_DPMS_ON) { if (intel_crtc->dpms_mode != DRM_MODE_DPMS_ON) {
crtc_funcs = crtc->helper_private; crtc_funcs = crtc->helper_private;
......
...@@ -55,10 +55,12 @@ struct drm_crtc_helper_funcs { ...@@ -55,10 +55,12 @@ struct drm_crtc_helper_funcs {
struct drm_display_mode *adjusted_mode); struct drm_display_mode *adjusted_mode);
/* Actually set the mode */ /* Actually set the mode */
void (*mode_set)(struct drm_crtc *crtc, struct drm_display_mode *mode, void (*mode_set)(struct drm_crtc *crtc, struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode, int x, int y); struct drm_display_mode *adjusted_mode, int x, int y,
struct drm_framebuffer *old_fb);
/* Move the crtc on the current fb to the given position *optional* */ /* Move the crtc on the current fb to the given position *optional* */
void (*mode_set_base)(struct drm_crtc *crtc, int x, int y); void (*mode_set_base)(struct drm_crtc *crtc, int x, int y,
struct drm_framebuffer *old_fb);
}; };
struct drm_encoder_helper_funcs { struct drm_encoder_helper_funcs {
...@@ -93,7 +95,8 @@ extern bool drm_helper_initial_config(struct drm_device *dev, bool can_grow); ...@@ -93,7 +95,8 @@ extern bool drm_helper_initial_config(struct drm_device *dev, bool can_grow);
extern int drm_crtc_helper_set_config(struct drm_mode_set *set); extern int drm_crtc_helper_set_config(struct drm_mode_set *set);
extern bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, extern bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
struct drm_display_mode *mode, struct drm_display_mode *mode,
int x, int y); int x, int y,
struct drm_framebuffer *old_fb);
extern bool drm_helper_crtc_in_use(struct drm_crtc *crtc); extern bool drm_helper_crtc_in_use(struct drm_crtc *crtc);
extern int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, extern int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment