Skip to content

Commit

Permalink
drm/tests: Add HDMI TDMS character rate tests
Browse files Browse the repository at this point in the history
The previous patch added an helper to compute the TMDS character rate on
an HDMI connector. Let's add a few tests to make sure it works as
expected.

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-10-c5af16c3aae2@kernel.org
Signed-off-by: Maxime Ripard <mripard@kernel.org>
  • Loading branch information
Maxime Ripard committed May 28, 2024
1 parent 40167bc commit abb6f74
Showing 1 changed file with 300 additions and 0 deletions.
300 changes: 300 additions & 0 deletions drivers/gpu/drm/tests/drm_connector_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@
#include <drm/drm_atomic_state_helper.h>
#include <drm/drm_connector.h>
#include <drm/drm_drv.h>
#include <drm/drm_edid.h>
#include <drm/drm_kunit_helpers.h>
#include <drm/drm_modes.h>

#include <drm/display/drm_hdmi_helper.h>

#include <kunit/test.h>

Expand Down Expand Up @@ -621,10 +625,306 @@ static struct kunit_suite drm_hdmi_connector_get_output_format_name_test_suite =
.test_cases = drm_hdmi_connector_get_output_format_name_tests,
};

/*
* Test that for a given mode, with 8bpc and an RGB output the TMDS
* character rate is equal to the mode pixel clock.
*/
static void drm_test_drm_hdmi_compute_mode_clock_rgb(struct kunit *test)
{
struct drm_connector_init_priv *priv = test->priv;
const struct drm_display_mode *mode;
unsigned long long rate;
struct drm_device *drm = &priv->drm;

mode = drm_display_mode_from_cea_vic(drm, 16);
KUNIT_ASSERT_NOT_NULL(test, mode);

KUNIT_ASSERT_FALSE(test, mode->flags & DRM_MODE_FLAG_DBLCLK);

rate = drm_hdmi_compute_mode_clock(mode, 8, HDMI_COLORSPACE_RGB);
KUNIT_ASSERT_GT(test, rate, 0);
KUNIT_EXPECT_EQ(test, mode->clock * 1000ULL, rate);
}

/*
* Test that for a given mode, with 10bpc and an RGB output the TMDS
* character rate is equal to 1.25 times the mode pixel clock.
*/
static void drm_test_drm_hdmi_compute_mode_clock_rgb_10bpc(struct kunit *test)
{
struct drm_connector_init_priv *priv = test->priv;
const struct drm_display_mode *mode;
unsigned long long rate;
struct drm_device *drm = &priv->drm;

mode = drm_display_mode_from_cea_vic(drm, 16);
KUNIT_ASSERT_NOT_NULL(test, mode);

KUNIT_ASSERT_FALSE(test, mode->flags & DRM_MODE_FLAG_DBLCLK);

rate = drm_hdmi_compute_mode_clock(mode, 10, HDMI_COLORSPACE_RGB);
KUNIT_ASSERT_GT(test, rate, 0);
KUNIT_EXPECT_EQ(test, mode->clock * 1250, rate);
}

/*
* Test that for the VIC-1 mode, with 10bpc and an RGB output the TMDS
* character rate computation fails.
*/
static void drm_test_drm_hdmi_compute_mode_clock_rgb_10bpc_vic_1(struct kunit *test)
{
struct drm_connector_init_priv *priv = test->priv;
const struct drm_display_mode *mode;
unsigned long long rate;
struct drm_device *drm = &priv->drm;

mode = drm_display_mode_from_cea_vic(drm, 1);
KUNIT_ASSERT_NOT_NULL(test, mode);

rate = drm_hdmi_compute_mode_clock(mode, 10, HDMI_COLORSPACE_RGB);
KUNIT_EXPECT_EQ(test, rate, 0);
}

/*
* Test that for a given mode, with 12bpc and an RGB output the TMDS
* character rate is equal to 1.5 times the mode pixel clock.
*/
static void drm_test_drm_hdmi_compute_mode_clock_rgb_12bpc(struct kunit *test)
{
struct drm_connector_init_priv *priv = test->priv;
const struct drm_display_mode *mode;
unsigned long long rate;
struct drm_device *drm = &priv->drm;

mode = drm_display_mode_from_cea_vic(drm, 16);
KUNIT_ASSERT_NOT_NULL(test, mode);

KUNIT_ASSERT_FALSE(test, mode->flags & DRM_MODE_FLAG_DBLCLK);

rate = drm_hdmi_compute_mode_clock(mode, 12, HDMI_COLORSPACE_RGB);
KUNIT_ASSERT_GT(test, rate, 0);
KUNIT_EXPECT_EQ(test, mode->clock * 1500, rate);
}

/*
* Test that for the VIC-1 mode, with 12bpc and an RGB output the TMDS
* character rate computation fails.
*/
static void drm_test_drm_hdmi_compute_mode_clock_rgb_12bpc_vic_1(struct kunit *test)
{
struct drm_connector_init_priv *priv = test->priv;
const struct drm_display_mode *mode;
unsigned long long rate;
struct drm_device *drm = &priv->drm;

mode = drm_display_mode_from_cea_vic(drm, 1);
KUNIT_ASSERT_NOT_NULL(test, mode);

rate = drm_hdmi_compute_mode_clock(mode, 12, HDMI_COLORSPACE_RGB);
KUNIT_EXPECT_EQ(test, rate, 0);
}

/*
* Test that for a mode with the pixel repetition flag, the TMDS
* character rate is indeed double the mode pixel clock.
*/
static void drm_test_drm_hdmi_compute_mode_clock_rgb_double(struct kunit *test)
{
struct drm_connector_init_priv *priv = test->priv;
const struct drm_display_mode *mode;
unsigned long long rate;
struct drm_device *drm = &priv->drm;

mode = drm_display_mode_from_cea_vic(drm, 6);
KUNIT_ASSERT_NOT_NULL(test, mode);

KUNIT_ASSERT_TRUE(test, mode->flags & DRM_MODE_FLAG_DBLCLK);

rate = drm_hdmi_compute_mode_clock(mode, 8, HDMI_COLORSPACE_RGB);
KUNIT_ASSERT_GT(test, rate, 0);
KUNIT_EXPECT_EQ(test, (mode->clock * 1000ULL) * 2, rate);
}

/*
* Test that the TMDS character rate computation for the VIC modes
* explicitly listed in the spec as supporting YUV420 succeed and return
* half the mode pixel clock.
*/
static void drm_test_connector_hdmi_compute_mode_clock_yuv420_valid(struct kunit *test)
{
struct drm_connector_init_priv *priv = test->priv;
const struct drm_display_mode *mode;
struct drm_device *drm = &priv->drm;
unsigned long long rate;
unsigned int vic = *(unsigned int *)test->param_value;

mode = drm_display_mode_from_cea_vic(drm, vic);
KUNIT_ASSERT_NOT_NULL(test, mode);

KUNIT_ASSERT_FALSE(test, mode->flags & DRM_MODE_FLAG_DBLCLK);

rate = drm_hdmi_compute_mode_clock(mode, 8, HDMI_COLORSPACE_YUV420);
KUNIT_ASSERT_GT(test, rate, 0);
KUNIT_EXPECT_EQ(test, (mode->clock * 1000ULL) / 2, rate);
}

static const unsigned int drm_hdmi_compute_mode_clock_yuv420_vic_valid_tests[] = {
96, 97, 101, 102, 106, 107,
};

static void drm_hdmi_compute_mode_clock_yuv420_vic_desc(const unsigned int *vic, char *desc)
{
sprintf(desc, "VIC %u", *vic);
}

KUNIT_ARRAY_PARAM(drm_hdmi_compute_mode_clock_yuv420_valid,
drm_hdmi_compute_mode_clock_yuv420_vic_valid_tests,
drm_hdmi_compute_mode_clock_yuv420_vic_desc);

/*
* Test that for a given mode listed supporting it and an YUV420 output
* with 10bpc, the TMDS character rate is equal to 0.625 times the mode
* pixel clock.
*/
static void drm_test_connector_hdmi_compute_mode_clock_yuv420_10_bpc(struct kunit *test)
{
struct drm_connector_init_priv *priv = test->priv;
const struct drm_display_mode *mode;
struct drm_device *drm = &priv->drm;
unsigned int vic =
drm_hdmi_compute_mode_clock_yuv420_vic_valid_tests[0];
unsigned long long rate;

mode = drm_display_mode_from_cea_vic(drm, vic);
KUNIT_ASSERT_NOT_NULL(test, mode);

KUNIT_ASSERT_FALSE(test, mode->flags & DRM_MODE_FLAG_DBLCLK);

rate = drm_hdmi_compute_mode_clock(mode, 10, HDMI_COLORSPACE_YUV420);
KUNIT_ASSERT_GT(test, rate, 0);

KUNIT_EXPECT_EQ(test, mode->clock * 625, rate);
}

/*
* Test that for a given mode listed supporting it and an YUV420 output
* with 12bpc, the TMDS character rate is equal to 0.75 times the mode
* pixel clock.
*/
static void drm_test_connector_hdmi_compute_mode_clock_yuv420_12_bpc(struct kunit *test)
{
struct drm_connector_init_priv *priv = test->priv;
const struct drm_display_mode *mode;
struct drm_device *drm = &priv->drm;
unsigned int vic =
drm_hdmi_compute_mode_clock_yuv420_vic_valid_tests[0];
unsigned long long rate;

mode = drm_display_mode_from_cea_vic(drm, vic);
KUNIT_ASSERT_NOT_NULL(test, mode);

KUNIT_ASSERT_FALSE(test, mode->flags & DRM_MODE_FLAG_DBLCLK);

rate = drm_hdmi_compute_mode_clock(mode, 12, HDMI_COLORSPACE_YUV420);
KUNIT_ASSERT_GT(test, rate, 0);

KUNIT_EXPECT_EQ(test, mode->clock * 750, rate);
}

/*
* Test that for a given mode, the computation of the TMDS character
* rate with 8bpc and a YUV422 output succeeds and returns a rate equal
* to the mode pixel clock.
*/
static void drm_test_connector_hdmi_compute_mode_clock_yuv422_8_bpc(struct kunit *test)
{
struct drm_connector_init_priv *priv = test->priv;
const struct drm_display_mode *mode;
struct drm_device *drm = &priv->drm;
unsigned long long rate;

mode = drm_display_mode_from_cea_vic(drm, 16);
KUNIT_ASSERT_NOT_NULL(test, mode);

KUNIT_ASSERT_FALSE(test, mode->flags & DRM_MODE_FLAG_DBLCLK);

rate = drm_hdmi_compute_mode_clock(mode, 8, HDMI_COLORSPACE_YUV422);
KUNIT_ASSERT_GT(test, rate, 0);
KUNIT_EXPECT_EQ(test, mode->clock * 1000, rate);
}

/*
* Test that for a given mode, the computation of the TMDS character
* rate with 10bpc and a YUV422 output succeeds and returns a rate equal
* to the mode pixel clock.
*/
static void drm_test_connector_hdmi_compute_mode_clock_yuv422_10_bpc(struct kunit *test)
{
struct drm_connector_init_priv *priv = test->priv;
const struct drm_display_mode *mode;
struct drm_device *drm = &priv->drm;
unsigned long long rate;

mode = drm_display_mode_from_cea_vic(drm, 16);
KUNIT_ASSERT_NOT_NULL(test, mode);

KUNIT_ASSERT_FALSE(test, mode->flags & DRM_MODE_FLAG_DBLCLK);

rate = drm_hdmi_compute_mode_clock(mode, 10, HDMI_COLORSPACE_YUV422);
KUNIT_ASSERT_GT(test, rate, 0);
KUNIT_EXPECT_EQ(test, mode->clock * 1000, rate);
}

/*
* Test that for a given mode, the computation of the TMDS character
* rate with 12bpc and a YUV422 output succeeds and returns a rate equal
* to the mode pixel clock.
*/
static void drm_test_connector_hdmi_compute_mode_clock_yuv422_12_bpc(struct kunit *test)
{
struct drm_connector_init_priv *priv = test->priv;
const struct drm_display_mode *mode;
struct drm_device *drm = &priv->drm;
unsigned long long rate;

mode = drm_display_mode_from_cea_vic(drm, 16);
KUNIT_ASSERT_NOT_NULL(test, mode);

KUNIT_ASSERT_FALSE(test, mode->flags & DRM_MODE_FLAG_DBLCLK);

rate = drm_hdmi_compute_mode_clock(mode, 12, HDMI_COLORSPACE_YUV422);
KUNIT_ASSERT_GT(test, rate, 0);
KUNIT_EXPECT_EQ(test, mode->clock * 1000, rate);
}

static struct kunit_case drm_hdmi_compute_mode_clock_tests[] = {
KUNIT_CASE(drm_test_drm_hdmi_compute_mode_clock_rgb),
KUNIT_CASE(drm_test_drm_hdmi_compute_mode_clock_rgb_10bpc),
KUNIT_CASE(drm_test_drm_hdmi_compute_mode_clock_rgb_10bpc_vic_1),
KUNIT_CASE(drm_test_drm_hdmi_compute_mode_clock_rgb_12bpc),
KUNIT_CASE(drm_test_drm_hdmi_compute_mode_clock_rgb_12bpc_vic_1),
KUNIT_CASE(drm_test_drm_hdmi_compute_mode_clock_rgb_double),
KUNIT_CASE_PARAM(drm_test_connector_hdmi_compute_mode_clock_yuv420_valid,
drm_hdmi_compute_mode_clock_yuv420_valid_gen_params),
KUNIT_CASE(drm_test_connector_hdmi_compute_mode_clock_yuv420_10_bpc),
KUNIT_CASE(drm_test_connector_hdmi_compute_mode_clock_yuv420_12_bpc),
KUNIT_CASE(drm_test_connector_hdmi_compute_mode_clock_yuv422_8_bpc),
KUNIT_CASE(drm_test_connector_hdmi_compute_mode_clock_yuv422_10_bpc),
KUNIT_CASE(drm_test_connector_hdmi_compute_mode_clock_yuv422_12_bpc),
{ }
};

static struct kunit_suite drm_hdmi_compute_mode_clock_test_suite = {
.name = "drm_test_connector_hdmi_compute_mode_clock",
.init = drm_test_connector_init,
.test_cases = drm_hdmi_compute_mode_clock_tests,
};

kunit_test_suites(
&drmm_connector_hdmi_init_test_suite,
&drmm_connector_init_test_suite,
&drm_get_tv_mode_from_name_test_suite,
&drm_hdmi_compute_mode_clock_test_suite,
&drm_hdmi_connector_get_output_format_name_test_suite
);

Expand Down

0 comments on commit abb6f74

Please sign in to comment.