[PATCH v2 01/20] drm/atomic: Handle max bpc properties before connector state allocation

From: Xilin Wu

Date: Thu Oct 08 2026 - 23:19:04 EST


Allow drivers to attach the max bpc property before allocating connector
state, as needed by the upcoming non-HDMI bridge connector support.
Only update the current state when one exists.

Initialize max_requested_bpc and max_bpc from the attached property default
when creating connector state. Use drm_object_property_get_default_value()
rather than the range maximum so that state creation and subsequent resets
restore the value chosen when attaching the property.

Cover deferred allocation, existing state and restoration of a default
that differs from the range maximum in the connector KUnit tests.

Assisted-by: LLM
Signed-off-by: Xilin Wu <sophon@xxxxxxxxx>
---
drivers/gpu/drm/drm_atomic_state_helper.c | 8 +++++
drivers/gpu/drm/drm_connector.c | 6 ++--
drivers/gpu/drm/tests/drm_connector_test.c | 53 ++++++++++++++++++++++++++++++
3 files changed, 65 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c
index a2ef272e9f27..8352b5a9097a 100644
--- a/drivers/gpu/drm/drm_atomic_state_helper.c
+++ b/drivers/gpu/drm/drm_atomic_state_helper.c
@@ -494,7 +494,15 @@ void
__drm_atomic_helper_connector_state_init(struct drm_connector_state *conn_state,
struct drm_connector *connector)
{
+ u64 val;
+
conn_state->connector = connector;
+ if (connector->max_bpc_property &&
+ !drm_object_property_get_default_value(&connector->base,
+ connector->max_bpc_property, &val)) {
+ conn_state->max_requested_bpc = val;
+ conn_state->max_bpc = val;
+ }
}
EXPORT_SYMBOL(__drm_atomic_helper_connector_state_init);

diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 8b4baed060f3..34c30469f405 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -2886,8 +2886,10 @@ int drm_connector_attach_max_bpc_property(struct drm_connector *connector,
}

drm_object_attach_property(&connector->base, prop, max);
- connector->state->max_requested_bpc = max;
- connector->state->max_bpc = max;
+ if (connector->state) {
+ connector->state->max_requested_bpc = max;
+ connector->state->max_bpc = max;
+ }

return 0;
}
diff --git a/drivers/gpu/drm/tests/drm_connector_test.c b/drivers/gpu/drm/tests/drm_connector_test.c
index beb1d50a6646..1174607441b9 100644
--- a/drivers/gpu/drm/tests/drm_connector_test.c
+++ b/drivers/gpu/drm/tests/drm_connector_test.c
@@ -12,6 +12,7 @@
#include <drm/drm_file.h>
#include <drm/drm_kunit_helpers.h>
#include <drm/drm_modes.h>
+#include <drm/drm_property.h>

#include <drm/display/drm_hdmi_helper.h>

@@ -187,7 +188,59 @@ KUNIT_ARRAY_PARAM(drm_connector_init_type_valid,
drm_connector_init_type_valid_tests,
drm_connector_init_type_desc);

+/* The attached default need not equal the upper end of the property range. */
+static void drm_test_connector_max_bpc_default(struct kunit *test)
+{
+ struct drm_connector_init_priv *priv = test->priv;
+ struct drm_connector *connector = &priv->connector;
+ struct drm_property *prop;
+ int ret;
+
+ ret = drmm_connector_init(&priv->drm, connector, &dummy_funcs,
+ DRM_MODE_CONNECTOR_DisplayPort, NULL);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ prop = drm_property_create_range(&priv->drm, 0, "max bpc", 6, 12);
+ KUNIT_ASSERT_NOT_NULL(test, prop);
+ connector->max_bpc_property = prop;
+ ret = drm_connector_attach_max_bpc_property(connector, 6, 10);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+ KUNIT_EXPECT_NULL(test, connector->state);
+
+ drm_mode_config_reset(&priv->drm);
+ KUNIT_ASSERT_NOT_NULL(test, connector->state);
+ KUNIT_EXPECT_EQ(test, connector->state->max_requested_bpc, 10);
+ KUNIT_EXPECT_EQ(test, connector->state->max_bpc, 10);
+
+ connector->state->max_requested_bpc = 8;
+ connector->state->max_bpc = 8;
+ drm_mode_config_reset(&priv->drm);
+ KUNIT_ASSERT_NOT_NULL(test, connector->state);
+ KUNIT_EXPECT_EQ(test, connector->state->max_requested_bpc, 10);
+ KUNIT_EXPECT_EQ(test, connector->state->max_bpc, 10);
+}
+
+static void drm_test_connector_max_bpc_existing_state(struct kunit *test)
+{
+ struct drm_connector_init_priv *priv = test->priv;
+ struct drm_connector *connector = &priv->connector;
+ int ret;
+
+ ret = drmm_connector_init(&priv->drm, connector, &dummy_funcs,
+ DRM_MODE_CONNECTOR_DisplayPort, NULL);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+ drm_mode_config_reset(&priv->drm);
+ KUNIT_ASSERT_NOT_NULL(test, connector->state);
+
+ ret = drm_connector_attach_max_bpc_property(connector, 6, 10);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+ KUNIT_EXPECT_EQ(test, connector->state->max_requested_bpc, 10);
+ KUNIT_EXPECT_EQ(test, connector->state->max_bpc, 10);
+}
+
static struct kunit_case drmm_connector_init_tests[] = {
+ KUNIT_CASE(drm_test_connector_max_bpc_default),
+ KUNIT_CASE(drm_test_connector_max_bpc_existing_state),
KUNIT_CASE(drm_test_drmm_connector_init),
KUNIT_CASE(drm_test_drmm_connector_init_null_ddc),
KUNIT_CASE_PARAM(drm_test_drmm_connector_init_type_valid,

--
2.56.0