diff options
author | Bin Meng <bmeng.cn@gmail.com> | 2018-06-12 18:36:22 +0300 |
---|---|---|
committer | Bin Meng <bmeng.cn@gmail.com> | 2018-06-17 16:16:04 +0300 |
commit | 4a08c74697c679607f1ddb56167c74fc31d53068 (patch) | |
tree | 4816671c72cba2b2aee0935d0ac44229da285ee9 /drivers/video | |
parent | d1fe9927465c3df03c7c0c8f62bd8468d24f66bc (diff) | |
download | u-boot-4a08c74697c679607f1ddb56167c74fc31d53068.tar.xz |
dm: video: Add an EFI framebuffer driver
This adds a DM video driver for U-Boot as the EFI payload. The driver
makes use of all necessary information from the passed EFI GOP info
to create a linear framebuffer device, as if it were initialized by
U-Boot itself.
Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anatolij Gustschin <agust@denx.de>
Diffstat (limited to 'drivers/video')
-rw-r--r-- | drivers/video/Kconfig | 9 | ||||
-rw-r--r-- | drivers/video/Makefile | 1 | ||||
-rw-r--r-- | drivers/video/efi.c | 146 |
3 files changed, 156 insertions, 0 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 4c4d2861fe..5ee9032dc9 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -156,6 +156,15 @@ config VIDEO_COREBOOT coreboot already. This can in principle be used with any platform that coreboot supports. +config VIDEO_EFI + bool "Enable EFI framebuffer driver support" + depends on EFI_STUB + help + Turn on this option to enable a framebuffeer driver when U-Boot is + loaded as a payload (see README.u-boot_on_efi) by an EFI BIOS where + the graphics device is configured by the EFI BIOS already. This can + in principle be used with any platform that has an EFI BIOS. + config VIDEO_VESA bool "Enable VESA video driver support" default n diff --git a/drivers/video/Makefile b/drivers/video/Makefile index cf7ad281c3..7c89c67dce 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -32,6 +32,7 @@ obj-$(CONFIG_LD9040) += ld9040.o obj-$(CONFIG_VIDEO_BCM2835) += bcm2835.o obj-$(CONFIG_VIDEO_COREBOOT) += coreboot.o obj-$(CONFIG_VIDEO_DA8XX) += da8xx-fb.o videomodes.o +obj-$(CONFIG_VIDEO_EFI) += efi.o obj-$(CONFIG_VIDEO_LCD_ANX9804) += anx9804.o obj-$(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM) += hitachi_tx18d42vm_lcd.o obj-$(CONFIG_VIDEO_LCD_SSD2828) += ssd2828.o diff --git a/drivers/video/efi.c b/drivers/video/efi.c new file mode 100644 index 0000000000..653cb47265 --- /dev/null +++ b/drivers/video/efi.c @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com> + * + * EFI framebuffer driver based on GOP + */ + +#include <common.h> +#include <dm.h> +#include <efi_api.h> +#include <vbe.h> +#include <video.h> + +struct pixel { + u8 pos; + u8 size; +}; + +static const struct efi_framebuffer { + struct pixel red; + struct pixel green; + struct pixel blue; + struct pixel rsvd; +} efi_framebuffer_format_map[] = { + [EFI_GOT_RGBA8] = { {0, 8}, {8, 8}, {16, 8}, {24, 8} }, + [EFI_GOT_BGRA8] = { {16, 8}, {8, 8}, {0, 8}, {24, 8} }, +}; + +static void efi_find_pixel_bits(u32 mask, u8 *pos, u8 *size) +{ + u8 first, len; + + first = 0; + len = 0; + + if (mask) { + while (!(mask & 0x1)) { + mask = mask >> 1; + first++; + } + + while (mask & 0x1) { + mask = mask >> 1; + len++; + } + } + + *pos = first; + *size = len; +} + +static int save_vesa_mode(struct vesa_mode_info *vesa) +{ + struct efi_entry_gopmode *mode; + const struct efi_framebuffer *fbinfo; + int size; + int ret; + + ret = efi_info_get(EFIET_GOP_MODE, (void **)&mode, &size); + if (ret == -ENOENT) { + debug("efi graphics output protocol mode not found\n"); + return -ENXIO; + } + + vesa->phys_base_ptr = mode->fb_base; + vesa->x_resolution = mode->info->width; + vesa->y_resolution = mode->info->height; + + if (mode->info->pixel_format < EFI_GOT_BITMASK) { + fbinfo = &efi_framebuffer_format_map[mode->info->pixel_format]; + vesa->red_mask_size = fbinfo->red.size; + vesa->red_mask_pos = fbinfo->red.pos; + vesa->green_mask_size = fbinfo->green.size; + vesa->green_mask_pos = fbinfo->green.pos; + vesa->blue_mask_size = fbinfo->blue.size; + vesa->blue_mask_pos = fbinfo->blue.pos; + vesa->reserved_mask_size = fbinfo->rsvd.size; + vesa->reserved_mask_pos = fbinfo->rsvd.pos; + + vesa->bits_per_pixel = 32; + vesa->bytes_per_scanline = mode->info->pixels_per_scanline * 4; + } else if (mode->info->pixel_format == EFI_GOT_BITMASK) { + efi_find_pixel_bits(mode->info->pixel_bitmask[0], + &vesa->red_mask_pos, + &vesa->red_mask_size); + efi_find_pixel_bits(mode->info->pixel_bitmask[1], + &vesa->green_mask_pos, + &vesa->green_mask_size); + efi_find_pixel_bits(mode->info->pixel_bitmask[2], + &vesa->blue_mask_pos, + &vesa->blue_mask_size); + efi_find_pixel_bits(mode->info->pixel_bitmask[3], + &vesa->reserved_mask_pos, + &vesa->reserved_mask_size); + vesa->bits_per_pixel = vesa->red_mask_size + + vesa->green_mask_size + + vesa->blue_mask_size + + vesa->reserved_mask_size; + vesa->bytes_per_scanline = (mode->info->pixels_per_scanline * + vesa->bits_per_pixel) / 8; + } else { + debug("efi set unknown framebuffer format: %d\n", + mode->info->pixel_format); + return -EINVAL; + } + + return 0; +} + +static int efi_video_probe(struct udevice *dev) +{ + struct video_uc_platdata *plat = dev_get_uclass_platdata(dev); + struct video_priv *uc_priv = dev_get_uclass_priv(dev); + struct vesa_mode_info *vesa = &mode_info.vesa; + int ret; + + /* Initialize vesa_mode_info structure */ + ret = save_vesa_mode(vesa); + if (ret) + goto err; + + ret = vbe_setup_video_priv(vesa, uc_priv, plat); + if (ret) + goto err; + + printf("Video: %dx%dx%d\n", uc_priv->xsize, uc_priv->ysize, + vesa->bits_per_pixel); + + return 0; + +err: + printf("No video mode configured in EFI!\n"); + return ret; +} + +static const struct udevice_id efi_video_ids[] = { + { .compatible = "efi-fb" }, + { } +}; + +U_BOOT_DRIVER(efi_video) = { + .name = "efi_video", + .id = UCLASS_VIDEO, + .of_match = efi_video_ids, + .probe = efi_video_probe, +}; |