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  */
7 
8 #include <common.h>
9 #include <dm.h>
10 #include <video.h>
11 #include <video_console.h>
12 #include <video_font.h>		/* Get font data, width and height */
13 
14 static int console_set_row_1(struct udevice *dev, uint row, int clr)
15 {
16 	struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
17 	int pbytes = VNBYTES(vid_priv->bpix);
18 	void *line;
19 	int i, j;
20 
21 	line = vid_priv->fb + vid_priv->line_length -
22 		(row + 1) * VIDEO_FONT_HEIGHT * pbytes;
23 	for (j = 0; j < vid_priv->ysize; j++) {
24 		switch (vid_priv->bpix) {
25 #ifdef CONFIG_VIDEO_BPP8
26 		case VIDEO_BPP8: {
27 			uint8_t *dst = line;
28 
29 			for (i = 0; i < VIDEO_FONT_HEIGHT; i++)
30 				*dst++ = clr;
31 			break;
32 		}
33 #endif
34 #ifdef CONFIG_VIDEO_BPP16
35 		case VIDEO_BPP16: {
36 			uint16_t *dst = line;
37 
38 			for (i = 0; i < VIDEO_FONT_HEIGHT; i++)
39 				*dst++ = clr;
40 			break;
41 		}
42 #endif
43 #ifdef CONFIG_VIDEO_BPP32
44 		case VIDEO_BPP32: {
45 			uint32_t *dst = line;
46 
47 			for (i = 0; i < VIDEO_FONT_HEIGHT; i++)
48 				*dst++ = clr;
49 			break;
50 		}
51 #endif
52 		default:
53 			return -ENOSYS;
54 		}
55 		line += vid_priv->line_length;
56 	}
57 
58 	return 0;
59 }
60 
61 static int console_move_rows_1(struct udevice *dev, uint rowdst, uint rowsrc,
62 			       uint count)
63 {
64 	struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
65 	void *dst;
66 	void *src;
67 	int pbytes = VNBYTES(vid_priv->bpix);
68 	int j;
69 
70 	dst = vid_priv->fb + vid_priv->line_length -
71 		(rowdst + count) * VIDEO_FONT_HEIGHT * pbytes;
72 	src = vid_priv->fb + vid_priv->line_length -
73 		(rowsrc + count) * VIDEO_FONT_HEIGHT * pbytes;
74 
75 	for (j = 0; j < vid_priv->ysize; j++) {
76 		memmove(dst, src, VIDEO_FONT_HEIGHT * pbytes * count);
77 		src += vid_priv->line_length;
78 		dst += vid_priv->line_length;
79 	}
80 
81 	return 0;
82 }
83 
84 static int console_putc_xy_1(struct udevice *dev, uint x_frac, uint y, char ch)
85 {
86 	struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev);
87 	struct udevice *vid = dev->parent;
88 	struct video_priv *vid_priv = dev_get_uclass_priv(vid);
89 	int pbytes = VNBYTES(vid_priv->bpix);
90 	int i, col;
91 	int mask = 0x80;
92 	void *line;
93 	uchar *pfont = video_fontdata + ch * VIDEO_FONT_HEIGHT;
94 
95 	line = vid_priv->fb + (VID_TO_PIXEL(x_frac) + 1) *
96 			vid_priv->line_length - (y + 1) * pbytes;
97 	if (x_frac + VID_TO_POS(vc_priv->x_charsize) > vc_priv->xsize_frac)
98 		return -EAGAIN;
99 
100 	for (col = 0; col < VIDEO_FONT_HEIGHT; col++) {
101 		switch (vid_priv->bpix) {
102 #ifdef CONFIG_VIDEO_BPP8
103 		case VIDEO_BPP8: {
104 			uint8_t *dst = line;
105 
106 			for (i = 0; i < VIDEO_FONT_HEIGHT; i++) {
107 				*dst-- = (pfont[i] & mask) ? vid_priv->colour_fg
108 					: vid_priv->colour_bg;
109 			}
110 			break;
111 		}
112 #endif
113 #ifdef CONFIG_VIDEO_BPP16
114 		case VIDEO_BPP16: {
115 			uint16_t *dst = line;
116 
117 			for (i = 0; i < VIDEO_FONT_HEIGHT; i++) {
118 				*dst-- = (pfont[i] & mask) ? vid_priv->colour_fg
119 					: vid_priv->colour_bg;
120 			}
121 			break;
122 		}
123 #endif
124 #ifdef CONFIG_VIDEO_BPP32
125 		case VIDEO_BPP32: {
126 			uint32_t *dst = line;
127 
128 			for (i = 0; i < VIDEO_FONT_HEIGHT; i++) {
129 				*dst-- = (pfont[i] & mask) ? vid_priv->colour_fg
130 					: vid_priv->colour_bg;
131 			}
132 			break;
133 		}
134 #endif
135 		default:
136 			return -ENOSYS;
137 		}
138 		line += vid_priv->line_length;
139 		mask >>= 1;
140 	}
141 
142 	return VID_TO_POS(VIDEO_FONT_WIDTH);
143 }
144 
145 
146 static int console_set_row_2(struct udevice *dev, uint row, int clr)
147 {
148 	struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
149 	void *line;
150 	int pixels = VIDEO_FONT_HEIGHT * vid_priv->xsize;
151 	int i;
152 
153 	line = vid_priv->fb + vid_priv->ysize * vid_priv->line_length -
154 		(row + 1) * VIDEO_FONT_HEIGHT * vid_priv->line_length;
155 	switch (vid_priv->bpix) {
156 #ifdef CONFIG_VIDEO_BPP8
157 	case VIDEO_BPP8: {
158 		uint8_t *dst = line;
159 
160 		for (i = 0; i < pixels; i++)
161 			*dst++ = clr;
162 		break;
163 	}
164 #endif
165 #ifdef CONFIG_VIDEO_BPP16
166 	case VIDEO_BPP16: {
167 		uint16_t *dst = line;
168 
169 		for (i = 0; i < pixels; i++)
170 			*dst++ = clr;
171 		break;
172 	}
173 #endif
174 #ifdef CONFIG_VIDEO_BPP32
175 	case VIDEO_BPP32: {
176 		uint32_t *dst = line;
177 
178 		for (i = 0; i < pixels; i++)
179 			*dst++ = clr;
180 		break;
181 	}
182 #endif
183 	default:
184 		return -ENOSYS;
185 	}
186 
187 	return 0;
188 }
189 
190 static int console_move_rows_2(struct udevice *dev, uint rowdst, uint rowsrc,
191 			       uint count)
192 {
193 	struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
194 	void *dst;
195 	void *src;
196 	void *end;
197 
198 	end = vid_priv->fb + vid_priv->ysize * vid_priv->line_length;
199 	dst = end - (rowdst + count) * VIDEO_FONT_HEIGHT *
200 		vid_priv->line_length;
201 	src = end - (rowsrc + count) * VIDEO_FONT_HEIGHT *
202 		vid_priv->line_length;
203 	memmove(dst, src, VIDEO_FONT_HEIGHT * vid_priv->line_length * count);
204 
205 	return 0;
206 }
207 
208 static int console_putc_xy_2(struct udevice *dev, uint x_frac, uint y, char ch)
209 {
210 	struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev);
211 	struct udevice *vid = dev->parent;
212 	struct video_priv *vid_priv = dev_get_uclass_priv(vid);
213 	int i, row;
214 	void *line;
215 
216 	if (x_frac + VID_TO_POS(vc_priv->x_charsize) > vc_priv->xsize_frac)
217 		return -EAGAIN;
218 
219 	line = vid_priv->fb + (vid_priv->ysize - y - 1) *
220 			vid_priv->line_length +
221 			(vid_priv->xsize - VID_TO_PIXEL(x_frac) -
222 			VIDEO_FONT_WIDTH - 1) * VNBYTES(vid_priv->bpix);
223 
224 	for (row = 0; row < VIDEO_FONT_HEIGHT; row++) {
225 		uchar bits = video_fontdata[ch * VIDEO_FONT_HEIGHT + row];
226 
227 		switch (vid_priv->bpix) {
228 #ifdef CONFIG_VIDEO_BPP8
229 		case VIDEO_BPP8: {
230 			uint8_t *dst = line;
231 
232 			for (i = 0; i < VIDEO_FONT_WIDTH; i++) {
233 				*dst-- = (bits & 0x80) ? vid_priv->colour_fg
234 					: vid_priv->colour_bg;
235 				bits <<= 1;
236 			}
237 			break;
238 		}
239 #endif
240 #ifdef CONFIG_VIDEO_BPP16
241 		case VIDEO_BPP16: {
242 			uint16_t *dst = line;
243 
244 			for (i = 0; i < VIDEO_FONT_WIDTH; i++) {
245 				*dst-- = (bits & 0x80) ? vid_priv->colour_fg
246 					: vid_priv->colour_bg;
247 				bits <<= 1;
248 			}
249 			break;
250 		}
251 #endif
252 #ifdef CONFIG_VIDEO_BPP32
253 		case VIDEO_BPP32: {
254 			uint32_t *dst = line;
255 
256 			for (i = 0; i < VIDEO_FONT_WIDTH; i++) {
257 				*dst-- = (bits & 0x80) ? vid_priv->colour_fg
258 					: vid_priv->colour_bg;
259 				bits <<= 1;
260 			}
261 			break;
262 		}
263 #endif
264 		default:
265 			return -ENOSYS;
266 		}
267 		line -= vid_priv->line_length;
268 	}
269 
270 	return VID_TO_POS(VIDEO_FONT_WIDTH);
271 }
272 
273 static int console_set_row_3(struct udevice *dev, uint row, int clr)
274 {
275 	struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
276 	int pbytes = VNBYTES(vid_priv->bpix);
277 	void *line;
278 	int i, j;
279 
280 	line = vid_priv->fb + row * VIDEO_FONT_HEIGHT * pbytes;
281 	for (j = 0; j < vid_priv->ysize; j++) {
282 		switch (vid_priv->bpix) {
283 #ifdef CONFIG_VIDEO_BPP8
284 		case VIDEO_BPP8: {
285 			uint8_t *dst = line;
286 
287 			for (i = 0; i < VIDEO_FONT_HEIGHT; i++)
288 				*dst++ = clr;
289 			break;
290 		}
291 #endif
292 #ifdef CONFIG_VIDEO_BPP16
293 		case VIDEO_BPP16: {
294 			uint16_t *dst = line;
295 
296 			for (i = 0; i < VIDEO_FONT_HEIGHT; i++)
297 				*dst++ = clr;
298 			break;
299 		}
300 #endif
301 #ifdef CONFIG_VIDEO_BPP32
302 		case VIDEO_BPP32: {
303 			uint32_t *dst = line;
304 
305 			for (i = 0; i < VIDEO_FONT_HEIGHT; i++)
306 				*dst++ = clr;
307 			break;
308 		}
309 #endif
310 		default:
311 			return -ENOSYS;
312 		}
313 		line += vid_priv->line_length;
314 	}
315 
316 	return 0;
317 }
318 
319 static int console_move_rows_3(struct udevice *dev, uint rowdst, uint rowsrc,
320 			       uint count)
321 {
322 	struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
323 	void *dst;
324 	void *src;
325 	int pbytes = VNBYTES(vid_priv->bpix);
326 	int j;
327 
328 	dst = vid_priv->fb + rowdst * VIDEO_FONT_HEIGHT * pbytes;
329 	src = vid_priv->fb + rowsrc * VIDEO_FONT_HEIGHT * pbytes;
330 
331 	for (j = 0; j < vid_priv->ysize; j++) {
332 		memmove(dst, src, VIDEO_FONT_HEIGHT * pbytes * count);
333 		src += vid_priv->line_length;
334 		dst += vid_priv->line_length;
335 	}
336 
337 	return 0;
338 }
339 
340 static int console_putc_xy_3(struct udevice *dev, uint x_frac, uint y, char ch)
341 {
342 	struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev);
343 	struct udevice *vid = dev->parent;
344 	struct video_priv *vid_priv = dev_get_uclass_priv(vid);
345 	int pbytes = VNBYTES(vid_priv->bpix);
346 	int i, col;
347 	int mask = 0x80;
348 	void *line = vid_priv->fb +
349 		(vid_priv->ysize - VID_TO_PIXEL(x_frac) - 1) *
350 		vid_priv->line_length + y * pbytes;
351 	uchar *pfont = video_fontdata + ch * VIDEO_FONT_HEIGHT;
352 
353 	if (x_frac + VID_TO_POS(vc_priv->x_charsize) > vc_priv->xsize_frac)
354 		return -EAGAIN;
355 
356 	for (col = 0; col < VIDEO_FONT_HEIGHT; col++) {
357 		switch (vid_priv->bpix) {
358 #ifdef CONFIG_VIDEO_BPP8
359 		case VIDEO_BPP8: {
360 			uint8_t *dst = line;
361 
362 			for (i = 0; i < VIDEO_FONT_HEIGHT; i++) {
363 				*dst++ = (pfont[i] & mask) ? vid_priv->colour_fg
364 					: vid_priv->colour_bg;
365 			}
366 			break;
367 		}
368 #endif
369 #ifdef CONFIG_VIDEO_BPP16
370 		case VIDEO_BPP16: {
371 			uint16_t *dst = line;
372 
373 			for (i = 0; i < VIDEO_FONT_HEIGHT; i++) {
374 				*dst++ = (pfont[i] & mask) ? vid_priv->colour_fg
375 					: vid_priv->colour_bg;
376 			}
377 			break;
378 		}
379 #endif
380 #ifdef CONFIG_VIDEO_BPP32
381 		case VIDEO_BPP32: {
382 			uint32_t *dst = line;
383 
384 			for (i = 0; i < VIDEO_FONT_HEIGHT; i++) {
385 				*dst++ = (pfont[i] & mask) ? vid_priv->colour_fg
386 					: vid_priv->colour_bg;
387 			}
388 			break;
389 		}
390 #endif
391 		default:
392 			return -ENOSYS;
393 		}
394 		line -= vid_priv->line_length;
395 		mask >>= 1;
396 	}
397 
398 	return VID_TO_POS(VIDEO_FONT_WIDTH);
399 }
400 
401 
402 static int console_probe_2(struct udevice *dev)
403 {
404 	struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev);
405 	struct udevice *vid_dev = dev->parent;
406 	struct video_priv *vid_priv = dev_get_uclass_priv(vid_dev);
407 
408 	vc_priv->x_charsize = VIDEO_FONT_WIDTH;
409 	vc_priv->y_charsize = VIDEO_FONT_HEIGHT;
410 	vc_priv->cols = vid_priv->xsize / VIDEO_FONT_WIDTH;
411 	vc_priv->rows = vid_priv->ysize / VIDEO_FONT_HEIGHT;
412 
413 	return 0;
414 }
415 
416 static int console_probe_1_3(struct udevice *dev)
417 {
418 	struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev);
419 	struct udevice *vid_dev = dev->parent;
420 	struct video_priv *vid_priv = dev_get_uclass_priv(vid_dev);
421 
422 	vc_priv->x_charsize = VIDEO_FONT_WIDTH;
423 	vc_priv->y_charsize = VIDEO_FONT_HEIGHT;
424 	vc_priv->cols = vid_priv->ysize / VIDEO_FONT_WIDTH;
425 	vc_priv->rows = vid_priv->xsize / VIDEO_FONT_HEIGHT;
426 	vc_priv->xsize_frac = VID_TO_POS(vid_priv->ysize);
427 
428 	return 0;
429 }
430 
431 struct vidconsole_ops console_ops_1 = {
432 	.putc_xy	= console_putc_xy_1,
433 	.move_rows	= console_move_rows_1,
434 	.set_row	= console_set_row_1,
435 };
436 
437 struct vidconsole_ops console_ops_2 = {
438 	.putc_xy	= console_putc_xy_2,
439 	.move_rows	= console_move_rows_2,
440 	.set_row	= console_set_row_2,
441 };
442 
443 struct vidconsole_ops console_ops_3 = {
444 	.putc_xy	= console_putc_xy_3,
445 	.move_rows	= console_move_rows_3,
446 	.set_row	= console_set_row_3,
447 };
448 
449 U_BOOT_DRIVER(vidconsole_1) = {
450 	.name	= "vidconsole1",
451 	.id	= UCLASS_VIDEO_CONSOLE,
452 	.ops	= &console_ops_1,
453 	.probe	= console_probe_1_3,
454 };
455 
456 U_BOOT_DRIVER(vidconsole_2) = {
457 	.name	= "vidconsole2",
458 	.id	= UCLASS_VIDEO_CONSOLE,
459 	.ops	= &console_ops_2,
460 	.probe	= console_probe_2,
461 };
462 
463 U_BOOT_DRIVER(vidconsole_3) = {
464 	.name	= "vidconsole3",
465 	.id	= UCLASS_VIDEO_CONSOLE,
466 	.ops	= &console_ops_3,
467 	.probe	= console_probe_1_3,
468 };
469