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 
draw_cursor_vertically(void ** line,struct video_priv * vid_priv,uint height,bool direction)179 int draw_cursor_vertically(void **line, struct video_priv *vid_priv,
180 			   uint height, bool direction)
181 {
182 	int step, line_step, pbytes, ret;
183 	uint value;
184 	void *dst;
185 
186 	ret = check_bpix_support(vid_priv->bpix);
187 	if (ret)
188 		return ret;
189 
190 	pbytes = VNBYTES(vid_priv->bpix);
191 	if (direction) {
192 		step = -pbytes;
193 		line_step = -vid_priv->line_length;
194 	} else {
195 		step = pbytes;
196 		line_step = vid_priv->line_length;
197 	}
198 
199 	value = vid_priv->colour_fg;
200 
201 	for (int row = 0; row < height; row++) {
202 		dst = *line;
203 		for (int col = 0; col < VIDCONSOLE_CURSOR_WIDTH; col++)
204 			fill_pixel_and_goto_next(&dst, value, pbytes, step);
205 		*line += line_step;
206 	}
207 	return ret;
208 }
209 
console_probe(struct udevice * dev)210 int console_probe(struct udevice *dev)
211 {
212 	return console_set_font(dev, fonts);
213 }
214 
console_simple_get_font_size(struct udevice * dev,uint * sizep)215 const char *console_simple_get_font_size(struct udevice *dev, uint *sizep)
216 {
217 	struct console_simple_priv *priv = dev_get_priv(dev);
218 
219 	*sizep = priv->fontdata->width;
220 
221 	return priv->fontdata->name;
222 }
223 
console_simple_get_font(struct udevice * dev,int seq,struct vidfont_info * info)224 int console_simple_get_font(struct udevice *dev, int seq, struct vidfont_info *info)
225 {
226 	info->name = fonts[seq].name;
227 
228 	return info->name ? 0 : -ENOENT;
229 }
230 
console_simple_select_font(struct udevice * dev,const char * name,uint size)231 int console_simple_select_font(struct udevice *dev, const char *name, uint size)
232 {
233 	struct video_fontdata *font;
234 
235 	if (!name) {
236 		if (fonts->name)
237 			console_set_font(dev, fonts);
238 		return 0;
239 	}
240 
241 	for (font = fonts; font->name; font++) {
242 		if (!strcmp(name, font->name)) {
243 			console_set_font(dev, font);
244 			return 0;
245 		}
246 	};
247 	printf("no such font: %s, make sure it's name has <width>x<height> format\n", name);
248 	return -ENOENT;
249 }
250