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