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