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