From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from new4-smtp.messagingengine.com (new4-smtp.messagingengine.com [66.111.4.230]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 335687B for ; Wed, 26 Oct 2022 15:34:00 +0000 (UTC) Received: from compute1.internal (compute1.nyi.internal [10.202.2.41]) by mailnew.nyi.internal (Postfix) with ESMTP id 56DD6580419; Wed, 26 Oct 2022 11:33:59 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute1.internal (MEProxy); Wed, 26 Oct 2022 11:33:59 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cerno.tech; h=cc :cc:content-transfer-encoding:content-type:date:date:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:sender:subject:subject:to:to; s=fm3; t=1666798439; x= 1666805639; bh=LKFpDzCajsIwQGw9uWJAx53kPxeNPxieIVd/FDLIbbk=; b=q 7chUDPE7doQSxWXvBm+tgW2sp0QxilaCaC53/529Z0uWB/gFwf7BSaKDjcvFC1eL qhgvjfgABiKyGQnLg8cyHD7fvP8mlaFW/ORuUbS6Yb9MJ86pjUDFIkaG4EQBoaXZ LDNUgCofjKjmxk4mFyaTlvrrZkUA1Y0thkwq8IGmqX1n7yRcG5IiQDHKerbknIj/ V1UM9ot/vlOZOofvVPeTUyy886xr2egcWONQnQ2P12KCa7AMyhs9JOkYuSvgfMxx 84QMrWWHHHWnKIVNyTOFLngs0PUHl9Cx3m6z3SlLCeDrEJRheqPZn5xcT7OxXKuJ EOskMZ7w2fQrCNdvjagsg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:sender:subject:subject:to:to:x-me-proxy:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm3; t=1666798439; x= 1666805639; bh=LKFpDzCajsIwQGw9uWJAx53kPxeNPxieIVd/FDLIbbk=; b=o mwzNKDk5qk+xc/jeCVLQNJY4f60N6Qngoe1W2H7aEn8vgospE3qA+MFce5EXtSvp 9iT+IpkWBNWBT+pWBJCS4oPinAKuq33BQLlt7Lm8ACxfAm7MVS1VjjQ6Czqgc4Gh 9XGy4tfjICxrJ8bfwZM/aBEK70q8ju/T0Nx5+j27Nsyw8qJs4IAGyJxp3/1x/M4x TVZRbG36A/eBv8kL81X+AWyEHI7NKkB9CYiu2Oqn5+2Xqoh0OMku3ubvtV8m7kIz anMg3Z2TFi2fozVkk8R0pEyduiZeJjyZopVmXbgA3r8JOVUdjOPp+NCBJ6LNpj2M 0G4rdGWOYy05VfAPlzDZQ== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvgedrtddvgdeltdcutefuodetggdotefrodftvf curfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfghnecu uegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenuc fjughrpefhfffugggtgffkfhgjvfevofesthekredtredtjeenucfhrhhomhepmhgrgihi mhgvsegtvghrnhhordhtvggthhenucggtffrrghtthgvrhhnpeefudfhgeevhefhfedtue evueeluddutdetuddtvddvgeekheelvefhteekteeihfenucevlhhushhtvghrufhiiigv pedvnecurfgrrhgrmhepmhgrihhlfhhrohhmpehmrgigihhmvgestggvrhhnohdrthgvtg hh X-ME-Proxy: Feedback-ID: i8771445c:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 26 Oct 2022 11:33:58 -0400 (EDT) From: maxime@cerno.tech Date: Wed, 26 Oct 2022 17:33:32 +0200 Subject: [PATCH v6 13/23] drm/modes: Introduce the tv_mode property as a command-line option Precedence: bulk X-Mailing-List: linux-sunxi@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 8bit Message-Id: <20220728-rpi-analog-tv-properties-v6-13-e7792734108f@cerno.tech> References: <20220728-rpi-analog-tv-properties-v6-0-e7792734108f@cerno.tech> In-Reply-To: <20220728-rpi-analog-tv-properties-v6-0-e7792734108f@cerno.tech> To: Karol Herbst , Emma Anholt , Ben Skeggs , Chen-Yu Tsai , Rodrigo Vivi , Maarten Lankhorst , Jani Nikula , Daniel Vetter , Thomas Zimmermann , Tvrtko Ursulin , Samuel Holland , Jernej Skrabec , David Airlie , Maxime Ripard , Joonas Lahtinen , Lyude Paul Cc: linux-sunxi@lists.linux.dev, Maxime Ripard , intel-gfx@lists.freedesktop.org, Phil Elwell , linux-arm-kernel@lists.infradead.org, nouveau@lists.freedesktop.org, Hans de Goede , Dom Cobley , Mateusz Kwiatkowski , dri-devel@lists.freedesktop.org, Dave Stevenson , linux-kernel@vger.kernel.org, Noralf Trønnes , Geert Uytterhoeven X-Mailer: b4 0.11.0-dev-99e3a X-Developer-Signature: v=1; a=openpgp-sha256; l=8374; i=maxime@cerno.tech; h=from:subject:message-id; bh=DEe2U0LmtZRAsNEkdjQQIdxB6MF41xJtymVSw2jpx1I=; b=owGbwMvMwCX2+D1vfrpE4FHG02pJDMmRwW7fW2Lt33x8Vnmsb8Kx91tv8J4+6sX1b/2KfaEGv55o BBfM7ChlYRDjYpAVU2SJETZfEndq1utONr55MHNYmUCGMHBxCsBEssoYGfbKFwRPO+w/hy/p17T32V sSFy4NEVIscNhoLcDH3DxpcSwjQ3/t0zMlZ+xXa30Om1IlwnyO58W3/nvLmFomsNq3HG8s5AEA X-Developer-Key: i=maxime@cerno.tech; a=openpgp; fpr=BE5675C37E818C8B5764241C254BCFC56BF6CE8D Our new tv mode option allows to specify the TV mode from a property. However, it can still be useful, for example to avoid any boot time artifact, to set that property directly from the kernel command line. Let's add some code to allow it, and some unit tests to exercise that code. Signed-off-by: Maxime Ripard --- Changes in v6: - Add a tv_mode_specified field Changes in v4: - Add Documentation of the command-line option to modedb.rst --- Documentation/fb/modedb.rst | 2 + drivers/gpu/drm/drm_modes.c | 37 ++++++++++++-- drivers/gpu/drm/tests/drm_cmdline_parser_test.c | 67 +++++++++++++++++++++++++ include/drm/drm_connector.h | 12 +++++ 4 files changed, 115 insertions(+), 3 deletions(-) diff --git a/Documentation/fb/modedb.rst b/Documentation/fb/modedb.rst index 4d2411e32ebb..5d6361a77f3c 100644 --- a/Documentation/fb/modedb.rst +++ b/Documentation/fb/modedb.rst @@ -65,6 +65,8 @@ Valid options are:: - reflect_y (boolean): Perform an axial symmetry on the Y axis - rotate (integer): Rotate the initial framebuffer by x degrees. Valid values are 0, 90, 180 and 270. + - tv_mode: Analog TV mode. One of "NTSC", "NTSC-443", "NTSC-J", "PAL", + "PAL-M", "PAL-N", or "SECAM". - panel_orientation, one of "normal", "upside_down", "left_side_up", or "right_side_up". For KMS drivers only, this sets the "panel orientation" property on the kms connector as hint for kms users. diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index c826f9583a1d..dc037f7ceb37 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -2133,6 +2133,30 @@ static int drm_mode_parse_panel_orientation(const char *delim, return 0; } +static int drm_mode_parse_tv_mode(const char *delim, + struct drm_cmdline_mode *mode) +{ + const char *value; + int ret; + + if (*delim != '=') + return -EINVAL; + + value = delim + 1; + delim = strchr(value, ','); + if (!delim) + delim = value + strlen(value); + + ret = drm_get_tv_mode_from_name(value, delim - value); + if (ret < 0) + return ret; + + mode->tv_mode_specified = true; + mode->tv_mode = ret; + + return 0; +} + static int drm_mode_parse_cmdline_options(const char *str, bool freestanding, const struct drm_connector *connector, @@ -2202,6 +2226,9 @@ static int drm_mode_parse_cmdline_options(const char *str, } else if (!strncmp(option, "panel_orientation", delim - option)) { if (drm_mode_parse_panel_orientation(delim, mode)) return -EINVAL; + } else if (!strncmp(option, "tv_mode", delim - option)) { + if (drm_mode_parse_tv_mode(delim, mode)) + return -EINVAL; } else { return -EINVAL; } @@ -2230,20 +2257,22 @@ struct drm_named_mode { unsigned int xres; unsigned int yres; unsigned int flags; + unsigned int tv_mode; }; -#define NAMED_MODE(_name, _pclk, _x, _y, _flags) \ +#define NAMED_MODE(_name, _pclk, _x, _y, _flags, _mode) \ { \ .name = _name, \ .pixel_clock_khz = _pclk, \ .xres = _x, \ .yres = _y, \ .flags = _flags, \ + .tv_mode = _mode, \ } static const struct drm_named_mode drm_named_modes[] = { - NAMED_MODE("NTSC", 13500, 720, 480, DRM_MODE_FLAG_INTERLACE), - NAMED_MODE("PAL", 13500, 720, 576, DRM_MODE_FLAG_INTERLACE), + NAMED_MODE("NTSC", 13500, 720, 480, DRM_MODE_FLAG_INTERLACE, DRM_MODE_TV_MODE_NTSC), + NAMED_MODE("PAL", 13500, 720, 576, DRM_MODE_FLAG_INTERLACE, DRM_MODE_TV_MODE_PAL), }; static int drm_mode_parse_cmdline_named_mode(const char *name, @@ -2288,6 +2317,8 @@ static int drm_mode_parse_cmdline_named_mode(const char *name, cmdline_mode->xres = mode->xres; cmdline_mode->yres = mode->yres; cmdline_mode->interlace = !!(mode->flags & DRM_MODE_FLAG_INTERLACE); + cmdline_mode->tv_mode = mode->tv_mode; + cmdline_mode->tv_mode_specified = true; cmdline_mode->specified = true; return 1; diff --git a/drivers/gpu/drm/tests/drm_cmdline_parser_test.c b/drivers/gpu/drm/tests/drm_cmdline_parser_test.c index 34790e7a3760..3e711b83b823 100644 --- a/drivers/gpu/drm/tests/drm_cmdline_parser_test.c +++ b/drivers/gpu/drm/tests/drm_cmdline_parser_test.c @@ -927,6 +927,14 @@ static const struct drm_cmdline_invalid_test drm_cmdline_invalid_tests[] = { .name = "invalid_option", .cmdline = "720x480,test=42", }, + { + .name = "invalid_tv_option", + .cmdline = "720x480i,tv_mode=invalid", + }, + { + .name = "truncated_tv_option", + .cmdline = "720x480i,tv_mode=NTS", + }, }; static void drm_cmdline_invalid_desc(const struct drm_cmdline_invalid_test *t, @@ -937,6 +945,64 @@ static void drm_cmdline_invalid_desc(const struct drm_cmdline_invalid_test *t, KUNIT_ARRAY_PARAM(drm_cmdline_invalid, drm_cmdline_invalid_tests, drm_cmdline_invalid_desc); +struct drm_cmdline_tv_option_test { + const char *name; + const char *cmdline; + struct drm_display_mode *(*mode_fn)(struct drm_device *dev); + enum drm_connector_tv_mode tv_mode; +}; + +static void drm_test_cmdline_tv_options(struct kunit *test) +{ + const struct drm_cmdline_tv_option_test *params = test->param_value; + const struct drm_display_mode *expected_mode = params->mode_fn(NULL); + struct drm_cmdline_mode mode = { }; + + KUNIT_EXPECT_TRUE(test, drm_mode_parse_command_line_for_connector(params->cmdline, + &no_connector, &mode)); + KUNIT_EXPECT_TRUE(test, mode.specified); + KUNIT_EXPECT_EQ(test, mode.xres, expected_mode->hdisplay); + KUNIT_EXPECT_EQ(test, mode.yres, expected_mode->vdisplay); + KUNIT_EXPECT_EQ(test, mode.tv_mode, params->tv_mode); + + KUNIT_EXPECT_FALSE(test, mode.refresh_specified); + + KUNIT_EXPECT_FALSE(test, mode.bpp_specified); + + KUNIT_EXPECT_FALSE(test, mode.rb); + KUNIT_EXPECT_FALSE(test, mode.cvt); + KUNIT_EXPECT_EQ(test, mode.interlace, !!(expected_mode->flags & DRM_MODE_FLAG_INTERLACE)); + KUNIT_EXPECT_FALSE(test, mode.margins); + KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED); +} + +#define TV_OPT_TEST(_opt, _cmdline, _mode_fn) \ + { \ + .name = #_opt, \ + .cmdline = _cmdline, \ + .mode_fn = _mode_fn, \ + .tv_mode = DRM_MODE_TV_MODE_ ## _opt, \ + } + +static const struct drm_cmdline_tv_option_test drm_cmdline_tv_option_tests[] = { + TV_OPT_TEST(NTSC, "720x480i,tv_mode=NTSC", drm_mode_analog_ntsc_480i), + TV_OPT_TEST(NTSC_443, "720x480i,tv_mode=NTSC-443", drm_mode_analog_ntsc_480i), + TV_OPT_TEST(NTSC_J, "720x480i,tv_mode=NTSC-J", drm_mode_analog_ntsc_480i), + TV_OPT_TEST(PAL, "720x576i,tv_mode=PAL", drm_mode_analog_pal_576i), + TV_OPT_TEST(PAL_M, "720x480i,tv_mode=PAL-M", drm_mode_analog_ntsc_480i), + TV_OPT_TEST(PAL_N, "720x576i,tv_mode=PAL-N", drm_mode_analog_pal_576i), + TV_OPT_TEST(SECAM, "720x576i,tv_mode=SECAM", drm_mode_analog_pal_576i), +}; + +static void drm_cmdline_tv_option_desc(const struct drm_cmdline_tv_option_test *t, + char *desc) +{ + sprintf(desc, "%s", t->name); +} +KUNIT_ARRAY_PARAM(drm_cmdline_tv_option, + drm_cmdline_tv_option_tests, + drm_cmdline_tv_option_desc); + static struct kunit_case drm_cmdline_parser_tests[] = { KUNIT_CASE(drm_test_cmdline_force_d_only), KUNIT_CASE(drm_test_cmdline_force_D_only_dvi), @@ -977,6 +1043,7 @@ static struct kunit_case drm_cmdline_parser_tests[] = { KUNIT_CASE(drm_test_cmdline_freestanding_force_e_and_options), KUNIT_CASE(drm_test_cmdline_panel_orientation), KUNIT_CASE_PARAM(drm_test_cmdline_invalid, drm_cmdline_invalid_gen_params), + KUNIT_CASE_PARAM(drm_test_cmdline_tv_options, drm_cmdline_tv_option_gen_params), {} }; diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 276f5cb0f351..2cd39a15bad8 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -1368,6 +1368,18 @@ struct drm_cmdline_mode { * @tv_margins: TV margins to apply to the mode. */ struct drm_connector_tv_margins tv_margins; + + /** + * @tv_mode: TV mode standard. See DRM_MODE_TV_MODE_*. + */ + enum drm_connector_tv_mode tv_mode; + + /** + * @tv_mode_specified: + * + * Did the mode have a preferred TV mode? + */ + bool tv_mode_specified; }; /** -- b4 0.11.0-dev-99e3a From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id A2D64C433FE for ; Wed, 26 Oct 2022 15:35:28 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id EABA510E534; Wed, 26 Oct 2022 15:34:14 +0000 (UTC) Received: from new4-smtp.messagingengine.com (new4-smtp.messagingengine.com [66.111.4.230]) by gabe.freedesktop.org (Postfix) with ESMTPS id 018E310E520; Wed, 26 Oct 2022 15:33:59 +0000 (UTC) Received: from compute1.internal (compute1.nyi.internal [10.202.2.41]) by mailnew.nyi.internal (Postfix) with ESMTP id 56DD6580419; Wed, 26 Oct 2022 11:33:59 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute1.internal (MEProxy); Wed, 26 Oct 2022 11:33:59 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cerno.tech; h=cc :cc:content-transfer-encoding:content-type:date:date:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:sender:subject:subject:to:to; s=fm3; t=1666798439; x= 1666805639; bh=LKFpDzCajsIwQGw9uWJAx53kPxeNPxieIVd/FDLIbbk=; b=q 7chUDPE7doQSxWXvBm+tgW2sp0QxilaCaC53/529Z0uWB/gFwf7BSaKDjcvFC1eL qhgvjfgABiKyGQnLg8cyHD7fvP8mlaFW/ORuUbS6Yb9MJ86pjUDFIkaG4EQBoaXZ LDNUgCofjKjmxk4mFyaTlvrrZkUA1Y0thkwq8IGmqX1n7yRcG5IiQDHKerbknIj/ V1UM9ot/vlOZOofvVPeTUyy886xr2egcWONQnQ2P12KCa7AMyhs9JOkYuSvgfMxx 84QMrWWHHHWnKIVNyTOFLngs0PUHl9Cx3m6z3SlLCeDrEJRheqPZn5xcT7OxXKuJ EOskMZ7w2fQrCNdvjagsg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:sender:subject:subject:to:to:x-me-proxy:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm3; t=1666798439; x= 1666805639; bh=LKFpDzCajsIwQGw9uWJAx53kPxeNPxieIVd/FDLIbbk=; b=o mwzNKDk5qk+xc/jeCVLQNJY4f60N6Qngoe1W2H7aEn8vgospE3qA+MFce5EXtSvp 9iT+IpkWBNWBT+pWBJCS4oPinAKuq33BQLlt7Lm8ACxfAm7MVS1VjjQ6Czqgc4Gh 9XGy4tfjICxrJ8bfwZM/aBEK70q8ju/T0Nx5+j27Nsyw8qJs4IAGyJxp3/1x/M4x TVZRbG36A/eBv8kL81X+AWyEHI7NKkB9CYiu2Oqn5+2Xqoh0OMku3ubvtV8m7kIz anMg3Z2TFi2fozVkk8R0pEyduiZeJjyZopVmXbgA3r8JOVUdjOPp+NCBJ6LNpj2M 0G4rdGWOYy05VfAPlzDZQ== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvgedrtddvgdeltdcutefuodetggdotefrodftvf curfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfghnecu uegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenuc fjughrpefhfffugggtgffkfhgjvfevofesthekredtredtjeenucfhrhhomhepmhgrgihi mhgvsegtvghrnhhordhtvggthhenucggtffrrghtthgvrhhnpeefudfhgeevhefhfedtue evueeluddutdetuddtvddvgeekheelvefhteekteeihfenucevlhhushhtvghrufhiiigv pedvnecurfgrrhgrmhepmhgrihhlfhhrohhmpehmrgigihhmvgestggvrhhnohdrthgvtg hh X-ME-Proxy: Feedback-ID: i8771445c:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 26 Oct 2022 11:33:58 -0400 (EDT) From: maxime@cerno.tech Date: Wed, 26 Oct 2022 17:33:32 +0200 MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 8bit Message-Id: <20220728-rpi-analog-tv-properties-v6-13-e7792734108f@cerno.tech> References: <20220728-rpi-analog-tv-properties-v6-0-e7792734108f@cerno.tech> In-Reply-To: <20220728-rpi-analog-tv-properties-v6-0-e7792734108f@cerno.tech> To: Karol Herbst , Emma Anholt , Ben Skeggs , Chen-Yu Tsai , Rodrigo Vivi , Maarten Lankhorst , Jani Nikula , Daniel Vetter , Thomas Zimmermann , Tvrtko Ursulin , Samuel Holland , Jernej Skrabec , David Airlie , Maxime Ripard , Joonas Lahtinen , Lyude Paul X-Mailer: b4 0.11.0-dev-99e3a X-Developer-Signature: v=1; a=openpgp-sha256; l=8374; i=maxime@cerno.tech; h=from:subject:message-id; bh=DEe2U0LmtZRAsNEkdjQQIdxB6MF41xJtymVSw2jpx1I=; b=owGbwMvMwCX2+D1vfrpE4FHG02pJDMmRwW7fW2Lt33x8Vnmsb8Kx91tv8J4+6sX1b/2KfaEGv55o BBfM7ChlYRDjYpAVU2SJETZfEndq1utONr55MHNYmUCGMHBxCsBEssoYGfbKFwRPO+w/hy/p17T32V sSFy4NEVIscNhoLcDH3DxpcSwjQ3/t0zMlZ+xXa30Om1IlwnyO58W3/nvLmFomsNq3HG8s5AEA X-Developer-Key: i=maxime@cerno.tech; a=openpgp; fpr=BE5675C37E818C8B5764241C254BCFC56BF6CE8D Subject: [Nouveau] [PATCH v6 13/23] drm/modes: Introduce the tv_mode property as a command-line option X-BeenThere: nouveau@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Nouveau development list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Dom Cobley , nouveau@lists.freedesktop.org, intel-gfx@lists.freedesktop.org, linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-sunxi@lists.linux.dev, Hans de Goede , Noralf Trønnes , Geert Uytterhoeven , Maxime Ripard , Mateusz Kwiatkowski , Phil Elwell , linux-arm-kernel@lists.infradead.org Errors-To: nouveau-bounces@lists.freedesktop.org Sender: "Nouveau" Our new tv mode option allows to specify the TV mode from a property. However, it can still be useful, for example to avoid any boot time artifact, to set that property directly from the kernel command line. Let's add some code to allow it, and some unit tests to exercise that code. Signed-off-by: Maxime Ripard --- Changes in v6: - Add a tv_mode_specified field Changes in v4: - Add Documentation of the command-line option to modedb.rst --- Documentation/fb/modedb.rst | 2 + drivers/gpu/drm/drm_modes.c | 37 ++++++++++++-- drivers/gpu/drm/tests/drm_cmdline_parser_test.c | 67 +++++++++++++++++++++++++ include/drm/drm_connector.h | 12 +++++ 4 files changed, 115 insertions(+), 3 deletions(-) diff --git a/Documentation/fb/modedb.rst b/Documentation/fb/modedb.rst index 4d2411e32ebb..5d6361a77f3c 100644 --- a/Documentation/fb/modedb.rst +++ b/Documentation/fb/modedb.rst @@ -65,6 +65,8 @@ Valid options are:: - reflect_y (boolean): Perform an axial symmetry on the Y axis - rotate (integer): Rotate the initial framebuffer by x degrees. Valid values are 0, 90, 180 and 270. + - tv_mode: Analog TV mode. One of "NTSC", "NTSC-443", "NTSC-J", "PAL", + "PAL-M", "PAL-N", or "SECAM". - panel_orientation, one of "normal", "upside_down", "left_side_up", or "right_side_up". For KMS drivers only, this sets the "panel orientation" property on the kms connector as hint for kms users. diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index c826f9583a1d..dc037f7ceb37 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -2133,6 +2133,30 @@ static int drm_mode_parse_panel_orientation(const char *delim, return 0; } +static int drm_mode_parse_tv_mode(const char *delim, + struct drm_cmdline_mode *mode) +{ + const char *value; + int ret; + + if (*delim != '=') + return -EINVAL; + + value = delim + 1; + delim = strchr(value, ','); + if (!delim) + delim = value + strlen(value); + + ret = drm_get_tv_mode_from_name(value, delim - value); + if (ret < 0) + return ret; + + mode->tv_mode_specified = true; + mode->tv_mode = ret; + + return 0; +} + static int drm_mode_parse_cmdline_options(const char *str, bool freestanding, const struct drm_connector *connector, @@ -2202,6 +2226,9 @@ static int drm_mode_parse_cmdline_options(const char *str, } else if (!strncmp(option, "panel_orientation", delim - option)) { if (drm_mode_parse_panel_orientation(delim, mode)) return -EINVAL; + } else if (!strncmp(option, "tv_mode", delim - option)) { + if (drm_mode_parse_tv_mode(delim, mode)) + return -EINVAL; } else { return -EINVAL; } @@ -2230,20 +2257,22 @@ struct drm_named_mode { unsigned int xres; unsigned int yres; unsigned int flags; + unsigned int tv_mode; }; -#define NAMED_MODE(_name, _pclk, _x, _y, _flags) \ +#define NAMED_MODE(_name, _pclk, _x, _y, _flags, _mode) \ { \ .name = _name, \ .pixel_clock_khz = _pclk, \ .xres = _x, \ .yres = _y, \ .flags = _flags, \ + .tv_mode = _mode, \ } static const struct drm_named_mode drm_named_modes[] = { - NAMED_MODE("NTSC", 13500, 720, 480, DRM_MODE_FLAG_INTERLACE), - NAMED_MODE("PAL", 13500, 720, 576, DRM_MODE_FLAG_INTERLACE), + NAMED_MODE("NTSC", 13500, 720, 480, DRM_MODE_FLAG_INTERLACE, DRM_MODE_TV_MODE_NTSC), + NAMED_MODE("PAL", 13500, 720, 576, DRM_MODE_FLAG_INTERLACE, DRM_MODE_TV_MODE_PAL), }; static int drm_mode_parse_cmdline_named_mode(const char *name, @@ -2288,6 +2317,8 @@ static int drm_mode_parse_cmdline_named_mode(const char *name, cmdline_mode->xres = mode->xres; cmdline_mode->yres = mode->yres; cmdline_mode->interlace = !!(mode->flags & DRM_MODE_FLAG_INTERLACE); + cmdline_mode->tv_mode = mode->tv_mode; + cmdline_mode->tv_mode_specified = true; cmdline_mode->specified = true; return 1; diff --git a/drivers/gpu/drm/tests/drm_cmdline_parser_test.c b/drivers/gpu/drm/tests/drm_cmdline_parser_test.c index 34790e7a3760..3e711b83b823 100644 --- a/drivers/gpu/drm/tests/drm_cmdline_parser_test.c +++ b/drivers/gpu/drm/tests/drm_cmdline_parser_test.c @@ -927,6 +927,14 @@ static const struct drm_cmdline_invalid_test drm_cmdline_invalid_tests[] = { .name = "invalid_option", .cmdline = "720x480,test=42", }, + { + .name = "invalid_tv_option", + .cmdline = "720x480i,tv_mode=invalid", + }, + { + .name = "truncated_tv_option", + .cmdline = "720x480i,tv_mode=NTS", + }, }; static void drm_cmdline_invalid_desc(const struct drm_cmdline_invalid_test *t, @@ -937,6 +945,64 @@ static void drm_cmdline_invalid_desc(const struct drm_cmdline_invalid_test *t, KUNIT_ARRAY_PARAM(drm_cmdline_invalid, drm_cmdline_invalid_tests, drm_cmdline_invalid_desc); +struct drm_cmdline_tv_option_test { + const char *name; + const char *cmdline; + struct drm_display_mode *(*mode_fn)(struct drm_device *dev); + enum drm_connector_tv_mode tv_mode; +}; + +static void drm_test_cmdline_tv_options(struct kunit *test) +{ + const struct drm_cmdline_tv_option_test *params = test->param_value; + const struct drm_display_mode *expected_mode = params->mode_fn(NULL); + struct drm_cmdline_mode mode = { }; + + KUNIT_EXPECT_TRUE(test, drm_mode_parse_command_line_for_connector(params->cmdline, + &no_connector, &mode)); + KUNIT_EXPECT_TRUE(test, mode.specified); + KUNIT_EXPECT_EQ(test, mode.xres, expected_mode->hdisplay); + KUNIT_EXPECT_EQ(test, mode.yres, expected_mode->vdisplay); + KUNIT_EXPECT_EQ(test, mode.tv_mode, params->tv_mode); + + KUNIT_EXPECT_FALSE(test, mode.refresh_specified); + + KUNIT_EXPECT_FALSE(test, mode.bpp_specified); + + KUNIT_EXPECT_FALSE(test, mode.rb); + KUNIT_EXPECT_FALSE(test, mode.cvt); + KUNIT_EXPECT_EQ(test, mode.interlace, !!(expected_mode->flags & DRM_MODE_FLAG_INTERLACE)); + KUNIT_EXPECT_FALSE(test, mode.margins); + KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED); +} + +#define TV_OPT_TEST(_opt, _cmdline, _mode_fn) \ + { \ + .name = #_opt, \ + .cmdline = _cmdline, \ + .mode_fn = _mode_fn, \ + .tv_mode = DRM_MODE_TV_MODE_ ## _opt, \ + } + +static const struct drm_cmdline_tv_option_test drm_cmdline_tv_option_tests[] = { + TV_OPT_TEST(NTSC, "720x480i,tv_mode=NTSC", drm_mode_analog_ntsc_480i), + TV_OPT_TEST(NTSC_443, "720x480i,tv_mode=NTSC-443", drm_mode_analog_ntsc_480i), + TV_OPT_TEST(NTSC_J, "720x480i,tv_mode=NTSC-J", drm_mode_analog_ntsc_480i), + TV_OPT_TEST(PAL, "720x576i,tv_mode=PAL", drm_mode_analog_pal_576i), + TV_OPT_TEST(PAL_M, "720x480i,tv_mode=PAL-M", drm_mode_analog_ntsc_480i), + TV_OPT_TEST(PAL_N, "720x576i,tv_mode=PAL-N", drm_mode_analog_pal_576i), + TV_OPT_TEST(SECAM, "720x576i,tv_mode=SECAM", drm_mode_analog_pal_576i), +}; + +static void drm_cmdline_tv_option_desc(const struct drm_cmdline_tv_option_test *t, + char *desc) +{ + sprintf(desc, "%s", t->name); +} +KUNIT_ARRAY_PARAM(drm_cmdline_tv_option, + drm_cmdline_tv_option_tests, + drm_cmdline_tv_option_desc); + static struct kunit_case drm_cmdline_parser_tests[] = { KUNIT_CASE(drm_test_cmdline_force_d_only), KUNIT_CASE(drm_test_cmdline_force_D_only_dvi), @@ -977,6 +1043,7 @@ static struct kunit_case drm_cmdline_parser_tests[] = { KUNIT_CASE(drm_test_cmdline_freestanding_force_e_and_options), KUNIT_CASE(drm_test_cmdline_panel_orientation), KUNIT_CASE_PARAM(drm_test_cmdline_invalid, drm_cmdline_invalid_gen_params), + KUNIT_CASE_PARAM(drm_test_cmdline_tv_options, drm_cmdline_tv_option_gen_params), {} }; diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 276f5cb0f351..2cd39a15bad8 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -1368,6 +1368,18 @@ struct drm_cmdline_mode { * @tv_margins: TV margins to apply to the mode. */ struct drm_connector_tv_margins tv_margins; + + /** + * @tv_mode: TV mode standard. See DRM_MODE_TV_MODE_*. + */ + enum drm_connector_tv_mode tv_mode; + + /** + * @tv_mode_specified: + * + * Did the mode have a preferred TV mode? + */ + bool tv_mode_specified; }; /** -- b4 0.11.0-dev-99e3a From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 4865AFA373E for ; Wed, 26 Oct 2022 15:35:46 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id D265610E549; Wed, 26 Oct 2022 15:34:17 +0000 (UTC) Received: from new4-smtp.messagingengine.com (new4-smtp.messagingengine.com [66.111.4.230]) by gabe.freedesktop.org (Postfix) with ESMTPS id 018E310E520; Wed, 26 Oct 2022 15:33:59 +0000 (UTC) Received: from compute1.internal (compute1.nyi.internal [10.202.2.41]) by mailnew.nyi.internal (Postfix) with ESMTP id 56DD6580419; Wed, 26 Oct 2022 11:33:59 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute1.internal (MEProxy); Wed, 26 Oct 2022 11:33:59 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cerno.tech; h=cc :cc:content-transfer-encoding:content-type:date:date:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:sender:subject:subject:to:to; s=fm3; t=1666798439; x= 1666805639; bh=LKFpDzCajsIwQGw9uWJAx53kPxeNPxieIVd/FDLIbbk=; b=q 7chUDPE7doQSxWXvBm+tgW2sp0QxilaCaC53/529Z0uWB/gFwf7BSaKDjcvFC1eL qhgvjfgABiKyGQnLg8cyHD7fvP8mlaFW/ORuUbS6Yb9MJ86pjUDFIkaG4EQBoaXZ LDNUgCofjKjmxk4mFyaTlvrrZkUA1Y0thkwq8IGmqX1n7yRcG5IiQDHKerbknIj/ V1UM9ot/vlOZOofvVPeTUyy886xr2egcWONQnQ2P12KCa7AMyhs9JOkYuSvgfMxx 84QMrWWHHHWnKIVNyTOFLngs0PUHl9Cx3m6z3SlLCeDrEJRheqPZn5xcT7OxXKuJ EOskMZ7w2fQrCNdvjagsg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:sender:subject:subject:to:to:x-me-proxy:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm3; t=1666798439; x= 1666805639; bh=LKFpDzCajsIwQGw9uWJAx53kPxeNPxieIVd/FDLIbbk=; b=o mwzNKDk5qk+xc/jeCVLQNJY4f60N6Qngoe1W2H7aEn8vgospE3qA+MFce5EXtSvp 9iT+IpkWBNWBT+pWBJCS4oPinAKuq33BQLlt7Lm8ACxfAm7MVS1VjjQ6Czqgc4Gh 9XGy4tfjICxrJ8bfwZM/aBEK70q8ju/T0Nx5+j27Nsyw8qJs4IAGyJxp3/1x/M4x TVZRbG36A/eBv8kL81X+AWyEHI7NKkB9CYiu2Oqn5+2Xqoh0OMku3ubvtV8m7kIz anMg3Z2TFi2fozVkk8R0pEyduiZeJjyZopVmXbgA3r8JOVUdjOPp+NCBJ6LNpj2M 0G4rdGWOYy05VfAPlzDZQ== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvgedrtddvgdeltdcutefuodetggdotefrodftvf curfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfghnecu uegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenuc fjughrpefhfffugggtgffkfhgjvfevofesthekredtredtjeenucfhrhhomhepmhgrgihi mhgvsegtvghrnhhordhtvggthhenucggtffrrghtthgvrhhnpeefudfhgeevhefhfedtue evueeluddutdetuddtvddvgeekheelvefhteekteeihfenucevlhhushhtvghrufhiiigv pedvnecurfgrrhgrmhepmhgrihhlfhhrohhmpehmrgigihhmvgestggvrhhnohdrthgvtg hh X-ME-Proxy: Feedback-ID: i8771445c:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 26 Oct 2022 11:33:58 -0400 (EDT) From: maxime@cerno.tech Date: Wed, 26 Oct 2022 17:33:32 +0200 Subject: [PATCH v6 13/23] drm/modes: Introduce the tv_mode property as a command-line option MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 8bit Message-Id: <20220728-rpi-analog-tv-properties-v6-13-e7792734108f@cerno.tech> References: <20220728-rpi-analog-tv-properties-v6-0-e7792734108f@cerno.tech> In-Reply-To: <20220728-rpi-analog-tv-properties-v6-0-e7792734108f@cerno.tech> To: Karol Herbst , Emma Anholt , Ben Skeggs , Chen-Yu Tsai , Rodrigo Vivi , Maarten Lankhorst , Jani Nikula , Daniel Vetter , Thomas Zimmermann , Tvrtko Ursulin , Samuel Holland , Jernej Skrabec , David Airlie , Maxime Ripard , Joonas Lahtinen , Lyude Paul X-Mailer: b4 0.11.0-dev-99e3a X-Developer-Signature: v=1; a=openpgp-sha256; l=8374; i=maxime@cerno.tech; h=from:subject:message-id; bh=DEe2U0LmtZRAsNEkdjQQIdxB6MF41xJtymVSw2jpx1I=; b=owGbwMvMwCX2+D1vfrpE4FHG02pJDMmRwW7fW2Lt33x8Vnmsb8Kx91tv8J4+6sX1b/2KfaEGv55o BBfM7ChlYRDjYpAVU2SJETZfEndq1utONr55MHNYmUCGMHBxCsBEssoYGfbKFwRPO+w/hy/p17T32V sSFy4NEVIscNhoLcDH3DxpcSwjQ3/t0zMlZ+xXa30Om1IlwnyO58W3/nvLmFomsNq3HG8s5AEA X-Developer-Key: i=maxime@cerno.tech; a=openpgp; fpr=BE5675C37E818C8B5764241C254BCFC56BF6CE8D X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Dom Cobley , Dave Stevenson , nouveau@lists.freedesktop.org, intel-gfx@lists.freedesktop.org, linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-sunxi@lists.linux.dev, Hans de Goede , Noralf Trønnes , Geert Uytterhoeven , Maxime Ripard , Mateusz Kwiatkowski , Phil Elwell , linux-arm-kernel@lists.infradead.org Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" Our new tv mode option allows to specify the TV mode from a property. However, it can still be useful, for example to avoid any boot time artifact, to set that property directly from the kernel command line. Let's add some code to allow it, and some unit tests to exercise that code. Signed-off-by: Maxime Ripard --- Changes in v6: - Add a tv_mode_specified field Changes in v4: - Add Documentation of the command-line option to modedb.rst --- Documentation/fb/modedb.rst | 2 + drivers/gpu/drm/drm_modes.c | 37 ++++++++++++-- drivers/gpu/drm/tests/drm_cmdline_parser_test.c | 67 +++++++++++++++++++++++++ include/drm/drm_connector.h | 12 +++++ 4 files changed, 115 insertions(+), 3 deletions(-) diff --git a/Documentation/fb/modedb.rst b/Documentation/fb/modedb.rst index 4d2411e32ebb..5d6361a77f3c 100644 --- a/Documentation/fb/modedb.rst +++ b/Documentation/fb/modedb.rst @@ -65,6 +65,8 @@ Valid options are:: - reflect_y (boolean): Perform an axial symmetry on the Y axis - rotate (integer): Rotate the initial framebuffer by x degrees. Valid values are 0, 90, 180 and 270. + - tv_mode: Analog TV mode. One of "NTSC", "NTSC-443", "NTSC-J", "PAL", + "PAL-M", "PAL-N", or "SECAM". - panel_orientation, one of "normal", "upside_down", "left_side_up", or "right_side_up". For KMS drivers only, this sets the "panel orientation" property on the kms connector as hint for kms users. diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index c826f9583a1d..dc037f7ceb37 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -2133,6 +2133,30 @@ static int drm_mode_parse_panel_orientation(const char *delim, return 0; } +static int drm_mode_parse_tv_mode(const char *delim, + struct drm_cmdline_mode *mode) +{ + const char *value; + int ret; + + if (*delim != '=') + return -EINVAL; + + value = delim + 1; + delim = strchr(value, ','); + if (!delim) + delim = value + strlen(value); + + ret = drm_get_tv_mode_from_name(value, delim - value); + if (ret < 0) + return ret; + + mode->tv_mode_specified = true; + mode->tv_mode = ret; + + return 0; +} + static int drm_mode_parse_cmdline_options(const char *str, bool freestanding, const struct drm_connector *connector, @@ -2202,6 +2226,9 @@ static int drm_mode_parse_cmdline_options(const char *str, } else if (!strncmp(option, "panel_orientation", delim - option)) { if (drm_mode_parse_panel_orientation(delim, mode)) return -EINVAL; + } else if (!strncmp(option, "tv_mode", delim - option)) { + if (drm_mode_parse_tv_mode(delim, mode)) + return -EINVAL; } else { return -EINVAL; } @@ -2230,20 +2257,22 @@ struct drm_named_mode { unsigned int xres; unsigned int yres; unsigned int flags; + unsigned int tv_mode; }; -#define NAMED_MODE(_name, _pclk, _x, _y, _flags) \ +#define NAMED_MODE(_name, _pclk, _x, _y, _flags, _mode) \ { \ .name = _name, \ .pixel_clock_khz = _pclk, \ .xres = _x, \ .yres = _y, \ .flags = _flags, \ + .tv_mode = _mode, \ } static const struct drm_named_mode drm_named_modes[] = { - NAMED_MODE("NTSC", 13500, 720, 480, DRM_MODE_FLAG_INTERLACE), - NAMED_MODE("PAL", 13500, 720, 576, DRM_MODE_FLAG_INTERLACE), + NAMED_MODE("NTSC", 13500, 720, 480, DRM_MODE_FLAG_INTERLACE, DRM_MODE_TV_MODE_NTSC), + NAMED_MODE("PAL", 13500, 720, 576, DRM_MODE_FLAG_INTERLACE, DRM_MODE_TV_MODE_PAL), }; static int drm_mode_parse_cmdline_named_mode(const char *name, @@ -2288,6 +2317,8 @@ static int drm_mode_parse_cmdline_named_mode(const char *name, cmdline_mode->xres = mode->xres; cmdline_mode->yres = mode->yres; cmdline_mode->interlace = !!(mode->flags & DRM_MODE_FLAG_INTERLACE); + cmdline_mode->tv_mode = mode->tv_mode; + cmdline_mode->tv_mode_specified = true; cmdline_mode->specified = true; return 1; diff --git a/drivers/gpu/drm/tests/drm_cmdline_parser_test.c b/drivers/gpu/drm/tests/drm_cmdline_parser_test.c index 34790e7a3760..3e711b83b823 100644 --- a/drivers/gpu/drm/tests/drm_cmdline_parser_test.c +++ b/drivers/gpu/drm/tests/drm_cmdline_parser_test.c @@ -927,6 +927,14 @@ static const struct drm_cmdline_invalid_test drm_cmdline_invalid_tests[] = { .name = "invalid_option", .cmdline = "720x480,test=42", }, + { + .name = "invalid_tv_option", + .cmdline = "720x480i,tv_mode=invalid", + }, + { + .name = "truncated_tv_option", + .cmdline = "720x480i,tv_mode=NTS", + }, }; static void drm_cmdline_invalid_desc(const struct drm_cmdline_invalid_test *t, @@ -937,6 +945,64 @@ static void drm_cmdline_invalid_desc(const struct drm_cmdline_invalid_test *t, KUNIT_ARRAY_PARAM(drm_cmdline_invalid, drm_cmdline_invalid_tests, drm_cmdline_invalid_desc); +struct drm_cmdline_tv_option_test { + const char *name; + const char *cmdline; + struct drm_display_mode *(*mode_fn)(struct drm_device *dev); + enum drm_connector_tv_mode tv_mode; +}; + +static void drm_test_cmdline_tv_options(struct kunit *test) +{ + const struct drm_cmdline_tv_option_test *params = test->param_value; + const struct drm_display_mode *expected_mode = params->mode_fn(NULL); + struct drm_cmdline_mode mode = { }; + + KUNIT_EXPECT_TRUE(test, drm_mode_parse_command_line_for_connector(params->cmdline, + &no_connector, &mode)); + KUNIT_EXPECT_TRUE(test, mode.specified); + KUNIT_EXPECT_EQ(test, mode.xres, expected_mode->hdisplay); + KUNIT_EXPECT_EQ(test, mode.yres, expected_mode->vdisplay); + KUNIT_EXPECT_EQ(test, mode.tv_mode, params->tv_mode); + + KUNIT_EXPECT_FALSE(test, mode.refresh_specified); + + KUNIT_EXPECT_FALSE(test, mode.bpp_specified); + + KUNIT_EXPECT_FALSE(test, mode.rb); + KUNIT_EXPECT_FALSE(test, mode.cvt); + KUNIT_EXPECT_EQ(test, mode.interlace, !!(expected_mode->flags & DRM_MODE_FLAG_INTERLACE)); + KUNIT_EXPECT_FALSE(test, mode.margins); + KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED); +} + +#define TV_OPT_TEST(_opt, _cmdline, _mode_fn) \ + { \ + .name = #_opt, \ + .cmdline = _cmdline, \ + .mode_fn = _mode_fn, \ + .tv_mode = DRM_MODE_TV_MODE_ ## _opt, \ + } + +static const struct drm_cmdline_tv_option_test drm_cmdline_tv_option_tests[] = { + TV_OPT_TEST(NTSC, "720x480i,tv_mode=NTSC", drm_mode_analog_ntsc_480i), + TV_OPT_TEST(NTSC_443, "720x480i,tv_mode=NTSC-443", drm_mode_analog_ntsc_480i), + TV_OPT_TEST(NTSC_J, "720x480i,tv_mode=NTSC-J", drm_mode_analog_ntsc_480i), + TV_OPT_TEST(PAL, "720x576i,tv_mode=PAL", drm_mode_analog_pal_576i), + TV_OPT_TEST(PAL_M, "720x480i,tv_mode=PAL-M", drm_mode_analog_ntsc_480i), + TV_OPT_TEST(PAL_N, "720x576i,tv_mode=PAL-N", drm_mode_analog_pal_576i), + TV_OPT_TEST(SECAM, "720x576i,tv_mode=SECAM", drm_mode_analog_pal_576i), +}; + +static void drm_cmdline_tv_option_desc(const struct drm_cmdline_tv_option_test *t, + char *desc) +{ + sprintf(desc, "%s", t->name); +} +KUNIT_ARRAY_PARAM(drm_cmdline_tv_option, + drm_cmdline_tv_option_tests, + drm_cmdline_tv_option_desc); + static struct kunit_case drm_cmdline_parser_tests[] = { KUNIT_CASE(drm_test_cmdline_force_d_only), KUNIT_CASE(drm_test_cmdline_force_D_only_dvi), @@ -977,6 +1043,7 @@ static struct kunit_case drm_cmdline_parser_tests[] = { KUNIT_CASE(drm_test_cmdline_freestanding_force_e_and_options), KUNIT_CASE(drm_test_cmdline_panel_orientation), KUNIT_CASE_PARAM(drm_test_cmdline_invalid, drm_cmdline_invalid_gen_params), + KUNIT_CASE_PARAM(drm_test_cmdline_tv_options, drm_cmdline_tv_option_gen_params), {} }; diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 276f5cb0f351..2cd39a15bad8 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -1368,6 +1368,18 @@ struct drm_cmdline_mode { * @tv_margins: TV margins to apply to the mode. */ struct drm_connector_tv_margins tv_margins; + + /** + * @tv_mode: TV mode standard. See DRM_MODE_TV_MODE_*. + */ + enum drm_connector_tv_mode tv_mode; + + /** + * @tv_mode_specified: + * + * Did the mode have a preferred TV mode? + */ + bool tv_mode_specified; }; /** -- b4 0.11.0-dev-99e3a From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 30609C38A2D for ; Wed, 26 Oct 2022 15:35:23 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 74F1F10E533; Wed, 26 Oct 2022 15:34:10 +0000 (UTC) Received: from new4-smtp.messagingengine.com (new4-smtp.messagingengine.com [66.111.4.230]) by gabe.freedesktop.org (Postfix) with ESMTPS id 018E310E520; Wed, 26 Oct 2022 15:33:59 +0000 (UTC) Received: from compute1.internal (compute1.nyi.internal [10.202.2.41]) by mailnew.nyi.internal (Postfix) with ESMTP id 56DD6580419; Wed, 26 Oct 2022 11:33:59 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute1.internal (MEProxy); Wed, 26 Oct 2022 11:33:59 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cerno.tech; h=cc :cc:content-transfer-encoding:content-type:date:date:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:sender:subject:subject:to:to; s=fm3; t=1666798439; x= 1666805639; bh=LKFpDzCajsIwQGw9uWJAx53kPxeNPxieIVd/FDLIbbk=; b=q 7chUDPE7doQSxWXvBm+tgW2sp0QxilaCaC53/529Z0uWB/gFwf7BSaKDjcvFC1eL qhgvjfgABiKyGQnLg8cyHD7fvP8mlaFW/ORuUbS6Yb9MJ86pjUDFIkaG4EQBoaXZ LDNUgCofjKjmxk4mFyaTlvrrZkUA1Y0thkwq8IGmqX1n7yRcG5IiQDHKerbknIj/ V1UM9ot/vlOZOofvVPeTUyy886xr2egcWONQnQ2P12KCa7AMyhs9JOkYuSvgfMxx 84QMrWWHHHWnKIVNyTOFLngs0PUHl9Cx3m6z3SlLCeDrEJRheqPZn5xcT7OxXKuJ EOskMZ7w2fQrCNdvjagsg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:sender:subject:subject:to:to:x-me-proxy:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm3; t=1666798439; x= 1666805639; bh=LKFpDzCajsIwQGw9uWJAx53kPxeNPxieIVd/FDLIbbk=; b=o mwzNKDk5qk+xc/jeCVLQNJY4f60N6Qngoe1W2H7aEn8vgospE3qA+MFce5EXtSvp 9iT+IpkWBNWBT+pWBJCS4oPinAKuq33BQLlt7Lm8ACxfAm7MVS1VjjQ6Czqgc4Gh 9XGy4tfjICxrJ8bfwZM/aBEK70q8ju/T0Nx5+j27Nsyw8qJs4IAGyJxp3/1x/M4x TVZRbG36A/eBv8kL81X+AWyEHI7NKkB9CYiu2Oqn5+2Xqoh0OMku3ubvtV8m7kIz anMg3Z2TFi2fozVkk8R0pEyduiZeJjyZopVmXbgA3r8JOVUdjOPp+NCBJ6LNpj2M 0G4rdGWOYy05VfAPlzDZQ== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvgedrtddvgdeltdcutefuodetggdotefrodftvf curfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfghnecu uegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenuc fjughrpefhfffugggtgffkfhgjvfevofesthekredtredtjeenucfhrhhomhepmhgrgihi mhgvsegtvghrnhhordhtvggthhenucggtffrrghtthgvrhhnpeefudfhgeevhefhfedtue evueeluddutdetuddtvddvgeekheelvefhteekteeihfenucevlhhushhtvghrufhiiigv pedvnecurfgrrhgrmhepmhgrihhlfhhrohhmpehmrgigihhmvgestggvrhhnohdrthgvtg hh X-ME-Proxy: Feedback-ID: i8771445c:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 26 Oct 2022 11:33:58 -0400 (EDT) From: maxime@cerno.tech Date: Wed, 26 Oct 2022 17:33:32 +0200 MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 8bit Message-Id: <20220728-rpi-analog-tv-properties-v6-13-e7792734108f@cerno.tech> References: <20220728-rpi-analog-tv-properties-v6-0-e7792734108f@cerno.tech> In-Reply-To: <20220728-rpi-analog-tv-properties-v6-0-e7792734108f@cerno.tech> To: Karol Herbst , Emma Anholt , Ben Skeggs , Chen-Yu Tsai , Rodrigo Vivi , Maarten Lankhorst , Jani Nikula , Daniel Vetter , Thomas Zimmermann , Tvrtko Ursulin , Samuel Holland , Jernej Skrabec , David Airlie , Maxime Ripard , Joonas Lahtinen , Lyude Paul X-Mailer: b4 0.11.0-dev-99e3a X-Developer-Signature: v=1; a=openpgp-sha256; l=8374; i=maxime@cerno.tech; h=from:subject:message-id; bh=DEe2U0LmtZRAsNEkdjQQIdxB6MF41xJtymVSw2jpx1I=; b=owGbwMvMwCX2+D1vfrpE4FHG02pJDMmRwW7fW2Lt33x8Vnmsb8Kx91tv8J4+6sX1b/2KfaEGv55o BBfM7ChlYRDjYpAVU2SJETZfEndq1utONr55MHNYmUCGMHBxCsBEssoYGfbKFwRPO+w/hy/p17T32V sSFy4NEVIscNhoLcDH3DxpcSwjQ3/t0zMlZ+xXa30Om1IlwnyO58W3/nvLmFomsNq3HG8s5AEA X-Developer-Key: i=maxime@cerno.tech; a=openpgp; fpr=BE5675C37E818C8B5764241C254BCFC56BF6CE8D Subject: [Intel-gfx] [PATCH v6 13/23] drm/modes: Introduce the tv_mode property as a command-line option X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Dom Cobley , Dave Stevenson , nouveau@lists.freedesktop.org, intel-gfx@lists.freedesktop.org, linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-sunxi@lists.linux.dev, Hans de Goede , Noralf Trønnes , Geert Uytterhoeven , Maxime Ripard , Mateusz Kwiatkowski , Phil Elwell , linux-arm-kernel@lists.infradead.org Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" Our new tv mode option allows to specify the TV mode from a property. However, it can still be useful, for example to avoid any boot time artifact, to set that property directly from the kernel command line. Let's add some code to allow it, and some unit tests to exercise that code. Signed-off-by: Maxime Ripard --- Changes in v6: - Add a tv_mode_specified field Changes in v4: - Add Documentation of the command-line option to modedb.rst --- Documentation/fb/modedb.rst | 2 + drivers/gpu/drm/drm_modes.c | 37 ++++++++++++-- drivers/gpu/drm/tests/drm_cmdline_parser_test.c | 67 +++++++++++++++++++++++++ include/drm/drm_connector.h | 12 +++++ 4 files changed, 115 insertions(+), 3 deletions(-) diff --git a/Documentation/fb/modedb.rst b/Documentation/fb/modedb.rst index 4d2411e32ebb..5d6361a77f3c 100644 --- a/Documentation/fb/modedb.rst +++ b/Documentation/fb/modedb.rst @@ -65,6 +65,8 @@ Valid options are:: - reflect_y (boolean): Perform an axial symmetry on the Y axis - rotate (integer): Rotate the initial framebuffer by x degrees. Valid values are 0, 90, 180 and 270. + - tv_mode: Analog TV mode. One of "NTSC", "NTSC-443", "NTSC-J", "PAL", + "PAL-M", "PAL-N", or "SECAM". - panel_orientation, one of "normal", "upside_down", "left_side_up", or "right_side_up". For KMS drivers only, this sets the "panel orientation" property on the kms connector as hint for kms users. diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index c826f9583a1d..dc037f7ceb37 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -2133,6 +2133,30 @@ static int drm_mode_parse_panel_orientation(const char *delim, return 0; } +static int drm_mode_parse_tv_mode(const char *delim, + struct drm_cmdline_mode *mode) +{ + const char *value; + int ret; + + if (*delim != '=') + return -EINVAL; + + value = delim + 1; + delim = strchr(value, ','); + if (!delim) + delim = value + strlen(value); + + ret = drm_get_tv_mode_from_name(value, delim - value); + if (ret < 0) + return ret; + + mode->tv_mode_specified = true; + mode->tv_mode = ret; + + return 0; +} + static int drm_mode_parse_cmdline_options(const char *str, bool freestanding, const struct drm_connector *connector, @@ -2202,6 +2226,9 @@ static int drm_mode_parse_cmdline_options(const char *str, } else if (!strncmp(option, "panel_orientation", delim - option)) { if (drm_mode_parse_panel_orientation(delim, mode)) return -EINVAL; + } else if (!strncmp(option, "tv_mode", delim - option)) { + if (drm_mode_parse_tv_mode(delim, mode)) + return -EINVAL; } else { return -EINVAL; } @@ -2230,20 +2257,22 @@ struct drm_named_mode { unsigned int xres; unsigned int yres; unsigned int flags; + unsigned int tv_mode; }; -#define NAMED_MODE(_name, _pclk, _x, _y, _flags) \ +#define NAMED_MODE(_name, _pclk, _x, _y, _flags, _mode) \ { \ .name = _name, \ .pixel_clock_khz = _pclk, \ .xres = _x, \ .yres = _y, \ .flags = _flags, \ + .tv_mode = _mode, \ } static const struct drm_named_mode drm_named_modes[] = { - NAMED_MODE("NTSC", 13500, 720, 480, DRM_MODE_FLAG_INTERLACE), - NAMED_MODE("PAL", 13500, 720, 576, DRM_MODE_FLAG_INTERLACE), + NAMED_MODE("NTSC", 13500, 720, 480, DRM_MODE_FLAG_INTERLACE, DRM_MODE_TV_MODE_NTSC), + NAMED_MODE("PAL", 13500, 720, 576, DRM_MODE_FLAG_INTERLACE, DRM_MODE_TV_MODE_PAL), }; static int drm_mode_parse_cmdline_named_mode(const char *name, @@ -2288,6 +2317,8 @@ static int drm_mode_parse_cmdline_named_mode(const char *name, cmdline_mode->xres = mode->xres; cmdline_mode->yres = mode->yres; cmdline_mode->interlace = !!(mode->flags & DRM_MODE_FLAG_INTERLACE); + cmdline_mode->tv_mode = mode->tv_mode; + cmdline_mode->tv_mode_specified = true; cmdline_mode->specified = true; return 1; diff --git a/drivers/gpu/drm/tests/drm_cmdline_parser_test.c b/drivers/gpu/drm/tests/drm_cmdline_parser_test.c index 34790e7a3760..3e711b83b823 100644 --- a/drivers/gpu/drm/tests/drm_cmdline_parser_test.c +++ b/drivers/gpu/drm/tests/drm_cmdline_parser_test.c @@ -927,6 +927,14 @@ static const struct drm_cmdline_invalid_test drm_cmdline_invalid_tests[] = { .name = "invalid_option", .cmdline = "720x480,test=42", }, + { + .name = "invalid_tv_option", + .cmdline = "720x480i,tv_mode=invalid", + }, + { + .name = "truncated_tv_option", + .cmdline = "720x480i,tv_mode=NTS", + }, }; static void drm_cmdline_invalid_desc(const struct drm_cmdline_invalid_test *t, @@ -937,6 +945,64 @@ static void drm_cmdline_invalid_desc(const struct drm_cmdline_invalid_test *t, KUNIT_ARRAY_PARAM(drm_cmdline_invalid, drm_cmdline_invalid_tests, drm_cmdline_invalid_desc); +struct drm_cmdline_tv_option_test { + const char *name; + const char *cmdline; + struct drm_display_mode *(*mode_fn)(struct drm_device *dev); + enum drm_connector_tv_mode tv_mode; +}; + +static void drm_test_cmdline_tv_options(struct kunit *test) +{ + const struct drm_cmdline_tv_option_test *params = test->param_value; + const struct drm_display_mode *expected_mode = params->mode_fn(NULL); + struct drm_cmdline_mode mode = { }; + + KUNIT_EXPECT_TRUE(test, drm_mode_parse_command_line_for_connector(params->cmdline, + &no_connector, &mode)); + KUNIT_EXPECT_TRUE(test, mode.specified); + KUNIT_EXPECT_EQ(test, mode.xres, expected_mode->hdisplay); + KUNIT_EXPECT_EQ(test, mode.yres, expected_mode->vdisplay); + KUNIT_EXPECT_EQ(test, mode.tv_mode, params->tv_mode); + + KUNIT_EXPECT_FALSE(test, mode.refresh_specified); + + KUNIT_EXPECT_FALSE(test, mode.bpp_specified); + + KUNIT_EXPECT_FALSE(test, mode.rb); + KUNIT_EXPECT_FALSE(test, mode.cvt); + KUNIT_EXPECT_EQ(test, mode.interlace, !!(expected_mode->flags & DRM_MODE_FLAG_INTERLACE)); + KUNIT_EXPECT_FALSE(test, mode.margins); + KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED); +} + +#define TV_OPT_TEST(_opt, _cmdline, _mode_fn) \ + { \ + .name = #_opt, \ + .cmdline = _cmdline, \ + .mode_fn = _mode_fn, \ + .tv_mode = DRM_MODE_TV_MODE_ ## _opt, \ + } + +static const struct drm_cmdline_tv_option_test drm_cmdline_tv_option_tests[] = { + TV_OPT_TEST(NTSC, "720x480i,tv_mode=NTSC", drm_mode_analog_ntsc_480i), + TV_OPT_TEST(NTSC_443, "720x480i,tv_mode=NTSC-443", drm_mode_analog_ntsc_480i), + TV_OPT_TEST(NTSC_J, "720x480i,tv_mode=NTSC-J", drm_mode_analog_ntsc_480i), + TV_OPT_TEST(PAL, "720x576i,tv_mode=PAL", drm_mode_analog_pal_576i), + TV_OPT_TEST(PAL_M, "720x480i,tv_mode=PAL-M", drm_mode_analog_ntsc_480i), + TV_OPT_TEST(PAL_N, "720x576i,tv_mode=PAL-N", drm_mode_analog_pal_576i), + TV_OPT_TEST(SECAM, "720x576i,tv_mode=SECAM", drm_mode_analog_pal_576i), +}; + +static void drm_cmdline_tv_option_desc(const struct drm_cmdline_tv_option_test *t, + char *desc) +{ + sprintf(desc, "%s", t->name); +} +KUNIT_ARRAY_PARAM(drm_cmdline_tv_option, + drm_cmdline_tv_option_tests, + drm_cmdline_tv_option_desc); + static struct kunit_case drm_cmdline_parser_tests[] = { KUNIT_CASE(drm_test_cmdline_force_d_only), KUNIT_CASE(drm_test_cmdline_force_D_only_dvi), @@ -977,6 +1043,7 @@ static struct kunit_case drm_cmdline_parser_tests[] = { KUNIT_CASE(drm_test_cmdline_freestanding_force_e_and_options), KUNIT_CASE(drm_test_cmdline_panel_orientation), KUNIT_CASE_PARAM(drm_test_cmdline_invalid, drm_cmdline_invalid_gen_params), + KUNIT_CASE_PARAM(drm_test_cmdline_tv_options, drm_cmdline_tv_option_gen_params), {} }; diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 276f5cb0f351..2cd39a15bad8 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -1368,6 +1368,18 @@ struct drm_cmdline_mode { * @tv_margins: TV margins to apply to the mode. */ struct drm_connector_tv_margins tv_margins; + + /** + * @tv_mode: TV mode standard. See DRM_MODE_TV_MODE_*. + */ + enum drm_connector_tv_mode tv_mode; + + /** + * @tv_mode_specified: + * + * Did the mode have a preferred TV mode? + */ + bool tv_mode_specified; }; /** -- b4 0.11.0-dev-99e3a From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 79189C433FE for ; Wed, 26 Oct 2022 15:42:18 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:Cc:To:In-Reply-To:References:Message-Id :MIME-Version:Subject:Date:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=Cu8C/UeSzDoIAhzbg4mbebJixmrmucybESkvhD+7g00=; b=Bajbo2poPUvk5C KQFEeEYI5d6h0YGWj8/+a7VlNNeMcYp97eL0d2JWjPzxZgWOPDjebMI7UaaitG87fayY+krXGYFha lzrJM5OGu7LfQKgIRBs8wT8HGis2+pGrH2TdUbSYZI+z52vaxNsofLLX2jWQL8uqnXDcUuPZDjJI+ LJptFaXcPl/++OnDlct57ZAKXdvMQPMuyhMg7QqkWcxKXsS5iPxs1Zi9uFJth2aHCP2k2XCP59oZd TeTOVLRTnCu+avPbf9qUi1JVvvIY6Y29/eI83e8eqsIvXm/uTINmNA2Kn58cROJvGY35lp5ZjudUC ETttARKQa05u0v1DIdag==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1oniWO-009x57-6y; Wed, 26 Oct 2022 15:40:48 +0000 Received: from new4-smtp.messagingengine.com ([66.111.4.230]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1oniPo-009u7D-0Y for linux-arm-kernel@lists.infradead.org; Wed, 26 Oct 2022 15:34:02 +0000 Received: from compute1.internal (compute1.nyi.internal [10.202.2.41]) by mailnew.nyi.internal (Postfix) with ESMTP id 56DD6580419; Wed, 26 Oct 2022 11:33:59 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute1.internal (MEProxy); Wed, 26 Oct 2022 11:33:59 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cerno.tech; h=cc :cc:content-transfer-encoding:content-type:date:date:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:sender:subject:subject:to:to; s=fm3; t=1666798439; x= 1666805639; bh=LKFpDzCajsIwQGw9uWJAx53kPxeNPxieIVd/FDLIbbk=; b=q 7chUDPE7doQSxWXvBm+tgW2sp0QxilaCaC53/529Z0uWB/gFwf7BSaKDjcvFC1eL qhgvjfgABiKyGQnLg8cyHD7fvP8mlaFW/ORuUbS6Yb9MJ86pjUDFIkaG4EQBoaXZ LDNUgCofjKjmxk4mFyaTlvrrZkUA1Y0thkwq8IGmqX1n7yRcG5IiQDHKerbknIj/ V1UM9ot/vlOZOofvVPeTUyy886xr2egcWONQnQ2P12KCa7AMyhs9JOkYuSvgfMxx 84QMrWWHHHWnKIVNyTOFLngs0PUHl9Cx3m6z3SlLCeDrEJRheqPZn5xcT7OxXKuJ EOskMZ7w2fQrCNdvjagsg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:sender:subject:subject:to:to:x-me-proxy:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm3; t=1666798439; x= 1666805639; bh=LKFpDzCajsIwQGw9uWJAx53kPxeNPxieIVd/FDLIbbk=; b=o mwzNKDk5qk+xc/jeCVLQNJY4f60N6Qngoe1W2H7aEn8vgospE3qA+MFce5EXtSvp 9iT+IpkWBNWBT+pWBJCS4oPinAKuq33BQLlt7Lm8ACxfAm7MVS1VjjQ6Czqgc4Gh 9XGy4tfjICxrJ8bfwZM/aBEK70q8ju/T0Nx5+j27Nsyw8qJs4IAGyJxp3/1x/M4x TVZRbG36A/eBv8kL81X+AWyEHI7NKkB9CYiu2Oqn5+2Xqoh0OMku3ubvtV8m7kIz anMg3Z2TFi2fozVkk8R0pEyduiZeJjyZopVmXbgA3r8JOVUdjOPp+NCBJ6LNpj2M 0G4rdGWOYy05VfAPlzDZQ== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvgedrtddvgdeltdcutefuodetggdotefrodftvf curfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfghnecu uegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenuc fjughrpefhfffugggtgffkfhgjvfevofesthekredtredtjeenucfhrhhomhepmhgrgihi mhgvsegtvghrnhhordhtvggthhenucggtffrrghtthgvrhhnpeefudfhgeevhefhfedtue evueeluddutdetuddtvddvgeekheelvefhteekteeihfenucevlhhushhtvghrufhiiigv pedvnecurfgrrhgrmhepmhgrihhlfhhrohhmpehmrgigihhmvgestggvrhhnohdrthgvtg hh X-ME-Proxy: Feedback-ID: i8771445c:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 26 Oct 2022 11:33:58 -0400 (EDT) From: maxime@cerno.tech Date: Wed, 26 Oct 2022 17:33:32 +0200 Subject: [PATCH v6 13/23] drm/modes: Introduce the tv_mode property as a command-line option MIME-Version: 1.0 Message-Id: <20220728-rpi-analog-tv-properties-v6-13-e7792734108f@cerno.tech> References: <20220728-rpi-analog-tv-properties-v6-0-e7792734108f@cerno.tech> In-Reply-To: <20220728-rpi-analog-tv-properties-v6-0-e7792734108f@cerno.tech> To: Karol Herbst , Emma Anholt , Ben Skeggs , Chen-Yu Tsai , Rodrigo Vivi , Maarten Lankhorst , Jani Nikula , Daniel Vetter , Thomas Zimmermann , Tvrtko Ursulin , Samuel Holland , Jernej Skrabec , David Airlie , Maxime Ripard , Joonas Lahtinen , Lyude Paul Cc: linux-sunxi@lists.linux.dev, Maxime Ripard , intel-gfx@lists.freedesktop.org, Phil Elwell , linux-arm-kernel@lists.infradead.org, nouveau@lists.freedesktop.org, Hans de Goede , Dom Cobley , Mateusz Kwiatkowski , dri-devel@lists.freedesktop.org, Dave Stevenson , linux-kernel@vger.kernel.org, Noralf Trønnes , Geert Uytterhoeven X-Mailer: b4 0.11.0-dev-99e3a X-Developer-Signature: v=1; a=openpgp-sha256; l=8374; i=maxime@cerno.tech; h=from:subject:message-id; bh=DEe2U0LmtZRAsNEkdjQQIdxB6MF41xJtymVSw2jpx1I=; b=owGbwMvMwCX2+D1vfrpE4FHG02pJDMmRwW7fW2Lt33x8Vnmsb8Kx91tv8J4+6sX1b/2KfaEGv55o BBfM7ChlYRDjYpAVU2SJETZfEndq1utONr55MHNYmUCGMHBxCsBEssoYGfbKFwRPO+w/hy/p17T32V sSFy4NEVIscNhoLcDH3DxpcSwjQ3/t0zMlZ+xXa30Om1IlwnyO58W3/nvLmFomsNq3HG8s5AEA X-Developer-Key: i=maxime@cerno.tech; a=openpgp; fpr=BE5675C37E818C8B5764241C254BCFC56BF6CE8D X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20221026_083400_167141_E86D12C6 X-CRM114-Status: GOOD ( 20.80 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Our new tv mode option allows to specify the TV mode from a property. However, it can still be useful, for example to avoid any boot time artifact, to set that property directly from the kernel command line. Let's add some code to allow it, and some unit tests to exercise that code. Signed-off-by: Maxime Ripard --- Changes in v6: - Add a tv_mode_specified field Changes in v4: - Add Documentation of the command-line option to modedb.rst --- Documentation/fb/modedb.rst | 2 + drivers/gpu/drm/drm_modes.c | 37 ++++++++++++-- drivers/gpu/drm/tests/drm_cmdline_parser_test.c | 67 +++++++++++++++++++++++++ include/drm/drm_connector.h | 12 +++++ 4 files changed, 115 insertions(+), 3 deletions(-) diff --git a/Documentation/fb/modedb.rst b/Documentation/fb/modedb.rst index 4d2411e32ebb..5d6361a77f3c 100644 --- a/Documentation/fb/modedb.rst +++ b/Documentation/fb/modedb.rst @@ -65,6 +65,8 @@ Valid options are:: - reflect_y (boolean): Perform an axial symmetry on the Y axis - rotate (integer): Rotate the initial framebuffer by x degrees. Valid values are 0, 90, 180 and 270. + - tv_mode: Analog TV mode. One of "NTSC", "NTSC-443", "NTSC-J", "PAL", + "PAL-M", "PAL-N", or "SECAM". - panel_orientation, one of "normal", "upside_down", "left_side_up", or "right_side_up". For KMS drivers only, this sets the "panel orientation" property on the kms connector as hint for kms users. diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index c826f9583a1d..dc037f7ceb37 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -2133,6 +2133,30 @@ static int drm_mode_parse_panel_orientation(const char *delim, return 0; } +static int drm_mode_parse_tv_mode(const char *delim, + struct drm_cmdline_mode *mode) +{ + const char *value; + int ret; + + if (*delim != '=') + return -EINVAL; + + value = delim + 1; + delim = strchr(value, ','); + if (!delim) + delim = value + strlen(value); + + ret = drm_get_tv_mode_from_name(value, delim - value); + if (ret < 0) + return ret; + + mode->tv_mode_specified = true; + mode->tv_mode = ret; + + return 0; +} + static int drm_mode_parse_cmdline_options(const char *str, bool freestanding, const struct drm_connector *connector, @@ -2202,6 +2226,9 @@ static int drm_mode_parse_cmdline_options(const char *str, } else if (!strncmp(option, "panel_orientation", delim - option)) { if (drm_mode_parse_panel_orientation(delim, mode)) return -EINVAL; + } else if (!strncmp(option, "tv_mode", delim - option)) { + if (drm_mode_parse_tv_mode(delim, mode)) + return -EINVAL; } else { return -EINVAL; } @@ -2230,20 +2257,22 @@ struct drm_named_mode { unsigned int xres; unsigned int yres; unsigned int flags; + unsigned int tv_mode; }; -#define NAMED_MODE(_name, _pclk, _x, _y, _flags) \ +#define NAMED_MODE(_name, _pclk, _x, _y, _flags, _mode) \ { \ .name = _name, \ .pixel_clock_khz = _pclk, \ .xres = _x, \ .yres = _y, \ .flags = _flags, \ + .tv_mode = _mode, \ } static const struct drm_named_mode drm_named_modes[] = { - NAMED_MODE("NTSC", 13500, 720, 480, DRM_MODE_FLAG_INTERLACE), - NAMED_MODE("PAL", 13500, 720, 576, DRM_MODE_FLAG_INTERLACE), + NAMED_MODE("NTSC", 13500, 720, 480, DRM_MODE_FLAG_INTERLACE, DRM_MODE_TV_MODE_NTSC), + NAMED_MODE("PAL", 13500, 720, 576, DRM_MODE_FLAG_INTERLACE, DRM_MODE_TV_MODE_PAL), }; static int drm_mode_parse_cmdline_named_mode(const char *name, @@ -2288,6 +2317,8 @@ static int drm_mode_parse_cmdline_named_mode(const char *name, cmdline_mode->xres = mode->xres; cmdline_mode->yres = mode->yres; cmdline_mode->interlace = !!(mode->flags & DRM_MODE_FLAG_INTERLACE); + cmdline_mode->tv_mode = mode->tv_mode; + cmdline_mode->tv_mode_specified = true; cmdline_mode->specified = true; return 1; diff --git a/drivers/gpu/drm/tests/drm_cmdline_parser_test.c b/drivers/gpu/drm/tests/drm_cmdline_parser_test.c index 34790e7a3760..3e711b83b823 100644 --- a/drivers/gpu/drm/tests/drm_cmdline_parser_test.c +++ b/drivers/gpu/drm/tests/drm_cmdline_parser_test.c @@ -927,6 +927,14 @@ static const struct drm_cmdline_invalid_test drm_cmdline_invalid_tests[] = { .name = "invalid_option", .cmdline = "720x480,test=42", }, + { + .name = "invalid_tv_option", + .cmdline = "720x480i,tv_mode=invalid", + }, + { + .name = "truncated_tv_option", + .cmdline = "720x480i,tv_mode=NTS", + }, }; static void drm_cmdline_invalid_desc(const struct drm_cmdline_invalid_test *t, @@ -937,6 +945,64 @@ static void drm_cmdline_invalid_desc(const struct drm_cmdline_invalid_test *t, KUNIT_ARRAY_PARAM(drm_cmdline_invalid, drm_cmdline_invalid_tests, drm_cmdline_invalid_desc); +struct drm_cmdline_tv_option_test { + const char *name; + const char *cmdline; + struct drm_display_mode *(*mode_fn)(struct drm_device *dev); + enum drm_connector_tv_mode tv_mode; +}; + +static void drm_test_cmdline_tv_options(struct kunit *test) +{ + const struct drm_cmdline_tv_option_test *params = test->param_value; + const struct drm_display_mode *expected_mode = params->mode_fn(NULL); + struct drm_cmdline_mode mode = { }; + + KUNIT_EXPECT_TRUE(test, drm_mode_parse_command_line_for_connector(params->cmdline, + &no_connector, &mode)); + KUNIT_EXPECT_TRUE(test, mode.specified); + KUNIT_EXPECT_EQ(test, mode.xres, expected_mode->hdisplay); + KUNIT_EXPECT_EQ(test, mode.yres, expected_mode->vdisplay); + KUNIT_EXPECT_EQ(test, mode.tv_mode, params->tv_mode); + + KUNIT_EXPECT_FALSE(test, mode.refresh_specified); + + KUNIT_EXPECT_FALSE(test, mode.bpp_specified); + + KUNIT_EXPECT_FALSE(test, mode.rb); + KUNIT_EXPECT_FALSE(test, mode.cvt); + KUNIT_EXPECT_EQ(test, mode.interlace, !!(expected_mode->flags & DRM_MODE_FLAG_INTERLACE)); + KUNIT_EXPECT_FALSE(test, mode.margins); + KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED); +} + +#define TV_OPT_TEST(_opt, _cmdline, _mode_fn) \ + { \ + .name = #_opt, \ + .cmdline = _cmdline, \ + .mode_fn = _mode_fn, \ + .tv_mode = DRM_MODE_TV_MODE_ ## _opt, \ + } + +static const struct drm_cmdline_tv_option_test drm_cmdline_tv_option_tests[] = { + TV_OPT_TEST(NTSC, "720x480i,tv_mode=NTSC", drm_mode_analog_ntsc_480i), + TV_OPT_TEST(NTSC_443, "720x480i,tv_mode=NTSC-443", drm_mode_analog_ntsc_480i), + TV_OPT_TEST(NTSC_J, "720x480i,tv_mode=NTSC-J", drm_mode_analog_ntsc_480i), + TV_OPT_TEST(PAL, "720x576i,tv_mode=PAL", drm_mode_analog_pal_576i), + TV_OPT_TEST(PAL_M, "720x480i,tv_mode=PAL-M", drm_mode_analog_ntsc_480i), + TV_OPT_TEST(PAL_N, "720x576i,tv_mode=PAL-N", drm_mode_analog_pal_576i), + TV_OPT_TEST(SECAM, "720x576i,tv_mode=SECAM", drm_mode_analog_pal_576i), +}; + +static void drm_cmdline_tv_option_desc(const struct drm_cmdline_tv_option_test *t, + char *desc) +{ + sprintf(desc, "%s", t->name); +} +KUNIT_ARRAY_PARAM(drm_cmdline_tv_option, + drm_cmdline_tv_option_tests, + drm_cmdline_tv_option_desc); + static struct kunit_case drm_cmdline_parser_tests[] = { KUNIT_CASE(drm_test_cmdline_force_d_only), KUNIT_CASE(drm_test_cmdline_force_D_only_dvi), @@ -977,6 +1043,7 @@ static struct kunit_case drm_cmdline_parser_tests[] = { KUNIT_CASE(drm_test_cmdline_freestanding_force_e_and_options), KUNIT_CASE(drm_test_cmdline_panel_orientation), KUNIT_CASE_PARAM(drm_test_cmdline_invalid, drm_cmdline_invalid_gen_params), + KUNIT_CASE_PARAM(drm_test_cmdline_tv_options, drm_cmdline_tv_option_gen_params), {} }; diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 276f5cb0f351..2cd39a15bad8 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -1368,6 +1368,18 @@ struct drm_cmdline_mode { * @tv_margins: TV margins to apply to the mode. */ struct drm_connector_tv_margins tv_margins; + + /** + * @tv_mode: TV mode standard. See DRM_MODE_TV_MODE_*. + */ + enum drm_connector_tv_mode tv_mode; + + /** + * @tv_mode_specified: + * + * Did the mode have a preferred TV mode? + */ + bool tv_mode_specified; }; /** -- b4 0.11.0-dev-99e3a _______________________________________________ linux-arm-kernel mailing list linux-arm-kernel@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel