From patchwork Fri Jul 8 09:40:55 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ying Liu X-Patchwork-Id: 9220341 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 E097860572 for ; Fri, 8 Jul 2016 09:41:44 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id CEB1E28638 for ; Fri, 8 Jul 2016 09:41:44 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id C34182863A; Fri, 8 Jul 2016 09:41:44 +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 2AEFA28638 for ; Fri, 8 Jul 2016 09:41:43 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id A583E6E8DA; Fri, 8 Jul 2016 09:41:38 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from NAM02-SN1-obe.outbound.protection.outlook.com (mail-sn1nam02on0053.outbound.protection.outlook.com [104.47.36.53]) by gabe.freedesktop.org (Postfix) with ESMTPS id 582E36E0FF for ; Fri, 8 Jul 2016 09:41:27 +0000 (UTC) Received: from BLUPR0301CA0039.namprd03.prod.outlook.com (10.162.113.177) by CY1PR03MB1504.namprd03.prod.outlook.com (10.163.17.22) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P384) id 15.1.539.14; Fri, 8 Jul 2016 09:41:24 +0000 Received: from BL2FFO11FD028.protection.gbl (2a01:111:f400:7c09::134) by BLUPR0301CA0039.outlook.office365.com (2a01:111:e400:5259::49) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P384) id 15.1.528.16 via Frontend Transport; Fri, 8 Jul 2016 09:41:24 +0000 Authentication-Results: spf=softfail (sender IP is 192.88.168.50) smtp.mailfrom=gmail.com; ffwll.ch; dkim=none (message not signed) header.d=none; ffwll.ch; 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 BL2FFO11FD028.mail.protection.outlook.com (10.173.161.107) with Microsoft SMTP Server (TLS) id 15.1.534.7 via Frontend Transport; Fri, 8 Jul 2016 09:41:24 +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 u689fBMp003192; Fri, 8 Jul 2016 02:41:21 -0700 From: Liu Ying To: Subject: [PATCH v4 03/10] drm/imx: atomic phase 1: Use transitional atomic CRTC and plane helpers Date: Fri, 8 Jul 2016 17:40:55 +0800 Message-ID: <1467970862-28012-4-git-send-email-gnuiyl@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1467970862-28012-1-git-send-email-gnuiyl@gmail.com> References: <1467970862-28012-1-git-send-email-gnuiyl@gmail.com> X-EOPAttributedMessage: 0 X-Matching-Connectors: 131124444842602568; (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)(7916002)(2980300002)(199003)(189002)(6260500002)(6806005)(2351001)(5890100001)(189998001)(4326007)(8676002)(2950100001)(47776003)(229853001)(50226002)(2906002)(83322999)(73392002)(19580405001)(19580395003)(77096005)(55446002)(50466002)(92566002)(87572001)(87936001)(97736004)(76482005)(11100500001)(110136002)(48376002)(36756003)(81156014)(586003)(8936002)(82202001)(81166006)(61266001)(68736007)(86362001)(5003940100001)(76176999)(50986999)(105596002)(33646002)(305945005)(104016004)(106466001)(81442002)(7846002)(73972006)(356003); DIR:OUT; SFP:1101; SCL:1; SRVR:CY1PR03MB1504; H:tx30smr01.am.freescale.net; FPR:; SPF:SoftFail; PTR:InfoDomainNonexistent; A:1; MX:1; LANG:en; X-Microsoft-Exchange-Diagnostics: 1; BL2FFO11FD028; 1:spzIB9nwwG5RzAIEdn6ZUhp8rBzEEOCOeHbwPMTCG6G7pc159Vh9pIMZseB+CjQWsEgTx/4jBkvAbJnTpBVVcVBRXEduabqDJbbZ4NVwQ5BUapIdhSvwfJsySGO/qNEH5IQj07Acew8j8acK5wqAPMdxB/jcd7I6FzWkapYdsdud129BNYL5Yb2HtGxULV6k60bicanOQfiNyIZ70tZn5Vacmd4K+cc/ayitva7fdxd2f66mW5eD8MJJL4x4bCwVt8if2V4NU36F60HhXoV5XPXfCZtBjTAZqoLoN81i+Orei0RWqcReyCQ88++T7LNAML6TAeQLuBo26lsE4tP9FO5nk/USaBDSjaU1dtxotGFJ2RaZKfrecyrj4+fi/u7b1wJ3MRHbK2HYpsWGjjfovyQNlqpPPX1KRXkQQvxK09LlybetPkr7o1IcCmq8lBb0uesZCNHw2eu01/IwPMCbVZTh6LBzE4IUdkJPomZw83QrKkWWmI6qelrT40Rqg05n1eJDviHJOPGTjwZdZ0RojBeGaqdr/NB3vqsxJswYW4ixMpHmGUEemT5/Yt2E7UEhK9mJ2LRfSiYV3dwxdwqHhA== MIME-Version: 1.0 X-MS-Office365-Filtering-Correlation-Id: a44e576f-3b13-475b-4ee7-08d3a71406ab X-Microsoft-Exchange-Diagnostics: 1; CY1PR03MB1504; 2:53PHisuMl5eAIPB2KD8QUlqMXTc7kBZxMLf6+SNcNJT/wqThURTnj0CVa+0dPH17ipL1kaNy0z0QkWwvi/pKn8MZ0ECYxAWwAG4qNrwpU6Hwo5RaSSxi6XlYWPgd6r0XxPM9i9jj8cfxAXAFbsZ9zIkfrzydgDe5zr4SZDok7zv3kKxgjV5pGQdcmIkhofKO; 3:js0EhOG/l6+SMMlSqC6GHTilojJVQPbLW51ahyFg+NP1IluhBC8StNrLLbG4pYBb5AAP8gcUzVD2ofTvzA2JlMDcMGIioNO+jQ7cEjdBE8Ew1uKVpZMeYZY08CY5+xF4b7KlRXTmkQFjqQYh9Pm9+Y1Ln3J/TPxhthsrKAOxaxaZr8gQw9oxQGeBJn7O8Jr6htNqm3LR3G+oQRGbI9KPhg3fzVaRRxhCmD/70KxUIKc= X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:CY1PR03MB1504; X-Microsoft-Exchange-Diagnostics: 1; CY1PR03MB1504; 25:L8ROPX/TMo6xsr2ufJTUL6fPtoMhP7TRuo4JkAqg4emdTqshTRf+ZmLw6I4cgt10CpShexYgLkGoDpsd13CzfrWD1/a2jLjrdJrTzXCPC16havLvmxnL3WbgCSbmG3qJ5LOZzYb+b8pknYgBt2qvhfYsqeBtUPeyd9jcEQo08WXJpQLhbZvWQu3cSa/NLkNRaV3dFWIx7tPy6oP8T0SN/DcQAvQrQNTmPMjmEtrMIIVDB+T7oDqtLt8VA/7P3TOMbZ8qd+3tMu3l0UX0TVZC/alNK1x8gMk7xy4MpAEkTK7kRm8qmn9tqmLqE2k2m4XYmVaEmciTv7AUmksBoSwkxCGsc+9pZ3nlzkBmMYUA/IWvIfxLlUkVGNxFHdCcG1pJqQGLoFC5i6mKVh5KK82zxbCEKg6Az17CRBgecug+kgCb63AHxhxcC1FlE7GqD4qyaPDyz9ox8g97yWP0wRiqCqmq9K92fmvfq99zxMlSiz9I7PrOh1ZtP7HkqXN6/kmcL1Ix0QBZN1IHXUz9dKvDUd4yHZiA0z+TtzOUckqyL7N9cobUlHXkBFMDqpgyn2DdInajefjezTup+K9Flbwjo4b2/uUUTBzURhTfYqx/PtEOuyWJLIGobSDnv6nInyJSfACcDb6mUiEdJlT8F+vtJ8cNKEm2vV4SydVmN+rkSofeskGNaj9z65lNNDJNwuQHkgsp2zqIqz6CeWt8EwM2xqq7JiEhbhcoBNCrXMvEKQ71PmngW50L7tCPgW3OOkm5 X-Microsoft-Exchange-Diagnostics: 1; CY1PR03MB1504; 31:hWHG5Coe37A1pqtxCgSncsqKMz1JL6cf1GV/hx1MNr98ALbXeCNM4TNo9YziPqZqNysNQ3oEzuCLxKzKP7Kgs71aWgvhb3jBvhcBfEI9O/0qGVYtUVoqvkUWYbbUTGM3lBrm3FHRZJqXC29zfeJ0taGHe1bC9Xv6bdgXYGBNJeZueVJ44OAII6SY3vOIu5YoPX3lLB07Xx0NW9MNeEBrgQ==; 4:gsnc00msNm6Esg4HyS+uOwQzXJxnmgqQOXWimQUvP7pTthG7FCFxE7YW5wzJcz9y6KkTK1t0zZJarOvsRv+HP92trpMsLTZhsnAX43VJW3lKUv/svP4McYzWS5KoNZ65S7n1DMpMCvYcnquGcJoW9ntRkhqB8YYRIYalQhYZXiochGViCJNUy99WCwt9kPlYKuR1OFUKuPsaNbQOmZr2tF9C5btENmzIk2krrDPEPG53RZlznts504anM6jfbVrekUcgFM2dEAllnBR3rpcdR4qudxE6FYIT5EYud9p7RRtNbuqzrJLIgTNzF2jNJIRkhndWIZOnHP3WO07pgZKt2PbQQXiLrOnK3qm7zB1c1e1i9PLcUA183VOU2JH3xGgWVazjIiBDO58jrmO+fHBTeuWcpGqHXR30Luo0zShwns2WDUAPSaOruqwU2MPedxBK2DGurOW68U2NS42q0WwPcc+K6OUju6qW3CgEotNSfyo= X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:; X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(601004)(2401047)(13015025)(8121501046)(5005006)(13017025)(13023025)(13018025)(13024025)(3002001)(10201501046)(6055026); SRVR:CY1PR03MB1504; BCL:0; PCL:0; RULEID:(400006); SRVR:CY1PR03MB1504; X-Forefront-PRVS: 0997523C40 X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; CY1PR03MB1504; 23:S1O3ch7qpu/HY3Rppg9S5AKhhSkrVUv4t2XonKSnt?= =?us-ascii?Q?+4NDwjiTkLrZhXYfLMCsmUoC5G13JO8gBUTi+EYVe/gqflYl63qhVXg0M6DD?= =?us-ascii?Q?4FgRbKgKk5/MjEoth1tKEAR7EjcKcTeevFpcCXMxuindrWA7pPyV5q6cb66F?= =?us-ascii?Q?ZLCDGICqGzwCaLiacKfp2NiXbxcZWg3EYAUPF2cAQJHrVz62jNDHkfu+Xrsx?= =?us-ascii?Q?q6yboD7IOQKa7xKWOJeQZ9W3E6xdkdKGge7RMjhl/q9+bdHdxfnlsqlGqQOC?= =?us-ascii?Q?8eKnZ94+W4H9OsN75yZj5HBc5JEZTgKwMRVDFjudnxPb0omf0BxNQ35oqcIE?= =?us-ascii?Q?1F+wqEnl2XHRHNVwTv/c7sAcpJ8PL0Oolz5j/1kiSWl49dpx7iAh70CFeaTN?= =?us-ascii?Q?Jfn0k7KV9rpXxuLBY5QIoJFO5zwHC0DjMuuvfOIc47cOlg0ChgotfPZa51Dj?= =?us-ascii?Q?p22IPEQNuhOgEcA2jOukphxd8lj6lThMbI2iPS2WQtdWeElZKuz7ouUDSCuL?= =?us-ascii?Q?027Lr5JG6nv1WresPfiap+7KsqpFsf1JhvtREueXWlRKBSPeGN5MUsvq9n7t?= =?us-ascii?Q?EfsAnfF2LRuHVglTsE/ZaFV6/oVi3WDxNr1GJYiDZmiRS/YgoQ1Vt88aEz2T?= =?us-ascii?Q?MzNozNf8Rg7cTiULGl9aCjsg9hJ8vhkVODT3OKvebnyRu+2VGCbtBTR6KwCK?= =?us-ascii?Q?ADQGqdv2dhItHL+jPN1vnVRqXm6nunSp9KGfpNKn6/+sG0KVYp4Q50pSySBl?= =?us-ascii?Q?mbAGxpR9zF3H/8E47EuMwk6m2TxIg2qnOHDDMSfpJFPWG0O1SyDGJ3U7Fcsn?= =?us-ascii?Q?/ubYDySB7YsNFFz9mJ3J6Zq3OkV0SMgVqxXVye2WV82LhFQrGmDAiJulDzmH?= =?us-ascii?Q?sda7BOmwHsNYvuTSqtGGCBJBfR/7RDucrUOj+sJYb+PJbFshyFqguogXUV0L?= =?us-ascii?Q?txJn3iSLOhYKjw4N+EHFwjI30JPzx+QlliC7jNLXBsBRyEb6VGXH4+Ke86Qp?= =?us-ascii?Q?3kdRydU0kgEw9rmqViYLcByaRyitzUhpwiWVhk4m04hBhu3M20sILSiKQg4S?= =?us-ascii?Q?H+f2FBHPN4fDoHVnsyF31hIPvdrmM6FPxC/aq99tcuh20XkX5hOHeuP0ai5F?= =?us-ascii?Q?2ZaLDZM43kwbew6I65Pr8CDe9kie+mV2ks+8bMuJmXb7mDa09rfA/5kS5wRQ?= =?us-ascii?Q?pEkK9zzlZGfjvFeVsQN/qrKWdZYRRTVc0Da2RMhCvSGv6usPn0yNtJ1M5p51?= =?us-ascii?Q?N8N796wwLIFQ1ktLdwDyJxaYwA1j+6DXRskN/6E?= X-Microsoft-Exchange-Diagnostics: 1; CY1PR03MB1504; 6:B8VQKb8XRSYk6tdl1GzBVY4mAdj8o1PF+Q2ZjIs0+1jVgYFoX4rb0xEiPyQNT7J3qdPCKpxaG+OGTqXzPWKGm+TQZBRI9/hXlQk3pBKwG7GA2TjzlezTLkKNi8u/13ooPq88o8cYg0DwboyosiQweiCvixJpY84px98RT3pjxsJfAUl8D52QjBscxO0GIwtKRI9jSYelk4DgzuLZ6mrZ2rBbDFy6szKlBhyJy0AaaJbX99CVkFFDMiTK/crqhndNernUF4c118N3+Q9xpNe/s7N4wpGJucM9GP6mRo2QNJo=; 5:quBM4G+9cmvKJNJKEVfnDaA5g+MFSBU6zipp8Y3DxQhwK8TySz+rd9tOAlPdu9FkJmyPCo4cgbjqsCr5aePpog13eHT/YA1qfmhd9omHuNbhvu6cNigui1CiUpwfIHwnDhmaD/WhDhrC95z0IP9g+6JxTVIttFAJPvOf95Y7nwE=; 24:JXLDllOYpMJ3BHTdhGz+V4w95mv/mJl2mM456usk+p5Yscj0v7Sxdbt8wsL4uFW90RTqXxlXkVQfjfgyZecd7TCEFEvML2Tb6D+Iy9OteXQ=; 7:mczng9TO1y9+jTDnbSH1pB3JxSJnvWSnTPqXgJrA7LPB/TVXNcHNn3LMHcFKDM7QXf25Jq+fK8xU5epBupWTVhSXYqJ/GezMhgzJx1au+a/eShzP0KWrkmGlnpOyujVo2tVRzE9dYq9DMtVJIH5J+ZMSLYZSVkTQQq5aFT0fRPb4VN00nfIhxwQaxmeBzgUNhFsvDX3qJmZbsHb/920Fj4yuMWp9iJdIvZKu+62D3dcswSGty2wvCPab1j6H+9Zp SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-MS-Exchange-CrossTenant-OriginalArrivalTime: 08 Jul 2016 09:41:24.0886 (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: CY1PR03MB1504 Cc: Russell King , Daniel Vetter 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() transitional 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 --- v3->v4: * Staticize ipu_plane_atomic_set_base(). v2->v3: * A minor change to simplify the way we find crtc->enabled in drm_plane_helper_funcs->atomic_check. v1->v2: * Get the overlay ipu plane resource when initializing the relevant CRTC and do not get ipu plane resource any more when updating plane to avoid resource allocation failure. * Remove obsolete comments from ipu_crtc_enable/disable(). drivers/gpu/drm/imx/ipuv3-crtc.c | 197 ++++++++------- drivers/gpu/drm/imx/ipuv3-plane.c | 511 +++++++++++++++++++++++--------------- drivers/gpu/drm/imx/ipuv3-plane.h | 16 +- drivers/gpu/ipu-v3/ipu-dc.c | 5 +- drivers/gpu/ipu-v3/ipu-di.c | 3 - 5 files changed, 410 insertions(+), 322 deletions(-) diff --git a/drivers/gpu/drm/imx/ipuv3-crtc.c b/drivers/gpu/drm/imx/ipuv3-crtc.c index fc04041..ba880fa 100644 --- a/drivers/gpu/drm/imx/ipuv3-crtc.c +++ b/drivers/gpu/drm/imx/ipuv3-crtc.c @@ -73,7 +73,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); @@ -81,30 +81,30 @@ 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); if (!ipu_crtc->enabled) return; - /* 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) @@ -115,12 +115,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; } } @@ -234,79 +234,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 = !(ipu_crtc->bus_flags & DRM_BUS_FLAG_DE_LOW); - /* Default to driving pixel data on negative clock edges */ - sig_cfg.clk_pol = !!(ipu_crtc->bus_flags & - DRM_BUS_FLAG_PIXDATA_POSEDGE); - 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; @@ -330,8 +257,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); @@ -355,6 +281,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; @@ -364,28 +293,95 @@ 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 = !(ipu_crtc->bus_flags & DRM_BUS_FLAG_DE_LOW); + /* Default to driving pixel data on negative clock edges */ + sig_cfg.clk_pol = !!(ipu_crtc->bus_flags & + DRM_BUS_FLAG_PIXDATA_POSEDGE); + 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; @@ -496,8 +492,16 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc, IPU_DP_FLOW_SYNC_FG, drm_crtc_mask(&ipu_crtc->base), DRM_PLANE_TYPE_OVERLAY); - if (IS_ERR(ipu_crtc->plane[1])) + if (IS_ERR(ipu_crtc->plane[1])) { ipu_crtc->plane[1] = NULL; + } else { + ret = ipu_plane_get_resources(ipu_crtc->plane[1]); + if (ret) { + dev_err(ipu_crtc->dev, "getting plane 1 " + "resources failed with %d.\n", ret); + goto err_put_plane0_res; + } + } } ipu_crtc->irq = ipu_plane_irq(ipu_crtc->plane[0]); @@ -505,7 +509,7 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc, "imx_drm", ipu_crtc); if (ret < 0) { dev_err(ipu_crtc->dev, "irq request failed with %d.\n", ret); - goto err_put_plane_res; + goto err_put_plane1_res; } /* Only enable IRQ when we actually need it to trigger work. */ disable_irq(ipu_crtc->irq); @@ -514,7 +518,10 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc, return 0; -err_put_plane_res: +err_put_plane1_res: + if (ipu_crtc->plane[1]) + ipu_plane_put_resources(ipu_crtc->plane[1]); +err_put_plane0_res: ipu_plane_put_resources(ipu_crtc->plane[0]); err_remove_crtc: imx_drm_remove_crtc(ipu_crtc->imx_crtc); @@ -554,8 +561,10 @@ 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); + if (ipu_crtc->plane[1]) + ipu_plane_put_resources(ipu_crtc->plane[1]); + ipu_plane_put_resources(ipu_crtc->plane[0]); } static const struct component_ops ipu_crtc_ops = { diff --git a/drivers/gpu/drm/imx/ipuv3-plane.c b/drivers/gpu/drm/imx/ipuv3-plane.c index 02701de..b85d102 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" @@ -53,12 +54,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); @@ -68,6 +72,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; @@ -81,13 +93,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: @@ -104,6 +114,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; @@ -114,8 +132,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; } @@ -130,16 +147,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, @@ -151,164 +163,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 device *dev = ipu_plane->base.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 (ipu_plane->base.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 (ipu_plane->base.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 != ipu_plane->base.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; +} + +static 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) @@ -355,7 +314,7 @@ err_out: return ret; } -void ipu_plane_enable(struct ipu_plane *ipu_plane) +static void ipu_plane_enable(struct ipu_plane *ipu_plane) { if (ipu_plane->dp) ipu_dp_enable(ipu_plane->ipu); @@ -363,14 +322,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) +static 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) @@ -381,74 +336,216 @@ 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) +static int ipu_disable_plane(struct drm_plane *plane) { 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); + DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); - if (!ipu_plane->enabled) - ipu_plane_enable(ipu_plane); + ipu_plane_disable(ipu_plane); return 0; } -static int ipu_disable_plane(struct drm_plane *plane) +static void ipu_plane_destroy(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_disable_plane(plane); + drm_plane_cleanup(plane); + kfree(ipu_plane); +} - ipu_plane_put_resources(ipu_plane); +static const struct drm_plane_funcs ipu_plane_funcs = { + .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_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 */ + if (!state->crtc->enabled) + return -EINVAL; + + /* 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_destroy(struct drm_plane *plane) +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; - DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); + if (old_state->fb) { + ipu_plane_atomic_set_base(ipu_plane, old_state); + return; + } - ipu_disable_plane(plane); - drm_plane_cleanup(plane); - kfree(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_funcs ipu_plane_funcs = { - .update_plane = ipu_update_plane, - .disable_plane = ipu_disable_plane, - .destroy = ipu_plane_destroy, +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, @@ -481,5 +578,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..c51a44b 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, @@ -48,10 +37,7 @@ int ipu_plane_mode_set(struct ipu_plane *plane, struct drm_crtc *crtc, uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h, bool interlaced); -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),