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