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++) 1093c97c4fbSSimon Glass vidconsole_putc_xy(con, 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++) 1163c97c4fbSSimon Glass vidconsole_putc_xy(con, 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); 191*85e08db8SSimon Glass 192*85e08db8SSimon Glass /* Test rotated text output through the console uclass */ 193*85e08db8SSimon Glass static int dm_test_video_rotation1(struct unit_test_state *uts) 194*85e08db8SSimon Glass { 195*85e08db8SSimon Glass ut_assertok(check_vidconsole_output(uts, 1, 1112, 680)); 196*85e08db8SSimon Glass 197*85e08db8SSimon Glass return 0; 198*85e08db8SSimon Glass } 199*85e08db8SSimon Glass DM_TEST(dm_test_video_rotation1, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); 200*85e08db8SSimon Glass 201*85e08db8SSimon Glass /* Test rotated text output through the console uclass */ 202*85e08db8SSimon Glass static int dm_test_video_rotation2(struct unit_test_state *uts) 203*85e08db8SSimon Glass { 204*85e08db8SSimon Glass ut_assertok(check_vidconsole_output(uts, 2, 785, 446)); 205*85e08db8SSimon Glass 206*85e08db8SSimon Glass return 0; 207*85e08db8SSimon Glass } 208*85e08db8SSimon Glass DM_TEST(dm_test_video_rotation2, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); 209*85e08db8SSimon Glass 210*85e08db8SSimon Glass /* Test rotated text output through the console uclass */ 211*85e08db8SSimon Glass static int dm_test_video_rotation3(struct unit_test_state *uts) 212*85e08db8SSimon Glass { 213*85e08db8SSimon Glass ut_assertok(check_vidconsole_output(uts, 3, 1134, 681)); 214*85e08db8SSimon Glass 215*85e08db8SSimon Glass return 0; 216*85e08db8SSimon Glass } 217*85e08db8SSimon Glass DM_TEST(dm_test_video_rotation3, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); 218