1
2
3
4
5
6
7#include <common.h>
8#include <dm.h>
9#include <video.h>
10#include <video_console.h>
11
12
13static int tt_floor(double val)
14{
15 if (val < 0)
16 return (int)(val - 0.999);
17
18 return (int)val;
19}
20
21static int tt_ceil(double val)
22{
23 if (val < 0)
24 return (int)val;
25
26 return (int)(val + 0.999);
27}
28
29static double frac(double val)
30{
31 return val - tt_floor(val);
32}
33
34static double tt_fabs(double x)
35{
36 return x < 0 ? -x : x;
37}
38
39
40
41
42
43
44
45
46
47static 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
80
81
82
83
84struct pos_info {
85 int xpos_frac;
86 int ypos;
87};
88
89
90
91
92
93#define POS_HISTORY_SIZE (CONFIG_SYS_CBSIZE * 11 / 10)
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115struct 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
125static 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
169static 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
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
190static 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
209 stbtt_GetCodepointHMetrics(font, ch, &advance, &lsb);
210
211
212
213
214
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
223
224
225
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
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
243
244
245
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
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
263
264
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
305
306
307
308
309
310
311
312
313
314
315
316
317static 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
367
368
369
370
371
372
373
374static 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
385
386
387 if (!priv->pos_ptr)
388 return -ENOSYS;
389
390
391 pos = &priv->pos[--priv->pos_ptr];
392
393
394
395
396
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
408 vc_priv->xcur_frac = pos->xpos_frac;
409 vc_priv->ycur = pos->ypos;
410
411 return 0;
412}
413
414static int console_truetype_entry_start(struct udevice *dev)
415{
416 struct console_tt_priv *priv = dev_get_priv(dev);
417
418
419 priv->pos_ptr = 0;
420
421 return 0;
422}
423
424
425
426
427
428
429
430
431
432struct 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
448FONT_DECL(nimbus_sans_l_regular);
449FONT_DECL(ankacoder_c75_r);
450FONT_DECL(rufscript010);
451FONT_DECL(cantoraone_regular);
452
453static 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 {}
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
475
476
477
478
479
480static 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
496static 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
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
537struct 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
545U_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