1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (c) 2015 Google, Inc
6 #define LOG_CATEGORY UCLASS_VIDEO
17 #include <stdio_dev.h>
19 #include <video_console.h>
20 #include <asm/cache.h>
21 #include <asm/global_data.h>
23 #include <dm/device_compat.h>
24 #include <dm/device-internal.h>
25 #include <dm/uclass-internal.h>
31 * Theory of operation:
33 * Before relocation each device is bound. The driver for each device must
34 * set the @align and @size values in struct video_uc_plat. This
35 * information represents the requires size and alignment of the frame buffer
36 * for the device. The values can be an over-estimate but cannot be too
37 * small. The actual values will be suppled (in the same manner) by the bind()
38 * method after relocation. Additionally driver can allocate frame buffer
39 * itself by setting plat->base.
41 * This information is then picked up by video_reserve() which works out how
42 * much memory is needed for all devices. This is allocated between
43 * gd->video_bottom and gd->video_top.
45 * After relocation the same process occurs. The driver supplies the same
46 * @size and @align information and this time video_post_bind() checks that
47 * the drivers does not overflow the allocated memory.
49 * The frame buffer address is actually set (to plat->base) in
50 * video_post_probe(). This function also clears the frame buffer and
51 * allocates a suitable text console device. This can then be used to write
52 * text to the video device.
54 DECLARE_GLOBAL_DATA_PTR
;
57 * struct video_uc_priv - Information for the video uclass
59 * @video_ptr: Current allocation position of the video framebuffer pointer.
60 * While binding devices after relocation, this points to the next
61 * available address to use for a device's framebuffer. It starts at
62 * gd->video_top and works downwards, running out of space when it hits
65 struct video_uc_priv
{
69 /** struct vid_rgb - Describes a video colour */
76 void video_set_flush_dcache(struct udevice
*dev
, bool flush
)
78 struct video_priv
*priv
= dev_get_uclass_priv(dev
);
80 priv
->flush_dcache
= flush
;
83 static ulong
alloc_fb_(ulong align
, ulong size
, ulong
*addrp
)
87 align
= align
? align
: 1 << 20;
96 static ulong
alloc_fb(struct udevice
*dev
, ulong
*addrp
)
98 struct video_uc_plat
*plat
= dev_get_uclass_plat(dev
);
102 if (IS_ENABLED(CONFIG_VIDEO_COPY
) && plat
->copy_size
) {
103 size
= alloc_fb_(plat
->align
, plat
->copy_size
, addrp
);
104 plat
->copy_base
= *addrp
;
111 /* Allow drivers to allocate the frame buffer themselves */
115 size
= alloc_fb_(plat
->align
, plat
->size
, addrp
);
121 int video_reserve(ulong
*addrp
)
126 if (IS_ENABLED(CONFIG_SPL_VIDEO_HANDOFF
) && spl_phase() == PHASE_BOARD_F
)
129 gd
->video_top
= *addrp
;
130 for (uclass_find_first_device(UCLASS_VIDEO
, &dev
);
132 uclass_find_next_device(&dev
)) {
133 size
= alloc_fb(dev
, addrp
);
134 debug("%s: Reserving %lx bytes at %lx for video device '%s'\n",
135 __func__
, size
, *addrp
, dev
->name
);
138 /* Allocate space for PCI video devices in case there were not bound */
139 if (*addrp
== gd
->video_top
)
140 *addrp
-= CONFIG_VAL(VIDEO_PCI_DEFAULT_FB_SIZE
);
142 gd
->video_bottom
= *addrp
;
143 gd
->fb_base
= *addrp
;
144 debug("Video frame buffers from %lx to %lx\n", gd
->video_bottom
,
147 if (spl_phase() == PHASE_SPL
&& CONFIG_IS_ENABLED(VIDEO_HANDOFF
)) {
148 struct video_handoff
*ho
;
150 ho
= bloblist_add(BLOBLISTT_U_BOOT_VIDEO
, sizeof(*ho
), 0);
152 return log_msg_ret("blf", -ENOENT
);
160 int video_fill_part(struct udevice
*dev
, int xstart
, int ystart
, int xend
,
161 int yend
, u32 colour
)
163 struct video_priv
*priv
= dev_get_uclass_priv(dev
);
165 int pixels
= xend
- xstart
;
168 start
= priv
->fb
+ ystart
* priv
->line_length
;
169 start
+= xstart
* VNBYTES(priv
->bpix
);
171 for (row
= ystart
; row
< yend
; row
++) {
172 switch (priv
->bpix
) {
176 if (IS_ENABLED(CONFIG_VIDEO_BPP8
)) {
177 for (i
= 0; i
< pixels
; i
++)
185 if (IS_ENABLED(CONFIG_VIDEO_BPP16
)) {
186 for (i
= 0; i
< pixels
; i
++)
194 if (IS_ENABLED(CONFIG_VIDEO_BPP32
)) {
195 for (i
= 0; i
< pixels
; i
++)
203 line
+= priv
->line_length
;
205 ret
= video_sync_copy(dev
, start
, line
);
212 int video_reserve_from_bloblist(struct video_handoff
*ho
)
214 if (!ho
->fb
|| ho
->size
== 0)
217 gd
->video_bottom
= ho
->fb
;
218 gd
->fb_base
= ho
->fb
;
219 gd
->video_top
= ho
->fb
+ ho
->size
;
220 debug("%s: Reserving %lx bytes at %08x as per bloblist received\n",
221 __func__
, (unsigned long)ho
->size
, (u32
)ho
->fb
);
226 int video_fill(struct udevice
*dev
, u32 colour
)
228 struct video_priv
*priv
= dev_get_uclass_priv(dev
);
231 switch (priv
->bpix
) {
233 if (CONFIG_IS_ENABLED(VIDEO_BPP16
)) {
234 u16
*ppix
= priv
->fb
;
235 u16
*end
= priv
->fb
+ priv
->fb_size
;
242 if (CONFIG_IS_ENABLED(VIDEO_BPP32
)) {
243 u32
*ppix
= priv
->fb
;
244 u32
*end
= priv
->fb
+ priv
->fb_size
;
251 memset(priv
->fb
, colour
, priv
->fb_size
);
254 ret
= video_sync_copy(dev
, priv
->fb
, priv
->fb
+ priv
->fb_size
);
258 return video_sync(dev
, false);
261 int video_clear(struct udevice
*dev
)
263 struct video_priv
*priv
= dev_get_uclass_priv(dev
);
266 ret
= video_fill(dev
, priv
->colour_bg
);
273 static const struct vid_rgb colours
[VID_COLOUR_COUNT
] = {
274 { 0x00, 0x00, 0x00 }, /* black */
275 { 0xc0, 0x00, 0x00 }, /* red */
276 { 0x00, 0xc0, 0x00 }, /* green */
277 { 0xc0, 0x60, 0x00 }, /* brown */
278 { 0x00, 0x00, 0xc0 }, /* blue */
279 { 0xc0, 0x00, 0xc0 }, /* magenta */
280 { 0x00, 0xc0, 0xc0 }, /* cyan */
281 { 0xc0, 0xc0, 0xc0 }, /* light gray */
282 { 0x80, 0x80, 0x80 }, /* gray */
283 { 0xff, 0x00, 0x00 }, /* bright red */
284 { 0x00, 0xff, 0x00 }, /* bright green */
285 { 0xff, 0xff, 0x00 }, /* yellow */
286 { 0x00, 0x00, 0xff }, /* bright blue */
287 { 0xff, 0x00, 0xff }, /* bright magenta */
288 { 0x00, 0xff, 0xff }, /* bright cyan */
289 { 0xff, 0xff, 0xff }, /* white */
292 u32
video_index_to_colour(struct video_priv
*priv
, enum colour_idx idx
)
294 switch (priv
->bpix
) {
296 if (CONFIG_IS_ENABLED(VIDEO_BPP16
)) {
297 return ((colours
[idx
].r
>> 3) << 11) |
298 ((colours
[idx
].g
>> 2) << 5) |
299 ((colours
[idx
].b
>> 3) << 0);
303 if (CONFIG_IS_ENABLED(VIDEO_BPP32
)) {
304 switch (priv
->format
) {
305 case VIDEO_X2R10G10B10
:
306 return (colours
[idx
].r
<< 22) |
307 (colours
[idx
].g
<< 12) |
308 (colours
[idx
].b
<< 2);
310 return (colours
[idx
].r
<< 24) |
311 (colours
[idx
].g
<< 16) |
312 (colours
[idx
].b
<< 8) | 0xff;
314 return (colours
[idx
].r
<< 16) |
315 (colours
[idx
].g
<< 8) |
316 (colours
[idx
].b
<< 0);
325 * For unknown bit arrangements just support
329 return 0xffffff; /* white */
331 return 0x000000; /* black */
334 void video_set_default_colors(struct udevice
*dev
, bool invert
)
336 struct video_priv
*priv
= dev_get_uclass_priv(dev
);
339 if (CONFIG_IS_ENABLED(SYS_WHITE_ON_BLACK
)) {
340 /* White is used when switching to bold, use light gray here */
341 fore
= VID_LIGHT_GRAY
;
354 priv
->fg_col_idx
= fore
;
355 priv
->bg_col_idx
= back
;
356 priv
->colour_fg
= video_index_to_colour(priv
, fore
);
357 priv
->colour_bg
= video_index_to_colour(priv
, back
);
360 /* Flush video activity to the caches */
361 int video_sync(struct udevice
*vid
, bool force
)
363 struct video_ops
*ops
= video_get_ops(vid
);
366 if (ops
&& ops
->video_sync
) {
367 ret
= ops
->video_sync(vid
);
373 * flush_dcache_range() is declared in common.h but it seems that some
374 * architectures do not actually implement it. Is there a way to find
375 * out whether it exists? For now, ARM is safe.
377 #if defined(CONFIG_ARM) && !CONFIG_IS_ENABLED(SYS_DCACHE_OFF)
378 struct video_priv
*priv
= dev_get_uclass_priv(vid
);
380 if (priv
->flush_dcache
) {
381 flush_dcache_range((ulong
)priv
->fb
,
382 ALIGN((ulong
)priv
->fb
+ priv
->fb_size
,
383 CONFIG_SYS_CACHELINE_SIZE
));
385 #elif defined(CONFIG_VIDEO_SANDBOX_SDL)
386 struct video_priv
*priv
= dev_get_uclass_priv(vid
);
387 static ulong last_sync
;
389 if (force
|| get_timer(last_sync
) > 100) {
390 sandbox_sdl_sync(priv
->fb
);
391 last_sync
= get_timer(0);
397 void video_sync_all(void)
402 for (uclass_find_first_device(UCLASS_VIDEO
, &dev
);
404 uclass_find_next_device(&dev
)) {
405 if (device_active(dev
)) {
406 ret
= video_sync(dev
, true);
408 dev_dbg(dev
, "Video sync failed\n");
413 bool video_is_active(void)
417 for (uclass_find_first_device(UCLASS_VIDEO
, &dev
);
419 uclass_find_next_device(&dev
)) {
420 if (device_active(dev
))
427 int video_get_xsize(struct udevice
*dev
)
429 struct video_priv
*priv
= dev_get_uclass_priv(dev
);
434 int video_get_ysize(struct udevice
*dev
)
436 struct video_priv
*priv
= dev_get_uclass_priv(dev
);
441 #ifdef CONFIG_VIDEO_COPY
442 int video_sync_copy(struct udevice
*dev
, void *from
, void *to
)
444 struct video_priv
*priv
= dev_get_uclass_priv(dev
);
449 /* Find the offset of the first byte to copy */
450 if ((ulong
)to
> (ulong
)from
) {
452 offset
= from
- priv
->fb
;
455 offset
= to
- priv
->fb
;
459 * Allow a bit of leeway for valid requests somewhere near the
462 if (offset
< -priv
->fb_size
|| offset
> 2 * priv
->fb_size
) {
466 snprintf(str
, sizeof(str
),
467 "[** FAULT sync_copy fb=%p, from=%p, to=%p, offset=%lx]",
468 priv
->fb
, from
, to
, offset
);
469 console_puts_select_stderr(true, str
);
475 * Silently crop the memcpy. This allows callers to avoid doing
476 * this themselves. It is common for the end pointer to go a
477 * few lines after the end of the frame buffer, since most of
478 * the update algorithms terminate a line after their last write
480 if (offset
+ size
> priv
->fb_size
) {
481 size
= priv
->fb_size
- offset
;
482 } else if (offset
< 0) {
487 memcpy(priv
->copy_fb
+ offset
, priv
->fb
+ offset
, size
);
493 int video_sync_copy_all(struct udevice
*dev
)
495 struct video_priv
*priv
= dev_get_uclass_priv(dev
);
497 video_sync_copy(dev
, priv
->fb
, priv
->fb
+ priv
->fb_size
);
504 #define SPLASH_DECL(_name) \
505 extern u8 __splash_ ## _name ## _begin[]; \
506 extern u8 __splash_ ## _name ## _end[]
508 #define SPLASH_START(_name) __splash_ ## _name ## _begin
510 SPLASH_DECL(u_boot_logo
);
512 void *video_get_u_boot_logo(void)
514 return SPLASH_START(u_boot_logo
);
517 static int show_splash(struct udevice
*dev
)
519 u8
*data
= SPLASH_START(u_boot_logo
);
522 ret
= video_bmp_display(dev
, map_to_sysmem(data
), -4, 4, true);
527 int video_default_font_height(struct udevice
*dev
)
529 struct vidconsole_priv
*vc_priv
= dev_get_uclass_priv(dev
);
531 if (IS_ENABLED(CONFIG_CONSOLE_TRUETYPE
))
532 return IF_ENABLED_INT(CONFIG_CONSOLE_TRUETYPE
,
533 CONFIG_CONSOLE_TRUETYPE_SIZE
);
535 return vc_priv
->y_charsize
;
538 /* Set up the display ready for use */
539 static int video_post_probe(struct udevice
*dev
)
541 struct video_uc_plat
*plat
= dev_get_uclass_plat(dev
);
542 struct video_priv
*priv
= dev_get_uclass_priv(dev
);
543 char name
[30], drv
[15], *str
;
544 const char *drv_name
= drv
;
545 struct udevice
*cons
;
548 /* Set up the line and display size */
549 priv
->fb
= map_sysmem(plat
->base
, plat
->size
);
550 if (!priv
->line_length
)
551 priv
->line_length
= priv
->xsize
* VNBYTES(priv
->bpix
);
553 priv
->fb_size
= priv
->line_length
* priv
->ysize
;
555 if (IS_ENABLED(CONFIG_VIDEO_COPY
) && plat
->copy_base
)
556 priv
->copy_fb
= map_sysmem(plat
->copy_base
, plat
->size
);
559 video_set_default_colors(dev
, false);
561 if (!CONFIG_IS_ENABLED(NO_FB_CLEAR
))
565 * Create a text console device. For now we always do this, although
566 * it might be useful to support only bitmap drawing on the device
567 * for boards that don't need to display text. We create a TrueType
568 * console if enabled, a rotated console if the video driver requests
569 * it, otherwise a normal console.
571 * The console can be override by setting vidconsole_drv_name before
572 * probing this video driver, or in the probe() method.
574 * TrueType does not support rotation at present so fall back to the
575 * rotated console in that case.
577 if (!priv
->rot
&& IS_ENABLED(CONFIG_CONSOLE_TRUETYPE
)) {
578 snprintf(name
, sizeof(name
), "%s.vidconsole_tt", dev
->name
);
579 strcpy(drv
, "vidconsole_tt");
581 snprintf(name
, sizeof(name
), "%s.vidconsole%d", dev
->name
,
583 snprintf(drv
, sizeof(drv
), "vidconsole%d", priv
->rot
);
589 if (priv
->vidconsole_drv_name
)
590 drv_name
= priv
->vidconsole_drv_name
;
591 ret
= device_bind_driver(dev
, drv_name
, str
, &cons
);
593 debug("%s: Cannot bind console driver\n", __func__
);
597 ret
= device_probe(cons
);
599 debug("%s: Cannot probe console driver\n", __func__
);
603 if (CONFIG_IS_ENABLED(VIDEO_LOGO
) &&
604 !CONFIG_IS_ENABLED(SPLASH_SCREEN
) && !plat
->hide_logo
) {
605 ret
= show_splash(dev
);
607 log_debug("Cannot show splash screen\n");
615 /* Post-relocation, allocate memory for the frame buffer */
616 static int video_post_bind(struct udevice
*dev
)
618 struct video_uc_priv
*uc_priv
;
622 /* Before relocation there is nothing to do here */
623 if (!(gd
->flags
& GD_FLG_RELOC
))
626 /* Set up the video pointer, if this is the first device */
627 uc_priv
= uclass_get_priv(dev
->uclass
);
628 if (!uc_priv
->video_ptr
)
629 uc_priv
->video_ptr
= gd
->video_top
;
631 /* Allocate framebuffer space for this device */
632 addr
= uc_priv
->video_ptr
;
633 size
= alloc_fb(dev
, &addr
);
634 if (addr
< gd
->video_bottom
) {
636 * Device tree node may need the 'bootph-all' or
637 * 'bootph-some-ram' tag
639 printf("Video device '%s' cannot allocate frame buffer memory "
640 "- ensure the device is set up before relocation\n",
644 debug("%s: Claiming %lx bytes at %lx for video device '%s'\n",
645 __func__
, size
, addr
, dev
->name
);
646 uc_priv
->video_ptr
= addr
;
651 UCLASS_DRIVER(video
) = {
654 .flags
= DM_UC_FLAG_SEQ_ALIAS
,
655 .post_bind
= video_post_bind
,
656 .post_probe
= video_post_probe
,
657 .priv_auto
= sizeof(struct video_uc_priv
),
658 .per_device_auto
= sizeof(struct video_priv
),
659 .per_device_plat_auto
= sizeof(struct video_uc_plat
),