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