Build a device from the default configuration with vkms_output_init(), its connector reading an EDID that declares 3D in its HDMI Vendor-Specific Data Block, and check that:
- the connector lists the stereo modes the EDID declares, frame packing, top-and-bottom and side by side (half), and no other; - the writeback connector accepts a buffer of the frame that holds both eyes and refuses other sizes, for each of these layouts and for a 2D mode. Export vkms_output_init() for KUnit and select the DRM KUnit helpers. Assisted-by: LLM Signed-off-by: Daniel Campos Ramos <[email protected]> --- drivers/gpu/drm/vkms/Kconfig | 1 + drivers/gpu/drm/vkms/tests/Makefile | 1 + drivers/gpu/drm/vkms/tests/vkms_stereo_test.c | 476 ++++++++++++++++++ drivers/gpu/drm/vkms/vkms_output.c | 2 + 4 files changed, 480 insertions(+) create mode 100644 drivers/gpu/drm/vkms/tests/vkms_stereo_test.c diff --git a/drivers/gpu/drm/vkms/Kconfig b/drivers/gpu/drm/vkms/Kconfig index 3977bbb99f..d0b7f772cc 100644 --- a/drivers/gpu/drm/vkms/Kconfig +++ b/drivers/gpu/drm/vkms/Kconfig @@ -19,6 +19,7 @@ config DRM_VKMS config DRM_VKMS_KUNIT_TEST tristate "KUnit tests for VKMS" if !KUNIT_ALL_TESTS depends on DRM_VKMS && KUNIT + select DRM_KUNIT_TEST_HELPERS default KUNIT_ALL_TESTS help This builds unit tests for VKMS. This option is not useful for diff --git a/drivers/gpu/drm/vkms/tests/Makefile b/drivers/gpu/drm/vkms/tests/Makefile index 92cfa7262b..cad869aa61 100644 --- a/drivers/gpu/drm/vkms/tests/Makefile +++ b/drivers/gpu/drm/vkms/tests/Makefile @@ -5,5 +5,6 @@ vkms-kunit-tests-y := \ vkms_format_test.o \ vkms_color_test.o \ vkms_configfs_test.o \ + vkms_stereo_test.o \ obj-$(CONFIG_DRM_VKMS_KUNIT_TEST) += vkms-kunit-tests.o diff --git a/drivers/gpu/drm/vkms/tests/vkms_stereo_test.c b/drivers/gpu/drm/vkms/tests/vkms_stereo_test.c new file mode 100644 index 0000000000..9229d5ae17 --- /dev/null +++ b/drivers/gpu/drm/vkms/tests/vkms_stereo_test.c @@ -0,0 +1,476 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include <kunit/test.h> + +#include <drm/drm_atomic.h> +#include <drm/drm_atomic_uapi.h> +#include <drm/drm_drv.h> +#include <drm/drm_fourcc.h> +#include <drm/drm_framebuffer.h> +#include <drm/drm_kunit_helpers.h> +#include <drm/drm_modeset_lock.h> +#include <drm/drm_probe_helper.h> +#include <drm/drm_writeback.h> + +#include "../vkms_config.h" +#include "../vkms_connector.h" +#include "../vkms_drv.h" + +MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING"); + +/* + * edid-decode (hex): + * + * 00 ff ff ff ff ff ff 00 31 d8 3d 00 00 00 00 00 + * 00 21 01 03 81 a0 5a 78 0a 00 00 00 00 00 00 00 + * 00 00 00 20 00 00 01 01 01 01 01 01 01 01 01 01 + * 01 01 01 01 01 01 02 3a 80 18 71 38 2d 40 58 2c + * 45 00 40 84 63 00 00 1e 00 00 00 fc 00 53 74 65 + * 72 65 6f 20 45 44 49 44 0a 20 00 00 00 fd 00 17 + * 4c 0f 8c 1e 00 0a 20 20 20 20 20 20 00 00 00 10 + * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 b4 + * + * 02 03 1d 81 46 10 04 20 13 1f 22 6e 03 0c 00 10 + * 00 00 3c 20 a0 04 01 00 06 50 e2 00 4a 00 00 00 + * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 7f + * + * ---------------- + * + * Block 0, Base EDID: + * EDID Structure Version & Revision: 1.3 + * Vendor & Product Identification: + * Manufacturer: LNX + * Model: 61 + * Made in: 2023 + * Basic Display Parameters & Features: + * Digital display + * DFP 1.x compatible TMDS + * Maximum image size: 160 cm x 90 cm + * Gamma: 2.20 + * RGB color display + * First detailed timing is the preferred timing + * Color Characteristics: + * Red : 0.0000, 0.0000 + * Green: 0.0000, 0.0000 + * Blue : 0.0000, 0.0000 + * White: 0.0000, 0.0000 + * Established Timings I & II: + * DMT 0x04: 640x480 59.940476 Hz 4:3 31.469 kHz 25.175000 MHz + * Standard Timings: none + * Detailed Timing Descriptors: + * DTD 1: 1920x1080 60.000000 Hz 16:9 67.500 kHz 148.500000 MHz (1600 mm x 900 mm) + * Hfront 88 Hsync 44 Hback 148 Hpol P + * Vfront 4 Vsync 5 Vback 36 Vpol P + * Display Product Name: 'Stereo EDID' + * Display Range Limits: + * Monitor ranges (GTF): 23-76 Hz V, 15-140 kHz H, max dotclock 300 MHz + * Dummy Descriptor: + * Extension blocks: 1 + * Checksum: 0xb4 + * + * ---------------- + * + * Block 1, CTA-861 Extension Block: + * Revision: 3 + * Underscans IT Video Formats by default + * Native detailed modes: 1 + * Video Data Block: + * VIC 16: 1920x1080 60.000000 Hz 16:9 67.500 kHz 148.500000 MHz + * VIC 4: 1280x720 60.000000 Hz 16:9 45.000 kHz 74.250000 MHz + * VIC 32: 1920x1080 24.000000 Hz 16:9 27.000 kHz 74.250000 MHz + * VIC 19: 1280x720 50.000000 Hz 16:9 37.500 kHz 74.250000 MHz + * VIC 31: 1920x1080 50.000000 Hz 16:9 56.250 kHz 148.500000 MHz + * VIC 34: 1920x1080 30.000000 Hz 16:9 33.750 kHz 74.250000 MHz + * Vendor-Specific Data Block (HDMI), OUI 00-0C-03: + * Source physical address: 1.0.0.0 + * Maximum TMDS clock: 300 MHz + * Extended HDMI video details: + * 3D present + * All advertised VICs are 3D-capable + * 3D: Side-by-side (half, horizontal) + * 3D VIC indices with specific capabilities: + * VIC 16: 1920x1080 60.000000 Hz 16:9 67.500 kHz 148.500000 MHz (top-and-bottom) + * VIC 34: 1920x1080 30.000000 Hz 16:9 33.750 kHz 74.250000 MHz (frame packing) + * Video Capability Data Block: + * YCbCr quantization: No Data + * RGB quantization: Selectable (via AVI Q) + * PT scan behavior: No Data + * IT scan behavior: Always Underscanned + * CE scan behavior: Always Underscanned + * Checksum: 0x7f + */ +static const u8 test_edid_hdmi_3d[] = { + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x31, 0xd8, 0x3d, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x01, 0x03, 0x81, 0xa0, 0x5a, 0x78, + 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3a, 0x80, 0x18, 0x71, 0x38, + 0x2d, 0x40, 0x58, 0x2c, 0x45, 0x00, 0x40, 0x84, 0x63, 0x00, 0x00, 0x1e, + 0x00, 0x00, 0x00, 0xfc, 0x00, 0x53, 0x74, 0x65, 0x72, 0x65, 0x6f, 0x20, + 0x45, 0x44, 0x49, 0x44, 0x0a, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x17, + 0x4c, 0x0f, 0x8c, 0x1e, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xb4, 0x02, 0x03, 0x1d, 0x81, + 0x46, 0x10, 0x04, 0x20, 0x13, 0x1f, 0x22, 0x6e, 0x03, 0x0c, 0x00, 0x10, + 0x00, 0x00, 0x3c, 0x20, 0xa0, 0x04, 0x01, 0x00, 0x06, 0x50, 0xe2, 0x00, + 0x4a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7f, +}; + +struct vkms_stereo_test_priv { + struct vkms_device *vkmsdev; + struct drm_connector *connector; + struct drm_writeback_connector *wb_connector; + struct drm_crtc *crtc; + struct drm_plane *primary; +}; + +struct vkms_stereo_test_mode { + int hdisplay; + int vdisplay; + int vrefresh; + u32 layout; +}; + +/* The stereo modes the EDID above declares, without the interlaced ones */ +static const struct vkms_stereo_test_mode test_edid_stereo_modes[] = { + /* 3D_present: the mandatory formats of the 2D formats listed */ + { 1920, 1080, 24, DRM_MODE_FLAG_3D_FRAME_PACKING }, + { 1920, 1080, 24, DRM_MODE_FLAG_3D_TOP_AND_BOTTOM }, + { 1280, 720, 60, DRM_MODE_FLAG_3D_FRAME_PACKING }, + { 1280, 720, 60, DRM_MODE_FLAG_3D_TOP_AND_BOTTOM }, + { 1280, 720, 50, DRM_MODE_FLAG_3D_FRAME_PACKING }, + { 1280, 720, 50, DRM_MODE_FLAG_3D_TOP_AND_BOTTOM }, + /* 3D_Structure_ALL: side by side (half) for every VIC */ + { 1920, 1080, 60, DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF }, + { 1280, 720, 60, DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF }, + { 1920, 1080, 24, DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF }, + { 1280, 720, 50, DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF }, + { 1920, 1080, 50, DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF }, + { 1920, 1080, 30, DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF }, + /* 3D_Structure_X */ + { 1920, 1080, 60, DRM_MODE_FLAG_3D_TOP_AND_BOTTOM }, + { 1920, 1080, 30, DRM_MODE_FLAG_3D_FRAME_PACKING }, +}; + +static void vkms_stereo_test_config_destroy(void *config) +{ + vkms_config_destroy(config); +} + +static void vkms_stereo_test_fb_destroy(struct drm_framebuffer *fb) +{ + drm_framebuffer_cleanup(fb); +} + +static const struct drm_framebuffer_funcs vkms_stereo_test_fb_funcs = { + .destroy = vkms_stereo_test_fb_destroy, +}; + +static void vkms_stereo_test_fb_put(void *fb) +{ + drm_framebuffer_put(fb); +} + +static struct drm_framebuffer *vkms_stereo_test_create_fb(struct kunit *test, + int width, int height) +{ + struct vkms_stereo_test_priv *priv = test->priv; + struct drm_framebuffer *fb; + int ret; + + fb = kunit_kzalloc(test, sizeof(*fb), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, fb); + + fb->dev = &priv->vkmsdev->drm; + fb->format = drm_format_info(DRM_FORMAT_XRGB8888); + fb->width = width; + fb->height = height; + fb->pitches[0] = width * 4; + + ret = drm_framebuffer_init(fb->dev, fb, &vkms_stereo_test_fb_funcs); + KUNIT_ASSERT_EQ(test, ret, 0); + + ret = kunit_add_action_or_reset(test, vkms_stereo_test_fb_put, fb); + KUNIT_ASSERT_EQ(test, ret, 0); + + return fb; +} + +static int vkms_stereo_test_init(struct kunit *test) +{ + struct vkms_stereo_test_priv *priv; + struct vkms_config_connector *connector_cfg; + struct vkms_config_plane *plane_cfg; + struct vkms_config_crtc *crtc_cfg; + struct vkms_config *config; + struct device *dev; + int ret; + + priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, priv); + test->priv = priv; + + config = vkms_config_default_create(false, true, false, false); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, config); + ret = kunit_add_action_or_reset(test, vkms_stereo_test_config_destroy, config); + KUNIT_ASSERT_EQ(test, ret, 0); + + vkms_config_for_each_connector(config, connector_cfg) { + vkms_config_connector_set_edid_enabled(connector_cfg, true); + vkms_config_connector_set_edid(connector_cfg, test_edid_hdmi_3d, + sizeof(test_edid_hdmi_3d)); + } + + dev = drm_kunit_helper_alloc_device(test); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev); + + priv->vkmsdev = drm_kunit_helper_alloc_drm_device(test, dev, struct vkms_device, drm, + DRIVER_MODESET | DRIVER_ATOMIC); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->vkmsdev); + + priv->vkmsdev->config = config; + config->dev = priv->vkmsdev; + + ret = vkms_output_init(priv->vkmsdev); + KUNIT_ASSERT_EQ(test, ret, 0); + + vkms_config_for_each_crtc(config, crtc_cfg) { + priv->crtc = &crtc_cfg->crtc->crtc; + priv->wb_connector = &crtc_cfg->crtc->wb_connector; + plane_cfg = vkms_config_crtc_primary_plane(config, crtc_cfg); + priv->primary = &plane_cfg->plane->base; + } + + vkms_config_for_each_connector(config, connector_cfg) + priv->connector = &connector_cfg->connector->base; + + return 0; +} + +static void vkms_stereo_test_probe(struct kunit *test) +{ + struct vkms_stereo_test_priv *priv = test->priv; + struct drm_device *drm = &priv->vkmsdev->drm; + int count; + + mutex_lock(&drm->mode_config.mutex); + count = drm_helper_probe_single_connector_modes(priv->connector, XRES_MAX, YRES_MAX); + mutex_unlock(&drm->mode_config.mutex); + + KUNIT_ASSERT_GT(test, count, 0); +} + +static bool vkms_stereo_test_mode_matches(const struct drm_display_mode *mode, + const struct vkms_stereo_test_mode *expected) +{ + return mode->hdisplay == expected->hdisplay && + mode->vdisplay == expected->vdisplay && + drm_mode_vrefresh(mode) == expected->vrefresh && + (mode->flags & DRM_MODE_FLAG_3D_MASK) == expected->layout; +} + +static const struct drm_display_mode * +vkms_stereo_test_find_mode(struct kunit *test, const struct vkms_stereo_test_mode *expected) +{ + struct vkms_stereo_test_priv *priv = test->priv; + const struct drm_display_mode *mode; + + list_for_each_entry(mode, &priv->connector->modes, head) { + if (vkms_stereo_test_mode_matches(mode, expected)) + return mode; + } + + return NULL; +} + +/* + * The connector lists the stereo modes of its EDID next to the 2D ones, and + * no other stereo mode. Formats at 24, 30 and 60 Hz are listed twice, at + * the integer rate and at 1000/1001 of it, both covered by one entry. + */ +static void vkms_stereo_test_edid_modes(struct kunit *test) +{ + static const struct vkms_stereo_test_mode mode_2d = { 1920, 1080, 60, 0 }; + struct vkms_stereo_test_priv *priv = test->priv; + const struct drm_display_mode *mode; + int i; + + vkms_stereo_test_probe(test); + + for (i = 0; i < ARRAY_SIZE(test_edid_stereo_modes); i++) { + const struct vkms_stereo_test_mode *expected = &test_edid_stereo_modes[i]; + + KUNIT_EXPECT_NOT_NULL_MSG(test, vkms_stereo_test_find_mode(test, expected), + "%dx%d@%d layout %u not listed", + expected->hdisplay, expected->vdisplay, + expected->vrefresh, expected->layout >> 14); + } + + list_for_each_entry(mode, &priv->connector->modes, head) { + bool expected = false; + + if (!(mode->flags & DRM_MODE_FLAG_3D_MASK)) + continue; + + for (i = 0; i < ARRAY_SIZE(test_edid_stereo_modes); i++) + expected |= vkms_stereo_test_mode_matches(mode, &test_edid_stereo_modes[i]); + + KUNIT_EXPECT_TRUE_MSG(test, expected, "unexpected " DRM_MODE_FMT, + DRM_MODE_ARG(mode)); + } + + KUNIT_EXPECT_NOT_NULL(test, vkms_stereo_test_find_mode(test, &mode_2d)); +} + +struct vkms_stereo_test_frame_case { + const char *name; + struct vkms_stereo_test_mode mode; + int width; + int height; + int bad_width; + int bad_height; +}; + +/* + * The frame of a mode is the buffer that holds both eyes: frame packing + * adds vtotal lines (1080 + 1125 for these modes), the other layouts keep + * the size of the mode. Each case also names a writeback buffer size that + * must be refused. + */ +static const struct vkms_stereo_test_frame_case vkms_stereo_test_frame_cases[] = { + { "2d", { 1920, 1080, 60, 0 }, 1920, 1080, 1920, 2205 }, + { "frame-packing", { 1920, 1080, 30, DRM_MODE_FLAG_3D_FRAME_PACKING }, + 1920, 2205, 1920, 1080 }, + { "top-and-bottom", { 1920, 1080, 60, DRM_MODE_FLAG_3D_TOP_AND_BOTTOM }, + 1920, 1080, 1920, 2205 }, + { "side-by-side-half", { 1920, 1080, 60, DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF }, + 1920, 1080, 3840, 1080 }, +}; + +static void vkms_stereo_test_frame_case_desc(const struct vkms_stereo_test_frame_case *t, + char *desc) +{ + strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE); +} + +KUNIT_ARRAY_PARAM(vkms_stereo_test_frame, vkms_stereo_test_frame_cases, + vkms_stereo_test_frame_case_desc); + +/* + * Checks an update showing a primary plane of the frame size and writing + * the composed frame back to a buffer of wb_width x wb_height. + */ +static int vkms_stereo_test_check_update(struct kunit *test, + const struct drm_display_mode *mode, + int width, int height, + int wb_width, int wb_height) +{ + struct vkms_stereo_test_priv *priv = test->priv; + struct drm_device *drm = &priv->vkmsdev->drm; + struct drm_framebuffer *fb, *wb_fb; + struct drm_connector_state *conn_state, *wb_state; + struct drm_modeset_acquire_ctx ctx; + struct drm_plane_state *plane_state; + struct drm_crtc_state *crtc_state; + struct drm_atomic_commit *state; + int ret; + + fb = vkms_stereo_test_create_fb(test, width, height); + wb_fb = vkms_stereo_test_create_fb(test, wb_width, wb_height); + + drm_modeset_acquire_init(&ctx, 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, priv->crtc); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state); + ret = drm_atomic_set_mode_for_crtc(crtc_state, mode); + KUNIT_ASSERT_EQ(test, ret, 0); + crtc_state->enable = true; + crtc_state->active = true; + + conn_state = drm_atomic_get_connector_state(state, priv->connector); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state); + ret = drm_atomic_set_crtc_for_connector(conn_state, priv->crtc); + KUNIT_ASSERT_EQ(test, ret, 0); + + plane_state = drm_atomic_get_plane_state(state, priv->primary); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane_state); + ret = drm_atomic_set_crtc_for_plane(plane_state, priv->crtc); + KUNIT_ASSERT_EQ(test, ret, 0); + drm_atomic_set_fb_for_plane(plane_state, fb); + plane_state->crtc_w = width; + plane_state->crtc_h = height; + plane_state->src_w = width << 16; + plane_state->src_h = height << 16; + + wb_state = drm_atomic_get_connector_state(state, &priv->wb_connector->base); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, wb_state); + ret = drm_atomic_set_crtc_for_connector(wb_state, priv->crtc); + KUNIT_ASSERT_EQ(test, ret, 0); + ret = drm_writeback_set_fb(wb_state, wb_fb); + KUNIT_ASSERT_EQ(test, ret, 0); + + ret = drm_atomic_check_only(state); + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); + + return ret; +} + +/* + * The writeback connector takes a buffer of the frame size, so it receives + * both eyes, and refuses any other size. + */ +static void vkms_stereo_test_writeback_frame(struct kunit *test) +{ + const struct vkms_stereo_test_frame_case *t = test->param_value; + const struct drm_display_mode *mode; + int ret; + + vkms_stereo_test_probe(test); + + mode = vkms_stereo_test_find_mode(test, &t->mode); + KUNIT_ASSERT_NOT_NULL(test, mode); + + ret = vkms_stereo_test_check_update(test, mode, t->width, t->height, + t->width, t->height); + KUNIT_EXPECT_EQ(test, ret, 0); + + ret = vkms_stereo_test_check_update(test, mode, t->width, t->height, + t->bad_width, t->bad_height); + KUNIT_EXPECT_EQ(test, ret, -EINVAL); +} + +static struct kunit_case vkms_stereo_test_cases[] = { + KUNIT_CASE(vkms_stereo_test_edid_modes), + KUNIT_CASE_PARAM(vkms_stereo_test_writeback_frame, + vkms_stereo_test_frame_gen_params), + {} +}; + +static struct kunit_suite vkms_stereo_test_suite = { + .name = "vkms-stereo", + .init = vkms_stereo_test_init, + .test_cases = vkms_stereo_test_cases, +}; + +kunit_test_suite(vkms_stereo_test_suite); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Kunit test for vkms stereo modes"); diff --git a/drivers/gpu/drm/vkms/vkms_output.c b/drivers/gpu/drm/vkms/vkms_output.c index ad901340ba..b484255c43 100644 --- a/drivers/gpu/drm/vkms/vkms_output.c +++ b/drivers/gpu/drm/vkms/vkms_output.c @@ -5,6 +5,7 @@ #include "vkms_drv.h" #include <drm/drm_managed.h> #include <drm/drm_print.h> +#include <kunit/visibility.h> int vkms_output_init(struct vkms_device *vkmsdev) { @@ -130,3 +131,4 @@ int vkms_output_init(struct vkms_device *vkmsdev) return 0; } +EXPORT_SYMBOL_IF_KUNIT(vkms_output_init);
