1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Kunit test for drm_probe_helper functions 4 */ 5 6 #include <drm/drm_atomic_state_helper.h> 7 #include <drm/drm_connector.h> 8 #include <drm/drm_device.h> 9 #include <drm/drm_drv.h> 10 #include <drm/drm_kunit_helpers.h> 11 #include <drm/drm_mode.h> 12 #include <drm/drm_modes.h> 13 #include <drm/drm_modeset_helper_vtables.h> 14 #include <drm/drm_probe_helper.h> 15 16 #include <kunit/test.h> 17 18 struct drm_probe_helper_test_priv { 19 struct drm_device *drm; 20 struct drm_connector connector; 21 }; 22 23 static const struct drm_connector_helper_funcs drm_probe_helper_connector_helper_funcs = { 24 }; 25 26 static const struct drm_connector_funcs drm_probe_helper_connector_funcs = { 27 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, 28 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, 29 .reset = drm_atomic_helper_connector_reset, 30 }; 31 32 static int drm_probe_helper_test_init(struct kunit *test) 33 { 34 struct drm_probe_helper_test_priv *priv; 35 struct drm_connector *connector; 36 int ret; 37 38 priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL); 39 KUNIT_ASSERT_NOT_NULL(test, priv); 40 test->priv = priv; 41 42 priv->drm = drm_kunit_device_init(test, DRIVER_MODESET | DRIVER_ATOMIC, 43 "drm-probe-helper-test"); 44 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->drm); 45 46 connector = &priv->connector; 47 ret = drmm_connector_init(priv->drm, connector, 48 &drm_probe_helper_connector_funcs, 49 DRM_MODE_CONNECTOR_Unknown, 50 NULL); 51 KUNIT_ASSERT_EQ(test, ret, 0); 52 53 drm_connector_helper_add(connector, &drm_probe_helper_connector_helper_funcs); 54 55 return 0; 56 } 57 58 typedef struct drm_display_mode *(*expected_mode_func_t)(struct drm_device *); 59 60 struct drm_connector_helper_tv_get_modes_test { 61 const char *name; 62 unsigned int supported_tv_modes; 63 enum drm_connector_tv_mode default_mode; 64 bool cmdline; 65 enum drm_connector_tv_mode cmdline_mode; 66 expected_mode_func_t *expected_modes; 67 unsigned int num_expected_modes; 68 }; 69 70 #define _TV_MODE_TEST(_name, _supported, _default, _cmdline, _cmdline_mode, ...) \ 71 { \ 72 .name = _name, \ 73 .supported_tv_modes = _supported, \ 74 .default_mode = _default, \ 75 .cmdline = _cmdline, \ 76 .cmdline_mode = _cmdline_mode, \ 77 .expected_modes = (expected_mode_func_t[]) { __VA_ARGS__ }, \ 78 .num_expected_modes = sizeof((expected_mode_func_t[]) { __VA_ARGS__ }) / \ 79 (sizeof(expected_mode_func_t)), \ 80 } 81 82 #define TV_MODE_TEST(_name, _supported, _default, ...) \ 83 _TV_MODE_TEST(_name, _supported, _default, false, 0, __VA_ARGS__) 84 85 #define TV_MODE_TEST_CMDLINE(_name, _supported, _default, _cmdline, ...) \ 86 _TV_MODE_TEST(_name, _supported, _default, true, _cmdline, __VA_ARGS__) 87 88 static void 89 drm_test_connector_helper_tv_get_modes_check(struct kunit *test) 90 { 91 const struct drm_connector_helper_tv_get_modes_test *params = test->param_value; 92 struct drm_probe_helper_test_priv *priv = test->priv; 93 struct drm_connector *connector = &priv->connector; 94 struct drm_cmdline_mode *cmdline = &connector->cmdline_mode; 95 struct drm_display_mode *mode; 96 const struct drm_display_mode *expected; 97 size_t len; 98 int ret; 99 100 if (params->cmdline) { 101 cmdline->tv_mode_specified = true; 102 cmdline->tv_mode = params->cmdline_mode; 103 } 104 105 ret = drm_mode_create_tv_properties(priv->drm, params->supported_tv_modes); 106 KUNIT_ASSERT_EQ(test, ret, 0); 107 108 drm_object_attach_property(&connector->base, 109 priv->drm->mode_config.tv_mode_property, 110 params->default_mode); 111 112 mutex_lock(&priv->drm->mode_config.mutex); 113 114 ret = drm_connector_helper_tv_get_modes(connector); 115 KUNIT_EXPECT_EQ(test, ret, params->num_expected_modes); 116 117 len = 0; 118 list_for_each_entry(mode, &connector->probed_modes, head) 119 len++; 120 KUNIT_EXPECT_EQ(test, len, params->num_expected_modes); 121 122 if (params->num_expected_modes >= 1) { 123 mode = list_first_entry_or_null(&connector->probed_modes, 124 struct drm_display_mode, head); 125 KUNIT_ASSERT_NOT_NULL(test, mode); 126 127 expected = params->expected_modes[0](priv->drm); 128 KUNIT_ASSERT_NOT_NULL(test, expected); 129 130 KUNIT_EXPECT_TRUE(test, drm_mode_equal(mode, expected)); 131 KUNIT_EXPECT_TRUE(test, mode->type & DRM_MODE_TYPE_PREFERRED); 132 } 133 134 if (params->num_expected_modes >= 2) { 135 mode = list_next_entry(mode, head); 136 KUNIT_ASSERT_NOT_NULL(test, mode); 137 138 expected = params->expected_modes[1](priv->drm); 139 KUNIT_ASSERT_NOT_NULL(test, expected); 140 141 KUNIT_EXPECT_TRUE(test, drm_mode_equal(mode, expected)); 142 KUNIT_EXPECT_FALSE(test, mode->type & DRM_MODE_TYPE_PREFERRED); 143 } 144 145 mutex_unlock(&priv->drm->mode_config.mutex); 146 } 147 148 static const 149 struct drm_connector_helper_tv_get_modes_test drm_connector_helper_tv_get_modes_tests[] = { 150 { .name = "None" }, 151 TV_MODE_TEST("PAL", 152 BIT(DRM_MODE_TV_MODE_PAL), 153 DRM_MODE_TV_MODE_PAL, 154 drm_mode_analog_pal_576i), 155 TV_MODE_TEST("NTSC", 156 BIT(DRM_MODE_TV_MODE_NTSC), 157 DRM_MODE_TV_MODE_NTSC, 158 drm_mode_analog_ntsc_480i), 159 TV_MODE_TEST("Both, NTSC Default", 160 BIT(DRM_MODE_TV_MODE_NTSC) | BIT(DRM_MODE_TV_MODE_PAL), 161 DRM_MODE_TV_MODE_NTSC, 162 drm_mode_analog_ntsc_480i, drm_mode_analog_pal_576i), 163 TV_MODE_TEST("Both, PAL Default", 164 BIT(DRM_MODE_TV_MODE_NTSC) | BIT(DRM_MODE_TV_MODE_PAL), 165 DRM_MODE_TV_MODE_PAL, 166 drm_mode_analog_pal_576i, drm_mode_analog_ntsc_480i), 167 TV_MODE_TEST_CMDLINE("Both, NTSC Default, with PAL on command-line", 168 BIT(DRM_MODE_TV_MODE_NTSC) | BIT(DRM_MODE_TV_MODE_PAL), 169 DRM_MODE_TV_MODE_NTSC, 170 DRM_MODE_TV_MODE_PAL, 171 drm_mode_analog_pal_576i, drm_mode_analog_ntsc_480i), 172 TV_MODE_TEST_CMDLINE("Both, PAL Default, with NTSC on command-line", 173 BIT(DRM_MODE_TV_MODE_NTSC) | BIT(DRM_MODE_TV_MODE_PAL), 174 DRM_MODE_TV_MODE_PAL, 175 DRM_MODE_TV_MODE_NTSC, 176 drm_mode_analog_ntsc_480i, drm_mode_analog_pal_576i), 177 }; 178 179 static void 180 drm_connector_helper_tv_get_modes_desc(const struct drm_connector_helper_tv_get_modes_test *t, 181 char *desc) 182 { 183 sprintf(desc, "%s", t->name); 184 } 185 186 KUNIT_ARRAY_PARAM(drm_connector_helper_tv_get_modes, 187 drm_connector_helper_tv_get_modes_tests, 188 drm_connector_helper_tv_get_modes_desc); 189 190 static struct kunit_case drm_test_connector_helper_tv_get_modes_tests[] = { 191 KUNIT_CASE_PARAM(drm_test_connector_helper_tv_get_modes_check, 192 drm_connector_helper_tv_get_modes_gen_params), 193 { } 194 }; 195 196 static struct kunit_suite drm_test_connector_helper_tv_get_modes_suite = { 197 .name = "drm_connector_helper_tv_get_modes", 198 .init = drm_probe_helper_test_init, 199 .test_cases = drm_test_connector_helper_tv_get_modes_tests, 200 }; 201 202 kunit_test_suite(drm_test_connector_helper_tv_get_modes_suite); 203 204 MODULE_AUTHOR("Maxime Ripard <maxime@cerno.tech>"); 205 MODULE_LICENSE("GPL"); 206