Merge tag 'drm-misc-next-2023-01-03' of git://anongit.freedesktop.org/drm/drm-misc into drm-next

drm-misc-next for v6.3:

UAPI Changes:

 * connector: Support analog-TV mode property
 * media: Add MEDIA_BUS_FMT_RGB565_1X24_CPADHI,
   MEDIA_BUS_FMT_RGB666_1X18 and MEDIA_BUS_FMT_RGB666_1X24_CPADHI

Cross-subsystem Changes:

 * dma-buf: Documentation fixes
 * i2c: Introduce i2c_client_get_device_id() helper

Core Changes:

 * Improve support for analog TV output
 * bridge: Remove unused drm_bridge_chain functions
 * debugfs: Add per-device helpers and convert various DRM drivers
 * dp-mst: Various fixes
 * fbdev emulation: Always pick 32 bpp as default
 * KUnit: Add tests for managed helpers; Various cleanups
 * panel-orientation: Add quirks for Lenovo Yoga Tab 3 X90F and DynaBook K50
 * TTM: Open-code ttm_bo_wait() and remove the helper

Driver Changes:

 * Fix preferred depth and bpp values throughout DRM drivers
 * Remove #CONFIG_PM guards throughout DRM drivers
 * ast: Various fixes
 * bridge: Implement i2c's probe_new in various drivers; Fixes; ite-it6505:
   Locking fixes, Cache EDID data; ite-it66121: Support IT6610 chip,
   Cleanups; lontium-tl9611: Fix HDMI on DragonBoard 845c; parade-ps8640:
   Use atomic bridge functions
 * gud: Convert to DRM shadow-plane helpers; Perform flushing synchronously
   during atomic update
 * ili9486: Support 16-bit pixel data
 * imx: Split off IPUv3 driver; Various fixes
 * mipi-dbi: Convert to DRM shadow-plane helpers plus rsp driver changes;i
   Support separate I/O-voltage supply
 * mxsfb: Depend on ARCH_MXS or ARCH_MXC
 * omapdrm: Various fixes
 * panel: Use ktime_get_boottime() to measure power-down delay in various
   drivers; Fix auto-suspend delay in various drivers; orisetech-ota5601a:
   Add support
 * sprd: Cleanups
 * sun4i: Convert to new TV-mode property
 * tidss: Various fixes
 * v3d: Various fixes
 * vc4: Convert to new TV-mode property; Support Kunit tests; Cleanups;
   dpi: Support RGB565 and RGB666 formats; dsi: Convert DSI driver to
   bridge
 * virtio: Improve tracing
 * vkms: Support small cursors in IGT tests; Various fixes

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
From: Thomas Zimmermann <tzimmermann@suse.de>
Link: https://patchwork.freedesktop.org/patch/msgid/Y7QIwlfElAYWxRcR@linux-uq9g
This commit is contained in:
Daniel Vetter
2023-01-04 14:59:24 +01:00
253 changed files with 6907 additions and 2517 deletions

View File

@@ -1,14 +1,20 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_DRM_KUNIT_TEST_HELPERS) += \
drm_kunit_helpers.o
obj-$(CONFIG_DRM_KUNIT_TEST) += \
drm_buddy_test.o \
drm_cmdline_parser_test.o \
drm_connector_test.o \
drm_damage_helper_test.o \
drm_dp_mst_helper_test.o \
drm_format_helper_test.o \
drm_format_test.o \
drm_framebuffer_test.o \
drm_kunit_helpers.o \
drm_managed_test.o \
drm_mm_test.o \
drm_modes_test.o \
drm_plane_helper_test.o \
drm_probe_helper_test.o \
drm_rect_test.o

View File

@@ -8,20 +8,39 @@
#include <drm/drm_connector.h>
#include <drm/drm_edid.h>
#include <drm/drm_drv.h>
#include <drm/drm_kunit_helpers.h>
#include <drm/drm_modes.h>
#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_probe_helper.h>
#include "drm_kunit_helpers.h"
struct drm_client_modeset_test_priv {
struct drm_device *drm;
struct device *dev;
struct drm_connector connector;
};
static int drm_client_modeset_connector_get_modes(struct drm_connector *connector)
{
return drm_add_modes_noedid(connector, 1920, 1200);
struct drm_display_mode *mode;
int count;
count = drm_add_modes_noedid(connector, 1920, 1200);
mode = drm_mode_analog_ntsc_480i(connector->dev);
if (!mode)
return count;
drm_mode_probed_add(connector, mode);
count += 1;
mode = drm_mode_analog_pal_576i(connector->dev);
if (!mode)
return count;
drm_mode_probed_add(connector, mode);
count += 1;
return count;
}
static const struct drm_connector_helper_funcs drm_client_modeset_connector_helper_funcs = {
@@ -41,7 +60,12 @@ static int drm_client_modeset_test_init(struct kunit *test)
test->priv = priv;
priv->drm = drm_kunit_device_init(test, DRIVER_MODESET, "drm-client-modeset-test");
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);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->drm);
ret = drmm_connector_init(priv->drm, &priv->connector,
@@ -52,9 +76,19 @@ static int drm_client_modeset_test_init(struct kunit *test)
drm_connector_helper_add(&priv->connector, &drm_client_modeset_connector_helper_funcs);
priv->connector.interlace_allowed = true;
priv->connector.doublescan_allowed = true;
return 0;
}
static void drm_client_modeset_test_exit(struct kunit *test)
{
struct drm_client_modeset_test_priv *priv = test->priv;
drm_kunit_helper_free_device(test, priv->dev);
}
static void drm_test_pick_cmdline_res_1920_1080_60(struct kunit *test)
{
struct drm_client_modeset_test_priv *priv = test->priv;
@@ -84,15 +118,83 @@ static void drm_test_pick_cmdline_res_1920_1080_60(struct kunit *test)
KUNIT_EXPECT_TRUE(test, drm_mode_equal(expected_mode, mode));
}
struct drm_connector_pick_cmdline_mode_test {
const char *cmdline;
struct drm_display_mode *(*func)(struct drm_device *drm);
};
#define TEST_CMDLINE(_cmdline, _fn) \
{ \
.cmdline = _cmdline, \
.func = _fn, \
}
static void drm_test_pick_cmdline_named(struct kunit *test)
{
const struct drm_connector_pick_cmdline_mode_test *params = test->param_value;
struct drm_client_modeset_test_priv *priv = test->priv;
struct drm_device *drm = priv->drm;
struct drm_connector *connector = &priv->connector;
struct drm_cmdline_mode *cmdline_mode = &connector->cmdline_mode;
const struct drm_display_mode *expected_mode, *mode;
const char *cmdline = params->cmdline;
int ret;
KUNIT_ASSERT_TRUE(test,
drm_mode_parse_command_line_for_connector(cmdline,
connector,
cmdline_mode));
mutex_lock(&drm->mode_config.mutex);
ret = drm_helper_probe_single_connector_modes(connector, 1920, 1080);
mutex_unlock(&drm->mode_config.mutex);
KUNIT_ASSERT_GT(test, ret, 0);
mode = drm_connector_pick_cmdline_mode(connector);
KUNIT_ASSERT_NOT_NULL(test, mode);
expected_mode = params->func(drm);
KUNIT_ASSERT_NOT_NULL(test, expected_mode);
KUNIT_EXPECT_TRUE(test, drm_mode_equal(expected_mode, mode));
}
static const
struct drm_connector_pick_cmdline_mode_test drm_connector_pick_cmdline_mode_tests[] = {
TEST_CMDLINE("NTSC", drm_mode_analog_ntsc_480i),
TEST_CMDLINE("NTSC-J", drm_mode_analog_ntsc_480i),
TEST_CMDLINE("PAL", drm_mode_analog_pal_576i),
TEST_CMDLINE("PAL-M", drm_mode_analog_ntsc_480i),
};
static void
drm_connector_pick_cmdline_mode_desc(const struct drm_connector_pick_cmdline_mode_test *t,
char *desc)
{
sprintf(desc, "%s", t->cmdline);
}
KUNIT_ARRAY_PARAM(drm_connector_pick_cmdline_mode,
drm_connector_pick_cmdline_mode_tests,
drm_connector_pick_cmdline_mode_desc);
static struct kunit_case drm_test_pick_cmdline_tests[] = {
KUNIT_CASE(drm_test_pick_cmdline_res_1920_1080_60),
KUNIT_CASE_PARAM(drm_test_pick_cmdline_named,
drm_connector_pick_cmdline_mode_gen_params),
{}
};
static struct kunit_suite drm_test_pick_cmdline_test_suite = {
.name = "drm_test_pick_cmdline",
.init = drm_client_modeset_test_init,
.exit = drm_client_modeset_test_exit,
.test_cases = drm_test_pick_cmdline_tests
};
kunit_test_suite(drm_test_pick_cmdline_test_suite);
/*
* This file is included directly by drm_client_modeset.c so we can't
* use any MODULE_* macro here.
*/

View File

@@ -927,6 +927,14 @@ static const struct drm_cmdline_invalid_test drm_cmdline_invalid_tests[] = {
.name = "invalid_option",
.cmdline = "720x480,test=42",
},
{
.name = "invalid_tv_option",
.cmdline = "720x480i,tv_mode=invalid",
},
{
.name = "truncated_tv_option",
.cmdline = "720x480i,tv_mode=NTS",
},
};
static void drm_cmdline_invalid_desc(const struct drm_cmdline_invalid_test *t,
@@ -937,6 +945,65 @@ static void drm_cmdline_invalid_desc(const struct drm_cmdline_invalid_test *t,
KUNIT_ARRAY_PARAM(drm_cmdline_invalid, drm_cmdline_invalid_tests, drm_cmdline_invalid_desc);
struct drm_cmdline_tv_option_test {
const char *name;
const char *cmdline;
struct drm_display_mode *(*mode_fn)(struct drm_device *dev);
enum drm_connector_tv_mode tv_mode;
};
static void drm_test_cmdline_tv_options(struct kunit *test)
{
const struct drm_cmdline_tv_option_test *params = test->param_value;
const struct drm_display_mode *expected_mode = params->mode_fn(NULL);
struct drm_cmdline_mode mode = { };
KUNIT_EXPECT_TRUE(test, drm_mode_parse_command_line_for_connector(params->cmdline,
&no_connector, &mode));
KUNIT_EXPECT_TRUE(test, mode.specified);
KUNIT_EXPECT_EQ(test, mode.xres, expected_mode->hdisplay);
KUNIT_EXPECT_EQ(test, mode.yres, expected_mode->vdisplay);
KUNIT_EXPECT_EQ(test, mode.tv_mode, params->tv_mode);
KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
KUNIT_EXPECT_FALSE(test, mode.bpp_specified);
KUNIT_EXPECT_FALSE(test, mode.rb);
KUNIT_EXPECT_FALSE(test, mode.cvt);
KUNIT_EXPECT_EQ(test, mode.interlace, !!(expected_mode->flags & DRM_MODE_FLAG_INTERLACE));
KUNIT_EXPECT_FALSE(test, mode.margins);
KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED);
}
#define TV_OPT_TEST(_opt, _cmdline, _mode_fn) \
{ \
.name = #_opt, \
.cmdline = _cmdline, \
.mode_fn = _mode_fn, \
.tv_mode = DRM_MODE_TV_MODE_ ## _opt, \
}
static const struct drm_cmdline_tv_option_test drm_cmdline_tv_option_tests[] = {
TV_OPT_TEST(NTSC, "720x480i,tv_mode=NTSC", drm_mode_analog_ntsc_480i),
TV_OPT_TEST(NTSC_443, "720x480i,tv_mode=NTSC-443", drm_mode_analog_ntsc_480i),
TV_OPT_TEST(NTSC_J, "720x480i,tv_mode=NTSC-J", drm_mode_analog_ntsc_480i),
TV_OPT_TEST(PAL, "720x576i,tv_mode=PAL", drm_mode_analog_pal_576i),
TV_OPT_TEST(PAL_M, "720x480i,tv_mode=PAL-M", drm_mode_analog_ntsc_480i),
TV_OPT_TEST(PAL_N, "720x576i,tv_mode=PAL-N", drm_mode_analog_pal_576i),
TV_OPT_TEST(SECAM, "720x576i,tv_mode=SECAM", drm_mode_analog_pal_576i),
};
static void drm_cmdline_tv_option_desc(const struct drm_cmdline_tv_option_test *t,
char *desc)
{
sprintf(desc, "%s", t->name);
}
KUNIT_ARRAY_PARAM(drm_cmdline_tv_option,
drm_cmdline_tv_option_tests,
drm_cmdline_tv_option_desc);
static struct kunit_case drm_cmdline_parser_tests[] = {
KUNIT_CASE(drm_test_cmdline_force_d_only),
KUNIT_CASE(drm_test_cmdline_force_D_only_dvi),
@@ -977,6 +1044,7 @@ static struct kunit_case drm_cmdline_parser_tests[] = {
KUNIT_CASE(drm_test_cmdline_freestanding_force_e_and_options),
KUNIT_CASE(drm_test_cmdline_panel_orientation),
KUNIT_CASE_PARAM(drm_test_cmdline_invalid, drm_cmdline_invalid_gen_params),
KUNIT_CASE_PARAM(drm_test_cmdline_tv_options, drm_cmdline_tv_option_gen_params),
{}
};

View File

@@ -0,0 +1,76 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Kunit test for drm_modes functions
*/
#include <drm/drm_connector.h>
#include <kunit/test.h>
struct drm_get_tv_mode_from_name_test {
const char *name;
enum drm_connector_tv_mode expected_mode;
};
#define TV_MODE_NAME(_name, _mode) \
{ \
.name = _name, \
.expected_mode = _mode, \
}
static void drm_test_get_tv_mode_from_name_valid(struct kunit *test)
{
const struct drm_get_tv_mode_from_name_test *params = test->param_value;
KUNIT_EXPECT_EQ(test,
drm_get_tv_mode_from_name(params->name, strlen(params->name)),
params->expected_mode);
}
static const
struct drm_get_tv_mode_from_name_test drm_get_tv_mode_from_name_valid_tests[] = {
TV_MODE_NAME("NTSC", DRM_MODE_TV_MODE_NTSC),
TV_MODE_NAME("NTSC-443", DRM_MODE_TV_MODE_NTSC_443),
TV_MODE_NAME("NTSC-J", DRM_MODE_TV_MODE_NTSC_J),
TV_MODE_NAME("PAL", DRM_MODE_TV_MODE_PAL),
TV_MODE_NAME("PAL-M", DRM_MODE_TV_MODE_PAL_M),
TV_MODE_NAME("PAL-N", DRM_MODE_TV_MODE_PAL_N),
TV_MODE_NAME("SECAM", DRM_MODE_TV_MODE_SECAM),
};
static void
drm_get_tv_mode_from_name_valid_desc(const struct drm_get_tv_mode_from_name_test *t,
char *desc)
{
sprintf(desc, "%s", t->name);
}
KUNIT_ARRAY_PARAM(drm_get_tv_mode_from_name_valid,
drm_get_tv_mode_from_name_valid_tests,
drm_get_tv_mode_from_name_valid_desc);
static void drm_test_get_tv_mode_from_name_truncated(struct kunit *test)
{
const char *name = "NTS";
int ret;
ret = drm_get_tv_mode_from_name(name, strlen(name));
KUNIT_EXPECT_LT(test, ret, 0);
};
static struct kunit_case drm_get_tv_mode_from_name_tests[] = {
KUNIT_CASE_PARAM(drm_test_get_tv_mode_from_name_valid,
drm_get_tv_mode_from_name_valid_gen_params),
KUNIT_CASE(drm_test_get_tv_mode_from_name_truncated),
{ }
};
static struct kunit_suite drm_get_tv_mode_from_name_test_suite = {
.name = "drm_get_tv_mode_from_name",
.test_cases = drm_get_tv_mode_from_name_tests,
};
kunit_test_suite(drm_get_tv_mode_from_name_test_suite);
MODULE_AUTHOR("Maxime Ripard <maxime@cerno.tech>");
MODULE_LICENSE("GPL");

View File

@@ -1,63 +1,101 @@
// SPDX-License-Identifier: GPL-2.0
#include <drm/drm_drv.h>
#include <drm/drm_kunit_helpers.h>
#include <drm/drm_managed.h>
#include <kunit/resource.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include "drm_kunit_helpers.h"
struct kunit_dev {
struct drm_device base;
};
#define KUNIT_DEVICE_NAME "drm-kunit-mock-device"
static const struct drm_mode_config_funcs drm_mode_config_funcs = {
};
static int dev_init(struct kunit_resource *res, void *ptr)
static int fake_probe(struct platform_device *pdev)
{
char *name = ptr;
struct device *dev;
dev = root_device_register(name);
if (IS_ERR(dev))
return PTR_ERR(dev);
res->data = dev;
return 0;
}
static void dev_free(struct kunit_resource *res)
static int fake_remove(struct platform_device *pdev)
{
struct device *dev = res->data;
root_device_unregister(dev);
return 0;
}
struct drm_device *drm_kunit_device_init(struct kunit *test, u32 features, char *name)
static struct platform_driver fake_platform_driver = {
.probe = fake_probe,
.remove = fake_remove,
.driver = {
.name = KUNIT_DEVICE_NAME,
},
};
/**
* drm_kunit_helper_alloc_device - Allocate a mock device for a KUnit test
* @test: The test context object
*
* This allocates a fake struct &device to create a mock for a KUnit
* test. The device will also be bound to a fake driver. It will thus be
* able to leverage the usual infrastructure and most notably the
* device-managed resources just like a "real" device.
*
* Callers need to make sure drm_kunit_helper_free_device() on the
* device when done.
*
* Returns:
* A pointer to the new device, or an ERR_PTR() otherwise.
*/
struct device *drm_kunit_helper_alloc_device(struct kunit *test)
{
struct kunit_dev *kdev;
struct drm_device *drm;
struct drm_driver *driver;
struct device *dev;
struct platform_device *pdev;
int ret;
dev = kunit_alloc_resource(test, dev_init, dev_free, GFP_KERNEL, name);
if (!dev)
return ERR_PTR(-ENOMEM);
ret = platform_driver_register(&fake_platform_driver);
KUNIT_ASSERT_EQ(test, ret, 0);
driver = kunit_kzalloc(test, sizeof(*driver), GFP_KERNEL);
if (!driver)
return ERR_PTR(-ENOMEM);
pdev = platform_device_alloc(KUNIT_DEVICE_NAME, PLATFORM_DEVID_NONE);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev);
driver->driver_features = features;
kdev = devm_drm_dev_alloc(dev, driver, struct kunit_dev, base);
if (IS_ERR(kdev))
return ERR_CAST(kdev);
ret = platform_device_add(pdev);
KUNIT_ASSERT_EQ(test, ret, 0);
drm = &kdev->base;
return &pdev->dev;
}
EXPORT_SYMBOL_GPL(drm_kunit_helper_alloc_device);
/**
* drm_kunit_helper_free_device - Frees a mock device
* @test: The test context object
* @dev: The device to free
*
* Frees a device allocated with drm_kunit_helper_alloc_device().
*/
void drm_kunit_helper_free_device(struct kunit *test, struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
platform_device_unregister(pdev);
platform_driver_unregister(&fake_platform_driver);
}
EXPORT_SYMBOL_GPL(drm_kunit_helper_free_device);
struct drm_device *
__drm_kunit_helper_alloc_drm_device_with_driver(struct kunit *test,
struct device *dev,
size_t size, size_t offset,
const struct drm_driver *driver)
{
struct drm_device *drm;
void *container;
int ret;
container = __devm_drm_dev_alloc(dev, driver, size, offset);
if (IS_ERR(container))
return ERR_CAST(container);
drm = container + offset;
drm->mode_config.funcs = &drm_mode_config_funcs;
ret = drmm_mode_config_init(drm);
@@ -66,6 +104,7 @@ struct drm_device *drm_kunit_device_init(struct kunit *test, u32 features, char
return drm;
}
EXPORT_SYMBOL_GPL(__drm_kunit_helper_alloc_drm_device_with_driver);
MODULE_AUTHOR("Maxime Ripard <maxime@cerno.tech>");
MODULE_LICENSE("GPL");

View File

@@ -1,11 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
#ifndef DRM_KUNIT_HELPERS_H_
#define DRM_KUNIT_HELPERS_H_
struct drm_device;
struct kunit;
struct drm_device *drm_kunit_device_init(struct kunit *test, u32 features, char *name);
#endif // DRM_KUNIT_HELPERS_H_

View File

@@ -0,0 +1,71 @@
// SPDX-License-Identifier: GPL-2.0
#include <drm/drm_drv.h>
#include <drm/drm_kunit_helpers.h>
#include <drm/drm_managed.h>
#include <kunit/resource.h>
#include <linux/device.h>
/* Ought to be enough for anybody */
#define TEST_TIMEOUT_MS 100
struct managed_test_priv {
bool action_done;
wait_queue_head_t action_wq;
};
static void drm_action(struct drm_device *drm, void *ptr)
{
struct managed_test_priv *priv = ptr;
priv->action_done = true;
wake_up_interruptible(&priv->action_wq);
}
static void drm_test_managed_run_action(struct kunit *test)
{
struct managed_test_priv *priv;
struct drm_device *drm;
struct device *dev;
int ret;
priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
init_waitqueue_head(&priv->action_wq);
dev = drm_kunit_helper_alloc_device(test);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
drm = __drm_kunit_helper_alloc_drm_device(test, dev, sizeof(*drm), 0, DRIVER_MODESET);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, drm);
ret = drmm_add_action_or_reset(drm, drm_action, priv);
KUNIT_EXPECT_EQ(test, ret, 0);
ret = drm_dev_register(drm, 0);
KUNIT_ASSERT_EQ(test, ret, 0);
drm_dev_unregister(drm);
drm_kunit_helper_free_device(test, dev);
ret = wait_event_interruptible_timeout(priv->action_wq, priv->action_done,
msecs_to_jiffies(TEST_TIMEOUT_MS));
KUNIT_EXPECT_GT(test, ret, 0);
}
static struct kunit_case drm_managed_tests[] = {
KUNIT_CASE(drm_test_managed_run_action),
{}
};
static struct kunit_suite drm_managed_test_suite = {
.name = "drm-test-managed",
.test_cases = drm_managed_tests
};
kunit_test_suite(drm_managed_test_suite);
MODULE_AUTHOR("Maxime Ripard <maxime@cerno.tech>");
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,158 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Kunit test for drm_modes functions
*/
#include <drm/drm_drv.h>
#include <drm/drm_kunit_helpers.h>
#include <drm/drm_modes.h>
#include <kunit/test.h>
#include <linux/units.h>
struct drm_test_modes_priv {
struct drm_device *drm;
struct device *dev;
};
static int drm_test_modes_init(struct kunit *test)
{
struct drm_test_modes_priv *priv;
priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, 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);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->drm);
test->priv = priv;
return 0;
}
static void drm_test_modes_exit(struct kunit *test)
{
struct drm_test_modes_priv *priv = test->priv;
drm_kunit_helper_free_device(test, priv->dev);
}
static void drm_test_modes_analog_tv_ntsc_480i(struct kunit *test)
{
struct drm_test_modes_priv *priv = test->priv;
struct drm_display_mode *mode;
mode = drm_analog_tv_mode(priv->drm,
DRM_MODE_TV_MODE_NTSC,
13500 * HZ_PER_KHZ, 720, 480,
true);
KUNIT_ASSERT_NOT_NULL(test, mode);
KUNIT_EXPECT_EQ(test, drm_mode_vrefresh(mode), 60);
KUNIT_EXPECT_EQ(test, mode->hdisplay, 720);
/* BT.601 defines hsync_start at 736 for 480i */
KUNIT_EXPECT_EQ(test, mode->hsync_start, 736);
/*
* The NTSC standard expects a line to take 63.556us. With a
* pixel clock of 13.5 MHz, a pixel takes around 74ns, so we
* need to have 63556ns / 74ns = 858.
*
* This is also mandated by BT.601.
*/
KUNIT_EXPECT_EQ(test, mode->htotal, 858);
KUNIT_EXPECT_EQ(test, mode->vdisplay, 480);
KUNIT_EXPECT_EQ(test, mode->vtotal, 525);
}
static void drm_test_modes_analog_tv_ntsc_480i_inlined(struct kunit *test)
{
struct drm_test_modes_priv *priv = test->priv;
struct drm_display_mode *expected, *mode;
expected = drm_analog_tv_mode(priv->drm,
DRM_MODE_TV_MODE_NTSC,
13500 * HZ_PER_KHZ, 720, 480,
true);
KUNIT_ASSERT_NOT_NULL(test, expected);
mode = drm_mode_analog_ntsc_480i(priv->drm);
KUNIT_ASSERT_NOT_NULL(test, mode);
KUNIT_EXPECT_TRUE(test, drm_mode_equal(expected, mode));
}
static void drm_test_modes_analog_tv_pal_576i(struct kunit *test)
{
struct drm_test_modes_priv *priv = test->priv;
struct drm_display_mode *mode;
mode = drm_analog_tv_mode(priv->drm,
DRM_MODE_TV_MODE_PAL,
13500 * HZ_PER_KHZ, 720, 576,
true);
KUNIT_ASSERT_NOT_NULL(test, mode);
KUNIT_EXPECT_EQ(test, drm_mode_vrefresh(mode), 50);
KUNIT_EXPECT_EQ(test, mode->hdisplay, 720);
/* BT.601 defines hsync_start at 732 for 576i */
KUNIT_EXPECT_EQ(test, mode->hsync_start, 732);
/*
* The PAL standard expects a line to take 64us. With a pixel
* clock of 13.5 MHz, a pixel takes around 74ns, so we need to
* have 64000ns / 74ns = 864.
*
* This is also mandated by BT.601.
*/
KUNIT_EXPECT_EQ(test, mode->htotal, 864);
KUNIT_EXPECT_EQ(test, mode->vdisplay, 576);
KUNIT_EXPECT_EQ(test, mode->vtotal, 625);
}
static void drm_test_modes_analog_tv_pal_576i_inlined(struct kunit *test)
{
struct drm_test_modes_priv *priv = test->priv;
struct drm_display_mode *expected, *mode;
expected = drm_analog_tv_mode(priv->drm,
DRM_MODE_TV_MODE_PAL,
13500 * HZ_PER_KHZ, 720, 576,
true);
KUNIT_ASSERT_NOT_NULL(test, expected);
mode = drm_mode_analog_pal_576i(priv->drm);
KUNIT_ASSERT_NOT_NULL(test, mode);
KUNIT_EXPECT_TRUE(test, drm_mode_equal(expected, mode));
}
static struct kunit_case drm_modes_analog_tv_tests[] = {
KUNIT_CASE(drm_test_modes_analog_tv_ntsc_480i),
KUNIT_CASE(drm_test_modes_analog_tv_ntsc_480i_inlined),
KUNIT_CASE(drm_test_modes_analog_tv_pal_576i),
KUNIT_CASE(drm_test_modes_analog_tv_pal_576i_inlined),
{ }
};
static struct kunit_suite drm_modes_analog_tv_test_suite = {
.name = "drm_modes_analog_tv",
.init = drm_test_modes_init,
.exit = drm_test_modes_exit,
.test_cases = drm_modes_analog_tv_tests,
};
kunit_test_suite(drm_modes_analog_tv_test_suite);
MODULE_AUTHOR("Maxime Ripard <maxime@cerno.tech>");
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,218 @@
// 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");