1*3c97c4fbSSimon Glass /* 2*3c97c4fbSSimon Glass * Copyright (c) 2014 Google, Inc 3*3c97c4fbSSimon Glass * Written by Simon Glass <sjg@chromium.org> 4*3c97c4fbSSimon Glass * 5*3c97c4fbSSimon Glass * SPDX-License-Identifier: GPL-2.0+ 6*3c97c4fbSSimon Glass */ 7*3c97c4fbSSimon Glass 8*3c97c4fbSSimon Glass #include <common.h> 9*3c97c4fbSSimon Glass #include <bzlib.h> 10*3c97c4fbSSimon Glass #include <dm.h> 11*3c97c4fbSSimon Glass #include <mapmem.h> 12*3c97c4fbSSimon Glass #include <os.h> 13*3c97c4fbSSimon Glass #include <video.h> 14*3c97c4fbSSimon Glass #include <video_console.h> 15*3c97c4fbSSimon Glass #include <dm/test.h> 16*3c97c4fbSSimon Glass #include <dm/uclass-internal.h> 17*3c97c4fbSSimon Glass #include <test/ut.h> 18*3c97c4fbSSimon Glass 19*3c97c4fbSSimon Glass /* 20*3c97c4fbSSimon Glass * These tests use the standard sandbox frame buffer, the resolution of which 21*3c97c4fbSSimon Glass * is defined in the device tree. This only supports 16bpp so the tests only 22*3c97c4fbSSimon Glass * test that code path. It would be possible to adjust this fairly easily, 23*3c97c4fbSSimon Glass * by adjusting the bpix value in struct sandbox_sdl_plat. However the code 24*3c97c4fbSSimon Glass * in sandbox_sdl_sync() would also need to change to handle the different 25*3c97c4fbSSimon Glass * surface depth. 26*3c97c4fbSSimon Glass */ 27*3c97c4fbSSimon Glass DECLARE_GLOBAL_DATA_PTR; 28*3c97c4fbSSimon Glass 29*3c97c4fbSSimon Glass /* Basic test of the video uclass */ 30*3c97c4fbSSimon Glass static int dm_test_video_base(struct unit_test_state *uts) 31*3c97c4fbSSimon Glass { 32*3c97c4fbSSimon Glass struct video_priv *priv; 33*3c97c4fbSSimon Glass struct udevice *dev; 34*3c97c4fbSSimon Glass 35*3c97c4fbSSimon Glass ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev)); 36*3c97c4fbSSimon Glass ut_asserteq(1366, video_get_xsize(dev)); 37*3c97c4fbSSimon Glass ut_asserteq(768, video_get_ysize(dev)); 38*3c97c4fbSSimon Glass priv = dev_get_uclass_priv(dev); 39*3c97c4fbSSimon Glass ut_asserteq(priv->fb_size, 1366 * 768 * 2); 40*3c97c4fbSSimon Glass 41*3c97c4fbSSimon Glass return 0; 42*3c97c4fbSSimon Glass } 43*3c97c4fbSSimon Glass DM_TEST(dm_test_video_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); 44*3c97c4fbSSimon Glass 45*3c97c4fbSSimon Glass /** 46*3c97c4fbSSimon Glass * compress_frame_buffer() - Compress the frame buffer and return its size 47*3c97c4fbSSimon Glass * 48*3c97c4fbSSimon Glass * We want to write tests which perform operations on the video console and 49*3c97c4fbSSimon Glass * check that the frame buffer ends up with the correct contents. But it is 50*3c97c4fbSSimon Glass * painful to store 'known good' images for comparison with the frame 51*3c97c4fbSSimon Glass * buffer. As an alternative, we can compress the frame buffer and check the 52*3c97c4fbSSimon Glass * size of the compressed data. This provides a pretty good level of 53*3c97c4fbSSimon Glass * certainty and the resulting tests need only check a single value. 54*3c97c4fbSSimon Glass * 55*3c97c4fbSSimon Glass * @dev: Video device 56*3c97c4fbSSimon Glass * @return compressed size of the frame buffer, or -ve on error 57*3c97c4fbSSimon Glass */ 58*3c97c4fbSSimon Glass static int compress_frame_buffer(struct udevice *dev) 59*3c97c4fbSSimon Glass { 60*3c97c4fbSSimon Glass struct video_priv *priv = dev_get_uclass_priv(dev); 61*3c97c4fbSSimon Glass uint destlen; 62*3c97c4fbSSimon Glass void *dest; 63*3c97c4fbSSimon Glass int ret; 64*3c97c4fbSSimon Glass 65*3c97c4fbSSimon Glass destlen = priv->fb_size; 66*3c97c4fbSSimon Glass dest = malloc(priv->fb_size); 67*3c97c4fbSSimon Glass if (!dest) 68*3c97c4fbSSimon Glass return -ENOMEM; 69*3c97c4fbSSimon Glass ret = BZ2_bzBuffToBuffCompress(dest, &destlen, 70*3c97c4fbSSimon Glass priv->fb, priv->fb_size, 71*3c97c4fbSSimon Glass 3, 0, 0); 72*3c97c4fbSSimon Glass free(dest); 73*3c97c4fbSSimon Glass if (ret) 74*3c97c4fbSSimon Glass return ret; 75*3c97c4fbSSimon Glass 76*3c97c4fbSSimon Glass return destlen; 77*3c97c4fbSSimon Glass } 78*3c97c4fbSSimon Glass 79*3c97c4fbSSimon Glass /* 80*3c97c4fbSSimon Glass * Call this function at any point to halt and show the current display. Be 81*3c97c4fbSSimon Glass * sure to run the test with the -l flag. 82*3c97c4fbSSimon Glass */ 83*3c97c4fbSSimon Glass static void __maybe_unused see_output(void) 84*3c97c4fbSSimon Glass { 85*3c97c4fbSSimon Glass video_sync_all(); 86*3c97c4fbSSimon Glass while (1); 87*3c97c4fbSSimon Glass } 88*3c97c4fbSSimon Glass 89*3c97c4fbSSimon Glass /* Test text output works on the video console */ 90*3c97c4fbSSimon Glass static int dm_test_video_text(struct unit_test_state *uts) 91*3c97c4fbSSimon Glass { 92*3c97c4fbSSimon Glass struct udevice *dev, *con; 93*3c97c4fbSSimon Glass int i; 94*3c97c4fbSSimon Glass 95*3c97c4fbSSimon Glass #define WHITE 0xffff 96*3c97c4fbSSimon Glass #define SCROLL_LINES 100 97*3c97c4fbSSimon Glass 98*3c97c4fbSSimon Glass ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev)); 99*3c97c4fbSSimon Glass ut_asserteq(46, compress_frame_buffer(dev)); 100*3c97c4fbSSimon Glass 101*3c97c4fbSSimon Glass ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con)); 102*3c97c4fbSSimon Glass vidconsole_putc_xy(con, 0, 0, 'a'); 103*3c97c4fbSSimon Glass ut_asserteq(79, compress_frame_buffer(dev)); 104*3c97c4fbSSimon Glass 105*3c97c4fbSSimon Glass vidconsole_putc_xy(con, 0, 0, ' '); 106*3c97c4fbSSimon Glass ut_asserteq(46, compress_frame_buffer(dev)); 107*3c97c4fbSSimon Glass 108*3c97c4fbSSimon Glass for (i = 0; i < 20; i++) 109*3c97c4fbSSimon Glass vidconsole_putc_xy(con, i * 8, 0, ' ' + i); 110*3c97c4fbSSimon Glass ut_asserteq(273, compress_frame_buffer(dev)); 111*3c97c4fbSSimon Glass 112*3c97c4fbSSimon Glass vidconsole_set_row(con, 0, WHITE); 113*3c97c4fbSSimon Glass ut_asserteq(46, compress_frame_buffer(dev)); 114*3c97c4fbSSimon Glass 115*3c97c4fbSSimon Glass for (i = 0; i < 20; i++) 116*3c97c4fbSSimon Glass vidconsole_putc_xy(con, i * 8, 0, ' ' + i); 117*3c97c4fbSSimon Glass ut_asserteq(273, compress_frame_buffer(dev)); 118*3c97c4fbSSimon Glass 119*3c97c4fbSSimon Glass return 0; 120*3c97c4fbSSimon Glass } 121*3c97c4fbSSimon Glass DM_TEST(dm_test_video_text, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); 122*3c97c4fbSSimon Glass 123*3c97c4fbSSimon Glass /* Test handling of special characters in the console */ 124*3c97c4fbSSimon Glass static int dm_test_video_chars(struct unit_test_state *uts) 125*3c97c4fbSSimon Glass { 126*3c97c4fbSSimon Glass struct udevice *dev, *con; 127*3c97c4fbSSimon 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."; 128*3c97c4fbSSimon Glass const char *s; 129*3c97c4fbSSimon Glass 130*3c97c4fbSSimon Glass ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev)); 131*3c97c4fbSSimon Glass ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con)); 132*3c97c4fbSSimon Glass for (s = test_string; *s; s++) 133*3c97c4fbSSimon Glass vidconsole_put_char(con, *s); 134*3c97c4fbSSimon Glass ut_asserteq(466, compress_frame_buffer(dev)); 135*3c97c4fbSSimon Glass 136*3c97c4fbSSimon Glass return 0; 137*3c97c4fbSSimon Glass } 138*3c97c4fbSSimon Glass DM_TEST(dm_test_video_chars, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); 139*3c97c4fbSSimon Glass 140*3c97c4fbSSimon Glass /** 141*3c97c4fbSSimon Glass * check_vidconsole_output() - Run a text console test 142*3c97c4fbSSimon Glass * 143*3c97c4fbSSimon Glass * @uts: Test state 144*3c97c4fbSSimon Glass * @rot: Console rotation (0, 90, 180, 270) 145*3c97c4fbSSimon Glass * @wrap_size: Expected size of compressed frame buffer for the wrap test 146*3c97c4fbSSimon Glass * @scroll_size: Same for the scroll test 147*3c97c4fbSSimon Glass * @return 0 on success 148*3c97c4fbSSimon Glass */ 149*3c97c4fbSSimon Glass static int check_vidconsole_output(struct unit_test_state *uts, int rot, 150*3c97c4fbSSimon Glass int wrap_size, int scroll_size) 151*3c97c4fbSSimon Glass { 152*3c97c4fbSSimon Glass struct udevice *dev, *con; 153*3c97c4fbSSimon Glass struct sandbox_sdl_plat *plat; 154*3c97c4fbSSimon Glass int i; 155*3c97c4fbSSimon Glass 156*3c97c4fbSSimon Glass ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev)); 157*3c97c4fbSSimon Glass ut_assert(!device_active(dev)); 158*3c97c4fbSSimon Glass plat = dev_get_platdata(dev); 159*3c97c4fbSSimon Glass plat->rot = rot; 160*3c97c4fbSSimon Glass 161*3c97c4fbSSimon Glass ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev)); 162*3c97c4fbSSimon Glass ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con)); 163*3c97c4fbSSimon Glass ut_asserteq(46, compress_frame_buffer(dev)); 164*3c97c4fbSSimon Glass 165*3c97c4fbSSimon Glass /* Check display wrap */ 166*3c97c4fbSSimon Glass for (i = 0; i < 120; i++) 167*3c97c4fbSSimon Glass vidconsole_put_char(con, 'A' + i % 50); 168*3c97c4fbSSimon Glass ut_asserteq(wrap_size, compress_frame_buffer(dev)); 169*3c97c4fbSSimon Glass 170*3c97c4fbSSimon Glass /* Check display scrolling */ 171*3c97c4fbSSimon Glass for (i = 0; i < SCROLL_LINES; i++) { 172*3c97c4fbSSimon Glass vidconsole_put_char(con, 'A' + i % 50); 173*3c97c4fbSSimon Glass vidconsole_put_char(con, '\n'); 174*3c97c4fbSSimon Glass } 175*3c97c4fbSSimon Glass ut_asserteq(scroll_size, compress_frame_buffer(dev)); 176*3c97c4fbSSimon Glass 177*3c97c4fbSSimon Glass /* If we scroll enough, the screen becomes blank again */ 178*3c97c4fbSSimon Glass for (i = 0; i < SCROLL_LINES; i++) 179*3c97c4fbSSimon Glass vidconsole_put_char(con, '\n'); 180*3c97c4fbSSimon Glass ut_asserteq(46, compress_frame_buffer(dev)); 181*3c97c4fbSSimon Glass 182*3c97c4fbSSimon Glass return 0; 183*3c97c4fbSSimon Glass } 184*3c97c4fbSSimon Glass 185*3c97c4fbSSimon Glass /* Test text output through the console uclass */ 186*3c97c4fbSSimon Glass static int dm_test_video_context(struct unit_test_state *uts) 187*3c97c4fbSSimon Glass { 188*3c97c4fbSSimon Glass return check_vidconsole_output(uts, 0, 788, 453); 189*3c97c4fbSSimon Glass } 190*3c97c4fbSSimon Glass DM_TEST(dm_test_video_context, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); 191