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