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 
set_src(struct drm_plane_state * plane_state,unsigned src_x,unsigned src_y,unsigned src_w,unsigned src_h)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 
check_src_eq(struct drm_plane_state * plane_state,unsigned src_x,unsigned src_y,unsigned src_w,unsigned src_h)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 
set_crtc(struct drm_plane_state * plane_state,int crtc_x,int crtc_y,unsigned crtc_w,unsigned crtc_h)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 
check_crtc_eq(struct drm_plane_state * plane_state,int crtc_x,int crtc_y,unsigned crtc_w,unsigned crtc_h)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 
igt_check_plane_state(void * ignored)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 
test_drm_helper_init(void)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");
248