From patchwork Thu Mar 7 13:38:46 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Maxime Ripard X-Patchwork-Id: 13585669 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 313BBC48BF6 for ; Thu, 7 Mar 2024 13:42:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:Cc:To:In-Reply-To:References:Message-Id :MIME-Version:Subject:Date:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=3aqiT5tllCMKj7rp77okMYGHshG9Sw0piIiegOAbPr4=; b=SaXSkr64bx63p5 5xmrimsiWpHA7AdRzrOQx4CHLxTofqHR0dZMuj3UKsv0X4o3/m/uoihSkxe6DgeT/zXfi7TF7Zwd+ BnzY4v0XAmPYf9bmPutOFhXfUD9NP6qGQ0u8t0Ou2br+kvDcYX8a13D/uGE51PMB8bPlLDVoTHY/Y FLM2qq4BNj62F1XrgKzNHSR8FAdKXpOmOwf0F/fzVXCM6ywCwBiBcDgFsRFluJczcVtd8qoZTnpU4 ZlkCr8NJHgbJAyP+mo9Ef9E2zNQQyaG5uaL9/EK0Gc+4DghfoXQ6ZNsMAO7YSsgg8HTDXDmFfPn2h HfLUfYY3mqJ5JzulNDag==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.97.1 #2 (Red Hat Linux)) id 1riE0S-00000004oht-1PVJ; Thu, 07 Mar 2024 13:41:56 +0000 Received: from sin.source.kernel.org ([145.40.73.55]) by bombadil.infradead.org with esmtps (Exim 4.97.1 #2 (Red Hat Linux)) id 1riDyS-00000004n8s-1zMF; Thu, 07 Mar 2024 13:40:00 +0000 Received: from smtp.kernel.org (transwarp.subspace.kernel.org [100.75.92.58]) by sin.source.kernel.org (Postfix) with ESMTP id 42107CE243D; Thu, 7 Mar 2024 13:39:50 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 1F92FC43394; Thu, 7 Mar 2024 13:39:48 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1709818789; bh=hdQFimYEoL1NKCgBJcqXUYcz0R/w6fqejvd5drDOq3w=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=CcnGj1mx/BjKG72fDm3+LOJSGFSu6S0gFxvEBbE6YWYFKwOBH0Zp1RPRt3mJD79x6 494NX9AusvNJQrqz4+MfcLAxJddFdQ9+bY5mNBrIAEWKLUslIeV+W7NydDru1ULDIz kN6nMWpfpgRtSacaXQpanj0jfrSdd8vrD+sIenzwB1U5mJk/DvaR4E5auQo4RKUUZB 25dPjRB3qSaDv/TaKXBgr1+17fJU0v/Yf5phBg/K6moVK9GNKrwx1HMO2MiGrM4nvS vINjaX1U3oQIwvPfnDKuCSfynbF2ydD9jAPpMRSrRyfql6E1wNwSn+3KjH2Svjt+WB G3ygVIJhV+thA== From: Maxime Ripard Date: Thu, 07 Mar 2024 14:38:46 +0100 Subject: [PATCH v8 19/27] drm/tests: Add RGB Quantization tests MIME-Version: 1.0 Message-Id: <20240307-kms-hdmi-connector-state-v8-19-ef6a6f31964b@kernel.org> References: <20240307-kms-hdmi-connector-state-v8-0-ef6a6f31964b@kernel.org> In-Reply-To: <20240307-kms-hdmi-connector-state-v8-0-ef6a6f31964b@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 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.12.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=20952; i=mripard@kernel.org; h=from:subject:message-id; bh=hdQFimYEoL1NKCgBJcqXUYcz0R/w6fqejvd5drDOq3w=; b=owGbwMvMwCX2+D1vfrpE4FHG02pJDKkvD6cniJp69pqHiJ8p+uardFHcOWnPdmPtehbPDyWMe vV2hrs7SlkYxLgYZMUUWWKEzZfEnZr1upONbx7MHFYmkCEMXJwCMJHjpowMOxd2e7ostU25tFdc 89/jNzUX1mZGZP/ZOHOtb/qmmWfijjIyvFb+GP8n5Xv/0ZCHX+aVu5oJvJn5qun5jZ3Xau/qPk/ kZwAA X-Developer-Key: i=mripard@kernel.org; a=openpgp; fpr=BE5675C37E818C8B5764241C254BCFC56BF6CE8D X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20240307_053953_458559_A4E6B83A X-CRM114-Status: GOOD ( 13.65 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org The previous commit added the infrastructure to the connector state to track what RGB Quantization should be used in a given state for an HDMI connector. Let's add some kunit tests to make sure it works as expected. Reviewed-by: Dave Stevenson Signed-off-by: Maxime Ripard --- .../gpu/drm/tests/drm_atomic_state_helper_test.c | 563 +++++++++++++++++++++ 1 file changed, 563 insertions(+) diff --git a/drivers/gpu/drm/tests/drm_atomic_state_helper_test.c b/drivers/gpu/drm/tests/drm_atomic_state_helper_test.c index 3de15cec2f5f..dcc0f7486f49 100644 --- a/drivers/gpu/drm/tests/drm_atomic_state_helper_test.c +++ b/drivers/gpu/drm/tests/drm_atomic_state_helper_test.c @@ -350,10 +350,564 @@ static void drm_test_check_broadcast_rgb_crtc_mode_not_changed(struct kunit *tes 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 for an HDMI connector, with an HDMI monitor, if the + * Broadcast RGB property is set to auto with a mode that isn't the + * VIC-1 mode, we will get a limited RGB Quantization Range. + */ +static void drm_test_check_broadcast_rgb_auto_cea_mode(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_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, + BIT(HDMI_COLORSPACE_RGB), + 8); + KUNIT_ASSERT_NOT_NULL(test, priv); + + conn = &priv->connector; + KUNIT_ASSERT_TRUE(test, conn->display_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); + KUNIT_ASSERT_NE(test, drm_match_cea_mode(preferred), 1); + + 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); + + conn_state = drm_atomic_get_connector_state(state, conn); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state); + + KUNIT_ASSERT_EQ(test, + conn_state->hdmi.broadcast_rgb, + DRM_HDMI_BROADCAST_RGB_AUTO); + + ret = drm_atomic_check_only(state); + KUNIT_ASSERT_EQ(test, ret, 0); + + conn_state = drm_atomic_get_connector_state(state, conn); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state); + + KUNIT_EXPECT_FALSE(test, conn_state->hdmi.is_full_range); +} + +/* + * Test that for an HDMI connector, with an HDMI monitor, if the + * Broadcast RGB property is set to auto with a VIC-1 mode, we will get + * a full RGB Quantization Range. + */ +static void drm_test_check_broadcast_rgb_auto_cea_mode_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_atomic_state *state; + struct drm_display_mode *mode; + 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; + KUNIT_ASSERT_TRUE(test, conn->display_info.is_hdmi); + + 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); + + drm = &priv->drm; + crtc = priv->crtc; + ret = light_up_connector(test, drm, crtc, conn, mode, 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); + + conn_state = drm_atomic_get_connector_state(state, conn); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state); + + KUNIT_ASSERT_EQ(test, + conn_state->hdmi.broadcast_rgb, + DRM_HDMI_BROADCAST_RGB_AUTO); + + ret = drm_atomic_check_only(state); + KUNIT_ASSERT_EQ(test, ret, 0); + + conn_state = drm_atomic_get_connector_state(state, conn); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state); + + KUNIT_EXPECT_TRUE(test, conn_state->hdmi.is_full_range); +} + +/* + * Test that for an HDMI connector, with an HDMI monitor, if the + * Broadcast RGB property is set to full with a mode that isn't the + * VIC-1 mode, we will get a full RGB Quantization Range. + */ +static void drm_test_check_broadcast_rgb_full_cea_mode(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_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, + BIT(HDMI_COLORSPACE_RGB), + 8); + KUNIT_ASSERT_NOT_NULL(test, priv); + + conn = &priv->connector; + KUNIT_ASSERT_TRUE(test, conn->display_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); + KUNIT_ASSERT_NE(test, drm_match_cea_mode(preferred), 1); + + 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); + + conn_state = drm_atomic_get_connector_state(state, conn); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state); + + conn_state->hdmi.broadcast_rgb = DRM_HDMI_BROADCAST_RGB_FULL; + + ret = drm_atomic_check_only(state); + KUNIT_ASSERT_EQ(test, ret, 0); + + conn_state = drm_atomic_get_connector_state(state, conn); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state); + + KUNIT_ASSERT_EQ(test, + conn_state->hdmi.broadcast_rgb, + DRM_HDMI_BROADCAST_RGB_FULL); + + KUNIT_EXPECT_TRUE(test, conn_state->hdmi.is_full_range); +} + +/* + * Test that for an HDMI connector, with an HDMI monitor, if the + * Broadcast RGB property is set to full with a VIC-1 mode, we will get + * a full RGB Quantization Range. + */ +static void drm_test_check_broadcast_rgb_full_cea_mode_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_atomic_state *state; + struct drm_display_mode *mode; + 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; + KUNIT_ASSERT_TRUE(test, conn->display_info.is_hdmi); + + 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); + + drm = &priv->drm; + crtc = priv->crtc; + ret = light_up_connector(test, drm, crtc, conn, mode, 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); + + conn_state = drm_atomic_get_connector_state(state, conn); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state); + + conn_state->hdmi.broadcast_rgb = DRM_HDMI_BROADCAST_RGB_FULL; + + ret = drm_atomic_check_only(state); + KUNIT_ASSERT_EQ(test, ret, 0); + + conn_state = drm_atomic_get_connector_state(state, conn); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state); + + KUNIT_ASSERT_EQ(test, + conn_state->hdmi.broadcast_rgb, + DRM_HDMI_BROADCAST_RGB_FULL); + + KUNIT_EXPECT_TRUE(test, conn_state->hdmi.is_full_range); +} + +/* + * Test that for an HDMI connector, with an HDMI monitor, if the + * Broadcast RGB property is set to limited with a mode that isn't the + * VIC-1 mode, we will get a limited RGB Quantization Range. + */ +static void drm_test_check_broadcast_rgb_limited_cea_mode(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_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, + BIT(HDMI_COLORSPACE_RGB), + 8); + KUNIT_ASSERT_NOT_NULL(test, priv); + + conn = &priv->connector; + KUNIT_ASSERT_TRUE(test, conn->display_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); + KUNIT_ASSERT_NE(test, drm_match_cea_mode(preferred), 1); + + 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); + + conn_state = drm_atomic_get_connector_state(state, conn); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state); + + conn_state->hdmi.broadcast_rgb = DRM_HDMI_BROADCAST_RGB_LIMITED; + + ret = drm_atomic_check_only(state); + KUNIT_ASSERT_EQ(test, ret, 0); + + conn_state = drm_atomic_get_connector_state(state, conn); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state); + + KUNIT_ASSERT_EQ(test, + conn_state->hdmi.broadcast_rgb, + DRM_HDMI_BROADCAST_RGB_LIMITED); + + KUNIT_EXPECT_FALSE(test, conn_state->hdmi.is_full_range); +} + +/* + * Test that for an HDMI connector, with an HDMI monitor, if the + * Broadcast RGB property is set to limited with a VIC-1 mode, we will + * get a limited RGB Quantization Range. + */ +static void drm_test_check_broadcast_rgb_limited_cea_mode_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_atomic_state *state; + struct drm_display_mode *mode; + 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; + KUNIT_ASSERT_TRUE(test, conn->display_info.is_hdmi); + + 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); + + drm = &priv->drm; + crtc = priv->crtc; + ret = light_up_connector(test, drm, crtc, conn, mode, 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); + + conn_state = drm_atomic_get_connector_state(state, conn); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state); + + conn_state->hdmi.broadcast_rgb = DRM_HDMI_BROADCAST_RGB_LIMITED; + + ret = drm_atomic_check_only(state); + KUNIT_ASSERT_EQ(test, ret, 0); + + conn_state = drm_atomic_get_connector_state(state, conn); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state); + + KUNIT_ASSERT_EQ(test, + conn_state->hdmi.broadcast_rgb, + DRM_HDMI_BROADCAST_RGB_LIMITED); + + KUNIT_EXPECT_FALSE(test, conn_state->hdmi.is_full_range); +} + +/* + * Test that if we have an HDMI connector that would use a YUV output, + * we always get a limited quantization range with the Broadcast RGB + * property set to auto. + */ +static void drm_test_check_broadcast_rgb_auto_yuv(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_atomic_state *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), + 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_connector_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_RGB); + KUNIT_ASSERT_GT(test, rate, info->max_tmds_clock * 1000); + + rate = drm_connector_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); + + 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, conn); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state); + + conn_state->hdmi.broadcast_rgb = DRM_HDMI_BROADCAST_RGB_AUTO; + + ret = drm_atomic_check_only(state); + KUNIT_ASSERT_EQ(test, ret, 0); + + conn_state = drm_atomic_get_connector_state(state, conn); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state); + + KUNIT_ASSERT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_YUV422); + KUNIT_EXPECT_FALSE(test, conn_state->hdmi.is_full_range); +} + +/* + * Test that if we have an HDMI connector that would use a YUV output, + * we always get a limited quantization range even if we have the + * Broadcast RGB property set to full. + */ +static void drm_test_check_broadcast_rgb_full_yuv(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_atomic_state *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), + 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_connector_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_RGB); + KUNIT_ASSERT_GT(test, rate, info->max_tmds_clock * 1000); + + rate = drm_connector_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); + + 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, conn); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state); + + conn_state->hdmi.broadcast_rgb = DRM_HDMI_BROADCAST_RGB_FULL; + + ret = drm_atomic_check_only(state); + KUNIT_ASSERT_EQ(test, ret, 0); + + conn_state = drm_atomic_get_connector_state(state, conn); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state); + + KUNIT_ASSERT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_YUV422); + KUNIT_EXPECT_FALSE(test, conn_state->hdmi.is_full_range); +} + +/* + * Test that if we have an HDMI connector that would use a YUV output, + * we always get a limited quantization range even if we have the + * Broadcast RGB property set to full. + */ +static void drm_test_check_broadcast_rgb_limited_yuv(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_atomic_state *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), + 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_connector_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_RGB); + KUNIT_ASSERT_GT(test, rate, info->max_tmds_clock * 1000); + + rate = drm_connector_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); + + 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, conn); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state); + + conn_state->hdmi.broadcast_rgb = DRM_HDMI_BROADCAST_RGB_LIMITED; + + ret = drm_atomic_check_only(state); + KUNIT_ASSERT_EQ(test, ret, 0); + + conn_state = drm_atomic_get_connector_state(state, conn); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state); + + KUNIT_ASSERT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_YUV422); + KUNIT_EXPECT_FALSE(test, conn_state->hdmi.is_full_range); +} + /* * 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. */ @@ -1185,10 +1739,19 @@ static void drm_test_check_output_bpc_format_display_8bpc_only(struct kunit *tes 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_broadcast_rgb_auto_cea_mode), + KUNIT_CASE(drm_test_check_broadcast_rgb_auto_cea_mode_vic_1), + KUNIT_CASE(drm_test_check_broadcast_rgb_auto_yuv), + KUNIT_CASE(drm_test_check_broadcast_rgb_full_cea_mode), + KUNIT_CASE(drm_test_check_broadcast_rgb_full_cea_mode_vic_1), + KUNIT_CASE(drm_test_check_broadcast_rgb_full_yuv), + KUNIT_CASE(drm_test_check_broadcast_rgb_limited_cea_mode), + KUNIT_CASE(drm_test_check_broadcast_rgb_limited_cea_mode_vic_1), + KUNIT_CASE(drm_test_check_broadcast_rgb_limited_yuv), KUNIT_CASE(drm_test_check_broadcast_rgb_crtc_mode_changed), KUNIT_CASE(drm_test_check_broadcast_rgb_crtc_mode_not_changed), 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),