blob: 6be5defc53c9177a99445668a4765b1818d21bdb [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>
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 */
Simon Glass3c97c4f2016-01-18 19:52:26 -070026/* Basic test of the video uclass */
27static 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}
40DM_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 */
55static 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 */
80static void __maybe_unused see_output(void)
81{
82 video_sync_all();
83 while (1);
84}
85
Simon Glass8df8dad2016-01-14 18:10:50 -070086/* Select the video console driver to use for a video device */
87static 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
Rob Clarka7495ac2017-09-25 15:45:08 -0400100static void vidconsole_put_string(struct udevice *dev, const char *str)
101{
102 const char *s;
103
104 for (s = str; *s; s++)
105 vidconsole_put_char(dev, *s);
106}
107
Simon Glass3c97c4f2016-01-18 19:52:26 -0700108/* Test text output works on the video console */
109static int dm_test_video_text(struct unit_test_state *uts)
110{
111 struct udevice *dev, *con;
112 int i;
113
114#define WHITE 0xffff
115#define SCROLL_LINES 100
116
Simon Glass8df8dad2016-01-14 18:10:50 -0700117 ut_assertok(select_vidconsole(uts, "vidconsole0"));
Simon Glass3c97c4f2016-01-18 19:52:26 -0700118 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
119 ut_asserteq(46, compress_frame_buffer(dev));
120
121 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
122 vidconsole_putc_xy(con, 0, 0, 'a');
123 ut_asserteq(79, compress_frame_buffer(dev));
124
125 vidconsole_putc_xy(con, 0, 0, ' ');
126 ut_asserteq(46, compress_frame_buffer(dev));
127
128 for (i = 0; i < 20; i++)
Simon Glassf2661782016-01-14 18:10:37 -0700129 vidconsole_putc_xy(con, VID_TO_POS(i * 8), 0, ' ' + i);
Simon Glass3c97c4f2016-01-18 19:52:26 -0700130 ut_asserteq(273, compress_frame_buffer(dev));
131
132 vidconsole_set_row(con, 0, WHITE);
133 ut_asserteq(46, compress_frame_buffer(dev));
134
135 for (i = 0; i < 20; i++)
Simon Glassf2661782016-01-14 18:10:37 -0700136 vidconsole_putc_xy(con, VID_TO_POS(i * 8), 0, ' ' + i);
Simon Glass3c97c4f2016-01-18 19:52:26 -0700137 ut_asserteq(273, compress_frame_buffer(dev));
138
139 return 0;
140}
141DM_TEST(dm_test_video_text, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
142
143/* Test handling of special characters in the console */
144static int dm_test_video_chars(struct unit_test_state *uts)
145{
146 struct udevice *dev, *con;
Simon Glass5508f102016-01-14 18:10:38 -0700147 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 -0700148
Simon Glass8df8dad2016-01-14 18:10:50 -0700149 ut_assertok(select_vidconsole(uts, "vidconsole0"));
Simon Glass3c97c4f2016-01-18 19:52:26 -0700150 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
151 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
Rob Clarka7495ac2017-09-25 15:45:08 -0400152 vidconsole_put_string(con, test_string);
Simon Glass3c97c4f2016-01-18 19:52:26 -0700153 ut_asserteq(466, compress_frame_buffer(dev));
154
155 return 0;
156}
157DM_TEST(dm_test_video_chars, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
158
Rob Clark40186ee2017-09-25 15:45:09 -0400159#ifdef CONFIG_VIDEO_ANSI
160#define ANSI_ESC "\x1b"
161/* Test handling of ANSI escape sequences */
162static int dm_test_video_ansi(struct unit_test_state *uts)
163{
164 struct udevice *dev, *con;
165
166 ut_assertok(select_vidconsole(uts, "vidconsole0"));
167 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
168 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
169
170 /* reference clear: */
171 video_clear(con->parent);
Simon Glass55d39912018-10-01 11:55:14 -0600172 video_sync(con->parent, false);
Rob Clark40186ee2017-09-25 15:45:09 -0400173 ut_asserteq(46, compress_frame_buffer(dev));
174
175 /* test clear escape sequence: [2J */
176 vidconsole_put_string(con, "A\tB\tC"ANSI_ESC"[2J");
177 ut_asserteq(46, compress_frame_buffer(dev));
178
179 /* test set-cursor: [%d;%df */
180 vidconsole_put_string(con, "abc"ANSI_ESC"[2;2fab"ANSI_ESC"[4;4fcd");
Heinrich Schuchardt118f0202018-11-10 19:55:48 +0100181 ut_asserteq(143, compress_frame_buffer(dev));
Rob Clark40186ee2017-09-25 15:45:09 -0400182
183 /* test colors (30-37 fg color, 40-47 bg color) */
184 vidconsole_put_string(con, ANSI_ESC"[30;41mfoo"); /* black on red */
185 vidconsole_put_string(con, ANSI_ESC"[33;44mbar"); /* yellow on blue */
Heinrich Schuchardt118f0202018-11-10 19:55:48 +0100186 ut_asserteq(272, compress_frame_buffer(dev));
Rob Clark40186ee2017-09-25 15:45:09 -0400187
188 return 0;
189}
190DM_TEST(dm_test_video_ansi, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
191#endif
192
Simon Glass3c97c4f2016-01-18 19:52:26 -0700193/**
194 * check_vidconsole_output() - Run a text console test
195 *
196 * @uts: Test state
197 * @rot: Console rotation (0, 90, 180, 270)
198 * @wrap_size: Expected size of compressed frame buffer for the wrap test
199 * @scroll_size: Same for the scroll test
200 * @return 0 on success
201 */
202static int check_vidconsole_output(struct unit_test_state *uts, int rot,
203 int wrap_size, int scroll_size)
204{
205 struct udevice *dev, *con;
206 struct sandbox_sdl_plat *plat;
207 int i;
208
209 ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
210 ut_assert(!device_active(dev));
211 plat = dev_get_platdata(dev);
212 plat->rot = rot;
213
214 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
215 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
216 ut_asserteq(46, compress_frame_buffer(dev));
217
218 /* Check display wrap */
219 for (i = 0; i < 120; i++)
220 vidconsole_put_char(con, 'A' + i % 50);
221 ut_asserteq(wrap_size, compress_frame_buffer(dev));
222
223 /* Check display scrolling */
224 for (i = 0; i < SCROLL_LINES; i++) {
225 vidconsole_put_char(con, 'A' + i % 50);
226 vidconsole_put_char(con, '\n');
227 }
228 ut_asserteq(scroll_size, compress_frame_buffer(dev));
229
230 /* If we scroll enough, the screen becomes blank again */
231 for (i = 0; i < SCROLL_LINES; i++)
232 vidconsole_put_char(con, '\n');
233 ut_asserteq(46, compress_frame_buffer(dev));
234
235 return 0;
236}
237
238/* Test text output through the console uclass */
239static int dm_test_video_context(struct unit_test_state *uts)
240{
Simon Glass8df8dad2016-01-14 18:10:50 -0700241 ut_assertok(select_vidconsole(uts, "vidconsole0"));
242 ut_assertok(check_vidconsole_output(uts, 0, 788, 453));
243
244 return 0;
Simon Glass3c97c4f2016-01-18 19:52:26 -0700245}
246DM_TEST(dm_test_video_context, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
Simon Glass85e08db2016-01-18 19:52:27 -0700247
248/* Test rotated text output through the console uclass */
249static int dm_test_video_rotation1(struct unit_test_state *uts)
250{
251 ut_assertok(check_vidconsole_output(uts, 1, 1112, 680));
252
253 return 0;
254}
255DM_TEST(dm_test_video_rotation1, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
256
257/* Test rotated text output through the console uclass */
258static int dm_test_video_rotation2(struct unit_test_state *uts)
259{
260 ut_assertok(check_vidconsole_output(uts, 2, 785, 446));
261
262 return 0;
263}
264DM_TEST(dm_test_video_rotation2, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
265
266/* Test rotated text output through the console uclass */
267static int dm_test_video_rotation3(struct unit_test_state *uts)
268{
269 ut_assertok(check_vidconsole_output(uts, 3, 1134, 681));
270
271 return 0;
272}
273DM_TEST(dm_test_video_rotation3, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
Simon Glass747440d2016-01-18 19:52:28 -0700274
275/* Read a file into memory and return a pointer to it */
276static int read_file(struct unit_test_state *uts, const char *fname,
277 ulong *addrp)
278{
279 int buf_size = 100000;
280 ulong addr = 0;
281 int size, fd;
282 char *buf;
283
284 buf = map_sysmem(addr, 0);
285 ut_assert(buf != NULL);
286 fd = os_open(fname, OS_O_RDONLY);
287 ut_assert(fd >= 0);
288 size = os_read(fd, buf, buf_size);
Simon Glassa1080822016-01-30 15:45:17 -0700289 os_close(fd);
Simon Glass747440d2016-01-18 19:52:28 -0700290 ut_assert(size >= 0);
291 ut_assert(size < buf_size);
Simon Glass747440d2016-01-18 19:52:28 -0700292 *addrp = addr;
293
294 return 0;
295}
296
297/* Test drawing a bitmap file */
298static int dm_test_video_bmp(struct unit_test_state *uts)
299{
300 struct udevice *dev;
301 ulong addr;
302
303 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
304 ut_assertok(read_file(uts, "tools/logos/denx.bmp", &addr));
305
306 ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
307 ut_asserteq(1368, compress_frame_buffer(dev));
308
309 return 0;
310}
311DM_TEST(dm_test_video_bmp, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
312
313/* Test drawing a compressed bitmap file */
314static int dm_test_video_bmp_comp(struct unit_test_state *uts)
315{
316 struct udevice *dev;
317 ulong addr;
318
319 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
320 ut_assertok(read_file(uts, "tools/logos/denx-comp.bmp", &addr));
321
322 ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
323 ut_asserteq(1368, compress_frame_buffer(dev));
324
325 return 0;
326}
327DM_TEST(dm_test_video_bmp_comp, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
Simon Glass5674ead2016-01-14 18:10:51 -0700328
329/* Test TrueType console */
330static int dm_test_video_truetype(struct unit_test_state *uts)
331{
332 struct udevice *dev, *con;
333 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 -0700334
335 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
336 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
Rob Clarka7495ac2017-09-25 15:45:08 -0400337 vidconsole_put_string(con, test_string);
Anatolij Gustschindaaba082018-12-29 00:31:45 +0100338 ut_asserteq(12237, compress_frame_buffer(dev));
Simon Glass5674ead2016-01-14 18:10:51 -0700339
340 return 0;
341}
342DM_TEST(dm_test_video_truetype, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
343
344/* Test scrolling TrueType console */
345static int dm_test_video_truetype_scroll(struct unit_test_state *uts)
346{
347 struct sandbox_sdl_plat *plat;
348 struct udevice *dev, *con;
349 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 -0700350
351 ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
352 ut_assert(!device_active(dev));
353 plat = dev_get_platdata(dev);
354 plat->font_size = 100;
355
356 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
357 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
Rob Clarka7495ac2017-09-25 15:45:08 -0400358 vidconsole_put_string(con, test_string);
Anatolij Gustschindaaba082018-12-29 00:31:45 +0100359 ut_asserteq(35030, compress_frame_buffer(dev));
Simon Glass5674ead2016-01-14 18:10:51 -0700360
361 return 0;
362}
363DM_TEST(dm_test_video_truetype_scroll, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
364
365/* Test TrueType backspace, within and across lines */
366static int dm_test_video_truetype_bs(struct unit_test_state *uts)
367{
368 struct sandbox_sdl_plat *plat;
369 struct udevice *dev, *con;
370 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 -0700371
372 ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
373 ut_assert(!device_active(dev));
374 plat = dev_get_platdata(dev);
375 plat->font_size = 100;
376
377 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
378 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
Rob Clarka7495ac2017-09-25 15:45:08 -0400379 vidconsole_put_string(con, test_string);
Anatolij Gustschindaaba082018-12-29 00:31:45 +0100380 ut_asserteq(29018, compress_frame_buffer(dev));
Simon Glass5674ead2016-01-14 18:10:51 -0700381
382 return 0;
383}
384DM_TEST(dm_test_video_truetype_bs, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);