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