blob: 0664e3f22b3ca825e8235d8f3091674a6c77ccaf [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Simon Glass3c97c4f2016-01-18 19:52:26 -07002/*
3 * Copyright (c) 2014 Google, Inc
4 * Written by Simon Glass <sjg@chromium.org>
Simon Glass3c97c4f2016-01-18 19:52:26 -07005 */
6
7#include <common.h>
8#include <bzlib.h>
9#include <dm.h>
Simon Glassf7ae49f2020-05-10 11:40:05 -060010#include <log.h>
Simon Glass336d4612020-02-03 07:36:16 -070011#include <malloc.h>
Simon Glass3c97c4f2016-01-18 19:52:26 -070012#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 */
Simon Glass3c97c4f2016-01-18 19:52:26 -070028/* Basic test of the video uclass */
29static 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}
42DM_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 */
57static 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 */
82static void __maybe_unused see_output(void)
83{
84 video_sync_all();
85 while (1);
86}
87
Simon Glass8df8dad2016-01-14 18:10:50 -070088/* Select the video console driver to use for a video device */
89static 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
Simon Glass3c97c4f2016-01-18 19:52:26 -0700102/* Test text output works on the video console */
103static 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
Simon Glass8df8dad2016-01-14 18:10:50 -0700111 ut_assertok(select_vidconsole(uts, "vidconsole0"));
Simon Glass3c97c4f2016-01-18 19:52:26 -0700112 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++)
Simon Glassf2661782016-01-14 18:10:37 -0700123 vidconsole_putc_xy(con, VID_TO_POS(i * 8), 0, ' ' + i);
Simon Glass3c97c4f2016-01-18 19:52:26 -0700124 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++)
Simon Glassf2661782016-01-14 18:10:37 -0700130 vidconsole_putc_xy(con, VID_TO_POS(i * 8), 0, ' ' + i);
Simon Glass3c97c4f2016-01-18 19:52:26 -0700131 ut_asserteq(273, compress_frame_buffer(dev));
132
133 return 0;
134}
135DM_TEST(dm_test_video_text, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
136
137/* Test handling of special characters in the console */
138static int dm_test_video_chars(struct unit_test_state *uts)
139{
140 struct udevice *dev, *con;
Simon Glass5508f102016-01-14 18:10:38 -0700141 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.";
Simon Glass3c97c4f2016-01-18 19:52:26 -0700142
Simon Glass8df8dad2016-01-14 18:10:50 -0700143 ut_assertok(select_vidconsole(uts, "vidconsole0"));
Simon Glass3c97c4f2016-01-18 19:52:26 -0700144 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
145 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
Rob Clarka7495ac2017-09-25 15:45:08 -0400146 vidconsole_put_string(con, test_string);
Simon Glass3c97c4f2016-01-18 19:52:26 -0700147 ut_asserteq(466, compress_frame_buffer(dev));
148
149 return 0;
150}
151DM_TEST(dm_test_video_chars, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
152
Rob Clark40186ee2017-09-25 15:45:09 -0400153#ifdef CONFIG_VIDEO_ANSI
154#define ANSI_ESC "\x1b"
155/* Test handling of ANSI escape sequences */
156static 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);
Simon Glass55d39912018-10-01 11:55:14 -0600166 video_sync(con->parent, false);
Rob Clark40186ee2017-09-25 15:45:09 -0400167 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");
Heinrich Schuchardt118f0202018-11-10 19:55:48 +0100175 ut_asserteq(143, compress_frame_buffer(dev));
Rob Clark40186ee2017-09-25 15:45:09 -0400176
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 */
Heinrich Schuchardt118f0202018-11-10 19:55:48 +0100180 ut_asserteq(272, compress_frame_buffer(dev));
Rob Clark40186ee2017-09-25 15:45:09 -0400181
182 return 0;
183}
184DM_TEST(dm_test_video_ansi, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
185#endif
186
Simon Glass3c97c4f2016-01-18 19:52:26 -0700187/**
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 */
196static 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 */
233static int dm_test_video_context(struct unit_test_state *uts)
234{
Simon Glass8df8dad2016-01-14 18:10:50 -0700235 ut_assertok(select_vidconsole(uts, "vidconsole0"));
236 ut_assertok(check_vidconsole_output(uts, 0, 788, 453));
237
238 return 0;
Simon Glass3c97c4f2016-01-18 19:52:26 -0700239}
240DM_TEST(dm_test_video_context, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
Simon Glass85e08db2016-01-18 19:52:27 -0700241
242/* Test rotated text output through the console uclass */
243static 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}
249DM_TEST(dm_test_video_rotation1, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
250
251/* Test rotated text output through the console uclass */
252static 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}
258DM_TEST(dm_test_video_rotation2, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
259
260/* Test rotated text output through the console uclass */
261static 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}
267DM_TEST(dm_test_video_rotation3, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
Simon Glass747440d2016-01-18 19:52:28 -0700268
269/* Read a file into memory and return a pointer to it */
270static 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);
Simon Glassa1080822016-01-30 15:45:17 -0700283 os_close(fd);
Simon Glass747440d2016-01-18 19:52:28 -0700284 ut_assert(size >= 0);
285 ut_assert(size < buf_size);
Simon Glass747440d2016-01-18 19:52:28 -0700286 *addrp = addr;
287
288 return 0;
289}
290
291/* Test drawing a bitmap file */
292static 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}
305DM_TEST(dm_test_video_bmp, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
306
307/* Test drawing a compressed bitmap file */
308static 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}
321DM_TEST(dm_test_video_bmp_comp, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
Simon Glass5674ead2016-01-14 18:10:51 -0700322
323/* Test TrueType console */
324static 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";
Simon Glass5674ead2016-01-14 18:10:51 -0700328
329 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
330 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
Rob Clarka7495ac2017-09-25 15:45:08 -0400331 vidconsole_put_string(con, test_string);
Anatolij Gustschindaaba082018-12-29 00:31:45 +0100332 ut_asserteq(12237, compress_frame_buffer(dev));
Simon Glass5674ead2016-01-14 18:10:51 -0700333
334 return 0;
335}
336DM_TEST(dm_test_video_truetype, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
337
338/* Test scrolling TrueType console */
339static 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";
Simon Glass5674ead2016-01-14 18:10:51 -0700344
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));
Rob Clarka7495ac2017-09-25 15:45:08 -0400352 vidconsole_put_string(con, test_string);
Anatolij Gustschindaaba082018-12-29 00:31:45 +0100353 ut_asserteq(35030, compress_frame_buffer(dev));
Simon Glass5674ead2016-01-14 18:10:51 -0700354
355 return 0;
356}
357DM_TEST(dm_test_video_truetype_scroll, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
358
359/* Test TrueType backspace, within and across lines */
360static 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.";
Simon Glass5674ead2016-01-14 18:10:51 -0700365
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));
Rob Clarka7495ac2017-09-25 15:45:08 -0400373 vidconsole_put_string(con, test_string);
Anatolij Gustschindaaba082018-12-29 00:31:45 +0100374 ut_asserteq(29018, compress_frame_buffer(dev));
Simon Glass5674ead2016-01-14 18:10:51 -0700375
376 return 0;
377}
378DM_TEST(dm_test_video_truetype_bs, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);