GNU Linux-libre 4.19.245-gnu1
[releases.git] / drivers / gpu / drm / selftests / test-drm-helper.c
1 /*
2  * Test cases for the drm_kms_helper functions
3  */
4
5 #define pr_fmt(fmt) "drm_kms_helper: " fmt
6
7 #include <linux/module.h>
8
9 #include <drm/drm_atomic_helper.h>
10 #include <drm/drm_plane_helper.h>
11 #include <drm/drm_modes.h>
12
13 #define TESTS "drm_helper_selftests.h"
14 #include "drm_selftest.h"
15
16 #define FAIL(test, msg, ...) \
17         do { \
18                 if (test) { \
19                         pr_err("%s/%u: " msg, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
20                         return -EINVAL; \
21                 } \
22         } while (0)
23
24 #define FAIL_ON(x) FAIL((x), "%s", "FAIL_ON(" __stringify(x) ")\n")
25
26 static void set_src(struct drm_plane_state *plane_state,
27                     unsigned src_x, unsigned src_y,
28                     unsigned src_w, unsigned src_h)
29 {
30         plane_state->src_x = src_x;
31         plane_state->src_y = src_y;
32         plane_state->src_w = src_w;
33         plane_state->src_h = src_h;
34 }
35
36 static bool check_src_eq(struct drm_plane_state *plane_state,
37                          unsigned src_x, unsigned src_y,
38                          unsigned src_w, unsigned src_h)
39 {
40         if (plane_state->src.x1 < 0) {
41                 pr_err("src x coordinate %x should never be below 0.\n", plane_state->src.x1);
42                 drm_rect_debug_print("src: ", &plane_state->src, true);
43                 return false;
44         }
45         if (plane_state->src.y1 < 0) {
46                 pr_err("src y coordinate %x should never be below 0.\n", plane_state->src.y1);
47                 drm_rect_debug_print("src: ", &plane_state->src, true);
48                 return false;
49         }
50
51         if (plane_state->src.x1 != src_x ||
52             plane_state->src.y1 != src_y ||
53             drm_rect_width(&plane_state->src) != src_w ||
54             drm_rect_height(&plane_state->src) != src_h) {
55                 drm_rect_debug_print("src: ", &plane_state->src, true);
56                 return false;
57         }
58
59         return true;
60 }
61
62 static void set_crtc(struct drm_plane_state *plane_state,
63                      int crtc_x, int crtc_y,
64                      unsigned crtc_w, unsigned crtc_h)
65 {
66         plane_state->crtc_x = crtc_x;
67         plane_state->crtc_y = crtc_y;
68         plane_state->crtc_w = crtc_w;
69         plane_state->crtc_h = crtc_h;
70 }
71
72 static bool check_crtc_eq(struct drm_plane_state *plane_state,
73                           int crtc_x, int crtc_y,
74                           unsigned crtc_w, unsigned crtc_h)
75 {
76         if (plane_state->dst.x1 != crtc_x ||
77             plane_state->dst.y1 != crtc_y ||
78             drm_rect_width(&plane_state->dst) != crtc_w ||
79             drm_rect_height(&plane_state->dst) != crtc_h) {
80                 drm_rect_debug_print("dst: ", &plane_state->dst, false);
81
82                 return false;
83         }
84
85         return true;
86 }
87
88 static int igt_check_plane_state(void *ignored)
89 {
90         int ret;
91
92         const struct drm_crtc_state crtc_state = {
93                 .crtc = ZERO_SIZE_PTR,
94                 .enable = true,
95                 .active = true,
96                 .mode = {
97                         DRM_MODE("1024x768", 0, 65000, 1024, 1048,
98                                 1184, 1344, 0, 768, 771, 777, 806, 0,
99                                 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC)
100                 },
101         };
102         struct drm_framebuffer fb = {
103                 .width = 2048,
104                 .height = 2048
105         };
106         struct drm_plane_state plane_state = {
107                 .crtc = ZERO_SIZE_PTR,
108                 .fb = &fb,
109                 .rotation = DRM_MODE_ROTATE_0
110         };
111
112         /* Simple clipping, no scaling. */
113         set_src(&plane_state, 0, 0, fb.width << 16, fb.height << 16);
114         set_crtc(&plane_state, 0, 0, fb.width, fb.height);
115         ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
116                                                   DRM_PLANE_HELPER_NO_SCALING,
117                                                   DRM_PLANE_HELPER_NO_SCALING,
118                                                   false, false);
119         FAIL(ret < 0, "Simple clipping check should pass\n");
120         FAIL_ON(!plane_state.visible);
121         FAIL_ON(!check_src_eq(&plane_state, 0, 0, 1024 << 16, 768 << 16));
122         FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1024, 768));
123
124         /* Rotated clipping + reflection, no scaling. */
125         plane_state.rotation = DRM_MODE_ROTATE_90 | DRM_MODE_REFLECT_X;
126         ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
127                                                   DRM_PLANE_HELPER_NO_SCALING,
128                                                   DRM_PLANE_HELPER_NO_SCALING,
129                                                   false, false);
130         FAIL(ret < 0, "Rotated clipping check should pass\n");
131         FAIL_ON(!plane_state.visible);
132         FAIL_ON(!check_src_eq(&plane_state, 0, 0, 768 << 16, 1024 << 16));
133         FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1024, 768));
134         plane_state.rotation = DRM_MODE_ROTATE_0;
135
136         /* Check whether positioning works correctly. */
137         set_src(&plane_state, 0, 0, 1023 << 16, 767 << 16);
138         set_crtc(&plane_state, 0, 0, 1023, 767);
139         ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
140                                                   DRM_PLANE_HELPER_NO_SCALING,
141                                                   DRM_PLANE_HELPER_NO_SCALING,
142                                                   false, false);
143         FAIL(!ret, "Should not be able to position on the crtc with can_position=false\n");
144
145         ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
146                                                   DRM_PLANE_HELPER_NO_SCALING,
147                                                   DRM_PLANE_HELPER_NO_SCALING,
148                                                   true, false);
149         FAIL(ret < 0, "Simple positioning should work\n");
150         FAIL_ON(!plane_state.visible);
151         FAIL_ON(!check_src_eq(&plane_state, 0, 0, 1023 << 16, 767 << 16));
152         FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1023, 767));
153
154         /* Simple scaling tests. */
155         set_src(&plane_state, 0, 0, 512 << 16, 384 << 16);
156         set_crtc(&plane_state, 0, 0, 1024, 768);
157         ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
158                                                   0x8001,
159                                                   DRM_PLANE_HELPER_NO_SCALING,
160                                                   false, false);
161         FAIL(!ret, "Upscaling out of range should fail.\n");
162         ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
163                                                   0x8000,
164                                                   DRM_PLANE_HELPER_NO_SCALING,
165                                                   false, false);
166         FAIL(ret < 0, "Upscaling exactly 2x should work\n");
167         FAIL_ON(!plane_state.visible);
168         FAIL_ON(!check_src_eq(&plane_state, 0, 0, 512 << 16, 384 << 16));
169         FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1024, 768));
170
171         set_src(&plane_state, 0, 0, 2048 << 16, 1536 << 16);
172         ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
173                                                   DRM_PLANE_HELPER_NO_SCALING,
174                                                   0x1ffff, false, false);
175         FAIL(!ret, "Downscaling out of range should fail.\n");
176         ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
177                                                   DRM_PLANE_HELPER_NO_SCALING,
178                                                   0x20000, false, false);
179         FAIL(ret < 0, "Should succeed with exact scaling limit\n");
180         FAIL_ON(!plane_state.visible);
181         FAIL_ON(!check_src_eq(&plane_state, 0, 0, 2048 << 16, 1536 << 16));
182         FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1024, 768));
183
184         /* Testing rounding errors. */
185         set_src(&plane_state, 0, 0, 0x40001, 0x40001);
186         set_crtc(&plane_state, 1022, 766, 4, 4);
187         ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
188                                                   DRM_PLANE_HELPER_NO_SCALING,
189                                                   0x10001,
190                                                   true, false);
191         FAIL(ret < 0, "Should succeed by clipping to exact multiple");
192         FAIL_ON(!plane_state.visible);
193         FAIL_ON(!check_src_eq(&plane_state, 0, 0, 2 << 16, 2 << 16));
194         FAIL_ON(!check_crtc_eq(&plane_state, 1022, 766, 2, 2));
195
196         set_src(&plane_state, 0x20001, 0x20001, 0x4040001, 0x3040001);
197         set_crtc(&plane_state, -2, -2, 1028, 772);
198         ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
199                                                   DRM_PLANE_HELPER_NO_SCALING,
200                                                   0x10001,
201                                                   false, false);
202         FAIL(ret < 0, "Should succeed by clipping to exact multiple");
203         FAIL_ON(!plane_state.visible);
204         FAIL_ON(!check_src_eq(&plane_state, 0x40002, 0x40002, 1024 << 16, 768 << 16));
205         FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1024, 768));
206
207         set_src(&plane_state, 0, 0, 0x3ffff, 0x3ffff);
208         set_crtc(&plane_state, 1022, 766, 4, 4);
209         ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
210                                                   0xffff,
211                                                   DRM_PLANE_HELPER_NO_SCALING,
212                                                   true, false);
213         FAIL(ret < 0, "Should succeed by clipping to exact multiple");
214         FAIL_ON(!plane_state.visible);
215         /* Should not be rounded to 0x20001, which would be upscaling. */
216         FAIL_ON(!check_src_eq(&plane_state, 0, 0, 2 << 16, 2 << 16));
217         FAIL_ON(!check_crtc_eq(&plane_state, 1022, 766, 2, 2));
218
219         set_src(&plane_state, 0x1ffff, 0x1ffff, 0x403ffff, 0x303ffff);
220         set_crtc(&plane_state, -2, -2, 1028, 772);
221         ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
222                                                   0xffff,
223                                                   DRM_PLANE_HELPER_NO_SCALING,
224                                                   false, false);
225         FAIL(ret < 0, "Should succeed by clipping to exact multiple");
226         FAIL_ON(!plane_state.visible);
227         FAIL_ON(!check_src_eq(&plane_state, 0x3fffe, 0x3fffe, 1024 << 16, 768 << 16));
228         FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1024, 768));
229
230         return 0;
231 }
232
233 #include "drm_selftest.c"
234
235 static int __init test_drm_helper_init(void)
236 {
237         int err;
238
239         err = run_selftests(selftests, ARRAY_SIZE(selftests), NULL);
240
241         return err > 0 ? 0 : err;
242 }
243
244 module_init(test_drm_helper_init);
245
246 MODULE_AUTHOR("Intel Corporation");
247 MODULE_LICENSE("GPL");