From patchwork Mon May 27 13:57:51 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Maxime Ripard X-Patchwork-Id: 799372 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 23E4A15F309; Mon, 27 May 2024 13:58:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716818294; cv=none; b=jC8L/4+PwNDUOQxIOfLjJlw1/hIpr2tziysac0ABij0SmX3f3Y361fwgI4yRrVFD1PR0l+RhXphn1zWUXRi5oQ7FvzksdixRkyxlRX9WlKlN2PnwdmjM6RTsIeMTukCV/M9WMbJQIF+yoXer60yHqIGCUHHipTa5koEdIsWhEfo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716818294; c=relaxed/simple; bh=Jd5Xo/csjHcnm5bNUzfT8E3FJ0NlCfRfDDxu197YBKE=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=VXFDMk5uCcnpZIvcuO/S5L728Fo/hnNQdRQY1hAU9PaW4N25EMuEel7SoW7Vr8hNi6EePqlL1nFyVDrHX+CRw+Y1DqS0thO2sNfTY6mip10IPThlFWHx1KMOZHd5Ixix0a3Q/A4dsHJy2ArULF2uKFvcMeCsmGf6H5UWIGZOORo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=t1pKMVRn; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="t1pKMVRn" Received: by smtp.kernel.org (Postfix) with ESMTPSA id A5E2DC4AF0A; Mon, 27 May 2024 13:58:13 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1716818294; bh=Jd5Xo/csjHcnm5bNUzfT8E3FJ0NlCfRfDDxu197YBKE=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=t1pKMVRnF/dibuWfNeZg5gHE47p0XOqiYYca3Qi2U4sIpoQwxkF6HWs/NNLmv9t+2 tKsaFtPXBg2/nl2PYyyWA6joFw3sfTLFvishPelujJsd/LuMeDjXb1PdSpGdUOXLag E6YJc5PaSF6dxfFJKopGV5xlPIny1L4e+JxfD42hB1flU1Oo3zQMYiwgH93O8kSHn9 m2pkuBXlV+sttYkVWo2IA/rvS9awRsqZJJz5mwfgMGOJ/7nOvfswSHSRbQw4qQ3+o+ Tq1A6wgZ82Msn+RD2L4PHNJeDISkQHVmCR7wX/roMgGPdVJW4dKM7bFCnyLjdu9pW7 VnwduZBgjMgfg== From: Maxime Ripard Date: Mon, 27 May 2024 15:57:51 +0200 Subject: [PATCH v15 02/29] drm/tests: connector: Add tests for drmm_connector_hdmi_init Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20240527-kms-hdmi-connector-state-v15-2-c5af16c3aae2@kernel.org> References: <20240527-kms-hdmi-connector-state-v15-0-c5af16c3aae2@kernel.org> In-Reply-To: <20240527-kms-hdmi-connector-state-v15-0-c5af16c3aae2@kernel.org> To: Maarten Lankhorst , Thomas Zimmermann , David Airlie , Daniel Vetter , Jonathan Corbet , Sandy Huang , =?utf-8?q?Heiko_St=C3=BCbner?= , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Andy Yan Cc: Hans Verkuil , Sebastian Wick , =?utf-8?b?VmlsbGUgU3lyasOkbMOk?= , dri-devel@lists.freedesktop.org, linux-arm-kernel@lists.infradead.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-rockchip@lists.infradead.org, linux-sunxi@lists.linux.dev, Maxime Ripard , Dave Stevenson , Dmitry Baryshkov X-Mailer: b4 0.13.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=5181; i=mripard@kernel.org; h=from:subject:message-id; bh=Jd5Xo/csjHcnm5bNUzfT8E3FJ0NlCfRfDDxu197YBKE=; b=owGbwMvMwCmsHn9OcpHtvjLG02pJDGkhExM+2HrN+nNoYfF+LtMPeSsmflLZaMAT88HO6N4Lc 75YKYb+jqksDMKcDLJiiixPZMJOL29fXOVgv/IHzBxWJpAhDFycAjAR9jTGOtWFU48qLRPblKdr lHCNef6e53w6en2yIuVvQi9rKKkxJEvNNJe9G3Zd6xzb46fX875WMdaZVa4zPLiz53PF6Zmz+AW vM19qYXJfXZW5NeLDsvsF7rpuPoGdGX0FjsorviaqXTn0hAMA X-Developer-Key: i=mripard@kernel.org; a=openpgp; fpr=BE5675C37E818C8B5764241C254BCFC56BF6CE8D We just introduced a new initialization function for our connectors, so let's build a kunit test suite for it as well. Reviewed-by: Dave Stevenson Reviewed-by: Dmitry Baryshkov Signed-off-by: Maxime Ripard --- drivers/gpu/drm/tests/drm_connector_test.c | 123 +++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) diff --git a/drivers/gpu/drm/tests/drm_connector_test.c b/drivers/gpu/drm/tests/drm_connector_test.c index 44f82ed2a958..261d4109946d 100644 --- a/drivers/gpu/drm/tests/drm_connector_test.c +++ b/drivers/gpu/drm/tests/drm_connector_test.c @@ -170,10 +170,132 @@ static struct kunit_suite drmm_connector_init_test_suite = { .name = "drmm_connector_init", .init = drm_test_connector_init, .test_cases = drmm_connector_init_tests, }; +/* + * Test that the registration of a bog standard connector works as + * expected and doesn't report any error. + */ +static void drm_test_connector_hdmi_init_valid(struct kunit *test) +{ + struct drm_connector_init_priv *priv = test->priv; + int ret; + + ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector, + &dummy_funcs, + DRM_MODE_CONNECTOR_HDMIA, + &priv->ddc); + KUNIT_EXPECT_EQ(test, ret, 0); +} + +/* + * Test that the registration of a connector without a DDC adapter + * doesn't report any error. + */ +static void drm_test_connector_hdmi_init_null_ddc(struct kunit *test) +{ + struct drm_connector_init_priv *priv = test->priv; + int ret; + + ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector, + &dummy_funcs, + DRM_MODE_CONNECTOR_HDMIA, + NULL); + KUNIT_EXPECT_EQ(test, ret, 0); +} + +/* + * Test that the registration of an HDMI connector with an HDMI + * connector type succeeds. + */ +static void drm_test_connector_hdmi_init_type_valid(struct kunit *test) +{ + struct drm_connector_init_priv *priv = test->priv; + unsigned int connector_type = *(unsigned int *)test->param_value; + int ret; + + ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector, + &dummy_funcs, + connector_type, + &priv->ddc); + KUNIT_EXPECT_EQ(test, ret, 0); +} + +static const unsigned int drm_connector_hdmi_init_type_valid_tests[] = { + DRM_MODE_CONNECTOR_HDMIA, + DRM_MODE_CONNECTOR_HDMIB, +}; + +static void drm_connector_hdmi_init_type_desc(const unsigned int *type, char *desc) +{ + sprintf(desc, "%s", drm_get_connector_type_name(*type)); +} + +KUNIT_ARRAY_PARAM(drm_connector_hdmi_init_type_valid, + drm_connector_hdmi_init_type_valid_tests, + drm_connector_hdmi_init_type_desc); + +/* + * Test that the registration of an HDMI connector with an !HDMI + * connector type fails. + */ +static void drm_test_connector_hdmi_init_type_invalid(struct kunit *test) +{ + struct drm_connector_init_priv *priv = test->priv; + unsigned int connector_type = *(unsigned int *)test->param_value; + int ret; + + ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector, + &dummy_funcs, + connector_type, + &priv->ddc); + KUNIT_EXPECT_LT(test, ret, 0); +} + +static const unsigned int drm_connector_hdmi_init_type_invalid_tests[] = { + DRM_MODE_CONNECTOR_Unknown, + DRM_MODE_CONNECTOR_VGA, + DRM_MODE_CONNECTOR_DVII, + DRM_MODE_CONNECTOR_DVID, + DRM_MODE_CONNECTOR_DVIA, + DRM_MODE_CONNECTOR_Composite, + DRM_MODE_CONNECTOR_SVIDEO, + DRM_MODE_CONNECTOR_LVDS, + DRM_MODE_CONNECTOR_Component, + DRM_MODE_CONNECTOR_9PinDIN, + DRM_MODE_CONNECTOR_DisplayPort, + DRM_MODE_CONNECTOR_TV, + DRM_MODE_CONNECTOR_eDP, + DRM_MODE_CONNECTOR_VIRTUAL, + DRM_MODE_CONNECTOR_DSI, + DRM_MODE_CONNECTOR_DPI, + DRM_MODE_CONNECTOR_WRITEBACK, + DRM_MODE_CONNECTOR_SPI, + DRM_MODE_CONNECTOR_USB, +}; + +KUNIT_ARRAY_PARAM(drm_connector_hdmi_init_type_invalid, + drm_connector_hdmi_init_type_invalid_tests, + drm_connector_hdmi_init_type_desc); + +static struct kunit_case drmm_connector_hdmi_init_tests[] = { + KUNIT_CASE(drm_test_connector_hdmi_init_valid), + KUNIT_CASE(drm_test_connector_hdmi_init_null_ddc), + KUNIT_CASE_PARAM(drm_test_connector_hdmi_init_type_valid, + drm_connector_hdmi_init_type_valid_gen_params), + KUNIT_CASE_PARAM(drm_test_connector_hdmi_init_type_invalid, + drm_connector_hdmi_init_type_invalid_gen_params), + { } +}; + +static struct kunit_suite drmm_connector_hdmi_init_test_suite = { + .name = "drmm_connector_hdmi_init", + .init = drm_test_connector_init, + .test_cases = drmm_connector_hdmi_init_tests, +}; + struct drm_get_tv_mode_from_name_test { const char *name; enum drm_connector_tv_mode expected_mode; }; @@ -234,10 +356,11 @@ static struct kunit_suite drm_get_tv_mode_from_name_test_suite = { .name = "drm_get_tv_mode_from_name", .test_cases = drm_get_tv_mode_from_name_tests, }; kunit_test_suites( + &drmm_connector_hdmi_init_test_suite, &drmm_connector_init_test_suite, &drm_get_tv_mode_from_name_test_suite ); MODULE_AUTHOR("Maxime Ripard "); From patchwork Mon May 27 13:57:53 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Maxime Ripard X-Patchwork-Id: 799371 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 80FE815FA7F; Mon, 27 May 2024 13:58:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716818300; cv=none; b=ZmNUvccPtrVIpy2iudGuPITY9syB1tO65BrVdXoWymTwPWECIzwZTtAQyeCiuRC/UfZke2dOaTETVH34lFU87Os2efJadOHncJ48ti54PCaQjDw7XY9u/29MZRLjI5ZzChingWWG3MZptbxwMLMc+kZG4NA7oCA9hnrWzCX0XVU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716818300; c=relaxed/simple; bh=+4AzKiyqAeO2P4pZZ0g8gEGGU0uN3S9W/yTh2M+2RBQ=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=qXJHsH3EFhSGrC7xLKxDItJa0rV6PmU08ILy31l0Y9cnwD5MfoOOZpl9CLUzrhblMr/yJEK8bbP1SrYlUPTMPunq0bOgfHSSYM9YwNO22vBZNISpSJDX/DWorJggCJ9yDtVhxJw6QMTjXJJ54cSQ3jO0c8aypLVy9D4rqxDOU2s= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=KswPnBSh; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="KswPnBSh" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 958B0C32781; Mon, 27 May 2024 13:58:19 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1716818300; bh=+4AzKiyqAeO2P4pZZ0g8gEGGU0uN3S9W/yTh2M+2RBQ=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=KswPnBShwfR4f80ulS2cCKEU6988qCfChlPRg6meSO0wToqfsZdzbiRE6DT1pBV+M DXBprmq53iL8FwcVBlSSJgRlSZoQJEowx0Rd7qmDu5cIoro9g6bAqnHxPW2fR5ntr4 5bUPXckH6j01RCxgAx79Jy8ZtrENyu2X/4+SW0Nmi2TPBKUK7q74iidXI4LZP4Vqez JhEfF2ra3cC7nFlGDs15GmdCGgcsFPvrk/0Wf8y+lvLJ6KhgfJ8Uwl+8r7mVrwjNoB NLCIOkOgW6IkDBrCjnb3ksCYFu4wcK0iFeR7V/ZKk5F2lVN26NtVzB9Ai2fLMLqg8a JV6wLWBtOkE0g== From: Maxime Ripard Date: Mon, 27 May 2024 15:57:53 +0200 Subject: [PATCH v15 04/29] drm/connector: hdmi: Add output BPC to the connector state Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20240527-kms-hdmi-connector-state-v15-4-c5af16c3aae2@kernel.org> References: <20240527-kms-hdmi-connector-state-v15-0-c5af16c3aae2@kernel.org> In-Reply-To: <20240527-kms-hdmi-connector-state-v15-0-c5af16c3aae2@kernel.org> To: Maarten Lankhorst , Thomas Zimmermann , David Airlie , Daniel Vetter , Jonathan Corbet , Sandy Huang , =?utf-8?q?Heiko_St=C3=BCbner?= , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Andy Yan Cc: Hans Verkuil , Sebastian Wick , =?utf-8?b?VmlsbGUgU3lyasOkbMOk?= , dri-devel@lists.freedesktop.org, linux-arm-kernel@lists.infradead.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-rockchip@lists.infradead.org, linux-sunxi@lists.linux.dev, Maxime Ripard , Dave Stevenson , Dmitry Baryshkov X-Mailer: b4 0.13.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=9019; i=mripard@kernel.org; h=from:subject:message-id; bh=+4AzKiyqAeO2P4pZZ0g8gEGGU0uN3S9W/yTh2M+2RBQ=; b=owGbwMvMwCmsHn9OcpHtvjLG02pJDGkhExMnz6hMKK2bqTSt1TNQkuewaK6/Q6nU1M+h1gql3 0I6k7Z3TGVhEOZkkBVTZHkiE3Z6efviKgf7lT9g5rAygQxh4OIUgIkIzmBsmBf/ZzHDtabfb025 P5kqa/x4EjDlxrLCud/OBPXdPj2rKzrdojTnve1VhsI9fZFSIhJbGBue1yWZn1EW9lXWkbrjpzx d/ss2gcMfJFf0TuU4VW5t9+3a+uxUqzPqq3mtgwPLbiX79QAA X-Developer-Key: i=mripard@kernel.org; a=openpgp; fpr=BE5675C37E818C8B5764241C254BCFC56BF6CE8D We'll add automatic selection of the output BPC in a following patch, but let's add it to the HDMI connector state already. Reviewed-by: Dave Stevenson Reviewed-by: Dmitry Baryshkov Signed-off-by: Maxime Ripard --- drivers/gpu/drm/display/drm_hdmi_state_helper.c | 20 ++++++++++++++++++++ drivers/gpu/drm/drm_atomic.c | 5 +++++ drivers/gpu/drm/drm_connector.c | 20 +++++++++++++++++++- drivers/gpu/drm/tests/drm_connector_test.c | 12 ++++++++---- include/drm/drm_connector.h | 12 +++++++++++- 5 files changed, 63 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c index 1e92c1108d23..82293d93b5f8 100644 --- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c +++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c @@ -16,10 +16,14 @@ * drm_atomic_helper_connector_reset(). */ void __drm_atomic_helper_connector_hdmi_reset(struct drm_connector *connector, struct drm_connector_state *new_conn_state) { + unsigned int max_bpc = connector->max_bpc; + + new_conn_state->max_bpc = max_bpc; + new_conn_state->max_requested_bpc = max_bpc; } EXPORT_SYMBOL(__drm_atomic_helper_connector_hdmi_reset); /** * drm_atomic_helper_connector_hdmi_check() - Helper to check HDMI connector atomic state @@ -34,8 +38,24 @@ EXPORT_SYMBOL(__drm_atomic_helper_connector_hdmi_reset); * Zero on success, or an errno code otherwise. */ int drm_atomic_helper_connector_hdmi_check(struct drm_connector *connector, struct drm_atomic_state *state) { + struct drm_connector_state *old_conn_state = + drm_atomic_get_old_connector_state(state, connector); + struct drm_connector_state *new_conn_state = + drm_atomic_get_new_connector_state(state, connector); + + if (old_conn_state->hdmi.output_bpc != new_conn_state->hdmi.output_bpc) { + struct drm_crtc *crtc = new_conn_state->crtc; + struct drm_crtc_state *crtc_state; + + crtc_state = drm_atomic_get_crtc_state(state, crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); + + crtc_state->mode_changed = true; + } + return 0; } EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_check); diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index a91737adf8e7..4e11cfb4518b 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -1141,10 +1141,15 @@ static void drm_atomic_connector_print_state(struct drm_printer *p, drm_printf(p, "\tcrtc=%s\n", state->crtc ? state->crtc->name : "(null)"); drm_printf(p, "\tself_refresh_aware=%d\n", state->self_refresh_aware); drm_printf(p, "\tmax_requested_bpc=%d\n", state->max_requested_bpc); drm_printf(p, "\tcolorspace=%s\n", drm_get_colorspace_name(state->colorspace)); + if (connector->connector_type == DRM_MODE_CONNECTOR_HDMIA || + connector->connector_type == DRM_MODE_CONNECTOR_HDMIB) { + drm_printf(p, "\toutput_bpc=%u\n", state->hdmi.output_bpc); + } + if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) if (state->writeback_job && state->writeback_job->fb) drm_printf(p, "\tfb=%d\n", state->writeback_job->fb->base.id); if (connector->funcs->atomic_print_state) diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index d9961cce8245..da51a2bcb978 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -457,10 +457,11 @@ EXPORT_SYMBOL(drmm_connector_init); * @dev: DRM device * @connector: A pointer to the HDMI connector to init * @funcs: callbacks for this connector * @connector_type: user visible type of the connector * @ddc: optional pointer to the associated ddc adapter + * @max_bpc: Maximum bits per char the HDMI connector supports * * Initialises a preallocated HDMI connector. Connectors can be * subclassed as part of driver connector objects. * * Cleanup is automatically handled with a call to @@ -473,22 +474,39 @@ EXPORT_SYMBOL(drmm_connector_init); */ int drmm_connector_hdmi_init(struct drm_device *dev, struct drm_connector *connector, const struct drm_connector_funcs *funcs, int connector_type, - struct i2c_adapter *ddc) + struct i2c_adapter *ddc, + unsigned int max_bpc) { int ret; if (!(connector_type == DRM_MODE_CONNECTOR_HDMIA || connector_type == DRM_MODE_CONNECTOR_HDMIB)) return -EINVAL; + if (!(max_bpc == 8 || max_bpc == 10 || max_bpc == 12)) + return -EINVAL; + ret = drmm_connector_init(dev, connector, funcs, connector_type, ddc); if (ret) return ret; + /* + * drm_connector_attach_max_bpc_property() requires the + * connector to have a state. + */ + if (connector->funcs->reset) + connector->funcs->reset(connector); + + drm_connector_attach_max_bpc_property(connector, 8, max_bpc); + connector->max_bpc = max_bpc; + + if (max_bpc > 8) + drm_connector_attach_hdr_output_metadata_property(connector); + return 0; } EXPORT_SYMBOL(drmm_connector_hdmi_init); /** diff --git a/drivers/gpu/drm/tests/drm_connector_test.c b/drivers/gpu/drm/tests/drm_connector_test.c index 261d4109946d..2661eb64a5cd 100644 --- a/drivers/gpu/drm/tests/drm_connector_test.c +++ b/drivers/gpu/drm/tests/drm_connector_test.c @@ -182,11 +182,12 @@ static void drm_test_connector_hdmi_init_valid(struct kunit *test) int ret; ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector, &dummy_funcs, DRM_MODE_CONNECTOR_HDMIA, - &priv->ddc); + &priv->ddc, + 8); KUNIT_EXPECT_EQ(test, ret, 0); } /* * Test that the registration of a connector without a DDC adapter @@ -198,11 +199,12 @@ static void drm_test_connector_hdmi_init_null_ddc(struct kunit *test) int ret; ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector, &dummy_funcs, DRM_MODE_CONNECTOR_HDMIA, - NULL); + NULL, + 8); KUNIT_EXPECT_EQ(test, ret, 0); } /* * Test that the registration of an HDMI connector with an HDMI @@ -215,11 +217,12 @@ static void drm_test_connector_hdmi_init_type_valid(struct kunit *test) int ret; ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector, &dummy_funcs, connector_type, - &priv->ddc); + &priv->ddc, + 8); KUNIT_EXPECT_EQ(test, ret, 0); } static const unsigned int drm_connector_hdmi_init_type_valid_tests[] = { DRM_MODE_CONNECTOR_HDMIA, @@ -246,11 +249,12 @@ static void drm_test_connector_hdmi_init_type_invalid(struct kunit *test) int ret; ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector, &dummy_funcs, connector_type, - &priv->ddc); + &priv->ddc, + 8); KUNIT_EXPECT_LT(test, ret, 0); } static const unsigned int drm_connector_hdmi_init_type_invalid_tests[] = { DRM_MODE_CONNECTOR_Unknown, diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 000a2a156619..d4d2ae15bc1e 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -1035,10 +1035,14 @@ struct drm_connector_state { /** * @hdmi: HDMI-related variable and properties. Filled by * @drm_atomic_helper_connector_hdmi_check(). */ struct { + /** + * @output_bpc: Bits per color channel to output. + */ + unsigned int output_bpc; } hdmi; }; /** * struct drm_connector_funcs - control connectors on a given device @@ -1680,10 +1684,15 @@ struct drm_connector { * DRM blob property data for the DP MST path property. This should only * be updated by calling drm_connector_set_path_property(). */ struct drm_property_blob *path_blob_ptr; + /** + * @max_bpc: Maximum bits per color channel the connector supports. + */ + unsigned int max_bpc; + /** * @max_bpc_property: Default connector property for the max bpc to be * driven out of the connector. */ struct drm_property *max_bpc_property; @@ -1913,11 +1922,12 @@ int drmm_connector_init(struct drm_device *dev, struct i2c_adapter *ddc); int drmm_connector_hdmi_init(struct drm_device *dev, struct drm_connector *connector, const struct drm_connector_funcs *funcs, int connector_type, - struct i2c_adapter *ddc); + struct i2c_adapter *ddc, + unsigned int max_bpc); void drm_connector_attach_edid_property(struct drm_connector *connector); int drm_connector_register(struct drm_connector *connector); void drm_connector_unregister(struct drm_connector *connector); int drm_connector_attach_encoder(struct drm_connector *connector, struct drm_encoder *encoder); From patchwork Mon May 27 13:57:55 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Maxime Ripard X-Patchwork-Id: 799370 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 1188F1607AD; Mon, 27 May 2024 13:58:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716818306; cv=none; b=dMf6yeEp+3S+1PIptu75S9Otdg8WTK4pg0hx1BIIRkaKmPUbUv/4XyooyJYjd4s4e1iJu26MI9d5r175BuNeyrWD6KPPVQAahcrG7q+dciEgST+QcOmH4nvDhAixuPIya2esVKx7wL9xSfTZCWCOc6uhasORm6qDTSvGbCCzqQo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716818306; c=relaxed/simple; bh=PxzUsmpOaeMG7ENMVN/f80mb26rJ3NstZ7d8IRJOqJI=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=HpjqKdXfMw/7g+7jzjWeQg78k62jsPAwixkwnZ74dIc1JuET1flyO71tUtt15a9Axspeen7j/VIgQ7ZFUGhu+3jd/ZnQpSmCs7bw5WMbXg50cOSFOXGBPn+A6Qd5mZSbqMtNjN7utu1t1k8EadCYBw+l7VoaShWwxgrzv2AYunc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Gw81+dtY; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Gw81+dtY" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 19296C4AF12; Mon, 27 May 2024 13:58:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1716818305; bh=PxzUsmpOaeMG7ENMVN/f80mb26rJ3NstZ7d8IRJOqJI=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=Gw81+dtYlsBTB8Em43xaJ8CVippPGt8DiFd0hl+WnEvGM4AaNG/dZdVV7svGCBSI7 rp3Z648N3thfg1q6V/aVoJhsZmTZ+qMeNCuoPfIpANU9BKGmvYtUKYneylsVsJQhAp fKqH3Y5upgsCWotyqpiXXcRRdEPWneiKjeWnvHGiS3/9WCk7ye7b59+4DSV5DuAoAN leZp6M4V3xczSUKWvkUZh/K6UWYVSxdnfD4zd6q/oa8C0ZEG4O/rTT/Dw4hOHNvIXJ PXiIaWAJpv5HlQzT/oEN9d14XvxxyEa66ErQNvXoTxH8X4wnQG2HFuG9/p+S38zEg2 BfEXPghB6NJfw== From: Maxime Ripard Date: Mon, 27 May 2024 15:57:55 +0200 Subject: [PATCH v15 06/29] drm/tests: Add output bpc tests Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20240527-kms-hdmi-connector-state-v15-6-c5af16c3aae2@kernel.org> References: <20240527-kms-hdmi-connector-state-v15-0-c5af16c3aae2@kernel.org> In-Reply-To: <20240527-kms-hdmi-connector-state-v15-0-c5af16c3aae2@kernel.org> To: Maarten Lankhorst , Thomas Zimmermann , David Airlie , Daniel Vetter , Jonathan Corbet , Sandy Huang , =?utf-8?q?Heiko_St=C3=BCbner?= , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Andy Yan Cc: Hans Verkuil , Sebastian Wick , =?utf-8?b?VmlsbGUgU3lyasOkbMOk?= , dri-devel@lists.freedesktop.org, linux-arm-kernel@lists.infradead.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-rockchip@lists.infradead.org, linux-sunxi@lists.linux.dev, Maxime Ripard , Dave Stevenson , Dmitry Baryshkov X-Mailer: b4 0.13.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=27772; i=mripard@kernel.org; h=from:subject:message-id; bh=PxzUsmpOaeMG7ENMVN/f80mb26rJ3NstZ7d8IRJOqJI=; b=owGbwMvMwCmsHn9OcpHtvjLG02pJDGkhE5PuVdjyJvt92MLNyPc8XfSdkG6ZleSmrycTWh14J +3fOcumYyoLgzAng6yYIssTmbDTy9sXVznYr/wBM4eVCWQIAxenAEwkgZuxYdK8Q5XLeRee33Xr 2BuxtYVnD9TfZKuT9uftXes0x/xhwaIV3dpxPqoG5XsnNBnuEolbx1hfxq/n9WzO9gexfU+vHgo QNf8bpjPJ+vnJOYm8bodsDkZyLFvd23A4vt7n5/ptxUe2ewsDAA== X-Developer-Key: i=mripard@kernel.org; a=openpgp; fpr=BE5675C37E818C8B5764241C254BCFC56BF6CE8D Now that we're tracking the output bpc count in the connector state, let's add a few tests to make sure it works as expected. Reviewed-by: Dave Stevenson Reviewed-by: Dmitry Baryshkov Signed-off-by: Maxime Ripard --- drivers/gpu/drm/Kconfig | 1 + drivers/gpu/drm/tests/Makefile | 1 + drivers/gpu/drm/tests/drm_connector_test.c | 155 ++++++++ drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 438 +++++++++++++++++++++ drivers/gpu/drm/tests/drm_kunit_edid.h | 106 +++++ 5 files changed, 701 insertions(+) diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 026444eeb5c6..9703429de6b9 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -77,10 +77,11 @@ config DRM_KUNIT_TEST_HELPERS config DRM_KUNIT_TEST tristate "KUnit tests for DRM" if !KUNIT_ALL_TESTS depends on DRM && KUNIT && MMU select DRM_BUDDY select DRM_DISPLAY_DP_HELPER + select DRM_DISPLAY_HDMI_STATE_HELPER select DRM_DISPLAY_HELPER select DRM_EXEC select DRM_EXPORT_FOR_TESTS if m select DRM_GEM_SHMEM_HELPER select DRM_KUNIT_TEST_HELPERS diff --git a/drivers/gpu/drm/tests/Makefile b/drivers/gpu/drm/tests/Makefile index d6183b3d7688..56dab563abd7 100644 --- a/drivers/gpu/drm/tests/Makefile +++ b/drivers/gpu/drm/tests/Makefile @@ -12,10 +12,11 @@ obj-$(CONFIG_DRM_KUNIT_TEST) += \ drm_exec_test.o \ drm_format_helper_test.o \ drm_format_test.o \ drm_framebuffer_test.o \ drm_gem_shmem_test.o \ + drm_hdmi_state_helper_test.o \ drm_managed_test.o \ drm_mm_test.o \ drm_modes_test.o \ drm_plane_helper_test.o \ drm_probe_helper_test.o \ diff --git a/drivers/gpu/drm/tests/drm_connector_test.c b/drivers/gpu/drm/tests/drm_connector_test.c index 2661eb64a5cd..9465fa33f3b6 100644 --- a/drivers/gpu/drm/tests/drm_connector_test.c +++ b/drivers/gpu/drm/tests/drm_connector_test.c @@ -10,10 +10,12 @@ #include #include #include +#include "../drm_crtc_internal.h" + struct drm_connector_init_priv { struct drm_device drm; struct drm_connector connector; struct i2c_adapter ddc; }; @@ -204,10 +206,158 @@ static void drm_test_connector_hdmi_init_null_ddc(struct kunit *test) NULL, 8); KUNIT_EXPECT_EQ(test, ret, 0); } +/* + * Test that the registration of a connector with an invalid maximum bpc + * count fails. + */ +static void drm_test_connector_hdmi_init_bpc_invalid(struct kunit *test) +{ + struct drm_connector_init_priv *priv = test->priv; + int ret; + + ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector, + &dummy_funcs, + DRM_MODE_CONNECTOR_HDMIA, + &priv->ddc, + 9); + KUNIT_EXPECT_LT(test, ret, 0); +} + +/* + * Test that the registration of a connector with a null maximum bpc + * count fails. + */ +static void drm_test_connector_hdmi_init_bpc_null(struct kunit *test) +{ + struct drm_connector_init_priv *priv = test->priv; + int ret; + + ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector, + &dummy_funcs, + DRM_MODE_CONNECTOR_HDMIA, + &priv->ddc, + 0); + KUNIT_EXPECT_LT(test, ret, 0); +} + +/* + * Test that the registration of a connector with a maximum bpc count of + * 8 succeeds, registers the max bpc property, but doesn't register the + * HDR output metadata one. + */ +static void drm_test_connector_hdmi_init_bpc_8(struct kunit *test) +{ + struct drm_connector_init_priv *priv = test->priv; + struct drm_connector_state *state; + struct drm_connector *connector = &priv->connector; + struct drm_property *prop; + uint64_t val; + int ret; + + ret = drmm_connector_hdmi_init(&priv->drm, connector, + &dummy_funcs, + DRM_MODE_CONNECTOR_HDMIA, + &priv->ddc, + 8); + KUNIT_EXPECT_EQ(test, ret, 0); + + prop = connector->max_bpc_property; + KUNIT_ASSERT_NOT_NULL(test, prop); + KUNIT_EXPECT_NOT_NULL(test, drm_mode_obj_find_prop_id(&connector->base, prop->base.id)); + + ret = drm_object_property_get_default_value(&connector->base, prop, &val); + KUNIT_EXPECT_EQ(test, ret, 0); + KUNIT_EXPECT_EQ(test, val, 8); + + state = connector->state; + KUNIT_EXPECT_EQ(test, state->max_bpc, 8); + KUNIT_EXPECT_EQ(test, state->max_requested_bpc, 8); + + prop = priv->drm.mode_config.hdr_output_metadata_property; + KUNIT_ASSERT_NOT_NULL(test, prop); + KUNIT_EXPECT_NULL(test, drm_mode_obj_find_prop_id(&connector->base, prop->base.id)); +} + +/* + * Test that the registration of a connector with a maximum bpc count of + * 10 succeeds and registers the max bpc and HDR output metadata + * properties. + */ +static void drm_test_connector_hdmi_init_bpc_10(struct kunit *test) +{ + struct drm_connector_init_priv *priv = test->priv; + struct drm_connector_state *state; + struct drm_connector *connector = &priv->connector; + struct drm_property *prop; + uint64_t val; + int ret; + + ret = drmm_connector_hdmi_init(&priv->drm, connector, + &dummy_funcs, + DRM_MODE_CONNECTOR_HDMIA, + &priv->ddc, + 10); + KUNIT_EXPECT_EQ(test, ret, 0); + + prop = connector->max_bpc_property; + KUNIT_ASSERT_NOT_NULL(test, prop); + KUNIT_EXPECT_NOT_NULL(test, drm_mode_obj_find_prop_id(&connector->base, prop->base.id)); + + ret = drm_object_property_get_default_value(&connector->base, prop, &val); + KUNIT_EXPECT_EQ(test, ret, 0); + KUNIT_EXPECT_EQ(test, val, 10); + + state = connector->state; + KUNIT_EXPECT_EQ(test, state->max_bpc, 10); + KUNIT_EXPECT_EQ(test, state->max_requested_bpc, 10); + + prop = priv->drm.mode_config.hdr_output_metadata_property; + KUNIT_ASSERT_NOT_NULL(test, prop); + KUNIT_EXPECT_NOT_NULL(test, drm_mode_obj_find_prop_id(&connector->base, prop->base.id)); +} + +/* + * Test that the registration of a connector with a maximum bpc count of + * 12 succeeds and registers the max bpc and HDR output metadata + * properties. + */ +static void drm_test_connector_hdmi_init_bpc_12(struct kunit *test) +{ + struct drm_connector_init_priv *priv = test->priv; + struct drm_connector_state *state; + struct drm_connector *connector = &priv->connector; + struct drm_property *prop; + uint64_t val; + int ret; + + ret = drmm_connector_hdmi_init(&priv->drm, connector, + &dummy_funcs, + DRM_MODE_CONNECTOR_HDMIA, + &priv->ddc, + 12); + KUNIT_EXPECT_EQ(test, ret, 0); + + prop = connector->max_bpc_property; + KUNIT_ASSERT_NOT_NULL(test, prop); + KUNIT_EXPECT_NOT_NULL(test, drm_mode_obj_find_prop_id(&connector->base, prop->base.id)); + + ret = drm_object_property_get_default_value(&connector->base, prop, &val); + KUNIT_EXPECT_EQ(test, ret, 0); + KUNIT_EXPECT_EQ(test, val, 12); + + state = connector->state; + KUNIT_EXPECT_EQ(test, state->max_bpc, 12); + KUNIT_EXPECT_EQ(test, state->max_requested_bpc, 12); + + prop = priv->drm.mode_config.hdr_output_metadata_property; + KUNIT_ASSERT_NOT_NULL(test, prop); + KUNIT_EXPECT_NOT_NULL(test, drm_mode_obj_find_prop_id(&connector->base, prop->base.id)); +} + /* * Test that the registration of an HDMI connector with an HDMI * connector type succeeds. */ static void drm_test_connector_hdmi_init_type_valid(struct kunit *test) @@ -282,10 +432,15 @@ KUNIT_ARRAY_PARAM(drm_connector_hdmi_init_type_invalid, drm_connector_hdmi_init_type_invalid_tests, drm_connector_hdmi_init_type_desc); static struct kunit_case drmm_connector_hdmi_init_tests[] = { KUNIT_CASE(drm_test_connector_hdmi_init_valid), + KUNIT_CASE(drm_test_connector_hdmi_init_bpc_8), + KUNIT_CASE(drm_test_connector_hdmi_init_bpc_10), + KUNIT_CASE(drm_test_connector_hdmi_init_bpc_12), + KUNIT_CASE(drm_test_connector_hdmi_init_bpc_invalid), + KUNIT_CASE(drm_test_connector_hdmi_init_bpc_null), KUNIT_CASE(drm_test_connector_hdmi_init_null_ddc), KUNIT_CASE_PARAM(drm_test_connector_hdmi_init_type_valid, drm_connector_hdmi_init_type_valid_gen_params), KUNIT_CASE_PARAM(drm_test_connector_hdmi_init_type_invalid, drm_connector_hdmi_init_type_invalid_gen_params), diff --git a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c new file mode 100644 index 000000000000..3ecae50ef47f --- /dev/null +++ b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c @@ -0,0 +1,438 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * Kunit test for drm_hdmi_state_helper functions + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "../drm_crtc_internal.h" + +#include + +#include "drm_kunit_edid.h" + +struct drm_atomic_helper_connector_hdmi_priv { + struct drm_device drm; + struct drm_plane *plane; + struct drm_crtc *crtc; + struct drm_encoder encoder; + struct drm_connector connector; + + const char *current_edid; + size_t current_edid_len; +}; + +#define connector_to_priv(c) \ + container_of_const(c, struct drm_atomic_helper_connector_hdmi_priv, connector) + +static struct drm_display_mode *find_preferred_mode(struct drm_connector *connector) +{ + struct drm_device *drm = connector->dev; + struct drm_display_mode *mode, *preferred; + + mutex_lock(&drm->mode_config.mutex); + preferred = list_first_entry(&connector->modes, struct drm_display_mode, head); + list_for_each_entry(mode, &connector->modes, head) + if (mode->type & DRM_MODE_TYPE_PREFERRED) + preferred = mode; + mutex_unlock(&drm->mode_config.mutex); + + return preferred; +} + +static int light_up_connector(struct kunit *test, + struct drm_device *drm, + struct drm_crtc *crtc, + struct drm_connector *connector, + struct drm_display_mode *mode, + struct drm_modeset_acquire_ctx *ctx) +{ + struct drm_atomic_state *state; + struct drm_connector_state *conn_state; + struct drm_crtc_state *crtc_state; + int ret; + + state = drm_kunit_helper_atomic_state_alloc(test, drm, ctx); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state); + + conn_state = drm_atomic_get_connector_state(state, connector); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state); + + ret = drm_atomic_set_crtc_for_connector(conn_state, crtc); + KUNIT_EXPECT_EQ(test, ret, 0); + + crtc_state = drm_atomic_get_crtc_state(state, crtc); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state); + + ret = drm_atomic_set_mode_for_crtc(crtc_state, mode); + KUNIT_EXPECT_EQ(test, ret, 0); + + crtc_state->enable = true; + crtc_state->active = true; + + ret = drm_atomic_commit(state); + KUNIT_ASSERT_EQ(test, ret, 0); + + return 0; +} + +static int set_connector_edid(struct kunit *test, struct drm_connector *connector, + const char *edid, size_t edid_len) +{ + struct drm_atomic_helper_connector_hdmi_priv *priv = + connector_to_priv(connector); + struct drm_device *drm = connector->dev; + int ret; + + priv->current_edid = edid; + priv->current_edid_len = edid_len; + + mutex_lock(&drm->mode_config.mutex); + ret = connector->funcs->fill_modes(connector, 4096, 4096); + mutex_unlock(&drm->mode_config.mutex); + KUNIT_ASSERT_GT(test, ret, 0); + + return 0; +} + +static int dummy_connector_get_modes(struct drm_connector *connector) +{ + struct drm_atomic_helper_connector_hdmi_priv *priv = + connector_to_priv(connector); + const struct drm_edid *edid; + unsigned int num_modes; + + edid = drm_edid_alloc(priv->current_edid, priv->current_edid_len); + if (!edid) + return -EINVAL; + + drm_edid_connector_update(connector, edid); + num_modes = drm_edid_connector_add_modes(connector); + + drm_edid_free(edid); + + return num_modes; +} + +static const struct drm_connector_helper_funcs dummy_connector_helper_funcs = { + .atomic_check = drm_atomic_helper_connector_hdmi_check, + .get_modes = dummy_connector_get_modes, +}; + +static void dummy_hdmi_connector_reset(struct drm_connector *connector) +{ + drm_atomic_helper_connector_reset(connector); + __drm_atomic_helper_connector_hdmi_reset(connector, connector->state); +} + +static const struct drm_connector_funcs dummy_connector_funcs = { + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .fill_modes = drm_helper_probe_single_connector_modes, + .reset = dummy_hdmi_connector_reset, +}; + +static +struct drm_atomic_helper_connector_hdmi_priv * +drm_atomic_helper_connector_hdmi_init(struct kunit *test, + unsigned int max_bpc) +{ + struct drm_atomic_helper_connector_hdmi_priv *priv; + struct drm_connector *conn; + struct drm_encoder *enc; + struct drm_device *drm; + struct device *dev; + int ret; + + dev = drm_kunit_helper_alloc_device(test); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev); + + priv = drm_kunit_helper_alloc_drm_device(test, dev, + struct drm_atomic_helper_connector_hdmi_priv, drm, + DRIVER_MODESET | DRIVER_ATOMIC); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv); + test->priv = priv; + + drm = &priv->drm; + priv->plane = drm_kunit_helper_create_primary_plane(test, drm, + NULL, + NULL, + NULL, 0, + NULL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->plane); + + priv->crtc = drm_kunit_helper_create_crtc(test, drm, + priv->plane, NULL, + NULL, + NULL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->crtc); + + enc = &priv->encoder; + ret = drmm_encoder_init(drm, enc, NULL, DRM_MODE_ENCODER_TMDS, NULL); + KUNIT_ASSERT_EQ(test, ret, 0); + + enc->possible_crtcs = drm_crtc_mask(priv->crtc); + + conn = &priv->connector; + ret = drmm_connector_hdmi_init(drm, conn, + &dummy_connector_funcs, + DRM_MODE_CONNECTOR_HDMIA, + NULL, + max_bpc); + KUNIT_ASSERT_EQ(test, ret, 0); + + drm_connector_helper_add(conn, &dummy_connector_helper_funcs); + drm_connector_attach_encoder(conn, enc); + + drm_mode_config_reset(drm); + + ret = set_connector_edid(test, conn, + test_edid_hdmi_1080p_rgb_max_200mhz, + ARRAY_SIZE(test_edid_hdmi_1080p_rgb_max_200mhz)); + KUNIT_ASSERT_EQ(test, ret, 0); + + return priv; +} + +/* + * Test that if we change the maximum bpc property to a different value, + * we trigger a mode change on the connector's CRTC, which will in turn + * disable/enable the connector. + */ +static void drm_test_check_output_bpc_crtc_mode_changed(struct kunit *test) +{ + struct drm_atomic_helper_connector_hdmi_priv *priv; + struct drm_modeset_acquire_ctx *ctx; + struct drm_connector_state *old_conn_state; + struct drm_connector_state *new_conn_state; + struct drm_crtc_state *crtc_state; + struct drm_atomic_state *state; + struct drm_display_mode *preferred; + struct drm_connector *conn; + struct drm_device *drm; + struct drm_crtc *crtc; + int ret; + + priv = drm_atomic_helper_connector_hdmi_init(test, 10); + KUNIT_ASSERT_NOT_NULL(test, priv); + + ctx = drm_kunit_helper_acquire_ctx_alloc(test); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); + + conn = &priv->connector; + preferred = find_preferred_mode(conn); + KUNIT_ASSERT_NOT_NULL(test, preferred); + + drm = &priv->drm; + crtc = priv->crtc; + ret = light_up_connector(test, drm, crtc, conn, preferred, ctx); + KUNIT_ASSERT_EQ(test, ret, 0); + + state = drm_kunit_helper_atomic_state_alloc(test, drm, ctx); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state); + + new_conn_state = drm_atomic_get_connector_state(state, conn); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_conn_state); + + old_conn_state = drm_atomic_get_old_connector_state(state, conn); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, old_conn_state); + + new_conn_state->hdmi.output_bpc = 8; + + KUNIT_ASSERT_NE(test, + old_conn_state->hdmi.output_bpc, + new_conn_state->hdmi.output_bpc); + + ret = drm_atomic_check_only(state); + KUNIT_ASSERT_EQ(test, ret, 0); + + old_conn_state = drm_atomic_get_old_connector_state(state, conn); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, old_conn_state); + + new_conn_state = drm_atomic_get_new_connector_state(state, conn); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_conn_state); + + KUNIT_ASSERT_NE(test, + old_conn_state->hdmi.output_bpc, + new_conn_state->hdmi.output_bpc); + + crtc_state = drm_atomic_get_new_crtc_state(state, crtc); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state); + KUNIT_EXPECT_TRUE(test, crtc_state->mode_changed); +} + +/* + * Test that if we set the output bpc property to the same value, we + * don't trigger a mode change on the connector's CRTC and leave the + * connector unaffected. + */ +static void drm_test_check_output_bpc_crtc_mode_not_changed(struct kunit *test) +{ + struct drm_atomic_helper_connector_hdmi_priv *priv; + struct drm_modeset_acquire_ctx *ctx; + struct drm_connector_state *old_conn_state; + struct drm_connector_state *new_conn_state; + struct drm_crtc_state *crtc_state; + struct drm_atomic_state *state; + struct drm_display_mode *preferred; + struct drm_connector *conn; + struct drm_device *drm; + struct drm_crtc *crtc; + int ret; + + priv = drm_atomic_helper_connector_hdmi_init(test, 10); + KUNIT_ASSERT_NOT_NULL(test, priv); + + ctx = drm_kunit_helper_acquire_ctx_alloc(test); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); + + conn = &priv->connector; + preferred = find_preferred_mode(conn); + KUNIT_ASSERT_NOT_NULL(test, preferred); + + drm = &priv->drm; + crtc = priv->crtc; + ret = light_up_connector(test, drm, crtc, conn, preferred, ctx); + KUNIT_ASSERT_EQ(test, ret, 0); + + state = drm_kunit_helper_atomic_state_alloc(test, drm, ctx); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state); + + new_conn_state = drm_atomic_get_connector_state(state, conn); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_conn_state); + + old_conn_state = drm_atomic_get_old_connector_state(state, conn); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, old_conn_state); + + KUNIT_ASSERT_EQ(test, + new_conn_state->hdmi.output_bpc, + old_conn_state->hdmi.output_bpc); + + ret = drm_atomic_check_only(state); + KUNIT_ASSERT_EQ(test, ret, 0); + + old_conn_state = drm_atomic_get_old_connector_state(state, conn); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, old_conn_state); + + new_conn_state = drm_atomic_get_new_connector_state(state, conn); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_conn_state); + + KUNIT_EXPECT_EQ(test, + old_conn_state->hdmi.output_bpc, + new_conn_state->hdmi.output_bpc); + + crtc_state = drm_atomic_get_new_crtc_state(state, crtc); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state); + KUNIT_EXPECT_FALSE(test, crtc_state->mode_changed); +} + +static struct kunit_case drm_atomic_helper_connector_hdmi_check_tests[] = { + KUNIT_CASE(drm_test_check_output_bpc_crtc_mode_changed), + KUNIT_CASE(drm_test_check_output_bpc_crtc_mode_not_changed), + { } +}; + +static struct kunit_suite drm_atomic_helper_connector_hdmi_check_test_suite = { + .name = "drm_atomic_helper_connector_hdmi_check", + .test_cases = drm_atomic_helper_connector_hdmi_check_tests, +}; + +/* + * Test that if the connector was initialised with a maximum bpc of 8, + * the value of the max_bpc and max_requested_bpc properties out of + * reset are also set to 8, and output_bpc is set to 0 and will be + * filled at atomic_check time. + */ +static void drm_test_check_bpc_8_value(struct kunit *test) +{ + struct drm_atomic_helper_connector_hdmi_priv *priv; + struct drm_connector_state *conn_state; + struct drm_connector *conn; + + priv = drm_atomic_helper_connector_hdmi_init(test, 8); + KUNIT_ASSERT_NOT_NULL(test, priv); + + conn = &priv->connector; + conn_state = conn->state; + KUNIT_EXPECT_EQ(test, conn_state->max_bpc, 8); + KUNIT_EXPECT_EQ(test, conn_state->max_requested_bpc, 8); + KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 0); +} + +/* + * Test that if the connector was initialised with a maximum bpc of 10, + * the value of the max_bpc and max_requested_bpc properties out of + * reset are also set to 10, and output_bpc is set to 0 and will be + * filled at atomic_check time. + */ +static void drm_test_check_bpc_10_value(struct kunit *test) +{ + struct drm_atomic_helper_connector_hdmi_priv *priv; + struct drm_connector_state *conn_state; + struct drm_connector *conn; + + priv = drm_atomic_helper_connector_hdmi_init(test, 10); + KUNIT_ASSERT_NOT_NULL(test, priv); + + conn = &priv->connector; + conn_state = conn->state; + KUNIT_EXPECT_EQ(test, conn_state->max_bpc, 10); + KUNIT_EXPECT_EQ(test, conn_state->max_requested_bpc, 10); + KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 0); +} + +/* + * Test that if the connector was initialised with a maximum bpc of 12, + * the value of the max_bpc and max_requested_bpc properties out of + * reset are also set to 12, and output_bpc is set to 0 and will be + * filled at atomic_check time. + */ +static void drm_test_check_bpc_12_value(struct kunit *test) +{ + struct drm_atomic_helper_connector_hdmi_priv *priv; + struct drm_connector_state *conn_state; + struct drm_connector *conn; + + priv = drm_atomic_helper_connector_hdmi_init(test, 12); + KUNIT_ASSERT_NOT_NULL(test, priv); + + conn = &priv->connector; + conn_state = conn->state; + KUNIT_EXPECT_EQ(test, conn_state->max_bpc, 12); + KUNIT_EXPECT_EQ(test, conn_state->max_requested_bpc, 12); + KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 0); +} + +static struct kunit_case drm_atomic_helper_connector_hdmi_reset_tests[] = { + KUNIT_CASE(drm_test_check_bpc_8_value), + KUNIT_CASE(drm_test_check_bpc_10_value), + KUNIT_CASE(drm_test_check_bpc_12_value), + { } +}; + +static struct kunit_suite drm_atomic_helper_connector_hdmi_reset_test_suite = { + .name = "drm_atomic_helper_connector_hdmi_reset", + .test_cases = drm_atomic_helper_connector_hdmi_reset_tests, +}; + +kunit_test_suites( + &drm_atomic_helper_connector_hdmi_check_test_suite, + &drm_atomic_helper_connector_hdmi_reset_test_suite, +); + +MODULE_AUTHOR("Maxime Ripard "); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/tests/drm_kunit_edid.h b/drivers/gpu/drm/tests/drm_kunit_edid.h new file mode 100644 index 000000000000..0366dd29c820 --- /dev/null +++ b/drivers/gpu/drm/tests/drm_kunit_edid.h @@ -0,0 +1,106 @@ +#ifndef DRM_KUNIT_EDID_H_ +#define DRM_KUNIT_EDID_H_ + +/* + * edid-decode (hex): + * + * 00 ff ff ff ff ff ff 00 31 d8 2a 00 00 00 00 00 + * 00 21 01 03 81 a0 5a 78 02 00 00 00 00 00 00 00 + * 00 00 00 20 00 00 01 01 01 01 01 01 01 01 01 01 + * 01 01 01 01 01 01 02 3a 80 18 71 38 2d 40 58 2c + * 45 00 40 84 63 00 00 1e 00 00 00 fc 00 54 65 73 + * 74 20 45 44 49 44 0a 20 20 20 00 00 00 fd 00 32 + * 46 1e 46 0f 00 0a 20 20 20 20 20 20 00 00 00 10 + * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 92 + * + * 02 03 1b 81 e3 05 00 20 41 10 e2 00 4a 6d 03 0c + * 00 12 34 00 28 20 00 00 00 00 00 00 00 00 00 00 + * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 d0 + * + * ---------------- + * + * Block 0, Base EDID: + * EDID Structure Version & Revision: 1.3 + * Vendor & Product Identification: + * Manufacturer: LNX + * Model: 42 + * Made in: 2023 + * Basic Display Parameters & Features: + * Digital display + * DFP 1.x compatible TMDS + * Maximum image size: 160 cm x 90 cm + * Gamma: 2.20 + * Monochrome or grayscale display + * First detailed timing is the preferred timing + * Color Characteristics: + * Red : 0.0000, 0.0000 + * Green: 0.0000, 0.0000 + * Blue : 0.0000, 0.0000 + * White: 0.0000, 0.0000 + * Established Timings I & II: + * DMT 0x04: 640x480 59.940476 Hz 4:3 31.469 kHz 25.175000 MHz + * Standard Timings: none + * Detailed Timing Descriptors: + * DTD 1: 1920x1080 60.000000 Hz 16:9 67.500 kHz 148.500000 MHz (1600 mm x 900 mm) + * Hfront 88 Hsync 44 Hback 148 Hpol P + * Vfront 4 Vsync 5 Vback 36 Vpol P + * Display Product Name: 'Test EDID' + * Display Range Limits: + * Monitor ranges (GTF): 50-70 Hz V, 30-70 kHz H, max dotclock 150 MHz + * Dummy Descriptor: + * Extension blocks: 1 + * Checksum: 0x92 + * + * ---------------- + * + * Block 1, CTA-861 Extension Block: + * Revision: 3 + * Underscans IT Video Formats by default + * Native detailed modes: 1 + * Colorimetry Data Block: + * sRGB + * Video Data Block: + * VIC 16: 1920x1080 60.000000 Hz 16:9 67.500 kHz 148.500000 MHz + * Video Capability Data Block: + * YCbCr quantization: No Data + * RGB quantization: Selectable (via AVI Q) + * PT scan behavior: No Data + * IT scan behavior: Always Underscanned + * CE scan behavior: Always Underscanned + * Vendor-Specific Data Block (HDMI), OUI 00-0C-03: + * Source physical address: 1.2.3.4 + * Maximum TMDS clock: 200 MHz + * Extended HDMI video details: + * Checksum: 0xd0 Unused space in Extension Block: 100 bytes + */ +static const unsigned char test_edid_hdmi_1080p_rgb_max_200mhz[] = { + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x31, 0xd8, 0x2a, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x01, 0x03, 0x81, 0xa0, 0x5a, 0x78, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3a, 0x80, 0x18, 0x71, 0x38, + 0x2d, 0x40, 0x58, 0x2c, 0x45, 0x00, 0x40, 0x84, 0x63, 0x00, 0x00, 0x1e, + 0x00, 0x00, 0x00, 0xfc, 0x00, 0x54, 0x65, 0x73, 0x74, 0x20, 0x45, 0x44, + 0x49, 0x44, 0x0a, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x32, + 0x46, 0x00, 0x00, 0xc4, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x41, 0x02, 0x03, 0x1b, 0x81, + 0xe3, 0x05, 0x00, 0x20, 0x41, 0x10, 0xe2, 0x00, 0x4a, 0x6d, 0x03, 0x0c, + 0x00, 0x12, 0x34, 0x00, 0x28, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xd0 +}; + +#endif // DRM_KUNIT_EDID_H_ From patchwork Mon May 27 13:57:57 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Maxime Ripard X-Patchwork-Id: 799369 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 33E89161325; Mon, 27 May 2024 13:58:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716818311; cv=none; b=DwbglhG1f3vi+uiUtd+mB4JWYQhojMseTKxiFkwdeJxKvXOFJVSZDFcjrlEXfb73WUXCjNlJbc/GTz9Q+JbyQld6BRrfGHDLU4Z6MON97TGEMtoma2gEczw2kgbZMemPyNw60x7ILRuGq67juvv+HhqnH042XXYGa8WWCjj7rnY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716818311; c=relaxed/simple; bh=SOQPfNrUwyqfTmtStDudqnm+AIbryO28dU1DQhlSVNA=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=fvHtiTPPGQiB38GD/HbMBzL0xZb0m+2lBiv0WuX1WRN+rKB8OLjNDn3Vr6HUBH5yFHdLXTUey+DZyoD+QDr9VJWVFi2nCTbP7PPCQxlyNKg926dwzKH+fQmRQ7HqWqeaWKsMoixuk0ckp5ozWXGsxcVi6+TJj8y/fYVZ2tz+EEE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=A5t1oU+F; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="A5t1oU+F" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 91C48C4AF08; Mon, 27 May 2024 13:58:30 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1716818311; bh=SOQPfNrUwyqfTmtStDudqnm+AIbryO28dU1DQhlSVNA=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=A5t1oU+Fa3Jeawwrep/wT9yuKMMZ2wZoE965Z9B4b2FiXwC3x3QQxH2KQs9jXizyZ gnfpnzuN81RwA4EmaEZ3R/PGpHizbAwh+yv12DrWlmfC0EOBsWD56qsM4SReyzgpfZ ARxmx88hFYkrCP6YfmmTHh+aGeZtilz6Nt0ASGbyFdY02fmGrfo9QAoTJH0AVVTQVL imY7fZSpcshW3gbZdhrYx5C+B4+HmutroOgftsjRsH6bUGCT3HfQOd9fdsJPSSxreN hIwZBYfsmzVjKe+T5pmClCemDwccLYwKU2CLOS0iy6GUueD7Yia2dAevq1ywVv891R +58pnbUYiHRGg== From: Maxime Ripard Date: Mon, 27 May 2024 15:57:57 +0200 Subject: [PATCH v15 08/29] drm/tests: Add output formats tests Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20240527-kms-hdmi-connector-state-v15-8-c5af16c3aae2@kernel.org> References: <20240527-kms-hdmi-connector-state-v15-0-c5af16c3aae2@kernel.org> In-Reply-To: <20240527-kms-hdmi-connector-state-v15-0-c5af16c3aae2@kernel.org> To: Maarten Lankhorst , Thomas Zimmermann , David Airlie , Daniel Vetter , Jonathan Corbet , Sandy Huang , =?utf-8?q?Heiko_St=C3=BCbner?= , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Andy Yan Cc: Hans Verkuil , Sebastian Wick , =?utf-8?b?VmlsbGUgU3lyasOkbMOk?= , dri-devel@lists.freedesktop.org, linux-arm-kernel@lists.infradead.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-rockchip@lists.infradead.org, linux-sunxi@lists.linux.dev, Maxime Ripard , Dave Stevenson , Dmitry Baryshkov X-Mailer: b4 0.13.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=8085; i=mripard@kernel.org; h=from:subject:message-id; bh=SOQPfNrUwyqfTmtStDudqnm+AIbryO28dU1DQhlSVNA=; b=owGbwMvMwCmsHn9OcpHtvjLG02pJDGkhE5Mn371k9kp7FdMnvqUOf9Y4p+7J6Ty+pz/y+NRty 6viDx3e0zGVhUGYk0FWTJHliUzY6eXti6sc7Ff+gJnDygQyhIGLUwAmMmkqY30OW7+EXrrz9p7t m5OVVOInP94uo7U0btrKk8mH5gWwJ5Xzr530IYBr+fSH8ZwVJ5qf/mJs2LS/7LvNrZrP23tWMwh +tl7jqeh9vaJx6rukgI6Zpq+OXDpq90r+v+O27ueNR7rPF6beAAA= X-Developer-Key: i=mripard@kernel.org; a=openpgp; fpr=BE5675C37E818C8B5764241C254BCFC56BF6CE8D Now that we track the HDMI output format as part of the connector state, let's add a few tests to make sure it works as expected. Reviewed-by: Dave Stevenson Reviewed-by: Dmitry Baryshkov Signed-off-by: Maxime Ripard --- drivers/gpu/drm/tests/drm_connector_test.c | 99 +++++++++++++++++++++- drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 32 +++++++ 2 files changed, 130 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/tests/drm_connector_test.c b/drivers/gpu/drm/tests/drm_connector_test.c index 37e6efd46d7e..250348ddfa70 100644 --- a/drivers/gpu/drm/tests/drm_connector_test.c +++ b/drivers/gpu/drm/tests/drm_connector_test.c @@ -361,10 +361,46 @@ static void drm_test_connector_hdmi_init_bpc_12(struct kunit *test) prop = priv->drm.mode_config.hdr_output_metadata_property; KUNIT_ASSERT_NOT_NULL(test, prop); KUNIT_EXPECT_NOT_NULL(test, drm_mode_obj_find_prop_id(&connector->base, prop->base.id)); } +/* + * Test that the registration of an HDMI connector with no supported + * format fails. + */ +static void drm_test_connector_hdmi_init_formats_empty(struct kunit *test) +{ + struct drm_connector_init_priv *priv = test->priv; + int ret; + + ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector, + &dummy_funcs, + DRM_MODE_CONNECTOR_HDMIA, + &priv->ddc, + 0, + 8); + KUNIT_EXPECT_LT(test, ret, 0); +} + +/* + * Test that the registration of an HDMI connector not listing RGB as a + * supported format fails. + */ +static void drm_test_connector_hdmi_init_formats_no_rgb(struct kunit *test) +{ + struct drm_connector_init_priv *priv = test->priv; + int ret; + + ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector, + &dummy_funcs, + DRM_MODE_CONNECTOR_HDMIA, + &priv->ddc, + BIT(HDMI_COLORSPACE_YUV422), + 8); + KUNIT_EXPECT_LT(test, ret, 0); +} + /* * Test that the registration of an HDMI connector with an HDMI * connector type succeeds. */ static void drm_test_connector_hdmi_init_type_valid(struct kunit *test) @@ -446,10 +482,12 @@ static struct kunit_case drmm_connector_hdmi_init_tests[] = { KUNIT_CASE(drm_test_connector_hdmi_init_bpc_8), KUNIT_CASE(drm_test_connector_hdmi_init_bpc_10), KUNIT_CASE(drm_test_connector_hdmi_init_bpc_12), KUNIT_CASE(drm_test_connector_hdmi_init_bpc_invalid), KUNIT_CASE(drm_test_connector_hdmi_init_bpc_null), + KUNIT_CASE(drm_test_connector_hdmi_init_formats_empty), + KUNIT_CASE(drm_test_connector_hdmi_init_formats_no_rgb), KUNIT_CASE(drm_test_connector_hdmi_init_null_ddc), KUNIT_CASE_PARAM(drm_test_connector_hdmi_init_type_valid, drm_connector_hdmi_init_type_valid_gen_params), KUNIT_CASE_PARAM(drm_test_connector_hdmi_init_type_invalid, drm_connector_hdmi_init_type_invalid_gen_params), @@ -523,13 +561,72 @@ static struct kunit_case drm_get_tv_mode_from_name_tests[] = { static struct kunit_suite drm_get_tv_mode_from_name_test_suite = { .name = "drm_get_tv_mode_from_name", .test_cases = drm_get_tv_mode_from_name_tests, }; +struct drm_hdmi_connector_get_output_format_name_test { + unsigned int kind; + const char *expected_name; +}; + +#define OUTPUT_FORMAT_TEST(_kind, _name) \ + { \ + .kind = _kind, \ + .expected_name = _name, \ + } + +static void drm_test_drm_hdmi_connector_get_output_format_name(struct kunit *test) +{ + const struct drm_hdmi_connector_get_output_format_name_test *params = + test->param_value; + + KUNIT_EXPECT_STREQ(test, + drm_hdmi_connector_get_output_format_name(params->kind), + params->expected_name); +} + +static const +struct drm_hdmi_connector_get_output_format_name_test +drm_hdmi_connector_get_output_format_name_valid_tests[] = { + OUTPUT_FORMAT_TEST(HDMI_COLORSPACE_RGB, "RGB"), + OUTPUT_FORMAT_TEST(HDMI_COLORSPACE_YUV420, "YUV 4:2:0"), + OUTPUT_FORMAT_TEST(HDMI_COLORSPACE_YUV422, "YUV 4:2:2"), + OUTPUT_FORMAT_TEST(HDMI_COLORSPACE_YUV444, "YUV 4:4:4"), +}; + +static void +drm_hdmi_connector_get_output_format_name_valid_desc(const struct drm_hdmi_connector_get_output_format_name_test *t, + char *desc) +{ + sprintf(desc, "%s", t->expected_name); +} + +KUNIT_ARRAY_PARAM(drm_hdmi_connector_get_output_format_name_valid, + drm_hdmi_connector_get_output_format_name_valid_tests, + drm_hdmi_connector_get_output_format_name_valid_desc); + +static void drm_test_drm_hdmi_connector_get_output_format_name_invalid(struct kunit *test) +{ + KUNIT_EXPECT_NULL(test, drm_hdmi_connector_get_output_format_name(4)); +}; + +static struct kunit_case drm_hdmi_connector_get_output_format_name_tests[] = { + KUNIT_CASE_PARAM(drm_test_drm_hdmi_connector_get_output_format_name, + drm_hdmi_connector_get_output_format_name_valid_gen_params), + KUNIT_CASE(drm_test_drm_hdmi_connector_get_output_format_name_invalid), + { } +}; + +static struct kunit_suite drm_hdmi_connector_get_output_format_name_test_suite = { + .name = "drm_hdmi_connector_get_output_format_name", + .test_cases = drm_hdmi_connector_get_output_format_name_tests, +}; + kunit_test_suites( &drmm_connector_hdmi_init_test_suite, &drmm_connector_init_test_suite, - &drm_get_tv_mode_from_name_test_suite + &drm_get_tv_mode_from_name_test_suite, + &drm_hdmi_connector_get_output_format_name_test_suite ); MODULE_AUTHOR("Maxime Ripard "); MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c index 333c81b8cf4f..8bc1f9b0b12b 100644 --- a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c +++ b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c @@ -347,10 +347,19 @@ static void drm_test_check_output_bpc_crtc_mode_not_changed(struct kunit *test) } static struct kunit_case drm_atomic_helper_connector_hdmi_check_tests[] = { KUNIT_CASE(drm_test_check_output_bpc_crtc_mode_changed), KUNIT_CASE(drm_test_check_output_bpc_crtc_mode_not_changed), + /* + * TODO: We should have tests to check that a change in the + * format triggers a CRTC mode change just like we do for the + * RGB Quantization and BPC. + * + * However, we don't have any way to control which format gets + * picked up aside from changing the BPC or mode which would + * already trigger a mode change. + */ { } }; static struct kunit_suite drm_atomic_helper_connector_hdmi_check_test_suite = { .name = "drm_atomic_helper_connector_hdmi_check", @@ -427,14 +436,37 @@ static void drm_test_check_bpc_12_value(struct kunit *test) KUNIT_EXPECT_EQ(test, conn_state->max_bpc, 12); KUNIT_EXPECT_EQ(test, conn_state->max_requested_bpc, 12); KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 0); } +/* + * Test that the value of the output format property out of reset is set + * to RGB, even if the driver supports more than that. + */ +static void drm_test_check_format_value(struct kunit *test) +{ + struct drm_atomic_helper_connector_hdmi_priv *priv; + struct drm_connector_state *conn_state; + struct drm_connector *conn; + + priv = drm_atomic_helper_connector_hdmi_init(test, + BIT(HDMI_COLORSPACE_RGB) | + BIT(HDMI_COLORSPACE_YUV422) | + BIT(HDMI_COLORSPACE_YUV444), + 8); + KUNIT_ASSERT_NOT_NULL(test, priv); + + conn = &priv->connector; + conn_state = conn->state; + KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB); +} + static struct kunit_case drm_atomic_helper_connector_hdmi_reset_tests[] = { KUNIT_CASE(drm_test_check_bpc_8_value), KUNIT_CASE(drm_test_check_bpc_10_value), KUNIT_CASE(drm_test_check_bpc_12_value), + KUNIT_CASE(drm_test_check_format_value), { } }; static struct kunit_suite drm_atomic_helper_connector_hdmi_reset_test_suite = { .name = "drm_atomic_helper_connector_hdmi_reset", From patchwork Mon May 27 13:57:59 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Maxime Ripard X-Patchwork-Id: 799368 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 CEE3416ABC6; Mon, 27 May 2024 13:58:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716818316; cv=none; b=b11T7YOmPKDUL12vXwzWJITjEg0avsUY99qC3Z/0Nmlphi9gZBIn0DY4ME1FwMT2eogpP/k3QZNzdg7YwJO90DaY79ky7aKq5RH38ZLJti5KO3HC9TLKhw5PTmelMQxuxPhx4CIyONCjTv0lC/E+lz+IBL3DGnZ6it1kz8QiRfo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716818316; c=relaxed/simple; bh=e/jwoeoO+PaaNiPn9HPamCKOCJwfe7VB9ubqQTA5C6A=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=KJWrVVd+Mj5OT17frIxRGFEQJHiFlzG1HRf02fdJ6qrHr+rmdnGDXztWeLsH9yFZwHBrLiIKDdI+njWT3CiQxqmx6OAYYR3SekxhExsYBoyfauQ6CkcjBEJ7dNq9r3Ed706dZ/tQQxPhC3h6W5Lg9ImkHlRi3GR94UGdQPm/YS4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=GyUaJ/ol; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="GyUaJ/ol" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 18BF8C4AF07; Mon, 27 May 2024 13:58:35 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1716818316; bh=e/jwoeoO+PaaNiPn9HPamCKOCJwfe7VB9ubqQTA5C6A=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=GyUaJ/olvgDcEdhfMs276D2B4VpJ0y2doSj4yOgIX4vgTJJ+DgpBX1v1IoAJxa34E BklUTJtgkKmvASqqCsVBX+bt1gd53wFiOGsfJfx9c+s/NlGhXkJsFPpt3PPU+pT+a9 Q3F8A8PWc3eFin4wbA2EhK53GAYg022MtZT45fJcPa0269rlbl1HZbRCFunJ9nxDo2 np0bd3jPvnKwPC9kB+V6fKBBF9ESgYYaWAbM2t31GNpq9rEdCla9fwQJMedh2r7e1l UGEn5k1Kpn9Cq/xldElkf7O0smcwpCLpQIXunuZ/TB0E0wdQuTml34fKhErbJsD1FT x1iVGwBFLn6Cw== From: Maxime Ripard Date: Mon, 27 May 2024 15:57:59 +0200 Subject: [PATCH v15 10/29] drm/tests: Add HDMI TDMS character rate tests Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20240527-kms-hdmi-connector-state-v15-10-c5af16c3aae2@kernel.org> References: <20240527-kms-hdmi-connector-state-v15-0-c5af16c3aae2@kernel.org> In-Reply-To: <20240527-kms-hdmi-connector-state-v15-0-c5af16c3aae2@kernel.org> To: Maarten Lankhorst , Thomas Zimmermann , David Airlie , Daniel Vetter , Jonathan Corbet , Sandy Huang , =?utf-8?q?Heiko_St=C3=BCbner?= , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Andy Yan Cc: Hans Verkuil , Sebastian Wick , =?utf-8?b?VmlsbGUgU3lyasOkbMOk?= , dri-devel@lists.freedesktop.org, linux-arm-kernel@lists.infradead.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-rockchip@lists.infradead.org, linux-sunxi@lists.linux.dev, Maxime Ripard , Dave Stevenson X-Mailer: b4 0.13.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=12157; i=mripard@kernel.org; h=from:subject:message-id; bh=e/jwoeoO+PaaNiPn9HPamCKOCJwfe7VB9ubqQTA5C6A=; b=owGbwMvMwCmsHn9OcpHtvjLG02pJDGkhE1M0799RCWiJzGHpmvGf70TSktzFBwsS8wRm72fhP BHnalzXMZWFQZiTQVZMkeWJTNjp5e2LqxzsV/6AmcPKBDKEgYtTACbCF85YnxzCxH7s0EX7rz7/ T1VPNnyXXnHNLPFC/LMtR+8WFLzcPsunyjKhNb2wIX25bPDcKc7+jHW2CxdOymv7lfeg6+7E5pz e0rboy2FzZzkIXL9W5Pb/G5MyJ+tTnZ1/vaJ0fbvntDvlnAUA X-Developer-Key: i=mripard@kernel.org; a=openpgp; fpr=BE5675C37E818C8B5764241C254BCFC56BF6CE8D The previous patch added an helper to compute the TMDS character rate on an HDMI connector. Let's add a few tests to make sure it works as expected. Reviewed-by: Dave Stevenson Signed-off-by: Maxime Ripard Reviewed-by: Dmitry Baryshkov --- drivers/gpu/drm/tests/drm_connector_test.c | 300 +++++++++++++++++++++++++++++ 1 file changed, 300 insertions(+) diff --git a/drivers/gpu/drm/tests/drm_connector_test.c b/drivers/gpu/drm/tests/drm_connector_test.c index 250348ddfa70..8557f722080c 100644 --- a/drivers/gpu/drm/tests/drm_connector_test.c +++ b/drivers/gpu/drm/tests/drm_connector_test.c @@ -6,11 +6,15 @@ #include #include #include #include +#include #include +#include + +#include #include #include "../drm_crtc_internal.h" @@ -619,14 +623,310 @@ static struct kunit_case drm_hdmi_connector_get_output_format_name_tests[] = { static struct kunit_suite drm_hdmi_connector_get_output_format_name_test_suite = { .name = "drm_hdmi_connector_get_output_format_name", .test_cases = drm_hdmi_connector_get_output_format_name_tests, }; +/* + * Test that for a given mode, with 8bpc and an RGB output the TMDS + * character rate is equal to the mode pixel clock. + */ +static void drm_test_drm_hdmi_compute_mode_clock_rgb(struct kunit *test) +{ + struct drm_connector_init_priv *priv = test->priv; + const struct drm_display_mode *mode; + unsigned long long rate; + struct drm_device *drm = &priv->drm; + + mode = drm_display_mode_from_cea_vic(drm, 16); + KUNIT_ASSERT_NOT_NULL(test, mode); + + KUNIT_ASSERT_FALSE(test, mode->flags & DRM_MODE_FLAG_DBLCLK); + + rate = drm_hdmi_compute_mode_clock(mode, 8, HDMI_COLORSPACE_RGB); + KUNIT_ASSERT_GT(test, rate, 0); + KUNIT_EXPECT_EQ(test, mode->clock * 1000ULL, rate); +} + +/* + * Test that for a given mode, with 10bpc and an RGB output the TMDS + * character rate is equal to 1.25 times the mode pixel clock. + */ +static void drm_test_drm_hdmi_compute_mode_clock_rgb_10bpc(struct kunit *test) +{ + struct drm_connector_init_priv *priv = test->priv; + const struct drm_display_mode *mode; + unsigned long long rate; + struct drm_device *drm = &priv->drm; + + mode = drm_display_mode_from_cea_vic(drm, 16); + KUNIT_ASSERT_NOT_NULL(test, mode); + + KUNIT_ASSERT_FALSE(test, mode->flags & DRM_MODE_FLAG_DBLCLK); + + rate = drm_hdmi_compute_mode_clock(mode, 10, HDMI_COLORSPACE_RGB); + KUNIT_ASSERT_GT(test, rate, 0); + KUNIT_EXPECT_EQ(test, mode->clock * 1250, rate); +} + +/* + * Test that for the VIC-1 mode, with 10bpc and an RGB output the TMDS + * character rate computation fails. + */ +static void drm_test_drm_hdmi_compute_mode_clock_rgb_10bpc_vic_1(struct kunit *test) +{ + struct drm_connector_init_priv *priv = test->priv; + const struct drm_display_mode *mode; + unsigned long long rate; + struct drm_device *drm = &priv->drm; + + mode = drm_display_mode_from_cea_vic(drm, 1); + KUNIT_ASSERT_NOT_NULL(test, mode); + + rate = drm_hdmi_compute_mode_clock(mode, 10, HDMI_COLORSPACE_RGB); + KUNIT_EXPECT_EQ(test, rate, 0); +} + +/* + * Test that for a given mode, with 12bpc and an RGB output the TMDS + * character rate is equal to 1.5 times the mode pixel clock. + */ +static void drm_test_drm_hdmi_compute_mode_clock_rgb_12bpc(struct kunit *test) +{ + struct drm_connector_init_priv *priv = test->priv; + const struct drm_display_mode *mode; + unsigned long long rate; + struct drm_device *drm = &priv->drm; + + mode = drm_display_mode_from_cea_vic(drm, 16); + KUNIT_ASSERT_NOT_NULL(test, mode); + + KUNIT_ASSERT_FALSE(test, mode->flags & DRM_MODE_FLAG_DBLCLK); + + rate = drm_hdmi_compute_mode_clock(mode, 12, HDMI_COLORSPACE_RGB); + KUNIT_ASSERT_GT(test, rate, 0); + KUNIT_EXPECT_EQ(test, mode->clock * 1500, rate); +} + +/* + * Test that for the VIC-1 mode, with 12bpc and an RGB output the TMDS + * character rate computation fails. + */ +static void drm_test_drm_hdmi_compute_mode_clock_rgb_12bpc_vic_1(struct kunit *test) +{ + struct drm_connector_init_priv *priv = test->priv; + const struct drm_display_mode *mode; + unsigned long long rate; + struct drm_device *drm = &priv->drm; + + mode = drm_display_mode_from_cea_vic(drm, 1); + KUNIT_ASSERT_NOT_NULL(test, mode); + + rate = drm_hdmi_compute_mode_clock(mode, 12, HDMI_COLORSPACE_RGB); + KUNIT_EXPECT_EQ(test, rate, 0); +} + +/* + * Test that for a mode with the pixel repetition flag, the TMDS + * character rate is indeed double the mode pixel clock. + */ +static void drm_test_drm_hdmi_compute_mode_clock_rgb_double(struct kunit *test) +{ + struct drm_connector_init_priv *priv = test->priv; + const struct drm_display_mode *mode; + unsigned long long rate; + struct drm_device *drm = &priv->drm; + + mode = drm_display_mode_from_cea_vic(drm, 6); + KUNIT_ASSERT_NOT_NULL(test, mode); + + KUNIT_ASSERT_TRUE(test, mode->flags & DRM_MODE_FLAG_DBLCLK); + + rate = drm_hdmi_compute_mode_clock(mode, 8, HDMI_COLORSPACE_RGB); + KUNIT_ASSERT_GT(test, rate, 0); + KUNIT_EXPECT_EQ(test, (mode->clock * 1000ULL) * 2, rate); +} + +/* + * Test that the TMDS character rate computation for the VIC modes + * explicitly listed in the spec as supporting YUV420 succeed and return + * half the mode pixel clock. + */ +static void drm_test_connector_hdmi_compute_mode_clock_yuv420_valid(struct kunit *test) +{ + struct drm_connector_init_priv *priv = test->priv; + const struct drm_display_mode *mode; + struct drm_device *drm = &priv->drm; + unsigned long long rate; + unsigned int vic = *(unsigned int *)test->param_value; + + mode = drm_display_mode_from_cea_vic(drm, vic); + KUNIT_ASSERT_NOT_NULL(test, mode); + + KUNIT_ASSERT_FALSE(test, mode->flags & DRM_MODE_FLAG_DBLCLK); + + rate = drm_hdmi_compute_mode_clock(mode, 8, HDMI_COLORSPACE_YUV420); + KUNIT_ASSERT_GT(test, rate, 0); + KUNIT_EXPECT_EQ(test, (mode->clock * 1000ULL) / 2, rate); +} + +static const unsigned int drm_hdmi_compute_mode_clock_yuv420_vic_valid_tests[] = { + 96, 97, 101, 102, 106, 107, +}; + +static void drm_hdmi_compute_mode_clock_yuv420_vic_desc(const unsigned int *vic, char *desc) +{ + sprintf(desc, "VIC %u", *vic); +} + +KUNIT_ARRAY_PARAM(drm_hdmi_compute_mode_clock_yuv420_valid, + drm_hdmi_compute_mode_clock_yuv420_vic_valid_tests, + drm_hdmi_compute_mode_clock_yuv420_vic_desc); + +/* + * Test that for a given mode listed supporting it and an YUV420 output + * with 10bpc, the TMDS character rate is equal to 0.625 times the mode + * pixel clock. + */ +static void drm_test_connector_hdmi_compute_mode_clock_yuv420_10_bpc(struct kunit *test) +{ + struct drm_connector_init_priv *priv = test->priv; + const struct drm_display_mode *mode; + struct drm_device *drm = &priv->drm; + unsigned int vic = + drm_hdmi_compute_mode_clock_yuv420_vic_valid_tests[0]; + unsigned long long rate; + + mode = drm_display_mode_from_cea_vic(drm, vic); + KUNIT_ASSERT_NOT_NULL(test, mode); + + KUNIT_ASSERT_FALSE(test, mode->flags & DRM_MODE_FLAG_DBLCLK); + + rate = drm_hdmi_compute_mode_clock(mode, 10, HDMI_COLORSPACE_YUV420); + KUNIT_ASSERT_GT(test, rate, 0); + + KUNIT_EXPECT_EQ(test, mode->clock * 625, rate); +} + +/* + * Test that for a given mode listed supporting it and an YUV420 output + * with 12bpc, the TMDS character rate is equal to 0.75 times the mode + * pixel clock. + */ +static void drm_test_connector_hdmi_compute_mode_clock_yuv420_12_bpc(struct kunit *test) +{ + struct drm_connector_init_priv *priv = test->priv; + const struct drm_display_mode *mode; + struct drm_device *drm = &priv->drm; + unsigned int vic = + drm_hdmi_compute_mode_clock_yuv420_vic_valid_tests[0]; + unsigned long long rate; + + mode = drm_display_mode_from_cea_vic(drm, vic); + KUNIT_ASSERT_NOT_NULL(test, mode); + + KUNIT_ASSERT_FALSE(test, mode->flags & DRM_MODE_FLAG_DBLCLK); + + rate = drm_hdmi_compute_mode_clock(mode, 12, HDMI_COLORSPACE_YUV420); + KUNIT_ASSERT_GT(test, rate, 0); + + KUNIT_EXPECT_EQ(test, mode->clock * 750, rate); +} + +/* + * Test that for a given mode, the computation of the TMDS character + * rate with 8bpc and a YUV422 output succeeds and returns a rate equal + * to the mode pixel clock. + */ +static void drm_test_connector_hdmi_compute_mode_clock_yuv422_8_bpc(struct kunit *test) +{ + struct drm_connector_init_priv *priv = test->priv; + const struct drm_display_mode *mode; + struct drm_device *drm = &priv->drm; + unsigned long long rate; + + mode = drm_display_mode_from_cea_vic(drm, 16); + KUNIT_ASSERT_NOT_NULL(test, mode); + + KUNIT_ASSERT_FALSE(test, mode->flags & DRM_MODE_FLAG_DBLCLK); + + rate = drm_hdmi_compute_mode_clock(mode, 8, HDMI_COLORSPACE_YUV422); + KUNIT_ASSERT_GT(test, rate, 0); + KUNIT_EXPECT_EQ(test, mode->clock * 1000, rate); +} + +/* + * Test that for a given mode, the computation of the TMDS character + * rate with 10bpc and a YUV422 output succeeds and returns a rate equal + * to the mode pixel clock. + */ +static void drm_test_connector_hdmi_compute_mode_clock_yuv422_10_bpc(struct kunit *test) +{ + struct drm_connector_init_priv *priv = test->priv; + const struct drm_display_mode *mode; + struct drm_device *drm = &priv->drm; + unsigned long long rate; + + mode = drm_display_mode_from_cea_vic(drm, 16); + KUNIT_ASSERT_NOT_NULL(test, mode); + + KUNIT_ASSERT_FALSE(test, mode->flags & DRM_MODE_FLAG_DBLCLK); + + rate = drm_hdmi_compute_mode_clock(mode, 10, HDMI_COLORSPACE_YUV422); + KUNIT_ASSERT_GT(test, rate, 0); + KUNIT_EXPECT_EQ(test, mode->clock * 1000, rate); +} + +/* + * Test that for a given mode, the computation of the TMDS character + * rate with 12bpc and a YUV422 output succeeds and returns a rate equal + * to the mode pixel clock. + */ +static void drm_test_connector_hdmi_compute_mode_clock_yuv422_12_bpc(struct kunit *test) +{ + struct drm_connector_init_priv *priv = test->priv; + const struct drm_display_mode *mode; + struct drm_device *drm = &priv->drm; + unsigned long long rate; + + mode = drm_display_mode_from_cea_vic(drm, 16); + KUNIT_ASSERT_NOT_NULL(test, mode); + + KUNIT_ASSERT_FALSE(test, mode->flags & DRM_MODE_FLAG_DBLCLK); + + rate = drm_hdmi_compute_mode_clock(mode, 12, HDMI_COLORSPACE_YUV422); + KUNIT_ASSERT_GT(test, rate, 0); + KUNIT_EXPECT_EQ(test, mode->clock * 1000, rate); +} + +static struct kunit_case drm_hdmi_compute_mode_clock_tests[] = { + KUNIT_CASE(drm_test_drm_hdmi_compute_mode_clock_rgb), + KUNIT_CASE(drm_test_drm_hdmi_compute_mode_clock_rgb_10bpc), + KUNIT_CASE(drm_test_drm_hdmi_compute_mode_clock_rgb_10bpc_vic_1), + KUNIT_CASE(drm_test_drm_hdmi_compute_mode_clock_rgb_12bpc), + KUNIT_CASE(drm_test_drm_hdmi_compute_mode_clock_rgb_12bpc_vic_1), + KUNIT_CASE(drm_test_drm_hdmi_compute_mode_clock_rgb_double), + KUNIT_CASE_PARAM(drm_test_connector_hdmi_compute_mode_clock_yuv420_valid, + drm_hdmi_compute_mode_clock_yuv420_valid_gen_params), + KUNIT_CASE(drm_test_connector_hdmi_compute_mode_clock_yuv420_10_bpc), + KUNIT_CASE(drm_test_connector_hdmi_compute_mode_clock_yuv420_12_bpc), + KUNIT_CASE(drm_test_connector_hdmi_compute_mode_clock_yuv422_8_bpc), + KUNIT_CASE(drm_test_connector_hdmi_compute_mode_clock_yuv422_10_bpc), + KUNIT_CASE(drm_test_connector_hdmi_compute_mode_clock_yuv422_12_bpc), + { } +}; + +static struct kunit_suite drm_hdmi_compute_mode_clock_test_suite = { + .name = "drm_test_connector_hdmi_compute_mode_clock", + .init = drm_test_connector_init, + .test_cases = drm_hdmi_compute_mode_clock_tests, +}; + kunit_test_suites( &drmm_connector_hdmi_init_test_suite, &drmm_connector_init_test_suite, &drm_get_tv_mode_from_name_test_suite, + &drm_hdmi_compute_mode_clock_test_suite, &drm_hdmi_connector_get_output_format_name_test_suite ); MODULE_AUTHOR("Maxime Ripard "); MODULE_LICENSE("GPL"); From patchwork Mon May 27 13:58:01 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Maxime Ripard X-Patchwork-Id: 799367 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 EBA1D16C687; Mon, 27 May 2024 13:58:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716818322; cv=none; b=Icv+aS3B0gnXySL1+DVCjmUyj5mCc3TRVLmEli1abdNZj7MnzwJy3OYY05+U/aYX/ThKinz8H79IVBnCXvUSOLlqrOuM2ON0/fNjv20zGD3o7kjf3MwhDQrloy9g1DZl8NXKnFAyN+eDEIqmay4Bs3/EeFXVmYp44oLGcdlZhlA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716818322; c=relaxed/simple; bh=I2SW5zw4dbiQrycUx9m42OMTiEZTjTZWhIvvZr1l95Q=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=LfFzeUVLRT2K+sJqEWCMmu9nxsQRVaodHMLOIuggeijg5BaPlrN+2jm9Jlv6b6r/wUNSQGk0n82X5+eA0+Ch6IMgcn6ewYkDW1g0Ask32j36XHwAbE7jEoPoc4KvEWBqCEZ0hz/dHZIvWetsl3TxkRfl549LWywDpSjGoilWmxg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=t/Qgygbb; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="t/Qgygbb" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 7B1D2C4AF08; Mon, 27 May 2024 13:58:41 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1716818321; bh=I2SW5zw4dbiQrycUx9m42OMTiEZTjTZWhIvvZr1l95Q=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=t/QgygbbRRdAbIEDt78qqKsGdd6/IHadCKF+3pTBAniP9POxWnDJZ1WmgysMl/kJJ guYXLt8GMA2lC8qfWwi1qBJDsL6mcOXJVUO9x1R+6lyzBkDhyMkR0IN7RkycI5a7Sf OB3OZK9kWluGwcc4D2J/7rpnFpv7NgQ9nU35NQpwicOtKY/2YDq5/eJYZHc5uaHj9a T5Bn9esBbAyErTruJJEzsmS0Uwuk87SUdVUll2a3xHkirmySOaZEO6lTRBboJDq6hV l6sLpZ0UlFNPSisSSlWlWlitwuOPs4EatDg1OnN8OHA4doDRdOYwp8KeIne/JgmEOU zcTwlerPDz5aQ== From: Maxime Ripard Date: Mon, 27 May 2024 15:58:01 +0200 Subject: [PATCH v15 12/29] drm/tests: Add TDMS character rate connector state tests Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20240527-kms-hdmi-connector-state-v15-12-c5af16c3aae2@kernel.org> References: <20240527-kms-hdmi-connector-state-v15-0-c5af16c3aae2@kernel.org> In-Reply-To: <20240527-kms-hdmi-connector-state-v15-0-c5af16c3aae2@kernel.org> To: Maarten Lankhorst , Thomas Zimmermann , David Airlie , Daniel Vetter , Jonathan Corbet , Sandy Huang , =?utf-8?q?Heiko_St=C3=BCbner?= , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Andy Yan Cc: Hans Verkuil , Sebastian Wick , =?utf-8?b?VmlsbGUgU3lyasOkbMOk?= , dri-devel@lists.freedesktop.org, linux-arm-kernel@lists.infradead.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-rockchip@lists.infradead.org, linux-sunxi@lists.linux.dev, Maxime Ripard , Dave Stevenson , Dmitry Baryshkov X-Mailer: b4 0.13.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=18013; i=mripard@kernel.org; h=from:subject:message-id; bh=I2SW5zw4dbiQrycUx9m42OMTiEZTjTZWhIvvZr1l95Q=; b=owGbwMvMwCmsHn9OcpHtvjLG02pJDGkhE1NbYg4vndd1V6fIZFv4rL4zHW+Ddqw8/+T44qxw5 kMT+OVNO6ayMAhzMsiKKbI8kQk7vbx9cZWD/cofMHNYmUCGMHBxCsBEDi1lbDhxRzaiLbXBvCpv 0gzfWSFnJr34Ui6sun7RsZcfZVJXbf7006PXYe4cCXudYraXh/RXdjDWF6Vfdy5lmNmnx9QXaPY 4S6Mj/97saTkrhIuMt/YEHbvG2eV/uX/6jf9zLJatPuyq8loCAA== X-Developer-Key: i=mripard@kernel.org; a=openpgp; fpr=BE5675C37E818C8B5764241C254BCFC56BF6CE8D The previous patch stores in the connector state the expected TMDS character rate matching the configuration of the HDMI connector. Let's add a few tests to make sure it works as expected. Reviewed-by: Dave Stevenson Reviewed-by: Dmitry Baryshkov Signed-off-by: Maxime Ripard --- drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 166 ++++++++++++++++ drivers/gpu/drm/tests/drm_kunit_edid.h | 216 +++++++++++++++++++++ 2 files changed, 382 insertions(+) diff --git a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c index 4f46a70a5017..8ff53ee54e97 100644 --- a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c +++ b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c @@ -347,13 +347,156 @@ static void drm_test_check_output_bpc_crtc_mode_not_changed(struct kunit *test) crtc_state = drm_atomic_get_new_crtc_state(state, crtc); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state); KUNIT_EXPECT_FALSE(test, crtc_state->mode_changed); } +/* + * Test that when doing a commit which would use RGB 8bpc, the TMDS + * clock rate stored in the connector state is equal to the mode clock + */ +static void drm_test_check_tmds_char_rate_rgb_8bpc(struct kunit *test) +{ + struct drm_atomic_helper_connector_hdmi_priv *priv; + struct drm_modeset_acquire_ctx *ctx; + struct drm_connector_state *conn_state; + struct drm_display_mode *preferred; + struct drm_connector *conn; + struct drm_device *drm; + struct drm_crtc *crtc; + int ret; + + priv = drm_atomic_helper_connector_hdmi_init(test, + BIT(HDMI_COLORSPACE_RGB), + 8); + KUNIT_ASSERT_NOT_NULL(test, priv); + + conn = &priv->connector; + ret = set_connector_edid(test, conn, + test_edid_hdmi_1080p_rgb_max_200mhz, + ARRAY_SIZE(test_edid_hdmi_1080p_rgb_max_200mhz)); + KUNIT_ASSERT_EQ(test, ret, 0); + + ctx = drm_kunit_helper_acquire_ctx_alloc(test); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); + + preferred = find_preferred_mode(conn); + KUNIT_ASSERT_NOT_NULL(test, preferred); + KUNIT_ASSERT_FALSE(test, preferred->flags & DRM_MODE_FLAG_DBLCLK); + + drm = &priv->drm; + crtc = priv->crtc; + ret = light_up_connector(test, drm, crtc, conn, preferred, ctx); + KUNIT_ASSERT_EQ(test, ret, 0); + + conn_state = conn->state; + KUNIT_ASSERT_NOT_NULL(test, conn_state); + + KUNIT_ASSERT_EQ(test, conn_state->hdmi.output_bpc, 8); + KUNIT_ASSERT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB); + KUNIT_EXPECT_EQ(test, conn_state->hdmi.tmds_char_rate, preferred->clock * 1000); +} + +/* + * Test that when doing a commit which would use RGB 10bpc, the TMDS + * clock rate stored in the connector state is equal to 1.25 times the + * mode pixel clock + */ +static void drm_test_check_tmds_char_rate_rgb_10bpc(struct kunit *test) +{ + struct drm_atomic_helper_connector_hdmi_priv *priv; + struct drm_modeset_acquire_ctx *ctx; + struct drm_connector_state *conn_state; + struct drm_display_mode *preferred; + struct drm_connector *conn; + struct drm_device *drm; + struct drm_crtc *crtc; + int ret; + + priv = drm_atomic_helper_connector_hdmi_init(test, + BIT(HDMI_COLORSPACE_RGB), + 10); + KUNIT_ASSERT_NOT_NULL(test, priv); + + conn = &priv->connector; + ret = set_connector_edid(test, conn, + test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz, + ARRAY_SIZE(test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz)); + KUNIT_ASSERT_EQ(test, ret, 0); + + ctx = drm_kunit_helper_acquire_ctx_alloc(test); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); + + preferred = find_preferred_mode(conn); + KUNIT_ASSERT_NOT_NULL(test, preferred); + KUNIT_ASSERT_FALSE(test, preferred->flags & DRM_MODE_FLAG_DBLCLK); + + drm = &priv->drm; + crtc = priv->crtc; + ret = light_up_connector(test, drm, crtc, conn, preferred, ctx); + KUNIT_ASSERT_EQ(test, ret, 0); + + conn_state = conn->state; + KUNIT_ASSERT_NOT_NULL(test, conn_state); + + KUNIT_ASSERT_EQ(test, conn_state->hdmi.output_bpc, 10); + KUNIT_ASSERT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB); + KUNIT_EXPECT_EQ(test, conn_state->hdmi.tmds_char_rate, preferred->clock * 1250); +} + +/* + * Test that when doing a commit which would use RGB 12bpc, the TMDS + * clock rate stored in the connector state is equal to 1.5 times the + * mode pixel clock + */ +static void drm_test_check_tmds_char_rate_rgb_12bpc(struct kunit *test) +{ + struct drm_atomic_helper_connector_hdmi_priv *priv; + struct drm_modeset_acquire_ctx *ctx; + struct drm_connector_state *conn_state; + struct drm_display_mode *preferred; + struct drm_connector *conn; + struct drm_device *drm; + struct drm_crtc *crtc; + int ret; + + priv = drm_atomic_helper_connector_hdmi_init(test, + BIT(HDMI_COLORSPACE_RGB), + 12); + KUNIT_ASSERT_NOT_NULL(test, priv); + + conn = &priv->connector; + ret = set_connector_edid(test, conn, + test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz, + ARRAY_SIZE(test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz)); + KUNIT_ASSERT_EQ(test, ret, 0); + + ctx = drm_kunit_helper_acquire_ctx_alloc(test); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); + + preferred = find_preferred_mode(conn); + KUNIT_ASSERT_NOT_NULL(test, preferred); + KUNIT_ASSERT_FALSE(test, preferred->flags & DRM_MODE_FLAG_DBLCLK); + + drm = &priv->drm; + crtc = priv->crtc; + ret = light_up_connector(test, drm, crtc, conn, preferred, ctx); + KUNIT_ASSERT_EQ(test, ret, 0); + + conn_state = conn->state; + KUNIT_ASSERT_NOT_NULL(test, conn_state); + + KUNIT_ASSERT_EQ(test, conn_state->hdmi.output_bpc, 12); + KUNIT_ASSERT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB); + KUNIT_EXPECT_EQ(test, conn_state->hdmi.tmds_char_rate, preferred->clock * 1500); +} + static struct kunit_case drm_atomic_helper_connector_hdmi_check_tests[] = { KUNIT_CASE(drm_test_check_output_bpc_crtc_mode_changed), KUNIT_CASE(drm_test_check_output_bpc_crtc_mode_not_changed), + KUNIT_CASE(drm_test_check_tmds_char_rate_rgb_8bpc), + KUNIT_CASE(drm_test_check_tmds_char_rate_rgb_10bpc), + KUNIT_CASE(drm_test_check_tmds_char_rate_rgb_12bpc), /* * TODO: We should have tests to check that a change in the * format triggers a CRTC mode change just like we do for the * RGB Quantization and BPC. * @@ -461,15 +604,38 @@ static void drm_test_check_format_value(struct kunit *test) conn = &priv->connector; conn_state = conn->state; KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB); } +/* + * Test that the value of the output format property out of reset is set + * to 0, and will be computed at atomic_check time. + */ +static void drm_test_check_tmds_char_value(struct kunit *test) +{ + struct drm_atomic_helper_connector_hdmi_priv *priv; + struct drm_connector_state *conn_state; + struct drm_connector *conn; + + priv = drm_atomic_helper_connector_hdmi_init(test, + BIT(HDMI_COLORSPACE_RGB) | + BIT(HDMI_COLORSPACE_YUV422) | + BIT(HDMI_COLORSPACE_YUV444), + 12); + KUNIT_ASSERT_NOT_NULL(test, priv); + + conn = &priv->connector; + conn_state = conn->state; + KUNIT_EXPECT_EQ(test, conn_state->hdmi.tmds_char_rate, 0); +} + static struct kunit_case drm_atomic_helper_connector_hdmi_reset_tests[] = { KUNIT_CASE(drm_test_check_bpc_8_value), KUNIT_CASE(drm_test_check_bpc_10_value), KUNIT_CASE(drm_test_check_bpc_12_value), KUNIT_CASE(drm_test_check_format_value), + KUNIT_CASE(drm_test_check_tmds_char_value), { } }; static struct kunit_suite drm_atomic_helper_connector_hdmi_reset_test_suite = { .name = "drm_atomic_helper_connector_hdmi_reset", diff --git a/drivers/gpu/drm/tests/drm_kunit_edid.h b/drivers/gpu/drm/tests/drm_kunit_edid.h index 0366dd29c820..ed051d356d5e 100644 --- a/drivers/gpu/drm/tests/drm_kunit_edid.h +++ b/drivers/gpu/drm/tests/drm_kunit_edid.h @@ -101,6 +101,222 @@ static const unsigned char test_edid_hdmi_1080p_rgb_max_200mhz[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0 }; +/* + * edid-decode (hex): + * + * 00 ff ff ff ff ff ff 00 31 d8 2a 00 00 00 00 00 + * 00 21 01 03 81 a0 5a 78 1a 00 00 00 00 00 00 00 + * 00 00 00 20 00 00 01 01 01 01 01 01 01 01 01 01 + * 01 01 01 01 01 01 02 3a 80 18 71 38 2d 40 58 2c + * 45 00 40 84 63 00 00 1e 00 00 00 fc 00 54 65 73 + * 74 20 45 44 49 44 0a 20 20 20 00 00 00 fd 00 32 + * 46 1e 46 0f 00 0a 20 20 20 20 20 20 00 00 00 10 + * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 7a + * + * 02 03 1b b1 e3 05 00 20 41 10 e2 00 ca 6d 03 0c + * 00 12 34 78 28 20 00 00 00 00 00 00 00 00 00 00 + * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 a8 + * + * ---------------- + * + * Block 0, Base EDID: + * EDID Structure Version & Revision: 1.3 + * Vendor & Product Identification: + * Manufacturer: LNX + * Model: 42 + * Made in: 2023 + * Basic Display Parameters & Features: + * Digital display + * DFP 1.x compatible TMDS + * Maximum image size: 160 cm x 90 cm + * Gamma: 2.20 + * Undefined display color type + * First detailed timing is the preferred timing + * Color Characteristics: + * Red : 0.0000, 0.0000 + * Green: 0.0000, 0.0000 + * Blue : 0.0000, 0.0000 + * White: 0.0000, 0.0000 + * Established Timings I & II: + * DMT 0x04: 640x480 59.940476 Hz 4:3 31.469 kHz 25.175000 MHz + * Standard Timings: none + * Detailed Timing Descriptors: + * DTD 1: 1920x1080 60.000000 Hz 16:9 67.500 kHz 148.500000 MHz (1600 mm x 900 mm) + * Hfront 88 Hsync 44 Hback 148 Hpol P + * Vfront 4 Vsync 5 Vback 36 Vpol P + * Display Product Name: 'Test EDID' + * Display Range Limits: + * Monitor ranges (GTF): 50-70 Hz V, 30-70 kHz H, max dotclock 150 MHz + * Dummy Descriptor: + * Extension blocks: 1 + * Checksum: 0x7a + * + * ---------------- + * + * Block 1, CTA-861 Extension Block: + * Revision: 3 + * Underscans IT Video Formats by default + * Supports YCbCr 4:4:4 + * Supports YCbCr 4:2:2 + * Native detailed modes: 1 + * Colorimetry Data Block: + * sRGB + * Video Data Block: + * VIC 16: 1920x1080 60.000000 Hz 16:9 67.500 kHz 148.500000 MHz + * Video Capability Data Block: + * YCbCr quantization: Selectable (via AVI YQ) + * RGB quantization: Selectable (via AVI Q) + * PT scan behavior: No Data + * IT scan behavior: Always Underscanned + * CE scan behavior: Always Underscanned + * Vendor-Specific Data Block (HDMI), OUI 00-0C-03: + * Source physical address: 1.2.3.4 + * DC_48bit + * DC_36bit + * DC_30bit + * DC_Y444 + * Maximum TMDS clock: 200 MHz + * Extended HDMI video details: + * Checksum: 0xa8 Unused space in Extension Block: 100 bytes + */ +static const unsigned char test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz[] = { + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x31, 0xd8, 0x2a, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x01, 0x03, 0x81, 0xa0, 0x5a, 0x78, + 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3a, 0x80, 0x18, 0x71, 0x38, + 0x2d, 0x40, 0x58, 0x2c, 0x45, 0x00, 0x40, 0x84, 0x63, 0x00, 0x00, 0x1e, + 0x00, 0x00, 0x00, 0xfc, 0x00, 0x54, 0x65, 0x73, 0x74, 0x20, 0x45, 0x44, + 0x49, 0x44, 0x0a, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x32, + 0x46, 0x1e, 0x46, 0x0f, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x7a, 0x02, 0x03, 0x1b, 0xb1, + 0xe3, 0x05, 0x00, 0x20, 0x41, 0x10, 0xe2, 0x00, 0xca, 0x6d, 0x03, 0x0c, + 0x00, 0x12, 0x34, 0x78, 0x28, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xa8 +}; + +/* + * edid-decode (hex): + * + * 00 ff ff ff ff ff ff 00 31 d8 2a 00 00 00 00 00 + * 00 21 01 03 81 a0 5a 78 0a 00 00 00 00 00 00 00 + * 00 00 00 20 00 00 01 01 01 01 01 01 01 01 01 01 + * 01 01 01 01 01 01 02 3a 80 18 71 38 2d 40 58 2c + * 45 00 40 84 63 00 00 1e 00 00 00 fc 00 54 65 73 + * 74 20 45 44 49 44 0a 20 20 20 00 00 00 fd 00 32 + * 46 1e 46 0f 00 0a 20 20 20 20 20 20 00 00 00 10 + * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 8a + * + * 02 03 1b b1 e3 05 00 20 41 10 e2 00 ca 6d 03 0c + * 00 12 34 78 44 20 00 00 00 00 00 00 00 00 00 00 + * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 8c + * + * ---------------- + * + * Block 0, Base EDID: + * EDID Structure Version & Revision: 1.3 + * Vendor & Product Identification: + * Manufacturer: LNX + * Model: 42 + * Made in: 2023 + * Basic Display Parameters & Features: + * Digital display + * DFP 1.x compatible TMDS + * Maximum image size: 160 cm x 90 cm + * Gamma: 2.20 + * RGB color display + * First detailed timing is the preferred timing + * Color Characteristics: + * Red : 0.0000, 0.0000 + * Green: 0.0000, 0.0000 + * Blue : 0.0000, 0.0000 + * White: 0.0000, 0.0000 + * Established Timings I & II: + * DMT 0x04: 640x480 59.940476 Hz 4:3 31.469 kHz 25.175000 MHz + * Standard Timings: none + * Detailed Timing Descriptors: + * DTD 1: 1920x1080 60.000000 Hz 16:9 67.500 kHz 148.500000 MHz (1600 mm x 900 mm) + * Hfront 88 Hsync 44 Hback 148 Hpol P + * Vfront 4 Vsync 5 Vback 36 Vpol P + * Display Product Name: 'Test EDID' + * Display Range Limits: + * Monitor ranges (GTF): 50-70 Hz V, 30-70 kHz H, max dotclock 150 MHz + * Dummy Descriptor: + * Extension blocks: 1 + * Checksum: 0x8a + * + * ---------------- + * + * Block 1, CTA-861 Extension Block: + * Revision: 3 + * Underscans IT Video Formats by default + * Supports YCbCr 4:4:4 + * Supports YCbCr 4:2:2 + * Native detailed modes: 1 + * Colorimetry Data Block: + * sRGB + * Video Data Block: + * VIC 16: 1920x1080 60.000000 Hz 16:9 67.500 kHz 148.500000 MHz + * Video Capability Data Block: + * YCbCr quantization: Selectable (via AVI YQ) + * RGB quantization: Selectable (via AVI Q) + * PT scan behavior: No Data + * IT scan behavior: Always Underscanned + * CE scan behavior: Always Underscanned + * Vendor-Specific Data Block (HDMI), OUI 00-0C-03: + * Source physical address: 1.2.3.4 + * DC_48bit + * DC_36bit + * DC_30bit + * DC_Y444 + * Maximum TMDS clock: 340 MHz + * Extended HDMI video details: + * Checksum: 0x8c Unused space in Extension Block: 100 bytes + */ +static const unsigned char test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz[] = { + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x31, 0xd8, 0x2a, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x01, 0x03, 0x81, 0xa0, 0x5a, 0x78, + 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3a, 0x80, 0x18, 0x71, 0x38, + 0x2d, 0x40, 0x58, 0x2c, 0x45, 0x00, 0x40, 0x84, 0x63, 0x00, 0x00, 0x1e, + 0x00, 0x00, 0x00, 0xfc, 0x00, 0x54, 0x65, 0x73, 0x74, 0x20, 0x45, 0x44, + 0x49, 0x44, 0x0a, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x32, + 0x46, 0x1e, 0x46, 0x0f, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x8a, 0x02, 0x03, 0x1b, 0xb1, + 0xe3, 0x05, 0x00, 0x20, 0x41, 0x10, 0xe2, 0x00, 0xca, 0x6d, 0x03, 0x0c, + 0x00, 0x12, 0x34, 0x78, 0x44, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x8c +}; + #endif // DRM_KUNIT_EDID_H_ From patchwork Mon May 27 13:58:03 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Maxime Ripard X-Patchwork-Id: 799366 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 A972A16C84E; Mon, 27 May 2024 13:58:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716818327; cv=none; b=fO/GEf6OjM9RL4gueepeSqM7XfTDtZ0O8y5oXb4O2EuUxmAgGbyQqk9RkK13SD1ohBuFqJOENdYvJayV1xnIplcW7JDcQEXrqVDcJTz5XnOMXK06YlozRdhMp9HaNN5QySgCIwJPJIjpsMgLArKNo8WK+ofvcoLF39WzKwin2Tc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716818327; c=relaxed/simple; bh=evdMziBD604xhpsHQgfDxIbpzA2cQVm7nC6u+fBPbFE=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=hwUx3y7ojAZuAX1/BJ7zbh7Um+yFwIsCfx3sUBnsrM2jrXIdXLF59Ziv8WPkktL/ylaO+65xcoosqsJz69VEK6LXkCROaATQGNW1FSx5b72cLlFm+mb1UTtSjA0IKSTF/cjIlSLO7NId8CbVyuR7w2WOgkvmOEWHS8a8VTlwz5U= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=am3wbWT0; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="am3wbWT0" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 3610FC2BBFC; Mon, 27 May 2024 13:58:47 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1716818327; bh=evdMziBD604xhpsHQgfDxIbpzA2cQVm7nC6u+fBPbFE=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=am3wbWT0VXs4fDL64MAoGiOWOL7SvD8wJtVXB2ShrW5bTL/2vkFMbi3nHoIqtm1g1 DOAtuEmRYpkKBY61zpjy/lEHTBDezE8RGGuR35y9uaWO4SI7Q6vcLtjF7+Qk2n4umZ 5g8yGeTw+dY0cEL7fyhEBuaPyzBEWK/fbdjcz71ssuoEWYT8UrnpPe0+dBJmKwnQON m2T3NirLWR/vetYVVUxdV0KkVBQTO7jrtLgUegavSH4wuVX6Ud8VvY75DfressUdzt VIV2AcbZaQDche6inIjEz7hwXmPEdGXRJDwtCoO0e+nJ10oCC8uRiiqrebhGGhUksD 6vC2WUfVqqBvg== From: Maxime Ripard Date: Mon, 27 May 2024 15:58:03 +0200 Subject: [PATCH v15 14/29] drm/tests: Add HDMI connector rate filter hook tests Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20240527-kms-hdmi-connector-state-v15-14-c5af16c3aae2@kernel.org> References: <20240527-kms-hdmi-connector-state-v15-0-c5af16c3aae2@kernel.org> In-Reply-To: <20240527-kms-hdmi-connector-state-v15-0-c5af16c3aae2@kernel.org> To: Maarten Lankhorst , Thomas Zimmermann , David Airlie , Daniel Vetter , Jonathan Corbet , Sandy Huang , =?utf-8?q?Heiko_St=C3=BCbner?= , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Andy Yan Cc: Hans Verkuil , Sebastian Wick , =?utf-8?b?VmlsbGUgU3lyasOkbMOk?= , dri-devel@lists.freedesktop.org, linux-arm-kernel@lists.infradead.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-rockchip@lists.infradead.org, linux-sunxi@lists.linux.dev, Maxime Ripard , Dave Stevenson , Dmitry Baryshkov X-Mailer: b4 0.13.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=3959; i=mripard@kernel.org; h=from:subject:message-id; bh=evdMziBD604xhpsHQgfDxIbpzA2cQVm7nC6u+fBPbFE=; b=owGbwMvMwCmsHn9OcpHtvjLG02pJDGkhE9OEGI1mNfYnFul8FNJNfvW0a5lk6/SneZ+WCG8Rv 36BNVapYyoLgzAng6yYIssTmbDTy9sXVznYr/wBM4eVCWQIAxenAEzkXjxjvVv1hczmsxwpTAvW BIf2+NmLGNjwBoW+YGNLvaS4O05E3/508YJIlkvMCpFupnVe+5MYG95UbjNeZb32+eQnGSGL3tx uYCos+h1y/3TJ2xUsgWtLlITf2fZm1xxI8ZtVtNPr83Z/MQA= X-Developer-Key: i=mripard@kernel.org; a=openpgp; fpr=BE5675C37E818C8B5764241C254BCFC56BF6CE8D The previous patch adds a new hook for HDMI connectors to filter out configurations based on the TMDS character rate. Let's add some tests to make sure it works as expected. Reviewed-by: Dave Stevenson Reviewed-by: Dmitry Baryshkov Signed-off-by: Maxime Ripard --- drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 65 ++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c index 7f9a48902db4..ead998a691e7 100644 --- a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c +++ b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c @@ -113,10 +113,22 @@ static int set_connector_edid(struct kunit *test, struct drm_connector *connecto } static const struct drm_connector_hdmi_funcs dummy_connector_hdmi_funcs = { }; +static enum drm_mode_status +reject_connector_tmds_char_rate_valid(const struct drm_connector *connector, + const struct drm_display_mode *mode, + unsigned long long tmds_rate) +{ + return MODE_BAD; +} + +static const struct drm_connector_hdmi_funcs reject_connector_hdmi_funcs = { + .tmds_char_rate_valid = reject_connector_tmds_char_rate_valid, +}; + static int dummy_connector_get_modes(struct drm_connector *connector) { struct drm_atomic_helper_connector_hdmi_priv *priv = connector_to_priv(connector); const struct drm_edid *edid; @@ -491,11 +503,64 @@ static void drm_test_check_tmds_char_rate_rgb_12bpc(struct kunit *test) KUNIT_ASSERT_EQ(test, conn_state->hdmi.output_bpc, 12); KUNIT_ASSERT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB); KUNIT_EXPECT_EQ(test, conn_state->hdmi.tmds_char_rate, preferred->clock * 1500); } +/* + * Test that if we filter a rate through our hook, it's indeed rejected + * by the whole atomic_check logic. + * + * We do so by first doing a commit on the pipeline to make sure that it + * works, change the HDMI helpers pointer, and then try the same commit + * again to see if it fails as it should. + */ +static void drm_test_check_hdmi_funcs_reject_rate(struct kunit *test) +{ + struct drm_atomic_helper_connector_hdmi_priv *priv; + struct drm_modeset_acquire_ctx *ctx; + struct drm_atomic_state *state; + struct drm_display_mode *preferred; + struct drm_crtc_state *crtc_state; + struct drm_connector *conn; + struct drm_device *drm; + struct drm_crtc *crtc; + int ret; + + priv = drm_atomic_helper_connector_hdmi_init(test, + BIT(HDMI_COLORSPACE_RGB), + 8); + KUNIT_ASSERT_NOT_NULL(test, priv); + + ctx = drm_kunit_helper_acquire_ctx_alloc(test); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); + + conn = &priv->connector; + preferred = find_preferred_mode(conn); + KUNIT_ASSERT_NOT_NULL(test, preferred); + + drm = &priv->drm; + crtc = priv->crtc; + ret = light_up_connector(test, drm, crtc, conn, preferred, ctx); + KUNIT_ASSERT_EQ(test, ret, 0); + + /* You shouldn't be doing that at home. */ + conn->hdmi.funcs = &reject_connector_hdmi_funcs; + + state = drm_kunit_helper_atomic_state_alloc(test, drm, ctx); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state); + + crtc_state = drm_atomic_get_crtc_state(state, crtc); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state); + + crtc_state->connectors_changed = true; + + ret = drm_atomic_check_only(state); + KUNIT_EXPECT_LT(test, ret, 0); +} + static struct kunit_case drm_atomic_helper_connector_hdmi_check_tests[] = { + KUNIT_CASE(drm_test_check_hdmi_funcs_reject_rate), KUNIT_CASE(drm_test_check_output_bpc_crtc_mode_changed), KUNIT_CASE(drm_test_check_output_bpc_crtc_mode_not_changed), KUNIT_CASE(drm_test_check_tmds_char_rate_rgb_8bpc), KUNIT_CASE(drm_test_check_tmds_char_rate_rgb_10bpc), KUNIT_CASE(drm_test_check_tmds_char_rate_rgb_12bpc), From patchwork Mon May 27 13:58:05 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Maxime Ripard X-Patchwork-Id: 799365 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 8EEA316D318; Mon, 27 May 2024 13:58:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716818333; cv=none; b=AMDQHuhNTuX8SnweF8JvKhmSdtSrRjSDVqxaTlSl/Vk0QLAtvH9SF9Z60puaekc7f/4PmcJFsxojq2j7vnb+PNz1xIKwIYdhUVW6mZQfRszM2DpYfwsMSUu9+yvXsDi6VZQS0Ap5x3JMRN5vqCKJBO4ErasH+fBxCI5ffhZ3eB4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716818333; c=relaxed/simple; bh=67B8qAf69XKci4QtCr3mNnPwFV3hUlKJAJwsS4JqCIo=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Bjh/TiYjty4EYFSXQsNqG8hdnv6FrnNSkRxRLqi2emGYUXwnSSV/8EbAV2ITYxdVbdxYX6KoAA6RNOHqxd1u7E6lJYKhcT4Wa4KWJ8Js4DHz/77VEobRf6rMKkSc0HP9RTZzOqko3Q7kcLxjj76+4VaZBXkJHdPlvFeagvwHKfY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=e51unT7W; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="e51unT7W" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 8A5E4C2BBFC; Mon, 27 May 2024 13:58:52 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1716818333; bh=67B8qAf69XKci4QtCr3mNnPwFV3hUlKJAJwsS4JqCIo=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=e51unT7WmSvKSLcqZYc4qWFNfny8PRtpqGs4f11CxHUEczzbkKl/O0G9NQDwH8//o 7oBc8aJZiyIR9kDuTfyAJwNqUFT4Acvr2ywNesakCsWK7j1vb43pW+Ny9w6hLwEqNv Kmukm/NowVbEZPA1qW1c/5YHqKc40ewl/fOSOQXV9n26jzW7kYSgY6OCX2d9N7CyFP OYeeK3utdU6NVizbm0thf7Km4USLZrxDHt7xA/nt7jzKC6eM2FvNCrBUXHPyj32Clw hbsyHhTyhTD60VU2x+7RsFOrLquWCSIV8OxbN5aQZ7lcIXMA4CWa1LCitfu+gKpEHV bM3r2tuqLhvcA== From: Maxime Ripard Date: Mon, 27 May 2024 15:58:05 +0200 Subject: [PATCH v15 16/29] drm/tests: Add HDMI connector bpc and format tests Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20240527-kms-hdmi-connector-state-v15-16-c5af16c3aae2@kernel.org> References: <20240527-kms-hdmi-connector-state-v15-0-c5af16c3aae2@kernel.org> In-Reply-To: <20240527-kms-hdmi-connector-state-v15-0-c5af16c3aae2@kernel.org> To: Maarten Lankhorst , Thomas Zimmermann , David Airlie , Daniel Vetter , Jonathan Corbet , Sandy Huang , =?utf-8?q?Heiko_St=C3=BCbner?= , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Andy Yan Cc: Hans Verkuil , Sebastian Wick , =?utf-8?b?VmlsbGUgU3lyasOkbMOk?= , dri-devel@lists.freedesktop.org, linux-arm-kernel@lists.infradead.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-rockchip@lists.infradead.org, linux-sunxi@lists.linux.dev, Maxime Ripard , Dmitry Baryshkov X-Mailer: b4 0.13.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=27716; i=mripard@kernel.org; h=from:subject:message-id; bh=67B8qAf69XKci4QtCr3mNnPwFV3hUlKJAJwsS4JqCIo=; b=kA0DAAkTJ1/OGaI9vnYByyZiAGZUkWeiB46+bUBy4tsisq1UFRvh/7/RoUlJHBXNxr5rf4SDv IiVBAATCQAdFiEE5BxWy6eHo3pAP6n4J1/OGaI9vnYFAmZUkWcACgkQJ1/OGaI9vnbTiQF/RbYa x54j2RCjw7NkX3dFoN4FSHsWoSPynt5vmxPIZzTf5kPLklbxBM9c1Al2T4VlAX9H1AUtBSxLh6z 5aNE1Ilf/zCkimWMiKZdKIfBLn0Hpq3En1g2m12mJtys6LqeliFM= X-Developer-Key: i=mripard@kernel.org; a=openpgp; fpr=BE5675C37E818C8B5764241C254BCFC56BF6CE8D The previous patch added the bpc and format an HDMI connector needs to be set up with for a given connector state. Let's add a few tests to make sure it works as expected. Reviewed-by: Dmitry Baryshkov Signed-off-by: Maxime Ripard --- drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 509 +++++++++++++++++++++ drivers/gpu/drm/tests/drm_kunit_edid.h | 160 +++++++ 2 files changed, 669 insertions(+) diff --git a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c index a49a544d7b49..968204781928 100644 --- a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c +++ b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c @@ -15,10 +15,11 @@ #include #include #include #include +#include #include #include "../drm_crtc_internal.h" #include @@ -370,10 +371,60 @@ static void drm_test_check_output_bpc_crtc_mode_not_changed(struct kunit *test) crtc_state = drm_atomic_get_new_crtc_state(state, crtc); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state); KUNIT_EXPECT_FALSE(test, crtc_state->mode_changed); } +/* + * Test that if we have an HDMI connector but a !HDMI display, we always + * output RGB with 8 bpc. + */ +static void drm_test_check_output_bpc_dvi(struct kunit *test) +{ + struct drm_atomic_helper_connector_hdmi_priv *priv; + struct drm_modeset_acquire_ctx *ctx; + struct drm_connector_state *conn_state; + struct drm_display_info *info; + struct drm_display_mode *preferred; + struct drm_connector *conn; + struct drm_device *drm; + struct drm_crtc *crtc; + int ret; + + priv = drm_atomic_helper_connector_hdmi_init(test, + BIT(HDMI_COLORSPACE_RGB) | + BIT(HDMI_COLORSPACE_YUV422) | + BIT(HDMI_COLORSPACE_YUV444), + 12); + KUNIT_ASSERT_NOT_NULL(test, priv); + + conn = &priv->connector; + ret = set_connector_edid(test, conn, + test_edid_dvi_1080p, + ARRAY_SIZE(test_edid_dvi_1080p)); + KUNIT_ASSERT_EQ(test, ret, 0); + + info = &conn->display_info; + KUNIT_ASSERT_FALSE(test, info->is_hdmi); + + ctx = drm_kunit_helper_acquire_ctx_alloc(test); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); + + preferred = find_preferred_mode(conn); + KUNIT_ASSERT_NOT_NULL(test, preferred); + + drm = &priv->drm; + crtc = priv->crtc; + ret = light_up_connector(test, drm, crtc, conn, preferred, ctx); + KUNIT_ASSERT_EQ(test, ret, 0); + + conn_state = conn->state; + KUNIT_ASSERT_NOT_NULL(test, conn_state); + + KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 8); + KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB); +} + /* * Test that when doing a commit which would use RGB 8bpc, the TMDS * clock rate stored in the connector state is equal to the mode clock */ static void drm_test_check_tmds_char_rate_rgb_8bpc(struct kunit *test) @@ -562,14 +613,472 @@ static void drm_test_check_hdmi_funcs_reject_rate(struct kunit *test) ret = drm_atomic_check_only(state); KUNIT_EXPECT_LT(test, ret, 0); } +/* + * Test that if: + * - We have an HDMI connector supporting RGB only + * - The chosen mode has a TMDS character rate higher than the display + * supports in RGB/12bpc + * - The chosen mode has a TMDS character rate lower than the display + * supports in RGB/10bpc. + * + * Then we will pick the latter, and the computed TMDS character rate + * will be equal to 1.25 times the mode pixel clock. + */ +static void drm_test_check_max_tmds_rate_bpc_fallback(struct kunit *test) +{ + struct drm_atomic_helper_connector_hdmi_priv *priv; + struct drm_modeset_acquire_ctx *ctx; + struct drm_connector_state *conn_state; + struct drm_display_info *info; + struct drm_display_mode *preferred; + unsigned long long rate; + struct drm_connector *conn; + struct drm_device *drm; + struct drm_crtc *crtc; + int ret; + + priv = drm_atomic_helper_connector_hdmi_init(test, + BIT(HDMI_COLORSPACE_RGB), + 12); + KUNIT_ASSERT_NOT_NULL(test, priv); + + conn = &priv->connector; + ret = set_connector_edid(test, conn, + test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz, + ARRAY_SIZE(test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz)); + KUNIT_ASSERT_EQ(test, ret, 0); + + info = &conn->display_info; + KUNIT_ASSERT_TRUE(test, info->is_hdmi); + KUNIT_ASSERT_GT(test, info->max_tmds_clock, 0); + + ctx = drm_kunit_helper_acquire_ctx_alloc(test); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); + + preferred = find_preferred_mode(conn); + KUNIT_ASSERT_NOT_NULL(test, preferred); + KUNIT_ASSERT_FALSE(test, preferred->flags & DRM_MODE_FLAG_DBLCLK); + + rate = drm_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_RGB); + KUNIT_ASSERT_GT(test, rate, info->max_tmds_clock * 1000); + + rate = drm_hdmi_compute_mode_clock(preferred, 10, HDMI_COLORSPACE_RGB); + KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000); + + drm = &priv->drm; + crtc = priv->crtc; + ret = light_up_connector(test, drm, crtc, conn, preferred, ctx); + KUNIT_EXPECT_EQ(test, ret, 0); + + conn_state = conn->state; + KUNIT_ASSERT_NOT_NULL(test, conn_state); + + KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 10); + KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB); + KUNIT_EXPECT_EQ(test, conn_state->hdmi.tmds_char_rate, preferred->clock * 1250); +} + +/* + * Test that if: + * - We have an HDMI connector supporting both RGB and YUV422 and up to + * 12 bpc + * - The chosen mode has a TMDS character rate higher than the display + * supports in RGB/12bpc but lower than the display supports in + * RGB/10bpc + * - The chosen mode has a TMDS character rate lower than the display + * supports in YUV422/12bpc. + * + * Then we will prefer to keep the RGB format with a lower bpc over + * picking YUV422. + */ +static void drm_test_check_max_tmds_rate_format_fallback(struct kunit *test) +{ + struct drm_atomic_helper_connector_hdmi_priv *priv; + struct drm_modeset_acquire_ctx *ctx; + struct drm_connector_state *conn_state; + struct drm_display_info *info; + struct drm_display_mode *preferred; + unsigned long long rate; + struct drm_connector *conn; + struct drm_device *drm; + struct drm_crtc *crtc; + int ret; + + priv = drm_atomic_helper_connector_hdmi_init(test, + BIT(HDMI_COLORSPACE_RGB) | + BIT(HDMI_COLORSPACE_YUV422) | + BIT(HDMI_COLORSPACE_YUV444), + 12); + KUNIT_ASSERT_NOT_NULL(test, priv); + + conn = &priv->connector; + ret = set_connector_edid(test, conn, + test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz, + ARRAY_SIZE(test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz)); + KUNIT_ASSERT_EQ(test, ret, 0); + + info = &conn->display_info; + KUNIT_ASSERT_TRUE(test, info->is_hdmi); + KUNIT_ASSERT_GT(test, info->max_tmds_clock, 0); + + ctx = drm_kunit_helper_acquire_ctx_alloc(test); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); + + preferred = find_preferred_mode(conn); + KUNIT_ASSERT_NOT_NULL(test, preferred); + KUNIT_ASSERT_FALSE(test, preferred->flags & DRM_MODE_FLAG_DBLCLK); + + rate = drm_hdmi_compute_mode_clock(preferred, 10, HDMI_COLORSPACE_RGB); + KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000); + + rate = drm_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_RGB); + KUNIT_ASSERT_GT(test, rate, info->max_tmds_clock * 1000); + + rate = drm_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_YUV422); + KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000); + + drm = &priv->drm; + crtc = priv->crtc; + ret = light_up_connector(test, drm, crtc, conn, preferred, ctx); + KUNIT_EXPECT_EQ(test, ret, 0); + + conn_state = conn->state; + KUNIT_ASSERT_NOT_NULL(test, conn_state); + + KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 10); + KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB); +} + +/* + * Test that if a driver and screen supports RGB and YUV formats, and we + * try to set the VIC 1 mode, we end up with 8bpc RGB even if we could + * have had a higher bpc. + */ +static void drm_test_check_output_bpc_format_vic_1(struct kunit *test) +{ + struct drm_atomic_helper_connector_hdmi_priv *priv; + struct drm_modeset_acquire_ctx *ctx; + struct drm_connector_state *conn_state; + struct drm_display_info *info; + struct drm_display_mode *mode; + unsigned long long rate; + struct drm_connector *conn; + struct drm_device *drm; + struct drm_crtc *crtc; + int ret; + + priv = drm_atomic_helper_connector_hdmi_init(test, + BIT(HDMI_COLORSPACE_RGB) | + BIT(HDMI_COLORSPACE_YUV422) | + BIT(HDMI_COLORSPACE_YUV444), + 12); + KUNIT_ASSERT_NOT_NULL(test, priv); + + drm = &priv->drm; + conn = &priv->connector; + ret = set_connector_edid(test, conn, + test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz, + ARRAY_SIZE(test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz)); + KUNIT_ASSERT_EQ(test, ret, 0); + + info = &conn->display_info; + KUNIT_ASSERT_TRUE(test, info->is_hdmi); + KUNIT_ASSERT_GT(test, info->max_tmds_clock, 0); + + ctx = drm_kunit_helper_acquire_ctx_alloc(test); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); + + mode = drm_display_mode_from_cea_vic(drm, 1); + KUNIT_ASSERT_NOT_NULL(test, mode); + + /* + * NOTE: We can't use drm_hdmi_compute_mode_clock() + * here because we're trying to get the rate of an invalid + * configuration. + * + * Thus, we have to calculate the rate by hand. + */ + rate = mode->clock * 1500; + KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000); + + drm = &priv->drm; + crtc = priv->crtc; + ret = light_up_connector(test, drm, crtc, conn, mode, ctx); + KUNIT_EXPECT_EQ(test, ret, 0); + + conn_state = conn->state; + KUNIT_ASSERT_NOT_NULL(test, conn_state); + + KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 8); + KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB); +} + +/* + * Test that if a driver supports only RGB but the screen also supports + * YUV formats, we only end up with an RGB format. + */ +static void drm_test_check_output_bpc_format_driver_rgb_only(struct kunit *test) +{ + struct drm_atomic_helper_connector_hdmi_priv *priv; + struct drm_modeset_acquire_ctx *ctx; + struct drm_connector_state *conn_state; + struct drm_display_info *info; + struct drm_display_mode *preferred; + unsigned long long rate; + struct drm_connector *conn; + struct drm_device *drm; + struct drm_crtc *crtc; + int ret; + + priv = drm_atomic_helper_connector_hdmi_init(test, + BIT(HDMI_COLORSPACE_RGB), + 12); + KUNIT_ASSERT_NOT_NULL(test, priv); + + conn = &priv->connector; + ret = set_connector_edid(test, conn, + test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz, + ARRAY_SIZE(test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz)); + KUNIT_ASSERT_EQ(test, ret, 0); + + info = &conn->display_info; + KUNIT_ASSERT_TRUE(test, info->is_hdmi); + KUNIT_ASSERT_GT(test, info->max_tmds_clock, 0); + + ctx = drm_kunit_helper_acquire_ctx_alloc(test); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); + + preferred = find_preferred_mode(conn); + KUNIT_ASSERT_NOT_NULL(test, preferred); + + /* + * We're making sure that YUV422 would be the preferred option + * here: we're always favouring higher bpc, we can't have RGB + * because the TMDS character rate exceeds the maximum supported + * by the display, and YUV422 works for that display. + * + * But since the driver only supports RGB, we should fallback to + * a lower bpc with RGB. + */ + rate = drm_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_RGB); + KUNIT_ASSERT_GT(test, rate, info->max_tmds_clock * 1000); + + rate = drm_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_YUV422); + KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000); + + drm = &priv->drm; + crtc = priv->crtc; + ret = light_up_connector(test, drm, crtc, conn, preferred, ctx); + KUNIT_EXPECT_EQ(test, ret, 0); + + conn_state = conn->state; + KUNIT_ASSERT_NOT_NULL(test, conn_state); + + KUNIT_EXPECT_LT(test, conn_state->hdmi.output_bpc, 12); + KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB); +} + +/* + * Test that if a screen supports only RGB but the driver also supports + * YUV formats, we only end up with an RGB format. + */ +static void drm_test_check_output_bpc_format_display_rgb_only(struct kunit *test) +{ + struct drm_atomic_helper_connector_hdmi_priv *priv; + struct drm_modeset_acquire_ctx *ctx; + struct drm_connector_state *conn_state; + struct drm_display_info *info; + struct drm_display_mode *preferred; + unsigned long long rate; + struct drm_connector *conn; + struct drm_device *drm; + struct drm_crtc *crtc; + int ret; + + priv = drm_atomic_helper_connector_hdmi_init(test, + BIT(HDMI_COLORSPACE_RGB) | + BIT(HDMI_COLORSPACE_YUV422) | + BIT(HDMI_COLORSPACE_YUV444), + 12); + KUNIT_ASSERT_NOT_NULL(test, priv); + + conn = &priv->connector; + ret = set_connector_edid(test, conn, + test_edid_hdmi_1080p_rgb_max_200mhz, + ARRAY_SIZE(test_edid_hdmi_1080p_rgb_max_200mhz)); + KUNIT_ASSERT_EQ(test, ret, 0); + + info = &conn->display_info; + KUNIT_ASSERT_TRUE(test, info->is_hdmi); + KUNIT_ASSERT_GT(test, info->max_tmds_clock, 0); + + ctx = drm_kunit_helper_acquire_ctx_alloc(test); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); + + preferred = find_preferred_mode(conn); + KUNIT_ASSERT_NOT_NULL(test, preferred); + + /* + * We're making sure that YUV422 would be the preferred option + * here: we're always favouring higher bpc, we can't have RGB + * because the TMDS character rate exceeds the maximum supported + * by the display, and YUV422 works for that display. + * + * But since the display only supports RGB, we should fallback to + * a lower bpc with RGB. + */ + rate = drm_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_RGB); + KUNIT_ASSERT_GT(test, rate, info->max_tmds_clock * 1000); + + rate = drm_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_YUV422); + KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000); + + drm = &priv->drm; + crtc = priv->crtc; + ret = light_up_connector(test, drm, crtc, conn, preferred, ctx); + KUNIT_EXPECT_EQ(test, ret, 0); + + conn_state = conn->state; + KUNIT_ASSERT_NOT_NULL(test, conn_state); + + KUNIT_EXPECT_LT(test, conn_state->hdmi.output_bpc, 12); + KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB); +} + +/* + * Test that if a display supports higher bpc but the driver only + * supports 8 bpc, we only end up with 8 bpc even if we could have had a + * higher bpc. + */ +static void drm_test_check_output_bpc_format_driver_8bpc_only(struct kunit *test) +{ + struct drm_atomic_helper_connector_hdmi_priv *priv; + struct drm_modeset_acquire_ctx *ctx; + struct drm_connector_state *conn_state; + struct drm_display_info *info; + struct drm_display_mode *preferred; + unsigned long long rate; + struct drm_connector *conn; + struct drm_device *drm; + struct drm_crtc *crtc; + int ret; + + priv = drm_atomic_helper_connector_hdmi_init(test, + BIT(HDMI_COLORSPACE_RGB), + 8); + KUNIT_ASSERT_NOT_NULL(test, priv); + + conn = &priv->connector; + ret = set_connector_edid(test, conn, + test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz, + ARRAY_SIZE(test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz)); + KUNIT_ASSERT_EQ(test, ret, 0); + + info = &conn->display_info; + KUNIT_ASSERT_TRUE(test, info->is_hdmi); + KUNIT_ASSERT_GT(test, info->max_tmds_clock, 0); + + ctx = drm_kunit_helper_acquire_ctx_alloc(test); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); + + preferred = find_preferred_mode(conn); + KUNIT_ASSERT_NOT_NULL(test, preferred); + + /* + * We're making sure that we have headroom on the TMDS character + * clock to actually use 12bpc. + */ + rate = drm_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_RGB); + KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000); + + drm = &priv->drm; + crtc = priv->crtc; + ret = light_up_connector(test, drm, crtc, conn, preferred, ctx); + KUNIT_EXPECT_EQ(test, ret, 0); + + conn_state = conn->state; + KUNIT_ASSERT_NOT_NULL(test, conn_state); + + KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 8); + KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB); +} + +/* + * Test that if a driver supports higher bpc but the display only + * supports 8 bpc, we only end up with 8 bpc even if we could have had a + * higher bpc. + */ +static void drm_test_check_output_bpc_format_display_8bpc_only(struct kunit *test) +{ + struct drm_atomic_helper_connector_hdmi_priv *priv; + struct drm_modeset_acquire_ctx *ctx; + struct drm_connector_state *conn_state; + struct drm_display_info *info; + struct drm_display_mode *preferred; + unsigned long long rate; + struct drm_connector *conn; + struct drm_device *drm; + struct drm_crtc *crtc; + int ret; + + priv = drm_atomic_helper_connector_hdmi_init(test, + BIT(HDMI_COLORSPACE_RGB) | + BIT(HDMI_COLORSPACE_YUV422) | + BIT(HDMI_COLORSPACE_YUV444), + 12); + KUNIT_ASSERT_NOT_NULL(test, priv); + + conn = &priv->connector; + ret = set_connector_edid(test, conn, + test_edid_hdmi_1080p_rgb_max_340mhz, + ARRAY_SIZE(test_edid_hdmi_1080p_rgb_max_340mhz)); + KUNIT_ASSERT_EQ(test, ret, 0); + + info = &conn->display_info; + KUNIT_ASSERT_TRUE(test, info->is_hdmi); + KUNIT_ASSERT_GT(test, info->max_tmds_clock, 0); + + ctx = drm_kunit_helper_acquire_ctx_alloc(test); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); + + preferred = find_preferred_mode(conn); + KUNIT_ASSERT_NOT_NULL(test, preferred); + + /* + * We're making sure that we have headroom on the TMDS character + * clock to actually use 12bpc. + */ + rate = drm_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_RGB); + KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000); + + drm = &priv->drm; + crtc = priv->crtc; + ret = light_up_connector(test, drm, crtc, conn, preferred, ctx); + KUNIT_EXPECT_EQ(test, ret, 0); + + conn_state = conn->state; + KUNIT_ASSERT_NOT_NULL(test, conn_state); + + KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 8); + KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB); +} + static struct kunit_case drm_atomic_helper_connector_hdmi_check_tests[] = { KUNIT_CASE(drm_test_check_hdmi_funcs_reject_rate), + KUNIT_CASE(drm_test_check_max_tmds_rate_bpc_fallback), + KUNIT_CASE(drm_test_check_max_tmds_rate_format_fallback), KUNIT_CASE(drm_test_check_output_bpc_crtc_mode_changed), KUNIT_CASE(drm_test_check_output_bpc_crtc_mode_not_changed), + KUNIT_CASE(drm_test_check_output_bpc_dvi), + KUNIT_CASE(drm_test_check_output_bpc_format_vic_1), + KUNIT_CASE(drm_test_check_output_bpc_format_display_8bpc_only), + KUNIT_CASE(drm_test_check_output_bpc_format_display_rgb_only), + KUNIT_CASE(drm_test_check_output_bpc_format_driver_8bpc_only), + KUNIT_CASE(drm_test_check_output_bpc_format_driver_rgb_only), KUNIT_CASE(drm_test_check_tmds_char_rate_rgb_8bpc), KUNIT_CASE(drm_test_check_tmds_char_rate_rgb_10bpc), KUNIT_CASE(drm_test_check_tmds_char_rate_rgb_12bpc), /* * TODO: We should have tests to check that a change in the diff --git a/drivers/gpu/drm/tests/drm_kunit_edid.h b/drivers/gpu/drm/tests/drm_kunit_edid.h index ed051d356d5e..cda410440aca 100644 --- a/drivers/gpu/drm/tests/drm_kunit_edid.h +++ b/drivers/gpu/drm/tests/drm_kunit_edid.h @@ -1,8 +1,66 @@ #ifndef DRM_KUNIT_EDID_H_ #define DRM_KUNIT_EDID_H_ +/* + * edid-decode (hex): + * + * 00 ff ff ff ff ff ff 00 31 d8 2a 00 00 00 00 00 + * 00 21 01 03 81 a0 5a 78 0a 00 00 00 00 00 00 00 + * 00 00 00 00 00 00 01 01 01 01 01 01 01 01 01 01 + * 01 01 01 01 01 01 02 3a 80 18 71 38 2d 40 58 2c + * 45 00 40 84 63 00 00 1e 00 00 00 fc 00 54 65 73 + * 74 20 45 44 49 44 0a 20 20 20 00 00 00 fd 00 32 + * 46 1e 46 0f 00 0a 20 20 20 20 20 20 00 00 00 10 + * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ab + * + * ---------------- + * + * Block 0, Base EDID: + * EDID Structure Version & Revision: 1.3 + * Vendor & Product Identification: + * Manufacturer: LNX + * Model: 42 + * Made in: 2023 + * Basic Display Parameters & Features: + * Digital display + * DFP 1.x compatible TMDS + * Maximum image size: 160 cm x 90 cm + * Gamma: 2.20 + * RGB color display + * First detailed timing is the preferred timing + * Color Characteristics: + * Red : 0.0000, 0.0000 + * Green: 0.0000, 0.0000 + * Blue : 0.0000, 0.0000 + * White: 0.0000, 0.0000 + * Established Timings I & II: none + * Standard Timings: none + * Detailed Timing Descriptors: + * DTD 1: 1920x1080 60.000000 Hz 16:9 67.500 kHz 148.500000 MHz (1600 mm x 900 mm) + * Hfront 88 Hsync 44 Hback 148 Hpol P + * Vfront 4 Vsync 5 Vback 36 Vpol P + * Display Product Name: 'Test EDID' + * Display Range Limits: + * Monitor ranges (GTF): 50-70 Hz V, 30-70 kHz H, max dotclock 150 MHz + * Dummy Descriptor: + * Checksum: 0xab + */ +static const unsigned char test_edid_dvi_1080p[] = { + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x31, 0xd8, 0x2a, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x01, 0x03, 0x81, 0xa0, 0x5a, 0x78, + 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3a, 0x80, 0x18, 0x71, 0x38, + 0x2d, 0x40, 0x58, 0x2c, 0x45, 0x00, 0x40, 0x84, 0x63, 0x00, 0x00, 0x1e, + 0x00, 0x00, 0x00, 0xfc, 0x00, 0x54, 0x65, 0x73, 0x74, 0x20, 0x45, 0x44, + 0x49, 0x44, 0x0a, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x32, + 0x46, 0x1e, 0x46, 0x0f, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xab +}; + /* * edid-decode (hex): * * 00 ff ff ff ff ff ff 00 31 d8 2a 00 00 00 00 00 * 00 21 01 03 81 a0 5a 78 02 00 00 00 00 00 00 00 @@ -101,10 +159,112 @@ static const unsigned char test_edid_hdmi_1080p_rgb_max_200mhz[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0 }; +/* + * edid-decode (hex): + * + * 00 ff ff ff ff ff ff 00 31 d8 2a 00 00 00 00 00 + * 00 21 01 03 81 a0 5a 78 02 00 00 00 00 00 00 00 + * 00 00 00 20 00 00 01 01 01 01 01 01 01 01 01 01 + * 01 01 01 01 01 01 02 3a 80 18 71 38 2d 40 58 2c + * 45 00 40 84 63 00 00 1e 00 00 00 fc 00 54 65 73 + * 74 20 45 44 49 44 0a 20 20 20 00 00 00 fd 00 32 + * 46 1e 46 0f 00 0a 20 20 20 20 20 20 00 00 00 10 + * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 92 + * + * 02 03 1b 81 e3 05 00 20 41 10 e2 00 4a 6d 03 0c + * 00 12 34 00 28 20 00 00 00 00 00 00 00 00 00 00 + * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 d0 + * + * ---------------- + * + * Block 0, Base EDID: + * EDID Structure Version & Revision: 1.3 + * Vendor & Product Identification: + * Manufacturer: LNX + * Model: 42 + * Made in: 2023 + * Basic Display Parameters & Features: + * Digital display + * DFP 1.x compatible TMDS + * Maximum image size: 160 cm x 90 cm + * Gamma: 2.20 + * Monochrome or grayscale display + * First detailed timing is the preferred timing + * Color Characteristics: + * Red : 0.0000, 0.0000 + * Green: 0.0000, 0.0000 + * Blue : 0.0000, 0.0000 + * White: 0.0000, 0.0000 + * Established Timings I & II: + * DMT 0x04: 640x480 59.940476 Hz 4:3 31.469 kHz 25.175000 MHz + * Standard Timings: none + * Detailed Timing Descriptors: + * DTD 1: 1920x1080 60.000000 Hz 16:9 67.500 kHz 148.500000 MHz (1600 mm x 900 mm) + * Hfront 88 Hsync 44 Hback 148 Hpol P + * Vfront 4 Vsync 5 Vback 36 Vpol P + * Display Product Name: 'Test EDID' + * Display Range Limits: + * Monitor ranges (GTF): 50-70 Hz V, 30-70 kHz H, max dotclock 150 MHz + * Dummy Descriptor: + * Extension blocks: 1 + * Checksum: 0x92 + * + * ---------------- + * + * Block 1, CTA-861 Extension Block: + * Revision: 3 + * Underscans IT Video Formats by default + * Native detailed modes: 1 + * Colorimetry Data Block: + * sRGB + * Video Data Block: + * VIC 16: 1920x1080 60.000000 Hz 16:9 67.500 kHz 148.500000 MHz + * Video Capability Data Block: + * YCbCr quantization: No Data + * RGB quantization: Selectable (via AVI Q) + * PT scan behavior: No Data + * IT scan behavior: Always Underscanned + * CE scan behavior: Always Underscanned + * Vendor-Specific Data Block (HDMI), OUI 00-0C-03: + * Source physical address: 1.2.3.4 + * Maximum TMDS clock: 340 MHz + * Extended HDMI video details: + * Checksum: 0xd0 Unused space in Extension Block: 100 bytes + */ +static const unsigned char test_edid_hdmi_1080p_rgb_max_340mhz[] = { + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x31, 0xd8, 0x2a, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x01, 0x03, 0x81, 0xa0, 0x5a, 0x78, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3a, 0x80, 0x18, 0x71, 0x38, + 0x2d, 0x40, 0x58, 0x2c, 0x45, 0x00, 0x40, 0x84, 0x63, 0x00, 0x00, 0x1e, + 0x00, 0x00, 0x00, 0xfc, 0x00, 0x54, 0x65, 0x73, 0x74, 0x20, 0x45, 0x44, + 0x49, 0x44, 0x0a, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x32, + 0x46, 0x00, 0x00, 0xc4, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x41, 0x02, 0x03, 0x1b, 0x81, + 0xe3, 0x05, 0x00, 0x20, 0x41, 0x10, 0xe2, 0x00, 0x4a, 0x6d, 0x03, 0x0c, + 0x00, 0x12, 0x34, 0x00, 0x44, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xd0 +}; + /* * edid-decode (hex): * * 00 ff ff ff ff ff ff 00 31 d8 2a 00 00 00 00 00 * 00 21 01 03 81 a0 5a 78 1a 00 00 00 00 00 00 00 From patchwork Mon May 27 13:58:07 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Maxime Ripard X-Patchwork-Id: 799364 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 7B76616D4D3; Mon, 27 May 2024 13:58:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716818338; cv=none; b=IwXnrjQKPPLTR9+VnMeUohWOZCsz6D68KeBBp3T/fdrrUqFsxIQx9yNEFSkECItmD6IRdeOUPVd4kSl+hdBqq2UpiWxUqj/rlkmjzID2xLwhulkTpwQ6PqlF9hyLF5z+rdSoGOvEHQkfm1NrwD6BoHOnSj11iSR4E7BLDoyVrRU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716818338; c=relaxed/simple; bh=UYZ7nxiWf/wEqMOzilGnc0eAFRCtTlDtsq0ctTBFvgo=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Roa9Gphpjjm5DRteh+ZWY+FYSXiwH9dmvnEjqzpzkd2mynkMKI7D1uIvTvnCBFVba5XASDzc0bU5TRTeVgc+Ceckyy3Gwg4IQQ0jgW9p7v7Rugc7qtEKPu5SLE9J44+6A9NzTHRK1aRT4C7nKvfpjnf5asKiDf6ypX0JQ65ZHvM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=UdnrV08/; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="UdnrV08/" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 06EB9C4AF0A; Mon, 27 May 2024 13:58:57 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1716818338; bh=UYZ7nxiWf/wEqMOzilGnc0eAFRCtTlDtsq0ctTBFvgo=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=UdnrV08/YdFg0GazVLzzjcX5sz8Kck9JdDny0YnYcpT6B6TNiQlzM5PZJ9RYVMwe/ nr8NjbWYC57DioFdWzFZ3SlFB/nxZ+R6a3kG2ZP4Tfm8Xxmja5Cbxg2MutymBS53i3 F/cFAi5eYaRmFulMGPtkT1sqhYvWLYuVSKtXFT8pVgFsrZ2w6k84Qlz2IrBhRnSw40 7iW/VVe5Yf9gniGlf2JnyxRmA9vYcf70lmsdEK/J4yjT/JSkFPSbGWWn2XmRC+TZdJ J+n1wGZRft14QYr6zUWYxbUoqGaVOfXXrPCkK0eDVwLied8z6LAmdIu75zCDKynIEH WV11dHljJROtA== From: Maxime Ripard Date: Mon, 27 May 2024 15:58:07 +0200 Subject: [PATCH v15 18/29] drm/connector: hdmi: Add Broadcast RGB property Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20240527-kms-hdmi-connector-state-v15-18-c5af16c3aae2@kernel.org> References: <20240527-kms-hdmi-connector-state-v15-0-c5af16c3aae2@kernel.org> In-Reply-To: <20240527-kms-hdmi-connector-state-v15-0-c5af16c3aae2@kernel.org> To: Maarten Lankhorst , Thomas Zimmermann , David Airlie , Daniel Vetter , Jonathan Corbet , Sandy Huang , =?utf-8?q?Heiko_St=C3=BCbner?= , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Andy Yan Cc: Hans Verkuil , Sebastian Wick , =?utf-8?b?VmlsbGUgU3lyasOkbMOk?= , dri-devel@lists.freedesktop.org, linux-arm-kernel@lists.infradead.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-rockchip@lists.infradead.org, linux-sunxi@lists.linux.dev, Maxime Ripard , Dave Stevenson , Pekka Paalanen X-Mailer: b4 0.13.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=14188; i=mripard@kernel.org; h=from:subject:message-id; bh=UYZ7nxiWf/wEqMOzilGnc0eAFRCtTlDtsq0ctTBFvgo=; b=owGbwMvMwCmsHn9OcpHtvjLG02pJDGkhEzPYnt/RD+ToX3bq2e9Terd3zFy+2eLz/Dzuy87HC n7/qeBI7JjKwiDMySArpsjyRCbs9PL2xVUO9it/wMxhZQIZwsDFKQAT2cHL2NCSKGRgLLODadt+ 2dOrd/1XOazWzM14vGOJgJ7Tj+l+IWUmV1l2C56RP2Qqui1g4nnxzYx1asYBYSmRPK0nz0TOllx 4MprlKZefUaCdO1dS567jYo0vhZWeT3Dnt5D0zp82KbTxMScA X-Developer-Key: i=mripard@kernel.org; a=openpgp; fpr=BE5675C37E818C8B5764241C254BCFC56BF6CE8D The i915 driver has a property to force the RGB range of an HDMI output. The vc4 driver then implemented the same property with the same semantics. KWin has support for it, and a PR for mutter is also there to support it. Both drivers implementing the same property with the same semantics, plus the userspace having support for it, is proof enough that it's pretty much a de-facto standard now and we can provide helpers for it. Let's plumb it into the newly created HDMI connector. Reviewed-by: Dave Stevenson Acked-by: Pekka Paalanen Reviewed-by: Sebastian Wick Signed-off-by: Maxime Ripard --- Documentation/gpu/kms-properties.csv | 1 - drivers/gpu/drm/display/drm_hdmi_state_helper.c | 4 +- drivers/gpu/drm/drm_atomic.c | 2 + drivers/gpu/drm/drm_atomic_uapi.c | 4 ++ drivers/gpu/drm/drm_connector.c | 88 +++++++++++++++++++++++++ include/drm/drm_connector.h | 36 ++++++++++ 6 files changed, 133 insertions(+), 2 deletions(-) diff --git a/Documentation/gpu/kms-properties.csv b/Documentation/gpu/kms-properties.csv index c3c50a277cc9..bfbfbf4f102d 100644 --- a/Documentation/gpu/kms-properties.csv +++ b/Documentation/gpu/kms-properties.csv @@ -15,11 +15,10 @@ Owner Module/Drivers,Group,Property Name,Type,Property Values,Object attached,De ,,“saturation”,RANGE,"Min=0, Max=100",Connector,TBD ,,“hue”,RANGE,"Min=0, Max=100",Connector,TBD ,Virtual GPU,“suggested X”,RANGE,"Min=0, Max=0xffffffff",Connector,property to suggest an X offset for a connector ,,“suggested Y”,RANGE,"Min=0, Max=0xffffffff",Connector,property to suggest an Y offset for a connector ,Optional,"""aspect ratio""",ENUM,"{ ""None"", ""4:3"", ""16:9"" }",Connector,TDB -i915,Generic,"""Broadcast RGB""",ENUM,"{ ""Automatic"", ""Full"", ""Limited 16:235"" }",Connector,"When this property is set to Limited 16:235 and CTM is set, the hardware will be programmed with the result of the multiplication of CTM by the limited range matrix to ensure the pixels normally in the range 0..1.0 are remapped to the range 16/255..235/255." ,,“audio”,ENUM,"{ ""force-dvi"", ""off"", ""auto"", ""on"" }",Connector,TBD ,SDVO-TV,“mode”,ENUM,"{ ""NTSC_M"", ""NTSC_J"", ""NTSC_443"", ""PAL_B"" } etc.",Connector,TBD ,,"""left_margin""",RANGE,"Min=0, Max= SDVO dependent",Connector,TBD ,,"""right_margin""",RANGE,"Min=0, Max= SDVO dependent",Connector,TBD ,,"""top_margin""",RANGE,"Min=0, Max= SDVO dependent",Connector,TBD diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c index 1623b96cd97c..57c66beec5bc 100644 --- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c +++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c @@ -23,10 +23,11 @@ void __drm_atomic_helper_connector_hdmi_reset(struct drm_connector *connector, { unsigned int max_bpc = connector->max_bpc; new_conn_state->max_bpc = max_bpc; new_conn_state->max_requested_bpc = max_bpc; + new_conn_state->hdmi.broadcast_rgb = DRM_HDMI_BROADCAST_RGB_AUTO; } EXPORT_SYMBOL(__drm_atomic_helper_connector_hdmi_reset); static const struct drm_display_mode * connector_state_get_mode(const struct drm_connector_state *conn_state) @@ -330,11 +331,12 @@ int drm_atomic_helper_connector_hdmi_check(struct drm_connector *connector, ret = hdmi_compute_config(connector, new_conn_state, mode); if (ret) return ret; - if (old_conn_state->hdmi.output_bpc != new_conn_state->hdmi.output_bpc || + if (old_conn_state->hdmi.broadcast_rgb != new_conn_state->hdmi.broadcast_rgb || + old_conn_state->hdmi.output_bpc != new_conn_state->hdmi.output_bpc || old_conn_state->hdmi.output_format != new_conn_state->hdmi.output_format) { struct drm_crtc *crtc = new_conn_state->crtc; struct drm_crtc_state *crtc_state; crtc_state = drm_atomic_get_crtc_state(state, crtc); diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 26f9e525c0a0..3e57d98d8418 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -1143,10 +1143,12 @@ static void drm_atomic_connector_print_state(struct drm_printer *p, drm_printf(p, "\tmax_requested_bpc=%d\n", state->max_requested_bpc); drm_printf(p, "\tcolorspace=%s\n", drm_get_colorspace_name(state->colorspace)); if (connector->connector_type == DRM_MODE_CONNECTOR_HDMIA || connector->connector_type == DRM_MODE_CONNECTOR_HDMIB) { + drm_printf(p, "\tbroadcast_rgb=%s\n", + drm_hdmi_connector_get_broadcast_rgb_name(state->hdmi.broadcast_rgb)); drm_printf(p, "\toutput_bpc=%u\n", state->hdmi.output_bpc); drm_printf(p, "\toutput_format=%s\n", drm_hdmi_connector_get_output_format_name(state->hdmi.output_format)); drm_printf(p, "\ttmds_char_rate=%llu\n", state->hdmi.tmds_char_rate); } diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c index fc16fddee5c5..22bbb2d83e30 100644 --- a/drivers/gpu/drm/drm_atomic_uapi.c +++ b/drivers/gpu/drm/drm_atomic_uapi.c @@ -774,10 +774,12 @@ static int drm_atomic_connector_set_property(struct drm_connector *connector, fence_ptr); } else if (property == connector->max_bpc_property) { state->max_requested_bpc = val; } else if (property == connector->privacy_screen_sw_state_property) { state->privacy_screen_sw_state = val; + } else if (property == connector->broadcast_rgb_property) { + state->hdmi.broadcast_rgb = val; } else if (connector->funcs->atomic_set_property) { return connector->funcs->atomic_set_property(connector, state, property, val); } else { drm_dbg_atomic(connector->dev, @@ -857,10 +859,12 @@ drm_atomic_connector_get_property(struct drm_connector *connector, *val = 0; } else if (property == connector->max_bpc_property) { *val = state->max_requested_bpc; } else if (property == connector->privacy_screen_sw_state_property) { *val = state->privacy_screen_sw_state; + } else if (property == connector->broadcast_rgb_property) { + *val = state->hdmi.broadcast_rgb; } else if (connector->funcs->atomic_get_property) { return connector->funcs->atomic_get_property(connector, state, property, val); } else { drm_dbg_atomic(dev, diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index 555eac20e5a4..bdd3361ccc73 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -1210,10 +1210,33 @@ static const u32 dp_colorspaces = BIT(DRM_MODE_COLORIMETRY_SYCC_601) | BIT(DRM_MODE_COLORIMETRY_OPYCC_601) | BIT(DRM_MODE_COLORIMETRY_BT2020_CYCC) | BIT(DRM_MODE_COLORIMETRY_BT2020_YCC); +static const struct drm_prop_enum_list broadcast_rgb_names[] = { + { DRM_HDMI_BROADCAST_RGB_AUTO, "Automatic" }, + { DRM_HDMI_BROADCAST_RGB_FULL, "Full" }, + { DRM_HDMI_BROADCAST_RGB_LIMITED, "Limited 16:235" }, +}; + +/* + * drm_hdmi_connector_get_broadcast_rgb_name - Return a string for HDMI connector RGB broadcast selection + * @broadcast_rgb: Broadcast RGB selection to compute name of + * + * Returns: the name of the Broadcast RGB selection, or NULL if the type + * is not valid. + */ +const char * +drm_hdmi_connector_get_broadcast_rgb_name(enum drm_hdmi_broadcast_rgb broadcast_rgb) +{ + if (broadcast_rgb >= ARRAY_SIZE(broadcast_rgb_names)) + return NULL; + + return broadcast_rgb_names[broadcast_rgb].name; +} +EXPORT_SYMBOL(drm_hdmi_connector_get_broadcast_rgb_name); + static const char * const output_format_str[] = { [HDMI_COLORSPACE_RGB] = "RGB", [HDMI_COLORSPACE_YUV420] = "YUV 4:2:0", [HDMI_COLORSPACE_YUV422] = "YUV 4:2:2", [HDMI_COLORSPACE_YUV444] = "YUV 4:4:4", @@ -1706,10 +1729,42 @@ void drm_connector_attach_dp_subconnector_property(struct drm_connector *connect EXPORT_SYMBOL(drm_connector_attach_dp_subconnector_property); /** * DOC: HDMI connector properties * + * Broadcast RGB (HDMI specific) + * Indicates the Quantization Range (Full vs Limited) used. The color + * processing pipeline will be adjusted to match the value of the + * property, and the Infoframes will be generated and sent accordingly. + * + * This property is only relevant if the HDMI output format is RGB. If + * it's one of the YCbCr variant, it will be ignored. + * + * The CRTC attached to the connector must be configured by user-space to + * always produce full-range pixels. + * + * The value of this property can be one of the following: + * + * Automatic: + * The quantization range is selected automatically based on the + * mode according to the HDMI specifications (HDMI 1.4b - Section + * 6.6 - Video Quantization Ranges). + * + * Full: + * Full quantization range is forced. + * + * Limited 16:235: + * Limited quantization range is forced. Unlike the name suggests, + * this works for any number of bits-per-component. + * + * Property values other than Automatic can result in colors being off (if + * limited is selected but the display expects full), or a black screen + * (if full is selected but the display expects limited). + * + * Drivers can set up this property by calling + * drm_connector_attach_broadcast_rgb_property(). + * * content type (HDMI specific): * Indicates content type setting to be used in HDMI infoframes to indicate * content type for the external device, so that it adjusts its display * settings accordingly. * @@ -2568,10 +2623,43 @@ int drm_connector_attach_hdr_output_metadata_property(struct drm_connector *conn return 0; } EXPORT_SYMBOL(drm_connector_attach_hdr_output_metadata_property); +/** + * drm_connector_attach_broadcast_rgb_property - attach "Broadcast RGB" property + * @connector: connector to attach the property on. + * + * This is used to add support for forcing the RGB range on a connector + * + * Returns: + * Zero on success, negative errno on failure. + */ +int drm_connector_attach_broadcast_rgb_property(struct drm_connector *connector) +{ + struct drm_device *dev = connector->dev; + struct drm_property *prop; + + prop = connector->broadcast_rgb_property; + if (!prop) { + prop = drm_property_create_enum(dev, DRM_MODE_PROP_ENUM, + "Broadcast RGB", + broadcast_rgb_names, + ARRAY_SIZE(broadcast_rgb_names)); + if (!prop) + return -EINVAL; + + connector->broadcast_rgb_property = prop; + } + + drm_object_attach_property(&connector->base, prop, + DRM_HDMI_BROADCAST_RGB_AUTO); + + return 0; +} +EXPORT_SYMBOL(drm_connector_attach_broadcast_rgb_property); + /** * drm_connector_attach_colorspace_property - attach "Colorspace" property * @connector: connector to attach the property on. * * This is used to allow the userspace to signal the output colorspace diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 3c0b6694074f..a40eaf3a8ce4 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -367,10 +367,33 @@ enum drm_panel_orientation { DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP, DRM_MODE_PANEL_ORIENTATION_LEFT_UP, DRM_MODE_PANEL_ORIENTATION_RIGHT_UP, }; +/** + * enum drm_hdmi_broadcast_rgb - Broadcast RGB Selection for an HDMI @drm_connector + */ +enum drm_hdmi_broadcast_rgb { + /** + * @DRM_HDMI_BROADCAST_RGB_AUTO: The RGB range is selected + * automatically based on the mode. + */ + DRM_HDMI_BROADCAST_RGB_AUTO, + + /** + * @DRM_HDMI_BROADCAST_RGB_FULL: Full range RGB is forced. + */ + DRM_HDMI_BROADCAST_RGB_FULL, + + /** + * @DRM_HDMI_BROADCAST_RGB_LIMITED: Limited range RGB is forced. + */ + DRM_HDMI_BROADCAST_RGB_LIMITED, +}; + +const char * +drm_hdmi_connector_get_broadcast_rgb_name(enum drm_hdmi_broadcast_rgb broadcast_rgb); const char * drm_hdmi_connector_get_output_format_name(enum hdmi_colorspace fmt); /** * struct drm_monitor_range_info - Panel's Monitor range in EDID for @@ -1039,10 +1062,16 @@ struct drm_connector_state { /** * @hdmi: HDMI-related variable and properties. Filled by * @drm_atomic_helper_connector_hdmi_check(). */ struct { + /** + * @broadcast_rgb: Connector property to pass the + * Broadcast RGB selection value. + */ + enum drm_hdmi_broadcast_rgb broadcast_rgb; + /** * @output_bpc: Bits per color channel to output. */ unsigned int output_bpc; @@ -1751,10 +1780,16 @@ struct drm_connector { * @privacy_screen_hw_state_property: Optional atomic property for the * connector to report the actual integrated privacy screen state. */ struct drm_property *privacy_screen_hw_state_property; + /** + * @broadcast_rgb_property: Connector property to set the + * Broadcast RGB selection to output with. + */ + struct drm_property *broadcast_rgb_property; + #define DRM_CONNECTOR_POLL_HPD (1 << 0) #define DRM_CONNECTOR_POLL_CONNECT (1 << 1) #define DRM_CONNECTOR_POLL_DISCONNECT (1 << 2) /** @@ -2090,10 +2125,11 @@ int drm_mode_create_scaling_mode_property(struct drm_device *dev); int drm_connector_attach_content_type_property(struct drm_connector *dev); int drm_connector_attach_scaling_mode_property(struct drm_connector *connector, u32 scaling_mode_mask); int drm_connector_attach_vrr_capable_property( struct drm_connector *connector); +int drm_connector_attach_broadcast_rgb_property(struct drm_connector *connector); int drm_connector_attach_colorspace_property(struct drm_connector *connector); int drm_connector_attach_hdr_output_metadata_property(struct drm_connector *connector); bool drm_connector_atomic_hdr_metadata_equal(struct drm_connector_state *old_state, struct drm_connector_state *new_state); int drm_mode_create_aspect_ratio_property(struct drm_device *dev); From patchwork Mon May 27 13:58:09 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Maxime Ripard X-Patchwork-Id: 799363 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 461F016D9B8; Mon, 27 May 2024 13:59:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716818344; cv=none; b=cVE3JsVrNjNdTaFKlshZwTim3CvxeEm3X8EI9GPz0HlkubJnY+mBXYZgdBpEkPmPw54XUc9iNK5OhakC6Bz3JVV6o7Ej4BeD+AjtEJWjPdxgJHCMrgDeC6JKIigvjgjqZIJ/WXdbXirHhD/jLndlYQtqzYZWKu5eDKgqn6W37MI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716818344; c=relaxed/simple; bh=UpH8jpECjgQvgSwNp+mVa+fgJ+awA1gYcQr4Ls9pDbg=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=h8jtQhfBM87hXHrpebmMvCpqA8VaY5jNy/hE6Lslr+HyRWZpOP251DdgqDvG9vRndBx3ux8LUhmErK33XYbAK/g1vkY1KfvNja0/FrgDwJHsDjMMP/sWKNgAczH31buMy7BkDYvXCPqBjvH477E7MiAU0eWTWORTZ2cPx82ItEU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=p6B+bCEl; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="p6B+bCEl" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 6BEF7C2BBFC; Mon, 27 May 2024 13:59:03 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1716818343; bh=UpH8jpECjgQvgSwNp+mVa+fgJ+awA1gYcQr4Ls9pDbg=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=p6B+bCEllwpcfP1jyTfhfnDz9WD4V8BqaD+zSEPYxpw5An+uVuY/c5lrZVQDcoDkF XXonuFvQl6KWGColqrKL47xgQOGMy7nr8/yDvgA9kZB8vEIVM92UVbfBiQtKKznZjS nabVlasj9Meq4KuSouw0cXqlJF5dMCGhObUjIodf+k1zaWn5X+HRyBHt8tXtnVMK3S 7D+9U5VKfupqu9zuKBc/DT6H2CSVDiFl2RqK29v1Xcp+PVKtmRRlZXDXsWNxgyNbgJ QtcijMx3AybADM0pUwb9nHgXF0Y69fJRz1jQXIRKv4IWy1puYpDUv1zuNTgKAlVrQM H8ZeNVsxRlAqg== From: Maxime Ripard Date: Mon, 27 May 2024 15:58:09 +0200 Subject: [PATCH v15 20/29] drm/connector: hdmi: Add RGB Quantization Range to the connector state Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20240527-kms-hdmi-connector-state-v15-20-c5af16c3aae2@kernel.org> References: <20240527-kms-hdmi-connector-state-v15-0-c5af16c3aae2@kernel.org> In-Reply-To: <20240527-kms-hdmi-connector-state-v15-0-c5af16c3aae2@kernel.org> To: Maarten Lankhorst , Thomas Zimmermann , David Airlie , Daniel Vetter , Jonathan Corbet , Sandy Huang , =?utf-8?q?Heiko_St=C3=BCbner?= , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Andy Yan Cc: Hans Verkuil , Sebastian Wick , =?utf-8?b?VmlsbGUgU3lyasOkbMOk?= , dri-devel@lists.freedesktop.org, linux-arm-kernel@lists.infradead.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-rockchip@lists.infradead.org, linux-sunxi@lists.linux.dev, Maxime Ripard , Dave Stevenson , Dmitry Baryshkov X-Mailer: b4 0.13.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=4161; i=mripard@kernel.org; h=from:subject:message-id; bh=UpH8jpECjgQvgSwNp+mVa+fgJ+awA1gYcQr4Ls9pDbg=; b=owGbwMvMwCmsHn9OcpHtvjLG02pJDGkhEzO/TpsoFTjJd8JJITl293UqSRbf27IsnsUv6FJ4f OpPYv7DjqksDMKcDLJiiixPZMJOL29fXOVgv/IHzBxWJpAhDFycAjCR1M+MDdNYHPXCNykYKCfM d//8VGFNvrWLr7zY+6vCvasjI01f7Zx8l+vcl0A9+f8T1smGF1alM9bw2qYpnZC/vl3A6eP2DpM dG1I66nQWb+BrXX61Lsv4i1Vu+3Ed5guahRsFT6l3y5t+0AIA X-Developer-Key: i=mripard@kernel.org; a=openpgp; fpr=BE5675C37E818C8B5764241C254BCFC56BF6CE8D HDMI controller drivers will need to figure out the RGB range they need to configure based on a mode and property values. Let's expose that in the HDMI connector state so drivers can just use that value. Reviewed-by: Dave Stevenson Reviewed-by: Dmitry Baryshkov Signed-off-by: Maxime Ripard --- drivers/gpu/drm/display/drm_hdmi_state_helper.c | 29 +++++++++++++++++++++++++ drivers/gpu/drm/drm_atomic.c | 1 + include/drm/drm_connector.h | 6 +++++ 3 files changed, 36 insertions(+) diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c index 57c66beec5bc..f18020cfe4ea 100644 --- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c +++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c @@ -49,10 +49,37 @@ connector_state_get_mode(const struct drm_connector_state *conn_state) return NULL; return &crtc_state->mode; } +static bool hdmi_is_limited_range(const struct drm_connector *connector, + const struct drm_connector_state *conn_state) +{ + const struct drm_display_info *info = &connector->display_info; + const struct drm_display_mode *mode = + connector_state_get_mode(conn_state); + + /* + * The Broadcast RGB property only applies to RGB format, and + * i915 just assumes limited range for YCbCr output, so let's + * just do the same. + */ + if (conn_state->hdmi.output_format != HDMI_COLORSPACE_RGB) + return true; + + if (conn_state->hdmi.broadcast_rgb == DRM_HDMI_BROADCAST_RGB_FULL) + return false; + + if (conn_state->hdmi.broadcast_rgb == DRM_HDMI_BROADCAST_RGB_LIMITED) + return true; + + if (!info->is_hdmi) + return false; + + return drm_default_rgb_quant_range(mode) == HDMI_QUANTIZATION_RANGE_LIMITED; +} + static bool sink_supports_format_bpc(const struct drm_connector *connector, const struct drm_display_info *info, const struct drm_display_mode *mode, unsigned int format, unsigned int bpc) @@ -327,10 +354,12 @@ int drm_atomic_helper_connector_hdmi_check(struct drm_connector *connector, drm_atomic_get_new_connector_state(state, connector); const struct drm_display_mode *mode = connector_state_get_mode(new_conn_state); int ret; + new_conn_state->hdmi.is_limited_range = hdmi_is_limited_range(connector, new_conn_state); + ret = hdmi_compute_config(connector, new_conn_state, mode); if (ret) return ret; if (old_conn_state->hdmi.broadcast_rgb != new_conn_state->hdmi.broadcast_rgb || diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 3e57d98d8418..07b4b394e3bf 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -1145,10 +1145,11 @@ static void drm_atomic_connector_print_state(struct drm_printer *p, if (connector->connector_type == DRM_MODE_CONNECTOR_HDMIA || connector->connector_type == DRM_MODE_CONNECTOR_HDMIB) { drm_printf(p, "\tbroadcast_rgb=%s\n", drm_hdmi_connector_get_broadcast_rgb_name(state->hdmi.broadcast_rgb)); + drm_printf(p, "\tis_limited_range=%c\n", state->hdmi.is_limited_range ? 'y' : 'n'); drm_printf(p, "\toutput_bpc=%u\n", state->hdmi.output_bpc); drm_printf(p, "\toutput_format=%s\n", drm_hdmi_connector_get_output_format_name(state->hdmi.output_format)); drm_printf(p, "\ttmds_char_rate=%llu\n", state->hdmi.tmds_char_rate); } diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index a40eaf3a8ce4..1fca26d51218 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -1068,10 +1068,16 @@ struct drm_connector_state { * @broadcast_rgb: Connector property to pass the * Broadcast RGB selection value. */ enum drm_hdmi_broadcast_rgb broadcast_rgb; + /** + * @is_full_range: Is the output supposed to use a full + * RGB Quantization Range or not? + */ + bool is_limited_range; + /** * @output_bpc: Bits per color channel to output. */ unsigned int output_bpc; From patchwork Mon May 27 13:58:11 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Maxime Ripard X-Patchwork-Id: 799362 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 7903416DEC2; Mon, 27 May 2024 13:59:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716818349; cv=none; b=tULNtxxdLs5wwuytm4WpWXs/jLpn+he/FDCtDrY9Jx8T/U5cOTEvHQ0ONF4GHyJARBAWREDVIGJPphIz6xtfRlQA9Wax8y74QeoU0BpCApUVmWuPCPOrdzRyb08t4C+FgnSYacRl+1p8wnTwLUWQz3c+r/d+p3ssTvW/hINruQk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716818349; c=relaxed/simple; bh=uC1FylYpPNc98tJ9Gl/fdyo2DgChFAc8B0kSqJCBDRY=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=O6+iUgILKunohGgNqT9v/UBsDugAgOf6yYnsyzGqBsIVApBuC5Qoxkh9jJwpKnPINSbwhDLyjI6s08BK/v+ZYARKXBN7LhnnZpc5tADyfMehq5rgJe6yDzA4ZAEnCpGurn6uVAOxnqdTKfpf+G9apzklqPrUMFr/0A7wkh5YdmM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=tJisAZoC; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="tJisAZoC" Received: by smtp.kernel.org (Postfix) with ESMTPSA id C99C8C32789; Mon, 27 May 2024 13:59:08 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1716818349; bh=uC1FylYpPNc98tJ9Gl/fdyo2DgChFAc8B0kSqJCBDRY=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=tJisAZoCnc/ngyOqAoew8mlrQOwaw4Bo/USPmRgMSbw2GBLcwgRS8u/MUihv/F9E3 isq8tUdrychxvmDU17RJ5KTcCcuwjykAj4K+a3yRG0F8Qv/XHArSiCbUvQOUjTvwSQ 4jviK1+JzY/9zcfpaollIDLe+YWRuerSfzLoSONStRxe7M2Oc2ZkCZ9FHZpB7SguoX Mv5BILan4N3So/2bch5OR4iA7wE7RDR1EcNrwwhNeijJzH3LKIPC5A3+v8tuuULnPt XG/NvXCSw48h4N18rrGtihrm83r1itdZerfxU6VEx1PrL5lB4KS0JRQDCYczBRkYje qGdG1E/3Bip6w== From: Maxime Ripard Date: Mon, 27 May 2024 15:58:11 +0200 Subject: [PATCH v15 22/29] drm/connector: hdmi: Add Infoframes generation Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20240527-kms-hdmi-connector-state-v15-22-c5af16c3aae2@kernel.org> References: <20240527-kms-hdmi-connector-state-v15-0-c5af16c3aae2@kernel.org> In-Reply-To: <20240527-kms-hdmi-connector-state-v15-0-c5af16c3aae2@kernel.org> To: Maarten Lankhorst , Thomas Zimmermann , David Airlie , Daniel Vetter , Jonathan Corbet , Sandy Huang , =?utf-8?q?Heiko_St=C3=BCbner?= , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Andy Yan Cc: Hans Verkuil , Sebastian Wick , =?utf-8?b?VmlsbGUgU3lyasOkbMOk?= , dri-devel@lists.freedesktop.org, linux-arm-kernel@lists.infradead.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-rockchip@lists.infradead.org, linux-sunxi@lists.linux.dev, Maxime Ripard , Dmitry Baryshkov X-Mailer: b4 0.13.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=27023; i=mripard@kernel.org; h=from:subject:message-id; bh=uC1FylYpPNc98tJ9Gl/fdyo2DgChFAc8B0kSqJCBDRY=; b=owGbwMvMwCmsHn9OcpHtvjLG02pJDGkhE7NeFXRLf1Tn/5bqkz6RreKJ3hSjbf5rJDaZGvRuZ WwoUObomMrCIMzJICumyPJEJuz08vbFVQ72K3/AzGFlAhnCwMUpABNRdGVs+FQd8IXv9Jsn6/WZ 29RPaT+JMw9xDXC+95J/dl/kkzcmLlyZZj4T/Y/H2P2M2cDq2dHL2ND3oNXzlrl6oPOhSXMZLkZ OeOu6oFTxFd/6xPd3XS6/4H7hwT074/3GpEXHNrSHHTpwxgkA X-Developer-Key: i=mripard@kernel.org; a=openpgp; fpr=BE5675C37E818C8B5764241C254BCFC56BF6CE8D Infoframes in KMS is usually handled by a bunch of low-level helpers that require quite some boilerplate for drivers. This leads to discrepancies with how drivers generate them, and which are actually sent. Now that we have everything needed to generate them in the HDMI connector state, we can generate them in our common logic so that drivers can simply reuse what we precomputed. Cc: Ville Syrjälä Reviewed-by: Dmitry Baryshkov Signed-off-by: Maxime Ripard --- drivers/gpu/drm/display/drm_hdmi_state_helper.c | 336 +++++++++++++++++++++ drivers/gpu/drm/drm_connector.c | 14 + drivers/gpu/drm/tests/drm_connector_test.c | 12 + drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 1 + include/drm/display/drm_hdmi_state_helper.h | 7 + include/drm/drm_connector.h | 111 ++++++- 6 files changed, 480 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c index f18020cfe4ea..ce96837eea65 100644 --- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c +++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c @@ -331,10 +331,148 @@ hdmi_compute_config(const struct drm_connector *connector, } return -EINVAL; } +static int hdmi_generate_avi_infoframe(const struct drm_connector *connector, + struct drm_connector_state *conn_state) +{ + const struct drm_display_mode *mode = + connector_state_get_mode(conn_state); + struct drm_connector_hdmi_infoframe *infoframe = + &conn_state->hdmi.infoframes.avi; + struct hdmi_avi_infoframe *frame = + &infoframe->data.avi; + bool is_limited_range = conn_state->hdmi.is_limited_range; + enum hdmi_quantization_range rgb_quant_range = + is_limited_range ? HDMI_QUANTIZATION_RANGE_LIMITED : HDMI_QUANTIZATION_RANGE_FULL; + int ret; + + ret = drm_hdmi_avi_infoframe_from_display_mode(frame, connector, mode); + if (ret) + return ret; + + frame->colorspace = conn_state->hdmi.output_format; + + /* + * FIXME: drm_hdmi_avi_infoframe_quant_range() doesn't handle + * YUV formats at all at the moment, so if we ever support YUV + * formats this needs to be revised. + */ + drm_hdmi_avi_infoframe_quant_range(frame, connector, mode, rgb_quant_range); + drm_hdmi_avi_infoframe_colorimetry(frame, conn_state); + drm_hdmi_avi_infoframe_bars(frame, conn_state); + + infoframe->set = true; + + return 0; +} + +static int hdmi_generate_spd_infoframe(const struct drm_connector *connector, + struct drm_connector_state *conn_state) +{ + struct drm_connector_hdmi_infoframe *infoframe = + &conn_state->hdmi.infoframes.spd; + struct hdmi_spd_infoframe *frame = + &infoframe->data.spd; + int ret; + + ret = hdmi_spd_infoframe_init(frame, + connector->hdmi.vendor, + connector->hdmi.product); + if (ret) + return ret; + + frame->sdi = HDMI_SPD_SDI_PC; + + infoframe->set = true; + + return 0; +} + +static int hdmi_generate_hdr_infoframe(const struct drm_connector *connector, + struct drm_connector_state *conn_state) +{ + struct drm_connector_hdmi_infoframe *infoframe = + &conn_state->hdmi.infoframes.hdr_drm; + struct hdmi_drm_infoframe *frame = + &infoframe->data.drm; + int ret; + + if (connector->max_bpc < 10) + return 0; + + if (!conn_state->hdr_output_metadata) + return 0; + + ret = drm_hdmi_infoframe_set_hdr_metadata(frame, conn_state); + if (ret) + return ret; + + infoframe->set = true; + + return 0; +} + +static int hdmi_generate_hdmi_vendor_infoframe(const struct drm_connector *connector, + struct drm_connector_state *conn_state) +{ + const struct drm_display_info *info = &connector->display_info; + const struct drm_display_mode *mode = + connector_state_get_mode(conn_state); + struct drm_connector_hdmi_infoframe *infoframe = + &conn_state->hdmi.infoframes.hdmi; + struct hdmi_vendor_infoframe *frame = + &infoframe->data.vendor.hdmi; + int ret; + + if (!info->has_hdmi_infoframe) + return 0; + + ret = drm_hdmi_vendor_infoframe_from_display_mode(frame, connector, mode); + if (ret) + return ret; + + infoframe->set = true; + + return 0; +} + +static int +hdmi_generate_infoframes(const struct drm_connector *connector, + struct drm_connector_state *conn_state) +{ + const struct drm_display_info *info = &connector->display_info; + int ret; + + if (!info->is_hdmi) + return 0; + + ret = hdmi_generate_avi_infoframe(connector, conn_state); + if (ret) + return ret; + + ret = hdmi_generate_spd_infoframe(connector, conn_state); + if (ret) + return ret; + + /* + * Audio Infoframes will be generated by ALSA, and updated by + * drm_atomic_helper_connector_hdmi_update_audio_infoframe(). + */ + + ret = hdmi_generate_hdr_infoframe(connector, conn_state); + if (ret) + return ret; + + ret = hdmi_generate_hdmi_vendor_infoframe(connector, conn_state); + if (ret) + return ret; + + return 0; +} + /** * drm_atomic_helper_connector_hdmi_check() - Helper to check HDMI connector atomic state * @connector: DRM Connector * @state: the DRM State object * @@ -360,10 +498,14 @@ int drm_atomic_helper_connector_hdmi_check(struct drm_connector *connector, ret = hdmi_compute_config(connector, new_conn_state, mode); if (ret) return ret; + ret = hdmi_generate_infoframes(connector, new_conn_state); + if (ret) + return ret; + if (old_conn_state->hdmi.broadcast_rgb != new_conn_state->hdmi.broadcast_rgb || old_conn_state->hdmi.output_bpc != new_conn_state->hdmi.output_bpc || old_conn_state->hdmi.output_format != new_conn_state->hdmi.output_format) { struct drm_crtc *crtc = new_conn_state->crtc; struct drm_crtc_state *crtc_state; @@ -376,5 +518,199 @@ int drm_atomic_helper_connector_hdmi_check(struct drm_connector *connector, } return 0; } EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_check); + +#define HDMI_MAX_INFOFRAME_SIZE 29 + +static int clear_device_infoframe(struct drm_connector *connector, + enum hdmi_infoframe_type type) +{ + const struct drm_connector_hdmi_funcs *funcs = connector->hdmi.funcs; + struct drm_device *dev = connector->dev; + int ret; + + drm_dbg_kms(dev, "Clearing infoframe type 0x%x\n", type); + + if (!funcs || !funcs->clear_infoframe) { + drm_dbg_kms(dev, "Function not implemented, bailing.\n"); + return 0; + } + + ret = funcs->clear_infoframe(connector, type); + if (ret) { + drm_dbg_kms(dev, "Call failed: %d\n", ret); + return ret; + } + + return 0; +} + +static int clear_infoframe(struct drm_connector *connector, + struct drm_connector_hdmi_infoframe *old_frame) +{ + int ret; + + ret = clear_device_infoframe(connector, old_frame->data.any.type); + if (ret) + return ret; + + return 0; +} + +static int write_device_infoframe(struct drm_connector *connector, + union hdmi_infoframe *frame) +{ + const struct drm_connector_hdmi_funcs *funcs = connector->hdmi.funcs; + struct drm_device *dev = connector->dev; + u8 buffer[HDMI_MAX_INFOFRAME_SIZE]; + int ret; + int len; + + drm_dbg_kms(dev, "Writing infoframe type %x\n", frame->any.type); + + if (!funcs || !funcs->write_infoframe) { + drm_dbg_kms(dev, "Function not implemented, bailing.\n"); + return -ENOSYS; + } + + len = hdmi_infoframe_pack(frame, buffer, sizeof(buffer)); + if (len < 0) + return len; + + ret = funcs->write_infoframe(connector, frame->any.type, buffer, len); + if (ret) { + drm_dbg_kms(dev, "Call failed: %d\n", ret); + return ret; + } + + return 0; +} + +static int write_infoframe(struct drm_connector *connector, + struct drm_connector_hdmi_infoframe *new_frame) +{ + int ret; + + ret = write_device_infoframe(connector, &new_frame->data); + if (ret) + return ret; + + return 0; +} + +static int write_or_clear_infoframe(struct drm_connector *connector, + struct drm_connector_hdmi_infoframe *old_frame, + struct drm_connector_hdmi_infoframe *new_frame) +{ + if (new_frame->set) + return write_infoframe(connector, new_frame); + + if (old_frame->set && !new_frame->set) + return clear_infoframe(connector, old_frame); + + return 0; +} + +/** + * drm_atomic_helper_connector_hdmi_update_infoframes - Update the Infoframes + * @connector: A pointer to the HDMI connector + * @state: The HDMI connector state to generate the infoframe from + * + * This function is meant for HDMI connector drivers to write their + * infoframes. It will typically be used in a + * @drm_connector_helper_funcs.atomic_enable implementation. + * + * Returns: + * Zero on success, error code on failure. + */ +int drm_atomic_helper_connector_hdmi_update_infoframes(struct drm_connector *connector, + struct drm_atomic_state *state) +{ + struct drm_connector_state *old_conn_state = + drm_atomic_get_old_connector_state(state, connector); + struct drm_connector_state *new_conn_state = + drm_atomic_get_new_connector_state(state, connector); + struct drm_display_info *info = &connector->display_info; + int ret; + + if (!info->is_hdmi) + return 0; + + mutex_lock(&connector->hdmi.infoframes.lock); + + ret = write_or_clear_infoframe(connector, + &old_conn_state->hdmi.infoframes.avi, + &new_conn_state->hdmi.infoframes.avi); + if (ret) + goto out; + + if (connector->hdmi.infoframes.audio.set) { + ret = write_infoframe(connector, + &connector->hdmi.infoframes.audio); + if (ret) + goto out; + } + + ret = write_or_clear_infoframe(connector, + &old_conn_state->hdmi.infoframes.hdr_drm, + &new_conn_state->hdmi.infoframes.hdr_drm); + if (ret) + goto out; + + ret = write_or_clear_infoframe(connector, + &old_conn_state->hdmi.infoframes.spd, + &new_conn_state->hdmi.infoframes.spd); + if (ret) + goto out; + + if (info->has_hdmi_infoframe) { + ret = write_or_clear_infoframe(connector, + &old_conn_state->hdmi.infoframes.hdmi, + &new_conn_state->hdmi.infoframes.hdmi); + if (ret) + goto out; + } + +out: + mutex_unlock(&connector->hdmi.infoframes.lock); + return ret; +} +EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_update_infoframes); + +/** + * drm_atomic_helper_connector_hdmi_update_audio_infoframe - Update the Audio Infoframe + * @connector: A pointer to the HDMI connector + * @frame: A pointer to the audio infoframe to write + * + * This function is meant for HDMI connector drivers to update their + * audio infoframe. It will typically be used in one of the ALSA hooks + * (most likely prepare). + * + * Returns: + * Zero on success, error code on failure. + */ +int +drm_atomic_helper_connector_hdmi_update_audio_infoframe(struct drm_connector *connector, + struct hdmi_audio_infoframe *frame) +{ + struct drm_connector_hdmi_infoframe *infoframe = + &connector->hdmi.infoframes.audio; + struct drm_display_info *info = &connector->display_info; + int ret; + + if (!info->is_hdmi) + return 0; + + mutex_lock(&connector->hdmi.infoframes.lock); + + memcpy(&infoframe->data, frame, sizeof(infoframe->data)); + infoframe->set = true; + + ret = write_infoframe(connector, infoframe); + + mutex_unlock(&connector->hdmi.infoframes.lock); + + return ret; +} +EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_update_audio_infoframe); diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index bdd3361ccc73..7237e8cf8c58 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -276,10 +276,11 @@ static int __drm_connector_init(struct drm_device *dev, INIT_LIST_HEAD(&connector->global_connector_list_entry); INIT_LIST_HEAD(&connector->probed_modes); INIT_LIST_HEAD(&connector->modes); mutex_init(&connector->mutex); mutex_init(&connector->edid_override_mutex); + mutex_init(&connector->hdmi.infoframes.lock); connector->edid_blob_ptr = NULL; connector->epoch_counter = 0; connector->tile_blob_ptr = NULL; connector->status = connector_status_unknown; connector->display_info.panel_orientation = @@ -454,10 +455,12 @@ EXPORT_SYMBOL(drmm_connector_init); /** * drmm_connector_hdmi_init - Init a preallocated HDMI connector * @dev: DRM device * @connector: A pointer to the HDMI connector to init + * @vendor: HDMI Controller Vendor name + * @product: HDMI Controller Product name * @funcs: callbacks for this connector * @hdmi_funcs: HDMI-related callbacks for this connector * @connector_type: user visible type of the connector * @ddc: optional pointer to the associated ddc adapter * @supported_formats: Bitmask of @hdmi_colorspace listing supported output formats @@ -474,19 +477,27 @@ EXPORT_SYMBOL(drmm_connector_init); * Returns: * Zero on success, error code on failure. */ int drmm_connector_hdmi_init(struct drm_device *dev, struct drm_connector *connector, + const char *vendor, const char *product, const struct drm_connector_funcs *funcs, const struct drm_connector_hdmi_funcs *hdmi_funcs, int connector_type, struct i2c_adapter *ddc, unsigned long supported_formats, unsigned int max_bpc) { int ret; + if (!vendor || !product) + return -EINVAL; + + if ((strlen(vendor) > DRM_CONNECTOR_HDMI_VENDOR_LEN) || + (strlen(product) > DRM_CONNECTOR_HDMI_PRODUCT_LEN)) + return -EINVAL; + if (!(connector_type == DRM_MODE_CONNECTOR_HDMIA || connector_type == DRM_MODE_CONNECTOR_HDMIB)) return -EINVAL; if (!supported_formats || !(supported_formats & BIT(HDMI_COLORSPACE_RGB))) @@ -498,10 +509,12 @@ int drmm_connector_hdmi_init(struct drm_device *dev, ret = drmm_connector_init(dev, connector, funcs, connector_type, ddc); if (ret) return ret; connector->hdmi.supported_formats = supported_formats; + strtomem_pad(connector->hdmi.vendor, vendor, 0); + strtomem_pad(connector->hdmi.product, product, 0); /* * drm_connector_attach_max_bpc_property() requires the * connector to have a state. */ @@ -650,10 +663,11 @@ void drm_connector_cleanup(struct drm_connector *connector) WARN_ON(connector->state && !connector->funcs->atomic_destroy_state); if (connector->state && connector->funcs->atomic_destroy_state) connector->funcs->atomic_destroy_state(connector, connector->state); + mutex_destroy(&connector->hdmi.infoframes.lock); mutex_destroy(&connector->mutex); memset(connector, 0, sizeof(*connector)); if (dev->registered) diff --git a/drivers/gpu/drm/tests/drm_connector_test.c b/drivers/gpu/drm/tests/drm_connector_test.c index a4ea170a2575..2e631617c391 100644 --- a/drivers/gpu/drm/tests/drm_connector_test.c +++ b/drivers/gpu/drm/tests/drm_connector_test.c @@ -189,10 +189,11 @@ static void drm_test_connector_hdmi_init_valid(struct kunit *test) { struct drm_connector_init_priv *priv = test->priv; int ret; ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector, + "Vendor", "Product", &dummy_funcs, &dummy_hdmi_funcs, DRM_MODE_CONNECTOR_HDMIA, &priv->ddc, BIT(HDMI_COLORSPACE_RGB), @@ -208,10 +209,11 @@ static void drm_test_connector_hdmi_init_null_ddc(struct kunit *test) { struct drm_connector_init_priv *priv = test->priv; int ret; ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector, + "Vendor", "Product", &dummy_funcs, &dummy_hdmi_funcs, DRM_MODE_CONNECTOR_HDMIA, NULL, BIT(HDMI_COLORSPACE_RGB), @@ -227,10 +229,11 @@ static void drm_test_connector_hdmi_init_bpc_invalid(struct kunit *test) { struct drm_connector_init_priv *priv = test->priv; int ret; ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector, + "Vendor", "Product", &dummy_funcs, &dummy_hdmi_funcs, DRM_MODE_CONNECTOR_HDMIA, &priv->ddc, BIT(HDMI_COLORSPACE_RGB), @@ -246,10 +249,11 @@ static void drm_test_connector_hdmi_init_bpc_null(struct kunit *test) { struct drm_connector_init_priv *priv = test->priv; int ret; ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector, + "Vendor", "Product", &dummy_funcs, &dummy_hdmi_funcs, DRM_MODE_CONNECTOR_HDMIA, &priv->ddc, BIT(HDMI_COLORSPACE_RGB), @@ -270,10 +274,11 @@ static void drm_test_connector_hdmi_init_bpc_8(struct kunit *test) struct drm_property *prop; uint64_t val; int ret; ret = drmm_connector_hdmi_init(&priv->drm, connector, + "Vendor", "Product", &dummy_funcs, &dummy_hdmi_funcs, DRM_MODE_CONNECTOR_HDMIA, &priv->ddc, BIT(HDMI_COLORSPACE_RGB), @@ -310,10 +315,11 @@ static void drm_test_connector_hdmi_init_bpc_10(struct kunit *test) struct drm_property *prop; uint64_t val; int ret; ret = drmm_connector_hdmi_init(&priv->drm, connector, + "Vendor", "Product", &dummy_funcs, &dummy_hdmi_funcs, DRM_MODE_CONNECTOR_HDMIA, &priv->ddc, BIT(HDMI_COLORSPACE_RGB), @@ -350,10 +356,11 @@ static void drm_test_connector_hdmi_init_bpc_12(struct kunit *test) struct drm_property *prop; uint64_t val; int ret; ret = drmm_connector_hdmi_init(&priv->drm, connector, + "Vendor", "Product", &dummy_funcs, &dummy_hdmi_funcs, DRM_MODE_CONNECTOR_HDMIA, &priv->ddc, BIT(HDMI_COLORSPACE_RGB), @@ -385,10 +392,11 @@ static void drm_test_connector_hdmi_init_formats_empty(struct kunit *test) { struct drm_connector_init_priv *priv = test->priv; int ret; ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector, + "Vendor", "Product", &dummy_funcs, &dummy_hdmi_funcs, DRM_MODE_CONNECTOR_HDMIA, &priv->ddc, 0, @@ -404,10 +412,11 @@ static void drm_test_connector_hdmi_init_formats_no_rgb(struct kunit *test) { struct drm_connector_init_priv *priv = test->priv; int ret; ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector, + "Vendor", "Product", &dummy_funcs, &dummy_hdmi_funcs, DRM_MODE_CONNECTOR_HDMIA, &priv->ddc, BIT(HDMI_COLORSPACE_YUV422), @@ -424,10 +433,11 @@ static void drm_test_connector_hdmi_init_type_valid(struct kunit *test) struct drm_connector_init_priv *priv = test->priv; unsigned int connector_type = *(unsigned int *)test->param_value; int ret; ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector, + "Vendor", "Product", &dummy_funcs, &dummy_hdmi_funcs, connector_type, &priv->ddc, BIT(HDMI_COLORSPACE_RGB), @@ -458,10 +468,11 @@ static void drm_test_connector_hdmi_init_type_invalid(struct kunit *test) struct drm_connector_init_priv *priv = test->priv; unsigned int connector_type = *(unsigned int *)test->param_value; int ret; ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector, + "Vendor", "Product", &dummy_funcs, &dummy_hdmi_funcs, connector_type, &priv->ddc, BIT(HDMI_COLORSPACE_RGB), @@ -723,10 +734,11 @@ static void drm_test_drm_connector_attach_broadcast_rgb_property_hdmi_connector( struct drm_connector *connector = &priv->connector; struct drm_property *prop; int ret; ret = drmm_connector_hdmi_init(&priv->drm, connector, + "Vendor", "Product", &dummy_funcs, &dummy_hdmi_funcs, DRM_MODE_CONNECTOR_HDMIA, &priv->ddc, BIT(HDMI_COLORSPACE_RGB), diff --git a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c index da5c3d9a80bb..e0bbe672642e 100644 --- a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c +++ b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c @@ -204,10 +204,11 @@ drm_atomic_helper_connector_hdmi_init(struct kunit *test, enc->possible_crtcs = drm_crtc_mask(priv->crtc); conn = &priv->connector; ret = drmm_connector_hdmi_init(drm, conn, + "Vendor", "Product", &dummy_connector_funcs, &dummy_connector_hdmi_funcs, DRM_MODE_CONNECTOR_HDMIA, NULL, formats, diff --git a/include/drm/display/drm_hdmi_state_helper.h b/include/drm/display/drm_hdmi_state_helper.h index 6021983e2602..fbf86ff9cdfb 100644 --- a/include/drm/display/drm_hdmi_state_helper.h +++ b/include/drm/display/drm_hdmi_state_helper.h @@ -4,13 +4,20 @@ #define DRM_HDMI_STATE_HELPER_H_ struct drm_atomic_state; struct drm_connector; struct drm_connector_state; +struct hdmi_audio_infoframe; void __drm_atomic_helper_connector_hdmi_reset(struct drm_connector *connector, struct drm_connector_state *new_conn_state); int drm_atomic_helper_connector_hdmi_check(struct drm_connector *connector, struct drm_atomic_state *state); +int drm_atomic_helper_connector_hdmi_update_audio_infoframe(struct drm_connector *connector, + struct hdmi_audio_infoframe *frame); +int drm_atomic_helper_connector_hdmi_update_infoframes(struct drm_connector *connector, + struct drm_atomic_state *state); + + #endif // DRM_HDMI_STATE_HELPER_H_ diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 1fca26d51218..450c5605d145 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -912,10 +912,25 @@ struct drm_tv_connector_state { unsigned int overscan; unsigned int saturation; unsigned int hue; }; +/** + * struct drm_connector_hdmi_infoframe - HDMI Infoframe container + */ +struct drm_connector_hdmi_infoframe { + /** + * @data: HDMI Infoframe structure + */ + union hdmi_infoframe data; + + /** + * @set: Is the content of @data valid? + */ + bool set; +}; + /** * struct drm_connector_state - mutable connector state */ struct drm_connector_state { /** @connector: backpointer to the connector */ @@ -1069,11 +1084,40 @@ struct drm_connector_state { * Broadcast RGB selection value. */ enum drm_hdmi_broadcast_rgb broadcast_rgb; /** - * @is_full_range: Is the output supposed to use a full + * @infoframes: HDMI Infoframes matching that state + */ + struct { + /** + * @avi: AVI Infoframes structure matching our + * state. + */ + struct drm_connector_hdmi_infoframe avi; + + /** + * @hdr_drm: DRM (Dynamic Range and Mastering) + * Infoframes structure matching our state. + */ + struct drm_connector_hdmi_infoframe hdr_drm; + + /** + * @spd: SPD Infoframes structure matching our + * state. + */ + struct drm_connector_hdmi_infoframe spd; + + /** + * @vendor: HDMI Vendor Infoframes structure + * matching our state. + */ + struct drm_connector_hdmi_infoframe hdmi; + } infoframes; + + /** + * @is_limited_range: Is the output supposed to use a limited * RGB Quantization Range or not? */ bool is_limited_range; /** @@ -1113,10 +1157,45 @@ struct drm_connector_hdmi_funcs { */ enum drm_mode_status (*tmds_char_rate_valid)(const struct drm_connector *connector, const struct drm_display_mode *mode, unsigned long long tmds_rate); + + /** + * @clear_infoframe: + * + * This callback is invoked through + * @drm_atomic_helper_connector_hdmi_update_infoframes during a + * commit to clear the infoframes into the hardware. It will be + * called multiple times, once for every disabled infoframe + * type. + * + * The @clear_infoframe callback is optional. + * + * Returns: + * 0 on success, a negative error code otherwise + */ + int (*clear_infoframe)(struct drm_connector *connector, + enum hdmi_infoframe_type type); + + /** + * @write_infoframe: + * + * This callback is invoked through + * @drm_atomic_helper_connector_hdmi_update_infoframes during a + * commit to program the infoframes into the hardware. It will + * be called multiple times, once for every updated infoframe + * type. + * + * The @write_infoframe callback is mandatory. + * + * Returns: + * 0 on success, a negative error code otherwise + */ + int (*write_infoframe)(struct drm_connector *connector, + enum hdmi_infoframe_type type, + const u8 *buffer, size_t len); }; /** * struct drm_connector_funcs - control connectors on a given device * @@ -1984,20 +2063,49 @@ struct drm_connector { /** * @hdmi: HDMI-related variable and properties. */ struct { +#define DRM_CONNECTOR_HDMI_VENDOR_LEN 8 + /** + * @vendor: HDMI Controller Vendor Name + */ + unsigned char vendor[DRM_CONNECTOR_HDMI_VENDOR_LEN] __nonstring; + +#define DRM_CONNECTOR_HDMI_PRODUCT_LEN 16 + /** + * @product: HDMI Controller Product Name + */ + unsigned char product[DRM_CONNECTOR_HDMI_PRODUCT_LEN] __nonstring; + /** * @supported_formats: Bitmask of @hdmi_colorspace * supported by the controller. */ unsigned long supported_formats; /** * @funcs: HDMI connector Control Functions */ const struct drm_connector_hdmi_funcs *funcs; + + /** + * @infoframes: Current Infoframes output by the connector + */ + struct { + /** + * @lock: Mutex protecting against concurrent access to + * the infoframes, most notably between KMS and ALSA. + */ + struct mutex lock; + + /** + * @audio: Current Audio Infoframes structure. Protected + * by @lock. + */ + struct drm_connector_hdmi_infoframe audio; + } infoframes; } hdmi; }; #define obj_to_connector(x) container_of(x, struct drm_connector, base) @@ -2015,10 +2123,11 @@ int drmm_connector_init(struct drm_device *dev, const struct drm_connector_funcs *funcs, int connector_type, struct i2c_adapter *ddc); int drmm_connector_hdmi_init(struct drm_device *dev, struct drm_connector *connector, + const char *vendor, const char *product, const struct drm_connector_funcs *funcs, const struct drm_connector_hdmi_funcs *hdmi_funcs, int connector_type, struct i2c_adapter *ddc, unsigned long supported_formats, From patchwork Mon May 27 13:58:13 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Maxime Ripard X-Patchwork-Id: 799361 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 6650516E881; Mon, 27 May 2024 13:59:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716818355; cv=none; b=AnjPC6xtv2QrliyXy7MRFuFFmgI9fmFdXd4t3neIfc48T9qobYEoGRvAHN49DBRo6cAZSgAheLaCJoY0M3rXYxsthmXVJ3vIaEBAuul8wFRG+zinWU1c0NAP4UanYo/pK7CXnM+bT9BgEoJhhIQ25XZvqC94XNGu3slRf10vviw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716818355; c=relaxed/simple; bh=O9JW27njJm+aYBAQyeNRFptyT1x+G6F+sYjE79pnkks=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Lcr3Pld7d2gV22WU29P76x7kpF1SwcF5k2F5mx+aNSqSqxT5KftVwWAEoTWrRZB1qdLgFZTSOxsxhcGx8ghRP5JkfUq3N3BhpL1a1cZvGdQr1whrhEjxoJZEB33lDcLL6BXBaujTMEleYJH4PSAQYHvrRcvSAmacuNi46KkD/Fs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=RlzDCJ+p; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="RlzDCJ+p" Received: by smtp.kernel.org (Postfix) with ESMTPSA id A70BAC32781; Mon, 27 May 2024 13:59:14 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1716818355; bh=O9JW27njJm+aYBAQyeNRFptyT1x+G6F+sYjE79pnkks=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=RlzDCJ+p+VnePxdwl5lqKgDaTwaZRQFM536yldfx3MpX7622uLqY4cg2Sx/4vYhio KaREQRosWDKywooNpIWe3YCs/82XoD74n6jQJz+tLtNbIgioskksGopS4KPlnD4eVp jC9r4dQtcJdqEKSniudpfKzXUkMGsTiQ4kLpNelKbjxZhTDg/xdb5Cg8SmnT0cx/Uu +2JqH3yiQ3c1hqhEc401DsuOiIV9PrTSvcWR69cPD810lcQ0feFwPgTpptUtqljPUR N6plVHPUEWhJuaudVc/bYXV44IF0UFPB7NkBqSpfoljDZUg2hcoIX+bKTaQQSTlXc1 nwshQQkqFr8SA== From: Maxime Ripard Date: Mon, 27 May 2024 15:58:13 +0200 Subject: [PATCH v15 24/29] drm/connector: hdmi: Create Infoframe DebugFS entries Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20240527-kms-hdmi-connector-state-v15-24-c5af16c3aae2@kernel.org> References: <20240527-kms-hdmi-connector-state-v15-0-c5af16c3aae2@kernel.org> In-Reply-To: <20240527-kms-hdmi-connector-state-v15-0-c5af16c3aae2@kernel.org> To: Maarten Lankhorst , Thomas Zimmermann , David Airlie , Daniel Vetter , Jonathan Corbet , Sandy Huang , =?utf-8?q?Heiko_St=C3=BCbner?= , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Andy Yan Cc: Hans Verkuil , Sebastian Wick , =?utf-8?b?VmlsbGUgU3lyasOkbMOk?= , dri-devel@lists.freedesktop.org, linux-arm-kernel@lists.infradead.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-rockchip@lists.infradead.org, linux-sunxi@lists.linux.dev, Maxime Ripard , Dmitry Baryshkov X-Mailer: b4 0.13.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=5480; i=mripard@kernel.org; h=from:subject:message-id; bh=O9JW27njJm+aYBAQyeNRFptyT1x+G6F+sYjE79pnkks=; b=owGbwMvMwCmsHn9OcpHtvjLG02pJDGkhE7M01dJ59dYsrF35ekG68UaX7E3bWeVt7hQkPFhqv GZVcdekjqksDMKcDLJiiixPZMJOL29fXOVgv/IHzBxWJpAhDFycAjARc0XGhj164gs/sjVMOdKo bzC7zWfxpYyJV1Pf+kfYLT1Y7c8evVzgoWLYg57/m77uMJ+muPRRLWND/703v5k901/mvy2dwas aGpO7hH9lRPrJcO5L2w0DE3/KSoXefTD9l6j57HkzmPPvvfIHAA== X-Developer-Key: i=mripard@kernel.org; a=openpgp; fpr=BE5675C37E818C8B5764241C254BCFC56BF6CE8D There has been some discussions recently about the infoframes sent by drivers and if they were properly generated. In parallel, there's been some interest in creating an infoframe-decode tool similar to edid-decode. Both would be much easier if we were to expose the infoframes programmed in the hardware. It won't be perfect since we have no guarantee that it's actually what goes through the wire, but it's the best we can do. Reviewed-by: Dmitry Baryshkov Signed-off-by: Maxime Ripard --- drivers/gpu/drm/drm_debugfs.c | 152 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+) diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c index 08fcefd804bc..dd39a5b7a711 100644 --- a/drivers/gpu/drm/drm_debugfs.c +++ b/drivers/gpu/drm/drm_debugfs.c @@ -518,10 +518,160 @@ static const struct file_operations drm_connector_fops = { .llseek = seq_lseek, .release = single_release, .write = connector_write }; +#define HDMI_MAX_INFOFRAME_SIZE 29 + +static ssize_t +audio_infoframe_read(struct file *filp, char __user *ubuf, size_t count, loff_t *ppos) +{ + struct drm_connector_hdmi_infoframe *infoframe; + struct drm_connector *connector; + union hdmi_infoframe *frame; + u8 buf[HDMI_INFOFRAME_SIZE(AUDIO)]; + ssize_t len = 0; + + connector = filp->private_data; + mutex_lock(&connector->hdmi.infoframes.lock); + + infoframe = &connector->hdmi.infoframes.audio; + if (!infoframe->set) + goto out; + + frame = &infoframe->data; + len = hdmi_infoframe_pack(frame, buf, sizeof(buf)); + if (len < 0) + goto out; + + len = simple_read_from_buffer(ubuf, count, ppos, buf, len); + +out: + mutex_unlock(&connector->hdmi.infoframes.lock); + return len; +} + +static const struct file_operations audio_infoframe_fops = { + .owner = THIS_MODULE, + .open = simple_open, + .read = audio_infoframe_read, +}; + +static int create_hdmi_audio_infoframe_file(struct drm_connector *connector, + struct dentry *parent) +{ + struct dentry *file; + + file = debugfs_create_file("audio", 0400, parent, connector, &audio_infoframe_fops); + if (IS_ERR(file)) + return PTR_ERR(file); + + return 0; +} + +#define DEFINE_INFOFRAME_FILE(_f) \ +static ssize_t _f##_read_infoframe(struct file *filp, \ + char __user *ubuf, \ + size_t count, \ + loff_t *ppos) \ +{ \ + struct drm_connector_hdmi_infoframe *infoframe; \ + struct drm_connector_state *conn_state; \ + struct drm_connector *connector; \ + union hdmi_infoframe *frame; \ + struct drm_device *dev; \ + u8 buf[HDMI_MAX_INFOFRAME_SIZE]; \ + ssize_t len = 0; \ + \ + connector = filp->private_data; \ + dev = connector->dev; \ + \ + drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); \ + \ + conn_state = connector->state; \ + infoframe = &conn_state->hdmi.infoframes._f; \ + if (!infoframe->set) \ + goto out; \ + \ + frame = &infoframe->data; \ + len = hdmi_infoframe_pack(frame, buf, sizeof(buf)); \ + if (len < 0) \ + goto out; \ + \ + len = simple_read_from_buffer(ubuf, count, ppos, buf, len); \ + \ +out: \ + drm_modeset_unlock(&dev->mode_config.connection_mutex); \ + return len; \ +} \ +\ +static const struct file_operations _f##_infoframe_fops = { \ + .owner = THIS_MODULE, \ + .open = simple_open, \ + .read = _f##_read_infoframe, \ +}; \ +\ +static int create_hdmi_## _f ## _infoframe_file (struct drm_connector *connector, \ + struct dentry *parent) \ +{ \ + struct dentry *file; \ + \ + file = debugfs_create_file(#_f, 0400, parent, connector, & _f ## _infoframe_fops); \ + if (IS_ERR(file)) \ + return PTR_ERR(file); \ + \ + return 0; \ +} + +DEFINE_INFOFRAME_FILE(avi); +DEFINE_INFOFRAME_FILE(hdmi); +DEFINE_INFOFRAME_FILE(hdr_drm); +DEFINE_INFOFRAME_FILE(spd); + +static int create_hdmi_infoframe_files(struct drm_connector *connector, + struct dentry *parent) +{ + int ret; + + ret = create_hdmi_audio_infoframe_file(connector, parent); + if (ret) + return ret; + + ret = create_hdmi_avi_infoframe_file(connector, parent); + if (ret) + return ret; + + ret = create_hdmi_hdmi_infoframe_file(connector, parent); + if (ret) + return ret; + + ret = create_hdmi_hdr_drm_infoframe_file(connector, parent); + if (ret) + return ret; + + ret = create_hdmi_spd_infoframe_file(connector, parent); + if (ret) + return ret; + + return 0; +} + +static void hdmi_debugfs_add(struct drm_connector *connector) +{ + struct dentry *dir; + + if (!(connector->connector_type == DRM_MODE_CONNECTOR_HDMIA || + connector->connector_type == DRM_MODE_CONNECTOR_HDMIB)) + return; + + dir = debugfs_create_dir("infoframes", connector->debugfs_entry); + if (IS_ERR(dir)) + return; + + create_hdmi_infoframe_files(connector, dir); +} + void drm_debugfs_connector_add(struct drm_connector *connector) { struct drm_device *dev = connector->dev; struct dentry *root; @@ -545,10 +695,12 @@ void drm_debugfs_connector_add(struct drm_connector *connector) /* max bpc */ debugfs_create_file("output_bpc", 0444, root, connector, &output_bpc_fops); + hdmi_debugfs_add(connector); + if (connector->funcs->debugfs_init) connector->funcs->debugfs_init(connector, root); } void drm_debugfs_connector_remove(struct drm_connector *connector) From patchwork Mon May 27 13:58:15 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Maxime Ripard X-Patchwork-Id: 799360 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 BCE4D15FA73; Mon, 27 May 2024 13:59:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716818360; cv=none; b=X6kVhIDwQ3EQ+tozfdWa1uoYe0xHfpA5g/RNGjav0bP7YkcMBoSS+VR6GyHybKSv97OyFw8Q/9GcHLImK6E0cLYrhNI/JD2BFSIBhVpOgm2iHTd9KP+ldvHXvzmlsNiPUmO6EyQvfOAbGGecv9g80VdmywWEt2KmyUmL7iIfkUg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716818360; c=relaxed/simple; bh=mxuD7pT2tlDQ0zzNZkqWfj36MC0sF3/2cyZNsO+d0UQ=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=o7XKQ93z3+JNIZXCApgrI/17V0yVxGgZRC/t9vtW1K+yAUqlMUJMC0YD5OjVgL16aHTMf8I1dYhDcVl2enqqRRzBDvIAvsZsbVE78zBB2sHKxQg7XLpDolH/3M1BDY9OwFGYweEnP00nMjJkPcMvqLgbnmyaUtVwbnkj+jY+yHg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=FKuryF+2; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="FKuryF+2" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 50293C32789; Mon, 27 May 2024 13:59:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1716818360; bh=mxuD7pT2tlDQ0zzNZkqWfj36MC0sF3/2cyZNsO+d0UQ=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=FKuryF+22rQwG/qEy5/4v9bTlcjIZHihnPXlqThJ8uifXGXWQJmU0JO5leNjcERAE DcMGln1awzi2ANxya+/nSnp1i6KUc0BNpNdlZQZXex1kSe3x2gJQzVtdesgnO+vqW9 eNo/B4NXIbSntIKKIRUzi47MlWLwfTVt6/DKG+HMCZu77IZGwpKDLHsb2ELt9YrIwp Av/UDH3TzC9Wj6lXRNBQF8hOYefqlkShxIUHX+apR1U0p+scINUYmc/87GVUI/Y4KT hRgaotCU+D+Oe2Sq1SzvaEBDgPETnVnJd+Jy/JlerRGOdfP3Wq+qFfEcCbeXpOAdZh yunFfOpw+wapg== From: Maxime Ripard Date: Mon, 27 May 2024 15:58:15 +0200 Subject: [PATCH v15 26/29] drm/vc4: tests: Remove vc4_dummy_plane structure Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20240527-kms-hdmi-connector-state-v15-26-c5af16c3aae2@kernel.org> References: <20240527-kms-hdmi-connector-state-v15-0-c5af16c3aae2@kernel.org> In-Reply-To: <20240527-kms-hdmi-connector-state-v15-0-c5af16c3aae2@kernel.org> To: Maarten Lankhorst , Thomas Zimmermann , David Airlie , Daniel Vetter , Jonathan Corbet , Sandy Huang , =?utf-8?q?Heiko_St=C3=BCbner?= , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Andy Yan Cc: Hans Verkuil , Sebastian Wick , =?utf-8?b?VmlsbGUgU3lyasOkbMOk?= , dri-devel@lists.freedesktop.org, linux-arm-kernel@lists.infradead.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-rockchip@lists.infradead.org, linux-sunxi@lists.linux.dev, Maxime Ripard , =?utf-8?q?Ma=C3=ADra_Canal?= X-Mailer: b4 0.13.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=3744; i=mripard@kernel.org; h=from:subject:message-id; bh=mxuD7pT2tlDQ0zzNZkqWfj36MC0sF3/2cyZNsO+d0UQ=; b=owGbwMvMwCmsHn9OcpHtvjLG02pJDGkhE7PDI86breGa0lSze/XRXVbVmefeHjj0YlntiY6vs w2uSK3b2zGVhUGYk0FWTJHliUzY6eXti6sc7Ff+gJnDygQyhIGLUwAmcqSJsc74+oGgP1Fhkosd VEuc3NRcSm6dWMHUYTunN1CpYd9TkYB7/12vmF7N3r3tEHvgexsva8aGw9U31t9bMVPq76ULbyV fcXkrcX9ryK7ds0Y7ruDuqeOx89znKKSXHbBVvbJy98Ls7glyAA== X-Developer-Key: i=mripard@kernel.org; a=openpgp; fpr=BE5675C37E818C8B5764241C254BCFC56BF6CE8D The vc4_dummy_plane structure was introduced as a mean to add mock-specific fields. However, we never really used it and it's still strictly equivalent to vc4_plane (which is in the same situation vs drm_plane), so we can simply remove the vc4_dummy_plane structure and make the mock code cleaner. Reviewed-by: Maíra Canal Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/tests/vc4_mock.c | 6 ++---- drivers/gpu/drm/vc4/tests/vc4_mock.h | 9 ++------- drivers/gpu/drm/vc4/tests/vc4_mock_plane.c | 14 +++++--------- 3 files changed, 9 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/vc4/tests/vc4_mock.c b/drivers/gpu/drm/vc4/tests/vc4_mock.c index becb3dbaa548..0731a7d85d7a 100644 --- a/drivers/gpu/drm/vc4/tests/vc4_mock.c +++ b/drivers/gpu/drm/vc4/tests/vc4_mock.c @@ -107,20 +107,18 @@ static const struct vc4_mock_desc vc5_mock = ); static int __build_one_pipe(struct kunit *test, struct drm_device *drm, const struct vc4_mock_pipe_desc *pipe) { - struct vc4_dummy_plane *dummy_plane; struct drm_plane *plane; struct vc4_dummy_crtc *dummy_crtc; struct drm_crtc *crtc; unsigned int i; - dummy_plane = vc4_dummy_plane(test, drm, DRM_PLANE_TYPE_PRIMARY); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dummy_plane); + plane = vc4_dummy_plane(test, drm, DRM_PLANE_TYPE_PRIMARY); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane); - plane = &dummy_plane->plane.base; dummy_crtc = vc4_mock_pv(test, drm, plane, pipe->data); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dummy_crtc); crtc = &dummy_crtc->crtc.base; for (i = 0; i < pipe->noutputs; i++) { diff --git a/drivers/gpu/drm/vc4/tests/vc4_mock.h b/drivers/gpu/drm/vc4/tests/vc4_mock.h index 2d0b339bd9f3..002b6218960c 100644 --- a/drivers/gpu/drm/vc4/tests/vc4_mock.h +++ b/drivers/gpu/drm/vc4/tests/vc4_mock.h @@ -19,17 +19,12 @@ struct drm_crtc *vc4_find_crtc_for_encoder(struct kunit *test, return crtc; return NULL; } -struct vc4_dummy_plane { - struct vc4_plane plane; -}; - -struct vc4_dummy_plane *vc4_dummy_plane(struct kunit *test, - struct drm_device *drm, - enum drm_plane_type type); +struct drm_plane *vc4_dummy_plane(struct kunit *test, struct drm_device *drm, + enum drm_plane_type type); struct vc4_dummy_crtc { struct vc4_crtc crtc; }; diff --git a/drivers/gpu/drm/vc4/tests/vc4_mock_plane.c b/drivers/gpu/drm/vc4/tests/vc4_mock_plane.c index 62b18f5f41db..973f5f929097 100644 --- a/drivers/gpu/drm/vc4/tests/vc4_mock_plane.c +++ b/drivers/gpu/drm/vc4/tests/vc4_mock_plane.c @@ -20,28 +20,24 @@ static const struct drm_plane_funcs vc4_dummy_plane_funcs = { static const uint32_t vc4_dummy_plane_formats[] = { DRM_FORMAT_XRGB8888, }; -struct vc4_dummy_plane *vc4_dummy_plane(struct kunit *test, - struct drm_device *drm, - enum drm_plane_type type) +struct drm_plane *vc4_dummy_plane(struct kunit *test, struct drm_device *drm, + enum drm_plane_type type) { - struct vc4_dummy_plane *dummy_plane; struct drm_plane *plane; - dummy_plane = drmm_universal_plane_alloc(drm, - struct vc4_dummy_plane, plane.base, + plane = __drmm_universal_plane_alloc(drm, sizeof(struct drm_plane), 0, 0, &vc4_dummy_plane_funcs, vc4_dummy_plane_formats, ARRAY_SIZE(vc4_dummy_plane_formats), NULL, DRM_PLANE_TYPE_PRIMARY, NULL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dummy_plane); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane); - plane = &dummy_plane->plane.base; drm_plane_helper_add(plane, &vc4_dummy_plane_helper_funcs); - return dummy_plane; + return plane; } From patchwork Mon May 27 13:58:17 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Maxime Ripard X-Patchwork-Id: 799359 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 58B6C16F0F4; Mon, 27 May 2024 13:59:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716818366; cv=none; b=EhOH8HBKZQiv7Bq41FO7JHgFgq4Fd3PoVhsT9CmrMTPoU3sLiH8sosP0iHTKxq7xsCMKiFGjCLax+nHi5oGRHQalDuDSfttopj70n3giaJ+SR38RwHrRwZA6st6cdGvAbD/yvBdrpKIlt9kRsljR6gluwSiA7QJZRNOx1+32LyY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716818366; c=relaxed/simple; bh=+OblqzYU14xprCQNzIIaZoJXKK/71giK4TwuuPVdMu0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=AL2mhgBVjmKlrtavCNrnlYd5M9o2C++inOLA8M2usd6BwJQHSqcE14kNzOYP7ixZr5k/0d9uy9xHnkdahJiQXdzA6XnAnoyMEfQyWeh44uAF5EDO02UYhNQYbJqPgevFR6slcHBOu1vUlI+LrKHxfsSOaoiEnH2Ulh5csdseL/o= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=hUX8jikr; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="hUX8jikr" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 99958C32781; Mon, 27 May 2024 13:59:25 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1716818366; bh=+OblqzYU14xprCQNzIIaZoJXKK/71giK4TwuuPVdMu0=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=hUX8jikrqB5VvlyTFHEKfaxpDo3exFC9zoz/pcDkMSTFCA5zAaq7sD3qjv4FSUBDa p6CdjD2UgovuyIABRoXEKWd71HrIw6PndDjIHoQq5DAuemOdIjnBrla+ldP0s3M/Ro dM9xA5Hzii4OIOen7H4S76uDAYSliyrxRsnF+sSNdruoDTKf72T3dvnzMTLIsj/lgy SD3dus0qybOCGzpNDiUaEUG61Sjv/o0KSDrg7jb3xfNSqEBHLkZkfrG4hxGHf2UXrU HTEOITV4NChO9HHmDtVmVnIoi0Zvl9ztVNDKI6DEKz6FZqnkwrrjTAnAO+PxV4eJmK xVAUpJI6GJOBQ== From: Maxime Ripard Date: Mon, 27 May 2024 15:58:17 +0200 Subject: [PATCH v15 28/29] drm/rockchip: inno_hdmi: Switch to HDMI connector Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20240527-kms-hdmi-connector-state-v15-28-c5af16c3aae2@kernel.org> References: <20240527-kms-hdmi-connector-state-v15-0-c5af16c3aae2@kernel.org> In-Reply-To: <20240527-kms-hdmi-connector-state-v15-0-c5af16c3aae2@kernel.org> To: Maarten Lankhorst , Thomas Zimmermann , David Airlie , Daniel Vetter , Jonathan Corbet , Sandy Huang , =?utf-8?q?Heiko_St=C3=BCbner?= , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Andy Yan Cc: Hans Verkuil , Sebastian Wick , =?utf-8?b?VmlsbGUgU3lyasOkbMOk?= , dri-devel@lists.freedesktop.org, linux-arm-kernel@lists.infradead.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-rockchip@lists.infradead.org, linux-sunxi@lists.linux.dev, Maxime Ripard , Andy Yan X-Mailer: b4 0.13.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=14418; i=mripard@kernel.org; h=from:subject:message-id; bh=+OblqzYU14xprCQNzIIaZoJXKK/71giK4TwuuPVdMu0=; b=owGbwMvMwCmsHn9OcpHtvjLG02pJDGkhE3NuT3/sNuVUzYZXbXLL7sUIz5t25Ni1SuY+nZCwi 3eWRVu1dkxlYRDmZJAVU2R5IhN2enn74ioH+5U/YOawMoEMYeDiFICJ/NzOWKcf/dtvinvBuwmX OU8qrWx9a/lw4/rYlSwXH9ybayLS6J4ZO7kuYOqu41XGHvsaBW5e28LYMNl6n+a30m+Xe9tuyKc d+aE9cdvuF+Zi0+t5Z/mltzTNe9u4q/Bw6h9eRj+7GKMX+x3kAA== X-Developer-Key: i=mripard@kernel.org; a=openpgp; fpr=BE5675C37E818C8B5764241C254BCFC56BF6CE8D The new HDMI connector infrastructure allows to remove some boilerplate, especially to generate infoframes. Let's switch to it. Reviewed-by: Heiko Stuebner Acked-by: Heiko Stuebner Acked-by: Andy Yan Signed-off-by: Maxime Ripard --- drivers/gpu/drm/rockchip/Kconfig | 3 + drivers/gpu/drm/rockchip/inno_hdmi.c | 172 +++++++++++++---------------------- 2 files changed, 66 insertions(+), 109 deletions(-) diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig index 1bf3e2829cd0..7df875e38517 100644 --- a/drivers/gpu/drm/rockchip/Kconfig +++ b/drivers/gpu/drm/rockchip/Kconfig @@ -72,10 +72,13 @@ config ROCKCHIP_DW_MIPI_DSI enable MIPI DSI on RK3288 or RK3399 based SoC, you should select this option. config ROCKCHIP_INNO_HDMI bool "Rockchip specific extensions for Innosilicon HDMI" + select DRM_DISPLAY_HDMI_HELPER + select DRM_DISPLAY_HDMI_STATE_HELPER + select DRM_DISPLAY_HELPER help This selects support for Rockchip SoC specific extensions for the Innosilicon HDMI driver. If you want to enable HDMI on RK3036 based SoC, you should select this option. diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 3df2cfcf9998..2241e53a2946 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -20,10 +20,13 @@ #include #include #include #include +#include +#include + #include "rockchip_drm_drv.h" #include "inno_hdmi.h" #define INNO_HDMI_MIN_TMDS_CLOCK 25000000U @@ -65,13 +68,11 @@ struct inno_hdmi { const struct inno_hdmi_variant *variant; }; struct inno_hdmi_connector_state { struct drm_connector_state base; - unsigned int enc_out_format; unsigned int colorimetry; - bool rgb_limited_range; }; static struct inno_hdmi *encoder_to_inno_hdmi(struct drm_encoder *encoder) { struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder); @@ -255,90 +256,53 @@ static void inno_hdmi_reset(struct inno_hdmi *hdmi) hdmi_modb(hdmi, HDMI_SYS_CTRL, msk, val); inno_hdmi_standby(hdmi); } -static void inno_hdmi_disable_frame(struct inno_hdmi *hdmi, - enum hdmi_infoframe_type type) +static int inno_hdmi_disable_frame(struct drm_connector *connector, + enum hdmi_infoframe_type type) { - struct drm_connector *connector = &hdmi->connector; - - if (type != HDMI_INFOFRAME_TYPE_AVI) { - drm_err(connector->dev, - "Unsupported infoframe type: %u\n", type); - return; - } - - hdmi_writeb(hdmi, HDMI_CONTROL_PACKET_BUF_INDEX, INFOFRAME_AVI); -} - -static int inno_hdmi_upload_frame(struct inno_hdmi *hdmi, - union hdmi_infoframe *frame, enum hdmi_infoframe_type type) -{ - struct drm_connector *connector = &hdmi->connector; - u8 packed_frame[HDMI_MAXIMUM_INFO_FRAME_SIZE]; - ssize_t rc, i; + struct inno_hdmi *hdmi = connector_to_inno_hdmi(connector); if (type != HDMI_INFOFRAME_TYPE_AVI) { drm_err(connector->dev, "Unsupported infoframe type: %u\n", type); return 0; } - inno_hdmi_disable_frame(hdmi, type); + hdmi_writeb(hdmi, HDMI_CONTROL_PACKET_BUF_INDEX, INFOFRAME_AVI); - rc = hdmi_infoframe_pack(frame, packed_frame, - sizeof(packed_frame)); - if (rc < 0) - return rc; + return 0; +} - for (i = 0; i < rc; i++) +static int inno_hdmi_upload_frame(struct drm_connector *connector, + enum hdmi_infoframe_type type, + const u8 *buffer, size_t len) +{ + struct inno_hdmi *hdmi = connector_to_inno_hdmi(connector); + u8 packed_frame[HDMI_MAXIMUM_INFO_FRAME_SIZE]; + ssize_t i; + + if (type != HDMI_INFOFRAME_TYPE_AVI) { + drm_err(connector->dev, + "Unsupported infoframe type: %u\n", type); + return 0; + } + + inno_hdmi_disable_frame(connector, type); + + for (i = 0; i < len; i++) hdmi_writeb(hdmi, HDMI_CONTROL_PACKET_ADDR + i, packed_frame[i]); return 0; } -static int inno_hdmi_config_video_avi(struct inno_hdmi *hdmi, - struct drm_display_mode *mode) -{ - struct drm_connector *connector = &hdmi->connector; - struct drm_connector_state *conn_state = connector->state; - struct inno_hdmi_connector_state *inno_conn_state = - to_inno_hdmi_conn_state(conn_state); - union hdmi_infoframe frame; - int rc; - - rc = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, - &hdmi->connector, - mode); - if (rc) { - inno_hdmi_disable_frame(hdmi, HDMI_INFOFRAME_TYPE_AVI); - return rc; - } - - if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_YUV444) - frame.avi.colorspace = HDMI_COLORSPACE_YUV444; - else if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_YUV422) - frame.avi.colorspace = HDMI_COLORSPACE_YUV422; - else - frame.avi.colorspace = HDMI_COLORSPACE_RGB; - - if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_RGB) { - drm_hdmi_avi_infoframe_quant_range(&frame.avi, - connector, mode, - inno_conn_state->rgb_limited_range ? - HDMI_QUANTIZATION_RANGE_LIMITED : - HDMI_QUANTIZATION_RANGE_FULL); - } else { - frame.avi.quantization_range = HDMI_QUANTIZATION_RANGE_DEFAULT; - frame.avi.ycc_quantization_range = - HDMI_YCC_QUANTIZATION_RANGE_LIMITED; - } - - return inno_hdmi_upload_frame(hdmi, &frame, HDMI_INFOFRAME_TYPE_AVI); -} +static const struct drm_connector_hdmi_funcs inno_hdmi_hdmi_connector_funcs = { + .clear_infoframe = inno_hdmi_disable_frame, + .write_infoframe = inno_hdmi_upload_frame, +}; static int inno_hdmi_config_video_csc(struct inno_hdmi *hdmi) { struct drm_connector *connector = &hdmi->connector; struct drm_connector_state *conn_state = connector->state; @@ -359,12 +323,12 @@ static int inno_hdmi_config_video_csc(struct inno_hdmi *hdmi) value = v_VIDEO_INPUT_BITS(VIDEO_INPUT_8BITS) | v_VIDEO_OUTPUT_COLOR(0) | v_VIDEO_INPUT_CSP(0); hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL2, value); - if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_RGB) { - if (inno_conn_state->rgb_limited_range) { + if (conn_state->hdmi.output_format == HDMI_COLORSPACE_RGB) { + if (conn_state->hdmi.is_limited_range) { csc_mode = CSC_RGB_0_255_TO_RGB_16_235_8BIT; auto_csc = AUTO_CSC_DISABLE; c0_c2_change = C0_C2_CHANGE_DISABLE; csc_enable = v_CSC_ENABLE; @@ -378,18 +342,18 @@ static int inno_hdmi_config_video_csc(struct inno_hdmi *hdmi) v_VIDEO_C0_C2_SWAP(C0_C2_CHANGE_DISABLE)); return 0; } } else { if (inno_conn_state->colorimetry == HDMI_COLORIMETRY_ITU_601) { - if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_YUV444) { + if (conn_state->hdmi.output_format == HDMI_COLORSPACE_YUV444) { csc_mode = CSC_RGB_0_255_TO_ITU601_16_235_8BIT; auto_csc = AUTO_CSC_DISABLE; c0_c2_change = C0_C2_CHANGE_DISABLE; csc_enable = v_CSC_ENABLE; } } else { - if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_YUV444) { + if (conn_state->hdmi.output_format == HDMI_COLORSPACE_YUV444) { csc_mode = CSC_RGB_0_255_TO_ITU709_16_235_8BIT; auto_csc = AUTO_CSC_DISABLE; c0_c2_change = C0_C2_CHANGE_DISABLE; csc_enable = v_CSC_ENABLE; } @@ -460,43 +424,52 @@ static int inno_hdmi_config_video_timing(struct inno_hdmi *hdmi, return 0; } static int inno_hdmi_setup(struct inno_hdmi *hdmi, - struct drm_display_mode *mode) + struct drm_atomic_state *state) { - struct drm_display_info *display = &hdmi->connector.display_info; - unsigned long mpixelclock = mode->clock * 1000; + struct drm_connector *connector = &hdmi->connector; + struct drm_display_info *display = &connector->display_info; + struct drm_connector_state *new_conn_state; + struct drm_crtc_state *new_crtc_state; + + new_conn_state = drm_atomic_get_new_connector_state(state, connector); + if (WARN_ON(!new_conn_state)) + return -EINVAL; + + new_crtc_state = drm_atomic_get_new_crtc_state(state, new_conn_state->crtc); + if (WARN_ON(!new_crtc_state)) + return -EINVAL; /* Mute video and audio output */ hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_VIDEO_BLACK, v_AUDIO_MUTE(1) | v_VIDEO_MUTE(1)); /* Set HDMI Mode */ hdmi_writeb(hdmi, HDMI_HDCP_CTRL, v_HDMI_DVI(display->is_hdmi)); - inno_hdmi_config_video_timing(hdmi, mode); + inno_hdmi_config_video_timing(hdmi, &new_crtc_state->adjusted_mode); inno_hdmi_config_video_csc(hdmi); - if (display->is_hdmi) - inno_hdmi_config_video_avi(hdmi, mode); + drm_atomic_helper_connector_hdmi_update_infoframes(connector, state); /* * When IP controller have configured to an accurate video * timing, then the TMDS clock source would be switched to * DCLK_LCDC, so we need to init the TMDS rate to mode pixel * clock rate, and reconfigure the DDC clock. */ - inno_hdmi_i2c_init(hdmi, mpixelclock); + inno_hdmi_i2c_init(hdmi, new_conn_state->hdmi.tmds_char_rate); /* Unmute video and audio output */ hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_VIDEO_BLACK, v_AUDIO_MUTE(0) | v_VIDEO_MUTE(0)); - inno_hdmi_power_up(hdmi, mpixelclock); + inno_hdmi_power_up(hdmi, new_conn_state->hdmi.tmds_char_rate); return 0; } static enum drm_mode_status inno_hdmi_display_mode_valid(struct inno_hdmi *hdmi, @@ -533,22 +506,12 @@ static enum drm_mode_status inno_hdmi_display_mode_valid(struct inno_hdmi *hdmi, static void inno_hdmi_encoder_enable(struct drm_encoder *encoder, struct drm_atomic_state *state) { struct inno_hdmi *hdmi = encoder_to_inno_hdmi(encoder); - struct drm_connector_state *conn_state; - struct drm_crtc_state *crtc_state; - conn_state = drm_atomic_get_new_connector_state(state, &hdmi->connector); - if (WARN_ON(!conn_state)) - return; - - crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc); - if (WARN_ON(!crtc_state)) - return; - - inno_hdmi_setup(hdmi, &crtc_state->adjusted_mode); + inno_hdmi_setup(hdmi, state); } static void inno_hdmi_encoder_disable(struct drm_encoder *encoder, struct drm_atomic_state *state) { @@ -561,11 +524,10 @@ static int inno_hdmi_encoder_atomic_check(struct drm_encoder *encoder, struct drm_crtc_state *crtc_state, struct drm_connector_state *conn_state) { struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state); - struct inno_hdmi *hdmi = encoder_to_inno_hdmi(encoder); struct drm_display_mode *mode = &crtc_state->adjusted_mode; u8 vic = drm_match_cea_mode(mode); struct inno_hdmi_connector_state *inno_conn_state = to_inno_hdmi_conn_state(conn_state); @@ -578,16 +540,11 @@ inno_hdmi_encoder_atomic_check(struct drm_encoder *encoder, vic == 17 || vic == 18) inno_conn_state->colorimetry = HDMI_COLORIMETRY_ITU_601; else inno_conn_state->colorimetry = HDMI_COLORIMETRY_ITU_709; - inno_conn_state->enc_out_format = HDMI_COLORSPACE_RGB; - inno_conn_state->rgb_limited_range = - drm_default_rgb_quant_range(mode) == HDMI_QUANTIZATION_RANGE_LIMITED; - - return inno_hdmi_display_mode_valid(hdmi, - &crtc_state->adjusted_mode) == MODE_OK ? 0 : -EINVAL; + return 0; } static struct drm_encoder_helper_funcs inno_hdmi_encoder_helper_funcs = { .atomic_check = inno_hdmi_encoder_atomic_check, .atomic_enable = inno_hdmi_encoder_enable, @@ -627,16 +584,10 @@ inno_hdmi_connector_mode_valid(struct drm_connector *connector, struct inno_hdmi *hdmi = connector_to_inno_hdmi(connector); return inno_hdmi_display_mode_valid(hdmi, mode); } -static void inno_hdmi_connector_destroy(struct drm_connector *connector) -{ - drm_connector_unregister(connector); - drm_connector_cleanup(connector); -} - static void inno_hdmi_connector_destroy_state(struct drm_connector *connector, struct drm_connector_state *state) { struct inno_hdmi_connector_state *inno_conn_state = @@ -658,14 +609,13 @@ static void inno_hdmi_connector_reset(struct drm_connector *connector) inno_conn_state = kzalloc(sizeof(*inno_conn_state), GFP_KERNEL); if (!inno_conn_state) return; __drm_atomic_helper_connector_reset(connector, &inno_conn_state->base); + __drm_atomic_helper_connector_hdmi_reset(connector, connector->state); inno_conn_state->colorimetry = HDMI_COLORIMETRY_ITU_709; - inno_conn_state->enc_out_format = HDMI_COLORSPACE_RGB; - inno_conn_state->rgb_limited_range = false; } static struct drm_connector_state * inno_hdmi_connector_duplicate_state(struct drm_connector *connector) { @@ -687,17 +637,17 @@ inno_hdmi_connector_duplicate_state(struct drm_connector *connector) } static const struct drm_connector_funcs inno_hdmi_connector_funcs = { .fill_modes = drm_helper_probe_single_connector_modes, .detect = inno_hdmi_connector_detect, - .destroy = inno_hdmi_connector_destroy, .reset = inno_hdmi_connector_reset, .atomic_duplicate_state = inno_hdmi_connector_duplicate_state, .atomic_destroy_state = inno_hdmi_connector_destroy_state, }; static struct drm_connector_helper_funcs inno_hdmi_connector_helper_funcs = { + .atomic_check = drm_atomic_helper_connector_hdmi_check, .get_modes = inno_hdmi_connector_get_modes, .mode_valid = inno_hdmi_connector_mode_valid, }; static int inno_hdmi_register(struct drm_device *drm, struct inno_hdmi *hdmi) @@ -721,14 +671,18 @@ static int inno_hdmi_register(struct drm_device *drm, struct inno_hdmi *hdmi) hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD; drm_connector_helper_add(&hdmi->connector, &inno_hdmi_connector_helper_funcs); - drm_connector_init_with_ddc(drm, &hdmi->connector, - &inno_hdmi_connector_funcs, - DRM_MODE_CONNECTOR_HDMIA, - hdmi->ddc); + drmm_connector_hdmi_init(drm, &hdmi->connector, + "Rockchip", "Inno HDMI", + &inno_hdmi_connector_funcs, + &inno_hdmi_hdmi_connector_funcs, + DRM_MODE_CONNECTOR_HDMIA, + hdmi->ddc, + BIT(HDMI_COLORSPACE_RGB), + 8); drm_connector_attach_encoder(&hdmi->connector, encoder); return 0; }