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