Prepare v2023.10
[platform/kernel/u-boot.git] / drivers / video / console_truetype.c
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 <log.h>
9 #include <malloc.h>
10 #include <video.h>
11 #include <video_console.h>
12
13 /* Functions needed by stb_truetype.h */
14 static int tt_floor(double val)
15 {
16         if (val < 0)
17                 return (int)(val - 0.999);
18
19         return (int)val;
20 }
21
22 static int tt_ceil(double val)
23 {
24         if (val < 0)
25                 return (int)val;
26
27         return (int)(val + 0.999);
28 }
29
30 static double frac(double val)
31 {
32         return val - tt_floor(val);
33 }
34
35 static double tt_fabs(double x)
36 {
37         return x < 0 ? -x : x;
38 }
39
40  /*
41   * Simple square root algorithm. This is from:
42   * http://stackoverflow.com/questions/1623375/writing-your-own-square-root-function
43   * Written by Chihung Yu
44   * Creative Commons license
45   * http://creativecommons.org/licenses/by-sa/3.0/legalcode
46   * It has been modified to compile correctly, and for U-Boot style.
47   */
48 static double tt_sqrt(double value)
49 {
50         double lo = 1.0;
51         double hi = value;
52
53         while (hi - lo > 0.00001) {
54                 double mid = lo + (hi - lo) / 2;
55
56                 if (mid * mid - value > 0.00001)
57                         hi = mid;
58                 else
59                         lo = mid;
60         }
61
62         return lo;
63 }
64
65 static double tt_fmod(double x, double y)
66 {
67         double rem;
68
69         if (y == 0.0)
70                 return 0.0;
71         rem = x - (x / y) * y;
72
73         return rem;
74 }
75
76 /* dummy implementation */
77 static double tt_pow(double x, double y)
78 {
79         return 0;
80 }
81
82 /* dummy implementation */
83 static double tt_cos(double val)
84 {
85         return 0;
86 }
87
88 /* dummy implementation */
89 static double tt_acos(double val)
90 {
91         return 0;
92 }
93
94 #define STBTT_ifloor            tt_floor
95 #define STBTT_iceil             tt_ceil
96 #define STBTT_fabs              tt_fabs
97 #define STBTT_sqrt              tt_sqrt
98 #define STBTT_pow               tt_pow
99 #define STBTT_fmod              tt_fmod
100 #define STBTT_cos               tt_cos
101 #define STBTT_acos              tt_acos
102 #define STBTT_malloc(size, u)   ((void)(u), malloc(size))
103 #define STBTT_free(size, u)     ((void)(u), free(size))
104 #define STBTT_assert(x)
105 #define STBTT_strlen(x)         strlen(x)
106 #define STBTT_memcpy            memcpy
107 #define STBTT_memset            memset
108
109 #define STB_TRUETYPE_IMPLEMENTATION
110 #include "stb_truetype.h"
111
112 /**
113  * struct pos_info - Records a cursor position
114  *
115  * @xpos_frac:  Fractional X position in pixels (multiplied by VID_FRAC_DIV)
116  * @ypos:       Y position (pixels from the top)
117  */
118 struct pos_info {
119         int xpos_frac;
120         int ypos;
121 };
122
123 /*
124  * Allow one for each character on the command line plus one for each newline.
125  * This is just an estimate, but it should not be exceeded.
126  */
127 #define POS_HISTORY_SIZE        (CONFIG_SYS_CBSIZE * 11 / 10)
128
129 /**
130  * struct console_tt_metrics - Information about a font / size combination
131  *
132  * This caches various font metrics which are expensive to regenerate each time
133  * the font size changes. There is one of these for each font / size combination
134  * that is being used
135  *
136  * @font_name:  Name of the font
137  * @font_size:  Vertical font size in pixels
138  * @font_data:  Pointer to TrueType font file contents
139  * @font:       TrueType font information for the current font
140  * @baseline:   Pixel offset of the font's baseline from the cursor position.
141  *              This is the 'ascent' of the font, scaled to pixel coordinates.
142  *              It measures the distance from the baseline to the top of the
143  *              font.
144  * @scale:      Scale of the font. This is calculated from the pixel height
145  *              of the font. It is used by the STB library to generate images
146  *              of the correct size.
147  */
148 struct console_tt_metrics {
149         const char *font_name;
150         int font_size;
151         const u8 *font_data;
152         stbtt_fontinfo font;
153         int baseline;
154         double scale;
155 };
156
157 /**
158  * struct console_tt_priv - Private data for this driver
159  *
160  * @cur_met:    Current metrics being used
161  * @metrics:    List metrics that can be used
162  * @num_metrics:        Number of available metrics
163  * @pos:        List of cursor positions for each character written. This is
164  *              used to handle backspace. We clear the frame buffer between
165  *              the last position and the current position, thus erasing the
166  *              last character. We record enough characters to go back to the
167  *              start of the current command line.
168  * @pos_ptr:    Current position in the position history
169  */
170 struct console_tt_priv {
171         struct console_tt_metrics *cur_met;
172         struct console_tt_metrics metrics[CONFIG_CONSOLE_TRUETYPE_MAX_METRICS];
173         int num_metrics;
174         struct pos_info pos[POS_HISTORY_SIZE];
175         int pos_ptr;
176 };
177
178 static int console_truetype_set_row(struct udevice *dev, uint row, int clr)
179 {
180         struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
181         struct console_tt_priv *priv = dev_get_priv(dev);
182         struct console_tt_metrics *met = priv->cur_met;
183         void *end, *line;
184         int ret;
185
186         line = vid_priv->fb + row * met->font_size * vid_priv->line_length;
187         end = line + met->font_size * vid_priv->line_length;
188
189         switch (vid_priv->bpix) {
190         case VIDEO_BPP8: {
191                 u8 *dst;
192
193                 if (IS_ENABLED(CONFIG_VIDEO_BPP8)) {
194                         for (dst = line; dst < (u8 *)end; ++dst)
195                                 *dst = clr;
196                 }
197                 break;
198         }
199         case VIDEO_BPP16: {
200                 u16 *dst = line;
201
202                 if (IS_ENABLED(CONFIG_VIDEO_BPP16)) {
203                         for (dst = line; dst < (u16 *)end; ++dst)
204                                 *dst = clr;
205                 }
206                 break;
207         }
208         case VIDEO_BPP32: {
209                 u32 *dst = line;
210
211                 if (IS_ENABLED(CONFIG_VIDEO_BPP32)) {
212                         for (dst = line; dst < (u32 *)end; ++dst)
213                                 *dst = clr;
214                 }
215                 break;
216         }
217         default:
218                 return -ENOSYS;
219         }
220         ret = vidconsole_sync_copy(dev, line, end);
221         if (ret)
222                 return ret;
223
224         return 0;
225 }
226
227 static int console_truetype_move_rows(struct udevice *dev, uint rowdst,
228                                      uint rowsrc, uint count)
229 {
230         struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
231         struct console_tt_priv *priv = dev_get_priv(dev);
232         struct console_tt_metrics *met = priv->cur_met;
233         void *dst;
234         void *src;
235         int i, diff, ret;
236
237         dst = vid_priv->fb + rowdst * met->font_size * vid_priv->line_length;
238         src = vid_priv->fb + rowsrc * met->font_size * vid_priv->line_length;
239         ret = vidconsole_memmove(dev, dst, src, met->font_size *
240                                  vid_priv->line_length * count);
241         if (ret)
242                 return ret;
243
244         /* Scroll up our position history */
245         diff = (rowsrc - rowdst) * met->font_size;
246         for (i = 0; i < priv->pos_ptr; i++)
247                 priv->pos[i].ypos -= diff;
248
249         return 0;
250 }
251
252 static int console_truetype_putc_xy(struct udevice *dev, uint x, uint y,
253                                     char ch)
254 {
255         struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev);
256         struct udevice *vid = dev->parent;
257         struct video_priv *vid_priv = dev_get_uclass_priv(vid);
258         struct console_tt_priv *priv = dev_get_priv(dev);
259         struct console_tt_metrics *met = priv->cur_met;
260         stbtt_fontinfo *font = &met->font;
261         int width, height, xoff, yoff;
262         double xpos, x_shift;
263         int lsb;
264         int width_frac, linenum;
265         struct pos_info *pos;
266         u8 *bits, *data;
267         int advance;
268         void *start, *end, *line;
269         int row, ret;
270
271         /* First get some basic metrics about this character */
272         stbtt_GetCodepointHMetrics(font, ch, &advance, &lsb);
273
274         /*
275          * First out our current X position in fractional pixels. If we wrote
276          * a character previously, using kerning to fine-tune the position of
277          * this character */
278         xpos = frac(VID_TO_PIXEL((double)x));
279         if (vc_priv->last_ch) {
280                 xpos += met->scale * stbtt_GetCodepointKernAdvance(font,
281                                                         vc_priv->last_ch, ch);
282         }
283
284         /*
285          * Figure out where the cursor will move to after this character, and
286          * abort if we are out of space on this line. Also calculate the
287          * effective width of this character, which will be our return value:
288          * it dictates how much the cursor will move forward on the line.
289          */
290         x_shift = xpos - (double)tt_floor(xpos);
291         xpos += advance * met->scale;
292         width_frac = (int)VID_TO_POS(advance * met->scale);
293         if (x + width_frac >= vc_priv->xsize_frac)
294                 return -EAGAIN;
295
296         /* Write the current cursor position into history */
297         if (priv->pos_ptr < POS_HISTORY_SIZE) {
298                 pos = &priv->pos[priv->pos_ptr];
299                 pos->xpos_frac = vc_priv->xcur_frac;
300                 pos->ypos = vc_priv->ycur;
301                 priv->pos_ptr++;
302         }
303
304         /*
305          * Figure out how much past the start of a pixel we are, and pass this
306          * information into the render, which will return a 8-bit-per-pixel
307          * image of the character. For empty characters, like ' ', data will
308          * return NULL;
309          */
310         data = stbtt_GetCodepointBitmapSubpixel(font, met->scale, met->scale,
311                                                 x_shift, 0, ch, &width, &height,
312                                                 &xoff, &yoff);
313         if (!data)
314                 return width_frac;
315
316         /* Figure out where to write the character in the frame buffer */
317         bits = data;
318         start = vid_priv->fb + y * vid_priv->line_length +
319                 VID_TO_PIXEL(x) * VNBYTES(vid_priv->bpix);
320         linenum = met->baseline + yoff;
321         if (linenum > 0)
322                 start += linenum * vid_priv->line_length;
323         line = start;
324
325         /*
326          * Write a row at a time, converting the 8bpp image into the colour
327          * depth of the display. We only expect white-on-black or the reverse
328          * so the code only handles this simple case.
329          */
330         for (row = 0; row < height; row++) {
331                 switch (vid_priv->bpix) {
332                 case VIDEO_BPP8:
333                         if (IS_ENABLED(CONFIG_VIDEO_BPP8)) {
334                                 u8 *dst = line + xoff;
335                                 int i;
336
337                                 for (i = 0; i < width; i++) {
338                                         int val = *bits;
339                                         int out;
340
341                                         if (vid_priv->colour_bg)
342                                                 val = 255 - val;
343                                         out = val;
344                                         if (vid_priv->colour_fg)
345                                                 *dst++ |= out;
346                                         else
347                                                 *dst++ &= out;
348                                         bits++;
349                                 }
350                                 end = dst;
351                         }
352                         break;
353                 case VIDEO_BPP16: {
354                         uint16_t *dst = (uint16_t *)line + xoff;
355                         int i;
356
357                         if (IS_ENABLED(CONFIG_VIDEO_BPP16)) {
358                                 for (i = 0; i < width; i++) {
359                                         int val = *bits;
360                                         int out;
361
362                                         if (vid_priv->colour_bg)
363                                                 val = 255 - val;
364                                         out = val >> 3 |
365                                                 (val >> 2) << 5 |
366                                                 (val >> 3) << 11;
367                                         if (vid_priv->colour_fg)
368                                                 *dst++ |= out;
369                                         else
370                                                 *dst++ &= out;
371                                         bits++;
372                                 }
373                                 end = dst;
374                         }
375                         break;
376                 }
377                 case VIDEO_BPP32: {
378                         u32 *dst = (u32 *)line + xoff;
379                         int i;
380
381                         if (IS_ENABLED(CONFIG_VIDEO_BPP32)) {
382                                 for (i = 0; i < width; i++) {
383                                         int val = *bits;
384                                         int out;
385
386                                         if (vid_priv->colour_bg)
387                                                 val = 255 - val;
388                                         out = val | val << 8 | val << 16;
389                                         if (vid_priv->colour_fg)
390                                                 *dst++ |= out;
391                                         else
392                                                 *dst++ &= out;
393                                         bits++;
394                                 }
395                                 end = dst;
396                         }
397                         break;
398                 }
399                 default:
400                         free(data);
401                         return -ENOSYS;
402                 }
403
404                 line += vid_priv->line_length;
405         }
406         ret = vidconsole_sync_copy(dev, start, line);
407         if (ret)
408                 return ret;
409         free(data);
410
411         return width_frac;
412 }
413
414 /**
415  * console_truetype_backspace() - Handle a backspace operation
416  *
417  * This clears the previous character so that the console looks as if it had
418  * not been entered.
419  *
420  * @dev:        Device to update
421  * Return: 0 if OK, -ENOSYS if not supported
422  */
423 static int console_truetype_backspace(struct udevice *dev)
424 {
425         struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev);
426         struct console_tt_priv *priv = dev_get_priv(dev);
427         struct udevice *vid_dev = dev->parent;
428         struct video_priv *vid_priv = dev_get_uclass_priv(vid_dev);
429         struct pos_info *pos;
430         int xend;
431
432         /*
433          * This indicates a very strange error higher in the stack. The caller
434          * has sent out n character and n + 1 backspaces.
435          */
436         if (!priv->pos_ptr)
437                 return -ENOSYS;
438
439         /* Pop the last cursor position off the stack */
440         pos = &priv->pos[--priv->pos_ptr];
441
442         /*
443          * Figure out the end position for clearing. Normally it is the current
444          * cursor position, but if we are clearing a character on the previous
445          * line, we clear from the end of the line.
446          */
447         if (pos->ypos == vc_priv->ycur)
448                 xend = VID_TO_PIXEL(vc_priv->xcur_frac);
449         else
450                 xend = vid_priv->xsize;
451
452         video_fill_part(vid_dev, VID_TO_PIXEL(pos->xpos_frac), pos->ypos,
453                         xend, pos->ypos + vc_priv->y_charsize,
454                         vid_priv->colour_bg);
455
456         /* Move the cursor back to where it was when we pushed this record */
457         vc_priv->xcur_frac = pos->xpos_frac;
458         vc_priv->ycur = pos->ypos;
459
460         return 0;
461 }
462
463 static int console_truetype_entry_start(struct udevice *dev)
464 {
465         struct console_tt_priv *priv = dev_get_priv(dev);
466
467         /* A new input line has start, so clear our history */
468         priv->pos_ptr = 0;
469
470         return 0;
471 }
472
473 /*
474  * Provides a list of fonts which can be obtained at run-time in U-Boot. These
475  * are compiled in by the Makefile.
476  *
477  * At present there is no mechanism to select a particular font - the first
478  * one found is the one that is used. But the build system and the code here
479  * supports multiple fonts, which may be useful for certain firmware screens.
480  */
481 struct font_info {
482         char *name;
483         u8 *begin;
484         u8 *end;
485 };
486
487 #define FONT_DECL(_name) \
488         extern u8 __ttf_ ## _name ## _begin[]; \
489         extern u8 __ttf_ ## _name ## _end[];
490
491 #define FONT_ENTRY(_name)               { \
492         .name = #_name, \
493         .begin = __ttf_ ## _name ## _begin, \
494         .end = __ttf_ ## _name ## _end, \
495         }
496
497 FONT_DECL(nimbus_sans_l_regular);
498 FONT_DECL(ankacoder_c75_r);
499 FONT_DECL(rufscript010);
500 FONT_DECL(cantoraone_regular);
501
502 static struct font_info font_table[] = {
503 #ifdef CONFIG_CONSOLE_TRUETYPE_NIMBUS
504         FONT_ENTRY(nimbus_sans_l_regular),
505 #endif
506 #ifdef CONFIG_CONSOLE_TRUETYPE_ANKACODER
507         FONT_ENTRY(ankacoder_c75_r),
508 #endif
509 #ifdef CONFIG_CONSOLE_TRUETYPE_RUFSCRIPT
510         FONT_ENTRY(rufscript010),
511 #endif
512 #ifdef CONFIG_CONSOLE_TRUETYPE_CANTORAONE
513         FONT_ENTRY(cantoraone_regular),
514 #endif
515         {} /* sentinel */
516 };
517
518 /**
519  * font_valid() - Check if a font-table entry is valid
520  *
521  * Depending on available files in the build system, fonts may end up being
522  * empty.
523  *
524  * @return true if the entry is valid
525  */
526 static inline bool font_valid(struct font_info *tab)
527 {
528         return abs(tab->begin - tab->end) > 4;
529 }
530
531 /**
532  * console_truetype_find_font() - Find a suitable font
533  *
534  * This searches for the first available font.
535  *
536  * Return: pointer to the font-table entry, or NULL if none is found
537  */
538 static struct font_info *console_truetype_find_font(void)
539 {
540         struct font_info *tab;
541
542         for (tab = font_table; tab->begin; tab++) {
543                 if (font_valid(tab)) {
544                         debug("%s: Font '%s', at %p, size %lx\n", __func__,
545                               tab->name, tab->begin,
546                               (ulong)(tab->end - tab->begin));
547                         return tab;
548                 }
549         }
550
551         return NULL;
552 }
553
554 int console_truetype_get_font(struct udevice *dev, int seq,
555                               struct vidfont_info *info)
556 {
557         struct font_info *tab;
558         int i;
559
560         for (i = 0, tab = font_table; tab->begin; tab++, i++) {
561                 if (i == seq && font_valid(tab)) {
562                         info->name = tab->name;
563                         return 0;
564                 }
565         }
566
567         return -ENOENT;
568 }
569
570 /**
571  * truetype_add_metrics() - Add a new font/size combination
572  *
573  * @dev:        Video console device to update
574  * @font_name:  Name of font
575  * @font_size:  Size of the font (norminal pixel height)
576  * @font_data:  Pointer to the font data
577  * @return 0 if OK, -EPERM if stbtt failed, -E2BIG if the the metrics table is
578  *      full
579  */
580 static int truetype_add_metrics(struct udevice *dev, const char *font_name,
581                                 uint font_size, const void *font_data)
582 {
583         struct console_tt_priv *priv = dev_get_priv(dev);
584         struct console_tt_metrics *met;
585         stbtt_fontinfo *font;
586         int ascent;
587
588         if (priv->num_metrics == CONFIG_CONSOLE_TRUETYPE_MAX_METRICS)
589                 return log_msg_ret("num", -E2BIG);
590
591         met = &priv->metrics[priv->num_metrics];
592         met->font_name = font_name;
593         met->font_size = font_size;
594         met->font_data = font_data;
595
596         font = &met->font;
597         if (!stbtt_InitFont(font, font_data, 0)) {
598                 debug("%s: Font init failed\n", __func__);
599                 return -EPERM;
600         }
601
602         /* Pre-calculate some things we will need regularly */
603         met->scale = stbtt_ScaleForPixelHeight(font, font_size);
604         stbtt_GetFontVMetrics(font, &ascent, 0, 0);
605         met->baseline = (int)(ascent * met->scale);
606
607         return priv->num_metrics++;
608 }
609
610 /**
611  * find_metrics() - Find the metrics for a given font and size
612  *
613  * @dev:        Video console device to update
614  * @name:       Name of font
615  * @size:       Size of the font (norminal pixel height)
616  * @return metrics, if found, else NULL
617  */
618 static struct console_tt_metrics *find_metrics(struct udevice *dev,
619                                                const char *name, uint size)
620 {
621         struct console_tt_priv *priv = dev_get_priv(dev);
622         int i;
623
624         for (i = 0; i < priv->num_metrics; i++) {
625                 struct console_tt_metrics *met = &priv->metrics[i];
626
627                 if (!strcmp(name, met->font_name) && met->font_size == size)
628                         return met;
629         }
630
631         return NULL;
632 }
633
634 static void select_metrics(struct udevice *dev, struct console_tt_metrics *met)
635 {
636         struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev);
637         struct console_tt_priv *priv = dev_get_priv(dev);
638         struct udevice *vid_dev = dev_get_parent(dev);
639         struct video_priv *vid_priv = dev_get_uclass_priv(vid_dev);
640
641         priv->cur_met = met;
642         vc_priv->x_charsize = met->font_size;
643         vc_priv->y_charsize = met->font_size;
644         vc_priv->xstart_frac = VID_TO_POS(2);
645         vc_priv->cols = vid_priv->xsize / met->font_size;
646         vc_priv->rows = vid_priv->ysize / met->font_size;
647         vc_priv->tab_width_frac = VID_TO_POS(met->font_size) * 8 / 2;
648 }
649
650 static int get_metrics(struct udevice *dev, const char *name, uint size,
651                        struct console_tt_metrics **metp)
652 {
653         struct console_tt_priv *priv = dev_get_priv(dev);
654         struct console_tt_metrics *met;
655         struct font_info *tab;
656
657         if (name || size) {
658                 if (!size)
659                         size = CONFIG_CONSOLE_TRUETYPE_SIZE;
660                 if (!name)
661                         name = font_table->name;
662
663                 met = find_metrics(dev, name, size);
664                 if (!met) {
665                         for (tab = font_table; tab->begin; tab++) {
666                                 if (font_valid(tab) &&
667                                     !strcmp(name, tab->name)) {
668                                         int ret;
669
670                                         ret = truetype_add_metrics(dev,
671                                                                    tab->name,
672                                                                    size,
673                                                                    tab->begin);
674                                         if (ret < 0)
675                                                 return log_msg_ret("add", ret);
676
677                                         met = &priv->metrics[ret];
678                                         break;
679                                 }
680                         }
681                 }
682                 if (!met)
683                         return log_msg_ret("find", -ENOENT);
684         } else {
685                 /* Use the default font */
686                 met = priv->metrics;
687         }
688
689         *metp = met;
690
691         return 0;
692 }
693
694 static int truetype_select_font(struct udevice *dev, const char *name,
695                                 uint size)
696 {
697         struct console_tt_metrics *met;
698         int ret;
699
700         ret = get_metrics(dev, name, size, &met);
701         if (ret)
702                 return log_msg_ret("sel", ret);
703
704         select_metrics(dev, met);
705
706         return 0;
707 }
708
709 int truetype_measure(struct udevice *dev, const char *name, uint size,
710                      const char *text, struct vidconsole_bbox *bbox)
711 {
712         struct console_tt_metrics *met;
713         stbtt_fontinfo *font;
714         int lsb, advance;
715         const char *s;
716         int width;
717         int last;
718         int ret;
719
720         ret = get_metrics(dev, name, size, &met);
721         if (ret)
722                 return log_msg_ret("sel", ret);
723
724         bbox->valid = false;
725         if (!*text)
726                 return 0;
727
728         font = &met->font;
729         width = 0;
730         for (last = 0, s = text; *s; s++) {
731                 int ch = *s;
732
733                 /* Used kerning to fine-tune the position of this character */
734                 if (last)
735                         width += stbtt_GetCodepointKernAdvance(font, last, ch);
736
737                 /* First get some basic metrics about this character */
738                 stbtt_GetCodepointHMetrics(font, ch, &advance, &lsb);
739
740                 width += advance;
741                 last = ch;
742         }
743
744         bbox->valid = true;
745         bbox->x0 = 0;
746         bbox->y0 = 0;
747         bbox->x1 = tt_ceil((double)width * met->scale);
748         bbox->y1 = met->font_size;
749
750         return 0;
751 }
752
753 const char *console_truetype_get_font_size(struct udevice *dev, uint *sizep)
754 {
755         struct console_tt_priv *priv = dev_get_priv(dev);
756         struct console_tt_metrics *met = priv->cur_met;
757
758         *sizep = met->font_size;
759
760         return met->font_name;
761 }
762
763 static int console_truetype_probe(struct udevice *dev)
764 {
765         struct console_tt_priv *priv = dev_get_priv(dev);
766         struct udevice *vid_dev = dev->parent;
767         struct video_priv *vid_priv = dev_get_uclass_priv(vid_dev);
768         struct font_info *tab;
769         uint font_size;
770         int ret;
771
772         debug("%s: start\n", __func__);
773         if (vid_priv->font_size)
774                 font_size = vid_priv->font_size;
775         else
776                 font_size = CONFIG_CONSOLE_TRUETYPE_SIZE;
777         tab = console_truetype_find_font();
778         if (!tab) {
779                 debug("%s: Could not find any fonts\n", __func__);
780                 return -EBFONT;
781         }
782
783         ret = truetype_add_metrics(dev, tab->name, font_size, tab->begin);
784         if (ret < 0)
785                 return log_msg_ret("add", ret);
786         priv->cur_met = &priv->metrics[ret];
787
788         select_metrics(dev, &priv->metrics[ret]);
789
790         debug("%s: ready\n", __func__);
791
792         return 0;
793 }
794
795 struct vidconsole_ops console_truetype_ops = {
796         .putc_xy        = console_truetype_putc_xy,
797         .move_rows      = console_truetype_move_rows,
798         .set_row        = console_truetype_set_row,
799         .backspace      = console_truetype_backspace,
800         .entry_start    = console_truetype_entry_start,
801         .get_font       = console_truetype_get_font,
802         .get_font_size  = console_truetype_get_font_size,
803         .select_font    = truetype_select_font,
804         .measure        = truetype_measure,
805 };
806
807 U_BOOT_DRIVER(vidconsole_truetype) = {
808         .name   = "vidconsole_tt",
809         .id     = UCLASS_VIDEO_CONSOLE,
810         .ops    = &console_truetype_ops,
811         .probe  = console_truetype_probe,
812         .priv_auto      = sizeof(struct console_tt_priv),
813 };