From patchwork Mon Mar 27 22:00:58 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sinclair Yeh X-Patchwork-Id: 9647581 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id CB434602C8 for ; Mon, 27 Mar 2017 22:02:35 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id BD2C127CF3 for ; Mon, 27 Mar 2017 22:02:35 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id B1E342815E; Mon, 27 Mar 2017 22:02:35 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id CDEA427CF3 for ; Mon, 27 Mar 2017 22:02:34 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 413D96E368; Mon, 27 Mar 2017 22:02:34 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from EX13-EDG-OU-002.vmware.com (ex13-edg-ou-002.vmware.com [208.91.0.190]) by gabe.freedesktop.org (Postfix) with ESMTPS id 8E08A6E368 for ; Mon, 27 Mar 2017 22:02:33 +0000 (UTC) Received: from sc9-mailhost3.vmware.com (10.113.161.73) by EX13-EDG-OU-002.vmware.com (10.113.208.156) with Microsoft SMTP Server id 15.0.1156.6; Mon, 27 Mar 2017 15:01:47 -0700 Received: from vmware.com (unknown [10.16.254.220]) by sc9-mailhost3.vmware.com (Postfix) with SMTP id 3464E40427; Mon, 27 Mar 2017 15:02:25 -0700 (PDT) Received: by vmware.com (sSMTP sendmail emulation); Mon, 27 Mar 2017 15:02:22 -0700 From: Sinclair Yeh To: Subject: [PATCH 05/11] drm/vmwgfx: Add and connect CRTC helper functions Date: Mon, 27 Mar 2017 15:00:58 -0700 Message-ID: <1490652064-44817-6-git-send-email-syeh@vmware.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1490652064-44817-1-git-send-email-syeh@vmware.com> References: <1490652064-44817-1-git-send-email-syeh@vmware.com> MIME-Version: 1.0 Received-SPF: None (EX13-EDG-OU-002.vmware.com: syeh@vmware.com does not designate permitted sender hosts) Cc: daniel.vetter@ffwll.ch, thellstrom@vmware.com X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" X-Virus-Scanned: ClamAV using ClamSMTP 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 Signed-off-by: Thomas Hellstrom Reviewed-by: Thomas Hellstrom --- 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, + .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,