]> Git Repo - J-u-boot.git/blame - drivers/video/video-uclass.c
video: Add function to obtain the U-Boot logo
[J-u-boot.git] / drivers / video / video-uclass.c
CommitLineData
83d290c5 1// SPDX-License-Identifier: GPL-2.0+
1acafc73
SG
2/*
3 * Copyright (c) 2015 Google, Inc
1acafc73
SG
4 */
5
b953ec2b
PD
6#define LOG_CATEGORY UCLASS_VIDEO
7
1acafc73 8#include <common.h>
9beac5da 9#include <console.h>
1eb69ae4 10#include <cpu_func.h>
1acafc73 11#include <dm.h>
f7ae49fc 12#include <log.h>
336d4615 13#include <malloc.h>
1acafc73
SG
14#include <mapmem.h>
15#include <stdio_dev.h>
16#include <video.h>
17#include <video_console.h>
90526e9f 18#include <asm/cache.h>
401d1c4f 19#include <asm/global_data.h>
1acafc73 20#include <dm/lists.h>
9de731f2 21#include <dm/device_compat.h>
1acafc73
SG
22#include <dm/device-internal.h>
23#include <dm/uclass-internal.h>
24#ifdef CONFIG_SANDBOX
25#include <asm/sdl.h>
26#endif
27
28/*
29 * Theory of operation:
30 *
31 * Before relocation each device is bound. The driver for each device must
8a8d24bd 32 * set the @align and @size values in struct video_uc_plat. This
1acafc73
SG
33 * information represents the requires size and alignment of the frame buffer
34 * for the device. The values can be an over-estimate but cannot be too
35 * small. The actual values will be suppled (in the same manner) by the bind()
bd0df823
T
36 * method after relocation. Additionally driver can allocate frame buffer
37 * itself by setting plat->base.
1acafc73
SG
38 *
39 * This information is then picked up by video_reserve() which works out how
40 * much memory is needed for all devices. This is allocated between
41 * gd->video_bottom and gd->video_top.
42 *
43 * After relocation the same process occurs. The driver supplies the same
44 * @size and @align information and this time video_post_bind() checks that
45 * the drivers does not overflow the allocated memory.
46 *
47 * The frame buffer address is actually set (to plat->base) in
48 * video_post_probe(). This function also clears the frame buffer and
49 * allocates a suitable text console device. This can then be used to write
50 * text to the video device.
51 */
52DECLARE_GLOBAL_DATA_PTR;
53
7812bbdc
SG
54/**
55 * struct video_uc_priv - Information for the video uclass
56 *
57 * @video_ptr: Current allocation position of the video framebuffer pointer.
58 * While binding devices after relocation, this points to the next
59 * available address to use for a device's framebuffer. It starts at
60 * gd->video_top and works downwards, running out of space when it hits
61 * gd->video_bottom.
62 */
63struct video_uc_priv {
64 ulong video_ptr;
65};
66
a032e4b5
SG
67/** struct vid_rgb - Describes a video colour */
68struct vid_rgb {
69 u32 r;
70 u32 g;
71 u32 b;
72};
73
68dcdc99
SG
74void video_set_flush_dcache(struct udevice *dev, bool flush)
75{
76 struct video_priv *priv = dev_get_uclass_priv(dev);
77
78 priv->flush_dcache = flush;
79}
80
1acafc73
SG
81static ulong alloc_fb(struct udevice *dev, ulong *addrp)
82{
8a8d24bd 83 struct video_uc_plat *plat = dev_get_uclass_plat(dev);
1acafc73
SG
84 ulong base, align, size;
85
3968398e
BM
86 if (!plat->size)
87 return 0;
88
bd0df823
T
89 /* Allow drivers to allocate the frame buffer themselves */
90 if (plat->base)
91 return 0;
92
1acafc73
SG
93 align = plat->align ? plat->align : 1 << 20;
94 base = *addrp - plat->size;
95 base &= ~(align - 1);
96 plat->base = base;
97 size = *addrp - base;
98 *addrp = base;
99
100 return size;
101}
102
103int video_reserve(ulong *addrp)
104{
105 struct udevice *dev;
106 ulong size;
107
108 gd->video_top = *addrp;
109 for (uclass_find_first_device(UCLASS_VIDEO, &dev);
110 dev;
111 uclass_find_next_device(&dev)) {
112 size = alloc_fb(dev, addrp);
113 debug("%s: Reserving %lx bytes at %lx for video device '%s'\n",
114 __func__, size, *addrp, dev->name);
115 }
551ca0e6
SG
116
117 /* Allocate space for PCI video devices in case there were not bound */
118 if (*addrp == gd->video_top)
119 *addrp -= CONFIG_VIDEO_PCI_DEFAULT_FB_SIZE;
120
1acafc73 121 gd->video_bottom = *addrp;
aef43ea0 122 gd->fb_base = *addrp;
1acafc73
SG
123 debug("Video frame buffers from %lx to %lx\n", gd->video_bottom,
124 gd->video_top);
125
126 return 0;
127}
128
50d562c0 129int video_fill(struct udevice *dev, u32 colour)
1acafc73
SG
130{
131 struct video_priv *priv = dev_get_uclass_priv(dev);
138dfea8 132 int ret;
1acafc73 133
d7a75d3c 134 switch (priv->bpix) {
0c20aafe
SG
135 case VIDEO_BPP16:
136 if (IS_ENABLED(CONFIG_VIDEO_BPP16)) {
137 u16 *ppix = priv->fb;
138 u16 *end = priv->fb + priv->fb_size;
139
140 while (ppix < end)
50d562c0 141 *ppix++ = colour;
0c20aafe
SG
142 break;
143 }
144 case VIDEO_BPP32:
145 if (IS_ENABLED(CONFIG_VIDEO_BPP32)) {
146 u32 *ppix = priv->fb;
147 u32 *end = priv->fb + priv->fb_size;
148
149 while (ppix < end)
50d562c0 150 *ppix++ = colour;
0c20aafe
SG
151 break;
152 }
d7a75d3c 153 default:
50d562c0 154 memset(priv->fb, colour, priv->fb_size);
d7a75d3c 155 break;
1acafc73 156 }
138dfea8
SG
157 ret = video_sync_copy(dev, priv->fb, priv->fb + priv->fb_size);
158 if (ret)
159 return ret;
c6ebd011 160
5337663e 161 return video_sync(dev, false);
1acafc73
SG
162}
163
50d562c0
SG
164int video_clear(struct udevice *dev)
165{
166 struct video_priv *priv = dev_get_uclass_priv(dev);
167 int ret;
168
169 ret = video_fill(dev, priv->colour_bg);
170 if (ret)
171 return ret;
172
173 return 0;
174}
175
a032e4b5
SG
176static const struct vid_rgb colours[VID_COLOUR_COUNT] = {
177 { 0x00, 0x00, 0x00 }, /* black */
178 { 0xc0, 0x00, 0x00 }, /* red */
179 { 0x00, 0xc0, 0x00 }, /* green */
180 { 0xc0, 0x60, 0x00 }, /* brown */
181 { 0x00, 0x00, 0xc0 }, /* blue */
182 { 0xc0, 0x00, 0xc0 }, /* magenta */
183 { 0x00, 0xc0, 0xc0 }, /* cyan */
184 { 0xc0, 0xc0, 0xc0 }, /* light gray */
185 { 0x80, 0x80, 0x80 }, /* gray */
186 { 0xff, 0x00, 0x00 }, /* bright red */
187 { 0x00, 0xff, 0x00 }, /* bright green */
188 { 0xff, 0xff, 0x00 }, /* yellow */
189 { 0x00, 0x00, 0xff }, /* bright blue */
190 { 0xff, 0x00, 0xff }, /* bright magenta */
191 { 0x00, 0xff, 0xff }, /* bright cyan */
192 { 0xff, 0xff, 0xff }, /* white */
193};
194
195u32 video_index_to_colour(struct video_priv *priv, unsigned int idx)
196{
197 switch (priv->bpix) {
198 case VIDEO_BPP16:
199 if (CONFIG_IS_ENABLED(VIDEO_BPP16)) {
200 return ((colours[idx].r >> 3) << 11) |
201 ((colours[idx].g >> 2) << 5) |
202 ((colours[idx].b >> 3) << 0);
203 }
204 break;
205 case VIDEO_BPP32:
206 if (CONFIG_IS_ENABLED(VIDEO_BPP32)) {
207 if (priv->format == VIDEO_X2R10G10B10)
208 return (colours[idx].r << 22) |
209 (colours[idx].g << 12) |
210 (colours[idx].b << 2);
211 else
212 return (colours[idx].r << 16) |
213 (colours[idx].g << 8) |
214 (colours[idx].b << 0);
215 }
216 break;
217 default:
218 break;
219 }
220
221 /*
222 * For unknown bit arrangements just support
223 * black and white.
224 */
225 if (idx)
226 return 0xffffff; /* white */
227
228 return 0x000000; /* black */
229}
230
b9f210a3 231void video_set_default_colors(struct udevice *dev, bool invert)
5c30fbb8 232{
b9f210a3
SG
233 struct video_priv *priv = dev_get_uclass_priv(dev);
234 int fore, back;
235
0c20aafe
SG
236 if (CONFIG_IS_ENABLED(SYS_WHITE_ON_BLACK)) {
237 /* White is used when switching to bold, use light gray here */
238 fore = VID_LIGHT_GRAY;
239 back = VID_BLACK;
240 } else {
241 fore = VID_BLACK;
242 back = VID_WHITE;
243 }
b9f210a3
SG
244 if (invert) {
245 int temp;
246
247 temp = fore;
248 fore = back;
249 back = temp;
250 }
251 priv->fg_col_idx = fore;
eabb0725 252 priv->bg_col_idx = back;
a032e4b5
SG
253 priv->colour_fg = video_index_to_colour(priv, fore);
254 priv->colour_bg = video_index_to_colour(priv, back);
5c30fbb8
HS
255}
256
1acafc73 257/* Flush video activity to the caches */
9de731f2 258int video_sync(struct udevice *vid, bool force)
1acafc73 259{
9d69c2d9
MS
260 struct video_ops *ops = video_get_ops(vid);
261 int ret;
262
263 if (ops && ops->video_sync) {
264 ret = ops->video_sync(vid);
265 if (ret)
266 return ret;
267 }
268
1acafc73
SG
269 /*
270 * flush_dcache_range() is declared in common.h but it seems that some
271 * architectures do not actually implement it. Is there a way to find
272 * out whether it exists? For now, ARM is safe.
273 */
10015025 274#if defined(CONFIG_ARM) && !CONFIG_IS_ENABLED(SYS_DCACHE_OFF)
1acafc73
SG
275 struct video_priv *priv = dev_get_uclass_priv(vid);
276
277 if (priv->flush_dcache) {
278 flush_dcache_range((ulong)priv->fb,
7981394e
SG
279 ALIGN((ulong)priv->fb + priv->fb_size,
280 CONFIG_SYS_CACHELINE_SIZE));
1acafc73
SG
281 }
282#elif defined(CONFIG_VIDEO_SANDBOX_SDL)
283 struct video_priv *priv = dev_get_uclass_priv(vid);
284 static ulong last_sync;
285
7c19e4cb 286 if (force || get_timer(last_sync) > 100) {
1acafc73
SG
287 sandbox_sdl_sync(priv->fb);
288 last_sync = get_timer(0);
289 }
290#endif
9de731f2 291 return 0;
1acafc73
SG
292}
293
294void video_sync_all(void)
295{
296 struct udevice *dev;
9de731f2 297 int ret;
1acafc73
SG
298
299 for (uclass_find_first_device(UCLASS_VIDEO, &dev);
300 dev;
301 uclass_find_next_device(&dev)) {
9de731f2
MS
302 if (device_active(dev)) {
303 ret = video_sync(dev, true);
304 if (ret)
305 dev_dbg(dev, "Video sync failed\n");
306 }
1acafc73
SG
307 }
308}
309
2e2e6d8c
PD
310bool video_is_active(void)
311{
312 struct udevice *dev;
313
314 for (uclass_find_first_device(UCLASS_VIDEO, &dev);
315 dev;
316 uclass_find_next_device(&dev)) {
317 if (device_active(dev))
318 return true;
319 }
320
321 return false;
322}
323
1acafc73
SG
324int video_get_xsize(struct udevice *dev)
325{
326 struct video_priv *priv = dev_get_uclass_priv(dev);
327
328 return priv->xsize;
329}
330
331int video_get_ysize(struct udevice *dev)
332{
333 struct video_priv *priv = dev_get_uclass_priv(dev);
334
335 return priv->ysize;
336}
337
9beac5da
SG
338#ifdef CONFIG_VIDEO_COPY
339int video_sync_copy(struct udevice *dev, void *from, void *to)
340{
341 struct video_priv *priv = dev_get_uclass_priv(dev);
342
343 if (priv->copy_fb) {
344 long offset, size;
345
346 /* Find the offset of the first byte to copy */
347 if ((ulong)to > (ulong)from) {
348 size = to - from;
349 offset = from - priv->fb;
350 } else {
351 size = from - to;
352 offset = to - priv->fb;
353 }
354
355 /*
356 * Allow a bit of leeway for valid requests somewhere near the
357 * frame buffer
358 */
359 if (offset < -priv->fb_size || offset > 2 * priv->fb_size) {
360#ifdef DEBUG
6a19e938 361 char str[120];
9beac5da
SG
362
363 snprintf(str, sizeof(str),
6a19e938 364 "[** FAULT sync_copy fb=%p, from=%p, to=%p, offset=%lx]",
9beac5da
SG
365 priv->fb, from, to, offset);
366 console_puts_select_stderr(true, str);
367#endif
368 return -EFAULT;
369 }
370
371 /*
372 * Silently crop the memcpy. This allows callers to avoid doing
373 * this themselves. It is common for the end pointer to go a
374 * few lines after the end of the frame buffer, since most of
375 * the update algorithms terminate a line after their last write
376 */
377 if (offset + size > priv->fb_size) {
378 size = priv->fb_size - offset;
379 } else if (offset < 0) {
380 size += offset;
381 offset = 0;
382 }
383
384 memcpy(priv->copy_fb + offset, priv->fb + offset, size);
385 }
386
387 return 0;
388}
7d70116f
SG
389
390int video_sync_copy_all(struct udevice *dev)
391{
392 struct video_priv *priv = dev_get_uclass_priv(dev);
393
394 video_sync_copy(dev, priv->fb, priv->fb + priv->fb_size);
395
396 return 0;
397}
398
9beac5da
SG
399#endif
400
84e63abf
SG
401#define SPLASH_DECL(_name) \
402 extern u8 __splash_ ## _name ## _begin[]; \
403 extern u8 __splash_ ## _name ## _end[]
404
405#define SPLASH_START(_name) __splash_ ## _name ## _begin
406
407SPLASH_DECL(u_boot_logo);
408
0d389018
SG
409void *video_get_u_boot_logo(void)
410{
411 return SPLASH_START(u_boot_logo);
412}
413
84e63abf
SG
414static int show_splash(struct udevice *dev)
415{
416 u8 *data = SPLASH_START(u_boot_logo);
417 int ret;
418
419 ret = video_bmp_display(dev, map_to_sysmem(data), -4, 4, true);
420
421 return 0;
422}
423
1acafc73
SG
424/* Set up the display ready for use */
425static int video_post_probe(struct udevice *dev)
426{
8a8d24bd 427 struct video_uc_plat *plat = dev_get_uclass_plat(dev);
1acafc73
SG
428 struct video_priv *priv = dev_get_uclass_priv(dev);
429 char name[30], drv[15], *str;
826f35f9 430 const char *drv_name = drv;
1acafc73
SG
431 struct udevice *cons;
432 int ret;
433
434 /* Set up the line and display size */
435 priv->fb = map_sysmem(plat->base, plat->size);
06696ebe
SG
436 if (!priv->line_length)
437 priv->line_length = priv->xsize * VNBYTES(priv->bpix);
438
1acafc73
SG
439 priv->fb_size = priv->line_length * priv->ysize;
440
6efa809d
SG
441 if (IS_ENABLED(CONFIG_VIDEO_COPY) && plat->copy_base)
442 priv->copy_fb = map_sysmem(plat->copy_base, plat->size);
443
5c30fbb8 444 /* Set up colors */
b9f210a3 445 video_set_default_colors(dev, false);
8ef05352
RC
446
447 if (!CONFIG_IS_ENABLED(NO_FB_CLEAR))
448 video_clear(dev);
1acafc73 449
83510766 450 /*
826f35f9 451 * Create a text console device. For now we always do this, although
83510766 452 * it might be useful to support only bitmap drawing on the device
826f35f9
SG
453 * for boards that don't need to display text. We create a TrueType
454 * console if enabled, a rotated console if the video driver requests
455 * it, otherwise a normal console.
456 *
457 * The console can be override by setting vidconsole_drv_name before
458 * probing this video driver, or in the probe() method.
459 *
460 * TrueType does not support rotation at present so fall back to the
461 * rotated console in that case.
83510766 462 */
826f35f9 463 if (!priv->rot && IS_ENABLED(CONFIG_CONSOLE_TRUETYPE)) {
a29b0120
SG
464 snprintf(name, sizeof(name), "%s.vidconsole_tt", dev->name);
465 strcpy(drv, "vidconsole_tt");
466 } else {
467 snprintf(name, sizeof(name), "%s.vidconsole%d", dev->name,
468 priv->rot);
469 snprintf(drv, sizeof(drv), "vidconsole%d", priv->rot);
470 }
471
83510766
SG
472 str = strdup(name);
473 if (!str)
474 return -ENOMEM;
826f35f9
SG
475 if (priv->vidconsole_drv_name)
476 drv_name = priv->vidconsole_drv_name;
477 ret = device_bind_driver(dev, drv_name, str, &cons);
83510766
SG
478 if (ret) {
479 debug("%s: Cannot bind console driver\n", __func__);
480 return ret;
481 }
826f35f9 482
83510766
SG
483 ret = device_probe(cons);
484 if (ret) {
485 debug("%s: Cannot probe console driver\n", __func__);
486 return ret;
487 }
488
25a44833
FE
489 if (IS_ENABLED(CONFIG_VIDEO_LOGO) &&
490 !IS_ENABLED(CONFIG_SPLASH_SCREEN) && !plat->hide_logo) {
84e63abf
SG
491 ret = show_splash(dev);
492 if (ret) {
493 log_debug("Cannot show splash screen\n");
494 return ret;
495 }
496 }
497
1acafc73
SG
498 return 0;
499};
500
501/* Post-relocation, allocate memory for the frame buffer */
502static int video_post_bind(struct udevice *dev)
503{
7812bbdc
SG
504 struct video_uc_priv *uc_priv;
505 ulong addr;
1acafc73
SG
506 ulong size;
507
508 /* Before relocation there is nothing to do here */
75164181 509 if (!(gd->flags & GD_FLG_RELOC))
1acafc73 510 return 0;
7812bbdc
SG
511
512 /* Set up the video pointer, if this is the first device */
0fd3d911 513 uc_priv = uclass_get_priv(dev->uclass);
7812bbdc
SG
514 if (!uc_priv->video_ptr)
515 uc_priv->video_ptr = gd->video_top;
516
517 /* Allocate framebuffer space for this device */
518 addr = uc_priv->video_ptr;
1acafc73
SG
519 size = alloc_fb(dev, &addr);
520 if (addr < gd->video_bottom) {
69989749
PD
521 /* Device tree node may need the 'u-boot,dm-pre-reloc' or
522 * 'u-boot,dm-pre-proper' tag
523 */
1acafc73
SG
524 printf("Video device '%s' cannot allocate frame buffer memory -ensure the device is set up before relocation\n",
525 dev->name);
526 return -ENOSPC;
527 }
528 debug("%s: Claiming %lx bytes at %lx for video device '%s'\n",
529 __func__, size, addr, dev->name);
7812bbdc 530 uc_priv->video_ptr = addr;
1acafc73
SG
531
532 return 0;
533}
534
535UCLASS_DRIVER(video) = {
536 .id = UCLASS_VIDEO,
537 .name = "video",
538 .flags = DM_UC_FLAG_SEQ_ALIAS,
539 .post_bind = video_post_bind,
1acafc73 540 .post_probe = video_post_probe,
41575d8e
SG
541 .priv_auto = sizeof(struct video_uc_priv),
542 .per_device_auto = sizeof(struct video_priv),
8a8d24bd 543 .per_device_plat_auto = sizeof(struct video_uc_plat),
1acafc73 544};
This page took 0.327415 seconds and 4 git commands to generate.