video: omap: rename LCD controller registers
[oweals/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 <malloc.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 #ifdef CONFIG_VIDEO_BPP32
292                 case VIDEO_BPP32: {
293                         u32 *dst = (u32 *)line + xoff;
294                         int i;
295
296                         for (i = 0; i < width; i++) {
297                                 int val = *bits;
298                                 int out;
299
300                                 if (vid_priv->colour_bg)
301                                         val = 255 - val;
302                                 out = val | val << 8 | val << 16;
303                                 if (vid_priv->colour_fg)
304                                         *dst++ |= out;
305                                 else
306                                         *dst++ &= out;
307                                 bits++;
308                         }
309                         break;
310                 }
311 #endif
312                 default:
313                         free(data);
314                         return -ENOSYS;
315                 }
316
317                 line += vid_priv->line_length;
318         }
319         free(data);
320
321         return width_frac;
322 }
323
324 /**
325  * console_truetype_erase() - Erase a character
326  *
327  * This is used for backspace. We erase a square of the display within the
328  * given bounds.
329  *
330  * @dev:        Device to update
331  * @xstart:     X start position in pixels from the left
332  * @ystart:     Y start position in pixels from the top
333  * @xend:       X end position in pixels from the left
334  * @yend:       Y end position  in pixels from the top
335  * @clr:        Value to write
336  * @return 0 if OK, -ENOSYS if the display depth is not supported
337  */
338 static int console_truetype_erase(struct udevice *dev, int xstart, int ystart,
339                                   int xend, int yend, int clr)
340 {
341         struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
342         void *line;
343         int pixels = xend - xstart;
344         int row, i;
345
346         line = vid_priv->fb + ystart * vid_priv->line_length;
347         line += xstart * VNBYTES(vid_priv->bpix);
348         for (row = ystart; row < yend; row++) {
349                 switch (vid_priv->bpix) {
350 #ifdef CONFIG_VIDEO_BPP8
351                 case VIDEO_BPP8: {
352                         uint8_t *dst = line;
353
354                         for (i = 0; i < pixels; i++)
355                                 *dst++ = clr;
356                         break;
357                 }
358 #endif
359 #ifdef CONFIG_VIDEO_BPP16
360                 case VIDEO_BPP16: {
361                         uint16_t *dst = line;
362
363                         for (i = 0; i < pixels; i++)
364                                 *dst++ = clr;
365                         break;
366                 }
367 #endif
368 #ifdef CONFIG_VIDEO_BPP32
369                 case VIDEO_BPP32: {
370                         uint32_t *dst = line;
371
372                         for (i = 0; i < pixels; i++)
373                                 *dst++ = clr;
374                         break;
375                 }
376 #endif
377                 default:
378                         return -ENOSYS;
379                 }
380                 line += vid_priv->line_length;
381         }
382
383         return 0;
384 }
385
386 /**
387  * console_truetype_backspace() - Handle a backspace operation
388  *
389  * This clears the previous character so that the console looks as if it had
390  * not been entered.
391  *
392  * @dev:        Device to update
393  * @return 0 if OK, -ENOSYS if not supported
394  */
395 static int console_truetype_backspace(struct udevice *dev)
396 {
397         struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev);
398         struct console_tt_priv *priv = dev_get_priv(dev);
399         struct udevice *vid_dev = dev->parent;
400         struct video_priv *vid_priv = dev_get_uclass_priv(vid_dev);
401         struct pos_info *pos;
402         int xend;
403
404         /*
405          * This indicates a very strange error higher in the stack. The caller
406          * has sent out n character and n + 1 backspaces.
407          */
408         if (!priv->pos_ptr)
409                 return -ENOSYS;
410
411         /* Pop the last cursor position off the stack */
412         pos = &priv->pos[--priv->pos_ptr];
413
414         /*
415          * Figure out the end position for clearing. Normlly it is the current
416          * cursor position, but if we are clearing a character on the previous
417          * line, we clear from the end of the line.
418          */
419         if (pos->ypos == vc_priv->ycur)
420                 xend = VID_TO_PIXEL(vc_priv->xcur_frac);
421         else
422                 xend = vid_priv->xsize;
423
424         console_truetype_erase(dev, VID_TO_PIXEL(pos->xpos_frac), pos->ypos,
425                                xend, pos->ypos + vc_priv->y_charsize,
426                                vid_priv->colour_bg);
427
428         /* Move the cursor back to where it was when we pushed this record */
429         vc_priv->xcur_frac = pos->xpos_frac;
430         vc_priv->ycur = pos->ypos;
431
432         return 0;
433 }
434
435 static int console_truetype_entry_start(struct udevice *dev)
436 {
437         struct console_tt_priv *priv = dev_get_priv(dev);
438
439         /* A new input line has start, so clear our history */
440         priv->pos_ptr = 0;
441
442         return 0;
443 }
444
445 /*
446  * Provides a list of fonts which can be obtained at run-time in U-Boot. These
447  * are compiled in by the Makefile.
448  *
449  * At present there is no mechanism to select a particular font - the first
450  * one found is the one that is used. But the build system and the code here
451  * supports multiple fonts, which may be useful for certain firmware screens.
452  */
453 struct font_info {
454         char *name;
455         u8 *begin;
456         u8 *end;
457 };
458
459 #define FONT_DECL(_name) \
460         extern u8 __ttf_ ## _name ## _begin[]; \
461         extern u8 __ttf_ ## _name ## _end[];
462
463 #define FONT_ENTRY(_name)               { \
464         .name = #_name, \
465         .begin = __ttf_ ## _name ## _begin, \
466         .end = __ttf_ ## _name ## _end, \
467         }
468
469 FONT_DECL(nimbus_sans_l_regular);
470 FONT_DECL(ankacoder_c75_r);
471 FONT_DECL(rufscript010);
472 FONT_DECL(cantoraone_regular);
473
474 static struct font_info font_table[] = {
475 #ifdef CONFIG_CONSOLE_TRUETYPE_NIMBUS
476         FONT_ENTRY(nimbus_sans_l_regular),
477 #endif
478 #ifdef CONFIG_CONSOLE_TRUETYPE_ANKACODER
479         FONT_ENTRY(ankacoder_c75_r),
480 #endif
481 #ifdef CONFIG_CONSOLE_TRUETYPE_RUFSCRIPT
482         FONT_ENTRY(rufscript010),
483 #endif
484 #ifdef CONFIG_CONSOLE_TRUETYPE_CANTORAONE
485         FONT_ENTRY(cantoraone_regular),
486 #endif
487         {} /* sentinel */
488 };
489
490 #define FONT_BEGIN(name)        __ttf_ ## name ## _begin
491 #define FONT_END(name)          __ttf_ ## name ## _end
492 #define FONT_IS_VALID(name)     (abs(FONT_END(name) - FONT_BEGIN) > 4)
493
494 /**
495  * console_truetype_find_font() - Find a suitable font
496  *
497  * This searched for the first available font.
498  *
499  * @return pointer to the font, or NULL if none is found
500  */
501 static u8 *console_truetype_find_font(void)
502 {
503         struct font_info *tab;
504
505         for (tab = font_table; tab->begin; tab++) {
506                 if (abs(tab->begin - tab->end) > 4) {
507                         debug("%s: Font '%s', at %p, size %lx\n", __func__,
508                               tab->name, tab->begin,
509                               (ulong)(tab->end - tab->begin));
510                         return tab->begin;
511                 }
512         }
513
514         return NULL;
515 }
516
517 static int console_truetype_probe(struct udevice *dev)
518 {
519         struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev);
520         struct console_tt_priv *priv = dev_get_priv(dev);
521         struct udevice *vid_dev = dev->parent;
522         struct video_priv *vid_priv = dev_get_uclass_priv(vid_dev);
523         stbtt_fontinfo *font = &priv->font;
524         int ascent;
525
526         debug("%s: start\n", __func__);
527         if (vid_priv->font_size)
528                 priv->font_size = vid_priv->font_size;
529         else
530                 priv->font_size = CONFIG_CONSOLE_TRUETYPE_SIZE;
531         priv->font_data = console_truetype_find_font();
532         if (!priv->font_data) {
533                 debug("%s: Could not find any fonts\n", __func__);
534                 return -EBFONT;
535         }
536
537         vc_priv->x_charsize = priv->font_size;
538         vc_priv->y_charsize = priv->font_size;
539         vc_priv->xstart_frac = VID_TO_POS(2);
540         vc_priv->cols = vid_priv->xsize / priv->font_size;
541         vc_priv->rows = vid_priv->ysize / priv->font_size;
542         vc_priv->tab_width_frac = VID_TO_POS(priv->font_size) * 8 / 2;
543
544         if (!stbtt_InitFont(font, priv->font_data, 0)) {
545                 debug("%s: Font init failed\n", __func__);
546                 return -EPERM;
547         }
548
549         /* Pre-calculate some things we will need regularly */
550         priv->scale = stbtt_ScaleForPixelHeight(font, priv->font_size);
551         stbtt_GetFontVMetrics(font, &ascent, 0, 0);
552         priv->baseline = (int)(ascent * priv->scale);
553         debug("%s: ready\n", __func__);
554
555         return 0;
556 }
557
558 struct vidconsole_ops console_truetype_ops = {
559         .putc_xy        = console_truetype_putc_xy,
560         .move_rows      = console_truetype_move_rows,
561         .set_row        = console_truetype_set_row,
562         .backspace      = console_truetype_backspace,
563         .entry_start    = console_truetype_entry_start,
564 };
565
566 U_BOOT_DRIVER(vidconsole_truetype) = {
567         .name   = "vidconsole_tt",
568         .id     = UCLASS_VIDEO_CONSOLE,
569         .ops    = &console_truetype_ops,
570         .probe  = console_truetype_probe,
571         .priv_auto_alloc_size   = sizeof(struct console_tt_priv),
572 };