1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2015 Google, Inc
4  * (C) Copyright 2015
5  * Bernecker & Rainer Industrieelektronik GmbH - http://www.br-automation.com
6  * (C) Copyright 2023 Dzmitry Sankouski <dsankouski@gmail.com>
7  */
8 
9 #include <video.h>
10 #include <video_console.h>
11 #include <dm.h>
12 #include <video_font.h>
13 #include "vidconsole_internal.h"
14 
15 /**
16  * console_set_font() - prepare vidconsole for chosen font.
17  *
18  * @dev		vidconsole device
19  * @fontdata	pointer to font data struct
20  */
console_set_font(struct udevice * dev,struct video_fontdata * fontdata)21 static int console_set_font(struct udevice *dev, struct video_fontdata *fontdata)
22 {
23 	struct console_simple_priv *priv = dev_get_priv(dev);
24 	struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev);
25 	struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
26 
27 	debug("console_simple: setting %s font\n", fontdata->name);
28 	debug("width: %d\n", fontdata->width);
29 	debug("byte width: %d\n", fontdata->byte_width);
30 	debug("height: %d\n", fontdata->height);
31 
32 	priv->fontdata = fontdata;
33 	vc_priv->x_charsize = fontdata->width;
34 	vc_priv->y_charsize = fontdata->height;
35 	if (vid_priv->rot % 2) {
36 		vc_priv->cols = vid_priv->ysize / fontdata->width;
37 		vc_priv->rows = vid_priv->xsize / fontdata->height;
38 		vc_priv->xsize_frac = VID_TO_POS(vid_priv->ysize);
39 	} else {
40 		vc_priv->cols = vid_priv->xsize / fontdata->width;
41 		vc_priv->rows = vid_priv->ysize / fontdata->height;
42 	}
43 
44 	return 0;
45 }
46 
check_bpix_support(int bpix)47 int check_bpix_support(int bpix)
48 {
49 	if (bpix == VIDEO_BPP8 && CONFIG_IS_ENABLED(VIDEO_BPP8))
50 		return 0;
51 	else if (bpix == VIDEO_BPP16 && CONFIG_IS_ENABLED(VIDEO_BPP16))
52 		return 0;
53 	else if (bpix == VIDEO_BPP32 && CONFIG_IS_ENABLED(VIDEO_BPP32))
54 		return 0;
55 	else
56 		return -ENOSYS;
57 }
58 
fill_pixel_and_goto_next(void ** dstp,u32 value,int pbytes,int step)59 inline void fill_pixel_and_goto_next(void **dstp, u32 value, int pbytes, int step)
60 {
61 	u8 *dst_byte = *dstp;
62 
63 	if (pbytes == 4) {
64 		u32 *dst = *dstp;
65 		*dst = value;
66 	}
67 	if (pbytes == 2) {
68 		u16 *dst = *dstp;
69 		*dst = value;
70 	}
71 	if (pbytes == 1) {
72 		u8 *dst = *dstp;
73 		*dst = value;
74 	}
75 	*dstp = dst_byte + step;
76 }
77 
fill_char_vertically(uchar * pfont,void ** line,struct video_priv * vid_priv,struct video_fontdata * fontdata,bool direction)78 int fill_char_vertically(uchar *pfont, void **line, struct video_priv *vid_priv,
79 			 struct video_fontdata *fontdata, bool direction)
80 {
81 	int step, line_step, pbytes, bitcount, width_remainder, ret;
82 	void *dst;
83 
84 	ret = check_bpix_support(vid_priv->bpix);
85 	if (ret)
86 		return ret;
87 
88 	pbytes = VNBYTES(vid_priv->bpix);
89 	if (direction) {
90 		step = -pbytes;
91 		line_step = -vid_priv->line_length;
92 	} else {
93 		step = pbytes;
94 		line_step = vid_priv->line_length;
95 	}
96 
97 	width_remainder = fontdata->width % 8;
98 	for (int row = 0; row < fontdata->height; row++) {
99 		uchar bits;
100 
101 		bitcount = 8;
102 		dst = *line;
103 		for (int col = 0; col < fontdata->byte_width; col++) {
104 			if (width_remainder) {
105 				bool is_last_col = (fontdata->byte_width - col == 1);
106 
107 				if (is_last_col)
108 					bitcount = width_remainder;
109 			}
110 			bits = pfont[col];
111 
112 			for (int bit = 0; bit < bitcount; bit++) {
113 				u32 value = (bits & 0x80) ?
114 					vid_priv->colour_fg :
115 					vid_priv->colour_bg;
116 
117 				fill_pixel_and_goto_next(&dst,
118 							 value,
119 							 pbytes,
120 							 step
121 				);
122 				bits <<= 1;
123 			}
124 		}
125 		*line += line_step;
126 		pfont += fontdata->byte_width;
127 	}
128 	return ret;
129 }
130 
fill_char_horizontally(uchar * pfont,void ** line,struct video_priv * vid_priv,struct video_fontdata * fontdata,bool direction)131 int fill_char_horizontally(uchar *pfont, void **line, struct video_priv *vid_priv,
132 			   struct video_fontdata *fontdata, bool direction)
133 {
134 	int step, line_step, pbytes, bitcount = 8, width_remainder, ret;
135 	void *dst;
136 	u8 mask;
137 
138 	ret = check_bpix_support(vid_priv->bpix);
139 	if (ret)
140 		return ret;
141 
142 	pbytes = VNBYTES(vid_priv->bpix);
143 	if (direction) {
144 		step = -pbytes;
145 		line_step = vid_priv->line_length;
146 	} else {
147 		step = pbytes;
148 		line_step = -vid_priv->line_length;
149 	}
150 
151 	width_remainder = fontdata->width % 8;
152 	for (int col = 0; col < fontdata->byte_width; col++) {
153 		mask = 0x80;
154 		if (width_remainder) {
155 			bool is_last_col = (fontdata->byte_width - col == 1);
156 
157 			if (is_last_col)
158 				bitcount = width_remainder;
159 		}
160 		for (int bit = 0; bit < bitcount; bit++) {
161 			dst = *line;
162 			for (int row = 0; row < fontdata->height; row++) {
163 				u32 value = (pfont[row * fontdata->byte_width + col]
164 					     & mask) ? vid_priv->colour_fg : vid_priv->colour_bg;
165 
166 				fill_pixel_and_goto_next(&dst,
167 							 value,
168 							 pbytes,
169 							 step
170 				);
171 			}
172 			*line += line_step;
173 			mask >>= 1;
174 		}
175 	}
176 	return ret;
177 }
178 
console_probe(struct udevice * dev)179 int console_probe(struct udevice *dev)
180 {
181 	return console_set_font(dev, fonts);
182 }
183 
console_simple_get_font_size(struct udevice * dev,uint * sizep)184 const char *console_simple_get_font_size(struct udevice *dev, uint *sizep)
185 {
186 	struct console_simple_priv *priv = dev_get_priv(dev);
187 
188 	*sizep = priv->fontdata->width;
189 
190 	return priv->fontdata->name;
191 }
192 
console_simple_get_font(struct udevice * dev,int seq,struct vidfont_info * info)193 int console_simple_get_font(struct udevice *dev, int seq, struct vidfont_info *info)
194 {
195 	info->name = fonts[seq].name;
196 
197 	return 0;
198 }
199 
console_simple_select_font(struct udevice * dev,const char * name,uint size)200 int console_simple_select_font(struct udevice *dev, const char *name, uint size)
201 {
202 	struct video_fontdata *font;
203 
204 	for (font = fonts; font->name; font++) {
205 		if (!strcmp(name, font->name)) {
206 			console_set_font(dev, font);
207 			return 0;
208 		}
209 	};
210 	printf("no such font: %s, make sure it's name has <width>x<height> format\n", name);
211 	return -ENOENT;
212 }
213