1
2
3
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
14static int tt_floor(double val)
15{
16 if (val < 0)
17 return (int)(val - 0.999);
18
19 return (int)val;
20}
21
22static int tt_ceil(double val)
23{
24 if (val < 0)
25 return (int)val;
26
27 return (int)(val + 0.999);
28}
29
30static double frac(double val)
31{
32 return val - tt_floor(val);
33}
34
35static double tt_fabs(double x)
36{
37 return x < 0 ? -x : x;
38}
39
40
41
42
43
44
45
46
47
48static 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
81
82
83
84
85struct pos_info {
86 int xpos_frac;
87 int ypos;
88};
89
90
91
92
93
94#define POS_HISTORY_SIZE (CONFIG_SYS_CBSIZE * 11 / 10)
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116struct 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
126static 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 ret;
132
133 line = vid_priv->fb + row * priv->font_size * vid_priv->line_length;
134 end = line + priv->font_size * vid_priv->line_length;
135
136 switch (vid_priv->bpix) {
137#ifdef CONFIG_VIDEO_BPP8
138 case VIDEO_BPP8: {
139 u8 *dst;
140
141 for (dst = line; dst < (u8 *)end; ++dst)
142 *dst = clr;
143 break;
144 }
145#endif
146#ifdef CONFIG_VIDEO_BPP16
147 case VIDEO_BPP16: {
148 u16 *dst = line;
149
150 for (dst = line; dst < (u16 *)end; ++dst)
151 *dst = clr;
152 break;
153 }
154#endif
155#ifdef CONFIG_VIDEO_BPP32
156 case VIDEO_BPP32: {
157 u32 *dst = line;
158
159 for (dst = line; dst < (u32 *)end; ++dst)
160 *dst = clr;
161 break;
162 }
163#endif
164 default:
165 return -ENOSYS;
166 }
167 ret = vidconsole_sync_copy(dev, line, end);
168 if (ret)
169 return ret;
170
171 return 0;
172}
173
174static int console_truetype_move_rows(struct udevice *dev, uint rowdst,
175 uint rowsrc, uint count)
176{
177 struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
178 struct console_tt_priv *priv = dev_get_priv(dev);
179 void *dst;
180 void *src;
181 int i, diff, ret;
182
183 dst = vid_priv->fb + rowdst * priv->font_size * vid_priv->line_length;
184 src = vid_priv->fb + rowsrc * priv->font_size * vid_priv->line_length;
185 ret = vidconsole_memmove(dev, dst, src, priv->font_size *
186 vid_priv->line_length * count);
187 if (ret)
188 return ret;
189
190
191 diff = (rowsrc - rowdst) * priv->font_size;
192 for (i = 0; i < priv->pos_ptr; i++)
193 priv->pos[i].ypos -= diff;
194
195 return 0;
196}
197
198static int console_truetype_putc_xy(struct udevice *dev, uint x, uint y,
199 char ch)
200{
201 struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev);
202 struct udevice *vid = dev->parent;
203 struct video_priv *vid_priv = dev_get_uclass_priv(vid);
204 struct console_tt_priv *priv = dev_get_priv(dev);
205 stbtt_fontinfo *font = &priv->font;
206 int width, height, xoff, yoff;
207 double xpos, x_shift;
208 int lsb;
209 int width_frac, linenum;
210 struct pos_info *pos;
211 u8 *bits, *data;
212 int advance;
213 void *start, *end, *line;
214 int row, ret;
215
216
217 stbtt_GetCodepointHMetrics(font, ch, &advance, &lsb);
218
219
220
221
222
223 xpos = frac(VID_TO_PIXEL((double)x));
224 if (vc_priv->last_ch) {
225 xpos += priv->scale * stbtt_GetCodepointKernAdvance(font,
226 vc_priv->last_ch, ch);
227 }
228
229
230
231
232
233
234
235 x_shift = xpos - (double)tt_floor(xpos);
236 xpos += advance * priv->scale;
237 width_frac = (int)VID_TO_POS(xpos);
238 if (x + width_frac >= vc_priv->xsize_frac)
239 return -EAGAIN;
240
241
242 if (priv->pos_ptr < POS_HISTORY_SIZE) {
243 pos = &priv->pos[priv->pos_ptr];
244 pos->xpos_frac = vc_priv->xcur_frac;
245 pos->ypos = vc_priv->ycur;
246 priv->pos_ptr++;
247 }
248
249
250
251
252
253
254
255 data = stbtt_GetCodepointBitmapSubpixel(font, priv->scale, priv->scale,
256 x_shift, 0, ch, &width, &height,
257 &xoff, &yoff);
258 if (!data)
259 return width_frac;
260
261
262 bits = data;
263 start = vid_priv->fb + y * vid_priv->line_length +
264 VID_TO_PIXEL(x) * VNBYTES(vid_priv->bpix);
265 linenum = priv->baseline + yoff;
266 if (linenum > 0)
267 start += linenum * vid_priv->line_length;
268 line = start;
269
270
271
272
273
274
275 for (row = 0; row < height; row++) {
276 switch (vid_priv->bpix) {
277#ifdef CONFIG_VIDEO_BPP16
278 case VIDEO_BPP16: {
279 uint16_t *dst = (uint16_t *)line + xoff;
280 int i;
281
282 for (i = 0; i < width; i++) {
283 int val = *bits;
284 int out;
285
286 if (vid_priv->colour_bg)
287 val = 255 - val;
288 out = val >> 3 |
289 (val >> 2) << 5 |
290 (val >> 3) << 11;
291 if (vid_priv->colour_fg)
292 *dst++ |= out;
293 else
294 *dst++ &= out;
295 bits++;
296 }
297 end = dst;
298 break;
299 }
300#endif
301#ifdef CONFIG_VIDEO_BPP32
302 case VIDEO_BPP32: {
303 u32 *dst = (u32 *)line + xoff;
304 int i;
305
306 for (i = 0; i < width; i++) {
307 int val = *bits;
308 int out;
309
310 if (vid_priv->colour_bg)
311 val = 255 - val;
312 out = val | val << 8 | val << 16;
313 if (vid_priv->colour_fg)
314 *dst++ |= out;
315 else
316 *dst++ &= out;
317 bits++;
318 }
319 end = dst;
320 break;
321 }
322#endif
323 default:
324 free(data);
325 return -ENOSYS;
326 }
327
328 line += vid_priv->line_length;
329 }
330 ret = vidconsole_sync_copy(dev, start, line);
331 if (ret)
332 return ret;
333 free(data);
334
335 return width_frac;
336}
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352static int console_truetype_erase(struct udevice *dev, int xstart, int ystart,
353 int xend, int yend, int clr)
354{
355 struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
356 void *start, *line;
357 int pixels = xend - xstart;
358 int row, i, ret;
359
360 start = vid_priv->fb + ystart * vid_priv->line_length;
361 start += xstart * VNBYTES(vid_priv->bpix);
362 line = start;
363 for (row = ystart; row < yend; row++) {
364 switch (vid_priv->bpix) {
365#ifdef CONFIG_VIDEO_BPP8
366 case VIDEO_BPP8: {
367 uint8_t *dst = line;
368
369 for (i = 0; i < pixels; i++)
370 *dst++ = clr;
371 break;
372 }
373#endif
374#ifdef CONFIG_VIDEO_BPP16
375 case VIDEO_BPP16: {
376 uint16_t *dst = line;
377
378 for (i = 0; i < pixels; i++)
379 *dst++ = clr;
380 break;
381 }
382#endif
383#ifdef CONFIG_VIDEO_BPP32
384 case VIDEO_BPP32: {
385 uint32_t *dst = line;
386
387 for (i = 0; i < pixels; i++)
388 *dst++ = clr;
389 break;
390 }
391#endif
392 default:
393 return -ENOSYS;
394 }
395 line += vid_priv->line_length;
396 }
397 ret = vidconsole_sync_copy(dev, start, line);
398 if (ret)
399 return ret;
400
401 return 0;
402}
403
404
405
406
407
408
409
410
411
412
413static int console_truetype_backspace(struct udevice *dev)
414{
415 struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev);
416 struct console_tt_priv *priv = dev_get_priv(dev);
417 struct udevice *vid_dev = dev->parent;
418 struct video_priv *vid_priv = dev_get_uclass_priv(vid_dev);
419 struct pos_info *pos;
420 int xend;
421
422
423
424
425
426 if (!priv->pos_ptr)
427 return -ENOSYS;
428
429
430 pos = &priv->pos[--priv->pos_ptr];
431
432
433
434
435
436
437 if (pos->ypos == vc_priv->ycur)
438 xend = VID_TO_PIXEL(vc_priv->xcur_frac);
439 else
440 xend = vid_priv->xsize;
441
442 console_truetype_erase(dev, VID_TO_PIXEL(pos->xpos_frac), pos->ypos,
443 xend, pos->ypos + vc_priv->y_charsize,
444 vid_priv->colour_bg);
445
446
447 vc_priv->xcur_frac = pos->xpos_frac;
448 vc_priv->ycur = pos->ypos;
449
450 return 0;
451}
452
453static int console_truetype_entry_start(struct udevice *dev)
454{
455 struct console_tt_priv *priv = dev_get_priv(dev);
456
457
458 priv->pos_ptr = 0;
459
460 return 0;
461}
462
463
464
465
466
467
468
469
470
471struct font_info {
472 char *name;
473 u8 *begin;
474 u8 *end;
475};
476
477#define FONT_DECL(_name) \
478 extern u8 __ttf_ ## _name ## _begin[]; \
479 extern u8 __ttf_ ## _name ## _end[];
480
481#define FONT_ENTRY(_name) { \
482 .name = #_name, \
483 .begin = __ttf_ ## _name ## _begin, \
484 .end = __ttf_ ## _name ## _end, \
485 }
486
487FONT_DECL(nimbus_sans_l_regular);
488FONT_DECL(ankacoder_c75_r);
489FONT_DECL(rufscript010);
490FONT_DECL(cantoraone_regular);
491
492static struct font_info font_table[] = {
493#ifdef CONFIG_CONSOLE_TRUETYPE_NIMBUS
494 FONT_ENTRY(nimbus_sans_l_regular),
495#endif
496#ifdef CONFIG_CONSOLE_TRUETYPE_ANKACODER
497 FONT_ENTRY(ankacoder_c75_r),
498#endif
499#ifdef CONFIG_CONSOLE_TRUETYPE_RUFSCRIPT
500 FONT_ENTRY(rufscript010),
501#endif
502#ifdef CONFIG_CONSOLE_TRUETYPE_CANTORAONE
503 FONT_ENTRY(cantoraone_regular),
504#endif
505 {}
506};
507
508#define FONT_BEGIN(name) __ttf_ ## name ## _begin
509#define FONT_END(name) __ttf_ ## name ## _end
510#define FONT_IS_VALID(name) (abs(FONT_END(name) - FONT_BEGIN) > 4)
511
512
513
514
515
516
517
518
519static u8 *console_truetype_find_font(void)
520{
521 struct font_info *tab;
522
523 for (tab = font_table; tab->begin; tab++) {
524 if (abs(tab->begin - tab->end) > 4) {
525 debug("%s: Font '%s', at %p, size %lx\n", __func__,
526 tab->name, tab->begin,
527 (ulong)(tab->end - tab->begin));
528 return tab->begin;
529 }
530 }
531
532 return NULL;
533}
534
535static int console_truetype_probe(struct udevice *dev)
536{
537 struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev);
538 struct console_tt_priv *priv = dev_get_priv(dev);
539 struct udevice *vid_dev = dev->parent;
540 struct video_priv *vid_priv = dev_get_uclass_priv(vid_dev);
541 stbtt_fontinfo *font = &priv->font;
542 int ascent;
543
544 debug("%s: start\n", __func__);
545 if (vid_priv->font_size)
546 priv->font_size = vid_priv->font_size;
547 else
548 priv->font_size = CONFIG_CONSOLE_TRUETYPE_SIZE;
549 priv->font_data = console_truetype_find_font();
550 if (!priv->font_data) {
551 debug("%s: Could not find any fonts\n", __func__);
552 return -EBFONT;
553 }
554
555 vc_priv->x_charsize = priv->font_size;
556 vc_priv->y_charsize = priv->font_size;
557 vc_priv->xstart_frac = VID_TO_POS(2);
558 vc_priv->cols = vid_priv->xsize / priv->font_size;
559 vc_priv->rows = vid_priv->ysize / priv->font_size;
560 vc_priv->tab_width_frac = VID_TO_POS(priv->font_size) * 8 / 2;
561
562 if (!stbtt_InitFont(font, priv->font_data, 0)) {
563 debug("%s: Font init failed\n", __func__);
564 return -EPERM;
565 }
566
567
568 priv->scale = stbtt_ScaleForPixelHeight(font, priv->font_size);
569 stbtt_GetFontVMetrics(font, &ascent, 0, 0);
570 priv->baseline = (int)(ascent * priv->scale);
571 debug("%s: ready\n", __func__);
572
573 return 0;
574}
575
576struct vidconsole_ops console_truetype_ops = {
577 .putc_xy = console_truetype_putc_xy,
578 .move_rows = console_truetype_move_rows,
579 .set_row = console_truetype_set_row,
580 .backspace = console_truetype_backspace,
581 .entry_start = console_truetype_entry_start,
582};
583
584U_BOOT_DRIVER(vidconsole_truetype) = {
585 .name = "vidconsole_tt",
586 .id = UCLASS_VIDEO_CONSOLE,
587 .ops = &console_truetype_ops,
588 .probe = console_truetype_probe,
589 .priv_auto = sizeof(struct console_tt_priv),
590};
591