1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2014 Google, Inc
4  * Written by Simon Glass <sjg@chromium.org>
5  */
6 
7 #include <bzlib.h>
8 #include <dm.h>
9 #include <gzip.h>
10 #include <log.h>
11 #include <malloc.h>
12 #include <mapmem.h>
13 #include <os.h>
14 #include <video.h>
15 #include <video_console.h>
16 #include <asm/test.h>
17 #include <asm/sdl.h>
18 #include <dm/test.h>
19 #include <dm/uclass-internal.h>
20 #include <test/lib.h>
21 #include <test/test.h>
22 #include <test/ut.h>
23 #include <test/video.h>
24 
25 /*
26  * These tests use the standard sandbox frame buffer, the resolution of which
27  * is defined in the device tree. This only supports 16bpp so the tests only
28  * test that code path. It would be possible to adjust this fairly easily,
29  * by adjusting the bpix value in struct sandbox_sdl_plat. However the code
30  * in sandbox_sdl_sync() would also need to change to handle the different
31  * surface depth.
32  */
33 /* Basic test of the video uclass */
dm_test_video_base(struct unit_test_state * uts)34 static int dm_test_video_base(struct unit_test_state *uts)
35 {
36 	struct video_priv *priv;
37 	struct udevice *dev;
38 
39 	ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
40 	ut_asserteq(1366, video_get_xsize(dev));
41 	ut_asserteq(768, video_get_ysize(dev));
42 	priv = dev_get_uclass_priv(dev);
43 	ut_asserteq(priv->fb_size, 1366 * 768 * 2);
44 
45 	return 0;
46 }
47 DM_TEST(dm_test_video_base, UTF_SCAN_PDATA | UTF_SCAN_FDT);
48 
video_compress_fb(struct unit_test_state * uts,struct udevice * dev,bool use_copy)49 int video_compress_fb(struct unit_test_state *uts, struct udevice *dev,
50 		      bool use_copy)
51 {
52 	struct video_priv *priv = dev_get_uclass_priv(dev);
53 	uint destlen;
54 	void *dest;
55 	int ret;
56 
57 	if (!IS_ENABLED(CONFIG_VIDEO_COPY))
58 		use_copy = false;
59 
60 	destlen = priv->fb_size;
61 	dest = malloc(priv->fb_size);
62 	if (!dest)
63 		return -ENOMEM;
64 	ret = BZ2_bzBuffToBuffCompress(dest, &destlen,
65 				       use_copy ? priv->copy_fb : priv->fb,
66 				       priv->fb_size,
67 				       3, 0, 0);
68 	free(dest);
69 	if (ret)
70 		return ret;
71 
72 	return destlen;
73 }
74 
video_check_copy_fb(struct unit_test_state * uts,struct udevice * dev)75 int video_check_copy_fb(struct unit_test_state *uts, struct udevice *dev)
76 {
77 	struct video_priv *priv = dev_get_uclass_priv(dev);
78 
79 	if (!IS_ENABLED(CONFIG_VIDEO_COPY))
80 		return 0;
81 
82 	video_sync(dev, false);
83 	ut_assertf(!memcmp(priv->fb, priv->copy_fb, priv->fb_size),
84 		   "Copy framebuffer does not match fb");
85 
86 	return 0;
87 }
88 
89 /*
90  * Call this function at any point to halt and show the current display. Be
91  * sure to run the test with the -l flag.
92  */
see_output(void)93 static void __maybe_unused see_output(void)
94 {
95 	video_sync_all();
96 	while (1);
97 }
98 
99 /* Select the video console driver to use for a video device */
select_vidconsole(struct unit_test_state * uts,const char * drv_name)100 static int select_vidconsole(struct unit_test_state *uts, const char *drv_name)
101 {
102 	struct sandbox_sdl_plat *plat;
103 	struct udevice *dev;
104 
105 	ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
106 	ut_assert(!device_active(dev));
107 	plat = dev_get_plat(dev);
108 	plat->vidconsole_drv_name = "vidconsole0";
109 
110 	return 0;
111 }
112 
113 /**
114  * video_get_nologo() - Disable the logo on the video device and return it
115  *
116  * @uts: Test state
117  * @devp: Returns video device
118  * Return: 0 if OK, -ve on error
119  */
video_get_nologo(struct unit_test_state * uts,struct udevice ** devp)120 static int video_get_nologo(struct unit_test_state *uts, struct udevice **devp)
121 {
122 	struct video_uc_plat *uc_plat;
123 	struct udevice *dev;
124 
125 	ut_assertok(uclass_find_first_device(UCLASS_VIDEO, &dev));
126 	ut_assertnonnull(dev);
127 	uc_plat = dev_get_uclass_plat(dev);
128 	uc_plat->hide_logo = true;
129 
130 	/* now probe it */
131 	ut_assertok(uclass_first_device_err(UCLASS_VIDEO, &dev));
132 	ut_assertnonnull(dev);
133 	*devp = dev;
134 
135 	return 0;
136 }
137 
138 /* Test text output works on the video console */
dm_test_video_text(struct unit_test_state * uts)139 static int dm_test_video_text(struct unit_test_state *uts)
140 {
141 	struct udevice *dev, *con;
142 	int i;
143 
144 #define WHITE		0xffff
145 #define SCROLL_LINES	100
146 
147 	ut_assertok(select_vidconsole(uts, "vidconsole0"));
148 	ut_assertok(video_get_nologo(uts, &dev));
149 	ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
150 	ut_assertok(vidconsole_select_font(con, "8x16", 0));
151 	ut_asserteq(46, video_compress_fb(uts, dev, false));
152 	ut_assertok(video_check_copy_fb(uts, dev));
153 
154 	ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
155 	vidconsole_putc_xy(con, 0, 0, 'a');
156 	ut_asserteq(79, video_compress_fb(uts, dev, false));
157 	ut_assertok(video_check_copy_fb(uts, dev));
158 
159 	vidconsole_putc_xy(con, 0, 0, ' ');
160 	ut_asserteq(46, video_compress_fb(uts, dev, false));
161 	ut_assertok(video_check_copy_fb(uts, dev));
162 
163 	for (i = 0; i < 20; i++)
164 		vidconsole_putc_xy(con, VID_TO_POS(i * 8), 0, ' ' + i);
165 	ut_asserteq(273, video_compress_fb(uts, dev, false));
166 	ut_assertok(video_check_copy_fb(uts, dev));
167 
168 	vidconsole_set_row(con, 0, WHITE);
169 	ut_asserteq(46, video_compress_fb(uts, dev, false));
170 	ut_assertok(video_check_copy_fb(uts, dev));
171 
172 	for (i = 0; i < 20; i++)
173 		vidconsole_putc_xy(con, VID_TO_POS(i * 8), 0, ' ' + i);
174 	ut_asserteq(273, video_compress_fb(uts, dev, false));
175 	ut_assertok(video_check_copy_fb(uts, dev));
176 
177 	return 0;
178 }
179 DM_TEST(dm_test_video_text, UTF_SCAN_PDATA | UTF_SCAN_FDT);
180 
dm_test_video_text_12x22(struct unit_test_state * uts)181 static int dm_test_video_text_12x22(struct unit_test_state *uts)
182 {
183 	struct udevice *dev, *con;
184 	int i;
185 
186 #define WHITE		0xffff
187 #define SCROLL_LINES	100
188 
189 	ut_assertok(select_vidconsole(uts, "vidconsole0"));
190 	ut_assertok(video_get_nologo(uts, &dev));
191 	ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
192 	ut_assertok(vidconsole_select_font(con, "12x22", 0));
193 	ut_asserteq(46, video_compress_fb(uts, dev, false));
194 	ut_assertok(video_check_copy_fb(uts, dev));
195 
196 	ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
197 	vidconsole_putc_xy(con, 0, 0, 'a');
198 	ut_asserteq(89, video_compress_fb(uts, dev, false));
199 	ut_assertok(video_check_copy_fb(uts, dev));
200 
201 	vidconsole_putc_xy(con, 0, 0, ' ');
202 	ut_asserteq(46, video_compress_fb(uts, dev, false));
203 	ut_assertok(video_check_copy_fb(uts, dev));
204 
205 	for (i = 0; i < 20; i++)
206 		vidconsole_putc_xy(con, VID_TO_POS(i * 8), 0, ' ' + i);
207 	ut_asserteq(363, video_compress_fb(uts, dev, false));
208 	ut_assertok(video_check_copy_fb(uts, dev));
209 
210 	vidconsole_set_row(con, 0, WHITE);
211 	ut_asserteq(46, video_compress_fb(uts, dev, false));
212 	ut_assertok(video_check_copy_fb(uts, dev));
213 
214 	for (i = 0; i < 20; i++)
215 		vidconsole_putc_xy(con, VID_TO_POS(i * 8), 0, ' ' + i);
216 	ut_asserteq(363, video_compress_fb(uts, dev, false));
217 	ut_assertok(video_check_copy_fb(uts, dev));
218 
219 	return 0;
220 }
221 DM_TEST(dm_test_video_text_12x22, UTF_SCAN_PDATA | UTF_SCAN_FDT);
222 
223 /* Test handling of special characters in the console */
dm_test_video_chars(struct unit_test_state * uts)224 static int dm_test_video_chars(struct unit_test_state *uts)
225 {
226 	struct udevice *dev, *con;
227 	const char *test_string = "Well\b\b\b\bxhe is\r \n\ta very \amodest  \bman\n\t\tand Has much to\b\bto be modest about.";
228 
229 	ut_assertok(select_vidconsole(uts, "vidconsole0"));
230 	ut_assertok(video_get_nologo(uts, &dev));
231 	ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
232 	ut_assertok(vidconsole_select_font(con, "8x16", 0));
233 	vidconsole_put_string(con, test_string);
234 	ut_asserteq(466, video_compress_fb(uts, dev, false));
235 	ut_assertok(video_check_copy_fb(uts, dev));
236 
237 	return 0;
238 }
239 DM_TEST(dm_test_video_chars, UTF_SCAN_PDATA | UTF_SCAN_FDT);
240 
241 #ifdef CONFIG_VIDEO_ANSI
242 #define ANSI_ESC "\x1b"
243 /* Test handling of ANSI escape sequences */
dm_test_video_ansi(struct unit_test_state * uts)244 static int dm_test_video_ansi(struct unit_test_state *uts)
245 {
246 	struct udevice *dev, *con;
247 
248 	ut_assertok(select_vidconsole(uts, "vidconsole0"));
249 	ut_assertok(video_get_nologo(uts, &dev));
250 	ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
251 	ut_assertok(vidconsole_select_font(con, "8x16", 0));
252 
253 	/* reference clear: */
254 	video_clear(con->parent);
255 	video_sync(con->parent, false);
256 	ut_asserteq(46, video_compress_fb(uts, dev, false));
257 	ut_assertok(video_check_copy_fb(uts, dev));
258 
259 	/* test clear escape sequence: [2J */
260 	vidconsole_put_string(con, "A\tB\tC"ANSI_ESC"[2J");
261 	ut_asserteq(46, video_compress_fb(uts, dev, false));
262 	ut_assertok(video_check_copy_fb(uts, dev));
263 
264 	/* test set-cursor: [%d;%df */
265 	vidconsole_put_string(con, "abc"ANSI_ESC"[2;2fab"ANSI_ESC"[4;4fcd");
266 	ut_asserteq(143, video_compress_fb(uts, dev, false));
267 	ut_assertok(video_check_copy_fb(uts, dev));
268 
269 	/* test colors (30-37 fg color, 40-47 bg color) */
270 	vidconsole_put_string(con, ANSI_ESC"[30;41mfoo"); /* black on red */
271 	vidconsole_put_string(con, ANSI_ESC"[33;44mbar"); /* yellow on blue */
272 	ut_asserteq(272, video_compress_fb(uts, dev, false));
273 	ut_assertok(video_check_copy_fb(uts, dev));
274 
275 	return 0;
276 }
277 DM_TEST(dm_test_video_ansi, UTF_SCAN_PDATA | UTF_SCAN_FDT);
278 #endif
279 
280 /**
281  * check_vidconsole_output() - Run a text console test
282  *
283  * @uts:	Test state
284  * @rot:	Console rotation (0=normal orientation, 1=90 degrees clockwise,
285  *		2=upside down, 3=90 degree counterclockwise)
286  * @wrap_size:	Expected size of compressed frame buffer for the wrap test
287  * @scroll_size: Same for the scroll test
288  * Return: 0 on success
289  */
check_vidconsole_output(struct unit_test_state * uts,int rot,int wrap_size,int scroll_size)290 static int check_vidconsole_output(struct unit_test_state *uts, int rot,
291 				   int wrap_size, int scroll_size)
292 {
293 	struct udevice *dev, *con;
294 	struct sandbox_sdl_plat *plat;
295 	int i;
296 
297 	ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
298 	ut_assert(!device_active(dev));
299 	plat = dev_get_plat(dev);
300 	plat->rot = rot;
301 
302 	ut_assertok(video_get_nologo(uts, &dev));
303 	ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
304 	ut_assertok(vidconsole_select_font(con, "8x16", 0));
305 	ut_asserteq(46, video_compress_fb(uts, dev, false));
306 	ut_assertok(video_check_copy_fb(uts, dev));
307 
308 	/* Check display wrap */
309 	for (i = 0; i < 120; i++)
310 		vidconsole_put_char(con, 'A' + i % 50);
311 	ut_asserteq(wrap_size, video_compress_fb(uts, dev, false));
312 	ut_assertok(video_check_copy_fb(uts, dev));
313 
314 	/* Check display scrolling */
315 	for (i = 0; i < SCROLL_LINES; i++) {
316 		vidconsole_put_char(con, 'A' + i % 50);
317 		vidconsole_put_char(con, '\n');
318 	}
319 	ut_asserteq(scroll_size, video_compress_fb(uts, dev, false));
320 	ut_assertok(video_check_copy_fb(uts, dev));
321 
322 	/* If we scroll enough, the screen becomes blank again */
323 	for (i = 0; i < SCROLL_LINES; i++)
324 		vidconsole_put_char(con, '\n');
325 	ut_asserteq(46, video_compress_fb(uts, dev, false));
326 	ut_assertok(video_check_copy_fb(uts, dev));
327 
328 	return 0;
329 }
330 
331 /* Test text output through the console uclass */
dm_test_video_context(struct unit_test_state * uts)332 static int dm_test_video_context(struct unit_test_state *uts)
333 {
334 	ut_assertok(select_vidconsole(uts, "vidconsole0"));
335 	ut_assertok(check_vidconsole_output(uts, 0, 788, 453));
336 
337 	return 0;
338 }
339 DM_TEST(dm_test_video_context, UTF_SCAN_PDATA | UTF_SCAN_FDT);
340 
341 /* Test rotated text output through the console uclass */
dm_test_video_rotation1(struct unit_test_state * uts)342 static int dm_test_video_rotation1(struct unit_test_state *uts)
343 {
344 	ut_assertok(check_vidconsole_output(uts, 1, 1112, 680));
345 
346 	return 0;
347 }
348 DM_TEST(dm_test_video_rotation1, UTF_SCAN_PDATA | UTF_SCAN_FDT);
349 
350 /* Test rotated text output through the console uclass */
dm_test_video_rotation2(struct unit_test_state * uts)351 static int dm_test_video_rotation2(struct unit_test_state *uts)
352 {
353 	ut_assertok(check_vidconsole_output(uts, 2, 783, 445));
354 
355 	return 0;
356 }
357 DM_TEST(dm_test_video_rotation2, UTF_SCAN_PDATA | UTF_SCAN_FDT);
358 
359 /* Test rotated text output through the console uclass */
dm_test_video_rotation3(struct unit_test_state * uts)360 static int dm_test_video_rotation3(struct unit_test_state *uts)
361 {
362 	ut_assertok(check_vidconsole_output(uts, 3, 1134, 681));
363 
364 	return 0;
365 }
366 DM_TEST(dm_test_video_rotation3, UTF_SCAN_PDATA | UTF_SCAN_FDT);
367 
368 /* Read a file into memory and return a pointer to it */
read_file(struct unit_test_state * uts,const char * fname,ulong * addrp)369 static int read_file(struct unit_test_state *uts, const char *fname,
370 		     ulong *addrp)
371 {
372 	int buf_size = 100000;
373 	ulong addr = 0;
374 	int size, fd;
375 	char *buf;
376 
377 	buf = map_sysmem(addr, 0);
378 	ut_assert(buf != NULL);
379 	fd = os_open(fname, OS_O_RDONLY);
380 	ut_assert(fd >= 0);
381 	size = os_read(fd, buf, buf_size);
382 	os_close(fd);
383 	ut_assert(size >= 0);
384 	ut_assert(size < buf_size);
385 	*addrp = addr;
386 
387 	return 0;
388 }
389 
390 /* Test drawing a bitmap file */
dm_test_video_bmp(struct unit_test_state * uts)391 static int dm_test_video_bmp(struct unit_test_state *uts)
392 {
393 	struct udevice *dev;
394 	ulong addr;
395 
396 	ut_assertok(video_get_nologo(uts, &dev));
397 	ut_assertok(read_file(uts, "tools/logos/denx.bmp", &addr));
398 
399 	ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
400 	ut_asserteq(1368, video_compress_fb(uts, dev, false));
401 	ut_assertok(video_check_copy_fb(uts, dev));
402 
403 	return 0;
404 }
405 DM_TEST(dm_test_video_bmp, UTF_SCAN_PDATA | UTF_SCAN_FDT);
406 
407 /* Test drawing a bitmap file on a 8bpp display */
dm_test_video_bmp8(struct unit_test_state * uts)408 static int dm_test_video_bmp8(struct unit_test_state *uts)
409 {
410 	struct udevice *dev;
411 	ulong addr;
412 
413 	ut_assertok(uclass_find_first_device(UCLASS_VIDEO, &dev));
414 	ut_assertnonnull(dev);
415 	ut_assertok(sandbox_sdl_set_bpp(dev, VIDEO_BPP8));
416 
417 	ut_assertok(read_file(uts, "tools/logos/denx.bmp", &addr));
418 
419 	ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
420 	ut_asserteq(1247, video_compress_fb(uts, dev, false));
421 	ut_assertok(video_check_copy_fb(uts, dev));
422 
423 	return 0;
424 }
425 DM_TEST(dm_test_video_bmp8, UTF_SCAN_PDATA | UTF_SCAN_FDT);
426 
427 /* Test drawing a bitmap file on a 16bpp display */
dm_test_video_bmp16(struct unit_test_state * uts)428 static int dm_test_video_bmp16(struct unit_test_state *uts)
429 {
430 	ulong src, src_len = ~0UL;
431 	uint dst_len = ~0U;
432 	struct udevice *dev;
433 	ulong dst = 0x10000;
434 
435 	ut_assertok(uclass_find_first_device(UCLASS_VIDEO, &dev));
436 	ut_assertnonnull(dev);
437 	ut_assertok(sandbox_sdl_set_bpp(dev, VIDEO_BPP16));
438 
439 	ut_assertok(read_file(uts, "tools/logos/denx-16bpp.bmp.gz", &src));
440 	ut_assertok(gunzip(map_sysmem(dst, 0), dst_len, map_sysmem(src, 0),
441 			   &src_len));
442 
443 	ut_assertok(video_bmp_display(dev, dst, 0, 0, false));
444 	ut_asserteq(3700, video_compress_fb(uts, dev, false));
445 	ut_assertok(video_check_copy_fb(uts, dev));
446 
447 	return 0;
448 }
449 DM_TEST(dm_test_video_bmp16, UTF_SCAN_PDATA | UTF_SCAN_FDT);
450 
451 /* Test drawing a 24bpp bitmap file on a 16bpp display */
dm_test_video_bmp24(struct unit_test_state * uts)452 static int dm_test_video_bmp24(struct unit_test_state *uts)
453 {
454 	ulong src, src_len = ~0UL;
455 	uint dst_len = ~0U;
456 	struct udevice *dev;
457 	ulong dst = 0x10000;
458 
459 	ut_assertok(uclass_find_first_device(UCLASS_VIDEO, &dev));
460 	ut_assertnonnull(dev);
461 	ut_assertok(sandbox_sdl_set_bpp(dev, VIDEO_BPP16));
462 
463 	ut_assertok(read_file(uts, "tools/logos/denx-24bpp.bmp.gz", &src));
464 	ut_assertok(gunzip(map_sysmem(dst, 0), dst_len, map_sysmem(src, 0),
465 			   &src_len));
466 
467 	ut_assertok(video_bmp_display(dev, dst, 0, 0, false));
468 	ut_asserteq(3656, video_compress_fb(uts, dev, false));
469 	ut_assertok(video_check_copy_fb(uts, dev));
470 
471 	return 0;
472 }
473 DM_TEST(dm_test_video_bmp24, UTF_SCAN_PDATA | UTF_SCAN_FDT);
474 
475 /* Test drawing a 24bpp bitmap file on a 32bpp display */
dm_test_video_bmp24_32(struct unit_test_state * uts)476 static int dm_test_video_bmp24_32(struct unit_test_state *uts)
477 {
478 	ulong src, src_len = ~0UL;
479 	uint dst_len = ~0U;
480 	struct udevice *dev;
481 	ulong dst = 0x10000;
482 
483 	ut_assertok(uclass_find_first_device(UCLASS_VIDEO, &dev));
484 	ut_assertnonnull(dev);
485 	ut_assertok(sandbox_sdl_set_bpp(dev, VIDEO_BPP32));
486 
487 	ut_assertok(read_file(uts, "tools/logos/denx-24bpp.bmp.gz", &src));
488 	ut_assertok(gunzip(map_sysmem(dst, 0), dst_len, map_sysmem(src, 0),
489 			   &src_len));
490 
491 	ut_assertok(video_bmp_display(dev, dst, 0, 0, false));
492 	ut_asserteq(6827, video_compress_fb(uts, dev, false));
493 	ut_assertok(video_check_copy_fb(uts, dev));
494 
495 	return 0;
496 }
497 DM_TEST(dm_test_video_bmp24_32, UTF_SCAN_PDATA | UTF_SCAN_FDT);
498 
499 /* Test drawing a bitmap file on a 32bpp display */
dm_test_video_bmp32(struct unit_test_state * uts)500 static int dm_test_video_bmp32(struct unit_test_state *uts)
501 {
502 	struct udevice *dev;
503 	ulong addr;
504 
505 	ut_assertok(uclass_find_first_device(UCLASS_VIDEO, &dev));
506 	ut_assertnonnull(dev);
507 	ut_assertok(sandbox_sdl_set_bpp(dev, VIDEO_BPP32));
508 	ut_assertok(read_file(uts, "tools/logos/denx.bmp", &addr));
509 
510 	ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
511 	ut_asserteq(2024, video_compress_fb(uts, dev, false));
512 	ut_assertok(video_check_copy_fb(uts, dev));
513 
514 	return 0;
515 }
516 DM_TEST(dm_test_video_bmp32, UTF_SCAN_PDATA | UTF_SCAN_FDT);
517 
518 /* Test drawing a compressed bitmap file */
dm_test_video_bmp_comp(struct unit_test_state * uts)519 static int dm_test_video_bmp_comp(struct unit_test_state *uts)
520 {
521 	struct udevice *dev;
522 	ulong addr;
523 
524 	ut_assertok(video_get_nologo(uts, &dev));
525 	ut_assertok(read_file(uts, "tools/logos/denx-comp.bmp", &addr));
526 
527 	ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
528 	ut_asserteq(1368, video_compress_fb(uts, dev, false));
529 	ut_assertok(video_check_copy_fb(uts, dev));
530 
531 	return 0;
532 }
533 DM_TEST(dm_test_video_bmp_comp, UTF_SCAN_PDATA | UTF_SCAN_FDT);
534 
535 /* Test drawing a bitmap file on a 32bpp display */
dm_test_video_comp_bmp32(struct unit_test_state * uts)536 static int dm_test_video_comp_bmp32(struct unit_test_state *uts)
537 {
538 	struct udevice *dev;
539 	ulong addr;
540 
541 	ut_assertok(uclass_find_first_device(UCLASS_VIDEO, &dev));
542 	ut_assertnonnull(dev);
543 	ut_assertok(sandbox_sdl_set_bpp(dev, VIDEO_BPP32));
544 
545 	ut_assertok(read_file(uts, "tools/logos/denx.bmp", &addr));
546 
547 	ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
548 	ut_asserteq(2024, video_compress_fb(uts, dev, false));
549 	ut_assertok(video_check_copy_fb(uts, dev));
550 
551 	return 0;
552 }
553 DM_TEST(dm_test_video_comp_bmp32, UTF_SCAN_PDATA | UTF_SCAN_FDT);
554 
555 /* Test drawing a bitmap file on a 8bpp display */
dm_test_video_comp_bmp8(struct unit_test_state * uts)556 static int dm_test_video_comp_bmp8(struct unit_test_state *uts)
557 {
558 	struct udevice *dev;
559 	ulong addr;
560 
561 	ut_assertok(uclass_find_first_device(UCLASS_VIDEO, &dev));
562 	ut_assertnonnull(dev);
563 	ut_assertok(sandbox_sdl_set_bpp(dev, VIDEO_BPP8));
564 
565 	ut_assertok(read_file(uts, "tools/logos/denx.bmp", &addr));
566 
567 	ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
568 	ut_asserteq(1247, video_compress_fb(uts, dev, false));
569 	ut_assertok(video_check_copy_fb(uts, dev));
570 
571 	return 0;
572 }
573 DM_TEST(dm_test_video_comp_bmp8, UTF_SCAN_PDATA | UTF_SCAN_FDT);
574 
575 /* Test TrueType console */
dm_test_video_truetype(struct unit_test_state * uts)576 static int dm_test_video_truetype(struct unit_test_state *uts)
577 {
578 	struct udevice *dev, *con;
579 	const char *test_string = "Criticism may not be agreeable, but it is necessary. It fulfils the same function as pain in the human body. It calls attention to an unhealthy state of things. Some see private enterprise as a predatory target to be shot, others as a cow to be milked, but few are those who see it as a sturdy horse pulling the wagon. The \aprice OF\b\bof greatness\n\tis responsibility.\n\nBye";
580 
581 	ut_assertok(video_get_nologo(uts, &dev));
582 	ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
583 	vidconsole_put_string(con, test_string);
584 	vidconsole_put_stringn(con, test_string, 30);
585 	ut_asserteq(13184, video_compress_fb(uts, dev, false));
586 	ut_assertok(video_check_copy_fb(uts, dev));
587 
588 	return 0;
589 }
590 DM_TEST(dm_test_video_truetype, UTF_SCAN_PDATA | UTF_SCAN_FDT);
591 
592 /* Test scrolling TrueType console */
dm_test_video_truetype_scroll(struct unit_test_state * uts)593 static int dm_test_video_truetype_scroll(struct unit_test_state *uts)
594 {
595 	struct sandbox_sdl_plat *plat;
596 	struct udevice *dev, *con;
597 	const char *test_string = "Criticism may not be agreeable, but it is necessary. It fulfils the same function as pain in the human body. It calls attention to an unhealthy state of things. Some see private enterprise as a predatory target to be shot, others as a cow to be milked, but few are those who see it as a sturdy horse pulling the wagon. The \aprice OF\b\bof greatness\n\tis responsibility.\n\nBye";
598 
599 	ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
600 	ut_assert(!device_active(dev));
601 	plat = dev_get_plat(dev);
602 	plat->font_size = 100;
603 
604 	ut_assertok(video_get_nologo(uts, &dev));
605 	ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
606 	vidconsole_put_string(con, test_string);
607 	ut_asserteq(34287, video_compress_fb(uts, dev, false));
608 	ut_assertok(video_check_copy_fb(uts, dev));
609 
610 	return 0;
611 }
612 DM_TEST(dm_test_video_truetype_scroll, UTF_SCAN_PDATA | UTF_SCAN_FDT);
613 
614 /* Test TrueType backspace, within and across lines */
dm_test_video_truetype_bs(struct unit_test_state * uts)615 static int dm_test_video_truetype_bs(struct unit_test_state *uts)
616 {
617 	struct sandbox_sdl_plat *plat;
618 	struct udevice *dev, *con;
619 	const char *test_string = "...Criticism may or may\b\b\b\b\b\bnot be agreeable, but seldom it is necessary\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\bit is necessary. It fulfils the same function as pain in the human body. It calls attention to an unhealthy state of things.";
620 
621 	ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
622 	ut_assert(!device_active(dev));
623 	plat = dev_get_plat(dev);
624 	plat->font_size = 100;
625 
626 	ut_assertok(video_get_nologo(uts, &dev));
627 	ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
628 	vidconsole_put_string(con, test_string);
629 	ut_asserteq(29471, video_compress_fb(uts, dev, false));
630 	ut_assertok(video_check_copy_fb(uts, dev));
631 
632 	return 0;
633 }
634 DM_TEST(dm_test_video_truetype_bs, UTF_SCAN_PDATA | UTF_SCAN_FDT);
635 
636 /* Test partial rendering onto hardware frame buffer */
dm_test_video_copy(struct unit_test_state * uts)637 static int dm_test_video_copy(struct unit_test_state *uts)
638 {
639 	struct sandbox_sdl_plat *plat;
640 	struct video_uc_plat *uc_plat;
641 	struct udevice *dev, *con;
642 	struct video_priv *priv;
643 	const char *test_string = "\n\tCriticism may not be agreeable, but it is necessary.\t";
644 	ulong addr;
645 
646 	if (!IS_ENABLED(CONFIG_VIDEO_COPY))
647 		return -EAGAIN;
648 
649 	ut_assertok(uclass_find_first_device(UCLASS_VIDEO, &dev));
650 	ut_assertnonnull(dev);
651 	uc_plat = dev_get_uclass_plat(dev);
652 	uc_plat->hide_logo = true;
653 	plat = dev_get_plat(dev);
654 	plat->font_size = 32;
655 	ut_assert(!device_active(dev));
656 	ut_assertok(uclass_first_device_err(UCLASS_VIDEO, &dev));
657 	ut_assertnonnull(dev);
658 	priv = dev_get_uclass_priv(dev);
659 
660 	ut_assertok(read_file(uts, "tools/logos/denx.bmp", &addr));
661 	ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
662 
663 	ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
664 	vidconsole_put_string(con, "\n\n\n\n\n");
665 	vidconsole_put_string(con, test_string);
666 	vidconsole_put_string(con, test_string);
667 
668 	ut_asserteq(6678, video_compress_fb(uts, dev, false));
669 	ut_assertok(video_check_copy_fb(uts, dev));
670 
671 	/*
672 	 * Secretly clear the hardware frame buffer, but in a different
673 	 * color (black) to see which parts will be overwritten.
674 	 */
675 	memset(priv->copy_fb, 0, priv->fb_size);
676 
677 	/*
678 	 * We should have the full content on the main buffer, but only
679 	 * 'damage' should have been copied to the copy buffer. This consists
680 	 * of a while rectangle with the Denx logo and four lines of text. The
681 	 * rest of the display is black.
682 	 *
683 	 * An easy way to try this is by changing video_sync() to call
684 	 * sandbox_sdl_sync(priv->copy_fb) instead of priv->fb then running the
685 	 * unit test:
686 	 *
687 	 *   ./u-boot -Tl
688 	 *   ut dm dm_test_video_copy
689 	 */
690 	vidconsole_put_string(con, test_string);
691 	vidconsole_put_string(con, test_string);
692 	video_sync(dev, true);
693 	ut_asserteq(7589, video_compress_fb(uts, dev, false));
694 	ut_asserteq(7704, video_compress_fb(uts, dev, true));
695 
696 	return 0;
697 }
698 DM_TEST(dm_test_video_copy, UTF_SCAN_PDATA | UTF_SCAN_FDT);
699 
700 /* Test video damage tracking */
dm_test_video_damage(struct unit_test_state * uts)701 static int dm_test_video_damage(struct unit_test_state *uts)
702 {
703 	struct sandbox_sdl_plat *plat;
704 	struct udevice *dev, *con;
705 	struct video_priv *priv;
706 	const char *test_string_1 = "Criticism may not be agreeable, ";
707 	const char *test_string_2 = "but it is necessary.";
708 	const char *test_string_3 = "It fulfils the same function as pain in the human body.";
709 
710 	if (!IS_ENABLED(CONFIG_VIDEO_DAMAGE))
711 		return -EAGAIN;
712 
713 	ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
714 	ut_assert(!device_active(dev));
715 	plat = dev_get_plat(dev);
716 	plat->font_size = 32;
717 
718 	ut_assertok(video_get_nologo(uts, &dev));
719 	ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
720 	priv = dev_get_uclass_priv(dev);
721 
722 	vidconsole_position_cursor(con, 14, 10);
723 	vidconsole_put_string(con, test_string_2);
724 	ut_asserteq(449, priv->damage.xstart);
725 	ut_asserteq(325, priv->damage.ystart);
726 	ut_asserteq(661, priv->damage.xend);
727 	ut_asserteq(350, priv->damage.yend);
728 
729 	vidconsole_position_cursor(con, 7, 5);
730 	vidconsole_put_string(con, test_string_1);
731 	ut_asserteq(225, priv->damage.xstart);
732 	ut_asserteq(164, priv->damage.ystart);
733 	ut_asserteq(661, priv->damage.xend);
734 	ut_asserteq(350, priv->damage.yend);
735 
736 	vidconsole_position_cursor(con, 21, 15);
737 	vidconsole_put_string(con, test_string_3);
738 	ut_asserteq(225, priv->damage.xstart);
739 	ut_asserteq(164, priv->damage.ystart);
740 	ut_asserteq(1280, priv->damage.xend);
741 	ut_asserteq(510, priv->damage.yend);
742 
743 	video_sync(dev, true);
744 	ut_asserteq(priv->xsize, priv->damage.xstart);
745 	ut_asserteq(priv->ysize, priv->damage.ystart);
746 	ut_asserteq(0, priv->damage.xend);
747 	ut_asserteq(0, priv->damage.yend);
748 
749 	ut_asserteq(7339, video_compress_fb(uts, dev, false));
750 	ut_assertok(video_check_copy_fb(uts, dev));
751 
752 	return 0;
753 }
754 DM_TEST(dm_test_video_damage, UTF_SCAN_PDATA | UTF_SCAN_FDT);
755 
756 /* Test font measurement */
dm_test_font_measure(struct unit_test_state * uts)757 static int dm_test_font_measure(struct unit_test_state *uts)
758 {
759 	const char *test_string = "There is always much\nto be said for not "
760 		"attempting more than you can do and for making a certainty of "
761 		"what you try. But this principle, like others in life and "
762 		"war, has its exceptions.";
763 	const struct vidconsole_mline *line;
764 	struct vidconsole_bbox bbox;
765 	struct video_priv *priv;
766 	struct udevice *dev, *con;
767 	const int limit = 0x320;
768 	struct alist lines;
769 	int nl;
770 
771 	ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
772 	priv = dev_get_uclass_priv(dev);
773 	ut_asserteq(1366, priv->xsize);
774 	ut_asserteq(768, priv->ysize);
775 
776 	/* this is using the Nimbus font with size of 18 pixels */
777 	ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
778 	vidconsole_position_cursor(con, 0, 0);
779 	alist_init_struct(&lines, struct vidconsole_mline);
780 	ut_assertok(vidconsole_measure(con, NULL, 0, test_string, -1, &bbox,
781 				       &lines));
782 	ut_asserteq(0, bbox.x0);
783 	ut_asserteq(0, bbox.y0);
784 	ut_asserteq(0x3ea, bbox.x1);
785 	ut_asserteq(0x24, bbox.y1);
786 	ut_asserteq(2, lines.count);
787 
788 	nl = strchr(test_string, '\n') - test_string;
789 
790 	line = alist_get(&lines, 0, struct vidconsole_mline);
791 	ut_assertnonnull(line);
792 	ut_asserteq(0, line->bbox.x0);
793 	ut_asserteq(0, line->bbox.y0);
794 	ut_asserteq(0x8c, line->bbox.x1);
795 	ut_asserteq(0x12, line->bbox.y1);
796 	ut_asserteq(0, line->start);
797 	ut_asserteq(20, line->len);
798 	ut_asserteq(nl, line->len);
799 
800 	line++;
801 	ut_asserteq(0x0, line->bbox.x0);
802 	ut_asserteq(0x12, line->bbox.y0);
803 	ut_asserteq(0x3ea, line->bbox.x1);
804 	ut_asserteq(0x24, line->bbox.y1);
805 	ut_asserteq(21, line->start);
806 	ut_asserteq(nl + 1, line->start);
807 	ut_asserteq(163, line->len);
808 	ut_asserteq(strlen(test_string + nl + 1), line->len);
809 
810 	/* now use a limit on the width */
811 	ut_assertok(vidconsole_measure(con, NULL, 0, test_string, limit, &bbox,
812 				       &lines));
813 	ut_asserteq(0, bbox.x0);
814 	ut_asserteq(0, bbox.y0);
815 	ut_asserteq(0x31e, bbox.x1);
816 	ut_asserteq(0x36, bbox.y1);
817 	ut_asserteq(3, lines.count);
818 
819 	nl = strchr(test_string, '\n') - test_string;
820 
821 	line = alist_get(&lines, 0, struct vidconsole_mline);
822 	ut_assertnonnull(line);
823 	ut_asserteq(0, line->bbox.x0);
824 	ut_asserteq(0, line->bbox.y0);
825 	ut_asserteq(0x8c, line->bbox.x1);
826 	ut_asserteq(0x12, line->bbox.y1);
827 	ut_asserteq(0, line->start);
828 	ut_asserteq(20, line->len);
829 	ut_asserteq(nl, line->len);
830 	printf("line0 '%.*s'\n", line->len, test_string + line->start);
831 	ut_asserteq_strn("There is always much",
832 			 test_string + line->start);
833 
834 	line++;
835 	ut_asserteq(0x0, line->bbox.x0);
836 	ut_asserteq(0x12, line->bbox.y0);
837 	ut_asserteq(0x31e, line->bbox.x1);
838 	ut_asserteq(0x24, line->bbox.y1);
839 	ut_asserteq(21, line->start);
840 	ut_asserteq(nl + 1, line->start);
841 	ut_asserteq(129, line->len);
842 	printf("line1 '%.*s'\n", line->len, test_string + line->start);
843 	ut_asserteq_strn("to be said for not attempting more than you can do "
844 			 "and for making a certainty of what you try. But this "
845 			 "principle, like others in",
846 			 test_string + line->start);
847 
848 	line++;
849 	ut_asserteq(0x0, line->bbox.x0);
850 	ut_asserteq(0x24, line->bbox.y0);
851 	ut_asserteq(0xc8, line->bbox.x1);
852 	ut_asserteq(0x36, line->bbox.y1);
853 	ut_asserteq(21 + 130, line->start);
854 	ut_asserteq(33, line->len);
855 	printf("line2 '%.*s'\n", line->len, test_string + line->start);
856 	ut_asserteq_strn("life and war, has its exceptions.",
857 			 test_string + line->start);
858 
859 	/*
860 	 * all characters should be accounted for, except the newline and the
861 	 * space which is consumed in the wordwrap
862 	 */
863 	ut_asserteq(strlen(test_string) - 2,
864 		    line[-2].len + line[-1].len + line->len);
865 
866 	return 0;
867 }
868 DM_TEST(dm_test_font_measure, UTF_SCAN_FDT);
869 
870 /* Test silencing the video console */
dm_test_video_silence(struct unit_test_state * uts)871 static int dm_test_video_silence(struct unit_test_state *uts)
872 {
873 	struct udevice *dev, *con;
874 	struct stdio_dev *sdev;
875 
876 	ut_assertok(uclass_first_device_err(UCLASS_VIDEO, &dev));
877 
878 	/*
879 	 * use the old console device from before when dm_test_pre_run() was
880 	 * called, since that is what is in stdio / console
881 	 */
882 	sdev = stdio_get_by_name("vidconsole");
883 	ut_assertnonnull(sdev);
884 	con = sdev->priv;
885 	ut_assertok(vidconsole_clear_and_reset(con));
886 	ut_unsilence_console(uts);
887 
888 	printf("message 1: console\n");
889 	vidconsole_put_string(con, "message 1: video\n");
890 
891 	vidconsole_set_quiet(con, true);
892 	printf("second message: console\n");
893 	vidconsole_put_string(con, "second message: video\n");
894 
895 	vidconsole_set_quiet(con, false);
896 	printf("final message: console\n");
897 	vidconsole_put_string(con, "final message: video\n");
898 
899 	ut_asserteq(3892, video_compress_fb(uts, dev, false));
900 	ut_assertok(video_check_copy_fb(uts, dev));
901 
902 	return 0;
903 }
904 DM_TEST(dm_test_video_silence, UTF_SCAN_FDT);
905 
906 /* test drawing a box */
dm_test_video_box(struct unit_test_state * uts)907 static int dm_test_video_box(struct unit_test_state *uts)
908 {
909 	struct video_priv *priv;
910 	struct udevice *dev;
911 
912 	ut_assertok(video_get_nologo(uts, &dev));
913 	priv = dev_get_uclass_priv(dev);
914 	video_draw_box(dev, 100, 100, 200, 200, 3,
915 		       video_index_to_colour(priv, VID_LIGHT_BLUE));
916 	video_draw_box(dev, 300, 100, 400, 200, 1,
917 		       video_index_to_colour(priv, VID_MAGENTA));
918 	video_draw_box(dev, 500, 100, 600, 200, 20,
919 		       video_index_to_colour(priv, VID_LIGHT_RED));
920 	ut_asserteq(133, video_compress_fb(uts, dev, false));
921 	ut_assertok(video_check_copy_fb(uts, dev));
922 
923 	return 0;
924 }
925 DM_TEST(dm_test_video_box, UTF_SCAN_FDT);
926