xref: /linux/drivers/gpu/drm/tests/drm_client_modeset_test.c (revision 7436a87db99d57196c49d10de35f41531993d5f1)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2022 Maxime Ripard <mripard@kernel.org>
4  */
5 
6 #include <kunit/test.h>
7 
8 #include <drm/drm_atomic_state_helper.h>
9 #include <drm/drm_connector.h>
10 #include <drm/drm_edid.h>
11 #include <drm/drm_drv.h>
12 #include <drm/drm_kunit_helpers.h>
13 #include <drm/drm_modes.h>
14 #include <drm/drm_modeset_helper_vtables.h>
15 #include <drm/drm_probe_helper.h>
16 
17 struct drm_client_modeset_test_priv {
18 	struct drm_device *drm;
19 	struct device *dev;
20 	struct drm_connector connector;
21 };
22 
23 static int drm_client_modeset_connector_get_modes(struct drm_connector *connector)
24 {
25 	struct drm_display_mode *mode;
26 	int count;
27 
28 	count = drm_add_modes_noedid(connector, 1920, 1200);
29 
30 	mode = drm_mode_analog_ntsc_480i(connector->dev);
31 	if (!mode)
32 		return count;
33 
34 	drm_mode_probed_add(connector, mode);
35 	count += 1;
36 
37 	mode = drm_mode_analog_pal_576i(connector->dev);
38 	if (!mode)
39 		return count;
40 
41 	drm_mode_probed_add(connector, mode);
42 	count += 1;
43 
44 	return count;
45 }
46 
47 static const struct drm_connector_helper_funcs drm_client_modeset_connector_helper_funcs = {
48 	.get_modes = drm_client_modeset_connector_get_modes,
49 };
50 
51 static const struct drm_connector_funcs drm_client_modeset_connector_funcs = {
52 	.atomic_destroy_state   = drm_atomic_helper_connector_destroy_state,
53 	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state
54 };
55 
56 static int drm_client_modeset_test_init(struct kunit *test)
57 {
58 	struct drm_client_modeset_test_priv *priv;
59 	int ret;
60 
61 	priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
62 	KUNIT_ASSERT_NOT_NULL(test, priv);
63 
64 	test->priv = priv;
65 
66 	priv->dev = drm_kunit_helper_alloc_device(test);
67 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->dev);
68 
69 	priv->drm = __drm_kunit_helper_alloc_drm_device(test, priv->dev,
70 							sizeof(*priv->drm), 0,
71 							DRIVER_MODESET);
72 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->drm);
73 
74 	ret = drmm_connector_init(priv->drm, &priv->connector,
75 				  &drm_client_modeset_connector_funcs,
76 				  DRM_MODE_CONNECTOR_Unknown,
77 				  NULL);
78 	KUNIT_ASSERT_EQ(test, ret, 0);
79 
80 	drm_connector_helper_add(&priv->connector, &drm_client_modeset_connector_helper_funcs);
81 
82 	priv->connector.interlace_allowed = true;
83 	priv->connector.doublescan_allowed = true;
84 
85 	return 0;
86 }
87 
88 static void drm_test_pick_cmdline_res_1920_1080_60(struct kunit *test)
89 {
90 	struct drm_client_modeset_test_priv *priv = test->priv;
91 	struct drm_device *drm = priv->drm;
92 	struct drm_connector *connector = &priv->connector;
93 	struct drm_cmdline_mode *cmdline_mode = &connector->cmdline_mode;
94 	struct drm_display_mode *expected_mode;
95 	const struct drm_display_mode *mode;
96 	const char *cmdline = "1920x1080@60";
97 	int ret;
98 
99 	expected_mode = drm_mode_find_dmt(priv->drm, 1920, 1080, 60, false);
100 	KUNIT_ASSERT_NOT_NULL(test, expected_mode);
101 
102 	ret = drm_kunit_add_mode_destroy_action(test, expected_mode);
103 	KUNIT_ASSERT_EQ(test, ret, 0);
104 
105 	KUNIT_ASSERT_TRUE(test,
106 			  drm_mode_parse_command_line_for_connector(cmdline,
107 								    connector,
108 								    cmdline_mode));
109 
110 	mutex_lock(&drm->mode_config.mutex);
111 	ret = drm_helper_probe_single_connector_modes(connector, 1920, 1080);
112 	mutex_unlock(&drm->mode_config.mutex);
113 	KUNIT_ASSERT_GT(test, ret, 0);
114 
115 	mode = drm_connector_pick_cmdline_mode(connector);
116 	KUNIT_ASSERT_NOT_NULL(test, mode);
117 
118 	KUNIT_EXPECT_TRUE(test, drm_mode_equal(expected_mode, mode));
119 }
120 
121 struct drm_connector_pick_cmdline_mode_test {
122 	const char *cmdline;
123 	struct drm_display_mode *(*func)(struct drm_device *drm);
124 };
125 
126 #define TEST_CMDLINE(_cmdline, _fn)		\
127 	{					\
128 		.cmdline = _cmdline,		\
129 		.func = _fn,			\
130 	}
131 
132 static void drm_test_pick_cmdline_named(struct kunit *test)
133 {
134 	const struct drm_connector_pick_cmdline_mode_test *params = test->param_value;
135 	struct drm_client_modeset_test_priv *priv = test->priv;
136 	struct drm_device *drm = priv->drm;
137 	struct drm_connector *connector = &priv->connector;
138 	struct drm_cmdline_mode *cmdline_mode = &connector->cmdline_mode;
139 	const struct drm_display_mode *mode;
140 	struct drm_display_mode *expected_mode;
141 	const char *cmdline = params->cmdline;
142 	int ret;
143 
144 	KUNIT_ASSERT_TRUE(test,
145 			  drm_mode_parse_command_line_for_connector(cmdline,
146 								    connector,
147 								    cmdline_mode));
148 
149 	mutex_lock(&drm->mode_config.mutex);
150 	ret = drm_helper_probe_single_connector_modes(connector, 1920, 1080);
151 	mutex_unlock(&drm->mode_config.mutex);
152 	KUNIT_ASSERT_GT(test, ret, 0);
153 
154 	mode = drm_connector_pick_cmdline_mode(connector);
155 	KUNIT_ASSERT_NOT_NULL(test, mode);
156 
157 	expected_mode = params->func(drm);
158 	KUNIT_ASSERT_NOT_NULL(test, expected_mode);
159 
160 	ret = drm_kunit_add_mode_destroy_action(test, expected_mode);
161 	KUNIT_ASSERT_EQ(test, ret, 0);
162 
163 	KUNIT_EXPECT_TRUE(test, drm_mode_equal(expected_mode, mode));
164 }
165 
166 static const
167 struct drm_connector_pick_cmdline_mode_test drm_connector_pick_cmdline_mode_tests[] = {
168 	TEST_CMDLINE("NTSC", drm_mode_analog_ntsc_480i),
169 	TEST_CMDLINE("NTSC-J", drm_mode_analog_ntsc_480i),
170 	TEST_CMDLINE("PAL", drm_mode_analog_pal_576i),
171 	TEST_CMDLINE("PAL-M", drm_mode_analog_ntsc_480i),
172 };
173 
174 static void
175 drm_connector_pick_cmdline_mode_desc(const struct drm_connector_pick_cmdline_mode_test *t,
176 				     char *desc)
177 {
178 	sprintf(desc, "%s", t->cmdline);
179 }
180 
181 KUNIT_ARRAY_PARAM(drm_connector_pick_cmdline_mode,
182 		  drm_connector_pick_cmdline_mode_tests,
183 		  drm_connector_pick_cmdline_mode_desc);
184 
185 static struct kunit_case drm_test_pick_cmdline_tests[] = {
186 	KUNIT_CASE(drm_test_pick_cmdline_res_1920_1080_60),
187 	KUNIT_CASE_PARAM(drm_test_pick_cmdline_named,
188 			 drm_connector_pick_cmdline_mode_gen_params),
189 	{}
190 };
191 
192 static struct kunit_suite drm_test_pick_cmdline_test_suite = {
193 	.name = "drm_test_pick_cmdline",
194 	.init = drm_client_modeset_test_init,
195 	.test_cases = drm_test_pick_cmdline_tests
196 };
197 
198 kunit_test_suite(drm_test_pick_cmdline_test_suite);
199 
200 /*
201  * This file is included directly by drm_client_modeset.c so we can't
202  * use any MODULE_* macro here.
203  */
204