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 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