Received: by 2002:a05:7412:f589:b0:e2:908c:2ebd with SMTP id eh9csp375831rdb; Tue, 31 Oct 2023 09:50:01 -0700 (PDT) X-Google-Smtp-Source: AGHT+IGA21wnakuDIPil8gB8VFaOfANWSb8QYax1mbhxy4A8EvFm9PaA6Md5WxDjotm6LccMYs98 X-Received: by 2002:aa7:800f:0:b0:6c2:cb9a:885a with SMTP id j15-20020aa7800f000000b006c2cb9a885amr1091919pfi.27.1698771001652; Tue, 31 Oct 2023 09:50:01 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1698771001; cv=none; d=google.com; s=arc-20160816; b=hj6jgHpRhyueYXAHC4nWtLt31DOsq0HOinhphe/daX/cOt8GuI2fHWNTt4VA0/65Gj DaZTNfb1yTz7tHCHNCGxkOOacbqcUM8QsJRq0D/7AO0UrHVOfiwPMasSVrnXJV9fFv05 vvZN9iUvVe8hs80QuHR33CC16kZ6lLnrkyJ38mrB9XAptEtX8rL2gpZQbIjKRo/7TC/P 04VD2cNm3c+zk27STwvISUDMiAOQnzyvjYCW7785LTaUg9Mlda8iAgClQ5JFwLELQ/uc ZJptqNlgGas/WkBiIENDLmxP0d3kibNkbBYnvB7AG+AgvPvIqK8OK6/4Np0fmbAS+V2/ 9JUA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:in-reply-to:references:message-id :content-transfer-encoding:mime-version:subject:date:from :dkim-signature; bh=cw4O00xWxuXBZNTpWNN4xtYxz8vqSwiGZjWFN8bfAn0=; fh=e6/uyeFf2k7v8JUtB6fPyaAS5iN3eSA1hjtg35V2Rzw=; b=xLNsV7Lkvo/VkHA4jIRe457ES+chVheSbj2XdHRM66T+qG+KSRVmS0bgarg9GqKFrb FCH2NT0nNqlhzd4oyrAI96nrvvN4KkiFGP5+WnHL6RSP42BqTUGK88WJymUmJAwB0YIa J6inZH/MPwfZYvqR/cJB4K5/AaAmvyPUwaYwub6nJprpXT9HVhurTUe9EUHnDZKzmrLC mOSRU/X+ysZ16Pbnm+a9vnkmDGSNCByEjBUJpDEJPCa4JzEWn9e7EmoN6MdPzCaEaWjM bIruvuyEndGrhgJyNAhLM2ASnfzWaTdPOjG2TQTM68o3yvv1ZRROCm8+KsvUcQloLoUn /6Yw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=l9kWcqgu; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::3:4 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Return-Path: Received: from howler.vger.email (howler.vger.email. [2620:137:e000::3:4]) by mx.google.com with ESMTPS id h66-20020a625345000000b006bd66ce21d9si1184882pfb.322.2023.10.31.09.50.01 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 31 Oct 2023 09:50:01 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::3:4 as permitted sender) client-ip=2620:137:e000::3:4; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=l9kWcqgu; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::3:4 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Received: from out1.vger.email (depot.vger.email [IPv6:2620:137:e000::3:0]) by howler.vger.email (Postfix) with ESMTP id 43A86802D321; Tue, 31 Oct 2023 09:49:57 -0700 (PDT) X-Virus-Status: Clean X-Virus-Scanned: clamav-milter 0.103.10 at howler.vger.email Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1346878AbjJaQta (ORCPT + 99 others); Tue, 31 Oct 2023 12:49:30 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34676 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1346813AbjJaQtH (ORCPT ); Tue, 31 Oct 2023 12:49:07 -0400 Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0E6EF92; Tue, 31 Oct 2023 09:49:04 -0700 (PDT) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 4A8A1C433C8; Tue, 31 Oct 2023 16:49:03 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1698770943; bh=rHYthuEAKWMT+SwH14h9aTghHT2m9GRJ6TpS16pFlgM=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=l9kWcqgu2ESQH2UcOr/q4TmJBMMye1TAarzPie8qKUb+sLZSG7coj4b+Y2fwm76Ku kqbsl3orAPX3OkuhxLxLvugf9jKYMFExmeitMxvIum8XdWaXOwJPojP8/ZG2AUKkSl odNaY6nbxX156ekN7kTvms9ManjBCQ8BbyYw9CXQc8IgoWyvMRRhw3Db4lyyQsXZ2V 8WltxCE/iblv2RLo1Yu4YFj81DOlZDw5AkjE2ROuSlnTyzvOPDJ562DUEjc+idZZli 8qJzH4p8mDlWdB2ksRPy96esxq0sLhzoc5VZhOOX0M7fLq2zJc6UNBJKv2XoAcyGAa qxPJG52Jb2EzA== From: Maxime Ripard Date: Tue, 31 Oct 2023 17:48:23 +0100 Subject: [PATCH RFC v3 10/37] drm/connector: hdmi: Compute bpc and format automatically MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Message-Id: <20231031-kms-hdmi-connector-state-v3-10-328b0fae43a7@kernel.org> References: <20231031-kms-hdmi-connector-state-v3-0-328b0fae43a7@kernel.org> In-Reply-To: <20231031-kms-hdmi-connector-state-v3-0-328b0fae43a7@kernel.org> To: Maarten Lankhorst , Thomas Zimmermann , David Airlie , Daniel Vetter , Emma Anholt , Jonathan Corbet , Sandy Huang , =?utf-8?q?Heiko_St=C3=BCbner?= , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland Cc: Hans Verkuil , 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 X-Mailer: b4 0.12.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=6972; i=mripard@kernel.org; h=from:subject:message-id; bh=rHYthuEAKWMT+SwH14h9aTghHT2m9GRJ6TpS16pFlgM=; b=owGbwMvMwCX2+D1vfrpE4FHG02pJDKmO+ve0v3yNbDNumTlJear6scSqH/Hs8XJeK56WOPB29 Wx6u5G3o5SFQYyLQVZMkSVG2HxJ3KlZrzvZ+ObBzGFlAhnCwMUpABPhbGL4779xe/Z7H816rZ07 rxvU/Ym4fvm2wgubYtvZU4x/WbC/NWZkuLR6W4dpzwb282UPWd4o/L1YELloStPsIOs9k6SnuTX sZwAA X-Developer-Key: i=mripard@kernel.org; a=openpgp; fpr=BE5675C37E818C8B5764241C254BCFC56BF6CE8D X-Spam-Status: No, score=-1.7 required=5.0 tests=DKIMWL_WL_HIGH,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,MAILING_LIST_MULTI, SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on howler.vger.email Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-Greylist: Sender passed SPF test, not delayed by milter-greylist-4.6.4 (howler.vger.email [0.0.0.0]); Tue, 31 Oct 2023 09:49:57 -0700 (PDT) Now that we have all the infrastructure needed, we can add some code that will, for a given connector state and mode, compute the best output format and bpc. The algorithm is the same one than the one already found in i915 and vc4. Signed-off-by: Maxime Ripard --- drivers/gpu/drm/drm_atomic_state_helper.c | 185 +++++++++++++++++++++++++++++- 1 file changed, 181 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c index 0dd1dad99cce..1420d9fdfa35 100644 --- a/drivers/gpu/drm/drm_atomic_state_helper.c +++ b/drivers/gpu/drm/drm_atomic_state_helper.c @@ -670,6 +670,96 @@ static bool hdmi_is_full_range(const struct drm_connector *connector, return drm_default_rgb_quant_range(mode); } +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) +{ + struct drm_device *dev = connector->dev; + u8 vic = drm_match_cea_mode(mode); + + if (vic == 1 && bpc != 8) { + drm_dbg(dev, "VIC1 requires a bpc of 8, got %u\n", bpc); + return false; + } + + if (!info->is_hdmi && + (format != HDMI_COLORSPACE_RGB || bpc != 8)) { + drm_dbg(dev, "DVI Monitors require an RGB output at 8 bpc\n"); + return false; + } + + if (!(connector->hdmi.supported_formats & BIT(format))) { + drm_dbg(dev, "%s format unsupported by the connector.\n", + drm_hdmi_connector_get_output_format_name(format)); + return false; + } + + switch (format) { + case HDMI_COLORSPACE_RGB: + drm_dbg(dev, "RGB Format, checking the constraints.\n"); + + if (!(info->color_formats & DRM_COLOR_FORMAT_RGB444)) + return false; + + if (bpc == 10 && !(info->edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_30)) { + drm_dbg(dev, "10 BPC but sink doesn't support Deep Color 30.\n"); + return false; + } + + if (bpc == 12 && !(info->edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_36)) { + drm_dbg(dev, "12 BPC but sink doesn't support Deep Color 36.\n"); + return false; + } + + drm_dbg(dev, "RGB format supported in that configuration.\n"); + + return true; + + case HDMI_COLORSPACE_YUV422: + drm_dbg(dev, "YUV422 format, checking the constraints.\n"); + + if (!(info->color_formats & DRM_COLOR_FORMAT_YCBCR422)) { + drm_dbg(dev, "Sink doesn't support YUV422.\n"); + return false; + } + + if (bpc != 12) { + drm_dbg(dev, "YUV422 only supports 12 bpc.\n"); + return false; + } + + drm_dbg(dev, "YUV422 format supported in that configuration.\n"); + + return true; + + case HDMI_COLORSPACE_YUV444: + drm_dbg(dev, "YUV444 format, checking the constraints.\n"); + + if (!(info->color_formats & DRM_COLOR_FORMAT_YCBCR444)) { + drm_dbg(dev, "Sink doesn't support YUV444.\n"); + return false; + } + + if (bpc == 10 && !(info->edid_hdmi_ycbcr444_dc_modes & DRM_EDID_HDMI_DC_30)) { + drm_dbg(dev, "10 BPC but sink doesn't support Deep Color 30.\n"); + return false; + } + + if (bpc == 12 && !(info->edid_hdmi_ycbcr444_dc_modes & DRM_EDID_HDMI_DC_36)) { + drm_dbg(dev, "12 BPC but sink doesn't support Deep Color 36.\n"); + return false; + } + + drm_dbg(dev, "YUV444 format supported in that configuration.\n"); + + return true; + } + + return false; +} + static enum drm_mode_status hdmi_clock_valid(const struct drm_connector *connector, const struct drm_display_mode *mode, @@ -714,6 +804,95 @@ hdmi_compute_clock(const struct drm_connector *connector, return 0; } +static bool +hdmi_try_format_bpc(const struct drm_connector *connector, + struct drm_connector_state *state, + const struct drm_display_mode *mode, + unsigned int bpc, enum hdmi_colorspace fmt) +{ + const struct drm_display_info *info = &connector->display_info; + struct drm_device *dev = connector->dev; + int ret; + + drm_dbg(dev, "Trying %s output format\n", + drm_hdmi_connector_get_output_format_name(fmt)); + + if (!sink_supports_format_bpc(connector, info, mode, fmt, bpc)) { + drm_dbg(dev, "%s output format not supported with %u bpc\n", + drm_hdmi_connector_get_output_format_name(fmt), bpc); + return false; + } + + ret = hdmi_compute_clock(connector, state, mode, bpc, fmt); + if (ret) { + drm_dbg(dev, "Couldn't compute clock for %s output format and %u bpc\n", + drm_hdmi_connector_get_output_format_name(fmt), bpc); + return false; + } + + drm_dbg(dev, "%s output format supported with %u (TMDS char rate: %llu Hz)\n", + drm_hdmi_connector_get_output_format_name(fmt), bpc, state->hdmi.tmds_char_rate); + + return true; +} + +static int +hdmi_compute_format(const struct drm_connector *connector, + struct drm_connector_state *state, + const struct drm_display_mode *mode, + unsigned int bpc) +{ + struct drm_device *dev = connector->dev; + + if (hdmi_try_format_bpc(connector, state, mode, bpc, HDMI_COLORSPACE_RGB)) { + state->hdmi.output_format = HDMI_COLORSPACE_RGB; + return 0; + } + + if (hdmi_try_format_bpc(connector, state, mode, bpc, HDMI_COLORSPACE_YUV422)) { + state->hdmi.output_format = HDMI_COLORSPACE_YUV422; + return 0; + } + + drm_dbg(dev, "Failed. No Format Supported for that bpc count.\n"); + + return -EINVAL; +} + +static int +hdmi_compute_config(const struct drm_connector *connector, + struct drm_connector_state *state, + const struct drm_display_mode *mode) +{ + struct drm_device *dev = connector->dev; + unsigned int max_bpc = clamp_t(unsigned int, + state->max_bpc, + 8, connector->max_bpc); + unsigned int bpc; + int ret; + + for (bpc = max_bpc; bpc >= 8; bpc -= 2) { + drm_dbg(dev, "Trying with a %d bpc output\n", bpc); + + ret = hdmi_compute_format(connector, state, mode, bpc); + if (ret) + continue; + + state->hdmi.output_bpc = bpc; + + drm_dbg(dev, + "Mode %ux%u @ %uHz: Found configuration: bpc: %u, fmt: %s, clock: %llu\n", + mode->hdisplay, mode->vdisplay, drm_mode_vrefresh(mode), + state->hdmi.output_bpc, + drm_hdmi_connector_get_output_format_name(state->hdmi.output_format), + state->hdmi.tmds_char_rate); + + return 0; + } + + return -EINVAL; +} + /** * drm_atomic_helper_connector_hdmi_check() - Helper to check HDMI connector atomic state * @connector: DRM Connector @@ -739,10 +918,8 @@ int drm_atomic_helper_connector_hdmi_check(struct drm_connector *connector, new_state->hdmi.is_full_range = hdmi_is_full_range(connector, new_state); - ret = hdmi_compute_clock(connector, new_state, mode, - new_state->hdmi.output_bpc, - new_state->hdmi.output_format); - if (!ret) + ret = hdmi_compute_config(connector, new_state, mode); + if (ret) return ret; if (old_state->hdmi.broadcast_rgb != new_state->hdmi.broadcast_rgb || -- 2.41.0