]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
drm/connector: hdmi: Calculate TMDS character rate
authorMaxime Ripard <mripard@kernel.org>
Mon, 27 May 2024 13:58:00 +0000 (15:58 +0200)
committerMaxime Ripard <mripard@kernel.org>
Tue, 28 May 2024 08:12:26 +0000 (10:12 +0200)
Most HDMI drivers have some code to calculate the TMDS character rate,
usually to adjust an internal clock to match what the mode requires.

Since the TMDS character rates mostly depends on the resolution, whether
we need to repeat pixels or not, the bpc count and the format, we can
now derive it from the HDMI connector state that stores all those infos
and remove the duplication from drivers.

Reviewed-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20240527-kms-hdmi-connector-state-v15-11-c5af16c3aae2@kernel.org
Signed-off-by: Maxime Ripard <mripard@kernel.org>
drivers/gpu/drm/display/drm_hdmi_state_helper.c
drivers/gpu/drm/drm_atomic.c
drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
include/drm/drm_connector.h

index f6cd0612ea2cb20eedd919a0951494b42d356009..08630561d8645f33a451604aee7a942ffc7249a9 100644 (file)
@@ -3,6 +3,7 @@
 #include <drm/drm_atomic.h>
 #include <drm/drm_connector.h>
 
+#include <drm/display/drm_hdmi_helper.h>
 #include <drm/display/drm_hdmi_state_helper.h>
 
 /**
@@ -25,6 +26,63 @@ void __drm_atomic_helper_connector_hdmi_reset(struct drm_connector *connector,
 }
 EXPORT_SYMBOL(__drm_atomic_helper_connector_hdmi_reset);
 
+static const struct drm_display_mode *
+connector_state_get_mode(const struct drm_connector_state *conn_state)
+{
+       struct drm_atomic_state *state;
+       struct drm_crtc_state *crtc_state;
+       struct drm_crtc *crtc;
+
+       state = conn_state->state;
+       if (!state)
+               return NULL;
+
+       crtc = conn_state->crtc;
+       if (!crtc)
+               return NULL;
+
+       crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
+       if (!crtc_state)
+               return NULL;
+
+       return &crtc_state->mode;
+}
+
+static enum drm_mode_status
+hdmi_clock_valid(const struct drm_connector *connector,
+                const struct drm_display_mode *mode,
+                unsigned long long clock)
+{
+       const struct drm_display_info *info = &connector->display_info;
+
+       if (info->max_tmds_clock && clock > info->max_tmds_clock * 1000)
+               return MODE_CLOCK_HIGH;
+
+       return MODE_OK;
+}
+
+static int
+hdmi_compute_clock(const struct drm_connector *connector,
+                  struct drm_connector_state *conn_state,
+                  const struct drm_display_mode *mode,
+                  unsigned int bpc, enum hdmi_colorspace fmt)
+{
+       enum drm_mode_status status;
+       unsigned long long clock;
+
+       clock = drm_hdmi_compute_mode_clock(mode, bpc, fmt);
+       if (!clock)
+               return -EINVAL;
+
+       status = hdmi_clock_valid(connector, mode, clock);
+       if (status != MODE_OK)
+               return -EINVAL;
+
+       conn_state->hdmi.tmds_char_rate = clock;
+
+       return 0;
+}
+
 /**
  * drm_atomic_helper_connector_hdmi_check() - Helper to check HDMI connector atomic state
  * @connector: DRM Connector
@@ -44,6 +102,15 @@ int drm_atomic_helper_connector_hdmi_check(struct drm_connector *connector,
                drm_atomic_get_old_connector_state(state, connector);
        struct drm_connector_state *new_conn_state =
                drm_atomic_get_new_connector_state(state, connector);
+       const struct drm_display_mode *mode =
+               connector_state_get_mode(new_conn_state);
+       int ret;
+
+       ret = hdmi_compute_clock(connector, new_conn_state, mode,
+                                new_conn_state->hdmi.output_bpc,
+                                new_conn_state->hdmi.output_format);
+       if (ret)
+               return ret;
 
        if (old_conn_state->hdmi.output_bpc != new_conn_state->hdmi.output_bpc ||
            old_conn_state->hdmi.output_format != new_conn_state->hdmi.output_format) {
index 8730137baa866a57ccfb4ca1dbf39961885fc47d..26f9e525c0a0756d28d9c4fbd263b8b512afc4e5 100644 (file)
@@ -1148,6 +1148,7 @@ static void drm_atomic_connector_print_state(struct drm_printer *p,
                drm_printf(p, "\toutput_bpc=%u\n", state->hdmi.output_bpc);
                drm_printf(p, "\toutput_format=%s\n",
                           drm_hdmi_connector_get_output_format_name(state->hdmi.output_format));
+               drm_printf(p, "\ttmds_char_rate=%llu\n", state->hdmi.tmds_char_rate);
        }
 
        if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
index 99fed169ea4df50ce8c736bbca9253fb17dd6855..71cfc7450134295be7955e1058a116d5fbaa5a66 100644 (file)
@@ -72,6 +72,9 @@ static int light_up_connector(struct kunit *test,
        conn_state = drm_atomic_get_connector_state(state, connector);
        KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
 
+       conn_state->hdmi.output_bpc = connector->max_bpc;
+       conn_state->hdmi.output_format = HDMI_COLORSPACE_RGB;
+
        ret = drm_atomic_set_crtc_for_connector(conn_state, crtc);
        KUNIT_EXPECT_EQ(test, ret, 0);
 
index 4b6b1117c7d015b74ae51a8228a5e584d54316bb..3bdcf904a11b5d67eae576d797e6006205ff74fa 100644 (file)
@@ -1049,6 +1049,11 @@ struct drm_connector_state {
                 * @output_format: Pixel format to output in.
                 */
                enum hdmi_colorspace output_format;
+
+               /**
+                * @tmds_char_rate: TMDS Character Rate, in Hz.
+                */
+               unsigned long long tmds_char_rate;
        } hdmi;
 };