blob: 19f78b6239084232bc30c4609e499cde9017558a [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 *
Simon Glassf578ca72020-07-02 21:12:29 -060054 * If the copy framebuffer is enabled, this compares it to the main framebuffer
55 * too.
56 *
57 * @uts: Test state
Simon Glass3c97c4f2016-01-18 19:52:26 -070058 * @dev: Video device
59 * @return compressed size of the frame buffer, or -ve on error
60 */
Simon Glassf578ca72020-07-02 21:12:29 -060061static int compress_frame_buffer(struct unit_test_state *uts,
62 struct udevice *dev)
Simon Glass3c97c4f2016-01-18 19:52:26 -070063{
64 struct video_priv *priv = dev_get_uclass_priv(dev);
Simon Glassf578ca72020-07-02 21:12:29 -060065 struct video_priv *uc_priv = dev_get_uclass_priv(dev);
Simon Glass3c97c4f2016-01-18 19:52:26 -070066 uint destlen;
67 void *dest;
68 int ret;
69
70 destlen = priv->fb_size;
71 dest = malloc(priv->fb_size);
72 if (!dest)
73 return -ENOMEM;
74 ret = BZ2_bzBuffToBuffCompress(dest, &destlen,
75 priv->fb, priv->fb_size,
76 3, 0, 0);
77 free(dest);
78 if (ret)
79 return ret;
80
Simon Glassf578ca72020-07-02 21:12:29 -060081 /* Check here that the copy frame buffer is working correctly */
82 if (IS_ENABLED(CONFIG_VIDEO_COPY)) {
83 ut_assertf(!memcmp(uc_priv->fb, uc_priv->copy_fb,
84 uc_priv->fb_size),
85 "Copy framebuffer does not match fb");
86 }
87
Simon Glass3c97c4f2016-01-18 19:52:26 -070088 return destlen;
89}
90
91/*
92 * Call this function at any point to halt and show the current display. Be
93 * sure to run the test with the -l flag.
94 */
95static void __maybe_unused see_output(void)
96{
97 video_sync_all();
98 while (1);
99}
100
Simon Glass8df8dad2016-01-14 18:10:50 -0700101/* Select the video console driver to use for a video device */
102static int select_vidconsole(struct unit_test_state *uts, const char *drv_name)
103{
104 struct sandbox_sdl_plat *plat;
105 struct udevice *dev;
106
107 ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
108 ut_assert(!device_active(dev));
109 plat = dev_get_platdata(dev);
110 plat->vidconsole_drv_name = "vidconsole0";
111
112 return 0;
113}
114
Simon Glass3c97c4f2016-01-18 19:52:26 -0700115/* Test text output works on the video console */
116static int dm_test_video_text(struct unit_test_state *uts)
117{
118 struct udevice *dev, *con;
119 int i;
120
121#define WHITE 0xffff
122#define SCROLL_LINES 100
123
Simon Glass8df8dad2016-01-14 18:10:50 -0700124 ut_assertok(select_vidconsole(uts, "vidconsole0"));
Simon Glass3c97c4f2016-01-18 19:52:26 -0700125 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
Simon Glassf578ca72020-07-02 21:12:29 -0600126 ut_asserteq(46, compress_frame_buffer(uts, dev));
Simon Glass3c97c4f2016-01-18 19:52:26 -0700127
128 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
129 vidconsole_putc_xy(con, 0, 0, 'a');
Simon Glassf578ca72020-07-02 21:12:29 -0600130 ut_asserteq(79, compress_frame_buffer(uts, dev));
Simon Glass3c97c4f2016-01-18 19:52:26 -0700131
132 vidconsole_putc_xy(con, 0, 0, ' ');
Simon Glassf578ca72020-07-02 21:12:29 -0600133 ut_asserteq(46, compress_frame_buffer(uts, dev));
Simon Glass3c97c4f2016-01-18 19:52:26 -0700134
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 Glassf578ca72020-07-02 21:12:29 -0600137 ut_asserteq(273, compress_frame_buffer(uts, dev));
Simon Glass3c97c4f2016-01-18 19:52:26 -0700138
139 vidconsole_set_row(con, 0, WHITE);
Simon Glassf578ca72020-07-02 21:12:29 -0600140 ut_asserteq(46, compress_frame_buffer(uts, dev));
Simon Glass3c97c4f2016-01-18 19:52:26 -0700141
142 for (i = 0; i < 20; i++)
Simon Glassf2661782016-01-14 18:10:37 -0700143 vidconsole_putc_xy(con, VID_TO_POS(i * 8), 0, ' ' + i);
Simon Glassf578ca72020-07-02 21:12:29 -0600144 ut_asserteq(273, compress_frame_buffer(uts, dev));
Simon Glass3c97c4f2016-01-18 19:52:26 -0700145
146 return 0;
147}
148DM_TEST(dm_test_video_text, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
149
150/* Test handling of special characters in the console */
151static int dm_test_video_chars(struct unit_test_state *uts)
152{
153 struct udevice *dev, *con;
Simon Glass5508f102016-01-14 18:10:38 -0700154 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 -0700155
Simon Glass8df8dad2016-01-14 18:10:50 -0700156 ut_assertok(select_vidconsole(uts, "vidconsole0"));
Simon Glass3c97c4f2016-01-18 19:52:26 -0700157 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
158 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
Rob Clarka7495ac2017-09-25 15:45:08 -0400159 vidconsole_put_string(con, test_string);
Simon Glassf578ca72020-07-02 21:12:29 -0600160 ut_asserteq(466, compress_frame_buffer(uts, dev));
Simon Glass3c97c4f2016-01-18 19:52:26 -0700161
162 return 0;
163}
164DM_TEST(dm_test_video_chars, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
165
Rob Clark40186ee2017-09-25 15:45:09 -0400166#ifdef CONFIG_VIDEO_ANSI
167#define ANSI_ESC "\x1b"
168/* Test handling of ANSI escape sequences */
169static int dm_test_video_ansi(struct unit_test_state *uts)
170{
171 struct udevice *dev, *con;
172
173 ut_assertok(select_vidconsole(uts, "vidconsole0"));
174 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
175 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
176
177 /* reference clear: */
178 video_clear(con->parent);
Simon Glass55d39912018-10-01 11:55:14 -0600179 video_sync(con->parent, false);
Simon Glassf578ca72020-07-02 21:12:29 -0600180 ut_asserteq(46, compress_frame_buffer(uts, dev));
Rob Clark40186ee2017-09-25 15:45:09 -0400181
182 /* test clear escape sequence: [2J */
183 vidconsole_put_string(con, "A\tB\tC"ANSI_ESC"[2J");
Simon Glassf578ca72020-07-02 21:12:29 -0600184 ut_asserteq(46, compress_frame_buffer(uts, dev));
Rob Clark40186ee2017-09-25 15:45:09 -0400185
186 /* test set-cursor: [%d;%df */
187 vidconsole_put_string(con, "abc"ANSI_ESC"[2;2fab"ANSI_ESC"[4;4fcd");
Simon Glassf578ca72020-07-02 21:12:29 -0600188 ut_asserteq(143, compress_frame_buffer(uts, dev));
Rob Clark40186ee2017-09-25 15:45:09 -0400189
190 /* test colors (30-37 fg color, 40-47 bg color) */
191 vidconsole_put_string(con, ANSI_ESC"[30;41mfoo"); /* black on red */
192 vidconsole_put_string(con, ANSI_ESC"[33;44mbar"); /* yellow on blue */
Simon Glassf578ca72020-07-02 21:12:29 -0600193 ut_asserteq(272, compress_frame_buffer(uts, dev));
Rob Clark40186ee2017-09-25 15:45:09 -0400194
195 return 0;
196}
197DM_TEST(dm_test_video_ansi, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
198#endif
199
Simon Glass3c97c4f2016-01-18 19:52:26 -0700200/**
201 * check_vidconsole_output() - Run a text console test
202 *
203 * @uts: Test state
Simon Glassef453122020-07-02 21:12:28 -0600204 * @rot: Console rotation (0=normal orientation, 1=90 degrees clockwise,
205 * 2=upside down, 3=90 degree counterclockwise)
Simon Glass3c97c4f2016-01-18 19:52:26 -0700206 * @wrap_size: Expected size of compressed frame buffer for the wrap test
207 * @scroll_size: Same for the scroll test
208 * @return 0 on success
209 */
210static int check_vidconsole_output(struct unit_test_state *uts, int rot,
211 int wrap_size, int scroll_size)
212{
213 struct udevice *dev, *con;
214 struct sandbox_sdl_plat *plat;
215 int i;
216
217 ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
218 ut_assert(!device_active(dev));
219 plat = dev_get_platdata(dev);
220 plat->rot = rot;
221
222 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
223 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
Simon Glassf578ca72020-07-02 21:12:29 -0600224 ut_asserteq(46, compress_frame_buffer(uts, dev));
Simon Glass3c97c4f2016-01-18 19:52:26 -0700225
226 /* Check display wrap */
227 for (i = 0; i < 120; i++)
228 vidconsole_put_char(con, 'A' + i % 50);
Simon Glassf578ca72020-07-02 21:12:29 -0600229 ut_asserteq(wrap_size, compress_frame_buffer(uts, dev));
Simon Glass3c97c4f2016-01-18 19:52:26 -0700230
231 /* Check display scrolling */
232 for (i = 0; i < SCROLL_LINES; i++) {
233 vidconsole_put_char(con, 'A' + i % 50);
234 vidconsole_put_char(con, '\n');
235 }
Simon Glassf578ca72020-07-02 21:12:29 -0600236 ut_asserteq(scroll_size, compress_frame_buffer(uts, dev));
Simon Glass3c97c4f2016-01-18 19:52:26 -0700237
238 /* If we scroll enough, the screen becomes blank again */
239 for (i = 0; i < SCROLL_LINES; i++)
240 vidconsole_put_char(con, '\n');
Simon Glassf578ca72020-07-02 21:12:29 -0600241 ut_asserteq(46, compress_frame_buffer(uts, dev));
Simon Glass3c97c4f2016-01-18 19:52:26 -0700242
243 return 0;
244}
245
246/* Test text output through the console uclass */
247static int dm_test_video_context(struct unit_test_state *uts)
248{
Simon Glass8df8dad2016-01-14 18:10:50 -0700249 ut_assertok(select_vidconsole(uts, "vidconsole0"));
250 ut_assertok(check_vidconsole_output(uts, 0, 788, 453));
251
252 return 0;
Simon Glass3c97c4f2016-01-18 19:52:26 -0700253}
254DM_TEST(dm_test_video_context, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
Simon Glass85e08db2016-01-18 19:52:27 -0700255
256/* Test rotated text output through the console uclass */
257static int dm_test_video_rotation1(struct unit_test_state *uts)
258{
259 ut_assertok(check_vidconsole_output(uts, 1, 1112, 680));
260
261 return 0;
262}
263DM_TEST(dm_test_video_rotation1, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
264
265/* Test rotated text output through the console uclass */
266static int dm_test_video_rotation2(struct unit_test_state *uts)
267{
Simon Glass9beb3642020-07-02 21:12:17 -0600268 ut_assertok(check_vidconsole_output(uts, 2, 783, 445));
Simon Glass85e08db2016-01-18 19:52:27 -0700269
270 return 0;
271}
272DM_TEST(dm_test_video_rotation2, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
273
274/* Test rotated text output through the console uclass */
275static int dm_test_video_rotation3(struct unit_test_state *uts)
276{
277 ut_assertok(check_vidconsole_output(uts, 3, 1134, 681));
278
279 return 0;
280}
281DM_TEST(dm_test_video_rotation3, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
Simon Glass747440d2016-01-18 19:52:28 -0700282
283/* Read a file into memory and return a pointer to it */
284static int read_file(struct unit_test_state *uts, const char *fname,
285 ulong *addrp)
286{
287 int buf_size = 100000;
288 ulong addr = 0;
289 int size, fd;
290 char *buf;
291
292 buf = map_sysmem(addr, 0);
293 ut_assert(buf != NULL);
294 fd = os_open(fname, OS_O_RDONLY);
295 ut_assert(fd >= 0);
296 size = os_read(fd, buf, buf_size);
Simon Glassa1080822016-01-30 15:45:17 -0700297 os_close(fd);
Simon Glass747440d2016-01-18 19:52:28 -0700298 ut_assert(size >= 0);
299 ut_assert(size < buf_size);
Simon Glass747440d2016-01-18 19:52:28 -0700300 *addrp = addr;
301
302 return 0;
303}
304
305/* Test drawing a bitmap file */
306static int dm_test_video_bmp(struct unit_test_state *uts)
307{
308 struct udevice *dev;
309 ulong addr;
310
311 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
312 ut_assertok(read_file(uts, "tools/logos/denx.bmp", &addr));
313
314 ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
Simon Glassf578ca72020-07-02 21:12:29 -0600315 ut_asserteq(1368, compress_frame_buffer(uts, dev));
Simon Glass747440d2016-01-18 19:52:28 -0700316
317 return 0;
318}
319DM_TEST(dm_test_video_bmp, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
320
321/* Test drawing a compressed bitmap file */
322static int dm_test_video_bmp_comp(struct unit_test_state *uts)
323{
324 struct udevice *dev;
325 ulong addr;
326
327 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
328 ut_assertok(read_file(uts, "tools/logos/denx-comp.bmp", &addr));
329
330 ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
Simon Glassf578ca72020-07-02 21:12:29 -0600331 ut_asserteq(1368, compress_frame_buffer(uts, dev));
Simon Glass747440d2016-01-18 19:52:28 -0700332
333 return 0;
334}
335DM_TEST(dm_test_video_bmp_comp, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
Simon Glass5674ead2016-01-14 18:10:51 -0700336
337/* Test TrueType console */
338static int dm_test_video_truetype(struct unit_test_state *uts)
339{
340 struct udevice *dev, *con;
341 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 -0700342
343 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
344 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
Rob Clarka7495ac2017-09-25 15:45:08 -0400345 vidconsole_put_string(con, test_string);
Simon Glassf578ca72020-07-02 21:12:29 -0600346 ut_asserteq(12237, compress_frame_buffer(uts, dev));
Simon Glass5674ead2016-01-14 18:10:51 -0700347
348 return 0;
349}
350DM_TEST(dm_test_video_truetype, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
351
352/* Test scrolling TrueType console */
353static int dm_test_video_truetype_scroll(struct unit_test_state *uts)
354{
355 struct sandbox_sdl_plat *plat;
356 struct udevice *dev, *con;
357 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 -0700358
359 ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
360 ut_assert(!device_active(dev));
361 plat = dev_get_platdata(dev);
362 plat->font_size = 100;
363
364 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
365 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
Rob Clarka7495ac2017-09-25 15:45:08 -0400366 vidconsole_put_string(con, test_string);
Simon Glassf578ca72020-07-02 21:12:29 -0600367 ut_asserteq(35030, compress_frame_buffer(uts, dev));
Simon Glass5674ead2016-01-14 18:10:51 -0700368
369 return 0;
370}
371DM_TEST(dm_test_video_truetype_scroll, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
372
373/* Test TrueType backspace, within and across lines */
374static int dm_test_video_truetype_bs(struct unit_test_state *uts)
375{
376 struct sandbox_sdl_plat *plat;
377 struct udevice *dev, *con;
378 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 -0700379
380 ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
381 ut_assert(!device_active(dev));
382 plat = dev_get_platdata(dev);
383 plat->font_size = 100;
384
385 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
386 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
Rob Clarka7495ac2017-09-25 15:45:08 -0400387 vidconsole_put_string(con, test_string);
Simon Glassf578ca72020-07-02 21:12:29 -0600388 ut_asserteq(29018, compress_frame_buffer(uts, dev));
Simon Glass5674ead2016-01-14 18:10:51 -0700389
390 return 0;
391}
392DM_TEST(dm_test_video_truetype_bs, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);