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>
lime2-spi
Bin Meng 6 years ago
parent d1fe992746
commit 4a08c74697
  1. 9
      drivers/video/Kconfig
  2. 1
      drivers/video/Makefile
  3. 146
      drivers/video/efi.c

@ -156,6 +156,15 @@ config VIDEO_COREBOOT
coreboot already. This can in principle be used with any platform coreboot already. This can in principle be used with any platform
that coreboot supports. 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 config VIDEO_VESA
bool "Enable VESA video driver support" bool "Enable VESA video driver support"
default n default n

@ -32,6 +32,7 @@ obj-$(CONFIG_LD9040) += ld9040.o
obj-$(CONFIG_VIDEO_BCM2835) += bcm2835.o obj-$(CONFIG_VIDEO_BCM2835) += bcm2835.o
obj-$(CONFIG_VIDEO_COREBOOT) += coreboot.o obj-$(CONFIG_VIDEO_COREBOOT) += coreboot.o
obj-$(CONFIG_VIDEO_DA8XX) += da8xx-fb.o videomodes.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_ANX9804) += anx9804.o
obj-$(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM) += hitachi_tx18d42vm_lcd.o obj-$(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM) += hitachi_tx18d42vm_lcd.o
obj-$(CONFIG_VIDEO_LCD_SSD2828) += ssd2828.o obj-$(CONFIG_VIDEO_LCD_SSD2828) += ssd2828.o

@ -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,
};
Loading…
Cancel
Save