From nobody Fri Sep 25 21:02:41 2026 Received: from sender4-pp-f112.zoho.com (sender4-pp-f112.zoho.com [136.143.188.112]) (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 D07B34B95A2; Mon, 21 Sep 2026 15:53:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=136.143.188.112 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790005989; cv=pass; b=ezX1yvaIocoM4vvF/Em8jU5JBPz6sJNhU/QYkp7lNyeJhzTyNy3iqzPkwK05F5BjDuhMPDEFxMnatkYrGKpm5YQ70z8lL2Y0HqQ8To8joUsUwFoOuJ0gc9PLmuS0tt1qoCAWpAZq0KxgKDEfK81DwhJjmai561inPoBENYbLNzA= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790005989; c=relaxed/simple; bh=ExTvC81Bs4eS6LV9WfZ/zyNCzqDz6KaMxsAYa/GJsWI=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=loMn8C78SfwzANB33+KERiwums0qxtHXpgJlq5xocudLd9pl42GZsX8V3iFL2EFuFNOMnoPSIXGjJZNCMlf0iMvpHphCuAN/dMKT3Ybm/3dUoLMudWQJnt/zLa8xrzGA5JEqe1m8nv4blGIwYv0JvskwGjKhC788ERf6HVH84/g= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (1024-bit key) header.d=collabora.com header.i=nicolas.frattaroli@collabora.com header.b=gU8WwUFL; arc=pass smtp.client-ip=136.143.188.112 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=collabora.com header.i=nicolas.frattaroli@collabora.com header.b="gU8WwUFL" ARC-Seal: i=1; a=rsa-sha256; t=1790005929; cv=none; d=zohomail.com; s=zohoarc; b=Ml3smdYUlqSH1mc6vbEi4yTO3jB8SQVOP3F5f7I0Sm7/CgNHUOqB6wbBfHlFhYXrh0DEPWTR1gWA9Yf5Mdvbc4mHAY2uPYwHSc5GaZNA8p09CWciJ53xvIr8ssVE8z+O7IDCoVNnP/H+480BENWeAaLtxrmmtGzg9YGzHl9P89A= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1790005929; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:MIME-Version:Message-ID:Subject:Subject:To:To:Message-Id:Reply-To; bh=ytG9EVMPqKl2Mw9Xbxf4dujO3AFiJ9cigwIohDH1vlA=; b=n2Ey+GF00mNbV9T77/DBajAOOcuV6t+CHyWyqkBNaL3MBXGttwujwgM/kM3Z5EVzL7P2Kk7RSA/a/idHnLOMdqCcufg6eXolwQf6+o1WPRbMfSQtHxz0/0aJ6SKCJBlYtFLGkVBdMBDtT2F/6sqpFepvXTCTNy/FKfaC/A7ndbM= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass header.i=collabora.com; spf=pass smtp.mailfrom=nicolas.frattaroli@collabora.com; dmarc=pass header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1790005929; s=zohomail; d=collabora.com; i=nicolas.frattaroli@collabora.com; h=From:From:Date:Date:Subject:Subject:MIME-Version:Content-Type:Content-Transfer-Encoding:Message-Id:Message-Id:In-Reply-To:To:To:Cc:Cc:Reply-To; bh=ytG9EVMPqKl2Mw9Xbxf4dujO3AFiJ9cigwIohDH1vlA=; b=gU8WwUFLpF1njrpENtAeLn9Je+89Y8DPu3LgczqOAd13iQ0DKPP/lMLfYOhGfLxD GjPUDSVLgBHWOgY9eGj15EgzocYYk2LfctCYNU13ft1oC7MzTYxBeOJFbOC+RdiVzCx J5MeO74szXzSbK08Cpgl+psIsvYdxXxIQlNKBTUs= Received: by smtp.zohomail.com with SMTPS id 1790005926723132.8117967235828; Mon, 21 Sep 2026 08:52:06 -0700 (PDT) From: Nicolas Frattaroli Date: Mon, 21 Sep 2026 17:51:27 +0200 Subject: [PATCH RFC 01/25] drm/edid: Add a query for vrr range Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260921-vrr-limiter-uapi-v1-1-2fcd7d011646@collabora.com> References: <20260921-vrr-limiter-uapi-v1-0-2fcd7d011646@collabora.com> In-Reply-To: <20260921-vrr-limiter-uapi-v1-0-2fcd7d011646@collabora.com> To: "Borah, Chaitanya Kumar" , Leo Li , Daniel Stone , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Helge Deller , Andrzej Hajda , Neil Armstrong , Robert Foss , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Luca Ceresoli , Sandy Huang , =?utf-8?q?Heiko_St=C3=BCbner?= , Andy Yan Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, linux-fbdev@vger.kernel.org, linux-rockchip@lists.infradead.org, linux-arm-kernel@lists.infradead.org, kernel@collabora.com, Derek Foreman , wayland-devel@lists.freedesktop.org, Nicolas Frattaroli X-Mailer: b4 0.15.2 From: Derek Foreman Query the minimum and maximum VRR vertical rates from EDID. Signed-off-by: Derek Foreman Signed-off-by: Nicolas Frattaroli --- drivers/gpu/drm/drm_edid.c | 26 ++++++++++++++++++++++++++ include/drm/drm_connector.h | 3 +++ 2 files changed, 29 insertions(+) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 3148038747b6..a1494028e0f5 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -6309,6 +6309,25 @@ static void drm_parse_dsc_info(struct drm_hdmi_dsc_c= ap *hdmi_dsc, hdmi_dsc->total_chunk_kbytes =3D hf_scds[13] & DRM_EDID_DSC_TOTAL_CHUNK_= KBYTES; } =20 +static void drm_parse_vrr_info(struct drm_display_info *info, const u8 *hf= _scds) +{ + struct drm_monitor_range_info *range =3D &info->monitor_range; + const int pld_len =3D cea_db_payload_len(hf_scds); + + if (pld_len < 10) + return; + + if (!range->min_vfreq) + range->min_vfreq =3D FIELD_GET(DRM_EDID_VRR_MIN_MASK, hf_scds[9]); + + if (pld_len < 11) + return; + + if (!range->max_vfreq) + range->max_vfreq =3D (FIELD_GET(DRM_EDID_VRR_MAX_UPPER_MASK, hf_scds[9])= << 8) | + hf_scds[10]; +} + /* Sink Capability Data Structure */ static void drm_parse_hdmi_forum_scds(struct drm_connector *connector, const u8 *hf_scds) @@ -6371,6 +6390,13 @@ static void drm_parse_hdmi_forum_scds(struct drm_con= nector *connector, dsc_support =3D true; } =20 + drm_parse_vrr_info(info, hf_scds); + + if (info->monitor_range.min_vfreq > 0) + hdmi->vrr_capable =3D true; + else + hdmi->vrr_capable =3D false; + drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] HF-VSDB: max TMDS clock: %d KHz, HDMI 2.1 support= : %s, DSC 1.2 support: %s\n", connector->base.id, connector->name, diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 2ee7c59329aa..593fbeaffa16 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -380,6 +380,9 @@ struct drm_hdmi_info { =20 /** @dsc_cap: DSC capabilities of the sink */ struct drm_hdmi_dsc_cap dsc_cap; + + /** @vrr_capable: The sink supports variable refresh rate */ + bool vrr_capable; }; =20 /** --=20 2.55.0 From nobody Fri Sep 25 21:02:41 2026 Received: from sender4-pp-f112.zoho.com (sender4-pp-f112.zoho.com [136.143.188.112]) (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 D422E4BA1EC; Mon, 21 Sep 2026 15:53:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=136.143.188.112 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790005989; cv=pass; b=EaVnijWYy5vG5PiioIgoG7THs4N/PEtCypjFnouyw4HjVVhsFiBUFujoxhDbE5H7XbRxxuv4L2gsfQ//HkJ1w2Wr4FJVDHy72QIB6CD7PuVGs6tDucTpVE38DhleLgF0fD6DuNCGwbtxhj7IsJZ4KqPxpo19y7PrX+BXlM7woS4= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790005989; c=relaxed/simple; bh=/xB7xPGoX6Fc0hViVOqrOKWzmSeDOdtc/GJJfB9XcJg=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=baSy48vczoL9MYnblL4bpKeown6k6Mi8ZHa7kaSicl6ZuqCNmkm9nQnlS/odc+BCnxxDsmbVlWYqx5phU2FqbtqElhujCrXyqyo4RqDtPOJulfQG8NsV4hB0KsFEQnWGI7LeUjusramtfyqGl9bxyrfOH8SHm53UiVElSsCyJ/U= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (1024-bit key) header.d=collabora.com header.i=nicolas.frattaroli@collabora.com header.b=DOswmEm0; arc=pass smtp.client-ip=136.143.188.112 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=collabora.com header.i=nicolas.frattaroli@collabora.com header.b="DOswmEm0" ARC-Seal: i=1; a=rsa-sha256; t=1790005935; cv=none; d=zohomail.com; s=zohoarc; b=OBVv96TUXdoXic0cqDd4x0l2klxzddq8NcTlmTRkDBPHPkwClnotLGwcJiHoZo6yb2uygiJBPSJF9nDHwWxVQZe+GehSaR6NCxgxvP1wbb+15HI/pU7WFSmD3T3vYqwVdKAvr1BlINBqVTJSGuP1F57Enstg9oqCSo88ZmfLXDM= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1790005935; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:MIME-Version:Message-ID:Subject:Subject:To:To:Message-Id:Reply-To; bh=JuZK847Y5757sJEnhMHU8hTY28zMxad07CW44p71Yy0=; b=MALTOISkOWJDGYoqcjLU+uLFaPLt9FIREdkWFykcGokRsVk4ACqnNnaCeLHHZXNsFaBOILT4a0hG7/ImpRK/qCDs4oqNQqlKwb5e4rB3d2CrFoUMy24gjWAwSgSw4NVJYzkM7i4PQNLnJqA2d5qAhax1/COYA1hMi0vzZ1NIGf0= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass header.i=collabora.com; spf=pass smtp.mailfrom=nicolas.frattaroli@collabora.com; dmarc=pass header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1790005935; s=zohomail; d=collabora.com; i=nicolas.frattaroli@collabora.com; h=From:From:Date:Date:Subject:Subject:MIME-Version:Content-Type:Content-Transfer-Encoding:Message-Id:Message-Id:In-Reply-To:To:To:Cc:Cc:Reply-To; bh=JuZK847Y5757sJEnhMHU8hTY28zMxad07CW44p71Yy0=; b=DOswmEm0LaguHnu3Q1ydRg1tcenDett7H52lBaFXY6HfGU28JSHcJxMpljDVAISg MMzHrQrD9IJyMbS1IEGDvZa9MhKFQrPp1yVtg1QpuRAdg6cQZND1uBOOefVfYCHdu1v KlXZTya6E5CVDpYu/axoP7Ys5MXV7nqk84QkuD/M= Received: by smtp.zohomail.com with SMTPS id 1790005932561371.5890654858862; Mon, 21 Sep 2026 08:52:12 -0700 (PDT) From: Nicolas Frattaroli Date: Mon, 21 Sep 2026 17:51:28 +0200 Subject: [PATCH RFC 02/25] drm: Add VRR state Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260921-vrr-limiter-uapi-v1-2-2fcd7d011646@collabora.com> References: <20260921-vrr-limiter-uapi-v1-0-2fcd7d011646@collabora.com> In-Reply-To: <20260921-vrr-limiter-uapi-v1-0-2fcd7d011646@collabora.com> To: "Borah, Chaitanya Kumar" , Leo Li , Daniel Stone , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Helge Deller , Andrzej Hajda , Neil Armstrong , Robert Foss , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Luca Ceresoli , Sandy Huang , =?utf-8?q?Heiko_St=C3=BCbner?= , Andy Yan Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, linux-fbdev@vger.kernel.org, linux-rockchip@lists.infradead.org, linux-arm-kernel@lists.infradead.org, kernel@collabora.com, Derek Foreman , wayland-devel@lists.freedesktop.org, Nicolas Frattaroli X-Mailer: b4 0.15.2 Add preliminary state tracking for VRR, and VRR state validation. This will be used for generating VTEM infoframes in order to support variable refresh rate functionality. Co-developed-by: Derek Foreman Signed-off-by: Derek Foreman Signed-off-by: Nicolas Frattaroli --- drivers/gpu/drm/display/drm_hdmi_state_helper.c | 227 ++++++++++++++++++++= ++++ include/drm/drm_crtc.h | 11 ++ 2 files changed, 238 insertions(+) diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/= drm/display/drm_hdmi_state_helper.c index 7cdb7ca3dc12..d55548399687 100644 --- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c +++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c @@ -887,6 +887,229 @@ hdmi_generate_infoframes(const struct drm_connector *= connector, return 0; } =20 +/** + * cmp_fraction - compares two fractional numbers + * @a: numerator of the first fraction + * @b: denominator of the first fraction + * @c: numerator of the second fraction + * @d: denominator of the second fraction + * + * Compare fractional expression given by @a divided by @b with fractional + * expression given by @c divided by @d, without running into rounding iss= ues. + * + * Neither @b nor @d should be 0. + * + * Returns: + * - %1 if @a / @b > @c / @d + * - %-1 if @a / @b < @c / @d + * - %0 if @a / @b =3D=3D @c / @d + * - %-EDOM if @b is zero or @d is zero. + */ +static int cmp_fraction(u32 a, u32 b, u32 c, u32 d) +{ + u64 a_d =3D mul_u32_u32(a, d); + u64 b_c =3D mul_u32_u32(b, c); + + if (WARN_ON(!b || !d)) + return -EDOM; + + /* a/b > c/d */ + if (a_d > b_c) + return 1; + + /* a/b < c/d */ + if (a_d < b_c) + return -1; + + /* a/b =3D=3D c/d */ + return 0; +} + +static int hdmi_calculate_vtotal(const struct drm_display_mode *mode, + u32 rate_n, u32 rate_d, u16 *out_vtotal, + u32 *out_denom, u32 *out_frame_err) +{ + u32 denom, result, err; + u64 numerator; + + /* + * We perform VRR based rate limiting by adjusting the vertical front + * porch. We do that by picking a new Vtotal to pass to the hardware, + * which extends the display period. Since we can change no other + * timings, this rarely results in a perfect integer match to the + * target framerate. However, we would like to correct for this error + * using only integer math. + * + * For a given refresh rate: + * + * Vtotal =3D clock + * ---------------------------------- + * Htotal * target_refresh + * + * We specify target_refresh as a ratio, because the possible target + * framerates include rates like 23.97... that are actually 24 / 1.001, + * or 24000 / 1001. + * + * clock + * Vtotal =3D ---------------------------------- + * Htotal * target_n / target_d + * + * Some algebra brings us to: + * + * clock * target_n + * Vtotal =3D ---------------------------------- + * Htotal * rate_n + * + * The amount of timing error we accumulate every frame will be + * the remainder of that division. + * + * We store the remainder for later. Every frame we add the remainder + * to an accumulator, and when the accumulator exceeds the denominator, + * one Htotal worth of error has accumulated. + * + * In practice, as soon as the accumulated error exceeds half the + * denominator, it is dithered across frames by temporarily extending + * Vtotal by a single row on that frame. + */ + + if (check_mul_overflow(mode->crtc_htotal, rate_n, &denom)) + return -ERANGE; + + if (check_mul_overflow(mode->crtc_clock * 1000ULL, rate_d, &numerator)) + return -ERANGE; + + result =3D div_u64_rem(numerator, denom, &err); + if (result > U16_MAX) + return -ERANGE; + + if (out_vtotal) + *out_vtotal =3D result; + if (out_denom) + *out_denom =3D denom; + if (out_frame_err) + *out_frame_err =3D err; + + return 0; +} + +static int hdmi_validate_vrr(struct drm_connector *connector, + struct drm_atomic_commit *state) +{ + struct drm_connector_state *new_conn_state =3D + drm_atomic_get_new_connector_state(state, connector); + struct drm_crtc_state *new_crtc_state =3D + drm_atomic_get_new_crtc_state(state, new_conn_state->crtc); + struct drm_crtc_state *old_crtc_state =3D + drm_atomic_get_old_crtc_state(state, new_conn_state->crtc); + struct drm_crtc_vrr_state *vrr_state =3D + &new_crtc_state->vrr_state; + struct drm_crtc_vrr_state *old_vrr_state =3D + &old_crtc_state->vrr_state; + struct drm_display_info *info =3D &connector->display_info; + const struct drm_display_mode *mode =3D &new_crtc_state->mode; + struct drm_device *dev =3D connector->dev; + int mode_refresh, vfront, ret; + u32 min_vfreq_n =3D info->monitor_range.min_vfreq; + u32 min_vfreq_d =3D 1; + u32 max_vfreq_n =3D info->monitor_range.max_vfreq; + u32 max_vfreq_d =3D 1; + + /* Save on the expensive vic lookup, if nothing else. */ + if (!new_crtc_state->mode_changed && + old_crtc_state->vrr_enabled && + old_vrr_state->vrr_min_n =3D=3D vrr_state->vrr_min_n && + old_vrr_state->vrr_min_d =3D=3D vrr_state->vrr_min_d && + old_vrr_state->vrr_max_n =3D=3D vrr_state->vrr_max_n && + old_vrr_state->vrr_max_d =3D=3D vrr_state->vrr_max_d && + info->hdmi.vrr_capable) { + memcpy(vrr_state, old_vrr_state, sizeof(*vrr_state)); + vrr_state->dynamic =3D false; + return 0; + } + + if (!new_crtc_state->vrr_enabled) + return 0; + + if (!info->hdmi.vrr_capable) + return -EOPNOTSUPP; + + mode_refresh =3D drm_mode_vrefresh(mode); + + /* HDMI uses 10 bits to signal the base refresh. */ + if (mode_refresh < 0 || mode_refresh > 1023) { + drm_dbg_kms(dev, "Mode's refresh of %dHz > HDMI VRR maximum (1023)\n", + mode_refresh); + return -EINVAL; + } + + if (!max_vfreq_n || max_vfreq_n > mode_refresh) + max_vfreq_n =3D mode_refresh; + + if (!min_vfreq_n) { + drm_dbg_kms(dev, "Could not get minimum VRR rate from sink\n"); + return -EINVAL; + } + + vfront =3D mode->crtc_vsync_start - mode->crtc_vdisplay; + if (vfront < 0 || vfront > U8_MAX) { + drm_dbg_kms(dev, "Vfront of %d would not fit in VTEM packet\n", vfront); + return -EINVAL; + } + + vrr_state->vic =3D drm_match_cea_mode(mode); + + if (cmp_fraction(min_vfreq_n, min_vfreq_d, max_vfreq_n, max_vfreq_d) > 0)= { + drm_dbg_kms(dev, "Target max (%u/%u) > target min (%u/%u)\n", + max_vfreq_n, max_vfreq_d, min_vfreq_n, min_vfreq_d); + return -EINVAL; + } + + ret =3D hdmi_calculate_vtotal(mode, max_vfreq_n, max_vfreq_d, + &vrr_state->base_vtotal, NULL, NULL); + if (ret) { + drm_dbg_kms(dev, "Couldn't calculate base_vtotal: %pe\n", ERR_PTR(ret)); + return ret; + } + + /* + * Even at its fastest, it can't go faster than the mode, so + * clamp to avoid imprecisely rounded mode_refresh values we + * can't do anything about from ruining our day. + */ + vrr_state->base_vtotal =3D max(vrr_state->base_vtotal, mode->crtc_vtotal); + + if (cmp_fraction(min_vfreq_n, min_vfreq_d, mode_refresh, 1) >=3D 0) { + /* refresh <=3D VRR min, don't do VRR vtotal adjustment */ + vrr_state->max_vtotal =3D mode->crtc_vtotal; + } else { + /* + * Allow additional front porch until effective rate =3D=3D VRR min + * In essence, this is mode->vtotal * mode_refresh / min_vfreq + * but the relevant factors factored out from drm_mode_vrefresh() + * to avoid working with rounded values, as well as using the + * hardware adjusted crtc_* values instead. + */ + ret =3D hdmi_calculate_vtotal(mode, min_vfreq_n, min_vfreq_d, + &vrr_state->max_vtotal, NULL, NULL); + if (ret) { + drm_dbg_kms(dev, "Couldn't calculate max_vtotal: %pe\n", ERR_PTR(ret)); + return ret; + } + + if (vrr_state->max_vtotal < mode->crtc_vtotal) { + drm_dbg_kms(dev, "max_vtotal=3D%u < crtc_vtotal=3D%u\n", + vrr_state->max_vtotal, mode->crtc_vtotal); + return -EINVAL; + } + } + + drm_dbg_kms(dev, "VRR has base_vtotal=3D%u max_vtotal=3D%u from %u/%uHz <= =3D rate <=3D %u/%uHz\n", + vrr_state->base_vtotal, vrr_state->max_vtotal, min_vfreq_n, + min_vfreq_d, max_vfreq_n, max_vfreq_d); + + return 0; +} + /** * drm_atomic_helper_connector_hdmi_check() - Helper to check HDMI connect= or atomic state * @connector: DRM Connector @@ -919,6 +1142,10 @@ int drm_atomic_helper_connector_hdmi_check(struct drm= _connector *connector, =20 new_conn_state->hdmi.is_limited_range =3D hdmi_is_limited_range(connector= , new_conn_state); =20 + ret =3D hdmi_validate_vrr(connector, state); + if (ret) + return ret; + ret =3D hdmi_generate_infoframes(connector, new_conn_state); if (ret) return ret; diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index be5dca538d87..9d58158af459 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -63,6 +63,14 @@ struct drm_atomic_commit; struct drm_crtc_helper_funcs; struct drm_plane_helper_funcs; =20 +struct drm_crtc_vrr_state { + u8 vic; + u16 cur_vtotal; + u16 max_vtotal; + u16 base_vtotal; + bool dynamic; +}; + /** * struct drm_crtc_state - mutable CRTC state * @@ -397,6 +405,9 @@ struct drm_crtc_state { */ struct drm_pending_vblank_event *event; =20 + /** @vrr_state: State related to variable refresh rate. */ + struct drm_crtc_vrr_state vrr_state; + /** * @commit: * --=20 2.55.0 From nobody Fri Sep 25 21:02:41 2026 Received: from sender4-pp-f112.zoho.com (sender4-pp-f112.zoho.com [136.143.188.112]) (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 0BA4B4C1515; Mon, 21 Sep 2026 15:53:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=136.143.188.112 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790005999; cv=pass; b=LP/zImgL4OesseytXtggH5hvThojgPvOMQS1ntfgpkhWztRNxW0YxGDVnUVPkC6pUaMERNKOcLzry6YnkPSD0++QxzBPaD6xXQuMfG2CK5LBdfn58VZGwAuO+CnQNH3cSwdpVdliV1TKpB4BFjMNWBctLfB+hAtyLHZRw68HYLQ= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790005999; c=relaxed/simple; bh=TBPexhzayAdH9jIT5ry4w25OQZ3HIU4oyIxANtSCtg8=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=UoIuYVB9PjLzLXqz7kP696DdZtF1LgCfD5ynUqKwA/tFBFOhr8v/UXLcJ3qjAhCRmx68usUStVVOtZ1fscw0rtBgh4HdZDBIU2AgB7JkU+gQKbLS/qN9Vm6E7qYTQNyD1FMkFrV7WamT7VniUMqQGwGg8lLZguLz1OW1n2Ry8jw= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (1024-bit key) header.d=collabora.com header.i=nicolas.frattaroli@collabora.com header.b=VEQ3WRT9; arc=pass smtp.client-ip=136.143.188.112 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=collabora.com header.i=nicolas.frattaroli@collabora.com header.b="VEQ3WRT9" ARC-Seal: i=1; a=rsa-sha256; t=1790005939; cv=none; d=zohomail.com; s=zohoarc; b=dL8QWo0f+z20HLw9HXd7aGFStuR/k/6l/FzgRHplWzXjfpgtJuClsAOR1DZ512xYHu8NCCcCazC2nApnrzpzPNhdvceP+z1X78p38mpx60wgUMZkUI/Ao4mFSgQSZWorMd1ffR8UsjM1jflS2DFrKLxXRt8gVLx0LlB0uhVfp8U= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1790005939; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:MIME-Version:Message-ID:Subject:Subject:To:To:Message-Id:Reply-To; bh=hVfhbzvE6GURebcBrX2O4AYlNWe76f6ylBqD+StMY7g=; b=HJFIqM47xYTMuV3pj9MXTVTK4CKFU/hv8W2mvG3UieaVb+Aop621PPBOBihh5WJDCUee+UI0PKD4Gv+dDnq8qmUosBaFflQN+2gn0bkgxMK+bpL9G6r40GTtnFb5uxzfQKdVT490HXiNrokbN+diPmvlgRv9vnVIZdseXXec0h8= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass header.i=collabora.com; spf=pass smtp.mailfrom=nicolas.frattaroli@collabora.com; dmarc=pass header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1790005939; s=zohomail; d=collabora.com; i=nicolas.frattaroli@collabora.com; h=From:From:Date:Date:Subject:Subject:MIME-Version:Content-Type:Content-Transfer-Encoding:Message-Id:Message-Id:In-Reply-To:To:To:Cc:Cc:Reply-To; bh=hVfhbzvE6GURebcBrX2O4AYlNWe76f6ylBqD+StMY7g=; b=VEQ3WRT9ZruGE+auQHYNi5JDxIAHiWLc38gvCVDu8IEpeZkhjV7guYnBbNvapKlB kuVL8L0Gg64ALMxnI3i58j7hSNJD8ia9h5AwssgPQFL5iEcXmYjvii55IRXKLDqb4Mb eUk+zgTbkKwFy7EiaiQoctyHlhWRtM0LJzTWf/Vg= Received: by smtp.zohomail.com with SMTPS id 1790005938404198.15695800259266; Mon, 21 Sep 2026 08:52:18 -0700 (PDT) From: Nicolas Frattaroli Date: Mon, 21 Sep 2026 17:51:29 +0200 Subject: [PATCH RFC 03/25] drm/atomic-helper: Set mode_changed on vrr_enabled change Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260921-vrr-limiter-uapi-v1-3-2fcd7d011646@collabora.com> References: <20260921-vrr-limiter-uapi-v1-0-2fcd7d011646@collabora.com> In-Reply-To: <20260921-vrr-limiter-uapi-v1-0-2fcd7d011646@collabora.com> To: "Borah, Chaitanya Kumar" , Leo Li , Daniel Stone , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Helge Deller , Andrzej Hajda , Neil Armstrong , Robert Foss , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Luca Ceresoli , Sandy Huang , =?utf-8?q?Heiko_St=C3=BCbner?= , Andy Yan Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, linux-fbdev@vger.kernel.org, linux-rockchip@lists.infradead.org, linux-arm-kernel@lists.infradead.org, kernel@collabora.com, Derek Foreman , wayland-devel@lists.freedesktop.org, Nicolas Frattaroli X-Mailer: b4 0.15.2 A change in whether VRR is enabled or not on a CRTC will be of interest to any VRR implementation, as they may need to recalculate certain internal state in response. So far, this was handled ad-hoc in the drivers that implement VRR. Handle this in the common DRM atomic core by setting the mode_changed flag when this occurs. The rationale for using mode_changed is that VRR is deeply intertwined with the current mode with regards to its timing. Consequently, any component that cares about a mode change is likely also going to care about VRR being enabled/disabled. Signed-off-by: Nicolas Frattaroli --- drivers/gpu/drm/drm_atomic_helper.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atom= ic_helper.c index 9d006f98413a..0664d5779282 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -694,6 +694,12 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, new_crtc_state->active_changed =3D true; } =20 + if (old_crtc_state->vrr_enabled !=3D new_crtc_state->vrr_enabled) { + drm_dbg_atomic(dev, "[CRTC:%d:%s] VRR changed\n", + crtc->base.id, crtc->name); + new_crtc_state->mode_changed =3D true; + } + if (new_crtc_state->enable !=3D has_connectors) { drm_dbg_atomic(dev, "[CRTC:%d:%s] enabled/connectors mismatch (%d/%d)\n= ", crtc->base.id, crtc->name, --=20 2.55.0 From nobody Fri Sep 25 21:02:41 2026 Received: from sender4-pp-f112.zoho.com (sender4-pp-f112.zoho.com [136.143.188.112]) (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 9CB1C4C10DF; Mon, 21 Sep 2026 15:53:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=136.143.188.112 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790005995; cv=pass; b=hNxmy8QSlvI4c9yB3+6mOtNBYmDnQXcMPwaxKVQjUforQMeU9Qkzfmw1UF9JynZZmEdLvVVxqSagvJnAWQ483st9h4m5Ls+R9CjleYx3twLqtQ3St/3Z87spnSHCWorvv8NWmv8+t8GXqGVknAW+6/yekqfG3MCllcf4Yo7Yhs8= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790005995; c=relaxed/simple; bh=BmCd6Sw/G9OOGOwOlBAzlWvGU8fxLplwZZMTJLJxLXU=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=YbjAKmRT2QwsNf6rlFMjCjU+u+DfUOD2smD3T1gUO5j60Kav7Mlb2lqu4xzTALzN2b0EGxT9/wiH2RuiZ8LM/PVjEgAQptI0hBe3Nc5TuOTVlh9Dd46kvfMTx6YO1XxRb7zyz26FpRJPc83SLxlID80I901dCOhtyGqARVZNijE= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (1024-bit key) header.d=collabora.com header.i=nicolas.frattaroli@collabora.com header.b=SqzMjGGz; arc=pass smtp.client-ip=136.143.188.112 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=collabora.com header.i=nicolas.frattaroli@collabora.com header.b="SqzMjGGz" ARC-Seal: i=1; a=rsa-sha256; t=1790005945; cv=none; d=zohomail.com; s=zohoarc; b=ljSNHs+y51ZZ4z/4x1pAepFaDbtFfHOtzS1eiQpDlDrLHxu0AKYd63k6/1MeeuoiNUQ2t/KSAUMhoedmb7ZoMJ2g3Px1KUD+7FVG/tRqQuR3FIY/uA5HJZpXpgMY+SA9pvvQRq9QMeY/urRpAzxgdB+Qne3cfdpJqmOE4L8T6ME= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1790005945; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:MIME-Version:Message-ID:Subject:Subject:To:To:Message-Id:Reply-To; bh=DiwDpN9riDDJQcO6V+hK0OwAgWXYH5bbcn0W29vlIso=; b=BMXp3pZ6gKVvowjbqMV9mALWOTrErIUMJZZbGQnfHRueiBNQXy4wcfJPl+PGBfDo4XJ2Pc6lrGGaixVBLHCXyuJ/Z1d0M9HryzRPcG78oqcpZ0GULkFX/fGch3sXdcB8rCNfqsJPk1mYYJX5kbHWyU0+YGYbeirqi+fdzXqRk0E= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass header.i=collabora.com; spf=pass smtp.mailfrom=nicolas.frattaroli@collabora.com; dmarc=pass header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1790005945; s=zohomail; d=collabora.com; i=nicolas.frattaroli@collabora.com; h=From:From:Date:Date:Subject:Subject:MIME-Version:Content-Type:Content-Transfer-Encoding:Message-Id:Message-Id:In-Reply-To:To:To:Cc:Cc:Reply-To; bh=DiwDpN9riDDJQcO6V+hK0OwAgWXYH5bbcn0W29vlIso=; b=SqzMjGGzJwUZ+VXI+7o8MgXBG1T1uWWFdvKtVqJPV1dDBuFmhnaNntTU9ggZGT+8 2Ds2KflAFHbrlmAnMeD67vFy9mlTbU228CCkIe62ZYILaYuREeGgHZ49Nsq1vsSJJGt YEA5V0xGGS1wLD+a2fxY39D/E7enNUtjIcWTcpZI= Received: by smtp.zohomail.com with SMTPS id 179000594398149.12293130246803; Mon, 21 Sep 2026 08:52:23 -0700 (PDT) From: Nicolas Frattaroli Date: Mon, 21 Sep 2026 17:51:30 +0200 Subject: [PATCH RFC 04/25] video/hdmi: Add VTEM EMP packing Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260921-vrr-limiter-uapi-v1-4-2fcd7d011646@collabora.com> References: <20260921-vrr-limiter-uapi-v1-0-2fcd7d011646@collabora.com> In-Reply-To: <20260921-vrr-limiter-uapi-v1-0-2fcd7d011646@collabora.com> To: "Borah, Chaitanya Kumar" , Leo Li , Daniel Stone , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Helge Deller , Andrzej Hajda , Neil Armstrong , Robert Foss , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Luca Ceresoli , Sandy Huang , =?utf-8?q?Heiko_St=C3=BCbner?= , Andy Yan Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, linux-fbdev@vger.kernel.org, linux-rockchip@lists.infradead.org, linux-arm-kernel@lists.infradead.org, kernel@collabora.com, Derek Foreman , wayland-devel@lists.freedesktop.org, Nicolas Frattaroli X-Mailer: b4 0.15.2 From: Derek Foreman VTEM EMPs are a type of infoframe that is required for Variable Refresh Rate. Add code to pack them. Signed-off-by: Derek Foreman Signed-off-by: Nicolas Frattaroli --- drivers/video/hdmi.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++= +++- include/linux/hdmi.h | 19 ++++++++++ 2 files changed, 115 insertions(+), 1 deletion(-) diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c index 45b42f14a750..ed9abc7ad228 100644 --- a/drivers/video/hdmi.c +++ b/drivers/video/hdmi.c @@ -983,6 +983,10 @@ hdmi_infoframe_pack(union hdmi_infoframe *frame, length =3D hdmi_vendor_any_infoframe_pack(&frame->vendor, buffer, size); break; + case HDMI_INFOFRAME_TYPE_EMP: + length =3D hdmi_emp_infoframe_vtem_pack(&frame->vtem, + buffer, size); + break; default: WARN(1, "Bad infoframe type %d\n", frame->any.type); length =3D -EINVAL; @@ -994,9 +998,11 @@ EXPORT_SYMBOL(hdmi_infoframe_pack); =20 static const char *hdmi_infoframe_type_get_name(enum hdmi_infoframe_type t= ype) { - if (type < 0x80 || type > 0x9f) + if (type < 0x7F || type > 0x9f) return "Invalid"; switch (type) { + case HDMI_INFOFRAME_TYPE_EMP: + return "EMP"; case HDMI_INFOFRAME_TYPE_VENDOR: return "Vendor"; case HDMI_INFOFRAME_TYPE_AVI: @@ -1516,6 +1522,29 @@ hdmi_vendor_any_infoframe_log(const char *level, } } =20 +static void +hdmi_emp_infoframe_vtem_log(const char *level, + struct device *dev, + const struct hdmi_emp_infoframe_vtem *frame) +{ + hdmi_infoframe_log_header(level, dev, + (const struct hdmi_any_infoframe *)frame); + + hdmi_log(" game vrr enabled: %u\n", frame->game_vrr_en); + hdmi_log(" fva factor minus 1: %u\n", frame->fva_factor_m1); + hdmi_log(" m_const: %u\n", frame->m_const); + hdmi_log(" base vertical front porch: %u\n", frame->base_vfront); + hdmi_log(" base refresh rate: %u\n", frame->base_refresh_rate); +} + +static void +hdmi_emp_infoframe_log(const char *level, + struct device *dev, + const union hdmi_infoframe *frame) +{ + /* Only support VTEM for now */ + hdmi_emp_infoframe_vtem_log(level, dev, &frame->vtem); +} /** * hdmi_infoframe_log() - log info of HDMI infoframe * @level: logging level @@ -1542,6 +1571,9 @@ void hdmi_infoframe_log(const char *level, case HDMI_INFOFRAME_TYPE_DRM: hdmi_drm_infoframe_log(level, dev, &frame->drm); break; + case HDMI_INFOFRAME_TYPE_EMP: + hdmi_emp_infoframe_log(level, dev, frame); + break; } } EXPORT_SYMBOL(hdmi_infoframe_log); @@ -1919,3 +1951,66 @@ int hdmi_infoframe_unpack(union hdmi_infoframe *fram= e, return ret; } EXPORT_SYMBOL(hdmi_infoframe_unpack); + +/** + * hdmi_emp_infoframe_vtem_init() - initialize an HDMI VTEM EMP + * @emp: HDMI VTEM EMP + */ +void hdmi_emp_infoframe_vtem_init(struct hdmi_emp_infoframe_vtem *emp) +{ + memset(emp, 0, sizeof(*emp)); + emp->type =3D HDMI_INFOFRAME_TYPE_EMP; +} +EXPORT_SYMBOL(hdmi_emp_infoframe_vtem_init); + +/** + * hdmi_emp_infoframe_vtem_pack() - pack a vtem into a binary buffer + * @vtem: pointer to &struct hdmi_emp_infoframe_vtem to pack + * @buffer: pointer to pre-allocated output buffer + * @size: maximum size in bytes of @buffer + * + * Pack a VTEM infoframe struct into a binary buffer in a way that's suita= ble + * to be sent out over the wire. + * + * Returns the number of bytes packed into the binary buffer or a negative + * error code on failure. + */ +ssize_t hdmi_emp_infoframe_vtem_pack(struct hdmi_emp_infoframe_vtem *vtem, + void *buffer, size_t size) +{ + u8 *ptr =3D buffer; + + if (size < HDMI_INFOFRAME_SIZE(VTEM)) + return -EINVAL; + + /* 4 bits max */ + if (vtem->fva_factor_m1 > 0xF) + return -EINVAL; + + memset(buffer, 0, size); + + /* Header Data */ + ptr[0] =3D vtem->type; + ptr[1] =3D BIT(7) | BIT(6); + ptr[2] =3D 0; + + ptr[3] =3D BIT(7) | BIT(2); + + ptr[4] =3D 0; + ptr[5] =3D 1; + ptr[6] =3D 0; + ptr[7] =3D 1; + ptr[8] =3D 0; + ptr[9] =3D 4; + + /* This is where the VTEM part starts */ + ptr[10] =3D (vtem->fva_factor_m1 << 4) | + (vtem->m_const ? BIT(1) : 0) | + (vtem->game_vrr_en ? BIT(0) : 0); + ptr[11] =3D vtem->base_vfront; + ptr[12] =3D vtem->base_refresh_rate >> 8 & 0x3; + ptr[13] =3D vtem->base_refresh_rate & 0xFF; + + return 14; +} +EXPORT_SYMBOL(hdmi_emp_infoframe_vtem_pack); diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h index b80a5ee63bb2..71e2b36896af 100644 --- a/include/linux/hdmi.h +++ b/include/linux/hdmi.h @@ -55,6 +55,7 @@ enum hdmi_packet_type { }; =20 enum hdmi_infoframe_type { + HDMI_INFOFRAME_TYPE_EMP =3D 0x7F, HDMI_INFOFRAME_TYPE_VENDOR =3D 0x81, HDMI_INFOFRAME_TYPE_AVI =3D 0x82, HDMI_INFOFRAME_TYPE_SPD =3D 0x83, @@ -76,6 +77,7 @@ enum hdmi_infoframe_type { #define HDMI_AUDIO_INFOFRAME_SIZE 10 #define HDMI_DRM_INFOFRAME_SIZE 26 #define HDMI_VENDOR_INFOFRAME_SIZE 4 +#define HDMI_VTEM_INFOFRAME_SIZE 10 =20 /* * HDMI 1.3a table 5-14 states that the largest InfoFrame_length is 27, @@ -235,6 +237,18 @@ struct hdmi_drm_infoframe { u16 max_fall; }; =20 +struct hdmi_emp_infoframe_vtem { + enum hdmi_infoframe_type type; + unsigned char version; + unsigned char length; + + bool game_vrr_en; + bool m_const; + unsigned char fva_factor_m1; + unsigned char base_vfront; + u16 base_refresh_rate; +}; + void hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame); ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *bu= ffer, size_t size); @@ -249,6 +263,10 @@ ssize_t hdmi_drm_infoframe_pack_only(const struct hdmi= _drm_infoframe *frame, int hdmi_drm_infoframe_check(struct hdmi_drm_infoframe *frame); int hdmi_drm_infoframe_unpack_only(struct hdmi_drm_infoframe *frame, const void *buffer, size_t size); +void hdmi_emp_infoframe_vtem_init(struct hdmi_emp_infoframe_vtem *frame); +ssize_t hdmi_emp_infoframe_vtem_pack(struct hdmi_emp_infoframe_vtem *frame, + void *buffer, + size_t size); =20 enum hdmi_spd_sdi { HDMI_SPD_SDI_UNKNOWN, @@ -457,6 +475,7 @@ union hdmi_infoframe { union hdmi_vendor_any_infoframe vendor; struct hdmi_audio_infoframe audio; struct hdmi_drm_infoframe drm; + struct hdmi_emp_infoframe_vtem vtem; }; =20 ssize_t hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, --=20 2.55.0 From nobody Fri Sep 25 21:02:41 2026 Received: from sender4-pp-f112.zoho.com (sender4-pp-f112.zoho.com [136.143.188.112]) (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 06E4A4BD366; Mon, 21 Sep 2026 15:53:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=136.143.188.112 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790005998; cv=pass; b=oeCuUM7Vs+QwaV3oD/1+hq+ZJjUB2qp3Iq662QNaQcaQ9qZTY8E94/ZYWif7FS3caHgilcWtCl1S4KWW9/qSdEUZ+2MJWgMj2kYpIygjskFojqDfuxJF1nvZdpZ2zOWyYxwRIerfGxY634cqmqQMw32LLmTnBMh19he6pGXinuk= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790005998; c=relaxed/simple; bh=PVwmAzt9UOSomrJzODsMy/tXZYNwc2/OR/5WOAK5PIs=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=OZyXJcdiS/3psfYuG+bWHPumO1/S1i4yRWqz9maFccs6GzJ0a6LWSfVCd34WMJg5PYk8+LDzIpFym6Rk7VCWoqg1QIKlvUxD9MuGAgZb7gQgMBZm7U8cmfSbmNQdik4vUNirK2oY4YdiykunNDo+LSX4jTNxGI+BQej8GvKFNFw= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (1024-bit key) header.d=collabora.com header.i=nicolas.frattaroli@collabora.com header.b=GB3YC3I9; arc=pass smtp.client-ip=136.143.188.112 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=collabora.com header.i=nicolas.frattaroli@collabora.com header.b="GB3YC3I9" ARC-Seal: i=1; a=rsa-sha256; t=1790005951; cv=none; d=zohomail.com; s=zohoarc; b=hJuEk/WXya3YSJ7LhRNDAFC1MHk9GtJeimnQ9ZLklDsPCi5INcsGyqoU7YgcuhI7RBUxaXaqlJ3LHlPHmnGCWeM2uwgW/mECm/ln4HEUwduM+kC1fbuy3Pgn+oLskBhtNTPSeuARsQ4ndvdFDYRHoaTWOPPgYBNmob8yO5dSGt0= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1790005951; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:MIME-Version:Message-ID:Subject:Subject:To:To:Message-Id:Reply-To; bh=CnFGpLHNPi3LH+koDqB85QbgcIXof8AnqDGa7CUOj4Y=; b=XRyI1gaI3qZ5mlYUnApgcWa77UECg29xCk/fMKtOFf6Rhhb/vnzuer+HUkTMk/PBB8cKMd6bKYvZ61ymabJ6HDBQ6XP9XiuTEhHUDkkfAvxgll9m1KxpH8Nm4TNRAiKCU2MjH9KDlinUTxB0Wp9QJJz6Z6le5U3fpUz3uiFuZxk= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass header.i=collabora.com; spf=pass smtp.mailfrom=nicolas.frattaroli@collabora.com; dmarc=pass header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1790005951; s=zohomail; d=collabora.com; i=nicolas.frattaroli@collabora.com; h=From:From:Date:Date:Subject:Subject:MIME-Version:Content-Type:Content-Transfer-Encoding:Message-Id:Message-Id:In-Reply-To:To:To:Cc:Cc:Reply-To; bh=CnFGpLHNPi3LH+koDqB85QbgcIXof8AnqDGa7CUOj4Y=; b=GB3YC3I9oUKWLc+A3JSbQ48WwIo5d3RbvksvfstgfXM1HSWAKqCwNK0rCMBOL4Gw TsY1K2CHvLXJ3mb9hg3MUwGK9dxRvZDh630zLevo5MT5M2VAWLhqC7YpdNH3V4G/5GJ 0DwfxoFydSyH/9Jwtr5kFfxj/gSbxl5zTPT1LNqA= Received: by smtp.zohomail.com with SMTPS id 1790005949614805.1464665003713; Mon, 21 Sep 2026 08:52:29 -0700 (PDT) From: Nicolas Frattaroli Date: Mon, 21 Sep 2026 17:51:31 +0200 Subject: [PATCH RFC 05/25] drm/bridge: Add VTEM EMP support Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260921-vrr-limiter-uapi-v1-5-2fcd7d011646@collabora.com> References: <20260921-vrr-limiter-uapi-v1-0-2fcd7d011646@collabora.com> In-Reply-To: <20260921-vrr-limiter-uapi-v1-0-2fcd7d011646@collabora.com> To: "Borah, Chaitanya Kumar" , Leo Li , Daniel Stone , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Helge Deller , Andrzej Hajda , Neil Armstrong , Robert Foss , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Luca Ceresoli , Sandy Huang , =?utf-8?q?Heiko_St=C3=BCbner?= , Andy Yan Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, linux-fbdev@vger.kernel.org, linux-rockchip@lists.infradead.org, linux-arm-kernel@lists.infradead.org, kernel@collabora.com, Derek Foreman , wayland-devel@lists.freedesktop.org, Nicolas Frattaroli X-Mailer: b4 0.15.2 From: Derek Foreman Add setters and support bit for VTEM emp to the bridge. Signed-off-by: Derek Foreman --- drivers/gpu/drm/display/drm_bridge_connector.c | 41 ++++++++++++++++++++++= ++++ include/drm/drm_bridge.h | 29 ++++++++++++++++++ include/drm/drm_connector.h | 8 +++++ 3 files changed, 78 insertions(+) diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/d= rm/display/drm_bridge_connector.c index 707d7143e475..dc814dbb5120 100644 --- a/drivers/gpu/drm/display/drm_bridge_connector.c +++ b/drivers/gpu/drm/display/drm_bridge_connector.c @@ -610,6 +610,33 @@ static int drm_bridge_connector_scrambler_disable(stru= ct drm_connector *connecto return bridge->funcs->hdmi_scrambler_disable(bridge); } =20 +static int drm_bridge_connector_clear_vtem_emp(struct drm_connector *conne= ctor) +{ + struct drm_bridge_connector *bridge_connector =3D + to_drm_bridge_connector(connector); + struct drm_bridge *bridge; + + bridge =3D bridge_connector->bridge_hdmi; + if (!bridge) + return -EINVAL; + + return bridge->funcs->hdmi_clear_vtem_emp(bridge); +} + +static int drm_bridge_connector_write_vtem_emp(struct drm_connector *conne= ctor, + const u8 *buffer, size_t len) +{ + struct drm_bridge_connector *bridge_connector =3D + to_drm_bridge_connector(connector); + struct drm_bridge *bridge; + + bridge =3D bridge_connector->bridge_hdmi; + if (!bridge) + return -EINVAL; + + return bridge->funcs->hdmi_write_vtem_emp(bridge, buffer, len); +} + static const struct drm_edid * drm_bridge_connector_read_edid(struct drm_connector *connector) { @@ -655,6 +682,11 @@ static const struct drm_connector_infoframe_funcs drm_= bridge_connector_hdmi_spd_ .write_infoframe =3D drm_bridge_connector_write_spd_infoframe, }; =20 +static const struct drm_connector_infoframe_funcs drm_bridge_connector_hdm= i_vtem_emp =3D { + .clear_infoframe =3D drm_bridge_connector_clear_vtem_emp, + .write_infoframe =3D drm_bridge_connector_write_vtem_emp, +}; + static int drm_bridge_connector_audio_startup(struct drm_connector *connec= tor) { struct drm_bridge_connector *bridge_connector =3D @@ -946,6 +978,11 @@ struct drm_connector *drm_bridge_connector_init(struct= drm_device *drm, !bridge->funcs->hdmi_scrambler_disable)) return ERR_PTR(-EINVAL); =20 + if (bridge->ops & DRM_BRIDGE_OP_HDMI_VTEM_EMP && + (!bridge->funcs->hdmi_write_vtem_emp || + !bridge->funcs->hdmi_clear_vtem_emp)) + return ERR_PTR(-EINVAL); + bridge_connector->bridge_hdmi =3D drm_bridge_get(bridge); } =20 @@ -1072,6 +1109,10 @@ struct drm_connector *drm_bridge_connector_init(stru= ct drm_device *drm, drm_bridge_connector_scrambler_disable; } =20 + if (bridge_connector->bridge_hdmi->ops & DRM_BRIDGE_OP_HDMI_VTEM_EMP) + bridge_connector->hdmi_funcs.vtem =3D + drm_bridge_connector_hdmi_vtem_emp; + ret =3D drmm_connector_hdmi_init(drm, connector, &drm_bridge_connector_funcs, &bridge_connector->hdmi_funcs, diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h index 77b3ffe69230..9dbd1bfa39af 100644 --- a/include/drm/drm_bridge.h +++ b/include/drm/drm_bridge.h @@ -684,6 +684,29 @@ struct drm_bridge_funcs { int (*hdmi_write_spd_infoframe)(struct drm_bridge *bridge, const u8 *buffer, size_t len); =20 + /** + * @hdmi_clear_vtem_emp: + * + * This callback clears the emp in the hardware during commit. + * + * This callback is optional but it must be implemented by bridges that + * set the DRM_BRIDGE_OP_HDMI_VTEM_EMP flag in their + * &drm_bridge->ops. + */ + int (*hdmi_clear_vtem_emp)(struct drm_bridge *bridge); + + /** + * @hdmi_write_spd_infoframe: + * + * Program the emp into the hardware. + * + * This callback is optional but it must be implemented by bridges that + * set the DRM_BRIDGE_OP_HDMI_VTEM_EMP flag in their + * &drm_bridge->ops. + */ + int (*hdmi_write_vtem_emp)(struct drm_bridge *bridge, + const u8 *buffer, size_t len); + /** * @hdmi_clear_audio_infoframe: * @@ -1021,6 +1044,12 @@ enum drm_bridge_ops { * &drm_bridge_funcs->hdmi_clear_spd_infoframe callbacks. */ DRM_BRIDGE_OP_HDMI_SPD_INFOFRAME =3D BIT(10), + /** + * @DRM_BRIDGE_OP_HDMI_VTEM_EMP: The bridge supports + * &drm_bridge_funcs->hdmi_write_vtem_emp and + * &drm_bridge_funcs->hdmi_clear_vtem_emp callbacks. + */ + DRM_BRIDGE_OP_HDMI_VTEM_EMP =3D BIT(11), }; =20 /** diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 593fbeaffa16..e561a444515f 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -1633,6 +1633,14 @@ struct drm_connector_hdmi_funcs { * optional. */ struct drm_connector_infoframe_funcs spd; + + /** + * @vtem: + * + * Set of callbacks for handling the VTEM EMP. These callbacks are + * optional. + */ + struct drm_connector_infoframe_funcs vtem; }; =20 /** --=20 2.55.0 From nobody Fri Sep 25 21:02:41 2026 Received: from sender4-pp-f112.zoho.com (sender4-pp-f112.zoho.com [136.143.188.112]) (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 1A9BC4C1515; Mon, 21 Sep 2026 15:53:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=136.143.188.112 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790006006; cv=pass; b=cSBvrCmY75DrB6N6r8e14g9JB7FYd5a7leguxs9DpRxr2HcDIozKxuM5XI8Vay6FciiXpt9jZOiRMGAaqBpyRKcOLVm8IOB0eP/CSttWk933zpPg72ezA1d2pneP2/X5jAuU4x7nbxXnF9wzVxSUrbl/klZmIf6ZUL2/Osl//WQ= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790006006; c=relaxed/simple; bh=51XJ37ALErZdpgcd7TJG6ZV55C35vXBoF0gb6Dm75HA=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=oIt4gTSOb0k0eqItV75Eyeyx6T/jP6amk+5wloL/2kvr2OXUK/TasCLmMA7asi+FNcwnKvo27lGhe6ZMyFbz+iv+BaGbhqu69rBalDxzH1OyQtV3RxiWSyj2U4SO8BdD2nmjN0Y9599oxkkgFbbsIDXLdB2Lb24yGqaoBvKQqG4= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (1024-bit key) header.d=collabora.com header.i=nicolas.frattaroli@collabora.com header.b=AIec5rfw; arc=pass smtp.client-ip=136.143.188.112 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=collabora.com header.i=nicolas.frattaroli@collabora.com header.b="AIec5rfw" ARC-Seal: i=1; a=rsa-sha256; t=1790005957; cv=none; d=zohomail.com; s=zohoarc; b=beMzLIihiAxRjocBPr3aCVxfqMlKF6jkyg4f26p+VvrEUfDJeu2UdaFtUmJASqVy2gNRcF23dS3PRb/77JJllZ2eW+5b1GCI6rmRaY8kXCq9GeFm4E3LdhMaROfHR7WZXjNZ9NZJ8pg/tdnW0TA43zITBnDiMYbP/CCj6jIWXgI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1790005957; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:MIME-Version:Message-ID:Subject:Subject:To:To:Message-Id:Reply-To; bh=NSgBlPaazMWThLQxRccKboWgimwqe5RrJvSFqr1YUfY=; b=LRsoAa6nE5g9sCkL8NKvVS9QE7QDxrbMyERS++oRbtvqhoyxooMTVj6jJ/5ZxQDVQDqoedyoHLNjatcb12V0CX4joAeYij5nQ1BstZFLfLmaQVxc35xJF+hHuCQuyiRdRW77S/3XEzORHIak9w4VNMQt+j6SIDwgDiz1A/Jj9VA= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass header.i=collabora.com; spf=pass smtp.mailfrom=nicolas.frattaroli@collabora.com; dmarc=pass header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1790005957; s=zohomail; d=collabora.com; i=nicolas.frattaroli@collabora.com; h=From:From:Date:Date:Subject:Subject:MIME-Version:Content-Type:Content-Transfer-Encoding:Message-Id:Message-Id:In-Reply-To:To:To:Cc:Cc:Reply-To; bh=NSgBlPaazMWThLQxRccKboWgimwqe5RrJvSFqr1YUfY=; b=AIec5rfwJnUWzqFY3jEIaG9P3LMqSFKgmjeuwplyo8oepFDQZD08gT7UIqDfcjW7 KfeFWUUQx9/7igjo+Zd0LzVVdc7y3pxTrxQhGkuo7qH2Z91wLTOKLKgzyxqX5g6ubve 9anHKgesNAf1jdt7QcN+XHzrup9TUTtB5Y8aEhJ0= Received: by smtp.zohomail.com with SMTPS id 1790005955159213.84382542019796; Mon, 21 Sep 2026 08:52:35 -0700 (PDT) From: Nicolas Frattaroli Date: Mon, 21 Sep 2026 17:51:32 +0200 Subject: [PATCH RFC 06/25] drm/connector: hdmi: Add VTEM EMP generation Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260921-vrr-limiter-uapi-v1-6-2fcd7d011646@collabora.com> References: <20260921-vrr-limiter-uapi-v1-0-2fcd7d011646@collabora.com> In-Reply-To: <20260921-vrr-limiter-uapi-v1-0-2fcd7d011646@collabora.com> To: "Borah, Chaitanya Kumar" , Leo Li , Daniel Stone , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Helge Deller , Andrzej Hajda , Neil Armstrong , Robert Foss , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Luca Ceresoli , Sandy Huang , =?utf-8?q?Heiko_St=C3=BCbner?= , Andy Yan Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, linux-fbdev@vger.kernel.org, linux-rockchip@lists.infradead.org, linux-arm-kernel@lists.infradead.org, kernel@collabora.com, Derek Foreman , wayland-devel@lists.freedesktop.org, Nicolas Frattaroli X-Mailer: b4 0.15.2 From: Derek Foreman Add VTEM EMP generation to enable variable refresh rate signalling over HDMI. These infoframes are only generated if the sink supports VRR. Signed-off-by: Derek Foreman Signed-off-by: Nicolas Frattaroli --- drivers/gpu/drm/display/drm_hdmi_state_helper.c | 60 +++++++++++++++++++++= ++++ include/drm/drm_connector.h | 5 +++ 2 files changed, 65 insertions(+) diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/= drm/display/drm_hdmi_state_helper.c index d55548399687..33d0c9491643 100644 --- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c +++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c @@ -853,6 +853,56 @@ static int hdmi_generate_hdmi_vendor_infoframe(const s= truct drm_connector *conne return 0; } =20 +static int hdmi_generate_emp_infoframe_vtem(const struct drm_connector *co= nnector, + struct drm_connector_state *conn_state) +{ + const struct drm_display_info *info =3D &connector->display_info; + const struct drm_crtc_state *crtc_state =3D + drm_atomic_get_crtc_state(conn_state->state, conn_state->crtc); + struct drm_connector_hdmi_infoframe *infoframe =3D + &conn_state->hdmi.infoframes.vtem; + struct hdmi_emp_infoframe_vtem *vtem =3D + &infoframe->data.vtem; + const struct drm_crtc_vrr_state *vrr =3D &crtc_state->vrr_state; + int vfront; + + infoframe->set =3D false; + + if (!connector->hdmi.funcs->vtem.write_infoframe) + return 0; + + if (!info->hdmi.vrr_capable) + return 0; + + hdmi_emp_infoframe_vtem_init(vtem); + if (!crtc_state->vrr_enabled || vrr->vic) { + vtem->base_refresh_rate =3D 0; + vtem->base_vfront =3D 0; + } else { + vtem->base_refresh_rate =3D drm_mode_vrefresh(&crtc_state->mode); + vfront =3D crtc_state->adjusted_mode.crtc_vsync_start - + crtc_state->adjusted_mode.crtc_vdisplay; + if (vfront > U8_MAX || vfront < 0) + return -EINVAL; + + vtem->base_vfront =3D vfront; + } + vtem->fva_factor_m1 =3D 0; + infoframe->set =3D true; + + if (!crtc_state->vrr_enabled) { + vtem->m_const =3D false; + vtem->game_vrr_en =3D false; + return 0; + } + + vtem->game_vrr_en =3D true; + + vtem->m_const =3D !vrr->dynamic; + + return 0; +} + static int hdmi_generate_infoframes(const struct drm_connector *connector, struct drm_connector_state *conn_state) @@ -884,6 +934,10 @@ hdmi_generate_infoframes(const struct drm_connector *c= onnector, if (ret) return ret; =20 + ret =3D hdmi_generate_emp_infoframe_vtem(connector, conn_state); + if (ret) + return ret; + return 0; } =20 @@ -1494,6 +1548,12 @@ int drm_atomic_helper_connector_hdmi_update_infofram= es(struct drm_connector *con goto out; } =20 + if (info->hdmi.vrr_capable) + ret =3D write_or_clear_infoframe(connector, + &funcs->vtem, "VTEM", + &old_conn_state->hdmi.infoframes.vtem, + &new_conn_state->hdmi.infoframes.vtem); + out: mutex_unlock(&connector->hdmi.infoframes.lock); return ret; diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index e561a444515f..6e431eb81705 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -1180,6 +1180,11 @@ struct drm_connector_hdmi_state { * matching our state. */ struct drm_connector_hdmi_infoframe hdmi; + + /** + * @vtem: VTEM EMP infoframes structure matching our state. + */ + struct drm_connector_hdmi_infoframe vtem; } infoframes; =20 /** --=20 2.55.0 From nobody Fri Sep 25 21:02:41 2026 Received: from sender4-pp-f112.zoho.com (sender4-pp-f112.zoho.com [136.143.188.112]) (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 A15E54A33EA; Mon, 21 Sep 2026 15:53:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=136.143.188.112 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790006014; cv=pass; b=BN2Ks1EFFzQAkSixe9b4uRLQDmVa3FeduZUtxpmxacMeqQ5P5HkQZB0zbhfph2jXv+Q7rod/WfTpvZVwmWbHPgfUDLB4uoZ7FUBDQy2JaGVhEKsHxh7TZm17JHDHmN/0866h9/FOCpfqrdsBgksUlsjFxVdjL3+YAjtLyT0F31k= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790006014; c=relaxed/simple; bh=i7369EXNVUL9nfixSD/eS3x3wYjFoM3yDmScV08zkLw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=JBiMLsXoI+b2g6WO1TT+7g77EvmlWFah1T9jpExSrSP7NJYlA5j81E7g986ewfjBpbg1RJCSobfik9FooCM+3OdB2Qc9BoCSsGuR2VBT+BJDSre8/e0M0+xeEP7BBVHihMnc3SLyxTVerHbulRy25FeB7v+zR+aB/CtrQa2Hwqo= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (1024-bit key) header.d=collabora.com header.i=nicolas.frattaroli@collabora.com header.b=XWOkjhXG; arc=pass smtp.client-ip=136.143.188.112 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=collabora.com header.i=nicolas.frattaroli@collabora.com header.b="XWOkjhXG" ARC-Seal: i=1; a=rsa-sha256; t=1790005961; cv=none; d=zohomail.com; s=zohoarc; b=ekDDWz6SKI6q6ld6C77KoGkwZ5pQEiQ2wumL+GCaea5SlhTExiwzvhnMqdMj6NNzbNmocdnyuw4Hx+bXnuubZ+Zoe8+T9Pu37KrWlO9mZa9uJECkZLdw51WHZxP7UZYU6y0ILrqV9R7d3qlYqHVT/qaFz2DuSXoBDwEO3ZJWN60= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1790005961; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:MIME-Version:Message-ID:Subject:Subject:To:To:Message-Id:Reply-To; bh=fVK7xdLrIgmNCx71jw7NwMha6WBnYRw57W6b6ElMFQw=; b=NU7kt8+teL4wsnrpXy5NYLNKO8qPyM/gShZqQhLcLg9fbS6H0xA2XwbnWXAB5sHmQ8B6kTg2vGGd0256mQS5EdGRL+z/lPh5NKhIpdcdCpYqUdSA+zonY3aQjjg3WJQ2NER4tUYD3gwKjECig1dwvlpCvuqOGt/+ashGZkdgIkE= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass header.i=collabora.com; spf=pass smtp.mailfrom=nicolas.frattaroli@collabora.com; dmarc=pass header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1790005961; s=zohomail; d=collabora.com; i=nicolas.frattaroli@collabora.com; h=From:From:Date:Date:Subject:Subject:MIME-Version:Content-Type:Content-Transfer-Encoding:Message-Id:Message-Id:In-Reply-To:To:To:Cc:Cc:Reply-To; bh=fVK7xdLrIgmNCx71jw7NwMha6WBnYRw57W6b6ElMFQw=; b=XWOkjhXGE+0Ttweod/Ofn4ftYbzzg/lblKp6FpAWxnMUd91E55EZpgcPCbkgP3fB h6h710VlM+Hg/y5T25Ga7MJxL42rVOQSeoh8jKL42RNrFf5q4C/BSguRCdTbaP7RSLg OHYpGkM2erk6Ch076Q07G4YVxL1vSZbSXiWiFD4o= Received: by smtp.zohomail.com with SMTPS id 1790005960600608.9880494214716; Mon, 21 Sep 2026 08:52:40 -0700 (PDT) From: Nicolas Frattaroli Date: Mon, 21 Sep 2026 17:51:33 +0200 Subject: [PATCH RFC 07/25] drm/crtc-helper: Add VRR helper functions Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260921-vrr-limiter-uapi-v1-7-2fcd7d011646@collabora.com> References: <20260921-vrr-limiter-uapi-v1-0-2fcd7d011646@collabora.com> In-Reply-To: <20260921-vrr-limiter-uapi-v1-0-2fcd7d011646@collabora.com> To: "Borah, Chaitanya Kumar" , Leo Li , Daniel Stone , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Helge Deller , Andrzej Hajda , Neil Armstrong , Robert Foss , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Luca Ceresoli , Sandy Huang , =?utf-8?q?Heiko_St=C3=BCbner?= , Andy Yan Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, linux-fbdev@vger.kernel.org, linux-rockchip@lists.infradead.org, linux-arm-kernel@lists.infradead.org, kernel@collabora.com, Derek Foreman , wayland-devel@lists.freedesktop.org, Nicolas Frattaroli X-Mailer: b4 0.15.2 VRR needs to change the vertical front porch timing to change the duration of a frame. Add two helpers to aid in this. drm_crtc_helper_vrr_flush should be called when the source has a new frame ready to present. It adjusts the internal VRR state, and returns whether the current vtotal has been changed. Callers can then adjust their hardware state as is necessary. drm_crtc_helper_vrr_vsync should be called in the vblank interrupt handler. It adjusts the internal VRR state, and returns whether the current vtotal has been changed. Callers can then adjust their hardware state as is necessary. Co-developed-by: Derek Foreman Signed-off-by: Derek Foreman Signed-off-by: Nicolas Frattaroli --- drivers/gpu/drm/drm_crtc_helper.c | 63 +++++++++++++++++++++++++++++++++++= ++++ include/drm/drm_crtc_helper.h | 4 +++ 2 files changed, 67 insertions(+) diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_h= elper.c index 4a8cfe046e4a..4ffb3b0b7878 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -838,6 +838,69 @@ int drm_crtc_helper_set_config(struct drm_mode_set *se= t, } EXPORT_SYMBOL(drm_crtc_helper_set_config); =20 +/** + * drm_crtc_helper_vrr_flush - Update VRR state on frame ready + * @crtc_state: pointer to &struct drm_crtc_state of CRTC that has a new f= rame ready + * + * Update the VRR state by communicating that a frame is ready on + * @crtc_state.crtc. + * + * Should be called from the @crtc_state.crtc &drm_crtc_helper_funcs.atomi= c_flush + * hook. + * + * Returns: + * - %true if @crtc_state.vrr_state.cur_vtotal changed + * - %false otherwise + */ +bool drm_crtc_helper_vrr_flush(struct drm_crtc_state *crtc_state) +{ + struct drm_crtc_vrr_state *vrr =3D &crtc_state->vrr_state; + + if (!crtc_state->vrr_enabled) { + if (vrr->cur_vtotal) { + vrr->cur_vtotal =3D 0; + return true; + } + return false; + } + + if (vrr->cur_vtotal =3D=3D vrr->base_vtotal) + return false; + + vrr->cur_vtotal =3D vrr->base_vtotal; + + return true; +} +EXPORT_SYMBOL(drm_crtc_helper_vrr_flush); + +/** + * drm_crtc_helper_vrr_vsync - Update VRR state on vblank end + * @crtc_state: pointer to &struct drm_crtc_state of CRTC the vblank occur= red on + * + * Update the VRR state by communicating that a vertical blank has ended a= nd a + * new frame is about to start. + * + * Returns: + * - %true if @crtc_state.vrr_state.cur_vtotal changed + * - %false otherwise + */ +bool drm_crtc_helper_vrr_vsync(struct drm_crtc_state *crtc_state) +{ + struct drm_crtc_vrr_state *vrr =3D &crtc_state->vrr_state; + u16 old_vtotal =3D vrr->cur_vtotal; + + if (!crtc_state->vrr_enabled) + vrr->cur_vtotal =3D 0; + else + vrr->cur_vtotal =3D vrr->max_vtotal; + + if (abs_diff(vrr->cur_vtotal, old_vtotal) > 1) + vrr->dynamic =3D true; + + return old_vtotal !=3D vrr->cur_vtotal; +} +EXPORT_SYMBOL(drm_crtc_helper_vrr_vsync); + static int drm_helper_choose_encoder_dpms(struct drm_encoder *encoder) { int dpms =3D DRM_MODE_DPMS_OFF; diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index 855da5733c47..0c8c11ea36dd 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -44,6 +44,7 @@ struct drm_encoder; struct drm_framebuffer; struct drm_mode_set; struct drm_modeset_acquire_ctx; +struct drm_crtc_state; =20 void drm_helper_disable_unused_functions(struct drm_device *dev); int drm_crtc_helper_set_config(struct drm_mode_set *set, @@ -62,4 +63,7 @@ int drm_helper_connector_dpms(struct drm_connector *conne= ctor, int mode); void drm_helper_resume_force_mode(struct drm_device *dev); int drm_helper_force_disable_all(struct drm_device *dev); =20 +bool drm_crtc_helper_vrr_flush(struct drm_crtc_state *crtc_state); +bool drm_crtc_helper_vrr_vsync(struct drm_crtc_state *crtc_state); + #endif --=20 2.55.0 From nobody Fri Sep 25 21:02:41 2026 Received: from sender4-pp-f112.zoho.com (sender4-pp-f112.zoho.com [136.143.188.112]) (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 2CD6C4BFE6A; Mon, 21 Sep 2026 15:53:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=136.143.188.112 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790006024; cv=pass; b=QRpKWMRXosX7GWogoNpxBQgMNdxE0x6Cq8q+85UO5ZPHiUQzVTPTDXYxyfM480W+n3Mkh/Fz2GGat6k3ifsfB3iXB9aXrn645yovcKx67R1ej2aD4OOeluz034blt6mxt65QAiHXANQoNdRWUILpjsCCBCoF6fRM3lIgd/R9OAc= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790006024; c=relaxed/simple; bh=7yFlaGWyHjezSRdYaw7ySWOKCfvuqXaLU0PcHYhnOjI=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=jeiCaNQTYKiKHKz1qshNcyy/CmCsdRgRFPqWb7nH8gxy0+IEf0ERadB+Rdd2G1iMRW9TC+szclTNS8zamg+Y96EofAPz1oFcDPQ5L7pYp/8NOy/MLcAjY2OaXpvNrTMFAkVedKK6hWLOKIA9mjpF5PGYCr7AAOvP3TyDAAtnPUM= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (1024-bit key) header.d=collabora.com header.i=nicolas.frattaroli@collabora.com header.b=eoObOOP2; arc=pass smtp.client-ip=136.143.188.112 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=collabora.com header.i=nicolas.frattaroli@collabora.com header.b="eoObOOP2" ARC-Seal: i=1; a=rsa-sha256; t=1790005967; cv=none; d=zohomail.com; s=zohoarc; b=eXCGYJemu4BVEiqC5856QnRCmHqKrEkFRxM0YUtesxCydeXdKQPq9fJXqcKdysNNd1q5f9oHd6alHOvOWKnkVxafl+gT+czPlez0JpXNaDktwrIW4GrLCAashst6cEJY9n3SfR2pWMtNmuzrWyqZuT9UaVjwk4MSZjUsaw5H6tw= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1790005967; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:MIME-Version:Message-ID:Subject:Subject:To:To:Message-Id:Reply-To; bh=NrH1BPLpuLOqQDQpOONb+r82Ea0xWENpicF6PhqY/S8=; b=LBgNiCsPouf5SGKErMhoq7Bl/06lEezg5d0KulEtR6QJRS166y3Obn3fHWs1reLiKPxKZMN5EQcHfDBdSXENZaeFDOrTYM4b7LU1HBnEJGn2kOXoJZS5lGyIgxdW0VGzXEwitNR8yt89f570y5GXYNoI3Gi7hZNZyLo5veqlQsE= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass header.i=collabora.com; spf=pass smtp.mailfrom=nicolas.frattaroli@collabora.com; dmarc=pass header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1790005967; s=zohomail; d=collabora.com; i=nicolas.frattaroli@collabora.com; h=From:From:Date:Date:Subject:Subject:MIME-Version:Content-Type:Content-Transfer-Encoding:Message-Id:Message-Id:In-Reply-To:To:To:Cc:Cc:Reply-To; bh=NrH1BPLpuLOqQDQpOONb+r82Ea0xWENpicF6PhqY/S8=; b=eoObOOP2Dc5eRhtDEA2ShosHM7hJxzu2HeIFqOlzIQExUrtPWD/UdiB0t2dDRNfw gpUucXuH46qfDDPYyQMBuq4n4AMDGVkcIQQWzUGtfCJtRVUsndEnQGCFdf4bN+qY/hM iF5/yDj8eu6yLjPmcZMZihVDmn/Zvr92ihZu/Hsk= Received: by smtp.zohomail.com with SMTPS id 17900059663881006.9027491955; Mon, 21 Sep 2026 08:52:46 -0700 (PDT) From: Nicolas Frattaroli Date: Mon, 21 Sep 2026 17:51:34 +0200 Subject: [PATCH RFC 08/25] drm/bridge: synopsys: Add VTEM EMP support Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260921-vrr-limiter-uapi-v1-8-2fcd7d011646@collabora.com> References: <20260921-vrr-limiter-uapi-v1-0-2fcd7d011646@collabora.com> In-Reply-To: <20260921-vrr-limiter-uapi-v1-0-2fcd7d011646@collabora.com> To: "Borah, Chaitanya Kumar" , Leo Li , Daniel Stone , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Helge Deller , Andrzej Hajda , Neil Armstrong , Robert Foss , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Luca Ceresoli , Sandy Huang , =?utf-8?q?Heiko_St=C3=BCbner?= , Andy Yan Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, linux-fbdev@vger.kernel.org, linux-rockchip@lists.infradead.org, linux-arm-kernel@lists.infradead.org, kernel@collabora.com, Derek Foreman , wayland-devel@lists.freedesktop.org, Nicolas Frattaroli X-Mailer: b4 0.15.2 From: Derek Foreman Add code to pack and schedule VTEM EMPs. Signed-off-by: Derek Foreman --- drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c | 50 ++++++++++++++++++++++++= +++- drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.h | 1 + 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm= /bridge/synopsys/dw-hdmi-qp.c index c9568aea98dc..3315082d4475 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c @@ -673,6 +673,15 @@ static int dw_hdmi_qp_bridge_clear_spd_infoframe(struc= t drm_bridge *bridge) return 0; } =20 +static int dw_hdmi_qp_bridge_clear_vtem_emp(struct drm_bridge *bridge) +{ + struct dw_hdmi_qp *hdmi =3D bridge->driver_private; + + dw_hdmi_qp_mod(hdmi, 0, PKTSCHED_EMP_VTEM_TX_EN, PKTSCHED_PKT_EN); + + return 0; +} + static int dw_hdmi_qp_bridge_clear_audio_infoframe(struct drm_bridge *brid= ge) { struct dw_hdmi_qp *hdmi =3D bridge->driver_private; @@ -775,6 +784,42 @@ static int dw_hdmi_qp_bridge_write_spd_infoframe(struc= t drm_bridge *bridge, return 0; } =20 +static int dw_hdmi_qp_bridge_write_vtem_emp(struct drm_bridge *bridge, + const u8 *buffer, size_t len) +{ + struct dw_hdmi_qp *hdmi =3D bridge->driver_private; + u32 val, i; + + if (len !=3D HDMI_INFOFRAME_SIZE(VTEM)) { + dev_err(hdmi->dev, "unsupported vtem emp packet size of %zu\n", len); + return -EINVAL; + } + + val =3D buffer[1] << 8 | buffer[2] << 16; + dw_hdmi_qp_write(hdmi, val, PKT_EMP_VTEM_CONTENTS0); + + val =3D buffer[3] | buffer[4] << 8; + dw_hdmi_qp_write(hdmi, val, PKT_EMP_VTEM_CONTENTS1); + + val =3D buffer[8] << 8 | buffer[9] << 16 | buffer[10] << 24; + dw_hdmi_qp_write(hdmi, val, PKT_EMP_VTEM_CONTENTS2); + + val =3D buffer[11] | buffer[12] << 8 | buffer[13] << 16; + dw_hdmi_qp_write(hdmi, val, PKT_EMP_VTEM_CONTENTS3); + + /* + * The remaining registers need to explicitly be rewritten even if they + * stay at 0, as per the hardware documentation. + */ + for (i =3D PKT_EMP_VTEM_CONTENTS4; i <=3D PKT_EMP_VTEM_CONTENTS7; i +=3D = 4) + dw_hdmi_qp_write(hdmi, 0, i); + + dw_hdmi_qp_mod(hdmi, PKTSCHED_EMP_VTEM_TX_EN, PKTSCHED_EMP_VTEM_TX_EN, + PKTSCHED_PKT_EN); + + return 0; +} + static int dw_hdmi_qp_bridge_write_audio_infoframe(struct drm_bridge *brid= ge, const u8 *buffer, size_t len) { @@ -1000,6 +1045,8 @@ static const struct drm_bridge_funcs dw_hdmi_qp_bridg= e_funcs =3D { .hdmi_write_hdr_drm_infoframe =3D dw_hdmi_qp_bridge_write_hdr_drm_infofra= me, .hdmi_clear_spd_infoframe =3D dw_hdmi_qp_bridge_clear_spd_infoframe, .hdmi_write_spd_infoframe =3D dw_hdmi_qp_bridge_write_spd_infoframe, + .hdmi_clear_vtem_emp =3D dw_hdmi_qp_bridge_clear_vtem_emp, + .hdmi_write_vtem_emp =3D dw_hdmi_qp_bridge_write_vtem_emp, .hdmi_clear_audio_infoframe =3D dw_hdmi_qp_bridge_clear_audio_infoframe, .hdmi_write_audio_infoframe =3D dw_hdmi_qp_bridge_write_audio_infoframe, .hdmi_audio_startup =3D dw_hdmi_qp_audio_enable, @@ -1118,7 +1165,8 @@ struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_de= vice *pdev, DRM_BRIDGE_OP_HDMI | DRM_BRIDGE_OP_HDMI_AUDIO | DRM_BRIDGE_OP_HDMI_HDR_DRM_INFOFRAME | - DRM_BRIDGE_OP_HDMI_SPD_INFOFRAME; + DRM_BRIDGE_OP_HDMI_SPD_INFOFRAME | + DRM_BRIDGE_OP_HDMI_VTEM_EMP; if (!hdmi->no_hpd) hdmi->bridge.ops |=3D DRM_BRIDGE_OP_HPD; hdmi->bridge.of_node =3D pdev->dev.of_node; diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.h b/drivers/gpu/drm= /bridge/synopsys/dw-hdmi-qp.h index c07847e8d7dd..6ce87064a267 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.h +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.h @@ -210,6 +210,7 @@ #define PKTSCHED_AVI_TX_EN BIT(13) #define PKTSCHED_VSI_TX_EN BIT(12) #define PKTSCHED_EMP_CVTEM_TX_EN BIT(10) +#define PKTSCHED_EMP_VTEM_TX_EN BIT(9) #define PKTSCHED_AMD_TX_EN BIT(8) #define PKTSCHED_GCP_TX_EN BIT(3) #define PKTSCHED_AUDS_TX_EN BIT(2) --=20 2.55.0 From nobody Fri Sep 25 21:02:41 2026 Received: from sender4-pp-f112.zoho.com (sender4-pp-f112.zoho.com [136.143.188.112]) (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 2ABE94B44BA; Mon, 21 Sep 2026 15:53:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=136.143.188.112 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790006032; cv=pass; b=Rea8ePeaxwISVqFjp1/h9FiOSBdv8cH2JZbYHuXqd1Tzz7b2An0drw9DrkDYnJH5+Uwfoucr+Ltqe1ZX1yjWDiDu9Ici440QEl8jTpL+K5UiB3mDOOzBvb+ttDULY/57is6MmAMopatYLlB3jX+R5Ep4B8f5J7uaw4hdG8ylU5k= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790006032; c=relaxed/simple; bh=VF4579qnkQUsS2t7TOtd+wRl1b1/uuZA/0FdqRnico4=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=feXUXx+5ofcZ3h+K3yUQKW0rnyctSbQ+cbRduL41JmIHRaZtfOw6juG68H/6RX/WXoHQ/SN2+3MQMeVBcdEJn5c1GVALg0TfNMx8oCvWIgBImatJ+smQj7Z6HahFBD1G7RH2f54AyQkkOmuJVMWmeKqfE1s23lmsMRYUEiQQP/0= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (1024-bit key) header.d=collabora.com header.i=nicolas.frattaroli@collabora.com header.b=NWS8s+//; arc=pass smtp.client-ip=136.143.188.112 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=collabora.com header.i=nicolas.frattaroli@collabora.com header.b="NWS8s+//" ARC-Seal: i=1; a=rsa-sha256; t=1790005973; cv=none; d=zohomail.com; s=zohoarc; b=KwU0MvN9TIqpzV48EIVHG5F1HhDllVYkeXB3229n+SkrqogUBlq6S9Xe00OwHtVFBuXJj/uJO4J+/6r2Ag/1bwjSCFTtc6O4WjUjKoB9a9N6vOp+ytK6c2FICBGElS3vVciYhJVKSlnX3flUc0EzeOKPVl9sgnrJ+1vsGAi//m4= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1790005973; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:MIME-Version:Message-ID:Subject:Subject:To:To:Message-Id:Reply-To; bh=A37lvk2K4kvKDIjEQaFWtxje/hLDqdNIP4aYihLpCOA=; b=PbqlYUF+Zvl3FGv7ItmwO2PiaxxqZiPWWKmb4fQ7kiyIXS4/V+d+VV3ZDsX0AtICpZopEzKL+vwmKoe5LoxOGevpk+T46LG3JAjNb/Tr2x1+U8/8Mc6Xh3/vQmYSRHyxFBFyaYzTaJPkkAYqcjzH2GvYkIRnZ74Td727/a63BaI= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass header.i=collabora.com; spf=pass smtp.mailfrom=nicolas.frattaroli@collabora.com; dmarc=pass header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1790005973; s=zohomail; d=collabora.com; i=nicolas.frattaroli@collabora.com; h=From:From:Date:Date:Subject:Subject:MIME-Version:Content-Type:Content-Transfer-Encoding:Message-Id:Message-Id:In-Reply-To:To:To:Cc:Cc:Reply-To; bh=A37lvk2K4kvKDIjEQaFWtxje/hLDqdNIP4aYihLpCOA=; b=NWS8s+//mfEFTrVR4p3kwSFSobcD+KUYqBd+Ckn1TlqEtQyMPU+FzLo51YECtZTN /o08VKT+AmRYkEay4XR8R0tPkQdU80OZIYY1E+bazrEX42TbQFjHrAkPO2xh6Dp7MFV mBHjUVK5v+ruHKeIfLt9Dzm68w9K9Q43oeDk2S0k= Received: by smtp.zohomail.com with SMTPS id 1790005971883349.0752585694669; Mon, 21 Sep 2026 08:52:51 -0700 (PDT) From: Nicolas Frattaroli Date: Mon, 21 Sep 2026 17:51:35 +0200 Subject: [PATCH RFC 09/25] drm/connector: Add drm_display_info_is_vrr_capable Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260921-vrr-limiter-uapi-v1-9-2fcd7d011646@collabora.com> References: <20260921-vrr-limiter-uapi-v1-0-2fcd7d011646@collabora.com> In-Reply-To: <20260921-vrr-limiter-uapi-v1-0-2fcd7d011646@collabora.com> To: "Borah, Chaitanya Kumar" , Leo Li , Daniel Stone , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Helge Deller , Andrzej Hajda , Neil Armstrong , Robert Foss , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Luca Ceresoli , Sandy Huang , =?utf-8?q?Heiko_St=C3=BCbner?= , Andy Yan Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, linux-fbdev@vger.kernel.org, linux-rockchip@lists.infradead.org, linux-arm-kernel@lists.infradead.org, kernel@collabora.com, Derek Foreman , wayland-devel@lists.freedesktop.org, Nicolas Frattaroli X-Mailer: b4 0.15.2 Add a function to return whether a sink, as described by a drm_display_info struct, is capable of receiving VRR signals. For HDMI sinks, this can just check the HDMI specific vrr_capable field, which is set by the EDID parsing code. For other types of displays, the generally agreed-upon method appears to be to check whether the monitor range's minimum frequency is above 0. Signed-off-by: Nicolas Frattaroli --- drivers/gpu/drm/drm_connector.c | 19 +++++++++++++++++++ include/drm/drm_connector.h | 2 ++ 2 files changed, 21 insertions(+) diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connecto= r.c index d94c86bfed86..fc7d9fcf9d9f 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -1378,6 +1378,25 @@ int drm_display_info_set_bus_formats(struct drm_disp= lay_info *info, } EXPORT_SYMBOL(drm_display_info_set_bus_formats); =20 +/** + * drm_display_info_is_vrr_capable - Check whether sink is VRR capable + * @info: pointer to a &struct drm_display_info representing the sink + * + * Check whether the sink supports variable refresh rate signals. + * + * Returns: + * - true if variable refresh rate is supported by the sink + * - false otherwise + */ +bool drm_display_info_is_vrr_capable(const struct drm_display_info *info) +{ + if (info->is_hdmi) + return info->hdmi.vrr_capable; + + return info->monitor_range.min_vfreq > 0; +} +EXPORT_SYMBOL(drm_display_info_is_vrr_capable); + /* Optional connector properties. */ static const struct drm_prop_enum_list drm_scaling_mode_enum_list[] =3D { { DRM_MODE_SCALE_NONE, "None" }, diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 6e431eb81705..b18684d039d5 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -1072,6 +1072,8 @@ int drm_display_info_set_bus_formats(struct drm_displ= ay_info *info, const u32 *formats, unsigned int num_formats); =20 +bool drm_display_info_is_vrr_capable(const struct drm_display_info *info); + /** * struct drm_connector_tv_margins - TV connector related margins * --=20 2.55.0 From nobody Fri Sep 25 21:02:41 2026 Received: from sender4-pp-f112.zoho.com (sender4-pp-f112.zoho.com [136.143.188.112]) (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 B643A4D0A06; Mon, 21 Sep 2026 15:53:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=136.143.188.112 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790006029; cv=pass; b=tuXDRKFiZMo/ADd947Q9Z/SnMF0v65Qqzl9iZVdZOs8EGFU34DxaAmQ7mMJxLn578KVvr74MwUoHEc3tl06voIxr94Q7grG9dS4Xrw+vZx1Frfigc6L+NEUUAsGEAfUf90VKsa7o+HZI1o53B6OWRmx2QJTyo21ndNLsMBR8Vco= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790006029; c=relaxed/simple; bh=knCbAlkLfrhlmFv8jqU0VreZUnHNDuwUkvMrOyIXedI=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=fZJnEpWUBBqAmEEM7wXOX7bC7C48Fo93LcWqjgET83UJyTbaxkuQuk80zic26NzAGQ5jdgOlDifZJObpvpCAQZ5e6p4ZgySwLSochBW5res430w+mV7pOfpgcNnr3lBdyR5VnZISjEirOmvnBoEW7g+omBxHQBm39bfQDi9tKYM= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (1024-bit key) header.d=collabora.com header.i=nicolas.frattaroli@collabora.com header.b=ddZwLhNz; arc=pass smtp.client-ip=136.143.188.112 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=collabora.com header.i=nicolas.frattaroli@collabora.com header.b="ddZwLhNz" ARC-Seal: i=1; a=rsa-sha256; t=1790005979; cv=none; d=zohomail.com; s=zohoarc; b=JKwzUMbfxHQlGe/yNuKoHW9nf6Q0mAZtxOCgaXBRmARIhBVnMdwTkWrZCuuIUonC0Lfe2TfJ0BNdEP6HzXLKeMU8bSpYTkFm0pjDVLpTGIlzn/2ByAvNFHzyXp96lqgOWqtYS+aqeWCUIAp7g8tOQWhf0N2YZE1RAknclb5lU3A= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1790005979; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:MIME-Version:Message-ID:Subject:Subject:To:To:Message-Id:Reply-To; bh=RCTNkmpiPL3Ra0ipjPKJl1ubfsMjpTQk6YfOLEZoGhI=; b=BSZvTTyoWSgKb3s04MrP2MNVo5RIgsBhCrYD7D0IpDPYeOq+L2Z/chVXRw4/YT3BJXOn3/wNS2a+5BWTyMhOJJZ4cvrtodewkSMhQpEJr56tlZv83lk+vpjK3jTOoko2ZgF3bd/mJ5TZNFeZdNQp1Eqtithr4w0PhQ93jql/+mg= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass header.i=collabora.com; spf=pass smtp.mailfrom=nicolas.frattaroli@collabora.com; dmarc=pass header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1790005979; s=zohomail; d=collabora.com; i=nicolas.frattaroli@collabora.com; h=From:From:Date:Date:Subject:Subject:MIME-Version:Content-Type:Content-Transfer-Encoding:Message-Id:Message-Id:In-Reply-To:To:To:Cc:Cc:Reply-To; bh=RCTNkmpiPL3Ra0ipjPKJl1ubfsMjpTQk6YfOLEZoGhI=; b=ddZwLhNzqWf6wD2hET1tRSxvLxp5nhVwL+oNjnYjeypbyEWOuOwR9OuTWQx7xbeC ydfnY3gG8EXraA7ywSp4OuySvdcft8BT3jClXhSw0EYqXUrc2wfUkmEL/i/+hgklufh OIQExfyKQExrHTSnJU3f5RSw23K0zsIfrLp4vKBk= Received: by smtp.zohomail.com with SMTPS id 179000597774875.93524699372142; Mon, 21 Sep 2026 08:52:57 -0700 (PDT) From: Nicolas Frattaroli Date: Mon, 21 Sep 2026 17:51:36 +0200 Subject: [PATCH RFC 10/25] drm/rockchip: dw_hdmi_qp: Add VRR support Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260921-vrr-limiter-uapi-v1-10-2fcd7d011646@collabora.com> References: <20260921-vrr-limiter-uapi-v1-0-2fcd7d011646@collabora.com> In-Reply-To: <20260921-vrr-limiter-uapi-v1-0-2fcd7d011646@collabora.com> To: "Borah, Chaitanya Kumar" , Leo Li , Daniel Stone , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Helge Deller , Andrzej Hajda , Neil Armstrong , Robert Foss , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Luca Ceresoli , Sandy Huang , =?utf-8?q?Heiko_St=C3=BCbner?= , Andy Yan Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, linux-fbdev@vger.kernel.org, linux-rockchip@lists.infradead.org, linux-arm-kernel@lists.infradead.org, kernel@collabora.com, Derek Foreman , wayland-devel@lists.freedesktop.org, Nicolas Frattaroli X-Mailer: b4 0.15.2 Register the vrr_capable property on the connector for RK3588, where VRR is implemented. In the encoder's atomic_check callback, the vrr_capable property, if present, is then set to true if the sink supports VRR. Signed-off-by: Nicolas Frattaroli --- drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/d= rm/rockchip/dw_hdmi_qp-rockchip.c index 9c4cf68d79d5..2b9432aa8c54 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c @@ -192,6 +192,7 @@ dw_hdmi_qp_rockchip_encoder_atomic_check(struct drm_enc= oder *encoder, struct drm_crtc_state *crtc_state, struct drm_connector_state *conn_state) { + struct drm_connector *connector =3D conn_state->connector; struct rockchip_crtc_state *s =3D to_rockchip_crtc_state(crtc_state); struct rockchip_hdmi_qp *hdmi =3D to_rockchip_hdmi_qp(encoder); union phy_configure_opts phy_cfg =3D {}; @@ -238,6 +239,10 @@ dw_hdmi_qp_rockchip_encoder_atomic_check(struct drm_en= coder *encoder, dev_err(hdmi->dev, "Failed to configure phy: %d\n", ret); } =20 + if (connector->vrr_capable_property) + drm_connector_set_vrr_capable_property(connector, + drm_display_info_is_vrr_capable(&connector->display_info)); + return ret; } =20 @@ -515,6 +520,7 @@ struct rockchip_hdmi_qp_cfg { unsigned int port_ids[MAX_HDMI_PORT_NUM]; const struct rockchip_hdmi_qp_ctrl_ops *ctrl_ops; const struct dw_hdmi_qp_phy_ops *phy_ops; + bool supports_vrr; }; =20 static const struct rockchip_hdmi_qp_cfg rk3576_hdmi_cfg =3D { @@ -534,6 +540,7 @@ static const struct rockchip_hdmi_qp_cfg rk3588_hdmi_cf= g =3D { }, .ctrl_ops =3D &rk3588_hdmi_ctrl_ops, .phy_ops =3D &rk3588_hdmi_phy_ops, + .supports_vrr =3D true, }; =20 static const struct of_device_id dw_hdmi_qp_rockchip_dt_ids[] =3D { @@ -695,6 +702,13 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev= , struct device *master, return dev_err_probe(hdmi->dev, PTR_ERR(connector), "Failed to init bridge connector\n"); =20 + if (cfg->supports_vrr) { + ret =3D drm_connector_attach_vrr_capable_property(connector); + if (ret) + return dev_err_probe(hdmi->dev, ret, + "Failed to attach 'vrr_capable' property\n"); + } + return 0; } =20 --=20 2.55.0 From nobody Fri Sep 25 21:02:41 2026 Received: from sender4-pp-f112.zoho.com (sender4-pp-f112.zoho.com [136.143.188.112]) (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 279B01E5B68; Mon, 21 Sep 2026 15:53:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=136.143.188.112 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790006041; cv=pass; b=ZmhZpc/UJ8cdQiB2ql8j5XaKy+ckez1N2Wg/csILYpssE07GjuKmkyqJ0SwBK2YlWiC4vt1OMyYO/fHayEcT+AxoX+pGGU4S5ufSiLSJfz5CnLaTuMSuKkRIjYOPoLrBx0Jtv6/YI9Lt4NIQ8h5hrAW+VGxy1+WMotxyT114SFY= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790006041; c=relaxed/simple; bh=1bzbmQPpKqErdxhqGvNL8r8WJgMdg+Ku5fCAQ2LM4SI=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=HH12LOcocC9lYciYnhqH4B/9mSH8D2vA+a594o8adedGcTd8WMNG2V2jLQkeb2g32M/A/diEuECuTlPWegjRAQtmoN0y+NG+GN5gX2z+OToFlKFUadg772j2uiGih4xqhvXnPb9VpaXq9eOJWPB4+bGMvsEMXj7KCthv3Tty6s4= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (1024-bit key) header.d=collabora.com header.i=nicolas.frattaroli@collabora.com header.b=fcrE2OXr; arc=pass smtp.client-ip=136.143.188.112 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=collabora.com header.i=nicolas.frattaroli@collabora.com header.b="fcrE2OXr" ARC-Seal: i=1; a=rsa-sha256; t=1790005985; cv=none; d=zohomail.com; s=zohoarc; b=MkvctPEgN/opcclJ7AbrHT0NUw5PyfmjTlw1EVX0+A9iCip/vCP3fTYIf4WeCcAmxdjPIfeki2VQrDQYcGZdVseNywFZQf87igLM7iofK+RpNwQExbBpkQ/GBA7eppgMrgnKur3C8we3HtOKWDzWZ/1qkMBPJkuFt9XdZSVZ+ME= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1790005985; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:MIME-Version:Message-ID:Subject:Subject:To:To:Message-Id:Reply-To; bh=y/u3vmta3+dbrofrUmndHlgFpIUmssOjUpr8W2OjIi4=; b=bqmI9sT7fNW9pKNoXHo6CGSAoz+HKc8xaQoLIMQjPz0JPYYdbgzRXXDQEkWFL5dFKj4xcPPJK7300o+RNR3Dkuk6CA5coRlKJsIKeKBuUMqEz60Fn9jkiHfxAfvXzAiI3r+GCfuQ6WW78Fdpj0n39jjCY4kIEhUbCEJvrFZ0zA0= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass header.i=collabora.com; spf=pass smtp.mailfrom=nicolas.frattaroli@collabora.com; dmarc=pass header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1790005985; s=zohomail; d=collabora.com; i=nicolas.frattaroli@collabora.com; h=From:From:Date:Date:Subject:Subject:MIME-Version:Content-Type:Content-Transfer-Encoding:Message-Id:Message-Id:In-Reply-To:To:To:Cc:Cc:Reply-To; bh=y/u3vmta3+dbrofrUmndHlgFpIUmssOjUpr8W2OjIi4=; b=fcrE2OXrBcW4dbZejVZKBloogh6hW3A6feRsFGFcBd4A5tiB57BqLjkWHwbBuKiN l6DmQrYGZiaHpBxaeZ8bYc85y0Bq9FNES1a+GcgVJu/iywyvc+9urb8Clkp/lIp9gzr 1TfyNvvK3GIlrrm9T1WjiL8RsRhKhSn4zUtBDa7M= Received: by smtp.zohomail.com with SMTPS id 179000598377154.95688948710904; Mon, 21 Sep 2026 08:53:03 -0700 (PDT) From: Nicolas Frattaroli Date: Mon, 21 Sep 2026 17:51:37 +0200 Subject: [PATCH RFC 11/25] drm/rockchip: vop2: Enable VRR Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260921-vrr-limiter-uapi-v1-11-2fcd7d011646@collabora.com> References: <20260921-vrr-limiter-uapi-v1-0-2fcd7d011646@collabora.com> In-Reply-To: <20260921-vrr-limiter-uapi-v1-0-2fcd7d011646@collabora.com> To: "Borah, Chaitanya Kumar" , Leo Li , Daniel Stone , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Helge Deller , Andrzej Hajda , Neil Armstrong , Robert Foss , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Luca Ceresoli , Sandy Huang , =?utf-8?q?Heiko_St=C3=BCbner?= , Andy Yan Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, linux-fbdev@vger.kernel.org, linux-rockchip@lists.infradead.org, linux-arm-kernel@lists.infradead.org, kernel@collabora.com, Derek Foreman , wayland-devel@lists.freedesktop.org, Nicolas Frattaroli X-Mailer: b4 0.15.2 Use the new VRR state tracking to handle VRR front porch adjustment. To avoid indenting too deeply, refactor the vblank handling into its own function while at it, where scope-based cleanup helpers for the lock can be used. Co-developed-by: Derek Foreman Signed-off-by: Derek Foreman Signed-off-by: Nicolas Frattaroli --- drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 62 ++++++++++++++++++++++--= ---- drivers/gpu/drm/rockchip/rockchip_drm_vop2.h | 9 ++++ 2 files changed, 59 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm= /rockchip/rockchip_drm_vop2.c index bfb384142568..e79081c04437 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -2011,6 +2012,25 @@ static void vop2_crtc_atomic_begin(struct drm_crtc *= crtc, vop2->ops->setup_overlay(vp); } =20 +static void vop2_vp_set_vrr_vtotal(struct vop2_video_port *vp, unsigned in= t vtotal) +{ + const u32 mask =3D RK3568_VP_DSP_VTOTAL_VS_END__DSP_VTOTAL | + RK3568_VP_DSP_VTOTAL_VS_END__IMD; + + if (!vtotal) { + vop2_vp_update_bits(vp, RK3568_VP_DSP_VTOTAL_VS_END, + RK3568_VP_DSP_VTOTAL_VS_END__IMD, 0); + return; + } + + /* Value is 13 bits at most, saturate it if too large */ + if (vtotal > RK3568_VP_DSP_VTOTAL_VS_END__DSP_VTOTAL >> 16) + vtotal =3D RK3568_VP_DSP_VTOTAL_VS_END__DSP_VTOTAL >> 16; + + vop2_vp_update_bits(vp, RK3568_VP_DSP_VTOTAL_VS_END, mask, + vtotal << 16 | RK3568_VP_DSP_VTOTAL_VS_END__IMD); +} + static void vop2_crtc_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_commit *state) { @@ -2029,6 +2049,11 @@ static void vop2_crtc_atomic_flush(struct drm_crtc *= crtc, =20 spin_lock_irq(&crtc->dev->event_lock); =20 + if (crtc_state->vrr_enabled) { + if (drm_crtc_helper_vrr_flush(crtc_state)) + vop2_vp_set_vrr_vtotal(vp, crtc_state->vrr_state.cur_vtotal); + } + if (crtc->state->event) { WARN_ON(drm_crtc_vblank_get(crtc)); vp->event =3D crtc->state->event; @@ -2371,6 +2396,30 @@ static irqreturn_t rk3576_vp_isr(int irq, void *data) return ret; } =20 +static void vop2_vp_handle_vblank(struct vop2_video_port *vp) +{ + struct drm_crtc *crtc =3D &vp->crtc; + struct vop2 *vop2 =3D vp->vop2; + u32 val; + + guard(spinlock)(&crtc->dev->event_lock); + + if (!vp->event) + return; + + val =3D vop2_readl(vop2, RK3568_REG_CFG_DONE); + + if (!(val & BIT(vp->id))) { + drm_crtc_send_vblank_event(crtc, vp->event); + vp->event =3D NULL; + drm_crtc_vblank_put(crtc); + + if (crtc->state->vrr_enabled) + if (drm_crtc_helper_vrr_vsync(crtc->state)) + vop2_vp_set_vrr_vtotal(vp, crtc->state->vrr_state.cur_vtotal); + } +} + static irqreturn_t vop2_isr(int irq, void *data) { struct vop2 *vop2 =3D data; @@ -2402,18 +2451,7 @@ static irqreturn_t vop2_isr(int irq, void *data) =20 if (irqs & VP_INT_FS_FIELD) { drm_crtc_handle_vblank(crtc); - spin_lock(&crtc->dev->event_lock); - if (vp->event) { - u32 val =3D vop2_readl(vop2, RK3568_REG_CFG_DONE); - - if (!(val & BIT(vp->id))) { - drm_crtc_send_vblank_event(crtc, vp->event); - vp->event =3D NULL; - drm_crtc_vblank_put(crtc); - } - } - spin_unlock(&crtc->dev->event_lock); - + vop2_vp_handle_vblank(vp); ret =3D IRQ_HANDLED; } =20 diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h b/drivers/gpu/drm= /rockchip/rockchip_drm_vop2.h index ffcb39c130aa..fdb2030e3ad4 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h @@ -655,6 +655,9 @@ enum dst_factor_mode { =20 #define RK3588_VP_DSP_CTRL__GAMMA_UPDATE_EN BIT(22) =20 +#define RK3568_VP_DSP_VTOTAL_VS_END__DSP_VTOTAL GENMASK(28, 16) +#define RK3568_VP_DSP_VTOTAL_VS_END__IMD BIT(15) + #define RK3588_VP_CLK_CTRL__DCLK_OUT_DIV GENMASK(3, 2) #define RK3588_VP_CLK_CTRL__DCLK_CORE_DIV GENMASK(1, 0) =20 @@ -810,6 +813,12 @@ static inline void vop2_vp_write(struct vop2_video_por= t *vp, u32 offset, u32 v) regmap_write(vp->vop2->map, vp->data->offset + offset, v); } =20 +static inline void vop2_vp_update_bits(struct vop2_video_port *vp, u32 off= set, + u32 mask, u32 v) +{ + regmap_update_bits(vp->vop2->map, vp->data->offset + offset, mask, v); +} + static inline u32 vop2_readl(struct vop2 *vop2, u32 offset) { u32 val; --=20 2.55.0 From nobody Fri Sep 25 21:02:41 2026 Received: from sender4-pp-f112.zoho.com (sender4-pp-f112.zoho.com [136.143.188.112]) (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 0C8E74BD7B7; Mon, 21 Sep 2026 15:53:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=136.143.188.112 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790006041; cv=pass; b=lltWwAMDk2M7lAWHoGR8mCkWeWcW4TrjuzV9GfvFHS3/f8dg6hstjlNvSM/rSXpvh8RkwOvBky7JIpFeN2Wo8qn+wnsqq3KVLdPFICVnunKCXvOtr7lky3WuZAvJB8ToZWxpiIM3bxZkYnkzDV9qp4Cvu+tvTg9MOXIhxCOCDU0= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790006041; c=relaxed/simple; bh=7W67VFKeSe8HA8OEGo9TcoNGnGrXL3/VTK/9E6ybVwg=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=uT2JNiwz79cyM4l9AS3jdVUXMiFAvbUo8U2DSmGkLlLEc0pA587UtLiT4A2XHTmNvDAd2wnzd9+xwEqjqLnhz6x7XZJiN4VHvUtyPmN8Eq88wzJ6HQ2fuIDUq1nMH2b1IQSyFALUal7sR2T5tAsN1nUA8XBdWW79iR9N1f9AEOg= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (1024-bit key) header.d=collabora.com header.i=nicolas.frattaroli@collabora.com header.b=DNYT7D1L; arc=pass smtp.client-ip=136.143.188.112 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=collabora.com header.i=nicolas.frattaroli@collabora.com header.b="DNYT7D1L" ARC-Seal: i=1; a=rsa-sha256; t=1790005991; cv=none; d=zohomail.com; s=zohoarc; b=IPFid0e9vODgcSMCEusJ+bQftHO17olv16R8WSLSSyhN/KFvjOfYrhEknHrN4LtxKQI5Y/1AL934WFqS55OiMDDsJZ7ABmjeZDm9tzNgWcnk+eRZfX7yZ970nBr+RFPOjKsMBneDbUEuU7sj/O0UcywETkcXkRT1EqdnzXsa7Eg= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1790005991; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:MIME-Version:Message-ID:Subject:Subject:To:To:Message-Id:Reply-To; bh=OTPs0m8K1NZZqNCZ2ZoGsft+mfIizutFeldFeGSDZYA=; b=mHppDmJko71JK/NbwhakTvzqCMT1YcR3SahXGhdLjuMSo6zZGSrq9DVY9G82jntXD8v/gJ8vp3e6aXdpD7tMVVPKzV64swKVQMaXOqB8KR8UX+LiUr3eDzLY96bPnDMNu8k2vHiCOwKzwOXbtclU2S1q4PK80eNQtaSchdon6Sc= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass header.i=collabora.com; spf=pass smtp.mailfrom=nicolas.frattaroli@collabora.com; dmarc=pass header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1790005991; s=zohomail; d=collabora.com; i=nicolas.frattaroli@collabora.com; h=From:From:Date:Date:Subject:Subject:MIME-Version:Content-Type:Content-Transfer-Encoding:Message-Id:Message-Id:In-Reply-To:To:To:Cc:Cc:Reply-To; bh=OTPs0m8K1NZZqNCZ2ZoGsft+mfIizutFeldFeGSDZYA=; b=DNYT7D1LE8zPm5SV05KRKU3gOwJah2VF7pX6LLN/tkiSeQDcLlew8WiSW3+V9p2Q z/y5l/h9zsFhoKbViarXQa3VWCr3L019j/OKjn+ef/e+D5Em636idyz9iCu6tI+6T4g R2jg/fVz+aOTEccx40zL7lciLVbt6pA2agj/XgpA= Received: by smtp.zohomail.com with SMTPS id 1790005989707834.0920962164566; Mon, 21 Sep 2026 08:53:09 -0700 (PDT) From: Nicolas Frattaroli Date: Mon, 21 Sep 2026 17:51:38 +0200 Subject: [PATCH RFC 12/25] drm/edid: Parse CinemaVRR flag from HDMI SCDS Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260921-vrr-limiter-uapi-v1-12-2fcd7d011646@collabora.com> References: <20260921-vrr-limiter-uapi-v1-0-2fcd7d011646@collabora.com> In-Reply-To: <20260921-vrr-limiter-uapi-v1-0-2fcd7d011646@collabora.com> To: "Borah, Chaitanya Kumar" , Leo Li , Daniel Stone , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Helge Deller , Andrzej Hajda , Neil Armstrong , Robert Foss , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Luca Ceresoli , Sandy Huang , =?utf-8?q?Heiko_St=C3=BCbner?= , Andy Yan Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, linux-fbdev@vger.kernel.org, linux-rockchip@lists.infradead.org, linux-arm-kernel@lists.infradead.org, kernel@collabora.com, Derek Foreman , wayland-devel@lists.freedesktop.org, Nicolas Frattaroli X-Mailer: b4 0.15.2 HDMI's extension to EDID contains a flag which is used by sinks to signal that they support "CinemaVRR". When CinemaVRR is enabled, some VRR is possible even if the minimum VRR range is set to 0. Parse it from the SCDS and store it in the sink's drm_hdmi_info. Signed-off-by: Nicolas Frattaroli --- drivers/gpu/drm/drm_edid.c | 7 ++++++- include/drm/drm_connector.h | 3 +++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index a1494028e0f5..cc6f2ba8c9f4 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -6314,6 +6314,11 @@ static void drm_parse_vrr_info(struct drm_display_in= fo *info, const u8 *hf_scds) struct drm_monitor_range_info *range =3D &info->monitor_range; const int pld_len =3D cea_db_payload_len(hf_scds); =20 + if (pld_len < 9) + return; + + info->hdmi.cinema_vrr =3D !!(hf_scds[8] & DRM_EDID_CINEMA_VRR); + if (pld_len < 10) return; =20 @@ -6392,7 +6397,7 @@ static void drm_parse_hdmi_forum_scds(struct drm_conn= ector *connector, =20 drm_parse_vrr_info(info, hf_scds); =20 - if (info->monitor_range.min_vfreq > 0) + if (info->monitor_range.min_vfreq > 0 || hdmi->cinema_vrr) hdmi->vrr_capable =3D true; else hdmi->vrr_capable =3D false; diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index b18684d039d5..b147b8474f1a 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -383,6 +383,9 @@ struct drm_hdmi_info { =20 /** @vrr_capable: The sink supports variable refresh rate */ bool vrr_capable; + + /** @cinema_vrr: The sink supports "CinemaVRR" */ + bool cinema_vrr; }; =20 /** --=20 2.55.0 From nobody Fri Sep 25 21:02:41 2026 Received: from sender4-pp-f112.zoho.com (sender4-pp-f112.zoho.com [136.143.188.112]) (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 B25734C2252; Mon, 21 Sep 2026 15:54:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=136.143.188.112 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790006042; cv=pass; b=U4EDz13KVCM/sz6+KrVzU5nmTG/LLzwDHwNZpHLWZxLaNGEF6n/gj/+yfKNTcFV4osJD1PJFBPMVadmaPpb5cLZbOVDw2BqEOrO+//5WEwziNS7HmYgajN2HWWiOvdD+a4DRWSTQtKuzX3MS4BAqiThXJczENxx8Hk4qlY0VCBU= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790006042; c=relaxed/simple; bh=SucLkbiXjq+ceXs1x5uTbroq7iKshDOiP4egQEXO0cE=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=pJXzgJ7EL39g1a9dMYXA7zPr5wy70urQcYkA0vQT6GH2r77uWD2BmWatWUgY3Iorh5Cw8Whr7Ih4d8kYykoGVZ5YrPDMKt2Rap6d3vDiu5xEvaflGM7+vS7UO8t6AYOLkXjL5PPi01C95kM+0tu0Q79xZyz+IJtqoHZFCXEJSQw= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (1024-bit key) header.d=collabora.com header.i=nicolas.frattaroli@collabora.com header.b=g6da8j9/; arc=pass smtp.client-ip=136.143.188.112 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=collabora.com header.i=nicolas.frattaroli@collabora.com header.b="g6da8j9/" ARC-Seal: i=1; a=rsa-sha256; t=1790005997; cv=none; d=zohomail.com; s=zohoarc; b=XahlPAYNjDzRctea301zGJHETm8cszOEd4hclQSx3BhQlOVrX56sZa2sbC07zTmRiV+6HeM07kk97xl7/zFEp/yVU4nXARI/dfxsX3iGzg6C3HBtjT/DYQ+FHXPE6yfvooAPVmXlz96ycY+/h2g0LO+TwhX6LVElp7GT5Re6DWA= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1790005997; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:MIME-Version:Message-ID:Subject:Subject:To:To:Message-Id:Reply-To; bh=/FoKRakhY4NsKczet48wwu0RDCyKt3DGaCiZ6bh1z0o=; b=H8JabL+G3SKEsM9FyVz/le7hCmsTcw9Z4ifRCodVQ8YVtPuvN/EUBrDy4On3i2doLwCi5GCgrx0Fuwm+UeLGvs0hvKC9CSZxj55ITUrME6oRjGdHL2faQpGCDC4mr2YcxMVPi5wUo/q9HKXTvYKeEY/6Sl4IpUdrdg3uvsftH1Y= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass header.i=collabora.com; spf=pass smtp.mailfrom=nicolas.frattaroli@collabora.com; dmarc=pass header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1790005997; s=zohomail; d=collabora.com; i=nicolas.frattaroli@collabora.com; h=From:From:Date:Date:Subject:Subject:MIME-Version:Content-Type:Content-Transfer-Encoding:Message-Id:Message-Id:In-Reply-To:To:To:Cc:Cc:Reply-To; bh=/FoKRakhY4NsKczet48wwu0RDCyKt3DGaCiZ6bh1z0o=; b=g6da8j9/euUYTP+py59U99/QEd4qOcDh0eHWCJXJ/EJTXlbJ+vX4zTkNXXHltAAf sX4+js/MMVyuDAyAIs2UnhE3r/tmZWZk125TOY068BYR2yCtQj0wA/JJRjJ7EFK56h1 iqyBOvHogPFrzdCS56u6i52IONlqL68S4inX7R7g= Received: by smtp.zohomail.com with SMTPS id 1790005995550693.3087509800898; Mon, 21 Sep 2026 08:53:15 -0700 (PDT) From: Nicolas Frattaroli Date: Mon, 21 Sep 2026 17:51:39 +0200 Subject: [PATCH RFC 13/25] drm: Add VRR target frame rate properties Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260921-vrr-limiter-uapi-v1-13-2fcd7d011646@collabora.com> References: <20260921-vrr-limiter-uapi-v1-0-2fcd7d011646@collabora.com> In-Reply-To: <20260921-vrr-limiter-uapi-v1-0-2fcd7d011646@collabora.com> To: "Borah, Chaitanya Kumar" , Leo Li , Daniel Stone , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Helge Deller , Andrzej Hajda , Neil Armstrong , Robert Foss , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Luca Ceresoli , Sandy Huang , =?utf-8?q?Heiko_St=C3=BCbner?= , Andy Yan Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, linux-fbdev@vger.kernel.org, linux-rockchip@lists.infradead.org, linux-arm-kernel@lists.infradead.org, kernel@collabora.com, Derek Foreman , wayland-devel@lists.freedesktop.org, Nicolas Frattaroli X-Mailer: b4 0.15.2 Userspace may wish to set a target frame rate for the Variable Refresh Rate mechanism. There are multiple possible ways such a target could be communicated. It's desirable for userspace to not only set a fixed target, but a target range within which VRR may operate. This is because even if a sink advertises a certain range as supported, said range may not be the ideal range to use, as numbers on the extreme end of the range may induce flickering or other glitches. There's four choices to how one bracketing value for the target range could be communicated: 1. Target frame rate in something like millihertz 2. Target frame period in something like usecs 3. Target vtotal value 4. Target frame rate as a fraction expressed by two integers Choice 1 is unpleasant as it would introduce some amount of rounding to common broadcast framerates like 24/1.001, which seems minor except that exact matches to standard framerates would rely on making all userspace and kernel agree on a specific method of rounding. This is sure to go wrong, so is disqualified. Choice 2 has the same problem as 1, with the added complication that the EDID's VRR range is expressed in frames per second, and other HDMI features express things in frames per second as well, which would require possibly imprecise computations. Choice 3 is disqualified as mechanisms other than VRR, such as FVA, may also modify the vtotal value. Additionally, it has the same drawbacks of choice 2 and 1. Choice 4 is therefore what's implemented. The frame rate 24/1.001Hz, for example, is expressed as nominator=3D24000 and denominator=3D1001. As there is both a minimum and a maximum, there are 4 properties in total: two numerators, and two denominators. A fixed rate with no variability is expressed by setting the minimum fractional and the maximum fractional properties to the same value. Signed-off-by: Nicolas Frattaroli --- drivers/gpu/drm/drm_atomic_uapi.c | 24 +++++++++++++++++++++ drivers/gpu/drm/drm_connector.c | 45 +++++++++++++++++++++++++++++++++++= ++++ drivers/gpu/drm/drm_crtc.c | 8 +++++++ drivers/gpu/drm/drm_mode_config.c | 20 +++++++++++++++++ include/drm/drm_crtc.h | 4 ++++ include/drm/drm_mode_config.h | 45 +++++++++++++++++++++++++++++++++++= ++++ 6 files changed, 146 insertions(+) diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic= _uapi.c index 1eebcf6f5e05..c9eb01d740b3 100644 --- a/drivers/gpu/drm/drm_atomic_uapi.c +++ b/drivers/gpu/drm/drm_atomic_uapi.c @@ -420,6 +420,22 @@ static int drm_atomic_crtc_set_property(struct drm_crt= c *crtc, return ret; } else if (property =3D=3D config->prop_vrr_enabled) { state->vrr_enabled =3D val; + } else if (property =3D=3D config->prop_vrr_min_numerator) { + if (val > U32_MAX) + return -EINVAL; + state->vrr_state.vrr_min_n =3D val; + } else if (property =3D=3D config->prop_vrr_min_denominator) { + if (val > U32_MAX) + return -EINVAL; + state->vrr_state.vrr_min_d =3D val; + } else if (property =3D=3D config->prop_vrr_max_numerator) { + if (val > U32_MAX) + return -EINVAL; + state->vrr_state.vrr_max_n =3D val; + } else if (property =3D=3D config->prop_vrr_max_denominator) { + if (val > U32_MAX) + return -EINVAL; + state->vrr_state.vrr_max_d =3D val; } else if (property =3D=3D config->degamma_lut_property) { const size_t elem_size =3D sizeof(struct drm_color_lut); u64 lut_size; @@ -505,6 +521,14 @@ drm_atomic_crtc_get_property(struct drm_crtc *crtc, *val =3D (state->mode_blob) ? state->mode_blob->base.id : 0; else if (property =3D=3D config->prop_vrr_enabled) *val =3D state->vrr_enabled; + else if (property =3D=3D config->prop_vrr_min_numerator) + *val =3D state->vrr_state.vrr_min_n; + else if (property =3D=3D config->prop_vrr_min_denominator) + *val =3D state->vrr_state.vrr_min_d; + else if (property =3D=3D config->prop_vrr_max_numerator) + *val =3D state->vrr_state.vrr_max_n; + else if (property =3D=3D config->prop_vrr_max_denominator) + *val =3D state->vrr_state.vrr_max_d; else if (property =3D=3D config->degamma_lut_property) *val =3D (state->degamma_lut) ? state->degamma_lut->base.id : 0; else if (property =3D=3D config->ctm_property) diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connecto= r.c index fc7d9fcf9d9f..5c07bd221977 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -2579,6 +2579,51 @@ EXPORT_SYMBOL(drm_mode_create_scaling_mode_property); * * The driver may place further restrictions within these minimum * and maximum bounds. + * + * VRR Limiter/Target Properties + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * The ``VRR_{MIN,MAX}_{NUMERATOR,DENOMINATOR}`` properties expose a mecha= nism + * through which userspace can control the desired range of refresh rates = in + * which VRR is allowed to operate. Each rate is expressed as a + * numerator/denominator fraction of refresh rates in Hz, allowing for rat= ional + * target rates like 24/1.001 Hz with no loss of precision or ambiguity. + * + * If the minimum and maximum rate are set to the same value (and not 0), = they + * are understood as a fixed target rate. This is especially useful for me= dia + * playback, where the content's frame rate is both constant and known in + * advance. In such cases, a refresh rate that is not an integer multiple = of the + * content's frame rate will introduce judder, since not every frame is + * displayed for the same amount of time. A modeset of the display with a + * compatible rate may in those cases be either undesirable or impossible,= but + * the rate can still effectively be reached through VRR. + * + * .. _VRR-MIN-NUMERATOR: + * + * "VRR_MIN_NUMERATOR": + * Default &drm_crtc integer property forming the numerator of a + * numerator/denominator pair of a frame rate to set as the minimum VRR + * target rate. Set to 0 to disable. + * + * "VRR_MIN_DENOMINATOR": + * Default &drm_crtc integer property forming the denominator of a + * numerator/denominator pair of a frame rate to set as the minimum VRR + * target rate. If :ref:`VRR_MIN_NUMERATOR ` is not + * zero, it must be non-zero. + * Otherwise, must also be zero. + * + * .. _VRR-MAX-NUMERATOR: + * + * "VRR_MAX_NUMERATOR": + * Default &drm_crtc integer property forming the numerator of a + * numerator/denominator pair of a frame rate to set as the maximum VRR + * target rate. Set to 0 to disable. + * + * "VRR_MAX_DENOMINATOR": + * Default &drm_crtc integer property forming the denominator of a + * numerator/denominator pair of a frame rate to set as the maximum VRR + * target rate. If :ref:`VRR_MAX_NUMERATOR ` is not + * zero, it must be non-zero. Otherwise, must also be zero. */ =20 /** diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 63ead8ba6756..9244fbf97029 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -322,6 +322,14 @@ static int __drm_crtc_init_with_planes(struct drm_devi= ce *dev, struct drm_crtc * config->prop_out_fence_ptr, 0); drm_object_attach_property(&crtc->base, config->prop_vrr_enabled, 0); + drm_object_attach_property(&crtc->base, + config->prop_vrr_min_numerator, 0); + drm_object_attach_property(&crtc->base, + config->prop_vrr_min_denominator, 0); + drm_object_attach_property(&crtc->base, + config->prop_vrr_max_numerator, 0); + drm_object_attach_property(&crtc->base, + config->prop_vrr_max_denominator, 0); } =20 return 0; diff --git a/drivers/gpu/drm/drm_mode_config.c b/drivers/gpu/drm/drm_mode_c= onfig.c index 48a56f23dadb..da967d60f832 100644 --- a/drivers/gpu/drm/drm_mode_config.c +++ b/drivers/gpu/drm/drm_mode_config.c @@ -535,6 +535,26 @@ static int drm_mode_create_standard_properties(struct = drm_device *dev) return -ENOMEM; dev->mode_config.prop_vrr_enabled =3D prop; =20 + prop =3D drm_property_create_range(dev, 0, "VRR_MIN_NUMERATOR", 0, U32_MA= X); + if (!prop) + return -ENOMEM; + dev->mode_config.prop_vrr_min_numerator =3D prop; + + prop =3D drm_property_create_range(dev, 0, "VRR_MIN_DENOMINATOR", 0, U32_= MAX); + if (!prop) + return -ENOMEM; + dev->mode_config.prop_vrr_min_denominator =3D prop; + + prop =3D drm_property_create_range(dev, 0, "VRR_MAX_NUMERATOR", 0, U32_MA= X); + if (!prop) + return -ENOMEM; + dev->mode_config.prop_vrr_max_numerator =3D prop; + + prop =3D drm_property_create_range(dev, 0, "VRR_MAX_DENOMINATOR", 0, U32_= MAX); + if (!prop) + return -ENOMEM; + dev->mode_config.prop_vrr_max_denominator =3D prop; + prop =3D drm_property_create(dev, DRM_MODE_PROP_BLOB, "DEGAMMA_LUT", 0); diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 9d58158af459..df37f4ebb58e 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -67,6 +67,10 @@ struct drm_crtc_vrr_state { u8 vic; u16 cur_vtotal; u16 max_vtotal; + u32 vrr_min_n; + u32 vrr_min_d; + u32 vrr_max_n; + u32 vrr_max_d; u16 base_vtotal; bool dynamic; }; diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h index 084517beb924..c8d5286f9267 100644 --- a/include/drm/drm_mode_config.h +++ b/include/drm/drm_mode_config.h @@ -702,6 +702,51 @@ struct drm_mode_config { */ struct drm_property *prop_vrr_enabled; =20 + /** + * @prop_vrr_min_numerator: Default atomic CRTC property to indicate the + * numerator of a numerator/denominator variable refresh rate minimum + * target frame rate. + * + * If not zero, @prop_vrr_min_numerator divided by + * @prop_vrr_min_denominator must result in a frame rate above the + * sink's minimum VRR rate. + */ + struct drm_property *prop_vrr_min_numerator; + + /** + * @prop_vrr_min_denominator: Default atomic CRTC property to indicate + * the denominator of a numerator/denominator variable refresh rate + * minimum target frame rate. + * + * If @prop_vrr_min_numerator is set, @prop_vrr_min_denominator must not + * be 0, and @prop_vrr_min_numerator divided by @prop_vrr_min_denominator + * must result in a frame rate above the minimum VRR rate. + */ + struct drm_property *prop_vrr_min_denominator; + + /** + * @prop_vrr_max_numerator: Default atomic CRTC property to indicate the + * numerator of a numerator/denominator variable refresh rate maximum + * target frame rate range. + * + * The fraction expressed by this property divided by its corresponding + * denominator must be equal to or greater than the value of + * @prop_vrr_min_numerator. + */ + struct drm_property *prop_vrr_max_numerator; + + /** + * @prop_vrr_max_denominator: Default atomic CRTC property to indicate + * the denominator of a numerator/denominator variable refresh rate + * maximum target frame rate range. + * + * If @prop_vrr_max_numerator is set, @prop_vrr_max_denominator must not + * be 0, and @prop_vrr_max_numerator divided by @prop_vrr_max_denominator + * must result in a frame rate equal to or above @prop_vrr_min_numerator + * divided by @prop_vrr_min_denominator. + */ + struct drm_property *prop_vrr_max_denominator; + /** * @dvi_i_subconnector_property: Optional DVI-I property to * differentiate between analog or digital mode. --=20 2.55.0 From nobody Fri Sep 25 21:02:41 2026 Received: from sender4-pp-f112.zoho.com (sender4-pp-f112.zoho.com [136.143.188.112]) (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 0DC1B4B8260; Mon, 21 Sep 2026 15:54:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=136.143.188.112 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790006050; cv=pass; b=DSrddvRu2fG2HRYAlGZGi2S14y4In3XRddooF0wxXsbhOmWB2SZY33iacABAb8AlPzih5lqj1xpnWkP/auO1AaU2B9ZcBPg8/FJ1OjP8iZ6fDUBDym7aByDrLDfVHDnbQtox0TKaGPhTUiGhWJiT38VXnguylnh7XWhNsVvsAzc= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790006050; c=relaxed/simple; bh=Q7jbDEF67e0ZNFDuThOV0VAu04swd23Jp1F6u0D98eI=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=PQLwjzqstY2fB8QxO2mxWG0mZtfs++PLNJNZLG5okgRwYH4ZF5tFEBjylV8ig5K/LVn/SrIlndetW9OWs2KoDQ7esidAm2J9YYMM95NRblT2vsxoD1GmgX/B2Scarnmay1sOoQf6D5MU/dc6ERnBYFoJmRQ2+AXB1Ra6ps2K1Z8= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (1024-bit key) header.d=collabora.com header.i=nicolas.frattaroli@collabora.com header.b=I2ERqQNv; arc=pass smtp.client-ip=136.143.188.112 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=collabora.com header.i=nicolas.frattaroli@collabora.com header.b="I2ERqQNv" ARC-Seal: i=1; a=rsa-sha256; t=1790006001; cv=none; d=zohomail.com; s=zohoarc; b=N7vVbuDej8VgLQ0DPVwNy3IK5WoD21dk+inFRdNbFD7BqFslISshLYyfchcjIatQsMl/bqHx0OCyBVQOrduuW3/jCuZXrhdo2JYAC0gvimhb5rOFS0jCyKC9xrJaGprCy4oFpLxEuu7XJ64YfU3KkHzdng1vR+usDjqyuD1/HvI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1790006001; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:MIME-Version:Message-ID:Subject:Subject:To:To:Message-Id:Reply-To; bh=2340rAUPh+cjIYbPiCBSqhKVXnIH+nymunIe5WSMkVg=; b=ZiWc8eitpYdEBN2y5Po87aQK+D2baoB5LfseFiKOiL0JGjMTxPVhCFVb/DCYcTC0SgQgIq8CgqnCl/GbzdS99sVtIx6Ygp9xsYB5DucByzGjOvSNdqlrPDXrl0pcKmKfLaRgAxYYy56yHq4V1cSGv5a3qM7elZtJtxSCkxVpQb0= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass header.i=collabora.com; spf=pass smtp.mailfrom=nicolas.frattaroli@collabora.com; dmarc=pass header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1790006001; s=zohomail; d=collabora.com; i=nicolas.frattaroli@collabora.com; h=From:From:Date:Date:Subject:Subject:MIME-Version:Content-Type:Content-Transfer-Encoding:Message-Id:Message-Id:In-Reply-To:To:To:Cc:Cc:Reply-To; bh=2340rAUPh+cjIYbPiCBSqhKVXnIH+nymunIe5WSMkVg=; b=I2ERqQNvVfm9A861OCq83Nz52IWUOpUIRkcyMwvJYfrdpGStzz+z690BUerdYOrB /EybheP/knZ22rMkIekvoh3p7dVokjwuF0wNx1kwJpElTYgNRPDO/qsHlItch6lVikV 1MtT8VUhLAFsTHeFKb+hyS/ETXLvi/R7zfmO7jeE= Received: by smtp.zohomail.com with SMTPS id 1790006000937510.4944678062657; Mon, 21 Sep 2026 08:53:20 -0700 (PDT) From: Nicolas Frattaroli Date: Mon, 21 Sep 2026 17:51:40 +0200 Subject: [PATCH RFC 14/25] drm: Implement VRR rate limiting Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260921-vrr-limiter-uapi-v1-14-2fcd7d011646@collabora.com> References: <20260921-vrr-limiter-uapi-v1-0-2fcd7d011646@collabora.com> In-Reply-To: <20260921-vrr-limiter-uapi-v1-0-2fcd7d011646@collabora.com> To: "Borah, Chaitanya Kumar" , Leo Li , Daniel Stone , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Helge Deller , Andrzej Hajda , Neil Armstrong , Robert Foss , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Luca Ceresoli , Sandy Huang , =?utf-8?q?Heiko_St=C3=BCbner?= , Andy Yan Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, linux-fbdev@vger.kernel.org, linux-rockchip@lists.infradead.org, linux-arm-kernel@lists.infradead.org, kernel@collabora.com, Derek Foreman , wayland-devel@lists.freedesktop.org, Nicolas Frattaroli X-Mailer: b4 0.15.2 Currently, VRR is allowed to use the entire range advertised by the sink's EDID. Userspace may find it desirable, however, to limit this range, or set a fixed target rate entirely. The latter is mainly useful for multimedia playback applications, where judder can be avoided by matching the content's frame rate precisely. With the new VRR target frame rate properties, the necessary infrastructure is in place to allow implementing this. Add the necessary logic to hdmi_validate_vrr, as well as the VRR helpers. Since not every target rate can be reached precisely, the per-frame error is calculated, and dithered one row at a time across subsequent frames. This means some frames are one vtotal larger than others, so that averaged over the frames, the desired target rate is achieved. Such dithering is explicitly permitted by HDMI, and is still considered a constant target frame rate. Co-developed-by: Derek Foreman Signed-off-by: Derek Foreman Signed-off-by: Nicolas Frattaroli --- drivers/gpu/drm/display/drm_hdmi_state_helper.c | 108 ++++++++++++++++++++= ---- drivers/gpu/drm/drm_crtc_helper.c | 34 +++++++- include/drm/drm_crtc.h | 3 + include/drm/drm_crtc_helper.h | 2 + 4 files changed, 130 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/= drm/display/drm_hdmi_state_helper.c index 33d0c9491643..7dbd678cf061 100644 --- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c +++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c @@ -5,6 +5,7 @@ =20 #include #include +#include #include #include #include @@ -1046,6 +1047,39 @@ static int hdmi_calculate_vtotal(const struct drm_di= splay_mode *mode, return 0; } =20 +static int hdmi_validate_vrr_limits(struct drm_crtc_state *crtc_state, u16= vrr_min) +{ + struct drm_crtc_vrr_state *vrr_state =3D &crtc_state->vrr_state; + const struct drm_display_mode *mode =3D &crtc_state->mode; + u32 limit_d; + int ret; + + /* No limiter, don't need to validate, but reset the error */ + if (!drm_crtc_helper_vrr_is_fixed_rate(vrr_state)) { + vrr_state->per_frame_err =3D 0; + return 0; + } + + /* Don't allow rates equal to or below the minimum VRR rate / 1.001 */ + if (cmp_fraction(vrr_state->vrr_min_n, vrr_state->vrr_min_d, + vrr_min * 1000, 1001) < 0) + return -EINVAL; + + if (check_mul_overflow(mode->crtc_htotal, vrr_state->vrr_min_n, &limit_d)) + return -ERANGE; + + ret =3D hdmi_calculate_vtotal(&crtc_state->mode, vrr_state->vrr_min_n, + vrr_state->vrr_min_d, &vrr_state->base_vtotal, + &vrr_state->denom, &vrr_state->per_frame_err); + if (ret) + return ret; + + if (vrr_state->base_vtotal < mode->crtc_vtotal) + return -EINVAL; + + return 0; +} + static int hdmi_validate_vrr(struct drm_connector *connector, struct drm_atomic_commit *state) { @@ -1067,6 +1101,7 @@ static int hdmi_validate_vrr(struct drm_connector *co= nnector, u32 min_vfreq_d =3D 1; u32 max_vfreq_n =3D info->monitor_range.max_vfreq; u32 max_vfreq_d =3D 1; + bool is_fixed; =20 /* Save on the expensive vic lookup, if nothing else. */ if (!new_crtc_state->mode_changed && @@ -1099,6 +1134,10 @@ static int hdmi_validate_vrr(struct drm_connector *c= onnector, if (!max_vfreq_n || max_vfreq_n > mode_refresh) max_vfreq_n =3D mode_refresh; =20 + is_fixed =3D drm_crtc_helper_vrr_is_fixed_rate(vrr_state); + if (is_fixed && info->hdmi.cinema_vrr) + min_vfreq_n =3D 24; + if (!min_vfreq_n) { drm_dbg_kms(dev, "Could not get minimum VRR rate from sink\n"); return -EINVAL; @@ -1112,25 +1151,64 @@ static int hdmi_validate_vrr(struct drm_connector *= connector, =20 vrr_state->vic =3D drm_match_cea_mode(mode); =20 - if (cmp_fraction(min_vfreq_n, min_vfreq_d, max_vfreq_n, max_vfreq_d) > 0)= { - drm_dbg_kms(dev, "Target max (%u/%u) > target min (%u/%u)\n", - max_vfreq_n, max_vfreq_d, min_vfreq_n, min_vfreq_d); - return -EINVAL; - } - - ret =3D hdmi_calculate_vtotal(mode, max_vfreq_n, max_vfreq_d, - &vrr_state->base_vtotal, NULL, NULL); + ret =3D hdmi_validate_vrr_limits(new_crtc_state, min_vfreq_n); if (ret) { - drm_dbg_kms(dev, "Couldn't calculate base_vtotal: %pe\n", ERR_PTR(ret)); + drm_dbg_kms(dev, "Invalid VRR fixed target rate: %pe\n", ERR_PTR(ret)); return ret; } =20 - /* - * Even at its fastest, it can't go faster than the mode, so - * clamp to avoid imprecisely rounded mode_refresh values we - * can't do anything about from ruining our day. - */ - vrr_state->base_vtotal =3D max(vrr_state->base_vtotal, mode->crtc_vtotal); + if (!is_fixed) { + vrr_state->dynamic =3D true; + + if (vrr_state->vrr_min_n) { + if (!vrr_state->vrr_min_d) + return -EINVAL; + + if (cmp_fraction(vrr_state->vrr_min_n, vrr_state->vrr_min_d, + min_vfreq_n * 1000, 1001) < 0) { + drm_dbg_kms(dev, "Target min (%u/%u) < supported min (%u/%u)\n", + vrr_state->vrr_min_n, vrr_state->vrr_min_d, + min_vfreq_n, min_vfreq_d); + return -EINVAL; + } + min_vfreq_n =3D vrr_state->vrr_min_n; + min_vfreq_d =3D vrr_state->vrr_min_d; + } + if (vrr_state->vrr_max_n) { + if (!vrr_state->vrr_max_d) + return -EINVAL; + + if (cmp_fraction(vrr_state->vrr_max_n, vrr_state->vrr_max_d, + max_vfreq_n, max_vfreq_d) > 0) { + drm_dbg_kms(dev, "Target max (%u/%u) > supported max (%u/%u)\n", + vrr_state->vrr_max_n, vrr_state->vrr_max_d, + max_vfreq_n, max_vfreq_d); + return -EINVAL; + } + max_vfreq_n =3D vrr_state->vrr_max_n; + max_vfreq_d =3D vrr_state->vrr_max_d; + } + if (cmp_fraction(min_vfreq_n, min_vfreq_d, max_vfreq_n, max_vfreq_d) > 0= ) { + drm_dbg_kms(dev, "Target max (%u/%u) > target min (%u/%u)\n", + max_vfreq_n, max_vfreq_d, min_vfreq_n, min_vfreq_d); + return -EINVAL; + } + + ret =3D hdmi_calculate_vtotal(mode, max_vfreq_n, max_vfreq_d, + &vrr_state->base_vtotal, NULL, NULL); + if (ret) { + drm_dbg_kms(dev, "Couldn't calculate base_vtotal: %pe\n", ERR_PTR(ret)); + return ret; + } + + /* + * Even at its fastest, it can't go faster than the mode, so + * clamp to avoid imprecisely rounded mode_refresh values we + * can't do anything about from ruining our day. + */ + vrr_state->base_vtotal =3D max(vrr_state->base_vtotal, + mode->crtc_vtotal); + } =20 if (cmp_fraction(min_vfreq_n, min_vfreq_d, mode_refresh, 1) >=3D 0) { /* refresh <=3D VRR min, don't do VRR vtotal adjustment */ diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_h= elper.c index 4ffb3b0b7878..c46de778df30 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -838,6 +838,22 @@ int drm_crtc_helper_set_config(struct drm_mode_set *se= t, } EXPORT_SYMBOL(drm_crtc_helper_set_config); =20 +bool drm_crtc_helper_vrr_is_fixed_rate(const struct drm_crtc_vrr_state *vr= r) +{ + if (!vrr->vrr_min_n) + return false; + + if (!vrr->vrr_min_d || !vrr->vrr_max_d) + return false; + + if (mul_u32_u32(vrr->vrr_min_n, vrr->vrr_max_d) =3D=3D + mul_u32_u32(vrr->vrr_min_d, vrr->vrr_max_n)) + return true; + + return false; +} +EXPORT_SYMBOL(drm_crtc_helper_vrr_is_fixed_rate); + /** * drm_crtc_helper_vrr_flush - Update VRR state on frame ready * @crtc_state: pointer to &struct drm_crtc_state of CRTC that has a new f= rame ready @@ -864,6 +880,9 @@ bool drm_crtc_helper_vrr_flush(struct drm_crtc_state *c= rtc_state) return false; } =20 + if (drm_crtc_helper_vrr_is_fixed_rate(vrr)) + return false; + if (vrr->cur_vtotal =3D=3D vrr->base_vtotal) return false; =20 @@ -889,10 +908,21 @@ bool drm_crtc_helper_vrr_vsync(struct drm_crtc_state = *crtc_state) struct drm_crtc_vrr_state *vrr =3D &crtc_state->vrr_state; u16 old_vtotal =3D vrr->cur_vtotal; =20 - if (!crtc_state->vrr_enabled) + if (!crtc_state->vrr_enabled) { vrr->cur_vtotal =3D 0; - else + vrr->cur_err =3D 0; + } else if (drm_crtc_helper_vrr_is_fixed_rate(vrr)) { + if (vrr->cur_err * 2 >=3D vrr->denom) { + vrr->cur_err -=3D vrr->denom; + vrr->cur_vtotal =3D vrr->base_vtotal + 1; + } else { + vrr->cur_vtotal =3D vrr->base_vtotal; + } + + vrr->cur_err +=3D vrr->per_frame_err; + } else { vrr->cur_vtotal =3D vrr->max_vtotal; + } =20 if (abs_diff(vrr->cur_vtotal, old_vtotal) > 1) vrr->dynamic =3D true; diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index df37f4ebb58e..00e9df02f3d5 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -71,6 +71,9 @@ struct drm_crtc_vrr_state { u32 vrr_min_d; u32 vrr_max_n; u32 vrr_max_d; + u32 denom; + u32 per_frame_err; + int cur_err; u16 base_vtotal; bool dynamic; }; diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index 0c8c11ea36dd..7d7b75045bd9 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -45,6 +45,7 @@ struct drm_framebuffer; struct drm_mode_set; struct drm_modeset_acquire_ctx; struct drm_crtc_state; +struct drm_crtc_vrr_state; =20 void drm_helper_disable_unused_functions(struct drm_device *dev); int drm_crtc_helper_set_config(struct drm_mode_set *set, @@ -63,6 +64,7 @@ int drm_helper_connector_dpms(struct drm_connector *conne= ctor, int mode); void drm_helper_resume_force_mode(struct drm_device *dev); int drm_helper_force_disable_all(struct drm_device *dev); =20 +bool drm_crtc_helper_vrr_is_fixed_rate(const struct drm_crtc_vrr_state *vr= r); bool drm_crtc_helper_vrr_flush(struct drm_crtc_state *crtc_state); bool drm_crtc_helper_vrr_vsync(struct drm_crtc_state *crtc_state); =20 --=20 2.55.0 From nobody Fri Sep 25 21:02:41 2026 Received: from sender4-pp-f112.zoho.com (sender4-pp-f112.zoho.com [136.143.188.112]) (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 938044C651F; Mon, 21 Sep 2026 15:54:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=136.143.188.112 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790006053; cv=pass; b=lDYuU7sWYPvWO+4sAU/fhy8SyTHA8Fg7tO18qz49KIS4r6qnRkxs6nAXlWPH9nnf/CmdFuF5/ouFtz98NeEc6HRmyI1a2M0sjfkRsyoEv/ENuC+spEMq+2GkZdJb9Hd/mIRzppjE1kD40IcHyZZmZzxsE9DKZuOofQJWsiKsRvI= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790006053; c=relaxed/simple; bh=O1W6VsCsNZ1ZwYBnqbivdpIQYLrQb27Ko83kNwPVyWc=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=FYTu7WJSprzviQuchkEjLlEhNqu2rrB6pgcoDUyVLR2ef6FVgP5+OvdQt/ECweMwjjZy/TTBXXqTZYMDv1CMcdpM48mGdjS5JsNzRYOs+wu+W6LqBi+CoxdwsTcJM872askxtony2hynNavkgCWZ6tgXYTQjOh5CcAeDLaQwY2M= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (1024-bit key) header.d=collabora.com header.i=nicolas.frattaroli@collabora.com header.b=a3AaHo/U; arc=pass smtp.client-ip=136.143.188.112 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=collabora.com header.i=nicolas.frattaroli@collabora.com header.b="a3AaHo/U" ARC-Seal: i=1; a=rsa-sha256; t=1790006007; cv=none; d=zohomail.com; s=zohoarc; b=ngcSx7tEb9T4eSKiUPia8xy5VnT8S4gMkwpOI5+/OKpbDFPTx/YwY5JO5tyldcqZjCXry6MhYEddp6UvxdiDznsK70yz4KmeB6jZMjgP4kKJS6ucjl2mtaFG7+cERrw4DfcGV9I7c2KUixhvLqqISWiuDt1SD+f9TMn4MLXTvlE= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1790006007; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:MIME-Version:Message-ID:Subject:Subject:To:To:Message-Id:Reply-To; bh=53MU4wodU5McFdFA8f4erFf1XjxuC7banbaoGYK3RK8=; b=OhC+ygNeEbKIliqfx1Igb0yeYHO1//55xpLvxp6mJkmDEMBmx5Aa/fNuCxXtkmz+qz5La+TzzoaF1+lodk9bR19T4xBJg6UN1mVmiLhMmgI6sxhbvxCa5n9+AuGrA0Ullr3WMcN8xxYufJJuD7P0qlinz2NV1TXHKJgIJWSfm/4= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass header.i=collabora.com; spf=pass smtp.mailfrom=nicolas.frattaroli@collabora.com; dmarc=pass header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1790006007; s=zohomail; d=collabora.com; i=nicolas.frattaroli@collabora.com; h=From:From:Date:Date:Subject:Subject:MIME-Version:Content-Type:Content-Transfer-Encoding:Message-Id:Message-Id:In-Reply-To:To:To:Cc:Cc:Reply-To; bh=53MU4wodU5McFdFA8f4erFf1XjxuC7banbaoGYK3RK8=; b=a3AaHo/UK2z7zkPs7JYtVfyLRknGywm+GDwp4vuHtWfHl2Ilvs9ny5uzGEAlOnCc gHTB1XdD2Y9vG7rYo9xkTMg2zIaaOJIP6+eUTtlNM7WSZKQCw1g8QeqQ3GsIITqlqcm w+Y6aLF953pelao+OvCTaLu0o5cq23i1+mGcK7xA= Received: by smtp.zohomail.com with SMTPS id 1790006006273303.45353173764124; Mon, 21 Sep 2026 08:53:26 -0700 (PDT) From: Nicolas Frattaroli Date: Mon, 21 Sep 2026 17:51:41 +0200 Subject: [PATCH RFC 15/25] drm/edid: Parse QMS flag from HDMI SCDS Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260921-vrr-limiter-uapi-v1-15-2fcd7d011646@collabora.com> References: <20260921-vrr-limiter-uapi-v1-0-2fcd7d011646@collabora.com> In-Reply-To: <20260921-vrr-limiter-uapi-v1-0-2fcd7d011646@collabora.com> To: "Borah, Chaitanya Kumar" , Leo Li , Daniel Stone , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Helge Deller , Andrzej Hajda , Neil Armstrong , Robert Foss , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Luca Ceresoli , Sandy Huang , =?utf-8?q?Heiko_St=C3=BCbner?= , Andy Yan Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, linux-fbdev@vger.kernel.org, linux-rockchip@lists.infradead.org, linux-arm-kernel@lists.infradead.org, kernel@collabora.com, Derek Foreman , wayland-devel@lists.freedesktop.org, Nicolas Frattaroli X-Mailer: b4 0.15.2 Thanks to a GPL'd source code release from a hardware vendor that shall not be named, which has since been scrubbed off GitHub, it's now public knowledge how the HDMI Forum EDID extension communicates support for QMS ("Quick Media Switching") on a sink. Bit number 6 indicates support for QMS in the same byte that also contains the CinemaVRR flag. Add this definition to the EDID header file, and parse it to a member of drm_hdmi_info. Signed-off-by: Nicolas Frattaroli --- drivers/gpu/drm/drm_edid.c | 1 + include/drm/drm_connector.h | 3 +++ include/drm/drm_edid.h | 1 + 3 files changed, 5 insertions(+) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index cc6f2ba8c9f4..5a7d3b7e65da 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -6318,6 +6318,7 @@ static void drm_parse_vrr_info(struct drm_display_inf= o *info, const u8 *hf_scds) return; =20 info->hdmi.cinema_vrr =3D !!(hf_scds[8] & DRM_EDID_CINEMA_VRR); + info->hdmi.qms_capable =3D !!(hf_scds[8] & DRM_EDID_QMS); =20 if (pld_len < 10) return; diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index b147b8474f1a..c97cf0625fda 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -386,6 +386,9 @@ struct drm_hdmi_info { =20 /** @cinema_vrr: The sink supports "CinemaVRR" */ bool cinema_vrr; + + /** @qms_capable: The sink supports Quick Media Switching */ + bool qms_capable; }; =20 /** diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index a2617aa34edf..f1e2052cb08b 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -265,6 +265,7 @@ struct detailed_timing { #define DRM_EDID_CNMVRR (1 << 3) #define DRM_EDID_CINEMA_VRR (1 << 4) #define DRM_EDID_MDELTA (1 << 5) +#define DRM_EDID_QMS (1 << 6) #define DRM_EDID_VRR_MAX_UPPER_MASK 0xc0 #define DRM_EDID_VRR_MAX_LOWER_MASK 0xff #define DRM_EDID_VRR_MIN_MASK 0x3f --=20 2.55.0 From nobody Fri Sep 25 21:02:41 2026 Received: from sender4-pp-f112.zoho.com (sender4-pp-f112.zoho.com [136.143.188.112]) (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 DB2934BB282; Mon, 21 Sep 2026 15:54:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=136.143.188.112 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790006062; cv=pass; b=sP3GIwejOSAsuYysgdyAh/kNyDqrHxW9x0I1BGHBTbnmHfLpqCjJHTz4gJBLUDvBMQzrC491191aCUD41+5yHlDDmeCnnbBZ1b2va8RKpvnOKflELuH2Rhx0tiaJJw/Iqvwwr5f2237GDxk38REjnLNm/q676OWtWszTaw+aY7I= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790006062; c=relaxed/simple; bh=9cFQpY0yIO87qIUyReDYrG9xxNE4tGwYPF9f+CuztTg=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=H3z4GdHcDozmM+KiO6B3emwjyJu5gJr8aRgGtYyiT4/VN75njGLM/r+ctxhDq5hELLQvjF20Ah/GC6BF5vAkv+FYvlFGjxA/QPztbEFvL2TTo4Ozly2HfU1iIi+57ezZUp3fRvBmvQW76es6RIsE84eRQiU4L2jOsyKQh13xTLA= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (1024-bit key) header.d=collabora.com header.i=nicolas.frattaroli@collabora.com header.b=asM16uei; arc=pass smtp.client-ip=136.143.188.112 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=collabora.com header.i=nicolas.frattaroli@collabora.com header.b="asM16uei" ARC-Seal: i=1; a=rsa-sha256; t=1790006013; cv=none; d=zohomail.com; s=zohoarc; b=mhxCIXPZ/+yEWUs1KgkZV/vPnjfe7MnmXqHd3FK9x+cOipio3AmrlBcvB623LhMN5Ee+IioCcYq+8mOPzQ9uJrJxg24Yv/otVDnPAZ4SIr6IRAtzue/HL4ZEjq4+xSylwUzGnCHVDuF2IXXtC/jqcye6GYmFbW0pacWgmjHQIzg= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1790006013; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:MIME-Version:Message-ID:Subject:Subject:To:To:Message-Id:Reply-To; bh=7klLKTxAqVvbufalhg35HG2HNYZ1gcqMNTnMqVx0mHY=; b=NW3OjKIFNJPYSqRYjjDTpZIeT4IE4hY60OuBMDKc3ZHjU388vwZtknP7N4QwyaAmGYIAnaXxsh/3bXoVMclnGIETLsYEdXNXaAorN229eE+fgiZoxGBvZBJQ06L1Xh5GlY2Ge/E3eAQE6OjjFt0xt4BCunbTbgmWSdLux3Mowsw= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass header.i=collabora.com; spf=pass smtp.mailfrom=nicolas.frattaroli@collabora.com; dmarc=pass header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1790006013; s=zohomail; d=collabora.com; i=nicolas.frattaroli@collabora.com; h=From:From:Date:Date:Subject:Subject:MIME-Version:Content-Type:Content-Transfer-Encoding:Message-Id:Message-Id:In-Reply-To:To:To:Cc:Cc:Reply-To; bh=7klLKTxAqVvbufalhg35HG2HNYZ1gcqMNTnMqVx0mHY=; b=asM16ueiap+8yleJX486m23IDB91JBay041dbXpcDeJ/7nc2/i3hj+SS107jzWyW keL71rS8GRFqp6ndLhaG4cifBJggDHseN1xiG7ezsg2trvX7WdLrDD7pMBxZPIofX0S /9wl8xIW2JWWkEO1cqISCDU+sEzA8hosb7wWDlzw= Received: by smtp.zohomail.com with SMTPS id 1790006011932527.0501784463283; Mon, 21 Sep 2026 08:53:31 -0700 (PDT) From: Nicolas Frattaroli Date: Mon, 21 Sep 2026 17:51:42 +0200 Subject: [PATCH RFC 16/25] drm/edid: Parse QMS TFR min/max flags from HDMI SCDS Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260921-vrr-limiter-uapi-v1-16-2fcd7d011646@collabora.com> References: <20260921-vrr-limiter-uapi-v1-0-2fcd7d011646@collabora.com> In-Reply-To: <20260921-vrr-limiter-uapi-v1-0-2fcd7d011646@collabora.com> To: "Borah, Chaitanya Kumar" , Leo Li , Daniel Stone , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Helge Deller , Andrzej Hajda , Neil Armstrong , Robert Foss , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Luca Ceresoli , Sandy Huang , =?utf-8?q?Heiko_St=C3=BCbner?= , Andy Yan Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, linux-fbdev@vger.kernel.org, linux-rockchip@lists.infradead.org, linux-arm-kernel@lists.infradead.org, kernel@collabora.com, Derek Foreman , wayland-devel@lists.freedesktop.org, Nicolas Frattaroli X-Mailer: b4 0.15.2 HDMI has two flags in the SCDS EDID extension that signal which minimum and maximum refresh rate the sink wishes to use when doing QMS ("Quick Media Switching"). How to parse these flags, and what they do, has been learned from the publicly available libdisplay-info source code. Add the definitions of where in the byte they are, the code for checking for them, as well as two new booleans in drm_hdmi_info to store the result. Signed-off-by: Nicolas Frattaroli --- drivers/gpu/drm/drm_edid.c | 6 ++++++ include/drm/drm_connector.h | 12 ++++++++++++ include/drm/drm_edid.h | 2 ++ 3 files changed, 20 insertions(+) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 5a7d3b7e65da..4fe754328b1c 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -6332,6 +6332,12 @@ static void drm_parse_vrr_info(struct drm_display_in= fo *info, const u8 *hf_scds) if (!range->max_vfreq) range->max_vfreq =3D (FIELD_GET(DRM_EDID_VRR_MAX_UPPER_MASK, hf_scds[9])= << 8) | hf_scds[10]; + + if (pld_len < 12) + return; + + info->hdmi.qms_tfr_min =3D !!(hf_scds[11] & DRM_EDID_QMS_TFR_MIN); + info->hdmi.qms_tfr_max =3D !!(hf_scds[11] & DRM_EDID_QMS_TFR_MAX); } =20 /* Sink Capability Data Structure */ diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index c97cf0625fda..8439c82db905 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -389,6 +389,18 @@ struct drm_hdmi_info { =20 /** @qms_capable: The sink supports Quick Media Switching */ bool qms_capable; + + /** + * @qms_tfr_min: If set, the sink uses 24/1.001Hz as its minimum rate + * for QMS. If unset, @drm_display_info.monitor_range.min_vfreq is used. + */ + bool qms_tfr_min; + + /** + * @qms_tfr_max: If set, @drm_display_info.monitor_range.max_vfreq is + * used by the sink as its maximum rate for QMS. If unset, 60Hz is used. + */ + bool qms_tfr_max; }; =20 /** diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index f1e2052cb08b..d339acd9ee52 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -269,6 +269,8 @@ struct detailed_timing { #define DRM_EDID_VRR_MAX_UPPER_MASK 0xc0 #define DRM_EDID_VRR_MAX_LOWER_MASK 0xff #define DRM_EDID_VRR_MIN_MASK 0x3f +#define DRM_EDID_QMS_TFR_MIN (1 << 4) +#define DRM_EDID_QMS_TFR_MAX (1 << 5) =20 /* DSC specific */ #define DRM_EDID_DSC_10BPC (1 << 0) --=20 2.55.0 From nobody Fri Sep 25 21:02:41 2026 Received: from sender4-pp-f112.zoho.com (sender4-pp-f112.zoho.com [136.143.188.112]) (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 2BB1B3F412B; Mon, 21 Sep 2026 15:54:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=136.143.188.112 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790006069; cv=pass; b=pxJPXLHkPH3eIc0jXEEIQ4qNp1pxmEQSbpr9dR5bWr7+56Dh9PSG54c3fs2OGxoMk1CxSMYuUc1NUMtMzTdoOZBHWA0wQt8I1iCr0F+R2HP/N4KE7ixKdZwKPPMaDsl9VYGOmfjyoy7J+UZOFXVMd6FsnP9vpNei/b0yQogMRDU= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790006069; c=relaxed/simple; bh=gh/uvGjwn8SMV66kD+6Hw1bNWx2xvLmcIJHzppDJmOE=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=qnLKjfK0JMFrAyt15L1624w5f9R2x4UQMw5rQhMcNpZbZ9na2wUMC5APlwFIOy0pxCTxj6chWllU4cClOQlkS2GujSQSa9LPYU1JW4tR3UoMA/6dRfIeq3Jb6oL85FNoDHhsbwvCAyd8zUHMRzkWemPGXdR5uvL2u0tHzRwOOeo= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (1024-bit key) header.d=collabora.com header.i=nicolas.frattaroli@collabora.com header.b=GdeTVI9/; arc=pass smtp.client-ip=136.143.188.112 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=collabora.com header.i=nicolas.frattaroli@collabora.com header.b="GdeTVI9/" ARC-Seal: i=1; a=rsa-sha256; t=1790006019; cv=none; d=zohomail.com; s=zohoarc; b=FTQ+bvPpqX8tKRr0WxT41jf+nn2CdZ26Q9PHySm9ZIiIFUbLRnbR75xkBQu9GHzeR/tTUKZcwo2nflRM1dZJoRuQmwVGlh9KPMNxgnyFXevwStMe9LrL/oy9dzqrgrUAvd3e+lJCx6ihylP04I21TFz/xGE9ig3bKvURuGKUbPQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1790006019; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:MIME-Version:Message-ID:Subject:Subject:To:To:Message-Id:Reply-To; bh=Y6pNKsL2/kxw9VEVLNj37g/I6SH0Xh54QzUA4fywo6s=; b=gjteqq/+Zr4bW7WKNFL6tCXHISRNB5IvV0jawTTOaHkdzDrSTDtXSbZlZhGMfZEM6hw0ROZK2JQ/X35/S5SspXl0jOL/mrw+ESKF2ButbTsltpsCZYV0akSKwYXNNTbYucAUmGxnfrd0B43tCS5j6wTbO45vqdHizRXIMoHu5tA= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass header.i=collabora.com; spf=pass smtp.mailfrom=nicolas.frattaroli@collabora.com; dmarc=pass header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1790006019; s=zohomail; d=collabora.com; i=nicolas.frattaroli@collabora.com; h=From:From:Date:Date:Subject:Subject:MIME-Version:Content-Type:Content-Transfer-Encoding:Message-Id:Message-Id:In-Reply-To:To:To:Cc:Cc:Reply-To; bh=Y6pNKsL2/kxw9VEVLNj37g/I6SH0Xh54QzUA4fywo6s=; b=GdeTVI9/ySknEWMlLie5aNFu0UnUhp3eVj85hhAUq7Ruz/ayGx7l5QYlKQYEsktZ IL9UF1L0Q8W6KLD5qzQYegcca7z+sGXmF+rnPaofApYn7kNqM0stlzXAOmhbSkRwznm E+ApJk2uanDoXaBpZIaQz5AMYqiCB0UfZvTgswao= Received: by smtp.zohomail.com with SMTPS id 1790006017269820.087454670457; Mon, 21 Sep 2026 08:53:37 -0700 (PDT) From: Nicolas Frattaroli Date: Mon, 21 Sep 2026 17:51:43 +0200 Subject: [PATCH RFC 17/25] drm/connector: Add "qms_enabled" drm property Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260921-vrr-limiter-uapi-v1-17-2fcd7d011646@collabora.com> References: <20260921-vrr-limiter-uapi-v1-0-2fcd7d011646@collabora.com> In-Reply-To: <20260921-vrr-limiter-uapi-v1-0-2fcd7d011646@collabora.com> To: "Borah, Chaitanya Kumar" , Leo Li , Daniel Stone , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Helge Deller , Andrzej Hajda , Neil Armstrong , Robert Foss , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Luca Ceresoli , Sandy Huang , =?utf-8?q?Heiko_St=C3=BCbner?= , Andy Yan Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, linux-fbdev@vger.kernel.org, linux-rockchip@lists.infradead.org, linux-arm-kernel@lists.infradead.org, kernel@collabora.com, Derek Foreman , wayland-devel@lists.freedesktop.org, Nicolas Frattaroli X-Mailer: b4 0.15.2 HDMI includes a feature called "Quick Media Switching", or QMS for short, which builds upon the existing VRR to allow for quick switching between a select few common frame rates. Add a DRM property to the connector to allow userspace to request the kernel to use QMS. Only connectors of sources which do support QMS should register this property, though whether a specific sink supports QMS is orthogonal to this. Signed-off-by: Nicolas Frattaroli --- drivers/gpu/drm/drm_atomic_helper.c | 3 +++ drivers/gpu/drm/drm_atomic_uapi.c | 4 ++++ drivers/gpu/drm/drm_connector.c | 48 +++++++++++++++++++++++++++++++++= ++++ include/drm/drm_connector.h | 23 ++++++++++++++++++ 4 files changed, 78 insertions(+) diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atom= ic_helper.c index 0664d5779282..a2919e3975a8 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -749,6 +749,9 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, new_connector_state->color_format) new_crtc_state->connectors_changed =3D true; =20 + if (old_connector_state->hdmi.qms_enabled !=3D + new_connector_state->hdmi.qms_enabled) + new_crtc_state->connectors_changed =3D true; } =20 if (funcs->atomic_check) diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic= _uapi.c index c9eb01d740b3..fe9516475451 100644 --- a/drivers/gpu/drm/drm_atomic_uapi.c +++ b/drivers/gpu/drm/drm_atomic_uapi.c @@ -993,6 +993,8 @@ static int drm_atomic_connector_set_property(struct drm= _connector *connector, state->hdmi.broadcast_rgb =3D val; } else if (property =3D=3D connector->color_format_property) { state->color_format =3D val; + } else if (property =3D=3D connector->qms_enabled_property) { + state->hdmi.qms_enabled =3D val; } else if (connector->funcs->atomic_set_property) { return connector->funcs->atomic_set_property(connector, state, property, val); @@ -1080,6 +1082,8 @@ drm_atomic_connector_get_property(struct drm_connecto= r *connector, *val =3D state->hdmi.broadcast_rgb; } else if (property =3D=3D connector->color_format_property) { *val =3D state->color_format; + } else if (property =3D=3D connector->qms_enabled_property) { + *val =3D state->hdmi.qms_enabled; } else if (connector->funcs->atomic_get_property) { return connector->funcs->atomic_get_property(connector, state, property, val); diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connecto= r.c index 5c07bd221977..7ea235a58781 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -2605,6 +2605,8 @@ EXPORT_SYMBOL(drm_mode_create_scaling_mode_property); * numerator/denominator pair of a frame rate to set as the minimum VRR * target rate. Set to 0 to disable. * + * .. _VRR-MIN-DENOMINATOR: + * * "VRR_MIN_DENOMINATOR": * Default &drm_crtc integer property forming the denominator of a * numerator/denominator pair of a frame rate to set as the minimum VRR @@ -2619,11 +2621,30 @@ EXPORT_SYMBOL(drm_mode_create_scaling_mode_property= ); * numerator/denominator pair of a frame rate to set as the maximum VRR * target rate. Set to 0 to disable. * + * .. _VRR-MAX-DENOMINATOR: + * * "VRR_MAX_DENOMINATOR": * Default &drm_crtc integer property forming the denominator of a * numerator/denominator pair of a frame rate to set as the maximum VRR * target rate. If :ref:`VRR_MAX_NUMERATOR ` is not * zero, it must be non-zero. Otherwise, must also be zero. + * + * "qms_enabled": + * Optional &drm_connector boolean property that drivers should attach with + * drm_connector_attach_qms_enabled_property() on connectors that support + * HDMI Quick Media Switching (QMS). Present only depending on source + * capability, with no regards to sink capability. Userspace may set it to + * true if the variable refresh target rate that's expressed through + * :ref:`VRR_MIN_NUMERATOR ` divided by + * :ref:`VRR_MIN_DENOMINATOR ` (which, in this case, + * should be equal to :ref:`VRR_MAX_NUMERATOR ` divided + * by :ref:`VRR_MAX_DENOMINATOR ` to signal a fixed + * rate) should be achieved with signaling for HDMI Quick Media Switching. + * + * Attempting to enable QMS when the attached display is not QMS capable, + * or when the set fixed target rate is not possible with QMS, will result + * in an error during the atomic check phase that will be passed up to + * userspace to handle. */ =20 /** @@ -3318,6 +3339,33 @@ int drm_connector_attach_color_format_property(struc= t drm_connector *connector, } EXPORT_SYMBOL(drm_connector_attach_color_format_property); =20 +/** + * drm_connector_attach_qms_enabled_property - attach "qms_enabled" proper= ty + * @connector: pointer to &struct drm_connector to attach this property on. + * + * Create and attach the "qms_enabled" property to the given @connector, w= hich + * can be used by userspace to signal that it would like to achieve the CR= TC's + * desired VRR target frame rate with HDMI "Quick Media Switching". + * + * Should only be called if the source actually supports generating the pa= ckets + * needed for QMS, but is present regardless of sink support for QMS. + * + * Returns: + * Zero on success, negative errno on failure. + */ +int drm_connector_attach_qms_enabled_property(struct drm_connector *connec= tor) +{ + connector->qms_enabled_property =3D + drm_property_create_bool(connector->dev, 0, "qms_enabled"); + if (!connector->qms_enabled_property) + return -ENOMEM; + + drm_object_attach_property(&connector->base, connector->qms_enabled_prope= rty, 0); + + return 0; +} +EXPORT_SYMBOL(drm_connector_attach_qms_enabled_property); + /** * drm_connector_atomic_hdr_metadata_equal - checks if the hdr metadata ch= anged * @old_state: old connector state to compare diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 8439c82db905..a5631bebb4df 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -1238,6 +1238,18 @@ struct drm_connector_hdmi_state { * deliberately not requested by the helper. */ bool scrambler_needed; + + /** + * @qms_tfr_byte: Target frame rate byte for HDMI QMS, or 0 if QMS is + * not in use. + */ + u8 qms_tfr_byte; + + /** + * @qms_enabled: Whether or not userspace requests to use HDMI Quick + * Media Switching to achieve the target frame rate. + */ + bool qms_enabled; }; =20 /** @@ -2490,6 +2502,16 @@ struct drm_connector { */ struct drm_property *vrr_capable_property; =20 + /** + * @qms_enabled_property: Optional atomic boolean property through which + * userspace can indicate that HDMI "Quick Media Switching" should be + * used to achieve the CRTC's target frame rate. + * + * Only HDMI connectors of sources capable of generating the right HDMI + * signalling packets should register this property. + */ + struct drm_property *qms_enabled_property; + /** * @colorspace_property: Connector property to set the suitable * colorspace supported by the sink. @@ -3016,6 +3038,7 @@ const char *drm_get_colorspace_name(enum drm_colorspa= ce colorspace); =20 int drm_connector_attach_color_format_property(struct drm_connector *conne= ctor, unsigned long supported_color_formats); +int drm_connector_attach_qms_enabled_property(struct drm_connector *connec= tor); =20 /** * drm_for_each_connector_iter - connector_list iterator macro --=20 2.55.0 From nobody Fri Sep 25 21:02:41 2026 Received: from sender4-pp-f112.zoho.com (sender4-pp-f112.zoho.com [136.143.188.112]) (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 D0B5A4C9E11; Mon, 21 Sep 2026 15:54:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=136.143.188.112 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790006078; cv=pass; b=bMnYk7WIuY3wBTCmWP6aARke/uAQwab4hs2DUzqApK9qbW5LaFNFHriqAOMtHILC4Mw9WkGBBceGkjCe5LUD5svZ9kGLVB/J510uz4lZOhhTVqDPrFumDMNj07iPQILuAVgZ9A63oWkdbpkdNaCHwZAST/QOo+ASMYi8ixvmPdA= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790006078; c=relaxed/simple; bh=DXr0pthflIdTVKQ5DTod3yDrxBL7oMYdg/eFEDf/HY8=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=lrEPXuMHoZrtlRIX9Qxl3/kQPg6aetE6bylPfpRZPRPBwMpn3cezggGWesR71rFjIff9Au+t01hS6R3yRXysFnnMZzONAa01h59Kr7TmNJSfbEgTddZBGsQg/JRtNQeebCCjW9ZCKzryWuB5XuZJmq3LDmhQThxOqFbwzIwH5cs= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (1024-bit key) header.d=collabora.com header.i=nicolas.frattaroli@collabora.com header.b=XP2LsrtV; arc=pass smtp.client-ip=136.143.188.112 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=collabora.com header.i=nicolas.frattaroli@collabora.com header.b="XP2LsrtV" ARC-Seal: i=1; a=rsa-sha256; t=1790006023; cv=none; d=zohomail.com; s=zohoarc; b=mNxYJPeTGHAGjPBxt2kG+O2omHs5iLPq053ahnUDuMDwCG+h/AgQV8SO1CcujSUd0RTs8zTxtr9YP1QcEg3zec8wba0rEkze1jbVLJaHKKMbgZ6SnL/2prDQmEPAgh8gxAwFEWhfnjYntkmJbR/+SW/NcMFAuYwgnBemfloyXpQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1790006023; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:MIME-Version:Message-ID:Subject:Subject:To:To:Message-Id:Reply-To; bh=hEhqBiuQL/MEW0Qf0v9yrljoDp5ccHOdzYzDtJ6My1Q=; b=AOytYHd7RrtEEmEKbAFxraFjfljCZppLavxE5SUIhncMkLyUtMk5Srjanz6f7JFISOf4oT5zlcwpLD1vYKZB5YZLfbFTfZHF37WBaNo78Sjyox26JwZS4vCoQ2f8+ih1Nxq+eheV/GGQNjEYs6xseLNlRMiewqB4XLNxBmfdWPw= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass header.i=collabora.com; spf=pass smtp.mailfrom=nicolas.frattaroli@collabora.com; dmarc=pass header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1790006023; s=zohomail; d=collabora.com; i=nicolas.frattaroli@collabora.com; h=From:From:Date:Date:Subject:Subject:MIME-Version:Content-Type:Content-Transfer-Encoding:Message-Id:Message-Id:In-Reply-To:To:To:Cc:Cc:Reply-To; bh=hEhqBiuQL/MEW0Qf0v9yrljoDp5ccHOdzYzDtJ6My1Q=; b=XP2LsrtVFXpGYiWDKFgWo+6g2O3stDZB0BqRxuDntgCEGqi0Do7N4jm6/EyqlGNC 6oLlKKzi9sX4i2Jc/xjliyQNMiEDC6h26bBrEf9cqdC3ZKmv1+VJQU9qPsWUWB8C2DV u2gQofzgkZkNipPBCS+uhTGbxA7JyecMz/KFnhNc= Received: by smtp.zohomail.com with SMTPS id 179000602308953.27122495413869; Mon, 21 Sep 2026 08:53:43 -0700 (PDT) From: Nicolas Frattaroli Date: Mon, 21 Sep 2026 17:51:44 +0200 Subject: [PATCH RFC 18/25] video/hdmi: Add support for QMS in VTEM EMP packing Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260921-vrr-limiter-uapi-v1-18-2fcd7d011646@collabora.com> References: <20260921-vrr-limiter-uapi-v1-0-2fcd7d011646@collabora.com> In-Reply-To: <20260921-vrr-limiter-uapi-v1-0-2fcd7d011646@collabora.com> To: "Borah, Chaitanya Kumar" , Leo Li , Daniel Stone , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Helge Deller , Andrzej Hajda , Neil Armstrong , Robert Foss , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Luca Ceresoli , Sandy Huang , =?utf-8?q?Heiko_St=C3=BCbner?= , Andy Yan Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, linux-fbdev@vger.kernel.org, linux-rockchip@lists.infradead.org, linux-arm-kernel@lists.infradead.org, kernel@collabora.com, Derek Foreman , wayland-devel@lists.freedesktop.org, Nicolas Frattaroli X-Mailer: b4 0.15.2 Add the necessary struct members and packing code to allow the hdmi_emp_infoframe_vtem_pack function to write VTEM packets with HDMI Quick Media Switching (QMS) data. Co-developed-by: Derek Foreman Signed-off-by: Derek Foreman Signed-off-by: Nicolas Frattaroli --- drivers/video/hdmi.c | 6 ++++-- include/linux/hdmi.h | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c index ed9abc7ad228..c164f69a646a 100644 --- a/drivers/video/hdmi.c +++ b/drivers/video/hdmi.c @@ -1994,7 +1994,7 @@ ssize_t hdmi_emp_infoframe_vtem_pack(struct hdmi_emp_= infoframe_vtem *vtem, ptr[1] =3D BIT(7) | BIT(6); ptr[2] =3D 0; =20 - ptr[3] =3D BIT(7) | BIT(2); + ptr[3] =3D BIT(7) | BIT(2) | (vtem->qms_en ? BIT(1) : 0); =20 ptr[4] =3D 0; ptr[5] =3D 1; @@ -2005,10 +2005,12 @@ ssize_t hdmi_emp_infoframe_vtem_pack(struct hdmi_em= p_infoframe_vtem *vtem, =20 /* This is where the VTEM part starts */ ptr[10] =3D (vtem->fva_factor_m1 << 4) | + (vtem->qms_en ? BIT(2) : 0) | (vtem->m_const ? BIT(1) : 0) | (vtem->game_vrr_en ? BIT(0) : 0); ptr[11] =3D vtem->base_vfront; - ptr[12] =3D vtem->base_refresh_rate >> 8 & 0x3; + ptr[12] =3D (vtem->next_tfr << 3) | + (vtem->base_refresh_rate >> 8 & 0x3); ptr[13] =3D vtem->base_refresh_rate & 0xFF; =20 return 14; diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h index 71e2b36896af..8eaa127f0cb5 100644 --- a/include/linux/hdmi.h +++ b/include/linux/hdmi.h @@ -243,10 +243,12 @@ struct hdmi_emp_infoframe_vtem { unsigned char length; =20 bool game_vrr_en; + bool qms_en; bool m_const; unsigned char fva_factor_m1; unsigned char base_vfront; u16 base_refresh_rate; + u8 next_tfr; }; =20 void hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame); --=20 2.55.0 From nobody Fri Sep 25 21:02:41 2026 Received: from sender4-pp-f112.zoho.com (sender4-pp-f112.zoho.com [136.143.188.112]) (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 8F9754DD3A8; Mon, 21 Sep 2026 15:54:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=136.143.188.112 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790006078; cv=pass; b=n5IgY9bIbsTf/loznuPPkT7H2A5I018HNE/Y4r8/Kahea+5PmFtPSY/g14zkBCpKcSzFa6197N8cxfr7MZqNRbj2e8nPw26P1Kfb0qxhAZ0FsBVj+7qQm6/5tI5ceO77pgGFwnpYoE8dTGBMu4qMeOeXxFQvdbhNeijhGT/fI28= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790006078; c=relaxed/simple; bh=z6GHbDkwPim4IeIve2OsuTqdxU7XFToO1raFQ1e8ZZs=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=c/0GCVuGiNYR7ZM1/LLKKL4Qd7zeNwt2AdqBQQRbv/Zqu31He9o3ZioF6j3G9RMzsEHwzjrpJsIMVrkGQAmuBU9T6SW3xqffcvWTX2H8UwgLvMrCchYF0tMQ/8hdyixfkUpGA/9ZT9QrgjsZic/OmxEJszLC1P8fY0RnwV8Rfc8= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (1024-bit key) header.d=collabora.com header.i=nicolas.frattaroli@collabora.com header.b=Jgz6DvBO; arc=pass smtp.client-ip=136.143.188.112 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=collabora.com header.i=nicolas.frattaroli@collabora.com header.b="Jgz6DvBO" ARC-Seal: i=1; a=rsa-sha256; t=1790006029; cv=none; d=zohomail.com; s=zohoarc; b=bucFePsIG3sHaaq/2CBWDuM6TEQB5ZUvSiVK4L87uB8k+NTxy+ifG1BiI8b4jqBlbXCNYrQDmCA/4OGZvHfYxCui3ll5076Kw9Pybc26IofFFJAlIpftObLG2oOywgrWVuvUAZaPUKTEjZhkc9qVXqXJRdtyOTZhjyQ7I+cg+9I= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1790006029; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:MIME-Version:Message-ID:Subject:Subject:To:To:Message-Id:Reply-To; bh=1N1AnyMnsM3RPCrD9BtF496M7LSPX+hpmo/Y3tqyskA=; b=iu3kjXMKrd5USM8jXxUw4CupgHeqjWdNt+Y9RDnUzADslvyhTk3jhiWYx3CZdpkEtPp1OD0R3Krt0Ixe8pasvpUlq+Y41zSNN62JwhWldKEe0CWNv0hJy1WutJTuN9LhFTsrXVJVPUUozy1zm0TUsIWuZq2TxVHcOIEmraV+eEY= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass header.i=collabora.com; spf=pass smtp.mailfrom=nicolas.frattaroli@collabora.com; dmarc=pass header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1790006029; s=zohomail; d=collabora.com; i=nicolas.frattaroli@collabora.com; h=From:From:Date:Date:Subject:Subject:MIME-Version:Content-Type:Content-Transfer-Encoding:Message-Id:Message-Id:In-Reply-To:To:To:Cc:Cc:Reply-To; bh=1N1AnyMnsM3RPCrD9BtF496M7LSPX+hpmo/Y3tqyskA=; b=Jgz6DvBOy9K+i2RfOAOPfYf7p6Y5KWJ1d4xUkaPCAHzfCYATKkhhFEz2coekjKsq pp87lncyTbEAsYCTjfRS7KVQQb1SMPsHoxZYEo3Qrl+ZltRJCRpZdwvnFwMSU2V39dY qzCVkuN7ulHwQJzmRYiR6hkfDv0aM0zLuFYZw5ts= Received: by smtp.zohomail.com with SMTPS id 1790006028396815.1028205617608; Mon, 21 Sep 2026 08:53:48 -0700 (PDT) From: Nicolas Frattaroli Date: Mon, 21 Sep 2026 17:51:45 +0200 Subject: [PATCH RFC 19/25] drm/connector: hdmi: Add QMS to VTEM EMP generation Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260921-vrr-limiter-uapi-v1-19-2fcd7d011646@collabora.com> References: <20260921-vrr-limiter-uapi-v1-0-2fcd7d011646@collabora.com> In-Reply-To: <20260921-vrr-limiter-uapi-v1-0-2fcd7d011646@collabora.com> To: "Borah, Chaitanya Kumar" , Leo Li , Daniel Stone , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Helge Deller , Andrzej Hajda , Neil Armstrong , Robert Foss , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Luca Ceresoli , Sandy Huang , =?utf-8?q?Heiko_St=C3=BCbner?= , Andy Yan Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, linux-fbdev@vger.kernel.org, linux-rockchip@lists.infradead.org, linux-arm-kernel@lists.infradead.org, kernel@collabora.com, Derek Foreman , wayland-devel@lists.freedesktop.org, Nicolas Frattaroli X-Mailer: b4 0.15.2 If userspace indicates that QMS is desired, set the QMS related fields in the VTEM EMP struct based on the connector state. Signed-off-by: Nicolas Frattaroli --- drivers/gpu/drm/display/drm_hdmi_state_helper.c | 10 +++++++++- 1 file changed, 9 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 7dbd678cf061..7237070fc9ee 100644 --- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c +++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c @@ -897,7 +897,15 @@ static int hdmi_generate_emp_infoframe_vtem(const stru= ct drm_connector *connecto return 0; } =20 - vtem->game_vrr_en =3D true; + if (conn_state->hdmi.qms_enabled) { + vtem->game_vrr_en =3D false; + vtem->qms_en =3D true; + vtem->next_tfr =3D conn_state->hdmi.qms_tfr_byte; + } else { + vtem->game_vrr_en =3D true; + vtem->qms_en =3D false; + vtem->next_tfr =3D 0; + } =20 vtem->m_const =3D !vrr->dynamic; =20 --=20 2.55.0 From nobody Fri Sep 25 21:02:41 2026 Received: from sender4-pp-f112.zoho.com (sender4-pp-f112.zoho.com [136.143.188.112]) (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 222344CA795; Mon, 21 Sep 2026 15:54:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=136.143.188.112 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790006078; cv=pass; b=agPQaZAaDZ6ZJy436fbZvjUn8ong/NpARoAMMdfSh0rX1T/NNw3k435ly9Kn1xvcnk3ayyKyiTcFZQK3TQw734psWvlsxvyYpzxSpTNbVs5+R7rcm6+5ekacZ5gNtQ1U3FYIQs9XjeRLvCwUTeyGJAP01X9egU2igygTcp5+UZo= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790006078; c=relaxed/simple; bh=QNY6uZrjC8F03odc5ARblg1qa0EwLcfSwYBjObj/uGk=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=PdpfKrlihK0E6JwrrNVgZAB3dk9GixnWQZJ4+pSfhwpTrfRyIr/W+s0Tl8hF9/I2PziYOWvO5TvH+x3AZhKrSHzPy4yA9LA+UlXTu6FJlJ8IhLm5gxKJ06GV2eZ2iFf1soTZ1yYjKb4+w3z/gPoCsXpONYxZLNs5DPxUCPvqNyQ= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (1024-bit key) header.d=collabora.com header.i=nicolas.frattaroli@collabora.com header.b=ko/84+RV; arc=pass smtp.client-ip=136.143.188.112 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=collabora.com header.i=nicolas.frattaroli@collabora.com header.b="ko/84+RV" ARC-Seal: i=1; a=rsa-sha256; t=1790006035; cv=none; d=zohomail.com; s=zohoarc; b=Qm70zm2P7Z3dLQEsA8wBm3JW+mpnGUIIXH2wYf8nn1LCGxEKVpcSav39j6zsVLlpiLYNDK+bTANoGSAOuZOvePK4LrQ+v5rDEZOQO2FxHnSmaa5plus13wmzwYsXtxdLUs9WUGwom2eVGSma1EfbqC5tvsM5J46L6C8WpPYO+j0= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1790006035; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:MIME-Version:Message-ID:Subject:Subject:To:To:Message-Id:Reply-To; bh=I5L+bsoWmPLekEYM66FjXrtQ+U3z611xrc5MNXFSuEI=; b=lOP9Cj+YJLxWf1N5VgiRomX/lqnO7uNB+42y+RG1F4Qt/A4czPYGAI2qjys4z2/Hr1Kz82zrjihmw0Y2fYToeSZ0E10ebYaQ1+KcEkI7/lUv8Wsu0gt83Ago97pkJc3meG+cvbTsWM274fyPyUavP+ZgGGWwG89EygSkAwI5NTA= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass header.i=collabora.com; spf=pass smtp.mailfrom=nicolas.frattaroli@collabora.com; dmarc=pass header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1790006035; s=zohomail; d=collabora.com; i=nicolas.frattaroli@collabora.com; h=From:From:Date:Date:Subject:Subject:MIME-Version:Content-Type:Content-Transfer-Encoding:Message-Id:Message-Id:In-Reply-To:To:To:Cc:Cc:Reply-To; bh=I5L+bsoWmPLekEYM66FjXrtQ+U3z611xrc5MNXFSuEI=; b=ko/84+RVAHXZLFMZhNu3TYTpih0LU9lzYu2K3dwFnPB4HL+Ii6QQI364DC0w3kaY NValglXTbMlKMbtRRk3hka1UNayLjTXrmobdhsIw8kroXnQ6Pb+c7hEAWAD/xME4dTH uQkeVtPXduSDJPpW6jeinF6lTdCAVNC24RnNsBOI= Received: by smtp.zohomail.com with SMTPS id 1790006033715880.1589251682541; Mon, 21 Sep 2026 08:53:53 -0700 (PDT) From: Nicolas Frattaroli Date: Mon, 21 Sep 2026 17:51:46 +0200 Subject: [PATCH RFC 20/25] drm/connector: hdmi: Add QMS state validation and computation Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260921-vrr-limiter-uapi-v1-20-2fcd7d011646@collabora.com> References: <20260921-vrr-limiter-uapi-v1-0-2fcd7d011646@collabora.com> In-Reply-To: <20260921-vrr-limiter-uapi-v1-0-2fcd7d011646@collabora.com> To: "Borah, Chaitanya Kumar" , Leo Li , Daniel Stone , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Helge Deller , Andrzej Hajda , Neil Armstrong , Robert Foss , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Luca Ceresoli , Sandy Huang , =?utf-8?q?Heiko_St=C3=BCbner?= , Andy Yan Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, linux-fbdev@vger.kernel.org, linux-rockchip@lists.infradead.org, linux-arm-kernel@lists.infradead.org, kernel@collabora.com, Derek Foreman , wayland-devel@lists.freedesktop.org, Nicolas Frattaroli X-Mailer: b4 0.15.2 Add the necessary code to the HDMI state helpers' hdmi_validate_vrr function in order to check and derive the state necessary for HDMI Quick Media Switching (QMS) support. Co-developed-by: Derek Foreman Signed-off-by: Derek Foreman Signed-off-by: Nicolas Frattaroli --- drivers/gpu/drm/display/drm_hdmi_state_helper.c | 103 ++++++++++++++++++++= +++- 1 file changed, 102 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 7237070fc9ee..d392ae2908f9 100644 --- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c +++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c @@ -2,6 +2,7 @@ =20 #include #include +#include =20 #include #include @@ -950,6 +951,26 @@ hdmi_generate_infoframes(const struct drm_connector *c= onnector, return 0; } =20 +static const struct { + u8 tfr_byte; + u32 rate_n; + u32 rate_d; +} hdmi_qms_tfrs[] =3D { + { 1, 24000, 1001 }, + { 2, 24, 1 }, + { 3, 25, 1 }, + { 4, 30000, 1001 }, + { 5, 30, 1 }, + { 6, 48000, 1001 }, + { 7, 48, 1 }, + { 8, 50, 1 }, + { 9, 60000, 1001 }, + { 10, 60, 1 }, + { 11, 100, 1 }, + { 12, 120000, 1001 }, + { 13, 120, 1 }, +}; + /** * cmp_fraction - compares two fractional numbers * @a: numerator of the first fraction @@ -988,6 +1009,69 @@ static int cmp_fraction(u32 a, u32 b, u32 c, u32 d) return 0; } =20 +/** + * hdmi_validate_qms - Validate HDMI QMS state + * @crtc_state: pointer to a &struct drm_crtc_state to run validation on + * @info: pointer to a &struct drm_display_info of the accompanying connec= tor + * + * Validate that the drm_crtc_vrr_state.vrr_min_numerator and + * drm_crtc_vrr_state.vrr_min_denominator are acceptable for HDMI QMS, and= check + * that the display is HDMI QMS capable. + * + * Returns: + * - Negative errno on failure + * - the corresponding QMS signaling byte for the target frame rate other= wise + */ +static int hdmi_validate_qms(struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state, + const struct drm_display_info *info) +{ + u32 rate_n =3D crtc_state->vrr_state.vrr_min_n; + u32 rate_d =3D crtc_state->vrr_state.vrr_min_d; + u32 min_rate_n, max_rate; + u32 g, i; + + if (!conn_state->hdmi.qms_enabled) + return 0; + + if (!info->hdmi.qms_capable) + return -EOPNOTSUPP; + + if (!drm_crtc_helper_vrr_is_fixed_rate(&crtc_state->vrr_state)) + return -EINVAL; + + if (info->hdmi.qms_tfr_min) + min_rate_n =3D 24000; + else + min_rate_n =3D info->monitor_range.min_vfreq * 1000; + + if (info->hdmi.qms_tfr_max) + max_rate =3D info->monitor_range.max_vfreq; + else + max_rate =3D 60; + + g =3D gcd(rate_n, rate_d); + if (g !=3D 1) { + rate_n /=3D g; + rate_d /=3D g; + } + + if (!rate_d) + return -EINVAL; + + for (i =3D 0; i < ARRAY_SIZE(hdmi_qms_tfrs); i++) { + if (cmp_fraction(min_rate_n, 1001, hdmi_qms_tfrs[i].rate_n, + hdmi_qms_tfrs[i].rate_d) > 0) + continue; + if (rate_n =3D=3D hdmi_qms_tfrs[i].rate_n && + rate_d =3D=3D hdmi_qms_tfrs[i].rate_d && + cmp_fraction(rate_n, rate_d, max_rate, 1) <=3D 0) + return hdmi_qms_tfrs[i].tfr_byte; + } + + return -EINVAL; +} + static int hdmi_calculate_vtotal(const struct drm_display_mode *mode, u32 rate_n, u32 rate_d, u16 *out_vtotal, u32 *out_denom, u32 *out_frame_err) @@ -1093,6 +1177,8 @@ static int hdmi_validate_vrr(struct drm_connector *co= nnector, { struct drm_connector_state *new_conn_state =3D drm_atomic_get_new_connector_state(state, connector); + struct drm_connector_state *old_conn_state =3D + drm_atomic_get_old_connector_state(state, connector); struct drm_crtc_state *new_crtc_state =3D drm_atomic_get_new_crtc_state(state, new_conn_state->crtc); struct drm_crtc_state *old_crtc_state =3D @@ -1113,6 +1199,7 @@ static int hdmi_validate_vrr(struct drm_connector *co= nnector, =20 /* Save on the expensive vic lookup, if nothing else. */ if (!new_crtc_state->mode_changed && + !new_crtc_state->connectors_changed && old_crtc_state->vrr_enabled && old_vrr_state->vrr_min_n =3D=3D vrr_state->vrr_min_n && old_vrr_state->vrr_min_d =3D=3D vrr_state->vrr_min_d && @@ -1143,7 +1230,9 @@ static int hdmi_validate_vrr(struct drm_connector *co= nnector, max_vfreq_n =3D mode_refresh; =20 is_fixed =3D drm_crtc_helper_vrr_is_fixed_rate(vrr_state); - if (is_fixed && info->hdmi.cinema_vrr) + if (is_fixed && (info->hdmi.cinema_vrr || (info->hdmi.qms_tfr_min && + new_conn_state->hdmi.qms_enabled && + info->hdmi.qms_capable))) min_vfreq_n =3D 24; =20 if (!min_vfreq_n) { @@ -1165,6 +1254,18 @@ static int hdmi_validate_vrr(struct drm_connector *c= onnector, return ret; } =20 + ret =3D hdmi_validate_qms(new_crtc_state, new_conn_state, info); + if (ret < 0) { + drm_dbg_kms(dev, "Invalid QMS rate: %pe\n", ERR_PTR(ret)); + return ret; + } + + new_conn_state->hdmi.qms_tfr_byte =3D ret; + if (new_conn_state->hdmi.qms_tfr_byte !=3D old_conn_state->hdmi.qms_tfr_b= yte) + vrr_state->dynamic =3D true; + else + vrr_state->dynamic =3D false; + if (!is_fixed) { vrr_state->dynamic =3D true; =20 --=20 2.55.0 From nobody Fri Sep 25 21:02:41 2026 Received: from sender4-pp-f112.zoho.com (sender4-pp-f112.zoho.com [136.143.188.112]) (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 5C8344DEC1B; Mon, 21 Sep 2026 15:54:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=136.143.188.112 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790006081; cv=pass; b=KOu++6mCgTyzIIwKM94W4qvf4i9tJsc/9smGRAaaupP53bf55XZTiM9b7V6irtxZlsqNHNqCmDy+j/3uIWx+yeD02+GCqQ88dF7BPoBxTYuMcTkMv28SW0xhRHE6AbLaz/KJnKttr1bv8eXml7hxUVGhQUrTcXO7VH6f72D6HaM= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790006081; c=relaxed/simple; bh=hgdrJmUY5WC2xIIO5U4MQbG/gE0OtfbomoZyNIZP+TI=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=K8+ZxLfUUB+0H+SnIW+B9EjxOyvOp1I7zHpC1OkV7pWbOATOwjGGCOjS2Neydl0BrSFRtMZp0TZnZV+Vb9ipyiRkxk/wzz55PS0rcnb/Gs0rLwKTeHp18IKKcbZCKzRa8Qccx/5HpQjLcWrcLqOOrA9HK6tlwkJEIt+YI3872Ys= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (1024-bit key) header.d=collabora.com header.i=nicolas.frattaroli@collabora.com header.b=U/5psYyp; arc=pass smtp.client-ip=136.143.188.112 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=collabora.com header.i=nicolas.frattaroli@collabora.com header.b="U/5psYyp" ARC-Seal: i=1; a=rsa-sha256; t=1790006039; cv=none; d=zohomail.com; s=zohoarc; b=gLqMhLxXpe6hx53mTo4znLvDBS2WttlbDjGxey7roZkgGUGP2hM4BbFXAliT+dWI7ucpuALigVRVWMWjcr8GLkWf6sitqZ6Kwa2DN/YW4Jm5+VdA0tP5OFM2PbUZfgMqXxDJftNkeA5MES9KEmsy4nf8xLR8WGniJbJYOXcXXFY= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1790006039; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:MIME-Version:Message-ID:Subject:Subject:To:To:Message-Id:Reply-To; bh=UZryrWM94xhdFNiIc91FHkuUZmbywMObyi/aWoB7MIo=; b=OT7gtSIKbWAIbk2sTJgFIMnBtLncQnXWOZvwsWmdo44J6rgtY2W/6UQvgUjcZ/nrLePrMRc3sEJtG4Q1J6QKsM3dH8kUv80NFLO9tcRBpwBGPNHh3IBOF7psiJGrKjGd4qIJx46+LV2GiAyr12dbEReXC13h3sOmjtrfbmsl5Qc= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass header.i=collabora.com; spf=pass smtp.mailfrom=nicolas.frattaroli@collabora.com; dmarc=pass header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1790006039; s=zohomail; d=collabora.com; i=nicolas.frattaroli@collabora.com; h=From:From:Date:Date:Subject:Subject:MIME-Version:Content-Type:Content-Transfer-Encoding:Message-Id:Message-Id:In-Reply-To:To:To:Cc:Cc:Reply-To; bh=UZryrWM94xhdFNiIc91FHkuUZmbywMObyi/aWoB7MIo=; b=U/5psYypXBarRk0a70YMj3Tq6qmKHVnIGnHTv7n4Olwg7Xxgath/pbq9On6AKQG+ kBBUc00bJd91NYSk8sJ6XuKMDJuJujQ6ggtLz09cTaAEIao2bt9pdB8XDWyPjin81RY 6NCzwzxtudxmtAmpfDiAsdlV3B2DX7LTyQ9GhFr8= Received: by smtp.zohomail.com with SMTPS id 179000603922831.181435721949583; Mon, 21 Sep 2026 08:53:59 -0700 (PDT) From: Nicolas Frattaroli Date: Mon, 21 Sep 2026 17:51:47 +0200 Subject: [PATCH RFC 21/25] drm/rockchip: dw_hdmi_qp: Add QMS support Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260921-vrr-limiter-uapi-v1-21-2fcd7d011646@collabora.com> References: <20260921-vrr-limiter-uapi-v1-0-2fcd7d011646@collabora.com> In-Reply-To: <20260921-vrr-limiter-uapi-v1-0-2fcd7d011646@collabora.com> To: "Borah, Chaitanya Kumar" , Leo Li , Daniel Stone , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Helge Deller , Andrzej Hajda , Neil Armstrong , Robert Foss , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Luca Ceresoli , Sandy Huang , =?utf-8?q?Heiko_St=C3=BCbner?= , Andy Yan Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, linux-fbdev@vger.kernel.org, linux-rockchip@lists.infradead.org, linux-arm-kernel@lists.infradead.org, kernel@collabora.com, Derek Foreman , wayland-devel@lists.freedesktop.org, Nicolas Frattaroli X-Mailer: b4 0.15.2 Register the "qms_enabled" property on RK3588. This property can then be used by userspace to request that a given VRR target frame rate on a CRTC should be achieved through QMS. The common HDMI state helpers implement the actual functionality for this. Signed-off-by: Nicolas Frattaroli --- drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/d= rm/rockchip/dw_hdmi_qp-rockchip.c index 2b9432aa8c54..01ed7c18a7e0 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c @@ -521,6 +521,7 @@ struct rockchip_hdmi_qp_cfg { const struct rockchip_hdmi_qp_ctrl_ops *ctrl_ops; const struct dw_hdmi_qp_phy_ops *phy_ops; bool supports_vrr; + bool supports_qms; }; =20 static const struct rockchip_hdmi_qp_cfg rk3576_hdmi_cfg =3D { @@ -541,6 +542,7 @@ static const struct rockchip_hdmi_qp_cfg rk3588_hdmi_cf= g =3D { .ctrl_ops =3D &rk3588_hdmi_ctrl_ops, .phy_ops =3D &rk3588_hdmi_phy_ops, .supports_vrr =3D true, + .supports_qms =3D true, }; =20 static const struct of_device_id dw_hdmi_qp_rockchip_dt_ids[] =3D { @@ -709,6 +711,13 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev= , struct device *master, "Failed to attach 'vrr_capable' property\n"); } =20 + if (cfg->supports_qms) { + ret =3D drm_connector_attach_qms_enabled_property(connector); + if (ret) + return dev_err_probe(hdmi->dev, ret, + "Failed to attach 'qms_enabled' property\n"); + } + return 0; } =20 --=20 2.55.0 From nobody Fri Sep 25 21:02:41 2026 Received: from sender4-pp-f112.zoho.com (sender4-pp-f112.zoho.com [136.143.188.112]) (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 CA4214BEE30; Mon, 21 Sep 2026 15:54:52 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=136.143.188.112 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790006094; cv=pass; b=Wwmf34voeD9wun9OXYcRI3bfjJvvkS9GQRllQffrzvRSi67PUQEO/mKXuvjVz0NkLL+Skj5awCxtd6GDCexaiZa9YNga+qKx5q3SQWKXQk7M4+67glFNcpRxkqTj0sc0S/v3eujbPy9PyfH7B7XMjEahy33flb/8Z9mr6DoIy/E= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790006094; c=relaxed/simple; bh=TPS90UzKlGoOP8rluX9bqNX1koB+9uDHTPJknC0e2rs=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=rsGwqYnQc0UNUqsxgX4b1AIbdzwdIen4YBaqXFvS8uEAYwFPx5/+h8Pt48xTaRWqXObSptperuxW3LDFBAlNIseIYKBnq+FrOFpuriJtSKNwPey/uDd7kmb+HNSqD6sRuHdDSEcwVSSsT9H8sfDPp6gkL6/2aSeeb4VnjDR9YKc= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (1024-bit key) header.d=collabora.com header.i=nicolas.frattaroli@collabora.com header.b=G+B2F0LC; arc=pass smtp.client-ip=136.143.188.112 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=collabora.com header.i=nicolas.frattaroli@collabora.com header.b="G+B2F0LC" ARC-Seal: i=1; a=rsa-sha256; t=1790006045; cv=none; d=zohomail.com; s=zohoarc; b=O4zW6rsjXoT/RAEKLIvZfdnRV+vrsEP6vfeO73PYNVWv/9llMXjEId8S7j0flsA6/JnMFVolmRdALqsYueP2i4JEG5fk+jjB1qgcs/9XY7Y6v2WRt4XPMt4wxOxvUsPl5A7LUoWdVfSp/DsU8BLiHtN9ixqNKR1s/KAjhFI7gmg= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1790006045; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:MIME-Version:Message-ID:Subject:Subject:To:To:Message-Id:Reply-To; bh=lYDlZpW716irxW3KFrd93W0EhzCkGRb/29feCpRb1eY=; b=IP6wZmEq6n+N11MZ4ZV2wxYoB5kLHL7+I9TNQY+gepToMTJ6UFnVfwZ4Fe/LFasZWVZlixyNClHxut0FuCRyhRgg4wC/GntFlUnpY0VQ6kwMmIOB7dthk7XgaOSLN1edP2NmEYrUnTzRiw1TtoXd+yU2S4t6QXJ4rDaXAHswAn8= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass header.i=collabora.com; spf=pass smtp.mailfrom=nicolas.frattaroli@collabora.com; dmarc=pass header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1790006045; s=zohomail; d=collabora.com; i=nicolas.frattaroli@collabora.com; h=From:From:Date:Date:Subject:Subject:MIME-Version:Content-Type:Content-Transfer-Encoding:Message-Id:Message-Id:In-Reply-To:To:To:Cc:Cc:Reply-To; bh=lYDlZpW716irxW3KFrd93W0EhzCkGRb/29feCpRb1eY=; b=G+B2F0LCohAZfH2LeUDdoMneUGn9Deww9EF/0LaeVz/aW5sQNdEA4efK1dsw8/YE Qyfl/0A898XIXegGCj3GTfIhJjH9F0vLTtOW5X81Mfx1Kxuyfe+ruIoOswgivcEGNgf MkqVA/7ErHON2xBklu7InSvS9S9xjMUACIvoSKHM= Received: by smtp.zohomail.com with SMTPS id 1790006044663940.059291944602; Mon, 21 Sep 2026 08:54:04 -0700 (PDT) From: Nicolas Frattaroli Date: Mon, 21 Sep 2026 17:51:48 +0200 Subject: [PATCH RFC 22/25] drm/tests: hdmi: Add "Game Mode" VRR tests Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260921-vrr-limiter-uapi-v1-22-2fcd7d011646@collabora.com> References: <20260921-vrr-limiter-uapi-v1-0-2fcd7d011646@collabora.com> In-Reply-To: <20260921-vrr-limiter-uapi-v1-0-2fcd7d011646@collabora.com> To: "Borah, Chaitanya Kumar" , Leo Li , Daniel Stone , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Helge Deller , Andrzej Hajda , Neil Armstrong , Robert Foss , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Luca Ceresoli , Sandy Huang , =?utf-8?q?Heiko_St=C3=BCbner?= , Andy Yan Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, linux-fbdev@vger.kernel.org, linux-rockchip@lists.infradead.org, linux-arm-kernel@lists.infradead.org, kernel@collabora.com, Derek Foreman , wayland-devel@lists.freedesktop.org, Nicolas Frattaroli X-Mailer: b4 0.15.2 Add a few tests to verify "Game Mode" VRR functionality. One test checks that hdmi_validate_vrr succeeds if the sink is VRR capable and VRR is enabled. Another test checks that hdmi_validate_vrr fails if the sink isn't VRR capable, but VRR is nevertheless enabled. Yet another test checks that flush/vsync have cur_vtotal bounce between base_vtotal and max_vtotal. Signed-off-by: Nicolas Frattaroli --- drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 264 +++++++++++++++++= ++++ drivers/gpu/drm/tests/drm_kunit_edid.h | 139 +++++++++++ 2 files changed, 403 insertions(+) diff --git a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c b/drivers/g= pu/drm/tests/drm_hdmi_state_helper_test.c index b2e347863a77..1486c16c2f78 100644 --- a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c +++ b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -3423,11 +3424,274 @@ static struct kunit_suite drm_atomic_helper_connec= tor_hdmi_infoframes_test_suite .test_cases =3D drm_atomic_helper_connector_hdmi_infoframes_tests, }; =20 +/* + * Check that on a VRR-capable sink with VRR enabled, an atomic commit wor= ks. + */ +static void drm_test_check_hdmi_vrr(struct kunit *test) +{ + struct drm_atomic_helper_connector_hdmi_priv *priv; + struct drm_modeset_acquire_ctx ctx; + struct drm_display_mode *preferred; + struct drm_crtc_state *crtc_state; + struct drm_atomic_commit *state; + struct drm_connector *conn; + struct drm_device *drm; + struct drm_crtc *crtc; + int ret; + + priv =3D drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test, + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), + 8, + &dummy_connector_hdmi_funcs, + test_edid_hdmi_vrr); + KUNIT_ASSERT_NOT_NULL(test, priv); + + drm =3D &priv->drm; + crtc =3D priv->crtc; + conn =3D &priv->connector; + KUNIT_ASSERT_TRUE(test, conn->display_info.is_hdmi); + KUNIT_ASSERT_TRUE(test, conn->display_info.hdmi.vrr_capable); + + preferred =3D find_preferred_mode(conn); + KUNIT_ASSERT_NOT_NULL(test, preferred); + + drm_modeset_acquire_init(&ctx, 0); + +retry_conn_enable: + ret =3D drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn, + preferred, &ctx); + if (ret =3D=3D -EDEADLK) { + ret =3D drm_modeset_backoff(&ctx); + if (!ret) + goto retry_conn_enable; + } + KUNIT_ASSERT_EQ(test, ret, 0); + + state =3D drm_kunit_helper_atomic_state_alloc(test, drm, &ctx); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state); + +retry_crtc_state: + crtc_state =3D drm_atomic_get_crtc_state(state, crtc); + if (PTR_ERR(crtc_state) =3D=3D -EDEADLK) { + drm_atomic_commit_clear(state); + ret =3D drm_modeset_backoff(&ctx); + if (!ret) + goto retry_crtc_state; + } + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state); + + crtc_state->vrr_enabled =3D true; + + ret =3D drm_atomic_commit(state); + if (ret =3D=3D -EDEADLK) { + drm_atomic_commit_clear(state); + ret =3D drm_modeset_backoff(&ctx); + if (!ret) + goto retry_crtc_state; + } + KUNIT_ASSERT_EQ(test, ret, 0); + + crtc_state =3D drm_atomic_get_new_crtc_state(state, crtc); + KUNIT_ASSERT_NOT_NULL(test, crtc_state); + + KUNIT_EXPECT_GE(test, crtc_state->vrr_state.base_vtotal, preferred->crtc_= vtotal); + KUNIT_EXPECT_GE(test, crtc_state->vrr_state.max_vtotal, preferred->crtc_v= total); + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); +} + +/* + * Check that on a sink that's not VRR capable, enabling VRR and doing an = atomic + * commit fails. + */ +static void drm_test_check_hdmi_vrr_sink_fail(struct kunit *test) +{ + struct drm_atomic_helper_connector_hdmi_priv *priv; + struct drm_modeset_acquire_ctx ctx; + struct drm_display_mode *preferred; + struct drm_crtc_state *crtc_state; + struct drm_atomic_commit *state; + struct drm_connector *conn; + struct drm_device *drm; + struct drm_crtc *crtc; + int ret; + + priv =3D drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test, + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), + 8, + &dummy_connector_hdmi_funcs, + test_edid_hdmi_4k_rgb_yuv420_dc_max_340mhz); + KUNIT_ASSERT_NOT_NULL(test, priv); + + drm =3D &priv->drm; + crtc =3D priv->crtc; + conn =3D &priv->connector; + KUNIT_ASSERT_TRUE(test, conn->display_info.is_hdmi); + KUNIT_ASSERT_FALSE(test, conn->display_info.hdmi.vrr_capable); + + preferred =3D find_preferred_mode(conn); + KUNIT_ASSERT_NOT_NULL(test, preferred); + + drm_modeset_acquire_init(&ctx, 0); + +retry_conn_enable: + ret =3D drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn, + preferred, &ctx); + if (ret =3D=3D -EDEADLK) { + ret =3D drm_modeset_backoff(&ctx); + if (!ret) + goto retry_conn_enable; + } + KUNIT_ASSERT_EQ(test, ret, 0); + + state =3D drm_kunit_helper_atomic_state_alloc(test, drm, &ctx); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state); + +retry_crtc_state: + crtc_state =3D drm_atomic_get_crtc_state(state, crtc); + if (PTR_ERR(crtc_state) =3D=3D -EDEADLK) { + drm_atomic_commit_clear(state); + ret =3D drm_modeset_backoff(&ctx); + if (!ret) + goto retry_crtc_state; + } + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state); + + crtc_state->vrr_enabled =3D true; + + ret =3D drm_atomic_commit(state); + if (ret =3D=3D -EDEADLK) { + drm_atomic_commit_clear(state); + ret =3D drm_modeset_backoff(&ctx); + if (!ret) + goto retry_crtc_state; + } + KUNIT_EXPECT_EQ(test, ret, -EOPNOTSUPP); + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); +} + +/* + * Check that the drm_crtc_helper_vrr_flush() and drm_crtc_helper_vrr_vsyn= c() + * helpers return the expected values on a VRR-capable sink with VRR enabl= ed. + */ +static void drm_test_check_hdmi_vrr_flush_vsync(struct kunit *test) +{ + struct drm_atomic_helper_connector_hdmi_priv *priv; + struct drm_modeset_acquire_ctx ctx; + struct drm_display_mode *preferred; + struct drm_crtc_state *crtc_state; + struct drm_atomic_commit *state; + struct drm_connector *conn; + struct drm_device *drm; + struct drm_crtc *crtc; + int ret; + + priv =3D drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test, + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), + 8, + &dummy_connector_hdmi_funcs, + test_edid_hdmi_vrr); + KUNIT_ASSERT_NOT_NULL(test, priv); + + drm =3D &priv->drm; + crtc =3D priv->crtc; + conn =3D &priv->connector; + KUNIT_ASSERT_TRUE(test, conn->display_info.is_hdmi); + KUNIT_ASSERT_TRUE(test, conn->display_info.hdmi.vrr_capable); + + preferred =3D find_preferred_mode(conn); + KUNIT_ASSERT_NOT_NULL(test, preferred); + + drm_modeset_acquire_init(&ctx, 0); + +retry_conn_enable: + ret =3D drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn, + preferred, &ctx); + if (ret =3D=3D -EDEADLK) { + ret =3D drm_modeset_backoff(&ctx); + if (!ret) + goto retry_conn_enable; + } + KUNIT_ASSERT_EQ(test, ret, 0); + + state =3D drm_kunit_helper_atomic_state_alloc(test, drm, &ctx); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state); + +retry_crtc_state: + crtc_state =3D drm_atomic_get_crtc_state(state, crtc); + if (PTR_ERR(crtc_state) =3D=3D -EDEADLK) { + drm_atomic_commit_clear(state); + ret =3D drm_modeset_backoff(&ctx); + if (!ret) + goto retry_crtc_state; + } + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state); + + crtc_state->vrr_enabled =3D true; + + ret =3D drm_atomic_commit(state); + if (ret =3D=3D -EDEADLK) { + drm_atomic_commit_clear(state); + ret =3D drm_modeset_backoff(&ctx); + if (!ret) + goto retry_crtc_state; + } + KUNIT_ASSERT_EQ(test, ret, 0); + + crtc_state =3D drm_atomic_get_new_crtc_state(state, crtc); + KUNIT_ASSERT_NOT_NULL(test, crtc_state); + + KUNIT_EXPECT_EQ(test, crtc_state->vrr_state.base_vtotal, preferred->crtc_= vtotal); + KUNIT_EXPECT_EQ(test, crtc_state->vrr_state.max_vtotal, + preferred->crtc_vtotal * (drm_mode_vrefresh(preferred) / 30)); + + KUNIT_EXPECT_TRUE(test, drm_crtc_helper_vrr_flush(crtc_state)); + KUNIT_EXPECT_EQ(test, crtc_state->vrr_state.cur_vtotal, + crtc_state->vrr_state.base_vtotal); + + /* + * Invoking drm_crtc_helper_vrr_flush() again should not change + * cur_vtotal, meaning it should return false. + */ + KUNIT_EXPECT_FALSE(test, drm_crtc_helper_vrr_flush(crtc_state)); + KUNIT_EXPECT_EQ(test, crtc_state->vrr_state.cur_vtotal, + crtc_state->vrr_state.base_vtotal); + + KUNIT_EXPECT_TRUE(test, drm_crtc_helper_vrr_vsync(crtc_state)); + KUNIT_EXPECT_EQ(test, crtc_state->vrr_state.cur_vtotal, + crtc_state->vrr_state.max_vtotal); + + /* Same as above, double invocation should leave it unchanged. */ + + KUNIT_EXPECT_FALSE(test, drm_crtc_helper_vrr_vsync(crtc_state)); + KUNIT_EXPECT_EQ(test, crtc_state->vrr_state.cur_vtotal, + crtc_state->vrr_state.max_vtotal); + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); +} + +static struct kunit_case drm_atomic_helper_connector_hdmi_vrr_tests[] =3D { + KUNIT_CASE(drm_test_check_hdmi_vrr), + KUNIT_CASE(drm_test_check_hdmi_vrr_sink_fail), + KUNIT_CASE(drm_test_check_hdmi_vrr_flush_vsync), + { } +}; + +static struct kunit_suite drm_atomic_helper_connector_hdmi_vrr_test_suite = =3D { + .name =3D "drm_atomic_helper_connector_hdmi_vrr", + .test_cases =3D drm_atomic_helper_connector_hdmi_vrr_tests, +}; + kunit_test_suites( &drm_atomic_helper_connector_hdmi_check_test_suite, &drm_atomic_helper_connector_hdmi_reset_test_suite, &drm_atomic_helper_connector_hdmi_mode_valid_test_suite, &drm_atomic_helper_connector_hdmi_infoframes_test_suite, + &drm_atomic_helper_connector_hdmi_vrr_test_suite, ); =20 MODULE_AUTHOR("Maxime Ripard "); diff --git a/drivers/gpu/drm/tests/drm_kunit_edid.h b/drivers/gpu/drm/tests= /drm_kunit_edid.h index 28b4df93a555..10175c9e1b2e 100644 --- a/drivers/gpu/drm/tests/drm_kunit_edid.h +++ b/drivers/gpu/drm/tests/drm_kunit_edid.h @@ -13,4 +13,143 @@ extern const unsigned char test_edid_hdmi_1080p_rgb_yuv= _dc_max_340mhz[256]; extern const unsigned char test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_2= 00mhz[256]; extern const unsigned char test_edid_hdmi_4k_rgb_yuv420_dc_max_340mhz[256]; =20 +/* + * Max resolution: 3840x2160@60Hz with YUV420 + * Max BPC: 16 for all modes + * Max TMDS clock: <340MHz, so set to 0 + * VRR range: 30Hz to 120Hz + * CinemaVRR flag is set + * + * edid-decode (hex): + * + * 00 ff ff ff ff ff ff 00 31 d8 43 00 00 00 00 00 + * 01 24 01 03 80 60 36 78 0f ee 91 a3 54 4c 99 26 + * 0f 50 54 20 00 00 01 01 01 01 01 01 01 01 01 01 + * 01 01 01 01 01 01 04 74 80 18 71 38 2d 40 58 2c + * 45 00 c0 1c 32 00 00 1e 04 74 00 30 f2 70 5a 80 + * b0 58 8a 00 c0 1c 32 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 18 78 18 87 22 00 0a 20 20 20 20 20 20 01 7e + * + * 02 03 29 31 42 3f 5f 6d 03 0c 00 10 00 78 00 20 + * 00 00 00 20 61 6d d8 5d c4 01 00 80 07 10 1e 78 + * 00 00 00 e2 0e 61 e2 00 ed 00 00 00 00 00 00 00 + * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 68 + * + * ---------------- + * + * Block 0, Base EDID: + * EDID Structure Version & Revision: 1.3 + * Vendor & Product Identification: + * Manufacturer: LNX + * Model: 67 + * Made in: week 1 of 2026 + * Basic Display Parameters & Features: + * Digital display + * Maximum image size: 96 cm x 54 cm + * Gamma: 2.20 + * RGB color display + * Default (sRGB) color space is primary color space + * First detailed timing is the preferred timing + * Supports GTF timings within operating range + * Color Characteristics: + * Red : 0.6396, 0.3300 + * Green: 0.2998, 0.5996 + * Blue : 0.1503, 0.0595 + * White: 0.3125, 0.3291 + * Established Timings I & II: + * DMT 0x04: 640x480 59.940476 Hz 4:3 31.469 kHz 25.1750= 00 MHz + * Standard Timings: none + * Detailed Timing Descriptors: + * DTD 1: 1920x1080 120.000000 Hz 16:9 135.000 kHz 297.000000 = MHz (960 mm x 540 mm) + * Hfront 88 Hsync 44 Hback 148 Hpol P + * Vfront 4 Vsync 5 Vback 36 Vpol P + * DTD 2: 3840x2160 30.000000 Hz 16:9 67.500 kHz 297.000000 = MHz (960 mm x 540 mm) + * Hfront 176 Hsync 88 Hback 296 Hpol P + * Vfront 8 Vsync 10 Vback 72 Vpol P + * Display Product Name: 'Test EDID' + * Display Range Limits: + * Monitor ranges (GTF): 24-120 Hz V, 24-135 kHz H, max dotclock 340 = MHz + * Extension blocks: 1 + * Checksum: 0x7e + * + * ---------------- + * + * Block 1, CTA-861 Extension Block: + * Revision: 3 + * Supports YCbCr 4:4:4 + * Supports YCbCr 4:2:2 + * Native detailed modes: 1 + * Video Data Block: + * VIC 63: 1920x1080 120.000000 Hz 16:9 135.000 kHz 297.00000= 0 MHz + * VIC 95: 3840x2160 30.000000 Hz 16:9 67.500 kHz 297.00000= 0 MHz + * Vendor-Specific Data Block (HDMI), OUI 00-0C-03: + * Source physical address: 1.0.0.0 + * DC_48bit + * DC_36bit + * DC_30bit + * DC_Y444 + * Maximum TMDS clock: 0 MHz + * Extended HDMI video details: + * Vendor-Specific Data Block (HDMI Forum), OUI C4-5D-D8: + * Version: 1 + * SCDC Present + * Supports 16-bits/component Deep Color 4:2:0 Pixel Encoding + * Supports 12-bits/component Deep Color 4:2:0 Pixel Encoding + * Supports 10-bits/component Deep Color 4:2:0 Pixel Encoding + * Supports media rates below VRRmin (CinemaVRR, deprecated) + * VRRmin: 30 Hz + * VRRmax: 120 Hz + * YCbCr 4:2:0 Video Data Block: + * VIC 97: 3840x2160 60.000000 Hz 16:9 135.000 kHz 594.00000= 0 MHz + * Video Capability Data Block: + * YCbCr quantization: Selectable (via AVI YQ) + * RGB quantization: Selectable (via AVI Q) + * PT scan behavior: Always Underscanned + * IT scan behavior: Supports both over- and underscan + * CE scan behavior: Always Overscanned + * Checksum: 0x68 Unused space in Extension Block: 86 bytes + * + * ---------------- + * + * edid-decode 1.32.0 + * + * Warnings: + * + * Block 1, CTA-861 Extension Block: + * *** v- pretty sure this one's a bug in edid-decode *** + * IT Video Formats are overscanned by default, but normally this should = be underscanned. + * Vendor-Specific Data Block (HDMI Forum), OUI C4-5D-D8: CinemaVRR is de= precated and must be cleared. + * + * EDID conformity: PASS + */ +static const unsigned char test_edid_hdmi_vrr[] =3D { + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x31, 0xd8, 0x43, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x24, 0x01, 0x03, 0x80, 0x60, 0x36, 0x78, + 0x0f, 0xee, 0x91, 0xa3, 0x54, 0x4c, 0x99, 0x26, 0x0f, 0x50, 0x54, 0x20, + 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x74, 0x80, 0x18, 0x71, 0x38, + 0x2d, 0x40, 0x58, 0x2c, 0x45, 0x00, 0xc0, 0x1c, 0x32, 0x00, 0x00, 0x1e, + 0x04, 0x74, 0x00, 0x30, 0xf2, 0x70, 0x5a, 0x80, 0xb0, 0x58, 0x8a, 0x00, + 0xc0, 0x1c, 0x32, 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, 0x18, 0x78, 0x18, 0x87, 0x22, 0x00, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, 0x7e, 0x02, 0x03, 0x29, 0x31, + 0x42, 0x3f, 0x5f, 0x6d, 0x03, 0x0c, 0x00, 0x10, 0x00, 0x78, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x20, 0x61, 0x6d, 0xd8, 0x5d, 0xc4, 0x01, 0x00, 0x80, + 0x07, 0x10, 0x1e, 0x78, 0x00, 0x00, 0x00, 0xe2, 0x0e, 0x61, 0xe2, 0x00, + 0xed, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x68 +}; + #endif // DRM_KUNIT_EDID_H_ --=20 2.55.0 From nobody Fri Sep 25 21:02:41 2026 Received: from sender4-pp-f112.zoho.com (sender4-pp-f112.zoho.com [136.143.188.112]) (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 7D2714CCDF5; Mon, 21 Sep 2026 15:54:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=136.143.188.112 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790006097; cv=pass; b=V/eneXs0xoybjEx6Pw5JVlP1FSG9zDdFGqKr0y5EZyvac+auKgihvK8NS/6D3BoY0BEfwOyZqL00LKkd+CugrHVPuN0jRefKRnydrFVfOCWwAoSjzeEpyL+AAjZvzi6s4FHHyvhO0MjPx7VJTcq6OqdQgJga5JtzUkPMy3GUIUI= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790006097; c=relaxed/simple; bh=PMMKaY8nE1sRbKrXmC5a1+zOTZLOHy3U/MxWP8rliMQ=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=D0VUysmdvPldYkxsLk3WM/jc4UBn9yvvyPZhd4BCrsiGtigPJ2Qcw852etI6XTsKDffEK1J2bUnsPQT8/f3noanhLeTscxvsy11hr2tfJnwCIZ9uJoZzlp1tqGLhZcdrG/hbnK7dUFt2YIe7mw7oDA2+YzoljeQcKMNm4D+xyUg= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (1024-bit key) header.d=collabora.com header.i=nicolas.frattaroli@collabora.com header.b=CH8pIiTi; arc=pass smtp.client-ip=136.143.188.112 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=collabora.com header.i=nicolas.frattaroli@collabora.com header.b="CH8pIiTi" ARC-Seal: i=1; a=rsa-sha256; t=1790006051; cv=none; d=zohomail.com; s=zohoarc; b=JbERihLlTl6ddoNa7uvB4QYs45V6byIzhah4jwffUAZ4gblS6HIgxrV94wvZfmXm25GzrDNLhBdKikYGPe+eLlHBoIYToKVk9cHtyrLEZXwQqefEXHHPz8IIqcWSdKy/g0Yu6pu/719zUFCmyh3yEEjNpkz/GTmviPzSChK3cOc= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1790006051; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:MIME-Version:Message-ID:Subject:Subject:To:To:Message-Id:Reply-To; bh=6omB1+qDFmqaueIObGOPy4D/eBZasljicjGizkGe7WQ=; b=dBjJllzz5y69ffDZum0f9ml1BKSGwHyZDcoLCLmZQCjmoYjP/hTluSdEa2PzRUlBX5rIJhNqoIBCfGRG2rKvNhmLoih2UX3FntywjTIcAfXeKFm5rCx/+9f58Zvc4tSK4QX/KbUAcKjUA+yzka+XRON1V80IXsxxeOVhBDCG9LQ= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass header.i=collabora.com; spf=pass smtp.mailfrom=nicolas.frattaroli@collabora.com; dmarc=pass header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1790006051; s=zohomail; d=collabora.com; i=nicolas.frattaroli@collabora.com; h=From:From:Date:Date:Subject:Subject:MIME-Version:Content-Type:Content-Transfer-Encoding:Message-Id:Message-Id:In-Reply-To:To:To:Cc:Cc:Reply-To; bh=6omB1+qDFmqaueIObGOPy4D/eBZasljicjGizkGe7WQ=; b=CH8pIiTi8UrYxx7DCM3CVe+7rBmdBalPDGRE+rQttc2Vf+gqdb4mjd07gd6Z5aUC 1re/e5KO4/Xvzd+eSpfxLyPpFaJLJFN/egD54q7mGw2G6uHDzyA1sytkCVp3fYZ7dcO KovmTE3Y/zKwLgnFvn2BFhYCxdQRAPE3kj6xzCZ0= Received: by smtp.zohomail.com with SMTPS id 1790006050167952.4265439297211; Mon, 21 Sep 2026 08:54:10 -0700 (PDT) From: Nicolas Frattaroli Date: Mon, 21 Sep 2026 17:51:49 +0200 Subject: [PATCH RFC 23/25] drm/tests: hdmi: Add Fixed/Constrained rate VRR tests Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260921-vrr-limiter-uapi-v1-23-2fcd7d011646@collabora.com> References: <20260921-vrr-limiter-uapi-v1-0-2fcd7d011646@collabora.com> In-Reply-To: <20260921-vrr-limiter-uapi-v1-0-2fcd7d011646@collabora.com> To: "Borah, Chaitanya Kumar" , Leo Li , Daniel Stone , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Helge Deller , Andrzej Hajda , Neil Armstrong , Robert Foss , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Luca Ceresoli , Sandy Huang , =?utf-8?q?Heiko_St=C3=BCbner?= , Andy Yan Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, linux-fbdev@vger.kernel.org, linux-rockchip@lists.infradead.org, linux-arm-kernel@lists.infradead.org, kernel@collabora.com, Derek Foreman , wayland-devel@lists.freedesktop.org, Nicolas Frattaroli X-Mailer: b4 0.15.2 Add tests to verify the functionality of the VRR_{MIN,MAX}_{NUMERATOR,DENOMINATOR} properties and the HDMI state helpers that make use of them. This includes tests for fixed rate scenarios, as well as a test for a constrained game mode scenario. A parametric test case checks that various erroneous target rates are rejected. Proper handling of CinemaVRR is tested as well. Signed-off-by: Nicolas Frattaroli --- drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 532 +++++++++++++++++= ++++ 1 file changed, 532 insertions(+) diff --git a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c b/drivers/g= pu/drm/tests/drm_hdmi_state_helper_test.c index 1486c16c2f78..e2d98280ea23 100644 --- a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c +++ b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c @@ -3674,10 +3674,542 @@ static void drm_test_check_hdmi_vrr_flush_vsync(st= ruct kunit *test) drm_modeset_acquire_fini(&ctx); } =20 +/* + * Check that on a VRR-capable sink with VRR enabled and a fixed target ra= te + * set, an atomic commit works, and the derived vtotals are as expected. + */ +static void drm_test_check_hdmi_vrr_fixed_rate(struct kunit *test) +{ + struct drm_atomic_helper_connector_hdmi_priv *priv; + struct drm_modeset_acquire_ctx ctx; + struct drm_display_mode *preferred; + struct drm_crtc_state *crtc_state; + struct drm_atomic_commit *state; + struct drm_connector *conn; + struct drm_device *drm; + struct drm_crtc *crtc; + int mode_refresh; + int ret; + + priv =3D drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test, + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), + 8, + &dummy_connector_hdmi_funcs, + test_edid_hdmi_vrr); + KUNIT_ASSERT_NOT_NULL(test, priv); + + drm =3D &priv->drm; + crtc =3D priv->crtc; + conn =3D &priv->connector; + KUNIT_ASSERT_TRUE(test, conn->display_info.is_hdmi); + KUNIT_ASSERT_TRUE(test, conn->display_info.hdmi.vrr_capable); + KUNIT_ASSERT_TRUE(test, conn->display_info.hdmi.cinema_vrr); + + preferred =3D find_preferred_mode(conn); + KUNIT_ASSERT_NOT_NULL(test, preferred); + + mode_refresh =3D drm_mode_vrefresh(preferred); + + drm_modeset_acquire_init(&ctx, 0); + +retry_conn_enable: + ret =3D drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn, + preferred, &ctx); + if (ret =3D=3D -EDEADLK) { + ret =3D drm_modeset_backoff(&ctx); + if (!ret) + goto retry_conn_enable; + } + KUNIT_ASSERT_EQ(test, ret, 0); + + state =3D drm_kunit_helper_atomic_state_alloc(test, drm, &ctx); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state); + +retry_crtc_state: + crtc_state =3D drm_atomic_get_crtc_state(state, crtc); + if (PTR_ERR(crtc_state) =3D=3D -EDEADLK) { + drm_atomic_commit_clear(state); + ret =3D drm_modeset_backoff(&ctx); + if (!ret) + goto retry_crtc_state; + } + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state); + + crtc_state->vrr_enabled =3D true; + crtc_state->vrr_state.vrr_min_n =3D 40; + crtc_state->vrr_state.vrr_min_d =3D 1; + /* Equivalent fraction, expressed differently to pose a hurdle */ + crtc_state->vrr_state.vrr_max_n =3D 40000; + crtc_state->vrr_state.vrr_max_d =3D 1000; + + ret =3D drm_atomic_commit(state); + if (ret =3D=3D -EDEADLK) { + drm_atomic_commit_clear(state); + ret =3D drm_modeset_backoff(&ctx); + if (!ret) + goto retry_crtc_state; + } + KUNIT_ASSERT_EQ(test, ret, 0); + + crtc_state =3D drm_atomic_get_new_crtc_state(state, crtc); + KUNIT_ASSERT_NOT_NULL(test, crtc_state); + + KUNIT_EXPECT_EQ(test, crtc_state->vrr_state.base_vtotal, + preferred->crtc_vtotal * mode_refresh / 40); + + /* Minimum rate is 24Hz because of the CinemaVRR flag */ + KUNIT_EXPECT_EQ(test, crtc_state->vrr_state.max_vtotal, + preferred->crtc_vtotal * mode_refresh / 24); + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); +} + +/* + * Check that the drm_hdmi_helper_vrr_flush() and drm_hdmi_helper_vrr_vsyn= c() + * helpers return the expected values on a VRR-capable sink with VRR enabl= ed + * and a fixed target set. + */ +static void drm_test_check_hdmi_vrr_fixed_rate_flush_vsync(struct kunit *t= est) +{ + struct drm_atomic_helper_connector_hdmi_priv *priv; + struct drm_modeset_acquire_ctx ctx; + struct drm_display_mode *preferred; + struct drm_crtc_state *crtc_state; + struct drm_atomic_commit *state; + struct drm_connector *conn; + struct drm_device *drm; + struct drm_crtc *crtc; + int mode_refresh; + int ret; + + priv =3D drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test, + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), + 8, + &dummy_connector_hdmi_funcs, + test_edid_hdmi_vrr); + KUNIT_ASSERT_NOT_NULL(test, priv); + + drm =3D &priv->drm; + crtc =3D priv->crtc; + conn =3D &priv->connector; + KUNIT_ASSERT_TRUE(test, conn->display_info.is_hdmi); + KUNIT_ASSERT_TRUE(test, conn->display_info.hdmi.vrr_capable); + + preferred =3D find_preferred_mode(conn); + KUNIT_ASSERT_NOT_NULL(test, preferred); + + mode_refresh =3D drm_mode_vrefresh(preferred); + + drm_modeset_acquire_init(&ctx, 0); + +retry_conn_enable: + ret =3D drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn, + preferred, &ctx); + if (ret =3D=3D -EDEADLK) { + ret =3D drm_modeset_backoff(&ctx); + if (!ret) + goto retry_conn_enable; + } + KUNIT_ASSERT_EQ(test, ret, 0); + + state =3D drm_kunit_helper_atomic_state_alloc(test, drm, &ctx); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state); + +retry_crtc_state: + crtc_state =3D drm_atomic_get_crtc_state(state, crtc); + if (PTR_ERR(crtc_state) =3D=3D -EDEADLK) { + drm_atomic_commit_clear(state); + ret =3D drm_modeset_backoff(&ctx); + if (!ret) + goto retry_crtc_state; + } + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state); + + crtc_state->vrr_enabled =3D true; + crtc_state->vrr_state.vrr_min_n =3D 40000; + crtc_state->vrr_state.vrr_min_d =3D 1001; + /* Equivalent fraction, expressed differently to pose a hurdle */ + crtc_state->vrr_state.vrr_max_n =3D 80000; + crtc_state->vrr_state.vrr_max_d =3D 2002; + + ret =3D drm_atomic_commit(state); + if (ret =3D=3D -EDEADLK) { + drm_atomic_commit_clear(state); + ret =3D drm_modeset_backoff(&ctx); + if (!ret) + goto retry_crtc_state; + } + KUNIT_ASSERT_EQ(test, ret, 0); + + crtc_state =3D drm_atomic_get_new_crtc_state(state, crtc); + KUNIT_ASSERT_NOT_NULL(test, crtc_state); + + KUNIT_EXPECT_EQ(test, crtc_state->vrr_state.base_vtotal, + mult_frac(preferred->crtc_vtotal, mode_refresh * 1000, 39960)); + + /* Fixed rate case: flush should never trigger a vtotal update. */ + KUNIT_EXPECT_FALSE(test, drm_crtc_helper_vrr_flush(crtc_state)); + KUNIT_EXPECT_EQ(test, crtc_state->vrr_state.cur_vtotal, 0); + + /* + * Invoking drm_hdmi_helper_vrr_flush() again should not change + * cur_vtotal, meaning it should return false. + */ + KUNIT_EXPECT_FALSE(test, drm_crtc_helper_vrr_flush(crtc_state)); + KUNIT_EXPECT_EQ(test, crtc_state->vrr_state.cur_vtotal, 0); + + /* First vsync will set cur_vtotal. */ + KUNIT_EXPECT_TRUE(test, drm_crtc_helper_vrr_vsync(crtc_state)); + KUNIT_EXPECT_EQ(test, crtc_state->vrr_state.cur_vtotal, + crtc_state->vrr_state.base_vtotal); + /* First vsync with fixed rate will still be dynamic. */ + KUNIT_EXPECT_TRUE(test, crtc_state->vrr_state.dynamic); + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); + + /* Try a second commit to evaluate the dynamic flag */ + + drm_modeset_acquire_init(&ctx, 0); + +retry_conn_enable_2: + ret =3D drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn, + preferred, &ctx); + if (ret =3D=3D -EDEADLK) { + ret =3D drm_modeset_backoff(&ctx); + if (!ret) + goto retry_conn_enable_2; + } + KUNIT_ASSERT_EQ(test, ret, 0); + + state =3D drm_kunit_helper_atomic_state_alloc(test, drm, &ctx); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state); + +retry_crtc_state_2: + crtc_state =3D drm_atomic_get_crtc_state(state, crtc); + if (PTR_ERR(crtc_state) =3D=3D -EDEADLK) { + drm_atomic_commit_clear(state); + ret =3D drm_modeset_backoff(&ctx); + if (!ret) + goto retry_crtc_state_2; + } + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state); + + ret =3D drm_atomic_commit(state); + if (ret =3D=3D -EDEADLK) { + drm_atomic_commit_clear(state); + ret =3D drm_modeset_backoff(&ctx); + if (!ret) + goto retry_crtc_state_2; + } + KUNIT_ASSERT_EQ(test, ret, 0); + + crtc_state =3D drm_atomic_get_new_crtc_state(state, crtc); + KUNIT_ASSERT_NOT_NULL(test, crtc_state); + + KUNIT_EXPECT_FALSE(test, drm_crtc_helper_vrr_flush(crtc_state)); + KUNIT_EXPECT_EQ(test, crtc_state->vrr_state.cur_vtotal, + crtc_state->vrr_state.base_vtotal); + KUNIT_EXPECT_FALSE(test, crtc_state->vrr_state.dynamic); + KUNIT_EXPECT_FALSE(test, drm_crtc_helper_vrr_vsync(crtc_state)); + KUNIT_EXPECT_EQ(test, crtc_state->vrr_state.cur_vtotal, + crtc_state->vrr_state.base_vtotal); + /* Subsequent vsyncs with fixed rate won't be dynamic. */ + KUNIT_EXPECT_FALSE(test, crtc_state->vrr_state.dynamic); + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); +} + +struct vrr_target_error_params { + unsigned int vrr_min_n; + unsigned int vrr_min_d; + unsigned int vrr_max_n; + unsigned int vrr_max_d; + bool cinema_vrr_override; + const char *desc; +}; + +static struct vrr_target_error_params vrr_target_errors[] =3D { + { 26, 1, 26 * 2000, 2000, false, "VRR target <=3D min rate should fail" }, + { 200, 1, 200, 1, true, "VRR target <=3D max rate should fail" }, + { 60, 1, 40, 1, true, "VRR max target <=3D VRR min target should fail" }, + { 40, 1, 60, 0, true, "VRR max target denominator of 0 should fail" }, + { 40, 0, 60, 1, true, "VRR min target denominator of 0 should fail" }, + { 25000, 1001, 30, 1, true, "CinemaVRR with non-fixed rate should fail" }, +}; + +KUNIT_ARRAY_PARAM_DESC(check_vrr_target_errors, vrr_target_errors, desc); + +/* + * Check that on a VRR-capable sink with VRR enabled and various erroneous + * combinations of target rates set, an atomic commit fails. + */ +static void drm_test_check_hdmi_vrr_target_rate_fail(struct kunit *test) +{ + const struct vrr_target_error_params *params =3D test->param_value; + struct drm_atomic_helper_connector_hdmi_priv *priv; + struct drm_modeset_acquire_ctx ctx; + struct drm_display_mode *preferred; + struct drm_crtc_state *crtc_state; + struct drm_atomic_commit *state; + struct drm_connector *conn; + struct drm_device *drm; + struct drm_crtc *crtc; + int ret; + + priv =3D drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test, + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), + 8, + &dummy_connector_hdmi_funcs, + test_edid_hdmi_vrr); + KUNIT_ASSERT_NOT_NULL(test, priv); + + drm =3D &priv->drm; + crtc =3D priv->crtc; + conn =3D &priv->connector; + KUNIT_ASSERT_TRUE(test, conn->display_info.is_hdmi); + KUNIT_ASSERT_TRUE(test, conn->display_info.hdmi.vrr_capable); + KUNIT_ASSERT_LT(test, 24, conn->display_info.monitor_range.min_vfreq); + + preferred =3D find_preferred_mode(conn); + KUNIT_ASSERT_NOT_NULL(test, preferred); + + drm_modeset_acquire_init(&ctx, 0); + +retry_conn_enable: + ret =3D drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn, + preferred, &ctx); + if (ret =3D=3D -EDEADLK) { + ret =3D drm_modeset_backoff(&ctx); + if (!ret) + goto retry_conn_enable; + } + KUNIT_ASSERT_EQ(test, ret, 0); + + state =3D drm_kunit_helper_atomic_state_alloc(test, drm, &ctx); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state); + + /* + * Allow individual test parameters to play with the CinemaVRR flag + * without needing to bring their own modified EDID. + */ + conn->display_info.hdmi.cinema_vrr =3D params->cinema_vrr_override; + +retry_crtc_state: + crtc_state =3D drm_atomic_get_crtc_state(state, crtc); + if (PTR_ERR(crtc_state) =3D=3D -EDEADLK) { + drm_atomic_commit_clear(state); + ret =3D drm_modeset_backoff(&ctx); + if (!ret) + goto retry_crtc_state; + } + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state); + + crtc_state->vrr_enabled =3D true; + crtc_state->vrr_state.vrr_min_n =3D params->vrr_min_n; + crtc_state->vrr_state.vrr_min_d =3D params->vrr_min_d; + crtc_state->vrr_state.vrr_max_n =3D params->vrr_max_n; + crtc_state->vrr_state.vrr_max_d =3D params->vrr_max_d; + + ret =3D drm_atomic_commit(state); + if (ret =3D=3D -EDEADLK) { + drm_atomic_commit_clear(state); + ret =3D drm_modeset_backoff(&ctx); + if (!ret) + goto retry_crtc_state; + } + KUNIT_EXPECT_LT(test, ret, 0); + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); +} + +/* + * Check that on a VRR-capable sink that has the CinemaVRR flag set, with = VRR + * enabled and a fixed target rate set, an atomic commit succeeds at a rate + * only possible if CinemaVRR is supported and a fixed target is used. + */ +static void drm_test_check_hdmi_vrr_fixed_rate_cinema_vrr(struct kunit *te= st) +{ + struct drm_atomic_helper_connector_hdmi_priv *priv; + struct drm_modeset_acquire_ctx ctx; + struct drm_display_mode *preferred; + struct drm_crtc_state *crtc_state; + struct drm_atomic_commit *state; + struct drm_connector *conn; + struct drm_device *drm; + struct drm_crtc *crtc; + int mode_refresh; + int ret; + + priv =3D drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test, + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), + 8, + &dummy_connector_hdmi_funcs, + test_edid_hdmi_vrr); + KUNIT_ASSERT_NOT_NULL(test, priv); + + drm =3D &priv->drm; + crtc =3D priv->crtc; + conn =3D &priv->connector; + KUNIT_ASSERT_TRUE(test, conn->display_info.is_hdmi); + KUNIT_ASSERT_TRUE(test, conn->display_info.hdmi.vrr_capable); + KUNIT_ASSERT_TRUE(test, conn->display_info.hdmi.cinema_vrr); + KUNIT_ASSERT_LT(test, 24, conn->display_info.monitor_range.min_vfreq); + + preferred =3D find_preferred_mode(conn); + KUNIT_ASSERT_NOT_NULL(test, preferred); + + mode_refresh =3D drm_mode_vrefresh(preferred); + + drm_modeset_acquire_init(&ctx, 0); + +retry_conn_enable: + ret =3D drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn, + preferred, &ctx); + if (ret =3D=3D -EDEADLK) { + ret =3D drm_modeset_backoff(&ctx); + if (!ret) + goto retry_conn_enable; + } + KUNIT_ASSERT_EQ(test, ret, 0); + + state =3D drm_kunit_helper_atomic_state_alloc(test, drm, &ctx); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state); + +retry_crtc_state: + crtc_state =3D drm_atomic_get_crtc_state(state, crtc); + if (PTR_ERR(crtc_state) =3D=3D -EDEADLK) { + drm_atomic_commit_clear(state); + ret =3D drm_modeset_backoff(&ctx); + if (!ret) + goto retry_crtc_state; + } + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state); + + crtc_state->vrr_enabled =3D true; + + /* 24/1.001 Hz should work */ + crtc_state->vrr_state.vrr_min_n =3D 24000; + crtc_state->vrr_state.vrr_min_d =3D 1001; + crtc_state->vrr_state.vrr_max_n =3D 24000; + crtc_state->vrr_state.vrr_max_d =3D 1001; + + ret =3D drm_atomic_commit(state); + if (ret =3D=3D -EDEADLK) { + drm_atomic_commit_clear(state); + ret =3D drm_modeset_backoff(&ctx); + if (!ret) + goto retry_crtc_state; + } + KUNIT_EXPECT_EQ(test, ret, 0); + KUNIT_EXPECT_EQ(test, crtc_state->vrr_state.base_vtotal, + mult_frac(preferred->crtc_vtotal, mode_refresh * 1000, 23976)); + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); +} + +/* + * Check that on a VRR-capable sink, an atomic commit with a VRR minimum a= nd + * maximum target rate that's more narrow than the monitor's target rate + * succeeds and produces the expected derived values. + */ +static void drm_test_check_hdmi_vrr_constrained_rate(struct kunit *test) +{ + struct drm_atomic_helper_connector_hdmi_priv *priv; + struct drm_modeset_acquire_ctx ctx; + struct drm_display_mode *preferred; + struct drm_crtc_state *crtc_state; + struct drm_atomic_commit *state; + struct drm_connector *conn; + struct drm_device *drm; + struct drm_crtc *crtc; + int mode_refresh; + int ret; + + priv =3D drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test, + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), + 8, + &dummy_connector_hdmi_funcs, + test_edid_hdmi_vrr); + KUNIT_ASSERT_NOT_NULL(test, priv); + + drm =3D &priv->drm; + crtc =3D priv->crtc; + conn =3D &priv->connector; + KUNIT_ASSERT_TRUE(test, conn->display_info.is_hdmi); + KUNIT_ASSERT_TRUE(test, conn->display_info.hdmi.vrr_capable); + + preferred =3D find_preferred_mode(conn); + KUNIT_ASSERT_NOT_NULL(test, preferred); + + mode_refresh =3D drm_mode_vrefresh(preferred); + + drm_modeset_acquire_init(&ctx, 0); + +retry_conn_enable: + ret =3D drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn, + preferred, &ctx); + if (ret =3D=3D -EDEADLK) { + ret =3D drm_modeset_backoff(&ctx); + if (!ret) + goto retry_conn_enable; + } + KUNIT_ASSERT_EQ(test, ret, 0); + + state =3D drm_kunit_helper_atomic_state_alloc(test, drm, &ctx); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state); + +retry_crtc_state: + crtc_state =3D drm_atomic_get_crtc_state(state, crtc); + if (PTR_ERR(crtc_state) =3D=3D -EDEADLK) { + drm_atomic_commit_clear(state); + ret =3D drm_modeset_backoff(&ctx); + if (!ret) + goto retry_crtc_state; + } + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state); + + crtc_state->vrr_enabled =3D true; + crtc_state->vrr_state.vrr_min_n =3D 40; + crtc_state->vrr_state.vrr_min_d =3D 1; + crtc_state->vrr_state.vrr_max_n =3D 80; + crtc_state->vrr_state.vrr_max_d =3D 1; + + ret =3D drm_atomic_commit(state); + if (ret =3D=3D -EDEADLK) { + drm_atomic_commit_clear(state); + ret =3D drm_modeset_backoff(&ctx); + if (!ret) + goto retry_crtc_state; + } + KUNIT_ASSERT_EQ(test, ret, 0); + + crtc_state =3D drm_atomic_get_new_crtc_state(state, crtc); + KUNIT_ASSERT_NOT_NULL(test, crtc_state); + + KUNIT_EXPECT_EQ(test, crtc_state->vrr_state.base_vtotal, + preferred->crtc_vtotal * mode_refresh / 80); + KUNIT_EXPECT_EQ(test, crtc_state->vrr_state.max_vtotal, + preferred->crtc_vtotal * mode_refresh / 40); + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); +} + static struct kunit_case drm_atomic_helper_connector_hdmi_vrr_tests[] =3D { KUNIT_CASE(drm_test_check_hdmi_vrr), KUNIT_CASE(drm_test_check_hdmi_vrr_sink_fail), KUNIT_CASE(drm_test_check_hdmi_vrr_flush_vsync), + KUNIT_CASE(drm_test_check_hdmi_vrr_fixed_rate), + KUNIT_CASE(drm_test_check_hdmi_vrr_fixed_rate_flush_vsync), + KUNIT_CASE_PARAM(drm_test_check_hdmi_vrr_target_rate_fail, + check_vrr_target_errors_gen_params), + KUNIT_CASE(drm_test_check_hdmi_vrr_fixed_rate_cinema_vrr), + KUNIT_CASE(drm_test_check_hdmi_vrr_constrained_rate), { } }; =20 --=20 2.55.0 From nobody Fri Sep 25 21:02:41 2026 Received: from sender4-pp-f112.zoho.com (sender4-pp-f112.zoho.com [136.143.188.112]) (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 D9D4F4A0921; Mon, 21 Sep 2026 15:55:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=136.143.188.112 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790006119; cv=pass; b=CfAZLvLNePjENl3lwV/ROFVOaH4/2YNjkB/NVZmtMz2l2EWSvKUYzplHf+JSyRifBCVH6o2tlxNjnNCL93sNAtZVEjqMeoUErTHmB4pz6lsObybYMJuTQGt/gmPtSfB31ELr4RO1Mn6HDUFvDQkJANZQdFruhm0/ODeRzn6jlEU= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790006119; c=relaxed/simple; bh=duYTZ2+1NUkw9f21PyMkC0CaDgz0EDpKIr774xSguPs=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=dpBB9+FtSpI3BZ3NEGp9is1MWmU4Fa7qruh2DjTbS0ECB+liaS9LBX2ARHkH85RyqfL2CRRWCsYfruPY5iaw7SenuSs+zeJgDKVrOcb6aCXznmyMda7bYJfPq2l1qW+rC768rUTSgkqNKuBExQMOcQYxDCMaacK5GQlonxHXalQ= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (1024-bit key) header.d=collabora.com header.i=nicolas.frattaroli@collabora.com header.b=UQzciu0C; arc=pass smtp.client-ip=136.143.188.112 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=collabora.com header.i=nicolas.frattaroli@collabora.com header.b="UQzciu0C" ARC-Seal: i=1; a=rsa-sha256; t=1790006057; cv=none; d=zohomail.com; s=zohoarc; b=kWnnucDCgjsMc15Ca0bKXevcthUdeUiLDSsY0dk+/jvyQp8ixUOIWll+G5S+XuSuhtwvK1EyNag2i+olZhnWcZiGXJJ1S+Ef9sVNgs/dyioFhMb7C/tq4UGgSbBxNWSkeoPKkdP1swQtPzxYGUQIzTl+QZBq5bDiTcx0VsUTFJQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1790006057; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:MIME-Version:Message-ID:Subject:Subject:To:To:Message-Id:Reply-To; bh=Vfsv6aK7GfXtbnn5HLKv5OIremt2SvHxyOB3/TnLMqk=; b=Q3TpK1kH0CGindO0+wI9IwuKPEcUjMsHktQQctrUO+STTAeOmAKM2LUDwO0cqndgfdS5XFzYhTtMhTABSO5/DL2BIJ8k8nbHcOOcRpAlRA2rsbMFK22WKncysYFJEuNu9gHZXP+jTRCwGJ2Z42JxCko3uH7BXX0xHuKBekjNRWw= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass header.i=collabora.com; spf=pass smtp.mailfrom=nicolas.frattaroli@collabora.com; dmarc=pass header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1790006057; s=zohomail; d=collabora.com; i=nicolas.frattaroli@collabora.com; h=From:From:Date:Date:Subject:Subject:MIME-Version:Content-Type:Content-Transfer-Encoding:Message-Id:Message-Id:In-Reply-To:To:To:Cc:Cc:Reply-To; bh=Vfsv6aK7GfXtbnn5HLKv5OIremt2SvHxyOB3/TnLMqk=; b=UQzciu0CaHxexI609MxVKwGZBAEhRpOtHL83rl6k/scIKUKnsy3+Rhpb/2nAyW5G aoP52cFNgjrGaoYxpJIVZ2sOMnk9OQeM5E+zQS9Ub9ZCJYMTtul1C/Vx/7U5nRiK6DT PS3m7PRsGjWyU2Gu95kX/W/h8Kg3HCpcKQ9Q5xoM= Received: by smtp.zohomail.com with SMTPS id 1790006055625821.5593241292398; Mon, 21 Sep 2026 08:54:15 -0700 (PDT) From: Nicolas Frattaroli Date: Mon, 21 Sep 2026 17:51:50 +0200 Subject: [PATCH RFC 24/25] drm/tests: hdmi: Add Quick Media Switching tests Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260921-vrr-limiter-uapi-v1-24-2fcd7d011646@collabora.com> References: <20260921-vrr-limiter-uapi-v1-0-2fcd7d011646@collabora.com> In-Reply-To: <20260921-vrr-limiter-uapi-v1-0-2fcd7d011646@collabora.com> To: "Borah, Chaitanya Kumar" , Leo Li , Daniel Stone , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Helge Deller , Andrzej Hajda , Neil Armstrong , Robert Foss , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Luca Ceresoli , Sandy Huang , =?utf-8?q?Heiko_St=C3=BCbner?= , Andy Yan Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, linux-fbdev@vger.kernel.org, linux-rockchip@lists.infradead.org, linux-arm-kernel@lists.infradead.org, kernel@collabora.com, Derek Foreman , wayland-devel@lists.freedesktop.org, Nicolas Frattaroli X-Mailer: b4 0.15.2 Add KUnit tests to validate the HDMI Quick Media Switching (QMS) functionality in the HDMI state helpers. This includes tests to validate that the QMS TFR min and QMS TFR max flags are respected. Signed-off-by: Nicolas Frattaroli --- drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 587 +++++++++++++++++= ++++ drivers/gpu/drm/tests/drm_kunit_edid.h | 140 +++++ 2 files changed, 727 insertions(+) diff --git a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c b/drivers/g= pu/drm/tests/drm_hdmi_state_helper_test.c index e2d98280ea23..961a4b48afd8 100644 --- a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c +++ b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c @@ -4200,6 +4200,587 @@ static void drm_test_check_hdmi_vrr_constrained_rat= e(struct kunit *test) drm_modeset_acquire_fini(&ctx); } =20 +/* + * Check that on a QMS-capable sink, an atomic commit with the qms_enabled + * connector property set succeeds, and produces the right connector state + * values. + */ +static void drm_test_check_hdmi_vrr_qms(struct kunit *test) +{ + struct drm_atomic_helper_connector_hdmi_priv *priv; + struct drm_connector_state *conn_state; + struct drm_modeset_acquire_ctx ctx; + struct drm_display_mode *preferred; + struct drm_crtc_state *crtc_state; + struct drm_atomic_commit *state; + struct drm_connector *conn; + struct drm_device *drm; + struct drm_crtc *crtc; + int ret; + + priv =3D drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test, + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), + 8, + &dummy_connector_hdmi_funcs, + test_edid_hdmi_vrr_qms); + KUNIT_ASSERT_NOT_NULL(test, priv); + + drm =3D &priv->drm; + crtc =3D priv->crtc; + conn =3D &priv->connector; + KUNIT_ASSERT_TRUE(test, conn->display_info.is_hdmi); + KUNIT_ASSERT_TRUE(test, conn->display_info.hdmi.vrr_capable); + KUNIT_ASSERT_TRUE(test, conn->display_info.hdmi.qms_capable); + + preferred =3D find_preferred_mode(conn); + KUNIT_ASSERT_NOT_NULL(test, preferred); + + drm_modeset_acquire_init(&ctx, 0); + +retry_conn_enable: + ret =3D drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn, + preferred, &ctx); + if (ret =3D=3D -EDEADLK) { + ret =3D drm_modeset_backoff(&ctx); + if (!ret) + goto retry_conn_enable; + } + KUNIT_ASSERT_EQ(test, ret, 0); + + state =3D drm_kunit_helper_atomic_state_alloc(test, drm, &ctx); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state); + +retry_crtc_state: + crtc_state =3D drm_atomic_get_crtc_state(state, crtc); + if (PTR_ERR(crtc_state) =3D=3D -EDEADLK) { + drm_atomic_commit_clear(state); + ret =3D drm_modeset_backoff(&ctx); + if (!ret) + goto retry_crtc_state; + } + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state); + + crtc_state->vrr_enabled =3D true; + crtc_state->vrr_state.vrr_min_n =3D 48000; + crtc_state->vrr_state.vrr_min_d =3D 1001; + /* Equivalent fraction, as an added hurdle */ + crtc_state->vrr_state.vrr_max_n =3D 48000 * 2; + crtc_state->vrr_state.vrr_max_d =3D 1001 * 2; + +retry_conn_state: + conn_state =3D drm_atomic_get_connector_state(state, conn); + if (PTR_ERR(conn_state) =3D=3D -EDEADLK) { + drm_atomic_commit_clear(state); + ret =3D drm_modeset_backoff(&ctx); + if (!ret) + goto retry_conn_state; + } + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state); + + conn_state->hdmi.qms_enabled =3D true; + + ret =3D drm_atomic_commit(state); + if (ret =3D=3D -EDEADLK) { + drm_atomic_commit_clear(state); + ret =3D drm_modeset_backoff(&ctx); + if (!ret) + goto retry_crtc_state; + } + KUNIT_EXPECT_EQ(test, ret, 0); + + conn_state =3D drm_atomic_get_new_connector_state(state, conn); + KUNIT_ASSERT_NOT_NULL(test, conn_state); + + KUNIT_EXPECT_EQ(test, conn_state->hdmi.qms_tfr_byte, 6); + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); +} + +/* + * Check that on a QMS-capable sink, an atomic commit with the qms_enabled + * connector property set fails if the requested target rate is not suppor= ted + * by QMS. + */ +static void drm_test_check_hdmi_vrr_qms_fail(struct kunit *test) +{ + struct drm_atomic_helper_connector_hdmi_priv *priv; + struct drm_connector_state *conn_state; + struct drm_modeset_acquire_ctx ctx; + struct drm_display_mode *preferred; + struct drm_crtc_state *crtc_state; + struct drm_atomic_commit *state; + struct drm_connector *conn; + struct drm_device *drm; + struct drm_crtc *crtc; + int ret; + + priv =3D drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test, + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), + 8, + &dummy_connector_hdmi_funcs, + test_edid_hdmi_vrr_qms); + KUNIT_ASSERT_NOT_NULL(test, priv); + + drm =3D &priv->drm; + crtc =3D priv->crtc; + conn =3D &priv->connector; + KUNIT_ASSERT_TRUE(test, conn->display_info.is_hdmi); + KUNIT_ASSERT_TRUE(test, conn->display_info.hdmi.vrr_capable); + KUNIT_ASSERT_TRUE(test, conn->display_info.hdmi.qms_capable); + + preferred =3D find_preferred_mode(conn); + KUNIT_ASSERT_NOT_NULL(test, preferred); + + drm_modeset_acquire_init(&ctx, 0); + +retry_conn_enable: + ret =3D drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn, + preferred, &ctx); + if (ret =3D=3D -EDEADLK) { + ret =3D drm_modeset_backoff(&ctx); + if (!ret) + goto retry_conn_enable; + } + KUNIT_ASSERT_EQ(test, ret, 0); + + state =3D drm_kunit_helper_atomic_state_alloc(test, drm, &ctx); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state); + +retry_crtc_state: + crtc_state =3D drm_atomic_get_crtc_state(state, crtc); + if (PTR_ERR(crtc_state) =3D=3D -EDEADLK) { + drm_atomic_commit_clear(state); + ret =3D drm_modeset_backoff(&ctx); + if (!ret) + goto retry_crtc_state; + } + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state); + + crtc_state->vrr_enabled =3D true; + crtc_state->vrr_state.vrr_min_n =3D 67; + crtc_state->vrr_state.vrr_min_d =3D 1; + crtc_state->vrr_state.vrr_max_n =3D 67; + crtc_state->vrr_state.vrr_max_d =3D 1; + +retry_conn_state: + conn_state =3D drm_atomic_get_connector_state(state, conn); + if (PTR_ERR(conn_state) =3D=3D -EDEADLK) { + drm_atomic_commit_clear(state); + ret =3D drm_modeset_backoff(&ctx); + if (!ret) + goto retry_conn_state; + } + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state); + + conn_state->hdmi.qms_enabled =3D true; + + ret =3D drm_atomic_commit(state); + if (ret =3D=3D -EDEADLK) { + drm_atomic_commit_clear(state); + ret =3D drm_modeset_backoff(&ctx); + if (!ret) + goto retry_crtc_state; + } + KUNIT_EXPECT_LT(test, ret, 0); + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); +} + +/* + * Check that on a QMS-capable sink, an atomic commit with the qms_enabled + * connector property set fails if the requested target rate is not a fixed + * rate. + */ +static void drm_test_check_hdmi_vrr_qms_nonfixed_fail(struct kunit *test) +{ + struct drm_atomic_helper_connector_hdmi_priv *priv; + struct drm_connector_state *conn_state; + struct drm_modeset_acquire_ctx ctx; + struct drm_display_mode *preferred; + struct drm_crtc_state *crtc_state; + struct drm_atomic_commit *state; + struct drm_connector *conn; + struct drm_device *drm; + struct drm_crtc *crtc; + int ret; + + priv =3D drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test, + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), + 8, + &dummy_connector_hdmi_funcs, + test_edid_hdmi_vrr_qms); + KUNIT_ASSERT_NOT_NULL(test, priv); + + drm =3D &priv->drm; + crtc =3D priv->crtc; + conn =3D &priv->connector; + KUNIT_ASSERT_TRUE(test, conn->display_info.is_hdmi); + KUNIT_ASSERT_TRUE(test, conn->display_info.hdmi.vrr_capable); + KUNIT_ASSERT_TRUE(test, conn->display_info.hdmi.qms_capable); + + preferred =3D find_preferred_mode(conn); + KUNIT_ASSERT_NOT_NULL(test, preferred); + + drm_modeset_acquire_init(&ctx, 0); + +retry_conn_enable: + ret =3D drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn, + preferred, &ctx); + if (ret =3D=3D -EDEADLK) { + ret =3D drm_modeset_backoff(&ctx); + if (!ret) + goto retry_conn_enable; + } + KUNIT_ASSERT_EQ(test, ret, 0); + + state =3D drm_kunit_helper_atomic_state_alloc(test, drm, &ctx); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state); + +retry_crtc_state: + crtc_state =3D drm_atomic_get_crtc_state(state, crtc); + if (PTR_ERR(crtc_state) =3D=3D -EDEADLK) { + drm_atomic_commit_clear(state); + ret =3D drm_modeset_backoff(&ctx); + if (!ret) + goto retry_crtc_state; + } + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state); + + crtc_state->vrr_enabled =3D true; + crtc_state->vrr_state.vrr_min_n =3D 30; + crtc_state->vrr_state.vrr_min_d =3D 1; + crtc_state->vrr_state.vrr_max_n =3D 60; + crtc_state->vrr_state.vrr_max_d =3D 1; + +retry_conn_state: + conn_state =3D drm_atomic_get_connector_state(state, conn); + if (PTR_ERR(conn_state) =3D=3D -EDEADLK) { + drm_atomic_commit_clear(state); + ret =3D drm_modeset_backoff(&ctx); + if (!ret) + goto retry_conn_state; + } + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state); + + conn_state->hdmi.qms_enabled =3D true; + + ret =3D drm_atomic_commit(state); + if (ret =3D=3D -EDEADLK) { + drm_atomic_commit_clear(state); + ret =3D drm_modeset_backoff(&ctx); + if (!ret) + goto retry_crtc_state; + } + KUNIT_EXPECT_LT(test, ret, 0); + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); +} + +/* + * Check that on a QMS-capable sink with QMS TFR min set, an atomic commit= with + * the qms_enabled connector property set succeeds even if the target rate= is + * below the monitor's range, and that it produces the right connector sta= te + * values. + */ +static void drm_test_check_hdmi_vrr_qms_tfr_min(struct kunit *test) +{ + struct drm_atomic_helper_connector_hdmi_priv *priv; + struct drm_connector_state *conn_state; + struct drm_modeset_acquire_ctx ctx; + struct drm_display_mode *preferred; + struct drm_crtc_state *crtc_state; + struct drm_atomic_commit *state; + struct drm_connector *conn; + struct drm_device *drm; + struct drm_crtc *crtc; + int ret; + + priv =3D drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test, + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), + 8, + &dummy_connector_hdmi_funcs, + test_edid_hdmi_vrr_qms); + KUNIT_ASSERT_NOT_NULL(test, priv); + + drm =3D &priv->drm; + crtc =3D priv->crtc; + conn =3D &priv->connector; + KUNIT_ASSERT_TRUE(test, conn->display_info.is_hdmi); + KUNIT_ASSERT_TRUE(test, conn->display_info.hdmi.vrr_capable); + KUNIT_ASSERT_TRUE(test, conn->display_info.hdmi.qms_capable); + KUNIT_ASSERT_TRUE(test, conn->display_info.hdmi.qms_tfr_min); + /* + * The CinemaVRR flag provides equivalent functionality to QMS Min TFR + * for non-QMS VRR, so it should be false to ensure that this unit test + * tests the right thing. + */ + KUNIT_ASSERT_FALSE(test, conn->display_info.hdmi.cinema_vrr); + + KUNIT_ASSERT_LT(test, 24, conn->display_info.monitor_range.min_vfreq); + + preferred =3D find_preferred_mode(conn); + KUNIT_ASSERT_NOT_NULL(test, preferred); + + drm_modeset_acquire_init(&ctx, 0); + +retry_conn_enable: + ret =3D drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn, + preferred, &ctx); + if (ret =3D=3D -EDEADLK) { + ret =3D drm_modeset_backoff(&ctx); + if (!ret) + goto retry_conn_enable; + } + KUNIT_ASSERT_EQ(test, ret, 0); + + state =3D drm_kunit_helper_atomic_state_alloc(test, drm, &ctx); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state); + +retry_crtc_state: + crtc_state =3D drm_atomic_get_crtc_state(state, crtc); + if (PTR_ERR(crtc_state) =3D=3D -EDEADLK) { + drm_atomic_commit_clear(state); + ret =3D drm_modeset_backoff(&ctx); + if (!ret) + goto retry_crtc_state; + } + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state); + + crtc_state->vrr_enabled =3D true; + crtc_state->vrr_state.vrr_min_n =3D 24; + crtc_state->vrr_state.vrr_min_d =3D 1; + crtc_state->vrr_state.vrr_max_n =3D 24; + crtc_state->vrr_state.vrr_max_d =3D 1; + +retry_conn_state: + conn_state =3D drm_atomic_get_connector_state(state, conn); + if (PTR_ERR(conn_state) =3D=3D -EDEADLK) { + drm_atomic_commit_clear(state); + ret =3D drm_modeset_backoff(&ctx); + if (!ret) + goto retry_conn_state; + } + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state); + + conn_state->hdmi.qms_enabled =3D true; + + ret =3D drm_atomic_commit(state); + if (ret =3D=3D -EDEADLK) { + drm_atomic_commit_clear(state); + ret =3D drm_modeset_backoff(&ctx); + if (!ret) + goto retry_crtc_state; + } + KUNIT_EXPECT_EQ(test, ret, 0); + + conn_state =3D drm_atomic_get_new_connector_state(state, conn); + KUNIT_ASSERT_NOT_NULL(test, conn_state); + + KUNIT_EXPECT_EQ(test, conn_state->hdmi.qms_tfr_byte, 2); + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); +} + +/* + * Check that on a QMS-capable sink without the QMS max TFR flag, an atomic + * commit with QMS enabled and a target rate above 60Hz fails. + */ +static void drm_test_check_hdmi_vrr_qms_no_tfr_max_fail(struct kunit *test) +{ + struct drm_atomic_helper_connector_hdmi_priv *priv; + struct drm_connector_state *conn_state; + struct drm_modeset_acquire_ctx ctx; + struct drm_display_mode *preferred; + struct drm_crtc_state *crtc_state; + struct drm_atomic_commit *state; + struct drm_connector *conn; + struct drm_device *drm; + struct drm_crtc *crtc; + int ret; + + priv =3D drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test, + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), + 8, + &dummy_connector_hdmi_funcs, + test_edid_hdmi_vrr_qms); + KUNIT_ASSERT_NOT_NULL(test, priv); + + drm =3D &priv->drm; + crtc =3D priv->crtc; + conn =3D &priv->connector; + KUNIT_ASSERT_TRUE(test, conn->display_info.is_hdmi); + KUNIT_ASSERT_TRUE(test, conn->display_info.hdmi.vrr_capable); + KUNIT_ASSERT_TRUE(test, conn->display_info.hdmi.qms_capable); + KUNIT_ASSERT_FALSE(test, conn->display_info.hdmi.qms_tfr_max); + + KUNIT_ASSERT_LE(test, 100, conn->display_info.monitor_range.max_vfreq); + + ret =3D drm_connector_attach_qms_enabled_property(conn); + KUNIT_ASSERT_EQ(test, ret, 0); + + preferred =3D find_preferred_mode(conn); + KUNIT_ASSERT_NOT_NULL(test, preferred); + + drm_modeset_acquire_init(&ctx, 0); + +retry_conn_enable: + ret =3D drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn, + preferred, &ctx); + if (ret =3D=3D -EDEADLK) { + ret =3D drm_modeset_backoff(&ctx); + if (!ret) + goto retry_conn_enable; + } + KUNIT_ASSERT_EQ(test, ret, 0); + + state =3D drm_kunit_helper_atomic_state_alloc(test, drm, &ctx); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state); + +retry_crtc_state: + crtc_state =3D drm_atomic_get_crtc_state(state, crtc); + if (PTR_ERR(crtc_state) =3D=3D -EDEADLK) { + drm_atomic_commit_clear(state); + ret =3D drm_modeset_backoff(&ctx); + if (!ret) + goto retry_crtc_state; + } + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state); + + crtc_state->vrr_enabled =3D true; + crtc_state->vrr_state.vrr_min_n =3D 100; + crtc_state->vrr_state.vrr_min_d =3D 1; + crtc_state->vrr_state.vrr_max_n =3D 100; + crtc_state->vrr_state.vrr_max_d =3D 1; + +retry_conn_state: + conn_state =3D drm_atomic_get_connector_state(state, conn); + if (PTR_ERR(conn_state) =3D=3D -EDEADLK) { + drm_atomic_commit_clear(state); + ret =3D drm_modeset_backoff(&ctx); + if (!ret) + goto retry_conn_state; + } + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state); + + conn_state->hdmi.qms_enabled =3D true; + + ret =3D drm_atomic_commit(state); + if (ret =3D=3D -EDEADLK) { + drm_atomic_commit_clear(state); + ret =3D drm_modeset_backoff(&ctx); + if (!ret) + goto retry_crtc_state; + } + KUNIT_EXPECT_LT(test, ret, 0); + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); +} + +/* + * Check that on a QMS-capable sink with the QMS max TFR flag, an atomic c= ommit + * with QMS enabled and a target rate above 60Hz succeeds. + */ +static void drm_test_check_hdmi_vrr_qms_tfr_max(struct kunit *test) +{ + struct drm_atomic_helper_connector_hdmi_priv *priv; + struct drm_connector_state *conn_state; + struct drm_modeset_acquire_ctx ctx; + struct drm_display_mode *preferred; + struct drm_crtc_state *crtc_state; + struct drm_atomic_commit *state; + struct drm_connector *conn; + struct drm_device *drm; + struct drm_crtc *crtc; + int ret; + + priv =3D drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test, + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), + 8, + &dummy_connector_hdmi_funcs, + test_edid_hdmi_vrr_qms); + KUNIT_ASSERT_NOT_NULL(test, priv); + + drm =3D &priv->drm; + crtc =3D priv->crtc; + conn =3D &priv->connector; + KUNIT_ASSERT_TRUE(test, conn->display_info.is_hdmi); + KUNIT_ASSERT_TRUE(test, conn->display_info.hdmi.vrr_capable); + KUNIT_ASSERT_TRUE(test, conn->display_info.hdmi.qms_capable); + + KUNIT_ASSERT_LE(test, 100, conn->display_info.monitor_range.max_vfreq); + + preferred =3D find_preferred_mode(conn); + KUNIT_ASSERT_NOT_NULL(test, preferred); + + drm_modeset_acquire_init(&ctx, 0); + +retry_conn_enable: + ret =3D drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn, + preferred, &ctx); + if (ret =3D=3D -EDEADLK) { + ret =3D drm_modeset_backoff(&ctx); + if (!ret) + goto retry_conn_enable; + } + KUNIT_ASSERT_EQ(test, ret, 0); + + state =3D drm_kunit_helper_atomic_state_alloc(test, drm, &ctx); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state); + + /* Manual override to not have to define an additional EDID. */ + conn->display_info.hdmi.qms_tfr_max =3D true; + +retry_crtc_state: + crtc_state =3D drm_atomic_get_crtc_state(state, crtc); + if (PTR_ERR(crtc_state) =3D=3D -EDEADLK) { + drm_atomic_commit_clear(state); + ret =3D drm_modeset_backoff(&ctx); + if (!ret) + goto retry_crtc_state; + } + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state); + + crtc_state->vrr_enabled =3D true; + crtc_state->vrr_state.vrr_min_n =3D 1000; /* Intentional tomfoolery. */ + crtc_state->vrr_state.vrr_min_d =3D 10; + crtc_state->vrr_state.vrr_max_n =3D 100; + crtc_state->vrr_state.vrr_max_d =3D 1; + +retry_conn_state: + conn_state =3D drm_atomic_get_connector_state(state, conn); + if (PTR_ERR(conn_state) =3D=3D -EDEADLK) { + drm_atomic_commit_clear(state); + ret =3D drm_modeset_backoff(&ctx); + if (!ret) + goto retry_conn_state; + } + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state); + + conn_state->hdmi.qms_enabled =3D true; + + ret =3D drm_atomic_commit(state); + if (ret =3D=3D -EDEADLK) { + drm_atomic_commit_clear(state); + ret =3D drm_modeset_backoff(&ctx); + if (!ret) + goto retry_crtc_state; + } + KUNIT_EXPECT_EQ(test, ret, 0); + + conn_state =3D drm_atomic_get_new_connector_state(state, conn); + KUNIT_ASSERT_NOT_NULL(test, conn_state); + + KUNIT_EXPECT_EQ(test, conn_state->hdmi.qms_tfr_byte, 11); + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); +} + static struct kunit_case drm_atomic_helper_connector_hdmi_vrr_tests[] =3D { KUNIT_CASE(drm_test_check_hdmi_vrr), KUNIT_CASE(drm_test_check_hdmi_vrr_sink_fail), @@ -4210,6 +4791,12 @@ static struct kunit_case drm_atomic_helper_connector= _hdmi_vrr_tests[] =3D { check_vrr_target_errors_gen_params), KUNIT_CASE(drm_test_check_hdmi_vrr_fixed_rate_cinema_vrr), KUNIT_CASE(drm_test_check_hdmi_vrr_constrained_rate), + KUNIT_CASE(drm_test_check_hdmi_vrr_qms), + KUNIT_CASE(drm_test_check_hdmi_vrr_qms_fail), + KUNIT_CASE(drm_test_check_hdmi_vrr_qms_nonfixed_fail), + KUNIT_CASE(drm_test_check_hdmi_vrr_qms_tfr_min), + KUNIT_CASE(drm_test_check_hdmi_vrr_qms_no_tfr_max_fail), + KUNIT_CASE(drm_test_check_hdmi_vrr_qms_tfr_max), { } }; =20 diff --git a/drivers/gpu/drm/tests/drm_kunit_edid.h b/drivers/gpu/drm/tests= /drm_kunit_edid.h index 10175c9e1b2e..71029101a4ab 100644 --- a/drivers/gpu/drm/tests/drm_kunit_edid.h +++ b/drivers/gpu/drm/tests/drm_kunit_edid.h @@ -152,4 +152,144 @@ static const unsigned char test_edid_hdmi_vrr[] =3D { 0x00, 0x00, 0x00, 0x68 }; =20 +/* + * Max resolution: 3840x2160@60Hz with YUV420 + * Max BPC: 16 for all modes + * Max TMDS clock: <340MHz, so set to 0 + * VRR range: 30Hz to 120Hz + * CinemaVRR flag is unset + * QMS flag is set + * QMS TFRmin flag is set + * + * edid-decode (hex): + * + * 00 ff ff ff ff ff ff 00 31 d8 45 00 00 00 00 00 + * 01 24 01 03 80 60 36 78 0f ee 91 a3 54 4c 99 26 + * 0f 50 54 20 00 00 01 01 01 01 01 01 01 01 01 01 + * 01 01 01 01 01 01 04 74 80 18 71 38 2d 40 58 2c + * 45 00 c0 1c 32 00 00 1e 04 74 00 30 f2 70 5a 80 + * b0 58 8a 00 c0 1c 32 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 18 78 18 87 22 00 0a 20 20 20 20 20 20 01 7c + * + * 02 03 29 31 42 3f 5f 6d 03 0c 00 10 00 78 00 20 + * 00 00 00 20 61 6d d8 5d c4 01 00 80 07 40 1e 78 + * 10 00 00 e2 0e 61 e2 00 ed 00 00 00 00 00 00 00 + * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 28 + * + * ---------------- + * + * Block 0, Base EDID: + * EDID Structure Version & Revision: 1.3 + * Vendor & Product Identification: + * Manufacturer: LNX + * Model: 69 + * Made in: week 1 of 2026 + * Basic Display Parameters & Features: + * Digital display + * Maximum image size: 96 cm x 54 cm + * Gamma: 2.20 + * RGB color display + * Default (sRGB) color space is primary color space + * First detailed timing is the preferred timing + * Supports GTF timings within operating range + * Color Characteristics: + * Red : 0.6396, 0.3300 + * Green: 0.2998, 0.5996 + * Blue : 0.1503, 0.0595 + * White: 0.3125, 0.3291 + * Established Timings I & II: + * DMT 0x04: 640x480 59.940476 Hz 4:3 31.469 kHz 25.1750= 00 MHz + * Standard Timings: none + * Detailed Timing Descriptors: + * DTD 1: 1920x1080 120.000000 Hz 16:9 135.000 kHz 297.000000 = MHz (960 mm x 540 mm) + * Hfront 88 Hsync 44 Hback 148 Hpol P + * Vfront 4 Vsync 5 Vback 36 Vpol P + * DTD 2: 3840x2160 30.000000 Hz 16:9 67.500 kHz 297.000000 = MHz (960 mm x 540 mm) + * Hfront 176 Hsync 88 Hback 296 Hpol P + * Vfront 8 Vsync 10 Vback 72 Vpol P + * Display Product Name: 'Test EDID' + * Display Range Limits: + * Monitor ranges (GTF): 24-120 Hz V, 24-135 kHz H, max dotclock 340 = MHz + * Extension blocks: 1 + * Checksum: 0x7c + * + * ---------------- + * + * Block 1, CTA-861 Extension Block: + * Revision: 3 + * Supports YCbCr 4:4:4 + * Supports YCbCr 4:2:2 + * Native detailed modes: 1 + * Video Data Block: + * VIC 63: 1920x1080 120.000000 Hz 16:9 135.000 kHz 297.00000= 0 MHz + * VIC 95: 3840x2160 30.000000 Hz 16:9 67.500 kHz 297.00000= 0 MHz + * Vendor-Specific Data Block (HDMI), OUI 00-0C-03: + * Source physical address: 1.0.0.0 + * DC_48bit + * DC_36bit + * DC_30bit + * DC_Y444 + * Maximum TMDS clock: 0 MHz + * Extended HDMI video details: + * Vendor-Specific Data Block (HDMI Forum), OUI C4-5D-D8: + * Version: 1 + * SCDC Present + * Supports 16-bits/component Deep Color 4:2:0 Pixel Encoding + * Supports 12-bits/component Deep Color 4:2:0 Pixel Encoding + * Supports 10-bits/component Deep Color 4:2:0 Pixel Encoding + * Supports QMS + * VRRmin: 30 Hz + * VRRmax: 120 Hz + * Supports QMS TFRmin + * YCbCr 4:2:0 Video Data Block: + * VIC 97: 3840x2160 60.000000 Hz 16:9 135.000 kHz 594.00000= 0 MHz + * Video Capability Data Block: + * YCbCr quantization: Selectable (via AVI YQ) + * RGB quantization: Selectable (via AVI Q) + * PT scan behavior: Always Underscanned + * IT scan behavior: Supports both over- and underscan + * CE scan behavior: Always Overscanned + * Checksum: 0x28 Unused space in Extension Block: 86 bytes + * + * ---------------- + * + * edid-decode 1.32.0 + * + * Warnings: + * + * Block 1, CTA-861 Extension Block: + * IT Video Formats are overscanned by default, but normally this should = be underscanned. + * + * EDID conformity: PASS + */ +static const unsigned char test_edid_hdmi_vrr_qms[] =3D { + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x31, 0xd8, 0x45, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x24, 0x01, 0x03, 0x80, 0x60, 0x36, 0x78, + 0x0f, 0xee, 0x91, 0xa3, 0x54, 0x4c, 0x99, 0x26, 0x0f, 0x50, 0x54, 0x20, + 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x74, 0x80, 0x18, 0x71, 0x38, + 0x2d, 0x40, 0x58, 0x2c, 0x45, 0x00, 0xc0, 0x1c, 0x32, 0x00, 0x00, 0x1e, + 0x04, 0x74, 0x00, 0x30, 0xf2, 0x70, 0x5a, 0x80, 0xb0, 0x58, 0x8a, 0x00, + 0xc0, 0x1c, 0x32, 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, 0x18, 0x78, 0x18, 0x87, 0x22, 0x00, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, 0x7c, 0x02, 0x03, 0x29, 0x31, + 0x42, 0x3f, 0x5f, 0x6d, 0x03, 0x0c, 0x00, 0x10, 0x00, 0x78, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x20, 0x61, 0x6d, 0xd8, 0x5d, 0xc4, 0x01, 0x00, 0x80, + 0x07, 0x40, 0x1e, 0x78, 0x10, 0x00, 0x00, 0xe2, 0x0e, 0x61, 0xe2, 0x00, + 0xed, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x28 +}; + #endif // DRM_KUNIT_EDID_H_ --=20 2.55.0 From nobody Fri Sep 25 21:02:41 2026 Received: from sender4-pp-f112.zoho.com (sender4-pp-f112.zoho.com [136.143.188.112]) (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 15C824BE453; Mon, 21 Sep 2026 15:55:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=136.143.188.112 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790006108; cv=pass; b=LHZ5aERXQ9Iyyfh32iWQrKKJO9BYPHm7yfsubV5rTLRezPatnV3wllG/7TAcxJhSFx9Sey/XnnYc+njRUAb//8uDzP9OjBjJ0ON2mSBHU7YbaqvQIPNZzOpby8RvSegeIU5alH9dpoHYzcvW9/j0WPJhpjGNZtxPp0GoAB21asM= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790006108; c=relaxed/simple; bh=CIjfVGA4XAY4BoJ/G/bTJlJw1cAPRAD+CYvA8qmeKpU=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=UkgK8TiM3oQWf4jYWhf5+QdcLDWpygtqGCcRtRm+9LVywMkv0Vk/s6WRDMKFuzWBD6nOZuJ40pk2NYCVJMWVJqWs3KsfM4vj120Uaa11PDMa9ougQE8NGloUIK0oDdHgLnsP9tQL1IzdsZ7FCHhXQavvcsJ1ZTcfGi0KENa8cr0= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (1024-bit key) header.d=collabora.com header.i=nicolas.frattaroli@collabora.com header.b=exKmfr7o; arc=pass smtp.client-ip=136.143.188.112 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=collabora.com header.i=nicolas.frattaroli@collabora.com header.b="exKmfr7o" ARC-Seal: i=1; a=rsa-sha256; t=1790006063; cv=none; d=zohomail.com; s=zohoarc; b=MGzb9I3lJG6/w4sDzPIQ6G7X83UNuPF/21AZ37wkS0cD6MZAsLDH+2RVj+GViuQApJgXnJz6kQcLZeBcCf0tCdRumo/9Xb+Sv+mWRTZPOj0j/7+dN8N+LTU7yCIqQLkfsA5w+uodald0sikSmpjZDKOkqlxasF11BqHCGECqLEs= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1790006063; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:MIME-Version:Message-ID:Subject:Subject:To:To:Message-Id:Reply-To; bh=OGTxG2oVwgVmmQXCyhauY5aLJERWACnLUbauLJungFQ=; b=RDtONl1oAN8C6S/Cq55Tc1m4dhomRBMo4mf1LG9KKP7IurcK7hT377vIH9k6TLcmDr7htH9fKk2sn68KAGzMvTnXz7vWpiEmLyoXno57Lyl1lWNwffP3Rc2tcXuQMiLKYbl4d8h6a2nBfEtl7xUkScZg4j5dvDAHTY8oOos/oBM= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass header.i=collabora.com; spf=pass smtp.mailfrom=nicolas.frattaroli@collabora.com; dmarc=pass header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1790006063; s=zohomail; d=collabora.com; i=nicolas.frattaroli@collabora.com; h=From:From:Date:Date:Subject:Subject:MIME-Version:Content-Type:Content-Transfer-Encoding:Message-Id:Message-Id:In-Reply-To:To:To:Cc:Cc:Reply-To; bh=OGTxG2oVwgVmmQXCyhauY5aLJERWACnLUbauLJungFQ=; b=exKmfr7oIJcDNpqQCMBp9rrgcLlUYiMSTfS9nfwLh86y6S65UZLHp+fvhIiEWCHG TEEShdoUxY6van1eWLJKYcgd6yQulWugGCzWbYog1ny7I1guaz6OnP2GgXzs7aAvYnM t660TgiABNqt77I6LKuUOhvbTs9Dt9lx4mAyWIKk= Received: by smtp.zohomail.com with SMTPS id 1790006061638752.154553168372; Mon, 21 Sep 2026 08:54:21 -0700 (PDT) From: Nicolas Frattaroli Date: Mon, 21 Sep 2026 17:51:51 +0200 Subject: [PATCH RFC 25/25] drm/atomic: Disable VRR in helper_set_config Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260921-vrr-limiter-uapi-v1-25-2fcd7d011646@collabora.com> References: <20260921-vrr-limiter-uapi-v1-0-2fcd7d011646@collabora.com> In-Reply-To: <20260921-vrr-limiter-uapi-v1-0-2fcd7d011646@collabora.com> To: "Borah, Chaitanya Kumar" , Leo Li , Daniel Stone , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Helge Deller , Andrzej Hajda , Neil Armstrong , Robert Foss , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Luca Ceresoli , Sandy Huang , =?utf-8?q?Heiko_St=C3=BCbner?= , Andy Yan Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, linux-fbdev@vger.kernel.org, linux-rockchip@lists.infradead.org, linux-arm-kernel@lists.infradead.org, kernel@collabora.com, Derek Foreman , wayland-devel@lists.freedesktop.org, Nicolas Frattaroli X-Mailer: b4 0.15.2 The in-kernel DRM clients do not know how to deal with VRR properties. This means that a DRM client that does, exits, and does not clean up after itself, will leave the KMS fbdev console non-functional. Address this by simply setting crtc_state->vrr_enabled to false in __drm_atomic_helper_set_config. Signed-off-by: Nicolas Frattaroli --- drivers/gpu/drm/drm_atomic.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 9bb761eda59f..1d3c35f7788e 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -2051,6 +2051,8 @@ int __drm_atomic_helper_set_config(struct drm_mode_se= t *set, =20 crtc_state->active =3D true; =20 + crtc_state->vrr_enabled =3D false; + ret =3D drm_atomic_set_crtc_for_plane(primary_state, crtc); if (ret !=3D 0) return ret; --=20 2.55.0