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