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