Skip to content

Commit

Permalink
drm/connector: hdmi: Calculate TMDS character rate
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Maxime Ripard committed May 28, 2024
1 parent abb6f74 commit f035f40
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 0 deletions.
67 changes: 67 additions & 0 deletions drivers/gpu/drm/display/drm_hdmi_state_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>

/**
Expand All @@ -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
Expand All @@ -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) {
Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/drm_atomic.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
3 changes: 3 additions & 0 deletions drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
5 changes: 5 additions & 0 deletions include/drm/drm_connector.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

Expand Down

0 comments on commit f035f40

Please sign in to comment.