video: Update rotated console to support copy buffer
[platform/kernel/u-boot.git] / drivers / video / console_rotate.c
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 *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
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
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
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
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
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
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
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
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
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
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 };