mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-29 20:30:35 +00:00
![Maxime Ripard](/assets/img/avatar_default.png)
The current helper to allocate a DRM device doesn't allow for any subclassing by drivers, which is going to be troublesome as we work on getting some kunit testing on atomic modesetting code. Let's use a similar pattern to the other allocation helpers by providing the structure size and offset as arguments. Reviewed-by: Javier Martinez Canillas <javierm@redhat.com> Link: https://lore.kernel.org/r/20221123-rpi-kunit-tests-v3-10-4615a663a84a@cerno.tech Signed-off-by: Maxime Ripard <maxime@cerno.tech>
218 lines
6.9 KiB
C
218 lines
6.9 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Kunit test for drm_probe_helper functions
|
|
*/
|
|
|
|
#include <drm/drm_atomic_state_helper.h>
|
|
#include <drm/drm_connector.h>
|
|
#include <drm/drm_device.h>
|
|
#include <drm/drm_drv.h>
|
|
#include <drm/drm_kunit_helpers.h>
|
|
#include <drm/drm_mode.h>
|
|
#include <drm/drm_modes.h>
|
|
#include <drm/drm_modeset_helper_vtables.h>
|
|
#include <drm/drm_probe_helper.h>
|
|
|
|
#include <kunit/test.h>
|
|
|
|
struct drm_probe_helper_test_priv {
|
|
struct drm_device *drm;
|
|
struct device *dev;
|
|
struct drm_connector connector;
|
|
};
|
|
|
|
static const struct drm_connector_helper_funcs drm_probe_helper_connector_helper_funcs = {
|
|
};
|
|
|
|
static const struct drm_connector_funcs drm_probe_helper_connector_funcs = {
|
|
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
|
|
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
|
|
.reset = drm_atomic_helper_connector_reset,
|
|
};
|
|
|
|
static int drm_probe_helper_test_init(struct kunit *test)
|
|
{
|
|
struct drm_probe_helper_test_priv *priv;
|
|
struct drm_connector *connector;
|
|
int ret;
|
|
|
|
priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
|
|
KUNIT_ASSERT_NOT_NULL(test, priv);
|
|
test->priv = priv;
|
|
|
|
priv->dev = drm_kunit_helper_alloc_device(test);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->dev);
|
|
|
|
priv->drm = __drm_kunit_helper_alloc_drm_device(test, priv->dev,
|
|
sizeof(*priv->drm), 0,
|
|
DRIVER_MODESET | DRIVER_ATOMIC);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->drm);
|
|
|
|
connector = &priv->connector;
|
|
ret = drmm_connector_init(priv->drm, connector,
|
|
&drm_probe_helper_connector_funcs,
|
|
DRM_MODE_CONNECTOR_Unknown,
|
|
NULL);
|
|
KUNIT_ASSERT_EQ(test, ret, 0);
|
|
|
|
drm_connector_helper_add(connector, &drm_probe_helper_connector_helper_funcs);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void drm_probe_helper_test_exit(struct kunit *test)
|
|
{
|
|
struct drm_probe_helper_test_priv *priv = test->priv;
|
|
|
|
drm_kunit_helper_free_device(test, priv->dev);
|
|
}
|
|
|
|
typedef struct drm_display_mode *(*expected_mode_func_t)(struct drm_device *);
|
|
|
|
struct drm_connector_helper_tv_get_modes_test {
|
|
const char *name;
|
|
unsigned int supported_tv_modes;
|
|
enum drm_connector_tv_mode default_mode;
|
|
bool cmdline;
|
|
enum drm_connector_tv_mode cmdline_mode;
|
|
expected_mode_func_t *expected_modes;
|
|
unsigned int num_expected_modes;
|
|
};
|
|
|
|
#define _TV_MODE_TEST(_name, _supported, _default, _cmdline, _cmdline_mode, ...) \
|
|
{ \
|
|
.name = _name, \
|
|
.supported_tv_modes = _supported, \
|
|
.default_mode = _default, \
|
|
.cmdline = _cmdline, \
|
|
.cmdline_mode = _cmdline_mode, \
|
|
.expected_modes = (expected_mode_func_t[]) { __VA_ARGS__ }, \
|
|
.num_expected_modes = sizeof((expected_mode_func_t[]) { __VA_ARGS__ }) / \
|
|
(sizeof(expected_mode_func_t)), \
|
|
}
|
|
|
|
#define TV_MODE_TEST(_name, _supported, _default, ...) \
|
|
_TV_MODE_TEST(_name, _supported, _default, false, 0, __VA_ARGS__)
|
|
|
|
#define TV_MODE_TEST_CMDLINE(_name, _supported, _default, _cmdline, ...) \
|
|
_TV_MODE_TEST(_name, _supported, _default, true, _cmdline, __VA_ARGS__)
|
|
|
|
static void
|
|
drm_test_connector_helper_tv_get_modes_check(struct kunit *test)
|
|
{
|
|
const struct drm_connector_helper_tv_get_modes_test *params = test->param_value;
|
|
struct drm_probe_helper_test_priv *priv = test->priv;
|
|
struct drm_connector *connector = &priv->connector;
|
|
struct drm_cmdline_mode *cmdline = &connector->cmdline_mode;
|
|
struct drm_display_mode *mode;
|
|
const struct drm_display_mode *expected;
|
|
size_t len;
|
|
int ret;
|
|
|
|
if (params->cmdline) {
|
|
cmdline->tv_mode_specified = true;
|
|
cmdline->tv_mode = params->cmdline_mode;
|
|
}
|
|
|
|
ret = drm_mode_create_tv_properties(priv->drm, params->supported_tv_modes);
|
|
KUNIT_ASSERT_EQ(test, ret, 0);
|
|
|
|
drm_object_attach_property(&connector->base,
|
|
priv->drm->mode_config.tv_mode_property,
|
|
params->default_mode);
|
|
|
|
mutex_lock(&priv->drm->mode_config.mutex);
|
|
|
|
ret = drm_connector_helper_tv_get_modes(connector);
|
|
KUNIT_EXPECT_EQ(test, ret, params->num_expected_modes);
|
|
|
|
len = 0;
|
|
list_for_each_entry(mode, &connector->probed_modes, head)
|
|
len++;
|
|
KUNIT_EXPECT_EQ(test, len, params->num_expected_modes);
|
|
|
|
if (params->num_expected_modes >= 1) {
|
|
mode = list_first_entry_or_null(&connector->probed_modes,
|
|
struct drm_display_mode, head);
|
|
KUNIT_ASSERT_NOT_NULL(test, mode);
|
|
|
|
expected = params->expected_modes[0](priv->drm);
|
|
KUNIT_ASSERT_NOT_NULL(test, expected);
|
|
|
|
KUNIT_EXPECT_TRUE(test, drm_mode_equal(mode, expected));
|
|
KUNIT_EXPECT_TRUE(test, mode->type & DRM_MODE_TYPE_PREFERRED);
|
|
}
|
|
|
|
if (params->num_expected_modes >= 2) {
|
|
mode = list_next_entry(mode, head);
|
|
KUNIT_ASSERT_NOT_NULL(test, mode);
|
|
|
|
expected = params->expected_modes[1](priv->drm);
|
|
KUNIT_ASSERT_NOT_NULL(test, expected);
|
|
|
|
KUNIT_EXPECT_TRUE(test, drm_mode_equal(mode, expected));
|
|
KUNIT_EXPECT_FALSE(test, mode->type & DRM_MODE_TYPE_PREFERRED);
|
|
}
|
|
|
|
mutex_unlock(&priv->drm->mode_config.mutex);
|
|
}
|
|
|
|
static const
|
|
struct drm_connector_helper_tv_get_modes_test drm_connector_helper_tv_get_modes_tests[] = {
|
|
{ .name = "None" },
|
|
TV_MODE_TEST("PAL",
|
|
BIT(DRM_MODE_TV_MODE_PAL),
|
|
DRM_MODE_TV_MODE_PAL,
|
|
drm_mode_analog_pal_576i),
|
|
TV_MODE_TEST("NTSC",
|
|
BIT(DRM_MODE_TV_MODE_NTSC),
|
|
DRM_MODE_TV_MODE_NTSC,
|
|
drm_mode_analog_ntsc_480i),
|
|
TV_MODE_TEST("Both, NTSC Default",
|
|
BIT(DRM_MODE_TV_MODE_NTSC) | BIT(DRM_MODE_TV_MODE_PAL),
|
|
DRM_MODE_TV_MODE_NTSC,
|
|
drm_mode_analog_ntsc_480i, drm_mode_analog_pal_576i),
|
|
TV_MODE_TEST("Both, PAL Default",
|
|
BIT(DRM_MODE_TV_MODE_NTSC) | BIT(DRM_MODE_TV_MODE_PAL),
|
|
DRM_MODE_TV_MODE_PAL,
|
|
drm_mode_analog_pal_576i, drm_mode_analog_ntsc_480i),
|
|
TV_MODE_TEST_CMDLINE("Both, NTSC Default, with PAL on command-line",
|
|
BIT(DRM_MODE_TV_MODE_NTSC) | BIT(DRM_MODE_TV_MODE_PAL),
|
|
DRM_MODE_TV_MODE_NTSC,
|
|
DRM_MODE_TV_MODE_PAL,
|
|
drm_mode_analog_pal_576i, drm_mode_analog_ntsc_480i),
|
|
TV_MODE_TEST_CMDLINE("Both, PAL Default, with NTSC on command-line",
|
|
BIT(DRM_MODE_TV_MODE_NTSC) | BIT(DRM_MODE_TV_MODE_PAL),
|
|
DRM_MODE_TV_MODE_PAL,
|
|
DRM_MODE_TV_MODE_NTSC,
|
|
drm_mode_analog_ntsc_480i, drm_mode_analog_pal_576i),
|
|
};
|
|
|
|
static void
|
|
drm_connector_helper_tv_get_modes_desc(const struct drm_connector_helper_tv_get_modes_test *t,
|
|
char *desc)
|
|
{
|
|
sprintf(desc, "%s", t->name);
|
|
}
|
|
|
|
KUNIT_ARRAY_PARAM(drm_connector_helper_tv_get_modes,
|
|
drm_connector_helper_tv_get_modes_tests,
|
|
drm_connector_helper_tv_get_modes_desc);
|
|
|
|
static struct kunit_case drm_test_connector_helper_tv_get_modes_tests[] = {
|
|
KUNIT_CASE_PARAM(drm_test_connector_helper_tv_get_modes_check,
|
|
drm_connector_helper_tv_get_modes_gen_params),
|
|
{ }
|
|
};
|
|
|
|
static struct kunit_suite drm_test_connector_helper_tv_get_modes_suite = {
|
|
.name = "drm_connector_helper_tv_get_modes",
|
|
.init = drm_probe_helper_test_init,
|
|
.exit = drm_probe_helper_test_exit,
|
|
.test_cases = drm_test_connector_helper_tv_get_modes_tests,
|
|
};
|
|
|
|
kunit_test_suite(drm_test_connector_helper_tv_get_modes_suite);
|
|
|
|
MODULE_AUTHOR("Maxime Ripard <maxime@cerno.tech>");
|
|
MODULE_LICENSE("GPL");
|