blob: 6a5626c5e3fdfd5098dc835a36de4459a2203944 [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
162/**
163 * check_vidconsole_output() - Run a text console test
164 *
165 * @uts: Test state
166 * @rot: Console rotation (0, 90, 180, 270)
167 * @wrap_size: Expected size of compressed frame buffer for the wrap test
168 * @scroll_size: Same for the scroll test
169 * @return 0 on success
170 */
171static int check_vidconsole_output(struct unit_test_state *uts, int rot,
172 int wrap_size, int scroll_size)
173{
174 struct udevice *dev, *con;
175 struct sandbox_sdl_plat *plat;
176 int i;
177
178 ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
179 ut_assert(!device_active(dev));
180 plat = dev_get_platdata(dev);
181 plat->rot = rot;
182
183 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
184 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
185 ut_asserteq(46, compress_frame_buffer(dev));
186
187 /* Check display wrap */
188 for (i = 0; i < 120; i++)
189 vidconsole_put_char(con, 'A' + i % 50);
190 ut_asserteq(wrap_size, compress_frame_buffer(dev));
191
192 /* Check display scrolling */
193 for (i = 0; i < SCROLL_LINES; i++) {
194 vidconsole_put_char(con, 'A' + i % 50);
195 vidconsole_put_char(con, '\n');
196 }
197 ut_asserteq(scroll_size, compress_frame_buffer(dev));
198
199 /* If we scroll enough, the screen becomes blank again */
200 for (i = 0; i < SCROLL_LINES; i++)
201 vidconsole_put_char(con, '\n');
202 ut_asserteq(46, compress_frame_buffer(dev));
203
204 return 0;
205}
206
207/* Test text output through the console uclass */
208static int dm_test_video_context(struct unit_test_state *uts)
209{
Simon Glassdaac9c72016-01-14 18:10:50 -0700210 ut_assertok(select_vidconsole(uts, "vidconsole0"));
211 ut_assertok(check_vidconsole_output(uts, 0, 788, 453));
212
213 return 0;
Simon Glass90b6fef2016-01-18 19:52:26 -0700214}
215DM_TEST(dm_test_video_context, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
Simon Glassa0f1efe2016-01-18 19:52:27 -0700216
217/* Test rotated text output through the console uclass */
218static int dm_test_video_rotation1(struct unit_test_state *uts)
219{
220 ut_assertok(check_vidconsole_output(uts, 1, 1112, 680));
221
222 return 0;
223}
224DM_TEST(dm_test_video_rotation1, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
225
226/* Test rotated text output through the console uclass */
227static int dm_test_video_rotation2(struct unit_test_state *uts)
228{
229 ut_assertok(check_vidconsole_output(uts, 2, 785, 446));
230
231 return 0;
232}
233DM_TEST(dm_test_video_rotation2, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
234
235/* Test rotated text output through the console uclass */
236static int dm_test_video_rotation3(struct unit_test_state *uts)
237{
238 ut_assertok(check_vidconsole_output(uts, 3, 1134, 681));
239
240 return 0;
241}
242DM_TEST(dm_test_video_rotation3, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
Simon Glass7a1cb292016-01-18 19:52:28 -0700243
244/* Read a file into memory and return a pointer to it */
245static int read_file(struct unit_test_state *uts, const char *fname,
246 ulong *addrp)
247{
248 int buf_size = 100000;
249 ulong addr = 0;
250 int size, fd;
251 char *buf;
252
253 buf = map_sysmem(addr, 0);
254 ut_assert(buf != NULL);
255 fd = os_open(fname, OS_O_RDONLY);
256 ut_assert(fd >= 0);
257 size = os_read(fd, buf, buf_size);
Simon Glass9050c5f2016-01-30 15:45:17 -0700258 os_close(fd);
Simon Glass7a1cb292016-01-18 19:52:28 -0700259 ut_assert(size >= 0);
260 ut_assert(size < buf_size);
Simon Glass7a1cb292016-01-18 19:52:28 -0700261 *addrp = addr;
262
263 return 0;
264}
265
266/* Test drawing a bitmap file */
267static int dm_test_video_bmp(struct unit_test_state *uts)
268{
269 struct udevice *dev;
270 ulong addr;
271
272 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
273 ut_assertok(read_file(uts, "tools/logos/denx.bmp", &addr));
274
275 ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
276 ut_asserteq(1368, compress_frame_buffer(dev));
277
278 return 0;
279}
280DM_TEST(dm_test_video_bmp, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
281
282/* Test drawing a compressed bitmap file */
283static int dm_test_video_bmp_comp(struct unit_test_state *uts)
284{
285 struct udevice *dev;
286 ulong addr;
287
288 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
289 ut_assertok(read_file(uts, "tools/logos/denx-comp.bmp", &addr));
290
291 ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
292 ut_asserteq(1368, compress_frame_buffer(dev));
293
294 return 0;
295}
296DM_TEST(dm_test_video_bmp_comp, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
Simon Glass32337982016-01-14 18:10:51 -0700297
298/* Test TrueType console */
299static int dm_test_video_truetype(struct unit_test_state *uts)
300{
301 struct udevice *dev, *con;
302 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 -0700303
304 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
305 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
Rob Clark985935b2017-09-25 15:45:08 -0400306 vidconsole_put_string(con, test_string);
Simon Glass32337982016-01-14 18:10:51 -0700307 ut_asserteq(12619, compress_frame_buffer(dev));
308
309 return 0;
310}
311DM_TEST(dm_test_video_truetype, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
312
313/* Test scrolling TrueType console */
314static int dm_test_video_truetype_scroll(struct unit_test_state *uts)
315{
316 struct sandbox_sdl_plat *plat;
317 struct udevice *dev, *con;
318 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 -0700319
320 ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
321 ut_assert(!device_active(dev));
322 plat = dev_get_platdata(dev);
323 plat->font_size = 100;
324
325 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
326 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
Rob Clark985935b2017-09-25 15:45:08 -0400327 vidconsole_put_string(con, test_string);
Simon Glass32337982016-01-14 18:10:51 -0700328 ut_asserteq(33849, compress_frame_buffer(dev));
329
330 return 0;
331}
332DM_TEST(dm_test_video_truetype_scroll, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
333
334/* Test TrueType backspace, within and across lines */
335static int dm_test_video_truetype_bs(struct unit_test_state *uts)
336{
337 struct sandbox_sdl_plat *plat;
338 struct udevice *dev, *con;
339 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 -0700340
341 ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
342 ut_assert(!device_active(dev));
343 plat = dev_get_platdata(dev);
344 plat->font_size = 100;
345
346 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
347 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
Rob Clark985935b2017-09-25 15:45:08 -0400348 vidconsole_put_string(con, test_string);
Simon Glass32337982016-01-14 18:10:51 -0700349 ut_asserteq(34871, compress_frame_buffer(dev));
350
351 return 0;
352}
353DM_TEST(dm_test_video_truetype_bs, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);