From patchwork Mon Jul 4 07:40:32 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ying Liu X-Patchwork-Id: 9211845 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 5418360572 for ; Mon, 4 Jul 2016 07:57:09 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 4305E284CB for ; Mon, 4 Jul 2016 07:57:09 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 371EF28572; Mon, 4 Jul 2016 07:57:09 +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 A43CC284CB for ; Mon, 4 Jul 2016 07:57:07 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id C80616E3B0; Mon, 4 Jul 2016 07:57:06 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org X-Greylist: delayed 953 seconds by postgrey-1.35 at gabe; Mon, 04 Jul 2016 07:57:04 UTC Received: from NAM01-BN3-obe.outbound.protection.outlook.com (mail-bn3nam01on0044.outbound.protection.outlook.com [104.47.33.44]) by gabe.freedesktop.org (Postfix) with ESMTPS id CAE5F6E3B0 for ; Mon, 4 Jul 2016 07:57:04 +0000 (UTC) Received: from BN3PR0301CA0037.namprd03.prod.outlook.com (10.160.180.175) by BY2PR03MB255.namprd03.prod.outlook.com (10.242.37.22) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P384) id 15.1.523.12; Mon, 4 Jul 2016 07:41:02 +0000 Received: from BN1AFFO11FD045.protection.gbl (2a01:111:f400:7c10::103) by BN3PR0301CA0037.outlook.office365.com (2a01:111:e400:4000::47) 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; Mon, 4 Jul 2016 07:41:02 +0000 Authentication-Results: spf=softfail (sender IP is 192.88.158.2) 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.158.2 as permitted sender) Received: from az84smr01.freescale.net (192.88.158.2) by BN1AFFO11FD045.mail.protection.outlook.com (10.58.53.60) with Microsoft SMTP Server (TLS) id 15.1.523.9 via Frontend Transport; Mon, 4 Jul 2016 07:41:01 +0000 Received: from victor.ap.freescale.net (victor.ap.freescale.net [10.192.241.62]) by az84smr01.freescale.net (8.14.3/8.14.0) with ESMTP id u647ep0S026135; Mon, 4 Jul 2016 00:40:59 -0700 From: Liu Ying To: Subject: [PATCH v3 03/10] drm/imx: atomic phase 1: Use transitional atomic CRTC and plane helpers Date: Mon, 4 Jul 2016 15:40:32 +0800 Message-ID: <1467618039-7457-4-git-send-email-gnuiyl@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1467618039-7457-1-git-send-email-gnuiyl@gmail.com> References: <1467618039-7457-1-git-send-email-gnuiyl@gmail.com> X-EOPAttributedMessage: 0 X-Matching-Connectors: 131120916620820167; (91ab9b29-cfa4-454e-5278-08d120cd25b8); () X-Forefront-Antispam-Report: CIP:192.88.158.2; IPV:NLI; CTRY:US; EFV:NLI; SFV:NSPM; SFS:(10009020)(6009001)(7916002)(2980300002)(189002)(199003)(6260500002)(356003)(50466002)(55446002)(81166006)(61266001)(2950100001)(77096005)(5003940100001)(92566002)(76482005)(47776003)(305945005)(110136002)(50226002)(5890100001)(48376002)(189998001)(81156014)(229853001)(106466001)(83322999)(97736004)(8676002)(2351001)(105596002)(82202001)(104016004)(7846002)(8936002)(33646002)(4326007)(6806005)(586003)(68736007)(73392002)(11100500001)(87572001)(69596002)(76176999)(50986999)(2906002)(81442002)(36756003)(87936001)(19580405001)(19580395003)(73972006)(86362001); DIR:OUT; SFP:1101; SCL:1; SRVR:BY2PR03MB255; H:az84smr01.freescale.net; FPR:; SPF:SoftFail; PTR:InfoDomainNonexistent; MX:1; A:1; LANG:en; X-Microsoft-Exchange-Diagnostics: 1; BN1AFFO11FD045; 1:YEsfv/NoPHW5U+n2HiGJrGyYXSk3zlzRnH7K5oVCKTbSJqxpWYmxpVYa1rEHF9HHV9G+o3yF2jBM5IYcVQc2SIqgOoayIRKxBfeKOGNscU5AIjkcu91nUjwhqnj+4b5W7F6C7T8I8LLI7YnJiDbXFb5x/wDExM+KCLKZNyZ8UB7VEFfYrcbBMAzvLVXf32fT24BZa/Jce6RBSNit6oYXFpCOiFzjQkmaIf60PU4X+X8bcb5+QFIaYWnngHZzG92h5gyPc8W5MFd5KySEsZv+EWeXhSOSm9xHLXcqkNa/ZSEwA3LO1FPLMMZGjhnL7Pte2hLO3WRLWrWjRInsHxdAqG0WDLYpHwNvO+QxDfclEHcfN2htKXmLMFRzFYTW9oqK8+qBXcTgHiRDbkmPOv9RaaP65Emkfzg6HXtA9IjE1rTTEKRpeLYA+U59TgQQwS/7Ml0AzklVciVIMq0g4RydQHr0rw/WNQbEgpzDwKqJT5cR6BiTytTZVSdWCbF+MMU1bwsYaiZNDYsFfEbU4rhyi6kz51B91JBD2BfivVB0nhlIc33J88BDP094Mox/u9BMqlsY6SZo1n3VhzcVSRiy6A== MIME-Version: 1.0 X-MS-Office365-Filtering-Correlation-Id: e0a672e2-22c7-4962-bec7-08d3a3de8c45 X-Microsoft-Exchange-Diagnostics: 1; BY2PR03MB255; 2:Gz/SKYsXQper3HCIOYmnBqtQf6hwkGWsCaZANTO8afNG5i2UfsxKYToTV5qqlHXegnN3jTGjxCxd45lbLYkCDR8u91b8uqH2Dp55w+4+JX7ePMifjSx3Fpuj/sg0AP4h1dqfSOXV+yKJhtG0tlZjis6BCUaeYUdqGesLYIi+FCUPiacMNIA22EgNvJgtBteP; 3:stj6O0KleSHKgA7xicapBfXZ97w0r/Bp1TX7q/I5U7H+ADymzWHKZb+v2xh6YznkPNDmK9EGZLJF/ZvBxkEWJMTnNf21Ro/nSPL0Y9g4zG9MGL/3Kb575Xn8H1n2dFcmfQxWypvzQQNNKr/zUNvbt9MFGAec5vD7hvxzwYdJnAvs35aUfgQDU/IiCgN9+IsZVPWmAYml2uGGKGGUnP/ZTOVLzJ6Wfnh9fdUyjuof3us=; 25:S+TPo2+C3V/+N+Sh2ajJqhx8aVs5MjiPVjC4pyFWKEf5tZt2u/ZblxBGs7/iRGJPjyS1HCd/ML1uiKHffnEgxpahsA/H6Op803pDkwRCFVdeyrz9MXt9EgRxav6zPlzOu6gOOHtlnQlK/to85oFeNmgVRY9XMg/qkZx/RWZ/0HzfC2ymDWq3erOSpDcHXB2S3LjIUMvvwMP0MftniX1b4BfQVK876Xa0rJCigbIGUOCIEbO02u/Lp8fAfvXIXaiPEgozxkPzBKWPBZRAidKy/RcRnrznOjeMKkSS1B9u1OUwb8pO5wFGDpNe3g2I+lbS3fJRt0l4IK7vJMtCUbbw7Zpy93ugONMjecdmPzFk2fVpzymtY+/BWM0fwZt62acztb8dxMtyi6IfB1ToUmT21bwPCn9vvKxg52jHh98lMU8= X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:BY2PR03MB255; X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:; X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(601004)(2401047)(5005006)(13015025)(8121501046)(13023025)(13017025)(13018025)(13024025)(10201501046)(3002001)(6055026); SRVR:BY2PR03MB255; BCL:0; PCL:0; RULEID:(400006); SRVR:BY2PR03MB255; X-Microsoft-Exchange-Diagnostics: 1; BY2PR03MB255; 4:P+MX2v3fXbi5juTW6gYwCMJpuhLU52Oggx73Goli0XOqUfP8Ge31Pi2SjWtmKGBgHeAixdw04zriarTXRf5KYmygfWkJ4GcpO2jhW7K2NO1uHlmFqfrqTdRHF9LHvbtFLOBoOrGD0/DE/vlSMBPu7XwGyGzuZn8kod9FJjT8UfxMcFgXtRFRzKtLgJ6uthQ8IrnsSDxdsn/xbmGlHBjix6XqmHdsVNoy6rosFha/qIumzWqqehvYAdd54mX6iQlbYfLpSGsrKbvQQu1SeLfPD5bR2xE1zfy84t1TiguAXaDPYv6+B1YcLrMzdmMR2+VWdbcpI86wUjprc5/Jht5KH3BsQEM1EyxhDzLqsvv4IwPFQSow/9lZC3YfVx3ghX/jzZkmG18l3VzOz11RnHmGEp11dAGxxE/0AEWmaFKPeFXllYu+6R2f0UhfGRU4t3NIcrr97zJNUlvqldf6akg1i71Lr+v7lHAM45dui9clL5s= X-Forefront-PRVS: 0993689CD1 X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; BY2PR03MB255; 23:HVprltx05MukJpXFFQSSsUIYmXUKEpHLs8DAgRNK7D?= =?us-ascii?Q?RGP6cZyb0VtjlXmQGBrjQyq1nrpL146euskwtKN3hbATosNCCIZKuzlJ26lL?= =?us-ascii?Q?wkVdBzM9ounShxIhLhZMQ//Ii6qgG0UeGnU1mFXlpnhihDfsGGwLhlpQ55Sy?= =?us-ascii?Q?Eyj3YkBV2b9GfWd/5xyKQtfXzhLQ+ix60JjwQ0L7imC1LngHE2/zwrhaVfzF?= =?us-ascii?Q?X1YcDhn+5Ic12zCMXXf+dCS31aORxLq0ZGwmsVJYdugVaqsXB1MGcRoY2Ylh?= =?us-ascii?Q?xV+fqQCcrpfRaLauQUEVqI01+LCdIoCWiEbD6pQafN/JKH6tG5qYkgCXEqEc?= =?us-ascii?Q?PSG2Y1AkH0x73/sR4tYgBu7PjBQbwu9Rkae51CVKdbd0o1tia92TnCs6kGku?= =?us-ascii?Q?ju0ZvQFoHWm10CS9gRdsPtM165NUNEym6XLgWJidIpj0+th2hnL+na9x+nPH?= =?us-ascii?Q?Zfi6ikBXeEcnuJXtrn9qawzS9OUE6a9/W9e5WHWuKJ0EBvgRgH3fnJZBA6M3?= =?us-ascii?Q?qlGfQQsjTELwqUvCpF97HFKRkIOhiyztfjApV8eUS1y3iqiPP0cqM9pW/4jU?= =?us-ascii?Q?xX7xlJsfgicUUMdyNaKy8/WHosP3xTpfn6ajyT93cqbV5EC5JrKp8KKAw1+E?= =?us-ascii?Q?VV4PH298EBzRcFCEEkTgtU9wPK1O1DC8OxEF4qGOX1CVUKHiUp/vRX6WTTq0?= =?us-ascii?Q?Jw5OBrd44IYCm5od0Y4CE3Y+umFnd+92XEgDCQ+pZ9hoj3pnypCq6nHtnAMC?= =?us-ascii?Q?2n8ZaQ6bo9x1WPgtDGLYhZ25xE3N7Oc9JBUr7U0UDD11eupjkJJEF8cBFwJi?= =?us-ascii?Q?P9EX0ZZqK94RJfiIgiOaCu9elCCbnYte1E3URquTHD8pIqDJZlaLMweP1Pox?= =?us-ascii?Q?Am9Q7ocBTVRevRsg6YFX6kgo9Jdu7VbZjWabY6mTrtmDQzmNDn8pFzE8As8N?= =?us-ascii?Q?sdq1fS/9fZQ2+mP6N4yAdrwglw6TGiP4qByLBTZ+lJTi8a3dX0cEoVq8MiDp?= =?us-ascii?Q?oRsxmGX0BSDRXMuXktASOmZl8FMO0GpdlKg6vXCMKQPoVodbPyIaHtytuB++?= =?us-ascii?Q?OEnXMr9K6P2sDbMWeM3oSzvMylVZtjWsFvttQCITXX7n4xylOsWL2rbNWKgs?= =?us-ascii?Q?wcnCZhKoeTkbSs7OZB4iz4fazsuUMxJra6yJuKGGUYMj1QrueHglG7gmO0XT?= =?us-ascii?Q?GjliX/U8XSZYLWGLH7V0c6AXVXCmjF6rrj29hHlvcVHPZhAmqx1en525fhmM?= =?us-ascii?Q?/1V7I8MQxW0MxRCvKSrhVOZdmCKYpTO/mTp3DFIXgzUJZfESpFqN+HCsugDQ?= =?us-ascii?Q?=3D=3D?= X-Microsoft-Exchange-Diagnostics: 1; BY2PR03MB255; 6:36ER3AT3bk+wi6fsRamoSYz0Jts9pMcz7T+m9zc9UmXD1jUBO5AQi5rvSDAiRu+f4JTWTm0aSRVCaIpLRnBaQXoBScpZhaEoX+/7s77+ycFQlJntyRFEBw+POXXu4/41xr9AWttFS0q405t47v2/XvsKnz+52kV47uvqaCy2r0bQRQXWtR6X0qYO5jU5cxksopiihGX1yPA0rTiRNBzFC476JPg4Aga0w8Q+fHA10AtM8T+vXAM/mFovFhsi62+M82P4Ljd6caczu+YuyrABjZCygiVLoJPmHS5Z23Zp0tplmLr92Qoxlmt6e/O2YOF+; 5:66F7vKDu9+q2t9zRD3+mzjMZOzFOOuRSXwDBOrEIehIjevoVeWEyHwOjHaiwztRIs6S3NW1ZjdcMuaMDH8cPQCEynzVC0elfmDCPlxVjui8udPMk1Y+lzSBz/TJotvF2srRO0ruoa14TMBkEHdo5jNDlFN0Iv5l6A0S/xYXgIPU=; 24:o+ZljiAG2WOYvVbbgVJLuYhxtW6+cTss2eQXa7SEHta5LF8gGiiK6Dw1Wu4iP48z/dt1P+PCvtr4ykWbPoJLPtu+9x9NQ2ONiWdIf4nPgAo=; 7:a07iLJxa52RH8lK0Chmh47BNyl4deCGBBaI/OeLkHHcmhwn+SNq/03oKntKpqQMtcrslN+EKMbvM3i35qO/iPMHmBu3v9E9Wvkvv30/T6eGBk6RnIWmwPNfl45cmNvxb7W1SfM8Jm7fqu31L9KdW/FGbdfKm2Kb+8g0mh1GDf9m7CXzGIA+tdj7qVWCn7DS0phTL2r/P/MXVGUqRflQD1H/J003yqlGZRHhMU5OdiO01wYiNEQ2sisoD5dfWuRRpDy4J/X/oTF+Z6yxmADRGsg== SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-MS-Exchange-CrossTenant-OriginalArrivalTime: 04 Jul 2016 07:41:01.8480 (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.158.2]; Helo=[az84smr01.freescale.net] X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: BY2PR03MB255 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 --- 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..59f2353 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; +} + +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),