From patchwork Sat May 26 15:56:23 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Osipenko X-Patchwork-Id: 10429041 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 1130F60249 for ; Sat, 26 May 2018 15:58:07 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 024A029052 for ; Sat, 26 May 2018 15:58:07 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id EAC9429077; Sat, 26 May 2018 15:58:06 +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=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, FREEMAIL_FROM, MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 4EF6A2905D for ; Sat, 26 May 2018 15:58:06 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1032111AbeEZP5u (ORCPT ); Sat, 26 May 2018 11:57:50 -0400 Received: from mail-wm0-f67.google.com ([74.125.82.67]:37344 "EHLO mail-wm0-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1032050AbeEZP5r (ORCPT ); Sat, 26 May 2018 11:57:47 -0400 Received: by mail-wm0-f67.google.com with SMTP id l1-v6so21892401wmb.2; Sat, 26 May 2018 08:57:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=AfbmA4XXBSErzGN+oVE+PXRmsMaZB7ea0kS9W/9u5Ls=; b=jjRtZUa859xogtK1lh/MvdS2luAD+vXKy9Mq5hbOVKZVy/AIBzkvNXXAQwShtza5E8 7+o5OX4VuCAtTqvwrJm9XVNDM29VnkYwEPyrUr9JoqCW1sTEGij5Dp7qyqG5XCDVwyVP udR4pe5ore4n9E/8Fj4PrXTnNkphElOvcEDGG45Q6bgWQ7ySW0fapZRfaTcLtmBIlr0m vkIFRhKC+sCgdXq/Avw0Gw5eohqvHsuAPVSJBhA8JJRjfbynx8jccBr/e7h/PDToeJ5R R8eWVAuO4DaBY7HNs14ooHhv8WboiDNygr4bJtupauWzlrZ7D6XyeBQHqUT/TAmINXLA ZqYA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=AfbmA4XXBSErzGN+oVE+PXRmsMaZB7ea0kS9W/9u5Ls=; b=cRAt710Sbgtd4aonZ4BaM8LbhjDtizqZsENWvEYff3Py5Ar07jsw7kOYbZJt536UvF cQsJneAh/61BGMyhA6Gn0/i6gHcUa+2R3urqdo0jEDnehlTHiZn62f2k+t+ahA8TGzyX 4wBZMuogf4OWFYBU7tJBePpGUClLTSG6SvNCJKXjOkk26w1Fcsej7BWlghOjSSw0PbOi eSHlS0N+r0TUfrJ1zJAIzfRVVP4xSfQbjAQaRa2fRcUsvRsUrBfO8TEMViB2xS8nDw7k tWi1pYsvh4KLEgJaMZafRSbNjxP54wniq0dFYxQMMyGf9zcGAQLTQoiQbZWFthw7CdmW e9CQ== X-Gm-Message-State: ALKqPwe3PHmCV5cJ+teKbHzkt3nLQyU7tC8+Pp32exy3vctRqu/MOaUy C1iSEFpIoGVDTXKouxMcIa8= X-Google-Smtp-Source: AB8JxZpXUdmp1cU1tdzQLnFwhH3zAUYvEjWVGrKAX+rROqTKd+1ZyqLf0Te0C6hcK9NzW76Im0HSgQ== X-Received: by 2002:a2e:93cf:: with SMTP id p15-v6mr4366145ljh.30.1527350265498; Sat, 26 May 2018 08:57:45 -0700 (PDT) Received: from localhost.localdomain (109-252-91-41.nat.spd-mgts.ru. [109.252.91.41]) by smtp.gmail.com with ESMTPSA id k23-v6sm2571010ljh.27.2018.05.26.08.57.44 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sat, 26 May 2018 08:57:44 -0700 (PDT) From: Dmitry Osipenko To: Laurent Pinchart , =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= , Thierry Reding , Neil Armstrong , Maxime Ripard , dri-devel@lists.freedesktop.org Cc: linux-media@vger.kernel.org, linux-renesas-soc@vger.kernel.org, Alexandru Gheorghe , Russell King , Ben Skeggs , Sinclair Yeh , Thomas Hellstrom , Jani Nikula , Joonas Lahtinen , Rodrigo Vivi , linux-tegra@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [RFC PATCH v2 2/2] drm/tegra: plane: Implement generic colorkey property for older Tegra's Date: Sat, 26 May 2018 18:56:23 +0300 Message-Id: <20180526155623.12610-3-digetx@gmail.com> X-Mailer: git-send-email 2.17.0 In-Reply-To: <20180526155623.12610-1-digetx@gmail.com> References: <20180526155623.12610-1-digetx@gmail.com> Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Color keying allows to draw on top of overlapping planes, like for example on top of a video plane. Older Tegra's have a limited color keying capability, such that blending features are reduced when color keying is enabled. In particular dependent weighting isn't possible, meaning that cursors plane can't be displayed properly. In most cases it is more useful to display content on top of video overlay, so sacrificing mouse cursor in the area of three planes intersection with colorkey mismatch is a reasonable tradeoff. This patch implements the generic DRM colorkey property. For the starter a minimal color keying support is implemented, it is enough to provide userspace like Opentegra Xorg driver with ability to support color keying by the XVideo extension. Signed-off-by: Dmitry Osipenko --- drivers/gpu/drm/tegra/dc.c | 31 +++++++ drivers/gpu/drm/tegra/dc.h | 7 ++ drivers/gpu/drm/tegra/plane.c | 147 ++++++++++++++++++++++++++++++++++ drivers/gpu/drm/tegra/plane.h | 1 + 4 files changed, 186 insertions(+) diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index 31e12a9dfcb8..a5add64e40e2 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -172,6 +172,11 @@ static void tegra_plane_setup_blending_legacy(struct tegra_plane *plane) state = to_tegra_plane_state(plane->base.state); + if (state->ckey_enabled) { + background[0] |= BLEND_COLOR_KEY_0; + background[2] |= BLEND_COLOR_KEY_0; + } + if (state->opaque) { /* * Since custom fix-weight blending isn't utilized and weight @@ -776,6 +781,11 @@ static struct drm_plane *tegra_primary_plane_create(struct drm_device *drm, drm_plane_helper_add(&plane->base, &tegra_plane_helper_funcs); drm_plane_create_zpos_property(&plane->base, plane->index, 0, 255); + if (dc->soc->has_legacy_blending) + drm_plane_create_colorkey_properties(&plane->base, + BIT(DRM_PLANE_COLORKEY_MODE_DISABLED) | + BIT(DRM_PLANE_COLORKEY_MODE_DST)); + return &plane->base; } @@ -1053,6 +1063,11 @@ static struct drm_plane *tegra_dc_overlay_plane_create(struct drm_device *drm, drm_plane_helper_add(&plane->base, &tegra_plane_helper_funcs); drm_plane_create_zpos_property(&plane->base, plane->index, 0, 255); + if (dc->soc->has_legacy_blending) + drm_plane_create_colorkey_properties(&plane->base, + BIT(DRM_PLANE_COLORKEY_MODE_DISABLED) | + BIT(DRM_PLANE_COLORKEY_MODE_DST)); + return &plane->base; } @@ -1153,6 +1168,7 @@ tegra_crtc_atomic_duplicate_state(struct drm_crtc *crtc) { struct tegra_dc_state *state = to_dc_state(crtc->state); struct tegra_dc_state *copy; + unsigned int i; copy = kmalloc(sizeof(*copy), GFP_KERNEL); if (!copy) @@ -1164,6 +1180,9 @@ tegra_crtc_atomic_duplicate_state(struct drm_crtc *crtc) copy->div = state->div; copy->planes = state->planes; + for (i = 0; i < 2; i++) + copy->ckey[i] = state->ckey[i]; + return ©->base; } @@ -1893,6 +1912,18 @@ static void tegra_crtc_atomic_flush(struct drm_crtc *crtc, struct tegra_dc *dc = to_tegra_dc(crtc); u32 value; + if (dc->soc->has_legacy_blending) { + tegra_dc_writel(dc, + state->ckey[0].lower, DC_DISP_COLOR_KEY0_LOWER); + tegra_dc_writel(dc, + state->ckey[0].upper, DC_DISP_COLOR_KEY0_UPPER); + + tegra_dc_writel(dc, + state->ckey[1].lower, DC_DISP_COLOR_KEY1_LOWER); + tegra_dc_writel(dc, + state->ckey[1].upper, DC_DISP_COLOR_KEY1_UPPER); + } + value = state->planes << 8 | GENERAL_UPDATE; tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL); value = tegra_dc_readl(dc, DC_CMD_STATE_CONTROL); diff --git a/drivers/gpu/drm/tegra/dc.h b/drivers/gpu/drm/tegra/dc.h index e96f582ca692..8209cb7d598a 100644 --- a/drivers/gpu/drm/tegra/dc.h +++ b/drivers/gpu/drm/tegra/dc.h @@ -18,6 +18,11 @@ struct tegra_output; +struct tegra_dc_color_key_state { + u32 lower; + u32 upper; +}; + struct tegra_dc_state { struct drm_crtc_state base; @@ -26,6 +31,8 @@ struct tegra_dc_state { unsigned int div; u32 planes; + + struct tegra_dc_color_key_state ckey[2]; }; static inline struct tegra_dc_state *to_dc_state(struct drm_crtc_state *state) diff --git a/drivers/gpu/drm/tegra/plane.c b/drivers/gpu/drm/tegra/plane.c index 0406c2ef432c..ba08b66d2499 100644 --- a/drivers/gpu/drm/tegra/plane.c +++ b/drivers/gpu/drm/tegra/plane.c @@ -57,6 +57,7 @@ tegra_plane_atomic_duplicate_state(struct drm_plane *plane) copy->format = state->format; copy->swap = state->swap; copy->opaque = state->opaque; + copy->ckey_enabled = state->ckey_enabled; for (i = 0; i < 2; i++) copy->blending[i] = state->blending[i]; @@ -464,6 +465,148 @@ static int tegra_plane_setup_transparency(struct tegra_plane *tegra, return 0; } +static int tegra_plane_setup_colorkey(struct tegra_plane *tegra, + struct tegra_plane_state *tegra_state) +{ + struct drm_plane_state *state; + struct drm_plane_state *new_plane; + struct drm_plane_state *old_plane; + struct drm_crtc_state *crtc_state; + struct drm_crtc_state *new_crtc; + struct tegra_dc_state *dc_state; + struct drm_plane *plane; + unsigned int mode; + u32 min, max; + u32 format; + + /* at first check if plane has the colorkey property attached */ + if (!tegra->base.colorkey.mode_property) + return 0; + + format = tegra_state->base.colorkey.format; + mode = tegra_state->base.colorkey.mode; + min = tegra_state->base.colorkey.min; + max = tegra_state->base.colorkey.max; + + state = &tegra_state->base; + old_plane = drm_atomic_get_old_plane_state(state->state, &tegra->base); + + /* no need to proceed if color keying is (and was) disabled */ + if (mode == DRM_PLANE_COLORKEY_MODE_DISABLED && + (!old_plane || old_plane->colorkey.mode == mode)) + return 0; + + /* + * Currently color keying implemented only for the middle plane + * to simplify things, hence check the ordering. + */ + if (state->normalized_zpos != 1) { + if (mode == DRM_PLANE_COLORKEY_MODE_DISABLED) + goto update_planes; + + return -EINVAL; + } + + /* validate the color key mode */ + if (mode != DRM_PLANE_COLORKEY_MODE_DST) + return -EINVAL; + + /* validate the color key mask */ + if ((state->colorkey.mask & 0xFFFFFF) != 0xFFFFFF) + return -EINVAL; + + /* validate the replacement mask */ + if (state->colorkey.replacement_mask != 0) + return -EINVAL; + + /* validate the color key inversion mode */ + if (state->colorkey.inverted_match != true) + return -EINVAL; + + /* + * There is no need to proceed, adding CRTC and other planes to + * the atomic update, if color key value is unchanged. + */ + if (old_plane && + old_plane->colorkey.mode != DRM_PLANE_COLORKEY_MODE_DISABLED && + old_plane->colorkey.format == format && + old_plane->colorkey.min == min && + old_plane->colorkey.max == max) + return 0; + + /* validate pixel format and convert color key value if necessary */ + switch (format) { + case DRM_FORMAT_XBGR8888: +#define XBGR8888_to_XRGB8888(v) \ + ((((v) & 0xFF0000) >> 16) | ((v) & 0x00FF00) | (((v) & 0x0000FF) << 16)) + + min = XBGR8888_to_XRGB8888(min); + max = XBGR8888_to_XRGB8888(max); + break; + + case DRM_FORMAT_XRGB8888: + break; + + default: + return -EINVAL; + } + + /* + * Tegra's HW stores the color key values within CRTC, hence adjust + * planes CRTC atomic state. + */ + crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); + + new_crtc = drm_atomic_get_new_crtc_state(state->state, state->crtc); + if (IS_ERR(new_crtc)) + return PTR_ERR(new_crtc); + + dc_state = to_dc_state(new_crtc); + + /* update CRTC's color key state */ + dc_state->ckey[0].lower = min; + dc_state->ckey[0].upper = max; + +update_planes: + /* + * Currently the only supported color keying mode is + * "dst-match-src-replace", i.e. in our case the actual matching + * is performed by the underlying plane. Hence setup the color + * matching for that plane and update other planes by including + * them into the atomic update. + */ + drm_for_each_plane(plane, tegra->base.dev) { + struct tegra_plane *p = to_tegra_plane(plane); + + /* skip this plane and planes on different CRTCs */ + if (p == tegra || p->dc != tegra->dc) + continue; + + state = drm_atomic_get_plane_state(state->state, plane); + if (IS_ERR(state)) + return PTR_ERR(state); + + new_plane = drm_atomic_get_new_plane_state(state->state, plane); + tegra_state = to_tegra_plane_state(new_plane); + + /* skip planes hovering this plane */ + if (new_plane->normalized_zpos > 1) { + tegra_state->ckey_enabled = false; + continue; + } + + /* update planes color keying state */ + if (mode == DRM_PLANE_COLORKEY_MODE_DISABLED) + tegra_state->ckey_enabled = false; + else + tegra_state->ckey_enabled = true; + } + + return 0; +} + int tegra_plane_setup_legacy_state(struct tegra_plane *tegra, struct tegra_plane_state *state) { @@ -477,5 +620,9 @@ int tegra_plane_setup_legacy_state(struct tegra_plane *tegra, if (err < 0) return err; + err = tegra_plane_setup_colorkey(tegra, state); + if (err < 0) + return err; + return 0; } diff --git a/drivers/gpu/drm/tegra/plane.h b/drivers/gpu/drm/tegra/plane.h index 7360ddfafee8..617f57d98135 100644 --- a/drivers/gpu/drm/tegra/plane.h +++ b/drivers/gpu/drm/tegra/plane.h @@ -49,6 +49,7 @@ struct tegra_plane_state { /* used for legacy blending support only */ struct tegra_plane_legacy_blending_state blending[2]; bool opaque; + bool ckey_enabled; }; static inline struct tegra_plane_state *