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