Message ID | 1490652064-44817-6-git-send-email-syeh@vmware.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Mon, Mar 27, 2017 at 03:00:58PM -0700, Sinclair Yeh wrote: > Atomic mode set requires us to refactor existing vmw_stdu_crtc_set_config > code into sections that check the validity of the new mode, and sections > that actually program the hardware state. > > vmw_du_crtc_atomic_check() takes CRTC-related checking code. In a later > patch, vmw_du_primary_plane_atomic_check() will take framebuffer-related > checking code. > > These helpers won't be called until we flip on the atomic support > flag or set drm_crtc_funcs->set_config to using the atomic > helper. > > v2: > * The state->num_connector is actually the total number of potential > connectors, not just the one associated with the display unit. > The proper one to check is ->connector_mask. > > * Add the check to only allow plane state to be the same as crtc state > (Thanks to mlankhorst) > > * Make sure to turn on SVGA mode before using VRAM. SVGA mode is > disabled in master_drop if dbdev is not running. > > Signed-off-by: Sinclair Yeh <syeh@vmware.com> > Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> > Reviewed-by: Thomas Hellstrom <thellstrom@vmware.com> > --- > drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 48 ++++++++++++++ > drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | 9 +++ > drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | 79 +++++++++++++++++++++++ > drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c | 119 +++++++++++++++++++++++++++++++++++ > drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | 117 ++++++++++++++++++++++++++++++++++ > 5 files changed, 372 insertions(+) > > diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c > index a8e0909..6f0f160 100644 > --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c > +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c > @@ -399,6 +399,54 @@ void vmw_du_primary_plane_destroy(struct drm_plane *plane) > } > > > +int vmw_du_crtc_atomic_check(struct drm_crtc *crtc, > + struct drm_crtc_state *new_state) > +{ > + struct vmw_display_unit *du = vmw_crtc_to_du(new_state->crtc); > + int connector_mask = 1 << drm_connector_index(&du->connector); > + bool has_primary = new_state->plane_mask & > + BIT(drm_plane_index(crtc->primary)); > + > + /* We always want to have an active plane with an active CRTC */ > + if (has_primary != new_state->enable) > + return -EINVAL; > + > + > + if (new_state->connector_mask != connector_mask && > + new_state->connector_mask != 0) { > + DRM_ERROR("Invalid connectors configuration\n"); > + return -EINVAL; > + } > + > + return 0; > +} > + > + > +void vmw_du_crtc_atomic_begin(struct drm_crtc *crtc, > + struct drm_crtc_state *old_crtc_state) > +{ > +} > + > + > +void vmw_du_crtc_atomic_flush(struct drm_crtc *crtc, > + struct drm_crtc_state *old_crtc_state) > +{ > + struct drm_pending_vblank_event *event = crtc->state->event; > + > + if (event) { > + crtc->state->event = NULL; > + > + spin_lock_irq(&crtc->dev->event_lock); > + if (drm_crtc_vblank_get(crtc) == 0) > + drm_crtc_arm_vblank_event(crtc, event); > + else > + drm_crtc_send_vblank_event(crtc, event); > + spin_unlock_irq(&crtc->dev->event_lock); > + } > + > +} > + > + > /** > * vmw_du_crtc_duplicate_state - duplicate crtc state > * @crtc: DRM crtc > diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h > index cc50bf3..f711b5d 100644 > --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h > +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h > @@ -161,6 +161,7 @@ struct vmw_crtc_state { > * @surf Display surface for STDU > * @dmabuf display dmabuf for SOU > * @content_fb_type Used by STDU. > + * @dmabuf_size Size of the dmabuf, used by Screen Object Display Unit > * @pinned pin count for STDU display surface > */ > struct vmw_plane_state { > @@ -169,6 +170,7 @@ struct vmw_plane_state { > struct vmw_dma_buffer *dmabuf; > > int content_fb_type; > + unsigned long dmabuf_size; > > int pinned; > }; > @@ -342,10 +344,17 @@ int vmw_du_cursor_plane_update(struct drm_plane *plane, > uint32_t src_x, uint32_t src_y, > uint32_t src_w, uint32_t src_h); > > +/* Atomic Helpers */ > void vmw_du_plane_reset(struct drm_plane *plane); > struct drm_plane_state *vmw_du_plane_duplicate_state(struct drm_plane *plane); > void vmw_du_plane_destroy_state(struct drm_plane *plane, > struct drm_plane_state *state); > +int vmw_du_crtc_atomic_check(struct drm_crtc *crtc, > + struct drm_crtc_state *state); > +void vmw_du_crtc_atomic_begin(struct drm_crtc *crtc, > + struct drm_crtc_state *old_crtc_state); > +void vmw_du_crtc_atomic_flush(struct drm_crtc *crtc, > + struct drm_crtc_state *old_crtc_state); > void vmw_du_crtc_reset(struct drm_crtc *crtc); > struct drm_crtc_state *vmw_du_crtc_duplicate_state(struct drm_crtc *crtc); > void vmw_du_crtc_destroy_state(struct drm_crtc *crtc, > diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c > index 276c744..d547e80 100644 > --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c > +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c > @@ -167,6 +167,7 @@ static int vmw_ldu_add_active(struct vmw_private *vmw_priv, > if (vfb != ld->fb) { > if (ld->fb && ld->fb->unpin) > ld->fb->unpin(ld->fb); > + vmw_svga_enable(vmw_priv); > if (vfb->pin) > vfb->pin(vfb); > ld->fb = vfb; > @@ -190,6 +191,68 @@ static int vmw_ldu_add_active(struct vmw_private *vmw_priv, > return 0; > } > > +/** > + * vmw_ldu_crtc_mode_set_nofb - Enable svga > + * > + * @crtc: CRTC associated with the new screen > + * > + * For LDU, just enable the svga > + */ > +static void vmw_ldu_crtc_mode_set_nofb(struct drm_crtc *crtc) > +{ > +} > + > +/** > + * vmw_ldu_crtc_helper_prepare - Noop > + * > + * @crtc: CRTC associated with the new screen > + * > + * Prepares the CRTC for a mode set, but we don't need to do anything here. > + * > + */ > +static void vmw_ldu_crtc_helper_prepare(struct drm_crtc *crtc) > +{ > +} > + > +/** > + * vmw_ldu_crtc_helper_commit - Noop > + * > + * @crtc: CRTC associated with the new screen > + * > + * This is called after a mode set has been completed. Here's > + * usually a good place to call vmw_ldu_add_active/vmw_ldu_del_active > + * but since for LDU the display plane is closely tied to the > + * CRTC, it makes more sense to do those at plane update time. > + */ > +static void vmw_ldu_crtc_helper_commit(struct drm_crtc *crtc) > +{ > + struct vmw_private *dev_priv; > + struct vmw_legacy_display_unit *ldu; > + struct vmw_framebuffer *vfb; > + struct drm_framebuffer *fb; > + > + > + ldu = vmw_crtc_to_ldu(crtc); > + dev_priv = vmw_priv(crtc->dev); > + fb = crtc->primary->fb; > + > + vfb = (fb) ? vmw_framebuffer_to_vfb(fb) : NULL; > + > + if (vfb) > + vmw_ldu_add_active(dev_priv, ldu, vfb); > + else > + vmw_ldu_del_active(dev_priv, ldu); > +} > + > +/** > + * vmw_ldu_crtc_helper_disable - Turns off CRTC > + * > + * @crtc: CRTC to be turned off > + */ > +static void vmw_ldu_crtc_helper_disable(struct drm_crtc *crtc) > +{ > +} > + > static int vmw_ldu_crtc_set_config(struct drm_mode_set *set) > { > struct vmw_private *dev_priv; > @@ -346,6 +409,20 @@ static const struct drm_plane_funcs vmw_ldu_cursor_funcs = { > .atomic_destroy_state = vmw_du_plane_destroy_state, > }; > > +/* > + * Atomic Helpers > + */ > +static const struct drm_crtc_helper_funcs vmw_ldu_crtc_helper_funcs = { > + .prepare = vmw_ldu_crtc_helper_prepare, > + .commit = vmw_ldu_crtc_helper_commit, > + .disable = vmw_ldu_crtc_helper_disable, > + .mode_set = drm_helper_crtc_mode_set, Note this is only needed for the transitional helpers. You can/should remove the .mode_set hook once you're fully atomic. I didn't see that anywhere later on, might have missed it. -Daniel > + .mode_set_nofb = vmw_ldu_crtc_mode_set_nofb, > + .atomic_check = vmw_du_crtc_atomic_check, > + .atomic_begin = vmw_du_crtc_atomic_begin, > + .atomic_flush = vmw_du_crtc_atomic_flush, > +}; > + > > static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit) > { > @@ -445,6 +522,8 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit) > goto err_free_unregister; > } > > + drm_crtc_helper_add(crtc, &vmw_ldu_crtc_helper_funcs); > + > drm_mode_crtc_set_gamma_size(crtc, 256); > > drm_object_attach_property(&connector->base, > diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c > index 36d42f5..662024c 100644 > --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c > +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c > @@ -250,6 +250,109 @@ static int vmw_sou_backing_alloc(struct vmw_private *dev_priv, > return ret; > } > > +/** > + * vmw_sou_crtc_mode_set_nofb - Create new screen > + * > + * @crtc: CRTC associated with the new screen > + * > + * This function creates/destroys a screen. This function cannot fail, so if > + * somehow we run into a failure, just do the best we can to get out. > + */ > +static void vmw_sou_crtc_mode_set_nofb(struct drm_crtc *crtc) > +{ > + struct vmw_private *dev_priv; > + struct vmw_screen_object_unit *sou; > + struct vmw_framebuffer *vfb; > + struct drm_framebuffer *fb; > + struct drm_plane_state *ps; > + struct vmw_plane_state *vps; > + int ret; > + > + > + sou = vmw_crtc_to_sou(crtc); > + dev_priv = vmw_priv(crtc->dev); > + ps = crtc->primary->state; > + fb = ps->fb; > + vps = vmw_plane_state_to_vps(ps); > + > + vfb = (fb) ? vmw_framebuffer_to_vfb(fb) : NULL; > + > + if (sou->defined) { > + ret = vmw_sou_fifo_destroy(dev_priv, sou); > + if (ret) { > + DRM_ERROR("Failed to destroy Screen Object\n"); > + return; > + } > + } > + > + if (vfb) { > + sou->buffer = vps->dmabuf; > + sou->buffer_size = vps->dmabuf_size; > + > + ret = vmw_sou_fifo_create(dev_priv, sou, crtc->x, crtc->y, > + &crtc->mode); > + if (ret) > + DRM_ERROR("Failed to define Screen Object %dx%d\n", > + crtc->x, crtc->y); > + > + vmw_kms_add_active(dev_priv, &sou->base, vfb); > + } else { > + sou->buffer = NULL; > + sou->buffer_size = 0; > + > + vmw_kms_del_active(dev_priv, &sou->base); > + } > +} > + > +/** > + * vmw_sou_crtc_helper_prepare - Noop > + * > + * @crtc: CRTC associated with the new screen > + * > + * Prepares the CRTC for a mode set, but we don't need to do anything here. > + */ > +static void vmw_sou_crtc_helper_prepare(struct drm_crtc *crtc) > +{ > +} > + > +/** > + * vmw_sou_crtc_helper_commit - Noop > + * > + * @crtc: CRTC associated with the new screen > + * > + * This is called after a mode set has been completed. > + */ > +static void vmw_sou_crtc_helper_commit(struct drm_crtc *crtc) > +{ > +} > + > +/** > + * vmw_sou_crtc_helper_disable - Turns off CRTC > + * > + * @crtc: CRTC to be turned off > + */ > +static void vmw_sou_crtc_helper_disable(struct drm_crtc *crtc) > +{ > + struct vmw_private *dev_priv; > + struct vmw_screen_object_unit *sou; > + int ret; > + > + > + if (!crtc) { > + DRM_ERROR("CRTC is NULL\n"); > + return; > + } > + > + sou = vmw_crtc_to_sou(crtc); > + dev_priv = vmw_priv(crtc->dev); > + > + if (sou->defined) { > + ret = vmw_sou_fifo_destroy(dev_priv, sou); > + if (ret) > + DRM_ERROR("Failed to destroy Screen Object\n"); > + } > +} > + > static int vmw_sou_crtc_set_config(struct drm_mode_set *set) > { > struct vmw_private *dev_priv; > @@ -527,6 +630,20 @@ static const struct drm_plane_funcs vmw_sou_cursor_funcs = { > .atomic_destroy_state = vmw_du_plane_destroy_state, > }; > > +/* > + * Atomic Helpers > + */ > +static const struct drm_crtc_helper_funcs vmw_sou_crtc_helper_funcs = { > + .prepare = vmw_sou_crtc_helper_prepare, > + .commit = vmw_sou_crtc_helper_commit, > + .disable = vmw_sou_crtc_helper_disable, > + .mode_set = drm_helper_crtc_mode_set, > + .mode_set_nofb = vmw_sou_crtc_mode_set_nofb, > + .atomic_check = vmw_du_crtc_atomic_check, > + .atomic_begin = vmw_du_crtc_atomic_begin, > + .atomic_flush = vmw_du_crtc_atomic_flush, > +}; > + > > static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit) > { > @@ -626,6 +743,8 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit) > goto err_free_unregister; > } > > + drm_crtc_helper_add(crtc, &vmw_sou_crtc_helper_funcs); > + > drm_mode_crtc_set_gamma_size(crtc, 256); > > drm_object_attach_property(&connector->base, > diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c > index b1fae49..6e3cfad 100644 > --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c > +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c > @@ -500,6 +500,106 @@ static int vmw_stdu_bind_fb(struct vmw_private *dev_priv, > return ret; > } > > + > +/** > + * vmw_stdu_crtc_mode_set_nofb - Updates screen target size > + * > + * @crtc: CRTC associated with the screen target > + * > + * This function defines/destroys a screen target > + * > + */ > +static void vmw_stdu_crtc_mode_set_nofb(struct drm_crtc *crtc) > +{ > + struct vmw_private *dev_priv; > + struct vmw_screen_target_display_unit *stdu; > + int ret; > + > + > + stdu = vmw_crtc_to_stdu(crtc); > + dev_priv = vmw_priv(crtc->dev); > + > + if (stdu->defined) { > + ret = vmw_stdu_bind_st(dev_priv, stdu, NULL); > + if (ret) > + DRM_ERROR("Failed to blank CRTC\n"); > + > + (void) vmw_stdu_update_st(dev_priv, stdu); > + > + ret = vmw_stdu_destroy_st(dev_priv, stdu); > + if (ret) > + DRM_ERROR("Failed to destroy Screen Target\n"); > + > + stdu->content_fb_type = SAME_AS_DISPLAY; > + } > + > + if (!crtc->state->enable) > + return; > + > + vmw_svga_enable(dev_priv); > + ret = vmw_stdu_define_st(dev_priv, stdu, &crtc->mode, crtc->x, crtc->y); > + > + if (ret) > + DRM_ERROR("Failed to define Screen Target of size %dx%d\n", > + crtc->x, crtc->y); > +} > + > + > +static void vmw_stdu_crtc_helper_prepare(struct drm_crtc *crtc) > +{ > +} > + > + > +static void vmw_stdu_crtc_helper_commit(struct drm_crtc *crtc) > +{ > + struct vmw_private *dev_priv; > + struct vmw_screen_target_display_unit *stdu; > + struct vmw_framebuffer *vfb; > + struct drm_framebuffer *fb; > + > + > + stdu = vmw_crtc_to_stdu(crtc); > + dev_priv = vmw_priv(crtc->dev); > + fb = crtc->primary->fb; > + > + vfb = (fb) ? vmw_framebuffer_to_vfb(fb) : NULL; > + > + if (vfb) > + vmw_kms_add_active(dev_priv, &stdu->base, vfb); > + else > + vmw_kms_del_active(dev_priv, &stdu->base); > +} > + > +static void vmw_stdu_crtc_helper_disable(struct drm_crtc *crtc) > +{ > + struct vmw_private *dev_priv; > + struct vmw_screen_target_display_unit *stdu; > + int ret; > + > + > + if (!crtc) { > + DRM_ERROR("CRTC is NULL\n"); > + return; > + } > + > + stdu = vmw_crtc_to_stdu(crtc); > + dev_priv = vmw_priv(crtc->dev); > + > + if (stdu->defined) { > + ret = vmw_stdu_bind_st(dev_priv, stdu, NULL); > + if (ret) > + DRM_ERROR("Failed to blank CRTC\n"); > + > + (void) vmw_stdu_update_st(dev_priv, stdu); > + > + ret = vmw_stdu_destroy_st(dev_priv, stdu); > + if (ret) > + DRM_ERROR("Failed to destroy Screen Target\n"); > + > + stdu->content_fb_type = SAME_AS_DISPLAY; > + } > +} > + > /** > * vmw_stdu_crtc_set_config - Sets a mode > * > @@ -1113,6 +1213,21 @@ static const struct drm_plane_funcs vmw_stdu_cursor_funcs = { > }; > > > +/* > + * Atomic Helpers > + */ > +static const struct drm_crtc_helper_funcs vmw_stdu_crtc_helper_funcs = { > + .prepare = vmw_stdu_crtc_helper_prepare, > + .commit = vmw_stdu_crtc_helper_commit, > + .disable = vmw_stdu_crtc_helper_disable, > + .mode_set = drm_helper_crtc_mode_set, > + .mode_set_nofb = vmw_stdu_crtc_mode_set_nofb, > + .atomic_check = vmw_du_crtc_atomic_check, > + .atomic_begin = vmw_du_crtc_atomic_begin, > + .atomic_flush = vmw_du_crtc_atomic_flush, > +}; > + > + > /** > * vmw_stdu_init - Sets up a Screen Target Display Unit > * > @@ -1219,6 +1334,8 @@ static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit) > goto err_free_unregister; > } > > + drm_crtc_helper_add(crtc, &vmw_stdu_crtc_helper_funcs); > + > drm_mode_crtc_set_gamma_size(crtc, 256); > > drm_object_attach_property(&connector->base, > -- > 2.7.4 >
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index a8e0909..6f0f160 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -399,6 +399,54 @@ void vmw_du_primary_plane_destroy(struct drm_plane *plane) } +int vmw_du_crtc_atomic_check(struct drm_crtc *crtc, + struct drm_crtc_state *new_state) +{ + struct vmw_display_unit *du = vmw_crtc_to_du(new_state->crtc); + int connector_mask = 1 << drm_connector_index(&du->connector); + bool has_primary = new_state->plane_mask & + BIT(drm_plane_index(crtc->primary)); + + /* We always want to have an active plane with an active CRTC */ + if (has_primary != new_state->enable) + return -EINVAL; + + + if (new_state->connector_mask != connector_mask && + new_state->connector_mask != 0) { + DRM_ERROR("Invalid connectors configuration\n"); + return -EINVAL; + } + + return 0; +} + + +void vmw_du_crtc_atomic_begin(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) +{ +} + + +void vmw_du_crtc_atomic_flush(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) +{ + struct drm_pending_vblank_event *event = crtc->state->event; + + if (event) { + crtc->state->event = NULL; + + spin_lock_irq(&crtc->dev->event_lock); + if (drm_crtc_vblank_get(crtc) == 0) + drm_crtc_arm_vblank_event(crtc, event); + else + drm_crtc_send_vblank_event(crtc, event); + spin_unlock_irq(&crtc->dev->event_lock); + } + +} + + /** * vmw_du_crtc_duplicate_state - duplicate crtc state * @crtc: DRM crtc diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index cc50bf3..f711b5d 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -161,6 +161,7 @@ struct vmw_crtc_state { * @surf Display surface for STDU * @dmabuf display dmabuf for SOU * @content_fb_type Used by STDU. + * @dmabuf_size Size of the dmabuf, used by Screen Object Display Unit * @pinned pin count for STDU display surface */ struct vmw_plane_state { @@ -169,6 +170,7 @@ struct vmw_plane_state { struct vmw_dma_buffer *dmabuf; int content_fb_type; + unsigned long dmabuf_size; int pinned; }; @@ -342,10 +344,17 @@ int vmw_du_cursor_plane_update(struct drm_plane *plane, uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h); +/* Atomic Helpers */ void vmw_du_plane_reset(struct drm_plane *plane); struct drm_plane_state *vmw_du_plane_duplicate_state(struct drm_plane *plane); void vmw_du_plane_destroy_state(struct drm_plane *plane, struct drm_plane_state *state); +int vmw_du_crtc_atomic_check(struct drm_crtc *crtc, + struct drm_crtc_state *state); +void vmw_du_crtc_atomic_begin(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state); +void vmw_du_crtc_atomic_flush(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state); void vmw_du_crtc_reset(struct drm_crtc *crtc); struct drm_crtc_state *vmw_du_crtc_duplicate_state(struct drm_crtc *crtc); void vmw_du_crtc_destroy_state(struct drm_crtc *crtc, diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index 276c744..d547e80 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -167,6 +167,7 @@ static int vmw_ldu_add_active(struct vmw_private *vmw_priv, if (vfb != ld->fb) { if (ld->fb && ld->fb->unpin) ld->fb->unpin(ld->fb); + vmw_svga_enable(vmw_priv); if (vfb->pin) vfb->pin(vfb); ld->fb = vfb; @@ -190,6 +191,68 @@ static int vmw_ldu_add_active(struct vmw_private *vmw_priv, return 0; } +/** + * vmw_ldu_crtc_mode_set_nofb - Enable svga + * + * @crtc: CRTC associated with the new screen + * + * For LDU, just enable the svga + */ +static void vmw_ldu_crtc_mode_set_nofb(struct drm_crtc *crtc) +{ +} + +/** + * vmw_ldu_crtc_helper_prepare - Noop + * + * @crtc: CRTC associated with the new screen + * + * Prepares the CRTC for a mode set, but we don't need to do anything here. + * + */ +static void vmw_ldu_crtc_helper_prepare(struct drm_crtc *crtc) +{ +} + +/** + * vmw_ldu_crtc_helper_commit - Noop + * + * @crtc: CRTC associated with the new screen + * + * This is called after a mode set has been completed. Here's + * usually a good place to call vmw_ldu_add_active/vmw_ldu_del_active + * but since for LDU the display plane is closely tied to the + * CRTC, it makes more sense to do those at plane update time. + */ +static void vmw_ldu_crtc_helper_commit(struct drm_crtc *crtc) +{ + struct vmw_private *dev_priv; + struct vmw_legacy_display_unit *ldu; + struct vmw_framebuffer *vfb; + struct drm_framebuffer *fb; + + + ldu = vmw_crtc_to_ldu(crtc); + dev_priv = vmw_priv(crtc->dev); + fb = crtc->primary->fb; + + vfb = (fb) ? vmw_framebuffer_to_vfb(fb) : NULL; + + if (vfb) + vmw_ldu_add_active(dev_priv, ldu, vfb); + else + vmw_ldu_del_active(dev_priv, ldu); +} + +/** + * vmw_ldu_crtc_helper_disable - Turns off CRTC + * + * @crtc: CRTC to be turned off + */ +static void vmw_ldu_crtc_helper_disable(struct drm_crtc *crtc) +{ +} + static int vmw_ldu_crtc_set_config(struct drm_mode_set *set) { struct vmw_private *dev_priv; @@ -346,6 +409,20 @@ static const struct drm_plane_funcs vmw_ldu_cursor_funcs = { .atomic_destroy_state = vmw_du_plane_destroy_state, }; +/* + * Atomic Helpers + */ +static const struct drm_crtc_helper_funcs vmw_ldu_crtc_helper_funcs = { + .prepare = vmw_ldu_crtc_helper_prepare, + .commit = vmw_ldu_crtc_helper_commit, + .disable = vmw_ldu_crtc_helper_disable, + .mode_set = drm_helper_crtc_mode_set, + .mode_set_nofb = vmw_ldu_crtc_mode_set_nofb, + .atomic_check = vmw_du_crtc_atomic_check, + .atomic_begin = vmw_du_crtc_atomic_begin, + .atomic_flush = vmw_du_crtc_atomic_flush, +}; + static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit) { @@ -445,6 +522,8 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit) goto err_free_unregister; } + drm_crtc_helper_add(crtc, &vmw_ldu_crtc_helper_funcs); + drm_mode_crtc_set_gamma_size(crtc, 256); drm_object_attach_property(&connector->base, diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index 36d42f5..662024c 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c @@ -250,6 +250,109 @@ static int vmw_sou_backing_alloc(struct vmw_private *dev_priv, return ret; } +/** + * vmw_sou_crtc_mode_set_nofb - Create new screen + * + * @crtc: CRTC associated with the new screen + * + * This function creates/destroys a screen. This function cannot fail, so if + * somehow we run into a failure, just do the best we can to get out. + */ +static void vmw_sou_crtc_mode_set_nofb(struct drm_crtc *crtc) +{ + struct vmw_private *dev_priv; + struct vmw_screen_object_unit *sou; + struct vmw_framebuffer *vfb; + struct drm_framebuffer *fb; + struct drm_plane_state *ps; + struct vmw_plane_state *vps; + int ret; + + + sou = vmw_crtc_to_sou(crtc); + dev_priv = vmw_priv(crtc->dev); + ps = crtc->primary->state; + fb = ps->fb; + vps = vmw_plane_state_to_vps(ps); + + vfb = (fb) ? vmw_framebuffer_to_vfb(fb) : NULL; + + if (sou->defined) { + ret = vmw_sou_fifo_destroy(dev_priv, sou); + if (ret) { + DRM_ERROR("Failed to destroy Screen Object\n"); + return; + } + } + + if (vfb) { + sou->buffer = vps->dmabuf; + sou->buffer_size = vps->dmabuf_size; + + ret = vmw_sou_fifo_create(dev_priv, sou, crtc->x, crtc->y, + &crtc->mode); + if (ret) + DRM_ERROR("Failed to define Screen Object %dx%d\n", + crtc->x, crtc->y); + + vmw_kms_add_active(dev_priv, &sou->base, vfb); + } else { + sou->buffer = NULL; + sou->buffer_size = 0; + + vmw_kms_del_active(dev_priv, &sou->base); + } +} + +/** + * vmw_sou_crtc_helper_prepare - Noop + * + * @crtc: CRTC associated with the new screen + * + * Prepares the CRTC for a mode set, but we don't need to do anything here. + */ +static void vmw_sou_crtc_helper_prepare(struct drm_crtc *crtc) +{ +} + +/** + * vmw_sou_crtc_helper_commit - Noop + * + * @crtc: CRTC associated with the new screen + * + * This is called after a mode set has been completed. + */ +static void vmw_sou_crtc_helper_commit(struct drm_crtc *crtc) +{ +} + +/** + * vmw_sou_crtc_helper_disable - Turns off CRTC + * + * @crtc: CRTC to be turned off + */ +static void vmw_sou_crtc_helper_disable(struct drm_crtc *crtc) +{ + struct vmw_private *dev_priv; + struct vmw_screen_object_unit *sou; + int ret; + + + if (!crtc) { + DRM_ERROR("CRTC is NULL\n"); + return; + } + + sou = vmw_crtc_to_sou(crtc); + dev_priv = vmw_priv(crtc->dev); + + if (sou->defined) { + ret = vmw_sou_fifo_destroy(dev_priv, sou); + if (ret) + DRM_ERROR("Failed to destroy Screen Object\n"); + } +} + static int vmw_sou_crtc_set_config(struct drm_mode_set *set) { struct vmw_private *dev_priv; @@ -527,6 +630,20 @@ static const struct drm_plane_funcs vmw_sou_cursor_funcs = { .atomic_destroy_state = vmw_du_plane_destroy_state, }; +/* + * Atomic Helpers + */ +static const struct drm_crtc_helper_funcs vmw_sou_crtc_helper_funcs = { + .prepare = vmw_sou_crtc_helper_prepare, + .commit = vmw_sou_crtc_helper_commit, + .disable = vmw_sou_crtc_helper_disable, + .mode_set = drm_helper_crtc_mode_set, + .mode_set_nofb = vmw_sou_crtc_mode_set_nofb, + .atomic_check = vmw_du_crtc_atomic_check, + .atomic_begin = vmw_du_crtc_atomic_begin, + .atomic_flush = vmw_du_crtc_atomic_flush, +}; + static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit) { @@ -626,6 +743,8 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit) goto err_free_unregister; } + drm_crtc_helper_add(crtc, &vmw_sou_crtc_helper_funcs); + drm_mode_crtc_set_gamma_size(crtc, 256); drm_object_attach_property(&connector->base, diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index b1fae49..6e3cfad 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c @@ -500,6 +500,106 @@ static int vmw_stdu_bind_fb(struct vmw_private *dev_priv, return ret; } + +/** + * vmw_stdu_crtc_mode_set_nofb - Updates screen target size + * + * @crtc: CRTC associated with the screen target + * + * This function defines/destroys a screen target + * + */ +static void vmw_stdu_crtc_mode_set_nofb(struct drm_crtc *crtc) +{ + struct vmw_private *dev_priv; + struct vmw_screen_target_display_unit *stdu; + int ret; + + + stdu = vmw_crtc_to_stdu(crtc); + dev_priv = vmw_priv(crtc->dev); + + if (stdu->defined) { + ret = vmw_stdu_bind_st(dev_priv, stdu, NULL); + if (ret) + DRM_ERROR("Failed to blank CRTC\n"); + + (void) vmw_stdu_update_st(dev_priv, stdu); + + ret = vmw_stdu_destroy_st(dev_priv, stdu); + if (ret) + DRM_ERROR("Failed to destroy Screen Target\n"); + + stdu->content_fb_type = SAME_AS_DISPLAY; + } + + if (!crtc->state->enable) + return; + + vmw_svga_enable(dev_priv); + ret = vmw_stdu_define_st(dev_priv, stdu, &crtc->mode, crtc->x, crtc->y); + + if (ret) + DRM_ERROR("Failed to define Screen Target of size %dx%d\n", + crtc->x, crtc->y); +} + + +static void vmw_stdu_crtc_helper_prepare(struct drm_crtc *crtc) +{ +} + + +static void vmw_stdu_crtc_helper_commit(struct drm_crtc *crtc) +{ + struct vmw_private *dev_priv; + struct vmw_screen_target_display_unit *stdu; + struct vmw_framebuffer *vfb; + struct drm_framebuffer *fb; + + + stdu = vmw_crtc_to_stdu(crtc); + dev_priv = vmw_priv(crtc->dev); + fb = crtc->primary->fb; + + vfb = (fb) ? vmw_framebuffer_to_vfb(fb) : NULL; + + if (vfb) + vmw_kms_add_active(dev_priv, &stdu->base, vfb); + else + vmw_kms_del_active(dev_priv, &stdu->base); +} + +static void vmw_stdu_crtc_helper_disable(struct drm_crtc *crtc) +{ + struct vmw_private *dev_priv; + struct vmw_screen_target_display_unit *stdu; + int ret; + + + if (!crtc) { + DRM_ERROR("CRTC is NULL\n"); + return; + } + + stdu = vmw_crtc_to_stdu(crtc); + dev_priv = vmw_priv(crtc->dev); + + if (stdu->defined) { + ret = vmw_stdu_bind_st(dev_priv, stdu, NULL); + if (ret) + DRM_ERROR("Failed to blank CRTC\n"); + + (void) vmw_stdu_update_st(dev_priv, stdu); + + ret = vmw_stdu_destroy_st(dev_priv, stdu); + if (ret) + DRM_ERROR("Failed to destroy Screen Target\n"); + + stdu->content_fb_type = SAME_AS_DISPLAY; + } +} + /** * vmw_stdu_crtc_set_config - Sets a mode * @@ -1113,6 +1213,21 @@ static const struct drm_plane_funcs vmw_stdu_cursor_funcs = { }; +/* + * Atomic Helpers + */ +static const struct drm_crtc_helper_funcs vmw_stdu_crtc_helper_funcs = { + .prepare = vmw_stdu_crtc_helper_prepare, + .commit = vmw_stdu_crtc_helper_commit, + .disable = vmw_stdu_crtc_helper_disable, + .mode_set = drm_helper_crtc_mode_set, + .mode_set_nofb = vmw_stdu_crtc_mode_set_nofb, + .atomic_check = vmw_du_crtc_atomic_check, + .atomic_begin = vmw_du_crtc_atomic_begin, + .atomic_flush = vmw_du_crtc_atomic_flush, +}; + + /** * vmw_stdu_init - Sets up a Screen Target Display Unit * @@ -1219,6 +1334,8 @@ static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit) goto err_free_unregister; } + drm_crtc_helper_add(crtc, &vmw_stdu_crtc_helper_funcs); + drm_mode_crtc_set_gamma_size(crtc, 256); drm_object_attach_property(&connector->base,