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