b924bc345948339ab8bd7a67a200f9aaa1969c7e
[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  * (C) Copyright 2023 Dzmitry Sankouski <dsankouski@gmail.com>
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 #include "vidconsole_internal.h"
15
16 static int console_set_row_1(struct udevice *dev, uint row, int clr)
17 {
18         struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
19         struct console_simple_priv *priv = dev_get_priv(dev);
20         struct video_fontdata *fontdata = priv->fontdata;
21         int pbytes = VNBYTES(vid_priv->bpix);
22         void *start, *dst, *line;
23         int i, j;
24         int ret;
25
26         start = vid_priv->fb + vid_priv->line_length -
27                 (row + 1) * fontdata->height * pbytes;
28         line = start;
29         for (j = 0; j < vid_priv->ysize; j++) {
30                 dst = line;
31                 for (i = 0; i < fontdata->height; i++)
32                         fill_pixel_and_goto_next(&dst, clr, pbytes, pbytes);
33                 line += vid_priv->line_length;
34         }
35         ret = vidconsole_sync_copy(dev, start, line);
36         if (ret)
37                 return ret;
38
39         return 0;
40 }
41
42 static int console_move_rows_1(struct udevice *dev, uint rowdst, uint rowsrc,
43                                    uint count)
44 {
45         struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
46         struct console_simple_priv *priv = dev_get_priv(dev);
47         struct video_fontdata *fontdata = priv->fontdata;
48         int pbytes = VNBYTES(vid_priv->bpix);
49         void *dst;
50         void *src;
51         int j, ret;
52
53         dst = vid_priv->fb + vid_priv->line_length -
54                 (rowdst + count) * fontdata->height * pbytes;
55         src = vid_priv->fb + vid_priv->line_length -
56                 (rowsrc + count) * fontdata->height * pbytes;
57
58         for (j = 0; j < vid_priv->ysize; j++) {
59                 ret = vidconsole_memmove(dev, dst, src,
60                                         fontdata->height * pbytes * count);
61                 if (ret)
62                         return ret;
63                 src += vid_priv->line_length;
64                 dst += vid_priv->line_length;
65         }
66
67         return 0;
68 }
69
70 static int console_putc_xy_1(struct udevice *dev, uint x_frac, uint y, char ch)
71 {
72         struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev);
73         struct udevice *vid = dev->parent;
74         struct video_priv *vid_priv = dev_get_uclass_priv(vid);
75         struct console_simple_priv *priv = dev_get_priv(dev);
76         struct video_fontdata *fontdata = priv->fontdata;
77         int pbytes = VNBYTES(vid_priv->bpix);
78         int x, linenum, ret;
79         void *start, *line;
80         uchar *pfont = fontdata->video_fontdata +
81                         (u8)ch * fontdata->char_pixel_bytes;
82
83         if (x_frac + VID_TO_POS(vc_priv->x_charsize) > vc_priv->xsize_frac)
84                 return -EAGAIN;
85         linenum = VID_TO_PIXEL(x_frac) + 1;
86         x = y + 1;
87         start = vid_priv->fb + linenum * vid_priv->line_length - x * pbytes;
88         line = start;
89
90         ret = fill_char_horizontally(pfont, &line, vid_priv, fontdata, FLIPPED_DIRECTION);
91         if (ret)
92                 return ret;
93
94         /* We draw backwards from 'start, so account for the first line */
95         ret = vidconsole_sync_copy(dev, start - vid_priv->line_length, line);
96         if (ret)
97                 return ret;
98
99         return VID_TO_POS(fontdata->width);
100 }
101
102
103 static int console_set_row_2(struct udevice *dev, uint row, int clr)
104 {
105         struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
106         struct console_simple_priv *priv = dev_get_priv(dev);
107         struct video_fontdata *fontdata = priv->fontdata;
108         void *start, *line, *dst, *end;
109         int pixels = fontdata->height * vid_priv->xsize;
110         int i, ret;
111         int pbytes = VNBYTES(vid_priv->bpix);
112
113         start = vid_priv->fb + vid_priv->ysize * vid_priv->line_length -
114                 (row + 1) * fontdata->height * vid_priv->line_length;
115         line = start;
116         dst = line;
117         for (i = 0; i < pixels; i++)
118                 fill_pixel_and_goto_next(&dst, clr, pbytes, pbytes);
119         end = dst;
120         ret = vidconsole_sync_copy(dev, start, end);
121         if (ret)
122                 return ret;
123
124         return 0;
125 }
126
127 static int console_move_rows_2(struct udevice *dev, uint rowdst, uint rowsrc,
128                                uint count)
129 {
130         struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
131         struct console_simple_priv *priv = dev_get_priv(dev);
132         struct video_fontdata *fontdata = priv->fontdata;
133         void *dst;
134         void *src;
135         void *end;
136
137         end = vid_priv->fb + vid_priv->ysize * vid_priv->line_length;
138         dst = end - (rowdst + count) * fontdata->height *
139                 vid_priv->line_length;
140         src = end - (rowsrc + count) * fontdata->height *
141                 vid_priv->line_length;
142         vidconsole_memmove(dev, dst, src,
143                            fontdata->height * vid_priv->line_length * count);
144
145         return 0;
146 }
147
148 static int console_putc_xy_2(struct udevice *dev, uint x_frac, uint y, char ch)
149 {
150         struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev);
151         struct udevice *vid = dev->parent;
152         struct video_priv *vid_priv = dev_get_uclass_priv(vid);
153         struct console_simple_priv *priv = dev_get_priv(dev);
154         struct video_fontdata *fontdata = priv->fontdata;
155         int pbytes = VNBYTES(vid_priv->bpix);
156         int linenum, x, ret;
157         void *start, *line;
158         uchar *pfont = fontdata->video_fontdata +
159                         (u8)ch * fontdata->char_pixel_bytes;
160
161         if (x_frac + VID_TO_POS(vc_priv->x_charsize) > vc_priv->xsize_frac)
162                 return -EAGAIN;
163         linenum = vid_priv->ysize - y - 1;
164         x = vid_priv->xsize - VID_TO_PIXEL(x_frac) - 1;
165         start = vid_priv->fb + linenum * vid_priv->line_length + x * pbytes;
166         line = start;
167
168         ret = fill_char_vertically(pfont, &line, vid_priv, fontdata, FLIPPED_DIRECTION);
169         if (ret)
170                 return ret;
171
172         /* Add 4 bytes to allow for the first pixel writen */
173         ret = vidconsole_sync_copy(dev, start + 4, line);
174         if (ret)
175                 return ret;
176
177         return VID_TO_POS(fontdata->width);
178 }
179
180 static int console_set_row_3(struct udevice *dev, uint row, int clr)
181 {
182         struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
183         struct console_simple_priv *priv = dev_get_priv(dev);
184         struct video_fontdata *fontdata = priv->fontdata;
185         int pbytes = VNBYTES(vid_priv->bpix);
186         void *start, *dst, *line;
187         int i, j, ret;
188
189         start = vid_priv->fb + row * fontdata->height * pbytes;
190         line = start;
191         for (j = 0; j < vid_priv->ysize; j++) {
192                 dst = line;
193                 for (i = 0; i < fontdata->height; i++)
194                         fill_pixel_and_goto_next(&dst, clr, pbytes, pbytes);
195                 line += vid_priv->line_length;
196         }
197         ret = vidconsole_sync_copy(dev, start, line);
198         if (ret)
199                 return ret;
200
201         return 0;
202 }
203
204 static int console_move_rows_3(struct udevice *dev, uint rowdst, uint rowsrc,
205                                uint count)
206 {
207         struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
208         struct console_simple_priv *priv = dev_get_priv(dev);
209         struct video_fontdata *fontdata = priv->fontdata;
210         int pbytes = VNBYTES(vid_priv->bpix);
211         void *dst;
212         void *src;
213         int j, ret;
214
215         dst = vid_priv->fb + rowdst * fontdata->height * pbytes;
216         src = vid_priv->fb + rowsrc * fontdata->height * pbytes;
217
218         for (j = 0; j < vid_priv->ysize; j++) {
219                 ret = vidconsole_memmove(dev, dst, src,
220                                         fontdata->height * pbytes * count);
221                 if (ret)
222                         return ret;
223                 src += vid_priv->line_length;
224                 dst += vid_priv->line_length;
225         }
226
227         return 0;
228 }
229
230 static int console_putc_xy_3(struct udevice *dev, uint x_frac, uint y, char ch)
231 {
232         struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev);
233         struct udevice *vid = dev->parent;
234         struct video_priv *vid_priv = dev_get_uclass_priv(vid);
235         struct console_simple_priv *priv = dev_get_priv(dev);
236         struct video_fontdata *fontdata = priv->fontdata;
237         int pbytes = VNBYTES(vid_priv->bpix);
238         int linenum, x, ret;
239         void *start, *line;
240         uchar *pfont = fontdata->video_fontdata +
241                         (u8)ch * fontdata->char_pixel_bytes;
242
243         if (x_frac + VID_TO_POS(vc_priv->x_charsize) > vc_priv->xsize_frac)
244                 return -EAGAIN;
245         x = y;
246         linenum = vid_priv->ysize - VID_TO_PIXEL(x_frac) - 1;
247         start = vid_priv->fb + linenum * vid_priv->line_length + y * pbytes;
248         line = start;
249
250         ret = fill_char_horizontally(pfont, &line, vid_priv, fontdata, NORMAL_DIRECTION);
251         if (ret)
252                 return ret;
253         /* Add a line to allow for the first pixels writen */
254         ret = vidconsole_sync_copy(dev, start + vid_priv->line_length, line);
255         if (ret)
256                 return ret;
257
258         return VID_TO_POS(fontdata->width);
259 }
260
261 struct vidconsole_ops console_ops_1 = {
262         .putc_xy        = console_putc_xy_1,
263         .move_rows      = console_move_rows_1,
264         .set_row        = console_set_row_1,
265 };
266
267 struct vidconsole_ops console_ops_2 = {
268         .putc_xy        = console_putc_xy_2,
269         .move_rows      = console_move_rows_2,
270         .set_row        = console_set_row_2,
271 };
272
273 struct vidconsole_ops console_ops_3 = {
274         .putc_xy        = console_putc_xy_3,
275         .move_rows      = console_move_rows_3,
276         .set_row        = console_set_row_3,
277 };
278
279 U_BOOT_DRIVER(vidconsole_1) = {
280         .name   = "vidconsole1",
281         .id     = UCLASS_VIDEO_CONSOLE,
282         .ops    = &console_ops_1,
283         .probe  = console_probe,
284         .priv_auto      = sizeof(struct console_simple_priv),
285 };
286
287 U_BOOT_DRIVER(vidconsole_2) = {
288         .name   = "vidconsole2",
289         .id     = UCLASS_VIDEO_CONSOLE,
290         .ops    = &console_ops_2,
291         .probe  = console_probe,
292         .priv_auto      = sizeof(struct console_simple_priv),
293 };
294
295 U_BOOT_DRIVER(vidconsole_3) = {
296         .name   = "vidconsole3",
297         .id     = UCLASS_VIDEO_CONSOLE,
298         .ops    = &console_ops_3,
299         .probe  = console_probe,
300         .priv_auto      = sizeof(struct console_simple_priv),
301 };