blob: 9523a0173dc997ca7a0344623f9a5aa26e0d727f [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 Glass0f2af882020-05-10 11:40:05 -060010#include <log.h>
Simon Glass9bc15642020-02-03 07:36:16 -070011#include <malloc.h>
Simon Glass90b6fef2016-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>
Simon Glass75c4d412020-07-19 10:15:37 -060018#include <test/test.h>
Simon Glass90b6fef2016-01-18 19:52:26 -070019#include <test/ut.h>
20
21/*
22 * These tests use the standard sandbox frame buffer, the resolution of which
23 * is defined in the device tree. This only supports 16bpp so the tests only
24 * test that code path. It would be possible to adjust this fairly easily,
25 * by adjusting the bpix value in struct sandbox_sdl_plat. However the code
26 * in sandbox_sdl_sync() would also need to change to handle the different
27 * surface depth.
28 */
Simon Glass90b6fef2016-01-18 19:52:26 -070029/* 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 *
Simon Glass2a0f8e32020-07-02 21:12:29 -060055 * If the copy framebuffer is enabled, this compares it to the main framebuffer
56 * too.
57 *
58 * @uts: Test state
Simon Glass90b6fef2016-01-18 19:52:26 -070059 * @dev: Video device
60 * @return compressed size of the frame buffer, or -ve on error
61 */
Simon Glass2a0f8e32020-07-02 21:12:29 -060062static int compress_frame_buffer(struct unit_test_state *uts,
63 struct udevice *dev)
Simon Glass90b6fef2016-01-18 19:52:26 -070064{
65 struct video_priv *priv = dev_get_uclass_priv(dev);
Simon Glass2a0f8e32020-07-02 21:12:29 -060066 struct video_priv *uc_priv = dev_get_uclass_priv(dev);
Simon Glass90b6fef2016-01-18 19:52:26 -070067 uint destlen;
68 void *dest;
69 int ret;
70
71 destlen = priv->fb_size;
72 dest = malloc(priv->fb_size);
73 if (!dest)
74 return -ENOMEM;
75 ret = BZ2_bzBuffToBuffCompress(dest, &destlen,
76 priv->fb, priv->fb_size,
77 3, 0, 0);
78 free(dest);
79 if (ret)
80 return ret;
81
Simon Glass2a0f8e32020-07-02 21:12:29 -060082 /* Check here that the copy frame buffer is working correctly */
83 if (IS_ENABLED(CONFIG_VIDEO_COPY)) {
84 ut_assertf(!memcmp(uc_priv->fb, uc_priv->copy_fb,
85 uc_priv->fb_size),
86 "Copy framebuffer does not match fb");
87 }
88
Simon Glass90b6fef2016-01-18 19:52:26 -070089 return destlen;
90}
91
92/*
93 * Call this function at any point to halt and show the current display. Be
94 * sure to run the test with the -l flag.
95 */
96static void __maybe_unused see_output(void)
97{
98 video_sync_all();
99 while (1);
100}
101
Simon Glassdaac9c72016-01-14 18:10:50 -0700102/* Select the video console driver to use for a video device */
103static int select_vidconsole(struct unit_test_state *uts, const char *drv_name)
104{
105 struct sandbox_sdl_plat *plat;
106 struct udevice *dev;
107
108 ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
109 ut_assert(!device_active(dev));
110 plat = dev_get_platdata(dev);
111 plat->vidconsole_drv_name = "vidconsole0";
112
113 return 0;
114}
115
Simon Glass90b6fef2016-01-18 19:52:26 -0700116/* Test text output works on the video console */
117static int dm_test_video_text(struct unit_test_state *uts)
118{
119 struct udevice *dev, *con;
120 int i;
121
122#define WHITE 0xffff
123#define SCROLL_LINES 100
124
Simon Glassdaac9c72016-01-14 18:10:50 -0700125 ut_assertok(select_vidconsole(uts, "vidconsole0"));
Simon Glass90b6fef2016-01-18 19:52:26 -0700126 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
Simon Glass2a0f8e32020-07-02 21:12:29 -0600127 ut_asserteq(46, compress_frame_buffer(uts, dev));
Simon Glass90b6fef2016-01-18 19:52:26 -0700128
129 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
130 vidconsole_putc_xy(con, 0, 0, 'a');
Simon Glass2a0f8e32020-07-02 21:12:29 -0600131 ut_asserteq(79, compress_frame_buffer(uts, dev));
Simon Glass90b6fef2016-01-18 19:52:26 -0700132
133 vidconsole_putc_xy(con, 0, 0, ' ');
Simon Glass2a0f8e32020-07-02 21:12:29 -0600134 ut_asserteq(46, compress_frame_buffer(uts, dev));
Simon Glass90b6fef2016-01-18 19:52:26 -0700135
136 for (i = 0; i < 20; i++)
Simon Glass52c10c52016-01-14 18:10:37 -0700137 vidconsole_putc_xy(con, VID_TO_POS(i * 8), 0, ' ' + i);
Simon Glass2a0f8e32020-07-02 21:12:29 -0600138 ut_asserteq(273, compress_frame_buffer(uts, dev));
Simon Glass90b6fef2016-01-18 19:52:26 -0700139
140 vidconsole_set_row(con, 0, WHITE);
Simon Glass2a0f8e32020-07-02 21:12:29 -0600141 ut_asserteq(46, compress_frame_buffer(uts, dev));
Simon Glass90b6fef2016-01-18 19:52:26 -0700142
143 for (i = 0; i < 20; i++)
Simon Glass52c10c52016-01-14 18:10:37 -0700144 vidconsole_putc_xy(con, VID_TO_POS(i * 8), 0, ' ' + i);
Simon Glass2a0f8e32020-07-02 21:12:29 -0600145 ut_asserteq(273, compress_frame_buffer(uts, dev));
Simon Glass90b6fef2016-01-18 19:52:26 -0700146
147 return 0;
148}
149DM_TEST(dm_test_video_text, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
150
151/* Test handling of special characters in the console */
152static int dm_test_video_chars(struct unit_test_state *uts)
153{
154 struct udevice *dev, *con;
Simon Glass37b80202016-01-14 18:10:38 -0700155 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 -0700156
Simon Glassdaac9c72016-01-14 18:10:50 -0700157 ut_assertok(select_vidconsole(uts, "vidconsole0"));
Simon Glass90b6fef2016-01-18 19:52:26 -0700158 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
159 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
Rob Clark985935b2017-09-25 15:45:08 -0400160 vidconsole_put_string(con, test_string);
Simon Glass2a0f8e32020-07-02 21:12:29 -0600161 ut_asserteq(466, compress_frame_buffer(uts, dev));
Simon Glass90b6fef2016-01-18 19:52:26 -0700162
163 return 0;
164}
165DM_TEST(dm_test_video_chars, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
166
Rob Clark09d64b32017-09-25 15:45:09 -0400167#ifdef CONFIG_VIDEO_ANSI
168#define ANSI_ESC "\x1b"
169/* Test handling of ANSI escape sequences */
170static int dm_test_video_ansi(struct unit_test_state *uts)
171{
172 struct udevice *dev, *con;
173
174 ut_assertok(select_vidconsole(uts, "vidconsole0"));
175 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
176 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
177
178 /* reference clear: */
179 video_clear(con->parent);
Simon Glass0806dcc2018-10-01 11:55:14 -0600180 video_sync(con->parent, false);
Simon Glass2a0f8e32020-07-02 21:12:29 -0600181 ut_asserteq(46, compress_frame_buffer(uts, dev));
Rob Clark09d64b32017-09-25 15:45:09 -0400182
183 /* test clear escape sequence: [2J */
184 vidconsole_put_string(con, "A\tB\tC"ANSI_ESC"[2J");
Simon Glass2a0f8e32020-07-02 21:12:29 -0600185 ut_asserteq(46, compress_frame_buffer(uts, dev));
Rob Clark09d64b32017-09-25 15:45:09 -0400186
187 /* test set-cursor: [%d;%df */
188 vidconsole_put_string(con, "abc"ANSI_ESC"[2;2fab"ANSI_ESC"[4;4fcd");
Simon Glass2a0f8e32020-07-02 21:12:29 -0600189 ut_asserteq(143, compress_frame_buffer(uts, dev));
Rob Clark09d64b32017-09-25 15:45:09 -0400190
191 /* test colors (30-37 fg color, 40-47 bg color) */
192 vidconsole_put_string(con, ANSI_ESC"[30;41mfoo"); /* black on red */
193 vidconsole_put_string(con, ANSI_ESC"[33;44mbar"); /* yellow on blue */
Simon Glass2a0f8e32020-07-02 21:12:29 -0600194 ut_asserteq(272, compress_frame_buffer(uts, dev));
Rob Clark09d64b32017-09-25 15:45:09 -0400195
196 return 0;
197}
198DM_TEST(dm_test_video_ansi, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
199#endif
200
Simon Glass90b6fef2016-01-18 19:52:26 -0700201/**
202 * check_vidconsole_output() - Run a text console test
203 *
204 * @uts: Test state
Simon Glass4425bf42020-07-02 21:12:28 -0600205 * @rot: Console rotation (0=normal orientation, 1=90 degrees clockwise,
206 * 2=upside down, 3=90 degree counterclockwise)
Simon Glass90b6fef2016-01-18 19:52:26 -0700207 * @wrap_size: Expected size of compressed frame buffer for the wrap test
208 * @scroll_size: Same for the scroll test
209 * @return 0 on success
210 */
211static int check_vidconsole_output(struct unit_test_state *uts, int rot,
212 int wrap_size, int scroll_size)
213{
214 struct udevice *dev, *con;
215 struct sandbox_sdl_plat *plat;
216 int i;
217
218 ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
219 ut_assert(!device_active(dev));
220 plat = dev_get_platdata(dev);
221 plat->rot = rot;
222
223 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
224 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
Simon Glass2a0f8e32020-07-02 21:12:29 -0600225 ut_asserteq(46, compress_frame_buffer(uts, dev));
Simon Glass90b6fef2016-01-18 19:52:26 -0700226
227 /* Check display wrap */
228 for (i = 0; i < 120; i++)
229 vidconsole_put_char(con, 'A' + i % 50);
Simon Glass2a0f8e32020-07-02 21:12:29 -0600230 ut_asserteq(wrap_size, compress_frame_buffer(uts, dev));
Simon Glass90b6fef2016-01-18 19:52:26 -0700231
232 /* Check display scrolling */
233 for (i = 0; i < SCROLL_LINES; i++) {
234 vidconsole_put_char(con, 'A' + i % 50);
235 vidconsole_put_char(con, '\n');
236 }
Simon Glass2a0f8e32020-07-02 21:12:29 -0600237 ut_asserteq(scroll_size, compress_frame_buffer(uts, dev));
Simon Glass90b6fef2016-01-18 19:52:26 -0700238
239 /* If we scroll enough, the screen becomes blank again */
240 for (i = 0; i < SCROLL_LINES; i++)
241 vidconsole_put_char(con, '\n');
Simon Glass2a0f8e32020-07-02 21:12:29 -0600242 ut_asserteq(46, compress_frame_buffer(uts, dev));
Simon Glass90b6fef2016-01-18 19:52:26 -0700243
244 return 0;
245}
246
247/* Test text output through the console uclass */
248static int dm_test_video_context(struct unit_test_state *uts)
249{
Simon Glassdaac9c72016-01-14 18:10:50 -0700250 ut_assertok(select_vidconsole(uts, "vidconsole0"));
251 ut_assertok(check_vidconsole_output(uts, 0, 788, 453));
252
253 return 0;
Simon Glass90b6fef2016-01-18 19:52:26 -0700254}
255DM_TEST(dm_test_video_context, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
Simon Glassa0f1efe2016-01-18 19:52:27 -0700256
257/* Test rotated text output through the console uclass */
258static int dm_test_video_rotation1(struct unit_test_state *uts)
259{
260 ut_assertok(check_vidconsole_output(uts, 1, 1112, 680));
261
262 return 0;
263}
264DM_TEST(dm_test_video_rotation1, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
265
266/* Test rotated text output through the console uclass */
267static int dm_test_video_rotation2(struct unit_test_state *uts)
268{
Simon Glassf50a6b92020-07-02 21:12:17 -0600269 ut_assertok(check_vidconsole_output(uts, 2, 783, 445));
Simon Glassa0f1efe2016-01-18 19:52:27 -0700270
271 return 0;
272}
273DM_TEST(dm_test_video_rotation2, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
274
275/* Test rotated text output through the console uclass */
276static int dm_test_video_rotation3(struct unit_test_state *uts)
277{
278 ut_assertok(check_vidconsole_output(uts, 3, 1134, 681));
279
280 return 0;
281}
282DM_TEST(dm_test_video_rotation3, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
Simon Glass7a1cb292016-01-18 19:52:28 -0700283
284/* Read a file into memory and return a pointer to it */
285static int read_file(struct unit_test_state *uts, const char *fname,
286 ulong *addrp)
287{
288 int buf_size = 100000;
289 ulong addr = 0;
290 int size, fd;
291 char *buf;
292
293 buf = map_sysmem(addr, 0);
294 ut_assert(buf != NULL);
295 fd = os_open(fname, OS_O_RDONLY);
296 ut_assert(fd >= 0);
297 size = os_read(fd, buf, buf_size);
Simon Glass9050c5f2016-01-30 15:45:17 -0700298 os_close(fd);
Simon Glass7a1cb292016-01-18 19:52:28 -0700299 ut_assert(size >= 0);
300 ut_assert(size < buf_size);
Simon Glass7a1cb292016-01-18 19:52:28 -0700301 *addrp = addr;
302
303 return 0;
304}
305
306/* Test drawing a bitmap file */
307static int dm_test_video_bmp(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.bmp", &addr));
314
315 ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
Simon Glass2a0f8e32020-07-02 21:12:29 -0600316 ut_asserteq(1368, compress_frame_buffer(uts, dev));
Simon Glass7a1cb292016-01-18 19:52:28 -0700317
318 return 0;
319}
320DM_TEST(dm_test_video_bmp, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
321
322/* Test drawing a compressed bitmap file */
323static int dm_test_video_bmp_comp(struct unit_test_state *uts)
324{
325 struct udevice *dev;
326 ulong addr;
327
328 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
329 ut_assertok(read_file(uts, "tools/logos/denx-comp.bmp", &addr));
330
331 ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
Simon Glass2a0f8e32020-07-02 21:12:29 -0600332 ut_asserteq(1368, compress_frame_buffer(uts, dev));
Simon Glass7a1cb292016-01-18 19:52:28 -0700333
334 return 0;
335}
336DM_TEST(dm_test_video_bmp_comp, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
Simon Glass32337982016-01-14 18:10:51 -0700337
338/* Test TrueType console */
339static int dm_test_video_truetype(struct unit_test_state *uts)
340{
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_get_device(UCLASS_VIDEO, 0, &dev));
345 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
Rob Clark985935b2017-09-25 15:45:08 -0400346 vidconsole_put_string(con, test_string);
Simon Glass2a0f8e32020-07-02 21:12:29 -0600347 ut_asserteq(12237, compress_frame_buffer(uts, dev));
Simon Glass32337982016-01-14 18:10:51 -0700348
349 return 0;
350}
351DM_TEST(dm_test_video_truetype, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
352
353/* Test scrolling TrueType console */
354static int dm_test_video_truetype_scroll(struct unit_test_state *uts)
355{
356 struct sandbox_sdl_plat *plat;
357 struct udevice *dev, *con;
358 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 -0700359
360 ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
361 ut_assert(!device_active(dev));
362 plat = dev_get_platdata(dev);
363 plat->font_size = 100;
364
365 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
366 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
Rob Clark985935b2017-09-25 15:45:08 -0400367 vidconsole_put_string(con, test_string);
Simon Glass2a0f8e32020-07-02 21:12:29 -0600368 ut_asserteq(35030, compress_frame_buffer(uts, dev));
Simon Glass32337982016-01-14 18:10:51 -0700369
370 return 0;
371}
372DM_TEST(dm_test_video_truetype_scroll, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
373
374/* Test TrueType backspace, within and across lines */
375static int dm_test_video_truetype_bs(struct unit_test_state *uts)
376{
377 struct sandbox_sdl_plat *plat;
378 struct udevice *dev, *con;
379 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 -0700380
381 ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
382 ut_assert(!device_active(dev));
383 plat = dev_get_platdata(dev);
384 plat->font_size = 100;
385
386 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
387 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
Rob Clark985935b2017-09-25 15:45:08 -0400388 vidconsole_put_string(con, test_string);
Simon Glass2a0f8e32020-07-02 21:12:29 -0600389 ut_asserteq(29018, compress_frame_buffer(uts, dev));
Simon Glass32337982016-01-14 18:10:51 -0700390
391 return 0;
392}
393DM_TEST(dm_test_video_truetype_bs, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);