dm: test: add test case for dev_read_u64 function
[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 <malloc.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 /* Test text output works on the video console */
102 static int dm_test_video_text(struct unit_test_state *uts)
103 {
104         struct udevice *dev, *con;
105         int i;
106
107 #define WHITE           0xffff
108 #define SCROLL_LINES    100
109
110         ut_assertok(select_vidconsole(uts, "vidconsole0"));
111         ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
112         ut_asserteq(46, compress_frame_buffer(dev));
113
114         ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
115         vidconsole_putc_xy(con, 0, 0, 'a');
116         ut_asserteq(79, compress_frame_buffer(dev));
117
118         vidconsole_putc_xy(con, 0, 0, ' ');
119         ut_asserteq(46, compress_frame_buffer(dev));
120
121         for (i = 0; i < 20; i++)
122                 vidconsole_putc_xy(con, VID_TO_POS(i * 8), 0, ' ' + i);
123         ut_asserteq(273, compress_frame_buffer(dev));
124
125         vidconsole_set_row(con, 0, WHITE);
126         ut_asserteq(46, compress_frame_buffer(dev));
127
128         for (i = 0; i < 20; i++)
129                 vidconsole_putc_xy(con, VID_TO_POS(i * 8), 0, ' ' + i);
130         ut_asserteq(273, compress_frame_buffer(dev));
131
132         return 0;
133 }
134 DM_TEST(dm_test_video_text, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
135
136 /* Test handling of special characters in the console */
137 static int dm_test_video_chars(struct unit_test_state *uts)
138 {
139         struct udevice *dev, *con;
140         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.";
141
142         ut_assertok(select_vidconsole(uts, "vidconsole0"));
143         ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
144         ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
145         vidconsole_put_string(con, test_string);
146         ut_asserteq(466, compress_frame_buffer(dev));
147
148         return 0;
149 }
150 DM_TEST(dm_test_video_chars, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
151
152 #ifdef CONFIG_VIDEO_ANSI
153 #define ANSI_ESC "\x1b"
154 /* Test handling of ANSI escape sequences */
155 static int dm_test_video_ansi(struct unit_test_state *uts)
156 {
157         struct udevice *dev, *con;
158
159         ut_assertok(select_vidconsole(uts, "vidconsole0"));
160         ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
161         ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
162
163         /* reference clear: */
164         video_clear(con->parent);
165         video_sync(con->parent, false);
166         ut_asserteq(46, compress_frame_buffer(dev));
167
168         /* test clear escape sequence: [2J */
169         vidconsole_put_string(con, "A\tB\tC"ANSI_ESC"[2J");
170         ut_asserteq(46, compress_frame_buffer(dev));
171
172         /* test set-cursor: [%d;%df */
173         vidconsole_put_string(con, "abc"ANSI_ESC"[2;2fab"ANSI_ESC"[4;4fcd");
174         ut_asserteq(143, compress_frame_buffer(dev));
175
176         /* test colors (30-37 fg color, 40-47 bg color) */
177         vidconsole_put_string(con, ANSI_ESC"[30;41mfoo"); /* black on red */
178         vidconsole_put_string(con, ANSI_ESC"[33;44mbar"); /* yellow on blue */
179         ut_asserteq(272, compress_frame_buffer(dev));
180
181         return 0;
182 }
183 DM_TEST(dm_test_video_ansi, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
184 #endif
185
186 /**
187  * check_vidconsole_output() - Run a text console test
188  *
189  * @uts:        Test state
190  * @rot:        Console rotation (0, 90, 180, 270)
191  * @wrap_size:  Expected size of compressed frame buffer for the wrap test
192  * @scroll_size: Same for the scroll test
193  * @return 0 on success
194  */
195 static int check_vidconsole_output(struct unit_test_state *uts, int rot,
196                                    int wrap_size, int scroll_size)
197 {
198         struct udevice *dev, *con;
199         struct sandbox_sdl_plat *plat;
200         int i;
201
202         ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
203         ut_assert(!device_active(dev));
204         plat = dev_get_platdata(dev);
205         plat->rot = rot;
206
207         ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
208         ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
209         ut_asserteq(46, compress_frame_buffer(dev));
210
211         /* Check display wrap */
212         for (i = 0; i < 120; i++)
213                 vidconsole_put_char(con, 'A' + i % 50);
214         ut_asserteq(wrap_size, compress_frame_buffer(dev));
215
216         /* Check display scrolling */
217         for (i = 0; i < SCROLL_LINES; i++) {
218                 vidconsole_put_char(con, 'A' + i % 50);
219                 vidconsole_put_char(con, '\n');
220         }
221         ut_asserteq(scroll_size, compress_frame_buffer(dev));
222
223         /* If we scroll enough, the screen becomes blank again */
224         for (i = 0; i < SCROLL_LINES; i++)
225                 vidconsole_put_char(con, '\n');
226         ut_asserteq(46, compress_frame_buffer(dev));
227
228         return 0;
229 }
230
231 /* Test text output through the console uclass */
232 static int dm_test_video_context(struct unit_test_state *uts)
233 {
234         ut_assertok(select_vidconsole(uts, "vidconsole0"));
235         ut_assertok(check_vidconsole_output(uts, 0, 788, 453));
236
237         return 0;
238 }
239 DM_TEST(dm_test_video_context, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
240
241 /* Test rotated text output through the console uclass */
242 static int dm_test_video_rotation1(struct unit_test_state *uts)
243 {
244         ut_assertok(check_vidconsole_output(uts, 1, 1112, 680));
245
246         return 0;
247 }
248 DM_TEST(dm_test_video_rotation1, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
249
250 /* Test rotated text output through the console uclass */
251 static int dm_test_video_rotation2(struct unit_test_state *uts)
252 {
253         ut_assertok(check_vidconsole_output(uts, 2, 785, 446));
254
255         return 0;
256 }
257 DM_TEST(dm_test_video_rotation2, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
258
259 /* Test rotated text output through the console uclass */
260 static int dm_test_video_rotation3(struct unit_test_state *uts)
261 {
262         ut_assertok(check_vidconsole_output(uts, 3, 1134, 681));
263
264         return 0;
265 }
266 DM_TEST(dm_test_video_rotation3, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
267
268 /* Read a file into memory and return a pointer to it */
269 static int read_file(struct unit_test_state *uts, const char *fname,
270                      ulong *addrp)
271 {
272         int buf_size = 100000;
273         ulong addr = 0;
274         int size, fd;
275         char *buf;
276
277         buf = map_sysmem(addr, 0);
278         ut_assert(buf != NULL);
279         fd = os_open(fname, OS_O_RDONLY);
280         ut_assert(fd >= 0);
281         size = os_read(fd, buf, buf_size);
282         os_close(fd);
283         ut_assert(size >= 0);
284         ut_assert(size < buf_size);
285         *addrp = addr;
286
287         return 0;
288 }
289
290 /* Test drawing a bitmap file */
291 static int dm_test_video_bmp(struct unit_test_state *uts)
292 {
293         struct udevice *dev;
294         ulong addr;
295
296         ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
297         ut_assertok(read_file(uts, "tools/logos/denx.bmp", &addr));
298
299         ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
300         ut_asserteq(1368, compress_frame_buffer(dev));
301
302         return 0;
303 }
304 DM_TEST(dm_test_video_bmp, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
305
306 /* Test drawing a compressed bitmap file */
307 static int dm_test_video_bmp_comp(struct unit_test_state *uts)
308 {
309         struct udevice *dev;
310         ulong addr;
311
312         ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
313         ut_assertok(read_file(uts, "tools/logos/denx-comp.bmp", &addr));
314
315         ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
316         ut_asserteq(1368, compress_frame_buffer(dev));
317
318         return 0;
319 }
320 DM_TEST(dm_test_video_bmp_comp, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
321
322 /* Test TrueType console */
323 static int dm_test_video_truetype(struct unit_test_state *uts)
324 {
325         struct udevice *dev, *con;
326         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";
327
328         ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
329         ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
330         vidconsole_put_string(con, test_string);
331         ut_asserteq(12237, compress_frame_buffer(dev));
332
333         return 0;
334 }
335 DM_TEST(dm_test_video_truetype, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
336
337 /* Test scrolling TrueType console */
338 static int dm_test_video_truetype_scroll(struct unit_test_state *uts)
339 {
340         struct sandbox_sdl_plat *plat;
341         struct udevice *dev, *con;
342         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";
343
344         ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
345         ut_assert(!device_active(dev));
346         plat = dev_get_platdata(dev);
347         plat->font_size = 100;
348
349         ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
350         ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
351         vidconsole_put_string(con, test_string);
352         ut_asserteq(35030, compress_frame_buffer(dev));
353
354         return 0;
355 }
356 DM_TEST(dm_test_video_truetype_scroll, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
357
358 /* Test TrueType backspace, within and across lines */
359 static int dm_test_video_truetype_bs(struct unit_test_state *uts)
360 {
361         struct sandbox_sdl_plat *plat;
362         struct udevice *dev, *con;
363         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.";
364
365         ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
366         ut_assert(!device_active(dev));
367         plat = dev_get_platdata(dev);
368         plat->font_size = 100;
369
370         ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
371         ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
372         vidconsole_put_string(con, test_string);
373         ut_asserteq(29018, compress_frame_buffer(dev));
374
375         return 0;
376 }
377 DM_TEST(dm_test_video_truetype_bs, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);