From patchwork Tue May 24 10:10:45 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ying Liu X-Patchwork-Id: 9133385 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 7CB76607D5 for ; Tue, 24 May 2016 10:27:24 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 74EAD28258 for ; Tue, 24 May 2016 10:27:24 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 699A328285; Tue, 24 May 2016 10:27:24 +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=BAD_ENC_HEADER,BAYES_00, DKIM_ADSP_CUSTOM_MED,FREEMAIL_FROM,RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id EA1672824F for ; Tue, 24 May 2016 10:27:22 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 354BB6E705; Tue, 24 May 2016 10:27:21 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from na01-bl2-obe.outbound.protection.outlook.com (mail-bl2on0064.outbound.protection.outlook.com [65.55.169.64]) by gabe.freedesktop.org (Postfix) with ESMTPS id 89FF26E701 for ; Tue, 24 May 2016 10:27:16 +0000 (UTC) Received: from BY2PR03CA012.namprd03.prod.outlook.com (10.255.93.29) by DM2PR0301MB1198.namprd03.prod.outlook.com (10.160.217.148) with Microsoft SMTP Server (TLS) id 15.1.497.12; Tue, 24 May 2016 10:11:28 +0000 Received: from BY2FFO11FD032.protection.gbl (10.255.93.4) by BY2PR03CA012.outlook.office365.com (10.255.93.29) with Microsoft SMTP Server (TLS) id 15.1.492.11 via Frontend Transport; Tue, 24 May 2016 10:11:28 +0000 Authentication-Results: spf=softfail (sender IP is 192.88.168.50) smtp.mailfrom=gmail.com; arm.linux.org.uk; dkim=none (message not signed) header.d=none; arm.linux.org.uk; dmarc=fail action=none header.from=gmail.com; Received-SPF: SoftFail (protection.outlook.com: domain of transitioning gmail.com discourages use of 192.88.168.50 as permitted sender) Received: from tx30smr01.am.freescale.net (192.88.168.50) by BY2FFO11FD032.mail.protection.outlook.com (10.1.14.210) with Microsoft SMTP Server (TLS) id 15.1.497.8 via Frontend Transport; Tue, 24 May 2016 10:11:28 +0000 Received: from victor.ap.freescale.net (victor.ap.freescale.net [10.192.241.62]) by tx30smr01.am.freescale.net (8.14.3/8.14.0) with ESMTP id u4OABCM5024148; Tue, 24 May 2016 03:11:25 -0700 From: Liu Ying To: Subject: [PATCH 06/14] drm/imx: atomic phase 1: Use transitional atomic CRTC and plane helpers Date: Tue, 24 May 2016 18:10:45 +0800 Message-ID: <1464084653-16684-7-git-send-email-gnuiyl@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1464084653-16684-1-git-send-email-gnuiyl@gmail.com> References: <1464084653-16684-1-git-send-email-gnuiyl@gmail.com> X-EOPAttributedMessage: 0 X-Matching-Connectors: 131085582884735274; (91ab9b29-cfa4-454e-5278-08d120cd25b8); () X-Forefront-Antispam-Report: CIP:192.88.168.50; IPV:NLI; CTRY:US; EFV:NLI; SFV:NSPM; SFS:(10009020)(6009001)(2980300002)(189002)(199003)(9170700003)(2906002)(4326007)(87936001)(76482005)(5008740100001)(33646002)(19580405001)(19580395003)(6806005)(104016004)(2950100001)(11100500001)(36756003)(77096005)(189998001)(1220700001)(92566002)(586003)(82202001)(73972006)(50226002)(5890100001)(81442002)(8676002)(86362001)(110136002)(2351001)(73392002)(105596002)(5003940100001)(106466001)(229853001)(87572001)(48376002)(50466002)(81166006)(76176999)(83322999)(50986999)(8936002)(61266001)(47776003); DIR:OUT; SFP:1101; SCL:1; SRVR:DM2PR0301MB1198; H:tx30smr01.am.freescale.net; FPR:; SPF:SoftFail; MLV:sfv; MX:1; A:1; LANG:en; X-Microsoft-Exchange-Diagnostics: 1; BY2FFO11FD032; 1:3qmihWXLfulFBi0bilXfXJwjxMA7F1fYOOCfuppqrYNzAWyEnHWj0/Rr1/Mb0OGC/3BsGdWrIA3ulcD3MvK+0kzVXt9y96BPLT0IXCa17ZZXRNM6JGJji2DOI8juvBFf4yAU/WvpKz7AXW40OB/FffzV4LB+w1GprNwugJt7q1fWdmrgdHrtGw/m6syWAAgtkLh8c6YjbscHF1vxQjhYfX8kS2gE+qhSUq90rHtKiyBfLfVMUP78XgkL28KTWC3snFSAr91vha/0Ztw9sgXSS4cTSHBXBjSPP25PLq928J5bNvh1QKoD3UCqLFkvPJ7pVSvsUcCxseWr9podeMlABT5B7z0cGwqNRPX7pZIP1Dabyfei9GNhl8l8ZEffCPoqzseVy3484BL4I+riEPS3ZLFbIIy4L82QAy4FvYwQ7FbjoLmJbwD30Ktv96vuQNcl71w9L0Rh+BSx5saoJJPMB3+Dma4SafXApebN2ltIS5a26ZfAZPgj8ZABTxq4f1bZ1a8HIpEn56INSV0z8JMQf0iDNN2DKMHErfow84KU+5lPadzJKbkk4LyECMGqVn9x MIME-Version: 1.0 X-MS-Office365-Filtering-Correlation-Id: ba2d70ae-af11-4361-092a-08d383bbc57c X-Microsoft-Exchange-Diagnostics: 1; DM2PR0301MB1198; 2:iNeZ9DvIEGieGA2axMdqfVdADMpwsPC1KoXIxH+XC6SqqDro1jcoIl/3FywD9gy16mMWCVDH5HeYAfo+DTzSGKoYIg27GAgPumH9Nc7U9lfC8mDurjAOkrkOiKFk7OC5EtAimzJj9yK9M0gzm7fbnvZ402cSCCiG05+mfSYu6yRba38PmBHtsLofBdDN2ARv; 3:g0S746X/jBFRn4AvJt0EASEcQ9RNH3MSmxZC6CcKS+8KjLrMF0DFbcEjii5BIuhGSuCqv1SCAGI+9m4k1y0twjSjRbLeFDyUyVCgA/R0RYHV5yOk+5p31lmGY0Y5qNm5jyMfxFC1LmjFubgYJP4AjEEjyOeRYsFH8Vh24n+hcmztNJMWY3q2dEru9++0qZ2FOD//Omz1ILzJdytA5QKjHwbLFMVZGcofPD64dUEg10g= X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:DM2PR0301MB1198; X-Microsoft-Exchange-Diagnostics: 1; DM2PR0301MB1198; 25:AUN2OEtQe36RaYSTj8Q0FP3sRqpN8yzjcHCfPEo2KxpIWFEwbSazBo7FzzBjHLwj589HQIKJdhjIxz83hu+ZumDFKDE7PeX8LUBVNcnT2lTshRvuKfByd2Bf6bEchQdaC+XOY+QlUHzMGjxNSwoy9fkhlb6LkoAWpoy4ah8xXdo/8CSRb56hefX9fLrTGE3TLoL8cmabrIB9NVsmwvsRL+qhA6PSzn0jPv613Ww16dBBJ+iOZEyXHlbLpes/3JuYhyp/bLPNX4iLncSOFV6ztMx9F4DJDizk0lq4VwbzWXYc4++1hJEs7VmqJbPGudtKhZNHDvpGFom9E6/i9aIQwS9YZ04jA4S9dim5onSviD22ckP3z0PFYPujMv1XMlHSqrk4s++0xe+zGeJC1q3jjvqDQbzvCWwd2ESaDUVooN6sOvUmds1ewTVPv0RAFpz8NyG30N6PjpWT4pyvotwMzG+AM+BkyV5StX9rBH5Fn31Dq1gXXI9pHujBLbVZCb6MUqA3yPp8mQMzVNJ4ob5lZhltCPuDdDvaaQSa8Cr2ff+4w78O0+7hHeoqw6e1bXuMM3Hs+JZ0i27XoK6cLEJvee8Xu7wD5Zf3k0PxlKrZxlaa1I2h5AvkO7WvXNKZdx1XQ2bnDdmzu94YojjZJBY3Vck6rROQvZsIJ54GtJRQyajrYPWvsNOJP3kDdySEX/dBRPFpO1kxIk7danGXlH05xa7G7vDB+fw5ZQJG0roBvYUPISUSlLwAKD3CA+sIfp46vCxzmqq6dksm91iRyI4jvg== X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:; X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(601004)(2401047)(13023025)(13024025)(13018025)(13017025)(8121501046)(13015025)(5005006)(3002001)(10201501046)(6055026); SRVR:DM2PR0301MB1198; BCL:0; PCL:0; RULEID:(400006); SRVR:DM2PR0301MB1198; X-Microsoft-Exchange-Diagnostics: 1; DM2PR0301MB1198; 4:eBX4fUZ8rDmm8r2nfWXBfIpHp7ID84zwmU2O/I1Pg19PRY6Gm8YcTnj5u3On+bj4/9rP1xwGdAN6A58RNSXFmZg3BdrIKV6GFGIhCgSaAYGmTwaQlG1RxcxNiDc5bNAkJwLb4TcKKOTUNKZv6pxKFxxiFXuXTaJoHUGB5Q9+0I8tgw1+BrvwBhlDEH9m3LrvS3T5yojBqO8ISqj5vTFvIqLW1VZIkELZBz5c/giRLugKms9WPgcN2d3RjwxMHNOo+eCItcfskMWjVRXuyfd0qs0/mvZPj4doZiuiZqeUdExVrBkXX1sMYtaooMaBkafoRkPzxIPidO9JlQ9cf+d/AvmBjrZc6ZYGzGRjkiZIDHJj+/QZwF8eXHzl2ZJXD0D542jtGYML9eamCyAoAo9roHB8Dnd+GlNyarFZVFW3OIEU1ZDIqRlOFt7ufY8ke2kNmIA2rggdb6HMqzIH/xBdRLp2xnCqOAgJqgajaKXfu5U= X-Forefront-PRVS: 09525C61DB X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; DM2PR0301MB1198; 23:n5LZ2DGcGJV/kWTaVpDBDVzr3qd7bI8X1ZHkBYO?= =?us-ascii?Q?amZa3JnB4m1r67Laqulo99CDzC8P0/Z3lI+h0SllN9AoUUXaQoNjznbPmecz?= =?us-ascii?Q?SPVw2JN+NX4OQMBfw74C0esIZJKXd4TNjZ3RyLI1rxcY+Q9aTut1056Hw9tS?= =?us-ascii?Q?CtzMPR1/E65gDGCqrduqlL3bmlc/7yR1s9YxKFLF+0sRceLs5GmF5neZlfFw?= =?us-ascii?Q?t9Rah1CIJY/BvOr1pYhG+mgtdYJ7mAcAF5BjUcayFxt/xWAvjXAAsS19p+5t?= =?us-ascii?Q?er3z/Sd7P25sSzc+hUBrcDUrq6tlDAYBN3I5w2aKBtnyrUkQKz+Njj/RNTtO?= =?us-ascii?Q?09Xe3FbkbTOXKj18V44iTe4sURICDb0wNvYNOmv5psSAGIJ+xw992PivnPh0?= =?us-ascii?Q?PyTsrX4kKZdf0f3dhGsG6ZvtHXPVBZerLPIvMuZJKdqTEbfyfrj8UEtR+hhd?= =?us-ascii?Q?gT4V7+JQRif29IuR9qdMjTNLJphNEOrO4Giru8fSl+0x/tF/UYe4rV/YOTJF?= =?us-ascii?Q?w54BCPPgOSvyHHoSFVfrVkew5pnDc6VZb4inZj9NxB48kSb44YBCZMnX8sy9?= =?us-ascii?Q?nV7Wd3etaWWArRfzuWaFHfwfq85d1iw88CC+sNSmpmP5HEM7lx8+AaCuyNGg?= =?us-ascii?Q?Fk/kk/QifKUrnZTabjabFwDWEtz9gCTHk5AtW+vzTl1cOccyOHYnTSs3803t?= =?us-ascii?Q?8RJ+wM8HbLqsFgjTIW2ddVpRgR7b2B95sxBNfyoSS3y+mZShIGl9HCQPaqiw?= =?us-ascii?Q?wrujbh9vfIJJeYuG4w7w68Et2I6N8wt9BRH50jwI3M1HOdB36gF+p/aWCwq0?= =?us-ascii?Q?Pd9DkU9hooqqmTwjdD7Gzb6xJou6VvgGroXXXeXBg9NHWyM/8f0AGc0V4nv/?= =?us-ascii?Q?CT0aXuYbHCJFnjdQY5MiH06MuikAIVVsHe9dTDLgzc2nkvHUHnBAqFCddh8h?= =?us-ascii?Q?w2vDwzVOUtHlSlGF4eIKEKq4Lwzjr6HC9Zpjl2At626J6WtsEAXPE200U6JL?= =?us-ascii?Q?Cuir0+awneudH/q1YbzJOTdSmMMtLCq2K50dwR+8ZWbV+VGRqcJ/e3e/iGSO?= =?us-ascii?Q?233gTY4R6CmGby1/Zu5YfivDVDxvlRtJPq097OgKps3zrWj3CpfhUP5I/U3u?= =?us-ascii?Q?Shig2f/fA0mkYG31FtIIJMvNbQTyilIYLSyPxvOZAgBRrr4lrLkbg3Nvb/KP?= =?us-ascii?Q?9jHY3FKy0zZxvQCSnxgstOzw81uE5GFh+/ENQ?= X-Microsoft-Exchange-Diagnostics: 1; DM2PR0301MB1198; 5:CnCCHNLcVg3eHf28W/FSsFkr7NCJTw/vtEoHcAqv0RMjhX9Je7I9ugZIWWI8JUas+UY4saU9eV1727A70cG/SABP/LfWhAkSuHaFwzcN98H60f4WvVPbIdDMb8VCGJZ1PFYHsTbZhZT0GG+AKz97TxAVDK1dY4GN1Tax3dkPbMs=; 24:PpoZ27dVgWxHzyveLnBA+FKA6fCrXoiBcjG1t/mV8F7hdQSORee7wJq9ge0Um7BPFqBrlwA71oRz/EbIkRPnYmq9w2fY9HO0Xy3vKWUZRu4=; 7:8BOKSLl/S9nAYeBAziViS8JGuYrzBDzBiJ4ed4j1Skb+DkCZMKA7lyH2kpnCdQV5rI01tf59xGNCTDw3gDpYeUr54qOSHuVfvdX6gKKAhNbI1iPJkoaBpqDs6UQqnAS1QcSZa8Pf0KQaSDeiBzBl1B7bM3JmZp/J/eFnqZyUBY16QIlwuhREp1oYo1nAhEQY SpamDiagnosticOutput: 1:23 SpamDiagnosticMetadata: NSPM X-MS-Exchange-CrossTenant-OriginalArrivalTime: 24 May 2016 10:11:28.2707 (UTC) X-MS-Exchange-CrossTenant-Id: 5afe0b00-7697-4969-b663-5eab37d5f47e X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=5afe0b00-7697-4969-b663-5eab37d5f47e; Ip=[192.88.168.50]; Helo=[tx30smr01.am.freescale.net] X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: DM2PR0301MB1198 Cc: Russell King 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 Use the drm_plane_helper_update/disable() and drm_helper_crtc_mode_set() transistional atomic helpers. The crtc->mode_set_nofb callback is added so that the primary plane is no longer tied to the CRTC. Check/update logics are separated to make sure crtc->mode_set_nofb and plane->atomic_update are always successful. Also, some necessary logics are tweaked for a smooth transition. Signed-off-by: Liu Ying --- drivers/gpu/drm/imx/ipuv3-crtc.c | 173 +++++++------ drivers/gpu/drm/imx/ipuv3-plane.c | 516 +++++++++++++++++++++++--------------- drivers/gpu/drm/imx/ipuv3-plane.h | 14 +- drivers/gpu/ipu-v3/ipu-dc.c | 5 +- drivers/gpu/ipu-v3/ipu-di.c | 3 - 5 files changed, 400 insertions(+), 311 deletions(-) diff --git a/drivers/gpu/drm/imx/ipuv3-crtc.c b/drivers/gpu/drm/imx/ipuv3-crtc.c index b2c30b8..11fad87 100644 --- a/drivers/gpu/drm/imx/ipuv3-crtc.c +++ b/drivers/gpu/drm/imx/ipuv3-crtc.c @@ -72,7 +72,7 @@ struct ipu_crtc { #define to_ipu_crtc(x) container_of(x, struct ipu_crtc, base) -static void ipu_fb_enable(struct ipu_crtc *ipu_crtc) +static void ipu_crtc_enable(struct ipu_crtc *ipu_crtc) { struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent); @@ -80,16 +80,19 @@ static void ipu_fb_enable(struct ipu_crtc *ipu_crtc) return; ipu_dc_enable(ipu); - ipu_plane_enable(ipu_crtc->plane[0]); /* Start DC channel and DI after IDMAC */ ipu_dc_enable_channel(ipu_crtc->dc); ipu_di_enable(ipu_crtc->di); - drm_crtc_vblank_on(&ipu_crtc->base); - ipu_crtc->enabled = 1; + + /* + * In order not to be warned on enabling vblank failure, + * we should call drm_crtc_vblank_on() after ->enabled is set to 1. + */ + drm_crtc_vblank_on(&ipu_crtc->base); } -static void ipu_fb_disable(struct ipu_crtc *ipu_crtc) +static void ipu_crtc_disable(struct ipu_crtc *ipu_crtc) { struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent); @@ -99,11 +102,10 @@ static void ipu_fb_disable(struct ipu_crtc *ipu_crtc) /* Stop DC channel and DI before IDMAC */ ipu_dc_disable_channel(ipu_crtc->dc); ipu_di_disable(ipu_crtc->di); - ipu_plane_disable(ipu_crtc->plane[0]); ipu_dc_disable(ipu); - drm_crtc_vblank_off(&ipu_crtc->base); - ipu_crtc->enabled = 0; + + drm_crtc_vblank_off(&ipu_crtc->base); } static void ipu_crtc_dpms(struct drm_crtc *crtc, int mode) @@ -114,12 +116,12 @@ static void ipu_crtc_dpms(struct drm_crtc *crtc, int mode) switch (mode) { case DRM_MODE_DPMS_ON: - ipu_fb_enable(ipu_crtc); + ipu_crtc_enable(ipu_crtc); break; case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_OFF: - ipu_fb_disable(ipu_crtc); + ipu_crtc_disable(ipu_crtc); break; } } @@ -233,77 +235,6 @@ static const struct drm_crtc_funcs ipu_crtc_funcs = { .page_flip = ipu_page_flip, }; -static int ipu_crtc_mode_set(struct drm_crtc *crtc, - struct drm_display_mode *orig_mode, - struct drm_display_mode *mode, - int x, int y, - struct drm_framebuffer *old_fb) -{ - struct drm_device *dev = crtc->dev; - struct drm_encoder *encoder; - struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); - struct ipu_di_signal_cfg sig_cfg = {}; - unsigned long encoder_types = 0; - int ret; - - dev_dbg(ipu_crtc->dev, "%s: mode->hdisplay: %d\n", __func__, - mode->hdisplay); - dev_dbg(ipu_crtc->dev, "%s: mode->vdisplay: %d\n", __func__, - mode->vdisplay); - - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) - if (encoder->crtc == crtc) - encoder_types |= BIT(encoder->encoder_type); - - dev_dbg(ipu_crtc->dev, "%s: attached to encoder types 0x%lx\n", - __func__, encoder_types); - - /* - * If we have DAC or LDB, then we need the IPU DI clock to be - * the same as the LDB DI clock. For TVDAC, derive the IPU DI - * clock from 27 MHz TVE_DI clock, but allow to divide it. - */ - if (encoder_types & (BIT(DRM_MODE_ENCODER_DAC) | - BIT(DRM_MODE_ENCODER_LVDS))) - sig_cfg.clkflags = IPU_DI_CLKMODE_SYNC | IPU_DI_CLKMODE_EXT; - else if (encoder_types & BIT(DRM_MODE_ENCODER_TVDAC)) - sig_cfg.clkflags = IPU_DI_CLKMODE_EXT; - else - sig_cfg.clkflags = 0; - - sig_cfg.enable_pol = 1; - sig_cfg.clk_pol = 0; - sig_cfg.bus_format = ipu_crtc->bus_format; - sig_cfg.v_to_h_sync = 0; - sig_cfg.hsync_pin = ipu_crtc->di_hsync_pin; - sig_cfg.vsync_pin = ipu_crtc->di_vsync_pin; - - drm_display_mode_to_videomode(mode, &sig_cfg.mode); - - ret = ipu_dc_init_sync(ipu_crtc->dc, ipu_crtc->di, - mode->flags & DRM_MODE_FLAG_INTERLACE, - ipu_crtc->bus_format, mode->hdisplay); - if (ret) { - dev_err(ipu_crtc->dev, - "initializing display controller failed with %d\n", - ret); - return ret; - } - - ret = ipu_di_init_sync_panel(ipu_crtc->di, &sig_cfg); - if (ret) { - dev_err(ipu_crtc->dev, - "initializing panel failed with %d\n", ret); - return ret; - } - - return ipu_plane_mode_set(ipu_crtc->plane[0], crtc, mode, - crtc->primary->fb, - 0, 0, mode->hdisplay, mode->vdisplay, - x, y, mode->hdisplay, mode->vdisplay, - mode->flags & DRM_MODE_FLAG_INTERLACE); -} - static void ipu_crtc_handle_pageflip(struct ipu_crtc *ipu_crtc) { unsigned long flags; @@ -327,8 +258,7 @@ static irqreturn_t ipu_irq_handler(int irq, void *dev_id) if (ipu_crtc->flip_state == IPU_FLIP_SUBMITTED) { struct ipu_plane *plane = ipu_crtc->plane[0]; - ipu_plane_set_base(plane, ipu_crtc->base.primary->fb, - plane->x, plane->y); + ipu_plane_set_base(plane, ipu_crtc->base.primary->fb); ipu_crtc_handle_pageflip(ipu_crtc); queue_work(ipu_crtc->flip_queue, &ipu_crtc->flip_work->unref_work); @@ -352,6 +282,9 @@ static bool ipu_crtc_mode_fixup(struct drm_crtc *crtc, if (ret) return false; + if ((vm.vsync_len == 0) || (vm.hsync_len == 0)) + return false; + drm_display_mode_from_videomode(&vm, adjusted_mode); return true; @@ -361,28 +294,93 @@ static void ipu_crtc_prepare(struct drm_crtc *crtc) { struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); - ipu_fb_disable(ipu_crtc); + ipu_crtc_disable(ipu_crtc); } static void ipu_crtc_commit(struct drm_crtc *crtc) { struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); - ipu_fb_enable(ipu_crtc); + ipu_crtc_enable(ipu_crtc); +} + +static int ipu_crtc_atomic_check(struct drm_crtc *crtc, + struct drm_crtc_state *state) +{ + return 0; +} + +static void ipu_crtc_mode_set_nofb(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_encoder *encoder; + struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); + struct drm_display_mode *mode = &crtc->state->adjusted_mode; + struct ipu_di_signal_cfg sig_cfg = {}; + unsigned long encoder_types = 0; + + dev_dbg(ipu_crtc->dev, "%s: mode->hdisplay: %d\n", __func__, + mode->hdisplay); + dev_dbg(ipu_crtc->dev, "%s: mode->vdisplay: %d\n", __func__, + mode->vdisplay); + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) + if (encoder->crtc == crtc) + encoder_types |= BIT(encoder->encoder_type); + + dev_dbg(ipu_crtc->dev, "%s: attached to encoder types 0x%lx\n", + __func__, encoder_types); + + /* + * If we have DAC or LDB, then we need the IPU DI clock to be + * the same as the LDB DI clock. For TVDAC, derive the IPU DI + * clock from 27 MHz TVE_DI clock, but allow to divide it. + */ + if (encoder_types & (BIT(DRM_MODE_ENCODER_DAC) | + BIT(DRM_MODE_ENCODER_LVDS))) + sig_cfg.clkflags = IPU_DI_CLKMODE_SYNC | IPU_DI_CLKMODE_EXT; + else if (encoder_types & BIT(DRM_MODE_ENCODER_TVDAC)) + sig_cfg.clkflags = IPU_DI_CLKMODE_EXT; + else + sig_cfg.clkflags = 0; + + sig_cfg.enable_pol = 1; + sig_cfg.clk_pol = 0; + sig_cfg.bus_format = ipu_crtc->bus_format; + sig_cfg.v_to_h_sync = 0; + sig_cfg.hsync_pin = ipu_crtc->di_hsync_pin; + sig_cfg.vsync_pin = ipu_crtc->di_vsync_pin; + + drm_display_mode_to_videomode(mode, &sig_cfg.mode); + + ipu_dc_init_sync(ipu_crtc->dc, ipu_crtc->di, + mode->flags & DRM_MODE_FLAG_INTERLACE, + ipu_crtc->bus_format, mode->hdisplay); + ipu_di_init_sync_panel(ipu_crtc->di, &sig_cfg); } static const struct drm_crtc_helper_funcs ipu_helper_funcs = { .dpms = ipu_crtc_dpms, .mode_fixup = ipu_crtc_mode_fixup, - .mode_set = ipu_crtc_mode_set, + .mode_set = drm_helper_crtc_mode_set, + .mode_set_nofb = ipu_crtc_mode_set_nofb, .prepare = ipu_crtc_prepare, .commit = ipu_crtc_commit, + .atomic_check = ipu_crtc_atomic_check, }; static int ipu_enable_vblank(struct drm_crtc *crtc) { struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); + /* + * ->commit is done after ->mode_set in drm_crtc_helper_set_mode(), + * so waiting for vblank in drm_plane_helper_commit() will timeout. + * Check the state here to avoid the waiting. + */ + if (!ipu_crtc->enabled) + return -EINVAL; + enable_irq(ipu_crtc->irq); return 0; @@ -506,6 +504,8 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc, /* Only enable IRQ when we actually need it to trigger work. */ disable_irq(ipu_crtc->irq); + ipu_plane_put_resources(ipu_crtc->plane[0]); + ipu_crtc->flip_queue = create_singlethread_workqueue("ipu-crtc-flip"); return 0; @@ -550,7 +550,6 @@ static void ipu_drm_unbind(struct device *dev, struct device *master, imx_drm_remove_crtc(ipu_crtc->imx_crtc); destroy_workqueue(ipu_crtc->flip_queue); - ipu_plane_put_resources(ipu_crtc->plane[0]); ipu_put_resources(ipu_crtc); } diff --git a/drivers/gpu/drm/imx/ipuv3-plane.c b/drivers/gpu/drm/imx/ipuv3-plane.c index 30cedbb..4511b84 100644 --- a/drivers/gpu/drm/imx/ipuv3-plane.c +++ b/drivers/gpu/drm/imx/ipuv3-plane.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "video/imx-ipu-v3.h" #include "ipuv3-plane.h" @@ -51,12 +52,15 @@ int ipu_plane_irq(struct ipu_plane *ipu_plane) IPU_IRQ_EOF); } -int ipu_plane_set_base(struct ipu_plane *ipu_plane, struct drm_framebuffer *fb, - int x, int y) +int ipu_plane_set_base(struct ipu_plane *ipu_plane, struct drm_framebuffer *fb) { - struct drm_gem_cma_object *cma_obj[3]; - unsigned long eba, ubo, vbo; + struct drm_gem_cma_object *cma_obj[3], *old_cma_obj[3]; + struct drm_plane_state *state = ipu_plane->base.state; + struct drm_framebuffer *old_fb = state->fb; + unsigned long eba, ubo, vbo, old_eba, old_ubo, old_vbo; int active, i; + int x = state->src_x >> 16; + int y = state->src_y >> 16; for (i = 0; i < drm_format_num_planes(fb->pixel_format); i++) { cma_obj[i] = drm_fb_cma_get_gem_obj(fb, i); @@ -66,6 +70,14 @@ int ipu_plane_set_base(struct ipu_plane *ipu_plane, struct drm_framebuffer *fb, } } + for (i = 0; i < drm_format_num_planes(old_fb->pixel_format); i++) { + old_cma_obj[i] = drm_fb_cma_get_gem_obj(old_fb, i); + if (!old_cma_obj[i]) { + DRM_DEBUG_KMS("plane %d entry is null.\n", i); + return -EFAULT; + } + } + eba = cma_obj[0]->paddr + fb->offsets[0] + fb->pitches[0] * y + (fb->bits_per_pixel >> 3) * x; @@ -79,13 +91,11 @@ int ipu_plane_set_base(struct ipu_plane *ipu_plane, struct drm_framebuffer *fb, return -EINVAL; } - if (ipu_plane->enabled && fb->pitches[0] != ipu_plane->stride[0]) { + if (fb->pitches[0] != old_fb->pitches[0]) { DRM_DEBUG_KMS("pitches must not change while plane is enabled.\n"); return -EINVAL; } - ipu_plane->stride[0] = fb->pitches[0]; - switch (fb->pixel_format) { case DRM_FORMAT_YUV420: case DRM_FORMAT_YVU420: @@ -102,6 +112,14 @@ int ipu_plane_set_base(struct ipu_plane *ipu_plane, struct drm_framebuffer *fb, vbo = cma_obj[2]->paddr + fb->offsets[2] + fb->pitches[2] * y / 2 + x / 2 - eba; + old_eba = old_cma_obj[0]->paddr + old_fb->offsets[0] + + old_fb->pitches[0] * y + + (old_fb->bits_per_pixel >> 3) * x; + old_ubo = old_cma_obj[1]->paddr + old_fb->offsets[1] + + old_fb->pitches[1] * y / 2 + x / 2 - old_eba; + old_vbo = old_cma_obj[2]->paddr + old_fb->offsets[2] + + old_fb->pitches[2] * y / 2 + x / 2 - old_eba; + if ((ubo & 0x7) || (vbo & 0x7)) { DRM_DEBUG_KMS("U/V buffer offsets must be a multiple of 8.\n"); return -EINVAL; @@ -112,8 +130,7 @@ int ipu_plane_set_base(struct ipu_plane *ipu_plane, struct drm_framebuffer *fb, return -EINVAL; } - if (ipu_plane->enabled && ((ipu_plane->u_offset != ubo) || - (ipu_plane->v_offset != vbo))) { + if (old_ubo != ubo || old_vbo != vbo) { DRM_DEBUG_KMS("U/V buffer offsets must not change while plane is enabled.\n"); return -EINVAL; } @@ -128,16 +145,11 @@ int ipu_plane_set_base(struct ipu_plane *ipu_plane, struct drm_framebuffer *fb, return -EINVAL; } - if (ipu_plane->enabled && - (ipu_plane->stride[1] != fb->pitches[1])) { + if (old_fb->pitches[1] != fb->pitches[1]) { DRM_DEBUG_KMS("U/V pitches must not change while plane is enabled.\n"); return -EINVAL; } - ipu_plane->u_offset = ubo; - ipu_plane->v_offset = vbo; - ipu_plane->stride[1] = fb->pitches[1]; - dev_dbg(ipu_plane->base.dev->dev, "phys = %pad %pad %pad, x = %d, y = %d", &cma_obj[0]->paddr, &cma_obj[1]->paddr, @@ -149,165 +161,111 @@ int ipu_plane_set_base(struct ipu_plane *ipu_plane, struct drm_framebuffer *fb, break; } - if (ipu_plane->enabled) { - active = ipu_idmac_get_current_buffer(ipu_plane->ipu_ch); - ipu_cpmem_set_buffer(ipu_plane->ipu_ch, !active, eba); - ipu_idmac_select_buffer(ipu_plane->ipu_ch, !active); - } else { - ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 0, eba); - ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 1, eba); - } - - /* cache offsets for subsequent pageflips */ - ipu_plane->x = x; - ipu_plane->y = y; + active = ipu_idmac_get_current_buffer(ipu_plane->ipu_ch); + ipu_cpmem_set_buffer(ipu_plane->ipu_ch, !active, eba); + ipu_idmac_select_buffer(ipu_plane->ipu_ch, !active); return 0; } -int ipu_plane_mode_set(struct ipu_plane *ipu_plane, struct drm_crtc *crtc, - struct drm_display_mode *mode, - struct drm_framebuffer *fb, int crtc_x, int crtc_y, - unsigned int crtc_w, unsigned int crtc_h, - uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h, bool interlaced) +static inline unsigned long +drm_plane_state_to_eba(struct drm_plane_state *state) { - struct drm_plane plane = ipu_plane->base; - struct device *dev = plane.dev->dev; - int ret; + struct drm_framebuffer *fb = state->fb; + struct drm_gem_cma_object *cma_obj; - /* no scaling */ - if (src_w != crtc_w || src_h != crtc_h) - return -EINVAL; + cma_obj = drm_fb_cma_get_gem_obj(fb, 0); + BUG_ON(!cma_obj); - if (plane.type == DRM_PLANE_TYPE_PRIMARY) { - /* full plane doesn't support partial off screen */ - if (crtc_x || crtc_y || crtc_w != mode->hdisplay || - crtc_h != mode->vdisplay) - return -EINVAL; + return cma_obj->paddr + fb->offsets[0] + + fb->pitches[0] * (state->src_y >> 16) + + (fb->bits_per_pixel >> 3) * (state->src_x >> 16); +} - /* full plane minimum width is 13 pixels */ - if (crtc_w < 13) - return -EINVAL; - } else if (plane.type == DRM_PLANE_TYPE_OVERLAY) { - /* clip to crtc bounds */ - if (crtc_x < 0) { - if (-crtc_x > crtc_w) - return -EINVAL; - src_x += -crtc_x; - src_w -= -crtc_x; - crtc_w -= -crtc_x; - crtc_x = 0; - } - if (crtc_y < 0) { - if (-crtc_y > crtc_h) - return -EINVAL; - src_y += -crtc_y; - src_h -= -crtc_y; - crtc_h -= -crtc_y; - crtc_y = 0; - } - if (crtc_x + crtc_w > mode->hdisplay) { - if (crtc_x > mode->hdisplay) - return -EINVAL; - crtc_w = mode->hdisplay - crtc_x; - src_w = crtc_w; - } - if (crtc_y + crtc_h > mode->vdisplay) { - if (crtc_y > mode->vdisplay) - return -EINVAL; - crtc_h = mode->vdisplay - crtc_y; - src_h = crtc_h; - } - } else - return -EINVAL; - if (crtc_h < 2) - return -EINVAL; +static inline unsigned long +drm_plane_state_to_ubo(struct drm_plane_state *state) +{ + struct drm_framebuffer *fb = state->fb; + struct drm_gem_cma_object *cma_obj; + unsigned long eba = drm_plane_state_to_eba(state); - /* - * since we cannot touch active IDMAC channels, we do not support - * resizing the enabled plane or changing its format - */ - if (ipu_plane->enabled) { - if (src_w != ipu_plane->w || src_h != ipu_plane->h || - fb->pixel_format != plane.fb->pixel_format) - return -EINVAL; + cma_obj = drm_fb_cma_get_gem_obj(fb, 1); + BUG_ON(!cma_obj); - return ipu_plane_set_base(ipu_plane, fb, src_x, src_y); - } + return cma_obj->paddr + fb->offsets[1] + + fb->pitches[1] * (state->src_y >> 16) / 2 + + (state->src_x >> 16) / 2 - eba; +} - switch (ipu_plane->dp_flow) { - case IPU_DP_FLOW_SYNC_BG: - ret = ipu_dp_setup_channel(ipu_plane->dp, - IPUV3_COLORSPACE_RGB, - IPUV3_COLORSPACE_RGB); - if (ret) { - dev_err(dev, - "initializing display processor failed with %d\n", - ret); - return ret; - } - ipu_dp_set_global_alpha(ipu_plane->dp, true, 0, true); - break; - case IPU_DP_FLOW_SYNC_FG: - ipu_dp_setup_channel(ipu_plane->dp, - ipu_drm_fourcc_to_colorspace(fb->pixel_format), - IPUV3_COLORSPACE_UNKNOWN); - ipu_dp_set_window_pos(ipu_plane->dp, crtc_x, crtc_y); - /* Enable local alpha on partial plane */ - switch (fb->pixel_format) { - case DRM_FORMAT_ARGB1555: - case DRM_FORMAT_ABGR1555: - case DRM_FORMAT_RGBA5551: - case DRM_FORMAT_BGRA5551: - case DRM_FORMAT_ARGB4444: - case DRM_FORMAT_ARGB8888: - case DRM_FORMAT_ABGR8888: - case DRM_FORMAT_RGBA8888: - case DRM_FORMAT_BGRA8888: - ipu_dp_set_global_alpha(ipu_plane->dp, false, 0, false); - break; - default: +static inline unsigned long +drm_plane_state_to_vbo(struct drm_plane_state *state) +{ + struct drm_framebuffer *fb = state->fb; + struct drm_gem_cma_object *cma_obj; + unsigned long eba = drm_plane_state_to_eba(state); + + cma_obj = drm_fb_cma_get_gem_obj(fb, 2); + BUG_ON(!cma_obj); + + return cma_obj->paddr + fb->offsets[2] + + fb->pitches[2] * (state->src_y >> 16) / 2 + + (state->src_x >> 16) / 2 - eba; +} + +void ipu_plane_atomic_set_base(struct ipu_plane *ipu_plane, + struct drm_plane_state *old_state) +{ + struct drm_plane *plane = &ipu_plane->base; + struct drm_plane_state *state = plane->state; + struct drm_framebuffer *fb = state->fb; + unsigned long eba, ubo, vbo; + int active; + + eba = drm_plane_state_to_eba(state); + + switch (fb->pixel_format) { + case DRM_FORMAT_YUV420: + case DRM_FORMAT_YVU420: + if (old_state->fb) break; - } - } - ipu_dmfc_config_wait4eot(ipu_plane->dmfc, crtc_w); + /* + * Multiplanar formats have to meet the following restrictions: + * - The (up to) three plane addresses are EBA, EBA+UBO, EBA+VBO + * - EBA, UBO and VBO are a multiple of 8 + * - UBO and VBO are unsigned and not larger than 0xfffff8 + * - Only EBA may be changed while scanout is active + * - The strides of U and V planes must be identical. + */ + ubo = drm_plane_state_to_ubo(state); + vbo = drm_plane_state_to_vbo(state); - ipu_cpmem_zero(ipu_plane->ipu_ch); - ipu_cpmem_set_resolution(ipu_plane->ipu_ch, src_w, src_h); - ret = ipu_cpmem_set_fmt(ipu_plane->ipu_ch, fb->pixel_format); - if (ret < 0) { - dev_err(dev, "unsupported pixel format 0x%08x\n", - fb->pixel_format); - return ret; - } - ipu_cpmem_set_high_priority(ipu_plane->ipu_ch); - ipu_idmac_set_double_buffer(ipu_plane->ipu_ch, 1); - ipu_cpmem_set_stride(ipu_plane->ipu_ch, fb->pitches[0]); + if (fb->pixel_format == DRM_FORMAT_YUV420) + ipu_cpmem_set_yuv_planar_full(ipu_plane->ipu_ch, + fb->pitches[1], ubo, vbo); + else + ipu_cpmem_set_yuv_planar_full(ipu_plane->ipu_ch, + fb->pitches[1], vbo, ubo); - ret = ipu_plane_set_base(ipu_plane, fb, src_x, src_y); - if (ret < 0) - return ret; - if (interlaced) - ipu_cpmem_interlaced_scan(ipu_plane->ipu_ch, fb->pitches[0]); - - if (fb->pixel_format == DRM_FORMAT_YUV420) { - ipu_cpmem_set_yuv_planar_full(ipu_plane->ipu_ch, - ipu_plane->stride[1], - ipu_plane->u_offset, - ipu_plane->v_offset); - } else if (fb->pixel_format == DRM_FORMAT_YVU420) { - ipu_cpmem_set_yuv_planar_full(ipu_plane->ipu_ch, - ipu_plane->stride[1], - ipu_plane->v_offset, - ipu_plane->u_offset); - } + dev_dbg(ipu_plane->base.dev->dev, + "phy = %lu %lu %lu, x = %d, y = %d", eba, ubo, vbo, + state->src_x >> 16, state->src_y >> 16); + break; + default: + dev_dbg(ipu_plane->base.dev->dev, "phys = %lu, x = %d, y = %d", + eba, state->src_x >> 16, state->src_y >> 16); - ipu_plane->w = src_w; - ipu_plane->h = src_h; + break; + } - return 0; + if (old_state->fb) { + active = ipu_idmac_get_current_buffer(ipu_plane->ipu_ch); + ipu_cpmem_set_buffer(ipu_plane->ipu_ch, !active, eba); + ipu_idmac_select_buffer(ipu_plane->ipu_ch, !active); + } else { + ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 0, eba); + ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 1, eba); + } } void ipu_plane_put_resources(struct ipu_plane *ipu_plane) @@ -362,14 +320,10 @@ void ipu_plane_enable(struct ipu_plane *ipu_plane) ipu_idmac_enable_channel(ipu_plane->ipu_ch); if (ipu_plane->dp) ipu_dp_enable_channel(ipu_plane->dp); - - ipu_plane->enabled = true; } void ipu_plane_disable(struct ipu_plane *ipu_plane) { - ipu_plane->enabled = false; - ipu_idmac_wait_busy(ipu_plane->ipu_ch, 50); if (ipu_plane->dp) @@ -380,53 +334,13 @@ void ipu_plane_disable(struct ipu_plane *ipu_plane) ipu_dp_disable(ipu_plane->ipu); } -/* - * drm_plane API - */ - -static int ipu_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, - struct drm_framebuffer *fb, int crtc_x, int crtc_y, - unsigned int crtc_w, unsigned int crtc_h, - uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h) -{ - struct ipu_plane *ipu_plane = to_ipu_plane(plane); - int ret = 0; - - DRM_DEBUG_KMS("plane - %p\n", plane); - - if (!ipu_plane->enabled) - ret = ipu_plane_get_resources(ipu_plane); - if (ret < 0) - return ret; - - ret = ipu_plane_mode_set(ipu_plane, crtc, &crtc->hwmode, fb, - crtc_x, crtc_y, crtc_w, crtc_h, - src_x >> 16, src_y >> 16, src_w >> 16, src_h >> 16, - false); - if (ret < 0) { - ipu_plane_put_resources(ipu_plane); - return ret; - } - - if (crtc != plane->crtc) - dev_dbg(plane->dev->dev, "crtc change: %p -> %p\n", - plane->crtc, crtc); - - if (!ipu_plane->enabled) - ipu_plane_enable(ipu_plane); - - return 0; -} - static int ipu_disable_plane(struct drm_plane *plane) { struct ipu_plane *ipu_plane = to_ipu_plane(plane); DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); - if (ipu_plane->enabled) - ipu_plane_disable(ipu_plane); + ipu_plane_disable(ipu_plane); ipu_plane_put_resources(ipu_plane); @@ -445,11 +359,203 @@ static void ipu_plane_destroy(struct drm_plane *plane) } static const struct drm_plane_funcs ipu_plane_funcs = { - .update_plane = ipu_update_plane, - .disable_plane = ipu_disable_plane, + .update_plane = drm_plane_helper_update, + .disable_plane = drm_plane_helper_disable, .destroy = ipu_plane_destroy, }; +static int ipu_plane_atomic_check(struct drm_plane *plane, + struct drm_plane_state *state) +{ + struct drm_plane_state *old_state = plane->state; + struct drm_crtc_state *crtc_state; + struct device *dev = plane->dev->dev; + struct drm_crtc *crtc; + struct drm_framebuffer *fb = state->fb; + struct drm_framebuffer *old_fb = old_state->fb; + unsigned long eba, ubo, vbo, old_ubo, old_vbo; + + /* Ok to disable */ + if (!fb) + return old_fb ? 0 : -EINVAL; + + /* CRTC should be enabled */ + drm_for_each_crtc(crtc, plane->dev) { + if (drm_crtc_mask(crtc) == plane->possible_crtcs) { + if (!crtc->enabled) + return -EINVAL; + break; + } + } + + /* no scaling */ + if (state->src_w >> 16 != state->crtc_w || + state->src_h >> 16 != state->crtc_h) + return -EINVAL; + + crtc_state = state->crtc->state; + + switch (plane->type) { + case DRM_PLANE_TYPE_PRIMARY: + /* full plane doesn't support partial off screen */ + if (state->crtc_x || state->crtc_y || + state->crtc_w != crtc_state->adjusted_mode.hdisplay || + state->crtc_h != crtc_state->adjusted_mode.vdisplay) + return -EINVAL; + + /* full plane minimum width is 13 pixels */ + if (state->crtc_w < 13) + return -EINVAL; + break; + case DRM_PLANE_TYPE_OVERLAY: + if (state->crtc_x < 0 || state->crtc_y < 0) + return -EINVAL; + + if (state->crtc_x + state->crtc_w > + crtc_state->adjusted_mode.hdisplay) + return -EINVAL; + if (state->crtc_y + state->crtc_h > + crtc_state->adjusted_mode.vdisplay) + return -EINVAL; + break; + default: + dev_warn(dev, "Unsupported plane type\n"); + return -EINVAL; + } + + if (state->crtc_h < 2) + return -EINVAL; + + /* + * since we cannot touch active IDMAC channels, we do not support + * resizing the enabled plane or changing its format + */ + if (old_fb && (state->src_w != old_state->src_w || + state->src_h != old_state->src_h || + fb->pixel_format != old_fb->pixel_format)) + return -EINVAL; + + eba = drm_plane_state_to_eba(state); + + if (eba & 0x7) + return -EINVAL; + + if (fb->pitches[0] < 1 || fb->pitches[0] > 16384) + return -EINVAL; + + if (old_fb && fb->pitches[0] != old_fb->pitches[0]) + return -EINVAL; + + switch (fb->pixel_format) { + case DRM_FORMAT_YUV420: + case DRM_FORMAT_YVU420: + /* + * Multiplanar formats have to meet the following restrictions: + * - The (up to) three plane addresses are EBA, EBA+UBO, EBA+VBO + * - EBA, UBO and VBO are a multiple of 8 + * - UBO and VBO are unsigned and not larger than 0xfffff8 + * - Only EBA may be changed while scanout is active + * - The strides of U and V planes must be identical. + */ + ubo = drm_plane_state_to_ubo(state); + vbo = drm_plane_state_to_vbo(state); + + if ((ubo & 0x7) || (vbo & 0x7)) + return -EINVAL; + + if ((ubo > 0xfffff8) || (vbo > 0xfffff8)) + return -EINVAL; + + if (old_fb) { + old_ubo = drm_plane_state_to_ubo(old_state); + old_vbo = drm_plane_state_to_vbo(old_state); + if (ubo != old_ubo || vbo != old_vbo) + return -EINVAL; + } + + if (fb->pitches[1] != fb->pitches[2]) + return -EINVAL; + + if (fb->pitches[1] < 1 || fb->pitches[1] > 16384) + return -EINVAL; + + if (old_fb && old_fb->pitches[1] != fb->pitches[1]) + return -EINVAL; + } + + return 0; +} + +static void ipu_plane_atomic_disable(struct drm_plane *plane, + struct drm_plane_state *old_state) +{ + ipu_disable_plane(plane); +} + +static void ipu_plane_atomic_update(struct drm_plane *plane, + struct drm_plane_state *old_state) +{ + struct ipu_plane *ipu_plane = to_ipu_plane(plane); + struct drm_plane_state *state = plane->state; + enum ipu_color_space ics; + + if (old_state->fb) { + ipu_plane_atomic_set_base(ipu_plane, old_state); + return; + } + + ipu_plane_get_resources(ipu_plane); + + switch (ipu_plane->dp_flow) { + case IPU_DP_FLOW_SYNC_BG: + ipu_dp_setup_channel(ipu_plane->dp, + IPUV3_COLORSPACE_RGB, + IPUV3_COLORSPACE_RGB); + ipu_dp_set_global_alpha(ipu_plane->dp, true, 0, true); + break; + case IPU_DP_FLOW_SYNC_FG: + ics = ipu_drm_fourcc_to_colorspace(state->fb->pixel_format); + ipu_dp_setup_channel(ipu_plane->dp, ics, + IPUV3_COLORSPACE_UNKNOWN); + ipu_dp_set_window_pos(ipu_plane->dp, state->crtc_x, + state->crtc_y); + /* Enable local alpha on partial plane */ + switch (state->fb->pixel_format) { + case DRM_FORMAT_ARGB1555: + case DRM_FORMAT_ABGR1555: + case DRM_FORMAT_RGBA5551: + case DRM_FORMAT_BGRA5551: + case DRM_FORMAT_ARGB4444: + case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_ABGR8888: + case DRM_FORMAT_RGBA8888: + case DRM_FORMAT_BGRA8888: + ipu_dp_set_global_alpha(ipu_plane->dp, false, 0, false); + break; + default: + break; + } + } + + ipu_dmfc_config_wait4eot(ipu_plane->dmfc, state->crtc_w); + + ipu_cpmem_zero(ipu_plane->ipu_ch); + ipu_cpmem_set_resolution(ipu_plane->ipu_ch, state->src_w >> 16, + state->src_h >> 16); + ipu_cpmem_set_fmt(ipu_plane->ipu_ch, state->fb->pixel_format); + ipu_cpmem_set_high_priority(ipu_plane->ipu_ch); + ipu_idmac_set_double_buffer(ipu_plane->ipu_ch, 1); + ipu_cpmem_set_stride(ipu_plane->ipu_ch, state->fb->pitches[0]); + ipu_plane_atomic_set_base(ipu_plane, old_state); + ipu_plane_enable(ipu_plane); +} + +static const struct drm_plane_helper_funcs ipu_plane_helper_funcs = { + .atomic_check = ipu_plane_atomic_check, + .atomic_disable = ipu_plane_atomic_disable, + .atomic_update = ipu_plane_atomic_update, +}; + struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu, int dma, int dp, unsigned int possible_crtcs, enum drm_plane_type type) @@ -480,5 +586,7 @@ struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu, return ERR_PTR(ret); } + drm_plane_helper_add(&ipu_plane->base, &ipu_plane_helper_funcs); + return ipu_plane; } diff --git a/drivers/gpu/drm/imx/ipuv3-plane.h b/drivers/gpu/drm/imx/ipuv3-plane.h index 4448fd4..26b9c59 100644 --- a/drivers/gpu/drm/imx/ipuv3-plane.h +++ b/drivers/gpu/drm/imx/ipuv3-plane.h @@ -23,17 +23,6 @@ struct ipu_plane { int dma; int dp_flow; - - int x; - int y; - int w; - int h; - - unsigned int u_offset; - unsigned int v_offset; - unsigned int stride[2]; - - bool enabled; }; struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu, @@ -50,8 +39,7 @@ int ipu_plane_mode_set(struct ipu_plane *plane, struct drm_crtc *crtc, void ipu_plane_enable(struct ipu_plane *plane); void ipu_plane_disable(struct ipu_plane *plane); -int ipu_plane_set_base(struct ipu_plane *plane, struct drm_framebuffer *fb, - int x, int y); +int ipu_plane_set_base(struct ipu_plane *plane, struct drm_framebuffer *fb); int ipu_plane_get_resources(struct ipu_plane *plane); void ipu_plane_put_resources(struct ipu_plane *plane); diff --git a/drivers/gpu/ipu-v3/ipu-dc.c b/drivers/gpu/ipu-v3/ipu-dc.c index 2f29780..cd72dad 100644 --- a/drivers/gpu/ipu-v3/ipu-dc.c +++ b/drivers/gpu/ipu-v3/ipu-dc.c @@ -178,10 +178,7 @@ int ipu_dc_init_sync(struct ipu_dc *dc, struct ipu_di *di, bool interlaced, dc->di = ipu_di_get_num(di); map = ipu_bus_format_to_map(bus_format); - if (map < 0) { - dev_dbg(priv->dev, "IPU_DISP: No MAP\n"); - return map; - } + BUG_ON(map < 0); /* * In interlaced mode we need more counters to create the asymmetric diff --git a/drivers/gpu/ipu-v3/ipu-di.c b/drivers/gpu/ipu-v3/ipu-di.c index 359268e..a8d87dd 100644 --- a/drivers/gpu/ipu-v3/ipu-di.c +++ b/drivers/gpu/ipu-v3/ipu-di.c @@ -572,9 +572,6 @@ int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig) dev_dbg(di->ipu->dev, "disp %d: panel size = %d x %d\n", di->id, sig->mode.hactive, sig->mode.vactive); - if ((sig->mode.vsync_len == 0) || (sig->mode.hsync_len == 0)) - return -EINVAL; - dev_dbg(di->ipu->dev, "Clocks: IPU %luHz DI %luHz Needed %luHz\n", clk_get_rate(di->clk_ipu), clk_get_rate(di->clk_di),