From: Mario Limonciello <[email protected]>

Discover the last bridge in a chain that owns brightness control, attach
its relative luminance range to the connector, and forward atomic
luminance updates to it.

Do not infer panel luminance support from a terminal panel bridge. Panels
still have direct consumers, so their connector integration must remain
explicit.

Signed-off-by: Mario Limonciello <[email protected]>
---
v10:
 * Split bridge connector integration into a separate patch
 * Do not special-case panels in the generic bridge connector
---
 drivers/gpu/drm/display/drm_bridge_connector.c | 48 ++++++++++++++++++++++++++
 1 file changed, 48 insertions(+)

diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c 
b/drivers/gpu/drm/display/drm_bridge_connector.c
index 81f3e26f6fdf5..bf0a6d162a7d3 100644
--- a/drivers/gpu/drm/display/drm_bridge_connector.c
+++ b/drivers/gpu/drm/display/drm_bridge_connector.c
@@ -125,6 +125,12 @@ struct drm_bridge_connector {
         */
        struct drm_bridge *bridge_hdmi_cec;
 
+       /**
+        * @bridge_luminance:
+        *
+        * The last bridge in the chain that controls panel luminance.
+        */
+       struct drm_bridge *bridge_luminance;
        /**
         * @hdmi_funcs:
         *
@@ -421,6 +427,28 @@ static int drm_bridge_connector_atomic_check(struct 
drm_connector *connector,
        return 0;
 }
 
+static void
+drm_bridge_connector_set_luminance(const struct drm_connector_state 
*conn_state)
+{
+       struct drm_bridge_connector *bridge_connector =
+               to_drm_bridge_connector(conn_state->connector);
+       struct drm_bridge *bridge = bridge_connector->bridge_luminance;
+
+       if (bridge)
+               bridge->funcs->set_luminance(bridge, conn_state->luminance);
+}
+
+static void
+drm_bridge_connector_disable_luminance(const struct drm_connector_state 
*conn_state)
+{
+       struct drm_bridge_connector *bridge_connector =
+               to_drm_bridge_connector(conn_state->connector);
+       struct drm_bridge *bridge = bridge_connector->bridge_luminance;
+
+       if (bridge)
+               bridge->funcs->set_luminance(bridge, 0);
+}
+
 static const struct drm_connector_helper_funcs 
drm_bridge_connector_helper_funcs = {
        .get_modes = drm_bridge_connector_get_modes,
        .detect_ctx = drm_bridge_connector_detect_ctx,
@@ -429,6 +457,8 @@ static const struct drm_connector_helper_funcs 
drm_bridge_connector_helper_funcs
        .enable_hpd = drm_bridge_connector_enable_hpd,
        .disable_hpd = drm_bridge_connector_disable_hpd,
        .atomic_check = drm_bridge_connector_atomic_check,
+       .set_luminance = drm_bridge_connector_set_luminance,
+       .disable_luminance = drm_bridge_connector_disable_luminance,
 };
 
 static enum drm_mode_status
@@ -835,6 +865,7 @@ static void drm_bridge_connector_put_bridges(struct 
drm_device *dev, void *data)
        drm_bridge_put(bridge_connector->bridge_hdmi_audio);
        drm_bridge_put(bridge_connector->bridge_dp_audio);
        drm_bridge_put(bridge_connector->bridge_hdmi_cec);
+       drm_bridge_put(bridge_connector->bridge_luminance);
 }
 
 /**
@@ -918,6 +949,13 @@ struct drm_connector *drm_bridge_connector_init(struct 
drm_device *drm,
                        drm_bridge_put(bridge_connector->bridge_detect);
                        bridge_connector->bridge_detect = 
drm_bridge_get(bridge);
                }
+               if (bridge->ops & DRM_BRIDGE_OP_LUMINANCE) {
+                       if (!bridge->funcs->set_luminance)
+                               return ERR_PTR(-EINVAL);
+
+                       drm_bridge_put(bridge_connector->bridge_luminance);
+                       bridge_connector->bridge_luminance = 
drm_bridge_get(bridge);
+               }
                if (bridge->ops & DRM_BRIDGE_OP_HDMI) {
                        if (bridge_connector->bridge_hdmi)
                                return ERR_PTR(-EBUSY);
@@ -1144,6 +1182,16 @@ struct drm_connector *drm_bridge_connector_init(struct 
drm_device *drm,
        if (panel_bridge)
                drm_panel_bridge_set_orientation(connector, panel_bridge);
 
+       if (IS_ENABLED(CONFIG_DRM_LUMINANCE) && 
bridge_connector->bridge_luminance && !connector->luminance_property) {
+               struct drm_bridge *bridge = bridge_connector->bridge_luminance;
+
+               ret = drm_connector_attach_luminance_property(connector, 0,
+                                                             
bridge->luminance_max,
+                                                            bridge->luminance);
+               if (ret)
+                       return ERR_PTR(ret);
+       }
+
        if (support_hdcp && IS_REACHABLE(CONFIG_DRM_DISPLAY_HELPER) &&
            IS_ENABLED(CONFIG_DRM_DISPLAY_HDCP_HELPER))
                drm_connector_attach_content_protection_property(connector, 
true);

-- 
2.53.0

Reply via email to