1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (c) 2016 Google, Inc 4 */ 5 6 #include <common.h> 7 #include <dm.h> 8 #include <video.h> 9 #include <video_console.h> 10 11 /* Functions needed by stb_truetype.h */ 12 static int tt_floor(double val) 13 { 14 if (val < 0) 15 return (int)(val - 0.999); 16 17 return (int)val; 18 } 19 20 static int tt_ceil(double val) 21 { 22 if (val < 0) 23 return (int)val; 24 25 return (int)(val + 0.999); 26 } 27 28 static double frac(double val) 29 { 30 return val - tt_floor(val); 31 } 32 33 static double tt_fabs(double x) 34 { 35 return x < 0 ? -x : x; 36 } 37 38 /* 39 * Simple square root algorithm. This is from: 40 * http://stackoverflow.com/questions/1623375/writing-your-own-square-root-function 41 * Written by Chihung Yu 42 * Creative Commons license 43 * http://creativecommons.org/licenses/by-sa/3.0/legalcode 44 * It has been modified to compile correctly, and for U-Boot style. 45 */ 46 static double tt_sqrt(double value) 47 { 48 double lo = 1.0; 49 double hi = value; 50 51 while (hi - lo > 0.00001) { 52 double mid = lo + (hi - lo) / 2; 53 54 if (mid * mid - value > 0.00001) 55 hi = mid; 56 else 57 lo = mid; 58 } 59 60 return lo; 61 } 62 63 #define STBTT_ifloor tt_floor 64 #define STBTT_iceil tt_ceil 65 #define STBTT_fabs tt_fabs 66 #define STBTT_sqrt tt_sqrt 67 #define STBTT_malloc(size, u) ((void)(u), malloc(size)) 68 #define STBTT_free(size, u) ((void)(u), free(size)) 69 #define STBTT_assert(x) 70 #define STBTT_strlen(x) strlen(x) 71 #define STBTT_memcpy memcpy 72 #define STBTT_memset memset 73 74 #define STB_TRUETYPE_IMPLEMENTATION 75 #include "stb_truetype.h" 76 77 /** 78 * struct pos_info - Records a cursor position 79 * 80 * @xpos_frac: Fractional X position in pixels (multiplied by VID_FRAC_DIV) 81 * @ypos: Y position (pixels from the top) 82 */ 83 struct pos_info { 84 int xpos_frac; 85 int ypos; 86 }; 87 88 /* 89 * Allow one for each character on the command line plus one for each newline. 90 * This is just an estimate, but it should not be exceeded. 91 */ 92 #define POS_HISTORY_SIZE (CONFIG_SYS_CBSIZE * 11 / 10) 93 94 /** 95 * struct console_tt_priv - Private data for this driver 96 * 97 * @font_size: Vertical font size in pixels 98 * @font_data: Pointer to TrueType font file contents 99 * @font: TrueType font information for the current font 100 * @pos: List of cursor positions for each character written. This is 101 * used to handle backspace. We clear the frame buffer between 102 * the last position and the current position, thus erasing the 103 * last character. We record enough characters to go back to the 104 * start of the current command line. 105 * @pos_ptr: Current position in the position history 106 * @baseline: Pixel offset of the font's baseline from the cursor position. 107 * This is the 'ascent' of the font, scaled to pixel coordinates. 108 * It measures the distance from the baseline to the top of the 109 * font. 110 * @scale: Scale of the font. This is calculated from the pixel height 111 * of the font. It is used by the STB library to generate images 112 * of the correct size. 113 */ 114 struct console_tt_priv { 115 int font_size; 116 u8 *font_data; 117 stbtt_fontinfo font; 118 struct pos_info pos[POS_HISTORY_SIZE]; 119 int pos_ptr; 120 int baseline; 121 double scale; 122 }; 123 124 static int console_truetype_set_row(struct udevice *dev, uint row, int clr) 125 { 126 struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent); 127 struct console_tt_priv *priv = dev_get_priv(dev); 128 void *line; 129 int pixels = priv->font_size * vid_priv->line_length; 130 int i; 131 132 line = vid_priv->fb + row * priv->font_size * vid_priv->line_length; 133 switch (vid_priv->bpix) { 134 #ifdef CONFIG_VIDEO_BPP8 135 case VIDEO_BPP8: { 136 uint8_t *dst = line; 137 138 for (i = 0; i < pixels; i++) 139 *dst++ = clr; 140 break; 141 } 142 #endif 143 #ifdef CONFIG_VIDEO_BPP16 144 case VIDEO_BPP16: { 145 uint16_t *dst = line; 146 147 for (i = 0; i < pixels; i++) 148 *dst++ = clr; 149 break; 150 } 151 #endif 152 #ifdef CONFIG_VIDEO_BPP32 153 case VIDEO_BPP32: { 154 uint32_t *dst = line; 155 156 for (i = 0; i < pixels; i++) 157 *dst++ = clr; 158 break; 159 } 160 #endif 161 default: 162 return -ENOSYS; 163 } 164 165 return 0; 166 } 167 168 static int console_truetype_move_rows(struct udevice *dev, uint rowdst, 169 uint rowsrc, uint count) 170 { 171 struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent); 172 struct console_tt_priv *priv = dev_get_priv(dev); 173 void *dst; 174 void *src; 175 int i, diff; 176 177 dst = vid_priv->fb + rowdst * priv->font_size * vid_priv->line_length; 178 src = vid_priv->fb + rowsrc * priv->font_size * vid_priv->line_length; 179 memmove(dst, src, priv->font_size * vid_priv->line_length * count); 180 181 /* Scroll up our position history */ 182 diff = (rowsrc - rowdst) * priv->font_size; 183 for (i = 0; i < priv->pos_ptr; i++) 184 priv->pos[i].ypos -= diff; 185 186 return 0; 187 } 188 189 static int console_truetype_putc_xy(struct udevice *dev, uint x, uint y, 190 char ch) 191 { 192 struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev); 193 struct udevice *vid = dev->parent; 194 struct video_priv *vid_priv = dev_get_uclass_priv(vid); 195 struct console_tt_priv *priv = dev_get_priv(dev); 196 stbtt_fontinfo *font = &priv->font; 197 int width, height, xoff, yoff; 198 double xpos, x_shift; 199 int lsb; 200 int width_frac, linenum; 201 struct pos_info *pos; 202 u8 *bits, *data; 203 int advance; 204 void *line; 205 int row; 206 207 /* First get some basic metrics about this character */ 208 stbtt_GetCodepointHMetrics(font, ch, &advance, &lsb); 209 210 /* 211 * First out our current X position in fractional pixels. If we wrote 212 * a character previously, using kerning to fine-tune the position of 213 * this character */ 214 xpos = frac(VID_TO_PIXEL((double)x)); 215 if (vc_priv->last_ch) { 216 xpos += priv->scale * stbtt_GetCodepointKernAdvance(font, 217 vc_priv->last_ch, ch); 218 } 219 220 /* 221 * Figure out where the cursor will move to after this character, and 222 * abort if we are out of space on this line. Also calculate the 223 * effective width of this character, which will be our return value: 224 * it dictates how much the cursor will move forward on the line. 225 */ 226 x_shift = xpos - (double)tt_floor(xpos); 227 xpos += advance * priv->scale; 228 width_frac = (int)VID_TO_POS(xpos); 229 if (x + width_frac >= vc_priv->xsize_frac) 230 return -EAGAIN; 231 232 /* Write the current cursor position into history */ 233 if (priv->pos_ptr < POS_HISTORY_SIZE) { 234 pos = &priv->pos[priv->pos_ptr]; 235 pos->xpos_frac = vc_priv->xcur_frac; 236 pos->ypos = vc_priv->ycur; 237 priv->pos_ptr++; 238 } 239 240 /* 241 * Figure out how much past the start of a pixel we are, and pass this 242 * information into the render, which will return a 8-bit-per-pixel 243 * image of the character. For empty characters, like ' ', data will 244 * return NULL; 245 */ 246 data = stbtt_GetCodepointBitmapSubpixel(font, priv->scale, priv->scale, 247 x_shift, 0, ch, &width, &height, 248 &xoff, &yoff); 249 if (!data) 250 return width_frac; 251 252 /* Figure out where to write the character in the frame buffer */ 253 bits = data; 254 line = vid_priv->fb + y * vid_priv->line_length + 255 VID_TO_PIXEL(x) * VNBYTES(vid_priv->bpix); 256 linenum = priv->baseline + yoff; 257 if (linenum > 0) 258 line += linenum * vid_priv->line_length; 259 260 /* 261 * Write a row at a time, converting the 8bpp image into the colour 262 * depth of the display. We only expect white-on-black or the reverse 263 * so the code only handles this simple case. 264 */ 265 for (row = 0; row < height; row++) { 266 switch (vid_priv->bpix) { 267 #ifdef CONFIG_VIDEO_BPP16 268 case VIDEO_BPP16: { 269 uint16_t *dst = (uint16_t *)line + xoff; 270 int i; 271 272 for (i = 0; i < width; i++) { 273 int val = *bits; 274 int out; 275 276 if (vid_priv->colour_bg) 277 val = 255 - val; 278 out = val >> 3 | 279 (val >> 2) << 5 | 280 (val >> 3) << 11; 281 if (vid_priv->colour_fg) 282 *dst++ |= out; 283 else 284 *dst++ &= out; 285 bits++; 286 } 287 break; 288 } 289 #endif 290 default: 291 free(data); 292 return -ENOSYS; 293 } 294 295 line += vid_priv->line_length; 296 } 297 free(data); 298 299 return width_frac; 300 } 301 302 /** 303 * console_truetype_erase() - Erase a character 304 * 305 * This is used for backspace. We erase a square of the display within the 306 * given bounds. 307 * 308 * @dev: Device to update 309 * @xstart: X start position in pixels from the left 310 * @ystart: Y start position in pixels from the top 311 * @xend: X end position in pixels from the left 312 * @yend: Y end position in pixels from the top 313 * @clr: Value to write 314 * @return 0 if OK, -ENOSYS if the display depth is not supported 315 */ 316 static int console_truetype_erase(struct udevice *dev, int xstart, int ystart, 317 int xend, int yend, int clr) 318 { 319 struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent); 320 void *line; 321 int pixels = xend - xstart; 322 int row, i; 323 324 line = vid_priv->fb + ystart * vid_priv->line_length; 325 line += xstart * VNBYTES(vid_priv->bpix); 326 for (row = ystart; row < yend; row++) { 327 switch (vid_priv->bpix) { 328 #ifdef CONFIG_VIDEO_BPP8 329 case VIDEO_BPP8: { 330 uint8_t *dst = line; 331 332 for (i = 0; i < pixels; i++) 333 *dst++ = clr; 334 break; 335 } 336 #endif 337 #ifdef CONFIG_VIDEO_BPP16 338 case VIDEO_BPP16: { 339 uint16_t *dst = line; 340 341 for (i = 0; i < pixels; i++) 342 *dst++ = clr; 343 break; 344 } 345 #endif 346 #ifdef CONFIG_VIDEO_BPP32 347 case VIDEO_BPP32: { 348 uint32_t *dst = line; 349 350 for (i = 0; i < pixels; i++) 351 *dst++ = clr; 352 break; 353 } 354 #endif 355 default: 356 return -ENOSYS; 357 } 358 line += vid_priv->line_length; 359 } 360 361 return 0; 362 } 363 364 /** 365 * console_truetype_backspace() - Handle a backspace operation 366 * 367 * This clears the previous character so that the console looks as if it had 368 * not been entered. 369 * 370 * @dev: Device to update 371 * @return 0 if OK, -ENOSYS if not supported 372 */ 373 static int console_truetype_backspace(struct udevice *dev) 374 { 375 struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev); 376 struct console_tt_priv *priv = dev_get_priv(dev); 377 struct udevice *vid_dev = dev->parent; 378 struct video_priv *vid_priv = dev_get_uclass_priv(vid_dev); 379 struct pos_info *pos; 380 int xend; 381 382 /* 383 * This indicates a very strange error higher in the stack. The caller 384 * has sent out n character and n + 1 backspaces. 385 */ 386 if (!priv->pos_ptr) 387 return -ENOSYS; 388 389 /* Pop the last cursor position off the stack */ 390 pos = &priv->pos[--priv->pos_ptr]; 391 392 /* 393 * Figure out the end position for clearing. Normlly it is the current 394 * cursor position, but if we are clearing a character on the previous 395 * line, we clear from the end of the line. 396 */ 397 if (pos->ypos == vc_priv->ycur) 398 xend = VID_TO_PIXEL(vc_priv->xcur_frac); 399 else 400 xend = vid_priv->xsize; 401 402 console_truetype_erase(dev, VID_TO_PIXEL(pos->xpos_frac), pos->ypos, 403 xend, pos->ypos + vc_priv->y_charsize, 404 vid_priv->colour_bg); 405 406 /* Move the cursor back to where it was when we pushed this record */ 407 vc_priv->xcur_frac = pos->xpos_frac; 408 vc_priv->ycur = pos->ypos; 409 410 return 0; 411 } 412 413 static int console_truetype_entry_start(struct udevice *dev) 414 { 415 struct console_tt_priv *priv = dev_get_priv(dev); 416 417 /* A new input line has start, so clear our history */ 418 priv->pos_ptr = 0; 419 420 return 0; 421 } 422 423 /* 424 * Provides a list of fonts which can be obtained at run-time in U-Boot. These 425 * are compiled in by the Makefile. 426 * 427 * At present there is no mechanism to select a particular font - the first 428 * one found is the one that is used. But the build system and the code here 429 * supports multiple fonts, which may be useful for certain firmware screens. 430 */ 431 struct font_info { 432 char *name; 433 u8 *begin; 434 u8 *end; 435 }; 436 437 #define FONT_DECL(_name) \ 438 extern u8 __ttf_ ## _name ## _begin[]; \ 439 extern u8 __ttf_ ## _name ## _end[]; 440 441 #define FONT_ENTRY(_name) { \ 442 .name = #_name, \ 443 .begin = __ttf_ ## _name ## _begin, \ 444 .end = __ttf_ ## _name ## _end, \ 445 } 446 447 FONT_DECL(nimbus_sans_l_regular); 448 FONT_DECL(ankacoder_c75_r); 449 FONT_DECL(rufscript010); 450 FONT_DECL(cantoraone_regular); 451 452 static struct font_info font_table[] = { 453 #ifdef CONFIG_CONSOLE_TRUETYPE_NIMBUS 454 FONT_ENTRY(nimbus_sans_l_regular), 455 #endif 456 #ifdef CONFIG_CONSOLE_TRUETYPE_ANKACODER 457 FONT_ENTRY(ankacoder_c75_r), 458 #endif 459 #ifdef CONFIG_CONSOLE_TRUETYPE_RUFSCRIPT 460 FONT_ENTRY(rufscript010), 461 #endif 462 #ifdef CONFIG_CONSOLE_TRUETYPE_CANTORAONE 463 FONT_ENTRY(cantoraone_regular), 464 #endif 465 {} /* sentinel */ 466 }; 467 468 #define FONT_BEGIN(name) __ttf_ ## name ## _begin 469 #define FONT_END(name) __ttf_ ## name ## _end 470 #define FONT_IS_VALID(name) (abs(FONT_END(name) - FONT_BEGIN) > 4) 471 472 /** 473 * console_truetype_find_font() - Find a suitable font 474 * 475 * This searched for the first available font. 476 * 477 * @return pointer to the font, or NULL if none is found 478 */ 479 static u8 *console_truetype_find_font(void) 480 { 481 struct font_info *tab; 482 483 for (tab = font_table; tab->begin; tab++) { 484 if (abs(tab->begin - tab->end) > 4) { 485 debug("%s: Font '%s', at %p, size %lx\n", __func__, 486 tab->name, tab->begin, 487 (ulong)(tab->end - tab->begin)); 488 return tab->begin; 489 } 490 } 491 492 return NULL; 493 } 494 495 static int console_truetype_probe(struct udevice *dev) 496 { 497 struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev); 498 struct console_tt_priv *priv = dev_get_priv(dev); 499 struct udevice *vid_dev = dev->parent; 500 struct video_priv *vid_priv = dev_get_uclass_priv(vid_dev); 501 stbtt_fontinfo *font = &priv->font; 502 int ascent; 503 504 debug("%s: start\n", __func__); 505 if (vid_priv->font_size) 506 priv->font_size = vid_priv->font_size; 507 else 508 priv->font_size = CONFIG_CONSOLE_TRUETYPE_SIZE; 509 priv->font_data = console_truetype_find_font(); 510 if (!priv->font_data) { 511 debug("%s: Could not find any fonts\n", __func__); 512 return -EBFONT; 513 } 514 515 vc_priv->x_charsize = priv->font_size; 516 vc_priv->y_charsize = priv->font_size; 517 vc_priv->xstart_frac = VID_TO_POS(2); 518 vc_priv->cols = vid_priv->xsize / priv->font_size; 519 vc_priv->rows = vid_priv->ysize / priv->font_size; 520 vc_priv->tab_width_frac = VID_TO_POS(priv->font_size) * 8 / 2; 521 522 if (!stbtt_InitFont(font, priv->font_data, 0)) { 523 debug("%s: Font init failed\n", __func__); 524 return -EPERM; 525 } 526 527 /* Pre-calculate some things we will need regularly */ 528 priv->scale = stbtt_ScaleForPixelHeight(font, priv->font_size); 529 stbtt_GetFontVMetrics(font, &ascent, 0, 0); 530 priv->baseline = (int)(ascent * priv->scale); 531 debug("%s: ready\n", __func__); 532 533 return 0; 534 } 535 536 struct vidconsole_ops console_truetype_ops = { 537 .putc_xy = console_truetype_putc_xy, 538 .move_rows = console_truetype_move_rows, 539 .set_row = console_truetype_set_row, 540 .backspace = console_truetype_backspace, 541 .entry_start = console_truetype_entry_start, 542 }; 543 544 U_BOOT_DRIVER(vidconsole_truetype) = { 545 .name = "vidconsole_tt", 546 .id = UCLASS_VIDEO_CONSOLE, 547 .ops = &console_truetype_ops, 548 .probe = console_truetype_probe, 549 .priv_auto_alloc_size = sizeof(struct console_tt_priv), 550 }; 551