xref: /openbmc/u-boot/test/dm/video.c (revision f266178698307608ee23741e69b9626196e66481)
13c97c4fbSSimon Glass /*
23c97c4fbSSimon Glass  * Copyright (c) 2014 Google, Inc
33c97c4fbSSimon Glass  * Written by Simon Glass <sjg@chromium.org>
43c97c4fbSSimon Glass  *
53c97c4fbSSimon Glass  * SPDX-License-Identifier:	GPL-2.0+
63c97c4fbSSimon Glass  */
73c97c4fbSSimon Glass 
83c97c4fbSSimon Glass #include <common.h>
93c97c4fbSSimon Glass #include <bzlib.h>
103c97c4fbSSimon Glass #include <dm.h>
113c97c4fbSSimon Glass #include <mapmem.h>
123c97c4fbSSimon Glass #include <os.h>
133c97c4fbSSimon Glass #include <video.h>
143c97c4fbSSimon Glass #include <video_console.h>
153c97c4fbSSimon Glass #include <dm/test.h>
163c97c4fbSSimon Glass #include <dm/uclass-internal.h>
173c97c4fbSSimon Glass #include <test/ut.h>
183c97c4fbSSimon Glass 
193c97c4fbSSimon Glass /*
203c97c4fbSSimon Glass  * These tests use the standard sandbox frame buffer, the resolution of which
213c97c4fbSSimon Glass  * is defined in the device tree. This only supports 16bpp so the tests only
223c97c4fbSSimon Glass  * test that code path. It would be possible to adjust this fairly easily,
233c97c4fbSSimon Glass  * by adjusting the bpix value in struct sandbox_sdl_plat. However the code
243c97c4fbSSimon Glass  * in sandbox_sdl_sync() would also need to change to handle the different
253c97c4fbSSimon Glass  * surface depth.
263c97c4fbSSimon Glass  */
273c97c4fbSSimon Glass DECLARE_GLOBAL_DATA_PTR;
283c97c4fbSSimon Glass 
293c97c4fbSSimon Glass /* Basic test of the video uclass */
303c97c4fbSSimon Glass static int dm_test_video_base(struct unit_test_state *uts)
313c97c4fbSSimon Glass {
323c97c4fbSSimon Glass 	struct video_priv *priv;
333c97c4fbSSimon Glass 	struct udevice *dev;
343c97c4fbSSimon Glass 
353c97c4fbSSimon Glass 	ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
363c97c4fbSSimon Glass 	ut_asserteq(1366, video_get_xsize(dev));
373c97c4fbSSimon Glass 	ut_asserteq(768, video_get_ysize(dev));
383c97c4fbSSimon Glass 	priv = dev_get_uclass_priv(dev);
393c97c4fbSSimon Glass 	ut_asserteq(priv->fb_size, 1366 * 768 * 2);
403c97c4fbSSimon Glass 
413c97c4fbSSimon Glass 	return 0;
423c97c4fbSSimon Glass }
433c97c4fbSSimon Glass DM_TEST(dm_test_video_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
443c97c4fbSSimon Glass 
453c97c4fbSSimon Glass /**
463c97c4fbSSimon Glass  * compress_frame_buffer() - Compress the frame buffer and return its size
473c97c4fbSSimon Glass  *
483c97c4fbSSimon Glass  * We want to write tests which perform operations on the video console and
493c97c4fbSSimon Glass  * check that the frame buffer ends up with the correct contents. But it is
503c97c4fbSSimon Glass  * painful to store 'known good' images for comparison with the frame
513c97c4fbSSimon Glass  * buffer. As an alternative, we can compress the frame buffer and check the
523c97c4fbSSimon Glass  * size of the compressed data. This provides a pretty good level of
533c97c4fbSSimon Glass  * certainty and the resulting tests need only check a single value.
543c97c4fbSSimon Glass  *
553c97c4fbSSimon Glass  * @dev:	Video device
563c97c4fbSSimon Glass  * @return compressed size of the frame buffer, or -ve on error
573c97c4fbSSimon Glass  */
583c97c4fbSSimon Glass static int compress_frame_buffer(struct udevice *dev)
593c97c4fbSSimon Glass {
603c97c4fbSSimon Glass 	struct video_priv *priv = dev_get_uclass_priv(dev);
613c97c4fbSSimon Glass 	uint destlen;
623c97c4fbSSimon Glass 	void *dest;
633c97c4fbSSimon Glass 	int ret;
643c97c4fbSSimon Glass 
653c97c4fbSSimon Glass 	destlen = priv->fb_size;
663c97c4fbSSimon Glass 	dest = malloc(priv->fb_size);
673c97c4fbSSimon Glass 	if (!dest)
683c97c4fbSSimon Glass 		return -ENOMEM;
693c97c4fbSSimon Glass 	ret = BZ2_bzBuffToBuffCompress(dest, &destlen,
703c97c4fbSSimon Glass 				       priv->fb, priv->fb_size,
713c97c4fbSSimon Glass 				       3, 0, 0);
723c97c4fbSSimon Glass 	free(dest);
733c97c4fbSSimon Glass 	if (ret)
743c97c4fbSSimon Glass 		return ret;
753c97c4fbSSimon Glass 
763c97c4fbSSimon Glass 	return destlen;
773c97c4fbSSimon Glass }
783c97c4fbSSimon Glass 
793c97c4fbSSimon Glass /*
803c97c4fbSSimon Glass  * Call this function at any point to halt and show the current display. Be
813c97c4fbSSimon Glass  * sure to run the test with the -l flag.
823c97c4fbSSimon Glass  */
833c97c4fbSSimon Glass static void __maybe_unused see_output(void)
843c97c4fbSSimon Glass {
853c97c4fbSSimon Glass 	video_sync_all();
863c97c4fbSSimon Glass 	while (1);
873c97c4fbSSimon Glass }
883c97c4fbSSimon Glass 
893c97c4fbSSimon Glass /* Test text output works on the video console */
903c97c4fbSSimon Glass static int dm_test_video_text(struct unit_test_state *uts)
913c97c4fbSSimon Glass {
923c97c4fbSSimon Glass 	struct udevice *dev, *con;
933c97c4fbSSimon Glass 	int i;
943c97c4fbSSimon Glass 
953c97c4fbSSimon Glass #define WHITE		0xffff
963c97c4fbSSimon Glass #define SCROLL_LINES	100
973c97c4fbSSimon Glass 
983c97c4fbSSimon Glass 	ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
993c97c4fbSSimon Glass 	ut_asserteq(46, compress_frame_buffer(dev));
1003c97c4fbSSimon Glass 
1013c97c4fbSSimon Glass 	ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
1023c97c4fbSSimon Glass 	vidconsole_putc_xy(con, 0, 0, 'a');
1033c97c4fbSSimon Glass 	ut_asserteq(79, compress_frame_buffer(dev));
1043c97c4fbSSimon Glass 
1053c97c4fbSSimon Glass 	vidconsole_putc_xy(con, 0, 0, ' ');
1063c97c4fbSSimon Glass 	ut_asserteq(46, compress_frame_buffer(dev));
1073c97c4fbSSimon Glass 
1083c97c4fbSSimon Glass 	for (i = 0; i < 20; i++)
109*f2661786SSimon Glass 		vidconsole_putc_xy(con, VID_TO_POS(i * 8), 0, ' ' + i);
1103c97c4fbSSimon Glass 	ut_asserteq(273, compress_frame_buffer(dev));
1113c97c4fbSSimon Glass 
1123c97c4fbSSimon Glass 	vidconsole_set_row(con, 0, WHITE);
1133c97c4fbSSimon Glass 	ut_asserteq(46, compress_frame_buffer(dev));
1143c97c4fbSSimon Glass 
1153c97c4fbSSimon Glass 	for (i = 0; i < 20; i++)
116*f2661786SSimon Glass 		vidconsole_putc_xy(con, VID_TO_POS(i * 8), 0, ' ' + i);
1173c97c4fbSSimon Glass 	ut_asserteq(273, compress_frame_buffer(dev));
1183c97c4fbSSimon Glass 
1193c97c4fbSSimon Glass 	return 0;
1203c97c4fbSSimon Glass }
1213c97c4fbSSimon Glass DM_TEST(dm_test_video_text, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
1223c97c4fbSSimon Glass 
1233c97c4fbSSimon Glass /* Test handling of special characters in the console */
1243c97c4fbSSimon Glass static int dm_test_video_chars(struct unit_test_state *uts)
1253c97c4fbSSimon Glass {
1263c97c4fbSSimon Glass 	struct udevice *dev, *con;
1273c97c4fbSSimon Glass 	const char *test_string = "Well\b\b\b\bxhe is\r \n\ta very modest  \bman\n\t\tand Has much to\b\bto be modest about.";
1283c97c4fbSSimon Glass 	const char *s;
1293c97c4fbSSimon Glass 
1303c97c4fbSSimon Glass 	ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
1313c97c4fbSSimon Glass 	ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
1323c97c4fbSSimon Glass 	for (s = test_string; *s; s++)
1333c97c4fbSSimon Glass 		vidconsole_put_char(con, *s);
1343c97c4fbSSimon Glass 	ut_asserteq(466, compress_frame_buffer(dev));
1353c97c4fbSSimon Glass 
1363c97c4fbSSimon Glass 	return 0;
1373c97c4fbSSimon Glass }
1383c97c4fbSSimon Glass DM_TEST(dm_test_video_chars, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
1393c97c4fbSSimon Glass 
1403c97c4fbSSimon Glass /**
1413c97c4fbSSimon Glass  * check_vidconsole_output() - Run a text console test
1423c97c4fbSSimon Glass  *
1433c97c4fbSSimon Glass  * @uts:	Test state
1443c97c4fbSSimon Glass  * @rot:	Console rotation (0, 90, 180, 270)
1453c97c4fbSSimon Glass  * @wrap_size:	Expected size of compressed frame buffer for the wrap test
1463c97c4fbSSimon Glass  * @scroll_size: Same for the scroll test
1473c97c4fbSSimon Glass  * @return 0 on success
1483c97c4fbSSimon Glass  */
1493c97c4fbSSimon Glass static int check_vidconsole_output(struct unit_test_state *uts, int rot,
1503c97c4fbSSimon Glass 				   int wrap_size, int scroll_size)
1513c97c4fbSSimon Glass {
1523c97c4fbSSimon Glass 	struct udevice *dev, *con;
1533c97c4fbSSimon Glass 	struct sandbox_sdl_plat *plat;
1543c97c4fbSSimon Glass 	int i;
1553c97c4fbSSimon Glass 
1563c97c4fbSSimon Glass 	ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
1573c97c4fbSSimon Glass 	ut_assert(!device_active(dev));
1583c97c4fbSSimon Glass 	plat = dev_get_platdata(dev);
1593c97c4fbSSimon Glass 	plat->rot = rot;
1603c97c4fbSSimon Glass 
1613c97c4fbSSimon Glass 	ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
1623c97c4fbSSimon Glass 	ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
1633c97c4fbSSimon Glass 	ut_asserteq(46, compress_frame_buffer(dev));
1643c97c4fbSSimon Glass 
1653c97c4fbSSimon Glass 	/* Check display wrap */
1663c97c4fbSSimon Glass 	for (i = 0; i < 120; i++)
1673c97c4fbSSimon Glass 		vidconsole_put_char(con, 'A' + i % 50);
1683c97c4fbSSimon Glass 	ut_asserteq(wrap_size, compress_frame_buffer(dev));
1693c97c4fbSSimon Glass 
1703c97c4fbSSimon Glass 	/* Check display scrolling */
1713c97c4fbSSimon Glass 	for (i = 0; i < SCROLL_LINES; i++) {
1723c97c4fbSSimon Glass 		vidconsole_put_char(con, 'A' + i % 50);
1733c97c4fbSSimon Glass 		vidconsole_put_char(con, '\n');
1743c97c4fbSSimon Glass 	}
1753c97c4fbSSimon Glass 	ut_asserteq(scroll_size, compress_frame_buffer(dev));
1763c97c4fbSSimon Glass 
1773c97c4fbSSimon Glass 	/* If we scroll enough, the screen becomes blank again */
1783c97c4fbSSimon Glass 	for (i = 0; i < SCROLL_LINES; i++)
1793c97c4fbSSimon Glass 		vidconsole_put_char(con, '\n');
1803c97c4fbSSimon Glass 	ut_asserteq(46, compress_frame_buffer(dev));
1813c97c4fbSSimon Glass 
1823c97c4fbSSimon Glass 	return 0;
1833c97c4fbSSimon Glass }
1843c97c4fbSSimon Glass 
1853c97c4fbSSimon Glass /* Test text output through the console uclass */
1863c97c4fbSSimon Glass static int dm_test_video_context(struct unit_test_state *uts)
1873c97c4fbSSimon Glass {
1883c97c4fbSSimon Glass 	return check_vidconsole_output(uts, 0, 788, 453);
1893c97c4fbSSimon Glass }
1903c97c4fbSSimon Glass DM_TEST(dm_test_video_context, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
19185e08db8SSimon Glass 
19285e08db8SSimon Glass /* Test rotated text output through the console uclass */
19385e08db8SSimon Glass static int dm_test_video_rotation1(struct unit_test_state *uts)
19485e08db8SSimon Glass {
19585e08db8SSimon Glass 	ut_assertok(check_vidconsole_output(uts, 1, 1112, 680));
19685e08db8SSimon Glass 
19785e08db8SSimon Glass 	return 0;
19885e08db8SSimon Glass }
19985e08db8SSimon Glass DM_TEST(dm_test_video_rotation1, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
20085e08db8SSimon Glass 
20185e08db8SSimon Glass /* Test rotated text output through the console uclass */
20285e08db8SSimon Glass static int dm_test_video_rotation2(struct unit_test_state *uts)
20385e08db8SSimon Glass {
20485e08db8SSimon Glass 	ut_assertok(check_vidconsole_output(uts, 2, 785, 446));
20585e08db8SSimon Glass 
20685e08db8SSimon Glass 	return 0;
20785e08db8SSimon Glass }
20885e08db8SSimon Glass DM_TEST(dm_test_video_rotation2, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
20985e08db8SSimon Glass 
21085e08db8SSimon Glass /* Test rotated text output through the console uclass */
21185e08db8SSimon Glass static int dm_test_video_rotation3(struct unit_test_state *uts)
21285e08db8SSimon Glass {
21385e08db8SSimon Glass 	ut_assertok(check_vidconsole_output(uts, 3, 1134, 681));
21485e08db8SSimon Glass 
21585e08db8SSimon Glass 	return 0;
21685e08db8SSimon Glass }
21785e08db8SSimon Glass DM_TEST(dm_test_video_rotation3, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
218747440d0SSimon Glass 
219747440d0SSimon Glass /* Read a file into memory and return a pointer to it */
220747440d0SSimon Glass static int read_file(struct unit_test_state *uts, const char *fname,
221747440d0SSimon Glass 		     ulong *addrp)
222747440d0SSimon Glass {
223747440d0SSimon Glass 	int buf_size = 100000;
224747440d0SSimon Glass 	ulong addr = 0;
225747440d0SSimon Glass 	int size, fd;
226747440d0SSimon Glass 	char *buf;
227747440d0SSimon Glass 
228747440d0SSimon Glass 	buf = map_sysmem(addr, 0);
229747440d0SSimon Glass 	ut_assert(buf != NULL);
230747440d0SSimon Glass 	fd = os_open(fname, OS_O_RDONLY);
231747440d0SSimon Glass 	ut_assert(fd >= 0);
232747440d0SSimon Glass 	size = os_read(fd, buf, buf_size);
233747440d0SSimon Glass 	ut_assert(size >= 0);
234747440d0SSimon Glass 	ut_assert(size < buf_size);
235747440d0SSimon Glass 	os_close(fd);
236747440d0SSimon Glass 	*addrp = addr;
237747440d0SSimon Glass 
238747440d0SSimon Glass 	return 0;
239747440d0SSimon Glass }
240747440d0SSimon Glass 
241747440d0SSimon Glass /* Test drawing a bitmap file */
242747440d0SSimon Glass static int dm_test_video_bmp(struct unit_test_state *uts)
243747440d0SSimon Glass {
244747440d0SSimon Glass 	struct udevice *dev;
245747440d0SSimon Glass 	ulong addr;
246747440d0SSimon Glass 
247747440d0SSimon Glass 	ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
248747440d0SSimon Glass 	ut_assertok(read_file(uts, "tools/logos/denx.bmp", &addr));
249747440d0SSimon Glass 
250747440d0SSimon Glass 	ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
251747440d0SSimon Glass 	ut_asserteq(1368, compress_frame_buffer(dev));
252747440d0SSimon Glass 
253747440d0SSimon Glass 	return 0;
254747440d0SSimon Glass }
255747440d0SSimon Glass DM_TEST(dm_test_video_bmp, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
256747440d0SSimon Glass 
257747440d0SSimon Glass /* Test drawing a compressed bitmap file */
258747440d0SSimon Glass static int dm_test_video_bmp_comp(struct unit_test_state *uts)
259747440d0SSimon Glass {
260747440d0SSimon Glass 	struct udevice *dev;
261747440d0SSimon Glass 	ulong addr;
262747440d0SSimon Glass 
263747440d0SSimon Glass 	ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
264747440d0SSimon Glass 	ut_assertok(read_file(uts, "tools/logos/denx-comp.bmp", &addr));
265747440d0SSimon Glass 
266747440d0SSimon Glass 	ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
267747440d0SSimon Glass 	ut_asserteq(1368, compress_frame_buffer(dev));
268747440d0SSimon Glass 
269747440d0SSimon Glass 	return 0;
270747440d0SSimon Glass }
271747440d0SSimon Glass DM_TEST(dm_test_video_bmp_comp, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
272