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