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