Merge branch 'agust@denx.de' of git://git.denx.de/u-boot-staging
[oweals/u-boot.git] / test / dm / video.c
1 /*
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  */
27 DECLARE_GLOBAL_DATA_PTR;
28
29 /* Basic test of the video uclass */
30 static 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 }
43 DM_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  */
58 static 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  */
83 static void __maybe_unused see_output(void)
84 {
85         video_sync_all();
86         while (1);
87 }
88
89 /* Select the video console driver to use for a video device */
90 static 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
103 /* Test text output works on the video console */
104 static int dm_test_video_text(struct unit_test_state *uts)
105 {
106         struct udevice *dev, *con;
107         int i;
108
109 #define WHITE           0xffff
110 #define SCROLL_LINES    100
111
112         ut_assertok(select_vidconsole(uts, "vidconsole0"));
113         ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
114         ut_asserteq(46, compress_frame_buffer(dev));
115
116         ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
117         vidconsole_putc_xy(con, 0, 0, 'a');
118         ut_asserteq(79, compress_frame_buffer(dev));
119
120         vidconsole_putc_xy(con, 0, 0, ' ');
121         ut_asserteq(46, compress_frame_buffer(dev));
122
123         for (i = 0; i < 20; i++)
124                 vidconsole_putc_xy(con, VID_TO_POS(i * 8), 0, ' ' + i);
125         ut_asserteq(273, compress_frame_buffer(dev));
126
127         vidconsole_set_row(con, 0, WHITE);
128         ut_asserteq(46, compress_frame_buffer(dev));
129
130         for (i = 0; i < 20; i++)
131                 vidconsole_putc_xy(con, VID_TO_POS(i * 8), 0, ' ' + i);
132         ut_asserteq(273, compress_frame_buffer(dev));
133
134         return 0;
135 }
136 DM_TEST(dm_test_video_text, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
137
138 /* Test handling of special characters in the console */
139 static int dm_test_video_chars(struct unit_test_state *uts)
140 {
141         struct udevice *dev, *con;
142         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.";
143         const char *s;
144
145         ut_assertok(select_vidconsole(uts, "vidconsole0"));
146         ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
147         ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
148         for (s = test_string; *s; s++)
149                 vidconsole_put_char(con, *s);
150         ut_asserteq(466, compress_frame_buffer(dev));
151
152         return 0;
153 }
154 DM_TEST(dm_test_video_chars, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
155
156 /**
157  * check_vidconsole_output() - Run a text console test
158  *
159  * @uts:        Test state
160  * @rot:        Console rotation (0, 90, 180, 270)
161  * @wrap_size:  Expected size of compressed frame buffer for the wrap test
162  * @scroll_size: Same for the scroll test
163  * @return 0 on success
164  */
165 static int check_vidconsole_output(struct unit_test_state *uts, int rot,
166                                    int wrap_size, int scroll_size)
167 {
168         struct udevice *dev, *con;
169         struct sandbox_sdl_plat *plat;
170         int i;
171
172         ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
173         ut_assert(!device_active(dev));
174         plat = dev_get_platdata(dev);
175         plat->rot = rot;
176
177         ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
178         ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
179         ut_asserteq(46, compress_frame_buffer(dev));
180
181         /* Check display wrap */
182         for (i = 0; i < 120; i++)
183                 vidconsole_put_char(con, 'A' + i % 50);
184         ut_asserteq(wrap_size, compress_frame_buffer(dev));
185
186         /* Check display scrolling */
187         for (i = 0; i < SCROLL_LINES; i++) {
188                 vidconsole_put_char(con, 'A' + i % 50);
189                 vidconsole_put_char(con, '\n');
190         }
191         ut_asserteq(scroll_size, compress_frame_buffer(dev));
192
193         /* If we scroll enough, the screen becomes blank again */
194         for (i = 0; i < SCROLL_LINES; i++)
195                 vidconsole_put_char(con, '\n');
196         ut_asserteq(46, compress_frame_buffer(dev));
197
198         return 0;
199 }
200
201 /* Test text output through the console uclass */
202 static int dm_test_video_context(struct unit_test_state *uts)
203 {
204         ut_assertok(select_vidconsole(uts, "vidconsole0"));
205         ut_assertok(check_vidconsole_output(uts, 0, 788, 453));
206
207         return 0;
208 }
209 DM_TEST(dm_test_video_context, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
210
211 /* Test rotated text output through the console uclass */
212 static int dm_test_video_rotation1(struct unit_test_state *uts)
213 {
214         ut_assertok(check_vidconsole_output(uts, 1, 1112, 680));
215
216         return 0;
217 }
218 DM_TEST(dm_test_video_rotation1, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
219
220 /* Test rotated text output through the console uclass */
221 static int dm_test_video_rotation2(struct unit_test_state *uts)
222 {
223         ut_assertok(check_vidconsole_output(uts, 2, 785, 446));
224
225         return 0;
226 }
227 DM_TEST(dm_test_video_rotation2, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
228
229 /* Test rotated text output through the console uclass */
230 static int dm_test_video_rotation3(struct unit_test_state *uts)
231 {
232         ut_assertok(check_vidconsole_output(uts, 3, 1134, 681));
233
234         return 0;
235 }
236 DM_TEST(dm_test_video_rotation3, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
237
238 /* Read a file into memory and return a pointer to it */
239 static int read_file(struct unit_test_state *uts, const char *fname,
240                      ulong *addrp)
241 {
242         int buf_size = 100000;
243         ulong addr = 0;
244         int size, fd;
245         char *buf;
246
247         buf = map_sysmem(addr, 0);
248         ut_assert(buf != NULL);
249         fd = os_open(fname, OS_O_RDONLY);
250         ut_assert(fd >= 0);
251         size = os_read(fd, buf, buf_size);
252         os_close(fd);
253         ut_assert(size >= 0);
254         ut_assert(size < buf_size);
255         *addrp = addr;
256
257         return 0;
258 }
259
260 /* Test drawing a bitmap file */
261 static int dm_test_video_bmp(struct unit_test_state *uts)
262 {
263         struct udevice *dev;
264         ulong addr;
265
266         ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
267         ut_assertok(read_file(uts, "tools/logos/denx.bmp", &addr));
268
269         ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
270         ut_asserteq(1368, compress_frame_buffer(dev));
271
272         return 0;
273 }
274 DM_TEST(dm_test_video_bmp, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
275
276 /* Test drawing a compressed bitmap file */
277 static int dm_test_video_bmp_comp(struct unit_test_state *uts)
278 {
279         struct udevice *dev;
280         ulong addr;
281
282         ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
283         ut_assertok(read_file(uts, "tools/logos/denx-comp.bmp", &addr));
284
285         ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
286         ut_asserteq(1368, compress_frame_buffer(dev));
287
288         return 0;
289 }
290 DM_TEST(dm_test_video_bmp_comp, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
291
292 /* Test TrueType console */
293 static int dm_test_video_truetype(struct unit_test_state *uts)
294 {
295         struct udevice *dev, *con;
296         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";
297         const char *s;
298
299         ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
300         ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
301         for (s = test_string; *s; s++)
302                 vidconsole_put_char(con, *s);
303         ut_asserteq(12619, compress_frame_buffer(dev));
304
305         return 0;
306 }
307 DM_TEST(dm_test_video_truetype, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
308
309 /* Test scrolling TrueType console */
310 static int dm_test_video_truetype_scroll(struct unit_test_state *uts)
311 {
312         struct sandbox_sdl_plat *plat;
313         struct udevice *dev, *con;
314         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";
315         const char *s;
316
317         ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
318         ut_assert(!device_active(dev));
319         plat = dev_get_platdata(dev);
320         plat->font_size = 100;
321
322         ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
323         ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
324         for (s = test_string; *s; s++)
325                 vidconsole_put_char(con, *s);
326         ut_asserteq(33849, compress_frame_buffer(dev));
327
328         return 0;
329 }
330 DM_TEST(dm_test_video_truetype_scroll, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
331
332 /* Test TrueType backspace, within and across lines */
333 static int dm_test_video_truetype_bs(struct unit_test_state *uts)
334 {
335         struct sandbox_sdl_plat *plat;
336         struct udevice *dev, *con;
337         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.";
338         const char *s;
339
340         ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
341         ut_assert(!device_active(dev));
342         plat = dev_get_platdata(dev);
343         plat->font_size = 100;
344
345         ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
346         ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
347         for (s = test_string; *s; s++)
348                 vidconsole_put_char(con, *s);
349         ut_asserteq(34871, compress_frame_buffer(dev));
350
351         return 0;
352 }
353 DM_TEST(dm_test_video_truetype_bs, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);