blob: 29917d0c2d831beaf2387db1cfd9d5651f999af2 [file] [log] [blame]
Simon Glass90b6fef2016-01-18 19:52:26 -07001/*
2 * Copyright (c) 2014 Google, Inc
3 * Written by Simon Glass <sjg@chromium.org>
4 *
5 * SPDX-License-Identifier: GPL-2.0+
6 */
7
8#include <common.h>
9#include <bzlib.h>
10#include <dm.h>
11#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 */
27DECLARE_GLOBAL_DATA_PTR;
28
29/* Basic test of the video uclass */
30static 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}
43DM_TEST(dm_test_video_base, DM_TESTF_SCAN_PDATA | DM_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 * @dev: Video device
56 * @return compressed size of the frame buffer, or -ve on error
57 */
58static int compress_frame_buffer(struct udevice *dev)
59{
60 struct video_priv *priv = dev_get_uclass_priv(dev);
61 uint destlen;
62 void *dest;
63 int ret;
64
65 destlen = priv->fb_size;
66 dest = malloc(priv->fb_size);
67 if (!dest)
68 return -ENOMEM;
69 ret = BZ2_bzBuffToBuffCompress(dest, &destlen,
70 priv->fb, priv->fb_size,
71 3, 0, 0);
72 free(dest);
73 if (ret)
74 return ret;
75
76 return destlen;
77}
78
79/*
80 * Call this function at any point to halt and show the current display. Be
81 * sure to run the test with the -l flag.
82 */
83static void __maybe_unused see_output(void)
84{
85 video_sync_all();
86 while (1);
87}
88
Simon Glassdaac9c72016-01-14 18:10:50 -070089/* Select the video console driver to use for a video device */
90static int select_vidconsole(struct unit_test_state *uts, const char *drv_name)
91{
92 struct sandbox_sdl_plat *plat;
93 struct udevice *dev;
94
95 ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
96 ut_assert(!device_active(dev));
97 plat = dev_get_platdata(dev);
98 plat->vidconsole_drv_name = "vidconsole0";
99
100 return 0;
101}
102
Rob Clark985935b2017-09-25 15:45:08 -0400103static void vidconsole_put_string(struct udevice *dev, const char *str)
104{
105 const char *s;
106
107 for (s = str; *s; s++)
108 vidconsole_put_char(dev, *s);
109}
110
Simon Glass90b6fef2016-01-18 19:52:26 -0700111/* Test text output works on the video console */
112static int dm_test_video_text(struct unit_test_state *uts)
113{
114 struct udevice *dev, *con;
115 int i;
116
117#define WHITE 0xffff
118#define SCROLL_LINES 100
119
Simon Glassdaac9c72016-01-14 18:10:50 -0700120 ut_assertok(select_vidconsole(uts, "vidconsole0"));
Simon Glass90b6fef2016-01-18 19:52:26 -0700121 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
122 ut_asserteq(46, compress_frame_buffer(dev));
123
124 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
125 vidconsole_putc_xy(con, 0, 0, 'a');
126 ut_asserteq(79, compress_frame_buffer(dev));
127
128 vidconsole_putc_xy(con, 0, 0, ' ');
129 ut_asserteq(46, compress_frame_buffer(dev));
130
131 for (i = 0; i < 20; i++)
Simon Glass52c10c52016-01-14 18:10:37 -0700132 vidconsole_putc_xy(con, VID_TO_POS(i * 8), 0, ' ' + i);
Simon Glass90b6fef2016-01-18 19:52:26 -0700133 ut_asserteq(273, compress_frame_buffer(dev));
134
135 vidconsole_set_row(con, 0, WHITE);
136 ut_asserteq(46, compress_frame_buffer(dev));
137
138 for (i = 0; i < 20; i++)
Simon Glass52c10c52016-01-14 18:10:37 -0700139 vidconsole_putc_xy(con, VID_TO_POS(i * 8), 0, ' ' + i);
Simon Glass90b6fef2016-01-18 19:52:26 -0700140 ut_asserteq(273, compress_frame_buffer(dev));
141
142 return 0;
143}
144DM_TEST(dm_test_video_text, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
145
146/* Test handling of special characters in the console */
147static int dm_test_video_chars(struct unit_test_state *uts)
148{
149 struct udevice *dev, *con;
Simon Glass37b80202016-01-14 18:10:38 -0700150 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 -0700151
Simon Glassdaac9c72016-01-14 18:10:50 -0700152 ut_assertok(select_vidconsole(uts, "vidconsole0"));
Simon Glass90b6fef2016-01-18 19:52:26 -0700153 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
154 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
Rob Clark985935b2017-09-25 15:45:08 -0400155 vidconsole_put_string(con, test_string);
Simon Glass90b6fef2016-01-18 19:52:26 -0700156 ut_asserteq(466, compress_frame_buffer(dev));
157
158 return 0;
159}
160DM_TEST(dm_test_video_chars, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
161
Rob Clark09d64b32017-09-25 15:45:09 -0400162#ifdef CONFIG_VIDEO_ANSI
163#define ANSI_ESC "\x1b"
164/* Test handling of ANSI escape sequences */
165static int dm_test_video_ansi(struct unit_test_state *uts)
166{
167 struct udevice *dev, *con;
168
169 ut_assertok(select_vidconsole(uts, "vidconsole0"));
170 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
171 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
172
173 /* reference clear: */
174 video_clear(con->parent);
175 video_sync(con->parent);
176 ut_asserteq(46, compress_frame_buffer(dev));
177
178 /* test clear escape sequence: [2J */
179 vidconsole_put_string(con, "A\tB\tC"ANSI_ESC"[2J");
180 ut_asserteq(46, compress_frame_buffer(dev));
181
182 /* test set-cursor: [%d;%df */
183 vidconsole_put_string(con, "abc"ANSI_ESC"[2;2fab"ANSI_ESC"[4;4fcd");
184 ut_asserteq(142, compress_frame_buffer(dev));
185
186 /* test colors (30-37 fg color, 40-47 bg color) */
187 vidconsole_put_string(con, ANSI_ESC"[30;41mfoo"); /* black on red */
188 vidconsole_put_string(con, ANSI_ESC"[33;44mbar"); /* yellow on blue */
189 ut_asserteq(268, compress_frame_buffer(dev));
190
191 return 0;
192}
193DM_TEST(dm_test_video_ansi, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
194#endif
195
Simon Glass90b6fef2016-01-18 19:52:26 -0700196/**
197 * check_vidconsole_output() - Run a text console test
198 *
199 * @uts: Test state
200 * @rot: Console rotation (0, 90, 180, 270)
201 * @wrap_size: Expected size of compressed frame buffer for the wrap test
202 * @scroll_size: Same for the scroll test
203 * @return 0 on success
204 */
205static int check_vidconsole_output(struct unit_test_state *uts, int rot,
206 int wrap_size, int scroll_size)
207{
208 struct udevice *dev, *con;
209 struct sandbox_sdl_plat *plat;
210 int i;
211
212 ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
213 ut_assert(!device_active(dev));
214 plat = dev_get_platdata(dev);
215 plat->rot = rot;
216
217 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
218 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
219 ut_asserteq(46, compress_frame_buffer(dev));
220
221 /* Check display wrap */
222 for (i = 0; i < 120; i++)
223 vidconsole_put_char(con, 'A' + i % 50);
224 ut_asserteq(wrap_size, compress_frame_buffer(dev));
225
226 /* Check display scrolling */
227 for (i = 0; i < SCROLL_LINES; i++) {
228 vidconsole_put_char(con, 'A' + i % 50);
229 vidconsole_put_char(con, '\n');
230 }
231 ut_asserteq(scroll_size, compress_frame_buffer(dev));
232
233 /* If we scroll enough, the screen becomes blank again */
234 for (i = 0; i < SCROLL_LINES; i++)
235 vidconsole_put_char(con, '\n');
236 ut_asserteq(46, compress_frame_buffer(dev));
237
238 return 0;
239}
240
241/* Test text output through the console uclass */
242static int dm_test_video_context(struct unit_test_state *uts)
243{
Simon Glassdaac9c72016-01-14 18:10:50 -0700244 ut_assertok(select_vidconsole(uts, "vidconsole0"));
245 ut_assertok(check_vidconsole_output(uts, 0, 788, 453));
246
247 return 0;
Simon Glass90b6fef2016-01-18 19:52:26 -0700248}
249DM_TEST(dm_test_video_context, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
Simon Glassa0f1efe2016-01-18 19:52:27 -0700250
251/* Test rotated text output through the console uclass */
252static int dm_test_video_rotation1(struct unit_test_state *uts)
253{
254 ut_assertok(check_vidconsole_output(uts, 1, 1112, 680));
255
256 return 0;
257}
258DM_TEST(dm_test_video_rotation1, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
259
260/* Test rotated text output through the console uclass */
261static int dm_test_video_rotation2(struct unit_test_state *uts)
262{
263 ut_assertok(check_vidconsole_output(uts, 2, 785, 446));
264
265 return 0;
266}
267DM_TEST(dm_test_video_rotation2, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
268
269/* Test rotated text output through the console uclass */
270static int dm_test_video_rotation3(struct unit_test_state *uts)
271{
272 ut_assertok(check_vidconsole_output(uts, 3, 1134, 681));
273
274 return 0;
275}
276DM_TEST(dm_test_video_rotation3, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
Simon Glass7a1cb292016-01-18 19:52:28 -0700277
278/* Read a file into memory and return a pointer to it */
279static int read_file(struct unit_test_state *uts, const char *fname,
280 ulong *addrp)
281{
282 int buf_size = 100000;
283 ulong addr = 0;
284 int size, fd;
285 char *buf;
286
287 buf = map_sysmem(addr, 0);
288 ut_assert(buf != NULL);
289 fd = os_open(fname, OS_O_RDONLY);
290 ut_assert(fd >= 0);
291 size = os_read(fd, buf, buf_size);
Simon Glass9050c5f2016-01-30 15:45:17 -0700292 os_close(fd);
Simon Glass7a1cb292016-01-18 19:52:28 -0700293 ut_assert(size >= 0);
294 ut_assert(size < buf_size);
Simon Glass7a1cb292016-01-18 19:52:28 -0700295 *addrp = addr;
296
297 return 0;
298}
299
300/* Test drawing a bitmap file */
301static int dm_test_video_bmp(struct unit_test_state *uts)
302{
303 struct udevice *dev;
304 ulong addr;
305
306 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
307 ut_assertok(read_file(uts, "tools/logos/denx.bmp", &addr));
308
309 ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
310 ut_asserteq(1368, compress_frame_buffer(dev));
311
312 return 0;
313}
314DM_TEST(dm_test_video_bmp, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
315
316/* Test drawing a compressed bitmap file */
317static int dm_test_video_bmp_comp(struct unit_test_state *uts)
318{
319 struct udevice *dev;
320 ulong addr;
321
322 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
323 ut_assertok(read_file(uts, "tools/logos/denx-comp.bmp", &addr));
324
325 ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
326 ut_asserteq(1368, compress_frame_buffer(dev));
327
328 return 0;
329}
330DM_TEST(dm_test_video_bmp_comp, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
Simon Glass32337982016-01-14 18:10:51 -0700331
332/* Test TrueType console */
333static int dm_test_video_truetype(struct unit_test_state *uts)
334{
335 struct udevice *dev, *con;
336 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 -0700337
338 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
339 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
Rob Clark985935b2017-09-25 15:45:08 -0400340 vidconsole_put_string(con, test_string);
Simon Glass32337982016-01-14 18:10:51 -0700341 ut_asserteq(12619, compress_frame_buffer(dev));
342
343 return 0;
344}
345DM_TEST(dm_test_video_truetype, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
346
347/* Test scrolling TrueType console */
348static int dm_test_video_truetype_scroll(struct unit_test_state *uts)
349{
350 struct sandbox_sdl_plat *plat;
351 struct udevice *dev, *con;
352 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 -0700353
354 ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
355 ut_assert(!device_active(dev));
356 plat = dev_get_platdata(dev);
357 plat->font_size = 100;
358
359 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
360 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
Rob Clark985935b2017-09-25 15:45:08 -0400361 vidconsole_put_string(con, test_string);
Simon Glass32337982016-01-14 18:10:51 -0700362 ut_asserteq(33849, compress_frame_buffer(dev));
363
364 return 0;
365}
366DM_TEST(dm_test_video_truetype_scroll, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
367
368/* Test TrueType backspace, within and across lines */
369static int dm_test_video_truetype_bs(struct unit_test_state *uts)
370{
371 struct sandbox_sdl_plat *plat;
372 struct udevice *dev, *con;
373 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 -0700374
375 ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
376 ut_assert(!device_active(dev));
377 plat = dev_get_platdata(dev);
378 plat->font_size = 100;
379
380 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
381 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
Rob Clark985935b2017-09-25 15:45:08 -0400382 vidconsole_put_string(con, test_string);
Simon Glass32337982016-01-14 18:10:51 -0700383 ut_asserteq(34871, compress_frame_buffer(dev));
384
385 return 0;
386}
387DM_TEST(dm_test_video_truetype_bs, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);