dm: devres: Add a new OFDATA phase
[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 <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 */
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  */
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  */
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 */
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 */
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 */
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 */
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  */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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);