The tests all deviate slightly in how they assign their local pointers to DRM entities. This makes refactoring pretty difficult, so let's just move the assignment as soon as the entities are allocated. Reviewed-by: Simona Vetter <simona.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/20250129-test-kunit-v2-3-fe59c43805d5@kernel.org Signed-off-by: Maxime Ripard <mripard@kernel.org>
1971 lines
60 KiB
C
1971 lines
60 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
/*
|
|
* Kunit test for drm_hdmi_state_helper functions
|
|
*/
|
|
|
|
#include <drm/drm_atomic.h>
|
|
#include <drm/drm_atomic_state_helper.h>
|
|
#include <drm/drm_atomic_uapi.h>
|
|
#include <drm/drm_drv.h>
|
|
#include <drm/drm_edid.h>
|
|
#include <drm/drm_connector.h>
|
|
#include <drm/drm_fourcc.h>
|
|
#include <drm/drm_kunit_helpers.h>
|
|
#include <drm/drm_managed.h>
|
|
#include <drm/drm_modeset_helper_vtables.h>
|
|
#include <drm/drm_print.h>
|
|
#include <drm/drm_probe_helper.h>
|
|
|
|
#include <drm/display/drm_hdmi_helper.h>
|
|
#include <drm/display/drm_hdmi_state_helper.h>
|
|
|
|
#include "../drm_crtc_internal.h"
|
|
|
|
#include <kunit/test.h>
|
|
|
|
#include "drm_kunit_edid.h"
|
|
|
|
struct drm_atomic_helper_connector_hdmi_priv {
|
|
struct drm_device drm;
|
|
struct drm_plane *plane;
|
|
struct drm_crtc *crtc;
|
|
struct drm_encoder encoder;
|
|
struct drm_connector connector;
|
|
|
|
const char *current_edid;
|
|
size_t current_edid_len;
|
|
};
|
|
|
|
#define connector_to_priv(c) \
|
|
container_of_const(c, struct drm_atomic_helper_connector_hdmi_priv, connector)
|
|
|
|
static struct drm_display_mode *find_preferred_mode(struct drm_connector *connector)
|
|
{
|
|
struct drm_device *drm = connector->dev;
|
|
struct drm_display_mode *mode, *preferred;
|
|
|
|
mutex_lock(&drm->mode_config.mutex);
|
|
preferred = list_first_entry_or_null(&connector->modes, struct drm_display_mode, head);
|
|
list_for_each_entry(mode, &connector->modes, head)
|
|
if (mode->type & DRM_MODE_TYPE_PREFERRED)
|
|
preferred = mode;
|
|
mutex_unlock(&drm->mode_config.mutex);
|
|
|
|
return preferred;
|
|
}
|
|
|
|
static int light_up_connector(struct kunit *test,
|
|
struct drm_device *drm,
|
|
struct drm_crtc *crtc,
|
|
struct drm_connector *connector,
|
|
struct drm_display_mode *mode,
|
|
struct drm_modeset_acquire_ctx *ctx)
|
|
{
|
|
struct drm_atomic_state *state;
|
|
struct drm_connector_state *conn_state;
|
|
struct drm_crtc_state *crtc_state;
|
|
int ret;
|
|
|
|
state = drm_kunit_helper_atomic_state_alloc(test, drm, ctx);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
|
|
|
|
retry:
|
|
conn_state = drm_atomic_get_connector_state(state, connector);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
|
|
|
|
ret = drm_atomic_set_crtc_for_connector(conn_state, crtc);
|
|
if (ret == -EDEADLK) {
|
|
drm_atomic_state_clear(state);
|
|
ret = drm_modeset_backoff(ctx);
|
|
if (!ret)
|
|
goto retry;
|
|
}
|
|
KUNIT_EXPECT_EQ(test, ret, 0);
|
|
|
|
crtc_state = drm_atomic_get_crtc_state(state, crtc);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
|
|
|
|
ret = drm_atomic_set_mode_for_crtc(crtc_state, mode);
|
|
KUNIT_EXPECT_EQ(test, ret, 0);
|
|
|
|
crtc_state->enable = true;
|
|
crtc_state->active = true;
|
|
|
|
ret = drm_atomic_commit(state);
|
|
KUNIT_ASSERT_EQ(test, ret, 0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int set_connector_edid(struct kunit *test, struct drm_connector *connector,
|
|
const char *edid, size_t edid_len)
|
|
{
|
|
struct drm_atomic_helper_connector_hdmi_priv *priv =
|
|
connector_to_priv(connector);
|
|
struct drm_device *drm = connector->dev;
|
|
int ret;
|
|
|
|
priv->current_edid = edid;
|
|
priv->current_edid_len = edid_len;
|
|
|
|
mutex_lock(&drm->mode_config.mutex);
|
|
ret = connector->funcs->fill_modes(connector, 4096, 4096);
|
|
mutex_unlock(&drm->mode_config.mutex);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static const struct drm_connector_hdmi_funcs dummy_connector_hdmi_funcs = {
|
|
};
|
|
|
|
static enum drm_mode_status
|
|
reject_connector_tmds_char_rate_valid(const struct drm_connector *connector,
|
|
const struct drm_display_mode *mode,
|
|
unsigned long long tmds_rate)
|
|
{
|
|
return MODE_BAD;
|
|
}
|
|
|
|
static const struct drm_connector_hdmi_funcs reject_connector_hdmi_funcs = {
|
|
.tmds_char_rate_valid = reject_connector_tmds_char_rate_valid,
|
|
};
|
|
|
|
static enum drm_mode_status
|
|
reject_100MHz_connector_tmds_char_rate_valid(const struct drm_connector *connector,
|
|
const struct drm_display_mode *mode,
|
|
unsigned long long tmds_rate)
|
|
{
|
|
return (tmds_rate > 100ULL * 1000 * 1000) ? MODE_BAD : MODE_OK;
|
|
}
|
|
|
|
static const struct drm_connector_hdmi_funcs reject_100_MHz_connector_hdmi_funcs = {
|
|
.tmds_char_rate_valid = reject_100MHz_connector_tmds_char_rate_valid,
|
|
};
|
|
|
|
static int dummy_connector_get_modes(struct drm_connector *connector)
|
|
{
|
|
struct drm_atomic_helper_connector_hdmi_priv *priv =
|
|
connector_to_priv(connector);
|
|
const struct drm_edid *edid;
|
|
unsigned int num_modes;
|
|
|
|
edid = drm_edid_alloc(priv->current_edid, priv->current_edid_len);
|
|
if (!edid)
|
|
return -EINVAL;
|
|
|
|
drm_edid_connector_update(connector, edid);
|
|
num_modes = drm_edid_connector_add_modes(connector);
|
|
|
|
drm_edid_free(edid);
|
|
|
|
return num_modes;
|
|
}
|
|
|
|
static const struct drm_connector_helper_funcs dummy_connector_helper_funcs = {
|
|
.atomic_check = drm_atomic_helper_connector_hdmi_check,
|
|
.get_modes = dummy_connector_get_modes,
|
|
.mode_valid = drm_hdmi_connector_mode_valid,
|
|
};
|
|
|
|
static void dummy_hdmi_connector_reset(struct drm_connector *connector)
|
|
{
|
|
drm_atomic_helper_connector_reset(connector);
|
|
__drm_atomic_helper_connector_hdmi_reset(connector, connector->state);
|
|
}
|
|
|
|
static const struct drm_connector_funcs dummy_connector_funcs = {
|
|
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
|
|
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
|
|
.fill_modes = drm_helper_probe_single_connector_modes,
|
|
.reset = dummy_hdmi_connector_reset,
|
|
};
|
|
|
|
static
|
|
struct drm_atomic_helper_connector_hdmi_priv *
|
|
drm_kunit_helper_connector_hdmi_init_funcs(struct kunit *test,
|
|
unsigned int formats,
|
|
unsigned int max_bpc,
|
|
const struct drm_connector_hdmi_funcs *hdmi_funcs)
|
|
{
|
|
struct drm_atomic_helper_connector_hdmi_priv *priv;
|
|
struct drm_connector *conn;
|
|
struct drm_encoder *enc;
|
|
struct drm_device *drm;
|
|
struct device *dev;
|
|
int ret;
|
|
|
|
dev = drm_kunit_helper_alloc_device(test);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
|
|
|
|
priv = drm_kunit_helper_alloc_drm_device(test, dev,
|
|
struct drm_atomic_helper_connector_hdmi_priv, drm,
|
|
DRIVER_MODESET | DRIVER_ATOMIC);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
|
|
test->priv = priv;
|
|
|
|
drm = &priv->drm;
|
|
priv->plane = drm_kunit_helper_create_primary_plane(test, drm,
|
|
NULL,
|
|
NULL,
|
|
NULL, 0,
|
|
NULL);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->plane);
|
|
|
|
priv->crtc = drm_kunit_helper_create_crtc(test, drm,
|
|
priv->plane, NULL,
|
|
NULL,
|
|
NULL);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->crtc);
|
|
|
|
enc = &priv->encoder;
|
|
ret = drmm_encoder_init(drm, enc, NULL, DRM_MODE_ENCODER_TMDS, NULL);
|
|
KUNIT_ASSERT_EQ(test, ret, 0);
|
|
|
|
enc->possible_crtcs = drm_crtc_mask(priv->crtc);
|
|
|
|
conn = &priv->connector;
|
|
ret = drmm_connector_hdmi_init(drm, conn,
|
|
"Vendor", "Product",
|
|
&dummy_connector_funcs,
|
|
hdmi_funcs,
|
|
DRM_MODE_CONNECTOR_HDMIA,
|
|
NULL,
|
|
formats,
|
|
max_bpc);
|
|
KUNIT_ASSERT_EQ(test, ret, 0);
|
|
|
|
drm_connector_helper_add(conn, &dummy_connector_helper_funcs);
|
|
drm_connector_attach_encoder(conn, enc);
|
|
|
|
drm_mode_config_reset(drm);
|
|
|
|
return priv;
|
|
}
|
|
|
|
static
|
|
struct drm_atomic_helper_connector_hdmi_priv *
|
|
drm_kunit_helper_connector_hdmi_init(struct kunit *test,
|
|
unsigned int formats,
|
|
unsigned int max_bpc)
|
|
{
|
|
struct drm_atomic_helper_connector_hdmi_priv *priv;
|
|
int ret;
|
|
|
|
priv = drm_kunit_helper_connector_hdmi_init_funcs(test,
|
|
formats, max_bpc,
|
|
&dummy_connector_hdmi_funcs);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
|
|
|
|
ret = set_connector_edid(test, &priv->connector,
|
|
test_edid_hdmi_1080p_rgb_max_200mhz,
|
|
ARRAY_SIZE(test_edid_hdmi_1080p_rgb_max_200mhz));
|
|
KUNIT_ASSERT_GT(test, ret, 0);
|
|
|
|
return priv;
|
|
}
|
|
|
|
/*
|
|
* Test that if we change the RGB quantization property to a different
|
|
* value, we trigger a mode change on the connector's CRTC, which will
|
|
* in turn disable/enable the connector.
|
|
*/
|
|
static void drm_test_check_broadcast_rgb_crtc_mode_changed(struct kunit *test)
|
|
{
|
|
struct drm_atomic_helper_connector_hdmi_priv *priv;
|
|
struct drm_modeset_acquire_ctx *ctx;
|
|
struct drm_connector_state *old_conn_state;
|
|
struct drm_connector_state *new_conn_state;
|
|
struct drm_crtc_state *crtc_state;
|
|
struct drm_atomic_state *state;
|
|
struct drm_display_mode *preferred;
|
|
struct drm_connector *conn;
|
|
struct drm_device *drm;
|
|
struct drm_crtc *crtc;
|
|
int ret;
|
|
|
|
priv = drm_kunit_helper_connector_hdmi_init(test,
|
|
BIT(HDMI_COLORSPACE_RGB),
|
|
8);
|
|
KUNIT_ASSERT_NOT_NULL(test, priv);
|
|
|
|
drm = &priv->drm;
|
|
crtc = priv->crtc;
|
|
conn = &priv->connector;
|
|
|
|
ctx = drm_kunit_helper_acquire_ctx_alloc(test);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
|
|
|
|
preferred = find_preferred_mode(conn);
|
|
KUNIT_ASSERT_NOT_NULL(test, preferred);
|
|
|
|
ret = light_up_connector(test, drm, crtc, conn, preferred, ctx);
|
|
KUNIT_ASSERT_EQ(test, ret, 0);
|
|
|
|
state = drm_kunit_helper_atomic_state_alloc(test, drm, ctx);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
|
|
|
|
new_conn_state = drm_atomic_get_connector_state(state, conn);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_conn_state);
|
|
|
|
old_conn_state = drm_atomic_get_old_connector_state(state, conn);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, old_conn_state);
|
|
|
|
new_conn_state->hdmi.broadcast_rgb = DRM_HDMI_BROADCAST_RGB_FULL;
|
|
|
|
KUNIT_ASSERT_NE(test,
|
|
old_conn_state->hdmi.broadcast_rgb,
|
|
new_conn_state->hdmi.broadcast_rgb);
|
|
|
|
ret = drm_atomic_check_only(state);
|
|
KUNIT_ASSERT_EQ(test, ret, 0);
|
|
|
|
new_conn_state = drm_atomic_get_new_connector_state(state, conn);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_conn_state);
|
|
KUNIT_EXPECT_EQ(test, new_conn_state->hdmi.broadcast_rgb, DRM_HDMI_BROADCAST_RGB_FULL);
|
|
|
|
crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
|
|
KUNIT_EXPECT_TRUE(test, crtc_state->mode_changed);
|
|
}
|
|
|
|
/*
|
|
* Test that if we set the RGB quantization property to the same value,
|
|
* we don't trigger a mode change on the connector's CRTC and leave the
|
|
* connector unaffected.
|
|
*/
|
|
static void drm_test_check_broadcast_rgb_crtc_mode_not_changed(struct kunit *test)
|
|
{
|
|
struct drm_atomic_helper_connector_hdmi_priv *priv;
|
|
struct drm_modeset_acquire_ctx *ctx;
|
|
struct drm_connector_state *old_conn_state;
|
|
struct drm_connector_state *new_conn_state;
|
|
struct drm_crtc_state *crtc_state;
|
|
struct drm_atomic_state *state;
|
|
struct drm_display_mode *preferred;
|
|
struct drm_connector *conn;
|
|
struct drm_device *drm;
|
|
struct drm_crtc *crtc;
|
|
int ret;
|
|
|
|
priv = drm_kunit_helper_connector_hdmi_init(test,
|
|
BIT(HDMI_COLORSPACE_RGB),
|
|
8);
|
|
KUNIT_ASSERT_NOT_NULL(test, priv);
|
|
|
|
drm = &priv->drm;
|
|
crtc = priv->crtc;
|
|
conn = &priv->connector;
|
|
|
|
ctx = drm_kunit_helper_acquire_ctx_alloc(test);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
|
|
|
|
preferred = find_preferred_mode(conn);
|
|
KUNIT_ASSERT_NOT_NULL(test, preferred);
|
|
|
|
ret = light_up_connector(test, drm, crtc, conn, preferred, ctx);
|
|
KUNIT_ASSERT_EQ(test, ret, 0);
|
|
|
|
state = drm_kunit_helper_atomic_state_alloc(test, drm, ctx);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
|
|
|
|
new_conn_state = drm_atomic_get_connector_state(state, conn);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_conn_state);
|
|
|
|
old_conn_state = drm_atomic_get_old_connector_state(state, conn);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, old_conn_state);
|
|
|
|
new_conn_state->hdmi.broadcast_rgb = old_conn_state->hdmi.broadcast_rgb;
|
|
|
|
ret = drm_atomic_check_only(state);
|
|
KUNIT_ASSERT_EQ(test, ret, 0);
|
|
|
|
old_conn_state = drm_atomic_get_old_connector_state(state, conn);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, old_conn_state);
|
|
|
|
new_conn_state = drm_atomic_get_new_connector_state(state, conn);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_conn_state);
|
|
|
|
KUNIT_EXPECT_EQ(test,
|
|
old_conn_state->hdmi.broadcast_rgb,
|
|
new_conn_state->hdmi.broadcast_rgb);
|
|
|
|
crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
|
|
KUNIT_EXPECT_FALSE(test, crtc_state->mode_changed);
|
|
}
|
|
|
|
/*
|
|
* Test that for an HDMI connector, with an HDMI monitor, if the
|
|
* Broadcast RGB property is set to auto with a mode that isn't the
|
|
* VIC-1 mode, we will get a limited RGB Quantization Range.
|
|
*/
|
|
static void drm_test_check_broadcast_rgb_auto_cea_mode(struct kunit *test)
|
|
{
|
|
struct drm_atomic_helper_connector_hdmi_priv *priv;
|
|
struct drm_modeset_acquire_ctx *ctx;
|
|
struct drm_connector_state *conn_state;
|
|
struct drm_atomic_state *state;
|
|
struct drm_display_mode *preferred;
|
|
struct drm_connector *conn;
|
|
struct drm_device *drm;
|
|
struct drm_crtc *crtc;
|
|
int ret;
|
|
|
|
priv = drm_kunit_helper_connector_hdmi_init(test,
|
|
BIT(HDMI_COLORSPACE_RGB),
|
|
8);
|
|
KUNIT_ASSERT_NOT_NULL(test, priv);
|
|
|
|
drm = &priv->drm;
|
|
crtc = priv->crtc;
|
|
conn = &priv->connector;
|
|
KUNIT_ASSERT_TRUE(test, conn->display_info.is_hdmi);
|
|
|
|
ctx = drm_kunit_helper_acquire_ctx_alloc(test);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
|
|
|
|
preferred = find_preferred_mode(conn);
|
|
KUNIT_ASSERT_NOT_NULL(test, preferred);
|
|
KUNIT_ASSERT_NE(test, drm_match_cea_mode(preferred), 1);
|
|
|
|
ret = light_up_connector(test, drm, crtc, conn, preferred, ctx);
|
|
KUNIT_ASSERT_EQ(test, ret, 0);
|
|
|
|
state = drm_kunit_helper_atomic_state_alloc(test, drm, ctx);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
|
|
|
|
conn_state = drm_atomic_get_connector_state(state, conn);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
|
|
|
|
KUNIT_ASSERT_EQ(test,
|
|
conn_state->hdmi.broadcast_rgb,
|
|
DRM_HDMI_BROADCAST_RGB_AUTO);
|
|
|
|
ret = drm_atomic_check_only(state);
|
|
KUNIT_ASSERT_EQ(test, ret, 0);
|
|
|
|
conn_state = drm_atomic_get_connector_state(state, conn);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
|
|
|
|
KUNIT_EXPECT_TRUE(test, conn_state->hdmi.is_limited_range);
|
|
}
|
|
|
|
/*
|
|
* Test that for an HDMI connector, with an HDMI monitor, if the
|
|
* Broadcast RGB property is set to auto with a VIC-1 mode, we will get
|
|
* a full RGB Quantization Range.
|
|
*/
|
|
static void drm_test_check_broadcast_rgb_auto_cea_mode_vic_1(struct kunit *test)
|
|
{
|
|
struct drm_atomic_helper_connector_hdmi_priv *priv;
|
|
struct drm_modeset_acquire_ctx *ctx;
|
|
struct drm_connector_state *conn_state;
|
|
struct drm_atomic_state *state;
|
|
struct drm_display_mode *mode;
|
|
struct drm_connector *conn;
|
|
struct drm_device *drm;
|
|
struct drm_crtc *crtc;
|
|
int ret;
|
|
|
|
priv = drm_kunit_helper_connector_hdmi_init(test,
|
|
BIT(HDMI_COLORSPACE_RGB),
|
|
8);
|
|
KUNIT_ASSERT_NOT_NULL(test, priv);
|
|
|
|
drm = &priv->drm;
|
|
conn = &priv->connector;
|
|
KUNIT_ASSERT_TRUE(test, conn->display_info.is_hdmi);
|
|
|
|
ctx = drm_kunit_helper_acquire_ctx_alloc(test);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
|
|
|
|
mode = drm_kunit_display_mode_from_cea_vic(test, drm, 1);
|
|
KUNIT_ASSERT_NOT_NULL(test, mode);
|
|
|
|
crtc = priv->crtc;
|
|
ret = light_up_connector(test, drm, crtc, conn, mode, ctx);
|
|
KUNIT_ASSERT_EQ(test, ret, 0);
|
|
|
|
state = drm_kunit_helper_atomic_state_alloc(test, drm, ctx);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
|
|
|
|
conn_state = drm_atomic_get_connector_state(state, conn);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
|
|
|
|
KUNIT_ASSERT_EQ(test,
|
|
conn_state->hdmi.broadcast_rgb,
|
|
DRM_HDMI_BROADCAST_RGB_AUTO);
|
|
|
|
ret = drm_atomic_check_only(state);
|
|
KUNIT_ASSERT_EQ(test, ret, 0);
|
|
|
|
conn_state = drm_atomic_get_connector_state(state, conn);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
|
|
|
|
KUNIT_EXPECT_FALSE(test, conn_state->hdmi.is_limited_range);
|
|
}
|
|
|
|
/*
|
|
* Test that for an HDMI connector, with an HDMI monitor, if the
|
|
* Broadcast RGB property is set to full with a mode that isn't the
|
|
* VIC-1 mode, we will get a full RGB Quantization Range.
|
|
*/
|
|
static void drm_test_check_broadcast_rgb_full_cea_mode(struct kunit *test)
|
|
{
|
|
struct drm_atomic_helper_connector_hdmi_priv *priv;
|
|
struct drm_modeset_acquire_ctx *ctx;
|
|
struct drm_connector_state *conn_state;
|
|
struct drm_atomic_state *state;
|
|
struct drm_display_mode *preferred;
|
|
struct drm_connector *conn;
|
|
struct drm_device *drm;
|
|
struct drm_crtc *crtc;
|
|
int ret;
|
|
|
|
priv = drm_kunit_helper_connector_hdmi_init(test,
|
|
BIT(HDMI_COLORSPACE_RGB),
|
|
8);
|
|
KUNIT_ASSERT_NOT_NULL(test, priv);
|
|
|
|
drm = &priv->drm;
|
|
crtc = priv->crtc;
|
|
conn = &priv->connector;
|
|
KUNIT_ASSERT_TRUE(test, conn->display_info.is_hdmi);
|
|
|
|
ctx = drm_kunit_helper_acquire_ctx_alloc(test);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
|
|
|
|
preferred = find_preferred_mode(conn);
|
|
KUNIT_ASSERT_NOT_NULL(test, preferred);
|
|
KUNIT_ASSERT_NE(test, drm_match_cea_mode(preferred), 1);
|
|
|
|
ret = light_up_connector(test, drm, crtc, conn, preferred, ctx);
|
|
KUNIT_ASSERT_EQ(test, ret, 0);
|
|
|
|
state = drm_kunit_helper_atomic_state_alloc(test, drm, ctx);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
|
|
|
|
conn_state = drm_atomic_get_connector_state(state, conn);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
|
|
|
|
conn_state->hdmi.broadcast_rgb = DRM_HDMI_BROADCAST_RGB_FULL;
|
|
|
|
ret = drm_atomic_check_only(state);
|
|
KUNIT_ASSERT_EQ(test, ret, 0);
|
|
|
|
conn_state = drm_atomic_get_connector_state(state, conn);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
|
|
|
|
KUNIT_ASSERT_EQ(test,
|
|
conn_state->hdmi.broadcast_rgb,
|
|
DRM_HDMI_BROADCAST_RGB_FULL);
|
|
|
|
KUNIT_EXPECT_FALSE(test, conn_state->hdmi.is_limited_range);
|
|
}
|
|
|
|
/*
|
|
* Test that for an HDMI connector, with an HDMI monitor, if the
|
|
* Broadcast RGB property is set to full with a VIC-1 mode, we will get
|
|
* a full RGB Quantization Range.
|
|
*/
|
|
static void drm_test_check_broadcast_rgb_full_cea_mode_vic_1(struct kunit *test)
|
|
{
|
|
struct drm_atomic_helper_connector_hdmi_priv *priv;
|
|
struct drm_modeset_acquire_ctx *ctx;
|
|
struct drm_connector_state *conn_state;
|
|
struct drm_atomic_state *state;
|
|
struct drm_display_mode *mode;
|
|
struct drm_connector *conn;
|
|
struct drm_device *drm;
|
|
struct drm_crtc *crtc;
|
|
int ret;
|
|
|
|
priv = drm_kunit_helper_connector_hdmi_init(test,
|
|
BIT(HDMI_COLORSPACE_RGB),
|
|
8);
|
|
KUNIT_ASSERT_NOT_NULL(test, priv);
|
|
|
|
drm = &priv->drm;
|
|
conn = &priv->connector;
|
|
KUNIT_ASSERT_TRUE(test, conn->display_info.is_hdmi);
|
|
|
|
ctx = drm_kunit_helper_acquire_ctx_alloc(test);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
|
|
|
|
mode = drm_kunit_display_mode_from_cea_vic(test, drm, 1);
|
|
KUNIT_ASSERT_NOT_NULL(test, mode);
|
|
|
|
crtc = priv->crtc;
|
|
ret = light_up_connector(test, drm, crtc, conn, mode, ctx);
|
|
KUNIT_ASSERT_EQ(test, ret, 0);
|
|
|
|
state = drm_kunit_helper_atomic_state_alloc(test, drm, ctx);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
|
|
|
|
conn_state = drm_atomic_get_connector_state(state, conn);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
|
|
|
|
conn_state->hdmi.broadcast_rgb = DRM_HDMI_BROADCAST_RGB_FULL;
|
|
|
|
ret = drm_atomic_check_only(state);
|
|
KUNIT_ASSERT_EQ(test, ret, 0);
|
|
|
|
conn_state = drm_atomic_get_connector_state(state, conn);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
|
|
|
|
KUNIT_ASSERT_EQ(test,
|
|
conn_state->hdmi.broadcast_rgb,
|
|
DRM_HDMI_BROADCAST_RGB_FULL);
|
|
|
|
KUNIT_EXPECT_FALSE(test, conn_state->hdmi.is_limited_range);
|
|
}
|
|
|
|
/*
|
|
* Test that for an HDMI connector, with an HDMI monitor, if the
|
|
* Broadcast RGB property is set to limited with a mode that isn't the
|
|
* VIC-1 mode, we will get a limited RGB Quantization Range.
|
|
*/
|
|
static void drm_test_check_broadcast_rgb_limited_cea_mode(struct kunit *test)
|
|
{
|
|
struct drm_atomic_helper_connector_hdmi_priv *priv;
|
|
struct drm_modeset_acquire_ctx *ctx;
|
|
struct drm_connector_state *conn_state;
|
|
struct drm_atomic_state *state;
|
|
struct drm_display_mode *preferred;
|
|
struct drm_connector *conn;
|
|
struct drm_device *drm;
|
|
struct drm_crtc *crtc;
|
|
int ret;
|
|
|
|
priv = drm_kunit_helper_connector_hdmi_init(test,
|
|
BIT(HDMI_COLORSPACE_RGB),
|
|
8);
|
|
KUNIT_ASSERT_NOT_NULL(test, priv);
|
|
|
|
drm = &priv->drm;
|
|
crtc = priv->crtc;
|
|
conn = &priv->connector;
|
|
KUNIT_ASSERT_TRUE(test, conn->display_info.is_hdmi);
|
|
|
|
ctx = drm_kunit_helper_acquire_ctx_alloc(test);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
|
|
|
|
preferred = find_preferred_mode(conn);
|
|
KUNIT_ASSERT_NOT_NULL(test, preferred);
|
|
KUNIT_ASSERT_NE(test, drm_match_cea_mode(preferred), 1);
|
|
|
|
ret = light_up_connector(test, drm, crtc, conn, preferred, ctx);
|
|
KUNIT_ASSERT_EQ(test, ret, 0);
|
|
|
|
state = drm_kunit_helper_atomic_state_alloc(test, drm, ctx);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
|
|
|
|
conn_state = drm_atomic_get_connector_state(state, conn);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
|
|
|
|
conn_state->hdmi.broadcast_rgb = DRM_HDMI_BROADCAST_RGB_LIMITED;
|
|
|
|
ret = drm_atomic_check_only(state);
|
|
KUNIT_ASSERT_EQ(test, ret, 0);
|
|
|
|
conn_state = drm_atomic_get_connector_state(state, conn);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
|
|
|
|
KUNIT_ASSERT_EQ(test,
|
|
conn_state->hdmi.broadcast_rgb,
|
|
DRM_HDMI_BROADCAST_RGB_LIMITED);
|
|
|
|
KUNIT_EXPECT_TRUE(test, conn_state->hdmi.is_limited_range);
|
|
}
|
|
|
|
/*
|
|
* Test that for an HDMI connector, with an HDMI monitor, if the
|
|
* Broadcast RGB property is set to limited with a VIC-1 mode, we will
|
|
* get a limited RGB Quantization Range.
|
|
*/
|
|
static void drm_test_check_broadcast_rgb_limited_cea_mode_vic_1(struct kunit *test)
|
|
{
|
|
struct drm_atomic_helper_connector_hdmi_priv *priv;
|
|
struct drm_modeset_acquire_ctx *ctx;
|
|
struct drm_connector_state *conn_state;
|
|
struct drm_atomic_state *state;
|
|
struct drm_display_mode *mode;
|
|
struct drm_connector *conn;
|
|
struct drm_device *drm;
|
|
struct drm_crtc *crtc;
|
|
int ret;
|
|
|
|
priv = drm_kunit_helper_connector_hdmi_init(test,
|
|
BIT(HDMI_COLORSPACE_RGB),
|
|
8);
|
|
KUNIT_ASSERT_NOT_NULL(test, priv);
|
|
|
|
drm = &priv->drm;
|
|
conn = &priv->connector;
|
|
KUNIT_ASSERT_TRUE(test, conn->display_info.is_hdmi);
|
|
|
|
ctx = drm_kunit_helper_acquire_ctx_alloc(test);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
|
|
|
|
mode = drm_kunit_display_mode_from_cea_vic(test, drm, 1);
|
|
KUNIT_ASSERT_NOT_NULL(test, mode);
|
|
|
|
crtc = priv->crtc;
|
|
ret = light_up_connector(test, drm, crtc, conn, mode, ctx);
|
|
KUNIT_ASSERT_EQ(test, ret, 0);
|
|
|
|
state = drm_kunit_helper_atomic_state_alloc(test, drm, ctx);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
|
|
|
|
conn_state = drm_atomic_get_connector_state(state, conn);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
|
|
|
|
conn_state->hdmi.broadcast_rgb = DRM_HDMI_BROADCAST_RGB_LIMITED;
|
|
|
|
ret = drm_atomic_check_only(state);
|
|
KUNIT_ASSERT_EQ(test, ret, 0);
|
|
|
|
conn_state = drm_atomic_get_connector_state(state, conn);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
|
|
|
|
KUNIT_ASSERT_EQ(test,
|
|
conn_state->hdmi.broadcast_rgb,
|
|
DRM_HDMI_BROADCAST_RGB_LIMITED);
|
|
|
|
KUNIT_EXPECT_TRUE(test, conn_state->hdmi.is_limited_range);
|
|
}
|
|
|
|
/*
|
|
* Test that if we change the maximum bpc property to a different value,
|
|
* we trigger a mode change on the connector's CRTC, which will in turn
|
|
* disable/enable the connector.
|
|
*/
|
|
static void drm_test_check_output_bpc_crtc_mode_changed(struct kunit *test)
|
|
{
|
|
struct drm_atomic_helper_connector_hdmi_priv *priv;
|
|
struct drm_modeset_acquire_ctx *ctx;
|
|
struct drm_connector_state *old_conn_state;
|
|
struct drm_connector_state *new_conn_state;
|
|
struct drm_crtc_state *crtc_state;
|
|
struct drm_atomic_state *state;
|
|
struct drm_display_mode *preferred;
|
|
struct drm_connector *conn;
|
|
struct drm_device *drm;
|
|
struct drm_crtc *crtc;
|
|
int ret;
|
|
|
|
priv = drm_kunit_helper_connector_hdmi_init(test,
|
|
BIT(HDMI_COLORSPACE_RGB),
|
|
10);
|
|
KUNIT_ASSERT_NOT_NULL(test, priv);
|
|
|
|
drm = &priv->drm;
|
|
crtc = priv->crtc;
|
|
conn = &priv->connector;
|
|
ret = set_connector_edid(test, conn,
|
|
test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz,
|
|
ARRAY_SIZE(test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz));
|
|
KUNIT_ASSERT_GT(test, ret, 0);
|
|
|
|
ctx = drm_kunit_helper_acquire_ctx_alloc(test);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
|
|
|
|
preferred = find_preferred_mode(conn);
|
|
KUNIT_ASSERT_NOT_NULL(test, preferred);
|
|
|
|
ret = light_up_connector(test, drm, crtc, conn, preferred, ctx);
|
|
KUNIT_ASSERT_EQ(test, ret, 0);
|
|
|
|
state = drm_kunit_helper_atomic_state_alloc(test, drm, ctx);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
|
|
|
|
new_conn_state = drm_atomic_get_connector_state(state, conn);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_conn_state);
|
|
|
|
old_conn_state = drm_atomic_get_old_connector_state(state, conn);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, old_conn_state);
|
|
|
|
new_conn_state->max_requested_bpc = 8;
|
|
|
|
KUNIT_ASSERT_NE(test,
|
|
old_conn_state->max_requested_bpc,
|
|
new_conn_state->max_requested_bpc);
|
|
|
|
ret = drm_atomic_check_only(state);
|
|
KUNIT_ASSERT_EQ(test, ret, 0);
|
|
|
|
old_conn_state = drm_atomic_get_old_connector_state(state, conn);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, old_conn_state);
|
|
|
|
new_conn_state = drm_atomic_get_new_connector_state(state, conn);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_conn_state);
|
|
|
|
KUNIT_ASSERT_NE(test,
|
|
old_conn_state->hdmi.output_bpc,
|
|
new_conn_state->hdmi.output_bpc);
|
|
|
|
crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
|
|
KUNIT_EXPECT_TRUE(test, crtc_state->mode_changed);
|
|
}
|
|
|
|
/*
|
|
* Test that if we set the output bpc property to the same value, we
|
|
* don't trigger a mode change on the connector's CRTC and leave the
|
|
* connector unaffected.
|
|
*/
|
|
static void drm_test_check_output_bpc_crtc_mode_not_changed(struct kunit *test)
|
|
{
|
|
struct drm_atomic_helper_connector_hdmi_priv *priv;
|
|
struct drm_modeset_acquire_ctx *ctx;
|
|
struct drm_connector_state *old_conn_state;
|
|
struct drm_connector_state *new_conn_state;
|
|
struct drm_crtc_state *crtc_state;
|
|
struct drm_atomic_state *state;
|
|
struct drm_display_mode *preferred;
|
|
struct drm_connector *conn;
|
|
struct drm_device *drm;
|
|
struct drm_crtc *crtc;
|
|
int ret;
|
|
|
|
priv = drm_kunit_helper_connector_hdmi_init(test,
|
|
BIT(HDMI_COLORSPACE_RGB),
|
|
10);
|
|
KUNIT_ASSERT_NOT_NULL(test, priv);
|
|
|
|
drm = &priv->drm;
|
|
crtc = priv->crtc;
|
|
conn = &priv->connector;
|
|
ret = set_connector_edid(test, conn,
|
|
test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz,
|
|
ARRAY_SIZE(test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz));
|
|
KUNIT_ASSERT_GT(test, ret, 0);
|
|
|
|
ctx = drm_kunit_helper_acquire_ctx_alloc(test);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
|
|
|
|
preferred = find_preferred_mode(conn);
|
|
KUNIT_ASSERT_NOT_NULL(test, preferred);
|
|
|
|
ret = light_up_connector(test, drm, crtc, conn, preferred, ctx);
|
|
KUNIT_ASSERT_EQ(test, ret, 0);
|
|
|
|
state = drm_kunit_helper_atomic_state_alloc(test, drm, ctx);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
|
|
|
|
new_conn_state = drm_atomic_get_connector_state(state, conn);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_conn_state);
|
|
|
|
old_conn_state = drm_atomic_get_old_connector_state(state, conn);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, old_conn_state);
|
|
|
|
KUNIT_ASSERT_EQ(test,
|
|
new_conn_state->hdmi.output_bpc,
|
|
old_conn_state->hdmi.output_bpc);
|
|
|
|
ret = drm_atomic_check_only(state);
|
|
KUNIT_ASSERT_EQ(test, ret, 0);
|
|
|
|
old_conn_state = drm_atomic_get_old_connector_state(state, conn);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, old_conn_state);
|
|
|
|
new_conn_state = drm_atomic_get_new_connector_state(state, conn);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_conn_state);
|
|
|
|
KUNIT_EXPECT_EQ(test,
|
|
old_conn_state->hdmi.output_bpc,
|
|
new_conn_state->hdmi.output_bpc);
|
|
|
|
crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
|
|
KUNIT_EXPECT_FALSE(test, crtc_state->mode_changed);
|
|
}
|
|
|
|
/*
|
|
* Test that if we have an HDMI connector but a !HDMI display, we always
|
|
* output RGB with 8 bpc.
|
|
*/
|
|
static void drm_test_check_output_bpc_dvi(struct kunit *test)
|
|
{
|
|
struct drm_atomic_helper_connector_hdmi_priv *priv;
|
|
struct drm_modeset_acquire_ctx *ctx;
|
|
struct drm_connector_state *conn_state;
|
|
struct drm_display_info *info;
|
|
struct drm_display_mode *preferred;
|
|
struct drm_connector *conn;
|
|
struct drm_device *drm;
|
|
struct drm_crtc *crtc;
|
|
int ret;
|
|
|
|
priv = drm_kunit_helper_connector_hdmi_init(test,
|
|
BIT(HDMI_COLORSPACE_RGB) |
|
|
BIT(HDMI_COLORSPACE_YUV422) |
|
|
BIT(HDMI_COLORSPACE_YUV444),
|
|
12);
|
|
KUNIT_ASSERT_NOT_NULL(test, priv);
|
|
|
|
drm = &priv->drm;
|
|
crtc = priv->crtc;
|
|
conn = &priv->connector;
|
|
ret = set_connector_edid(test, conn,
|
|
test_edid_dvi_1080p,
|
|
ARRAY_SIZE(test_edid_dvi_1080p));
|
|
KUNIT_ASSERT_GT(test, ret, 0);
|
|
|
|
info = &conn->display_info;
|
|
KUNIT_ASSERT_FALSE(test, info->is_hdmi);
|
|
|
|
ctx = drm_kunit_helper_acquire_ctx_alloc(test);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
|
|
|
|
preferred = find_preferred_mode(conn);
|
|
KUNIT_ASSERT_NOT_NULL(test, preferred);
|
|
|
|
ret = light_up_connector(test, drm, crtc, conn, preferred, ctx);
|
|
KUNIT_ASSERT_EQ(test, ret, 0);
|
|
|
|
conn_state = conn->state;
|
|
KUNIT_ASSERT_NOT_NULL(test, conn_state);
|
|
|
|
KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 8);
|
|
KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB);
|
|
}
|
|
|
|
/*
|
|
* Test that when doing a commit which would use RGB 8bpc, the TMDS
|
|
* clock rate stored in the connector state is equal to the mode clock
|
|
*/
|
|
static void drm_test_check_tmds_char_rate_rgb_8bpc(struct kunit *test)
|
|
{
|
|
struct drm_atomic_helper_connector_hdmi_priv *priv;
|
|
struct drm_modeset_acquire_ctx *ctx;
|
|
struct drm_connector_state *conn_state;
|
|
struct drm_display_mode *preferred;
|
|
struct drm_connector *conn;
|
|
struct drm_device *drm;
|
|
struct drm_crtc *crtc;
|
|
int ret;
|
|
|
|
priv = drm_kunit_helper_connector_hdmi_init(test,
|
|
BIT(HDMI_COLORSPACE_RGB),
|
|
8);
|
|
KUNIT_ASSERT_NOT_NULL(test, priv);
|
|
|
|
drm = &priv->drm;
|
|
crtc = priv->crtc;
|
|
conn = &priv->connector;
|
|
ret = set_connector_edid(test, conn,
|
|
test_edid_hdmi_1080p_rgb_max_200mhz,
|
|
ARRAY_SIZE(test_edid_hdmi_1080p_rgb_max_200mhz));
|
|
KUNIT_ASSERT_GT(test, ret, 0);
|
|
|
|
ctx = drm_kunit_helper_acquire_ctx_alloc(test);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
|
|
|
|
preferred = find_preferred_mode(conn);
|
|
KUNIT_ASSERT_NOT_NULL(test, preferred);
|
|
KUNIT_ASSERT_FALSE(test, preferred->flags & DRM_MODE_FLAG_DBLCLK);
|
|
|
|
ret = light_up_connector(test, drm, crtc, conn, preferred, ctx);
|
|
KUNIT_ASSERT_EQ(test, ret, 0);
|
|
|
|
conn_state = conn->state;
|
|
KUNIT_ASSERT_NOT_NULL(test, conn_state);
|
|
|
|
KUNIT_ASSERT_EQ(test, conn_state->hdmi.output_bpc, 8);
|
|
KUNIT_ASSERT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB);
|
|
KUNIT_EXPECT_EQ(test, conn_state->hdmi.tmds_char_rate, preferred->clock * 1000);
|
|
}
|
|
|
|
/*
|
|
* Test that when doing a commit which would use RGB 10bpc, the TMDS
|
|
* clock rate stored in the connector state is equal to 1.25 times the
|
|
* mode pixel clock
|
|
*/
|
|
static void drm_test_check_tmds_char_rate_rgb_10bpc(struct kunit *test)
|
|
{
|
|
struct drm_atomic_helper_connector_hdmi_priv *priv;
|
|
struct drm_modeset_acquire_ctx *ctx;
|
|
struct drm_connector_state *conn_state;
|
|
struct drm_display_mode *preferred;
|
|
struct drm_connector *conn;
|
|
struct drm_device *drm;
|
|
struct drm_crtc *crtc;
|
|
int ret;
|
|
|
|
priv = drm_kunit_helper_connector_hdmi_init(test,
|
|
BIT(HDMI_COLORSPACE_RGB),
|
|
10);
|
|
KUNIT_ASSERT_NOT_NULL(test, priv);
|
|
|
|
drm = &priv->drm;
|
|
crtc = priv->crtc;
|
|
conn = &priv->connector;
|
|
ret = set_connector_edid(test, conn,
|
|
test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz,
|
|
ARRAY_SIZE(test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz));
|
|
KUNIT_ASSERT_GT(test, ret, 0);
|
|
|
|
ctx = drm_kunit_helper_acquire_ctx_alloc(test);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
|
|
|
|
preferred = find_preferred_mode(conn);
|
|
KUNIT_ASSERT_NOT_NULL(test, preferred);
|
|
KUNIT_ASSERT_FALSE(test, preferred->flags & DRM_MODE_FLAG_DBLCLK);
|
|
|
|
ret = light_up_connector(test, drm, crtc, conn, preferred, ctx);
|
|
KUNIT_ASSERT_EQ(test, ret, 0);
|
|
|
|
conn_state = conn->state;
|
|
KUNIT_ASSERT_NOT_NULL(test, conn_state);
|
|
|
|
KUNIT_ASSERT_EQ(test, conn_state->hdmi.output_bpc, 10);
|
|
KUNIT_ASSERT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB);
|
|
KUNIT_EXPECT_EQ(test, conn_state->hdmi.tmds_char_rate, preferred->clock * 1250);
|
|
}
|
|
|
|
/*
|
|
* Test that when doing a commit which would use RGB 12bpc, the TMDS
|
|
* clock rate stored in the connector state is equal to 1.5 times the
|
|
* mode pixel clock
|
|
*/
|
|
static void drm_test_check_tmds_char_rate_rgb_12bpc(struct kunit *test)
|
|
{
|
|
struct drm_atomic_helper_connector_hdmi_priv *priv;
|
|
struct drm_modeset_acquire_ctx *ctx;
|
|
struct drm_connector_state *conn_state;
|
|
struct drm_display_mode *preferred;
|
|
struct drm_connector *conn;
|
|
struct drm_device *drm;
|
|
struct drm_crtc *crtc;
|
|
int ret;
|
|
|
|
priv = drm_kunit_helper_connector_hdmi_init(test,
|
|
BIT(HDMI_COLORSPACE_RGB),
|
|
12);
|
|
KUNIT_ASSERT_NOT_NULL(test, priv);
|
|
|
|
drm = &priv->drm;
|
|
crtc = priv->crtc;
|
|
conn = &priv->connector;
|
|
ret = set_connector_edid(test, conn,
|
|
test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz,
|
|
ARRAY_SIZE(test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz));
|
|
KUNIT_ASSERT_GT(test, ret, 0);
|
|
|
|
ctx = drm_kunit_helper_acquire_ctx_alloc(test);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
|
|
|
|
preferred = find_preferred_mode(conn);
|
|
KUNIT_ASSERT_NOT_NULL(test, preferred);
|
|
KUNIT_ASSERT_FALSE(test, preferred->flags & DRM_MODE_FLAG_DBLCLK);
|
|
|
|
ret = light_up_connector(test, drm, crtc, conn, preferred, ctx);
|
|
KUNIT_ASSERT_EQ(test, ret, 0);
|
|
|
|
conn_state = conn->state;
|
|
KUNIT_ASSERT_NOT_NULL(test, conn_state);
|
|
|
|
KUNIT_ASSERT_EQ(test, conn_state->hdmi.output_bpc, 12);
|
|
KUNIT_ASSERT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB);
|
|
KUNIT_EXPECT_EQ(test, conn_state->hdmi.tmds_char_rate, preferred->clock * 1500);
|
|
}
|
|
|
|
/*
|
|
* Test that if we filter a rate through our hook, it's indeed rejected
|
|
* by the whole atomic_check logic.
|
|
*
|
|
* We do so by first doing a commit on the pipeline to make sure that it
|
|
* works, change the HDMI helpers pointer, and then try the same commit
|
|
* again to see if it fails as it should.
|
|
*/
|
|
static void drm_test_check_hdmi_funcs_reject_rate(struct kunit *test)
|
|
{
|
|
struct drm_atomic_helper_connector_hdmi_priv *priv;
|
|
struct drm_modeset_acquire_ctx *ctx;
|
|
struct drm_atomic_state *state;
|
|
struct drm_display_mode *preferred;
|
|
struct drm_crtc_state *crtc_state;
|
|
struct drm_connector *conn;
|
|
struct drm_device *drm;
|
|
struct drm_crtc *crtc;
|
|
int ret;
|
|
|
|
priv = drm_kunit_helper_connector_hdmi_init(test,
|
|
BIT(HDMI_COLORSPACE_RGB),
|
|
8);
|
|
KUNIT_ASSERT_NOT_NULL(test, priv);
|
|
|
|
drm = &priv->drm;
|
|
crtc = priv->crtc;
|
|
conn = &priv->connector;
|
|
|
|
ctx = drm_kunit_helper_acquire_ctx_alloc(test);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
|
|
|
|
preferred = find_preferred_mode(conn);
|
|
KUNIT_ASSERT_NOT_NULL(test, preferred);
|
|
|
|
ret = light_up_connector(test, drm, crtc, conn, preferred, ctx);
|
|
KUNIT_ASSERT_EQ(test, ret, 0);
|
|
|
|
/* You shouldn't be doing that at home. */
|
|
conn->hdmi.funcs = &reject_connector_hdmi_funcs;
|
|
|
|
state = drm_kunit_helper_atomic_state_alloc(test, drm, ctx);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
|
|
|
|
crtc_state = drm_atomic_get_crtc_state(state, crtc);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
|
|
|
|
crtc_state->connectors_changed = true;
|
|
|
|
ret = drm_atomic_check_only(state);
|
|
KUNIT_EXPECT_LT(test, ret, 0);
|
|
}
|
|
|
|
/*
|
|
* Test that if:
|
|
* - We have an HDMI connector supporting RGB only
|
|
* - The chosen mode has a TMDS character rate higher than the display
|
|
* supports in RGB/12bpc
|
|
* - The chosen mode has a TMDS character rate lower than the display
|
|
* supports in RGB/10bpc.
|
|
*
|
|
* Then we will pick the latter, and the computed TMDS character rate
|
|
* will be equal to 1.25 times the mode pixel clock.
|
|
*/
|
|
static void drm_test_check_max_tmds_rate_bpc_fallback(struct kunit *test)
|
|
{
|
|
struct drm_atomic_helper_connector_hdmi_priv *priv;
|
|
struct drm_modeset_acquire_ctx *ctx;
|
|
struct drm_connector_state *conn_state;
|
|
struct drm_display_info *info;
|
|
struct drm_display_mode *preferred;
|
|
unsigned long long rate;
|
|
struct drm_connector *conn;
|
|
struct drm_device *drm;
|
|
struct drm_crtc *crtc;
|
|
int ret;
|
|
|
|
priv = drm_kunit_helper_connector_hdmi_init(test,
|
|
BIT(HDMI_COLORSPACE_RGB),
|
|
12);
|
|
KUNIT_ASSERT_NOT_NULL(test, priv);
|
|
|
|
drm = &priv->drm;
|
|
crtc = priv->crtc;
|
|
conn = &priv->connector;
|
|
ret = set_connector_edid(test, conn,
|
|
test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz,
|
|
ARRAY_SIZE(test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz));
|
|
KUNIT_ASSERT_GT(test, ret, 0);
|
|
|
|
info = &conn->display_info;
|
|
KUNIT_ASSERT_TRUE(test, info->is_hdmi);
|
|
KUNIT_ASSERT_GT(test, info->max_tmds_clock, 0);
|
|
|
|
ctx = drm_kunit_helper_acquire_ctx_alloc(test);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
|
|
|
|
preferred = find_preferred_mode(conn);
|
|
KUNIT_ASSERT_NOT_NULL(test, preferred);
|
|
KUNIT_ASSERT_FALSE(test, preferred->flags & DRM_MODE_FLAG_DBLCLK);
|
|
|
|
rate = drm_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_RGB);
|
|
KUNIT_ASSERT_GT(test, rate, info->max_tmds_clock * 1000);
|
|
|
|
rate = drm_hdmi_compute_mode_clock(preferred, 10, HDMI_COLORSPACE_RGB);
|
|
KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000);
|
|
|
|
ret = light_up_connector(test, drm, crtc, conn, preferred, ctx);
|
|
KUNIT_EXPECT_EQ(test, ret, 0);
|
|
|
|
conn_state = conn->state;
|
|
KUNIT_ASSERT_NOT_NULL(test, conn_state);
|
|
|
|
KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 10);
|
|
KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB);
|
|
KUNIT_EXPECT_EQ(test, conn_state->hdmi.tmds_char_rate, preferred->clock * 1250);
|
|
}
|
|
|
|
/*
|
|
* Test that if:
|
|
* - We have an HDMI connector supporting both RGB and YUV422 and up to
|
|
* 12 bpc
|
|
* - The chosen mode has a TMDS character rate higher than the display
|
|
* supports in RGB/12bpc but lower than the display supports in
|
|
* RGB/10bpc
|
|
* - The chosen mode has a TMDS character rate lower than the display
|
|
* supports in YUV422/12bpc.
|
|
*
|
|
* Then we will prefer to keep the RGB format with a lower bpc over
|
|
* picking YUV422.
|
|
*/
|
|
static void drm_test_check_max_tmds_rate_format_fallback(struct kunit *test)
|
|
{
|
|
struct drm_atomic_helper_connector_hdmi_priv *priv;
|
|
struct drm_modeset_acquire_ctx *ctx;
|
|
struct drm_connector_state *conn_state;
|
|
struct drm_display_info *info;
|
|
struct drm_display_mode *preferred;
|
|
unsigned long long rate;
|
|
struct drm_connector *conn;
|
|
struct drm_device *drm;
|
|
struct drm_crtc *crtc;
|
|
int ret;
|
|
|
|
priv = drm_kunit_helper_connector_hdmi_init(test,
|
|
BIT(HDMI_COLORSPACE_RGB) |
|
|
BIT(HDMI_COLORSPACE_YUV422) |
|
|
BIT(HDMI_COLORSPACE_YUV444),
|
|
12);
|
|
KUNIT_ASSERT_NOT_NULL(test, priv);
|
|
|
|
drm = &priv->drm;
|
|
crtc = priv->crtc;
|
|
conn = &priv->connector;
|
|
ret = set_connector_edid(test, conn,
|
|
test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz,
|
|
ARRAY_SIZE(test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz));
|
|
KUNIT_ASSERT_GT(test, ret, 0);
|
|
|
|
info = &conn->display_info;
|
|
KUNIT_ASSERT_TRUE(test, info->is_hdmi);
|
|
KUNIT_ASSERT_GT(test, info->max_tmds_clock, 0);
|
|
|
|
ctx = drm_kunit_helper_acquire_ctx_alloc(test);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
|
|
|
|
preferred = find_preferred_mode(conn);
|
|
KUNIT_ASSERT_NOT_NULL(test, preferred);
|
|
KUNIT_ASSERT_FALSE(test, preferred->flags & DRM_MODE_FLAG_DBLCLK);
|
|
|
|
rate = drm_hdmi_compute_mode_clock(preferred, 10, HDMI_COLORSPACE_RGB);
|
|
KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000);
|
|
|
|
rate = drm_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_RGB);
|
|
KUNIT_ASSERT_GT(test, rate, info->max_tmds_clock * 1000);
|
|
|
|
rate = drm_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_YUV422);
|
|
KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000);
|
|
|
|
ret = light_up_connector(test, drm, crtc, conn, preferred, ctx);
|
|
KUNIT_EXPECT_EQ(test, ret, 0);
|
|
|
|
conn_state = conn->state;
|
|
KUNIT_ASSERT_NOT_NULL(test, conn_state);
|
|
|
|
KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 10);
|
|
KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB);
|
|
}
|
|
|
|
/*
|
|
* Test that if a driver and screen supports RGB and YUV formats, and we
|
|
* try to set the VIC 1 mode, we end up with 8bpc RGB even if we could
|
|
* have had a higher bpc.
|
|
*/
|
|
static void drm_test_check_output_bpc_format_vic_1(struct kunit *test)
|
|
{
|
|
struct drm_atomic_helper_connector_hdmi_priv *priv;
|
|
struct drm_modeset_acquire_ctx *ctx;
|
|
struct drm_connector_state *conn_state;
|
|
struct drm_display_info *info;
|
|
struct drm_display_mode *mode;
|
|
unsigned long long rate;
|
|
struct drm_connector *conn;
|
|
struct drm_device *drm;
|
|
struct drm_crtc *crtc;
|
|
int ret;
|
|
|
|
priv = drm_kunit_helper_connector_hdmi_init(test,
|
|
BIT(HDMI_COLORSPACE_RGB) |
|
|
BIT(HDMI_COLORSPACE_YUV422) |
|
|
BIT(HDMI_COLORSPACE_YUV444),
|
|
12);
|
|
KUNIT_ASSERT_NOT_NULL(test, priv);
|
|
|
|
drm = &priv->drm;
|
|
conn = &priv->connector;
|
|
ret = set_connector_edid(test, conn,
|
|
test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz,
|
|
ARRAY_SIZE(test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz));
|
|
KUNIT_ASSERT_GT(test, ret, 0);
|
|
|
|
info = &conn->display_info;
|
|
KUNIT_ASSERT_TRUE(test, info->is_hdmi);
|
|
KUNIT_ASSERT_GT(test, info->max_tmds_clock, 0);
|
|
|
|
ctx = drm_kunit_helper_acquire_ctx_alloc(test);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
|
|
|
|
mode = drm_kunit_display_mode_from_cea_vic(test, drm, 1);
|
|
KUNIT_ASSERT_NOT_NULL(test, mode);
|
|
|
|
/*
|
|
* NOTE: We can't use drm_hdmi_compute_mode_clock()
|
|
* here because we're trying to get the rate of an invalid
|
|
* configuration.
|
|
*
|
|
* Thus, we have to calculate the rate by hand.
|
|
*/
|
|
rate = mode->clock * 1500;
|
|
KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000);
|
|
|
|
crtc = priv->crtc;
|
|
ret = light_up_connector(test, drm, crtc, conn, mode, ctx);
|
|
KUNIT_EXPECT_EQ(test, ret, 0);
|
|
|
|
conn_state = conn->state;
|
|
KUNIT_ASSERT_NOT_NULL(test, conn_state);
|
|
|
|
KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 8);
|
|
KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB);
|
|
}
|
|
|
|
/*
|
|
* Test that if a driver supports only RGB but the screen also supports
|
|
* YUV formats, we only end up with an RGB format.
|
|
*/
|
|
static void drm_test_check_output_bpc_format_driver_rgb_only(struct kunit *test)
|
|
{
|
|
struct drm_atomic_helper_connector_hdmi_priv *priv;
|
|
struct drm_modeset_acquire_ctx *ctx;
|
|
struct drm_connector_state *conn_state;
|
|
struct drm_display_info *info;
|
|
struct drm_display_mode *preferred;
|
|
unsigned long long rate;
|
|
struct drm_connector *conn;
|
|
struct drm_device *drm;
|
|
struct drm_crtc *crtc;
|
|
int ret;
|
|
|
|
priv = drm_kunit_helper_connector_hdmi_init(test,
|
|
BIT(HDMI_COLORSPACE_RGB),
|
|
12);
|
|
KUNIT_ASSERT_NOT_NULL(test, priv);
|
|
|
|
drm = &priv->drm;
|
|
crtc = priv->crtc;
|
|
conn = &priv->connector;
|
|
ret = set_connector_edid(test, conn,
|
|
test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz,
|
|
ARRAY_SIZE(test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz));
|
|
KUNIT_ASSERT_GT(test, ret, 0);
|
|
|
|
info = &conn->display_info;
|
|
KUNIT_ASSERT_TRUE(test, info->is_hdmi);
|
|
KUNIT_ASSERT_GT(test, info->max_tmds_clock, 0);
|
|
|
|
ctx = drm_kunit_helper_acquire_ctx_alloc(test);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
|
|
|
|
preferred = find_preferred_mode(conn);
|
|
KUNIT_ASSERT_NOT_NULL(test, preferred);
|
|
|
|
/*
|
|
* We're making sure that YUV422 would be the preferred option
|
|
* here: we're always favouring higher bpc, we can't have RGB
|
|
* because the TMDS character rate exceeds the maximum supported
|
|
* by the display, and YUV422 works for that display.
|
|
*
|
|
* But since the driver only supports RGB, we should fallback to
|
|
* a lower bpc with RGB.
|
|
*/
|
|
rate = drm_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_RGB);
|
|
KUNIT_ASSERT_GT(test, rate, info->max_tmds_clock * 1000);
|
|
|
|
rate = drm_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_YUV422);
|
|
KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000);
|
|
|
|
ret = light_up_connector(test, drm, crtc, conn, preferred, ctx);
|
|
KUNIT_EXPECT_EQ(test, ret, 0);
|
|
|
|
conn_state = conn->state;
|
|
KUNIT_ASSERT_NOT_NULL(test, conn_state);
|
|
|
|
KUNIT_EXPECT_LT(test, conn_state->hdmi.output_bpc, 12);
|
|
KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB);
|
|
}
|
|
|
|
/*
|
|
* Test that if a screen supports only RGB but the driver also supports
|
|
* YUV formats, we only end up with an RGB format.
|
|
*/
|
|
static void drm_test_check_output_bpc_format_display_rgb_only(struct kunit *test)
|
|
{
|
|
struct drm_atomic_helper_connector_hdmi_priv *priv;
|
|
struct drm_modeset_acquire_ctx *ctx;
|
|
struct drm_connector_state *conn_state;
|
|
struct drm_display_info *info;
|
|
struct drm_display_mode *preferred;
|
|
unsigned long long rate;
|
|
struct drm_connector *conn;
|
|
struct drm_device *drm;
|
|
struct drm_crtc *crtc;
|
|
int ret;
|
|
|
|
priv = drm_kunit_helper_connector_hdmi_init(test,
|
|
BIT(HDMI_COLORSPACE_RGB) |
|
|
BIT(HDMI_COLORSPACE_YUV422) |
|
|
BIT(HDMI_COLORSPACE_YUV444),
|
|
12);
|
|
KUNIT_ASSERT_NOT_NULL(test, priv);
|
|
|
|
drm = &priv->drm;
|
|
crtc = priv->crtc;
|
|
conn = &priv->connector;
|
|
ret = set_connector_edid(test, conn,
|
|
test_edid_hdmi_1080p_rgb_max_200mhz,
|
|
ARRAY_SIZE(test_edid_hdmi_1080p_rgb_max_200mhz));
|
|
KUNIT_ASSERT_GT(test, ret, 0);
|
|
|
|
info = &conn->display_info;
|
|
KUNIT_ASSERT_TRUE(test, info->is_hdmi);
|
|
KUNIT_ASSERT_GT(test, info->max_tmds_clock, 0);
|
|
|
|
ctx = drm_kunit_helper_acquire_ctx_alloc(test);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
|
|
|
|
preferred = find_preferred_mode(conn);
|
|
KUNIT_ASSERT_NOT_NULL(test, preferred);
|
|
|
|
/*
|
|
* We're making sure that YUV422 would be the preferred option
|
|
* here: we're always favouring higher bpc, we can't have RGB
|
|
* because the TMDS character rate exceeds the maximum supported
|
|
* by the display, and YUV422 works for that display.
|
|
*
|
|
* But since the display only supports RGB, we should fallback to
|
|
* a lower bpc with RGB.
|
|
*/
|
|
rate = drm_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_RGB);
|
|
KUNIT_ASSERT_GT(test, rate, info->max_tmds_clock * 1000);
|
|
|
|
rate = drm_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_YUV422);
|
|
KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000);
|
|
|
|
ret = light_up_connector(test, drm, crtc, conn, preferred, ctx);
|
|
KUNIT_EXPECT_EQ(test, ret, 0);
|
|
|
|
conn_state = conn->state;
|
|
KUNIT_ASSERT_NOT_NULL(test, conn_state);
|
|
|
|
KUNIT_EXPECT_LT(test, conn_state->hdmi.output_bpc, 12);
|
|
KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB);
|
|
}
|
|
|
|
/*
|
|
* Test that if a display supports higher bpc but the driver only
|
|
* supports 8 bpc, we only end up with 8 bpc even if we could have had a
|
|
* higher bpc.
|
|
*/
|
|
static void drm_test_check_output_bpc_format_driver_8bpc_only(struct kunit *test)
|
|
{
|
|
struct drm_atomic_helper_connector_hdmi_priv *priv;
|
|
struct drm_modeset_acquire_ctx *ctx;
|
|
struct drm_connector_state *conn_state;
|
|
struct drm_display_info *info;
|
|
struct drm_display_mode *preferred;
|
|
unsigned long long rate;
|
|
struct drm_connector *conn;
|
|
struct drm_device *drm;
|
|
struct drm_crtc *crtc;
|
|
int ret;
|
|
|
|
priv = drm_kunit_helper_connector_hdmi_init(test,
|
|
BIT(HDMI_COLORSPACE_RGB),
|
|
8);
|
|
KUNIT_ASSERT_NOT_NULL(test, priv);
|
|
|
|
drm = &priv->drm;
|
|
crtc = priv->crtc;
|
|
conn = &priv->connector;
|
|
ret = set_connector_edid(test, conn,
|
|
test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz,
|
|
ARRAY_SIZE(test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz));
|
|
KUNIT_ASSERT_GT(test, ret, 0);
|
|
|
|
info = &conn->display_info;
|
|
KUNIT_ASSERT_TRUE(test, info->is_hdmi);
|
|
KUNIT_ASSERT_GT(test, info->max_tmds_clock, 0);
|
|
|
|
ctx = drm_kunit_helper_acquire_ctx_alloc(test);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
|
|
|
|
preferred = find_preferred_mode(conn);
|
|
KUNIT_ASSERT_NOT_NULL(test, preferred);
|
|
|
|
/*
|
|
* We're making sure that we have headroom on the TMDS character
|
|
* clock to actually use 12bpc.
|
|
*/
|
|
rate = drm_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_RGB);
|
|
KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000);
|
|
|
|
ret = light_up_connector(test, drm, crtc, conn, preferred, ctx);
|
|
KUNIT_EXPECT_EQ(test, ret, 0);
|
|
|
|
conn_state = conn->state;
|
|
KUNIT_ASSERT_NOT_NULL(test, conn_state);
|
|
|
|
KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 8);
|
|
KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB);
|
|
}
|
|
|
|
/*
|
|
* Test that if a driver supports higher bpc but the display only
|
|
* supports 8 bpc, we only end up with 8 bpc even if we could have had a
|
|
* higher bpc.
|
|
*/
|
|
static void drm_test_check_output_bpc_format_display_8bpc_only(struct kunit *test)
|
|
{
|
|
struct drm_atomic_helper_connector_hdmi_priv *priv;
|
|
struct drm_modeset_acquire_ctx *ctx;
|
|
struct drm_connector_state *conn_state;
|
|
struct drm_display_info *info;
|
|
struct drm_display_mode *preferred;
|
|
unsigned long long rate;
|
|
struct drm_connector *conn;
|
|
struct drm_device *drm;
|
|
struct drm_crtc *crtc;
|
|
int ret;
|
|
|
|
priv = drm_kunit_helper_connector_hdmi_init(test,
|
|
BIT(HDMI_COLORSPACE_RGB) |
|
|
BIT(HDMI_COLORSPACE_YUV422) |
|
|
BIT(HDMI_COLORSPACE_YUV444),
|
|
12);
|
|
KUNIT_ASSERT_NOT_NULL(test, priv);
|
|
|
|
drm = &priv->drm;
|
|
crtc = priv->crtc;
|
|
conn = &priv->connector;
|
|
ret = set_connector_edid(test, conn,
|
|
test_edid_hdmi_1080p_rgb_max_340mhz,
|
|
ARRAY_SIZE(test_edid_hdmi_1080p_rgb_max_340mhz));
|
|
KUNIT_ASSERT_GT(test, ret, 0);
|
|
|
|
info = &conn->display_info;
|
|
KUNIT_ASSERT_TRUE(test, info->is_hdmi);
|
|
KUNIT_ASSERT_GT(test, info->max_tmds_clock, 0);
|
|
|
|
ctx = drm_kunit_helper_acquire_ctx_alloc(test);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
|
|
|
|
preferred = find_preferred_mode(conn);
|
|
KUNIT_ASSERT_NOT_NULL(test, preferred);
|
|
|
|
/*
|
|
* We're making sure that we have headroom on the TMDS character
|
|
* clock to actually use 12bpc.
|
|
*/
|
|
rate = drm_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_RGB);
|
|
KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000);
|
|
|
|
ret = light_up_connector(test, drm, crtc, conn, preferred, ctx);
|
|
KUNIT_EXPECT_EQ(test, ret, 0);
|
|
|
|
conn_state = conn->state;
|
|
KUNIT_ASSERT_NOT_NULL(test, conn_state);
|
|
|
|
KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 8);
|
|
KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB);
|
|
}
|
|
|
|
/* Test that atomic check succeeds when disabling a connector. */
|
|
static void drm_test_check_disable_connector(struct kunit *test)
|
|
{
|
|
struct drm_atomic_helper_connector_hdmi_priv *priv;
|
|
struct drm_modeset_acquire_ctx *ctx;
|
|
struct drm_connector_state *conn_state;
|
|
struct drm_crtc_state *crtc_state;
|
|
struct drm_atomic_state *state;
|
|
struct drm_display_mode *preferred;
|
|
struct drm_connector *conn;
|
|
struct drm_device *drm;
|
|
struct drm_crtc *crtc;
|
|
int ret;
|
|
|
|
priv = drm_kunit_helper_connector_hdmi_init(test,
|
|
BIT(HDMI_COLORSPACE_RGB),
|
|
8);
|
|
KUNIT_ASSERT_NOT_NULL(test, priv);
|
|
|
|
ctx = drm_kunit_helper_acquire_ctx_alloc(test);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
|
|
|
|
conn = &priv->connector;
|
|
preferred = find_preferred_mode(conn);
|
|
KUNIT_ASSERT_NOT_NULL(test, preferred);
|
|
|
|
drm = &priv->drm;
|
|
crtc = priv->crtc;
|
|
ret = light_up_connector(test, drm, crtc, conn, preferred, ctx);
|
|
KUNIT_ASSERT_EQ(test, ret, 0);
|
|
|
|
state = drm_kunit_helper_atomic_state_alloc(test, drm, ctx);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
|
|
|
|
crtc_state = drm_atomic_get_crtc_state(state, crtc);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
|
|
|
|
crtc_state->active = false;
|
|
ret = drm_atomic_set_mode_for_crtc(crtc_state, NULL);
|
|
KUNIT_EXPECT_EQ(test, ret, 0);
|
|
|
|
conn_state = drm_atomic_get_connector_state(state, conn);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
|
|
|
|
ret = drm_atomic_set_crtc_for_connector(conn_state, NULL);
|
|
KUNIT_EXPECT_EQ(test, ret, 0);
|
|
|
|
ret = drm_atomic_check_only(state);
|
|
KUNIT_ASSERT_EQ(test, ret, 0);
|
|
}
|
|
|
|
static struct kunit_case drm_atomic_helper_connector_hdmi_check_tests[] = {
|
|
KUNIT_CASE(drm_test_check_broadcast_rgb_auto_cea_mode),
|
|
KUNIT_CASE(drm_test_check_broadcast_rgb_auto_cea_mode_vic_1),
|
|
KUNIT_CASE(drm_test_check_broadcast_rgb_full_cea_mode),
|
|
KUNIT_CASE(drm_test_check_broadcast_rgb_full_cea_mode_vic_1),
|
|
KUNIT_CASE(drm_test_check_broadcast_rgb_limited_cea_mode),
|
|
KUNIT_CASE(drm_test_check_broadcast_rgb_limited_cea_mode_vic_1),
|
|
/*
|
|
* TODO: When we'll have YUV output support, we need to check
|
|
* that the limited range is always set to limited no matter
|
|
* what the value of Broadcast RGB is.
|
|
*/
|
|
KUNIT_CASE(drm_test_check_broadcast_rgb_crtc_mode_changed),
|
|
KUNIT_CASE(drm_test_check_broadcast_rgb_crtc_mode_not_changed),
|
|
KUNIT_CASE(drm_test_check_disable_connector),
|
|
KUNIT_CASE(drm_test_check_hdmi_funcs_reject_rate),
|
|
KUNIT_CASE(drm_test_check_max_tmds_rate_bpc_fallback),
|
|
KUNIT_CASE(drm_test_check_max_tmds_rate_format_fallback),
|
|
KUNIT_CASE(drm_test_check_output_bpc_crtc_mode_changed),
|
|
KUNIT_CASE(drm_test_check_output_bpc_crtc_mode_not_changed),
|
|
KUNIT_CASE(drm_test_check_output_bpc_dvi),
|
|
KUNIT_CASE(drm_test_check_output_bpc_format_vic_1),
|
|
KUNIT_CASE(drm_test_check_output_bpc_format_display_8bpc_only),
|
|
KUNIT_CASE(drm_test_check_output_bpc_format_display_rgb_only),
|
|
KUNIT_CASE(drm_test_check_output_bpc_format_driver_8bpc_only),
|
|
KUNIT_CASE(drm_test_check_output_bpc_format_driver_rgb_only),
|
|
KUNIT_CASE(drm_test_check_tmds_char_rate_rgb_8bpc),
|
|
KUNIT_CASE(drm_test_check_tmds_char_rate_rgb_10bpc),
|
|
KUNIT_CASE(drm_test_check_tmds_char_rate_rgb_12bpc),
|
|
/*
|
|
* TODO: We should have tests to check that a change in the
|
|
* format triggers a CRTC mode change just like we do for the
|
|
* RGB Quantization and BPC.
|
|
*
|
|
* However, we don't have any way to control which format gets
|
|
* picked up aside from changing the BPC or mode which would
|
|
* already trigger a mode change.
|
|
*/
|
|
{ }
|
|
};
|
|
|
|
static struct kunit_suite drm_atomic_helper_connector_hdmi_check_test_suite = {
|
|
.name = "drm_atomic_helper_connector_hdmi_check",
|
|
.test_cases = drm_atomic_helper_connector_hdmi_check_tests,
|
|
};
|
|
|
|
/*
|
|
* Test that the value of the Broadcast RGB property out of reset is set
|
|
* to auto.
|
|
*/
|
|
static void drm_test_check_broadcast_rgb_value(struct kunit *test)
|
|
{
|
|
struct drm_atomic_helper_connector_hdmi_priv *priv;
|
|
struct drm_connector_state *conn_state;
|
|
struct drm_connector *conn;
|
|
|
|
priv = drm_kunit_helper_connector_hdmi_init(test,
|
|
BIT(HDMI_COLORSPACE_RGB),
|
|
8);
|
|
KUNIT_ASSERT_NOT_NULL(test, priv);
|
|
|
|
conn = &priv->connector;
|
|
conn_state = conn->state;
|
|
KUNIT_EXPECT_EQ(test, conn_state->hdmi.broadcast_rgb, DRM_HDMI_BROADCAST_RGB_AUTO);
|
|
}
|
|
|
|
/*
|
|
* Test that if the connector was initialised with a maximum bpc of 8,
|
|
* the value of the max_bpc and max_requested_bpc properties out of
|
|
* reset are also set to 8, and output_bpc is set to 0 and will be
|
|
* filled at atomic_check time.
|
|
*/
|
|
static void drm_test_check_bpc_8_value(struct kunit *test)
|
|
{
|
|
struct drm_atomic_helper_connector_hdmi_priv *priv;
|
|
struct drm_connector_state *conn_state;
|
|
struct drm_connector *conn;
|
|
|
|
priv = drm_kunit_helper_connector_hdmi_init(test,
|
|
BIT(HDMI_COLORSPACE_RGB),
|
|
8);
|
|
KUNIT_ASSERT_NOT_NULL(test, priv);
|
|
|
|
conn = &priv->connector;
|
|
conn_state = conn->state;
|
|
KUNIT_EXPECT_EQ(test, conn_state->max_bpc, 8);
|
|
KUNIT_EXPECT_EQ(test, conn_state->max_requested_bpc, 8);
|
|
KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 0);
|
|
}
|
|
|
|
/*
|
|
* Test that if the connector was initialised with a maximum bpc of 10,
|
|
* the value of the max_bpc and max_requested_bpc properties out of
|
|
* reset are also set to 10, and output_bpc is set to 0 and will be
|
|
* filled at atomic_check time.
|
|
*/
|
|
static void drm_test_check_bpc_10_value(struct kunit *test)
|
|
{
|
|
struct drm_atomic_helper_connector_hdmi_priv *priv;
|
|
struct drm_connector_state *conn_state;
|
|
struct drm_connector *conn;
|
|
|
|
priv = drm_kunit_helper_connector_hdmi_init(test,
|
|
BIT(HDMI_COLORSPACE_RGB),
|
|
10);
|
|
KUNIT_ASSERT_NOT_NULL(test, priv);
|
|
|
|
conn = &priv->connector;
|
|
conn_state = conn->state;
|
|
KUNIT_EXPECT_EQ(test, conn_state->max_bpc, 10);
|
|
KUNIT_EXPECT_EQ(test, conn_state->max_requested_bpc, 10);
|
|
KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 0);
|
|
}
|
|
|
|
/*
|
|
* Test that if the connector was initialised with a maximum bpc of 12,
|
|
* the value of the max_bpc and max_requested_bpc properties out of
|
|
* reset are also set to 12, and output_bpc is set to 0 and will be
|
|
* filled at atomic_check time.
|
|
*/
|
|
static void drm_test_check_bpc_12_value(struct kunit *test)
|
|
{
|
|
struct drm_atomic_helper_connector_hdmi_priv *priv;
|
|
struct drm_connector_state *conn_state;
|
|
struct drm_connector *conn;
|
|
|
|
priv = drm_kunit_helper_connector_hdmi_init(test,
|
|
BIT(HDMI_COLORSPACE_RGB),
|
|
12);
|
|
KUNIT_ASSERT_NOT_NULL(test, priv);
|
|
|
|
conn = &priv->connector;
|
|
conn_state = conn->state;
|
|
KUNIT_EXPECT_EQ(test, conn_state->max_bpc, 12);
|
|
KUNIT_EXPECT_EQ(test, conn_state->max_requested_bpc, 12);
|
|
KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 0);
|
|
}
|
|
|
|
/*
|
|
* Test that the value of the output format property out of reset is set
|
|
* to RGB, even if the driver supports more than that.
|
|
*/
|
|
static void drm_test_check_format_value(struct kunit *test)
|
|
{
|
|
struct drm_atomic_helper_connector_hdmi_priv *priv;
|
|
struct drm_connector_state *conn_state;
|
|
struct drm_connector *conn;
|
|
|
|
priv = drm_kunit_helper_connector_hdmi_init(test,
|
|
BIT(HDMI_COLORSPACE_RGB) |
|
|
BIT(HDMI_COLORSPACE_YUV422) |
|
|
BIT(HDMI_COLORSPACE_YUV444),
|
|
8);
|
|
KUNIT_ASSERT_NOT_NULL(test, priv);
|
|
|
|
conn = &priv->connector;
|
|
conn_state = conn->state;
|
|
KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, 0);
|
|
}
|
|
|
|
/*
|
|
* Test that the value of the output format property out of reset is set
|
|
* to 0, and will be computed at atomic_check time.
|
|
*/
|
|
static void drm_test_check_tmds_char_value(struct kunit *test)
|
|
{
|
|
struct drm_atomic_helper_connector_hdmi_priv *priv;
|
|
struct drm_connector_state *conn_state;
|
|
struct drm_connector *conn;
|
|
|
|
priv = drm_kunit_helper_connector_hdmi_init(test,
|
|
BIT(HDMI_COLORSPACE_RGB) |
|
|
BIT(HDMI_COLORSPACE_YUV422) |
|
|
BIT(HDMI_COLORSPACE_YUV444),
|
|
12);
|
|
KUNIT_ASSERT_NOT_NULL(test, priv);
|
|
|
|
conn = &priv->connector;
|
|
conn_state = conn->state;
|
|
KUNIT_EXPECT_EQ(test, conn_state->hdmi.tmds_char_rate, 0);
|
|
}
|
|
|
|
static struct kunit_case drm_atomic_helper_connector_hdmi_reset_tests[] = {
|
|
KUNIT_CASE(drm_test_check_broadcast_rgb_value),
|
|
KUNIT_CASE(drm_test_check_bpc_8_value),
|
|
KUNIT_CASE(drm_test_check_bpc_10_value),
|
|
KUNIT_CASE(drm_test_check_bpc_12_value),
|
|
KUNIT_CASE(drm_test_check_format_value),
|
|
KUNIT_CASE(drm_test_check_tmds_char_value),
|
|
{ }
|
|
};
|
|
|
|
static struct kunit_suite drm_atomic_helper_connector_hdmi_reset_test_suite = {
|
|
.name = "drm_atomic_helper_connector_hdmi_reset",
|
|
.test_cases = drm_atomic_helper_connector_hdmi_reset_tests,
|
|
};
|
|
|
|
/*
|
|
* Test that the default behaviour for drm_hdmi_connector_mode_valid() is not
|
|
* to reject any modes. Pass a correct EDID and verify that preferred mode
|
|
* matches the expectations (1080p).
|
|
*/
|
|
static void drm_test_check_mode_valid(struct kunit *test)
|
|
{
|
|
struct drm_atomic_helper_connector_hdmi_priv *priv;
|
|
struct drm_connector *conn;
|
|
struct drm_display_mode *preferred;
|
|
|
|
priv = drm_kunit_helper_connector_hdmi_init(test,
|
|
BIT(HDMI_COLORSPACE_RGB),
|
|
8);
|
|
KUNIT_ASSERT_NOT_NULL(test, priv);
|
|
|
|
conn = &priv->connector;
|
|
preferred = find_preferred_mode(conn);
|
|
KUNIT_ASSERT_NOT_NULL(test, preferred);
|
|
|
|
KUNIT_EXPECT_EQ(test, preferred->hdisplay, 1920);
|
|
KUNIT_EXPECT_EQ(test, preferred->vdisplay, 1080);
|
|
KUNIT_EXPECT_EQ(test, preferred->clock, 148500);
|
|
}
|
|
|
|
/*
|
|
* Test that the drm_hdmi_connector_mode_valid() will reject modes depending on
|
|
* the .tmds_char_rate_valid() behaviour.
|
|
* Pass a correct EDID and verify that high-rate modes are filtered.
|
|
*/
|
|
static void drm_test_check_mode_valid_reject_rate(struct kunit *test)
|
|
{
|
|
struct drm_atomic_helper_connector_hdmi_priv *priv;
|
|
struct drm_connector *conn;
|
|
struct drm_display_mode *preferred;
|
|
int ret;
|
|
|
|
priv = drm_kunit_helper_connector_hdmi_init_funcs(test,
|
|
BIT(HDMI_COLORSPACE_RGB),
|
|
8,
|
|
&reject_100_MHz_connector_hdmi_funcs);
|
|
KUNIT_ASSERT_NOT_NULL(test, priv);
|
|
|
|
conn = &priv->connector;
|
|
|
|
ret = set_connector_edid(test, conn,
|
|
test_edid_hdmi_1080p_rgb_max_200mhz,
|
|
ARRAY_SIZE(test_edid_hdmi_1080p_rgb_max_200mhz));
|
|
KUNIT_ASSERT_GT(test, ret, 0);
|
|
|
|
/*
|
|
* Unlike the drm_test_check_mode_valid() here 1080p is rejected, but
|
|
* 480p is allowed.
|
|
*/
|
|
preferred = find_preferred_mode(conn);
|
|
KUNIT_ASSERT_NOT_NULL(test, preferred);
|
|
KUNIT_EXPECT_EQ(test, preferred->hdisplay, 640);
|
|
KUNIT_EXPECT_EQ(test, preferred->vdisplay, 480);
|
|
KUNIT_EXPECT_EQ(test, preferred->clock, 25200);
|
|
}
|
|
|
|
/*
|
|
* Test that the drm_hdmi_connector_mode_valid() will not mark any modes as
|
|
* valid if .tmds_char_rate_valid() rejects all of them. Pass a correct EDID
|
|
* and verify that there is no preferred mode and no modes were set for the
|
|
* connector.
|
|
*/
|
|
static void drm_test_check_mode_valid_reject(struct kunit *test)
|
|
{
|
|
struct drm_atomic_helper_connector_hdmi_priv *priv;
|
|
struct drm_connector *conn;
|
|
struct drm_display_mode *preferred;
|
|
int ret;
|
|
|
|
priv = drm_kunit_helper_connector_hdmi_init_funcs(test,
|
|
BIT(HDMI_COLORSPACE_RGB),
|
|
8,
|
|
&reject_connector_hdmi_funcs);
|
|
KUNIT_ASSERT_NOT_NULL(test, priv);
|
|
|
|
conn = &priv->connector;
|
|
|
|
/* should reject all modes */
|
|
ret = set_connector_edid(test, conn,
|
|
test_edid_hdmi_1080p_rgb_max_200mhz,
|
|
ARRAY_SIZE(test_edid_hdmi_1080p_rgb_max_200mhz));
|
|
KUNIT_ASSERT_EQ(test, ret, 0);
|
|
|
|
preferred = find_preferred_mode(conn);
|
|
KUNIT_ASSERT_NULL(test, preferred);
|
|
}
|
|
|
|
/*
|
|
* Test that the drm_hdmi_connector_mode_valid() will reject modes that don't
|
|
* pass the info.max_tmds_clock filter. Pass crafted EDID and verify that
|
|
* high-rate modes are filtered.
|
|
*/
|
|
static void drm_test_check_mode_valid_reject_max_clock(struct kunit *test)
|
|
{
|
|
struct drm_atomic_helper_connector_hdmi_priv *priv;
|
|
struct drm_connector *conn;
|
|
struct drm_display_mode *preferred;
|
|
int ret;
|
|
|
|
priv = drm_kunit_helper_connector_hdmi_init(test,
|
|
BIT(HDMI_COLORSPACE_RGB),
|
|
8);
|
|
KUNIT_ASSERT_NOT_NULL(test, priv);
|
|
|
|
conn = &priv->connector;
|
|
|
|
ret = set_connector_edid(test, conn,
|
|
test_edid_hdmi_1080p_rgb_max_100mhz,
|
|
ARRAY_SIZE(test_edid_hdmi_1080p_rgb_max_100mhz));
|
|
KUNIT_ASSERT_GT(test, ret, 0);
|
|
|
|
KUNIT_ASSERT_EQ(test, conn->display_info.max_tmds_clock, 100 * 1000);
|
|
|
|
preferred = find_preferred_mode(conn);
|
|
KUNIT_ASSERT_NOT_NULL(test, preferred);
|
|
KUNIT_EXPECT_EQ(test, preferred->hdisplay, 640);
|
|
KUNIT_EXPECT_EQ(test, preferred->vdisplay, 480);
|
|
KUNIT_EXPECT_EQ(test, preferred->clock, 25200);
|
|
}
|
|
|
|
static struct kunit_case drm_atomic_helper_connector_hdmi_mode_valid_tests[] = {
|
|
KUNIT_CASE(drm_test_check_mode_valid),
|
|
KUNIT_CASE(drm_test_check_mode_valid_reject),
|
|
KUNIT_CASE(drm_test_check_mode_valid_reject_rate),
|
|
KUNIT_CASE(drm_test_check_mode_valid_reject_max_clock),
|
|
{ }
|
|
};
|
|
|
|
static struct kunit_suite drm_atomic_helper_connector_hdmi_mode_valid_test_suite = {
|
|
.name = "drm_atomic_helper_connector_hdmi_mode_valid",
|
|
.test_cases = drm_atomic_helper_connector_hdmi_mode_valid_tests,
|
|
};
|
|
|
|
kunit_test_suites(
|
|
&drm_atomic_helper_connector_hdmi_check_test_suite,
|
|
&drm_atomic_helper_connector_hdmi_reset_test_suite,
|
|
&drm_atomic_helper_connector_hdmi_mode_valid_test_suite,
|
|
);
|
|
|
|
MODULE_AUTHOR("Maxime Ripard <mripard@kernel.org>");
|
|
MODULE_DESCRIPTION("Kunit test for drm_hdmi_state_helper functions");
|
|
MODULE_LICENSE("GPL");
|