uboot/test/dm/video.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (c) 2014 Google, Inc
   4 * Written by Simon Glass <sjg@chromium.org>
   5 */
   6
   7#include <common.h>
   8#include <bzlib.h>
   9#include <dm.h>
  10#include <mapmem.h>
  11#include <os.h>
  12#include <video.h>
  13#include <video_console.h>
  14#include <dm/test.h>
  15#include <dm/uclass-internal.h>
  16#include <test/ut.h>
  17
  18/*
  19 * These tests use the standard sandbox frame buffer, the resolution of which
  20 * is defined in the device tree. This only supports 16bpp so the tests only
  21 * test that code path. It would be possible to adjust this fairly easily,
  22 * by adjusting the bpix value in struct sandbox_sdl_plat. However the code
  23 * in sandbox_sdl_sync() would also need to change to handle the different
  24 * surface depth.
  25 */
  26/* Basic test of the video uclass */
  27static int dm_test_video_base(struct unit_test_state *uts)
  28{
  29        struct video_priv *priv;
  30        struct udevice *dev;
  31
  32        ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
  33        ut_asserteq(1366, video_get_xsize(dev));
  34        ut_asserteq(768, video_get_ysize(dev));
  35        priv = dev_get_uclass_priv(dev);
  36        ut_asserteq(priv->fb_size, 1366 * 768 * 2);
  37
  38        return 0;
  39}
  40DM_TEST(dm_test_video_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
  41
  42/**
  43 * compress_frame_buffer() - Compress the frame buffer and return its size
  44 *
  45 * We want to write tests which perform operations on the video console and
  46 * check that the frame buffer ends up with the correct contents. But it is
  47 * painful to store 'known good' images for comparison with the frame
  48 * buffer. As an alternative, we can compress the frame buffer and check the
  49 * size of the compressed data. This provides a pretty good level of
  50 * certainty and the resulting tests need only check a single value.
  51 *
  52 * @dev:        Video device
  53 * @return compressed size of the frame buffer, or -ve on error
  54 */
  55static int compress_frame_buffer(struct udevice *dev)
  56{
  57        struct video_priv *priv = dev_get_uclass_priv(dev);
  58        uint destlen;
  59        void *dest;
  60        int ret;
  61
  62        destlen = priv->fb_size;
  63        dest = malloc(priv->fb_size);
  64        if (!dest)
  65                return -ENOMEM;
  66        ret = BZ2_bzBuffToBuffCompress(dest, &destlen,
  67                                       priv->fb, priv->fb_size,
  68                                       3, 0, 0);
  69        free(dest);
  70        if (ret)
  71                return ret;
  72
  73        return destlen;
  74}
  75
  76/*
  77 * Call this function at any point to halt and show the current display. Be
  78 * sure to run the test with the -l flag.
  79 */
  80static void __maybe_unused see_output(void)
  81{
  82        video_sync_all();
  83        while (1);
  84}
  85
  86/* Select the video console driver to use for a video device */
  87static int select_vidconsole(struct unit_test_state *uts, const char *drv_name)
  88{
  89        struct sandbox_sdl_plat *plat;
  90        struct udevice *dev;
  91
  92        ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
  93        ut_assert(!device_active(dev));
  94        plat = dev_get_platdata(dev);
  95        plat->vidconsole_drv_name = "vidconsole0";
  96
  97        return 0;
  98}
  99
 100static void vidconsole_put_string(struct udevice *dev, const char *str)
 101{
 102        const char *s;
 103
 104        for (s = str; *s; s++)
 105                vidconsole_put_char(dev, *s);
 106}
 107
 108/* Test text output works on the video console */
 109static int dm_test_video_text(struct unit_test_state *uts)
 110{
 111        struct udevice *dev, *con;
 112        int i;
 113
 114#define WHITE           0xffff
 115#define SCROLL_LINES    100
 116
 117        ut_assertok(select_vidconsole(uts, "vidconsole0"));
 118        ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
 119        ut_asserteq(46, compress_frame_buffer(dev));
 120
 121        ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
 122        vidconsole_putc_xy(con, 0, 0, 'a');
 123        ut_asserteq(79, compress_frame_buffer(dev));
 124
 125        vidconsole_putc_xy(con, 0, 0, ' ');
 126        ut_asserteq(46, compress_frame_buffer(dev));
 127
 128        for (i = 0; i < 20; i++)
 129                vidconsole_putc_xy(con, VID_TO_POS(i * 8), 0, ' ' + i);
 130        ut_asserteq(273, compress_frame_buffer(dev));
 131
 132        vidconsole_set_row(con, 0, WHITE);
 133        ut_asserteq(46, compress_frame_buffer(dev));
 134
 135        for (i = 0; i < 20; i++)
 136                vidconsole_putc_xy(con, VID_TO_POS(i * 8), 0, ' ' + i);
 137        ut_asserteq(273, compress_frame_buffer(dev));
 138
 139        return 0;
 140}
 141DM_TEST(dm_test_video_text, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
 142
 143/* Test handling of special characters in the console */
 144static int dm_test_video_chars(struct unit_test_state *uts)
 145{
 146        struct udevice *dev, *con;
 147        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.";
 148
 149        ut_assertok(select_vidconsole(uts, "vidconsole0"));
 150        ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
 151        ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
 152        vidconsole_put_string(con, test_string);
 153        ut_asserteq(466, compress_frame_buffer(dev));
 154
 155        return 0;
 156}
 157DM_TEST(dm_test_video_chars, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
 158
 159#ifdef CONFIG_VIDEO_ANSI
 160#define ANSI_ESC "\x1b"
 161/* Test handling of ANSI escape sequences */
 162static int dm_test_video_ansi(struct unit_test_state *uts)
 163{
 164        struct udevice *dev, *con;
 165
 166        ut_assertok(select_vidconsole(uts, "vidconsole0"));
 167        ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
 168        ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
 169
 170        /* reference clear: */
 171        video_clear(con->parent);
 172        video_sync(con->parent, false);
 173        ut_asserteq(46, compress_frame_buffer(dev));
 174
 175        /* test clear escape sequence: [2J */
 176        vidconsole_put_string(con, "A\tB\tC"ANSI_ESC"[2J");
 177        ut_asserteq(46, compress_frame_buffer(dev));
 178
 179        /* test set-cursor: [%d;%df */
 180        vidconsole_put_string(con, "abc"ANSI_ESC"[2;2fab"ANSI_ESC"[4;4fcd");
 181        ut_asserteq(142, compress_frame_buffer(dev));
 182
 183        /* test colors (30-37 fg color, 40-47 bg color) */
 184        vidconsole_put_string(con, ANSI_ESC"[30;41mfoo"); /* black on red */
 185        vidconsole_put_string(con, ANSI_ESC"[33;44mbar"); /* yellow on blue */
 186        ut_asserteq(265, compress_frame_buffer(dev));
 187
 188        return 0;
 189}
 190DM_TEST(dm_test_video_ansi, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
 191#endif
 192
 193/**
 194 * check_vidconsole_output() - Run a text console test
 195 *
 196 * @uts:        Test state
 197 * @rot:        Console rotation (0, 90, 180, 270)
 198 * @wrap_size:  Expected size of compressed frame buffer for the wrap test
 199 * @scroll_size: Same for the scroll test
 200 * @return 0 on success
 201 */
 202static int check_vidconsole_output(struct unit_test_state *uts, int rot,
 203                                   int wrap_size, int scroll_size)
 204{
 205        struct udevice *dev, *con;
 206        struct sandbox_sdl_plat *plat;
 207        int i;
 208
 209        ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
 210        ut_assert(!device_active(dev));
 211        plat = dev_get_platdata(dev);
 212        plat->rot = rot;
 213
 214        ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
 215        ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
 216        ut_asserteq(46, compress_frame_buffer(dev));
 217
 218        /* Check display wrap */
 219        for (i = 0; i < 120; i++)
 220                vidconsole_put_char(con, 'A' + i % 50);
 221        ut_asserteq(wrap_size, compress_frame_buffer(dev));
 222
 223        /* Check display scrolling */
 224        for (i = 0; i < SCROLL_LINES; i++) {
 225                vidconsole_put_char(con, 'A' + i % 50);
 226                vidconsole_put_char(con, '\n');
 227        }
 228        ut_asserteq(scroll_size, compress_frame_buffer(dev));
 229
 230        /* If we scroll enough, the screen becomes blank again */
 231        for (i = 0; i < SCROLL_LINES; i++)
 232                vidconsole_put_char(con, '\n');
 233        ut_asserteq(46, compress_frame_buffer(dev));
 234
 235        return 0;
 236}
 237
 238/* Test text output through the console uclass */
 239static int dm_test_video_context(struct unit_test_state *uts)
 240{
 241        ut_assertok(select_vidconsole(uts, "vidconsole0"));
 242        ut_assertok(check_vidconsole_output(uts, 0, 788, 453));
 243
 244        return 0;
 245}
 246DM_TEST(dm_test_video_context, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
 247
 248/* Test rotated text output through the console uclass */
 249static int dm_test_video_rotation1(struct unit_test_state *uts)
 250{
 251        ut_assertok(check_vidconsole_output(uts, 1, 1112, 680));
 252
 253        return 0;
 254}
 255DM_TEST(dm_test_video_rotation1, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
 256
 257/* Test rotated text output through the console uclass */
 258static int dm_test_video_rotation2(struct unit_test_state *uts)
 259{
 260        ut_assertok(check_vidconsole_output(uts, 2, 785, 446));
 261
 262        return 0;
 263}
 264DM_TEST(dm_test_video_rotation2, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
 265
 266/* Test rotated text output through the console uclass */
 267static int dm_test_video_rotation3(struct unit_test_state *uts)
 268{
 269        ut_assertok(check_vidconsole_output(uts, 3, 1134, 681));
 270
 271        return 0;
 272}
 273DM_TEST(dm_test_video_rotation3, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
 274
 275/* Read a file into memory and return a pointer to it */
 276static int read_file(struct unit_test_state *uts, const char *fname,
 277                     ulong *addrp)
 278{
 279        int buf_size = 100000;
 280        ulong addr = 0;
 281        int size, fd;
 282        char *buf;
 283
 284        buf = map_sysmem(addr, 0);
 285        ut_assert(buf != NULL);
 286        fd = os_open(fname, OS_O_RDONLY);
 287        ut_assert(fd >= 0);
 288        size = os_read(fd, buf, buf_size);
 289        os_close(fd);
 290        ut_assert(size >= 0);
 291        ut_assert(size < buf_size);
 292        *addrp = addr;
 293
 294        return 0;
 295}
 296
 297/* Test drawing a bitmap file */
 298static int dm_test_video_bmp(struct unit_test_state *uts)
 299{
 300        struct udevice *dev;
 301        ulong addr;
 302
 303        ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
 304        ut_assertok(read_file(uts, "tools/logos/denx.bmp", &addr));
 305
 306        ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
 307        ut_asserteq(1368, compress_frame_buffer(dev));
 308
 309        return 0;
 310}
 311DM_TEST(dm_test_video_bmp, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
 312
 313/* Test drawing a compressed bitmap file */
 314static int dm_test_video_bmp_comp(struct unit_test_state *uts)
 315{
 316        struct udevice *dev;
 317        ulong addr;
 318
 319        ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
 320        ut_assertok(read_file(uts, "tools/logos/denx-comp.bmp", &addr));
 321
 322        ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
 323        ut_asserteq(1368, compress_frame_buffer(dev));
 324
 325        return 0;
 326}
 327DM_TEST(dm_test_video_bmp_comp, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
 328
 329/* Test TrueType console */
 330static int dm_test_video_truetype(struct unit_test_state *uts)
 331{
 332        struct udevice *dev, *con;
 333        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";
 334
 335        ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
 336        ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
 337        vidconsole_put_string(con, test_string);
 338        ut_asserteq(12619, compress_frame_buffer(dev));
 339
 340        return 0;
 341}
 342DM_TEST(dm_test_video_truetype, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
 343
 344/* Test scrolling TrueType console */
 345static int dm_test_video_truetype_scroll(struct unit_test_state *uts)
 346{
 347        struct sandbox_sdl_plat *plat;
 348        struct udevice *dev, *con;
 349        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";
 350
 351        ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
 352        ut_assert(!device_active(dev));
 353        plat = dev_get_platdata(dev);
 354        plat->font_size = 100;
 355
 356        ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
 357        ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
 358        vidconsole_put_string(con, test_string);
 359        ut_asserteq(33849, compress_frame_buffer(dev));
 360
 361        return 0;
 362}
 363DM_TEST(dm_test_video_truetype_scroll, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
 364
 365/* Test TrueType backspace, within and across lines */
 366static int dm_test_video_truetype_bs(struct unit_test_state *uts)
 367{
 368        struct sandbox_sdl_plat *plat;
 369        struct udevice *dev, *con;
 370        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.";
 371
 372        ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
 373        ut_assert(!device_active(dev));
 374        plat = dev_get_platdata(dev);
 375        plat->font_size = 100;
 376
 377        ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
 378        ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
 379        vidconsole_put_string(con, test_string);
 380        ut_asserteq(34871, compress_frame_buffer(dev));
 381
 382        return 0;
 383}
 384DM_TEST(dm_test_video_truetype_bs, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
 385