blob: f72979fac4ee895598acac4fc4917673ca85bc59 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Simon Glass90b6fef2016-01-18 19:52:26 -07002/*
3 * Copyright (c) 2014 Google, Inc
4 * Written by Simon Glass <sjg@chromium.org>
Simon Glass90b6fef2016-01-18 19:52:26 -07005 */
6
7#include <common.h>
8#include <bzlib.h>
9#include <dm.h>
Simon Glass9bc15642020-02-03 07:36:16 -070010#include <malloc.h>
Simon Glass90b6fef2016-01-18 19:52:26 -070011#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 */
Simon Glass90b6fef2016-01-18 19:52:26 -070027/* Basic test of the video uclass */
28static 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}
41DM_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 */
56static 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 */
81static void __maybe_unused see_output(void)
82{
83 video_sync_all();
84 while (1);
85}
86
Simon Glassdaac9c72016-01-14 18:10:50 -070087/* Select the video console driver to use for a video device */
88static 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
Simon Glass90b6fef2016-01-18 19:52:26 -0700101/* Test text output works on the video console */
102static 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
Simon Glassdaac9c72016-01-14 18:10:50 -0700110 ut_assertok(select_vidconsole(uts, "vidconsole0"));
Simon Glass90b6fef2016-01-18 19:52:26 -0700111 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++)
Simon Glass52c10c52016-01-14 18:10:37 -0700122 vidconsole_putc_xy(con, VID_TO_POS(i * 8), 0, ' ' + i);
Simon Glass90b6fef2016-01-18 19:52:26 -0700123 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++)
Simon Glass52c10c52016-01-14 18:10:37 -0700129 vidconsole_putc_xy(con, VID_TO_POS(i * 8), 0, ' ' + i);
Simon Glass90b6fef2016-01-18 19:52:26 -0700130 ut_asserteq(273, compress_frame_buffer(dev));
131
132 return 0;
133}
134DM_TEST(dm_test_video_text, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
135
136/* Test handling of special characters in the console */
137static int dm_test_video_chars(struct unit_test_state *uts)
138{
139 struct udevice *dev, *con;
Simon Glass37b80202016-01-14 18:10:38 -0700140 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 Glass90b6fef2016-01-18 19:52:26 -0700141
Simon Glassdaac9c72016-01-14 18:10:50 -0700142 ut_assertok(select_vidconsole(uts, "vidconsole0"));
Simon Glass90b6fef2016-01-18 19:52:26 -0700143 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
144 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
Rob Clark985935b2017-09-25 15:45:08 -0400145 vidconsole_put_string(con, test_string);
Simon Glass90b6fef2016-01-18 19:52:26 -0700146 ut_asserteq(466, compress_frame_buffer(dev));
147
148 return 0;
149}
150DM_TEST(dm_test_video_chars, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
151
Rob Clark09d64b32017-09-25 15:45:09 -0400152#ifdef CONFIG_VIDEO_ANSI
153#define ANSI_ESC "\x1b"
154/* Test handling of ANSI escape sequences */
155static 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);
Simon Glass0806dcc2018-10-01 11:55:14 -0600165 video_sync(con->parent, false);
Rob Clark09d64b32017-09-25 15:45:09 -0400166 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");
Heinrich Schuchardtc3c69302018-11-10 19:55:48 +0100174 ut_asserteq(143, compress_frame_buffer(dev));
Rob Clark09d64b32017-09-25 15:45:09 -0400175
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 */
Heinrich Schuchardtc3c69302018-11-10 19:55:48 +0100179 ut_asserteq(272, compress_frame_buffer(dev));
Rob Clark09d64b32017-09-25 15:45:09 -0400180
181 return 0;
182}
183DM_TEST(dm_test_video_ansi, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
184#endif
185
Simon Glass90b6fef2016-01-18 19:52:26 -0700186/**
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 */
195static 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 */
232static int dm_test_video_context(struct unit_test_state *uts)
233{
Simon Glassdaac9c72016-01-14 18:10:50 -0700234 ut_assertok(select_vidconsole(uts, "vidconsole0"));
235 ut_assertok(check_vidconsole_output(uts, 0, 788, 453));
236
237 return 0;
Simon Glass90b6fef2016-01-18 19:52:26 -0700238}
239DM_TEST(dm_test_video_context, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
Simon Glassa0f1efe2016-01-18 19:52:27 -0700240
241/* Test rotated text output through the console uclass */
242static 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}
248DM_TEST(dm_test_video_rotation1, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
249
250/* Test rotated text output through the console uclass */
251static 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}
257DM_TEST(dm_test_video_rotation2, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
258
259/* Test rotated text output through the console uclass */
260static 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}
266DM_TEST(dm_test_video_rotation3, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
Simon Glass7a1cb292016-01-18 19:52:28 -0700267
268/* Read a file into memory and return a pointer to it */
269static 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);
Simon Glass9050c5f2016-01-30 15:45:17 -0700282 os_close(fd);
Simon Glass7a1cb292016-01-18 19:52:28 -0700283 ut_assert(size >= 0);
284 ut_assert(size < buf_size);
Simon Glass7a1cb292016-01-18 19:52:28 -0700285 *addrp = addr;
286
287 return 0;
288}
289
290/* Test drawing a bitmap file */
291static 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}
304DM_TEST(dm_test_video_bmp, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
305
306/* Test drawing a compressed bitmap file */
307static 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}
320DM_TEST(dm_test_video_bmp_comp, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
Simon Glass32337982016-01-14 18:10:51 -0700321
322/* Test TrueType console */
323static 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";
Simon Glass32337982016-01-14 18:10:51 -0700327
328 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
329 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
Rob Clark985935b2017-09-25 15:45:08 -0400330 vidconsole_put_string(con, test_string);
Anatolij Gustschinf744a552018-12-29 00:31:45 +0100331 ut_asserteq(12237, compress_frame_buffer(dev));
Simon Glass32337982016-01-14 18:10:51 -0700332
333 return 0;
334}
335DM_TEST(dm_test_video_truetype, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
336
337/* Test scrolling TrueType console */
338static 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";
Simon Glass32337982016-01-14 18:10:51 -0700343
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));
Rob Clark985935b2017-09-25 15:45:08 -0400351 vidconsole_put_string(con, test_string);
Anatolij Gustschinf744a552018-12-29 00:31:45 +0100352 ut_asserteq(35030, compress_frame_buffer(dev));
Simon Glass32337982016-01-14 18:10:51 -0700353
354 return 0;
355}
356DM_TEST(dm_test_video_truetype_scroll, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
357
358/* Test TrueType backspace, within and across lines */
359static 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.";
Simon Glass32337982016-01-14 18:10:51 -0700364
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));
Rob Clark985935b2017-09-25 15:45:08 -0400372 vidconsole_put_string(con, test_string);
Anatolij Gustschinf744a552018-12-29 00:31:45 +0100373 ut_asserteq(29018, compress_frame_buffer(dev));
Simon Glass32337982016-01-14 18:10:51 -0700374
375 return 0;
376}
377DM_TEST(dm_test_video_truetype_bs, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);