• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <common.h>
8 #include <bzlib.h>
9 #include <dm.h>
10 #include <mapmem.h>
11 #include <os.h>
12 #include <video.h>
13 #include <video_console.h>
14 #include <dm/test.h>
15 #include <dm/uclass-internal.h>
16 #include <test/ut.h>
17 
18 /*
19  * These tests use the standard sandbox frame buffer, the resolution of which
20  * is defined in the device tree. This only supports 16bpp so the tests only
21  * test that code path. It would be possible to adjust this fairly easily,
22  * by adjusting the bpix value in struct sandbox_sdl_plat. However the code
23  * in sandbox_sdl_sync() would also need to change to handle the different
24  * surface depth.
25  */
26 /* Basic test of the video uclass */
dm_test_video_base(struct unit_test_state * uts)27 static int dm_test_video_base(struct unit_test_state *uts)
28 {
29 	struct video_priv *priv;
30 	struct udevice *dev;
31 
32 	ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
33 	ut_asserteq(1366, video_get_xsize(dev));
34 	ut_asserteq(768, video_get_ysize(dev));
35 	priv = dev_get_uclass_priv(dev);
36 	ut_asserteq(priv->fb_size, 1366 * 768 * 2);
37 
38 	return 0;
39 }
40 DM_TEST(dm_test_video_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
41 
42 /**
43  * compress_frame_buffer() - Compress the frame buffer and return its size
44  *
45  * We want to write tests which perform operations on the video console and
46  * check that the frame buffer ends up with the correct contents. But it is
47  * painful to store 'known good' images for comparison with the frame
48  * buffer. As an alternative, we can compress the frame buffer and check the
49  * size of the compressed data. This provides a pretty good level of
50  * certainty and the resulting tests need only check a single value.
51  *
52  * @dev:	Video device
53  * @return compressed size of the frame buffer, or -ve on error
54  */
compress_frame_buffer(struct udevice * dev)55 static int compress_frame_buffer(struct udevice *dev)
56 {
57 	struct video_priv *priv = dev_get_uclass_priv(dev);
58 	uint destlen;
59 	void *dest;
60 	int ret;
61 
62 	destlen = priv->fb_size;
63 	dest = malloc(priv->fb_size);
64 	if (!dest)
65 		return -ENOMEM;
66 	ret = BZ2_bzBuffToBuffCompress(dest, &destlen,
67 				       priv->fb, priv->fb_size,
68 				       3, 0, 0);
69 	free(dest);
70 	if (ret)
71 		return ret;
72 
73 	return destlen;
74 }
75 
76 /*
77  * Call this function at any point to halt and show the current display. Be
78  * sure to run the test with the -l flag.
79  */
see_output(void)80 static void __maybe_unused see_output(void)
81 {
82 	video_sync_all();
83 	while (1);
84 }
85 
86 /* Select the video console driver to use for a video device */
select_vidconsole(struct unit_test_state * uts,const char * drv_name)87 static int select_vidconsole(struct unit_test_state *uts, const char *drv_name)
88 {
89 	struct sandbox_sdl_plat *plat;
90 	struct udevice *dev;
91 
92 	ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
93 	ut_assert(!device_active(dev));
94 	plat = dev_get_platdata(dev);
95 	plat->vidconsole_drv_name = "vidconsole0";
96 
97 	return 0;
98 }
99 
100 /* Test text output works on the video console */
dm_test_video_text(struct unit_test_state * uts)101 static int dm_test_video_text(struct unit_test_state *uts)
102 {
103 	struct udevice *dev, *con;
104 	int i;
105 
106 #define WHITE		0xffff
107 #define SCROLL_LINES	100
108 
109 	ut_assertok(select_vidconsole(uts, "vidconsole0"));
110 	ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
111 	ut_asserteq(46, compress_frame_buffer(dev));
112 
113 	ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
114 	vidconsole_putc_xy(con, 0, 0, 'a');
115 	ut_asserteq(79, compress_frame_buffer(dev));
116 
117 	vidconsole_putc_xy(con, 0, 0, ' ');
118 	ut_asserteq(46, compress_frame_buffer(dev));
119 
120 	for (i = 0; i < 20; i++)
121 		vidconsole_putc_xy(con, VID_TO_POS(i * 8), 0, ' ' + i);
122 	ut_asserteq(273, compress_frame_buffer(dev));
123 
124 	vidconsole_set_row(con, 0, WHITE);
125 	ut_asserteq(46, compress_frame_buffer(dev));
126 
127 	for (i = 0; i < 20; i++)
128 		vidconsole_putc_xy(con, VID_TO_POS(i * 8), 0, ' ' + i);
129 	ut_asserteq(273, compress_frame_buffer(dev));
130 
131 	return 0;
132 }
133 DM_TEST(dm_test_video_text, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
134 
135 /* Test handling of special characters in the console */
dm_test_video_chars(struct unit_test_state * uts)136 static int dm_test_video_chars(struct unit_test_state *uts)
137 {
138 	struct udevice *dev, *con;
139 	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.";
140 
141 	ut_assertok(select_vidconsole(uts, "vidconsole0"));
142 	ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
143 	ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
144 	vidconsole_put_string(con, test_string);
145 	ut_asserteq(466, compress_frame_buffer(dev));
146 
147 	return 0;
148 }
149 DM_TEST(dm_test_video_chars, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
150 
151 #ifdef CONFIG_VIDEO_ANSI
152 #define ANSI_ESC "\x1b"
153 /* Test handling of ANSI escape sequences */
dm_test_video_ansi(struct unit_test_state * uts)154 static int dm_test_video_ansi(struct unit_test_state *uts)
155 {
156 	struct udevice *dev, *con;
157 
158 	ut_assertok(select_vidconsole(uts, "vidconsole0"));
159 	ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
160 	ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
161 
162 	/* reference clear: */
163 	video_clear(con->parent);
164 	video_sync(con->parent, false);
165 	ut_asserteq(46, compress_frame_buffer(dev));
166 
167 	/* test clear escape sequence: [2J */
168 	vidconsole_put_string(con, "A\tB\tC"ANSI_ESC"[2J");
169 	ut_asserteq(46, compress_frame_buffer(dev));
170 
171 	/* test set-cursor: [%d;%df */
172 	vidconsole_put_string(con, "abc"ANSI_ESC"[2;2fab"ANSI_ESC"[4;4fcd");
173 	ut_asserteq(143, compress_frame_buffer(dev));
174 
175 	/* test colors (30-37 fg color, 40-47 bg color) */
176 	vidconsole_put_string(con, ANSI_ESC"[30;41mfoo"); /* black on red */
177 	vidconsole_put_string(con, ANSI_ESC"[33;44mbar"); /* yellow on blue */
178 	ut_asserteq(272, compress_frame_buffer(dev));
179 
180 	return 0;
181 }
182 DM_TEST(dm_test_video_ansi, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
183 #endif
184 
185 /**
186  * check_vidconsole_output() - Run a text console test
187  *
188  * @uts:	Test state
189  * @rot:	Console rotation (0, 90, 180, 270)
190  * @wrap_size:	Expected size of compressed frame buffer for the wrap test
191  * @scroll_size: Same for the scroll test
192  * @return 0 on success
193  */
check_vidconsole_output(struct unit_test_state * uts,int rot,int wrap_size,int scroll_size)194 static int check_vidconsole_output(struct unit_test_state *uts, int rot,
195 				   int wrap_size, int scroll_size)
196 {
197 	struct udevice *dev, *con;
198 	struct sandbox_sdl_plat *plat;
199 	int i;
200 
201 	ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
202 	ut_assert(!device_active(dev));
203 	plat = dev_get_platdata(dev);
204 	plat->rot = rot;
205 
206 	ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
207 	ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
208 	ut_asserteq(46, compress_frame_buffer(dev));
209 
210 	/* Check display wrap */
211 	for (i = 0; i < 120; i++)
212 		vidconsole_put_char(con, 'A' + i % 50);
213 	ut_asserteq(wrap_size, compress_frame_buffer(dev));
214 
215 	/* Check display scrolling */
216 	for (i = 0; i < SCROLL_LINES; i++) {
217 		vidconsole_put_char(con, 'A' + i % 50);
218 		vidconsole_put_char(con, '\n');
219 	}
220 	ut_asserteq(scroll_size, compress_frame_buffer(dev));
221 
222 	/* If we scroll enough, the screen becomes blank again */
223 	for (i = 0; i < SCROLL_LINES; i++)
224 		vidconsole_put_char(con, '\n');
225 	ut_asserteq(46, compress_frame_buffer(dev));
226 
227 	return 0;
228 }
229 
230 /* Test text output through the console uclass */
dm_test_video_context(struct unit_test_state * uts)231 static int dm_test_video_context(struct unit_test_state *uts)
232 {
233 	ut_assertok(select_vidconsole(uts, "vidconsole0"));
234 	ut_assertok(check_vidconsole_output(uts, 0, 788, 453));
235 
236 	return 0;
237 }
238 DM_TEST(dm_test_video_context, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
239 
240 /* Test rotated text output through the console uclass */
dm_test_video_rotation1(struct unit_test_state * uts)241 static int dm_test_video_rotation1(struct unit_test_state *uts)
242 {
243 	ut_assertok(check_vidconsole_output(uts, 1, 1112, 680));
244 
245 	return 0;
246 }
247 DM_TEST(dm_test_video_rotation1, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
248 
249 /* Test rotated text output through the console uclass */
dm_test_video_rotation2(struct unit_test_state * uts)250 static int dm_test_video_rotation2(struct unit_test_state *uts)
251 {
252 	ut_assertok(check_vidconsole_output(uts, 2, 785, 446));
253 
254 	return 0;
255 }
256 DM_TEST(dm_test_video_rotation2, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
257 
258 /* Test rotated text output through the console uclass */
dm_test_video_rotation3(struct unit_test_state * uts)259 static int dm_test_video_rotation3(struct unit_test_state *uts)
260 {
261 	ut_assertok(check_vidconsole_output(uts, 3, 1134, 681));
262 
263 	return 0;
264 }
265 DM_TEST(dm_test_video_rotation3, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
266 
267 /* Read a file into memory and return a pointer to it */
read_file(struct unit_test_state * uts,const char * fname,ulong * addrp)268 static int read_file(struct unit_test_state *uts, const char *fname,
269 		     ulong *addrp)
270 {
271 	int buf_size = 100000;
272 	ulong addr = 0;
273 	int size, fd;
274 	char *buf;
275 
276 	buf = map_sysmem(addr, 0);
277 	ut_assert(buf != NULL);
278 	fd = os_open(fname, OS_O_RDONLY);
279 	ut_assert(fd >= 0);
280 	size = os_read(fd, buf, buf_size);
281 	os_close(fd);
282 	ut_assert(size >= 0);
283 	ut_assert(size < buf_size);
284 	*addrp = addr;
285 
286 	return 0;
287 }
288 
289 /* Test drawing a bitmap file */
dm_test_video_bmp(struct unit_test_state * uts)290 static int dm_test_video_bmp(struct unit_test_state *uts)
291 {
292 	struct udevice *dev;
293 	ulong addr;
294 
295 	ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
296 	ut_assertok(read_file(uts, "tools/logos/denx.bmp", &addr));
297 
298 	ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
299 	ut_asserteq(1368, compress_frame_buffer(dev));
300 
301 	return 0;
302 }
303 DM_TEST(dm_test_video_bmp, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
304 
305 /* Test drawing a compressed bitmap file */
dm_test_video_bmp_comp(struct unit_test_state * uts)306 static int dm_test_video_bmp_comp(struct unit_test_state *uts)
307 {
308 	struct udevice *dev;
309 	ulong addr;
310 
311 	ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
312 	ut_assertok(read_file(uts, "tools/logos/denx-comp.bmp", &addr));
313 
314 	ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
315 	ut_asserteq(1368, compress_frame_buffer(dev));
316 
317 	return 0;
318 }
319 DM_TEST(dm_test_video_bmp_comp, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
320 
321 /* Test TrueType console */
dm_test_video_truetype(struct unit_test_state * uts)322 static int dm_test_video_truetype(struct unit_test_state *uts)
323 {
324 	struct udevice *dev, *con;
325 	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";
326 
327 	ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
328 	ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
329 	vidconsole_put_string(con, test_string);
330 	ut_asserteq(12237, compress_frame_buffer(dev));
331 
332 	return 0;
333 }
334 DM_TEST(dm_test_video_truetype, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
335 
336 /* Test scrolling TrueType console */
dm_test_video_truetype_scroll(struct unit_test_state * uts)337 static int dm_test_video_truetype_scroll(struct unit_test_state *uts)
338 {
339 	struct sandbox_sdl_plat *plat;
340 	struct udevice *dev, *con;
341 	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";
342 
343 	ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
344 	ut_assert(!device_active(dev));
345 	plat = dev_get_platdata(dev);
346 	plat->font_size = 100;
347 
348 	ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
349 	ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
350 	vidconsole_put_string(con, test_string);
351 	ut_asserteq(35030, compress_frame_buffer(dev));
352 
353 	return 0;
354 }
355 DM_TEST(dm_test_video_truetype_scroll, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
356 
357 /* Test TrueType backspace, within and across lines */
dm_test_video_truetype_bs(struct unit_test_state * uts)358 static int dm_test_video_truetype_bs(struct unit_test_state *uts)
359 {
360 	struct sandbox_sdl_plat *plat;
361 	struct udevice *dev, *con;
362 	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.";
363 
364 	ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
365 	ut_assert(!device_active(dev));
366 	plat = dev_get_platdata(dev);
367 	plat->font_size = 100;
368 
369 	ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
370 	ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
371 	vidconsole_put_string(con, test_string);
372 	ut_asserteq(29018, compress_frame_buffer(dev));
373 
374 	return 0;
375 }
376 DM_TEST(dm_test_video_truetype_bs, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
377