blob: b4852555989adebc4ca41067cef1312417015215 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Simon Glassb5146b22016-01-18 19:52:19 -07002/*
3 * Copyright (c) 2015 Google, Inc
4 * (C) Copyright 2015
5 * Bernecker & Rainer Industrieelektronik GmbH - http://www.br-automation.com
Simon Glassb5146b22016-01-18 19:52:19 -07006 */
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
14static 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) {
Simon Glassc6567312019-12-20 18:10:35 -070025 case VIDEO_BPP8:
26 if (IS_ENABLED(CONFIG_VIDEO_BPP8)) {
27 uint8_t *dst = line;
Simon Glassb5146b22016-01-18 19:52:19 -070028
Simon Glassc6567312019-12-20 18:10:35 -070029 for (i = 0; i < VIDEO_FONT_HEIGHT; i++)
30 *dst++ = clr;
31 break;
32 }
33 case VIDEO_BPP16:
34 if (IS_ENABLED(CONFIG_VIDEO_BPP16)) {
35 uint16_t *dst = line;
Simon Glassb5146b22016-01-18 19:52:19 -070036
Simon Glassc6567312019-12-20 18:10:35 -070037 for (i = 0; i < VIDEO_FONT_HEIGHT; i++)
38 *dst++ = clr;
39 break;
40 }
41 case VIDEO_BPP32:
42 if (IS_ENABLED(CONFIG_VIDEO_BPP32)) {
43 uint32_t *dst = line;
Simon Glassb5146b22016-01-18 19:52:19 -070044
Simon Glassc6567312019-12-20 18:10:35 -070045 for (i = 0; i < VIDEO_FONT_HEIGHT; i++)
46 *dst++ = clr;
47 break;
48 }
Simon Glassb5146b22016-01-18 19:52:19 -070049 default:
50 return -ENOSYS;
51 }
52 line += vid_priv->line_length;
53 }
54
55 return 0;
56}
57
58static int console_move_rows_1(struct udevice *dev, uint rowdst, uint rowsrc,
59 uint count)
60{
61 struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
62 void *dst;
63 void *src;
64 int pbytes = VNBYTES(vid_priv->bpix);
65 int j;
66
67 dst = vid_priv->fb + vid_priv->line_length -
68 (rowdst + count) * VIDEO_FONT_HEIGHT * pbytes;
69 src = vid_priv->fb + vid_priv->line_length -
70 (rowsrc + count) * VIDEO_FONT_HEIGHT * pbytes;
71
72 for (j = 0; j < vid_priv->ysize; j++) {
73 memmove(dst, src, VIDEO_FONT_HEIGHT * pbytes * count);
74 src += vid_priv->line_length;
75 dst += vid_priv->line_length;
76 }
77
78 return 0;
79}
80
Simon Glassf2661782016-01-14 18:10:37 -070081static int console_putc_xy_1(struct udevice *dev, uint x_frac, uint y, char ch)
Simon Glassb5146b22016-01-18 19:52:19 -070082{
Simon Glassf2661782016-01-14 18:10:37 -070083 struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev);
Simon Glassb5146b22016-01-18 19:52:19 -070084 struct udevice *vid = dev->parent;
85 struct video_priv *vid_priv = dev_get_uclass_priv(vid);
86 int pbytes = VNBYTES(vid_priv->bpix);
87 int i, col;
88 int mask = 0x80;
Simon Glassf2661782016-01-14 18:10:37 -070089 void *line;
Andre Przywara96c9bf72019-03-23 01:29:55 +000090 uchar *pfont = video_fontdata + (u8)ch * VIDEO_FONT_HEIGHT;
Simon Glassb5146b22016-01-18 19:52:19 -070091
Simon Glassf2661782016-01-14 18:10:37 -070092 line = vid_priv->fb + (VID_TO_PIXEL(x_frac) + 1) *
93 vid_priv->line_length - (y + 1) * pbytes;
94 if (x_frac + VID_TO_POS(vc_priv->x_charsize) > vc_priv->xsize_frac)
95 return -EAGAIN;
96
Simon Glassb5146b22016-01-18 19:52:19 -070097 for (col = 0; col < VIDEO_FONT_HEIGHT; col++) {
98 switch (vid_priv->bpix) {
Simon Glassc6567312019-12-20 18:10:35 -070099 case VIDEO_BPP8:
100 if (IS_ENABLED(CONFIG_VIDEO_BPP8)) {
101 uint8_t *dst = line;
Simon Glassb5146b22016-01-18 19:52:19 -0700102
Simon Glassc6567312019-12-20 18:10:35 -0700103 for (i = 0; i < VIDEO_FONT_HEIGHT; i++) {
104 *dst-- = (pfont[i] & mask) ?
105 vid_priv->colour_fg :
106 vid_priv->colour_bg;
107 }
108 break;
Simon Glassb5146b22016-01-18 19:52:19 -0700109 }
Simon Glassc6567312019-12-20 18:10:35 -0700110 case VIDEO_BPP16:
111 if (IS_ENABLED(CONFIG_VIDEO_BPP16)) {
112 uint16_t *dst = line;
Simon Glassb5146b22016-01-18 19:52:19 -0700113
Simon Glassc6567312019-12-20 18:10:35 -0700114 for (i = 0; i < VIDEO_FONT_HEIGHT; i++) {
115 *dst-- = (pfont[i] & mask) ?
116 vid_priv->colour_fg :
117 vid_priv->colour_bg;
118 }
119 break;
Simon Glassb5146b22016-01-18 19:52:19 -0700120 }
Simon Glassc6567312019-12-20 18:10:35 -0700121 case VIDEO_BPP32:
122 if (IS_ENABLED(CONFIG_VIDEO_BPP32)) {
123 uint32_t *dst = line;
Simon Glassb5146b22016-01-18 19:52:19 -0700124
Simon Glassc6567312019-12-20 18:10:35 -0700125 for (i = 0; i < VIDEO_FONT_HEIGHT; i++) {
126 *dst-- = (pfont[i] & mask) ?
127 vid_priv->colour_fg :
128 vid_priv->colour_bg;
129 }
130 break;
Simon Glassb5146b22016-01-18 19:52:19 -0700131 }
Simon Glassb5146b22016-01-18 19:52:19 -0700132 default:
133 return -ENOSYS;
134 }
135 line += vid_priv->line_length;
136 mask >>= 1;
137 }
138
Simon Glassf2661782016-01-14 18:10:37 -0700139 return VID_TO_POS(VIDEO_FONT_WIDTH);
Simon Glassb5146b22016-01-18 19:52:19 -0700140}
141
142
143static int console_set_row_2(struct udevice *dev, uint row, int clr)
144{
145 struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
146 void *line;
147 int pixels = VIDEO_FONT_HEIGHT * vid_priv->xsize;
148 int i;
149
150 line = vid_priv->fb + vid_priv->ysize * vid_priv->line_length -
151 (row + 1) * VIDEO_FONT_HEIGHT * vid_priv->line_length;
152 switch (vid_priv->bpix) {
Simon Glassc6567312019-12-20 18:10:35 -0700153 case VIDEO_BPP8:
154 if (IS_ENABLED(CONFIG_VIDEO_BPP8)) {
155 uint8_t *dst = line;
Simon Glassb5146b22016-01-18 19:52:19 -0700156
Simon Glassc6567312019-12-20 18:10:35 -0700157 for (i = 0; i < pixels; i++)
158 *dst++ = clr;
159 break;
160 }
161 case VIDEO_BPP16:
162 if (IS_ENABLED(CONFIG_VIDEO_BPP16)) {
163 uint16_t *dst = line;
Simon Glassb5146b22016-01-18 19:52:19 -0700164
Simon Glassc6567312019-12-20 18:10:35 -0700165 for (i = 0; i < pixels; i++)
166 *dst++ = clr;
167 break;
168 }
169 case VIDEO_BPP32:
170 if (IS_ENABLED(CONFIG_VIDEO_BPP32)) {
171 uint32_t *dst = line;
Simon Glassb5146b22016-01-18 19:52:19 -0700172
Simon Glassc6567312019-12-20 18:10:35 -0700173 for (i = 0; i < pixels; i++)
174 *dst++ = clr;
175 break;
176 }
Simon Glassb5146b22016-01-18 19:52:19 -0700177 default:
178 return -ENOSYS;
179 }
180
181 return 0;
182}
183
184static int console_move_rows_2(struct udevice *dev, uint rowdst, uint rowsrc,
185 uint count)
186{
187 struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
188 void *dst;
189 void *src;
190 void *end;
191
192 end = vid_priv->fb + vid_priv->ysize * vid_priv->line_length;
193 dst = end - (rowdst + count) * VIDEO_FONT_HEIGHT *
194 vid_priv->line_length;
195 src = end - (rowsrc + count) * VIDEO_FONT_HEIGHT *
196 vid_priv->line_length;
197 memmove(dst, src, VIDEO_FONT_HEIGHT * vid_priv->line_length * count);
198
199 return 0;
200}
201
Simon Glassf2661782016-01-14 18:10:37 -0700202static int console_putc_xy_2(struct udevice *dev, uint x_frac, uint y, char ch)
Simon Glassb5146b22016-01-18 19:52:19 -0700203{
Simon Glassf2661782016-01-14 18:10:37 -0700204 struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev);
Simon Glassb5146b22016-01-18 19:52:19 -0700205 struct udevice *vid = dev->parent;
206 struct video_priv *vid_priv = dev_get_uclass_priv(vid);
207 int i, row;
208 void *line;
209
Simon Glassf2661782016-01-14 18:10:37 -0700210 if (x_frac + VID_TO_POS(vc_priv->x_charsize) > vc_priv->xsize_frac)
211 return -EAGAIN;
212
Simon Glassb5146b22016-01-18 19:52:19 -0700213 line = vid_priv->fb + (vid_priv->ysize - y - 1) *
Simon Glassf2661782016-01-14 18:10:37 -0700214 vid_priv->line_length +
215 (vid_priv->xsize - VID_TO_PIXEL(x_frac) -
216 VIDEO_FONT_WIDTH - 1) * VNBYTES(vid_priv->bpix);
Simon Glassb5146b22016-01-18 19:52:19 -0700217
218 for (row = 0; row < VIDEO_FONT_HEIGHT; row++) {
Andre Przywara96c9bf72019-03-23 01:29:55 +0000219 unsigned int idx = (u8)ch * VIDEO_FONT_HEIGHT + row;
220 uchar bits = video_fontdata[idx];
Simon Glassb5146b22016-01-18 19:52:19 -0700221
222 switch (vid_priv->bpix) {
Simon Glassc6567312019-12-20 18:10:35 -0700223 case VIDEO_BPP8:
224 if (IS_ENABLED(CONFIG_VIDEO_BPP8)) {
225 uint8_t *dst = line;
Simon Glassb5146b22016-01-18 19:52:19 -0700226
Simon Glassc6567312019-12-20 18:10:35 -0700227 for (i = 0; i < VIDEO_FONT_WIDTH; i++) {
228 *dst-- = (bits & 0x80) ?
229 vid_priv->colour_fg :
230 vid_priv->colour_bg;
231 bits <<= 1;
232 }
233 break;
Simon Glassb5146b22016-01-18 19:52:19 -0700234 }
Simon Glassc6567312019-12-20 18:10:35 -0700235 case VIDEO_BPP16:
236 if (IS_ENABLED(CONFIG_VIDEO_BPP16)) {
237 uint16_t *dst = line;
Simon Glassb5146b22016-01-18 19:52:19 -0700238
Simon Glassc6567312019-12-20 18:10:35 -0700239 for (i = 0; i < VIDEO_FONT_WIDTH; i++) {
240 *dst-- = (bits & 0x80) ?
241 vid_priv->colour_fg :
242 vid_priv->colour_bg;
243 bits <<= 1;
244 }
245 break;
Simon Glassb5146b22016-01-18 19:52:19 -0700246 }
Simon Glassc6567312019-12-20 18:10:35 -0700247 case VIDEO_BPP32:
248 if (IS_ENABLED(CONFIG_VIDEO_BPP32)) {
249 uint32_t *dst = line;
Simon Glassb5146b22016-01-18 19:52:19 -0700250
Simon Glassc6567312019-12-20 18:10:35 -0700251 for (i = 0; i < VIDEO_FONT_WIDTH; i++) {
252 *dst-- = (bits & 0x80) ?
253 vid_priv->colour_fg :
254 vid_priv->colour_bg;
255 bits <<= 1;
256 }
257 break;
Simon Glassb5146b22016-01-18 19:52:19 -0700258 }
Simon Glassb5146b22016-01-18 19:52:19 -0700259 default:
260 return -ENOSYS;
261 }
262 line -= vid_priv->line_length;
263 }
264
Simon Glassf2661782016-01-14 18:10:37 -0700265 return VID_TO_POS(VIDEO_FONT_WIDTH);
Simon Glassb5146b22016-01-18 19:52:19 -0700266}
267
268static int console_set_row_3(struct udevice *dev, uint row, int clr)
269{
270 struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
271 int pbytes = VNBYTES(vid_priv->bpix);
272 void *line;
273 int i, j;
274
275 line = vid_priv->fb + row * VIDEO_FONT_HEIGHT * pbytes;
276 for (j = 0; j < vid_priv->ysize; j++) {
277 switch (vid_priv->bpix) {
Simon Glassc6567312019-12-20 18:10:35 -0700278 case VIDEO_BPP8:
279 if (IS_ENABLED(CONFIG_VIDEO_BPP8)) {
280 uint8_t *dst = line;
Simon Glassb5146b22016-01-18 19:52:19 -0700281
Simon Glassc6567312019-12-20 18:10:35 -0700282 for (i = 0; i < VIDEO_FONT_HEIGHT; i++)
283 *dst++ = clr;
284 break;
285 }
286 case VIDEO_BPP16:
287 if (IS_ENABLED(CONFIG_VIDEO_BPP16)) {
288 uint16_t *dst = line;
Simon Glassb5146b22016-01-18 19:52:19 -0700289
Simon Glassc6567312019-12-20 18:10:35 -0700290 for (i = 0; i < VIDEO_FONT_HEIGHT; i++)
291 *dst++ = clr;
292 break;
293 }
294 case VIDEO_BPP32:
295 if (IS_ENABLED(CONFIG_VIDEO_BPP32)) {
296 uint32_t *dst = line;
Simon Glassb5146b22016-01-18 19:52:19 -0700297
Simon Glassc6567312019-12-20 18:10:35 -0700298 for (i = 0; i < VIDEO_FONT_HEIGHT; i++)
299 *dst++ = clr;
300 break;
301 }
Simon Glassb5146b22016-01-18 19:52:19 -0700302 default:
303 return -ENOSYS;
304 }
305 line += vid_priv->line_length;
306 }
307
308 return 0;
309}
310
311static int console_move_rows_3(struct udevice *dev, uint rowdst, uint rowsrc,
312 uint count)
313{
314 struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
315 void *dst;
316 void *src;
317 int pbytes = VNBYTES(vid_priv->bpix);
318 int j;
319
320 dst = vid_priv->fb + rowdst * VIDEO_FONT_HEIGHT * pbytes;
321 src = vid_priv->fb + rowsrc * VIDEO_FONT_HEIGHT * pbytes;
322
323 for (j = 0; j < vid_priv->ysize; j++) {
324 memmove(dst, src, VIDEO_FONT_HEIGHT * pbytes * count);
325 src += vid_priv->line_length;
326 dst += vid_priv->line_length;
327 }
328
329 return 0;
330}
331
Simon Glassf2661782016-01-14 18:10:37 -0700332static int console_putc_xy_3(struct udevice *dev, uint x_frac, uint y, char ch)
Simon Glassb5146b22016-01-18 19:52:19 -0700333{
Simon Glassf2661782016-01-14 18:10:37 -0700334 struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev);
Simon Glassb5146b22016-01-18 19:52:19 -0700335 struct udevice *vid = dev->parent;
336 struct video_priv *vid_priv = dev_get_uclass_priv(vid);
337 int pbytes = VNBYTES(vid_priv->bpix);
338 int i, col;
339 int mask = 0x80;
Simon Glassf2661782016-01-14 18:10:37 -0700340 void *line = vid_priv->fb +
341 (vid_priv->ysize - VID_TO_PIXEL(x_frac) - 1) *
Simon Glassb5146b22016-01-18 19:52:19 -0700342 vid_priv->line_length + y * pbytes;
Andre Przywara96c9bf72019-03-23 01:29:55 +0000343 uchar *pfont = video_fontdata + (u8)ch * VIDEO_FONT_HEIGHT;
Simon Glassb5146b22016-01-18 19:52:19 -0700344
Simon Glassf2661782016-01-14 18:10:37 -0700345 if (x_frac + VID_TO_POS(vc_priv->x_charsize) > vc_priv->xsize_frac)
346 return -EAGAIN;
347
Simon Glassb5146b22016-01-18 19:52:19 -0700348 for (col = 0; col < VIDEO_FONT_HEIGHT; col++) {
349 switch (vid_priv->bpix) {
Simon Glassc6567312019-12-20 18:10:35 -0700350 case VIDEO_BPP8:
351 if (IS_ENABLED(CONFIG_VIDEO_BPP8)) {
352 uint8_t *dst = line;
Simon Glassb5146b22016-01-18 19:52:19 -0700353
Simon Glassc6567312019-12-20 18:10:35 -0700354 for (i = 0; i < VIDEO_FONT_HEIGHT; i++) {
355 *dst++ = (pfont[i] & mask) ?
356 vid_priv->colour_fg :
357 vid_priv->colour_bg;
358 }
359 break;
Simon Glassb5146b22016-01-18 19:52:19 -0700360 }
Simon Glassc6567312019-12-20 18:10:35 -0700361 case VIDEO_BPP16:
362 if (IS_ENABLED(CONFIG_VIDEO_BPP16)) {
363 uint16_t *dst = line;
Simon Glassb5146b22016-01-18 19:52:19 -0700364
Simon Glassc6567312019-12-20 18:10:35 -0700365 for (i = 0; i < VIDEO_FONT_HEIGHT; i++) {
366 *dst++ = (pfont[i] & mask) ?
367 vid_priv->colour_fg :
368 vid_priv->colour_bg;
369 }
370 break;
Simon Glassb5146b22016-01-18 19:52:19 -0700371 }
Simon Glassc6567312019-12-20 18:10:35 -0700372 case VIDEO_BPP32:
373 if (IS_ENABLED(CONFIG_VIDEO_BPP32)) {
374 uint32_t *dst = line;
Simon Glassb5146b22016-01-18 19:52:19 -0700375
Simon Glassc6567312019-12-20 18:10:35 -0700376 for (i = 0; i < VIDEO_FONT_HEIGHT; i++) {
377 *dst++ = (pfont[i] & mask) ?
378 vid_priv->colour_fg :
379 vid_priv->colour_bg;
380 }
381 break;
Simon Glassb5146b22016-01-18 19:52:19 -0700382 }
Simon Glassb5146b22016-01-18 19:52:19 -0700383 default:
384 return -ENOSYS;
385 }
386 line -= vid_priv->line_length;
387 mask >>= 1;
388 }
389
Simon Glassf2661782016-01-14 18:10:37 -0700390 return VID_TO_POS(VIDEO_FONT_WIDTH);
Simon Glassb5146b22016-01-18 19:52:19 -0700391}
392
393
Simon Glassf2661782016-01-14 18:10:37 -0700394static int console_probe_2(struct udevice *dev)
395{
396 struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev);
397 struct udevice *vid_dev = dev->parent;
398 struct video_priv *vid_priv = dev_get_uclass_priv(vid_dev);
399
400 vc_priv->x_charsize = VIDEO_FONT_WIDTH;
401 vc_priv->y_charsize = VIDEO_FONT_HEIGHT;
402 vc_priv->cols = vid_priv->xsize / VIDEO_FONT_WIDTH;
403 vc_priv->rows = vid_priv->ysize / VIDEO_FONT_HEIGHT;
404
405 return 0;
406}
407
Simon Glassb5146b22016-01-18 19:52:19 -0700408static int console_probe_1_3(struct udevice *dev)
409{
Simon Glassf2661782016-01-14 18:10:37 -0700410 struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev);
411 struct udevice *vid_dev = dev->parent;
412 struct video_priv *vid_priv = dev_get_uclass_priv(vid_dev);
Simon Glassb5146b22016-01-18 19:52:19 -0700413
Simon Glassf2661782016-01-14 18:10:37 -0700414 vc_priv->x_charsize = VIDEO_FONT_WIDTH;
415 vc_priv->y_charsize = VIDEO_FONT_HEIGHT;
416 vc_priv->cols = vid_priv->ysize / VIDEO_FONT_WIDTH;
417 vc_priv->rows = vid_priv->xsize / VIDEO_FONT_HEIGHT;
418 vc_priv->xsize_frac = VID_TO_POS(vid_priv->ysize);
Simon Glassb5146b22016-01-18 19:52:19 -0700419
420 return 0;
421}
422
423struct vidconsole_ops console_ops_1 = {
424 .putc_xy = console_putc_xy_1,
425 .move_rows = console_move_rows_1,
426 .set_row = console_set_row_1,
427};
428
429struct vidconsole_ops console_ops_2 = {
430 .putc_xy = console_putc_xy_2,
431 .move_rows = console_move_rows_2,
432 .set_row = console_set_row_2,
433};
434
435struct vidconsole_ops console_ops_3 = {
436 .putc_xy = console_putc_xy_3,
437 .move_rows = console_move_rows_3,
438 .set_row = console_set_row_3,
439};
440
441U_BOOT_DRIVER(vidconsole_1) = {
442 .name = "vidconsole1",
443 .id = UCLASS_VIDEO_CONSOLE,
444 .ops = &console_ops_1,
445 .probe = console_probe_1_3,
446};
447
448U_BOOT_DRIVER(vidconsole_2) = {
449 .name = "vidconsole2",
450 .id = UCLASS_VIDEO_CONSOLE,
451 .ops = &console_ops_2,
Simon Glassf2661782016-01-14 18:10:37 -0700452 .probe = console_probe_2,
Simon Glassb5146b22016-01-18 19:52:19 -0700453};
454
455U_BOOT_DRIVER(vidconsole_3) = {
456 .name = "vidconsole3",
457 .id = UCLASS_VIDEO_CONSOLE,
458 .ops = &console_ops_3,
459 .probe = console_probe_1_3,
460};