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