1 /*
2  * Copyright (c) 2018 PHYTEC Messtechnik GmbH
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/kernel.h>
8 #include <string.h>
9 #include <zephyr/display/cfb.h>
10 #include <zephyr/sys/byteorder.h>
11 
12 #define LOG_LEVEL CONFIG_CFB_LOG_LEVEL
13 #include <zephyr/logging/log.h>
14 LOG_MODULE_REGISTER(cfb);
15 
16 STRUCT_SECTION_START_EXTERN(cfb_font);
17 STRUCT_SECTION_END_EXTERN(cfb_font);
18 
19 #define LSB_BIT_MASK(x) BIT_MASK(x)
20 #define MSB_BIT_MASK(x) (BIT_MASK(x) << (8 - x))
21 
byte_reverse(uint8_t b)22 static inline uint8_t byte_reverse(uint8_t b)
23 {
24 	b = (b & 0xf0) >> 4 | (b & 0x0f) << 4;
25 	b = (b & 0xcc) >> 2 | (b & 0x33) << 2;
26 	b = (b & 0xaa) >> 1 | (b & 0x55) << 1;
27 	return b;
28 }
29 
30 struct char_framebuffer {
31 	/** Pointer to a buffer in RAM */
32 	uint8_t *buf;
33 
34 	/** Size of the framebuffer */
35 	uint32_t size;
36 
37 	/** Pointer to the font entry array */
38 	const struct cfb_font *fonts;
39 
40 	/** Display pixel format */
41 	enum display_pixel_format pixel_format;
42 
43 	/** Display screen info */
44 	enum display_screen_info screen_info;
45 
46 	/** Resolution of a framebuffer in pixels in X direction */
47 	uint16_t x_res;
48 
49 	/** Resolution of a framebuffer in pixels in Y direction */
50 	uint16_t y_res;
51 
52 	/** Number of pixels per tile, typically 8 */
53 	uint8_t ppt;
54 
55 	/** Number of available fonts */
56 	uint8_t numof_fonts;
57 
58 	/** Current font index */
59 	uint8_t font_idx;
60 
61 	/** Font kerning */
62 	int8_t kerning;
63 
64 	/** Inverted */
65 	bool inverted;
66 };
67 
68 static struct char_framebuffer char_fb;
69 
get_glyph_ptr(const struct cfb_font * fptr,uint8_t c)70 static inline uint8_t *get_glyph_ptr(const struct cfb_font *fptr, uint8_t c)
71 {
72 	if (c < fptr->first_char || c > fptr->last_char) {
73 		return NULL;
74 	}
75 
76 	return (uint8_t *)fptr->data +
77 	       (c - fptr->first_char) *
78 	       (fptr->width * fptr->height / 8U);
79 }
80 
get_glyph_byte(uint8_t * glyph_ptr,const struct cfb_font * fptr,uint8_t x,uint8_t y,bool vtiled)81 static inline uint8_t get_glyph_byte(uint8_t *glyph_ptr, const struct cfb_font *fptr,
82 				     uint8_t x, uint8_t y, bool vtiled)
83 {
84 	if (fptr->caps & CFB_FONT_MONO_VPACKED) {
85 		if (vtiled) {
86 			return glyph_ptr[x * (fptr->height / 8U) + y];
87 		} else {
88 			return glyph_ptr[(x * fptr->height + y) / 8];
89 		}
90 	} else if (fptr->caps & CFB_FONT_MONO_HPACKED) {
91 		return glyph_ptr[y * (fptr->width) + x];
92 	}
93 
94 	LOG_WRN("Unknown font type");
95 	return 0;
96 }
97 
98 /*
99  * Draw the monochrome character in the monochrome tiled framebuffer,
100  * a byte is interpreted as 8 pixels ordered vertically among each other.
101  */
draw_char_vtmono(const struct char_framebuffer * fb,uint8_t c,uint16_t x,uint16_t y,bool draw_bg)102 static uint8_t draw_char_vtmono(const struct char_framebuffer *fb,
103 				uint8_t c, uint16_t x, uint16_t y,
104 				bool draw_bg)
105 {
106 	const struct cfb_font *fptr = &(fb->fonts[fb->font_idx]);
107 	const bool font_is_msbfirst = ((fptr->caps & CFB_FONT_MSB_FIRST) != 0);
108 	const bool need_reverse =
109 		(((fb->screen_info & SCREEN_INFO_MONO_MSB_FIRST) != 0) != font_is_msbfirst);
110 	uint8_t *glyph_ptr;
111 
112 	if (c < fptr->first_char || c > fptr->last_char) {
113 		c = ' ';
114 	}
115 
116 	glyph_ptr = get_glyph_ptr(fptr, c);
117 	if (!glyph_ptr) {
118 		return 0;
119 	}
120 
121 	for (size_t g_x = 0; g_x < fptr->width; g_x++) {
122 		const int16_t fb_x = x + g_x;
123 
124 		for (size_t g_y = 0; g_y < fptr->height;) {
125 			/*
126 			 * Process glyph rendering in the y direction
127 			 * by separating per 8-line boundaries.
128 			 */
129 
130 			const int16_t fb_y = y + g_y;
131 			const size_t fb_index = (fb_y / 8U) * fb->x_res + fb_x;
132 			const size_t offset = y % 8;
133 			const uint8_t bottom_lines = ((offset + fptr->height) % 8);
134 			uint8_t bg_mask;
135 			uint8_t byte;
136 			uint8_t next_byte;
137 
138 			if (fb_x < 0 || fb->x_res <= fb_x || fb_y < 0 || fb->y_res <= fb_y) {
139 				g_y++;
140 				continue;
141 			}
142 
143 			if (offset == 0 || g_y == 0) {
144 				/*
145 				 * The case of drawing the first line of the glyphs or
146 				 * starting to draw with a tile-aligned position case.
147 				 * In this case, no character is above it.
148 				 * So, we process assume that nothing is drawn above.
149 				 */
150 				byte = 0;
151 				next_byte = get_glyph_byte(glyph_ptr, fptr, g_x, g_y / 8, true);
152 			} else {
153 				byte = get_glyph_byte(glyph_ptr, fptr, g_x, g_y / 8, true);
154 				next_byte =
155 					get_glyph_byte(glyph_ptr, fptr, g_x, (g_y + 8) / 8, true);
156 			}
157 
158 			if (font_is_msbfirst) {
159 				/*
160 				 * Extract the necessary 8 bits from the combined 2 tiles of glyphs.
161 				 */
162 				byte = ((byte << 8) | next_byte) >> (offset);
163 
164 				if (g_y == 0) {
165 					/*
166 					 * Create a mask that does not draw offset white space.
167 					 */
168 					bg_mask = BIT_MASK(8 - offset);
169 				} else {
170 					/*
171 					 * The drawing of the second line onwards
172 					 * is aligned with the tile, so it draws all the bits.
173 					 */
174 					bg_mask = 0xFF;
175 				}
176 			} else {
177 				byte = ((next_byte << 8) | byte) >> (8 - offset);
178 				if (g_y == 0) {
179 					bg_mask = BIT_MASK(8 - offset) << offset;
180 				} else {
181 					bg_mask = 0xFF;
182 				}
183 			}
184 
185 			/*
186 			 * Clip the bottom margin to protect existing draw contents.
187 			 */
188 			if (((fptr->height - g_y) < 8) && (bottom_lines != 0)) {
189 				const uint8_t clip = font_is_msbfirst ? MSB_BIT_MASK(bottom_lines)
190 								      : LSB_BIT_MASK(bottom_lines);
191 
192 				bg_mask &= clip;
193 				byte &= clip;
194 			}
195 
196 			if (draw_bg) {
197 				if (need_reverse) {
198 					bg_mask = byte_reverse(bg_mask);
199 				}
200 				fb->buf[fb_index] &= ~bg_mask;
201 			}
202 
203 			if (need_reverse) {
204 				byte = byte_reverse(byte);
205 			}
206 			fb->buf[fb_index] |= byte;
207 
208 			if (g_y == 0) {
209 				g_y += (8 - offset);
210 			} else if ((fptr->height - g_y) >= 8) {
211 				g_y += 8;
212 			} else {
213 				g_y += bottom_lines;
214 			}
215 		}
216 	}
217 
218 	return fptr->width;
219 }
220 
221 /*
222  * Draw the monochrome character in the monochrome tiled framebuffer,
223  * a byte is interpreted as 8 pixels ordered horizontally among each other.
224  */
draw_char_htmono(const struct char_framebuffer * fb,uint8_t c,uint16_t x,uint16_t y,bool draw_bg)225 static uint8_t draw_char_htmono(const struct char_framebuffer *fb,
226 				uint8_t c, uint16_t x, uint16_t y,
227 				bool draw_bg)
228 {
229 	const struct cfb_font *fptr = &(fb->fonts[fb->font_idx]);
230 	const bool font_is_msbfirst = (fptr->caps & CFB_FONT_MSB_FIRST) != 0;
231 	const bool display_is_msbfirst = (fb->screen_info & SCREEN_INFO_MONO_MSB_FIRST) != 0;
232 	uint8_t *glyph_ptr;
233 
234 	if (c < fptr->first_char || c > fptr->last_char) {
235 		c = ' ';
236 	}
237 
238 	glyph_ptr = get_glyph_ptr(fptr, c);
239 	if (!glyph_ptr) {
240 		return 0;
241 	}
242 
243 	for (size_t g_y = 0; g_y < fptr->height; g_y++) {
244 		const int16_t fb_y = y + g_y;
245 
246 		for (size_t g_x = 0; g_x < fptr->width; g_x++) {
247 			const int16_t fb_x = x + g_x;
248 			const size_t fb_pixel_index = fb_y * fb->x_res + fb_x;
249 			const size_t fb_byte_index = fb_pixel_index / 8;
250 			uint8_t byte;
251 			uint8_t pixel_value;
252 
253 			if (fb_x < 0 || fb->x_res <= fb_x || fb_y < 0 || fb->y_res <= fb_y) {
254 				g_y++;
255 				continue;
256 			}
257 
258 			byte = get_glyph_byte(glyph_ptr, fptr, g_x, g_y, false);
259 			if (font_is_msbfirst) {
260 				byte = byte_reverse(byte);
261 			}
262 			pixel_value = byte & BIT(g_y % 8);
263 
264 			if (pixel_value) {
265 				if (display_is_msbfirst) {
266 					fb->buf[fb_byte_index] |= BIT(7 - (fb_x % 8));
267 				} else {
268 					fb->buf[fb_byte_index] |= BIT(fb_x % 8);
269 				}
270 			}
271 		}
272 	}
273 
274 	return fptr->width;
275 }
276 
draw_point(struct char_framebuffer * fb,int16_t x,int16_t y)277 static inline void draw_point(struct char_framebuffer *fb, int16_t x, int16_t y)
278 {
279 	const bool need_reverse = ((fb->screen_info & SCREEN_INFO_MONO_MSB_FIRST) != 0);
280 	size_t index;
281 	uint8_t m;
282 
283 	if ((fb->screen_info & SCREEN_INFO_MONO_VTILED) != 0) {
284 		index = (x + (y / 8) * fb->x_res);
285 		m = BIT(y % 8);
286 	} else {
287 		index = ((x / 8) + y * (fb->x_res / 8));
288 		m = BIT(x % 8);
289 	}
290 
291 	if (x < 0 || x >= fb->x_res) {
292 		return;
293 	}
294 
295 	if (y < 0 || y >= fb->y_res) {
296 		return;
297 	}
298 
299 	if (need_reverse) {
300 		m = byte_reverse(m);
301 	}
302 
303 	fb->buf[index] |= m;
304 }
305 
draw_line(struct char_framebuffer * fb,int16_t x0,int16_t y0,int16_t x1,int16_t y1)306 static void draw_line(struct char_framebuffer *fb, int16_t x0, int16_t y0, int16_t x1, int16_t y1)
307 {
308 	int16_t sx = (x0 < x1) ? 1 : -1;
309 	int16_t sy = (y0 < y1) ? 1 : -1;
310 	int16_t dx = (sx > 0) ? (x1 - x0) : (x0 - x1);
311 	int16_t dy = (sy > 0) ? (y0 - y1) : (y1 - y0);
312 	int16_t err = dx + dy;
313 	int16_t e2;
314 
315 	while (true) {
316 		draw_point(fb, x0, y0);
317 
318 		if (x0 == x1 && y0 == y1) {
319 			break;
320 		}
321 
322 		e2 = 2 * err;
323 
324 		if (e2 >= dy) {
325 			err += dy;
326 			x0 += sx;
327 		}
328 
329 		if (e2 <= dx) {
330 			err += dx;
331 			y0 += sy;
332 		}
333 	}
334 }
335 
draw_text(const struct device * dev,const char * const str,int16_t x,int16_t y,bool wrap)336 static int draw_text(const struct device *dev, const char *const str, int16_t x, int16_t y,
337 		     bool wrap)
338 {
339 	const struct char_framebuffer *fb = &char_fb;
340 	const struct cfb_font *fptr;
341 
342 	if (!fb->fonts || !fb->buf) {
343 		return -ENODEV;
344 	}
345 
346 	fptr = &(fb->fonts[fb->font_idx]);
347 
348 	if (fptr->height % 8) {
349 		LOG_ERR("Wrong font size");
350 		return -EINVAL;
351 	}
352 
353 	const size_t len = strlen(str);
354 
355 	for (size_t i = 0; i < len; i++) {
356 		if ((x + fptr->width > fb->x_res) && wrap) {
357 			x = 0U;
358 			y += fptr->height;
359 		}
360 		if (fb->screen_info & SCREEN_INFO_MONO_VTILED) {
361 			x += fb->kerning + draw_char_vtmono(fb, str[i], x, y, wrap);
362 		} else {
363 			x += fb->kerning + draw_char_htmono(fb, str[i], x, y, wrap);
364 		}
365 	}
366 	return 0;
367 }
368 
cfb_draw_point(const struct device * dev,const struct cfb_position * pos)369 int cfb_draw_point(const struct device *dev, const struct cfb_position *pos)
370 {
371 	struct char_framebuffer *fb = &char_fb;
372 
373 	draw_point(fb, pos->x, pos->y);
374 
375 	return 0;
376 }
377 
cfb_draw_line(const struct device * dev,const struct cfb_position * start,const struct cfb_position * end)378 int cfb_draw_line(const struct device *dev, const struct cfb_position *start,
379 		  const struct cfb_position *end)
380 {
381 	struct char_framebuffer *fb = &char_fb;
382 
383 	draw_line(fb, start->x, start->y, end->x, end->y);
384 
385 	return 0;
386 }
387 
cfb_draw_rect(const struct device * dev,const struct cfb_position * start,const struct cfb_position * end)388 int cfb_draw_rect(const struct device *dev, const struct cfb_position *start,
389 		  const struct cfb_position *end)
390 {
391 	struct char_framebuffer *fb = &char_fb;
392 
393 	draw_line(fb, start->x, start->y, end->x, start->y);
394 	draw_line(fb, end->x, start->y, end->x, end->y);
395 	draw_line(fb, end->x, end->y, start->x, end->y);
396 	draw_line(fb, start->x, end->y, start->x, start->y);
397 
398 	return 0;
399 }
400 
cfb_draw_circle(const struct device * dev,const struct cfb_position * center,uint16_t radius)401 int cfb_draw_circle(const struct device *dev, const struct cfb_position *center, uint16_t radius)
402 {
403 	struct char_framebuffer *fb = &char_fb;
404 	uint16_t x = 0;
405 	int16_t y = -radius;
406 	int16_t p = -radius;
407 
408 	/* Using the Midpoint Circle Algorithm */
409 	while (x < -y) {
410 		if (p > 0) {
411 			p += 2 * (x + ++y) + 1;
412 		} else {
413 			p += 2 * x + 1;
414 		}
415 
416 		draw_point(fb, center->x + x, center->y + y);
417 		draw_point(fb, center->x - x, center->y + y);
418 		draw_point(fb, center->x + x, center->y - y);
419 		draw_point(fb, center->x - x, center->y - y);
420 		draw_point(fb, center->x + y, center->y + x);
421 		draw_point(fb, center->x + y, center->y - x);
422 		draw_point(fb, center->x - y, center->y + x);
423 		draw_point(fb, center->x - y, center->y - x);
424 
425 		x++;
426 	}
427 
428 	return 0;
429 }
430 
cfb_draw_text(const struct device * dev,const char * const str,int16_t x,int16_t y)431 int cfb_draw_text(const struct device *dev, const char *const str, int16_t x, int16_t y)
432 {
433 	return draw_text(dev, str, x, y, false);
434 }
435 
cfb_print(const struct device * dev,const char * const str,uint16_t x,uint16_t y)436 int cfb_print(const struct device *dev, const char *const str, uint16_t x, uint16_t y)
437 {
438 	return draw_text(dev, str, x, y, true);
439 }
440 
cfb_invert_area(const struct device * dev,uint16_t x,uint16_t y,uint16_t width,uint16_t height)441 int cfb_invert_area(const struct device *dev, uint16_t x, uint16_t y,
442 		    uint16_t width, uint16_t height)
443 {
444 	const struct char_framebuffer *fb = &char_fb;
445 	const bool need_reverse = ((fb->screen_info & SCREEN_INFO_MONO_MSB_FIRST) != 0);
446 
447 	if (x >= fb->x_res || y >= fb->y_res) {
448 		LOG_ERR("Coordinates outside of framebuffer");
449 
450 		return -EINVAL;
451 	}
452 
453 	if ((fb->screen_info & SCREEN_INFO_MONO_VTILED)) {
454 		if (x > fb->x_res) {
455 			x = fb->x_res;
456 		}
457 
458 		if (y > fb->y_res) {
459 			y = fb->y_res;
460 		}
461 
462 		if (x + width > fb->x_res) {
463 			width = fb->x_res - x;
464 		}
465 
466 		if (y + height > fb->y_res) {
467 			height = fb->y_res - y;
468 		}
469 
470 		for (size_t i = x; i < x + width; i++) {
471 			for (size_t j = y; j < (y + height); j++) {
472 				/*
473 				 * Process inversion in the y direction
474 				 * by separating per 8-line boundaries.
475 				 */
476 
477 				const size_t index = ((j / 8) * fb->x_res) + i;
478 				const uint8_t remains = y + height - j;
479 
480 				/*
481 				 * Make mask to prevent overwriting the drawing contents that on
482 				 * between the start line or end line and the 8-line boundary.
483 				 */
484 				if ((j % 8) > 0) {
485 					uint8_t m = BIT_MASK((j % 8));
486 					uint8_t b = fb->buf[index];
487 
488 					/*
489 					 * Generate mask for remaining lines in case of
490 					 * drawing within 8 lines from the start line
491 					 */
492 					if (remains < 8) {
493 						m |= BIT_MASK((8 - (j % 8) + remains))
494 						     << ((j % 8) + remains);
495 					}
496 
497 					if (need_reverse) {
498 						m = byte_reverse(m);
499 					}
500 
501 					fb->buf[index] = (b ^ (~m));
502 					j += 7 - (j % 8);
503 				} else if (remains >= 8) {
504 					/* No mask required if no start or end line is included */
505 					fb->buf[index] = ~fb->buf[index];
506 					j += 7;
507 				} else {
508 					uint8_t m = BIT_MASK(8 - remains) << (remains);
509 					uint8_t b = fb->buf[index];
510 
511 					if (need_reverse) {
512 						m = byte_reverse(m);
513 					}
514 
515 					fb->buf[index] = (b ^ (~m));
516 					j += (remains - 1);
517 				}
518 			}
519 		}
520 
521 		return 0;
522 	}
523 
524 	LOG_ERR("Unsupported framebuffer configuration");
525 	return -EINVAL;
526 }
527 
cfb_invert(const struct char_framebuffer * fb)528 static int cfb_invert(const struct char_framebuffer *fb)
529 {
530 	for (size_t i = 0; i < fb->x_res * fb->y_res / 8U; i++) {
531 		fb->buf[i] = ~fb->buf[i];
532 	}
533 
534 	return 0;
535 }
536 
cfb_framebuffer_clear(const struct device * dev,bool clear_display)537 int cfb_framebuffer_clear(const struct device *dev, bool clear_display)
538 {
539 	const struct char_framebuffer *fb = &char_fb;
540 
541 	if (!fb->buf) {
542 		return -ENODEV;
543 	}
544 
545 	memset(fb->buf, 0, fb->size);
546 
547 	if (clear_display) {
548 		cfb_framebuffer_finalize(dev);
549 	}
550 
551 	return 0;
552 }
553 
cfb_framebuffer_invert(const struct device * dev)554 int cfb_framebuffer_invert(const struct device *dev)
555 {
556 	struct char_framebuffer *fb = &char_fb;
557 
558 	fb->inverted = !fb->inverted;
559 
560 	return 0;
561 }
562 
cfb_framebuffer_finalize(const struct device * dev)563 int cfb_framebuffer_finalize(const struct device *dev)
564 {
565 	const struct display_driver_api *api = dev->api;
566 	const struct char_framebuffer *fb = &char_fb;
567 	int err;
568 
569 	__ASSERT_NO_MSG(DEVICE_API_IS(display, dev));
570 
571 	if (!fb->buf) {
572 		return -ENODEV;
573 	}
574 
575 	struct display_buffer_descriptor desc = {
576 		.buf_size = fb->size,
577 		.width = fb->x_res,
578 		.height = fb->y_res,
579 		.pitch = fb->x_res,
580 	};
581 
582 	if ((fb->pixel_format == PIXEL_FORMAT_MONO10) == fb->inverted) {
583 		cfb_invert(fb);
584 		err = api->write(dev, 0, 0, &desc, fb->buf);
585 		cfb_invert(fb);
586 		return err;
587 	}
588 
589 	return api->write(dev, 0, 0, &desc, fb->buf);
590 }
591 
cfb_get_display_parameter(const struct device * dev,enum cfb_display_param param)592 int cfb_get_display_parameter(const struct device *dev,
593 			       enum cfb_display_param param)
594 {
595 	const struct char_framebuffer *fb = &char_fb;
596 
597 	switch (param) {
598 	case CFB_DISPLAY_HEIGHT:
599 		return fb->y_res;
600 	case CFB_DISPLAY_WIDTH:
601 		return fb->x_res;
602 	case CFB_DISPLAY_PPT:
603 		return fb->ppt;
604 	case CFB_DISPLAY_ROWS:
605 		if (fb->screen_info & SCREEN_INFO_MONO_VTILED) {
606 			return fb->y_res / fb->ppt;
607 		}
608 		return fb->y_res;
609 	case CFB_DISPLAY_COLS:
610 		if (fb->screen_info & SCREEN_INFO_MONO_VTILED) {
611 			return fb->x_res;
612 		}
613 		return fb->x_res / fb->ppt;
614 	}
615 	return 0;
616 }
617 
cfb_framebuffer_set_font(const struct device * dev,uint8_t idx)618 int cfb_framebuffer_set_font(const struct device *dev, uint8_t idx)
619 {
620 	struct char_framebuffer *fb = &char_fb;
621 
622 	if (idx >= fb->numof_fonts) {
623 		return -EINVAL;
624 	}
625 
626 	fb->font_idx = idx;
627 
628 	return 0;
629 }
630 
cfb_get_font_size(const struct device * dev,uint8_t idx,uint8_t * width,uint8_t * height)631 int cfb_get_font_size(const struct device *dev, uint8_t idx, uint8_t *width,
632 		      uint8_t *height)
633 {
634 	const struct char_framebuffer *fb = &char_fb;
635 
636 	if (idx >= fb->numof_fonts) {
637 		return -EINVAL;
638 	}
639 
640 	if (width) {
641 		*width = TYPE_SECTION_START(cfb_font)[idx].width;
642 	}
643 
644 	if (height) {
645 		*height = TYPE_SECTION_START(cfb_font)[idx].height;
646 	}
647 
648 	return 0;
649 }
650 
cfb_set_kerning(const struct device * dev,int8_t kerning)651 int cfb_set_kerning(const struct device *dev, int8_t kerning)
652 {
653 	char_fb.kerning = kerning;
654 
655 	return 0;
656 }
657 
cfb_get_numof_fonts(const struct device * dev)658 int cfb_get_numof_fonts(const struct device *dev)
659 {
660 	const struct char_framebuffer *fb = &char_fb;
661 
662 	return fb->numof_fonts;
663 }
664 
cfb_framebuffer_init(const struct device * dev)665 int cfb_framebuffer_init(const struct device *dev)
666 {
667 	const struct display_driver_api *api = dev->api;
668 	struct char_framebuffer *fb = &char_fb;
669 	struct display_capabilities cfg;
670 
671 	__ASSERT_NO_MSG(DEVICE_API_IS(display, dev));
672 
673 	api->get_capabilities(dev, &cfg);
674 
675 	STRUCT_SECTION_COUNT(cfb_font, &fb->numof_fonts);
676 
677 	LOG_DBG("number of fonts %d", fb->numof_fonts);
678 
679 	fb->x_res = cfg.x_resolution;
680 	fb->y_res = cfg.y_resolution;
681 	fb->ppt = 8U;
682 	fb->pixel_format = cfg.current_pixel_format;
683 	fb->screen_info = cfg.screen_info;
684 	fb->kerning = 0;
685 	fb->inverted = false;
686 
687 	fb->fonts = TYPE_SECTION_START(cfb_font);
688 	fb->font_idx = 0U;
689 
690 	fb->size = fb->x_res * fb->y_res / fb->ppt;
691 	fb->buf = k_malloc(fb->size);
692 	if (!fb->buf) {
693 		return -ENOMEM;
694 	}
695 
696 	memset(fb->buf, 0, fb->size);
697 
698 	return 0;
699 }
700 
cfb_framebuffer_deinit(const struct device * dev)701 void cfb_framebuffer_deinit(const struct device *dev)
702 {
703 	struct char_framebuffer *fb = &char_fb;
704 
705 	if (fb->buf) {
706 		k_free(fb->buf);
707 		fb->buf = NULL;
708 	}
709 
710 }
711